OpenGL: Mehrere Texturen speichern
-
Ich habe versucht eine srImage-Klasse zu schreiben, die sich mehrere Texturen merken soll. Aber irgendwie läuft was schief. Wenn ich in meine srOpenGL-Klasse versuche eine Textur mit glBindTexture(GL_TEXTURE_2D, image->GetID()[index]); einzubinden, so erhält nur der Index-Wert mit der höchsten Zahl eine Textur; also praktisch die letzte definierte Bild-Datei. Alle anderen Texturen sind irgendwie gelöscht. Hat einer eine Erklärung? Hier ist mein Quelltext:
image.h:
//////////////////////////////////////////////////////////////////////////////// /// Die srImage-Schablone //////////////////////////////////////////////////////////////////////////////// #ifndef _srImage_h_ #define _srImage_h_ #include <cmath> #include <GL/gl.h> #include <vector> #include <wx/image.h> #include <wx/msgdlg.h> class srImage { private: unsigned int array; int *height; int *width; GLuint *id; public: srImage(unsigned int array = 1); ~srImage(); bool IsPowerOfTwo(unsigned int index); bool IsTexture(unsigned int index); const int *GetHeight(); const int *GetWidth(); const GLuint *GetID(); void Destroy(); void LoadFile(const wxString &file, unsigned int index); void Storage(); }; #endif
image.cpp:
//////////////////////////////////////////////////////////////////////////////// /// Die srImage-Implementierung //////////////////////////////////////////////////////////////////////////////// #include "image.h" srImage::srImage(unsigned int array) { //////////////////////////////////////////////////////////////////////////////// /// Die Konfiguration //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////// this->array = array; this->id = new GLuint[this->array]; this->height = new int[this->array]; this->width = new int[this->array]; glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glGenTextures(array, &this->id[0]); //////////////////////////////////////// } srImage::~srImage() { //////////////////////////////////////////////////////////////////////////////// /// Die Konfiguration //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////// delete[] this->width; delete[] this->height; delete[] this->id; //////////////////////////////////////// } bool srImage::IsPowerOfTwo(unsigned int index) { //////////////////////////////////////////////////////////////////////////////// /// Die Textur auf Zweierpotenz überprüfen //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////// float height, width; height = std::log(static_cast<float>(this->GetHeight()[index]))/std::log(2.0f); width = std::log(static_cast<float>(this->GetWidth()[index]))/std::log(2.0f); if(index<this->array) { if((static_cast<int>(height)==height)&&(static_cast<int>(width)==width)) { return TRUE; } else { return FALSE; } } else { return FALSE; } //////////////////////////////////////// } bool srImage::IsTexture(unsigned int index) { //////////////////////////////////////////////////////////////////////////////// /// Die Textur-ID überprüfen //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////// wxString caption, message; caption = wxT("Fehlermeldung"); if(index<this->array) { if(glIsTexture(this->id[index]) == GL_FALSE) { message = wxT("Die ID bezeichnet keine\nexisierende OpenGL-Textur!"); wxMessageBox(message, caption); return FALSE; } else { return TRUE; } } else { return FALSE; } //////////////////////////////////////// } const int *srImage::GetHeight() { //////////////////////////////////////////////////////////////////////////////// /// Der Höhen-Akzessor //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////// return this->height; //////////////////////////////////////// } const int *srImage::GetWidth() { //////////////////////////////////////////////////////////////////////////////// /// Der Breiten-Akzessor //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////// return this->width; //////////////////////////////////////// } const GLuint *srImage::GetID() { //////////////////////////////////////////////////////////////////////////////// /// Der Textur-ID-Akzessor //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////// return this->id; //////////////////////////////////////// } void srImage::Destroy() { //////////////////////////////////////////////////////////////////////////////// /// Alle Texturen entfernen //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////// glDeleteTextures(this->array, &this->id[0]); //////////////////////////////////////// } void srImage::LoadFile(const wxString &file, unsigned int index) { //////////////////////////////////////////////////////////////////////////////// /// Die Textur laden //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////// wxString caption, message; caption = wxT("Fehlermeldung"); wxInitAllImageHandlers(); if(!wxFileExists(file)) { message = wxT("Die Datei \""); message.Append(file); message.Append(wxT("\"\nwurde nicht gefunden!")); wxMessageBox(message, caption); return; } wxImage *image = new wxImage(file); this->height[index] = image->GetHeight(); this->width[index] = image->GetWidth(); if(index<this->array) { if(this->IsPowerOfTwo(index)) { int intPixel, size; intPixel = image->HasAlpha()?4:3; size = this->GetWidth()[index]*this->GetHeight()[index]; std::vector<unsigned char>imageData(intPixel*size); unsigned char *alphaData, *rgbData; alphaData = image->GetAlpha(); rgbData = image->GetData(); glBindTexture(GL_TEXTURE_2D, this->id[index]); for(unsigned int c; c<size; c++) { imageData[c*intPixel] = rgbData[c*3]; imageData[c*intPixel+1] = rgbData[c*3+1]; imageData[c*intPixel+2] = rgbData[c*3+2]; if(intPixel==4) { imageData[c*intPixel+3] = alphaData[c]; } } glTexImage2D(GL_TEXTURE_2D, 0, intPixel, this->GetWidth()[index], this->GetHeight()[index], 0, image->HasAlpha()?GL_RGBA:GL_RGB, GL_UNSIGNED_BYTE, static_cast<const GLvoid*>(&imageData[0])); } else { message = wxT("Die Auflösung der Textur\nstellt keine Zweierpotenz dar!"); wxMessageBox(message, caption); } } delete image; //////////////////////////////////////// } void srImage::Storage() { //////////////////////////////////////////////////////////////////////////////// /// Die Textureinstellungen merken //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////// glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); //////////////////////////////////////// }
-
Hallo littletux,
wie ist denn deine Vorgehensweise?
Du erzeugst ein srImage-Objekt mit Parameter 2 und testest dann mit IsTexture()? Oder wird nur eine Textur dargestellt?Übrigens ab OpenGL 2.0 müssen Texturen meines Wissens nicht mehr der powerOfTwo Restriktion unterliegen. Du kannst eine beliebige Höhe und Breite angeben.
Viele Grüße,
MaBa
-
Als erstes erzeuge ich in der srOpenGl-Klasse ein neues Objekt vom Typ srImage im Heap-Speicher.
srImage *image; //steht in meine Header-Datei opengl.h this->image = new srImage(2); //steht im Konstruktor von opengl.cpp
Dann lade ich vor dem Zeichnen die Texturen einzeln mit den Index-Werten.
void srOpenGL::OnPaint(wxPaintEvent &event) { //////////////////////////////////////////////////////////////////////////////// /// OpenGL einrichten //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////// wxPaintDC *paint = new wxPaintDC(this); wxGLCanvas::SetCurrent(); if(!this->init) //<- Funktion beim zeichnen einmalig für die Initialisierung aufrufen { this->InitOpenGL(); image->LoadFile(wxT("test.bmp"), 0); //<- Textur-ID 1 image->LoadFile(wxT("test2.bmp"), 1); //<-Textur-ID 2 image->Storage(); //<- Textureinstellungen laden this->init = TRUE; } this->Render(); glFlush(); wxGLCanvas::SwapBuffers(); delete paint; //////////////////////////////////////// }
Mit der DrawObject-Methode kann ich, aus irgendwelchen Gründen, nur die Textur mit den höchsten Wert zeichnen. In diesem Fall währe es 1.
void srOpenGL::DrawObject() { //////////////////////////////////////////////////////////////////////////////// /// Das Objekt zeichnen //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////// glBindTexture(GL_TEXTURE_2D, image->GetID()[1]); //<- Nur Textur-ID 2 wird richtig dargestellt glBegin(GL_QUADS); glTexCoord2f(0.0f, 0.0f); glVertex3f(-0.5f, 0.5f, 0.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f(0.5f, 0.5f, 0.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f(0.5f, -0.5f, 0.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f(-0.5f, -0.5f, 0.0f); glEnd(); //////////////////////////////////////// }
Mein Problem ist, dass ich es nicht verstehe, warum es nicht klappt, wenn ich für die Funktion glBindTexture den Parameter image->GetID()[0] eingebe. Ich finde, ich habe die Codes schon ordentlich und nach den neusten C++-Standards geschrieben. Aber irgendwie ergärt es mich schon, nicht zu wissen warum nur die zuletzt definierte Textur funktioniert.
-
Ich habe das Problem selbst gelöst! Ich habe per Zufall her raus gefunden, dass die Befehle
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
nicht nur einmal, sondern mehrmals aufgerufen werden muss. Ich habe die Anweisungen jetzt in die LoadFile-Methode eingebaut und die Methode Storage entfernt. Jetzt klappt alles wunderbar!