StandardCanvasGame

Hi folks,



I've been playing around with jme for some months now and from the very beginning I wished to use the StandarGame and GameStateManager in order to render to a Canvas.



I'm not a "3D guy", I'm a total newbie and I'm not (yet) a game developer. At this time, I'm interested in deploying swing applications for 3D simulation and system test (robotics, physics, etc.). After a lot of nights without sleeping and a lot of fighting I achieved a very basic StandarGame implementation that is capable to render in a Canvas as it was supposed to StandardGame to do. I create a brand new class inspite of messing with StandardGame for some reasons…I give a couple:

1 - StandardGame is final and this new class is not. Further implementations and customizations are imperial for canvas games.

2 - StandardGame has to many issues with the Canvas mode and it doesn't work at all. I tryed to mess with the StandardGame but this implementation is such different that I found that would be a good decision not to mess with the StandardGame class (to much code for such a powerful and complex class)



This is a 0.1 version. It's far away from being stable and there are some bugs/issues that I want to correct in the future:

1 - Once the canvas is On, the displaysystem and sounds can't be reinitialized. I don't really understand about Java's Concurrency and I don't know very well how to call a function/procedure inside GL thread.

2 - (1) Again! locks and unlocks and calling for example, my destroy() will result in a exception because isn't being called withing GL thread…hope to learn much more about this in the future :?

3 - At this moment I can only use InputSystem.INPUT_SYSTEM_AWT provider…I don't know if it is possible to switch between other providers…can I? or when using a swing/awt application I'm limited to the hardware providers?

4 - JMEDesktop and JMEDesktopStates seem to have problems with swing applications and I don't expect them to work…



In spite of those issues, StandarCanvasGame works very much like StandardGame…lol, at least I hope.



So, the code:


package jmecs.app;

import java.awt.Canvas;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.prefs.BackingStoreException;
import java.util.prefs.Preferences;

import javax.swing.SwingUtilities;

import com.jme.app.AbstractGame;
import com.jme.input.joystick.JoystickInput;
import com.jme.math.Vector3f;
import com.jme.renderer.Camera;
import com.jme.renderer.ColorRGBA;
import com.jme.renderer.Renderer;
import com.jme.scene.Node;
import com.jme.system.DisplaySystem;
import com.jme.system.GameSettings;
import com.jme.system.PreferencesGameSettings;
import com.jme.system.canvas.JMECanvasImplementor;
import com.jme.system.jogl.JOGLDisplaySystem;
import com.jme.system.lwjgl.LWJGLDisplaySystem;
import com.jme.util.GameTaskQueue;
import com.jme.util.GameTaskQueueManager;
import com.jme.util.TextureManager;
import com.jme.util.Timer;
import com.jmex.audio.AudioSystem;
import com.jmex.game.state.BasicGameState;
import com.jmex.game.state.GameStateManager;

/**
 * @author jecs
 * @version 0.2
 *
 * Just works with LWJGL
 */
public class StandardCanvasGame extends AbstractGame
{
   private static final Logger      logger   = Logger.getLogger(StandardCanvasGame.class.getName());

   // #region Variables
   protected Renderer            renderer;
   protected Camera            camera;
   protected GameStateManager      stateManager;
   protected Timer               timer;
   protected Float               tpf;

   protected BasicGameState      rootState;
   protected Node               rootNode;
   protected Canvas            canvas;
   protected JMECanvasImplementor   implementor;

   // #endregion Variables

   // #region Getters & Setters
   public Renderer getRenderer()
   {
      return renderer;
   }

   public Camera getCamera()
   {
      return camera;
   }

   public GameStateManager getStateManager()
   {
      return stateManager;
   }

   public Timer getTimer()
   {
      return timer;
   }

   public Float getTpf()
   {
      return tpf;
   }

   public Canvas getCanvas()
   {
      return canvas;
   }

   public DisplaySystem getDisplay()
   {
      return display;
   }

   public GameSettings getSettings()
   {
      return settings;
   }

   // #endregion Getters & Setters

   // #region Constructors
   public StandardCanvasGame()
   {
      this(null);
   }

   public StandardCanvasGame(GameSettings settings)
   {
      this.settings = settings;
      if (this.settings == null)
      {
         getAttributes();
      }
      DisplaySystem.getDisplaySystem(this.settings.getRenderer());
   }

   // #endregion Constructors

