Files
GTASource/game/Cutscene/CutSceneParticleEffectObject.cpp
expvintl 419f2e4752 init
2025-02-23 17:40:52 +08:00

442 lines
13 KiB
C++

//////////////////////////////////////////////////////////////////////////////////////
//
// FILE : CutsceneParticleEffectObject.cpp
// PURPOSE : Describes an in game particle effect. The effects updated via their
// respective entity types. Entitys call the objects update function when
// required. The particles are updated via the cutscene animation class;
// When initated the time of anim start time is stored an used to calculate
// its phase based on its duration.
// AUTHOR : Thomas French
// STARTED : 01/10 /2009
//
/////////////////////////////////////////////////////////////////////////////////////
//Rage includes
#include "grcore/debugdraw.h"
#include "rmptfx/ptxeffectrule.h"
#include "vfx/ptfx/ptfxwrapper.h"
#include "vfx/ptfx/ptfxscript.h"
#include "vfx/systems/Vfxscript.h"
//Game includes
#include "cutscene/cutscenemanagernew.h"
#include "cutscene/animatedModelEntity.h"
#include "cutscene/cutscene_channel.h"
#include "renderer/color.h"
#include "string/stringhash.h"
#include "CutSceneParticleEffectObject.h"
#include "cutfile/cutfobject.h"
#include "control/replay/effects/ParticleMiscFxPacket.h"
/////////////////////////////////////////////////////////////////////////////////////
ANIM_OPTIMISATIONS ()
/////////////////////////////////////////////////////////////////////////////////////
CCutSceneParticleEffect::CCutSceneParticleEffect()//, s32 iAttachedEntityId = -1)
{
m_mParticleEffect.Identity();
m_iEffectId = -1;
m_IsActive = false;
m_AttachParent = 0;
m_BoneHash = 0;
#if __BANK
m_bCanOverrideEffect = false;
m_vOverridenParticleEffectPos = VEC3_ZERO;
m_vOverridenParticleEffectRot = VEC3_ZERO;
#endif
}
/////////////////////////////////////////////////////////////////////////////////////
CCutSceneParticleEffect::~CCutSceneParticleEffect()
{
}
CEntity* CCutSceneParticleEffect::GetAttachParent(cutsManager* pManager, u32 AttachParentId)
{
cutsEntity* pCutsEntity = pManager->GetEntityByObjectId( AttachParentId);
CEntity* pGameEntity = NULL;
if(pCutsEntity && (pCutsEntity->GetType() == CUTSCENE_PROP_GAME_ENITITY ||
pCutsEntity->GetType() == CUTSCENE_WEAPON_GAME_ENTITY ||
pCutsEntity->GetType() == CUTSCENE_ACTOR_GAME_ENITITY ||
pCutsEntity->GetType() == CUTSCENE_VEHICLE_GAME_ENITITY))
{
CCutsceneAnimatedModelEntity* pModelEntity = static_cast<CCutsceneAnimatedModelEntity*>(pCutsEntity);
pGameEntity = pModelEntity->GetGameEntity();
}
return pGameEntity;
}
s32 CCutSceneParticleEffect::GetAttachParentsBoneIndex(cutsManager* pManager, u16 BoneHash, u32 AttachParentId)
{
s32 boneIndex = -1;
CEntity* pGameEntity = GetAttachParent( pManager, AttachParentId);
if(pGameEntity && pGameEntity->GetIsDynamic())
{
CDynamicEntity* pDynamicEntity = static_cast<CDynamicEntity*>(pGameEntity);
if(pDynamicEntity->GetSkeleton())
{
pDynamicEntity->GetSkeletonData().ConvertBoneIdToIndex(BoneHash, boneIndex);
}
}
return boneIndex;
}
/////////////////////////////////////////////////////////////////////////////////////
//Sets if the effect is triggered or continuous, checks an instance of the effect and checks their duration
CCutSceneAnimatedParticleEffect::CCutSceneAnimatedParticleEffect(const cutfAnimatedParticleEffectObject* pObject)
:CCutSceneParticleEffect()
,m_pCutfObject(pObject)
{
m_EffectRuleHashName = m_pCutfObject->GetStreamingName();
}
CCutSceneAnimatedParticleEffect::~CCutSceneAnimatedParticleEffect()
{
}
void CCutSceneAnimatedParticleEffect::StopParticleEffect(const cutsManager* pManager)
{
if (m_iEffectId != -1)
{
m_AttachParent = -1;
m_BoneHash = 0;
const CutSceneManager* pCutManager = static_cast<const CutSceneManager*>(pManager);
if (pCutManager->WasSkipped())
{
ptfxScript::Remove(m_iEffectId);
m_iEffectId = -1;
}
else
{
ptfxScript::Stop(m_iEffectId);
#if GTA_REPLAY
if(CReplayMgr::ShouldRecord())
{
CReplayMgr::RecordPersistantFx<CPacketStopScriptPtFx>(CPacketStopScriptPtFx(), CTrackedEventInfo<ptxEffectRef>((ptxEffectRef)m_iEffectId), NULL, false);
CReplayMgr::StopTrackingFx(CTrackedEventInfo<ptxEffectRef>((ptxEffectRef)m_iEffectId));
}
#endif
m_iEffectId = -1;
}
}
}
void CCutSceneAnimatedParticleEffect::Update( cutsManager* pManager)
{
if (m_Animation.GetClip() && IsActive() && m_pCutfObject)
{
if(m_EffectListHashName.GetHash() == 0)
{
m_EffectListHashName = g_vfxScript.GetCutscenePtFxAssetName(pManager->GetCutsceneName());
}
CutSceneManager* pCutManager = static_cast<CutSceneManager*>(pManager);
float fPhase = 0.0f;
const crClip* pClip = m_Animation.GetClip();
s32 boneIndex = -1;
CEntity* pAttachEntity = NULL;
if (pClip)
{
if(m_AttachParent> 0)
{
boneIndex = GetAttachParentsBoneIndex(pManager, m_BoneHash, m_AttachParent);
cutsceneAssertf( boneIndex != -1, "Bone hash %d for attach parent id %d does not return a valid bone index. Particle: %s",m_BoneHash , m_AttachParent, m_pCutfObject->GetDisplayName().c_str());
pAttachEntity = GetAttachParent(pManager, m_AttachParent);
cutsceneAssertf( pAttachEntity, "Attach parent id %d does not return a valid attach entity, check that the parent id matches the entity you want to attach particle %s to.", m_AttachParent, m_pCutfObject->GetDisplayName().c_str());
}
fPhase = pCutManager->GetPhaseUpdateAmount( pClip, m_Animation.GetStartTime());
Vector3 vEffectPos (VEC3_ZERO);
m_Animation.GetVector3Value(m_Animation.GetClip(),kTrackBoneTranslation,fPhase, vEffectPos);
Quaternion qValue (Quaternion::sm_I);
m_Animation.GetQuaternionValue(m_Animation.GetClip(),kTrackBoneRotation, fPhase,qValue);
m_mParticleEffect.FromQuaternion(qValue);
m_mParticleEffect.d = vEffectPos;
//not attaching to a bone so make the effect scene space relative
if(boneIndex == -1)
{
Matrix34 SceneMat(M34_IDENTITY);
pCutManager->GetSceneOrientationMatrix(SceneMat);
SceneMat.d = pCutManager->GetSceneOffset();
m_mParticleEffect.Dot(SceneMat);
#if __BANK
if(m_bCanOverrideEffect)
{
m_mParticleEffect.Identity3x3();
m_mParticleEffect.d = m_vOverridenParticleEffectPos;
m_mParticleEffect.FromEulersYXZ(m_vOverridenParticleEffectRot);
}
#endif
}
if (m_iEffectId == -1)
{
Vector3 vZero = VEC3_ZERO;
if(boneIndex != -1 && pAttachEntity)
{
m_iEffectId = ptfxScript::Start(m_EffectRuleHashName, m_EffectListHashName, pAttachEntity, boneIndex, RC_VEC3V(m_mParticleEffect.d), RC_VEC3V(vZero));
#if GTA_REPLAY
if(CReplayMgr::ShouldRecord())
{
CReplayMgr::RecordPersistantFx<CPacketStartScriptPtFx>(
CPacketStartScriptPtFx(atHashWithStringNotFinal(m_EffectRuleHashName), m_EffectListHashName, boneIndex, m_mParticleEffect.d, vZero, 1.0f, 0),
CTrackedEventInfo<ptxEffectRef>((ptxEffectRef)m_iEffectId),
pAttachEntity,
true);
}
#endif
ptfxScript::UpdateOffset(m_iEffectId, MATRIX34_TO_MAT34V(m_mParticleEffect));
#if __BANK
Matrix34 BoneGlobal;
pAttachEntity->GetSkeleton()->GetGlobalMtx(boneIndex, RC_MAT34V(BoneGlobal));
m_mParticleEffectWorld = m_mParticleEffect;
m_mParticleEffectWorld.Dot(BoneGlobal);
#endif
}
else
{
ptxEffectRule* pEffectRule = ptfxWrapper::GetEffectRule(m_EffectRuleHashName, m_EffectListHashName);
if (pEffectRule)
{
// duration is -1 for looped
if (pEffectRule->GetIsInfinitelyLooped())
{
m_iEffectId = ptfxScript::Start(m_EffectRuleHashName, m_EffectListHashName, NULL, 0, RC_VEC3V(m_mParticleEffect.d), RC_VEC3V(vZero));
#if GTA_REPLAY
if(CReplayMgr::ShouldRecord())
{
CReplayMgr::RecordPersistantFx<CPacketStartScriptPtFx>(
CPacketStartScriptPtFx(atHashWithStringNotFinal(m_EffectRuleHashName), m_EffectListHashName, 0, m_mParticleEffect.d, vZero, 1.0f, 0),
CTrackedEventInfo<ptxEffectRef>((ptxEffectRef)m_iEffectId),
NULL,
true);
}
#endif
ptfxScript::UpdateOffset(m_iEffectId, MATRIX34_TO_MAT34V(m_mParticleEffect));
}
else
{
//legacy support - Need to convert to non animated particle effects
ptfxScript::Trigger(m_EffectRuleHashName, m_EffectListHashName, NULL, 0, MATRIX34_TO_MAT34V(m_mParticleEffect));
SetIsActive(false);
}
}
#if __BANK
m_mParticleEffectWorld = m_mParticleEffect;
#endif
}
Assertf( m_iEffectId != 0, "Effect: %s could not be started", m_pCutfObject->GetDisplayName().c_str() );
}
else
{
//the start effect returns 0 if the effect is unknown
if (m_iEffectId != 0)
{
ptfxScript::UpdateOffset(m_iEffectId, MATRIX34_TO_MAT34V(m_mParticleEffect));
#if GTA_REPLAY
if(CReplayMgr::ShouldRecord())
{
CReplayMgr::RecordPersistantFx<CPacketUpdateOffsetScriptPtFx>(
CPacketUpdateOffsetScriptPtFx(m_mParticleEffect),
CTrackedEventInfo<ptxEffectRef>((ptxEffectRef)m_iEffectId),
NULL,
true);
}
#endif
//keep the particle up todate for debugging
#if __BANK
if(boneIndex != -1 && pAttachEntity)
{
Matrix34 BoneGlobal;
pAttachEntity->GetSkeleton()->GetGlobalMtx(boneIndex, RC_MAT34V(BoneGlobal));
m_mParticleEffectWorld = m_mParticleEffect;
m_mParticleEffectWorld.Dot(BoneGlobal);
}
else
{
m_mParticleEffectWorld = m_mParticleEffect;
}
#endif
if(m_pCutfObject->GetAttributeList().GetAttributeArray().GetCount() > 0)
{
for(int i = 0; i < m_pCutfObject->GetAttributeList().GetAttributeArray().GetCount(); i++)
{
const crClip* pClip = m_Animation.GetClip();
float EvoEffect = 0.0f;
u16 EffectId = (u16) m_pCutfObject->GetAttributeList().GetAttributeArray()[i].GetIntValue();
if(m_Animation.GetFloatValue(pClip,kTrackParticleData, fPhase, EvoEffect, EffectId))
{
ptfxScript::UpdateEvo(m_iEffectId, EffectId, EvoEffect);
}
else
{
cutsceneAssertf(0, "Not a valid evo track %d for particle %s", EffectId, m_pCutfObject->GetDisplayName().c_str());
}
}
}
}
}
}
}
}
CCutSceneTriggeredParticleEffect::CCutSceneTriggeredParticleEffect(const cutfParticleEffectObject* pObject)
:CCutSceneParticleEffect()
,m_pCutfObject(pObject)
{
m_EffectRuleHashName = m_pCutfObject->GetStreamingName();
}
CCutSceneTriggeredParticleEffect::~CCutSceneTriggeredParticleEffect()
{
}
void CCutSceneTriggeredParticleEffect::Update(cutsManager* pManager)
{
CutSceneManager* pCutManager = static_cast<CutSceneManager*>(pManager);
if (pCutManager->WasSkipped()==false && m_pCutfObject)
{
if(m_EffectListHashName.GetHash() == 0)
{
m_EffectListHashName = g_vfxScript.GetCutscenePtFxAssetName(pManager->GetCutsceneName());
}
s32 boneIndex = -1;
CEntity* pGameEntity = NULL;
if(m_AttachParent > 0)
{
boneIndex = GetAttachParentsBoneIndex(pManager, m_BoneHash, m_AttachParent);
cutsceneAssertf( boneIndex != -1, "Bone hash %d for attach parent id %d does not return a valid bone index. Particle: %s",m_BoneHash , m_AttachParent, m_pCutfObject->GetDisplayName().c_str());
pGameEntity = GetAttachParent(pManager, m_AttachParent);
cutsceneAssertf( pGameEntity, "Attach parent id %d does not return a valid attach entity, check that the parent id matches the entity you want to attach particle %s to.", m_AttachParent, m_pCutfObject->GetDisplayName().c_str());
}
Quaternion Rot(m_InitialRotation);
m_mParticleEffect.FromQuaternion(Rot);
m_mParticleEffect.d = m_Position;
if( boneIndex == -1)
{
//there is not attach bone so we assume that the positions are scene relative
Matrix34 SceneMat(M34_IDENTITY);
pCutManager->GetSceneOrientationMatrix(SceneMat);
m_mParticleEffect.Dot(SceneMat);
REPLAY_ONLY(bool success = )ptfxScript::Trigger(m_EffectRuleHashName, m_EffectListHashName, NULL, 0, MATRIX34_TO_MAT34V(m_mParticleEffect));
#if GTA_REPLAY
if(success && CReplayMgr::ShouldRecord())
{
CReplayMgr::RecordFx<CPacketTriggeredScriptPtFx>(
CPacketTriggeredScriptPtFx(atHashWithStringNotFinal(m_EffectRuleHashName), m_EffectListHashName, 0, m_mParticleEffect),
NULL,
true);
}
#endif
#if __BANK
m_mParticleEffectWorld = m_mParticleEffect;
#endif
}
else if(boneIndex != -1 && pGameEntity)
{
REPLAY_ONLY(bool success =) ptfxScript::Trigger(m_EffectRuleHashName, m_EffectListHashName, pGameEntity, boneIndex, MATRIX34_TO_MAT34V(m_mParticleEffect));
#if GTA_REPLAY
if(success && CReplayMgr::ShouldRecord())
{
CReplayMgr::RecordFx<CPacketTriggeredScriptPtFx>(
CPacketTriggeredScriptPtFx(atHashWithStringNotFinal(m_EffectRuleHashName), m_EffectListHashName, boneIndex, m_mParticleEffect),
pGameEntity,
true);
}
#endif
#if __BANK
if(boneIndex != -1 && pGameEntity)
{
Matrix34 BoneGlobal;
pGameEntity->GetSkeleton()->GetGlobalMtx(boneIndex, RC_MAT34V(BoneGlobal));
m_mParticleEffectWorld = m_mParticleEffect;
m_mParticleEffectWorld.Dot(BoneGlobal);
}
#endif
}
}
}
#if __BANK
Vector3 CCutSceneParticleEffect::GetEffectRotation() const
{
Vector3 rot;
m_mParticleEffect.ToEulersFastYXZ(rot);
return rot;
}
void CCutSceneParticleEffect::DisplayDebugInfo(const char* pName) const
{
grcDebugDraw::Axis(m_mParticleEffectWorld, 0.3f, true);
grcDebugDraw::Text(m_mParticleEffectWorld.d, CRGBA(0,0,0,255),0, grcDebugDraw::GetScreenSpaceTextHeight(), pName );
}
#endif
/////////////////////////////////////////////////////////////////////////////////////