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
12ALL RIGHTS RESERVED
13
14Permission to use, copy, modify, and distribute this software
15for any purpose and without fee is hereby granted, provided
16that the above copyright notice appear in all copies and that
17both the copyright notice and this permission notice appear in
18supporting documentation, and that the name of Silicon
19Graphics, Inc. not be used in advertising or publicity
20pertaining to distribution of the software without specific,
21written prior permission.
22
23THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU
24"AS-IS" AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR
25OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF
26MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  IN NO
27EVENT SHALL SILICON GRAPHICS, INC.  BE LIABLE TO YOU OR ANYONE
28ELSE FOR ANY DIRECT, SPECIAL, INCIDENTAL, INDIRECT OR
29CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER,
30INCLUDING WITHOUT LIMITATION, LOSS OF PROFIT, LOSS OF USE,
31SAVINGS OR REVENUE, OR THE CLAIMS OF THIRD PARTIES, WHETHER OR
32NOT SILICON GRAPHICS, INC.  HAS BEEN ADVISED OF THE POSSIBILITY
33OF SUCH LOSS, HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
34ARISING OUT OF OR IN CONNECTION WITH THE POSSESSION, USE OR
35PERFORMANCE OF THIS SOFTWARE.
36
37US Government Users Restricted Rights
38
39Use, duplication, or disclosure by the Government is subject to
40restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
41(c)(1)(ii) of the Rights in Technical Data and Computer
42Software clause at DFARS 252.227-7013 and/or in similar or
43successor clauses in the FAR or the DOD or NASA FAR
44Supplement.  Unpublished-- rights reserved under the copyright
45laws of the United States.  Contractor/manufacturer is Silicon
46Graphics, Inc., 2011 N.  Shoreline Blvd., Mountain View, CA
4794039-7311.
48
49OpenGL(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
60static GLUquadricObj *quadObj;
61
62#define QUAD_OBJ_INIT() { if(!quadObj) initQuadObj(); }
63
64static void
65initQuadObj(void)
66{
67  quadObj = gluNewQuadric();
68  if (!quadObj)
69    __glutFatalError("out of memory.");
70}
71
72/* CENTRY */
73void APIENTRY
74glutWireSphere(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
85void APIENTRY
86glutSolidSphere(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
97void APIENTRY
98glutWireCone(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
110void APIENTRY
111glutSolidCone(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
125static void
126drawBox(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 */
168void APIENTRY
169glutWireCube(GLdouble size)
170{
171  drawBox(size, GL_LINE_LOOP);
172}
173
174void APIENTRY
175glutSolidCube(GLdouble size)
176{
177  drawBox(size, GL_QUADS);
178}
179
180/* ENDCENTRY */
181
182static void
183doughnut(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 */
224void APIENTRY
225glutWireTorus(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
234void APIENTRY
235glutSolidTorus(GLdouble innerRadius, GLdouble outerRadius,
236  GLint nsides, GLint rings)
237{
238  doughnut(innerRadius, outerRadius, nsides, rings);
239}
240
241/* ENDCENTRY */
242
243static GLfloat dodec[20][3];
244
245static void
246initDodecahedron(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
284static void
285crossprod(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
297static void
298normalize(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
313static void
314pentagon(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
333static void
334dodecahedron(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 */
357void APIENTRY
358glutWireDodecahedron(void)
359{
360  dodecahedron(GL_LINE_LOOP);
361}
362
363void APIENTRY
364glutSolidDodecahedron(void)
365{
366  dodecahedron(GL_TRIANGLE_FAN);
367}
368
369/* ENDCENTRY */
370
371static void
372recorditem(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
390static void
391subdivide(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
427static void
428drawtriangle(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 */
441static 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
451static 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
463static void
464octahedron(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 */
474void APIENTRY
475glutWireOctahedron(void)
476{
477  octahedron(GL_LINE_LOOP);
478}
479
480void APIENTRY
481glutSolidOctahedron(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
494static 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
510static 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
534static void
535icosahedron(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 */
545void APIENTRY
546glutWireIcosahedron(void)
547{
548  icosahedron(GL_LINE_LOOP);
549}
550
551void APIENTRY
552glutSolidIcosahedron(void)
553{
554  icosahedron(GL_TRIANGLES);
555}
556
557/* ENDCENTRY */
558
559/* tetrahedron data: */
560
561#define T       1.73205080756887729
562
563static GLfloat tdata[4][3] =
564{
565  {T, T, T},
566  {T, -T, -T},
567  {-T, T, -T},
568  {-T, -T, T}
569};
570
571static int tndex[4][3] =
572{
573  {0, 1, 3},
574  {2, 1, 0},
575  {3, 2, 0},
576  {1, 2, 3}
577};
578
579static void
580tetrahedron(GLenum shadeType)
581{
582  int i;
583
584  for (i = 3; i >= 0; i--)
585    drawtriangle(i, tdata, tndex, shadeType);
586}
587
588/* CENTRY */
589void APIENTRY
590glutWireTetrahedron(void)
591{
592  tetrahedron(GL_LINE_LOOP);
593}
594
595void APIENTRY
596glutSolidTetrahedron(void)
597{
598  tetrahedron(GL_TRIANGLES);
599}
600
601/* ENDCENTRY */
602