/* cm_demo.c - EXT_texture_cube_map example */ /* Copyright NVIDIA Corporation, 1999. */ /* This program uses a pre-generated set of cube map images for an outdoor patio environment. The EXT_texture_cube_map extension is used. The cube map environment is be applied to a teapot, torus, or sphere. You can spin the object with the mouse. In theory, cube maps are view independent so the eye position could change (this would not be true of a sphere map), but this demo does not change the eye position. Also the EXT_texture_lod_bias can be used (when supported) to bias the texture LOD to force blurrier mipmap levels. This can simulate a less shiny surface with duller reflections. */ /* Windows command line compile instructions: cl cm_demo.c trackball.c tga.c glut32.lib Unix command line compile instructions: cc -o cm_demo cm_demo.c trackball.c tga.c -lglut -lGLU -lGL -lXext -lX11 -lm Note that this program requires the OpenGL Utility Toolkit (GLUT). You can download GLUT from http://reality.sgi.com/opengl/glut3 */ #include #include #include #include /* In case your does not advertise EXT_texture_lod_bias... */ #ifndef GL_EXT_texture_lod_bias # define GL_MAX_TEXTURE_LOD_BIAS_EXT 0x84fd # define GL_TEXTURE_FILTER_CONTROL_EXT 0x8500 # define GL_TEXTURE_LOD_BIAS_EXT 0x8501 #endif /* In case your does not advertise EXT_texture_cube_map... */ #ifndef GL_EXT_texture_cube_map # define GL_NORMAL_MAP_EXT 0x8511 # define GL_REFLECTION_MAP_EXT 0x8512 # define GL_TEXTURE_CUBE_MAP_EXT 0x8513 # define GL_TEXTURE_BINDING_CUBE_MAP_EXT 0x8514 # define GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT 0x8515 # define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_EXT 0x8516 # define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_EXT 0x8517 # define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT 0x8518 # define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_EXT 0x8519 # define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT 0x851A # define GL_PROXY_TEXTURE_CUBE_MAP_EXT 0x851B # define GL_MAX_CUBE_MAP_TEXTURE_SIZE_EXT 0x851C #endif #include "tga.h" /* simple TGA image file loader */ #include "trackball.h" /* trackball quaternion routines */ static GLenum faceTarget[6] = { GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT, GL_TEXTURE_CUBE_MAP_NEGATIVE_X_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_Y_EXT, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_Z_EXT, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT }; /* Pre-generated cube map images. */ char *faceFile[6] = { "cm_left.tga", "cm_right.tga", "cm_top.tga", "cm_bottom.tga", "cm_back.tga", "cm_front.tga", }; /* Menu items. */ enum { M_TEAPOT, M_TORUS, M_SPHERE, M_SHINY, M_DULL, M_REFLECTION_MAP, M_NORMAL_MAP, }; int hasTextureLodBias = 0; int mode = GL_REFLECTION_MAP_EXT; int wrap = GL_CLAMP; int shape = M_TEAPOT; int mipmaps = 1; float lodBias = 0.0; int spinning = 0, moving = 0; int beginx, beginy; int W = 300, H = 300; float curquat[4]; float lastquat[4]; /* Rim, body, lid, and bottom data must be reflected in x and y; handle and spout data across the y axis only. */ static int patchdata[][16] = { /* rim */ {102, 103, 104, 105, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, /* body */ {12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27}, {24, 25, 26, 27, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40}, /* lid */ {96, 96, 96, 96, 97, 98, 99, 100, 101, 101, 101, 101, 0, 1, 2, 3,}, {0, 1, 2, 3, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117}, /* bottom */ {118, 118, 118, 118, 124, 122, 119, 121, 123, 126, 125, 120, 40, 39, 38, 37}, /* handle */ {41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56}, {53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 28, 65, 66, 67}, /* spout */ {68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83}, {80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95} }; /* *INDENT-OFF* */ static float cpdata[][3] = { {0.2, 0, 2.7}, {0.2, -0.112, 2.7}, {0.112, -0.2, 2.7}, {0, -0.2, 2.7}, {1.3375, 0, 2.53125}, {1.3375, -0.749, 2.53125}, {0.749, -1.3375, 2.53125}, {0, -1.3375, 2.53125}, {1.4375, 0, 2.53125}, {1.4375, -0.805, 2.53125}, {0.805, -1.4375, 2.53125}, {0, -1.4375, 2.53125}, {1.5, 0, 2.4}, {1.5, -0.84, 2.4}, {0.84, -1.5, 2.4}, {0, -1.5, 2.4}, {1.75, 0, 1.875}, {1.75, -0.98, 1.875}, {0.98, -1.75, 1.875}, {0, -1.75, 1.875}, {2, 0, 1.35}, {2, -1.12, 1.35}, {1.12, -2, 1.35}, {0, -2, 1.35}, {2, 0, 0.9}, {2, -1.12, 0.9}, {1.12, -2, 0.9}, {0, -2, 0.9}, {-2, 0, 0.9}, {2, 0, 0.45}, {2, -1.12, 0.45}, {1.12, -2, 0.45}, {0, -2, 0.45}, {1.5, 0, 0.225}, {1.5, -0.84, 0.225}, {0.84, -1.5, 0.225}, {0, -1.5, 0.225}, {1.5, 0, 0.15}, {1.5, -0.84, 0.15}, {0.84, -1.5, 0.15}, {0, -1.5, 0.15}, {-1.6, 0, 2.025}, {-1.6, -0.3, 2.025}, {-1.5, -0.3, 2.25}, {-1.5, 0, 2.25}, {-2.3, 0, 2.025}, {-2.3, -0.3, 2.025}, {-2.5, -0.3, 2.25}, {-2.5, 0, 2.25}, {-2.7, 0, 2.025}, {-2.7, -0.3, 2.025}, {-3, -0.3, 2.25}, {-3, 0, 2.25}, {-2.7, 0, 1.8}, {-2.7, -0.3, 1.8}, {-3, -0.3, 1.8}, {-3, 0, 1.8}, {-2.7, 0, 1.575}, {-2.7, -0.3, 1.575}, {-3, -0.3, 1.35}, {-3, 0, 1.35}, {-2.5, 0, 1.125}, {-2.5, -0.3, 1.125}, {-2.65, -0.3, 0.9375}, {-2.65, 0, 0.9375}, {-2, -0.3, 0.9}, {-1.9, -0.3, 0.6}, {-1.9, 0, 0.6}, {1.7, 0, 1.425}, {1.7, -0.66, 1.425}, {1.7, -0.66, 0.6}, {1.7, 0, 0.6}, {2.6, 0, 1.425}, {2.6, -0.66, 1.425}, {3.1, -0.66, 0.825}, {3.1, 0, 0.825}, {2.3, 0, 2.1}, {2.3, -0.25, 2.1}, {2.4, -0.25, 2.025}, {2.4, 0, 2.025}, {2.7, 0, 2.4}, {2.7, -0.25, 2.4}, {3.3, -0.25, 2.4}, {3.3, 0, 2.4}, {2.8, 0, 2.475}, {2.8, -0.25, 2.475}, {3.525, -0.25, 2.49375}, {3.525, 0, 2.49375}, {2.9, 0, 2.475}, {2.9, -0.15, 2.475}, {3.45, -0.15, 2.5125}, {3.45, 0, 2.5125}, {2.8, 0, 2.4}, {2.8, -0.15, 2.4}, {3.2, -0.15, 2.4}, {3.2, 0, 2.4}, {0, 0, 3.15}, {0.8, 0, 3.15}, {0.8, -0.45, 3.15}, {0.45, -0.8, 3.15}, {0, -0.8, 3.15}, {0, 0, 2.85}, {1.4, 0, 2.4}, {1.4, -0.784, 2.4}, {0.784, -1.4, 2.4}, {0, -1.4, 2.4}, {0.4, 0, 2.55}, {0.4, -0.224, 2.55}, {0.224, -0.4, 2.55}, {0, -0.4, 2.55}, {1.3, 0, 2.55}, {1.3, -0.728, 2.55}, {0.728, -1.3, 2.55}, {0, -1.3, 2.55}, {1.3, 0, 2.4}, {1.3, -0.728, 2.4}, {0.728, -1.3, 2.4}, {0, -1.3, 2.4}, {0, 0, 0}, {1.425, -0.798, 0}, {1.5, 0, 0.075}, {1.425, 0, 0}, {0.798, -1.425, 0}, {0, -1.5, 0.075}, {0, -1.425, 0}, {1.5, -0.84, 0.075}, {0.84, -1.5, 0.075} }; /* *INDENT-ON* */ /* This "fastTeapot" routine is faster than glutSolidTeapot. */ static void fastSolidTeapot(GLint grid, GLdouble scale) { float p[4][4][3], q[4][4][3], r[4][4][3], s[4][4][3]; long i, j, k, l; glEnable(GL_AUTO_NORMAL); glEnable(GL_MAP2_VERTEX_3); glRotatef(270.0, 1.0, 0.0, 0.0); glScalef(0.5 * scale, 0.5 * scale, 0.5 * scale); glTranslatef(0.0, 0.0, -1.5); for (i = 0; i < 10; i++) { for (j = 0; j < 4; j++) { for (k = 0; k < 4; k++) { for (l = 0; l < 3; l++) { p[j][k][l] = cpdata[patchdata[i][j * 4 + k]][l]; q[j][k][l] = cpdata[patchdata[i][j * 4 + (3 - k)]][l]; if (l == 1) q[j][k][l] *= -1.0; if (i < 6) { r[j][k][l] = cpdata[patchdata[i][j * 4 + (3 - k)]][l]; if (l == 0) r[j][k][l] *= -1.0; s[j][k][l] = cpdata[patchdata[i][j * 4 + k]][l]; if (l == 0) s[j][k][l] *= -1.0; if (l == 1) s[j][k][l] *= -1.0; } } } } glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4, &p[0][0][0]); glMapGrid2f(grid, 0.0, 1.0, grid, 0.0, 1.0); glEvalMesh2(GL_FILL, 0, grid, 0, grid); glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4, &q[0][0][0]); glEvalMesh2(GL_FILL, 0, grid, 0, grid); if (i < 6) { glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4, &r[0][0][0]); glEvalMesh2(GL_FILL, 0, grid, 0, grid); glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4, &s[0][0][0]); glEvalMesh2(GL_FILL, 0, grid, 0, grid); } } } void loadFace(GLenum target, char *filename) { FILE *file; gliGenericImage *image; file = fopen(filename, "rb"); if (file == NULL) { printf("cm_demo: could not open \"%s\"\n", filename); exit(1); } image = gliReadTGA(file, filename); fclose(file); if (mipmaps) { gluBuild2DMipmaps(target, image->components, image->width, image->height, image->format, GL_UNSIGNED_BYTE, image->pixels); } else { glTexImage2D(target, 0, image->components, image->width, image->height, 0, image->format, GL_UNSIGNED_BYTE, image->pixels); } } void updateTexgen(void) { assert(mode == GL_NORMAL_MAP_EXT || mode == GL_REFLECTION_MAP_EXT); glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, mode); glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, mode); glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, mode); } void updateWrap(void) { glTexParameteri(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_WRAP_S, wrap); glTexParameteri(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_WRAP_T, wrap); } void makeCubeMap(void) { int i; for (i=0; i<6; i++) { loadFace(faceTarget[i], faceFile[i]); } if (mipmaps) { glTexParameteri(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } else { glTexParameteri(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } glEnable(GL_TEXTURE_CUBE_MAP_EXT); updateTexgen(); updateWrap(); glEnable(GL_TEXTURE_GEN_S); glEnable(GL_TEXTURE_GEN_T); glEnable(GL_TEXTURE_GEN_R); } void display(void) { GLfloat m[4][4]; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); build_rotmatrix(m, curquat); glMultMatrixf(&m[0][0]); switch (shape) { case M_TEAPOT: fastSolidTeapot(5, 1.1); break; case M_TORUS: glutSolidTorus(0.4, 0.9, 35, 35); break; case M_SPHERE: glutSolidSphere(1.0, 35, 35); break; default: assert(0); } glPopMatrix(); glutSwapBuffers(); } void reshape(int w, int h) { glViewport(0, 0, w, h); W = w; H = h; } void keyboard(unsigned char c, int x, int y) { switch (c) { case 27: exit(0); break; case ' ': if (mode == GL_REFLECTION_MAP_EXT) { mode = GL_NORMAL_MAP_EXT; } else { mode = GL_REFLECTION_MAP_EXT; } updateTexgen(); glutPostRedisplay(); break; case 'c': if (wrap == GL_REPEAT) { wrap = GL_CLAMP; } else { wrap = GL_REPEAT; } updateWrap(); glutPostRedisplay(); break; case 's': shape++; if (shape > M_SPHERE) { shape = M_TEAPOT; } glutPostRedisplay(); break; case 'm': glMatrixMode(GL_TEXTURE); glScalef(-1,-1,-1); glMatrixMode(GL_MODELVIEW); glutPostRedisplay(); break; case 'a': if (hasTextureLodBias) { lodBias += 0.05; if (lodBias > 5.0) { lodBias = 5.0; } glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, lodBias); glutPostRedisplay(); } break; case 'z': if (hasTextureLodBias) { lodBias -= 0.05; if (lodBias < 0.0) { lodBias = 0.0; } glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, lodBias); glutPostRedisplay(); } break; } } void mouse(int button, int state, int x, int y) { if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) { spinning = 0; glutIdleFunc(NULL); moving = 1; beginx = x; beginy = y; } if (button == GLUT_LEFT_BUTTON && state == GLUT_UP) { moving = 0; } } void animate(void) { add_quats(lastquat, curquat, curquat); glutPostRedisplay(); } void motion(int x, int y) { if (moving) { trackball(lastquat, (2.0 * beginx - W) / W, (H - 2.0 * beginy) / H, (2.0 * x - W) / W, (H - 2.0 * y) / H ); beginx = x; beginy = y; spinning = 1; glutIdleFunc(animate); } } void menu(int item) { switch (item) { case M_TEAPOT: case M_TORUS: case M_SPHERE: shape = item; break; case M_SHINY: lodBias = 0.0; glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, lodBias); break; case M_DULL: lodBias = 1.4; glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, lodBias); break; case M_NORMAL_MAP: mode = GL_NORMAL_MAP_EXT; updateTexgen(); break; case M_REFLECTION_MAP: mode = GL_REFLECTION_MAP_EXT; updateTexgen(); break; default: assert(0); } glutPostRedisplay(); } int main(int argc, char **argv) { int i; glutInitWindowSize(500, 500); glutInit(&argc, argv); for (i=1; i