Merge branch 'mesa_7_5_branch'
[mesa.git] / progs / demos / 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/glew.h>
22 #include <GL/glut.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
32 int NumTextures = 1;
33
34 int winWidth, winHeight;
35
36 GLboolean redrawContinuously = GL_FALSE;
37
38 float angle, axis[3];
39 enum MoveModes {
40 MoveNone, MoveView, MoveObject, MoveTexture
41 };
42 enum MoveModes mode = MoveNone;
43
44 GLfloat objectXform[4][4];
45 GLfloat textureXform[MAX_TEX][4][4];
46
47 void (*drawObject) (void);
48 void (*loadTexture) (void);
49 GLboolean textureEnabled = GL_TRUE;
50 GLboolean showProjection = GL_TRUE;
51 GLboolean linearFilter = GL_TRUE;
52
53 char *texFilename[MAX_TEX] = {
54 "../images/girl.rgb",
55 "../images/tile.rgb",
56 "../images/bw.rgb",
57 "../images/reflect.rgb"
58 };
59
60
61 GLfloat zoomFactor = 1.0;
62
63 /*****************************************************************/
64
65
66 static void
67 ActiveTexture(int i)
68 {
69 glActiveTextureARB(i);
70 }
71
72
73 /* matrix = identity */
74 static 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 static 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 static 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 static 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 static 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 static 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 static 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 static 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 static 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 static 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 0
684 if (i & 1)
685 glRotatef(angle, axis[0], axis[1], axis[2]);
686 else
687 #endif
688 glRotatef(angle*(i+1), axis[0], axis[1], axis[2]);
689
690 glMultMatrixf((GLfloat *) textureXform[i]);
691 glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat *) textureXform[i]);
692 glPopMatrix();
693 }
694 }
695 for (i = 0; i < NumTextures; i++) {
696 loadTextureProjection(i, (GLfloat *) textureXform[i]);
697 }
698
699 if (showProjection) {
700 for (i = 0; i < NumTextures; i++) {
701 ActiveTexture(GL_TEXTURE0_ARB + i);
702 glPushMatrix();
703 glMultMatrixf((GLfloat *) textureXform[i]);
704 glDisable(GL_LIGHTING);
705 drawTextureProjection();
706 glEnable(GL_LIGHTING);
707 glPopMatrix();
708 }
709 }
710 for (i = 0; i < NumTextures; i++) {
711 ActiveTexture(GL_TEXTURE0_ARB + i);
712 glEnable(GL_TEXTURE_2D);
713 glEnable(GL_TEXTURE_GEN_S);
714 glEnable(GL_TEXTURE_GEN_T);
715 glEnable(GL_TEXTURE_GEN_R);
716 glEnable(GL_TEXTURE_GEN_Q);
717 }
718 }
719 if (mode == MoveObject || mode == MoveView) {
720 /* Have OpenGL compute the new transformation (simple but slow). */
721 glPushMatrix();
722 glLoadIdentity();
723 glRotatef(angle, axis[0], axis[1], axis[2]);
724 glMultMatrixf((GLfloat *) objectXform);
725 glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat *) objectXform);
726 glPopMatrix();
727 }
728 glPushMatrix();
729 glMultMatrixf((GLfloat *) objectXform);
730 (*drawObject) ();
731 glPopMatrix();
732
733 for (i = 0; i < NumTextures; i++) {
734 ActiveTexture(GL_TEXTURE0_ARB + i);
735 glDisable(GL_TEXTURE_2D);
736 glDisable(GL_TEXTURE_GEN_S);
737 glDisable(GL_TEXTURE_GEN_T);
738 glDisable(GL_TEXTURE_GEN_R);
739 glDisable(GL_TEXTURE_GEN_Q);
740 }
741
742 if (zoomFactor > 1.0) {
743 glDisable(GL_DEPTH_TEST);
744 glCopyPixels(0, 0, winWidth / zoomFactor, winHeight / zoomFactor, GL_COLOR);
745 glEnable(GL_DEPTH_TEST);
746 }
747 glFlush();
748 glutSwapBuffers();
749 checkErrors();
750 }
751
752 /*****************************************************************/
753
754 /* simple trackball-like motion control */
755 static float lastPos[3];
756 static int lastTime;
757
758 static void
759 ptov(int x, int y, int width, int height, float v[3])
760 {
761 float d, a;
762
763 /* project x,y onto a hemi-sphere centered within width, height */
764 v[0] = (2.0 * x - width) / width;
765 v[1] = (height - 2.0 * y) / height;
766 d = sqrt(v[0] * v[0] + v[1] * v[1]);
767 v[2] = cos((M_PI / 2.0) * ((d < 1.0) ? d : 1.0));
768 a = 1.0 / sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
769 v[0] *= a;
770 v[1] *= a;
771 v[2] *= a;
772 }
773
774 static void
775 startMotion(int x, int y, int but, int time)
776 {
777 if (but == GLUT_LEFT_BUTTON) {
778 mode = MoveView;
779 } else if (but == GLUT_MIDDLE_BUTTON) {
780 mode = MoveTexture;
781 } else {
782 return;
783 }
784
785 lastTime = time;
786 ptov(x, y, winWidth, winHeight, lastPos);
787 }
788
789 static void
790 animate(void)
791 {
792 glutPostRedisplay();
793 }
794
795 static void
796 vis(int visible)
797 {
798 if (visible == GLUT_VISIBLE) {
799 if (redrawContinuously)
800 glutIdleFunc(animate);
801 } else {
802 if (redrawContinuously)
803 glutIdleFunc(NULL);
804 }
805 }
806
807 static void
808 stopMotion(int but, int time)
809 {
810 if ((but == GLUT_LEFT_BUTTON && mode == MoveView) ||
811 (but == GLUT_MIDDLE_BUTTON && mode == MoveTexture)) {
812 } else {
813 return;
814 }
815
816 if (time == lastTime) {
817 /* redrawContinuously = GL_TRUE;*/
818 glutIdleFunc(animate);
819 } else {
820 angle = 0.0;
821 redrawContinuously = GL_FALSE;
822 glutIdleFunc(0);
823 }
824 if (!redrawContinuously) {
825 mode = MoveNone;
826 }
827 }
828
829 static void
830 trackMotion(int x, int y)
831 {
832 float curPos[3], dx, dy, dz;
833
834 ptov(x, y, winWidth, winHeight, curPos);
835
836 dx = curPos[0] - lastPos[0];
837 dy = curPos[1] - lastPos[1];
838 dz = curPos[2] - lastPos[2];
839 angle = 90.0 * sqrt(dx * dx + dy * dy + dz * dz);
840
841 axis[0] = lastPos[1] * curPos[2] - lastPos[2] * curPos[1];
842 axis[1] = lastPos[2] * curPos[0] - lastPos[0] * curPos[2];
843 axis[2] = lastPos[0] * curPos[1] - lastPos[1] * curPos[0];
844
845 lastTime = glutGet(GLUT_ELAPSED_TIME);
846 lastPos[0] = curPos[0];
847 lastPos[1] = curPos[1];
848 lastPos[2] = curPos[2];
849 glutPostRedisplay();
850 }
851
852 /*****************************************************************/
853
854 static void
855 object(void)
856 {
857 static int object;
858
859 object++;
860 object %= 3;
861 switch (object) {
862 case 0:
863 drawObject = drawCube;
864 break;
865 case 1:
866 drawObject = drawDodecahedron;
867 break;
868 case 2:
869 drawObject = drawSphere;
870 break;
871 default:
872 break;
873 }
874 }
875
876 static void
877 nop(void)
878 {
879 }
880
881 static void
882 texture(void)
883 {
884 static int texture = 0;
885
886 texture++;
887 texture %= 3;
888 if (texture == 1 && texFilename == NULL) {
889 /* Skip file texture if not loaded. */
890 texture++;
891 }
892 switch (texture) {
893 case 0:
894 loadTexture = nop;
895 textureEnabled = GL_FALSE;
896 break;
897 case 1:
898 loadTexture = loadImageTextures;
899 (*loadTexture) ();
900 textureEnabled = GL_TRUE;
901 break;
902 case 2:
903 loadTexture = loadSpotlightTexture;
904 (*loadTexture) ();
905 textureEnabled = GL_TRUE;
906 break;
907 default:
908 break;
909 }
910 }
911
912 static void
913 help(void)
914 {
915 printf("'h' - help\n");
916 printf("'l' - toggle linear/nearest filter\n");
917 printf("'s' - toggle projection frustum\n");
918 printf("'t' - toggle projected texture\n");
919 printf("'o' - toggle object\n");
920 printf("'z' - increase zoom factor\n");
921 printf("'Z' - decrease zoom factor\n");
922 printf("left mouse - move view\n");
923 printf("middle mouse - move projection\n");
924 }
925
926 /* ARGSUSED1 */
927 static void
928 key(unsigned char key, int x, int y)
929 {
930 switch (key) {
931 case '\033':
932 exit(0);
933 break;
934 case 'l':
935 linearFilter = !linearFilter;
936 (*loadTexture) ();
937 break;
938 case 's':
939 showProjection = !showProjection;
940 break;
941 case 't':
942 texture();
943 break;
944 case 'o':
945 object();
946 break;
947 case 'z':
948 zoomFactor += 1.0;
949 glPixelZoom(zoomFactor, zoomFactor);
950 glViewport(0, 0, winWidth / zoomFactor, winHeight / zoomFactor);
951 break;
952 case 'Z':
953 zoomFactor -= 1.0;
954 if (zoomFactor < 1.0)
955 zoomFactor = 1.0;
956 glPixelZoom(zoomFactor, zoomFactor);
957 glViewport(0, 0, winWidth / zoomFactor, winHeight / zoomFactor);
958 break;
959 case 'h':
960 help();
961 break;
962 }
963 glutPostRedisplay();
964 }
965
966 static void
967 mouse(int button, int state, int x, int y)
968 {
969 if (state == GLUT_DOWN)
970 startMotion(x, y, button, glutGet(GLUT_ELAPSED_TIME));
971 else if (state == GLUT_UP)
972 stopMotion(button, glutGet(GLUT_ELAPSED_TIME));
973 glutPostRedisplay();
974 }
975
976 static void
977 reshape(int w, int h)
978 {
979 winWidth = w;
980 winHeight = h;
981 glViewport(0, 0, w / zoomFactor, h / zoomFactor);
982 }
983
984
985 static void
986 menu(int selection)
987 {
988 if (selection == 666) {
989 exit(0);
990 }
991 key((unsigned char) selection, 0, 0);
992 }
993
994 int
995 main(int argc, char **argv)
996 {
997 glutInit(&argc, argv);
998
999 if (argc > 1) {
1000 NumTextures = atoi(argv[1]);
1001 }
1002 assert(NumTextures <= MAX_TEX);
1003
1004 glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE);
1005 glutInitWindowSize(500,500);
1006 (void) glutCreateWindow("projtex");
1007 glewInit();
1008
1009 loadTexture = loadImageTextures;
1010 drawObject = drawCube;
1011 initialize();
1012 glutDisplayFunc(display);
1013 glutKeyboardFunc(key);
1014 glutReshapeFunc(reshape);
1015 glutMouseFunc(mouse);
1016 glutMotionFunc(trackMotion);
1017 glutVisibilityFunc(vis);
1018 glutCreateMenu(menu);
1019 glutAddMenuEntry("Toggle showing projection", 's');
1020 glutAddMenuEntry("Switch texture", 't');
1021 glutAddMenuEntry("Switch object", 'o');
1022 glutAddMenuEntry("Toggle filtering", 'l');
1023 glutAddMenuEntry("Quit", 666);
1024 glutAttachMenu(GLUT_RIGHT_BUTTON);
1025 texture();
1026 glutMainLoop();
1027 return 0; /* ANSI C requires main to return int. */
1028 }