Swing: Editor with multiple 3D views

Hello,

currently, I’m working on a editor for three-dimensional visual languages. This editor should support multiple views, so I realized this as a Multiple Document Interface using the Java classes JDesktopPane and JInternalFrame. To support a 3D view for a internal frame proceed like in the swing canvas example (in the wiki) by using a subclass of SimpleApplication.

If I have only one internal frame, already is fine and it works as it should be work. But my goal is to support multiple 3D views, which bases on a instance of SimpleApplication class, each. Unfortunately, it is not possible to have multiple SimpleApplication instances at the same. So, I have the idea to have only one instance for that window which has the focus. If the focus switches from view1 to view2, I would like to stop the SimpleApplication instance for view1 and instaciate a new application for view2. Is this in generally possible? Some initial experiments fails. Or can the AwtPanel class solve my problem?

Ok, may be that should be a way that will work. But I think that is contrary to my actual implementation. Because I have for each internal frame window one SimpleApplication instance. And following your idea, I need one SimpleApplication instance and as many scene graph nodes as views to structure the different content for each view in the scene graph. And then I have a associate such scene graph node with a new viewport (which has its own camera). Yes, that should work, but really a lot of work to restructure my (yet complex) project. For that reason I thought, a little “hack” - like mentioned in my first post (stop application when the internal frame lost the focus and restart it when it get the focus) - is easier.

One more question: Assuming, I have multiple viewports (each with a own cam). Is it possible to interact with each view? In the TestMultiViews example it is not possible: the interaction is restricted to the buttom right view.

Hmm… Yes… In that particular example its the same teapot :slight_smile: But im not saying that the example is the exact solution to your needs. But, imagine your different cams look at different teapots.



Pesudo code:

Teapot tp1 = new Teapot();

Teapot tp2 = new Teapot();



Camera cam1 = new Camera();

ViewPort view1 = new Viewport(cam1);



Camera cam2 = new Camera();

ViewPort view2 = new Viewport(cam2);



cam1.lookAt(tp1);

cam2.lookAt(tp2);



There u go… - Thats what I think you need - i might be wrong.

As I unterstand it, it is the same teapot, because it’s the only geometry in the example and is the only child of rootNode. And each viewport refers to this rootNode.

But I thinks my approach is completely different: I would like so show completely different things in each view. And I need for each view interaction support, to allow the user to add or modify objects.

Multiple views, can be solved with having more viewports, and/or multiple cams.



See this example:

http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/renderer/TestMultiViews.java



Is that what you search for?

No, thats not exactly what I want. Because, in that example are four views showing the same tea pot from different perspectives. But my approach is to display completely different things in multiple views. So each view have its own scene graph. Do you have another solution or idea for me?

You can add a cam to each viewPort… So you will have 4 different views. Ergo, its NOT the same teapot the viewPorts will show.



Regarding the scene graph, I think you need to have assistance from a JME developer.

1 Like

This is all easily possible. You just attach a rootNode for each view and render each like in TestMultiViews but you use jme3 AWTPanels to display the output of the views. Don’t forget to call updateLogicalState() and updateGeometricState() on the rootNodes on each update. “Interaction” is two things a) modifying the scene which can be done via each rootNode obviously and b) mouse input which can be set via an InputManager check the AWTPanels tests, you would have to switch the inputManager input panel by swing focus.

Thanks norman for your post.

I have tried to test this approach. Here is my code (based on TestAwtPanels):

[java]package mygame;



import com.jme3.app.SimpleApplication;

import com.jme3.material.Material;

import com.jme3.math.ColorRGBA;

import com.jme3.math.Vector3f;

import com.jme3.renderer.Camera;

import com.jme3.renderer.ViewPort;

import com.jme3.scene.Geometry;

import com.jme3.scene.Node;

import com.jme3.scene.shape.Box;

import com.jme3.system.AppSettings;

import com.jme3.system.awt.AwtPanel;

import com.jme3.system.awt.AwtPanelsContext;

import com.jme3.system.awt.PaintMode;

import java.awt.BorderLayout;

import java.awt.Dimension;

import java.awt.Toolkit;

import java.awt.event.WindowAdapter;

import java.awt.event.WindowEvent;

import javax.swing.JFrame;

import javax.swing.SwingUtilities;



