/** * @(#) gears.java * @(#) author: Brian Paul (converted to Java by Ron Cemer) * * This is a modification of the standard gears demo so that it * uses the Virutal Sphere for converting mouse input to 3D * rotation. --- Joe Huwaldt, Feburary 20, 2001 * */ import java.applet.*; import java.awt.*; import java.awt.event.*; import java.lang.*; import java.util.*; import java.io.*; import java.util.*; import gl4java.*; import gl4java.drawable.*; import gl4java.awt.GLAnimCanvas; import gl4java.applet.SimpleGLAnimApplet1; import jahuwaldt.gl.*; /** * A version of the standard "gears" OpenGL demo * modified to use the Virtual Sphere algorithm for * converting 2D mouse movement into 3D model rotation. **/ public class GearsVS extends SimpleGLAnimApplet1 { /* Initialize the applet */ public void init() { super.init(); Dimension d = getSize(); GLCapabilities caps = new GLCapabilities(); //caps.setDoubleBuffered(false); canvas = GLDrawableFactory.getFactory().createGLAnimCanvas(caps, d.width, d.height); GearsVSRenderer gear = new GearsVSRenderer(true); canvas.addGLEventListener(gear); add("Center", canvas); } public static void main( String args[] ) { GLContext.gljNativeDebug = true; GLContext.gljClassDebug = true; Frame mainFrame = new Frame("Gears with Virtual Sphere"); mainFrame.addWindowListener( new WindowAdapter() { public void windowClosed(WindowEvent e) { System.exit(0); } public void windowClosing(WindowEvent e) { System.exit(0); } } ); Applet applet = new GearsVS(); mainFrame.add(applet); applet.setSize(400, 500); applet.init(); applet.start(); Dimension ps = applet.getPreferredSize(); mainFrame.setBounds(-100,-100,99,99); mainFrame.setVisible(true); mainFrame.setVisible(false); mainFrame.setVisible(true); Insets is = mainFrame.getInsets(); mainFrame.setBounds(0,0, ps.width+is.left+is.right, ps.height+is.top+is.bottom); mainFrame.setVisible(true); } private class GearsVSRenderer implements GLEventListener, MouseListener, MouseMotionListener { private static final float M_PI = 3.14159265359f; private int gear1, gear2, gear3; private float angle = 0.0f; private boolean showGL = false; private Point prevMouse; private boolean mouseRButtonDown = false; private float rot_matrix[] = Matrix.identity(); // Class variables required to implement the virtual sphere. private VirtualSphere vs = new VirtualSphere(); private Point cueCenter = new Point(); private int cueRadius; private boolean mouseDown = false; private GLFunc gl; private GLUFunc glu; private GLContext glj; Graphics gc = null; public GearsVSRenderer(boolean showGL) { this.showGL=showGL; } public void init(GLDrawable drawable) { gl = drawable.getGL(); glu = drawable.getGLU(); glj = drawable.getGLContext(); GLAnimCanvas cvs = (GLAnimCanvas)drawable; Dimension size = cvs.getSize(); setupVS(size.width, size.height); setInitialRotation(); float pos[] = { 5.0f, 5.0f, 10.0f, 0.0f }; float red[] = { 0.8f, 0.1f, 0.0f, 1.0f }; float green[] = { 0.0f, 0.8f, 0.2f, 1.0f }; float blue[] = { 0.2f, 0.2f, 1.0f, 1.0f }; gl.glClearColor(0f, 0f, 0f, 0f); gl.glLightfv(GL_LIGHT0, GL_POSITION, pos); gl.glEnable(GL_CULL_FACE); gl.glEnable(GL_LIGHTING); gl.glEnable(GL_LIGHT0); gl.glEnable(GL_DEPTH_TEST); /* make the gears */ gear1 = gl.glGenLists(1); gl.glNewList(gear1, GL_COMPILE); gl.glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red); gear(1.0f, 4.0f, 1.0f, 20, 0.7f); gl.glEndList(); gear2 = gl.glGenLists(1); gl.glNewList(gear2, GL_COMPILE); gl.glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green); gear(0.5f, 2.0f, 2.0f, 10, 0.7f); gl.glEndList(); gear3 = gl.glGenLists(1); gl.glNewList(gear3, GL_COMPILE); gl.glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, blue); gear(1.3f, 2.0f, 0.5f, 10, 0.7f); gl.glEndList(); gl.glEnable(GL_NORMALIZE); glj.gljCheckGL(); drawable.addMouseListener(this); drawable.addMouseMotionListener(this); System.out.println("init .."); } public void cleanup(GLDrawable drawable) { System.out.println("destroy(): " + this); drawable.removeMouseListener(this); drawable.removeMouseMotionListener(this); } public void reshape(gl4java.drawable.GLDrawable gld, int width, int height) { float h = (float)height / (float)width; gl.glViewport(0,0,width,height); gl.glMatrixMode(GL_PROJECTION); gl.glLoadIdentity(); gl.glFrustum(-1.0f, 1.0f, -h, h, 5.0f, 60.0f); gl.glMatrixMode(GL_MODELVIEW); gl.glLoadIdentity(); gl.glTranslatef(0.0f, 0.0f, -40.0f); // Resize the virtual sphere too! setupVS(width, height); } public void preDisplay(GLDrawable drawable) { } public void display(GLDrawable drawable) { if(showGL) { showGL=false; System.out.println("GL VERSION : "+gl.glGetString(GL_VERSION)); System.out.println("GL RENDERER: "+gl.glGetString(GL_RENDERER)); System.out.println("GL VENDOR : "+gl.glGetString(GL_VENDOR)); } angle += 0.5f; gl.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); gl.glPushMatrix(); gl.glMultMatrixf(rot_matrix); gl.glPushMatrix(); gl.glTranslatef(-3.0f, -2.0f, 0.0f); gl.glRotatef(angle, 0.0f, 0.0f, 1.0f); gl.glCallList(gear1); gl.glPopMatrix(); gl.glPushMatrix(); gl.glTranslatef(3.1f, -2.0f, 0.0f); gl.glRotatef(-2.0f * angle - 9.0f, 0.0f, 0.0f, 1.0f); gl.glCallList(gear2); gl.glPopMatrix(); gl.glPushMatrix(); gl.glTranslatef(-3.1f, 4.2f, 0.0f); gl.glRotatef(-2.0f * angle - 25.0f, 0.0f, 0.0f, 1.0f); gl.glCallList(gear3); gl.glPopMatrix(); gl.glPopMatrix(); } public void postDisplay(GLDrawable drawable) { // If the mouse is down, draw the virtual sphere 2D representation. if (mouseDown) drawVS(drawable); } /** * Set up the virtual sphere cue center and radius. **/ private void setupVS(int w, int h) { cueCenter.x = w/2; cueCenter.y = h/2; cueRadius = Math.min(w-20, h-20)/2; } /** * Render a 2D representation of the virtual sphere * to give the user some visual feedback. **/ private void drawVS(GLDrawable drawable) { GLAnimCanvas cvs = (GLAnimCanvas)drawable; if(gc==null) gc = cvs.getGraphics(); Color saveColor = gc.getColor(); gc.setColor(Color.gray); vs.draw(gc, prevMouse, cueCenter, cueRadius); gc.setColor(saveColor); } private void gear (float inner_radius, float outer_radius, float width, int teeth, float tooth_depth) { int i; float r0, r1, r2; float angle, da; float u, v, len; r0 = inner_radius; r1 = outer_radius - tooth_depth / 2.0f; r2 = outer_radius + tooth_depth / 2.0f; da = 2.0f * M_PI / teeth / 4.0f; gl.glShadeModel(GL_FLAT); gl.glNormal3f(0.0f, 0.0f, 1.0f); /* draw front face */ gl.glBegin(GL_QUAD_STRIP); for (i = 0; i <= teeth; i++) { angle = i * 2.0f * M_PI / teeth; gl.glVertex3f(r0 * (float)Math.cos(angle), r0 * (float)Math.sin(angle), width * 0.5f); gl.glVertex3f(r1 * (float)Math.cos(angle), r1 * (float)Math.sin(angle), width * 0.5f); gl.glVertex3f(r0 * (float)Math.cos(angle), r0 * (float)Math.sin(angle), width * 0.5f); gl.glVertex3f(r1 * (float)Math.cos(angle + 3.0f * da), r1 * (float)Math.sin(angle + 3.0f * da), width * 0.5f); } gl.glEnd(); /* draw front sides of teeth */ gl.glBegin(GL_QUADS); da = 2.0f * M_PI / teeth / 4.0f; for (i = 0; i < teeth; i++) { angle = i * 2.0f * M_PI / teeth; gl.glVertex3f(r1 * (float)Math.cos(angle), r1 * (float)Math.sin(angle), width * 0.5f); gl.glVertex3f(r2 * (float)Math.cos(angle + da), r2 * (float)Math.sin(angle + da), width * 0.5f); gl.glVertex3f(r2 * (float)Math.cos(angle + 2.0f * da), r2 * (float)Math.sin(angle + 2.0f * da), width * 0.5f); gl.glVertex3f(r1 * (float)Math.cos(angle + 3.0f * da), r1 * (float)Math.sin(angle + 3.0f * da), width * 0.5f); } gl.glEnd(); gl.glNormal3f(0.0f, 0.0f, -1.0f); /* draw back face */ gl.glBegin(GL_QUAD_STRIP); for (i = 0; i <= teeth; i++) { angle = i * 2.0f * M_PI / teeth; gl.glVertex3f(r1 * (float)Math.cos(angle), r1 * (float)Math.sin(angle), -width * 0.5f); gl.glVertex3f(r0 * (float)Math.cos(angle), r0 * (float)Math.sin(angle), -width * 0.5f); gl.glVertex3f(r1 * (float)Math.cos(angle + 3 * da), r1 * (float)Math.sin(angle + 3 * da), -width * 0.5f); gl.glVertex3f(r0 * (float)Math.cos(angle), r0 * (float)Math.sin(angle), -width * 0.5f); } gl.glEnd(); /* draw back sides of teeth */ gl.glBegin(GL_QUADS); da = 2.0f * M_PI / teeth / 4.0f; for (i = 0; i < teeth; i++) { angle = i * 2.0f * M_PI / teeth; gl.glVertex3f(r1 * (float)Math.cos(angle + 3 * da), r1 * (float)Math.sin(angle + 3 * da), -width * 0.5f); gl.glVertex3f(r2 * (float)Math.cos(angle + 2 * da), r2 * (float)Math.sin(angle + 2 * da), -width * 0.5f); gl.glVertex3f(r2 * (float)Math.cos(angle + da), r2 * (float)Math.sin(angle + da), -width * 0.5f); gl.glVertex3f(r1 * (float)Math.cos(angle), r1 * (float)Math.sin(angle), -width * 0.5f); } gl.glEnd(); /* draw outward faces of teeth */ gl.glBegin(GL_QUAD_STRIP); for (i = 0; i < teeth; i++) { angle = i * 2.0f * M_PI / teeth; gl.glVertex3f(r1 * (float)Math.cos(angle), r1 * (float)Math.sin(angle), width * 0.5f); gl.glVertex3f(r1 * (float)Math.cos(angle), r1 * (float)Math.sin(angle), -width * 0.5f); u = r2 * (float)Math.cos(angle + da) - r1 * (float)Math.cos(angle); v = r2 * (float)Math.sin(angle + da) - r1 * (float)Math.sin(angle); len = (float)Math.sqrt(u * u + v * v); u /= len; v /= len; gl.glNormal3f(v, -u, 0.0f); gl.glVertex3f(r2 * (float)Math.cos(angle + da), r2 * (float)Math.sin(angle + da), width * 0.5f); gl.glVertex3f(r2 * (float)Math.cos(angle + da), r2 * (float)Math.sin(angle + da), -width * 0.5f); gl.glNormal3f((float)Math.cos(angle), (float)Math.sin(angle), 0.0f); gl.glVertex3f(r2 * (float)Math.cos(angle + 2 * da), r2 * (float)Math.sin(angle + 2 * da), width * 0.5f); gl.glVertex3f(r2 * (float)Math.cos(angle + 2 * da), r2 * (float)Math.sin(angle + 2 * da), -width * 0.5f); u = r1 * (float)Math.cos(angle + 3 * da) - r2 * (float)Math.cos(angle + 2 * da); v = r1 * (float)Math.sin(angle + 3 * da) - r2 * (float)Math.sin(angle + 2 * da); gl.glNormal3f(v, -u, 0.0f); gl.glVertex3f(r1 * (float)Math.cos(angle + 3 * da), r1 * (float)Math.sin(angle + 3 * da), width * 0.5f); gl.glVertex3f(r1 * (float)Math.cos(angle + 3 * da), r1 * (float)Math.sin(angle + 3 * da), -width * 0.5f); gl.glNormal3f((float)Math.cos(angle), (float)Math.sin(angle), 0.0f); } gl.glVertex3f(r1 * (float)Math.cos(0), r1 * (float)Math.sin(0), width * 0.5f); gl.glVertex3f(r1 * (float)Math.cos(0), r1 * (float)Math.sin(0), -width * 0.5f); gl.glEnd(); gl.glShadeModel(GL_SMOOTH); /* draw inside radius cylinder */ gl.glBegin(GL_QUAD_STRIP); for (i = 0; i <= teeth; i++) { angle = i * 2.0f * M_PI / teeth; gl.glNormal3f(-(float)Math.cos(angle), -(float)Math.sin(angle), 0.0f); gl.glVertex3f(r0 * (float)Math.cos(angle), r0 * (float)Math.sin(angle), -width * 0.5f); gl.glVertex3f(r0 * (float)Math.cos(angle), r0 * (float)Math.sin(angle), width * 0.5f); } gl.glEnd(); } // Reset the rotation matrix to the default view. private void setInitialRotation() { Matrix.rotateY(Matrix.deg2Rad(30), rot_matrix); Matrix.rotateX(Matrix.deg2Rad(20), rot_matrix); fixRotationMatrix(); } private void fixRotationMatrix() { // Fix any problems with the rotation matrix. rot_matrix[3] = rot_matrix[7] = rot_matrix[11] = rot_matrix[12] = rot_matrix[13] = rot_matrix[14] = 0.0f; rot_matrix[15] = 1.0f; float fac; if ((fac = (float)Math.sqrt ((rot_matrix[0]*rot_matrix[0]) + (rot_matrix[4]*rot_matrix[4]) + (rot_matrix[8]*rot_matrix[8]))) != 1.0f) { if (fac != 0.0f) { fac = 1.0f/fac; rot_matrix[0] *= fac; rot_matrix[4] *= fac; rot_matrix[8] *= fac; } } if ((fac = (float)Math.sqrt ((rot_matrix[1]*rot_matrix[1]) + (rot_matrix[5]*rot_matrix[5]) + (rot_matrix[9]*rot_matrix[9]))) != 1.0f) { if (fac != 0.0f) { fac = 1.0f/fac; rot_matrix[1] *= fac; rot_matrix[5] *= fac; rot_matrix[9] *= fac; } } if ((fac = (float)Math.sqrt ((rot_matrix[2]*rot_matrix[2]) + (rot_matrix[6]*rot_matrix[6]) + (rot_matrix[10]*rot_matrix[10]))) != 1.0f) { if (fac != 0.0f) { fac = 1.0f/fac; rot_matrix[2] *= fac; rot_matrix[6] *= fac; rot_matrix[10] *= fac; } } } // Methods required for the implementation of MouseListener public void mouseEntered( MouseEvent evt ) { } public void mouseExited( MouseEvent evt ) { } public void mousePressed( MouseEvent evt ) { mouseDown = true; prevMouse = evt.getPoint(); if ((evt.getModifiers() & evt.BUTTON3_MASK) != 0) { mouseRButtonDown = true; evt.consume(); } } public void mouseReleased( MouseEvent evt ) { mouseDown = false; if ((evt.getModifiers() & evt.BUTTON3_MASK) != 0) { mouseRButtonDown = false; evt.consume(); } } public void mouseClicked( MouseEvent evt ) { } // Methods required for the implementation of MouseMotionListener float[] mouseMtx = new float[16]; // The rot-matrix calculated by the virtual sphere. public void mouseDragged( MouseEvent evt ) { Point newMouse = evt.getPoint(); if (newMouse.x != prevMouse.x || newMouse.y != prevMouse.y) { // Use virtual sphere to determine an incremental rotation matrix. vs.makeRotationMtx(prevMouse, newMouse, cueCenter, cueRadius, mouseMtx); // Multiply overall rotation matrix by incremental rot-matrix to get new rotation. rot_matrix = Matrix.multiply(rot_matrix, mouseMtx); fixRotationMatrix(); prevMouse = newMouse; } evt.consume(); } public void mouseMoved( MouseEvent evt ) { } } }