Where in the code is the window created?

Or alternately, is there any way to modify the display area without modifying the JME source code?



I want to be able to include the Lobo browser alongside the game window. I had code that did this in a test application that called JOGL directly, but now I’d like to be able to do it alongside JME.



This is what the code in the test app looks like:



      mainWindow = new Frame("Sage Games");
      
      mainWindow.setSize(640, 480);
      mainWindow.setMinimumSize(new Dimension(640, 480));
      mainWindow.setBackground(Color.BLACK);

      SpringLayout sl = new SpringLayout();
      mainWindow.setLayout(sl);
      
      glPanel = new GLCanvas();
      glPanel.addGLEventListener(sg);
      final Animator animator = new Animator(glPanel);
      mainWindow.addWindowListener(new WindowAdapter() {
         @Override
         public void windowClosing(WindowEvent e) {
            // Run this on another thread than the AWT event queue to
            // make sure the call to Animator.stop() completes before
            // exiting
            new Thread(new Runnable() {
               public void run() {
                  animator.stop();
                  System.exit(0);
               }
            }).start();
         }
      });
      
      mainWindow.add(glPanel);
      sl.putConstraint(
         SpringLayout.WEST, glPanel, 0,
         SpringLayout.WEST, mainWindow
      );
      sl.putConstraint(
         SpringLayout.NORTH, glPanel, 0,
         SpringLayout.NORTH, mainWindow
      );
      sl.putConstraint(
         SpringLayout.SOUTH, glPanel, 0,
         SpringLayout.SOUTH, mainWindow
      );
      
      if (LOAD_LOBO) {
         try {
            PlatformInit.getInstance().initLogging(false);
            PlatformInit.getInstance().init(false, false);
      
            loboPanel = new FramePanel();
         }
         catch (Exception e) {
            loboPanel = null;
         }
      }
      
      if (loboPanel != null) {
         mainWindow.add(loboPanel);
         
         sl.putConstraint(
            SpringLayout.WEST, loboPanel, -200,
            SpringLayout.EAST, mainWindow
         );
         sl.putConstraint(
            SpringLayout.EAST, loboPanel, 0,
            SpringLayout.EAST, mainWindow
         );
         sl.putConstraint(
            SpringLayout.NORTH, loboPanel, 0,
            SpringLayout.NORTH, mainWindow
         );
         sl.putConstraint(
            SpringLayout.SOUTH, loboPanel, 0,
            SpringLayout.SOUTH, mainWindow
         );
         
         try {
            loboPanel.navigate("http://www.google.com/");
         }
         catch (Exception e) {
            
         }
         
         sl.putConstraint(
            SpringLayout.EAST, glPanel, -2,
            SpringLayout.WEST, loboPanel
         );
      }
      else {
         sl.putConstraint(
            SpringLayout.EAST, glPanel, 0,
            SpringLayout.EAST, mainWindow
         );
      }

      mainWindow.setVisible(true);
      animator.start();

Just use your canvas and place the browser beside it with a Swing layout (I personally like BorderLayout, but if you are comorftable with SpringLayout use it).  :slight_smile:

Well this code compiles and runs, but it doesn't show the browser:


import java.util.concurrent.Callable;

import com.jme.bounding.BoundingSphere;
import com.jme.math.Vector3f;
import com.jme.scene.shape.Box;
import com.jme.util.GameTaskQueueManager;
import com.jmex.editors.swing.settings.GameSettingsPanel;
import com.jmex.game.StandardGame;
import com.jmex.game.state.DebugGameState;
import com.jmex.game.state.GameStateManager;

import java.awt.Canvas;
import java.awt.Container;
import javax.swing.SpringLayout;
import org.lobobrowser.gui.FramePanel;
import org.lobobrowser.main.PlatformInit;

/**
 * <code>TestStandardGame</code> is meant to be an example replacement of
 * <code>jmetest.base.TestSimpleGame</code> using the StandardGame implementation
 * instead of SimpleGame.
 *
 * @author Matthew D. Hicks
 */
