1 2/* projtex.c - by David Yu and David Blythe, SGI */ 3 4/** 5 ** Demonstrates simple projective texture mapping. 6 ** 7 ** Button1 changes view, Button2 moves texture. 8 ** 9 ** (See: Segal, Korobkin, van Widenfelt, Foran, and Haeberli 10 ** "Fast Shadows and Lighting Effects Using Texture Mapping", SIGGRAPH '92) 11 ** 12 ** 1994,1995 -- David G Yu 13 ** 14 ** cc -o projtex projtex.c texture.c -lglut -lGLU -lGL -lX11 -lm 15 **/ 16 17#include <assert.h> 18#include <stdio.h> 19#include <stdlib.h> 20#include <math.h> 21#include <GL/glew.h> 22#include "glut_wrap.h" 23#include "readtex.h" 24 25 26/* Some <math.h> files do not define M_PI... */ 27#ifndef M_PI 28#define M_PI 3.14159265358979323846 29#endif 30 31#define MAX_TEX 4 32int NumTextures = 1; 33 34int winWidth, winHeight; 35 36GLboolean redrawContinuously = GL_FALSE; 37 38float angle, axis[3]; 39enum MoveModes { 40 MoveNone, MoveView, MoveObject, MoveTexture 41}; 42enum MoveModes mode = MoveNone; 43 44GLfloat objectXform[4][4]; 45GLfloat textureXform[MAX_TEX][4][4]; 46 47void (*drawObject) (void); 48void (*loadTexture) (void); 49GLboolean textureEnabled = GL_TRUE; 50GLboolean showProjection = GL_TRUE; 51GLboolean linearFilter = GL_TRUE; 52 53char *texFilename[MAX_TEX] = { 54 DEMOS_DATA_DIR "girl.rgb", 55 DEMOS_DATA_DIR "tile.rgb", 56 DEMOS_DATA_DIR "bw.rgb", 57 DEMOS_DATA_DIR "reflect.rgb" 58}; 59 60 61GLfloat zoomFactor = 1.0; 62 63/*****************************************************************/ 64 65 66static void 67ActiveTexture(int i) 68{ 69 glActiveTextureARB(i); 70} 71 72 73/* matrix = identity */ 74static void 75matrixIdentity(GLfloat matrix[16]) 76{ 77 matrix[0] = 1.0; 78 matrix[1] = 0.0; 79 matrix[2] = 0.0; 80 matrix[3] = 0.0; 81 matrix[4] = 0.0; 82 matrix[5] = 1.0; 83 matrix[6] = 0.0; 84 matrix[7] = 0.0; 85 matrix[8] = 0.0; 86 matrix[9] = 0.0; 87 matrix[10] = 1.0; 88 matrix[11] = 0.0; 89 matrix[12] = 0.0; 90 matrix[13] = 0.0; 91 matrix[14] = 0.0; 92 matrix[15] = 1.0; 93} 94 95/* matrix2 = transpose(matrix1) */ 96static void 97matrixTranspose(GLfloat matrix2[16], GLfloat matrix1[16]) 98{ 99 matrix2[0] = matrix1[0]; 100 matrix2[1] = matrix1[4]; 101 matrix2[2] = matrix1[8]; 102 matrix2[3] = matrix1[12]; 103 104 matrix2[4] = matrix1[1]; 105 matrix2[5] = matrix1[5]; 106 matrix2[6] = matrix1[9]; 107 matrix2[7] = matrix1[13]; 108 109 matrix2[8] = matrix1[2]; 110 matrix2[9] = matrix1[6]; 111 matrix2[10] = matrix1[10]; 112 matrix2[11] = matrix1[14]; 113 114 matrix2[12] = matrix1[3]; 115 matrix2[13] = matrix1[7]; 116 matrix2[14] = matrix1[14]; 117 matrix2[15] = matrix1[15]; 118} 119 120/*****************************************************************/ 121 122/* load SGI .rgb image (pad with a border of the specified width and color) */ 123#if 0 124static void 125imgLoad(char *filenameIn, int borderIn, GLfloat borderColorIn[4], 126 int *wOut, int *hOut, GLubyte ** imgOut) 127{ 128 int border = borderIn; 129 int width, height; 130 int w, h; 131 GLubyte *image, *img, *p; 132 int i, j, components; 133 134 image = (GLubyte *) read_texture(filenameIn, &width, &height, &components); 135 w = width + 2 * border; 136 h = height + 2 * border; 137 img = (GLubyte *) calloc(w * h, 4 * sizeof(unsigned char)); 138 139 p = img; 140 for (j = -border; j < height + border; ++j) { 141 for (i = -border; i < width + border; ++i) { 142 if (0 <= j && j <= height - 1 && 0 <= i && i <= width - 1) { 143 p[0] = image[4 * (j * width + i) + 0]; 144 p[1] = image[4 * (j * width + i) + 1]; 145 p[2] = image[4 * (j * width + i) + 2]; 146 p[3] = 0xff; 147 } else { 148 p[0] = borderColorIn[0] * 0xff; 149 p[1] = borderColorIn[1] * 0xff; 150 p[2] = borderColorIn[2] * 0xff; 151 p[3] = borderColorIn[3] * 0xff; 152 } 153 p += 4; 154 } 155 } 156 free(image); 157 *wOut = w; 158 *hOut = h; 159 *imgOut = img; 160} 161#endif 162 163 164/*****************************************************************/ 165 166/* Load the image file specified on the command line as the current texture */ 167static void 168loadImageTextures(void) 169{ 170 GLfloat borderColor[4] = 171 {1.0, 1.0, 1.0, 1.0}; 172 int tex; 173 174 for (tex = 0; tex < NumTextures; tex++) { 175 GLubyte *image, *texData3, *texData4; 176 GLint imgWidth, imgHeight; 177 GLenum imgFormat; 178 int i, j; 179 180 printf("loading %s\n", texFilename[tex]); 181 image = LoadRGBImage(texFilename[tex], &imgWidth, &imgHeight, &imgFormat); 182 if (!image) { 183 printf("can't find %s\n", texFilename[tex]); 184 exit(1); 185 } 186 assert(imgFormat == GL_RGB); 187 188 /* scale to 256x256 */ 189 texData3 = malloc(256 * 256 * 4); 190 texData4 = malloc(256 * 256 * 4); 191 assert(texData3); 192 assert(texData4); 193 gluScaleImage(imgFormat, imgWidth, imgHeight, GL_UNSIGNED_BYTE, image, 194 256, 256, GL_UNSIGNED_BYTE, texData3); 195 196 /* convert to rgba */ 197 for (i = 0; i < 256 * 256; i++) { 198 texData4[i*4+0] = texData3[i*3+0]; 199 texData4[i*4+1] = texData3[i*3+1]; 200 texData4[i*4+2] = texData3[i*3+2]; 201 texData4[i*4+3] = 128; 202 } 203 204 /* put transparent border around image */ 205 for (i = 0; i < 256; i++) { 206 texData4[i*4+0] = 255; 207 texData4[i*4+1] = 255; 208 texData4[i*4+2] = 255; 209 texData4[i*4+3] = 0; 210 } 211 j = 256 * 255 * 4; 212 for (i = 0; i < 256; i++) { 213 texData4[j + i*4+0] = 255; 214 texData4[j + i*4+1] = 255; 215 texData4[j + i*4+2] = 255; 216 texData4[j + i*4+3] = 0; 217 } 218 for (i = 0; i < 256; i++) { 219 j = i * 256 * 4; 220 texData4[j+0] = 255; 221 texData4[j+1] = 255; 222 texData4[j+2] = 255; 223 texData4[j+3] = 0; 224 } 225 for (i = 0; i < 256; i++) { 226 j = i * 256 * 4 + 255 * 4; 227 texData4[j+0] = 255; 228 texData4[j+1] = 255; 229 texData4[j+2] = 255; 230 texData4[j+3] = 0; 231 } 232 233 ActiveTexture(GL_TEXTURE0_ARB + tex); 234 glBindTexture(GL_TEXTURE_2D, tex + 1); 235 236 glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 237 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, 238 GL_RGBA, GL_UNSIGNED_BYTE, texData4); 239 240 if (linearFilter) { 241 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 242 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 243 } else { 244 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 245 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 246 } 247 glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor); 248 249 free(texData3); 250 free(texData4); 251 free(image); 252 } 253} 254 255/* Create a simple spotlight pattern and make it the current texture */ 256static void 257loadSpotlightTexture(void) 258{ 259 static int texWidth = 64, texHeight = 64; 260 static GLubyte *texData; 261 GLfloat borderColor[4] = 262 {0.1, 0.1, 0.1, 1.0}; 263 264 if (!texData) { 265 GLubyte *p; 266 int i, j; 267 268 texData = (GLubyte *) malloc(texWidth * texHeight * 4 * sizeof(GLubyte)); 269 270 p = texData; 271 for (j = 0; j < texHeight; ++j) { 272 float dy = (texHeight * 0.5 - j + 0.5) / (texHeight * 0.5); 273 274 for (i = 0; i < texWidth; ++i) { 275 float dx = (texWidth * 0.5 - i + 0.5) / (texWidth * 0.5); 276 float r = cos(M_PI / 2.0 * sqrt(dx * dx + dy * dy)); 277 float c; 278 279 r = (r < 0) ? 0 : r * r; 280 c = 0xff * (r + borderColor[0]); 281 p[0] = (c <= 0xff) ? c : 0xff; 282 c = 0xff * (r + borderColor[1]); 283 p[1] = (c <= 0xff) ? c : 0xff; 284 c = 0xff * (r + borderColor[2]); 285 p[2] = (c <= 0xff) ? c : 0xff; 286 c = 0xff * (r + borderColor[3]); 287 p[3] = (c <= 0xff) ? c : 0xff; 288 p += 4; 289 } 290 } 291 } 292 if (linearFilter) { 293 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 294 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 295 } else { 296 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 297 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 298 } 299 glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor); 300 gluBuild2DMipmaps(GL_TEXTURE_2D, 4, texWidth, texHeight, 301 GL_RGBA, GL_UNSIGNED_BYTE, texData); 302} 303 304/*****************************************************************/ 305 306static void 307checkErrors(void) 308{ 309 GLenum error; 310 while ((error = glGetError()) != GL_NO_ERROR) { 311 fprintf(stderr, "Error: %s\n", (char *) gluErrorString(error)); 312 } 313} 314 315static void 316drawCube(void) 317{ 318 glBegin(GL_QUADS); 319 320 glNormal3f(-1.0, 0.0, 0.0); 321 glColor3f(0.80, 0.50, 0.50); 322 glVertex3f(-0.5, -0.5, -0.5); 323 glVertex3f(-0.5, -0.5, 0.5); 324 glVertex3f(-0.5, 0.5, 0.5); 325 glVertex3f(-0.5, 0.5, -0.5); 326 327 glNormal3f(1.0, 0.0, 0.0); 328 glColor3f(0.50, 0.80, 0.50); 329 glVertex3f(0.5, 0.5, 0.5); 330 glVertex3f(0.5, -0.5, 0.5); 331 glVertex3f(0.5, -0.5, -0.5); 332 glVertex3f(0.5, 0.5, -0.5); 333 334 glNormal3f(0.0, -1.0, 0.0); 335 glColor3f(0.50, 0.50, 0.80); 336 glVertex3f(-0.5, -0.5, -0.5); 337 glVertex3f(0.5, -0.5, -0.5); 338 glVertex3f(0.5, -0.5, 0.5); 339 glVertex3f(-0.5, -0.5, 0.5); 340 341 glNormal3f(0.0, 1.0, 0.0); 342 glColor3f(0.50, 0.80, 0.80); 343 glVertex3f(0.5, 0.5, 0.5); 344 glVertex3f(0.5, 0.5, -0.5); 345 glVertex3f(-0.5, 0.5, -0.5); 346 glVertex3f(-0.5, 0.5, 0.5); 347 348 glNormal3f(0.0, 0.0, -1.0); 349 glColor3f(0.80, 0.50, 0.80); 350 glVertex3f(-0.5, -0.5, -0.5); 351 glVertex3f(-0.5, 0.5, -0.5); 352 glVertex3f(0.5, 0.5, -0.5); 353 glVertex3f(0.5, -0.5, -0.5); 354 355 glNormal3f(0.0, 0.0, 1.0); 356 glColor3f(1.00, 0.80, 0.50); 357 glVertex3f(0.5, 0.5, 0.5); 358 glVertex3f(-0.5, 0.5, 0.5); 359 glVertex3f(-0.5, -0.5, 0.5); 360 glVertex3f(0.5, -0.5, 0.5); 361 glEnd(); 362} 363 364static void 365drawDodecahedron(void) 366{ 367#define A (0.5 * 1.61803) /* (sqrt(5) + 1) / 2 */ 368#define B (0.5 * 0.61803) /* (sqrt(5) - 1) / 2 */ 369#define C (0.5 * 1.0) 370 GLfloat vertexes[20][3] = 371 { 372 {-A, 0.0, B}, 373 {-A, 0.0, -B}, 374 {A, 0.0, -B}, 375 {A, 0.0, B}, 376 {B, -A, 0.0}, 377 {-B, -A, 0.0}, 378 {-B, A, 0.0}, 379 {B, A, 0.0}, 380 {0.0, B, -A}, 381 {0.0, -B, -A}, 382 {0.0, -B, A}, 383 {0.0, B, A}, 384 {-C, -C, C}, 385 {-C, -C, -C}, 386 {C, -C, -C}, 387 {C, -C, C}, 388 {-C, C, C}, 389 {-C, C, -C}, 390 {C, C, -C}, 391 {C, C, C}, 392 }; 393#undef A 394#undef B 395#undef C 396 GLint polygons[12][5] = 397 { 398 {0, 12, 10, 11, 16}, 399 {1, 17, 8, 9, 13}, 400 {2, 14, 9, 8, 18}, 401 {3, 19, 11, 10, 15}, 402 {4, 14, 2, 3, 15}, 403 {5, 12, 0, 1, 13}, 404 {6, 17, 1, 0, 16}, 405 {7, 19, 3, 2, 18}, 406 {8, 17, 6, 7, 18}, 407 {9, 14, 4, 5, 13}, 408 {10, 12, 5, 4, 15}, 409 {11, 19, 7, 6, 16}, 410 }; 411 int i; 412 413 glColor3f(0.75, 0.75, 0.75); 414 for (i = 0; i < 12; ++i) { 415 GLfloat *p0, *p1, *p2, d; 416 GLfloat u[3], v[3], n[3]; 417 418 p0 = &vertexes[polygons[i][0]][0]; 419 p1 = &vertexes[polygons[i][1]][0]; 420 p2 = &vertexes[polygons[i][2]][0]; 421 422 u[0] = p2[0] - p1[0]; 423 u[1] = p2[1] - p1[1]; 424 u[2] = p2[2] - p1[2]; 425 426 v[0] = p0[0] - p1[0]; 427 v[1] = p0[1] - p1[1]; 428 v[2] = p0[2] - p1[2]; 429 430 n[0] = u[1] * v[2] - u[2] * v[1]; 431 n[1] = u[2] * v[0] - u[0] * v[2]; 432 n[2] = u[0] * v[1] - u[1] * v[0]; 433 434 d = 1.0 / sqrt(n[0] * n[0] + n[1] * n[1] + n[2] * n[2]); 435 n[0] *= d; 436 n[1] *= d; 437 n[2] *= d; 438 439 glBegin(GL_POLYGON); 440 glNormal3fv(n); 441 glVertex3fv(p0); 442 glVertex3fv(p1); 443 glVertex3fv(p2); 444 glVertex3fv(vertexes[polygons[i][3]]); 445 glVertex3fv(vertexes[polygons[i][4]]); 446 glEnd(); 447 } 448} 449 450static void 451drawSphere(void) 452{ 453 int numMajor = 24; 454 int numMinor = 32; 455 float radius = 0.8; 456 double majorStep = (M_PI / numMajor); 457 double minorStep = (2.0 * M_PI / numMinor); 458 int i, j; 459 460 glColor3f(0.50, 0.50, 0.50); 461 for (i = 0; i < numMajor; ++i) { 462 double a = i * majorStep; 463 double b = a + majorStep; 464 double r0 = radius * sin(a); 465 double r1 = radius * sin(b); 466 GLfloat z0 = radius * cos(a); 467 GLfloat z1 = radius * cos(b); 468 469 glBegin(GL_TRIANGLE_STRIP); 470 for (j = 0; j <= numMinor; ++j) { 471 double c = j * minorStep; 472 GLfloat x = cos(c); 473 GLfloat y = sin(c); 474 475 glNormal3f((x * r0) / radius, (y * r0) / radius, z0 / radius); 476 glTexCoord2f(j / (GLfloat) numMinor, i / (GLfloat) numMajor); 477 glVertex3f(x * r0, y * r0, z0); 478 479 glNormal3f((x * r1) / radius, (y * r1) / radius, z1 / radius); 480 glTexCoord2f(j / (GLfloat) numMinor, (i + 1) / (GLfloat) numMajor); 481 glVertex3f(x * r1, y * r1, z1); 482 } 483 glEnd(); 484 } 485} 486 487/*****************************************************************/ 488 489float xmin = -0.035, xmax = 0.035; 490float ymin = -0.035, ymax = 0.035; 491float nnear = 0.1; 492float ffar = 1.9; 493float distance = -1.0; 494 495static void 496loadTextureProjection(int texUnit, GLfloat m[16]) 497{ 498 GLfloat mInverse[4][4]; 499 500 /* Should use true inverse, but since m consists only of rotations, we can 501 just use the transpose. */ 502 matrixTranspose((GLfloat *) mInverse, m); 503 504 ActiveTexture(GL_TEXTURE0_ARB + texUnit); 505 glMatrixMode(GL_TEXTURE); 506 glLoadIdentity(); 507 glTranslatef(0.5, 0.5, 0.0); 508 glScalef(0.5, 0.5, 1.0); 509 glFrustum(xmin, xmax, ymin, ymax, nnear, ffar); 510 glTranslatef(0.0, 0.0, distance); 511 glMultMatrixf((GLfloat *) mInverse); 512 glMatrixMode(GL_MODELVIEW); 513} 514 515static void 516drawTextureProjection(void) 517{ 518 float t = ffar / nnear; 519 GLfloat n[4][3]; 520 GLfloat f[4][3]; 521 522 n[0][0] = xmin; 523 n[0][1] = ymin; 524 n[0][2] = -(nnear + distance); 525 526 n[1][0] = xmax; 527 n[1][1] = ymin; 528 n[1][2] = -(nnear + distance); 529 530 n[2][0] = xmax; 531 n[2][1] = ymax; 532 n[2][2] = -(nnear + distance); 533 534 n[3][0] = xmin; 535 n[3][1] = ymax; 536 n[3][2] = -(nnear + distance); 537 538 f[0][0] = xmin * t; 539 f[0][1] = ymin * t; 540 f[0][2] = -(ffar + distance); 541 542 f[1][0] = xmax * t; 543 f[1][1] = ymin * t; 544 f[1][2] = -(ffar + distance); 545 546 f[2][0] = xmax * t; 547 f[2][1] = ymax * t; 548 f[2][2] = -(ffar + distance); 549 550 f[3][0] = xmin * t; 551 f[3][1] = ymax * t; 552 f[3][2] = -(ffar + distance); 553 554 glColor3f(1.0, 1.0, 0.0); 555 glBegin(GL_LINE_LOOP); 556 glVertex3fv(n[0]); 557 glVertex3fv(n[1]); 558 glVertex3fv(n[2]); 559 glVertex3fv(n[3]); 560 glVertex3fv(f[3]); 561 glVertex3fv(f[2]); 562 glVertex3fv(f[1]); 563 glVertex3fv(f[0]); 564 glVertex3fv(n[0]); 565 glVertex3fv(n[1]); 566 glVertex3fv(f[1]); 567 glVertex3fv(f[0]); 568 glVertex3fv(f[3]); 569 glVertex3fv(f[2]); 570 glVertex3fv(n[2]); 571 glVertex3fv(n[3]); 572 glEnd(); 573} 574 575/*****************************************************************/ 576 577static void 578initialize(void) 579{ 580 GLfloat light0Pos[4] = 581 {0.3, 0.3, 0.0, 1.0}; 582 GLfloat matAmb[4] = 583 {0.01, 0.01, 0.01, 1.00}; 584 GLfloat matDiff[4] = 585 {0.65, 0.65, 0.65, 1.00}; 586 GLfloat matSpec[4] = 587 {0.30, 0.30, 0.30, 1.00}; 588 GLfloat matShine = 10.0; 589 GLfloat eyePlaneS[] = 590 {1.0, 0.0, 0.0, 0.0}; 591 GLfloat eyePlaneT[] = 592 {0.0, 1.0, 0.0, 0.0}; 593 GLfloat eyePlaneR[] = 594 {0.0, 0.0, 1.0, 0.0}; 595 GLfloat eyePlaneQ[] = 596 {0.0, 0.0, 0.0, 1.0}; 597 int i; 598 599 /* Setup Misc. */ 600 glClearColor(0.41, 0.41, 0.31, 0.0); 601 602 glEnable(GL_DEPTH_TEST); 603 604 /* glLineWidth(2.0);*/ 605 606 glCullFace(GL_FRONT); 607 glEnable(GL_CULL_FACE); 608 609 glMatrixMode(GL_PROJECTION); 610 glFrustum(-0.5, 0.5, -0.5, 0.5, 1, 3); 611 glMatrixMode(GL_MODELVIEW); 612 glTranslatef(0, 0, -2); 613 614 matrixIdentity((GLfloat *) objectXform); 615 for (i = 0; i < NumTextures; i++) { 616 matrixIdentity((GLfloat *) textureXform[i]); 617 } 618 619 glMatrixMode(GL_PROJECTION); 620 glPushMatrix(); 621 glLoadIdentity(); 622 glOrtho(0, 1, 0, 1, -1, 1); 623 glMatrixMode(GL_MODELVIEW); 624 glPushMatrix(); 625 glLoadIdentity(); 626 627 glRasterPos2i(0, 0); 628 629 glPopMatrix(); 630 glMatrixMode(GL_PROJECTION); 631 glPopMatrix(); 632 glMatrixMode(GL_MODELVIEW); 633 634 /* Setup Lighting */ 635 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, matAmb); 636 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, matDiff); 637 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, matSpec); 638 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, matShine); 639 640 glEnable(GL_COLOR_MATERIAL); 641 642 glLightfv(GL_LIGHT0, GL_POSITION, light0Pos); 643 glEnable(GL_LIGHT0); 644 645 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE); 646 glEnable(GL_LIGHTING); 647 648 /* Setup Texture */ 649 650 (*loadTexture) (); 651 652 653 for (i = 0; i < NumTextures; i++) { 654 ActiveTexture(GL_TEXTURE0_ARB + i); 655 656 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); 657 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); 658 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); 659 660 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); 661 glTexGenfv(GL_S, GL_EYE_PLANE, eyePlaneS); 662 663 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); 664 glTexGenfv(GL_T, GL_EYE_PLANE, eyePlaneT); 665 666 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); 667 glTexGenfv(GL_R, GL_EYE_PLANE, eyePlaneR); 668 669 glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); 670 glTexGenfv(GL_Q, GL_EYE_PLANE, eyePlaneQ); 671 } 672} 673 674static void 675display(void) 676{ 677 int i; 678 679 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 680 681 if (textureEnabled) { 682 if (mode == MoveTexture || mode == MoveView) { 683 /* Have OpenGL compute the new transformation (simple but slow). */ 684 for (i = 0; i < NumTextures; i++) { 685 glPushMatrix(); 686 glLoadIdentity(); 687#if 0 688 if (i & 1) 689 glRotatef(angle, axis[0], axis[1], axis[2]); 690 else 691#endif 692 glRotatef(angle*(i+1), axis[0], axis[1], axis[2]); 693 694 glMultMatrixf((GLfloat *) textureXform[i]); 695 glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat *) textureXform[i]); 696 glPopMatrix(); 697 } 698 } 699 for (i = 0; i < NumTextures; i++) { 700 loadTextureProjection(i, (GLfloat *) textureXform[i]); 701 } 702 703 if (showProjection) { 704 for (i = 0; i < NumTextures; i++) { 705 ActiveTexture(GL_TEXTURE0_ARB + i); 706 glPushMatrix(); 707 glMultMatrixf((GLfloat *) textureXform[i]); 708 glDisable(GL_LIGHTING); 709 drawTextureProjection(); 710 glEnable(GL_LIGHTING); 711 glPopMatrix(); 712 } 713 } 714 for (i = 0; i < NumTextures; i++) { 715 ActiveTexture(GL_TEXTURE0_ARB + i); 716 glEnable(GL_TEXTURE_2D); 717 glEnable(GL_TEXTURE_GEN_S); 718 glEnable(GL_TEXTURE_GEN_T); 719 glEnable(GL_TEXTURE_GEN_R); 720 glEnable(GL_TEXTURE_GEN_Q); 721 } 722 } 723 if (mode == MoveObject || mode == MoveView) { 724 /* Have OpenGL compute the new transformation (simple but slow). */ 725 glPushMatrix(); 726 glLoadIdentity(); 727 glRotatef(angle, axis[0], axis[1], axis[2]); 728 glMultMatrixf((GLfloat *) objectXform); 729 glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat *) objectXform); 730 glPopMatrix(); 731 } 732 glPushMatrix(); 733 glMultMatrixf((GLfloat *) objectXform); 734 (*drawObject) (); 735 glPopMatrix(); 736 737 for (i = 0; i < NumTextures; i++) { 738 ActiveTexture(GL_TEXTURE0_ARB + i); 739 glDisable(GL_TEXTURE_2D); 740 glDisable(GL_TEXTURE_GEN_S); 741 glDisable(GL_TEXTURE_GEN_T); 742 glDisable(GL_TEXTURE_GEN_R); 743 glDisable(GL_TEXTURE_GEN_Q); 744 } 745 746 if (zoomFactor > 1.0) { 747 glDisable(GL_DEPTH_TEST); 748 glCopyPixels(0, 0, winWidth / zoomFactor, winHeight / zoomFactor, GL_COLOR); 749 glEnable(GL_DEPTH_TEST); 750 } 751 glFlush(); 752 glutSwapBuffers(); 753 checkErrors(); 754} 755 756/*****************************************************************/ 757 758/* simple trackball-like motion control */ 759static float lastPos[3]; 760static int lastTime; 761 762static void 763ptov(int x, int y, int width, int height, float v[3]) 764{ 765 float d, a; 766 767 /* project x,y onto a hemi-sphere centered within width, height */ 768 v[0] = (2.0 * x - width) / width; 769 v[1] = (height - 2.0 * y) / height; 770 d = sqrt(v[0] * v[0] + v[1] * v[1]); 771 v[2] = cos((M_PI / 2.0) * ((d < 1.0) ? d : 1.0)); 772 a = 1.0 / sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); 773 v[0] *= a; 774 v[1] *= a; 775 v[2] *= a; 776} 777 778static void 779startMotion(int x, int y, int but, int time) 780{ 781 if (but == GLUT_LEFT_BUTTON) { 782 mode = MoveView; 783 } else if (but == GLUT_MIDDLE_BUTTON) { 784 mode = MoveTexture; 785 } else { 786 return; 787 } 788 789 lastTime = time; 790 ptov(x, y, winWidth, winHeight, lastPos); 791} 792 793static void 794animate(void) 795{ 796 glutPostRedisplay(); 797} 798 799static void 800vis(int visible) 801{ 802 if (visible == GLUT_VISIBLE) { 803 if (redrawContinuously) 804 glutIdleFunc(animate); 805 } else { 806 if (redrawContinuously) 807 glutIdleFunc(NULL); 808 } 809} 810 811static void 812stopMotion(int but, int time) 813{ 814 if ((but == GLUT_LEFT_BUTTON && mode == MoveView) || 815 (but == GLUT_MIDDLE_BUTTON && mode == MoveTexture)) { 816 } else { 817 return; 818 } 819 820 if (time == lastTime) { 821 /* redrawContinuously = GL_TRUE;*/ 822 glutIdleFunc(animate); 823 } else { 824 angle = 0.0; 825 redrawContinuously = GL_FALSE; 826 glutIdleFunc(0); 827 } 828 if (!redrawContinuously) { 829 mode = MoveNone; 830 } 831} 832 833static void 834trackMotion(int x, int y) 835{ 836 float curPos[3], dx, dy, dz; 837 838 ptov(x, y, winWidth, winHeight, curPos); 839 840 dx = curPos[0] - lastPos[0]; 841 dy = curPos[1] - lastPos[1]; 842 dz = curPos[2] - lastPos[2]; 843 angle = 90.0 * sqrt(dx * dx + dy * dy + dz * dz); 844 845 axis[0] = lastPos[1] * curPos[2] - lastPos[2] * curPos[1]; 846 axis[1] = lastPos[2] * curPos[0] - lastPos[0] * curPos[2]; 847 axis[2] = lastPos[0] * curPos[1] - lastPos[1] * curPos[0]; 848 849 lastTime = glutGet(GLUT_ELAPSED_TIME); 850 lastPos[0] = curPos[0]; 851 lastPos[1] = curPos[1]; 852 lastPos[2] = curPos[2]; 853 glutPostRedisplay(); 854} 855 856/*****************************************************************/ 857 858static void 859object(void) 860{ 861 static int object; 862 863 object++; 864 object %= 3; 865 switch (object) { 866 case 0: 867 drawObject = drawCube; 868 break; 869 case 1: 870 drawObject = drawDodecahedron; 871 break; 872 case 2: 873 drawObject = drawSphere; 874 break; 875 default: 876 break; 877 } 878} 879 880static void 881nop(void) 882{ 883} 884 885static void 886texture(void) 887{ 888 static int texture = 0; 889 890 texture++; 891 texture %= 3; 892 if (texture == 1 && texFilename == NULL) { 893 /* Skip file texture if not loaded. */ 894 texture++; 895 } 896 switch (texture) { 897 case 0: 898 loadTexture = nop; 899 textureEnabled = GL_FALSE; 900 break; 901 case 1: 902 loadTexture = loadImageTextures; 903 (*loadTexture) (); 904 textureEnabled = GL_TRUE; 905 break; 906 case 2: 907 loadTexture = loadSpotlightTexture; 908 (*loadTexture) (); 909 textureEnabled = GL_TRUE; 910 break; 911 default: 912 break; 913 } 914} 915 916static void 917help(void) 918{ 919 printf("'h' - help\n"); 920 printf("'l' - toggle linear/nearest filter\n"); 921 printf("'s' - toggle projection frustum\n"); 922 printf("'t' - toggle projected texture\n"); 923 printf("'o' - toggle object\n"); 924 printf("'z' - increase zoom factor\n"); 925 printf("'Z' - decrease zoom factor\n"); 926 printf("left mouse - move view\n"); 927 printf("middle mouse - move projection\n"); 928} 929 930/* ARGSUSED1 */ 931static void 932key(unsigned char key, int x, int y) 933{ 934 switch (key) { 935 case '\033': 936 exit(0); 937 break; 938 case 'l': 939 linearFilter = !linearFilter; 940 (*loadTexture) (); 941 break; 942 case 's': 943 showProjection = !showProjection; 944 break; 945 case 't': 946 texture(); 947 break; 948 case 'o': 949 object(); 950 break; 951 case 'z': 952 zoomFactor += 1.0; 953 glPixelZoom(zoomFactor, zoomFactor); 954 glViewport(0, 0, winWidth / zoomFactor, winHeight / zoomFactor); 955 break; 956 case 'Z': 957 zoomFactor -= 1.0; 958 if (zoomFactor < 1.0) 959 zoomFactor = 1.0; 960 glPixelZoom(zoomFactor, zoomFactor); 961 glViewport(0, 0, winWidth / zoomFactor, winHeight / zoomFactor); 962 break; 963 case 'h': 964 help(); 965 break; 966 } 967 glutPostRedisplay(); 968} 969 970static void 971mouse(int button, int state, int x, int y) 972{ 973 if (state == GLUT_DOWN) 974 startMotion(x, y, button, glutGet(GLUT_ELAPSED_TIME)); 975 else if (state == GLUT_UP) 976 stopMotion(button, glutGet(GLUT_ELAPSED_TIME)); 977 glutPostRedisplay(); 978} 979 980static void 981reshape(int w, int h) 982{ 983 winWidth = w; 984 winHeight = h; 985 glViewport(0, 0, w / zoomFactor, h / zoomFactor); 986} 987 988 989static void 990menu(int selection) 991{ 992 if (selection == 666) { 993 exit(0); 994 } 995 key((unsigned char) selection, 0, 0); 996} 997 998int 999main(int argc, char **argv) 1000{ 1001 glutInitWindowSize(500,500); 1002 glutInit(&argc, argv); 1003 glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE); 1004 (void) glutCreateWindow("projtex"); 1005 glewInit(); 1006 1007 if (argc > 1) { 1008 NumTextures = atoi(argv[1]); 1009 } 1010 assert(NumTextures <= MAX_TEX); 1011 1012 loadTexture = loadImageTextures; 1013 drawObject = drawCube; 1014 initialize(); 1015 glutDisplayFunc(display); 1016 glutKeyboardFunc(key); 1017 glutReshapeFunc(reshape); 1018 glutMouseFunc(mouse); 1019 glutMotionFunc(trackMotion); 1020 glutVisibilityFunc(vis); 1021 glutCreateMenu(menu); 1022 glutAddMenuEntry("Toggle showing projection", 's'); 1023 glutAddMenuEntry("Switch texture", 't'); 1024 glutAddMenuEntry("Switch object", 'o'); 1025 glutAddMenuEntry("Toggle filtering", 'l'); 1026 glutAddMenuEntry("Quit", 666); 1027 glutAttachMenu(GLUT_RIGHT_BUTTON); 1028 texture(); 1029 glutMainLoop(); 1030 return 0; /* ANSI C requires main to return int. */ 1031} 1032