Large Scenegraph

Hey all - newbie here. I’ve searched the forums and the web in general for an answer to this question, so maybe you all will take a moment and help a newbie out a bit…



I’m using JME3 in a Swing scientific engineering application which requires that the user load and display hundreds of objects in the scenegraph at the push of a button. I need to know if there is a way to check for the finish of the drawing of all the objects to the screen. The purpose of this would be to provide the user of the application with a busy cursor during the several seconds that it takes to load all the models and draw them all on the canvas. Any help would be appreciated. Thanks. (sorry if this is in the wrong thread… I didn’t know where else to post this to).

The loading screen is a good example of this:

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

As you are using swing you should be used to the implications of an update loop like the AWT one. Just make sure you use jME3’s app.enqueue() like you would use SwingUtilities.invokeLater() for swing.

The actual drawing of your objects should be fast (assuming you are getting a decent framerate) so all you need to worry about is the load time.



Surely that means that all you need to do is start the “please wait” thingy when you start the loading process, then on the GUI thread run through the list of objects to load.



Once they’ve all been attached to the scene graph you are done and can close the “please wait”.



If you want to show partial rendering as the scene loads then chunk it up and attach X objects per frame rather than holding everything until they are all done.



(i.e. if you have a thousand objects rather than attaching 1000 at once attach 10 each frame until the list is exhausted - that will allow the ones already loaded to keep displaying at a decent framerate and won’t actually slow your loading down as much as you might think…since the load time for each chunk is the same as it would be anyway and the time taken to display each frame inbetween isn’t too large.)



That will also have the advantage of getting the process of sending everything over to the graphics card underway as well.

wezrule2, normen, and zarch - thanks to you all for your kind help and quick replies.



@normen: I learned the hard way a while back about the need to enqueue calls onto the JME thread when interacting with the scenegraph. :slight_smile:



@wezrule2: Thanks for the link. After digging through the wiki for months now, can you believe I’ve not noticed that particular link before? Although it had some good points, unfortunately the two examples there didn’t bring closure to my problem. In the first example, the objective is to split the loading up into smaller chunks and update a nifty progress bar after loading each chunk… unfortunately, I am pretty much forced (for reasons I can’t go into right now) to load everything in one shot. So, in following the first example, for frameCount == 1, I set my busy cursor on the window and then performed the entire loading operation … then for frameCount == 2, I set my cursor back to normal and set load back to false. Result: still no busy cursor while the canvas sits there empty for about 3 or 4 seconds until everything shows up on the screen (no surprise there :stuck_out_tongue_winking_eye: ). For the second example (the threaded example) I could not adopt that strategy because you cannot attach objects to the scenegraph from inside the Callable, which is what I think I would need to be doing while waiting for the Future object to set the isDone() flag to true and then setting my cursor back to normal. What would be most helpful is if there was some sort of “I’m done drawing everything to the screen” flag somewhere in the API that I could repeatedly check from inside the update loop to see when the scene had completed drawing and then set my busy cursor back to normal. So, here’s the geeky question for anyone who might know: Is there such a flag available anywhere in the API, and if not, where and how might I go about modifying the API to put such a flag in place?



Again, thank you all for your kind support !

When the next update() is called, the previous frame is done.



If you are enqueuing a Callable on the rendering thread using Application.enqueue() it CAN add things to the scene graph.



If you’ve enqueued more than one thing then enqueue yet another thing to notify you when it is executed. All enqueued items are executed in order and all currently enqueued items are executed completely in an update() pass.



So I’m not sure what the issue you have is but maybe it’s just one of understanding.

@jmonkeyfan said:
@wezrule2: Thanks for the link. After digging through the wiki for months now, can you believe I've not noticed that particular link before?


Its inside one of the NiftyGUI wiki pages, just gotta look harder :P

@jmonkeyfan said:
For the second example (the threaded example) I could not adopt that strategy because you cannot attach objects to the scenegraph from inside the Callable


pretty sure you can

@pspeed, @wezrule2 … The threading example doesn’t enqueue a callable on the rendering thread. It submits a callable to the executor service, so you really can’t add objects to the scene from there. The example even tells you so.



Unfortunately I cannot post any code here due to restrictions on it’s distribution, so maybe my problem would be better stated like this: a push of a button on my swing thread enqueues a large scene loading operation on the renderer thread. Now, since the operation was enqueued on the renderer thread from the swing thread, the Swing thread then continues along happily and has no idea about the state of the large operation that is now occurring on the renderer thread. I need to somehow detect when the renderer thread is finished with it’s load operation so that I can provide the user of the application some type of notification when the loading operation is in progress and when it is finished (I don’t want my user pushing the button twice thinking nothing happened on the first push). From what I can tell by digging through the API, unless I missed it, there is no way to tell when the renderer has finished that large drawing operation except to just sit back and wait for it all suddenly appear on the screen.

You submitted your own callable. That callable is run on the rendering thread. Your own callable can notify you however it wants and can even send you a notification of some kind when it’s finished. It could even have been given a Swing ProgressMonitor object to report progress to or whatever.



