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