diff options
author | Kenneth Russel <[email protected]> | 2005-08-20 00:29:15 +0000 |
---|---|---|
committer | Kenneth Russel <[email protected]> | 2005-08-20 00:29:15 +0000 |
commit | 7197a255a1688551a4861ca221233956b8fd21c0 (patch) | |
tree | 16f170a505e42038db36f3db9883e66ee0d05412 | |
parent | ed077c1bffc51024dbcaaab2a9a947a925c22914 (diff) |
Refactored Animator and FPSAnimator and improved efficiency in base
Animator class when drawing multiple JComponents (GLJPanels). Deleted
Animator.sync(). Fixed typo in GLJPanel comments.
git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/branches/JSR-231@351 232f8b59-042b-4e1e-8c03-345bb8c30851
-rw-r--r-- | src/net/java/games/jogl/Animator.java | 149 | ||||
-rwxr-xr-x | src/net/java/games/jogl/FPSAnimator.java | 6 | ||||
-rw-r--r-- | src/net/java/games/jogl/GLJPanel.java | 2 |
3 files changed, 128 insertions, 29 deletions
diff --git a/src/net/java/games/jogl/Animator.java b/src/net/java/games/jogl/Animator.java index de4b922ba..15d31c224 100644 --- a/src/net/java/games/jogl/Animator.java +++ b/src/net/java/games/jogl/Animator.java @@ -39,8 +39,13 @@ package net.java.games.jogl; +import java.awt.Component; import java.awt.EventQueue; +import java.awt.Rectangle; import java.util.*; +import javax.swing.*; + +import net.java.games.jogl.impl.*; /** <P> An Animator can be attached to one or more {@link GLAutoDrawable}s to drive their display() methods in a loop. </P> @@ -55,6 +60,7 @@ import java.util.*; */ public class Animator { + private static final boolean DEBUG = Debug.debug("Animator"); private volatile ArrayList/*<GLAutoDrawable>*/ drawables = new ArrayList(); private Runnable runnable; private Thread thread; @@ -62,6 +68,12 @@ public class Animator { protected boolean ignoreExceptions; protected boolean printExceptions; + // For efficient rendering of Swing components, in particular when + // they overlap one another + private List lightweights = new ArrayList(); + private Map repaintManagers = new IdentityHashMap(); + private Map dirtyRegions = new IdentityHashMap(); + /** Creates a new, empty Animator. */ public Animator() { } @@ -107,14 +119,42 @@ public class Animator { this.printExceptions = printExceptions; } - /** Called every frame after redrawing all drawables to cause a - brief pause in animation. Subclasses may override this to cause - different behavior in animation. The default implementation - calls <code>Thread.sleep(1)</code>. */ - protected void sync() { - try { - Thread.sleep(1); - } catch (InterruptedException e) { + /** Called every frame to cause redrawing of all of the + GLAutoDrawables this Animator manages. Subclasses should call + this to get the most optimized painting behavior for the set of + components this Animator manages, in particular when multiple + lightweight widgets are continually being redrawn. */ + protected void display() { + Iterator iter = drawableIterator(); + while (iter.hasNext()) { + GLAutoDrawable drawable = (GLAutoDrawable) iter.next(); + if (drawable instanceof JComponent) { + // Lightweight components need a more efficient drawing + // scheme than simply forcing repainting of each one in + // turn since drawing one can force another one to be + // drawn in turn + lightweights.add(drawable); + } else { + try { + drawable.display(); + } catch (RuntimeException e) { + if (ignoreExceptions) { + if (printExceptions) { + e.printStackTrace(); + } + } else { + throw(e); + } + } + } + } + if (lightweights.size() > 0) { + try { + SwingUtilities.invokeAndWait(drawWithRepaintManagerRunnable); + } catch (Exception e) { + e.printStackTrace(); + } + lightweights.clear(); } } @@ -133,22 +173,12 @@ public class Animator { } } } - Iterator iter = drawableIterator(); - while (iter.hasNext()) { - GLAutoDrawable drawable = (GLAutoDrawable) iter.next(); - try { - drawable.display(); - } catch (RuntimeException e) { - if (ignoreExceptions) { - if (printExceptions) { - e.printStackTrace(); - } - } else { - throw(e); - } - } + display(); + // Avoid swamping the CPU + try { + Thread.sleep(1); + } catch (InterruptedException e) { } - sync(); } } finally { shouldStop = false; @@ -193,4 +223,77 @@ public class Animator { } } } + + // Uses RepaintManager APIs to implement more efficient redrawing of + // the Swing widgets we're animating + private Runnable drawWithRepaintManagerRunnable = new Runnable() { + public void run() { + if (DEBUG) { + System.err.println("Drawing " + lightweights.size() + " with RepaintManager"); + } + for (Iterator iter = lightweights.iterator(); iter.hasNext(); ) { + JComponent comp = (JComponent) iter.next(); + RepaintManager rm = RepaintManager.currentManager(comp); + rm.markCompletelyDirty(comp); + repaintManagers.put(rm, rm); + + // RepaintManagers don't currently optimize the case of + // overlapping sibling components. If we have two + // JInternalFrames in a JDesktopPane, the redraw of the + // bottom one will cause the top one to be redrawn as + // well. The top one will then be redrawn separately. In + // order to optimize this case we need to compute the union + // of all of the dirty regions on a particular JComponent if + // optimized drawing isn't enabled for it. + + // Walk up the hierarchy trying to find a non-optimizable + // ancestor + Rectangle visible = comp.getVisibleRect(); + int x = visible.x; + int y = visible.y; + while (comp != null) { + x += comp.getX(); + y += comp.getY(); + Component c = comp.getParent(); + if ((c == null) || (!(c instanceof JComponent))) { + comp = null; + } else { + comp = (JComponent) c; + if (!comp.isOptimizedDrawingEnabled()) { + rm = RepaintManager.currentManager(comp); + repaintManagers.put(rm, rm); + // Need to dirty this region + Rectangle dirty = (Rectangle) dirtyRegions.get(comp); + if (dirty == null) { + dirty = new Rectangle(x, y, visible.width, visible.height); + dirtyRegions.put(comp, dirty); + } else { + // Compute union with already dirty region + // Note we could compute multiple non-overlapping + // regions: might want to do that in the future + // (prob. need more complex algorithm -- dynamic + // programming?) + dirty.add(new Rectangle(x, y, visible.width, visible.height)); + } + } + } + } + } + + // Dirty any needed regions on non-optimizable components + for (Iterator iter = dirtyRegions.keySet().iterator(); iter.hasNext(); ) { + JComponent comp = (JComponent) iter.next(); + Rectangle rect = (Rectangle) dirtyRegions.get(comp); + RepaintManager rm = RepaintManager.currentManager(comp); + rm.addDirtyRegion(comp, rect.x, rect.y, rect.width, rect.height); + } + + // Draw all dirty regions + for (Iterator iter = repaintManagers.keySet().iterator(); iter.hasNext(); ) { + ((RepaintManager) iter.next()).paintDirtyRegions(); + } + dirtyRegions.clear(); + repaintManagers.clear(); + } + }; } diff --git a/src/net/java/games/jogl/FPSAnimator.java b/src/net/java/games/jogl/FPSAnimator.java index 131a35562..311a9b722 100755 --- a/src/net/java/games/jogl/FPSAnimator.java +++ b/src/net/java/games/jogl/FPSAnimator.java @@ -72,11 +72,7 @@ public class FPSAnimator extends Animator { long delay = (long) (1000.0f / (float) fps); timer.schedule(new TimerTask() { public void run() { - Iterator iter = drawableIterator(); - while (iter.hasNext()) { - GLAutoDrawable drawable = (GLAutoDrawable) iter.next(); - drawable.display(); - } + display(); } }, 0, delay); } diff --git a/src/net/java/games/jogl/GLJPanel.java b/src/net/java/games/jogl/GLJPanel.java index 856bfd306..d3d95166c 100644 --- a/src/net/java/games/jogl/GLJPanel.java +++ b/src/net/java/games/jogl/GLJPanel.java @@ -137,7 +137,7 @@ public class GLJPanel extends JPanel implements GLAutoDrawable { component. The GLCapabilitiesChooser must be non-null and specifies the algorithm for selecting one of the available GLCapabilities for the component; the GLDrawableFactory uses a - DefaultGLCapabilitesChooser if the user does not provide + DefaultGLCapabilitiesChooser if the user does not provide one. The passed GLContext may be null and specifies an OpenGL context with which to share textures, display lists and other OpenGL state. */ |