Hi all,
I’ve been working on integrating CEGUI (http://www.cegui.org.uk) into Panda3d.
Here is a what I have right now:
Full version
http://imgur.com/GIE7.png
How is this better than DirectGUI?
- It knows about pixels AND does relative element positioning;
- It uses XML for layouts;
- It doesn’t use 3D coordinates to position 2D GUI elements!
- It uses the coordinate system where (0, 0) is the top left corner of the screen, just like the rest of the world does .
- It is skinnable, check out http://www.cegui.org.uk/skins/
- It is not visually painful
There is a Python integration module called CEGUIPython, but I didn’t get to that yet.
Limitations: nothing major so far. Currently, OpenGL only, but why would you use anything else ?
Here are some implementation details, on which I’d like to have some feedback and suggestions.
To render Cegui in OpenGL, we need to call CEGUI::System::renderGUI() every frame. The trick here is that this must be called in the render thread between begin_frame and end_frame (that’s what my experience shows). The only way I could find to do that is to create a new cull bin, CullBinCegui, which has this code:
void CullBinCegui::
draw(bool force, Thread *current_thread) {
CEGUI::System::getSingleton().renderGUI();
}
So, to use Cegui, we must put some visible geometry into this new bin. This geometry must be visible, so that it would not be culled away, and draw would eventually be called. I used CardMaker to generate a white card, parented that under render2d, and set the bin to my new bin, “cegui”.
The question is, is there an easier way to do this? I tried to subclass a Geom, so that when it’s being drawn, it would render Cegui, but Geom.draw is not virtual (for performance reasons, I guess). The only virtual method I could find in the render code is CullBin.draw.
If this is the way to do it, then the quesiton is: how to integrate this gracefully into the Panda3d system? Right now, I have to modify these files:
panda3d_src/panda/src/cull/config_cull.cxx | 6 +
panda3d_src/panda/src/cull/cullBinCegui.cxx | 72 +
panda3d_src/panda/src/cull/cullBinCegui.h | 72 +
panda3d_src/panda/src/cull/cull_composite1.cxx | 1 +
panda3d_src/panda/src/pgraph/cullBinEnums.h | 1 +
panda3d_src/panda/src/pgraph/cullBinManager.cxx | 12 +
This seems excessive to me.
One way to make it easier would be to eliminate the CullBinEnums. Essentially, there is a mapping [CullBin name (string)] --> CullBin, and there is no need for these enums. Then, if I want to add a CullBin, I just say CullBinManager.add_bin(string name, CullBin bin) - no need for the enums.
Another issue is passing input events to Cegui (mouse and keyboard). Cegui requires to inject input events into it. For that, I’m using CeguiInputHandler, a subclass of DataNode, to listen to input data from MouseAndKeyboard, convert it and pass it to Cegui. The plan is to insert CeguiInputHandler below MouseAndKeyboard, and reparent all the children of MouseAndKeyboard to CeguiInputHandler, so they would only get those events that did not get consumed by Cegui. However, this may cause some problems.
Right now, I’m writing this in C++, so I’m testing it with PandaFramework, but I’m looking for a way to make it work the same way with ShowBase. Both ShowBase and PandaFramework define a MouseAndKeyboard node, so it should work the same way.
So this is the story so far. Any help, feedback and comments appreciated.
Thanks,
Nik