/* ------------------------------------------------------------------------------------ */ void Particle_SystemRemoveAll(Particle_System *ps) { Particle *ptcl; ptcl = ps->psParticles; while(ptcl) { Particle *temp; temp = ptcl->ptclNext; UnlinkParticle(ps, ptcl); DestroyParticle(ps, ptcl); ptcl = temp; } }
/* ------------------------------------------------------------------------------------ */ void Particle_SystemDestroy(Particle_System *ps) { Particle *ptcl; ptcl = ps->psParticles; while(ptcl) { Particle *temp; temp = ptcl->ptclNext; DestroyParticle(ps, ptcl); ptcl = temp; } geRam_Free(ps); }
//------------------------------------------------------------------------------ // void gosFX::ParticleCloud::Kill() { Check_Object(this); // //------------------------------------------------------------- // Destroy all the particles and set up an empty particle cloud //------------------------------------------------------------- // for(int i=0; i < m_activeParticleCount; i++) DestroyParticle(i); m_activeParticleCount = 0; m_birthAccumulator = 0.0f; // //---------------------------------------- // Now let the base effect handle stopping //---------------------------------------- // Effect::Kill(); }
//------------------------------------------------------------------------------ // bool gosFX::ParticleCloud::Execute(ExecuteInfo *info) { Check_Object(this); Check_Object(info); Verify(IsExecuted()); // //-------------------------------------------------------------------- // If we were given a new matrix, see if we have a parent. If so, // concatenate the two and figure out its inverse. If no parent, then // just invert the new matrix, otherwise just use the existing one //-------------------------------------------------------------------- // Stuff::LinearMatrix4D new_world_to_local; Stuff::LinearMatrix4D *matrix = NULL; int sim_mode = GetSimulationMode(); if (sim_mode == DynamicWorldSpaceSimulationMode) { Stuff::LinearMatrix4D local_to_world; local_to_world.Multiply(m_localToParent, *info->m_parentToWorld); new_world_to_local.Invert(local_to_world); matrix = &new_world_to_local; } // //-------------------------------------------------------- // Figure out the birth rate and request the new particles //-------------------------------------------------------- // Specification *spec = GetSpecification(); Check_Object(spec); Stuff::Scalar dT = static_cast<Stuff::Scalar>(info->m_time - m_lastRan); Verify(dT >= 0.0f); Stuff::Scalar prev_age = m_age; m_age += dT * m_ageRate; if (m_age >= 1.0f) m_birthAccumulator = 0.0f; else { Stuff::Scalar new_life = spec->m_particlesPerSecond.ComputeValue(m_age, m_seed); Min_Clamp(new_life, 0.0f); m_birthAccumulator += dT * new_life; } // //----------------------------------- // Deal with all the active particles //----------------------------------- // int i; int last_real = -1; for (i = 0; i < m_activeParticleCount; i++) { // //-------------------------------------------------------------------- // If the particle is active, age it and if it is not yet time to die, // go to the next particle, otherwise kill it //-------------------------------------------------------------------- // Particle *particle = GetParticle(i); Check_Object(particle); if (particle->m_age < 1.0f) { particle->m_age += dT*particle->m_ageRate; if (AnimateParticle(i, matrix, info->m_time)) { last_real = i; continue; } DestroyParticle(i); } // //-------------------------------------------------------------------- // If there are new particles to be born, go ahead and create them now //-------------------------------------------------------------------- // if (m_birthAccumulator >= 1.0f) { Stuff::Point3D translation; CreateNewParticle(i, &translation); if (AnimateParticle(i, matrix, info->m_time)) last_real = i; else DestroyParticle(i); m_birthAccumulator -= 1.0f; } } m_activeParticleCount = last_real + 1; // //---------------------------------------------------------------------- // If there are still new particles to be born, then we must try to grow // the active particle count //---------------------------------------------------------------------- // while ( m_birthAccumulator >= 1.0f && m_activeParticleCount < spec->m_maxParticleCount ) { i = m_activeParticleCount++; Stuff::Point3D translation; CreateNewParticle(i, &translation); if (!AnimateParticle(i, matrix, info->m_time)) { DestroyParticle(i); --m_activeParticleCount; } m_birthAccumulator -= 1.0f; } // //--------------------------------------------------------- // Only allow fractional births to carry over to next frame //--------------------------------------------------------- // m_birthAccumulator -= static_cast<Stuff::Scalar>(floor(m_birthAccumulator)); // //---------------------------- // Now let effect do its thing //---------------------------- // m_age = prev_age; return Effect::Execute(info); }
/* ------------------------------------------------------------------------------------ */ void Particle_SystemFrame(Particle_System *ps, geFloat DeltaTime) { geVec3d AnchorDelta; // the quick fix to the particle no-draw problem ps->psQuantumSeconds = DeltaTime; { Particle *ptcl; ptcl = ps->psParticles; while(ptcl) { ptcl->ptclTime -= ps->psQuantumSeconds; if(ptcl->ptclTime <= 0.0f) { Particle *temp; temp = ptcl->ptclNext; UnlinkParticle(ps, ptcl); DestroyParticle(ps, ptcl); ptcl = temp; continue; } else { // locals geVec3d DeltaPos = {0.0f, 0.0f, 0.0f}; // apply velocity if(ptcl->ptclFlags & PARTICLE_HASVELOCITY) { geVec3d_Scale(&(ptcl->ptclVelocity), ps->psQuantumSeconds, &DeltaPos); } // apply gravity if(ptcl->ptclFlags & PARTICLE_HASGRAVITY) { // locals geVec3d Gravity; // make gravity vector geVec3d_Scale(&(ptcl->Gravity), ps->psQuantumSeconds, &Gravity); // apply gravity to built in velocity and DeltaPos geVec3d_Add(&(ptcl->ptclVelocity), &Gravity, &(ptcl->ptclVelocity)); geVec3d_Add(&DeltaPos, &Gravity, &DeltaPos); } //apply wind if(ptcl->ptclFlags & PARTICLE_HASWIND) { geVec3d Wind = CCD->Player()->GetWind(); //make wind vector geVec3d_Scale(&Wind, ps->psQuantumSeconds, &Wind); //add wind to delta pos geVec3d_Add(&DeltaPos, &Wind, &DeltaPos); } // apply DeltaPos to particle position if((ptcl->ptclFlags & PARTICLE_HASVELOCITY) || (ptcl->ptclFlags & PARTICLE_HASGRAVITY) || (ptcl->ptclFlags & PARTICLE_HASWIND)) { geVec3d temppos, temppos1; GE_Collision Collision; geVec3d_Copy((geVec3d*)&(ptcl->ptclVertex.X), &temppos); geVec3d_Add(&temppos, &DeltaPos, &temppos1); if(ptcl->Bounce) { float totalTravelled = 1.0f;// keeps track of fraction of path travelled (1.0=complete) float margin = 0.001f; // margin to be satisfied with (1.0 - margin == 1.0) int loopCounter = 0; // safety valve for endless collisions in tight corners const int maxLoops = 10; while(geWorld_Collision(CCD->World(), NULL, NULL, &temppos, &temppos1, GE_VISIBLE_CONTENTS, GE_COLLIDE_ALL, 0, NULL, NULL, &Collision)) { float ratio ; float elasticity = 1.3f ; float friction = 0.9f ; // loses (1 minus friction) of speed CollisionCalcRatio(Collision, temppos, temppos1, &ratio); CollisionCalcImpactPoint(Collision, temppos, temppos1, 1.0f, ratio, &temppos1); CollisionCalcVelocityImpact(Collision, ptcl->ptclVelocity, elasticity, friction, &(ptcl->ptclVelocity)); if(ratio >= 0) totalTravelled += (1.0f - totalTravelled) * ratio ; if(totalTravelled >= 1.0f - margin) break ; if(++loopCounter >= maxLoops) // safety check break ; } } else { if(geWorld_Collision(CCD->World(), NULL, NULL, &temppos, &temppos1, GE_VISIBLE_CONTENTS, GE_COLLIDE_ALL, 0, NULL, NULL, &Collision)) { Particle *temp; temp = ptcl->ptclNext; UnlinkParticle(ps, ptcl); DestroyParticle(ps, ptcl); ptcl = temp; continue; } } geVec3d_Copy(&temppos1, (geVec3d *)&(ptcl->ptclVertex.X)); } // make the particle follow its anchor point if it has one if(ptcl->AnchorPoint != (const geVec3d*)NULL) { geVec3d_Subtract(ptcl->AnchorPoint, &(ptcl->CurrentAnchorPoint), &AnchorDelta); geVec3d_Add((geVec3d*)&(ptcl->ptclVertex.X), &AnchorDelta, (geVec3d*)&(ptcl->ptclVertex.X)); geVec3d_Copy(ptcl->AnchorPoint, &(ptcl->CurrentAnchorPoint)); } } #ifndef POLYQ // set particle alpha ptcl->ptclVertex.a = ptcl->Alpha * (ptcl->ptclTime / ptcl->ptclTotalTime); geWorld_AddPolyOnce(ps->psWorld, &(ptcl->ptclVertex), 1, ptcl->ptclTexture, GE_TEXTURED_POINT, PARTICLE_RENDERSTYLE, ptcl->Scale); #else // set particle alpha ptcl->ptclVertex.a = ptcl->Alpha * (ptcl->ptclTime / ptcl->ptclTotalTime); if(ptcl->ptclPoly) gePoly_SetLVertex(ptcl->ptclPoly, 0, &(ptcl->ptclVertex)); #endif ptcl = ptcl->ptclNext; } DeltaTime -= QUANTUMSIZE; } ps->psLastTime += DeltaTime; }