/src/ogre/OgreMain/src/OgreRenderQueue.cpp
Line | Count | Source |
1 | | /* |
2 | | ----------------------------------------------------------------------------- |
3 | | This source file is part of OGRE |
4 | | (Object-oriented Graphics Rendering Engine) |
5 | | For the latest info, see http://www.ogre3d.org/ |
6 | | |
7 | | Copyright (c) 2000-2014 Torus Knot Software Ltd |
8 | | |
9 | | Permission is hereby granted, free of charge, to any person obtaining a copy |
10 | | of this software and associated documentation files (the "Software"), to deal |
11 | | in the Software without restriction, including without limitation the rights |
12 | | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
13 | | copies of the Software, and to permit persons to whom the Software is |
14 | | furnished to do so, subject to the following conditions: |
15 | | |
16 | | The above copyright notice and this permission notice shall be included in |
17 | | all copies or substantial portions of the Software. |
18 | | |
19 | | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
20 | | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
21 | | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
22 | | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
23 | | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
24 | | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
25 | | THE SOFTWARE. |
26 | | ----------------------------------------------------------------------------- |
27 | | */ |
28 | | #include "OgreStableHeaders.h" |
29 | | |
30 | | #include "OgreRenderQueue.h" |
31 | | |
32 | | #include <memory> |
33 | | #include "OgreMaterial.h" |
34 | | #include "OgreRenderQueueSortingGrouping.h" |
35 | | #include "OgreSceneManagerEnumerator.h" |
36 | | |
37 | | namespace Ogre { |
38 | | |
39 | | //--------------------------------------------------------------------- |
40 | | RenderQueue::RenderQueue() |
41 | 0 | : mSplitPassesByLightingType(false) |
42 | 0 | , mSplitNoShadowPasses(false) |
43 | 0 | , mShadowCastersCannotBeReceivers(false) |
44 | 0 | , mRenderableListener(0) |
45 | 0 | { |
46 | | // Create the 'main' queue up-front since we'll always need that |
47 | 0 | mGroups[RENDER_QUEUE_MAIN] = std::make_unique<RenderQueueGroup>( |
48 | 0 | mSplitPassesByLightingType, mSplitNoShadowPasses, mShadowCastersCannotBeReceivers); |
49 | | |
50 | | // set default queue |
51 | 0 | mDefaultQueueGroup = RENDER_QUEUE_MAIN; |
52 | 0 | mDefaultRenderablePriority = Renderable::DEFAULT_PRIORITY; |
53 | |
|
54 | 0 | } |
55 | | //--------------------------------------------------------------------- |
56 | | RenderQueue::~RenderQueue() |
57 | 0 | { |
58 | | |
59 | | // trigger the pending pass updates, otherwise we could leak |
60 | 0 | Pass::processPendingPassUpdates(); |
61 | 0 | } |
62 | | |
63 | | static bool onTransparentQueue(Technique* pTech) |
64 | 0 | { |
65 | | // Transparent and depth/colour settings mean depth sorting is required? |
66 | | // Note: colour write disabled with depth check/write enabled means |
67 | | // setup depth buffer for other passes use. |
68 | 0 | if (pTech->isTransparentSortingForced() || |
69 | 0 | (pTech->isTransparent() && |
70 | 0 | (!pTech->isDepthWriteEnabled() || !pTech->isDepthCheckEnabled() || pTech->hasColourWriteDisabled()))) |
71 | 0 | { |
72 | 0 | return true; |
73 | 0 | } |
74 | | |
75 | 0 | return false; |
76 | 0 | } |
77 | | |
78 | | //----------------------------------------------------------------------- |
79 | | void RenderQueue::addRenderable(Renderable* pRend, uint8 groupID, ushort priority) |
80 | 0 | { |
81 | 0 | Technique* pTech; |
82 | | |
83 | | // tell material it's been used |
84 | 0 | if (pRend->getMaterial()) |
85 | 0 | pRend->getMaterial()->touch(); |
86 | | |
87 | | // Check material & technique supplied (the former since the default implementation |
88 | | // of getTechnique is based on it for backwards compatibility |
89 | 0 | if(!pRend->getMaterial() || !pRend->getTechnique()) |
90 | 0 | { |
91 | | // Use default base white, with lighting only if vertices has normals |
92 | 0 | RenderOperation op; |
93 | 0 | pRend->getRenderOperation(op); |
94 | 0 | bool useLighting = (NULL != op.vertexData->vertexDeclaration->findElementBySemantic(VES_NORMAL)); |
95 | 0 | MaterialPtr defaultMat = MaterialManager::getSingleton().getDefaultMaterial(useLighting); |
96 | 0 | defaultMat->load(); |
97 | 0 | pTech = defaultMat->getBestTechnique(); |
98 | 0 | } |
99 | 0 | else |
100 | 0 | pTech = pRend->getTechnique(); |
101 | |
|
102 | 0 | if (mRenderableListener) |
103 | 0 | { |
104 | | // Allow listener to override technique and to abort |
105 | 0 | if (!mRenderableListener->renderableQueued(pRend, groupID, priority, |
106 | 0 | &pTech, this)) |
107 | 0 | return; // rejected |
108 | | |
109 | | // tell material it's been used (incase changed) |
110 | 0 | pTech->getParent()->touch(); |
111 | 0 | } |
112 | | |
113 | 0 | if(groupID == mDefaultQueueGroup && onTransparentQueue(pTech)) |
114 | 0 | groupID = RENDER_QUEUE_TRANSPARENTS; |
115 | | |
116 | | // Find group |
117 | 0 | RenderQueueGroup* pGroup = getQueueGroup(groupID); |
118 | 0 | pGroup->addRenderable(pRend, pTech, priority); |
119 | |
|
120 | 0 | } |
121 | | //----------------------------------------------------------------------- |
122 | | void RenderQueue::clear(bool destroyPassMaps) |
123 | 0 | { |
124 | | // Note: We clear dirty passes from all RenderQueues in all |
125 | | // SceneManagers, because the following recalculation of pass hashes |
126 | | // also considers all RenderQueues and could become inconsistent, otherwise. |
127 | 0 | for (auto p : SceneManagerEnumerator::getSingleton().getSceneManagers()) |
128 | 0 | { |
129 | 0 | RenderQueue* queue = p.second->getRenderQueue(); |
130 | |
|
131 | 0 | for (auto & g : queue->mGroups) |
132 | 0 | { |
133 | 0 | if(g) |
134 | 0 | g->clear(destroyPassMaps); |
135 | 0 | } |
136 | 0 | } |
137 | | |
138 | | // Now trigger the pending pass updates |
139 | 0 | Pass::processPendingPassUpdates(); |
140 | | |
141 | | // NB this leaves the items present (but empty) |
142 | | // We're assuming that frame-by-frame, the same groups are likely to |
143 | | // be used, so no point destroying the vectors and incurring the overhead |
144 | | // that would cause, let them be destroyed in the destructor. |
145 | 0 | } |
146 | | //----------------------------------------------------------------------- |
147 | | void RenderQueue::addRenderable(Renderable* pRend, uint8 groupID) |
148 | 0 | { |
149 | 0 | addRenderable(pRend, groupID, mDefaultRenderablePriority); |
150 | 0 | } |
151 | | //----------------------------------------------------------------------- |
152 | | void RenderQueue::addRenderable(Renderable* pRend) |
153 | 0 | { |
154 | 0 | addRenderable(pRend, mDefaultQueueGroup, mDefaultRenderablePriority); |
155 | 0 | } |
156 | | //----------------------------------------------------------------------- |
157 | | uint8 RenderQueue::getDefaultQueueGroup(void) const |
158 | 0 | { |
159 | 0 | return mDefaultQueueGroup; |
160 | 0 | } |
161 | | //----------------------------------------------------------------------- |
162 | | void RenderQueue::setDefaultQueueGroup(uint8 grp) |
163 | 0 | { |
164 | 0 | mDefaultQueueGroup = grp; |
165 | 0 | } |
166 | | //----------------------------------------------------------------------- |
167 | | ushort RenderQueue::getDefaultRenderablePriority(void) const |
168 | 0 | { |
169 | 0 | return mDefaultRenderablePriority; |
170 | 0 | } |
171 | | //----------------------------------------------------------------------- |
172 | | void RenderQueue::setDefaultRenderablePriority(ushort priority) |
173 | 0 | { |
174 | 0 | mDefaultRenderablePriority = priority; |
175 | 0 | } |
176 | | |
177 | | |
178 | | //----------------------------------------------------------------------- |
179 | | RenderQueueGroup* RenderQueue::getQueueGroup(uint8 groupID) |
180 | 0 | { |
181 | 0 | if (!mGroups[groupID]) |
182 | 0 | { |
183 | | // Insert new |
184 | 0 | mGroups[groupID] = std::make_unique<RenderQueueGroup>(mSplitPassesByLightingType, mSplitNoShadowPasses, |
185 | 0 | mShadowCastersCannotBeReceivers); |
186 | 0 | } |
187 | |
|
188 | 0 | return mGroups[groupID].get(); |
189 | |
|
190 | 0 | } |
191 | | //----------------------------------------------------------------------- |
192 | | void RenderQueue::setSplitPassesByLightingType(bool split) |
193 | 0 | { |
194 | 0 | mSplitPassesByLightingType = split; |
195 | |
|
196 | 0 | for (auto & g : mGroups) |
197 | 0 | { |
198 | 0 | if(g) |
199 | 0 | g->setSplitPassesByLightingType(split); |
200 | 0 | } |
201 | 0 | } |
202 | | //----------------------------------------------------------------------- |
203 | | bool RenderQueue::getSplitPassesByLightingType(void) const |
204 | 0 | { |
205 | 0 | return mSplitPassesByLightingType; |
206 | 0 | } |
207 | | //----------------------------------------------------------------------- |
208 | | void RenderQueue::setSplitNoShadowPasses(bool split) |
209 | 0 | { |
210 | 0 | mSplitNoShadowPasses = split; |
211 | |
|
212 | 0 | for (auto & g : mGroups) |
213 | 0 | { |
214 | 0 | if(g) |
215 | 0 | g->setSplitNoShadowPasses(split); |
216 | 0 | } |
217 | 0 | } |
218 | | //----------------------------------------------------------------------- |
219 | | bool RenderQueue::getSplitNoShadowPasses(void) const |
220 | 0 | { |
221 | 0 | return mSplitNoShadowPasses; |
222 | 0 | } |
223 | | //----------------------------------------------------------------------- |
224 | | void RenderQueue::setShadowCastersCannotBeReceivers(bool ind) |
225 | 0 | { |
226 | 0 | mShadowCastersCannotBeReceivers = ind; |
227 | |
|
228 | 0 | for (auto & g : mGroups) |
229 | 0 | { |
230 | 0 | if(g) |
231 | 0 | g->setShadowCastersCannotBeReceivers(ind); |
232 | 0 | } |
233 | 0 | } |
234 | | //----------------------------------------------------------------------- |
235 | | bool RenderQueue::getShadowCastersCannotBeReceivers(void) const |
236 | 0 | { |
237 | 0 | return mShadowCastersCannotBeReceivers; |
238 | 0 | } |
239 | | //----------------------------------------------------------------------- |
240 | | void RenderQueue::merge( const RenderQueue* rhs ) |
241 | 0 | { |
242 | 0 | for (size_t i = 0; i < RENDER_QUEUE_COUNT; ++i) |
243 | 0 | { |
244 | 0 | if(!rhs->mGroups[i]) |
245 | 0 | continue; |
246 | | |
247 | 0 | RenderQueueGroup* pDstGroup = getQueueGroup( i ); |
248 | 0 | pDstGroup->merge( rhs->mGroups[i].get() ); |
249 | 0 | } |
250 | 0 | } |
251 | | |
252 | | //--------------------------------------------------------------------- |
253 | | void RenderQueue::processVisibleObject(MovableObject* mo, |
254 | | Camera* cam, |
255 | | bool onlyShadowCasters, |
256 | | VisibleObjectsBoundsInfo* visibleBounds) |
257 | 0 | { |
258 | | // receiveShadows is a material property, so we can query it before LOD |
259 | 0 | bool receiveShadows = getQueueGroup(mo->getRenderQueueGroup())->getShadowsEnabled() && mo->getReceivesShadows(); |
260 | |
|
261 | 0 | if(onlyShadowCasters && !mo->getCastShadows() && !receiveShadows) |
262 | 0 | return; |
263 | | |
264 | 0 | mo->_notifyCurrentCamera(cam); |
265 | 0 | if (!mo->isVisible()) |
266 | 0 | return; |
267 | | |
268 | 0 | const auto& bbox = mo->getWorldBoundingBox(true); |
269 | 0 | const auto& bsphere = mo->getWorldBoundingSphere(true); |
270 | |
|
271 | 0 | if (!onlyShadowCasters || mo->getCastShadows()) |
272 | 0 | { |
273 | 0 | mo->_updateRenderQueue(this); |
274 | 0 | if (visibleBounds) |
275 | 0 | { |
276 | 0 | visibleBounds->merge(bbox, bsphere, cam, receiveShadows); |
277 | 0 | } |
278 | 0 | } |
279 | | // not shadow caster, receiver only? |
280 | 0 | else if (receiveShadows) |
281 | 0 | { |
282 | 0 | visibleBounds->mergeNonRenderedButInFrustum(bbox, bsphere, cam); |
283 | 0 | } |
284 | 0 | } |
285 | | |
286 | | } |
287 | | |