   // #region AbstractGame Implementation
   @Override
   public void start()
   {
      implementor = new BaseCanvasGameImplementor();
      StandardJMECanvas canvasFactory = new StandardJMECanvas(settings.getWidth(), settings.getHeight(), implementor, this);
      canvas = canvasFactory.getGlCanvas();
   }

   @Override
   protected void initSystem()
   {
      logger.info(getVersion());
      display = DisplaySystem.getDisplaySystem();
      displayMins();
      // initSound();
      assertDisplayCreated();
      if (settings.getRenderer().equalsIgnoreCase("JOGL"))
         ((JOGLDisplaySystem) display).initForCanvas(display.getWidth(), display.getHeight());
      else
         ((LWJGLDisplaySystem) display).initForCanvas(display.getWidth(), display.getHeight());

      logger.info("Running on: " + display.getAdapter() + "nDriver version: " + display.getDriverVersion() + "n"
            + display.getDisplayVendor() + " - " + display.getDisplayRenderer() + " - "
            + display.getDisplayAPIVersion());

      renderer = display.getRenderer();
      camera = display.getRenderer().createCamera(display.getWidth(), display.getHeight());
      implementor.setRenderer(display.getRenderer());
      /** Set a black background. */
      display.getRenderer().setBackgroundColor(ColorRGBA.black.clone());

      // Configure Camera
      cameraPerspective();
      cameraRealocate();
      camera.update();
      display.getRenderer().setCamera(camera);

      /** Get a high resolution timer for FPS updates. */
      timer = Timer.getTimer();

      /** Sets the title of our display. */
      String className = getClass().getName();
      if (className.lastIndexOf('.') > 0)
         className = className.substring(className.lastIndexOf('.') + 1);
      display.setTitle(className);
      if ((settings.isMusic()) || (settings.isSFX()))
      {
         initSound();
      }
   }

   @Override
   protected void initGame()
   {
      GameStateManager.create();
      stateManager = GameStateManager.getInstance();
   }

   @Override
   protected void render(float interpolation)
   {
      renderer.clearBuffers();

      // Execute renderQueue item
      GameTaskQueueManager.getManager().getQueue(GameTaskQueue.RENDER).execute();

      // Render the GameStates
      GameStateManager.getInstance().render(interpolation);
   }

   @Override
   protected void update(float interpolation)
   {
      // Execute updateQueue item
      GameTaskQueueManager.getManager().getQueue(GameTaskQueue.UPDATE).execute();

      // Update the GameStates
      GameStateManager.getInstance().update(interpolation);

      if ((settings.isMusic()) || (settings.isSFX()))
      {
         AudioSystem.getSystem().update();
      }
   }

   @Override
   protected void cleanup()
   {
      GameStateManager.getInstance().cleanup();

      try
      {
         if (renderer != null)
            renderer.cleanup(); // causing problems! -> GLCapabilities is null!?
      } catch (Exception e)
      {
         // e.printStackTrace();
      }
      TextureManager.doTextureCleanup();
      TextureManager.clearCache();

      JoystickInput.destroyIfInitalized();
      if (AudioSystem.isCreated())
      {
         AudioSystem.getSystem().cleanup();
      }
   }

   @Override
   protected GameSettings getNewSettings()
   {
      boolean newNode = true;
      Preferences userPrefsRoot = Preferences.userRoot();
      try
      {
         newNode = !userPrefsRoot.nodeExists(this.getClass().getName());
      } catch (BackingStoreException bse)
      {
      }

      return new PreferencesGameSettings(userPrefsRoot.node(this.getClass().getName()), newNode,
            "game-defaults.properties");
   }

   public boolean isSetup()
   {
      if (implementor == null)
         return false;
      return implementor.isSetup();
   }

   protected void initSound()
   {
      AudioSystem.getSystem().getEar().trackOrientation(camera);
      AudioSystem.getSystem().getEar().trackPosition(camera);
   }

   private void displayMins()
   {
      display.setMinDepthBits(settings.getDepthBits());
      display.setMinStencilBits(settings.getStencilBits());
      display.setMinAlphaBits(settings.getAlphaBits());
      display.setMinSamples(settings.getSamples());
   }

   @Override
   protected void quit()
   {
      if (display != null)
      {
         display.reset();
         display.close();
      }
   }

   @Override
   protected void reinit()
   {
      reinitAudio();
      reinitVideo();
   }

