deargui-vpl/ref/virtools/Samples/Behaviors/ParticlesSystem/behaviors src/ParticleEmitter.cpp

1228 lines
35 KiB
C++

#include "CKAll.h"
#include <time.h>
#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<ThreadParam> PSqueue;
#endif
// Destructeur
ParticleEmitter::~ParticleEmitter()
{
#ifdef USE_THR
if (hasBeenEnqueud) {
WaitForSingleObject(hasBeenComputedEvent, INFINITE);
while (hasBeenEnqueud) {
int a = 0;
}
}
EnterCriticalSection(&PSqueue.mGuardAccess);
for (list<ThreadParam>::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 && totalParticles<pCount ) {
p->m_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<ParticleEmitter::ParticleHistoric> t_array_ph;
int idx = ((BYTE *)part - m_BackPool) / sizeof (Particle);
XASSERT(idx < m_MaximumParticles);
return old_pos[idx];
}