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