2003-09-26 05:54:33 +08:00
# include <osg/AlphaFunc>
2003-09-30 23:50:46 +08:00
# include <osg/Billboard>
2003-09-26 05:54:33 +08:00
# include <osg/BlendFunc>
2003-09-30 23:50:46 +08:00
# include <osg/Depth>
# include <osg/Geode>
2003-09-26 05:54:33 +08:00
# include <osg/Geometry>
2003-09-30 23:50:46 +08:00
# include <osg/Material>
# include <osg/Math>
2003-09-26 05:54:33 +08:00
# include <osg/MatrixTransform>
2003-09-30 23:50:46 +08:00
# include <osg/PolygonOffset>
# include <osg/Projection>
# include <osg/ShapeDrawable>
# include <osg/StateSet>
2003-09-26 05:54:33 +08:00
# include <osg/Switch>
2003-09-30 23:50:46 +08:00
# include <osg/Texture2D>
2003-09-26 05:54:33 +08:00
# include <osgDB/ReadFile>
2003-09-30 23:50:46 +08:00
2003-09-26 05:54:33 +08:00
# include <osgUtil/IntersectVisitor>
# include <osgUtil/SmoothingVisitor>
2003-09-30 23:50:46 +08:00
# include <osgText/Text>
# include <osgProducer/Viewer>
2003-09-26 05:54:33 +08:00
// for the grid data..
# include "../osghangglide/terrain_coords.h"
2003-09-26 19:20:43 +08:00
// class to create the forest and manage the movement between various techniques.
class ForestTechniqueManager : public osg : : Referenced
2003-09-26 05:54:33 +08:00
{
public :
2003-09-26 19:20:43 +08:00
ForestTechniqueManager ( ) { }
class Tree : public osg : : Referenced
{
public :
Tree ( ) :
_color ( 255 , 255 , 255 , 255 ) ,
_width ( 1.0f ) ,
_height ( 1.0f ) ,
_type ( 0 ) { }
Tree ( const osg : : Vec3 & position , const osg : : UByte4 & color , float width , float height , unsigned int type ) :
_position ( position ) ,
_color ( color ) ,
_width ( width ) ,
_height ( height ) ,
_type ( type ) { }
osg : : Vec3 _position ;
osg : : UByte4 _color ;
float _width ;
float _height ;
unsigned int _type ;
} ;
2003-09-30 21:48:58 +08:00
2003-09-26 19:20:43 +08:00
typedef std : : vector < osg : : ref_ptr < Tree > > TreeList ;
2003-09-30 21:48:58 +08:00
class Cell : public osg : : Referenced
{
public :
typedef std : : vector < osg : : ref_ptr < Cell > > CellList ;
Cell ( ) : _parent ( 0 ) { }
Cell ( osg : : BoundingBox & bb ) : _parent ( 0 ) , _bb ( bb ) { }
void addCell ( Cell * cell ) { cell - > _parent = this ; _cells . push_back ( cell ) ; }
void addTree ( Tree * tree ) { _trees . push_back ( tree ) ; }
void addTrees ( const TreeList & trees ) { _trees . insert ( _trees . end ( ) , trees . begin ( ) , trees . end ( ) ) ; }
void computeBound ( ) ;
bool contains ( const osg : : Vec3 & position ) const { return _bb . contains ( position ) ; }
bool divide ( unsigned int maxNumTreesPerCell = 10 ) ;
bool devide ( bool xAxis , bool yAxis , bool zAxis ) ;
void bin ( ) ;
Cell * _parent ;
osg : : BoundingBox _bb ;
CellList _cells ;
TreeList _trees ;
} ;
2003-09-26 19:20:43 +08:00
float random ( float min , float max ) { return min + ( max - min ) * ( float ) rand ( ) / ( float ) RAND_MAX ; }
int random ( int min , int max ) { return min + ( int ) ( ( float ) ( max - min ) * ( float ) rand ( ) / ( float ) RAND_MAX ) ; }
osg : : Geode * createTerrain ( const osg : : Vec3 & origin , const osg : : Vec3 & size ) ;
void createTreeList ( osg : : Node * terrain , const osg : : Vec3 & origin , const osg : : Vec3 & size , unsigned int numTreesToCreate , TreeList & trees ) ;
osg : : Geometry * createSprite ( float w , float h , osg : : UByte4 color ) ;
osg : : Geometry * createOrthogonalQuads ( const osg : : Vec3 & pos , float w , float h , osg : : UByte4 color ) ;
2003-09-30 21:48:58 +08:00
osg : : Node * createBillboardGraph ( Cell * cell , osg : : StateSet * stateset ) ;
osg : : Node * createXGraph ( Cell * cell , osg : : StateSet * stateset ) ;
osg : : Node * createTransformGraph ( Cell * cell , osg : : StateSet * stateset ) ;
2003-09-30 23:50:46 +08:00
osg : : Node * createHUDWithText ( const std : : string & text ) ;
2003-09-30 21:48:58 +08:00
2003-09-30 23:50:46 +08:00
osg : : Node * createScene ( unsigned int numTreesToCreates ) ;
2003-09-26 19:20:43 +08:00
void advanceToNextTechnique ( int delta = 1 )
{
if ( _techniqueSwitch . valid ( ) )
{
2003-09-30 23:50:46 +08:00
_currentTechnique + = delta ;
if ( _currentTechnique < 0 )
_currentTechnique = _techniqueSwitch - > getNumChildren ( ) - 1 ;
if ( _currentTechnique > = ( int ) _techniqueSwitch - > getNumChildren ( ) )
_currentTechnique = 0 ;
2003-09-26 19:20:43 +08:00
_techniqueSwitch - > setSingleChildOn ( _currentTechnique ) ;
}
}
osg : : ref_ptr < osg : : Switch > _techniqueSwitch ;
int _currentTechnique ;
2003-09-26 05:54:33 +08:00
} ;
2003-09-26 19:20:43 +08:00
// event handler to capture keyboard events and use them to advance the technique used for rendering
2005-03-23 18:41:51 +08:00
class TechniqueEventHandler : public osgGA : : GUIEventHandler
2003-09-26 19:20:43 +08:00
{
public :
TechniqueEventHandler ( ForestTechniqueManager * ttm = 0 ) { _ForestTechniqueManager = ttm ; }
META_Object ( osgforestApp , TechniqueEventHandler ) ;
virtual void accept ( osgGA : : GUIEventHandlerVisitor & v ) { v . visit ( * this ) ; }
2005-03-12 04:19:16 +08:00
virtual bool handle ( const osgGA : : GUIEventAdapter & ea , osgGA : : GUIActionAdapter & , osg : : Object * , osg : : NodeVisitor * ) ;
2003-09-26 19:20:43 +08:00
virtual void getUsage ( osg : : ApplicationUsage & usage ) const ;
protected :
2003-09-26 05:54:33 +08:00
2003-09-26 19:20:43 +08:00
~ TechniqueEventHandler ( ) { }
TechniqueEventHandler ( const TechniqueEventHandler & , const osg : : CopyOp & ) { }
osg : : ref_ptr < ForestTechniqueManager > _ForestTechniqueManager ;
} ;
2005-03-12 04:19:16 +08:00
bool TechniqueEventHandler : : handle ( const osgGA : : GUIEventAdapter & ea , osgGA : : GUIActionAdapter & , osg : : Object * , osg : : NodeVisitor * )
2003-09-26 19:20:43 +08:00
{
switch ( ea . getEventType ( ) )
{
case ( osgGA : : GUIEventAdapter : : KEYDOWN ) :
{
if ( ea . getKey ( ) = = ' n ' | |
ea . getKey ( ) = = osgGA : : GUIEventAdapter : : KEY_Right | |
ea . getKey ( ) = = osgGA : : GUIEventAdapter : : KEY_KP_Right )
{
_ForestTechniqueManager - > advanceToNextTechnique ( 1 ) ;
return true ;
}
else if ( ea . getKey ( ) = = ' p ' | |
ea . getKey ( ) = = osgGA : : GUIEventAdapter : : KEY_Left | |
ea . getKey ( ) = = osgGA : : GUIEventAdapter : : KEY_KP_Left )
{
_ForestTechniqueManager - > advanceToNextTechnique ( - 1 ) ;
return true ;
}
return false ;
}
default :
return false ;
}
}
void TechniqueEventHandler : : getUsage ( osg : : ApplicationUsage & usage ) const
{
usage . addKeyboardMouseBinding ( " n or Left Arrow " , " Advance to next technique " ) ;
usage . addKeyboardMouseBinding ( " p or Right Array " , " Move to previous technique " ) ;
}
2003-09-30 21:48:58 +08:00
void ForestTechniqueManager : : Cell : : computeBound ( )
{
_bb . init ( ) ;
for ( CellList : : iterator citr = _cells . begin ( ) ;
citr ! = _cells . end ( ) ;
+ + citr )
{
( * citr ) - > computeBound ( ) ;
_bb . expandBy ( ( * citr ) - > _bb ) ;
}
for ( TreeList : : iterator titr = _trees . begin ( ) ;
titr ! = _trees . end ( ) ;
+ + titr )
{
_bb . expandBy ( ( * titr ) - > _position ) ;
}
}
bool ForestTechniqueManager : : Cell : : divide ( unsigned int maxNumTreesPerCell )
{
if ( _trees . size ( ) < = maxNumTreesPerCell ) return false ;
computeBound ( ) ;
float radius = _bb . radius ( ) ;
float divide_distance = radius * 0.7f ;
if ( devide ( ( _bb . xMax ( ) - _bb . xMin ( ) ) > divide_distance , ( _bb . yMax ( ) - _bb . yMin ( ) ) > divide_distance , ( _bb . zMax ( ) - _bb . zMin ( ) ) > divide_distance ) )
{
// recusively divide the new cells till maxNumTreesPerCell is met.
for ( CellList : : iterator citr = _cells . begin ( ) ;
citr ! = _cells . end ( ) ;
+ + citr )
{
( * citr ) - > divide ( maxNumTreesPerCell ) ;
}
return true ;
}
else
{
return false ;
}
}
bool ForestTechniqueManager : : Cell : : devide ( bool xAxis , bool yAxis , bool zAxis )
{
if ( ! ( xAxis | | yAxis | | zAxis ) ) return false ;
if ( _cells . empty ( ) )
_cells . push_back ( new Cell ( _bb ) ) ;
if ( xAxis )
{
unsigned int numCellsToDivide = _cells . size ( ) ;
for ( unsigned int i = 0 ; i < numCellsToDivide ; + + i )
{
Cell * orig_cell = _cells [ i ] . get ( ) ;
Cell * new_cell = new Cell ( orig_cell - > _bb ) ;
float xCenter = ( orig_cell - > _bb . xMin ( ) + orig_cell - > _bb . xMax ( ) ) * 0.5f ;
orig_cell - > _bb . xMax ( ) = xCenter ;
new_cell - > _bb . xMin ( ) = xCenter ;
_cells . push_back ( new_cell ) ;
}
}
if ( yAxis )
{
unsigned int numCellsToDivide = _cells . size ( ) ;
for ( unsigned int i = 0 ; i < numCellsToDivide ; + + i )
{
Cell * orig_cell = _cells [ i ] . get ( ) ;
Cell * new_cell = new Cell ( orig_cell - > _bb ) ;
float yCenter = ( orig_cell - > _bb . yMin ( ) + orig_cell - > _bb . yMax ( ) ) * 0.5f ;
orig_cell - > _bb . yMax ( ) = yCenter ;
new_cell - > _bb . yMin ( ) = yCenter ;
_cells . push_back ( new_cell ) ;
}
}
if ( zAxis )
{
unsigned int numCellsToDivide = _cells . size ( ) ;
for ( unsigned int i = 0 ; i < numCellsToDivide ; + + i )
{
Cell * orig_cell = _cells [ i ] . get ( ) ;
Cell * new_cell = new Cell ( orig_cell - > _bb ) ;
float zCenter = ( orig_cell - > _bb . zMin ( ) + orig_cell - > _bb . zMax ( ) ) * 0.5f ;
orig_cell - > _bb . zMax ( ) = zCenter ;
new_cell - > _bb . zMin ( ) = zCenter ;
_cells . push_back ( new_cell ) ;
}
}
bin ( ) ;
return true ;
}
void ForestTechniqueManager : : Cell : : bin ( )
{
// put trees in apprpriate cells.
TreeList treesNotAssigned ;
for ( TreeList : : iterator titr = _trees . begin ( ) ;
titr ! = _trees . end ( ) ;
+ + titr )
{
Tree * tree = titr - > get ( ) ;
bool assigned = false ;
for ( CellList : : iterator citr = _cells . begin ( ) ;
citr ! = _cells . end ( ) & & ! assigned ;
+ + citr )
{
if ( ( * citr ) - > contains ( tree - > _position ) )
{
( * citr ) - > addTree ( tree ) ;
assigned = true ;
}
}
if ( ! assigned ) treesNotAssigned . push_back ( tree ) ;
}
// put the unassigned trees back into the original local tree list.
_trees . swap ( treesNotAssigned ) ;
// prune empty cells.
CellList cellsNotEmpty ;
for ( CellList : : iterator citr = _cells . begin ( ) ;
citr ! = _cells . end ( ) ;
+ + citr )
{
if ( ! ( ( * citr ) - > _trees . empty ( ) ) )
{
cellsNotEmpty . push_back ( * citr ) ;
}
}
_cells . swap ( cellsNotEmpty ) ;
}
2003-09-26 19:20:43 +08:00
osg : : Geode * ForestTechniqueManager : : createTerrain ( const osg : : Vec3 & origin , const osg : : Vec3 & size )
2003-09-26 05:54:33 +08:00
{
osg : : Geode * geode = new osg : : Geode ( ) ;
// ---------------------------------------
// Set up a StateSet to texture the objects
// ---------------------------------------
osg : : StateSet * stateset = new osg : : StateSet ( ) ;
osg : : Image * image = osgDB : : readImageFile ( " Images/lz.rgb " ) ;
if ( image )
{
osg : : Texture2D * texture = new osg : : Texture2D ;
texture - > setImage ( image ) ;
stateset - > setTextureAttributeAndModes ( 0 , texture , osg : : StateAttribute : : ON ) ;
}
geode - > setStateSet ( stateset ) ;
unsigned int numColumns = 38 ;
unsigned int numRows = 39 ;
unsigned int r ;
unsigned int c ;
// compute z range of z values of grid data so we can scale it.
float min_z = FLT_MAX ;
float max_z = - FLT_MAX ;
for ( r = 0 ; r < numRows ; + + r )
{
for ( c = 0 ; c < numColumns ; + + c )
{
min_z = osg : : minimum ( min_z , vertex [ r + c * numRows ] [ 2 ] ) ;
max_z = osg : : maximum ( max_z , vertex [ r + c * numRows ] [ 2 ] ) ;
}
}
float scale_z = size . z ( ) / ( max_z - min_z ) ;
bool createGrid = false ;
if ( createGrid )
{
2003-10-28 00:07:21 +08:00
osg : : HeightField * grid = new osg : : HeightField ;
2005-05-09 21:09:07 +08:00
grid - > allocate ( numColumns , numRows ) ;
2003-09-26 05:54:33 +08:00
grid - > setOrigin ( origin ) ;
grid - > setXInterval ( size . x ( ) / ( float ) ( numColumns - 1 ) ) ;
grid - > setYInterval ( size . y ( ) / ( float ) ( numRows - 1 ) ) ;
for ( r = 0 ; r < numRows ; + + r )
{
for ( c = 0 ; c < numColumns ; + + c )
{
grid - > setHeight ( c , r , ( vertex [ r + c * numRows ] [ 2 ] - min_z ) * scale_z ) ;
}
}
geode - > addDrawable ( new osg : : ShapeDrawable ( grid ) ) ;
}
else
{
osg : : Geometry * geometry = new osg : : Geometry ;
osg : : Vec3Array & v = * ( new osg : : Vec3Array ( numColumns * numRows ) ) ;
osg : : Vec2Array & t = * ( new osg : : Vec2Array ( numColumns * numRows ) ) ;
osg : : UByte4Array & color = * ( new osg : : UByte4Array ( 1 ) ) ;
color [ 0 ] . set ( 255 , 255 , 255 , 255 ) ;
float rowCoordDelta = size . y ( ) / ( float ) ( numRows - 1 ) ;
float columnCoordDelta = size . x ( ) / ( float ) ( numColumns - 1 ) ;
float rowTexDelta = 1.0f / ( float ) ( numRows - 1 ) ;
float columnTexDelta = 1.0f / ( float ) ( numColumns - 1 ) ;
osg : : Vec3 pos = origin ;
osg : : Vec2 tex ( 0.0f , 0.0f ) ;
int vi = 0 ;
for ( r = 0 ; r < numRows ; + + r )
{
pos . x ( ) = origin . x ( ) ;
tex . x ( ) = 0.0f ;
for ( c = 0 ; c < numColumns ; + + c )
{
v [ vi ] . set ( pos . x ( ) , pos . y ( ) , pos . z ( ) + ( vertex [ r + c * numRows ] [ 2 ] - min_z ) * scale_z ) ;
t [ vi ] . set ( tex . x ( ) , tex . y ( ) ) ;
pos . x ( ) + = columnCoordDelta ;
tex . x ( ) + = columnTexDelta ;
+ + vi ;
}
pos . y ( ) + = rowCoordDelta ;
tex . y ( ) + = rowTexDelta ;
}
geometry - > setVertexArray ( & v ) ;
geometry - > setColorArray ( & color ) ;
geometry - > setColorBinding ( osg : : Geometry : : BIND_OVERALL ) ;
geometry - > setTexCoordArray ( 0 , & t ) ;
for ( r = 0 ; r < numRows - 1 ; + + r )
{
osg : : DrawElementsUShort & drawElements = * ( new osg : : DrawElementsUShort ( GL_QUAD_STRIP , 2 * numColumns ) ) ;
geometry - > addPrimitiveSet ( & drawElements ) ;
int ei = 0 ;
for ( c = 0 ; c < numColumns ; + + c )
{
drawElements [ ei + + ] = ( r + 1 ) * numColumns + c ;
drawElements [ ei + + ] = ( r ) * numColumns + c ;
}
}
geode - > addDrawable ( geometry ) ;
osgUtil : : SmoothingVisitor sv ;
sv . smooth ( * geometry ) ;
}
return geode ;
}
2003-09-26 19:20:43 +08:00
void ForestTechniqueManager : : createTreeList ( osg : : Node * terrain , const osg : : Vec3 & origin , const osg : : Vec3 & size , unsigned int numTreesToCreate , TreeList & trees )
2003-09-26 05:54:33 +08:00
{
float max_TreeHeight = sqrtf ( size . length2 ( ) / ( float ) numTreesToCreate ) ;
float max_TreeWidth = max_TreeHeight * 0.5f ;
float min_TreeHeight = max_TreeHeight * 0.3f ;
float min_TreeWidth = min_TreeHeight * 0.5f ;
trees . reserve ( trees . size ( ) + numTreesToCreate ) ;
for ( unsigned int i = 0 ; i < numTreesToCreate ; + + i )
{
Tree * tree = new Tree ;
tree - > _position . set ( random ( origin . x ( ) , origin . x ( ) + size . x ( ) ) , random ( origin . y ( ) , origin . y ( ) + size . y ( ) ) , origin . z ( ) ) ;
tree - > _color . set ( random ( 128 , 255 ) , random ( 128 , 255 ) , random ( 128 , 255 ) , 255 ) ;
tree - > _width = random ( min_TreeWidth , max_TreeWidth ) ;
tree - > _height = random ( min_TreeHeight , max_TreeHeight ) ;
tree - > _type = 0 ;
if ( terrain )
{
osgUtil : : IntersectVisitor iv ;
osg : : ref_ptr < osg : : LineSegment > segDown = new osg : : LineSegment ;
segDown - > set ( tree - > _position , tree - > _position + osg : : Vec3 ( 0.0f , 0.0f , size . z ( ) ) ) ;
iv . addLineSegment ( segDown . get ( ) ) ;
terrain - > accept ( iv ) ;
if ( iv . hits ( ) )
{
osgUtil : : IntersectVisitor : : HitList & hitList = iv . getHitList ( segDown . get ( ) ) ;
if ( ! hitList . empty ( ) )
{
osg : : Vec3 ip = hitList . front ( ) . getWorldIntersectPoint ( ) ;
osg : : Vec3 np = hitList . front ( ) . getWorldIntersectNormal ( ) ;
tree - > _position = ip ;
}
}
}
trees . push_back ( tree ) ;
}
}
2003-09-26 19:20:43 +08:00
osg : : Geometry * ForestTechniqueManager : : createSprite ( float w , float h , osg : : UByte4 color )
2003-09-26 05:54:33 +08:00
{
// set up the coords
osg : : Vec3Array & v = * ( new osg : : Vec3Array ( 4 ) ) ;
osg : : Vec2Array & t = * ( new osg : : Vec2Array ( 4 ) ) ;
osg : : UByte4Array & c = * ( new osg : : UByte4Array ( 1 ) ) ;
v [ 0 ] . set ( - w * 0.5f , 0.0f , 0.0f ) ;
v [ 1 ] . set ( w * 0.5f , 0.0f , 0.0f ) ;
v [ 2 ] . set ( w * 0.5f , 0.0f , h ) ;
v [ 3 ] . set ( - w * 0.5f , 0.0f , h ) ;
c [ 0 ] = color ;
t [ 0 ] . set ( 0.0f , 0.0f ) ;
t [ 1 ] . set ( 1.0f , 0.0f ) ;
t [ 2 ] . set ( 1.0f , 1.0f ) ;
t [ 3 ] . set ( 0.0f , 1.0f ) ;
osg : : Geometry * geom = new osg : : Geometry ;
geom - > setVertexArray ( & v ) ;
geom - > setTexCoordArray ( 0 , & t ) ;
geom - > setColorArray ( & c ) ;
geom - > setColorBinding ( osg : : Geometry : : BIND_OVERALL ) ;
geom - > addPrimitiveSet ( new osg : : DrawArrays ( osg : : PrimitiveSet : : QUADS , 0 , 4 ) ) ;
return geom ;
}
2003-09-26 19:20:43 +08:00
osg : : Geometry * ForestTechniqueManager : : createOrthogonalQuads ( const osg : : Vec3 & pos , float w , float h , osg : : UByte4 color )
2003-09-26 05:54:33 +08:00
{
// set up the coords
osg : : Vec3Array & v = * ( new osg : : Vec3Array ( 8 ) ) ;
osg : : Vec2Array & t = * ( new osg : : Vec2Array ( 8 ) ) ;
osg : : UByte4Array & c = * ( new osg : : UByte4Array ( 1 ) ) ;
float rotation = random ( 0.0f , osg : : PI / 2.0f ) ;
float sw = sinf ( rotation ) * w * 0.5f ;
float cw = cosf ( rotation ) * w * 0.5f ;
v [ 0 ] . set ( pos . x ( ) - sw , pos . y ( ) - cw , pos . z ( ) + 0.0f ) ;
v [ 1 ] . set ( pos . x ( ) + sw , pos . y ( ) + cw , pos . z ( ) + 0.0f ) ;
v [ 2 ] . set ( pos . x ( ) + sw , pos . y ( ) + cw , pos . z ( ) + h ) ;
v [ 3 ] . set ( pos . x ( ) - sw , pos . y ( ) - cw , pos . z ( ) + h ) ;
v [ 4 ] . set ( pos . x ( ) - cw , pos . y ( ) + sw , pos . z ( ) + 0.0f ) ;
v [ 5 ] . set ( pos . x ( ) + cw , pos . y ( ) - sw , pos . z ( ) + 0.0f ) ;
v [ 6 ] . set ( pos . x ( ) + cw , pos . y ( ) - sw , pos . z ( ) + h ) ;
v [ 7 ] . set ( pos . x ( ) - cw , pos . y ( ) + sw , pos . z ( ) + h ) ;
c [ 0 ] = color ;
t [ 0 ] . set ( 0.0f , 0.0f ) ;
t [ 1 ] . set ( 1.0f , 0.0f ) ;
t [ 2 ] . set ( 1.0f , 1.0f ) ;
t [ 3 ] . set ( 0.0f , 1.0f ) ;
t [ 4 ] . set ( 0.0f , 0.0f ) ;
t [ 5 ] . set ( 1.0f , 0.0f ) ;
t [ 6 ] . set ( 1.0f , 1.0f ) ;
t [ 7 ] . set ( 0.0f , 1.0f ) ;
osg : : Geometry * geom = new osg : : Geometry ;
geom - > setVertexArray ( & v ) ;
geom - > setTexCoordArray ( 0 , & t ) ;
geom - > setColorArray ( & c ) ;
geom - > setColorBinding ( osg : : Geometry : : BIND_OVERALL ) ;
geom - > addPrimitiveSet ( new osg : : DrawArrays ( osg : : PrimitiveSet : : QUADS , 0 , 8 ) ) ;
return geom ;
}
2003-09-30 21:48:58 +08:00
osg : : Node * ForestTechniqueManager : : createBillboardGraph ( Cell * cell , osg : : StateSet * stateset )
2003-09-26 05:54:33 +08:00
{
2003-09-30 21:48:58 +08:00
bool needGroup = ! ( cell - > _cells . empty ( ) ) ;
bool needBillboard = ! ( cell - > _trees . empty ( ) ) ;
2003-09-26 05:54:33 +08:00
2003-09-30 21:48:58 +08:00
osg : : Billboard * billboard = 0 ;
osg : : Group * group = 0 ;
2003-09-26 05:54:33 +08:00
2003-09-30 21:48:58 +08:00
if ( needBillboard )
2003-09-26 05:54:33 +08:00
{
2003-09-30 21:48:58 +08:00
billboard = new osg : : Billboard ;
billboard - > setStateSet ( stateset ) ;
for ( TreeList : : iterator itr = cell - > _trees . begin ( ) ;
itr ! = cell - > _trees . end ( ) ;
2003-09-26 05:54:33 +08:00
+ + itr )
{
Tree & tree = * * itr ;
billboard - > addDrawable ( createSprite ( tree . _width , tree . _height , tree . _color ) , tree . _position ) ;
}
2003-09-30 21:48:58 +08:00
}
2003-09-26 05:54:33 +08:00
2003-09-30 21:48:58 +08:00
if ( needGroup )
{
group = new osg : : Group ;
for ( Cell : : CellList : : iterator itr = cell - > _cells . begin ( ) ;
itr ! = cell - > _cells . end ( ) ;
+ + itr )
{
group - > addChild ( createBillboardGraph ( itr - > get ( ) , stateset ) ) ;
}
if ( billboard ) group - > addChild ( billboard ) ;
2003-09-26 05:54:33 +08:00
}
2003-09-30 21:48:58 +08:00
if ( group ) return group ;
else return billboard ;
}
2003-09-26 05:54:33 +08:00
2003-09-30 21:48:58 +08:00
osg : : Node * ForestTechniqueManager : : createXGraph ( Cell * cell , osg : : StateSet * stateset )
{
bool needGroup = ! ( cell - > _cells . empty ( ) ) ;
bool needTrees = ! ( cell - > _trees . empty ( ) ) ;
osg : : Geode * geode = 0 ;
osg : : Group * group = 0 ;
if ( needTrees )
2003-09-26 05:54:33 +08:00
{
2003-09-30 21:48:58 +08:00
geode = new osg : : Geode ;
geode - > setStateSet ( stateset ) ;
2003-09-26 05:54:33 +08:00
2003-09-30 21:48:58 +08:00
for ( TreeList : : iterator itr = cell - > _trees . begin ( ) ;
itr ! = cell - > _trees . end ( ) ;
2003-09-26 05:54:33 +08:00
+ + itr )
{
Tree & tree = * * itr ;
geode - > addDrawable ( createOrthogonalQuads ( tree . _position , tree . _width , tree . _height , tree . _color ) ) ;
}
2003-09-30 21:48:58 +08:00
}
if ( needGroup )
{
group = new osg : : Group ;
for ( Cell : : CellList : : iterator itr = cell - > _cells . begin ( ) ;
itr ! = cell - > _cells . end ( ) ;
+ + itr )
{
group - > addChild ( createXGraph ( itr - > get ( ) , stateset ) ) ;
}
if ( geode ) group - > addChild ( geode ) ;
2003-09-26 05:54:33 +08:00
}
2003-09-30 21:48:58 +08:00
if ( group ) return group ;
else return geode ;
}
2003-09-26 05:54:33 +08:00
2003-09-30 21:48:58 +08:00
osg : : Node * ForestTechniqueManager : : createTransformGraph ( Cell * cell , osg : : StateSet * stateset )
{
bool needGroup = ! ( cell - > _cells . empty ( ) ) ;
bool needTrees = ! ( cell - > _trees . empty ( ) ) ;
osg : : Group * transform_group = 0 ;
osg : : Group * group = 0 ;
if ( needTrees )
2003-09-26 05:54:33 +08:00
{
2003-09-30 21:48:58 +08:00
transform_group = new osg : : Group ;
2003-09-26 05:54:33 +08:00
osg : : Geometry * geometry = createOrthogonalQuads ( osg : : Vec3 ( 0.0f , 0.0f , 0.0f ) , 1.0f , 1.0f , osg : : UByte4 ( 255 , 255 , 255 , 255 ) ) ;
2003-09-30 21:48:58 +08:00
for ( TreeList : : iterator itr = cell - > _trees . begin ( ) ;
itr ! = cell - > _trees . end ( ) ;
2003-09-26 05:54:33 +08:00
+ + itr )
{
Tree & tree = * * itr ;
osg : : MatrixTransform * transform = new osg : : MatrixTransform ;
transform - > setMatrix ( osg : : Matrix : : scale ( tree . _width , tree . _width , tree . _height ) * osg : : Matrix : : translate ( tree . _position ) ) ;
osg : : Geode * geode = new osg : : Geode ;
2003-09-30 21:48:58 +08:00
geode - > setStateSet ( stateset ) ;
2003-09-26 05:54:33 +08:00
geode - > addDrawable ( geometry ) ;
transform - > addChild ( geode ) ;
transform_group - > addChild ( transform ) ;
}
2003-09-30 21:48:58 +08:00
}
if ( needGroup )
{
group = new osg : : Group ;
for ( Cell : : CellList : : iterator itr = cell - > _cells . begin ( ) ;
itr ! = cell - > _cells . end ( ) ;
+ + itr )
{
group - > addChild ( createTransformGraph ( itr - > get ( ) , stateset ) ) ;
}
if ( transform_group ) group - > addChild ( transform_group ) ;
2003-09-26 05:54:33 +08:00
}
2003-09-30 21:48:58 +08:00
if ( group ) return group ;
else return transform_group ;
}
2003-09-30 23:50:46 +08:00
osg : : Node * ForestTechniqueManager : : createHUDWithText ( const std : : string & str )
{
osg : : Geode * geode = new osg : : Geode ( ) ;
std : : string timesFont ( " fonts/arial.ttf " ) ;
// turn lighting off for the text and disable depth test to ensure its always ontop.
osg : : StateSet * stateset = geode - > getOrCreateStateSet ( ) ;
stateset - > setMode ( GL_LIGHTING , osg : : StateAttribute : : OFF ) ;
2003-09-30 21:48:58 +08:00
2003-09-30 23:50:46 +08:00
// or disable depth test, and make sure that the hud is drawn after everything
// else so that it always appears ontop.
stateset - > setMode ( GL_DEPTH_TEST , osg : : StateAttribute : : OFF ) ;
stateset - > setRenderBinDetails ( 11 , " RenderBin " ) ;
osg : : Vec3 position ( 150.0f , 800.0f , 0.0f ) ;
osg : : Vec3 delta ( 0.0f , - 120.0f , 0.0f ) ;
{
osgText : : Text * text = new osgText : : Text ;
geode - > addDrawable ( text ) ;
text - > setFont ( timesFont ) ;
text - > setPosition ( position ) ;
text - > setText ( str ) ;
position + = delta ;
}
// create the hud.
osg : : MatrixTransform * modelview_abs = new osg : : MatrixTransform ;
2004-10-25 04:04:00 +08:00
modelview_abs - > setReferenceFrame ( osg : : Transform : : ABSOLUTE_RF ) ;
2003-09-30 23:50:46 +08:00
modelview_abs - > setMatrix ( osg : : Matrix : : identity ( ) ) ;
modelview_abs - > addChild ( geode ) ;
osg : : Projection * projection = new osg : : Projection ;
projection - > setMatrix ( osg : : Matrix : : ortho2D ( 0 , 1280 , 0 , 1024 ) ) ;
projection - > addChild ( modelview_abs ) ;
return projection ;
}
osg : : Node * ForestTechniqueManager : : createScene ( unsigned int numTreesToCreates )
2003-09-30 21:48:58 +08:00
{
osg : : Vec3 origin ( 0.0f , 0.0f , 0.0f ) ;
osg : : Vec3 size ( 1000.0f , 1000.0f , 200.0f ) ;
std : : cout < < " Creating terrain... " ;
osg : : ref_ptr < osg : : Node > terrain = createTerrain ( origin , size ) ;
std : : cout < < " done. " < < std : : endl ;
std : : cout < < " Creating tree locations... " ; std : : cout . flush ( ) ;
TreeList trees ;
createTreeList ( terrain . get ( ) , origin , size , numTreesToCreates , trees ) ;
std : : cout < < " done. " < < std : : endl ;
std : : cout < < " Creating cell subdivision... " ;
osg : : ref_ptr < Cell > cell = new Cell ;
cell - > addTrees ( trees ) ;
cell - > divide ( ) ;
std : : cout < < " done. " < < std : : endl ;
osg : : Texture2D * tex = new osg : : Texture2D ;
2003-10-17 18:22:46 +08:00
tex - > setWrap ( osg : : Texture2D : : WRAP_S , osg : : Texture2D : : CLAMP ) ;
tex - > setWrap ( osg : : Texture2D : : WRAP_T , osg : : Texture2D : : CLAMP ) ;
2003-09-30 21:48:58 +08:00
tex - > setImage ( osgDB : : readImageFile ( " Images/tree0.rgba " ) ) ;
osg : : StateSet * dstate = new osg : : StateSet ;
{
dstate - > setTextureAttributeAndModes ( 0 , tex , osg : : StateAttribute : : ON ) ;
dstate - > setTextureAttribute ( 0 , new osg : : TexEnv ) ;
dstate - > setAttributeAndModes ( new osg : : BlendFunc , osg : : StateAttribute : : ON ) ;
osg : : AlphaFunc * alphaFunc = new osg : : AlphaFunc ;
alphaFunc - > setFunction ( osg : : AlphaFunc : : GEQUAL , 0.05f ) ;
dstate - > setAttributeAndModes ( alphaFunc , osg : : StateAttribute : : ON ) ;
dstate - > setMode ( GL_LIGHTING , osg : : StateAttribute : : OFF ) ;
dstate - > setRenderingHint ( osg : : StateSet : : TRANSPARENT_BIN ) ;
}
_techniqueSwitch = new osg : : Switch ;
2003-09-30 23:50:46 +08:00
{
std : : cout < < " Creating billboard based forest... " ;
osg : : Group * group = new osg : : Group ;
group - > addChild ( createBillboardGraph ( cell . get ( ) , dstate ) ) ;
group - > addChild ( createHUDWithText ( " Using osg::Billboard's to create a forest \n \n Press left cursor key to select osg::MatrixTransform based forest \n Press right cursor key to select double quad based forest " ) ) ;
_techniqueSwitch - > addChild ( group ) ;
std : : cout < < " done. " < < std : : endl ;
}
{
std : : cout < < " Creating billboard based forest... " ;
osg : : Group * group = new osg : : Group ;
group - > addChild ( createXGraph ( cell . get ( ) , dstate ) ) ;
group - > addChild ( createHUDWithText ( " Using double quads to create a forest \n \n Press left cursor key to select osg::Billboard based forest \n Press right cursor key to select osg::MatrixTransform based forest \n " ) ) ;
_techniqueSwitch - > addChild ( group ) ;
std : : cout < < " done. " < < std : : endl ;
}
2003-09-30 21:48:58 +08:00
2003-09-30 23:50:46 +08:00
{
std : : cout < < " Creating billboard based forest... " ;
osg : : Group * group = new osg : : Group ;
group - > addChild ( createTransformGraph ( cell . get ( ) , dstate ) ) ;
group - > addChild ( createHUDWithText ( " Using osg::MatrixTransform's to create a forest \n \n Press left cursor key to select double quad based forest \n Press right cursor key to select osg::Billboard based forest " ) ) ;
_techniqueSwitch - > addChild ( group ) ;
std : : cout < < " done. " < < std : : endl ;
}
2003-09-26 05:54:33 +08:00
2003-09-26 19:20:43 +08:00
_currentTechnique = 0 ;
_techniqueSwitch - > setSingleChildOn ( _currentTechnique ) ;
2003-09-26 05:54:33 +08:00
osg : : Group * scene = new osg : : Group ;
scene - > addChild ( terrain . get ( ) ) ;
2003-09-26 19:20:43 +08:00
scene - > addChild ( _techniqueSwitch . get ( ) ) ;
2003-09-26 05:54:33 +08:00
return scene ;
}
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 ( ) - > setDescription ( arguments . getApplicationName ( ) + " is the example which demonstrates the osg::Shape classes. " ) ;
arguments . getApplicationUsage ( ) - > setCommandLineUsage ( arguments . getApplicationName ( ) + " [options] filename ... " ) ;
arguments . getApplicationUsage ( ) - > addCommandLineOption ( " -h or --help " , " Display this information " ) ;
2003-09-30 23:50:46 +08:00
arguments . getApplicationUsage ( ) - > addCommandLineOption ( " --trees <number> " , " Set the number of trees to create " ) ;
2003-09-26 05:54:33 +08:00
// construct the viewer.
osgProducer : : Viewer viewer ( arguments ) ;
2003-09-30 23:50:46 +08:00
float numTreesToCreates = 10000 ;
arguments . read ( " --trees " , numTreesToCreates ) ;
2003-09-26 05:54:33 +08:00
// set up the value with sensible default event handlers.
viewer . setUpViewer ( osgProducer : : Viewer : : STANDARD_SETTINGS ) ;
2003-09-26 19:20:43 +08:00
osg : : ref_ptr < ForestTechniqueManager > ttm = new ForestTechniqueManager ;
viewer . getEventHandlerList ( ) . push_front ( new TechniqueEventHandler ( ttm . get ( ) ) ) ;
2003-09-26 05:54:33 +08:00
// get details on keyboard and mouse bindings used by the viewer.
viewer . getUsage ( * arguments . getApplicationUsage ( ) ) ;
// if user request help write it out to cout.
if ( arguments . read ( " -h " ) | | arguments . read ( " --help " ) )
{
arguments . getApplicationUsage ( ) - > write ( std : : cout ) ;
return 1 ;
}
// any option left unread are converted into errors to write out later.
arguments . reportRemainingOptionsAsUnrecognized ( ) ;
// report any errors if they have occured when parsing the program aguments.
if ( arguments . errors ( ) )
{
arguments . writeErrorMessages ( std : : cout ) ;
return 1 ;
}
2003-09-30 23:50:46 +08:00
osg : : Node * node = ttm - > createScene ( ( unsigned int ) numTreesToCreates ) ;
2003-09-26 05:54:33 +08:00
// add model to viewer.
viewer . setSceneData ( node ) ;
// create the windows and run the threads.
viewer . realize ( ) ;
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 ( ) ;
// fire off the cull and draw traversals of the scene.
viewer . frame ( ) ;
}
// wait for all cull and draw threads to complete before exit.
viewer . sync ( ) ;
return 0 ;
}