2003-02-24 01:01:05 +08:00
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2003 Robert Osfield
*
* This library is open source and may be redistributed and / or modified under
* the terms of the OpenSceneGraph Public License ( OSGPL ) version 0.0 or
* ( at your option ) any later version . The full license is in LICENSE file
* included with this distribution , and on the openscenegraph . org website .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* OpenSceneGraph Public License for more details .
*/
2003-02-25 20:28:16 +08:00
# include <osgProducer/Viewer>
2003-02-24 01:01:05 +08:00
# include <osgDB/ReadFile>
2003-03-23 04:35:11 +08:00
# include <osgDB/WriteFile>
2003-02-24 01:01:05 +08:00
# include <osgUtil/Optimizer>
2003-02-25 20:28:16 +08:00
# include <osg/Geode>
2003-02-24 01:01:05 +08:00
# include <osg/Notify>
# include <osg/MatrixTransform>
2003-03-23 04:35:11 +08:00
# include <osg/Switch>
# include <osg/TexMat>
# include <osg/Texture2D>
2003-02-24 01:01:05 +08:00
2003-03-23 04:35:11 +08:00
typedef std : : vector < std : : string > FileList ;
class SlideEventHandler : public osgGA : : GUIEventHandler , public osg : : NodeCallback
{
public :
SlideEventHandler ( ) ;
META_Object ( osgStereImageApp , SlideEventHandler ) ;
void set ( osg : : Switch * sw , osg : : TexMat * texmat , float timePerSlide , bool autoSteppingActive ) ;
virtual void accept ( osgGA : : GUIEventHandlerVisitor & v ) { v . visit ( * this ) ; }
virtual bool handle ( const osgGA : : GUIEventAdapter & ea , osgGA : : GUIActionAdapter & ) ;
virtual void getUsage ( osg : : ApplicationUsage & usage ) const ;
virtual void operator ( ) ( osg : : Node * node , osg : : NodeVisitor * nv ) ;
void nextSlide ( ) ;
void previousSlide ( ) ;
void scaleImage ( float s ) ;
void rotateImage ( float rx , float ry ) ;
protected :
~ SlideEventHandler ( ) { }
SlideEventHandler ( const SlideEventHandler & , const osg : : CopyOp & ) { }
osg : : ref_ptr < osg : : Switch > _switch ;
osg : : ref_ptr < osg : : TexMat > _texmat ;
bool _firstTraversal ;
unsigned int _activeSlide ;
double _previousTime ;
double _timePerSlide ;
bool _autoSteppingActive ;
} ;
SlideEventHandler : : SlideEventHandler ( ) :
_switch ( 0 ) ,
_texmat ( 0 ) ,
_firstTraversal ( true ) ,
_activeSlide ( 0 ) ,
_previousTime ( - 1.0f ) ,
_timePerSlide ( 5.0 ) ,
_autoSteppingActive ( false )
{
}
void SlideEventHandler : : set ( osg : : Switch * sw , osg : : TexMat * texmat , float timePerSlide , bool autoSteppingActive )
{
_switch = sw ;
_switch - > setUpdateCallback ( this ) ;
_texmat = texmat ;
_timePerSlide = timePerSlide ;
_autoSteppingActive = autoSteppingActive ;
}
bool SlideEventHandler : : handle ( const osgGA : : GUIEventAdapter & ea , osgGA : : GUIActionAdapter & )
{
switch ( ea . getEventType ( ) )
{
case ( osgGA : : GUIEventAdapter : : KEYDOWN ) :
{
if ( ea . getKey ( ) = = ' a ' )
{
_autoSteppingActive = ! _autoSteppingActive ;
_previousTime = ea . time ( ) ;
return true ;
}
else if ( ea . getKey ( ) = = ' n ' )
{
nextSlide ( ) ;
return true ;
}
else if ( ea . getKey ( ) = = ' p ' )
{
previousSlide ( ) ;
return true ;
}
else if ( ea . getKey ( ) = = ' z ' )
{
scaleImage ( 0.99f ) ;
return true ;
}
else if ( ea . getKey ( ) = = ' x ' )
{
scaleImage ( 1.01f ) ;
return true ;
}
else if ( ea . getKey ( ) = = ' ' )
{
if ( _texmat . valid ( ) ) _texmat - > setMatrix ( osg : : Matrix : : identity ( ) ) ;
return true ;
}
return false ;
}
case ( osgGA : : GUIEventAdapter : : DRAG ) :
case ( osgGA : : GUIEventAdapter : : MOVE ) :
{
static int px = ea . getX ( ) ;
static int py = ea . getY ( ) ;
int dx = ea . getX ( ) - px ;
int dy = ea . getY ( ) - py ;
px = ea . getX ( ) ;
py = ea . getY ( ) ;
rotateImage ( ( float ) dx / ( float ) ( ea . getXmax ( ) - ea . getXmin ( ) ) , ( float ) dy / ( float ) ( ea . getYmax ( ) - ea . getYmin ( ) ) ) ;
return true ;
}
default :
return false ;
}
}
void SlideEventHandler : : getUsage ( osg : : ApplicationUsage & usage ) const
{
usage . addKeyboardMouseBinding ( " Space " , " Reset the image position to center " ) ;
usage . addKeyboardMouseBinding ( " a " , " Toggle on/off the automatic advancement for image to image " ) ;
usage . addKeyboardMouseBinding ( " n " , " Advance to next image " ) ;
usage . addKeyboardMouseBinding ( " p " , " Move to previous image " ) ;
usage . addKeyboardMouseBinding ( " z " , " Zoom into the image " ) ;
usage . addKeyboardMouseBinding ( " x " , " Zoom out of the image " ) ;
}
void SlideEventHandler : : operator ( ) ( osg : : Node * node , osg : : NodeVisitor * nv )
{
if ( _autoSteppingActive & & nv - > getFrameStamp ( ) )
{
double time = nv - > getFrameStamp ( ) - > getReferenceTime ( ) ;
if ( _firstTraversal )
{
_firstTraversal = false ;
_previousTime = time ;
}
else if ( time - _previousTime > _timePerSlide )
{
_previousTime = time ;
nextSlide ( ) ;
}
}
traverse ( node , nv ) ;
}
void SlideEventHandler : : nextSlide ( )
{
if ( _switch - > getNumChildren ( ) = = 0 ) return ;
+ + _activeSlide ;
if ( _activeSlide > = _switch - > getNumChildren ( ) ) _activeSlide = 0 ;
_switch - > setSingleChildOn ( _activeSlide ) ;
}
void SlideEventHandler : : previousSlide ( )
{
if ( _switch - > getNumChildren ( ) = = 0 ) return ;
if ( _activeSlide = = 0 ) _activeSlide = _switch - > getNumChildren ( ) - 1 ;
else - - _activeSlide ;
_switch - > setSingleChildOn ( _activeSlide ) ;
}
void SlideEventHandler : : scaleImage ( float s )
{
if ( _texmat . valid ( ) )
{
_texmat - > setMatrix ( _texmat - > getMatrix ( ) * osg : : Matrix : : translate ( - 0.5f , - 0.5f , 0.0f ) * osg : : Matrix : : scale ( s , s , 1.0f ) * osg : : Matrix : : translate ( 0.5f , 0.5f , 0.0f ) ) ;
}
}
void SlideEventHandler : : rotateImage ( float rx , float ry )
{
if ( _texmat . valid ( ) )
{
const float scale = 0.5f ;
_texmat - > setMatrix ( _texmat - > getMatrix ( ) * osg : : Matrix : : translate ( - rx * scale , ry * scale , 0.0f ) ) ;
}
}
osg : : Geode * createSectorForImage ( osg : : Image * image , float s , float t , float radius , float height , float length )
{
int numSegments = 20 ;
float Theta = length / radius ;
float dTheta = Theta / ( float ) ( numSegments - 1 ) ;
float ThetaZero = height * s / ( t * radius ) ;
// set up the texture.
osg : : Texture2D * texture = new osg : : Texture2D ;
texture - > setFilter ( osg : : Texture2D : : MIN_FILTER , osg : : Texture2D : : LINEAR ) ;
texture - > setFilter ( osg : : Texture2D : : MAG_FILTER , osg : : Texture2D : : LINEAR ) ;
texture - > setImage ( image ) ;
// set up the drawstate.
osg : : StateSet * dstate = new osg : : StateSet ;
dstate - > setMode ( GL_CULL_FACE , osg : : StateAttribute : : OFF ) ;
dstate - > setMode ( GL_LIGHTING , osg : : StateAttribute : : OFF ) ;
dstate - > setTextureAttributeAndModes ( 0 , texture , osg : : StateAttribute : : ON ) ;
// set up the geoset.
osg : : Geometry * geom = new osg : : Geometry ;
geom - > setStateSet ( dstate ) ;
osg : : Vec3Array * coords = new osg : : Vec3Array ( ) ;
osg : : Vec2Array * tcoords = new osg : : Vec2Array ( ) ;
int i ;
float angle = - Theta / 2.0f ;
for ( i = 0 ;
i < numSegments ;
+ + i , angle + = dTheta )
{
coords - > push_back ( osg : : Vec3 ( sinf ( angle ) * radius , cosf ( angle ) * radius , height * 0.5f ) ) ; // top
coords - > push_back ( osg : : Vec3 ( sinf ( angle ) * radius , cosf ( angle ) * radius , - height * 0.5f ) ) ; // bottom.
tcoords - > push_back ( osg : : Vec2 ( angle / ThetaZero + 0.5f , 1.0f ) ) ; // top
tcoords - > push_back ( osg : : Vec2 ( angle / ThetaZero + 0.5f , 0.0f ) ) ; // bottom.
}
osg : : Vec4Array * colors = new osg : : Vec4Array ( ) ;
colors - > push_back ( osg : : Vec4 ( 1.0f , 1.0f , 1.0f , 1.0f ) ) ;
osg : : DrawArrays * elements = new osg : : DrawArrays ( osg : : PrimitiveSet : : QUAD_STRIP , 0 , coords - > size ( ) ) ;
geom - > setVertexArray ( coords ) ;
geom - > setTexCoordArray ( 0 , tcoords ) ;
geom - > setColorArray ( colors ) ;
geom - > setColorBinding ( osg : : Geometry : : BIND_OVERALL ) ;
geom - > addPrimitiveSet ( elements ) ;
// set up the geode.
osg : : Geode * geode = new osg : : Geode ;
geode - > addDrawable ( geom ) ;
return geode ;
}
// create a switch containing a set of child each containing a
// stereo image pair.
osg : : Switch * createScene ( const FileList & fileList , float radius , float height , float length )
{
osg : : Switch * sw = new osg : : Switch ;
// load the images.
for ( unsigned int i = 0 ; i + 1 < fileList . size ( ) ; i + = 2 )
{
osg : : ref_ptr < osg : : Image > imageLeft = osgDB : : readImageFile ( fileList [ i ] ) ;
osg : : ref_ptr < osg : : Image > imageRight = osgDB : : readImageFile ( fileList [ i + 1 ] ) ;
if ( imageLeft . valid ( ) & & imageRight . valid ( ) )
{
float average_s = ( imageLeft - > s ( ) + imageRight - > s ( ) ) * 0.5f ;
float average_t = ( imageLeft - > t ( ) + imageRight - > t ( ) ) * 0.5f ;
osg : : Geode * geodeLeft = createSectorForImage ( imageLeft . get ( ) , average_s , average_t , radius , height , length ) ;
geodeLeft - > setNodeMask ( 0x01 ) ;
osg : : Geode * geodeRight = createSectorForImage ( imageRight . get ( ) , average_s , average_t , radius , height , length ) ;
geodeRight - > setNodeMask ( 0x02 ) ;
osg : : ref_ptr < osg : : Group > imageGroup = new osg : : Group ;
imageGroup - > addChild ( geodeLeft ) ;
imageGroup - > addChild ( geodeRight ) ;
sw - > addChild ( imageGroup . get ( ) ) ;
}
else
{
std : : cout < < " Warning: Unable to load both image files, ' " < < fileList [ i ] < < " ' & ' " < < fileList [ i + 1 ] < < " ', required for stereo imaging. " < < std : : endl ;
}
}
if ( sw - > getNumChildren ( ) > 0 )
{
// select first child.
sw - > setSingleChildOn ( 0 ) ;
}
return sw ;
}
2003-02-24 01:01:05 +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.
arguments . getApplicationUsage ( ) - > setCommandLineUsage ( arguments . getProgramName ( ) + " [options] image_file_left_eye image_file_right_eye " ) ;
2003-03-23 04:35:11 +08:00
arguments . getApplicationUsage ( ) - > addCommandLineOption ( " -d <float> " , " Time delay in sceonds between the display of successive image pairs when in auto advance mode. " ) ;
arguments . getApplicationUsage ( ) - > addCommandLineOption ( " -a " , " Enter auto advance of image pairs on start up. " ) ;
2003-02-24 01:01:05 +08:00
arguments . getApplicationUsage ( ) - > addCommandLineOption ( " -h or --help " , " Display this information " ) ;
// construct the viewer.
osgProducer : : Viewer viewer ( arguments ) ;
// set up the value with sensible default event handlers.
2003-03-23 04:35:11 +08:00
viewer . setUpViewer ( osgProducer : : Viewer : : ESCAPE_SETS_DONE ) ;
// register the handler to add keyboard and mosue handling.
SlideEventHandler * seh = new SlideEventHandler ( ) ;
viewer . getEventHandlerList ( ) . push_front ( seh ) ;
2003-02-24 01:01:05 +08:00
// get details on keyboard and mouse bindings used by the viewer.
viewer . getUsage ( * arguments . getApplicationUsage ( ) ) ;
2003-03-23 04:35:11 +08:00
// read any time delay argument.
float timeDelayBetweenSlides = 5.0f ;
while ( arguments . read ( " -d " , timeDelayBetweenSlides ) ) { }
bool autoSteppingActive = false ;
while ( arguments . read ( " -a " ) ) autoSteppingActive = true ;
2003-02-24 01:01:05 +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 ;
}
// extract the filenames from the arguments list.
2003-03-23 04:35:11 +08:00
FileList fileList ;
2003-02-24 01:01:05 +08:00
for ( int pos = 1 ; pos < arguments . argc ( ) ; + + pos )
{
2003-03-23 04:35:11 +08:00
if ( arguments . isString ( pos ) ) fileList . push_back ( arguments [ pos ] ) ;
2003-02-24 01:01:05 +08:00
}
2003-03-25 21:57:16 +08:00
if ( fileList . size ( ) < 2 )
{
return 1 ;
}
2003-02-24 01:01:05 +08:00
2003-03-23 04:35:11 +08:00
// set up the use of stereo by default.
osg : : DisplaySettings * ds = viewer . getDisplaySettings ( ) ;
if ( ! ds ) ds = osg : : DisplaySettings : : instance ( ) ;
if ( ds ) ds - > setStereo ( true ) ;
// create the windows and run the threads.
viewer . realize ( Producer : : CameraGroup : : ThreadPerCamera ) ;
// now the windows have been realized we switch off the cursor to prevent it
// distracting the people seeing the stereo images.
float fovy = 1.0f ;
for ( unsigned int i = 0 ; i < viewer . getCameraConfig ( ) - > getNumberOfCameras ( ) ; i + + )
2003-02-24 01:01:05 +08:00
{
2003-03-23 04:35:11 +08:00
Producer : : Camera * cam = viewer . getCameraConfig ( ) - > getCamera ( i ) ;
Producer : : RenderSurface * rs = cam - > getRenderSurface ( ) ;
rs - > useCursor ( false ) ;
fovy = cam - > getLensVerticalFov ( ) ;
2003-02-24 01:01:05 +08:00
}
2003-03-23 04:35:11 +08:00
float radius = 1.0f ;
float height = 2 * radius * tanf ( fovy * 0.5f ) ;
float length = osg : : PI * radius ; // half a cylinder.
2003-02-24 01:01:05 +08:00
2003-03-23 04:35:11 +08:00
// creat the scene from the file list.
osg : : ref_ptr < osg : : Switch > rootNode = createScene ( fileList , radius , height , length ) ;
2003-02-24 01:01:05 +08:00
2003-03-23 04:35:11 +08:00
// use a texure matrix to control the placement of the image.
osg : : StateSet * stateset = rootNode - > getOrCreateStateSet ( ) ;
osg : : TexMat * texmat = new osg : : TexMat ;
stateset - > setTextureAttribute ( 0 , texmat ) ;
2003-04-01 20:00:13 +08:00
//osgDB::writeNodeFile(*rootNode,"test.osg");
2003-02-24 01:01:05 +08:00
// set the scene to render
viewer . setSceneData ( rootNode . get ( ) ) ;
// set all the sceneview's up so that their left and right add cull masks are set up.
2003-02-25 20:28:16 +08:00
for ( osgProducer : : OsgCameraGroup : : SceneHandlerList : : iterator itr = viewer . getSceneHandlerList ( ) . begin ( ) ;
2003-02-24 01:01:05 +08:00
itr ! = viewer . getSceneHandlerList ( ) . end ( ) ;
+ + itr )
{
2003-03-19 04:27:09 +08:00
osgUtil : : SceneView * sceneview = itr - > get ( ) ;
2003-02-24 01:01:05 +08:00
sceneview - > setCullMask ( 0xffffffff ) ;
sceneview - > setCullMaskLeft ( 0x00000001 ) ;
sceneview - > setCullMaskRight ( 0x00000002 ) ;
2003-03-23 04:35:11 +08:00
sceneview - > setFusionDistance ( osgUtil : : SceneView : : USE_FUSION_DISTANCE_VALUE , radius ) ;
sceneview - > setCamera ( 0 ) ;
2003-02-24 01:01:05 +08:00
}
2003-03-23 04:35:11 +08:00
// set up the SlideEventHandler.
seh - > set ( rootNode . get ( ) , texmat , timeDelayBetweenSlides , autoSteppingActive ) ;
osg : : Matrix homePosition ;
homePosition . makeLookAt ( osg : : Vec3 ( 0.0f , 0.0f , 0.0f ) , osg : : Vec3 ( 0.0f , 1.0f , 0.0f ) , osg : : Vec3 ( 0.0f , 0.0f , 1.0f ) ) ;
2003-02-24 01:01:05 +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 ( ) ;
2003-03-23 04:35:11 +08:00
viewer . setView ( homePosition . ptr ( ) ) ;
2003-02-24 01:01:05 +08:00
// fire off the cull and draw traversals of the scene.
viewer . frame ( ) ;
}
2003-03-25 18:05:09 +08:00
// wait for all cull and draw threads to complete before exit.
viewer . sync ( ) ;
2003-02-24 01:01:05 +08:00
return 0 ;
}