1 /* GdkGLExt - OpenGL Extension to GDK
2  * Copyright (C) 2002-2004  Naofumi Yasufuku
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA.
17  */
18 
19 #include <math.h>
20 
21 #include <glib.h>
22 
23 #include "gdkglprivate.h"
24 #include "gdkglshapes.h"
25 
26 #ifdef G_OS_WIN32
27 #define WIN32_LEAN_AND_MEAN 1
28 #include <windows.h>
29 #endif
30 
31 #include <GL/gl.h>
32 #include <GL/glu.h>
33 
34 /*
35  * The following code is imported from GLUT.
36  */
37 
38 /* Copyright (c) Mark J. Kilgard, 1994, 1997. */
39 
40 /**
41 (c) Copyright 1993, Silicon Graphics, Inc.
42 
43 ALL RIGHTS RESERVED
44 
45 Permission to use, copy, modify, and distribute this software
46 for any purpose and without fee is hereby granted, provided
47 that the above copyright notice appear in all copies and that
48 both the copyright notice and this permission notice appear in
49 supporting documentation, and that the name of Silicon
50 Graphics, Inc. not be used in advertising or publicity
51 pertaining to distribution of the software without specific,
52 written prior permission.
53 
54 THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU
55 "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR
56 OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF
57 MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  IN NO
58 EVENT SHALL SILICON GRAPHICS, INC.  BE LIABLE TO YOU OR ANYONE
59 ELSE FOR ANY DIRECT, SPECIAL, INCIDENTAL, INDIRECT OR
60 CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER,
61 INCLUDING WITHOUT LIMITATION, LOSS OF PROFIT, LOSS OF USE,
62 SAVINGS OR REVENUE, OR THE CLAIMS OF THIRD PARTIES, WHETHER OR
63 NOT SILICON GRAPHICS, INC.  HAS BEEN ADVISED OF THE POSSIBILITY
64 OF SUCH LOSS, HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
65 ARISING OUT OF OR IN CONNECTION WITH THE POSSESSION, USE OR
66 PERFORMANCE OF THIS SOFTWARE.
67 
68 US Government Users Restricted Rights
69 
70 Use, duplication, or disclosure by the Government is subject to
71 restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
72 (c)(1)(ii) of the Rights in Technical Data and Computer
73 Software clause at DFARS 252.227-7013 and/or in similar or
74 successor clauses in the FAR or the DOD or NASA FAR
75 Supplement.  Unpublished-- rights reserved under the copyright
76 laws of the United States.  Contractor/manufacturer is Silicon
77 Graphics, Inc., 2011 N.  Shoreline Blvd., Mountain View, CA
78 94039-7311.
79 
80 OpenGL(TM) is a trademark of Silicon Graphics, Inc.
81 */
82 
83 /*
84  * Cube
85  */
86 
87 static void
drawBox(GLfloat size,GLenum type)88 drawBox(GLfloat size, GLenum type)
89 {
90   static GLfloat n[6][3] =
91   {
92     {-1.0, 0.0, 0.0},
93     {0.0, 1.0, 0.0},
94     {1.0, 0.0, 0.0},
95     {0.0, -1.0, 0.0},
96     {0.0, 0.0, 1.0},
97     {0.0, 0.0, -1.0}
98   };
99   static GLint faces[6][4] =
100   {
101     {0, 1, 2, 3},
102     {3, 2, 6, 7},
103     {7, 6, 5, 4},
104     {4, 5, 1, 0},
105     {5, 6, 2, 1},
106     {7, 4, 0, 3}
107   };
108   GLfloat v[8][3];
109   GLint i;
110 
111   v[0][0] = v[1][0] = v[2][0] = v[3][0] = -size / 2;
112   v[4][0] = v[5][0] = v[6][0] = v[7][0] = size / 2;
113   v[0][1] = v[1][1] = v[4][1] = v[5][1] = -size / 2;
114   v[2][1] = v[3][1] = v[6][1] = v[7][1] = size / 2;
115   v[0][2] = v[3][2] = v[4][2] = v[7][2] = -size / 2;
116   v[1][2] = v[2][2] = v[5][2] = v[6][2] = size / 2;
117 
118   for (i = 5; i >= 0; i--) {
119     glBegin(type);
120     glNormal3fv(&n[i][0]);
121     glVertex3fv(&v[faces[i][0]][0]);
122     glVertex3fv(&v[faces[i][1]][0]);
123     glVertex3fv(&v[faces[i][2]][0]);
124     glVertex3fv(&v[faces[i][3]][0]);
125     glEnd();
126   }
127 }
128 
129 /**
130  * gdk_gl_draw_cube:
131  * @solid: TRUE if the cube should be solid.
132  * @size: length of cube sides.
133  *
134  * Renders a cube.
135  * The cube is centered at the modeling coordinates origin with sides of
136  * length @size.
137  *
138  **/
139 void
gdk_gl_draw_cube(gboolean solid,double size)140 gdk_gl_draw_cube (gboolean solid,
141                   double   size)
142 {
143   if (solid)
144     drawBox (size, GL_QUADS);
145   else
146     drawBox (size, GL_LINE_LOOP);
147 }
148 
149 /*
150  * Quadrics
151  */
152 
153 static GLUquadricObj *quadObj = NULL;
154 
155 #define QUAD_OBJ_INIT() { if(!quadObj) initQuadObj(); }
156 
157 static void
initQuadObj(void)158 initQuadObj(void)
159 {
160   quadObj = gluNewQuadric();
161   if (!quadObj)
162     g_error("out of memory.");
163 }
164 
165 /**
166  * gdk_gl_draw_sphere:
167  * @solid: TRUE if the sphere should be solid.
168  * @radius: the radius of the sphere.
169  * @slices: the number of subdivisions around the Z axis (similar to lines of
170  *          longitude).
171  * @stacks: the number of subdivisions along the Z axis (similar to lines of
172  *          latitude).
173  *
174  * Renders a sphere centered at the modeling coordinates origin of
175  * the specified @radius. The sphere is subdivided around the Z axis into
176  * @slices and along the Z axis into @stacks.
177  *
178  **/
179 void
gdk_gl_draw_sphere(gboolean solid,double radius,int slices,int stacks)180 gdk_gl_draw_sphere (gboolean solid,
181                     double   radius,
182                     int      slices,
183                     int      stacks)
184 {
185   QUAD_OBJ_INIT();
186 
187   if (solid)
188     gluQuadricDrawStyle (quadObj, GLU_FILL);
189   else
190     gluQuadricDrawStyle (quadObj, GLU_LINE);
191 
192   gluQuadricNormals (quadObj, GLU_SMOOTH);
193 
194   /* If we ever changed/used the texture or orientation state
195      of quadObj, we'd need to change it to the defaults here
196      with gluQuadricTexture and/or gluQuadricOrientation. */
197   gluSphere (quadObj, radius, slices, stacks);
198 }
199 
200 /**
201  * gdk_gl_draw_cone:
202  * @solid: TRUE if the cone should be solid.
203  * @base: the radius of the base of the cone.
204  * @height: the height of the cone.
205  * @slices: the number of subdivisions around the Z axis.
206  * @stacks: the number of subdivisions along the Z axis.
207  *
208  * Renders a cone oriented along the Z axis.
209  * The @base of the cone is placed at Z = 0, and the top at Z = @height.
210  * The cone is subdivided around the Z axis into @slices, and along
211  * the Z axis into @stacks.
212  *
213  **/
214 void
gdk_gl_draw_cone(gboolean solid,double base,double height,int slices,int stacks)215 gdk_gl_draw_cone (gboolean solid,
216                   double   base,
217                   double   height,
218                   int      slices,
219                   int      stacks)
220 {
221   QUAD_OBJ_INIT();
222 
223   if (solid)
224     gluQuadricDrawStyle (quadObj, GLU_FILL);
225   else
226     gluQuadricDrawStyle (quadObj, GLU_LINE);
227 
228   gluQuadricNormals (quadObj, GLU_SMOOTH);
229 
230   /* If we ever changed/used the texture or orientation state
231      of quadObj, we'd need to change it to the defaults here
232      with gluQuadricTexture and/or gluQuadricOrientation. */
233   gluCylinder (quadObj, base, 0.0, height, slices, stacks);
234 }
235 
236 /*
237  * Torus
238  */
239 
240 static void
doughnut(GLfloat r,GLfloat R,GLint nsides,GLint rings)241 doughnut(GLfloat r, GLfloat R, GLint nsides, GLint rings)
242 {
243   int i, j;
244   GLfloat theta, phi, theta1;
245   GLfloat cosTheta, sinTheta;
246   GLfloat cosTheta1, sinTheta1;
247   GLfloat ringDelta, sideDelta;
248 
249   ringDelta = 2.0 * G_PI / rings;
250   sideDelta = 2.0 * G_PI / nsides;
251 
252   theta = 0.0;
253   cosTheta = 1.0;
254   sinTheta = 0.0;
255   for (i = rings - 1; i >= 0; i--) {
256     theta1 = theta + ringDelta;
257     cosTheta1 = cos(theta1);
258     sinTheta1 = sin(theta1);
259     glBegin(GL_QUAD_STRIP);
260     phi = 0.0;
261     for (j = nsides; j >= 0; j--) {
262       GLfloat cosPhi, sinPhi, dist;
263 
264       phi += sideDelta;
265       cosPhi = cos(phi);
266       sinPhi = sin(phi);
267       dist = R + r * cosPhi;
268 
269       glNormal3f(cosTheta1 * cosPhi, -sinTheta1 * cosPhi, sinPhi);
270       glVertex3f(cosTheta1 * dist, -sinTheta1 * dist, r * sinPhi);
271       glNormal3f(cosTheta * cosPhi, -sinTheta * cosPhi, sinPhi);
272       glVertex3f(cosTheta * dist, -sinTheta * dist,  r * sinPhi);
273     }
274     glEnd();
275     theta = theta1;
276     cosTheta = cosTheta1;
277     sinTheta = sinTheta1;
278   }
279 }
280 
281 /**
282  * gdk_gl_draw_torus:
283  * @solid: TRUE if the torus should be solid.
284  * @inner_radius: inner radius of the torus.
285  * @outer_radius: outer radius of the torus.
286  * @nsides: number of sides for each radial section.
287  * @rings: number of radial divisions for the torus.
288  *
289  * Renders a torus (doughnut) centered at the modeling coordinates
290  * origin whose axis is aligned with the Z axis.
291  *
292  **/
293 void
gdk_gl_draw_torus(gboolean solid,double inner_radius,double outer_radius,int nsides,int rings)294 gdk_gl_draw_torus (gboolean solid,
295                    double   inner_radius,
296                    double   outer_radius,
297                    int      nsides,
298                    int      rings)
299 {
300   if (solid)
301     {
302       doughnut (inner_radius, outer_radius, nsides, rings);
303     }
304   else
305     {
306       glPushAttrib (GL_POLYGON_BIT);
307       glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
308       doughnut (inner_radius, outer_radius, nsides, rings);
309       glPopAttrib ();
310     }
311 }
312 
313 #define DIFF3(_a,_b,_c) { \
314     (_c)[0] = (_a)[0] - (_b)[0]; \
315     (_c)[1] = (_a)[1] - (_b)[1]; \
316     (_c)[2] = (_a)[2] - (_b)[2]; \
317 }
318 
319 static void
crossprod(GLfloat v1[3],GLfloat v2[3],GLfloat prod[3])320 crossprod(GLfloat v1[3], GLfloat v2[3], GLfloat prod[3])
321 {
322   GLfloat p[3];         /* in case prod == v1 or v2 */
323 
324   p[0] = v1[1] * v2[2] - v2[1] * v1[2];
325   p[1] = v1[2] * v2[0] - v2[2] * v1[0];
326   p[2] = v1[0] * v2[1] - v2[0] * v1[1];
327   prod[0] = p[0];
328   prod[1] = p[1];
329   prod[2] = p[2];
330 }
331 
332 static void
normalize(GLfloat v[3])333 normalize(GLfloat v[3])
334 {
335   GLfloat d;
336 
337   d = sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
338   if (d == 0.0) {
339     g_warning("normalize: zero length vector");
340     v[0] = d = 1.0;
341   }
342   d = 1 / d;
343   v[0] *= d;
344   v[1] *= d;
345   v[2] *= d;
346 }
347 
348 static void
recorditem(GLfloat * n1,GLfloat * n2,GLfloat * n3,GLenum shadeType)349 recorditem(GLfloat * n1, GLfloat * n2, GLfloat * n3,
350            GLenum shadeType)
351 {
352   GLfloat q0[3], q1[3];
353 
354   DIFF3(n1, n2, q0);
355   DIFF3(n2, n3, q1);
356   crossprod(q0, q1, q1);
357   normalize(q1);
358 
359   glBegin(shadeType);
360   glNormal3fv(q1);
361   glVertex3fv(n1);
362   glVertex3fv(n2);
363   glVertex3fv(n3);
364   glEnd();
365 }
366 
367 static void
subdivide(GLfloat * v0,GLfloat * v1,GLfloat * v2,GLenum shadeType)368 subdivide(GLfloat * v0, GLfloat * v1, GLfloat * v2,
369           GLenum shadeType)
370 {
371   int depth;
372   GLfloat w0[3], w1[3], w2[3];
373   GLfloat l;
374   int i, j, k, n;
375 
376   depth = 1;
377   for (i = 0; i < depth; i++) {
378     for (j = 0; i + j < depth; j++) {
379       k = depth - i - j;
380       for (n = 0; n < 3; n++) {
381         w0[n] = (i * v0[n] + j * v1[n] + k * v2[n]) / depth;
382         w1[n] = ((i + 1) * v0[n] + j * v1[n] + (k - 1) * v2[n])
383           / depth;
384         w2[n] = (i * v0[n] + (j + 1) * v1[n] + (k - 1) * v2[n])
385           / depth;
386       }
387       l = sqrt(w0[0] * w0[0] + w0[1] * w0[1] + w0[2] * w0[2]);
388       w0[0] /= l;
389       w0[1] /= l;
390       w0[2] /= l;
391       l = sqrt(w1[0] * w1[0] + w1[1] * w1[1] + w1[2] * w1[2]);
392       w1[0] /= l;
393       w1[1] /= l;
394       w1[2] /= l;
395       l = sqrt(w2[0] * w2[0] + w2[1] * w2[1] + w2[2] * w2[2]);
396       w2[0] /= l;
397       w2[1] /= l;
398       w2[2] /= l;
399       recorditem(w1, w0, w2, shadeType);
400     }
401   }
402 }
403 
404 static void
drawtriangle(int i,GLfloat data[][3],int ndx[][3],GLenum shadeType)405 drawtriangle(int i, GLfloat data[][3], int ndx[][3],
406              GLenum shadeType)
407 {
408   GLfloat *x0, *x1, *x2;
409 
410   x0 = data[ndx[i][0]];
411   x1 = data[ndx[i][1]];
412   x2 = data[ndx[i][2]];
413   subdivide(x0, x1, x2, shadeType);
414 }
415 
416 /*
417  * Tetrahedron
418  */
419 
420 /* tetrahedron data: */
421 
422 #define T       1.73205080756887729
423 
424 static GLfloat tdata[4][3] =
425 {
426   {T, T, T},
427   {T, -T, -T},
428   {-T, T, -T},
429   {-T, -T, T}
430 };
431 
432 static int tndex[4][3] =
433 {
434   {0, 1, 3},
435   {2, 1, 0},
436   {3, 2, 0},
437   {1, 2, 3}
438 };
439 
440 static void
tetrahedron(GLenum shadeType)441 tetrahedron(GLenum shadeType)
442 {
443   int i;
444 
445   for (i = 3; i >= 0; i--)
446     drawtriangle(i, tdata, tndex, shadeType);
447 }
448 
449 /**
450  * gdk_gl_draw_tetrahedron:
451  * @solid: TRUE if the tetrahedron should be solid.
452  *
453  * Renders a tetrahedron centered at the modeling coordinates
454  * origin with a radius of the square root of 3.
455  *
456  **/
457 void
gdk_gl_draw_tetrahedron(gboolean solid)458 gdk_gl_draw_tetrahedron (gboolean solid)
459 {
460   if (solid)
461     tetrahedron (GL_TRIANGLES);
462   else
463     tetrahedron (GL_LINE_LOOP);
464 }
465 
466 /*
467  * Octahedron
468  */
469 
470 /* octahedron data: The octahedron produced is centered at the
471    origin and has radius 1.0 */
472 static GLfloat odata[6][3] =
473 {
474   {1.0, 0.0, 0.0},
475   {-1.0, 0.0, 0.0},
476   {0.0, 1.0, 0.0},
477   {0.0, -1.0, 0.0},
478   {0.0, 0.0, 1.0},
479   {0.0, 0.0, -1.0}
480 };
481 
482 static int ondex[8][3] =
483 {
484   {0, 4, 2},
485   {1, 2, 4},
486   {0, 3, 4},
487   {1, 4, 3},
488   {0, 2, 5},
489   {1, 5, 2},
490   {0, 5, 3},
491   {1, 3, 5}
492 };
493 
494 static void
octahedron(GLenum shadeType)495 octahedron(GLenum shadeType)
496 {
497   int i;
498 
499   for (i = 7; i >= 0; i--) {
500     drawtriangle(i, odata, ondex, shadeType);
501   }
502 }
503 
504 /**
505  * gdk_gl_draw_octahedron:
506  * @solid: TRUE if the octahedron should be solid.
507  *
508  * Renders a octahedron centered at the modeling coordinates
509  * origin with a radius of 1.0.
510  *
511  **/
512 void
gdk_gl_draw_octahedron(gboolean solid)513 gdk_gl_draw_octahedron (gboolean solid)
514 {
515   if (solid)
516     octahedron (GL_TRIANGLES);
517   else
518     octahedron (GL_LINE_LOOP);
519 }
520 
521 /*
522  * Icosahedron
523  */
524 
525 /* icosahedron data: These numbers are rigged to make an
526    icosahedron of radius 1.0 */
527 
528 #define X .525731112119133606
529 #define Z .850650808352039932
530 
531 static GLfloat idata[12][3] =
532 {
533   {-X, 0, Z},
534   {X, 0, Z},
535   {-X, 0, -Z},
536   {X, 0, -Z},
537   {0, Z, X},
538   {0, Z, -X},
539   {0, -Z, X},
540   {0, -Z, -X},
541   {Z, X, 0},
542   {-Z, X, 0},
543   {Z, -X, 0},
544   {-Z, -X, 0}
545 };
546 
547 static int myindex[20][3] =
548 {
549   {0, 4, 1},
550   {0, 9, 4},
551   {9, 5, 4},
552   {4, 5, 8},
553   {4, 8, 1},
554   {8, 10, 1},
555   {8, 3, 10},
556   {5, 3, 8},
557   {5, 2, 3},
558   {2, 7, 3},
559   {7, 10, 3},
560   {7, 6, 10},
561   {7, 11, 6},
562   {11, 0, 6},
563   {0, 1, 6},
564   {6, 1, 10},
565   {9, 0, 11},
566   {9, 11, 2},
567   {9, 2, 5},
568   {7, 2, 11},
569 };
570 
571 static void
icosahedron(GLenum shadeType)572 icosahedron(GLenum shadeType)
573 {
574   int i;
575 
576   for (i = 19; i >= 0; i--) {
577     drawtriangle(i, idata, myindex, shadeType);
578   }
579 }
580 
581 /**
582  * gdk_gl_draw_icosahedron:
583  * @solid: TRUE if the icosahedron should be solid.
584  *
585  * Renders a icosahedron.
586  * The icosahedron is centered at the modeling coordinates origin
587  * and has a radius of 1.0.
588  *
589  **/
590 void
gdk_gl_draw_icosahedron(gboolean solid)591 gdk_gl_draw_icosahedron (gboolean solid)
592 {
593   if (solid)
594     icosahedron (GL_TRIANGLES);
595   else
596     icosahedron (GL_LINE_LOOP);
597 }
598 
599 /*
600  * Dodecahedron
601  */
602 
603 static GLfloat dodec[20][3];
604 
605 static void
initDodecahedron(void)606 initDodecahedron(void)
607 {
608   GLfloat alpha, beta;
609 
610   alpha = sqrt(2.0 / (3.0 + sqrt(5.0)));
611   beta = 1.0 + sqrt(6.0 / (3.0 + sqrt(5.0)) -
612     2.0 + 2.0 * sqrt(2.0 / (3.0 + sqrt(5.0))));
613   /* *INDENT-OFF* */
614   dodec[0][0] = -alpha; dodec[0][1] = 0; dodec[0][2] = beta;
615   dodec[1][0] = alpha; dodec[1][1] = 0; dodec[1][2] = beta;
616   dodec[2][0] = -1; dodec[2][1] = -1; dodec[2][2] = -1;
617   dodec[3][0] = -1; dodec[3][1] = -1; dodec[3][2] = 1;
618   dodec[4][0] = -1; dodec[4][1] = 1; dodec[4][2] = -1;
619   dodec[5][0] = -1; dodec[5][1] = 1; dodec[5][2] = 1;
620   dodec[6][0] = 1; dodec[6][1] = -1; dodec[6][2] = -1;
621   dodec[7][0] = 1; dodec[7][1] = -1; dodec[7][2] = 1;
622   dodec[8][0] = 1; dodec[8][1] = 1; dodec[8][2] = -1;
623   dodec[9][0] = 1; dodec[9][1] = 1; dodec[9][2] = 1;
624   dodec[10][0] = beta; dodec[10][1] = alpha; dodec[10][2] = 0;
625   dodec[11][0] = beta; dodec[11][1] = -alpha; dodec[11][2] = 0;
626   dodec[12][0] = -beta; dodec[12][1] = alpha; dodec[12][2] = 0;
627   dodec[13][0] = -beta; dodec[13][1] = -alpha; dodec[13][2] = 0;
628   dodec[14][0] = -alpha; dodec[14][1] = 0; dodec[14][2] = -beta;
629   dodec[15][0] = alpha; dodec[15][1] = 0; dodec[15][2] = -beta;
630   dodec[16][0] = 0; dodec[16][1] = beta; dodec[16][2] = alpha;
631   dodec[17][0] = 0; dodec[17][1] = beta; dodec[17][2] = -alpha;
632   dodec[18][0] = 0; dodec[18][1] = -beta; dodec[18][2] = alpha;
633   dodec[19][0] = 0; dodec[19][1] = -beta; dodec[19][2] = -alpha;
634   /* *INDENT-ON* */
635 
636 }
637 
638 static void
pentagon(int a,int b,int c,int d,int e,GLenum shadeType)639 pentagon(int a, int b, int c, int d, int e, GLenum shadeType)
640 {
641   GLfloat n0[3], d1[3], d2[3];
642 
643   DIFF3(dodec[a], dodec[b], d1);
644   DIFF3(dodec[b], dodec[c], d2);
645   crossprod(d1, d2, n0);
646   normalize(n0);
647 
648   glBegin(shadeType);
649   glNormal3fv(n0);
650   glVertex3fv(&dodec[a][0]);
651   glVertex3fv(&dodec[b][0]);
652   glVertex3fv(&dodec[c][0]);
653   glVertex3fv(&dodec[d][0]);
654   glVertex3fv(&dodec[e][0]);
655   glEnd();
656 }
657 
658 static void
dodecahedron(GLenum type)659 dodecahedron(GLenum type)
660 {
661   static int inited = 0;
662 
663   if (inited == 0) {
664     inited = 1;
665     initDodecahedron();
666   }
667   pentagon(0, 1, 9, 16, 5, type);
668   pentagon(1, 0, 3, 18, 7, type);
669   pentagon(1, 7, 11, 10, 9, type);
670   pentagon(11, 7, 18, 19, 6, type);
671   pentagon(8, 17, 16, 9, 10, type);
672   pentagon(2, 14, 15, 6, 19, type);
673   pentagon(2, 13, 12, 4, 14, type);
674   pentagon(2, 19, 18, 3, 13, type);
675   pentagon(3, 0, 5, 12, 13, type);
676   pentagon(6, 15, 8, 10, 11, type);
677   pentagon(4, 17, 8, 15, 14, type);
678   pentagon(4, 12, 5, 16, 17, type);
679 }
680 
681 /**
682  * gdk_gl_draw_dodecahedron:
683  * @solid: TRUE if the dodecahedron should be solid.
684  *
685  * Renders a dodecahedron centered at the modeling coordinates
686  * origin with a radius of the square root of 3.
687  *
688  **/
689 void
gdk_gl_draw_dodecahedron(gboolean solid)690 gdk_gl_draw_dodecahedron (gboolean solid)
691 {
692   if (solid)
693     dodecahedron (GL_TRIANGLE_FAN);
694   else
695     dodecahedron (GL_LINE_LOOP);
696 }
697 
698 /*
699  * Teapot
700  */
701 
702 /* Rim, body, lid, and bottom data must be reflected in x and
703    y; handle and spout data across the y axis only.  */
704 
705 static int patchdata[][16] =
706 {
707     /* rim */
708   {102, 103, 104, 105, 4, 5, 6, 7, 8, 9, 10, 11,
709     12, 13, 14, 15},
710     /* body */
711   {12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
712     24, 25, 26, 27},
713   {24, 25, 26, 27, 29, 30, 31, 32, 33, 34, 35, 36,
714     37, 38, 39, 40},
715     /* lid */
716   {96, 96, 96, 96, 97, 98, 99, 100, 101, 101, 101,
717     101, 0, 1, 2, 3,},
718   {0, 1, 2, 3, 106, 107, 108, 109, 110, 111, 112,
719     113, 114, 115, 116, 117},
720     /* bottom */
721   {118, 118, 118, 118, 124, 122, 119, 121, 123, 126,
722     125, 120, 40, 39, 38, 37},
723     /* handle */
724   {41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
725     53, 54, 55, 56},
726   {53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
727     28, 65, 66, 67},
728     /* spout */
729   {68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
730     80, 81, 82, 83},
731   {80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91,
732     92, 93, 94, 95}
733 };
734 /* *INDENT-OFF* */
735 
736 static float cpdata[][3] =
737 {
738     {0.2, 0, 2.7}, {0.2, -0.112, 2.7}, {0.112, -0.2, 2.7}, {0,
739     -0.2, 2.7}, {1.3375, 0, 2.53125}, {1.3375, -0.749, 2.53125},
740     {0.749, -1.3375, 2.53125}, {0, -1.3375, 2.53125}, {1.4375,
741     0, 2.53125}, {1.4375, -0.805, 2.53125}, {0.805, -1.4375,
742     2.53125}, {0, -1.4375, 2.53125}, {1.5, 0, 2.4}, {1.5, -0.84,
743     2.4}, {0.84, -1.5, 2.4}, {0, -1.5, 2.4}, {1.75, 0, 1.875},
744     {1.75, -0.98, 1.875}, {0.98, -1.75, 1.875}, {0, -1.75,
745     1.875}, {2, 0, 1.35}, {2, -1.12, 1.35}, {1.12, -2, 1.35},
746     {0, -2, 1.35}, {2, 0, 0.9}, {2, -1.12, 0.9}, {1.12, -2,
747     0.9}, {0, -2, 0.9}, {-2, 0, 0.9}, {2, 0, 0.45}, {2, -1.12,
748     0.45}, {1.12, -2, 0.45}, {0, -2, 0.45}, {1.5, 0, 0.225},
749     {1.5, -0.84, 0.225}, {0.84, -1.5, 0.225}, {0, -1.5, 0.225},
750     {1.5, 0, 0.15}, {1.5, -0.84, 0.15}, {0.84, -1.5, 0.15}, {0,
751     -1.5, 0.15}, {-1.6, 0, 2.025}, {-1.6, -0.3, 2.025}, {-1.5,
752     -0.3, 2.25}, {-1.5, 0, 2.25}, {-2.3, 0, 2.025}, {-2.3, -0.3,
753     2.025}, {-2.5, -0.3, 2.25}, {-2.5, 0, 2.25}, {-2.7, 0,
754     2.025}, {-2.7, -0.3, 2.025}, {-3, -0.3, 2.25}, {-3, 0,
755     2.25}, {-2.7, 0, 1.8}, {-2.7, -0.3, 1.8}, {-3, -0.3, 1.8},
756     {-3, 0, 1.8}, {-2.7, 0, 1.575}, {-2.7, -0.3, 1.575}, {-3,
757     -0.3, 1.35}, {-3, 0, 1.35}, {-2.5, 0, 1.125}, {-2.5, -0.3,
758     1.125}, {-2.65, -0.3, 0.9375}, {-2.65, 0, 0.9375}, {-2,
759     -0.3, 0.9}, {-1.9, -0.3, 0.6}, {-1.9, 0, 0.6}, {1.7, 0,
760     1.425}, {1.7, -0.66, 1.425}, {1.7, -0.66, 0.6}, {1.7, 0,
761     0.6}, {2.6, 0, 1.425}, {2.6, -0.66, 1.425}, {3.1, -0.66,
762     0.825}, {3.1, 0, 0.825}, {2.3, 0, 2.1}, {2.3, -0.25, 2.1},
763     {2.4, -0.25, 2.025}, {2.4, 0, 2.025}, {2.7, 0, 2.4}, {2.7,
764     -0.25, 2.4}, {3.3, -0.25, 2.4}, {3.3, 0, 2.4}, {2.8, 0,
765     2.475}, {2.8, -0.25, 2.475}, {3.525, -0.25, 2.49375},
766     {3.525, 0, 2.49375}, {2.9, 0, 2.475}, {2.9, -0.15, 2.475},
767     {3.45, -0.15, 2.5125}, {3.45, 0, 2.5125}, {2.8, 0, 2.4},
768     {2.8, -0.15, 2.4}, {3.2, -0.15, 2.4}, {3.2, 0, 2.4}, {0, 0,
769     3.15}, {0.8, 0, 3.15}, {0.8, -0.45, 3.15}, {0.45, -0.8,
770     3.15}, {0, -0.8, 3.15}, {0, 0, 2.85}, {1.4, 0, 2.4}, {1.4,
771     -0.784, 2.4}, {0.784, -1.4, 2.4}, {0, -1.4, 2.4}, {0.4, 0,
772     2.55}, {0.4, -0.224, 2.55}, {0.224, -0.4, 2.55}, {0, -0.4,
773     2.55}, {1.3, 0, 2.55}, {1.3, -0.728, 2.55}, {0.728, -1.3,
774     2.55}, {0, -1.3, 2.55}, {1.3, 0, 2.4}, {1.3, -0.728, 2.4},
775     {0.728, -1.3, 2.4}, {0, -1.3, 2.4}, {0, 0, 0}, {1.425,
776     -0.798, 0}, {1.5, 0, 0.075}, {1.425, 0, 0}, {0.798, -1.425,
777     0}, {0, -1.5, 0.075}, {0, -1.425, 0}, {1.5, -0.84, 0.075},
778     {0.84, -1.5, 0.075}
779 };
780 
781 static float tex[2][2][2] =
782 {
783   { {0, 0},
784     {1, 0}},
785   { {0, 1},
786     {1, 1}}
787 };
788 
789 /* *INDENT-ON* */
790 
791 static void
teapot(GLint grid,GLdouble scale,GLenum type)792 teapot(GLint grid, GLdouble scale, GLenum type)
793 {
794   float p[4][4][3], q[4][4][3], r[4][4][3], s[4][4][3];
795   long i, j, k, l;
796 
797   glPushAttrib(GL_ENABLE_BIT | GL_EVAL_BIT);
798   glEnable(GL_AUTO_NORMAL);
799   glEnable(GL_NORMALIZE);
800   glEnable(GL_MAP2_VERTEX_3);
801   glEnable(GL_MAP2_TEXTURE_COORD_2);
802   glPushMatrix();
803   glRotatef(270.0, 1.0, 0.0, 0.0);
804   glScalef(0.5 * scale, 0.5 * scale, 0.5 * scale);
805   glTranslatef(0.0, 0.0, -1.5);
806   for (i = 0; i < 10; i++) {
807     for (j = 0; j < 4; j++) {
808       for (k = 0; k < 4; k++) {
809         for (l = 0; l < 3; l++) {
810           p[j][k][l] = cpdata[patchdata[i][j * 4 + k]][l];
811           q[j][k][l] = cpdata[patchdata[i][j * 4 + (3 - k)]][l];
812           if (l == 1)
813             q[j][k][l] *= -1.0;
814           if (i < 6) {
815             r[j][k][l] =
816               cpdata[patchdata[i][j * 4 + (3 - k)]][l];
817             if (l == 0)
818               r[j][k][l] *= -1.0;
819             s[j][k][l] = cpdata[patchdata[i][j * 4 + k]][l];
820             if (l == 0)
821               s[j][k][l] *= -1.0;
822             if (l == 1)
823               s[j][k][l] *= -1.0;
824           }
825         }
826       }
827     }
828     glMap2f(GL_MAP2_TEXTURE_COORD_2, 0, 1, 2, 2, 0, 1, 4, 2,
829       &tex[0][0][0]);
830     glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4,
831       &p[0][0][0]);
832     glMapGrid2f(grid, 0.0, 1.0, grid, 0.0, 1.0);
833     glEvalMesh2(type, 0, grid, 0, grid);
834     glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4,
835       &q[0][0][0]);
836     glEvalMesh2(type, 0, grid, 0, grid);
837     if (i < 6) {
838       glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4,
839         &r[0][0][0]);
840       glEvalMesh2(type, 0, grid, 0, grid);
841       glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4,
842         &s[0][0][0]);
843       glEvalMesh2(type, 0, grid, 0, grid);
844     }
845   }
846   glPopMatrix();
847   glPopAttrib();
848 }
849 
850 /**
851  * gdk_gl_draw_teapot:
852  * @solid: TRUE if the teapot should be solid.
853  * @scale: relative size of the teapot.
854  *
855  * Renders a teapot.
856  * Both surface normals and texture coordinates for the teapot are generated.
857  * The teapot is generated with OpenGL evaluators.
858  *
859  **/
860 void
gdk_gl_draw_teapot(gboolean solid,double scale)861 gdk_gl_draw_teapot (gboolean solid,
862                     double   scale)
863 {
864   if (solid)
865     teapot (7, scale, GL_FILL);
866   else
867     teapot (10, scale, GL_LINE);
868 }
869