Proper resource de-allocation in JME

Hi,



I'm currently working on a Swing application that has many different panels where one uses JME with the JMECanvas integration. Basically the JMECanvas resides on a JPanel. When I want to destroy the panel and go back to the main menu of the application, choose to go again to the panel where the JMECanvas integration resides, then I get the following exception:


Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
   at com.jme.scene.state.lwjgl.LWJGLZBufferState.enableDepthTest(Unknown Source)
   at com.jme.scene.state.lwjgl.LWJGLZBufferState.apply(Unknown Source)
   at com.jme.renderer.lwjgl.LWJGLRenderer.clearBuffers(Unknown Source)
   at com.jmex.awt.SimpleCanvasImpl.doRender(Unknown Source)
   at com.jmex.awt.lwjgl.LWJGLCanvas.paintGL(Unknown Source)
   at org.lwjgl.opengl.AWTGLCanvas.paint(AWTGLCanvas.java:308)
   at sun.awt.RepaintArea.paintComponent(RepaintArea.java:248)SimpleCanvasImplementor simpleSetup

   at sun.awt.RepaintArea.paint(RepaintArea.java:224)
   at sun.awt.windows.WComponentPeer.handleEvent(WComponentPeer.java:254)
   at java.awt.Component.dispatchEventImpl(Component.java:4060)
   at java.awt.Component.dispatchEvent(Component.java:3819)
   at java.awt.EventQueue.dispatchEvent(EventQueue.java:463)
   at java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:242)
   at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:163)
   at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:157)
   at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:149)
   at java.awt.EventDispatchThread.run(EventDispatchThread.java:110)



Here is the code where I try to do the proper resource de-allocation so that I should be able to call the panel with the JMECanvas integration the next time:

jmeCanvasPanel = null;
TextureManager.doTextureCleanup();
TextureManager.clearCache();
DisplaySystem.getDisplaySystem().getCurrentContext().invalidateStates();
DisplaySystem.getDisplaySystem().reset();
DisplaySystem.getDisplaySystem().close();



Does anybody know what is wrong with that?

Any help would be much appreciated.

Thanks,

Michael

I haven’t checked what is going on exactly when you close the display in jME, so I can’t say what the problem is. But you can try using the jME context system for your canvases, the display management code there is all custom and written from scratch and it was also made to handle multi-canvas applications so it might work for you.

Looks like you have cleared down a panel and then tried to display the same panel which has been partially cleared rather than to create a new panel.

When you get nullPointerExceptions on AWT event threads, that is probably because the GL context is owned by another thread. Try calling "makeCurrent" on the canvas before you call GL functions. Just remember that you will need to give back the context to the rendering thread. Dont know how/what the jME context system does, but this worked for me:



This is part of the code of class subclassed from "AWTGLCanvas" (modified JMECanvas):



public void paintGL() {
        synchronized (PAINT_LOCK) {
            try {
                // if locked, skip repainting this frame
                if(locked)
                    return;
                try {
                    this.makeCurrent();
                } catch (LWJGLException ex) {
                    return;
                }
               

// call rendering here

            } catch (LWJGLException e) {
                logger.log(Level.SEVERE, "Exception in paintGL()", e);
            }
}



Locking and unlocking the canvas:


    public boolean lockEngine() {
        synchronized(PAINT_LOCK) {
            locked = true;
            try {
                this.makeCurrent();
            } catch (LWJGLException ex) {
                locked=false;
            }
        }
        return locked;
    }
   
    public void unlockEngine() {
        locked = false;
    }



Now whenever you do something to the scene from an AWT thread, just call lockEngine() before, and unlockEngine() afterwards. The GL display will freeze for that time, but that is the proper way to do it anyway.

EDIT:
Never mind this, now i noticed that your code actualy breaks in the repaint method, so the code above does not apply to your problem.

Hi,



Well thank you for your answers so far. I got rid of the NullPointer Exception, but after leaving the JPanel where the JMECanvas resides (using SimpleGame Implementation) and going back afterwards with recreating the JPanel and the JMECanvas, I have a strange looking white box in the middle of my game canvas and also my keyboard inputs are ignored. But at least I don't get any exceptions anymore  :wink:



I now use the following cleanup code:


public void cleanup() {
        TextureManager.doTextureCleanup();
        TextureManager.clearCache();
        rootNode.detachAllChildren();
        MouseInput.get().removeListeners();
        MouseInput.destroyIfInitalized();
        KeyInput.get().removeListeners();
        KeyInput.destroyIfInitalized();
}



Any ideas what I'm doing wrong?

Thanks,

Michael

If i remember correctly, the input classes actualy reference the JMECanvas when they are created, they create listeners. My guess is that the listeners still refer to the old canvas, so that is why you dont get any input. Why are you recreating the canvas? You can add the old one to another parent and you can resize it if needed.

Think you also should think about designing the UI in a MVC or similar pattern.



Removing all listeners from the mouse and keyboard will remove ALL listeners. Therefore if you had one listener that delegates all UI calls to the appropiate target you wouldnt need to keep clearing down the mouse listeners.

Hi,



Thank you for your replies so far. Just using the old canvas unfortunately led to very strange results for me. After recreating the panel where the JME Canvas resides and also recreating the JME Canvas, I don't get any keyboard input anymore. How can it be that the input classes still reference to the old canvas when I do the following cleanup statements?



jmeCanvasPanel.removeKeyListener(keyListener);

KeyInput.get().removeListeners();

KeyInput.destroyIfInitalized();



After recreating the JME Canvas I do the following keyboard input initialization:



((JMECanvas) jmeCanvasPanel).setUpdateInput(true);



if (!KeyInput.isInited()) {

KeyInput.setProvider(InputSystem.INPUT_SYSTEM_AWT);

} else {

System.out.println("Could not set Key Provider!!!");

}



kl = (KeyListener) KeyInput.get();

jmeCanvasPanel.addKeyListener(kl);



Thanks,



Michael