package com.jogamp.opengl.test.junit.jogl.demos.gl2; import com.jogamp.opengl.GL; import com.jogamp.opengl.GL2; import com.jogamp.opengl.GL2GL3; import com.jogamp.opengl.GLAutoDrawable; import com.jogamp.opengl.GLEventListener; import com.jogamp.opengl.GLProfile; import com.jogamp.opengl.fixedfunc.GLLightingFunc; import com.jogamp.opengl.fixedfunc.GLMatrixFunc; import com.jogamp.newt.Window; import com.jogamp.newt.event.InputEvent; import com.jogamp.newt.event.KeyAdapter; import com.jogamp.newt.event.KeyEvent; import com.jogamp.newt.event.KeyListener; import com.jogamp.newt.event.MouseAdapter; import com.jogamp.newt.event.MouseEvent; import com.jogamp.newt.event.MouseListener; import com.jogamp.newt.event.awt.AWTKeyAdapter; import com.jogamp.newt.event.awt.AWTMouseAdapter; import com.jogamp.opengl.GLRendererQuirks; import com.jogamp.opengl.JoglVersion; import com.jogamp.opengl.util.TileRendererBase; /** * Gears.java <BR> * author: Brian Paul (converted to Java by Ron Cemer and Sven Gothel) <P> * * This version is equal to Brian Paul's version 1.2 1999/10/21 */ public class Gears implements GLEventListener, TileRendererBase.TileRendererListener { private float view_rotx = 20.0f, view_roty = 30.0f; private final float view_rotz = 0.0f; private int gear1=0, gear2=0, gear3=0; private Gears sharedGears = null; private Object syncObjects = null; private float angle = 0.0f; private boolean doRotate = true; private final int swapInterval; private final MouseListener gearsMouse = new GearsMouseAdapter(); private final KeyListener gearsKeys = new GearsKeyAdapter(); private TileRendererBase tileRendererInUse = null; private boolean doRotateBeforePrinting; private boolean verbose = true; private boolean flipVerticalInGLOrientation = false; private volatile boolean isInit = false; // private boolean mouseRButtonDown = false; private int prevMouseX, prevMouseY; public Gears(final int swapInterval) { this.swapInterval = swapInterval; } public Gears() { this.swapInterval = 1; } @Override public void addTileRendererNotify(final TileRendererBase tr) { tileRendererInUse = tr; doRotateBeforePrinting = doRotate; setDoRotation(false); } @Override public void removeTileRendererNotify(final TileRendererBase tr) { tileRendererInUse = null; setDoRotation(doRotateBeforePrinting); } @Override public void startTileRendering(final TileRendererBase tr) { System.err.println("Gears.startTileRendering: "+tr); } @Override public void endTileRendering(final TileRendererBase tr) { System.err.println("Gears.endTileRendering: "+tr); } public void setDoRotation(final boolean rotate) { doRotate = rotate; } public void setVerbose(final boolean v) { verbose = v; } public void setFlipVerticalInGLOrientation(final boolean v) { flipVerticalInGLOrientation=v; } public void setSharedGears(final Gears shared) { sharedGears = shared; } /** * @return display list gear1 */ public int getGear1() { return gear1; } /** * @return display list gear2 */ public int getGear2() { return gear2; } /** * @return display list gear3 */ public int getGear3() { return gear3; } @Override public void init(final GLAutoDrawable drawable) { final GL2 gl = drawable.getGL().getGL2(); if( init(gl) ) { final Object upstreamWidget = drawable.getUpstreamWidget(); if (upstreamWidget instanceof Window) { final Window window = (Window) upstreamWidget; window.addMouseListener(gearsMouse); window.addKeyListener(gearsKeys); } else if (GLProfile.isAWTAvailable() && upstreamWidget instanceof java.awt.Component) { final java.awt.Component comp = (java.awt.Component) upstreamWidget; new AWTMouseAdapter(gearsMouse, drawable).addTo(comp); new AWTKeyAdapter(gearsKeys, drawable).addTo(comp); } } else { drawable.setGLEventListenerInitState(this, false); } } boolean enableCullFace = false; private void enableStates(final GL gl, final boolean enable) { final boolean msaa = gl.getContext().getGLDrawable().getChosenGLCapabilities().getSampleBuffers(); if( enable ) { if( enableCullFace ) { gl.glEnable(GL.GL_CULL_FACE); } gl.glEnable(GLLightingFunc.GL_LIGHTING); gl.glEnable(GLLightingFunc.GL_LIGHT0); gl.glEnable(GL.GL_DEPTH_TEST); gl.glDepthFunc(GL.GL_LESS); // default gl.glEnable(GLLightingFunc.GL_NORMALIZE); if( msaa ) { gl.glEnable(GL.GL_MULTISAMPLE); } } else { if( enableCullFace ) { gl.glDisable(GL.GL_CULL_FACE); } gl.glDisable(GLLightingFunc.GL_LIGHTING); gl.glDisable(GLLightingFunc.GL_LIGHT0); gl.glDisable(GL.GL_DEPTH_TEST); gl.glDisable(GLLightingFunc.GL_NORMALIZE); if( msaa ) { gl.glDisable(GL.GL_MULTISAMPLE); } } } public boolean init(final GL2 gl) { if(null != sharedGears && !sharedGears.isInit() ) { System.err.println(Thread.currentThread()+" GearsES1.init.0: pending shared Gears .. re-init later XXXXX"); return false; } final float lightPos[] = { 5.0f, 5.0f, 10.0f, 0.0f }; final float red[] = { 0.8f, 0.1f, 0.0f, 0.7f }; final float green[] = { 0.0f, 0.8f, 0.2f, 0.7f }; final float blue[] = { 0.2f, 0.2f, 1.0f, 0.7f }; System.err.println(Thread.currentThread()+" Gears.init: tileRendererInUse "+tileRendererInUse); if(verbose) { System.err.println("GearsES2 init on "+Thread.currentThread()); System.err.println("Chosen GLCapabilities: " + gl.getContext().getGLDrawable().getChosenGLCapabilities()); System.err.println("INIT GL IS: " + gl.getClass().getName()); System.err.println(JoglVersion.getGLStrings(gl, null, false).toString()); } gl.glLightfv(GLLightingFunc.GL_LIGHT0, GLLightingFunc.GL_POSITION, lightPos, 0); if( ! ( flipVerticalInGLOrientation && gl.getContext().getGLDrawable().isGLOriented() ) ) { // Only possible if we do not flip the projection matrix enableCullFace = true; } else { enableCullFace = false; } enableStates(gl, true); /* make the gears */ if( null != sharedGears ) { gear1 = sharedGears.getGear1(); gear2 = sharedGears.getGear2(); gear3 = sharedGears.getGear3(); System.err.println("gear1 list reused: "+gear1); System.err.println("gear2 list reused: "+gear2); System.err.println("gear3 list reused: "+gear3); if( gl.getContext().hasRendererQuirk(GLRendererQuirks.NeedSharedObjectSync) ) { syncObjects = sharedGears; System.err.println("Shared Gears: Synchronized Objects due to quirk "+GLRendererQuirks.toString(GLRendererQuirks.NeedSharedObjectSync)); } else { syncObjects = new Object(); System.err.println("Shared Gears: Unsynchronized Objects"); } } else { gear1 = gl.glGenLists(1); gl.glNewList(gear1, GL2.GL_COMPILE); gl.glMaterialfv(GL.GL_FRONT, GLLightingFunc.GL_AMBIENT_AND_DIFFUSE, red, 0); gear(gl, 1.0f, 4.0f, 1.0f, 20, 0.7f); gl.glEndList(); System.err.println("gear1 list created: "+gear1); gear2 = gl.glGenLists(1); gl.glNewList(gear2, GL2.GL_COMPILE); gl.glMaterialfv(GL.GL_FRONT, GLLightingFunc.GL_AMBIENT_AND_DIFFUSE, green, 0); gear(gl, 0.5f, 2.0f, 2.0f, 10, 0.7f); gl.glEndList(); System.err.println("gear2 list created: "+gear2); gear3 = gl.glGenLists(1); gl.glNewList(gear3, GL2.GL_COMPILE); gl.glMaterialfv(GL.GL_FRONT, GLLightingFunc.GL_AMBIENT_AND_DIFFUSE, blue, 0); gear(gl, 1.3f, 2.0f, 0.5f, 10, 0.7f); gl.glEndList(); System.err.println("gear3 list created: "+gear3); syncObjects = new Object(); } enableStates(gl, false); isInit = true; return true; } public final boolean isInit() { return isInit; } @Override public void reshape(final GLAutoDrawable glad, final int x, final int y, final int width, final int height) { if( !isInit ) { return; } final GL2 gl = glad.getGL().getGL2(); gl.setSwapInterval(swapInterval); reshape(gl, x, y, width, height, width, height); } @Override public void reshapeTile(final TileRendererBase tr, final int tileX, final int tileY, final int tileWidth, final int tileHeight, final int imageWidth, final int imageHeight) { if( !isInit ) { return; } final GL2 gl = tr.getAttachedDrawable().getGL().getGL2(); gl.setSwapInterval(0); reshape(gl, tileX, tileY, tileWidth, tileHeight, imageWidth, imageHeight); } public void reshape(final GL2 gl, final int tileX, final int tileY, final int tileWidth, final int tileHeight, final int imageWidth, final int imageHeight) { System.err.println(Thread.currentThread()+" Gears.reshape "+tileX+"/"+tileY+" "+tileWidth+"x"+tileHeight+" of "+imageWidth+"x"+imageHeight+", swapInterval "+swapInterval+", drawable 0x"+Long.toHexString(gl.getContext().getGLDrawable().getHandle())+", tileRendererInUse "+tileRendererInUse); // compute projection parameters 'normal' float left, right, bottom, top; if( imageHeight > imageWidth ) { final float a = (float)imageHeight / (float)imageWidth; left = -1.0f; right = 1.0f; bottom = -a; top = a; } else { final float a = (float)imageWidth / (float)imageHeight; left = -a; right = a; bottom = -1.0f; top = 1.0f; } final float w = right - left; final float h = top - bottom; // compute projection parameters 'tiled' final float l = left + tileX * w / imageWidth; final float r = l + tileWidth * w / imageWidth; final float b = bottom + tileY * h / imageHeight; final float t = b + tileHeight * h / imageHeight; final float _w = r - l; final float _h = t - b; if(verbose) { System.err.println(">> Gears angle "+angle+", [l "+left+", r "+right+", b "+bottom+", t "+top+"] "+w+"x"+h+" -> [l "+l+", r "+r+", b "+b+", t "+t+"] "+_w+"x"+_h+", v-flip "+flipVerticalInGLOrientation); } gl.glMatrixMode(GLMatrixFunc.GL_PROJECTION); gl.glLoadIdentity(); if( flipVerticalInGLOrientation && gl.getContext().getGLDrawable().isGLOriented() ) { gl.glScalef(1f, -1f, 1f); } gl.glFrustum(l, r, b, t, 5.0f, 60.0f); gl.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); gl.glLoadIdentity(); gl.glTranslatef(0.0f, 0.0f, -40.0f); } @Override public void dispose(final GLAutoDrawable drawable) { if( !isInit ) { return; } isInit = false; System.err.println(Thread.currentThread()+" Gears.dispose: tileRendererInUse "+tileRendererInUse); try { final Object upstreamWidget = drawable.getUpstreamWidget(); if (upstreamWidget instanceof Window) { final Window window = (Window) upstreamWidget; window.removeMouseListener(gearsMouse); window.removeKeyListener(gearsKeys); } } catch (final Exception e) { System.err.println("Caught: "); e.printStackTrace(); } gear1 = 0; gear2 = 0; gear3 = 0; sharedGears = null; syncObjects = null; } @Override public void display(final GLAutoDrawable drawable) { if( !isInit ) { return; } // Get the GL corresponding to the drawable we are animating final GL2 gl = drawable.getGL().getGL2(); enableStates(gl, true); if( null == tileRendererInUse ) { gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); } else { gl.glClearColor(1.0f, 1.0f, 1.0f, 0.0f); } // Special handling for the case where the GLJPanel is translucent // and wants to be composited with other Java 2D content if (GLProfile.isAWTAvailable() && (drawable instanceof com.jogamp.opengl.awt.GLJPanel) && !((com.jogamp.opengl.awt.GLJPanel) drawable).isOpaque() && ((com.jogamp.opengl.awt.GLJPanel) drawable).shouldPreserveColorBufferIfTranslucent()) { gl.glClear(GL.GL_DEPTH_BUFFER_BIT); } else { gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); } displayImpl(gl); enableStates(gl, false); } public void display(final GL2 gl) { if( !isInit ) { return; } enableStates(gl, true); if( null == tileRendererInUse ) { gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); } else { gl.glClearColor(1.0f, 1.0f, 1.0f, 0.0f); } gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); displayImpl(gl); enableStates(gl, false); } private void displayImpl(final GL2 gl) { if( doRotate ) { // Turn the gears' teeth angle += 0.5f; } // Rotate the entire assembly of gears based on how the user // dragged the mouse around gl.glPushMatrix(); gl.glRotatef(view_rotx, 1.0f, 0.0f, 0.0f); gl.glRotatef(view_roty, 0.0f, 1.0f, 0.0f); gl.glRotatef(view_rotz, 0.0f, 0.0f, 1.0f); // Place the first gear and call its display list synchronized ( syncObjects ) { gl.glPushMatrix(); gl.glTranslatef(-3.0f, -2.0f, 0.0f); gl.glRotatef(angle, 0.0f, 0.0f, 1.0f); gl.glCallList(gear1); gl.glPopMatrix(); // Place the second gear and call its display list 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(); // Place the third gear and call its display list 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(); } // Remember that every push needs a pop; this one is paired with // rotating the entire gear assembly gl.glPopMatrix(); } public static void gear(final GL2 gl, final float inner_radius, final float outer_radius, final float width, final int teeth, final 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 * (float) Math.PI / teeth / 4.0f; gl.glShadeModel(GLLightingFunc.GL_FLAT); gl.glNormal3f(0.0f, 0.0f, 1.0f); /* draw front face */ gl.glBegin(GL2.GL_QUAD_STRIP); for (i = 0; i <= teeth; i++) { angle = i * 2.0f * (float) Math.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); if(i < teeth) { 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(GL2GL3.GL_QUADS); for (i = 0; i < teeth; i++) { angle = i * 2.0f * (float) Math.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(); /* draw back face */ gl.glBegin(GL2.GL_QUAD_STRIP); for (i = 0; i <= teeth; i++) { angle = i * 2.0f * (float) Math.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(GL2GL3.GL_QUADS); for (i = 0; i < teeth; i++) { angle = i * 2.0f * (float) Math.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(GL2.GL_QUAD_STRIP); for (i = 0; i < teeth; i++) { angle = i * 2.0f * (float) Math.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(GLLightingFunc.GL_SMOOTH); // default /* draw inside radius cylinder */ gl.glBegin(GL2.GL_QUAD_STRIP); for (i = 0; i <= teeth; i++) { angle = i * 2.0f * (float) Math.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(); } class GearsKeyAdapter extends KeyAdapter { public void keyPressed(final KeyEvent e) { final int kc = e.getKeyCode(); if(KeyEvent.VK_LEFT == kc) { view_roty -= 1; } else if(KeyEvent.VK_RIGHT == kc) { view_roty += 1; } else if(KeyEvent.VK_UP == kc) { view_rotx -= 1; } else if(KeyEvent.VK_DOWN == kc) { view_rotx += 1; } } } class GearsMouseAdapter extends MouseAdapter { public void mousePressed(final MouseEvent e) { prevMouseX = e.getX(); prevMouseY = e.getY(); if ((e.getModifiers() & InputEvent.BUTTON3_MASK) != 0) { // mouseRButtonDown = true; } } public void mouseReleased(final MouseEvent e) { if ((e.getModifiers() & InputEvent.BUTTON3_MASK) != 0) { // mouseRButtonDown = false; } } public void mouseDragged(final MouseEvent e) { final int x = e.getX(); final int y = e.getY(); int width=0, height=0; final Object source = e.getSource(); if(source instanceof Window) { final Window window = (Window) source; width=window.getSurfaceWidth(); height=window.getSurfaceHeight(); } else if (source instanceof GLAutoDrawable) { final GLAutoDrawable glad = (GLAutoDrawable) source; width = glad.getSurfaceWidth(); height = glad.getSurfaceHeight(); } else if (GLProfile.isAWTAvailable() && source instanceof java.awt.Component) { final java.awt.Component comp = (java.awt.Component) source; width=comp.getWidth(); // FIXME HiDPI: May need to convert window units -> pixel units! height=comp.getHeight(); } else { throw new RuntimeException("Event source neither Window nor Component: "+source); } final float thetaY = 360.0f * ( (float)(x-prevMouseX)/(float)width); final float thetaX = 360.0f * ( (float)(prevMouseY-y)/(float)height); prevMouseX = x; prevMouseY = y; view_rotx += thetaX; view_roty += thetaY; } } }