2003-03-15 04:35:45 +08:00
# include <osg/Notify>
# include <osg/MatrixTransform>
# include <osg/PositionAttitudeTransform>
# include <osg/Geometry>
# include <osg/Geode>
# include <osgUtil/Optimizer>
# include <osgDB/Registry>
# include <osgDB/ReadFile>
# include <osgGA/TrackballManipulator>
# include <osgGA/FlightManipulator>
# include <osgGA/DriveManipulator>
2005-09-06 23:48:18 +08:00
# include <osgSim/OverlayNode>
2003-03-15 04:35:45 +08:00
# include <osgProducer/Viewer>
osg : : AnimationPath * createAnimationPath ( const osg : : Vec3 & center , float radius , double looptime )
{
// set up the animation path
osg : : AnimationPath * animationPath = new osg : : AnimationPath ;
animationPath - > setLoopMode ( osg : : AnimationPath : : LOOP ) ;
int numSamples = 40 ;
float yaw = 0.0f ;
float yaw_delta = 2.0f * osg : : PI / ( ( float ) numSamples - 1.0f ) ;
float roll = osg : : inDegrees ( 30.0f ) ;
double time = 0.0f ;
double time_delta = looptime / ( double ) numSamples ;
for ( int i = 0 ; i < numSamples ; + + i )
{
osg : : Vec3 position ( center + osg : : Vec3 ( sinf ( yaw ) * radius , cosf ( yaw ) * radius , 0.0f ) ) ;
osg : : Quat rotation ( osg : : Quat ( roll , osg : : Vec3 ( 0.0 , 1.0 , 0.0 ) ) * osg : : Quat ( - ( yaw + osg : : inDegrees ( 90.0f ) ) , osg : : Vec3 ( 0.0 , 0.0 , 1.0 ) ) ) ;
animationPath - > insert ( time , osg : : AnimationPath : : ControlPoint ( position , rotation ) ) ;
yaw + = yaw_delta ;
time + = time_delta ;
}
return animationPath ;
}
osg : : Node * createBase ( const osg : : Vec3 & center , float radius )
{
int numTilesX = 10 ;
int numTilesY = 10 ;
float width = 2 * radius ;
float height = 2 * radius ;
osg : : Vec3 v000 ( center - osg : : Vec3 ( width * 0.5f , height * 0.5f , 0.0f ) ) ;
osg : : Vec3 dx ( osg : : Vec3 ( width / ( ( float ) numTilesX ) , 0.0 , 0.0f ) ) ;
osg : : Vec3 dy ( osg : : Vec3 ( 0.0f , height / ( ( float ) numTilesY ) , 0.0f ) ) ;
// fill in vertices for grid, note numTilesX+1 * numTilesY+1...
osg : : Vec3Array * coords = new osg : : Vec3Array ;
int iy ;
for ( iy = 0 ; iy < = numTilesY ; + + iy )
{
for ( int ix = 0 ; ix < = numTilesX ; + + ix )
{
coords - > push_back ( v000 + dx * ( float ) ix + dy * ( float ) iy ) ;
}
}
//Just two colours - black and white.
osg : : Vec4Array * colors = new osg : : Vec4Array ;
colors - > push_back ( osg : : Vec4 ( 1.0f , 1.0f , 1.0f , 1.0f ) ) ; // white
colors - > push_back ( osg : : Vec4 ( 0.0f , 0.0f , 0.0f , 1.0f ) ) ; // black
int numColors = colors - > size ( ) ;
int numIndicesPerRow = numTilesX + 1 ;
osg : : UByteArray * coordIndices = new osg : : UByteArray ; // assumes we are using less than 256 points...
osg : : UByteArray * colorIndices = new osg : : UByteArray ;
for ( iy = 0 ; iy < numTilesY ; + + iy )
{
for ( int ix = 0 ; ix < numTilesX ; + + ix )
{
// four vertices per quad.
coordIndices - > push_back ( ix + ( iy + 1 ) * numIndicesPerRow ) ;
coordIndices - > push_back ( ix + iy * numIndicesPerRow ) ;
coordIndices - > push_back ( ( ix + 1 ) + iy * numIndicesPerRow ) ;
coordIndices - > push_back ( ( ix + 1 ) + ( iy + 1 ) * numIndicesPerRow ) ;
// one color per quad
colorIndices - > push_back ( ( ix + iy ) % numColors ) ;
}
}
// set up a single normal
osg : : Vec3Array * normals = new osg : : Vec3Array ;
normals - > push_back ( osg : : Vec3 ( 0.0f , 0.0f , 1.0f ) ) ;
osg : : Geometry * geom = new osg : : Geometry ;
geom - > setVertexArray ( coords ) ;
geom - > setVertexIndices ( coordIndices ) ;
geom - > setColorArray ( colors ) ;
geom - > setColorIndices ( colorIndices ) ;
geom - > setColorBinding ( osg : : Geometry : : BIND_PER_PRIMITIVE ) ;
geom - > setNormalArray ( normals ) ;
geom - > setNormalBinding ( osg : : Geometry : : BIND_OVERALL ) ;
geom - > addPrimitiveSet ( new osg : : DrawArrays ( osg : : PrimitiveSet : : QUADS , 0 , coordIndices - > size ( ) ) ) ;
osg : : Geode * geode = new osg : : Geode ;
geode - > addDrawable ( geom ) ;
return geode ;
}
osg : : Node * createMovingModel ( const osg : : Vec3 & center , float radius )
{
float animationLength = 10.0f ;
osg : : AnimationPath * animationPath = createAnimationPath ( center , radius , animationLength ) ;
osg : : Group * model = new osg : : Group ;
osg : : Node * glider = osgDB : : readNodeFile ( " glider.osg " ) ;
if ( glider )
{
const osg : : BoundingSphere & bs = glider - > getBound ( ) ;
float size = radius / bs . radius ( ) * 0.3f ;
osg : : MatrixTransform * positioned = new osg : : MatrixTransform ;
positioned - > setDataVariance ( osg : : Object : : STATIC ) ;
positioned - > setMatrix ( osg : : Matrix : : translate ( - bs . center ( ) ) *
osg : : Matrix : : scale ( size , size , size ) *
osg : : Matrix : : rotate ( osg : : inDegrees ( - 90.0f ) , 0.0f , 0.0f , 1.0f ) ) ;
positioned - > addChild ( glider ) ;
osg : : PositionAttitudeTransform * xform = new osg : : PositionAttitudeTransform ;
xform - > setUpdateCallback ( new osg : : AnimationPathCallback ( animationPath , 0.0 , 1.0 ) ) ;
xform - > addChild ( positioned ) ;
model - > addChild ( xform ) ;
}
osg : : Node * cessna = osgDB : : readNodeFile ( " cessna.osg " ) ;
if ( cessna )
{
const osg : : BoundingSphere & bs = cessna - > getBound ( ) ;
float size = radius / bs . radius ( ) * 0.3f ;
osg : : MatrixTransform * positioned = new osg : : MatrixTransform ;
positioned - > setDataVariance ( osg : : Object : : STATIC ) ;
positioned - > setMatrix ( osg : : Matrix : : translate ( - bs . center ( ) ) *
osg : : Matrix : : scale ( size , size , size ) *
osg : : Matrix : : rotate ( osg : : inDegrees ( 180.0f ) , 0.0f , 0.0f , 1.0f ) ) ;
positioned - > addChild ( cessna ) ;
osg : : MatrixTransform * xform = new osg : : MatrixTransform ;
xform - > setUpdateCallback ( new osg : : AnimationPathCallback ( animationPath , 0.0f , 2.0 ) ) ;
xform - > addChild ( positioned ) ;
model - > addChild ( xform ) ;
}
return model ;
}
2005-10-28 18:11:12 +08:00
osg : : Node * createModel ( bool overlay )
2003-03-15 04:35:45 +08:00
{
osg : : Vec3 center ( 0.0f , 0.0f , 0.0f ) ;
float radius = 100.0f ;
osg : : Group * root = new osg : : Group ;
2005-09-06 23:48:18 +08:00
osg : : Node * baseModel = createBase ( center - osg : : Vec3 ( 0.0f , 0.0f , radius * 0.5 ) , radius ) ;
osg : : Node * movingModel = createMovingModel ( center , radius * 0.8f ) ;
2005-10-28 18:11:12 +08:00
if ( overlay )
{
osgSim : : OverlayNode * overlayNode = new osgSim : : OverlayNode ;
2006-02-21 05:05:23 +08:00
overlayNode - > setContinuousUpdate ( true ) ;
2005-10-28 18:11:12 +08:00
overlayNode - > setOverlaySubgraph ( movingModel ) ;
overlayNode - > addChild ( baseModel ) ;
root - > addChild ( overlayNode ) ;
}
else
{
root - > addChild ( baseModel ) ;
}
2005-09-06 23:48:18 +08:00
root - > addChild ( movingModel ) ;
2003-03-15 04:35:45 +08:00
return root ;
}
int main ( int argc , char * * argv )
{
// use an ArgumentParser object to manage the program arguments.
osg : : ArgumentParser arguments ( & argc , argv ) ;
// set up the usage document, in case we need to print out how to use this program.
2003-04-09 19:44:32 +08:00
arguments . getApplicationUsage ( ) - > setDescription ( arguments . getApplicationName ( ) + " is the example which demonstrates use of osg::AnimationPath and UpdateCallbacks for adding animation to your scenes. " ) ;
2003-04-07 05:32:44 +08:00
arguments . getApplicationUsage ( ) - > setCommandLineUsage ( arguments . getApplicationName ( ) + " [options] filename ... " ) ;
2003-03-15 04:35:45 +08:00
arguments . getApplicationUsage ( ) - > addCommandLineOption ( " -h or --help " , " Display this information " ) ;
// initialize the viewer.
osgProducer : : Viewer viewer ( arguments ) ;
// set up the value with sensible default event handlers.
viewer . setUpViewer ( osgProducer : : Viewer : : STANDARD_SETTINGS ) ;
// get details on keyboard and mouse bindings used by the viewer.
viewer . getUsage ( * arguments . getApplicationUsage ( ) ) ;
// if user request help write it out to cout.
if ( arguments . read ( " -h " ) | | arguments . read ( " --help " ) )
{
arguments . getApplicationUsage ( ) - > write ( std : : cout ) ;
return 1 ;
}
2005-10-28 18:11:12 +08:00
bool overlay = false ;
while ( arguments . read ( " --overlay " ) ) overlay = true ;
2003-03-15 04:35:45 +08:00
// any option left unread are converted into errors to write out later.
arguments . reportRemainingOptionsAsUnrecognized ( ) ;
// report any errors if they have occured when parsing the program aguments.
if ( arguments . errors ( ) )
{
arguments . writeErrorMessages ( std : : cout ) ;
return 1 ;
}
2003-04-07 05:32:44 +08:00
2003-03-15 04:35:45 +08:00
// load the nodes from the commandline arguments.
2005-10-28 18:11:12 +08:00
osg : : Node * model = createModel ( overlay ) ;
2003-03-15 04:35:45 +08:00
if ( ! model )
{
return 1 ;
}
// tilt the scene so the default eye position is looking down on the model.
osg : : MatrixTransform * rootnode = new osg : : MatrixTransform ;
rootnode - > setMatrix ( osg : : Matrix : : rotate ( osg : : inDegrees ( 30.0f ) , 1.0f , 0.0f , 0.0f ) ) ;
rootnode - > addChild ( model ) ;
// run optimization over the scene graph
osgUtil : : Optimizer optimzer ;
optimzer . optimize ( rootnode ) ;
// set the scene to render
viewer . setSceneData ( rootnode ) ;
// create the windows and run the threads.
2003-04-08 23:18:45 +08:00
viewer . realize ( ) ;
2003-03-15 04:35:45 +08:00
while ( ! viewer . done ( ) )
{
// wait for all cull and draw threads to complete.
viewer . sync ( ) ;
// update the scene by traversing it with the the update visitor which will
// call all node update callbacks and animations.
viewer . update ( ) ;
// fire off the cull and draw traversals of the scene.
viewer . frame ( ) ;
}
2003-03-25 18:05:09 +08:00
2006-08-03 03:55:03 +08:00
// wait for all cull and draw threads to complete.
viewer . sync ( ) ;
// run a clean up frame to delete all OpenGL objects.
viewer . cleanup_frame ( ) ;
// wait for all the clean up frame to complete.
2003-03-25 18:05:09 +08:00
viewer . sync ( ) ;
2003-03-15 04:35:45 +08:00
return 0 ;
}