Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/OgreMain/src/OgreRenderQueueSortingGrouping.cpp @ 3

Last change on this file since 3 was 3, checked in by anonymous, 17 years ago

=update

File size: 15.2 KB
Line 
1/*
2-----------------------------------------------------------------------------
3This source file is part of OGRE
4(Object-oriented Graphics Rendering Engine)
5For the latest info, see http://www.ogre3d.org/
6
7Copyright (c) 2000-2006 Torus Knot Software Ltd
8Also see acknowledgements in Readme.html
9
10This program is free software; you can redistribute it and/or modify it under
11the terms of the GNU Lesser General Public License as published by the Free Software
12Foundation; either version 2 of the License, or (at your option) any later
13version.
14
15This program is distributed in the hope that it will be useful, but WITHOUT
16ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
18
19You should have received a copy of the GNU Lesser General Public License along with
20this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21Place - Suite 330, Boston, MA 02111-1307, USA, or go to
22http://www.gnu.org/copyleft/lesser.txt.
23
24You may alternatively use this source under the terms of a specific version of
25the OGRE Unrestricted License provided you have obtained such a license from
26Torus Knot Software Ltd.
27-----------------------------------------------------------------------------
28*/
29#include "OgreStableHeaders.h"
30#include "OgreRenderQueueSortingGrouping.h"
31#include "OgreException.h"
32
33namespace Ogre {
34    // Init statics
35    RadixSort<QueuedRenderableCollection::RenderablePassList,
36        RenderablePass, uint32> QueuedRenderableCollection::msRadixSorter1;
37    RadixSort<QueuedRenderableCollection::RenderablePassList,
38        RenderablePass, float> QueuedRenderableCollection::msRadixSorter2;
39
40
41        //-----------------------------------------------------------------------
42        RenderPriorityGroup::RenderPriorityGroup(RenderQueueGroup* parent, 
43            bool splitPassesByLightingType,
44            bool splitNoShadowPasses, 
45                        bool shadowCastersNotReceivers)
46                : mParent(parent)
47        , mSplitPassesByLightingType(splitPassesByLightingType)
48        , mSplitNoShadowPasses(splitNoShadowPasses)
49        , mShadowCastersNotReceivers(shadowCastersNotReceivers)
50        {
51                // Initialise collection sorting options
52                // this can become dynamic according to invocation later
53                defaultOrganisationMode();
54
55                // Transparents will always be sorted this way
56                mTransparents.addOrganisationMode(QueuedRenderableCollection::OM_SORT_DESCENDING);
57
58               
59        }
60        //-----------------------------------------------------------------------
61        void RenderPriorityGroup::resetOrganisationModes(void)
62        {
63                mSolidsBasic.resetOrganisationModes();
64                mSolidsDiffuseSpecular.resetOrganisationModes();
65                mSolidsDecal.resetOrganisationModes();
66                mSolidsNoShadowReceive.resetOrganisationModes();
67        }
68        //-----------------------------------------------------------------------
69        void RenderPriorityGroup::addOrganisationMode(QueuedRenderableCollection::OrganisationMode om)
70        {
71                mSolidsBasic.addOrganisationMode(om);
72                mSolidsDiffuseSpecular.addOrganisationMode(om);
73                mSolidsDecal.addOrganisationMode(om);
74                mSolidsNoShadowReceive.addOrganisationMode(om);
75        }
76        //-----------------------------------------------------------------------
77        void RenderPriorityGroup::defaultOrganisationMode(void)
78        {
79                resetOrganisationModes();
80                addOrganisationMode(QueuedRenderableCollection::OM_PASS_GROUP);
81        }
82        //-----------------------------------------------------------------------
83    void RenderPriorityGroup::addRenderable(Renderable* rend, Technique* pTech)
84    {
85        // Transparent and depth/colour settings mean depth sorting is required?
86        // Note: colour write disabled with depth check/write enabled means
87        //       setup depth buffer for other passes use.
88        if (pTech->isTransparent() && 
89            (!pTech->isDepthWriteEnabled() ||
90             !pTech->isDepthCheckEnabled() ||
91             pTech->hasColourWriteDisabled()))
92        {
93            addTransparentRenderable(pTech, rend);
94        }
95        else
96        {
97            if (mSplitNoShadowPasses &&
98                mParent->getShadowsEnabled() &&
99                                (!pTech->getParent()->getReceiveShadows() ||
100                                rend->getCastsShadows() && mShadowCastersNotReceivers))
101            {
102                // Add solid renderable and add passes to no-shadow group
103                addSolidRenderable(pTech, rend, true);
104            }
105            else
106            {
107                if (mSplitPassesByLightingType && mParent->getShadowsEnabled())
108                {
109                    addSolidRenderableSplitByLightType(pTech, rend);
110                }
111                else
112                {
113                    addSolidRenderable(pTech, rend, false);
114                }
115            }
116        }
117
118    }
119    //-----------------------------------------------------------------------
120    void RenderPriorityGroup::addSolidRenderable(Technique* pTech, 
121        Renderable* rend, bool addToNoShadow)
122    {
123        Technique::PassIterator pi = pTech->getPassIterator();
124
125                QueuedRenderableCollection* collection;
126        if (addToNoShadow)
127        {
128            collection = &mSolidsNoShadowReceive;
129        }
130        else
131        {
132            collection = &mSolidsBasic;
133        }
134
135
136        while (pi.hasMoreElements())
137        {
138            // Insert into solid list
139            Pass* p = pi.getNext();
140                        collection->addRenderable(p, rend);
141        }
142    }
143    //-----------------------------------------------------------------------
144    void RenderPriorityGroup::addSolidRenderableSplitByLightType(Technique* pTech,
145        Renderable* rend)
146    {
147        // Divide the passes into the 3 categories
148        Technique::IlluminationPassIterator pi = 
149            pTech->getIlluminationPassIterator();
150
151        while (pi.hasMoreElements())
152        {
153            // Insert into solid list
154            IlluminationPass* p = pi.getNext();
155            QueuedRenderableCollection* collection;
156            switch(p->stage)
157            {
158            case IS_AMBIENT:
159                collection = &mSolidsBasic;
160                break;
161            case IS_PER_LIGHT:
162                collection = &mSolidsDiffuseSpecular;
163                break;
164            case IS_DECAL:
165                collection = &mSolidsDecal;
166                break;
167            default:
168                assert(false); // should never happen
169            };
170
171                        collection->addRenderable(p->pass, rend);
172        }
173    }
174    //-----------------------------------------------------------------------
175    void RenderPriorityGroup::addTransparentRenderable(Technique* pTech, Renderable* rend)
176    {
177        Technique::PassIterator pi = pTech->getPassIterator();
178
179        while (pi.hasMoreElements())
180        {
181            // Insert into transparent list
182            mTransparents.addRenderable(pi.getNext(), rend);
183        }
184    }
185    //-----------------------------------------------------------------------
186        void RenderPriorityGroup::removePassEntry(Pass* p)
187        {
188                mSolidsBasic.removePassGroup(p);
189                mSolidsDiffuseSpecular.removePassGroup(p);
190                mSolidsNoShadowReceive.removePassGroup(p);
191                mSolidsDecal.removePassGroup(p);
192                mTransparents.removePassGroup(p); // shouldn't be any, but for completeness
193        }       
194    //-----------------------------------------------------------------------
195    void RenderPriorityGroup::clear(void)
196    {
197        // Delete queue groups which are using passes which are to be
198        // deleted, we won't need these any more and they clutter up
199        // the list and can cause problems with future clones
200                {
201                        // Hmm, a bit hacky but least obtrusive for now
202                        OGRE_LOCK_MUTEX(Pass::msPassGraveyardMutex)
203                        const Pass::PassSet& graveyardList = Pass::getPassGraveyard();
204                        Pass::PassSet::const_iterator gi, giend;
205                        giend = graveyardList.end();
206                        for (gi = graveyardList.begin(); gi != giend; ++gi)
207                        {
208                                removePassEntry(*gi);
209                        }
210                }
211
212        // Now remove any dirty passes, these will have their hashes recalculated
213        // by the parent queue after all groups have been processed
214        // If we don't do this, the std::map will become inconsistent for new insterts
215                {
216                        // Hmm, a bit hacky but least obtrusive for now
217                        OGRE_LOCK_MUTEX(Pass::msDirtyHashListMutex)
218                        const Pass::PassSet& dirtyList = Pass::getDirtyHashList();
219                        Pass::PassSet::const_iterator di, diend;
220                        diend = dirtyList.end();
221                        for (di = dirtyList.begin(); di != diend; ++di)
222                        {
223                                removePassEntry(*di);
224                        }
225                }
226        // NB we do NOT clear the graveyard or the dirty list here, because
227        // it needs to be acted on for all groups, the parent queue takes
228        // care of this afterwards
229
230                // Now empty the remaining collections
231                // Note that groups don't get deleted, just emptied hence the difference
232                // between the pass groups which are removed above, and clearing done
233                // here
234                mSolidsBasic.clear();
235        mSolidsDecal.clear();
236        mSolidsDiffuseSpecular.clear();
237        mSolidsNoShadowReceive.clear();
238        mTransparents.clear();
239
240    }
241        //-----------------------------------------------------------------------
242        void RenderPriorityGroup::sort(const Camera* cam)
243        {
244                mSolidsBasic.sort(cam);
245                mSolidsDecal.sort(cam);
246                mSolidsDiffuseSpecular.sort(cam);
247                mSolidsNoShadowReceive.sort(cam);
248                mTransparents.sort(cam);
249        }
250    //-----------------------------------------------------------------------
251        QueuedRenderableCollection::QueuedRenderableCollection(void)
252                :mOrganisationMode(0)
253        {
254        }
255    //-----------------------------------------------------------------------
256        QueuedRenderableCollection::~QueuedRenderableCollection(void)
257        {
258        // destroy all the pass map entries (rather than clearing)
259        PassGroupRenderableMap::iterator i, iend;
260        iend = mGrouped.end();
261        for (i = mGrouped.begin(); i != iend; ++i)
262        {
263            // Free the list associated with this pass
264            delete i->second;
265        }
266               
267        }
268    //-----------------------------------------------------------------------
269        void QueuedRenderableCollection::clear(void)
270        {
271        PassGroupRenderableMap::iterator i, iend;
272        iend = mGrouped.end();
273        for (i = mGrouped.begin(); i != iend; ++i)
274        {
275            // Clear the list associated with this pass, but leave the pass entry
276            i->second->clear();
277        }
278
279                // Clear sorted list
280                mSortedDescending.clear();
281        }
282    //-----------------------------------------------------------------------
283        void QueuedRenderableCollection::removePassGroup(Pass* p)
284        {
285        PassGroupRenderableMap::iterator i;
286
287        i = mGrouped.find(p);
288        if (i != mGrouped.end())
289        {
290            // free memory
291            delete i->second;
292            // erase from map
293            mGrouped.erase(i);
294        }
295        }
296    //-----------------------------------------------------------------------
297        void QueuedRenderableCollection::sort(const Camera* cam)
298    {
299                // ascending and descending sort both set bit 1
300                if (mOrganisationMode & OM_SORT_DESCENDING)
301                {
302                       
303                        // We can either use a stable_sort and the 'less' implementation,
304                        // or a 2-pass radix sort (once by pass, then by distance, since
305                        // radix sorting is inherently stable this will work)
306                        // We use stable_sort if the number of items is 512 or less, since
307                        // the complexity of the radix sort is approximately O(10N), since
308                        // each sort is O(5N) (1 pass histograms, 4 passes sort)
309                        // Since stable_sort has a worst-case performance of O(N(logN)^2)
310                        // the performance tipping point is from about 1500 items, but in
311                        // stable_sorts best-case scenario O(NlogN) it would be much higher.
312                        // Take a stab at 2000 items.
313                       
314                        if (mSortedDescending.size() > 2000)
315                        {
316                                // sort by pass
317                                msRadixSorter1.sort(mSortedDescending, RadixSortFunctorPass());
318                                // sort by depth
319                                msRadixSorter2.sort(mSortedDescending, RadixSortFunctorDistance(cam));
320                        }
321                        else
322                        {
323                                std::stable_sort(
324                                        mSortedDescending.begin(), mSortedDescending.end(), 
325                                        DepthSortDescendingLess(cam));
326                        }
327                }
328
329                // Nothing needs to be done for pass groups, they auto-organise
330
331    }
332    //-----------------------------------------------------------------------
333    void QueuedRenderableCollection::addRenderable(Pass* pass, Renderable* rend)
334        {
335                // ascending and descending sort both set bit 1
336                if (mOrganisationMode & OM_SORT_DESCENDING)
337                {
338                        mSortedDescending.push_back(RenderablePass(rend, pass));
339                }
340
341                if (mOrganisationMode & OM_PASS_GROUP)
342                {
343            PassGroupRenderableMap::iterator i = mGrouped.find(pass);
344            if (i == mGrouped.end())
345            {
346                std::pair<PassGroupRenderableMap::iterator, bool> retPair;
347                // Create new pass entry, build a new list
348                // Note that this pass and list are never destroyed until the
349                                // engine shuts down, or a pass is destroyed or has it's hash
350                                // recalculated, although the lists will be cleared
351                retPair = mGrouped.insert(
352                    PassGroupRenderableMap::value_type(
353                                                pass, new RenderableList() ));
354                assert(retPair.second && 
355                                        "Error inserting new pass entry into PassGroupRenderableMap");
356                i = retPair.first;
357            }
358            // Insert renderable
359            i->second->push_back(rend);
360                       
361                }
362               
363        }
364    //-----------------------------------------------------------------------
365        void QueuedRenderableCollection::acceptVisitor(
366                QueuedRenderableVisitor* visitor, OrganisationMode om) const
367        {
368                if ((om & mOrganisationMode) == 0)
369                {
370                        OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 
371                                "Organisation mode requested in acceptVistor was not notified "
372                                "to this class ahead of time, therefore may not be supported.", 
373                                "QueuedRenderableCollection::acceptVisitor");
374                }
375
376                switch(om)
377                {
378                case OM_PASS_GROUP:
379                        acceptVisitorGrouped(visitor);
380                        break;
381                case OM_SORT_DESCENDING:
382                        acceptVisitorDescending(visitor);
383                        break;
384                case OM_SORT_ASCENDING:
385                        acceptVisitorAscending(visitor);
386                        break;
387                }
388               
389        }
390    //-----------------------------------------------------------------------
391        void QueuedRenderableCollection::acceptVisitorGrouped(
392                QueuedRenderableVisitor* visitor) const
393        {
394                PassGroupRenderableMap::const_iterator ipass, ipassend;
395                ipassend = mGrouped.end();
396                for (ipass = mGrouped.begin(); ipass != ipassend; ++ipass)
397                {
398                        // Fast bypass if this group is now empty
399                        if (ipass->second->empty()) continue;
400
401                        // Visit Pass - allow skip
402                        if (!visitor->visit(ipass->first))
403                                continue;
404
405                        RenderableList* rendList = ipass->second;
406                        RenderableList::const_iterator irend, irendend;
407                        irendend = rendList->end();
408                        for (irend = rendList->begin(); irend != irendend; ++irend)
409                        {
410                                // Visit Renderable
411                                visitor->visit(*irend);
412                        }
413                } 
414
415        }
416    //-----------------------------------------------------------------------
417        void QueuedRenderableCollection::acceptVisitorDescending(
418                QueuedRenderableVisitor* visitor) const
419        {
420                // List is already in descending order, so iterate forward
421                RenderablePassList::const_iterator i, iend;
422
423                iend = mSortedDescending.end();
424                for (i = mSortedDescending.begin(); i != iend; ++i)
425                {
426                        visitor->visit(&(*i));
427                }
428        }
429    //-----------------------------------------------------------------------
430        void QueuedRenderableCollection::acceptVisitorAscending(
431                QueuedRenderableVisitor* visitor) const
432        {
433                // List is in descending order, so iterate in reverse
434                RenderablePassList::const_reverse_iterator i, iend;
435
436                iend = mSortedDescending.rend();
437                for (i = mSortedDescending.rbegin(); i != iend; ++i)
438                {
439                        visitor->visit(&(*i));
440                }
441
442        }
443
444
445}
446
Note: See TracBrowser for help on using the repository browser.