The SoCallbackAction SoCallbackAction SoCallbackAction allows you to traverse the scene graph and accumulate state. It includes methods for calling back to application functions whenever nodes of a specified type are encountered during the traversal. At every node, the callback function has access to the entire Inventor traversal state. It can thus query any element in the state, such as the current coordinates, current normals, or current material binding. See the Open Inventor C++ Reference Manual on SoCallbackAction SoCallbackAction SoCallbackAction for a description of all state query functions.
The callback action also allows you to register callback functions that are called whenever certain shape nodes are traversed. The primitives used to draw the shape are passed to the callback function for use by the application.
This action provides a convenient mechanism for adding your own action to Inventor without subclassing (see The Inventor Toolmaker for information on creating a new action). It is particularly useful for C programmers who want to add functionality to scene graph traversal.
An example of creating an instance of SoCallbackAction SoCallbackAction SoCallbackAction is as follows:
SoCallbackAction cbAction;
SoCallbackAction cbAction = new SoCallbackAction();
SoCallbackAction cbAction = new SoCallbackAction();
Inventor provides a number of methods for setting callback functions for a node. Each method takes a node type, a pointer to the user callback function, and a pointer to user data. The function is called whenever a node of the specified type or a subclass of that type, is encountered during traversal of the scene graph.
The following functions are set for any type of node:
adds a callback function that is called just before a node of a particular type is traversed | |
adds a callback function that is called just after a node of a particular type is traversed | |
adds a callback function that is called just before the last node in the path is traversed | |
adds a callback function that is called just after the last node in the path is traversed |
In the case of a separator node, the addPreCallback() method is called before the children are traversed, and the addPostCallback() method is called after the children are traversed but before the state is restored. The addPreTailCallback() and addPostTailCallback() methods are used only when you apply the callback action to a path.
A general-purpose callback function must return one of three values:
The following callback functions are set for a particular type of shape node. When these callback functions are set and the shape is traversed, primitives for the shape are generated, the callback function is invoked, and the primitives are passed to the callback function. You might use addTriangleCallback(), for example, if you are writing your own renderer and you want to tessellate all filled objects into triangles.
adds a callback function to a node that generates triangles, such as SoFaceSet SoFaceSet SoFaceSet or SoNurbsSurface SoNurbsSurface SoNurbsSurface | |
adds a callback function to a node that generates line segments, such as SoLineSet SoLineSet SoLineSet or SoIndexedLineSet SoIndexedLineSet SoIndexedLineSet (but not to SoFaceSet SoFaceSet SoFaceSet or related classes even when the draw-style is LINES) | |
adds a callback function to a node that generates points, such as SoPointSet SoPointSet SoPointSet (but not to SoFaceSet SoFaceSet SoFaceSet or SoLineSet SoLineSet SoLineSet even when the draw-style is POINTS) |
For triangles, the associated callback is of the following form:
void SoTriangleCB(void *userData, SoCallbackAction *action, const SoPrimitiveVertex *v1, const SoPrimitiveVertex *v2, const SoPrimitiveVertex *v3);
Here, the callback function is called once for each triangle the shape generates. An example of using this callback function would be if you are writing a ray tracer and want to deal with only one type of data structure for all polygonal shapes. A triangle callback function can be registered on spheres, cones, cylinders, and NURBS surfaces, as well as on face sets and quad meshes.
An SoPrimitiveVertex SoPrimitiveVertex is a vertex of a primitive shape (triangle, line segment, or point) that is generated by a callback action. It contains an object-space point, normal, texture coordinate, material index, and a pointer to an instance of an SoDetail SoDetail SoDetail subclass. The detail may contain additional information about the vertex.
Tip: Your callback function can use the value of the draw-style element from the state if you want to determine if the triangles would be rendered as points or lines. For example: |
if(SoDrawStyleElement::get(action->getState())== SoDrawStyleElement::LINES)
if(SoDrawStyleElement.Get(action.GetState())== SoDrawStyleElement.Styles.LINES)
if(SoDrawStyleElement.get(action.getState())== SoDrawStyleElement.Styles.LINES)
...//do something See The Inventor Toolmaker for more information on elements.
SoCallbackAction SoCallbackAction SoCallbackAction can be applied to a node, a path, or a path list.
Example 8.3, “ Using a Triangle Callback Function ” shows using the callback action to decompose a sphere into a set of triangle primitives.
Example 8.3. Using a Triangle Callback Function
... SoSphere *mySphere = new SoSphere; mySphere->ref(); printSpheres(mySphere); ... void printSpheres(SoNode *root) { SoCallbackAction myAction; myAction.addPreCallback(SoSphere::getClassTypeId(), printHeaderCallback, NULL); myAction.addTriangleCallback(SoSphere::getClassTypeId(), printTriangleCallback, NULL); myAction.apply(root); } SoCallbackAction::Response printHeaderCallback(void *, SoCallbackAction *, const SoNode *node) { printf("\n Sphere "); // Print the node name (if it exists) and address if (! !node->getName()) printf("named \"%s\" ", node->getName()); printf("at address %#x\n", node); return SoCallbackAction::CONTINUE; } void printTriangleCallback(void *, SoCallbackAction *, const SoPrimitiveVertex *vertex1, const SoPrimitiveVertex *vertex2, const SoPrimitiveVertex *vertex3) { printf("Triangle:\n"); printVertex(vertex1); printVertex(vertex2); printVertex(vertex3); } void printVertex(const SoPrimitiveVertex *vertex) { const SbVec3f &point = vertex->getPoint(); printf("\tCoords = (%g, %g, %g)\n", point[0], point[1], point[2]); const SbVec3f &normal = vertex->getNormal(); printf("\tNormal = (%g, %g, %g)\n", normal[0], normal[1], normal[2]); }
... void printSpheres(SoNode root) { SoCallbackAction myAction = new SoCallbackAction(); Console.WriteLine(typeof(SoSphere)); myAction.AddPreCallback(typeof(SoNode), new SoCallbackAction.CallbackActionCB(printHeaderCallback)); myAction.AddTriangleCallback(typeof(SoNode), new SoCallbackAction.TriangleCB(printTriangleCallback)); myAction.Apply(root); } SoCallbackAction.Responses printHeaderCallback(SoCallbackAction action, SoNode node) { if (node.GetName() != "") Console.WriteLine("Sphere named " + node.GetName()); return SoCallbackAction.Responses.CONTINUE; } void printTriangleCallback(SoCallbackAction action, ref SoPrimitiveVertex vertex1, ref SoPrimitiveVertex vertex2, ref SoPrimitiveVertex vertex3) { Console.WriteLine("Triangle:"); printVertex(vertex1); printVertex(vertex2); printVertex(vertex3); } void printVertex(SoPrimitiveVertex vertex) { float x, y, z; vertex.Point.GetValue(out x, out y, out z); SbVec3f point = new SbVec3f(x, y, z); Console.WriteLine("\t Coords = ({0}, {1}, {2})\n", point[0], point[1], point[2]); vertex.Normal.GetValue(out x, out y, out z); SbVec3f normal = new SbVec3f(x, y, z); Console.WriteLine("\tNormal = ({0}, {1}, {2})\n", normal[0], normal[1], normal[2]); }
private void printSpheres(SoNode root)
{
SoCallbackAction myAction = new SoCallbackAction();
myAction.addPreCallback(SoSphere.class, new PrintHeaderCallback(), null);
myAction.addTriangleCallback(SoSphere.class, new PrintTriangleCallback(), null);
myAction.apply(root);
}
class PrintHeaderCallback extends SoCallbackActionCB
{
public int invoke(SoCallbackAction s, SoNode node)
{
String str = "Sphere ";
// Print the node name (if it exists) and address
if ( node.getName().length() != 0 )
str += "named " + node.getName() + " ";
m_txtArea.append(str + "\n");
//
return SoCallbackAction.Responses.CONTINUE.getValue();
}
}
class PrintTriangleCallback extends SoTriangleCB
{
public void invoke(SoCallbackAction s, SoPrimitiveVertex v1,
SoPrimitiveVertex v2, SoPrimitiveVertex v3)
{
m_txtArea.append("Triangle:\n");
printVertex(v1);
printVertex(v2);
printVertex(v3);
}
private void printVertex(SoPrimitiveVertex vertex)
{
SbVec3f point = vertex.getPoint();
m_txtArea.append("\tCoords = (" + point.getX() + ", " + point.getY() +
", " + point.getZ() + ")\n");
SbVec3f normal = vertex.getNormal();
m_txtArea.append("\tNormal = (" + normal.getX() + ", " + normal.getY() +
", " + normal.getZ() + ")\n");
}
}