CMSC 405 OpenGL and Java

By: Nicholas Duchon
Date: Sep 20, 2016


Outline:
My pages
Other pages


GLEW:


Mac GLUT API's and deprecation:

Setup:

A code example:


Code:

// File: Project1.java
// Date: Aug 4, 2016
// Author: Nicholas Duchon
// Purpose: reproduce Duane Jarc's C++ Project 1
//   in Java using JOGL
// Environment:
//   JDK 8
//   JOGL - jar libraries:
//      JOGL/jogamp-all-platforms/jar/gluegen-rt.jar
//      JOGL/jogamp-all-platforms/jar/jogl-all.jar
//   API:
//      https://jogamp.org/deployment/jogamp-next/javadoc/jogl/javadoc/
//      https://jogamp.org/
//   See:
//      GLUT class for predefined objects

import javax.swing.JFrame;     // hold the GUI stuff
import javax.swing.JButton;    // add a control
import javax.swing.JSplitPane; // put two JOGL panels into frame
import java.awt.BorderLayout;  // put JOGL stuff in center of screen

// ND: Your code may need to reference:
//     com.jogamp package rather than javax.media
// for example:
//  import com.jogamp.opengl.GL2;

import javax.media.opengl.awt.GLJPanel;    // ND: location of GLJPanel for java JPanel
import javax.media.opengl.GLEventListener; // make JOGL work
import javax.media.opengl.GLAutoDrawable;  // parameter for event listener interfaces
import javax.media.opengl.GL2;             // drawing graphic context

public class Project1 extends JFrame {
   public static final long serialVersionUID = 982374; // garbage value
 
   int count = 0; // button counter to test button events
   JButton jbA;   // just for fun, and an example
 
   public Project1 (String t) {
      setSize(200, 200);
      setVisible (true);
      setLocationRelativeTo (null);
      setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
     
      jbA = new JButton ("One: " + count);
      add (jbA, BorderLayout.NORTH);
      jbA.addActionListener (e -> buttonPress ());
     
      MyGLPanel mg1 = new MyGLPanel (new float [] { 1f, .5f, 1f, 0f});
      MyGLPanel mg2 = new MyGLPanel (new float [] {.5f, .5f, 1f, 0f});
     
      JSplitPane jsp = new JSplitPane (1, mg1, mg2); // 0 = -, 1 = |
      jsp.setDividerLocation (130);
      add (jsp, BorderLayout.CENTER);
     
      validate (); // show button and other stuff
  
} // end String constructor
 
   void buttonPress () {
      jbA.setText ("Count:  " + ++count);
  
} // end method buttonPress
 
   public static void main (String args []) {
      new Project1 ("JOGL Project 1");
      System.out.println ("--- Done ---");
  
} // end main
} // end class Project1

