403 lines
11 KiB
C++
403 lines
11 KiB
C++
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Crytek Engine Source File.
|
|
// Copyright (C), Crytek Studios, 2002.
|
|
// -------------------------------------------------------------------------
|
|
// File name: particleemitter.cpp
|
|
// Version: v1.00
|
|
// Created: 18/7/2003 by Timur.
|
|
// Compilers: Visual Studio.NET
|
|
// Description:
|
|
// -------------------------------------------------------------------------
|
|
// History:
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "StdAfx.h"
|
|
#include "ParticleEmitter.h"
|
|
#include "partman.h"
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
CParticleEmitter::~CParticleEmitter()
|
|
{
|
|
if (m_bActive)
|
|
OnActivate(false);
|
|
ReleaseParams();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CParticleEmitter::ReleaseParams()
|
|
{
|
|
if (m_pParams && m_pParams->pStatObj)
|
|
m_pParams->pStatObj->UnregisterUser();
|
|
if (m_pChildParams && m_pChildParams->pStatObj)
|
|
m_pChildParams->pStatObj->UnregisterUser();
|
|
|
|
if (m_pParams && m_bOwnParams)
|
|
{
|
|
delete m_pParams;
|
|
}
|
|
if (m_pChildParams && m_bOwnParams)
|
|
{
|
|
delete m_pChildParams;
|
|
}
|
|
|
|
m_pParams = 0;
|
|
m_pChildParams = 0;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CParticleEmitter::SetParams( const ParticleParams ¶ms )
|
|
{
|
|
ReleaseParams();
|
|
|
|
m_bOwnParams = true;
|
|
m_pParams = new ParticleParams;
|
|
|
|
float fCurTime = m_pPartManager->GetParticlesTime();
|
|
m_startTime = fCurTime + params.fSpawnDelay.GetVariantValue();
|
|
SetLifeTime(params.fEmitterLifeTime.GetVariantValue());
|
|
m_spawnPeriod = params.fSpawnPeriod;
|
|
m_lastActiveTime = m_startTime;
|
|
m_lastSpawnTime = -100000.0f; // Force to spawn first time.
|
|
|
|
*m_pParams = params;
|
|
m_pParams->pChild = 0;
|
|
if (params.pChild != NULL && params.pChild->nCount > 0)
|
|
{
|
|
m_pChildParams = new ParticleParams;
|
|
m_pParams->pChild = m_pChildParams;
|
|
*m_pChildParams = *params.pChild;
|
|
}
|
|
m_pMaterial = params.pMaterial;
|
|
m_pSpawnerEntity = params.pEntity;
|
|
m_pos = params.vPosition;
|
|
m_dir = params.vDirection;
|
|
m_bbox.min = m_bbox.max = m_pos;
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Keep object from suddenly deleting.
|
|
//////////////////////////////////////////////////////////////////////////
|
|
if (m_pParams && m_pParams->pStatObj)
|
|
m_pParams->pStatObj->RegisterUser();
|
|
if (m_pChildParams && m_pChildParams->pStatObj)
|
|
m_pChildParams->pStatObj->RegisterUser();
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
InitTexture( m_pParams );
|
|
if (m_pChildParams)
|
|
InitTexture( m_pChildParams );
|
|
|
|
CalculateWaterLevel();
|
|
}
|
|
|
|
void CParticleEmitter::InitTexture( ParticleParams *pParams )
|
|
{
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Initialize texure ids.
|
|
//////////////////////////////////////////////////////////////////////////
|
|
if (pParams->nTexAnimFramesCount>1 && pParams->nTexId)
|
|
{
|
|
AnimTexInfo *p = Cry3DEngineBase::GetRenderer()->GetAnimTexInfoFromId(pParams->nTexId);
|
|
if(!p)
|
|
{
|
|
#if !defined(LINUX)
|
|
Cry3DEngineBase::Warning( 0,0,"Invalid Animated Texture Id %d for Particles",pParams->nTexId );
|
|
#endif
|
|
return;
|
|
}
|
|
pParams->pAnimTex = p;
|
|
}
|
|
else if(!pParams->nTexId && !pParams->pStatObj)
|
|
{
|
|
pParams->nTexId = m_pPartManager->GetGlowTexID();
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CParticleEmitter::SetEffect( IParticleEffect *pEffect )
|
|
{
|
|
AssignEffect( pEffect,true );
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CParticleEmitter::AssignEffect( IParticleEffect *pEffect,bool bChildEffects )
|
|
{
|
|
ReleaseParams();
|
|
m_bOwnParams = false;
|
|
|
|
m_pEffect = pEffect;
|
|
m_pParams = &m_pEffect->GetParticleParams(0);
|
|
ParticleParams& childParams = m_pEffect->GetParticleParams(1);
|
|
|
|
float fCurTime = m_pPartManager->GetParticlesTime();
|
|
m_startTime = fCurTime + m_pParams->fSpawnDelay.GetVariantValue();
|
|
SetLifeTime(m_pParams->fEmitterLifeTime.GetVariantValue());
|
|
m_spawnPeriod = m_pParams->fSpawnPeriod;
|
|
m_lastActiveTime = m_startTime;
|
|
m_lastSpawnTime = -100000.0f; // Force to spawn first time.
|
|
|
|
if (m_pParams->pChild)
|
|
{
|
|
m_pChildParams = m_pParams->pChild;
|
|
}
|
|
else if (childParams.nCount > 0)
|
|
{
|
|
m_pChildParams = &childParams;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Keep object from suddenly deleting.
|
|
//////////////////////////////////////////////////////////////////////////
|
|
if (m_pParams && m_pParams->pStatObj)
|
|
m_pParams->pStatObj->RegisterUser();
|
|
if (m_pChildParams && m_pChildParams->pStatObj)
|
|
m_pChildParams->pStatObj->RegisterUser();
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
//Not needed. m_pMaterial = m_pParams->pMaterial;
|
|
m_pSpawnerEntity = m_pParams->pEntity;
|
|
m_pos = m_pParams->vPosition;
|
|
m_dir = m_pParams->vDirection;
|
|
m_bbox.min = m_bbox.max = m_pos;
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Play looped sound for this particle emitter.
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Create child effects
|
|
//////////////////////////////////////////////////////////////////////////
|
|
if (bChildEffects && pEffect->GetChildCount() > 0)
|
|
{
|
|
for (int i = 0; i < pEffect->GetChildCount(); i++)
|
|
{
|
|
// Create child emitter.
|
|
CParticleEmitter *pEmitter = new CParticleEmitter(m_pPartManager);
|
|
pEmitter->m_bChildEmitter = true;
|
|
pEmitter->m_bPermament = true;
|
|
m_childEmitters.push_back( pEmitter );
|
|
CParticleEffect *pChildEffect = (CParticleEffect*)pEffect->GetChild(i);
|
|
pEmitter->SetEffect(pChildEffect);
|
|
pEmitter->m_bbox.min = pEmitter->m_bbox.max = m_pos;
|
|
// If uncommented Sounds of child emitters not playing then..
|
|
// pEmitter->m_bActive = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CParticleEmitter::UpdateChildSpawnTimes( float fCurrTime )
|
|
{
|
|
for (int i = 0; i < (int)m_childEmitters.size(); i++)
|
|
{
|
|
CParticleEmitter *pEmitter = m_childEmitters[i];
|
|
if (pEmitter && pEmitter->m_pParams)
|
|
{
|
|
pEmitter->m_bActiveChild = true;
|
|
pEmitter->m_startTime = fCurrTime + pEmitter->m_pParams->fSpawnDelay.GetVariantValue();
|
|
pEmitter->SetLifeTime(pEmitter->m_pParams->fEmitterLifeTime.GetVariantValue());
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
const ParticleParams& CParticleEmitter::GetParams() const
|
|
{
|
|
return *m_pParams;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CParticleEmitter::SetPos( const Vec3 &vPos,const Vec3 &vDir,float fScale )
|
|
{
|
|
bool bPosChanged = false;
|
|
if (m_pos != vPos)
|
|
bPosChanged = true;
|
|
m_pos = vPos;
|
|
m_dir = vDir;
|
|
m_fScale = fScale;
|
|
m_lastActiveTime = m_pPartManager->GetParticlesTime();
|
|
|
|
if (bPosChanged)
|
|
{
|
|
if (!m_bActive)
|
|
{
|
|
m_bbox.min = vPos;
|
|
m_bbox.max = vPos;
|
|
}
|
|
|
|
if (m_pSound)
|
|
{
|
|
// Update sound position.
|
|
m_pSound->SetPosition( m_pos + m_pParams->vPositionOffset );
|
|
}
|
|
|
|
for (int i = 0; i < (int)m_childEmitters.size(); i++)
|
|
{
|
|
CParticleEmitter *pEmitter = m_childEmitters[i];
|
|
if (pEmitter)
|
|
{
|
|
pEmitter->SetPos(vPos,vDir,fScale);
|
|
}
|
|
}
|
|
|
|
CalculateWaterLevel();
|
|
}
|
|
|
|
if (!m_bChildEmitter)
|
|
{
|
|
// Make sure this emitter is active.
|
|
m_pPartManager->ActivateEmitter( this );
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CParticleEmitter::SetSpawnPeriod( float fSpawnPeriod )
|
|
{
|
|
m_spawnPeriod = fSpawnPeriod;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CParticleEmitter::SetLifeTime( float fLifeTime )
|
|
{
|
|
m_endTime = m_startTime + max(fLifeTime,0);
|
|
m_bUseEndTime=true;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CParticleEmitter::SetUnlimitedLife()
|
|
{
|
|
m_bUseEndTime=false; // Unlimited life time.
|
|
}
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CParticleEmitter::SetEntity( IEntityRender *pEntity )
|
|
{
|
|
m_pSpawnerEntity = pEntity;
|
|
|
|
CalculateWaterLevel();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CParticleEmitter::SetMaterial( IMatInfo *pMaterial )
|
|
{
|
|
m_pMaterial = pMaterial;
|
|
m_pShader = NULL;
|
|
if (m_pMaterial)
|
|
{
|
|
IShader *pContainerShader = m_pMaterial->GetShaderItem().m_pShader;
|
|
m_pShader = pContainerShader->GetTemplate(-1);
|
|
}
|
|
|
|
if(m_pMaterial)
|
|
m_pMaterial->SetFlags(m_pMaterial->GetFlags()|MIF_WASUSED);
|
|
}
|
|
|
|
void CParticleEmitter::CalculateWaterLevel()
|
|
{
|
|
// remember water level to avoid calculating it for each particle
|
|
if(m_pSpawnerEntity)
|
|
m_fWaterLevel = Cry3DEngineBase::Get3DEngine()->GetWaterLevel(m_pSpawnerEntity);
|
|
else
|
|
m_fWaterLevel = Cry3DEngineBase::Get3DEngine()->GetWaterLevel(&m_pos);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CParticleEmitter::OnActivate( bool bActive )
|
|
{
|
|
if (bActive == m_bActive)
|
|
return;
|
|
|
|
m_bActive = bActive;
|
|
if (bActive)
|
|
{
|
|
// Effect is activated.
|
|
// Play sound if have.
|
|
ISoundSystem *pISoundSystem = GetISystem()->GetISoundSystem();
|
|
#if !defined(LINUX64)
|
|
if (pISoundSystem != NULL && m_pEffect != NULL)
|
|
#else
|
|
if (pISoundSystem != 0 && m_pEffect != 0)
|
|
#endif
|
|
{
|
|
// Check if effect needs to play sounds.
|
|
IParticleEffect::SoundParams soundParams;
|
|
m_pEffect->GetSoundParams( soundParams );
|
|
if (strlen(soundParams.szSound) > 0)
|
|
{
|
|
int nSndFlags = FLAG_SOUND_3D | FLAG_SOUND_RADIUS | FLAG_SOUND_OCCLUSION;
|
|
if (soundParams.bLoop && m_bPermament)
|
|
{
|
|
m_bLoopSound = true;
|
|
nSndFlags |= FLAG_SOUND_LOOP;
|
|
}
|
|
else
|
|
m_bLoopSound = false;
|
|
|
|
m_pSound = pISoundSystem->LoadSound( soundParams.szSound,nSndFlags );
|
|
#if !defined(LINUX64)
|
|
if (m_pSound != NULL && !soundParams.bOnEverySpawn)
|
|
#else
|
|
if (m_pSound != 0 && !soundParams.bOnEverySpawn)
|
|
#endif
|
|
{
|
|
PlaySound();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Effect is deactivated.
|
|
if (m_pSound != 0 && m_bLoopSound)
|
|
{
|
|
m_pSound->Stop();
|
|
m_pSound = NULL;
|
|
}
|
|
}
|
|
|
|
// Activate/deactivate childs.
|
|
for (int i = 0; i < (int)m_childEmitters.size(); i++)
|
|
{
|
|
CParticleEmitter *pEmitter = m_childEmitters[i];
|
|
if (pEmitter)
|
|
{
|
|
pEmitter->OnActivate( bActive );
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CParticleEmitter::PlaySound()
|
|
{
|
|
if (!m_pEffect || !m_pSound)
|
|
return;
|
|
|
|
IParticleEffect::SoundParams soundParams;
|
|
m_pEffect->GetSoundParams( soundParams );
|
|
|
|
m_pSound->SetVolume( (int)soundParams.volume );
|
|
m_pSound->SetMinMaxDistance( soundParams.minRadius,soundParams.maxRadius );
|
|
Vec3 vOffset = m_pParams->vPositionOffset;
|
|
m_pSound->SetPosition( m_pos + vOffset );
|
|
m_pSound->Play();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Called when particles are spawned.
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CParticleEmitter::OnSpawnParticles( bool bChildProcess )
|
|
{
|
|
#if !defined(LINUX64)
|
|
if (!bChildProcess && m_pSound != NULL && m_pEffect != NULL)
|
|
#else
|
|
if (!bChildProcess && m_pSound != 0 && m_pEffect != 0)
|
|
#endif
|
|
{
|
|
IParticleEffect::SoundParams soundParams;
|
|
m_pEffect->GetSoundParams( soundParams );
|
|
if (soundParams.bOnEverySpawn)
|
|
{
|
|
PlaySound();
|
|
}
|
|
}
|
|
} |