JPCT and Jide Docking Framework

Started by kavyro, September 01, 2021, 10:42:00 AM

Previous topic - Next topic

kavyro

In our project we use JPCT together with Jide Docking Framework (http://www.jidesoft.com/products/dock.htm). Jide arranges components in "frames". The JPCT canvas (buffer.enableGLCanvasRenderer()) is also running as a separate "frame", so user can move/minimize/maximize the frame freely. Jide frames works perfectly with swing components, but has issues when it comes to JPCT. When application starts everything works OK: the JPCT canvas displays the world with all objects (see screenshot "before.png" in attachments). However when JPCT frame is moved/minimized/maximized/etc most of the objects "disappears" (screenshot "after.png"). It is extremely hard to identify what exactly produces such issues. Neither Jide or JPCT logs any errors. Since not all objects "disappear" but most of them it looks like JPCT issue. So the question is - is it a JPCT issue? Can you point me to correct direction if the issue is related to JPCT?

Some code related to JPCT init:

...
protected void setupFrameBuffer(Dimension size) {
    Dimension framebufferSize = size == null ? Toolkit.getDefaultToolkit().getScreenSize() : size;

    _buffer = new FrameBuffer(framebufferSize.width, framebufferSize.height, FrameBuffer.SAMPLINGMODE_NORMAL);

    _frameBufferBGColor = DEFAULT_FRAMEBUFFER_BG_COLOR;

    _buffer.disableRenderer(IRenderer.RENDERER_SOFTWARE);
    _buffer.enableRenderer(IRenderer.RENDERER_OPENGL);
    _canvas = _buffer.enableGLCanvasRenderer();
   
    _textureHandler.setFrameBuffer(_buffer);
    _textureHandler.setCanvas(_canvas);
   
    getNotifier().rendererInitialized(_canvas);
  }

  ...
  public void updateFrameBuffer() {
    _performanceStatistics.incrementFPS();
    _performanceStatistics.startMethod();

    _buffer.clear(_frameBufferBGColor);

    world.renderScene(_buffer);
    world.draw(_buffer);
    _textureHandler.blit();

    _buffer.update();

    _videoHandler.encodeFrame(_currentDate);

    _buffer.displayGLOnly();

    _canvas.repaint();
   
    _performanceStatistics.endDrawMethod();
  }

EgonOlsen

jPCT actually doesn't really care to where it outputs the rendering, at least not in a way that it should matter in this case. Are you calling FrameBuffer.resize() when the size of the output window changes?

kavyro

Yep, I perfectly know that. But the issue in my case is so strange...
Now I call buffer resize() when output windows size changes, but it makes no difference - the issue is still there

EgonOlsen

Is there any other log output from jPCT when the resize happens?

kavyro

Nope, JPCT logs nothing when resize. At all.

EgonOlsen

Where are you doing the resize? Directly in the component listener?

kavyro

#6
Yes, it is done in component listener


     addComponentListener(new ComponentAdapter() {

      @Override
      public void componentResized(ComponentEvent e) {
        resizeRenderer(getSize());
      }

    });


I'd like to add some more info which hopefully can help to identify the reason of issue. I was thinking what's special about those elements remaining visible. It turns out we have elements added in batches and have ones added directly. Apparently those not using batches remain visible.

Here is a part of code where the world is created:


public void setupWorld() {
...
HashSet<Element> nonBatched = new HashSet<>();
// add non batched elements here
...

worldObject = Object3D.createDummyObj();

for (Group group : getElementGroups()) {
     
List<Object3D> objects = new ArrayList<Object3D>();

for (Element element : group.getElements()) {
 
  try {
Object3D object = new Object3D(0);
element.setObject3D(object);
if (element.isBatchEnabled() && !nonBatched.contains(element)) {
  objects.add(object);
} else {
  object.setAdditionalColor(RGBColor.white);
  object.compile(true, true, true, true, 8000);
  world.addObject(object);
  group.addObject3D(object);
}
  } catch (Exception e) {
_log.error("Unable to create Object3D for element : " + element, e);
  }
}
Object3D object = null;
if (objects.size() > 0) {
  object = Object3D.mergeAll(objects.toArray(new Object3D[objects.size()]));
  object.setTexture(TextureHandler.ELEMENTS_TEXTURENAME);
  object.setName(group.getName());
  object.setVisibility(group.isVisible());
  object.setAdditionalColor(Color.white);
  object.compileAndStrip();
  world.addObject(object);
  worldObject.addChild(object);
  group.addObject3D(object);
}     
    }
...
}

EgonOlsen

Try to replace the Object3D.compileAndStrip() call with Object3D.compile(). If you strip them, some data needed to upload it again to changed GL context might get deleted. A resize will most likely change the context, so maybe that's the issue.

kavyro

Nope, unfortunately it didn't fix the issue :(. Elements still disappear.

EgonOlsen

Strange. Actually, it might be a better idea to do the resize in the main thread, not in the event thread in which the listener is being called, because it pushes a new command into the pipeline that is actually being executed at that stage. But I doubt that this will fix the issue. It's worth a try though.

EgonOlsen

#10
Another difference is, that you compile the non-batched objects as dynamic, but not the batched ones. Have you tried to use the exact same compile-call for the batched ones as for the non-batched ones?

kavyro

Thank you EgonOlsen for your effort. Your help is really appreciated :)

To exclude differences between batched/not batched elements I created a small new "fresh" project with the code form https://www.jpct.net/wiki/index.php?title=Using_jPCT_in_Swing and Jide. The code was adapted to initialize and run in same way as main project:
   - jpct (rendering) stuff like "game" loop is running in main thread,
   - UI stuff is running in EDT,
   - jpct renderer and UI communicate through listeners when it is needed.

As a result I got same issue - the 3D cube is running OK until the frame is moving around and "disappears" afterwards.
I can send you the project code anytime if you want to have a closer look to it.

kavyro

Jide has listeners for frame's different states... as a possible solution I was thinking about "reseting" the renderer when frame in moving around. So the next question is how to "quickly" (without reloading textures and other time consuming tasks) reset/recreate/reinit the renderer in the correct way? (If that is possible)

EgonOlsen

You can try to call dispose on the renderer and create a new one. I'm not sure how the underlying AWTGL implementation handles this though, but it's worth a try. Feel free to send me your test as well, so that I can see for myself and at least admire the problem... ;)

kavyro

Disposing the buffer and recreate again when frame moved seems to do the trick. The cube is shown again :). I'll apply the hack to main project to see how it works. The link to project I'll send you in a private message ;)