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-2006 Torus Knot Software Ltd |
---|
8 | Also see acknowledgements in Readme.html |
---|
9 | |
---|
10 | This program is free software; you can redistribute it and/or modify it under |
---|
11 | the terms of the GNU Lesser General Public License as published by the Free Software |
---|
12 | Foundation; either version 2 of the License, or (at your option) any later |
---|
13 | version. |
---|
14 | |
---|
15 | This program is distributed in the hope that it will be useful, but WITHOUT |
---|
16 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
---|
17 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. |
---|
18 | |
---|
19 | You should have received a copy of the GNU Lesser General Public License along with |
---|
20 | this program; if not, write to the Free Software Foundation, Inc., 59 Temple |
---|
21 | Place - Suite 330, Boston, MA 02111-1307, USA, or go to |
---|
22 | http://www.gnu.org/copyleft/lesser.txt. |
---|
23 | |
---|
24 | You may alternatively use this source under the terms of a specific version of |
---|
25 | the OGRE Unrestricted License provided you have obtained such a license from |
---|
26 | Torus Knot Software Ltd. |
---|
27 | ----------------------------------------------------------------------------- |
---|
28 | */ |
---|
29 | #include "OgreStableHeaders.h" |
---|
30 | |
---|
31 | #include "OgrePass.h" |
---|
32 | #include "OgreTechnique.h" |
---|
33 | #include "OgreException.h" |
---|
34 | #include "OgreGpuProgramUsage.h" |
---|
35 | #include "OgreTextureUnitState.h" |
---|
36 | #include "OgreStringConverter.h" |
---|
37 | |
---|
38 | namespace Ogre { |
---|
39 | |
---|
40 | /** Default pass hash function. |
---|
41 | @remarks |
---|
42 | Tries to minimise the number of texture changes. |
---|
43 | */ |
---|
44 | struct MinTextureStateChangeHashFunc : public Pass::HashFunc |
---|
45 | { |
---|
46 | uint32 operator()(const Pass* p) const |
---|
47 | { |
---|
48 | |
---|
49 | _StringHash H; |
---|
50 | uint32 hash = p->getIndex() << 28; |
---|
51 | size_t c = p->getNumTextureUnitStates(); |
---|
52 | |
---|
53 | const TextureUnitState* t0 = 0; |
---|
54 | const TextureUnitState* t1 = 0; |
---|
55 | if (c) |
---|
56 | t0 = p->getTextureUnitState(0); |
---|
57 | if (c > 1) |
---|
58 | t1 = p->getTextureUnitState(1); |
---|
59 | |
---|
60 | if (t0 && !t0->getTextureName().empty()) |
---|
61 | hash += (static_cast<uint32>(H(t0->getTextureName())) |
---|
62 | % (1 << 14)) << 14; |
---|
63 | if (t1 && !t1->getTextureName().empty()) |
---|
64 | hash += (static_cast<uint32>(H(t1->getTextureName())) |
---|
65 | % (1 << 14)); |
---|
66 | |
---|
67 | return hash; |
---|
68 | } |
---|
69 | }; |
---|
70 | MinTextureStateChangeHashFunc sMinTextureStateChangeHashFunc; |
---|
71 | /** Alternate pass hash function. |
---|
72 | @remarks |
---|
73 | Tries to minimise the number of GPU program changes. |
---|
74 | */ |
---|
75 | struct MinGpuProgramChangeHashFunc : public Pass::HashFunc |
---|
76 | { |
---|
77 | uint32 operator()(const Pass* p) const |
---|
78 | { |
---|
79 | |
---|
80 | _StringHash H; |
---|
81 | uint32 hash = p->getIndex() << 28; |
---|
82 | if (p->hasVertexProgram()) |
---|
83 | hash += (static_cast<uint32>(H(p->getVertexProgramName())) |
---|
84 | % (1 << 14)) << 14; |
---|
85 | if (p->hasFragmentProgram()) |
---|
86 | hash += (static_cast<uint32>(H(p->getFragmentProgramName())) |
---|
87 | % (1 << 14)); |
---|
88 | |
---|
89 | return hash; |
---|
90 | } |
---|
91 | }; |
---|
92 | MinGpuProgramChangeHashFunc sMinGpuProgramChangeHashFunc; |
---|
93 | //----------------------------------------------------------------------------- |
---|
94 | Pass::PassSet Pass::msDirtyHashList; |
---|
95 | Pass::PassSet Pass::msPassGraveyard; |
---|
96 | OGRE_STATIC_MUTEX_INSTANCE(Pass::msDirtyHashListMutex) |
---|
97 | OGRE_STATIC_MUTEX_INSTANCE(Pass::msPassGraveyardMutex) |
---|
98 | |
---|
99 | Pass::HashFunc* Pass::msHashFunc = &sMinTextureStateChangeHashFunc; |
---|
100 | //----------------------------------------------------------------------------- |
---|
101 | void Pass::setHashFunction(BuiltinHashFunction builtin) |
---|
102 | { |
---|
103 | switch(builtin) |
---|
104 | { |
---|
105 | case MIN_TEXTURE_CHANGE: |
---|
106 | msHashFunc = &sMinTextureStateChangeHashFunc; |
---|
107 | break; |
---|
108 | case MIN_GPU_PROGRAM_CHANGE: |
---|
109 | msHashFunc = &sMinGpuProgramChangeHashFunc; |
---|
110 | break; |
---|
111 | } |
---|
112 | } |
---|
113 | //----------------------------------------------------------------------------- |
---|
114 | Pass::Pass(Technique* parent, unsigned short index) |
---|
115 | : mParent(parent) |
---|
116 | , mIndex(index) |
---|
117 | , mHash(0) |
---|
118 | , mAmbient(ColourValue::White) |
---|
119 | , mDiffuse(ColourValue::White) |
---|
120 | , mSpecular(ColourValue::Black) |
---|
121 | , mEmissive(ColourValue::Black) |
---|
122 | , mShininess(0) |
---|
123 | , mTracking(TVC_NONE) |
---|
124 | , mSourceBlendFactor(SBF_ONE) |
---|
125 | , mDestBlendFactor(SBF_ZERO) |
---|
126 | , mDepthCheck(true) |
---|
127 | , mDepthWrite(true) |
---|
128 | , mDepthFunc(CMPF_LESS_EQUAL) |
---|
129 | , mDepthBiasConstant(0.0f) |
---|
130 | , mDepthBiasSlopeScale(0.0f) |
---|
131 | , mColourWrite(true) |
---|
132 | , mAlphaRejectFunc(CMPF_ALWAYS_PASS) |
---|
133 | , mAlphaRejectVal(0) |
---|
134 | , mCullMode(CULL_CLOCKWISE) |
---|
135 | , mManualCullMode(MANUAL_CULL_BACK) |
---|
136 | , mLightingEnabled(true) |
---|
137 | , mMaxSimultaneousLights(OGRE_MAX_SIMULTANEOUS_LIGHTS) |
---|
138 | , mStartLight(0) |
---|
139 | , mIteratePerLight(false) |
---|
140 | , mLightsPerIteration(1) |
---|
141 | , mRunOnlyForOneLightType(false) |
---|
142 | , mOnlyLightType(Light::LT_POINT) |
---|
143 | , mShadeOptions(SO_GOURAUD) |
---|
144 | , mPolygonMode(PM_SOLID) |
---|
145 | , mFogOverride(false) |
---|
146 | , mFogMode(FOG_NONE) |
---|
147 | , mFogColour(ColourValue::White) |
---|
148 | , mFogStart(0.0) |
---|
149 | , mFogEnd(1.0) |
---|
150 | , mFogDensity(0.001) |
---|
151 | , mVertexProgramUsage(0) |
---|
152 | , mShadowCasterVertexProgramUsage(0) |
---|
153 | , mShadowReceiverVertexProgramUsage(0) |
---|
154 | , mFragmentProgramUsage(0) |
---|
155 | , mShadowReceiverFragmentProgramUsage(0) |
---|
156 | , mQueuedForDeletion(false) |
---|
157 | , mPassIterationCount(1) |
---|
158 | , mPointSize(1.0f) |
---|
159 | , mPointMinSize(0.0f) |
---|
160 | , mPointMaxSize(0.0f) |
---|
161 | , mPointSpritesEnabled(false) |
---|
162 | , mPointAttenuationEnabled(false) |
---|
163 | , mContentTypeLookupBuilt(false) |
---|
164 | { |
---|
165 | mPointAttenuationCoeffs[0] = 1.0f; |
---|
166 | mPointAttenuationCoeffs[1] = mPointAttenuationCoeffs[2] = 0.0f; |
---|
167 | |
---|
168 | // default name to index |
---|
169 | mName = StringConverter::toString(mIndex); |
---|
170 | |
---|
171 | _dirtyHash(); |
---|
172 | } |
---|
173 | |
---|
174 | //----------------------------------------------------------------------------- |
---|
175 | Pass::Pass(Technique *parent, unsigned short index, const Pass& oth) |
---|
176 | :mParent(parent), mIndex(index), mQueuedForDeletion(false), mPassIterationCount(1) |
---|
177 | { |
---|
178 | *this = oth; |
---|
179 | mParent = parent; |
---|
180 | mIndex = index; |
---|
181 | mQueuedForDeletion = false; |
---|
182 | _dirtyHash(); |
---|
183 | } |
---|
184 | //----------------------------------------------------------------------------- |
---|
185 | Pass::~Pass() |
---|
186 | { |
---|
187 | |
---|
188 | } |
---|
189 | //----------------------------------------------------------------------------- |
---|
190 | Pass& Pass::operator=(const Pass& oth) |
---|
191 | { |
---|
192 | mName = oth.mName; |
---|
193 | mHash = oth.mHash; |
---|
194 | mAmbient = oth.mAmbient; |
---|
195 | mDiffuse = oth.mDiffuse; |
---|
196 | mSpecular = oth.mSpecular; |
---|
197 | mEmissive = oth.mEmissive; |
---|
198 | mShininess = oth.mShininess; |
---|
199 | mTracking = oth.mTracking; |
---|
200 | |
---|
201 | // Copy fog parameters |
---|
202 | mFogOverride = oth.mFogOverride; |
---|
203 | mFogMode = oth.mFogMode; |
---|
204 | mFogColour = oth.mFogColour; |
---|
205 | mFogStart = oth.mFogStart; |
---|
206 | mFogEnd = oth.mFogEnd; |
---|
207 | mFogDensity = oth.mFogDensity; |
---|
208 | |
---|
209 | // Default blending (overwrite) |
---|
210 | mSourceBlendFactor = oth.mSourceBlendFactor; |
---|
211 | mDestBlendFactor = oth.mDestBlendFactor; |
---|
212 | |
---|
213 | mDepthCheck = oth.mDepthCheck; |
---|
214 | mDepthWrite = oth.mDepthWrite; |
---|
215 | mAlphaRejectFunc = oth.mAlphaRejectFunc; |
---|
216 | mAlphaRejectVal = oth.mAlphaRejectVal; |
---|
217 | mColourWrite = oth.mColourWrite; |
---|
218 | mDepthFunc = oth.mDepthFunc; |
---|
219 | mDepthBiasConstant = oth.mDepthBiasConstant; |
---|
220 | mDepthBiasSlopeScale = oth.mDepthBiasSlopeScale; |
---|
221 | mCullMode = oth.mCullMode; |
---|
222 | mManualCullMode = oth.mManualCullMode; |
---|
223 | mLightingEnabled = oth.mLightingEnabled; |
---|
224 | mMaxSimultaneousLights = oth.mMaxSimultaneousLights; |
---|
225 | mStartLight = oth.mStartLight; |
---|
226 | mIteratePerLight = oth.mIteratePerLight; |
---|
227 | mLightsPerIteration = oth.mLightsPerIteration; |
---|
228 | mRunOnlyForOneLightType = oth.mRunOnlyForOneLightType; |
---|
229 | mOnlyLightType = oth.mOnlyLightType; |
---|
230 | mShadeOptions = oth.mShadeOptions; |
---|
231 | mPolygonMode = oth.mPolygonMode; |
---|
232 | mPassIterationCount = oth.mPassIterationCount; |
---|
233 | mPointSize = oth.mPointSize; |
---|
234 | mPointMinSize = oth.mPointMinSize; |
---|
235 | mPointMaxSize = oth.mPointMaxSize; |
---|
236 | mPointSpritesEnabled = oth.mPointSpritesEnabled; |
---|
237 | mPointAttenuationEnabled = oth.mPointAttenuationEnabled; |
---|
238 | memcpy(mPointAttenuationCoeffs, oth.mPointAttenuationCoeffs, sizeof(Real)*3); |
---|
239 | mShadowContentTypeLookup = oth.mShadowContentTypeLookup; |
---|
240 | mContentTypeLookupBuilt = oth.mContentTypeLookupBuilt; |
---|
241 | |
---|
242 | |
---|
243 | if (oth.mVertexProgramUsage) |
---|
244 | { |
---|
245 | mVertexProgramUsage = new GpuProgramUsage(*(oth.mVertexProgramUsage)); |
---|
246 | } |
---|
247 | else |
---|
248 | { |
---|
249 | mVertexProgramUsage = NULL; |
---|
250 | } |
---|
251 | if (oth.mShadowCasterVertexProgramUsage) |
---|
252 | { |
---|
253 | mShadowCasterVertexProgramUsage = new GpuProgramUsage(*(oth.mShadowCasterVertexProgramUsage)); |
---|
254 | } |
---|
255 | else |
---|
256 | { |
---|
257 | mShadowCasterVertexProgramUsage = NULL; |
---|
258 | } |
---|
259 | if (oth.mShadowReceiverVertexProgramUsage) |
---|
260 | { |
---|
261 | mShadowReceiverVertexProgramUsage = new GpuProgramUsage(*(oth.mShadowReceiverVertexProgramUsage)); |
---|
262 | } |
---|
263 | else |
---|
264 | { |
---|
265 | mShadowReceiverVertexProgramUsage = NULL; |
---|
266 | } |
---|
267 | if (oth.mFragmentProgramUsage) |
---|
268 | { |
---|
269 | mFragmentProgramUsage = new GpuProgramUsage(*(oth.mFragmentProgramUsage)); |
---|
270 | } |
---|
271 | else |
---|
272 | { |
---|
273 | mFragmentProgramUsage = NULL; |
---|
274 | } |
---|
275 | if (oth.mShadowReceiverFragmentProgramUsage) |
---|
276 | { |
---|
277 | mShadowReceiverFragmentProgramUsage = new GpuProgramUsage(*(oth.mShadowReceiverFragmentProgramUsage)); |
---|
278 | } |
---|
279 | else |
---|
280 | { |
---|
281 | mShadowReceiverFragmentProgramUsage = NULL; |
---|
282 | } |
---|
283 | |
---|
284 | TextureUnitStates::const_iterator i, iend; |
---|
285 | |
---|
286 | // Clear texture units but doesn't notify need recompilation in the case |
---|
287 | // we are cloning, The parent material will take care of this. |
---|
288 | iend = mTextureUnitStates.end(); |
---|
289 | for (i = mTextureUnitStates.begin(); i != iend; ++i) |
---|
290 | { |
---|
291 | delete *i; |
---|
292 | } |
---|
293 | |
---|
294 | mTextureUnitStates.clear(); |
---|
295 | |
---|
296 | // Copy texture units |
---|
297 | iend = oth.mTextureUnitStates.end(); |
---|
298 | for (i = oth.mTextureUnitStates.begin(); i != iend; ++i) |
---|
299 | { |
---|
300 | TextureUnitState* t = new TextureUnitState(this, *(*i)); |
---|
301 | mTextureUnitStates.push_back(t); |
---|
302 | } |
---|
303 | |
---|
304 | _dirtyHash(); |
---|
305 | |
---|
306 | return *this; |
---|
307 | } |
---|
308 | //----------------------------------------------------------------------- |
---|
309 | void Pass::setName(const String& name) |
---|
310 | { |
---|
311 | mName = name; |
---|
312 | } |
---|
313 | //----------------------------------------------------------------------- |
---|
314 | void Pass::setPointSize(Real ps) |
---|
315 | { |
---|
316 | mPointSize = ps; |
---|
317 | } |
---|
318 | //----------------------------------------------------------------------- |
---|
319 | void Pass::setPointSpritesEnabled(bool enabled) |
---|
320 | { |
---|
321 | mPointSpritesEnabled = enabled; |
---|
322 | } |
---|
323 | //----------------------------------------------------------------------- |
---|
324 | bool Pass::getPointSpritesEnabled(void) const |
---|
325 | { |
---|
326 | return mPointSpritesEnabled; |
---|
327 | } |
---|
328 | //----------------------------------------------------------------------- |
---|
329 | void Pass::setPointAttenuation(bool enabled, |
---|
330 | Real constant, Real linear, Real quadratic) |
---|
331 | { |
---|
332 | mPointAttenuationEnabled = enabled; |
---|
333 | mPointAttenuationCoeffs[0] = constant; |
---|
334 | mPointAttenuationCoeffs[1] = linear; |
---|
335 | mPointAttenuationCoeffs[2] = quadratic; |
---|
336 | } |
---|
337 | //----------------------------------------------------------------------- |
---|
338 | bool Pass::isPointAttenuationEnabled(void) const |
---|
339 | { |
---|
340 | return mPointAttenuationEnabled; |
---|
341 | } |
---|
342 | //----------------------------------------------------------------------- |
---|
343 | Real Pass::getPointAttenuationConstant(void) const |
---|
344 | { |
---|
345 | return mPointAttenuationCoeffs[0]; |
---|
346 | } |
---|
347 | //----------------------------------------------------------------------- |
---|
348 | Real Pass::getPointAttenuationLinear(void) const |
---|
349 | { |
---|
350 | return mPointAttenuationCoeffs[1]; |
---|
351 | } |
---|
352 | //----------------------------------------------------------------------- |
---|
353 | Real Pass::getPointAttenuationQuadratic(void) const |
---|
354 | { |
---|
355 | return mPointAttenuationCoeffs[2]; |
---|
356 | } |
---|
357 | //----------------------------------------------------------------------- |
---|
358 | void Pass::setPointMinSize(Real min) |
---|
359 | { |
---|
360 | mPointMinSize = min; |
---|
361 | } |
---|
362 | //----------------------------------------------------------------------- |
---|
363 | Real Pass::getPointMinSize(void) const |
---|
364 | { |
---|
365 | return mPointMinSize; |
---|
366 | } |
---|
367 | //----------------------------------------------------------------------- |
---|
368 | void Pass::setPointMaxSize(Real max) |
---|
369 | { |
---|
370 | mPointMaxSize = max; |
---|
371 | } |
---|
372 | //----------------------------------------------------------------------- |
---|
373 | Real Pass::getPointMaxSize(void) const |
---|
374 | { |
---|
375 | return mPointMaxSize; |
---|
376 | } |
---|
377 | //----------------------------------------------------------------------- |
---|
378 | void Pass::setAmbient(Real red, Real green, Real blue) |
---|
379 | { |
---|
380 | mAmbient.r = red; |
---|
381 | mAmbient.g = green; |
---|
382 | mAmbient.b = blue; |
---|
383 | |
---|
384 | } |
---|
385 | //----------------------------------------------------------------------- |
---|
386 | void Pass::setAmbient(const ColourValue& ambient) |
---|
387 | { |
---|
388 | mAmbient = ambient; |
---|
389 | } |
---|
390 | //----------------------------------------------------------------------- |
---|
391 | void Pass::setDiffuse(Real red, Real green, Real blue, Real alpha) |
---|
392 | { |
---|
393 | mDiffuse.r = red; |
---|
394 | mDiffuse.g = green; |
---|
395 | mDiffuse.b = blue; |
---|
396 | mDiffuse.a = alpha; |
---|
397 | } |
---|
398 | //----------------------------------------------------------------------- |
---|
399 | void Pass::setDiffuse(const ColourValue& diffuse) |
---|
400 | { |
---|
401 | mDiffuse = diffuse; |
---|
402 | } |
---|
403 | //----------------------------------------------------------------------- |
---|
404 | void Pass::setSpecular(Real red, Real green, Real blue, Real alpha) |
---|
405 | { |
---|
406 | mSpecular.r = red; |
---|
407 | mSpecular.g = green; |
---|
408 | mSpecular.b = blue; |
---|
409 | mSpecular.a = alpha; |
---|
410 | } |
---|
411 | //----------------------------------------------------------------------- |
---|
412 | void Pass::setSpecular(const ColourValue& specular) |
---|
413 | { |
---|
414 | mSpecular = specular; |
---|
415 | } |
---|
416 | //----------------------------------------------------------------------- |
---|
417 | void Pass::setShininess(Real val) |
---|
418 | { |
---|
419 | mShininess = val; |
---|
420 | } |
---|
421 | //----------------------------------------------------------------------- |
---|
422 | void Pass::setSelfIllumination(Real red, Real green, Real blue) |
---|
423 | { |
---|
424 | mEmissive.r = red; |
---|
425 | mEmissive.g = green; |
---|
426 | mEmissive.b = blue; |
---|
427 | |
---|
428 | } |
---|
429 | //----------------------------------------------------------------------- |
---|
430 | void Pass::setSelfIllumination(const ColourValue& selfIllum) |
---|
431 | { |
---|
432 | mEmissive = selfIllum; |
---|
433 | } |
---|
434 | //----------------------------------------------------------------------- |
---|
435 | void Pass::setVertexColourTracking(TrackVertexColourType tracking) |
---|
436 | { |
---|
437 | mTracking = tracking; |
---|
438 | } |
---|
439 | //----------------------------------------------------------------------- |
---|
440 | Real Pass::getPointSize(void) const |
---|
441 | { |
---|
442 | return mPointSize; |
---|
443 | } |
---|
444 | //----------------------------------------------------------------------- |
---|
445 | const ColourValue& Pass::getAmbient(void) const |
---|
446 | { |
---|
447 | return mAmbient; |
---|
448 | } |
---|
449 | //----------------------------------------------------------------------- |
---|
450 | const ColourValue& Pass::getDiffuse(void) const |
---|
451 | { |
---|
452 | return mDiffuse; |
---|
453 | } |
---|
454 | //----------------------------------------------------------------------- |
---|
455 | const ColourValue& Pass::getSpecular(void) const |
---|
456 | { |
---|
457 | return mSpecular; |
---|
458 | } |
---|
459 | //----------------------------------------------------------------------- |
---|
460 | const ColourValue& Pass::getSelfIllumination(void) const |
---|
461 | { |
---|
462 | return mEmissive; |
---|
463 | } |
---|
464 | //----------------------------------------------------------------------- |
---|
465 | Real Pass::getShininess(void) const |
---|
466 | { |
---|
467 | return mShininess; |
---|
468 | } |
---|
469 | //----------------------------------------------------------------------- |
---|
470 | TrackVertexColourType Pass::getVertexColourTracking(void) const |
---|
471 | { |
---|
472 | return mTracking; |
---|
473 | } |
---|
474 | //----------------------------------------------------------------------- |
---|
475 | TextureUnitState* Pass::createTextureUnitState(void) |
---|
476 | { |
---|
477 | TextureUnitState *t = new TextureUnitState(this); |
---|
478 | addTextureUnitState(t); |
---|
479 | mContentTypeLookupBuilt = false; |
---|
480 | return t; |
---|
481 | } |
---|
482 | //----------------------------------------------------------------------- |
---|
483 | TextureUnitState* Pass::createTextureUnitState( |
---|
484 | const String& textureName, unsigned short texCoordSet) |
---|
485 | { |
---|
486 | TextureUnitState *t = new TextureUnitState(this); |
---|
487 | t->setTextureName(textureName); |
---|
488 | t->setTextureCoordSet(texCoordSet); |
---|
489 | addTextureUnitState(t); |
---|
490 | mContentTypeLookupBuilt = false; |
---|
491 | return t; |
---|
492 | } |
---|
493 | //----------------------------------------------------------------------- |
---|
494 | void Pass::addTextureUnitState(TextureUnitState* state) |
---|
495 | { |
---|
496 | assert(state && "state is 0 in Pass::addTextureUnitState()"); |
---|
497 | if (state) |
---|
498 | { |
---|
499 | // only attach TUS to pass if TUS does not belong to another pass |
---|
500 | if ((state->getParent() == 0) || (state->getParent() == this)) |
---|
501 | { |
---|
502 | mTextureUnitStates.push_back(state); |
---|
503 | // Notify state |
---|
504 | state->_notifyParent(this); |
---|
505 | // if texture unit state name is empty then give it a default name based on its index |
---|
506 | if (state->getName().empty()) |
---|
507 | { |
---|
508 | // its the last entry in the container so its index is size - 1 |
---|
509 | size_t idx = mTextureUnitStates.size() - 1; |
---|
510 | state->setName( StringConverter::toString(idx) ); |
---|
511 | /** since the name was never set and a default one has been made, clear the alias name |
---|
512 | so that when the texture unit name is set by the user, the alias name will be set to |
---|
513 | that name |
---|
514 | */ |
---|
515 | state->setTextureNameAlias(StringUtil::BLANK); |
---|
516 | } |
---|
517 | // Needs recompilation |
---|
518 | mParent->_notifyNeedsRecompile(); |
---|
519 | _dirtyHash(); |
---|
520 | } |
---|
521 | else |
---|
522 | { |
---|
523 | OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "TextureUnitState already attached to another pass", |
---|
524 | "Pass:addTextureUnitState"); |
---|
525 | |
---|
526 | } |
---|
527 | mContentTypeLookupBuilt = false; |
---|
528 | } |
---|
529 | } |
---|
530 | //----------------------------------------------------------------------- |
---|
531 | TextureUnitState* Pass::getTextureUnitState(unsigned short index) |
---|
532 | { |
---|
533 | assert (index < mTextureUnitStates.size() && "Index out of bounds"); |
---|
534 | return mTextureUnitStates[index]; |
---|
535 | } |
---|
536 | //----------------------------------------------------------------------------- |
---|
537 | TextureUnitState* Pass::getTextureUnitState(const String& name) |
---|
538 | { |
---|
539 | TextureUnitStates::iterator i = mTextureUnitStates.begin(); |
---|
540 | TextureUnitStates::iterator iend = mTextureUnitStates.end(); |
---|
541 | TextureUnitState* foundTUS = 0; |
---|
542 | |
---|
543 | // iterate through TUS Container to find a match |
---|
544 | while (i != iend) |
---|
545 | { |
---|
546 | if ( (*i)->getName() == name ) |
---|
547 | { |
---|
548 | foundTUS = (*i); |
---|
549 | break; |
---|
550 | } |
---|
551 | |
---|
552 | ++i; |
---|
553 | } |
---|
554 | |
---|
555 | return foundTUS; |
---|
556 | } |
---|
557 | //----------------------------------------------------------------------- |
---|
558 | const TextureUnitState* Pass::getTextureUnitState(unsigned short index) const |
---|
559 | { |
---|
560 | assert (index < mTextureUnitStates.size() && "Index out of bounds"); |
---|
561 | return mTextureUnitStates[index]; |
---|
562 | } |
---|
563 | //----------------------------------------------------------------------------- |
---|
564 | const TextureUnitState* Pass::getTextureUnitState(const String& name) const |
---|
565 | { |
---|
566 | TextureUnitStates::const_iterator i = mTextureUnitStates.begin(); |
---|
567 | TextureUnitStates::const_iterator iend = mTextureUnitStates.end(); |
---|
568 | const TextureUnitState* foundTUS = 0; |
---|
569 | |
---|
570 | // iterate through TUS Container to find a match |
---|
571 | while (i != iend) |
---|
572 | { |
---|
573 | if ( (*i)->getName() == name ) |
---|
574 | { |
---|
575 | foundTUS = (*i); |
---|
576 | break; |
---|
577 | } |
---|
578 | |
---|
579 | ++i; |
---|
580 | } |
---|
581 | |
---|
582 | return foundTUS; |
---|
583 | } |
---|
584 | |
---|
585 | //----------------------------------------------------------------------- |
---|
586 | unsigned short Pass::getTextureUnitStateIndex(const TextureUnitState* state) const |
---|
587 | { |
---|
588 | assert(state && "state is 0 in Pass::getTextureUnitStateIndex()"); |
---|
589 | |
---|
590 | // only find index for state attached to this pass |
---|
591 | if (state->getParent() == this) |
---|
592 | { |
---|
593 | TextureUnitStates::const_iterator i = |
---|
594 | std::find(mTextureUnitStates.begin(), mTextureUnitStates.end(), state); |
---|
595 | assert(i != mTextureUnitStates.end() && "state is supposed to attached to this pass"); |
---|
596 | return static_cast<unsigned short>(std::distance(mTextureUnitStates.begin(), i)); |
---|
597 | } |
---|
598 | else |
---|
599 | { |
---|
600 | OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "TextureUnitState is not attached to this pass", |
---|
601 | "Pass:getTextureUnitStateIndex"); |
---|
602 | } |
---|
603 | } |
---|
604 | |
---|
605 | //----------------------------------------------------------------------- |
---|
606 | Pass::TextureUnitStateIterator |
---|
607 | Pass::getTextureUnitStateIterator(void) |
---|
608 | { |
---|
609 | return TextureUnitStateIterator(mTextureUnitStates.begin(), mTextureUnitStates.end()); |
---|
610 | } |
---|
611 | //----------------------------------------------------------------------- |
---|
612 | Pass::ConstTextureUnitStateIterator |
---|
613 | Pass::getTextureUnitStateIterator(void) const |
---|
614 | { |
---|
615 | return ConstTextureUnitStateIterator(mTextureUnitStates.begin(), mTextureUnitStates.end()); |
---|
616 | } |
---|
617 | //----------------------------------------------------------------------- |
---|
618 | void Pass::removeTextureUnitState(unsigned short index) |
---|
619 | { |
---|
620 | assert (index < mTextureUnitStates.size() && "Index out of bounds"); |
---|
621 | |
---|
622 | TextureUnitStates::iterator i = mTextureUnitStates.begin() + index; |
---|
623 | delete *i; |
---|
624 | mTextureUnitStates.erase(i); |
---|
625 | if (!mQueuedForDeletion) |
---|
626 | { |
---|
627 | // Needs recompilation |
---|
628 | mParent->_notifyNeedsRecompile(); |
---|
629 | } |
---|
630 | _dirtyHash(); |
---|
631 | mContentTypeLookupBuilt = false; |
---|
632 | } |
---|
633 | //----------------------------------------------------------------------- |
---|
634 | void Pass::removeAllTextureUnitStates(void) |
---|
635 | { |
---|
636 | TextureUnitStates::iterator i, iend; |
---|
637 | iend = mTextureUnitStates.end(); |
---|
638 | for (i = mTextureUnitStates.begin(); i != iend; ++i) |
---|
639 | { |
---|
640 | delete *i; |
---|
641 | } |
---|
642 | mTextureUnitStates.clear(); |
---|
643 | if (!mQueuedForDeletion) |
---|
644 | { |
---|
645 | // Needs recompilation |
---|
646 | mParent->_notifyNeedsRecompile(); |
---|
647 | } |
---|
648 | _dirtyHash(); |
---|
649 | mContentTypeLookupBuilt = false; |
---|
650 | } |
---|
651 | //----------------------------------------------------------------------- |
---|
652 | void Pass::setSceneBlending(SceneBlendType sbt) |
---|
653 | { |
---|
654 | // Turn predefined type into blending factors |
---|
655 | switch (sbt) |
---|
656 | { |
---|
657 | case SBT_TRANSPARENT_ALPHA: |
---|
658 | setSceneBlending(SBF_SOURCE_ALPHA, SBF_ONE_MINUS_SOURCE_ALPHA); |
---|
659 | break; |
---|
660 | case SBT_TRANSPARENT_COLOUR: |
---|
661 | setSceneBlending(SBF_SOURCE_COLOUR, SBF_ONE_MINUS_SOURCE_COLOUR); |
---|
662 | break; |
---|
663 | case SBT_MODULATE: |
---|
664 | setSceneBlending(SBF_DEST_COLOUR, SBF_ZERO); |
---|
665 | break; |
---|
666 | case SBT_ADD: |
---|
667 | setSceneBlending(SBF_ONE, SBF_ONE); |
---|
668 | break; |
---|
669 | case SBT_REPLACE: |
---|
670 | setSceneBlending(SBF_ONE, SBF_ZERO); |
---|
671 | break; |
---|
672 | // TODO: more |
---|
673 | } |
---|
674 | |
---|
675 | } |
---|
676 | //----------------------------------------------------------------------- |
---|
677 | void Pass::setSceneBlending(SceneBlendFactor sourceFactor, SceneBlendFactor destFactor) |
---|
678 | { |
---|
679 | mSourceBlendFactor = sourceFactor; |
---|
680 | mDestBlendFactor = destFactor; |
---|
681 | } |
---|
682 | //----------------------------------------------------------------------- |
---|
683 | SceneBlendFactor Pass::getSourceBlendFactor(void) const |
---|
684 | { |
---|
685 | return mSourceBlendFactor; |
---|
686 | } |
---|
687 | //----------------------------------------------------------------------- |
---|
688 | SceneBlendFactor Pass::getDestBlendFactor(void) const |
---|
689 | { |
---|
690 | return mDestBlendFactor; |
---|
691 | } |
---|
692 | //----------------------------------------------------------------------- |
---|
693 | bool Pass::isTransparent(void) const |
---|
694 | { |
---|
695 | // Transparent if any of the destination colour is taken into account |
---|
696 | if (mDestBlendFactor == SBF_ZERO && |
---|
697 | mSourceBlendFactor != SBF_DEST_COLOUR && |
---|
698 | mSourceBlendFactor != SBF_ONE_MINUS_DEST_COLOUR && |
---|
699 | mSourceBlendFactor != SBF_DEST_ALPHA && |
---|
700 | mSourceBlendFactor != SBF_ONE_MINUS_DEST_ALPHA) |
---|
701 | { |
---|
702 | return false; |
---|
703 | } |
---|
704 | else |
---|
705 | { |
---|
706 | return true; |
---|
707 | } |
---|
708 | } |
---|
709 | //----------------------------------------------------------------------- |
---|
710 | void Pass::setDepthCheckEnabled(bool enabled) |
---|
711 | { |
---|
712 | mDepthCheck = enabled; |
---|
713 | } |
---|
714 | //----------------------------------------------------------------------- |
---|
715 | bool Pass::getDepthCheckEnabled(void) const |
---|
716 | { |
---|
717 | return mDepthCheck; |
---|
718 | } |
---|
719 | //----------------------------------------------------------------------- |
---|
720 | void Pass::setDepthWriteEnabled(bool enabled) |
---|
721 | { |
---|
722 | mDepthWrite = enabled; |
---|
723 | } |
---|
724 | //----------------------------------------------------------------------- |
---|
725 | bool Pass::getDepthWriteEnabled(void) const |
---|
726 | { |
---|
727 | return mDepthWrite; |
---|
728 | } |
---|
729 | //----------------------------------------------------------------------- |
---|
730 | void Pass::setDepthFunction( CompareFunction func) |
---|
731 | { |
---|
732 | mDepthFunc = func; |
---|
733 | } |
---|
734 | //----------------------------------------------------------------------- |
---|
735 | CompareFunction Pass::getDepthFunction(void) const |
---|
736 | { |
---|
737 | return mDepthFunc; |
---|
738 | } |
---|
739 | //----------------------------------------------------------------------- |
---|
740 | void Pass::setAlphaRejectSettings(CompareFunction func, unsigned char value) |
---|
741 | { |
---|
742 | mAlphaRejectFunc = func; |
---|
743 | mAlphaRejectVal = value; |
---|
744 | } |
---|
745 | //----------------------------------------------------------------------- |
---|
746 | void Pass::setAlphaRejectFunction(CompareFunction func) |
---|
747 | { |
---|
748 | mAlphaRejectFunc = func; |
---|
749 | } |
---|
750 | //----------------------------------------------------------------------- |
---|
751 | void Pass::setAlphaRejectValue(unsigned char val) |
---|
752 | { |
---|
753 | mAlphaRejectVal = val; |
---|
754 | } |
---|
755 | //----------------------------------------------------------------------- |
---|
756 | void Pass::setColourWriteEnabled(bool enabled) |
---|
757 | { |
---|
758 | mColourWrite = enabled; |
---|
759 | } |
---|
760 | //----------------------------------------------------------------------- |
---|
761 | bool Pass::getColourWriteEnabled(void) const |
---|
762 | { |
---|
763 | return mColourWrite; |
---|
764 | } |
---|
765 | //----------------------------------------------------------------------- |
---|
766 | void Pass::setCullingMode( CullingMode mode) |
---|
767 | { |
---|
768 | mCullMode = mode; |
---|
769 | } |
---|
770 | //----------------------------------------------------------------------- |
---|
771 | CullingMode Pass::getCullingMode(void) const |
---|
772 | { |
---|
773 | return mCullMode; |
---|
774 | } |
---|
775 | //----------------------------------------------------------------------- |
---|
776 | void Pass::setLightingEnabled(bool enabled) |
---|
777 | { |
---|
778 | mLightingEnabled = enabled; |
---|
779 | } |
---|
780 | //----------------------------------------------------------------------- |
---|
781 | bool Pass::getLightingEnabled(void) const |
---|
782 | { |
---|
783 | return mLightingEnabled; |
---|
784 | } |
---|
785 | //----------------------------------------------------------------------- |
---|
786 | void Pass::setMaxSimultaneousLights(unsigned short maxLights) |
---|
787 | { |
---|
788 | mMaxSimultaneousLights = maxLights; |
---|
789 | } |
---|
790 | //----------------------------------------------------------------------- |
---|
791 | unsigned short Pass::getMaxSimultaneousLights(void) const |
---|
792 | { |
---|
793 | return mMaxSimultaneousLights; |
---|
794 | } |
---|
795 | //----------------------------------------------------------------------- |
---|
796 | void Pass::setStartLight(unsigned short startLight) |
---|
797 | { |
---|
798 | mStartLight = startLight; |
---|
799 | } |
---|
800 | //----------------------------------------------------------------------- |
---|
801 | unsigned short Pass::getStartLight(void) const |
---|
802 | { |
---|
803 | return mStartLight; |
---|
804 | } |
---|
805 | //----------------------------------------------------------------------- |
---|
806 | void Pass::setLightCountPerIteration(unsigned short c) |
---|
807 | { |
---|
808 | mLightsPerIteration = c; |
---|
809 | } |
---|
810 | //----------------------------------------------------------------------- |
---|
811 | unsigned short Pass::getLightCountPerIteration(void) const |
---|
812 | { |
---|
813 | return mLightsPerIteration; |
---|
814 | } |
---|
815 | //----------------------------------------------------------------------- |
---|
816 | void Pass::setIteratePerLight(bool enabled, |
---|
817 | bool onlyForOneLightType, Light::LightTypes lightType) |
---|
818 | { |
---|
819 | mIteratePerLight = enabled; |
---|
820 | mRunOnlyForOneLightType = onlyForOneLightType; |
---|
821 | mOnlyLightType = lightType; |
---|
822 | } |
---|
823 | //----------------------------------------------------------------------- |
---|
824 | void Pass::setShadingMode(ShadeOptions mode) |
---|
825 | { |
---|
826 | mShadeOptions = mode; |
---|
827 | } |
---|
828 | //----------------------------------------------------------------------- |
---|
829 | ShadeOptions Pass::getShadingMode(void) const |
---|
830 | { |
---|
831 | return mShadeOptions; |
---|
832 | } |
---|
833 | //----------------------------------------------------------------------- |
---|
834 | void Pass::setPolygonMode(PolygonMode mode) |
---|
835 | { |
---|
836 | mPolygonMode = mode; |
---|
837 | } |
---|
838 | //----------------------------------------------------------------------- |
---|
839 | PolygonMode Pass::getPolygonMode(void) const |
---|
840 | { |
---|
841 | return mPolygonMode; |
---|
842 | } |
---|
843 | //----------------------------------------------------------------------- |
---|
844 | void Pass::setManualCullingMode(ManualCullingMode mode) |
---|
845 | { |
---|
846 | mManualCullMode = mode; |
---|
847 | } |
---|
848 | //----------------------------------------------------------------------- |
---|
849 | ManualCullingMode Pass::getManualCullingMode(void) const |
---|
850 | { |
---|
851 | return mManualCullMode; |
---|
852 | } |
---|
853 | //----------------------------------------------------------------------- |
---|
854 | void Pass::setFog(bool overrideScene, FogMode mode, const ColourValue& colour, Real density, Real start, Real end) |
---|
855 | { |
---|
856 | mFogOverride = overrideScene; |
---|
857 | if (overrideScene) |
---|
858 | { |
---|
859 | mFogMode = mode; |
---|
860 | mFogColour = colour; |
---|
861 | mFogStart = start; |
---|
862 | mFogEnd = end; |
---|
863 | mFogDensity = density; |
---|
864 | } |
---|
865 | } |
---|
866 | //----------------------------------------------------------------------- |
---|
867 | bool Pass::getFogOverride(void) const |
---|
868 | { |
---|
869 | return mFogOverride; |
---|
870 | } |
---|
871 | //----------------------------------------------------------------------- |
---|
872 | FogMode Pass::getFogMode(void) const |
---|
873 | { |
---|
874 | return mFogMode; |
---|
875 | } |
---|
876 | //----------------------------------------------------------------------- |
---|
877 | const ColourValue& Pass::getFogColour(void) const |
---|
878 | { |
---|
879 | return mFogColour; |
---|
880 | } |
---|
881 | //----------------------------------------------------------------------- |
---|
882 | Real Pass::getFogStart(void) const |
---|
883 | { |
---|
884 | return mFogStart; |
---|
885 | } |
---|
886 | //----------------------------------------------------------------------- |
---|
887 | Real Pass::getFogEnd(void) const |
---|
888 | { |
---|
889 | return mFogEnd; |
---|
890 | } |
---|
891 | //----------------------------------------------------------------------- |
---|
892 | Real Pass::getFogDensity(void) const |
---|
893 | { |
---|
894 | return mFogDensity; |
---|
895 | } |
---|
896 | //----------------------------------------------------------------------- |
---|
897 | void Pass::setDepthBias(float constantBias, float slopeScaleBias) |
---|
898 | { |
---|
899 | mDepthBiasConstant = constantBias; |
---|
900 | mDepthBiasSlopeScale = slopeScaleBias; |
---|
901 | } |
---|
902 | //----------------------------------------------------------------------- |
---|
903 | float Pass::getDepthBiasConstant(void) const |
---|
904 | { |
---|
905 | return mDepthBiasConstant; |
---|
906 | } |
---|
907 | //----------------------------------------------------------------------- |
---|
908 | float Pass::getDepthBiasSlopeScale(void) const |
---|
909 | { |
---|
910 | return mDepthBiasSlopeScale; |
---|
911 | } |
---|
912 | //----------------------------------------------------------------------- |
---|
913 | Pass* Pass::_split(unsigned short numUnits) |
---|
914 | { |
---|
915 | if (mVertexProgramUsage || mFragmentProgramUsage) |
---|
916 | { |
---|
917 | OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Programmable passes cannot be " |
---|
918 | "automatically split, define a fallback technique instead.", |
---|
919 | "Pass:_split"); |
---|
920 | } |
---|
921 | |
---|
922 | if (mTextureUnitStates.size() > numUnits) |
---|
923 | { |
---|
924 | size_t start = mTextureUnitStates.size() - numUnits; |
---|
925 | |
---|
926 | Pass* newPass = mParent->createPass(); |
---|
927 | |
---|
928 | TextureUnitStates::iterator istart, i, iend; |
---|
929 | iend = mTextureUnitStates.end(); |
---|
930 | i = istart = mTextureUnitStates.begin() + start; |
---|
931 | // Set the new pass to fallback using scene blend |
---|
932 | newPass->setSceneBlending( |
---|
933 | (*i)->getColourBlendFallbackSrc(), (*i)->getColourBlendFallbackDest()); |
---|
934 | // Fixup the texture unit 0 of new pass blending method to replace |
---|
935 | // all colour and alpha with texture without adjustment, because we |
---|
936 | // assume it's detail texture. |
---|
937 | (*i)->setColourOperationEx(LBX_SOURCE1, LBS_TEXTURE, LBS_CURRENT); |
---|
938 | (*i)->setAlphaOperation(LBX_SOURCE1, LBS_TEXTURE, LBS_CURRENT); |
---|
939 | |
---|
940 | // Add all the other texture unit states |
---|
941 | for (; i != iend; ++i) |
---|
942 | { |
---|
943 | // detach from parent first |
---|
944 | (*i)->_notifyParent(0); |
---|
945 | newPass->addTextureUnitState(*i); |
---|
946 | } |
---|
947 | // Now remove texture units from this Pass, we don't need to delete since they've |
---|
948 | // been transferred |
---|
949 | mTextureUnitStates.erase(istart, iend); |
---|
950 | _dirtyHash(); |
---|
951 | mContentTypeLookupBuilt = false; |
---|
952 | return newPass; |
---|
953 | } |
---|
954 | return NULL; |
---|
955 | } |
---|
956 | //----------------------------------------------------------------------------- |
---|
957 | void Pass::_notifyIndex(unsigned short index) |
---|
958 | { |
---|
959 | if (mIndex != index) |
---|
960 | { |
---|
961 | mIndex = index; |
---|
962 | _dirtyHash(); |
---|
963 | } |
---|
964 | } |
---|
965 | //----------------------------------------------------------------------- |
---|
966 | void Pass::_load(void) |
---|
967 | { |
---|
968 | // We assume the Technique only calls this when the material is being |
---|
969 | // loaded |
---|
970 | |
---|
971 | // Load each TextureUnitState |
---|
972 | TextureUnitStates::iterator i, iend; |
---|
973 | iend = mTextureUnitStates.end(); |
---|
974 | for (i = mTextureUnitStates.begin(); i != iend; ++i) |
---|
975 | { |
---|
976 | (*i)->_load(); |
---|
977 | } |
---|
978 | |
---|
979 | // Load programs |
---|
980 | if (mVertexProgramUsage) |
---|
981 | { |
---|
982 | // Load vertex program |
---|
983 | mVertexProgramUsage->_load(); |
---|
984 | } |
---|
985 | if (mShadowCasterVertexProgramUsage) |
---|
986 | { |
---|
987 | // Load vertex program |
---|
988 | mShadowCasterVertexProgramUsage->_load(); |
---|
989 | } |
---|
990 | if (mShadowReceiverVertexProgramUsage) |
---|
991 | { |
---|
992 | // Load vertex program |
---|
993 | mShadowReceiverVertexProgramUsage->_load(); |
---|
994 | } |
---|
995 | |
---|
996 | if (mFragmentProgramUsage) |
---|
997 | { |
---|
998 | // Load fragment program |
---|
999 | mFragmentProgramUsage->_load(); |
---|
1000 | } |
---|
1001 | if (mShadowReceiverFragmentProgramUsage) |
---|
1002 | { |
---|
1003 | // Load Fragment program |
---|
1004 | mShadowReceiverFragmentProgramUsage->_load(); |
---|
1005 | } |
---|
1006 | |
---|
1007 | } |
---|
1008 | //----------------------------------------------------------------------- |
---|
1009 | void Pass::_unload(void) |
---|
1010 | { |
---|
1011 | // Unload each TextureUnitState |
---|
1012 | TextureUnitStates::iterator i, iend; |
---|
1013 | iend = mTextureUnitStates.end(); |
---|
1014 | for (i = mTextureUnitStates.begin(); i != iend; ++i) |
---|
1015 | { |
---|
1016 | (*i)->_unload(); |
---|
1017 | } |
---|
1018 | |
---|
1019 | // Unload programs |
---|
1020 | if (mVertexProgramUsage) |
---|
1021 | { |
---|
1022 | // TODO |
---|
1023 | } |
---|
1024 | if (mFragmentProgramUsage) |
---|
1025 | { |
---|
1026 | // TODO |
---|
1027 | } |
---|
1028 | } |
---|
1029 | //----------------------------------------------------------------------- |
---|
1030 | void Pass::setVertexProgram(const String& name, bool resetParams) |
---|
1031 | { |
---|
1032 | // Turn off vertex program if name blank |
---|
1033 | if (name.empty()) |
---|
1034 | { |
---|
1035 | if (mVertexProgramUsage) delete mVertexProgramUsage; |
---|
1036 | mVertexProgramUsage = NULL; |
---|
1037 | } |
---|
1038 | else |
---|
1039 | { |
---|
1040 | if (!mVertexProgramUsage) |
---|
1041 | { |
---|
1042 | mVertexProgramUsage = new GpuProgramUsage(GPT_VERTEX_PROGRAM); |
---|
1043 | } |
---|
1044 | mVertexProgramUsage->setProgramName(name, resetParams); |
---|
1045 | } |
---|
1046 | // Needs recompilation |
---|
1047 | mParent->_notifyNeedsRecompile(); |
---|
1048 | } |
---|
1049 | //----------------------------------------------------------------------- |
---|
1050 | void Pass::setVertexProgramParameters(GpuProgramParametersSharedPtr params) |
---|
1051 | { |
---|
1052 | if (!mVertexProgramUsage) |
---|
1053 | { |
---|
1054 | OGRE_EXCEPT (Exception::ERR_INVALIDPARAMS, |
---|
1055 | "This pass does not have a vertex program assigned!", |
---|
1056 | "Pass::setVertexProgramParameters"); |
---|
1057 | } |
---|
1058 | mVertexProgramUsage->setParameters(params); |
---|
1059 | } |
---|
1060 | //----------------------------------------------------------------------- |
---|
1061 | void Pass::setFragmentProgram(const String& name, bool resetParams) |
---|
1062 | { |
---|
1063 | // Turn off fragment program if name blank |
---|
1064 | if (name.empty()) |
---|
1065 | { |
---|
1066 | if (mFragmentProgramUsage) delete mFragmentProgramUsage; |
---|
1067 | mFragmentProgramUsage = NULL; |
---|
1068 | } |
---|
1069 | else |
---|
1070 | { |
---|
1071 | if (!mFragmentProgramUsage) |
---|
1072 | { |
---|
1073 | mFragmentProgramUsage = new GpuProgramUsage(GPT_FRAGMENT_PROGRAM); |
---|
1074 | } |
---|
1075 | mFragmentProgramUsage->setProgramName(name, resetParams); |
---|
1076 | } |
---|
1077 | // Needs recompilation |
---|
1078 | mParent->_notifyNeedsRecompile(); |
---|
1079 | } |
---|
1080 | //----------------------------------------------------------------------- |
---|
1081 | void Pass::setFragmentProgramParameters(GpuProgramParametersSharedPtr params) |
---|
1082 | { |
---|
1083 | if (!mFragmentProgramUsage) |
---|
1084 | { |
---|
1085 | OGRE_EXCEPT (Exception::ERR_INVALIDPARAMS, |
---|
1086 | "This pass does not have a fragment program assigned!", |
---|
1087 | "Pass::setFragmentProgramParameters"); |
---|
1088 | } |
---|
1089 | mFragmentProgramUsage->setParameters(params); |
---|
1090 | } |
---|
1091 | //----------------------------------------------------------------------- |
---|
1092 | const String& Pass::getVertexProgramName(void) const |
---|
1093 | { |
---|
1094 | if (!mVertexProgramUsage) |
---|
1095 | return StringUtil::BLANK; |
---|
1096 | else |
---|
1097 | return mVertexProgramUsage->getProgramName(); |
---|
1098 | } |
---|
1099 | //----------------------------------------------------------------------- |
---|
1100 | GpuProgramParametersSharedPtr Pass::getVertexProgramParameters(void) const |
---|
1101 | { |
---|
1102 | if (!mVertexProgramUsage) |
---|
1103 | { |
---|
1104 | OGRE_EXCEPT (Exception::ERR_INVALIDPARAMS, |
---|
1105 | "This pass does not have a vertex program assigned!", |
---|
1106 | "Pass::getVertexProgramParameters"); |
---|
1107 | } |
---|
1108 | return mVertexProgramUsage->getParameters(); |
---|
1109 | } |
---|
1110 | //----------------------------------------------------------------------- |
---|
1111 | const GpuProgramPtr& Pass::getVertexProgram(void) const |
---|
1112 | { |
---|
1113 | return mVertexProgramUsage->getProgram(); |
---|
1114 | } |
---|
1115 | //----------------------------------------------------------------------- |
---|
1116 | const String& Pass::getFragmentProgramName(void) const |
---|
1117 | { |
---|
1118 | if (!mFragmentProgramUsage) |
---|
1119 | return StringUtil::BLANK; |
---|
1120 | else |
---|
1121 | return mFragmentProgramUsage->getProgramName(); |
---|
1122 | } |
---|
1123 | //----------------------------------------------------------------------- |
---|
1124 | GpuProgramParametersSharedPtr Pass::getFragmentProgramParameters(void) const |
---|
1125 | { |
---|
1126 | return mFragmentProgramUsage->getParameters(); |
---|
1127 | } |
---|
1128 | //----------------------------------------------------------------------- |
---|
1129 | const GpuProgramPtr& Pass::getFragmentProgram(void) const |
---|
1130 | { |
---|
1131 | return mFragmentProgramUsage->getProgram(); |
---|
1132 | } |
---|
1133 | //----------------------------------------------------------------------- |
---|
1134 | bool Pass::isLoaded(void) const |
---|
1135 | { |
---|
1136 | return mParent->isLoaded(); |
---|
1137 | } |
---|
1138 | //----------------------------------------------------------------------- |
---|
1139 | void Pass::_recalculateHash(void) |
---|
1140 | { |
---|
1141 | /* Hash format is 32-bit, divided as follows (high to low bits) |
---|
1142 | bits purpose |
---|
1143 | 4 Pass index (i.e. max 16 passes!) |
---|
1144 | 14 Hashed texture name from unit 0 |
---|
1145 | 14 Hashed texture name from unit 1 |
---|
1146 | |
---|
1147 | Note that at the moment we don't sort on the 3rd texture unit plus |
---|
1148 | on the assumption that these are less frequently used; sorting on |
---|
1149 | the first 2 gives us the most benefit for now. |
---|
1150 | */ |
---|
1151 | mHash = (*msHashFunc)(this); |
---|
1152 | } |
---|
1153 | //----------------------------------------------------------------------- |
---|
1154 | void Pass::_dirtyHash(void) |
---|
1155 | { |
---|
1156 | OGRE_LOCK_MUTEX(msDirtyHashListMutex) |
---|
1157 | // Mark this hash as for follow up |
---|
1158 | msDirtyHashList.insert(this); |
---|
1159 | } |
---|
1160 | //--------------------------------------------------------------------- |
---|
1161 | void Pass::clearDirtyHashList(void) |
---|
1162 | { |
---|
1163 | OGRE_LOCK_MUTEX(msDirtyHashListMutex) |
---|
1164 | msDirtyHashList.clear(); |
---|
1165 | } |
---|
1166 | //----------------------------------------------------------------------- |
---|
1167 | void Pass::_notifyNeedsRecompile(void) |
---|
1168 | { |
---|
1169 | mParent->_notifyNeedsRecompile(); |
---|
1170 | } |
---|
1171 | //----------------------------------------------------------------------- |
---|
1172 | void Pass::setTextureFiltering(TextureFilterOptions filterType) |
---|
1173 | { |
---|
1174 | TextureUnitStates::iterator i, iend; |
---|
1175 | iend = mTextureUnitStates.end(); |
---|
1176 | for (i = mTextureUnitStates.begin(); i != iend; ++i) |
---|
1177 | { |
---|
1178 | (*i)->setTextureFiltering(filterType); |
---|
1179 | } |
---|
1180 | } |
---|
1181 | // -------------------------------------------------------------------- |
---|
1182 | void Pass::setTextureAnisotropy(unsigned int maxAniso) |
---|
1183 | { |
---|
1184 | TextureUnitStates::iterator i, iend; |
---|
1185 | iend = mTextureUnitStates.end(); |
---|
1186 | for (i = mTextureUnitStates.begin(); i != iend; ++i) |
---|
1187 | { |
---|
1188 | (*i)->setTextureAnisotropy(maxAniso); |
---|
1189 | } |
---|
1190 | } |
---|
1191 | //----------------------------------------------------------------------- |
---|
1192 | void Pass::_updateAutoParamsNoLights(const AutoParamDataSource& source) const |
---|
1193 | { |
---|
1194 | if (hasVertexProgram()) |
---|
1195 | { |
---|
1196 | // Update vertex program auto params |
---|
1197 | mVertexProgramUsage->getParameters()->_updateAutoParamsNoLights(source); |
---|
1198 | } |
---|
1199 | |
---|
1200 | if (hasFragmentProgram()) |
---|
1201 | { |
---|
1202 | // Update fragment program auto params |
---|
1203 | mFragmentProgramUsage->getParameters()->_updateAutoParamsNoLights(source); |
---|
1204 | } |
---|
1205 | } |
---|
1206 | //----------------------------------------------------------------------- |
---|
1207 | void Pass::_updateAutoParamsLightsOnly(const AutoParamDataSource& source) const |
---|
1208 | { |
---|
1209 | if (hasVertexProgram()) |
---|
1210 | { |
---|
1211 | // Update vertex program auto params |
---|
1212 | mVertexProgramUsage->getParameters()->_updateAutoParamsLightsOnly(source); |
---|
1213 | } |
---|
1214 | |
---|
1215 | if (hasFragmentProgram()) |
---|
1216 | { |
---|
1217 | // Update fragment program auto params |
---|
1218 | mFragmentProgramUsage->getParameters()->_updateAutoParamsLightsOnly(source); |
---|
1219 | } |
---|
1220 | } |
---|
1221 | //----------------------------------------------------------------------- |
---|
1222 | void Pass::processPendingPassUpdates(void) |
---|
1223 | { |
---|
1224 | { |
---|
1225 | OGRE_LOCK_MUTEX(msPassGraveyardMutex) |
---|
1226 | // Delete items in the graveyard |
---|
1227 | PassSet::iterator i, iend; |
---|
1228 | iend = msPassGraveyard.end(); |
---|
1229 | for (i = msPassGraveyard.begin(); i != iend; ++i) |
---|
1230 | { |
---|
1231 | delete *i; |
---|
1232 | } |
---|
1233 | msPassGraveyard.clear(); |
---|
1234 | } |
---|
1235 | |
---|
1236 | { |
---|
1237 | OGRE_LOCK_MUTEX(msDirtyHashListMutex) |
---|
1238 | PassSet::iterator i, iend; |
---|
1239 | // The dirty ones will have been removed from the groups above using the old hash now |
---|
1240 | iend = msDirtyHashList.end(); |
---|
1241 | for (i = msDirtyHashList.begin(); i != iend; ++i) |
---|
1242 | { |
---|
1243 | Pass* p = *i; |
---|
1244 | p->_recalculateHash(); |
---|
1245 | } |
---|
1246 | // Clear the dirty list |
---|
1247 | msDirtyHashList.clear(); |
---|
1248 | } |
---|
1249 | } |
---|
1250 | //----------------------------------------------------------------------- |
---|
1251 | void Pass::queueForDeletion(void) |
---|
1252 | { |
---|
1253 | mQueuedForDeletion = true; |
---|
1254 | |
---|
1255 | removeAllTextureUnitStates(); |
---|
1256 | if (mVertexProgramUsage) |
---|
1257 | { |
---|
1258 | delete mVertexProgramUsage; |
---|
1259 | mVertexProgramUsage = 0; |
---|
1260 | } |
---|
1261 | if (mShadowCasterVertexProgramUsage) |
---|
1262 | { |
---|
1263 | delete mShadowCasterVertexProgramUsage; |
---|
1264 | mShadowCasterVertexProgramUsage = 0; |
---|
1265 | } |
---|
1266 | if (mShadowReceiverVertexProgramUsage) |
---|
1267 | { |
---|
1268 | delete mShadowReceiverVertexProgramUsage; |
---|
1269 | mShadowReceiverVertexProgramUsage = 0; |
---|
1270 | } |
---|
1271 | if (mFragmentProgramUsage) |
---|
1272 | { |
---|
1273 | delete mFragmentProgramUsage; |
---|
1274 | mFragmentProgramUsage = 0; |
---|
1275 | } |
---|
1276 | if (mShadowReceiverFragmentProgramUsage) |
---|
1277 | { |
---|
1278 | delete mShadowReceiverFragmentProgramUsage; |
---|
1279 | mShadowReceiverFragmentProgramUsage = 0; |
---|
1280 | } |
---|
1281 | // remove from dirty list, if there |
---|
1282 | { |
---|
1283 | OGRE_LOCK_MUTEX(msDirtyHashListMutex) |
---|
1284 | msDirtyHashList.erase(this); |
---|
1285 | } |
---|
1286 | { |
---|
1287 | OGRE_LOCK_MUTEX(msPassGraveyardMutex) |
---|
1288 | msPassGraveyard.insert(this); |
---|
1289 | } |
---|
1290 | } |
---|
1291 | //----------------------------------------------------------------------- |
---|
1292 | bool Pass::isAmbientOnly(void) const |
---|
1293 | { |
---|
1294 | // treat as ambient if lighting is off, or colour write is off, |
---|
1295 | // or all non-ambient (& emissive) colours are black |
---|
1296 | // NB a vertex program could override this, but passes using vertex |
---|
1297 | // programs are expected to indicate they are ambient only by |
---|
1298 | // setting the state so it matches one of the conditions above, even |
---|
1299 | // though this state is not used in rendering. |
---|
1300 | return (!mLightingEnabled || !mColourWrite || |
---|
1301 | (mDiffuse == ColourValue::Black && |
---|
1302 | mSpecular == ColourValue::Black)); |
---|
1303 | } |
---|
1304 | //----------------------------------------------------------------------- |
---|
1305 | void Pass::setShadowCasterVertexProgram(const String& name) |
---|
1306 | { |
---|
1307 | // Turn off vertex program if name blank |
---|
1308 | if (name.empty()) |
---|
1309 | { |
---|
1310 | if (mShadowCasterVertexProgramUsage) delete mShadowCasterVertexProgramUsage; |
---|
1311 | mShadowCasterVertexProgramUsage = NULL; |
---|
1312 | } |
---|
1313 | else |
---|
1314 | { |
---|
1315 | if (!mShadowCasterVertexProgramUsage) |
---|
1316 | { |
---|
1317 | mShadowCasterVertexProgramUsage = new GpuProgramUsage(GPT_VERTEX_PROGRAM); |
---|
1318 | } |
---|
1319 | mShadowCasterVertexProgramUsage->setProgramName(name); |
---|
1320 | } |
---|
1321 | // Needs recompilation |
---|
1322 | mParent->_notifyNeedsRecompile(); |
---|
1323 | } |
---|
1324 | //----------------------------------------------------------------------- |
---|
1325 | void Pass::setShadowCasterVertexProgramParameters(GpuProgramParametersSharedPtr params) |
---|
1326 | { |
---|
1327 | if (!mShadowCasterVertexProgramUsage) |
---|
1328 | { |
---|
1329 | OGRE_EXCEPT (Exception::ERR_INVALIDPARAMS, |
---|
1330 | "This pass does not have a shadow caster vertex program assigned!", |
---|
1331 | "Pass::setShadowCasterVertexProgramParameters"); |
---|
1332 | } |
---|
1333 | mShadowCasterVertexProgramUsage->setParameters(params); |
---|
1334 | } |
---|
1335 | //----------------------------------------------------------------------- |
---|
1336 | const String& Pass::getShadowCasterVertexProgramName(void) const |
---|
1337 | { |
---|
1338 | if (!mShadowCasterVertexProgramUsage) |
---|
1339 | return StringUtil::BLANK; |
---|
1340 | else |
---|
1341 | return mShadowCasterVertexProgramUsage->getProgramName(); |
---|
1342 | } |
---|
1343 | //----------------------------------------------------------------------- |
---|
1344 | GpuProgramParametersSharedPtr Pass::getShadowCasterVertexProgramParameters(void) const |
---|
1345 | { |
---|
1346 | if (!mShadowCasterVertexProgramUsage) |
---|
1347 | { |
---|
1348 | OGRE_EXCEPT (Exception::ERR_INVALIDPARAMS, |
---|
1349 | "This pass does not have a shadow caster vertex program assigned!", |
---|
1350 | "Pass::getShadowCasterVertexProgramParameters"); |
---|
1351 | } |
---|
1352 | return mShadowCasterVertexProgramUsage->getParameters(); |
---|
1353 | } |
---|
1354 | //----------------------------------------------------------------------- |
---|
1355 | const GpuProgramPtr& Pass::getShadowCasterVertexProgram(void) const |
---|
1356 | { |
---|
1357 | return mShadowCasterVertexProgramUsage->getProgram(); |
---|
1358 | } |
---|
1359 | //----------------------------------------------------------------------- |
---|
1360 | void Pass::setShadowReceiverVertexProgram(const String& name) |
---|
1361 | { |
---|
1362 | // Turn off vertex program if name blank |
---|
1363 | if (name.empty()) |
---|
1364 | { |
---|
1365 | if (mShadowReceiverVertexProgramUsage) delete mShadowReceiverVertexProgramUsage; |
---|
1366 | mShadowReceiverVertexProgramUsage = NULL; |
---|
1367 | } |
---|
1368 | else |
---|
1369 | { |
---|
1370 | if (!mShadowReceiverVertexProgramUsage) |
---|
1371 | { |
---|
1372 | mShadowReceiverVertexProgramUsage = new GpuProgramUsage(GPT_VERTEX_PROGRAM); |
---|
1373 | } |
---|
1374 | mShadowReceiverVertexProgramUsage->setProgramName(name); |
---|
1375 | } |
---|
1376 | // Needs recompilation |
---|
1377 | mParent->_notifyNeedsRecompile(); |
---|
1378 | } |
---|
1379 | //----------------------------------------------------------------------- |
---|
1380 | void Pass::setShadowReceiverVertexProgramParameters(GpuProgramParametersSharedPtr params) |
---|
1381 | { |
---|
1382 | if (!mShadowReceiverVertexProgramUsage) |
---|
1383 | { |
---|
1384 | OGRE_EXCEPT (Exception::ERR_INVALIDPARAMS, |
---|
1385 | "This pass does not have a shadow receiver vertex program assigned!", |
---|
1386 | "Pass::setShadowReceiverVertexProgramParameters"); |
---|
1387 | } |
---|
1388 | mShadowReceiverVertexProgramUsage->setParameters(params); |
---|
1389 | } |
---|
1390 | //----------------------------------------------------------------------- |
---|
1391 | const String& Pass::getShadowReceiverVertexProgramName(void) const |
---|
1392 | { |
---|
1393 | if (!mShadowReceiverVertexProgramUsage) |
---|
1394 | return StringUtil::BLANK; |
---|
1395 | else |
---|
1396 | return mShadowReceiverVertexProgramUsage->getProgramName(); |
---|
1397 | } |
---|
1398 | //----------------------------------------------------------------------- |
---|
1399 | GpuProgramParametersSharedPtr Pass::getShadowReceiverVertexProgramParameters(void) const |
---|
1400 | { |
---|
1401 | if (!mShadowReceiverVertexProgramUsage) |
---|
1402 | { |
---|
1403 | OGRE_EXCEPT (Exception::ERR_INVALIDPARAMS, |
---|
1404 | "This pass does not have a shadow receiver vertex program assigned!", |
---|
1405 | "Pass::getShadowReceiverVertexProgramParameters"); |
---|
1406 | } |
---|
1407 | return mShadowReceiverVertexProgramUsage->getParameters(); |
---|
1408 | } |
---|
1409 | //----------------------------------------------------------------------- |
---|
1410 | const GpuProgramPtr& Pass::getShadowReceiverVertexProgram(void) const |
---|
1411 | { |
---|
1412 | return mShadowReceiverVertexProgramUsage->getProgram(); |
---|
1413 | } |
---|
1414 | //----------------------------------------------------------------------- |
---|
1415 | void Pass::setShadowReceiverFragmentProgram(const String& name) |
---|
1416 | { |
---|
1417 | // Turn off Fragment program if name blank |
---|
1418 | if (name.empty()) |
---|
1419 | { |
---|
1420 | if (mShadowReceiverFragmentProgramUsage) delete mShadowReceiverFragmentProgramUsage; |
---|
1421 | mShadowReceiverFragmentProgramUsage = NULL; |
---|
1422 | } |
---|
1423 | else |
---|
1424 | { |
---|
1425 | if (!mShadowReceiverFragmentProgramUsage) |
---|
1426 | { |
---|
1427 | mShadowReceiverFragmentProgramUsage = new GpuProgramUsage(GPT_FRAGMENT_PROGRAM); |
---|
1428 | } |
---|
1429 | mShadowReceiverFragmentProgramUsage->setProgramName(name); |
---|
1430 | } |
---|
1431 | // Needs recompilation |
---|
1432 | mParent->_notifyNeedsRecompile(); |
---|
1433 | } |
---|
1434 | //----------------------------------------------------------------------- |
---|
1435 | void Pass::setShadowReceiverFragmentProgramParameters(GpuProgramParametersSharedPtr params) |
---|
1436 | { |
---|
1437 | if (!mShadowReceiverFragmentProgramUsage) |
---|
1438 | { |
---|
1439 | OGRE_EXCEPT (Exception::ERR_INVALIDPARAMS, |
---|
1440 | "This pass does not have a shadow receiver fragment program assigned!", |
---|
1441 | "Pass::setShadowReceiverFragmentProgramParameters"); |
---|
1442 | } |
---|
1443 | mShadowReceiverFragmentProgramUsage->setParameters(params); |
---|
1444 | } |
---|
1445 | //----------------------------------------------------------------------- |
---|
1446 | const String& Pass::getShadowReceiverFragmentProgramName(void) const |
---|
1447 | { |
---|
1448 | if (!mShadowReceiverFragmentProgramUsage) |
---|
1449 | return StringUtil::BLANK; |
---|
1450 | else |
---|
1451 | return mShadowReceiverFragmentProgramUsage->getProgramName(); |
---|
1452 | } |
---|
1453 | //----------------------------------------------------------------------- |
---|
1454 | GpuProgramParametersSharedPtr Pass::getShadowReceiverFragmentProgramParameters(void) const |
---|
1455 | { |
---|
1456 | if (!mShadowReceiverFragmentProgramUsage) |
---|
1457 | { |
---|
1458 | OGRE_EXCEPT (Exception::ERR_INVALIDPARAMS, |
---|
1459 | "This pass does not have a shadow receiver fragment program assigned!", |
---|
1460 | "Pass::getShadowReceiverFragmentProgramParameters"); |
---|
1461 | } |
---|
1462 | return mShadowReceiverFragmentProgramUsage->getParameters(); |
---|
1463 | } |
---|
1464 | //----------------------------------------------------------------------- |
---|
1465 | const GpuProgramPtr& Pass::getShadowReceiverFragmentProgram(void) const |
---|
1466 | { |
---|
1467 | return mShadowReceiverFragmentProgramUsage->getProgram(); |
---|
1468 | } |
---|
1469 | //----------------------------------------------------------------------- |
---|
1470 | const String& Pass::getResourceGroup(void) const |
---|
1471 | { |
---|
1472 | return mParent->getResourceGroup(); |
---|
1473 | } |
---|
1474 | |
---|
1475 | //----------------------------------------------------------------------- |
---|
1476 | bool Pass::applyTextureAliases(const AliasTextureNamePairList& aliasList, const bool apply) const |
---|
1477 | { |
---|
1478 | // iterate through each texture unit state and apply the texture alias if it applies |
---|
1479 | TextureUnitStates::const_iterator i, iend; |
---|
1480 | iend = mTextureUnitStates.end(); |
---|
1481 | bool testResult = false; |
---|
1482 | |
---|
1483 | for (i = mTextureUnitStates.begin(); i != iend; ++i) |
---|
1484 | { |
---|
1485 | if ((*i)->applyTextureAliases(aliasList, apply)) |
---|
1486 | testResult = true; |
---|
1487 | } |
---|
1488 | |
---|
1489 | return testResult; |
---|
1490 | |
---|
1491 | } |
---|
1492 | //----------------------------------------------------------------------- |
---|
1493 | unsigned short Pass::_getTextureUnitWithContentTypeIndex( |
---|
1494 | TextureUnitState::ContentType contentType, unsigned short index) const |
---|
1495 | { |
---|
1496 | if (!mContentTypeLookupBuilt) |
---|
1497 | { |
---|
1498 | mShadowContentTypeLookup.clear(); |
---|
1499 | for (unsigned short i = 0; i < mTextureUnitStates.size(); ++i) |
---|
1500 | { |
---|
1501 | if (mTextureUnitStates[i]->getContentType() == TextureUnitState::CONTENT_SHADOW) |
---|
1502 | { |
---|
1503 | mShadowContentTypeLookup.push_back(i); |
---|
1504 | } |
---|
1505 | } |
---|
1506 | mContentTypeLookupBuilt = true; |
---|
1507 | } |
---|
1508 | |
---|
1509 | switch(contentType) |
---|
1510 | { |
---|
1511 | case TextureUnitState::CONTENT_SHADOW: |
---|
1512 | if (index < mShadowContentTypeLookup.size()) |
---|
1513 | { |
---|
1514 | return mShadowContentTypeLookup[index]; |
---|
1515 | } |
---|
1516 | break; |
---|
1517 | default: |
---|
1518 | // Simple iteration |
---|
1519 | for (unsigned short i = 0; i < mTextureUnitStates.size(); ++i) |
---|
1520 | { |
---|
1521 | if (mTextureUnitStates[i]->getContentType() == TextureUnitState::CONTENT_SHADOW) |
---|
1522 | { |
---|
1523 | if (index == 0) |
---|
1524 | { |
---|
1525 | return i; |
---|
1526 | } |
---|
1527 | else |
---|
1528 | { |
---|
1529 | --index; |
---|
1530 | } |
---|
1531 | } |
---|
1532 | } |
---|
1533 | break; |
---|
1534 | } |
---|
1535 | |
---|
1536 | // not found - return out of range |
---|
1537 | return static_cast<unsigned short>(mTextureUnitStates.size() + 1); |
---|
1538 | |
---|
1539 | } |
---|
1540 | |
---|
1541 | |
---|
1542 | } |
---|