class MyGLPanel extends
   GLJPanel                    // extends javax.swing.JPanel
   implements GLEventListener  // 4 methods: init, display, reshape, dispose
{

   public static final long serialVersionUID = 23; // garbage value
   float [] bc = {0f, 1f, 1f, 0f}; // background color
  
   { addGLEventListener (this); } // instance initializer
  
   public MyGLPanel () {} // end constructor
  
   // background color constructor
   public MyGLPanel (float [] pbc) {bc = pbc;}
 
   public void init    (GLAutoDrawable d) {}
   public void reshape (GLAutoDrawable d, int x, int y, int w, int h) {}
   public void dispose (GLAutoDrawable d) {}

   public void display (GLAutoDrawable d) {
      GL2 gl = d.getGL().getGL2();
   //       drawOne (gl);
      drawTwo (gl);
  
} // end interface method display
  
   // GL_POINTS mode
   void drawTwo (GL2 gl) {
      gl.glClearColor (bc[0], bc[1], bc[2], bc[3]); // background color
      gl.glClear(javax.media.opengl.GL.GL_COLOR_BUFFER_BIT); // do this AFTER clear color
      double r1 = .2, r2 = .5, dx = .2, dy = -.2;
      double s, c;
     
      gl.glPointSize (3f);  // measured in pixels?
      gl.glBegin (GL2.GL_POINTS);
      {
         for (double d = 0; d < 2 * Math.PI; d += Math.PI / 30) {
            s = r1 * Math.sin (d); // draws ellipses,
            c = r2 * Math.cos (d);
            gl.glColor4f  (1f, 0f, 0f, 0f);  // foreground color = red
            gl.glVertex2d (s + dx, c + dy);
            gl.glColor4f  (0f, 0f, 0f, 0f);  // foreground color = black
            gl.glVertex2d (s - dx, c + dy);
            gl.glColor4f  (1f, 1f, 0f, 0f);  // foreground color = yellow
            gl.glVertex2d (s + dx, c - dy);
            gl.glColor4f  (1f, 1f, 1f, 0f);  // foreground color = white
            gl.glVertex2d (s - dx, c - dy);
         } // end for every entry in circle
      } gl.glEnd (); // end points in GL2
  
  
} // end method drawTwo
  
   // GL_TRIANGLES mode
   void drawOne (GL2 gl) {
      // three triangles:
      float[] coords = {  0  ,   0, -.5F, -.5F, .5f, -.5F
                        , .3f, .3f,  .2f,  .2f, .4f,  .2f
                        , .0f, .0f,   4f,   0f, 4f,   -4f
                       };
      gl.glClearColor (bc[0], bc[1], bc[2], bc[3]); // background color
      gl.glClear(javax.media.opengl.GL.GL_COLOR_BUFFER_BIT); // do this AFTER clear color
  
      gl.glBegin(GL2.GL_TRIANGLES); // solid triangle
      {
         // first triangle, vertex colors blended
         gl.glColor4f    (1f, 0f, 0f, 0f);  // foreground color = red
         gl.glVertex2fv(coords, 0);         // first vertex data starts at index 0
         gl.glColor4f    (0f, 0f, 1f, 0f);  // foreground color = blue
         gl.glVertex2fv(coords, 2);         // second vertex data starts at index 2
         gl.glColor4f    (1f, 1f, 0f, 0f);  // foreground color = yellow
         gl.glVertex2fv(coords, 4);         // third vertex data starts at index 4
     
         // second triangle - yellow
         gl.glColor4f    (1f, 1f, 0f, 0f);  // foreground color = yellow
         gl.glVertex2fv(coords, 6);         // 3 vertices, start locations 6,8,10
         gl.glVertex2fv(coords, 8);         //
         gl.glVertex2fv(coords, 10);        //
     
         // third triangle - yellow, oversized
         gl.glColor4f  (0f, 1f, 0f, 0f);     // foreground color = green
         gl.glVertex2fv(coords, 12);         // 3 vertices, start locations 6,8,10
         gl.glVertex2fv(coords, 14);         //
         gl.glVertex2fv(coords, 16);         //
     
      } gl.glEnd(); 
     
      gl.glTranslated (-.5, .2, 0);
      gl.glRectd (0, 0, .2, .2);
      gl.glTranslated (.5, -.2, 0);
  
   } // end method drawOne

} // end class MyGLPanel

// Primitives, as in, modes of glBegin:
//   gl.glBegin (GL2.<primitive>);
// GL_POINTS
// GL_LINES
// GL_LINE_STRIP
// GL_LINE_LOOP
// GL_TRIANGLES
// GL_TRIANGLE_FAN
// GL_POLYGON

// figure methods in GL2
//  

// import com.jogamp.opengl.util;
// import javax.media.opengl.GLCapabilities;  // setup in parent class?
// import javax.media.opengl.GLProfile;       // more setup?
// import javax.media.opengl.awt.GLCanvas;        // ??

// ------- GLEventListener: INTERFACE methods -------//
//   public void init    (GLAutoDrawable d) {}
//   public void display (GLAutoDrawable d) {}
//   public void reshape (GLAutoDrawable d, int x, int y, int w, int h) {}
//   public void dispose (GLAutoDrawable d) {}

// GLCanvas // ND: Canvas and JPanel seem to work about the same way

