Posted by
BrickFarmer on
Mar 05, 2011; 3:37pm
URL: https://forum.jogamp.org/1-5-FPS-Animator-tp2638305.html
Now that JOGL is moving towards 1.5 Yipee! I thought I'd share my FPS animator I've been using recently. You can toggle between current implementation and this new one with the boolean at the top of the code 'useOwnAnimator'. I wrote this primarily when JOGL was having some concurrency issues adding and removing drawables from animators (since fixed). However I've still been using this implementation which I find gives a smoother frame rate, ymmv.
For me, when I zoom out to show my whole game world, and hold a rotate key down, I can really see the difference between the two implementations. With gl.setSwapInterval(1) also set it's even smoother! but then my 1st person mode seems to fail with mouse detection - work in progress :)
Peter
PS. tested under latest OSX with GLCanvs only
package com.brickfarmer.gameclient.widgets;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import javax.media.opengl.GLAutoDrawable;
import com.jogamp.opengl.util.Animator;
import com.jogamp.opengl.util.AnimatorBase;
import com.jogamp.opengl.util.FPSAnimator;
public final class WHAnimator {
private static final boolean useOwnAnimator = true;
private static final int fpsReportingPeriodSeconds = 5;
private final CopyOnWriteArraySet<GLAutoDrawable> drawables = new CopyOnWriteArraySet<GLAutoDrawable>();
private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
private final ScheduledExecutorService fpsCounter = Executors.newSingleThreadScheduledExecutor();
private final int delayBetweenFramesMicroSeconds;
private final AtomicBoolean animating = new AtomicBoolean(false);
private final AtomicInteger frames = new AtomicInteger(0);
private final AtomicInteger fps = new AtomicInteger(0);
//old animator
private AnimatorBase animator;
private final AtomicInteger lastFrameCount = new AtomicInteger(0);
Runnable displayJob = new Runnable() {
public void run() {
try {
frames.incrementAndGet();
for (GLAutoDrawable drawable : drawables) {
drawable.display();
}
} catch (RuntimeException r) {
r.printStackTrace();
}
}
};
Runnable fpsJob = new Runnable() {
public void run() {
int frameCount;
if (useOwnAnimator) {
frameCount = frames.getAndSet(0);
} else {
int newFrameCount = animator.getTotalFrames();
frameCount = newFrameCount - lastFrameCount.getAndSet(newFrameCount);
}
fps.set(frameCount/fpsReportingPeriodSeconds);
System.out.println("Animator: "+drawables.size()+" scenes. "+frameCount+" frames in "+fpsReportingPeriodSeconds+"s. "+fps.get()+"fps");
}
};
/**
* Animate as fast as possible
*/
public WHAnimator() {
delayBetweenFramesMicroSeconds = 1;
if (!useOwnAnimator) {
animator = new Animator();
}
}
/**
* @param targetFramerate 60 means 60fps
*/
public WHAnimator(final int targetFramerate) {
delayBetweenFramesMicroSeconds = 1000000/targetFramerate;
//System.out.println("delay between frames: "+delayBetweenFrames);
if (!useOwnAnimator) {
animator = new FPSAnimator(targetFramerate, true);
}
}
public void add(final GLAutoDrawable drawable) {
if (useOwnAnimator) {
drawables.add(drawable);
} else {
animator.add(drawable);
}
}
public void remove(final GLAutoDrawable drawable) {
if (useOwnAnimator) {
drawables.remove(drawable);
} else {
animator.remove(drawable);
}
}
public void start() {
fpsCounter.scheduleAtFixedRate(fpsJob, 0, fpsReportingPeriodSeconds, TimeUnit.SECONDS);
if (useOwnAnimator) {
scheduler.scheduleAtFixedRate(displayJob, 0, delayBetweenFramesMicroSeconds, TimeUnit.MICROSECONDS);
} else {
animator.start();
}
animating.set(true);
}
public void stop() {
if (useOwnAnimator) {
} else {
animator.stop();
}
animating.set(false);
}
public boolean isAnimating() {
return (useOwnAnimator) ? animating.get() : animator.isAnimating();
}
public int getFps() {
return fps.get();
}
}