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

Revision 14195, 47.2 kB (checked in by robert, 17 hours ago)

Added simple test script for osgUI's TabWidget?

  • 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/TextureBuffer>
35#include <osg/Image>
36#include <osg/TexEnv>
37#include <osg/VertexProgram>
38#include <osg/FragmentProgram>
39
40#include <osgDB/ReadFile>
41#include <osgDB/FileUtils>
42
43#include <osgUtil/LineSegmentIntersector>
44#include <osgUtil/IntersectionVisitor>
45#include <osgUtil/SmoothingVisitor>
46
47#include <osgText/Text>
48
49#include <osgViewer/Viewer>
50#include <osgViewer/ViewerEventHandlers>
51
52#include <osgGA/StateSetManipulator>
53
54#include <iostream>
55#include <sstream>
56
57// for the grid data..
58#include "../osghangglide/terrain_coords.h"
59
60// class to create the forest and manage the movement between various techniques.
61class ForestTechniqueManager : public osg::Referenced
62{
63public:
64
65    ForestTechniqueManager() {}
66
67    class Tree : public osg::Referenced
68    {
69    public:
70
71        Tree():
72            _color(255,255,255,255),
73            _width(1.0f),
74            _height(1.0f),
75            _type(0) {}
76
77        Tree(const osg::Vec3& position, const osg::Vec4ub& color, float width, float height, unsigned int type):
78            _position(position),
79            _color(color),
80            _width(width),
81            _height(height),
82            _type(type) {}
83
84        osg::Vec3       _position;
85        osg::Vec4ub     _color;
86        float           _width;
87        float           _height;
88        unsigned int    _type;
89    };
90
91    typedef std::vector< osg::ref_ptr<Tree> > TreeList;
92
93    class Cell : public osg::Referenced
94    {
95    public:
96        typedef std::vector< osg::ref_ptr<Cell> > CellList;
97
98        Cell():_parent(0) {}
99        Cell(osg::BoundingBox& bb):_parent(0), _bb(bb) {}
100
101        void addCell(Cell* cell) { cell->_parent=this; _cells.push_back(cell); }
102
103        void addTree(Tree* tree) { _trees.push_back(tree); }
104
105        void addTrees(const TreeList& trees) { _trees.insert(_trees.end(),trees.begin(),trees.end()); }
106
107        void computeBound();
108
109        bool contains(const osg::Vec3& position) const { return _bb.contains(position); }
110
111        bool divide(unsigned int maxNumTreesPerCell=10);
112
113        bool divide(bool xAxis, bool yAxis, bool zAxis);
114
115        void bin();
116
117
118        Cell*               _parent;
119        osg::BoundingBox    _bb;
120        CellList            _cells;
121        TreeList            _trees;
122
123    };
124
125    float random(float min,float max) { return min + (max-min)*(float)rand()/(float)RAND_MAX; }
126    int random(int min,int max) { return min + (int)((float)(max-min)*(float)rand()/(float)RAND_MAX); }
127
128    osg::Geode* createTerrain(const osg::Vec3& origin, const osg::Vec3& size);
129
130    void createTreeList(osg::Node* terrain,const osg::Vec3& origin, const osg::Vec3& size,unsigned int numTreesToCreate,TreeList& trees);
131
132    osg::Geometry* createSprite( float w, float h, osg::Vec4ub color );
133
134    osg::Geometry* createOrthogonalQuads( const osg::Vec3& pos, float w, float h, osg::Vec4ub color );
135    osg::Geometry* createOrthogonalQuadsNoColor( const osg::Vec3& pos, float w, float h );
136
137    osg::Node* createBillboardGraph(Cell* cell,osg::StateSet* stateset);
138
139    osg::Node* createXGraph(Cell* cell,osg::StateSet* stateset);
140
141    osg::Node* createTransformGraph(Cell* cell,osg::StateSet* stateset);
142
143    osg::Node* createShaderGraph(Cell* cell,osg::StateSet* stateset);
144
145    osg::Node* createGeometryShaderGraph(Cell* cell, osg::StateSet* stateset);
146
147    osg::Node* createTextureBufferGraph(Cell* cell, osg::Geometry* templateGeometry);
148
149    void CollectTreePositions(Cell* cell, std::vector< osg::Vec3 >& positions);
150
151    osg::Node* createHUDWithText(const std::string& text);
152
153    osg::Node* createScene(unsigned int numTreesToCreates, unsigned int maxNumTreesPerCell);
154
155    void advanceToNextTechnique(int delta=1)
156    {
157        if (_techniqueSwitch.valid())
158        {
159            _currentTechnique += delta;
160            if (_currentTechnique<0)
161                _currentTechnique = _techniqueSwitch->getNumChildren()-1;
162            if (_currentTechnique>=(int)_techniqueSwitch->getNumChildren())
163                _currentTechnique = 0;
164            _techniqueSwitch->setSingleChildOn(_currentTechnique);
165        }
166    }
167
168    osg::ref_ptr<osg::Switch>   _techniqueSwitch;
169    int                         _currentTechnique;
170
171
172};
173
174// event handler to capture keyboard events and use them to advance the technique used for rendering
175class TechniqueEventHandler : public osgGA::GUIEventHandler
176{
177public:
178
179    TechniqueEventHandler(ForestTechniqueManager* ttm=0) { _ForestTechniqueManager = ttm; }
180
181    META_Object(osgforestApp,TechniqueEventHandler);
182
183    virtual bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter&, osg::Object*, osg::NodeVisitor*);
184
185    virtual void getUsage(osg::ApplicationUsage& usage) const;
186
187protected:
188
189    ~TechniqueEventHandler() {}
190
191    TechniqueEventHandler(const TechniqueEventHandler&,const osg::CopyOp&) {}
192
193    osg::ref_ptr<ForestTechniqueManager> _ForestTechniqueManager;
194
195
196};
197
198bool TechniqueEventHandler::handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter&, osg::Object*, osg::NodeVisitor*)
199{
200    switch(ea.getEventType())
201    {
202        case(osgGA::GUIEventAdapter::KEYDOWN):
203        {
204            if (ea.getKey()=='n' ||
205                ea.getKey()==osgGA::GUIEventAdapter::KEY_Right ||
206                ea.getKey()==osgGA::GUIEventAdapter::KEY_KP_Right)
207            {
208                _ForestTechniqueManager->advanceToNextTechnique(1);
209                return true;
210            }
211            else if (ea.getKey()=='p' ||
212                     ea.getKey()==osgGA::GUIEventAdapter::KEY_Left ||
213                     ea.getKey()==osgGA::GUIEventAdapter::KEY_KP_Left)
214            {
215                _ForestTechniqueManager->advanceToNextTechnique(-1);
216                return true;
217            }
218            return false;
219        }
220
221        default:
222            return false;
223    }
224}
225
226void TechniqueEventHandler::getUsage(osg::ApplicationUsage& usage) const
227{
228    usage.addKeyboardMouseBinding("n or Left Arrow","Advance to next technique");
229    usage.addKeyboardMouseBinding("p or Right Array","Move to previous technique");
230}
231
232
233void ForestTechniqueManager::Cell::computeBound()
234{
235    _bb.init();
236    for(CellList::iterator citr=_cells.begin();
237        citr!=_cells.end();
238        ++citr)
239    {
240        (*citr)->computeBound();
241        _bb.expandBy((*citr)->_bb);
242    }
243
244    for(TreeList::iterator titr=_trees.begin();
245        titr!=_trees.end();
246        ++titr)
247    {
248        _bb.expandBy((*titr)->_position);
249    }
250}
251
252bool ForestTechniqueManager::Cell::divide(unsigned int maxNumTreesPerCell)
253{
254
255    if (_trees.size()<=maxNumTreesPerCell) return false;
256
257    computeBound();
258
259    float radius = _bb.radius();
260    float divide_distance = radius*0.7f;
261    if (divide((_bb.xMax()-_bb.xMin())>divide_distance,(_bb.yMax()-_bb.yMin())>divide_distance,(_bb.zMax()-_bb.zMin())>divide_distance))
262    {
263        // recusively divide the new cells till maxNumTreesPerCell is met.
264        for(CellList::iterator citr=_cells.begin();
265            citr!=_cells.end();
266            ++citr)
267        {
268            (*citr)->divide(maxNumTreesPerCell);
269        }
270        return true;
271   }
272   else
273   {
274        return false;
275   }
276}
277
278bool ForestTechniqueManager::Cell::divide(bool xAxis, bool yAxis, bool zAxis)
279{
280    if (!(xAxis || yAxis || zAxis)) return false;
281
282    if (_cells.empty())
283        _cells.push_back(new Cell(_bb));
284
285    if (xAxis)
286    {
287        unsigned int numCellsToDivide=_cells.size();
288        for(unsigned int i=0;i<numCellsToDivide;++i)
289        {
290            Cell* orig_cell = _cells[i].get();
291            Cell* new_cell = new Cell(orig_cell->_bb);
292
293            float xCenter = (orig_cell->_bb.xMin()+orig_cell->_bb.xMax())*0.5f;
294            orig_cell->_bb.xMax() = xCenter;
295            new_cell->_bb.xMin() = xCenter;
296
297            _cells.push_back(new_cell);
298        }
299    }
300
301    if (yAxis)
302    {
303        unsigned int numCellsToDivide=_cells.size();
304        for(unsigned int i=0;i<numCellsToDivide;++i)
305        {
306            Cell* orig_cell = _cells[i].get();
307            Cell* new_cell = new Cell(orig_cell->_bb);
308
309            float yCenter = (orig_cell->_bb.yMin()+orig_cell->_bb.yMax())*0.5f;
310            orig_cell->_bb.yMax() = yCenter;
311            new_cell->_bb.yMin() = yCenter;
312
313            _cells.push_back(new_cell);
314        }
315    }
316
317    if (zAxis)
318    {
319        unsigned int numCellsToDivide=_cells.size();
320        for(unsigned int i=0;i<numCellsToDivide;++i)
321        {
322            Cell* orig_cell = _cells[i].get();
323            Cell* new_cell = new Cell(orig_cell->_bb);
324
325            float zCenter = (orig_cell->_bb.zMin()+orig_cell->_bb.zMax())*0.5f;
326            orig_cell->_bb.zMax() = zCenter;
327            new_cell->_bb.zMin() = zCenter;
328
329            _cells.push_back(new_cell);
330        }
331    }
332
333    bin();
334
335    return true;
336
337}
338
339void ForestTechniqueManager::Cell::bin()
340{
341    // put trees in appropriate cells.
342    TreeList treesNotAssigned;
343    for(TreeList::iterator titr=_trees.begin();
344        titr!=_trees.end();
345        ++titr)
346    {
347        Tree* tree = titr->get();
348        bool assigned = false;
349        for(CellList::iterator citr=_cells.begin();
350            citr!=_cells.end() && !assigned;
351            ++citr)
352        {
353            if ((*citr)->contains(tree->_position))
354            {
355                (*citr)->addTree(tree);
356                assigned = true;
357            }
358        }
359        if (!assigned) treesNotAssigned.push_back(tree);
360    }
361
362    // put the unassigned trees back into the original local tree list.
363    _trees.swap(treesNotAssigned);
364
365
366    // prune empty cells.
367    CellList cellsNotEmpty;
368    for(CellList::iterator citr=_cells.begin();
369        citr!=_cells.end();
370        ++citr)
371    {
372        if (!((*citr)->_trees.empty()))
373        {
374            cellsNotEmpty.push_back(*citr);
375        }
376    }
377    _cells.swap(cellsNotEmpty);
378
379
380}
381
382osg::Geode* ForestTechniqueManager::createTerrain(const osg::Vec3& origin, const osg::Vec3& size)
383{
384    osg::Geode* geode = new osg::Geode();
385
386    // ---------------------------------------
387    // Set up a StateSet to texture the objects
388    // ---------------------------------------
389    osg::StateSet* stateset = new osg::StateSet();
390
391    osg::Image* image = osgDB::readImageFile("Images/lz.rgb");
392    if (image)
393    {
394        osg::Texture2D* texture = new osg::Texture2D;
395        texture->setImage(image);
396        stateset->setTextureAttributeAndModes(0,texture,osg::StateAttribute::ON);
397    }
398
399    geode->setStateSet( stateset );
400
401    unsigned int numColumns = 38;
402    unsigned int numRows = 39;
403    unsigned int r;
404    unsigned int c;
405
406    // compute z range of z values of grid data so we can scale it.
407    float min_z = FLT_MAX;
408    float max_z = -FLT_MAX;
409    for(r=0;r<numRows;++r)
410    {
411        for(c=0;c<numColumns;++c)
412        {
413            min_z = osg::minimum(min_z,vertex[r+c*numRows][2]);
414            max_z = osg::maximum(max_z,vertex[r+c*numRows][2]);
415        }
416    }
417
418    float scale_z = size.z()/(max_z-min_z);
419
420
421    bool createGrid = false;
422    if (createGrid)
423    {
424
425        osg::HeightField* grid = new osg::HeightField;
426        grid->allocate(numColumns,numRows);
427        grid->setOrigin(origin);
428        grid->setXInterval(size.x()/(float)(numColumns-1));
429        grid->setYInterval(size.y()/(float)(numRows-1));
430
431        for(r=0;r<numRows;++r)
432        {
433            for(c=0;c<numColumns;++c)
434            {
435                grid->setHeight(c,r,(vertex[r+c*numRows][2]-min_z)*scale_z);
436            }
437        }
438
439        geode->addDrawable(new osg::ShapeDrawable(grid));
440    }
441    else
442    {
443        osg::Geometry* geometry = new osg::Geometry;
444
445        osg::Vec3Array& v = *(new osg::Vec3Array(numColumns*numRows));
446        osg::Vec2Array& t = *(new osg::Vec2Array(numColumns*numRows));
447        osg::Vec4ubArray& color = *(new osg::Vec4ubArray(1));
448
449        color[0].set(255,255,255,255);
450
451        float rowCoordDelta = size.y()/(float)(numRows-1);
452        float columnCoordDelta = size.x()/(float)(numColumns-1);
453
454        float rowTexDelta = 1.0f/(float)(numRows-1);
455        float columnTexDelta = 1.0f/(float)(numColumns-1);
456
457        osg::Vec3 pos = origin;
458        osg::Vec2 tex(0.0f,0.0f);
459        int vi=0;
460        for(r=0;r<numRows;++r)
461        {
462            pos.x() = origin.x();
463            tex.x() = 0.0f;
464            for(c=0;c<numColumns;++c)
465            {
466                v[vi].set(pos.x(),pos.y(),pos.z()+(vertex[r+c*numRows][2]-min_z)*scale_z);
467                t[vi].set(tex.x(),tex.y());
468                pos.x()+=columnCoordDelta;
469                tex.x()+=columnTexDelta;
470                ++vi;
471            }
472            pos.y() += rowCoordDelta;
473            tex.y() += rowTexDelta;
474        }
475
476        geometry->setVertexArray(&v);
477        geometry->setColorArray(&color, osg::Array::BIND_OVERALL);
478        geometry->setTexCoordArray(0,&t);
479
480        for(r=0;r<numRows-1;++r)
481        {
482            osg::DrawElementsUShort& drawElements = *(new osg::DrawElementsUShort(GL_QUAD_STRIP,2*numColumns));
483            geometry->addPrimitiveSet(&drawElements);
484            int ei=0;
485            for(c=0;c<numColumns;++c)
486            {
487                drawElements[ei++] = (r+1)*numColumns+c;
488                drawElements[ei++] = (r)*numColumns+c;
489            }
490        }
491
492        geode->addDrawable(geometry);
493
494        osgUtil::SmoothingVisitor sv;
495        sv.smooth(*geometry);
496    }
497
498    return geode;
499}
500
501void ForestTechniqueManager::createTreeList(osg::Node* terrain,const osg::Vec3& origin, const osg::Vec3& size,unsigned int numTreesToCreate,TreeList& trees)
502{
503
504    float max_TreeHeight = sqrtf(size.length2()/(float)numTreesToCreate);
505    float max_TreeWidth = max_TreeHeight*0.5f;
506
507    float min_TreeHeight = max_TreeHeight*0.3f;
508    float min_TreeWidth = min_TreeHeight*0.5f;
509
510    trees.reserve(trees.size()+numTreesToCreate);
511
512
513    for(unsigned int i=0;i<numTreesToCreate;++i)
514    {
515        Tree* tree = new Tree;
516        tree->_position.set(random(origin.x(),origin.x()+size.x()),random(origin.y(),origin.y()+size.y()),origin.z());
517        tree->_color.set(random(128,255),random(128,255),random(128,255),255);
518        tree->_width = random(min_TreeWidth,max_TreeWidth);
519        tree->_height = random(min_TreeHeight,max_TreeHeight);
520        tree->_type = 0;
521
522        if (terrain)
523        {
524            osg::ref_ptr<osgUtil::LineSegmentIntersector> intersector =
525                new osgUtil::LineSegmentIntersector(tree->_position,tree->_position+osg::Vec3(0.0f,0.0f,size.z()));
526
527            osgUtil::IntersectionVisitor iv(intersector.get());
528
529            terrain->accept(iv);
530
531            if (intersector->containsIntersections())
532            {
533                osgUtil::LineSegmentIntersector::Intersections& intersections = intersector->getIntersections();
534                for(osgUtil::LineSegmentIntersector::Intersections::iterator itr = intersections.begin();
535                    itr != intersections.end();
536                    ++itr)
537                {
538                    const osgUtil::LineSegmentIntersector::Intersection& intersection = *itr;
539                    tree->_position = intersection.getWorldIntersectPoint();
540                }
541            }
542        }
543
544        trees.push_back(tree);
545    }
546}
547
548osg::Geometry* ForestTechniqueManager::createSprite( float w, float h, osg::Vec4ub color )
549{
550    // set up the coords
551    osg::Vec3Array& v = *(new osg::Vec3Array(4));
552    osg::Vec2Array& t = *(new osg::Vec2Array(4));
553    osg::Vec4ubArray& c = *(new osg::Vec4ubArray(1));
554
555    v[0].set(-w*0.5f,0.0f,0.0f);
556    v[1].set( w*0.5f,0.0f,0.0f);
557    v[2].set( w*0.5f,0.0f,h);
558    v[3].set(-w*0.5f,0.0f,h);
559
560    c[0] = color;
561
562    t[0].set(0.0f,0.0f);
563    t[1].set(1.0f,0.0f);
564    t[2].set(1.0f,1.0f);
565    t[3].set(0.0f,1.0f);
566
567    osg::Geometry *geom = new osg::Geometry;
568
569    geom->setVertexArray( &v );
570
571    geom->setTexCoordArray( 0, &t );
572
573    geom->setColorArray( &c, osg::Array::BIND_OVERALL );
574
575    geom->addPrimitiveSet( new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,4) );
576
577    return geom;
578}
579
580osg::Geometry* ForestTechniqueManager::createOrthogonalQuads( const osg::Vec3& pos, float w, float h, osg::Vec4ub color )
581{
582    // set up the coords
583    osg::Vec3Array& v = *(new osg::Vec3Array(8));
584    osg::Vec2Array& t = *(new osg::Vec2Array(8));
585    osg::Vec4ubArray& c = *(new osg::Vec4ubArray(1));
586
587    float rotation = random(0.0f,osg::PI/2.0f);
588    float sw = sinf(rotation)*w*0.5f;
589    float cw = cosf(rotation)*w*0.5f;
590
591    v[0].set(pos.x()-sw,pos.y()-cw,pos.z()+0.0f);
592    v[1].set(pos.x()+sw,pos.y()+cw,pos.z()+0.0f);
593    v[2].set(pos.x()+sw,pos.y()+cw,pos.z()+h);
594    v[3].set(pos.x()-sw,pos.y()-cw,pos.z()+h);
595
596    v[4].set(pos.x()-cw,pos.y()+sw,pos.z()+0.0f);
597    v[5].set(pos.x()+cw,pos.y()-sw,pos.z()+0.0f);
598    v[6].set(pos.x()+cw,pos.y()-sw,pos.z()+h);
599    v[7].set(pos.x()-cw,pos.y()+sw,pos.z()+h);
600
601    c[0] = color;
602
603    t[0].set(0.0f,0.0f);
604    t[1].set(1.0f,0.0f);
605    t[2].set(1.0f,1.0f);
606    t[3].set(0.0f,1.0f);
607
608    t[4].set(0.0f,0.0f);
609    t[5].set(1.0f,0.0f);
610    t[6].set(1.0f,1.0f);
611    t[7].set(0.0f,1.0f);
612
613    osg::Geometry *geom = new osg::Geometry;
614
615    geom->setVertexArray( &v );
616
617    geom->setTexCoordArray( 0, &t );
618
619    geom->setColorArray( &c, osg::Array::BIND_OVERALL );
620
621    geom->addPrimitiveSet( new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,8) );
622
623    return geom;
624}
625
626osg::Node* ForestTechniqueManager::createBillboardGraph(Cell* cell,osg::StateSet* stateset)
627{
628    bool needGroup = !(cell->_cells.empty());
629    bool needBillboard = !(cell->_trees.empty());
630
631    osg::Billboard* billboard = 0;
632    osg::Group* group = 0;
633
634    if (needBillboard)
635    {
636        billboard = new osg::Billboard;
637        billboard->setStateSet(stateset);
638        for(TreeList::iterator itr=cell->_trees.begin();
639            itr!=cell->_trees.end();
640            ++itr)
641        {
642            Tree& tree = **itr;
643            billboard->addDrawable(createSprite(tree._width,tree._height,tree._color),tree._position);
644        }
645    }
646
647    if (needGroup)
648    {
649        group = new osg::Group;
650        for(Cell::CellList::iterator itr=cell->_cells.begin();
651            itr!=cell->_cells.end();
652            ++itr)
653        {
654            group->addChild(createBillboardGraph(itr->get(),stateset));
655        }
656
657        if (billboard) group->addChild(billboard);
658
659    }
660    if (group) return group;
661    else return billboard;
662}
663
664osg::Node* ForestTechniqueManager::createXGraph(Cell* cell,osg::StateSet* stateset)
665{
666    bool needGroup = !(cell->_cells.empty());
667    bool needTrees = !(cell->_trees.empty());
668
669    osg::Geode* geode = 0;
670    osg::Group* group = 0;
671
672    if (needTrees)
673    {
674        geode = new osg::Geode;
675        geode->setStateSet(stateset);
676
677        for(TreeList::iterator itr=cell->_trees.begin();
678            itr!=cell->_trees.end();
679            ++itr)
680        {
681            Tree& tree = **itr;
682            geode->addDrawable(createOrthogonalQuads(tree._position,tree._width,tree._height,tree._color));
683        }
684    }
685
686    if (needGroup)
687    {
688        group = new osg::Group;
689        for(Cell::CellList::iterator itr=cell->_cells.begin();
690            itr!=cell->_cells.end();
691            ++itr)
692        {
693            group->addChild(createXGraph(itr->get(),stateset));
694        }
695
696        if (geode) group->addChild(geode);
697
698    }
699    if (group) return group;
700    else return geode;
701}
702
703osg::Node* ForestTechniqueManager::createTransformGraph(Cell* cell,osg::StateSet* stateset)
704{
705    bool needGroup = !(cell->_cells.empty());
706    bool needTrees = !(cell->_trees.empty());
707
708    osg::Group* transform_group = 0;
709    osg::Group* group = 0;
710
711    if (needTrees)
712    {
713        transform_group = new osg::Group;
714
715        osg::Geometry* geometry = createOrthogonalQuads(osg::Vec3(0.0f,0.0f,0.0f),1.0f,1.0f,osg::Vec4ub(255,255,255,255));
716
717        for(TreeList::iterator itr=cell->_trees.begin();
718            itr!=cell->_trees.end();
719            ++itr)
720        {
721            Tree& tree = **itr;
722            osg::MatrixTransform* transform = new osg::MatrixTransform;
723            transform->setMatrix(osg::Matrix::scale(tree._width,tree._width,tree._height)*osg::Matrix::translate(tree._position));
724
725            osg::Geode* geode = new osg::Geode;
726            geode->setStateSet(stateset);
727            geode->addDrawable(geometry);
728            transform->addChild(geode);
729            transform_group->addChild(transform);
730        }
731    }
732
733    if (needGroup)
734    {
735        group = new osg::Group;
736        for(Cell::CellList::iterator itr=cell->_cells.begin();
737            itr!=cell->_cells.end();
738            ++itr)
739        {
740            group->addChild(createTransformGraph(itr->get(),stateset));
741        }
742
743        if (transform_group) group->addChild(transform_group);
744
745    }
746    if (group) return group;
747    else return transform_group;
748}
749
750osg::Geometry* ForestTechniqueManager::createOrthogonalQuadsNoColor( const osg::Vec3& pos, float w, float h)
751{
752    // set up the coords
753    osg::Vec3Array& v = *(new osg::Vec3Array(8));
754    osg::Vec2Array& t = *(new osg::Vec2Array(8));
755
756    float rotation = random(0.0f,osg::PI/2.0f);
757    float sw = sinf(rotation)*w*0.5f;
758    float cw = cosf(rotation)*w*0.5f;
759
760    v[0].set(pos.x()-sw,pos.y()-cw,pos.z()+0.0f);
761    v[1].set(pos.x()+sw,pos.y()+cw,pos.z()+0.0f);
762    v[2].set(pos.x()+sw,pos.y()+cw,pos.z()+h);
763    v[3].set(pos.x()-sw,pos.y()-cw,pos.z()+h);
764
765    v[4].set(pos.x()-cw,pos.y()+sw,pos.z()+0.0f);
766    v[5].set(pos.x()+cw,pos.y()-sw,pos.z()+0.0f);
767    v[6].set(pos.x()+cw,pos.y()-sw,pos.z()+h);
768    v[7].set(pos.x()-cw,pos.y()+sw,pos.z()+h);
769
770    t[0].set(0.0f,0.0f);
771    t[1].set(1.0f,0.0f);
772    t[2].set(1.0f,1.0f);
773    t[3].set(0.0f,1.0f);
774
775    t[4].set(0.0f,0.0f);
776    t[5].set(1.0f,0.0f);
777    t[6].set(1.0f,1.0f);
778    t[7].set(0.0f,1.0f);
779
780    osg::Geometry *geom = new osg::Geometry;
781
782    geom->setVertexArray( &v );
783
784    geom->setTexCoordArray( 0, &t );
785
786    geom->addPrimitiveSet( new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,8) );
787
788    return geom;
789}
790
791class ShaderGeometry : public osg::Drawable
792{
793    public:
794        ShaderGeometry() { setUseDisplayList(false); }
795
796        /** Copy constructor using CopyOp to manage deep vs shallow copy.*/
797        ShaderGeometry(const ShaderGeometry& ShaderGeometry,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY):
798            osg::Drawable(ShaderGeometry,copyop) {}
799
800        META_Object(osg,ShaderGeometry)
801
802        typedef std::vector<osg::Vec4> PositionSizeList;
803
804        virtual void drawImplementation(osg::RenderInfo& renderInfo) const
805        {
806            for(PositionSizeList::const_iterator itr = _trees.begin();
807                itr != _trees.end();
808                ++itr)
809            {
810                renderInfo.getState()->Color((*itr)[0],(*itr)[1],(*itr)[2],(*itr)[3]);
811                _geometry->draw(renderInfo);
812            }
813        }
814
815        virtual osg::BoundingBox computeBoundingBox() const
816        {
817            osg::BoundingBox geom_box = _geometry->getBoundingBox();
818            osg::BoundingBox bb;
819            for(PositionSizeList::const_iterator itr = _trees.begin();
820                itr != _trees.end();
821                ++itr)
822            {
823                bb.expandBy(geom_box.corner(0)*(*itr)[3] +
824                            osg::Vec3( (*itr)[0], (*itr)[1], (*itr)[2] ));
825                bb.expandBy(geom_box.corner(7)*(*itr)[3] +
826                            osg::Vec3( (*itr)[0], (*itr)[1], (*itr)[2] ));
827            }
828            return bb;
829        }
830
831        void setGeometry(osg::Geometry* geometry)
832        {
833            _geometry = geometry;
834        }
835
836        void addTree(ForestTechniqueManager::Tree& tree)
837        {
838            _trees.push_back(osg::Vec4(tree._position.x(), tree._position.y(), tree._position.z(), tree._height));
839        }
840
841        osg::ref_ptr<osg::Geometry> _geometry;
842
843        PositionSizeList _trees;
844
845    protected:
846
847        virtual ~ShaderGeometry() {}
848
849};
850
851osg::Geometry* shared_geometry = 0;
852
853osg::Program* createGeometryShader()
854{
855    static const char* vertSource = {
856    "#version 120\n"
857    "#extension GL_EXT_geometry_shader4 : enable\n"
858    "varying vec2 texcoord;\n"
859    "void main(void)\n"
860    "{\n"
861    "    gl_Position = gl_Vertex;\n"
862    "    texcoord = gl_MultiTexCoord0.st;\n"
863    "}\n"
864    };
865
866    static const char* geomSource = {
867    "#version 120\n"
868    "#extension GL_EXT_geometry_shader4 : enable\n"
869    "varying vec2 texcoord;\n"
870    "varying float intensity; \n"
871    "varying float red_intensity; \n"
872    "void main(void)\n"
873    "{\n"
874    "    vec4 v = gl_PositionIn[0];\n"
875    "    vec4 info = gl_PositionIn[1];\n"
876    "    intensity = info.y;\n"
877    "    red_intensity = info.z;\n"
878    "\n"
879    "    float h = info.x;\n"
880    "    float w = h*0.35;\n"
881    "    vec4 e;\n"
882    "    e = v + vec4(-w,0.0,0.0,0.0);  gl_Position = gl_ModelViewProjectionMatrix * e; texcoord = vec2(0.0,0.0); EmitVertex();\n"
883    "    e = v + vec4(w,0.0,0.0,0.0);  gl_Position = gl_ModelViewProjectionMatrix * e;  texcoord = vec2(1.0,0.0); EmitVertex();\n"
884    "    e = v + vec4(-w,0.0,h,0.0);  gl_Position = gl_ModelViewProjectionMatrix * e;  texcoord = vec2(0.0,1.0); EmitVertex();\n"
885    "    e = v + vec4(w,0.0,h,0.0);  gl_Position = gl_ModelViewProjectionMatrix * e;  texcoord = vec2(1.0,1.0); EmitVertex();\n"
886    "    EndPrimitive();\n"
887    "    e = v + vec4(0.0,-w,0.0,0.0);  gl_Position = gl_ModelViewProjectionMatrix * e; texcoord = vec2(0.0,0.0); EmitVertex();\n"
888    "    e = v + vec4(0.0,w,0.0,0.0);  gl_Position = gl_ModelViewProjectionMatrix * e;  texcoord = vec2(1.0,0.0); EmitVertex();\n"
889    "    e = v + vec4(0.0,-w,h,0.0);  gl_Position = gl_ModelViewProjectionMatrix * e;  texcoord = vec2(0.0,1.0); EmitVertex();\n"
890    "    e = v + vec4(0.0,w,h,0.0);  gl_Position = gl_ModelViewProjectionMatrix * e;  texcoord = vec2(1.0,1.0); EmitVertex();\n"
891    "    EndPrimitive();\n"
892    "}\n"
893    };
894
895
896    static const char* fragSource = {
897        "uniform sampler2D baseTexture; \n"
898        "varying vec2 texcoord; \n"
899        "varying float intensity; \n"
900        "varying float red_intensity; \n"
901        "\n"
902        "void main(void) \n"
903        "{ \n"
904        "   vec4 finalColor = texture2D( baseTexture, texcoord); \n"
905        "   vec4 color = finalColor * intensity;\n"
906        "   color.w = finalColor.w;\n"
907        "   color.x *= red_intensity;\n"
908        "   gl_FragColor = color;\n"
909        "}\n"
910    };
911
912
913    osg::Program* pgm = new osg::Program;
914    pgm->setName( "osgshader2 demo" );
915
916    pgm->addShader( new osg::Shader( osg::Shader::VERTEX,   vertSource ) );
917    pgm->addShader( new osg::Shader( osg::Shader::FRAGMENT, fragSource ) );
918
919    pgm->addShader( new osg::Shader( osg::Shader::GEOMETRY, geomSource ) );
920    pgm->setParameter( GL_GEOMETRY_VERTICES_OUT_EXT, 8 );
921    pgm->setParameter( GL_GEOMETRY_INPUT_TYPE_EXT, GL_LINES );
922    pgm->setParameter( GL_GEOMETRY_OUTPUT_TYPE_EXT, GL_TRIANGLE_STRIP);
923
924    return pgm;
925}
926
927void ForestTechniqueManager::CollectTreePositions(Cell* cell, std::vector< osg::Vec3 >& positions)
928{
929    bool needGroup = !(cell->_cells.empty());
930    bool needTrees = !(cell->_trees.empty());
931
932    if (needTrees)
933    {
934        for(TreeList::iterator itr=cell->_trees.begin();
935            itr!=cell->_trees.end();
936            ++itr)
937        {
938            Tree& tree = **itr;
939            positions.push_back(tree._position);
940        }
941    }
942
943    if (needGroup)
944    {
945        for(Cell::CellList::iterator itr=cell->_cells.begin();
946            itr!=cell->_cells.end();
947            ++itr)
948        {
949            CollectTreePositions(itr->get(),positions);
950        }
951
952    }
953}
954
955osg::Node* ForestTechniqueManager::createGeometryShaderGraph(Cell* cell, osg::StateSet* dstate)
956{
957    bool needGroup = !(cell->_cells.empty());
958    bool needTrees = !(cell->_trees.empty());
959
960    osg::Geode* geode = 0;
961    osg::Group* group = 0;
962
963    if (needTrees)
964    {
965        geode = new osg::Geode;
966        geode->setStateSet(dstate);
967
968        osg::Geometry* geometry = new osg::Geometry;
969        geode->addDrawable(geometry);
970
971        osg::Vec3Array* v = new osg::Vec3Array;
972
973        for(TreeList::iterator itr=cell->_trees.begin();
974            itr!=cell->_trees.end();
975            ++itr)
976        {
977            Tree& tree = **itr;
978            v->push_back(tree._position);
979            v->push_back(osg::Vec3(/*tree._height*/30.0,(double)random(0.75f,1.15f),(double)random(1.0f,1.250f)));
980        }
981        geometry->setVertexArray( v );
982        geometry->addPrimitiveSet( new osg::DrawArrays( GL_LINES, 0, v->size() ) );
983
984        osg::StateSet* sset = geode->getOrCreateStateSet();
985        sset->setMode( GL_LIGHTING, osg::StateAttribute::OFF );
986        sset->setAttribute( createGeometryShader() );
987
988        osg::Uniform* baseTextureSampler = new osg::Uniform("baseTexture",0);
989        sset->addUniform(baseTextureSampler);
990
991    }
992
993    if (needGroup)
994    {
995        group = new osg::Group;
996        for(Cell::CellList::iterator itr=cell->_cells.begin();
997            itr!=cell->_cells.end();
998            ++itr)
999        {
1000            group->addChild(createGeometryShaderGraph(itr->get(),dstate));
1001        }
1002
1003        if (geode) group->addChild(geode);
1004
1005    }
1006    if (group) return group;
1007    else return geode;
1008}
1009
1010osg::Node* ForestTechniqueManager::createTextureBufferGraph(Cell* cell, osg::Geometry* templateGeometry)
1011{
1012    bool needGroup = !(cell->_cells.empty());
1013    bool needTrees = !(cell->_trees.empty());
1014
1015    osg::Geode* geode = 0;
1016    osg::Group* group = 0;
1017
1018    if (needTrees)
1019    {
1020        osg::Geometry* geometry = (osg::Geometry*)templateGeometry->clone( osg::CopyOp::DEEP_COPY_PRIMITIVES );
1021        osg::DrawArrays* primSet = dynamic_cast<osg::DrawArrays*>( geometry->getPrimitiveSet(0) );
1022        primSet->setNumInstances( cell->_trees.size() );
1023        geode = new osg::Geode;
1024        geode->addDrawable(geometry);
1025
1026        osg::ref_ptr<osg::Image> treeParamsImage = new osg::Image;
1027        treeParamsImage->allocateImage( 3*cell->_trees.size(), 1, 1, GL_RGBA, GL_FLOAT );
1028
1029        unsigned int i=0;
1030        for(TreeList::iterator itr=cell->_trees.begin();
1031            itr!=cell->_trees.end();
1032            ++itr,++i)
1033        {
1034            osg::Vec4f* ptr = (osg::Vec4f*)treeParamsImage->data(3*i);
1035            Tree& tree = **itr;
1036            ptr[0] = osg::Vec4f(tree._position.x(),tree._position.y(),tree._position.z(),1.0);
1037            ptr[1] = osg::Vec4f((float)tree._color.r()/255.0f,(float)tree._color.g()/255.0f, (float)tree._color.b()/255.0f, 1.0);
1038            ptr[2] = osg::Vec4f(tree._width, tree._height, 1.0, 1.0);
1039        }
1040        osg::ref_ptr<osg::TextureBuffer> tbo = new osg::TextureBuffer;
1041        tbo->setImage( treeParamsImage.get() );
1042        tbo->setInternalFormat(GL_RGBA32F_ARB);
1043        geometry->getOrCreateStateSet()->setTextureAttribute(1, tbo.get());
1044        geometry->setInitialBound( cell->_bb );
1045    }
1046
1047    if (needGroup)
1048    {
1049        group = new osg::Group;
1050        for(Cell::CellList::iterator itr=cell->_cells.begin();
1051            itr!=cell->_cells.end();
1052            ++itr)
1053        {
1054            group->addChild(createTextureBufferGraph(itr->get(),templateGeometry));
1055        }
1056
1057        if (geode) group->addChild(geode);
1058
1059    }
1060    if (group) return group;
1061    else return geode;
1062}
1063
1064
1065osg::Node* ForestTechniqueManager::createShaderGraph(Cell* cell,osg::StateSet* stateset)
1066{
1067    if (shared_geometry==0)
1068    {
1069        shared_geometry = createOrthogonalQuadsNoColor(osg::Vec3(0.0f,0.0f,0.0f),1.0f,1.0f);
1070        //shared_geometry->setUseDisplayList(false);
1071    }
1072
1073
1074    bool needGroup = !(cell->_cells.empty());
1075    bool needTrees = !(cell->_trees.empty());
1076
1077    osg::Geode* geode = 0;
1078    osg::Group* group = 0;
1079
1080    if (needTrees)
1081    {
1082        geode = new osg::Geode;
1083
1084        ShaderGeometry* shader_geometry = new ShaderGeometry;
1085        shader_geometry->setGeometry(shared_geometry);
1086
1087
1088        for(TreeList::iterator itr=cell->_trees.begin();
1089            itr!=cell->_trees.end();
1090            ++itr)
1091        {
1092            Tree& tree = **itr;
1093            shader_geometry->addTree(tree);
1094
1095        }
1096
1097        geode->setStateSet(stateset);
1098        geode->addDrawable(shader_geometry);
1099    }
1100
1101    if (needGroup)
1102    {
1103        group = new osg::Group;
1104        for(Cell::CellList::iterator itr=cell->_cells.begin();
1105            itr!=cell->_cells.end();
1106            ++itr)
1107        {
1108            group->addChild(createShaderGraph(itr->get(),stateset));
1109        }
1110
1111        if (geode) group->addChild(geode);
1112
1113    }
1114    if (group) return group;
1115    else return geode;
1116}
1117
1118osg::Node* ForestTechniqueManager::createHUDWithText(const std::string& str)
1119{
1120    osg::Geode* geode = new osg::Geode();
1121
1122    std::string timesFont("fonts/arial.ttf");
1123
1124    // turn lighting off for the text and disable depth test to ensure its always ontop.
1125    osg::StateSet* stateset = geode->getOrCreateStateSet();
1126    stateset->setMode(GL_LIGHTING,osg::StateAttribute::OFF);
1127
1128    // or disable depth test, and make sure that the hud is drawn after everything
1129    // else so that it always appears ontop.
1130    stateset->setMode(GL_DEPTH_TEST,osg::StateAttribute::OFF);
1131    stateset->setRenderBinDetails(11,"RenderBin");
1132
1133    osg::Vec3 position(150.0f,800.0f,0.0f);
1134    osg::Vec3 delta(0.0f,-120.0f,0.0f);
1135
1136    {
1137        osgText::Text* text = new  osgText::Text;
1138        geode->addDrawable( text );
1139
1140        text->setFont(timesFont);
1141        text->setPosition(position);
1142        text->setText(str);
1143
1144        position += delta;
1145    }
1146
1147
1148    // create the hud.
1149    osg::MatrixTransform* modelview_abs = new osg::MatrixTransform;
1150    modelview_abs->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
1151    modelview_abs->setMatrix(osg::Matrix::identity());
1152    modelview_abs->addChild(geode);
1153
1154    osg::Projection* projection = new osg::Projection;
1155    projection->setMatrix(osg::Matrix::ortho2D(0,1280,0,1024));
1156    projection->addChild(modelview_abs);
1157
1158    return projection;
1159}
1160
1161osg::Node* ForestTechniqueManager::createScene(unsigned int numTreesToCreates, unsigned int maxNumTreesPerCell)
1162{
1163    osg::Vec3 origin(0.0f,0.0f,0.0f);
1164    osg::Vec3 size(1000.0f,1000.0f,200.0f);
1165
1166    std::cout<<"Creating terrain...";
1167    osg::ref_ptr<osg::Node> terrain = createTerrain(origin,size);
1168    std::cout<<"done."<<std::endl;
1169
1170    std::cout<<"Creating tree locations...";std::cout.flush();
1171    TreeList trees;
1172    createTreeList(terrain.get(),origin,size,numTreesToCreates,trees);
1173    std::cout<<"done."<<std::endl;
1174
1175    std::cout<<"Creating cell subdivision...";
1176    osg::ref_ptr<Cell> cell = new Cell;
1177    cell->addTrees(trees);
1178    cell->divide(maxNumTreesPerCell);
1179    std::cout<<"done."<<std::endl;
1180
1181
1182    osg::Texture2D *tex = new osg::Texture2D;
1183    tex->setWrap( osg::Texture2D::WRAP_S, osg::Texture2D::CLAMP );
1184    tex->setWrap( osg::Texture2D::WRAP_T, osg::Texture2D::CLAMP );
1185    tex->setImage(osgDB::readImageFile("Images/tree0.rgba"));
1186
1187    osg::StateSet *dstate = new osg::StateSet;
1188    {
1189        dstate->setTextureAttributeAndModes(0, tex, osg::StateAttribute::ON );
1190
1191        dstate->setTextureAttribute(0, new osg::TexEnv );
1192
1193        dstate->setAttributeAndModes( new osg::BlendFunc, osg::StateAttribute::ON );
1194
1195        osg::AlphaFunc* alphaFunc = new osg::AlphaFunc;
1196        alphaFunc->setFunction(osg::AlphaFunc::GEQUAL,0.05f);
1197        dstate->setAttributeAndModes( alphaFunc, osg::StateAttribute::ON );
1198
1199        dstate->setMode( GL_LIGHTING, osg::StateAttribute::OFF );
1200
1201        dstate->setRenderingHint( osg::StateSet::TRANSPARENT_BIN );
1202    }
1203
1204
1205    _techniqueSwitch = new osg::Switch;
1206
1207    {
1208        std::cout<<"Creating osg::Billboard based forest...";
1209        osg::Group* group = new osg::Group;
1210        group->addChild(createBillboardGraph(cell.get(),dstate));
1211        group->addChild(createHUDWithText("Using osg::Billboard's to create a forest\n\nPress left cursor key to select geometry instancing with Texture Buffer Object\nPress right cursor key to select double quad based forest"));
1212        _techniqueSwitch->addChild(group);
1213        std::cout<<"done."<<std::endl;
1214    }
1215
1216    {
1217        std::cout<<"Creating double quad based forest...";
1218        osg::Group* group = new osg::Group;
1219        group->addChild(createXGraph(cell.get(),dstate));
1220        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"));
1221        _techniqueSwitch->addChild(group);
1222        std::cout<<"done."<<std::endl;
1223    }
1224
1225    {
1226        std::cout<<"Creating osg::MatrixTransform based forest...";
1227        osg::Group* group = new osg::Group;
1228        group->addChild(createTransformGraph(cell.get(),dstate));
1229        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 osg::Vertex/FragmentProgram based forest"));
1230        _techniqueSwitch->addChild(group);
1231        std::cout<<"done."<<std::endl;
1232    }
1233
1234    {
1235        std::cout<<"Creating osg::Vertex/FragmentProgram based forest...";
1236        osg::Group* group = new osg::Group;
1237
1238        osg::StateSet* stateset = new osg::StateSet(*dstate, osg::CopyOp::DEEP_COPY_ALL);
1239
1240        {
1241            // vertex program
1242            std::ostringstream vp_oss;
1243            vp_oss <<
1244                "!!ARBvp1.0\n"
1245
1246                "ATTRIB vpos = vertex.position;\n"
1247                "ATTRIB vcol = vertex.color;\n"
1248                "ATTRIB tc = vertex.texcoord[" << 0 << "];"
1249
1250                "PARAM mvp[4] = { state.matrix.mvp };\n"
1251                "PARAM one = { 1.0, 1.0, 1.0, 1.0 };"
1252
1253                "TEMP position;\n"
1254
1255                // vec3 position = gl_Vertex.xyz * gl_Color.w + gl_Color.xyz;
1256                "MAD position, vpos, vcol.w, vcol;\n"
1257
1258                // gl_Position     = gl_ModelViewProjectionMatrix * vec4(position,1.0);
1259                "MOV position.w, one;\n"
1260                "DP4 result.position.x, mvp[0], position;\n"
1261                "DP4 result.position.y, mvp[1], position;\n"
1262                "DP4 result.position.z, mvp[2], position;\n"
1263                "DP4 result.position.w, mvp[3], position;\n"
1264
1265                // gl_FrontColor = vec4(1.0,1.0,1.0,1.0);
1266                "MOV result.color.front.primary, one;\n"
1267
1268                // texcoord = gl_MultiTexCoord0.st;
1269                "MOV result.texcoord, tc;\n"
1270                "END\n";
1271
1272
1273            // fragment program
1274            std::ostringstream fp_oss;
1275            fp_oss <<
1276                "!!ARBfp1.0\n"
1277                "TEX result.color, fragment.texcoord[" << 0 << "], texture[" << 0 << "], 2D;"
1278                "END\n";
1279
1280            osg::ref_ptr<osg::VertexProgram> vp = new osg::VertexProgram;
1281            vp->setVertexProgram(vp_oss.str());
1282            stateset->setAttributeAndModes(vp.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);
1283
1284            osg::ref_ptr<osg::FragmentProgram> fp = new osg::FragmentProgram;
1285            fp->setFragmentProgram(fp_oss.str());
1286            stateset->setAttributeAndModes(fp.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);
1287        }
1288
1289        group->addChild(createShaderGraph(cell.get(),stateset));
1290        group->addChild(createHUDWithText("Using osg::Vertex/FragmentProgram to create a forest\n\nPress left cursor key to select osg::MatrixTransform's based forest\nPress right cursor key to select OpenGL shader based forest"));
1291        _techniqueSwitch->addChild(group);
1292        std::cout<<"done."<<std::endl;
1293    }
1294
1295    {
1296        std::cout<<"Creating OpenGL shader based forest...";
1297        osg::Group* group = new osg::Group;
1298
1299        osg::StateSet* stateset = new osg::StateSet(*dstate, osg::CopyOp::DEEP_COPY_ALL);
1300
1301        {
1302            osg::Program* program = new osg::Program;
1303            stateset->setAttribute(program);
1304
1305#if 1
1306            // use inline shaders
1307
1308            ///////////////////////////////////////////////////////////////////
1309            // vertex shader using just Vec4 coefficients
1310            char vertexShaderSource[] =
1311                "varying vec2 texcoord;\n"
1312                "\n"
1313                "void main(void)\n"
1314                "{\n"
1315                "    vec3 position = gl_Vertex.xyz * gl_Color.w + gl_Color.xyz;\n"
1316                "    gl_Position     = gl_ModelViewProjectionMatrix * vec4(position,1.0);\n"
1317                "    gl_FrontColor = vec4(1.0,1.0,1.0,1.0);\n"
1318                "    texcoord = gl_MultiTexCoord0.st;\n"
1319                "}\n";
1320
1321            //////////////////////////////////////////////////////////////////
1322            // fragment shader
1323            //
1324            char fragmentShaderSource[] =
1325                "uniform sampler2D baseTexture; \n"
1326                "varying vec2 texcoord; \n"
1327                "\n"
1328                "void main(void) \n"
1329                "{ \n"
1330                "    gl_FragColor = texture2D( baseTexture, texcoord); \n"
1331                "}\n";
1332
1333            osg::Shader* vertex_shader = new osg::Shader(osg::Shader::VERTEX, vertexShaderSource);
1334            program->addShader(vertex_shader);
1335
1336            osg::Shader* fragment_shader = new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource);
1337            program->addShader(fragment_shader);
1338
1339#else
1340
1341            // get shaders from source
1342            program->addShader(osg::Shader::readShaderFile(osg::Shader::VERTEX, osgDB::findDataFile("shaders/forest.vert")));
1343            program->addShader(osg::Shader::readShaderFile(osg::Shader::FRAGMENT, osgDB::findDataFile("shaders/forest.frag")));
1344
1345#endif
1346
1347            osg::Uniform* baseTextureSampler = new osg::Uniform("baseTexture",0);
1348            stateset->addUniform(baseTextureSampler);
1349        }
1350
1351        group->addChild(createShaderGraph(cell.get(),stateset));
1352        group->addChild(createHUDWithText("Using OpenGL Shader to create a forest\n\nPress left cursor key to select osg::Vertex/FragmentProgram based forest\nPress right cursor key to select osg::Vertex/Geometry/FragmentProgram based forest"));
1353        _techniqueSwitch->addChild(group);
1354        std::cout<<"done."<<std::endl;
1355    }
1356
1357    {
1358        std::cout<<"Creating Geometry Shader based forest...";
1359
1360        osg::StateSet* stateset = new osg::StateSet(*dstate, osg::CopyOp::DEEP_COPY_ALL);
1361
1362        osg::Group* group = new osg::Group;
1363        group->addChild(createGeometryShaderGraph(cell.get(), stateset));
1364        group->addChild(createHUDWithText("Using osg::Vertex/Geometry/FragmentProgram to create a forest\n\nPress left cursor key to select OpenGL Shader based forest\nPress right cursor key to select geometry instancing with Texture Buffer Object"));
1365
1366        _techniqueSwitch->addChild(group);
1367        std::cout<<"done."<<std::endl;
1368    }
1369
1370    {
1371        std::cout<<"Creating forest using geometry instancing and texture buffer objects ...";
1372
1373        osg::StateSet* stateset = new osg::StateSet(*dstate, osg::CopyOp::DEEP_COPY_ALL);
1374        {
1375            osg::Program* program = new osg::Program;
1376            stateset->setAttribute(program);
1377
1378            char vertexShaderSource[] =
1379                "#version 420 compatibility\n"
1380                "uniform samplerBuffer dataBuffer;\n"
1381                "layout(location = 0) in vec3 VertexPosition;\n"
1382                "layout(location = 8) in vec3 VertexTexCoord;\n"
1383                "out vec2 TexCoord;\n"
1384                "out vec4 Color;\n"
1385                "void main()\n"
1386                "{\n"
1387                "   int instanceAddress = gl_InstanceID * 3;\n"
1388                "   vec3 position = texelFetch(dataBuffer, instanceAddress).xyz;\n"
1389                "   Color         = texelFetch(dataBuffer, instanceAddress + 1);\n"
1390                "   vec2 size     = texelFetch(dataBuffer, instanceAddress + 2).xy;\n"
1391                "   mat4 mvpMatrix = gl_ModelViewProjectionMatrix *\n"
1392                "        mat4( size.x, 0.0, 0.0, 0.0,\n"
1393                "              0.0, size.x, 0.0, 0.0,\n"
1394                "              0.0, 0.0, size.y, 0.0,\n"
1395                "              position.x, position.y, position.z, 1.0);\n"
1396                "   gl_Position = mvpMatrix * vec4(VertexPosition,1.0) ;\n"
1397                "   TexCoord = VertexTexCoord.xy;\n"
1398                "}\n";
1399
1400            char fragmentShaderSource[] =
1401                "#version 420 core\n"
1402                "uniform sampler2D baseTexture; \n"
1403                "in vec2 TexCoord;\n"
1404                "in vec4 Color;\n"
1405                "layout(location = 0, index = 0) out vec4 FragData0;\n"
1406                "void main(void) \n"
1407                "{\n"
1408                "    FragData0 = Color*texture(baseTexture, TexCoord);\n"
1409                "}\n";
1410
1411            osg::Shader* vertex_shader = new osg::Shader(osg::Shader::VERTEX, vertexShaderSource);
1412            program->addShader(vertex_shader);
1413
1414            osg::Shader* fragment_shader = new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource);
1415            program->addShader(fragment_shader);
1416
1417            osg::Uniform* baseTextureSampler = new osg::Uniform("baseTexture",0);
1418            stateset->addUniform(baseTextureSampler);
1419
1420            osg::Uniform* dataBufferSampler = new osg::Uniform("dataBuffer",1);
1421            stateset->addUniform(dataBufferSampler);
1422        }
1423
1424        osg::ref_ptr<osg::Geometry> templateGeometry = createOrthogonalQuadsNoColor(osg::Vec3(0.0f,0.0f,0.0f),1.0f,1.0f);
1425        templateGeometry->setUseVertexBufferObjects(true);
1426        templateGeometry->setUseDisplayList(false);
1427        osg::Node* textureBufferGraph = createTextureBufferGraph(cell.get(), templateGeometry.get());
1428        textureBufferGraph->setStateSet( stateset );
1429        osg::Group* group = new osg::Group;
1430        group->addChild(textureBufferGraph);
1431        group->addChild(createHUDWithText("Using geometry instancing to create a forest\n\nPress left cursor key to select osg::Vertex/Geometry/FragmentProgram based forest\nPress right cursor key to select osg::Billboard based forest"));
1432
1433        _techniqueSwitch->addChild(group);
1434
1435        std::cout<<"done."<<std::endl;
1436    }
1437
1438
1439    _currentTechnique = 0;
1440    _techniqueSwitch->setSingleChildOn(_currentTechnique);
1441
1442
1443    osg::Group* scene = new osg::Group;
1444
1445    scene->addChild(terrain.get());
1446    scene->addChild(_techniqueSwitch.get());
1447
1448    return scene;
1449}
1450
1451int main( int argc, char **argv )
1452{
1453
1454    // use an ArgumentParser object to manage the program arguments.
1455    osg::ArgumentParser arguments(&argc,argv);
1456
1457    // construct the viewer.
1458    osgViewer::Viewer viewer(arguments);
1459
1460    unsigned int numTreesToCreate = 10000;
1461    arguments.read("--trees",numTreesToCreate);
1462
1463    unsigned int maxNumTreesPerCell = sqrtf(static_cast<float>(numTreesToCreate));
1464
1465    arguments.read("--trees-per-cell",maxNumTreesPerCell);
1466
1467    osg::ref_ptr<ForestTechniqueManager> ttm = new ForestTechniqueManager;
1468
1469    // add the stats handler
1470    viewer.addEventHandler(new osgViewer::StatsHandler);
1471
1472    viewer.addEventHandler(new TechniqueEventHandler(ttm.get()));
1473    viewer.addEventHandler(new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()));
1474
1475    // add model to viewer.
1476    viewer.setSceneData( ttm->createScene(numTreesToCreate, maxNumTreesPerCell) );
1477
1478
1479    return viewer.run();
1480}
Note: See TracBrowser for help on using the browser.