PageRenderTime 44ms CodeModel.GetById 8ms app.highlight 32ms RepoModel.GetById 0ms app.codeStats 0ms

/Irrlicht/CParticleSystemSceneNode.cpp

http://myjeh.googlecode.com/
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