aboutsummaryrefslogtreecommitdiffstats
path: root/src/jogl/classes/com/jogamp/opengl/util/Animator.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/jogl/classes/com/jogamp/opengl/util/Animator.java')
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/Animator.java266
1 files changed, 146 insertions, 120 deletions
diff --git a/src/jogl/classes/com/jogamp/opengl/util/Animator.java b/src/jogl/classes/com/jogamp/opengl/util/Animator.java
index 66d3d5b88..5d48405e2 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/Animator.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/Animator.java
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright (c) 2010 JogAmp Community. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -39,12 +40,16 @@
package com.jogamp.opengl.util;
-import java.util.*;
-
-import javax.media.opengl.*;
+import javax.media.opengl.GLAnimatorControl;
+import javax.media.opengl.GLAutoDrawable;
+import javax.media.opengl.GLException;
+import javax.media.opengl.GLProfile;
import com.jogamp.opengl.impl.Debug;
+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>
@@ -54,44 +59,34 @@ import com.jogamp.opengl.impl.Debug;
CPU, unless {@link #setRunAsFastAsPossible} has been called. </P>
*/
-public class Animator {
- protected static final boolean DEBUG = Debug.debug("Animator");
+public class Animator extends AnimatorBase {
- private volatile ArrayList/*<GLAutoDrawable>*/ drawables = new ArrayList();
- private AnimatorImpl impl;
+ protected ThreadGroup threadGroup;
private Runnable runnable;
private boolean runAsFastAsPossible;
- protected ThreadGroup threadGroup;
- protected Thread thread;
+ protected volatile boolean isAnimating;
+ protected volatile boolean shouldPause;
protected volatile boolean shouldStop;
- protected boolean ignoreExceptions;
- protected boolean printExceptions;
-
- /** Creates a new, empty Animator. */
- public Animator(ThreadGroup tg) {
- if(GLProfile.isAWTAvailable()) {
- try {
- impl = (AnimatorImpl) Class.forName("com.jogamp.opengl.util.awt.AWTAnimatorImpl").newInstance();
- } catch (Exception e) { }
- }
- if(null==impl) {
- impl = new AnimatorImpl();
+ public Animator() {
+ super();
+ if(DEBUG) {
+ System.err.println("Animator created");
}
+ }
+
+ public Animator(ThreadGroup tg) {
+ super();
threadGroup = tg;
if(DEBUG) {
- System.out.println("Animator created, ThreadGroup: "+threadGroup);
+ System.err.println("Animator created, ThreadGroup: "+threadGroup);
}
}
- public Animator() {
- this((ThreadGroup)null);
- }
-
/** Creates a new Animator for a particular drawable. */
public Animator(GLAutoDrawable drawable) {
- this((ThreadGroup)null);
+ super();
add(drawable);
}
@@ -101,142 +96,131 @@ public class Animator {
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();
+ protected String getBaseName(String prefix) {
+ return prefix + "Animator" ;
}
- /** 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;
- }
-
- /** Sets a flag in this Animator indicating that it is to run as
- fast as possible. By default there is a brief pause in the
- animation loop which prevents the CPU from getting swamped.
- This method may not have an effect on subclasses. */
+ /**
+ * Sets a flag in this Animator indicating that it is to run as
+ * fast as possible. By default there is a brief pause in the
+ * animation loop which prevents the CPU from getting swamped.
+ * This method may not have an effect on subclasses.
+ */
public final void setRunAsFastAsPossible(boolean runFast) {
runAsFastAsPossible = runFast;
}
- /** 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() {
- impl.display(this, ignoreExceptions, printExceptions);
- }
-
- private long startTime = 0;
- private long curTime = 0;
- private int totalFrames = 0;
-
class MainLoop implements Runnable {
public void run() {
try {
if(DEBUG) {
- System.out.println("Animator started: "+Thread.currentThread());
+ System.err.println("Animator started: "+Thread.currentThread());
}
startTime = System.currentTimeMillis();
curTime = startTime;
+ totalFrames = 0;
+
+ synchronized (Animator.this) {
+ isAnimating = true;
+ Animator.this.notifyAll();
+ }
while (!shouldStop) {
- // Don't consume CPU unless there is work to be done
- if (drawables.size() == 0) {
+ // Don't consume CPU unless there is work to be done and not paused
+ if ( !shouldStop && ( shouldPause || drawables.size() == 0 ) ) {
synchronized (Animator.this) {
- while (drawables.size() == 0 && !shouldStop) {
+ boolean wasPaused = false;
+ while ( !shouldStop && ( shouldPause || drawables.size() == 0 ) ) {
+ if(DEBUG) {
+ System.err.println("Animator paused: "+Thread.currentThread());
+ }
+ isAnimating = false;
+ wasPaused = true;
+ Animator.this.notifyAll();
try {
Animator.this.wait();
} catch (InterruptedException e) {
}
}
+ if ( wasPaused ) {
+ startTime = System.currentTimeMillis();
+ curTime = startTime;
+ totalFrames = 0;
+ if(DEBUG) {
+ System.err.println("Animator resumed: "+Thread.currentThread());
+ }
+ isAnimating = true;
+ Animator.this.notifyAll();
+ }
}
}
- display();
- curTime = System.currentTimeMillis();
- totalFrames++;
- if (!runAsFastAsPossible) {
- // Avoid swamping the CPU
- Thread.yield();
+ if ( !shouldStop ) {
+ display();
+ if (!runAsFastAsPossible) {
+ // Avoid swamping the CPU
+ Thread.yield();
+ }
}
}
- if(DEBUG) {
- System.out.println("Animator stopped: "+Thread.currentThread());
- }
} finally {
- shouldStop = false;
synchronized (Animator.this) {
+ if(DEBUG) {
+ System.err.println("Animator stopped: "+Thread.currentThread());
+ }
+ shouldStop = false;
+ shouldPause = false;
thread = null;
- Animator.this.notify();
+ isAnimating = false;
+ Animator.this.notifyAll();
}
}
}
}
- public long getStartTime() { return startTime; }
- public long getCurrentTime() { return curTime; }
- public long getDuration() { return curTime-startTime; }
- public int getTotalFrames() { return totalFrames; }
+ public final synchronized boolean isStarted() {
+ return (thread != null);
+ }
+
+ public final synchronized boolean isAnimating() {
+ return (thread != null) && isAnimating;
+ }
+
+ public final synchronized boolean isPaused() {
+ return (thread != null) && shouldPause;
+ }
- /** Starts this animator. */
public synchronized void start() {
- if (thread != null) {
- throw new GLException("Already started");
+ boolean started = null != thread;
+ if ( started || isAnimating ) {
+ throw new GLException("Already running (started "+started+" (false), animating "+isAnimating+" (false))");
}
if (runnable == null) {
runnable = new MainLoop();
}
+ int id;
+ String threadName = Thread.currentThread().getName()+"-"+baseName;
if(null==threadGroup) {
- thread = new Thread(runnable);
+ thread = new Thread(runnable, threadName);
} else {
- thread = new Thread(threadGroup, runnable);
- }
- for(Iterator iter = drawables.iterator(); iter.hasNext(); ) {
- ((GLAutoDrawable) iter.next()).setAnimator(thread);
+ thread = new Thread(threadGroup, runnable, threadName);
}
thread.start();
- }
- /** Indicates whether this animator is currently running. This
- should only be used as a heuristic to applications because in
- some circumstances the Animator may be in the process of
- shutting down and this method will still return true. */
- public synchronized boolean isAnimating() {
- return (thread != null);
+ if (!impl.skipWaitForCompletion(thread)) {
+ while (!isAnimating && thread != null) {
+ try {
+ wait();
+ } catch (InterruptedException ie) {
+ }
+ }
+ }
}
- /** 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() {
+ boolean started = null != thread;
+ if ( !started || !isAnimating ) {
+ throw new GLException("Not running (started "+started+" (true), animating "+isAnimating+" (true) )");
+ }
shouldStop = true;
notifyAll();
@@ -244,16 +228,58 @@ public class Animator {
// dependencies on the Animator's internal thread. Currently we
// use a couple of heuristics to determine whether we should do
// the blocking wait().
- if (!impl.skipWaitForStop(thread)) {
- while (shouldStop && thread != null) {
+ if (!impl.skipWaitForCompletion(thread)) {
+ while (isAnimating && thread != null) {
try {
wait();
} catch (InterruptedException ie) {
}
}
}
- for(Iterator iter = drawables.iterator(); iter.hasNext(); ) {
- ((GLAutoDrawable) iter.next()).setAnimator(null);
+ }
+
+ public synchronized void pause() {
+ boolean started = null != thread;
+ if ( !started || !isAnimating || shouldPause ) {
+ throw new GLException("Invalid state (started "+started+" (true), animating "+isAnimating+" (true), paused "+shouldPause+" (false) )");
+ }
+ shouldPause = true;
+ notifyAll();
+
+ if (!impl.skipWaitForCompletion(thread)) {
+ while (isAnimating && thread != null) {
+ try {
+ wait();
+ } catch (InterruptedException ie) {
+ }
+ }
+ }
+ }
+
+ public synchronized void resume() {
+ boolean started = null != thread;
+ if ( !started || !shouldPause ) {
+ throw new GLException("Invalid state (started "+started+" (true), paused "+shouldPause+" (true) )");
+ }
+ shouldPause = false;
+ notifyAll();
+
+ if (!impl.skipWaitForCompletion(thread)) {
+ while (!isAnimating && thread != null) {
+ try {
+ wait();
+ } catch (InterruptedException ie) {
+ }
+ }
}
}
+
+ protected final boolean getShouldPause() {
+ return shouldPause;
+ }
+
+ protected final boolean getShouldStop() {
+ return shouldStop;
+ }
+
}