BaseApplet lifecycle problems and an initial patch

Hi all,



I'm testing the lifecycle of jme2 SimpleApplet class, and it seems to me it is broken (similar problems occur with StandardApplet class, too).

Two use cases with the TestSimpleApplet class loaded by Sun appletViewer:



a) Restart

if the user selects the appletViewer "Restart" menu item, the jvm process hangs.

No logs, no stack traces.



Restart calls the following applet methods:

  • destroy
  • init
  • start



    b) Reload

    if the user selects the appletViewer "Reload" menu item, this breaks the application.

    This is the log:



INFO: display_parent.isDisplayable() = false
org.lwjgl.LWJGLException: Parent.isDisplayable() must be true
   at org.lwjgl.opengl.Display.createWindow(Display.java:303)
   at org.lwjgl.opengl.Display.create(Display.java:840)
   at org.lwjgl.opengl.Display.create(Display.java:768)
   at com.jmex.awt.applet.BaseApplet$1.run(BaseApplet.java:122)
28-dic-2009 2.18.22 com.jme.renderer.lwjgl.LWJGLRenderer <init>
INFO: LWJGLRenderer created. W: 640 H: 480   Version: 2.2.1
28-dic-2009 2.18.22 class jmetest.awt.applet.TestSimpleApplet start()
GRAVE: Exception in game loop
java.lang.NullPointerException
   at com.jme.renderer.lwjgl.LWJGLRenderer.<init>(LWJGLRenderer.java:200)
   at com.jme.system.lwjgl.LWJGLDisplaySystem.initForApplet(LWJGLDisplaySystem.java:708)
   at com.jmex.awt.applet.BaseApplet.gameLoop(BaseApplet.java:152)
   at com.jmex.awt.applet.BaseApplet$1.run(BaseApplet.java:128)
28-dic-2009 2.18.22 com.jmex.awt.applet.BaseSimpleApplet cleanup
INFO: Cleaning up resources.
28-dic-2009 2.18.22 com.jmex.awt.applet.BaseApplet$1 run
INFO: Application ending.



Reload calls the following applet methods:
* destroy
* new applet instance (constructor, if any)
* init
* start
   
I tried to fix the BaseApplet class (used by SimpleApplet)... initial patch in attachment.
The same use cases:

a) Restart

"Restart" seems to work now.
The unique problem with TestSimpleApplet class is that the "F4 - toggle stats" text object is not correctly rendered when the applet restarts.

b) Reload

still doesn't work. The log contains:


Exception in thread "Thread-8" java.lang.RuntimeException: org.lwjgl.LWJGLException: Parent.isDisplayable() must be true
   at com.jmex.awt.applet.BaseApplet$1.run(BaseApplet.java:133)
Caused by: org.lwjgl.LWJGLException: Parent.isDisplayable() must be true
   at org.lwjgl.opengl.Display.createWindow(Display.java:303)
   at org.lwjgl.opengl.Display.create(Display.java:840)
   at org.lwjgl.opengl.Display.create(Display.java:768)
   at com.jmex.awt.applet.BaseApplet$1.run(BaseApplet.java:130)



BaseApplet init() method adds the new created "displayParent" canvas to the applet container and then calls thsi.setVisible(true).
So I don't understand why the "displayParent" canvas object, when the applet is reloaded, is NOT displayable (that is, not attached to any parent container or not visible, is it correct ?).

Any idea ???

Thank you,
Luca

Ok, two things…



Sun appletViewer doesn't have the same behaviour of the applet container provided by the browser… so my previous tests are not really correct.



I discovered my applet lifecycle problem was generated by this beast:



29-dic-2009 3.43.54 class com.lotec.worldviewer.WorldViewerApplet start()
GRAVE: Exception in game loop
java.lang.OutOfMemoryError: Direct buffer memory
    at java.nio.Bits.reserveMemory(Unknown Source)
    at java.nio.DirectByteBuffer.<init>(Unknown Source)
    at java.nio.ByteBuffer.allocateDirect(Unknown Source)
    at com.jme.util.geom.BufferUtils.createByteBuffer(BufferUtils.java:850)
    at com.jme.util.TextureManager.loadImage(TextureManager.java:675)
    at com.jme.util.TextureManager.loadImage(TextureManager.java:524)
    at com.jme.util.TextureManager.loadImage(TextureManager.java:482)
    at com.jme.util.TextureManager.loadImage(TextureManager.java:460)
    at com.jme.util.TextureManager.loadTexture(TextureManager.java:350)
    at com.jme.util.TextureManager.loadTexture(TextureManager.java:311)
    at com.jme.util.TextureManager.loadTexture(TextureManager.java:255)
    at com.jmex.game.state.load.TransitionGameState.initBackground(TransitionGameState.java:106)
    at com.jmex.game.state.load.TransitionGameState.<init>(TransitionGameState.java:39)
    at com.lotec.worldviewer.state.WorldViewerState.createWorldState(WorldViewerState.java:219)
    at com.lotec.worldviewer.WorldViewerApplet.startGame(WorldViewerApplet.java:22)
    at com.lotec.jme.game.LotecGameApplicationApplet.initGame(LotecGameApplicationApplet.java:44)
    at com.jmex.awt.applet.StandardApplet.gameLoop(StandardApplet.java:318)
    at com.jmex.awt.applet.StandardApplet$1.run(StandardApplet.java:278)
29-dic-2009 3.43.54 com.jmex.awt.applet.StandardApplet$1 run



I tried to dig into the StandardApplet code ... and it seems to me when an user refreshes the browser window, the applet never calls the cleanup() method (that calls  TextureManager.doTextureCleanup() & TextureManager.clearCache()).

To force the applet to exit to the main gameLoop() method, and then to call the cleanup() one, it seems to me it is sufficient to add:


  @Override
  public void stop()
  {
    logger.info("Applet stopped");
    finish();  // force the system to exit from gameLoop() method
   
    pause(1000); // Thread.sleep stuff ... wait a bit... gameLoop thread should terminate, now...
  }



What do you think about it ?

Thank you,
Luca