problems GLCanvas --> GLJPanel

Hello,
I have developped an application using GLCanvas, and I wanted to replace my GLCanvas component by a GLJPanel, because I will need to integrate my developments with JInternalFrame.

1-
I read that GLJPanel was the only solution to use JOGL in JInternalFrame, is this still the case?

2-
I changed my GLCanvas by a GLJPanel, and I really lost performance! Is there any work done on this point (the lose of performance)? Do you have methods in order to keep the performance of the GLCanvas component?

3-
When I replaced my GLCanvas by the GLJPanel, I encountered some problems.
I have a class called MyClass in which I have my GLJPanel. In the constructor of MyClass, I create my GLJPanel :


                  GLCapabilities glcaps = new GLCapabilities();
  		
  		  glcaps.setRedBits(8);
  		  glcaps.setBlueBits(8);
  		  glcaps.setGreenBits(8);
  		  glcaps.setAlphaBits(8);
  		  glcaps.setStencilBits(1);
  		  
  		  glcaps.setDoubleBuffered(true);
  		  
  		  glcaps.setHardwareAccelerated( true);
  		  this.gljpanel = GLDrawableFactory.getFactory().createGLJPanel(glcaps);
  		  this.gljpanel.addGLEventListener(this);
  		  
                  ref_animator = new Animator(gljpanel);

I think this code is ok, because I didn’t have any problems with the GLCanvas component. But is this better to create the animator in the constructor of MyClass or in the init method (by checking if a ref_animator is null or not, because I know that the init method is called several times (each time a new context opengl is created))?

public void init(GLDrawable gld) 
      {                     
          //--- On récupère les fonctions GL et GLU
          final GL gl = gld.getGL();
          final GLU glu = gld.getGLU();

          //--- On affecte un debbuger pour GL
          gld.setGL( new DebugGL(gld.getGL() ));

          gl.glEnable(GL.GL_BLEND);
          gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA ); // Select The Type Of Blending
        
          gl.glHint(GL.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_FASTEST);
          gl.glHint(GL.GL_LINE_SMOOTH_HINT, GL.GL_FASTEST);
          gl.glHint(GL.GL_POINT_SMOOTH_HINT, GL.GL_FASTEST);
          gl.glHint(GL.GL_POLYGON_SMOOTH_HINT, GL.GL_FASTEST);
          
          gl.glEnable(GL.GL_POLYGON_OFFSET_FILL);

          //--- Définition du mode d'éclairage        
          gl.glLightModelfv(GL.GL_LIGHT_MODEL_AMBIENT, new float[] {0.5f, 0.5f, 0.5f});                

          
          //--- Définition de la lampe 0
          gl.glEnable(GL.GL_LIGHT0);        
          gl.glLightfv(GL.GL_LIGHT0, GL.GL_AMBIENT , new float[] { 0.4f, 0.4f, 0.4f, 1.0f});
          gl.glLightfv(GL.GL_LIGHT0, GL.GL_DIFFUSE , new float[] { 0.4f, 0.4f, 0.4f, 1.0f});         
          gl.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, light_position);

          //--- Activation des lumières
          gl.glEnable(GL.GL_LIGHTING);
     
          gl.glClearColor(Constantes.CLEAR_COLOR_R / 255.0f,
                        Constantes.CLEAR_COLOR_G / 255.0f,
                        Constantes.CLEAR_COLOR_B / 255.0f, 
                        Constantes.CLEAR_COLOR_A / 255.0f);
          
          gl.glClearDepth(1.0);                                  //Enables Clearing Of The Depth Buffer
          gl.glEnable(GL.GL_DEPTH_TEST);                            //Enables Depth Testing 
          gl.glDepthFunc(GL.GL_LEQUAL );

         //        --- On active le tampon de stencil
          gl.glClearStencil(0);
          gl.glEnable(GL.GL_STENCIL_TEST);
          
          //--- On rend le swapping de buffer automatique
          if(!gld.getAutoSwapBufferMode())
          {
              gld.setAutoSwapBufferMode(true);            
          }      
   
          //--- Création de l'animator
//          if(ref_animator != null){
//                 ref_animator.stop();
//                 ref_animator = null;
//                 System.gc();            
//          }
//          this.ref_animator = new Animator(gld);
//          start();   //method that starts the animator
        
          start();
          
          //this will recreate my opengl call list
          this.setUpdate(MODE_WITH_COLOR);        
      }

4-
When I exit the GLJPanel, I stop the animator, and when I enter it, I start the animator (in order to have cpu time for other application when the user is not on the gljpanel or glcanvas).
By replacing the glcanvas by gljpanel, I had a new problem :
when the animator is stopped and when I resize my GLJPanel, a call to init is made, which is following to a call of the reshape method. But I want the image on the gljpanel to refresh, even if the animator is stopped. It was ok with the glcanvas component, but with the gljpanel, I have no image untill a mouseEntered event is called. And this, even if I put a gljpanel.display() in the init method or in the reshape method (which make an error), I also tried gljpanel.invalidate(), and I also tried to start the animator at the end of the init method or the reshape method. But nothing runs, I can’t have the image refreshed (only with gljpanel).