//         gl.glClear(javax.media.opengl.GL.GL_DEPTH_BUFFER_BIT);
//         gl.glLoadIdentity();

//    public void init    (GLAutoDrawable d) {
//       GL2 gl = d.getGL().getGL2();
//         gl.glShadeModel(javax.media.opengl.fixedfunc.GLLightingFunc.GL_SMOOTH);
//         gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
//         gl.glClearDepth(1.0f);
//         gl.glEnable(javax.media.opengl.GL.GL_DEPTH_TEST);
//         gl.glDepthFunc(javax.media.opengl.GL.GL_LEQUAL);
//         gl.glHint(javax.media.opengl.GL2ES1.GL_PERSPECTIVE_CORRECTION_HINT,
//               javax.media.opengl.GL.GL_NICEST);
//    } // end init from JOGLQuad.java - none of this is required for a simple triangle

   //       setupJOGL ();

   /**
    * Create the basics of the JOGL screen details.
    */
//    private void setupJOGL()
//    {
//    //         GLCapabilities caps = new GLCapabilities();
//       GLCapabilities caps = new GLCapabilities(GLProfile.getDefault()); // ND:
//       caps.setDoubleBuffered(true);
//       caps.setHardwareAccelerated(true);
//   
//       canvas = new GLCanvas(caps);
//       canvas.addGLEventListener(this);
//   
//       add(canvas, BorderLayout.CENTER);
//   
//       Animator anim = new Animator(canvas);
//       anim.start();
//    }



glutBitmapString

The code needed on a Mac to implement this call:

void glutBitmapString (void * fontID, const char * string) {
    for(int c = 0; c < strlen( ( char * )string ); c++ )
        glutBitmapCharacter(fontID, string[c]);
} // end local method from freeGLUT

// Sample call:
  const char * x = "this is a test";
  glutBitmapString (GLUT_BITMAP_HELVETICA_12, x);


Second Example:


Summary:

Code:

// File: Project1.java
// Date: Aug 4, 2016; Jun 12, 2018
// Author: Nicholas Duchon
// Purpose: reproduce Duane Jarc's C++ Project 1
//   in Java using JOGL
//   now experimenting with JOGL issues
// Environment:
//   JDK 8
//   JOGL - jar libraries:
//      JOGL/jogamp-all-platforms/jar/gluegen-rt.jar
//      JOGL/jogamp-all-platforms/jar/jogl-all.jar
//   API:
//      https://jogamp.org/deployment/jogamp-next/javadoc/jogl/javadoc/
//      https://jogamp.org/
//   See:
//      GLUT class for predefined objects
// Update Jun 12, 2018:
//    created MyGLUT class to color the faces of the dodecahedron

import javax.swing.JFrame;     // hold the GUI stuff
import javax.swing.JButton;    // add a control
import javax.swing.JSplitPane; // put two JOGL panels into frame
import java.awt.BorderLayout;  // put JOGL stuff in center of screen
import java.awt.Font;
import java.util.Random;

// ND: Your code may need to reference - careful, some classes in one package, some in the other
//     com.jogamp
//     javax.media

//   documentation differentiates javax.media stuff from com.jogamp stuff!
//          see the documentation link:
//        >>>> https://jogamp.org/deployment/v2.1.0/javadoc/jogl/javadoc/index.html

// The following worked in my installation of JOGL

import javax.media.opengl.awt.GLJPanel;    // ND: location of GLJPanel for java JPanel
import javax.media.opengl.GLEventListener; // make JOGL work
import javax.media.opengl.GLAutoDrawable;  // parameter for event listener interfaces
import javax.media.opengl.GL2;             // drawing graphic context
import javax.media.opengl.GL;

import com.jogamp.opengl.util.awt.TextRenderer;  // Fancy text using fonts and integer font locations
import com.jogamp.opengl.util.gl2.GLUT;          // plain text using double font locations.

public class Project1 extends JFrame {
   public static final long serialVersionUID = 982374; // garbage value
 
   int count = 0; // button counter to test button events
 
