diff options
Diffstat (limited to 'gl4java/swing')
-rw-r--r-- | gl4java/swing/GLAnimJPanel.java | 720 | ||||
-rw-r--r-- | gl4java/swing/GLJPanel.java | 865 | ||||
-rw-r--r-- | gl4java/swing/GLJPanel.java,v | 959 | ||||
-rw-r--r-- | gl4java/swing/SimpleGLJApplet1.java | 292 |
4 files changed, 2836 insertions, 0 deletions
diff --git a/gl4java/swing/GLAnimJPanel.java b/gl4java/swing/GLAnimJPanel.java new file mode 100644 index 0000000..e9bdbdf --- /dev/null +++ b/gl4java/swing/GLAnimJPanel.java @@ -0,0 +1,720 @@ +/** + * @(#) 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 ! + * + * <p> + * + * If you are interessting in further Documentation and/or + * the history of GL4Java follow the following link. + * + * <pre> + <a href="../../GL4Java.html">The GL4Java Documentation</a> + * </pre> + * <p> + * + * 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: + * + * <pre> + <a href="GLAnimJPanel.html#setUseRepaint(boolean)">setUseRepaint(false)</a> + * </pre> + * <p> + * + * 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: + * + * <pre> + <a href="GLAnimJPanel.html#setUseFpsSleep(boolean)">setUseFpsSleep(false)</a> + * </pre> + * <p> + * 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: + * + * <pre> + <p> + A JVM with operating system threads has: <b>native-threads</b> + <p> + A JVM where all JVM threads runs in one operating-system-thread + has: <b>green-threads</b> + + <a name="table"> + <table border> + <tr> + <th><th>green-threads<th>native-threads + <tr> + <td align=center><a href="GLAnimJPanel.html#setUseRepaint(boolean)"><code>setUseRepaint</code></a> + <td align=center><code>true</code> + <td align=center><code> true & false </code> + <tr> + <td align=center><a href="GLAnimJPanel.html#setUseFpsSleep(boolean)"><code>setUseFpsSleep</code></a> + <td align=center><code>true</code> + <td align=center><code> true & false </code> + + </table> + </a> + * </pre> + * + * If you play with setUseRepaint or setUseFpsSleep, + * be shure to have a Java VM with native-thread support, + * because a GL-Context can be shared by many threads, + * but one thread can have just one GL-Context ! + * + * (comments welcome) + * + * <p> + * To use real fps settings, the following functions provides you to do so: + * <pre> + <a href="GLAnimJPanel.html#setAnimateFps(double, int)">setAnimateFps</a> + <a href="GLAnimJPanel.html#getMaxFps()">getMaxFps</a> + * </pre> + * Like the first animation run, this class renders a view frames (default 10) + * to subtract the render time from the sleep time ! + * <p> + * You should overwrite the following methods for your needs: + * <pre> + <a href="GLAnimJPanel.html#init()">init - 1st initialisation</a> + <a href="GLAnimJPanel.html#display()">display - render one frame</a> + <a href="GLCanvas.html#reshape(int, int)">reshape - to reshape (window resize)</a> + <a href="GLAnimJPanel.html#ReInit()">ReInit - ReInitialisation after stop for setSuspended(false)</a> + * </pre> + * + * @see 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 GLAnimJPanel#run + */ + protected double FramesPerSec=20; + protected long mSecPerFrame=0; + + /** + * the delays .. + */ + protected long dFpsMilli = 0; + + /** + * The thread for referencing Thread (Animation) + * + * @see GLAnimJPanel#stop + * @see GLAnimJPanel#start + * @see GLAnimJPanel#run + */ + protected Thread killme = null; + + /** + * Instead of using suspend (JAVA2) + * + * @see 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 GLCanvas#GLCanvas + * + */ + public GLAnimJPanel( ) + { + super(); + setAnimateFps(FramesPerSec); + } + + /** + * init should be overwritten by you, + * to enter your initialisation code + * + */ + public void init() + { + /* here we should add and initialize our JAVA components */ + + /* ... and furthet OpenGL init's - like you want to */ + + glj.gljCheckGL(); + + ReInit(); + + /* and start our working thread ... */ + start(); + } + + /** + * + * This is the rendering-method called by sDisplay + * (and sDisplay is called by paint, or by the thread directly !). + * The derived-class (Your Subclass) will redefine this, + * to draw it's own animation ! + * + * <p> + * + * You should set shallWeRender here, + * to signalize the animation-loop 'run' to supsend + * <p> + * To restart the thread, just call setSuspended(false) + * + * @see GLAnimJPanel#shallWeRender + * @see GLAnimJPanel#run + * @see GLAnimJPanel#setSuspended + * @see GLCanvas#sDisplay + * @see GLCanvas#paint + */ + public void display() + { + int i; + + // ... just render it + + } + + /** + * ReInit should be overwritten by you, + * to enter your re-initialisation within setSuspended(false) + * + * @see 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. + * <p> + * 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 ! + * <p> + * + * @param b if true, uses repaint (default), otherwise directly sDisplay + * @see GLCanvas#sDisplay + * @see 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 ! + * <p> + * + * @param b if true, uses Fps sleeping, else not ! + * @see GLCanvas#sDisplay + * @see 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(); + } + + /** + * Should be set in display, + * whether to render or not while the animation loop + * <p> + * If shallWeRender is false, + * this thread will suspend ! + * + * @see GLAnimJPanel#display + * @see GLAnimJPanel#run + */ + 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 GLAnimJPanel#shallWeRender + * @see GLAnimJPanel#display + * @see GLAnimJPanel#diplay + */ + 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 GLAnimJPanel#isAlive + * @see 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 GLAnimJPanel#isAlive + * @see 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 GLAnimJPanel#run + * @see GLAnimJPanel#setSuspended + * @see GLAnimJPanel#start + * @see 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 GLAnimJPanel#run + * @see GLAnimJPanel#setSuspended + * @see GLAnimJPanel#start + * @see 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 + * <p> + * this function is called automatically by + * start and setSuspended + * + * @see GLAnimJPanel#start + * @see GLAnimJPanel#setSuspended + * @see GLAnimJPanel#resetFpsCounter + * @see GLAnimJPanel#stopFpsCounter + * @see GLAnimJPanel#getFps + * @see GLAnimJPanel#getFpsDuration + * @see GLAnimJPanel#getFpsFrames + * @see 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 + * <p> + * this function is called automatically by + * run, if the thread is suspended via shallWeRender + * <p> + * All data's are print out on System.out + * if verboseFps is set ! + * + * @see GLAnimJPanel#run + * @see GLAnimJPanel#shallWeRender + * @see GLAnimJPanel#resetFpsCounter + * @see GLAnimJPanel#stopFpsCounter + * @see GLAnimJPanel#getFps + * @see GLAnimJPanel#getFpsDuration + * @see GLAnimJPanel#getFpsFrames + * @see 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 ! + * <p> + * verboseFps is set to true by default ! + * + * @see GLAnimJPanel#run + * @see GLAnimJPanel#shallWeRender + * @see GLAnimJPanel#resetFpsCounter + * @see GLAnimJPanel#stopFpsCounter + * @see GLAnimJPanel#getFps + * @see GLAnimJPanel#getFpsDuration + * @see GLAnimJPanel#getFpsFrames + * @see GLAnimJPanel#setVerboseFps + */ + public void setVerboseFps(boolean v) + { + verboseFps=v; + } + + /** + * returns the calculated frames per secounds + * <p> + * this data is avaiable after calling stopFpsCounter + * + * @see GLAnimJPanel#resetFpsCounter + * @see GLAnimJPanel#stopFpsCounter + * @see GLAnimJPanel#getFps + * @see GLAnimJPanel#getFpsDuration + * @see GLAnimJPanel#getFpsFrames + * @see GLAnimJPanel#setVerboseFps + */ + public double getFps() + { + return fps; + } + + /** + * returns the calculated duration in millisecs + * <p> + * this data is avaiable after calling stopFpsCounter + * + * @see GLAnimJPanel#resetFpsCounter + * @see GLAnimJPanel#stopFpsCounter + * @see GLAnimJPanel#getFps + * @see GLAnimJPanel#getFpsDuration + * @see GLAnimJPanel#getFpsFrames + * @see GLAnimJPanel#setVerboseFps + */ + public long getFpsDuration() + { + return fps_duration; + } + + /** + * returns the calculated frames number + * <p> + * this data is avaiable after calling stopFpsCounter + * + * @see GLAnimJPanel#resetFpsCounter + * @see GLAnimJPanel#stopFpsCounter + * @see GLAnimJPanel#getFps + * @see GLAnimJPanel#getFpsDuration + * @see GLAnimJPanel#getFpsFrames + * @see 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 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 GLAnimJPanel#setAnimateFps + */ + public double getMaxFps() + { + return (1.0/(double)_f_dur_total)*1000.0; + } + +} + diff --git a/gl4java/swing/GLJPanel.java b/gl4java/swing/GLJPanel.java new file mode 100644 index 0000000..21beb39 --- /dev/null +++ b/gl4java/swing/GLJPanel.java @@ -0,0 +1,865 @@ +package gl4java.swing; + +import gl4java.*; + +import java.awt.*; +import java.awt.image.*; +import java.awt.event.*; +import javax.swing.*; + +/** + * This is meant as an base class writing + * easy render functions. A clean usage of multi-threading compatible + * with JAVA2 is implemented in GLAnimJPanel ! + * + * <p> + * + * If you are interessting in further Documentation and/or + * the history of GL4Java follow the following link. + * + * <pre> + <a href="../../GL4Java.html">The GL4Java Documentation</a> + * </pre> + * <p> + * + * You should overwrite the following methods for your needs: + * <pre> + <a href="GLJPanel.html#init()">preInit - initialisation before creating GLContext</a> + <a href="GLJPanel.html#init()">init - 1st initialisation after creating GLContext</a> + <a href="GLJPanel.html#doCleanup()">doCleanup - OGL cleanup prior to context deletion</a> + <a href="GLJPanel.html#display()">display - render your frame</a> + <a href="GLJPanel.html#reshape(int, int)">reshape - to reshape (window resize), gljResize() is allready invoked !</a> + * </pre> + * + * To check if you can use the GLContext and GL and GLU methods, + * use the function + * <pre> + <a href="GLJPanel.html#cvsIsInit()">cvsIsInit</a> + * </pre> + * <p> + * IF you remove/release a GLJPanel, + * e.g. you want to close/dispose it�s Window (which contains this GLJPanel), + * you HAVE TO call: + * + * <pre> + <a href="GLJPanel.html#cvsDispose()">cvsDispose</a> + * </pre> + * You should call this before releasing/dispose this Window ! + * Also you can overwrite this class, + * to dispose your own elements, e.g. a Frame etc. - + * but be shure that you call + * cvsDispose implementation call this one ! + * + * <p> + * We do override the following Canvas methods. + * + * <pre> + <a href="GLJPanel.html#update(java.awt.Graphics)">update</a> + <a href="GLJPanel.html#paint(java.awt.Graphics)">paint</a> + * </pre> + * <p> + * + * @see GLAnimJPanel + * @version 2.0, 21. April 1999 + * @author Sven Goethel + * + */ +public class GLJPanel extends JPanel + implements GLEnum, GLUEnum, + ComponentListener, WindowListener, MouseListener +{ + protected GLContext glj = null; + public GLFunc gl = null; + public GLUFunc glu = null; + + protected boolean mustResize = false; + + protected boolean cvsInitialized=false; + + protected boolean needCvsDispose = false; + + /** + * Visual pre-set for stencil-bit number, default: 0 + * This value is updated after a GLContext is created with the + * original updated value of GLContext ! + * + * @see GLJPanel#preInit + * @see GLJPanel#paint + */ + protected int stencilBits = 0; + + /** + * Visual pre-set for accumulator buffer size, default: 0 + * This value is updated after a GLContext is created with the + * original updated value of GLContext ! + * + * @see GLJPanel#preInit + * @see GLJPanel#paint + */ + protected int accumSize = 0; + + /** + * Visual pre-set for stereoView, default: false + * This value is updated after a GLContext is created with the + * original updated value of GLContext ! + * + * @see GLJPanel#preInit + * @see GLJPanel#paint + */ + protected boolean stereoView = false; + + /** + * Visual pre-set for RGBA usage, default: true - of course ;-) + * This value is updated after a GLContext is created with the + * original updated value of GLContext ! + * + * @see GLJPanel#preInit + * @see GLJPanel#paint + */ + protected boolean rgba = true; + + /** + * The context with witch display lists and textures will be shared. + * + * @see GLJPanel#preInit + * @see GLJPanel#paint + */ + protected GLContext sharedGLContext; + + /** + * The data to hold the offscreen pixels on the java side ! + * + * @see GLJPanel#offImagePixels + * @see GLJPanel#paint + */ + protected BufferedImage offImage = null; + + /** + * The data to hold the offscreen pixels on the GL side ! + * + * @see GLJPanel#offImage + * @see GLJPanel#paint + */ + protected byte[] offImagePixels = null; + + /** + * The custom set offscreen Size + * + * If this is set to != null, + * the offscreen pixmap is used in this size, + * not in the components-size (-> faster if smaller) + * + * @see GLJPanel#paint + * @see GLJPanel#setOffScreenSize + * @see GLJPanel#getOffScreenSize + */ + protected Dimension offScrnSize = null; + protected boolean customOffScrnSize=false; + protected boolean offScrnSizeChanged=false; + + static { + if(GLContext.loadNativeLibraries(null, null, null)==false) + System.out.println("GLJPanel 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 GLJPanel( String gl_Name, + String glu_Name, + LayoutManager layout, boolean isDoubleBuffered + ) + { + super( layout, isDoubleBuffered ); + + if( (gl=GLContext.createGLFunc(gl_Name)) ==null) + { + System.out.println("GLFunc implementation "+gl_Name+" not created"); + } + if( (glu=GLContext.createGLUFunc(glu_Name)) ==null) + { + System.out.println("GLUFunc implementation "+glu_Name+" not created"); + } + + /* to be able for RESIZE event's */ + addComponentListener(this); + + setOpaque(false); + } + + /** + * + * Constructor + * + * @param layout the layout manager + * @param isDoubleBuffered the flag indicates, + * if double buffer should be used + * + */ + public GLJPanel( LayoutManager layout, boolean isDoubleBuffered ) + { + this(null, null, layout, isDoubleBuffered); + } + + /** + * + * Constructor + * + * Uses the default GLFunc and GLUFunc implementation ! + * + * @param isDoubleBuffered the flag indicates, + * if double buffer should be used + */ + public GLJPanel( boolean isDoubleBuffered ) + { + this(null, null, new FlowLayout(), isDoubleBuffered); + } + + /** + * + * Constructor + * + * Uses the default GLFunc and GLUFunc implementation ! + * + * @param layout the layout manager + */ + public GLJPanel(LayoutManager layout) + { + this(null, null, layout, true); + } + + /** + * + * Constructor + * + * Uses the default GLFunc and GLUFunc implementation ! + * + */ + public GLJPanel( ) + { + this(null, null, new FlowLayout(), true); + } + + /** + * Used to return the created GLContext + */ + public final GLContext getGLContext() { return glj; } + + /** + * Safe the toplevel window + */ + protected Window topLevelWindow = null; + + /** + * + * This function returns the found TopLevelWindow, + * which contains this Canvas .. + * + * @return void + * + * @see GLJPanel#paint + */ + public final Window getTopLevelWindow() + { return topLevelWindow; } + + /** + * The customers offscreen Size + * + * If this is set, + * the offscreen pixmap is used in this size, + * not in the components-size (-> faster if smaller) + * + * @see GLJPanel#offScrnSize + * @see GLJPanel#setOffScreenSize + */ + public Dimension getOffScreenSize() + { return offScrnSize; } + + /** + * The customers offscreen Size + * + * If this is set, + * the offscreen pixmap is used in this size, + * not in the components-size (-> faster if smaller) + * + * @see GLJPanel#offScrnSize + * @see GLJPanel#getOffScreenSize + */ + public void setOffScreenSize(Dimension size) + { + if((size!=null && size.equals(offScrnSize)==false) || + size!=offScrnSize + ) + { + offScrnSizeChanged=true; + offScrnSize=size; + customOffScrnSize=offScrnSize!=null; + } + } + + /** + * this function overrides the Canvas paint method ! + * + * For the first paint, + * the user function preInit is called, a GLContext is created + * and the user function init is called ! + * + * Also, if a GL Context exist, GLJPanel's sDisplay-method will be called + * to do OpenGL-rendering. + * + * The sDisplay method itself calls the display-method ! + * sDisplay is needed to be thread-safe, to manage + * the resize functionality and to safe the time per frame. + * + * To define your rendering, you should overwrite the display-method + * in your derivation. + * + * @see gl4java.GLContext#GLContext + * @see GLJPanel#cvsIsInit + * @see GLJPanel#sDisplay + * @see GLJPanel#display + * @see GLJPanel#preInit + * @see GLJPanel#init + */ + public synchronized final void paintComponent(Graphics g) + { + if(glj == null || + (mustResize && !customOffScrnSize) || offScrnSizeChanged ) + { + if(mustResize) + { + cvsDispose(); + mustResize=false; + } + preInit(); + glj = GLContext.createOffScreenCtx ( this, gl, glu, + stereoView, + rgba, stencilBits, accumSize, + sharedGLContext, + offScrnSize + ); + + if(glj!=null) + { + /* + createOwnWindow = glj.isOwnWindowCreated(); + doubleBuffer = glj.isDoubleBuffer(); + */ + stencilBits = glj.getStencilBitNumber(); + accumSize = glj.getAccumSize(); + stereoView = glj.isStereoView(); + rgba = glj.isRGBA(); + } + if(offImage!=null) + offImage.flush(); + offImage=null; + offScrnSizeChanged=false; + + init(); + + // fetch the top-level window , + // to add us as the windowListener + // + Container _c = getParent(); + Container c = null; + + while(_c!=null) + { + c = _c; + _c = _c.getParent(); + } + + if(c instanceof Window) { + topLevelWindow = (Window)c; + topLevelWindow.addComponentListener(this); + topLevelWindow.addMouseListener(this); + } else { + topLevelWindow = null; + System.out.println("toplevel is not a Window: "+c); + } + + if(topLevelWindow!=null) + { + topLevelWindow.addWindowListener(this); + } else { + System.out.println("no parent found for "+getName()); + System.out.flush(); + } + if(glj!=null && glj.gljIsInit()) + cvsInitialized=true; + } + /* + if( mustResize ) size = getSize(); + g.setClip(0, 0, size.width, size.height ); + */ + //super.paintComponent(g); + + gr = g; + sDisplay(); + } + + Graphics gr = null; + DataBufferInt dbInt = null; + + /** + * + * This is the thread save rendering-method called by paint. + * The actual thread will be set to highes priority befor calling + * 'display'. After 'display' the priority will be reset ! + * + * 'gljFree' will be NOT called after 'display'. + * + * We tested the above to use multi-threading and + * for the demonstration 'glDemos' it works ;-)) ! + * + * BE SURE, if you want to call 'display' by yourself + * (e.g. in the run method for animation) + * YOU HAVE TO CALL sDisplay -- OR YOU MUST KNOW WHAT YOU ARE DOING THEN ! + * + * @return void + * + * @see GLJPanel#paint + * @see GLJPanel#display + */ + public synchronized final void sDisplay() + { + boolean ok = true; + + long _s = System.currentTimeMillis(); + + if(!cvsIsInit()) + return; + + if( glj.gljMakeCurrent() == false ) { + System.out.println("GLJPanel: problem in use() method"); + return; + } + + if(ok) + { + display(); + _f_dur_self = System.currentTimeMillis()-_s; + if(GLContext.gljClassDebug) + { + _f_dur_self_sum+=_f_dur_self; + glj.gljCheckGL(); + } + + int glFormat; + int glComps; + int awtFormat; + + glFormat = (rgba == true)?GL_RGBA:GL_RGB; + glComps = (rgba == true)?4:3; + awtFormat = (rgba == true)?BufferedImage.TYPE_INT_ARGB: + BufferedImage.TYPE_INT_RGB; + + Dimension size = null; + if(customOffScrnSize) + size=offScrnSize; + else + size=getSize(); + int w=size.width; + int h=size.height; + + long _s_tst = System.currentTimeMillis(); + + if(offImage==null || + offImage.getHeight()!=h || offImage.getWidth()!=w) + { + if(offImage!=null) + offImage.flush(); + offImage = new BufferedImage(w,h,awtFormat); + offImagePixels=new byte[w*h*glComps]; + dbInt = (DataBufferInt) + offImage.getRaster().getDataBuffer(); + + if(GLContext.gljClassDebug) + { + System.out.print("set offImage to size: "+size+ + "(hw size: "+w+"x"+h+"), type: "); + switch(glFormat) { + case GL_RGB: System.out.println("RGB"); break; + case GL_RGBA: System.out.println("RGBA"); break; + case GL_BGR_EXT: System.out.println("BGR"); break; + case GL_BGRA_EXT: System.out.println("BGRA"); break; + } + } + } + + glj.gljReadPixelGL2AWT(0,0,w,h,glFormat,GL_UNSIGNED_BYTE, + glj.isDoubleBuffer()?GL_BACK:GL_FRONT, + offImagePixels, dbInt.getData()); + + //glj.gljSwap(); // no true swapping with offscreen buffers .. + + if(GLContext.gljClassDebug) + _f_dur_tst_sum+=System.currentTimeMillis()-_s_tst; + + if(GLContext.gljClassDebug) + glj.gljCheckGL(); + glj.gljFree(); // enable ctx for threads ... + + if(!customOffScrnSize) + gr.drawImage(offImage, 0, 0, this); + else { + size=super.getSize(); + gr.drawImage(offImage, 0, 0, size.width, size.height, this); + } + + _f_dur_total = System.currentTimeMillis()-_s; + if(GLContext.gljClassDebug) + { + _f_dur_total_sum+=_f_dur_total; + if(++_f_dur_times==100) + { + System.out.println("self p 100: "+ + (double)(_f_dur_self_sum/100)/1000.0+" s"); + + System.out.println("tst p 100: "+ + (double)(_f_dur_tst_sum/100)/1000.0+" s"); + + System.out.println("gl-bitblit p 100: "+ + (double)((_f_dur_total_sum-_f_dur_self_sum)/100)/1000.0+" s"); + System.out.println("total p 100: "+ + (double)(_f_dur_total_sum/100)/1000.0+" s"); + + _f_dur_self_sum=0; + _f_dur_tst_sum=0; + _f_dur_total_sum=0; + _f_dur_times=0; + } + } + + } + + } + + /** + * + * This is the rendering-method called by sDisplay + * (and sDisplay is called by paint !). + * The derived-class (Your Subclass) will redefine this, to draw it's own... + * + * BE SURE, if you want to call 'display' by yourself + * (e.g. in the run method for animation) + * YOU HAVE TO CALL sDisplay ! + * + * 'sDisplay' manages a semaphore to avoid reentrance of + * the display function !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + * + * @return void + * + * @see GLJPanel#sDisplay + * @see GLJPanel#paint + */ + public void display() + { + } + + /** + * + * This is your pre-init method. + * preInit is called just BEFORE the GL-Context is created. + * You should override preInit, to initialize your visual-stuff, + * like the protected vars: doubleBuffer and stereoView + * + * @return void + * + * @see GLJPanel#paint + * @see GLJPanel#doubleBuffer + * @see GLJPanel#stereoView + * @see GLJPanel#rgba + * @see GLJPanel#stencilBits + * @see GLJPanel#accumSize + */ + public void preInit() + { + } + + /** + * + * This is your init method. + * init is called right after the GL-Context is initialized. + * You should override init, to initialize your stuff needed + * by OpenGL an Java ! + * + * @return void + * + * @see GLJPanel#paint + */ + public void init() + { + } + + /** + * This method is used to clean up any OpenGL stuff (delete textures + * or whatever) prior to actually deleting the OpenGL context. + * You should override this with your own version, if you need to do + * any cleanup work at this phase. + * This functions is called within cvsDispose + * + * @return void + * + * @see GLJPanel#cvsDispose + */ + public void doCleanup() + { + } + + /** + * This function returns, if everything is init: the GLContext, + * the and the users init function + * This value is set in the paint method! + * + * @return boolean + * + * @see GLJPanel#paint + * @see GLJPanel#init + */ + public boolean cvsIsInit() + { + return cvsInitialized; + } + + protected long _f_dur_self = 0; + protected long _f_dur_self_sum = 0; + protected long _f_dur_tst_sum = 0; + protected long _f_dur_total = 0; + protected long _f_dur_total_sum = 0; + protected int _f_dur_times = 0; + + /** + * + * This is the reshape-method called by paint. + * The derived-class (Your Subclass) will redefine this, + * to manage your individual reshape ... + * + * This �reshape� method will be invoked after the first paint command + * after GLJPanel.componentResize is called AND only if �gljUse� was + * succesfull (so a call of gljUse is redundant). + * �reshape� is not an overloading of java.awt.Component.reshape, + * �reshape� is more like �glut�-reshape. + * + * GLJPanel.reshape allready has a simple default implementation, + * which calls �gljResize� and �glViewport� - so you may be can + * left this one as it is (no need to overload). + * The needed call to �gljResize� is done by hte invoker paint ! + * + * @param width the new width + * @param height the new height + * @return void + * + * @see GLJPanel#paint + * @see GLJPanel#sDisplay + */ + public void reshape( int width, int height ) + { + if(GLContext.gljClassDebug) + System.out.println("GLJPanel::reshape bounds("+getBounds()+")"); + gl.glViewport(0,0, width, height); + } + + /** + * + * �componentResized� is the componentListeners event handler. + * + * This method sets the variable �mustResize� to true, + * so the upcoming �paint� method-call will invoke �reshape� ! + * + * This little look-alike complicating thing is done, + * to avoid an Exception by using the glContext from more than + * one concurrent thread�s ! + * + * You cannot override this implementation, it is final + * - override �reshape' instead ! + * + * @param e the element, which is resized + * @return void + * + * @see GLJPanel#paint + * @see GLJPanel#reshape + */ + public void componentResized(ComponentEvent e) + { + if(GLContext.gljClassDebug) + System.out.println("GLJPanel::componentResized("+e.getComponent()+")"); + if(glj!=null && glj.gljIsInit() && e.getComponent()==this ) + { + mustResize = true; + //repaint(); + } + } + + public void componentMoved(ComponentEvent e) + { + /* + if(GLContext.gljClassDebug) + System.out.print("GLJPanel::componentMoved("+e.getComponent()+")"); + if(e.getComponent().equals(topLevelWindow)) + { + repaint(); + } + */ + } + + public void componentShown(ComponentEvent e) + { + } + + public void componentHidden(ComponentEvent e) + { + } + + public void mouseClicked(MouseEvent e) + { + } + public void mouseEntered(MouseEvent e) + { + /* + if(GLContext.gljClassDebug) + System.out.print("GLJPanel::mouseEntered("+e.getComponent()+")"); + if(e.getComponent().equals(topLevelWindow)) + { + repaint(); + } + */ + } + public void mouseExited(MouseEvent e) + {} + public void mousePressed(MouseEvent e) + { + } + public void mouseReleased(MouseEvent e) + { + } + + public void windowOpened(WindowEvent e) + { + } + + /** + * + * �windowClosing� is the windowListeners event handler + * for the topLevelWindow of this Canvas ! + * + * This methods free�s AND destroy�s + * the GL Context with �glj.gljDestroy� ! + * + * @return void + * + */ + public void windowClosing(WindowEvent e) + { + if(e.getComponent().equals(topLevelWindow)) + { + cvsDispose(); + } + } + + /** + * + * �windowClosed� is the windowListeners event handler. + * + * @return void + * + */ + public void windowClosed(WindowEvent e) + { + if (needCvsDispose) cvsDispose(); + } + + public void windowIconified(WindowEvent e) + { + } + + public void windowDeiconified(WindowEvent e) + { + } + + public void windowActivated(WindowEvent e) + { + } + + public void windowDeactivated(WindowEvent e) + { + } + + /** + * You should call this before releasing/dispose this Window ! + * Also you can overwrite this class, + * to dispose your own elements, e.g. a Frame etc. - + * but be shure that you call + * cvsDispose implementation call this one ! + * + * This function calls gljDestroy of GLContext ! + * + * @see gl4java.GLContext#gljDestroy + * @see GLJPanel#doCleanup + */ + public void cvsDispose() + { + cvsInitialized = false; + if (glj != null) + { + if (glj.gljIsInit()) + { + /* Sometimes the Microsoft VM calls the + Applet.stop() method but doesn't have + permissions to do J/Direct calls, so + this whole block of code will throw a + security exception. If this happens, + however, windowClosing() will still + call us again later and we will have + another opportunity to shut down the + context, so it all works out fine. */ + try + { + glj.gljFree(); + doCleanup(); + //locks and free's GLContext + glj.setEnabled(false); + glj.gljDestroy(); + needCvsDispose = false; + } + catch (Exception ex) + { + needCvsDispose = true; + } + } + } + + // Setting glj to null will simply cause paint() to re-initialize. + // We don't want that to happen, so we will leave glj non-null. + } + + public Dimension getSize() + { + if(customOffScrnSize) + return offScrnSize; + return super.getSize(); + } + + /** + * get methods + */ + public final int cvsGetWidth() { + return getSize().width; + } + public final int cvsGetHeight() { + return getSize().height; + } +} + diff --git a/gl4java/swing/GLJPanel.java,v b/gl4java/swing/GLJPanel.java,v new file mode 100644 index 0000000..2d89e6c --- /dev/null +++ b/gl4java/swing/GLJPanel.java,v @@ -0,0 +1,959 @@ +head 1.2; +access; +symbols; +locks; strict; +comment @# @; + + +1.2 +date 2000.07.19.12.08.58; author sven; state Exp; +branches; +next 1.1; + +1.1 +date 2000.07.19.12.01.31; author sven; state Exp; +branches; +next ; + + +desc +@the first - with experimental code +@ + + +1.2 +log +@stabile +@ +text +@package gl4java.swing; + +import gl4java.*; + +import java.awt.*; +import java.awt.image.*; +import java.awt.event.*; +import javax.swing.*; + +/** + * This is meant as an base class writing + * easy render functions. A clean usage of multi-threading compatible + * with JAVA2 is implemented in GLAnimJPanel ! + * + * <p> + * + * If you are interessting in further Documentation and/or + * the history of GL4Java follow the following link. + * + * <pre> + <a href="../../GL4Java.html">The GL4Java Documentation</a> + * </pre> + * <p> + * + * You should overwrite the following methods for your needs: + * <pre> + <a href="GLJPanel.html#init()">preInit - initialisation before creating GLContext</a> + <a href="GLJPanel.html#init()">init - 1st initialisation after creating GLContext</a> + <a href="GLJPanel.html#doCleanup()">doCleanup - OGL cleanup prior to context deletion</a> + <a href="GLJPanel.html#display()">display - render your frame</a> + <a href="GLJPanel.html#reshape(int, int)">reshape - to reshape (window resize), gljResize() is allready invoked !</a> + * </pre> + * + * To check if you can use the GLContext and GL and GLU methods, + * use the function + * <pre> + <a href="GLJPanel.html#cvsIsInit()">cvsIsInit</a> + * </pre> + * <p> + * IF you remove/release a GLJPanel, + * e.g. you want to close/dispose it�s Window (which contains this GLJPanel), + * you HAVE TO call: + * + * <pre> + <a href="GLJPanel.html#cvsDispose()">cvsDispose</a> + * </pre> + * You should call this before releasing/dispose this Window ! + * Also you can overwrite this class, + * to dispose your own elements, e.g. a Frame etc. - + * but be shure that you call + * cvsDispose implementation call this one ! + * + * <p> + * We do override the following Canvas methods. + * + * <pre> + <a href="GLJPanel.html#update(java.awt.Graphics)">update</a> + <a href="GLJPanel.html#paint(java.awt.Graphics)">paint</a> + * </pre> + * <p> + * + * @@see GLAnimJPanel + * @@version 2.0, 21. April 1999 + * @@author Sven Goethel + * + */ +public class GLJPanel extends JPanel + implements GLEnum, GLUEnum, + ComponentListener, WindowListener, MouseListener +{ + protected GLContext glj = null; + public GLFunc gl = null; + public GLUFunc glu = null; + + protected boolean mustResize = false; + + protected boolean cvsInitialized=false; + + protected boolean needCvsDispose = false; + + /** + * Visual pre-set for stencil-bit number, default: 0 + * This value is updated after a GLContext is created with the + * original updated value of GLContext ! + * + * @@see GLJPanel#preInit + * @@see GLJPanel#paint + */ + protected int stencilBits = 0; + + /** + * Visual pre-set for accumulator buffer size, default: 0 + * This value is updated after a GLContext is created with the + * original updated value of GLContext ! + * + * @@see GLJPanel#preInit + * @@see GLJPanel#paint + */ + protected int accumSize = 0; + + /** + * Visual pre-set for stereoView, default: false + * This value is updated after a GLContext is created with the + * original updated value of GLContext ! + * + * @@see GLJPanel#preInit + * @@see GLJPanel#paint + */ + protected boolean stereoView = false; + + /** + * Visual pre-set for RGBA usage, default: true - of course ;-) + * This value is updated after a GLContext is created with the + * original updated value of GLContext ! + * + * @@see GLJPanel#preInit + * @@see GLJPanel#paint + */ + protected boolean rgba = true; + + /** + * The context with witch display lists and textures will be shared. + * + * @@see GLJPanel#preInit + * @@see GLJPanel#paint + */ + protected GLContext sharedGLContext; + + /** + * The data to hold the offscreen pixels on the java side ! + * + * @@see GLJPanel#offImagePixels + * @@see GLJPanel#paint + */ + protected BufferedImage offImage = null; + + /** + * The data to hold the offscreen pixels on the GL side ! + * + * @@see GLJPanel#offImage + * @@see GLJPanel#paint + */ + protected byte[] offImagePixels = null; + + /** + * The custom set offscreen Size + * + * If this is set to != null, + * the offscreen pixmap is used in this size, + * not in the components-size (-> faster if smaller) + * + * @@see GLJPanel#paint + * @@see GLJPanel#setOffScreenSize + * @@see GLJPanel#getOffScreenSize + */ + protected Dimension offScrnSize = null; + protected boolean customOffScrnSize=false; + protected boolean offScrnSizeChanged=false; + + static { + if(GLContext.loadNativeLibraries(null, null, null)==false) + System.out.println("GLJPanel 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 GLJPanel( String gl_Name, + String glu_Name, + LayoutManager layout, boolean isDoubleBuffered + ) + { + super( layout, isDoubleBuffered ); + + if( (gl=GLContext.createGLFunc(gl_Name)) ==null) + { + System.out.println("GLFunc implementation "+gl_Name+" not created"); + } + if( (glu=GLContext.createGLUFunc(glu_Name)) ==null) + { + System.out.println("GLUFunc implementation "+glu_Name+" not created"); + } + + /* to be able for RESIZE event's */ + addComponentListener(this); + + setOpaque(false); + } + + /** + * + * Constructor + * + * @@param layout the layout manager + * @@param isDoubleBuffered the flag indicates, + * if double buffer should be used + * + */ + public GLJPanel( LayoutManager layout, boolean isDoubleBuffered ) + { + this(null, null, layout, isDoubleBuffered); + } + + /** + * + * Constructor + * + * Uses the default GLFunc and GLUFunc implementation ! + * + * @@param isDoubleBuffered the flag indicates, + * if double buffer should be used + */ + public GLJPanel( boolean isDoubleBuffered ) + { + this(null, null, new FlowLayout(), isDoubleBuffered); + } + + /** + * + * Constructor + * + * Uses the default GLFunc and GLUFunc implementation ! + * + * @@param layout the layout manager + */ + public GLJPanel(LayoutManager layout) + { + this(null, null, layout, true); + } + + /** + * + * Constructor + * + * Uses the default GLFunc and GLUFunc implementation ! + * + */ + public GLJPanel( ) + { + this(null, null, new FlowLayout(), true); + } + + /** + * Used to return the created GLContext + */ + public final GLContext getGLContext() { return glj; } + + /** + * Safe the toplevel window + */ + protected Window topLevelWindow = null; + + /** + * + * This function returns the found TopLevelWindow, + * which contains this Canvas .. + * + * @@return void + * + * @@see GLJPanel#paint + */ + public final Window getTopLevelWindow() + { return topLevelWindow; } + + /** + * The customers offscreen Size + * + * If this is set, + * the offscreen pixmap is used in this size, + * not in the components-size (-> faster if smaller) + * + * @@see GLJPanel#offScrnSize + * @@see GLJPanel#setOffScreenSize + */ + public Dimension getOffScreenSize() + { return offScrnSize; } + + /** + * The customers offscreen Size + * + * If this is set, + * the offscreen pixmap is used in this size, + * not in the components-size (-> faster if smaller) + * + * @@see GLJPanel#offScrnSize + * @@see GLJPanel#getOffScreenSize + */ + public void setOffScreenSize(Dimension size) + { + if((size!=null && size.equals(offScrnSize)==false) || + size!=offScrnSize + ) + { + offScrnSizeChanged=true; + offScrnSize=size; + customOffScrnSize=offScrnSize!=null; + } + } + + /** + * this function overrides the Canvas paint method ! + * + * For the first paint, + * the user function preInit is called, a GLContext is created + * and the user function init is called ! + * + * Also, if a GL Context exist, GLJPanel's sDisplay-method will be called + * to do OpenGL-rendering. + * + * The sDisplay method itself calls the display-method ! + * sDisplay is needed to be thread-safe, to manage + * the resize functionality and to safe the time per frame. + * + * To define your rendering, you should overwrite the display-method + * in your derivation. + * + * @@see gl4java.GLContext#GLContext + * @@see GLJPanel#cvsIsInit + * @@see GLJPanel#sDisplay + * @@see GLJPanel#display + * @@see GLJPanel#preInit + * @@see GLJPanel#init + */ + public synchronized final void paintComponent(Graphics g) + { + if(glj == null || + (mustResize && !customOffScrnSize) || offScrnSizeChanged ) + { + if(mustResize) + { + cvsDispose(); + mustResize=false; + } + preInit(); + glj = GLContext.createOffScreenCtx ( this, gl, glu, + stereoView, + rgba, stencilBits, accumSize, + sharedGLContext, + offScrnSize + ); + + if(glj!=null) + { + /* + createOwnWindow = glj.isOwnWindowCreated(); + doubleBuffer = glj.isDoubleBuffer(); + */ + stencilBits = glj.getStencilBitNumber(); + accumSize = glj.getAccumSize(); + stereoView = glj.isStereoView(); + rgba = glj.isRGBA(); + } + if(offImage!=null) + offImage.flush(); + offImage=null; + offScrnSizeChanged=false; + + init(); + + // fetch the top-level window , + // to add us as the windowListener + // + Container _c = getParent(); + Container c = null; + + while(_c!=null) + { + c = _c; + _c = _c.getParent(); + } + + if(c instanceof Window) { + topLevelWindow = (Window)c; + topLevelWindow.addComponentListener(this); + topLevelWindow.addMouseListener(this); + } else { + topLevelWindow = null; + System.out.println("toplevel is not a Window: "+c); + } + + if(topLevelWindow!=null) + { + topLevelWindow.addWindowListener(this); + } else { + System.out.println("no parent found for "+getName()); + System.out.flush(); + } + if(glj!=null && glj.gljIsInit()) + cvsInitialized=true; + } + /* + if( mustResize ) size = getSize(); + g.setClip(0, 0, size.width, size.height ); + */ + //super.paintComponent(g); + + gr = g; + sDisplay(); + } + + Graphics gr = null; + DataBufferInt dbInt = null; + + /** + * + * This is the thread save rendering-method called by paint. + * The actual thread will be set to highes priority befor calling + * 'display'. After 'display' the priority will be reset ! + * + * 'gljFree' will be NOT called after 'display'. + * + * We tested the above to use multi-threading and + * for the demonstration 'glDemos' it works ;-)) ! + * + * BE SURE, if you want to call 'display' by yourself + * (e.g. in the run method for animation) + * YOU HAVE TO CALL sDisplay -- OR YOU MUST KNOW WHAT YOU ARE DOING THEN ! + * + * @@return void + * + * @@see GLJPanel#paint + * @@see GLJPanel#display + */ + public synchronized final void sDisplay() + { + boolean ok = true; + + long _s = System.currentTimeMillis(); + + if(!cvsIsInit()) + return; + + if( glj.gljMakeCurrent() == false ) { + System.out.println("GLJPanel: problem in use() method"); + return; + } + + if(ok) + { + display(); + _f_dur_self = System.currentTimeMillis()-_s; + if(GLContext.gljClassDebug) + { + _f_dur_self_sum+=_f_dur_self; + glj.gljCheckGL(); + } + + int glFormat; + int glComps; + int awtFormat; + + glFormat = (rgba == true)?GL_RGBA:GL_RGB; + glComps = (rgba == true)?4:3; + awtFormat = (rgba == true)?BufferedImage.TYPE_INT_ARGB: + BufferedImage.TYPE_INT_RGB; + + Dimension size = null; + if(customOffScrnSize) + size=offScrnSize; + else + size=getSize(); + int w=size.width; + int h=size.height; + + long _s_tst = System.currentTimeMillis(); + + if(offImage==null || + offImage.getHeight()!=h || offImage.getWidth()!=w) + { + if(offImage!=null) + offImage.flush(); + offImage = new BufferedImage(w,h,awtFormat); + offImagePixels=new byte[w*h*glComps]; + dbInt = (DataBufferInt) + offImage.getRaster().getDataBuffer(); + + if(GLContext.gljClassDebug) + { + System.out.print("set offImage to size: "+size+ + "(hw size: "+w+"x"+h+"), type: "); + switch(glFormat) { + case GL_RGB: System.out.println("RGB"); break; + case GL_RGBA: System.out.println("RGBA"); break; + case GL_BGR_EXT: System.out.println("BGR"); break; + case GL_BGRA_EXT: System.out.println("BGRA"); break; + } + } + } + + glj.gljReadPixelGL2AWT(0,0,w,h,glFormat,GL_UNSIGNED_BYTE, + glj.isDoubleBuffer()?GL_BACK:GL_FRONT, + offImagePixels, dbInt.getData()); + + //glj.gljSwap(); // no true swapping with offscreen buffers .. + + if(GLContext.gljClassDebug) + _f_dur_tst_sum+=System.currentTimeMillis()-_s_tst; + + if(GLContext.gljClassDebug) + glj.gljCheckGL(); + glj.gljFree(); // enable ctx for threads ... + + if(!customOffScrnSize) + gr.drawImage(offImage, 0, 0, this); + else { + size=super.getSize(); + gr.drawImage(offImage, 0, 0, size.width, size.height, this); + } + + _f_dur_total = System.currentTimeMillis()-_s; + if(GLContext.gljClassDebug) + { + _f_dur_total_sum+=_f_dur_total; + if(++_f_dur_times==100) + { + System.out.println("self p 100: "+ + (double)(_f_dur_self_sum/100)/1000.0+" s"); + + System.out.println("tst p 100: "+ + (double)(_f_dur_tst_sum/100)/1000.0+" s"); + + System.out.println("gl-bitblit p 100: "+ + (double)((_f_dur_total_sum-_f_dur_self_sum)/100)/1000.0+" s"); + System.out.println("total p 100: "+ + (double)(_f_dur_total_sum/100)/1000.0+" s"); + + _f_dur_self_sum=0; + _f_dur_tst_sum=0; + _f_dur_total_sum=0; + _f_dur_times=0; + } + } + + } + + } + + /** + * + * This is the rendering-method called by sDisplay + * (and sDisplay is called by paint !). + * The derived-class (Your Subclass) will redefine this, to draw it's own... + * + * BE SURE, if you want to call 'display' by yourself + * (e.g. in the run method for animation) + * YOU HAVE TO CALL sDisplay ! + * + * 'sDisplay' manages a semaphore to avoid reentrance of + * the display function !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + * + * @@return void + * + * @@see GLJPanel#sDisplay + * @@see GLJPanel#paint + */ + public void display() + { + } + + /** + * + * This is your pre-init method. + * preInit is called just BEFORE the GL-Context is created. + * You should override preInit, to initialize your visual-stuff, + * like the protected vars: doubleBuffer and stereoView + * + * @@return void + * + * @@see GLJPanel#paint + * @@see GLJPanel#doubleBuffer + * @@see GLJPanel#stereoView + * @@see GLJPanel#rgba + * @@see GLJPanel#stencilBits + * @@see GLJPanel#accumSize + */ + public void preInit() + { + } + + /** + * + * This is your init method. + * init is called right after the GL-Context is initialized. + * You should override init, to initialize your stuff needed + * by OpenGL an Java ! + * + * @@return void + * + * @@see GLJPanel#paint + */ + public void init() + { + } + + /** + * This method is used to clean up any OpenGL stuff (delete textures + * or whatever) prior to actually deleting the OpenGL context. + * You should override this with your own version, if you need to do + * any cleanup work at this phase. + * This functions is called within cvsDispose + * + * @@return void + * + * @@see GLJPanel#cvsDispose + */ + public void doCleanup() + { + } + + /** + * This function returns, if everything is init: the GLContext, + * the and the users init function + * This value is set in the paint method! + * + * @@return boolean + * + * @@see GLJPanel#paint + * @@see GLJPanel#init + */ + public boolean cvsIsInit() + { + return cvsInitialized; + } + + protected long _f_dur_self = 0; + protected long _f_dur_self_sum = 0; + protected long _f_dur_tst_sum = 0; + protected long _f_dur_total = 0; + protected long _f_dur_total_sum = 0; + protected int _f_dur_times = 0; + + /** + * + * This is the reshape-method called by paint. + * The derived-class (Your Subclass) will redefine this, + * to manage your individual reshape ... + * + * This �reshape� method will be invoked after the first paint command + * after GLJPanel.componentResize is called AND only if �gljUse� was + * succesfull (so a call of gljUse is redundant). + * �reshape� is not an overloading of java.awt.Component.reshape, + * �reshape� is more like �glut�-reshape. + * + * GLJPanel.reshape allready has a simple default implementation, + * which calls �gljResize� and �glViewport� - so you may be can + * left this one as it is (no need to overload). + * The needed call to �gljResize� is done by hte invoker paint ! + * + * @@param width the new width + * @@param height the new height + * @@return void + * + * @@see GLJPanel#paint + * @@see GLJPanel#sDisplay + */ + public void reshape( int width, int height ) + { + if(GLContext.gljClassDebug) + System.out.println("GLJPanel::reshape bounds("+getBounds()+")"); + gl.glViewport(0,0, width, height); + } + + /** + * + * �componentResized� is the componentListeners event handler. + * + * This method sets the variable �mustResize� to true, + * so the upcoming �paint� method-call will invoke �reshape� ! + * + * This little look-alike complicating thing is done, + * to avoid an Exception by using the glContext from more than + * one concurrent thread�s ! + * + * You cannot override this implementation, it is final + * - override �reshape' instead ! + * + * @@param e the element, which is resized + * @@return void + * + * @@see GLJPanel#paint + * @@see GLJPanel#reshape + */ + public void componentResized(ComponentEvent e) + { + if(GLContext.gljClassDebug) + System.out.println("GLJPanel::componentResized("+e.getComponent()+")"); + if(glj!=null && glj.gljIsInit() && e.getComponent()==this ) + { + mustResize = true; + //repaint(); + } + } + + public void componentMoved(ComponentEvent e) + { + /* + if(GLContext.gljClassDebug) + System.out.print("GLJPanel::componentMoved("+e.getComponent()+")"); + if(e.getComponent().equals(topLevelWindow)) + { + repaint(); + } + */ + } + + public void componentShown(ComponentEvent e) + { + } + + public void componentHidden(ComponentEvent e) + { + } + + public void mouseClicked(MouseEvent e) + { + } + public void mouseEntered(MouseEvent e) + { + /* + if(GLContext.gljClassDebug) + System.out.print("GLJPanel::mouseEntered("+e.getComponent()+")"); + if(e.getComponent().equals(topLevelWindow)) + { + repaint(); + } + */ + } + public void mouseExited(MouseEvent e) + {} + public void mousePressed(MouseEvent e) + { + } + public void mouseReleased(MouseEvent e) + { + } + + public void windowOpened(WindowEvent e) + { + } + + /** + * + * �windowClosing� is the windowListeners event handler + * for the topLevelWindow of this Canvas ! + * + * This methods free�s AND destroy�s + * the GL Context with �glj.gljDestroy� ! + * + * @@return void + * + */ + public void windowClosing(WindowEvent e) + { + if(e.getComponent().equals(topLevelWindow)) + { + cvsDispose(); + } + } + + /** + * + * �windowClosed� is the windowListeners event handler. + * + * @@return void + * + */ + public void windowClosed(WindowEvent e) + { + if (needCvsDispose) cvsDispose(); + } + + public void windowIconified(WindowEvent e) + { + } + + public void windowDeiconified(WindowEvent e) + { + } + + public void windowActivated(WindowEvent e) + { + } + + public void windowDeactivated(WindowEvent e) + { + } + + /** + * You should call this before releasing/dispose this Window ! + * Also you can overwrite this class, + * to dispose your own elements, e.g. a Frame etc. - + * but be shure that you call + * cvsDispose implementation call this one ! + * + * This function calls gljDestroy of GLContext ! + * + * @@see gl4java.GLContext#gljDestroy + * @@see GLJPanel#doCleanup + */ + public void cvsDispose() + { + cvsInitialized = false; + if (glj != null) + { + if (glj.gljIsInit()) + { + /* Sometimes the Microsoft VM calls the + Applet.stop() method but doesn't have + permissions to do J/Direct calls, so + this whole block of code will throw a + security exception. If this happens, + however, windowClosing() will still + call us again later and we will have + another opportunity to shut down the + context, so it all works out fine. */ + try + { + glj.gljFree(); + doCleanup(); + //locks and free's GLContext + glj.setEnabled(false); + glj.gljDestroy(); + needCvsDispose = false; + } + catch (Exception ex) + { + needCvsDispose = true; + } + } + } + + // Setting glj to null will simply cause paint() to re-initialize. + // We don't want that to happen, so we will leave glj non-null. + } + + public Dimension getSize() + { + if(customOffScrnSize) + return offScrnSize; + return super.getSize(); + } + + /** + * get methods + */ + public final int cvsGetWidth() { + return getSize().width; + } + public final int cvsGetHeight() { + return getSize().height; + } +} + +@ + + +1.1 +log +@Initial revision +@ +text +@a414 1 + DataBufferByte dbByte = null; +a438 9 + boolean useBGR = false; + boolean useNativeCpy = false; + + /* + if(glj.getNativeOSType()==GLContext.OsWindoof) + useBGR=true; + if(glj.getNativeOSType()==GLContext.OsX11) + useNativeCpy=true; + */ +d464 3 +a466 10 + if(useBGR) + { + glFormat = (rgba == true)?GL_BGRA_EXT:GL_BGR_EXT; + glComps = (rgba == true)?4:3; + awtFormat = (rgba == true)?BufferedImage.TYPE_4BYTE_ABGR: + BufferedImage.TYPE_3BYTE_BGR; + } else { + glFormat = (rgba == true)?GL_RGBA:GL_RGB; + glComps = (rgba == true)?4:3; + awtFormat = (rgba == true)?BufferedImage.TYPE_INT_ARGB: +a467 1 + } +d485 4 +a488 15 + if(useBGR) + { + offImagePixels=null; + dbByte = (DataBufferByte) + offImage.getRaster().getDataBuffer(); + dbInt = null; + } else { + if(!useNativeCpy) + offImagePixels=new byte[w*h*glComps]; + else + offImagePixels=null; + dbInt = (DataBufferInt) + offImage.getRaster().getDataBuffer(); + dbByte = null; + } +d502 3 +a504 12 + if(useBGR) + glj.gljReadPixelGL2AWT(0,0,w,h,glFormat,GL_UNSIGNED_BYTE, + glj.isDoubleBuffer()?GL_BACK:GL_FRONT, + dbByte.getData()); + else if(useNativeCpy) + { + glj.gljCpyOffScrnImg2Buffer(w, h, glFormat, dbInt.getData()); + glj.gljSwap(); + } else + glj.gljReadPixelGL2AWT(0,0,w,h,glFormat,GL_UNSIGNED_BYTE, + glj.isDoubleBuffer()?GL_BACK:GL_FRONT, + offImagePixels, dbInt.getData()); +@ diff --git a/gl4java/swing/SimpleGLJApplet1.java b/gl4java/swing/SimpleGLJApplet1.java new file mode 100644 index 0000000..0dc21f4 --- /dev/null +++ b/gl4java/swing/SimpleGLJApplet1.java @@ -0,0 +1,292 @@ +/**
+ * @(#) SimpleGLJApplet1.java
+ * @(#) author: Sven Goethel
+ */
+
+package gl4java.swing;
+
+/* This program is licensed under the LGPL */
+
+import java.applet.*;
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.*;
+import java.lang.*;
+import gl4java.GLContext;
+import gl4java.GLFunc;
+import gl4java.GLUFunc;
+import gl4java.awt.GLAnimCanvas;
+
+public class SimpleGLJApplet1 extends JApplet
+ implements MouseListener, WindowListener, ActionListener, ItemListener
+{
+ public GLJPanel canvas = null;
+
+ public Button buttonInfo = null;
+ public Button buttonFps = null;
+ public TextField textFps = null;
+ public Checkbox checkUseRepaint = null;
+ public Checkbox checkUseFpsSleep = null;
+ public Button buttonReStart = null;
+
+
+ Frame fInfo = null;
+
+ /* Initialize the applet */
+
+ public void init()
+ {
+ JPanel master = new JPanel (new BorderLayout());
+ setContentPane(master);
+
+ JPanel pan = new JPanel();
+ pan.setLayout(new GridLayout(2,3));
+
+ buttonInfo = new Button("GL4Java");
+ buttonInfo.addMouseListener(this);
+ pan.add(buttonInfo);
+
+ checkUseRepaint = new Checkbox("repaint", true);
+ checkUseRepaint.addItemListener(this);
+ pan.add(checkUseRepaint);
+
+ checkUseFpsSleep = new Checkbox("fps-sleep", true);
+ checkUseFpsSleep.addItemListener(this);
+ pan.add(checkUseFpsSleep);
+
+ buttonReStart = new Button("start/stop");
+ buttonReStart.addMouseListener(this);
+ pan.add(buttonReStart);
+
+ buttonFps = new Button("fps: ");
+ buttonFps.addMouseListener(this);
+ pan.add(buttonFps);
+
+ textFps=new TextField("0000000000");
+ textFps.addActionListener(this);
+ pan.add(textFps);
+
+ master.add("South",pan);
+ }
+
+
+ public void start()
+ {
+ if(canvas instanceof GLAnimJPanel)
+ ((GLAnimJPanel)canvas).start();
+ }
+
+
+ public void stop()
+ {
+ if(canvas instanceof GLAnimJPanel)
+ ((GLAnimJPanel)canvas).stop();
+ }
+
+
+ public void destroy()
+ {
+ if(fInfo!=null)
+ {
+ fInfo.dispose();
+ fInfo=null;
+ }
+ if(canvas instanceof GLAnimJPanel)
+ {
+ ((GLAnimJPanel)canvas).stop();
+ ((GLAnimJPanel)canvas).cvsDispose();
+ }
+ }
+
+
+ // Methods required for the implementation of MouseListener
+ public void mouseEntered( MouseEvent evt )
+ {
+ }
+
+ public void mouseExited( MouseEvent evt )
+ {
+ }
+
+ public void mousePressed( MouseEvent evt )
+ {
+ }
+
+ public void mouseReleased( MouseEvent evt )
+ {
+ }
+
+ public void mouseClicked( MouseEvent evt )
+ {
+ Component comp = evt.getComponent();
+
+ if((canvas instanceof GLAnimJPanel)==false)
+ return;
+
+ GLAnimJPanel canvasAnim = (GLAnimJPanel)canvas;
+
+ if( canvasAnim!=null && comp.equals(buttonFps) )
+ {
+ double fps = 0;
+ int a1;
+
+ canvasAnim.stopFpsCounter();
+ fps=canvasAnim.getFps();
+ a1=(int)(fps*100.0);
+ fps=(double)a1/100.0;
+ textFps.setText(String.valueOf(fps));
+ canvasAnim.resetFpsCounter();
+ } else if( comp.equals(buttonInfo) )
+ {
+ if(fInfo==null && canvasAnim!=null && canvasAnim.getGLContext()!=null)
+ fInfo = showGLInfo();
+ }
+ else if( comp.equals(buttonReStart) )
+ {
+ canvasAnim.setSuspended(!canvasAnim.isSuspended(),
+ evt.getClickCount()>1 // -> ReInit
+ );
+ }
+ }
+
+ public void itemStateChanged( ItemEvent evt )
+ {
+ ItemSelectable comp = evt.getItemSelectable();
+
+ if((canvas instanceof GLAnimJPanel)==false)
+ return;
+
+ GLAnimJPanel canvasAnim = (GLAnimJPanel)canvas;
+
+ if( comp.equals(checkUseRepaint ) )
+ {
+ if(canvasAnim!=null)
+ {
+ canvasAnim.setUseRepaint(checkUseRepaint.getState());
+ System.out.println("canvas uses repaint: "+
+ checkUseRepaint.getState());
+ }
+ }
+ if( comp.equals(checkUseFpsSleep ) )
+ {
+ if(canvasAnim!=null)
+ {
+ canvasAnim.setUseFpsSleep(checkUseFpsSleep.getState());
+ System.out.println("canvas uses fps-sleep: "+
+ checkUseFpsSleep.getState());
+ }
+ }
+ }
+
+ public void actionPerformed(ActionEvent event)
+ {
+ Object source = event.getSource();
+
+ if((canvas instanceof GLAnimJPanel)==false)
+ return;
+
+ GLAnimJPanel canvasAnim = (GLAnimJPanel)canvas;
+
+ if ( source == textFps)
+ {
+ try {
+ double FramesPerSec=
+ Double.valueOf(textFps.getText()).doubleValue();
+ if(canvasAnim!=null)
+ {
+ canvasAnim.setAnimateFps(FramesPerSec);
+ canvasAnim.setSuspended(false, true);
+ }
+ } catch (NumberFormatException s) {
+ System.out.println("wrong fps format, use float ..");
+ }
+
+ }
+ }
+
+ public void windowOpened(WindowEvent e)
+ {
+ }
+
+ public void windowClosing(WindowEvent e)
+ {
+ Window w = e.getWindow();
+ if(w == fInfo && fInfo!=null)
+ {
+ fInfo.dispose();
+ fInfo=null;
+ }
+ }
+
+ public void windowClosed(WindowEvent e)
+ {
+ Window w = e.getWindow();
+ if(w == fInfo && fInfo!=null)
+ {
+ fInfo.dispose();
+ fInfo=null;
+ }
+ }
+
+ public void windowIconified(WindowEvent e)
+ {
+ }
+
+ public void windowDeiconified(WindowEvent e)
+ {
+ }
+
+ public void windowActivated(WindowEvent e)
+ {
+ }
+
+ public void windowDeactivated(WindowEvent e)
+ {
+ }
+
+ public Frame showGLInfo()
+ {
+ if(canvas==null) return null;
+
+ GLContext glc = canvas.getGLContext();
+ if(glc==null) return null;
+
+ GLFunc gl = glc.getGLFunc();
+ if(gl==null) return null;
+
+ GLUFunc glu = glc.getGLUFunc();
+ if(gl==null) return null;
+
+ if((canvas instanceof GLAnimJPanel)==false)
+ ((GLAnimJPanel)canvas).setSuspended(true, false);
+
+ Frame f = new Frame("GL4Java Version");
+ TextArea info= new TextArea(25, 80);
+ info.setEditable(false);
+ f.add(info);
+ f.setSize(600, 400);
+
+ String str = "null string";
+ if( glc.gljMakeCurrent() == false )
+ {
+ str="problem in use() method\n";
+ } else {
+ str=canvas.getGLContext().gljGetVersions();
+ if(str==null)
+ str="could not get versions";
+ System.out.println(str);
+ glc.gljFree();
+ }
+ info.append(str);
+
+ f.addWindowListener(this);
+
+ if((canvas instanceof GLAnimJPanel)==false)
+ ((GLAnimJPanel)canvas).setSuspended(false, false);
+
+ f.pack();
+ f.setVisible(true);
+
+ return f;
+ }
+}
|