The effects of a callback node may not be cacheable, depending on what it does. For example, if the callback node contains shapes whose geometry is changing, it should not be cached. In Using a Callback Node , the callback node creates a checked background, which can be cached because it is not changing.
If a callback node relies on any information outside of Inventor that may change (such as a global variable), it should not be cached. To prevent Inventor from automatically creating a cache, use the SoCacheElement::- invalidate() method from within a callback. For example:
#include <GL/gl.h>
#include <Inventor/SbLinear.h>
#include <Inventor/Xt/SoXt.h>
#include <Inventor/Xt/SoXtRenderArea.h>
#include <Inventor/nodes/SoCallback.h>
#include <Inventor/nodes/SoCube.h>
#include <Inventor/nodes/SoDirectionalLight.h>
#include <Inventor/nodes/SoLightModel.h>
#include <Inventor/nodes/SoMaterial.h>
#include <Inventor/nodes/SoPerspectiveCamera.h>
#include <Inventor/nodes/SoSeparator.h>
#include <Inventor/nodes/SoSphere.h>
#include <Inventor/nodes/SoTransform.h>
float floorObj[81][3];
// Build a scene with two objects and some light
void
buildScene( SoGroup* root )
{
// Some light
root->addChild( new SoLightModel );
root->addChild( new SoDirectionalLight );
// A red cube translated to the left and down
SoTransform* myTrans = new SoTransform;
myTrans->translation.setValue( -2.0, -2.0, 0.0 );
root->addChild( myTrans );
SoMaterial* myMtl = new SoMaterial;
myMtl->diffuseColor.setValue( 1.0, 0.0, 0.0 );
root->addChild( myMtl );
root->addChild( new SoCube );
// A blue sphere translated right
myTrans = new SoTransform;
myTrans->translation.setValue( 4.0, 0.0, 0.0 );
root->addChild( myTrans );
myMtl = new SoMaterial;
myMtl->diffuseColor.setValue( 0.0, 0.0, 1.0 );
root->addChild( myMtl );
root->addChild( new SoSphere );
}
// Build the floor that will be rendered using OpenGL.
void
buildFloor()
{
int a = 0;
for ( float i = -5.0; i <= 5.0; i += 1.25 )
{
for ( float j = -5.0; j <= 5.0; j += 1.25, a++ )
{
floorObj[a][0] = j;
floorObj[a][1] = 0.0;
floorObj[a][2] = i;
}
}
}
// Draw the lines that make up the floor, using OpenGL
void
drawFloor()
{
int i;
glBegin( GL_LINES );
for ( i = 0; i < 4; i++ )
{
glVertex3fv( floorObj[i * 18] );
glVertex3fv( floorObj[( i * 18 ) + 8] );
glVertex3fv( floorObj[( i * 18 ) + 17] );
glVertex3fv( floorObj[( i * 18 ) + 9] );
}
glVertex3fv( floorObj[i * 18] );
glVertex3fv( floorObj[( i * 18 ) + 8] );
glEnd();
glBegin( GL_LINES );
for ( i = 0; i < 4; i++ )
{
glVertex3fv( floorObj[i * 2] );
glVertex3fv( floorObj[( i * 2 ) + 72] );
glVertex3fv( floorObj[( i * 2 ) + 73] );
glVertex3fv( floorObj[( i * 2 ) + 1] );
}
glVertex3fv( floorObj[i * 2] );
glVertex3fv( floorObj[( i * 2 ) + 72] );
glEnd();
}
// Callback routine to render the floor using OpenGL
void
myCallbackRoutine( void*, SoAction* )
{
glPushMatrix();
glTranslatef( 0.0, -3.0, 0.0 );
glColor3f( 0.0, 0.7, 0.0 );
glLineWidth( 2 );
glDisable( GL_LIGHTING ); // so we don't have to set normals
drawFloor();
glEnable( GL_LIGHTING );
glLineWidth( 1 );
glPopMatrix();
}
main( int, char** )
{
// Initialize Inventor utilities
Widget myWindow = SoXt::init( "Example 17.1" );
buildFloor();
// Build a simple scene graph, including a camera and
// a SoCallback node for performing some GL rendering.
SoSeparator* root = new SoSeparator;
root->ref();
SoPerspectiveCamera* myCamera = new SoPerspectiveCamera;
myCamera->position.setValue( 0.0, 0.0, 5.0 );
myCamera->heightAngle = M_PI / 2.0; // 90 degrees
myCamera->nearDistance = 2.0;
myCamera->farDistance = 12.0;
root->addChild( myCamera );
SoCallback* myCallback = new SoCallback;
myCallback->setCallback( myCallbackRoutine );
root->addChild( myCallback );
buildScene( root );
// Initialize an Inventor Xt RenderArea and draw the scene.
SoXtRenderArea* myRenderArea = new SoXtRenderArea( myWindow );
myRenderArea->setSceneGraph( root );
myRenderArea->setTitle( "OpenGL Callback" );
myRenderArea->setBackgroundColor( SbColor( .8, .8, .8 ) );
myRenderArea->show();
SoXt::show( myWindow );
SoXt::mainLoop();
}