Material.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755
  1. //
  2. // Urho3D Engine
  3. // Copyright (c) 2008-2011 Lasse Öörni
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining a copy
  6. // of this software and associated documentation files (the "Software"), to deal
  7. // in the Software without restriction, including without limitation the rights
  8. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. // copies of the Software, and to permit persons to whom the Software is
  10. // furnished to do so, subject to the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be included in
  13. // all copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. // THE SOFTWARE.
  22. //
  23. #include "Precompiled.h"
  24. #include "Log.h"
  25. #include "Material.h"
  26. #include "Matrix4x3.h"
  27. #include "PixelShader.h"
  28. #include "Profiler.h"
  29. #include "ResourceCache.h"
  30. #include "StringUtils.h"
  31. #include "Texture2D.h"
  32. #include "TextureCube.h"
  33. #include "VertexShader.h"
  34. #include "XMLFile.h"
  35. #include "DebugNew.h"
  36. static const std::string passNames[] =
  37. {
  38. "deferred",
  39. "prepass",
  40. "material",
  41. "emissive",
  42. "postopaque",
  43. "ambient",
  44. "negative",
  45. "light",
  46. "shadow"
  47. };
  48. static const std::string textureUnitNames[] =
  49. {
  50. "diffuse",
  51. "normal",
  52. "specular",
  53. "detail",
  54. "environment",
  55. "emissive",
  56. "lightramp", // Not defined by materials
  57. "lightspot" // Not defined by materials
  58. };
  59. static const std::string blendModeNames[] =
  60. {
  61. "replace",
  62. "add",
  63. "multiply",
  64. "alpha",
  65. "addalpha",
  66. "premulalpha",
  67. "invdestalpha"
  68. };
  69. static const std::string cullModeNames[] =
  70. {
  71. "none",
  72. "ccw",
  73. "cw"
  74. };
  75. static const std::string compareModeNames[] =
  76. {
  77. "always",
  78. "equal",
  79. "notequal",
  80. "less",
  81. "lessequal",
  82. "greater",
  83. "greaterequal"
  84. };
  85. MaterialPass::MaterialPass() :
  86. mParent(0),
  87. mAlphaMask(false),
  88. mAlphaTest(false),
  89. mBlendMode(BLEND_REPLACE),
  90. mCullMode(CULL_CCW),
  91. mDepthTestMode(CMP_LESSEQUAL),
  92. mDepthWrite(true)
  93. {
  94. }
  95. MaterialPass::~MaterialPass()
  96. {
  97. }
  98. void MaterialPass::setAlphaMask(bool enable)
  99. {
  100. mAlphaMask = enable;
  101. if (mParent)
  102. mParent->setDirty();
  103. }
  104. void MaterialPass::setAlphaTest(bool enable)
  105. {
  106. mAlphaTest = enable;
  107. if (mParent)
  108. mParent->setDirty();
  109. }
  110. void MaterialPass::setBlendMode(BlendMode mode)
  111. {
  112. mBlendMode = mode;
  113. if (mParent)
  114. mParent->setDirty();
  115. }
  116. void MaterialPass::setCullMode(CullMode mode)
  117. {
  118. mCullMode = mode;
  119. if (mParent)
  120. mParent->setDirty();
  121. }
  122. void MaterialPass::setDepthTestMode(CompareMode mode)
  123. {
  124. mDepthTestMode = mode;
  125. if (mParent)
  126. mParent->setDirty();
  127. }
  128. void MaterialPass::setDepthWrite(bool enable)
  129. {
  130. mDepthWrite = enable;
  131. if (mParent)
  132. mParent->setDirty();
  133. }
  134. void MaterialPass::setVertexShader(const std::string& name)
  135. {
  136. mVertexShaderName = name;
  137. releaseShaders();
  138. if (mParent)
  139. mParent->setDirty();
  140. }
  141. void MaterialPass::setPixelShader(const std::string& name)
  142. {
  143. mPixelShaderName = name;
  144. releaseShaders();
  145. if (mParent)
  146. mParent->setDirty();
  147. }
  148. void MaterialPass::releaseShaders()
  149. {
  150. mVertexShaders.clear();
  151. mPixelShaders.clear();
  152. }
  153. void MaterialPass::setParent(Material* parent)
  154. {
  155. mParent = parent;
  156. }
  157. MaterialTechnique::MaterialTechnique() :
  158. mParent(0),
  159. mQualityLevel(0),
  160. mLodDistance(0.0f),
  161. mRequireSM3(false),
  162. mShadersLoadedFrameNumber(M_MAX_UNSIGNED),
  163. mAuxViewFrameNumber(M_MAX_UNSIGNED)
  164. {
  165. mTextures.resize(MAX_MATERIAL_TEXTURE_UNITS);
  166. // Setup often used defaults
  167. mVSParameters[VSP_UOFFSET] = Vector4(1.0f, 0.0f, 0.0f, 0.0f);
  168. mVSParameters[VSP_VOFFSET] = Vector4(0.0f, 1.0f, 0.0f, 0.0f);
  169. mPSParameters[PSP_MATDIFFCOLOR] = Vector4::sUnity;
  170. mPSParameters[PSP_MATEMISSIVECOLOR] = Vector4::sZero;
  171. mPSParameters[PSP_MATSPECPROPERTIES] = Vector4::sZero;
  172. }
  173. MaterialTechnique::~MaterialTechnique()
  174. {
  175. }
  176. void MaterialTechnique::setQualityLevel(int quality)
  177. {
  178. mQualityLevel = quality;
  179. }
  180. void MaterialTechnique::setLodDistance(float distance)
  181. {
  182. mLodDistance = distance;
  183. }
  184. void MaterialTechnique::setRequireSM3(bool enable)
  185. {
  186. mRequireSM3 = enable;
  187. }
  188. void MaterialTechnique::setVertexShaderParameter(VSParameter parameter, const Vector4& value)
  189. {
  190. mVSParameters[parameter] = value;
  191. }
  192. void MaterialTechnique::setPixelShaderParameter(PSParameter parameter, const Vector4& value)
  193. {
  194. mPSParameters[parameter] = value;
  195. }
  196. void MaterialTechnique::setTexture(TextureUnit unit, Texture* texture)
  197. {
  198. if (unit >= MAX_MATERIAL_TEXTURE_UNITS)
  199. return;
  200. mTextures[unit] = texture;
  201. }
  202. void MaterialTechnique::setUVTransform(const Vector2& offset, float rotation, const Vector2& repeat)
  203. {
  204. Matrix4x3 transform = Matrix4x3::sIdentity;
  205. transform.m00 = repeat.mX;
  206. transform.m11 = repeat.mY;
  207. transform.m03 = -0.5f * transform.m00 + 0.5f;
  208. transform.m13 = -0.5f * transform.m11 + 0.5f;
  209. Matrix4x3 rotationMatrix = Matrix4x3::sIdentity;
  210. float angleRad = rotation * M_DEGTORAD;
  211. rotationMatrix.m00 = cosf(angleRad);
  212. rotationMatrix.m01 = sinf(angleRad);
  213. rotationMatrix.m10 = -rotationMatrix.m01;
  214. rotationMatrix.m11 = rotationMatrix.m00;
  215. rotationMatrix.m03 = 0.5f - 0.5f * (rotationMatrix.m00 + rotationMatrix.m01);
  216. rotationMatrix.m13 = 0.5f - 0.5f * (rotationMatrix.m10 + rotationMatrix.m11);
  217. transform = rotationMatrix * transform;
  218. Matrix4x3 offsetMatrix = Matrix4x3::sIdentity;
  219. offsetMatrix.m03 = offset.mX;
  220. offsetMatrix.m13 = offset.mY;
  221. transform = offsetMatrix * transform;
  222. Vector4& uOffset = mVSParameters[VSP_UOFFSET];
  223. Vector4& vOffset = mVSParameters[VSP_VOFFSET];
  224. uOffset.mX = transform.m00;
  225. uOffset.mY = transform.m01;
  226. uOffset.mW = transform.m03;
  227. vOffset.mX = transform.m10;
  228. vOffset.mY = transform.m11;
  229. vOffset.mW = transform.m13;
  230. }
  231. void MaterialTechnique::setUVTransform(const Vector2& offset, float rotation, float repeat)
  232. {
  233. setUVTransform(offset, rotation, Vector2(repeat, repeat));
  234. }
  235. void MaterialTechnique::releaseShaders()
  236. {
  237. for (std::map<PassType, MaterialPass>::iterator i = mPasses.begin(); i != mPasses.end(); ++i)
  238. i->second.releaseShaders();
  239. }
  240. MaterialPass* MaterialTechnique::createPass(PassType pass)
  241. {
  242. MaterialPass* existing = getPass(pass);
  243. if (existing)
  244. return existing;
  245. MaterialPass newPass;
  246. newPass.setParent(mParent);
  247. mPasses[pass] = newPass;
  248. return getPass(pass);
  249. }
  250. void MaterialTechnique::removePass(PassType pass)
  251. {
  252. mPasses.erase(pass);
  253. }
  254. void MaterialTechnique::setParent(Material* parent)
  255. {
  256. mParent = parent;
  257. for (std::map<PassType, MaterialPass>::iterator i = mPasses.begin(); i != mPasses.end(); ++i)
  258. i->second.setParent(parent);
  259. }
  260. void MaterialTechnique::markForAuxView(unsigned frameNumber)
  261. {
  262. mAuxViewFrameNumber = frameNumber;
  263. }
  264. void MaterialTechnique::markShadersLoaded(unsigned frameNumber)
  265. {
  266. mShadersLoadedFrameNumber = frameNumber;
  267. }
  268. Texture* MaterialTechnique::getTexture(TextureUnit unit) const
  269. {
  270. if ((unsigned)unit >= mTextures.size())
  271. return 0;
  272. return mTextures[unit];
  273. }
  274. Material::Material(const std::string& name) :
  275. Resource(name),
  276. mDirty(true),
  277. mCastShadows(false),
  278. mOcclusion(true),
  279. mOcclusionCullMode(CULL_CCW)
  280. {
  281. setNumTechniques(1);
  282. }
  283. Material::~Material()
  284. {
  285. }
  286. void Material::load(Deserializer& source, ResourceCache* cache)
  287. {
  288. PROFILE(Material_Load);
  289. XMLFile xml;
  290. xml.load(source, cache);
  291. XMLElement rootElem = xml.getRootElement();
  292. // Check for base material and inherit all settings, techniques and passes
  293. XMLElement baseElem = rootElem.getChildElement("base");
  294. if (baseElem)
  295. {
  296. Material* baseMaterial = cache->getResource<Material>(baseElem.getString("name"));
  297. mTechniques = baseMaterial->mTechniques;
  298. // Reparent, and release all shaders, because they most likely will be different in the new material
  299. for (unsigned i = 0; i < mTechniques.size(); ++i)
  300. {
  301. mTechniques[i].setParent(this);
  302. mTechniques[i].releaseShaders();
  303. }
  304. }
  305. else
  306. mTechniques.clear();
  307. XMLElement techniqueElem = rootElem.getChildElement("technique");
  308. unsigned index = 0;
  309. while (techniqueElem)
  310. {
  311. if (mTechniques.size() < index + 1)
  312. setNumTechniques(index + 1);
  313. MaterialTechnique& newTechnique = mTechniques[index];
  314. if (techniqueElem.hasAttribute("quality"))
  315. newTechnique.setQualityLevel(techniqueElem.getInt("quality"));
  316. if (techniqueElem.hasAttribute("loddistance"))
  317. newTechnique.setLodDistance(techniqueElem.getFloat("loddistance"));
  318. if (techniqueElem.hasAttribute("sm3"))
  319. newTechnique.setRequireSM3(techniqueElem.getBool("sm3"));
  320. XMLElement textureElem = techniqueElem.getChildElement("texture");
  321. while (textureElem)
  322. {
  323. TextureUnit unit = TU_DIFFUSE;
  324. if (textureElem.hasAttribute("unit"))
  325. {
  326. std::string unitName = textureElem.getStringLower("unit");
  327. unit = (TextureUnit)getIndexFromStringList(unitName, textureUnitNames, MAX_MATERIAL_TEXTURE_UNITS,
  328. MAX_MATERIAL_TEXTURE_UNITS);
  329. if (unitName == "diff")
  330. unit = TU_DIFFUSE;
  331. if (unitName == "norm")
  332. unit = TU_NORMAL;
  333. if (unitName == "spec")
  334. unit = TU_SPECULAR;
  335. if (unitName == "env")
  336. unit = TU_ENVIRONMENT;
  337. if (unit == MAX_MATERIAL_TEXTURE_UNITS)
  338. LOGERROR("Unknown texture unit " + unitName);
  339. }
  340. if (unit != MAX_MATERIAL_TEXTURE_UNITS)
  341. {
  342. std::string name = textureElem.getString("name");
  343. // Detect cube maps by file extension: they are defined by an XML file
  344. if (getExtension(name) == ".xml")
  345. newTechnique.setTexture(unit, cache->getResource<TextureCube>(name));
  346. else
  347. newTechnique.setTexture(unit, cache->getResource<Texture2D>(name));
  348. }
  349. textureElem = textureElem.getNextElement("texture");
  350. }
  351. XMLElement parameterElem = techniqueElem.getChildElement("parameter");
  352. while (parameterElem)
  353. {
  354. std::string name = parameterElem.getString("name");
  355. Vector4 value = parameterElem.getVector("value");
  356. VSParameter vsParam = VertexShader::getParameter(name);
  357. if (vsParam != MAX_VS_PARAMETERS)
  358. newTechnique.setVertexShaderParameter(vsParam, value);
  359. else
  360. {
  361. PSParameter psParam = PixelShader::getParameter(name);
  362. if (psParam != MAX_PS_PARAMETERS)
  363. newTechnique.setPixelShaderParameter(psParam, value);
  364. else
  365. LOGERROR("Unknown shader parameter " + name);
  366. }
  367. parameterElem = parameterElem.getNextElement("parameter");
  368. }
  369. XMLElement passElem = techniqueElem.getChildElement("pass");
  370. while (passElem)
  371. {
  372. PassType type = MAX_PASSES;
  373. if (passElem.hasAttribute("name"))
  374. {
  375. std::string name = passElem.getStringLower("name");
  376. type = (PassType)getIndexFromStringList(name, passNames, MAX_PASSES, MAX_PASSES);
  377. if (name == "gbuffer")
  378. type = PASS_DEFERRED;
  379. if (name == "custom")
  380. type = PASS_POSTOPAQUE;
  381. if (type == MAX_PASSES)
  382. LOGERROR("Unknown pass " + name);
  383. }
  384. else
  385. LOGERROR("Missing pass name");
  386. if (type != MAX_PASSES)
  387. {
  388. MaterialPass& newPass = *newTechnique.createPass(type);
  389. if (passElem.hasAttribute("vs"))
  390. newPass.setVertexShader(passElem.getString("vs"));
  391. if (passElem.hasAttribute("ps"))
  392. newPass.setPixelShader(passElem.getString("ps"));
  393. if (passElem.hasAttribute("alphamask"))
  394. newPass.setAlphaMask(passElem.getBool("alphamask"));
  395. if (passElem.hasAttribute("alphatest"))
  396. newPass.setAlphaTest(passElem.getBool("alphatest"));
  397. if (passElem.hasAttribute("blend"))
  398. {
  399. std::string blend = passElem.getStringLower("blend");
  400. newPass.setBlendMode((BlendMode)getIndexFromStringList(blend, blendModeNames, MAX_BLENDMODES, BLEND_REPLACE));
  401. }
  402. if (passElem.hasAttribute("cull"))
  403. {
  404. std::string cull = passElem.getStringLower("cull");
  405. newPass.setCullMode((CullMode)getIndexFromStringList(cull, cullModeNames, MAX_CULLMODES, CULL_CCW));
  406. }
  407. if (passElem.hasAttribute("depthtest"))
  408. {
  409. std::string depthTest = passElem.getStringLower("depthtest");
  410. if (depthTest == "false")
  411. newPass.setDepthTestMode(CMP_ALWAYS);
  412. else
  413. newPass.setDepthTestMode((CompareMode)getIndexFromStringList(depthTest, compareModeNames, MAX_COMPAREMODES,
  414. CMP_LESSEQUAL));
  415. }
  416. if (passElem.hasAttribute("depthwrite"))
  417. newPass.setDepthWrite(passElem.getBool("depthwrite"));
  418. // Undefine a pass by setting empty vertex or pixel shader name
  419. if ((newPass.getVertexShaderName().empty()) || (newPass.getPixelShaderName().empty()))
  420. newTechnique.removePass(type);
  421. }
  422. passElem = passElem.getNextElement("pass");
  423. }
  424. techniqueElem = techniqueElem.getNextElement("technique");
  425. ++index;
  426. }
  427. // Calculate memory use
  428. unsigned memoryUse = 0;
  429. memoryUse += sizeof(Material);
  430. for (unsigned i = 0; i < mTechniques.size(); ++i)
  431. {
  432. MaterialTechnique& technique = mTechniques[i];
  433. memoryUse += sizeof(MaterialTechnique);
  434. memoryUse += technique.getTextures().size() * sizeof(SharedPtr<Texture>);
  435. memoryUse += technique.getVertexShaderParameters().size() * (sizeof(VSParameter) + sizeof(Vector4));
  436. memoryUse += technique.getPixelShaderParameters().size() * (sizeof(PSParameter) + sizeof(Vector4));
  437. const std::map<PassType, MaterialPass>& passes = technique.getPasses();
  438. for (std::map<PassType, MaterialPass>::const_iterator j = passes.begin(); j != passes.end(); ++j)
  439. memoryUse += sizeof(MaterialPass);
  440. }
  441. setMemoryUse(memoryUse);
  442. setDirty();
  443. }
  444. void Material::save(Serializer& dest)
  445. {
  446. XMLFile xml;
  447. XMLElement materialElem = xml.createRootElement("material");
  448. // Write techniques
  449. for (unsigned i = 0; i < mTechniques.size(); ++i)
  450. {
  451. MaterialTechnique& technique = mTechniques[i];
  452. XMLElement techniqueElem = materialElem.createChildElement("technique");
  453. // Write quality & lod settings
  454. if (technique.getQualityLevel() != 0)
  455. techniqueElem.setInt("quality", technique.getQualityLevel());
  456. if (technique.getLodDistance() != 0.0f)
  457. techniqueElem.setFloat("loddistance", technique.getLodDistance());
  458. if (technique.getRequireSM3())
  459. techniqueElem.setBool("sm3", true);
  460. // Write texture units
  461. for (unsigned j = 0; j < MAX_MATERIAL_TEXTURE_UNITS; ++j)
  462. {
  463. Texture* texture = technique.getTexture((TextureUnit)j);
  464. if (texture)
  465. {
  466. XMLElement textureElem = techniqueElem.createChildElement("texture");
  467. textureElem.setString("unit", textureUnitNames[j]);
  468. textureElem.setString("name", texture->getName());
  469. }
  470. }
  471. // Write shader parameters. Exclude default values to keep output simpler
  472. const std::map<VSParameter, Vector4>& vsParameters = technique.getVertexShaderParameters();
  473. for (std::map<VSParameter, Vector4>::const_iterator j = vsParameters.begin(); j != vsParameters.end(); ++j)
  474. {
  475. if ((j->first == VSP_UOFFSET) && (j->second == Vector4(1.0f, 0.0f, 0.0f, 0.0f)))
  476. continue;
  477. if ((j->first == VSP_VOFFSET) && (j->second == Vector4(0.0f, 1.0f, 0.0f, 0.0f)))
  478. continue;
  479. XMLElement parameterElem = techniqueElem.createChildElement("parameter");
  480. parameterElem.setString("name", VertexShader::getParameterName(j->first));
  481. parameterElem.setVector4("value", j->second);
  482. }
  483. const std::map<PSParameter, Vector4>& psParameters = technique.getPixelShaderParameters();
  484. for (std::map<PSParameter, Vector4>::const_iterator j = psParameters.begin(); j != psParameters.end(); ++j)
  485. {
  486. if ((j->first == PSP_MATDIFFCOLOR) && (j->second == Vector4::sUnity))
  487. continue;
  488. if ((j->first == PSP_MATEMISSIVECOLOR) && (j->second == Vector4::sZero))
  489. continue;
  490. if ((j->first == PSP_MATSPECPROPERTIES) && (j->second == Vector4::sZero))
  491. continue;
  492. XMLElement parameterElem = techniqueElem.createChildElement("parameter");
  493. parameterElem.setString("name", PixelShader::getParameterName(j->first));
  494. parameterElem.setVector4("value", j->second);
  495. }
  496. // Write passes
  497. const std::map<PassType, MaterialPass>& passes = technique.getPasses();
  498. for (std::map<PassType, MaterialPass>::const_iterator j = passes.begin(); j != passes.end(); ++j)
  499. {
  500. XMLElement passElem = techniqueElem.createChildElement("pass");
  501. passElem.setString("name", getPassName(j->first));
  502. passElem.setString("vs", j->second.getVertexShaderName());
  503. passElem.setString("ps", j->second.getPixelShaderName());
  504. // Exclude default values to keep output simpler
  505. if (j->second.getAlphaMask())
  506. passElem.setBool("alphamask", true);
  507. if (j->second.getAlphaTest())
  508. passElem.setBool("alphatest", true);
  509. if (j->second.getBlendMode() != BLEND_REPLACE)
  510. passElem.setString("blend", blendModeNames[j->second.getBlendMode()]);
  511. if (j->second.getCullMode() != CULL_CCW)
  512. passElem.setString("cull", cullModeNames[j->second.getCullMode()]);
  513. if (j->second.getDepthTestMode() != CMP_LESSEQUAL)
  514. passElem.setString("depthtest", compareModeNames[j->second.getDepthTestMode()]);
  515. if (!j->second.getDepthWrite())
  516. passElem.setBool("depthwrite", false);
  517. }
  518. }
  519. xml.save(dest);
  520. }
  521. void Material::setNumTechniques(unsigned num)
  522. {
  523. if (!num)
  524. return;
  525. mTechniques.resize(num);
  526. for (unsigned i = 0; i < mTechniques.size(); ++i)
  527. mTechniques[i].setParent(this);
  528. }
  529. void Material::setVertexShaderParameter(VSParameter parameter, const Vector4& value)
  530. {
  531. for (unsigned i = 0; i < mTechniques.size(); ++i)
  532. mTechniques[i].setVertexShaderParameter(parameter, value);
  533. }
  534. void Material::setPixelShaderParameter(PSParameter parameter, const Vector4& value)
  535. {
  536. for (unsigned i = 0; i < mTechniques.size(); ++i)
  537. mTechniques[i].setPixelShaderParameter(parameter, value);
  538. }
  539. void Material::setTexture(TextureUnit unit, Texture* texture)
  540. {
  541. for (unsigned i = 0; i < mTechniques.size(); ++i)
  542. mTechniques[i].setTexture(unit, texture);
  543. }
  544. void Material::setUVTransform(const Vector2& offset, float rotation, const Vector2& repeat)
  545. {
  546. for (unsigned i = 0; i < mTechniques.size(); ++i)
  547. mTechniques[i].setUVTransform(offset, rotation, repeat);
  548. }
  549. void Material::setUVTransform(const Vector2& offset, float rotation, float repeat)
  550. {
  551. for (unsigned i = 0; i < mTechniques.size(); ++i)
  552. mTechniques[i].setUVTransform(offset, rotation, repeat);
  553. }
  554. void Material::releaseShaders()
  555. {
  556. for (unsigned i = 0; i < mTechniques.size(); ++i)
  557. mTechniques[i].releaseShaders();
  558. }
  559. void Material::setDirty()
  560. {
  561. mDirty = true;
  562. }
  563. SharedPtr<Material> Material::clone(const std::string& cloneName) const
  564. {
  565. SharedPtr<Material> ret(new Material(cloneName));
  566. ret->mTechniques = mTechniques;
  567. ret->mCastShadows = mCastShadows;
  568. ret->mOcclusion = mOcclusion;
  569. ret->mOcclusionCullMode = mOcclusionCullMode;
  570. // Reparent, and release shaders from the clone, in case they will be set different
  571. for (unsigned i = 0; i < ret->mTechniques.size(); ++i)
  572. {
  573. ret->mTechniques[i].setParent(ret);
  574. ret->mTechniques[i].releaseShaders();
  575. }
  576. return ret;
  577. }
  578. MaterialTechnique* Material::getTechnique(unsigned index)
  579. {
  580. return index < mTechniques.size() ? &mTechniques[index] : 0;
  581. }
  582. MaterialPass* Material::getPass(unsigned technique, PassType pass)
  583. {
  584. if (technique >= mTechniques.size())
  585. return 0;
  586. return mTechniques[technique].getPass(pass);
  587. }
  588. const std::string& Material::getPassName(PassType pass)
  589. {
  590. return passNames[pass];
  591. }
  592. const std::string& Material::getTextureUnitName(TextureUnit unit)
  593. {
  594. return textureUnitNames[unit];
  595. }
  596. bool Material::getCastShadows()
  597. {
  598. if (mDirty)
  599. update();
  600. return mCastShadows;
  601. }
  602. bool Material::getOcclusion()
  603. {
  604. if (mDirty)
  605. update();
  606. return mOcclusion;
  607. }
  608. CullMode Material::getOcclusionCullMode()
  609. {
  610. if (mDirty)
  611. update();
  612. return mOcclusionCullMode;
  613. }
  614. void Material::update()
  615. {
  616. // Report true if any of the material's techniques casts shadows
  617. mCastShadows = false;
  618. for (unsigned i = 0; i < mTechniques.size(); ++i)
  619. {
  620. if (mTechniques[i].hasPass(PASS_SHADOW))
  621. {
  622. mCastShadows = true;
  623. break;
  624. }
  625. }
  626. // Determine occlusion by checking the first pass of each technique
  627. mOcclusion = false;
  628. for (unsigned i = 0; i < mTechniques.size(); ++i)
  629. {
  630. const std::map<PassType, MaterialPass>& passes = mTechniques[i].getPasses();
  631. if (!passes.empty())
  632. {
  633. // If pass writes depth, enable occlusion
  634. const MaterialPass& pass = passes.begin()->second;
  635. if (pass.getDepthWrite())
  636. {
  637. mOcclusion = true;
  638. mOcclusionCullMode = pass.getCullMode();
  639. break;
  640. }
  641. }
  642. }
  643. mDirty = false;
  644. }