ParticleEffect.cpp 24 KB

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