public class TestJME {
   public static void main(String[] args) throws Exception {
       // Enable statistics gathering
       System.setProperty("jme.stats", "set");
      
      // Instantiate StandardGame
      StandardGame game = new StandardGame("A Simple Test");
      // Show settings screen
      if (GameSettingsPanel.prompt(game.getSettings())) {
         
         // Start StandardGame, it will block until it has initialized successfully, then return
         game.start();
         
         GameTaskQueueManager.getManager().update(new Callable<Void>() {

            public Void call() throws Exception {
               // Create a DebugGameState - has all the built-in features that SimpleGame provides
               // NOTE: for a distributable game implementation you'll want to use something like
               // BasicGameState instead and provide control features yourself.
               DebugGameState state = new DebugGameState();
               // Put our box in it
               Box box = new Box("my box", new Vector3f(0, 0, 0), 2, 2, 2);
                box.setModelBound(new BoundingSphere());
                box.updateModelBound();
                // We had to add the following line because the render thread is already running
                // Anytime we add content we need to updateRenderState or we get funky effects
                state.getRootNode().attachChild(box);
                box.updateRenderState();
               // Add it to the manager
               GameStateManager.getInstance().attachChild(state);
               // Activate the game state
               state.setActive(true);
               
               return null;
            }
         });
         
         FramePanel loboPanel = null;
         Canvas glPanel = game.getCanvas();
         Container tainer = glPanel.getParent();
         SpringLayout sl = new SpringLayout();
         tainer.setLayout(sl);
         
         try {
            PlatformInit.getInstance().initLogging(false);
            PlatformInit.getInstance().init(false, false);
      
            loboPanel = new FramePanel();
         }
         catch (Exception e) {
            loboPanel = null;
         }
         
         if (loboPanel != null) {
            tainer.add(loboPanel);

            sl.putConstraint(
               SpringLayout.WEST, loboPanel, -200,
               SpringLayout.EAST, tainer
            );
            sl.putConstraint(
               SpringLayout.EAST, loboPanel, 0,
               SpringLayout.EAST, tainer
            );
            sl.putConstraint(
               SpringLayout.NORTH, loboPanel, 0,
               SpringLayout.NORTH, tainer
            );
            sl.putConstraint(
               SpringLayout.SOUTH, loboPanel, 0,
               SpringLayout.SOUTH, tainer
            );
            
            try {
               loboPanel.navigate("http://www.google.com/");
            }
            catch (Exception e) {
               
            }
            
            sl.putConstraint(
               SpringLayout.EAST, glPanel, -2,
               SpringLayout.WEST, loboPanel
            );
         }
      }
   }
}



I'm using SpringLayout because the Lobo panel ignores having its size set. SpringLayout lets me force a width on it.
  • Specifically, I'm getting a null pointer exception when I call getParent()

Umm, you cant use the 'native' LWJGL window to do that (in your previous code snippet there was only a reference to canvas, which I assumed was a LWLJGL canvas). 



You will need to implement the AWT gfx stuff (implementor and canvas)



Here is a bundled class I created (for ease of use)



import com.jme.input.InputSystem;
import com.jme.input.KeyInput;
import com.jme.input.MouseInput;
import com.jme.scene.Node;
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.jme.util.Timer;
import com.jmex.awt.input.AWTKeyInput;
import com.jmex.awt.input.AWTMouseInput;
import com.jmex.awt.lwjgl.LWJGLAWTCanvasConstructor;

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.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelListener;
import java.util.concurrent.Callable;



public class AwtGfxImplementor extends JMECanvasImplementor {

    private final GfxCanvas gfxCanvas;
    private final Node rootNode = new Node( "rootNode" );
    //
    private Timer timer = null;

    public AwtGfxImplementor() throws Exception {

        gfxCanvas = new GfxCanvas( this, 800, 600 );
    }

    @Override
    public void doSetup() {
        super.doSetup();

        gfxCanvas.setUpdateInput( false );

        setRenderer( DisplaySystem.getDisplaySystem().getRenderer() );
        getRenderer().setCamera( getRenderer().createCamera( 800, 600 ) );
        timer = Timer.getTimer();
    }

    public void doUpdate() {
        timer.update();
        rootNode.updateGeometricState( timer.getTimePerFrame(), true );
        GameTaskQueueManager.getManager().getQueue( GameTaskQueue.UPDATE ).execute();
    }

    @Override
    public void doRender() {

        renderer.clearBuffers();

        GameTaskQueueManager.getManager().getQueue( GameTaskQueue.RENDER ).execute();

        renderer.draw( rootNode );

        renderer.displayBackBuffer();
    }


    public Canvas getCanvas() {
        return gfxCanvas.getCanvas();
    }


    public Node getRootNode() {
        return rootNode;
    }





    private class GfxCanvas {

        private final JMECanvasImplementor implementor;
        private final Canvas gfxCanvas;

