/** * @(#) GLCanvas.java */ package gl4java.awt; import gl4java.*; import gl4java.drawable.*; import gl4java.drawable.utils.*; import java.awt.*; import java.awt.event.*; import java.util.EventListener; /** * This is meant as an base class writing * easy render functions. A clean usage of multi-threading compatible * with JAVA2 is implemented in GLAnimCanvas ! * *

* * 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 GLCanvas: the {@link * gl4java.drawable.GLEventListener} model or the subclassing model. Earlier * versions of OpenGL for Java 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: *

        preInit - initialisation before creating GLContext
        init - 1st initialisation after creating GLContext
        doCleanup - OGL cleanup prior to context deletion
        display - render your frame
	reshape - to reshape (window resize), gljResize() is allready invoked !
 * 
* * To check if you can use the GLContext and GL and GLU methods, * use the function *
        cvsIsInit
 * 
*

* IF you remove/release a GLCanvas, * e.g. you want to close/dispose it´s Window (which contains this GLCanvas), * you HAVE TO call: * *

        cvsDispose
 * 
* 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 ! * *

* We do override the following Canvas methods. * *

        update
        paint
 * 
*

* * @see gl4java.awt.GLAnimCanvas * @version 2.0, 21. April 1999 * @author Sven Goethel * */ public class GLCanvas extends Canvas implements GLEnum, GLUEnum, ComponentListener, WindowListener, MouseListener, GLDrawable { protected GLContext glj = null; public GLFunc gl = null; public GLUFunc glu = null; protected Dimension size = null; protected boolean mustResize = false; protected boolean needCvsDispose = false; /** * Visual pre-set for doubleBuffer, default: true * This value is updated after a GLContext is created with the * original updated value of GLContext ! * * @see gl4java.awt.GLCanvas#preInit * @see gl4java.awt.GLCanvas#paint */ protected boolean doubleBuffer = true; /** * 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 gl4java.awt.GLCanvas#preInit * @see gl4java.awt.GLCanvas#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 ! * * This value has a special behavior. * For input - within the contructor, * it is the value for each component ! * * The output value, after the constructor returns, * it is the summary of all accumulation bits of all components ! * * @see gl4java.awt.GLCanvas#preInit * @see gl4java.awt.GLCanvas#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 gl4java.awt.GLCanvas#preInit * @see gl4java.awt.GLCanvas#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 gl4java.awt.GLCanvas#preInit * @see gl4java.awt.GLCanvas#paint */ protected boolean rgba = true; protected GLCapabilities capabilities = null; /** * 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 gl4java.awt.GLCanvas#preInit * @see gl4java.awt.GLCanvas#paint */ protected boolean createOwnWindow = false; /** * The context with wich display lists and textures will be shared. * * @see gl4java.awt.GLCanvas#preInit * @see gl4java.awt.GLCanvas#paint */ protected GLContext sharedGLContext; // The list of GLEventListeners private GLEventListenerList listeners = new GLEventListenerList(); // Indicates whether init() has been called yet. private volatile boolean initCalled = false; // Indicates whether the canvas will permit any calls to init() or // display() from within the paint() method; defaults to true for // backward compatibility. private boolean enableAWTThreadRendering = true; // Indicates whether display() automatically makes the canvas's // GLContext current and frees it each call; defaults to true for // backward compatibility. On higher-end graphics cards it is // important to minimize the number of "make current" calls even // across frames; a GLAnimCanvas running in its own thread, and // with AWT thread rendering disabled, will only make its // associated context current once, at the beginning of its // rendering loop. private boolean autoMakeContextCurrent = true; static { if(GLContext.doLoadNativeLibraries(null, null, null)==false) System.out.println("GLCanvas could not load def. native libs."); } /** * * Constructor * * @param width the canvas initial-prefered width * @param height the canvas initial-prefered height * * @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 ! * */ public GLCanvas( GLCapabilities capabilities, int width, int height, String gl_Name, String glu_Name ) { super( ); this.capabilities=capabilities; 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"); } size = new Dimension(width, height); setSize(size); } /** * * Constructor * * @param width the canvas initial-prefered width * @param height the canvas initial-prefered height * * @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 ! * */ public GLCanvas( GLCapabilities capabilities, int width, int height ) { this(capabilities, width, height, null, null); } /** * * Constructor * * @param width the canvas initial-prefered width * @param height the canvas initial-prefered height * * @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 ! * */ public GLCanvas( int width, int height, String gl_Name, String glu_Name ) { this(null, width, height, gl_Name, glu_Name); } /** * * Constructor * * Uses the default GLFunc and GLUFunc implementation ! * * @param width the canvas initial-prefered width * @param height the canvas initial-prefered height * */ public GLCanvas( int width, int height ) { this(width, height, null, null); } /** * * Constructor (JDK 1.2 or later) * * @param config the GraphicsConfiguration for this canvas (>= JDK 1.2) * * @param width the canvas initial-prefered width * @param height the canvas initial-prefered height * * @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 ! * */ public GLCanvas( GraphicsConfiguration config, GLCapabilities capabilities, int width, int height, String gl_Name, String glu_Name ) { super( config ); this.capabilities=capabilities; 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"); } size = new Dimension(width, height); setSize(size); } /** * * Constructor (JDK 1.2 or later) * * Uses the default GLFunc and GLUFunc implementation ! * * @param config the GraphicsConfiguration for this canvas (>= JDK 1.2) * * @param width the canvas initial-prefered width * @param height the canvas initial-prefered height * */ public GLCanvas( GraphicsConfiguration config, GLCapabilities capabilities, int width, int height ) { this(config, capabilities, width, height, null, null); } /* GLCanvas AWT classes */ public Dimension getPreferredSize() { return getMinimumSize(); } public Dimension getMinimumSize() { return size; } /** * Used to return the created GLContext */ public final GLContext getGLContext() { return glj; } /** * * Overridden update * This one only call's the paint method, without clearing * the background - thats hopefully done by OpenGL ;-) * * @param g the Graphics Context * @return void * * @see gl4java.awt.GLCanvas#paint */ public void update(Graphics g) { /* let's let OpenGL clear the background ... */ paint(g); } /** * Safe the toplevel window */ protected Window topLevelWindow = null; /** * * This function returns the found TopLevelWindow, * which contains this Canvas .. * * @return void * * @see gl4java.awt.GLCanvas#paint */ public final Window getTopLevelWindow() { return topLevelWindow; } /** Enables/disables calls to init() and display() from within the AWT thread. If this is enabled (the default, for backward compatibility with earlier releases), the first call to paint() from within the AWT thread (typically prompted by a repaint()) will cause the canvas to be initialized, and subsequent calls to paint() will cause display() to be called. If AWT thread rendering is disabled, the AWT thread will not cause init() or display() to be called if repaint() is called, and the first call to display() will cause the canvas to be initialized. This function is present both to work around bugs in certain vendors' drivers which do not function properly in multithreaded settings, and to allow improved performance of GLAnimCanvas. */ public void setAWTThreadRenderingEnabled(boolean val) { enableAWTThreadRendering = val; } /** Indicates whether AWT thread rendering is enabled; see {@link #setAWTThreadRenderingEnabled}. */ public boolean getAWTThreadRenderingEnabled() { return enableAWTThreadRendering; } /** Indicates whether the canvas automatically makes its underlying GLContext current and frees it during each call to display(); defaults to true for backward compatibility. On higher-end graphics cards it is important to minimize the number of "make current" calls even across frames; a GLAnimCanvas running in its own thread and with AWT thread rendering disabled will only make its associated context current once, at the beginning of its rendering loop. */ public void setAutoMakeContextCurrent(boolean val) { autoMakeContextCurrent = val; } /** Indicates whether the canvas automatically makes its underlying GLContext current and frees it during each call to display(); see {@link #setAutoMakeContextCurrent}. */ public boolean getAutoMakeContextCurrent() { return autoMakeContextCurrent; } /** Convenience routine which Enables or disables optimized context handling by calling {@link #setAWTThreadRenderingEnabled} and {@link #setAutoMakeContextCurrent} with the given boolean. */ public void optimizeContextHandling(boolean yesOrNo) { setAWTThreadRenderingEnabled(yesOrNo); setAutoMakeContextCurrent(yesOrNo); } /** * 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, GLCanvas'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 gl4java.awt.GLCanvas#cvsIsInit * @see gl4java.awt.GLCanvas#sDisplay * @see gl4java.awt.GLCanvas#display * @see gl4java.awt.GLCanvas#preInit * @see gl4java.awt.GLCanvas#init */ public synchronized final void paint( Graphics g ) { if(glj == null || ( !glj.gljIsInit() && isGLEnabled() ) ) { if(GLContext.gljClassDebug) System.out.println("GLCanvas create GLContext (recreate="+ (glj != null) +")"); preInit(); if(glj!=null) glj=null; if (capabilities != null ) { glj = new GLContext ( this, gl, glu, capabilities, sharedGLContext ); } else { glj = new GLContext ( this, gl, glu, createOwnWindow, doubleBuffer, stereoView, rgba, stencilBits, accumSize, sharedGLContext ); } if(glj!=null) { createOwnWindow = glj.isOwnWindowCreated(); doubleBuffer = glj.isDoubleBuffer(); stencilBits = glj.getStencilBitNumber(); accumSize = glj.getAccumSize(); stereoView = glj.isStereoView(); rgba = glj.isRGBA(); } Color col = getBackground(); gl.glClearColor((float)col.getRed()/255.0f, (float)col.getGreen()/255.0f, (float)col.getBlue()/255.0f, 0.0f); if (getAWTThreadRenderingEnabled()) { init(); initCalled = true; } // 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); } 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(); } /* to be able for RESIZE event's */ addComponentListener(this); addMouseListener(this); /* force a reshape, to be sure .. */ mustResize = true; // Free up the OpenGL context for another thread to use glj.gljFree(); } if (getAWTThreadRenderingEnabled()) { sDisplay(); } } /** * * 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 gl4java.awt.GLCanvas#paint * @see gl4java.awt.GLCanvas#doubleBuffer * @see gl4java.awt.GLCanvas#stereoView * @see gl4java.awt.GLCanvas#rgba * @see gl4java.awt.GLCanvas#stencilBits * @see gl4java.awt.GLCanvas#accumSize */ public void preInit() { } /** * * init is called right after the GL-Context is initialized. * The default implementation calls init() on all of this * component's GLEventListeners. * *

* If using the subclassing model, you can override this to * perform one-time OpenGL initializations such as setting up * lights and display lists. * * @return void * * @see gl4java.awt.GLCanvas#paint * @see gl4java.drawable.GLEventListener#init */ public void init() { listeners.sendInitEvent(this); } /** * 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 gl4java.awt.GLCanvas#cvsDispose * @see gl4java.drawable.GLEventListener#cleanup */ public void doCleanup() { listeners.sendCleanupEvent(this); } /** * 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 gl4java.awt.GLCanvas#paint * @see gl4java.awt.GLCanvas#init */ public boolean cvsIsInit() { if(glj!=null) return glj.gljIsInit(); return false; } /** * This function enables, disables the GL-Context ! * If false is given, the openGL renderer/context is * disabled and disconected (gljFree is called, if initialized) ! * * If disabled, all GL Functions are disabled but the * Destroy & Free are not ! * * @return boolean * * @see gl4java.awt.GLCanvas#cvsDispose * @see gl4java.GLContext#setEnabled * @see gl4java.GLContext#gljMakeCurrent * @see gl4java.GLContext#gljDestroy * @see gl4java.GLContext#gljFree */ public void setGLEnabled(boolean b) { if(glj!=null) glj.setEnabled(b); } /** * This function enables, disables the GL-Context ! * If false is given, the openGL renderer/context is * disabled and disconected (gljFree is called, if initialized) ! * * If disabled, all GL Functions are disabled but the * Destroy & Free are not ! * * The Visible-Flag of this AWT Component is also set to the given value ! * The setVisible(boolean) method of Component is called ! * * @return boolean * * @see gl4java.awt.GLCanvas#cvsDispose * @see gl4java.GLContext#setEnabled * @see gl4java.GLContext#gljMakeCurrent * @see gl4java.GLContext#gljDestroy * @see gl4java.GLContext#gljFree */ public void setVisible(boolean b) { if(glj!=null) glj.setEnabled(b); super.setVisible(b); } /** * This function queries, if the GL-Context is enabled ! * * @return boolean * * @see gl4java.GLContext#isEnabled * @see gl4java.GLContext#gljMakeCurrent */ public boolean isGLEnabled() { if(glj!=null) return glj.isEnabled(); return false; } protected long _f_dur = 0; /** * * 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 gl4java.awt.GLCanvas#paint * @see gl4java.awt.GLCanvas#display */ public synchronized final void sDisplay() { long _s = System.currentTimeMillis(); display(); _f_dur = System.currentTimeMillis()-_s; } /** * * This is the rendering-method called by sDisplay * (and sDisplay is called by paint !). * *

* The default implementation of display() sends * preDisplay, display and postDisplay events to * all {@link gl4java.GLEventListener}s associated with this * GLCanvas in the above order. * *

*

        reset timer for frame duration (done by sDisplay)

     	for_all(gl4java.GLEventListener)
		SEND preDisplay

	if( gljMakeCurrent() )
	{
		for_all(gl4java.GLEventListener)
			SEND display
		gljFree()
		gljSwap()

		for_all(gl4java.GLEventListener)
			SEND postDisplay
	}

        stop timer for frame duration (done by sDisplay)
     * 
* *

* If you use the subclassing model (as opposed to the * GLEventListener model), your subclass will redefine this to * perform its OpenGL drawing. In this case you MUST encapsulate * your OpenGL calls within: *

    	- glj.gljMakeCurrent()
		YOUR OpenGL commands here !
    	- glj.gljFree()
     * 
* * 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 gl4java.awt.GLCanvas#sDisplay * @see gl4java.awt.GLCanvas#paint * @see gl4java.GLContext#gljMakeCurrent * @see gl4java.GLContext#gljSwap * @see gl4java.drawable.GLEventListener#preDisplay * @see gl4java.drawable.GLEventListener#display * @see gl4java.drawable.GLEventListener#postDisplay */ public void display() { if(!cvsIsInit()) { return; } if( mustResize ) { if (getAutoMakeContextCurrent() && getAWTThreadRenderingEnabled()) { if( glj.gljMakeCurrent() == true ) { size = getSize(); glj.gljResize( size.width, size.height ) ; reshape(size.width, size.height); mustResize = false; invalidate(); repaint(100); glj.gljFree(); } } else if (getAutoMakeContextCurrent()) { if( glj.gljMakeCurrent() == true ) { size = getSize(); glj.gljResize( size.width, size.height ) ; reshape(size.width, size.height); mustResize = false; invalidate(); repaint(100); glj.gljFree(); } } else if (getAWTThreadRenderingEnabled()) { size = getSize(); glj.gljResize( size.width, size.height ) ; reshape(size.width, size.height); mustResize = false; invalidate(); repaint(100); } else { size = getSize(); glj.gljResize( size.width, size.height ) ; mustResize = false; } } if (!getAWTThreadRenderingEnabled()) { if (!initCalled) { init(); initCalled = true; } } listeners.sendPreDisplayEvent(this); if (getAutoMakeContextCurrent()) { if (glj.gljMakeCurrent()) { listeners.sendDisplayEvent(this); glj.gljSwap(); glj.gljCheckGL(); glj.gljFree(); listeners.sendPostDisplayEvent(this); } } else { listeners.sendDisplayEvent(this); glj.gljSwap(); glj.gljCheckGL(); listeners.sendPostDisplayEvent(this); } } /** * * This ´reshape´ method will be invoked after the first paint command * after GLCanvas.componentResize is called AND only if ´gljMakeCurrent´ was * successful (so a call of gljMakeCurrent is redundant). * ´reshape´ is not an overloading of java.awt.Component.reshape, * ´reshape´ is more like ´glut´-reshape. * *

* GLCanvas.reshape already has a simple default implementation, * which calls ´gljResize´ and ´glViewport´. It also sends the * reshape() event to all GLEventListeners. If using the * GLEventListener model, it may not be necessary to do anything * in your event listener's reshape() method; if using the * subclassing model, it may not be necessary to override this. * *

* The needed call to ´gljResize´ is done by the invoker paint ! * * @param width the new width * @param height the new height * @return void * * @see gl4java.awt.GLCanvas#paint * @see gl4java.awt.GLCanvas#sDisplay * @see gl4java.drawable.GLEventListener#reshape */ public void reshape( int width, int height ) { gl.glViewport(0,0, width, height); listeners.sendReshapeEvent(this, 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 gl4java.awt.GLCanvas#paint * @see gl4java.awt.GLCanvas#reshape */ public void componentResized(ComponentEvent e) { if(glj!=null && glj.gljIsInit() && e.getComponent()==this ) { mustResize = true; repaint(); } } public void componentMoved(ComponentEvent e) { if(glj!=null && glj.gljIsInit()) { repaint(100); } } public void componentShown(ComponentEvent e) { } public void componentHidden(ComponentEvent e) { } public void mouseClicked(MouseEvent e) { if(glj!=null && glj.gljIsInit()) { repaint(); } } public void mouseEntered(MouseEvent e) { } 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) { if(glj!=null && glj.gljIsInit()) { repaint(100); } } 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 ! * The Visibility is set to false ! * The Enabled is set to false either ! * * To bring this component back to live, * you need call setVisible(true) ! * * @see gl4java.GLContext#gljDestroy * @see gl4java.awt.GLCanvas#doCleanup */ public void cvsDispose() { if(GLContext.gljClassDebug) System.out.println("GLCanvas cvsDispose (doit="+ ( (glj != null) && glj.gljIsInit() ) +")"); removeComponentListener(this); removeMouseListener(this); 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 { setVisible(false); doCleanup(); 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. } /** * does nothing than: * * @see gl4java.awt.GLCanvas#cvsDispose */ protected void finalize() throws Throwable { if(GLContext.gljClassDebug) System.out.println("GLCanvas finalize .."); cvsDispose(); super.finalize(); } /** * does nothing than: * * @see gl4java.awt.GLCanvas#cvsDispose * * @deprecated Use cvsDispose instead, well finalize is also implemented */ public void destroy() { if(GLContext.gljClassDebug) System.out.println("GLCanvas destroy .."); cvsDispose(); } /** * get methods */ public final int cvsGetWidth() { return getSize().width; } public final int cvsGetHeight() { return getSize().height; } //---------------------------------------------------------------------- // Implementation of GLDrawable // public void addGLEventListener(GLEventListener listener) { listeners.add(listener); } public void removeGLEventListener(GLEventListener listener) { listeners.remove(listener); } public EventListener[] getListeners(Class listenerType) throws ClassCastException { EventListener[] evtlst=null; Class _GLEventListener = null; try { _GLEventListener = Class.forName("gl4java.drawable.GLEventListener"); } catch (Exception ex) { System.out.println(ex); } if (_GLEventListener!=null && listenerType.isAssignableFrom(_GLEventListener) ) evtlst = listeners.getListeners(); EventListener[] t_evtlst = super.getListeners(listenerType); if(t_evtlst==null || t_evtlst.length==0) return evtlst; if(evtlst==null || evtlst.length==0) return t_evtlst; EventListener[] n_evtlst = new EventListener[t_evtlst.length+evtlst.length]; try { System.arraycopy(evtlst, 0, n_evtlst, 0, evtlst.length); System.arraycopy(t_evtlst, 0, n_evtlst, evtlst.length, t_evtlst.length); } catch (Exception ex) { System.out.println(ex); } evtlst = null; t_evtlst = null; return n_evtlst; } public GLFunc getGL() { return gl; } public GLUFunc getGLU() { return glu; } }