Open Inventor Release 2024.2.0
 
Loading...
Searching...
No Matches
Using an SoCallback Node

A typical use of an SoCallback node is to make calls to OpenGL. At the beginning of the callback function, you need to check the action type and then proceed based on the type of action that has been applied to the node. Typically, you are interested in the render action:

C++ :

if ( action->isOfType( SoGLRenderAction::getClassTypeId() ) )
{
... execute rendering code..
}

C# :

if ( action is SoGLRenderAction )
{
... execute rendering code..
}

Java :

if ( action instanceof SoGLRenderAction )
{
... execute rendering code..
}

Caching

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:

C++ :

void
myCallback( void* myData, SoAction* action )
{
if ( action->isOfType( SoGLRenderAction::getClassTypeId() ) )
{
SoCacheElement::invalidate( action->getState() );
// makes sure this isn't cached
//...make OpenGL calls that depend on a global variable...//
}
}

C# :

void
MyCallback( SoAction action )
{
if ( action is SoGLRenderAction )
{
SoCacheElement.Invalidate( action.GetState() );
// makes sure this isn't cached
//...make OpenGL calls that depend on a global variable...//
}
}

Java :

callback.setCallback(new SoCallback.CB()
{
public void invoke( SoAction action )
{
if ( action instanceof SoGLRenderAction )
{
SoCacheElement.invalidate( action.getState() );
// makes sure this isn't cached
//...make OpenGL calls that depend on a global variable...//
}
}
}

Be careful when opening an OpenGL display list inside an SoCallback node. Recall from Applying Actions that the Inventor render cache contains an OpenGL display list. Only one OpenGL display list can be open at a time, and a separator node above the callback node may have already opened a display list for caching. If your callback node opens a second display list, an error occurs. Use the SoCacheElement::anyOpen() method to check whether a cache is open.

Using a Callback Node

Using a Callback Node creates an Inventor render area. It uses Inventor to create a red cube and a blue sphere and then uses an SoCallback node containing GL calls to draw a checked “floor.” The floor is cached automatically by Inventor. Note that the SoXtRenderArea automatically redraws the scene when the window is resized. Using a GLX Window , which uses a GLX window, does not redraw automatically.

Both Examples 17-2 and 17-3 produce the same image, shown in Combining Use of Inventor and OpenGL .

Combining Use of Inventor and OpenGL

Example : Using a Callback Node

C++ :

#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();
}

C# :

Java :