source: GTP/trunk/App/Demos/Geom/OgreStuff/include/OgreRenderQueueSortingGrouping.h @ 1812

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