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
39GLenum rgb, doubleBuffer;
40
41#include "tkmap.c"
42
43GLint colorIndexes1[3];
44GLint colorIndexes2[3];
45GLenum clearMask = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT;
46
47GLenum smooth = GL_FALSE;
48GLenum lighting = GL_TRUE;
49GLenum depth = GL_TRUE;
50GLenum stepMode = GL_FALSE;
51GLenum spinMode = GL_FALSE;
52GLint contouring = 0;
53
54GLint widthX, widthY;
55GLint checkerSize;
56float height;
57
58GLint frames, curFrame = 0, nextFrame = 0;
59
60struct facet {
61    float color[3];
62    float normal[3];
63};
64struct coord {
65    float vertex[3];
66    float normal[3];
67};
68struct 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
77GLubyte contourTexture1[] = {
78    255, 255, 255, 255,
79    255, 255, 255, 255,
80    255, 255, 255, 255,
81    127, 127, 127, 127,
82};
83GLubyte 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
95static 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
112static 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
202static 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
245static 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
356static 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
398static 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
408static 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
430static void Reshape(int width, int height)
431{
432
433    glViewport(0, 0, (GLint)width, (GLint)height);
434}
435
436static 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
530static 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
588int 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