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

Revision 9082, 33.9 kB (checked in by robert, 5 years ago)

Added very basic osgvnc example that uses the LibVNCServer client libries for implementing a vnc client
as an osg::Image with the vnc data stream going to it.

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