        public GfxCanvas( final JMECanvasImplementor imp, int width, int height ) throws Exception {
            this.implementor = imp;

            final DisplaySystem display = DisplaySystem.getDisplaySystem();

            display.registerCanvasConstructor( "AWT", LWJGLAWTCanvasConstructor.class );
            gfxCanvas = (Canvas) display.createCanvas( width, height );

            gfxCanvas.addComponentListener( new ComponentAdapter() {

                @Override
                public void componentResized( ComponentEvent ce ) {
                    doResize();
                }
            } );

            gfxCanvas.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 );
                }
            } );

            setImplementor( implementor );

            if( !KeyInput.isInited() ){
                KeyInput.setProvider( InputSystem.INPUT_SYSTEM_AWT );
            }

            if( !MouseInput.isInited() ){
                MouseInput.setProvider( InputSystem.INPUT_SYSTEM_AWT );
                AWTMouseInput.setup( gfxCanvas, false );
            }


            ( (AWTMouseInput) MouseInput.get() ).setEnabled( true );
            gfxCanvas.addMouseListener( (MouseListener) MouseInput.get() );
            gfxCanvas.addMouseWheelListener( (MouseWheelListener) MouseInput.get() );
            gfxCanvas.addMouseMotionListener( (MouseMotionListener) MouseInput.get() );

            ( (AWTKeyInput) KeyInput.get() ).setEnabled( true );
            KeyListener kl = (KeyListener) KeyInput.get();
            gfxCanvas.addKeyListener( kl );

            setTargetRate( 60 );
            setDrawWhenDirty( false );
            setUpdateInput( true );
        }

        public Canvas getCanvas() {
            return gfxCanvas;
        }

        public void setImplementor( JMECanvasImplementor impl ) {
            ( (JMECanvas) gfxCanvas ).setImplementor( impl );
        }

        public void setUpdateInput( boolean doUpdate ) {
            ( (JMECanvas) gfxCanvas ).setUpdateInput( doUpdate );
        }

        public int getTargetSyncRate() {
            return ( (JMECanvas) gfxCanvas ).getTargetSyncRate();
        }

        public boolean isDrawWhenDirty() {
            return ( (JMECanvas) gfxCanvas ).isDrawWhenDirty();
        }

        public boolean isUpdateInput() {
            return ( (JMECanvas) gfxCanvas ).isUpdateInput();
        }

        public void makeDirty() {
            ( (JMECanvas) gfxCanvas ).makeDirty();
        }

        public void setDrawWhenDirty( boolean whenDirty ) {
            ( (JMECanvas) gfxCanvas ).setDrawWhenDirty( whenDirty );
        }

        public void setTargetRate( int fps ) {
            ( (JMECanvas) gfxCanvas ).setTargetRate( fps );
        }

        public void exit() {
            ( (JMECanvas) gfxCanvas ).killGfxContext();
        }

        private void doResize() {

            if( !implementor.isSetup() ){
                return;
            }

            GameTaskQueueManager.getManager().getQueue( GameTaskQueue.UPDATE ).enqueue(
                    new Callable() {

                        public Object call() {
                            implementor.resizeCanvas( gfxCanvas.getWidth(), gfxCanvas.getHeight() );
                            return null;
                        }
                    } );
        }
    }
}



And a test to show how to use it:


import java.awt.BorderLayout;
import java.awt.Dimension;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JPanel;



public class CanvasTest {


    // Start Test Stuff
    public static void main( String[] args ) {
        try{
            new CanvasTest().launchCanvasTest();
        } catch( Exception ex ){
            Logger.getLogger( CanvasTest.class.getName() ).log( Level.SEVERE, null, ex );
        }
    }
   
    protected void launchCanvasTest() {


        AwtGfxImplementor gfxImp = null;
        try{
            gfxImp = new AwtGfxImplementor();
        } catch( Exception ex ){
            Logger.getLogger( CanvasTest.class.getName() ).log( Level.SEVERE, null, ex );
            System.exit( -1 );
        }


        final JPanel mainPanel = new JPanel( new BorderLayout() );
        mainPanel.setPreferredSize( new Dimension( 800, 600 ) );
        mainPanel.add( gfxImp.getCanvas(), BorderLayout.CENTER );

        JFrame frame = new JFrame();
        frame.setContentPane( mainPanel );
        frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
        frame.pack();
        frame.setVisible( true );
    }

}



(Not this creates a LWJGL canvas, for JOGL implementation it will need to be modified...)

I've got tutorials showing me how to init, update, and paint using SimpleGame, StandardGame, etc. In your example code, how do I proceed on to those?

Sage Rat said:

I've got tutorials showing me how to init, update, and paint using SimpleGame, StandardGame, etc. In your example code, how do I proceed on to those?


Those game classes aren't the same as a canvas implementer, as the latter is intended to be used to render to an AWT Canvas that you can place in a JFrame/jpanel/etc, so you can build your Swing application and have your browser window on the left on one panel, and a canvas for whats in jMe on your right on another (or whatever you are striving for).

If you go the SimpleGame style route, you'd be working with a native window, not a canvas that can be embedded into a Swing app, so it's stand alone. If you go with that route, you'd have to put your browser inside it using something like JMEDesktop (essentially embedding a swing app in jme heh), but that's more of a "using Swing as a HUD" rather than something that co-exists with your 3D app (as your original post mentions).

They're two different methods of using jME so I'm not exactly sure what you're asking, because basixs gave a nice way of implementing the canvas to be used in a Swing app, and of course there's lots of tutorials (as you mention) for doing it the "regular" way.