2003-03-15 04:35:45 +08:00
# ifdef USE_MEM_CHECK
# include <mcheck.h>
# endif
# include <osg/Group>
# include <osg/Notify>
# include <osgDB/Registry>
# include <osgDB/ReadFile>
# include <osgProducer/Viewer>
# include <osg/Quat>
2004-08-04 16:27:43 +08:00
# if defined (WIN32) && !defined(__CYGWIN__)
2003-03-15 04:35:45 +08:00
# include <winsock.h>
# endif
# include "receiver.h"
# include "broadcaster.h"
typedef unsigned char * BytePtr ;
template < class T >
inline void swapBytes ( T & s )
{
if ( sizeof ( T ) = = 1 ) return ;
T d = s ;
BytePtr sptr = ( BytePtr ) & s ;
BytePtr dptr = & ( ( ( BytePtr ) & d ) [ sizeof ( T ) - 1 ] ) ;
for ( unsigned int i = 0 ; i < sizeof ( T ) ; i + + )
* ( sptr + + ) = * ( dptr - - ) ;
}
class CameraPacket {
public :
CameraPacket ( ) : _masterKilled ( false )
2003-10-10 17:41:04 +08:00
{
_byte_order = 0x12345678 ;
}
2003-03-15 04:35:45 +08:00
2003-03-17 05:58:27 +08:00
void setPacket ( const osg : : Matrix & matrix , const osg : : FrameStamp * frameStamp )
2003-03-15 04:35:45 +08:00
{
2003-03-17 05:58:27 +08:00
_matrix = matrix ;
2003-03-15 04:35:45 +08:00
if ( frameStamp )
{
_frameStamp = * frameStamp ;
}
}
2003-03-17 05:58:27 +08:00
void getModelView ( osg : : Matrix & matrix , float angle_offset = 0.0f )
2003-03-15 04:35:45 +08:00
{
2003-10-10 17:41:04 +08:00
matrix = _matrix * osg : : Matrix : : rotate ( osg : : DegreesToRadians ( angle_offset ) , 0.0f , 1.0f , 0.0f ) ;
2003-03-15 04:35:45 +08:00
}
2003-10-10 17:41:04 +08:00
void checkByteOrder ( void )
2003-05-21 20:15:45 +08:00
{
2003-10-10 17:41:04 +08:00
if ( _byte_order = = 0x78563412 ) // We're backwards
{
swapBytes ( _byte_order ) ;
swapBytes ( _masterKilled ) ;
for ( int i = 0 ; i < 16 ; i + + )
swapBytes ( _matrix . ptr ( ) [ i ] ) ;
// umm.. we should byte swap _frameStamp too...
}
2003-05-21 20:15:45 +08:00
}
2003-03-15 04:35:45 +08:00
void setMasterKilled ( const bool flag ) { _masterKilled = flag ; }
const bool getMasterKilled ( ) const { return _masterKilled ; }
2003-05-21 20:15:45 +08:00
unsigned long _byte_order ;
2003-03-15 04:35:45 +08:00
bool _masterKilled ;
osg : : Matrix _matrix ;
// note don't use a ref_ptr as used elsewhere for FrameStamp
// since we don't want to copy the pointer - but the memory.
// FrameStamp doesn't have a private destructor to allow
// us to do this, even though its a reference counted object.
osg : : FrameStamp _frameStamp ;
} ;
2003-03-17 05:58:27 +08:00
enum ViewerMode
2003-03-15 04:35:45 +08:00
{
2003-03-17 05:58:27 +08:00
STAND_ALONE ,
SLAVE ,
MASTER
} ;
2003-03-15 04:35:45 +08:00
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 how to approach implementation of clustering. Note, cluster support will soon be encompassed in Producer itself. " ) ;
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 " ) ;
2003-03-17 05:58:27 +08:00
arguments . getApplicationUsage ( ) - > addCommandLineOption ( " -m " , " Set viewer to MASTER mode, sending view via packets. " ) ;
arguments . getApplicationUsage ( ) - > addCommandLineOption ( " -s " , " Set viewer to SLAVE mode, reciving view via packets. " ) ;
arguments . getApplicationUsage ( ) - > addCommandLineOption ( " -n <int> " , " Socket number to transmit packets " ) ;
arguments . getApplicationUsage ( ) - > addCommandLineOption ( " -f <float> " , " Field of view of camera " ) ;
arguments . getApplicationUsage ( ) - > addCommandLineOption ( " -o <float> " , " Offset angle of camera " ) ;
2003-03-15 04:35:45 +08:00
// construct 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 ( ) ) ;
2003-03-17 05:58:27 +08:00
// read up the osgcluster specific arguments.
ViewerMode viewerMode = STAND_ALONE ;
while ( arguments . read ( " -m " ) ) viewerMode = MASTER ;
while ( arguments . read ( " -s " ) ) viewerMode = SLAVE ;
float socketNumber = 8100.0f ;
while ( arguments . read ( " -n " , socketNumber ) ) ;
2004-10-19 21:52:46 +08:00
float camera_fov = - 1.0f ;
2003-10-10 17:41:04 +08:00
while ( arguments . read ( " -f " , camera_fov ) )
{
}
2003-03-17 05:58:27 +08:00
float camera_offset = 45.0f ;
while ( arguments . read ( " -o " , camera_offset ) ) ;
2003-03-15 04:35:45 +08:00
// if user request help write it out to cout.
if ( arguments . read ( " -h " ) | | arguments . read ( " --help " ) )
{
arguments . getApplicationUsage ( ) - > write ( std : : cout ) ;
return 1 ;
}
// 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
if ( arguments . argc ( ) < = 1 )
{
arguments . getApplicationUsage ( ) - > write ( std : : cout , osg : : ApplicationUsage : : COMMAND_LINE_OPTION ) ;
return 1 ;
}
2003-03-15 04:35:45 +08:00
2003-03-17 05:58:27 +08:00
// load model.
osg : : ref_ptr < osg : : Node > rootnode = osgDB : : readNodeFiles ( arguments ) ;
2003-03-15 04:35:45 +08:00
// set the scene to render
2003-03-17 05:58:27 +08:00
viewer . setSceneData ( rootnode . get ( ) ) ;
2003-03-15 04:35:45 +08:00
// 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
2004-10-19 21:52:46 +08:00
// set up the lens after realize as the Producer lens is not set up properly before this.... will need to inveestigate this at a later date.
if ( camera_fov > 0.0f )
{
float aspectRatio = tan ( osg : : DegreesToRadians ( viewer . getLensVerticalFov ( ) * 0.5 ) ) / tan ( osg : : DegreesToRadians ( viewer . getLensHorizontalFov ( ) * 0.5 ) ) ;
float new_fovy = osg : : RadiansToDegrees ( atan ( aspectRatio * tan ( osg : : DegreesToRadians ( camera_fov * 0.5 ) ) ) ) * 2.0f ;
std : : cout < < " setting lens perspective : original " < < viewer . getLensHorizontalFov ( ) < < " " < < viewer . getLensVerticalFov ( ) < < std : : endl ;
viewer . setLensPerspective ( camera_fov , new_fovy , 1.0f , 1000.0f ) ;
std : : cout < < " setting lens perspective : new " < < viewer . getLensHorizontalFov ( ) < < " " < < viewer . getLensVerticalFov ( ) < < std : : endl ;
}
2003-03-17 17:51:19 +08:00
// objects for managing the broadcasting and recieving of camera packets.
2003-03-17 05:58:27 +08:00
Broadcaster bc ;
Receiver rc ;
2003-05-21 20:15:45 +08:00
bc . setPort ( static_cast < short int > ( socketNumber ) ) ;
rc . setPort ( static_cast < short int > ( socketNumber ) ) ;
bool masterKilled = false ;
while ( ! viewer . done ( ) & & ! masterKilled )
2003-03-15 04:35:45 +08:00
{
// 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 ( ) ;
2003-03-17 05:58:27 +08:00
// special handling for working as a cluster.
switch ( viewerMode )
{
case ( MASTER ) :
{
CameraPacket cp ;
// take camera zero as the guide.
osg : : Matrix modelview ( viewer . getCameraConfig ( ) - > getCamera ( 0 ) - > getViewMatrix ( ) ) ;
cp . setPacket ( modelview , viewer . getFrameStamp ( ) ) ;
bc . setBuffer ( & cp , sizeof ( CameraPacket ) ) ;
2004-06-15 03:31:48 +08:00
bc . sync ( ) ;
2003-03-17 05:58:27 +08:00
}
break ;
case ( SLAVE ) :
{
CameraPacket cp ;
rc . setBuffer ( & cp , sizeof ( CameraPacket ) ) ;
2003-05-21 20:15:45 +08:00
rc . sync ( ) ;
cp . checkByteOrder ( ) ;
2003-03-17 05:58:27 +08:00
osg : : Matrix modelview ;
cp . getModelView ( modelview , camera_offset ) ;
2003-04-07 02:18:52 +08:00
viewer . setView ( modelview ) ;
2003-03-17 05:58:27 +08:00
if ( cp . getMasterKilled ( ) )
{
2003-05-21 20:15:45 +08:00
std : : cout < < " received master killed " < < std : : endl ;
2003-03-17 17:51:19 +08:00
// break out of while (!done) loop since we've now want to shut down.
2003-05-21 20:15:45 +08:00
masterKilled = true ;
2003-03-17 05:58:27 +08:00
}
}
break ;
default :
// no need to anything here, just a normal interactive viewer.
break ;
}
2003-03-15 04:35:45 +08:00
// fire off the cull and draw traversals of the scene.
2003-05-21 20:15:45 +08:00
if ( ! masterKilled )
viewer . frame ( ) ;
2003-03-15 04:35:45 +08:00
}
2003-05-21 20:15:45 +08:00
2003-03-25 18:05:09 +08:00
// wait for all cull and draw threads to complete before exit.
viewer . sync ( ) ;
2003-03-17 05:58:27 +08:00
// if we are master clean up by telling all slaves that we're going down.
if ( viewerMode = = MASTER )
{
// need to broadcast my death.
CameraPacket cp ;
cp . setPacket ( osg : : Matrix : : identity ( ) , viewer . getFrameStamp ( ) ) ;
cp . setMasterKilled ( true ) ;
bc . setBuffer ( & cp , sizeof ( CameraPacket ) ) ;
2003-05-21 20:15:45 +08:00
bc . sync ( ) ;
2003-03-17 05:58:27 +08:00
std : : cout < < " broadcasting death " < < std : : endl ;
}
2003-03-15 04:35:45 +08:00
return 0 ;
}