[SOLVED] JME-JavaFX scene synchronization problem

I have decided to use JavaFX for my HUD. All the menus and windows work great so then I decided to port my in game entity identifiers into my JavaXF scene. These are little markers that identify the objects in the scene. My old code painted them on the GUI node so porting them as dynamic JavaFX nodes was a piece of cake.

Now for the problem. Those planet indicators in the screen shot are controlled by the planet controllers. In controlUpdate() I get the entity’s screen coordinates and update the JavaFX node’s x and y settings. When I move the camera my indicators lag behind the spatial. The faster I move it the bigger the lag. Now, I understand that the JME thread and the JavaFX thread are separate but the lag is HUGE and not justified when the JavaFX thread should be running at 60 ticks per second.

Has anyone solved this problem?

One thing to check… since the updating of screen coordinates is going to be based on the current camera view… make sure that the camera view has already been updated when the control’s update is called. It probably is but it’s good to check.

An app state’s postRender() method is one of the absolute last things called, so if you log some kind of frame boundary there, any logging after that should show you the order in the next frame. Generally, InputManager, simpleUpdate(), appState.update(), control update of the root and guiNodes, control render of the root and guiNodes, app state render(), actually rendering the scene, the app state postRender().

…that’s off the top of my head.

Because the JavaFX solution renders to an image and then copies that, it could be that it will always be one frame behind. For something simple like ship markers, you might consider using something more tightly JME-integrated like Lemur. It’s GUI elements are actually spatials and are rendered with everything else… so there will be no lag. (Edit: you can always continue to use JavaFX for the rest of the UI.)

I looked into this further and it’s a JavaFX bug that will not be resolved until JavaFX 9 which will come out when we get JDK9. The problem is that the JavaFX architecture is based on a TWO thread pipeline. One thread that processed events and a separate thread that renders frames. So when I queue up my translation changes with Platform.runLater(() what hapens is my code goes onto the event queue, the event thread picks it up, applies the changes, then the render thread picks up the changes and renders the frame. These two thread are synchronized with a complicated locking mechanism that gives priority to the rendering thread. It’s a VERY STUPID DESIGN that ensures that my code is two frames behind at best (3 with the JME render to texture) … and at worst N+3 frames behind. I confirmed this by just creating a simple JavaFX only application that moved a node around through mouse events … when I moved the mouse quickly the node lagged behind the mouse pointer. This screwed up architecture is why JavaFX will NEVER be a viable technology for the foundation of a gaming engine.

Now, for the million dollar question … can I somehow render the indicator node in a JME quad and move the quad on the gui node in JME and still pick up all the JavaFX mouse / keyboard inputs on the JavaFX node? I saw some old code example on old posts but that old API is deprecated. This way I can use JME for movement and JavaFX for cool controls like animated circular menu items.

JFX is not really viable for live ingame overlays of moving stuff (btw many other engines ui toolkits suffer similar problems, quite some even render their ui trough a chrome based browser)

However there is no reason why the input should not work as expected. Take a look at

public void setEverListeningRawInputListener(final RawInputListener rawInputListenerAdapter)

You can basically get any information from that listener, additionally you can register a focus listener, to notice if something in jfx thinks it has focus.

JFX per default only has focus and consumes the events if something non transparent is on it, else it forwards them to jme.

Yes, this should be possible… but assuming you mean mouse events with your indicators, note that your JavaFX node will lag. That should be ok unless you need to drag them or something.

Note also: if you used Lemur for your ship indicators then you could use its mouse events and just add listeners directly to the indicators. Or if you chose to use JME Quads, you could still use Lemur just to add listeners to the Quad geometries. It’s flexible.

@pspeed am already using lemur. My question really is how to create and destroy the indicator quads that have the fako material that the JavaFX modes are painted on.Is it as simple as a JmeFxTextureContainer instance per indicator?

I don’t know anything about JavaFX or what it’s involved in indicators. So I don’t know.

The indicators are my little squares in the scene with text next to them. My question was can I create a JmeTextureContainer for each one and just use that texture in quads on the root pane?

Isn’t that a long way to go for a little symbol and some text next to it? That’s what I meant by not understanding why JFX has to be involved in the indicators. Seems the long way to go for a relatively simple thing.

Normally I would agree but it’s more than just that. When you hover over is an animated set of circular icons spin out of the center that give the user actions that they can take of the entity. Pilot a ship for example. I get all those cool effects for free with JavaFX. I settled on a proper compromise though … I am using lemur for the symbol and text and using the lemur mouse event handler to overlay the animated icons that are a single reusable JavaFX quad. I have one for each entity type. Everything works perfectly now.

Time to move onto my 3D compass control :slight_smile:

I still wonder why jfx lags so hard for you.

If you have application with 60fps 4frames delay would mean: 64ms delay. However if you take a look at the GuiManager you see that at least per default the jfx thread fps limitation is removed, so it should render pretty fast. How many cpu cores do you have (physical not hyperthreading?) Does it help to use the other Constructor which does not apply those settings?

It’s not that the JavaFX render thread is lagging … It’s a bug in JavaFX … actually it’s more of a JavaFX architectural stupidity. JavaFX rendering works on a two thread model. The event thread and the rendering thread. All your code runs on the event thread and the FPS rendering happens on the rendering thread. The rendering thread has higher priority than the event thread. This means that even if you create a simple JavaFX application where you image follows your mouse and you move your mouse around quickly, the image will ALWAYS lag behind your mouse. No way to fix that unless they change their threading model. This bug (stupid design) has been known for years but they refuse to fix it. There are talks that it will be addressed in JavaFX 9 but I am not holding my breath. I just switched to using lemur for my in game indicators and called it a day.

Yes I know that it always will lag a bit, but I never found it to be that noticeable (I do inventory drag and drop with it)

But yeah depends on speed of objects of course as well. Anyway good you found a solution.

Inventory drag and drop is not an issue but when you pan your camera around and need to move those indicators it’s noticeable because they move around VERY fast.

Yeah, in those cases even one frame late looks very bad… and if JFX doesn’t render this frame then it won’t render until next frame. Can’t be otherwise… and doesn’t really have anything to do with speed of the render.

1 Like

True, for panning scenarios or other faster movements jfx is not possible to be used.

1 Like

@zissis, does that means, that you still use javaFX(for hud) and Lemur(for scene indicators) at the same time?
Or you completely switched from javaFX to Lemur?

I use both at the same time. JavaFX for HUD, windows, menus, etc … but Lemur for in game indicators and in game entity right mouse click action events.

1 Like

Thanks @zissis

1 Like