diff --git a/Runtime/Audio/CAudioSys.hpp b/Runtime/Audio/CAudioSys.hpp index 6fafff6f0..2dc59e6f3 100644 --- a/Runtime/Audio/CAudioSys.hpp +++ b/Runtime/Audio/CAudioSys.hpp @@ -44,8 +44,8 @@ public: u16 x24_sfxId; float x26_maxVol; float x27_minVol; - u8 x28_; - u8 x29_; + bool x28_important; // Can't be allocated over, regardless of priority + u8 x29_prio; }; CAudioSys(boo::IAudioVoiceEngine* voiceEngine, amuse::IBackendVoiceAllocator& backend, u8,u8,u8,u8,u32) diff --git a/Runtime/Audio/CSfxManager.cpp b/Runtime/Audio/CSfxManager.cpp index fb9329290..e62b0f32c 100644 --- a/Runtime/Audio/CSfxManager.cpp +++ b/Runtime/Audio/CSfxManager.cpp @@ -413,11 +413,11 @@ CSfxHandle CSfxManager::AddEmitter(u16 id, const zeus::CVector3f& pos, const zeu parmData.xc_dir = dir; parmData.x18_maxDist = 150.f; parmData.x1c_distComp = 0.1f; - parmData.x20_flags = 1; + parmData.x20_flags = 1; // Continuous parameter update parmData.x24_sfxId = id; parmData.x26_maxVol = std::max(vol, 0.165f); - parmData.x28_ = 0; - parmData.x29_ = 0x7f; + parmData.x28_important = false; + parmData.x29_prio = 0x7f; return AddEmitter(parmData, useAcoustics, prio, looped, areaId); } @@ -429,7 +429,7 @@ CSfxHandle CSfxManager::AddEmitter(const CAudioSys::C3DEmitterParmData& parmData CAudioSys::C3DEmitterParmData data = parmData; if (looped) - data.x20_flags |= 0x6; + data.x20_flags |= 0x6; // Pausable/restartable when inaudible m_doUpdate = true; CSfxHandle wrapper = std::make_shared(looped, prio, data, useAcoustics, areaId); CSfxChannel& chanObj = m_channels[int(m_currentChannel)]; diff --git a/Runtime/Character/CAnimData.cpp b/Runtime/Character/CAnimData.cpp index c5c6f33be..aa6c671cf 100644 --- a/Runtime/Character/CAnimData.cpp +++ b/Runtime/Character/CAnimData.cpp @@ -554,9 +554,9 @@ void CAnimData::SetAnimation(const CAnimPlaybackParms& parms, bool noTrans) x220_29_animationJustStarted = true; } -SAdvancementDeltas CAnimData::DoAdvance(float dt, bool& b1, CRandom16& random, bool advTree) +SAdvancementDeltas CAnimData::DoAdvance(float dt, bool& suspendParticles, CRandom16& random, bool advTree) { - b1 = false; + suspendParticles = false; zeus::CVector3f offsetPre, offsetPost; zeus::CQuaternion quatPre, quatPost; @@ -572,14 +572,14 @@ SAdvancementDeltas CAnimData::DoAdvance(float dt, bool& b1, CRandom16& random, b if (!x220_24_animating) { - b1 = true; + suspendParticles = true; return {}; } if (x220_29_animationJustStarted) { x220_29_animationJustStarted = false; - b1 = true; + suspendParticles = true; } if (advTree && x1f8_animRoot) @@ -629,25 +629,27 @@ SAdvancementDeltas CAnimData::DoAdvance(float dt, bool& b1, CRandom16& random, b SAdvancementDeltas CAnimData::Advance(float dt, const zeus::CVector3f& scale, CStateManager& stateMgr, TAreaId aid, bool advTree) { - bool b2; - return DoAdvance(dt, b2, *stateMgr.GetActiveRandom(), advTree); - if (b2) + bool suspendParticles; + SAdvancementDeltas deltas = DoAdvance(dt, suspendParticles, *stateMgr.GetActiveRandom(), advTree); + if (suspendParticles) x120_particleDB.SuspendAllActiveEffects(stateMgr); for (CParticlePOINode& node : g_ParticlePOINodes) { if (node.GetCharacterIndex() == -1 || node.GetCharacterIndex() == x204_charIdx) { - x120_particleDB.StartEffect(node.GetString(), node.GetFlags(), node.GetParticleData(), - scale, stateMgr, aid, x21c_); + x120_particleDB.AddParticleEffect(node.GetString(), node.GetFlags(), node.GetParticleData(), + scale, stateMgr, aid, false, x21c_particleLightIdx); } } + + return deltas; } SAdvancementDeltas CAnimData::AdvanceIgnoreParticles(float dt, CRandom16& random, bool advTree) { - bool b2; - return DoAdvance(dt, b2, random, advTree); + bool suspendParticles; + return DoAdvance(dt, suspendParticles, random, advTree); } void CAnimData::AdvanceAnim(CCharAnimTime& time, zeus::CVector3f& offset, zeus::CQuaternion& quat) @@ -819,4 +821,12 @@ void CAnimData::SubstituteModelData(const TCachedToken& model) x108_aabb = xd8_modelData->GetModel()->GetAABB(); } +void CAnimData::SetParticleCEXTValue(const std::string& name, int idx, float value) +{ + auto search = std::find_if(xc_charInfo.x98_effects.begin(), xc_charInfo.x98_effects.end(), + [&name](const auto& v) { return v.first == name; }); + if (search != xc_charInfo.x98_effects.end() && search->second.size()) + x120_particleDB.SetCEXTValue(search->second.front().GetComponentName(), idx, value); +} + } diff --git a/Runtime/Character/CAnimData.hpp b/Runtime/Character/CAnimData.hpp index d48dd4221..112be40d7 100644 --- a/Runtime/Character/CAnimData.hpp +++ b/Runtime/Character/CAnimData.hpp @@ -84,6 +84,8 @@ struct SAdvancementResults; class CAnimData { friend class CModelData; + friend class CActor; + TLockedToken x0_charFactory; CCharacterInfo xc_charInfo; TLockedToken xcc_layoutData; @@ -109,7 +111,7 @@ class CAnimData u32 x210_passedIntCount = 0; u32 x214_passedParticleCount = 0; u32 x218_passedSoundCount = 0; - u32 x21c_ = 0; + u32 x21c_particleLightIdx = 0; union { @@ -201,7 +203,7 @@ public: std::vector& tokensOut, bool preLock); void GetAnimationPrimitives(const CAnimPlaybackParms& parms, std::set& primsOut) const; void SetAnimation(const CAnimPlaybackParms& parms, bool); - SAdvancementDeltas DoAdvance(float, bool&, CRandom16&, bool advTree); + SAdvancementDeltas DoAdvance(float, bool& suspendParticles, CRandom16&, bool advTree); SAdvancementDeltas Advance(float, const zeus::CVector3f&, CStateManager& stateMgr, TAreaId aid, bool advTree); SAdvancementDeltas AdvanceIgnoreParticles(float, CRandom16&, bool advTree); void AdvanceAnim(CCharAnimTime& time, zeus::CVector3f&, zeus::CQuaternion&); @@ -225,6 +227,15 @@ public: static void InitializeCache(); const CHierarchyPoseBuilder& GetPoseBuilder() const { return x2fc_poseBuilder; } const CParticleDatabase& GetParticleDB() const { return x120_particleDB; } + CParticleDatabase& GetParticleDB() { return x120_particleDB; } + void SetParticleCEXTValue(const std::string& name, int idx, float value); + + u32 GetPassedBoolPOICount() const { return x20c_passedBoolCount; } + u32 GetPassedIntPOICount() const { return x210_passedIntCount; } + u32 GetPassedParticlePOICount() const { return x214_passedParticleCount; } + u32 GetPassedSoundPOICount() const { return x218_passedSoundCount; } + + u32 GetCharacterIndex() const { return x204_charIdx; } }; } diff --git a/Runtime/Character/CCharacterInfo.hpp b/Runtime/Character/CCharacterInfo.hpp index e6f058e41..6bdbf0797 100644 --- a/Runtime/Character/CCharacterInfo.hpp +++ b/Runtime/Character/CCharacterInfo.hpp @@ -11,6 +11,7 @@ namespace urde class CCharacterInfo { + friend class CAnimData; public: struct CParticleResData { diff --git a/Runtime/Character/CEffectComponent.cpp b/Runtime/Character/CEffectComponent.cpp index 445d3327f..1250abdb0 100644 --- a/Runtime/Character/CEffectComponent.cpp +++ b/Runtime/Character/CEffectComponent.cpp @@ -11,19 +11,8 @@ CEffectComponent::CEffectComponent(CInputStream& in) x10_tag = GetSObjectTagFromStream(in); x18_boneName = in.readString(); x28_scale = in.readFloatBig(); - x2c_parentedMode = in.readUint32Big(); + x2c_parentedMode = CParticleData::EParentedMode(in.readUint32Big()); x30_flags = in.readUint32Big(); } -const std::string& CEffectComponent::GetComponentName() const { return x0_name; } - -const SObjectTag& CEffectComponent::GetParticleTag() const { return x10_tag; } - -const std::string& CEffectComponent::GetSegmentName() const { return x18_boneName; } - -float CEffectComponent::GetScale() const { return x28_scale; } - -u32 CEffectComponent::GetParentedMode() const { return x2c_parentedMode; } - -u32 CEffectComponent::GetFlags() const { return x30_flags; } } diff --git a/Runtime/Character/CEffectComponent.hpp b/Runtime/Character/CEffectComponent.hpp index 0871cbd96..863bfa8e3 100644 --- a/Runtime/Character/CEffectComponent.hpp +++ b/Runtime/Character/CEffectComponent.hpp @@ -3,6 +3,7 @@ #include "IOStreams.hpp" #include "RetroTypes.hpp" +#include "CParticleData.hpp" namespace urde { @@ -13,18 +14,18 @@ class CEffectComponent SObjectTag x10_tag; std::string x18_boneName; float x28_scale; - u32 x2c_parentedMode; + CParticleData::EParentedMode x2c_parentedMode; u32 x30_flags; static SObjectTag GetSObjectTagFromStream(CInputStream& in); public: CEffectComponent(CInputStream& in); - const std::string& GetComponentName() const; - const SObjectTag& GetParticleTag() const; - const std::string& GetSegmentName() const; - float GetScale() const; - u32 GetParentedMode() const; - u32 GetFlags() const; + const std::string& GetComponentName() const { return x0_name; } + const SObjectTag& GetParticleTag() const { return x10_tag; } + const std::string& GetSegmentName() const { return x18_boneName; } + float GetScale() const { return x28_scale; } + CParticleData::EParentedMode GetParentedMode() const { return x2c_parentedMode; } + u32 GetFlags() const { return x30_flags; } }; } diff --git a/Runtime/Character/CPOINode.hpp b/Runtime/Character/CPOINode.hpp index 037b66d55..4ba20e927 100644 --- a/Runtime/Character/CPOINode.hpp +++ b/Runtime/Character/CPOINode.hpp @@ -13,6 +13,7 @@ enum class EPOIType : u16 Loop = 0, EmptyBool = 1, EmptyInt32 = 2, + SoundInt32 = 4, Particle = 5, UserEvent = 6, RandRate = 7, diff --git a/Runtime/Character/CParticleData.hpp b/Runtime/Character/CParticleData.hpp index 9d41d367c..7f2a991b5 100644 --- a/Runtime/Character/CParticleData.hpp +++ b/Runtime/Character/CParticleData.hpp @@ -25,7 +25,16 @@ private: public: CParticleData() = default; CParticleData(CInputStream& in); - EParentedMode GetParentedMode() const {return x20_parentMode;} + u32 GetDuration() const { return x0_duration; } + const SObjectTag& GetTag() const { return x4_particle; } + const std::string& GetSegmentName() const { return xc_boneName; } + float GetScale() const { return x1c_scale; } + EParentedMode GetParentedMode() const { return x20_parentMode; } +}; + +class CAuxiliaryParticleData +{ +public: }; } diff --git a/Runtime/Character/CParticleDatabase.cpp b/Runtime/Character/CParticleDatabase.cpp index f1a3edfc8..6936f8ecd 100644 --- a/Runtime/Character/CParticleDatabase.cpp +++ b/Runtime/Character/CParticleDatabase.cpp @@ -1,10 +1,21 @@ #include "CParticleDatabase.hpp" #include "CSimplePool.hpp" #include "GameGlobalObjects.hpp" +#include "Character/CCharLayoutInfo.hpp" +#include "Character/CPoseAsTransforms.hpp" +#include "Particle/CElementGen.hpp" +#include "Particle/CParticleSwoosh.hpp" +#include "Particle/CParticleElectric.hpp" namespace urde { +CParticleDatabase::CParticleDatabase() +{ + xb4_24_active = true; + xb4_25_drawingEnds = false; +} + void CParticleDatabase::CacheParticleDesc(const CCharacterInfo::CParticleResData& desc) { for (ResId id : desc.x0_part) @@ -30,31 +41,436 @@ void CParticleDatabase::CacheParticleDesc(const CCharacterInfo::CParticleResData } } +void CParticleDatabase::SetModulationColorAllActiveEffectsForParticleDB(const zeus::CColor& color, + std::map>& map) +{ + for (auto& e : map) + { + if (e.second) + e.second->SetModulationColor(color); + } +} + void CParticleDatabase::SetModulationColorAllActiveEffects(const zeus::CColor& color) { + SetModulationColorAllActiveEffectsForParticleDB(color, x3c_rendererDrawLoop); + SetModulationColorAllActiveEffectsForParticleDB(color, x50_firstDrawLoop); + SetModulationColorAllActiveEffectsForParticleDB(color, x64_lastDrawLoop); + SetModulationColorAllActiveEffectsForParticleDB(color, x78_rendererDraw); + SetModulationColorAllActiveEffectsForParticleDB(color, x8c_firstDraw); + SetModulationColorAllActiveEffectsForParticleDB(color, xa0_lastDraw); +} + +void CParticleDatabase::SuspendAllActiveEffectsForParticleDB(CStateManager& mgr, + std::map>& map) +{ + for (auto& e : map) + { + e.second->SetParticleEmission(false, mgr); + } } void CParticleDatabase::SuspendAllActiveEffects(CStateManager& stateMgr) { + SuspendAllActiveEffectsForParticleDB(stateMgr, x3c_rendererDrawLoop); + SuspendAllActiveEffectsForParticleDB(stateMgr, x50_firstDrawLoop); + SuspendAllActiveEffectsForParticleDB(stateMgr, x64_lastDrawLoop); } -void CParticleDatabase::StartEffect(const std::string& name, u32 flags, const CParticleData& data, - const zeus::CVector3f& scale, CStateManager& stateMgr, TAreaId aid, u32 unk1) +void CParticleDatabase::DeleteAllLightsForParticleDB(CStateManager& mgr, + std::map>& map) { + for (auto& e : map) + { + e.second->DeleteLight(mgr); + } +} + +void CParticleDatabase::DeleteAllLights(CStateManager& mgr) +{ + DeleteAllLightsForParticleDB(mgr, x3c_rendererDrawLoop); + DeleteAllLightsForParticleDB(mgr, x50_firstDrawLoop); + DeleteAllLightsForParticleDB(mgr, x64_lastDrawLoop); + DeleteAllLightsForParticleDB(mgr, x78_rendererDraw); + DeleteAllLightsForParticleDB(mgr, x8c_firstDraw); + DeleteAllLightsForParticleDB(mgr, xa0_lastDraw); +} + +void CParticleDatabase::UpdateParticleGenDB(float dt, const CPoseAsTransforms& pose, const CCharLayoutInfo& charInfo, + const zeus::CTransform& xf, const zeus::CVector3f& scale, CStateManager& stateMgr, + std::map>& map, bool deleteIfDone) +{ + for (auto it = map.begin() ; it != map.end() ;) + { + CParticleGenInfo& info = *it->second; + if (info.GetIsActive()) + { + if (info.GetState() == EParticleGenState::NotStarted) + { + CSegId segId = charInfo.GetSegIdFromString(info.GetLocatorName()); + if (segId == 0xff) + { + ++it; + continue; + } + if (!pose.ContainsDataFor(segId)) + { + ++it; + continue; + } + const zeus::CVector3f& off = pose.GetOffset(segId); + switch (info.GetParentedMode()) + { + case CParticleData::EParentedMode::Initial: + { + if (info.GetIsGrabInitialData()) + { + zeus::CTransform segXf( + (info.GetFlags() & 0x10) ? zeus::CMatrix3f::skIdentityMatrix3f : pose.GetTransformMinusOffset(segId), + off * scale); + zeus::CTransform compXf = xf * segXf; + info.SetCurTransform(compXf.getRotation()); + info.SetCurOffset(compXf.origin); + info.SetCurrentTime(0.f); + info.SetIsGrabInitialData(false); + } + + info.SetOrientation(info.GetCurTransform(), stateMgr); + info.SetTranslation(info.GetCurOffset(), stateMgr); + + if (info.GetFlags() & 0x2000) + info.SetGlobalScale(info.GetCurScale() * scale); + else + info.SetGlobalScale(info.GetCurScale()); + + break; + } + case CParticleData::EParentedMode::ContinuousEmitter: + case CParticleData::EParentedMode::ContinuousSystem: + { + if (info.GetIsGrabInitialData()) + { + info.SetCurrentTime(0.f); + info.SetIsGrabInitialData(false); + } + + zeus::CTransform segXf(pose.GetTransformMinusOffset(segId), off * scale); + zeus::CTransform compXf = xf * segXf; + + if (info.GetParentedMode() == CParticleData::EParentedMode::ContinuousEmitter) + { + info.SetTranslation(compXf.origin, stateMgr); + if (info.GetFlags() & 0x10) + info.SetOrientation(xf.getRotation(), stateMgr); + else + info.SetOrientation(compXf.getRotation(), stateMgr); + } + else + { + info.SetGlobalTranslation(compXf.origin, stateMgr); + if (info.GetFlags() & 0x10) + info.SetGlobalOrientation(xf.getRotation(), stateMgr); + else + info.SetGlobalOrientation(compXf.getRotation(), stateMgr); + } + + if (info.GetFlags() & 0x2000) + info.SetGlobalScale(info.GetCurScale() * scale); + else + info.SetGlobalScale(info.GetCurScale()); + + break; + } + default: break; + } + + float sec = (info.GetInactiveStartTime() == 0.f) ? 10000000.f : info.GetInactiveStartTime(); + if (info.GetCurrentTime() > sec) + { + info.SetIsActive(false); + info.SetParticleEmission(false, stateMgr); + info.MarkFinishTime(); + if (info.GetFlags() & 1) + info.DestroyParticles(); + } + } + } + + info.Update(dt, stateMgr); + + if (!info.GetIsActive()) + { + if (!info.HasActiveParticles() && info.GetCurrentTime() - info.GetFinishTime() > 5.f && deleteIfDone) + { + info.DeleteLight(stateMgr); + it = map.erase(it); + continue; + } + } + else if (info.IsSystemDeletable()) + { + info.DeleteLight(stateMgr); + it = map.erase(it); + continue; + } + + info.OffsetTime(dt); + ++it; + } } void CParticleDatabase::Update(float dt, const CPoseAsTransforms& pose, const CCharLayoutInfo& charInfo, - const zeus::CTransform& xf, const zeus::CVector3f& vec, CStateManager& stateMgr) + const zeus::CTransform& xf, const zeus::CVector3f& scale, CStateManager& stateMgr) { + if (!xb4_24_active) + return; + + UpdateParticleGenDB(dt, pose, charInfo, xf, scale, stateMgr, x3c_rendererDrawLoop, true); + UpdateParticleGenDB(dt, pose, charInfo, xf, scale, stateMgr, x50_firstDrawLoop, true); + UpdateParticleGenDB(dt, pose, charInfo, xf, scale, stateMgr, x64_lastDrawLoop, true); + UpdateParticleGenDB(dt, pose, charInfo, xf, scale, stateMgr, x78_rendererDraw, false); + UpdateParticleGenDB(dt, pose, charInfo, xf, scale, stateMgr, x8c_firstDraw, false); + UpdateParticleGenDB(dt, pose, charInfo, xf, scale, stateMgr, xa0_lastDraw, false); + + xb4_25_drawingEnds = (x50_firstDrawLoop.size() || x64_lastDrawLoop.size() || x8c_firstDraw.size() || xa0_lastDraw.size()); } -void CParticleDatabase::AddToRendererClipped(const zeus::CFrustum& frustum) +void CParticleDatabase::RenderParticleGenMap(const std::map>& map) { + for (auto& e : map) + { + e.second->Render(); + } } -void CParticleDatabase::GetActiveParticleLightIds(std::vector&) +void CParticleDatabase::RenderParticleGenMapMasked(const std::map>& map, + int mask, int target) +{ + for (auto& e : map) + { + if ((e.second->GetFlags() & mask) == target) + e.second->Render(); + } +} + +void CParticleDatabase::AddToRendererClippedParticleGenMap(const std::map>& map, + const zeus::CFrustum& frustum) +{ + for (auto& e : map) + { + if (frustum.aabbFrustumTest(*e.second->GetBounds())) + e.second->AddToRenderer(); + } +} + +void CParticleDatabase::AddToRendererClippedParticleGenMapMasked(const std::map>& map, + const zeus::CFrustum& frustum, int mask, int target) +{ + for (auto& e : map) + { + if ((e.second->GetFlags() & mask) == target) + if (frustum.aabbFrustumTest(*e.second->GetBounds())) + e.second->AddToRenderer(); + } +} + +void CParticleDatabase::RenderSystemsToBeDrawnLastMasked(int mask, int target) const +{ + RenderParticleGenMapMasked(xa0_lastDraw, mask, target); + RenderParticleGenMapMasked(x64_lastDrawLoop, mask, target); +} + +void CParticleDatabase::RenderSystemsToBeDrawnLast() const +{ + RenderParticleGenMap(xa0_lastDraw); + RenderParticleGenMap(x64_lastDrawLoop); +} + +void CParticleDatabase::RenderSystemsToBeDrawnFirstMasked(int mask, int target) const +{ + RenderParticleGenMapMasked(x8c_firstDraw, mask, target); + RenderParticleGenMapMasked(x50_firstDrawLoop, mask, target); +} + +void CParticleDatabase::RenderSystemsToBeDrawnFirst() const +{ + RenderParticleGenMap(x8c_firstDraw); + RenderParticleGenMap(x50_firstDrawLoop); +} + +void CParticleDatabase::AddToRendererClippedMasked(const zeus::CFrustum& frustum, int mask, int target) const +{ + AddToRendererClippedParticleGenMapMasked(x78_rendererDraw, frustum, mask, target); + AddToRendererClippedParticleGenMapMasked(x3c_rendererDrawLoop, frustum, mask, target); +} + +void CParticleDatabase::AddToRendererClipped(const zeus::CFrustum& frustum) const +{ + AddToRendererClippedParticleGenMap(x78_rendererDraw, frustum); + AddToRendererClippedParticleGenMap(x3c_rendererDrawLoop, frustum); +} + +CParticleGenInfo* CParticleDatabase::GetParticleEffect(const std::string& name) const +{ + auto search = x3c_rendererDrawLoop.find(name); + if (search != x3c_rendererDrawLoop.end()) + return search->second.get(); + search = x50_firstDrawLoop.find(name); + if (search != x50_firstDrawLoop.end()) + return search->second.get(); + search = x64_lastDrawLoop.find(name); + if (search != x64_lastDrawLoop.end()) + return search->second.get(); + search = x78_rendererDraw.find(name); + if (search != x78_rendererDraw.end()) + return search->second.get(); + search = x8c_firstDraw.find(name); + if (search != x8c_firstDraw.end()) + return search->second.get(); + search = xa0_lastDraw.find(name); + if (search != xa0_lastDraw.end()) + return search->second.get(); + return nullptr; +} + +void CParticleDatabase::SetParticleEffectState(const std::string& name, bool active, CStateManager& mgr) +{ + if (CParticleGenInfo* info = GetParticleEffect(name)) + { + info->SetParticleEmission(active, mgr); + info->SetIsActive(active); + if (!active && (info->GetFlags() & 1) != 0) + info->DestroyParticles(); + info->SetIsGrabInitialData(true); + } +} + +void CParticleDatabase::SetCEXTValue(const std::string& name, int idx, float value) +{ + if (CParticleGenInfo* info = GetParticleEffect(name)) + { + static_cast(static_cast(info)-> + GetParticleSystem().get())->SetCEXTValue(idx, value); + } +} + +template +static int _getGraphicLightId(const T& system, const U& desc) +{ + if (system->SystemHasLight()) + return desc.GetObjectTag()->id; + return -1; +} + +void CParticleDatabase::AddAuxiliaryParticleEffect(const std::string& name, int flags, const CAuxiliaryParticleData& data, + const zeus::CVector3f& scale, CStateManager& mgr, TAreaId aid, int lightIdx) { } +void CParticleDatabase::AddParticleEffect(const std::string& name, int flags, const CParticleData& data, + const zeus::CVector3f& scale, CStateManager& mgr, TAreaId aid, + bool oneShot, int lightId) +{ + if (CParticleGenInfo* info = GetParticleEffect(name)) + { + if (!info->GetIsActive()) + { + info->SetParticleEmission(true, mgr); + info->SetIsActive(true); + info->SetIsGrabInitialData(true); + info->SetFlags(flags); + } + return; + } + + zeus::CVector3f scaleVec; + if (flags & 0x2) + scaleVec.splat(data.GetScale()); + else + scaleVec = scale * data.GetScale(); + + std::unique_ptr newGen; + switch (data.GetTag().type) + { + case SBIG('PART'): + { + auto search = x0_particleDescs.find(data.GetTag().id); + if (search != x0_particleDescs.end()) + { + auto sys = std::make_shared(*search->second, CElementGen::EModelOrientationType::Normal, + CElementGen::EOptionalSystemFlags::One); + newGen = std::make_unique(data.GetTag(), sys, data.GetDuration(), data.GetSegmentName(), + scaleVec, data.GetParentedMode(), flags, mgr, aid, + lightId + _getGraphicLightId(sys, *search->second), + EParticleGenState::NotStarted); + } + break; + } + case SBIG('SWHC'): + { + auto search = x14_swooshDescs.find(data.GetTag().id); + if (search != x14_swooshDescs.end()) + { + auto sys = std::make_shared(*search->second, 0); + newGen = std::make_unique(data.GetTag(), sys, data.GetDuration(), data.GetSegmentName(), + scaleVec, data.GetParentedMode(), flags, mgr, aid, + -1, EParticleGenState::NotStarted); + } + break; + } + case SBIG('ELSC'): + { + auto search = x28_electricDescs.find(data.GetTag().id); + if (search != x28_electricDescs.end()) + { + auto sys = std::make_shared(*search->second); + newGen = std::make_unique(data.GetTag(), sys, data.GetDuration(), data.GetSegmentName(), + scaleVec, data.GetParentedMode(), flags, mgr, aid, + lightId + _getGraphicLightId(sys, *search->second), + EParticleGenState::NotStarted); + } + break; + } + default: break; + } + + if (newGen) + { + newGen->SetIsActive(true); + newGen->SetParticleEmission(true, mgr); + newGen->SetIsGrabInitialData(true); + InsertParticleGen(oneShot, flags, name, std::move(newGen)); + } +} + +void CParticleDatabase::InsertParticleGen(bool oneShot, int flags, const std::string& name, + std::unique_ptr&& gen) +{ + std::map>* useMap; + if (oneShot) + { + if (flags & 0x40) + useMap = &xa0_lastDraw; + else if (flags & 0x20) + useMap = &x8c_firstDraw; + else + useMap = &x78_rendererDraw; + } + else + { + if (flags & 0x40) + useMap = &x64_lastDrawLoop; + else if (flags & 0x20) + useMap = &x50_firstDrawLoop; + else + useMap = &x3c_rendererDrawLoop; + } + + useMap->insert(std::make_pair(name, std::move(gen))); + + if (flags & 0x60) + xb4_25_drawingEnds = true; +} + } diff --git a/Runtime/Character/CParticleDatabase.hpp b/Runtime/Character/CParticleDatabase.hpp index 003a43083..15775ddf6 100644 --- a/Runtime/Character/CParticleDatabase.hpp +++ b/Runtime/Character/CParticleDatabase.hpp @@ -20,26 +20,54 @@ class CParticleDatabase std::map>> x0_particleDescs; std::map>> x14_swooshDescs; std::map>> x28_electricDescs; - std::map> x3c_; - std::map> x50_; - std::map> x64_; - std::map> x78_; - std::map> x8c_; - std::map> xa0_; + std::map> x3c_rendererDrawLoop; + std::map> x50_firstDrawLoop; + std::map> x64_lastDrawLoop; + std::map> x78_rendererDraw; + std::map> x8c_firstDraw; + std::map> xa0_lastDraw; + bool xb4_24_active : 1; + bool xb4_25_drawingEnds : 1; + static void SetModulationColorAllActiveEffectsForParticleDB(const zeus::CColor& color, + std::map>& map); + static void SuspendAllActiveEffectsForParticleDB(CStateManager& mgr, + std::map>& map); + static void DeleteAllLightsForParticleDB(CStateManager& mgr, + std::map>& map); + static void RenderParticleGenMap(const std::map>& map); + static void RenderParticleGenMapMasked(const std::map>& map, + int mask, int target); + static void AddToRendererClippedParticleGenMap(const std::map>& map, + const zeus::CFrustum& frustum); + static void AddToRendererClippedParticleGenMapMasked(const std::map>& map, + const zeus::CFrustum& frustum, int mask, int target); + static void UpdateParticleGenDB(float dt, const CPoseAsTransforms& pose, const CCharLayoutInfo& charInfo, + const zeus::CTransform& xf, const zeus::CVector3f& vec, CStateManager& stateMgr, + std::map>& map, bool deleteIfDone); public: + CParticleDatabase(); void CacheParticleDesc(const CCharacterInfo::CParticleResData& desc); void SetModulationColorAllActiveEffects(const zeus::CColor& color); void SuspendAllActiveEffects(CStateManager& stateMgr); - void StartEffect(const std::string& name, u32 flags, const CParticleData& data, const zeus::CVector3f& scale, - CStateManager& stateMgr, TAreaId aid, u32 unk1); + void DeleteAllLights(CStateManager& stateMgr); void Update(float dt, const CPoseAsTransforms& pose, const CCharLayoutInfo& charInfo, const zeus::CTransform& xf, - const zeus::CVector3f& vec, CStateManager& stateMgr); - void AddToRendererClipped(const zeus::CFrustum& frustum); - void GetActiveParticleLightIds(std::vector&); - void GetActiveParticleLightIdsFromParticleDB( - std::vector&, - const std::map, std::less>&); + const zeus::CVector3f& scale, CStateManager& stateMgr); + void RenderSystemsToBeDrawnLastMasked(int mask, int target) const; + void RenderSystemsToBeDrawnLast() const; + void RenderSystemsToBeDrawnFirstMasked(int mask, int target) const; + void RenderSystemsToBeDrawnFirst() const; + void AddToRendererClippedMasked(const zeus::CFrustum& frustum, int mask, int target) const; + void AddToRendererClipped(const zeus::CFrustum& frustum) const; + CParticleGenInfo* GetParticleEffect(const std::string& name) const; + void SetParticleEffectState(const std::string& name, bool active, CStateManager& mgr); + void SetCEXTValue(const std::string& name, int idx, float value); + void AddAuxiliaryParticleEffect(const std::string& name, int flags, const CAuxiliaryParticleData& data, + const zeus::CVector3f& scale, CStateManager& mgr, TAreaId aid, int lightIdx); + void AddParticleEffect(const std::string& name, int flags, const CParticleData& data, + const zeus::CVector3f& scale, CStateManager& mgr, TAreaId aid, bool oneShot, int lightIdx); + void InsertParticleGen(bool oneShot, int flags, const std::string& name, + std::unique_ptr&& gen); }; } diff --git a/Runtime/Character/CParticleGenInfo.cpp b/Runtime/Character/CParticleGenInfo.cpp index 580747ceb..b3d91fd57 100644 --- a/Runtime/Character/CParticleGenInfo.cpp +++ b/Runtime/Character/CParticleGenInfo.cpp @@ -11,14 +11,15 @@ namespace urde { CParticleGenInfo::CParticleGenInfo(const SObjectTag& part, int frameCount, const std::string& boneName, - const zeus::CVector3f& scale, CParticleData::EParentedMode parentMode, int a, int b) + const zeus::CVector3f& scale, CParticleData::EParentedMode parentMode, + int flags, EParticleGenState state) : x4_part(part) , xc_seconds(frameCount / 60.f) , x10_boneName(boneName) , x28_parentMode(parentMode) -, x2c_a(a) +, x2c_flags(flags) , x30_particleScale(scale) -, x80_(b) +, x80_state(state) { } @@ -41,8 +42,9 @@ static TUniqueId _initializeLight(const std::weak_ptr& system, CSt CParticleGenInfoGeneric::CParticleGenInfoGeneric(const SObjectTag& part, const std::weak_ptr& system, int frameCount, const std::string& boneName, const zeus::CVector3f& scale, CParticleData::EParentedMode parentMode, - int a, CStateManager& stateMgr, TAreaId areaId, int lightId, int b) -: CParticleGenInfo(part, frameCount, boneName, scale, parentMode, a, b), x84_system(system) + int flags, CStateManager& stateMgr, TAreaId areaId, int lightId, + EParticleGenState state) +: CParticleGenInfo(part, frameCount, boneName, scale, parentMode, flags, state), x84_system(system) { if (lightId == -1) x88_lightId = kInvalidUniqueId; @@ -141,7 +143,10 @@ TUniqueId CParticleGenInfoGeneric::GetLightId() const { return x88_lightId; } void CParticleGenInfoGeneric::DeleteLight(CStateManager& mgr) { if (x88_lightId != kInvalidUniqueId) - mgr.DeleteObjectRequest(x88_lightId); + { + mgr.FreeScriptObject(x88_lightId); + x88_lightId = kInvalidUniqueId; + } } void CParticleGenInfoGeneric::SetModulationColor(const zeus::CColor& color) { x84_system->SetModulationColor(color); } diff --git a/Runtime/Character/CParticleGenInfo.hpp b/Runtime/Character/CParticleGenInfo.hpp index deaba6e25..e894ce21c 100644 --- a/Runtime/Character/CParticleGenInfo.hpp +++ b/Runtime/Character/CParticleGenInfo.hpp @@ -12,25 +12,32 @@ struct SObjectTag; class CParticleGen; class CStateManager; +enum class EParticleGenState +{ + NotStarted, + Started +}; + class CParticleGenInfo { SObjectTag x4_part; float xc_seconds; std::string x10_boneName; - float x20_ = 0.f; - bool x24_ = false; + float x20_curTime = 0.f; + bool x24_active = false; CParticleData::EParentedMode x28_parentMode; - int x2c_a; + s32 x2c_flags; zeus::CVector3f x30_particleScale; - float x3c_ = 0.f; - bool x40_ = false; + float x3c_finishTime = 0.f; + bool x40_grabInitialData = false; zeus::CTransform x44_transform; zeus::CVector3f x74_offset; - s32 x80_; + EParticleGenState x80_state; public: - CParticleGenInfo(const SObjectTag& part, int frameCount, const std::string& boneName, const zeus::CVector3f&, - CParticleData::EParentedMode parentMode, int a, int b); + CParticleGenInfo(const SObjectTag& part, int frameCount, const std::string& boneName, + const zeus::CVector3f& scale, CParticleData::EParentedMode parentMode, + int flags, EParticleGenState state); virtual ~CParticleGenInfo() = default; virtual void AddToRenderer() = 0; @@ -48,22 +55,30 @@ public: virtual void DestroyParticles() = 0; virtual bool HasLight() const = 0; virtual TUniqueId GetLightId() const = 0; - virtual void DeleteLight(CStateManager&) const = 0; + virtual void DeleteLight(CStateManager& stateMgr) = 0; virtual void SetModulationColor(const zeus::CColor& color) = 0; - void SetFlags(s32); - s32 GetFlags() const; - void SetIsGrabInitialData(bool); - bool GetIsGrabInitialData() const; - bool GetIsActive() const; - bool SetIsActive(bool); - void OffsetTime(float); + void SetFlags(s32 f) { x2c_flags = f; } + s32 GetFlags() const { return x2c_flags; } + void SetIsGrabInitialData(bool g) { x40_grabInitialData = g; } + bool GetIsGrabInitialData() const { return x40_grabInitialData; } + bool GetIsActive() const { return x24_active; } + void SetIsActive(bool a) { x24_active = a; } + void OffsetTime(float dt) { x20_curTime += dt; } + const zeus::CVector3f& GetCurOffset() const { return x74_offset; } void SetCurOffset(const zeus::CVector3f& offset) { x74_offset = offset; } + const zeus::CTransform& GetCurTransform() const { return x44_transform; } void SetCurTransform(const zeus::CTransform& xf) { x44_transform = xf; } - void SetInactiveStartTime(float); - float GetInactiveStartTime() const; - float GetFinishTime() const; - float GetCurrentTime() const; + const zeus::CVector3f& GetCurScale() const { return x30_particleScale; } + void SetCurScale(const zeus::CVector3f& scale) { x30_particleScale = scale; } + void SetInactiveStartTime(float s) { xc_seconds = s; } + float GetInactiveStartTime() const { return xc_seconds; } + void MarkFinishTime() { x3c_finishTime = x20_curTime; } + float GetFinishTime() const { return x3c_finishTime; } + float GetCurrentTime() const { return x20_curTime; } + void SetCurrentTime(float t) { x20_curTime = t; } + EParticleGenState GetState() const { return x80_state; } + void SetState(EParticleGenState s) { x80_state = s; } CParticleData::EParentedMode GetParentedMode() const { return x28_parentMode; } const std::string& GetLocatorName() const { return x10_boneName; } @@ -75,10 +90,10 @@ class CParticleGenInfoGeneric : public CParticleGenInfo TUniqueId x88_lightId; public: - CParticleGenInfoGeneric(const SObjectTag& part, const std::weak_ptr& system, int, - const std::string& boneName, const zeus::CVector3f& scale, - CParticleData::EParentedMode parentMode, int a, CStateManager& stateMgr, TAreaId, - int lightId, int b); + CParticleGenInfoGeneric(const SObjectTag& part, const std::weak_ptr& system, + int frames, const std::string& boneName, const zeus::CVector3f& scale, + CParticleData::EParentedMode parentMode, int flags, CStateManager& stateMgr, TAreaId, + int lightId, EParticleGenState state); void AddToRenderer(); void Render(); @@ -95,8 +110,9 @@ public: void DestroyParticles(); bool HasLight() const; TUniqueId GetLightId() const; - void DeleteLight(CStateManager&); + void DeleteLight(CStateManager& mgr); void SetModulationColor(const zeus::CColor& color); + const std::shared_ptr GetParticleSystem() const { return x84_system; } }; } diff --git a/Runtime/Character/CPoseAsTransforms.hpp b/Runtime/Character/CPoseAsTransforms.hpp index 7ebd00117..ce725271c 100644 --- a/Runtime/Character/CPoseAsTransforms.hpp +++ b/Runtime/Character/CPoseAsTransforms.hpp @@ -32,6 +32,7 @@ public: const zeus::CTransform& GetRestToAccumTransform(const CSegId& id) const; const zeus::CVector3f& GetOffset(const CSegId& id) const; const zeus::CMatrix3f& GetRotation(const CSegId& id) const; + const zeus::CMatrix3f& GetTransformMinusOffset(const CSegId& id) const { return GetRotation(id); } void Insert(const CSegId& id, const zeus::CMatrix3f& rotation, const zeus::CVector3f& offset, diff --git a/Runtime/Character/CSoundPOINode.hpp b/Runtime/Character/CSoundPOINode.hpp index d4ca274d7..3b1f9d59e 100644 --- a/Runtime/Character/CSoundPOINode.hpp +++ b/Runtime/Character/CSoundPOINode.hpp @@ -22,6 +22,9 @@ public: static CSoundPOINode CopyNodeMinusStartTime(const CSoundPOINode& node, const CCharAnimTime& startTime); + u32 GetSfxId() const { return x38_sfxId; } + float GetFalloff() const { return x3c_falloff; } + float GetMaxDist() const { return x40_maxDist; } }; } diff --git a/Runtime/Graphics/CLight.hpp b/Runtime/Graphics/CLight.hpp index bc2b01db3..f9d95c046 100644 --- a/Runtime/Graphics/CLight.hpp +++ b/Runtime/Graphics/CLight.hpp @@ -42,7 +42,7 @@ class CLight float x34_angleL; float x38_angleQ; u32 x3c_priority = 0; - u32 x40_loadedIdx = 0; + u32 x40_lightId = 0; // Serves as unique key float x44_cachedRadius; float x48_cachedIntensity; bool x4c_24_intensityDirty : 1; diff --git a/Runtime/Graphics/Shaders/CColoredQuadFilter.cpp b/Runtime/Graphics/Shaders/CColoredQuadFilter.cpp index 364a5ae3b..7513d8b4f 100644 --- a/Runtime/Graphics/Shaders/CColoredQuadFilter.cpp +++ b/Runtime/Graphics/Shaders/CColoredQuadFilter.cpp @@ -33,13 +33,8 @@ void CColoredQuadFilter::draw(const zeus::CColor& color, const zeus::CRectangle& m_uniform.m_color = color; m_uniBuf->load(&m_uniform, sizeof(m_uniform)); - CGraphics::g_BooMainCommandQueue->setShaderDataBinding(m_dataBind); - CGraphics::g_BooMainCommandQueue->draw(0, 4); -} - -void CColoredQuadFilter::DrawFilter(EFilterShape shape, const zeus::CColor& color, float t) -{ - + CGraphics::SetShaderDataBinding(m_dataBind); + CGraphics::DrawArray(0, 4); } void CWideScreenFilter::draw(const zeus::CColor& color, float t) diff --git a/Runtime/Graphics/Shaders/CColoredQuadFilter.hpp b/Runtime/Graphics/Shaders/CColoredQuadFilter.hpp index 3b616ba88..8c164a947 100644 --- a/Runtime/Graphics/Shaders/CColoredQuadFilter.hpp +++ b/Runtime/Graphics/Shaders/CColoredQuadFilter.hpp @@ -34,7 +34,7 @@ public: CColoredQuadFilter(EFilterType type, const TLockedToken&) : CColoredQuadFilter(type) {} void draw(const zeus::CColor& color, const zeus::CRectangle& rect=DefaultRect); - void DrawFilter(EFilterShape shape, const zeus::CColor& color, float t); + void DrawFilter(EFilterShape shape, const zeus::CColor& color, float t) { draw(color); } using _CLS = CColoredQuadFilter; #include "TMultiBlendShaderDecl.hpp" diff --git a/Runtime/Graphics/Shaders/CTexturedQuadFilter.cpp b/Runtime/Graphics/Shaders/CTexturedQuadFilter.cpp index f2b24e7d9..c793d03af 100644 --- a/Runtime/Graphics/Shaders/CTexturedQuadFilter.cpp +++ b/Runtime/Graphics/Shaders/CTexturedQuadFilter.cpp @@ -14,7 +14,7 @@ CTexturedQuadFilter::CTexturedQuadFilter(EFilterType type, boo::ITexture* tex) { m_token = CGraphics::g_BooFactory->commitTransaction([&](boo::IGraphicsDataFactory::Context& ctx) -> bool { - m_vbo = ctx.newDynamicBuffer(boo::BufferUse::Vertex, 32, 4); + m_vbo = ctx.newDynamicBuffer(boo::BufferUse::Vertex, 32, 16); m_uniBuf = ctx.newDynamicBuffer(boo::BufferUse::Uniform, sizeof(Uniform), 1); m_dataBind = TMultiBlendShader::BuildShaderDataBinding(ctx, type, *this); return true; @@ -46,8 +46,8 @@ void CTexturedQuadFilter::draw(const zeus::CColor& color, float uvScale, const z m_uniform.m_color = color; m_uniBuf->load(&m_uniform, sizeof(m_uniform)); - CGraphics::g_BooMainCommandQueue->setShaderDataBinding(m_dataBind); - CGraphics::g_BooMainCommandQueue->draw(0, 4); + CGraphics::SetShaderDataBinding(m_dataBind); + CGraphics::DrawArray(0, 4); } void CTexturedQuadFilter::drawCropped(const zeus::CColor& color, float uvScale) @@ -69,8 +69,8 @@ void CTexturedQuadFilter::drawCropped(const zeus::CColor& color, float uvScale) m_uniform.m_color = color; m_uniBuf->load(&m_uniform, sizeof(m_uniform)); - CGraphics::g_BooMainCommandQueue->setShaderDataBinding(m_dataBind); - CGraphics::g_BooMainCommandQueue->draw(0, 4); + CGraphics::SetShaderDataBinding(m_dataBind); + CGraphics::DrawArray(0, 4); } void CTexturedQuadFilter::drawVerts(const zeus::CColor& color, const Vert verts[4], float lod) @@ -82,13 +82,58 @@ void CTexturedQuadFilter::drawVerts(const zeus::CColor& color, const Vert verts[ m_uniform.m_lod = lod; m_uniBuf->load(&m_uniform, sizeof(m_uniform)); - CGraphics::g_BooMainCommandQueue->setShaderDataBinding(m_dataBind); - CGraphics::g_BooMainCommandQueue->draw(0, 4); + CGraphics::SetShaderDataBinding(m_dataBind); + CGraphics::DrawArray(0, 4); } void CTexturedQuadFilter::DrawFilter(EFilterShape shape, const zeus::CColor& color, float t) { + m_uniform.m_matrix = zeus::CMatrix4f::skIdentityMatrix4f; + m_uniform.m_lod = 0.f; + m_uniform.m_color = color; + m_uniBuf->load(&m_uniform, sizeof(m_uniform)); + CGraphics::SetShaderDataBinding(m_dataBind); + + if (shape == EFilterShape::FullscreenQuarters) + { + Vert QuadVerts[] = + { + {{-1.f, -1.f, 0.f}, {0.f, 0.f}}, + {{-1.f, 0.f, 0.f}, {0.f, t}}, + {{ 0.f, -1.f, 0.f}, {t, 0.f}}, + {{ 0.f, 0.f, 0.f}, {t, t}}, + {{-1.f, 1.f, 0.f}, {0.f, 0.f}}, + {{-1.f, 0.f, 0.f}, {0.f, t}}, + {{ 0.f, 1.f, 0.f}, {t, 0.f}}, + {{ 0.f, 0.f, 0.f}, {t, t}}, + {{ 1.f, -1.f, 0.f}, {0.f, 0.f}}, + {{ 1.f, 0.f, 0.f}, {0.f, t}}, + {{ 0.f, -1.f, 0.f}, {t, 0.f}}, + {{ 0.f, 0.f, 0.f}, {t, t}}, + {{ 1.f, 1.f, 0.f}, {0.f, 0.f}}, + {{ 1.f, 0.f, 0.f}, {0.f, t}}, + {{ 0.f, 1.f, 0.f}, {t, 0.f}}, + {{ 0.f, 0.f, 0.f}, {t, t}}, + }; + m_vbo->load(QuadVerts, sizeof(Vert) * 16); + CGraphics::DrawArray(0, 4); + CGraphics::DrawArray(4, 4); + CGraphics::DrawArray(8, 4); + CGraphics::DrawArray(12, 4); + } + else + { + Vert FullscreenVerts[] = + { + {{-1.f, -1.f, 0.f}, {0.f, 0.f}}, + {{-1.f, 1.f, 0.f}, {0.f, t}}, + {{ 1.f, -1.f, 0.f}, {t, 0.f}}, + {{ 1.f, 1.f, 0.f}, {t, t}}, + }; + m_vbo->load(FullscreenVerts, sizeof(Vert) * 4); + CGraphics::DrawArray(0, 4); + } } const zeus::CRectangle CTexturedQuadFilter::DefaultRect = {0.f, 0.f, 1.f, 1.f}; diff --git a/Runtime/GuiSys/CGuiFrame.cpp b/Runtime/GuiSys/CGuiFrame.cpp index c6c113a58..5844b9323 100644 --- a/Runtime/GuiSys/CGuiFrame.cpp +++ b/Runtime/GuiSys/CGuiFrame.cpp @@ -105,12 +105,12 @@ void CGuiFrame::DisableLights() const void CGuiFrame::RemoveLight(CGuiLight* light) { - m_indexedLights[light->GetLoadedIdx()] = nullptr; + m_indexedLights[light->GetLightId()] = nullptr; } void CGuiFrame::AddLight(CGuiLight* light) { - m_indexedLights[light->GetLoadedIdx()] = light; + m_indexedLights[light->GetLightId()] = light; } void CGuiFrame::RegisterLight(std::shared_ptr&& light) diff --git a/Runtime/GuiSys/CGuiLight.cpp b/Runtime/GuiSys/CGuiLight.cpp index 9ecb0984f..0a2c1ceca 100644 --- a/Runtime/GuiSys/CGuiLight.cpp +++ b/Runtime/GuiSys/CGuiLight.cpp @@ -14,7 +14,7 @@ CGuiLight::CGuiLight(const CGuiWidgetParms& parms, const CLight& light) xcc_angleC(light.x30_angleC), xd0_angleL(light.x34_angleL), xd4_angleQ(light.x38_angleQ), - xd8_loadedIdx(light.x40_loadedIdx) + xd8_lightId(light.x40_lightId) {} CGuiLight::~CGuiLight() @@ -65,7 +65,7 @@ std::shared_ptr CGuiLight::Create(CGuiFrame* frame, CInputStream& in float angC = in.readFloatBig(); float angL = in.readFloatBig(); float angQ = in.readFloatBig(); - u32 loadedIdx = in.readUint32Big(); + u32 lightId = in.readUint32Big(); std::shared_ptr ret = {}; switch (tp) @@ -77,7 +77,7 @@ std::shared_ptr CGuiLight::Create(CGuiFrame* frame, CInputStream& in parms.x10_color, cutoff); lt.SetAttenuation(distC, distL, distQ); lt.SetAngleAttenuation(angC, angL, angQ); - lt.x40_loadedIdx = loadedIdx; + lt.x40_lightId = lightId; ret = std::make_shared(parms, lt); break; } @@ -85,14 +85,14 @@ std::shared_ptr CGuiLight::Create(CGuiFrame* frame, CInputStream& in { CLight lt = CLight::BuildPoint(zeus::CVector3f::skZero, parms.x10_color); lt.SetAttenuation(distC, distL, distQ); - lt.x40_loadedIdx = loadedIdx; + lt.x40_lightId = lightId; ret = std::make_shared(parms, lt); break; } case ELightType::Directional: { CLight lt = CLight::BuildDirectional(zeus::CVector3f::skZero, parms.x10_color); - lt.x40_loadedIdx = loadedIdx; + lt.x40_lightId = lightId; ret = std::make_shared(parms, lt); break; } diff --git a/Runtime/GuiSys/CGuiLight.hpp b/Runtime/GuiSys/CGuiLight.hpp index f163f94d4..3a447e2aa 100644 --- a/Runtime/GuiSys/CGuiLight.hpp +++ b/Runtime/GuiSys/CGuiLight.hpp @@ -18,7 +18,7 @@ class CGuiLight : public CGuiWidget float xcc_angleC; float xd0_angleL; float xd4_angleQ; - u32 xd8_loadedIdx; + u32 xd8_lightId; zeus::CColor xdc_ambColor = zeus::CColor::skBlack; public: ~CGuiLight(); @@ -27,7 +27,7 @@ public: CLight BuildLight() const; void SetIsVisible(bool vis); - u32 GetLoadedIdx() const {return xd8_loadedIdx;} + u32 GetLightId() const {return xd8_lightId;} const zeus::CColor& GetAmbientLightColor() const {return xdc_ambColor;} void SetSpotCutoff(float v) {xbc_spotCutoff = v;} void SetDistC(float v) {xc0_distC = v;} @@ -36,7 +36,7 @@ public: void SetAngleC(float v) {xcc_angleC = v;} void SetAngleL(float v) {xd0_angleL = v;} void SetAngleQ(float v) {xd4_angleQ = v;} - void SetLoadedIdx(u32 idx) {xd8_loadedIdx = idx;} + void SetLightId(u32 idx) {xd8_lightId = idx;} void SetAmbientLightColor(const zeus::CColor& color) {xdc_ambColor = color;} static std::shared_ptr Create(CGuiFrame* frame, CInputStream& in, CSimplePool* sp); diff --git a/Runtime/MP1/CSamusHud.cpp b/Runtime/MP1/CSamusHud.cpp index e4ffd8cab..f6c24183e 100644 --- a/Runtime/MP1/CSamusHud.cpp +++ b/Runtime/MP1/CSamusHud.cpp @@ -334,7 +334,7 @@ void CSamusHud::InitializeDamageLight() x3d4_damageLight->SetAngleC(g_tweakGui->GetDamageLightAngleC()); x3d4_damageLight->SetAngleL(g_tweakGui->GetDamageLightAngleL()); x3d4_damageLight->SetAngleQ(g_tweakGui->GetDamageLightAngleQ()); - x3d4_damageLight->SetLoadedIdx(4); + x3d4_damageLight->SetLightId(4); x3d4_damageLight->SetLocalTransform(zeus::CTransform::Identity()); diff --git a/Runtime/MP1/World/CActorContraption.cpp b/Runtime/MP1/World/CActorContraption.cpp index 137b952a0..c930a7d40 100644 --- a/Runtime/MP1/World/CActorContraption.cpp +++ b/Runtime/MP1/World/CActorContraption.cpp @@ -63,7 +63,7 @@ void MP1::CActorContraption::ResetFlameThrowers(CStateManager& mgr) } } -void MP1::CActorContraption::DoUserAnimEvent(CStateManager& mgr, CInt32POINode& node, EUserEventType evType) +void MP1::CActorContraption::DoUserAnimEvent(CStateManager& mgr, CInt32POINode& node, EUserEventType evType, float dt) { if (evType == EUserEventType::DamageOff) { @@ -76,7 +76,7 @@ void MP1::CActorContraption::DoUserAnimEvent(CStateManager& mgr, CInt32POINode& fl->Fire(GetTransform(), mgr, false); } else - CActor::DoUserAnimEvent(mgr, node, evType); + CActor::DoUserAnimEvent(mgr, node, evType, dt); } CFlameThrower* MP1::CActorContraption::CreateFlameThrower(const std::string& name, CStateManager& mgr) diff --git a/Runtime/MP1/World/CActorContraption.hpp b/Runtime/MP1/World/CActorContraption.hpp index eafe49345..13193dd65 100644 --- a/Runtime/MP1/World/CActorContraption.hpp +++ b/Runtime/MP1/World/CActorContraption.hpp @@ -24,7 +24,7 @@ public: void Accept(IVisitor &visitor); void AcceptScriptMsg(EScriptObjectMessage, TUniqueId, CStateManager &); void Think(float, CStateManager &); - void DoUserAnimEvent(CStateManager &, CInt32POINode &, EUserEventType); + void DoUserAnimEvent(CStateManager &, CInt32POINode &, EUserEventType, float dt); CFlameThrower* CreateFlameThrower(const std::string&, CStateManager&); void ResetFlameThrowers(CStateManager& mgr); }; diff --git a/Runtime/Particle/CElementGen.hpp b/Runtime/Particle/CElementGen.hpp index b7a5cb610..b7120c62c 100644 --- a/Runtime/Particle/CElementGen.hpp +++ b/Runtime/Particle/CElementGen.hpp @@ -90,6 +90,7 @@ private: float x6c_generatorRemainder = 0.f; int x90_MAXP = 0; u16 x94_randomSeed = 99; + float x9c_cextValues[16] = {}; float x78_generatorRate = 1.f; zeus::CVector3f x7c_translation; zeus::CVector3f x88_globalTranslation; @@ -221,6 +222,8 @@ public: u32 GetParticleCountAll() const {return x20c_recursiveParticleCount;} void EndLifetime(); void ForceParticleCreation(int amount); + float GetCEXTValue(int i) const { return x9c_cextValues[i]; } + void SetCEXTValue(int i, float v) { x9c_cextValues[i] = v; } bool InternalUpdate(double); void RenderModels(); diff --git a/Runtime/Particle/CRealElement.cpp b/Runtime/Particle/CRealElement.cpp index 3975c012d..6b37fe3b7 100644 --- a/Runtime/Particle/CRealElement.cpp +++ b/Runtime/Particle/CRealElement.cpp @@ -339,7 +339,7 @@ bool CRECEXT::GetValue(int frame, float& valOut) const int a; x4_a->GetValue(frame, a); int cv = std::max(0, a); - /* TODO: Figure out how value table is generated/stored in 0-00 */ + valOut = CParticleGlobals::g_currentParticleSystem->x4_system->GetCEXTValue(cv & 0xf); return false; } diff --git a/Runtime/World/CActor.cpp b/Runtime/World/CActor.cpp index 3482ef2b2..8e600c3d5 100644 --- a/Runtime/World/CActor.cpp +++ b/Runtime/World/CActor.cpp @@ -6,6 +6,7 @@ #include "TCastTo.hpp" #include "Character/IAnimReader.hpp" #include "Character/CActorLights.hpp" +#include "Camera/CGameCamera.hpp" namespace urde { @@ -28,6 +29,7 @@ CActor::CActor(TUniqueId uid, bool active, const std::string& name, const CEntit { if (mData.x10_animData || mData.x1c_normalModel) x64_modelData = std::make_unique(std::move(mData)); + xd8_nonLoopingSfxHandles.resize(2); } void CActor::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr) @@ -123,11 +125,11 @@ zeus::CVector3f CActor::GetScanObjectIndicatorPosition(const CStateManager&) con void CActor::RemoveEmitter() { - if (x8c_sfxHandle) + if (x8c_loopingSfxHandle) { - CSfxManager::RemoveEmitter(*x8c_sfxHandle.get()); + CSfxManager::RemoveEmitter(x8c_loopingSfxHandle); x88_sfxId = -1; - x8c_sfxHandle.reset(); + x8c_loopingSfxHandle.reset(); } } @@ -161,7 +163,7 @@ void CActor::OnScanStateChanged(EScanState state, CStateManager& mgr) zeus::CAABox CActor::GetSortingBounds(const CStateManager&) const { return x9c_aabox; } -void CActor::DoUserAnimEvent(CStateManager&, CInt32POINode&, EUserEventType) {} +void CActor::DoUserAnimEvent(CStateManager&, CInt32POINode&, EUserEventType, float dt) {} void CActor::RemoveMaterial(EMaterialTypes t1, EMaterialTypes t2, EMaterialTypes t3, EMaterialTypes t4, CStateManager& mgr) @@ -265,16 +267,14 @@ void CActor::SetInFluid(bool in, TUniqueId uid) bool CActor::HasModelData() const { return bool(x64_modelData); } -const CSfxHandle* CActor::GetSfxHandle() const { return x8c_sfxHandle.get(); } - -void CActor::SetSfxPitchBend(s32 val) +void CActor::SetSoundEventPitchBend(s32 val) { xe6_30_enablePitchBend = true; - xc0_ = val; - if (x8c_sfxHandle == 0) + xc0_pitchBend = val / 8192.f; + if (!x8c_loopingSfxHandle) return; - CSfxManager::PitchBend(*x8c_sfxHandle.get(), val); + CSfxManager::PitchBend(x8c_loopingSfxHandle, val); } void CActor::SetRotation(const zeus::CQuaternion &q) @@ -318,9 +318,154 @@ void CActor::EnsureRendered(const CStateManager& stateMgr, const zeus::CVector3f stateMgr.AddDrawableActor(*this, pos, aabb); } -SAdvancementDeltas CActor::UpdateAnimation(float, CStateManager&, bool) +void CActor::UpdateSfxEmitters() { - return {}; + for (CSfxHandle& sfx : xd8_nonLoopingSfxHandles) + CSfxManager::UpdateEmitter(sfx, x34_transform.origin, zeus::CVector3f::skZero, xd4_maxVol); +} + +void CActor::ProcessSoundEvent(u32 sfxId, float weight, u32 flags, float falloff, float maxDist, + float minVol, float maxVol, const zeus::CVector3f& toListener, + const zeus::CVector3f& position, TAreaId aid, CStateManager& mgr, + bool translateId) +{ + if (toListener.magSquared() >= maxDist * maxDist) + return; + u16 id = translateId ? CSfxManager::TranslateSFXID(sfxId) : sfxId; + + u32 musyxFlags = 0x1; // Continuous parameter update + if (flags & 0x8) + musyxFlags |= 0x8; // Doppler FX + + CAudioSys::C3DEmitterParmData parms; + parms.x0_pos = position; + parms.xc_dir = zeus::CVector3f::skZero; + parms.x18_maxDist = maxDist; + parms.x1c_distComp = falloff; + parms.x20_flags = musyxFlags; + parms.x24_sfxId = id; + parms.x26_maxVol = maxVol; + parms.x27_minVol = minVol; + parms.x28_important = false; + parms.x29_prio = 0x7f; + + bool useAcoustics = (flags & 0x80) == 0; + bool looping = (sfxId & 0x80000000) != 0; + bool nonEmitter = (sfxId & 0x40000000) != 0; + bool continuousUpdate = (sfxId & 0x20000000) != 0; + + if (mgr.GetActiveRandom()->Float() > weight) + return; + + if (looping) + { + u16 curId = x88_sfxId; + if (!x8c_loopingSfxHandle) + { + CSfxHandle handle; + if (nonEmitter) + handle = CSfxManager::SfxStart(id, 1.f, 0.f, true, 0x7f, true, aid); + else + handle = CSfxManager::AddEmitter(parms, useAcoustics, 0x7f, true, aid); + if (handle) + { + x88_sfxId = id; + x8c_loopingSfxHandle = handle; + if (xe6_30_enablePitchBend) + CSfxManager::PitchBend(handle, xc0_pitchBend); + } + } + else if (curId == id) + { + CSfxManager::UpdateEmitter(x8c_loopingSfxHandle, position, zeus::CVector3f::skZero, maxVol); + } + else if (flags & 0x4) + { + CSfxManager::RemoveEmitter(x8c_loopingSfxHandle); + CSfxHandle handle = CSfxManager::AddEmitter(parms, useAcoustics, 0x7f, true, aid); + if (handle) + { + x88_sfxId = id; + x8c_loopingSfxHandle = handle; + if (xe6_30_enablePitchBend) + CSfxManager::PitchBend(handle, xc0_pitchBend); + } + } + } + else + { + CSfxHandle handle; + if (nonEmitter) + handle = CSfxManager::SfxStart(id, 1.f, 0.f, useAcoustics, 0x7f, false, aid); + else + handle = CSfxManager::AddEmitter(parms, useAcoustics, 0x7f, false, aid); + + if (continuousUpdate) + { + xd8_nonLoopingSfxHandles[xe4_24_nextNonLoopingSfxHandle] = handle; + xe4_24_nextNonLoopingSfxHandle = (xe4_24_nextNonLoopingSfxHandle + 1) % xd8_nonLoopingSfxHandles.size(); + } + + if (xe6_30_enablePitchBend) + CSfxManager::PitchBend(handle, xc0_pitchBend); + } +} + +SAdvancementDeltas CActor::UpdateAnimation(float dt, CStateManager& mgr, bool advTree) +{ + SAdvancementDeltas deltas = x64_modelData->AdvanceAnimation(dt, mgr, GetAreaId(), advTree); + x64_modelData->AdvanceParticles(x34_transform, dt, mgr); + UpdateSfxEmitters(); + if (x64_modelData && x64_modelData->HasAnimData()) + { + zeus::CVector3f toCamera = + mgr.GetCameraManager()->GetCurrentCamera(mgr)->GetTranslation() - x34_transform.origin; + + for (int i=0 ; iGetAnimationData()->GetPassedSoundPOICount() ; ++i) + { + CSoundPOINode& poi = CAnimData::g_SoundPOINodes[i]; + if (poi.GetPoiType() != EPOIType::Sound) + continue; + if (xe5_26_muted) + continue; + if (poi.GetCharacterIndex() != -1 && + x64_modelData->GetAnimationData()->GetCharacterIndex() != poi.GetCharacterIndex()) + continue; + ProcessSoundEvent(poi.GetSfxId(), poi.GetWeight(), poi.GetFlags(), poi.GetFalloff(), + poi.GetMaxDist(), 0.16f, xd4_maxVol, toCamera, x34_transform.origin, x4_areaId, + mgr, true); + } + + for (int i=0 ; iGetAnimationData()->GetPassedIntPOICount() ; ++i) + { + CInt32POINode& poi = CAnimData::g_Int32POINodes[i]; + if (poi.GetPoiType() == EPOIType::SoundInt32) + { + if (xe5_26_muted) + continue; + if (poi.GetCharacterIndex() != -1 && + x64_modelData->GetAnimationData()->GetCharacterIndex() != poi.GetCharacterIndex()) + continue; + ProcessSoundEvent(poi.GetValue(), poi.GetWeight(), poi.GetFlags(), 0.1f, + 150.f, 0.16f, xd4_maxVol, toCamera, x34_transform.origin, x4_areaId, + mgr, true); + } + else if (poi.GetPoiType() == EPOIType::UserEvent) + { + DoUserAnimEvent(mgr, poi, EUserEventType(poi.GetValue()), dt); + } + } + + for (int i=0 ; iGetAnimationData()->GetPassedParticlePOICount() ; ++i) + { + CParticlePOINode& poi = CAnimData::g_ParticlePOINodes[i]; + if (poi.GetCharacterIndex() != -1 && + x64_modelData->GetAnimationData()->GetCharacterIndex() != poi.GetCharacterIndex()) + continue; + x64_modelData->AnimationData()->GetParticleDB().SetParticleEffectState(poi.GetString(), true, mgr); + } + } + return deltas; } void CActor::SetActorLights(std::unique_ptr lights) diff --git a/Runtime/World/CActor.hpp b/Runtime/World/CActor.hpp index 3ce6453d4..b447e443f 100644 --- a/Runtime/World/CActor.hpp +++ b/Runtime/World/CActor.hpp @@ -33,25 +33,26 @@ protected: CMaterialList x68_material; CMaterialFilter x70_materialFilter; s16 x88_sfxId = -1; - std::unique_ptr x8c_sfxHandle; + CSfxHandle x8c_loopingSfxHandle; std::unique_ptr x90_actorLights; std::unique_ptr x94_simpleShadow; std::unique_ptr> x98_scanObjectInfo; zeus::CAABox x9c_aabox; CModelFlags xb4_drawFlags; float xbc_time = 0.f; - s32 xc0_ = 0; + float xc0_pitchBend = 0.f; TUniqueId xc4_fluidId = kInvalidUniqueId; TUniqueId xc6_nextDrawNode = kInvalidUniqueId; u32 xc8_drawnToken = -1; u32 xcc_addedToken = -1; float xd0_; - u8 xd4_ = 0x7F; - u32 xd8_ = 2; + float xd4_maxVol = 1.f; + rstl::reserved_vector xd8_nonLoopingSfxHandles; union { struct { + u8 xe4_24_nextNonLoopingSfxHandle : 3; bool xe4_27_ : 1; bool xe4_28_ : 1; bool xe4_29_ : 1; @@ -72,6 +73,7 @@ protected: u32 dummy = 0; }; void _CreateShadow(); + void UpdateSfxEmitters(); public: enum class EFluidState @@ -117,7 +119,7 @@ public: virtual void FluidFXThink(EFluidState, CScriptWater&, CStateManager&); virtual void OnScanStateChanged(EScanState, CStateManager&); virtual zeus::CAABox GetSortingBounds(const CStateManager&) const; - virtual void DoUserAnimEvent(CStateManager&, CInt32POINode&, EUserEventType); + virtual void DoUserAnimEvent(CStateManager&, CInt32POINode&, EUserEventType, float dt); void RemoveEmitter(); const zeus::CTransform& GetTransform() const { return x34_transform; } @@ -145,8 +147,8 @@ public: const CMaterialList& GetMaterialList() const { return x68_material; } void SetInFluid(bool in, TUniqueId uid); bool HasModelData() const; - const CSfxHandle* GetSfxHandle() const; - void SetSfxPitchBend(s32); + const CSfxHandle& GetSfxHandle() const { return x8c_loopingSfxHandle; } + void SetSoundEventPitchBend(s32); void SetRotation(const zeus::CQuaternion& q); void SetTranslation(const zeus::CVector3f& tr); void SetTransform(const zeus::CTransform& tr); @@ -157,6 +159,10 @@ public: CModelData* ModelData() { return x64_modelData.get(); } void EnsureRendered(const CStateManager&); void EnsureRendered(const CStateManager&, const zeus::CVector3f&, const zeus::CAABox&) const; + void ProcessSoundEvent(u32 sfxId, float weight, u32 flags, float falloff, float maxDist, + float minVol, float maxVol, const zeus::CVector3f& toListener, + const zeus::CVector3f& position, TAreaId aid, CStateManager& mgr, + bool translateId); SAdvancementDeltas UpdateAnimation(float, CStateManager&, bool); void SetActorLights(std::unique_ptr); bool CanDrawStatic() const; diff --git a/Runtime/World/CGameLight.cpp b/Runtime/World/CGameLight.cpp index 992de0533..b30b9c9cd 100644 --- a/Runtime/World/CGameLight.cpp +++ b/Runtime/World/CGameLight.cpp @@ -35,7 +35,7 @@ void CGameLight::Think(float dt, CStateManager& mgr) void CGameLight::SetLightPriorityAndId() { xec_light.x3c_priority = x140_priority; - xec_light.x40_loadedIdx = x13c_loadedIdx; + xec_light.x40_lightId = x13c_loadedIdx; } void CGameLight::SetLight(const CLight& light)