2007-06-12 22:20:16 +08:00
/* OpenSceneGraph example, osgvolume.
*
* Permission is hereby granted , free of charge , to any person obtaining a copy
* of this software and associated documentation files ( the " Software " ) , to deal
* in the Software without restriction , including without limitation the rights
* to use , copy , modify , merge , publish , distribute , sublicense , and / or sell
* copies of the Software , and to permit persons to whom the Software is
* furnished to do so , subject to the following conditions :
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
* LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM ,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE .
*/
2004-06-29 21:59:07 +08:00
# include <osg/Node>
# include <osg/Geometry>
# include <osg/Notify>
# include <osg/Texture3D>
2008-09-24 18:45:15 +08:00
# include <osg/Texture1D>
2008-09-29 18:56:42 +08:00
# include <osg/ImageSequence>
2004-06-29 21:59:07 +08:00
# include <osg/TexGen>
# include <osg/Geode>
# include <osg/Billboard>
# include <osg/PositionAttitudeTransform>
# include <osg/ClipNode>
# include <osg/AlphaFunc>
# include <osg/TexGenNode>
2005-05-02 03:48:49 +08:00
# include <osg/TexEnv>
2004-06-29 21:59:07 +08:00
# include <osg/TexEnvCombine>
2004-07-07 23:05:00 +08:00
# include <osg/Material>
2005-09-05 17:14:30 +08:00
# include <osg/PrimitiveSet>
2005-02-01 04:09:24 +08:00
# include <osg/Endian>
2008-08-18 23:08:04 +08:00
# include <osg/BlendFunc>
# include <osg/BlendEquation>
2008-09-12 23:41:30 +08:00
# include <osg/TransferFunction>
2008-10-02 23:45:08 +08:00
# include <osg/MatrixTransform>
2004-06-29 21:59:07 +08:00
# include <osgDB/Registry>
# include <osgDB/ReadFile>
# include <osgDB/WriteFile>
2005-09-05 15:48:55 +08:00
# include <osgDB/FileUtils>
2004-06-29 21:59:07 +08:00
# include <osgDB/FileNameUtils>
2005-09-05 21:19:20 +08:00
# include <osgGA/EventVisitor>
2008-09-29 18:56:42 +08:00
# include <osgGA/TrackballManipulator>
# include <osgGA/FlightManipulator>
# include <osgGA/KeySwitchMatrixManipulator>
2013-11-26 01:36:17 +08:00
# include <osgGA/StateSetManipulator>
2005-09-05 21:19:20 +08:00
2004-06-29 21:59:07 +08:00
# include <osgUtil/CullVisitor>
2007-01-11 23:19:59 +08:00
# include <osgViewer/Viewer>
2008-08-27 01:40:04 +08:00
# include <osgViewer/ViewerEventHandlers>
2007-01-11 23:19:59 +08:00
2009-07-03 02:50:45 +08:00
# include <osgManipulator/TabBoxDragger>
2009-07-03 13:54:27 +08:00
# include <osgManipulator/TabPlaneTrackballDragger>
# include <osgManipulator/TrackballDragger>
2009-07-03 02:50:45 +08:00
2008-08-23 00:35:49 +08:00
# include <osg/io_utils>
2008-09-13 21:38:06 +08:00
# include <algorithm>
2007-01-11 23:19:59 +08:00
# include <iostream>
2004-06-29 21:59:07 +08:00
2009-01-09 23:19:25 +08:00
# include <osg/ImageUtils>
# include <osgVolume/Volume>
# include <osgVolume/VolumeTile>
2009-01-21 22:27:58 +08:00
# include <osgVolume/RayTracedTechnique>
2009-01-14 01:20:32 +08:00
# include <osgVolume/FixedFunctionTechnique>
2013-11-22 02:17:44 +08:00
# include <osgVolume/MultipassTechnique>
# include <osgVolume/VolumeScene>
2004-06-29 21:59:07 +08:00
2008-09-26 19:29:00 +08:00
enum ShadingModel
{
Standard ,
Light ,
Isosurface ,
MaximumIntensityProjection
} ;
2011-06-09 00:10:46 +08:00
osg : : Image * createTexture3D ( osg : : ImageList & imageList ,
unsigned int numComponentsDesired ,
int s_maximumTextureSize ,
int t_maximumTextureSize ,
int r_maximumTextureSize ,
bool resizeToPowerOfTwo )
{
if ( numComponentsDesired = = 0 )
{
2011-06-09 01:45:24 +08:00
return osg : : createImage3DWithAlpha ( imageList ,
s_maximumTextureSize ,
t_maximumTextureSize ,
r_maximumTextureSize ,
resizeToPowerOfTwo ) ;
2011-06-09 00:10:46 +08:00
}
else
{
2011-06-09 01:45:24 +08:00
GLenum desiredPixelFormat = 0 ;
2011-06-09 00:10:46 +08:00
switch ( numComponentsDesired )
{
case ( 1 ) : desiredPixelFormat = GL_LUMINANCE ; break ;
case ( 2 ) : desiredPixelFormat = GL_LUMINANCE_ALPHA ; break ;
case ( 3 ) : desiredPixelFormat = GL_RGB ; break ;
case ( 4 ) : desiredPixelFormat = GL_RGBA ; break ;
}
2011-06-09 01:45:24 +08:00
return osg : : createImage3D ( imageList ,
2011-06-09 00:10:46 +08:00
desiredPixelFormat ,
s_maximumTextureSize ,
t_maximumTextureSize ,
r_maximumTextureSize ,
resizeToPowerOfTwo ) ;
}
}
2005-02-01 04:09:24 +08:00
struct ScaleOperator
{
2005-02-02 06:36:05 +08:00
ScaleOperator ( ) : _scale ( 1.0f ) { }
2005-02-01 04:09:24 +08:00
ScaleOperator ( float scale ) : _scale ( scale ) { }
2005-02-02 06:36:05 +08:00
ScaleOperator ( const ScaleOperator & so ) : _scale ( so . _scale ) { }
2009-09-01 18:48:32 +08:00
2005-02-02 06:36:05 +08:00
ScaleOperator & operator = ( const ScaleOperator & so ) { _scale = so . _scale ; return * this ; }
2005-02-01 04:09:24 +08:00
float _scale ;
2009-09-01 18:48:32 +08:00
inline void luminance ( float & l ) const { l * = _scale ; }
inline void alpha ( float & a ) const { a * = _scale ; }
inline void luminance_alpha ( float & l , float & a ) const { l * = _scale ; a * = _scale ; }
2005-02-01 04:09:24 +08:00
inline void rgb ( float & r , float & g , float & b ) const { r * = _scale ; g * = _scale ; b * = _scale ; }
inline void rgba ( float & r , float & g , float & b , float & a ) const { r * = _scale ; g * = _scale ; b * = _scale ; a * = _scale ; }
} ;
2013-11-06 17:23:21 +08:00
struct RecordRowOperator : public osg : : CastAndScaleToFloatOperation
2005-02-01 17:02:01 +08:00
{
RecordRowOperator ( unsigned int num ) : _colours ( num ) , _pos ( 0 ) { }
mutable std : : vector < osg : : Vec4 > _colours ;
mutable unsigned int _pos ;
2009-09-01 18:48:32 +08:00
inline void luminance ( float l ) const { rgba ( l , l , l , 1.0f ) ; }
inline void alpha ( float a ) const { rgba ( 1.0f , 1.0f , 1.0f , a ) ; }
inline void luminance_alpha ( float l , float a ) const { rgba ( l , l , l , a ) ; }
2005-02-01 17:02:01 +08:00
inline void rgb ( float r , float g , float b ) const { rgba ( r , g , b , 1.0f ) ; }
inline void rgba ( float r , float g , float b , float a ) const { _colours [ _pos + + ] . set ( r , g , b , a ) ; }
} ;
struct WriteRowOperator
{
WriteRowOperator ( ) : _pos ( 0 ) { }
WriteRowOperator ( unsigned int num ) : _colours ( num ) , _pos ( 0 ) { }
std : : vector < osg : : Vec4 > _colours ;
mutable unsigned int _pos ;
2009-09-01 18:48:32 +08:00
inline void luminance ( float & l ) const { l = _colours [ _pos + + ] . r ( ) ; }
inline void alpha ( float & a ) const { a = _colours [ _pos + + ] . a ( ) ; }
inline void luminance_alpha ( float & l , float & a ) const { l = _colours [ _pos ] . r ( ) ; a = _colours [ _pos + + ] . a ( ) ; }
2005-09-04 04:56:25 +08:00
inline void rgb ( float & r , float & g , float & b ) const { r = _colours [ _pos ] . r ( ) ; g = _colours [ _pos ] . g ( ) ; b = _colours [ _pos ] . b ( ) ; }
inline void rgba ( float & r , float & g , float & b , float & a ) const { r = _colours [ _pos ] . r ( ) ; g = _colours [ _pos ] . g ( ) ; b = _colours [ _pos ] . b ( ) ; a = _colours [ _pos + + ] . a ( ) ; }
2005-02-01 17:02:01 +08:00
} ;
2011-06-09 01:45:24 +08:00
void clampToNearestValidPowerOfTwo ( int & sizeX , int & sizeY , int & sizeZ , int s_maximumTextureSize , int t_maximumTextureSize , int r_maximumTextureSize )
{
// compute nearest powers of two for each axis.
int s_nearestPowerOfTwo = 1 ;
while ( s_nearestPowerOfTwo < sizeX & & s_nearestPowerOfTwo < s_maximumTextureSize ) s_nearestPowerOfTwo * = 2 ;
int t_nearestPowerOfTwo = 1 ;
while ( t_nearestPowerOfTwo < sizeY & & t_nearestPowerOfTwo < t_maximumTextureSize ) t_nearestPowerOfTwo * = 2 ;
int r_nearestPowerOfTwo = 1 ;
while ( r_nearestPowerOfTwo < sizeZ & & r_nearestPowerOfTwo < r_maximumTextureSize ) r_nearestPowerOfTwo * = 2 ;
sizeX = s_nearestPowerOfTwo ;
sizeY = t_nearestPowerOfTwo ;
sizeZ = r_nearestPowerOfTwo ;
}
2005-02-01 04:09:24 +08:00
osg : : Image * readRaw ( int sizeX , int sizeY , int sizeZ , int numberBytesPerComponent , int numberOfComponents , const std : : string & endian , const std : : string & raw_filename )
{
2008-11-07 23:08:08 +08:00
osgDB : : ifstream fin ( raw_filename . c_str ( ) , std : : ifstream : : binary ) ;
2005-02-01 04:09:24 +08:00
if ( ! fin ) return 0 ;
GLenum pixelFormat ;
switch ( numberOfComponents )
{
case 1 : pixelFormat = GL_LUMINANCE ; break ;
case 2 : pixelFormat = GL_LUMINANCE_ALPHA ; break ;
case 3 : pixelFormat = GL_RGB ; break ;
case 4 : pixelFormat = GL_RGBA ; break ;
default :
osg : : notify ( osg : : NOTICE ) < < " Error: numberOfComponents= " < < numberOfComponents < < " not supported, only 1,2,3 or 4 are supported. " < < std : : endl ;
return 0 ;
}
2009-09-01 18:48:32 +08:00
2005-02-01 04:09:24 +08:00
GLenum dataType ;
switch ( numberBytesPerComponent )
{
case 1 : dataType = GL_UNSIGNED_BYTE ; break ;
case 2 : dataType = GL_UNSIGNED_SHORT ; break ;
case 4 : dataType = GL_UNSIGNED_INT ; break ;
2009-09-01 18:48:32 +08:00
default :
2005-02-01 04:09:24 +08:00
osg : : notify ( osg : : NOTICE ) < < " Error: numberBytesPerComponent= " < < numberBytesPerComponent < < " not supported, only 1,2 or 4 are supported. " < < std : : endl ;
return 0 ;
}
2009-09-01 18:48:32 +08:00
2005-02-01 04:09:24 +08:00
int s_maximumTextureSize = 256 , t_maximumTextureSize = 256 , r_maximumTextureSize = 256 ;
2009-09-01 18:48:32 +08:00
2005-02-01 04:09:24 +08:00
int sizeS = sizeX ;
int sizeT = sizeY ;
int sizeR = sizeZ ;
clampToNearestValidPowerOfTwo ( sizeS , sizeT , sizeR , s_maximumTextureSize , t_maximumTextureSize , r_maximumTextureSize ) ;
osg : : ref_ptr < osg : : Image > image = new osg : : Image ;
image - > allocateImage ( sizeS , sizeT , sizeR , pixelFormat , dataType ) ;
2009-09-01 18:48:32 +08:00
2005-02-02 06:36:05 +08:00
bool endianSwap = ( osg : : getCpuByteOrder ( ) = = osg : : BigEndian ) ? ( endian ! = " big " ) : ( endian = = " big " ) ;
2009-09-01 18:48:32 +08:00
2005-02-01 04:09:24 +08:00
unsigned int r_offset = ( sizeZ < sizeR ) ? sizeR / 2 - sizeZ / 2 : 0 ;
2009-09-01 18:48:32 +08:00
2005-02-01 04:09:24 +08:00
int offset = endianSwap ? numberBytesPerComponent : 0 ;
int delta = endianSwap ? - 1 : 1 ;
for ( int r = 0 ; r < sizeZ ; + + r )
{
for ( int t = 0 ; t < sizeY ; + + t )
{
char * data = ( char * ) image - > data ( 0 , t , r + r_offset ) ;
for ( int s = 0 ; s < sizeX ; + + s )
{
if ( ! fin ) return 0 ;
2009-09-01 18:48:32 +08:00
2005-02-01 04:09:24 +08:00
for ( int c = 0 ; c < numberOfComponents ; + + c )
{
char * ptr = data + offset ;
for ( int b = 0 ; b < numberBytesPerComponent ; + + b )
{
fin . read ( ( char * ) ptr , 1 ) ;
ptr + = delta ;
}
data + = numberBytesPerComponent ;
}
}
}
}
2005-02-01 17:38:07 +08:00
// normalise texture
2005-02-01 04:09:24 +08:00
{
2005-02-01 17:38:07 +08:00
// compute range of values
2008-09-16 23:32:23 +08:00
osg : : Vec4 minValue , maxValue ;
2009-01-09 23:19:25 +08:00
osg : : computeMinMax ( image . get ( ) , minValue , maxValue ) ;
2009-09-01 18:48:32 +08:00
osg : : modifyImage ( image . get ( ) , ScaleOperator ( 1.0f / maxValue . r ( ) ) ) ;
2005-02-01 04:09:24 +08:00
}
2009-09-01 18:48:32 +08:00
2005-02-01 04:09:24 +08:00
fin . close ( ) ;
2005-02-01 17:02:01 +08:00
if ( dataType ! = GL_UNSIGNED_BYTE )
{
// need to convert to ubyte
2009-09-01 18:48:32 +08:00
2005-02-01 17:38:07 +08:00
osg : : ref_ptr < osg : : Image > new_image = new osg : : Image ;
new_image - > allocateImage ( sizeS , sizeT , sizeR , pixelFormat , GL_UNSIGNED_BYTE ) ;
2009-09-01 18:48:32 +08:00
2005-02-01 17:38:07 +08:00
RecordRowOperator readOp ( sizeS ) ;
WriteRowOperator writeOp ;
for ( int r = 0 ; r < sizeR ; + + r )
{
for ( int t = 0 ; t < sizeT ; + + t )
{
2007-12-11 01:30:18 +08:00
// reset the indices to beginning
2005-02-01 17:38:07 +08:00
readOp . _pos = 0 ;
writeOp . _pos = 0 ;
2009-09-01 18:48:32 +08:00
2005-02-01 17:38:07 +08:00
// read the pixels into readOp's _colour array
2009-01-09 23:19:25 +08:00
osg : : readRow ( sizeS , pixelFormat , dataType , image - > data ( 0 , t , r ) , readOp ) ;
2009-09-01 18:48:32 +08:00
2005-02-01 17:38:07 +08:00
// pass readOp's _colour array contents over to writeOp (note this is just a pointer swap).
writeOp . _colours . swap ( readOp . _colours ) ;
2009-09-01 18:48:32 +08:00
2009-01-09 23:19:25 +08:00
osg : : modifyRow ( sizeS , pixelFormat , GL_UNSIGNED_BYTE , new_image - > data ( 0 , t , r ) , writeOp ) ;
2005-02-01 17:38:07 +08:00
// return readOp's _colour array contents back to its rightful owner.
writeOp . _colours . swap ( readOp . _colours ) ;
}
}
2009-09-01 18:48:32 +08:00
2005-02-01 17:38:07 +08:00
image = new_image ;
2005-02-01 17:02:01 +08:00
}
2009-09-01 18:48:32 +08:00
2005-02-01 04:09:24 +08:00
return image . release ( ) ;
2009-09-01 18:48:32 +08:00
2005-02-01 04:09:24 +08:00
}
2004-06-29 21:59:07 +08:00
2008-08-25 19:37:53 +08:00
class TestSupportOperation : public osg : : GraphicsOperation
{
public :
TestSupportOperation ( ) :
2015-07-23 23:46:39 +08:00
osg : : Referenced ( true ) ,
2008-08-25 19:37:53 +08:00
osg : : GraphicsOperation ( " TestSupportOperation " , false ) ,
supported ( true ) ,
errorMessage ( ) ,
maximumTextureSize ( 256 ) { }
virtual void operator ( ) ( osg : : GraphicsContext * gc )
{
OpenThreads : : ScopedLock < OpenThreads : : Mutex > lock ( mutex ) ;
glGetIntegerv ( GL_MAX_3D_TEXTURE_SIZE , & maximumTextureSize ) ;
2009-09-01 18:48:32 +08:00
2008-08-25 19:37:53 +08:00
osg : : notify ( osg : : NOTICE ) < < " Max texture size= " < < maximumTextureSize < < std : : endl ;
}
2009-09-01 18:48:32 +08:00
2008-08-25 19:37:53 +08:00
OpenThreads : : Mutex mutex ;
bool supported ;
std : : string errorMessage ;
GLint maximumTextureSize ;
} ;
2009-07-03 02:50:45 +08:00
class DraggerVolumeTileCallback : public osgManipulator : : DraggerCallback
{
public :
DraggerVolumeTileCallback ( osgVolume : : VolumeTile * volume , osgVolume : : Locator * locator ) :
_volume ( volume ) ,
_locator ( locator ) { }
virtual bool receive ( const osgManipulator : : MotionCommand & command ) ;
osg : : observer_ptr < osgVolume : : VolumeTile > _volume ;
osg : : ref_ptr < osgVolume : : Locator > _locator ;
osg : : Matrix _startMotionMatrix ;
osg : : Matrix _localToWorld ;
osg : : Matrix _worldToLocal ;
} ;
bool DraggerVolumeTileCallback : : receive ( const osgManipulator : : MotionCommand & command )
{
if ( ! _locator ) return false ;
switch ( command . getStage ( ) )
{
case osgManipulator : : MotionCommand : : START :
{
// Save the current matrix
_startMotionMatrix = _locator - > getTransform ( ) ;
// Get the LocalToWorld and WorldToLocal matrix for this node.
osg : : NodePath nodePathToRoot ;
osgManipulator : : computeNodePathToRoot ( * _volume , nodePathToRoot ) ;
_localToWorld = _startMotionMatrix * osg : : computeLocalToWorld ( nodePathToRoot ) ;
_worldToLocal = osg : : Matrix : : inverse ( _localToWorld ) ;
return true ;
}
case osgManipulator : : MotionCommand : : MOVE :
{
// Transform the command's motion matrix into local motion matrix.
osg : : Matrix localMotionMatrix = _localToWorld * command . getWorldToLocal ( )
* command . getMotionMatrix ( )
* command . getLocalToWorld ( ) * _worldToLocal ;
// Transform by the localMotionMatrix
_locator - > setTransform ( localMotionMatrix * _startMotionMatrix ) ;
2008-08-25 19:37:53 +08:00
2009-07-03 02:50:45 +08:00
// osg::notify(osg::NOTICE)<<"New locator matrix "<<_locator->getTransform()<<std::endl;
return true ;
}
case osgManipulator : : MotionCommand : : FINISH :
{
return true ;
}
case osgManipulator : : MotionCommand : : NONE :
default :
return false ;
}
}
2008-08-25 19:37:53 +08:00
2005-02-02 06:36:05 +08:00
int main ( int argc , char * * argv )
{
2004-06-29 21:59:07 +08:00
// use an ArgumentParser object to manage the program arguments.
osg : : ArgumentParser arguments ( & argc , argv ) ;
2009-09-01 18:48:32 +08:00
2004-06-29 21:59:07 +08:00
// set up the usage document, in case we need to print out how to use this program.
arguments . getApplicationUsage ( ) - > setDescription ( arguments . getApplicationName ( ) + " is the example which demonstrates use of 3D textures. " ) ;
arguments . getApplicationUsage ( ) - > setCommandLineUsage ( arguments . getApplicationName ( ) + " [options] filename ... " ) ;
arguments . getApplicationUsage ( ) - > addCommandLineOption ( " -h or --help " , " Display this information " ) ;
2006-07-18 23:11:41 +08:00
arguments . getApplicationUsage ( ) - > addCommandLineOption ( " --images [filenames] " , " Specify a stack of 2d images to build the 3d volume from. " ) ;
2008-09-28 23:16:13 +08:00
arguments . getApplicationUsage ( ) - > addCommandLineOption ( " --shader " , " Use OpenGL Shading Language. (default) " ) ;
2013-11-22 02:17:44 +08:00
arguments . getApplicationUsage ( ) - > addCommandLineOption ( " --multi-pass " , " Use MultipassTechnique to render volumes. " ) ;
arguments . getApplicationUsage ( ) - > addCommandLineOption ( " --model " , " load 3D model and insert into the scene along with the volume. " ) ;
arguments . getApplicationUsage ( ) - > addCommandLineOption ( " --hull " , " load 3D hull that defines the extents of the region to volume render. " ) ;
2008-09-28 23:16:13 +08:00
arguments . getApplicationUsage ( ) - > addCommandLineOption ( " --no-shader " , " Disable use of OpenGL Shading Language. " ) ;
arguments . getApplicationUsage ( ) - > addCommandLineOption ( " --gpu-tf " , " Aply the transfer function on the GPU. (default) " ) ;
arguments . getApplicationUsage ( ) - > addCommandLineOption ( " --cpu-tf " , " Apply the transfer function on the CPU. " ) ;
2008-08-18 23:08:04 +08:00
arguments . getApplicationUsage ( ) - > addCommandLineOption ( " --mip " , " Use Maximum Intensity Projection (MIP) filtering. " ) ;
2011-02-23 19:28:43 +08:00
arguments . getApplicationUsage ( ) - > addCommandLineOption ( " --isosurface " , " Use Iso surface render. " ) ;
arguments . getApplicationUsage ( ) - > addCommandLineOption ( " --light " , " Use normals computed on the GPU to render a lit volume. " ) ;
arguments . getApplicationUsage ( ) - > addCommandLineOption ( " -n " , " Use normals computed on the GPU to render a lit volume. " ) ;
2005-02-01 04:09:24 +08:00
arguments . getApplicationUsage ( ) - > addCommandLineOption ( " --xSize <size> " , " Relative width of rendered brick. " ) ;
arguments . getApplicationUsage ( ) - > addCommandLineOption ( " --ySize <size> " , " Relative length of rendered brick. " ) ;
arguments . getApplicationUsage ( ) - > addCommandLineOption ( " --zSize <size> " , " Relative height of rendered brick. " ) ;
arguments . getApplicationUsage ( ) - > addCommandLineOption ( " --maxTextureSize <size> " , " Set the texture maximum resolution in the s,t,r (x,y,z) dimensions. " ) ;
arguments . getApplicationUsage ( ) - > addCommandLineOption ( " --s_maxTextureSize <size> " , " Set the texture maximum resolution in the s (x) dimension. " ) ;
arguments . getApplicationUsage ( ) - > addCommandLineOption ( " --t_maxTextureSize <size> " , " Set the texture maximum resolution in the t (y) dimension. " ) ;
arguments . getApplicationUsage ( ) - > addCommandLineOption ( " --r_maxTextureSize <size> " , " Set the texture maximum resolution in the r (z) dimension. " ) ;
2008-11-05 23:59:48 +08:00
arguments . getApplicationUsage ( ) - > addCommandLineOption ( " --modulate-alpha-by-luminance " , " For each pixel multiply the alpha value by the luminance. " ) ;
arguments . getApplicationUsage ( ) - > addCommandLineOption ( " --replace-alpha-with-luminance " , " For each pixel set the alpha value to the luminance. " ) ;
arguments . getApplicationUsage ( ) - > addCommandLineOption ( " --replace-rgb-with-luminance " , " For each rgb pixel convert to the luminance. " ) ;
2005-08-26 21:26:02 +08:00
arguments . getApplicationUsage ( ) - > addCommandLineOption ( " --num-components <num> " , " Set the number of components to in he target image. " ) ;
2008-11-05 23:59:48 +08:00
arguments . getApplicationUsage ( ) - > addCommandLineOption ( " --no-rescale " , " Disable the rescaling of the pixel data to 0.0 to 1.0 range " ) ;
arguments . getApplicationUsage ( ) - > addCommandLineOption ( " --rescale " , " Enable the rescale of the pixel data to 0.0 to 1.0 range (default). " ) ;
arguments . getApplicationUsage ( ) - > addCommandLineOption ( " --shift-min-to-zero " , " Shift the pixel data so min value is 0.0. " ) ;
2009-02-11 02:51:43 +08:00
arguments . getApplicationUsage ( ) - > addCommandLineOption ( " --sequence-length <num> " , " Set the length of time that a sequence of images with run for. " ) ;
arguments . getApplicationUsage ( ) - > addCommandLineOption ( " --sd <num> " , " Short hand for --sequence-length " ) ;
2011-06-09 18:48:19 +08:00
arguments . getApplicationUsage ( ) - > addCommandLineOption ( " --sdwm <num> " , " Set the SampleDensityWhenMovingProperty to specified value " ) ;
arguments . getApplicationUsage ( ) - > addCommandLineOption ( " --lod " , " Enable techniques to reduce the level of detail when moving. " ) ;
2005-02-01 04:09:24 +08:00
// arguments.getApplicationUsage()->addCommandLineOption("--raw <sizeX> <sizeY> <sizeZ> <numberBytesPerComponent> <numberOfComponents> <endian> <filename>","read a raw image data");
2004-06-29 21:59:07 +08:00
// construct the viewer.
2008-08-25 17:53:24 +08:00
osgViewer : : Viewer viewer ( arguments ) ;
2004-06-29 21:59:07 +08:00
2008-08-27 01:40:04 +08:00
// add the window size toggle handler
viewer . addEventHandler ( new osgViewer : : WindowSizeHandler ) ;
2009-09-01 18:48:32 +08:00
2008-09-29 18:56:42 +08:00
{
osg : : ref_ptr < osgGA : : KeySwitchMatrixManipulator > keyswitchManipulator = new osgGA : : KeySwitchMatrixManipulator ;
keyswitchManipulator - > addMatrixManipulator ( ' 1 ' , " Trackball " , new osgGA : : TrackballManipulator ( ) ) ;
2009-09-01 18:48:32 +08:00
2008-09-30 02:30:17 +08:00
osgGA : : FlightManipulator * flightManipulator = new osgGA : : FlightManipulator ( ) ;
flightManipulator - > setYawControlMode ( osgGA : : FlightManipulator : : NO_AUTOMATIC_YAW ) ;
keyswitchManipulator - > addMatrixManipulator ( ' 2 ' , " Flight " , flightManipulator ) ;
2008-09-29 18:56:42 +08:00
viewer . setCameraManipulator ( keyswitchManipulator . get ( ) ) ;
}
2008-08-27 01:40:04 +08:00
// add the stats handler
viewer . addEventHandler ( new osgViewer : : StatsHandler ) ;
2013-11-26 01:36:17 +08:00
// add stateset manipulator
viewer . addEventHandler ( new osgGA : : StateSetManipulator ( viewer . getCamera ( ) - > getOrCreateStateSet ( ) ) ) ;
2008-08-25 18:38:39 +08:00
viewer . getCamera ( ) - > setClearColor ( osg : : Vec4 ( 0.0f , 0.0f , 0.0f , 0.0f ) ) ;
2004-06-29 21:59:07 +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 ;
}
std : : string outputFile ;
while ( arguments . read ( " -o " , outputFile ) ) { }
2008-09-12 23:41:30 +08:00
osg : : ref_ptr < osg : : TransferFunction1D > transferFunction ;
std : : string tranferFunctionFile ;
while ( arguments . read ( " --tf " , tranferFunctionFile ) )
{
2015-10-22 22:14:53 +08:00
transferFunction = osgDB : : readRefFile < osg : : TransferFunction1D > ( tranferFunctionFile ) ;
2011-06-03 23:58:36 +08:00
}
2009-09-01 18:48:32 +08:00
2009-02-02 22:43:27 +08:00
while ( arguments . read ( " --test " ) )
{
transferFunction = new osg : : TransferFunction1D ;
transferFunction - > setColor ( 0.0 , osg : : Vec4 ( 1.0 , 0.0 , 0.0 , 0.0 ) ) ;
transferFunction - > setColor ( 0.5 , osg : : Vec4 ( 1.0 , 1.0 , 0.0 , 0.5 ) ) ;
transferFunction - > setColor ( 1.0 , osg : : Vec4 ( 0.0 , 0.0 , 1.0 , 1.0 ) ) ;
}
while ( arguments . read ( " --test2 " ) )
{
transferFunction = new osg : : TransferFunction1D ;
transferFunction - > setColor ( 0.0 , osg : : Vec4 ( 1.0 , 0.0 , 0.0 , 0.0 ) ) ;
transferFunction - > setColor ( 0.5 , osg : : Vec4 ( 1.0 , 1.0 , 0.0 , 0.5 ) ) ;
transferFunction - > setColor ( 1.0 , osg : : Vec4 ( 0.0 , 0.0 , 1.0 , 1.0 ) ) ;
transferFunction - > assign ( transferFunction - > getColorMap ( ) ) ;
}
2008-09-12 23:41:30 +08:00
2011-02-23 19:43:30 +08:00
{
// deprecated options
bool invalidOption = false ;
unsigned int numSlices = 500 ;
while ( arguments . read ( " -s " , numSlices ) ) { OSG_NOTICE < < " Warning: -s option no longer supported. " < < std : : endl ; invalidOption = true ; }
float sliceEnd = 1.0f ;
while ( arguments . read ( " --clip " , sliceEnd ) ) { OSG_NOTICE < < " Warning: --clip option no longer supported. " < < std : : endl ; invalidOption = true ; }
if ( invalidOption ) return 1 ;
}
2009-09-01 18:48:32 +08:00
2011-02-23 20:48:17 +08:00
float xMultiplier = 1.0f ;
while ( arguments . read ( " --xMultiplier " , xMultiplier ) ) { }
float yMultiplier = 1.0f ;
while ( arguments . read ( " --yMultiplier " , yMultiplier ) ) { }
float zMultiplier = 1.0f ;
while ( arguments . read ( " --zMultiplier " , zMultiplier ) ) { }
2004-07-12 00:38:16 +08:00
2004-09-03 23:42:43 +08:00
float alphaFunc = 0.02f ;
while ( arguments . read ( " --alphaFunc " , alphaFunc ) ) { }
2004-07-12 00:38:16 +08:00
2009-09-01 18:48:32 +08:00
2008-09-26 19:29:00 +08:00
ShadingModel shadingModel = Standard ;
while ( arguments . read ( " --mip " ) ) shadingModel = MaximumIntensityProjection ;
2011-02-23 19:28:43 +08:00
while ( arguments . read ( " --isosurface " ) | | arguments . read ( " --iso-surface " ) ) shadingModel = Isosurface ;
2009-01-21 01:41:45 +08:00
2011-02-23 19:28:43 +08:00
while ( arguments . read ( " --light " ) | | arguments . read ( " -n " ) ) shadingModel = Light ;
2004-07-12 00:38:16 +08:00
2009-02-19 22:24:10 +08:00
float xSize = 0.0f , ySize = 0.0f , zSize = 0.0f ;
2004-09-04 17:22:26 +08:00
while ( arguments . read ( " --xSize " , xSize ) ) { }
while ( arguments . read ( " --ySize " , ySize ) ) { }
while ( arguments . read ( " --zSize " , zSize ) ) { }
2008-08-25 19:37:53 +08:00
osg : : ref_ptr < TestSupportOperation > testSupportOperation = new TestSupportOperation ;
viewer . setRealizeOperation ( testSupportOperation . get ( ) ) ;
2009-09-01 18:48:32 +08:00
2008-08-25 19:37:53 +08:00
viewer . realize ( ) ;
int maximumTextureSize = testSupportOperation - > maximumTextureSize ;
2008-09-12 23:41:30 +08:00
int s_maximumTextureSize = maximumTextureSize ;
int t_maximumTextureSize = maximumTextureSize ;
int r_maximumTextureSize = maximumTextureSize ;
2004-09-04 17:22:26 +08:00
while ( arguments . read ( " --maxTextureSize " , maximumTextureSize ) )
{
s_maximumTextureSize = maximumTextureSize ;
t_maximumTextureSize = maximumTextureSize ;
r_maximumTextureSize = maximumTextureSize ;
}
while ( arguments . read ( " --s_maxTextureSize " , s_maximumTextureSize ) ) { }
while ( arguments . read ( " --t_maxTextureSize " , t_maximumTextureSize ) ) { }
while ( arguments . read ( " --r_maxTextureSize " , r_maximumTextureSize ) ) { }
2004-09-03 23:42:43 +08:00
2005-02-02 06:36:05 +08:00
// set up colour space operation.
2012-11-13 21:32:01 +08:00
osg : : ColorSpaceOperation colourSpaceOperation = osg : : NO_COLOR_SPACE_OPERATION ;
2005-02-02 06:36:05 +08:00
osg : : Vec4 colourModulate ( 0.25f , 0.25f , 0.25f , 0.25f ) ;
2012-11-13 21:16:10 +08:00
while ( arguments . read ( " --modulate-alpha-by-luminance " ) ) { colourSpaceOperation = osg : : MODULATE_ALPHA_BY_LUMINANCE ; }
2012-11-13 21:32:01 +08:00
while ( arguments . read ( " --modulate-alpha-by-colour " , colourModulate . x ( ) , colourModulate . y ( ) , colourModulate . z ( ) , colourModulate . w ( ) ) ) { colourSpaceOperation = osg : : MODULATE_ALPHA_BY_COLOR ; }
2012-11-13 21:16:10 +08:00
while ( arguments . read ( " --replace-alpha-with-luminance " ) ) { colourSpaceOperation = osg : : REPLACE_ALPHA_WITH_LUMINANCE ; }
while ( arguments . read ( " --replace-rgb-with-luminance " ) ) { colourSpaceOperation = osg : : REPLACE_RGB_WITH_LUMINANCE ; }
2008-11-05 23:59:48 +08:00
enum RescaleOperation
{
NO_RESCALE ,
RESCALE_TO_ZERO_TO_ONE_RANGE ,
SHIFT_MIN_TO_ZERO
} ;
2009-09-01 18:48:32 +08:00
2008-11-05 23:59:48 +08:00
RescaleOperation rescaleOperation = RESCALE_TO_ZERO_TO_ONE_RANGE ;
while ( arguments . read ( " --no-rescale " ) ) rescaleOperation = NO_RESCALE ;
while ( arguments . read ( " --rescale " ) ) rescaleOperation = RESCALE_TO_ZERO_TO_ONE_RANGE ;
while ( arguments . read ( " --shift-min-to-zero " ) ) rescaleOperation = SHIFT_MIN_TO_ZERO ;
2009-09-01 18:48:32 +08:00
2008-09-12 23:41:30 +08:00
bool resizeToPowerOfTwo = false ;
2009-09-01 18:48:32 +08:00
unsigned int numComponentsDesired = 0 ;
2005-08-26 21:26:02 +08:00
while ( arguments . read ( " --num-components " , numComponentsDesired ) ) { }
2009-07-03 02:50:45 +08:00
bool useManipulator = false ;
while ( arguments . read ( " --manipulator " ) | | arguments . read ( " -m " ) ) { useManipulator = true ; }
2009-09-01 18:48:32 +08:00
bool useShader = true ;
2005-09-05 15:48:55 +08:00
while ( arguments . read ( " --shader " ) ) { useShader = true ; }
2009-01-16 19:27:20 +08:00
while ( arguments . read ( " --no-shader " ) ) { useShader = false ; }
2005-08-26 21:26:02 +08:00
2013-11-22 02:17:44 +08:00
bool useMultipass = false ;
while ( arguments . read ( " --multi-pass " ) ) useMultipass = true ;
std : : string filename ;
osg : : ref_ptr < osg : : Group > models ;
while ( arguments . read ( " --model " , filename ) )
{
2015-10-22 22:14:53 +08:00
osg : : ref_ptr < osg : : Node > model = osgDB : : readRefNodeFile ( filename ) ;
2013-11-22 02:17:44 +08:00
if ( model . valid ( ) )
{
if ( ! models ) models = new osg : : Group ;
models - > addChild ( model . get ( ) ) ;
}
}
osg : : ref_ptr < osg : : Group > hulls ;
while ( arguments . read ( " --hull " , filename ) )
{
2015-10-22 22:14:53 +08:00
osg : : ref_ptr < osg : : Node > hull = osgDB : : readRefNodeFile ( filename ) ;
2013-11-22 02:17:44 +08:00
if ( hull . valid ( ) )
{
if ( ! hulls ) hulls = new osg : : Group ;
hulls - > addChild ( hull . get ( ) ) ;
}
}
2009-09-01 18:48:32 +08:00
bool gpuTransferFunction = true ;
2008-09-24 18:45:15 +08:00
while ( arguments . read ( " --gpu-tf " ) ) { gpuTransferFunction = true ; }
2008-09-28 23:16:13 +08:00
while ( arguments . read ( " --cpu-tf " ) ) { gpuTransferFunction = false ; }
2008-09-24 18:45:15 +08:00
2011-06-09 18:48:19 +08:00
double sampleDensityWhenMoving = 0.0 ;
while ( arguments . read ( " --sdwm " , sampleDensityWhenMoving ) ) { }
2013-12-12 17:53:24 +08:00
double sampleRatioWhenMoving = 0.0 ;
while ( arguments . read ( " --srwm " , sampleRatioWhenMoving ) ) { }
2011-06-09 18:48:19 +08:00
while ( arguments . read ( " --lod " ) ) { sampleDensityWhenMoving = 0.02 ; }
2009-02-11 02:51:43 +08:00
double sequenceLength = 10.0 ;
2009-09-01 18:48:32 +08:00
while ( arguments . read ( " --sequence-duration " , sequenceLength ) | |
2011-06-09 18:48:19 +08:00
arguments . read ( " --sd " , sequenceLength ) ) { }
2009-02-11 02:51:43 +08:00
2008-09-29 18:56:42 +08:00
typedef std : : list < osg : : ref_ptr < osg : : Image > > Images ;
Images images ;
2008-09-23 01:24:26 +08:00
std : : string vh_filename ;
2009-09-01 18:48:32 +08:00
while ( arguments . read ( " --vh " , vh_filename ) )
2008-09-23 01:24:26 +08:00
{
std : : string raw_filename , transfer_filename ;
2009-09-01 18:48:32 +08:00
int xdim ( 0 ) , ydim ( 0 ) , zdim ( 0 ) ;
2008-09-23 01:24:26 +08:00
2008-11-07 23:08:08 +08:00
osgDB : : ifstream header ( vh_filename . c_str ( ) ) ;
2008-09-23 01:24:26 +08:00
if ( header )
{
header > > raw_filename > > transfer_filename > > xdim > > ydim > > zdim > > xSize > > ySize > > zSize ;
}
2009-09-01 18:48:32 +08:00
2008-09-23 01:24:26 +08:00
if ( xdim * ydim * zdim = = 0 )
{
std : : cout < < " Error in reading volume header " < < vh_filename < < std : : endl ;
return 1 ;
}
2009-09-01 18:48:32 +08:00
2008-09-23 01:24:26 +08:00
if ( ! raw_filename . empty ( ) )
{
2008-09-29 18:56:42 +08:00
images . push_back ( readRaw ( xdim , ydim , zdim , 1 , 1 , " little " , raw_filename ) ) ;
2008-09-23 01:24:26 +08:00
}
2009-09-01 18:48:32 +08:00
2008-09-23 01:24:26 +08:00
if ( ! transfer_filename . empty ( ) )
{
2008-11-07 23:08:08 +08:00
osgDB : : ifstream fin ( transfer_filename . c_str ( ) ) ;
2008-09-23 01:24:26 +08:00
if ( fin )
{
2009-02-02 22:43:27 +08:00
osg : : TransferFunction1D : : ColorMap colorMap ;
2008-09-23 01:24:26 +08:00
float value = 0.0 ;
2008-09-24 18:20:23 +08:00
while ( fin & & value < = 1.0 )
2008-09-23 01:24:26 +08:00
{
float red , green , blue , alpha ;
fin > > red > > green > > blue > > alpha ;
2009-09-01 18:48:32 +08:00
if ( fin )
2008-09-23 01:24:26 +08:00
{
2009-02-02 22:43:27 +08:00
colorMap [ value ] = osg : : Vec4 ( red / 255.0f , green / 255.0f , blue / 255.0f , alpha / 255.0f ) ;
2008-09-24 18:20:23 +08:00
std : : cout < < " value = " < < value < < " ( " < < red < < " , " < < green < < " , " < < blue < < " , " < < alpha < < " ) " ;
2009-02-02 22:43:27 +08:00
std : : cout < < " ( " < < colorMap [ value ] < < " ) " < < std : : endl ;
2008-09-23 01:24:26 +08:00
}
value + = 1 / 255.0 ;
}
2009-02-02 22:43:27 +08:00
if ( colorMap . empty ( ) )
2008-09-23 01:24:26 +08:00
{
std : : cout < < " Error: No values read from transfer function file: " < < transfer_filename < < std : : endl ;
return 0 ;
}
transferFunction = new osg : : TransferFunction1D ;
2009-02-02 22:43:27 +08:00
transferFunction - > assign ( colorMap ) ;
2008-09-23 01:24:26 +08:00
}
}
}
2009-09-01 18:48:32 +08:00
2005-02-01 04:09:24 +08:00
int sizeX , sizeY , sizeZ , numberBytesPerComponent , numberOfComponents ;
std : : string endian , raw_filename ;
2009-09-01 18:48:32 +08:00
while ( arguments . read ( " --raw " , sizeX , sizeY , sizeZ , numberBytesPerComponent , numberOfComponents , endian , raw_filename ) )
2005-02-01 04:09:24 +08:00
{
2008-09-29 18:56:42 +08:00
images . push_back ( readRaw ( sizeX , sizeY , sizeZ , numberBytesPerComponent , numberOfComponents , endian , raw_filename ) ) ;
2005-02-01 04:09:24 +08:00
}
2008-11-04 20:57:30 +08:00
int images_pos = arguments . find ( " --images " ) ;
if ( images_pos > = 0 )
2004-06-29 21:59:07 +08:00
{
2011-06-09 00:10:46 +08:00
osg : : ImageList imageList ;
2008-11-04 20:57:30 +08:00
int pos = images_pos + 1 ;
for ( ; pos < arguments . argc ( ) & & ! arguments . isOption ( pos ) ; + + pos )
2004-06-29 21:59:07 +08:00
{
2010-11-01 19:06:12 +08:00
std : : string arg ( arguments [ pos ] ) ;
if ( arg . find ( ' * ' ) ! = std : : string : : npos )
2004-06-29 21:59:07 +08:00
{
2010-11-01 19:06:12 +08:00
osgDB : : DirectoryContents contents = osgDB : : expandWildcardsInFilename ( arg ) ;
for ( unsigned int i = 0 ; i < contents . size ( ) ; + + i )
{
2015-10-22 22:14:53 +08:00
osg : : ref_ptr < osg : : Image > image = osgDB : : readRefImageFile ( contents [ i ] ) ;
2010-11-01 19:06:12 +08:00
if ( image )
{
2011-02-23 18:37:51 +08:00
OSG_NOTICE < < " Read osg::Image FileName:: " < < image - > getFileName ( ) < < " , pixelFormat=0x " < < std : : hex < < image - > getPixelFormat ( ) < < std : : dec < < " , s= " < < image - > s ( ) < < " , t= " < < image - > t ( ) < < " , r= " < < image - > r ( ) < < std : : endl ;
2010-11-01 19:06:12 +08:00
imageList . push_back ( image ) ;
}
}
}
else
{
// not an option so assume string is a filename.
2015-10-22 22:14:53 +08:00
osg : : ref_ptr < osg : : Image > image = osgDB : : readRefImageFile ( arguments [ pos ] ) ;
2010-11-01 19:06:12 +08:00
if ( image )
{
2011-02-23 18:37:51 +08:00
OSG_NOTICE < < " Read osg::Image FileName:: " < < image - > getFileName ( ) < < " , pixelFormat=0x " < < std : : hex < < image - > getPixelFormat ( ) < < std : : dec < < " , s= " < < image - > s ( ) < < " , t= " < < image - > t ( ) < < " , r= " < < image - > r ( ) < < std : : endl ;
2010-11-01 19:06:12 +08:00
imageList . push_back ( image ) ;
}
2004-06-29 21:59:07 +08:00
}
}
2009-09-01 18:48:32 +08:00
2008-11-04 20:57:30 +08:00
arguments . remove ( images_pos , pos - images_pos ) ;
2009-09-01 18:48:32 +08:00
2004-06-29 21:59:07 +08:00
// pack the textures into a single texture.
2011-06-09 00:10:46 +08:00
osg : : Image * image = createTexture3D ( imageList , numComponentsDesired , s_maximumTextureSize , t_maximumTextureSize , r_maximumTextureSize , resizeToPowerOfTwo ) ;
2011-02-23 18:37:51 +08:00
if ( image )
{
images . push_back ( image ) ;
}
2011-10-20 16:59:47 +08:00
else
{
OSG_NOTICE < < " Unable to create 3D image from source files. " < < std : : endl ;
}
2004-06-29 21:59:07 +08:00
}
// any option left unread are converted into errors to write out later.
arguments . reportRemainingOptionsAsUnrecognized ( ) ;
2007-12-11 01:30:18 +08:00
// report any errors if they have occurred when parsing the program arguments.
2004-06-29 21:59:07 +08:00
if ( arguments . errors ( ) )
{
arguments . writeErrorMessages ( std : : cout ) ;
return 1 ;
}
2009-09-01 18:48:32 +08:00
2004-06-29 21:59:07 +08:00
2007-12-11 01:30:18 +08:00
// assume remaining arguments are file names of textures.
2008-09-29 18:56:42 +08:00
for ( int pos = 1 ; pos < arguments . argc ( ) ; + + pos )
2004-06-29 21:59:07 +08:00
{
if ( ! arguments . isOption ( pos ) )
{
2008-09-13 21:38:06 +08:00
std : : string filename = arguments [ pos ] ;
2008-09-16 03:59:12 +08:00
if ( osgDB : : getLowerCaseFileExtension ( filename ) = = " dicom " )
2008-09-13 21:38:06 +08:00
{
2008-10-02 23:45:08 +08:00
// not an option so assume string is a filename.
2015-10-22 22:14:53 +08:00
osg : : ref_ptr < osg : : Image > image = osgDB : : readRefImageFile ( filename ) ;
2010-10-04 19:19:41 +08:00
if ( image )
2008-10-02 23:45:08 +08:00
{
images . push_back ( image ) ;
}
2008-09-13 21:38:06 +08:00
}
2008-09-16 03:59:12 +08:00
else
2008-09-13 21:38:06 +08:00
{
2008-09-16 03:59:12 +08:00
osgDB : : FileType fileType = osgDB : : fileType ( filename ) ;
if ( fileType = = osgDB : : FILE_NOT_FOUND )
2008-09-13 21:38:06 +08:00
{
2008-09-16 03:59:12 +08:00
filename = osgDB : : findDataFile ( filename ) ;
fileType = osgDB : : fileType ( filename ) ;
}
if ( fileType = = osgDB : : DIRECTORY )
{
2015-10-22 22:14:53 +08:00
osg : : ref_ptr < osg : : Image > image = osgDB : : readRefImageFile ( filename + " .dicom " ) ;
2010-10-04 19:19:41 +08:00
if ( image ) images . push_back ( image ) ;
2008-09-16 03:59:12 +08:00
}
else if ( fileType = = osgDB : : REGULAR_FILE )
{
// not an option so assume string is a filename.
2015-10-22 22:14:53 +08:00
osg : : ref_ptr < osg : : Image > image = osgDB : : readRefImageFile ( filename ) ;
2010-10-04 19:19:41 +08:00
if ( image ) images . push_back ( image ) ;
2008-09-16 03:59:12 +08:00
}
else
{
osg : : notify ( osg : : NOTICE ) < < " Error: could not find file: " < < filename < < std : : endl ;
return 1 ;
}
2009-09-01 18:48:32 +08:00
}
2004-06-29 21:59:07 +08:00
}
}
2009-09-01 18:48:32 +08:00
if ( images . empty ( ) )
2008-08-25 17:53:24 +08:00
{
2011-10-20 16:59:47 +08:00
std : : cout < < " No model loaded, please specify a volumetric image file on the command line. " < < std : : endl ;
2008-08-25 17:53:24 +08:00
return 1 ;
}
2008-09-16 23:32:23 +08:00
2008-09-29 18:56:42 +08:00
Images : : iterator sizeItr = images . begin ( ) ;
2009-02-19 22:24:10 +08:00
int image_s = ( * sizeItr ) - > s ( ) ;
int image_t = ( * sizeItr ) - > t ( ) ;
int image_r = ( * sizeItr ) - > r ( ) ;
2008-09-29 18:56:42 +08:00
+ + sizeItr ;
2008-09-30 02:30:17 +08:00
2008-09-29 18:56:42 +08:00
for ( ; sizeItr ! = images . end ( ) ; + + sizeItr )
{
2009-09-01 18:48:32 +08:00
if ( ( * sizeItr ) - > s ( ) ! = image_s | |
2009-02-19 22:24:10 +08:00
( * sizeItr ) - > t ( ) ! = image_t | |
( * sizeItr ) - > r ( ) ! = image_r )
2008-09-29 18:56:42 +08:00
{
std : : cout < < " Images in sequence are not of the same dimensions. " < < std : : endl ;
return 1 ;
}
}
2009-09-01 18:48:32 +08:00
osg : : ref_ptr < osgVolume : : ImageDetails > details = dynamic_cast < osgVolume : : ImageDetails * > ( images . front ( ) - > getUserData ( ) ) ;
osg : : ref_ptr < osg : : RefMatrix > matrix = details ? details - > getMatrix ( ) : dynamic_cast < osg : : RefMatrix * > ( images . front ( ) - > getUserData ( ) ) ;
2009-02-19 22:24:10 +08:00
if ( ! matrix )
{
if ( xSize = = 0.0 ) xSize = static_cast < float > ( image_s ) ;
if ( ySize = = 0.0 ) ySize = static_cast < float > ( image_t ) ;
if ( zSize = = 0.0 ) zSize = static_cast < float > ( image_r ) ;
2009-09-01 18:48:32 +08:00
2009-02-19 22:24:10 +08:00
matrix = new osg : : RefMatrix ( xSize , 0.0 , 0.0 , 0.0 ,
0.0 , ySize , 0.0 , 0.0 ,
0.0 , 0.0 , zSize , 0.0 ,
0.0 , 0.0 , 0.0 , 1.0 ) ;
}
2008-09-16 23:32:23 +08:00
2011-02-23 20:48:17 +08:00
if ( xMultiplier ! = 1.0 | | yMultiplier ! = 1.0 | | zMultiplier ! = 1.0 )
{
matrix - > postMultScale ( osg : : Vec3d ( fabs ( xMultiplier ) , fabs ( yMultiplier ) , fabs ( zMultiplier ) ) ) ;
}
2008-10-02 23:45:08 +08:00
osg : : Vec4 minValue ( FLT_MAX , FLT_MAX , FLT_MAX , FLT_MAX ) ;
osg : : Vec4 maxValue ( - FLT_MAX , - FLT_MAX , - FLT_MAX , - FLT_MAX ) ;
2008-09-29 18:56:42 +08:00
bool computeMinMax = false ;
for ( Images : : iterator itr = images . begin ( ) ;
itr ! = images . end ( ) ;
+ + itr )
{
2008-10-02 23:45:08 +08:00
osg : : Vec4 localMinValue , localMaxValue ;
2009-01-09 23:19:25 +08:00
if ( osg : : computeMinMax ( itr - > get ( ) , localMinValue , localMaxValue ) )
2008-09-30 02:30:17 +08:00
{
2008-10-02 23:45:08 +08:00
if ( localMinValue . r ( ) < minValue . r ( ) ) minValue . r ( ) = localMinValue . r ( ) ;
if ( localMinValue . g ( ) < minValue . g ( ) ) minValue . g ( ) = localMinValue . g ( ) ;
if ( localMinValue . b ( ) < minValue . b ( ) ) minValue . b ( ) = localMinValue . b ( ) ;
if ( localMinValue . a ( ) < minValue . a ( ) ) minValue . a ( ) = localMinValue . a ( ) ;
if ( localMaxValue . r ( ) > maxValue . r ( ) ) maxValue . r ( ) = localMaxValue . r ( ) ;
if ( localMaxValue . g ( ) > maxValue . g ( ) ) maxValue . g ( ) = localMaxValue . g ( ) ;
if ( localMaxValue . b ( ) > maxValue . b ( ) ) maxValue . b ( ) = localMaxValue . b ( ) ;
if ( localMaxValue . a ( ) > maxValue . a ( ) ) maxValue . a ( ) = localMaxValue . a ( ) ;
osg : : notify ( osg : : NOTICE ) < < " ( " < < localMinValue < < " ) ( " < < localMaxValue < < " ) " < < ( * itr ) - > getFileName ( ) < < std : : endl ;
computeMinMax = true ;
2008-09-30 02:30:17 +08:00
}
2008-09-29 18:56:42 +08:00
}
2009-09-01 18:48:32 +08:00
2008-09-29 18:56:42 +08:00
if ( computeMinMax )
2008-09-16 23:32:23 +08:00
{
osg : : notify ( osg : : NOTICE ) < < " Min value " < < minValue < < std : : endl ;
osg : : notify ( osg : : NOTICE ) < < " Max value " < < maxValue < < std : : endl ;
float minComponent = minValue [ 0 ] ;
minComponent = osg : : minimum ( minComponent , minValue [ 1 ] ) ;
minComponent = osg : : minimum ( minComponent , minValue [ 2 ] ) ;
minComponent = osg : : minimum ( minComponent , minValue [ 3 ] ) ;
float maxComponent = maxValue [ 0 ] ;
maxComponent = osg : : maximum ( maxComponent , maxValue [ 1 ] ) ;
maxComponent = osg : : maximum ( maxComponent , maxValue [ 2 ] ) ;
maxComponent = osg : : maximum ( maxComponent , maxValue [ 3 ] ) ;
2009-09-01 18:48:32 +08:00
#if 0
2008-11-05 23:59:48 +08:00
switch ( rescaleOperation )
{
case ( NO_RESCALE ) :
break ;
case ( RESCALE_TO_ZERO_TO_ONE_RANGE ) :
{
float scale = 0.99f / ( maxComponent - minComponent ) ;
float offset = - minComponent * scale ;
for ( Images : : iterator itr = images . begin ( ) ;
itr ! = images . end ( ) ;
+ + itr )
2009-09-01 18:48:32 +08:00
{
osg : : offsetAndScaleImage ( itr - > get ( ) ,
2008-11-05 23:59:48 +08:00
osg : : Vec4 ( offset , offset , offset , offset ) ,
osg : : Vec4 ( scale , scale , scale , scale ) ) ;
}
break ;
}
case ( SHIFT_MIN_TO_ZERO ) :
{
float offset = - minComponent ;
for ( Images : : iterator itr = images . begin ( ) ;
itr ! = images . end ( ) ;
+ + itr )
2009-09-01 18:48:32 +08:00
{
osg : : offsetAndScaleImage ( itr - > get ( ) ,
2008-11-05 23:59:48 +08:00
osg : : Vec4 ( offset , offset , offset , offset ) ,
osg : : Vec4 ( 1.0f , 1.0f , 1.0f , 1.0f ) ) ;
}
break ;
}
} ;
2009-09-01 18:48:32 +08:00
# endif
2008-09-16 23:32:23 +08:00
}
2009-09-01 18:48:32 +08:00
2012-11-13 21:32:01 +08:00
if ( colourSpaceOperation ! = osg : : NO_COLOR_SPACE_OPERATION )
2005-02-02 06:36:05 +08:00
{
2008-09-29 18:56:42 +08:00
for ( Images : : iterator itr = images . begin ( ) ;
itr ! = images . end ( ) ;
+ + itr )
2009-09-01 18:48:32 +08:00
{
2012-11-13 21:16:10 +08:00
( * itr ) = osg : : colorSpaceConversion ( colourSpaceOperation , itr - > get ( ) , colourModulate ) ;
2008-09-29 18:56:42 +08:00
}
2005-02-02 06:36:05 +08:00
}
2009-09-01 18:48:32 +08:00
2008-09-24 18:45:15 +08:00
if ( ! gpuTransferFunction & & transferFunction . valid ( ) )
2008-09-12 23:41:30 +08:00
{
2008-09-29 18:56:42 +08:00
for ( Images : : iterator itr = images . begin ( ) ;
itr ! = images . end ( ) ;
+ + itr )
2009-09-01 18:48:32 +08:00
{
2009-01-17 01:59:38 +08:00
* itr = osgVolume : : applyTransferFunction ( itr - > get ( ) , transferFunction . get ( ) ) ;
2008-09-29 18:56:42 +08:00
}
2008-09-12 23:41:30 +08:00
}
2009-09-01 18:48:32 +08:00
2008-09-29 18:56:42 +08:00
osg : : ref_ptr < osg : : Image > image_3d = 0 ;
2004-09-29 18:01:46 +08:00
2008-09-29 18:56:42 +08:00
if ( images . size ( ) = = 1 )
{
osg : : notify ( osg : : NOTICE ) < < " Single image " < < images . size ( ) < < " volumes. " < < std : : endl ;
image_3d = images . front ( ) ;
}
else
{
osg : : notify ( osg : : NOTICE ) < < " Creating sequence of " < < images . size ( ) < < " volumes. " < < std : : endl ;
2009-09-01 18:48:32 +08:00
2008-09-29 18:56:42 +08:00
osg : : ref_ptr < osg : : ImageSequence > imageSequence = new osg : : ImageSequence ;
2009-02-11 02:51:43 +08:00
imageSequence - > setLength ( sequenceLength ) ;
2008-09-29 18:56:42 +08:00
image_3d = imageSequence . get ( ) ;
for ( Images : : iterator itr = images . begin ( ) ;
itr ! = images . end ( ) ;
+ + itr )
2009-09-01 18:48:32 +08:00
{
2008-09-29 18:56:42 +08:00
imageSequence - > addImage ( itr - > get ( ) ) ;
}
imageSequence - > play ( ) ;
}
2009-09-01 18:48:32 +08:00
2009-01-21 20:06:13 +08:00
osg : : ref_ptr < osgVolume : : Volume > volume = new osgVolume : : Volume ;
osg : : ref_ptr < osgVolume : : VolumeTile > tile = new osgVolume : : VolumeTile ;
2009-01-22 03:01:26 +08:00
volume - > addChild ( tile . get ( ) ) ;
2009-01-21 20:06:13 +08:00
2009-09-01 18:48:32 +08:00
osg : : ref_ptr < osgVolume : : ImageLayer > layer = new osgVolume : : ImageLayer ( image_3d . get ( ) ) ;
if ( details )
{
2009-09-03 21:40:50 +08:00
layer - > setTexelOffset ( details - > getTexelOffset ( ) ) ;
layer - > setTexelScale ( details - > getTexelScale ( ) ) ;
2009-09-01 18:48:32 +08:00
}
switch ( rescaleOperation )
{
case ( NO_RESCALE ) :
break ;
case ( RESCALE_TO_ZERO_TO_ONE_RANGE ) :
{
layer - > rescaleToZeroToOneRange ( ) ;
break ;
}
case ( SHIFT_MIN_TO_ZERO ) :
{
layer - > translateMinToZero ( ) ;
break ;
}
} ;
2009-01-21 20:06:13 +08:00
2011-02-23 21:56:41 +08:00
if ( xMultiplier < 0.0 | | yMultiplier < 0.0 | | zMultiplier < 0.0 )
{
layer - > setLocator ( new osgVolume : : Locator (
osg : : Matrix : : translate ( xMultiplier < 0.0 ? - 1.0 : 0.0 , yMultiplier < 0.0 ? - 1.0 : 0.0 , zMultiplier < 0.0 ? - 1.0 : 0.0 ) *
osg : : Matrix : : scale ( xMultiplier < 0.0 ? - 1.0 : 1.0 , yMultiplier < 0.0 ? - 1.0 : 1.0 , zMultiplier < 0.0 ? - 1.0 : 1.0 ) *
( * matrix )
) ) ; ;
}
else
{
layer - > setLocator ( new osgVolume : : Locator ( * matrix ) ) ;
}
2009-07-03 02:50:45 +08:00
tile - > setLocator ( new osgVolume : : Locator ( * matrix ) ) ;
2009-01-09 23:19:25 +08:00
2009-01-21 20:06:13 +08:00
tile - > setLayer ( layer . get ( ) ) ;
2009-01-14 01:20:32 +08:00
2009-01-21 20:06:13 +08:00
tile - > setEventCallback ( new osgVolume : : PropertyAdjustmentCallback ( ) ) ;
2009-01-21 19:46:03 +08:00
2009-01-21 20:06:13 +08:00
if ( useShader )
{
2009-01-21 19:46:03 +08:00
osgVolume : : SwitchProperty * sp = new osgVolume : : SwitchProperty ;
sp - > setActiveProperty ( 0 ) ;
2009-01-21 20:06:13 +08:00
osgVolume : : AlphaFuncProperty * ap = new osgVolume : : AlphaFuncProperty ( alphaFunc ) ;
2013-12-11 20:00:27 +08:00
osgVolume : : IsoSurfaceProperty * isop = new osgVolume : : IsoSurfaceProperty ( alphaFunc ) ;
2013-12-10 18:43:48 +08:00
// SampleDensity is now deprecated
osgVolume : : SampleDensityProperty * sd = new osgVolume : : SampleDensityProperty ( 0.005f ) ;
2011-06-09 18:48:19 +08:00
osgVolume : : SampleDensityWhenMovingProperty * sdwm = sampleDensityWhenMoving ! = 0.0 ? new osgVolume : : SampleDensityWhenMovingProperty ( sampleDensityWhenMoving ) : 0 ;
2013-12-10 18:43:48 +08:00
// use SampleRatio in place of SampleDensity
osgVolume : : SampleRatioProperty * sr = new osgVolume : : SampleRatioProperty ( 1.0f ) ;
2013-12-12 17:53:24 +08:00
osgVolume : : SampleRatioWhenMovingProperty * srwm = sampleRatioWhenMoving ! = 0.0 ? new osgVolume : : SampleRatioWhenMovingProperty ( sampleRatioWhenMoving ) : 0 ;
2013-12-10 18:43:48 +08:00
2009-01-21 20:06:13 +08:00
osgVolume : : TransparencyProperty * tp = new osgVolume : : TransparencyProperty ( 1.0 ) ;
2009-02-01 05:45:47 +08:00
osgVolume : : TransferFunctionProperty * tfp = transferFunction . valid ( ) ? new osgVolume : : TransferFunctionProperty ( transferFunction . get ( ) ) : 0 ;
2009-01-21 20:06:13 +08:00
2009-01-21 19:46:03 +08:00
{
// Standard
osgVolume : : CompositeProperty * cp = new osgVolume : : CompositeProperty ;
2009-01-21 20:06:13 +08:00
cp - > addProperty ( ap ) ;
2013-12-12 17:53:24 +08:00
if ( useMultipass )
{
cp - > addProperty ( sr ) ;
if ( srwm ) cp - > addProperty ( srwm ) ;
}
else
{
cp - > addProperty ( sd ) ;
if ( sdwm ) cp - > addProperty ( sdwm ) ;
}
2009-01-21 20:06:13 +08:00
cp - > addProperty ( tp ) ;
2013-12-10 18:43:48 +08:00
2013-12-11 20:00:27 +08:00
if ( tfp )
{
OSG_NOTICE < < " Adding TransferFunction " < < std : : endl ;
cp - > addProperty ( tfp ) ;
}
2009-01-21 19:46:03 +08:00
sp - > addProperty ( cp ) ;
}
{
// Light
osgVolume : : CompositeProperty * cp = new osgVolume : : CompositeProperty ;
2009-01-21 20:06:13 +08:00
cp - > addProperty ( ap ) ;
2013-12-10 18:43:48 +08:00
if ( useMultipass ) cp - > addProperty ( sr ) ;
else cp - > addProperty ( sd ) ;
2009-01-21 20:06:13 +08:00
cp - > addProperty ( tp ) ;
2009-01-21 19:46:03 +08:00
cp - > addProperty ( new osgVolume : : LightingProperty ) ;
2011-06-09 18:48:19 +08:00
if ( sdwm ) cp - > addProperty ( sdwm ) ;
2009-01-29 17:24:45 +08:00
if ( tfp ) cp - > addProperty ( tfp ) ;
2009-01-21 19:46:03 +08:00
sp - > addProperty ( cp ) ;
}
{
// Isosurface
osgVolume : : CompositeProperty * cp = new osgVolume : : CompositeProperty ;
2013-12-10 18:43:48 +08:00
if ( useMultipass ) cp - > addProperty ( sr ) ;
else cp - > addProperty ( sd ) ;
2009-01-21 20:06:13 +08:00
cp - > addProperty ( tp ) ;
2013-12-11 20:00:27 +08:00
cp - > addProperty ( isop ) ;
2011-06-09 18:48:19 +08:00
if ( sdwm ) cp - > addProperty ( sdwm ) ;
2009-01-29 17:24:45 +08:00
if ( tfp ) cp - > addProperty ( tfp ) ;
2009-01-21 19:46:03 +08:00
sp - > addProperty ( cp ) ;
}
{
// MaximumIntensityProjection
osgVolume : : CompositeProperty * cp = new osgVolume : : CompositeProperty ;
2009-01-21 20:06:13 +08:00
cp - > addProperty ( ap ) ;
2013-12-10 18:43:48 +08:00
if ( useMultipass ) cp - > addProperty ( sr ) ;
else cp - > addProperty ( sd ) ;
2009-01-21 20:06:13 +08:00
cp - > addProperty ( tp ) ;
2009-01-21 19:46:03 +08:00
cp - > addProperty ( new osgVolume : : MaximumIntensityProjectionProperty ) ;
2011-06-09 18:48:19 +08:00
if ( sdwm ) cp - > addProperty ( sdwm ) ;
2009-01-29 17:24:45 +08:00
if ( tfp ) cp - > addProperty ( tfp ) ;
2009-01-21 19:46:03 +08:00
sp - > addProperty ( cp ) ;
}
2009-01-21 20:06:13 +08:00
2009-01-29 17:24:45 +08:00
switch ( shadingModel )
2009-01-21 20:06:13 +08:00
{
2009-01-29 17:24:45 +08:00
case ( Standard ) : sp - > setActiveProperty ( 0 ) ; break ;
case ( Light ) : sp - > setActiveProperty ( 1 ) ; break ;
case ( Isosurface ) : sp - > setActiveProperty ( 2 ) ; break ;
case ( MaximumIntensityProjection ) : sp - > setActiveProperty ( 3 ) ; break ;
2009-01-21 20:06:13 +08:00
}
2009-01-29 17:24:45 +08:00
layer - > addProperty ( sp ) ;
2009-01-21 20:06:13 +08:00
2013-11-22 02:17:44 +08:00
if ( useMultipass )
{
tile - > setVolumeTechnique ( new osgVolume : : MultipassTechnique ) ;
}
else
{
tile - > setVolumeTechnique ( new osgVolume : : RayTracedTechnique ) ;
}
2009-01-21 20:06:13 +08:00
}
else
{
layer - > addProperty ( new osgVolume : : AlphaFuncProperty ( alphaFunc ) ) ;
tile - > setVolumeTechnique ( new osgVolume : : FixedFunctionTechnique ) ;
2008-10-02 23:45:08 +08:00
}
2009-09-01 18:48:32 +08:00
2004-06-29 21:59:07 +08:00
if ( ! outputFile . empty ( ) )
2009-09-01 18:48:32 +08:00
{
2004-06-29 21:59:07 +08:00
std : : string ext = osgDB : : getFileExtension ( outputFile ) ;
std : : string name_no_ext = osgDB : : getNameLessExtension ( outputFile ) ;
2011-06-08 00:17:35 +08:00
if ( ext = = " osg " | | ext = = " osgt " | | ext = = " osgx " )
2004-06-29 21:59:07 +08:00
{
2004-09-06 22:58:29 +08:00
if ( image_3d . valid ( ) )
{
2014-07-02 23:34:37 +08:00
std : : string image_writeExtension = " .osgb " ;
image_3d - > setFileName ( name_no_ext + image_writeExtension ) ;
2014-06-30 23:31:36 +08:00
osg : : ref_ptr < osgDB : : Options > options = new osgDB : : Options ( " ddsNoAutoFlipWrite " ) ; ;
osgDB : : writeImageFile ( * image_3d , image_3d - > getFileName ( ) , options . get ( ) ) ;
2004-09-06 22:58:29 +08:00
}
2009-01-21 20:06:13 +08:00
osgDB : : writeNodeFile ( * volume , outputFile ) ;
2004-06-29 21:59:07 +08:00
}
2011-06-08 00:17:35 +08:00
else if ( ext = = " ive " | | ext = = " osgb " )
2004-06-29 21:59:07 +08:00
{
2009-09-01 18:48:32 +08:00
osgDB : : writeNodeFile ( * volume , outputFile ) ;
2004-06-29 21:59:07 +08:00
}
else if ( ext = = " dds " )
{
2009-01-21 20:06:13 +08:00
osgDB : : writeImageFile ( * image_3d , outputFile ) ;
2004-06-29 21:59:07 +08:00
}
else
{
std : : cout < < " Extension not support for file output, not file written. " < < std : : endl ;
}
2009-09-01 18:48:32 +08:00
2004-06-29 22:58:24 +08:00
return 0 ;
2004-06-29 21:59:07 +08:00
}
2009-09-01 18:48:32 +08:00
if ( volume . valid ( ) )
2004-06-29 21:59:07 +08:00
{
2009-07-03 02:50:45 +08:00
osg : : ref_ptr < osg : : Node > loadedModel = volume . get ( ) ;
if ( useManipulator )
{
osg : : ref_ptr < osg : : Group > group = new osg : : Group ;
2009-07-03 13:54:27 +08:00
# if 1
osg : : ref_ptr < osgManipulator : : Dragger > dragger = new osgManipulator : : TabBoxDragger ;
# else
osg : : ref_ptr < osgManipulator : : Dragger > dragger = new osgManipulator : : TrackballDragger ( ) ;
# endif
2009-07-03 02:50:45 +08:00
dragger - > setupDefaultGeometry ( ) ;
dragger - > setHandleEvents ( true ) ;
2009-07-04 03:16:53 +08:00
dragger - > setActivationModKeyMask ( osgGA : : GUIEventAdapter : : MODKEY_SHIFT ) ;
2009-07-03 02:50:45 +08:00
dragger - > addDraggerCallback ( new DraggerVolumeTileCallback ( tile . get ( ) , tile - > getLocator ( ) ) ) ;
dragger - > setMatrix ( osg : : Matrix : : translate ( 0.5 , 0.5 , 0.5 ) * tile - > getLocator ( ) - > getTransform ( ) ) ;
2016-11-12 01:16:40 +08:00
dragger - > applyAppropriateFrontFace ( dragger - > getOrCreateStateSet ( ) ) ;
2009-07-03 02:50:45 +08:00
group - > addChild ( dragger . get ( ) ) ;
//dragger->addChild(volume.get());
group - > addChild ( volume . get ( ) ) ;
loadedModel = group ;
}
2013-11-22 02:17:44 +08:00
if ( hulls . get ( ) )
{
tile - > addChild ( hulls . get ( ) ) ;
}
// add add models into the scene alongside the volume
if ( models . get ( ) )
{
osg : : ref_ptr < osg : : Group > group = new osg : : Group ;
group - > addChild ( models . get ( ) ) ;
group - > addChild ( loadedModel . get ( ) ) ;
loadedModel = group . get ( ) ;
}
// if we want to do multi-pass volume rendering we need decorate the whole scene with a VolumeScene node.
if ( useMultipass )
{
osg : : ref_ptr < osgVolume : : VolumeScene > volumeScene = new osgVolume : : VolumeScene ;
volumeScene - > addChild ( loadedModel . get ( ) ) ;
2013-12-07 03:31:12 +08:00
loadedModel - > getOrCreateStateSet ( ) ;
2013-11-22 02:17:44 +08:00
loadedModel = volumeScene . get ( ) ;
}
2009-07-03 02:50:45 +08:00
2013-11-26 01:36:17 +08:00
2004-06-29 21:59:07 +08:00
// set the scene to render
2009-07-03 02:50:45 +08:00
viewer . setSceneData ( loadedModel . get ( ) ) ;
2009-09-01 18:48:32 +08:00
2015-06-01 21:11:49 +08:00
// the viewers main frame loop
2007-01-11 23:19:59 +08:00
viewer . run ( ) ;
2009-09-01 18:48:32 +08:00
}
2004-06-29 21:59:07 +08:00
return 0 ;
}