diff options
Diffstat (limited to 'src/net/java/games')
-rw-r--r-- | src/net/java/games/jogl/Animator.java | 156 | ||||
-rwxr-xr-x | src/net/java/games/jogl/FPSAnimator.java | 93 |
2 files changed, 209 insertions, 40 deletions
diff --git a/src/net/java/games/jogl/Animator.java b/src/net/java/games/jogl/Animator.java index c2f7eeb6e..de4b922ba 100644 --- a/src/net/java/games/jogl/Animator.java +++ b/src/net/java/games/jogl/Animator.java @@ -40,34 +40,124 @@ package net.java.games.jogl; import java.awt.EventQueue; -import net.java.games.jogl.impl.SingleThreadedWorkaround; - -/** <P> An Animator can be attached to a GLDrawable to drive its - display() method in a loop. For efficiency, it sets up the - rendering thread for the drawable to be its own internal thread, - so it can not be combined with manual repaints of the - surface. </P> - - <P> The Animator currently contains a workaround for a bug in - NVidia's drivers (80174). The current semantics are that once an - Animator is created with a given GLDrawable as a target, repaints - will likely be suspended for that GLDrawable until the Animator is - started. This prevents multithreaded access to the context (which - can be problematic) when the application's intent is for - single-threaded access within the Animator. It is not guaranteed - that repaints will be prevented during this time and applications - should not rely on this behavior for correctness. </P> +import java.util.*; + +/** <P> An Animator can be attached to one or more {@link + GLAutoDrawable}s to drive their display() methods in a loop. </P> + + <P> The Animator class creates a background thread in which the + calls to <code>display()</code> are performed. After each drawable + has been redrawn, {@link #sync} is called to cause a brief pause. + The default implementation of {@link #sync} calls + <code>Thread.sleep(1)</code> to yield the CPU briefly. Subclasses + may override this behavior to cause different animation behavior. + </P> */ public class Animator { - private GLAutoDrawable drawable; + private volatile ArrayList/*<GLAutoDrawable>*/ drawables = new ArrayList(); private Runnable runnable; private Thread thread; - private boolean shouldStop; + private volatile boolean shouldStop; + protected boolean ignoreExceptions; + protected boolean printExceptions; + + /** Creates a new, empty Animator. */ + public Animator() { + } /** Creates a new Animator for a particular drawable. */ public Animator(GLAutoDrawable drawable) { - this.drawable = drawable; + add(drawable); + } + + /** Adds a drawable to the list managed by this Animator. */ + public synchronized void add(GLAutoDrawable drawable) { + ArrayList newList = (ArrayList) drawables.clone(); + newList.add(drawable); + drawables = newList; + notifyAll(); + } + + /** Removes a drawable from the list managed by this Animator. */ + public synchronized void remove(GLAutoDrawable drawable) { + ArrayList newList = (ArrayList) drawables.clone(); + newList.remove(drawable); + drawables = newList; + } + + /** Returns an iterator over the drawables managed by this + Animator. */ + public Iterator/*<GLAutoDrawable>*/ drawableIterator() { + return drawables.iterator(); + } + + /** Sets a flag causing this Animator to ignore exceptions produced + while redrawing the drawables. By default this flag is set to + false, causing any exception thrown to halt the Animator. */ + public void setIgnoreExceptions(boolean ignoreExceptions) { + this.ignoreExceptions = ignoreExceptions; + } + + /** Sets a flag indicating that when exceptions are being ignored by + this Animator (see {@link #setIgnoreExceptions}), to print the + exceptions' stack traces for diagnostic information. Defaults to + false. */ + public void setPrintExceptions(boolean printExceptions) { + 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) { + } + } + + class MainLoop implements Runnable { + public void run() { + try { + while (!shouldStop) { + // Don't consume CPU unless there is work to be done + if (drawables.size() == 0) { + synchronized (Animator.this) { + while (drawables.size() == 0 && !shouldStop) { + try { + Animator.this.wait(); + } catch (InterruptedException e) { + } + } + } + } + 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); + } + } + } + sync(); + } + } finally { + shouldStop = false; + synchronized (Animator.this) { + thread = null; + Animator.this.notify(); + } + } + } } /** Starts this animator. */ @@ -76,33 +166,19 @@ public class Animator { throw new GLException("Already started"); } if (runnable == null) { - runnable = new Runnable() { - public void run() { - boolean noException = false; - try { - while (!shouldStop) { - noException = false; - drawable.display(); - noException = true; - } - } finally { - shouldStop = false; - synchronized (Animator.this) { - thread = null; - Animator.this.notify(); - } - } - } - }; + runnable = new MainLoop(); } thread = new Thread(runnable); thread.start(); } - /** Stops this animator, blocking until the animation thread has - finished. */ + /** Stops this animator. In most situations this method blocks until + completion, except when called from the animation thread itself + or in some cases from an implementation-internal thread like the + AWT event queue thread. */ public synchronized void stop() { shouldStop = true; + notifyAll(); // It's hard to tell whether the thread which calls stop() has // dependencies on the Animator's internal thread. Currently we // use a couple of heuristics to determine whether we should do diff --git a/src/net/java/games/jogl/FPSAnimator.java b/src/net/java/games/jogl/FPSAnimator.java new file mode 100755 index 000000000..cbe8b3571 --- /dev/null +++ b/src/net/java/games/jogl/FPSAnimator.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN + * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR + * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR + * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR + * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR + * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE + * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, + * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF + * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use + * in the design, construction, operation or maintenance of any nuclear + * facility. + * + * Sun gratefully acknowledges that this software was originally authored + * and developed by Kenneth Bradley Russell and Christopher John Kline. + */ + +package net.java.games.jogl; + +import java.util.*; + +/** An Animator subclass which attempts to achieve a target + frames-per-second rate to avoid using all CPU time. The target FPS + is only an estimate and is not guaranteed. */ + +public class FPSAnimator extends Animator { + private Timer timer; + private int fps; + + /** Creates an FPSAnimator with a given target frames-per-second value. */ + public FPSAnimator(int fps) { + this(null, fps); + } + + /** Creates an FPSAnimator with a given target frames-per-second + value and an initial drawable to animate. */ + public FPSAnimator(GLAutoDrawable drawable, int fps) { + this.fps = fps; + if (drawable != null) { + add(drawable); + } + } + + /** Starts this FPSAnimator. */ + public synchronized void start() { + if (timer != null) { + throw new GLException("Already started"); + } + 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(); + } + } + }, 0, delay); + } + + /** Stops this FPSAnimator. Due to the implementation of the + FPSAnimator it is not guaranteed that the FPSAnimator will be + completely stopped by the time this method returns. */ + public synchronized void stop() { + if (timer == null) { + throw new GLException("Already stopped"); + } + timer.cancel(); + timer = null; + } +} |