Multiple viewports MouseEventControl problem in Lemur

Hi, I’m trying to have an extra viewport inside a lemur panel.

I have some panels in the main view (guiNode) and some other panels in the post view (which is inside a lemur panel and it is working fine). Something like this:

The panel on the main view receives correctly the MouseEventControl, but the panel inside the post view doesn’t.

I try to use:

stateManager.getState(BasePickState.class).addCollisionRoot(postViewPortRootNode, postViewPort);

But it doesn’t work so I was wondering if it is possible to have the lemur events working inside that custom viewport too.

What version of Lemur are you running? How is your viewport setup?

I’m using Lemur version 1.8.1

viewport = renderManager.createPostView("viewportPanel", cam);
viewport.setClearFlags(false, true, true);

viewPortNode = new Node("Root Node ViewPort Panel");
viewport.attachScene(viewPortNode);

And, in the class who has the viewport:

addControl(new AbstractControl() {
    @Override
    protected void controlUpdate(float tpf) {
        viewPortNode.updateLogicalState(tpf);
    }

    @Override
    protected void controlRender(RenderManager rm, ViewPort vp) {
        viewPortNode.updateGeometricState();
    }
});

I add the Panels inside the viewport to the viewPortNode.

And the new viewport uses the same camera or?

I’ve done some testing on my own with nested viewports and fixed a bunch of things but that was a long time ago… pretty sure that’s already in the release but maybe something got lost.

No, it’s a cloned camera.

I use too:

cam.setViewPort(left, right, bottom, top);
cam.setFrustumPerspective(40, size, 0.05f, 500f);

cam.setParallelProjection(true);
cam.lookAtDirection(Vector3f.UNIT_Z.negate(), Vector3f.UNIT_Y);

Hmmm… you shouldn’t have to do that with the camera. You can probably just get away with cloning the camera from the normal gui viewport.

Also, make sure your root node for the viewport is in the gui bucket. (And in that case, it hardly matters what the camera settings are other than viewport I think)

Yes, maybe, but should it make a huge difference? (I’m creating a “viewport panel” that has a 3D camera and extending it to have a 2D “viewport panel” just changing some camera parameters and making some math tricks to have it working).

Every time I do that with my customized camera I stop seeing anything. So, I just tried cloning the guiViewPort camera and then it goes fine with the gui bucket (however, I still have to change the math tricks :stuck_out_tongue:, my viewport, the “viewport panel” can have different sizes).

However, and coming back to the problem, it persists, I can’t make the events work in that viewport.

PD: Do you know what I’m missing that would make the first approach (customizing the camera) work?

I don’t know. But making code the generically handles ray casting in any viewport no matter how different its camera is defined is kind of hard. So I suspect that I’m doing something wrong in that code.

If you could put together a simple test case then I can try it locally. Else if you want to trace through the code then maybe you spot something.

Also, I’m not clear… are you trying to draw GUI elements or 3D elements.

What is it about a normal camera setup and viewport setup that doesn’t work with your GUI elements? I mean, I should support it but I want to understand which you are doing.

In JME, anything in the GUI bucket is always forced to x,y pixel orientation with 0,0 at the lower left. In the gui buclet the camera is actually irrelevant.

Sorry for the no response.

Let me explain: I need a list wich I can move with the scroll wheel. The list will clip the extra parts of the objects that are out of the panel and I will be able to click the items that contain the list. So… I need a viewport.
I need to reacomodate the size and position of that viewport acording to a layout too.

So I’m trying to create a custom Panel with a ViewPort inside, adapting the viewport to the size and position of the panel.

I tried to do a test case:

  • Use a clone of the GuiViewport Camera.
  • Use the RenderManager of the SimpleApp.
  • Use the AppStateManager of the SimpleApp to get the BasePickState and add a new CollisionRoot.
  • Create a viewPortNode in the Gui Bucket.
public class CustomViewPort extends Panel {
    ViewPort viewport;
    
    Node viewPortNode;
    Container container;
    
    Camera cam;
    RenderManager renderManager;
    AppStateManager stateManager;
    
