//////////////////////////////////////////////////// // Demonstrates texture mapping on a rotating cube // Don Fussell, CS, U. Texas. // Mod. by Saty Raghavachary, USC //////////////////////////////////////////////////// #include #include #include #define MAX_VERTICES 2000 #define MAX_POLYGONS 2000 //Vertex type typedef struct{ float x,y,z; }vType; //Triangle type typedef struct{ int a,b,c; }tType; //Texture coordinates type typedef struct{ float u,v; }texType; //Object type typedef struct { vType vertex[MAX_VERTICES]; tType triangle[MAX_POLYGONS]; texType texCoord[MAX_VERTICES]; GLuint textureID; } oType, *oTypePtr; //Window size int width=640; int height=480; //Starting rotation angles and increments double rotation_x = 0, rotation_x_increment = 0.11; double rotation_y = 0, rotation_y_increment = 0.07; double rotation_z = 0, rotation_z_increment = 0.05; //Flag for rendering as lines or filled polygons int fill = 1; //0=OFF 1=ON //Filename char * fileName; oType cube = { { -10, -10, 10, // vertex v0 10, -10, 10, // vertex v1 10, -10, -10, // vertex v2 -10, -10, -10, // vertex v3 -10, 10, 10, // vertex v4 10, 10, 10, // vertex v5 10, 10, -10, // vertex v6 -10, 10, -10 // vertex v7 }, { 0, 1, 4, // polygon v0,v1,v4 1, 5, 4, // polygon v1,v5,v4 1, 2, 5, // polygon v1,v2,v5 2, 6, 5, // polygon v2,v6,v5 2, 3, 6, // polygon v2,v3,v6 3, 7, 6, // polygon v3,v7,v6 3, 0, 7, // polygon v3,v0,v7 0, 4, 7, // polygon v0,v4,v7 4, 5, 7, // polygon v4,v5,v7 5, 6, 7, // polygon v5,v6,v7 3, 2, 0, // polygon v3,v2,v0 2, 1, 0 // polygon v2,v1,v0 }, { 0.0, 0.0, // mapping coordinates for vertex v0 1.0, 0.0, // mapping coordinates for vertex v1 1.0, 0.0, // mapping coordinates for vertex v2 0.0, 0.0, // mapping coordinates for vertex v3 0.0, 1.0, // mapping coordinates for vertex v4 1.0, 1.0, // mapping coordinates for vertex v5 1.0, 1.0, // mapping coordinates for vertex v6 0.0, 1.0 // mapping coordinates for vertex v7 }, 0, }; //////////////////////////////////////////////////////////// // Load OpenGL textures from binary ppm files //////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////// // FUNCTION LoadPPM(char *) // Load a binary ppm file into an OpenGL texture and return the OpenGL texture reference ID //////////////////////////////////////////////////////////// int loadPPM(char *filename) { FILE *inFile; //File pointer char buffer[100]; //Input buffer GLubyte *theTexture; //Texture buffer pointer unsigned char c; //Input character int width, height, maxVal, pixelSize; //Image characteristics from ppm file GLuint textureID = 0; //OpenGL texture ID to be returned int i; //Try to open the file for reading if( (inFile = fopen(filename, "rb")) == NULL) { fprintf (stderr, "cannot open %s\n", filename); return(-1); } //Read file type identifier (magic number) fgets(buffer, sizeof(buffer), inFile); if ((buffer[0] != 'P') || (buffer[1] != '6')) { fprintf (stderr, "not a binary ppm file %s\n", filename); return(-1); } if(buffer[2] == 'A') pixelSize = 4; else pixelSize = 3; //Read image size do fgets(buffer, sizeof (buffer), inFile); while (buffer[0] == '#'); sscanf (buffer, "%d %d", &width, &height); //Read maximum pixel value (usually 255) do fgets (buffer, sizeof (buffer), inFile); while (buffer[0] == '#'); sscanf (buffer, "%d", &maxVal); //Allocate RGBA texture buffer int memSize = width * height * 4 * sizeof(GLubyte); theTexture = (GLubyte *)malloc(memSize); // read RGB data and set alpha value for (i = 0; i < memSize; i++) { if ((i % 4) < 3 || pixelSize == 4) { c = fgetc(inFile); theTexture[i]=(GLubyte) c; } else theTexture[i] = (GLubyte) 255; //Set alpha to opaque } fclose(inFile); glBindTexture(GL_TEXTURE_2D, ++textureID); //Set texture parameters glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); //Ignore surface color glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); //Define the texture glTexImage2D(GL_TEXTURE_2D, 0, 4, (GLuint)width, (GLuint)height, 0, GL_RGBA, GL_UNSIGNED_BYTE, theTexture); //Create mipmaps gluBuild2DMipmaps(GL_TEXTURE_2D, 4, (GLuint)width, (GLuint)height, GL_RGBA, GL_UNSIGNED_BYTE, theTexture); free(theTexture); return(textureID); } void init() { glClearColor(0.0, 0.0, 0.2, 0.0); glShadeModel(GL_SMOOTH); //Set viewport glViewport(0, 0, width, height); //Set perspective glMatrixMode(GL_PROJECTION); gluPerspective(45.0f, (GLfloat)width/(GLfloat)height, 1.0f, 1000.0f); glEnable(GL_DEPTH_TEST); glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); glEnable(GL_TEXTURE_2D); cube.textureID = loadPPM(fileName); } void resize(int w, int h) { glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45.0f, (GLfloat)w/(GLfloat)h, 1.0f, 1000.0f); glutPostRedisplay(); } void keyboard (unsigned char key, int x, int y) { switch (key) { case ' ': rotation_x_increment=0; rotation_y_increment=0; rotation_z_increment=0; break; case 'r': case 'R': if (fill == 0) { glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); fill = 1; } else { glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); fill = 0; } break; } } void keyboard_s (int key, int x, int y) { switch (key) { case GLUT_KEY_UP: rotation_x_increment = rotation_x_increment +0.005; break; case GLUT_KEY_DOWN: rotation_x_increment = rotation_x_increment -0.005; break; case GLUT_KEY_LEFT: rotation_y_increment = rotation_y_increment +0.005; break; case GLUT_KEY_RIGHT: rotation_y_increment = rotation_y_increment -0.005; break; } } void display(void) { int i; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //Set the view glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(0.0,0.0,-50); //Set the cube rotation rotation_x = rotation_x + rotation_x_increment; rotation_y = rotation_y + rotation_y_increment; rotation_z = rotation_z + rotation_z_increment; if (rotation_x > 359) rotation_x = 0; if (rotation_y > 359) rotation_y = 0; if (rotation_z > 359) rotation_z = 0; glRotatef(rotation_x,1.0,0.0,0.0); glRotatef(rotation_y,0.0,1.0,0.0); glRotatef(rotation_z,0.0,0.0,1.0); //Set active texture glBindTexture(GL_TEXTURE_2D, cube.textureID); //Draw the cube glBegin(GL_TRIANGLES); for (i = 0; i < 12; i++) { // Texture coordinates of the first vertex glTexCoord2f( cube.texCoord[ cube.triangle[i].a ].u, cube.texCoord[ cube.triangle[i].a ].v); // Coordinates of the first vertex glVertex3f( cube.vertex[ cube.triangle[i].a ].x, cube.vertex[ cube.triangle[i].a ].y, cube.vertex[ cube.triangle[i].a ].z); // Texture coordinates of the second vertex glTexCoord2f( cube.texCoord[ cube.triangle[i].b ].u, cube.texCoord[ cube.triangle[i].b ].v); // Coordinates of the second vertex glVertex3f( cube.vertex[ cube.triangle[i].b ].x, cube.vertex[ cube.triangle[i].b ].y, cube.vertex[ cube.triangle[i].b ].z); // Texture coordinates of the third vertex glTexCoord2f( cube.texCoord[ cube.triangle[i].c ].u, cube.texCoord[ cube.triangle[i].c ].v); // Coordinates of the third vertex glVertex3f( cube.vertex[ cube.triangle[i].c ].x, cube.vertex[ cube.triangle[i].c ].y, cube.vertex[ cube.triangle[i].c ].z); } glEnd(); glFlush(); glutSwapBuffers(); } int main(int argc, char **argv) { if (argc > 1) fileName = argv[1]; else fileName = "texmap.ppm"; glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(width, height); glutInitWindowPosition(0,0); glutCreateWindow("Texture Mapping"); glutDisplayFunc(display); glutIdleFunc(display); glutReshapeFunc(resize); glutKeyboardFunc(keyboard); glutSpecialFunc(keyboard_s); init(); glutMainLoop(); return(0); }