nuclear@0: #include "particles.h" nuclear@0: #include "3deng.h" nuclear@0: #include nuclear@0: nuclear@0: ////////////////////////////////////////////////////// nuclear@0: // --==( Particle class implementation )==-- // nuclear@0: ////////////////////////////////////////////////////// nuclear@0: using namespace std; nuclear@0: nuclear@0: Particle::Particle(int life) { nuclear@0: pos = Vector3(0, 0, 0); nuclear@0: vel = Vector3(0, 0, 0); nuclear@0: this->life = life; nuclear@0: } nuclear@0: nuclear@0: Particle::Particle(const Vector3 &pos, int life) { nuclear@0: this->pos = pos; nuclear@0: vel = Vector3(0, 0, 0); nuclear@0: this->life = life; nuclear@0: } nuclear@0: nuclear@0: Particle::Particle(const Vector3 &pos, const Vector3 &vel, int life) { nuclear@0: this->pos = pos; nuclear@0: this->vel = vel; nuclear@0: this->life = life; nuclear@0: } nuclear@0: nuclear@0: void Particle::Update(const Vector3 &forces, float friction) { nuclear@0: if(!life) return; nuclear@0: vel *= 1.0f - friction; nuclear@0: pos += vel + forces; nuclear@0: life--; nuclear@0: } nuclear@0: nuclear@0: /////////////////////////////////////////////////////// nuclear@0: // --==( Particle System implementation )==-- // nuclear@0: /////////////////////////////////////////////////////// nuclear@0: nuclear@0: ParticleSystem::ParticleSystem(GraphicsContext *gc) { nuclear@0: this->gc = gc; nuclear@0: pos = prevpos = Vector3(0, 0, 0); nuclear@0: size = 1.0f; nuclear@0: friction = 0.0f; nuclear@0: SpawnRate = 5; nuclear@0: life = 100; nuclear@0: EmmiterAffectsParticleTrajectory = false; nuclear@0: varray = 0; nuclear@0: tarray = 0; nuclear@0: texture = 0; nuclear@0: obj = 0; nuclear@0: nuclear@0: SetShootDirection(Vector3(0, 0, 0)); nuclear@0: SetMaxDispersionAngle(0.01f); nuclear@0: SetInitialColor(1, 1, 1); nuclear@0: SetDeathColor(0, 0, 0); nuclear@0: nuclear@0: // initialize the shape of the particles nuclear@0: pquad[0] = Vertex(Vector3(-0.5f, 0.5f, 0), 0, 0, 0xffffffff); nuclear@0: pquad[1] = Vertex(Vector3(0.5f, 0.5f, 1), 1, 0, 0xffffffff); nuclear@0: pquad[2] = Vertex(Vector3(0.5f, -0.5f, 1), 1, 1, 0xffffffff); nuclear@0: pquad[3] = Vertex(Vector3(-0.5f, -0.5f, 0), 0, 1, 0xffffffff); nuclear@0: nuclear@0: ptris[0] = Triangle(0, 1, 2); nuclear@0: ptris[1] = Triangle(0, 2, 3); nuclear@0: nuclear@0: for(int i=0; i<4; i++) { nuclear@0: pquad[i].normal = Vector3(0, 0, -1); nuclear@0: } nuclear@0: nuclear@0: SetBlendingMode(BLEND_ONE, BLEND_ONE); nuclear@0: SpawnDiffDispersion = 0.0f; nuclear@0: nuclear@0: FixedUpdateRate = true; nuclear@0: UpdateRate = 30.0f; nuclear@0: LastUpdate = -(1.0f / UpdateRate); nuclear@0: nuclear@0: SpawnRateChange = 0; nuclear@0: } nuclear@0: nuclear@0: ParticleSystem::~ParticleSystem() { nuclear@0: } nuclear@0: nuclear@0: void ParticleSystem::SetGraphicsContext(GraphicsContext *gc) { nuclear@0: this->gc = gc; nuclear@0: } nuclear@0: nuclear@0: void ParticleSystem::SetParticleSize(float psize) { nuclear@0: size = psize; nuclear@0: } nuclear@0: nuclear@0: void ParticleSystem::SetParticleLife(int life) { nuclear@0: this->life = life; nuclear@0: } nuclear@0: nuclear@0: void ParticleSystem::SetFriction(float friction) { nuclear@0: this->friction = friction; nuclear@0: } nuclear@0: nuclear@0: void ParticleSystem::SetSpawnRate(float spawnrate) { nuclear@0: SpawnRate = (int)spawnrate; nuclear@0: } nuclear@0: nuclear@0: void ParticleSystem::SetSpawnRadius(float radius) { nuclear@0: SpawnRadius = radius; nuclear@0: } nuclear@0: nuclear@0: void ParticleSystem::SetTexture(Texture *texture) { nuclear@0: this->texture = texture; nuclear@0: } nuclear@0: nuclear@0: void ParticleSystem::SetObject(Object *obj) { nuclear@0: this->obj = obj; nuclear@0: } nuclear@0: nuclear@0: void ParticleSystem::SetPosition(const Vector3 &pos) { nuclear@0: this->pos = pos; nuclear@0: } nuclear@0: nuclear@0: void ParticleSystem::SetShootDirection(const Vector3 &dir) { nuclear@0: ShootDirection = dir; nuclear@0: } nuclear@0: nuclear@0: void ParticleSystem::SetGravitualForce(float grav) { nuclear@0: GravForce = grav; nuclear@0: } nuclear@0: nuclear@0: void ParticleSystem::SetEmmiterDependence(bool dep) { nuclear@0: EmmiterAffectsParticleTrajectory = dep; nuclear@0: } nuclear@0: nuclear@0: void ParticleSystem::SetMaxDispersionAngle(float maxdisp) { nuclear@0: DispRads = maxdisp; nuclear@0: } nuclear@0: nuclear@0: void ParticleSystem::SetInitialColor(float r, float g, float b) { nuclear@0: StartRed = r; nuclear@0: StartGreen = g; nuclear@0: StartBlue = b; nuclear@0: } nuclear@0: nuclear@0: void ParticleSystem::SetDeathColor(float r, float g, float b) { nuclear@0: EndRed = r; nuclear@0: EndGreen = g; nuclear@0: EndBlue = b; nuclear@0: } nuclear@0: nuclear@0: void ParticleSystem::SetBlendingMode(BlendingFactor src, BlendingFactor dest) { nuclear@0: SourceBlend = src; nuclear@0: DestBlend = dest; nuclear@0: } nuclear@0: nuclear@0: void ParticleSystem::SetSpawningDifferenceDispersion(float val) { nuclear@0: SpawnDiffDispersion = val; nuclear@0: } nuclear@0: nuclear@0: void ParticleSystem::SetSpawnRateChange(int change) { nuclear@0: SpawnRateChange = change; nuclear@0: } nuclear@0: nuclear@0: // transformation stuff nuclear@0: void ParticleSystem::Translate(float x, float y, float z) { nuclear@0: Translation.Translate(x, y, z); nuclear@0: } nuclear@0: nuclear@0: void ParticleSystem::Rotate(float x, float y, float z) { nuclear@0: OrbitRot.Rotate(x, y, z); nuclear@0: } nuclear@0: nuclear@0: void ParticleSystem::Rotate(const Vector3 &axis, float angle) { nuclear@0: OrbitRot.Rotate(axis, angle); nuclear@0: } nuclear@0: nuclear@0: void ParticleSystem::ResetRotation() { nuclear@0: OrbitRot.ResetIdentity(); nuclear@0: } nuclear@0: nuclear@0: void ParticleSystem::ResetTranslation() { nuclear@0: Translation.ResetIdentity(); nuclear@0: } nuclear@0: nuclear@0: int ParticleSystem::CountParticles() { nuclear@0: ParticleCount = (int)particles.size(); nuclear@0: TriCount = ParticleCount << 1; nuclear@0: VertexCount = ParticleCount << 2; nuclear@0: IndexCount = TriCount * 3; nuclear@0: nuclear@0: return ParticleCount; nuclear@0: } nuclear@0: nuclear@0: void ParticleSystem::Update(float t) { nuclear@0: nuclear@0: if(FixedUpdateRate && t-LastUpdate < 1.0f/UpdateRate) return; nuclear@0: LastUpdate = t; nuclear@0: nuclear@0: // remove all particles that are dead nuclear@0: list::iterator iter = particles.begin(); nuclear@0: while(iter != particles.end()) { nuclear@0: if(!iter->life) { nuclear@0: iter = particles.erase(iter); nuclear@0: // if we erase the iterator points to the next so no need to advance explicitly nuclear@0: } else { nuclear@0: iter++; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: nuclear@0: // spawn the new particles according to spawn rate nuclear@0: int LeftToSpawn = SpawnRate; nuclear@0: Vector3 ShootDir = ShootDirection; nuclear@0: Matrix4x4 dispxform; nuclear@0: nuclear@0: Vector3 forces = Vector3(0.0f, -GravForce, 0.0f); nuclear@0: nuclear@0: // find the velocity of the system by differenciating between the nuclear@0: // last and the current position (time interval is considered constant) nuclear@0: Vector3 velocity = (pos - prevpos) * 0.1f; nuclear@0: nuclear@0: // adjust the shoot vector to take under consideration the velocity of the system nuclear@0: if(EmmiterAffectsParticleTrajectory) ShootDir += velocity; nuclear@0: nuclear@0: nuclear@0: while(LeftToSpawn--) { nuclear@0: Vector3 dir = ShootDir; nuclear@0: dispxform.Rotate(frand(DispRads) - DispRads/2.0f, frand(DispRads) - DispRads/2.0f, frand(DispRads) - DispRads/2.0f); nuclear@0: dir.Transform(dispxform); nuclear@0: nuclear@0: Vector3 SpawnOffset(frand(SpawnRadius) - SpawnRadius / 2.0f, frand(SpawnRadius) - SpawnRadius / 2.0f, frand(SpawnRadius) - SpawnRadius / 2.0f); nuclear@0: Vector3 SpawnDisp(0.0f, 0.0f, 0.0f); nuclear@0: if(SpawnDiffDispersion > 0.0f) { nuclear@0: SpawnDisp = Vector3(frand(1.0f) - 0.5f, frand(1.0f) - 0.5f, frand(1.0f) - 0.5f); nuclear@0: SpawnDisp.Normalize(); nuclear@0: SpawnDisp *= SpawnDiffDispersion; nuclear@0: } nuclear@0: particles.insert(particles.end(), Particle(pos + SpawnOffset, dir + SpawnDisp, life)); nuclear@0: } nuclear@0: nuclear@0: nuclear@0: //if(EmmiterAffectsParticleTrajectory) forces += velocity; nuclear@0: nuclear@0: iter = particles.begin(); nuclear@0: while(iter != particles.end()) { nuclear@0: iter->Update(forces, friction); nuclear@0: iter++; nuclear@0: } nuclear@0: nuclear@0: SpawnRate += SpawnRateChange; nuclear@0: if(SpawnRate < 0) SpawnRate = 0; nuclear@0: } nuclear@0: nuclear@0: inline dword FtoDW(float f) { return *((dword*)&f); } nuclear@0: nuclear@0: void ParticleSystem::Render() { nuclear@0: nuclear@0: CountParticles(); nuclear@0: if(!ParticleCount) return; nuclear@0: nuclear@0: list::iterator iter = particles.begin(); nuclear@0: nuclear@0: if(!obj) { nuclear@0: nuclear@0: // ----- Render Billboarded Textured Quads ----- nuclear@0: nuclear@0: VertexBuffer *vb; nuclear@0: gc->CreateVertexBuffer(ParticleCount, UsageStatic, &vb); nuclear@0: Vertex *vbptr; nuclear@0: Lock(vb, &vbptr); nuclear@0: nuclear@0: for(int i=0; ipos; nuclear@0: nuclear@0: float t = 1.0f - (float)iter->life / (float)life; nuclear@0: float red = StartRed + (EndRed - StartRed) * t; nuclear@0: float green = StartGreen + (EndGreen - StartGreen) * t; nuclear@0: float blue = StartBlue + (EndBlue - StartBlue) * t; nuclear@0: nuclear@0: vbptr[i].color = Color(red, green, blue).GetPacked32(); nuclear@0: nuclear@0: iter++; nuclear@0: } nuclear@0: Unlock(vb); nuclear@0: nuclear@0: gc->SetWorldMatrix(Matrix4x4()); nuclear@0: gc->SetLighting(false); nuclear@0: gc->SetZWrite(false); nuclear@0: gc->SetTexture(0, texture); nuclear@0: gc->SetTextureStageColor(0, TexBlendModulate, TexArgCurrent, TexArgTexture); nuclear@0: gc->SetAlphaBlending(true); nuclear@0: gc->SetBlendFunc(SourceBlend, DestBlend); nuclear@0: gc->SetVertexProgram(FixedFunction); nuclear@0: nuclear@0: gc->SetColorVertex(true); nuclear@0: nuclear@0: gc->D3DDevice->SetRenderState(D3DRS_POINTSPRITEENABLE, true); nuclear@0: gc->D3DDevice->SetRenderState(D3DRS_POINTSCALEENABLE, true); nuclear@0: gc->D3DDevice->SetRenderState(D3DRS_POINTSIZE, FtoDW(size)); nuclear@0: gc->D3DDevice->SetRenderState(D3DRS_POINTSCALE_A, FtoDW(0.0f)); nuclear@0: gc->D3DDevice->SetRenderState(D3DRS_POINTSCALE_B, FtoDW(0.0f)); nuclear@0: gc->D3DDevice->SetRenderState(D3DRS_POINTSCALE_C, FtoDW(1.0f)); nuclear@0: nuclear@0: gc->D3DDevice->SetStreamSource(0, vb, sizeof(Vertex)); nuclear@0: gc->D3DDevice->DrawPrimitive(D3DPT_POINTLIST, 0, ParticleCount); nuclear@0: nuclear@0: gc->D3DDevice->SetRenderState(D3DRS_POINTSPRITEENABLE, false); nuclear@0: gc->D3DDevice->SetRenderState(D3DRS_POINTSCALEENABLE, false); nuclear@0: nuclear@0: gc->SetColorVertex(false); nuclear@0: nuclear@0: gc->SetLighting(true); nuclear@0: gc->SetZWrite(true); nuclear@0: gc->SetAlphaBlending(false); nuclear@0: nuclear@0: vb->Release(); nuclear@0: } else { nuclear@0: nuclear@0: // ---- Render Mesh Objects ---- nuclear@0: for(int i=0; iResetTranslation(); nuclear@0: obj->Translate(iter->pos.x, iter->pos.y, iter->pos.z); nuclear@0: obj->Render(); nuclear@0: iter++; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: nuclear@0: }