1 /*
2  * Copyright (c) 1991, 1992, 1993 Silicon Graphics, Inc.
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and
5  * its documentation for any purpose is hereby granted without fee, provided
6  * that (i) the above copyright notices and this permission notice appear in
7  * all copies of the software and related documentation, and (ii) the name of
8  * Silicon Graphics may not be used in any advertising or
9  * publicity relating to the software without the specific, prior written
10  * permission of Silicon Graphics.
11  *
12  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF
13  * ANY KIND,
14  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
15  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
16  *
17  * IN NO EVENT SHALL SILICON GRAPHICS BE LIABLE FOR
18  * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
19  * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
20  * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
21  * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
22  * OF THIS SOFTWARE.
23  */
24 
25 #include <stdio.h>
26 #include <string.h>
27 #include <stdlib.h>
28 #include <math.h>
29 #include "glut_wrap.h"
30 
31 #ifndef PI
32 #define PI 3.14159265358979323846
33 #endif
34 
35 #define GETCOORD(frame, x, y) (&(theMesh.coords[frame*theMesh.numCoords+(x)+(y)*(theMesh.widthX+1)]))
36 #define GETFACET(frame, x, y) (&(theMesh.facets[frame*theMesh.numFacets+(x)+(y)*theMesh.widthX]))
37 
38 
39 GLenum rgb, doubleBuffer;
40 
41 #include "tkmap.c"
42 
43 GLint colorIndexes1[3];
44 GLint colorIndexes2[3];
45 GLenum clearMask = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT;
46 
47 GLenum smooth = GL_FALSE;
48 GLenum lighting = GL_TRUE;
49 GLenum depth = GL_TRUE;
50 GLenum stepMode = GL_FALSE;
51 GLenum spinMode = GL_FALSE;
52 GLint contouring = 0;
53 
54 GLint widthX, widthY;
55 GLint checkerSize;
56 float height;
57 
58 GLint frames, curFrame = 0, nextFrame = 0;
59 
60 struct facet {
61     float color[3];
62     float normal[3];
63 };
64 struct coord {
65     float vertex[3];
66     float normal[3];
67 };
68 struct mesh {
69     GLint widthX, widthY;
70     GLint numFacets;
71     GLint numCoords;
72     GLint frames;
73     struct coord *coords;
74     struct facet *facets;
75 } theMesh;
76 
77 GLubyte contourTexture1[] = {
78     255, 255, 255, 255,
79     255, 255, 255, 255,
80     255, 255, 255, 255,
81     127, 127, 127, 127,
82 };
83 GLubyte contourTexture2[] = {
84     255, 255, 255, 255,
85     255, 127, 127, 127,
86     255, 127, 127, 127,
87     255, 127, 127, 127,
88 };
89 
90 #if !defined(GLUTCALLBACK)
91 #define GLUTCALLBACK
92 #endif
93 
94 
glut_post_redisplay_p(void)95 static void GLUTCALLBACK glut_post_redisplay_p(void)
96 {
97     static double t0 = -1.;
98     double t, dt;
99     t = glutGet(GLUT_ELAPSED_TIME) / 1000.;
100     if (t0 < 0.)
101        t0 = t;
102     dt = t - t0;
103 
104     if (dt < 1./30.)
105         return;
106 
107     t0 = t;
108 
109     glutPostRedisplay();
110 }
111 
Animate(void)112 static void Animate(void)
113 {
114     struct coord *coord;
115     struct facet *facet;
116     float *lastColor;
117     float *thisColor;
118     GLint i, j;
119 
120     glClear(clearMask);
121 
122     if (nextFrame || !stepMode) {
123 	curFrame++;
124     }
125     if (curFrame >= theMesh.frames) {
126 	curFrame = 0;
127     }
128 
129     if ((nextFrame || !stepMode) && spinMode) {
130 	glRotatef(5.0, 0.0, 0.0, 1.0);
131     }
132     nextFrame = 0;
133 
134     for (i = 0; i < theMesh.widthX; i++) {
135 	glBegin(GL_QUAD_STRIP);
136 	lastColor = NULL;
137 	for (j = 0; j < theMesh.widthY; j++) {
138 	    facet = GETFACET(curFrame, i, j);
139 	    if (!smooth && lighting) {
140 		glNormal3fv(facet->normal);
141 	    }
142 	    if (lighting) {
143 		if (rgb) {
144 		    thisColor = facet->color;
145 		    glColor3fv(facet->color);
146 		} else {
147 		    thisColor = facet->color;
148 		    glMaterialfv(GL_FRONT_AND_BACK, GL_COLOR_INDEXES,
149 				 facet->color);
150 		}
151 	    } else {
152 		if (rgb) {
153 		    thisColor = facet->color;
154 		    glColor3fv(facet->color);
155 		} else {
156 		    thisColor = facet->color;
157 		    glIndexf(facet->color[1]);
158 		}
159 	    }
160 
161 	    if (!lastColor || (thisColor[0] != lastColor[0] && smooth)) {
162 		if (lastColor) {
163 		    glEnd();
164 		    glBegin(GL_QUAD_STRIP);
165 		}
166 		coord = GETCOORD(curFrame, i, j);
167 		if (smooth && lighting) {
168 		    glNormal3fv(coord->normal);
169 		}
170 		glVertex3fv(coord->vertex);
171 
172 		coord = GETCOORD(curFrame, i+1, j);
173 		if (smooth && lighting) {
174 		    glNormal3fv(coord->normal);
175 		}
176 		glVertex3fv(coord->vertex);
177 	    }
178 
179 	    coord = GETCOORD(curFrame, i, j+1);
180 	    if (smooth && lighting) {
181 		glNormal3fv(coord->normal);
182 	    }
183 	    glVertex3fv(coord->vertex);
184 
185 	    coord = GETCOORD(curFrame, i+1, j+1);
186 	    if (smooth && lighting) {
187 		glNormal3fv(coord->normal);
188 	    }
189 	    glVertex3fv(coord->vertex);
190 
191 	    lastColor = thisColor;
192 	}
193 	glEnd();
194     }
195 
196     glFlush();
197     if (doubleBuffer) {
198 	glutSwapBuffers();
199     }
200 }
201 
SetColorMap(void)202 static void SetColorMap(void)
203 {
204     static float green[3] = {0.2, 1.0, 0.2};
205     static float red[3] = {1.0, 0.2, 0.2};
206     float *color = 0, percent;
207     GLint *indexes = 0, entries, i, j;
208 
209     entries = glutGet(GLUT_WINDOW_COLORMAP_SIZE);
210 
211     colorIndexes1[0] = 1;
212     colorIndexes1[1] = 1 + (GLint)((entries - 1) * 0.3);
213     colorIndexes1[2] = (GLint)((entries - 1) * 0.5);
214     colorIndexes2[0] = 1 + (GLint)((entries - 1) * 0.5);
215     colorIndexes2[1] = 1 + (GLint)((entries - 1) * 0.8);
216     colorIndexes2[2] = entries - 1;
217 
218     for (i = 0; i < 2; i++) {
219 	switch (i) {
220 	  case 0:
221 	    color = green;
222 	    indexes = colorIndexes1;
223 	    break;
224 	  case 1:
225 	    color = red;
226 	    indexes = colorIndexes2;
227 	    break;
228 	}
229 
230 	for (j = indexes[0]; j < indexes[1]; j++) {
231 	    percent = 0.2 + 0.8 * (j - indexes[0]) /
232 		      (float)(indexes[1] - indexes[0]);
233 	    glutSetColor(j, percent*color[0], percent*color[1],
234 			   percent*color[2]);
235 	}
236 	for (j=indexes[1]; j<=indexes[2]; j++) {
237 	    percent = (j - indexes[1]) / (float)(indexes[2] - indexes[1]);
238 	    glutSetColor(j, percent*(1-color[0])+color[0],
239 			   percent*(1-color[1])+color[1],
240 			   percent*(1-color[2])+color[2]);
241 	}
242     }
243 }
244 
InitMesh(void)245 static void InitMesh(void)
246 {
247     struct coord *coord;
248     struct facet *facet;
249     float dp1[3], dp2[3];
250     float *pt1, *pt2, *pt3;
251     float angle, d, x, y;
252     GLint numFacets, numCoords, frameNum, i, j;
253 
254     theMesh.widthX = widthX;
255     theMesh.widthY = widthY;
256     theMesh.frames = frames;
257 
258     numFacets = widthX * widthY;
259     numCoords = (widthX + 1) * (widthY + 1);
260 
261     theMesh.numCoords = numCoords;
262     theMesh.numFacets = numFacets;
263 
264     theMesh.coords = (struct coord *)malloc(frames*numCoords*
265 					    sizeof(struct coord));
266     theMesh.facets = (struct facet *)malloc(frames*numFacets*
267 					    sizeof(struct facet));
268     if (theMesh.coords == NULL || theMesh.facets == NULL) {
269 	printf("Out of memory.\n");
270 	exit(1);
271     }
272 
273     for (frameNum = 0; frameNum < frames; frameNum++) {
274 	for (i = 0; i <= widthX; i++) {
275 	    x = i / (float)widthX;
276 	    for (j = 0; j <= widthY; j++) {
277 		y = j / (float)widthY;
278 
279 		d = sqrt(x*x+y*y);
280 		if (d == 0.0) {
281 		    d = 0.0001;
282 		}
283 		angle = 2 * PI * d + (2 * PI / frames * frameNum);
284 
285 		coord = GETCOORD(frameNum, i, j);
286 
287 		coord->vertex[0] = x - 0.5;
288 		coord->vertex[1] = y - 0.5;
289 		coord->vertex[2] = (height - height * d) * cos(angle);
290 
291 		coord->normal[0] = -(height / d) * x * ((1 - d) * 2 * PI *
292 				   sin(angle) + cos(angle));
293 		coord->normal[1] = -(height / d) * y * ((1 - d) * 2 * PI *
294 				   sin(angle) + cos(angle));
295 		coord->normal[2] = -1;
296 
297 		d = 1.0 / sqrt(coord->normal[0]*coord->normal[0]+
298 			       coord->normal[1]*coord->normal[1]+1);
299 		coord->normal[0] *= d;
300 		coord->normal[1] *= d;
301 		coord->normal[2] *= d;
302 	    }
303 	}
304 	for (i = 0; i < widthX; i++) {
305 	    for (j = 0; j < widthY; j++) {
306 		facet = GETFACET(frameNum, i, j);
307 		if (((i/checkerSize)%2)^(j/checkerSize)%2) {
308 		    if (rgb) {
309 			facet->color[0] = 1.0;
310 			facet->color[1] = 0.2;
311 			facet->color[2] = 0.2;
312 		    } else {
313 			facet->color[0] = colorIndexes1[0];
314 			facet->color[1] = colorIndexes1[1];
315 			facet->color[2] = colorIndexes1[2];
316 		    }
317 		} else {
318 		    if (rgb) {
319 			facet->color[0] = 0.2;
320 			facet->color[1] = 1.0;
321 			facet->color[2] = 0.2;
322 		    } else {
323 			facet->color[0] = colorIndexes2[0];
324 			facet->color[1] = colorIndexes2[1];
325 			facet->color[2] = colorIndexes2[2];
326 		    }
327 		}
328 		pt1 = GETCOORD(frameNum, i, j)->vertex;
329 		pt2 = GETCOORD(frameNum, i, j+1)->vertex;
330 		pt3 = GETCOORD(frameNum, i+1, j+1)->vertex;
331 
332 		dp1[0] = pt2[0] - pt1[0];
333 		dp1[1] = pt2[1] - pt1[1];
334 		dp1[2] = pt2[2] - pt1[2];
335 
336 		dp2[0] = pt3[0] - pt2[0];
337 		dp2[1] = pt3[1] - pt2[1];
338 		dp2[2] = pt3[2] - pt2[2];
339 
340 		facet->normal[0] = dp1[1] * dp2[2] - dp1[2] * dp2[1];
341 		facet->normal[1] = dp1[2] * dp2[0] - dp1[0] * dp2[2];
342 		facet->normal[2] = dp1[0] * dp2[1] - dp1[1] * dp2[0];
343 
344 		d = 1.0 / sqrt(facet->normal[0]*facet->normal[0]+
345 			       facet->normal[1]*facet->normal[1]+
346 			       facet->normal[2]*facet->normal[2]);
347 
348 		facet->normal[0] *= d;
349 		facet->normal[1] *= d;
350 		facet->normal[2] *= d;
351 	    }
352 	}
353     }
354 }
355 
InitMaterials(void)356 static void InitMaterials(void)
357 {
358     static float ambient[] = {0.1, 0.1, 0.1, 1.0};
359     static float diffuse[] = {0.5, 1.0, 1.0, 1.0};
360     static float position[] = {90.0, 90.0, 150.0, 0.0};
361     static float front_mat_shininess[] = {60.0};
362     static float front_mat_specular[] = {0.2, 0.2, 0.2, 1.0};
363     static float front_mat_diffuse[] = {0.5, 0.28, 0.38, 1.0};
364     static float back_mat_shininess[] = {60.0};
365     static float back_mat_specular[] = {0.5, 0.5, 0.2, 1.0};
366     static float back_mat_diffuse[] = {1.0, 1.0, 0.2, 1.0};
367     static float lmodel_ambient[] = {1.0, 1.0, 1.0, 1.0};
368     static float lmodel_twoside[] = {GL_TRUE};
369 
370     glMatrixMode(GL_PROJECTION);
371     gluPerspective(90.0, 1.0, 0.5, 10.0);
372 
373     glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
374     glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
375     glLightfv(GL_LIGHT0, GL_POSITION, position);
376     glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
377     glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, lmodel_twoside);
378     glEnable(GL_LIGHTING);
379     glEnable(GL_LIGHT0);
380 
381     glMaterialfv(GL_FRONT, GL_SHININESS, front_mat_shininess);
382     glMaterialfv(GL_FRONT, GL_SPECULAR, front_mat_specular);
383     glMaterialfv(GL_FRONT, GL_DIFFUSE, front_mat_diffuse);
384     glMaterialfv(GL_BACK, GL_SHININESS, back_mat_shininess);
385     glMaterialfv(GL_BACK, GL_SPECULAR, back_mat_specular);
386     glMaterialfv(GL_BACK, GL_DIFFUSE, back_mat_diffuse);
387     if (rgb) {
388 	glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
389     }
390 
391     if (rgb) {
392 	glEnable(GL_COLOR_MATERIAL);
393     } else {
394 	SetColorMap();
395     }
396 }
397 
InitTexture(void)398 static void InitTexture(void)
399 {
400 
401     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
402     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
403     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
404     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
405     glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
406 }
407 
Init(void)408 static void Init(void)
409 {
410 
411     glClearColor(0.0, 0.0, 0.0, 0.0);
412 
413     glShadeModel(GL_FLAT);
414 
415     glFrontFace(GL_CW);
416 
417     glEnable(GL_DEPTH_TEST);
418 
419     InitMaterials();
420     InitTexture();
421     InitMesh();
422 
423     glMatrixMode(GL_MODELVIEW);
424     glTranslatef(0.0, 0.4, -1.8);
425     glScalef(2.0, 2.0, 2.0);
426     glRotatef(-35.0, 1.0, 0.0, 0.0);
427     glRotatef(35.0, 0.0, 0.0, 1.0);
428 }
429 
Reshape(int width,int height)430 static void Reshape(int width, int height)
431 {
432 
433     glViewport(0, 0, (GLint)width, (GLint)height);
434 }
435 
Key(unsigned char key,int x,int y)436 static void Key(unsigned char key, int x, int y)
437 {
438 
439     switch (key) {
440       case 27:
441 	exit(1);
442       case 'c':
443 	contouring++;
444 	if (contouring == 1) {
445 	    static GLfloat map[4] = {0, 0, 20, 0};
446 
447 	    glTexImage2D(GL_TEXTURE_2D, 0, 3, 4, 4, 0, GL_LUMINANCE,
448 			 GL_UNSIGNED_BYTE, (GLvoid *)contourTexture1);
449 	    glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
450 	    glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
451 	    glTexGenfv(GL_S, GL_OBJECT_PLANE, map);
452 	    glTexGenfv(GL_T, GL_OBJECT_PLANE, map);
453 	    glEnable(GL_TEXTURE_2D);
454 	    glEnable(GL_TEXTURE_GEN_S);
455 	    glEnable(GL_TEXTURE_GEN_T);
456 	} else if (contouring == 2) {
457 	    static GLfloat map[4] = {0, 0, 20, 0};
458 
459 	    glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
460 	    glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
461 	    glPushMatrix();
462 	    glMatrixMode(GL_MODELVIEW);
463 	    glLoadIdentity();
464 	    glTexGenfv(GL_S, GL_EYE_PLANE, map);
465 	    glTexGenfv(GL_T, GL_EYE_PLANE, map);
466 	    glPopMatrix();
467 	} else {
468 	    contouring = 0;
469 	    glDisable(GL_TEXTURE_GEN_S);
470 	    glDisable(GL_TEXTURE_GEN_T);
471 	    glDisable(GL_TEXTURE_2D);
472 	}
473 	break;
474       case 's':
475 	smooth = !smooth;
476 	if (smooth) {
477 	    glShadeModel(GL_SMOOTH);
478 	} else {
479 	    glShadeModel(GL_FLAT);
480 	}
481 	break;
482       case 'l':
483 	lighting = !lighting;
484 	if (lighting) {
485 	    glEnable(GL_LIGHTING);
486 	    glEnable(GL_LIGHT0);
487 	    if (rgb) {
488 		glEnable(GL_COLOR_MATERIAL);
489 	    }
490 	} else {
491 	    glDisable(GL_LIGHTING);
492 	    glDisable(GL_LIGHT0);
493 	    if (rgb) {
494 		glDisable(GL_COLOR_MATERIAL);
495 	    }
496 	}
497 	break;
498       case 'd':
499 	depth = !depth;
500 	if (depth) {
501 	    glEnable(GL_DEPTH_TEST);
502 	    clearMask |= GL_DEPTH_BUFFER_BIT;
503 	} else {
504 	    glDisable(GL_DEPTH_TEST);
505 	    clearMask &= ~GL_DEPTH_BUFFER_BIT;
506 	}
507 	break;
508       case 32:
509 	stepMode = !stepMode;
510 	if (stepMode) {
511 	    glutIdleFunc(0);
512 	} else {
513 	    glutIdleFunc(glut_post_redisplay_p);
514 	}
515 	break;
516       case 'n':
517 	if (stepMode) {
518 	    nextFrame = 1;
519 	}
520 	break;
521       case 'a':
522 	spinMode = !spinMode;
523 	break;
524       default:
525 	return;
526     }
527     glutPostRedisplay();
528 }
529 
Args(int argc,char ** argv)530 static GLenum Args(int argc, char **argv)
531 {
532     GLint i;
533 
534     rgb = GL_TRUE;
535     doubleBuffer = GL_TRUE;
536     frames = 10;
537     widthX = 10;
538     widthY = 10;
539     checkerSize = 2;
540     height = 0.2;
541 
542     for (i = 1; i < argc; i++) {
543 	if (strcmp(argv[i], "-ci") == 0) {
544 	    rgb = GL_FALSE;
545 	} else if (strcmp(argv[i], "-rgb") == 0) {
546 	    rgb = GL_TRUE;
547 	} else if (strcmp(argv[i], "-sb") == 0) {
548 	    doubleBuffer = GL_FALSE;
549 	} else if (strcmp(argv[i], "-db") == 0) {
550 	    doubleBuffer = GL_TRUE;
551 	} else if (strcmp(argv[i], "-grid") == 0) {
552 	    if (i+2 >= argc || argv[i+1][0] == '-' || argv[i+2][0] == '-') {
553 		printf("-grid (No numbers).\n");
554 		return GL_FALSE;
555 	    } else {
556 		widthX = atoi(argv[++i]);
557 		widthY = atoi(argv[++i]);
558 	    }
559 	} else if (strcmp(argv[i], "-size") == 0) {
560 	    if (i+1 >= argc || argv[i+1][0] == '-') {
561 		printf("-checker (No number).\n");
562 		return GL_FALSE;
563 	    } else {
564 		checkerSize = atoi(argv[++i]);
565 	    }
566 	} else if (strcmp(argv[i], "-wave") == 0) {
567 	    if (i+1 >= argc || argv[i+1][0] == '-') {
568 		printf("-wave (No number).\n");
569 		return GL_FALSE;
570 	    } else {
571 		height = atof(argv[++i]);
572 	    }
573 	} else if (strcmp(argv[i], "-frames") == 0) {
574 	    if (i+1 >= argc || argv[i+1][0] == '-') {
575 		printf("-frames (No number).\n");
576 		return GL_FALSE;
577 	    } else {
578 		frames = atoi(argv[++i]);
579 	    }
580 	} else {
581 	    printf("%s (Bad option).\n", argv[i]);
582 	    return GL_FALSE;
583 	}
584     }
585     return GL_TRUE;
586 }
587 
main(int argc,char ** argv)588 int main(int argc, char **argv)
589 {
590     GLenum type;
591 
592     glutInit(&argc, argv);
593 
594     if (Args(argc, argv) == GL_FALSE) {
595 	exit(1);
596     }
597 
598     glutInitWindowPosition(0, 0); glutInitWindowSize( 300, 300);
599 
600     type = GLUT_DEPTH;
601     type |= (rgb) ? GLUT_RGB : GLUT_INDEX;
602     type |= (doubleBuffer) ? GLUT_DOUBLE : GLUT_SINGLE;
603     glutInitDisplayMode(type);
604 
605     if (glutCreateWindow("Wave Demo") == GL_FALSE) {
606 	exit(1);
607     }
608 
609     InitMap();
610 
611     Init();
612 
613     glutReshapeFunc(Reshape);
614     glutKeyboardFunc(Key);
615     glutDisplayFunc(Animate);
616     glutIdleFunc(glut_post_redisplay_p);
617     glutMainLoop();
618 	return 0;
619 }
620