5-
Another problem with GLJpanel I had is that if you create your gljpanel and just after you call gljpanel.getGLU(), you sometimes have a nullPointerException, I think that is because sometimes, the init method is not yet called when the gljpanel.getGLU() is called (perhaps because the gljpanel is not yet shown??).

this.gljpanel = GLDrawableFactory.getFactory().createGLJPanel(glcaps);
this.gljpanel.addGLEventListener(this);
gljpanel.getGLU() 

6-
I also often have problems with start and stop methods of the ref_animator (net.java.games.jogl.GLException: Already started). I test before if the animator is already started or not, and I also tried to put methods in synchronized, but sometimes, I have this error, and my animator is blocked… But this is not my most important problem, I would like to know if GLJPanel is a good choice or not and to solve my problems with this component.

Thank you for your help.

I’ll try to answer your questions in as much detail as I can. First, though, keep in mind that the JOGL code base is about to undergo a large transformation in the next couple of weeks once JSR-231 goes into Early Draft Review. At that point the current code base will be replaced with the new APIs and new implementation. From a practical standpoint your existing JOGL applications will work almost unmodified, but the implementation has changed drastically and a lot of issues with the GLJPanel have been fixed in the new code base. The Animator has also been reimplemented, supports animation of multiple GLDrawables (now called GLAutoDrawables in the JSR-231 workspace), and no longer consumes any CPU when it is not animating any visible GLAutoDrawables.

(1) The GLJPanel is still the only way to get 100% correct behavior with JInternalFrames. VLSolutions has a docking framework which supports Swing components on top of GLCanvases, but this still doesn’t address the key issue of 100% Swing interoperability. See the thread “Java2D/JOGL Interoperability Demo” several threads down for some details about what’s possible in Java SE 6 (“Mustang”).

(2) See above.

(3) Create your Animator outside your GLEventListener. The GLJPanel typically goes through many more OpenGL context destroy/init cycles than the GLCanvas due to the need to resize the backing pbuffer, which involves destroying and recreating it.

(4) I would really avoid mucking with the Animator in your GLEventListener’s callback methods. Either look at the JSR-231 sources and copy the Animator from there or roll your own. You can see the JSR-231 sources using cvs with


cvs -d :pserver:guest@cvs.dev.java.net:/cvs co -r JSR-231 -P jogl jogl-demos

(5) Yes, it’s not valid to call getGLU() or getGL() on a GLJPanel before your GLEventListener’s init() method. You also shouldn’t call that method when your GLEventListener’s callback methods aren’t active on the stack. The JSR-231 implementation has refactored this so the GLU is decoupled from the GLDrawable; you can instantiate a GLU object anywhere, but can only call its methods when there is an OpenGL context current.

(6) Again, I would avoid messing with the Animator but would instead write your own if necessary.

Regarding the suitability of GLJPanel, the current implementation is fine for small windows. GLJPanel is really fast when run with the Java2D OpenGL pipeline on Mustang (Java SE 6) and is completely compatible with Java2D. I would strongly recommend running in that configuration if you can run on pre-release software. FYI, Mustang is due out next year. If you can’t run on pre-release software and need higher performance for larger windows, look into VLSolutions’ docking framework and see if it fits your needs.

Thank you for your response.

In my application, I only need to have high performance when the JInternaFrame which contains the Canvas (GLJPanel or GLCanvas) is activated. If it is another JInternalFrame which is activated, I can have lower performance.

Therefore, I tried to use both component (GLCanvas and GLJPanel), when my JInternalFrame is activated, I remove the GLJPanel from my JInternalFrame, and I add the GLCanvas to the frame, and when the JInternalFrame is desactivated, I remove the GLCanvas, and I add the GLJPanel.

This worked very well in term of performance, but sometimes, when a call to the activation of my JInternalFrame (which owns the canvas) is made, I have an instruction which removes the GLJPanel of my JInternalFrame and it sometimes freezes my application. This never happen with the remove of the GLCanvas component…

I have just found a solution which is : instead of simply call

remove(gljpanel)

, it is probably better (because my application is never blocked with it) calling

gljpanel.removeNotify()

But I don’t understand why one case works and the other not? And why my application is blocked (but this doesn’t happen each time)?
Is this better to call “theComponent.removeNotify()” or “remove(theComponent)” ?

Again thank you for your help.

You should just call remove(gljpanel). removeNotify is called automatically by the AWT when a component is removed from the hierarchy and should not be called by applications directly.

In the JSR-231 branch of the JOGL source tree the GLJPanel has been substantially rewritten and is much more robust than in the main trunk. If you have time, I would recommend checking out the newer code.


cvs -d :pserver:guest@cvs.dev.java.net:/cvs co -r JSR-231 -P jogl jogl-demos

You’ll (unfortunately) need to build it yourself for now; within a few weeks this branch will be merged in with the main trunk and we’ll have nightly builds pushed to java.net. Your JOGL application will require some small modifications to work with these APIs (net.java.games.jogl becomes javax.media.opengl, GLDrawable becomes GLAutoDrawable, GLU is accessed differently) but the new APIs are pretty stable at this point so you’ll only have to do the conversion once. If you try the new sources, please post to let us know whether they work better for you.