summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKenneth Russel <[email protected]>2005-08-20 00:29:15 +0000
committerKenneth Russel <[email protected]>2005-08-20 00:29:15 +0000
commit7197a255a1688551a4861ca221233956b8fd21c0 (patch)
tree16f170a505e42038db36f3db9883e66ee0d05412
parented077c1bffc51024dbcaaab2a9a947a925c22914 (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.java149
-rwxr-xr-xsrc/net/java/games/jogl/FPSAnimator.java6
-rw-r--r--src/net/java/games/jogl/GLJPanel.java2
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. */