1741 lines
42 KiB
C++
1741 lines
42 KiB
C++
|
|
#include "CKAll.h"
|
|
|
|
#include "CKRasterizer.h"
|
|
|
|
#include "ParticleEmitter.h"
|
|
#include "ParticleSystemRenderCallbacks.h"
|
|
|
|
int (*renderParticles)(CKRenderContext *dev,CKRenderObject *obj,void *arg);
|
|
|
|
// ACC - July 10,2002
|
|
// Need to add code into each RenderCB to test if shutdown
|
|
// Then we need to wait on PE to be finished
|
|
//
|
|
extern VxMutex logguard;
|
|
extern FILE* ACCLOG;
|
|
|
|
#ifdef USE_THR
|
|
void
|
|
ThreadWaitForCompletion(ParticleEmitter* em,const char* RenderingMethod)
|
|
{
|
|
#ifdef MT_VERB
|
|
// ACC, July 10, 2002
|
|
{
|
|
VxMutexLock lock (logguard);
|
|
fprintf(ACCLOG, "About to render a %s\n",RenderingMethod);
|
|
fflush(ACCLOG);
|
|
}
|
|
#endif
|
|
|
|
// Wait
|
|
if (!em->hasBeenRendered && em->hasBeenEnqueud) {
|
|
WaitForSingleObject(em->hasBeenComputedEvent, INFINITE);
|
|
em->hasBeenRendered = TRUE;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
bool
|
|
IsRenderingNeeded(ParticleEmitter *em)
|
|
{
|
|
// This section of code can go into the render call back, and return premature
|
|
// if particle is shutdown
|
|
// if there is no more particles and the behavior is inactive
|
|
// We get the activity
|
|
CKBehavior* beh = em->m_Behavior;
|
|
|
|
int activity = 0;
|
|
beh->GetLocalParameterValue(1,&activity);
|
|
|
|
if(!activity && !(em->getParticles())) {
|
|
ShowParticles(beh,FALSE);
|
|
beh->ActivateOutput(1);
|
|
return false;
|
|
}
|
|
|
|
if(!em->particleCount)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
int
|
|
RenderParticles_P(CKRenderContext *dev,CKRenderObject *obj,void *arg)
|
|
{
|
|
CK3dEntity* mov = (CK3dEntity *)obj;
|
|
ParticleEmitter *em = (ParticleEmitter*)arg;
|
|
|
|
#ifdef USE_THR
|
|
ThreadWaitForCompletion(em,"Point");
|
|
#endif
|
|
if (!IsRenderingNeeded(em))
|
|
return CKBR_OK;
|
|
|
|
VxDrawPrimitiveData* data = dev->GetDrawPrimitiveStructure(CKRST_DP_TR_CL_VC,em->particleCount);
|
|
|
|
VxMatrix oldmatrix = dev->GetWorldTransformationMatrix();
|
|
dev->SetWorldTransformationMatrix(oldmatrix*mov->GetInverseWorldMatrix());
|
|
|
|
// we don't let write to the ZBuffer
|
|
dev->SetTexture(NULL);
|
|
dev->SetState(VXRENDERSTATE_ZWRITEENABLE , FALSE);
|
|
dev->SetState(VXRENDERSTATE_SRCBLEND, em->m_SrcBlend);
|
|
dev->SetState(VXRENDERSTATE_DESTBLEND, em->m_DestBlend);
|
|
if(em->m_DestBlend!=VXBLEND_ZERO) dev->SetState(VXRENDERSTATE_ALPHABLENDENABLE, TRUE);
|
|
else dev->SetState(VXRENDERSTATE_ALPHABLENDENABLE, FALSE);
|
|
dev->SetTextureStageState(CKRST_TSS_STAGEBLEND,0,1);
|
|
|
|
Particle* p = em->getParticles();
|
|
|
|
XPtrStrided<VxVector4> positions(data->Positions);
|
|
XPtrStrided<DWORD> colors(data->Colors);
|
|
|
|
while(p) {
|
|
*positions = p->pos;
|
|
*colors = RGBAFTOCOLOR(&(p->m_Color));
|
|
|
|
// next point
|
|
p = p->next;
|
|
|
|
++colors;
|
|
++positions;
|
|
}
|
|
|
|
// The drawing
|
|
dev->DrawPrimitive(VX_POINTLIST,(WORD*)NULL,em->particleCount,data);
|
|
|
|
// we let write to the ZBuffer
|
|
dev->SetState(VXRENDERSTATE_ZWRITEENABLE , TRUE);
|
|
|
|
dev->SetWorldTransformationMatrix(oldmatrix);
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
RenderParticles_L(CKRenderContext *dev,CKRenderObject *obj,void *arg)
|
|
{
|
|
CK3dEntity* mov = (CK3dEntity *)obj;
|
|
ParticleEmitter *em = (ParticleEmitter*)arg;
|
|
|
|
#ifdef USE_THR
|
|
ThreadWaitForCompletion(em,"Line");
|
|
#endif
|
|
if (!IsRenderingNeeded(em))
|
|
return CKBR_OK;
|
|
|
|
VxDrawPrimitiveData* data = dev->GetDrawPrimitiveStructure(CKRST_DP_TR_CL_VC,2*em->particleCount);
|
|
|
|
VxMatrix oldmatrix = dev->GetWorldTransformationMatrix();
|
|
dev->SetWorldTransformationMatrix(oldmatrix*mov->GetInverseWorldMatrix());
|
|
|
|
// we don't let write to the ZBuffer
|
|
dev->SetTexture(NULL);
|
|
dev->SetState(VXRENDERSTATE_ZWRITEENABLE , FALSE);
|
|
dev->SetState(VXRENDERSTATE_SRCBLEND, em->m_SrcBlend);
|
|
dev->SetState(VXRENDERSTATE_DESTBLEND, em->m_DestBlend);
|
|
if(em->m_DestBlend!=VXBLEND_ZERO) dev->SetState(VXRENDERSTATE_ALPHABLENDENABLE, TRUE);
|
|
else dev->SetState(VXRENDERSTATE_ALPHABLENDENABLE, FALSE);
|
|
dev->SetTextureStageState(CKRST_TSS_STAGEBLEND,0,1);
|
|
|
|
Particle* p = em->getParticles();
|
|
int i=0;
|
|
VxColor oldColor;
|
|
|
|
XPtrStrided<VxVector4> positions(data->Positions);
|
|
XPtrStrided<DWORD> colors(data->Colors);
|
|
|
|
while(p) {
|
|
// Colors
|
|
oldColor.r = p->m_Color.r - p->deltaColor.r*p->m_DeltaTime;
|
|
oldColor.g = p->m_Color.g - p->deltaColor.g*p->m_DeltaTime;
|
|
oldColor.b = p->m_Color.b - p->deltaColor.b*p->m_DeltaTime;
|
|
oldColor.a = p->m_Color.a - p->deltaColor.a*p->m_DeltaTime;
|
|
|
|
// Start of line
|
|
*positions = p->pos - p->dir*p->m_DeltaTime;
|
|
++positions;
|
|
|
|
*colors = RGBAFTOCOLOR(&oldColor);
|
|
++colors;
|
|
|
|
|
|
// End of line
|
|
*positions = p->pos + p->dir*p->m_Angle;
|
|
++positions;
|
|
|
|
*colors = RGBAFTOCOLOR(&(p->m_Color));
|
|
++colors;
|
|
|
|
// Next particle
|
|
p = p->next;
|
|
}
|
|
|
|
// the Drawing itself
|
|
dev->DrawPrimitive(VX_LINELIST,(WORD*)NULL,em->particleCount,data);
|
|
|
|
// we let write to the ZBuffer
|
|
dev->SetState(VXRENDERSTATE_ZWRITEENABLE , TRUE);
|
|
|
|
dev->SetWorldTransformationMatrix(oldmatrix);
|
|
return 0;
|
|
}
|
|
|
|
|
|
int
|
|
RenderParticles_LL(CKRenderContext *dev,CKRenderObject *obj,void *arg)
|
|
{
|
|
CK3dEntity* mov = (CK3dEntity *)obj;
|
|
ParticleEmitter *em = (ParticleEmitter*)arg;
|
|
|
|
#ifdef USE_THR
|
|
ThreadWaitForCompletion(em,"LongLine");
|
|
#endif
|
|
if (!IsRenderingNeeded(em))
|
|
return CKBR_OK;
|
|
|
|
VxDrawPrimitiveData* data = dev->GetDrawPrimitiveStructure(CKRST_DP_TR_CL_VC,
|
|
(em->m_TrailCount) * 2 * em->particleCount);
|
|
|
|
VxMatrix oldmatrix = dev->GetWorldTransformationMatrix();
|
|
dev->SetWorldTransformationMatrix(oldmatrix*mov->GetInverseWorldMatrix());
|
|
|
|
// we don't let write to the ZBuffer
|
|
dev->SetTexture(NULL);
|
|
dev->SetState(VXRENDERSTATE_ZWRITEENABLE , FALSE);
|
|
dev->SetState(VXRENDERSTATE_SRCBLEND, em->m_SrcBlend);
|
|
dev->SetState(VXRENDERSTATE_DESTBLEND, em->m_DestBlend);
|
|
if(em->m_DestBlend!=VXBLEND_ZERO) dev->SetState(VXRENDERSTATE_ALPHABLENDENABLE, TRUE);
|
|
else dev->SetState(VXRENDERSTATE_ALPHABLENDENABLE, FALSE);
|
|
dev->SetTextureStageState(CKRST_TSS_STAGEBLEND,0,1);
|
|
|
|
Particle* p = em->getParticles();
|
|
int i=0;
|
|
VxColor oldColor;
|
|
|
|
XPtrStrided<VxVector4> positions(data->Positions);
|
|
XPtrStrided<DWORD> colors(data->Colors);
|
|
|
|
DWORD num_prims = 0;
|
|
while(p)
|
|
{
|
|
#define for if (false) {} else for
|
|
ParticleEmitter::ParticleHistoric &ph = em->GetParticleHistoric(p);
|
|
|
|
// L. Puts the particle in the VB
|
|
// Assumes, that when count isn't to the max, start is always 0;
|
|
unsigned int prev = 0;
|
|
unsigned int px = 1;
|
|
unsigned int l1end = 0;
|
|
unsigned int l2end = 0;
|
|
if (ph.start == 0)
|
|
{
|
|
l1end = ph.count;
|
|
l2end = 0;
|
|
}
|
|
else
|
|
{
|
|
l1end = ph.start;
|
|
l2end = ph.particles.Size();
|
|
|
|
*positions = ph.particles[l2end - 1].pos;
|
|
++positions;
|
|
|
|
*colors = RGBAFTOCOLOR(&(p->m_Color));
|
|
++colors;
|
|
|
|
*positions = ph.particles[0].pos;
|
|
++positions;
|
|
|
|
*colors = RGBAFTOCOLOR(&(p->m_Color));
|
|
++colors;
|
|
}
|
|
for (; px < l1end; prev = px++)
|
|
{
|
|
*positions = ph.particles[prev].pos;
|
|
++positions;
|
|
|
|
*colors = RGBAFTOCOLOR(&(p->m_Color));
|
|
++colors;
|
|
|
|
*positions = ph.particles[px].pos;
|
|
++positions;
|
|
|
|
*colors = RGBAFTOCOLOR(&(p->m_Color));
|
|
++colors;
|
|
}
|
|
for (prev = px++; px < l2end; prev = px++)
|
|
{
|
|
*positions = ph.particles[prev].pos;
|
|
++positions;
|
|
|
|
*colors = RGBAFTOCOLOR(&(p->m_Color));
|
|
++colors;
|
|
|
|
*positions = ph.particles[px].pos;
|
|
++positions;
|
|
|
|
*colors = RGBAFTOCOLOR(&(p->m_Color));
|
|
++colors;
|
|
}
|
|
num_prims += ph.count - 1;
|
|
|
|
// Next particle
|
|
p = p->next;
|
|
}
|
|
|
|
// the Drawing itself
|
|
dev->DrawPrimitive(VX_LINELIST,(WORD*)NULL,num_prims,data);
|
|
|
|
// we let write to the ZBuffer
|
|
dev->SetState(VXRENDERSTATE_ZWRITEENABLE , TRUE);
|
|
|
|
dev->SetWorldTransformationMatrix(oldmatrix);
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int
|
|
RenderParticles_S(CKRenderContext *dev,CKRenderObject *obj,void *arg)
|
|
{
|
|
CK3dEntity* mov = (CK3dEntity *)obj;
|
|
ParticleEmitter *em = (ParticleEmitter*)arg;
|
|
|
|
#ifdef USE_THR
|
|
ThreadWaitForCompletion(em,"Sprite");
|
|
#endif
|
|
if (!IsRenderingNeeded(em))
|
|
return CKBR_OK;
|
|
|
|
const int VBUFFERSIZE = 4000;
|
|
|
|
int pc = em->particleCount;
|
|
#ifndef PSX2
|
|
VxDrawPrimitiveData* data = dev->GetDrawPrimitiveStructure((CKRST_DPFLAGS)(CKRST_DP_TR_CL_VCT|CKRST_DP_VBUFFER),(4*pc>VBUFFERSIZE)?VBUFFERSIZE:4*pc);
|
|
#else
|
|
VxDrawPrimitiveData* data = dev->GetDrawPrimitiveStructure((CKRST_DPFLAGS)(CKRST_DP_TR_CL_VCT),(4*pc>VBUFFERSIZE)?VBUFFERSIZE:4*pc);
|
|
#endif
|
|
|
|
XPtrStrided<VxUV> uvs(data->TexCoord);
|
|
XPtrStrided<VxVector4> positions(data->Positions);
|
|
XPtrStrided<DWORD> colors(data->Colors);
|
|
|
|
///
|
|
// Indices
|
|
if (pc*6 > ParticleEmitter::m_GlobalIndicesCount) {
|
|
delete [] ParticleEmitter::m_GlobalIndices;
|
|
|
|
ParticleEmitter::m_GlobalIndicesCount = pc*6;
|
|
ParticleEmitter::m_GlobalIndices = new WORD[ParticleEmitter::m_GlobalIndicesCount];
|
|
|
|
int ni = 0;
|
|
int fi = 0;
|
|
for (int i=0; i<pc; ++i) {
|
|
ParticleEmitter::m_GlobalIndices[fi] = ni;
|
|
ParticleEmitter::m_GlobalIndices[fi+1] = ni+1;
|
|
ParticleEmitter::m_GlobalIndices[fi+2] = ni+2;
|
|
ParticleEmitter::m_GlobalIndices[fi+3] = ni;
|
|
ParticleEmitter::m_GlobalIndices[fi+4] = ni+2;
|
|
ParticleEmitter::m_GlobalIndices[fi+5] = ni+3;
|
|
fi += 6;
|
|
ni += 4;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
// Render States
|
|
// TMP TMP em->SetState(dev);
|
|
|
|
|
|
CK3dEntity *cam = dev->GetViewpoint();
|
|
const VxMatrix& mat = cam->GetWorldMatrix();
|
|
VxMatrix oldmatrix = dev->GetWorldTransformationMatrix();
|
|
VxMatrix realmatrix = oldmatrix*mov->GetInverseWorldMatrix();
|
|
dev->SetWorldTransformationMatrix(realmatrix);
|
|
VxVector camright; Vx3DRotateVector(&camright,realmatrix,&mat[0]);
|
|
VxVector camup; Vx3DRotateVector(&camup,realmatrix,&mat[1]);
|
|
|
|
camright.Normalize();
|
|
camup.Normalize();
|
|
|
|
BOOL changeuv = FALSE;
|
|
float step = 1.0f;
|
|
int framehc = 0;
|
|
if(em->m_TextureFrameCount>1) {
|
|
changeuv = TRUE;
|
|
framehc = 1+(int)(sqrtf((float)(em->m_TextureFrameCount-1)));
|
|
step = 1.0f/framehc;
|
|
}
|
|
|
|
Particle* p = em->getParticles();
|
|
|
|
VxVector cr,cu;
|
|
VxVector rcr,rcu;
|
|
VxVector pos;
|
|
|
|
float u = 0.0f;
|
|
float v = 0.0f;
|
|
|
|
int np=0;
|
|
int remaining = 4*pc;
|
|
|
|
unsigned int (*ColorConvertor) (const VxColor*);
|
|
if (dev->GetRasterizerContext()->m_Driver->m_3DCaps.CKRasterizerSpecificCaps & CKRST_SPECIFICCAPS_VERTEXCOLORABGR)
|
|
ColorConvertor = &BGRAFTOCOLOR;
|
|
else
|
|
ColorConvertor = &RGBAFTOCOLOR;
|
|
|
|
|
|
while(p) {
|
|
pos = p->pos;
|
|
|
|
// Precalcul for positions
|
|
float halfsize = p->m_Size*0.5f;
|
|
cr = camright*halfsize;
|
|
cu = camup*halfsize;
|
|
|
|
// Angle rotation, if necessary
|
|
if(p->m_Angle) {
|
|
float cosa = cosf(p->m_Angle);
|
|
float sina = sinf(p->m_Angle);
|
|
rcr = cr*cosa - cu*sina;
|
|
rcu = cr*sina + cu*cosa;
|
|
cr = rcr;
|
|
cu = rcu;
|
|
}
|
|
|
|
// Precalcul for color
|
|
// We must now swap the color according to the rasterizer
|
|
DWORD col = (*ColorConvertor)(&(p->m_Color));
|
|
|
|
// Precalcul for uvs
|
|
if (changeuv) {
|
|
v = 0.0f;
|
|
int c = p->m_CurrentFrame;
|
|
|
|
while(c >= framehc) {
|
|
v += step;
|
|
c -= framehc;
|
|
}
|
|
u=c*step;
|
|
}
|
|
|
|
|
|
// Filling vertices
|
|
*positions = pos-cr+cu;
|
|
++positions;
|
|
*colors = col;
|
|
++colors;
|
|
uvs->u = u;
|
|
uvs->v = v;
|
|
++uvs;
|
|
|
|
*positions = pos+cr+cu;
|
|
++positions;
|
|
*colors = col;
|
|
++colors;
|
|
uvs->u = u+step;
|
|
uvs->v = v;
|
|
++uvs;
|
|
|
|
*positions = pos+cr-cu;
|
|
++positions;
|
|
*colors = col;
|
|
++colors;
|
|
uvs->u = u+step;
|
|
uvs->v = v+step;
|
|
++uvs;
|
|
|
|
*positions = pos-cr-cu;
|
|
++positions;
|
|
*colors = col;
|
|
++colors;
|
|
uvs->u = u;
|
|
uvs->v = v+step;
|
|
++uvs;
|
|
|
|
++np;
|
|
p = p->next;
|
|
|
|
if (np*4 == VBUFFERSIZE) { // need to flush the vertex buffer
|
|
// The Primitive Drawing
|
|
em->DrawPrimitive(dev, FALSE, VX_TRIANGLELIST, ParticleEmitter::m_GlobalIndices, 6*np, data );
|
|
|
|
remaining -= VBUFFERSIZE;
|
|
np = 0; // restart
|
|
|
|
if (remaining > 0) {
|
|
#ifndef PSX2
|
|
data = dev->GetDrawPrimitiveStructure((CKRST_DPFLAGS)(CKRST_DP_TR_CL_VCT|CKRST_DP_VBUFFER),(remaining>VBUFFERSIZE)?VBUFFERSIZE:remaining);
|
|
#else
|
|
data = dev->GetDrawPrimitiveStructure((CKRST_DPFLAGS)(CKRST_DP_TR_CL_VCT),(remaining>VBUFFERSIZE)?VBUFFERSIZE:remaining);
|
|
#endif
|
|
uvs = data->TexCoord;
|
|
positions = data->Positions;
|
|
colors = data->Colors;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
// The Primitive Drawing
|
|
if (remaining) em->DrawPrimitive(dev, FALSE, VX_TRIANGLELIST, ParticleEmitter::m_GlobalIndices, 6*np, data );
|
|
|
|
// we let write to the ZBuffer
|
|
dev->SetState(VXRENDERSTATE_ZWRITEENABLE , TRUE);
|
|
|
|
dev->SetWorldTransformationMatrix(oldmatrix);
|
|
return 1;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Long sprite (with trail)
|
|
int
|
|
RenderParticles_LS(CKRenderContext *dev,CKRenderObject *obj,void *arg)
|
|
{
|
|
CK3dEntity* mov = (CK3dEntity *)obj;
|
|
ParticleEmitter *em = (ParticleEmitter*)arg;
|
|
|
|
#ifdef USE_THR
|
|
ThreadWaitForCompletion(em,"LongSprite");
|
|
#endif
|
|
if (!IsRenderingNeeded(em))
|
|
return CKBR_OK;
|
|
|
|
const int VBUFFERSIZE = 4000;
|
|
|
|
assert(em->m_TrailCount > 0);
|
|
int pc = em->particleCount * em->m_TrailCount;
|
|
#ifndef PSX2
|
|
VxDrawPrimitiveData* data = dev->GetDrawPrimitiveStructure((CKRST_DPFLAGS)(CKRST_DP_TR_CL_VCT|CKRST_DP_VBUFFER),(4*pc>VBUFFERSIZE)?VBUFFERSIZE:4*pc);
|
|
#else
|
|
VxDrawPrimitiveData* data = dev->GetDrawPrimitiveStructure((CKRST_DPFLAGS)(CKRST_DP_TR_CL_VCT),(4*pc>VBUFFERSIZE)?VBUFFERSIZE:4*pc);
|
|
#endif
|
|
|
|
XPtrStrided<VxUV> uvs(data->TexCoord);
|
|
XPtrStrided<VxVector4> positions(data->Positions);
|
|
XPtrStrided<DWORD> colors(data->Colors);
|
|
|
|
|
|
///
|
|
// Indices
|
|
if (pc*6 > ParticleEmitter::m_GlobalIndicesCount) {
|
|
delete [] ParticleEmitter::m_GlobalIndices;
|
|
|
|
ParticleEmitter::m_GlobalIndicesCount = pc*6;
|
|
ParticleEmitter::m_GlobalIndices = new WORD[ParticleEmitter::m_GlobalIndicesCount];
|
|
|
|
int ni = 0;
|
|
int fi = 0;
|
|
for (int i=0; i<pc; ++i) {
|
|
ParticleEmitter::m_GlobalIndices[fi] = ni;
|
|
ParticleEmitter::m_GlobalIndices[fi+1] = ni+1;
|
|
ParticleEmitter::m_GlobalIndices[fi+2] = ni+2;
|
|
ParticleEmitter::m_GlobalIndices[fi+3] = ni;
|
|
ParticleEmitter::m_GlobalIndices[fi+4] = ni+2;
|
|
ParticleEmitter::m_GlobalIndices[fi+5] = ni+3;
|
|
fi += 6;
|
|
ni += 4;
|
|
}
|
|
}
|
|
|
|
// Render States
|
|
// TMP TMP em->SetState(dev);
|
|
|
|
CK3dEntity *cam = dev->GetViewpoint();
|
|
const VxMatrix& mat = cam->GetWorldMatrix();
|
|
VxMatrix oldmatrix = dev->GetWorldTransformationMatrix();
|
|
VxMatrix realmatrix = oldmatrix*mov->GetInverseWorldMatrix();
|
|
dev->SetWorldTransformationMatrix(realmatrix);
|
|
VxVector camright; Vx3DRotateVector(&camright,realmatrix,&mat[0]);
|
|
VxVector camup; Vx3DRotateVector(&camup,realmatrix,&mat[1]);
|
|
|
|
camright.Normalize();
|
|
camup.Normalize();
|
|
|
|
BOOL changeuv = FALSE;
|
|
float step = 1.0f;
|
|
int framehc = 0;
|
|
if(em->m_TextureFrameCount>1) {
|
|
changeuv = TRUE;
|
|
framehc = 1+(int)(sqrtf((float)(em->m_TextureFrameCount-1)));
|
|
step = 1.0f/framehc;
|
|
}
|
|
|
|
Particle* p = em->getParticles();
|
|
|
|
int np=0;
|
|
int remaining = 4*pc;
|
|
|
|
while(p)
|
|
{
|
|
struct local
|
|
{
|
|
static inline void FillParticle(const Particle *p,
|
|
VxDrawPrimitiveData* data, XPtrStrided<VxVector4>& positions, XPtrStrided<DWORD>& colors,
|
|
XPtrStrided<VxUV>& uvs, const VxVector &camup, const VxVector &camright,
|
|
BOOL changeuv, int framehc, float step)
|
|
{
|
|
VxVector pos = p->pos;
|
|
|
|
// Precalcul for positions
|
|
float halfsize = p->m_Size * 0.5f;
|
|
VxVector cr = camright*halfsize;
|
|
VxVector cu = camup*halfsize;
|
|
VxVector rcr , rcu;
|
|
|
|
// Angle rotation, if necessary
|
|
if(p->m_Angle) {
|
|
float cosa = cosf(p->m_Angle);
|
|
float sina = sinf(p->m_Angle);
|
|
rcr = cr*cosa - cu*sina;
|
|
rcu = cr*sina + cu*cosa;
|
|
cr = rcr;
|
|
cu = rcu;
|
|
}
|
|
|
|
// Precalcul for color
|
|
DWORD col = RGBAFTOCOLOR(&(p->m_Color));
|
|
|
|
float u = 0.0f;
|
|
float v = 0.0f;
|
|
// Precalcul for uvs
|
|
if (changeuv) {
|
|
v = 0.0f;
|
|
int c = p->m_CurrentFrame;
|
|
|
|
while(c >= framehc) {
|
|
v += step;
|
|
c -= framehc;
|
|
}
|
|
u=c*step;
|
|
}
|
|
|
|
// Filling vertices
|
|
*positions = pos-cr+cu;
|
|
++positions;
|
|
*colors = col;
|
|
++colors;
|
|
uvs->u = u;
|
|
uvs->v = v;
|
|
++uvs;
|
|
|
|
*positions = pos+cr+cu;
|
|
++positions;
|
|
*colors = col;
|
|
++colors;
|
|
uvs->u = u+step;
|
|
uvs->v = v;
|
|
++uvs;
|
|
|
|
*positions = pos+cr-cu;
|
|
++positions;
|
|
*colors = col;
|
|
++colors;
|
|
uvs->u = u+step;
|
|
uvs->v = v+step;
|
|
++uvs;
|
|
|
|
*positions = pos-cr-cu;
|
|
++positions;
|
|
*colors = col;
|
|
++colors;
|
|
uvs->u = u;
|
|
uvs->v = v+step;
|
|
++uvs;
|
|
}
|
|
};
|
|
|
|
// need to flush the vertex buffer
|
|
if ((np + em->m_TrailCount) * 4 > VBUFFERSIZE)
|
|
{
|
|
// The Primitive Drawing
|
|
em->DrawPrimitive(dev, FALSE, VX_TRIANGLELIST, ParticleEmitter::m_GlobalIndices, 6 * np, data );
|
|
|
|
remaining -= np * 4;
|
|
np = 0; // restart
|
|
|
|
if (remaining > 0) {
|
|
#ifndef PSX2
|
|
data = dev->GetDrawPrimitiveStructure((CKRST_DPFLAGS)(CKRST_DP_TR_CL_VCT|CKRST_DP_VBUFFER),(remaining>VBUFFERSIZE)?VBUFFERSIZE:remaining);
|
|
#else
|
|
data = dev->GetDrawPrimitiveStructure((CKRST_DPFLAGS)(CKRST_DP_TR_CL_VCT),(remaining>VBUFFERSIZE)?VBUFFERSIZE:remaining);
|
|
#endif
|
|
uvs = data->TexCoord;
|
|
positions = data->Positions;
|
|
colors = data->Colors;
|
|
}
|
|
|
|
}
|
|
|
|
if (em->m_TrailCount == 0)
|
|
{
|
|
local::FillParticle(p, data, positions, colors, uvs, camup, camright,
|
|
changeuv, framehc, step);
|
|
++np;
|
|
}
|
|
else
|
|
{
|
|
// Assumes that when start != 0, count == m_TrailCount
|
|
// So the buffer is full, and order does not matter.
|
|
ParticleEmitter::ParticleHistoric &ph = em->GetParticleHistoric(p);
|
|
|
|
for (int px = 0; px < ph.count; ++px)
|
|
{
|
|
local::FillParticle(&ph.particles[px], data, positions, colors,
|
|
uvs, camup, camright, changeuv, framehc, step);
|
|
++np;
|
|
}
|
|
}
|
|
|
|
p = p->next;
|
|
}
|
|
|
|
// The Primitive Drawing
|
|
if (remaining && np > 0)
|
|
em->DrawPrimitive(dev, FALSE, VX_TRIANGLELIST, ParticleEmitter::m_GlobalIndices, 6 * np, data );
|
|
|
|
dev->ReleaseCurrentVB();
|
|
|
|
// we let write to the ZBuffer
|
|
dev->SetState(VXRENDERSTATE_ZWRITEENABLE , TRUE);
|
|
|
|
dev->SetWorldTransformationMatrix(oldmatrix);
|
|
return 1;
|
|
}
|
|
|
|
int
|
|
RenderParticles_FS(CKRenderContext *dev,CKRenderObject *obj,void *arg)
|
|
{
|
|
CK3dEntity* mov = (CK3dEntity *)obj;
|
|
ParticleEmitter *em = (ParticleEmitter*)arg;
|
|
|
|
#ifdef USE_THR
|
|
ThreadWaitForCompletion(em,"FastSprite");
|
|
#endif
|
|
if (!IsRenderingNeeded(em))
|
|
return CKBR_OK;
|
|
|
|
int pc = em->particleCount;
|
|
VxDrawPrimitiveData* data = dev->GetDrawPrimitiveStructure((CKRST_DPFLAGS)(CKRST_DP_TR_CL_VCT),3*pc);
|
|
|
|
XPtrStrided<VxUV> uvs(data->TexCoord);
|
|
XPtrStrided<VxVector4> positions(data->Positions);
|
|
XPtrStrided<DWORD> colors(data->Colors);
|
|
|
|
// Render States
|
|
// TMP TMP em->SetState(dev);
|
|
|
|
CK3dEntity *cam = dev->GetViewpoint();
|
|
const VxMatrix& mat = cam->GetWorldMatrix();
|
|
VxMatrix oldmatrix = dev->GetWorldTransformationMatrix();
|
|
VxMatrix realmatrix = oldmatrix*mov->GetInverseWorldMatrix();
|
|
dev->SetWorldTransformationMatrix(realmatrix);
|
|
VxVector camright; Vx3DRotateVector(&camright,realmatrix,&mat[0]);
|
|
VxVector camup; Vx3DRotateVector(&camup,realmatrix,&mat[1]);
|
|
camright.Normalize();
|
|
camup.Normalize();
|
|
|
|
BOOL changeuv = FALSE;
|
|
float step = 1.0f;
|
|
int framehc = 0;
|
|
if(em->m_TextureFrameCount>1) {
|
|
changeuv = TRUE;
|
|
framehc = 1+(int)(sqrtf((float)(em->m_TextureFrameCount-1)));
|
|
step = 1.0f/framehc;
|
|
}
|
|
|
|
Particle* p = em->getParticles();
|
|
|
|
VxVector cr,cu;
|
|
VxVector rcr,rcu;
|
|
VxVector pos;
|
|
|
|
float u = 0.0f;
|
|
float v = 0.0f;
|
|
|
|
int count = 0;
|
|
while(p) {
|
|
cr = camright*p->m_Size*0.5f;
|
|
cu = camup*p->m_Size*0.5f;
|
|
|
|
// Positions
|
|
if(p->m_Angle) {
|
|
float cosa = cosf(p->m_Angle);
|
|
float sina = sinf(p->m_Angle);
|
|
rcr = cr*cosa - cu*sina;
|
|
rcu = cr*sina + cu*cosa;
|
|
cr = rcr;
|
|
cu = rcu;
|
|
}
|
|
pos = p->pos;
|
|
|
|
// Colors
|
|
DWORD col = RGBAFTOCOLOR(&(p->m_Color));
|
|
|
|
// The texture coordinates
|
|
if(changeuv) {
|
|
v = 0.0f;
|
|
int c = p->m_CurrentFrame;
|
|
|
|
while(c >= framehc) {
|
|
v += step;
|
|
c -= framehc;
|
|
}
|
|
u=c*step;
|
|
}
|
|
|
|
|
|
*positions = pos+cu;
|
|
++positions;
|
|
*colors = col;
|
|
++colors;
|
|
uvs->u = u+step*0.5f;
|
|
uvs->v = v;
|
|
++uvs;
|
|
|
|
*positions = pos+cr-cu;
|
|
++positions;
|
|
*colors = col;
|
|
++colors;
|
|
uvs->u = u+step;
|
|
uvs->v = v+step;
|
|
++uvs;
|
|
|
|
*positions = pos-cr-cu;
|
|
++positions;
|
|
*colors = col;
|
|
++colors;
|
|
uvs->u = u;
|
|
uvs->v = v+step;
|
|
++uvs;
|
|
|
|
p = p->next;
|
|
++count;
|
|
}
|
|
|
|
// The Primitive Drawing
|
|
em->DrawPrimitive(dev, FALSE, VX_TRIANGLELIST, (WORD*)NULL, 3*pc, data );
|
|
|
|
// we let write to the ZBuffer
|
|
dev->SetState(VXRENDERSTATE_ZWRITEENABLE , TRUE);
|
|
|
|
dev->SetWorldTransformationMatrix(oldmatrix);
|
|
return 1;
|
|
}
|
|
|
|
// Oriented Sprite
|
|
int
|
|
RenderParticles_OS(CKRenderContext *dev,CKRenderObject *obj,void *arg)
|
|
{
|
|
CK3dEntity* mov = (CK3dEntity *)obj;
|
|
ParticleEmitter *em = (ParticleEmitter*)arg;
|
|
|
|
#ifdef USE_THR
|
|
ThreadWaitForCompletion(em,"OrientableSprite");
|
|
#endif
|
|
if (!IsRenderingNeeded(em))
|
|
return CKBR_OK;
|
|
int pc = em->particleCount;
|
|
#ifndef PSX2
|
|
VxDrawPrimitiveData* data = dev->GetDrawPrimitiveStructure((CKRST_DPFLAGS)(CKRST_DP_TR_CL_VCT/*|CKRST_DP_VBUFFER*/),4*pc);
|
|
#else
|
|
VxDrawPrimitiveData* data = dev->GetDrawPrimitiveStructure((CKRST_DPFLAGS)(CKRST_DP_TR_CL_VCT),4*pc);
|
|
#endif
|
|
|
|
XPtrStrided<VxUV> uvs(data->TexCoord);
|
|
XPtrStrided<VxVector4> positions(data->Positions);
|
|
XPtrStrided<DWORD> colors(data->Colors);
|
|
|
|
///
|
|
// Indices
|
|
if (pc*6 > ParticleEmitter::m_GlobalIndicesCount) {
|
|
delete [] ParticleEmitter::m_GlobalIndices;
|
|
|
|
ParticleEmitter::m_GlobalIndicesCount = pc*6;
|
|
ParticleEmitter::m_GlobalIndices = new WORD[ParticleEmitter::m_GlobalIndicesCount];
|
|
|
|
int ni = 0;
|
|
int fi = 0;
|
|
for (int i=0; i<pc; ++i) {
|
|
ParticleEmitter::m_GlobalIndices[fi] = ni;
|
|
ParticleEmitter::m_GlobalIndices[fi+1] = ni+1;
|
|
ParticleEmitter::m_GlobalIndices[fi+2] = ni+2;
|
|
ParticleEmitter::m_GlobalIndices[fi+3] = ni;
|
|
ParticleEmitter::m_GlobalIndices[fi+4] = ni+2;
|
|
ParticleEmitter::m_GlobalIndices[fi+5] = ni+3;
|
|
fi += 6;
|
|
ni += 4;
|
|
}
|
|
|
|
}
|
|
|
|
// Set States
|
|
// TMP TMP em->SetState(dev,TRUE);
|
|
|
|
CK3dEntity *cam = dev->GetViewpoint();
|
|
const VxMatrix& mat = cam->GetWorldMatrix();
|
|
VxMatrix oldmatrix = dev->GetWorldTransformationMatrix();
|
|
VxMatrix realmatrix = oldmatrix*mov->GetInverseWorldMatrix();
|
|
dev->SetWorldTransformationMatrix(realmatrix);
|
|
VxVector camright; Vx3DRotateVector(&camright,realmatrix,&mat[0]);
|
|
VxVector camup; Vx3DRotateVector(&camup,realmatrix,&mat[1]);
|
|
VxVector camdir; Vx3DRotateVector(&camdir,realmatrix,&mat[2]);
|
|
camright.Normalize();
|
|
camup.Normalize();
|
|
camdir.Normalize();
|
|
|
|
BOOL changeuv = FALSE;
|
|
float step = 1.0f;
|
|
int framehc = 0;
|
|
if(em->m_TextureFrameCount>1) {
|
|
changeuv = TRUE;
|
|
framehc = 1+(int)((float)(sqrtf((float)(em->m_TextureFrameCount-1))));
|
|
step = 1.0f/framehc;
|
|
}
|
|
|
|
Particle* p = em->getParticles();
|
|
|
|
|
|
VxVector pos,dir,old,vv(0,0,0),ww(0,0,0);
|
|
float oldsize;
|
|
VxColor oldColor;
|
|
|
|
float u = 0.0f;
|
|
float v = 0.0f;
|
|
|
|
int ni = 0;
|
|
int fi = 0;
|
|
while(p) {
|
|
|
|
pos = p->pos;
|
|
dir = p->dir;
|
|
|
|
// the old pos
|
|
old = pos - dir*p->m_DeltaTime;
|
|
// the old size
|
|
oldsize = p->m_Size - p->m_DeltaSize * p->m_DeltaTime;
|
|
// we exagerate the current position according to the latenty
|
|
pos += dir*p->m_Angle;
|
|
|
|
vv = pos - old;
|
|
vv.Normalize();
|
|
ww = Normalize(CrossProduct(camdir,vv));
|
|
|
|
// the colors
|
|
oldColor.r = p->m_Color.r - p->deltaColor.r*p->m_DeltaTime;
|
|
oldColor.g = p->m_Color.g - p->deltaColor.g*p->m_DeltaTime;
|
|
oldColor.b = p->m_Color.b - p->deltaColor.b*p->m_DeltaTime;
|
|
oldColor.a = p->m_Color.a - p->deltaColor.a*p->m_DeltaTime;
|
|
|
|
DWORD col = RGBAFTOCOLOR(&(p->m_Color));
|
|
DWORD oldcol = RGBAFTOCOLOR(&oldColor);
|
|
|
|
// The texture coordinates
|
|
if(changeuv) {
|
|
v = 0.0f;
|
|
int c = p->m_CurrentFrame;
|
|
|
|
while(c >= framehc) {
|
|
v += step;
|
|
c -= framehc;
|
|
}
|
|
u=c*step;
|
|
}
|
|
|
|
// Filling vertices
|
|
*positions = pos+vv*p->m_Size+ww*p->m_Size;
|
|
++positions;
|
|
*colors = col;
|
|
++colors;
|
|
uvs->u = u;
|
|
uvs->v = v;
|
|
++uvs;
|
|
|
|
*positions = pos+vv*p->m_Size-ww*p->m_Size;
|
|
++positions;
|
|
*colors = col;
|
|
++colors;
|
|
uvs->u = u+step;
|
|
uvs->v = v;
|
|
++uvs;
|
|
|
|
*positions = old-vv*oldsize-ww*oldsize;
|
|
++positions;
|
|
*colors = oldcol;
|
|
++colors;
|
|
uvs->u = u+step;
|
|
uvs->v = v+step;
|
|
++uvs;
|
|
|
|
*positions = old-vv*oldsize+ww*oldsize;
|
|
++positions;
|
|
*colors = oldcol;
|
|
++colors;
|
|
|
|
uvs->u = u;
|
|
uvs->v = v+step;
|
|
++uvs;
|
|
|
|
p = p->next;
|
|
ni += 4;
|
|
}
|
|
|
|
// The Primitive Drawing
|
|
em->DrawPrimitive(dev, TRUE, VX_TRIANGLELIST, ParticleEmitter::m_GlobalIndices, 6*pc, data );
|
|
|
|
// we let write to the ZBuffer
|
|
dev->SetState(VXRENDERSTATE_ZWRITEENABLE , TRUE);
|
|
|
|
dev->SetWorldTransformationMatrix(oldmatrix);
|
|
return 1;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Long Oriented Sprite (with trail)
|
|
int
|
|
RenderParticles_LOS(CKRenderContext *dev,CKRenderObject *obj,void *arg)
|
|
{
|
|
CK3dEntity* mov = (CK3dEntity *)obj;
|
|
ParticleEmitter *em = (ParticleEmitter*)arg;
|
|
|
|
#ifdef USE_THR
|
|
ThreadWaitForCompletion(em,"LongOrientableSprite");
|
|
#endif
|
|
if (!IsRenderingNeeded(em))
|
|
return CKBR_OK;
|
|
|
|
const int VBUFFERSIZE = 4000;
|
|
|
|
assert(em->m_TrailCount > 1);
|
|
int pc = em->particleCount;
|
|
// Maximum number of vertices per particle.
|
|
const int num_vtx_max = (em->m_TrailCount) * 2;
|
|
// Maximum number of indices per particle.
|
|
const int num_idx_max = (em->m_TrailCount - 1) * 2 * 3;
|
|
#ifndef PSX2
|
|
VxDrawPrimitiveData* data = dev->GetDrawPrimitiveStructure((CKRST_DPFLAGS)(CKRST_DP_TR_CL_VCT|CKRST_DP_VBUFFER),(num_vtx_max*pc>VBUFFERSIZE)?VBUFFERSIZE:num_vtx_max*pc);
|
|
#else
|
|
VxDrawPrimitiveData* data = dev->GetDrawPrimitiveStructure((CKRST_DPFLAGS)(CKRST_DP_TR_CL_VCT),(num_vtx_max*pc>VBUFFERSIZE)?VBUFFERSIZE:num_vtx_max*pc);
|
|
#endif
|
|
|
|
XPtrStrided<VxUV> uvs(data->TexCoord);
|
|
XPtrStrided<VxVector4> positions(data->Positions);
|
|
XPtrStrided<DWORD> colors(data->Colors);
|
|
|
|
// Index buffer
|
|
CKWORD *index_buffer = dev->GetDrawPrimitiveIndices(pc * num_idx_max);
|
|
|
|
// Render States
|
|
// TMP TMP em->SetState(dev);
|
|
|
|
CK3dEntity *cam = dev->GetViewpoint();
|
|
const VxMatrix& mat = cam->GetWorldMatrix();
|
|
VxMatrix oldmatrix = dev->GetWorldTransformationMatrix();
|
|
VxMatrix realmatrix = oldmatrix*mov->GetInverseWorldMatrix();
|
|
dev->SetWorldTransformationMatrix(realmatrix);
|
|
VxVector camdir; Vx3DRotateVector(&camdir,realmatrix,&mat[2]);
|
|
|
|
BOOL changeuv = FALSE;
|
|
float step = 1.0f;
|
|
int framehc = 0;
|
|
if(em->m_TextureFrameCount>1) {
|
|
changeuv = TRUE;
|
|
framehc = 1+(int)(sqrtf((float)(em->m_TextureFrameCount-1)));
|
|
step = 1.0f/framehc;
|
|
}
|
|
|
|
Particle* p = em->getParticles();
|
|
|
|
int remaining = num_vtx_max * pc;
|
|
int fi=0; // face index
|
|
int ni=0; // number of indices
|
|
while(p)
|
|
{
|
|
// Precalcul for positions
|
|
float halfsize = p->m_Size * 0.5f;
|
|
VxVector cd = CrossProduct(camdir, p->dir);
|
|
cd.Normalize();
|
|
cd *= halfsize;
|
|
|
|
// Precalcul for color
|
|
DWORD col = RGBAFTOCOLOR(&(p->m_Color));
|
|
|
|
float u = 0.0f;
|
|
float v = 0.0f;
|
|
// Precalcul for uvs
|
|
if (changeuv) {
|
|
v = 0.0f;
|
|
int c = p->m_CurrentFrame;
|
|
|
|
while(c >= framehc) {
|
|
v += step;
|
|
c -= framehc;
|
|
}
|
|
u=c*step;
|
|
}
|
|
|
|
// Assumes that when start != 0, count == m_TrailCount
|
|
// So the buffer is full.
|
|
// Along u texture coordinate.
|
|
ParticleEmitter::ParticleHistoric &ph = em->GetParticleHistoric(p);
|
|
// Number of vertices per particles.
|
|
const int num_vtx = (ph.count) * 2;
|
|
|
|
// need to flush the vertex buffer
|
|
if (ni + num_vtx > VBUFFERSIZE)
|
|
{
|
|
// The Primitive Drawing
|
|
em->DrawPrimitive(dev, FALSE, VX_TRIANGLELIST, index_buffer, fi, data );
|
|
|
|
remaining -= ni;
|
|
fi = 0;
|
|
ni = 0;
|
|
|
|
if (remaining > 0)
|
|
{
|
|
#ifndef PSX2
|
|
data = dev->GetDrawPrimitiveStructure((CKRST_DPFLAGS)(CKRST_DP_TR_CL_VCT|CKRST_DP_VBUFFER),(remaining>VBUFFERSIZE)?VBUFFERSIZE:remaining);
|
|
#else
|
|
data = dev->GetDrawPrimitiveStructure((CKRST_DPFLAGS)(CKRST_DP_TR_CL_VCT),(remaining>VBUFFERSIZE)?VBUFFERSIZE:remaining);
|
|
#endif
|
|
uvs = data->TexCoord;
|
|
positions = data->Positions;
|
|
colors = data->Colors;
|
|
|
|
index_buffer = dev->GetDrawPrimitiveIndices(pc * num_idx_max);
|
|
}
|
|
}
|
|
|
|
float local_step = step * (1.0f / (ph.count + 1));
|
|
int start = ph.start;
|
|
int size = ph.count;
|
|
while (start || size)
|
|
{
|
|
for (int px = start; px < size; ++px)
|
|
{
|
|
VxVector &pos = ph.particles[px].pos;
|
|
DWORD col = RGBAFTOCOLOR(&ph.particles[px].m_Color);
|
|
|
|
// Filling vertices
|
|
*positions = pos + cd;
|
|
++positions;
|
|
*colors = col;
|
|
++colors;
|
|
uvs->u = u;
|
|
uvs->v = v;
|
|
++uvs;
|
|
|
|
*positions = pos - cd;
|
|
++positions;
|
|
*colors = col;
|
|
++colors;
|
|
uvs->u = u;
|
|
uvs->v = v + step;
|
|
++uvs;
|
|
|
|
u += local_step;
|
|
|
|
if (px != ph.start)
|
|
{
|
|
index_buffer[fi] = ni-2;
|
|
index_buffer[fi+1] = ni;
|
|
index_buffer[fi+2] = ni+1;
|
|
index_buffer[fi+3] = ni-2;
|
|
index_buffer[fi+4] = ni+1;
|
|
index_buffer[fi+5] = ni-1;
|
|
fi += 6;
|
|
}
|
|
ni += 2;
|
|
}
|
|
if (size == ph.count)
|
|
{
|
|
start = 0;
|
|
size = ph.start;
|
|
}
|
|
else
|
|
{
|
|
start = size = 0;
|
|
}
|
|
}
|
|
p = p->next;
|
|
}
|
|
|
|
// The Primitive Drawing
|
|
if (remaining && fi > 0)
|
|
{
|
|
data->VertexCount = ni;
|
|
em->DrawPrimitive(dev, FALSE, VX_TRIANGLELIST, index_buffer, fi, data);
|
|
}
|
|
dev->ReleaseCurrentVB();
|
|
// we let write to the ZBuffer
|
|
dev->SetState(VXRENDERSTATE_ZWRITEENABLE , TRUE);
|
|
|
|
dev->SetWorldTransformationMatrix(oldmatrix);
|
|
return 1;
|
|
}
|
|
|
|
// Comet Sprite
|
|
int
|
|
RenderParticles_CS(CKRenderContext *dev,CKRenderObject *obj,void *arg)
|
|
{
|
|
CK3dEntity* mov = (CK3dEntity *)obj;
|
|
ParticleEmitter *em = (ParticleEmitter*)arg;
|
|
|
|
#ifdef USE_THR
|
|
ThreadWaitForCompletion(em,"Comet");
|
|
#endif
|
|
if (!IsRenderingNeeded(em))
|
|
return CKBR_OK;
|
|
|
|
int pc = em->particleCount;
|
|
VxDrawPrimitiveData* data = dev->GetDrawPrimitiveStructure(CKRST_DP_TR_CL_VCT,4*pc);
|
|
|
|
XPtrStrided<VxUV> uvs(data->TexCoord);
|
|
XPtrStrided<VxVector4> positions(data->Positions);
|
|
XPtrStrided<DWORD> colors(data->Colors);
|
|
///
|
|
// Indices
|
|
if (pc*6 > ParticleEmitter::m_GlobalIndicesCount) {
|
|
delete [] ParticleEmitter::m_GlobalIndices;
|
|
|
|
ParticleEmitter::m_GlobalIndicesCount = pc*6;
|
|
ParticleEmitter::m_GlobalIndices = new WORD[ParticleEmitter::m_GlobalIndicesCount];
|
|
|
|
int ni = 0;
|
|
int fi = 0;
|
|
for (int i=0; i<pc; ++i) {
|
|
ParticleEmitter::m_GlobalIndices[fi] = ni;
|
|
ParticleEmitter::m_GlobalIndices[fi+1] = ni+1;
|
|
ParticleEmitter::m_GlobalIndices[fi+2] = ni+2;
|
|
ParticleEmitter::m_GlobalIndices[fi+3] = ni;
|
|
ParticleEmitter::m_GlobalIndices[fi+4] = ni+2;
|
|
ParticleEmitter::m_GlobalIndices[fi+5] = ni+3;
|
|
fi += 6;
|
|
ni += 4;
|
|
}
|
|
|
|
}
|
|
|
|
// Set States
|
|
// TMP TMP em->SetState(dev,TRUE);
|
|
|
|
CK3dEntity *cam = dev->GetViewpoint();
|
|
const VxMatrix& mat = cam->GetWorldMatrix();
|
|
VxMatrix oldmatrix = dev->GetWorldTransformationMatrix();
|
|
VxMatrix realmatrix = oldmatrix*mov->GetInverseWorldMatrix();
|
|
dev->SetWorldTransformationMatrix(realmatrix);
|
|
VxVector camright; Vx3DRotateVector(&camright,realmatrix,&mat[0]);
|
|
VxVector camup; Vx3DRotateVector(&camup,realmatrix,&mat[1]);
|
|
VxVector camdir; Vx3DRotateVector(&camdir,realmatrix,&mat[2]);
|
|
camright.Normalize();
|
|
camup.Normalize();
|
|
camdir.Normalize();
|
|
|
|
BOOL changeuv = FALSE;
|
|
float step = 1.0f;
|
|
int framehc = 0;
|
|
if(em->m_TextureFrameCount>1) {
|
|
changeuv = TRUE;
|
|
framehc = 1+(int)((float)(sqrtf((float)(em->m_TextureFrameCount-1))));
|
|
step = 1.0f/framehc;
|
|
}
|
|
|
|
Particle* p = em->getParticles();
|
|
|
|
|
|
VxVector pos,dir,center,old,vv(0,0,0),ww(0,0,0);
|
|
VxColor oldColor;
|
|
|
|
float u = 0.0f;
|
|
float v = 0.0f;
|
|
|
|
int ni = 0;
|
|
int fi = 0;
|
|
while(p) {
|
|
pos = p->pos;
|
|
dir = p->dir;
|
|
float halfsize = p->m_Size;
|
|
float speed = Magnitude(dir);
|
|
dir /= speed;
|
|
|
|
// the old pos
|
|
old = pos - dir*(2.0f*halfsize+speed*p->m_Angle*p->m_DeltaTime);
|
|
|
|
vv = pos - old;
|
|
|
|
float fu = -halfsize*DotProduct(dir,camright);
|
|
float fv = -halfsize*DotProduct(dir,camup);
|
|
ww = -fv*camright+fu*camup;
|
|
center = pos - halfsize*dir;
|
|
|
|
// w = Normalize(CrossProduct(camdir,v));
|
|
|
|
// Colors
|
|
oldColor.r = p->m_Color.r - p->deltaColor.r*p->m_DeltaTime;
|
|
oldColor.g = p->m_Color.g - p->deltaColor.g*p->m_DeltaTime;
|
|
oldColor.b = p->m_Color.b - p->deltaColor.b*p->m_DeltaTime;
|
|
oldColor.a = p->m_Color.a - p->deltaColor.a*p->m_DeltaTime;
|
|
|
|
DWORD col = RGBAFTOCOLOR(&(p->m_Color));
|
|
DWORD oldcol = RGBAFTOCOLOR(&oldColor);
|
|
|
|
// The texture coordinates
|
|
if(changeuv) {
|
|
v = 0.0f;
|
|
int c = p->m_CurrentFrame;
|
|
|
|
while(c >= framehc) {
|
|
v += step;
|
|
c -= framehc;
|
|
}
|
|
u=c*step;
|
|
}
|
|
|
|
// Filling vertices
|
|
*positions = center+ww;
|
|
++positions;
|
|
*colors = col;
|
|
++colors;
|
|
|
|
uvs->u = u;
|
|
uvs->v = v;
|
|
++uvs;
|
|
|
|
*positions = pos;
|
|
++positions;
|
|
*colors = col;
|
|
++colors;
|
|
|
|
uvs->u = u+step;
|
|
uvs->v = v;
|
|
++uvs;
|
|
|
|
*positions = center-ww;
|
|
++positions;
|
|
*colors = col;
|
|
++colors;
|
|
|
|
uvs->u = u+step;
|
|
uvs->v = v+step;
|
|
++uvs;
|
|
|
|
*positions = old;
|
|
++positions;
|
|
*colors = oldcol;
|
|
++colors;
|
|
uvs->u = u;
|
|
uvs->v = v+step;
|
|
++uvs;
|
|
|
|
p = p->next;
|
|
ni += 4;
|
|
}
|
|
|
|
// The Primitive Drawing
|
|
em->DrawPrimitive(dev, TRUE, VX_TRIANGLELIST, ParticleEmitter::m_GlobalIndices, 6*pc, data );
|
|
|
|
// we let write to the ZBuffer
|
|
dev->SetState(VXRENDERSTATE_ZWRITEENABLE , TRUE);
|
|
|
|
dev->SetWorldTransformationMatrix(oldmatrix);
|
|
return 1;
|
|
}
|
|
|
|
int
|
|
RenderParticles_RS(CKRenderContext *dev,CKRenderObject *obj,void *arg)
|
|
{
|
|
CK3dEntity* mov = (CK3dEntity *)obj;
|
|
ParticleEmitter *em = (ParticleEmitter*)arg;
|
|
// ACC, July 10, 2002
|
|
|
|
#ifdef USE_THR
|
|
ThreadWaitForCompletion(em,"Radial");
|
|
#endif
|
|
if (!IsRenderingNeeded(em))
|
|
return CKBR_OK;
|
|
|
|
int pc = em->particleCount;
|
|
VxDrawPrimitiveData* data = dev->GetDrawPrimitiveStructure(CKRST_DP_TR_CL_VCT,4*pc);
|
|
|
|
///
|
|
// Indices
|
|
if (pc*6 > ParticleEmitter::m_GlobalIndicesCount) {
|
|
delete [] ParticleEmitter::m_GlobalIndices;
|
|
|
|
ParticleEmitter::m_GlobalIndicesCount = pc*6;
|
|
ParticleEmitter::m_GlobalIndices = new WORD[ParticleEmitter::m_GlobalIndicesCount];
|
|
|
|
int ni = 0;
|
|
int fi = 0;
|
|
for (int i=0; i<pc; ++i) {
|
|
ParticleEmitter::m_GlobalIndices[fi] = ni;
|
|
ParticleEmitter::m_GlobalIndices[fi+1] = ni+1;
|
|
ParticleEmitter::m_GlobalIndices[fi+2] = ni+2;
|
|
ParticleEmitter::m_GlobalIndices[fi+3] = ni;
|
|
ParticleEmitter::m_GlobalIndices[fi+4] = ni+2;
|
|
ParticleEmitter::m_GlobalIndices[fi+5] = ni+3;
|
|
fi += 6;
|
|
ni += 4;
|
|
}
|
|
|
|
}
|
|
|
|
XPtrStrided<VxUV> uvs(data->TexCoord);
|
|
XPtrStrided<VxVector4> positions(data->Positions);
|
|
XPtrStrided<DWORD> colors(data->Colors);
|
|
|
|
// Render States
|
|
// TMP TMP em->SetState(dev);
|
|
|
|
CK3dEntity *cam = dev->GetViewpoint();
|
|
VxMatrix oldmatrix = dev->GetWorldTransformationMatrix();
|
|
dev->SetWorldTransformationMatrix( cam->GetWorldMatrix() );
|
|
|
|
BOOL changeuv = FALSE;
|
|
float step = 1.0f;
|
|
int framehc = 0;
|
|
if(em->m_TextureFrameCount>1) {
|
|
changeuv = TRUE;
|
|
framehc = 1+(int)(sqrtf((float)(em->m_TextureFrameCount-1)));
|
|
step = 1.0f/framehc;
|
|
}
|
|
|
|
Particle* p = em->getParticles();
|
|
|
|
VxVector pos,old(0,0,0),vv(0,0,0),ww(0,0,0);
|
|
|
|
float u = 0.0f;
|
|
float v = 0.0f;
|
|
|
|
CK3dEntity* ent = (CK3dEntity*)dev->GetCKContext()->GetObject(em->m_Entity);
|
|
cam->InverseTransform(&old,&vv,ent);
|
|
const VxMatrix& worldCam = cam->GetWorldMatrix();
|
|
|
|
|
|
// move the reference point backward in camera space (don't work with z-buffer test, so added the choice for this offset in the settings)
|
|
old += Normalize(old)* em->m_RadialParticleOffset;
|
|
|
|
|
|
CK_ID oldtex = -1;
|
|
|
|
const VxMatrix& invCam = cam->GetInverseWorldMatrix();
|
|
|
|
VxMatrix finalMat = /*ent->GetWorldMatrix()*/invCam;
|
|
|
|
int fi = 0;
|
|
int ni = 0;
|
|
while(p) {
|
|
|
|
Vx3DMultiplyMatrixVector(&pos,finalMat,&p->pos);
|
|
|
|
vv.x = pos.x - old.x;
|
|
vv.y = pos.y - old.y;
|
|
vv.Normalize();
|
|
ww.x = -vv.y;
|
|
ww.y = vv.x;
|
|
|
|
// the colors
|
|
DWORD col = RGBAFTOCOLOR(&(p->m_Color));
|
|
|
|
// The texture coordinates
|
|
if(changeuv) {
|
|
v = 0.0f;
|
|
int c = p->m_CurrentFrame;
|
|
|
|
while(c >= framehc) {
|
|
v += step;
|
|
c -= framehc;
|
|
}
|
|
u=c*step;
|
|
}
|
|
|
|
// Filling vertices
|
|
*positions = pos+vv*p->m_Size+ww*p->m_Size;
|
|
++positions;
|
|
*colors = col;
|
|
++colors;
|
|
uvs->u = u;
|
|
uvs->v = v;
|
|
++uvs;
|
|
|
|
*positions = pos+vv*p->m_Size-ww*p->m_Size;
|
|
++positions;
|
|
*colors = col;
|
|
++colors;
|
|
uvs->u = u+step;
|
|
uvs->v = v;
|
|
++uvs;
|
|
|
|
*positions = old-vv*p->m_Size-ww*p->m_Size;
|
|
++positions;
|
|
*colors = col;
|
|
++colors;
|
|
uvs->u = u+step;
|
|
uvs->v = v+step;
|
|
++uvs;
|
|
|
|
*positions = old-vv*p->m_Size+ww*p->m_Size;
|
|
++positions;
|
|
*colors = col;
|
|
++colors;
|
|
uvs->u = u;
|
|
uvs->v = v+step;
|
|
++uvs;
|
|
|
|
p = p->next;
|
|
ni += 4;
|
|
}
|
|
|
|
|
|
|
|
em->DrawPrimitive(dev, FALSE, VX_TRIANGLELIST, ParticleEmitter::m_GlobalIndices, pc*6, data );
|
|
|
|
// we let write to the ZBuffer
|
|
dev->SetState(VXRENDERSTATE_ZWRITEENABLE , TRUE);
|
|
|
|
dev->SetWorldTransformationMatrix(oldmatrix);
|
|
return 1;
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO : change this callback : not very nice...
|
|
int
|
|
RenderParticles_O(CKRenderContext *dev,CKRenderObject *obj,void *arg)
|
|
{
|
|
// int todo_manage_reflection_in_objects;
|
|
CK3dEntity* mov = (CK3dEntity *)obj;
|
|
ParticleEmitter *em = (ParticleEmitter*)arg;
|
|
|
|
#ifdef USE_THR
|
|
ThreadWaitForCompletion(em,"Object");
|
|
#endif
|
|
if (!IsRenderingNeeded(em))
|
|
return CKBR_OK;
|
|
|
|
VxMatrix backup = mov->GetWorldMatrix();
|
|
|
|
CKGroup* group = (CKGroup*)dev->GetCKContext()->GetObject(em->m_Group);
|
|
if(!group) return 1;
|
|
CK3dEntity* ent;
|
|
CKMaterial* mat;
|
|
CKMesh* mesh;
|
|
Particle* p = em->getParticles();
|
|
VxVector dir,up,right;
|
|
int oc = group->GetObjectCount();
|
|
while(p) {
|
|
if(p->m_GroupIndex < oc) ent = (CK3dEntity*)group->GetObject(p->m_GroupIndex);
|
|
else ent = (CK3dEntity*)group->GetObject(0);
|
|
if(CKIsChildClassOf(ent,CKCID_3DENTITY)) {
|
|
mesh = ent->GetCurrentMesh();
|
|
if(mesh) {
|
|
mat = mesh->GetFaceMaterial(0);
|
|
if(mat) mat->SetDiffuse((p->m_Color));
|
|
|
|
ent->SetPosition(&(p->pos), NULL);
|
|
dir = Normalize(p->dir);
|
|
up.Set(0,1,0);
|
|
right = CrossProduct(up,dir);
|
|
up = CrossProduct(dir,right);
|
|
ent->SetOrientation(&dir,&up,&right);
|
|
if(p->m_Angle) {
|
|
ent->Rotate(&dir,p->m_Angle);
|
|
}
|
|
VxVector v(p->m_Size,p->m_Size,p->m_Size);
|
|
ent->SetScale(&v);
|
|
ent->Render( dev, FALSE );
|
|
}
|
|
}
|
|
p = p->next;
|
|
}
|
|
|
|
dev->SetWorldTransformationMatrix(backup);
|
|
|
|
return 1;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// PointSprite (Hardware) Render
|
|
int
|
|
RenderParticles_PS(CKRenderContext *dev,CKRenderObject *obj,void *arg)
|
|
{
|
|
CK3dEntity* mov = (CK3dEntity *)obj;
|
|
ParticleEmitter *em = (ParticleEmitter*)arg;
|
|
|
|
#ifdef USE_THR
|
|
ThreadWaitForCompletion(em,"PointSprite");
|
|
#endif
|
|
if (!IsRenderingNeeded(em))
|
|
return CKBR_OK;
|
|
|
|
const int VBUFFERSIZE = 4000;
|
|
int pc = em->particleCount;
|
|
VxDrawPrimitiveData* data = dev->GetDrawPrimitiveStructure(CKRST_DPFLAGS(CKRST_DP_TR_CL_VC|CKRST_DP_VBUFFER), (pc>VBUFFERSIZE)?VBUFFERSIZE:pc);
|
|
|
|
VxMatrix oldmatrix = dev->GetWorldTransformationMatrix();
|
|
// To manage reflection
|
|
dev->SetWorldTransformationMatrix(oldmatrix*mov->GetInverseWorldMatrix());
|
|
|
|
// we don't let write to the ZBuffer
|
|
// TMP TMP em->SetState(dev);
|
|
float averageSize = em->m_StartSize * 2.0f;
|
|
float minSize = 0.0f;
|
|
float maxSize = 4096.0f;
|
|
dev->SetState(VXRENDERSTATE_POINTSPRITEENABLE, TRUE);
|
|
dev->SetState(VXRENDERSTATE_POINTSIZE, *(DWORD*)&averageSize);
|
|
dev->SetState(VXRENDERSTATE_POINTSIZE_MIN,*(DWORD*)&minSize);
|
|
dev->SetState(VXRENDERSTATE_POINTSIZE_MAX,*(DWORD*)&maxSize);
|
|
dev->SetState(VXRENDERSTATE_POINTSCALEENABLE, TRUE);
|
|
|
|
float pointScaleA = 1.0f;
|
|
float pointScaleB = 0.0f;
|
|
float pointScaleC = 1.0f;
|
|
dev->SetState(VXRENDERSTATE_POINTSCALE_A,*(DWORD*)&pointScaleA);
|
|
dev->SetState(VXRENDERSTATE_POINTSCALE_B,*(DWORD*)&pointScaleB);
|
|
dev->SetState(VXRENDERSTATE_POINTSCALE_C,*(DWORD*)&pointScaleC);
|
|
|
|
Particle* p = em->getParticles();
|
|
|
|
XPtrStrided<VxVector4> positions(data->Positions);
|
|
XPtrStrided<DWORD> colors(data->Colors);
|
|
|
|
int np = 0;
|
|
int remaining = pc;
|
|
|
|
unsigned int (*ColorConvertor) (const VxColor*);
|
|
if (dev->GetRasterizerContext()->m_Driver->m_3DCaps.CKRasterizerSpecificCaps & CKRST_SPECIFICCAPS_VERTEXCOLORABGR)
|
|
ColorConvertor = &BGRAFTOCOLOR;
|
|
else
|
|
ColorConvertor = &RGBAFTOCOLOR;
|
|
|
|
|
|
while (p) {
|
|
*positions = p->pos;
|
|
*colors = (*ColorConvertor)(&(p->m_Color));
|
|
|
|
// next point
|
|
p = p->next;
|
|
|
|
++colors;
|
|
++positions;
|
|
++np;
|
|
|
|
if (np == VBUFFERSIZE) { // need to flush the vertex buffer
|
|
// The Primitive Drawing
|
|
em->DrawPrimitive(dev, FALSE, VX_POINTLIST, (WORD*)0, np, data);
|
|
|
|
remaining -= VBUFFERSIZE;
|
|
np = 0; // restart
|
|
|
|
if (remaining > 0) {
|
|
data = dev->GetDrawPrimitiveStructure((CKRST_DPFLAGS)(CKRST_DP_TR_CL_VCT|CKRST_DP_VBUFFER),(remaining>VBUFFERSIZE)?VBUFFERSIZE:remaining);
|
|
positions = data->Positions;
|
|
colors = data->Colors;
|
|
}
|
|
}
|
|
}
|
|
|
|
// The Primitive Drawing
|
|
if (remaining)
|
|
em->DrawPrimitive(dev, FALSE, VX_POINTLIST, (WORD*)NULL, remaining, data);
|
|
|
|
// we let write to the ZBuffer
|
|
dev->SetState(VXRENDERSTATE_ZWRITEENABLE , TRUE);
|
|
dev->SetState(VXRENDERSTATE_POINTSPRITEENABLE, FALSE);
|
|
|
|
|
|
dev->SetWorldTransformationMatrix(oldmatrix);
|
|
return 0;
|
|
}
|
|
|
|
// FixedPointSprite (Hardware) Render
|
|
int
|
|
RenderParticles_FPS(CKRenderContext *dev,CKRenderObject *obj,void *arg)
|
|
{
|
|
CK3dEntity* mov = (CK3dEntity *)obj;
|
|
ParticleEmitter *em = (ParticleEmitter*)arg;
|
|
|
|
#ifdef USE_THR
|
|
ThreadWaitForCompletion(em,"PointSprite");
|
|
#endif
|
|
if (!IsRenderingNeeded(em))
|
|
return CKBR_OK;
|
|
|
|
const int VBUFFERSIZE = 4000;
|
|
int pc = em->particleCount;
|
|
VxDrawPrimitiveData* data = dev->GetDrawPrimitiveStructure(CKRST_DPFLAGS(CKRST_DP_TR_CL_VC|CKRST_DP_VBUFFER), (pc>VBUFFERSIZE)?VBUFFERSIZE:pc);
|
|
|
|
VxMatrix oldmatrix = dev->GetWorldTransformationMatrix();
|
|
// To manage reflection
|
|
dev->SetWorldTransformationMatrix(oldmatrix*mov->GetInverseWorldMatrix());
|
|
|
|
// we don't let write to the ZBuffer
|
|
// TMP TMP em->SetState(dev);
|
|
float averageSize = em->m_StartSize * 2.0f;
|
|
float minSize = 0.0f;
|
|
float maxSize = 4096.0f;
|
|
dev->SetState(VXRENDERSTATE_POINTSPRITEENABLE, TRUE);
|
|
dev->SetState(VXRENDERSTATE_POINTSIZE, *(DWORD*)&averageSize);
|
|
dev->SetState(VXRENDERSTATE_POINTSIZE_MIN,*(DWORD*)&minSize);
|
|
dev->SetState(VXRENDERSTATE_POINTSIZE_MAX,*(DWORD*)&maxSize);
|
|
dev->SetState(VXRENDERSTATE_POINTSCALEENABLE, FALSE);
|
|
|
|
Particle* p = em->getParticles();
|
|
|
|
XPtrStrided<VxVector4> positions(data->Positions);
|
|
XPtrStrided<DWORD> colors(data->Colors);
|
|
|
|
int np = 0;
|
|
int remaining = pc;
|
|
|
|
unsigned int (*ColorConvertor) (const VxColor*);
|
|
if (dev->GetRasterizerContext()->m_Driver->m_3DCaps.CKRasterizerSpecificCaps & CKRST_SPECIFICCAPS_VERTEXCOLORABGR)
|
|
ColorConvertor = &BGRAFTOCOLOR;
|
|
else
|
|
ColorConvertor = &RGBAFTOCOLOR;
|
|
|
|
|
|
while (p) {
|
|
*positions = p->pos;
|
|
*colors = (*ColorConvertor)(&(p->m_Color));
|
|
|
|
// next point
|
|
p = p->next;
|
|
|
|
++colors;
|
|
++positions;
|
|
++np;
|
|
|
|
if (np == VBUFFERSIZE) { // need to flush the vertex buffer
|
|
// The Primitive Drawing
|
|
em->DrawPrimitive(dev, FALSE, VX_POINTLIST, (WORD*)0, np, data);
|
|
|
|
remaining -= VBUFFERSIZE;
|
|
np = 0; // restart
|
|
|
|
if (remaining > 0) {
|
|
data = dev->GetDrawPrimitiveStructure((CKRST_DPFLAGS)(CKRST_DP_TR_CL_VCT|CKRST_DP_VBUFFER),(remaining>VBUFFERSIZE)?VBUFFERSIZE:remaining);
|
|
positions = data->Positions;
|
|
colors = data->Colors;
|
|
}
|
|
}
|
|
}
|
|
|
|
// The Primitive Drawing
|
|
if (remaining)
|
|
em->DrawPrimitive(dev, FALSE, VX_POINTLIST, (WORD*)NULL, remaining, data);
|
|
|
|
// we let write to the ZBuffer
|
|
dev->SetState(VXRENDERSTATE_ZWRITEENABLE , TRUE);
|
|
dev->SetState(VXRENDERSTATE_POINTSPRITEENABLE, FALSE);
|
|
|
|
|
|
dev->SetWorldTransformationMatrix(oldmatrix);
|
|
return 0;
|
|
}
|