/src/ogre/OgreMain/src/OgreTechnique.cpp
Line | Count | Source |
1 | | /* |
2 | | ----------------------------------------------------------------------------- |
3 | | This source file is part of OGRE |
4 | | (Object-oriented Graphics Rendering Engine) |
5 | | For the latest info, see http://www.ogre3d.org/ |
6 | | |
7 | | Copyright (c) 2000-2014 Torus Knot Software Ltd |
8 | | |
9 | | Permission is hereby granted, free of charge, to any person obtaining a copy |
10 | | of this software and associated documentation files (the "Software"), to deal |
11 | | in the Software without restriction, including without limitation the rights |
12 | | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
13 | | copies of the Software, and to permit persons to whom the Software is |
14 | | furnished to do so, subject to the following conditions: |
15 | | |
16 | | The above copyright notice and this permission notice shall be included in |
17 | | all copies or substantial portions of the Software. |
18 | | |
19 | | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
20 | | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
21 | | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
22 | | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
23 | | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
24 | | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
25 | | THE SOFTWARE. |
26 | | ----------------------------------------------------------------------------- |
27 | | */ |
28 | | #include "OgreStableHeaders.h" |
29 | | #include "OgreMaterial.h" |
30 | | |
31 | | |
32 | | namespace Ogre { |
33 | | //----------------------------------------------------------------------------- |
34 | | Technique::Technique(Material* parent) |
35 | 3 | : mParent(parent), mIlluminationPassesCompilationPhase(IPS_NOT_COMPILED), mIsSupported(false), mLodIndex(0), mSchemeIndex(0) |
36 | 3 | { |
37 | | // See above, defaults to unsupported until examined |
38 | 3 | } |
39 | | //----------------------------------------------------------------------------- |
40 | | Technique::Technique(Material* parent, const Technique& oth) |
41 | 0 | : mParent(parent), mLodIndex(0), mSchemeIndex(0) |
42 | 0 | { |
43 | | // Copy using operator= |
44 | 0 | *this = oth; |
45 | 0 | } |
46 | | //----------------------------------------------------------------------------- |
47 | | Technique::~Technique() |
48 | 0 | { |
49 | 0 | removeAllPasses(); |
50 | 0 | clearIlluminationPasses(); |
51 | 0 | } |
52 | | //----------------------------------------------------------------------------- |
53 | | bool Technique::isSupported(void) const |
54 | 2 | { |
55 | 2 | return mIsSupported; |
56 | 2 | } |
57 | | //----------------------------------------------------------------------------- |
58 | | size_t Technique::calculateSize(void) const |
59 | 0 | { |
60 | 0 | size_t memSize = 0; |
61 | | |
62 | | // Tally up passes |
63 | 0 | for (auto *p : mPasses) |
64 | 0 | { |
65 | 0 | memSize += p->calculateSize(); |
66 | 0 | } |
67 | 0 | return memSize; |
68 | 0 | } |
69 | | //----------------------------------------------------------------------------- |
70 | | String Technique::_compile(bool autoManageTextureUnits) |
71 | 0 | { |
72 | 0 | StringStream errors; |
73 | |
|
74 | 0 | mIsSupported = checkGPURules(errors) && checkHardwareSupport(autoManageTextureUnits, errors); |
75 | | |
76 | | // Compile for categorised illumination on demand |
77 | 0 | clearIlluminationPasses(); |
78 | 0 | mIlluminationPassesCompilationPhase = IPS_NOT_COMPILED; |
79 | |
|
80 | 0 | return errors.str(); |
81 | |
|
82 | 0 | } |
83 | | //--------------------------------------------------------------------- |
84 | | bool Technique::checkHardwareSupport(bool autoManageTextureUnits, StringStream& compileErrors) |
85 | 0 | { |
86 | | // Go through each pass, checking requirements |
87 | 0 | Passes::iterator i; |
88 | 0 | unsigned short passNum = 0; |
89 | 0 | const RenderSystemCapabilities* caps = nullptr; |
90 | 0 | if (auto rs = Root::getSingleton().getRenderSystem()) |
91 | 0 | caps = rs->getCapabilities(); |
92 | 0 | else |
93 | 0 | { |
94 | 0 | static RenderSystemCapabilities nullCaps; |
95 | 0 | caps = &nullCaps; |
96 | 0 | } |
97 | |
|
98 | 0 | unsigned short numTexUnits = caps->getNumTextureUnits(); |
99 | 0 | for (i = mPasses.begin(); i != mPasses.end(); ++i, ++passNum) |
100 | 0 | { |
101 | 0 | Pass* currPass = *i; |
102 | | // Adjust pass index |
103 | 0 | currPass->_notifyIndex(passNum); |
104 | |
|
105 | 0 | const char* err = 0; |
106 | |
|
107 | 0 | if(currPass->getLineWidth() != 1 && !caps->hasCapability(RSC_WIDE_LINES)) |
108 | 0 | err = "line_width > 1"; |
109 | 0 | else if(currPass->getPointSize() != 1 && !caps->hasCapability(RSC_POINT_SPRITES)) |
110 | 0 | err = "point_size > 1"; |
111 | |
|
112 | 0 | if(err) |
113 | 0 | { |
114 | 0 | compileErrors << "Pass " << passNum << ": " << err << " not supported by RenderSystem"; |
115 | 0 | return false; |
116 | 0 | } |
117 | | |
118 | | // Check a few fixed-function options in texture layers |
119 | 0 | size_t texUnit = 0; |
120 | 0 | for(const TextureUnitState* tex : currPass->getTextureUnitStates()) |
121 | 0 | { |
122 | 0 | if ((tex->getTextureType() == TEX_TYPE_3D) && !caps->hasCapability(RSC_TEXTURE_3D)) |
123 | 0 | err = "Volume"; |
124 | |
|
125 | 0 | if ((tex->getTextureType() == TEX_TYPE_2D_ARRAY) && !caps->hasCapability(RSC_TEXTURE_2D_ARRAY)) |
126 | 0 | err = "Array"; |
127 | |
|
128 | 0 | if (err) |
129 | 0 | { |
130 | | // Fail |
131 | 0 | compileErrors << "Pass " << passNum << " Tex " << texUnit << ": " << err |
132 | 0 | << " textures not supported by RenderSystem"; |
133 | 0 | return false; |
134 | 0 | } |
135 | 0 | ++texUnit; |
136 | 0 | } |
137 | | |
138 | | // Check texture unit requirements |
139 | 0 | size_t numTexUnitsRequested = currPass->getNumTextureUnitStates(); |
140 | | // Don't trust getNumTextureUnits for programmable |
141 | 0 | if(!currPass->hasFragmentProgram()) |
142 | 0 | { |
143 | | #if defined(OGRE_PRETEND_TEXTURE_UNITS) && OGRE_PRETEND_TEXTURE_UNITS > 0 |
144 | | numTexUnits = std::min(numTexUnits, OGRE_PRETEND_TEXTURE_UNITS); |
145 | | #endif |
146 | 0 | if (numTexUnitsRequested > numTexUnits) |
147 | 0 | { |
148 | 0 | if (!autoManageTextureUnits) |
149 | 0 | { |
150 | | // The user disabled auto pass split |
151 | 0 | compileErrors << "Pass " << passNum << |
152 | 0 | ": Too many texture units for the current hardware and no splitting allowed"; |
153 | 0 | return false; |
154 | 0 | } |
155 | 0 | else if (currPass->hasVertexProgram()) |
156 | 0 | { |
157 | | // Can't do this one, and can't split a programmable pass |
158 | 0 | compileErrors << "Pass " << passNum << |
159 | 0 | ": Too many texture units for the current hardware and " |
160 | 0 | "cannot split programmable passes"; |
161 | 0 | return false; |
162 | 0 | } |
163 | 0 | } |
164 | | |
165 | | // We're ok on operations, now we need to check # texture units |
166 | | |
167 | | // Keep splitting this pass so long as units requested > gpu units |
168 | 0 | while (numTexUnitsRequested > numTexUnits) |
169 | 0 | { |
170 | | // chop this pass into many passes |
171 | 0 | currPass = currPass->_split(numTexUnits); |
172 | 0 | numTexUnitsRequested = currPass->getNumTextureUnitStates(); |
173 | | // Advance pass number |
174 | 0 | ++passNum; |
175 | | // Reset iterator |
176 | 0 | i = mPasses.begin() + passNum; |
177 | | // Move the new pass to the right place (will have been created |
178 | | // at the end, may be other passes in between) |
179 | 0 | assert(mPasses.back() == currPass); |
180 | 0 | std::copy_backward(i, (mPasses.end() - 1), mPasses.end()); |
181 | 0 | *i = currPass; |
182 | | // Adjust pass index |
183 | 0 | currPass->_notifyIndex(passNum); |
184 | 0 | } |
185 | 0 | } |
186 | | |
187 | | // try to catch user missing a program early on |
188 | 0 | if (!caps->hasCapability(RSC_FIXED_FUNCTION) && currPass->isProgrammable() && |
189 | 0 | !currPass->hasGpuProgram(GPT_COMPUTE_PROGRAM)) |
190 | 0 | { |
191 | 0 | if ((!currPass->hasVertexProgram() && !currPass->hasGpuProgram(GPT_MESH_PROGRAM)) || |
192 | 0 | (!currPass->hasFragmentProgram() && !currPass->hasGeometryProgram())) |
193 | 0 | { |
194 | 0 | compileErrors << "Pass " << passNum << ": RenderSystem requires both vertex and fragment programs"; |
195 | 0 | return false; |
196 | 0 | } |
197 | 0 | } |
198 | | |
199 | | //Check compilation errors for all program types. |
200 | 0 | for (int t = 0; t < GPT_COUNT; t++) |
201 | 0 | { |
202 | 0 | GpuProgramType programType = GpuProgramType(t); |
203 | 0 | if (currPass->hasGpuProgram(programType)) |
204 | 0 | { |
205 | 0 | GpuProgramPtr program = currPass->getGpuProgram(programType); |
206 | 0 | if (!program->isSupported()) |
207 | 0 | { |
208 | 0 | compileErrors << "Pass " << passNum << |
209 | 0 | ": " << GpuProgram::getProgramTypeName(programType) + " program " << program->getName() |
210 | 0 | << " cannot be used - "; |
211 | 0 | if (program->hasCompileError() && program->getSource().empty()) |
212 | 0 | compileErrors << "resource not found"; |
213 | 0 | else if (program->hasCompileError()) |
214 | 0 | compileErrors << "compile error"; |
215 | 0 | else |
216 | 0 | compileErrors << "not supported"; |
217 | |
|
218 | 0 | return false; |
219 | 0 | } |
220 | 0 | } |
221 | 0 | } |
222 | 0 | } |
223 | | // If we got this far, we're ok |
224 | 0 | return true; |
225 | 0 | } |
226 | | //--------------------------------------------------------------------- |
227 | | bool Technique::checkGPURules(StringStream& errors) |
228 | 0 | { |
229 | 0 | const RenderSystemCapabilities* caps = nullptr; |
230 | 0 | if (auto rs = Root::getSingleton().getRenderSystem()) |
231 | 0 | caps = rs->getCapabilities(); |
232 | |
|
233 | 0 | if (!caps && (!mGPUVendorRules.empty() || !mGPUDeviceNameRules.empty())) |
234 | 0 | { |
235 | 0 | errors << "GPU rules failed because the RenderSystem is NULL"; |
236 | 0 | return false; |
237 | 0 | } |
238 | | |
239 | 0 | StringStream includeRules; |
240 | 0 | bool includeRulesPresent = false; |
241 | 0 | bool includeRuleMatched = false; |
242 | | |
243 | | // Check vendors first |
244 | 0 | for (auto& r : mGPUVendorRules) |
245 | 0 | { |
246 | 0 | if (r.includeOrExclude == INCLUDE) |
247 | 0 | { |
248 | 0 | includeRulesPresent = true; |
249 | 0 | includeRules << caps->vendorToString(r.vendor) << " "; |
250 | 0 | if (r.vendor == caps->getVendor()) |
251 | 0 | includeRuleMatched = true; |
252 | 0 | } |
253 | 0 | else // EXCLUDE |
254 | 0 | { |
255 | 0 | if (r.vendor == caps->getVendor()) |
256 | 0 | { |
257 | 0 | errors << "Excluded GPU vendor: " << caps->vendorToString(r.vendor) |
258 | 0 | << std::endl; |
259 | 0 | return false; |
260 | 0 | } |
261 | |
|
262 | 0 | } |
263 | 0 | } |
264 | | |
265 | 0 | if (includeRulesPresent && !includeRuleMatched) |
266 | 0 | { |
267 | 0 | errors << "Failed to match GPU vendor: " << includeRules.str( ) |
268 | 0 | << std::endl; |
269 | 0 | return false; |
270 | 0 | } |
271 | | |
272 | | // now check device names |
273 | 0 | includeRules.str(BLANKSTRING); |
274 | 0 | includeRulesPresent = false; |
275 | 0 | includeRuleMatched = false; |
276 | |
|
277 | 0 | for (auto& r : mGPUDeviceNameRules) |
278 | 0 | { |
279 | 0 | if (r.includeOrExclude == INCLUDE) |
280 | 0 | { |
281 | 0 | includeRulesPresent = true; |
282 | 0 | includeRules << r.devicePattern << " "; |
283 | 0 | if (StringUtil::match(caps->getDeviceName(), r.devicePattern, r.caseSensitive)) |
284 | 0 | includeRuleMatched = true; |
285 | 0 | } |
286 | 0 | else // EXCLUDE |
287 | 0 | { |
288 | 0 | if (StringUtil::match(caps->getDeviceName(), r.devicePattern, r.caseSensitive)) |
289 | 0 | { |
290 | 0 | errors << "Excluded GPU device: " << r.devicePattern |
291 | 0 | << std::endl; |
292 | 0 | return false; |
293 | 0 | } |
294 | |
|
295 | 0 | } |
296 | 0 | } |
297 | | |
298 | 0 | if (includeRulesPresent && !includeRuleMatched) |
299 | 0 | { |
300 | 0 | errors << "Failed to match GPU device: " << includeRules.str( ) |
301 | 0 | << std::endl; |
302 | 0 | return false; |
303 | 0 | } |
304 | | |
305 | | // passed |
306 | 0 | return true; |
307 | 0 | } |
308 | | //----------------------------------------------------------------------------- |
309 | | Pass* Technique::createPass(void) |
310 | 1 | { |
311 | 1 | Pass* newPass = OGRE_NEW Pass(this, static_cast<unsigned short>(mPasses.size())); |
312 | 1 | mPasses.push_back(newPass); |
313 | 1 | return newPass; |
314 | 1 | } |
315 | | //----------------------------------------------------------------------------- |
316 | | Pass* Technique::getPass(const String& name) const |
317 | 0 | { |
318 | | // iterate through techniques to find a match |
319 | 0 | for (Pass *p : mPasses) { |
320 | 0 | if (p->getName() == name ) |
321 | 0 | return p; |
322 | 0 | } |
323 | | |
324 | 0 | return (Pass *)0; |
325 | 0 | } |
326 | | //----------------------------------------------------------------------------- |
327 | | void Technique::removePass(unsigned short index) |
328 | 0 | { |
329 | 0 | assert(index < mPasses.size() && "Index out of bounds"); |
330 | 0 | Passes::iterator i = mPasses.begin() + index; |
331 | 0 | (*i)->queueForDeletion(); |
332 | 0 | i = mPasses.erase(i); |
333 | | // Adjust passes index |
334 | 0 | for (; i != mPasses.end(); ++i, ++index) |
335 | 0 | { |
336 | 0 | (*i)->_notifyIndex(index); |
337 | 0 | } |
338 | 0 | } |
339 | | //----------------------------------------------------------------------------- |
340 | | void Technique::removeAllPasses(void) |
341 | 2 | { |
342 | 2 | for (auto *p : mPasses) |
343 | 0 | { |
344 | 0 | p->queueForDeletion(); |
345 | 0 | } |
346 | 2 | mPasses.clear(); |
347 | 2 | } |
348 | | |
349 | | //----------------------------------------------------------------------------- |
350 | | bool Technique::movePass(const unsigned short sourceIndex, const unsigned short destinationIndex) |
351 | 0 | { |
352 | 0 | bool moveSuccessful = false; |
353 | | |
354 | | // don't move the pass if source == destination |
355 | 0 | if (sourceIndex == destinationIndex) return true; |
356 | | |
357 | 0 | if( (sourceIndex < mPasses.size()) && (destinationIndex < mPasses.size())) |
358 | 0 | { |
359 | 0 | Passes::iterator i = mPasses.begin() + sourceIndex; |
360 | | //Passes::iterator DestinationIterator = mPasses.begin() + destinationIndex; |
361 | |
|
362 | 0 | Pass* pass = (*i); |
363 | 0 | mPasses.erase(i); |
364 | |
|
365 | 0 | i = mPasses.begin() + destinationIndex; |
366 | |
|
367 | 0 | mPasses.insert(i, pass); |
368 | | |
369 | | // Adjust passes index |
370 | 0 | unsigned short beginIndex, endIndex; |
371 | 0 | if (destinationIndex > sourceIndex) |
372 | 0 | { |
373 | 0 | beginIndex = sourceIndex; |
374 | 0 | endIndex = destinationIndex; |
375 | 0 | } |
376 | 0 | else |
377 | 0 | { |
378 | 0 | beginIndex = destinationIndex; |
379 | 0 | endIndex = sourceIndex; |
380 | 0 | } |
381 | 0 | for (unsigned short index = beginIndex; index <= endIndex; ++index) |
382 | 0 | { |
383 | 0 | mPasses[index]->_notifyIndex(index); |
384 | 0 | } |
385 | 0 | moveSuccessful = true; |
386 | 0 | } |
387 | |
|
388 | 0 | return moveSuccessful; |
389 | 0 | } |
390 | | |
391 | | //----------------------------------------------------------------------------- |
392 | | const Technique::PassIterator Technique::getPassIterator(void) |
393 | 0 | { |
394 | 0 | return PassIterator(mPasses.begin(), mPasses.end()); |
395 | 0 | } |
396 | | //----------------------------------------------------------------------------- |
397 | | Technique& Technique::operator=(const Technique& rhs) |
398 | 2 | { |
399 | 2 | if (this == &rhs) |
400 | 0 | return *this; |
401 | | |
402 | 2 | mName = rhs.mName; |
403 | 2 | this->mIsSupported = rhs.mIsSupported; |
404 | 2 | this->mLodIndex = rhs.mLodIndex; |
405 | 2 | this->mSchemeIndex = rhs.mSchemeIndex; |
406 | 2 | this->mShadowCasterMaterial = rhs.mShadowCasterMaterial; |
407 | 2 | this->mShadowCasterMaterialName = rhs.mShadowCasterMaterialName; |
408 | 2 | this->mShadowReceiverMaterial = rhs.mShadowReceiverMaterial; |
409 | 2 | this->mShadowReceiverMaterialName = rhs.mShadowReceiverMaterialName; |
410 | 2 | this->mGPUVendorRules = rhs.mGPUVendorRules; |
411 | 2 | this->mGPUDeviceNameRules = rhs.mGPUDeviceNameRules; |
412 | | |
413 | | // copy passes |
414 | 2 | removeAllPasses(); |
415 | 2 | for (auto *rp : rhs.mPasses) |
416 | 2 | { |
417 | 2 | Pass* p = OGRE_NEW Pass(this, rp->getIndex(), *(rp)); |
418 | 2 | mPasses.push_back(p); |
419 | 2 | } |
420 | | // Compile for categorised illumination on demand |
421 | 2 | clearIlluminationPasses(); |
422 | 2 | mIlluminationPassesCompilationPhase = IPS_NOT_COMPILED; |
423 | 2 | return *this; |
424 | 2 | } |
425 | | //----------------------------------------------------------------------------- |
426 | | bool Technique::isTransparent(void) const |
427 | 0 | { |
428 | 0 | if (mPasses.empty()) |
429 | 0 | { |
430 | 0 | return false; |
431 | 0 | } |
432 | 0 | else |
433 | 0 | { |
434 | | // Base decision on the transparency of the first pass |
435 | 0 | return mPasses[0]->isTransparent(); |
436 | 0 | } |
437 | 0 | } |
438 | | //----------------------------------------------------------------------------- |
439 | | bool Technique::isTransparentSortingEnabled(void) const |
440 | 0 | { |
441 | 0 | if (mPasses.empty()) |
442 | 0 | { |
443 | 0 | return true; |
444 | 0 | } |
445 | 0 | else |
446 | 0 | { |
447 | | // Base decision on the transparency of the first pass |
448 | 0 | return mPasses[0]->getTransparentSortingEnabled(); |
449 | 0 | } |
450 | 0 | } |
451 | | //----------------------------------------------------------------------------- |
452 | | bool Technique::isTransparentSortingForced(void) const |
453 | 0 | { |
454 | 0 | if (mPasses.empty()) |
455 | 0 | { |
456 | 0 | return false; |
457 | 0 | } |
458 | 0 | else |
459 | 0 | { |
460 | | // Base decision on the first pass |
461 | 0 | return mPasses[0]->getTransparentSortingForced(); |
462 | 0 | } |
463 | 0 | } |
464 | | //----------------------------------------------------------------------------- |
465 | | bool Technique::isDepthWriteEnabled(void) const |
466 | 0 | { |
467 | 0 | if (mPasses.empty()) |
468 | 0 | { |
469 | 0 | return false; |
470 | 0 | } |
471 | 0 | else |
472 | 0 | { |
473 | | // Base decision on the depth settings of the first pass |
474 | 0 | return mPasses[0]->getDepthWriteEnabled(); |
475 | 0 | } |
476 | 0 | } |
477 | | //----------------------------------------------------------------------------- |
478 | | bool Technique::isDepthCheckEnabled(void) const |
479 | 0 | { |
480 | 0 | if (mPasses.empty()) |
481 | 0 | { |
482 | 0 | return false; |
483 | 0 | } |
484 | 0 | else |
485 | 0 | { |
486 | | // Base decision on the depth settings of the first pass |
487 | 0 | return mPasses[0]->getDepthCheckEnabled(); |
488 | 0 | } |
489 | 0 | } |
490 | | //----------------------------------------------------------------------------- |
491 | | bool Technique::hasColourWriteDisabled(void) const |
492 | 0 | { |
493 | 0 | if (mPasses.empty()) |
494 | 0 | { |
495 | 0 | return true; |
496 | 0 | } |
497 | 0 | else |
498 | 0 | { |
499 | | // Base decision on the colour write settings of the first pass |
500 | 0 | return !mPasses[0]->getColourWriteEnabled(); |
501 | 0 | } |
502 | 0 | } |
503 | | //----------------------------------------------------------------------------- |
504 | | void Technique::_prepare(void) |
505 | 0 | { |
506 | 0 | assert (mIsSupported && "This technique is not supported"); |
507 | | // Load each pass |
508 | 0 | for (auto *p : mPasses) |
509 | 0 | { |
510 | 0 | p->_prepare(); |
511 | 0 | } |
512 | |
|
513 | 0 | for (auto *i : mIlluminationPasses) |
514 | 0 | { |
515 | 0 | if(i->pass != i->originalPass) |
516 | 0 | i->pass->_prepare(); |
517 | 0 | } |
518 | 0 | } |
519 | | //----------------------------------------------------------------------------- |
520 | | void Technique::_unprepare(void) |
521 | 0 | { |
522 | | // Unload each pass |
523 | 0 | for (auto *p : mPasses) |
524 | 0 | { |
525 | 0 | p->_unprepare(); |
526 | 0 | } |
527 | 0 | } |
528 | | //----------------------------------------------------------------------------- |
529 | | void Technique::_load(void) |
530 | 0 | { |
531 | | // Load each pass |
532 | 0 | for (auto *p : mPasses) |
533 | 0 | { |
534 | 0 | p->_load(); |
535 | 0 | } |
536 | |
|
537 | 0 | for (auto *i : mIlluminationPasses) |
538 | 0 | { |
539 | 0 | if(i->pass != i->originalPass) |
540 | 0 | i->pass->_load(); |
541 | 0 | } |
542 | |
|
543 | 0 | if (!mShadowCasterMaterial && !mShadowCasterMaterialName.empty()) |
544 | 0 | { |
545 | | // in case we could not get material as it wasn't yet parsed/existent at that time. |
546 | 0 | mShadowCasterMaterial = MaterialManager::getSingleton().getByName(mShadowCasterMaterialName); |
547 | 0 | } |
548 | |
|
549 | 0 | if (mShadowCasterMaterial && mShadowCasterMaterial.get() != getParent()) |
550 | 0 | { |
551 | 0 | mShadowCasterMaterial->load(); |
552 | 0 | } |
553 | |
|
554 | 0 | if(!mShadowReceiverMaterial && !mShadowReceiverMaterialName.empty()) |
555 | 0 | { |
556 | | // in case we could not get material as it wasn't yet parsed/existent at that time. |
557 | 0 | mShadowReceiverMaterial = MaterialManager::getSingleton().getByName(mShadowReceiverMaterialName); |
558 | 0 | } |
559 | |
|
560 | 0 | if (mShadowReceiverMaterial && mShadowReceiverMaterial.get() != getParent()) |
561 | 0 | { |
562 | 0 | mShadowReceiverMaterial->load(); |
563 | 0 | } |
564 | 0 | } |
565 | | //----------------------------------------------------------------------------- |
566 | | void Technique::_unload(void) |
567 | 0 | { |
568 | | // Unload each pass |
569 | 0 | for (auto *p : mPasses) |
570 | 0 | { |
571 | 0 | p->_unload(); |
572 | 0 | } |
573 | 0 | } |
574 | | //----------------------------------------------------------------------------- |
575 | | bool Technique::isLoaded(void) const |
576 | 0 | { |
577 | | // Only supported technique will be loaded |
578 | 0 | return mParent->isLoaded() && mIsSupported; |
579 | 0 | } |
580 | | //----------------------------------------------------------------------- |
581 | 1 | #define ALL_PASSES(fncall) for(auto p : mPasses) p->fncall |
582 | 0 | void Technique::setPointSize(Real ps) { ALL_PASSES(setPointSize(ps)); } |
583 | | //----------------------------------------------------------------------- |
584 | 0 | void Technique::setAmbient(float red, float green, float blue) { setAmbient(ColourValue(red, green, blue)); } |
585 | | //----------------------------------------------------------------------- |
586 | 0 | void Technique::setAmbient(const ColourValue& ambient) { ALL_PASSES(setAmbient(ambient)); } |
587 | | //----------------------------------------------------------------------- |
588 | | void Technique::setDiffuse(float red, float green, float blue, float alpha) |
589 | 0 | { |
590 | 0 | ALL_PASSES(setDiffuse(red, green, blue, alpha)); |
591 | 0 | } |
592 | | //----------------------------------------------------------------------- |
593 | 0 | void Technique::setDiffuse(const ColourValue& diffuse) { setDiffuse(diffuse.r, diffuse.g, diffuse.b, diffuse.a); } |
594 | | //----------------------------------------------------------------------- |
595 | | void Technique::setSpecular(float red, float green, float blue, float alpha) |
596 | 0 | { |
597 | 0 | ALL_PASSES(setSpecular(red, green, blue, alpha)); |
598 | 0 | } |
599 | | //----------------------------------------------------------------------- |
600 | | void Technique::setSpecular(const ColourValue& specular) |
601 | 0 | { |
602 | 0 | setSpecular(specular.r, specular.g, specular.b, specular.a); |
603 | 0 | } |
604 | | //----------------------------------------------------------------------- |
605 | 0 | void Technique::setShininess(Real val) { ALL_PASSES(setShininess(val)); } |
606 | | //----------------------------------------------------------------------- |
607 | | void Technique::setSelfIllumination(float red, float green, float blue) |
608 | 0 | { |
609 | 0 | setSelfIllumination(ColourValue(red, green, blue)); |
610 | 0 | } |
611 | | //----------------------------------------------------------------------- |
612 | 0 | void Technique::setSelfIllumination(const ColourValue& selfIllum) { ALL_PASSES(setSelfIllumination(selfIllum)); } |
613 | | //----------------------------------------------------------------------- |
614 | 0 | void Technique::setDepthCheckEnabled(bool enabled) { ALL_PASSES(setDepthCheckEnabled(enabled)); } |
615 | | //----------------------------------------------------------------------- |
616 | 0 | void Technique::setDepthWriteEnabled(bool enabled) { ALL_PASSES(setDepthWriteEnabled(enabled)); } |
617 | | //----------------------------------------------------------------------- |
618 | 0 | void Technique::setDepthFunction(CompareFunction func) { ALL_PASSES(setDepthFunction(func)); } |
619 | | //----------------------------------------------------------------------- |
620 | 0 | void Technique::setColourWriteEnabled(bool enabled) { ALL_PASSES(setColourWriteEnabled(enabled)); } |
621 | | //----------------------------------------------------------------------- |
622 | | void Technique::setColourWriteEnabled(bool red, bool green, bool blue, bool alpha) |
623 | 0 | { |
624 | 0 | ALL_PASSES(setColourWriteEnabled(red, green, blue, alpha)); |
625 | 0 | } |
626 | | //----------------------------------------------------------------------- |
627 | 0 | void Technique::setCullingMode(CullingMode mode) { ALL_PASSES(setCullingMode(mode)); } |
628 | | //----------------------------------------------------------------------- |
629 | 0 | void Technique::setManualCullingMode(ManualCullingMode mode) { ALL_PASSES(setManualCullingMode(mode)); } |
630 | | //----------------------------------------------------------------------- |
631 | 1 | void Technique::setLightingEnabled(bool enabled) { ALL_PASSES(setLightingEnabled(enabled)); } |
632 | | //----------------------------------------------------------------------- |
633 | 0 | void Technique::setShadingMode(ShadeOptions mode) { ALL_PASSES(setShadingMode(mode)); } |
634 | | //----------------------------------------------------------------------- |
635 | | void Technique::setFog(bool overrideScene, FogMode mode, const ColourValue& colour, Real expDensity, |
636 | | Real linearStart, Real linearEnd) |
637 | 0 | { |
638 | 0 | ALL_PASSES(setFog(overrideScene, mode, colour, expDensity, linearStart, linearEnd)); |
639 | 0 | } |
640 | | //----------------------------------------------------------------------- |
641 | | void Technique::setDepthBias(float constantBias, float slopeScaleBias) |
642 | 0 | { |
643 | 0 | ALL_PASSES(setDepthBias(constantBias, slopeScaleBias)); |
644 | 0 | } |
645 | | //----------------------------------------------------------------------- |
646 | | void Technique::setTextureFiltering(TextureFilterOptions filterType) |
647 | 0 | { |
648 | 0 | ALL_PASSES(setTextureFiltering(filterType)); |
649 | 0 | } |
650 | | // -------------------------------------------------------------------- |
651 | 0 | void Technique::setTextureAnisotropy(unsigned int maxAniso) { ALL_PASSES(setTextureAnisotropy(maxAniso)); } |
652 | | // -------------------------------------------------------------------- |
653 | 0 | void Technique::setSceneBlending(const SceneBlendType sbt) { ALL_PASSES(setSceneBlending(sbt)); } |
654 | | // -------------------------------------------------------------------- |
655 | | void Technique::setSeparateSceneBlending(const SceneBlendType sbt, const SceneBlendType sbta) |
656 | 0 | { |
657 | 0 | ALL_PASSES(setSeparateSceneBlending(sbt, sbta)); |
658 | 0 | } |
659 | | // -------------------------------------------------------------------- |
660 | | void Technique::setSceneBlending(const SceneBlendFactor sourceFactor, const SceneBlendFactor destFactor) |
661 | 0 | { |
662 | 0 | ALL_PASSES(setSceneBlending(sourceFactor, destFactor)); |
663 | 0 | } |
664 | | // -------------------------------------------------------------------- |
665 | | void Technique::setSeparateSceneBlending( const SceneBlendFactor sourceFactor, const SceneBlendFactor destFactor, const SceneBlendFactor sourceFactorAlpha, const SceneBlendFactor destFactorAlpha) |
666 | 0 | { |
667 | 0 | ALL_PASSES(setSeparateSceneBlending(sourceFactor, destFactor, sourceFactorAlpha, destFactorAlpha)); |
668 | 0 | } |
669 | | #undef ALL_PASSES |
670 | | |
671 | | // -------------------------------------------------------------------- |
672 | | void Technique::setName(const String& name) |
673 | 0 | { |
674 | 0 | mName = name; |
675 | 0 | } |
676 | | |
677 | | |
678 | | //----------------------------------------------------------------------- |
679 | | void Technique::_notifyNeedsRecompile(void) |
680 | 0 | { |
681 | | // Disable require to recompile when splitting illumination passes |
682 | 0 | if (mIlluminationPassesCompilationPhase != IPS_COMPILE_DISABLED) |
683 | 0 | { |
684 | 0 | mParent->_notifyNeedsRecompile(); |
685 | 0 | } |
686 | 0 | } |
687 | | //----------------------------------------------------------------------- |
688 | | void Technique::setLodIndex(unsigned short index) |
689 | 0 | { |
690 | 0 | mLodIndex = index; |
691 | 0 | _notifyNeedsRecompile(); |
692 | 0 | } |
693 | | //----------------------------------------------------------------------- |
694 | | void Technique::setSchemeName(const String& schemeName) |
695 | 0 | { |
696 | 0 | mSchemeIndex = MaterialManager::getSingleton()._getSchemeIndex(schemeName); |
697 | 0 | _notifyNeedsRecompile(); |
698 | 0 | } |
699 | | //----------------------------------------------------------------------- |
700 | | const String& Technique::getSchemeName(void) const |
701 | 0 | { |
702 | 0 | return MaterialManager::getSingleton()._getSchemeName(mSchemeIndex); |
703 | 0 | } |
704 | | //----------------------------------------------------------------------- |
705 | | unsigned short Technique::_getSchemeIndex(void) const |
706 | 0 | { |
707 | 0 | return mSchemeIndex; |
708 | 0 | } |
709 | | //--------------------------------------------------------------------- |
710 | | bool Technique::checkManuallyOrganisedIlluminationPasses() |
711 | 0 | { |
712 | | // first check whether all passes have manually assigned illumination |
713 | 0 | for (auto *p : mPasses) |
714 | 0 | { |
715 | 0 | if (p->getIlluminationStage() == IS_UNKNOWN) |
716 | 0 | return false; |
717 | 0 | } |
718 | | |
719 | | // ok, all manually controlled, so just use that |
720 | 0 | for (auto *p : mPasses) |
721 | 0 | { |
722 | 0 | IlluminationPass* iPass = OGRE_NEW IlluminationPass(); |
723 | 0 | iPass->destroyOnShutdown = false; |
724 | 0 | iPass->originalPass = iPass->pass = p; |
725 | 0 | iPass->stage = p->getIlluminationStage(); |
726 | 0 | mIlluminationPasses.push_back(iPass); |
727 | 0 | } |
728 | |
|
729 | 0 | return true; |
730 | 0 | } |
731 | | //----------------------------------------------------------------------- |
732 | | void Technique::_compileIlluminationPasses(void) |
733 | 0 | { |
734 | 0 | clearIlluminationPasses(); |
735 | |
|
736 | 0 | if (!checkManuallyOrganisedIlluminationPasses()) |
737 | 0 | { |
738 | | // Build based on our own heuristics |
739 | |
|
740 | 0 | Passes::iterator i, iend; |
741 | 0 | iend = mPasses.end(); |
742 | 0 | i = mPasses.begin(); |
743 | |
|
744 | 0 | IlluminationStage iStage = IS_AMBIENT; |
745 | |
|
746 | 0 | bool haveAmbient = false; |
747 | 0 | while (i != iend) |
748 | 0 | { |
749 | 0 | IlluminationPass* iPass; |
750 | 0 | Pass* p = *i; |
751 | 0 | switch(iStage) |
752 | 0 | { |
753 | 0 | case IS_AMBIENT: |
754 | | // Keep looking for ambient only |
755 | 0 | if (p->isAmbientOnly()) |
756 | 0 | { |
757 | | // Add this pass wholesale |
758 | 0 | iPass = OGRE_NEW IlluminationPass(); |
759 | 0 | iPass->destroyOnShutdown = false; |
760 | 0 | iPass->originalPass = iPass->pass = p; |
761 | 0 | iPass->stage = iStage; |
762 | 0 | mIlluminationPasses.push_back(iPass); |
763 | 0 | haveAmbient = true; |
764 | | // progress to next pass |
765 | 0 | ++i; |
766 | 0 | } |
767 | 0 | else |
768 | 0 | { |
769 | | // Split off any ambient part |
770 | 0 | if (p->getAmbient() != ColourValue::Black || |
771 | 0 | p->getSelfIllumination() != ColourValue::Black || |
772 | 0 | p->getAlphaRejectFunction() != CMPF_ALWAYS_PASS) |
773 | 0 | { |
774 | | // Copy existing pass |
775 | 0 | Pass* newPass = OGRE_NEW Pass(this, p->getIndex(), *p); |
776 | 0 | if (newPass->getAlphaRejectFunction() != CMPF_ALWAYS_PASS) |
777 | 0 | { |
778 | | // Alpha rejection passes must retain their transparency, so |
779 | | // we allow the texture units, but override the colour functions |
780 | 0 | for(auto *s : newPass->getTextureUnitStates()) |
781 | 0 | { |
782 | 0 | s->setColourOperationEx(LBX_SOURCE1, LBS_CURRENT); |
783 | 0 | } |
784 | 0 | } |
785 | 0 | else |
786 | 0 | { |
787 | | // Remove any texture units |
788 | 0 | newPass->removeAllTextureUnitStates(); |
789 | 0 | } |
790 | | // Remove any fragment program |
791 | 0 | if (newPass->hasFragmentProgram()) |
792 | 0 | newPass->setFragmentProgram(""); |
793 | | // We have to leave vertex program alone (if any) and |
794 | | // just trust that the author is using light bindings, which |
795 | | // we will ensure there are none in the ambient pass |
796 | 0 | newPass->setDiffuse(0, 0, 0, newPass->getDiffuse().a); // Preserving alpha |
797 | 0 | newPass->setSpecular(ColourValue::Black); |
798 | | |
799 | | // Calculate hash value for new pass, because we are compiling |
800 | | // illumination passes on demand, which will loss hash calculate |
801 | | // before it add to render queue first time. |
802 | 0 | newPass->_recalculateHash(); |
803 | |
|
804 | 0 | iPass = OGRE_NEW IlluminationPass(); |
805 | 0 | iPass->destroyOnShutdown = true; |
806 | 0 | iPass->originalPass = p; |
807 | 0 | iPass->pass = newPass; |
808 | 0 | iPass->stage = iStage; |
809 | |
|
810 | 0 | mIlluminationPasses.push_back(iPass); |
811 | 0 | haveAmbient = true; |
812 | |
|
813 | 0 | } |
814 | |
|
815 | 0 | if (!haveAmbient) |
816 | 0 | { |
817 | | // Make up a new basic pass |
818 | 0 | Pass* newPass = OGRE_NEW Pass(this, p->getIndex()); |
819 | 0 | newPass->setAmbient(ColourValue::Black); |
820 | 0 | newPass->setDiffuse(ColourValue::Black); |
821 | | |
822 | | // Calculate hash value for new pass, because we are compiling |
823 | | // illumination passes on demand, which will loss hash calculate |
824 | | // before it add to render queue first time. |
825 | 0 | newPass->_recalculateHash(); |
826 | |
|
827 | 0 | iPass = OGRE_NEW IlluminationPass(); |
828 | 0 | iPass->destroyOnShutdown = true; |
829 | 0 | iPass->originalPass = p; |
830 | 0 | iPass->pass = newPass; |
831 | 0 | iPass->stage = iStage; |
832 | 0 | mIlluminationPasses.push_back(iPass); |
833 | 0 | haveAmbient = true; |
834 | 0 | } |
835 | | // This means we're done with ambients, progress to per-light |
836 | 0 | iStage = IS_PER_LIGHT; |
837 | 0 | } |
838 | 0 | break; |
839 | 0 | case IS_PER_LIGHT: |
840 | 0 | if (p->getIteratePerLight()) |
841 | 0 | { |
842 | | // If this is per-light already, use it directly |
843 | 0 | iPass = OGRE_NEW IlluminationPass(); |
844 | 0 | iPass->destroyOnShutdown = false; |
845 | 0 | iPass->originalPass = iPass->pass = p; |
846 | 0 | iPass->stage = iStage; |
847 | 0 | mIlluminationPasses.push_back(iPass); |
848 | | // progress to next pass |
849 | 0 | ++i; |
850 | 0 | } |
851 | 0 | else |
852 | 0 | { |
853 | | // Split off per-light details (can only be done for one) |
854 | 0 | if (p->getLightingEnabled() && |
855 | 0 | (p->getDiffuse() != ColourValue::Black || |
856 | 0 | p->getSpecular() != ColourValue::Black)) |
857 | 0 | { |
858 | | // Copy existing pass |
859 | 0 | Pass* newPass = OGRE_NEW Pass(this, p->getIndex(), *p); |
860 | 0 | if (newPass->getAlphaRejectFunction() != CMPF_ALWAYS_PASS) |
861 | 0 | { |
862 | | // Alpha rejection passes must retain their transparency, so |
863 | | // we allow the texture units, but override the colour functions |
864 | 0 | for(auto *s : newPass->getTextureUnitStates()) |
865 | 0 | { |
866 | 0 | s->setColourOperationEx(LBX_SOURCE1, LBS_CURRENT); |
867 | 0 | } |
868 | 0 | } |
869 | 0 | else |
870 | 0 | { |
871 | | // remove texture units |
872 | 0 | newPass->removeAllTextureUnitStates(); |
873 | 0 | } |
874 | | // remove fragment programs |
875 | 0 | if (newPass->hasFragmentProgram()) |
876 | 0 | newPass->setFragmentProgram(""); |
877 | | // Cannot remove vertex program, have to assume that |
878 | | // it will process diffuse lights, ambient will be turned off |
879 | 0 | newPass->setAmbient(ColourValue::Black); |
880 | 0 | newPass->setSelfIllumination(ColourValue::Black); |
881 | | // must be additive |
882 | 0 | newPass->setSceneBlending(SBF_ONE, SBF_ONE); |
883 | | |
884 | | // Calculate hash value for new pass, because we are compiling |
885 | | // illumination passes on demand, which will loss hash calculate |
886 | | // before it add to render queue first time. |
887 | 0 | newPass->_recalculateHash(); |
888 | |
|
889 | 0 | iPass = OGRE_NEW IlluminationPass(); |
890 | 0 | iPass->destroyOnShutdown = true; |
891 | 0 | iPass->originalPass = p; |
892 | 0 | iPass->pass = newPass; |
893 | 0 | iPass->stage = iStage; |
894 | |
|
895 | 0 | mIlluminationPasses.push_back(iPass); |
896 | |
|
897 | 0 | } |
898 | | // This means the end of per-light passes |
899 | 0 | iStage = IS_DECAL; |
900 | 0 | } |
901 | 0 | break; |
902 | 0 | case IS_DECAL: |
903 | | // We just want a 'lighting off' pass to finish off |
904 | | // and only if there are texture units |
905 | 0 | if (p->getNumTextureUnitStates() > 0) |
906 | 0 | { |
907 | 0 | if (!p->getLightingEnabled()) |
908 | 0 | { |
909 | | // we assume this pass already combines as required with the scene |
910 | 0 | iPass = OGRE_NEW IlluminationPass(); |
911 | 0 | iPass->destroyOnShutdown = false; |
912 | 0 | iPass->originalPass = iPass->pass = p; |
913 | 0 | iPass->stage = iStage; |
914 | 0 | mIlluminationPasses.push_back(iPass); |
915 | 0 | } |
916 | 0 | else |
917 | 0 | { |
918 | | // Copy the pass and tweak away the lighting parts |
919 | 0 | Pass* newPass = OGRE_NEW Pass(this, p->getIndex(), *p); |
920 | 0 | newPass->setAmbient(ColourValue::Black); |
921 | 0 | newPass->setDiffuse(0, 0, 0, newPass->getDiffuse().a); // Preserving alpha |
922 | 0 | newPass->setSpecular(ColourValue::Black); |
923 | 0 | newPass->setSelfIllumination(ColourValue::Black); |
924 | 0 | newPass->setLightingEnabled(false); |
925 | 0 | newPass->setIteratePerLight(false, false); |
926 | | // modulate |
927 | 0 | newPass->setSceneBlending(SBF_DEST_COLOUR, SBF_ZERO); |
928 | | |
929 | | // Calculate hash value for new pass, because we are compiling |
930 | | // illumination passes on demand, which will loss hash calculate |
931 | | // before it add to render queue first time. |
932 | 0 | newPass->_recalculateHash(); |
933 | | |
934 | | // NB there is nothing we can do about vertex & fragment |
935 | | // programs here, so people will just have to make their |
936 | | // programs friendly-like if they want to use this technique |
937 | 0 | iPass = OGRE_NEW IlluminationPass(); |
938 | 0 | iPass->destroyOnShutdown = true; |
939 | 0 | iPass->originalPass = p; |
940 | 0 | iPass->pass = newPass; |
941 | 0 | iPass->stage = iStage; |
942 | 0 | mIlluminationPasses.push_back(iPass); |
943 | |
|
944 | 0 | } |
945 | 0 | } |
946 | 0 | ++i; // always increment on decal, since nothing more to do with this pass |
947 | |
|
948 | 0 | break; |
949 | 0 | case IS_UNKNOWN: |
950 | 0 | break; |
951 | 0 | } |
952 | 0 | } |
953 | 0 | } |
954 | |
|
955 | 0 | } |
956 | | //----------------------------------------------------------------------- |
957 | | void Technique::clearIlluminationPasses(void) |
958 | 2 | { |
959 | 2 | if(MaterialManager::getSingletonPtr()) |
960 | 2 | MaterialManager::getSingleton()._notifyBeforeIlluminationPassesCleared(this); |
961 | | |
962 | 2 | for (auto *i : mIlluminationPasses) |
963 | 0 | { |
964 | 0 | if (i->destroyOnShutdown) |
965 | 0 | { |
966 | 0 | i->pass->queueForDeletion(); |
967 | 0 | } |
968 | 0 | OGRE_DELETE i; |
969 | 0 | } |
970 | 2 | mIlluminationPasses.clear(); |
971 | 2 | } |
972 | | //----------------------------------------------------------------------- |
973 | | const IlluminationPassList& |
974 | | Technique::getIlluminationPasses(void) |
975 | 0 | { |
976 | 0 | IlluminationPassesState targetState = IPS_COMPILED; |
977 | 0 | if(mIlluminationPassesCompilationPhase != targetState |
978 | 0 | && mIlluminationPassesCompilationPhase != IPS_COMPILE_DISABLED) |
979 | 0 | { |
980 | | // prevents parent->_notifyNeedsRecompile() call during compile |
981 | 0 | mIlluminationPassesCompilationPhase = IPS_COMPILE_DISABLED; |
982 | | // Splitting the passes into illumination passes |
983 | 0 | _compileIlluminationPasses(); |
984 | | // Post notification, so that technique owner can post-process created passes |
985 | 0 | if(MaterialManager::getSingletonPtr()) |
986 | 0 | MaterialManager::getSingleton()._notifyAfterIlluminationPassesCreated(this); |
987 | | // Mark that illumination passes compilation finished |
988 | 0 | mIlluminationPassesCompilationPhase = targetState; |
989 | 0 | } |
990 | |
|
991 | 0 | return mIlluminationPasses; |
992 | 0 | } |
993 | | //----------------------------------------------------------------------- |
994 | | const String& Technique::getResourceGroup(void) const |
995 | 0 | { |
996 | 0 | return mParent->getGroup(); |
997 | 0 | } |
998 | | //----------------------------------------------------------------------- |
999 | | Ogre::MaterialPtr Technique::getShadowCasterMaterial() const |
1000 | 0 | { |
1001 | 0 | return mShadowCasterMaterial; |
1002 | 0 | } |
1003 | | //----------------------------------------------------------------------- |
1004 | | void Technique::setShadowCasterMaterial(Ogre::MaterialPtr val) |
1005 | 0 | { |
1006 | 0 | if (!val) |
1007 | 0 | { |
1008 | 0 | mShadowCasterMaterial.reset(); |
1009 | 0 | mShadowCasterMaterialName.clear(); |
1010 | 0 | } |
1011 | 0 | else |
1012 | 0 | { |
1013 | | // shadow caster material should never receive shadows |
1014 | 0 | val->setReceiveShadows(false); // should we warn if this is not set? |
1015 | 0 | mShadowCasterMaterial = val; |
1016 | 0 | mShadowCasterMaterialName = val->getName(); |
1017 | 0 | } |
1018 | 0 | } |
1019 | | //----------------------------------------------------------------------- |
1020 | | void Technique::setShadowCasterMaterial(const Ogre::String &name) |
1021 | 0 | { |
1022 | 0 | setShadowCasterMaterial(MaterialManager::getSingleton().getByName(name)); |
1023 | | // remember the name, even if it is not created yet |
1024 | 0 | mShadowCasterMaterialName = name; |
1025 | 0 | } |
1026 | | //----------------------------------------------------------------------- |
1027 | | Ogre::MaterialPtr Technique::getShadowReceiverMaterial() const |
1028 | 0 | { |
1029 | 0 | return mShadowReceiverMaterial; |
1030 | 0 | } |
1031 | | //----------------------------------------------------------------------- |
1032 | | void Technique::setShadowReceiverMaterial(Ogre::MaterialPtr val) |
1033 | 0 | { |
1034 | 0 | if (!val) |
1035 | 0 | { |
1036 | 0 | mShadowReceiverMaterial.reset(); |
1037 | 0 | mShadowReceiverMaterialName.clear(); |
1038 | 0 | } |
1039 | 0 | else |
1040 | 0 | { |
1041 | 0 | mShadowReceiverMaterial = val; |
1042 | 0 | mShadowReceiverMaterialName = val->getName(); |
1043 | 0 | } |
1044 | 0 | } |
1045 | | //----------------------------------------------------------------------- |
1046 | | void Technique::setShadowReceiverMaterial(const Ogre::String &name) |
1047 | 0 | { |
1048 | 0 | mShadowReceiverMaterialName = name; |
1049 | 0 | mShadowReceiverMaterial = MaterialManager::getSingleton().getByName(name); |
1050 | 0 | } |
1051 | | //--------------------------------------------------------------------- |
1052 | | void Technique::addGPUVendorRule(GPUVendor vendor, Technique::IncludeOrExclude includeOrExclude) |
1053 | 0 | { |
1054 | 0 | addGPUVendorRule(GPUVendorRule(vendor, includeOrExclude)); |
1055 | 0 | } |
1056 | | //--------------------------------------------------------------------- |
1057 | | void Technique::addGPUVendorRule(const Technique::GPUVendorRule& rule) |
1058 | 0 | { |
1059 | | // remove duplicates |
1060 | 0 | removeGPUVendorRule(rule.vendor); |
1061 | 0 | mGPUVendorRules.push_back(rule); |
1062 | 0 | } |
1063 | | //--------------------------------------------------------------------- |
1064 | | void Technique::removeGPUVendorRule(GPUVendor vendor) |
1065 | 0 | { |
1066 | 0 | for (GPUVendorRuleList::iterator i = mGPUVendorRules.begin(); i != mGPUVendorRules.end(); ) |
1067 | 0 | { |
1068 | 0 | if (i->vendor == vendor) |
1069 | 0 | i = mGPUVendorRules.erase(i); |
1070 | 0 | else |
1071 | 0 | ++i; |
1072 | 0 | } |
1073 | 0 | } |
1074 | | //--------------------------------------------------------------------- |
1075 | | Technique::GPUVendorRuleIterator Technique::getGPUVendorRuleIterator() const |
1076 | 0 | { |
1077 | 0 | return GPUVendorRuleIterator(mGPUVendorRules.begin(), mGPUVendorRules.end()); |
1078 | 0 | } |
1079 | | //--------------------------------------------------------------------- |
1080 | | void Technique::addGPUDeviceNameRule(const String& devicePattern, |
1081 | | Technique::IncludeOrExclude includeOrExclude, bool caseSensitive) |
1082 | 0 | { |
1083 | 0 | addGPUDeviceNameRule(GPUDeviceNameRule(devicePattern, includeOrExclude, caseSensitive)); |
1084 | 0 | } |
1085 | | //--------------------------------------------------------------------- |
1086 | | void Technique::addGPUDeviceNameRule(const Technique::GPUDeviceNameRule& rule) |
1087 | 0 | { |
1088 | | // remove duplicates |
1089 | 0 | removeGPUDeviceNameRule(rule.devicePattern); |
1090 | 0 | mGPUDeviceNameRules.push_back(rule); |
1091 | 0 | } |
1092 | | //--------------------------------------------------------------------- |
1093 | | void Technique::removeGPUDeviceNameRule(const String& devicePattern) |
1094 | 0 | { |
1095 | 0 | for (GPUDeviceNameRuleList::iterator i = mGPUDeviceNameRules.begin(); i != mGPUDeviceNameRules.end(); ) |
1096 | 0 | { |
1097 | 0 | if (i->devicePattern == devicePattern) |
1098 | 0 | i = mGPUDeviceNameRules.erase(i); |
1099 | 0 | else |
1100 | 0 | ++i; |
1101 | 0 | } |
1102 | 0 | } |
1103 | | //--------------------------------------------------------------------- |
1104 | | Technique::GPUDeviceNameRuleIterator Technique::getGPUDeviceNameRuleIterator() const |
1105 | 0 | { |
1106 | 0 | return GPUDeviceNameRuleIterator(mGPUDeviceNameRules.begin(), mGPUDeviceNameRules.end()); |
1107 | 0 | } |
1108 | | //--------------------------------------------------------------------- |
1109 | | } |