Trouble with mouse setGeometry()

I’m building a level editor with a zooming interface and I want the mouse cursor to represent the type of object that is currently being placed. To do this I’ve created a collection of NodePaths and show() and hide() them according to the active element. For the active element, we

base.mouseWatcherNode.setGeometry(activeNP.node())

Now is when it gets a bit complicated. I’ve replaced the lens on base.camera with an orthographic one (some of the system’s architecture requires that I use render rather than render2d). It’s a 16:9 aspect display and the zooming is handled by setting the filmSize of base.camera’s lens.

The trouble is that the geometry representing the cursor does not match where the mouse cursor would be. The model appears to move about 1/16 as much as the mouse in the X direction and about 1/9 as much as the mouse in the Y direction. This, of course, means that there’s a lot of the screen that I can’t point to.

Also, I’ve scaled some of the models, and those scales are not reflected in the geometry ‘attached to the cursor’.

All of this makes me think that the cursor position is computed against a node in the scene graph that’s not the one I’m expecting. How can I correct this? Is it reasonable to move the mouseWatcherNode around in the graph?

Make sure your activeNP is parented to render2d, not aspect2d.

David

Like I said, the architecture sort of requires that all these NodePaths be parented to render, not anything 2d.

Is there some coupling between MouseWatcher and render2d?

So I attached the objects to render2d as a test, and it did fix the mouse tracking problem, but had no effect on the scale problems I’ve been having: the scale seems to be absolute, regardless of calls to setScale().

The scale is probably getting overwritten by the mouse positioning code, along with the rest of the transform. Instead of setting the scale on the same node that you pass to setGeometry(), set the scale on a lower node. For instance:

dummyNP = render2d.attachNewNode('dummy')
activeNP.reparentTo(dummyNP)
activeNP.setScale(0.5)
base.mouseWatcherNode.setGeometry(dummyNP.node())

David

That’s a great tip. Thanks. I abandoned setGeometry() in favor of:

if base.mouseWatcherNode.hasMouse():
    x = base.mouseWatcherNode.getMouseX() * self.filmSize[0]/2.
    y = base.mouseWatcherNode.getMouseY() * self.filmSize[1]/2.
    self.activeCursor.setPos(x,self.activeCursor.getY(),y)

in a task, where filmSize is a local copy of the lens’s film size.

Is there a significant difference between these two approaches, or is the mouseWatcherNode.setGeometry() a convenience?

setGeometry() is a convenience. It’s a tiny bit faster than your Python code, since it’s implemented in C++, but this probably won’t make a practical difference; and the convenience of having it do exactly what you want may outweigh the convenience of having it already written for you. :slight_smile:

Note that in either case, your mouse pointer will be bound to the render frame rate, which is fine if your frame rate is high, but kind of crummy if it is low. It may be better to set the hardware mouse cursor instead. Panda provides a limited interface to do this, via the WindowProperties structure, though it’s not a great interface.

David