/src/ogre/OgreMain/src/OgrePass.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 <memory> |
29 | | |
30 | | #include "OgreStableHeaders.h" |
31 | | |
32 | | #include "OgreGpuProgramUsage.h" |
33 | | #include "OgreTextureUnitState.h" |
34 | | |
35 | | namespace Ogre { |
36 | | |
37 | | /** Default pass hash function. |
38 | | |
39 | | Tries to minimise the number of texture changes. |
40 | | */ |
41 | | struct MinTextureStateChangeHashFunc : public Pass::HashFunc |
42 | | { |
43 | | uint32 operator()(const Pass* p) const override |
44 | 0 | { |
45 | 0 | OGRE_LOCK_MUTEX(p->mTexUnitChangeMutex); |
46 | 0 | uint32 hash = 0; |
47 | 0 | ushort c = p->getNumTextureUnitStates(); |
48 | |
|
49 | 0 | for (ushort i = 0; i < c; ++i) |
50 | 0 | { |
51 | 0 | const TextureUnitState* tus = 0; |
52 | 0 | tus = p->getTextureUnitState(i); |
53 | 0 | hash = FastHash(tus->getTextureName().c_str(), tus->getTextureName().size(), hash); |
54 | 0 | } |
55 | |
|
56 | 0 | return hash; |
57 | 0 | } |
58 | | }; |
59 | | MinTextureStateChangeHashFunc sMinTextureStateChangeHashFunc; |
60 | | /** Alternate pass hash function. |
61 | | |
62 | | Tries to minimise the number of GPU program changes. |
63 | | */ |
64 | | struct MinGpuProgramChangeHashFunc : public Pass::HashFunc |
65 | | { |
66 | | uint32 operator()(const Pass* p) const override |
67 | 0 | { |
68 | 0 | OGRE_LOCK_MUTEX(p->mGpuProgramChangeMutex); |
69 | 0 | uint32 hash = 0; |
70 | |
|
71 | 0 | for(int i = 0; i < GPT_COUNT; i++) |
72 | 0 | { |
73 | 0 | const String& name = p->getGpuProgramName(GpuProgramType(i)); |
74 | 0 | if(!name.empty()) { |
75 | 0 | hash = FastHash(name.c_str(), name.size(), hash); |
76 | 0 | } |
77 | 0 | } |
78 | |
|
79 | 0 | return hash; |
80 | 0 | } |
81 | | }; |
82 | | MinGpuProgramChangeHashFunc sMinGpuProgramChangeHashFunc; |
83 | | //----------------------------------------------------------------------------- |
84 | | Pass::PassSet Pass::msDirtyHashList; |
85 | | Pass::PassSet Pass::msPassGraveyard; |
86 | | OGRE_STATIC_MUTEX_INSTANCE(Pass::msDirtyHashListMutex); |
87 | | OGRE_STATIC_MUTEX_INSTANCE(Pass::msPassGraveyardMutex); |
88 | | |
89 | | Pass::HashFunc* Pass::msHashFunc = &sMinGpuProgramChangeHashFunc; |
90 | | //----------------------------------------------------------------------------- |
91 | | Pass::HashFunc* Pass::getBuiltinHashFunction(BuiltinHashFunction builtin) |
92 | 0 | { |
93 | 0 | Pass::HashFunc* hashFunc = NULL; |
94 | |
|
95 | 0 | switch(builtin) |
96 | 0 | { |
97 | 0 | case MIN_TEXTURE_CHANGE: |
98 | 0 | hashFunc = &sMinTextureStateChangeHashFunc; |
99 | 0 | break; |
100 | 0 | case MIN_GPU_PROGRAM_CHANGE: |
101 | 0 | hashFunc = &sMinGpuProgramChangeHashFunc; |
102 | 0 | break; |
103 | 0 | } |
104 | | |
105 | 0 | return hashFunc; |
106 | 0 | } |
107 | | //----------------------------------------------------------------------------- |
108 | | void Pass::setHashFunction(BuiltinHashFunction builtin) |
109 | 0 | { |
110 | 0 | switch(builtin) |
111 | 0 | { |
112 | 0 | case MIN_TEXTURE_CHANGE: |
113 | 0 | msHashFunc = &sMinTextureStateChangeHashFunc; |
114 | 0 | break; |
115 | 0 | case MIN_GPU_PROGRAM_CHANGE: |
116 | 0 | msHashFunc = &sMinGpuProgramChangeHashFunc; |
117 | 0 | break; |
118 | 0 | } |
119 | 0 | } |
120 | | //----------------------------------------------------------------------------- |
121 | | Pass::Pass(Technique* parent, unsigned short index) |
122 | 0 | : mParent(parent) |
123 | 0 | , mHash(0) |
124 | 0 | , mAmbient(ColourValue::White) |
125 | 0 | , mDiffuse(ColourValue::White) |
126 | 0 | , mSpecular(ColourValue::Black) |
127 | 0 | , mEmissive(ColourValue::Black) |
128 | 0 | , mShininess(0) |
129 | 0 | , mTracking(TVC_NONE) |
130 | 0 | , mHashDirtyQueued(false) |
131 | 0 | , mDepthCheck(true) |
132 | 0 | , mDepthWrite(true) |
133 | 0 | , mAlphaToCoverageEnabled(false) |
134 | 0 | , mTransparentSorting(true) |
135 | 0 | , mTransparentSortingForced(false) |
136 | 0 | , mLightingEnabled(true) |
137 | 0 | , mIteratePerLight(false) |
138 | 0 | , mRunOnlyForOneLightType(false) |
139 | 0 | , mPolygonModeOverrideable(true) |
140 | 0 | , mFogOverride(false) |
141 | 0 | , mQueuedForDeletion(false) |
142 | 0 | , mLightScissoring(false) |
143 | 0 | , mLightClipPlanes(false) |
144 | 0 | , mPointSpritesEnabled(false) |
145 | 0 | , mPointAttenuationEnabled(false) |
146 | 0 | , mContentTypeLookupBuilt(false) |
147 | 0 | , mAlphaRejectVal(0) |
148 | 0 | , mDepthBiasConstant(0.0f) |
149 | 0 | , mDepthBiasSlopeScale(0.0f) |
150 | 0 | , mDepthBiasPerIteration(0.0f) |
151 | 0 | , mDepthFunc(CMPF_LESS_EQUAL) |
152 | 0 | , mAlphaRejectFunc(CMPF_ALWAYS_PASS) |
153 | 0 | , mCullMode(CULL_CLOCKWISE) |
154 | 0 | , mManualCullMode(MANUAL_CULL_BACK) |
155 | 0 | , mMaxSimultaneousLights(OGRE_MAX_SIMULTANEOUS_LIGHTS) |
156 | 0 | , mStartLight(0) |
157 | 0 | , mLightsPerIteration(1) |
158 | 0 | , mIndex(index) |
159 | 0 | , mLightMask(0xFFFFFFFF) |
160 | 0 | , mFogColour(ColourValue::White) |
161 | 0 | , mFogStart(0.0) |
162 | 0 | , mFogEnd(1.0) |
163 | 0 | , mFogDensity(0.001) |
164 | 0 | , mLineWidth(1.0f) |
165 | 0 | , mPassIterationCount(1) |
166 | 0 | , mPointMinSize(0.0f) |
167 | 0 | , mPointMaxSize(0.0f) |
168 | 0 | , mPointAttenution(1.0f, 1.0f, 0.0f, 0.0f) |
169 | 0 | , mShadeOptions(SO_GOURAUD) |
170 | 0 | , mPolygonMode(PM_SOLID) |
171 | 0 | , mIlluminationStage(IS_UNKNOWN) |
172 | 0 | , mOnlyLightType(Light::LT_POINT) |
173 | 0 | , mFogMode(FOG_NONE) |
174 | 0 | { |
175 | | // init the hash inline |
176 | 0 | _recalculateHash(); |
177 | 0 | } |
178 | | |
179 | | //----------------------------------------------------------------------------- |
180 | | Pass::Pass(Technique *parent, unsigned short index, const Pass& oth) |
181 | 0 | : mParent(parent), mQueuedForDeletion(false), mIndex(index), mPassIterationCount(1) |
182 | 0 | { |
183 | 0 | *this = oth; |
184 | 0 | mParent = parent; |
185 | 0 | mIndex = index; |
186 | 0 | mQueuedForDeletion = false; |
187 | | |
188 | | // init the hash inline |
189 | 0 | _recalculateHash(); |
190 | 0 | } |
191 | 0 | Pass::~Pass() = default; // ensure unique_ptr destructors are in cpp |
192 | | //----------------------------------------------------------------------------- |
193 | | Pass& Pass::operator=(const Pass& oth) |
194 | 0 | { |
195 | 0 | mName = oth.mName; |
196 | 0 | mHash = oth.mHash; |
197 | 0 | mAmbient = oth.mAmbient; |
198 | 0 | mDiffuse = oth.mDiffuse; |
199 | 0 | mSpecular = oth.mSpecular; |
200 | 0 | mEmissive = oth.mEmissive; |
201 | 0 | mShininess = oth.mShininess; |
202 | 0 | mTracking = oth.mTracking; |
203 | | |
204 | | // Copy fog parameters |
205 | 0 | mFogOverride = oth.mFogOverride; |
206 | 0 | mFogMode = oth.mFogMode; |
207 | 0 | mFogColour = oth.mFogColour; |
208 | 0 | mFogStart = oth.mFogStart; |
209 | 0 | mFogEnd = oth.mFogEnd; |
210 | 0 | mFogDensity = oth.mFogDensity; |
211 | | |
212 | | // Default blending (overwrite) |
213 | 0 | mBlendState = oth.mBlendState; |
214 | |
|
215 | 0 | mDepthCheck = oth.mDepthCheck; |
216 | 0 | mDepthWrite = oth.mDepthWrite; |
217 | 0 | mAlphaRejectFunc = oth.mAlphaRejectFunc; |
218 | 0 | mAlphaRejectVal = oth.mAlphaRejectVal; |
219 | 0 | mAlphaToCoverageEnabled = oth.mAlphaToCoverageEnabled; |
220 | 0 | mTransparentSorting = oth.mTransparentSorting; |
221 | 0 | mTransparentSortingForced = oth.mTransparentSortingForced; |
222 | 0 | mDepthFunc = oth.mDepthFunc; |
223 | 0 | mDepthBiasConstant = oth.mDepthBiasConstant; |
224 | 0 | mDepthBiasSlopeScale = oth.mDepthBiasSlopeScale; |
225 | 0 | mDepthBiasPerIteration = oth.mDepthBiasPerIteration; |
226 | 0 | mCullMode = oth.mCullMode; |
227 | 0 | mManualCullMode = oth.mManualCullMode; |
228 | 0 | mLightingEnabled = oth.mLightingEnabled; |
229 | 0 | mMaxSimultaneousLights = oth.mMaxSimultaneousLights; |
230 | 0 | mStartLight = oth.mStartLight; |
231 | 0 | mIteratePerLight = oth.mIteratePerLight; |
232 | 0 | mLightsPerIteration = oth.mLightsPerIteration; |
233 | 0 | mRunOnlyForOneLightType = oth.mRunOnlyForOneLightType; |
234 | 0 | mOnlyLightType = oth.mOnlyLightType; |
235 | 0 | mShadeOptions = oth.mShadeOptions; |
236 | 0 | mPolygonMode = oth.mPolygonMode; |
237 | 0 | mPolygonModeOverrideable = oth.mPolygonModeOverrideable; |
238 | 0 | mPassIterationCount = oth.mPassIterationCount; |
239 | 0 | mLineWidth = oth.mLineWidth; |
240 | 0 | mPointAttenution = oth.mPointAttenution; |
241 | 0 | mPointMinSize = oth.mPointMinSize; |
242 | 0 | mPointMaxSize = oth.mPointMaxSize; |
243 | 0 | mPointSpritesEnabled = oth.mPointSpritesEnabled; |
244 | 0 | mPointAttenuationEnabled = oth.mPointAttenuationEnabled; |
245 | 0 | mShadowContentTypeLookup = oth.mShadowContentTypeLookup; |
246 | 0 | mContentTypeLookupBuilt = oth.mContentTypeLookupBuilt; |
247 | 0 | mLightScissoring = oth.mLightScissoring; |
248 | 0 | mLightClipPlanes = oth.mLightClipPlanes; |
249 | 0 | mIlluminationStage = oth.mIlluminationStage; |
250 | 0 | mLightMask = oth.mLightMask; |
251 | |
|
252 | 0 | for(int i = 0; i < GPT_PIPELINE_COUNT; i++) |
253 | 0 | { |
254 | 0 | auto& programUsage = mProgramUsage[i]; |
255 | 0 | auto& othUsage = oth.mProgramUsage[i]; |
256 | 0 | programUsage = othUsage ? std::make_unique<GpuProgramUsage>(*othUsage, this) : nullptr; |
257 | 0 | } |
258 | | |
259 | | // Clear texture units but doesn't notify need recompilation in the case |
260 | | // we are cloning, The parent material will take care of this. |
261 | 0 | for (auto *t : mTextureUnitStates) |
262 | 0 | { |
263 | 0 | OGRE_DELETE t; |
264 | 0 | } |
265 | |
|
266 | 0 | mTextureUnitStates.clear(); |
267 | | |
268 | | // Copy texture units |
269 | 0 | for (auto *s : oth.mTextureUnitStates) |
270 | 0 | { |
271 | 0 | TextureUnitState* t = OGRE_NEW TextureUnitState(this, *s); |
272 | 0 | mTextureUnitStates.push_back(t); |
273 | 0 | } |
274 | |
|
275 | 0 | _dirtyHash(); |
276 | |
|
277 | 0 | return *this; |
278 | 0 | } |
279 | | //----------------------------------------------------------------------------- |
280 | | size_t Pass::calculateSize(void) const |
281 | 0 | { |
282 | 0 | size_t memSize = 0; |
283 | | |
284 | | // Tally up TU states |
285 | 0 | for (auto *t : mTextureUnitStates) |
286 | 0 | { |
287 | 0 | memSize += t->calculateSize(); |
288 | 0 | } |
289 | 0 | for(const auto& u : mProgramUsage) |
290 | 0 | memSize += u ? u->calculateSize() : 0; |
291 | |
|
292 | 0 | return memSize; |
293 | 0 | } |
294 | | //----------------------------------------------------------------------- |
295 | | void Pass::setPointAttenuation(bool enabled, float constant, float linear, float quadratic) |
296 | 0 | { |
297 | 0 | mPointAttenuationEnabled = enabled; |
298 | 0 | mPointAttenution[1] = enabled ? constant : 1.0f; |
299 | 0 | mPointAttenution[2] = enabled ? linear : 0.0f; |
300 | 0 | mPointAttenution[3] = enabled ? quadratic : 0.0f; |
301 | 0 | } |
302 | | //----------------------------------------------------------------------- |
303 | | void Pass::setPointMinSize(Real min) |
304 | 0 | { |
305 | 0 | mPointMinSize = min; |
306 | 0 | } |
307 | | //----------------------------------------------------------------------- |
308 | | Real Pass::getPointMinSize(void) const |
309 | 0 | { |
310 | 0 | return mPointMinSize; |
311 | 0 | } |
312 | | //----------------------------------------------------------------------- |
313 | | void Pass::setPointMaxSize(Real max) |
314 | 0 | { |
315 | 0 | mPointMaxSize = max; |
316 | 0 | } |
317 | | //----------------------------------------------------------------------- |
318 | | Real Pass::getPointMaxSize(void) const |
319 | 0 | { |
320 | 0 | return mPointMaxSize; |
321 | 0 | } |
322 | | //----------------------------------------------------------------------- |
323 | | void Pass::setAmbient(float red, float green, float blue) |
324 | 0 | { |
325 | 0 | mAmbient.r = red; |
326 | 0 | mAmbient.g = green; |
327 | 0 | mAmbient.b = blue; |
328 | |
|
329 | 0 | } |
330 | | //----------------------------------------------------------------------- |
331 | | void Pass::setDiffuse(float red, float green, float blue, float alpha) |
332 | 0 | { |
333 | 0 | mDiffuse.r = red; |
334 | 0 | mDiffuse.g = green; |
335 | 0 | mDiffuse.b = blue; |
336 | 0 | mDiffuse.a = alpha; |
337 | 0 | } |
338 | | //----------------------------------------------------------------------- |
339 | | void Pass::setSpecular(float red, float green, float blue, float alpha) |
340 | 0 | { |
341 | 0 | mSpecular.r = red; |
342 | 0 | mSpecular.g = green; |
343 | 0 | mSpecular.b = blue; |
344 | 0 | mSpecular.a = alpha; |
345 | 0 | } |
346 | | //----------------------------------------------------------------------- |
347 | | void Pass::setSelfIllumination(float red, float green, float blue) |
348 | 0 | { |
349 | 0 | mEmissive.r = red; |
350 | 0 | mEmissive.g = green; |
351 | 0 | mEmissive.b = blue; |
352 | 0 | } |
353 | | //----------------------------------------------------------------------- |
354 | | TextureUnitState* Pass::createTextureUnitState(void) |
355 | 0 | { |
356 | 0 | TextureUnitState *t = OGRE_NEW TextureUnitState(this); |
357 | 0 | addTextureUnitState(t); |
358 | 0 | mContentTypeLookupBuilt = false; |
359 | 0 | return t; |
360 | 0 | } |
361 | | //----------------------------------------------------------------------- |
362 | | TextureUnitState* Pass::createTextureUnitState( |
363 | | const String& textureName, unsigned short texCoordSet) |
364 | 0 | { |
365 | 0 | TextureUnitState *t = OGRE_NEW TextureUnitState(this); |
366 | 0 | t->setTextureName(textureName); |
367 | 0 | t->setTextureCoordSet(texCoordSet); |
368 | 0 | addTextureUnitState(t); |
369 | 0 | mContentTypeLookupBuilt = false; |
370 | 0 | return t; |
371 | 0 | } |
372 | | //----------------------------------------------------------------------- |
373 | | void Pass::addTextureUnitState(TextureUnitState* state) |
374 | 0 | { |
375 | 0 | OGRE_LOCK_MUTEX(mTexUnitChangeMutex); |
376 | |
|
377 | 0 | OgreAssert(state , "TextureUnitState is NULL"); |
378 | | |
379 | | // only attach TUS to pass if TUS does not belong to another pass |
380 | 0 | OgreAssert(!state->getParent() || (state->getParent() == this), "TextureUnitState already attached to another pass"); |
381 | | |
382 | 0 | mTextureUnitStates.push_back(state); |
383 | | // Notify state |
384 | 0 | state->_notifyParent(this); |
385 | | // if texture unit state name is empty then give it a default name based on its index |
386 | 0 | if (state->getName().empty()) |
387 | 0 | { |
388 | | // its the last entry in the container so its index is size - 1 |
389 | 0 | size_t idx = mTextureUnitStates.size() - 1; |
390 | | |
391 | | // allow 8 digit hex number. there should never be that many texture units. |
392 | | // This sprintf replaced a call to StringConverter::toString for performance reasons |
393 | 0 | state->setName( StringUtil::format("%lx", static_cast<long>(idx))); |
394 | 0 | } |
395 | 0 | _notifyNeedsRecompile(); |
396 | 0 | _dirtyHash(); |
397 | |
|
398 | 0 | mContentTypeLookupBuilt = false; |
399 | 0 | } |
400 | | //----------------------------------------------------------------------------- |
401 | | TextureUnitState* Pass::getTextureUnitState(const String& name) const |
402 | 0 | { |
403 | 0 | OGRE_LOCK_MUTEX(mTexUnitChangeMutex); |
404 | 0 | TextureUnitState* foundTUS = 0; |
405 | | |
406 | | // iterate through TUS Container to find a match |
407 | 0 | for (auto *t : mTextureUnitStates) |
408 | 0 | { |
409 | 0 | if (t->getName() == name) |
410 | 0 | { |
411 | 0 | foundTUS = t; |
412 | 0 | break; |
413 | 0 | } |
414 | 0 | } |
415 | |
|
416 | 0 | return foundTUS; |
417 | 0 | } |
418 | | |
419 | | //----------------------------------------------------------------------- |
420 | | unsigned short Pass::getTextureUnitStateIndex(const TextureUnitState* state) const |
421 | 0 | { |
422 | 0 | OGRE_LOCK_MUTEX(mTexUnitChangeMutex); |
423 | 0 | assert(state && "state is 0 in Pass::getTextureUnitStateIndex()"); |
424 | | |
425 | | // only find index for state attached to this pass |
426 | 0 | OgreAssert(state->getParent() == this, "TextureUnitState is not attached to this pass"); |
427 | 0 | auto i = std::find(mTextureUnitStates.begin(), mTextureUnitStates.end(), state); |
428 | 0 | assert(i != mTextureUnitStates.end() && "state is supposed to attached to this pass"); |
429 | 0 | return static_cast<unsigned short>(std::distance(mTextureUnitStates.begin(), i)); |
430 | 0 | } |
431 | | |
432 | | //----------------------------------------------------------------------- |
433 | | Pass::TextureUnitStateIterator |
434 | | Pass::getTextureUnitStateIterator(void) |
435 | 0 | { |
436 | 0 | return TextureUnitStateIterator(mTextureUnitStates.begin(), mTextureUnitStates.end()); |
437 | 0 | } |
438 | | //----------------------------------------------------------------------- |
439 | | Pass::ConstTextureUnitStateIterator |
440 | | Pass::getTextureUnitStateIterator(void) const |
441 | 0 | { |
442 | 0 | return ConstTextureUnitStateIterator(mTextureUnitStates.begin(), mTextureUnitStates.end()); |
443 | 0 | } |
444 | | //----------------------------------------------------------------------- |
445 | | void Pass::removeTextureUnitState(unsigned short index) |
446 | 0 | { |
447 | 0 | OGRE_LOCK_MUTEX(mTexUnitChangeMutex); |
448 | 0 | assert (index < mTextureUnitStates.size() && "Index out of bounds"); |
449 | |
|
450 | 0 | TextureUnitStates::iterator i = mTextureUnitStates.begin() + index; |
451 | 0 | OGRE_DELETE *i; |
452 | 0 | mTextureUnitStates.erase(i); |
453 | 0 | _notifyNeedsRecompile(); |
454 | 0 | _dirtyHash(); |
455 | 0 | mContentTypeLookupBuilt = false; |
456 | 0 | } |
457 | | //----------------------------------------------------------------------- |
458 | | void Pass::removeAllTextureUnitStates(void) |
459 | 0 | { |
460 | 0 | OGRE_LOCK_MUTEX(mTexUnitChangeMutex); |
461 | 0 | TextureUnitStates::iterator i, iend; |
462 | 0 | iend = mTextureUnitStates.end(); |
463 | 0 | for (i = mTextureUnitStates.begin(); i != iend; ++i) |
464 | 0 | { |
465 | 0 | OGRE_DELETE *i; |
466 | 0 | } |
467 | 0 | mTextureUnitStates.clear(); |
468 | 0 | _notifyNeedsRecompile(); |
469 | 0 | _dirtyHash(); |
470 | 0 | mContentTypeLookupBuilt = false; |
471 | 0 | } |
472 | | //----------------------------------------------------------------------- |
473 | | static void _getBlendFlags(SceneBlendType type, SceneBlendFactor& source, SceneBlendFactor& dest) |
474 | 0 | { |
475 | 0 | switch ( type ) |
476 | 0 | { |
477 | 0 | case SBT_TRANSPARENT_ALPHA: |
478 | 0 | source = SBF_SOURCE_ALPHA; |
479 | 0 | dest = SBF_ONE_MINUS_SOURCE_ALPHA; |
480 | 0 | return; |
481 | 0 | case SBT_TRANSPARENT_COLOUR: |
482 | 0 | source = SBF_SOURCE_COLOUR; |
483 | 0 | dest = SBF_ONE_MINUS_SOURCE_COLOUR; |
484 | 0 | return; |
485 | 0 | case SBT_MODULATE: |
486 | 0 | source = SBF_DEST_COLOUR; |
487 | 0 | dest = SBF_ZERO; |
488 | 0 | return; |
489 | 0 | case SBT_ADD: |
490 | 0 | source = SBF_ONE; |
491 | 0 | dest = SBF_ONE; |
492 | 0 | return; |
493 | 0 | default: |
494 | 0 | case SBT_REPLACE: |
495 | 0 | source = SBF_ONE; |
496 | 0 | dest = SBF_ZERO; |
497 | 0 | return; |
498 | 0 | } |
499 | 0 | } |
500 | | //----------------------------------------------------------------------- |
501 | | void Pass::setSceneBlending(SceneBlendType sbt) |
502 | 0 | { |
503 | | // Convert type into blend factors |
504 | |
|
505 | 0 | SceneBlendFactor source; |
506 | 0 | SceneBlendFactor dest; |
507 | 0 | _getBlendFlags(sbt, source, dest); |
508 | | |
509 | | // Set blend factors |
510 | |
|
511 | 0 | setSceneBlending(source, dest); |
512 | 0 | } |
513 | | //----------------------------------------------------------------------- |
514 | | void Pass::setSeparateSceneBlending( const SceneBlendType sbt, const SceneBlendType sbta ) |
515 | 0 | { |
516 | | // Convert types into blend factors |
517 | |
|
518 | 0 | SceneBlendFactor source; |
519 | 0 | SceneBlendFactor dest; |
520 | 0 | _getBlendFlags(sbt, source, dest); |
521 | |
|
522 | 0 | SceneBlendFactor sourceAlpha; |
523 | 0 | SceneBlendFactor destAlpha; |
524 | 0 | _getBlendFlags(sbta, sourceAlpha, destAlpha); |
525 | | |
526 | | // Set blend factors |
527 | |
|
528 | 0 | setSeparateSceneBlending(source, dest, sourceAlpha, destAlpha); |
529 | 0 | } |
530 | | |
531 | | //----------------------------------------------------------------------- |
532 | | void Pass::setSceneBlending(SceneBlendFactor sourceFactor, SceneBlendFactor destFactor) |
533 | 0 | { |
534 | 0 | mBlendState.sourceFactor = sourceFactor; |
535 | 0 | mBlendState.sourceFactorAlpha = sourceFactor; |
536 | 0 | mBlendState.destFactor = destFactor; |
537 | 0 | mBlendState.destFactorAlpha = destFactor; |
538 | 0 | } |
539 | | //----------------------------------------------------------------------- |
540 | | void Pass::setSeparateSceneBlending( const SceneBlendFactor sourceFactor, const SceneBlendFactor destFactor, const SceneBlendFactor sourceFactorAlpha, const SceneBlendFactor destFactorAlpha ) |
541 | 0 | { |
542 | 0 | mBlendState.sourceFactor = sourceFactor; |
543 | 0 | mBlendState.destFactor = destFactor; |
544 | 0 | mBlendState.sourceFactorAlpha = sourceFactorAlpha; |
545 | 0 | mBlendState.destFactorAlpha = destFactorAlpha; |
546 | 0 | } |
547 | | //----------------------------------------------------------------------- |
548 | | void Pass::setSceneBlendingOperation(SceneBlendOperation op) |
549 | 0 | { |
550 | 0 | mBlendState.operation = op; |
551 | 0 | mBlendState.alphaOperation = op; |
552 | 0 | } |
553 | | //----------------------------------------------------------------------- |
554 | | void Pass::setSeparateSceneBlendingOperation(SceneBlendOperation op, SceneBlendOperation alphaOp) |
555 | 0 | { |
556 | 0 | mBlendState.operation = op; |
557 | 0 | mBlendState.alphaOperation = alphaOp; |
558 | 0 | } |
559 | | //----------------------------------------------------------------------- |
560 | | bool Pass::isTransparent(void) const |
561 | 0 | { |
562 | | // Transparent if any of the destination colour is taken into account |
563 | 0 | if (mBlendState.destFactor == SBF_ZERO && |
564 | 0 | mBlendState.sourceFactor != SBF_DEST_COLOUR && |
565 | 0 | mBlendState.sourceFactor != SBF_ONE_MINUS_DEST_COLOUR && |
566 | 0 | mBlendState.sourceFactor != SBF_DEST_ALPHA && |
567 | 0 | mBlendState.sourceFactor != SBF_ONE_MINUS_DEST_ALPHA) |
568 | 0 | { |
569 | 0 | return false; |
570 | 0 | } |
571 | 0 | else |
572 | 0 | { |
573 | 0 | return true; |
574 | 0 | } |
575 | 0 | } |
576 | | //----------------------------------------------------------------------- |
577 | | void Pass::setAlphaRejectSettings(CompareFunction func, unsigned char value, bool alphaToCoverage) |
578 | 0 | { |
579 | 0 | mAlphaRejectFunc = func; |
580 | 0 | mAlphaRejectVal = value; |
581 | 0 | mAlphaToCoverageEnabled = alphaToCoverage; |
582 | 0 | } |
583 | | //----------------------------------------------------------------------- |
584 | | void Pass::setColourWriteEnabled(bool enabled) |
585 | 0 | { |
586 | 0 | mBlendState.writeR = enabled; |
587 | 0 | mBlendState.writeG = enabled; |
588 | 0 | mBlendState.writeB = enabled; |
589 | 0 | mBlendState.writeA = enabled; |
590 | 0 | } |
591 | | //----------------------------------------------------------------------- |
592 | | bool Pass::getColourWriteEnabled() const |
593 | 0 | { |
594 | 0 | return mBlendState.writeR || mBlendState.writeG || mBlendState.writeB || |
595 | 0 | mBlendState.writeA; |
596 | 0 | } |
597 | | //----------------------------------------------------------------------- |
598 | | |
599 | | void Pass::setColourWriteEnabled(bool red, bool green, bool blue, bool alpha) |
600 | 0 | { |
601 | 0 | mBlendState.writeR = red; |
602 | 0 | mBlendState.writeG = green; |
603 | 0 | mBlendState.writeB = blue; |
604 | 0 | mBlendState.writeA = alpha; |
605 | 0 | } |
606 | | //----------------------------------------------------------------------- |
607 | | void Pass::getColourWriteEnabled(bool& red, bool& green, bool& blue, bool& alpha) const |
608 | 0 | { |
609 | 0 | red = mBlendState.writeR; |
610 | 0 | green = mBlendState.writeG; |
611 | 0 | blue = mBlendState.writeB; |
612 | 0 | alpha = mBlendState.writeA; |
613 | 0 | } |
614 | | //----------------------------------------------------------------------- |
615 | | void Pass::setIteratePerLight(bool enabled, |
616 | | bool onlyForOneLightType, Light::LightTypes lightType) |
617 | 0 | { |
618 | 0 | mIteratePerLight = enabled; |
619 | 0 | mRunOnlyForOneLightType = onlyForOneLightType; |
620 | 0 | mOnlyLightType = lightType; |
621 | 0 | } |
622 | | //----------------------------------------------------------------------- |
623 | | void Pass::setManualCullingMode(ManualCullingMode mode) |
624 | 0 | { |
625 | 0 | mManualCullMode = mode; |
626 | 0 | } |
627 | | //----------------------------------------------------------------------- |
628 | | ManualCullingMode Pass::getManualCullingMode(void) const |
629 | 0 | { |
630 | 0 | return mManualCullMode; |
631 | 0 | } |
632 | | //----------------------------------------------------------------------- |
633 | | void Pass::setFog(bool overrideScene, FogMode mode, const ColourValue& colour, float density, float start, float end) |
634 | 0 | { |
635 | 0 | mFogOverride = overrideScene; |
636 | 0 | if (overrideScene) |
637 | 0 | { |
638 | 0 | mFogMode = mode; |
639 | 0 | mFogColour = colour; |
640 | 0 | mFogStart = start; |
641 | 0 | mFogEnd = end; |
642 | 0 | mFogDensity = density; |
643 | 0 | } |
644 | 0 | } |
645 | | //----------------------------------------------------------------------- |
646 | | void Pass::setDepthBias(float constantBias, float slopeScaleBias) |
647 | 0 | { |
648 | 0 | mDepthBiasConstant = constantBias; |
649 | 0 | mDepthBiasSlopeScale = slopeScaleBias; |
650 | 0 | } |
651 | | //----------------------------------------------------------------------- |
652 | | Pass* Pass::_split(unsigned short numUnits) |
653 | 0 | { |
654 | 0 | OgreAssert( |
655 | 0 | !isProgrammable(), |
656 | 0 | "Programmable passes cannot be automatically split, define a fallback technique instead"); |
657 | | |
658 | 0 | if (mTextureUnitStates.size() > numUnits) |
659 | 0 | { |
660 | 0 | size_t start = mTextureUnitStates.size() - numUnits; |
661 | |
|
662 | 0 | Pass* newPass = mParent->createPass(); |
663 | |
|
664 | 0 | TextureUnitStates::iterator istart, i, iend; |
665 | 0 | iend = mTextureUnitStates.end(); |
666 | 0 | i = istart = mTextureUnitStates.begin() + start; |
667 | | // Set the new pass to fallback using scene blend |
668 | 0 | newPass->setSceneBlending( |
669 | 0 | (*i)->getColourBlendFallbackSrc(), (*i)->getColourBlendFallbackDest()); |
670 | | // Fixup the texture unit 0 of new pass blending method to replace |
671 | | // all colour and alpha with texture without adjustment, because we |
672 | | // assume it's detail texture. |
673 | 0 | (*i)->setColourOperationEx(LBX_SOURCE1, LBS_TEXTURE, LBS_CURRENT); |
674 | 0 | (*i)->setAlphaOperation(LBX_SOURCE1, LBS_TEXTURE, LBS_CURRENT); |
675 | | |
676 | | // Add all the other texture unit states |
677 | 0 | for (; i != iend; ++i) |
678 | 0 | { |
679 | | // detach from parent first |
680 | 0 | (*i)->_notifyParent(0); |
681 | 0 | newPass->addTextureUnitState(*i); |
682 | 0 | } |
683 | | // Now remove texture units from this Pass, we don't need to delete since they've |
684 | | // been transferred |
685 | 0 | mTextureUnitStates.erase(istart, iend); |
686 | 0 | _dirtyHash(); |
687 | 0 | mContentTypeLookupBuilt = false; |
688 | 0 | return newPass; |
689 | 0 | } |
690 | 0 | return NULL; |
691 | 0 | } |
692 | | //----------------------------------------------------------------------------- |
693 | | void Pass::_notifyIndex(unsigned short index) |
694 | 0 | { |
695 | 0 | if (mIndex != index) |
696 | 0 | { |
697 | 0 | mIndex = index; |
698 | 0 | _dirtyHash(); |
699 | 0 | } |
700 | 0 | } |
701 | | //----------------------------------------------------------------------- |
702 | | void Pass::_prepare(void) |
703 | 0 | { |
704 | | // We assume the Technique only calls this when the material is being |
705 | | // prepared |
706 | | // prepare each TextureUnitState |
707 | 0 | for (auto *t : mTextureUnitStates) |
708 | 0 | { |
709 | 0 | t->_prepare(); |
710 | 0 | } |
711 | |
|
712 | 0 | } |
713 | | //----------------------------------------------------------------------- |
714 | | void Pass::_unprepare(void) |
715 | 0 | { |
716 | | // unprepare each TextureUnitState |
717 | 0 | for (auto *t : mTextureUnitStates) |
718 | 0 | { |
719 | 0 | t->_unprepare(); |
720 | 0 | } |
721 | |
|
722 | 0 | } |
723 | | //----------------------------------------------------------------------- |
724 | | void Pass::_load(void) |
725 | 0 | { |
726 | | // We assume the Technique only calls this when the material is being |
727 | | // loaded |
728 | | // Load each TextureUnitState |
729 | 0 | for (auto *t : mTextureUnitStates) |
730 | 0 | { |
731 | 0 | t->_load(); |
732 | 0 | } |
733 | | |
734 | | // Load programs |
735 | 0 | for (const auto& u : mProgramUsage) |
736 | 0 | if(u) u->_load(); |
737 | |
|
738 | 0 | if (mHashDirtyQueued) |
739 | 0 | { |
740 | 0 | _dirtyHash(); |
741 | 0 | } |
742 | |
|
743 | 0 | } |
744 | | //----------------------------------------------------------------------- |
745 | | void Pass::_unload(void) |
746 | 0 | { |
747 | | // Unload each TextureUnitState |
748 | 0 | for (auto *t : mTextureUnitStates) |
749 | 0 | { |
750 | 0 | t->_unload(); |
751 | 0 | } |
752 | | |
753 | | // TODO Unload programs |
754 | 0 | } |
755 | | //----------------------------------------------------------------------- |
756 | | void Pass::setGpuProgramParameters(GpuProgramType type, const GpuProgramParametersSharedPtr& params) |
757 | 0 | { |
758 | 0 | OGRE_LOCK_MUTEX(mGpuProgramChangeMutex); |
759 | |
|
760 | 0 | const auto& programUsage = getProgramUsage(type); |
761 | 0 | if (!programUsage) |
762 | 0 | { |
763 | 0 | OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, |
764 | 0 | "This pass does not have this program type assigned!"); |
765 | 0 | } |
766 | 0 | programUsage->setParameters(params); |
767 | 0 | } |
768 | | //----------------------------------------------------------------------- |
769 | | void Pass::setGpuProgram(GpuProgramType type, const GpuProgramPtr& program, bool resetParams) |
770 | 0 | { |
771 | 0 | OGRE_LOCK_MUTEX(mGpuProgramChangeMutex); |
772 | |
|
773 | 0 | std::unique_ptr<GpuProgramUsage>& programUsage = getProgramUsage(type); |
774 | | |
775 | | // Turn off fragment program if name blank |
776 | 0 | if (!program) |
777 | 0 | { |
778 | 0 | programUsage.reset(); |
779 | 0 | } |
780 | 0 | else |
781 | 0 | { |
782 | 0 | if (!programUsage) |
783 | 0 | { |
784 | 0 | programUsage = std::make_unique<GpuProgramUsage>(type, this); |
785 | 0 | } |
786 | 0 | programUsage->setProgram(program, resetParams); |
787 | 0 | } |
788 | | // Needs recompilation |
789 | 0 | _notifyNeedsRecompile(); |
790 | |
|
791 | 0 | if( Pass::getHashFunction() == Pass::getBuiltinHashFunction( Pass::MIN_GPU_PROGRAM_CHANGE ) ) |
792 | 0 | { |
793 | 0 | _dirtyHash(); |
794 | 0 | } |
795 | 0 | } |
796 | | |
797 | | void Pass::setGpuProgram(GpuProgramType type, const String& name, bool resetParams) |
798 | 0 | { |
799 | 0 | if (getGpuProgramName(type) == name) |
800 | 0 | return; |
801 | | |
802 | 0 | GpuProgramPtr program; |
803 | 0 | if (!name.empty()) |
804 | 0 | program = GpuProgramUsage::_getProgramByName(name, getResourceGroup(), type); |
805 | |
|
806 | 0 | setGpuProgram(type, program, resetParams); |
807 | 0 | } |
808 | | //----------------------------------------------------------------------- |
809 | | const GpuProgramParametersSharedPtr& Pass::getGpuProgramParameters(GpuProgramType type) const |
810 | 0 | { |
811 | 0 | OGRE_LOCK_MUTEX(mGpuProgramChangeMutex); |
812 | 0 | const auto& programUsage = getProgramUsage(type); |
813 | 0 | if (!programUsage) |
814 | 0 | { |
815 | 0 | OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "This pass has no " + to_string(type) + " program"); |
816 | 0 | } |
817 | 0 | return programUsage->getParameters(); |
818 | 0 | } |
819 | | |
820 | 0 | std::unique_ptr<GpuProgramUsage>& Pass::getProgramUsage(GpuProgramType programType) { |
821 | 0 | return mProgramUsage[programType % GPT_PIPELINE_COUNT]; |
822 | 0 | } |
823 | | |
824 | | const std::unique_ptr<GpuProgramUsage>& Pass::getProgramUsage(GpuProgramType programType) const |
825 | 0 | { |
826 | 0 | static std::unique_ptr<GpuProgramUsage> nullUsage; |
827 | 0 | auto& ret = mProgramUsage[programType % GPT_PIPELINE_COUNT]; |
828 | 0 | return ret && ret->getType() == programType ? ret : nullUsage; |
829 | 0 | } |
830 | | |
831 | 0 | bool Pass::hasGpuProgram(GpuProgramType programType) const { |
832 | 0 | return getProgramUsage(programType) != NULL; |
833 | 0 | } |
834 | | const GpuProgramPtr& Pass::getGpuProgram(GpuProgramType programType) const |
835 | 0 | { |
836 | 0 | OGRE_LOCK_MUTEX(mGpuProgramChangeMutex); |
837 | 0 | const auto& programUsage = getProgramUsage(programType); |
838 | 0 | OgreAssert(programUsage, "check whether program is available using hasGpuProgram()"); |
839 | 0 | return programUsage->getProgram(); |
840 | 0 | } |
841 | | //----------------------------------------------------------------------- |
842 | | const String& Pass::getGpuProgramName(GpuProgramType type) const |
843 | 0 | { |
844 | 0 | OGRE_LOCK_MUTEX(mGpuProgramChangeMutex); |
845 | |
|
846 | 0 | const std::unique_ptr<GpuProgramUsage>& programUsage = getProgramUsage(type); |
847 | 0 | if (!programUsage) |
848 | 0 | return BLANKSTRING; |
849 | 0 | else |
850 | 0 | return programUsage->getProgramName(); |
851 | 0 | } |
852 | | //----------------------------------------------------------------------- |
853 | | bool Pass::isLoaded(void) const |
854 | 0 | { |
855 | 0 | return mParent->isLoaded(); |
856 | 0 | } |
857 | | //----------------------------------------------------------------------- |
858 | | void Pass::_recalculateHash(void) |
859 | 0 | { |
860 | | /* Hash format is 32-bit, divided as follows (high to low bits) |
861 | | bits purpose |
862 | | 4 Pass index (i.e. max 16 passes!) |
863 | | 28 Pass contents |
864 | | */ |
865 | 0 | mHash = (*msHashFunc)(this); |
866 | | |
867 | | // overwrite the 4 upper bits with pass index |
868 | 0 | mHash = (uint32(mIndex) << 28) | (mHash >> 4); |
869 | 0 | } |
870 | | //----------------------------------------------------------------------- |
871 | | void Pass::_dirtyHash(void) |
872 | 0 | { |
873 | 0 | if (mQueuedForDeletion) |
874 | 0 | return; |
875 | | |
876 | 0 | Material* mat = mParent->getParent(); |
877 | 0 | if (mat->isLoading() || mat->isLoaded()) |
878 | 0 | { |
879 | 0 | OGRE_LOCK_MUTEX(msDirtyHashListMutex); |
880 | | // Mark this hash as for follow up |
881 | 0 | msDirtyHashList.insert(this); |
882 | 0 | mHashDirtyQueued = false; |
883 | 0 | } |
884 | 0 | else |
885 | 0 | { |
886 | 0 | mHashDirtyQueued = true; |
887 | 0 | } |
888 | 0 | } |
889 | | //--------------------------------------------------------------------- |
890 | | void Pass::clearDirtyHashList(void) |
891 | 0 | { |
892 | 0 | OGRE_LOCK_MUTEX(msDirtyHashListMutex); |
893 | 0 | msDirtyHashList.clear(); |
894 | 0 | } |
895 | | //----------------------------------------------------------------------- |
896 | | void Pass::_notifyNeedsRecompile(void) |
897 | 0 | { |
898 | 0 | if (!mQueuedForDeletion) |
899 | 0 | mParent->_notifyNeedsRecompile(); |
900 | 0 | } |
901 | | //----------------------------------------------------------------------- |
902 | | void Pass::setTextureFiltering(TextureFilterOptions filterType) |
903 | 0 | { |
904 | 0 | OGRE_LOCK_MUTEX(mTexUnitChangeMutex); |
905 | 0 | for (auto *t : mTextureUnitStates) |
906 | 0 | { |
907 | 0 | t->setTextureFiltering(filterType); |
908 | 0 | } |
909 | 0 | } |
910 | | // -------------------------------------------------------------------- |
911 | | void Pass::setTextureAnisotropy(unsigned int maxAniso) |
912 | 0 | { |
913 | 0 | OGRE_LOCK_MUTEX(mTexUnitChangeMutex); |
914 | 0 | for (auto *t : mTextureUnitStates) |
915 | 0 | { |
916 | 0 | t->setTextureAnisotropy(maxAniso); |
917 | 0 | } |
918 | 0 | } |
919 | | //----------------------------------------------------------------------- |
920 | | void Pass::_updateAutoParams(const AutoParamDataSource* source, uint16 mask) const |
921 | 0 | { |
922 | 0 | for(int i = 0; i < GPT_COUNT; i++) |
923 | 0 | { |
924 | 0 | const auto& programUsage = getProgramUsage(GpuProgramType(i)); |
925 | 0 | if (programUsage) |
926 | 0 | { |
927 | | // Update program auto params |
928 | 0 | programUsage->getParameters()->_updateAutoParams(source, mask); |
929 | 0 | } |
930 | 0 | } |
931 | 0 | } |
932 | | //----------------------------------------------------------------------- |
933 | | void Pass::processPendingPassUpdates(void) |
934 | 1 | { |
935 | 1 | { |
936 | 1 | OGRE_LOCK_MUTEX(msPassGraveyardMutex); |
937 | | // Delete items in the graveyard |
938 | 1 | for (auto& i : msPassGraveyard) |
939 | 0 | { |
940 | 0 | OGRE_DELETE i; |
941 | 0 | } |
942 | 1 | msPassGraveyard.clear(); |
943 | 1 | } |
944 | 1 | PassSet tempDirtyHashList; |
945 | 1 | { |
946 | 1 | OGRE_LOCK_MUTEX(msDirtyHashListMutex); |
947 | | // The dirty ones will have been removed from the groups above using the old hash now |
948 | 1 | tempDirtyHashList.swap(msDirtyHashList); |
949 | 1 | } |
950 | 1 | for (auto *p : tempDirtyHashList) |
951 | 0 | { |
952 | 0 | p->_recalculateHash(); |
953 | 0 | } |
954 | 1 | } |
955 | | //----------------------------------------------------------------------- |
956 | | void Pass::queueForDeletion(void) |
957 | 0 | { |
958 | 0 | mQueuedForDeletion = true; |
959 | |
|
960 | 0 | removeAllTextureUnitStates(); |
961 | 0 | for (auto& u : mProgramUsage) |
962 | 0 | u.reset(); |
963 | | |
964 | | // remove from dirty list, if there |
965 | 0 | { |
966 | 0 | OGRE_LOCK_MUTEX(msDirtyHashListMutex); |
967 | 0 | msDirtyHashList.erase(this); |
968 | 0 | } |
969 | 0 | { |
970 | 0 | OGRE_LOCK_MUTEX(msPassGraveyardMutex); |
971 | 0 | msPassGraveyard.insert(this); |
972 | 0 | } |
973 | 0 | } |
974 | | //----------------------------------------------------------------------- |
975 | | bool Pass::isAmbientOnly(void) const |
976 | 0 | { |
977 | | // treat as ambient if lighting is off, or colour write is off, |
978 | | // or all non-ambient (& emissive) colours are black |
979 | | // NB a vertex program could override this, but passes using vertex |
980 | | // programs are expected to indicate they are ambient only by |
981 | | // setting the state so it matches one of the conditions above, even |
982 | | // though this state is not used in rendering. |
983 | 0 | return (!mLightingEnabled || !getColourWriteEnabled() || |
984 | 0 | (mDiffuse == ColourValue::Black && |
985 | 0 | mSpecular == ColourValue::Black)); |
986 | 0 | } |
987 | | //----------------------------------------------------------------------- |
988 | | const String& Pass::getResourceGroup(void) const |
989 | 0 | { |
990 | 0 | return mParent->getResourceGroup(); |
991 | 0 | } |
992 | | //----------------------------------------------------------------------- |
993 | | unsigned short Pass::_getTextureUnitWithContentTypeIndex( |
994 | | TextureUnitState::ContentType contentType, unsigned short index) const |
995 | 0 | { |
996 | 0 | if (!mContentTypeLookupBuilt) |
997 | 0 | { |
998 | 0 | mShadowContentTypeLookup.clear(); |
999 | 0 | for (unsigned short i = 0; i < mTextureUnitStates.size(); ++i) |
1000 | 0 | { |
1001 | 0 | if (mTextureUnitStates[i]->getContentType() == TextureUnitState::CONTENT_SHADOW) |
1002 | 0 | { |
1003 | 0 | mShadowContentTypeLookup.push_back(i); |
1004 | 0 | } |
1005 | 0 | } |
1006 | 0 | mContentTypeLookupBuilt = true; |
1007 | 0 | } |
1008 | |
|
1009 | 0 | switch(contentType) |
1010 | 0 | { |
1011 | 0 | case TextureUnitState::CONTENT_SHADOW: |
1012 | 0 | if (index < mShadowContentTypeLookup.size()) |
1013 | 0 | { |
1014 | 0 | return mShadowContentTypeLookup[index]; |
1015 | 0 | } |
1016 | 0 | break; |
1017 | 0 | default: |
1018 | | // Simple iteration |
1019 | 0 | for (unsigned short i = 0; i < mTextureUnitStates.size(); ++i) |
1020 | 0 | { |
1021 | 0 | if (mTextureUnitStates[i]->getContentType() == TextureUnitState::CONTENT_SHADOW) |
1022 | 0 | { |
1023 | 0 | if (index == 0) |
1024 | 0 | { |
1025 | 0 | return i; |
1026 | 0 | } |
1027 | 0 | else |
1028 | 0 | { |
1029 | 0 | --index; |
1030 | 0 | } |
1031 | 0 | } |
1032 | 0 | } |
1033 | 0 | break; |
1034 | 0 | } |
1035 | | |
1036 | | // not found - return out of range |
1037 | 0 | return static_cast<unsigned short>(mTextureUnitStates.size() + 1); |
1038 | |
|
1039 | 0 | } |
1040 | | } |