CParticleSystemSceneNode.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721
  1. // Copyright (C) 2002-2012 Nikolaus Gebhardt
  2. // This file is part of the "Irrlicht Engine".
  3. // For conditions of distribution and use, see copyright notice in irrlicht.h
  4. #include "CParticleSystemSceneNode.h"
  5. #include "os.h"
  6. #include "ISceneManager.h"
  7. #include "ICameraSceneNode.h"
  8. #include "IVideoDriver.h"
  9. #include "CParticleAnimatedMeshSceneNodeEmitter.h"
  10. #include "CParticleBoxEmitter.h"
  11. #include "CParticleCylinderEmitter.h"
  12. #include "CParticleMeshEmitter.h"
  13. #include "CParticlePointEmitter.h"
  14. #include "CParticleRingEmitter.h"
  15. #include "CParticleSphereEmitter.h"
  16. #include "CParticleAttractionAffector.h"
  17. #include "CParticleFadeOutAffector.h"
  18. #include "CParticleGravityAffector.h"
  19. #include "CParticleRotationAffector.h"
  20. #include "CParticleScaleAffector.h"
  21. #include "SViewFrustum.h"
  22. namespace irr
  23. {
  24. namespace scene
  25. {
  26. //! constructor
  27. CParticleSystemSceneNode::CParticleSystemSceneNode(bool createDefaultEmitter,
  28. ISceneNode* parent, ISceneManager* mgr, s32 id,
  29. const core::vector3df& position, const core::vector3df& rotation,
  30. const core::vector3df& scale)
  31. : IParticleSystemSceneNode(parent, mgr, id, position, rotation, scale),
  32. Emitter(0), ParticleSize(core::dimension2d<f32>(5.0f, 5.0f)), LastEmitTime(0),
  33. MaxParticles(0xffff), Buffer(0), ParticlesAreGlobal(true)
  34. {
  35. #ifdef _DEBUG
  36. setDebugName("CParticleSystemSceneNode");
  37. #endif
  38. Buffer = new SMeshBuffer();
  39. if (createDefaultEmitter)
  40. {
  41. IParticleEmitter* e = createBoxEmitter();
  42. setEmitter(e);
  43. e->drop();
  44. }
  45. }
  46. //! destructor
  47. CParticleSystemSceneNode::~CParticleSystemSceneNode()
  48. {
  49. if (Emitter)
  50. Emitter->drop();
  51. if (Buffer)
  52. Buffer->drop();
  53. removeAllAffectors();
  54. }
  55. //! Gets the particle emitter, which creates the particles.
  56. IParticleEmitter* CParticleSystemSceneNode::getEmitter()
  57. {
  58. return Emitter;
  59. }
  60. //! Sets the particle emitter, which creates the particles.
  61. void CParticleSystemSceneNode::setEmitter(IParticleEmitter* emitter)
  62. {
  63. if (emitter == Emitter)
  64. return;
  65. if (Emitter)
  66. Emitter->drop();
  67. Emitter = emitter;
  68. if (Emitter)
  69. Emitter->grab();
  70. }
  71. //! Adds new particle effector to the particle system.
  72. void CParticleSystemSceneNode::addAffector(IParticleAffector* affector)
  73. {
  74. affector->grab();
  75. AffectorList.push_back(affector);
  76. }
  77. //! Get a list of all particle affectors.
  78. const core::list<IParticleAffector*>& CParticleSystemSceneNode::getAffectors() const
  79. {
  80. return AffectorList;
  81. }
  82. //! Removes all particle affectors in the particle system.
  83. void CParticleSystemSceneNode::removeAllAffectors()
  84. {
  85. core::list<IParticleAffector*>::Iterator it = AffectorList.begin();
  86. while (it != AffectorList.end())
  87. {
  88. (*it)->drop();
  89. it = AffectorList.erase(it);
  90. }
  91. }
  92. //! Returns the material based on the zero based index i.
  93. video::SMaterial& CParticleSystemSceneNode::getMaterial(u32 i)
  94. {
  95. return Buffer->Material;
  96. }
  97. //! Returns amount of materials used by this scene node.
  98. u32 CParticleSystemSceneNode::getMaterialCount() const
  99. {
  100. return 1;
  101. }
  102. //! Creates a particle emitter for an animated mesh scene node
  103. IParticleAnimatedMeshSceneNodeEmitter*
  104. CParticleSystemSceneNode::createAnimatedMeshSceneNodeEmitter(
  105. scene::IAnimatedMeshSceneNode* node, bool useNormalDirection,
  106. const core::vector3df& direction, f32 normalDirectionModifier,
  107. s32 mbNumber, bool everyMeshVertex,
  108. u32 minParticlesPerSecond, u32 maxParticlesPerSecond,
  109. const video::SColor& minStartColor, const video::SColor& maxStartColor,
  110. u32 lifeTimeMin, u32 lifeTimeMax, s32 maxAngleDegrees,
  111. const core::dimension2df& minStartSize,
  112. const core::dimension2df& maxStartSize )
  113. {
  114. return new CParticleAnimatedMeshSceneNodeEmitter( node,
  115. useNormalDirection, direction, normalDirectionModifier,
  116. mbNumber, everyMeshVertex,
  117. minParticlesPerSecond, maxParticlesPerSecond,
  118. minStartColor, maxStartColor,
  119. lifeTimeMin, lifeTimeMax, maxAngleDegrees,
  120. minStartSize, maxStartSize );
  121. }
  122. //! Creates a box particle emitter.
  123. IParticleBoxEmitter* CParticleSystemSceneNode::createBoxEmitter(
  124. const core::aabbox3df& box, const core::vector3df& direction,
  125. u32 minParticlesPerSecond, u32 maxParticlesPerSecond,
  126. const video::SColor& minStartColor, const video::SColor& maxStartColor,
  127. u32 lifeTimeMin, u32 lifeTimeMax,
  128. s32 maxAngleDegrees, const core::dimension2df& minStartSize,
  129. const core::dimension2df& maxStartSize )
  130. {
  131. return new CParticleBoxEmitter(box, direction, minParticlesPerSecond,
  132. maxParticlesPerSecond, minStartColor, maxStartColor,
  133. lifeTimeMin, lifeTimeMax, maxAngleDegrees,
  134. minStartSize, maxStartSize );
  135. }
  136. //! Creates a particle emitter for emitting from a cylinder
  137. IParticleCylinderEmitter* CParticleSystemSceneNode::createCylinderEmitter(
  138. const core::vector3df& center, f32 radius,
  139. const core::vector3df& normal, f32 length,
  140. bool outlineOnly, const core::vector3df& direction,
  141. u32 minParticlesPerSecond, u32 maxParticlesPerSecond,
  142. const video::SColor& minStartColor, const video::SColor& maxStartColor,
  143. u32 lifeTimeMin, u32 lifeTimeMax, s32 maxAngleDegrees,
  144. const core::dimension2df& minStartSize,
  145. const core::dimension2df& maxStartSize )
  146. {
  147. return new CParticleCylinderEmitter( center, radius, normal, length,
  148. outlineOnly, direction,
  149. minParticlesPerSecond, maxParticlesPerSecond,
  150. minStartColor, maxStartColor,
  151. lifeTimeMin, lifeTimeMax, maxAngleDegrees,
  152. minStartSize, maxStartSize );
  153. }
  154. //! Creates a mesh particle emitter.
  155. IParticleMeshEmitter* CParticleSystemSceneNode::createMeshEmitter(
  156. scene::IMesh* mesh, bool useNormalDirection,
  157. const core::vector3df& direction, f32 normalDirectionModifier,
  158. s32 mbNumber, bool everyMeshVertex,
  159. u32 minParticlesPerSecond, u32 maxParticlesPerSecond,
  160. const video::SColor& minStartColor, const video::SColor& maxStartColor,
  161. u32 lifeTimeMin, u32 lifeTimeMax, s32 maxAngleDegrees,
  162. const core::dimension2df& minStartSize,
  163. const core::dimension2df& maxStartSize)
  164. {
  165. return new CParticleMeshEmitter( mesh, useNormalDirection, direction,
  166. normalDirectionModifier, mbNumber, everyMeshVertex,
  167. minParticlesPerSecond, maxParticlesPerSecond,
  168. minStartColor, maxStartColor,
  169. lifeTimeMin, lifeTimeMax, maxAngleDegrees,
  170. minStartSize, maxStartSize );
  171. }
  172. //! Creates a point particle emitter.
  173. IParticlePointEmitter* CParticleSystemSceneNode::createPointEmitter(
  174. const core::vector3df& direction, u32 minParticlesPerSecond,
  175. u32 maxParticlesPerSecond, const video::SColor& minStartColor,
  176. const video::SColor& maxStartColor, u32 lifeTimeMin, u32 lifeTimeMax,
  177. s32 maxAngleDegrees, const core::dimension2df& minStartSize,
  178. const core::dimension2df& maxStartSize )
  179. {
  180. return new CParticlePointEmitter(direction, minParticlesPerSecond,
  181. maxParticlesPerSecond, minStartColor, maxStartColor,
  182. lifeTimeMin, lifeTimeMax, maxAngleDegrees,
  183. minStartSize, maxStartSize );
  184. }
  185. //! Creates a ring particle emitter.
  186. IParticleRingEmitter* CParticleSystemSceneNode::createRingEmitter(
  187. const core::vector3df& center, f32 radius, f32 ringThickness,
  188. const core::vector3df& direction,
  189. u32 minParticlesPerSecond, u32 maxParticlesPerSecond,
  190. const video::SColor& minStartColor, const video::SColor& maxStartColor,
  191. u32 lifeTimeMin, u32 lifeTimeMax, s32 maxAngleDegrees,
  192. const core::dimension2df& minStartSize, const core::dimension2df& maxStartSize )
  193. {
  194. return new CParticleRingEmitter( center, radius, ringThickness, direction,
  195. minParticlesPerSecond, maxParticlesPerSecond, minStartColor,
  196. maxStartColor, lifeTimeMin, lifeTimeMax, maxAngleDegrees,
  197. minStartSize, maxStartSize );
  198. }
  199. //! Creates a sphere particle emitter.
  200. IParticleSphereEmitter* CParticleSystemSceneNode::createSphereEmitter(
  201. const core::vector3df& center, f32 radius, const core::vector3df& direction,
  202. u32 minParticlesPerSecond, u32 maxParticlesPerSecond,
  203. const video::SColor& minStartColor, const video::SColor& maxStartColor,
  204. u32 lifeTimeMin, u32 lifeTimeMax,
  205. s32 maxAngleDegrees, const core::dimension2df& minStartSize,
  206. const core::dimension2df& maxStartSize )
  207. {
  208. return new CParticleSphereEmitter(center, radius, direction,
  209. minParticlesPerSecond, maxParticlesPerSecond,
  210. minStartColor, maxStartColor,
  211. lifeTimeMin, lifeTimeMax, maxAngleDegrees,
  212. minStartSize, maxStartSize );
  213. }
  214. //! Creates a point attraction affector. This affector modifies the positions of the
  215. //! particles and attracts them to a specified point at a specified speed per second.
  216. IParticleAttractionAffector* CParticleSystemSceneNode::createAttractionAffector(
  217. const core::vector3df& point, f32 speed, bool attract,
  218. bool affectX, bool affectY, bool affectZ )
  219. {
  220. return new CParticleAttractionAffector( point, speed, attract, affectX, affectY, affectZ );
  221. }
  222. //! Creates a scale particle affector.
  223. IParticleAffector* CParticleSystemSceneNode::createScaleParticleAffector(const core::dimension2df& scaleTo)
  224. {
  225. return new CParticleScaleAffector(scaleTo);
  226. }
  227. //! Creates a fade out particle affector.
  228. IParticleFadeOutAffector* CParticleSystemSceneNode::createFadeOutParticleAffector(
  229. const video::SColor& targetColor, u32 timeNeededToFadeOut)
  230. {
  231. return new CParticleFadeOutAffector(targetColor, timeNeededToFadeOut);
  232. }
  233. //! Creates a gravity affector.
  234. IParticleGravityAffector* CParticleSystemSceneNode::createGravityAffector(
  235. const core::vector3df& gravity, u32 timeForceLost)
  236. {
  237. return new CParticleGravityAffector(gravity, timeForceLost);
  238. }
  239. //! Creates a rotation affector. This affector rotates the particles around a specified pivot
  240. //! point. The speed represents Degrees of rotation per second.
  241. IParticleRotationAffector* CParticleSystemSceneNode::createRotationAffector(
  242. const core::vector3df& speed, const core::vector3df& pivotPoint )
  243. {
  244. return new CParticleRotationAffector( speed, pivotPoint );
  245. }
  246. //! pre render event
  247. void CParticleSystemSceneNode::OnRegisterSceneNode()
  248. {
  249. doParticleSystem(os::Timer::getTime());
  250. if (IsVisible && (Particles.size() != 0))
  251. {
  252. SceneManager->registerNodeForRendering(this);
  253. ISceneNode::OnRegisterSceneNode();
  254. }
  255. }
  256. //! render
  257. void CParticleSystemSceneNode::render()
  258. {
  259. video::IVideoDriver* driver = SceneManager->getVideoDriver();
  260. ICameraSceneNode* camera = SceneManager->getActiveCamera();
  261. if (!camera || !driver)
  262. return;
  263. #if 0
  264. // calculate vectors for letting particles look to camera
  265. core::vector3df view(camera->getTarget() - camera->getAbsolutePosition());
  266. view.normalize();
  267. view *= -1.0f;
  268. #else
  269. const core::matrix4 &m = camera->getViewFrustum()->getTransform( video::ETS_VIEW );
  270. const core::vector3df view ( -m[2], -m[6] , -m[10] );
  271. #endif
  272. // reallocate arrays, if they are too small
  273. reallocateBuffers();
  274. // create particle vertex data
  275. s32 idx = 0;
  276. for (u32 i=0; i<Particles.size(); ++i)
  277. {
  278. const SParticle& particle = Particles[i];
  279. drawBillboardParticle(idx, particle, view, m);
  280. idx +=4;
  281. }
  282. // render all
  283. core::matrix4 mat;
  284. if (!ParticlesAreGlobal)
  285. mat.setTranslation(AbsoluteTransformation.getTranslation());
  286. driver->setTransform(video::ETS_WORLD, mat);
  287. driver->setMaterial(Buffer->Material);
  288. driver->drawVertexPrimitiveList(Buffer->getVertices(), Particles.size()*4,
  289. Buffer->getIndices(), Particles.size()*2, video::EVT_STANDARD, EPT_TRIANGLES,Buffer->getIndexType());
  290. // for debug purposes only:
  291. if ( DebugDataVisible & scene::EDS_BBOX )
  292. {
  293. driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
  294. video::SMaterial deb_m;
  295. deb_m.Lighting = false;
  296. driver->setMaterial(deb_m);
  297. driver->draw3DBox(Buffer->BoundingBox, video::SColor(0,255,255,255));
  298. }
  299. }
  300. //! Draw billboard particle
  301. void CParticleSystemSceneNode::drawBillboardParticle(const irr::s32 &idx,
  302. const SParticle &particle, const core::vector3df &view, const irr::core::matrix4 &m)
  303. {
  304. f32 f;
  305. f = 0.5f * particle.size.Width;
  306. const core::vector3df horizontal ( m[0] * f, m[4] * f, m[8] * f );
  307. f = -0.5f * particle.size.Height;
  308. const core::vector3df vertical ( m[1] * f, m[5] * f, m[9] * f );
  309. Buffer->Vertices[0+idx].Pos = particle.pos + horizontal + vertical;
  310. Buffer->Vertices[0+idx].Color = particle.color;
  311. Buffer->Vertices[0+idx].Normal = view;
  312. Buffer->Vertices[1+idx].Pos = particle.pos + horizontal - vertical;
  313. Buffer->Vertices[1+idx].Color = particle.color;
  314. Buffer->Vertices[1+idx].Normal = view;
  315. Buffer->Vertices[2+idx].Pos = particle.pos - horizontal - vertical;
  316. Buffer->Vertices[2+idx].Color = particle.color;
  317. Buffer->Vertices[2+idx].Normal = view;
  318. Buffer->Vertices[3+idx].Pos = particle.pos - horizontal + vertical;
  319. Buffer->Vertices[3+idx].Color = particle.color;
  320. Buffer->Vertices[3+idx].Normal = view;
  321. }
  322. //! returns the axis aligned bounding box of this node
  323. const core::aabbox3d<f32>& CParticleSystemSceneNode::getBoundingBox() const
  324. {
  325. return Buffer->getBoundingBox();
  326. }
  327. void CParticleSystemSceneNode::doParticleSystem(u32 time)
  328. {
  329. if (LastEmitTime==0)
  330. {
  331. LastEmitTime = time;
  332. return;
  333. }
  334. u32 now = time;
  335. u32 timediff = time - LastEmitTime;
  336. LastEmitTime = time;
  337. // run emitter
  338. if (Emitter && IsVisible)
  339. {
  340. SParticle* array = 0;
  341. s32 newParticles = Emitter->emitt(now, timediff, array);
  342. if (newParticles && array)
  343. {
  344. s32 j=Particles.size();
  345. if (newParticles > 16250-j)
  346. newParticles=16250-j;
  347. Particles.set_used(j+newParticles);
  348. for (s32 i=j; i<j+newParticles; ++i)
  349. {
  350. Particles[i]=array[i-j];
  351. AbsoluteTransformation.rotateVect(Particles[i].startVector);
  352. if (ParticlesAreGlobal)
  353. AbsoluteTransformation.transformVect(Particles[i].pos);
  354. }
  355. }
  356. }
  357. // run affectors
  358. core::list<IParticleAffector*>::Iterator ait = AffectorList.begin();
  359. for (; ait != AffectorList.end(); ++ait)
  360. (*ait)->affect(now, Particles.pointer(), Particles.size());
  361. if (ParticlesAreGlobal)
  362. Buffer->BoundingBox.reset(AbsoluteTransformation.getTranslation());
  363. else
  364. Buffer->BoundingBox.reset(core::vector3df(0,0,0));
  365. // animate all particles
  366. f32 scale = (f32)timediff;
  367. for (u32 i=0; i<Particles.size();)
  368. {
  369. // erase is pretty expensive!
  370. if (now > Particles[i].endTime)
  371. {
  372. // Particle order does not seem to matter.
  373. // So we can delete by switching with last particle and deleting that one.
  374. // This is a lot faster and speed is very important here as the erase otherwise
  375. // can cause noticable freezes.
  376. Particles[i] = Particles[Particles.size()-1];
  377. Particles.erase( Particles.size()-1 );
  378. }
  379. else
  380. {
  381. Particles[i].pos += (Particles[i].vector * scale);
  382. Buffer->BoundingBox.addInternalPoint(Particles[i].pos);
  383. ++i;
  384. }
  385. }
  386. const f32 m = (ParticleSize.Width > ParticleSize.Height ? ParticleSize.Width : ParticleSize.Height) * 0.5f;
  387. Buffer->BoundingBox.MaxEdge.X += m;
  388. Buffer->BoundingBox.MaxEdge.Y += m;
  389. Buffer->BoundingBox.MaxEdge.Z += m;
  390. Buffer->BoundingBox.MinEdge.X -= m;
  391. Buffer->BoundingBox.MinEdge.Y -= m;
  392. Buffer->BoundingBox.MinEdge.Z -= m;
  393. if (ParticlesAreGlobal)
  394. {
  395. core::matrix4 absinv( AbsoluteTransformation, core::matrix4::EM4CONST_INVERSE );
  396. absinv.transformBoxEx(Buffer->BoundingBox);
  397. }
  398. }
  399. //! Sets if the particles should be global. If it is, the particles are affected by
  400. //! the movement of the particle system scene node too, otherwise they completely
  401. //! ignore it. Default is true.
  402. void CParticleSystemSceneNode::setParticlesAreGlobal(bool global)
  403. {
  404. ParticlesAreGlobal = global;
  405. }
  406. //! Remove all currently visible particles
  407. void CParticleSystemSceneNode::clearParticles()
  408. {
  409. Particles.set_used(0);
  410. }
  411. //! Sets the size of all particles.
  412. void CParticleSystemSceneNode::setParticleSize(const core::dimension2d<f32> &size)
  413. {
  414. os::Printer::log("setParticleSize is deprecated, use setMinStartSize/setMaxStartSize in emitter.", irr::ELL_WARNING);
  415. //A bit of a hack, but better here than in the particle code
  416. if (Emitter)
  417. {
  418. Emitter->setMinStartSize(size);
  419. Emitter->setMaxStartSize(size);
  420. }
  421. ParticleSize = size;
  422. }
  423. void CParticleSystemSceneNode::reallocateBuffers()
  424. {
  425. if (Particles.size() * 4 > Buffer->getVertexCount() ||
  426. Particles.size() * 6 > Buffer->getIndexCount())
  427. {
  428. u32 oldSize = Buffer->getVertexCount();
  429. Buffer->Vertices.set_used(Particles.size() * 4);
  430. u32 i;
  431. // fill remaining vertices
  432. for (i=oldSize; i<Buffer->Vertices.size(); i+=4)
  433. {
  434. Buffer->Vertices[0+i].TCoords.set(0.0f, 0.0f);
  435. Buffer->Vertices[1+i].TCoords.set(0.0f, 1.0f);
  436. Buffer->Vertices[2+i].TCoords.set(1.0f, 1.0f);
  437. Buffer->Vertices[3+i].TCoords.set(1.0f, 0.0f);
  438. }
  439. // fill remaining indices
  440. u32 oldIdxSize = Buffer->getIndexCount();
  441. u32 oldvertices = oldSize;
  442. Buffer->Indices.set_used(Particles.size() * 6);
  443. for (i=oldIdxSize; i<Buffer->Indices.size(); i+=6)
  444. {
  445. Buffer->Indices[0+i] = (u16)0+oldvertices;
  446. Buffer->Indices[1+i] = (u16)2+oldvertices;
  447. Buffer->Indices[2+i] = (u16)1+oldvertices;
  448. Buffer->Indices[3+i] = (u16)0+oldvertices;
  449. Buffer->Indices[4+i] = (u16)3+oldvertices;
  450. Buffer->Indices[5+i] = (u16)2+oldvertices;
  451. oldvertices += 4;
  452. }
  453. }
  454. }
  455. //! Writes attributes of the scene node.
  456. void CParticleSystemSceneNode::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const
  457. {
  458. IParticleSystemSceneNode::serializeAttributes(out, options);
  459. out->addBool("GlobalParticles", ParticlesAreGlobal);
  460. out->addFloat("ParticleWidth", ParticleSize.Width);
  461. out->addFloat("ParticleHeight", ParticleSize.Height);
  462. // write emitter
  463. E_PARTICLE_EMITTER_TYPE type = EPET_COUNT;
  464. if (Emitter)
  465. type = Emitter->getType();
  466. out->addEnum("Emitter", (s32)type, ParticleEmitterTypeNames);
  467. if (Emitter)
  468. Emitter->serializeAttributes(out, options);
  469. // write affectors
  470. E_PARTICLE_AFFECTOR_TYPE atype = EPAT_NONE;
  471. for (core::list<IParticleAffector*>::ConstIterator it = AffectorList.begin();
  472. it != AffectorList.end(); ++it)
  473. {
  474. atype = (*it)->getType();
  475. out->addEnum("Affector", (s32)atype, ParticleAffectorTypeNames);
  476. (*it)->serializeAttributes(out);
  477. }
  478. // add empty affector to make it possible to add further affectors
  479. if (options && options->Flags & io::EARWF_FOR_EDITOR)
  480. out->addEnum("Affector", EPAT_NONE, ParticleAffectorTypeNames);
  481. }
  482. //! Reads attributes of the scene node.
  483. void CParticleSystemSceneNode::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options)
  484. {
  485. IParticleSystemSceneNode::deserializeAttributes(in, options);
  486. ParticlesAreGlobal = in->getAttributeAsBool("GlobalParticles");
  487. ParticleSize.Width = in->getAttributeAsFloat("ParticleWidth");
  488. ParticleSize.Height = in->getAttributeAsFloat("ParticleHeight");
  489. // read emitter
  490. int emitterIdx = in->findAttribute("Emitter");
  491. if (emitterIdx == -1)
  492. return;
  493. if (Emitter)
  494. Emitter->drop();
  495. Emitter = 0;
  496. E_PARTICLE_EMITTER_TYPE type = (E_PARTICLE_EMITTER_TYPE)
  497. in->getAttributeAsEnumeration("Emitter", ParticleEmitterTypeNames);
  498. switch(type)
  499. {
  500. case EPET_POINT:
  501. Emitter = createPointEmitter();
  502. break;
  503. case EPET_ANIMATED_MESH:
  504. Emitter = createAnimatedMeshSceneNodeEmitter(NULL); // we can't set the node - the user will have to do this
  505. break;
  506. case EPET_BOX:
  507. Emitter = createBoxEmitter();
  508. break;
  509. case EPET_CYLINDER:
  510. Emitter = createCylinderEmitter(core::vector3df(0,0,0), 10.f, core::vector3df(0,1,0), 10.f); // (values here don't matter)
  511. break;
  512. case EPET_MESH:
  513. Emitter = createMeshEmitter(NULL); // we can't set the mesh - the user will have to do this
  514. break;
  515. case EPET_RING:
  516. Emitter = createRingEmitter(core::vector3df(0,0,0), 10.f, 10.f); // (values here don't matter)
  517. break;
  518. case EPET_SPHERE:
  519. Emitter = createSphereEmitter(core::vector3df(0,0,0), 10.f); // (values here don't matter)
  520. break;
  521. default:
  522. break;
  523. }
  524. u32 idx = 0;
  525. #if 0
  526. if (Emitter)
  527. idx = Emitter->deserializeAttributes(idx, in);
  528. ++idx;
  529. #else
  530. if (Emitter)
  531. Emitter->deserializeAttributes(in);
  532. #endif
  533. // read affectors
  534. removeAllAffectors();
  535. u32 cnt = in->getAttributeCount();
  536. while(idx < cnt)
  537. {
  538. const char* name = in->getAttributeName(idx);
  539. if (!name || strcmp("Affector", name))
  540. return;
  541. E_PARTICLE_AFFECTOR_TYPE atype =
  542. (E_PARTICLE_AFFECTOR_TYPE)in->getAttributeAsEnumeration(idx, ParticleAffectorTypeNames);
  543. IParticleAffector* aff = 0;
  544. switch(atype)
  545. {
  546. case EPAT_ATTRACT:
  547. aff = createAttractionAffector(core::vector3df(0,0,0));
  548. break;
  549. case EPAT_FADE_OUT:
  550. aff = createFadeOutParticleAffector();
  551. break;
  552. case EPAT_GRAVITY:
  553. aff = createGravityAffector();
  554. break;
  555. case EPAT_ROTATE:
  556. aff = createRotationAffector();
  557. break;
  558. case EPAT_SCALE:
  559. aff = createScaleParticleAffector();
  560. break;
  561. case EPAT_NONE:
  562. default:
  563. break;
  564. }
  565. ++idx;
  566. if (aff)
  567. {
  568. #if 0
  569. idx = aff->deserializeAttributes(idx, in, options);
  570. ++idx;
  571. #else
  572. aff->deserializeAttributes(in, options);
  573. #endif
  574. addAffector(aff);
  575. aff->drop();
  576. }
  577. }
  578. }
  579. } // end namespace scene
  580. } // end namespace irr