From 393b5cd1dc438872af89d334ef6e5fcc59f27d47 Mon Sep 17 00:00:00 2001 From: David Walter Seikel Date: Sun, 13 Jan 2013 17:24:39 +1000 Subject: Added Irrlicht 1.8, but without all the Windows binaries. --- .../source/Irrlicht/CParticleSystemSceneNode.cpp | 721 +++++++++++++++++++++ 1 file changed, 721 insertions(+) create mode 100644 libraries/irrlicht-1.8/source/Irrlicht/CParticleSystemSceneNode.cpp (limited to 'libraries/irrlicht-1.8/source/Irrlicht/CParticleSystemSceneNode.cpp') diff --git a/libraries/irrlicht-1.8/source/Irrlicht/CParticleSystemSceneNode.cpp b/libraries/irrlicht-1.8/source/Irrlicht/CParticleSystemSceneNode.cpp new file mode 100644 index 0000000..54bfcc7 --- /dev/null +++ b/libraries/irrlicht-1.8/source/Irrlicht/CParticleSystemSceneNode.cpp @@ -0,0 +1,721 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CParticleSystemSceneNode.h" +#include "os.h" +#include "ISceneManager.h" +#include "ICameraSceneNode.h" +#include "IVideoDriver.h" + +#include "CParticleAnimatedMeshSceneNodeEmitter.h" +#include "CParticleBoxEmitter.h" +#include "CParticleCylinderEmitter.h" +#include "CParticleMeshEmitter.h" +#include "CParticlePointEmitter.h" +#include "CParticleRingEmitter.h" +#include "CParticleSphereEmitter.h" +#include "CParticleAttractionAffector.h" +#include "CParticleFadeOutAffector.h" +#include "CParticleGravityAffector.h" +#include "CParticleRotationAffector.h" +#include "CParticleScaleAffector.h" +#include "SViewFrustum.h" + +namespace irr +{ +namespace scene +{ + +//! constructor +CParticleSystemSceneNode::CParticleSystemSceneNode(bool createDefaultEmitter, + ISceneNode* parent, ISceneManager* mgr, s32 id, + const core::vector3df& position, const core::vector3df& rotation, + const core::vector3df& scale) + : IParticleSystemSceneNode(parent, mgr, id, position, rotation, scale), + Emitter(0), ParticleSize(core::dimension2d(5.0f, 5.0f)), LastEmitTime(0), + MaxParticles(0xffff), Buffer(0), ParticlesAreGlobal(true) +{ + #ifdef _DEBUG + setDebugName("CParticleSystemSceneNode"); + #endif + + Buffer = new SMeshBuffer(); + if (createDefaultEmitter) + { + IParticleEmitter* e = createBoxEmitter(); + setEmitter(e); + e->drop(); + } +} + + +//! destructor +CParticleSystemSceneNode::~CParticleSystemSceneNode() +{ + if (Emitter) + Emitter->drop(); + if (Buffer) + Buffer->drop(); + + removeAllAffectors(); +} + + +//! Gets the particle emitter, which creates the particles. +IParticleEmitter* CParticleSystemSceneNode::getEmitter() +{ + return Emitter; +} + + +//! Sets the particle emitter, which creates the particles. +void CParticleSystemSceneNode::setEmitter(IParticleEmitter* emitter) +{ + if (emitter == Emitter) + return; + if (Emitter) + Emitter->drop(); + + Emitter = emitter; + + if (Emitter) + Emitter->grab(); +} + + +//! Adds new particle effector to the particle system. +void CParticleSystemSceneNode::addAffector(IParticleAffector* affector) +{ + affector->grab(); + AffectorList.push_back(affector); +} + +//! Get a list of all particle affectors. +const core::list& CParticleSystemSceneNode::getAffectors() const +{ + return AffectorList; +} + +//! Removes all particle affectors in the particle system. +void CParticleSystemSceneNode::removeAllAffectors() +{ + core::list::Iterator it = AffectorList.begin(); + while (it != AffectorList.end()) + { + (*it)->drop(); + it = AffectorList.erase(it); + } +} + + +//! Returns the material based on the zero based index i. +video::SMaterial& CParticleSystemSceneNode::getMaterial(u32 i) +{ + return Buffer->Material; +} + + +//! Returns amount of materials used by this scene node. +u32 CParticleSystemSceneNode::getMaterialCount() const +{ + return 1; +} + + +//! Creates a particle emitter for an animated mesh scene node +IParticleAnimatedMeshSceneNodeEmitter* +CParticleSystemSceneNode::createAnimatedMeshSceneNodeEmitter( + scene::IAnimatedMeshSceneNode* node, bool useNormalDirection, + const core::vector3df& direction, f32 normalDirectionModifier, + s32 mbNumber, bool everyMeshVertex, + u32 minParticlesPerSecond, u32 maxParticlesPerSecond, + const video::SColor& minStartColor, const video::SColor& maxStartColor, + u32 lifeTimeMin, u32 lifeTimeMax, s32 maxAngleDegrees, + const core::dimension2df& minStartSize, + const core::dimension2df& maxStartSize ) +{ + return new CParticleAnimatedMeshSceneNodeEmitter( node, + useNormalDirection, direction, normalDirectionModifier, + mbNumber, everyMeshVertex, + minParticlesPerSecond, maxParticlesPerSecond, + minStartColor, maxStartColor, + lifeTimeMin, lifeTimeMax, maxAngleDegrees, + minStartSize, maxStartSize ); +} + + +//! Creates a box particle emitter. +IParticleBoxEmitter* CParticleSystemSceneNode::createBoxEmitter( + const core::aabbox3df& box, const core::vector3df& direction, + u32 minParticlesPerSecond, u32 maxParticlesPerSecond, + const video::SColor& minStartColor, const video::SColor& maxStartColor, + u32 lifeTimeMin, u32 lifeTimeMax, + s32 maxAngleDegrees, const core::dimension2df& minStartSize, + const core::dimension2df& maxStartSize ) +{ + return new CParticleBoxEmitter(box, direction, minParticlesPerSecond, + maxParticlesPerSecond, minStartColor, maxStartColor, + lifeTimeMin, lifeTimeMax, maxAngleDegrees, + minStartSize, maxStartSize ); +} + + +//! Creates a particle emitter for emitting from a cylinder +IParticleCylinderEmitter* CParticleSystemSceneNode::createCylinderEmitter( + const core::vector3df& center, f32 radius, + const core::vector3df& normal, f32 length, + bool outlineOnly, const core::vector3df& direction, + u32 minParticlesPerSecond, u32 maxParticlesPerSecond, + const video::SColor& minStartColor, const video::SColor& maxStartColor, + u32 lifeTimeMin, u32 lifeTimeMax, s32 maxAngleDegrees, + const core::dimension2df& minStartSize, + const core::dimension2df& maxStartSize ) +{ + return new CParticleCylinderEmitter( center, radius, normal, length, + outlineOnly, direction, + minParticlesPerSecond, maxParticlesPerSecond, + minStartColor, maxStartColor, + lifeTimeMin, lifeTimeMax, maxAngleDegrees, + minStartSize, maxStartSize ); +} + + +//! Creates a mesh particle emitter. +IParticleMeshEmitter* CParticleSystemSceneNode::createMeshEmitter( + scene::IMesh* mesh, bool useNormalDirection, + const core::vector3df& direction, f32 normalDirectionModifier, + s32 mbNumber, bool everyMeshVertex, + u32 minParticlesPerSecond, u32 maxParticlesPerSecond, + const video::SColor& minStartColor, const video::SColor& maxStartColor, + u32 lifeTimeMin, u32 lifeTimeMax, s32 maxAngleDegrees, + const core::dimension2df& minStartSize, + const core::dimension2df& maxStartSize) +{ + return new CParticleMeshEmitter( mesh, useNormalDirection, direction, + normalDirectionModifier, mbNumber, everyMeshVertex, + minParticlesPerSecond, maxParticlesPerSecond, + minStartColor, maxStartColor, + lifeTimeMin, lifeTimeMax, maxAngleDegrees, + minStartSize, maxStartSize ); +} + + +//! Creates a point particle emitter. +IParticlePointEmitter* CParticleSystemSceneNode::createPointEmitter( + const core::vector3df& direction, u32 minParticlesPerSecond, + u32 maxParticlesPerSecond, const video::SColor& minStartColor, + const video::SColor& maxStartColor, u32 lifeTimeMin, u32 lifeTimeMax, + s32 maxAngleDegrees, const core::dimension2df& minStartSize, + const core::dimension2df& maxStartSize ) +{ + return new CParticlePointEmitter(direction, minParticlesPerSecond, + maxParticlesPerSecond, minStartColor, maxStartColor, + lifeTimeMin, lifeTimeMax, maxAngleDegrees, + minStartSize, maxStartSize ); +} + + +//! Creates a ring particle emitter. +IParticleRingEmitter* CParticleSystemSceneNode::createRingEmitter( + const core::vector3df& center, f32 radius, f32 ringThickness, + const core::vector3df& direction, + u32 minParticlesPerSecond, u32 maxParticlesPerSecond, + const video::SColor& minStartColor, const video::SColor& maxStartColor, + u32 lifeTimeMin, u32 lifeTimeMax, s32 maxAngleDegrees, + const core::dimension2df& minStartSize, const core::dimension2df& maxStartSize ) +{ + return new CParticleRingEmitter( center, radius, ringThickness, direction, + minParticlesPerSecond, maxParticlesPerSecond, minStartColor, + maxStartColor, lifeTimeMin, lifeTimeMax, maxAngleDegrees, + minStartSize, maxStartSize ); +} + + +//! Creates a sphere particle emitter. +IParticleSphereEmitter* CParticleSystemSceneNode::createSphereEmitter( + const core::vector3df& center, f32 radius, const core::vector3df& direction, + u32 minParticlesPerSecond, u32 maxParticlesPerSecond, + const video::SColor& minStartColor, const video::SColor& maxStartColor, + u32 lifeTimeMin, u32 lifeTimeMax, + s32 maxAngleDegrees, const core::dimension2df& minStartSize, + const core::dimension2df& maxStartSize ) +{ + return new CParticleSphereEmitter(center, radius, direction, + minParticlesPerSecond, maxParticlesPerSecond, + minStartColor, maxStartColor, + lifeTimeMin, lifeTimeMax, maxAngleDegrees, + minStartSize, maxStartSize ); +} + + +//! Creates a point attraction affector. This affector modifies the positions of the +//! particles and attracts them to a specified point at a specified speed per second. +IParticleAttractionAffector* CParticleSystemSceneNode::createAttractionAffector( + const core::vector3df& point, f32 speed, bool attract, + bool affectX, bool affectY, bool affectZ ) +{ + return new CParticleAttractionAffector( point, speed, attract, affectX, affectY, affectZ ); +} + +//! Creates a scale particle affector. +IParticleAffector* CParticleSystemSceneNode::createScaleParticleAffector(const core::dimension2df& scaleTo) +{ + return new CParticleScaleAffector(scaleTo); +} + + +//! Creates a fade out particle affector. +IParticleFadeOutAffector* CParticleSystemSceneNode::createFadeOutParticleAffector( + const video::SColor& targetColor, u32 timeNeededToFadeOut) +{ + return new CParticleFadeOutAffector(targetColor, timeNeededToFadeOut); +} + + +//! Creates a gravity affector. +IParticleGravityAffector* CParticleSystemSceneNode::createGravityAffector( + const core::vector3df& gravity, u32 timeForceLost) +{ + return new CParticleGravityAffector(gravity, timeForceLost); +} + + +//! Creates a rotation affector. This affector rotates the particles around a specified pivot +//! point. The speed represents Degrees of rotation per second. +IParticleRotationAffector* CParticleSystemSceneNode::createRotationAffector( + const core::vector3df& speed, const core::vector3df& pivotPoint ) +{ + return new CParticleRotationAffector( speed, pivotPoint ); +} + + +//! pre render event +void CParticleSystemSceneNode::OnRegisterSceneNode() +{ + doParticleSystem(os::Timer::getTime()); + + if (IsVisible && (Particles.size() != 0)) + { + SceneManager->registerNodeForRendering(this); + ISceneNode::OnRegisterSceneNode(); + } +} + + +//! render +void CParticleSystemSceneNode::render() +{ + video::IVideoDriver* driver = SceneManager->getVideoDriver(); + ICameraSceneNode* camera = SceneManager->getActiveCamera(); + + if (!camera || !driver) + return; + + +#if 0 + // calculate vectors for letting particles look to camera + core::vector3df view(camera->getTarget() - camera->getAbsolutePosition()); + view.normalize(); + + view *= -1.0f; + +#else + + const core::matrix4 &m = camera->getViewFrustum()->getTransform( video::ETS_VIEW ); + + const core::vector3df view ( -m[2], -m[6] , -m[10] ); + +#endif + + // reallocate arrays, if they are too small + reallocateBuffers(); + + // create particle vertex data + s32 idx = 0; + for (u32 i=0; igetUpVector().crossProduct(view); + horizontal.normalize(); + horizontal *= 0.5f * particle.size.Width; + + core::vector3df vertical = horizontal.crossProduct(view); + vertical.normalize(); + vertical *= 0.5f * particle.size.Height; + + #else + f32 f; + + f = 0.5f * particle.size.Width; + const core::vector3df horizontal ( m[0] * f, m[4] * f, m[8] * f ); + + f = -0.5f * particle.size.Height; + const core::vector3df vertical ( m[1] * f, m[5] * f, m[9] * f ); + #endif + + Buffer->Vertices[0+idx].Pos = particle.pos + horizontal + vertical; + Buffer->Vertices[0+idx].Color = particle.color; + Buffer->Vertices[0+idx].Normal = view; + + Buffer->Vertices[1+idx].Pos = particle.pos + horizontal - vertical; + Buffer->Vertices[1+idx].Color = particle.color; + Buffer->Vertices[1+idx].Normal = view; + + Buffer->Vertices[2+idx].Pos = particle.pos - horizontal - vertical; + Buffer->Vertices[2+idx].Color = particle.color; + Buffer->Vertices[2+idx].Normal = view; + + Buffer->Vertices[3+idx].Pos = particle.pos - horizontal + vertical; + Buffer->Vertices[3+idx].Color = particle.color; + Buffer->Vertices[3+idx].Normal = view; + + idx +=4; + } + + // render all + core::matrix4 mat; + if (!ParticlesAreGlobal) + mat.setTranslation(AbsoluteTransformation.getTranslation()); + driver->setTransform(video::ETS_WORLD, mat); + + driver->setMaterial(Buffer->Material); + + driver->drawVertexPrimitiveList(Buffer->getVertices(), Particles.size()*4, + Buffer->getIndices(), Particles.size()*2, video::EVT_STANDARD, EPT_TRIANGLES,Buffer->getIndexType()); + + // for debug purposes only: + if ( DebugDataVisible & scene::EDS_BBOX ) + { + driver->setTransform(video::ETS_WORLD, AbsoluteTransformation); + video::SMaterial deb_m; + deb_m.Lighting = false; + driver->setMaterial(deb_m); + driver->draw3DBox(Buffer->BoundingBox, video::SColor(0,255,255,255)); + } +} + + +//! returns the axis aligned bounding box of this node +const core::aabbox3d& CParticleSystemSceneNode::getBoundingBox() const +{ + return Buffer->getBoundingBox(); +} + + +void CParticleSystemSceneNode::doParticleSystem(u32 time) +{ + if (LastEmitTime==0) + { + LastEmitTime = time; + return; + } + + u32 now = time; + u32 timediff = time - LastEmitTime; + LastEmitTime = time; + + // run emitter + + if (Emitter && IsVisible) + { + SParticle* array = 0; + s32 newParticles = Emitter->emitt(now, timediff, array); + + if (newParticles && array) + { + s32 j=Particles.size(); + if (newParticles > 16250-j) + newParticles=16250-j; + Particles.set_used(j+newParticles); + for (s32 i=j; i::Iterator ait = AffectorList.begin(); + for (; ait != AffectorList.end(); ++ait) + (*ait)->affect(now, Particles.pointer(), Particles.size()); + + if (ParticlesAreGlobal) + Buffer->BoundingBox.reset(AbsoluteTransformation.getTranslation()); + else + Buffer->BoundingBox.reset(core::vector3df(0,0,0)); + + // animate all particles + f32 scale = (f32)timediff; + + for (u32 i=0; i Particles[i].endTime) + { + // Particle order does not seem to matter. + // So we can delete by switching with last particle and deleting that one. + // This is a lot faster and speed is very important here as the erase otherwise + // can cause noticable freezes. + Particles[i] = Particles[Particles.size()-1]; + Particles.erase( Particles.size()-1 ); + } + else + { + Particles[i].pos += (Particles[i].vector * scale); + Buffer->BoundingBox.addInternalPoint(Particles[i].pos); + ++i; + } + } + + const f32 m = (ParticleSize.Width > ParticleSize.Height ? ParticleSize.Width : ParticleSize.Height) * 0.5f; + Buffer->BoundingBox.MaxEdge.X += m; + Buffer->BoundingBox.MaxEdge.Y += m; + Buffer->BoundingBox.MaxEdge.Z += m; + + Buffer->BoundingBox.MinEdge.X -= m; + Buffer->BoundingBox.MinEdge.Y -= m; + Buffer->BoundingBox.MinEdge.Z -= m; + + if (ParticlesAreGlobal) + { + core::matrix4 absinv( AbsoluteTransformation, core::matrix4::EM4CONST_INVERSE ); + absinv.transformBoxEx(Buffer->BoundingBox); + } +} + + +//! Sets if the particles should be global. If it is, the particles are affected by +//! the movement of the particle system scene node too, otherwise they completely +//! ignore it. Default is true. +void CParticleSystemSceneNode::setParticlesAreGlobal(bool global) +{ + ParticlesAreGlobal = global; +} + +//! Remove all currently visible particles +void CParticleSystemSceneNode::clearParticles() +{ + Particles.set_used(0); +} + +//! Sets the size of all particles. +void CParticleSystemSceneNode::setParticleSize(const core::dimension2d &size) +{ + os::Printer::log("setParticleSize is deprecated, use setMinStartSize/setMaxStartSize in emitter.", irr::ELL_WARNING); + //A bit of a hack, but better here than in the particle code + if (Emitter) + { + Emitter->setMinStartSize(size); + Emitter->setMaxStartSize(size); + } + ParticleSize = size; +} + + +void CParticleSystemSceneNode::reallocateBuffers() +{ + if (Particles.size() * 4 > Buffer->getVertexCount() || + Particles.size() * 6 > Buffer->getIndexCount()) + { + u32 oldSize = Buffer->getVertexCount(); + Buffer->Vertices.set_used(Particles.size() * 4); + + u32 i; + + // fill remaining vertices + for (i=oldSize; iVertices.size(); i+=4) + { + Buffer->Vertices[0+i].TCoords.set(0.0f, 0.0f); + Buffer->Vertices[1+i].TCoords.set(0.0f, 1.0f); + Buffer->Vertices[2+i].TCoords.set(1.0f, 1.0f); + Buffer->Vertices[3+i].TCoords.set(1.0f, 0.0f); + } + + // fill remaining indices + u32 oldIdxSize = Buffer->getIndexCount(); + u32 oldvertices = oldSize; + Buffer->Indices.set_used(Particles.size() * 6); + + for (i=oldIdxSize; iIndices.size(); i+=6) + { + Buffer->Indices[0+i] = (u16)0+oldvertices; + Buffer->Indices[1+i] = (u16)2+oldvertices; + Buffer->Indices[2+i] = (u16)1+oldvertices; + Buffer->Indices[3+i] = (u16)0+oldvertices; + Buffer->Indices[4+i] = (u16)3+oldvertices; + Buffer->Indices[5+i] = (u16)2+oldvertices; + oldvertices += 4; + } + } +} + + +//! Writes attributes of the scene node. +void CParticleSystemSceneNode::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const +{ + IParticleSystemSceneNode::serializeAttributes(out, options); + + out->addBool("GlobalParticles", ParticlesAreGlobal); + out->addFloat("ParticleWidth", ParticleSize.Width); + out->addFloat("ParticleHeight", ParticleSize.Height); + + // write emitter + + E_PARTICLE_EMITTER_TYPE type = EPET_COUNT; + if (Emitter) + type = Emitter->getType(); + + out->addEnum("Emitter", (s32)type, ParticleEmitterTypeNames); + + if (Emitter) + Emitter->serializeAttributes(out, options); + + // write affectors + + E_PARTICLE_AFFECTOR_TYPE atype = EPAT_NONE; + + for (core::list::ConstIterator it = AffectorList.begin(); + it != AffectorList.end(); ++it) + { + atype = (*it)->getType(); + + out->addEnum("Affector", (s32)atype, ParticleAffectorTypeNames); + + (*it)->serializeAttributes(out); + } + + // add empty affector to make it possible to add further affectors + + if (options && options->Flags & io::EARWF_FOR_EDITOR) + out->addEnum("Affector", EPAT_NONE, ParticleAffectorTypeNames); +} + + +//! Reads attributes of the scene node. +void CParticleSystemSceneNode::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) +{ + IParticleSystemSceneNode::deserializeAttributes(in, options); + + ParticlesAreGlobal = in->getAttributeAsBool("GlobalParticles"); + ParticleSize.Width = in->getAttributeAsFloat("ParticleWidth"); + ParticleSize.Height = in->getAttributeAsFloat("ParticleHeight"); + + // read emitter + + int emitterIdx = in->findAttribute("Emitter"); + if (emitterIdx == -1) + return; + + if (Emitter) + Emitter->drop(); + Emitter = 0; + + E_PARTICLE_EMITTER_TYPE type = (E_PARTICLE_EMITTER_TYPE) + in->getAttributeAsEnumeration("Emitter", ParticleEmitterTypeNames); + + switch(type) + { + case EPET_POINT: + Emitter = createPointEmitter(); + break; + case EPET_ANIMATED_MESH: + Emitter = createAnimatedMeshSceneNodeEmitter(NULL); // we can't set the node - the user will have to do this + break; + case EPET_BOX: + Emitter = createBoxEmitter(); + break; + case EPET_CYLINDER: + Emitter = createCylinderEmitter(core::vector3df(0,0,0), 10.f, core::vector3df(0,1,0), 10.f); // (values here don't matter) + break; + case EPET_MESH: + Emitter = createMeshEmitter(NULL); // we can't set the mesh - the user will have to do this + break; + case EPET_RING: + Emitter = createRingEmitter(core::vector3df(0,0,0), 10.f, 10.f); // (values here don't matter) + break; + case EPET_SPHERE: + Emitter = createSphereEmitter(core::vector3df(0,0,0), 10.f); // (values here don't matter) + break; + default: + break; + } + + u32 idx = 0; + +#if 0 + if (Emitter) + idx = Emitter->deserializeAttributes(idx, in); + + ++idx; +#else + if (Emitter) + Emitter->deserializeAttributes(in); +#endif + + // read affectors + + removeAllAffectors(); + u32 cnt = in->getAttributeCount(); + + while(idx < cnt) + { + const char* name = in->getAttributeName(idx); + + if (!name || strcmp("Affector", name)) + return; + + E_PARTICLE_AFFECTOR_TYPE atype = + (E_PARTICLE_AFFECTOR_TYPE)in->getAttributeAsEnumeration(idx, ParticleAffectorTypeNames); + + IParticleAffector* aff = 0; + + switch(atype) + { + case EPAT_ATTRACT: + aff = createAttractionAffector(core::vector3df(0,0,0)); + break; + case EPAT_FADE_OUT: + aff = createFadeOutParticleAffector(); + break; + case EPAT_GRAVITY: + aff = createGravityAffector(); + break; + case EPAT_ROTATE: + aff = createRotationAffector(); + break; + case EPAT_SCALE: + aff = createScaleParticleAffector(); + break; + case EPAT_NONE: + default: + break; + } + + ++idx; + + if (aff) + { +#if 0 + idx = aff->deserializeAttributes(idx, in, options); + ++idx; +#else + aff->deserializeAttributes(in, options); +#endif + + addAffector(aff); + aff->drop(); + } + } +} + + +} // end namespace scene +} // end namespace irr + + -- cgit v1.1