root/OpenSceneGraph/trunk/src/osgUtil/RenderBin.cpp @ 10504

Revision 10504, 17.3 kB (checked in by robert, 5 years ago)

From Chris Hanson, typo and comment clean ups

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2 *
3 * This library is open source and may be redistributed and/or modified under 
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version.  The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * OpenSceneGraph Public License for more details.
12*/
13#include <stdlib.h>
14#include <string.h>
15
16#include <osgUtil/RenderBin>
17#include <osgUtil/RenderStage>
18#include <osgUtil/Statistics>
19
20#include <osg/Notify>
21#include <osg/ApplicationUsage>
22#include <osg/AlphaFunc>
23
24#include <algorithm>
25
26using namespace osg;
27using namespace osgUtil;
28
29class RenderBinPrototypeList : osg::depends_on<OpenThreads::Mutex*, osg::Referenced::getGlobalReferencedMutex>,
30                               public osg::Referenced, public std::map< std::string, osg::ref_ptr<RenderBin> >
31{
32    public:
33        RenderBinPrototypeList() {}
34        ~RenderBinPrototypeList() {}
35};
36
37// register a RenderStage prototype with the RenderBin prototype list.
38RegisterRenderBinProxy s_registerRenderBinProxy("RenderBin",new RenderBin(RenderBin::getDefaultRenderBinSortMode()));
39RegisterRenderBinProxy s_registerStateSortedBinProxy("StateSortedBin",new RenderBin(RenderBin::SORT_BY_STATE));
40RegisterRenderBinProxy s_registerDepthSortedBinProxy("DepthSortedBin",new RenderBin(RenderBin::SORT_BACK_TO_FRONT));
41RegisterRenderBinProxy s_registerTraversalOrderProxy("TraversalOrderBin",new RenderBin(RenderBin::TRAVERSAL_ORDER));
42
43
44static RenderBinPrototypeList* renderBinPrototypeList()
45{
46    static osg::ref_ptr<RenderBinPrototypeList> s_renderBinPrototypeList = new  RenderBinPrototypeList;
47    return s_renderBinPrototypeList.get();
48}
49
50RenderBin* RenderBin::getRenderBinPrototype(const std::string& binName)
51{
52    RenderBinPrototypeList* list = renderBinPrototypeList();
53    if (list)
54    {
55        RenderBinPrototypeList::iterator itr = list->find(binName);
56        if (itr != list->end()) return itr->second.get();
57    }
58    return NULL;
59}
60
61RenderBin* RenderBin::createRenderBin(const std::string& binName)
62{
63    RenderBinPrototypeList* list = renderBinPrototypeList();
64    if (list)
65    {
66        RenderBin* prototype = getRenderBinPrototype(binName);
67        if (prototype) return dynamic_cast<RenderBin*>(prototype->clone(osg::CopyOp::DEEP_COPY_ALL));
68    }
69   
70    osg::notify(osg::WARN) <<"Warning: RenderBin \""<<binName<<"\" implementation not found, using default RenderBin as a fallback."<<std::endl;
71    return new RenderBin;
72}
73
74void RenderBin::addRenderBinPrototype(const std::string& binName,RenderBin* proto)
75{
76    RenderBinPrototypeList* list = renderBinPrototypeList();
77    if (list && proto)
78    {
79        (*list)[binName] = proto;
80    }
81}
82
83void RenderBin::removeRenderBinPrototype(RenderBin* proto)
84{
85    RenderBinPrototypeList* list = renderBinPrototypeList();
86    if (list && proto)
87    {
88        for(RenderBinPrototypeList::iterator itr = list->begin();
89            itr != list->end();
90            ++itr)
91        {
92            if (itr->second == proto)
93            {
94                // osg::notify(osg::NOTICE)<<"Found protype, now erasing "<<itr->first<<std::endl;
95                list->erase(itr);
96                return;
97            }
98        }
99    }
100    // osg::notify(osg::NOTICE)<<"Not found protype"<<std::endl;
101}
102
103static bool s_defaultBinSortModeInitialized = false;
104static RenderBin::SortMode s_defaultBinSortMode = RenderBin::SORT_BY_STATE;
105static osg::ApplicationUsageProxy RenderBin_e0(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_DEFAULT_BIN_SORT_MODE <type>","SORT_BY_STATE | SORT_BY_STATE_THEN_FRONT_TO_BACK | SORT_FRONT_TO_BACK | SORT_BACK_TO_FRONT");
106
107void RenderBin::setDefaultRenderBinSortMode(RenderBin::SortMode mode)
108{
109    s_defaultBinSortModeInitialized = true;
110    s_defaultBinSortMode = mode;
111}
112
113
114RenderBin::SortMode RenderBin::getDefaultRenderBinSortMode()
115{
116    if (!s_defaultBinSortModeInitialized)
117    {
118        s_defaultBinSortModeInitialized = true;
119       
120        const char* str = getenv("OSG_DEFAULT_BIN_SORT_MODE");
121        if (str)
122        {
123            if (strcmp(str,"SORT_BY_STATE")==0) s_defaultBinSortMode = RenderBin::SORT_BY_STATE;
124            else if (strcmp(str,"SORT_BY_STATE_THEN_FRONT_TO_BACK")==0) s_defaultBinSortMode = RenderBin::SORT_BY_STATE_THEN_FRONT_TO_BACK;
125            else if (strcmp(str,"SORT_FRONT_TO_BACK")==0) s_defaultBinSortMode = RenderBin::SORT_FRONT_TO_BACK;
126            else if (strcmp(str,"SORT_BACK_TO_FRONT")==0) s_defaultBinSortMode = RenderBin::SORT_BACK_TO_FRONT;
127            else if (strcmp(str,"TRAVERSAL_ORDER")==0) s_defaultBinSortMode = RenderBin::TRAVERSAL_ORDER;
128        }
129    }
130   
131    return s_defaultBinSortMode;
132}
133
134RenderBin::RenderBin()
135{
136    _binNum = 0;
137    _parent = NULL;
138    _stage = NULL;
139    _sorted = false;
140    _sortMode = getDefaultRenderBinSortMode();
141}
142
143RenderBin::RenderBin(SortMode mode)
144{
145    _binNum = 0;
146    _parent = NULL;
147    _stage = NULL;
148    _sorted = false;
149    _sortMode = mode;
150
151#if 1
152    if (_sortMode==SORT_BACK_TO_FRONT)
153    {
154        _stateset  = new osg::StateSet;
155        _stateset->setThreadSafeRefUnref(true);
156       
157         // set up an alphafunc by default to speed up blending operations.
158        osg::AlphaFunc* alphafunc = new osg::AlphaFunc;
159        alphafunc->setFunction(osg::AlphaFunc::GREATER,0.0f);
160        alphafunc->setThreadSafeRefUnref(true);
161       
162        _stateset->setAttributeAndModes(alphafunc, osg::StateAttribute::ON);
163    }
164#endif   
165}
166
167RenderBin::RenderBin(const RenderBin& rhs,const CopyOp& copyop):
168        Object(rhs,copyop),
169        _binNum(rhs._binNum),
170        _parent(rhs._parent),
171        _stage(rhs._stage),
172        _bins(rhs._bins),
173        _stateGraphList(rhs._stateGraphList),
174        _renderLeafList(rhs._renderLeafList),
175        _sorted(rhs._sorted),
176        _sortMode(rhs._sortMode),
177        _sortCallback(rhs._sortCallback),
178        _drawCallback(rhs._drawCallback),
179        _stateset(rhs._stateset)
180{
181
182}
183
184RenderBin::~RenderBin()
185{
186}
187
188void RenderBin::reset()
189{
190    _stateGraphList.clear();
191    _renderLeafList.clear();
192    _bins.clear();
193    _sorted = false;
194}
195
196void RenderBin::sort()
197{
198    if (_sorted) return;
199
200    for(RenderBinList::iterator itr = _bins.begin();
201        itr!=_bins.end();
202        ++itr)
203    {
204        itr->second->sort();
205    }
206   
207    if (_sortCallback.valid())
208    {
209        _sortCallback->sortImplementation(this);
210    }
211    else sortImplementation();
212   
213    _sorted = true;
214}
215
216void RenderBin::setSortMode(SortMode mode)
217{
218    _sortMode = mode;
219}
220
221void RenderBin::sortImplementation()
222{
223    switch(_sortMode)
224    {
225        case(SORT_BY_STATE):
226            sortByState();
227            break;
228        case(SORT_BY_STATE_THEN_FRONT_TO_BACK):
229            sortByStateThenFrontToBack();
230            break;
231        case(SORT_FRONT_TO_BACK):
232            sortFrontToBack();
233            break;
234        case(SORT_BACK_TO_FRONT):
235            sortBackToFront();
236            break;
237        case(TRAVERSAL_ORDER):
238            sortTraversalOrder();
239            break;
240    }
241}
242
243struct SortByStateFunctor
244{
245    bool operator() (const StateGraph* lhs,const StateGraph* rhs) const
246    {
247        return (*(lhs->_stateset)<*(rhs->_stateset));
248    }
249};
250
251void RenderBin::sortByState()
252{
253    //osg::notify(osg::NOTICE)<<"sortByState()"<<std::endl;
254    // actually we'll do nothing right now, as fine grained sorting by state
255    // appears to cost more to do than it saves in draw.  The contents of
256    // the StateGraph leaves is already coarse grained sorted, this
257    // sorting is as a function of the cull traversal.
258    // cout << "doing sortByState "<<this<<endl;
259}
260
261
262struct StateGraphFrontToBackSortFunctor
263{
264    bool operator() (const StateGraph* lhs,const StateGraph* rhs) const
265    {
266        return (lhs->_minimumDistance<rhs->_minimumDistance);
267    }
268};
269
270void RenderBin::sortByStateThenFrontToBack()
271{
272    for(StateGraphList::iterator itr=_stateGraphList.begin();
273        itr!=_stateGraphList.end();
274        ++itr)
275    {
276        (*itr)->sortFrontToBack();
277        (*itr)->getMinimumDistance();
278    }
279    std::sort(_stateGraphList.begin(),_stateGraphList.end(),StateGraphFrontToBackSortFunctor());
280}
281
282struct FrontToBackSortFunctor
283{
284    bool operator() (const RenderLeaf* lhs,const RenderLeaf* rhs) const
285    {
286        return (lhs->_depth<rhs->_depth);
287    }
288};
289
290   
291void RenderBin::sortFrontToBack()
292{
293    copyLeavesFromStateGraphListToRenderLeafList();
294
295    // now sort the list into acending depth order.
296    std::sort(_renderLeafList.begin(),_renderLeafList.end(),FrontToBackSortFunctor());
297   
298//    cout << "sort front to back"<<endl;
299}
300
301struct BackToFrontSortFunctor
302{
303    bool operator() (const RenderLeaf* lhs,const RenderLeaf* rhs) const
304    {
305        return (rhs->_depth<lhs->_depth);
306    }
307};
308
309void RenderBin::sortBackToFront()
310{
311    copyLeavesFromStateGraphListToRenderLeafList();
312
313    // now sort the list into acending depth order.
314    std::sort(_renderLeafList.begin(),_renderLeafList.end(),BackToFrontSortFunctor());
315
316//    cout << "sort back to front"<<endl;
317}
318
319
320struct TraversalOrderFunctor
321{
322    bool operator() (const RenderLeaf* lhs,const RenderLeaf* rhs) const
323    {
324        return (lhs->_traversalNumber<rhs->_traversalNumber);
325    }
326};
327
328void RenderBin::sortTraversalOrder()
329{
330    copyLeavesFromStateGraphListToRenderLeafList();
331
332    // now sort the list into acending depth order.
333    std::sort(_renderLeafList.begin(),_renderLeafList.end(),TraversalOrderFunctor());
334}
335
336void RenderBin::copyLeavesFromStateGraphListToRenderLeafList()
337{
338    _renderLeafList.clear();
339
340    int totalsize=0;
341    StateGraphList::iterator itr;
342    for(itr=_stateGraphList.begin();
343        itr!=_stateGraphList.end();
344        ++itr)
345    {
346        totalsize += (*itr)->_leaves.size();
347    }
348
349    _renderLeafList.reserve(totalsize);
350   
351    bool detectedNaN = false;
352       
353    // first copy all the leaves from the render graphs into the leaf list.
354    for(itr=_stateGraphList.begin();
355        itr!=_stateGraphList.end();
356        ++itr)
357    {
358        for(StateGraph::LeafList::iterator dw_itr = (*itr)->_leaves.begin();
359            dw_itr != (*itr)->_leaves.end();
360            ++dw_itr)
361        {
362            if (!osg::isNaN((*dw_itr)->_depth))
363            {
364                _renderLeafList.push_back(dw_itr->get());
365            }
366            else
367            {
368                detectedNaN = true;
369            }
370        }
371    }
372   
373    if (detectedNaN) osg::notify(osg::NOTICE)<<"Warning: RenderBin::copyLeavesFromStateGraphListToRenderLeafList() detected NaN depth values, database may be corrupted."<<std::endl;
374   
375    // empty the render graph list to prevent it being drawn along side the render leaf list (see drawImplementation.)
376    _stateGraphList.clear();
377}
378
379RenderBin* RenderBin::find_or_insert(int binNum,const std::string& binName)
380{
381    // search for appropriate bin.
382    RenderBinList::iterator itr = _bins.find(binNum);
383    if (itr!=_bins.end()) return itr->second.get();
384
385    // create a rendering bin and insert into bin list.
386    RenderBin* rb = RenderBin::createRenderBin(binName);
387    if (rb)
388    {
389
390        RenderStage* rs = dynamic_cast<RenderStage*>(rb);
391        if (rs)
392        {
393            rs->_binNum = binNum;
394            rs->_parent = NULL;
395            rs->_stage = rs;
396            _stage->addPreRenderStage(rs);
397        }
398        else
399        {
400            rb->_binNum = binNum;
401            rb->_parent = this;
402            rb->_stage = _stage;
403            _bins[binNum] = rb;
404        }
405    }
406    return rb;
407}
408
409void RenderBin::draw(osg::RenderInfo& renderInfo,RenderLeaf*& previous)
410{
411    if (_drawCallback.valid())
412    {
413        _drawCallback->drawImplementation(this,renderInfo,previous);
414    }
415    else drawImplementation(renderInfo,previous);
416}
417
418void RenderBin::drawImplementation(osg::RenderInfo& renderInfo,RenderLeaf*& previous)
419{
420    osg::State& state = *renderInfo.getState();
421
422    // osg::notify(osg::NOTICE)<<"begin RenderBin::drawImplementation "<<className()<<" sortMode "<<getSortMode()<<std::endl;
423
424
425    unsigned int numToPop = (previous ? StateGraph::numToPop(previous->_parent) : 0);
426    if (numToPop>1) --numToPop;
427    unsigned int insertStateSetPosition = state.getStateSetStackSize() - numToPop;
428
429    if (_stateset.valid())
430    {
431        state.insertStateSet(insertStateSetPosition, _stateset.get());
432    }
433
434
435    // draw first set of draw bins.
436    RenderBinList::iterator rbitr;
437    for(rbitr = _bins.begin();
438        rbitr!=_bins.end() && rbitr->first<0;
439        ++rbitr)
440    {
441        rbitr->second->draw(renderInfo,previous);
442    }
443
444    // draw fine grained ordering.
445    for(RenderLeafList::iterator rlitr= _renderLeafList.begin();
446        rlitr!= _renderLeafList.end();
447        ++rlitr)
448    {
449        RenderLeaf* rl = *rlitr;
450        rl->render(renderInfo,previous);
451        previous = rl;
452    }
453
454
455    bool draw_forward = true; //(_sortMode!=SORT_BY_STATE) || (state.getFrameStamp()->getFrameNumber() % 2)==0;
456
457    // draw coarse grained ordering.
458    if (draw_forward)
459    {
460        for(StateGraphList::iterator oitr=_stateGraphList.begin();
461            oitr!=_stateGraphList.end();
462            ++oitr)
463        {
464
465            for(StateGraph::LeafList::iterator dw_itr = (*oitr)->_leaves.begin();
466                dw_itr != (*oitr)->_leaves.end();
467                ++dw_itr)
468            {
469                RenderLeaf* rl = dw_itr->get();
470                rl->render(renderInfo,previous);
471                previous = rl;
472
473            }
474        }
475    }
476    else
477    {
478        for(StateGraphList::reverse_iterator oitr=_stateGraphList.rbegin();
479            oitr!=_stateGraphList.rend();
480            ++oitr)
481        {
482
483            for(StateGraph::LeafList::iterator dw_itr = (*oitr)->_leaves.begin();
484                dw_itr != (*oitr)->_leaves.end();
485                ++dw_itr)
486            {
487                RenderLeaf* rl = dw_itr->get();
488                rl->render(renderInfo,previous);
489                previous = rl;
490
491            }
492        }
493    }
494
495    // draw post bins.
496    for(;
497        rbitr!=_bins.end();
498        ++rbitr)
499    {
500        rbitr->second->draw(renderInfo,previous);
501    }
502
503    if (_stateset.valid())
504    {
505        state.removeStateSet(insertStateSetPosition);
506        // state.apply();
507    }
508
509
510    // osg::notify(osg::NOTICE)<<"end RenderBin::drawImplementation "<<className()<<std::endl;
511}
512
513// stats
514bool RenderBin::getStats(Statistics& stats) const
515{
516    stats.addBins(1);
517
518    // different by return type - collects the stats in this renderrBin
519    bool statsCollected = false;
520
521    // draw fine grained ordering.
522    for(RenderLeafList::const_iterator dw_itr = _renderLeafList.begin();
523        dw_itr != _renderLeafList.end();
524        ++dw_itr)
525    {
526        const RenderLeaf* rl = *dw_itr;
527        const Drawable* dw= rl->getDrawable();
528        stats.addDrawable(); // number of geosets
529        if (rl->_modelview.get())
530        {
531            stats.addMatrix(); // number of matrices
532        }
533       
534        if (dw)
535        {
536              // then tot up the primitive types and no vertices.
537              dw->accept(stats); // use sub-class to find the stats for each drawable
538        }
539        statsCollected = true;
540    }
541
542    for(StateGraphList::const_iterator oitr=_stateGraphList.begin();
543        oitr!=_stateGraphList.end();
544        ++oitr)
545    {
546       
547        for(StateGraph::LeafList::const_iterator dw_itr = (*oitr)->_leaves.begin();
548            dw_itr != (*oitr)->_leaves.end();
549            ++dw_itr)
550        {
551            const RenderLeaf* rl = dw_itr->get();
552            const Drawable* dw= rl->getDrawable();
553            stats.addDrawable(); // number of geosets
554            if (rl->_modelview.get()) stats.addMatrix(); // number of matrices
555            if (dw)
556            {
557                // then tot up the primitive types and no vertices.
558                dw->accept(stats); // use sub-class to find the stats for each drawable
559            }
560        }
561        statsCollected = true;
562    }
563
564    // now collects stats for any subbins.
565    for(RenderBinList::const_iterator itr = _bins.begin();
566        itr!=_bins.end();
567        ++itr)
568    {
569        if (itr->second->getStats(stats))
570        {
571            statsCollected = true;
572        }
573    }
574
575    return statsCollected;
576}
577
578unsigned int RenderBin::computeNumberOfDynamicRenderLeaves() const
579{
580    unsigned int count = 0;
581
582    // draw first set of draw bins.
583    RenderBinList::const_iterator rbitr;
584    for(rbitr = _bins.begin();
585        rbitr!=_bins.end() && rbitr->first<0;
586        ++rbitr)
587    {
588        count += rbitr->second->computeNumberOfDynamicRenderLeaves();
589    }
590
591    // draw fine grained ordering.
592    for(RenderLeafList::const_iterator rlitr= _renderLeafList.begin();
593        rlitr!= _renderLeafList.end();
594        ++rlitr)
595    {
596        RenderLeaf* rl = *rlitr;
597        if (rl->_dynamic) ++count;
598    }
599
600
601    // draw coarse grained ordering.
602    for(StateGraphList::const_iterator oitr=_stateGraphList.begin();
603        oitr!=_stateGraphList.end();
604        ++oitr)
605    {
606
607        for(StateGraph::LeafList::const_iterator dw_itr = (*oitr)->_leaves.begin();
608            dw_itr != (*oitr)->_leaves.end();
609            ++dw_itr)
610        {
611            RenderLeaf* rl = dw_itr->get();
612            if (rl->_dynamic) ++count;
613        }
614    }
615
616    // draw post bins.
617    for(;
618        rbitr!=_bins.end();
619        ++rbitr)
620    {
621        count += rbitr->second->computeNumberOfDynamicRenderLeaves();
622    }
623   
624    return count;
625}
Note: See TracBrowser for help on using the browser.