/** * @(#) GLAnimJPanel.java */ package gl4java.swing; import gl4java.GLContext; import java.awt.*; import java.awt.event.*; import java.lang.Math; /** * This is meant as an base class writing * Animations. A clean usage of multi-threading compatible * with JAVA2 is implemented here ! * *
* * If you are interessting in further Documentation and/or * the history of GL4Java follow the following link. * *
The GL4Java Documentation ** *
* There are two ways of using a GLAnimJPanel: the {@link * gl4java.GLEventListener} model or the subclassing model. Earlier * versions of the system only supported the subclassing model. The * default implementations of {@link #init}, {@link #display}, * {@link #reshape} and {@link #doCleanup} * now send events to GLEventListeners; they can * still be overridden as before to support the subclassing model. * *
* If using the subclassing model, you should override the following * methods for your needs: *
init - 1st initialisation display - render one frame reshape - to reshape (window resize) ReInit - ReInitialisation after stop for setSuspended(false) **
* * This code uses repaint() to fire a sDisplay call by the AWT-Event thread ! * and sleep to suspend for a given Frames per secounds value as default !! * * To switch this behavior for a better performance, and responsiveness * so that sDisplay is called by the animation thread itself * call: * *
setUseRepaint(false) **
* * This code sleep's for a given Frames per secounds after each frame * as default !! * * To switch this behavior for a better performance, * so that much frames are rendered as the machine can do ! * call: * *
setUseFpsSleep(false) **
* But be sure, that the other threads may not have enough time or i * may not get the cpu power ... * * The following settings for setUseRepaint and setUseFpsSleep looks fine: * *
A JVM with operating system threads has: native-threads
A JVM where all JVM threads runs in one operating-system-thread has: green-threads
green-threads | native-threads | |
---|---|---|
setUseRepaint
| true
| true & false
|
setUseFpsSleep
| true
| true & false
|
* To use real fps settings, the following functions provides you to do so: *
setAnimateFps getMaxFps ** Like the first animation run, this class renders a view frames (default 10) * to subtract the render time from the sleep time ! * * @see gl4java.awt.GLCanvas * @version 2.0, 21. April 1999 * @author Sven Goethel * */ public class GLAnimJPanel extends GLJPanel implements Runnable { /** * To support frames per scounds, * instead of killing the machine :-) * * A little GUI is supported ! * * @see gl4java.swing.GLAnimJPanel#run */ protected double FramesPerSec=20; protected long mSecPerFrame=0; /** * the delays .. */ protected long dFpsMilli = 0; /** * The thread for referencing Thread (Animation) * * @see gl4java.swing.GLAnimJPanel#stop * @see gl4java.swing.GLAnimJPanel#start * @see gl4java.swing.GLAnimJPanel#run */ protected Thread killme = null; /** * Instead of using suspend (JAVA2) * * @see gl4java.swing.GLAnimJPanel#run */ protected boolean threadSuspended = false; static { if(GLContext.loadNativeLibraries(null, null, null)==false) System.out.println("GLAnimJPanel could not load def. native libs."); } /** * * Constructor * * @param gl_Name The name of the GLFunc implementation * If gl_Name==null, the default class will be used ! * * @param glu_Name The name of the GLUFunc implementation * If gl_LibName==null, the default class will be used ! * * @param layout the layout manager * @param isDoubleBuffered the flag indicates, * if double buffer should be used * */ public GLAnimJPanel( String gl_Name, String glu_Name, LayoutManager layout, boolean isDoubleBuffered ) { super( gl_Name, glu_Name, layout, isDoubleBuffered ); setAnimateFps(FramesPerSec); } /** * * Constructor * * @param layout the layout manager * @param isDoubleBuffered the flag indicates, * if double buffer should be used * */ public GLAnimJPanel( LayoutManager layout, boolean isDoubleBuffered ) { super(layout, isDoubleBuffered); setAnimateFps(FramesPerSec); } /** * * Constructor * * Uses the default GLFunc and GLUFunc implementation ! * * @param isDoubleBuffered the flag indicates, * if double buffer should be used */ public GLAnimJPanel( boolean isDoubleBuffered ) { super(isDoubleBuffered); setAnimateFps(FramesPerSec); } /** * * Constructor * * Uses the default GLFunc and GLUFunc implementation ! * * @param layout the layout manager */ public GLAnimJPanel(LayoutManager layout) { super(layout); setAnimateFps(FramesPerSec); } /** * * Constructor * * Uses the default GLFunc and GLUFunc implementation ! * * @see gl4java.awt.GLCanvas#GLCanvas * */ public GLAnimJPanel( ) { super(); setAnimateFps(FramesPerSec); } /** * ReInit should be overwritten by you, * to enter your re-initialisation within setSuspended(false) * * @see gl4java.swing.GLAnimJPanel#setSuspended */ public void ReInit() { } protected boolean useRepaint = true; protected boolean useFpsSleep = true; /** * The normal behavior is to use 'repaint' * within the AWT-Event Thread to render. *
* If you have serious reasons, e.g. measuring performance, * you can change it while invoke this function with 'false'. * In this case, the thread itself calls the sDisplay method ! * * On fast good multi-threading machines (native-thread-JVM), * this should increase the performance and the responsiveness ! *
* * @param b if true, uses repaint (default), otherwise directly sDisplay * @see gl4java.awt.GLAnimCanvas#sDisplay * @see gl4java.swing.GLAnimJPanel#setUseFpsSleep */ public void setUseRepaint(boolean b) { useRepaint = b; } /** * The normal behavior is to use FpsSleep * * But you can overwrite this behavior and * drop the Frame Per Secound sleeps - * so that much frames are rendered as the machine can do ! *
* * @param b if true, uses Fps sleeping, else not ! * @see gl4java.awt.GLAnimCanvas#sDisplay * @see gl4java.swing.GLAnimJPanel#setUseRepaint */ public void setUseFpsSleep(boolean b) { useFpsSleep = b; } public boolean getUseRepaint() { return useRepaint; } public boolean getUseFpsSleep() { return useFpsSleep; } /** * HERE WE DO HAVE OUR RUNNING THREAD ! * WE NEED STUFF LIKE THAT FOR ANIMATION ;-) */ public void start() { if(killme == null) { killme = new Thread(this); killme.start(); resetFpsCounter(); } } public synchronized void stop() { killme = null; threadSuspended=false; notify(); } protected boolean shallWeRender = true; private long _fDelay = 0; private long _fDelay_Frames = 10; private boolean _fDelaySync=true; private boolean _fDelayRun=false; /** * The running loop for animations * which initiates the call of display * * @see gl4java.swing.GLAnimJPanel#setSuspended * @see gl4java.swing.GLAnimJPanel#display */ public void run() { Thread thisThread = Thread.currentThread(); while (killme==thisThread) { if(cvsIsInit()) { /* DRAW THE TINGS .. */ if (shallWeRender) { if(useRepaint) repaint(); else sDisplay(); } else { // lets sleep ... synchronized (this) { threadSuspended=true; } } if(fps_isCounting) fps_frames++; } try { if(useFpsSleep) { if(useRepaint) { if(mSecPerFrame<_f_dur_total) dFpsMilli=_f_dur_total; else dFpsMilli=mSecPerFrame; } else { dFpsMilli= mSecPerFrame - _f_dur_total; if (dFpsMilli<=0) dFpsMilli= 1; } Thread.currentThread().sleep(dFpsMilli, 0 ); } if (threadSuspended) { stopFpsCounter(); synchronized (this) { while (threadSuspended) wait(); } } } catch (InterruptedException e) {} } } /** * Here we can (re)start or suspend animation ... * * If the thread should be (re)started and is not alive -> killed, * or never be started, it will be started ! * * @param suspend if true the thread will be suspended, * if false, the thread will be (re)started * * @see gl4java.swing.GLAnimJPanel#isAlive * @see gl4java.swing.GLAnimJPanel#start */ public void setSuspended(boolean suspend) { setSuspended(suspend, false); } /** * Here we can (re)start or suspend animation ... * * If the thread should be (re)started and is not alive -> killed, * or never be started, it will be started ! * * @param suspend if true the thread will be suspended, * if false, the thread will be (re)started * * @param reInit if true the ReInit will be called additionally, * where the user can set additional initialisations * * @see gl4java.swing.GLAnimJPanel#isAlive * @see gl4java.swing.GLAnimJPanel#start */ public synchronized void setSuspended(boolean suspend, boolean reInit) { if(suspend) { shallWeRender=false; } else if(isAlive()==false) { start(); } else { // the thread is alive, but suspended and should be // re-started shallWeRender=true; resetFpsCounter(); if(reInit) ReInit(); threadSuspended=false; notify(); } } /** * is the thread alive, means is started and not died ? * * @see gl4java.swing.GLAnimJPanel#run * @see gl4java.swing.GLAnimJPanel#setSuspended * @see gl4java.swing.GLAnimJPanel#start * @see gl4java.swing.GLAnimJPanel#stop */ public boolean isAlive() { if(killme==null) return false; return killme.isAlive(); } /** * is the thread suspended, means is started but waiting, * or not alive (ok :-| - but it is practical) * * @see gl4java.swing.GLAnimJPanel#run * @see gl4java.swing.GLAnimJPanel#setSuspended * @see gl4java.swing.GLAnimJPanel#start * @see gl4java.swing.GLAnimJPanel#stop */ public boolean isSuspended() { if(killme==null) return true; return threadSuspended; } private double fps=0; // frame-per-sec private long fps_duration =0; // milli-secs private long fps_start=0; // milli-secs private long fps_frames =0; // number of frames private boolean fps_isCounting =true; // shall i count private boolean verboseFps =true; // shall i be verbose /** * resets the Fps Counter *
* this function is called automatically by * start and setSuspended * * @see gl4java.swing.GLAnimJPanel#start * @see gl4java.swing.GLAnimJPanel#setSuspended * @see gl4java.swing.GLAnimJPanel#resetFpsCounter * @see gl4java.swing.GLAnimJPanel#stopFpsCounter * @see gl4java.swing.GLAnimJPanel#getFps * @see gl4java.swing.GLAnimJPanel#getFpsDuration * @see gl4java.swing.GLAnimJPanel#getFpsFrames * @see gl4java.swing.GLAnimJPanel#setVerboseFps */ public void resetFpsCounter() { fps=0; // frame-per-sec fps_duration =0; // milli-secs fps_frames =0; // number of frames fps_isCounting =true; // shall i count fps_start=System.currentTimeMillis(); } /** * stops the Fps Counter and sets all values * fot the getFps* methods *
* this function is called automatically by * run, if the thread is suspended via setSuspended *
* All data's are print out on System.out * if verboseFps is set ! * * @see gl4java.swing.GLAnimJPanel#run * @see gl4java.swing.GLAnimJPanel#setSuspended * @see gl4java.swing.GLAnimJPanel#resetFpsCounter * @see gl4java.swing.GLAnimJPanel#stopFpsCounter * @see gl4java.swing.GLAnimJPanel#getFps * @see gl4java.swing.GLAnimJPanel#getFpsDuration * @see gl4java.swing.GLAnimJPanel#getFpsFrames * @see gl4java.swing.GLAnimJPanel#setVerboseFps */ public void stopFpsCounter() { if(fps_isCounting==true) { long fps_end=System.currentTimeMillis(); fps_duration = fps_end-fps_start; double timed= ((double)fps_duration)/1000.0; if(timed==0) timed=1.0; fps = ((double)fps_frames)/timed ; fps_isCounting=false; } if(verboseFps) { System.out.println("\nfps = "+String.valueOf(fps)); System.out.println("time = "+String.valueOf(fps_duration)+" ms"); System.out.println("frames = "+String.valueOf(fps_frames)); if(fps_frames==0) fps_frames=1; System.out.println("time/f = "+String.valueOf(fps_duration/fps_frames)+" ms"); } } /** * sets if the Fps data shall be printed to System.out * while stopFpsCounter is called ! *
* verboseFps is set to true by default ! * * @see gl4java.swing.GLAnimJPanel#run * @see gl4java.swing.GLAnimJPanel#setSuspended * @see gl4java.swing.GLAnimJPanel#resetFpsCounter * @see gl4java.swing.GLAnimJPanel#stopFpsCounter * @see gl4java.swing.GLAnimJPanel#getFps * @see gl4java.swing.GLAnimJPanel#getFpsDuration * @see gl4java.swing.GLAnimJPanel#getFpsFrames * @see gl4java.swing.GLAnimJPanel#setVerboseFps */ public void setVerboseFps(boolean v) { verboseFps=v; } /** * returns the calculated frames per secounds *
* this data is avaiable after calling stopFpsCounter * * @see gl4java.swing.GLAnimJPanel#resetFpsCounter * @see gl4java.swing.GLAnimJPanel#stopFpsCounter * @see gl4java.swing.GLAnimJPanel#getFps * @see gl4java.swing.GLAnimJPanel#getFpsDuration * @see gl4java.swing.GLAnimJPanel#getFpsFrames * @see gl4java.swing.GLAnimJPanel#setVerboseFps */ public double getFps() { return fps; } /** * returns the calculated duration in millisecs *
* this data is avaiable after calling stopFpsCounter * * @see gl4java.swing.GLAnimJPanel#resetFpsCounter * @see gl4java.swing.GLAnimJPanel#stopFpsCounter * @see gl4java.swing.GLAnimJPanel#getFps * @see gl4java.swing.GLAnimJPanel#getFpsDuration * @see gl4java.swing.GLAnimJPanel#getFpsFrames * @see gl4java.swing.GLAnimJPanel#setVerboseFps */ public long getFpsDuration() { return fps_duration; } /** * returns the calculated frames number *
* this data is avaiable after calling stopFpsCounter * * @see gl4java.swing.GLAnimJPanel#resetFpsCounter * @see gl4java.swing.GLAnimJPanel#stopFpsCounter * @see gl4java.swing.GLAnimJPanel#getFps * @see gl4java.swing.GLAnimJPanel#getFpsDuration * @see gl4java.swing.GLAnimJPanel#getFpsFrames * @see gl4java.swing.GLAnimJPanel#setVerboseFps */ public long getFpsFrames() { return fps_frames; } /** * Just set the FramePerSecounds for Animation * * @deprecated Now the frames per seconds are allways * calculated, no pre-sync needed. * @see #setAnimateFps(double) */ public void setAnimateFps(double fps, int synFrames) { setAnimateFps(fps); } /** * Just set the FramePerSecounds for Animation * * @see gl4java.swing.GLAnimJPanel#getMaxFps */ public void setAnimateFps(double fps) { FramesPerSec=fps; mSecPerFrame = (long) ( (1.0/FramesPerSec) * 1000.0 ) ; if(verboseFps) { System.out.println("\nset fps := "+ String.valueOf(fps)+ " -> "+String.valueOf(mSecPerFrame)+ " [ms/frame]" ); } resetFpsCounter(); } /** * Just get the maximum number of Frames per secounds, * which is calculated with the time, one frame needs to render ! * * this value is avaiable after the thread is started * and the first frames are rendered ! * * @see gl4java.swing.GLAnimJPanel#setAnimateFps */ public double getMaxFps() { return (1.0/(double)_f_dur_total)*1000.0; } }