ViewPort Switchover IllegalStateException

Hey all,



I’m trying to create a map system for Gentrieve 2. When the player enables the map, I want the current viewport to disappear, and a new “Map” viewport to appear. I tried following the instructions here:



https://wiki.jmonkeyengine.org/legacy/doku.php/jme3:advanced:multiple_camera_views



… and came up with this code:



[java] public static void ShowMap() {

//BuildMap();

BaseMapNode = new Node();

if( MapView == null ) {

MapCam = Main.GApp.getCamera().clone();

MapCam.setViewPort(0f, 1f, 0f, 1f);

MapCam.setLocation(new Vector3f(-0.10f, 1.57f, -4.81f));

MapCam.lookAt(Vector3f.ZERO, Vector3f.UNIT_X);

MapView = Main.GApp.getRenderManager().createMainView(“MapView”, MapCam);

MapView.setClearFlags(true, true, true);

MapView.attachScene(BaseMapNode);

}

MapView.setEnabled(true);

Main.GApp.getViewPort().setEnabled(false);

InMap = true;

}

[/java]



… which is called via an ActionListener’s onAction call (e.g. pressing the “M” key) using jMonkeyEngine’s inputManager.



I get this exception immediately when pressing the M key:



[java]SEVERE: Uncaught exception thrown in Thread[LWJGL Renderer Thread,5,main]

java.lang.IllegalStateException: Scene graph is not properly updated for rendering.

State was changed after rootNode.updateGeometricState() call.

Make sure you do not modify the scene from another thread!

Problem spatial name: null

at com.jme3.scene.Spatial.checkCulling(Spatial.java:241)

at com.jme3.renderer.RenderManager.renderScene(RenderManager.java:636)

at com.jme3.renderer.RenderManager.renderViewPort(RenderManager.java:965)

at com.jme3.renderer.RenderManager.render(RenderManager.java:1016)

at com.jme3.app.SimpleApplication.update(SimpleApplication.java:251)

at com.jme3.system.lwjgl.LwjglAbstractDisplay.runLoop(LwjglAbstractDisplay.java:151)

at com.jme3.system.lwjgl.LwjglDisplay.runLoop(LwjglDisplay.java:184)

at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:228)

at java.lang.Thread.run(Thread.java:722)[/java]



If I do MapView.setEnabled(false); – I do not get this exception (but then my map ViewPort doesn’t show…)



Any ideas? :confused:



Thank you!

Why you want to mess as low as with the views? Then you have to manage and update your own scenegraph (as indicated by the message). Just attach/detach a rootNode with an AppState for your in-game and whatever other screens you have.

This documentation says nothing of managing & updating your own scenegraphs:



https://wiki.jmonkeyengine.org/legacy/doku.php/jme3:advanced:multiple_camera_views



… so, it made it sound easy to do it this way. The only other time I’ve seen this exception is when I accidentally make a change in another thread – something I wasn’t doing here.



At any rate, I have many things attached to SimpleApplication.rootNode. Is it possible to detach this node from the scene graph and add another? Or do I need to attach everything to sub-root nodes that get swapped in and out?

I tried this:



[java] public static void ShowMap() {

//BuildMap();

BaseMapNode = new Node();

Main.GApp.getViewPort().detachScene(Main.GApp.getRootNode());

Main.GApp.getViewPort().attachScene(BaseMapNode);

InMap = true;

}[/java]



… and I get the same IllegalStateException :frowning:



EDIT: If I add BaseMapNode.updateGeometricState(); before I attach the scene, it works fine.



shrug

In my “preview window”, where I use a second viewport, I use my own “rootnode” that I have to manage, it works fine.



In your case you’re probably modifying the node after it’s been “updated” so when the rendering part comes up, it’s not refreshed and causes the crash.

This code ended up working, even if it is some kinda bandaid:



[java] public static void ShowMap() {

BuildMap();

BaseMapNode.updateGeometricState();

Main.GApp.getViewPort().detachScene(Main.GApp.getRootNode());

Main.GApp.getViewPort().attachScene(BaseMapNode);

InMap = true;

}[/java]



… I’ll use that for now.

I posted an app state once that helps manage the needs of a ViewPort every frame:

http://hub.jmonkeyengine.org/groups/graphics/forum/topic/can-i-render-an-object-ontop-of-everything-but-under-gui/?topic_page=2&num=15#post-133200

you need to update the Logical state too if you want controls in your UI to be updated (if you have any)



These operations are done by the simple Application on the rootNode, but you have to handle them yourself if you are using your own root Node in a particular scene (here your map ui).

@phr00t said:
At any rate, I have many things attached to SimpleApplication.rootNode. Is it possible to detach this node from the scene graph and add another? Or do I need to attach everything to sub-root nodes that get swapped in and out?

Just use sub-nodes, yeah. Wheres the difference? Or have an AppState manage what Spatials it brings in so it can detach them again.

Thank you for the suggestions, although it looks like just detaching the built-in rootNode from the built-in ViewPort and replacing it with another “map root” node is working. I do have to do the updateGeometricState() call on my “map root” node, but that is easier than organizing all of my objects sitting directly on the built-in rootNode :stuck_out_tongue:

@phr00t said:
Thank you for the suggestions, although it looks like just detaching the built-in rootNode from the built-in ViewPort and replacing it with another "map root" node is working. I do have to do the updateGeometricState() call on my "map root" node, but that is easier than organizing all of my objects sitting directly on the built-in rootNode :P


I'm trying to understand why this is different than adding your map node to the built in root node?

I've never seen the need to replace the built in root node because any time I wanted to create my own root node, I just did and added it as a child of the regular one.
@pspeed said:
I'm trying to understand why this is different than adding your map node to the built in root node?

I've never seen the need to replace the built in root node because any time I wanted to create my own root node, I just did and added it as a child of the regular one.


Chalk it up to poor planning, but my built-in rootNode gets filled with lots of stuff that I don't want rendered while viewing the map. Instead of detaching all of those things, then re-attaching them when leaving the map, I can just detach that whole scene and attach my map scene (and vice versa).

The view is just a super-rootnode, the difference is still not explained. At any instance, tip from the developers of the engine is: Use sub-nodes amd not viewPorts.

In your simple application you could overload getRootNode(). Have it return sceneRootNode which you have attached to the real root node.



Then you can add mapRootNode - and add getMapRootNode() for the map stuff…with a method to swap in and out the two root nodes.

Don’t use the Node constructor without arguments. As the javadoc says its “Serialization only. Do not use.”

@normen said:
The view is just a super-rootnode, the difference is still not explained. At any instance, tip from the developers of the engine is: Use sub-nodes amd not viewPorts.


I'm not sure what explanation you are looking for? Maybe we are talking about the same thing? I changed the "super-rootnode" by detaching the simpleApplication's rootNode from the default ViewPort and attached my own BaseMapNode to the default ViewPort. This is different than keeping the same simpleApplication's rootNode attached to the default ViewPort and attaching BaseMapNode to that rootNode, because all of my other undesired objects would still be attached to the rootNode along with it. At any rate, I didn't create another ViewPort or change the default ViewPort, I just changed its "super-rootnode".

@Momoko_Fan said:
Don't use the Node constructor without arguments. As the javadoc says its "Serialization only. Do not use."


Fixed, thanks.

@zarch said:
In your simple application you could overload getRootNode(). Have it return sceneRootNode which you have attached to the real root node.

Then you can add mapRootNode - and add getMapRootNode() for the map stuff...with a method to swap in and out the two root nodes.


Yeah, there are some other things that could be done here, but it all generally ends up with the same result. I got this working and I'm moving on to debug other stuff now.. :P
@phr00t said:
At any rate, I didn't create another ViewPort or change the default ViewPort, I just changed its "super-rootnode".

Yeah you replaced the rootnode which means you disable the complete default update process, thats definitely not "the same result" as using a root node for your stuff that you attach to the main rootNode. If the update process is changed or extended you have to recreate that in your application. When we develop jme further we always expect people to use the engine as intended, for anything else we cannot assure it will work properly in the future. Ofc you will have another comment on why all this is bollocks and you surely can use and abuse the engine all the way you want but I don't know why you come here for help if you don't want advice.
@normen said:
Yeah you replaced the rootnode which means you disable the complete default update process, thats definitely not "the same result" as using a root node for your stuff that you attach to the main rootNode. If the update process is changed or extended you have to recreate that in your application. When we develop jme further we always expect people to use the engine as intended, for anything else we cannot assure it will work properly in the future.


I said "the same result" as in the results look the same, not necessarily implying it works the same under-the-hood. I understand the potential implications of replacing the rootNode, and the ideal situation would be to organize my nodes correctly off the built-in rootNode. However, I'm not looking to spend the time making sure my game is 100% jME3 future-proof at this pre-alpha point, I've got to get my map system working -- I can always come back later and organize my nodes better (which isn't difficult, it just takes time).

Ofc you will have another comment on why all this is bollocks and you surely can use and abuse the engine all the way you want but I don't know why you come here for help if you don't want advice.


Normen, I have nothing against you. I don't understand why you are always trying to pick a fight with me. I come here for advice, and I get good advice, even from you. I take this advice into consideration, but in the end, I write my own code (just as every other developer does). Can we please remove this combative element from our discussions?
@phr00t said:
I don't understand why you are always trying to pick a fight with me.

In every situation you took as "picking a fight" I was only correcting false statements from your side. As in this case the "same result". You are a good programmer and can handle this I guess, if everybody starts taking apart the bits and pieces like this _we_ are the ones that will drown in the complaints and discussions hence I will continue to do so.
In every situation you took as “picking a fight” I was only correcting false statements from your side.


You are assuming I took other situations in this thread as picking a fight. I did not. This is the statement you made, which I quoted earlier, that is certainly just picking a fight:

Ofc you will have another comment on why all this is bollocks and you surely can use and abuse the engine all the way you want but I don’t know why you come here for help if you don’t want advice.


I don't mind being corrected (or making corrections) -- it means people are learning something.

As in this case the “same result”. You are a good programmer and can handle this I guess, if everybody starts taking apart the bits and pieces like this _we_ are the ones that will drown in the complaints and discussions hence I will continue to do so.


I can understand this concern, it is very valid. However, we'd all be better served if these concerns were shared with the community without the combative attitude.