   /**
    * Not Yet Tested
    */
   protected void reinitAudio()
   {
      if (AudioSystem.isCreated())
      {
         AudioSystem.getSystem().cleanup();
      }
   }

   /**
    * Not Yet Tested
    */
   protected void reinitVideo()
   {
      displayMins();
      camera = display.getRenderer().createCamera(display.getWidth(), display.getHeight());
      if ((settings.isMusic()) || (settings.isSFX()))
      {
         initSound();
      }
   }

   /**
    * Not Yet Tested
    */
   public void destroy()
   {
      try
      {
         cleanup();
      } catch (Exception e)
      {
         e.printStackTrace();
         logger.warning("Problems while destroying!");
      } finally
      {
         quit();
      }
   }

   // #endregion AbstractGame Implementation

   // #region Other
   private Object   setupLock   = new Object();

   public void waitForSetup() throws InterruptedException
   {
      if (!SwingUtilities.isEventDispatchThread())
      {
         synchronized (setupLock)
         {
            if (!isSetup())
            {
               setupLock.wait();
            }
         }
      }
   }

   protected void cameraRealocate()
   {
      Vector3f loc = new Vector3f(0.0f, 0.0f, 25.0f);
      Vector3f left = new Vector3f(-1.0f, 0.0f, 0.0f);
      Vector3f up = new Vector3f(0.0f, 1.0f, 0.0f);
      Vector3f dir = new Vector3f(0.0f, 0.0f, -1.0f);
      camera.setFrame(loc, left, up, dir);
   }

   protected void cameraPerspective()
   {
      camera.setFrustumPerspective(45.0f, (float) canvas.getWidth() / (float) canvas.getHeight(), 1.0f, 1500.0f);
      camera.setParallelProjection(false);
      camera.update();
   }

   protected void cameraParallel()
   {
      camera.setParallelProjection(true);
      float aspect = (float) canvas.getWidth() / (float) canvas.getHeight();
      camera.setFrustum(-100, 1500, -50 * aspect, 50 * aspect, -50, 50);
      camera.normalize();
      camera.update();
   }

   public void resetCamera()
   {
      cameraRealocate();
   }

   // #endregion Other

   protected class BaseCanvasGameImplementor extends JMECanvasImplementor
   {
      private Lock   updateLock;
      int            preferredFPS         = -1;
      long         preferredTicksPerFrame   = -1;
      long         frameStartTick         = -1;
      long         frames               = 0;
      long         frameDurationTicks      = -1;

      @Override
      public void doSetup()
      {
         updateLock = new ReentrantLock(true); // Make our lock be fair (first come, first serve)
         lock();
         initSystem();
         initGame();
         preferredFPS = settings.getFramerate() > 0 ? settings.getFramerate() : 60;
         if (preferredFPS >= 0)
         {
            preferredTicksPerFrame = Math.round((float) timer.getResolution() / (float) preferredFPS);
         }
         super.doSetup();
         synchronized (setupLock)
         {
            setupLock.notifyAll();
         }
      }

      @Override
      public void doUpdate()
      {
         // Open the lock up for just a brief second
         unlock();
         lock();
         if (preferredTicksPerFrame >= 0)
            frameStartTick = timer.getTime();
         timer.update();
         tpf = timer.getTimePerFrame();
         update(tpf);
      }

      @Override
      public void doRender()
      {
         render(tpf);
         renderer.displayBackBuffer();
         fixFrameRate();
      }

      public void lock()
      {
         updateLock.lock();
      }

      public void unlock()
      {
         updateLock.unlock();
      }

      private void fixFrameRate()
      {
         if (preferredTicksPerFrame >= 0)
         {
            frames++;
            frameDurationTicks = timer.getTime() - frameStartTick;
            while (frameDurationTicks < preferredTicksPerFrame)
            {
               long sleepTime = ((preferredTicksPerFrame - frameDurationTicks) * 1000) / timer.getResolution();
               try
               {
                  Thread.sleep(sleepTime);
               } catch (InterruptedException exc)
               {
                  logger.log(Level.SEVERE, "Interrupted while sleeping in fixed-framerate", exc);
               }
               frameDurationTicks = timer.getTime() - frameStartTick;
            }
            if (frames == Long.MAX_VALUE)
               frames = 0;
         }
      }
   }
}



and the StandarJMECanvas class:


package jmecs.app;

import java.awt.Canvas;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.concurrent.Callable;
import java.util.logging.Logger;

