ParticleEffect.cpp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961
  1. //
  2. // Copyright (c) 2008-2015 the Urho3D project.
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to deal
  6. // in the Software without restriction, including without limitation the rights
  7. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. // copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. // THE SOFTWARE.
  21. //
  22. #include "../Core/Context.h"
  23. #include "../IO/Log.h"
  24. #include "../Graphics/Material.h"
  25. #include "../Graphics/ParticleEffect.h"
  26. #include "../Resource/ResourceCache.h"
  27. #include "../Resource/XMLFile.h"
  28. #include "../DebugNew.h"
  29. namespace Urho3D
  30. {
  31. static const char* emitterTypeNames[] =
  32. {
  33. "Sphere",
  34. "Box",
  35. 0
  36. };
  37. static const Vector2 DEFAULT_PARTICLE_SIZE(0.1f, 0.1f);
  38. static const float DEFAULT_EMISSION_RATE = 10.0f;
  39. static const float MIN_EMISSION_RATE = 0.01f;
  40. static const float DEFAULT_TIME_TO_LIVE = 1.0f;
  41. static const float DEFAULT_VELOCITY = 1.0f;
  42. static const Vector3 DEFAULT_DIRECTION_MIN(-1.0f, -1.0f, -1.0f);
  43. static const Vector3 DEFAULT_DIRECTION_MAX(1.0f, 1.0f, 1.0f);
  44. ParticleEffect::ParticleEffect(Context* context) :
  45. Resource(context),
  46. numParticles_(DEFAULT_NUM_PARTICLES),
  47. updateInvisible_(false),
  48. relative_(true),
  49. scaled_(true),
  50. sorted_(false),
  51. animationLodBias_(0.0f),
  52. emitterType_(EMITTER_SPHERE),
  53. emitterSize_(Vector3::ZERO),
  54. directionMin_(DEFAULT_DIRECTION_MIN),
  55. directionMax_(DEFAULT_DIRECTION_MAX),
  56. constantForce_(Vector3::ZERO),
  57. dampingForce_(0.0f),
  58. activeTime_(0.0f),
  59. inactiveTime_(0.0f),
  60. emissionRateMin_(DEFAULT_EMISSION_RATE),
  61. emissionRateMax_(DEFAULT_EMISSION_RATE),
  62. sizeMin_(DEFAULT_PARTICLE_SIZE),
  63. sizeMax_(DEFAULT_PARTICLE_SIZE),
  64. timeToLiveMin_(DEFAULT_TIME_TO_LIVE),
  65. timeToLiveMax_(DEFAULT_TIME_TO_LIVE),
  66. velocityMin_(DEFAULT_VELOCITY),
  67. velocityMax_(DEFAULT_VELOCITY),
  68. rotationMin_(0.0f),
  69. rotationMax_(0.0f),
  70. rotationSpeedMin_(0.0f),
  71. rotationSpeedMax_(0.0f),
  72. sizeAdd_(0.0f),
  73. sizeMul_(1.0f)
  74. {
  75. }
  76. ParticleEffect::~ParticleEffect()
  77. {
  78. }
  79. void ParticleEffect::RegisterObject(Context* context)
  80. {
  81. context->RegisterFactory<ParticleEffect>();
  82. }
  83. bool ParticleEffect::BeginLoad(Deserializer& source)
  84. {
  85. loadMaterialName_.Clear();
  86. XMLFile file(context_);
  87. if (!file.Load(source))
  88. {
  89. LOGERROR("Load particle effect file failed");
  90. return false;
  91. }
  92. XMLElement rootElem = file.GetRoot();
  93. if (!rootElem)
  94. {
  95. LOGERROR("Particle emitter parameter file does not have a valid root element");
  96. return false;
  97. }
  98. // Reset to defaults first so that missing parameters in case of a live reload behave as expected
  99. material_.Reset();
  100. numParticles_ = DEFAULT_NUM_PARTICLES;
  101. updateInvisible_ = false;
  102. relative_ = true;
  103. scaled_ = true;
  104. sorted_ = false;
  105. animationLodBias_ = 0.0f;
  106. emitterType_ = EMITTER_SPHERE;
  107. emitterSize_ = Vector3::ZERO;
  108. directionMin_ = DEFAULT_DIRECTION_MIN;
  109. directionMax_ = DEFAULT_DIRECTION_MAX;
  110. constantForce_ = Vector3::ZERO;
  111. dampingForce_ = 0.0f;
  112. activeTime_ = 0.0f;
  113. inactiveTime_ = 0.0;
  114. emissionRateMin_ = DEFAULT_EMISSION_RATE;
  115. emissionRateMax_ = DEFAULT_EMISSION_RATE;
  116. sizeMin_ = DEFAULT_PARTICLE_SIZE;
  117. sizeMax_ = DEFAULT_PARTICLE_SIZE;
  118. timeToLiveMin_ = DEFAULT_TIME_TO_LIVE;
  119. timeToLiveMax_ = DEFAULT_TIME_TO_LIVE;
  120. velocityMin_ = DEFAULT_VELOCITY;
  121. velocityMax_ = DEFAULT_VELOCITY;
  122. rotationMin_ = 0.0f;
  123. rotationMax_ = 0.0f;
  124. rotationSpeedMin_ = 0.0f;
  125. rotationSpeedMax_ = 0.0f;
  126. sizeAdd_ = 0.0f;
  127. sizeMul_ = 1.0f;
  128. colorFrames_.Clear();
  129. textureFrames_.Clear();
  130. if (rootElem.HasChild("material"))
  131. {
  132. loadMaterialName_ = rootElem.GetChild("material").GetAttribute("name");
  133. // If async loading, can not GetResource() the material. But can do a background request for it
  134. if (GetAsyncLoadState() == ASYNC_LOADING)
  135. GetSubsystem<ResourceCache>()->BackgroundLoadResource<Material>(loadMaterialName_, true, this);
  136. }
  137. if (rootElem.HasChild("numparticles"))
  138. SetNumParticles(rootElem.GetChild("numparticles").GetInt("value"));
  139. if (rootElem.HasChild("updateinvisible"))
  140. updateInvisible_ = rootElem.GetChild("updateinvisible").GetBool("enable");
  141. if (rootElem.HasChild("relative"))
  142. relative_ = rootElem.GetChild("relative").GetBool("enable");
  143. if (rootElem.HasChild("scaled"))
  144. scaled_ = rootElem.GetChild("scaled").GetBool("enable");
  145. if (rootElem.HasChild("sorted"))
  146. sorted_ = rootElem.GetChild("sorted").GetBool("enable");
  147. if (rootElem.HasChild("animlodbias"))
  148. SetAnimationLodBias(rootElem.GetChild("animlodbias").GetFloat("value"));
  149. if (rootElem.HasChild("emittertype"))
  150. {
  151. String type = rootElem.GetChild("emittertype").GetAttributeLower("value");
  152. if (type == "point")
  153. {
  154. // Point emitter type is deprecated, handled as zero sized sphere
  155. emitterType_ = EMITTER_SPHERE;
  156. emitterSize_ = Vector3::ZERO;
  157. }
  158. else if (type == "box")
  159. emitterType_ = EMITTER_BOX;
  160. else if (type == "sphere")
  161. emitterType_ = EMITTER_SPHERE;
  162. else
  163. LOGERROR("Unknown particle emitter type " + type);
  164. }
  165. if (rootElem.HasChild("emittersize"))
  166. emitterSize_ = rootElem.GetChild("emittersize").GetVector3("value");
  167. if (rootElem.HasChild("emitterradius"))
  168. emitterSize_.x_ = emitterSize_.y_ = emitterSize_.z_ = rootElem.GetChild("emitterradius").GetFloat("value");
  169. if (rootElem.HasChild("direction"))
  170. GetVector3MinMax(rootElem.GetChild("direction"), directionMin_, directionMax_);
  171. if (rootElem.HasChild("constantforce"))
  172. constantForce_ = rootElem.GetChild("constantforce").GetVector3("value");
  173. if (rootElem.HasChild("dampingforce"))
  174. dampingForce_ = rootElem.GetChild("dampingforce").GetFloat("value");
  175. if (rootElem.HasChild("activetime"))
  176. activeTime_ = rootElem.GetChild("activetime").GetFloat("value");
  177. if (activeTime_ < 0.0f)
  178. activeTime_ = M_INFINITY;
  179. if (rootElem.HasChild("inactivetime"))
  180. inactiveTime_ = rootElem.GetChild("inactivetime").GetFloat("value");
  181. if (inactiveTime_ < 0.0f)
  182. inactiveTime_ = M_INFINITY;
  183. if (rootElem.HasChild("emissionrate"))
  184. GetFloatMinMax(rootElem.GetChild("emissionrate"), emissionRateMin_, emissionRateMax_);
  185. if (rootElem.HasChild("interval"))
  186. {
  187. float intervalMin = 0.0f;
  188. float intervalMax = 0.0f;
  189. GetFloatMinMax(rootElem.GetChild("interval"), intervalMin, intervalMax);
  190. emissionRateMax_ = 1.0f / intervalMin;
  191. emissionRateMin_ = 1.0f / intervalMax;
  192. }
  193. if (rootElem.HasChild("particlesize"))
  194. GetVector2MinMax(rootElem.GetChild("particlesize"), sizeMin_, sizeMax_);
  195. if (rootElem.HasChild("timetolive"))
  196. GetFloatMinMax(rootElem.GetChild("timetolive"), timeToLiveMin_, timeToLiveMax_);
  197. if (rootElem.HasChild("velocity"))
  198. GetFloatMinMax(rootElem.GetChild("velocity"), velocityMin_, velocityMax_);
  199. if (rootElem.HasChild("rotation"))
  200. GetFloatMinMax(rootElem.GetChild("rotation"), rotationMin_, rotationMax_);
  201. if (rootElem.HasChild("rotationspeed"))
  202. GetFloatMinMax(rootElem.GetChild("rotationspeed"), rotationSpeedMin_, rotationSpeedMax_);
  203. if (rootElem.HasChild("sizedelta"))
  204. {
  205. XMLElement deltaElem = rootElem.GetChild("sizedelta");
  206. if (deltaElem.HasAttribute("add"))
  207. sizeAdd_ = deltaElem.GetFloat("add");
  208. if (deltaElem.HasAttribute("mul"))
  209. sizeMul_ = deltaElem.GetFloat("mul");
  210. }
  211. if (rootElem.HasChild("color"))
  212. {
  213. ColorFrame colorFrame(rootElem.GetChild("color").GetColor("value"));
  214. SetColorFrame(0, colorFrame);
  215. }
  216. if (rootElem.HasChild("colorfade"))
  217. {
  218. Vector<ColorFrame> fades;
  219. for (XMLElement colorFadeElem = rootElem.GetChild("colorfade"); colorFadeElem; colorFadeElem = colorFadeElem.GetNext("colorfade"))
  220. fades.Push(ColorFrame(colorFadeElem.GetColor("color"), colorFadeElem.GetFloat("time")));
  221. SetColorFrames(fades);
  222. }
  223. if (colorFrames_.Empty())
  224. colorFrames_.Push(ColorFrame(Color::WHITE));
  225. if (rootElem.HasChild("texanim"))
  226. {
  227. Vector<TextureFrame> animations;
  228. for (XMLElement animElem = rootElem.GetChild("texanim"); animElem; animElem = animElem.GetNext("texanim"))
  229. {
  230. TextureFrame animation;
  231. animation.uv_ = animElem.GetRect("uv");
  232. animation.time_ = animElem.GetFloat("time");
  233. animations.Push(animation);
  234. }
  235. SetTextureFrames(animations);
  236. }
  237. return true;
  238. }
  239. bool ParticleEffect::EndLoad()
  240. {
  241. // Apply the material now
  242. if (!loadMaterialName_.Empty())
  243. {
  244. SetMaterial(GetSubsystem<ResourceCache>()->GetResource<Material>(loadMaterialName_));
  245. loadMaterialName_.Clear();
  246. }
  247. return true;
  248. }
  249. bool ParticleEffect::Load(const XMLElement& source)
  250. {
  251. // Reset to defaults first so that missing parameters in case of a live reload behave as expected
  252. material_.Reset();
  253. numParticles_ = DEFAULT_NUM_PARTICLES;
  254. updateInvisible_ = false;
  255. relative_ = true;
  256. scaled_ = true;
  257. sorted_ = false;
  258. animationLodBias_ = 0.0f;
  259. emitterType_ = EMITTER_SPHERE;
  260. emitterSize_ = Vector3::ZERO;
  261. directionMin_ = DEFAULT_DIRECTION_MIN;
  262. directionMax_ = DEFAULT_DIRECTION_MAX;
  263. constantForce_ = Vector3::ZERO;
  264. dampingForce_ = 0.0f;
  265. activeTime_ = 0.0f;
  266. inactiveTime_ = 0.0;
  267. emissionRateMin_ = DEFAULT_EMISSION_RATE;
  268. emissionRateMax_ = DEFAULT_EMISSION_RATE;
  269. sizeMin_ = DEFAULT_PARTICLE_SIZE;
  270. sizeMax_ = DEFAULT_PARTICLE_SIZE;
  271. timeToLiveMin_ = DEFAULT_TIME_TO_LIVE;
  272. timeToLiveMax_ = DEFAULT_TIME_TO_LIVE;
  273. velocityMin_ = DEFAULT_VELOCITY;
  274. velocityMax_ = DEFAULT_VELOCITY;
  275. rotationMin_ = 0.0f;
  276. rotationMax_ = 0.0f;
  277. rotationSpeedMin_ = 0.0f;
  278. rotationSpeedMax_ = 0.0f;
  279. sizeAdd_ = 0.0f;
  280. sizeMul_ = 1.0f;
  281. colorFrames_.Clear();
  282. textureFrames_.Clear();
  283. if (source.IsNull())
  284. {
  285. LOGERROR("Can not load particle effect from null XML element");
  286. return false;
  287. }
  288. if (source.HasChild("material"))
  289. {
  290. material_ = GetSubsystem<ResourceCache>()->GetResource<Material>(source.GetChild("material").GetAttribute("name"));
  291. }
  292. if (source.HasChild("numparticles"))
  293. SetNumParticles(source.GetChild("numparticles").GetInt("value"));
  294. if (source.HasChild("updateinvisible"))
  295. updateInvisible_ = source.GetChild("updateinvisible").GetBool("enable");
  296. if (source.HasChild("relative"))
  297. relative_ = source.GetChild("relative").GetBool("enable");
  298. if (source.HasChild("scaled"))
  299. scaled_ = source.GetChild("scaled").GetBool("enable");
  300. if (source.HasChild("sorted"))
  301. sorted_ = source.GetChild("sorted").GetBool("enable");
  302. if (source.HasChild("animlodbias"))
  303. SetAnimationLodBias(source.GetChild("animlodbias").GetFloat("value"));
  304. if (source.HasChild("emittertype"))
  305. {
  306. String type = source.GetChild("emittertype").GetAttributeLower("value");
  307. if (type == "point")
  308. {
  309. // Point emitter type is deprecated, handled as zero sized sphere
  310. emitterType_ = EMITTER_SPHERE;
  311. emitterSize_ = Vector3::ZERO;
  312. }
  313. else if (type == "box")
  314. emitterType_ = EMITTER_BOX;
  315. else if (type == "sphere")
  316. emitterType_ = EMITTER_SPHERE;
  317. else
  318. LOGERROR("Unknown particle emitter type " + type);
  319. }
  320. if (source.HasChild("emittersize"))
  321. emitterSize_ = source.GetChild("emittersize").GetVector3("value");
  322. if (source.HasChild("emitterradius"))
  323. emitterSize_.x_ = emitterSize_.y_ = emitterSize_.z_ = source.GetChild("emitterradius").GetFloat("value");
  324. if (source.HasChild("direction"))
  325. GetVector3MinMax(source.GetChild("direction"), directionMin_, directionMax_);
  326. if (source.HasChild("constantforce"))
  327. constantForce_ = source.GetChild("constantforce").GetVector3("value");
  328. if (source.HasChild("dampingforce"))
  329. dampingForce_ = source.GetChild("dampingforce").GetFloat("value");
  330. if (source.HasChild("activetime"))
  331. activeTime_ = source.GetChild("activetime").GetFloat("value");
  332. if (activeTime_ < 0.0f)
  333. activeTime_ = M_INFINITY;
  334. if (source.HasChild("inactivetime"))
  335. inactiveTime_ = source.GetChild("inactivetime").GetFloat("value");
  336. if (inactiveTime_ < 0.0f)
  337. inactiveTime_ = M_INFINITY;
  338. if (source.HasChild("emissionrate"))
  339. GetFloatMinMax(source.GetChild("emissionrate"), emissionRateMin_, emissionRateMax_);
  340. if (source.HasChild("interval"))
  341. {
  342. float intervalMin = 0.0f;
  343. float intervalMax = 0.0f;
  344. GetFloatMinMax(source.GetChild("interval"), intervalMin, intervalMax);
  345. emissionRateMax_ = 1.0f / intervalMin;
  346. emissionRateMin_ = 1.0f / intervalMax;
  347. }
  348. if (source.HasChild("particlesize"))
  349. GetVector2MinMax(source.GetChild("particlesize"), sizeMin_, sizeMax_);
  350. if (source.HasChild("timetolive"))
  351. GetFloatMinMax(source.GetChild("timetolive"), timeToLiveMin_, timeToLiveMax_);
  352. if (source.HasChild("velocity"))
  353. GetFloatMinMax(source.GetChild("velocity"), velocityMin_, velocityMax_);
  354. if (source.HasChild("rotation"))
  355. GetFloatMinMax(source.GetChild("rotation"), rotationMin_, rotationMax_);
  356. if (source.HasChild("rotationspeed"))
  357. GetFloatMinMax(source.GetChild("rotationspeed"), rotationSpeedMin_, rotationSpeedMax_);
  358. if (source.HasChild("sizedelta"))
  359. {
  360. XMLElement deltaElem = source.GetChild("sizedelta");
  361. if (deltaElem.HasAttribute("add"))
  362. sizeAdd_ = deltaElem.GetFloat("add");
  363. if (deltaElem.HasAttribute("mul"))
  364. sizeMul_ = deltaElem.GetFloat("mul");
  365. }
  366. if (source.HasChild("color"))
  367. {
  368. ColorFrame colorFrame(source.GetChild("color").GetColor("value"));
  369. SetColorFrame(0, colorFrame);
  370. }
  371. if (source.HasChild("colorfade"))
  372. {
  373. Vector<ColorFrame> fades;
  374. for (XMLElement colorFadeElem = source.GetChild("colorfade"); colorFadeElem; colorFadeElem = colorFadeElem.GetNext("colorfade"))
  375. fades.Push(ColorFrame(colorFadeElem.GetColor("color"), colorFadeElem.GetFloat("time")));
  376. SetColorFrames(fades);
  377. }
  378. if (colorFrames_.Empty())
  379. colorFrames_.Push(ColorFrame(Color::WHITE));
  380. if (source.HasChild("texanim"))
  381. {
  382. Vector<TextureFrame> animations;
  383. for (XMLElement animElem = source.GetChild("texanim"); animElem; animElem = animElem.GetNext("texanim"))
  384. {
  385. TextureFrame animation;
  386. animation.uv_ = animElem.GetRect("uv");
  387. animation.time_ = animElem.GetFloat("time");
  388. animations.Push(animation);
  389. }
  390. SetTextureFrames(animations);
  391. }
  392. return true;
  393. }
  394. bool ParticleEffect::Save(Serializer& dest) const
  395. {
  396. SharedPtr<XMLFile> xml(new XMLFile(context_));
  397. XMLElement materialElem = xml->CreateRoot("particleeffect");
  398. Save(materialElem);
  399. return xml->Save(dest);
  400. }
  401. bool ParticleEffect::Save(XMLElement& dest) const
  402. {
  403. if (dest.IsNull())
  404. {
  405. LOGERROR("Can not save particle effect to null XML element");
  406. return false;
  407. }
  408. XMLElement childElem = dest.CreateChild("material");
  409. childElem.SetAttribute("name", GetResourceName(material_));
  410. childElem = dest.CreateChild("numparticles");
  411. childElem.SetInt("value", numParticles_);
  412. childElem = dest.CreateChild("updateinvisible");
  413. childElem.SetBool("enable", updateInvisible_);
  414. childElem = dest.CreateChild("relative");
  415. childElem.SetBool("enable", relative_);
  416. childElem = dest.CreateChild("scaled");
  417. childElem.SetBool("enable", scaled_);
  418. childElem = dest.CreateChild("sorted");
  419. childElem.SetBool("enable", sorted_);
  420. childElem = dest.CreateChild("animlodbias");
  421. childElem.SetFloat("value", animationLodBias_);
  422. childElem = dest.CreateChild("emittertype");
  423. childElem.SetAttribute("value", emitterTypeNames[emitterType_]);
  424. childElem = dest.CreateChild("emittersize");
  425. childElem.SetVector3("value", emitterSize_);
  426. childElem = dest.CreateChild("direction");
  427. childElem.SetVector3("min", directionMin_);
  428. childElem.SetVector3("max", directionMax_);
  429. childElem = dest.CreateChild("constantforce");
  430. childElem.SetVector3("value", constantForce_);
  431. childElem = dest.CreateChild("dampingforce");
  432. childElem.SetFloat("value", dampingForce_);
  433. childElem = dest.CreateChild("activetime");
  434. childElem.SetFloat("value", activeTime_);
  435. childElem = dest.CreateChild("inactivetime");
  436. childElem.SetFloat("value", inactiveTime_);
  437. childElem = dest.CreateChild("emissionrate");
  438. childElem.SetFloat("min", emissionRateMin_);
  439. childElem.SetFloat("max", emissionRateMax_);
  440. childElem = dest.CreateChild("particlesize");
  441. childElem.SetVector2("min", sizeMin_);
  442. childElem.SetVector2("max", sizeMax_);
  443. childElem = dest.CreateChild("timetolive");
  444. childElem.SetFloat("min", timeToLiveMin_);
  445. childElem.SetFloat("max", timeToLiveMax_);
  446. childElem = dest.CreateChild("velocity");
  447. childElem.SetFloat("min", velocityMin_);
  448. childElem.SetFloat("max", velocityMax_);
  449. childElem = dest.CreateChild("rotation");
  450. childElem.SetFloat("min", rotationMin_);
  451. childElem.SetFloat("max", rotationMax_);
  452. childElem = dest.CreateChild("rotationspeed");
  453. childElem.SetFloat("min", rotationSpeedMin_);
  454. childElem.SetFloat("max", rotationSpeedMax_);
  455. childElem = dest.CreateChild("sizedelta");
  456. childElem.SetFloat("add", sizeAdd_);
  457. childElem.SetFloat("mul", sizeMul_);
  458. if (colorFrames_.Size() == 1)
  459. {
  460. childElem = dest.CreateChild("color");
  461. childElem.SetColor("value", colorFrames_[0].color_);
  462. }
  463. if (colorFrames_.Size() > 1)
  464. {
  465. for (unsigned i = 0; i < colorFrames_.Size(); ++i)
  466. {
  467. childElem = dest.CreateChild("colorfade");
  468. childElem.SetColor("color", colorFrames_[i].color_);
  469. childElem.SetFloat("time", colorFrames_[i].time_);
  470. }
  471. }
  472. for (unsigned i = 0; i < textureFrames_.Size(); ++i)
  473. {
  474. childElem = dest.CreateChild("texanim");
  475. childElem.SetRect("uv", textureFrames_[i].uv_);
  476. childElem.SetFloat("time", textureFrames_[i].time_);
  477. }
  478. return true;
  479. }
  480. void ParticleEffect::SetMaterial(Material* material)
  481. {
  482. material_ = material;
  483. }
  484. void ParticleEffect::SetNumParticles(unsigned num)
  485. {
  486. numParticles_ = Max(0, num);
  487. }
  488. void ParticleEffect::SetUpdateInvisible(bool enable)
  489. {
  490. updateInvisible_ = enable;
  491. }
  492. void ParticleEffect::SetRelative(bool enable)
  493. {
  494. relative_ = enable;
  495. }
  496. void ParticleEffect::SetScaled(bool enable)
  497. {
  498. scaled_ = enable;
  499. }
  500. void ParticleEffect::SetSorted(bool enable)
  501. {
  502. sorted_ = enable;
  503. }
  504. void ParticleEffect::SetAnimationLodBias(float lodBias)
  505. {
  506. animationLodBias_ = lodBias;
  507. }
  508. void ParticleEffect::SetEmitterType(EmitterType type)
  509. {
  510. emitterType_ = type;
  511. }
  512. void ParticleEffect::SetEmitterSize(const Vector3& size)
  513. {
  514. emitterSize_ = size;
  515. }
  516. void ParticleEffect::SetMinDirection(const Vector3& direction)
  517. {
  518. directionMin_ = direction;
  519. }
  520. void ParticleEffect::SetMaxDirection(const Vector3& direction)
  521. {
  522. directionMax_ = direction;
  523. }
  524. void ParticleEffect::SetConstantForce(const Vector3& force)
  525. {
  526. constantForce_ = force;
  527. }
  528. void ParticleEffect::SetDampingForce(float force)
  529. {
  530. dampingForce_ = force;
  531. }
  532. void ParticleEffect::SetActiveTime(float time)
  533. {
  534. activeTime_ = time;
  535. }
  536. void ParticleEffect::SetInactiveTime(float time)
  537. {
  538. inactiveTime_ = time;
  539. }
  540. void ParticleEffect::SetMinEmissionRate(float rate)
  541. {
  542. emissionRateMin_ = Max(rate, MIN_EMISSION_RATE);
  543. }
  544. void ParticleEffect::SetMaxEmissionRate(float rate)
  545. {
  546. emissionRateMax_ = Max(rate, MIN_EMISSION_RATE);
  547. }
  548. void ParticleEffect::SetMinParticleSize(const Vector2& size)
  549. {
  550. sizeMin_ = size;
  551. }
  552. void ParticleEffect::SetMaxParticleSize(const Vector2& size)
  553. {
  554. sizeMax_ = size;
  555. }
  556. void ParticleEffect::SetMinTimeToLive(float time)
  557. {
  558. timeToLiveMin_ = Max(time, 0.0f);
  559. }
  560. void ParticleEffect::SetMaxTimeToLive(float time)
  561. {
  562. timeToLiveMax_ = Max(time, 0.0f);
  563. }
  564. void ParticleEffect::SetMinVelocity(float velocity)
  565. {
  566. velocityMin_ = velocity;
  567. }
  568. void ParticleEffect::SetMaxVelocity(float velocity)
  569. {
  570. velocityMax_ = velocity;
  571. }
  572. void ParticleEffect::SetMinRotation(float rotation)
  573. {
  574. rotationMin_ = rotation;
  575. }
  576. void ParticleEffect::SetMaxRotation(float rotation)
  577. {
  578. rotationMax_ = rotation;
  579. }
  580. void ParticleEffect::SetMinRotationSpeed(float speed)
  581. {
  582. rotationSpeedMin_ = speed;
  583. }
  584. void ParticleEffect::SetMaxRotationSpeed(float speed)
  585. {
  586. rotationSpeedMax_ = speed;
  587. }
  588. void ParticleEffect::SetSizeAdd(float sizeAdd)
  589. {
  590. sizeAdd_ = sizeAdd;
  591. }
  592. void ParticleEffect::SetSizeMul(float sizeMul)
  593. {
  594. sizeMul_ = sizeMul;
  595. }
  596. void ParticleEffect::AddColorTime(const Color& color, const float time)
  597. {
  598. unsigned s = colorFrames_.Size();
  599. colorFrames_.Resize(s + 1);
  600. for (unsigned i = 0; i < s; i++)
  601. {
  602. if (colorFrames_[i].time_ > time)
  603. {
  604. for (unsigned j = s; j > i; j--)
  605. {
  606. colorFrames_[j].color_ = colorFrames_[j - 1].color_;
  607. colorFrames_[j].time_ = colorFrames_[j - 1].time_;
  608. }
  609. colorFrames_[i].color_ = color;
  610. colorFrames_[i].time_ = time;
  611. return;
  612. }
  613. }
  614. // highest time, add last:
  615. colorFrames_[s].color_ = color;
  616. colorFrames_[s].time_ = time;
  617. }
  618. void ParticleEffect::AddColorFrame(const ColorFrame& colorFrame)
  619. {
  620. AddColorTime(colorFrame.color_, colorFrame.time_);
  621. }
  622. void ParticleEffect::RemoveColorFrame(unsigned index)
  623. {
  624. unsigned s = colorFrames_.Size();
  625. for (unsigned i = index; i < s - 1 ; i++)
  626. {
  627. colorFrames_[i].color_ = colorFrames_[i + 1].color_;
  628. colorFrames_[i].time_ = colorFrames_[i + 1].time_;
  629. }
  630. colorFrames_.Resize(s - 1);
  631. }
  632. void ParticleEffect::SetColorFrames(const Vector<ColorFrame>& colorFrames)
  633. {
  634. colorFrames_ = colorFrames;
  635. }
  636. void ParticleEffect::SetColorFrame(unsigned index, const ColorFrame& colorFrame)
  637. {
  638. if (colorFrames_.Size() < index + 1)
  639. colorFrames_.Resize(index + 1);
  640. colorFrames_[index] = colorFrame;
  641. }
  642. void ParticleEffect::SetNumColorFrames(unsigned number)
  643. {
  644. unsigned s = colorFrames_.Size();
  645. if (s != number)
  646. colorFrames_.Resize(number);
  647. }
  648. void ParticleEffect::SortColorFrames()
  649. {
  650. Vector<ColorFrame> cf = colorFrames_;
  651. colorFrames_.Clear();
  652. for (unsigned i = 0; i < cf.Size(); i++)
  653. AddColorFrame(cf[i]);
  654. }
  655. void ParticleEffect::AddTextureTime(const Rect& uv, const float time)
  656. {
  657. unsigned s = textureFrames_.Size();
  658. textureFrames_.Resize(s + 1);
  659. for (unsigned i = 0; i < s; i++)
  660. {
  661. if (textureFrames_[i].time_ > time)
  662. {
  663. for (unsigned j = s; j > i; j--)
  664. {
  665. textureFrames_[j].uv_ = textureFrames_[j - 1].uv_;
  666. textureFrames_[j].time_ = textureFrames_[j - 1].time_;
  667. }
  668. textureFrames_[i].uv_ = uv;
  669. textureFrames_[i].time_ = time;
  670. return;
  671. }
  672. }
  673. // highest time, add last:
  674. textureFrames_[s].uv_ = uv;
  675. textureFrames_[s].time_ = time;
  676. }
  677. void ParticleEffect::AddTextureFrame(const TextureFrame& textureFrame)
  678. {
  679. AddTextureTime(textureFrame.uv_, textureFrame.time_);
  680. }
  681. void ParticleEffect::RemoveTextureFrame(unsigned index)
  682. {
  683. unsigned s = textureFrames_.Size();
  684. for (unsigned i = index; i < s - 1 ; i++)
  685. {
  686. textureFrames_[i].uv_ = textureFrames_[i + 1].uv_;
  687. textureFrames_[i].time_ = textureFrames_[i + 1].time_;
  688. }
  689. textureFrames_.Resize(s - 1);
  690. }
  691. void ParticleEffect::SetTextureFrames(const Vector<TextureFrame>& textureFrames)
  692. {
  693. textureFrames_ = textureFrames;
  694. }
  695. void ParticleEffect::SetTextureFrame(unsigned index, const TextureFrame& textureFrame)
  696. {
  697. if (textureFrames_.Size() < index + 1)
  698. textureFrames_.Resize(index + 1);
  699. textureFrames_[index] = textureFrame;
  700. }
  701. void ParticleEffect::SetNumTextureFrames(unsigned number)
  702. {
  703. unsigned s = textureFrames_.Size();
  704. if (s != number)
  705. textureFrames_.Resize(number);
  706. }
  707. void ParticleEffect::SortTextureFrames()
  708. {
  709. Vector<TextureFrame> tf = textureFrames_;
  710. textureFrames_.Clear();
  711. for (unsigned i = 0; i < tf.Size(); i++)
  712. AddTextureFrame(tf[i]);
  713. }
  714. const ColorFrame* ParticleEffect::GetColorFrame(unsigned index) const
  715. {
  716. return index < colorFrames_.Size() ? &colorFrames_[index] : (ColorFrame*)0;
  717. }
  718. const TextureFrame* ParticleEffect::GetTextureFrame(unsigned index) const
  719. {
  720. return index < textureFrames_.Size() ? &textureFrames_[index] : (TextureFrame*)0;
  721. }
  722. Vector3 ParticleEffect::GetRandomDirection() const
  723. {
  724. return Vector3(
  725. Lerp(directionMin_.x_, directionMax_.x_, Random(1.0f)),
  726. Lerp(directionMin_.y_, directionMax_.y_, Random(1.0f)),
  727. Lerp(directionMin_.z_, directionMax_.z_, Random(1.0f))
  728. );
  729. }
  730. Vector2 ParticleEffect::GetRandomSize() const
  731. {
  732. return sizeMin_.Lerp(sizeMax_, Random(1.0f));
  733. }
  734. float ParticleEffect::GetRandomVelocity() const
  735. {
  736. return Lerp(velocityMin_, velocityMax_, Random(1.0f));
  737. }
  738. float ParticleEffect::GetRandomTimeToLive() const
  739. {
  740. return Lerp(timeToLiveMin_, timeToLiveMax_, Random(1.0f));
  741. }
  742. float ParticleEffect::GetRandomRotationSpeed() const
  743. {
  744. return Lerp(rotationSpeedMin_, rotationSpeedMax_, Random(1.0f));
  745. }
  746. float ParticleEffect::GetRandomRotation() const
  747. {
  748. return Lerp(rotationMin_, rotationMax_, Random(1.0f));
  749. }
  750. void ParticleEffect::GetFloatMinMax(const XMLElement& element, float& minValue, float& maxValue)
  751. {
  752. if (element.IsNull())
  753. return;
  754. if (element.HasAttribute("value"))
  755. minValue = maxValue = element.GetFloat("value");
  756. if (element.HasAttribute("min") && element.HasAttribute("max"))
  757. {
  758. minValue = element.GetFloat("min");
  759. maxValue = element.GetFloat("max");
  760. }
  761. }
  762. void ParticleEffect::GetVector2MinMax(const XMLElement& element, Vector2& minValue, Vector2& maxValue)
  763. {
  764. if (element.IsNull())
  765. return;
  766. if (element.HasAttribute("value"))
  767. minValue = maxValue = element.GetVector2("value");
  768. if (element.HasAttribute("min") && element.HasAttribute("max"))
  769. {
  770. minValue = element.GetVector2("min");
  771. maxValue = element.GetVector2("max");
  772. }
  773. }
  774. void ParticleEffect::GetVector3MinMax(const XMLElement& element, Vector3& minValue, Vector3& maxValue)
  775. {
  776. if (element.IsNull())
  777. return;
  778. if (element.HasAttribute("value"))
  779. minValue = maxValue = element.GetVector3("value");
  780. if (element.HasAttribute("min") && element.HasAttribute("max"))
  781. {
  782. minValue = element.GetVector3("min");
  783. maxValue = element.GetVector3("max");
  784. }
  785. }
  786. }