    public CustomViewPort(RenderManager rm, Camera cam, AppStateManager stateManager) {
        viewPortNode = new Node("Root Node ViewPort Panel");
        
        this.cam = cam.clone();
        this.renderManager = rm;
        this.stateManager = stateManager;
        
        container = new Container();
        container.setPreferredSize(new Vector3f(100, 100, 1));
        container.setLocalTranslation(100, Display.getHeight() - 100, 0);
        
        viewPortNode.attachChild(container);
        viewPortNode.setQueueBucket(RenderQueue.Bucket.Gui);
        
        float left = 0.1f;
        float right = 0.5f;
        float bottom = 0.2f;
        float top = 0.9f;
        
        this.cam.setViewPort(left, right, bottom, top);
        
        container.setLocalScale(1/(right - left), 1/(top - bottom), 1);
        
        addControl(new AbstractControl() {
            @Override
            protected void controlUpdate(float tpf) {
                viewPortNode.updateLogicalState(tpf);
            }

            @Override
            protected void controlRender(RenderManager rm, ViewPort vp) {
                viewPortNode.updateGeometricState();
            }
        });
        
        MouseEventControl.addListenersToSpatial(container, new BasicMouseListener() {
            @Override
            public void mouseEntered(MouseMotionEvent event, Spatial target, Spatial capture) {
                System.out.println("Mouse entered on CONTAINER");
                
            }
            
            @Override
            public void mouseExited(MouseMotionEvent event, Spatial target, Spatial capture) {
                System.out.println("Mouse exited of CONTAINER");
            }
        });
    }
    
    public void open() {
        viewport = renderManager.createPostView("viewportPanel", cam);
        
        viewport.setClearFlags(true, true, true);
        viewport.attachScene(viewPortNode);
        viewport.setBackgroundColor(ColorRGBA.Red);
        
        stateManager.getState(BasePickState.class).addCollisionRoot(container, viewport);
    }
    
    public void close() {
        renderManager.removePostView(viewport);
        stateManager.getState(BasePickState.class).removeCollisionRoot(viewport);
    }
}

Just for trying I create a class extending Panel. I give the cam viewport size a random value to test and a square size to the container.
I need to show and hide the panel so I create the functions open and close, creating and removing the viewport.

I’m adding this Panel to my UserInterface.

I scale the container to show it square shape but the collision shape doesn’t adjust to it.

I wonder if you are getting hit by an event ordering problem… though it should fall through to the other layers anyway. (In the latest version, there is the ability to more strictly control which layers get picks in which order… it was a little hit or miss before and your added viewport is likely processed after the regular guiNode which is backwards in this case.)

I’d really like to resolve this issue because I will need stuff like this, too. I have done separate viewports before, though and didn’t have any issues.

There are three options for figuring this out:

  1. I create my own stand-alone test case and see what’s happening. (Won’t happen for at least two weeks because I’m trying to clean my house for a party on Saturday and then will be making up day-job work.)
  2. You create a stand-alone test case for me and maybe I spot what’s happening before then or can run it early next week.
  3. You do a little debugging for me by stepping through the PickEventSession code when your viewport should be getting events. Maybe you spot some strange things that I can comment on.

The ideal test case should be as small as possible to eliminate any other contributing factors. Like, a single class where all listeners are added in that class, viewports created, etc…

Your best/easiest option might be (3) for now. After all, there is the chance that you spot the bug instantly in that case.

I apologize that I can’t look into this more directly at the moment but life has me swamped.

I’m trying something, there is a way to indicate where you see the viewport except of the cam.setViewport?

Maybe with cam.setLocation or cam.setFrame? If it is possible, I can just resize the cam and locate where I want.

As I saw, when I use the function cam.setViewport, the viewport itself is changing it size and position (wherever I see the viewport it always has a full pixels environment, starting from 0,0 and ending at screenWidth * screenHeight). But if I could change the cam position of the viewport (letting the viewport be as big as the screen) to be where I want in the screen instead of the left down I could trick the panels to have their spatials and their events synced.

Yes, after some tries (I made so many failed workarounds) , I change the layer used, now I use the PICK_LAYER_GUI and it works:

// stateManager.getState(BasePickState.class).addCollisionRoot(container, viewport);
stateManager.getState(BasePickState.class).addCollisionRoot(viewPortNode, viewport, PickState.PICK_LAYER_GUI);

Sorry for the delay of the answer, I’m slowly learning how to use Lemur :sweat_smile: