ParticleEmitterResource2.cpp 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. // Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #include <AnKi/Resource/ParticleEmitterResource2.h>
  6. #include <AnKi/Resource/ResourceManager.h>
  7. #include <AnKi/Resource/ShaderProgramResource.h>
  8. #include <AnKi/Util/Xml.h>
  9. #include <AnKi/Gr/GrManager.h>
  10. namespace anki {
  11. static Bool mutatorValueExists(const ShaderBinaryMutator& m, MutatorValue val)
  12. {
  13. for(MutatorValue v : m.m_values)
  14. {
  15. if(v == val)
  16. {
  17. return true;
  18. }
  19. }
  20. return false;
  21. }
  22. Error ParticleEmitterResource2::load(const ResourceFilename& filename, Bool async)
  23. {
  24. ResourceXmlDocument doc;
  25. XmlElement el;
  26. ANKI_CHECK(openFileParseXml(filename, doc));
  27. // <material>
  28. XmlElement rootEl;
  29. ANKI_CHECK(doc.getChildElement("particleEmitter", rootEl));
  30. // <shaderPrograms>
  31. XmlElement shaderProgramEl;
  32. ANKI_CHECK(rootEl.getChildElement("shaderProgram", shaderProgramEl));
  33. ANKI_CHECK(parseShaderProgram(shaderProgramEl, async));
  34. // <particleCount>
  35. XmlElement particleCountEl;
  36. ANKI_CHECK(rootEl.getChildElement("particleCount", particleCountEl));
  37. ANKI_CHECK(particleCountEl.getAttributeNumber("value", m_commonProps.m_particleCount));
  38. if(m_commonProps.m_particleCount == 0 || m_commonProps.m_particleCount > kMaxU16) // kMaxU16 is arbitary
  39. {
  40. ANKI_RESOURCE_LOGE("Can't accept particleCount of: %u", m_commonProps.m_particleCount);
  41. return Error::kUserData;
  42. }
  43. // <emissionPeriod>
  44. XmlElement emissionPeriodEl;
  45. ANKI_CHECK(rootEl.getChildElement("emissionPeriod", emissionPeriodEl));
  46. ANKI_CHECK(emissionPeriodEl.getAttributeNumber("value", m_commonProps.m_emissionPeriod));
  47. // <particlesPerEmission>
  48. XmlElement particlesPerEmissionEl;
  49. ANKI_CHECK(rootEl.getChildElement("particlesPerEmission", particlesPerEmissionEl));
  50. ANKI_CHECK(particlesPerEmissionEl.getAttributeNumber("value", m_commonProps.m_particlesPerEmission));
  51. if(m_commonProps.m_particlesPerEmission == 0)
  52. {
  53. ANKI_RESOURCE_LOGE("Can't accept particlesPerEmission of: %u", m_commonProps.m_particlesPerEmission);
  54. return Error::kUserData;
  55. }
  56. // Inputs
  57. ANKI_CHECK(rootEl.getChildElementOptional("inputs", el));
  58. if(el)
  59. {
  60. XmlElement inputEl;
  61. ANKI_CHECK(el.getChildElement("input", inputEl));
  62. do
  63. {
  64. ANKI_CHECK(parseInput(inputEl));
  65. ANKI_CHECK(inputEl.getNextSiblingElement("input", inputEl));
  66. } while(inputEl);
  67. }
  68. return Error::kNone;
  69. }
  70. Error ParticleEmitterResource2::parseShaderProgram(XmlElement shaderProgramEl, Bool async)
  71. {
  72. // name
  73. CString shaderName;
  74. ANKI_CHECK(shaderProgramEl.getAttributeText("name", shaderName));
  75. ResourceString fname;
  76. fname.sprintf("ShaderBinaries/%s.ankiprogbin", shaderName.cstr());
  77. ANKI_CHECK(ResourceManager::getSingleton().loadResource(fname, m_prog, async));
  78. // <mutation>
  79. ShaderProgramResourceVariantInitInfo variantInitInfo(m_prog);
  80. XmlElement mutatorsEl;
  81. ANKI_CHECK(shaderProgramEl.getChildElementOptional("mutation", mutatorsEl));
  82. if(mutatorsEl)
  83. {
  84. ANKI_CHECK(parseMutators(mutatorsEl, variantInitInfo));
  85. }
  86. // Create the GR prog
  87. variantInitInfo.addMutation("ANKI_WAVE_SIZE", GrManager::getSingleton().getDeviceCapabilities().m_maxWaveSize);
  88. const ShaderProgramResourceVariant* variant;
  89. m_prog->getOrCreateVariant(variantInitInfo, variant);
  90. if(!variant)
  91. {
  92. ANKI_RESOURCE_LOGE("Shader variant creation failed");
  93. return Error::kUserData;
  94. }
  95. m_grProg.reset(&variant->getProgram());
  96. // Create the properties
  97. {
  98. // Find struct
  99. const ShaderBinary& binary = m_prog->getBinary();
  100. const ShaderBinaryStruct* propsStruct = nullptr;
  101. for(const ShaderBinaryStruct& strct : binary.m_structs)
  102. {
  103. if(CString(strct.m_name.getBegin()) == "AnKiParticleEmitterProperties")
  104. {
  105. propsStruct = &strct;
  106. break;
  107. }
  108. }
  109. if(!propsStruct)
  110. {
  111. ANKI_RESOURCE_LOGE("AnKiParticleEmitterProperties struct not found");
  112. return Error::kUserData;
  113. }
  114. m_prefilledAnKiParticleEmitterProperties.resize(propsStruct->m_size, 0_U8);
  115. m_otherProps.resize(propsStruct->m_members.getSize());
  116. for(U32 i = 0; i < propsStruct->m_members.getSize(); ++i)
  117. {
  118. const ShaderBinaryStructMember& member = propsStruct->m_members[i];
  119. const U32 memberSize = getShaderVariableDataTypeInfo(member.m_type).m_size;
  120. ANKI_ASSERT(member.m_offset + memberSize <= propsStruct->m_size);
  121. memcpy(m_prefilledAnKiParticleEmitterProperties.getBegin() + member.m_offset, member.m_defaultValues.getBegin(), memberSize);
  122. // Initialize the property with the default values
  123. ParticleEmitterResourceProperty& prop = m_otherProps[i];
  124. prop.m_offsetInAnKiParticleEmitterProperties = member.m_offset;
  125. prop.m_name = member.m_name.getBegin();
  126. prop.m_dataType = member.m_type;
  127. switch(prop.m_dataType)
  128. {
  129. #define ANKI_SVDT_MACRO(type, baseType, rowCount, columnCount, isIntagralType) \
  130. case ShaderVariableDataType::k##type: \
  131. { \
  132. ANKI_ASSERT(sizeof(prop.m_##type) == memberSize); \
  133. memcpy(&prop.m_##type, member.m_defaultValues.getBegin(), memberSize); \
  134. break; \
  135. }
  136. #include <AnKi/Gr/ShaderVariableDataType.def.h>
  137. default:
  138. ANKI_ASSERT(0);
  139. }
  140. }
  141. }
  142. return Error::kNone;
  143. }
  144. Error ParticleEmitterResource2::parseMutators(XmlElement mutatorsEl, ShaderProgramResourceVariantInitInfo& variantInitInfo)
  145. {
  146. XmlElement mutatorEl;
  147. ANKI_CHECK(mutatorsEl.getChildElement("mutator", mutatorEl));
  148. U32 mutatorCount = 0;
  149. ANKI_CHECK(mutatorEl.getSiblingElementsCount(mutatorCount));
  150. ++mutatorCount;
  151. ANKI_ASSERT(mutatorCount > 0);
  152. do
  153. {
  154. // name
  155. CString mutatorName;
  156. ANKI_CHECK(mutatorEl.getAttributeText("name", mutatorName));
  157. if(mutatorName.isEmpty())
  158. {
  159. ANKI_RESOURCE_LOGE("Mutator name is empty");
  160. return Error::kUserData;
  161. }
  162. if(mutatorName.find("ANKI_") == 0)
  163. {
  164. ANKI_RESOURCE_LOGE("Mutators can't start with ANKI_: %s", mutatorName.cstr());
  165. return Error::kUserData;
  166. }
  167. // value
  168. MutatorValue mval;
  169. ANKI_CHECK(mutatorEl.getAttributeNumber("value", mval));
  170. // Find mutator
  171. const ShaderBinaryMutator* mutator = m_prog->tryFindMutator(mutatorName);
  172. if(!mutator)
  173. {
  174. ANKI_RESOURCE_LOGE("Mutator not found in program %s", &mutatorName[0]);
  175. return Error::kUserData;
  176. }
  177. if(!mutatorValueExists(*mutator, mval))
  178. {
  179. ANKI_RESOURCE_LOGE("Value %d is not part of the mutator %s", mval, mutatorName.cstr());
  180. return Error::kUserData;
  181. }
  182. variantInitInfo.addMutation(mutatorName, mval);
  183. // Advance
  184. ANKI_CHECK(mutatorEl.getNextSiblingElement("mutator", mutatorEl));
  185. } while(mutatorEl);
  186. return Error::kNone;
  187. }
  188. Error ParticleEmitterResource2::parseInput(XmlElement inputEl)
  189. {
  190. // Get var name
  191. CString varName;
  192. ANKI_CHECK(inputEl.getAttributeText("name", varName));
  193. // Find struct
  194. const ShaderBinary& binary = m_prog->getBinary();
  195. const ShaderBinaryStruct* propsStruct = nullptr;
  196. for(const ShaderBinaryStruct& strct : binary.m_structs)
  197. {
  198. if(CString(strct.m_name.getBegin()) == "AnKiParticleEmitterProperties")
  199. {
  200. propsStruct = &strct;
  201. break;
  202. }
  203. }
  204. ANKI_ASSERT(propsStruct);
  205. // Find the member
  206. const ShaderBinaryStructMember* foundMember = nullptr;
  207. U32 foundMemberIdx = kMaxU32;
  208. for(U32 i = 0; i < propsStruct->m_members.getSize(); ++i)
  209. {
  210. const ShaderBinaryStructMember& member = propsStruct->m_members[i];
  211. const CString memberName = member.m_name.getBegin();
  212. if(memberName == varName)
  213. {
  214. foundMember = &member;
  215. foundMemberIdx = i;
  216. break;
  217. }
  218. }
  219. if(!foundMember)
  220. {
  221. ANKI_RESOURCE_LOGE("Input not found in AnKiParticleEmitterProperties: %s", varName.cstr());
  222. return Error::kUserData;
  223. }
  224. const U32 memberSize = getShaderVariableDataTypeInfo(foundMember->m_type).m_size;
  225. const U32 memberOffset = foundMember->m_offset;
  226. ParticleEmitterResourceProperty& prop = m_otherProps[foundMemberIdx];
  227. // Set the value
  228. switch(foundMember->m_type)
  229. {
  230. #define ANKI_SVDT_MACRO(type, baseType, rowCount, columnCount, isIntagralType) \
  231. case ShaderVariableDataType::k##type: \
  232. { \
  233. Array<baseType, rowCount * columnCount> arr; \
  234. ANKI_CHECK(inputEl.getAttributeNumbers("value", arr)); \
  235. ANKI_ASSERT(memberOffset + memberSize <= m_prefilledAnKiParticleEmitterProperties.getSize()); \
  236. ANKI_ASSERT(memberSize == sizeof(arr)); \
  237. memcpy(m_prefilledAnKiParticleEmitterProperties.getBegin() + memberOffset, arr.getBegin(), memberSize); \
  238. memcpy(&prop.m_##type, arr.getBegin(), memberSize); \
  239. break; \
  240. }
  241. #include <AnKi/Gr/ShaderVariableDataType.def.h>
  242. default:
  243. ANKI_ASSERT(0);
  244. break;
  245. }
  246. return Error::kNone;
  247. }
  248. } // end namespace anki