Kyllästyin SDL:ään ja aloin tekemään omaa grafiikkakirjastoa 2D-grafiikkaa varten. Se luo SDL:n avulla ikkunan, mutta piirtäminen tapahtuu OpenGL:n avulla. Tein siitä täysin oliopohjaisen, mutta en tiedä onko sekään paras mahdollinen ratkaisu (vinkkejä, olisiko funktiopohjainen parempi?).
Tällä hetkellä piirtäminen toimii aivan oikein pikselikoordinaateilla, ja jopa bitmap kuvia saa ladattua ja nekin näkyvät oikein. Tai ainakin melkein. Tuo systeemi, jolla hallitsen kuvia eli tekstuureita, tuntuu kusevan. Ensinnäkin, poistetut tekstuurit eivät poistu, vaan niitä pystyy käyttämään senkin jälkeen kun Simple2D.Delete() on kutsuttu jollekin kuvalle. Muita oireita on aika vaikea selittää, kun poistun ohjelmasta niin joissain tilanteissa juuri ennen ruudun katoamista sinne ilmestyy tekstuureita, vaikka ruutu on puhdistettu glClear():lla jonka jälkeen ei pitäisi mitään tapahtua.
No, lähinnä haluaisin apua tuohon miten tekisin paremmin tuon tekstuurisysteemin. Nyt se on aikamoinen patentti, kuten koodista tulee huomaamaan. Minulla on iso taulukko unsigned inttejä, joihin tallennetaan luodun tekstuurin ID. Tämän ID:n avulla sitä sitten käsitellään, tarvittaessa poistetaan. Systeemin oli tarkoitus täyttää ensimmäinen tyhjä ID, mutta se ei vaikuta toimivan. Pidemmittä puheitta, koodia:
#ifndef Simple2D__ #define Simple2D__ typedef unsigned int GLuint; typedef int Image2D; class S2D { private: GLuint Textures[1000]; // This array is used to hold texture handles. GLuint = unsigned int. int ImageWidth[1000]; int ImageHeight[1000]; public: int Init(); // This initializes both SDL and OpenGL. After this Simple2D is ready for use. void Quit(); // Just a cleanup method. Must be used ALWAYS when exiting. void Draw(int x, int y, int Image); // This does the drawing. Very self-explaining. void FlipBuffer(); // Yes. int LoadIMG(char *Filename); // Loads a BMP image into graphics card's memory. void DeleteIMG(int ID); // Destroys any loaded texture. }; #endif
// Tämä piirtää halutun kuvan void S2D::Draw(int x, int y, int Image) { if (ImageWidth[Image] > 0 && ImageHeight[Image] > 0) { glBindTexture(GL_TEXTURE_2D, Textures[Image]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glBegin(GL_QUADS); glTexCoord2f(0.0f, 0.0f); glVertex2f(x, y); glTexCoord2f(0.0f, 1.0f); glVertex2f(x, y + ImageHeight[Image]); glTexCoord2f(1.0f, 1.0f); glVertex2f(x + ImageWidth[Image], y + ImageHeight[Image]); glTexCoord2f(1.0f, 0.0f); glVertex2f(x + ImageWidth[Image], y); glEnd(); } } // Tätä tulee kutsua jotta ruutu päivitetään void S2D::FlipBuffer() { SDL_GL_SwapBuffers(); glClear(GL_COLOR_BUFFER_BIT); } // Tässä tämä patentti kuvanlataus int S2D::LoadIMG(char *Filename) { SDL_Surface *TextureImage; if (TextureImage = SDL_LoadBMP(Filename)) { int ID = 0; for (int i = 0; i < 1000; i++) { if (Textures[i] == 0) ID = i; } glGenTextures(1, &Textures[ID]); glBindTexture(GL_TEXTURE_2D, Textures[ID]); glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage->w, TextureImage->h, 0, GL_BGR, GL_UNSIGNED_BYTE, TextureImage->pixels); ImageWidth[ID] = TextureImage->w; ImageHeight[ID] = TextureImage->h; SDL_FreeSurface(TextureImage); return ID; } else return -1; } // Tämän pitäisi poistaa kuva... void S2D::DeleteIMG (int ID) { glDeleteTextures(1, &Textures[ID]); Textures[ID] = 0; ImageWidth[ID] = 0; ImageHeight[ID] = 0; }
Käytä ihmeessä C++:n STL:n containeria, kuten vaikkapa vektoria, noiden hirveiden purkkaviritystaulukoiden sijaan.
EDIT:
Mitään takuuta ei ole, että taulukoiden (GLuint Textures[1000], int ImageWidth[1000], int ImageHeight[1000]) alkiot olisivat automaattisesti nolla, kuten oletat:
for (int i = 0; i < 1000; i++) { if (Textures[i] == 0) ID = i; }
Muutenkaan tuo ei ole paras mahdollinen tapa toteuttaa, siispä jälleen suosittelen käyttämään jotakin kehittyneempää kuin staattisesti varattuja taulukoita. ;)
Nämä voit ainakin siirtää Draw:sta LoadIMG puolelle:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
Toisekseen ohjelmasi ei pidä vertaa kyseisen tekstuurin indeksiä edelliseen, joten se saattaa kutsua
glBindTexture(GL_TEXTURE_2D, Textures[Image]);
samalle indeksille monta kertaa peräkkäin mikä hidastaa ohjelmaa esim partikkelien tapauksessa tuhottomasti.
Legu kirjoitti:
Käytä ihmeessä C++:n STL:n containeria, kuten vaikkapa vektoria, noiden hirveiden purkkaviritystaulukoiden sijaan.
Aloitin tutustumisen.
Legu kirjoitti:
Mitään takuuta ei ole, että taulukoiden (GLuint Textures[1000], int ImageWidth[1000], int ImageHeight[1000]) alkiot olisivat automaattisesti nolla, kuten oletat:
En oleta, taulukoiden alustus on tuolla Init metodissa jota en pistänyt näkyviin. ;)
User137 kirjoitti:
Toisekseen ohjelmasi ei pidä vertaa kyseisen tekstuurin indeksiä edelliseen, joten se saattaa kutsua
glBindTexture(GL_TEXTURE_2D, Textures[Image]);samalle indeksille monta kertaa peräkkäin mikä hidastaa ohjelmaa esim partikkelien tapauksessa tuhottomasti.
Tiedän, mutta kaikki aikanaan.
Itse käytän seuraavaa tapaa:
1) Minulla on Texture-luokka, joka sisältää itse datan (DX tai OGL) yms. yleishyödykkäitä metodeita (load, create...)
2) Minulla on TextureManager-luokka, joka pitää kirjaa KAIKISTA ohjelman tekstuureista. Tämä on yleensä singleton, joten sitä voi kutsua mistä tahansa. Tekstuurit on "arkistoitu" niiden tiedostonimen perusteella std::map-rakenteeseen, josta voidaan tarkistaa tekstuurien olemassaolo sekä välttää tekstuurien lataamista moneen kertaan.
Vielä yksinkertainen esimerkki (ei toimiva):
class Texture { //public void load(...) GLuint getId(...) int getWidth() jne... // private GLuint m_textId; yms.. tietoja.. }; class TextureManager // (hyvin mahdollisesti) : public Singleton<TextureManager> { // private std::map<string, Texture*> m_textures; // public Texture* loadTexture(string file) { std::map::iterator i = m_textures.find( file ); if( i != m_textures.end() ) return i->second; Texture* t = new Texture(); t->load(file); m_textures[ file ] = t; return t; } muut mahdolliset hallinta/poistometodit... }
Aihe on jo aika vanha, joten et voi enää vastata siihen.