   public Project1 (String t) {
      setSize(1300, 300);
      setTitle (t);
      setVisible (true);
      setLocationRelativeTo (null);
      setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
    
      // just for fun, and an example
      JButton jbA = new JButton ("One: " + count);
      add (jbA, BorderLayout.NORTH);
      jbA.addActionListener (e -> jbA.setText ("Count:  " + ++count));
    
      MyGLPanel mg1 = new MyGLPanel (1, new float [] { 1f, .5f,  1f, 0f});
      MyGLPanel mg2 = new MyGLPanel (2, new float [] {.5f, .5f,  1f, 0f});
      MyGLPanel mg3 = new MyGLPanel (3, new float [] { 1f,  1f,  0f, 0f});
      MyGLPanel mg4 = new MyGLPanel (4, new float [] { 1f, .5f, .5f, 0f});
      MyGLPanel mg5 = new MyGLPanel (5, new float [] { 1f,  1f,  1f, 0f});
    
      JSplitPane jsp1 = new JSplitPane (1,  mg1, mg2); // 0 = -, 1 = |
      jsp1.setDividerLocation (200);
      JSplitPane jsp2 = new JSplitPane (1, jsp1, mg3); // 0 = -, 1 = |
      jsp2.setDividerLocation (400);
      JSplitPane jsp3 = new JSplitPane (1, jsp2, mg4); // 0 = -, 1 = |
      jsp3.setDividerLocation (800);
      JSplitPane jsp4 = new JSplitPane (1, jsp3, mg5); // 0 = -, 1 = |
      jsp4.setDividerLocation (1000);
      add (jsp4, BorderLayout.CENTER);
    
      validate ();
    
   } // end String constructor
 
   public static void main (String args []) {
      new Project1 ("JOGL Project 1");
      System.out.println ("--- Done ---");
   } // end main
} // end class Project1