The loading is what is taking a long time… not the rendering.

Thanks pspeed, and yes, I realize that the loading and not the rendering is what is taking so long. Your suggestion about using a ProgressMonitor seems to be the thing I need to do, but I’ve no clue how I should incorporate it. Can you post an example of how I should incorporate a ProgressMonitor object to report the progress on the loading operation?



Thanks !

[java]

public class YourCallable implements Callable {

private ProgressMonitor theMonitor;

private WhateverJmeStuffYouNeed something;



public YourCallable( ProgressMonitor theMonitor, WhateverJmeStuffYouNeed something ) {

this.theMonitor = theMonitor;

this.something = something;

}



public Object call() {

// do your loading

/// report your progress

}

}[/java]



Seems pretty simple to me. So I’m not sure where the confusion is… are you really new to Java by any chance? If so, I recommend brushing up on some tutorials maybe.

[java]

AppContext.getJme3().enqueue(new Callable<Object>() {



public Object call() throws Exception {

doMyReallyLongThing();

notifyWhateverILikeHoweverILikeThatItIsDone();

return null;

}



});

[/java]

@pspeed said:

Seems pretty simple to me. So I'm not sure where the confusion is... are you really new to Java by any chance? If so, I recommend brushing up on some tutorials maybe.


Doh, you beat me by 4 minutes with a more detailed example :p

What I get for not replying immediately after opening a page...
@zarch said:
Doh, you beat me by 4 minutes with a more detailed example :p

What I get for not replying immediately after opening a page...


@normen needs to add a ninja monkey icon for these cases. :)

Thanks guys for putting up with me and for your help.



@zarch, Thanks for your suggestion. I’ve tried it already and that line “notifyWhateverILikeHoweverILikeThatItIsDone();” seems to execute before everything shows up visually in the scene. In the code snippet below, my default cursor shows back up almost immediately and beats the objects showing up in the scene by about 3-4 seconds on average. Please don’t flame me for my poor coding skills … I’ve just begun learning all this.



[java] AppContext.getJme3().enqueue(new Callable<Object>() {

public Object call() throws Exception {

try {

window.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));

doMyReallyLongThing();

} catch (Exception e) {

e.printStackTrace();



} finally {

window.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));



}

return null;

}

});[/java]

Code looks fine to me, nice to see proper use of a finally block :smiley:



All I can suggest is that your doMyReallyLongThing is not actually the thing that’s taking the time. Perhaps try commenting chunks of it out and see if you can identify what it is that you are triggering that is finishing later?



I’m going to bow out at this stage though as pspeed has infinitely more JME3 experience than me.

@jmonkeyfan said:
Thanks guys for putting up with me and for your help.

@zarch, Thanks for your suggestion. I've tried it already and that line "notifyWhateverILikeHoweverILikeThatItIsDone();" seems to execute before everything shows up visually in the scene. In the code snippet below, my default cursor shows back up almost immediately and beats the objects showing up in the scene by about 3-4 seconds on average. Please don't flame me for my poor coding skills ... I've just begun learning all this.

[java] AppContext.getJme3().enqueue(new Callable&lt;Object&gt;() {
public Object call() throws Exception {
try {
window.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
doMyReallyLongThing();
} catch (Exception e) {
e.printStackTrace();

} finally {
window.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));

}
return null;
}
});[/java]


In your code block, what does getJme3() return?

If you put something like:
long start = System.nanoTime();
Before the doReallyLongThing() and after it put:
long end = System.nanoTime();
long time = end - start;
System.out.println( "Really long thing took:" + (time / 1000000.0) + " ms" );

That will show you how long doReallyLongThing() is actually taking.

I think the getJME3() was copied from my example. It returns the SimpleApplication.

@pspeed said:
In your code block, what does getJme3() return?


It returns my instance of the application.


If you put something like:
long start = System.nanoTime();
Before the doReallyLongThing() and after it put:
long end = System.nanoTime();
long time = end - start;
System.out.println( "Really long thing took:" + (time / 1000000.0) + " ms" );

That will show you how long doReallyLongThing() is actually taking.


It actually takes very little time for the code to traverse that doReallyLongThing() call which iterates a list of a couple thousand objects and loads models for them and attaches them to the scene. There is still a few seconds of time after the print statement before all the objects appear in the scene. I get the feeling that the application thread is throwing the drawing operations over the wall to yet another thread, like the ljwgl thread. I really haven't a clue about that, so don't pound me too hard for making the assumption, but that really feels like the sort of behavior that is going on here. Just like it's been submitted to yet another thread for interaction with the graphics card. Just my stupid humble opinion...

The render calls are submitted to the GPU and that takes time. update() enqueues everything to go and then render() actually sends them to the GPU… this is all done on the “open GL thread”… or “application thread” as you put it.



By the time the next update() is called, all of that has been rendered since it’s all on the same thread.



If you really wanted to catch the next update() you could always attach an app state at the end of your processing just to remove it again when it’s update is called. App states added in one update cycle won’t be initialized and updated until the next update cycle… at least if you are running the latest stable build.