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