xref: /haiku/src/libs/glut/glut_shapes.c (revision 820dca4df6c7bf955c46e8f6521b9408f50b2900)
1 /*
2  * Copyright 1994-1997 Mark Kilgard, All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *      Mark Kilgard
7  */
8 
9 /**
10 (c) Copyright 1993, Silicon Graphics, Inc.
11 
12 ALL RIGHTS RESERVED
13 
14 Permission to use, copy, modify, and distribute this software
15 for any purpose and without fee is hereby granted, provided
16 that the above copyright notice appear in all copies and that
17 both the copyright notice and this permission notice appear in
18 supporting documentation, and that the name of Silicon
19 Graphics, Inc. not be used in advertising or publicity
20 pertaining to distribution of the software without specific,
21 written prior permission.
22 
23 THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU
24 "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR
25 OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF
26 MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  IN NO
27 EVENT SHALL SILICON GRAPHICS, INC.  BE LIABLE TO YOU OR ANYONE
28 ELSE FOR ANY DIRECT, SPECIAL, INCIDENTAL, INDIRECT OR
29 CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER,
30 INCLUDING WITHOUT LIMITATION, LOSS OF PROFIT, LOSS OF USE,
31 SAVINGS OR REVENUE, OR THE CLAIMS OF THIRD PARTIES, WHETHER OR
32 NOT SILICON GRAPHICS, INC.  HAS BEEN ADVISED OF THE POSSIBILITY
33 OF SUCH LOSS, HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
34 ARISING OUT OF OR IN CONNECTION WITH THE POSSESSION, USE OR
35 PERFORMANCE OF THIS SOFTWARE.
36 
37 US Government Users Restricted Rights
38 
39 Use, duplication, or disclosure by the Government is subject to
40 restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
41 (c)(1)(ii) of the Rights in Technical Data and Computer
42 Software clause at DFARS 252.227-7013 and/or in similar or
43 successor clauses in the FAR or the DOD or NASA FAR
44 Supplement.  Unpublished-- rights reserved under the copyright
45 laws of the United States.  Contractor/manufacturer is Silicon
46 Graphics, Inc., 2011 N.  Shoreline Blvd., Mountain View, CA
47 94039-7311.
48 
49 OpenGL(TM) is a trademark of Silicon Graphics, Inc.
50 */
51 
52 #include <math.h>
53 #include "glutint.h"
54 
55 /* Some <math.h> files do not define M_PI... */
56 #ifndef M_PI
57 #define M_PI 3.14159265358979323846
58 #endif
59 
60 static GLUquadricObj *quadObj;
61 
62 #define QUAD_OBJ_INIT() { if(!quadObj) initQuadObj(); }
63 
64 static void
65 initQuadObj(void)
66 {
67   quadObj = gluNewQuadric();
68   if (!quadObj)
69     __glutFatalError("out of memory.");
70 }
71 
72 /* CENTRY */
73 void APIENTRY
74 glutWireSphere(GLdouble radius, GLint slices, GLint stacks)
75 {
76   QUAD_OBJ_INIT();
77   gluQuadricDrawStyle(quadObj, GLU_LINE);
78   gluQuadricNormals(quadObj, GLU_SMOOTH);
79   /* If we ever changed/used the texture or orientation state
80      of quadObj, we'd need to change it to the defaults here
81      with gluQuadricTexture and/or gluQuadricOrientation. */
82   gluSphere(quadObj, radius, slices, stacks);
83 }
84 
85 void APIENTRY
86 glutSolidSphere(GLdouble radius, GLint slices, GLint stacks)
87 {
88   QUAD_OBJ_INIT();
89   gluQuadricDrawStyle(quadObj, GLU_FILL);
90   gluQuadricNormals(quadObj, GLU_SMOOTH);
91   /* If we ever changed/used the texture or orientation state
92      of quadObj, we'd need to change it to the defaults here
93      with gluQuadricTexture and/or gluQuadricOrientation. */
94   gluSphere(quadObj, radius, slices, stacks);
95 }
96 
97 void APIENTRY
98 glutWireCone(GLdouble base, GLdouble height,
99   GLint slices, GLint stacks)
100 {
101   QUAD_OBJ_INIT();
102   gluQuadricDrawStyle(quadObj, GLU_LINE);
103   gluQuadricNormals(quadObj, GLU_SMOOTH);
104   /* If we ever changed/used the texture or orientation state
105      of quadObj, we'd need to change it to the defaults here
106      with gluQuadricTexture and/or gluQuadricOrientation. */
107   gluCylinder(quadObj, base, 0.0, height, slices, stacks);
108 }
109 
110 void APIENTRY
111 glutSolidCone(GLdouble base, GLdouble height,
112   GLint slices, GLint stacks)
113 {
114   QUAD_OBJ_INIT();
115   gluQuadricDrawStyle(quadObj, GLU_FILL);
116   gluQuadricNormals(quadObj, GLU_SMOOTH);
117   /* If we ever changed/used the texture or orientation state
118      of quadObj, we'd need to change it to the defaults here
119      with gluQuadricTexture and/or gluQuadricOrientation. */
120   gluCylinder(quadObj, base, 0.0, height, slices, stacks);
121 }
122 
123 /* ENDCENTRY */
124 
125 static void
126 drawBox(GLfloat size, GLenum type)
127 {
128   static GLfloat n[6][3] =
129   {
130     {-1.0, 0.0, 0.0},
131     {0.0, 1.0, 0.0},
132     {1.0, 0.0, 0.0},
133     {0.0, -1.0, 0.0},
134     {0.0, 0.0, 1.0},
135     {0.0, 0.0, -1.0}
136   };
137   static GLint faces[6][4] =
138   {
139     {0, 1, 2, 3},
140     {3, 2, 6, 7},
141     {7, 6, 5, 4},
142     {4, 5, 1, 0},
143     {5, 6, 2, 1},
144     {7, 4, 0, 3}
145   };
146   GLfloat v[8][3];
147   GLint i;
148 
149   v[0][0] = v[1][0] = v[2][0] = v[3][0] = -size / 2;
150   v[4][0] = v[5][0] = v[6][0] = v[7][0] = size / 2;
151   v[0][1] = v[1][1] = v[4][1] = v[5][1] = -size / 2;
152   v[2][1] = v[3][1] = v[6][1] = v[7][1] = size / 2;
153   v[0][2] = v[3][2] = v[4][2] = v[7][2] = -size / 2;
154   v[1][2] = v[2][2] = v[5][2] = v[6][2] = size / 2;
155 
156   for (i = 5; i >= 0; i--) {
157     glBegin(type);
158     glNormal3fv(&n[i][0]);
159     glVertex3fv(&v[faces[i][0]][0]);
160     glVertex3fv(&v[faces[i][1]][0]);
161     glVertex3fv(&v[faces[i][2]][0]);
162     glVertex3fv(&v[faces[i][3]][0]);
163     glEnd();
164   }
165 }
166 
167 /* CENTRY */
168 void APIENTRY
169 glutWireCube(GLdouble size)
170 {
171   drawBox(size, GL_LINE_LOOP);
172 }
173 
174 void APIENTRY
175 glutSolidCube(GLdouble size)
176 {
177   drawBox(size, GL_QUADS);
178 }
179 
180 /* ENDCENTRY */
181 
182 static void
183 doughnut(GLfloat r, GLfloat R, GLint nsides, GLint rings)
184 {
185   int i, j;
186   GLfloat theta, phi, theta1;
187   GLfloat cosTheta, sinTheta;
188   GLfloat cosTheta1, sinTheta1;
189   GLfloat ringDelta, sideDelta;
190 
191   ringDelta = 2.0 * M_PI / rings;
192   sideDelta = 2.0 * M_PI / nsides;
193 
194   theta = 0.0;
195   cosTheta = 1.0;
196   sinTheta = 0.0;
197   for (i = rings - 1; i >= 0; i--) {
198     theta1 = theta + ringDelta;
199     cosTheta1 = cos(theta1);
200     sinTheta1 = sin(theta1);
201     glBegin(GL_QUAD_STRIP);
202     phi = 0.0;
203     for (j = nsides; j >= 0; j--) {
204       GLfloat cosPhi, sinPhi, dist;
205 
206       phi += sideDelta;
207       cosPhi = cos(phi);
208       sinPhi = sin(phi);
209       dist = R + r * cosPhi;
210 
211       glNormal3f(cosTheta1 * cosPhi, -sinTheta1 * cosPhi, sinPhi);
212       glVertex3f(cosTheta1 * dist, -sinTheta1 * dist, r * sinPhi);
213       glNormal3f(cosTheta * cosPhi, -sinTheta * cosPhi, sinPhi);
214       glVertex3f(cosTheta * dist, -sinTheta * dist,  r * sinPhi);
215     }
216     glEnd();
217     theta = theta1;
218     cosTheta = cosTheta1;
219     sinTheta = sinTheta1;
220   }
221 }
222 
223 /* CENTRY */
224 void APIENTRY
225 glutWireTorus(GLdouble innerRadius, GLdouble outerRadius,
226   GLint nsides, GLint rings)
227 {
228   glPushAttrib(GL_POLYGON_BIT);
229   glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
230   doughnut(innerRadius, outerRadius, nsides, rings);
231   glPopAttrib();
232 }
233 
234 void APIENTRY
235 glutSolidTorus(GLdouble innerRadius, GLdouble outerRadius,
236   GLint nsides, GLint rings)
237 {
238   doughnut(innerRadius, outerRadius, nsides, rings);
239 }
240 
241 /* ENDCENTRY */
242 
243 static GLfloat dodec[20][3];
244 
245 static void
246 initDodecahedron(void)
247 {
248   GLfloat alpha, beta;
249 
250   alpha = sqrt(2.0 / (3.0 + sqrt(5.0)));
251   beta = 1.0 + sqrt(6.0 / (3.0 + sqrt(5.0)) -
252     2.0 + 2.0 * sqrt(2.0 / (3.0 + sqrt(5.0))));
253   /* *INDENT-OFF* */
254   dodec[0][0] = -alpha; dodec[0][1] = 0; dodec[0][2] = beta;
255   dodec[1][0] = alpha; dodec[1][1] = 0; dodec[1][2] = beta;
256   dodec[2][0] = -1; dodec[2][1] = -1; dodec[2][2] = -1;
257   dodec[3][0] = -1; dodec[3][1] = -1; dodec[3][2] = 1;
258   dodec[4][0] = -1; dodec[4][1] = 1; dodec[4][2] = -1;
259   dodec[5][0] = -1; dodec[5][1] = 1; dodec[5][2] = 1;
260   dodec[6][0] = 1; dodec[6][1] = -1; dodec[6][2] = -1;
261   dodec[7][0] = 1; dodec[7][1] = -1; dodec[7][2] = 1;
262   dodec[8][0] = 1; dodec[8][1] = 1; dodec[8][2] = -1;
263   dodec[9][0] = 1; dodec[9][1] = 1; dodec[9][2] = 1;
264   dodec[10][0] = beta; dodec[10][1] = alpha; dodec[10][2] = 0;
265   dodec[11][0] = beta; dodec[11][1] = -alpha; dodec[11][2] = 0;
266   dodec[12][0] = -beta; dodec[12][1] = alpha; dodec[12][2] = 0;
267   dodec[13][0] = -beta; dodec[13][1] = -alpha; dodec[13][2] = 0;
268   dodec[14][0] = -alpha; dodec[14][1] = 0; dodec[14][2] = -beta;
269   dodec[15][0] = alpha; dodec[15][1] = 0; dodec[15][2] = -beta;
270   dodec[16][0] = 0; dodec[16][1] = beta; dodec[16][2] = alpha;
271   dodec[17][0] = 0; dodec[17][1] = beta; dodec[17][2] = -alpha;
272   dodec[18][0] = 0; dodec[18][1] = -beta; dodec[18][2] = alpha;
273   dodec[19][0] = 0; dodec[19][1] = -beta; dodec[19][2] = -alpha;
274   /* *INDENT-ON* */
275 
276 }
277 
278 #define DIFF3(_a,_b,_c) { \
279     (_c)[0] = (_a)[0] - (_b)[0]; \
280     (_c)[1] = (_a)[1] - (_b)[1]; \
281     (_c)[2] = (_a)[2] - (_b)[2]; \
282 }
283 
284 static void
285 crossprod(GLfloat v1[3], GLfloat v2[3], GLfloat prod[3])
286 {
287   GLfloat p[3];         /* in case prod == v1 or v2 */
288 
289   p[0] = v1[1] * v2[2] - v2[1] * v1[2];
290   p[1] = v1[2] * v2[0] - v2[2] * v1[0];
291   p[2] = v1[0] * v2[1] - v2[0] * v1[1];
292   prod[0] = p[0];
293   prod[1] = p[1];
294   prod[2] = p[2];
295 }
296 
297 static void
298 normalize(GLfloat v[3])
299 {
300   GLfloat d;
301 
302   d = sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
303   if (d == 0.0) {
304     __glutWarning("normalize: zero length vector");
305     v[0] = d = 1.0;
306   }
307   d = 1 / d;
308   v[0] *= d;
309   v[1] *= d;
310   v[2] *= d;
311 }
312 
313 static void
314 pentagon(int a, int b, int c, int d, int e, GLenum shadeType)
315 {
316   GLfloat n0[3], d1[3], d2[3];
317 
318   DIFF3(dodec[a], dodec[b], d1);
319   DIFF3(dodec[b], dodec[c], d2);
320   crossprod(d1, d2, n0);
321   normalize(n0);
322 
323   glBegin(shadeType);
324   glNormal3fv(n0);
325   glVertex3fv(&dodec[a][0]);
326   glVertex3fv(&dodec[b][0]);
327   glVertex3fv(&dodec[c][0]);
328   glVertex3fv(&dodec[d][0]);
329   glVertex3fv(&dodec[e][0]);
330   glEnd();
331 }
332 
333 static void
334 dodecahedron(GLenum type)
335 {
336   static int inited = 0;
337 
338   if (inited == 0) {
339     inited = 1;
340     initDodecahedron();
341   }
342   pentagon(0, 1, 9, 16, 5, type);
343   pentagon(1, 0, 3, 18, 7, type);
344   pentagon(1, 7, 11, 10, 9, type);
345   pentagon(11, 7, 18, 19, 6, type);
346   pentagon(8, 17, 16, 9, 10, type);
347   pentagon(2, 14, 15, 6, 19, type);
348   pentagon(2, 13, 12, 4, 14, type);
349   pentagon(2, 19, 18, 3, 13, type);
350   pentagon(3, 0, 5, 12, 13, type);
351   pentagon(6, 15, 8, 10, 11, type);
352   pentagon(4, 17, 8, 15, 14, type);
353   pentagon(4, 12, 5, 16, 17, type);
354 }
355 
356 /* CENTRY */
357 void APIENTRY
358 glutWireDodecahedron(void)
359 {
360   dodecahedron(GL_LINE_LOOP);
361 }
362 
363 void APIENTRY
364 glutSolidDodecahedron(void)
365 {
366   dodecahedron(GL_TRIANGLE_FAN);
367 }
368 
369 /* ENDCENTRY */
370 
371 static void
372 recorditem(GLfloat * n1, GLfloat * n2, GLfloat * n3,
373   GLenum shadeType)
374 {
375   GLfloat q0[3], q1[3];
376 
377   DIFF3(n1, n2, q0);
378   DIFF3(n2, n3, q1);
379   crossprod(q0, q1, q1);
380   normalize(q1);
381 
382   glBegin(shadeType);
383   glNormal3fv(q1);
384   glVertex3fv(n1);
385   glVertex3fv(n2);
386   glVertex3fv(n3);
387   glEnd();
388 }
389 
390 static void
391 subdivide(GLfloat * v0, GLfloat * v1, GLfloat * v2,
392   GLenum shadeType)
393 {
394   int depth;
395   GLfloat w0[3], w1[3], w2[3];
396   GLfloat l;
397   int i, j, k, n;
398 
399   depth = 1;
400   for (i = 0; i < depth; i++) {
401     for (j = 0; i + j < depth; j++) {
402       k = depth - i - j;
403       for (n = 0; n < 3; n++) {
404         w0[n] = (i * v0[n] + j * v1[n] + k * v2[n]) / depth;
405         w1[n] = ((i + 1) * v0[n] + j * v1[n] + (k - 1) * v2[n])
406           / depth;
407         w2[n] = (i * v0[n] + (j + 1) * v1[n] + (k - 1) * v2[n])
408           / depth;
409       }
410       l = sqrt(w0[0] * w0[0] + w0[1] * w0[1] + w0[2] * w0[2]);
411       w0[0] /= l;
412       w0[1] /= l;
413       w0[2] /= l;
414       l = sqrt(w1[0] * w1[0] + w1[1] * w1[1] + w1[2] * w1[2]);
415       w1[0] /= l;
416       w1[1] /= l;
417       w1[2] /= l;
418       l = sqrt(w2[0] * w2[0] + w2[1] * w2[1] + w2[2] * w2[2]);
419       w2[0] /= l;
420       w2[1] /= l;
421       w2[2] /= l;
422       recorditem(w1, w0, w2, shadeType);
423     }
424   }
425 }
426 
427 static void
428 drawtriangle(int i, GLfloat data[][3], int ndx[][3],
429   GLenum shadeType)
430 {
431   GLfloat *x0, *x1, *x2;
432 
433   x0 = data[ndx[i][0]];
434   x1 = data[ndx[i][1]];
435   x2 = data[ndx[i][2]];
436   subdivide(x0, x1, x2, shadeType);
437 }
438 
439 /* octahedron data: The octahedron produced is centered at the
440    origin and has radius 1.0 */
441 static GLfloat odata[6][3] =
442 {
443   {1.0, 0.0, 0.0},
444   {-1.0, 0.0, 0.0},
445   {0.0, 1.0, 0.0},
446   {0.0, -1.0, 0.0},
447   {0.0, 0.0, 1.0},
448   {0.0, 0.0, -1.0}
449 };
450 
451 static int ondex[8][3] =
452 {
453   {0, 4, 2},
454   {1, 2, 4},
455   {0, 3, 4},
456   {1, 4, 3},
457   {0, 2, 5},
458   {1, 5, 2},
459   {0, 5, 3},
460   {1, 3, 5}
461 };
462 
463 static void
464 octahedron(GLenum shadeType)
465 {
466   int i;
467 
468   for (i = 7; i >= 0; i--) {
469     drawtriangle(i, odata, ondex, shadeType);
470   }
471 }
472 
473 /* CENTRY */
474 void APIENTRY
475 glutWireOctahedron(void)
476 {
477   octahedron(GL_LINE_LOOP);
478 }
479 
480 void APIENTRY
481 glutSolidOctahedron(void)
482 {
483   octahedron(GL_TRIANGLES);
484 }
485 
486 /* ENDCENTRY */
487 
488 /* icosahedron data: These numbers are rigged to make an
489    icosahedron of radius 1.0 */
490 
491 #define X .525731112119133606
492 #define Z .850650808352039932
493 
494 static GLfloat idata[12][3] =
495 {
496   {-X, 0, Z},
497   {X, 0, Z},
498   {-X, 0, -Z},
499   {X, 0, -Z},
500   {0, Z, X},
501   {0, Z, -X},
502   {0, -Z, X},
503   {0, -Z, -X},
504   {Z, X, 0},
505   {-Z, X, 0},
506   {Z, -X, 0},
507   {-Z, -X, 0}
508 };
509 
510 static int iIndex[20][3] =
511 {
512   {0, 4, 1},
513   {0, 9, 4},
514   {9, 5, 4},
515   {4, 5, 8},
516   {4, 8, 1},
517   {8, 10, 1},
518   {8, 3, 10},
519   {5, 3, 8},
520   {5, 2, 3},
521   {2, 7, 3},
522   {7, 10, 3},
523   {7, 6, 10},
524   {7, 11, 6},
525   {11, 0, 6},
526   {0, 1, 6},
527   {6, 1, 10},
528   {9, 0, 11},
529   {9, 11, 2},
530   {9, 2, 5},
531   {7, 2, 11},
532 };
533 
534 static void
535 icosahedron(GLenum shadeType)
536 {
537   int i;
538 
539   for (i = 19; i >= 0; i--) {
540     drawtriangle(i, idata, iIndex, shadeType);
541   }
542 }
543 
544 /* CENTRY */
545 void APIENTRY
546 glutWireIcosahedron(void)
547 {
548   icosahedron(GL_LINE_LOOP);
549 }
550 
551 void APIENTRY
552 glutSolidIcosahedron(void)
553 {
554   icosahedron(GL_TRIANGLES);
555 }
556 
557 /* ENDCENTRY */
558 
559 /* tetrahedron data: */
560 
561 #define T       1.73205080756887729
562 
563 static GLfloat tdata[4][3] =
564 {
565   {T, T, T},
566   {T, -T, -T},
567   {-T, T, -T},
568   {-T, -T, T}
569 };
570 
571 static int tndex[4][3] =
572 {
573   {0, 1, 3},
574   {2, 1, 0},
575   {3, 2, 0},
576   {1, 2, 3}
577 };
578 
579 static void
580 tetrahedron(GLenum shadeType)
581 {
582   int i;
583 
584   for (i = 3; i >= 0; i--)
585     drawtriangle(i, tdata, tndex, shadeType);
586 }
587 
588 /* CENTRY */
589 void APIENTRY
590 glutWireTetrahedron(void)
591 {
592   tetrahedron(GL_LINE_LOOP);
593 }
594 
595 void APIENTRY
596 glutSolidTetrahedron(void)
597 {
598   tetrahedron(GL_TRIANGLES);
599 }
600 
601 /* ENDCENTRY */
602