import com.jme.input.InputSystem;
import com.jme.input.KeyInput;
import com.jme.input.MouseInput;
import com.jme.system.DisplaySystem;
import com.jme.system.canvas.JMECanvas;
import com.jme.system.canvas.JMECanvasImplementor;
import com.jme.util.GameTaskQueue;
import com.jme.util.GameTaskQueueManager;
import com.jmex.awt.input.AWTKeyInput;
import com.jmex.awt.input.AWTMouseInput;
import com.jmex.awt.lwjgl.LWJGLAWTCanvasConstructor;

/**
 * @author jecs
 * @version 0.2
 *
 * Just works with LWJGL
 */
public class StandardJMECanvas implements JMECanvas
{

   private static final Logger      logger      = Logger.getLogger(StandardJMECanvas.class.getName());
   protected Canvas            glCanvas   = null;
   protected JMECanvasImplementor   implementor   = null;
   protected DisplaySystem         display      = null;
   protected StandardCanvasGame game = null;

   public StandardJMECanvas(int width, int height, JMECanvasImplementor impl, StandardCanvasGame game)
   {
      display = DisplaySystem.getDisplaySystem();
      display.registerCanvasConstructor("AWT", LWJGLAWTCanvasConstructor.class);
      glCanvas = (Canvas) display.createCanvas(width, height);
      this.game = game;
      // setup future resize behaviour
      glCanvas.addComponentListener(new ComponentAdapter()
      {
         @Override
         public void componentResized(ComponentEvent ce)
         {
            doResize();
         }
      });

      // setup the way Key and Mouse Inputs are set on and off (focus dependant)
      glCanvas.addFocusListener(new FocusListener()
      {
         public void focusGained(FocusEvent arg0)
         {
            ((AWTKeyInput) KeyInput.get()).setEnabled(true);
            ((AWTMouseInput) MouseInput.get()).setEnabled(true);
         }

         public void focusLost(FocusEvent arg0)
         {
            ((AWTKeyInput) KeyInput.get()).setEnabled(false);
            ((AWTMouseInput) MouseInput.get()).setEnabled(false);
         }
      });

      // grant focus when mouse entered
      glCanvas.addMouseListener(new MouseAdapter()
      {
         @Override
         public void mouseEntered(MouseEvent e)
         {
            glCanvas.requestFocus();
            super.mouseEntered(e);
         }
      });

      setImplementor(impl);

      if (!KeyInput.isInited())
         KeyInput.setProvider(InputSystem.INPUT_SYSTEM_AWT);
      if (!MouseInput.isInited())
         AWTMouseInput.setup(glCanvas, false);

      ((AWTKeyInput) KeyInput.get()).setEnabled(true);
      ((AWTMouseInput) MouseInput.get()).setEnabled(true);
      KeyListener kl = (KeyListener) KeyInput.get();
      glCanvas.addKeyListener(kl);

      setUpdateInput(true);

      Callable<?> exe = new Callable<?>()
      {
         public Object call()
         {
            forceUpdateToSize();
            return null;
         }
      };
      GameTaskQueueManager.getManager().getQueue(GameTaskQueue.RENDER).enqueue(exe);
   }

   protected void doResize()
   {
      if (implementor != null && implementor.getRenderer() != null)
      {
         implementor.resizeCanvas(glCanvas.getWidth(), glCanvas.getHeight());
         logger.info("Canvas will resize to: (" + glCanvas.getWidth() + "," + glCanvas.getHeight() + ")");
         
         // Maintain aspect ratio
         Callable<?> exe = new Callable<?>() {
             public Object call() {
            if(game.getCamera().isParallelProjection())
               game.cameraParallel();
            else
               game.cameraPerspective();
            return null;
             }
         };
         GameTaskQueueManager.getManager()
            .getQueue(GameTaskQueue.RENDER).enqueue(exe);
      }
   }

   public void forceUpdateToSize()
   {
      // force a resize to ensure proper canvas size.
      glCanvas.setSize(glCanvas.getWidth(), glCanvas.getHeight() + 1);
      glCanvas.setSize(glCanvas.getWidth(), glCanvas.getHeight() - 1);
   }

   public JMECanvasImplementor getImplementor()
   {
      return implementor;
   }

   @Override
   public void setImplementor(JMECanvasImplementor impl)
   {
      ((JMECanvas) glCanvas).setImplementor(impl);
      this.implementor = impl;
   }

