// This code example is created for educational purpose // by Thorsten Thormaehlen (contact: www.thormae.de). // It is distributed without any warranty. #include // we use glut here as window manager #define _USE_MATH_DEFINES #include #include #include #include #include #include using namespace std; #ifndef GL_GENERATE_MIPMAP #define GL_GENERATE_MIPMAP 0x8191 #endif #ifndef GL_MIRRORED_REPEAT #define GL_MIRRORED_REPEAT 0x8370 #endif #ifndef GL_CLAMP_TO_BORDER #define GL_CLAMP_TO_BORDER 0x812D #endif class Renderer { public: float t; int wrapS; int wrapT; int magFilter; int minFilter; int selectedTexID; private: GLuint texID0; GLuint texID1; public: // constructor Renderer() : t(-90.0f), wrapS(GL_REPEAT), wrapT(GL_REPEAT), magFilter(GL_LINEAR), minFilter(GL_LINEAR_MIPMAP_LINEAR), selectedTexID(0), texID0(0), texID1(0) {} // destructor ~Renderer() { if(texID0 !=0) glDeleteTextures( 1, &texID0); if(texID1 !=0) glDeleteTextures( 1, &texID1); } public: void init() { glEnable(GL_DEPTH_TEST); std::string fileName0("checker_texture_512.ppm"); texID0 = loadTexture(fileName0); std::string fileName1("checker_texture_32.ppm"); texID1 = loadTexture(fileName1); } 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.7f, 0.7f, 0.7f, 0.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); // set camera gluLookAt(8.0, -2.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0); //gluLookAt(0.0, 0.0, 10.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0); // draw scene glRotatef(t, 0.0f, 0.0f, 1.0f); drawTexturedPlane(); } // returns a valid textureID on success, otherwise 0 GLuint loadTexture(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); // parameters that define how to warp the texture glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); GLfloat borderColor[4] = {1.0f, 1.0f, 0.0f, 1.0f}; glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor); // parameters that define how to filter the texture glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); // 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 setTextureParameters() { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapS); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter); } void drawTexturedPlane() { glEnable(GL_TEXTURE_2D); if(selectedTexID == 0) { glBindTexture(GL_TEXTURE_2D, texID0); }else{ glBindTexture(GL_TEXTURE_2D, texID1); } setTextureParameters(); glColor3f(1.0f,0.0f,0.0f); glBegin(GL_POLYGON); glTexCoord2f(5.00f, 5.00f); glVertex3f(-10.0f, 10.0f, 0.0f); glTexCoord2f(5.00f, -4.00f); glVertex3f(-10.0f,-10.0f, 0.0f); glTexCoord2f(-4.00f, -4.00f); glVertex3f( 10.0f,-10.0f, 0.0f); glTexCoord2f(-4.00f, 5.00f); glVertex3f( 10.0f, 10.0f, 0.0f); glEnd(); glDisable(GL_TEXTURE_2D); } bool loadPPMImageFlipped(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 cerr << "Can not find texture data file " << filename.c_str() << endl; return false; } input.unsetf(std::ios_base::skipws); string line; input >> line >> std::ws; if (line != "P6") { cerr << "File is not PPM P6 raw format" << endl; 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) { cerr << "Only 8-bit PPM format is supported" << endl; 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; } }; //this is a static pointer to a Renderer used in the glut callback functions static Renderer *renderer; //glut static callbacks start static void glutResize(int w, int h) { renderer->resize(w,h); } static void glutDisplay() { renderer->display(); glutSwapBuffers(); glutReportErrors(); } static void timer(int v) { float offset = 0.25f; renderer->t += offset; glutDisplay(); glutTimerFunc(unsigned(20), timer, ++v); } static void glutKeyboard(unsigned char key, int x, int y) { bool redraw = false; std::string modeStr; switch(key) { case '1': if(renderer->wrapS == GL_REPEAT) { renderer->wrapS = GL_CLAMP; modeStr = "wrapS = GL_CLAMP"; } else if(renderer->wrapS == GL_CLAMP) { renderer->wrapS = GL_MIRRORED_REPEAT; modeStr = "wrapS = GL_MIRRORED_REPEAT"; } else if(renderer->wrapS == GL_MIRRORED_REPEAT) { renderer->wrapS = GL_CLAMP_TO_BORDER; modeStr = "wrapS = GL_CLAMP_TO_BORDER"; } else if(renderer->wrapS == GL_CLAMP_TO_BORDER) { renderer->wrapS = GL_REPEAT; modeStr = "wrapS = GL_REPEAT"; } redraw = true; break; case '2': if(renderer->wrapT == GL_REPEAT) { renderer->wrapT = GL_CLAMP; modeStr = "wrapT = GL_CLAMP"; } else if(renderer->wrapT == GL_CLAMP) { renderer->wrapT = GL_MIRRORED_REPEAT; modeStr = "wrapT = GL_MIRRORED_REPEAT"; } else if(renderer->wrapT == GL_MIRRORED_REPEAT) { renderer->wrapT = GL_CLAMP_TO_BORDER; modeStr = "wrapT = GL_CLAMP_TO_BORDER"; } else if(renderer->wrapT == GL_CLAMP_TO_BORDER) { renderer->wrapT = GL_REPEAT; modeStr = "wrapT = GL_REPEAT"; } redraw = true; break; case '3': if(renderer->minFilter == GL_NEAREST) { renderer->minFilter = GL_LINEAR; modeStr = "minFilter = GL_LINEAR"; } else if(renderer->minFilter == GL_LINEAR) { renderer->minFilter = GL_NEAREST_MIPMAP_NEAREST; modeStr = "minFilter = GL_NEAREST_MIPMAP_NEAREST"; } else if(renderer->minFilter == GL_NEAREST_MIPMAP_NEAREST) { renderer->minFilter = GL_LINEAR_MIPMAP_NEAREST; modeStr = "minFilter = GL_LINEAR_MIPMAP_NEAREST"; } else if(renderer->minFilter == GL_LINEAR_MIPMAP_NEAREST) { renderer->minFilter = GL_NEAREST_MIPMAP_LINEAR; modeStr = "minFilter = GL_NEAREST_MIPMAP_LINEAR"; } else if(renderer->minFilter == GL_NEAREST_MIPMAP_LINEAR) { renderer->minFilter = GL_LINEAR_MIPMAP_LINEAR; modeStr = "minFilter = GL_LINEAR_MIPMAP_LINEAR"; } else if(renderer->minFilter == GL_LINEAR_MIPMAP_LINEAR) { renderer->minFilter = GL_NEAREST; modeStr = "minFilter = GL_NEAREST"; } redraw = true; break; case '4': if(renderer->magFilter == GL_NEAREST) { renderer->magFilter = GL_LINEAR; modeStr = "magFilter = GL_LINEAR"; } else if(renderer->magFilter == GL_LINEAR) { renderer->magFilter = GL_NEAREST; modeStr = "magFilter = GL_NEAREST"; } redraw = true; break; case '5': if(renderer->selectedTexID == 0) { renderer->selectedTexID = 1; modeStr = "texture resolution 32x32 pixels"; } else { renderer->selectedTexID = 0; modeStr = "texture resolution 512x512 pixels"; } redraw = true; break; } if(redraw) { glutDisplay(); cout << modeStr << endl; glutSetWindowTitle(modeStr.c_str()); } } int main(int argc, char **argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA); glutInitWindowPosition(100,100); glutInitWindowSize(320, 320); glutCreateWindow("Use the 1 to 5 keys to change the texture parameters"); glutDisplayFunc(glutDisplay); //glutIdleFunc(glutDisplay); glutReshapeFunc(glutResize); glutKeyboardFunc(glutKeyboard); renderer = new Renderer; renderer->init(); glutTimerFunc(unsigned(20), timer, 0); glutMainLoop(); }