2010-03-20 00:31:48 +08:00
/* OpenSceneGraph example, osgterrain.
*
* 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 .
*/
# include <osg/ArgumentParser>
# include <osgDB/ReadFile>
# include <osgViewer/Viewer>
# include <osgViewer/ViewerEventHandlers>
# include <osgGA/TrackballManipulator>
# include <osgGA/FlightManipulator>
# include <osgGA/DriveManipulator>
# include <osgGA/KeySwitchMatrixManipulator>
# include <osgGA/StateSetManipulator>
# include <osgGA/AnimationPathManipulator>
# include <osgGA/TerrainManipulator>
# include <osgTerrain/Terrain>
# include <osgTerrain/TerrainTile>
# include <osgTerrain/GeometryTechnique>
2014-11-26 22:04:20 +08:00
# include <osgTerrain/DisplacementMappingTechnique>
2010-03-20 00:31:48 +08:00
# include <osgTerrain/Layer>
2015-01-23 21:50:12 +08:00
# include <osgFX/MultiTextureControl>
2014-10-21 23:08:44 +08:00
2010-03-20 00:31:48 +08:00
# include <iostream>
template < class T >
class FindTopMostNodeOfTypeVisitor : public osg : : NodeVisitor
{
public :
FindTopMostNodeOfTypeVisitor ( ) :
osg : : NodeVisitor ( osg : : NodeVisitor : : TRAVERSE_ALL_CHILDREN ) ,
_foundNode ( 0 )
{ }
void apply ( osg : : Node & node )
{
T * result = dynamic_cast < T * > ( & node ) ;
if ( result )
{
_foundNode = result ;
}
else
{
traverse ( node ) ;
}
}
T * _foundNode ;
} ;
template < class T >
T * findTopMostNodeOfType ( osg : : Node * node )
{
if ( ! node ) return 0 ;
FindTopMostNodeOfTypeVisitor < T > fnotv ;
node - > accept ( fnotv ) ;
return fnotv . _foundNode ;
}
2010-03-29 16:49:20 +08:00
// class to handle events with a pick
class TerrainHandler : public osgGA : : GUIEventHandler {
public :
2015-01-23 21:50:12 +08:00
TerrainHandler ( osgTerrain : : Terrain * terrain , osgFX : : MultiTextureControl * mtc ) :
_terrain ( terrain ) ,
_mtc ( mtc ) { }
2010-03-29 16:49:20 +08:00
2016-06-08 19:10:00 +08:00
bool handle ( const osgGA : : GUIEventAdapter & ea , osgGA : : GUIActionAdapter & /*aa*/ )
2010-03-29 16:49:20 +08:00
{
switch ( ea . getEventType ( ) )
{
case ( osgGA : : GUIEventAdapter : : KEYDOWN ) :
{
if ( ea . getKey ( ) = = ' r ' )
{
_terrain - > setSampleRatio ( _terrain - > getSampleRatio ( ) * 0.5 ) ;
osg : : notify ( osg : : NOTICE ) < < " Sample ratio " < < _terrain - > getSampleRatio ( ) < < std : : endl ;
return true ;
}
else if ( ea . getKey ( ) = = ' R ' )
{
_terrain - > setSampleRatio ( _terrain - > getSampleRatio ( ) / 0.5 ) ;
osg : : notify ( osg : : NOTICE ) < < " Sample ratio " < < _terrain - > getSampleRatio ( ) < < std : : endl ;
return true ;
}
else if ( ea . getKey ( ) = = ' v ' )
{
_terrain - > setVerticalScale ( _terrain - > getVerticalScale ( ) * 1.25 ) ;
osg : : notify ( osg : : NOTICE ) < < " Vertical scale " < < _terrain - > getVerticalScale ( ) < < std : : endl ;
return true ;
}
else if ( ea . getKey ( ) = = ' V ' )
{
_terrain - > setVerticalScale ( _terrain - > getVerticalScale ( ) / 1.25 ) ;
osg : : notify ( osg : : NOTICE ) < < " Vertical scale " < < _terrain - > getVerticalScale ( ) < < std : : endl ;
return true ;
}
2015-01-23 21:50:12 +08:00
else if ( ea . getKey ( ) = = ' ! ' ) // shift 1
{
assignTextureWeightToSingleTextureUnit ( 1 ) ;
return true ;
}
else if ( ea . getKey ( ) = = ' " ' ) // shift 1
{
assignTextureWeightToSingleTextureUnit ( 2 ) ;
return true ;
}
else if ( ea . getKey ( ) = = ' ) ' ) // shift 1
{
assignTextureWeightToSingleTextureUnit ( 0 ) ;
return true ;
}
else if ( ea . getKey ( ) = = ' A ' )
{
assignedToAll ( ) ;
return true ;
}
2015-02-11 01:20:26 +08:00
else if ( ea . getKey ( ) = = ' l ' )
{
2015-02-18 03:22:37 +08:00
toggleDefine ( " LIGHTING " ) ;
2015-02-11 01:20:26 +08:00
return true ;
}
2015-02-20 23:02:43 +08:00
else if ( ea . getKey ( ) = = ' h ' )
{
toggleDefine ( " HEIGHTFIELD_LAYER " ) ;
return true ;
}
2015-02-11 01:20:26 +08:00
else if ( ea . getKey ( ) = = ' t ' )
{
2015-02-18 03:22:37 +08:00
toggleDefine ( " TEXTURE_2D " ) ;
2015-02-11 01:20:26 +08:00
return true ;
}
2015-02-20 23:02:43 +08:00
else if ( ea . getKey ( ) = = ' y ' )
{
toggleDefine ( " COLOR_LAYER0 " ) ;
return true ;
}
else if ( ea . getKey ( ) = = ' u ' )
{
toggleDefine ( " COLOR_LAYER1 " ) ;
return true ;
}
else if ( ea . getKey ( ) = = ' i ' )
{
toggleDefine ( " COLOR_LAYER2 " ) ;
return true ;
}
2015-02-11 01:20:26 +08:00
else if ( ea . getKey ( ) = = ' d ' )
{
2015-02-20 23:12:57 +08:00
toggleDefine ( " COMPUTE_DIAGONALS " , osg : : StateAttribute : : OFF ) ;
2015-02-11 01:20:26 +08:00
return true ;
}
2010-03-29 16:49:20 +08:00
return false ;
}
default :
return false ;
}
}
2015-02-20 23:12:57 +08:00
void toggleDefine ( const std : : string & defineName , int expectedDefault = osg : : StateAttribute : : ON )
2015-02-11 01:20:26 +08:00
{
osg : : StateSet : : DefineList & defineList = _terrain - > getOrCreateStateSet ( ) - > getDefineList ( ) ;
osg : : StateSet : : DefineList : : iterator itr = defineList . find ( defineName ) ;
if ( itr = = defineList . end ( ) )
{
2015-02-20 23:12:57 +08:00
defineList [ defineName ] . second = ( expectedDefault | osg : : StateAttribute : : OVERRIDE ) ; // assume the defines start off.
itr = defineList . find ( defineName ) ;
2015-02-11 01:20:26 +08:00
}
2015-02-20 23:12:57 +08:00
osg : : StateSet : : DefinePair & dp = itr - > second ;
if ( ( dp . second & osg : : StateAttribute : : ON ) = = 0 ) dp . second = ( osg : : StateAttribute : : ON | osg : : StateAttribute : : OVERRIDE ) ;
else dp . second = ( osg : : StateAttribute : : OFF | osg : : StateAttribute : : OVERRIDE ) ;
2015-02-11 01:20:26 +08:00
}
2010-03-29 16:49:20 +08:00
protected :
~ TerrainHandler ( ) { }
2015-01-23 21:50:12 +08:00
void assignTextureWeightToSingleTextureUnit ( unsigned int unit )
{
if ( ! _mtc ) return ;
for ( unsigned int i = 0 ; i < _mtc - > getNumTextureWeights ( ) ; + + i )
{
_mtc - > setTextureWeight ( i , ( i = = unit ) ? 1.0f : 0.0f ) ;
}
}
void assignedToAll ( )
{
if ( ! _mtc & & _mtc - > getNumTextureWeights ( ) > 0 ) return ;
float div = 1.0f / static_cast < float > ( _mtc - > getNumTextureWeights ( ) ) ;
for ( unsigned int i = 0 ; i < _mtc - > getNumTextureWeights ( ) ; + + i )
{
_mtc - > setTextureWeight ( i , div ) ;
}
}
2010-03-29 16:49:20 +08:00
2015-01-23 21:50:12 +08:00
osg : : ref_ptr < osgTerrain : : Terrain > _terrain ;
osg : : ref_ptr < osgFX : : MultiTextureControl > _mtc ;
} ;
2014-10-21 23:08:44 +08:00
class CleanTechniqueReadFileCallback : public osgDB : : ReadFileCallback
{
public :
class CleanTechniqueVisitor : public osg : : NodeVisitor
{
public :
CleanTechniqueVisitor ( ) :
osg : : NodeVisitor ( osg : : NodeVisitor : : TRAVERSE_ALL_CHILDREN ) { }
void apply ( osg : : Node & node )
{
osgTerrain : : TerrainTile * tile = dynamic_cast < osgTerrain : : TerrainTile * > ( & node ) ;
if ( tile )
{
if ( tile - > getTerrainTechnique ( ) )
{
// OSG_NOTICE<<"Resetting TerrainTechnhique "<<tile->getTerrainTechnique()->className()<<" to 0"<<std::endl;
tile - > setTerrainTechnique ( 0 ) ;
}
}
else
{
traverse ( node ) ;
}
}
} ;
virtual osgDB : : ReaderWriter : : ReadResult readNode ( const std : : string & filename , const osgDB : : Options * options )
{
osgDB : : ReaderWriter : : ReadResult rr = ReadFileCallback : : readNode ( filename , options ) ;
if ( rr . validNode ( ) )
{
CleanTechniqueVisitor ctv ;
rr . getNode ( ) - > accept ( ctv ) ;
}
return rr ;
}
protected :
virtual ~ CleanTechniqueReadFileCallback ( ) { }
} ;
2010-03-20 00:31:48 +08:00
int main ( int argc , char * * argv )
{
osg : : ArgumentParser arguments ( & argc , argv ) ;
// construct the viewer.
osgViewer : : Viewer viewer ( arguments ) ;
// set up the camera manipulators.
{
osg : : ref_ptr < osgGA : : KeySwitchMatrixManipulator > keyswitchManipulator = new osgGA : : KeySwitchMatrixManipulator ;
keyswitchManipulator - > addMatrixManipulator ( ' 1 ' , " Trackball " , new osgGA : : TrackballManipulator ( ) ) ;
keyswitchManipulator - > addMatrixManipulator ( ' 2 ' , " Flight " , new osgGA : : FlightManipulator ( ) ) ;
keyswitchManipulator - > addMatrixManipulator ( ' 3 ' , " Drive " , new osgGA : : DriveManipulator ( ) ) ;
keyswitchManipulator - > addMatrixManipulator ( ' 4 ' , " Terrain " , new osgGA : : TerrainManipulator ( ) ) ;
std : : string pathfile ;
char keyForAnimationPath = ' 5 ' ;
while ( arguments . read ( " -p " , pathfile ) )
{
osgGA : : AnimationPathManipulator * apm = new osgGA : : AnimationPathManipulator ( pathfile ) ;
2014-10-21 23:08:44 +08:00
if ( apm | | ! apm - > valid ( ) )
2010-03-20 00:31:48 +08:00
{
unsigned int num = keyswitchManipulator - > getNumMatrixManipulators ( ) ;
keyswitchManipulator - > addMatrixManipulator ( keyForAnimationPath , " Path " , apm ) ;
keyswitchManipulator - > selectMatrixManipulator ( num ) ;
+ + keyForAnimationPath ;
}
}
viewer . setCameraManipulator ( keyswitchManipulator . get ( ) ) ;
}
// add the state manipulator
viewer . addEventHandler ( new osgGA : : StateSetManipulator ( viewer . getCamera ( ) - > getOrCreateStateSet ( ) ) ) ;
// add the stats handler
viewer . addEventHandler ( new osgViewer : : StatsHandler ) ;
// add the record camera path handler
viewer . addEventHandler ( new osgViewer : : RecordCameraPathHandler ) ;
2010-04-02 05:04:36 +08:00
// add the window size toggle handler
viewer . addEventHandler ( new osgViewer : : WindowSizeHandler ) ;
2010-03-20 00:31:48 +08:00
// obtain the vertical scale
float verticalScale = 1.0f ;
while ( arguments . read ( " -v " , verticalScale ) ) { }
// obtain the sample ratio
float sampleRatio = 1.0f ;
while ( arguments . read ( " -r " , sampleRatio ) ) { }
osgTerrain : : TerrainTile : : BlendingPolicy blendingPolicy = osgTerrain : : TerrainTile : : INHERIT ;
std : : string strBlendingPolicy ;
while ( arguments . read ( " --blending-policy " , strBlendingPolicy ) )
{
if ( strBlendingPolicy = = " INHERIT " ) blendingPolicy = osgTerrain : : TerrainTile : : INHERIT ;
else if ( strBlendingPolicy = = " DO_NOT_SET_BLENDING " ) blendingPolicy = osgTerrain : : TerrainTile : : DO_NOT_SET_BLENDING ;
else if ( strBlendingPolicy = = " ENABLE_BLENDING " ) blendingPolicy = osgTerrain : : TerrainTile : : ENABLE_BLENDING ;
else if ( strBlendingPolicy = = " ENABLE_BLENDING_WHEN_ALPHA_PRESENT " ) blendingPolicy = osgTerrain : : TerrainTile : : ENABLE_BLENDING_WHEN_ALPHA_PRESENT ;
}
2014-11-26 22:04:20 +08:00
bool useDisplacementMappingTechnique = arguments . read ( " --dm " ) ;
if ( useDisplacementMappingTechnique )
2014-10-21 23:08:44 +08:00
{
osgDB : : Registry : : instance ( ) - > setReadFileCallback ( new CleanTechniqueReadFileCallback ( ) ) ;
}
2014-11-21 22:46:08 +08:00
bool setDatabaseThreadAffinity = false ;
unsigned int cpuNum = 0 ;
while ( arguments . read ( " --db-affinity " , cpuNum ) ) { setDatabaseThreadAffinity = true ; }
2014-10-21 23:08:44 +08:00
2010-03-20 00:31:48 +08:00
// load the nodes from the commandline arguments.
2015-10-22 21:42:19 +08:00
osg : : ref_ptr < osg : : Node > rootnode = osgDB : : readRefNodeFiles ( arguments ) ;
2010-03-20 00:31:48 +08:00
if ( ! rootnode )
{
osg : : notify ( osg : : NOTICE ) < < " Warning: no valid data loaded, please specify a database on the command line. " < < std : : endl ;
return 1 ;
}
2010-12-23 17:59:35 +08:00
osg : : ref_ptr < osgTerrain : : Terrain > terrain = findTopMostNodeOfType < osgTerrain : : Terrain > ( rootnode . get ( ) ) ;
2010-03-20 00:31:48 +08:00
if ( ! terrain )
{
2010-12-09 20:16:11 +08:00
// no Terrain node present insert one above the loaded model.
2010-03-20 00:31:48 +08:00
terrain = new osgTerrain : : Terrain ;
2010-12-09 20:16:11 +08:00
// if CoordinateSystemNode is present copy it's contents into the Terrain, and discard it.
2010-12-23 17:59:35 +08:00
osg : : CoordinateSystemNode * csn = findTopMostNodeOfType < osg : : CoordinateSystemNode > ( rootnode . get ( ) ) ;
2010-12-09 20:16:11 +08:00
if ( csn )
{
terrain - > set ( * csn ) ;
for ( unsigned int i = 0 ; i < csn - > getNumChildren ( ) ; + + i )
{
terrain - > addChild ( csn - > getChild ( i ) ) ;
}
}
else
{
terrain - > addChild ( rootnode . get ( ) ) ;
}
rootnode = terrain . get ( ) ;
2010-03-20 00:31:48 +08:00
}
terrain - > setSampleRatio ( sampleRatio ) ;
terrain - > setVerticalScale ( verticalScale ) ;
terrain - > setBlendingPolicy ( blendingPolicy ) ;
2015-01-23 21:50:12 +08:00
2014-11-26 22:04:20 +08:00
if ( useDisplacementMappingTechnique )
2014-10-21 23:08:44 +08:00
{
2014-11-26 22:04:20 +08:00
terrain - > setTerrainTechniquePrototype ( new osgTerrain : : DisplacementMappingTechnique ( ) ) ;
2014-10-21 23:08:44 +08:00
}
2010-03-29 16:49:20 +08:00
// register our custom handler for adjust Terrain settings
2015-01-23 21:50:12 +08:00
viewer . addEventHandler ( new TerrainHandler ( terrain . get ( ) , findTopMostNodeOfType < osgFX : : MultiTextureControl > ( rootnode . get ( ) ) ) ) ;
2010-03-29 16:49:20 +08:00
2010-03-20 00:31:48 +08:00
// add a viewport to the viewer and attach the scene graph.
2010-12-09 20:16:11 +08:00
viewer . setSceneData ( rootnode . get ( ) ) ;
2010-03-20 00:31:48 +08:00
2014-11-21 22:46:08 +08:00
// if required set the DatabaseThread affinity, note must call after viewer.setSceneData() so that the osgViewer::Scene object is constructed with it's DatabasePager.
if ( setDatabaseThreadAffinity )
{
for ( unsigned int i = 0 ; i < viewer . getDatabasePager ( ) - > getNumDatabaseThreads ( ) ; + + i )
{
osgDB : : DatabasePager : : DatabaseThread * thread = viewer . getDatabasePager ( ) - > getDatabaseThread ( i ) ;
thread - > setProcessorAffinity ( cpuNum ) ;
OSG_NOTICE < < " Settings affinity of DatabaseThread= " < < thread < < " isRunning()= " < < thread - > isRunning ( ) < < " cpuNum= " < < cpuNum < < std : : endl ;
}
}
2010-03-20 00:31:48 +08:00
2015-02-18 03:22:37 +08:00
// following are tests of the #pragma(tic) shader composition
//terrain->getOrCreateStateSet()->setDefine("NUM_LIGHTS", "1");
//terrain->getOrCreateStateSet()->setDefine("LIGHTING"); // , osg::StateAttribute::OFF|osg::StateAttribute::OVERRIDE);
2015-02-11 01:20:26 +08:00
//terrain->getOrCreateStateSet()->setDefine("COMPUTE_DIAGONALS"); // , osg::StateAttribute::OFF|osg::StateAttribute::OVERRIDE);
2010-03-20 00:31:48 +08:00
// run the viewers main loop
return viewer . run ( ) ;
}