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 <glad/glad.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
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    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 
61 GLfloat zoomFactor = 1.0;
62 
63 /*****************************************************************/
64 
65 
66 static void
ActiveTexture(int i)67 ActiveTexture(int i)
68 {
69    glActiveTextureARB(i);
70 }
71 
72 
73 /* matrix = identity */
74 static void
matrixIdentity(GLfloat matrix[16])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
matrixTranspose(GLfloat matrix2[16],GLfloat matrix1[16])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
loadImageTextures(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      free(texData3);
250      free(texData4);
251      free(image);
252   }
253 }
254 
255 /* Create a simple spotlight pattern and make it the current texture */
256 static void
loadSpotlightTexture(void)257 loadSpotlightTexture(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 
306 static void
checkErrors(void)307 checkErrors(void)
308 {
309   GLenum error;
310   while ((error = glGetError()) != GL_NO_ERROR) {
311     fprintf(stderr, "Error: %s\n", (char *) gluErrorString(error));
312   }
313 }
314 
315 static void
drawCube(void)316 drawCube(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 
364 static void
drawDodecahedron(void)365 drawDodecahedron(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 
450 static void
drawSphere(void)451 drawSphere(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 
489 float xmin = -0.035, xmax = 0.035;
490 float ymin = -0.035, ymax = 0.035;
491 float nnear = 0.1;
492 float ffar = 1.9;
493 float distance = -1.0;
494 
495 static void
loadTextureProjection(int texUnit,GLfloat m[16])496 loadTextureProjection(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 
515 static void
drawTextureProjection(void)516 drawTextureProjection(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 
577 static void
initialize(void)578 initialize(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 
674 static void
display(void)675 display(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 */
759 static float lastPos[3];
760 static int lastTime;
761 
762 static void
ptov(int x,int y,int width,int height,float v[3])763 ptov(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 
778 static void
startMotion(int x,int y,int but,int time)779 startMotion(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 
793 static void
animate(void)794 animate(void)
795 {
796   glutPostRedisplay();
797 }
798 
799 static void
vis(int visible)800 vis(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 
811 static void
stopMotion(int but,int time)812 stopMotion(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 
833 static void
trackMotion(int x,int y)834 trackMotion(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 
858 static void
object(void)859 object(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 
880 static void
nop(void)881 nop(void)
882 {
883 }
884 
885 static void
texture(void)886 texture(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 
916 static void
help(void)917 help(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 */
931 static void
key(unsigned char key,int x,int y)932 key(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 
970 static void
mouse(int button,int state,int x,int y)971 mouse(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 
980 static void
reshape(int w,int h)981 reshape(int w, int h)
982 {
983   winWidth = w;
984   winHeight = h;
985   glViewport(0, 0, w / zoomFactor, h / zoomFactor);
986 }
987 
988 
989 static void
menu(int selection)990 menu(int selection)
991 {
992   if (selection == 666) {
993     exit(0);
994   }
995   key((unsigned char) selection, 0, 0);
996 }
997 
998 int
main(int argc,char ** argv)999 main(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   gladLoadGL();
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