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