   @Override
   public void setUpdateInput(boolean doUpdate)
   {
      ((JMECanvas) glCanvas).setUpdateInput(doUpdate);
   }

   public Canvas getGlCanvas()
   {
      return glCanvas;
   }

   /**
    * Same as {@link getGlCanvas}
    *
    * @return glCanvas
    */
   public Canvas getCanvas()
   {
      return glCanvas;
   }

   @Override
   public int getTargetSyncRate()
   {
      return ((JMECanvas) glCanvas).getTargetSyncRate();
   }

   @Override
   public boolean isDrawWhenDirty()
   {
      return ((JMECanvas) glCanvas).isDrawWhenDirty();
   }

   @Override
   public boolean isUpdateInput()
   {
      return ((JMECanvas) glCanvas).isUpdateInput();
   }

   @Override
   public void makeDirty()
   {
      ((JMECanvas) glCanvas).makeDirty();
   }

   @Override
   public void setDrawWhenDirty(boolean whenDirty)
   {
      ((JMECanvas) glCanvas).setDrawWhenDirty(whenDirty);
   }

   @Override
   public void setTargetRate(int fps)
   {
      ((JMECanvas) glCanvas).setTargetRate(fps);
   }

   @Override
   public void killGfxContext()
   {
      ((JMECanvas) glCanvas).killGfxContext();
   }

   @Override
   public void setAutoKillGfxContext(boolean shouldAutoKillGfxContext)
   {
      ((JMECanvas) glCanvas).setAutoKillGfxContext(shouldAutoKillGfxContext);
   }

   @Override
   public boolean shouldAutoKillGfxContext()
   {
      return ((JMECanvas) glCanvas).shouldAutoKillGfxContext();
   }
}



Hope that my first contribution helps at least one folk...

Any feedback, ideas and help are very much appreciated. :) jecs

(Sorry for my english)

Here's a test class:


package jmecstests.app;

import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.GridLayout;
import java.awt.Panel;
import java.util.prefs.Preferences;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

import jmecs.app.StandardCanvasGame;

import com.jme.math.Vector3f;
import com.jme.scene.Controller;
import com.jme.scene.Spatial;
import com.jme.scene.Spatial.LightCombineMode;
import com.jme.scene.shape.Box;
import com.jme.scene.state.TextureState;
import com.jme.scene.state.ZBufferState;
import com.jme.scene.state.ZBufferState.TestFunction;
import com.jme.system.DisplaySystem;
import com.jme.system.GameSettings;
import com.jme.system.PreferencesGameSettings;
import com.jme.util.Timer;
import com.jmex.editors.swing.settings.GameSettingsPanel;
import com.jmex.game.state.FPSGameState;
import com.jmex.game.state.GameStateManager;

/**
 * @author jecs
 * @version 1.0
 *
 * Just works with LWJGL
 */
public class StandardCanvasGameTest extends JFrame
{
   private static final long   serialVersionUID   = 1L;
   private JPanel            jContentPane      = null;
   private Panel            panel            = null;
   private Canvas            canvas            = null;
   private StandardCanvasGame   game            = null;
   private static GameSettings   settings         = null;

   public StandardCanvasGameTest()
   {
      super();
      init3D();
      initialize();
   }

