Using GL Callbacks

In Performer, plain OpenGL code may be added to a program using callback functions attached to nodes in the scene graph. These functions will then be called in the drawing process whenever the nodes they are attached to are being drawn. You can define a pre-draw callback, a post-draw callback, or both. Defining both is typically useful when you want to use GL feature which should be applied to all the nodes under the callback node in the scene. Otherwise, for simple GL drawing code, a single callback should be sufficient.

In XP, we can define a new node class which includes a GL drawing callback and assigns it to the XP node's Performer node. A pointer to the Performer node is obtained using the xpNode member function pfnode(). A Performer callback function is assigned using setTravFuncs. So, the basic way to set a pre-draw callback for an XP node is:

	pfnode()->setTravFuncs(PFTRAV_DRAW, glfunc, NULL);

Because it is implemented using a function pointer, the callback must be an ordinary C function or a static class function - it cannot be a class member function. If you need to pass some data to the callback function (such as a pointer to the XP node object), use:

	pfnode()->setTravData(PFTRAV_DRAW, data);

The form for a drawing callback function is:

	int glfunc(pfTraverser *traverser, void *data)
	{
	 /* do GL stuff */
	 return PFTRAV_CONT;
	}

The "traverser" argument is a Performer data structure which contains some Performer-related data, such as the currently applied transformation matrix; it typically is not needed in drawing callbacks - it's more important in app callbacks in normal Perfomer programs. The "data" argument is the data pointer which you passed to setTravData() The function should always return the value PFTRAV_CONT, to let Performer know that everything is proceeding normally.

A shell outline of a GL-callback XP node is here:       glNode.h       glNode.cxx

An example of using both pre- and post-draw callbacks is the clipper node, as created for the Multi-MegaBook. Code for this (updated to XP 0.4) is here:       clipper.h       clipper.cxx

Important Notes

When running on a CAVE or ImmersaDesk, Performer will normally be operating in multi-process mode. This means that the app calculations and the drawing are in separate processes, and any data that you wish to pass from the app to your drawing callback will have to be in shared memory. You can allocate shared memory using pfMalloc() and pfGetSharedArena(). For example:

	data_ = (struct cbData *) pfMalloc(sizeof(struct cbData), pfGetSharedArena());
	pfnode()->setTravData(PFTRAV_DRAW, data_);

Performer culls its scene graph to remove any elements which are not expected to be visible, in order to improve the rendering speed. It does this by checking the bounding volumes of nodes against the current viewing volume. Performer automatically computes the bounding volumes of its own data (pfGeoSets etc.), such as that loaded from model files by xpObject; on the other hand, by default it has no idea about the bounding volume of your GL drawing code. If your callback will be drawing its own primitives (as opposed to applying some GL feature to standard Performer objects below it in the scene graph), you will need to assign an appropriate bounding sphere to your node, or Performer will always cull it and it will never be drawn. A bounding sphere can be set as follows (this example defines a bounding sphere 100 units in diameter, centered at the local origin):

	pfSphere boundingSphere;
	boundingSphere.center.set(0,0,0);
	boundingSphere.radius = 100.0;
	pfnode()->setBound(&boundingSphere, PFBOUND_STATIC);


Last modified 28 February 2000.
Dave Pape, pape@evl.uic.edu