import javax.swing.*; import javax.swing.table.*; import java.awt.*; import java.awt.event.*; import java.util.*; import java.awt.image.*; import javax.media.opengl.awt.*; import javax.media.opengl.*; import com.jogamp.opengl.util.*; public class JitterProblemJoGL { static JitterProblemJoGL laf; public static boolean show_problem = true; public static boolean use_panel_above_canvas = false; static private float view_rotx = 20.0f, view_roty = 30.0f, view_rotz = 0.0f; static private int gear1, gear2, gear3; static private float angle = 0.0f; static class Sketcher extends JPanel implements MouseMotionListener { Vector allpoints = new Vector(); public Sketcher(){ } public Dimension getPreferredSize(){ return new Dimension(300, 300); } public Dimension getMinimumSize(){ return new Dimension(300, 300); } public void mouseDragged(MouseEvent e){} public void mouseMoved(MouseEvent e){ allpoints.add(new Point(e.getX(), e.getY())); if (show_problem){ super.repaint(); } } int prevnumpoints = 0; BufferedImage bi = null; Dimension prevSize = null; public void paint(Graphics g){ if (allpoints.isEmpty()){ return; } if (show_problem){ g.setColor(Color.black); Point prevpt = allpoints.firstElement(); for (Point pt : allpoints){ g.drawLine(prevpt.x, prevpt.y, pt.x, pt.y); prevpt = pt; } } else { Dimension size = getSize(); if (!(allpoints.size() == prevnumpoints && bi!=null && size.width==bi.getWidth() && size.height==bi.getHeight())){ // create the image bi = new BufferedImage(size.width, size.height, BufferedImage.TYPE_4BYTE_ABGR); Graphics big = bi.getGraphics(); big.setColor(Color.black); Point prevpt = allpoints.firstElement(); for (Point pt : allpoints){ big.drawLine(prevpt.x, prevpt.y, pt.x, pt.y); prevpt = pt; } } g.drawImage(bi, 0, 0, null); } } }; static Sketcher sketcher = new Sketcher(); public static void main(String[] args) { laf = new JitterProblemJoGL(); try { UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName()); } catch(Exception err) { err.printStackTrace(); } JFrame f = new JFrame("JitterProblemJoGL"); GLCapabilities gl_capabilities = new GLCapabilities(GLProfile.getDefault()); final GLCanvas canvas = new GLCanvas(gl_capabilities); final Animator animator = new Animator(canvas); f.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { // Run this on another thread than the AWT event queue to // make sure the call to Animator.stop() completes before // exiting new Thread(new Runnable() { public void run() { animator.stop(); System.exit(0); } }).start(); } }); JPanel joglpanel = new JPanel(); if (use_panel_above_canvas){ joglpanel.add(canvas); } canvas.addGLEventListener(new GLEventListener(){ public void init(GLAutoDrawable drawable){ System.out.println("init() called drawable=" + drawable); GL2 gl = drawable.getGL().getGL2(); System.err.println("INIT GL IS: " + gl.getClass().getName()); System.err.println("Chosen GLCapabilities: " + drawable.getChosenGLCapabilities()); gl.setSwapInterval(1); 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.glLightfv(GL2.GL_LIGHT0, GL2.GL_POSITION, pos, 0); gl.glEnable(GL2.GL_CULL_FACE); gl.glEnable(GL2.GL_LIGHTING); gl.glEnable(GL2.GL_LIGHT0); gl.glEnable(GL2.GL_DEPTH_TEST); /* make the gears */ gear1 = gl.glGenLists(1); gl.glNewList(gear1, GL2.GL_COMPILE); gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_AMBIENT_AND_DIFFUSE, red, 0); gear(gl, 1.0f, 4.0f, 1.0f, 20, 0.7f); gl.glEndList(); gear2 = gl.glGenLists(1); gl.glNewList(gear2, GL2.GL_COMPILE); gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_AMBIENT_AND_DIFFUSE, green, 0); gear(gl, 0.5f, 2.0f, 2.0f, 10, 0.7f); gl.glEndList(); gear3 = gl.glGenLists(1); gl.glNewList(gear3, GL2.GL_COMPILE); gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_AMBIENT_AND_DIFFUSE, blue, 0); gear(gl, 1.3f, 2.0f, 0.5f, 10, 0.7f); gl.glEndList(); gl.glEnable(GL2.GL_NORMALIZE); } public void dispose(GLAutoDrawable drawable){ System.out.println("Gears.dispose: "+drawable); } public void display(GLAutoDrawable drawable){ // Turn the gears' teeth angle += 2.0f; // Get the GL corresponding to the drawable we are animating GL2 gl = drawable.getGL().getGL2(); // Special handling for the case where the GLJPanel is translucent // and wants to be composited with other Java 2D content if ((drawable instanceof GLJPanel) && !((GLJPanel) drawable).isOpaque() && ((GLJPanel) drawable).shouldPreserveColorBufferIfTranslucent()) { gl.glClear(GL2.GL_DEPTH_BUFFER_BIT); } else { gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT); } // 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 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 void reshape(GLAutoDrawable drawable, int x, int y, int width, int height){ GL2 gl = drawable.getGL().getGL2(); float h = (float)height / (float)width; gl.glMatrixMode(GL2.GL_PROJECTION); System.err.println("GL_VENDOR: " + gl.glGetString(GL2.GL_VENDOR)); System.err.println("GL_RENDERER: " + gl.glGetString(GL2.GL_RENDERER)); System.err.println("GL_VERSION: " + gl.glGetString(GL2.GL_VERSION)); gl.glLoadIdentity(); gl.glFrustum(-1.0f, 1.0f, -h, h, 5.0f, 60.0f); gl.glMatrixMode(GL2.GL_MODELVIEW); gl.glLoadIdentity(); gl.glTranslatef(0.0f, 0.0f, -40.0f); } }); JPanel panel = new JPanel(); panel.setLayout(new BorderLayout()); if (use_panel_above_canvas){ panel.add(joglpanel); } else { panel.add(canvas); } panel.add(sketcher, BorderLayout.WEST); sketcher.addMouseMotionListener(sketcher); ActionListener taskPerformer = new ActionListener() { public void actionPerformed(ActionEvent evt) { sketcher.repaint(); } }; int expectedFrameRate = 30; /* 30 frames per second for Swing/AWT panels is sufficient */ javax.swing.Timer timer = new javax.swing.Timer(1000/expectedFrameRate, taskPerformer); if (!show_problem){ timer.start(); } f.setContentPane(panel); f.setExtendedState(JFrame.MAXIMIZED_BOTH); f.setVisible(true); animator.start(); } public static void gear(GL2 gl, 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 * (float) Math.PI / teeth / 4.0f; gl.glShadeModel(GL2.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(GL2.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(GL2.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(GL2.GL_SMOOTH); /* 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(); } }