class MyGLPanel extends
   GLJPanel                    // extends javax.swing.JPanel
   implements GLEventListener  // 4 methods: init, display, reshape, dispose
{

   public static final long serialVersionUID = 23; // garbage value
   float [] bc = {0f, 1f, 1f, 0f}; // background color
   int type = 0; // select what is displayed on this panel, see display method below
 
   { addGLEventListener (this); } // instance initializer
 
   public MyGLPanel () {} // end constructor
 
   // background color constructor
   public MyGLPanel (int t, float [] pbc) {type = t; bc = pbc;}
 
   public void init    (GLAutoDrawable d) {
           // called when the panel is created
      if (type == 5) { // 3d drawing panel
         GL2 gl = d.getGL().getGL2();
         gl.glClearColor(0.8F, 0.8F, 0.8F, 1.0F);
         gl.glEnable(GL.GL_DEPTH_TEST);
         gl.glEnable(GL2.GL_LIGHTING);
         gl.glEnable(GL2.GL_LIGHT0);
         gl.glEnable(GL2.GL_COLOR_MATERIAL);
      } // end if type = 5
   } // end interface method init

   public void reshape (GLAutoDrawable d, int x, int y, int w, int h) {}
   public void dispose (GLAutoDrawable d) {}

   public void display (GLAutoDrawable d) {
      GL2 gl = d.getGL().getGL2();
      switch (type) {
         case 1: drawOne   (gl);
            break;
         case 2: drawTwo   (gl);
            break;
         case 3: drawThree (d);
            break;
         case 4: drawFour  (d);
            break;
         case 5: drawFive  (d);
            break;
      } // end switch type
   } // end interface method display
 
   // GL_TRIANGLES mode
   void drawOne (GL2 gl) {
      // three triangles:
      float[] coords = {  0  ,   0, -.5F, -.5F, .5f, -.5F
                        , .3f, .3f,  .2f,  .2f, .4f,  .2f
                        , .0f, .0f,   4f,   0f, 4f,   -4f
                       };
      int dim   =    2; // dimension, coordinates per point
      int index = -dim; // walk through coordinates, always index += dim
  
      gl.glClearColor (bc[0], bc[1], bc[2], bc[3]);          // background color
      gl.glClear(GL.GL_COLOR_BUFFER_BIT); // do this AFTER clear color
  
      gl.glBegin(GL2.GL_TRIANGLES); // solid triangle
      {
         // first triangle, vertex colors blended
         gl.glColor4f    (1f, 0f, 0f, 0f);     // foreground color = red
         gl.glVertex2fv(coords, index += dim); // first vertex data starts at index 0
         gl.glColor4f    (0f, 0f, 1f, 0f);     // foreground color = blue
         gl.glVertex2fv(coords, index += dim); // second vertex data starts at index 2
         gl.glColor4f    (1f, 1f, 0f, 0f);     // foreground color = yellow
         gl.glVertex2fv(coords, index += dim); // third vertex data starts at index 4
     
         // second triangle - yellow
         gl.glColor4f    (1f, 1f, 0f, 0f);     // foreground color = yellow
         gl.glVertex2fv(coords, index += dim); // 3 vertices, start locations 6,8,10
         gl.glVertex2fv(coords, index += dim); //
         gl.glVertex2fv(coords, index += dim); //
     
         // third triangle - green, oversized
         gl.glColor4f  (0f, 1f, 0f, 0f);       // foreground color = green
         gl.glVertex2fv(coords, index += dim); // 3 vertices, start locations 12, 14, 16
         gl.glVertex2fv(coords, index += dim); //
         gl.glVertex2fv(coords, index += dim); //
     
      } gl.glEnd();
    
      gl.glTranslated (-.5, .2, 0);
      gl.glRectd (0, 0, .2, .2);
      gl.glTranslated (.5, -.2, 0); // Untranslate, otherwise translates chain
  
   } // end method drawOne

   // GL_POINTS mode
   void drawTwo (GL2 gl) {
      gl.glClearColor (bc[0], bc[1], bc[2], bc[3]); // background color
      gl.glClear(GL.GL_COLOR_BUFFER_BIT); // do this AFTER clear color
  
      double r1 = .5, r2 = .2, xOffset = .2, yOffset = -.2;
      double dx, dy;
      int steps = 50;
    
      gl.glPointSize (3f);  // measured in pixels?
      gl.glBegin (GL2.GL_POINTS);
      {
         for (double d = 0; d < 2 * Math.PI; d += Math.PI / steps) {
            dx = r1 * Math.sin (d); // draws ellipses,
            dy = r2 * Math.cos (d);
            gl.glColor4f  (1f, 0f, 0f, 0f);  // foreground color = red
            gl.glVertex2d (dx + xOffset, dy + yOffset);
            gl.glColor4f  (0f, 0f, 0f, 0f);  // foreground color = black
            gl.glVertex2d (dx - xOffset, dy + yOffset);
            gl.glColor4f  (1f, 1f, 0f, 0f);  // foreground color = yellow
            gl.glVertex2d (dx + xOffset, dy - yOffset);
            gl.glColor4f  (1f, 1f, 1f, 0f);  // foreground color = white
            gl.glVertex2d (dx - xOffset, dy - yOffset);
         } // end for every entry in circle
      } gl.glEnd (); // end points in GL2
  
   } // end method drawTwo
 
   // rendering text: drawing a string
   void drawThree (GLAutoDrawable d) {
      TextRenderer renderer;
      GL2 gl = d.getGL().getGL2();
      int xp, yp;
  
      gl.glClearColor (bc[0], bc[1], bc[2], bc[3]); // background color
      gl.glClear(GL.GL_COLOR_BUFFER_BIT); // do this AFTER clear color
    
   //       renderer = new TextRenderer(new java.awt.Font("SansSerif", java.awt.Font.BOLD, 20));
   //       renderer = new TextRenderer(new java.awt.Font("Luminari", java.awt.Font.BOLD, 36));
    
      xp = 10; yp = 20;
      renderer = new TextRenderer(new Font("Phosphate", Font.BOLD, 36));
      renderer.beginRendering(d.getWidth(), d.getHeight());
      {
         renderer.setColor(1.0f, 0.2f, 0.2f, 0.8f);
         renderer.draw("Pos: (" + xp + "," + yp + ")", xp, yp);
         xp += 10; yp += 30;
         renderer.draw("Pos: (" + xp + "," + yp + ")", xp, yp);
         xp = 50; yp += 30;
         renderer.draw("Pos: (" + xp + "," + yp + ")", xp, yp);
      } renderer.endRendering();
    
      xp = 30; yp = 150;
      renderer = new TextRenderer(new Font("Luminari", Font.BOLD, 36));
      renderer.beginRendering(d.getWidth(), d.getHeight());
      {
         renderer.setColor(1.0f, 0.2f, 0.2f, 0.8f);
         renderer.draw("Pos: (" + xp + "," + yp + ")", xp, yp);
         xp = 150; yp += 50;
         renderer.draw("Pos: (" + xp + "," + yp + ")", xp, yp);
      } renderer.endRendering();
  
    
      gl.glColor4f  (0f, 0f, 1f, 0f);  // foreground color = green
      GLUT glut = new GLUT ();
  
      gl.glRasterPos2d (0, 0); // Apparently 2i just fails
   //       gl.glRasterPos2i (10,10); // Apparently 2i just fails
      glut.glutBitmapString (GLUT.BITMAP_9_BY_15, "Center");
  
      gl.glRasterPos2d (-.9, .8);
      glut.glutBitmapString (GLUT.BITMAP_9_BY_15, "Pos: (-.2,.3)");
  
      gl.glRasterPos2d (.2, -.8);
      glut.glutBitmapString (GLUT.BITMAP_TIMES_ROMAN_24, "Pos: (.2,.5)");
  
      gl.glRasterPos2d (0, 0); // reset raster position, otherwise following stuff messed up    
  
   } // end method drawThree
 
   // rendering text: drawing a string
   // draw a random noise bit map
   void drawFour (GLAutoDrawable d) {
      GL2 gl = d.getGL().getGL2();
      Random rn = new Random ();
  
      gl.glClearColor (bc[0], bc[1], bc[2], bc[3]); // background color
      gl.glClear(GL.GL_COLOR_BUFFER_BIT); // do this AFTER clear color
          
      gl.glColor4f  (1f, 1f, 1f, 0f);  // foreground color = white
  
      GLUT glut = new GLUT ();
      gl.glRasterPos2d (-.97, .8);
      glut.glutBitmapString (GLUT.BITMAP_9_BY_15, "DrawFour Center");
      gl.glRasterPos2d (-.97, .9);
      glut.glutBitmapString (GLUT.BITMAP_9_BY_15, "Random Noise Bit Map");
  
      // random noise bit map
      int rows = 64, cols = 128;
      byte [] bm = new byte [rows*cols];
      rn.nextBytes (bm); // new radom thing every time resize or display event called
  
      gl.glColor4f  (0f, 0f, 1f, 0f);  // foreground color = blue
      gl.glRasterPos2d (-.8, -.5);
      gl.glBitmap (cols, rows, 0f, 0f, 0f, 0f, bm, 0);
      gl.glRasterPos2d (0, 0); // reset raster position, otherwise following stuff messed up    
  
   } // end method drawFour
 
   // drawing dodecNDahedrons
   void drawFive (GLAutoDrawable d) {
      GL2 gl = d.getGL().getGL2();
      int xr = 90, yr = 45, zr = 0;
  
      gl.glClearColor (bc[0], bc[1], bc[2], bc[3]); // background color
      gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT ); // do this AFTER clear color
    
      MyGLUT glut = new MyGLUT ();
  
   //       gl.glColor4f  (0f, 0f, 1f, 0f);  // foreground color = white
   //       gl.glColor3d (1, 0, 0);
      gl.glMatrixMode(GL2.GL_PROJECTION);  //
      gl.glLoadIdentity();
      int dim = 16;
      gl.glOrtho(-dim,  dim, -dim,  dim, -dim,  dim);      // parameters are doubles
      gl.glMatrixMode(GL2.GL_MODELVIEW);
  
      xr = 0;
      double xa = -14, yas = 14, ya;
      for (int i = 0; i < 8; i++) {
         yr = 0; ya = yas;
         for (int j = 0; j < 8; j++) {
            gl.glLoadIdentity();             // Set up modelview transform.
            gl.glTranslated (xa, ya, 0);
            gl.glRotated(xr,1,0,0);
            gl.glRotated(yr,0,1,0);
            gl.glRotated(0,0,0,1);
         //             glut.glutWireDodecahedron (gl);
            glut.glutSolidDodecahedron (gl);
            yr += 45;
            ya -= 4;
         } // end for y values
         xr += 45;
         xa += 4;
      } // end for x values
  
   } // end method drawFive
 

} // end class MyGLPanel

