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