1 /*
2  * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  * - Redistribution of source code must retain the above copyright
9  *   notice, this list of conditions and the following disclaimer.
10  *
11  * - Redistribution in binary form must reproduce the above copyright
12  *   notice, this list of conditions and the following disclaimer in the
13  *   documentation and/or other materials provided with the distribution.
14  *
15  * Neither the name of Sun Microsystems, Inc. or the names of
16  * contributors may be used to endorse or promote products derived from
17  * this software without specific prior written permission.
18  *
19  * This software is provided "AS IS," without a warranty of any kind. ALL
20  * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
21  * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
22  * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
23  * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
24  * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
25  * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
26  * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
27  * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
28  * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
29  * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
30  * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
31  *
32  * You acknowledge that this software is not designed or intended for use
33  * in the design, construction, operation or maintenance of any nuclear
34  * facility.
35  *
36  * Sun gratefully acknowledges that this software was originally authored
37  * and developed by Kenneth Bradley Russell and Christopher John Kline.
38  */
39 
40 package com.sun.opengl.util;
41 
42 import javax.media.opengl.*;
43 import javax.media.opengl.glu.*;
44 
45 /** Subset of the routines provided by the GLUT interface. Note the
46     signatures of many of the methods are necessarily different than
47     the corresponding C version. A GLUT object must only be used from
48     one particular thread at a time. <P>
49 
50     Copyright (c) Mark J. Kilgard, 1994, 1997. <P>
51 
52     (c) Copyright 1993, Silicon Graphics, Inc. <P>
53 
54     ALL RIGHTS RESERVED <P>
55 
56     Permission to use, copy, modify, and distribute this software
57     for any purpose and without fee is hereby granted, provided
58     that the above copyright notice appear in all copies and that
59     both the copyright notice and this permission notice appear in
60     supporting documentation, and that the name of Silicon
61     Graphics, Inc. not be used in advertising or publicity
62     pertaining to distribution of the software without specific,
63     written prior permission. <P>
64 
65     THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU
66     "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR
67     OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF
68     MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  IN NO
69     EVENT SHALL SILICON GRAPHICS, INC.  BE LIABLE TO YOU OR ANYONE
70     ELSE FOR ANY DIRECT, SPECIAL, INCIDENTAL, INDIRECT OR
71     CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER,
72     INCLUDING WITHOUT LIMITATION, LOSS OF PROFIT, LOSS OF USE,
73     SAVINGS OR REVENUE, OR THE CLAIMS OF THIRD PARTIES, WHETHER OR
74     NOT SILICON GRAPHICS, INC.  HAS BEEN ADVISED OF THE POSSIBILITY
75     OF SUCH LOSS, HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
76     ARISING OUT OF OR IN CONNECTION WITH THE POSSESSION, USE OR
77     PERFORMANCE OF THIS SOFTWARE. <P>
78 
79     US Government Users Restricted Rights <P>
80 
81     Use, duplication, or disclosure by the Government is subject to
82     restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
83     (c)(1)(ii) of the Rights in Technical Data and Computer
84     Software clause at DFARS 252.227-7013 and/or in similar or
85     successor clauses in the FAR or the DOD or NASA FAR
86     Supplement.  Unpublished-- rights reserved under the copyright
87     laws of the United States.  Contractor/manufacturer is Silicon
88     Graphics, Inc., 2011 N.  Shoreline Blvd., Mountain View, CA
89     94039-7311. <P>
90 
91     OpenGL(TM) is a trademark of Silicon Graphics, Inc. <P>
92 */
93 
94 public class GLUT {
95   public static final int STROKE_ROMAN = 0;
96   public static final int STROKE_MONO_ROMAN = 1;
97   public static final int BITMAP_9_BY_15 = 2;
98   public static final int BITMAP_8_BY_13 = 3;
99   public static final int BITMAP_TIMES_ROMAN_10 = 4;
100   public static final int BITMAP_TIMES_ROMAN_24 = 5;
101   public static final int BITMAP_HELVETICA_10 = 6;
102   public static final int BITMAP_HELVETICA_12 = 7;
103   public static final int BITMAP_HELVETICA_18 = 8;
104 
105   private GLU glu = new GLU();
106 
107   //----------------------------------------------------------------------
108   // Shapes
109   //
110 
glutWireSphere(double radius, int slices, int stacks)111   public void glutWireSphere(double radius, int slices, int stacks) {
112     quadObjInit(glu);
113     glu.gluQuadricDrawStyle(quadObj, GLU.GLU_LINE);
114     glu.gluQuadricNormals(quadObj, GLU.GLU_SMOOTH);
115     /* If we ever changed/used the texture or orientation state
116        of quadObj, we'd need to change it to the defaults here
117        with gluQuadricTexture and/or gluQuadricOrientation. */
118     glu.gluSphere(quadObj, radius, slices, stacks);
119   }
120 
glutSolidSphere(double radius, int slices, int stacks)121   public void glutSolidSphere(double radius, int slices, int stacks) {
122     quadObjInit(glu);
123     glu.gluQuadricDrawStyle(quadObj, GLU.GLU_FILL);
124     glu.gluQuadricNormals(quadObj, GLU.GLU_SMOOTH);
125     /* If we ever changed/used the texture or orientation state
126        of quadObj, we'd need to change it to the defaults here
127        with gluQuadricTexture and/or gluQuadricOrientation. */
128     glu.gluSphere(quadObj, radius, slices, stacks);
129   }
130 
glutWireCone(double base, double height, int slices, int stacks)131   public void glutWireCone(double base, double height,
132                            int slices, int stacks) {
133     quadObjInit(glu);
134     glu.gluQuadricDrawStyle(quadObj, GLU.GLU_LINE);
135     glu.gluQuadricNormals(quadObj, GLU.GLU_SMOOTH);
136     /* If we ever changed/used the texture or orientation state
137        of quadObj, we'd need to change it to the defaults here
138        with gluQuadricTexture and/or gluQuadricOrientation. */
139     glu.gluCylinder(quadObj, base, 0.0, height, slices, stacks);
140   }
141 
glutSolidCone(double base, double height, int slices, int stacks)142   public void glutSolidCone(double base, double height,
143                             int slices, int stacks) {
144     quadObjInit(glu);
145     glu.gluQuadricDrawStyle(quadObj, GLU.GLU_FILL);
146     glu.gluQuadricNormals(quadObj, GLU.GLU_SMOOTH);
147     /* If we ever changed/used the texture or orientation state
148        of quadObj, we'd need to change it to the defaults here
149        with gluQuadricTexture and/or gluQuadricOrientation. */
150     glu.gluCylinder(quadObj, base, 0.0, height, slices, stacks);
151   }
152 
glutWireCylinder(double radius, double height, int slices, int stacks)153   public void glutWireCylinder(double radius, double height, int slices, int stacks) {
154     quadObjInit(glu);
155     glu.gluQuadricDrawStyle(quadObj, GLU.GLU_LINE);
156     glu.gluQuadricNormals(quadObj, GLU.GLU_SMOOTH);
157     /* If we ever changed/used the texture or orientation state
158        of quadObj, we'd need to change it to the defaults here
159        with gluQuadricTexture and/or gluQuadricOrientation. */
160     glu.gluCylinder(quadObj, radius, radius, height, slices, stacks);
161   }
162 
glutSolidCylinder(double radius, double height, int slices, int stacks)163   public void glutSolidCylinder(double radius, double height, int slices, int stacks) {
164     GL gl = glu.getCurrentGL();
165 
166     // Prepare table of points for drawing end caps
167     double [] x = new double[slices];
168     double [] y = new double[slices];
169     double angleDelta = Math.PI * 2 / slices;
170     double angle = 0;
171     for (int i = 0 ; i < slices ; i ++) {
172       angle = i * angleDelta;
173       x[i] = Math.cos(angle) * radius;
174       y[i] = Math.sin(angle) * radius;
175     }
176 
177     // Draw bottom cap
178     gl.glBegin(GL.GL_TRIANGLE_FAN);
179     gl.glNormal3d(0,0,-1);
180     gl.glVertex3d(0,0,0);
181     for (int i = 0 ; i < slices ; i ++) {
182       gl.glVertex3d(x[i], y[i], 0);
183     }
184     gl.glVertex3d(x[0], y[0], 0);
185     gl.glEnd();
186 
187     // Draw top cap
188     gl.glBegin(GL.GL_TRIANGLE_FAN);
189     gl.glNormal3d(0,0,1);
190     gl.glVertex3d(0,0,height);
191     for (int i = 0 ; i < slices ; i ++) {
192       gl.glVertex3d(x[i], y[i], height);
193     }
194     gl.glVertex3d(x[0], y[0], height);
195     gl.glEnd();
196 
197     // Draw walls
198     quadObjInit(glu);
199     glu.gluQuadricDrawStyle(quadObj, GLU.GLU_FILL);
200     glu.gluQuadricNormals(quadObj, GLU.GLU_SMOOTH);
201     /* If we ever changed/used the texture or orientation state
202        of quadObj, we'd need to change it to the defaults here
203        with gluQuadricTexture and/or gluQuadricOrientation. */
204     glu.gluCylinder(quadObj, radius, radius, height, slices, stacks);
205   }
206 
glutWireCube(float size)207   public void glutWireCube(float size) {
208     drawBox(GLU.getCurrentGL(), size, GL.GL_LINE_LOOP);
209   }
210 
glutSolidCube(float size)211   public void glutSolidCube(float size) {
212     drawBox(GLU.getCurrentGL(), size, GL.GL_QUADS);
213   }
214 
glutWireTorus(double innerRadius, double outerRadius, int nsides, int rings)215   public void glutWireTorus(double innerRadius, double outerRadius,
216                             int nsides, int rings) {
217     GL gl = GLU.getCurrentGL();
218     gl.glPushAttrib(GL.GL_POLYGON_BIT);
219     gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL.GL_LINE);
220     doughnut(gl, innerRadius, outerRadius, nsides, rings);
221     gl.glPopAttrib();
222   }
223 
glutSolidTorus(double innerRadius, double outerRadius, int nsides, int rings)224   public void glutSolidTorus(double innerRadius, double outerRadius,
225                              int nsides, int rings) {
226     doughnut(GLU.getCurrentGL(), innerRadius, outerRadius, nsides, rings);
227   }
228 
glutWireDodecahedron()229   public void glutWireDodecahedron() {
230     dodecahedron(GLU.getCurrentGL(), GL.GL_LINE_LOOP);
231   }
232 
glutSolidDodecahedron()233   public void glutSolidDodecahedron() {
234     dodecahedron(GLU.getCurrentGL(), GL.GL_TRIANGLE_FAN);
235   }
236 
glutWireOctahedron()237   public void glutWireOctahedron() {
238     octahedron(GLU.getCurrentGL(), GL.GL_LINE_LOOP);
239   }
240 
glutSolidOctahedron()241   public void glutSolidOctahedron() {
242     octahedron(GLU.getCurrentGL(), GL.GL_TRIANGLES);
243   }
244 
glutWireIcosahedron()245   public void glutWireIcosahedron() {
246     icosahedron(GLU.getCurrentGL(), GL.GL_LINE_LOOP);
247   }
248 
glutSolidIcosahedron()249   public void glutSolidIcosahedron() {
250     icosahedron(GLU.getCurrentGL(), GL.GL_TRIANGLES);
251   }
252 
glutWireTetrahedron()253   public void glutWireTetrahedron() {
254     tetrahedron(GLU.getCurrentGL(), GL.GL_LINE_LOOP);
255   }
256 
glutSolidTetrahedron()257   public void glutSolidTetrahedron() {
258     tetrahedron(GLU.getCurrentGL(), GL.GL_TRIANGLES);
259   }
260 
261 /**
262    * Renders the teapot as a solid shape of the specified size. The teapot is
263    * created in a way that replicates the C GLUT implementation.
264    *
265    * @param scale
266    *        the factor by which to scale the teapot
267    */
glutSolidTeapot(double scale)268   public void glutSolidTeapot(double scale) {
269     glutSolidTeapot(scale, true);
270   }
271 
272   /**
273    * Renders the teapot as a solid shape of the specified size. The teapot can
274    * either be created in a way that is backward-compatible with the standard
275    * C glut library (i.e. broken), or in a more pleasing way (i.e. with
276    * surfaces whose front-faces point outwards and standing on the z=0 plane,
277    * instead of the y=-1 plane). Both surface normals and texture coordinates
278    * for the teapot are generated. The teapot is generated with OpenGL
279    * evaluators.
280    *
281    * @param scale
282    *        the factor by which to scale the teapot
283    * @param cStyle
284    *        whether to create the teapot in exactly the same way as in the C
285    *        implementation of GLUT
286    */
glutSolidTeapot(double scale, boolean cStyle)287   public void glutSolidTeapot(double scale, boolean cStyle) {
288     teapot(GLU.getCurrentGL(), 14, scale, GL.GL_FILL, cStyle);
289   }
290 
291   /**
292    * Renders the teapot as a wireframe shape of the specified size. The teapot
293    * is created in a way that replicates the C GLUT implementation.
294    *
295    * @param scale
296    *        the factor by which to scale the teapot
297    */
glutWireTeapot(double scale)298   public void glutWireTeapot(double scale) {
299     glutWireTeapot(scale, true);
300   }
301 
302   /**
303    * Renders the teapot as a wireframe shape of the specified size. The teapot
304    * can either be created in a way that is backward-compatible with the
305    * standard C glut library (i.e. broken), or in a more pleasing way (i.e.
306    * with surfaces whose front-faces point outwards and standing on the z=0
307    * plane, instead of the y=-1 plane). Both surface normals and texture
308    * coordinates for the teapot are generated. The teapot is generated with
309    * OpenGL evaluators.
310    *
311    * @param scale
312    *        the factor by which to scale the teapot
313    * @param cStyle
314    *        whether to create the teapot in exactly the same way as in the C
315    *        implementation of GLUT
316    */
glutWireTeapot(double scale, boolean cStyle)317   public void glutWireTeapot(double scale, boolean cStyle) {
318     teapot(GLU.getCurrentGL(), 10, scale, GL.GL_LINE, cStyle);
319   }
320 
321   //----------------------------------------------------------------------
322   // Fonts
323   //
324 
glutBitmapCharacter(int font, char character)325   public void glutBitmapCharacter(int font, char character) {
326     GL gl = GLU.getCurrentGL();
327     int[] swapbytes  = new int[1];
328     int[] lsbfirst   = new int[1];
329     int[] rowlength  = new int[1];
330     int[] skiprows   = new int[1];
331     int[] skippixels = new int[1];
332     int[] alignment  = new int[1];
333     beginBitmap(gl,
334                 swapbytes,
335                 lsbfirst,
336                 rowlength,
337                 skiprows,
338                 skippixels,
339                 alignment);
340     bitmapCharacterImpl(gl, font, character);
341     endBitmap(gl,
342               swapbytes,
343               lsbfirst,
344               rowlength,
345               skiprows,
346               skippixels,
347               alignment);
348   }
349 
glutBitmapString(int font, String string)350   public void glutBitmapString   (int font, String string) {
351     GL gl = GLU.getCurrentGL();
352     int[] swapbytes  = new int[1];
353     int[] lsbfirst   = new int[1];
354     int[] rowlength  = new int[1];
355     int[] skiprows   = new int[1];
356     int[] skippixels = new int[1];
357     int[] alignment  = new int[1];
358     beginBitmap(gl,
359                 swapbytes,
360                 lsbfirst,
361                 rowlength,
362                 skiprows,
363                 skippixels,
364                 alignment);
365     int len = string.length();
366     for (int i = 0; i < len; i++) {
367       bitmapCharacterImpl(gl, font, string.charAt(i));
368     }
369     endBitmap(gl,
370               swapbytes,
371               lsbfirst,
372               rowlength,
373               skiprows,
374               skippixels,
375               alignment);
376   }
377 
glutBitmapWidth(int font, char character)378   public int  glutBitmapWidth    (int font, char character) {
379     BitmapFontRec fontinfo = getBitmapFont(font);
380     int c = character & 0xFFFF;
381     if (c < fontinfo.first || c >= fontinfo.first + fontinfo.num_chars)
382       return 0;
383     BitmapCharRec ch = fontinfo.ch[c - fontinfo.first];
384     if (ch != null)
385       return (int) ch.advance;
386     else
387       return 0;
388   }
389 
glutStrokeCharacter(int font, char character)390   public void glutStrokeCharacter(int font, char character) {
391     GL gl = GLU.getCurrentGL();
392     StrokeFontRec fontinfo = getStrokeFont(font);
393     int c = character & 0xFFFF;
394     if (c < 0 || c >= fontinfo.num_chars)
395       return;
396     StrokeCharRec ch = fontinfo.ch[c];
397     if (ch != null) {
398       for (int i = 0; i < ch.num_strokes; i++) {
399         StrokeRec stroke = ch.stroke[i];
400         gl.glBegin(GL.GL_LINE_STRIP);
401         for (int j = 0; j < stroke.num_coords; j++) {
402           CoordRec coord = stroke.coord[j];
403           gl.glVertex2f(coord.x, coord.y);
404         }
405         gl.glEnd();
406       }
407       gl.glTranslatef(ch.right, 0.0f, 0.0f);
408     }
409   }
410 
glutStrokeString(int font, String string)411   public void glutStrokeString(int font, String string) {
412     GL gl = GLU.getCurrentGL();
413     StrokeFontRec fontinfo = getStrokeFont(font);
414     int len = string.length();
415     for (int pos = 0; pos < len; pos++) {
416       int c = string.charAt(pos) & 0xFFFF;
417       if (c < 0 || c >= fontinfo.num_chars)
418         continue;
419       StrokeCharRec ch = fontinfo.ch[c];
420       if (ch != null) {
421         for (int i = 0; i < ch.num_strokes; i++) {
422           StrokeRec stroke = ch.stroke[i];
423           gl.glBegin(GL.GL_LINE_STRIP);
424           for (int j = 0; j < stroke.num_coords; j++) {
425             CoordRec coord = stroke.coord[j];
426             gl.glVertex2f(coord.x, coord.y);
427           }
428           gl.glEnd();
429         }
430         gl.glTranslatef(ch.right, 0.0f, 0.0f);
431       }
432     }
433   }
434 
glutStrokeWidth(int font, char character)435   public int  glutStrokeWidth    (int font, char character) {
436     return (int) glutStrokeWidthf(font, character);
437   }
438 
glutStrokeWidthf(int font, char character)439   public float glutStrokeWidthf   (int font, char character) {
440     StrokeFontRec fontinfo = getStrokeFont(font);
441     int c = character & 0xFFFF;
442     if (c < 0 || c >= fontinfo.num_chars)
443       return 0;
444     StrokeCharRec ch = fontinfo.ch[c];
445     if (ch != null)
446       return ch.right;
447     else
448       return 0;
449   }
450 
glutBitmapLength(int font, String string)451   public int  glutBitmapLength   (int font, String string) {
452     BitmapFontRec fontinfo = getBitmapFont(font);
453     int length = 0;
454     int len = string.length();
455     for (int pos = 0; pos < len; pos++) {
456       int c = string.charAt(pos) & 0xFFFF;
457       if (c >= fontinfo.first && c < fontinfo.first + fontinfo.num_chars) {
458         BitmapCharRec ch = fontinfo.ch[c - fontinfo.first];
459         if (ch != null)
460           length += ch.advance;
461       }
462     }
463     return length;
464   }
465 
glutStrokeLength(int font, String string)466   public int  glutStrokeLength   (int font, String string) {
467     return (int) glutStrokeLengthf(font, string);
468   }
469 
glutStrokeLengthf(int font, String string)470   public float glutStrokeLengthf  (int font, String string) {
471     StrokeFontRec fontinfo = getStrokeFont(font);
472     float length = 0;
473     int len = string.length();
474     for (int i = 0; i < len; i++) {
475       char c = string.charAt(i);
476       if (c >= 0 && c < fontinfo.num_chars) {
477         StrokeCharRec ch = fontinfo.ch[c];
478         if (ch != null)
479           length += ch.right;
480       }
481     }
482     return length;
483   }
484 
485   /**
486      This function draws a wireframe dodecahedron whose
487      facets are rhombic and
488      whose vertices are at unit radius.
489      No facet lies normal to any coordinate axes.
490      The polyhedron is centered at the origin.
491   */
glutWireRhombicDodecahedron()492   public void glutWireRhombicDodecahedron() {
493     GL gl = glu.getCurrentGL();
494     for( int i = 0; i < 12; i++ ) {
495       gl.glBegin( GL.GL_LINE_LOOP );
496       gl.glNormal3dv( rdod_n[ i ],0 );
497       gl.glVertex3dv( rdod_r[ rdod_v[ i ][ 0 ] ],0 );
498       gl.glVertex3dv( rdod_r[ rdod_v[ i ][ 1 ] ],0 );
499       gl.glVertex3dv( rdod_r[ rdod_v[ i ][ 2 ] ],0 );
500       gl.glVertex3dv( rdod_r[ rdod_v[ i ][ 3 ] ],0 );
501       gl.glEnd( );
502     }
503   }
504 
505   /**
506    This function draws a solid-shaded dodecahedron
507    whose facets are rhombic and
508    whose vertices are at unit radius.
509    No facet lies normal to any coordinate axes.
510    The polyhedron is centered at the origin.
511    */
glutSolidRhombicDodecahedron()512   public void glutSolidRhombicDodecahedron() {
513     GL gl = glu.getCurrentGL();
514     gl.glBegin( GL.GL_QUADS );
515     for( int i = 0; i < 12; i++ ) {
516       gl.glNormal3dv( rdod_n[ i ],0 );
517       gl.glVertex3dv( rdod_r[ rdod_v[ i ][ 0 ] ],0 );
518       gl.glVertex3dv( rdod_r[ rdod_v[ i ][ 1 ] ],0 );
519       gl.glVertex3dv( rdod_r[ rdod_v[ i ][ 2 ] ],0 );
520       gl.glVertex3dv( rdod_r[ rdod_v[ i ][ 3 ] ],0 );
521     }
522     gl.glEnd( );
523   }
524 
525   //----------------------------------------------------------------------
526   // Internals only below this point
527   //
528 
529   //----------------------------------------------------------------------
530   // Shape implementation
531   //
532 
533   private GLUquadric quadObj;
quadObjInit(GLU glu)534   private void quadObjInit(GLU glu) {
535     if (quadObj == null) {
536       quadObj = glu.gluNewQuadric();
537     }
538     if (quadObj == null) {
539       throw new GLException("Out of memory");
540     }
541   }
542 
doughnut(GL gl, double r, double R, int nsides, int rings)543   private static void doughnut(GL gl, double r, double R, int nsides, int rings) {
544     int i, j;
545     float theta, phi, theta1;
546     float cosTheta, sinTheta;
547     float cosTheta1, sinTheta1;
548     float ringDelta, sideDelta;
549 
550     ringDelta = (float) (2.0 * Math.PI / rings);
551     sideDelta = (float) (2.0 * Math.PI / nsides);
552 
553     theta = 0.0f;
554     cosTheta = 1.0f;
555     sinTheta = 0.0f;
556     for (i = rings - 1; i >= 0; i--) {
557       theta1 = theta + ringDelta;
558       cosTheta1 = (float) Math.cos(theta1);
559       sinTheta1 = (float) Math.sin(theta1);
560       gl.glBegin(GL.GL_QUAD_STRIP);
561       phi = 0.0f;
562       for (j = nsides; j >= 0; j--) {
563         float cosPhi, sinPhi, dist;
564 
565         phi += sideDelta;
566         cosPhi = (float) Math.cos(phi);
567         sinPhi = (float) Math.sin(phi);
568         dist = (float) (R + r * cosPhi);
569 
570         gl.glNormal3f(cosTheta1 * cosPhi, -sinTheta1 * cosPhi, sinPhi);
571         gl.glVertex3f(cosTheta1 * dist,   -sinTheta1 * dist,   (float) r * sinPhi);
572         gl.glNormal3f(cosTheta  * cosPhi, -sinTheta  * cosPhi, sinPhi);
573         gl.glVertex3f(cosTheta  * dist,   -sinTheta  * dist,   (float) r * sinPhi);
574       }
575       gl.glEnd();
576       theta = theta1;
577       cosTheta = cosTheta1;
578       sinTheta = sinTheta1;
579     }
580   }
581 
582   private static float[][] boxVertices;
583   private static final float[][] boxNormals = {
584     {-1.0f, 0.0f, 0.0f},
585     {0.0f, 1.0f, 0.0f},
586     {1.0f, 0.0f, 0.0f},
587     {0.0f, -1.0f, 0.0f},
588     {0.0f, 0.0f, 1.0f},
589     {0.0f, 0.0f, -1.0f}
590   };
591   private static final int[][] boxFaces = {
592     {0, 1, 2, 3},
593     {3, 2, 6, 7},
594     {7, 6, 5, 4},
595     {4, 5, 1, 0},
596     {5, 6, 2, 1},
597     {7, 4, 0, 3}
598   };
drawBox(GL gl, float size, int type)599   private void drawBox(GL gl, float size, int type) {
600     if (boxVertices == null) {
601       float[][] v = new float[8][];
602       for (int i = 0; i < 8; i++) {
603         v[i] = new float[3];
604       }
605       v[0][0] = v[1][0] = v[2][0] = v[3][0] = -0.5f;
606       v[4][0] = v[5][0] = v[6][0] = v[7][0] =  0.5f;
607       v[0][1] = v[1][1] = v[4][1] = v[5][1] = -0.5f;
608       v[2][1] = v[3][1] = v[6][1] = v[7][1] =  0.5f;
609       v[0][2] = v[3][2] = v[4][2] = v[7][2] = -0.5f;
610       v[1][2] = v[2][2] = v[5][2] = v[6][2] =  0.5f;
611       boxVertices = v;
612     }
613     float[][] v = boxVertices;
614     float[][] n = boxNormals;
615     int[][] faces = boxFaces;
616     for (int i = 5; i >= 0; i--) {
617       gl.glBegin(type);
618       gl.glNormal3fv(n[i], 0);
619       float[] vt = v[faces[i][0]];
620       gl.glVertex3f(vt[0] * size, vt[1] * size, vt[2] * size);
621       vt = v[faces[i][1]];
622       gl.glVertex3f(vt[0] * size, vt[1] * size, vt[2] * size);
623       vt = v[faces[i][2]];
624       gl.glVertex3f(vt[0] * size, vt[1] * size, vt[2] * size);
625       vt = v[faces[i][3]];
626       gl.glVertex3f(vt[0] * size, vt[1] * size, vt[2] * size);
627       gl.glEnd();
628     }
629   }
630 
631   private float[][] dodec;
632 
initDodecahedron()633   private void initDodecahedron() {
634     dodec = new float[20][];
635     for (int i = 0; i < dodec.length; i++) {
636       dodec[i] = new float[3];
637     }
638 
639     float alpha, beta;
640 
641     alpha = (float) Math.sqrt(2.0f / (3.0f + Math.sqrt(5.0)));
642     beta = 1.0f + (float) Math.sqrt(6.0 / (3.0 + Math.sqrt(5.0)) -
643                                     2.0 + 2.0 * Math.sqrt(2.0 / (3.0 + Math.sqrt(5.0))));
644     dodec[0][0] = -alpha; dodec[0][1] = 0; dodec[0][2] = beta;
645     dodec[1][0] = alpha; dodec[1][1] = 0; dodec[1][2] = beta;
646     dodec[2][0] = -1; dodec[2][1] = -1; dodec[2][2] = -1;
647     dodec[3][0] = -1; dodec[3][1] = -1; dodec[3][2] = 1;
648     dodec[4][0] = -1; dodec[4][1] = 1; dodec[4][2] = -1;
649     dodec[5][0] = -1; dodec[5][1] = 1; dodec[5][2] = 1;
650     dodec[6][0] = 1; dodec[6][1] = -1; dodec[6][2] = -1;
651     dodec[7][0] = 1; dodec[7][1] = -1; dodec[7][2] = 1;
652     dodec[8][0] = 1; dodec[8][1] = 1; dodec[8][2] = -1;
653     dodec[9][0] = 1; dodec[9][1] = 1; dodec[9][2] = 1;
654     dodec[10][0] = beta; dodec[10][1] = alpha; dodec[10][2] = 0;
655     dodec[11][0] = beta; dodec[11][1] = -alpha; dodec[11][2] = 0;
656     dodec[12][0] = -beta; dodec[12][1] = alpha; dodec[12][2] = 0;
657     dodec[13][0] = -beta; dodec[13][1] = -alpha; dodec[13][2] = 0;
658     dodec[14][0] = -alpha; dodec[14][1] = 0; dodec[14][2] = -beta;
659     dodec[15][0] = alpha; dodec[15][1] = 0; dodec[15][2] = -beta;
660     dodec[16][0] = 0; dodec[16][1] = beta; dodec[16][2] = alpha;
661     dodec[17][0] = 0; dodec[17][1] = beta; dodec[17][2] = -alpha;
662     dodec[18][0] = 0; dodec[18][1] = -beta; dodec[18][2] = alpha;
663     dodec[19][0] = 0; dodec[19][1] = -beta; dodec[19][2] = -alpha;
664   }
665 
diff3(float[] a, float[] b, float[] c)666   private static void diff3(float[] a, float[] b, float[] c) {
667     c[0] = a[0] - b[0];
668     c[1] = a[1] - b[1];
669     c[2] = a[2] - b[2];
670   }
671 
crossprod(float[] v1, float[] v2, float[] prod)672   private static void crossprod(float[] v1, float[] v2, float[] prod) {
673     float[] p = new float[3];         /* in case prod == v1 or v2 */
674 
675     p[0] = v1[1] * v2[2] - v2[1] * v1[2];
676     p[1] = v1[2] * v2[0] - v2[2] * v1[0];
677     p[2] = v1[0] * v2[1] - v2[0] * v1[1];
678     prod[0] = p[0];
679     prod[1] = p[1];
680     prod[2] = p[2];
681   }
682 
normalize(float[] v)683   private static void normalize(float[] v) {
684     float d;
685 
686     d = (float) Math.sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
687     if (d == 0.0) {
688       v[0] = d = 1.0f;
689     }
690     d = 1 / d;
691     v[0] *= d;
692     v[1] *= d;
693     v[2] *= d;
694   }
695 
pentagon(GL gl, int a, int b, int c, int d, int e, int shadeType)696   private void pentagon(GL gl, int a, int b, int c, int d, int e, int shadeType) {
697     float[] n0 = new float[3];
698     float[] d1 = new float[3];
699     float[] d2 = new float[3];
700 
701     diff3(dodec[a], dodec[b], d1);
702     diff3(dodec[b], dodec[c], d2);
703     crossprod(d1, d2, n0);
704     normalize(n0);
705 
706     gl.glBegin(shadeType);
707     gl.glNormal3fv(n0, 0);
708     gl.glVertex3fv(dodec[a], 0);
709     gl.glVertex3fv(dodec[b], 0);
710     gl.glVertex3fv(dodec[c], 0);
711     gl.glVertex3fv(dodec[d], 0);
712     gl.glVertex3fv(dodec[e], 0);
713     gl.glEnd();
714   }
715 
dodecahedron(GL gl, int type)716   private void dodecahedron(GL gl, int type) {
717     if (dodec == null) {
718       initDodecahedron();
719     }
720     pentagon(gl, 0, 1, 9, 16, 5, type);
721     pentagon(gl, 1, 0, 3, 18, 7, type);
722     pentagon(gl, 1, 7, 11, 10, 9, type);
723     pentagon(gl, 11, 7, 18, 19, 6, type);
724     pentagon(gl, 8, 17, 16, 9, 10, type);
725     pentagon(gl, 2, 14, 15, 6, 19, type);
726     pentagon(gl, 2, 13, 12, 4, 14, type);
727     pentagon(gl, 2, 19, 18, 3, 13, type);
728     pentagon(gl, 3, 0, 5, 12, 13, type);
729     pentagon(gl, 6, 15, 8, 10, 11, type);
730     pentagon(gl, 4, 17, 8, 15, 14, type);
731     pentagon(gl, 4, 12, 5, 16, 17, type);
732   }
733 
recorditem(GL gl, float[] n1, float[] n2, float[] n3, int shadeType)734   private static void recorditem(GL gl, float[] n1, float[] n2, float[] n3, int shadeType) {
735     float[] q0 = new float[3];
736     float[] q1 = new float[3];
737 
738     diff3(n1, n2, q0);
739     diff3(n2, n3, q1);
740     crossprod(q0, q1, q1);
741     normalize(q1);
742 
743     gl.glBegin(shadeType);
744     gl.glNormal3fv(q1, 0);
745     gl.glVertex3fv(n1, 0);
746     gl.glVertex3fv(n2, 0);
747     gl.glVertex3fv(n3, 0);
748     gl.glEnd();
749   }
750 
subdivide(GL gl, float[] v0, float[] v1, float[] v2, int shadeType)751   private static void subdivide(GL gl, float[] v0, float[] v1, float[] v2, int shadeType) {
752     int depth;
753     float[] w0 = new float[3];
754     float[] w1 = new float[3];
755     float[] w2 = new float[3];
756     float l;
757     int i, j, k, n;
758 
759     depth = 1;
760     for (i = 0; i < depth; i++) {
761       for (j = 0; i + j < depth; j++) {
762         k = depth - i - j;
763         for (n = 0; n < 3; n++) {
764           w0[n] = (i * v0[n] + j * v1[n] + k * v2[n]) / depth;
765           w1[n] = ((i + 1) * v0[n] + j * v1[n] + (k - 1) * v2[n])
766             / depth;
767           w2[n] = (i * v0[n] + (j + 1) * v1[n] + (k - 1) * v2[n])
768             / depth;
769         }
770         l = (float) Math.sqrt(w0[0] * w0[0] + w0[1] * w0[1] + w0[2] * w0[2]);
771         w0[0] /= l;
772         w0[1] /= l;
773         w0[2] /= l;
774         l = (float) Math.sqrt(w1[0] * w1[0] + w1[1] * w1[1] + w1[2] * w1[2]);
775         w1[0] /= l;
776         w1[1] /= l;
777         w1[2] /= l;
778         l = (float) Math.sqrt(w2[0] * w2[0] + w2[1] * w2[1] + w2[2] * w2[2]);
779         w2[0] /= l;
780         w2[1] /= l;
781         w2[2] /= l;
782         recorditem(gl, w1, w0, w2, shadeType);
783       }
784     }
785   }
786 
drawtriangle(GL gl, int i, float[][] data, int[][] ndx, int shadeType)787   private static void drawtriangle(GL gl, int i, float[][] data, int[][] ndx, int shadeType) {
788     float[] x0 = data[ndx[i][0]];
789     float[] x1 = data[ndx[i][1]];
790     float[] x2 = data[ndx[i][2]];
791     subdivide(gl, x0, x1, x2, shadeType);
792   }
793 
794   /* octahedron data: The octahedron produced is centered at the
795      origin and has radius 1.0 */
796   private static final float[][] odata =
797   {
798     {1.0f, 0.0f, 0.0f},
799     {-1.0f, 0.0f, 0.0f},
800     {0.0f, 1.0f, 0.0f},
801     {0.0f, -1.0f, 0.0f},
802     {0.0f, 0.0f, 1.0f},
803     {0.0f, 0.0f, -1.0f}
804   };
805 
806   private static final int[][] ondex =
807   {
808     {0, 4, 2},
809     {1, 2, 4},
810     {0, 3, 4},
811     {1, 4, 3},
812     {0, 2, 5},
813     {1, 5, 2},
814     {0, 5, 3},
815     {1, 3, 5}
816   };
817 
octahedron(GL gl, int shadeType)818   private static void octahedron(GL gl, int shadeType) {
819     int i;
820 
821     for (i = 7; i >= 0; i--) {
822       drawtriangle(gl, i, odata, ondex, shadeType);
823     }
824   }
825 
826   /* icosahedron data: These numbers are rigged to make an
827      icosahedron of radius 1.0 */
828 
829   private static final float X = .525731112119133606f;
830   private static final float Z = .850650808352039932f;
831 
832   private static final float[][] idata =
833   {
834     {-X, 0, Z},
835     {X, 0, Z},
836     {-X, 0, -Z},
837     {X, 0, -Z},
838     {0, Z, X},
839     {0, Z, -X},
840     {0, -Z, X},
841     {0, -Z, -X},
842     {Z, X, 0},
843     {-Z, X, 0},
844     {Z, -X, 0},
845     {-Z, -X, 0}
846   };
847 
848   private static final int[][] index =
849   {
850     {0, 4, 1},
851     {0, 9, 4},
852     {9, 5, 4},
853     {4, 5, 8},
854     {4, 8, 1},
855     {8, 10, 1},
856     {8, 3, 10},
857     {5, 3, 8},
858     {5, 2, 3},
859     {2, 7, 3},
860     {7, 10, 3},
861     {7, 6, 10},
862     {7, 11, 6},
863     {11, 0, 6},
864     {0, 1, 6},
865     {6, 1, 10},
866     {9, 0, 11},
867     {9, 11, 2},
868     {9, 2, 5},
869     {7, 2, 11},
870   };
871 
icosahedron(GL gl, int shadeType)872   private static void icosahedron(GL gl, int shadeType) {
873     int i;
874 
875     for (i = 19; i >= 0; i--) {
876       drawtriangle(gl, i, idata, index, shadeType);
877     }
878   }
879 
880   /* rhombic dodecahedron data: */
881 
882   private static final double rdod_r[][] =
883   {
884     { 0.0, 0.0, 1.0 },
885     {  0.707106781187,  0.000000000000,  0.5 },
886     {  0.000000000000,  0.707106781187,  0.5 },
887     { -0.707106781187,  0.000000000000,  0.5 },
888     {  0.000000000000, -0.707106781187,  0.5 },
889     {  0.707106781187,  0.707106781187,  0.0 },
890     { -0.707106781187,  0.707106781187,  0.0 },
891     { -0.707106781187, -0.707106781187,  0.0 },
892     {  0.707106781187, -0.707106781187,  0.0 },
893     {  0.707106781187,  0.000000000000, -0.5 },
894     {  0.000000000000,  0.707106781187, -0.5 },
895     { -0.707106781187,  0.000000000000, -0.5 },
896     {  0.000000000000, -0.707106781187, -0.5 },
897     {  0.0, 0.0, -1.0 }
898   };
899 
900   private static final int rdod_v[][] =
901   {
902     { 0,  1,  5,  2 },
903     { 0,  2,  6,  3 },
904     { 0,  3,  7,  4 },
905     { 0,  4,  8,  1 },
906     { 5, 10,  6,  2 },
907     { 6, 11,  7,  3 },
908     { 7, 12,  8,  4 },
909     { 8,  9,  5,  1 },
910     { 5,  9, 13, 10 },
911     { 6, 10, 13, 11 },
912     { 7, 11, 13, 12 },
913     { 8, 12, 13,  9 }
914   };
915 
916   private static final double rdod_n[][] =
917   {
918     {  0.353553390594,  0.353553390594,  0.5 },
919     { -0.353553390594,  0.353553390594,  0.5 },
920     { -0.353553390594, -0.353553390594,  0.5 },
921     {  0.353553390594, -0.353553390594,  0.5 },
922     {  0.000000000000,  1.000000000000,  0.0 },
923     { -1.000000000000,  0.000000000000,  0.0 },
924     {  0.000000000000, -1.000000000000,  0.0 },
925     {  1.000000000000,  0.000000000000,  0.0 },
926     {  0.353553390594,  0.353553390594, -0.5 },
927     { -0.353553390594,  0.353553390594, -0.5 },
928     { -0.353553390594, -0.353553390594, -0.5 },
929     {  0.353553390594, -0.353553390594, -0.5 }
930   };
931 
932   /* tetrahedron data: */
933 
934   private static final float T = 1.73205080756887729f;
935 
936   private static final float[][] tdata =
937   {
938     {T, T, T},
939     {T, -T, -T},
940     {-T, T, -T},
941     {-T, -T, T}
942   };
943 
944   private static final int[][] tndex =
945   {
946     {0, 1, 3},
947     {2, 1, 0},
948     {3, 2, 0},
949     {1, 2, 3}
950   };
951 
tetrahedron(GL gl, int shadeType)952   private static final void tetrahedron(GL gl, int shadeType) {
953     for (int i = 3; i >= 0; i--)
954       drawtriangle(gl, i, tdata, tndex, shadeType);
955   }
956 
957   // Teapot implementation (a modified port of glut_teapot.c)
958   //
959   // Rim, body, lid, and bottom data must be reflected in x and
960   // y; handle and spout data across the y axis only.
961   private static final int[][] teapotPatchData = {
962     /* rim */
963     {102, 103, 104, 105, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
964     /* body */
965     {12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27},
966     {24, 25, 26, 27, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40},
967     /* lid */
968     {96, 96, 96, 96, 97, 98, 99, 100, 101, 101, 101, 101, 0, 1, 2, 3,},
969     {0, 1, 2, 3, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117},
970     /* bottom */
971     {118, 118, 118, 118, 124, 122, 119, 121, 123, 126, 125, 120, 40, 39, 38, 37},
972     /* handle */
973     {41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56},
974     {53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 28, 65, 66, 67},
975     /* spout */
976     {68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83},
977     {80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95}
978   };
979   private static final float[][] teapotCPData = {
980     {0.2f, 0f, 2.7f},
981     {0.2f, -0.112f, 2.7f},
982     {0.112f, -0.2f, 2.7f},
983     {0f, -0.2f, 2.7f},
984     {1.3375f, 0f, 2.53125f},
985     {1.3375f, -0.749f, 2.53125f},
986     {0.749f, -1.3375f, 2.53125f},
987     {0f, -1.3375f, 2.53125f},
988     {1.4375f, 0f, 2.53125f},
989     {1.4375f, -0.805f, 2.53125f},
990     {0.805f, -1.4375f, 2.53125f},
991     {0f, -1.4375f, 2.53125f},
992     {1.5f, 0f, 2.4f},
993     {1.5f, -0.84f, 2.4f},
994     {0.84f, -1.5f, 2.4f},
995     {0f, -1.5f, 2.4f},
996     {1.75f, 0f, 1.875f},
997     {1.75f, -0.98f, 1.875f},
998     {0.98f, -1.75f, 1.875f},
999     {0f, -1.75f, 1.875f},
1000     {2f, 0f, 1.35f},
1001     {2f, -1.12f, 1.35f},
1002     {1.12f, -2f, 1.35f},
1003     {0f, -2f, 1.35f},
1004     {2f, 0f, 0.9f},
1005     {2f, -1.12f, 0.9f},
1006     {1.12f, -2f, 0.9f},
1007     {0f, -2f, 0.9f},
1008     {-2f, 0f, 0.9f},
1009     {2f, 0f, 0.45f},
1010     {2f, -1.12f, 0.45f},
1011     {1.12f, -2f, 0.45f},
1012     {0f, -2f, 0.45f},
1013     {1.5f, 0f, 0.225f},
1014     {1.5f, -0.84f, 0.225f},
1015     {0.84f, -1.5f, 0.225f},
1016     {0f, -1.5f, 0.225f},
1017     {1.5f, 0f, 0.15f},
1018     {1.5f, -0.84f, 0.15f},
1019     {0.84f, -1.5f, 0.15f},
1020     {0f, -1.5f, 0.15f},
1021     {-1.6f, 0f, 2.025f},
1022     {-1.6f, -0.3f, 2.025f},
1023     {-1.5f, -0.3f, 2.25f},
1024     {-1.5f, 0f, 2.25f},
1025     {-2.3f, 0f, 2.025f},
1026     {-2.3f, -0.3f, 2.025f},
1027     {-2.5f, -0.3f, 2.25f},
1028     {-2.5f, 0f, 2.25f},
1029     {-2.7f, 0f, 2.025f},
1030     {-2.7f, -0.3f, 2.025f},
1031     {-3f, -0.3f, 2.25f},
1032     {-3f, 0f, 2.25f},
1033     {-2.7f, 0f, 1.8f},
1034     {-2.7f, -0.3f, 1.8f},
1035     {-3f, -0.3f, 1.8f},
1036     {-3f, 0f, 1.8f},
1037     {-2.7f, 0f, 1.575f},
1038     {-2.7f, -0.3f, 1.575f},
1039     {-3f, -0.3f, 1.35f},
1040     {-3f, 0f, 1.35f},
1041     {-2.5f, 0f, 1.125f},
1042     {-2.5f, -0.3f, 1.125f},
1043     {-2.65f, -0.3f, 0.9375f},
1044     {-2.65f, 0f, 0.9375f},
1045     {-2f, -0.3f, 0.9f},
1046     {-1.9f, -0.3f, 0.6f},
1047     {-1.9f, 0f, 0.6f},
1048     {1.7f, 0f, 1.425f},
1049     {1.7f, -0.66f, 1.425f},
1050     {1.7f, -0.66f, 0.6f},
1051     {1.7f, 0f, 0.6f},
1052     {2.6f, 0f, 1.425f},
1053     {2.6f, -0.66f, 1.425f},
1054     {3.1f, -0.66f, 0.825f},
1055     {3.1f, 0f, 0.825f},
1056     {2.3f, 0f, 2.1f},
1057     {2.3f, -0.25f, 2.1f},
1058     {2.4f, -0.25f, 2.025f},
1059     {2.4f, 0f, 2.025f},
1060     {2.7f, 0f, 2.4f},
1061     {2.7f, -0.25f, 2.4f},
1062     {3.3f, -0.25f, 2.4f},
1063     {3.3f, 0f, 2.4f},
1064     {2.8f, 0f, 2.475f},
1065     {2.8f, -0.25f, 2.475f},
1066     {3.525f, -0.25f, 2.49375f},
1067     {3.525f, 0f, 2.49375f},
1068     {2.9f, 0f, 2.475f},
1069     {2.9f, -0.15f, 2.475f},
1070     {3.45f, -0.15f, 2.5125f},
1071     {3.45f, 0f, 2.5125f},
1072     {2.8f, 0f, 2.4f},
1073     {2.8f, -0.15f, 2.4f},
1074     {3.2f, -0.15f, 2.4f},
1075     {3.2f, 0f, 2.4f},
1076     {0f, 0f, 3.15f},
1077     {0.8f, 0f, 3.15f},
1078     {0.8f, -0.45f, 3.15f},
1079     {0.45f, -0.8f, 3.15f},
1080     {0f, -0.8f, 3.15f},
1081     {0f, 0f, 2.85f},
1082     {1.4f, 0f, 2.4f},
1083     {1.4f, -0.784f, 2.4f},
1084     {0.784f, -1.4f, 2.4f},
1085     {0f, -1.4f, 2.4f},
1086     {0.4f, 0f, 2.55f},
1087     {0.4f, -0.224f, 2.55f},
1088     {0.224f, -0.4f, 2.55f},
1089     {0f, -0.4f, 2.55f},
1090     {1.3f, 0f, 2.55f},
1091     {1.3f, -0.728f, 2.55f},
1092     {0.728f, -1.3f, 2.55f},
1093     {0f, -1.3f, 2.55f},
1094     {1.3f, 0f, 2.4f},
1095     {1.3f, -0.728f, 2.4f},
1096     {0.728f, -1.3f, 2.4f},
1097     {0f, -1.3f, 2.4f},
1098     {0f, 0f, 0f},
1099     {1.425f, -0.798f, 0f},
1100     {1.5f, 0f, 0.075f},
1101     {1.425f, 0f, 0f},
1102     {0.798f, -1.425f, 0f},
1103     {0f, -1.5f, 0.075f},
1104     {0f, -1.425f, 0f},
1105     {1.5f, -0.84f, 0.075f},
1106     {0.84f, -1.5f, 0.075f}
1107   };
1108   // Since GL.glMap2f expects a packed array of floats, we must convert
1109   // from a 3-dimensional array to a 1-dimensional array
1110   private static final float[] teapotTex = {
1111     0, 0, 1, 0, 0, 1, 1, 1
1112   };
1113 
teapot(GL gl, int grid, double scale, int type, boolean backCompatible)1114   private static void teapot(GL gl,
1115                              int grid,
1116                              double scale,
1117                              int type,
1118                              boolean backCompatible)
1119   {
1120     // As mentioned above, GL.glMap2f expects a packed array of floats
1121     float[] p = new float[4*4*3];
1122     float[] q = new float[4*4*3];
1123     float[] r = new float[4*4*3];
1124     float[] s = new float[4*4*3];
1125     int i, j, k, l;
1126 
1127     gl.glPushAttrib(GL.GL_ENABLE_BIT | GL.GL_EVAL_BIT | GL.GL_POLYGON_BIT);
1128     gl.glEnable(GL.GL_AUTO_NORMAL);
1129     gl.glEnable(GL.GL_NORMALIZE);
1130     gl.glEnable(GL.GL_MAP2_VERTEX_3);
1131     gl.glEnable(GL.GL_MAP2_TEXTURE_COORD_2);
1132     gl.glPushMatrix();
1133     if (!backCompatible) {
1134       // The time has come to have the teapot no longer be inside out
1135       gl.glFrontFace(GL.GL_CW);
1136       gl.glScaled(0.5*scale, 0.5*scale, 0.5*scale);
1137     } else {
1138       // We want the teapot in it's backward compatible position and
1139       // orientation
1140       gl.glRotatef(270.0f, 1, 0, 0);
1141       gl.glScalef((float)(0.5 * scale),
1142                   (float)(0.5 * scale),
1143                   (float)(0.5 * scale));
1144       gl.glTranslatef(0.0f, 0.0f, -1.5f);
1145     }
1146     for (i = 0; i < 10; i++) {
1147       for (j = 0; j < 4; j++) {
1148         for (k = 0; k < 4; k++) {
1149           for (l = 0; l < 3; l++) {
1150             p[(j*4+k)*3+l] = teapotCPData[teapotPatchData[i][j * 4 + k]][l];
1151             q[(j*4+k)*3+l] =
1152               teapotCPData[teapotPatchData[i][j * 4 + (3 - k)]][l];
1153             if (l == 1)
1154               q[(j*4+k)*3+l] *= -1.0;
1155             if (i < 6) {
1156               r[(j*4+k)*3+l] =
1157                 teapotCPData[teapotPatchData[i][j * 4 + (3 - k)]][l];
1158               if (l == 0)
1159                 r[(j*4+k)*3+l] *= -1.0;
1160               s[(j*4+k)*3+l] = teapotCPData[teapotPatchData[i][j * 4 + k]][l];
1161               if (l == 0)
1162                 s[(j*4+k)*3+l] *= -1.0;
1163               if (l == 1)
1164                 s[(j*4+k)*3+l] *= -1.0;
1165             }
1166           }
1167         }
1168       }
1169       gl.glMap2f(GL.GL_MAP2_TEXTURE_COORD_2, 0, 1, 2, 2, 0, 1, 4, 2, teapotTex, 0);
1170       gl.glMap2f(GL.GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4, p, 0);
1171       gl.glMapGrid2f(grid, 0.0f, 1.0f, grid, 0.0f, 1.0f);
1172       evaluateTeapotMesh(gl, grid, type, i, !backCompatible);
1173       gl.glMap2f(GL.GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4, q, 0);
1174       evaluateTeapotMesh(gl, grid, type, i, !backCompatible);
1175       if (i < 6) {
1176         gl.glMap2f(GL.GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4, r, 0);
1177         evaluateTeapotMesh(gl, grid, type, i, !backCompatible);
1178         gl.glMap2f(GL.GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4, s, 0);
1179         evaluateTeapotMesh(gl, grid, type, i, !backCompatible);
1180       }
1181     }
1182     gl.glPopMatrix();
1183     gl.glPopAttrib();
1184   }
1185 
evaluateTeapotMesh(GL gl, int grid, int type, int partNum, boolean repairSingularities)1186   private static void evaluateTeapotMesh(GL gl,
1187                                          int grid,
1188                                          int type,
1189                                          int partNum,
1190                                          boolean repairSingularities)
1191   {
1192     if (repairSingularities && (partNum == 5 || partNum == 3)) {
1193       // Instead of using evaluators that give bad results at singularities,
1194       // evaluate by hand
1195       gl.glPolygonMode(GL.GL_FRONT_AND_BACK, type);
1196       for (int nv = 0; nv < grid; nv++) {
1197         if (nv == 0) {
1198           // Draw a small triangle-fan to fill the hole
1199           gl.glDisable(GL.GL_AUTO_NORMAL);
1200           gl.glNormal3f(0, 0, partNum == 3 ? 1 : -1);
1201           gl.glBegin(GL.GL_TRIANGLE_FAN);
1202           {
1203             gl.glEvalCoord2f(0, 0);
1204             // Note that we draw in clock-wise order to match the evaluator
1205             // method
1206             for (int nu = 0; nu <= grid; nu++)
1207             {
1208               gl.glEvalCoord2f(nu / (float)grid, (1f / grid) / (float)grid);
1209             }
1210           }
1211           gl.glEnd();
1212           gl.glEnable(GL.GL_AUTO_NORMAL);
1213         }
1214         // Draw the rest of the piece as an evaluated quad-strip
1215         gl.glBegin(GL.GL_QUAD_STRIP);
1216         {
1217           // Note that we draw in clock-wise order to match the evaluator method
1218           for (int nu = grid; nu >= 0; nu--) {
1219             gl.glEvalCoord2f(nu / (float)grid, (nv + 1) / (float)grid);
1220             gl.glEvalCoord2f(nu / (float)grid, Math.max(nv, 1f / grid)
1221                                                          / (float)grid);
1222           }
1223         }
1224         gl.glEnd();
1225       }
1226     } else {
1227       gl.glEvalMesh2(type, 0, grid, 0, grid);
1228     }
1229   }
1230 
1231   //----------------------------------------------------------------------
1232   // Font implementation
1233   //
1234 
bitmapCharacterImpl(GL gl, int font, char cin)1235   private static void bitmapCharacterImpl(GL gl, int font, char cin) {
1236     BitmapFontRec fontinfo = getBitmapFont(font);
1237     int c = cin & 0xFFFF;
1238     if (c < fontinfo.first ||
1239         c >= fontinfo.first + fontinfo.num_chars)
1240       return;
1241     BitmapCharRec ch = fontinfo.ch[c - fontinfo.first];
1242     if (ch != null) {
1243       gl.glBitmap(ch.width, ch.height, ch.xorig, ch.yorig,
1244                   ch.advance, 0, ch.bitmap, 0);
1245     }
1246   }
1247 
1248   private static final BitmapFontRec[] bitmapFonts = new BitmapFontRec[9];
1249   private static final StrokeFontRec[] strokeFonts = new StrokeFontRec[9];
1250 
getBitmapFont(int font)1251   private static BitmapFontRec getBitmapFont(int font) {
1252     BitmapFontRec rec = bitmapFonts[font];
1253     if (rec == null) {
1254       switch (font) {
1255         case BITMAP_9_BY_15:
1256           rec = GLUTBitmap9x15.glutBitmap9By15;
1257           break;
1258         case BITMAP_8_BY_13:
1259           rec = GLUTBitmap8x13.glutBitmap8By13;
1260           break;
1261         case BITMAP_TIMES_ROMAN_10:
1262           rec = GLUTBitmapTimesRoman10.glutBitmapTimesRoman10;
1263           break;
1264         case BITMAP_TIMES_ROMAN_24:
1265           rec = GLUTBitmapTimesRoman24.glutBitmapTimesRoman24;
1266           break;
1267         case BITMAP_HELVETICA_10:
1268           rec = GLUTBitmapHelvetica10.glutBitmapHelvetica10;
1269           break;
1270         case BITMAP_HELVETICA_12:
1271           rec = GLUTBitmapHelvetica12.glutBitmapHelvetica12;
1272           break;
1273         case BITMAP_HELVETICA_18:
1274           rec = GLUTBitmapHelvetica18.glutBitmapHelvetica18;
1275           break;
1276         default:
1277           throw new GLException("Unknown bitmap font number " + font);
1278       }
1279       bitmapFonts[font] = rec;
1280     }
1281     return rec;
1282   }
1283 
getStrokeFont(int font)1284   private static StrokeFontRec getStrokeFont(int font) {
1285     StrokeFontRec rec = strokeFonts[font];
1286     if (rec == null) {
1287       switch (font) {
1288         case STROKE_ROMAN:
1289           rec = GLUTStrokeRoman.glutStrokeRoman;
1290           break;
1291         case STROKE_MONO_ROMAN:
1292           rec = GLUTStrokeMonoRoman.glutStrokeMonoRoman;
1293           break;
1294         default:
1295           throw new GLException("Unknown stroke font number " + font);
1296       }
1297     }
1298     return rec;
1299   }
1300 
beginBitmap(GL gl, int[] swapbytes, int[] lsbfirst, int[] rowlength, int[] skiprows, int[] skippixels, int[] alignment)1301   private static void beginBitmap(GL gl,
1302                                   int[] swapbytes,
1303                                   int[] lsbfirst,
1304                                   int[] rowlength,
1305                                   int[] skiprows,
1306                                   int[] skippixels,
1307                                   int[] alignment) {
1308     gl.glGetIntegerv(GL.GL_UNPACK_SWAP_BYTES, swapbytes, 0);
1309     gl.glGetIntegerv(GL.GL_UNPACK_LSB_FIRST, lsbfirst, 0);
1310     gl.glGetIntegerv(GL.GL_UNPACK_ROW_LENGTH, rowlength, 0);
1311     gl.glGetIntegerv(GL.GL_UNPACK_SKIP_ROWS, skiprows, 0);
1312     gl.glGetIntegerv(GL.GL_UNPACK_SKIP_PIXELS, skippixels, 0);
1313     gl.glGetIntegerv(GL.GL_UNPACK_ALIGNMENT, alignment, 0);
1314     /* Little endian machines (DEC Alpha for example) could
1315        benefit from setting GL_UNPACK_LSB_FIRST to GL_TRUE
1316        instead of GL_FALSE, but this would require changing the
1317        generated bitmaps too. */
1318     gl.glPixelStorei(GL.GL_UNPACK_SWAP_BYTES, GL.GL_FALSE);
1319     gl.glPixelStorei(GL.GL_UNPACK_LSB_FIRST, GL.GL_FALSE);
1320     gl.glPixelStorei(GL.GL_UNPACK_ROW_LENGTH, 0);
1321     gl.glPixelStorei(GL.GL_UNPACK_SKIP_ROWS, 0);
1322     gl.glPixelStorei(GL.GL_UNPACK_SKIP_PIXELS, 0);
1323     gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 1);
1324   }
1325 
endBitmap(GL gl, int[] swapbytes, int[] lsbfirst, int[] rowlength, int[] skiprows, int[] skippixels, int[] alignment)1326   private static void endBitmap(GL gl,
1327                                 int[] swapbytes,
1328                                 int[] lsbfirst,
1329                                 int[] rowlength,
1330                                 int[] skiprows,
1331                                 int[] skippixels,
1332                                 int[] alignment) {
1333     /* Restore saved modes. */
1334     gl.glPixelStorei(GL.GL_UNPACK_SWAP_BYTES, swapbytes[0]);
1335     gl.glPixelStorei(GL.GL_UNPACK_LSB_FIRST, lsbfirst[0]);
1336     gl.glPixelStorei(GL.GL_UNPACK_ROW_LENGTH, rowlength[0]);
1337     gl.glPixelStorei(GL.GL_UNPACK_SKIP_ROWS, skiprows[0]);
1338     gl.glPixelStorei(GL.GL_UNPACK_SKIP_PIXELS, skippixels[0]);
1339     gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, alignment[0]);
1340   }
1341 }
1342