Files
2026-06-01 12:46:52 +02:00

583 lines
16 KiB
C++

#include "stdafx.h"
#include "SGameEnhanceFx.h"
#include "KRenderObjectMesh.h"
#include "krenderobjectEtc.h"
#include "SGameAvatarEx.h"
//#include "SEnhanceFXDB.h"
#include "SSoundResourceDB.h"
#include "SDebug_Util.h"
namespace
{
//시스템 사양에 따른 파티클 수
const int c_nLowQualityParticle = 20;
const int c_nMediumQualityParticle = 50;
const int c_nHighQualityParticle = 80;
float RandomNumber(float fMin, float fMax)
{
if (fMin == fMax) return(fMin);
float fRandom = (float)rand() / (float)RAND_MAX;
return((fRandom * (float)fabs(fMax-fMin))+fMin);
};
K3DVector RandomNumber(K3DVector vMin, K3DVector vMax)
{
float x = RandomNumber(vMin.x, vMax.x);
float y = RandomNumber(vMin.y, vMax.y);
float z = RandomNumber(vMin.z, vMax.z);
return(K3DVector(x,y,z));
};
}
SParticleRecycling::SParticleRecycling()
{
m_pParticle = NULL;
m_vStartPosition = K3DVector( 0.f, 0.f, 0.f );
m_vEndPosition = K3DVector( 0.f, 0.f, 0.f );
m_bAlive = false;
m_dwLifeTime = 0;
m_fMoveSpeed = 0.f;
m_fStartSize = 1.f;
m_fEndSize = 0.f;
m_vEmitRadius = K3DVector( 0.f, 0.f, 0.f );
m_dwStartTime = 0;
m_dwIncreaseTime = 30;
m_bIsEnd = false;
}
SParticleRecycling::~SParticleRecycling()
{
SAFE_DELETE( m_pParticle );
}
void SParticleRecycling::CreateSeqForm( const char* szFileName )
{
SAFE_DELETE( m_pParticle );
m_pParticle = new KSeqModel;
m_pParticle->AddAnimation( "effect_middle", szFileName );
m_pParticle->PlayAnimation( 0, "effect_middle", KSeqForm::SEQTYPE_LOOP );
}
//렌더 끄기
void SParticleRecycling::SetRenderFlagOff()
{
_CID( SETFORCERENDER_FLAG );
m_pParticle->Perform( id_SETFORCERENDER_FLAG, KArg() );
m_bAlive = false;
}
void SParticleRecycling::PlayAnimation()
{
_CID( SETRENDER_FLAG );
KMsgSET_RENDERFLAG msg;
msg.bRenderFlag = TRUE;
m_pParticle->Perform( id_SETRENDER_FLAG, msg );
}
void SParticleRecycling::SetMoveSpeed( float fMoveSpeed ) { m_fMoveSpeed = fMoveSpeed; }
void SParticleRecycling::SetStartSize( float fSize ) { m_fStartSize = fSize; }
void SParticleRecycling::SetEndSize( float fSize ) { m_fEndSize = fSize; }
void SParticleRecycling::SetLive( bool bAlive ) { m_bAlive = bAlive; }
void SParticleRecycling::SetEnd( bool bEnd ) { m_bIsEnd = bEnd; }
void SParticleRecycling::SetLifeTime( DWORD dwLifeTime ) { m_dwLifeTime = dwLifeTime; }
void SParticleRecycling::SetResetTime( DWORD dwTime ) { m_dwStartTime = dwTime; }
void SParticleRecycling::SetEmitRadius( K3DVector* vEmitRadius )
{
m_vEmitRadius = RandomNumber( -(*vEmitRadius), *vEmitRadius );
}
void SParticleRecycling::SetDirection( K3DVector* vMinDirection, K3DVector* vMaxDirection )
{
m_vDirection = RandomNumber( *vMinDirection, *vMaxDirection );
}
void SParticleRecycling::SetStartRandomPosition( K3DVector* vMinStartPositon, K3DVector* vMaxStartPositon)
{
m_vStartPosition = RandomNumber( *vMinStartPositon, *vMaxStartPositon );
m_vStartPosition += m_vEmitRadius;
}
void SParticleRecycling::SetStartPosition( K3DVector* vStartPositon )
{
m_vStartPosition = *vStartPositon;
m_vStartPosition += m_vEmitRadius;
}
float SParticleRecycling::Visiblity( float fS )
{
float fOut = fS + fS;
if( fS > 0.5f )
{
fOut = fOut - 1.0f;
return 1.0f - fOut;
}
return fOut;
}
float SParticleRecycling::floatLinear( float v0, float v1, float t )
{
return v0 + ( t * ( v1 - v0 ) );
}
bool SParticleRecycling::ProcessParticleMove( DWORD dwTime, const K3DMatrix* pSMatrix, const K3DMatrix* pEMatrix )
{
m_vStartPosition = K3DVector( pSMatrix->_41, pSMatrix->_42, pSMatrix->_43 );
m_vEndPosition = K3DVector( pEMatrix->_41, pEMatrix->_42, pEMatrix->_43 );
K3DVector vTemp;
float fSize = 0.f;
float fLerp = (float)(m_dwStartTime) / m_dwLifeTime;
m_dwStartTime += m_dwIncreaseTime;
K3DVectorLerp( vTemp, m_vStartPosition, m_vEndPosition, fLerp );
K3DMatrix matTrans, matScaling;
K3DMatrixIdentity( matTrans );
K3DMatrixIdentity( matScaling );
if( m_dwStartTime < m_dwLifeTime )
{
vTemp += m_vEmitRadius;
fSize = floatLinear( m_fStartSize, m_fEndSize, fLerp );
K3DMatrixScaling( matScaling, fSize, fSize, fSize );
m_pParticle->SetVisibility( Visiblity( fLerp ) );
}
else
{
vTemp = m_vEndPosition;
K3DMatrixScaling( matScaling, 0.f, 0.f, 0.f );
m_pParticle->SetVisibility( 0.f );
m_bIsEnd = true;
}
matTrans._41 = vTemp.x;
matTrans._42 = vTemp.y;
matTrans._43 = vTemp.z;
matTrans = matScaling * matTrans;
m_pParticle->Process( dwTime );
m_pParticle->SetTransform( matTrans );
return true;
}
bool SParticleRecycling::ProcessParticleDirMove( DWORD dwTime, const K3DMatrix* pMatEp, const K3DMatrix* pMatAttch, const K3DMatrix* pMatParent )
{
float fSize = 0.f;
float fLerp = (float)(m_dwStartTime) / m_dwLifeTime;
m_dwStartTime += m_dwIncreaseTime;
K3DMatrix matTrans, matScaling;
K3DMatrixIdentity( matTrans );
K3DMatrixIdentity( matScaling );
if( m_dwStartTime < m_dwLifeTime )
{
fSize = floatLinear( m_fStartSize, m_fEndSize, fLerp );
K3DMatrixScaling( matScaling, fSize, fSize, fSize );
m_pParticle->SetVisibility( Visiblity( fLerp ) );
}
else
{
K3DMatrixScaling( matScaling, 0.f, 0.f, 0.f );
m_pParticle->SetVisibility( 0.f );
m_bIsEnd = true;
}
m_vStartPosition += m_vDirection * m_fMoveSpeed;
matTrans = *pMatEp;
// matTrans._41 = -m_vStartPosition.x;
// matTrans._42 = -m_vStartPosition.y;
// matTrans._43 = -m_vStartPosition.z;
matTrans._41 = m_vStartPosition.x;
matTrans._42 = m_vStartPosition.y;
matTrans._43 = m_vStartPosition.z;
K3DMatrixMultiply( matTrans, matTrans, *pMatAttch );
K3DMatrixMultiply( matTrans, matTrans, *pMatParent );
matTrans = matScaling * matTrans;
m_pParticle->Process( dwTime );
m_pParticle->SetTransform( matTrans );
return true;
}
void SParticleRecycling::Render( KViewportObject* ppViewportList )
{
m_pParticle->Render( ppViewportList );
}
/////////////////////////////////////////////////////////
SGameEnhanceFx::SGameEnhanceFx()
{
m_pEnhanceType = NULL;
//m_pEnhanceFx = NULL;
m_pPlayer = 0;
m_nWpEffectPos = 0;
m_nEnhanceFxID = 0;
m_bIsEnd = false;
m_bRender = true;
}
SGameEnhanceFx::~SGameEnhanceFx()
{
Destroy();
}
void SGameEnhanceFx::Destroy()
{
m_pPlayer = NULL;
//SAFE_DELETE( m_pEnhanceFx );
SAFE_DELETE( m_pEnhanceType );
}
void SGameEnhanceFx::Init( SGameAvatarEx* pAvatar, int nWeaponEffectPos, int nItemClass )
{
//DB에서 읽어온 값을 적용 시키자 지금은 없으이 임시로 연출값 하드코딩 ㅡ.,ㅡ
//m_pEnhanceFx = new EnhanceFX;
//*m_pEnhanceFx = *pEnhanceFx;
switch( 0 )
{
case 0: m_pEnhanceType = new SEnhanceParticleMoveFx; break;
case 1: m_pEnhanceType = new SEnhanceParticleDirMoveFx; break;
case 2: m_pEnhanceType = new SEnhanceMeshFx; break;
default:
{
assert( false );
return;
}
}
m_pPlayer = pAvatar;
m_nWpEffectPos = nWeaponEffectPos;
m_pEnhanceType->Init();
m_pEnhanceType->SetMatrix( pAvatar, nWeaponEffectPos );
}
void SGameEnhanceFx::Process( DWORD dwTime )
{
if( !m_bRender ) return;
if( m_pEnhanceType ) m_pEnhanceType->Process( dwTime );
}
void SGameEnhanceFx::Render( unsigned long uRenderBitVector, KViewportObject** ppViewportList, int nViewportCount )
{
if( !m_bRender ) return;
if( m_pEnhanceType )
{
for(int vit = 0; vit < nViewportCount; ++vit)
{
if(ppViewportList[vit]->GetAttributes() & KViewportObject::VIEWPORT_GAME)
m_pEnhanceType->Render( ppViewportList[vit] );
if(ppViewportList[vit]->GetAttributes() & KViewportObject::VIEWPORT_WATER)
m_pEnhanceType->Render( ppViewportList[vit] );
}
}
}
//치트=================================================================================
void SGameEnhanceFx::SetParticleQuality( int nQuality )
{
/* if( nQuality == 0 )
{
m_bRender = false;
return;
}
unsigned short nOldParticleSize = m_nMaxParticleSize;
if( nQuality == 1 ) m_nMaxParticleSize = c_nLowQualityParticle;
else if( nQuality == 2 ) m_nMaxParticleSize = c_nMediumQualityParticle;
else if( nQuality == 3 ) m_nMaxParticleSize = c_nHighQualityParticle;
if( nOldParticleSize != m_nMaxParticleSize )
{
Create();
}*/
}
void SGameEnhanceFx::SetEnhanceFxType( int nType )
{
SAFE_DELETE( m_pEnhanceType );
switch( nType )
{
case 0: m_pEnhanceType = new SEnhanceParticleMoveFx; break;
case 1: m_pEnhanceType = new SEnhanceParticleDirMoveFx; break;
case 2: m_pEnhanceType = new SEnhanceMeshFx; break;
default:
{
assert( false );
return;
}
}
m_pEnhanceType->Init( );
m_pEnhanceType->SetMatrix( m_pPlayer, m_nWpEffectPos );
}
void SGameEnhanceFx::SetLifeTime( DWORD nLifeTime )
{
// m_pEnhanceFxInfo->m_dwLifeTime = nLifeTime;
}
void SGameEnhanceFx::SetMoveSpeed( float fSpeed )
{
// m_pEnhanceFxInfo->m_fMoveSpeed = fSpeed;
}
void SGameEnhanceFx::SetSize( float fStartSize, float fEndSize )
{
// m_pEnhanceFxInfo->m_fStartSize = fStartSize;
// m_pEnhanceFxInfo->m_fEndSize = fEndSize;
}
void SGameEnhanceFx::SetEmitRadius( K3DVector vEmitRadius )
{
// m_pEnhanceFxInfo->m_vEmitRadius = vEmitRadius;
}
void SGameEnhanceFx::SetEmitRate( float fMin, float fMax )
{
// m_pEnhanceFxInfo->m_fEmitRateMin = fMin;
// m_pEnhanceFxInfo->m_fEmitRateMax = fMax;
m_pEnhanceType->SetEmitRate();
}
void SGameEnhanceFx::SetCreateInterval( float fInterval )
{
// m_pEnhanceFxInfo->m_fCreateInterval = fInterval;
}
void SGameEnhanceFx::SetMinDirection( K3DVector vMinDirection )
{
// m_pEnhanceFxInfo->m_vMinDirection = vMinDirection;
}
void SGameEnhanceFx::SetMaxDirection( K3DVector vMaxDirection )
{
// m_pEnhanceFxInfo->m_vMaxDirection = vMaxDirection;
}
//치트=================================================================================
SEnhanceFxType::SEnhanceFxType()
{
m_pParticleRecycling = NULL;
m_pMeshFx = NULL;
// m_pEnhanceFxInfo = NULL;
for( int i = 0; i < EFFECT_POS_WEAPON_EP_MAX; ++i )
{
m_pmatEPParent[i] = NULL;
m_pmatEpAttach[i] = NULL;
m_pmatEpPoint[i] = NULL;
K3DMatrixIdentity( m_matTransform[i] );
}
m_dwTime = 0;
m_nMaxParticleSize = c_nLowQualityParticle;
}
SEnhanceFxType::~SEnhanceFxType()
{
SAFE_DELETE_ARRAY( m_pParticleRecycling );
SAFE_DELETE( m_pMeshFx );
}
void SEnhanceFxType::Init()
{
// m_pEnhanceFxInfo = pEnhanceFxInfo;
//DB값이 없는 관계로 기본 수치
// m_fEmitRate = RandomNumber(m_pEnhanceFxInfo->m_fEmitRateMin, m_pEnhanceFxInfo->m_fEmitRateMax);
m_fNumNewPartsExcess = 0.f;
m_nMaxParticleSize = c_nLowQualityParticle;
CreateSequence();
}
void SEnhanceFxType::CreateMeshSequence()
{
m_pMeshFx = new KSeqModel;
// m_pMeshFx->AddAnimation( "effect_middle", GetResourceDB().GetEffectResourceName( m_pEnhanceFxInfo->m_nEffectID ) );
m_pMeshFx->PlayAnimation( 0, "effect_middle", KSeqForm::SEQTYPE_LOOP );
}
void SEnhanceFxType::CreateParticleSequence()
{
// m_pParticleRecycling = new SParticleRecycling[m_nMaxParticleSize];
// for( int x = 0; x < m_nMaxParticleSize; x++ )
// m_pParticleRecycling[x].CreateSeqForm( GetResourceDB().GetEffectResourceName( m_pEnhanceFxInfo->m_nEffectID ) );
}
void SEnhanceFxType::SetMatrix( SGameAvatarEx* pAvatar, int nWeaponEffectPos )
{
for( int i = 0; i < EFFECT_POS_WEAPON_EP_MAX; ++i )
{
m_pmatEPParent[i] = pAvatar->GetWeaponEventPointParentMatrix( nWeaponEffectPos, i );
m_pmatEpAttach[i] = pAvatar->GetWeaponEventPointAttachMatrix( nWeaponEffectPos, i );
m_pmatEpPoint[i] = pAvatar->GetWeaponEventPointMatrix( nWeaponEffectPos, i );
}
}
void SEnhanceFxType::Process( DWORD dwTime )
{
m_dwTime = dwTime;
}
void SEnhanceFxType::Render( KViewportObject* ppViewportList )
{
}
bool SEnhanceFxType::ProcessMatrix( EFFECT_POS_WEAPON_EP nEffectPosEp )
{
K3DMatrixIdentity( m_matTransform[nEffectPosEp] );
if( m_pmatEPParent[nEffectPosEp] )
{
if( m_pmatEpAttach[nEffectPosEp] && m_pmatEpPoint[nEffectPosEp] )
{
K3DMatrixMultiply( m_matTransform[nEffectPosEp], *m_pmatEpPoint[nEffectPosEp], *m_pmatEpAttach[nEffectPosEp] );
K3DMatrixMultiply( m_matTransform[nEffectPosEp], m_matTransform[nEffectPosEp], *m_pmatEPParent[nEffectPosEp] );
}
else
return false;
}
else
return false;
return true;
}
bool SEnhanceFxType::ParticleResurrection( int nCount )
{
//죽은 넘이라면 방출 비율과 생성 간격을 계산해서 다시 살려줘야한다.
/* int nNumNewPart = (int)(m_fEmitRate * m_pEnhanceFxInfo->m_fCreateInterval );
m_fNumNewPartsExcess += (float)(m_fEmitRate * m_pEnhanceFxInfo->m_fCreateInterval) - nNumNewPart;
if( m_fNumNewPartsExcess > 1.f )
{
nNumNewPart += (int)m_fNumNewPartsExcess;
m_fNumNewPartsExcess -= (int)m_fNumNewPartsExcess;
}
if( nNumNewPart > 0 )
{
m_pParticleRecycling[nCount].PlayAnimation();
m_pParticleRecycling[nCount].SetResetTime( 0 );
m_pParticleRecycling[nCount].SetMoveSpeed( m_pEnhanceFxInfo->m_fMoveSpeed );
m_pParticleRecycling[nCount].SetStartSize( m_pEnhanceFxInfo->m_fStartSize );
m_pParticleRecycling[nCount].SetEndSize( m_pEnhanceFxInfo->m_fEndSize );
m_pParticleRecycling[nCount].SetEmitRadius( &m_pEnhanceFxInfo->m_vEmitRadius );
m_pParticleRecycling[nCount].SetLifeTime( m_pEnhanceFxInfo->m_dwLifeTime );
m_pParticleRecycling[nCount].SetDirection( &m_pEnhanceFxInfo->m_vMinDirection, &m_pEnhanceFxInfo->m_vMaxDirection );
m_pParticleRecycling[nCount].SetLive(true);
m_pParticleRecycling[nCount].SetEnd(false);
return true;
}*/
return false;
}
void SEnhanceFxType::SetEmitRate()
{
// m_fEmitRate = RandomNumber(m_pEnhanceFxInfo->m_fEmitRateMin, m_pEnhanceFxInfo->m_fEmitRateMax );
}
//시작점에서 끝점으로 이동하는 Particle Effect
void SEnhanceParticleMoveFx::CreateSequence()
{
CreateParticleSequence();
}
void SEnhanceParticleMoveFx::Process( DWORD dwTime )
{
m_dwTime = dwTime;
}
void SEnhanceParticleMoveFx::Render( KViewportObject* ppViewportList )
{
// sonador 7.0.16 Mantis 0002790: [모션] 아바타가 활을 착용하고 오르니토를 탔을 때 모션 문제
if( !ProcessMatrix(EFFECT_POS_WEAPON_EP_START) || !ProcessMatrix(EFFECT_POS_WEAPON_EP_END) || !m_pParticleRecycling ) return;
for( int x = 0; x < m_nMaxParticleSize; ++x )
{
if( m_pParticleRecycling[x].IsLive() )
{
m_pParticleRecycling[x].ProcessParticleMove( m_dwTime, &m_matTransform[EFFECT_POS_WEAPON_EP_START], &m_matTransform[EFFECT_POS_WEAPON_EP_END] );
m_pParticleRecycling[x].Render( ppViewportList );
if( m_pParticleRecycling[x].IsEnd() )
m_pParticleRecycling[x].SetRenderFlagOff();
}
else
ParticleResurrection( x );
}
}
//랜덤 방향으로 이동하는 Particle Effect
void SEnhanceParticleDirMoveFx::CreateSequence()
{
CreateParticleSequence();
}
void SEnhanceParticleDirMoveFx::Process( DWORD dwTime )
{
m_dwTime = dwTime;
}
void SEnhanceParticleDirMoveFx::Render( KViewportObject* ppViewportList )
{
// sonador 7.0.16 Mantis 0002790: [모션] 아바타가 활을 착용하고 오르니토를 탔을 때 모션 문제
if( !ProcessMatrix(EFFECT_POS_WEAPON_EP_START) || !ProcessMatrix(EFFECT_POS_WEAPON_EP_END) || !m_pParticleRecycling ) return;
for( int x = 0; x < m_nMaxParticleSize; ++x )
{
if( m_pParticleRecycling[x].IsLive() )
{
m_pParticleRecycling[x].ProcessParticleDirMove( m_dwTime, m_pmatEpPoint[EFFECT_POS_WEAPON_EP_START],
m_pmatEpAttach[EFFECT_POS_WEAPON_EP_START],
m_pmatEPParent[EFFECT_POS_WEAPON_EP_START]);
m_pParticleRecycling[x].Render( ppViewportList );
if( m_pParticleRecycling[x].IsEnd() )
m_pParticleRecycling[x].SetRenderFlagOff();
}
else
{
if( ParticleResurrection( x ) )
{
K3DVector vStart, vEnd;
K3DMatrixGetPosVector( vStart, *m_pmatEpPoint[EFFECT_POS_WEAPON_EP_START] );
K3DMatrixGetPosVector( vEnd, *m_pmatEpPoint[EFFECT_POS_WEAPON_EP_END] );
m_pParticleRecycling[x].SetStartRandomPosition( &vStart, &vEnd );
}
}
}
}
//Mesh Effect
void SEnhanceMeshFx::CreateSequence()
{
CreateMeshSequence();
}
void SEnhanceMeshFx::Process( DWORD dwTime )
{
m_dwTime = dwTime;
if( m_pMeshFx )
{
m_pMeshFx->Process( dwTime );
}
}
void SEnhanceMeshFx::Render( KViewportObject* ppViewportList )
{
if( !ProcessMatrix(EFFECT_POS_WEAPON_EP_START) ) return;
if( m_pMeshFx )
{
m_pMeshFx->SetTransform( m_matTransform[EFFECT_POS_WEAPON_EP_START] );
m_pMeshFx->Render( ppViewportList );
}
}