#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 ); } }