Files
FC1/RenderDll/Common/RendElements/CREParticleSpray.cpp
romkazvo 34d6c5d489 123
2023-08-07 19:29:24 +08:00

1406 lines
36 KiB
C++

/*=============================================================================
CParticleSpray.cpp : implementation of the particle effects RE.
Copyright 2001 Crytek Studios. All Rights Reserved.
Revision history:
* Created by Honitch Andrey
=============================================================================*/
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#include "RenderPCH.h"
//==================================================================
// Particle Spray
//==================================================================
CREParticleSpray::~CREParticleSpray()
{
if (mParticlePntr[0])
delete [] mParticlePntr[0];
if (mParticlePntr[1])
delete [] mParticlePntr[1];
}
/// Global Definitions ////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
CREParticleSpray& CREParticleSpray::operator = (const CREParticleSpray& Orig)
{
mfSetType(eDATA_ParticleSpray);
mfSetFlags(Orig.m_Flags);
mFrame = 0;
mParticlePool[0] = new SParticle[Orig.mEmitter.totalParticles[0]];
mParticlePntr[0] = mParticlePool[0];
// THIS IS A LINKED LIST OF PARTICLES, SO I NEED TO ESTABLISH LINKS
int loop;
for (loop=0; loop<Orig.mEmitter.totalParticles[0]-1; loop++)
{
mParticlePool[0][loop].next = &mParticlePool[0][loop + 1];
}
// SET THE LAST PARTICLE TO POINT TO NULL
mParticlePool[0][Orig.mEmitter.totalParticles[0]-1].next = NULL;
if (Orig.mEmitter.totalParticles[1])
{
mParticlePool[1] = new SParticle[Orig.mEmitter.totalParticles[1]];
mParticlePntr[1] = mParticlePool[1];
// THIS IS A LINKED LIST OF PARTICLES, SO I NEED TO ESTABLISH LINKS
for (loop=0; loop<Orig.mEmitter.totalParticles[1]-1; loop++)
{
mParticlePool[1][loop].next = &mParticlePool[1][loop + 1];
}
// SET THE LAST PARTICLE TO POINT TO NULL
mParticlePool[1][Orig.mEmitter.totalParticles[1]-1].next = NULL;
}
else
{
mParticlePntr[1] = mParticlePool[1] = NULL;
}
memcpy(&mEmitter, &Orig.mEmitter, sizeof(SEmitter));
mEmitter.particle = NULL;
return *this;
}
bool CREParticleSpray::mfInitParticleSystem(void)
{
int loop;
// SO I DON'T NEED TO DYNAMICALLY ALLOC THE PARTICLES IN THE RUNTIME
// I WANT TO PULL ALREADY CREATED PARTICLES FROM A GLOBAL POOL.
mEmitter.totalParticles[1] = mEmitter.totalParticles[0] * mEmitter.NumSparks;
mParticlePool[0] = new SParticle[mEmitter.totalParticles[0]];
mParticlePntr[0] = mParticlePool[0];
// THIS IS A LINKED LIST OF PARTICLES, SO I NEED TO ESTABLISH LINKS
for (loop=0; loop<mEmitter.totalParticles[0]-1; loop++)
{
mParticlePool[0][loop].next = &mParticlePool[0][loop + 1];
}
// SET THE LAST PARTICLE TO POINT TO NULL
mParticlePool[0][mEmitter.totalParticles[0]-1].next = NULL;
if (mEmitter.totalParticles[1])
{
mParticlePool[1] = new SParticle[mEmitter.totalParticles[1]];
mParticlePntr[1] = mParticlePool[1];
// THIS IS A LINKED LIST OF PARTICLES, SO I NEED TO ESTABLISH LINKS
for (loop=0; loop<mEmitter.totalParticles[1]-1; loop++)
{
mParticlePool[1][loop].next = &mParticlePool[1][loop + 1];
}
// SET THE LAST PARTICLE TO POINT TO NULL
mParticlePool[1][mEmitter.totalParticles[1]-1].next = NULL;
}
else
{
mParticlePool[1] = mParticlePntr[1] = NULL;
}
return TRUE;
}
///////////////////////////////////////////////////////////////////////////////
// Function: CREParticleSpray::mfInitEmitter
// Purpose: Initialize an emitter in the system
// Arguments: The emitter to initialize
///////////////////////////////////////////////////////////////////////////////
bool CREParticleSpray::mfInitEmitter(SEmitter *emitter)
{
mfSetDefaultEmitter(emitter);
emitter->particle = NULL; // NULL TERMINATED LINKED LIST
return TRUE;
}
///////////////////////////////////////////////////////////////////////////////
// Function: CREParticleSpray::mfSetDefaultEmitter
// Purpose: Set up some default settings
// Arguments: The emitter to setup
///////////////////////////////////////////////////////////////////////////////
bool CREParticleSpray::mfSetDefaultEmitter(SEmitter *emitter)
{
emitter->eCollisionType = ePCollision_None;
emitter->pi.yaw = 0;
emitter->pi.yawVar = 360.0f;
emitter->pi.pitch = 90.0f;
emitter->pi.pitchVar = 40.0f;
emitter->pi.speed = 0.05f;
emitter->pi.speedVar = 0.01f;
emitter->totalParticles[0] = MAX_PARTICLES;
emitter->totalParticles[1] = 0;
emitter->particleCount[0] = emitter->particleCount[1] = 0;
emitter->emitsPerFrame = 100;
emitter->emitVar = 15;
emitter->pi.life = 60;
emitter->pi.lifeVar = 15;
emitter->pi.startColor = CFColor(0.6f, 0.6f, 0.8f, 1.0f);
emitter->pi.startColorVar = CFColor(0.1f, 0.1f, 0.1f, 0.1f);
emitter->pi.endColor = CFColor(0.0f, 0.0f, 0.8f, 0.1f);
emitter->pi.endColorVar = CFColor(0.1f, 0.1f, 0.2f, 0.1f);
emitter->pi.force = Vec3d(0.0f, 0.0f, -0.001f);
emitter->Life = 0;
return true;
}
bool CREParticleSpray::mfCull(CCObject *obj)
{
mfUpdateEmitter(&mEmitter);
if (CRenderer::CV_r_noparticles)
return true;
CREParticleSpray::mRS.NumSprays++;
SParticle *particle;
// IF THERE IS AN EMITTER
particle = mEmitter.particle;
if (!particle)
return false;
Vec3d mins, maxs;
mins = Vec3d( 999999.0f, 999999.0f, 999999.0f);
maxs = Vec3d(-999999.0f,-999999.0f,-999999.0f);
// GO THROUGH THE PARTICLES AND UPDATE THEM
if (mEmitter.pi.ePT == ePTPoly || mEmitter.pi.ePT == ePTPoint || mEmitter.pi.ePT == ePTBeam)
{
while (particle)
{
mins.CheckMin(particle->pos);
maxs.CheckMax(particle->pos);
particle = particle->next;
}
}
else
{
while (particle)
{
mins.CheckMin(particle->pos);
maxs.CheckMax(particle->pos);
particle = particle->next;
}
}
if (mfGetFlags() & FCEF_TRANSFORM)
{
Vec3d org = Vec3d(gRenDev->m_RP.m_pCurObject->GetTranslation());
mins += org;
maxs += org;
}
//if (gfCullBox(mins, maxs))
// return true;
return false;
}
bool CREParticleSpray::mfIsValidTime(SShader *ef, CCObject *obj, float curtime)
{
if (obj->m_TempVars[0] && !mEmitter.particle)
{
return false;
}
return true;
}
static _inline void sMoveParticle(SParticle *particle, SParticleInfo *pi)
{
int i;
Vec3d v(0,0,0);
float wf;
float f;
for (i=0; i<pi->mNumMoves; i++)
{
SPartMoveStage *pm = &pi->mMoves[i];
switch(pm->eMoveType)
{
case eMTWave:
wf = SEvalFuncs::EvalWaveForm(&pm->WaveMove);
particle->realPos += particle->moveDir * wf;
break;
case eMTWhirl:
wf = SEvalFuncs::EvalWaveForm(&pm->WaveMove);
//RotatePointAroundVector(&v[0], &particle->moveDir[0], &particle->realPos[0], wf);
particle->realPos = v;
break;
case eMTSqueeze:
f = (float)particle->life / particle->startLife;
wf = SEvalFuncs::EvalWaveForm2(&pm->WaveMove, f);
f = particle->realPos[2];
particle->realPos *= wf;
particle->realPos[2] = f;
break;
}
}
}
static void sUpdatePart(SParticle *particle, SParticleInfo *pi, bool bSpark)
{
// SAVE ITS OLD POS FOR ANTI ALIASING
if (pi->ePT != ePTBeam)
{
if (pi->StackSize == 1)
{
particle->prevPos[0] = particle->realPos;
}
else
{
int n = pi->StackSize - 1;
while(n>=0)
{
particle->prevPos[n] = particle->prevPos[n-1];
n--;
}
particle->prevPos[0] = particle->realPos;
}
// CALCULATE THE NEW
particle->pos = particle->pos + particle->dir;
particle->realPos = particle->pos;
}
if (pi->mNumMoves)
sMoveParticle(particle, pi);
if (pi->Squeeze)
{
float frac = (float)particle->life / particle->startLife;
frac *= pi->Squeeze;
particle->realPos[0] *= frac;
particle->realPos[1] *= frac;
}
// APPLY GLOBAL FORCE TO DIRECTION
particle->dir = particle->dir + pi->force;
// SAVE THE OLD COLOR
particle->prevColor = particle->color;
// GET THE NEW COLOR
particle->color += particle->deltaColor;
particle->curSize += particle->deltaSize;
particle->life--; // IT IS A CYCLE OLDER
}
STrace (*Trace) (Vec3d& start, Vec3d& mins, Vec3d& maxs, Vec3d& end, CCObject *passobj, int contentmask);
_inline void LerpVector (Vec3d& a, Vec3d& b, float f, Vec3d& res)
{
for (int i=0; i<3; i++)
{
res[i] = LERP(a[i], b[i], f);
}
}
///////////////////////////////////////////////////////////////////////////////
// Function: CREParticleSpray::mfUpdateParticle
// Purpose: mfUpdateParticle settings
// Arguments: The particle to update and the emitter it came from
///////////////////////////////////////////////////////////////////////////////
bool CREParticleSpray::mfUpdateParticle(SParticle *particle,SEmitter *emitter)
{
// IF THIS IS AN VALID PARTICLE
if (particle != NULL && particle->life > 0)
{
if (!particle->bSpark)
sUpdatePart(particle, &emitter->pi, false);
else
sUpdatePart(particle, &emitter->Spark, true);
if (emitter->eCollisionType && !particle->bSpark)
{
if (emitter->eCollisionType == ePCollision_Plane)
{
Vec3d v, v0, v1;
Vec3d org = gRenDev->m_RP.m_pCurObject->GetTranslation();
v = org + emitter->PlaneOffs;
float planeDist = v | emitter->PlaneAxis;
v0 = org + particle->prevPos[0];
v1 = org + particle->realPos;
float d0 = (v0 | emitter->PlaneAxis) - planeDist;
float d1 = (v1 | emitter->PlaneAxis) - planeDist;
if (d0>=0 && d1<=0)
{
if (d0-d1)
{
float f = (d0 - 0.1f) / (d0 - d1);
LerpVector(particle->realPos, particle->prevPos[0], f, particle->realPos);
}
particle->life = 0;
mfEmitSparks(particle, emitter);
}
}
else
if (emitter->eCollisionType == ePCollision_True)
{
Vec3d v0, v1, org;
org = gRenDev->m_RP.m_pCurObject->GetTranslation();
v0 = org + particle->prevPos[0];
v1 = org + particle->realPos;
/*STrace trace = Trace (&v0[0], Vec3d.Clear(), Vec3d.Clear(), &v1[0], (CCObject *)gRenDev->m_RP.m_pCurObject, MASK_OPAQUE);
if (trace.fraction < 0.99f)
{
float f = trace.fraction;
LerpVector(&particle->prevPos[0][0], &particle->realPos[0], f, &particle->realPos[0]);
particle->life = 0;
mfEmitSparks(particle, emitter);
}*/
}
}
return TRUE;
}
else
if (particle != NULL && particle->life == 0)
{
// FREE THIS SUCKER UP BACK TO THE MAIN POOL
if (particle->prev != NULL)
particle->prev->next = particle->next;
else
emitter->particle = particle->next;
// FIX UP THE NEXT'S PREV POINTER IF THERE IS A NEXT
if (particle->next != NULL)
particle->next->prev = particle->prev;
particle->next = mParticlePool[particle->bSpark];
mParticlePool[particle->bSpark] = particle; // NEW POOL POINTER
emitter->particleCount[particle->bSpark]--; // ADD ONE TO POOL
}
return FALSE;
}
///////////////////////////////////////////////////////////////////////////////
// Function: sRotationToDirection
// Purpose: Convert a Yaw and Pitch to a direction vector
///////////////////////////////////////////////////////////////////////////////
static void sRotationToDirection(float pitch,float yaw,Vec3d& direction)
{
direction[0] = (float)(-sin_tpl(yaw) * cos_tpl(pitch));
direction[1] = (float)sin_tpl(pitch);
direction[2] = (float)(cos_tpl(pitch) * cos_tpl(yaw));
}
static Vec3d sOrg;
void CREParticleSpray::mfEmitSparks(SParticle *p, SEmitter *emitter)
{
sOrg = p->realPos;
for (int i=0; i<emitter->NumSparks; i++)
{
mfAddParticle(emitter, &emitter->Spark);
}
}
inline void AxisFromAngles(const Vec3d& v, Vec3d* forward, Vec3d* right, Vec3d* up)
{
float angle;
float sr, sp, sy, cr, cp, cy;
angle = (v.y * ((float)PI / 180.0f));
sy = (float)sin_tpl(angle);
cy = (float)cos_tpl(angle);
angle = (v.x * ((float)PI / 180.0f));
sp = (float)sin_tpl(angle);
cp = (float)cos_tpl(angle);
angle = (v.z * ((float)PI / 180.0f));
sr = (float)sin_tpl(angle);
cr = (float)cos_tpl(angle);
if (forward)
{
forward->x = cp*cy;
forward->y = cp*sy;
forward->z = -sp;
}
if (right)
{
right->x = (-1*sr*sp*cy+-1*cr*-sy);
right->y = (-1*sr*sp*sy+-1*cr*cy);
right->z = -1*sr*cp;
}
if (up)
{
up->x = (cr*sp*cy+-sr*-sy);
up->y = (cr*sp*sy+-sr*cy);
up->z = cr*cp;
}
}
///////////////////////////////////////////////////////////////////////////////
// Function: CREParticleSpray::mfAddParticle
// Purpose: add a particle to an emitter
// Arguments: The emitter to add to
///////////////////////////////////////////////////////////////////////////////
bool CREParticleSpray::mfAddParticle(SEmitter *emitter, SParticleInfo *pi)
{
/// Local Variables ///////////////////////////////////////////////////////////
SParticle *particle;
CFColor colend;
float yaw, pitch, speed;
///////////////////////////////////////////////////////////////////////////////
// IF THERE IS AN EMITTER AND A PARTICLE IN THE POOL
// AND I HAVEN'T EMITTED MY MAX
bool bSpark = (pi == &emitter->Spark);
if (emitter != NULL && mParticlePool[bSpark] != NULL && emitter->particleCount[bSpark] < emitter->totalParticles[bSpark])
{
particle = mParticlePool[bSpark]; // THE CURRENT PARTICLE
mParticlePool[bSpark] = mParticlePool[bSpark]->next; // FIX THE POOL POINTERS
if (emitter->particle != NULL)
emitter->particle->prev = particle; // SET BACK LINK
particle->bSpark = bSpark;
particle->next = emitter->particle; // SET ITS NEXT POINTER
particle->prev = NULL; // IT HAS NO BACK POINTER
emitter->particle = particle; // SET IT IN THE EMITTER
if (pi->ePT != ePTBeam)
{
if (!bSpark)
{
Vec3d var = Vec3d(emitter->startPosVar.x*RandomNum(),emitter->startPosVar.y*RandomNum(),emitter->startPosVar.z*RandomNum());
particle->pos = emitter->startPos + var;
}
else
{
particle->pos = sOrg;
}
particle->realPos = particle->pos;
int n = pi->StackSize;
while (n>=0)
{
particle->prevPos[n-1] = particle->pos; // USED FOR ANTI ALIAS
n--;
}
// CALCULATE THE STARTING DIRECTION VECTOR
yaw = pi->yaw + (pi->yawVar * RandomNum());
pitch = pi->pitch + (pi->pitchVar * RandomNum());
// CONVERT THE ROTATIONS TO A VECTOR
Vec3d v;
v[PITCH] = -pitch;
v[YAW] = yaw;
v[ROLL] = 0;
AxisFromAngles( v, &particle->dir, NULL, NULL);
}
else
{
particle->pos = gRenDev->m_RP.m_pCurObject->GetTranslation();
particle->realPos = particle->pos;
particle->prevPos[0] = Vec3d(gRenDev->m_RP.m_pCurObject->m_Trans2[0], gRenDev->m_RP.m_pCurObject->m_Trans2[1], gRenDev->m_RP.m_pCurObject->m_Trans2[2]);
}
Vec3d var = Vec3d(pi->moveDirVar.x*RandomNum(), pi->moveDirVar.y*RandomNum(),pi->moveDirVar.z*RandomNum());
particle->moveDir = pi->moveDir + var;
// MULTIPLY IN THE SPEED FACTOR
speed = pi->speed + (pi->speedVar * RandomNum());
particle->dir *= speed;
// CALCULATE THE COLORS
CFColor c;
c = CFColor(RandomNum(), RandomNum(), RandomNum(), RandomNum());
particle->color = pi->startColor + (pi->startColorVar * c);
particle->color.Clamp();
c = CFColor(RandomNum(), RandomNum(), RandomNum(), RandomNum());
colend = pi->endColor + (pi->endColorVar * c);
colend.Clamp();
// CALCULATE THE LIFE SPAN
particle->life = pi->life + (int)((float)pi->lifeVar * RandomNum());
particle->startLife = particle->life;
// CREATE THE COLOR DELTA
particle->deltaColor = (colend - particle->color) / (float)particle->life;
particle->curSize = pi->startSize + (RandomNum() * pi->startSizeVar);
float endSize = pi->endSize + (RandomNum() * pi->endSizeVar);
particle->deltaSize = (endSize - particle->curSize) / particle->life;
emitter->particleCount[bSpark]++; // A NEW PARTICLE IS BORN
return true;
}
return false;
}
///////////////////////////////////////////////////////////////////////////////
// Function: CREParticleSpray::mfUpdateEmitter
// Purpose: Update Emitter setting
// Arguments: The Emitter to update
// Notes: This is called once per frame to update the emitter
///////////////////////////////////////////////////////////////////////////////
bool CREParticleSpray::mfUpdateEmitter(SEmitter *emitter)
{
/// Local Variables ///////////////////////////////////////////////////////////
int loop,emits;
SParticle *particle, *next;
///////////////////////////////////////////////////////////////////////////////
if (mFrame == gRenDev->m_RP.m_RenderFrame)
return TRUE;
mFrame = gRenDev->m_RP.m_RenderFrame;
// IF THERE IS AN EMITTER
if (emitter != NULL)
{
if (emitter->particle != NULL)
{
// GO THROUGH THE PARTICLES AND UPDATE THEM
particle = emitter->particle;
while (particle)
{
next = particle->next; // SAVE THIS BECAUSE IT MAY CHANGE UNDER ME
mfUpdateParticle(particle,emitter);
particle = next;
}
}
// EMIT PARTICLES FOR THIS FRAME
emits = emitter->emitsPerFrame + (int)((float)emitter->emitVar * RandomNum());
if (emitter->Life < 0)
{
if (gRenDev->m_RP.m_pCurObject->m_TempVars[0] + emits < emitter->totalParticles[0])
{
gRenDev->m_RP.m_pCurObject->m_TempVars[0] += emits;
}
else
{
emits = (int)(emitter->totalParticles[0] - gRenDev->m_RP.m_pCurObject->m_TempVars[0]);
gRenDev->m_RP.m_pCurObject->m_TempVars[0] = (float)emitter->totalParticles[0];
}
}
for (loop = 0; loop < emits; loop++)
mfAddParticle(emitter, &emitter->pi);
return true;
}
return false;
}
void CREParticleSpray::mfPrepare()
{
static int inds[] = {3, 0, 2, 2, 0, 1};
int n;
int np;
CREParticleSpray::mRS.NumRendSprays++;
if (mEmitter.pi.ePT == ePTPoint || mEmitter.pi.ePT == ePTLine)
{
//gRenDev->mfRenderSimpleParticleEmitter(&mEmitter, mfGetFlags());
return;
}
if (mEmitter.pi.ePT != ePTPoly && mEmitter.pi.ePT != ePTPolySegs && mEmitter.pi.ePT != ePTBeam)
return;
SEmitter *em = &mEmitter;
SParticle *pt;
Vec3d vc1, vc2, vc3, vc4;
SShader *ef = gRenDev->m_RP.m_pShader;
int savev = gRenDev->m_RP.m_RendNumVerts;
int savei = gRenDev->m_RP.m_RendNumIndices;
Vec3d vecVel;
if (em != NULL)
{
if (em->particle != NULL)
{
pt = em->particle;
np = 0;
Vec3d VecX, VecY;
VecX = gRenDev->m_RP.m_CamVecs[1];
VecY = gRenDev->m_RP.m_CamVecs[2];
vc1 = VecX + VecY;
vc2 = -VecX + VecY;
vc3 = -VecX - VecY;
vc4 = VecX - VecY;
n = gRenDev->m_RP.m_RendNumVerts;
int steps;
float oldDist = -9999.0f;
UPipeVertex ptr = gRenDev->m_RP.m_NextPtr;
byte *cols;
if (!(gRenDev->m_RP.m_FT & FLT_COL))
cols = (byte *)(&gRenDev->m_RP.m_pClientColors[n]);
else
cols = gRenDev->m_RP.m_NextPtr.PtrB+gRenDev->m_RP.m_OffsD;
while (pt)
{
CREParticleSpray::mRS.NumParticles++;
Vec3d vecTL, vecBL, vecBR, vecTR;
float dist;
EParticleType ePT;
float so;
int ms, ss;
dist = pt->curSize * 0.5f;
if (pt->bSpark)
{
ePT = em->Spark.ePT;
ms = em->Spark.segmMax;
so = em->Spark.segmOffs;
ss = em->Spark.StackSize;
}
else
{
ePT = em->pi.ePT;
ms = em->pi.segmMax;
so = em->pi.segmOffs;
ss = em->pi.StackSize;
}
if (dist != oldDist)
{
oldDist = dist;
vecTL = vc1 * dist;
vecBL = vc2 * dist;
vecBR = vc3 * dist;
vecTR = vc4 * dist;
}
Vec3d vecPos;
if (ePT == ePTPoly)
{
steps = 1;
vecPos = (pt->realPos);
}
else
{
vecPos = pt->prevPos[ss-1];
vecVel = pt->realPos - vecPos;
float fL2 = GetLengthSquared(vecVel);
if (!fL2)
steps = 1;
else
{
fL2 = cry_sqrtf(fL2);
float fst = fL2 / (pt->curSize * so);
if (fst <= 1)
steps = 1;
else
{
vecVel /= fst;
steps = QRound(fst);
if (steps > ms)
steps = ms;
}
}
}
bvec4 c;
if ((gRenDev->m_RP.m_FT & FLT_COL) && gbRgb)
{
c[2] = (byte)QRound(pt->color[0] * 255.0f);
c[1] = (byte)QRound(pt->color[1] * 255.0f);
c[0] = (byte)QRound(pt->color[2] * 255.0f);
c[3] = (byte)QRound(pt->color[3] * 255.0f);
}
else
{
c[0] = (byte)QRound(pt->color[0] * 255.0f);
c[1] = (byte)QRound(pt->color[1] * 255.0f);
c[2] = (byte)QRound(pt->color[2] * 255.0f);
c[3] = (byte)QRound(pt->color[3] * 255.0f);
}
for(int i=0; i<steps; i++)
{
if (n+4 >= gRenDev->m_RP.m_MaxVerts || gRenDev->m_RP.m_RendNumIndices+2*3 >= gRenDev->m_RP.m_MaxTris*3)
{
gRenDev->m_RP.m_RendNumVerts = n;
gRenDev->m_RP.m_pRenderFunc();
gRenDev->EF_Start(gRenDev->m_RP.m_pShader, gRenDev->m_RP.m_pStateShader, NULL, gRenDev->m_RP.m_pFogVolume ? (gRenDev->m_RP.m_pFogVolume-&gRenDev->m_RP.m_FogVolumes[0]) : 0, this);
n = 0;
ptr = gRenDev->m_RP.m_NextPtr;
}
for (int ii=0; ii<6; ii++)
{
gRenDev->m_RP.m_RendIndices[gRenDev->m_RP.m_RendNumIndices++] = inds[ii]+n;
}
/*if (!(gRenDev->m_RP.mFT & FLT_COL))
{
int nn = gRenDev->m_RP.m_Stride;
ptr.Ptr_D_2T->xyz[0] = vecPos.x + vecTL.x;
ptr.Ptr_D_2T->xyz[1] = vecPos.y + vecTL.y;
ptr.Ptr_D_2T->xyz[2] = vecPos.z + vecTL.z;
*(uint *)(&cols[0]) = *(uint *)c;
ptr.Ptr_D_2T->st[0][0] = 0;
ptr.Ptr_D_2T->st[0][1] = 0;
ptr.PtrB += nn;
ptr.Ptr_D_2T->xyz[0] = vecPos.x + vecBL.x;
ptr.Ptr_D_2T->xyz[1] = vecPos.y + vecBL.y;
ptr.Ptr_D_2T->xyz[2] = vecPos.z + vecBL.z;
*(uint *)(&cols[4]) = *(uint *)c;
ptr.Ptr_D_2T->st[0][0] = 1.0f;
ptr.Ptr_D_2T->st[0][1] = 0;
ptr.PtrB += nn;
ptr.Ptr_D_2T->xyz[0] = vecPos.x + vecBR.x;
ptr.Ptr_D_2T->xyz[1] = vecPos.y + vecBR.y;
ptr.Ptr_D_2T->xyz[2] = vecPos.z + vecBR.z;
*(uint *)(&cols[8]) = *(uint *)c;
ptr.Ptr_D_2T->st[0][0] = 1.0f;
ptr.Ptr_D_2T->st[0][1] = 1.0f;
ptr.PtrB += nn;
ptr.Ptr_D_2T->xyz[0] = vecPos.x + vecTR.x;
ptr.Ptr_D_2T->xyz[1] = vecPos.y + vecTR.y;
ptr.Ptr_D_2T->xyz[2] = vecPos.z + vecTR.z;
*(uint *)(&cols[12]) = *(uint *)c;
ptr.Ptr_D_2T->st[0][0] = 0;
ptr.Ptr_D_2T->st[0][1] = 1.0f;
ptr.PtrB += nn;
cols += 16;
}
else
{
int nn = gRenDev->m_RP.m_Stride;
ptr.Ptr_D_2T->xyz[0] = vecPos.x + vecTL.x;
ptr.Ptr_D_2T->xyz[1] = vecPos.y + vecTL.y;
ptr.Ptr_D_2T->xyz[2] = vecPos.z + vecTL.z;
*(uint *)(&cols[0]) = *(uint *)c;
ptr.Ptr_D_2T->st[0][0] = 0;
ptr.Ptr_D_2T->st[0][1] = 0;
ptr.PtrB += nn;
cols += nn;
ptr.Ptr_D_2T->xyz[0] = vecPos.x + vecBL.x;
ptr.Ptr_D_2T->xyz[1] = vecPos.y + vecBL.y;
ptr.Ptr_D_2T->xyz[2] = vecPos.z + vecBL.z;
*(uint *)(&cols[0]) = *(uint *)c;
ptr.Ptr_D_2T->st[0][0] = 1.0f;
ptr.Ptr_D_2T->st[0][1] = 0;
ptr.PtrB += nn;
cols += nn;
ptr.Ptr_D_2T->xyz[0] = vecPos.x + vecBR.x;
ptr.Ptr_D_2T->xyz[1] = vecPos.y + vecBR.y;
ptr.Ptr_D_2T->xyz[2] = vecPos.z + vecBR.z;
*(uint *)(&cols[0]) = *(uint *)c;
ptr.Ptr_D_2T->st[0][0] = 1.0f;
ptr.Ptr_D_2T->st[0][1] = 1.0f;
ptr.PtrB += nn;
cols += nn;
ptr.Ptr_D_2T->xyz[0] = vecPos.x + vecTR.x;
ptr.Ptr_D_2T->xyz[1] = vecPos.y + vecTR.y;
ptr.Ptr_D_2T->xyz[2] = vecPos.z + vecTR.z;
*(uint *)(&cols[0]) = *(uint *)c;
ptr.Ptr_D_2T->st[0][0] = 0;
ptr.Ptr_D_2T->st[0][1] = 1.0f;
ptr.PtrB += nn;
cols += nn;
}*/
n += 4;
vecPos += vecVel;
}
pt = pt->next;
np++;
}
gRenDev->m_RP.m_RendNumVerts = n;
gRenDev->m_RP.m_NextPtr = ptr;
}
}
if (em->Life)
{
if (em->Life < 0)
{
if (!np)
{
//gRenDev->m_RP.m_pCurObject->m_ObjFlags |= FOB_NOTVISIBLE;
}
return;
}
else
if (gRenDev->m_RP.m_RealTime - gRenDev->m_RP.m_pCurObject->m_StartTime >= em->Life)
{
//gRenDev->m_RP.m_pCurObject->m_ObjFlags |= FOB_NOTVISIBLE;
return;
}
}
CREParticleSpray::mRS.NumVerts += gRenDev->m_RP.m_RendNumVerts - savev;
CREParticleSpray::mRS.NumIndices += gRenDev->m_RP.m_RendNumIndices - savei;
}
//======================================================================
SParticleStat CREParticleSpray::mRS;
void CREParticleSpray::mfPrintStat()
{
/* char str[1024];
*gpCurPrX = 4;
sprintf(str, "Num Indices: %i\n", mRS.NumIndices);
gRenDev->mfPrintString (str, PS_TRANSPARENT | PS_UP);
*gpCurPrX = 4;
sprintf(str, "Num Verts: %i\n", mRS.NumVerts);
gRenDev->mfPrintString (str, PS_TRANSPARENT | PS_UP);
*gpCurPrX = 4;
sprintf(str, "Num Render Particles: %i\n", mRS.NumParticles);
gRenDev->mfPrintString (str, PS_TRANSPARENT | PS_UP);
*gpCurPrX = 4;
sprintf(str, "Num Render Particle Sprays: %i\n", mRS.NumRendSprays);
gRenDev->mfPrintString (str, PS_TRANSPARENT | PS_UP);
*gpCurPrX = 4;
sprintf(str, "Num Added Particle Sprays: %i\n", mRS.NumSprays);
gRenDev->mfPrintString (str, PS_TRANSPARENT | PS_UP);
*gpCurPrX = 4;
gRenDev->mfPrintString ("\nParticles status info:\n", PS_TRANSPARENT | PS_UP);*/
}
//=================================================================================
// Parsing
bool CREParticleSpray::mfCompileMoveTypeWave(SShader *ef, SPartMoveStage *pm, char *scr)
{
char* name;
long cmd;
char *params;
enum {eWaveForm=1};
static tokenDesc commands[] =
{
{eWaveForm, "WaveForm"},
{0,0}
};
while ((cmd = shGetObject (&scr, commands, &name, &params)) > 0)
{
switch (cmd)
{
case eWaveForm:
gRenDev->m_cEF.mfCompileWaveForm(&pm->WaveMove, params);
break;
}
}
return true;
}
bool CREParticleSpray::mfCompileMoveTypeWhirl(SShader *ef, SPartMoveStage *pm, char *scr)
{
char* name;
long cmd;
char *params;
enum {eWaveForm=1};
static tokenDesc commands[] =
{
{eWaveForm, "WaveForm"},
{0,0}
};
while ((cmd = shGetObject (&scr, commands, &name, &params)) > 0)
{
switch (cmd)
{
case eWaveForm:
gRenDev->m_cEF.mfCompileWaveForm(&pm->WaveMove, params);
break;
}
}
return true;
}
bool CREParticleSpray::mfCompileMoveTypeSqueeze(SShader *ef, SPartMoveStage *pm, char *scr)
{
char* name;
long cmd;
char *params;
enum {eWaveForm=1};
static tokenDesc commands[] =
{
{eWaveForm, "WaveForm"},
{0,0}
};
while ((cmd = shGetObject (&scr, commands, &name, &params)) > 0)
{
switch (cmd)
{
case eWaveForm:
gRenDev->m_cEF.mfCompileWaveForm(&pm->WaveMove, params);
break;
}
}
return true;
}
bool CREParticleSpray::mfCompileMove(SShader *ef, SPartMoveStage *pm, SParticleInfo *pi, char *scr)
{
char* name;
long cmd;
char *params;
char *data;
enum {eType=1, eDir, eVarDir};
static tokenDesc commands[] =
{
{eType, "Type"},
{eDir, "Dir"},
{eVarDir, "VarDir"},
{0,0}
};
while ((cmd = shGetObject (&scr, commands, &name, &params)) > 0)
{
data = NULL;
if (name)
data = name;
else
if (params)
data = params;
switch (cmd)
{
case eType:
if (!data || !data[0])
{
Warning( 0,0,"missing parameters for Move Type in Particle Client Shader '%s' (Skipping)\n", ef->m_Name.c_str());
return false;
}
if (!stricmp(data, "Wave"))
{
if (mfCompileMoveTypeWave(ef, pm, params))
pm->eMoveType = eMTWave;
else
return false;
}
else
if (!stricmp(data, "Whirl"))
{
if (mfCompileMoveTypeWhirl(ef, pm, params))
pm->eMoveType = eMTWhirl;
else
return false;
}
else
if (!stricmp(data, "Squeeze"))
{
if (mfCompileMoveTypeSqueeze(ef, pm, params))
pm->eMoveType = eMTSqueeze;
else
return false;
}
else
{
Warning( 0,0,"Unknown move type '%s' in Shader '%s' (skipping)\n", data, ef->m_Name.c_str());
return false;
}
break;
case eDir:
shGetVector(data, pi->moveDir);
break;
case eVarDir:
shGetVector(data, pi->moveDirVar);
break;
}
}
return true;
}
void CREParticleSpray::mfCompileCollision(SShader *ef, SEmitter *em, char *scr, char *Collide)
{
char* name;
long cmd;
char *params;
char *data;
enum {ePlaneAxis=1, ePlaneOffs, eSparks, eNumSparks};
static tokenDesc commands[] =
{
{ePlaneAxis, "PlaneAxis"},
{ePlaneOffs, "PlaneOffs"},
{eSparks, "Sparks"},
{eNumSparks, "NumSparks"},
{0,0}
};
if (!stricmp(Collide, "True"))
em->eCollisionType = ePCollision_True;
else
if (!stricmp(Collide, "Plane"))
em->eCollisionType = ePCollision_Plane;
else
{
Warning( 0,0,"Can't determine collision type '%s' in Shader '%s' (skipping)\n", Collide, ef->m_Name.c_str());
em->eCollisionType = ePCollision_None;
return;
}
em->NumSparks = 4;
em->PlaneAxis = Vec3d(0, 0, -1);
em->PlaneOffs.Set(0.0f,0.0f,0.0f);
while ((cmd = shGetObject (&scr, commands, &name, &params)) > 0)
{
data = NULL;
if (name)
data = name;
else
if (params)
data = params;
switch (cmd)
{
case ePlaneAxis:
if (!data || !data[0])
{
Warning( 0,0,"missing parameters for PlaneAxis in Particle Client Shader '%s' (Use default)\n", ef->m_Name.c_str());
break;
}
shGetVector(data, em->PlaneAxis);
break;
case ePlaneOffs:
if (!data || !data[0])
{
Warning( 0,0,"missing parameters for PlaneOffs in Particle Client Shader '%s' (Use default)\n", ef->m_Name.c_str());
break;
}
shGetVector(data, em->PlaneOffs);
break;
case eSparks:
mfCompileParticleInfo(ef, &em->Spark, params);
break;
case eNumSparks:
em->NumSparks = shGetInt(data);
break;
}
}
}
void CREParticleSpray::mfCompileParticleInfo(SShader *ef, SParticleInfo *pi, char *scr)
{
char* name;
long cmd;
char *params;
char *data;
enum {eAntiAlias=1, ePoints, eLines, ePolySegs, ePolygons, eBeam, eYaw, eVarYaw, ePitch, eVarPitch, eSpeed, eVarSpeed, eLife, eVarLife, eStartColor, eVarStartColor, eEndColor, eVarEndColor, eForce, eSize, eStartSize, eEndSize, eVarStartSize, eVarEndSize, eSegmOffs, eSegmsMax, eMove, eStackSize, eSqueeze};
static tokenDesc commands[] =
{
{eYaw, "Yaw"},
{eVarYaw, "VarYaw"},
{ePitch, "Pitch"},
{eVarPitch, "VarPitch"},
{eSpeed, "Speed"},
{eVarSpeed, "VarSpeed"},
{eLife, "Life"},
{eVarLife, "VarLife"},
{eSize, "Size"},
{eStartSize, "StartSize"},
{eEndSize, "EndSize"},
{eVarStartSize, "VarStartSize"},
{eVarEndSize, "VarEndSize"},
{eSegmOffs, "SegmOffs"},
{eSegmsMax, "SegmsMax"},
{ePoints, "Points"},
{eLines, "Lines"},
{ePolygons, "Polygons"},
{ePolySegs, "PolySegs"},
{eBeam, "Beam"},
{eStartColor, "StartColor"},
{eVarStartColor, "VarStartColor"},
{eEndColor, "EndColor"},
{eVarEndColor, "VarEndColor"},
{eForce, "Force"},
{eMove, "Move"},
{eStackSize, "StackSize"},
{eSqueeze, "Squeeze"},
{0,0}
};
pi->mNumMoves = 0;
pi->StackSize = 1;
pi->Squeeze = 0;
while ((cmd = shGetObject (&scr, commands, &name, &params)) > 0)
{
data = NULL;
if (name)
data = name;
else
if (params)
data = params;
switch (cmd)
{
case eAntiAlias:
pi->Flags |= FP_ANTIALIAS;
break;
case ePoints:
pi->ePT = ePTPoint;
break;
case eLines:
pi->ePT = ePTLine;
break;
case ePolygons:
pi->ePT = ePTPoly;
break;
case ePolySegs:
pi->ePT = ePTPolySegs;
break;
case eBeam:
pi->ePT = ePTBeam;
break;
case eYaw:
pi->yaw = shGetFloat(data);
break;
case eVarYaw:
pi->yawVar = shGetFloat(data);
break;
case ePitch:
pi->pitch = shGetFloat(data);
break;
case eVarPitch:
pi->pitchVar = shGetFloat(data);
break;
case eSpeed:
pi->speed = shGetFloat(data);
break;
case eVarSpeed:
pi->speedVar = shGetFloat(data);
break;
case eSqueeze:
pi->Squeeze = shGetFloat(data);
break;
case eLife:
pi->life = shGetInt(data);
break;
case eVarLife:
pi->lifeVar = shGetInt(data);
break;
case eStartColor:
shGetColor(data, pi->startColor);
break;
case eVarStartColor:
shGetColor(data, pi->startColorVar);
break;
case eEndColor:
shGetColor(data, pi->endColor);
break;
case eVarEndColor:
shGetColor(data, pi->endColorVar);
break;
case eForce:
shGetVector(data, pi->force);
break;
case eSize:
pi->startSize = shGetFloat(data);
pi->endSize = pi->startSize;
pi->startSizeVar = pi->endSizeVar = 0;
break;
case eStartSize:
pi->startSize = shGetFloat(data);
break;
case eEndSize:
pi->endSize = shGetFloat(data);
break;
case eVarStartSize:
pi->startSizeVar = shGetFloat(data);
break;
case eVarEndSize:
pi->endSizeVar = shGetFloat(data);
break;
case eSegmOffs:
pi->segmOffs = shGetFloat(data);
break;
case eSegmsMax:
pi->segmMax = shGetInt(data);
break;
case eStackSize:
pi->StackSize = shGetInt(data);
break;
case eMove:
if (pi->mNumMoves == MAX_PART_MOVE_STAGES)
{
Warning( 0,0,"MAX_PART_MOVE_STAGES hit in Shader '%s'\n", ef->m_Name.c_str());
}
else
if (mfCompileMove(ef, &pi->mMoves[pi->mNumMoves], pi, params))
{
pi->mNumMoves++;
}
break;
}
}
}
bool CREParticleSpray::mfCompile(SShader *ef, char *scr)
{
char* name;
long cmd;
char *params;
char *data;
enum {eParticle = 1, eTotalParticles, eEmits, eVarEmits, eStartPos, eVarStartPos, eCollide, eLife, eAllowMerge};
static tokenDesc commands[] =
{
{eTotalParticles, "TotalParticles"},
{eAllowMerge, "AllowMerge"},
{eEmits, "Emits"},
{eVarEmits, "VarEmits"},
{eParticle, "Particle"},
{eStartPos, "StartPos"},
{eVarStartPos, "VarStartPos"},
{eCollide, "Collide"},
{eLife, "Life"},
{0,0}
};
SEmitter *em = mfGetEmitter();
while ((cmd = shGetObject (&scr, commands, &name, &params)) > 0)
{
data = NULL;
if (name)
data = name;
else
if (params)
data = params;
switch (cmd)
{
case eTotalParticles:
em->totalParticles[0] = shGetInt(data);
break;
case eAllowMerge:
mfClearFlags(FCEF_TRANSFORM);
break;
case eEmits:
em->emitsPerFrame = shGetInt(data);
break;
case eVarEmits:
em->emitVar = shGetInt(data);
break;
case eStartPos:
shGetVector(data, em->startPos);
break;
case eVarStartPos:
shGetVector(data, em->startPosVar);
break;
case eLife:
em->Life = shGetFloat(data);
break;
case eParticle:
mfCompileParticleInfo(ef, &em->pi, params);
break;
case eCollide:
if (!data || !data[0])
{
Warning( 0,0,"Missing Collide arg in Particle Shader '%s'\n", ef->m_Name.c_str());
break;
}
mfCompileCollision(ef, em, params, data);
break;
}
}
mfInitParticleSystem();
return true;
}