   private void init3D()
   {
      game = new StandardCanvasGame(settings);
      game.start();
      new Thread(new Runnable()
      {
         public void run()
         {
            try
            {
               game.waitForSetup();
            } catch (InterruptedException e)
            {
               e.printStackTrace();
            }
            FPSGameState boxState = new FPSGameState()
            {
               {
                  setupNodeZBS(super.rootNode);
                  Box box = createRotatingJMEBox(new Vector3f(-2, -2, -2), new Vector3f(2, 2, 2));
                  rootNode.attachChild(box);
                  rootNode.updateRenderState();
               };

               @Override
               public void update(float tpf)
               {
                  super.update(tpf);
                  rootNode.updateGeometricState(tpf, true);
               }

               @Override
               public void render(float tpf)
               {
                  super.render(tpf);
                  DisplaySystem.getDisplaySystem().getRenderer().draw(rootNode);
               }
            };
            GameStateManager.getInstance().attachChild(boxState);
            boxState.setActive(true);
         }

         protected Spatial setupNodeZBS(Spatial node)
         {
            if (node != null)
            {
               ZBufferState zbs = DisplaySystem.getDisplaySystem().getRenderer().createZBufferState();
               zbs.setEnabled(true);
               zbs.setFunction(TestFunction.LessThanOrEqualTo);
               zbs.setWritable(true);
               node.setRenderState(zbs);
               node.updateRenderState();
               node.updateModelBound();
               node.updateWorldBound();
               node.updateWorldVectors();
               node.updateGeometricState(0.0f, true);
            }
            return node;
         }

         protected Box createRotatingJMEBox(Vector3f min, Vector3f max)
         {
            // Put our box in it
            final Vector3f axis = new Vector3f(1, 1, 0.5f).normalizeLocal();

            final Box box = new Box("Box", min, max);
            box.setRandomColors();
            box.setLightCombineMode(LightCombineMode.Off);
            TextureState ts = DisplaySystem.getDisplaySystem().getRenderer().createTextureState();
            ts.setEnabled(true);
            box.setRenderState(ts);

            // let the box rotate
            box.addController(new Controller()
            {
               private static final long   serialVersionUID   = 1L;

               @Override
               public void update(float time)
               {
                  box.getLocalRotation().fromAngleNormalAxis(Timer.getTimer().getTimeInSeconds(), axis);
               }
            });
            box.updateRenderState();
            setupNodeZBS(box);
            return box;
         }
      }).start();
   }

   private void initialize()
   {
      this.setSize(settings.getWidth(), settings.getHeight());
      this.setContentPane(getJContentPane());
      this.setTitle("StandardCanvasGame Test1");
      this.addWindowListener(new java.awt.event.WindowAdapter()
      {
         @Override
         public void windowClosing(java.awt.event.WindowEvent e)
         {
            game.destroy();
         }
      });
      this.setLocationRelativeTo(null);
   }

   private JPanel getJContentPane()
   {
      if (jContentPane == null)
      {
         jContentPane = new JPanel();
         jContentPane.setLayout(new BorderLayout());
         jContentPane.add(getPanel(), BorderLayout.CENTER);
      }
      return jContentPane;
   }

   private Panel getPanel()
   {
      if (panel == null)
      {
         GridLayout gridLayout = new GridLayout();
         gridLayout.setRows(1);
         panel = new Panel();
         panel.setLayout(gridLayout);
         panel.add(getCanvas(), null);
      }
      return panel;
   }

   private Canvas getCanvas()
   {
      if (canvas == null)
      {
         canvas = game.getCanvas();
      }
      return canvas;
   }

   public static void main(String[] args) throws InterruptedException
   {
      System.setProperty("jme.stats", "set");
      settings = new PreferencesGameSettings(Preferences.userRoot(), true, "game-defaults.properties");
      GameSettingsPanel.prompt(settings);
      SwingUtilities.invokeLater(new Runnable()
      {
         public void run()
         {
            StandardCanvasGameTest thisClass = new StandardCanvasGameTest();
            thisClass.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            thisClass.setVisible(true);
         }
      });
   }
}



:D

Thanx jecs!



I was in the middle of refactoring a rather large project into jME 2.0 and found this little tidbit to bit invaluable.  I am only using your Canvas class (I don't need gameStates for AWT graphics) and the one thing I could suggest is moving the call to resize the frustum out of the GlCanvas and into the StandardGame part.  Also, either you or I should post the GlCanvas stuff in the Wiki under the jME2.0 tutorials.  Since this was your stuff I will give you a couple for days to get it up and if I end up doing it I will make sure you get some credit :).

StandardGame will remain final since it is not designed to be extended and there should be no circumstance where you have to.  Other than that, if there are problems in StandardGame you should consider posting a patch to resolve the problems rather than writing an entirely new class if possible.

Hi jecs,



Could you post your current version of the files? Some things have changed in JMECanvas…

Furthermore: It uses a cameramanager that I don't have… correct?



TIA,

Alex

Thanks jecs, I'll give it a go!

jecs said:

Meanwhile I've make some minor changes and some bug/issues fix. I tried to make it work with JOGL but with no positive results  :'(

Don't be sad, StandardGame doesn't work with JOGL too. As far as I know, the bug I submitted has not been fixed, I haven't found any solution. I had to write a kind of replacement of StandardGame too whereas I would have liked not to do it.

I will try to look into this in the near future (over the weekend I hope)…



jecs I may need to ask a JOGL question or two, its been at least 2 years since I did any JOGL stuff; but maybe it will hit me when looking.