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.java289
1 files changed, 123 insertions, 166 deletions
diff --git a/src/jogl/classes/com/jogamp/opengl/util/Animator.java b/src/jogl/classes/com/jogamp/opengl/util/Animator.java
index 20ba27c16..799069292 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/Animator.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/Animator.java
@@ -1,22 +1,22 @@
/*
* 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
* 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
@@ -29,11 +29,11 @@
* 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.
*/
@@ -41,7 +41,7 @@
package com.jogamp.opengl.util;
import javax.media.opengl.GLAutoDrawable;
-
+import javax.media.opengl.GLException;
/** <P> An Animator can be attached to one or more {@link
GLAutoDrawable}s to drive their display() methods in a loop. </P>
@@ -56,12 +56,8 @@ import javax.media.opengl.GLAutoDrawable;
* so it is able to keep an application from terminating.<br>
* Call {@link #stop() } to terminate the animation and it's execution thread.
* </p>
-*/
-
+ */
public class Animator extends AnimatorBase {
- /** timeout in milliseconds, 15 frames @ 60Hz = 240ms, limiting {@link #finishLifecycleAction(Condition)} */
- private static final long TO_WAIT_FOR_FINISH_LIFECYCLE_ACTION = 15*16;
-
protected ThreadGroup threadGroup;
private Runnable runnable;
private boolean runAsFastAsPossible;
@@ -69,6 +65,9 @@ public class Animator extends AnimatorBase {
protected boolean pauseIssued;
protected volatile boolean stopIssued;
+ /**
+ * Creates a new, empty Animator.
+ */
public Animator() {
super();
if(DEBUG) {
@@ -76,28 +75,42 @@ public class Animator extends AnimatorBase {
}
}
+ /**
+ * Creates a new Animator w/ an associated ThreadGroup.
+ */
public Animator(ThreadGroup tg) {
super();
- threadGroup = tg;
-
+ setThreadGroup(tg);
if(DEBUG) {
System.err.println("Animator created, ThreadGroup: "+threadGroup);
}
}
- /** Creates a new Animator for a particular drawable. */
+ /**
+ * Creates a new Animator for a particular drawable.
+ */
public Animator(GLAutoDrawable drawable) {
super();
add(drawable);
+ if(DEBUG) {
+ System.err.println("Animator created, w/ "+drawable);
+ }
}
- /** Creates a new Animator for a particular drawable. */
+ /**
+ * Creates a new Animator w/ an associated ThreadGroup for a particular drawable.
+ */
public Animator(ThreadGroup tg, GLAutoDrawable drawable) {
- this(tg);
+ super();
+ setThreadGroup(tg);
add(drawable);
+ if(DEBUG) {
+ System.err.println("Animator created, ThreadGroup: "+threadGroup+" and "+drawable);
+ }
}
- protected String getBaseName(String prefix) {
+ @Override
+ protected final String getBaseName(String prefix) {
return prefix + "Animator" ;
}
@@ -107,68 +120,67 @@ public class Animator extends AnimatorBase {
* animation loop which prevents the CPU from getting swamped.
* This method may not have an effect on subclasses.
*/
- public final void setRunAsFastAsPossible(boolean runFast) {
- stateSync.lock();
- try {
- runAsFastAsPossible = runFast;
- } finally {
- stateSync.unlock();
- }
- }
-
- private final void setIsAnimatingSynced(boolean v) {
- stateSync.lock();
- try {
- isAnimating = v;
- } finally {
- stateSync.unlock();
- }
+ public final synchronized void setRunAsFastAsPossible(boolean runFast) {
+ runAsFastAsPossible = runFast;
}
class MainLoop implements Runnable {
+ @Override
public String toString() {
- return "[started "+isStartedImpl()+", animating "+isAnimatingImpl()+", paused "+isPausedImpl()+", drawable "+drawables.size()+"]";
+ return "[started "+isStarted()+", animating "+isAnimating()+", paused "+isPaused()+", drawable "+drawables.size()+", drawablesEmpty "+drawablesEmpty+"]";
}
+ @Override
public void run() {
try {
synchronized (Animator.this) {
if(DEBUG) {
- System.err.println("Animator start:" + Thread.currentThread() + ": " + toString());
+ System.err.println("Animator start on " + getThreadName() + ": " + toString());
}
fpsCounter.resetFPSCounter();
animThread = Thread.currentThread();
- setIsAnimatingSynced(false); // barrier
- Animator.this.notifyAll();
+ isAnimating = false;
+ // 'waitForStartedCondition' wake-up is handled below!
}
while (!stopIssued) {
synchronized (Animator.this) {
- // Don't consume CPU unless there is work to be done and not paused
+ // Pause; Also don't consume CPU unless there is work to be done and not paused
+ boolean ectCleared = false;
while (!stopIssued && (pauseIssued || drawablesEmpty)) {
+ if( drawablesEmpty ) {
+ pauseIssued = true;
+ }
boolean wasPaused = pauseIssued;
if (DEBUG) {
- System.err.println("Animator pause:" + Thread.currentThread() + ": " + toString());
+ System.err.println("Animator pause on " + animThread.getName() + ": " + toString());
+ }
+ if ( exclusiveContext && !drawablesEmpty && !ectCleared ) {
+ ectCleared = true;
+ setDrawablesExclCtxState(false);
+ display(); // propagate exclusive change!
}
- setIsAnimatingSynced(false); // barrier
+ isAnimating = false;
Animator.this.notifyAll();
try {
Animator.this.wait();
} catch (InterruptedException e) {
}
-
if (wasPaused) {
// resume from pause -> reset counter
fpsCounter.resetFPSCounter();
if (DEBUG) {
- System.err.println("Animator resume:" + Thread.currentThread() + ": " + toString());
+ System.err.println("Animator resume on " + animThread.getName() + ": " + toString());
}
}
}
if (!stopIssued && !isAnimating) {
- // resume from pause or drawablesEmpty,
+ // Wakes up 'waitForStartedCondition' sync
+ // - and -
+ // Resume from pause or drawablesEmpty,
// implies !pauseIssued and !drawablesEmpty
- setIsAnimatingSynced(true);
+ isAnimating = true;
+ setDrawablesExclCtxState(exclusiveContext);
Animator.this.notifyAll();
}
} // sync Animator.this
@@ -180,179 +192,124 @@ public class Animator extends AnimatorBase {
Thread.yield();
}
}
+ } catch( ThreadDeath td) {
+ if(DEBUG) {
+ System.err.println("Animator Catched: "+td.getClass().getName()+": "+td.getMessage());
+ td.printStackTrace();
+ }
} finally {
+ if( exclusiveContext && !drawablesEmpty ) {
+ setDrawablesExclCtxState(false);
+ display(); // propagate exclusive change!
+ }
synchronized (Animator.this) {
if(DEBUG) {
- System.err.println("Animator stop " + Thread.currentThread() + ": " + toString());
+ System.err.println("Animator stop on " + animThread.getName() + ": " + toString());
}
stopIssued = false;
pauseIssued = false;
animThread = null;
- setIsAnimatingSynced(false); // barrier
+ isAnimating = false;
Animator.this.notifyAll();
}
}
}
}
- private final boolean isStartedImpl() {
- return animThread != null ;
- }
- public final boolean isStarted() {
- stateSync.lock();
- try {
- return animThread != null ;
- } finally {
- stateSync.unlock();
- }
- }
-
- private final boolean isAnimatingImpl() {
+ @Override
+ public final synchronized boolean isAnimating() {
return animThread != null && isAnimating ;
}
- public final boolean isAnimating() {
- stateSync.lock();
- try {
- return animThread != null && isAnimating ;
- } finally {
- stateSync.unlock();
- }
- }
- private final boolean isPausedImpl() {
+ @Override
+ public final synchronized boolean isPaused() {
return animThread != null && pauseIssued ;
}
- public final boolean isPaused() {
- stateSync.lock();
- try {
- return animThread != null && pauseIssued ;
- } finally {
- stateSync.unlock();
- }
- }
-
- interface Condition {
- /**
- * @return true if branching (cont waiting, action), otherwise false
- */
- boolean result();
- }
- private synchronized void finishLifecycleAction(Condition condition) {
- // It's hard to tell whether the thread which changes the lifecycle has
- // dependencies on the Animator's internal thread. Currently we
- // use a couple of heuristics to determine whether we should do
- // the blocking wait().
- final boolean blocking = impl.blockUntilDone(animThread);
- long remaining = blocking ? TO_WAIT_FOR_FINISH_LIFECYCLE_ACTION : 0;
- while (remaining>0 && condition.result()) {
- long td = System.currentTimeMillis();
- try {
- wait(remaining);
- } catch (InterruptedException ie) { }
- remaining -= (System.currentTimeMillis() - td) ;
- }
- if(DEBUG) {
- if(remaining<0) {
- System.err.println("finishLifecycleAction(" + condition.getClass().getName() + "): ++++++ timeout reached ++++++ " + Thread.currentThread().getName());
- }
- System.err.println("finishLifecycleAction(" + condition.getClass().getName() + "): finished "+
- "- blocking "+blocking+
- ", waited " + (blocking ? ( TO_WAIT_FOR_FINISH_LIFECYCLE_ACTION - remaining ) : 0 ) + "/" + TO_WAIT_FOR_FINISH_LIFECYCLE_ACTION +
- ", started: " + isStartedImpl() +", animating: " + isAnimatingImpl() +
- ", paused: " + isPausedImpl() + ", drawables " + drawables.size() + " - " + Thread.currentThread().getName());
+ /**
+ * Set a {@link ThreadGroup} for the {@link #getThread() animation thread}.
+ *
+ * @param tg the {@link ThreadGroup}
+ * @throws GLException if the animator has already been started
+ */
+ public final synchronized void setThreadGroup(ThreadGroup tg) throws GLException {
+ if ( isStarted() ) {
+ throw new GLException("Animator already started.");
}
+ threadGroup = tg;
}
- public synchronized boolean start() {
- if ( isStartedImpl() ) {
+ @Override
+ public final synchronized boolean start() {
+ if ( isStarted() ) {
return false;
}
if (runnable == null) {
runnable = new MainLoop();
}
fpsCounter.resetFPSCounter();
- String threadName = Thread.currentThread().getName()+"-"+baseName;
+ String threadName = getThreadName()+"-"+baseName;
Thread thread;
if(null==threadGroup) {
thread = new Thread(runnable, threadName);
} else {
thread = new Thread(threadGroup, runnable, threadName);
}
- thread.setDaemon(false); // force to be non daemon, regardless of parent thread
+ thread.setDaemon(false); // force to be non daemon, regardless of parent thread
if(DEBUG) {
final Thread ct = Thread.currentThread();
System.err.println("Animator "+ct.getName()+"[daemon "+ct.isDaemon()+"]: starting "+thread.getName()+"[daemon "+thread.isDaemon()+"]");
}
thread.start();
- finishLifecycleAction(waitForStartedCondition);
- return true;
+ return finishLifecycleAction(waitForStartedCondition, 0);
}
+ private final Condition waitForStartedCondition = new Condition() {
+ @Override
+ public boolean eval() {
+ return !isStarted() || (!drawablesEmpty && !isAnimating) ;
+ } };
- private class WaitForStartedCondition implements Condition {
- public boolean result() {
- return !isStartedImpl() || (!drawablesEmpty && !isAnimating) ;
- }
- }
- Condition waitForStartedCondition = new WaitForStartedCondition();
-
- public synchronized boolean stop() {
- if ( !isStartedImpl() ) {
+ @Override
+ public final synchronized boolean stop() {
+ if ( !isStarted() ) {
return false;
}
stopIssued = true;
- notifyAll();
- finishLifecycleAction(waitForStoppedCondition);
- return true;
- }
- private class WaitForStoppedCondition implements Condition {
- public boolean result() {
- return isStartedImpl();
- }
+ return finishLifecycleAction(waitForStoppedCondition, 0);
}
- Condition waitForStoppedCondition = new WaitForStoppedCondition();
+ private final Condition waitForStoppedCondition = new Condition() {
+ @Override
+ public boolean eval() {
+ return isStarted();
+ } };
- public synchronized boolean pause() {
- if ( !isStartedImpl() || pauseIssued ) {
+ @Override
+ public final synchronized boolean pause() {
+ if ( !isStarted() || pauseIssued ) {
return false;
}
- stateSync.lock();
- try {
- pauseIssued = true;
- } finally {
- stateSync.unlock();
- }
- notifyAll();
- finishLifecycleAction(waitForPausedCondition);
- return true;
+ pauseIssued = true;
+ return finishLifecycleAction(waitForPausedCondition, 0);
}
- private class WaitForPausedCondition implements Condition {
- public boolean result() {
+ private final Condition waitForPausedCondition = new Condition() {
+ @Override
+ public boolean eval() {
// end waiting if stopped as well
- return isAnimating && isStartedImpl();
- }
- }
- Condition waitForPausedCondition = new WaitForPausedCondition();
+ return isStarted() && isAnimating;
+ } };
- public synchronized boolean resume() {
- if ( !isStartedImpl() || !pauseIssued ) {
+ @Override
+ public final synchronized boolean resume() {
+ if ( !isStarted() || !pauseIssued ) {
return false;
}
- stateSync.lock();
- try {
- pauseIssued = false;
- } finally {
- stateSync.unlock();
- }
- notifyAll();
- finishLifecycleAction(waitForResumeCondition);
- return true;
+ pauseIssued = false;
+ return finishLifecycleAction(waitForResumeCondition, 0);
}
- private class WaitForResumeCondition implements Condition {
- public boolean result() {
+ private final Condition waitForResumeCondition = new Condition() {
+ @Override
+ public boolean eval() {
// end waiting if stopped as well
- return !drawablesEmpty && !isAnimating && isStartedImpl();
- }
- }
- Condition waitForResumeCondition = new WaitForResumeCondition();
+ return isStarted() && ( !drawablesEmpty && !isAnimating || drawablesEmpty && !pauseIssued ) ;
+ } };
}