root/OpenSceneGraph/trunk/examples/osgforest/osgforest.cpp @ 5636

Revision 5636, 34.5 kB (checked in by robert, 8 years ago)

Removed deprecated GUIEventHandler method

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1#include <osg/AlphaFunc>
2#include <osg/Billboard>
3#include <osg/BlendFunc>
4#include <osg/Depth>
5#include <osg/Geode>
6#include <osg/Geometry>
7#include <osg/Material>
8#include <osg/Math>
9#include <osg/MatrixTransform>
10#include <osg/PolygonOffset>
11#include <osg/Projection>
12#include <osg/ShapeDrawable>
13#include <osg/StateSet>
14#include <osg/Switch>
15#include <osg/Texture2D>
16#include <osg/TexEnv>
17
18#include <osgDB/ReadFile>
19#include <osgDB/FileUtils>
20
21#include <osgUtil/IntersectVisitor>
22#include <osgUtil/SmoothingVisitor>
23
24#include <osgText/Text>
25
26#include <osgProducer/Viewer>
27
28// for the grid data..
29#include "../osghangglide/terrain_coords.h"
30
31// class to create the forest and manage the movement between various techniques.
32class ForestTechniqueManager : public osg::Referenced
33{
34public:
35
36    ForestTechniqueManager() {}
37
38    class Tree : public osg::Referenced
39    {
40    public:
41
42        Tree():
43            _color(255,255,255,255),
44            _width(1.0f),
45            _height(1.0f),
46            _type(0) {}
47
48        Tree(const osg::Vec3& position, const osg::Vec4ub& color, float width, float height, unsigned int type):
49            _position(position),
50            _color(color),
51            _width(width),
52            _height(height),
53            _type(type) {}
54
55        osg::Vec3       _position;
56        osg::Vec4ub     _color;
57        float           _width;
58        float           _height;
59        unsigned int    _type;
60    };
61   
62    typedef std::vector< osg::ref_ptr<Tree> > TreeList;
63   
64    class Cell : public osg::Referenced
65    {
66    public:
67        typedef std::vector< osg::ref_ptr<Cell> > CellList;
68
69        Cell():_parent(0) {}
70        Cell(osg::BoundingBox& bb):_parent(0), _bb(bb) {}
71       
72        void addCell(Cell* cell) { cell->_parent=this; _cells.push_back(cell); }
73
74        void addTree(Tree* tree) { _trees.push_back(tree); }
75       
76        void addTrees(const TreeList& trees) { _trees.insert(_trees.end(),trees.begin(),trees.end()); }
77       
78        void computeBound();
79       
80        bool contains(const osg::Vec3& position) const { return _bb.contains(position); }
81       
82        bool divide(unsigned int maxNumTreesPerCell=10);
83       
84        bool devide(bool xAxis, bool yAxis, bool zAxis);
85       
86        void bin();
87
88
89        Cell*               _parent;
90        osg::BoundingBox    _bb;
91        CellList            _cells;
92        TreeList            _trees;
93       
94    };
95
96    float random(float min,float max) { return min + (max-min)*(float)rand()/(float)RAND_MAX; }
97    int random(int min,int max) { return min + (int)((float)(max-min)*(float)rand()/(float)RAND_MAX); }
98
99    osg::Geode* createTerrain(const osg::Vec3& origin, const osg::Vec3& size);
100
101    void createTreeList(osg::Node* terrain,const osg::Vec3& origin, const osg::Vec3& size,unsigned int numTreesToCreate,TreeList& trees);
102
103    osg::Geometry* createSprite( float w, float h, osg::Vec4ub color );
104
105    osg::Geometry* createOrthogonalQuads( const osg::Vec3& pos, float w, float h, osg::Vec4ub color );
106    osg::Geometry* createOrthogonalQuadsNoColor( const osg::Vec3& pos, float w, float h );
107
108    osg::Node* createBillboardGraph(Cell* cell,osg::StateSet* stateset);
109
110    osg::Node* createXGraph(Cell* cell,osg::StateSet* stateset);
111
112    osg::Node* createTransformGraph(Cell* cell,osg::StateSet* stateset);
113
114    osg::Node* createShaderGraph(Cell* cell,osg::StateSet* stateset);
115   
116    osg::Node* createHUDWithText(const std::string& text);
117
118    osg::Node* createScene(unsigned int numTreesToCreates);
119   
120    void advanceToNextTechnique(int delta=1)
121    {
122        if (_techniqueSwitch.valid())
123        {
124            _currentTechnique += delta;
125            if (_currentTechnique<0)
126                _currentTechnique = _techniqueSwitch->getNumChildren()-1;
127            if (_currentTechnique>=(int)_techniqueSwitch->getNumChildren())
128                _currentTechnique = 0;
129            _techniqueSwitch->setSingleChildOn(_currentTechnique);
130        }
131    }
132   
133    osg::ref_ptr<osg::Switch>   _techniqueSwitch;
134    int                         _currentTechnique;
135   
136
137};
138
139// event handler to capture keyboard events and use them to advance the technique used for rendering
140class TechniqueEventHandler : public osgGA::GUIEventHandler
141{
142public:
143
144    TechniqueEventHandler(ForestTechniqueManager* ttm=0) { _ForestTechniqueManager = ttm; }
145   
146    META_Object(osgforestApp,TechniqueEventHandler);
147
148    virtual bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter&, osg::Object*, osg::NodeVisitor*);
149   
150    virtual void getUsage(osg::ApplicationUsage& usage) const;
151
152protected:
153
154    ~TechniqueEventHandler() {}
155   
156    TechniqueEventHandler(const TechniqueEventHandler&,const osg::CopyOp&) {}
157   
158    osg::ref_ptr<ForestTechniqueManager> _ForestTechniqueManager;
159
160       
161};
162
163bool TechniqueEventHandler::handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter&, osg::Object*, osg::NodeVisitor*)
164{
165    switch(ea.getEventType())
166    {
167        case(osgGA::GUIEventAdapter::KEYDOWN):
168        {
169            if (ea.getKey()=='n' ||
170                ea.getKey()==osgGA::GUIEventAdapter::KEY_Right ||
171                ea.getKey()==osgGA::GUIEventAdapter::KEY_KP_Right)
172            {
173                _ForestTechniqueManager->advanceToNextTechnique(1);
174                return true;
175            }
176            else if (ea.getKey()=='p' ||
177                     ea.getKey()==osgGA::GUIEventAdapter::KEY_Left ||
178                     ea.getKey()==osgGA::GUIEventAdapter::KEY_KP_Left)
179            {
180                _ForestTechniqueManager->advanceToNextTechnique(-1);
181                return true;
182            }
183            return false;
184        }
185
186        default:
187            return false;
188    }
189}
190
191void TechniqueEventHandler::getUsage(osg::ApplicationUsage& usage) const
192{
193    usage.addKeyboardMouseBinding("n or Left Arrow","Advance to next technique");
194    usage.addKeyboardMouseBinding("p or Right Array","Move to previous technique");
195}
196
197
198void ForestTechniqueManager::Cell::computeBound()
199{
200    _bb.init();
201    for(CellList::iterator citr=_cells.begin();
202        citr!=_cells.end();
203        ++citr)
204    {
205        (*citr)->computeBound();
206        _bb.expandBy((*citr)->_bb);
207    }
208
209    for(TreeList::iterator titr=_trees.begin();
210        titr!=_trees.end();
211        ++titr)
212    {
213        _bb.expandBy((*titr)->_position);
214    }
215}
216
217bool ForestTechniqueManager::Cell::divide(unsigned int maxNumTreesPerCell)
218{
219
220    if (_trees.size()<=maxNumTreesPerCell) return false;
221
222    computeBound();
223
224    float radius = _bb.radius();
225    float divide_distance = radius*0.7f;
226    if (devide((_bb.xMax()-_bb.xMin())>divide_distance,(_bb.yMax()-_bb.yMin())>divide_distance,(_bb.zMax()-_bb.zMin())>divide_distance))
227    {
228        // recusively divide the new cells till maxNumTreesPerCell is met.
229        for(CellList::iterator citr=_cells.begin();
230            citr!=_cells.end();
231            ++citr)
232        {
233            (*citr)->divide(maxNumTreesPerCell);
234        }
235        return true;
236   }
237   else
238   {
239        return false;
240   }
241}
242
243bool ForestTechniqueManager::Cell::devide(bool xAxis, bool yAxis, bool zAxis)
244{
245    if (!(xAxis || yAxis || zAxis)) return false;
246
247    if (_cells.empty())
248        _cells.push_back(new Cell(_bb));
249
250    if (xAxis)
251    {
252        unsigned int numCellsToDivide=_cells.size();
253        for(unsigned int i=0;i<numCellsToDivide;++i)
254        {
255            Cell* orig_cell = _cells[i].get();
256            Cell* new_cell = new Cell(orig_cell->_bb);
257
258            float xCenter = (orig_cell->_bb.xMin()+orig_cell->_bb.xMax())*0.5f;
259            orig_cell->_bb.xMax() = xCenter;
260            new_cell->_bb.xMin() = xCenter;
261
262            _cells.push_back(new_cell);
263        }
264    }
265
266    if (yAxis)
267    {
268        unsigned int numCellsToDivide=_cells.size();
269        for(unsigned int i=0;i<numCellsToDivide;++i)
270        {
271            Cell* orig_cell = _cells[i].get();
272            Cell* new_cell = new Cell(orig_cell->_bb);
273
274            float yCenter = (orig_cell->_bb.yMin()+orig_cell->_bb.yMax())*0.5f;
275            orig_cell->_bb.yMax() = yCenter;
276            new_cell->_bb.yMin() = yCenter;
277
278            _cells.push_back(new_cell);
279        }
280    }
281
282    if (zAxis)
283    {
284        unsigned int numCellsToDivide=_cells.size();
285        for(unsigned int i=0;i<numCellsToDivide;++i)
286        {
287            Cell* orig_cell = _cells[i].get();
288            Cell* new_cell = new Cell(orig_cell->_bb);
289
290            float zCenter = (orig_cell->_bb.zMin()+orig_cell->_bb.zMax())*0.5f;
291            orig_cell->_bb.zMax() = zCenter;
292            new_cell->_bb.zMin() = zCenter;
293
294            _cells.push_back(new_cell);
295        }
296    }
297
298    bin();
299
300    return true;
301
302}
303
304void ForestTechniqueManager::Cell::bin()
305{   
306    // put trees in apprpriate cells.
307    TreeList treesNotAssigned;
308    for(TreeList::iterator titr=_trees.begin();
309        titr!=_trees.end();
310        ++titr)
311    {
312        Tree* tree = titr->get();
313        bool assigned = false;
314        for(CellList::iterator citr=_cells.begin();
315            citr!=_cells.end() && !assigned;
316            ++citr)
317        {
318            if ((*citr)->contains(tree->_position))
319            {
320                (*citr)->addTree(tree);
321                assigned = true;
322            }
323        }
324        if (!assigned) treesNotAssigned.push_back(tree);
325    }
326
327    // put the unassigned trees back into the original local tree list.
328    _trees.swap(treesNotAssigned);
329
330
331    // prune empty cells.
332    CellList cellsNotEmpty;
333    for(CellList::iterator citr=_cells.begin();
334        citr!=_cells.end();
335        ++citr)
336    {
337        if (!((*citr)->_trees.empty()))
338        {
339            cellsNotEmpty.push_back(*citr);
340        }
341    }
342    _cells.swap(cellsNotEmpty);
343
344
345}
346
347osg::Geode* ForestTechniqueManager::createTerrain(const osg::Vec3& origin, const osg::Vec3& size)
348{
349    osg::Geode* geode = new osg::Geode();
350
351    // ---------------------------------------
352    // Set up a StateSet to texture the objects
353    // ---------------------------------------
354    osg::StateSet* stateset = new osg::StateSet();
355
356    osg::Image* image = osgDB::readImageFile("Images/lz.rgb");
357    if (image)
358    {
359        osg::Texture2D* texture = new osg::Texture2D;
360        texture->setImage(image);
361        stateset->setTextureAttributeAndModes(0,texture,osg::StateAttribute::ON);
362    }
363   
364    geode->setStateSet( stateset );
365   
366    unsigned int numColumns = 38;
367    unsigned int numRows = 39;
368    unsigned int r;
369    unsigned int c;
370
371    // compute z range of z values of grid data so we can scale it.
372    float min_z = FLT_MAX;
373    float max_z = -FLT_MAX;
374    for(r=0;r<numRows;++r)
375    {
376        for(c=0;c<numColumns;++c)
377        {
378            min_z = osg::minimum(min_z,vertex[r+c*numRows][2]);
379            max_z = osg::maximum(max_z,vertex[r+c*numRows][2]);
380        }
381    }
382   
383    float scale_z = size.z()/(max_z-min_z);
384
385
386    bool createGrid = false;
387    if (createGrid)
388    {
389
390        osg::HeightField* grid = new osg::HeightField;
391        grid->allocate(numColumns,numRows);
392        grid->setOrigin(origin);
393        grid->setXInterval(size.x()/(float)(numColumns-1));
394        grid->setYInterval(size.y()/(float)(numRows-1));
395
396        for(r=0;r<numRows;++r)
397        {
398            for(c=0;c<numColumns;++c)
399            {
400                grid->setHeight(c,r,(vertex[r+c*numRows][2]-min_z)*scale_z);
401            }
402        }
403       
404        geode->addDrawable(new osg::ShapeDrawable(grid));
405    }
406    else
407    {
408        osg::Geometry* geometry = new osg::Geometry;
409       
410        osg::Vec3Array& v = *(new osg::Vec3Array(numColumns*numRows));
411        osg::Vec2Array& t = *(new osg::Vec2Array(numColumns*numRows));
412        osg::Vec4ubArray& color = *(new osg::Vec4ubArray(1));
413       
414        color[0].set(255,255,255,255);
415
416        float rowCoordDelta = size.y()/(float)(numRows-1);
417        float columnCoordDelta = size.x()/(float)(numColumns-1);
418       
419        float rowTexDelta = 1.0f/(float)(numRows-1);
420        float columnTexDelta = 1.0f/(float)(numColumns-1);
421
422        osg::Vec3 pos = origin;
423        osg::Vec2 tex(0.0f,0.0f);
424        int vi=0;
425        for(r=0;r<numRows;++r)
426        {
427            pos.x() = origin.x();
428            tex.x() = 0.0f;
429            for(c=0;c<numColumns;++c)
430            {
431                v[vi].set(pos.x(),pos.y(),pos.z()+(vertex[r+c*numRows][2]-min_z)*scale_z);
432                t[vi].set(tex.x(),tex.y());
433                pos.x()+=columnCoordDelta;
434                tex.x()+=columnTexDelta;
435                ++vi;
436            }
437            pos.y() += rowCoordDelta;
438            tex.y() += rowTexDelta;
439        }
440       
441        geometry->setVertexArray(&v);
442        geometry->setColorArray(&color);
443        geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
444        geometry->setTexCoordArray(0,&t);
445       
446        for(r=0;r<numRows-1;++r)
447        {
448            osg::DrawElementsUShort& drawElements = *(new osg::DrawElementsUShort(GL_QUAD_STRIP,2*numColumns));
449            geometry->addPrimitiveSet(&drawElements);
450            int ei=0;
451            for(c=0;c<numColumns;++c)
452            {
453                drawElements[ei++] = (r+1)*numColumns+c;
454                drawElements[ei++] = (r)*numColumns+c;
455            }
456        }
457       
458        geode->addDrawable(geometry);
459       
460        osgUtil::SmoothingVisitor sv;
461        sv.smooth(*geometry);
462    }
463   
464    return geode;
465}
466
467void ForestTechniqueManager::createTreeList(osg::Node* terrain,const osg::Vec3& origin, const osg::Vec3& size,unsigned int numTreesToCreate,TreeList& trees)
468{
469
470    float max_TreeHeight = sqrtf(size.length2()/(float)numTreesToCreate);
471    float max_TreeWidth = max_TreeHeight*0.5f;
472   
473    float min_TreeHeight = max_TreeHeight*0.3f;
474    float min_TreeWidth = min_TreeHeight*0.5f;
475
476    trees.reserve(trees.size()+numTreesToCreate);
477
478
479    for(unsigned int i=0;i<numTreesToCreate;++i)
480    {
481        Tree* tree = new Tree;
482        tree->_position.set(random(origin.x(),origin.x()+size.x()),random(origin.y(),origin.y()+size.y()),origin.z());
483        tree->_color.set(random(128,255),random(128,255),random(128,255),255);
484        tree->_width = random(min_TreeWidth,max_TreeWidth);
485        tree->_height = random(min_TreeHeight,max_TreeHeight);
486        tree->_type = 0;
487       
488        if (terrain)
489        {
490            osgUtil::IntersectVisitor iv;
491            osg::ref_ptr<osg::LineSegment> segDown = new osg::LineSegment;
492
493            segDown->set(tree->_position,tree->_position+osg::Vec3(0.0f,0.0f,size.z()));
494            iv.addLineSegment(segDown.get());
495           
496            terrain->accept(iv);
497
498            if (iv.hits())
499            {
500                osgUtil::IntersectVisitor::HitList& hitList = iv.getHitList(segDown.get());
501                if (!hitList.empty())
502                {
503                    osg::Vec3 ip = hitList.front().getWorldIntersectPoint();
504                    osg::Vec3 np = hitList.front().getWorldIntersectNormal();
505                    tree->_position = ip;
506                }
507            }
508        }
509       
510        trees.push_back(tree);
511    }
512}
513
514osg::Geometry* ForestTechniqueManager::createSprite( float w, float h, osg::Vec4ub color )
515{
516    // set up the coords
517    osg::Vec3Array& v = *(new osg::Vec3Array(4));
518    osg::Vec2Array& t = *(new osg::Vec2Array(4));
519    osg::Vec4ubArray& c = *(new osg::Vec4ubArray(1));
520
521    v[0].set(-w*0.5f,0.0f,0.0f);
522    v[1].set( w*0.5f,0.0f,0.0f);
523    v[2].set( w*0.5f,0.0f,h);
524    v[3].set(-w*0.5f,0.0f,h);
525
526    c[0] = color;
527
528    t[0].set(0.0f,0.0f);
529    t[1].set(1.0f,0.0f);
530    t[2].set(1.0f,1.0f);
531    t[3].set(0.0f,1.0f);
532
533    osg::Geometry *geom = new osg::Geometry;
534
535    geom->setVertexArray( &v );
536
537    geom->setTexCoordArray( 0, &t );
538
539    geom->setColorArray( &c );
540    geom->setColorBinding( osg::Geometry::BIND_OVERALL );
541
542    geom->addPrimitiveSet( new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,4) );
543
544    return geom;
545}
546
547osg::Geometry* ForestTechniqueManager::createOrthogonalQuads( const osg::Vec3& pos, float w, float h, osg::Vec4ub color )
548{
549    // set up the coords
550    osg::Vec3Array& v = *(new osg::Vec3Array(8));
551    osg::Vec2Array& t = *(new osg::Vec2Array(8));
552    osg::Vec4ubArray& c = *(new osg::Vec4ubArray(1));
553   
554    float rotation = random(0.0f,osg::PI/2.0f);
555    float sw = sinf(rotation)*w*0.5f;
556    float cw = cosf(rotation)*w*0.5f;
557
558    v[0].set(pos.x()-sw,pos.y()-cw,pos.z()+0.0f);
559    v[1].set(pos.x()+sw,pos.y()+cw,pos.z()+0.0f);
560    v[2].set(pos.x()+sw,pos.y()+cw,pos.z()+h);
561    v[3].set(pos.x()-sw,pos.y()-cw,pos.z()+h);
562
563    v[4].set(pos.x()-cw,pos.y()+sw,pos.z()+0.0f);
564    v[5].set(pos.x()+cw,pos.y()-sw,pos.z()+0.0f);
565    v[6].set(pos.x()+cw,pos.y()-sw,pos.z()+h);
566    v[7].set(pos.x()-cw,pos.y()+sw,pos.z()+h);
567
568    c[0] = color;
569
570    t[0].set(0.0f,0.0f);
571    t[1].set(1.0f,0.0f);
572    t[2].set(1.0f,1.0f);
573    t[3].set(0.0f,1.0f);
574
575    t[4].set(0.0f,0.0f);
576    t[5].set(1.0f,0.0f);
577    t[6].set(1.0f,1.0f);
578    t[7].set(0.0f,1.0f);
579
580    osg::Geometry *geom = new osg::Geometry;
581
582    geom->setVertexArray( &v );
583
584    geom->setTexCoordArray( 0, &t );
585
586    geom->setColorArray( &c );
587    geom->setColorBinding( osg::Geometry::BIND_OVERALL );
588
589    geom->addPrimitiveSet( new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,8) );
590
591    return geom;
592}
593
594osg::Node* ForestTechniqueManager::createBillboardGraph(Cell* cell,osg::StateSet* stateset)
595{
596    bool needGroup = !(cell->_cells.empty());
597    bool needBillboard = !(cell->_trees.empty());
598   
599    osg::Billboard* billboard = 0;
600    osg::Group* group = 0;
601   
602    if (needBillboard)
603    {
604        billboard = new osg::Billboard;
605        billboard->setStateSet(stateset);
606        for(TreeList::iterator itr=cell->_trees.begin();
607            itr!=cell->_trees.end();
608            ++itr)
609        {
610            Tree& tree = **itr;
611            billboard->addDrawable(createSprite(tree._width,tree._height,tree._color),tree._position);   
612        }
613    }
614   
615    if (needGroup)
616    {
617        group = new osg::Group;
618        for(Cell::CellList::iterator itr=cell->_cells.begin();
619            itr!=cell->_cells.end();
620            ++itr)
621        {
622            group->addChild(createBillboardGraph(itr->get(),stateset));
623        }
624       
625        if (billboard) group->addChild(billboard);
626       
627    }
628    if (group) return group;
629    else return billboard;
630}
631
632osg::Node* ForestTechniqueManager::createXGraph(Cell* cell,osg::StateSet* stateset)
633{
634    bool needGroup = !(cell->_cells.empty());
635    bool needTrees = !(cell->_trees.empty());
636   
637    osg::Geode* geode = 0;
638    osg::Group* group = 0;
639   
640    if (needTrees)
641    {
642        geode = new osg::Geode;
643        geode->setStateSet(stateset);
644       
645        for(TreeList::iterator itr=cell->_trees.begin();
646            itr!=cell->_trees.end();
647            ++itr)
648        {
649            Tree& tree = **itr;
650            geode->addDrawable(createOrthogonalQuads(tree._position,tree._width,tree._height,tree._color));
651        }
652    }
653   
654    if (needGroup)
655    {
656        group = new osg::Group;
657        for(Cell::CellList::iterator itr=cell->_cells.begin();
658            itr!=cell->_cells.end();
659            ++itr)
660        {
661            group->addChild(createXGraph(itr->get(),stateset));
662        }
663       
664        if (geode) group->addChild(geode);
665       
666    }
667    if (group) return group;
668    else return geode;
669}
670
671osg::Node* ForestTechniqueManager::createTransformGraph(Cell* cell,osg::StateSet* stateset)
672{
673    bool needGroup = !(cell->_cells.empty());
674    bool needTrees = !(cell->_trees.empty());
675   
676    osg::Group* transform_group = 0;
677    osg::Group* group = 0;
678   
679    if (needTrees)
680    {
681        transform_group = new osg::Group;
682       
683        osg::Geometry* geometry = createOrthogonalQuads(osg::Vec3(0.0f,0.0f,0.0f),1.0f,1.0f,osg::Vec4ub(255,255,255,255));
684       
685        for(TreeList::iterator itr=cell->_trees.begin();
686            itr!=cell->_trees.end();
687            ++itr)
688        {
689            Tree& tree = **itr;
690            osg::MatrixTransform* transform = new osg::MatrixTransform;
691            transform->setMatrix(osg::Matrix::scale(tree._width,tree._width,tree._height)*osg::Matrix::translate(tree._position));
692   
693            osg::Geode* geode = new osg::Geode;
694            geode->setStateSet(stateset);
695            geode->addDrawable(geometry);
696            transform->addChild(geode);
697            transform_group->addChild(transform);
698        }
699    }
700   
701    if (needGroup)
702    {
703        group = new osg::Group;
704        for(Cell::CellList::iterator itr=cell->_cells.begin();
705            itr!=cell->_cells.end();
706            ++itr)
707        {
708            group->addChild(createTransformGraph(itr->get(),stateset));
709        }
710       
711        if (transform_group) group->addChild(transform_group);
712       
713    }
714    if (group) return group;
715    else return transform_group;
716}
717
718osg::Geometry* ForestTechniqueManager::createOrthogonalQuadsNoColor( const osg::Vec3& pos, float w, float h)
719{
720    // set up the coords
721    osg::Vec3Array& v = *(new osg::Vec3Array(8));
722    osg::Vec2Array& t = *(new osg::Vec2Array(8));
723   
724    float rotation = random(0.0f,osg::PI/2.0f);
725    float sw = sinf(rotation)*w*0.5f;
726    float cw = cosf(rotation)*w*0.5f;
727
728    v[0].set(pos.x()-sw,pos.y()-cw,pos.z()+0.0f);
729    v[1].set(pos.x()+sw,pos.y()+cw,pos.z()+0.0f);
730    v[2].set(pos.x()+sw,pos.y()+cw,pos.z()+h);
731    v[3].set(pos.x()-sw,pos.y()-cw,pos.z()+h);
732
733    v[4].set(pos.x()-cw,pos.y()+sw,pos.z()+0.0f);
734    v[5].set(pos.x()+cw,pos.y()-sw,pos.z()+0.0f);
735    v[6].set(pos.x()+cw,pos.y()-sw,pos.z()+h);
736    v[7].set(pos.x()-cw,pos.y()+sw,pos.z()+h);
737
738    t[0].set(0.0f,0.0f);
739    t[1].set(1.0f,0.0f);
740    t[2].set(1.0f,1.0f);
741    t[3].set(0.0f,1.0f);
742
743    t[4].set(0.0f,0.0f);
744    t[5].set(1.0f,0.0f);
745    t[6].set(1.0f,1.0f);
746    t[7].set(0.0f,1.0f);
747
748    osg::Geometry *geom = new osg::Geometry;
749
750    geom->setVertexArray( &v );
751
752    geom->setTexCoordArray( 0, &t );
753
754    geom->addPrimitiveSet( new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,8) );
755
756    return geom;
757}
758
759class ShaderGeometry : public osg::Drawable
760{
761    public:
762        ShaderGeometry() { setUseDisplayList(false); }
763
764        /** Copy constructor using CopyOp to manage deep vs shallow copy.*/
765        ShaderGeometry(const ShaderGeometry& ShaderGeometry,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY):
766            osg::Drawable(ShaderGeometry,copyop) {}
767
768        META_Object(osg,ShaderGeometry)
769
770        typedef std::vector<osg::Vec4> PositionSizeList;
771       
772        virtual void drawImplementation(osg::RenderInfo& renderInfo) const
773        {
774            for(PositionSizeList::const_iterator itr = _trees.begin();
775                itr != _trees.end();
776                ++itr)
777            {
778                glColor4fv(itr->ptr());
779                _geometry->draw(renderInfo);
780            }
781        }
782
783        virtual osg::BoundingBox computeBound() const
784        {
785            osg::BoundingBox geom_box = _geometry->getBound();
786            osg::BoundingBox bb;
787            for(PositionSizeList::const_iterator itr = _trees.begin();
788                itr != _trees.end();
789                ++itr)
790            {
791                bb.expandBy(geom_box.corner(0)*(*itr)[3] +
792                            osg::Vec3( (*itr)[0], (*itr)[1], (*itr)[2] ));
793                bb.expandBy(geom_box.corner(7)*(*itr)[3] +
794                            osg::Vec3( (*itr)[0], (*itr)[1], (*itr)[2] ));
795            }
796            return bb;
797        }
798       
799        void setGeometry(osg::Geometry* geometry)
800        {
801            _geometry = geometry;
802        }
803       
804        void addTree(ForestTechniqueManager::Tree& tree)
805        {
806            _trees.push_back(osg::Vec4(tree._position.x(), tree._position.y(), tree._position.z(), tree._height));
807        }
808       
809        osg::ref_ptr<osg::Geometry> _geometry;
810
811        PositionSizeList _trees;
812
813    protected:
814   
815        virtual ~ShaderGeometry() {}
816       
817};
818
819osg::Geometry* shared_geometry = 0;
820
821osg::Node* ForestTechniqueManager::createShaderGraph(Cell* cell,osg::StateSet* stateset)
822{
823    if (shared_geometry==0)
824    {
825        shared_geometry = createOrthogonalQuadsNoColor(osg::Vec3(0.0f,0.0f,0.0f),1.0f,1.0f);
826        //shared_geometry->setUseDisplayList(false);
827    }
828
829
830    bool needGroup = !(cell->_cells.empty());
831    bool needTrees = !(cell->_trees.empty());
832   
833    osg::Geode* geode = 0;
834    osg::Group* group = 0;
835   
836    if (needTrees)
837    {
838        geode = new osg::Geode;
839       
840        ShaderGeometry* shader_geometry = new ShaderGeometry;
841        shader_geometry->setGeometry(shared_geometry);
842       
843       
844        for(TreeList::iterator itr=cell->_trees.begin();
845            itr!=cell->_trees.end();
846            ++itr)
847        {
848            Tree& tree = **itr;
849            shader_geometry->addTree(tree);
850
851        }
852
853        geode->setStateSet(stateset);
854        geode->addDrawable(shader_geometry);
855    }
856   
857    if (needGroup)
858    {
859        group = new osg::Group;
860        for(Cell::CellList::iterator itr=cell->_cells.begin();
861            itr!=cell->_cells.end();
862            ++itr)
863        {
864            group->addChild(createShaderGraph(itr->get(),stateset));
865        }
866       
867        if (geode) group->addChild(geode);
868       
869    }
870    if (group) return group;
871    else return geode;
872}
873
874osg::Node* ForestTechniqueManager::createHUDWithText(const std::string& str)
875{
876    osg::Geode* geode = new osg::Geode();
877   
878    std::string timesFont("fonts/arial.ttf");
879
880    // turn lighting off for the text and disable depth test to ensure its always ontop.
881    osg::StateSet* stateset = geode->getOrCreateStateSet();
882    stateset->setMode(GL_LIGHTING,osg::StateAttribute::OFF);
883
884    // or disable depth test, and make sure that the hud is drawn after everything
885    // else so that it always appears ontop.
886    stateset->setMode(GL_DEPTH_TEST,osg::StateAttribute::OFF);
887    stateset->setRenderBinDetails(11,"RenderBin");
888
889    osg::Vec3 position(150.0f,800.0f,0.0f);
890    osg::Vec3 delta(0.0f,-120.0f,0.0f);
891
892    {
893        osgText::Text* text = new  osgText::Text;
894        geode->addDrawable( text );
895
896        text->setFont(timesFont);
897        text->setPosition(position);
898        text->setText(str);
899       
900        position += delta;
901    }   
902
903   
904    // create the hud.
905    osg::MatrixTransform* modelview_abs = new osg::MatrixTransform;
906    modelview_abs->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
907    modelview_abs->setMatrix(osg::Matrix::identity());
908    modelview_abs->addChild(geode);
909
910    osg::Projection* projection = new osg::Projection;
911    projection->setMatrix(osg::Matrix::ortho2D(0,1280,0,1024));
912    projection->addChild(modelview_abs);
913
914    return projection;
915}
916
917osg::Node* ForestTechniqueManager::createScene(unsigned int numTreesToCreates)
918{
919    osg::Vec3 origin(0.0f,0.0f,0.0f);
920    osg::Vec3 size(1000.0f,1000.0f,200.0f);
921
922    std::cout<<"Creating terrain...";
923    osg::ref_ptr<osg::Node> terrain = createTerrain(origin,size);
924    std::cout<<"done."<<std::endl;
925   
926    std::cout<<"Creating tree locations...";std::cout.flush();
927    TreeList trees;
928    createTreeList(terrain.get(),origin,size,numTreesToCreates,trees);
929    std::cout<<"done."<<std::endl;
930   
931    std::cout<<"Creating cell subdivision...";
932    osg::ref_ptr<Cell> cell = new Cell;
933    cell->addTrees(trees);
934    cell->divide();
935     std::cout<<"done."<<std::endl;
936   
937   
938    osg::Texture2D *tex = new osg::Texture2D;
939    tex->setWrap( osg::Texture2D::WRAP_S, osg::Texture2D::CLAMP );
940    tex->setWrap( osg::Texture2D::WRAP_T, osg::Texture2D::CLAMP );
941    tex->setImage(osgDB::readImageFile("Images/tree0.rgba"));
942
943    osg::StateSet *dstate = new osg::StateSet;
944    {   
945        dstate->setTextureAttributeAndModes(0, tex, osg::StateAttribute::ON );
946        dstate->setTextureAttribute(0, new osg::TexEnv );
947
948        dstate->setAttributeAndModes( new osg::BlendFunc, osg::StateAttribute::ON );
949
950        osg::AlphaFunc* alphaFunc = new osg::AlphaFunc;
951        alphaFunc->setFunction(osg::AlphaFunc::GEQUAL,0.05f);
952        dstate->setAttributeAndModes( alphaFunc, osg::StateAttribute::ON );
953
954        dstate->setMode( GL_LIGHTING, osg::StateAttribute::OFF );
955
956        dstate->setRenderingHint( osg::StateSet::TRANSPARENT_BIN );
957    }
958   
959
960    _techniqueSwitch = new osg::Switch;
961
962    {
963        std::cout<<"Creating billboard based forest...";
964        osg::Group* group = new osg::Group;
965        group->addChild(createBillboardGraph(cell.get(),dstate));
966        group->addChild(createHUDWithText("Using osg::Billboard's to create a forest\n\nPress left cursor key to select OpenGL shader based forest\nPress right cursor key to select double quad based forest"));
967        _techniqueSwitch->addChild(group);
968        std::cout<<"done."<<std::endl;
969    }
970   
971    {
972        std::cout<<"Creating billboard based forest...";
973        osg::Group* group = new osg::Group;
974        group->addChild(createXGraph(cell.get(),dstate));
975        group->addChild(createHUDWithText("Using double quads to create a forest\n\nPress left cursor key to select osg::Billboard based forest\nPress right cursor key to select osg::MatrixTransform based forest\n"));
976        _techniqueSwitch->addChild(group);
977        std::cout<<"done."<<std::endl;
978    }
979
980    {
981        std::cout<<"Creating billboard based forest...";
982        osg::Group* group = new osg::Group;
983        group->addChild(createTransformGraph(cell.get(),dstate));
984        group->addChild(createHUDWithText("Using osg::MatrixTransform's to create a forest\n\nPress left cursor key to select double quad based forest\nPress right cursor key to select OpenGL shder based forest"));
985        _techniqueSwitch->addChild(group);
986        std::cout<<"done."<<std::endl;
987    }
988
989    {
990        osg::Group* group = new osg::Group;
991       
992
993        osg::StateSet* stateset = new osg::StateSet;
994
995        stateset->setTextureAttributeAndModes(0, tex, osg::StateAttribute::ON );
996        stateset->setRenderingHint( osg::StateSet::TRANSPARENT_BIN );
997
998        {
999            osg::Program* program = new osg::Program;
1000            stateset->setAttribute(program);
1001
1002#if 1
1003            // use inline shaders
1004           
1005            ///////////////////////////////////////////////////////////////////
1006            // vertex shader using just Vec4 coefficients
1007            char vertexShaderSource[] =
1008                "varying vec2 texcoord;\n"
1009                "\n"
1010                "void main(void)\n"
1011                "{\n"
1012                "    vec3 position = gl_Vertex.xyz * gl_Color.w + gl_Color.xyz;\n"
1013                "    gl_Position     = gl_ModelViewProjectionMatrix * vec4(position,1.0);\n"
1014                "    gl_FrontColor = vec4(1.0,1.0,1.0,1.0);\n"
1015                "    texcoord = gl_MultiTexCoord0.st;\n"
1016                "}\n";
1017
1018            //////////////////////////////////////////////////////////////////
1019            // fragment shader
1020            //
1021            char fragmentShaderSource[] =
1022                "uniform sampler2D baseTexture; \n"
1023                "varying vec2 texcoord; \n"
1024                "\n"
1025                "void main(void) \n"
1026                "{ \n"
1027                "    gl_FragColor = texture2D( baseTexture, texcoord); \n"
1028                "}\n";
1029
1030            osg::Shader* vertex_shader = new osg::Shader(osg::Shader::VERTEX, vertexShaderSource);
1031            program->addShader(vertex_shader);
1032
1033            osg::Shader* fragment_shader = new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource);
1034            program->addShader(fragment_shader);
1035           
1036#else
1037
1038            // get shaders from source
1039            program->addShader(osg::Shader::readShaderFile(osg::Shader::VERTEX, osgDB::findDataFile("shaders/forest.vert")));
1040            program->addShader(osg::Shader::readShaderFile(osg::Shader::FRAGMENT, osgDB::findDataFile("shaders/forest.frag")));
1041
1042#endif
1043
1044            osg::Uniform* baseTextureSampler = new osg::Uniform("baseTexture",0);
1045            stateset->addUniform(baseTextureSampler);
1046        }
1047
1048        std::cout<<"Creating billboard based forest...";
1049        group->addChild(createShaderGraph(cell.get(),stateset));
1050        group->addChild(createHUDWithText("Using OpenGL Shader to create a forest\n\nPress left cursor key to select osg::MatrixTransform based forest\nPress right cursor key to select osg::Billboard based forest"));
1051        _techniqueSwitch->addChild(group);
1052        std::cout<<"done."<<std::endl;
1053    }
1054
1055    _currentTechnique = 0;
1056    _techniqueSwitch->setSingleChildOn(_currentTechnique);
1057   
1058
1059    osg::Group* scene = new osg::Group;
1060   
1061    scene->addChild(terrain.get());
1062    scene->addChild(_techniqueSwitch.get());
1063
1064    return scene;
1065}
1066
1067int main( int argc, char **argv )
1068{
1069
1070    // use an ArgumentParser object to manage the program arguments.
1071    osg::ArgumentParser arguments(&argc,argv);
1072
1073    // set up the usage document, in case we need to print out how to use this program.
1074    arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" is the example which demonstrates the osg::Shape classes.");
1075    arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] filename ...");
1076    arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display this information");
1077    arguments.getApplicationUsage()->addCommandLineOption("--trees <number>","Set the number of trees to create");
1078   
1079    // construct the viewer.
1080    osgProducer::Viewer viewer(arguments);
1081
1082    float numTreesToCreates = 10000;
1083    arguments.read("--trees",numTreesToCreates);
1084
1085    // set up the value with sensible default event handlers.
1086    viewer.setUpViewer(osgProducer::Viewer::STANDARD_SETTINGS);
1087   
1088    osg::ref_ptr<ForestTechniqueManager> ttm = new ForestTechniqueManager;
1089   
1090    viewer.getEventHandlerList().push_front(new TechniqueEventHandler(ttm.get()));
1091
1092    // get details on keyboard and mouse bindings used by the viewer.
1093    viewer.getUsage(*arguments.getApplicationUsage());
1094
1095    // if user request help write it out to cout.
1096    if (arguments.read("-h") || arguments.read("--help"))
1097    {
1098        arguments.getApplicationUsage()->write(std::cout);
1099        return 1;
1100    }
1101
1102    // any option left unread are converted into errors to write out later.
1103    arguments.reportRemainingOptionsAsUnrecognized();
1104
1105    // report any errors if they have occured when parsing the program aguments.
1106    if (arguments.errors())
1107    {
1108        arguments.writeErrorMessages(std::cout);
1109        return 1;
1110    }
1111   
1112    osg::Node* node = ttm->createScene((unsigned int)numTreesToCreates);
1113
1114    // add model to viewer.
1115    viewer.setSceneData( node );
1116
1117    // create the windows and run the threads.
1118    viewer.realize();
1119
1120    while( !viewer.done() )
1121    {
1122        // wait for all cull and draw threads to complete.
1123        viewer.sync();
1124
1125        // update the scene by traversing it with the the update visitor which will
1126        // call all node update callbacks and animations.
1127        viewer.update();
1128         
1129        // fire off the cull and draw traversals of the scene.
1130        viewer.frame();
1131       
1132    }
1133   
1134    // wait for all cull and draw threads to complete.
1135    viewer.sync();
1136
1137    // run a clean up frame to delete all OpenGL objects.
1138    viewer.cleanup_frame();
1139
1140    // wait for all the clean up frame to complete.
1141    viewer.sync();
1142
1143    return 0;
1144}
Note: See TracBrowser for help on using the browser.