// See the following page for original source code for GLUT
// http://book2s.com/java/src/package/com/jogamp/opengl/util/gl2/glut.html
// See the following page for a list of the colors I used:
// https://sashat.me/2017/01/11/list-of-20-simple-distinct-colors/
// for some reason glColor3i does not seem to be working for me, so:
//  /255. is a way to convert int's to double's and use glColor3d

class MyGLUT extends GLUT {
// having dodecND null is a way to make sure init only called once in display method
   float[][] dodecND;
  
   static float alpha = (float) Math.sqrt(2.0f / (3.0f + Math.sqrt(5.0)));
   static float beta = 1.0f + (float) Math.sqrt(6.0 / (3.0 + Math.sqrt(5.0)) - 2.0
                + 2.0 * Math.sqrt(2.0 / (3.0 + Math.sqrt(5.0))));

   public void glutWireDodecahedron(GL2 gl) {
      dodecahedron(gl, GL.GL_LINE_LOOP);
   } // end method glutWireDodecahedron

   public void glutSolidDodecahedron(GL2 gl) {
      dodecahedron(gl, GL.GL_TRIANGLE_FAN);
   } // end method glutSolidDodecahedron

   void initDodecahedron() {
      dodecND = new float[20][3];
  
      dodecND[0][0] = -alpha;
      dodecND[0][1] = 0;
      dodecND[0][2] = beta;
      dodecND[1][0] = alpha;
      dodecND[1][1] = 0;
      dodecND[1][2] = beta;
      dodecND[2][0] = -1;
      dodecND[2][1] = -1;
      dodecND[2][2] = -1;
      dodecND[3][0] = -1;
      dodecND[3][1] = -1;
      dodecND[3][2] = 1;
      dodecND[4][0] = -1;
      dodecND[4][1] = 1;
      dodecND[4][2] = -1;
      dodecND[5][0] = -1;
      dodecND[5][1] = 1;
      dodecND[5][2] = 1;
      dodecND[6][0] = 1;
      dodecND[6][1] = -1;
      dodecND[6][2] = -1;
      dodecND[7][0] = 1;
      dodecND[7][1] = -1;
      dodecND[7][2] = 1;
      dodecND[8][0] = 1;
      dodecND[8][1] = 1;
      dodecND[8][2] = -1;
      dodecND[9][0] = 1;
      dodecND[9][1] = 1;
      dodecND[9][2] = 1;
      dodecND[10][0] = beta;
      dodecND[10][1] = alpha;
      dodecND[10][2] = 0;
      dodecND[11][0] = beta;
      dodecND[11][1] = -alpha;
      dodecND[11][2] = 0;
      dodecND[12][0] = -beta;
      dodecND[12][1] = alpha;
      dodecND[12][2] = 0;
      dodecND[13][0] = -beta;
      dodecND[13][1] = -alpha;
      dodecND[13][2] = 0;
      dodecND[14][0] = -alpha;
      dodecND[14][1] = 0;
      dodecND[14][2] = -beta;
      dodecND[15][0] = alpha;
      dodecND[15][1] = 0;
      dodecND[15][2] = -beta;
      dodecND[16][0] = 0;
      dodecND[16][1] = beta;
      dodecND[16][2] = alpha;
      dodecND[17][0] = 0;
      dodecND[17][1] = beta;
      dodecND[17][2] = -alpha;
      dodecND[18][0] = 0;
      dodecND[18][1] = -beta;
      dodecND[18][2] = alpha;
      dodecND[19][0] = 0;
      dodecND[19][1] = -beta;
      dodecND[19][2] = -alpha;
   } // end method initDodecahedron
  
