/*
===========================================================================
ARX FATALIS GPL Source Code
Copyright (C) 1999-2010 Arkane Studios SA, a ZeniMax Media company.
This file is part of the Arx Fatalis GPL Source Code ('Arx Fatalis Source Code').
Arx Fatalis Source Code is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
Arx Fatalis Source Code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with Arx Fatalis Source Code. If not, see
.
In addition, the Arx Fatalis Source Code is also subject to certain additional terms. You should have received a copy of these
additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Arx
Fatalis Source Code. If not, please request a copy in writing from Arkane Studios at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing Arkane Studios, c/o
ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
//-----------------------------------------------------------------------------
#include "eerielight.h"
#include "eeriedraw.h"
#include "eerietypes.h"
#include "arx_time.h"
#include "arx_cspellfx.h"
#include "arx_cparticles.h"
#include "arx_cparticle.h"
#include "ARX_CParticleParams.h"
#include
#include
#include
using namespace std;
#define _CRTDBG_MAP_ALLOC
#include
void CParticleSystem::RecomputeDirection()
{
EERIE_3D eVect;
eVect.x = p3ParticleDirection.x;
eVect.y = -p3ParticleDirection.y;
eVect.z = p3ParticleDirection.z;
GenerateMatrixUsingVector(&eMat, &eVect, 0);
}
//-----------------------------------------------------------------------------
CParticleSystem::CParticleSystem()
{
int i;
for (i = 0; i < 20; i++)
{
tex_tab[i] = NULL;
}
lLightId = -1;
iParticleNbMax = 50;
ulTime = 0;
ulNbParticleGen = 10;
iParticleNbAlive = 0;
iNbTex = 0;
iTexTime = 500;
fParticleRotation = 0;
fParticleFreq = -1;
iSrcBlend = D3DBLEND_ONE;
iDstBlend = D3DBLEND_ONE;
ulParticleSpawn = 0;
// default settings for EDITOR MODE only
p3ParticleDirection.x = 0;
p3ParticleDirection.y = -1;
p3ParticleDirection.z = 0;
EERIE_3D eVect;
eVect.x = p3ParticleDirection.x;
eVect.y = -p3ParticleDirection.y;
eVect.z = p3ParticleDirection.z;
GenerateMatrixUsingVector(&eMat, &eVect, 0);
fParticleStartSize = 1;
fParticleEndSize = 1;
fParticleStartColor[0] = 0.1f;
fParticleStartColor[1] = 0.1f;
fParticleStartColor[2] = 0.1f;
fParticleStartColor[3] = 0.1f;
fParticleEndColor[0] = 0.1f;
fParticleEndColor[1] = 0.1f;
fParticleEndColor[2] = 0.1f;
fParticleEndColor[3] = 0.1f;
fParticleSpeed = 10;
fParticleLife = 1000;
p3ParticlePos.x = 0;
p3ParticlePos.y = 0;
p3ParticlePos.z = 0;
bParticleFollow = true;
fParticleFlash = 0;
fParticleRotation = 0;
bParticleRotationRandomDirection = false;
bParticleRotationRandomStart = false;
p3ParticleGravity.x = 0;
p3ParticleGravity.y = 0;
p3ParticleGravity.z = 0;
fParticleLifeRandom = 1000;
fParticleAngle = 0;
fParticleSpeedRandom = 10;
bParticleStartColorRandomLock = false;
fParticleStartSizeRandom = 1;
fParticleStartColorRandom[0] = 0.1f;
fParticleStartColorRandom[1] = 0.1f;
fParticleStartColorRandom[2] = 0.1f;
fParticleStartColorRandom[3] = 0.1f;
bParticleEndColorRandomLock = false;
fParticleEndSizeRandom = 1;
fParticleEndColorRandom[0] = 0.1f;
fParticleEndColorRandom[1] = 0.1f;
fParticleEndColorRandom[2] = 0.1f;
fParticleEndColorRandom[3] = 0.1f;
iSrcBlend = 0;
iDstBlend = 0;
iSrcBlend = D3DBLEND_ONE;
iDstBlend = D3DBLEND_ONE;
}
//-----------------------------------------------------------------------------
CParticleSystem::~CParticleSystem()
{
list::iterator i = listParticle.begin();
CParticle * pP;
while (i != listParticle.end())
{
pP = *i;
++i;
if (pP)
{
delete pP;
listParticle.remove(pP);
}
}
listParticle.clear();
}
//-----------------------------------------------------------------------------
void CParticleSystem::SetPos(Point3 _p3)
{
p3Pos.x = _p3.x;
p3Pos.y = _p3.y;
p3Pos.z = _p3.z;
if (lLightId != -1)
{
DynLight[lLightId].pos.x = p3Pos.x;
DynLight[lLightId].pos.y = p3Pos.y;
DynLight[lLightId].pos.z = p3Pos.z;
}
}
//-----------------------------------------------------------------------------
void CParticleSystem::SetColor(float _fR, float _fG, float _fB)
{
if (lLightId != -1)
{
DynLight[lLightId].rgb.r = _fR;
DynLight[lLightId].rgb.g = _fG;
DynLight[lLightId].rgb.b = _fB;
}
}
//-----------------------------------------------------------------------------
void CParticleSystem::SetParams(CParticleParams & _pp)
{
iParticleNbMax = _pp.iNbMax;
fParticleLife = _pp.fLife;
fParticleLifeRandom = _pp.fLifeRandom;
p3ParticlePos.x = _pp.p3Pos.x;
p3ParticlePos.y = _pp.p3Pos.y;
p3ParticlePos.z = _pp.p3Pos.z;
p3ParticleDirection.x = _pp.p3Direction.x * DIV10;
p3ParticleDirection.y = _pp.p3Direction.y * DIV10;
p3ParticleDirection.z = _pp.p3Direction.z * DIV10;
fParticleAngle = _pp.fAngle;
fParticleSpeed = _pp.fSpeed;
fParticleSpeedRandom = _pp.fSpeedRandom;
p3ParticleGravity.x = _pp.p3Gravity.x;
p3ParticleGravity.y = _pp.p3Gravity.y;
p3ParticleGravity.z = _pp.p3Gravity.z;
fParticleFlash = _pp.fFlash * DIV100;
if (_pp.fRotation >= 2)
{
fParticleRotation = 1.0f / (101 - _pp.fRotation);
}
else
{
fParticleRotation = 0.0f;
}
bParticleRotationRandomDirection = _pp.bRotationRandomDirection;
bParticleRotationRandomStart = _pp.bRotationRandomStart;
fParticleStartSize = _pp.fStartSize;
fParticleStartSizeRandom = _pp.fStartSizeRandom;
for (int i = 0; i < 4; i++)
{
fParticleStartColor[i] = _pp.fStartColor[i] / 255.0f;
fParticleStartColorRandom[i] = _pp.fStartColorRandom[i] / 255.0f;
}
bParticleStartColorRandomLock = _pp.bStartLock;
fParticleEndSize = _pp.fEndSize;
fParticleEndSizeRandom = _pp.fEndSizeRandom;
for (int i = 0; i < 4; i++)
{
fParticleEndColor[i] = _pp.fEndColor[i] / 255.0f;
fParticleEndColorRandom[i] = _pp.fEndColorRandom[i] / 255.0f;
}
bParticleEndColorRandomLock = _pp.bEndLock;
TRUEVector_Normalize(&p3ParticleDirection);
EERIE_3D eVect;
eVect.x = p3ParticleDirection.x;
eVect.y = -p3ParticleDirection.y;
eVect.z = p3ParticleDirection.z;
GenerateMatrixUsingVector(&eMat, &eVect, 0);
float r = (fParticleStartColor[0] + fParticleEndColor[0] ) * 0.5f;
float g = (fParticleStartColor[1] + fParticleEndColor[1] ) * 0.5f;
float b = (fParticleStartColor[2] + fParticleEndColor[2] ) * 0.5f;
SetColor(r, g, b);
switch (_pp.iBlendMode)
{
case 0:
iSrcBlend = D3DBLEND_ONE;
iDstBlend = D3DBLEND_ONE;
break;
case 1:
iSrcBlend = D3DBLEND_ZERO;
iDstBlend = D3DBLEND_INVSRCCOLOR;
break;
case 2:
iSrcBlend = D3DBLEND_SRCCOLOR;
iDstBlend = D3DBLEND_DESTCOLOR;
break;
case 3:
iSrcBlend = D3DBLEND_SRCALPHA;
iDstBlend = D3DBLEND_ONE;
break;
case 4:
iSrcBlend = 0;
iDstBlend = 0;
break;
case 5:
iSrcBlend = D3DBLEND_INVDESTCOLOR;
iDstBlend = D3DBLEND_ONE;
break;
default:
iSrcBlend = D3DBLEND_ONE;
iDstBlend = D3DBLEND_ONE;
break;
}
if (_pp.bTexInfo)
{
SetTexture(_pp.lpszTexName, _pp.iTexNb, _pp.iTexTime, _pp.bTexLoop);
}
}
//-----------------------------------------------------------------------------
void CParticleSystem::SetTexture(char * _pszTex, int _iNbTex, int _iTime, bool _bLoop)
{
if (_iNbTex == 0)
{
tex_tab[0] = MakeTCFromFile(_pszTex);
iNbTex = 0;
}
else
{
_iNbTex = min(_iNbTex, 20);
char cBuf[256];
for (int i = 0; i < _iNbTex; i++)
{
ZeroMemory(cBuf, 256);
sprintf(cBuf, "%s_%04d.bmp", _pszTex, i + 1);
tex_tab[i] = MakeTCFromFile(cBuf);
}
iNbTex = _iNbTex;
iTexTime = _iTime;
bTexLoop = _bLoop;
}
}
//-----------------------------------------------------------------------------
void CParticleSystem::SpawnParticle(CParticle * pP)
{
pP->p3Pos.x = 0;
pP->p3Pos.y = 0;
pP->p3Pos.z = 0;
// CIRCULAR BORDER
if (((ulParticleSpawn & PARTICLE_CIRCULAR) == PARTICLE_CIRCULAR) && ((ulParticleSpawn & PARTICLE_BORDER) == PARTICLE_BORDER))
{
float randd = rnd() * 360.f;
pP->p3Pos.x = EEsin(randd) * p3ParticlePos.x;
pP->p3Pos.y = rnd() * p3ParticlePos.y;
pP->p3Pos.z = EEcos(randd) * p3ParticlePos.z;
}
// CIRCULAR
else if ((ulParticleSpawn & PARTICLE_CIRCULAR) == PARTICLE_CIRCULAR)
{
float randd = rnd() * 360.f;
pP->p3Pos.x = EEsin(randd) * rnd() * p3ParticlePos.x;
pP->p3Pos.y = rnd() * p3ParticlePos.y;
pP->p3Pos.z = EEcos(randd) * rnd() * p3ParticlePos.z;
}
else
{
pP->p3Pos.x = frand2() * p3ParticlePos.x;
pP->p3Pos.y = frand2() * p3ParticlePos.y;
pP->p3Pos.z = frand2() * p3ParticlePos.z;
}
if (bParticleFollow == false)
{
pP->p3Pos.x = p3Pos.x;
pP->p3Pos.y = p3Pos.y;
pP->p3Pos.z = p3Pos.z;
}
}
//-----------------------------------------------------------------------------
void VectorRotateY(EERIE_3D & _eIn, EERIE_3D & _eOut, float _fAngle)
{
register float c = EEcos(_fAngle);
register float s = EEsin(_fAngle);
_eOut.x = (_eIn.x * c) + (_eIn.z * s);
_eOut.y = _eIn.y;
_eOut.z = (_eIn.z * c) - (_eIn.x * s);
}
//-----------------------------------------------------------------------------
void VectorRotateZ(EERIE_3D & _eIn, EERIE_3D & _eOut, float _fAngle)
{
register float c = EEcos(_fAngle);
register float s = EEsin(_fAngle);
_eOut.x = (_eIn.x * c) + (_eIn.y * s);
_eOut.y = (_eIn.y * c) - (_eIn.x * s);
_eOut.z = _eIn.z;
}
//-----------------------------------------------------------------------------
void CParticleSystem::SetParticleParams(CParticle * pP)
{
SpawnParticle(pP);
float fTTL = fParticleLife + rnd() * fParticleLifeRandom;
ARX_CHECK_LONG(fTTL);
pP->ulTTL = ARX_CLEAN_WARN_CAST_LONG(fTTL);
pP->fOneOnTTL = 1.0f / (float)pP->ulTTL;
float fAngleX = rnd() * fParticleAngle; //*0.5f;
EERIE_3D vv1, vvz;
vv1.x = p3ParticleDirection.x;
vv1.y = p3ParticleDirection.y;
vv1.z = p3ParticleDirection.z;
// ici modifs ----------------------------------
vv1.x = 0;
vv1.y = -1;
vv1.z = 0;
VectorRotateZ(vv1, vvz, fAngleX);
VectorRotateY(vvz, vv1, DEG2RAD(rnd() * 360.0f));
VectorMatrixMultiply(&vvz, &vv1, &eMat);
float fSpeed = fParticleSpeed + rnd() * fParticleSpeedRandom;
pP->p3Velocity.x = vvz.x * fSpeed;
pP->p3Velocity.y = vvz.y * fSpeed;
pP->p3Velocity.z = vvz.z * fSpeed;
pP->fSizeStart = fParticleStartSize + rnd() * fParticleStartSizeRandom;
if (bParticleStartColorRandomLock)
{
float t = rnd() * fParticleStartColorRandom[0];
pP->fColorStart[0] = fParticleStartColor[0] + t;
pP->fColorStart[1] = fParticleStartColor[1] + t;
pP->fColorStart[2] = fParticleStartColor[2] + t;
}
else
{
pP->fColorStart[0] = fParticleStartColor[0] + rnd() * fParticleStartColorRandom[0];
pP->fColorStart[1] = fParticleStartColor[1] + rnd() * fParticleStartColorRandom[1];
pP->fColorStart[2] = fParticleStartColor[2] + rnd() * fParticleStartColorRandom[2];
}
pP->fColorStart[3] = fParticleStartColor[3] + rnd() * fParticleStartColorRandom[3];
pP->fSizeEnd = fParticleEndSize + rnd() * fParticleEndSizeRandom;
if (bParticleEndColorRandomLock)
{
float t = rnd() * fParticleEndColorRandom[0];
pP->fColorEnd[0] = fParticleEndColor[0] + t;
pP->fColorEnd[1] = fParticleEndColor[1] + t;
pP->fColorEnd[2] = fParticleEndColor[2] + t;
}
else
{
pP->fColorEnd[0] = fParticleEndColor[0] + rnd() * fParticleEndColorRandom[0];
pP->fColorEnd[1] = fParticleEndColor[1] + rnd() * fParticleEndColorRandom[1];
pP->fColorEnd[2] = fParticleEndColor[2] + rnd() * fParticleEndColorRandom[2];
}
pP->fColorEnd[3] = fParticleEndColor[3] + rnd() * fParticleEndColorRandom[3];
if (bParticleRotationRandomDirection)
{
float fRandom = frand2() ;
ARX_CHECK_INT(fRandom);
pP->iRot = ARX_CLEAN_WARN_CAST_INT(fRandom);
if (pP->iRot < 0)
pP->iRot = -1;
if (pP->iRot >= 0)
pP->iRot = 1;
}
else
{
pP->iRot = 1;
}
if (bParticleRotationRandomStart)
{
pP->fRotStart = rnd() * 360.0f;
}
else
{
pP->fRotStart = 0;
}
}
//-----------------------------------------------------------------------------
bool CParticleSystem::IsAlive()
{
if ((iParticleNbAlive == 0) && (iParticleNbMax == 0))
return false;
return true;
}
//-----------------------------------------------------------------------------
void CParticleSystem::Update(long _lTime)
{
if (ARXPausedTimer) return;
ulTime += _lTime;
int nbtotal = 0;
int iNb;
float fTimeSec = _lTime * DIV1000;
CParticle * pP;
list::iterator i;
iParticleNbAlive = 0;
i = listParticle.begin();
while (i != listParticle.end())
{
pP = *i;
++i;
nbtotal++;
if (pP->isAlive())
{
pP->Update(_lTime);
pP->p3Velocity.x += p3ParticleGravity.x * fTimeSec;
pP->p3Velocity.y += p3ParticleGravity.y * fTimeSec;
pP->p3Velocity.z += p3ParticleGravity.z * fTimeSec;
iParticleNbAlive ++;
}
else
{
if (iParticleNbAlive >= iParticleNbMax)
{
delete pP;
listParticle.remove(pP);
}
else
{
pP->Regen();
SetParticleParams(pP);
pP->Validate();
pP->Update(0);
ulNbParticleGen++;
iParticleNbAlive++;
}
}
}
// création de particules en fct de la fréquence
if (iParticleNbAlive < iParticleNbMax)
{
long t = iParticleNbMax - iParticleNbAlive;
if (fParticleFreq != -1)
{
ARX_CHECK_LONG(fTimeSec * fParticleFreq);
t = min(ARX_CLEAN_WARN_CAST_LONG(fTimeSec * fParticleFreq), t);
if (t < 1) t = 1;
}
for (iNb = 0; iNb < t; iNb++)
{
CParticle * pP = new CParticle();
SetParticleParams(pP);
pP->Validate();
pP->Update(0);
listParticle.insert(listParticle.end(), pP);
ulNbParticleGen ++;
iParticleNbAlive++;
}
}
}
//-----------------------------------------------------------------------------
void CParticleSystem::Render(LPDIRECT3DDEVICE7 _lpD3DDevice, int _iSRCBLEND, int _iDESTBLEND)
{
SETCULL(_lpD3DDevice, D3DCULL_NONE);
SETZWRITE(_lpD3DDevice, FALSE);
_lpD3DDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND, iSrcBlend);
_lpD3DDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, iDstBlend);
SETALPHABLEND(_lpD3DDevice, TRUE);
int inumtex = 0;
list::iterator i;
for (i = listParticle.begin(); i != listParticle.end(); ++i)
{
CParticle * p = *i;
if (p->isAlive())
{
if (fParticleFlash > 0)
{
if (rnd() < fParticleFlash)
continue;
}
if (iNbTex > 0)
{
inumtex = p->iTexNum;
if (iTexTime == 0)
{
float fNbTex = (p->ulTime * p->fOneOnTTL) * (iNbTex);
ARX_CHECK_INT(fNbTex);
inumtex = ARX_CLEAN_WARN_CAST_INT(fNbTex);
if (inumtex >= iNbTex)
{
inumtex = iNbTex - 1;
}
}
else
{
if (p->iTexTime > iTexTime)
{
p->iTexTime -= iTexTime;
p->iTexNum++;
if (p->iTexNum > iNbTex - 1)
{
if (bTexLoop)
{
p->iTexNum = 0;
}
else
{
p->iTexNum = iNbTex - 1;
}
}
inumtex = p->iTexNum;
}
}
}
D3DTLVERTEX p3pos;
p3pos.sx = p->p3Pos.x;
p3pos.sy = p->p3Pos.y;
p3pos.sz = p->p3Pos.z;
if (bParticleFollow)
{
p3pos.sx += p3Pos.x;
p3pos.sy += p3Pos.y;
p3pos.sz += p3Pos.z;
}
float fRot = 0;
if (fParticleRotation != 0)
{
if (p->iRot == 1)
fRot = (fParticleRotation) * p->ulTime + p->fRotStart;
else
fRot = (-fParticleRotation) * p->ulTime + p->fRotStart;
if ((tex_tab[inumtex] && tex_tab[inumtex]->m_pddsSurface))
EERIEDrawRotatedSprite(_lpD3DDevice, &p3pos, p->fSize, tex_tab[inumtex], p->ulColor, 2, fRot);
}
else
{
if ((tex_tab[inumtex] && tex_tab[inumtex]->m_pddsSurface))
EERIEDrawSprite(_lpD3DDevice, &p3pos, p->fSize, tex_tab[inumtex], p->ulColor, 2);
}
}
}
}