| |
| /* projtex.c - by David Yu and David Blythe, SGI */ |
| |
| /** |
| ** Demonstrates simple projective texture mapping. |
| ** |
| ** Button1 changes view, Button2 moves texture. |
| ** |
| ** (See: Segal, Korobkin, van Widenfelt, Foran, and Haeberli |
| ** "Fast Shadows and Lighting Effects Using Texture Mapping", SIGGRAPH '92) |
| ** |
| ** 1994,1995 -- David G Yu |
| ** |
| ** cc -o projtex projtex.c texture.c -lglut -lGLU -lGL -lX11 -lm |
| **/ |
| |
| #include <assert.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <math.h> |
| #include <GL/glut.h> |
| #if 0 |
| #include "texture.h" |
| #else |
| #include "../util/readtex.c" |
| #endif |
| |
| |
| /* Some <math.h> files do not define M_PI... */ |
| #ifndef M_PI |
| #define M_PI 3.14159265358979323846 |
| #endif |
| |
| #define MAX_TEX 4 |
| int NumTextures = 1; |
| |
| int winWidth, winHeight; |
| |
| GLboolean redrawContinuously = GL_FALSE; |
| |
| float angle, axis[3]; |
| enum MoveModes { |
| MoveNone, MoveView, MoveObject, MoveTexture |
| }; |
| enum MoveModes mode = MoveNone; |
| |
| GLfloat objectXform[4][4]; |
| GLfloat textureXform[MAX_TEX][4][4]; |
| |
| void (*drawObject) (void); |
| void (*loadTexture) (void); |
| GLboolean textureEnabled = GL_TRUE; |
| GLboolean showProjection = GL_TRUE; |
| GLboolean linearFilter = GL_TRUE; |
| |
| char *texFilename[MAX_TEX] = { |
| "../images/girl.rgb", |
| "../images/tile.rgb", |
| "../images/bw.rgb", |
| "../images/reflect.rgb" |
| }; |
| |
| |
| GLfloat zoomFactor = 1.0; |
| |
| /*****************************************************************/ |
| |
| |
| void ActiveTexture(int i) |
| { |
| glActiveTextureARB(i); |
| } |
| |
| |
| /* matrix = identity */ |
| void |
| matrixIdentity(GLfloat matrix[16]) |
| { |
| matrix[0] = 1.0; |
| matrix[1] = 0.0; |
| matrix[2] = 0.0; |
| matrix[3] = 0.0; |
| matrix[4] = 0.0; |
| matrix[5] = 1.0; |
| matrix[6] = 0.0; |
| matrix[7] = 0.0; |
| matrix[8] = 0.0; |
| matrix[9] = 0.0; |
| matrix[10] = 1.0; |
| matrix[11] = 0.0; |
| matrix[12] = 0.0; |
| matrix[13] = 0.0; |
| matrix[14] = 0.0; |
| matrix[15] = 1.0; |
| } |
| |
| /* matrix2 = transpose(matrix1) */ |
| void |
| matrixTranspose(GLfloat matrix2[16], GLfloat matrix1[16]) |
| { |
| matrix2[0] = matrix1[0]; |
| matrix2[1] = matrix1[4]; |
| matrix2[2] = matrix1[8]; |
| matrix2[3] = matrix1[12]; |
| |
| matrix2[4] = matrix1[1]; |
| matrix2[5] = matrix1[5]; |
| matrix2[6] = matrix1[9]; |
| matrix2[7] = matrix1[13]; |
| |
| matrix2[8] = matrix1[2]; |
| matrix2[9] = matrix1[6]; |
| matrix2[10] = matrix1[10]; |
| matrix2[11] = matrix1[14]; |
| |
| matrix2[12] = matrix1[3]; |
| matrix2[13] = matrix1[7]; |
| matrix2[14] = matrix1[14]; |
| matrix2[15] = matrix1[15]; |
| } |
| |
| /*****************************************************************/ |
| |
| /* load SGI .rgb image (pad with a border of the specified width and color) */ |
| #if 0 |
| static void |
| imgLoad(char *filenameIn, int borderIn, GLfloat borderColorIn[4], |
| int *wOut, int *hOut, GLubyte ** imgOut) |
| { |
| int border = borderIn; |
| int width, height; |
| int w, h; |
| GLubyte *image, *img, *p; |
| int i, j, components; |
| |
| image = (GLubyte *) read_texture(filenameIn, &width, &height, &components); |
| w = width + 2 * border; |
| h = height + 2 * border; |
| img = (GLubyte *) calloc(w * h, 4 * sizeof(unsigned char)); |
| |
| p = img; |
| for (j = -border; j < height + border; ++j) { |
| for (i = -border; i < width + border; ++i) { |
| if (0 <= j && j <= height - 1 && 0 <= i && i <= width - 1) { |
| p[0] = image[4 * (j * width + i) + 0]; |
| p[1] = image[4 * (j * width + i) + 1]; |
| p[2] = image[4 * (j * width + i) + 2]; |
| p[3] = 0xff; |
| } else { |
| p[0] = borderColorIn[0] * 0xff; |
| p[1] = borderColorIn[1] * 0xff; |
| p[2] = borderColorIn[2] * 0xff; |
| p[3] = borderColorIn[3] * 0xff; |
| } |
| p += 4; |
| } |
| } |
| free(image); |
| *wOut = w; |
| *hOut = h; |
| *imgOut = img; |
| } |
| #endif |
| |
| |
| /*****************************************************************/ |
| |
| /* Load the image file specified on the command line as the current texture */ |
| void |
| loadImageTextures(void) |
| { |
| GLfloat borderColor[4] = |
| {1.0, 1.0, 1.0, 1.0}; |
| int tex; |
| |
| for (tex = 0; tex < NumTextures; tex++) { |
| GLubyte *image, *texData3, *texData4; |
| GLint imgWidth, imgHeight; |
| GLenum imgFormat; |
| int i, j; |
| |
| printf("loading %s\n", texFilename[tex]); |
| image = LoadRGBImage(texFilename[tex], &imgWidth, &imgHeight, &imgFormat); |
| if (!image) { |
| printf("can't find %s\n", texFilename[tex]); |
| exit(1); |
| } |
| assert(imgFormat == GL_RGB); |
| |
| /* scale to 256x256 */ |
| texData3 = malloc(256 * 256 * 4); |
| texData4 = malloc(256 * 256 * 4); |
| assert(texData3); |
| assert(texData4); |
| gluScaleImage(imgFormat, imgWidth, imgHeight, GL_UNSIGNED_BYTE, image, |
| 256, 256, GL_UNSIGNED_BYTE, texData3); |
| |
| /* convert to rgba */ |
| for (i = 0; i < 256 * 256; i++) { |
| texData4[i*4+0] = texData3[i*3+0]; |
| texData4[i*4+1] = texData3[i*3+1]; |
| texData4[i*4+2] = texData3[i*3+2]; |
| texData4[i*4+3] = 128; |
| } |
| |
| /* put transparent border around image */ |
| for (i = 0; i < 256; i++) { |
| texData4[i*4+0] = 255; |
| texData4[i*4+1] = 255; |
| texData4[i*4+2] = 255; |
| texData4[i*4+3] = 0; |
| } |
| j = 256 * 255 * 4; |
| for (i = 0; i < 256; i++) { |
| texData4[j + i*4+0] = 255; |
| texData4[j + i*4+1] = 255; |
| texData4[j + i*4+2] = 255; |
| texData4[j + i*4+3] = 0; |
| } |
| for (i = 0; i < 256; i++) { |
| j = i * 256 * 4; |
| texData4[j+0] = 255; |
| texData4[j+1] = 255; |
| texData4[j+2] = 255; |
| texData4[j+3] = 0; |
| } |
| for (i = 0; i < 256; i++) { |
| j = i * 256 * 4 + 255 * 4; |
| texData4[j+0] = 255; |
| texData4[j+1] = 255; |
| texData4[j+2] = 255; |
| texData4[j+3] = 0; |
| } |
| |
| ActiveTexture(GL_TEXTURE0_ARB + tex); |
| glBindTexture(GL_TEXTURE_2D, tex + 1); |
| |
| glPixelStorei(GL_UNPACK_ALIGNMENT, 1); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, |
| GL_RGBA, GL_UNSIGNED_BYTE, texData4); |
| |
| if (linearFilter) { |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
| } else { |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| } |
| glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor); |
| } |
| } |
| |
| /* Create a simple spotlight pattern and make it the current texture */ |
| void |
| loadSpotlightTexture(void) |
| { |
| static int texWidth = 64, texHeight = 64; |
| static GLubyte *texData; |
| GLfloat borderColor[4] = |
| {0.1, 0.1, 0.1, 1.0}; |
| |
| if (!texData) { |
| GLubyte *p; |
| int i, j; |
| |
| texData = (GLubyte *) malloc(texWidth * texHeight * 4 * sizeof(GLubyte)); |
| |
| p = texData; |
| for (j = 0; j < texHeight; ++j) { |
| float dy = (texHeight * 0.5 - j + 0.5) / (texHeight * 0.5); |
| |
| for (i = 0; i < texWidth; ++i) { |
| float dx = (texWidth * 0.5 - i + 0.5) / (texWidth * 0.5); |
| float r = cos(M_PI / 2.0 * sqrt(dx * dx + dy * dy)); |
| float c; |
| |
| r = (r < 0) ? 0 : r * r; |
| c = 0xff * (r + borderColor[0]); |
| p[0] = (c <= 0xff) ? c : 0xff; |
| c = 0xff * (r + borderColor[1]); |
| p[1] = (c <= 0xff) ? c : 0xff; |
| c = 0xff * (r + borderColor[2]); |
| p[2] = (c <= 0xff) ? c : 0xff; |
| c = 0xff * (r + borderColor[3]); |
| p[3] = (c <= 0xff) ? c : 0xff; |
| p += 4; |
| } |
| } |
| } |
| if (linearFilter) { |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
| } else { |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| } |
| glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor); |
| gluBuild2DMipmaps(GL_TEXTURE_2D, 4, texWidth, texHeight, |
| GL_RGBA, GL_UNSIGNED_BYTE, texData); |
| } |
| |
| /*****************************************************************/ |
| |
| void |
| checkErrors(void) |
| { |
| GLenum error; |
| while ((error = glGetError()) != GL_NO_ERROR) { |
| fprintf(stderr, "Error: %s\n", (char *) gluErrorString(error)); |
| } |
| } |
| |
| void |
| drawCube(void) |
| { |
| glBegin(GL_QUADS); |
| |
| glNormal3f(-1.0, 0.0, 0.0); |
| glColor3f(0.80, 0.50, 0.50); |
| glVertex3f(-0.5, -0.5, -0.5); |
| glVertex3f(-0.5, -0.5, 0.5); |
| glVertex3f(-0.5, 0.5, 0.5); |
| glVertex3f(-0.5, 0.5, -0.5); |
| |
| glNormal3f(1.0, 0.0, 0.0); |
| glColor3f(0.50, 0.80, 0.50); |
| glVertex3f(0.5, 0.5, 0.5); |
| glVertex3f(0.5, -0.5, 0.5); |
| glVertex3f(0.5, -0.5, -0.5); |
| glVertex3f(0.5, 0.5, -0.5); |
| |
| glNormal3f(0.0, -1.0, 0.0); |
| glColor3f(0.50, 0.50, 0.80); |
| glVertex3f(-0.5, -0.5, -0.5); |
| glVertex3f(0.5, -0.5, -0.5); |
| glVertex3f(0.5, -0.5, 0.5); |
| glVertex3f(-0.5, -0.5, 0.5); |
| |
| glNormal3f(0.0, 1.0, 0.0); |
| glColor3f(0.50, 0.80, 0.80); |
| glVertex3f(0.5, 0.5, 0.5); |
| glVertex3f(0.5, 0.5, -0.5); |
| glVertex3f(-0.5, 0.5, -0.5); |
| glVertex3f(-0.5, 0.5, 0.5); |
| |
| glNormal3f(0.0, 0.0, -1.0); |
| glColor3f(0.80, 0.50, 0.80); |
| glVertex3f(-0.5, -0.5, -0.5); |
| glVertex3f(-0.5, 0.5, -0.5); |
| glVertex3f(0.5, 0.5, -0.5); |
| glVertex3f(0.5, -0.5, -0.5); |
| |
| glNormal3f(0.0, 0.0, 1.0); |
| glColor3f(1.00, 0.80, 0.50); |
| glVertex3f(0.5, 0.5, 0.5); |
| glVertex3f(-0.5, 0.5, 0.5); |
| glVertex3f(-0.5, -0.5, 0.5); |
| glVertex3f(0.5, -0.5, 0.5); |
| glEnd(); |
| } |
| |
| void |
| drawDodecahedron(void) |
| { |
| #define A (0.5 * 1.61803) /* (sqrt(5) + 1) / 2 */ |
| #define B (0.5 * 0.61803) /* (sqrt(5) - 1) / 2 */ |
| #define C (0.5 * 1.0) |
| GLfloat vertexes[20][3] = |
| { |
| {-A, 0.0, B}, |
| {-A, 0.0, -B}, |
| {A, 0.0, -B}, |
| {A, 0.0, B}, |
| {B, -A, 0.0}, |
| {-B, -A, 0.0}, |
| {-B, A, 0.0}, |
| {B, A, 0.0}, |
| {0.0, B, -A}, |
| {0.0, -B, -A}, |
| {0.0, -B, A}, |
| {0.0, B, A}, |
| {-C, -C, C}, |
| {-C, -C, -C}, |
| {C, -C, -C}, |
| {C, -C, C}, |
| {-C, C, C}, |
| {-C, C, -C}, |
| {C, C, -C}, |
| {C, C, C}, |
| }; |
| #undef A |
| #undef B |
| #undef C |
| GLint polygons[12][5] = |
| { |
| {0, 12, 10, 11, 16}, |
| {1, 17, 8, 9, 13}, |
| {2, 14, 9, 8, 18}, |
| {3, 19, 11, 10, 15}, |
| {4, 14, 2, 3, 15}, |
| {5, 12, 0, 1, 13}, |
| {6, 17, 1, 0, 16}, |
| {7, 19, 3, 2, 18}, |
| {8, 17, 6, 7, 18}, |
| {9, 14, 4, 5, 13}, |
| {10, 12, 5, 4, 15}, |
| {11, 19, 7, 6, 16}, |
| }; |
| int i; |
| |
| glColor3f(0.75, 0.75, 0.75); |
| for (i = 0; i < 12; ++i) { |
| GLfloat *p0, *p1, *p2, d; |
| GLfloat u[3], v[3], n[3]; |
| |
| p0 = &vertexes[polygons[i][0]][0]; |
| p1 = &vertexes[polygons[i][1]][0]; |
| p2 = &vertexes[polygons[i][2]][0]; |
| |
| u[0] = p2[0] - p1[0]; |
| u[1] = p2[1] - p1[1]; |
| u[2] = p2[2] - p1[2]; |
| |
| v[0] = p0[0] - p1[0]; |
| v[1] = p0[1] - p1[1]; |
| v[2] = p0[2] - p1[2]; |
| |
| n[0] = u[1] * v[2] - u[2] * v[1]; |
| n[1] = u[2] * v[0] - u[0] * v[2]; |
| n[2] = u[0] * v[1] - u[1] * v[0]; |
| |
| d = 1.0 / sqrt(n[0] * n[0] + n[1] * n[1] + n[2] * n[2]); |
| n[0] *= d; |
| n[1] *= d; |
| n[2] *= d; |
| |
| glBegin(GL_POLYGON); |
| glNormal3fv(n); |
| glVertex3fv(p0); |
| glVertex3fv(p1); |
| glVertex3fv(p2); |
| glVertex3fv(vertexes[polygons[i][3]]); |
| glVertex3fv(vertexes[polygons[i][4]]); |
| glEnd(); |
| } |
| } |
| |
| void |
| drawSphere(void) |
| { |
| int numMajor = 24; |
| int numMinor = 32; |
| float radius = 0.8; |
| double majorStep = (M_PI / numMajor); |
| double minorStep = (2.0 * M_PI / numMinor); |
| int i, j; |
| |
| glColor3f(0.50, 0.50, 0.50); |
| for (i = 0; i < numMajor; ++i) { |
| double a = i * majorStep; |
| double b = a + majorStep; |
| double r0 = radius * sin(a); |
| double r1 = radius * sin(b); |
| GLfloat z0 = radius * cos(a); |
| GLfloat z1 = radius * cos(b); |
| |
| glBegin(GL_TRIANGLE_STRIP); |
| for (j = 0; j <= numMinor; ++j) { |
| double c = j * minorStep; |
| GLfloat x = cos(c); |
| GLfloat y = sin(c); |
| |
| glNormal3f((x * r0) / radius, (y * r0) / radius, z0 / radius); |
| glTexCoord2f(j / (GLfloat) numMinor, i / (GLfloat) numMajor); |
| glVertex3f(x * r0, y * r0, z0); |
| |
| glNormal3f((x * r1) / radius, (y * r1) / radius, z1 / radius); |
| glTexCoord2f(j / (GLfloat) numMinor, (i + 1) / (GLfloat) numMajor); |
| glVertex3f(x * r1, y * r1, z1); |
| } |
| glEnd(); |
| } |
| } |
| |
| /*****************************************************************/ |
| |
| float xmin = -0.035, xmax = 0.035; |
| float ymin = -0.035, ymax = 0.035; |
| float nnear = 0.1; |
| float ffar = 1.9; |
| float distance = -1.0; |
| |
| static void |
| loadTextureProjection(int texUnit, GLfloat m[16]) |
| { |
| GLfloat mInverse[4][4]; |
| |
| /* Should use true inverse, but since m consists only of rotations, we can |
| just use the transpose. */ |
| matrixTranspose((GLfloat *) mInverse, m); |
| |
| ActiveTexture(GL_TEXTURE0_ARB + texUnit); |
| glMatrixMode(GL_TEXTURE); |
| glLoadIdentity(); |
| glTranslatef(0.5, 0.5, 0.0); |
| glScalef(0.5, 0.5, 1.0); |
| glFrustum(xmin, xmax, ymin, ymax, nnear, ffar); |
| glTranslatef(0.0, 0.0, distance); |
| glMultMatrixf((GLfloat *) mInverse); |
| glMatrixMode(GL_MODELVIEW); |
| } |
| |
| static void |
| drawTextureProjection(void) |
| { |
| float t = ffar / nnear; |
| GLfloat n[4][3]; |
| GLfloat f[4][3]; |
| |
| n[0][0] = xmin; |
| n[0][1] = ymin; |
| n[0][2] = -(nnear + distance); |
| |
| n[1][0] = xmax; |
| n[1][1] = ymin; |
| n[1][2] = -(nnear + distance); |
| |
| n[2][0] = xmax; |
| n[2][1] = ymax; |
| n[2][2] = -(nnear + distance); |
| |
| n[3][0] = xmin; |
| n[3][1] = ymax; |
| n[3][2] = -(nnear + distance); |
| |
| f[0][0] = xmin * t; |
| f[0][1] = ymin * t; |
| f[0][2] = -(ffar + distance); |
| |
| f[1][0] = xmax * t; |
| f[1][1] = ymin * t; |
| f[1][2] = -(ffar + distance); |
| |
| f[2][0] = xmax * t; |
| f[2][1] = ymax * t; |
| f[2][2] = -(ffar + distance); |
| |
| f[3][0] = xmin * t; |
| f[3][1] = ymax * t; |
| f[3][2] = -(ffar + distance); |
| |
| glColor3f(1.0, 1.0, 0.0); |
| glBegin(GL_LINE_LOOP); |
| glVertex3fv(n[0]); |
| glVertex3fv(n[1]); |
| glVertex3fv(n[2]); |
| glVertex3fv(n[3]); |
| glVertex3fv(f[3]); |
| glVertex3fv(f[2]); |
| glVertex3fv(f[1]); |
| glVertex3fv(f[0]); |
| glVertex3fv(n[0]); |
| glVertex3fv(n[1]); |
| glVertex3fv(f[1]); |
| glVertex3fv(f[0]); |
| glVertex3fv(f[3]); |
| glVertex3fv(f[2]); |
| glVertex3fv(n[2]); |
| glVertex3fv(n[3]); |
| glEnd(); |
| } |
| |
| /*****************************************************************/ |
| |
| void |
| initialize(void) |
| { |
| GLfloat light0Pos[4] = |
| {0.3, 0.3, 0.0, 1.0}; |
| GLfloat matAmb[4] = |
| {0.01, 0.01, 0.01, 1.00}; |
| GLfloat matDiff[4] = |
| {0.65, 0.65, 0.65, 1.00}; |
| GLfloat matSpec[4] = |
| {0.30, 0.30, 0.30, 1.00}; |
| GLfloat matShine = 10.0; |
| GLfloat eyePlaneS[] = |
| {1.0, 0.0, 0.0, 0.0}; |
| GLfloat eyePlaneT[] = |
| {0.0, 1.0, 0.0, 0.0}; |
| GLfloat eyePlaneR[] = |
| {0.0, 0.0, 1.0, 0.0}; |
| GLfloat eyePlaneQ[] = |
| {0.0, 0.0, 0.0, 1.0}; |
| int i; |
| |
| /* Setup Misc. */ |
| glClearColor(0.41, 0.41, 0.31, 0.0); |
| |
| glEnable(GL_DEPTH_TEST); |
| |
| /* glLineWidth(2.0);*/ |
| |
| glCullFace(GL_FRONT); |
| glEnable(GL_CULL_FACE); |
| |
| glMatrixMode(GL_PROJECTION); |
| glFrustum(-0.5, 0.5, -0.5, 0.5, 1, 3); |
| glMatrixMode(GL_MODELVIEW); |
| glTranslatef(0, 0, -2); |
| |
| matrixIdentity((GLfloat *) objectXform); |
| for (i = 0; i < NumTextures; i++) { |
| matrixIdentity((GLfloat *) textureXform[i]); |
| } |
| |
| glMatrixMode(GL_PROJECTION); |
| glPushMatrix(); |
| glLoadIdentity(); |
| glOrtho(0, 1, 0, 1, -1, 1); |
| glMatrixMode(GL_MODELVIEW); |
| glPushMatrix(); |
| glLoadIdentity(); |
| |
| glRasterPos2i(0, 0); |
| |
| glPopMatrix(); |
| glMatrixMode(GL_PROJECTION); |
| glPopMatrix(); |
| glMatrixMode(GL_MODELVIEW); |
| |
| /* Setup Lighting */ |
| glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, matAmb); |
| glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, matDiff); |
| glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, matSpec); |
| glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, matShine); |
| |
| glEnable(GL_COLOR_MATERIAL); |
| |
| glLightfv(GL_LIGHT0, GL_POSITION, light0Pos); |
| glEnable(GL_LIGHT0); |
| |
| glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE); |
| glEnable(GL_LIGHTING); |
| |
| /* Setup Texture */ |
| |
| (*loadTexture) (); |
| |
| |
| for (i = 0; i < NumTextures; i++) { |
| ActiveTexture(GL_TEXTURE0_ARB + i); |
| |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); |
| glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); |
| |
| glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); |
| glTexGenfv(GL_S, GL_EYE_PLANE, eyePlaneS); |
| |
| glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); |
| glTexGenfv(GL_T, GL_EYE_PLANE, eyePlaneT); |
| |
| glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); |
| glTexGenfv(GL_R, GL_EYE_PLANE, eyePlaneR); |
| |
| glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); |
| glTexGenfv(GL_Q, GL_EYE_PLANE, eyePlaneQ); |
| } |
| } |
| |
| void |
| display(void) |
| { |
| int i; |
| |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
| |
| if (textureEnabled) { |
| if (mode == MoveTexture || mode == MoveView) { |
| /* Have OpenGL compute the new transformation (simple but slow). */ |
| for (i = 0; i < NumTextures; i++) { |
| glPushMatrix(); |
| glLoadIdentity(); |
| #if 0 |
| if (i & 1) |
| glRotatef(angle, axis[0], axis[1], axis[2]); |
| else |
| #endif |
| glRotatef(angle*(i+1), axis[0], axis[1], axis[2]); |
| |
| glMultMatrixf((GLfloat *) textureXform[i]); |
| glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat *) textureXform[i]); |
| glPopMatrix(); |
| } |
| } |
| for (i = 0; i < NumTextures; i++) { |
| loadTextureProjection(i, (GLfloat *) textureXform[i]); |
| } |
| |
| if (showProjection) { |
| for (i = 0; i < NumTextures; i++) { |
| ActiveTexture(GL_TEXTURE0_ARB + i); |
| glPushMatrix(); |
| glMultMatrixf((GLfloat *) textureXform[i]); |
| glDisable(GL_LIGHTING); |
| drawTextureProjection(); |
| glEnable(GL_LIGHTING); |
| glPopMatrix(); |
| } |
| } |
| for (i = 0; i < NumTextures; i++) { |
| ActiveTexture(GL_TEXTURE0_ARB + i); |
| glEnable(GL_TEXTURE_2D); |
| glEnable(GL_TEXTURE_GEN_S); |
| glEnable(GL_TEXTURE_GEN_T); |
| glEnable(GL_TEXTURE_GEN_R); |
| glEnable(GL_TEXTURE_GEN_Q); |
| } |
| } |
| if (mode == MoveObject || mode == MoveView) { |
| /* Have OpenGL compute the new transformation (simple but slow). */ |
| glPushMatrix(); |
| glLoadIdentity(); |
| glRotatef(angle, axis[0], axis[1], axis[2]); |
| glMultMatrixf((GLfloat *) objectXform); |
| glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat *) objectXform); |
| glPopMatrix(); |
| } |
| glPushMatrix(); |
| glMultMatrixf((GLfloat *) objectXform); |
| (*drawObject) (); |
| glPopMatrix(); |
| |
| for (i = 0; i < NumTextures; i++) { |
| ActiveTexture(GL_TEXTURE0_ARB + i); |
| glDisable(GL_TEXTURE_2D); |
| glDisable(GL_TEXTURE_GEN_S); |
| glDisable(GL_TEXTURE_GEN_T); |
| glDisable(GL_TEXTURE_GEN_R); |
| glDisable(GL_TEXTURE_GEN_Q); |
| } |
| |
| if (zoomFactor > 1.0) { |
| glDisable(GL_DEPTH_TEST); |
| glCopyPixels(0, 0, winWidth / zoomFactor, winHeight / zoomFactor, GL_COLOR); |
| glEnable(GL_DEPTH_TEST); |
| } |
| glFlush(); |
| glutSwapBuffers(); |
| checkErrors(); |
| } |
| |
| /*****************************************************************/ |
| |
| /* simple trackball-like motion control */ |
| float lastPos[3]; |
| int lastTime; |
| |
| void |
| ptov(int x, int y, int width, int height, float v[3]) |
| { |
| float d, a; |
| |
| /* project x,y onto a hemi-sphere centered within width, height */ |
| v[0] = (2.0 * x - width) / width; |
| v[1] = (height - 2.0 * y) / height; |
| d = sqrt(v[0] * v[0] + v[1] * v[1]); |
| v[2] = cos((M_PI / 2.0) * ((d < 1.0) ? d : 1.0)); |
| a = 1.0 / sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); |
| v[0] *= a; |
| v[1] *= a; |
| v[2] *= a; |
| } |
| |
| void |
| startMotion(int x, int y, int but, int time) |
| { |
| if (but == GLUT_LEFT_BUTTON) { |
| mode = MoveView; |
| } else if (but == GLUT_MIDDLE_BUTTON) { |
| mode = MoveTexture; |
| } else { |
| return; |
| } |
| |
| lastTime = time; |
| ptov(x, y, winWidth, winHeight, lastPos); |
| } |
| |
| void |
| animate(void) |
| { |
| glutPostRedisplay(); |
| } |
| |
| void |
| vis(int visible) |
| { |
| if (visible == GLUT_VISIBLE) { |
| if (redrawContinuously) |
| glutIdleFunc(animate); |
| } else { |
| if (redrawContinuously) |
| glutIdleFunc(NULL); |
| } |
| } |
| |
| void |
| stopMotion(int but, int time) |
| { |
| if ((but == GLUT_LEFT_BUTTON && mode == MoveView) || |
| (but == GLUT_MIDDLE_BUTTON && mode == MoveTexture)) { |
| } else { |
| return; |
| } |
| |
| if (time == lastTime) { |
| /* redrawContinuously = GL_TRUE;*/ |
| glutIdleFunc(animate); |
| } else { |
| angle = 0.0; |
| redrawContinuously = GL_FALSE; |
| glutIdleFunc(0); |
| } |
| if (!redrawContinuously) { |
| mode = MoveNone; |
| } |
| } |
| |
| void |
| trackMotion(int x, int y) |
| { |
| float curPos[3], dx, dy, dz; |
| |
| ptov(x, y, winWidth, winHeight, curPos); |
| |
| dx = curPos[0] - lastPos[0]; |
| dy = curPos[1] - lastPos[1]; |
| dz = curPos[2] - lastPos[2]; |
| angle = 90.0 * sqrt(dx * dx + dy * dy + dz * dz); |
| |
| axis[0] = lastPos[1] * curPos[2] - lastPos[2] * curPos[1]; |
| axis[1] = lastPos[2] * curPos[0] - lastPos[0] * curPos[2]; |
| axis[2] = lastPos[0] * curPos[1] - lastPos[1] * curPos[0]; |
| |
| lastTime = glutGet(GLUT_ELAPSED_TIME); |
| lastPos[0] = curPos[0]; |
| lastPos[1] = curPos[1]; |
| lastPos[2] = curPos[2]; |
| glutPostRedisplay(); |
| } |
| |
| /*****************************************************************/ |
| |
| void |
| object(void) |
| { |
| static int object; |
| |
| object++; |
| object %= 3; |
| switch (object) { |
| case 0: |
| drawObject = drawCube; |
| break; |
| case 1: |
| drawObject = drawDodecahedron; |
| break; |
| case 2: |
| drawObject = drawSphere; |
| break; |
| default: |
| break; |
| } |
| } |
| |
| static void |
| nop(void) |
| { |
| } |
| |
| void |
| texture(void) |
| { |
| static int texture = 0; |
| |
| texture++; |
| texture %= 3; |
| if (texture == 1 && texFilename == NULL) { |
| /* Skip file texture if not loaded. */ |
| texture++; |
| } |
| switch (texture) { |
| case 0: |
| loadTexture = nop; |
| textureEnabled = GL_FALSE; |
| break; |
| case 1: |
| loadTexture = loadImageTextures; |
| (*loadTexture) (); |
| textureEnabled = GL_TRUE; |
| break; |
| case 2: |
| loadTexture = loadSpotlightTexture; |
| (*loadTexture) (); |
| textureEnabled = GL_TRUE; |
| break; |
| default: |
| break; |
| } |
| } |
| |
| void |
| help(void) |
| { |
| printf("'h' - help\n"); |
| printf("'l' - toggle linear/nearest filter\n"); |
| printf("'s' - toggle projection frustum\n"); |
| printf("'t' - toggle projected texture\n"); |
| printf("'o' - toggle object\n"); |
| printf("'z' - increase zoom factor\n"); |
| printf("'Z' - decrease zoom factor\n"); |
| printf("left mouse - move view\n"); |
| printf("middle mouse - move projection\n"); |
| } |
| |
| /* ARGSUSED1 */ |
| void |
| key(unsigned char key, int x, int y) |
| { |
| switch (key) { |
| case '\033': |
| exit(0); |
| break; |
| case 'l': |
| linearFilter = !linearFilter; |
| (*loadTexture) (); |
| break; |
| case 's': |
| showProjection = !showProjection; |
| break; |
| case 't': |
| texture(); |
| break; |
| case 'o': |
| object(); |
| break; |
| case 'z': |
| zoomFactor += 1.0; |
| glPixelZoom(zoomFactor, zoomFactor); |
| glViewport(0, 0, winWidth / zoomFactor, winHeight / zoomFactor); |
| break; |
| case 'Z': |
| zoomFactor -= 1.0; |
| if (zoomFactor < 1.0) |
| zoomFactor = 1.0; |
| glPixelZoom(zoomFactor, zoomFactor); |
| glViewport(0, 0, winWidth / zoomFactor, winHeight / zoomFactor); |
| break; |
| case 'h': |
| help(); |
| break; |
| } |
| glutPostRedisplay(); |
| } |
| |
| void |
| mouse(int button, int state, int x, int y) |
| { |
| if (state == GLUT_DOWN) |
| startMotion(x, y, button, glutGet(GLUT_ELAPSED_TIME)); |
| else if (state == GLUT_UP) |
| stopMotion(button, glutGet(GLUT_ELAPSED_TIME)); |
| glutPostRedisplay(); |
| } |
| |
| void |
| reshape(int w, int h) |
| { |
| winWidth = w; |
| winHeight = h; |
| glViewport(0, 0, w / zoomFactor, h / zoomFactor); |
| } |
| |
| |
| void |
| menu(int selection) |
| { |
| if (selection == 666) { |
| exit(0); |
| } |
| key((unsigned char) selection, 0, 0); |
| } |
| |
| int |
| main(int argc, char **argv) |
| { |
| glutInit(&argc, argv); |
| |
| if (argc > 1) { |
| NumTextures = atoi(argv[1]); |
| } |
| assert(NumTextures <= MAX_TEX); |
| |
| glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE); |
| (void) glutCreateWindow("projtex"); |
| |
| loadTexture = loadImageTextures; |
| drawObject = drawCube; |
| initialize(); |
| glutDisplayFunc(display); |
| glutKeyboardFunc(key); |
| glutReshapeFunc(reshape); |
| glutMouseFunc(mouse); |
| glutMotionFunc(trackMotion); |
| glutVisibilityFunc(vis); |
| glutCreateMenu(menu); |
| glutAddMenuEntry("Toggle showing projection", 's'); |
| glutAddMenuEntry("Switch texture", 't'); |
| glutAddMenuEntry("Switch object", 'o'); |
| glutAddMenuEntry("Toggle filtering", 'l'); |
| glutAddMenuEntry("Quit", 666); |
| glutAttachMenu(GLUT_RIGHT_BUTTON); |
| texture(); |
| glutMainLoop(); |
| return 0; /* ANSI C requires main to return int. */ |
| } |