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

Revision 13437, 47.4 kB (checked in by robert, 6 days ago)

Fixed comment

  • 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);
478        geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
479        geometry->setTexCoordArray(0,&t);
480
481        for(r=0;r<numRows-1;++r)
482        {
483            osg::DrawElementsUShort& drawElements = *(new osg::DrawElementsUShort(GL_QUAD_STRIP,2*numColumns));
484            geometry->addPrimitiveSet(&drawElements);
485            int ei=0;
486            for(c=0;c<numColumns;++c)
487            {
488                drawElements[ei++] = (r+1)*numColumns+c;
489                drawElements[ei++] = (r)*numColumns+c;
490            }
491        }
492
493        geode->addDrawable(geometry);
494
495        osgUtil::SmoothingVisitor sv;
496        sv.smooth(*geometry);
497    }
498
499    return geode;
500}
501
502void ForestTechniqueManager::createTreeList(osg::Node* terrain,const osg::Vec3& origin, const osg::Vec3& size,unsigned int numTreesToCreate,TreeList& trees)
503{
504
505    float max_TreeHeight = sqrtf(size.length2()/(float)numTreesToCreate);
506    float max_TreeWidth = max_TreeHeight*0.5f;
507
508    float min_TreeHeight = max_TreeHeight*0.3f;
509    float min_TreeWidth = min_TreeHeight*0.5f;
510
511    trees.reserve(trees.size()+numTreesToCreate);
512
513
514    for(unsigned int i=0;i<numTreesToCreate;++i)
515    {
516        Tree* tree = new Tree;
517        tree->_position.set(random(origin.x(),origin.x()+size.x()),random(origin.y(),origin.y()+size.y()),origin.z());
518        tree->_color.set(random(128,255),random(128,255),random(128,255),255);
519        tree->_width = random(min_TreeWidth,max_TreeWidth);
520        tree->_height = random(min_TreeHeight,max_TreeHeight);
521        tree->_type = 0;
522
523        if (terrain)
524        {
525            osg::ref_ptr<osgUtil::LineSegmentIntersector> intersector =
526                new osgUtil::LineSegmentIntersector(tree->_position,tree->_position+osg::Vec3(0.0f,0.0f,size.z()));
527
528            osgUtil::IntersectionVisitor iv(intersector.get());
529
530            terrain->accept(iv);
531
532            if (intersector->containsIntersections())
533            {
534                osgUtil::LineSegmentIntersector::Intersections& intersections = intersector->getIntersections();
535                for(osgUtil::LineSegmentIntersector::Intersections::iterator itr = intersections.begin();
536                    itr != intersections.end();
537                    ++itr)
538                {
539                    const osgUtil::LineSegmentIntersector::Intersection& intersection = *itr;
540                    tree->_position = intersection.getWorldIntersectPoint();
541                }
542            }
543        }
544
545        trees.push_back(tree);
546    }
547}
548
549osg::Geometry* ForestTechniqueManager::createSprite( float w, float h, osg::Vec4ub color )
550{
551    // set up the coords
552    osg::Vec3Array& v = *(new osg::Vec3Array(4));
553    osg::Vec2Array& t = *(new osg::Vec2Array(4));
554    osg::Vec4ubArray& c = *(new osg::Vec4ubArray(1));
555
556    v[0].set(-w*0.5f,0.0f,0.0f);
557    v[1].set( w*0.5f,0.0f,0.0f);
558    v[2].set( w*0.5f,0.0f,h);
559    v[3].set(-w*0.5f,0.0f,h);
560
561    c[0] = color;
562
563    t[0].set(0.0f,0.0f);
564    t[1].set(1.0f,0.0f);
565    t[2].set(1.0f,1.0f);
566    t[3].set(0.0f,1.0f);
567
568    osg::Geometry *geom = new osg::Geometry;
569
570    geom->setVertexArray( &v );
571
572    geom->setTexCoordArray( 0, &t );
573
574    geom->setColorArray( &c );
575    geom->setColorBinding( osg::Geometry::BIND_OVERALL );
576
577    geom->addPrimitiveSet( new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,4) );
578
579    return geom;
580}
581
582osg::Geometry* ForestTechniqueManager::createOrthogonalQuads( const osg::Vec3& pos, float w, float h, osg::Vec4ub color )
583{
584    // set up the coords
585    osg::Vec3Array& v = *(new osg::Vec3Array(8));
586    osg::Vec2Array& t = *(new osg::Vec2Array(8));
587    osg::Vec4ubArray& c = *(new osg::Vec4ubArray(1));
588
589    float rotation = random(0.0f,osg::PI/2.0f);
590    float sw = sinf(rotation)*w*0.5f;
591    float cw = cosf(rotation)*w*0.5f;
592
593    v[0].set(pos.x()-sw,pos.y()-cw,pos.z()+0.0f);
594    v[1].set(pos.x()+sw,pos.y()+cw,pos.z()+0.0f);
595    v[2].set(pos.x()+sw,pos.y()+cw,pos.z()+h);
596    v[3].set(pos.x()-sw,pos.y()-cw,pos.z()+h);
597
598    v[4].set(pos.x()-cw,pos.y()+sw,pos.z()+0.0f);
599    v[5].set(pos.x()+cw,pos.y()-sw,pos.z()+0.0f);
600    v[6].set(pos.x()+cw,pos.y()-sw,pos.z()+h);
601    v[7].set(pos.x()-cw,pos.y()+sw,pos.z()+h);
602
603    c[0] = color;
604
605    t[0].set(0.0f,0.0f);
606    t[1].set(1.0f,0.0f);
607    t[2].set(1.0f,1.0f);
608    t[3].set(0.0f,1.0f);
609
610    t[4].set(0.0f,0.0f);
611    t[5].set(1.0f,0.0f);
612    t[6].set(1.0f,1.0f);
613    t[7].set(0.0f,1.0f);
614
615    osg::Geometry *geom = new osg::Geometry;
616
617    geom->setVertexArray( &v );
618
619    geom->setTexCoordArray( 0, &t );
620
621    geom->setColorArray( &c );
622    geom->setColorBinding( osg::Geometry::BIND_OVERALL );
623
624    geom->addPrimitiveSet( new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,8) );
625
626    return geom;
627}
628
629osg::Node* ForestTechniqueManager::createBillboardGraph(Cell* cell,osg::StateSet* stateset)
630{
631    bool needGroup = !(cell->_cells.empty());
632    bool needBillboard = !(cell->_trees.empty());
633
634    osg::Billboard* billboard = 0;
635    osg::Group* group = 0;
636
637    if (needBillboard)
638    {
639        billboard = new osg::Billboard;
640        billboard->setStateSet(stateset);
641        for(TreeList::iterator itr=cell->_trees.begin();
642            itr!=cell->_trees.end();
643            ++itr)
644        {
645            Tree& tree = **itr;
646            billboard->addDrawable(createSprite(tree._width,tree._height,tree._color),tree._position);
647        }
648    }
649
650    if (needGroup)
651    {
652        group = new osg::Group;
653        for(Cell::CellList::iterator itr=cell->_cells.begin();
654            itr!=cell->_cells.end();
655            ++itr)
656        {
657            group->addChild(createBillboardGraph(itr->get(),stateset));
658        }
659
660        if (billboard) group->addChild(billboard);
661
662    }
663    if (group) return group;
664    else return billboard;
665}
666
667osg::Node* ForestTechniqueManager::createXGraph(Cell* cell,osg::StateSet* stateset)
668{
669    bool needGroup = !(cell->_cells.empty());
670    bool needTrees = !(cell->_trees.empty());
671
672    osg::Geode* geode = 0;
673    osg::Group* group = 0;
674
675    if (needTrees)
676    {
677        geode = new osg::Geode;
678        geode->setStateSet(stateset);
679
680        for(TreeList::iterator itr=cell->_trees.begin();
681            itr!=cell->_trees.end();
682            ++itr)
683        {
684            Tree& tree = **itr;
685            geode->addDrawable(createOrthogonalQuads(tree._position,tree._width,tree._height,tree._color));
686        }
687    }
688
689    if (needGroup)
690    {
691        group = new osg::Group;
692        for(Cell::CellList::iterator itr=cell->_cells.begin();
693            itr!=cell->_cells.end();
694            ++itr)
695        {
696            group->addChild(createXGraph(itr->get(),stateset));
697        }
698
699        if (geode) group->addChild(geode);
700
701    }
702    if (group) return group;
703    else return geode;
704}
705
706osg::Node* ForestTechniqueManager::createTransformGraph(Cell* cell,osg::StateSet* stateset)
707{
708    bool needGroup = !(cell->_cells.empty());
709    bool needTrees = !(cell->_trees.empty());
710
711    osg::Group* transform_group = 0;
712    osg::Group* group = 0;
713
714    if (needTrees)
715    {
716        transform_group = new osg::Group;
717
718        osg::Geometry* geometry = createOrthogonalQuads(osg::Vec3(0.0f,0.0f,0.0f),1.0f,1.0f,osg::Vec4ub(255,255,255,255));
719
720        for(TreeList::iterator itr=cell->_trees.begin();
721            itr!=cell->_trees.end();
722            ++itr)
723        {
724            Tree& tree = **itr;
725            osg::MatrixTransform* transform = new osg::MatrixTransform;
726            transform->setMatrix(osg::Matrix::scale(tree._width,tree._width,tree._height)*osg::Matrix::translate(tree._position));
727
728            osg::Geode* geode = new osg::Geode;
729            geode->setStateSet(stateset);
730            geode->addDrawable(geometry);
731            transform->addChild(geode);
732            transform_group->addChild(transform);
733        }
734    }
735
736    if (needGroup)
737    {
738        group = new osg::Group;
739        for(Cell::CellList::iterator itr=cell->_cells.begin();
740            itr!=cell->_cells.end();
741            ++itr)
742        {
743            group->addChild(createTransformGraph(itr->get(),stateset));
744        }
745
746        if (transform_group) group->addChild(transform_group);
747
748    }
749    if (group) return group;
750    else return transform_group;
751}
752
753osg::Geometry* ForestTechniqueManager::createOrthogonalQuadsNoColor( const osg::Vec3& pos, float w, float h)
754{
755    // set up the coords
756    osg::Vec3Array& v = *(new osg::Vec3Array(8));
757    osg::Vec2Array& t = *(new osg::Vec2Array(8));
758
759    float rotation = random(0.0f,osg::PI/2.0f);
760    float sw = sinf(rotation)*w*0.5f;
761    float cw = cosf(rotation)*w*0.5f;
762
763    v[0].set(pos.x()-sw,pos.y()-cw,pos.z()+0.0f);
764    v[1].set(pos.x()+sw,pos.y()+cw,pos.z()+0.0f);
765    v[2].set(pos.x()+sw,pos.y()+cw,pos.z()+h);
766    v[3].set(pos.x()-sw,pos.y()-cw,pos.z()+h);
767
768    v[4].set(pos.x()-cw,pos.y()+sw,pos.z()+0.0f);
769    v[5].set(pos.x()+cw,pos.y()-sw,pos.z()+0.0f);
770    v[6].set(pos.x()+cw,pos.y()-sw,pos.z()+h);
771    v[7].set(pos.x()-cw,pos.y()+sw,pos.z()+h);
772
773    t[0].set(0.0f,0.0f);
774    t[1].set(1.0f,0.0f);
775    t[2].set(1.0f,1.0f);
776    t[3].set(0.0f,1.0f);
777
778    t[4].set(0.0f,0.0f);
779    t[5].set(1.0f,0.0f);
780    t[6].set(1.0f,1.0f);
781    t[7].set(0.0f,1.0f);
782
783    osg::Geometry *geom = new osg::Geometry;
784
785    geom->setVertexArray( &v );
786
787    geom->setTexCoordArray( 0, &t );
788
789    geom->addPrimitiveSet( new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,8) );
790
791    return geom;
792}
793
794class ShaderGeometry : public osg::Drawable
795{
796    public:
797        ShaderGeometry() { setUseDisplayList(false); }
798
799        /** Copy constructor using CopyOp to manage deep vs shallow copy.*/
800        ShaderGeometry(const ShaderGeometry& ShaderGeometry,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY):
801            osg::Drawable(ShaderGeometry,copyop) {}
802
803        META_Object(osg,ShaderGeometry)
804
805        typedef std::vector<osg::Vec4> PositionSizeList;
806
807        virtual void drawImplementation(osg::RenderInfo& renderInfo) const
808        {
809            for(PositionSizeList::const_iterator itr = _trees.begin();
810                itr != _trees.end();
811                ++itr)
812            {
813                renderInfo.getState()->Color((*itr)[0],(*itr)[1],(*itr)[2],(*itr)[3]);
814                _geometry->draw(renderInfo);
815            }
816        }
817
818        virtual osg::BoundingBox computeBound() const
819        {
820            osg::BoundingBox geom_box = _geometry->getBound();
821            osg::BoundingBox bb;
822            for(PositionSizeList::const_iterator itr = _trees.begin();
823                itr != _trees.end();
824                ++itr)
825            {
826                bb.expandBy(geom_box.corner(0)*(*itr)[3] +
827                            osg::Vec3( (*itr)[0], (*itr)[1], (*itr)[2] ));
828                bb.expandBy(geom_box.corner(7)*(*itr)[3] +
829                            osg::Vec3( (*itr)[0], (*itr)[1], (*itr)[2] ));
830            }
831            return bb;
832        }
833
834        void setGeometry(osg::Geometry* geometry)
835        {
836            _geometry = geometry;
837        }
838
839        void addTree(ForestTechniqueManager::Tree& tree)
840        {
841            _trees.push_back(osg::Vec4(tree._position.x(), tree._position.y(), tree._position.z(), tree._height));
842        }
843
844        osg::ref_ptr<osg::Geometry> _geometry;
845
846        PositionSizeList _trees;
847
848    protected:
849
850        virtual ~ShaderGeometry() {}
851
852};
853
854osg::Geometry* shared_geometry = 0;
855
856osg::Program* createGeometryShader()
857{
858    static const char* vertSource = {
859    "#version 120\n"
860    "#extension GL_EXT_geometry_shader4 : enable\n"
861    "varying vec2 texcoord;\n"
862    "void main(void)\n"
863    "{\n"
864    "    gl_Position = gl_Vertex;\n"
865    "    texcoord = gl_MultiTexCoord0.st;\n"
866    "}\n"
867    };
868
869    static const char* geomSource = {
870    "#version 120\n"
871    "#extension GL_EXT_geometry_shader4 : enable\n"
872    "varying vec2 texcoord;\n"
873    "varying float intensity; \n"
874    "varying float red_intensity; \n"
875    "void main(void)\n"
876    "{\n"
877    "    vec4 v = gl_PositionIn[0];\n"
878    "    vec4 info = gl_PositionIn[1];\n"
879    "    intensity = info.y;\n"
880    "    red_intensity = info.z;\n"
881    "\n"
882    "    float h = info.x;\n"
883    "    float w = h*0.35;\n"
884    "    vec4 e;\n"
885    "    e = v + vec4(-w,0.0,0.0,0.0);  gl_Position = gl_ModelViewProjectionMatrix * e; texcoord = vec2(0.0,0.0); EmitVertex();\n"
886    "    e = v + vec4(w,0.0,0.0,0.0);  gl_Position = gl_ModelViewProjectionMatrix * e;  texcoord = vec2(1.0,0.0); EmitVertex();\n"
887    "    e = v + vec4(-w,0.0,h,0.0);  gl_Position = gl_ModelViewProjectionMatrix * e;  texcoord = vec2(0.0,1.0); EmitVertex();\n"
888    "    e = v + vec4(w,0.0,h,0.0);  gl_Position = gl_ModelViewProjectionMatrix * e;  texcoord = vec2(1.0,1.0); EmitVertex();\n"
889    "    EndPrimitive();\n"
890    "    e = v + vec4(0.0,-w,0.0,0.0);  gl_Position = gl_ModelViewProjectionMatrix * e; texcoord = vec2(0.0,0.0); EmitVertex();\n"
891    "    e = v + vec4(0.0,w,0.0,0.0);  gl_Position = gl_ModelViewProjectionMatrix * e;  texcoord = vec2(1.0,0.0); EmitVertex();\n"
892    "    e = v + vec4(0.0,-w,h,0.0);  gl_Position = gl_ModelViewProjectionMatrix * e;  texcoord = vec2(0.0,1.0); EmitVertex();\n"
893    "    e = v + vec4(0.0,w,h,0.0);  gl_Position = gl_ModelViewProjectionMatrix * e;  texcoord = vec2(1.0,1.0); EmitVertex();\n"
894    "    EndPrimitive();\n"
895    "}\n"
896    };
897
898
899    static const char* fragSource = {
900        "uniform sampler2D baseTexture; \n"
901        "varying vec2 texcoord; \n"
902        "varying float intensity; \n"
903        "varying float red_intensity; \n"
904        "\n"
905        "void main(void) \n"
906        "{ \n"
907        "   vec4 finalColor = texture2D( baseTexture, texcoord); \n"
908        "   vec4 color = finalColor * intensity;\n"
909        "   color.w = finalColor.w;\n"
910        "   color.x *= red_intensity;\n"
911        "   gl_FragColor = color;\n"
912        "}\n"
913    };
914
915
916    osg::Program* pgm = new osg::Program;
917    pgm->setName( "osgshader2 demo" );
918
919    pgm->addShader( new osg::Shader( osg::Shader::VERTEX,   vertSource ) );
920    pgm->addShader( new osg::Shader( osg::Shader::FRAGMENT, fragSource ) );
921
922    pgm->addShader( new osg::Shader( osg::Shader::GEOMETRY, geomSource ) );
923    pgm->setParameter( GL_GEOMETRY_VERTICES_OUT_EXT, 8 );
924    pgm->setParameter( GL_GEOMETRY_INPUT_TYPE_EXT, GL_LINES );
925    pgm->setParameter( GL_GEOMETRY_OUTPUT_TYPE_EXT, GL_TRIANGLE_STRIP);
926
927    return pgm;
928}
929
930void ForestTechniqueManager::CollectTreePositions(Cell* cell, std::vector< osg::Vec3 >& positions)
931{
932    bool needGroup = !(cell->_cells.empty());
933    bool needTrees = !(cell->_trees.empty());
934
935    if (needTrees)
936    {
937        for(TreeList::iterator itr=cell->_trees.begin();
938            itr!=cell->_trees.end();
939            ++itr)
940        {
941            Tree& tree = **itr;
942            positions.push_back(tree._position);
943        }
944    }
945
946    if (needGroup)
947    {
948        for(Cell::CellList::iterator itr=cell->_cells.begin();
949            itr!=cell->_cells.end();
950            ++itr)
951        {
952            CollectTreePositions(itr->get(),positions);
953        }
954
955    }
956}
957
958osg::Node* ForestTechniqueManager::createGeometryShaderGraph(Cell* cell, osg::StateSet* dstate)
959{
960    bool needGroup = !(cell->_cells.empty());
961    bool needTrees = !(cell->_trees.empty());
962
963    osg::Geode* geode = 0;
964    osg::Group* group = 0;
965
966    if (needTrees)
967    {
968        geode = new osg::Geode;
969        geode->setStateSet(dstate);
970
971        osg::Geometry* geometry = new osg::Geometry;
972        geode->addDrawable(geometry);
973
974        osg::Vec3Array* v = new osg::Vec3Array;
975
976        for(TreeList::iterator itr=cell->_trees.begin();
977            itr!=cell->_trees.end();
978            ++itr)
979        {
980            Tree& tree = **itr;
981            v->push_back(tree._position);
982            v->push_back(osg::Vec3(/*tree._height*/30.0,(double)random(0.75f,1.15f),(double)random(1.0f,1.250f)));
983        }
984        geometry->setVertexArray( v );
985        geometry->addPrimitiveSet( new osg::DrawArrays( GL_LINES, 0, v->size() ) );
986
987        osg::StateSet* sset = geode->getOrCreateStateSet();
988        sset->setMode( GL_LIGHTING, osg::StateAttribute::OFF );
989        sset->setAttribute( createGeometryShader() );
990
991        osg::Uniform* baseTextureSampler = new osg::Uniform("baseTexture",0);
992        sset->addUniform(baseTextureSampler);
993
994    }
995
996    if (needGroup)
997    {
998        group = new osg::Group;
999        for(Cell::CellList::iterator itr=cell->_cells.begin();
1000            itr!=cell->_cells.end();
1001            ++itr)
1002        {
1003            group->addChild(createGeometryShaderGraph(itr->get(),dstate));
1004        }
1005
1006        if (geode) group->addChild(geode);
1007
1008    }
1009    if (group) return group;
1010    else return geode;
1011}
1012
1013osg::Node* ForestTechniqueManager::createTextureBufferGraph(Cell* cell, osg::Geometry* templateGeometry)
1014{
1015    bool needGroup = !(cell->_cells.empty());
1016    bool needTrees = !(cell->_trees.empty());
1017
1018    osg::Geode* geode = 0;
1019    osg::Group* group = 0;
1020
1021    if (needTrees)
1022    {
1023        osg::Geometry* geometry = (osg::Geometry*)templateGeometry->clone( osg::CopyOp::DEEP_COPY_PRIMITIVES );
1024        osg::DrawArrays* primSet = dynamic_cast<osg::DrawArrays*>( geometry->getPrimitiveSet(0) );
1025        primSet->setNumInstances( cell->_trees.size() );
1026        geode = new osg::Geode;
1027        geode->addDrawable(geometry);
1028       
1029        osg::ref_ptr<osg::Image> treeParamsImage = new osg::Image;
1030        treeParamsImage->allocateImage( 3*cell->_trees.size(), 1, 1, GL_RGBA, GL_FLOAT );
1031       
1032        unsigned int i=0;
1033        for(TreeList::iterator itr=cell->_trees.begin();
1034            itr!=cell->_trees.end();
1035            ++itr,++i)
1036        {
1037            osg::Vec4f* ptr = (osg::Vec4f*)treeParamsImage->data(3*i);
1038            Tree& tree = **itr;
1039            ptr[0] = osg::Vec4f(tree._position.x(),tree._position.y(),tree._position.z(),1.0);
1040            ptr[1] = osg::Vec4f((float)tree._color.r()/255.0f,(float)tree._color.g()/255.0f, (float)tree._color.b()/255.0f, 1.0);
1041            ptr[2] = osg::Vec4f(tree._width, tree._height, 1.0, 1.0);
1042        }
1043        osg::ref_ptr<osg::TextureBuffer> tbo = new osg::TextureBuffer;
1044        tbo->setImage( treeParamsImage.get() );
1045        tbo->setInternalFormat(GL_RGBA32F_ARB);
1046        geometry->getOrCreateStateSet()->setTextureAttribute(1, tbo.get());
1047        geometry->setInitialBound( cell->_bb );
1048    }
1049
1050    if (needGroup)
1051    {
1052        group = new osg::Group;
1053        for(Cell::CellList::iterator itr=cell->_cells.begin();
1054            itr!=cell->_cells.end();
1055            ++itr)
1056        {
1057            group->addChild(createTextureBufferGraph(itr->get(),templateGeometry));
1058        }
1059
1060        if (geode) group->addChild(geode);
1061
1062    }
1063    if (group) return group;
1064    else return geode;
1065}
1066
1067
1068osg::Node* ForestTechniqueManager::createShaderGraph(Cell* cell,osg::StateSet* stateset)
1069{
1070    if (shared_geometry==0)
1071    {
1072        shared_geometry = createOrthogonalQuadsNoColor(osg::Vec3(0.0f,0.0f,0.0f),1.0f,1.0f);
1073        //shared_geometry->setUseDisplayList(false);
1074    }
1075
1076
1077    bool needGroup = !(cell->_cells.empty());
1078    bool needTrees = !(cell->_trees.empty());
1079
1080    osg::Geode* geode = 0;
1081    osg::Group* group = 0;
1082
1083    if (needTrees)
1084    {
1085        geode = new osg::Geode;
1086
1087        ShaderGeometry* shader_geometry = new ShaderGeometry;
1088        shader_geometry->setGeometry(shared_geometry);
1089
1090
1091        for(TreeList::iterator itr=cell->_trees.begin();
1092            itr!=cell->_trees.end();
1093            ++itr)
1094        {
1095            Tree& tree = **itr;
1096            shader_geometry->addTree(tree);
1097
1098        }
1099
1100        geode->setStateSet(stateset);
1101        geode->addDrawable(shader_geometry);
1102    }
1103
1104    if (needGroup)
1105    {
1106        group = new osg::Group;
1107        for(Cell::CellList::iterator itr=cell->_cells.begin();
1108            itr!=cell->_cells.end();
1109            ++itr)
1110        {
1111            group->addChild(createShaderGraph(itr->get(),stateset));
1112        }
1113
1114        if (geode) group->addChild(geode);
1115
1116    }
1117    if (group) return group;
1118    else return geode;
1119}
1120
1121osg::Node* ForestTechniqueManager::createHUDWithText(const std::string& str)
1122{
1123    osg::Geode* geode = new osg::Geode();
1124
1125    std::string timesFont("fonts/arial.ttf");
1126
1127    // turn lighting off for the text and disable depth test to ensure its always ontop.
1128    osg::StateSet* stateset = geode->getOrCreateStateSet();
1129    stateset->setMode(GL_LIGHTING,osg::StateAttribute::OFF);
1130
1131    // or disable depth test, and make sure that the hud is drawn after everything
1132    // else so that it always appears ontop.
1133    stateset->setMode(GL_DEPTH_TEST,osg::StateAttribute::OFF);
1134    stateset->setRenderBinDetails(11,"RenderBin");
1135
1136    osg::Vec3 position(150.0f,800.0f,0.0f);
1137    osg::Vec3 delta(0.0f,-120.0f,0.0f);
1138
1139    {
1140        osgText::Text* text = new  osgText::Text;
1141        geode->addDrawable( text );
1142
1143        text->setFont(timesFont);
1144        text->setPosition(position);
1145        text->setText(str);
1146
1147        position += delta;
1148    }
1149
1150
1151    // create the hud.
1152    osg::MatrixTransform* modelview_abs = new osg::MatrixTransform;
1153    modelview_abs->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
1154    modelview_abs->setMatrix(osg::Matrix::identity());
1155    modelview_abs->addChild(geode);
1156
1157    osg::Projection* projection = new osg::Projection;
1158    projection->setMatrix(osg::Matrix::ortho2D(0,1280,0,1024));
1159    projection->addChild(modelview_abs);
1160
1161    return projection;
1162}
1163
1164osg::Node* ForestTechniqueManager::createScene(unsigned int numTreesToCreates, unsigned int maxNumTreesPerCell)
1165{
1166    osg::Vec3 origin(0.0f,0.0f,0.0f);
1167    osg::Vec3 size(1000.0f,1000.0f,200.0f);
1168
1169    std::cout<<"Creating terrain...";
1170    osg::ref_ptr<osg::Node> terrain = createTerrain(origin,size);
1171    std::cout<<"done."<<std::endl;
1172
1173    std::cout<<"Creating tree locations...";std::cout.flush();
1174    TreeList trees;
1175    createTreeList(terrain.get(),origin,size,numTreesToCreates,trees);
1176    std::cout<<"done."<<std::endl;
1177
1178    std::cout<<"Creating cell subdivision...";
1179    osg::ref_ptr<Cell> cell = new Cell;
1180    cell->addTrees(trees);
1181    cell->divide(maxNumTreesPerCell);
1182    std::cout<<"done."<<std::endl;
1183
1184
1185    osg::Texture2D *tex = new osg::Texture2D;
1186    tex->setWrap( osg::Texture2D::WRAP_S, osg::Texture2D::CLAMP );
1187    tex->setWrap( osg::Texture2D::WRAP_T, osg::Texture2D::CLAMP );
1188    tex->setImage(osgDB::readImageFile("Images/tree0.rgba"));
1189
1190    osg::StateSet *dstate = new osg::StateSet;
1191    {
1192        dstate->setTextureAttributeAndModes(0, tex, osg::StateAttribute::ON );
1193
1194        dstate->setTextureAttribute(0, new osg::TexEnv );
1195
1196        dstate->setAttributeAndModes( new osg::BlendFunc, osg::StateAttribute::ON );
1197
1198        osg::AlphaFunc* alphaFunc = new osg::AlphaFunc;
1199        alphaFunc->setFunction(osg::AlphaFunc::GEQUAL,0.05f);
1200        dstate->setAttributeAndModes( alphaFunc, osg::StateAttribute::ON );
1201
1202        dstate->setMode( GL_LIGHTING, osg::StateAttribute::OFF );
1203
1204        dstate->setRenderingHint( osg::StateSet::TRANSPARENT_BIN );
1205    }
1206
1207
1208    _techniqueSwitch = new osg::Switch;
1209
1210    {
1211        std::cout<<"Creating osg::Billboard based forest...";
1212        osg::Group* group = new osg::Group;
1213        group->addChild(createBillboardGraph(cell.get(),dstate));
1214        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"));
1215        _techniqueSwitch->addChild(group);
1216        std::cout<<"done."<<std::endl;
1217    }
1218
1219    {
1220        std::cout<<"Creating double quad based forest...";
1221        osg::Group* group = new osg::Group;
1222        group->addChild(createXGraph(cell.get(),dstate));
1223        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"));
1224        _techniqueSwitch->addChild(group);
1225        std::cout<<"done."<<std::endl;
1226    }
1227
1228    {
1229        std::cout<<"Creating osg::MatrixTransform based forest...";
1230        osg::Group* group = new osg::Group;
1231        group->addChild(createTransformGraph(cell.get(),dstate));
1232        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"));
1233        _techniqueSwitch->addChild(group);
1234        std::cout<<"done."<<std::endl;
1235    }
1236
1237    {
1238        std::cout<<"Creating osg::Vertex/FragmentProgram based forest...";
1239        osg::Group* group = new osg::Group;
1240
1241        osg::StateSet* stateset = new osg::StateSet(*dstate, osg::CopyOp::DEEP_COPY_ALL);
1242
1243        {
1244            // vertex program
1245            std::ostringstream vp_oss;
1246            vp_oss <<
1247                "!!ARBvp1.0\n"
1248
1249                "ATTRIB vpos = vertex.position;\n"
1250                "ATTRIB vcol = vertex.color;\n"
1251                "ATTRIB tc = vertex.texcoord[" << 0 << "];"
1252
1253                "PARAM mvp[4] = { state.matrix.mvp };\n"
1254                "PARAM one = { 1.0, 1.0, 1.0, 1.0 };"
1255
1256                "TEMP position;\n"
1257
1258                // vec3 position = gl_Vertex.xyz * gl_Color.w + gl_Color.xyz;
1259                "MAD position, vpos, vcol.w, vcol;\n"
1260
1261                // gl_Position     = gl_ModelViewProjectionMatrix * vec4(position,1.0);
1262                "MOV position.w, one;\n"
1263                "DP4 result.position.x, mvp[0], position;\n"
1264                "DP4 result.position.y, mvp[1], position;\n"
1265                "DP4 result.position.z, mvp[2], position;\n"
1266                "DP4 result.position.w, mvp[3], position;\n"
1267
1268                // gl_FrontColor = vec4(1.0,1.0,1.0,1.0);
1269                "MOV result.color.front.primary, one;\n"
1270
1271                // texcoord = gl_MultiTexCoord0.st;
1272                "MOV result.texcoord, tc;\n"
1273                "END\n";
1274
1275
1276            // fragment program
1277            std::ostringstream fp_oss;
1278            fp_oss <<
1279                "!!ARBfp1.0\n"
1280                "TEX result.color, fragment.texcoord[" << 0 << "], texture[" << 0 << "], 2D;"
1281                "END\n";
1282
1283            osg::ref_ptr<osg::VertexProgram> vp = new osg::VertexProgram;
1284            vp->setVertexProgram(vp_oss.str());
1285            stateset->setAttributeAndModes(vp.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);
1286
1287            osg::ref_ptr<osg::FragmentProgram> fp = new osg::FragmentProgram;
1288            fp->setFragmentProgram(fp_oss.str());
1289            stateset->setAttributeAndModes(fp.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);
1290        }
1291
1292        group->addChild(createShaderGraph(cell.get(),stateset));
1293        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"));
1294        _techniqueSwitch->addChild(group);
1295        std::cout<<"done."<<std::endl;
1296    }
1297
1298    {
1299        std::cout<<"Creating OpenGL shader based forest...";
1300        osg::Group* group = new osg::Group;
1301
1302        osg::StateSet* stateset = new osg::StateSet(*dstate, osg::CopyOp::DEEP_COPY_ALL);
1303
1304        {
1305            osg::Program* program = new osg::Program;
1306            stateset->setAttribute(program);
1307
1308#if 1
1309            // use inline shaders
1310
1311            ///////////////////////////////////////////////////////////////////
1312            // vertex shader using just Vec4 coefficients
1313            char vertexShaderSource[] =
1314                "varying vec2 texcoord;\n"
1315                "\n"
1316                "void main(void)\n"
1317                "{\n"
1318                "    vec3 position = gl_Vertex.xyz * gl_Color.w + gl_Color.xyz;\n"
1319                "    gl_Position     = gl_ModelViewProjectionMatrix * vec4(position,1.0);\n"
1320                "    gl_FrontColor = vec4(1.0,1.0,1.0,1.0);\n"
1321                "    texcoord = gl_MultiTexCoord0.st;\n"
1322                "}\n";
1323
1324            //////////////////////////////////////////////////////////////////
1325            // fragment shader
1326            //
1327            char fragmentShaderSource[] =
1328                "uniform sampler2D baseTexture; \n"
1329                "varying vec2 texcoord; \n"
1330                "\n"
1331                "void main(void) \n"
1332                "{ \n"
1333                "    gl_FragColor = texture2D( baseTexture, texcoord); \n"
1334                "}\n";
1335
1336            osg::Shader* vertex_shader = new osg::Shader(osg::Shader::VERTEX, vertexShaderSource);
1337            program->addShader(vertex_shader);
1338
1339            osg::Shader* fragment_shader = new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource);
1340            program->addShader(fragment_shader);
1341
1342#else
1343
1344            // get shaders from source
1345            program->addShader(osg::Shader::readShaderFile(osg::Shader::VERTEX, osgDB::findDataFile("shaders/forest.vert")));
1346            program->addShader(osg::Shader::readShaderFile(osg::Shader::FRAGMENT, osgDB::findDataFile("shaders/forest.frag")));
1347
1348#endif
1349
1350            osg::Uniform* baseTextureSampler = new osg::Uniform("baseTexture",0);
1351            stateset->addUniform(baseTextureSampler);
1352        }
1353
1354        group->addChild(createShaderGraph(cell.get(),stateset));
1355        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"));
1356        _techniqueSwitch->addChild(group);
1357        std::cout<<"done."<<std::endl;
1358    }
1359
1360    {
1361        std::cout<<"Creating Geometry Shader based forest...";
1362
1363        osg::StateSet* stateset = new osg::StateSet(*dstate, osg::CopyOp::DEEP_COPY_ALL);
1364
1365        osg::Group* group = new osg::Group;
1366        group->addChild(createGeometryShaderGraph(cell.get(), stateset));
1367        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"));
1368
1369        _techniqueSwitch->addChild(group);
1370        std::cout<<"done."<<std::endl;
1371    }
1372   
1373    {
1374        std::cout<<"Creating forest using geometry instancing and texture buffer objects ...";
1375
1376        osg::StateSet* stateset = new osg::StateSet(*dstate, osg::CopyOp::DEEP_COPY_ALL);
1377        {
1378            osg::Program* program = new osg::Program;
1379            stateset->setAttribute(program);
1380
1381            char vertexShaderSource[] =
1382                "#version 420 compatibility\n"
1383                "uniform samplerBuffer dataBuffer;\n"
1384                "layout(location = 0) in vec3 VertexPosition;\n"
1385                "layout(location = 8) in vec3 VertexTexCoord;\n"
1386                "out vec2 TexCoord;\n"
1387                "out vec4 Color;\n"
1388                "void main()\n"
1389                "{\n"
1390                "   int instanceAddress = gl_InstanceID * 3;\n"
1391                "   vec3 position = texelFetch(dataBuffer, instanceAddress).xyz;\n"
1392                "   Color         = texelFetch(dataBuffer, instanceAddress + 1);\n"
1393                "   vec2 size     = texelFetch(dataBuffer, instanceAddress + 2).xy;\n"
1394                "   mat4 mvpMatrix = gl_ModelViewProjectionMatrix *\n" 
1395                "        mat4( size.x, 0.0, 0.0, 0.0,\n"
1396                "              0.0, size.x, 0.0, 0.0,\n"
1397                "              0.0, 0.0, size.y, 0.0,\n"
1398                "              position.x, position.y, position.z, 1.0);\n"
1399                "   gl_Position = mvpMatrix * vec4(VertexPosition,1.0) ;\n"
1400                "   TexCoord = VertexTexCoord.xy;\n"
1401                "}\n";
1402
1403            char fragmentShaderSource[] =
1404                "#version 420 core\n"
1405                "uniform sampler2D baseTexture; \n"
1406                "in vec2 TexCoord;\n"
1407                "in vec4 Color;\n"
1408                "layout(location = 0, index = 0) out vec4 FragData0;\n"
1409                "void main(void) \n"
1410                "{\n"
1411                "    FragData0 = Color*texture(baseTexture, TexCoord);\n"
1412                "}\n";
1413
1414            osg::Shader* vertex_shader = new osg::Shader(osg::Shader::VERTEX, vertexShaderSource);
1415            program->addShader(vertex_shader);
1416
1417            osg::Shader* fragment_shader = new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource);
1418            program->addShader(fragment_shader);
1419
1420            osg::Uniform* baseTextureSampler = new osg::Uniform("baseTexture",0);
1421            stateset->addUniform(baseTextureSampler);
1422           
1423            osg::Uniform* dataBufferSampler = new osg::Uniform("dataBuffer",1);
1424            stateset->addUniform(dataBufferSampler);
1425        }
1426       
1427        osg::ref_ptr<osg::Geometry> templateGeometry = createOrthogonalQuadsNoColor(osg::Vec3(0.0f,0.0f,0.0f),1.0f,1.0f);
1428        templateGeometry->setUseVertexBufferObjects(true);
1429        templateGeometry->setUseDisplayList(false);
1430        osg::Node* textureBufferGraph = createTextureBufferGraph(cell.get(), templateGeometry.get());
1431        textureBufferGraph->setStateSet( stateset );
1432        osg::Group* group = new osg::Group;
1433        group->addChild(textureBufferGraph);
1434        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"));
1435
1436        _techniqueSwitch->addChild(group);
1437       
1438        std::cout<<"done."<<std::endl;
1439    }
1440   
1441
1442    _currentTechnique = 0;
1443    _techniqueSwitch->setSingleChildOn(_currentTechnique);
1444
1445
1446    osg::Group* scene = new osg::Group;
1447
1448    scene->addChild(terrain.get());
1449    scene->addChild(_techniqueSwitch.get());
1450
1451    return scene;
1452}
1453
1454int main( int argc, char **argv )
1455{
1456
1457    // use an ArgumentParser object to manage the program arguments.
1458    osg::ArgumentParser arguments(&argc,argv);
1459
1460    // construct the viewer.
1461    osgViewer::Viewer viewer(arguments);
1462
1463    unsigned int numTreesToCreate = 10000;
1464    arguments.read("--trees",numTreesToCreate);
1465   
1466    unsigned int maxNumTreesPerCell = sqrtf(static_cast<float>(numTreesToCreate));
1467   
1468    arguments.read("--trees-per-cell",maxNumTreesPerCell);
1469
1470    osg::ref_ptr<ForestTechniqueManager> ttm = new ForestTechniqueManager;
1471   
1472    // add the stats handler
1473    viewer.addEventHandler(new osgViewer::StatsHandler);
1474
1475    viewer.addEventHandler(new TechniqueEventHandler(ttm.get()));
1476    viewer.addEventHandler(new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()));
1477
1478    // add model to viewer.
1479    viewer.setSceneData( ttm->createScene(numTreesToCreate, maxNumTreesPerCell) );
1480
1481
1482    return viewer.run();
1483}
Note: See TracBrowser for help on using the browser.