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

Revision 13437, 47.4 kB (checked in by robert, 3 hours ago)

From Mattias Helsing, "Seems I was only half right given what you asked for. CMP0017 only
says that modules that are found and ran from cmake modules dir should
prefer cmake-provided modules. find_package() and include() still look
in CMAKE_MODULE_PATH first.

After some investigating I've come up with a proposal examplified in
the attached FindGDAL.cmake script. It simply calls the cmake provided
FindGDAL.cmake if it exists and returns if it succeeds in finding GDAL
using that, otherwise continue with our local cmake code.
Pro: Wont clutter our root CMakeLists.txt
Con: If we begin to write more advanced Findxxx modules (using
COMPONENTS, REQUIRED etc.) we may have to revise this scheme.
"

  • 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.