The example below shows the class declaration found in the include file OverlayHighlightRenderAction.h.
The example below shows the class definition, found in the source file.
#include <Inventor/SbBox.h>
#include <Inventor/SoNodeKitPath.h>
#include <Inventor/SoPath.h>
#include <Inventor/actions/SoGetBoundingBoxAction.h>
#include <Inventor/actions/SoSearchAction.h>
#include <Inventor/nodekits/SoBaseKit.h>
#include <Inventor/nodes/SoColorIndex.h>
#include <Inventor/nodes/SoCoordinate3.h>
#include <Inventor/nodes/SoDrawStyle.h>
#include <Inventor/nodes/SoFaceSet.h>
#include <Inventor/nodes/SoLightModel.h>
#include <Inventor/nodes/SoOrthographicCamera.h>
#include <Inventor/nodes/SoPickStyle.h>
#include <Inventor/nodes/SoSelection.h>
#include <Inventor/nodes/SoSeparator.h>
#include <limits.h>
#include <math.h>
#include "OverlayHighlightRenderAction.h"
SO_ACTION_SOURCE( OverlayHighlightRenderAction );
// Initializes the OverlayHighlightRenderAction class.
void
OverlayHighlightRenderAction::initClass()
{
SO_ACTION_INIT_CLASS( OverlayHighlightRenderAction, SoGLRenderAction );
}
void
OverlayHighlightRenderAction::exitClass()
{
SO_ACTION_EXIT_CLASS( OverlayHighlightRenderAction );
}
// Constructor
OverlayHighlightRenderAction::OverlayHighlightRenderAction()
: SoGLRenderAction( SbVec2s( 1, 1 ) ) // pass a dummy
// viewport region
{
SO_ACTION_CONSTRUCTOR( OverlayHighlightRenderAction );
selPath = NULL;
// Set up the local rendering graph
localRoot = new SoSeparator;
localRoot->ref();
SoPickStyle* pickStyle = new SoPickStyle;
pickStyle->style = SoPickStyle::UNPICKABLE;
localRoot->addChild( pickStyle );
// Set up camera to look at 0 <= x,y <= 1
orthoCam = new SoOrthographicCamera;
orthoCam->position.setValue( .5, .5, 1. );
orthoCam->height = 1.0;
localRoot->addChild( orthoCam );
SoLightModel* lmodel = new SoLightModel;
lmodel->model = SoLightModel::BASE_COLOR;
localRoot->addChild( lmodel );
SoColorIndex* color = new SoColorIndex;
color->index = 1;
localRoot->addChild( color );
SoDrawStyle* drawStyle = new SoDrawStyle;
drawStyle->style = SoDrawStyle::LINES;
drawStyle->lineWidth = 3;
drawStyle->linePattern = 0xffff;
localRoot->addChild( drawStyle );
coords = new SoCoordinate3;
coords->point.setNum( 0 );
localRoot->addChild( coords );
SoFaceSet* fset = new SoFaceSet;
fset->numVertices = 4;
localRoot->addChild( fset );
}
// Destructor
OverlayHighlightRenderAction::~OverlayHighlightRenderAction()
{
localRoot->unref();
if ( selPath != NULL )
selPath->unref();
}
// Update the bbox to surround the projected bounding box of
// the path.
// Use: protected
void
OverlayHighlightRenderAction::updateBbox( SoPath* p, SoCamera* camera )
{
coords->point.deleteValues( 0 ); // clear them all out
if ( camera == NULL )
return;
// Compute the 3d bounding box of the passed path
SoGetBoundingBoxAction bba( getViewportRegion() );
bba.apply( p );
SbVec3f min, max;
bba.getBoundingBox().getBounds( min, max );
// Project points to (0 <= x,y,z <= 1) screen coordinates
SbViewVolume vv = camera->getViewVolume();
SbVec3f screenPoint[8];
vv.projectToScreen( SbVec3f( min[0], min[1], min[2] ), screenPoint[0] );
vv.projectToScreen( SbVec3f( min[0], min[1], max[2] ), screenPoint[1] );
vv.projectToScreen( SbVec3f( min[0], max[1], min[2] ), screenPoint[2] );
vv.projectToScreen( SbVec3f( min[0], max[1], max[2] ), screenPoint[3] );
vv.projectToScreen( SbVec3f( max[0], min[1], min[2] ), screenPoint[4] );
vv.projectToScreen( SbVec3f( max[0], min[1], max[2] ), screenPoint[5] );
vv.projectToScreen( SbVec3f( max[0], max[1], min[2] ), screenPoint[6] );
vv.projectToScreen( SbVec3f( max[0], max[1], max[2] ), screenPoint[7] );
// Find the encompassing 2d box (0 <= x,y <= 1)
SbBox2f bbox2;
for ( int i = 0; i < 8; i++ )
bbox2.extendBy( SbVec2f( screenPoint[i][0], screenPoint[i][1] ) );
if ( !bbox2.isEmpty() )
{
float xmin, ymin, xmax, ymax;
bbox2.getBounds( xmin, ymin, xmax, ymax );
// Set up the coordinate node
coords->point.set1Value( 0, xmin, ymin, 0 );
coords->point.set1Value( 1, xmax, ymin, 0 );
coords->point.set1Value( 2, xmax, ymax, 0 );
coords->point.set1Value( 3, xmin, ymax, 0 );
}
}
// beginTraversal - render highlights for our selection node.
void
OverlayHighlightRenderAction::apply( SoNode* renderRoot )
{
// Do not render the scene - only render the highlights
// Is our cached path still valid?
if ( ( selPath == NULL ) || ( selPath->getHead() != renderRoot ) || ( !selPath->getTail()->isOfType( SoSelection::getClassTypeId() ) ) )
{
// Find the selection node under the render root
SoSearchAction sa;
sa.setFind( SoSearchAction::TYPE );
sa.setInterest( SoSearchAction::FIRST );
sa.setType( SoSelection::getClassTypeId() );
sa.apply( renderRoot );
// Cache this path
if ( selPath != NULL )
selPath->unref();
selPath = sa.getPath();
if ( selPath != NULL )
{
selPath = selPath->copy();
selPath->ref();
}
}
if ( selPath != NULL )
{
// Make sure something is selected.
SoSelection* sel = ( SoSelection* )selPath->getTail();
if ( sel->getNumSelected() == 0 )
return;
// Keep the length from the root to the selection
// as an optimization so we can reuse this data.
int reusablePathLength = selPath->getLength();
// For each selection path, create a new path rooted
// under our localRoot.
for ( int j = 0; j < sel->getNumSelected(); j++ )
{
// Continue the path down to the selected object.
// No need to deal with p[0] since that is the sel
// node.
SoPath* p = sel->getPath( j );
SoNode* pathTail = p->getTail();
if ( pathTail->isOfType( SoBaseKit::getClassTypeId() ) )
{
// Find the last nodekit on the path.
SoNode* kitTail = ( ( SoNodeKitPath* )p )->getTail();
// Extend the selectionPath until it reaches this
// last kit.
SoFullPath* fp = ( SoFullPath* )p;
int k = 0;
do
{
selPath->append( fp->getIndex( ++k ) );
} while ( fp->getNode( k ) != kitTail );
}
else
{
for ( int k = 1; k < p->getLength(); k++ )
selPath->append( p->getIndex( k ) );
}
// Find the camera used to render the selected object.
SoNode* camera;
SoSearchAction sa;
sa.setFind( SoSearchAction::TYPE );
sa.setInterest( SoSearchAction::LAST );
sa.setType( SoCamera::getClassTypeId() );
sa.apply( selPath );
camera = ( sa.getPath() == NULL ? NULL : sa.getPath()->getTail() );
// Get the bounding box of the object and update the
// local highlight graph.
updateBbox( selPath, ( SoCamera* )camera );
// Make sure the box has some size.
if ( coords->point.getNum() == 0 )
{
#ifdef DEBUG
SoDebugError::post("OverlayHighlightRenderAction::apply", "selected object has no bounding box - cannot render a highlight");
#endif
}
else
{
// Render the highlight.
SoGLRenderAction::apply( localRoot );
}
// Restore selPath for reuse.
selPath->truncate( reusablePathLength );
}
}
}
// Function stubs: we do not highlight paths and pathLists.
void
OverlayHighlightRenderAction::apply( SoPath* path )
{
SoGLRenderAction::apply( path );
}
void
OverlayHighlightRenderAction::apply( const SoPathList& pathList, SbBool obeysRules )
{
SoGLRenderAction::apply( pathList, obeysRules );
}
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <Inventor/SoDB.h>
#include <Inventor/SoInput.h>
#include <Inventor/Xt/SoXt.h>
#include <Inventor/Xt/viewers/SoXtExaminerViewer.h>
#include <Inventor/nodes/SoSelection.h>
#include "OverlayHighlightRenderAction.h"
void
main( int, char* argv[] )
{
// Initialization
Widget mainWindow = SoXt::init( argv[0] );
OverlayHighlightRenderAction::initClass();
// Open the data file
SoInput in;
char* datafile = "monitor.iv";
if ( !in.openFile( datafile ) )
{
fprintf( stderr, "Cannot open %s for reading.\n", datafile );
return;
}
// Read the input file
SoNode* n;
SoSeparator* sep = new SoSeparator;
while ( ( SoDB::read( &in, n ) != FALSE ) && ( n != NULL ) )
sep->addChild( n );
// Create a selection root to show off our new highlight.
SoSelection* sel = new SoSelection;
sel->addChild( sep );
// Create a viewer.
SoXtExaminerViewer* viewer = new SoXtExaminerViewer( mainWindow );
viewer->setSceneGraph( sel );
// Set the overlay scene graph same as normal. For viewers,
// we have to cast to render area graph.
viewer->setOverlaySceneGraph( viewer->SoXtRenderArea::getSceneGraph() );
viewer->setTitle( "Overlay highlight" );
viewer->redrawOverlayOnSelectionChange( sel );
viewer->setOverlayGLRenderAction( new OverlayHighlightRenderAction );
// Set up the overlay color map
SbColor red( 1, 0, 0 );
viewer->setOverlayColorMap( 1, 1, &red );
viewer->show();
SoXt::show( mainWindow );
SoXt::mainLoop();
OverlayHighlightRenderAction::exitClass();
return 0;
}