public class MultipleViews extends SimpleApplication {

private static MultipleViews app;

private static AwtPanel panel1, panel2;

private static int panelsClosed = 0;

private static AwtPanelsContext ctx;



private static void createWindowForPanel(final AwtPanel panel, int location){

JFrame frame = new JFrame("Render Display " + location);

frame.getContentPane().setLayout(new BorderLayout());

frame.getContentPane().add(panel, BorderLayout.CENTER);

frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

frame.addWindowListener(new WindowAdapter() {

@Override

public void windowClosed(WindowEvent e) {

if (++panelsClosed == 2){

app.stop();

}

}

public void windowActivated(WindowEvent e) {

ctx.setInputSource(panel);

}

});

frame.pack();

frame.setLocation(location, Toolkit.getDefaultToolkit().getScreenSize().height - 900);

frame.setVisible(true);

}



public static void main(String[] args){

app = new MultipleViews();

app.setShowSettings(false);

AppSettings settings = new AppSettings(true);

settings.setCustomRenderer(AwtPanelsContext.class);

settings.setFrameRate(60);

app.setSettings(settings);

app.start();

ctx = (AwtPanelsContext) app.getContext();



SwingUtilities.invokeLater(new Runnable(){

public void run(){

panel1 = ctx.createPanel(PaintMode.Accelerated);

panel1.setPreferredSize(new Dimension(400, 300));



panel2 = ctx.createPanel(PaintMode.Accelerated);

panel2.setPreferredSize(new Dimension(400, 300));

ctx.setInputSource(panel1);



createWindowForPanel(panel1, 100);

createWindowForPanel(panel2, 500);

}

});

}



@Override

public void simpleInitApp() {

Node rootNodeView1 = new Node(“rootNode View 1”);

Node rootNodeView2 = new Node(“rootNode View 2”);

rootNode.attachChild(rootNodeView1);

rootNode.attachChild(rootNodeView2);



flyCam.setDragToRotate(true);

flyCam.setMoveSpeed(100f);



Box b = new Box(Vector3f.ZERO, 1, 1, 1);

Geometry geom1 = new Geometry(“Box1”, b);

Material mat = new Material(assetManager, “Common/MatDefs/Misc/Unshaded.j3md”);

mat.setColor(“Color”, ColorRGBA.Blue);

geom1.setMaterial(mat);

rootNodeView1.attachChild(geom1);



Box b2 = new Box(new Vector3f(5, 0, 0), 1, 1, 1);

Geometry geom2 = new Geometry(“Box2”, b2);

Material mat2 = new Material(assetManager, “Common/MatDefs/Misc/Unshaded.j3md”);

mat2.setColor(“Color”, ColorRGBA.Red);

geom2.setMaterial(mat2);

rootNodeView2.attachChild(geom2);



Camera cam1 = cam.clone();

ViewPort vp1 = renderManager.createMainView(“view1”, cam1);

//vp1.setClearFlags(true, true, true);

vp1.attachScene(rootNodeView1);

panel1.attachTo(true, vp1);



Camera cam2 = cam.clone();

ViewPort vp2 = renderManager.createMainView(“view2”, cam2);

//vp2.setClearFlags(true, true, true);

vp2.attachScene(rootNodeView2);

panel2.attachTo(true, vp2);





rootNodeView1.updateLogicalState(speed);

rootNodeView1.updateGeometricState();

rootNodeView2.updateLogicalState(speed);

rootNodeView2.updateGeometricState();

}

}[/java]



The idea was to show in one Panel the blue box (attached to rootNodeView1) and in the other panel (attached to rootNodeView2) the red box. The rootNodes are attached to a viewPort each and such viewPorts are attached to the two panels. But the outcome is disappointing:

The first view is empty and the second view shows both boxes twice. Does anybody know what I’m doing wrong?

I am pretty sure you can only override the main framebuffer on one panel. One of the “true” arguments in AwtPanel.attachTo() needs to be “false”. Sorry the docs are a bit lacking for this one

Thank you; with argument “false” the one view shows the red box and the other one the blue box.

But after that, there is another problem: The camera movement is disabled, so can not change the lookAt point by mouse or the camera position by keybord-keys. Do you know, how to enable this?

You’re cloning the camera instead of using the original, what did you expect?