   static void diff3(final float[] a, final float[] b,
            final float[] c) {

      c[0] = a[0] - b[0];
      c[1] = a[1] - b[1];
      c[2] = a[2] - b[2];
   } // end method diff3

   static void crossprod(final float[] v1, final float[] v2,
            final float[] prod) {

      final float[] p = new float[3]; /* in case prod == v1 or v2 */
  
      p[0] = v1[1] * v2[2] - v2[1] * v1[2];
      p[1] = v1[2] * v2[0] - v2[2] * v1[0];
      p[2] = v1[0] * v2[1] - v2[0] * v1[1];
      prod[0] = p[0];
      prod[1] = p[1];
      prod[2] = p[2];
   } // end method crossprod

   static void normalize(final float[] v) {
      float d;
  
      d = (float) Math.sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
      if (d == 0.0) {
         v[0] = d = 1.0f;
      }
      d = 1 / d;
      v[0] *= d;
      v[1] *= d;
      v[2] *= d;
   } // end method normalize
  
   void pentagon(final GL2 gl, final int a, final int b,
            final int c, final int d, final int e, final int shadeType) {

      final float[] n0 = new float[3];
      final float[] d1 = new float[3];
      final float[] d2 = new float[3];
  
      diff3(dodecND[a], dodecND[b], d1);
      diff3(dodecND[b], dodecND[c], d2);
      crossprod(d1, d2, n0);
      normalize(n0);
  
      gl.glBegin(shadeType);
      gl.glNormal3fv(n0, 0);
      gl.glVertex3fv(dodecND[a], 0);
      gl.glVertex3fv(dodecND[b], 0);
      gl.glVertex3fv(dodecND[c], 0);
      gl.glVertex3fv(dodecND[d], 0);
      gl.glVertex3fv(dodecND[e], 0);
      gl.glEnd();
   } // end method pentagon
  
