diff options
author | Kenneth Russel <[email protected]> | 2005-05-02 06:06:08 +0000 |
---|---|---|
committer | Kenneth Russel <[email protected]> | 2005-05-02 06:06:08 +0000 |
commit | 94e0cc9f1e2bd8ab233c8ec3750317dff3a2f701 (patch) | |
tree | 350caa11e28fc34071663f79e04de0a87fa67a23 | |
parent | 25642283fd65b5a22becd588b2564d162e85871a (diff) |
Fixed Issue 160: Resource leaks in GLJPanel
Added addNotify and removeNotify to GLJPanel which clean up the
associated OpenGL contexts and other resources. Extended JRefract demo
to stress GLJPanel creation and destruction. New code appears to be
correct. Can see resource leaks when the bunny is loaded over and
over, but believe these are probably due to allocation of large NIO
buffers that are not getting finalized promptly. Stressing the Gears
demo with both the pbuffer and software rendering paths shows that the
OpenGL resources are being reclaimed properly.
git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/../svn-server-sync/jogl-demos/trunk@66 3298f667-5e0e-4b4a-8ed4-a3559d26a5f4
-rwxr-xr-x | src/demos/jrefract/JRefract.java | 444 |
1 files changed, 428 insertions, 16 deletions
diff --git a/src/demos/jrefract/JRefract.java b/src/demos/jrefract/JRefract.java index a2feafe..2307136 100755 --- a/src/demos/jrefract/JRefract.java +++ b/src/demos/jrefract/JRefract.java @@ -42,6 +42,7 @@ import java.util.*; import javax.imageio.*; import javax.imageio.stream.*; import javax.swing.*; +import javax.swing.event.*; import net.java.games.jogl.*; import net.java.games.jogl.util.*; @@ -63,24 +64,31 @@ import gleem.linalg.*; public class JRefract { private boolean useRegisterCombiners; - private GLJPanel canvas; - private Animator animator; + private ArrayList canvases; + private volatile boolean quit; + private volatile boolean animatorStopped; + private JDesktopPane desktop; public static void main(String[] args) { new JRefract().run(args); } - public void run(String[] args) { - - JFrame frame = new JFrame("JOGL and Swing Interoperability"); - JDesktopPane desktop = new JDesktopPane(); - desktop.setSize(1024, 768); - JInternalFrame inner = new JInternalFrame("Refraction Using Vertex Programs"); + private JInternalFrame addWindow(boolean bunny) { + String str = bunny ? + "Refraction Using Vertex Programs" : + "Gears Demo"; + final JInternalFrame inner = new JInternalFrame(str); inner.setResizable(true); + inner.setClosable(true); + inner.setVisible(true); - canvas = GLDrawableFactory.getFactory().createGLJPanel(new GLCapabilities()); - canvas.addGLEventListener(new Listener()); + final GLJPanel canvas = GLDrawableFactory.getFactory().createGLJPanel(new GLCapabilities()); + if (bunny) { + canvas.addGLEventListener(new Listener()); + } else { + canvas.addGLEventListener(new GearRenderer()); + } canvas.setSize(512, 512); canvas.addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent e) { @@ -88,6 +96,15 @@ public class JRefract { } }); + addJPanel(canvas); + + inner.addInternalFrameListener(new InternalFrameAdapter() { + public void internalFrameClosed(InternalFrameEvent e) { + removeJPanel(canvas); + System.gc(); + } + }); + inner.getContentPane().setLayout(new BorderLayout()); inner.getContentPane().add(canvas, BorderLayout.CENTER); inner.getContentPane().add(new JButton("West"), BorderLayout.WEST); @@ -95,10 +112,20 @@ public class JRefract { inner.getContentPane().add(new JButton("North"), BorderLayout.NORTH); inner.getContentPane().add(new JButton("South"), BorderLayout.SOUTH); inner.setSize(canvas.getSize()); + desktop.add(inner); + + return inner; + } + + public void run(String[] args) { + + canvases = new ArrayList(); + + JFrame frame = new JFrame("JOGL and Swing Interoperability"); + desktop = new JDesktopPane(); + desktop.setSize(1024, 768); frame.getContentPane().setLayout(new BorderLayout()); frame.getContentPane().add(desktop, BorderLayout.CENTER); - desktop.add(inner); - inner.setVisible(true); JInternalFrame inner2 = new JInternalFrame("Hello, World"); JLabel label = new JLabel("Hello, World!"); @@ -109,7 +136,44 @@ public class JRefract { desktop.add(inner2); inner2.setVisible(true); - animator = new Animator(canvas); + JMenuBar menuBar = new JMenuBar(); + + JMenu menu = new JMenu("Actions"); + JMenuItem item = new JMenuItem("New bunny"); + item.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + addWindow(true); + } + }); + menu.add(item); + + item = new JMenuItem("New gears"); + item.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + addWindow(false); + } + }); + menu.add(item); + + item = new JMenuItem("Auto mode"); + item.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + startAutoMode(); + } + }); + menu.add(item); + + item = new JMenuItem("Exit"); + item.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + runExit(); + } + }); + menu.add(item); + + menuBar.add(menu); + frame.setJMenuBar(menuBar); + frame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { runExit(); @@ -117,7 +181,8 @@ public class JRefract { }); frame.setSize(desktop.getSize()); frame.setVisible(true); - animator.start(); + + new Thread(new ListAnimator()).start(); } class Listener implements GLEventListener { @@ -539,7 +604,9 @@ public class JRefract { for (int i = 0; i < suffixes.length; i++) { String resourceName = baseName + "_" + suffixes[i] + ".png"; // Note: use of BufferedInputStream works around 4764639/4892246 - BufferedImage img = ImageIO.read(new BufferedInputStream(getClass().getClassLoader().getResourceAsStream(resourceName))); + BufferedInputStream bis = new BufferedInputStream(getClass().getClassLoader().getResourceAsStream(resourceName)); + BufferedImage img = ImageIO.read(bis); + bis.close(); if (img == null) { throw new RuntimeException("Error reading PNG image " + resourceName); } @@ -766,6 +833,12 @@ public class JRefract { private void runExit() { quit = true; + while (!animatorStopped) { + try { + Thread.sleep(1); + } catch (InterruptedException e) { + } + } // Note: calling System.exit() synchronously inside the draw, // reshape or init callbacks can lead to deadlocks on certain // platforms (in particular, X11) because the JAWT's locking @@ -773,9 +846,348 @@ public class JRefract { // the exit routine in another thread. new Thread(new Runnable() { public void run() { - animator.stop(); System.exit(0); } }).start(); } + + private synchronized void addJPanel(GLJPanel panel) { + ArrayList newCanvases = (ArrayList) canvases.clone(); + newCanvases.add(panel); + canvases = newCanvases; + } + + private synchronized void removeJPanel(GLJPanel panel) { + ArrayList newCanvases = (ArrayList) canvases.clone(); + newCanvases.remove(panel); + canvases = newCanvases; + } + + class ListAnimator implements Runnable { + public void run() { + while (!quit) { + if (canvases.isEmpty()) { + try { + Thread.sleep(10); + } catch (InterruptedException e) { + } + } else { + for (Iterator iter = canvases.iterator(); iter.hasNext(); ) { + GLJPanel panel = (GLJPanel) iter.next(); + panel.display(); + } + } + } + animatorStopped = true; + } + } + + static class GearRenderer implements GLEventListener, MouseListener, MouseMotionListener { + private float view_rotx = 20.0f, view_roty = 30.0f, view_rotz = 0.0f; + private int gear1, gear2, gear3; + private float angle = 0.0f; + + private int prevMouseX, prevMouseY; + private boolean mouseRButtonDown = false; + + + public void init(GLDrawable drawable) { + GL gl = drawable.getGL(); + System.err.println("INIT GL IS: " + gl.getClass().getName()); + + 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(GL.GL_LIGHT0, GL.GL_POSITION, pos); + gl.glEnable(GL.GL_CULL_FACE); + gl.glEnable(GL.GL_LIGHTING); + gl.glEnable(GL.GL_LIGHT0); + gl.glEnable(GL.GL_DEPTH_TEST); + + /* make the gears */ + gear1 = gl.glGenLists(1); + gl.glNewList(gear1, GL.GL_COMPILE); + gl.glMaterialfv(GL.GL_FRONT, GL.GL_AMBIENT_AND_DIFFUSE, red); + gear(gl, 1.0f, 4.0f, 1.0f, 20, 0.7f); + gl.glEndList(); + + gear2 = gl.glGenLists(1); + gl.glNewList(gear2, GL.GL_COMPILE); + gl.glMaterialfv(GL.GL_FRONT, GL.GL_AMBIENT_AND_DIFFUSE, green); + gear(gl, 0.5f, 2.0f, 2.0f, 10, 0.7f); + gl.glEndList(); + + gear3 = gl.glGenLists(1); + gl.glNewList(gear3, GL.GL_COMPILE); + gl.glMaterialfv(GL.GL_FRONT, GL.GL_AMBIENT_AND_DIFFUSE, blue); + gear(gl, 1.3f, 2.0f, 0.5f, 10, 0.7f); + gl.glEndList(); + + gl.glEnable(GL.GL_NORMALIZE); + + drawable.addMouseListener(this); + drawable.addMouseMotionListener(this); + } + + public void reshape(GLDrawable drawable, int x, int y, int width, int height) { + GL gl = drawable.getGL(); + + float h = (float)height / (float)width; + + gl.glMatrixMode(GL.GL_PROJECTION); + + System.err.println("GL_VENDOR: " + gl.glGetString(GL.GL_VENDOR)); + System.err.println("GL_RENDERER: " + gl.glGetString(GL.GL_RENDERER)); + System.err.println("GL_VERSION: " + gl.glGetString(GL.GL_VERSION)); + System.err.println(); + System.err.println("glLoadTransposeMatrixfARB() supported: " + + gl.isFunctionAvailable("glLoadTransposeMatrixfARB")); + if (!gl.isFunctionAvailable("glLoadTransposeMatrixfARB")) { + // --- not using extensions + gl.glLoadIdentity(); + } else { + // --- using extensions + final float[] identityTranspose = new float[] { + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 + }; + gl.glLoadTransposeMatrixfARB(identityTranspose); + } + gl.glFrustum(-1.0f, 1.0f, -h, h, 5.0f, 60.0f); + gl.glMatrixMode(GL.GL_MODELVIEW); + gl.glLoadIdentity(); + gl.glTranslatef(0.0f, 0.0f, -40.0f); + } + + public void display(GLDrawable drawable) { + angle += 2.0f; + + GL gl = drawable.getGL(); + gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); + + 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); + + 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 displayChanged(GLDrawable drawable, boolean modeChanged, boolean deviceChanged) {} + + private void gear(GL 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(GL.GL_FLAT); + + gl.glNormal3f(0.0f, 0.0f, 1.0f); + + /* draw front face */ + gl.glBegin(GL.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(GL.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(GL.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(GL.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(GL.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(GL.GL_SMOOTH); + + /* draw inside radius cylinder */ + gl.glBegin(GL.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(); + } + + // Methods required for the implementation of MouseListener + public void mouseEntered(MouseEvent e) {} + public void mouseExited(MouseEvent e) {} + + public void mousePressed(MouseEvent e) { + prevMouseX = e.getX(); + prevMouseY = e.getY(); + if ((e.getModifiers() & e.BUTTON3_MASK) != 0) { + mouseRButtonDown = true; + } + } + + public void mouseReleased(MouseEvent e) { + if ((e.getModifiers() & e.BUTTON3_MASK) != 0) { + mouseRButtonDown = false; + } + } + + public void mouseClicked(MouseEvent e) {} + + // Methods required for the implementation of MouseMotionListener + public void mouseDragged(MouseEvent e) { + int x = e.getX(); + int y = e.getY(); + Dimension size = e.getComponent().getSize(); + + float thetaY = 360.0f * ( (float)(x-prevMouseX)/(float)size.width); + float thetaX = 360.0f * ( (float)(prevMouseY-y)/(float)size.height); + + prevMouseX = x; + prevMouseY = y; + + view_rotx += thetaX; + view_roty += thetaY; + } + + public void mouseMoved(MouseEvent e) {} + } + + private JInternalFrame curFrame; + private void startAutoMode() { + new Thread(new Runnable() { + public void run() { + while (true) { + try { + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + curFrame = addWindow(false); + } + }); + } catch (Exception e) { + e.printStackTrace(); + } + + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + } + + try { + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + curFrame.doDefaultCloseAction(); + } + }); + } catch (Exception e) { + e.printStackTrace(); + } + + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + } + } + } + }).start(); + } } |