source: OGRE/trunk/ogre_changes/Ogre1.2/OgreMain/include/OgreRenderQueueSortingGrouping.h @ 921

Revision 921, 23.9 KB checked in by mattausch, 18 years ago (diff)

added updates for visibility

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#ifdef GTP_VISIBILITY_MODIFIED_OGRE
248                void clear(bool destroy);
249#endif // GTP_VISIBILITY_MODIFIED_OGRE
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#ifdef GTP_VISIBILITY_MODIFIED_OGRE
412       
413                enum {SOLID_PASSES = 1,
414                          SOLID_PASSES_DECAL = 2,
415                          SOLID_PASSES_DIFFUSE_SPECULAR = 4,
416                          SOLID_PASSES_NOSHADOW = 8,
417                          TRANSPARENT_PASSES = 16};
418
419                /** Clears passes determined by parameter.
420                        @param passes can be one or several (combined by |) of:
421                        SOLID_PASSES
422                        SOLID_PASSES_DECAL
423                        SOLID_PASSES_DIFFUSE_SPECULAR
424                        SOLID_PASSES_NOSHADOW
425                        TRANSPARENT_PASSES
426                */
427                void clear(const int leavePassesInQueue, bool destroy);
428
429                /*** msz: no more destroy function, hope we don't need it***/
430
431#endif // GTP_VISIBILITY_MODIFIED_OGRE 
432
433        /** Sets whether or not the queue will split passes by their lighting type,
434        ie ambient, per-light and decal.
435        */
436        void setSplitPassesByLightingType(bool split)
437        {
438            mSplitPassesByLightingType = split;
439        }
440
441        /** Sets whether or not passes which have shadow receive disabled should
442            be separated.
443        */
444        void setSplitNoShadowPasses(bool split)
445        {
446            mSplitNoShadowPasses = split;
447        }
448
449                /** Sets whether or not objects which cast shadows should be treated as
450                        never receiving shadows.
451                */
452                void setShadowCastersCannotBeReceivers(bool ind)
453                {
454                        mShadowCastersNotReceivers = ind;
455                }
456
457
458
459    };
460
461
462    /** A grouping level underneath RenderQueue which groups renderables
463    to be issued at coarsely the same time to the renderer.
464    @remarks
465        Each instance of this class itself hold RenderPriorityGroup instances,
466        which are the groupings of renderables by priority for fine control
467        of ordering (not required for most instances).
468    */
469    class _OgreExport RenderQueueGroup
470    {
471    public:
472        typedef std::map<ushort, RenderPriorityGroup*, std::less<ushort> > PriorityMap;
473        typedef MapIterator<PriorityMap> PriorityMapIterator;
474    protected:
475        RenderQueue* mParent;
476        bool mSplitPassesByLightingType;
477        bool mSplitNoShadowPasses;
478                bool mShadowCastersNotReceivers;
479        /// Map of RenderPriorityGroup objects
480        PriorityMap mPriorityGroups;
481                /// Whether shadows are enabled for this queue
482                bool mShadowsEnabled;
483
484
485    public:
486                RenderQueueGroup(RenderQueue* parent,
487            bool splitPassesByLightingType,
488            bool splitNoShadowPasses,
489            bool shadowCastersNotReceivers)
490            : mParent(parent)
491            , mSplitPassesByLightingType(splitPassesByLightingType)
492            , mSplitNoShadowPasses(splitNoShadowPasses)
493            , mShadowCastersNotReceivers(shadowCastersNotReceivers)
494            , mShadowsEnabled(true)
495        {
496        }
497
498        ~RenderQueueGroup() {
499            // destroy contents now
500            PriorityMap::iterator i;
501            for (i = mPriorityGroups.begin(); i != mPriorityGroups.end(); ++i)
502            {
503                delete i->second;
504            }
505        }
506
507        /** Get an iterator for browsing through child contents. */
508        PriorityMapIterator getIterator(void)
509        {
510            return PriorityMapIterator(mPriorityGroups.begin(), mPriorityGroups.end());
511        }
512
513        /** Add a renderable to this group, with the given priority. */
514        void addRenderable(Renderable* pRend, Technique* pTech, ushort priority)
515        {
516            // Check if priority group is there
517            PriorityMap::iterator i = mPriorityGroups.find(priority);
518            RenderPriorityGroup* pPriorityGrp;
519            if (i == mPriorityGroups.end())
520            {
521                // Missing, create
522                pPriorityGrp = new RenderPriorityGroup(this,
523                    mSplitPassesByLightingType,
524                    mSplitNoShadowPasses,
525                                        mShadowCastersNotReceivers);
526                mPriorityGroups.insert(PriorityMap::value_type(priority, pPriorityGrp));
527            }
528            else
529            {
530                pPriorityGrp = i->second;
531            }
532
533            // Add
534            pPriorityGrp->addRenderable(pRend, pTech);
535
536        }
537
538        /** Clears this group of renderables.
539        @param destroy
540            If false, doesn't delete any priority groups, just empties them. Saves on
541            memory deallocations since the chances are rougly the same kinds of
542            renderables are going to be sent to the queue again next time. If
543                        true, completely destroys.
544        */
545        void clear(bool destroy = false)
546        {
547            PriorityMap::iterator i, iend;
548            iend = mPriorityGroups.end();
549            for (i = mPriorityGroups.begin(); i != iend; ++i)
550            {
551                                if (destroy)
552                                        delete i->second;
553                                else
554                                        i->second->clear();
555            }
556
557                        if (destroy)
558                                mPriorityGroups.clear();
559
560        }
561
562#ifdef GTP_VISIBILITY_MODIFIED_OGRE     
563                void clear(const int passes, bool destroy = false)
564        {
565            PriorityMap::iterator i, iend;
566            iend = mPriorityGroups.end();
567            for (i = mPriorityGroups.begin(); i != iend; ++i)
568            {
569                                i->second->clear(passes, destroy);
570            }
571
572                        /** msz: destroy all when no passes left **/
573                        if (!passes && destroy)
574                        {
575                                mPriorityGroups.clear();
576                        }
577        }
578
579#endif // GTP_VISIBILITY_MODIFIED_OGRE 
580
581                /** Indicate whether a given queue group will be doing any
582                shadow setup.
583                @remarks
584                This method allows you to inform the queue about a queue group, and to
585                indicate whether this group will require shadow processing of any sort.
586                In order to preserve rendering order, OGRE has to treat queue groups
587                as very separate elements of the scene, and this can result in it
588                having to duplicate shadow setup for each group. Therefore, if you
589                know that a group which you are using will never need shadows, you
590                should preregister the group using this method in order to improve
591                the performance.
592                */
593                void setShadowsEnabled(bool enabled) { mShadowsEnabled = enabled; }
594
595                /** Are shadows enabled for this queue? */
596                bool getShadowsEnabled(void) const { return mShadowsEnabled; }
597
598        /** Sets whether or not the queue will split passes by their lighting type,
599        ie ambient, per-light and decal.
600        */
601        void setSplitPassesByLightingType(bool split)
602        {
603            mSplitPassesByLightingType = split;
604            PriorityMap::iterator i, iend;
605            iend = mPriorityGroups.end();
606            for (i = mPriorityGroups.begin(); i != iend; ++i)
607            {
608                i->second->setSplitPassesByLightingType(split);
609            }
610        }
611        /** Sets whether or not the queue will split passes which have shadow receive
612        turned off (in their parent material), which is needed when certain shadow
613        techniques are used.
614        */
615        void setSplitNoShadowPasses(bool split)
616        {
617            mSplitNoShadowPasses = split;
618            PriorityMap::iterator i, iend;
619            iend = mPriorityGroups.end();
620            for (i = mPriorityGroups.begin(); i != iend; ++i)
621            {
622                i->second->setSplitNoShadowPasses(split);
623            }
624        }
625                /** Sets whether or not objects which cast shadows should be treated as
626                never receiving shadows.
627                */
628                void setShadowCastersCannotBeReceivers(bool ind)
629                {
630                        mShadowCastersNotReceivers = ind;
631                        PriorityMap::iterator i, iend;
632                        iend = mPriorityGroups.end();
633                        for (i = mPriorityGroups.begin(); i != iend; ++i)
634                        {
635                                i->second->setShadowCastersCannotBeReceivers(ind);
636                        }
637                }
638                /** Reset the organisation modes required for the solids in this group.
639                @remarks
640                        You can only do this when the group is empty, ie after clearing the
641                        queue.
642                @see QueuedRenderableCollection::OrganisationMode
643                */
644                void resetOrganisationModes(void)
645                {
646                        PriorityMap::iterator i, iend;
647                        iend = mPriorityGroups.end();
648                        for (i = mPriorityGroups.begin(); i != iend; ++i)
649                        {
650                                i->second->resetOrganisationModes();
651                        }
652                }
653               
654                /** Add a required sorting / grouping mode for the solids in this group.
655                @remarks
656                        You can only do this when the group is empty, ie after clearing the
657                        queue.
658                @see QueuedRenderableCollection::OrganisationMode
659                */
660                void addOrganisationMode(QueuedRenderableCollection::OrganisationMode om)
661                {
662                        PriorityMap::iterator i, iend;
663                        iend = mPriorityGroups.end();
664                        for (i = mPriorityGroups.begin(); i != iend; ++i)
665                        {
666                                i->second->addOrganisationMode(om);
667                        }
668                }
669
670                /** Setthe  sorting / grouping mode for the solids in this group to the default.
671                @remarks
672                        You can only do this when the group is empty, ie after clearing the
673                        queue.
674                @see QueuedRenderableCollection::OrganisationMode
675                */
676                void defaultOrganisationMode(void)
677                {
678                        PriorityMap::iterator i, iend;
679                        iend = mPriorityGroups.end();
680                        for (i = mPriorityGroups.begin(); i != iend; ++i)
681                        {
682                                i->second->defaultOrganisationMode();
683                        }
684                }
685
686    };
687
688
689
690}
691
692#endif
693
694
Note: See TracBrowser for help on using the repository browser.