2008-03-03 22:17:56 +08:00
/* OpenSceneGraph example, osgmultitexture.
*
* 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/Notify>
# include <osg/Texture2D>
2008-03-04 02:12:21 +08:00
# include <osg/io_utils>
2008-03-03 22:17:56 +08:00
# include <osgDB/Registry>
# include <osgDB/ReadFile>
# include <osgFX/MultiTextureControl>
# include <osgGA/TerrainManipulator>
2008-03-11 20:10:09 +08:00
# include <osgGA/StateSetManipulator>
2008-03-24 18:53:14 +08:00
# include <osgGA/AnimationPathManipulator>
# include <osgGA/TrackballManipulator>
# include <osgGA/FlightManipulator>
# include <osgGA/DriveManipulator>
# include <osgGA/KeySwitchMatrixManipulator>
# include <osgGA/StateSetManipulator>
# include <osgGA/AnimationPathManipulator>
# include <osgGA/TerrainManipulator>
2008-03-11 20:10:09 +08:00
2008-03-27 19:55:03 +08:00
# include <osgTerrain/Terrain>
2008-09-11 02:11:54 +08:00
# include <osgTerrain/TerrainTile>
2008-03-27 04:06:54 +08:00
2008-03-11 20:10:09 +08:00
# include <osgViewer/ViewerEventHandlers>
# include <osgViewer/Viewer>
2008-03-03 22:17:56 +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 ;
}
2008-03-04 02:12:21 +08:00
/** Callback used to track the elevation of the camera and update the texture weights in an MultiTextureControl node.*/
class ElevationLayerBlendingCallback : public osg : : NodeCallback
{
public :
typedef std : : vector < double > Elevations ;
ElevationLayerBlendingCallback ( osgFX : : MultiTextureControl * mtc , const Elevations & elevations , float animationTime = 4.0f ) :
_previousFrame ( - 1 ) ,
_previousTime ( 0.0 ) ,
2008-07-16 23:58:15 +08:00
_currentElevation ( 0.0 ) ,
2008-03-04 02:12:21 +08:00
_mtc ( mtc ) ,
_elevations ( elevations ) ,
_animationTime ( animationTime ) { }
/** Callback method called by the NodeVisitor when visiting a node.*/
virtual void operator ( ) ( osg : : Node * node , osg : : NodeVisitor * nv )
2008-07-16 23:58:15 +08:00
{
if ( nv - > getVisitorType ( ) = = osg : : NodeVisitor : : UPDATE_VISITOR )
2008-03-04 02:12:21 +08:00
{
2008-07-16 23:58:15 +08:00
float deltaTime = 0.01f ;
if ( _previousFrame ! = - 1 )
2008-03-04 02:12:21 +08:00
{
2008-07-16 23:58:15 +08:00
deltaTime = float ( nv - > getFrameStamp ( ) - > getReferenceTime ( ) - _previousTime ) ;
2008-03-04 02:12:21 +08:00
}
2008-07-16 23:58:15 +08:00
_previousTime = nv - > getFrameStamp ( ) - > getReferenceTime ( ) ;
_previousFrame = nv - > getFrameStamp ( ) - > getFrameNumber ( ) ;
if ( _mtc . valid ( ) & & ! _elevations . empty ( ) )
2008-03-04 02:12:21 +08:00
{
2008-07-16 23:58:15 +08:00
unsigned int index = _mtc - > getNumTextureWeights ( ) - 1 ;
for ( unsigned int i = 0 ; i < _elevations . size ( ) ; + + i )
2008-03-04 02:12:21 +08:00
{
2008-07-16 23:58:15 +08:00
if ( _currentElevation > _elevations [ i ] )
2008-03-04 02:12:21 +08:00
{
2008-07-16 23:58:15 +08:00
index = i ;
break ;
2008-03-04 02:12:21 +08:00
}
2008-07-16 23:58:15 +08:00
}
float delta = std : : min ( deltaTime / _animationTime , 1.0f ) ;
for ( unsigned int i = 0 ; i < _mtc - > getNumTextureWeights ( ) ; + + i )
{
float currentValue = _mtc - > getTextureWeight ( i ) ;
float desiredValue = ( i = = index ) ? 1.0f : 0.0f ;
if ( desiredValue ! = currentValue )
2008-03-04 02:12:21 +08:00
{
2008-07-16 23:58:15 +08:00
if ( currentValue < desiredValue )
{
desiredValue = std : : min ( currentValue + delta , desiredValue ) ;
}
else
{
desiredValue = std : : max ( currentValue - delta , desiredValue ) ;
}
_mtc - > setTextureWeight ( i , desiredValue ) ;
2008-03-04 02:12:21 +08:00
}
}
2008-07-16 23:58:15 +08:00
2008-03-04 02:12:21 +08:00
}
}
2008-07-16 23:58:15 +08:00
else if ( nv - > getVisitorType ( ) = = osg : : NodeVisitor : : CULL_VISITOR )
{
_currentElevation = nv - > getViewPoint ( ) . z ( ) ;
osg : : CoordinateSystemNode * csn = dynamic_cast < osg : : CoordinateSystemNode * > ( node ) ;
if ( csn )
{
osg : : EllipsoidModel * em = csn - > getEllipsoidModel ( ) ;
if ( em )
{
double X = nv - > getViewPoint ( ) . x ( ) ;
double Y = nv - > getViewPoint ( ) . y ( ) ;
double Z = nv - > getViewPoint ( ) . z ( ) ;
double latitude , longitude ;
em - > convertXYZToLatLongHeight ( X , Y , Z , latitude , longitude , _currentElevation ) ;
}
}
}
2008-03-04 02:12:21 +08:00
traverse ( node , nv ) ;
}
int _previousFrame ;
double _previousTime ;
float _animationTime ;
2008-07-16 23:58:15 +08:00
double _currentElevation ;
2008-03-04 02:12:21 +08:00
osg : : observer_ptr < osgFX : : MultiTextureControl > _mtc ;
Elevations _elevations ;
} ;
2008-05-27 23:28:39 +08:00
// class to handle events with a pick
class TerrainHandler : public osgGA : : GUIEventHandler {
public :
TerrainHandler ( osgTerrain : : Terrain * terrain ) :
_terrain ( terrain ) { }
bool handle ( const osgGA : : GUIEventAdapter & ea , osgGA : : GUIActionAdapter & aa )
{
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 ;
}
return false ;
}
default :
return false ;
}
}
protected :
~ TerrainHandler ( ) { }
osg : : ref_ptr < osgTerrain : : Terrain > _terrain ;
} ;
2008-03-03 22:17:56 +08:00
int main ( int argc , char * * argv )
{
// use an ArgumentParser object to manage the program arguments.
osg : : ArgumentParser arguments ( & argc , argv ) ;
2008-07-21 23:05:08 +08:00
arguments . getApplicationUsage ( ) - > addCommandLineOption ( " -v " , " Set the terrain vertical scale. " ) ;
arguments . getApplicationUsage ( ) - > addCommandLineOption ( " -r " , " Set the terrain sample ratio. " ) ;
arguments . getApplicationUsage ( ) - > addCommandLineOption ( " --login <url> <username> <password> " , " Provide authentication information for http file access. " ) ;
2008-03-03 22:17:56 +08:00
2008-09-11 21:21:58 +08:00
// construct the viewer.
osgViewer : : Viewer viewer ( arguments ) ;
2008-09-11 02:11:54 +08:00
// set the tile loaded callback to load the optional imagery
2008-09-11 21:21:58 +08:00
osg : : ref_ptr < osgTerrain : : WhiteListTileLoadedCallback > whiteList = new osgTerrain : : WhiteListTileLoadedCallback ;
2008-09-11 18:40:48 +08:00
std : : string setname ;
while ( arguments . read ( " --allow " , setname ) )
{
whiteList - > allow ( setname ) ;
}
2008-09-11 21:21:58 +08:00
while ( arguments . read ( " --allow-all " ) )
{
whiteList - > setAllowAll ( true ) ;
}
2008-09-11 18:40:48 +08:00
osgTerrain : : TerrainTile : : setTileLoadedCallback ( whiteList . get ( ) ) ;
2008-09-11 21:21:58 +08:00
// obtain the vertical scale
2008-05-27 23:28:39 +08:00
float verticalScale = 1.0f ;
while ( arguments . read ( " -v " , verticalScale ) ) { }
2008-09-11 21:21:58 +08:00
// obtain the sample ratio
2008-05-27 23:28:39 +08:00
float sampleRatio = 1.0f ;
while ( arguments . read ( " -r " , sampleRatio ) ) { }
2008-03-04 02:12:21 +08:00
2008-09-11 21:21:58 +08:00
// set up any authentication.
2008-07-21 23:05:08 +08:00
std : : string url , username , password ;
while ( arguments . read ( " --login " , url , username , password ) )
{
if ( ! osgDB : : Registry : : instance ( ) - > getAuthenticationMap ( ) )
{
osgDB : : Registry : : instance ( ) - > setAuthenticationMap ( new osgDB : : AuthenticationMap ) ;
osgDB : : Registry : : instance ( ) - > getAuthenticationMap ( ) - > addAuthenticationDetails (
url ,
new osgDB : : AuthenticationDetails ( username , password )
) ;
}
}
2008-03-03 22:17:56 +08:00
2008-03-11 20:10:09 +08:00
// add all the event handlers to the viewer
{
// add the state manipulator
viewer . addEventHandler ( new osgGA : : StateSetManipulator ( viewer . getCamera ( ) - > getOrCreateStateSet ( ) ) ) ;
// add the thread model handler
viewer . addEventHandler ( new osgViewer : : ThreadingHandler ) ;
// add the window size toggle handler
viewer . addEventHandler ( new osgViewer : : WindowSizeHandler ) ;
// add the stats handler
viewer . addEventHandler ( new osgViewer : : StatsHandler ) ;
// add the help handler
viewer . addEventHandler ( new osgViewer : : HelpHandler ( arguments . getApplicationUsage ( ) ) ) ;
// add the record camera path handler
viewer . addEventHandler ( new osgViewer : : RecordCameraPathHandler ) ;
// add the LOD Scale handler
viewer . addEventHandler ( new osgViewer : : LODScaleHandler ) ;
}
2008-03-28 23:28:03 +08:00
// add all the camera manipulators
2008-03-24 18:53:14 +08:00
{
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 ( ) ) ;
unsigned int num = keyswitchManipulator - > getNumMatrixManipulators ( ) ;
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 ) ;
if ( apm | | ! apm - > valid ( ) )
{
num = keyswitchManipulator - > getNumMatrixManipulators ( ) ;
keyswitchManipulator - > addMatrixManipulator ( keyForAnimationPath , " Path " , apm ) ;
+ + keyForAnimationPath ;
}
}
keyswitchManipulator - > selectMatrixManipulator ( num ) ;
viewer . setCameraManipulator ( keyswitchManipulator . get ( ) ) ;
}
2008-03-28 23:28:03 +08:00
// set up the scene graph
{
// load the nodes from the commandline arguments.
osg : : Node * rootnode = osgDB : : readNodeFiles ( arguments ) ;
if ( ! rootnode )
{
osg : : notify ( osg : : NOTICE ) < < " Warning: no valid data loaded, please specify a database on the command line. " < < std : : endl ;
return 1 ;
}
osgTerrain : : Terrain * terrain = findTopMostNodeOfType < osgTerrain : : Terrain > ( rootnode ) ;
if ( ! terrain )
{
terrain = new osgTerrain : : Terrain ;
terrain - > addChild ( rootnode ) ;
rootnode = terrain ;
}
2008-05-27 23:28:39 +08:00
terrain - > setSampleRatio ( sampleRatio ) ;
terrain - > setVerticalScale ( verticalScale ) ;
// register our custom handler for adjust Terrain settings
viewer . addEventHandler ( new TerrainHandler ( terrain ) ) ;
2008-03-28 23:28:03 +08:00
osg : : CoordinateSystemNode * csn = findTopMostNodeOfType < osg : : CoordinateSystemNode > ( rootnode ) ;
unsigned int numLayers = 1 ;
osgFX : : MultiTextureControl * mtc = findTopMostNodeOfType < osgFX : : MultiTextureControl > ( rootnode ) ;
if ( mtc )
{
numLayers = mtc - > getNumTextureWeights ( ) ;
2008-09-11 21:21:58 +08:00
// switch on just the first texture layer.
mtc - > setTextureWeight ( 0 , 1.0f ) ;
for ( unsigned int i = 1 ; i < numLayers ; + + i )
{
mtc - > setTextureWeight ( i , 0.0f ) ;
}
2008-03-28 23:28:03 +08:00
}
if ( numLayers < 2 )
{
osg : : notify ( osg : : NOTICE ) < < " Warning: scene must have MultiTextureControl node with at least 2 texture units defined. " < < std : : endl ;
return 1 ;
}
double maxElevationTransition = 1e6 ;
ElevationLayerBlendingCallback : : Elevations elevations ;
for ( unsigned int i = 0 ; i < numLayers ; + + i )
{
elevations . push_back ( maxElevationTransition ) ;
maxElevationTransition / = 2.0 ;
}
ElevationLayerBlendingCallback * elbc = new ElevationLayerBlendingCallback ( mtc , elevations ) ;
// assign to the most appropriate node (the CoordinateSystemNode is best as it provides the elevation on the globe.)
2008-07-16 23:58:15 +08:00
// note we must assign callback as both an update and cull callback, as update callback to do the update of
// the the osgFX::MultiTextureControl node a thread safe way, and as a cull callback to gather the camera
// position information.
osg : : Node * nodeToAssignCallbackTo = csn ? csn : ( mtc ? mtc : rootnode ) ;
nodeToAssignCallbackTo - > setUpdateCallback ( elbc ) ;
nodeToAssignCallbackTo - > setCullCallback ( elbc ) ;
2008-03-28 23:28:03 +08:00
// add a viewport to the viewer and attach the scene graph.
viewer . setSceneData ( rootnode ) ;
}
2008-03-03 22:17:56 +08:00
2008-07-21 23:05:08 +08:00
2008-03-03 22:17:56 +08:00
// create the windows and run the threads.
viewer . realize ( ) ;
return viewer . run ( ) ;
}