#include "CKAll.h" #include #include "ParticleEmitter.h" #include "ParticleManager.h" #include "ParticleSystemRenderCallbacks.h" // 128 Bytes to have 16 bytes aligned data for Pentium3 optimisations 32 DWORDS BYTE _PS_AlignedMemory[128]; DWORD* g_PS_AlignZone =(DWORD *)((DWORD)(_PS_AlignedMemory + 15) & 0xFFFFFFF0); float* g_Min =(float *)g_PS_AlignZone; // 16 Bytes (4 floats) +4 float* g_Max =(float *)(g_PS_AlignZone+4); // 16 Bytes (4 floats) +8 float* g_One =(float *)(g_PS_AlignZone+8); // 16 Bytes (4 floats) +12 (1.0f,1.0f,1.0f,1.0f); float* g_Delta =(float *)(g_PS_AlignZone+12); // 16 Bytes (4 floats) +16 (delta,delta,delta,delta); WORD* ParticleEmitter::m_GlobalIndices = 0; int ParticleEmitter::m_GlobalIndicesCount = 0; // Constructeur ParticleEmitter::ParticleEmitter(CKContext* ctx,CK_ID entity,char* name) { m_Context = ctx; g_One[0]=g_One[1]=g_One[2]=g_One[3]=1.0f; m_MaximumParticles = 100; m_BackPool = NULL; m_InteractorsFlags = 0; m_YawVariation = 0; m_PitchVariation = 0; m_Speed = 0; m_SpeedVariation = 0; m_AngularSpeed = 0; m_AngularSpeedVariation = 0; totalParticles = 0; particleCount = 0; emitsPerFrame = 0; emitsVar = 0; m_Life = 0; m_LifeVariation = 0; m_StartSize = 0; m_StartSizeVar = 0; m_EndSize = 0; m_EndSizeVar = 0; m_Weight = 0; m_WeightVariation = 0; m_Surface = 0; m_SurfaceVariation = 0; m_Bounce = 0; m_BounceVariation = 0; m_StartColor.r = 0.6f; m_StartColor.g = 0.6f; m_StartColor.b = 0.8f; m_StartColor.b = 1.0f; m_StartColorVar.r = 0.0f; m_StartColorVar.g = 0.0f; m_StartColorVar.b = 0.0f; m_StartColorVar.a = 0.0f; m_EndColor.r = 0.0f; m_EndColor.g = 0.0f; m_EndColor.b = 0.0f; m_EndColor.a = 0.0f; m_EndColorVar.r = 0.0f; m_EndColorVar.g = 0.0f; m_EndColorVar.b = 0.0f; m_EndColorVar.a = 0.0f; m_InitialTextureFrame = 0; m_InitialTextureFrameVariance = 0; m_SpeedTextureFrame = 0; m_SpeedTextureFrameVariance = 0; m_TextureFrameCount = 0; m_TextureFrameloop = FALSE; m_EvolutionsFlags = 0; m_VariancesFlags = 0; m_InteractorsFlags = 0; m_DeflectorsFlags = 0; m_RenderMode = 3; m_TrailCount = 0; m_RadialParticleOffset = 0.f; m_Mesh = 0; m_Entity = entity; CK3dEntity* ent = (CK3dEntity*)m_Context->GetObject(m_Entity); if (ent) m_EntityBbox = ent->GetBoundingBox(TRUE); m_Texture = 0; m_Group = 0; m_MessageType = -1; m_CurrentImpact = 0; m_Behavior = NULL; #ifdef WIN32 // ACC, July 10, 2002 Create Event to be waited in Render CB hasBeenComputedEvent = CreateEvent(NULL, FALSE, FALSE, NULL); hasBeenRendered =false; hasBeenEnqueud =false; #endif InitParticleSystem(); }; #ifdef USE_THR #include "blockingqueue.h" #include "GeneralParticleSystem.h" extern BlockingQueue PSqueue; #endif // Destructeur ParticleEmitter::~ParticleEmitter() { #ifdef USE_THR if (hasBeenEnqueud) { WaitForSingleObject(hasBeenComputedEvent, INFINITE); while (hasBeenEnqueud) { int a = 0; } } EnterCriticalSection(&PSqueue.mGuardAccess); for (list::iterator it = PSqueue.mQueue.begin(); it != PSqueue.mQueue.end(); ) { if (it->pe == this) { it = PSqueue.mQueue.erase(it); int a = 0; } else ++it; } LeaveCriticalSection(&PSqueue.mGuardAccess); #endif delete [] m_BackPool; m_BackPool = NULL; CK3dEntity* ent = (CK3dEntity*)m_Context->GetObject(m_Entity); if (ent) ent->SetBoundingBox(&m_EntityBbox, TRUE); m_Entity = 0; #ifdef WIN32 CloseHandle(hasBeenComputedEvent); #endif } void ParticleEmitter::InitParticleSystem() { if(m_BackPool) { delete [] m_BackPool; m_BackPool = NULL; } m_BackPool = new BYTE[m_MaximumParticles*sizeof(Particle)+16]; memset(m_BackPool,0,m_MaximumParticles*sizeof(Particle)+16); m_Pool = (Particle *)((DWORD)(m_BackPool + 15) & 0xFFFFFFF0); for (int loop = 0; loop < m_MaximumParticles - 1; loop++) { m_Pool[loop].next = &m_Pool[loop + 1]; } m_Pool[m_MaximumParticles - 1].next = NULL; particles = NULL; particleCount = 0; // Clear Historic pool. old_pos.Clear(); old_pos.Reserve(m_MaximumParticles); for (int i = 0; i < m_MaximumParticles; i++) old_pos.PushBack(ParticleHistoric(m_TrailCount)); } void ParticleEmitter::UpdateParticles(float rdeltat) { ParticleManager* pm = m_Manager; //--- Kill over-max-number particles if( totalParticles < particleCount ){ int pCount = particleCount; Particle* p = particles; while( p && totalParticlesm_Life = -1; p = p->next; --pCount; } } // We clear the impact array m_Impacts.Clear(); m_CurrentImpact = 0; float deltat; Particle* particle=particles; // If there is no particles yet, we buzz off if(!particles) return; VxVector minv(100000,100000,100000),maxv(-100000,-100000,-100000); g_Min[0]=g_Min[1]=g_Min[2]=g_Min[3]=1e6f; g_Max[0]=g_Max[1]=g_Max[2]=g_Max[3]=-1e6f; /// // Interactors management // Gravity float gravityForce = 0.0f; if (m_InteractorsFlags & PI_GRAVITY) { const XObjectPointerArray& Array = m_Context->GetAttributeManager()->GetAttributeListPtr(pm->m_GravityAttribute); for (CKObject** it = Array.Begin(); it != Array.End(); ++it) { // we get attribute owner CKBeObject* ent = (CKBeObject*)*it; // we get the attribute value CKParameterOut* pout = ent->GetAttributeParameter(pm->m_GravityAttribute); float f = 0.0f; pout->GetValue(&f); gravityForce += f; } gravityForce *= rdeltat; } if(m_InteractorsFlags & PI_ATMOSPHERE) pm->ManageAtmosphere(this,rdeltat); if(m_InteractorsFlags & PI_GLOBALWIND) pm->ManageGlobalWind(this,rdeltat); if(m_InteractorsFlags & PI_LOCALWIND) pm->ManageLocalWind(this,rdeltat); // The magnet act on the position so it came after positionning if(m_InteractorsFlags & PI_MAGNET) pm->ManageMagnet(this,rdeltat); if(m_InteractorsFlags & PI_VORTEX) pm->ManageVortex(this,rdeltat); if(m_InteractorsFlags & PI_DISRUPTIONBOX) pm->ManageDisruptionBox(this,rdeltat); if(m_InteractorsFlags & PI_MUTATIONBOX) pm->ManageMutationBox(this,rdeltat); if(m_InteractorsFlags & PI_TUNNEL) pm->ManageTunnel(this,rdeltat); if(m_InteractorsFlags & PI_PROJECTOR) pm->ManageProjector(this,rdeltat); // Disable SSE code generation for this file // cause of interferences with hand made asm optimizations #if (_M_IX86_FP != 0) #error "Cannot Compile this file with the /arch SSE or SS2" #endif DWORD ProcessorFeatures = GetProcessorFeatures(); #ifdef SIMD_SUPPORTED if (ProcessorFeatures & PROC_SIMD) { __asm { // preload katmai registers mov esi,g_Min mov edi,g_Max mov edx,g_One movaps xmm7,[edi] // Load Max movaps xmm6,[esi] // Load Min movaps xmm5,[edx] // Load One xorps xmm3,xmm3 // Zero xmm3 } } #endif while(particle) { // IF THIS IS AN VALID PARTICLE if (particle->m_Life > 0) { if(particle->m_Life < rdeltat) { deltat = particle->m_Life; } else { deltat = rdeltat; } particle->prevpos = particle->pos; // Gravity management particle->dir.y += gravityForce*particle->m_Weight; #ifdef SIMD_SUPPORTED if (ProcessorFeatures & PROC_SIMD) { __asm { lea ecx,[deltat] mov ebx,particle movss xmm0,[ecx] // Load delta factor movaps xmm2,[ebx+16] // Load Delta Color shufps xmm0,xmm0,0 // propagate delta to 4 floats mulps xmm2,xmm0 // Delta Color * delta Factor movaps xmm4,[ebx+48] // Load Delta position + Delta Angle addps xmm2,[ebx] // Add to original color mulps xmm4,xmm0 // Delta Position * delta Factor minps xmm6,[ebx+32] // compute minpos before adding delta maxps xmm7,[ebx+32] // compute maxpos before adding delta minps xmm2,xmm5 // Ceil Color to One addps xmm4,[ebx+32] // Add to original position maxps xmm2,xmm3 // Floor to Zero movaps [ebx+32],xmm4 // Store position movaps [ebx],xmm2 // Store Color minps xmm6,xmm4 // compute minpos maxps xmm7,xmm4 // compute maxpos } } else #endif { // Calculating new angle particle->m_Angle += particle->m_DeltaAngle*deltat; if(particle->pos.x < minv.x) { minv.x = particle->pos.x; } if(particle->pos.y < minv.y) { minv.y = particle->pos.y; } if(particle->pos.z < minv.z) { minv.z = particle->pos.z; } if( maxv.x < particle->pos.x) { maxv.x = particle->pos.x; } if( maxv.y < particle->pos.y) { maxv.y = particle->pos.y; } if( maxv.z < particle->pos.z) { maxv.z = particle->pos.z; } // CALCULATE THE NEW particle->pos += (particle->dir*deltat); ////////////////////////////// // BOUNDING BOX UPDATING ////////////////////////////// if(particle->pos.x < minv.x) { minv.x = particle->pos.x; } if(particle->pos.y < minv.y) { minv.y = particle->pos.y; } if(particle->pos.z < minv.z) { minv.z = particle->pos.z; } if( maxv.x < particle->pos.x) { maxv.x = particle->pos.x; } if( maxv.y < particle->pos.y) { maxv.y = particle->pos.y; } if( maxv.z < particle->pos.z) { maxv.z = particle->pos.z; } ///////////////////////////// // EVOLUTIONS MANAGEMENT ///////////////////////////// // color management if(m_EvolutionsFlags & PE_COLOR) { particle->m_Color.r += particle->deltaColor.r*deltat; if(particle->m_Color.r < 0.0f) particle->m_Color.r = 0.0f; else if(particle->m_Color.r > 1.0f) particle->m_Color.r = 1.0f; particle->m_Color.g += particle->deltaColor.g*deltat; if(particle->m_Color.g < 0.0f) particle->m_Color.g = 0.0f; else if(particle->m_Color.g > 1.0f) particle->m_Color.g = 1.0f; particle->m_Color.b += particle->deltaColor.b*deltat; if(particle->m_Color.b < 0.0f) particle->m_Color.b = 0.0f; else if(particle->m_Color.b > 1.0f) particle->m_Color.b = 1.0f; particle->m_Color.a += particle->deltaColor.a*deltat; if(particle->m_Color.a < 0.0f) particle->m_Color.a = 0.0f; else if(particle->m_Color.a > 1.0f) particle->m_Color.a = 1.0f; } } // Size management if (m_EvolutionsFlags & PE_SIZE) particle->m_Size += particle->m_DeltaSize*deltat; // texture management if (particle->m_DeltaFrametime) if (m_EvolutionsFlags & PE_TEXTURE && m_RenderMode!=PR_OBJECT) { particle->m_CurrentFrametime += deltat; float dft = particle->m_DeltaFrametime; int tfi = 1; if(particle->m_DeltaFrametime < 0) { dft = -particle->m_DeltaFrametime; tfi = -1; } while(particle->m_CurrentFrametime > dft) { particle->m_CurrentFrame+=tfi; if(particle->m_CurrentFrame >= m_TextureFrameCount) { switch(m_TextureFrameloop) { case PL_NOLOOP:particle->m_CurrentFrame = m_TextureFrameCount-1; break; case PL_LOOP:particle->m_CurrentFrame = 0; break; case PL_PINGPONG: particle->m_CurrentFrame = m_TextureFrameCount-2; particle->m_DeltaFrametime = -particle->m_DeltaFrametime; break; } } else { if(particle->m_CurrentFrame < 0) { switch(m_TextureFrameloop) { case PL_NOLOOP:particle->m_CurrentFrame = 0; break; case PL_LOOP:particle->m_CurrentFrame = m_TextureFrameCount-1; break; case PL_PINGPONG: particle->m_CurrentFrame = 1; particle->m_DeltaFrametime = -particle->m_DeltaFrametime; break; } } } particle->m_CurrentFrametime -= dft; } } // New lifespan particle->m_Life -= deltat; // new delta time particle->m_DeltaTime = deltat; // Updates trail position. if (m_TrailCount) { int idx = ((BYTE*)particle - m_BackPool) / sizeof (Particle); XASSERT(idx < m_MaximumParticles); ParticleHistoric &ph = old_pos[idx]; if (ph.count == m_TrailCount) { ph.particles[ph.start++] = *particle; if (ph.start >= m_TrailCount) ph.start = 0; } else ph.particles[ph.count++] = *particle; } particle = particle->next; } else { // Delete particle if (m_TrailCount) { int idx = ((BYTE*)particle - m_BackPool) / sizeof (Particle); XASSERT(idx < m_MaximumParticles); ParticleHistoric &ph = old_pos[idx]; ph.start = 0; ph.count = 0; } Particle*tmp = particle->next; if (particle->prev) particle->prev->next = particle->next; else particles = particle->next; if (particle->next) particle->next->prev = particle->prev; particle->next = m_Pool; m_Pool = particle; // NEW POOL POINTER particleCount--; // ADD ONE TO POOL particle = tmp; } } VxBbox bbox; #ifdef SIMD_SUPPORTED if (ProcessorFeatures & PROC_SIMD) { __asm { // preload katmai registers mov esi,g_Min mov edi,g_Max movaps [esi],xmm6 // Save Min movaps [edi],xmm7 // Save Max } bbox.Min = *(VxVector *)g_Min; bbox.Max = *(VxVector *)g_Max; } else #endif { bbox.Min = minv; bbox.Max = maxv; } CK3dEntity* entity = (CK3dEntity*)m_Context->GetObject(m_Entity); if (particleCount>0) { float particleExtent = XMax(m_StartSize + m_StartSizeVar, m_EndSize + m_EndSizeVar); bbox.Max.x += particleExtent; bbox.Max.y += particleExtent; bbox.Max.z += particleExtent; bbox.Min.x -= particleExtent; bbox.Min.y -= particleExtent; bbox.Min.z -= particleExtent; //The real bbox is the union between the object box and the particules box VxBbox real_bbox; real_bbox.TransformFrom(m_EntityBbox, entity->GetWorldMatrix()); real_bbox.Merge(bbox.Max); real_bbox.Merge(bbox.Min); entity->SetBoundingBox(&real_bbox); // enlarge with particle sizes } else { entity->SetBoundingBox(&m_EntityBbox, TRUE); } // Deflectors management if(m_DeflectorsFlags & PD_PLANE) pm->ManagePlaneDeflectors(this,rdeltat); if(m_DeflectorsFlags & PD_INFINITEPLANE) pm->ManageInfinitePlaneDeflectors(this,rdeltat); if(m_DeflectorsFlags & PD_CYLINDER) pm->ManageCylinderDeflectors(this,rdeltat); if(m_DeflectorsFlags & PD_SPHERE) pm->ManageSphereDeflectors(this,rdeltat); if(m_DeflectorsFlags & PD_BOX) pm->ManageBoxDeflectors(this,rdeltat); if(m_DeflectorsFlags & PD_OBJECT) pm->ManageObjectDeflectors(this,rdeltat); } void ParticleEmitter::AddParticles() { // emits particles for this frame int emits; if(m_VariancesFlags & PV_EMISSION) { emits = emitsPerFrame + (int)((float)emitsVar * RANDNUM); } else { emits = emitsPerFrame; } if(emits<=0) return; do { if (m_Pool != NULL && particleCount < totalParticles) { Particle *p; p = m_Pool; m_Pool = m_Pool->next; if (particles != NULL) particles->prev = p; p->next = particles; p->prev = NULL; particleCount++; particles = p; // Calculate the initial Position InitiateParticle(p); // CALCULATE THE STARTING DIRECTION VECTOR InitiateDirection(p); // Initiate density p->m_Density = rand()*INV_RAND; // Calculate the speed if(m_VariancesFlags & PV_SPEED) { p->dir *= m_Speed + (m_SpeedVariation * RANDNUM); } else { p->dir *= m_Speed; } switch(m_RenderMode) { case PR_LINE: case PR_OSPRITE: case PR_CSPRITE: // we manage here latency p->m_Angle = m_AngularSpeed; p->m_DeltaAngle = m_AngularSpeedVariation; break; case PR_SPRITE: case PR_FSPRITE: p->m_Angle = 0; if(m_VariancesFlags & PV_ANGULARSPEED) { p->m_DeltaAngle = m_AngularSpeed + m_AngularSpeedVariation*RANDNUM; } else { p->m_DeltaAngle = 0; } break; case PR_OBJECT: { CKGroup* group = (CKGroup*)m_Context->GetObject(m_Group); int oc; if(group) oc = group->GetObjectCount(); else oc=0; p->m_GroupIndex = (int)(oc*((float)rand()*INV_RAND)); p->m_Angle = 0; if(m_VariancesFlags & PV_ANGULARSPEED) { p->m_DeltaAngle = m_AngularSpeed + m_AngularSpeedVariation*RANDNUM; } else { p->m_DeltaAngle = 0; } } break; default: p->m_Angle = 0; p->m_DeltaAngle = 0; break; } //////////////////////// // LifeSpan Management //////////////////////// if(m_VariancesFlags & PV_LIFESPAN) { p->m_Life = m_Life + m_LifeVariation * RANDNUM; } else { p->m_Life = m_Life; } float invlife = 1.0f/p->m_Life; //////////////////////// // Color Management //////////////////////// // Initial Color if(m_VariancesFlags & PV_INITIALCOLOR) { p->m_Color.r = m_StartColor.r + (m_StartColorVar.r * RANDNUM); p->m_Color.g = m_StartColor.g + (m_StartColorVar.g * RANDNUM); p->m_Color.b = m_StartColor.b + (m_StartColorVar.b * RANDNUM); p->m_Color.a = m_StartColor.a + (m_StartColorVar.a * RANDNUM); } else { p->m_Color = m_StartColor; } // Color Delta if(m_EvolutionsFlags & PE_COLOR) { if(m_VariancesFlags & PV_ENDINGCOLOR) { p->deltaColor.r = ((m_EndColor.r + (m_EndColorVar.r * RANDNUM)) - p->m_Color.r) * invlife; p->deltaColor.g = ((m_EndColor.g + (m_EndColorVar.g * RANDNUM)) - p->m_Color.g) * invlife; p->deltaColor.b = ((m_EndColor.b + (m_EndColorVar.b * RANDNUM)) - p->m_Color.b) * invlife; p->deltaColor.a = ((m_EndColor.a + (m_EndColorVar.a * RANDNUM)) - p->m_Color.a) * invlife; } else { p->deltaColor.r = (m_EndColor.r - p->m_Color.r) * invlife; p->deltaColor.g = (m_EndColor.g - p->m_Color.g) * invlife; p->deltaColor.b = (m_EndColor.b - p->m_Color.b) * invlife; p->deltaColor.a = (m_EndColor.a - p->m_Color.a) * invlife; } } else { p->deltaColor.r = 0; p->deltaColor.g = 0; p->deltaColor.b = 0; p->deltaColor.a = 0; } ///////////////////////// // Size Management ///////////////////////// // Initial Size if(m_VariancesFlags & PV_INITIALSIZE) { p->m_Size = m_StartSize + (m_StartSizeVar * RANDNUM); } else { p->m_Size = m_StartSize; } // Size Delta if(m_EvolutionsFlags & PE_SIZE) { if(m_VariancesFlags & PV_ENDINGSIZE) { p->m_DeltaSize = (m_EndSize + (m_EndSizeVar * RANDNUM) - p->m_Size) * invlife; } else { p->m_DeltaSize = (m_EndSize - p->m_Size) * invlife; } } else { p->m_DeltaSize = 0; } ///////////////////////// // Texture management ///////////////////////// switch(m_RenderMode) { case PR_SPRITE: case PR_FSPRITE: case PR_OSPRITE: case PR_CSPRITE: case PR_RSPRITE: // Initial Texture if(m_VariancesFlags & PV_INITIALTEXTURE) { p->m_CurrentFrame = m_InitialTextureFrame + (int)(m_InitialTextureFrameVariance * RANDNUMP); } else { p->m_CurrentFrame = m_InitialTextureFrame; } // Initialisation of the current frame time p->m_CurrentFrametime = 0; // Texture Delta time if ((m_EvolutionsFlags & PE_TEXTURE) && (m_TextureFrameCount>1)){ if(m_VariancesFlags & PV_SPEEDTEXTURE) { p->m_DeltaFrametime = m_SpeedTextureFrame + m_SpeedTextureFrameVariance*RANDNUM; } else { p->m_DeltaFrametime = (float)m_SpeedTextureFrame; } } else { p->m_DeltaFrametime = 0; } break; default: p->m_DeltaFrametime = 0; break; } ////////////////////////// // Deflectors Management ////////////////////////// // Particle Bouncing factor if(m_DeflectorsFlags) { if(m_VariancesFlags & PV_BOUNCE) { p->m_Bounce = m_Bounce+(m_BounceVariation*RANDNUM); } else { p->m_Bounce = m_Bounce; } } ////////////////////////// // Interactors Management ////////////////////////// // Particle Weight if(m_InteractorsFlags&PI_GRAVITY) { if(m_VariancesFlags & PV_WEIGHT) { p->m_Weight = m_Weight+(m_WeightVariation * RANDNUM); } else { p->m_Weight = m_Weight; } } // Time Management p->m_DeltaTime = 0.01f; // Particle Surface if(m_InteractorsFlags&(PI_LOCALWIND|PI_GLOBALWIND|PI_ATMOSPHERE)) { if(m_VariancesFlags & PV_SURFACE) { p->m_Surface = m_Surface+(m_SurfaceVariation * RANDNUM); } else { p->m_Surface = m_Surface; } } } else break; } while(--emits); } void ParticleEmitter::InitiateDirection(Particle* p) { VxVector dir; CK3dEntity* entity = (CK3dEntity*)m_Context->GetObject(m_Entity); dir.z = cosf(m_PitchVariation * RANDNUM); dir.x = dir.z * sinf(m_YawVariation * RANDNUM); dir.z *= cosf(m_YawVariation * RANDNUM); dir.y = sinf(m_PitchVariation * RANDNUM); entity->TransformVector(&(p->dir),&dir); } void ParticleEmitter::ReadInputs(CKBehavior* beh) { beh->GetInputParameterValue(YAWVARIATION,&m_YawVariation); beh->GetInputParameterValue(PITCHVARIATION,&m_PitchVariation); beh->GetInputParameterValue(SPEED,&m_Speed); if(m_VariancesFlags & PV_SPEED) beh->GetInputParameterValue(SPEEDVARIATION,&m_SpeedVariation); beh->GetInputParameterValue(ANGSPEED,&m_AngularSpeed); if(m_VariancesFlags & PV_ANGULARSPEED) beh->GetInputParameterValue(ANGSPEEDVARIATION,&m_AngularSpeedVariation); //////// // Size //////// // Initial Size beh->GetInputParameterValue(STARTSIZE,&m_StartSize); if(m_VariancesFlags & PV_INITIALSIZE) { beh->GetInputParameterValue(STARTSIZEVARIANCE,&m_StartSizeVar); } // End Size if(m_EvolutionsFlags & PE_SIZE) { beh->GetInputParameterValue(ENDSIZE,&m_EndSize); if(m_VariancesFlags & PV_ENDINGSIZE) { beh->GetInputParameterValue(ENDSIZEVARIANCE,&m_EndSizeVar); } } beh->GetInputParameterValue(LIFE,&m_Life); if(m_VariancesFlags & PV_LIFESPAN) beh->GetInputParameterValue(LIFEVARIATION,&m_LifeVariation); beh->GetInputParameterValue(NUMBER,&totalParticles); beh->GetInputParameterValue(EMITION,&emitsPerFrame); if(m_VariancesFlags & PV_EMISSION) beh->GetInputParameterValue(EMITIONVARIATION,&emitsVar); /////////// // Colors /////////// // Initial Color beh->GetInputParameterValue(STARTCOLOR,&m_StartColor); if(m_VariancesFlags & PV_INITIALCOLOR) { beh->GetInputParameterValue(STARTCOLORVARIANCE,&m_StartColorVar); } // Ending Color if(m_EvolutionsFlags & PE_COLOR) { beh->GetInputParameterValue(ENDCOLOR,&m_EndColor); if(m_VariancesFlags & PV_ENDINGCOLOR) { beh->GetInputParameterValue(ENDCOLORVARIANCE,&m_EndColorVar); } } /////////// // Textures /////////// // We get the texture beh->GetInputParameterValue(TEXTURE,&m_Texture); // Initial Texture beh->GetInputParameterValue(STARTTEXTURE,&m_InitialTextureFrame); if(m_VariancesFlags & PV_INITIALTEXTURE) { beh->GetInputParameterValue(STARTTEXTUREVARIANCE,&m_InitialTextureFrameVariance); } // Speed Texture if(m_EvolutionsFlags & PE_TEXTURE) { beh->GetInputParameterValue(SPEEDTEXTURE,&m_SpeedTextureFrame); if(m_VariancesFlags & PV_SPEEDTEXTURE) { beh->GetInputParameterValue(SPEEDTEXTUREVARIANCE,&m_SpeedTextureFrameVariance); } } // Texture Count beh->GetInputParameterValue(TEXTURECOUNT,&m_TextureFrameCount); // Texture Loop beh->GetInputParameterValue(TEXTURELOOP,&m_TextureFrameloop); // Deflectors parameter if(m_DeflectorsFlags) { beh->GetInputParameterValue(BOUNCE,&m_Bounce); if(m_VariancesFlags & PV_BOUNCE) beh->GetInputParameterValue(BOUNCEVARIATION,&m_BounceVariation); } // Gravity parameters if(m_InteractorsFlags & PI_GRAVITY) { beh->GetInputParameterValue(WEIGHT,&m_Weight); if(m_VariancesFlags & PV_WEIGHT) beh->GetInputParameterValue(WEIGHTVARIATION,&m_WeightVariation); } // Wind parameters if(m_InteractorsFlags& (PI_LOCALWIND|PI_GLOBALWIND|PI_ATMOSPHERE)) { beh->GetInputParameterValue(SURFACE,&m_Surface); if(m_VariancesFlags & PV_SURFACE) beh->GetInputParameterValue(SURFACEVARIATION,&m_SurfaceVariation); } } void ParticleEmitter::ReadSettings(CKBehavior* beh) { // Patch to see if its not an old behavior CKParameterLocal* pl = beh->GetLocalParameter(MESSAGE); if(pl && pl->GetGUID() != CKPGUID_MESSAGE) { char buffer[256]; sprintf(buffer,"Wrong Particle System Version. Please Delete and Reattach : %s on object %s",beh->GetName(),beh->GetOwner()->GetName()); m_Context->OutputToConsole(buffer); return; } // Trail int tc = 0; beh->GetLocalParameterValue(TRAILCOUNT, &tc); /////////////////////////// // Memory Management /////////////////////////// int pn; beh->GetLocalParameterValue(PARTICLENUMBER,&pn); if ((pn != m_MaximumParticles && pn > 0) || (tc != m_TrailCount && tc > 0)) { m_TrailCount = tc; m_MaximumParticles = pn; InitParticleSystem(); } else { m_TrailCount = tc; m_MaximumParticles = pn; } /////////////////////////// // Interactors Diplay /////////////////////////// ParticleManager* pm = m_Manager; BOOL display; beh->GetLocalParameterValue(DISPLAYINTERACTORS,&display); pm->ShowInteractors(display); /////////////////////////// // Render Mode Management /////////////////////////// beh->GetLocalParameterValue(RENDERMODES,&m_RenderMode); if(m_RenderMode == PR_POINT) m_RenderParticlesCallback = RenderParticles_P; else if(m_RenderMode == PR_LINE) { if (m_TrailCount > 1) m_RenderParticlesCallback = RenderParticles_LL; else m_RenderParticlesCallback = RenderParticles_L; } else if(m_RenderMode == PR_SPRITE) { if (m_TrailCount > 1) m_RenderParticlesCallback = RenderParticles_LS; else m_RenderParticlesCallback = RenderParticles_S; } else if(m_RenderMode == PR_OBJECT) m_RenderParticlesCallback = RenderParticles_O; else if(m_RenderMode == PR_FSPRITE) m_RenderParticlesCallback = RenderParticles_FS; else if(m_RenderMode == PR_POINTSPRITE) m_RenderParticlesCallback = RenderParticles_PS; else if(m_RenderMode == PR_FIXEDPOINTSPRITE) m_RenderParticlesCallback = RenderParticles_FPS; else if(m_RenderMode == PR_OSPRITE) { if (m_TrailCount > 1) m_RenderParticlesCallback = RenderParticles_LOS; else m_RenderParticlesCallback = RenderParticles_OS; } else if(m_RenderMode == PR_CSPRITE) m_RenderParticlesCallback = RenderParticles_CS; else if(m_RenderMode == PR_RSPRITE) m_RenderParticlesCallback = RenderParticles_RS; else m_RenderParticlesCallback = 0; /* CK3dEntity* entity = (CK3dEntity*)CKGetObject(m_Entity); entity->SetRenderCallBack( m_RenderParticlesCallback, this ); */ ////////////////////////////// // Blend Factors management ////////////////////////////// beh->GetLocalParameterValue(SRCBLEND,&m_SrcBlend); beh->GetLocalParameterValue(DESTBLEND,&m_DestBlend); /////////////////////////// // Flags Management /////////////////////////// // we clear the flags m_EvolutionsFlags = 0; m_VariancesFlags = 0; m_DeflectorsFlags = 0; m_InteractorsFlags = 0; ////////////////////////////// // Evolution Management ////////////////////////////// beh->GetLocalParameterValue(EVOLUTIONS,&m_EvolutionsFlags); // management of the input parameters beh->EnableInputParameter(ENDSIZE,m_EvolutionsFlags&PE_SIZE); beh->EnableInputParameter(ENDCOLOR,m_EvolutionsFlags&PE_COLOR); beh->EnableInputParameter(SPEEDTEXTURE,m_EvolutionsFlags&PE_TEXTURE); beh->EnableInputParameter(TEXTURELOOP,m_EvolutionsFlags&PE_TEXTURE); ////////////////////////////// // Variances Management ////////////////////////////// beh->GetLocalParameterValue(VARIANCES,&m_VariancesFlags); // management of the input parameters beh->EnableInputParameter(SPEEDVARIATION,m_VariancesFlags&PV_SPEED); beh->EnableInputParameter(ANGSPEEDVARIATION,m_VariancesFlags&PV_ANGULARSPEED); beh->EnableInputParameter(LIFEVARIATION,m_VariancesFlags&PV_LIFESPAN); beh->EnableInputParameter(EMITIONVARIATION,m_VariancesFlags&PV_EMISSION); beh->EnableInputParameter(STARTSIZEVARIANCE,m_VariancesFlags&PV_INITIALSIZE); beh->EnableInputParameter(BOUNCEVARIATION,m_VariancesFlags&PV_BOUNCE); beh->EnableInputParameter(WEIGHTVARIATION,m_VariancesFlags&PV_WEIGHT); beh->EnableInputParameter(SURFACEVARIATION,m_VariancesFlags&PV_SURFACE); beh->EnableInputParameter(STARTCOLORVARIANCE,m_VariancesFlags&PV_INITIALCOLOR); beh->EnableInputParameter(STARTTEXTUREVARIANCE,m_VariancesFlags&PV_INITIALTEXTURE); //////////////////////////////// // Combined Parameters //////////////////////////////// beh->EnableInputParameter(ENDCOLORVARIANCE,m_EvolutionsFlags&PE_COLOR && m_VariancesFlags&PV_ENDINGCOLOR); beh->EnableInputParameter(ENDSIZEVARIANCE,m_EvolutionsFlags&PE_SIZE && m_VariancesFlags&PV_ENDINGSIZE); beh->EnableInputParameter(SPEEDTEXTUREVARIANCE,m_EvolutionsFlags&PE_TEXTURE && m_VariancesFlags&PV_SPEEDTEXTURE); // DEFLECTORS //----------- beh->GetLocalParameterValue(MANAGEDEFLECTORS,&m_DeflectorsFlags); // Bounce Parameter Only if Deflector beh->EnableInputParameter(BOUNCE,m_DeflectorsFlags&PD_ALL); beh->EnableInputParameter(BOUNCEVARIATION,m_DeflectorsFlags&PD_ALL && m_VariancesFlags&PV_BOUNCE); // Collision Outputs if (m_DeflectorsFlags&PD_IMPACTS) { // we have to create outputs param and ios if (beh->GetInputCount() == 3) { // first we destroy all the outputs while (beh->GetOutputParameterCount()) { CKDestroyObject(beh->RemoveOutputParameter(0)); } beh->CreateInput("Impacts Loop In"); beh->CreateOutput("Impacts Loop Out"); beh->CreateOutputParameter("Impact Position",CKPGUID_VECTOR); beh->CreateOutputParameter("Impact Direction",CKPGUID_VECTOR); beh->CreateOutputParameter("Impact Object",CKPGUID_3DENTITY); beh->CreateOutputParameter("Impact Texture Coordinates",CKPGUID_2DVECTOR); } } else { // we have to delete outputs param and ios beh->DeleteInput(3); beh->DeleteOutput(3); if (beh->GetOutputParameterCount() >= 4) { CKDestroyObject(beh->RemoveOutputParameter(3)); CKDestroyObject(beh->RemoveOutputParameter(2)); CKDestroyObject(beh->RemoveOutputParameter(1)); CKDestroyObject(beh->RemoveOutputParameter(0)); } } /// // Output are either C C C C, or C C C C P or P and nothing else CKBOOL outputParticleCount = FALSE; beh->GetLocalParameterValue(PARTICLESCOUNT,&outputParticleCount); if (outputParticleCount) { if (beh->GetOutputParameterCount() == 0 || beh->GetOutputParameterCount() == 4) { beh->CreateOutputParameter("Particle Count",CKPGUID_INT); } } else { if (beh->GetOutputParameterCount() == 1) { CKDestroyObject(beh->RemoveOutputParameter(0)); } else { // there is the collision outputs, then the p count CKDestroyObject(beh->RemoveOutputParameter(4)); } } // INTERACTORS //------------ beh->GetLocalParameterValue(MANAGEINTERACTORS,&m_InteractorsFlags); // Weight Parameter Only if Gravity beh->EnableInputParameter(WEIGHT,m_InteractorsFlags&PI_GRAVITY); beh->EnableInputParameter(WEIGHTVARIATION,m_InteractorsFlags&PI_GRAVITY && m_VariancesFlags&PV_WEIGHT); // Surface Parameter Only if Wind beh->EnableInputParameter(SURFACE,m_InteractorsFlags & (PI_LOCALWIND|PI_GLOBALWIND|PI_ATMOSPHERE)); beh->EnableInputParameter(SURFACEVARIATION,m_InteractorsFlags & (PI_LOCALWIND|PI_GLOBALWIND|PI_ATMOSPHERE) && m_VariancesFlags&PV_SURFACE); // Group of object to throw beh->GetLocalParameterValue(OBJECTS,&m_Group); // Message to deflectors... beh->GetLocalParameterValue(MESSAGE,&m_MessageType); // fix for radial particles beh->GetLocalParameterValue(RADIALPARTICLEOFFSET, &m_RadialParticleOffset); } int ParticleEmitter::BeginPasses(CKRenderContext* dev,CKBOOL gouraud) { if (!m_Manager->m_ParticleMaterial) return 1; CKRenderContext* RdCtx = (CKRenderContext*) dev; CKMaterial* mat = m_Manager->m_ParticleMaterial; CKTexture* tex = (CKTexture*)RdCtx->GetCKContext()->GetObject(m_Texture); mat->SetTexture(tex); mat->SetSourceBlend(m_SrcBlend); mat->SetDestBlend(m_DestBlend); mat->SetShadeMode(gouraud ? VXSHADE_GOURAUD : VXSHADE_FLAT); if(m_DestBlend == VXBLEND_ZERO && ((m_SrcBlend == VXBLEND_SRCALPHA) || (m_SrcBlend == VXBLEND_SRCCOLOR) || (m_SrcBlend == VXBLEND_ONE))) { mat->EnableAlphaBlend(FALSE); mat->EnableZWrite(TRUE); } else { mat->EnableAlphaBlend(TRUE); mat->EnableZWrite(FALSE); } // RdCtx->OverrideMaterial(mat, m_OverridenMaterial); CKMaterialShader* matShader = m_OverridenMaterial.m_MaterialShader; CKShaderManager* sMan = RdCtx->m_ShaderManager; if (sMan && m_OverridenMaterial.m_MaterialShader && m_OverridenMaterial.m_ShaderTechniqueIndex >= 0) { sMan->BeginShaders(RdCtx); CKShader* fx = matShader->m_Shader; XASSERT(fx != NULL); fx->SetTechnique( m_OverridenMaterial.m_ShaderTechniqueIndex ); fx->SetParameters( matShader->m_Params ); int num_passes = fx->Begin(RdCtx); sMan->m_CurrentPassCount = num_passes; RdCtx->SetValuesOfUsedAutomatics( *fx, m_OverridenMaterial.m_ShaderMeaningMaterial, m_OverridenMaterial.m_MaterialShader, NULL); m_InShaderMode = TRUE; return num_passes; } else { dev->SetCurrentMaterial(mat, FALSE /* Lit */); // no shader mode m_InShaderMode = FALSE; return 1; } } /* void ParticleEmitter::SetState(CKRenderContext* dev,CKBOOL gouraud) { // The Texture CKTexture* tex = (CKTexture*)dev->GetCKContext()->GetObject(m_Texture); dev->SetTexture(tex); dev->SetState(VXRENDERSTATE_SPECULARENABLE, FALSE); dev->SetState(VXRENDERSTATE_FILLMODE, VXFILL_SOLID); // Gouraud / Flat if (gouraud) dev->SetState(VXRENDERSTATE_SHADEMODE, VXSHADE_GOURAUD); else dev->SetState(VXRENDERSTATE_SHADEMODE, VXSHADE_FLAT); dev->SetTextureStageState(CKRST_TSS_TEXTUREMAPBLEND,VXTEXTUREBLEND_MODULATEALPHA); dev->SetTextureStageState(CKRST_TSS_MAGFILTER , VXTEXTUREFILTER_LINEAR); dev->SetTextureStageState(CKRST_TSS_MINFILTER , VXTEXTUREFILTER_LINEARMIPLINEAR); // States dev->SetState(VXRENDERSTATE_WRAP0 , 0); dev->SetState(VXRENDERSTATE_CULLMODE, VXCULL_NONE); dev->SetState(VXRENDERSTATE_SRCBLEND, m_SrcBlend); dev->SetState(VXRENDERSTATE_DESTBLEND, m_DestBlend); if(m_DestBlend == VXBLEND_ZERO && ((m_SrcBlend == VXBLEND_SRCALPHA) || (m_SrcBlend == VXBLEND_SRCCOLOR) || (m_SrcBlend == VXBLEND_ONE))) { dev->SetState(VXRENDERSTATE_ALPHABLENDENABLE, FALSE); dev->SetState(VXRENDERSTATE_ZWRITEENABLE , TRUE); } else { dev->SetState(VXRENDERSTATE_ALPHABLENDENABLE, TRUE); dev->SetState(VXRENDERSTATE_ZWRITEENABLE , FALSE); } dev->SetTextureStageState(CKRST_TSS_STAGEBLEND,0,1); dev->SetTextureStageState(CKRST_TSS_TEXTURETRANSFORMFLAGS, 0); dev->SetTextureStageState(CKRST_TSS_TEXCOORDINDEX, 0); } */ void ParticleEmitter::BeginPass(CKRenderContext* dev, int passIndex) { if (!m_InShaderMode) return; CKRenderContext* RdCtx = (CKRenderContext*) dev; CKShaderManager* sMan = RdCtx->m_ShaderManager; sMan->m_CurrentPassIndex = passIndex; CKMaterialShader* matShader = m_OverridenMaterial.m_MaterialShader; CKShader* fx = matShader->m_Shader; XASSERT(fx != NULL); fx->ExecutePerPassMeanings( (CK3dEntity*)this, m_OverridenMaterial.m_ShaderMeaningMaterial, m_OverridenMaterial.m_MaterialShader, RdCtx ); fx->BeginPass(passIndex, dev); } void ParticleEmitter::EndPass(CKRenderContext* dev) { if (!m_InShaderMode) return; CKMaterialShader* matShader = m_OverridenMaterial.m_MaterialShader; CKShader* fx = matShader->m_Shader; XASSERT(fx != NULL); fx->EndPass(dev); } void ParticleEmitter::EndPasses(CKRenderContext* dev) { if (!m_InShaderMode) return; CKRenderContext* RdCtx = (CKRenderContext *)dev; CKShaderManager* sMan = RdCtx->m_ShaderManager; CKMaterialShader* matShader = m_OverridenMaterial.m_MaterialShader; CKShader* fx = matShader->m_Shader; XASSERT(fx != NULL); fx->End(dev); if (sMan) sMan->EndShaders(dev); } void ParticleEmitter::DrawPrimitive(CKRenderContext* dev, CKBOOL gouraud, VXPRIMITIVETYPE pType,DWORD* indices,int indexcount,VxDrawPrimitiveData* data) { // slow but working int passCount = BeginPasses(dev, gouraud); for (int i = 0; i < passCount; ++i) { BeginPass(dev, i); dev->DrawPrimitive(pType, indices, indexcount, data); EndPass(dev); } EndPasses(dev); } void ParticleEmitter::DrawPrimitive(CKRenderContext* dev, CKBOOL gouraud, VXPRIMITIVETYPE pType, WORD* indices,int indexcount,VxDrawPrimitiveData* data) { // slow but working int passCount = BeginPasses(dev, gouraud); for (int i = 0; i < passCount; ++i) { BeginPass(dev, i); dev->DrawPrimitive(pType, indices, indexcount, data); EndPass(dev); } EndPasses(dev); } ParticleEmitter::ParticleHistoric & ParticleEmitter::GetParticleHistoric(Particle *part) { typedef XClassArray t_array_ph; int idx = ((BYTE *)part - m_BackPool) / sizeof (Particle); XASSERT(idx < m_MaximumParticles); return old_pos[idx]; }