Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/OgreMain/include/OgreRenderQueueSortingGrouping.h @ 3

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

=update

File size: 22.3 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#ifndef __RenderQueueSortingGrouping_H__
30#define __RenderQueueSortingGrouping_H__
31
32// Precompiler options
33#include "OgrePrerequisites.h"
34#include "OgreIteratorWrappers.h"
35#include "OgreMaterial.h"
36#include "OgreTechnique.h"
37#include "OgrePass.h"
38#include "OgreRadixSort.h"
39
40namespace Ogre {
41
42        /** Struct associating a single Pass with a single Renderable.
43                This is used to for objects sorted by depth and thus not
44                grouped by pass.
45        */
46        struct RenderablePass
47        {
48                /// Pointer to the Renderable details
49                Renderable* renderable;
50                /// Pointer to the Pass
51                Pass* pass;
52
53                RenderablePass(Renderable* rend, Pass* p) :renderable(rend), pass(p) {}
54        };
55
56
57        /** Visitor interface for items in a QueuedRenderableCollection.
58        @remarks
59                Those wishing to iterate over the items in a
60                QueuedRenderableCollection should implement this visitor pattern,
61                since internal organisation of the collection depends on the
62                sorting method in use.
63        */
64        class _OgreExport QueuedRenderableVisitor
65        {
66        public:
67                QueuedRenderableVisitor() {}
68                virtual ~QueuedRenderableVisitor() {}
69               
70                /** Called when visiting a RenderablePass, ie items in a
71                        sorted collection where items are not grouped by pass.
72                @remarks
73                        If this is called, neither of the other 2 visit methods
74                        will be called.
75                */
76                virtual void visit(const RenderablePass* rp) = 0;
77
78                /* When visiting a collection grouped by pass, this is
79                        called when the grouping pass changes.
80                @remarks
81                        If this method is called, the RenderablePass visit
82                        method will not be called for this collection. The
83                        Renderable visit method will be called for each item
84                        underneath the pass grouping level.
85                @returns True to continue, false to skip the Renderables underneath
86                */
87                virtual bool visit(const Pass* p) = 0;
88                /** Visit method called once per Renderable on a grouped
89                        collection.
90                @remarks
91                        If this method is called, the RenderablePass visit
92                        method will not be called for this collection.
93                */
94                virtual void visit(const Renderable* r) = 0;
95               
96               
97        };
98
99        /** Lowest level collection of renderables.
100        @remarks
101                To iterate over items in this collection, you must call
102                the accept method and supply a QueuedRenderableVisitor.
103                The order of the iteration, and whether that iteration is
104                over a RenderablePass list or a 2-level grouped list which
105                causes a visit call at the Pass level, and a call for each
106                Renderable underneath.
107        */
108        class _OgreExport QueuedRenderableCollection
109        {
110        public:
111                /** Organisation modes required for this collection.
112                @remarks
113                        This affects the internal placement of the items added to this collection;
114                        if only one type of sorting / grouping is to be required, then renderables
115                        can be stored only once, whilst if multiple types are going to be needed
116                        then internally there will be multiple organisations. Changing the organisation
117                        needs to be done when the collection is empty.
118                */             
119                enum OrganisationMode
120                {
121                        /// Group by pass
122                        OM_PASS_GROUP = 1,
123                        /// Sort descending camera distance
124                        OM_SORT_DESCENDING = 2,
125                        /** Sort ascending camera distance
126                                Note value overlaps with descending since both use same sort
127                        */
128                        OM_SORT_ASCENDING = 6
129                };
130
131        protected:
132        /// Comparator to order pass groups
133        struct PassGroupLess
134        {
135            bool _OgreExport operator()(const Pass* a, const Pass* b) const
136            {
137                // Sort by passHash, which is pass, then texture unit changes
138                uint32 hasha = a->getHash();
139                uint32 hashb = b->getHash();
140                if (hasha == hashb)
141                {
142                    // Must differentTransparentQueueItemLessiate by pointer incase 2 passes end up with the same hash
143                    return a < b;
144                }
145                else
146                {
147                    return hasha < hashb;
148                }
149            }
150        };
151        /// Comparator to order objects by descending camera distance
152                struct DepthSortDescendingLess
153        {
154            const Camera* camera;
155
156            DepthSortDescendingLess(const Camera* cam)
157                : camera(cam)
158            {
159            }
160
161            bool _OgreExport operator()(const RenderablePass& a, const RenderablePass& b) const
162            {
163                if (a.renderable == b.renderable)
164                {
165                    // Same renderable, sort by pass hash
166                    return a.pass->getHash() < b.pass->getHash();
167                }
168                else
169                {
170                    // Different renderables, sort by depth
171                    Real adepth = a.renderable->getSquaredViewDepth(camera);
172                    Real bdepth = b.renderable->getSquaredViewDepth(camera);
173                                        if (Math::RealEqual(adepth, bdepth))
174                                    {
175                        // Must return deterministic result, doesn't matter what
176                        return a.pass < b.pass;
177                                    }
178                                    else
179                                    {
180                                        // Sort DESCENDING by depth (ie far objects first)
181                                            return (adepth > bdepth);
182                                    }
183                }
184
185            }
186        };
187
188        /** Vector of RenderablePass objects, this is built on the assumption that
189         vectors only ever increase in size, so even if we do clear() the memory stays
190         allocated, ie fast */
191        typedef std::vector<RenderablePass> RenderablePassList;
192        typedef std::vector<Renderable*> RenderableList;
193        /** Map of pass to renderable lists, this is a grouping by pass. */
194        typedef std::map<Pass*, RenderableList*, PassGroupLess> PassGroupRenderableMap;
195
196                /// Functor for accessing sort value 1 for radix sort (Pass)
197                struct RadixSortFunctorPass
198                {
199                        uint32 operator()(const RenderablePass& p) const
200            {
201                return p.pass->getHash();
202            }
203                };
204
205        /// Radix sorter for accessing sort value 1 (Pass)
206                static RadixSort<RenderablePassList, RenderablePass, uint32> msRadixSorter1;
207
208                /// Functor for descending sort value 2 for radix sort (distance)
209                struct RadixSortFunctorDistance
210                {
211                        const Camera* camera;
212
213            RadixSortFunctorDistance(const Camera* cam)
214                : camera(cam)
215            {
216            }
217
218                        float operator()(const RenderablePass& p) const
219            {
220                // Sort DESCENDING by depth (ie far objects first), use negative distance
221                // here because radix sorter always dealing with accessing sort
222                return static_cast<float>(- p.renderable->getSquaredViewDepth(camera));
223            }
224                };
225
226        /// Radix sorter for sort value 2 (distance)
227                static RadixSort<RenderablePassList, RenderablePass, float> msRadixSorter2;
228
229                /// Bitmask of the organisation modes requested
230                uint8 mOrganisationMode;
231
232                /// Grouped
233                PassGroupRenderableMap mGrouped;
234                /// Sorted descending (can iterate backwards to get ascending)
235                RenderablePassList mSortedDescending;
236
237                /// Internal visitor implementation
238                void acceptVisitorGrouped(QueuedRenderableVisitor* visitor) const;
239                /// Internal visitor implementation
240                void acceptVisitorDescending(QueuedRenderableVisitor* visitor) const;
241                /// Internal visitor implementation
242                void acceptVisitorAscending(QueuedRenderableVisitor* visitor) const;
243
244        public:
245                QueuedRenderableCollection();
246                ~QueuedRenderableCollection();
247
248                /// Empty the collection
249                void clear(void);
250
251                /** Remove the group entry (if any) for a given Pass.
252                @remarks
253                        To be used when a pass is destroyed, such that any
254                        grouping level for it becomes useless.
255                */     
256                void removePassGroup(Pass* p);
257               
258                /** Reset the organisation modes required for this collection.
259                @remarks
260                        You can only do this when the collection is empty.
261                @see OrganisationMode
262                */
263                void resetOrganisationModes(void) 
264                { 
265                        mOrganisationMode = 0; 
266                }
267               
268                /** Add a required sorting / grouping mode to this collection when next used.
269                @remarks
270                        You can only do this when the collection is empty.
271                @see OrganisationMode
272                */
273                void addOrganisationMode(OrganisationMode om) 
274                { 
275                        mOrganisationMode |= om; 
276                }
277
278        /// Add a renderable to the collection using a given pass
279        void addRenderable(Pass* pass, Renderable* rend);
280               
281                /** Perform any sorting that is required on this collection.
282                @param cam The camera
283                */
284                void sort(const Camera* cam);
285
286                /** Accept a visitor over the collection contents.
287                @param visitor Visitor class which should be called back
288                @param om The organisation mode which you want to iterate over.
289                        Note that this must have been included in an addOrganisationMode
290                        call before any renderables were added.
291                */
292                void acceptVisitor(QueuedRenderableVisitor* visitor, OrganisationMode om) const;
293               
294        };
295
296        /** Collection of renderables by priority.
297    @remarks
298        This class simply groups renderables for rendering. All the
299        renderables contained in this class are destined for the same
300        RenderQueueGroup (coarse groupings like those between the main
301        scene and overlays) and have the same priority (fine groupings
302        for detailed overlap control).
303    @par
304        This class can order solid renderables by a number of criteria;
305                it can optimise them into groups based on pass to reduce render
306                state changes, or can sort them by ascending or descending view
307                depth. Transparent objects are always ordered by descending depth.
308        @par
309                To iterate over items in the collections held by this object
310                you should retrieve the collection in use (e.g. solids, solids with
311                no shadows, transparents) and use the accept() method, providing
312                a class implementing QueuedRenderableVisitor.
313       
314    */
315    class _OgreExport RenderPriorityGroup
316    {
317        protected:
318
319                /// Parent queue group
320        RenderQueueGroup* mParent;
321        bool mSplitPassesByLightingType;
322        bool mSplitNoShadowPasses;
323                bool mShadowCastersNotReceivers;
324        /// Solid pass list, used when no shadows, modulative shadows, or ambient passes for additive
325                QueuedRenderableCollection mSolidsBasic;
326        /// Solid per-light pass list, used with additive shadows
327        QueuedRenderableCollection mSolidsDiffuseSpecular;
328        /// Solid decal (texture) pass list, used with additive shadows
329        QueuedRenderableCollection mSolidsDecal;
330        /// Solid pass list, used when shadows are enabled but shadow receive is turned off for these passes
331        QueuedRenderableCollection mSolidsNoShadowReceive;
332                /// Transparent list
333                QueuedRenderableCollection mTransparents;
334
335        /// remove a pass entry from all collections
336        void removePassEntry(Pass* p);
337
338        /// Internal method for adding a solid renderable
339        void addSolidRenderable(Technique* pTech, Renderable* rend, bool toNoShadowMap);
340        /// Internal method for adding a solid renderable
341        void addSolidRenderableSplitByLightType(Technique* pTech, Renderable* rend);
342        /// Internal method for adding a transparent renderable
343        void addTransparentRenderable(Technique* pTech, Renderable* rend);
344
345    public:
346        RenderPriorityGroup(RenderQueueGroup* parent, 
347            bool splitPassesByLightingType,
348            bool splitNoShadowPasses, 
349                        bool shadowCastersNotReceivers); 
350           
351        ~RenderPriorityGroup() { }
352
353        /** Get the collection of basic solids currently queued, this includes
354                        all solids when there are no shadows, or all solids which have shadow
355                        receiving enabled when using modulative shadows, or all ambient passes
356                        of solids which have shadow receive enabled for additive shadows. */
357        const QueuedRenderableCollection& getSolidsBasic(void) const
358        { return mSolidsBasic; }
359        /** Get the collection of solids currently queued per light (only applicable in
360                        additive shadow modes). */
361        const QueuedRenderableCollection& getSolidsDiffuseSpecular(void) const
362        { return mSolidsDiffuseSpecular; }
363        /** Get the collection of solids currently queued for decal passes (only
364                        applicable in additive shadow modes). */
365        const QueuedRenderableCollection& getSolidsDecal(void) const
366        { return mSolidsDecal; }
367        /** Get the collection of solids for which shadow receipt is disabled (only
368                        applicable when shadows are enabled). */
369        const QueuedRenderableCollection& getSolidsNoShadowReceive(void) const
370        { return mSolidsNoShadowReceive; }
371        /** Get the collection of transparent objects currently queued */
372        const QueuedRenderableCollection& getTransparents(void) const
373        { return mTransparents; }
374
375
376                /** Reset the organisation modes required for the solids in this group.
377                @remarks
378                        You can only do this when the group is empty, ie after clearing the
379                        queue.
380                @see QueuedRenderableCollection::OrganisationMode
381                */
382                void resetOrganisationModes(void);
383               
384                /** Add a required sorting / grouping mode for the solids in this group.
385                @remarks
386                        You can only do this when the group is empty, ie after clearing the
387                        queue.
388                @see QueuedRenderableCollection::OrganisationMode
389                */
390                void addOrganisationMode(QueuedRenderableCollection::OrganisationMode om); 
391
392                /** Set the sorting / grouping mode for the solids in this group to the default.
393                @remarks
394                        You can only do this when the group is empty, ie after clearing the
395                        queue.
396                @see QueuedRenderableCollection::OrganisationMode
397                */
398                void defaultOrganisationMode(void); 
399
400                /** Add a renderable to this group. */
401        void addRenderable(Renderable* pRend, Technique* pTech);
402
403                /** Sorts the objects which have been added to the queue; transparent objects by their
404            depth in relation to the passed in Camera. */
405                void sort(const Camera* cam);
406
407        /** Clears this group of renderables.
408        */
409        void clear(void);
410
411        /** Sets whether or not the queue will split passes by their lighting type,
412        ie ambient, per-light and decal.
413        */
414        void setSplitPassesByLightingType(bool split)
415        {
416            mSplitPassesByLightingType = split;
417        }
418
419        /** Sets whether or not passes which have shadow receive disabled should
420            be separated.
421        */
422        void setSplitNoShadowPasses(bool split)
423        {
424            mSplitNoShadowPasses = split;
425        }
426
427                /** Sets whether or not objects which cast shadows should be treated as
428                        never receiving shadows.
429                */
430                void setShadowCastersCannotBeReceivers(bool ind)
431                {
432                        mShadowCastersNotReceivers = ind;
433                }
434
435
436
437    };
438
439
440    /** A grouping level underneath RenderQueue which groups renderables
441    to be issued at coarsely the same time to the renderer.
442    @remarks
443        Each instance of this class itself hold RenderPriorityGroup instances,
444        which are the groupings of renderables by priority for fine control
445        of ordering (not required for most instances).
446    */
447    class _OgreExport RenderQueueGroup
448    {
449    public:
450        typedef std::map<ushort, RenderPriorityGroup*, std::less<ushort> > PriorityMap;
451        typedef MapIterator<PriorityMap> PriorityMapIterator;
452    protected:
453        RenderQueue* mParent;
454        bool mSplitPassesByLightingType;
455        bool mSplitNoShadowPasses;
456                bool mShadowCastersNotReceivers;
457        /// Map of RenderPriorityGroup objects
458        PriorityMap mPriorityGroups;
459                /// Whether shadows are enabled for this queue
460                bool mShadowsEnabled;
461
462
463    public:
464                RenderQueueGroup(RenderQueue* parent,
465            bool splitPassesByLightingType,
466            bool splitNoShadowPasses,
467            bool shadowCastersNotReceivers) 
468            : mParent(parent)
469            , mSplitPassesByLightingType(splitPassesByLightingType)
470            , mSplitNoShadowPasses(splitNoShadowPasses)
471            , mShadowCastersNotReceivers(shadowCastersNotReceivers)
472            , mShadowsEnabled(true)
473        {
474        }
475
476        ~RenderQueueGroup() {
477            // destroy contents now
478            PriorityMap::iterator i;
479            for (i = mPriorityGroups.begin(); i != mPriorityGroups.end(); ++i)
480            {
481                delete i->second;
482            }
483        }
484
485        /** Get an iterator for browsing through child contents. */
486        PriorityMapIterator getIterator(void)
487        {
488            return PriorityMapIterator(mPriorityGroups.begin(), mPriorityGroups.end());
489        }
490
491        /** Add a renderable to this group, with the given priority. */
492        void addRenderable(Renderable* pRend, Technique* pTech, ushort priority)
493        {
494            // Check if priority group is there
495            PriorityMap::iterator i = mPriorityGroups.find(priority);
496            RenderPriorityGroup* pPriorityGrp;
497            if (i == mPriorityGroups.end())
498            {
499                // Missing, create
500                pPriorityGrp = new RenderPriorityGroup(this, 
501                    mSplitPassesByLightingType,
502                    mSplitNoShadowPasses, 
503                                        mShadowCastersNotReceivers);
504                mPriorityGroups.insert(PriorityMap::value_type(priority, pPriorityGrp));
505            }
506            else
507            {
508                pPriorityGrp = i->second;
509            }
510
511            // Add
512            pPriorityGrp->addRenderable(pRend, pTech);
513
514        }
515
516        /** Clears this group of renderables.
517        @param destroy
518            If false, doesn't delete any priority groups, just empties them. Saves on
519            memory deallocations since the chances are rougly the same kinds of
520            renderables are going to be sent to the queue again next time. If
521                        true, completely destroys.
522        */
523        void clear(bool destroy = false)
524        {
525            PriorityMap::iterator i, iend;
526            iend = mPriorityGroups.end();
527            for (i = mPriorityGroups.begin(); i != iend; ++i)
528            {
529                                if (destroy)
530                                        delete i->second;
531                                else
532                                        i->second->clear();
533            }
534
535                        if (destroy)
536                                mPriorityGroups.clear();
537
538        }
539
540                /** Indicate whether a given queue group will be doing any
541                shadow setup.
542                @remarks
543                This method allows you to inform the queue about a queue group, and to
544                indicate whether this group will require shadow processing of any sort.
545                In order to preserve rendering order, OGRE has to treat queue groups
546                as very separate elements of the scene, and this can result in it
547                having to duplicate shadow setup for each group. Therefore, if you
548                know that a group which you are using will never need shadows, you
549                should preregister the group using this method in order to improve
550                the performance.
551                */
552                void setShadowsEnabled(bool enabled) { mShadowsEnabled = enabled; }
553
554                /** Are shadows enabled for this queue? */
555                bool getShadowsEnabled(void) const { return mShadowsEnabled; }
556
557        /** Sets whether or not the queue will split passes by their lighting type,
558        ie ambient, per-light and decal.
559        */
560        void setSplitPassesByLightingType(bool split)
561        {
562            mSplitPassesByLightingType = split;
563            PriorityMap::iterator i, iend;
564            iend = mPriorityGroups.end();
565            for (i = mPriorityGroups.begin(); i != iend; ++i)
566            {
567                i->second->setSplitPassesByLightingType(split);
568            }
569        }
570        /** Sets whether or not the queue will split passes which have shadow receive
571        turned off (in their parent material), which is needed when certain shadow
572        techniques are used.
573        */
574        void setSplitNoShadowPasses(bool split)
575        {
576            mSplitNoShadowPasses = split;
577            PriorityMap::iterator i, iend;
578            iend = mPriorityGroups.end();
579            for (i = mPriorityGroups.begin(); i != iend; ++i)
580            {
581                i->second->setSplitNoShadowPasses(split);
582            }
583        }
584                /** Sets whether or not objects which cast shadows should be treated as
585                never receiving shadows.
586                */
587                void setShadowCastersCannotBeReceivers(bool ind)
588                {
589                        mShadowCastersNotReceivers = ind;
590                        PriorityMap::iterator i, iend;
591                        iend = mPriorityGroups.end();
592                        for (i = mPriorityGroups.begin(); i != iend; ++i)
593                        {
594                                i->second->setShadowCastersCannotBeReceivers(ind);
595                        }
596                }
597                /** Reset the organisation modes required for the solids in this group.
598                @remarks
599                        You can only do this when the group is empty, ie after clearing the
600                        queue.
601                @see QueuedRenderableCollection::OrganisationMode
602                */
603                void resetOrganisationModes(void)
604                {
605                        PriorityMap::iterator i, iend;
606                        iend = mPriorityGroups.end();
607                        for (i = mPriorityGroups.begin(); i != iend; ++i)
608                        {
609                                i->second->resetOrganisationModes();
610                        }
611                }
612               
613                /** Add a required sorting / grouping mode for the solids in this group.
614                @remarks
615                        You can only do this when the group is empty, ie after clearing the
616                        queue.
617                @see QueuedRenderableCollection::OrganisationMode
618                */
619                void addOrganisationMode(QueuedRenderableCollection::OrganisationMode om)
620                {
621                        PriorityMap::iterator i, iend;
622                        iend = mPriorityGroups.end();
623                        for (i = mPriorityGroups.begin(); i != iend; ++i)
624                        {
625                                i->second->addOrganisationMode(om);
626                        }
627                }
628
629                /** Setthe  sorting / grouping mode for the solids in this group to the default.
630                @remarks
631                        You can only do this when the group is empty, ie after clearing the
632                        queue.
633                @see QueuedRenderableCollection::OrganisationMode
634                */
635                void defaultOrganisationMode(void)
636                {
637                        PriorityMap::iterator i, iend;
638                        iend = mPriorityGroups.end();
639                        for (i = mPriorityGroups.begin(); i != iend; ++i)
640                        {
641                                i->second->defaultOrganisationMode();
642                        }
643                }
644
645    };
646
647
648
649}
650
651#endif
652
653
Note: See TracBrowser for help on using the repository browser.