   void dodecahedron(final GL2 gl, final int type) {
      if (dodecND == null) {
         initDodecahedron();
      }
      gl.glColor3d (230/255., 25/255., 75/255.);
      pentagon(gl, 0, 1, 9, 16, 5, type);
      gl.glColor3d (60/255., 180/255., 75/255.);
      pentagon(gl, 1, 0, 3, 18, 7, type);
      gl.glColor3d (255/255., 225/255., 25/255.);
      pentagon(gl, 1, 7, 11, 10, 9, type);
      gl.glColor3d (0/255., 130/255., 200/255.);
      pentagon(gl, 11, 7, 18, 19, 6, type);
      gl.glColor3d (245/255., 130/255., 48/255.);
      pentagon(gl, 8, 17, 16, 9, 10, type);
      gl.glColor3d (145/255., 30/255., 180/255.)    ;
      pentagon(gl, 2, 14, 15, 6, 19, type);
      gl.glColor3d (70/255., 240/255., 240/255.);
      pentagon(gl, 2, 13, 12, 4, 14, type);
      gl.glColor3d (240/255., 50/255., 230/255.)    ;
      pentagon(gl, 2, 19, 18, 3, 13, type);
      gl.glColor3d (210/255., 245/255., 60/255.)    ;
      pentagon(gl, 3, 0, 5, 12, 13, type);
      gl.glColor3d (250/255., 190/255., 190/255.)    ;
      pentagon(gl, 6, 15, 8, 10, 11, type);
      gl.glColor3d (0/255., 128/255., 128/255.)    ;
      pentagon(gl, 4, 17, 8, 15, 14, type);
      gl.glColor3d (230/255., 190/255., 255/255.)    ;
      pentagon(gl, 4, 12, 5, 16, 17, type);
   } // end method dodecahedron
  
} // end class MyGLUT


(end)