// This code example is created for educational purpose // by Thorsten Thormaehlen (contact: www.thormae.de). // It is distributed without any warranty. #include #include #include #include #include #include #include #include #include using namespace std; class Renderer : protected QOpenGLFunctions_2_0 { public: float t; private: GLuint texID; public: // constructor Renderer() : t(0.0), texID(0) {} public: void init() { initializeOpenGLFunctions(); glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH); texID = loadTexture(findFile("dice_texture.ppm", "qt", 5)); } void resize(int w, int h) { glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective (30.0, (float)w/(float)h, 0.1, 50.0); } void display() { glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); // set camera gluLookAt(8.0, -2.0, 5.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0); // draw scene glRotatef(t, 0.0f, 0.0f, 1.0f); drawTexturedCube(); } void dispose() { if(texID !=0) glDeleteTextures( 1, &texID); } private: // returns a valid textureID on success, otherwise 0 GLuint loadTexture(const std::string &filename) { unsigned width; unsigned height; int level = 0; int border = 0; std::vector imgData; // load image data if(!loadPPMImageFlipped(filename, width, height, imgData)) return 0; // data is aligned in byte order glPixelStorei(GL_UNPACK_ALIGNMENT, 1); //request textureID GLuint textureID; glGenTextures( 1, &textureID); // bind texture glBindTexture( GL_TEXTURE_2D, textureID); //define how to filter the texture (important but ignore for now) glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); //texture colors should replace the original color values glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); //GL_MODULATE // specify the 2D texture map glTexImage2D(GL_TEXTURE_2D, level, GL_RGB, width, height, border, GL_RGB, GL_UNSIGNED_BYTE, &imgData[0]); // return unique texture identifier return textureID; } void drawTexturedCube() { glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, texID); glColor3f(1.0f,0.0f,0.0f); glBegin(GL_POLYGON); // three glTexCoord2f(0.25f,0.50f); glVertex3f(-1.0f, 1.0f, 1.0f); glTexCoord2f(0.25f,0.25f); glVertex3f(-1.0f,-1.0f, 1.0f); glTexCoord2f(0.50f,0.25f); glVertex3f( 1.0f,-1.0f, 1.0f); glTexCoord2f(0.50f,0.50f); glVertex3f( 1.0f, 1.0f, 1.0f); glEnd(); glColor3f(1.0f,1.0f,0.0f); glBegin(GL_POLYGON); // five glTexCoord2f(0.00f,0.50f); glVertex3f(-1.0f, 1.0f,-1.0f); glTexCoord2f(0.00f,0.25f); glVertex3f(-1.0f,-1.0f,-1.0f); glTexCoord2f(0.25f,0.25f); glVertex3f(-1.0f,-1.0f, 1.0f); glTexCoord2f(0.25f,0.50f); glVertex3f(-1.0f, 1.0f, 1.0f); glEnd(); glColor3f(0.0f,0.0f,1.0f); glBegin(GL_POLYGON); // two glTexCoord2f(0.50f,0.50f); glVertex3f( 1.0f, 1.0f, 1.0f); glTexCoord2f(0.50f,0.25f); glVertex3f( 1.0f,-1.0f, 1.0f); glTexCoord2f(0.75f,0.25f); glVertex3f( 1.0f,-1.0f,-1.0f); glTexCoord2f(0.75f,0.50f); glVertex3f( 1.0f, 1.0f,-1.0f); glEnd(); glColor3f(1.0f,1.0f,1.0f); glBegin(GL_POLYGON); // six glTexCoord2f(0.25f,0.75f); glVertex3f(-1.0f, 1.0f,-1.0f); glTexCoord2f(0.25f,0.50f); glVertex3f(-1.0f, 1.0f, 1.0f); glTexCoord2f(0.50f,0.50f); glVertex3f( 1.0f, 1.0f, 1.0f); glTexCoord2f(0.50f,0.75f); glVertex3f( 1.0f, 1.0f,-1.0f); glEnd(); glColor3f(0.0f,1.0f,1.0f); glBegin(GL_POLYGON); // one glTexCoord2f(0.25f,0.25f); glVertex3f(-1.0f, -1.0f, 1.0f); glTexCoord2f(0.25f,0.00f); glVertex3f(-1.0f, -1.0f,-1.0f); glTexCoord2f(0.50f,0.00f); glVertex3f( 1.0f, -1.0f,-1.0f); glTexCoord2f(0.50f,0.25f); glVertex3f( 1.0f, -1.0f, 1.0f); glEnd(); glColor3f(0.0f,1.0f,0.0f); glBegin(GL_POLYGON); //four glTexCoord2f(0.75f,0.50f); glVertex3f( 1.0f, 1.0f,-1.0f); glTexCoord2f(0.75f,0.25f); glVertex3f( 1.0f,-1.0f,-1.0f); glTexCoord2f(1.00f,0.25f); glVertex3f(-1.0f,-1.0f,-1.0f); glTexCoord2f(1.00f,0.50f); glVertex3f(-1.0f, 1.0f,-1.0f); glEnd(); glDisable(GL_TEXTURE_2D); } bool loadPPMImageFlipped(const std::string &filename, unsigned &width, unsigned &height, std::vector &imgData) { ifstream input(filename.c_str(), ifstream::in | ifstream::binary); if(!input) { // cast istream to bool to see if something went wrong QMessageBox msgBox; msgBox.setText(QString("Can not find texture data file ")+QString(filename.c_str())); msgBox.exec(); return false; } input.unsetf(std::ios_base::skipws); string line; input >> line >> std::ws; if (line != "P6") { QMessageBox msgBox; msgBox.setText("File is not PPM P6 raw format"); msgBox.exec(); return false; } width = 0; height = 0; unsigned depth = 0; unsigned readItems = 0; unsigned char lastCharBeforeBinary; while (readItems < 3) { input >> std::ws; if(input.peek() != '#') { if (readItems == 0) input >> width; if (readItems == 1) input >> height; if (readItems == 2) input >> depth >> lastCharBeforeBinary; readItems++; }else{ // skip comments std::getline(input, line); } } if(depth >= 256) { QMessageBox msgBox; msgBox.setText("Only 8-bit PPM format is supported"); msgBox.exec(); return false; } unsigned byteCount = width * height * 3; imgData.resize(byteCount); input.read((char*)&imgData[0], byteCount*sizeof(unsigned char)); // vertically flip the image because the image origin // in OpenGL is the lower-left corner unsigned char tmpData; for(unsigned y=0; y < height / 2; y++) { int sourceIndex = y * width * 3; int targetIndex = (height-1-y) * width *3; for(unsigned x=0; x < width*3; x++) { tmpData = imgData[targetIndex]; imgData[targetIndex] = imgData[sourceIndex]; imgData[sourceIndex] = tmpData; sourceIndex++; targetIndex++; } } return true; } bool fileExists(const std::string& filename) { ifstream myfile(filename.c_str()); if (!myfile.is_open()) { return false; } myfile.close(); return true; } std::string findFile(const std::string& filename, const std::string& subdir, int depth) { int counter = 0; std::string path(""); while (counter < depth) { if (fileExists(path + filename)) return path + filename; if (fileExists(path + "/" + subdir + "/" + filename)) return path + "/" + subdir + "/" + filename; path += "../"; counter++; } return filename; } }; class MyWidget : public QOpenGLWidget { private: Renderer *renderer; QTimer *timer; public: MyWidget(QWidget *parent = NULL) : QOpenGLWidget(parent) { this->setWindowTitle("Texture Demo"); this->resize(320, 320); renderer = new Renderer(); timer = new QTimer(this); connect(timer, SIGNAL(timeout()), this, SLOT(update())); timer->start(30); } ~MyWidget() { makeCurrent(); renderer->dispose(); doneCurrent(); delete renderer; delete timer; } protected: void initializeGL() { renderer->init(); } void resizeGL(int w, int h){ renderer->resize(w, h); } void paintGL() { float offset = 1.0f; renderer->t += offset; renderer->display(); } }; int main (int argc, char* argv[]) { // create a QApplication object that handles initialization, // finalization, and the main event loop QApplication appl(argc, argv); MyWidget widget; // create a widget widget.show(); //show the widget and its children return appl.exec(); // execute the application }