1 /* shapes.c */
2 
3 
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <math.h>
7 
8 #include <GL/gl.h>
9 #include <GL/glu.h>
10 
11 #include "glaux.h"
12 #include "3d.h"
13 
14 
15 
16 #define SPHEREWIRE	0
17 #define CUBEWIRE	1
18 #define BOXWIRE		2
19 #define TORUSWIRE	3
20 #define CYLINDERWIRE	4
21 #define ICOSAWIRE	5
22 #define OCTAWIRE	6
23 #define TETRAWIRE	7
24 #define DODECAWIRE	8
25 #define CONEWIRE	9
26 #define SPHERESOLID	10
27 #define CUBESOLID	11
28 #define BOXSOLID	12
29 #define TORUSSOLID	13
30 #define CYLINDERSOLID	14
31 #define ICOSASOLID	15
32 #define OCTASOLID	16
33 #define TETRASOLID	17
34 #define DODECASOLID	18
35 #define CONESOLID	19
36 
37 #define PI 3.1415926535897
38 
39 /*	structure for each geometric object	*/
40 typedef struct model {
41     GLuint list;	/*  display list to render object   */
42     struct model *ptr;	/*  pointer to next object	*/
43     int numParam;	/*  # of parameters		*/
44     GLdouble *params;	/*  array with parameters	*/
45 } MODEL, *MODELPTR;
46 
47 /*	array of linked lists--used to keep track of display lists
48  *	for each different type of geometric object.
49  */
50 static MODELPTR lists[25] = {
51     NULL, NULL, NULL, NULL, NULL,
52     NULL, NULL, NULL, NULL, NULL,
53     NULL, NULL, NULL, NULL, NULL,
54     NULL, NULL, NULL, NULL, NULL,
55     NULL, NULL, NULL, NULL, NULL
56 };
57 
58 GLuint findList (int lindex, GLdouble *paramArray, int size);
59 int compareParams (GLdouble *oneArray, GLdouble *twoArray, int size);
60 GLuint makeModelPtr (int lindex, GLdouble *sizeArray, int count);
61 
62 static void drawbox(GLdouble, GLdouble, GLdouble,
63 	GLdouble, GLdouble, GLdouble, GLenum);
64 static void doughnut(GLdouble, GLdouble, GLint, GLint, GLenum);
65 static void icosahedron(GLdouble *, GLdouble, GLenum);
66 static void octahedron(GLdouble *, GLdouble, GLenum);
67 static void tetrahedron(GLdouble *, GLdouble, GLenum);
68 static void subdivide(int, GLdouble *, GLdouble *, GLdouble *,
69 	GLdouble *, GLdouble, GLenum, int);
70 static void drawtriangle(int, int, int,
71 	GLdouble *, GLdouble, GLenum, int);
72 static void recorditem(GLdouble *, GLdouble *, GLdouble *,
73 	GLdouble *, GLdouble, GLenum, int);
74 static void initdodec(void);
75 static void dodecahedron(GLdouble *, GLdouble, GLenum);
76 static void pentagon(int, int, int, int, int, GLenum);
77 
78 
79 /*  Render wire frame or solid sphere.  If no display list with
80  *  the current model size exists, create a new display list.
81  */
auxWireSphere(GLdouble radius)82 void auxWireSphere (GLdouble radius)
83 {
84     GLUquadricObj *quadObj;
85     GLdouble *sizeArray;
86     GLuint displayList;
87 
88     sizeArray = (GLdouble *) malloc (sizeof (GLdouble) * 1);
89     *sizeArray = radius;
90     displayList = findList (SPHEREWIRE, sizeArray, 1);
91 
92     if (displayList == 0) {
93 	glNewList(makeModelPtr (SPHEREWIRE, sizeArray, 1),
94 	    GL_COMPILE_AND_EXECUTE);
95 	    quadObj = gluNewQuadric ();
96 	    gluQuadricDrawStyle (quadObj, GLU_LINE);
97 	    gluSphere (quadObj, radius, 16, 16);
98 	glEndList();
99     }
100     else {
101 	glCallList(displayList);
102 	free (sizeArray);
103     }
104 }
105 
auxSolidSphere(GLdouble radius)106 void auxSolidSphere (GLdouble radius)
107 {
108     GLUquadricObj *quadObj;
109     GLdouble *sizeArray;
110     GLuint displayList;
111 
112     sizeArray = (GLdouble *) malloc (sizeof (GLdouble) * 1);
113     *sizeArray = radius;
114     displayList = findList (SPHERESOLID, sizeArray, 1);
115 
116     if (displayList == 0) {
117 	glNewList(makeModelPtr (SPHERESOLID, sizeArray, 1),
118 	    GL_COMPILE_AND_EXECUTE);
119 	    quadObj = gluNewQuadric ();
120 	    gluQuadricDrawStyle (quadObj, GLU_FILL);
121 	    gluQuadricNormals (quadObj, GLU_SMOOTH);
122 	    gluSphere (quadObj, radius, 16, 16);
123 	glEndList();
124     }
125     else {
126 	glCallList(displayList);
127 	free (sizeArray);
128     }
129 }
130 
131 /*  Render wire frame or solid cube.  If no display list with
132  *  the current model size exists, create a new display list.
133  */
auxWireCube(GLdouble size)134 void auxWireCube (GLdouble size)
135 {
136     GLdouble *sizeArray;
137     GLuint displayList;
138 
139     sizeArray = (GLdouble *) malloc (sizeof (GLdouble) * 1);
140     *sizeArray = size;
141     displayList = findList (CUBEWIRE, sizeArray, 1);
142 
143     if (displayList == 0) {
144 	glNewList(makeModelPtr (CUBEWIRE, sizeArray, 1),
145 	    GL_COMPILE_AND_EXECUTE);
146 	    drawbox(-size/2., size/2., -size/2., size/2.,
147 		-size/2., size/2., GL_LINE_LOOP);
148 	glEndList();
149     }
150     else {
151 	glCallList(displayList);
152 	free (sizeArray);
153     }
154 }
155 
auxSolidCube(GLdouble size)156 void auxSolidCube (GLdouble size)
157 {
158     GLdouble *sizeArray;
159     GLuint displayList;
160 
161     sizeArray = (GLdouble *) malloc (sizeof (GLdouble) * 1);
162     *sizeArray = size;
163     displayList = findList (CUBESOLID, sizeArray, 1);
164 
165     if (displayList == 0) {
166 	glNewList(makeModelPtr (CUBESOLID, sizeArray, 1),
167 	    GL_COMPILE_AND_EXECUTE);
168 	    drawbox(-size/2., size/2., -size/2., size/2.,
169 		-size/2., size/2., GL_QUADS);
170 	glEndList();
171     }
172     else {
173 	glCallList(displayList);
174 	free (sizeArray);
175     }
176 }
177 
178 /*  Render wire frame or solid cube.  If no display list with
179  *  the current model size exists, create a new display list.
180  */
auxWireBox(GLdouble width,GLdouble height,GLdouble depth)181 void auxWireBox (GLdouble width, GLdouble height, GLdouble depth)
182 {
183     GLdouble *sizeArray, *tmp;
184     GLuint displayList;
185 
186     sizeArray = (GLdouble *) malloc (sizeof (GLdouble) * 3);
187     tmp = sizeArray;
188     *tmp++ = width;
189     *tmp++ = height;
190     *tmp++ = depth;
191     displayList = findList (BOXWIRE, sizeArray, 3);
192 
193     if (displayList == 0) {
194 	glNewList(makeModelPtr (BOXWIRE, sizeArray, 3),
195 	    GL_COMPILE_AND_EXECUTE);
196 	    drawbox(-width/2., width/2., -height/2., height/2.,
197 		-depth/2., depth/2., GL_LINE_LOOP);
198 	glEndList();
199     }
200     else {
201 	glCallList(displayList);
202 	free (sizeArray);
203     }
204 }
205 
auxSolidBox(GLdouble width,GLdouble height,GLdouble depth)206 void auxSolidBox (GLdouble width, GLdouble height, GLdouble depth)
207 {
208     GLdouble *sizeArray, *tmp;
209     GLuint displayList;
210 
211     sizeArray = (GLdouble *) malloc (sizeof (GLdouble) * 3);
212     tmp = sizeArray;
213     *tmp++ = width;
214     *tmp++ = height;
215     *tmp++ = depth;
216     displayList = findList (BOXSOLID, sizeArray, 3);
217 
218     if (displayList == 0) {
219 	glNewList(makeModelPtr (BOXSOLID, sizeArray, 3),
220 	    GL_COMPILE_AND_EXECUTE);
221 	    drawbox(-width/2., width/2., -height/2., height/2.,
222 		-depth/2., depth/2., GL_QUADS);
223 	glEndList();
224     }
225     else {
226 	glCallList(displayList);
227 	free (sizeArray);
228     }
229 }
230 
231 /*  Render wire frame or solid tori.  If no display list with
232  *  the current model size exists, create a new display list.
233  */
auxWireTorus(GLdouble innerRadius,GLdouble outerRadius)234 void auxWireTorus (GLdouble innerRadius, GLdouble outerRadius)
235 {
236     GLdouble *sizeArray, *tmp;
237     GLuint displayList;
238 
239     sizeArray = (GLdouble *) malloc (sizeof (GLdouble) * 2);
240     tmp = sizeArray;
241     *tmp++ = innerRadius;
242     *tmp++ = outerRadius;
243     displayList = findList (TORUSWIRE, sizeArray, 2);
244 
245     if (displayList == 0) {
246 	glNewList(makeModelPtr (TORUSWIRE, sizeArray, 2),
247 	    GL_COMPILE_AND_EXECUTE);
248 	    doughnut(innerRadius, outerRadius, 5, 10, GL_LINE_LOOP);
249 	glEndList();
250     }
251     else {
252 	glCallList(displayList);
253 	free (sizeArray);
254     }
255 }
256 
auxSolidTorus(GLdouble innerRadius,GLdouble outerRadius)257 void auxSolidTorus (GLdouble innerRadius, GLdouble outerRadius)
258 {
259     GLdouble *sizeArray, *tmp;
260     GLuint displayList;
261 
262     sizeArray = (GLdouble *) malloc (sizeof (GLdouble) * 2);
263     tmp = sizeArray;
264     *tmp++ = innerRadius;
265     *tmp++ = outerRadius;
266     displayList = findList (TORUSSOLID, sizeArray, 2);
267 
268     if (displayList == 0) {
269 	glNewList(makeModelPtr (TORUSSOLID, sizeArray, 2),
270 	    GL_COMPILE_AND_EXECUTE);
271 	    doughnut(innerRadius, outerRadius, 8, 15, GL_QUADS);
272 	glEndList();
273     }
274     else {
275 	glCallList(displayList);
276 	free (sizeArray);
277     }
278 }
279 
280 /*  Render wire frame or solid cylinders.  If no display list with
281  *  the current model size exists, create a new display list.
282  */
auxWireCylinder(GLdouble radius,GLdouble height)283 void auxWireCylinder (GLdouble radius, GLdouble height)
284 {
285     GLUquadricObj *quadObj;
286     GLdouble *sizeArray, *tmp;
287     GLuint displayList;
288 
289     sizeArray = (GLdouble *) malloc (sizeof (GLdouble) * 2);
290     tmp = sizeArray;
291     *tmp++ = radius;
292     *tmp++ = height;
293     displayList = findList (CYLINDERWIRE, sizeArray, 2);
294 
295     if (displayList == 0) {
296 	glNewList(makeModelPtr (CYLINDERWIRE, sizeArray, 2),
297 	    GL_COMPILE_AND_EXECUTE);
298 	    glPushMatrix ();
299 	    glRotatef (90.0, 1.0, 0.0, 0.0);
300 	    glTranslatef (0.0, 0.0, -1.0);
301 	    quadObj = gluNewQuadric ();
302 	    gluQuadricDrawStyle (quadObj, GLU_LINE);
303 	    gluCylinder (quadObj, radius, radius, height, 12, 2);
304 	    glPopMatrix ();
305 	glEndList();
306     }
307     else {
308 	glCallList(displayList);
309 	free (sizeArray);
310     }
311 }
312 
auxSolidCylinder(GLdouble radius,GLdouble height)313 void auxSolidCylinder (GLdouble radius, GLdouble height)
314 {
315     GLUquadricObj *quadObj;
316     GLdouble *sizeArray, *tmp;
317     GLuint displayList;
318 
319     sizeArray = (GLdouble *) malloc (sizeof (GLdouble) * 2);
320     tmp = sizeArray;
321     *tmp++ = radius;
322     *tmp++ = height;
323     displayList = findList (CYLINDERWIRE, sizeArray, 2);
324 
325     if (displayList == 0) {
326 	glNewList(makeModelPtr (CYLINDERWIRE, sizeArray, 2),
327 	    GL_COMPILE_AND_EXECUTE);
328 	    glPushMatrix ();
329 	    glRotatef (90.0, 1.0, 0.0, 0.0);
330 	    glTranslatef (0.0, 0.0, -1.0);
331 	    quadObj = gluNewQuadric ();
332 	    gluQuadricDrawStyle (quadObj, GLU_FILL);
333 	    gluQuadricNormals (quadObj, GLU_SMOOTH);
334 	    gluCylinder (quadObj, radius, radius, height, 12, 2);
335 	    glPopMatrix ();
336 	glEndList();
337     }
338     else {
339 	glCallList(displayList);
340 	free (sizeArray);
341     }
342 }
343 
344 /*  Render wire frame or solid icosahedra.  If no display list with
345  *  the current model size exists, create a new display list.
346  */
auxWireIcosahedron(GLdouble radius)347 void auxWireIcosahedron (GLdouble radius)
348 {
349     GLdouble *sizeArray;
350     GLuint displayList;
351     GLdouble center[3] = {0.0, 0.0, 0.0};
352 
353     sizeArray = (GLdouble *) malloc (sizeof (GLdouble) * 1);
354     *sizeArray = radius;
355     displayList = findList (ICOSAWIRE, sizeArray, 1);
356 
357     if (displayList == 0) {
358 	glNewList(makeModelPtr (ICOSAWIRE, sizeArray, 1),
359 	    GL_COMPILE_AND_EXECUTE);
360 	    icosahedron (center, radius, GL_LINE_LOOP);
361 	glEndList();
362     }
363     else {
364 	glCallList(displayList);
365 	free (sizeArray);
366     }
367 }
368 
auxSolidIcosahedron(GLdouble radius)369 void auxSolidIcosahedron (GLdouble radius)
370 {
371     GLdouble *sizeArray;
372     GLuint displayList;
373     GLdouble center[3] = {0.0, 0.0, 0.0};
374 
375     sizeArray = (GLdouble *) malloc (sizeof (GLdouble) * 1);
376     *sizeArray = radius;
377     displayList = findList (ICOSASOLID, sizeArray, 1);
378 
379     if (displayList == 0) {
380 	glNewList(makeModelPtr (ICOSASOLID, sizeArray, 1),
381 	    GL_COMPILE_AND_EXECUTE);
382 	    icosahedron (center, radius, GL_TRIANGLES);
383 	glEndList();
384     }
385     else {
386 	glCallList(displayList);
387 	free (sizeArray);
388     }
389 }
390 
391 /*  Render wire frame or solid octahedra.  If no display list with
392  *  the current model size exists, create a new display list.
393  */
auxWireOctahedron(GLdouble radius)394 void auxWireOctahedron (GLdouble radius)
395 {
396     GLdouble *sizeArray;
397     GLuint displayList;
398     GLdouble center[3] = {0.0, 0.0, 0.0};
399 
400     sizeArray = (GLdouble *) malloc (sizeof (GLdouble) * 1);
401     *sizeArray = radius;
402     displayList = findList (OCTAWIRE, sizeArray, 1);
403 
404     if (displayList == 0) {
405 	glNewList(makeModelPtr (OCTAWIRE, sizeArray, 1),
406 	    GL_COMPILE_AND_EXECUTE);
407 	    octahedron (center, radius, GL_LINE_LOOP);
408 	glEndList();
409     }
410     else {
411 	glCallList(displayList);
412 	free (sizeArray);
413     }
414 }
415 
auxSolidOctahedron(GLdouble radius)416 void auxSolidOctahedron (GLdouble radius)
417 {
418     GLdouble *sizeArray;
419     GLuint displayList;
420     GLdouble center[3] = {0.0, 0.0, 0.0};
421 
422     sizeArray = (GLdouble *) malloc (sizeof (GLdouble) * 1);
423     *sizeArray = radius;
424     displayList = findList (OCTASOLID, sizeArray, 1);
425 
426     if (displayList == 0) {
427 	glNewList(makeModelPtr (OCTASOLID, sizeArray, 1),
428 	    GL_COMPILE_AND_EXECUTE);
429 	    octahedron (center, radius, GL_TRIANGLES);
430 	glEndList();
431     }
432     else {
433 	glCallList(displayList);
434 	free (sizeArray);
435     }
436 }
437 
438 /*  Render wire frame or solid tetrahedra.  If no display list with
439  *  the current model size exists, create a new display list.
440  */
auxWireTetrahedron(GLdouble radius)441 void auxWireTetrahedron (GLdouble radius)
442 {
443     GLdouble *sizeArray;
444     GLuint displayList;
445     GLdouble center[3] = {0.0, 0.0, 0.0};
446 
447     sizeArray = (GLdouble *) malloc (sizeof (GLdouble) * 1);
448     *sizeArray = radius;
449     displayList = findList (TETRAWIRE, sizeArray, 1);
450 
451     if (displayList == 0) {
452 	glNewList(makeModelPtr (TETRAWIRE, sizeArray, 1),
453 	    GL_COMPILE_AND_EXECUTE);
454 	    tetrahedron (center, radius, GL_LINE_LOOP);
455 	glEndList();
456     }
457     else {
458 	glCallList(displayList);
459 	free (sizeArray);
460     }
461 }
462 
auxSolidTetrahedron(GLdouble radius)463 void auxSolidTetrahedron (GLdouble radius)
464 {
465     GLdouble *sizeArray;
466     GLuint displayList;
467     GLdouble center[3] = {0.0, 0.0, 0.0};
468 
469     sizeArray = (GLdouble *) malloc (sizeof (GLdouble) * 1);
470     *sizeArray = radius;
471     displayList = findList (TETRASOLID, sizeArray, 1);
472 
473     if (displayList == 0) {
474 	glNewList(makeModelPtr (TETRASOLID, sizeArray, 1),
475 	    GL_COMPILE_AND_EXECUTE);
476 	    tetrahedron (center, radius, GL_TRIANGLES);
477 	glEndList();
478     }
479     else {
480 	glCallList(displayList);
481 	free (sizeArray);
482     }
483 }
484 
485 /*  Render wire frame or solid dodecahedra.  If no display list with
486  *  the current model size exists, create a new display list.
487  */
auxWireDodecahedron(GLdouble radius)488 void auxWireDodecahedron (GLdouble radius)
489 {
490     GLdouble *sizeArray;
491     GLuint displayList;
492     GLdouble center[3] = {0.0, 0.0, 0.0};
493 
494     sizeArray = (GLdouble *) malloc (sizeof (GLdouble) * 1);
495     *sizeArray = radius;
496     displayList = findList (DODECAWIRE, sizeArray, 1);
497 
498     if (displayList == 0) {
499 	glNewList(makeModelPtr (DODECAWIRE, sizeArray, 1),
500 	    GL_COMPILE_AND_EXECUTE);
501 	    dodecahedron (center, radius/1.73, GL_LINE_LOOP);
502 	glEndList();
503     }
504     else {
505 	glCallList(displayList);
506 	free (sizeArray);
507     }
508 }
509 
auxSolidDodecahedron(GLdouble radius)510 void auxSolidDodecahedron (GLdouble radius)
511 {
512     GLdouble *sizeArray;
513     GLuint displayList;
514     GLdouble center[3] = {0.0, 0.0, 0.0};
515 
516     sizeArray = (GLdouble *) malloc (sizeof (GLdouble) * 1);
517     *sizeArray = radius;
518     displayList = findList (DODECASOLID, sizeArray, 1);
519 
520     if (displayList == 0) {
521 	glNewList(makeModelPtr (DODECASOLID, sizeArray, 1),
522 	    GL_COMPILE_AND_EXECUTE);
523 	    dodecahedron (center, radius/1.73, GL_TRIANGLE_FAN);
524 	glEndList();
525     }
526     else {
527 	glCallList(displayList);
528 	free (sizeArray);
529     }
530 }
531 
532 /*  Render wire frame or solid cones.  If no display list with
533  *  the current model size exists, create a new display list.
534  */
auxWireCone(GLdouble base,GLdouble height)535 void auxWireCone (GLdouble base, GLdouble height)
536 {
537     GLUquadricObj *quadObj;
538     GLdouble *sizeArray, *tmp;
539     GLuint displayList;
540 
541     sizeArray = (GLdouble *) malloc (sizeof (GLdouble) * 2);
542     tmp = sizeArray;
543     *tmp++ = base;
544     *tmp++ = height;
545     displayList = findList (CONEWIRE, sizeArray, 2);
546 
547     if (displayList == 0) {
548 	glNewList(makeModelPtr (CONEWIRE, sizeArray, 2),
549 	    GL_COMPILE_AND_EXECUTE);
550 	    quadObj = gluNewQuadric ();
551 	    gluQuadricDrawStyle (quadObj, GLU_LINE);
552 	    gluCylinder (quadObj, base, 0.0, height, 15, 10);
553 	glEndList();
554     }
555     else {
556 	glCallList(displayList);
557 	free (sizeArray);
558     }
559 }
560 
auxSolidCone(GLdouble base,GLdouble height)561 void auxSolidCone (GLdouble base, GLdouble height)
562 {
563     GLUquadricObj *quadObj;
564     GLdouble *sizeArray, *tmp;
565     GLuint displayList;
566 
567     sizeArray = (GLdouble *) malloc (sizeof (GLdouble) * 2);
568     tmp = sizeArray;
569     *tmp++ = base;
570     *tmp++ = height;
571     displayList = findList (CONEWIRE, sizeArray, 2);
572 
573     if (displayList == 0) {
574 	glNewList(makeModelPtr (CONEWIRE, sizeArray, 2),
575 	    GL_COMPILE_AND_EXECUTE);
576 	    quadObj = gluNewQuadric ();
577 	    gluQuadricDrawStyle (quadObj, GLU_FILL);
578 	    gluQuadricNormals (quadObj, GLU_SMOOTH);
579 	    gluCylinder (quadObj, base, 0.0, height, 15, 10);
580 	glEndList();
581     }
582     else {
583 	glCallList(displayList);
584 	free (sizeArray);
585     }
586 }
587 
588 /* Routines to build 3 dimensional solids, including:
589  *
590  * drawbox, doughnut, icosahedron,
591  * octahedron, tetrahedron, dodecahedron.
592  */
593 
594 /* drawbox:
595  *
596  * draws a rectangular box with the given x, y, and z ranges.
597  * The box is axis-aligned.
598  */
drawbox(GLdouble x0,GLdouble x1,GLdouble y0,GLdouble y1,GLdouble z0,GLdouble z1,GLenum type)599 static void drawbox(GLdouble x0, GLdouble x1, GLdouble y0, GLdouble y1,
600 	GLdouble z0, GLdouble z1, GLenum type)
601 {
602     static GLdouble n[6][3] = {
603 	{-1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {1.0, 0.0, 0.0},
604 	{0.0, -1.0, 0.0}, {0.0, 0.0, 1.0}, {0.0, 0.0, -1.0}
605     };
606     static GLint faces[6][4] = {
607 	{ 0, 1, 2, 3 }, { 3, 2, 6, 7 }, { 7, 6, 5, 4 },
608 	{ 4, 5, 1, 0 }, { 5, 6, 2, 1 }, { 7, 4, 0, 3 }
609     };
610     GLdouble v[8][3], tmp;
611     GLint i;
612 
613     if (x0 > x1) {
614 	tmp = x0; x0 = x1; x1 = tmp;
615     }
616     if (y0 > y1) {
617 	tmp = y0; y0 = y1; y1 = tmp;
618     }
619     if (z0 > z1) {
620 	tmp = z0; z0 = z1; z1 = tmp;
621     }
622     v[0][0] = v[1][0] = v[2][0] = v[3][0] = x0;
623     v[4][0] = v[5][0] = v[6][0] = v[7][0] = x1;
624     v[0][1] = v[1][1] = v[4][1] = v[5][1] = y0;
625     v[2][1] = v[3][1] = v[6][1] = v[7][1] = y1;
626     v[0][2] = v[3][2] = v[4][2] = v[7][2] = z0;
627     v[1][2] = v[2][2] = v[5][2] = v[6][2] = z1;
628 
629     for (i = 0; i < 6; i++) {
630 	glBegin(type);
631 	glNormal3dv(&n[i][0]);
632 	glVertex3dv(&v[faces[i][0]][0]);
633 	glNormal3dv(&n[i][0]);
634 	glVertex3dv(&v[faces[i][1]][0]);
635 	glNormal3dv(&n[i][0]);
636 	glVertex3dv(&v[faces[i][2]][0]);
637 	glNormal3dv(&n[i][0]);
638 	glVertex3dv(&v[faces[i][3]][0]);
639 	glEnd();
640     }
641 }
642 
643 /* doughnut:
644  *
645  * draws a doughnut, centered at (0, 0, 0) whose axis is aligned with
646  * the z-axis.  The doughnut's major radius is R, and minor radius is r.
647  */
648 
doughnut(GLdouble r,GLdouble R,GLint nsides,GLint rings,GLenum type)649 static void doughnut(GLdouble r, GLdouble R, GLint nsides, GLint rings, GLenum type)
650 {
651     int	i, j;
652     GLdouble	theta, phi, theta1, phi1;
653     GLdouble	p0[03], p1[3], p2[3], p3[3];
654     GLdouble	n0[3], n1[3], n2[3], n3[3];
655 
656     for (i = 0; i < rings; i++) {
657 	theta = (GLdouble)i*2.0*PI/rings;
658 	theta1 = (GLdouble)(i+1)*2.0*PI/rings;
659 	for (j = 0; j < nsides; j++) {
660 	    phi = (GLdouble)j*2.0*PI/nsides;
661 	    phi1 = (GLdouble)(j+1)*2.0*PI/nsides;
662 
663 	    p0[0] = cos(theta)*(R + r*cos(phi));
664 	    p0[1] = -sin(theta)*(R + r*cos(phi));
665 	    p0[2] = r*sin(phi);
666 
667 	    p1[0] = cos(theta1)*(R + r*cos(phi));
668 	    p1[1] = -sin(theta1)*(R + r*cos(phi));
669 	    p1[2] = r*sin(phi);
670 
671 	    p2[0] = cos(theta1)*(R + r*cos(phi1));
672 	    p2[1] = -sin(theta1)*(R + r*cos(phi1));
673 	    p2[2] = r*sin(phi1);
674 
675 	    p3[0] = cos(theta)*(R + r*cos(phi1));
676 	    p3[1] = -sin(theta)*(R + r*cos(phi1));
677 	    p3[2] = r*sin(phi1);
678 
679 	    n0[0] = cos(theta)*(cos(phi));
680 	    n0[1] = -sin(theta)*(cos(phi));
681 	    n0[2] = sin(phi);
682 
683 	    n1[0] = cos(theta1)*(cos(phi));
684 	    n1[1] = -sin(theta1)*(cos(phi));
685 	    n1[2] = sin(phi);
686 
687 	    n2[0] = cos(theta1)*(cos(phi1));
688 	    n2[1] = -sin(theta1)*(cos(phi1));
689 	    n2[2] = sin(phi1);
690 
691 	    n3[0] = cos(theta)*(cos(phi1));
692 	    n3[1] = -sin(theta)*(cos(phi1));
693 	    n3[2] = sin(phi1);
694 
695 	    m_xformpt(p0, p0, n0, n0);
696 	    m_xformpt(p1, p1, n1, n1);
697 	    m_xformpt(p2, p2, n2, n2);
698 	    m_xformpt(p3, p3, n3, n3);
699 
700 	    glBegin(type);
701 		glNormal3dv(n3);
702 		glVertex3dv(p3);
703 		glNormal3dv(n2);
704 		glVertex3dv(p2);
705 		glNormal3dv(n1);
706 		glVertex3dv(p1);
707 		glNormal3dv(n0);
708 		glVertex3dv(p0);
709 	    glEnd();
710 	}
711     }
712 }
713 
714 /* octahedron data: The octahedron produced is centered
715  * at the origin and has radius 1.0
716  */
717 static GLdouble odata[6][3] = {
718   {1.0, 0.0, 0.0},
719   {-1.0, 0.0, 0.0},
720   {0.0, 1.0, 0.0},
721   {0.0, -1.0, 0.0},
722   {0.0, 0.0, 1.0},
723   {0.0, 0.0, -1.0}
724 };
725 
726 static int ondex[8][3] = {
727     {0, 4, 2}, {1, 2, 4}, {0, 3, 4}, {1, 4, 3},
728     {0, 2, 5}, {1, 5, 2}, {0, 5, 3}, {1, 3, 5}
729 };
730 
731 /* tetrahedron data: */
732 
733 #define T	1.73205080756887729
734 
735 static GLdouble tdata[4][3] = {
736     {T, T, T}, {T, -T, -T}, {-T, T, -T}, {-T, -T, T}
737 };
738 
739 static int tndex[4][3] = {
740     {0, 1, 3}, {2, 1, 0}, {3, 2, 0}, {1, 2, 3}
741 };
742 
743 /* icosahedron data: These numbers are rigged to
744  * make an icosahedron of radius 1.0
745  */
746 
747 #define X .525731112119133606
748 #define Z .850650808352039932
749 
750 static GLdouble idata[12][3] = {
751   {-X, 0.0, Z},
752   {X, 0.0, Z},
753   {-X, 0.0, -Z},
754   {X, 0.0, -Z},
755   {0.0, Z, X},
756   {0.0, Z, -X},
757   {0.0, -Z, X},
758   {0.0, -Z, -X},
759   {Z, X, 0.0},
760   {-Z, X, 0.0},
761   {Z, -X, 0.0},
762   {-Z, -X, 0.0},
763 };
764 
765 static int iindex[20][3] = {
766     {0, 4, 1},    {0, 9, 4},
767     {9, 5, 4},    {4, 5, 8},
768     {4, 8, 1},    {8, 10, 1},
769     {8, 3, 10},    {5, 3, 8},
770     {5, 2, 3},    {2, 7, 3},
771     {7, 10, 3},    {7, 6, 10},
772     {7, 11, 6},    {11, 0, 6},
773     {0, 1, 6},    {6, 1, 10},
774     {9, 0, 11},    {9, 11, 2},
775     {9, 2, 5},    {7, 2, 11},
776 };
777 
778 /* icosahedron:
779  *
780  * Draws an icosahedron with center at p0 having the
781  * given radius.
782  */
783 
icosahedron(GLdouble p0[3],GLdouble radius,GLenum shadeType)784 static void icosahedron(GLdouble p0[3], GLdouble radius, GLenum shadeType)
785 {
786     int i;
787 
788     for (i = 0; i < 20; i++)
789 	drawtriangle(i, 0, 1, p0, radius, shadeType, 0);
790 }
791 
792 /* octahedron:
793  *
794  * Draws an octahedron with center at p0 having the
795  * given radius.
796  */
octahedron(GLdouble p0[3],GLdouble radius,GLenum shadeType)797 static void octahedron(GLdouble p0[3], GLdouble radius, GLenum shadeType)
798 {
799     int i;
800 
801     for (i = 0; i < 8; i++)
802 	drawtriangle(i, 1, 1, p0, radius, shadeType, 0);
803 }
804 
805 /* tetrahedron:
806  *
807  * Draws an tetrahedron with center at p0 having the
808  * given radius.
809  */
810 
tetrahedron(GLdouble p0[3],GLdouble radius,GLenum shadeType)811 static void tetrahedron(GLdouble p0[3], GLdouble radius, GLenum shadeType)
812 {
813     int i;
814 
815     for (i = 0; i < 4; i++)
816 	drawtriangle(i, 2, 1, p0, radius, shadeType, 0);
817 }
818 
subdivide(int depth,GLdouble * v0,GLdouble * v1,GLdouble * v2,GLdouble p0[3],GLdouble radius,GLenum shadeType,int avnormal)819 static void subdivide(int depth, GLdouble *v0, GLdouble *v1, GLdouble *v2,
820 	GLdouble p0[3], GLdouble radius, GLenum shadeType, int avnormal)
821 {
822     GLdouble w0[3], w1[3], w2[3];
823     GLdouble l;
824     int i, j, k, n;
825 
826     for (i = 0; i < depth; i++)
827 	for (j = 0; i + j < depth; j++) {
828 	    k = depth - i - j;
829 	    for (n = 0; n < 3; n++) {
830 		w0[n] = (i*v0[n] + j*v1[n] + k*v2[n])/depth;
831 		w1[n] = ((i+1)*v0[n] + j*v1[n] + (k-1)*v2[n])/depth;
832 		w2[n] = (i*v0[n] + (j+1)*v1[n] + (k-1)*v2[n])/depth;
833 	    }
834 	    l = sqrt(w0[0]*w0[0] + w0[1]*w0[1] + w0[2]*w0[2]);
835 	    w0[0] /= l; w0[1] /= l; w0[2] /= l;
836 	    l = sqrt(w1[0]*w1[0] + w1[1]*w1[1] + w1[2]*w1[2]);
837 	    w1[0] /= l; w1[1] /= l; w1[2] /= l;
838 	    l = sqrt(w2[0]*w2[0] + w2[1]*w2[1] + w2[2]*w2[2]);
839 	    w2[0] /= l; w2[1] /= l; w2[2] /= l;
840 	    recorditem(w1, w0, w2, p0, radius, shadeType, avnormal);
841 	}
842     for (i = 0; i < depth-1; i++)
843 	for (j = 0; i + j < depth-1; j++) {
844 	    k = depth - i - j;
845 	    for (n = 0; n < 3; n++) {
846 		w0[n] = ((i+1)*v0[n] + (j+1)*v1[n] + (k-2)*v2[n])/depth;
847 		w1[n] = ((i+1)*v0[n] + j*v1[n] + (k-1)*v2[n])/depth;
848 		w2[n] = (i*v0[n] + (j+1)*v1[n] + (k-1)*v2[n])/depth;
849 	    }
850 	    l = sqrt(w0[0]*w0[0] + w0[1]*w0[1] + w0[2]*w0[2]);
851 	    w0[0] /= l; w0[1] /= l; w0[2] /= l;
852 	    l = sqrt(w1[0]*w1[0] + w1[1]*w1[1] + w1[2]*w1[2]);
853 	    w1[0] /= l; w1[1] /= l; w1[2] /= l;
854 	    l = sqrt(w2[0]*w2[0] + w2[1]*w2[1] + w2[2]*w2[2]);
855 	    w2[0] /= l; w2[1] /= l; w2[2] /= l;
856 	    recorditem(w0, w1, w2, p0, radius, shadeType, avnormal);
857 	}
858 }
859 
drawtriangle(int i,int geomType,int depth,GLdouble p0[3],GLdouble radius,GLenum shadeType,int avnormal)860 static void drawtriangle(int i, int geomType, int depth,
861 	GLdouble p0[3], GLdouble radius, GLenum shadeType, int avnormal)
862 {
863     GLdouble *x0, *x1, *x2;
864 
865     switch (geomType) {
866 	case 0:	/* icosahedron */
867 	    x0 = &idata[iindex[i][0]][0];
868 	    x1 = &idata[iindex[i][1]][0];
869 	    x2 = &idata[iindex[i][2]][0];
870 	    break;
871 	case 1: /* octahedron */
872 	    x0 = &odata[ondex[i][0]][0];
873 	    x1 = &odata[ondex[i][1]][0];
874 	    x2 = &odata[ondex[i][2]][0];
875 	    break;
876 	case 2: /* tetrahedron */
877 	    x0 = &tdata[tndex[i][0]][0];
878 	    x1 = &tdata[tndex[i][1]][0];
879 	    x2 = &tdata[tndex[i][2]][0];
880 	    break;
881     }
882     subdivide(depth, x0, x1, x2, p0, radius, shadeType, avnormal);
883 }
884 
recorditem(GLdouble * n1,GLdouble * n2,GLdouble * n3,GLdouble center[3],GLdouble radius,GLenum shadeType,int avnormal)885 static void recorditem(GLdouble *n1, GLdouble *n2, GLdouble *n3,
886 	GLdouble center[3], GLdouble radius, GLenum shadeType, int avnormal)
887 {
888     GLdouble p1[3], p2[3], p3[3], q0[3], q1[3], n11[3], n22[3], n33[3];
889     int	i;
890 
891     for (i = 0; i < 3; i++) {
892 	p1[i] = n1[i]*radius + center[i];
893 	p2[i] = n2[i]*radius + center[i];
894 	p3[i] = n3[i]*radius + center[i];
895     }
896     if (avnormal == 0) {
897 	diff3(p1, p2, q0);
898 	diff3(p2, p3, q1);
899 	crossprod(q0, q1, q1);
900 	normalize(q1);
901 	m_xformpt(p1, p1, q1, n11);
902 	m_xformptonly(p2, p2);
903 	m_xformptonly(p3, p3);
904 
905 	glBegin (shadeType);
906 	glNormal3dv(n11);
907 	glVertex3dv(p1);
908 	glVertex3dv(p2);
909 	glVertex3dv(p3);
910 	glEnd();
911 	return;
912     }
913     m_xformpt(p1, p1, n1, n11);
914     m_xformpt(p2, p2, n2, n22);
915     m_xformpt(p3, p3, n3, n33);
916 
917     glBegin (shadeType);
918     glNormal3dv(n11);
919     glVertex3dv(p1);
920     glNormal3dv(n22);
921     glVertex3dv(p2);
922     glNormal3dv(n33);
923     glVertex3dv(p3);
924     glEnd();
925 }
926 
927 static GLdouble dodec[20][3];
928 
initdodec()929 static void initdodec()
930 {
931     GLdouble alpha, beta;
932 
933     alpha = sqrt(2.0/(3.0 + sqrt(5.0)));
934     beta = 1.0 + sqrt(6.0/(3.0 + sqrt(5.0)) - 2.0 + 2.0*sqrt(2.0/(3.0 +
935 							    sqrt(5.0))));
936     dodec[0][0] = -alpha; dodec[0][1] = 0; dodec[0][2] = beta;
937     dodec[1][0] = alpha; dodec[1][1] = 0; dodec[1][2] = beta;
938     dodec[2][0] = -1; dodec[2][1] = -1; dodec[2][2] = -1;
939     dodec[3][0] = -1; dodec[3][1] = -1; dodec[3][2] = 1;
940     dodec[4][0] = -1; dodec[4][1] = 1; dodec[4][2] = -1;
941     dodec[5][0] = -1; dodec[5][1] = 1; dodec[5][2] = 1;
942     dodec[6][0] = 1; dodec[6][1] = -1; dodec[6][2] = -1;
943     dodec[7][0] = 1; dodec[7][1] = -1; dodec[7][2] = 1;
944     dodec[8][0] = 1; dodec[8][1] = 1; dodec[8][2] = -1;
945     dodec[9][0] = 1; dodec[9][1] = 1; dodec[9][2] = 1;
946     dodec[10][0] = beta; dodec[10][1] = alpha; dodec[10][2] = 0;
947     dodec[11][0] = beta; dodec[11][1] = -alpha; dodec[11][2] = 0;
948     dodec[12][0] = -beta; dodec[12][1] = alpha; dodec[12][2] = 0;
949     dodec[13][0] = -beta; dodec[13][1] = -alpha; dodec[13][2] = 0;
950     dodec[14][0] = -alpha; dodec[14][1] = 0; dodec[14][2] = -beta;
951     dodec[15][0] = alpha; dodec[15][1] = 0; dodec[15][2] = -beta;
952     dodec[16][0] = 0; dodec[16][1] = beta; dodec[16][2] = alpha;
953     dodec[17][0] = 0; dodec[17][1] = beta; dodec[17][2] = -alpha;
954     dodec[18][0] = 0; dodec[18][1] = -beta; dodec[18][2] = alpha;
955     dodec[19][0] = 0; dodec[19][1] = -beta; dodec[19][2] = -alpha;
956 }
957 
958 /* dodecahedron:
959  *
960  * Draws an dodecahedron with center at 0.0. The radius
961  * is sqrt(3).
962  */
dodecahedron(GLdouble center[3],GLdouble sc,GLenum type)963 static void dodecahedron(GLdouble center[3], GLdouble sc, GLenum type)
964 {
965     static int inited = 0;
966 
967     if ( inited == 0) {
968 	inited = 1;
969 	initdodec();
970     }
971     m_pushmatrix();
972     m_translate(center[0], center[1], center[2]);
973     m_scale(sc, sc, sc);
974     pentagon(0, 1, 9, 16, 5, type);
975     pentagon(1, 0, 3, 18, 7, type);
976     pentagon(1, 7, 11, 10, 9, type);
977     pentagon(11, 7, 18, 19, 6, type);
978     pentagon(8, 17, 16, 9, 10, type);
979     pentagon(2, 14, 15, 6, 19, type);
980     pentagon(2, 13, 12, 4, 14, type);
981     pentagon(2, 19, 18, 3, 13, type);
982     pentagon(3, 0, 5, 12, 13, type);
983     pentagon(6, 15, 8, 10, 11, type);
984     pentagon(4, 17, 8, 15, 14, type);
985     pentagon(4, 12, 5, 16, 17, type);
986     m_popmatrix();
987 }
988 
pentagon(int a,int b,int c,int d,int e,GLenum shadeType)989 static void pentagon(int a, int b, int c, int d, int e, GLenum shadeType)
990 {
991     GLdouble n0[3], d1[3], d2[3], d3[3], d4[3], d5[3], nout[3];
992 
993     diff3(&dodec[a][0], &dodec[b][0], d1);
994     diff3(&dodec[b][0], &dodec[c][0], d2);
995     crossprod(d1, d2, n0);
996     normalize(n0);
997     m_xformpt(&dodec[a][0], d1, n0, nout);
998     m_xformptonly(&dodec[b][0], d2);
999     m_xformptonly(&dodec[c][0], d3);
1000     m_xformptonly(&dodec[d][0], d4);
1001     m_xformptonly(&dodec[e][0], d5);
1002 
1003     glBegin (shadeType);
1004     glNormal3dv(nout);
1005     glVertex3dv(d1);
1006     glVertex3dv(d2);
1007     glVertex3dv(d3);
1008     glVertex3dv(d4);
1009     glVertex3dv(d5);
1010     glEnd();
1011 }
1012 
1013 /*	linked lists--display lists for each different
1014  *	type of geometric objects.  The linked list is
1015  *	searched, until an object of the requested
1016  *	size is found.  If no geometric object of that size
1017  *	has been previously made, a new one is created.
1018  */
findList(int lindex,GLdouble * paramArray,int size)1019 GLuint findList (int lindex, GLdouble *paramArray, int size)
1020 {
1021     MODELPTR endList;
1022     int found = 0;
1023 
1024     endList = lists[lindex];
1025     while (endList != NULL) {
1026 	if (compareParams (endList->params, paramArray, size))
1027 	    return (endList->list);
1028 	endList = endList->ptr;
1029     }
1030 /*  if not found, return 0 and calling routine should
1031  *  make a new list
1032  */
1033     return (0);
1034 }
1035 
compareParams(GLdouble * oneArray,GLdouble * twoArray,int size)1036 int compareParams (GLdouble *oneArray, GLdouble *twoArray, int size)
1037 {
1038     int i;
1039     int matches = 1;
1040 
1041     for (i = 0; (i < size) && matches; i++) {
1042 	if (*oneArray++ != *twoArray++)
1043 	    matches = 0;
1044     }
1045     return (matches);
1046 }
1047 
makeModelPtr(int lindex,GLdouble * sizeArray,int count)1048 GLuint makeModelPtr (int lindex, GLdouble *sizeArray, int count)
1049 {
1050     MODELPTR newModel;
1051 
1052     newModel = (MODELPTR) malloc (sizeof (MODEL));
1053     newModel->list = glGenLists (1);
1054     newModel->numParam = count;
1055     newModel->params = sizeArray;
1056     newModel->ptr = lists[lindex];
1057     lists[lindex] = newModel;
1058 
1059     return (newModel->list);
1060 }
1061