blob: ad205c741374b11cf21e161861ebd7c4b48b791f [file] [log] [blame]
Brian Paul6b2eab12000-11-18 17:07:39 +00001
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>
Keith Whitwella58065d2009-03-10 13:11:23 +000021#include <GL/glew.h>
Brian Paul6b2eab12000-11-18 17:07:39 +000022#include <GL/glut.h>
Brian Paul49c3e712009-04-18 13:05:51 -060023#include "readtex.h"
Brian Paul6b2eab12000-11-18 17:07:39 +000024
25
26/* Some <math.h> files do not define M_PI... */
27#ifndef M_PI
28#define M_PI 3.14159265358979323846
29#endif
30
Brian Paul4e3e9ac2001-01-23 23:44:15 +000031#define MAX_TEX 4
Brian Paul6b2eab12000-11-18 17:07:39 +000032int NumTextures = 1;
33
34int winWidth, winHeight;
35
36GLboolean redrawContinuously = GL_FALSE;
37
38float angle, axis[3];
39enum MoveModes {
40 MoveNone, MoveView, MoveObject, MoveTexture
41};
42enum MoveModes mode = MoveNone;
43
44GLfloat objectXform[4][4];
45GLfloat textureXform[MAX_TEX][4][4];
46
47void (*drawObject) (void);
48void (*loadTexture) (void);
49GLboolean textureEnabled = GL_TRUE;
50GLboolean showProjection = GL_TRUE;
51GLboolean linearFilter = GL_TRUE;
52
53char *texFilename[MAX_TEX] = {
54 "../images/girl.rgb",
Brian Paul4e3e9ac2001-01-23 23:44:15 +000055 "../images/tile.rgb",
56 "../images/bw.rgb",
57 "../images/reflect.rgb"
Brian Paul6b2eab12000-11-18 17:07:39 +000058};
59
60
61GLfloat zoomFactor = 1.0;
62
63/*****************************************************************/
64
65
Brian Paul49c3e712009-04-18 13:05:51 -060066static void
67ActiveTexture(int i)
Brian Paul6b2eab12000-11-18 17:07:39 +000068{
69 glActiveTextureARB(i);
70}
71
72
73/* matrix = identity */
Brian Paul49c3e712009-04-18 13:05:51 -060074static void
Brian Paul6b2eab12000-11-18 17:07:39 +000075matrixIdentity(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) */
Brian Paul49c3e712009-04-18 13:05:51 -060096static void
Brian Paul6b2eab12000-11-18 17:07:39 +000097matrixTranspose(GLfloat matrix2[16], GLfloat matrix1[16])
98{
99 matrix2[0] = matrix1[0];
100 matrix2[1] = matrix1[4];
101 matrix2[2] = matrix1[8];
102 matrix2[3] = matrix1[12];
103
104 matrix2[4] = matrix1[1];
105 matrix2[5] = matrix1[5];
106 matrix2[6] = matrix1[9];
107 matrix2[7] = matrix1[13];
108
109 matrix2[8] = matrix1[2];
110 matrix2[9] = matrix1[6];
111 matrix2[10] = matrix1[10];
112 matrix2[11] = matrix1[14];
113
114 matrix2[12] = matrix1[3];
115 matrix2[13] = matrix1[7];
116 matrix2[14] = matrix1[14];
117 matrix2[15] = matrix1[15];
118}
119
120/*****************************************************************/
121
122/* load SGI .rgb image (pad with a border of the specified width and color) */
123#if 0
124static void
125imgLoad(char *filenameIn, int borderIn, GLfloat borderColorIn[4],
126 int *wOut, int *hOut, GLubyte ** imgOut)
127{
128 int border = borderIn;
129 int width, height;
130 int w, h;
131 GLubyte *image, *img, *p;
132 int i, j, components;
133
134 image = (GLubyte *) read_texture(filenameIn, &width, &height, &components);
135 w = width + 2 * border;
136 h = height + 2 * border;
137 img = (GLubyte *) calloc(w * h, 4 * sizeof(unsigned char));
138
139 p = img;
140 for (j = -border; j < height + border; ++j) {
141 for (i = -border; i < width + border; ++i) {
142 if (0 <= j && j <= height - 1 && 0 <= i && i <= width - 1) {
143 p[0] = image[4 * (j * width + i) + 0];
144 p[1] = image[4 * (j * width + i) + 1];
145 p[2] = image[4 * (j * width + i) + 2];
146 p[3] = 0xff;
147 } else {
148 p[0] = borderColorIn[0] * 0xff;
149 p[1] = borderColorIn[1] * 0xff;
150 p[2] = borderColorIn[2] * 0xff;
151 p[3] = borderColorIn[3] * 0xff;
152 }
153 p += 4;
154 }
155 }
156 free(image);
157 *wOut = w;
158 *hOut = h;
159 *imgOut = img;
160}
161#endif
162
163
164/*****************************************************************/
165
166/* Load the image file specified on the command line as the current texture */
Brian Paul49c3e712009-04-18 13:05:51 -0600167static void
Brian Paul6b2eab12000-11-18 17:07:39 +0000168loadImageTextures(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);
Vinson Lee5820dae2009-11-16 16:31:34 -0800248
249 free(texData3);
250 free(texData4);
Brian Paul6b2eab12000-11-18 17:07:39 +0000251 }
252}
253
254/* Create a simple spotlight pattern and make it the current texture */
Brian Paul49c3e712009-04-18 13:05:51 -0600255static void
Brian Paul6b2eab12000-11-18 17:07:39 +0000256loadSpotlightTexture(void)
257{
258 static int texWidth = 64, texHeight = 64;
259 static GLubyte *texData;
260 GLfloat borderColor[4] =
261 {0.1, 0.1, 0.1, 1.0};
262
263 if (!texData) {
264 GLubyte *p;
265 int i, j;
266
267 texData = (GLubyte *) malloc(texWidth * texHeight * 4 * sizeof(GLubyte));
268
269 p = texData;
270 for (j = 0; j < texHeight; ++j) {
271 float dy = (texHeight * 0.5 - j + 0.5) / (texHeight * 0.5);
272
273 for (i = 0; i < texWidth; ++i) {
274 float dx = (texWidth * 0.5 - i + 0.5) / (texWidth * 0.5);
275 float r = cos(M_PI / 2.0 * sqrt(dx * dx + dy * dy));
276 float c;
277
278 r = (r < 0) ? 0 : r * r;
279 c = 0xff * (r + borderColor[0]);
280 p[0] = (c <= 0xff) ? c : 0xff;
281 c = 0xff * (r + borderColor[1]);
282 p[1] = (c <= 0xff) ? c : 0xff;
283 c = 0xff * (r + borderColor[2]);
284 p[2] = (c <= 0xff) ? c : 0xff;
285 c = 0xff * (r + borderColor[3]);
286 p[3] = (c <= 0xff) ? c : 0xff;
287 p += 4;
288 }
289 }
290 }
291 if (linearFilter) {
292 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
293 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
294 } else {
295 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
296 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
297 }
298 glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
299 gluBuild2DMipmaps(GL_TEXTURE_2D, 4, texWidth, texHeight,
300 GL_RGBA, GL_UNSIGNED_BYTE, texData);
301}
302
303/*****************************************************************/
304
Brian Paul49c3e712009-04-18 13:05:51 -0600305static void
Brian Paul6b2eab12000-11-18 17:07:39 +0000306checkErrors(void)
307{
308 GLenum error;
309 while ((error = glGetError()) != GL_NO_ERROR) {
310 fprintf(stderr, "Error: %s\n", (char *) gluErrorString(error));
311 }
312}
313
Brian Paul49c3e712009-04-18 13:05:51 -0600314static void
Brian Paul6b2eab12000-11-18 17:07:39 +0000315drawCube(void)
316{
317 glBegin(GL_QUADS);
318
319 glNormal3f(-1.0, 0.0, 0.0);
320 glColor3f(0.80, 0.50, 0.50);
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 glVertex3f(-0.5, 0.5, -0.5);
325
326 glNormal3f(1.0, 0.0, 0.0);
327 glColor3f(0.50, 0.80, 0.50);
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 glVertex3f(0.5, 0.5, -0.5);
332
333 glNormal3f(0.0, -1.0, 0.0);
334 glColor3f(0.50, 0.50, 0.80);
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 glVertex3f(-0.5, -0.5, 0.5);
339
340 glNormal3f(0.0, 1.0, 0.0);
341 glColor3f(0.50, 0.80, 0.80);
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 glVertex3f(-0.5, 0.5, 0.5);
346
347 glNormal3f(0.0, 0.0, -1.0);
348 glColor3f(0.80, 0.50, 0.80);
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 glVertex3f(0.5, -0.5, -0.5);
353
354 glNormal3f(0.0, 0.0, 1.0);
355 glColor3f(1.00, 0.80, 0.50);
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 glVertex3f(0.5, -0.5, 0.5);
360 glEnd();
361}
362
Brian Paul49c3e712009-04-18 13:05:51 -0600363static void
Brian Paul6b2eab12000-11-18 17:07:39 +0000364drawDodecahedron(void)
365{
366#define A (0.5 * 1.61803) /* (sqrt(5) + 1) / 2 */
367#define B (0.5 * 0.61803) /* (sqrt(5) - 1) / 2 */
368#define C (0.5 * 1.0)
369 GLfloat vertexes[20][3] =
370 {
371 {-A, 0.0, B},
372 {-A, 0.0, -B},
373 {A, 0.0, -B},
374 {A, 0.0, B},
375 {B, -A, 0.0},
376 {-B, -A, 0.0},
377 {-B, A, 0.0},
378 {B, A, 0.0},
379 {0.0, B, -A},
380 {0.0, -B, -A},
381 {0.0, -B, A},
382 {0.0, B, A},
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 {C, C, C},
391 };
392#undef A
393#undef B
394#undef C
395 GLint polygons[12][5] =
396 {
397 {0, 12, 10, 11, 16},
398 {1, 17, 8, 9, 13},
399 {2, 14, 9, 8, 18},
400 {3, 19, 11, 10, 15},
401 {4, 14, 2, 3, 15},
402 {5, 12, 0, 1, 13},
403 {6, 17, 1, 0, 16},
404 {7, 19, 3, 2, 18},
405 {8, 17, 6, 7, 18},
406 {9, 14, 4, 5, 13},
407 {10, 12, 5, 4, 15},
408 {11, 19, 7, 6, 16},
409 };
410 int i;
411
412 glColor3f(0.75, 0.75, 0.75);
413 for (i = 0; i < 12; ++i) {
414 GLfloat *p0, *p1, *p2, d;
415 GLfloat u[3], v[3], n[3];
416
417 p0 = &vertexes[polygons[i][0]][0];
418 p1 = &vertexes[polygons[i][1]][0];
419 p2 = &vertexes[polygons[i][2]][0];
420
421 u[0] = p2[0] - p1[0];
422 u[1] = p2[1] - p1[1];
423 u[2] = p2[2] - p1[2];
424
425 v[0] = p0[0] - p1[0];
426 v[1] = p0[1] - p1[1];
427 v[2] = p0[2] - p1[2];
428
429 n[0] = u[1] * v[2] - u[2] * v[1];
430 n[1] = u[2] * v[0] - u[0] * v[2];
431 n[2] = u[0] * v[1] - u[1] * v[0];
432
433 d = 1.0 / sqrt(n[0] * n[0] + n[1] * n[1] + n[2] * n[2]);
434 n[0] *= d;
435 n[1] *= d;
436 n[2] *= d;
437
438 glBegin(GL_POLYGON);
439 glNormal3fv(n);
440 glVertex3fv(p0);
441 glVertex3fv(p1);
442 glVertex3fv(p2);
443 glVertex3fv(vertexes[polygons[i][3]]);
444 glVertex3fv(vertexes[polygons[i][4]]);
445 glEnd();
446 }
447}
448
Brian Paul49c3e712009-04-18 13:05:51 -0600449static void
Brian Paul6b2eab12000-11-18 17:07:39 +0000450drawSphere(void)
451{
452 int numMajor = 24;
453 int numMinor = 32;
454 float radius = 0.8;
455 double majorStep = (M_PI / numMajor);
456 double minorStep = (2.0 * M_PI / numMinor);
457 int i, j;
458
459 glColor3f(0.50, 0.50, 0.50);
460 for (i = 0; i < numMajor; ++i) {
461 double a = i * majorStep;
462 double b = a + majorStep;
463 double r0 = radius * sin(a);
464 double r1 = radius * sin(b);
465 GLfloat z0 = radius * cos(a);
466 GLfloat z1 = radius * cos(b);
467
468 glBegin(GL_TRIANGLE_STRIP);
469 for (j = 0; j <= numMinor; ++j) {
470 double c = j * minorStep;
471 GLfloat x = cos(c);
472 GLfloat y = sin(c);
473
474 glNormal3f((x * r0) / radius, (y * r0) / radius, z0 / radius);
475 glTexCoord2f(j / (GLfloat) numMinor, i / (GLfloat) numMajor);
476 glVertex3f(x * r0, y * r0, z0);
477
478 glNormal3f((x * r1) / radius, (y * r1) / radius, z1 / radius);
479 glTexCoord2f(j / (GLfloat) numMinor, (i + 1) / (GLfloat) numMajor);
480 glVertex3f(x * r1, y * r1, z1);
481 }
482 glEnd();
483 }
484}
485
486/*****************************************************************/
487
488float xmin = -0.035, xmax = 0.035;
489float ymin = -0.035, ymax = 0.035;
490float nnear = 0.1;
491float ffar = 1.9;
492float distance = -1.0;
493
494static void
495loadTextureProjection(int texUnit, GLfloat m[16])
496{
497 GLfloat mInverse[4][4];
498
499 /* Should use true inverse, but since m consists only of rotations, we can
500 just use the transpose. */
501 matrixTranspose((GLfloat *) mInverse, m);
502
503 ActiveTexture(GL_TEXTURE0_ARB + texUnit);
504 glMatrixMode(GL_TEXTURE);
505 glLoadIdentity();
506 glTranslatef(0.5, 0.5, 0.0);
507 glScalef(0.5, 0.5, 1.0);
508 glFrustum(xmin, xmax, ymin, ymax, nnear, ffar);
509 glTranslatef(0.0, 0.0, distance);
510 glMultMatrixf((GLfloat *) mInverse);
511 glMatrixMode(GL_MODELVIEW);
512}
513
514static void
515drawTextureProjection(void)
516{
517 float t = ffar / nnear;
518 GLfloat n[4][3];
519 GLfloat f[4][3];
520
521 n[0][0] = xmin;
522 n[0][1] = ymin;
523 n[0][2] = -(nnear + distance);
524
525 n[1][0] = xmax;
526 n[1][1] = ymin;
527 n[1][2] = -(nnear + distance);
528
529 n[2][0] = xmax;
530 n[2][1] = ymax;
531 n[2][2] = -(nnear + distance);
532
533 n[3][0] = xmin;
534 n[3][1] = ymax;
535 n[3][2] = -(nnear + distance);
536
537 f[0][0] = xmin * t;
538 f[0][1] = ymin * t;
539 f[0][2] = -(ffar + distance);
540
541 f[1][0] = xmax * t;
542 f[1][1] = ymin * t;
543 f[1][2] = -(ffar + distance);
544
545 f[2][0] = xmax * t;
546 f[2][1] = ymax * t;
547 f[2][2] = -(ffar + distance);
548
549 f[3][0] = xmin * t;
550 f[3][1] = ymax * t;
551 f[3][2] = -(ffar + distance);
552
553 glColor3f(1.0, 1.0, 0.0);
554 glBegin(GL_LINE_LOOP);
555 glVertex3fv(n[0]);
556 glVertex3fv(n[1]);
557 glVertex3fv(n[2]);
558 glVertex3fv(n[3]);
559 glVertex3fv(f[3]);
560 glVertex3fv(f[2]);
561 glVertex3fv(f[1]);
562 glVertex3fv(f[0]);
563 glVertex3fv(n[0]);
564 glVertex3fv(n[1]);
565 glVertex3fv(f[1]);
566 glVertex3fv(f[0]);
567 glVertex3fv(f[3]);
568 glVertex3fv(f[2]);
569 glVertex3fv(n[2]);
570 glVertex3fv(n[3]);
571 glEnd();
572}
573
574/*****************************************************************/
575
Brian Paul49c3e712009-04-18 13:05:51 -0600576static void
Brian Paul6b2eab12000-11-18 17:07:39 +0000577initialize(void)
578{
579 GLfloat light0Pos[4] =
580 {0.3, 0.3, 0.0, 1.0};
581 GLfloat matAmb[4] =
582 {0.01, 0.01, 0.01, 1.00};
583 GLfloat matDiff[4] =
584 {0.65, 0.65, 0.65, 1.00};
585 GLfloat matSpec[4] =
586 {0.30, 0.30, 0.30, 1.00};
587 GLfloat matShine = 10.0;
588 GLfloat eyePlaneS[] =
589 {1.0, 0.0, 0.0, 0.0};
590 GLfloat eyePlaneT[] =
591 {0.0, 1.0, 0.0, 0.0};
592 GLfloat eyePlaneR[] =
593 {0.0, 0.0, 1.0, 0.0};
594 GLfloat eyePlaneQ[] =
595 {0.0, 0.0, 0.0, 1.0};
596 int i;
597
598 /* Setup Misc. */
599 glClearColor(0.41, 0.41, 0.31, 0.0);
600
601 glEnable(GL_DEPTH_TEST);
602
603 /* glLineWidth(2.0);*/
604
605 glCullFace(GL_FRONT);
606 glEnable(GL_CULL_FACE);
607
608 glMatrixMode(GL_PROJECTION);
609 glFrustum(-0.5, 0.5, -0.5, 0.5, 1, 3);
610 glMatrixMode(GL_MODELVIEW);
611 glTranslatef(0, 0, -2);
612
613 matrixIdentity((GLfloat *) objectXform);
614 for (i = 0; i < NumTextures; i++) {
615 matrixIdentity((GLfloat *) textureXform[i]);
616 }
617
618 glMatrixMode(GL_PROJECTION);
619 glPushMatrix();
620 glLoadIdentity();
621 glOrtho(0, 1, 0, 1, -1, 1);
622 glMatrixMode(GL_MODELVIEW);
623 glPushMatrix();
624 glLoadIdentity();
625
626 glRasterPos2i(0, 0);
627
628 glPopMatrix();
629 glMatrixMode(GL_PROJECTION);
630 glPopMatrix();
631 glMatrixMode(GL_MODELVIEW);
632
633 /* Setup Lighting */
634 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, matAmb);
635 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, matDiff);
636 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, matSpec);
637 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, matShine);
638
639 glEnable(GL_COLOR_MATERIAL);
640
641 glLightfv(GL_LIGHT0, GL_POSITION, light0Pos);
642 glEnable(GL_LIGHT0);
643
644 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
645 glEnable(GL_LIGHTING);
646
647 /* Setup Texture */
648
649 (*loadTexture) ();
650
651
652 for (i = 0; i < NumTextures; i++) {
653 ActiveTexture(GL_TEXTURE0_ARB + i);
654
Brian Paul4e3e9ac2001-01-23 23:44:15 +0000655 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
656 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
657 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
Brian Paul6b2eab12000-11-18 17:07:39 +0000658
659 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
660 glTexGenfv(GL_S, GL_EYE_PLANE, eyePlaneS);
661
662 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
663 glTexGenfv(GL_T, GL_EYE_PLANE, eyePlaneT);
664
665 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
666 glTexGenfv(GL_R, GL_EYE_PLANE, eyePlaneR);
667
668 glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
669 glTexGenfv(GL_Q, GL_EYE_PLANE, eyePlaneQ);
670 }
671}
672
Brian Paul49c3e712009-04-18 13:05:51 -0600673static void
Brian Paul6b2eab12000-11-18 17:07:39 +0000674display(void)
675{
676 int i;
677
678 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
679
680 if (textureEnabled) {
681 if (mode == MoveTexture || mode == MoveView) {
682 /* Have OpenGL compute the new transformation (simple but slow). */
683 for (i = 0; i < NumTextures; i++) {
684 glPushMatrix();
685 glLoadIdentity();
Brian Paul4e3e9ac2001-01-23 23:44:15 +0000686#if 0
Brian Paul6b2eab12000-11-18 17:07:39 +0000687 if (i & 1)
688 glRotatef(angle, axis[0], axis[1], axis[2]);
689 else
Brian Paul4e3e9ac2001-01-23 23:44:15 +0000690#endif
691 glRotatef(angle*(i+1), axis[0], axis[1], axis[2]);
Brian Paul6b2eab12000-11-18 17:07:39 +0000692
693 glMultMatrixf((GLfloat *) textureXform[i]);
694 glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat *) textureXform[i]);
695 glPopMatrix();
696 }
697 }
698 for (i = 0; i < NumTextures; i++) {
699 loadTextureProjection(i, (GLfloat *) textureXform[i]);
700 }
701
702 if (showProjection) {
703 for (i = 0; i < NumTextures; i++) {
704 ActiveTexture(GL_TEXTURE0_ARB + i);
705 glPushMatrix();
706 glMultMatrixf((GLfloat *) textureXform[i]);
707 glDisable(GL_LIGHTING);
708 drawTextureProjection();
709 glEnable(GL_LIGHTING);
710 glPopMatrix();
711 }
712 }
713 for (i = 0; i < NumTextures; i++) {
714 ActiveTexture(GL_TEXTURE0_ARB + i);
715 glEnable(GL_TEXTURE_2D);
716 glEnable(GL_TEXTURE_GEN_S);
717 glEnable(GL_TEXTURE_GEN_T);
718 glEnable(GL_TEXTURE_GEN_R);
719 glEnable(GL_TEXTURE_GEN_Q);
720 }
721 }
722 if (mode == MoveObject || mode == MoveView) {
723 /* Have OpenGL compute the new transformation (simple but slow). */
724 glPushMatrix();
725 glLoadIdentity();
726 glRotatef(angle, axis[0], axis[1], axis[2]);
727 glMultMatrixf((GLfloat *) objectXform);
728 glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat *) objectXform);
729 glPopMatrix();
730 }
731 glPushMatrix();
732 glMultMatrixf((GLfloat *) objectXform);
733 (*drawObject) ();
734 glPopMatrix();
735
736 for (i = 0; i < NumTextures; i++) {
737 ActiveTexture(GL_TEXTURE0_ARB + i);
738 glDisable(GL_TEXTURE_2D);
739 glDisable(GL_TEXTURE_GEN_S);
740 glDisable(GL_TEXTURE_GEN_T);
741 glDisable(GL_TEXTURE_GEN_R);
742 glDisable(GL_TEXTURE_GEN_Q);
743 }
744
745 if (zoomFactor > 1.0) {
746 glDisable(GL_DEPTH_TEST);
747 glCopyPixels(0, 0, winWidth / zoomFactor, winHeight / zoomFactor, GL_COLOR);
748 glEnable(GL_DEPTH_TEST);
749 }
750 glFlush();
751 glutSwapBuffers();
752 checkErrors();
753}
754
755/*****************************************************************/
756
757/* simple trackball-like motion control */
Brian Paul49c3e712009-04-18 13:05:51 -0600758static float lastPos[3];
759static int lastTime;
Brian Paul6b2eab12000-11-18 17:07:39 +0000760
Brian Paul49c3e712009-04-18 13:05:51 -0600761static void
Brian Paul6b2eab12000-11-18 17:07:39 +0000762ptov(int x, int y, int width, int height, float v[3])
763{
764 float d, a;
765
766 /* project x,y onto a hemi-sphere centered within width, height */
767 v[0] = (2.0 * x - width) / width;
768 v[1] = (height - 2.0 * y) / height;
769 d = sqrt(v[0] * v[0] + v[1] * v[1]);
770 v[2] = cos((M_PI / 2.0) * ((d < 1.0) ? d : 1.0));
771 a = 1.0 / sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
772 v[0] *= a;
773 v[1] *= a;
774 v[2] *= a;
775}
776
Brian Paul49c3e712009-04-18 13:05:51 -0600777static void
Brian Paul6b2eab12000-11-18 17:07:39 +0000778startMotion(int x, int y, int but, int time)
779{
780 if (but == GLUT_LEFT_BUTTON) {
781 mode = MoveView;
782 } else if (but == GLUT_MIDDLE_BUTTON) {
783 mode = MoveTexture;
784 } else {
785 return;
786 }
787
788 lastTime = time;
789 ptov(x, y, winWidth, winHeight, lastPos);
790}
791
Brian Paul49c3e712009-04-18 13:05:51 -0600792static void
Brian Paul6b2eab12000-11-18 17:07:39 +0000793animate(void)
794{
795 glutPostRedisplay();
796}
797
Brian Paul49c3e712009-04-18 13:05:51 -0600798static void
Brian Paul6b2eab12000-11-18 17:07:39 +0000799vis(int visible)
800{
801 if (visible == GLUT_VISIBLE) {
802 if (redrawContinuously)
803 glutIdleFunc(animate);
804 } else {
805 if (redrawContinuously)
806 glutIdleFunc(NULL);
807 }
808}
809
Brian Paul49c3e712009-04-18 13:05:51 -0600810static void
Brian Paul6b2eab12000-11-18 17:07:39 +0000811stopMotion(int but, int time)
812{
813 if ((but == GLUT_LEFT_BUTTON && mode == MoveView) ||
814 (but == GLUT_MIDDLE_BUTTON && mode == MoveTexture)) {
815 } else {
816 return;
817 }
818
819 if (time == lastTime) {
820 /* redrawContinuously = GL_TRUE;*/
821 glutIdleFunc(animate);
822 } else {
823 angle = 0.0;
824 redrawContinuously = GL_FALSE;
825 glutIdleFunc(0);
826 }
827 if (!redrawContinuously) {
828 mode = MoveNone;
829 }
830}
831
Brian Paul49c3e712009-04-18 13:05:51 -0600832static void
Brian Paul6b2eab12000-11-18 17:07:39 +0000833trackMotion(int x, int y)
834{
835 float curPos[3], dx, dy, dz;
836
837 ptov(x, y, winWidth, winHeight, curPos);
838
839 dx = curPos[0] - lastPos[0];
840 dy = curPos[1] - lastPos[1];
841 dz = curPos[2] - lastPos[2];
842 angle = 90.0 * sqrt(dx * dx + dy * dy + dz * dz);
843
844 axis[0] = lastPos[1] * curPos[2] - lastPos[2] * curPos[1];
845 axis[1] = lastPos[2] * curPos[0] - lastPos[0] * curPos[2];
846 axis[2] = lastPos[0] * curPos[1] - lastPos[1] * curPos[0];
847
848 lastTime = glutGet(GLUT_ELAPSED_TIME);
849 lastPos[0] = curPos[0];
850 lastPos[1] = curPos[1];
851 lastPos[2] = curPos[2];
852 glutPostRedisplay();
853}
854
855/*****************************************************************/
856
Brian Paul49c3e712009-04-18 13:05:51 -0600857static void
Brian Paul6b2eab12000-11-18 17:07:39 +0000858object(void)
859{
860 static int object;
861
862 object++;
863 object %= 3;
864 switch (object) {
865 case 0:
866 drawObject = drawCube;
867 break;
868 case 1:
869 drawObject = drawDodecahedron;
870 break;
871 case 2:
872 drawObject = drawSphere;
873 break;
874 default:
875 break;
876 }
877}
878
879static void
880nop(void)
881{
882}
883
Brian Paul49c3e712009-04-18 13:05:51 -0600884static void
Brian Paul6b2eab12000-11-18 17:07:39 +0000885texture(void)
886{
887 static int texture = 0;
888
889 texture++;
890 texture %= 3;
891 if (texture == 1 && texFilename == NULL) {
892 /* Skip file texture if not loaded. */
893 texture++;
894 }
895 switch (texture) {
896 case 0:
897 loadTexture = nop;
898 textureEnabled = GL_FALSE;
899 break;
900 case 1:
901 loadTexture = loadImageTextures;
902 (*loadTexture) ();
903 textureEnabled = GL_TRUE;
904 break;
905 case 2:
906 loadTexture = loadSpotlightTexture;
907 (*loadTexture) ();
908 textureEnabled = GL_TRUE;
909 break;
910 default:
911 break;
912 }
913}
914
Brian Paul49c3e712009-04-18 13:05:51 -0600915static void
Brian Paul6b2eab12000-11-18 17:07:39 +0000916help(void)
917{
918 printf("'h' - help\n");
919 printf("'l' - toggle linear/nearest filter\n");
920 printf("'s' - toggle projection frustum\n");
921 printf("'t' - toggle projected texture\n");
922 printf("'o' - toggle object\n");
923 printf("'z' - increase zoom factor\n");
924 printf("'Z' - decrease zoom factor\n");
925 printf("left mouse - move view\n");
926 printf("middle mouse - move projection\n");
927}
928
929/* ARGSUSED1 */
Brian Paul49c3e712009-04-18 13:05:51 -0600930static void
Brian Paul6b2eab12000-11-18 17:07:39 +0000931key(unsigned char key, int x, int y)
932{
933 switch (key) {
934 case '\033':
935 exit(0);
936 break;
937 case 'l':
938 linearFilter = !linearFilter;
939 (*loadTexture) ();
940 break;
941 case 's':
942 showProjection = !showProjection;
943 break;
944 case 't':
945 texture();
946 break;
947 case 'o':
948 object();
949 break;
950 case 'z':
951 zoomFactor += 1.0;
952 glPixelZoom(zoomFactor, zoomFactor);
953 glViewport(0, 0, winWidth / zoomFactor, winHeight / zoomFactor);
954 break;
955 case 'Z':
956 zoomFactor -= 1.0;
957 if (zoomFactor < 1.0)
958 zoomFactor = 1.0;
959 glPixelZoom(zoomFactor, zoomFactor);
960 glViewport(0, 0, winWidth / zoomFactor, winHeight / zoomFactor);
961 break;
962 case 'h':
963 help();
964 break;
965 }
966 glutPostRedisplay();
967}
968
Brian Paul49c3e712009-04-18 13:05:51 -0600969static void
Brian Paul6b2eab12000-11-18 17:07:39 +0000970mouse(int button, int state, int x, int y)
971{
972 if (state == GLUT_DOWN)
973 startMotion(x, y, button, glutGet(GLUT_ELAPSED_TIME));
974 else if (state == GLUT_UP)
975 stopMotion(button, glutGet(GLUT_ELAPSED_TIME));
976 glutPostRedisplay();
977}
978
Brian Paul49c3e712009-04-18 13:05:51 -0600979static void
Brian Paul6b2eab12000-11-18 17:07:39 +0000980reshape(int w, int h)
981{
982 winWidth = w;
983 winHeight = h;
984 glViewport(0, 0, w / zoomFactor, h / zoomFactor);
985}
986
987
Brian Paul49c3e712009-04-18 13:05:51 -0600988static void
Brian Paul6b2eab12000-11-18 17:07:39 +0000989menu(int selection)
990{
991 if (selection == 666) {
992 exit(0);
993 }
994 key((unsigned char) selection, 0, 0);
995}
996
997int
998main(int argc, char **argv)
999{
1000 glutInit(&argc, argv);
1001
1002 if (argc > 1) {
1003 NumTextures = atoi(argv[1]);
1004 }
Brian Paul4e3e9ac2001-01-23 23:44:15 +00001005 assert(NumTextures <= MAX_TEX);
Brian Paul6b2eab12000-11-18 17:07:39 +00001006
1007 glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE);
Brian Paul49c3e712009-04-18 13:05:51 -06001008 glutInitWindowSize(500,500);
Brian Paul6b2eab12000-11-18 17:07:39 +00001009 (void) glutCreateWindow("projtex");
Keith Whitwella58065d2009-03-10 13:11:23 +00001010 glewInit();
Brian Paul6b2eab12000-11-18 17:07:39 +00001011
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}