A ZUI for Panda3D

Download the code from my github account: github.com/seanh/PandaZUI/

So this is what I’ve been working on for the past while. A ZUI (Zoomable User Interface) is “a graphical environment where users can change the scale of the viewed area in to see more detail or less.” So there you go. The idea is that your “desktop” is an infinite and infinitely scalable plane, onto which you place all the objects that the user interacts with. Users can pan the camera around and zoom it in and out, move the objects around, and generally do whatever you can imagine and then implement. I think the main reference for the idea has to be the “Zoom World” in Jef Raskin’s book The Humane Interface, but it was never implemented. With all these new devices with small screens the I think concept is having a bit of a revival. A few links on the subject:

en.wikipedia.org/wiki/Zooming_user_interface
advogato.org/article/788.html
rchi.raskincenter.org/index.php? … cification

Some other implementations of this sort of thing include Piccolo, Clutter and Project Scene Graph.

cs.umd.edu/hcil/jazz/
clutter-project.org/
scenegraph.dev.java.net/

What does this code actually do? Let’s see, we’ve got:

  • A ZCanvas, an infinite and infinitely scalable plane with a viewport that can pan around and zoom in and out. It’s implemented by transforming a node on Panda’s 2D scene graph. Thanks to ynjh_jo for the code for the zoom transformation.

  • Nodes that you can automatically zoom the camera to, e.g. by clicking on them

  • Nodes can change state depending on what the camera is focused on

  • Nodes that respond to mouse-over highlights

  • Nodes that can be dragged and dropped onto other nodes

  • Container nodes that implement layouts. Provided are horizontal and vertical line layouts and a grid layout, but the general Box and BoxList framework provided supports easily creating arbitrary layouts. Compound layouts (layouts within layouts) are also supported.

  • DirectGUI compatibility, i.e. you can embed DirectGUI widgets into the zoom scene, and put them into layout containers.

It’s all fairly generic, I think, so you could use it to implement lots of different interfaces. I’m using it to implement a little story writing prototype called ‘Story Cards’ which is also included in the download.

I wouldn’t say it is finished and perfect in every way, but you have to draw the line somewhere. Suggestions and bug reports welcome. One of the main problems. if anyone wants to help, is that the Story Cards application is pretty slow. I ran pstats on it, and it seems to be all to do with the collision ray used to detect mouse overs. Maybe it can be made more efficient somehow. I reckon it might be a lot faster if the collision ray were removed completely, and it was re-written to use MouseWatcher instead, but that would take a little work.

That sounds pretty interesting, chombee, and potentially pretty useful, I think. :slight_smile:

As to your picking ray issue, are you performing any broad checks before the ray collision test is run? It might help to keep the various items in some form of scene graph so that large sections can be culled, and then to first perform point-in-rectangle tests to determine which items to check and only then run your ray test on that final sub-set.

Update: added download. :oops:

Collision is indeed the problem. Panda already implements bounds-based proximity check steps for you down in C++. But it only works under render, not render2d. It’s definitely a bug since v1.4. If you move exactly the same scene to render, you’d notice the difference. From my last test, I got 30 fps to 220+ fps. It seems there is infinite bounds somewhere.
[EDIT] :
I was wrong, it’s not render2d, but aspect2d. So, the bug is somewhere between CollisionTraverser and PGTop.

Oh, hmm, it’s probably this:

>>> aspect2d.node().getBounds()
bsphere, infinite
>>> aspect2d.node().isFinal()
1

We put an infinite bounding volume on aspect2d, and set it “final”, to intentionally turn off culling. The idea was that no one parents things to aspect2d that aren’t going to be within the screen coordinates anyway, and this way we save a few milliseconds on the time it takes to test every node’s bounding volume while traversing aspect2d.

This is, of course, not true in the case that you want to perform collision tests on nodes under aspect2d. So you could work around this by undoing our simple optimization:

aspect2d.node().setFinal(False)
aspect2d.node().clearBounds()

David

Yes, that did it.

That’s tripled, quadrupled or more the framerate on my laptop depending on where the camera is, and certainly I would never have discovered it myself. Thanks! I’ve updated the download with this fix. I could probably make it even faster by turning off the collision masks on objects whenever they are not needed, right now I just leave them all on all the time. It’s more than fast enough already now though.

Update: I stopped working on PandaZUI as I’ve moved over to Piccolo as a graphics engine instead. I’ve hosted the latest PandaZUI code on my github account: github.com/seanh/PandaZUI/