From e923d836175b3c1fb6084644810244b6b8a0ce03 Mon Sep 17 00:00:00 2001 From: Jack Andersen Date: Sun, 26 Feb 2017 19:25:14 -1000 Subject: [PATCH] CScriptMidi and work on CGameArea loading --- DataSpec/DNACommon/AROTBuilder.cpp | 8 +- DataSpec/DNAMP1/MLVL.cpp | 9 +- DataSpec/DNAMP1/MREA.cpp | 2 +- DataSpec/DNAMP1/ScriptObjects/Midi.hpp | 8 +- Editor/ProjectResourceFactoryBase.cpp | 35 +++++++- Editor/ProjectResourceFactoryBase.hpp | 7 ++ Editor/ProjectResourceFactoryMP1.cpp | 2 + Runtime/Audio/CMidiManager.cpp | 49 +++++++++++ Runtime/Audio/CMidiManager.hpp | 47 +++++++++++ Runtime/CInGameTweakManagerBase.hpp | 6 +- Runtime/CStateManager.cpp | 8 +- Runtime/CStateManager.hpp | 4 +- Runtime/Collision/CAreaOctTree.cpp | 42 +++++----- Runtime/Collision/CAreaOctTree.hpp | 18 ++-- Runtime/MP1/CInGameGuiManager.cpp | 7 ++ Runtime/MP1/CInGameGuiManager.hpp | 1 + Runtime/MP1/CMFGame.cpp | 2 +- Runtime/MkCastTo.py | 1 + Runtime/World/CGameArea.cpp | 110 ++++++++++++++++--------- Runtime/World/CGameArea.hpp | 22 ++--- Runtime/World/CMakeLists.txt | 1 + Runtime/World/CScriptMidi.cpp | 89 ++++++++++++++++++++ Runtime/World/CScriptMidi.hpp | 33 ++++++++ Runtime/World/ScriptLoader.cpp | 12 ++- amuse | 2 +- visigen/VISIBuilder.cpp | 8 +- visigen/VISIBuilder.hpp | 3 +- visigen/VISIRenderer.cpp | 22 +++++ 28 files changed, 446 insertions(+), 112 deletions(-) create mode 100644 Runtime/World/CScriptMidi.cpp create mode 100644 Runtime/World/CScriptMidi.hpp diff --git a/DataSpec/DNACommon/AROTBuilder.cpp b/DataSpec/DNACommon/AROTBuilder.cpp index f6e9d685a..00f188dfe 100644 --- a/DataSpec/DNACommon/AROTBuilder.cpp +++ b/DataSpec/DNACommon/AROTBuilder.cpp @@ -70,6 +70,10 @@ void AROTBuilder::Node::nodeCount(size_t& sz, size_t& idxRefs, BitmapPool& bmpPo if (poolIdx > 65535) Log.report(logvisor::Fatal, "AROT bitmap exceeds 16-bit node addressing; area too complex"); + uint32_t childCount = AROTChildCounts[flags]; + nodeOff = curOff; + nodeSz = childCount * 2 + 4; + curOff += nodeSz; if (childNodes.size()) { for (int i=0 ; i < 1 + ((flags & 0x1) != 0) ; ++i) @@ -82,10 +86,6 @@ void AROTBuilder::Node::nodeCount(size_t& sz, size_t& idxRefs, BitmapPool& bmpPo } } } - uint32_t childCount = AROTChildCounts[flags]; - nodeOff = curOff; - nodeSz = childCount * 2 + 4; - curOff += nodeSz; idxRefs += childCount; } } diff --git a/DataSpec/DNAMP1/MLVL.cpp b/DataSpec/DNAMP1/MLVL.cpp index 5ca5c9d53..10a81ee3b 100644 --- a/DataSpec/DNAMP1/MLVL.cpp +++ b/DataSpec/DNAMP1/MLVL.cpp @@ -270,7 +270,8 @@ bool MLVL::Cook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPat { addedPaths.insert(path.hash()); urde::SObjectTag tag = g_curSpec->BuildTagFromPath(path, btok); - areaOut.deps.emplace_back(tag.id, tag.type); + if (tag.id != -1) + areaOut.deps.emplace_back(tag.id, tag.type); } } } @@ -308,12 +309,14 @@ bool MLVL::Cook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPat { addedPaths.insert(path.hash()); urde::SObjectTag tag = g_curSpec->BuildTagFromPath(path, btok); - areaOut.deps.emplace_back(tag.id, tag.type); + if (tag.id != -1) + areaOut.deps.emplace_back(tag.id, tag.type); } } urde::SObjectTag tag = g_curSpec->BuildTagFromPath(areaPath, btok); - areaOut.deps.emplace_back(tag.id, tag.type); + if (tag.id != -1) + areaOut.deps.emplace_back(tag.id, tag.type); } ++areaIdx; diff --git a/DataSpec/DNAMP1/MREA.cpp b/DataSpec/DNAMP1/MREA.cpp index 881e398d8..1aeafa69c 100644 --- a/DataSpec/DNAMP1/MREA.cpp +++ b/DataSpec/DNAMP1/MREA.cpp @@ -518,7 +518,7 @@ bool MREA::PCCook(const hecl::ProjectPath& outPath, } } if (!good) - secs.emplace_back(0, 0); + secs.emplace_back(4, 0); } /* PATH */ diff --git a/DataSpec/DNAMP1/ScriptObjects/Midi.hpp b/DataSpec/DNAMP1/ScriptObjects/Midi.hpp index 83eebf202..622c3909c 100644 --- a/DataSpec/DNAMP1/ScriptObjects/Midi.hpp +++ b/DataSpec/DNAMP1/ScriptObjects/Midi.hpp @@ -13,11 +13,11 @@ struct Midi : IScriptObject { DECL_YAML String<-1> name; - Value unknown1; + Value active; UniqueID32 song; - Value unknown2; - Value unknown3; - Value unknown4; + Value fadeInTime; + Value fadeOutTime; + Value volume; void nameIDs(PAKRouter& pakRouter) const { diff --git a/Editor/ProjectResourceFactoryBase.cpp b/Editor/ProjectResourceFactoryBase.cpp index fbd9f2310..1aa8eb39f 100644 --- a/Editor/ProjectResourceFactoryBase.cpp +++ b/Editor/ProjectResourceFactoryBase.cpp @@ -532,10 +532,19 @@ void ProjectResourceFactoryBase::AsyncTask::CookComplete() /* Ready for buffer transaction at this point */ u32 availSz = std::max(0, s32(fr.length()) - s32(x14_resOffset)); x14_resSize = std::min(x14_resSize, availSz); - x10_loadBuffer.reset(new u8[x14_resSize]); - m_bufTransaction = m_parent.m_clientProc.addBufferTransaction(m_cookedPath, - x10_loadBuffer.get(), - x14_resSize, x14_resOffset); + if (xc_targetDataRawPtr) + { + m_bufTransaction = m_parent.m_clientProc.addBufferTransaction(m_cookedPath, + xc_targetDataRawPtr, + x14_resSize, x14_resOffset); + } + else + { + x10_loadBuffer.reset(new u8[x14_resSize]); + m_bufTransaction = m_parent.m_clientProc.addBufferTransaction(m_cookedPath, + x10_loadBuffer.get(), + x14_resSize, x14_resOffset); + } } bool ProjectResourceFactoryBase::AsyncTask::AsyncPump() @@ -778,6 +787,17 @@ ProjectResourceFactoryBase::LoadResourcePartAsync(const urde::SObjectTag& tag, std::make_shared(*this, tag, target, size, off))).first->second; } +std::shared_ptr +ProjectResourceFactoryBase::LoadResourcePartAsync(const urde::SObjectTag& tag, u32 size, u32 off, u8* target) +{ + if ((tag.id & 0xffffffff) == 0xffffffff || !tag.id) + Log.report(logvisor::Fatal, "attempted to access null id"); + if (m_asyncLoadList.find(tag) != m_asyncLoadList.end()) + return {}; + return m_asyncLoadList.emplace(std::make_pair(tag, + std::make_shared(*this, tag, target, size, off))).first->second; +} + std::unique_ptr ProjectResourceFactoryBase::LoadResourceSync(const urde::SObjectTag& tag) { if ((tag.id & 0xffffffff) == 0xffffffff || !tag.id) @@ -986,6 +1006,13 @@ bool ProjectResourceFactoryBase::AsyncPumpTask( task.x0_tag.type.toString().c_str(), u32(task.x0_tag.id)); } + else if (task.xc_targetDataRawPtr) + { + /* Buffer only raw */ + Log.report(logvisor::Info, "async-loaded %.4s %08X", + task.x0_tag.type.toString().c_str(), + u32(task.x0_tag.id)); + } } it = m_asyncLoadList.erase(it); diff --git a/Editor/ProjectResourceFactoryBase.hpp b/Editor/ProjectResourceFactoryBase.hpp index 52074974c..b465cd042 100644 --- a/Editor/ProjectResourceFactoryBase.hpp +++ b/Editor/ProjectResourceFactoryBase.hpp @@ -27,6 +27,7 @@ public: SObjectTag x0_tag; //IDvdRequest* x8_dvdReq = nullptr; std::unique_ptr* xc_targetDataPtr = nullptr; + u8* xc_targetDataRawPtr = nullptr; IObj** xc_targetObjPtr = nullptr; std::unique_ptr x10_loadBuffer; u32 x14_resSize = UINT32_MAX; @@ -50,6 +51,11 @@ public: : m_parent(parent), x0_tag(tag), xc_targetDataPtr(&ptr), x14_resSize(size), x14_resOffset(off) {} + AsyncTask(ProjectResourceFactoryBase& parent, const SObjectTag& tag, + u8* ptr, u32 size, u32 off) + : m_parent(parent), x0_tag(tag), xc_targetDataRawPtr(ptr), x14_resSize(size), + x14_resOffset(off) {} + AsyncTask(ProjectResourceFactoryBase& parent, const SObjectTag& tag, IObj** ptr, const CVParamTransfer& xfer, CObjectReference* selfRef) : m_parent(parent), x0_tag(tag), xc_targetObjPtr(ptr), x18_cvXfer(xfer), m_selfRef(selfRef) {} @@ -131,6 +137,7 @@ public: u32 ResourceSize(const SObjectTag& tag); std::shared_ptr LoadResourceAsync(const urde::SObjectTag& tag, std::unique_ptr& target); std::shared_ptr LoadResourcePartAsync(const urde::SObjectTag& tag, u32 size, u32 off, std::unique_ptr& target); + std::shared_ptr LoadResourcePartAsync(const urde::SObjectTag& tag, u32 size, u32 off, u8* target); std::unique_ptr LoadResourceSync(const urde::SObjectTag& tag); std::unique_ptr LoadResourcePartSync(const urde::SObjectTag& tag, u32 size, u32 off); diff --git a/Editor/ProjectResourceFactoryMP1.cpp b/Editor/ProjectResourceFactoryMP1.cpp index 69c405558..7d875b8f9 100644 --- a/Editor/ProjectResourceFactoryMP1.cpp +++ b/Editor/ProjectResourceFactoryMP1.cpp @@ -28,6 +28,7 @@ #include "Runtime/CScannableObjectInfo.hpp" #include "Audio/CAudioGroupSet.hpp" #include "Audio/CSfxManager.hpp" +#include "Audio/CMidiManager.hpp" #include "Runtime/CDependencyGroup.hpp" #include "DataSpec/DNACommon/TXTR.hpp" #include "CSimplePool.hpp" @@ -109,6 +110,7 @@ ProjectResourceFactoryMP1::ProjectResourceFactoryMP1(hecl::ClientProcess& client m_factoryMgr.AddFactory(FOURCC('DCLN'), FFactoryFunc(FCollidableOBBTreeGroupFactory)); m_factoryMgr.AddFactory(FOURCC('DGRP'), FFactoryFunc(FDependencyGroupFactory)); m_factoryMgr.AddFactory(FOURCC('AGSC'), FMemFactoryFunc(FAudioGroupSetDataFactory)); + m_factoryMgr.AddFactory(FOURCC('CSNG'), FFactoryFunc(FMidiDataFactory)); m_factoryMgr.AddFactory(FOURCC('ATBL'), FFactoryFunc(FAudioTranslationTableFactory)); m_factoryMgr.AddFactory(FOURCC('STRG'), FFactoryFunc(FStringTableFactory)); m_factoryMgr.AddFactory(FOURCC('HINT'), FFactoryFunc(FHintFactory)); diff --git a/Runtime/Audio/CMidiManager.cpp b/Runtime/Audio/CMidiManager.cpp index f4397017a..f061dd5d1 100644 --- a/Runtime/Audio/CMidiManager.cpp +++ b/Runtime/Audio/CMidiManager.cpp @@ -3,9 +3,58 @@ namespace urde { +std::unordered_set CMidiManager::m_MidiWrappers = {}; + void CMidiManager::StopAll() { + for (auto it = m_MidiWrappers.begin() ; it != m_MidiWrappers.end() ;) + it = Stop(it, 0); +} +void CMidiManager::Stop(const CMidiHandle& handle, float fadeTime) +{ + handle->GetAudioSysHandle()->stopSong(fadeTime); + m_MidiWrappers.erase(handle); +} + +std::unordered_set::iterator +CMidiManager::Stop(std::unordered_set::iterator handle, float fadeTime) +{ + const CMidiHandle& h = *handle; + h->GetAudioSysHandle()->stopSong(fadeTime); + return m_MidiWrappers.erase(handle); +} + +CMidiHandle CMidiManager::Play(const CMidiData& data, float fadeTime, bool stopExisting, float volume) +{ + if (stopExisting) + for (auto it = m_MidiWrappers.begin() ; it != m_MidiWrappers.end() ;) + it = Stop(it, fadeTime); + + CMidiHandle handle = *m_MidiWrappers.insert(std::make_shared()).first; + handle->SetAudioSysHandle(CAudioSys::GetAmuseEngine().seqPlay( + data.GetGroupId(), data.GetSetupId(), data.GetArrData())); + handle->GetAudioSysHandle()->setVolume(volume, fadeTime); + handle->SetSongId(data.GetSetupId()); + return handle; +} + +CMidiManager::CMidiData::CMidiData(CInputStream& in) +{ + in.readUint32Big(); + x0_setupId = in.readUint32Big(); + x2_groupId = in.readUint32Big(); + x4_agscId = in.readUint32Big(); + u32 length = in.readUint32Big(); + x8_arrData.reset(new u8[length]); + in.readUBytesToBuf(x8_arrData.get(), length); +} + +CFactoryFnReturn FMidiDataFactory(const SObjectTag& tag, CInputStream& in, + const CVParamTransfer& parms, + CObjectReference* selfRef) +{ + return TToken::GetIObjObjectFor(std::make_unique(in)); } } diff --git a/Runtime/Audio/CMidiManager.hpp b/Runtime/Audio/CMidiManager.hpp index cb8b2853a..81b2981f1 100644 --- a/Runtime/Audio/CMidiManager.hpp +++ b/Runtime/Audio/CMidiManager.hpp @@ -1,15 +1,62 @@ #ifndef __URDE_CMIDIMANAGER_HPP__ #define __URDE_CMIDIMANAGER_HPP__ +#include "CSfxManager.hpp" + namespace urde { class CMidiManager { public: + class CMidiData + { + u16 x0_setupId; + u16 x2_groupId; + ResId x4_agscId; + std::unique_ptr x8_arrData; + public: + u16 GetSetupId() const { return x0_setupId; } + u16 GetGroupId() const { return x2_groupId; } + ResId GetAGSCAssetId() const { return x4_agscId; } + const u8* GetArrData() const { return x8_arrData.get(); } + CMidiData(CInputStream& in); + }; + + class CMidiWrapper + { + std::shared_ptr x0_sequencer; + //CSfxHandle x4_handle; + u16 x8_songId; + bool xa_available = true; + public: + const std::shared_ptr& GetAudioSysHandle() const { return x0_sequencer; } + void SetAudioSysHandle(const std::shared_ptr& sequencer) { x0_sequencer = sequencer; } + //const CSfxHandle& GetManagerHandle() const { return x4_handle; } + //void SetMidiHandle(const CSfxHandle& handle) { x4_handle = handle; } + bool IsAvailable() const { return xa_available; } + void SetAvailable(bool available) { xa_available = available; } + u16 GetSongId() const { return x8_songId; } + void SetSongId(u16 songId) { x8_songId = songId; } + }; + using CMidiHandle = std::shared_ptr; + static void StopAll(); + static void Stop(const CMidiHandle& handle, float fadeTime); + static std::unordered_set::iterator + Stop(std::unordered_set::iterator handle, float fadeTime); + static CMidiHandle Play(const CMidiData& data, float fadeTime, bool stopExisting, float volume); + +private: + static std::unordered_set m_MidiWrappers; }; +CFactoryFnReturn FMidiDataFactory(const SObjectTag& tag, CInputStream& in, + const CVParamTransfer& parms, + CObjectReference* selfRef); + +using CMidiHandle = CMidiManager::CMidiHandle; + } #endif // __URDE_CMIDIMANAGER_HPP__ diff --git a/Runtime/CInGameTweakManagerBase.hpp b/Runtime/CInGameTweakManagerBase.hpp index 93e35522a..2c9d6b3bb 100644 --- a/Runtime/CInGameTweakManagerBase.hpp +++ b/Runtime/CInGameTweakManagerBase.hpp @@ -16,14 +16,14 @@ public: { float x0_fadeIn, x4_fadeOut, x8_volume; std::string xc_fileName; - u32 x1c_handle; + ResId x1c_res; Audio(float fadeIn, float fadeOut, float vol, const std::string& fileName, u32 handle) - : x0_fadeIn(fadeIn), x4_fadeOut(fadeOut), x8_volume(vol), xc_fileName(fileName), x1c_handle(handle) {} + : x0_fadeIn(fadeIn), x4_fadeOut(fadeOut), x8_volume(vol), xc_fileName(fileName), x1c_res(handle) {} float GetFadeIn() const { return x0_fadeIn; } float GetFadeOut() const { return x4_fadeOut; } float GetVolume() const { return x8_volume; } const std::string& GetFileName() const { return xc_fileName; } - u32 GetHandle() const { return x1c_handle; } + ResId GetResId() const { return x1c_res; } static Audio None() { return Audio{0.f, 0.f, 0.f, "", 0}; } }; enum class EType diff --git a/Runtime/CStateManager.cpp b/Runtime/CStateManager.cpp index 4519c06a4..4cd932cdf 100644 --- a/Runtime/CStateManager.cpp +++ b/Runtime/CStateManager.cpp @@ -703,14 +703,14 @@ void CStateManager::InitializeState(ResId mlvlId, TAreaId aid, ResId mreaId) bool hadRandom = x900_activeRandom != nullptr; SetActiveRandomToDefault(); - if (xb3c_initPhase == InitPhase::LoadWorld) + if (xb3c_initPhase == EInitPhase::LoadWorld) { CreateStandardGameObjects(); x850_world.reset(new CWorld(*g_SimplePool, *g_ResFactory, mlvlId)); - xb3c_initPhase = InitPhase::LoadFirstArea; + xb3c_initPhase = EInitPhase::LoadFirstArea; } - if (xb3c_initPhase == InitPhase::LoadFirstArea) + if (xb3c_initPhase == EInitPhase::LoadFirstArea) { if (!x8f0_shadowTex.IsLoaded()) return; @@ -725,7 +725,7 @@ void CStateManager::InitializeState(ResId mlvlId, TAreaId aid, ResId mreaId) area->StartStreamIn(*this); return; } - xb3c_initPhase = InitPhase::Done; + xb3c_initPhase = EInitPhase::Done; } SetCurrentAreaId(x8cc_nextAreaId); diff --git a/Runtime/CStateManager.hpp b/Runtime/CStateManager.hpp index 6a475e80b..f9e827200 100644 --- a/Runtime/CStateManager.hpp +++ b/Runtime/CStateManager.hpp @@ -147,12 +147,12 @@ class CStateManager std::set xab4_uniqueInstanceNames; - enum class InitPhase + enum class EInitPhase { LoadWorld, LoadFirstArea, Done - } xb3c_initPhase = InitPhase::LoadWorld; + } xb3c_initPhase = EInitPhase::LoadWorld; CFinalInput xb54_finalInput; CCameraFilterPass xb84_camFilterPasses[9]; diff --git a/Runtime/Collision/CAreaOctTree.cpp b/Runtime/Collision/CAreaOctTree.cpp index 569801ac6..fae0deffc 100644 --- a/Runtime/Collision/CAreaOctTree.cpp +++ b/Runtime/Collision/CAreaOctTree.cpp @@ -99,10 +99,10 @@ void CAreaOctTree::SwapTreeNode(u8* ptr, Node::ETreeType type) } } -CAreaOctTree::CAreaOctTree(const zeus::CAABox& aabb, Node::ETreeType treeType, u8* buf, std::unique_ptr&& treeBuf, - u32 matCount, u32* materials, u8* vertMats, u8* edgeMats, u8* polyMats, - u32 edgeCount, CCollisionEdge* edges, u32 polyCount, u16* polyEdges, - u32 vertCount, zeus::CVector3f* verts) +CAreaOctTree::CAreaOctTree(const zeus::CAABox& aabb, Node::ETreeType treeType, const u8* buf, std::unique_ptr&& treeBuf, + u32 matCount, const u32* materials, const u8* vertMats, const u8* edgeMats, const u8* polyMats, + u32 edgeCount, const CCollisionEdge* edges, u32 polyCount, const u16* polyEdges, + u32 vertCount, const zeus::CVector3f* verts) : x0_aabb(aabb), x18_treeType(treeType), x1c_buf(buf), x20_treeBuf(std::move(treeBuf)), x24_matCount(matCount), x2c_vertMats(vertMats), x30_edgeMats(edgeMats), x34_polyMats(polyMats), x38_edgeCount(edgeCount), @@ -140,7 +140,7 @@ CAreaOctTree::CAreaOctTree(const zeus::CAABox& aabb, Node::ETreeType treeType, u } } -std::unique_ptr CAreaOctTree::MakeFromMemory(void* buf, unsigned int size) +std::unique_ptr CAreaOctTree::MakeFromMemory(const void* buf, unsigned int size) { athena::io::MemoryReader r(buf, size); r.readUint32Big(); @@ -149,48 +149,48 @@ std::unique_ptr CAreaOctTree::MakeFromMemory(void* buf, unsigned i aabb.readBoundingBoxBig(r); Node::ETreeType nodeType = Node::ETreeType(r.readUint32Big()); u32 treeSize = r.readUint32Big(); - u8* cur = reinterpret_cast(buf) + r.position(); + const u8* cur = reinterpret_cast(buf) + r.position(); std::unique_ptr treeBuf(new u8[treeSize]); memmove(treeBuf.get(), cur, treeSize); cur += treeSize; - u32 matCount = hecl::SBig(*reinterpret_cast(cur)); + u32 matCount = hecl::SBig(*reinterpret_cast(cur)); cur += 4; - u32* matBuf = reinterpret_cast(cur); + const u32* matBuf = reinterpret_cast(cur); cur += 4 * matCount; - u32 vertMatsCount = hecl::SBig(*reinterpret_cast(cur)); + u32 vertMatsCount = hecl::SBig(*reinterpret_cast(cur)); cur += 4; - u8* vertMatsBuf = cur; + const u8* vertMatsBuf = cur; cur += vertMatsCount; - u32 edgeMatsCount = hecl::SBig(*reinterpret_cast(cur)); + u32 edgeMatsCount = hecl::SBig(*reinterpret_cast(cur)); cur += 4; - u8* edgeMatsBuf = cur; + const u8* edgeMatsBuf = cur; cur += edgeMatsCount; - u32 polyMatsCount = hecl::SBig(*reinterpret_cast(cur)); + u32 polyMatsCount = hecl::SBig(*reinterpret_cast(cur)); cur += 4; - u8* polyMatsBuf = cur; + const u8* polyMatsBuf = cur; cur += polyMatsCount; - u32 edgeCount = hecl::SBig(*reinterpret_cast(cur)); + u32 edgeCount = hecl::SBig(*reinterpret_cast(cur)); cur += 4; - CCollisionEdge* edgeBuf = reinterpret_cast(cur); + const CCollisionEdge* edgeBuf = reinterpret_cast(cur); cur += edgeCount * sizeof(edgeCount); - u32 polyCount = hecl::SBig(*reinterpret_cast(cur)); + u32 polyCount = hecl::SBig(*reinterpret_cast(cur)); cur += 4; - u16* polyBuf = reinterpret_cast(cur); + const u16* polyBuf = reinterpret_cast(cur); cur += polyCount * 2; - u32 vertCount = hecl::SBig(*reinterpret_cast(cur)); + u32 vertCount = hecl::SBig(*reinterpret_cast(cur)); cur += 4; - zeus::CVector3f* vertBuf = reinterpret_cast(cur); + const zeus::CVector3f* vertBuf = reinterpret_cast(cur); cur += polyCount * 2; - return std::make_unique(aabb, nodeType, reinterpret_cast(buf), std::move(treeBuf), + return std::make_unique(aabb, nodeType, reinterpret_cast(buf), std::move(treeBuf), matCount, matBuf, vertMatsBuf, edgeMatsBuf, polyMatsBuf, edgeCount, edgeBuf, polyCount, polyBuf, vertCount, vertBuf); } diff --git a/Runtime/Collision/CAreaOctTree.hpp b/Runtime/Collision/CAreaOctTree.hpp index cde3a28e9..c051fd9da 100644 --- a/Runtime/Collision/CAreaOctTree.hpp +++ b/Runtime/Collision/CAreaOctTree.hpp @@ -94,13 +94,13 @@ public: zeus::CAABox x0_aabb; Node::ETreeType x18_treeType; - u8* x1c_buf; + const u8* x1c_buf; std::unique_ptr x20_treeBuf; u32 x24_matCount; std::vector x28_materials; - u8* x2c_vertMats; - u8* x30_edgeMats; - u8* x34_polyMats; + const u8* x2c_vertMats; + const u8* x30_edgeMats; + const u8* x34_polyMats; u32 x38_edgeCount; std::vector x3c_edges; u32 x40_polyCount; @@ -111,10 +111,10 @@ public: void SwapTreeNode(u8* ptr, Node::ETreeType type); public: - CAreaOctTree(const zeus::CAABox& aabb, Node::ETreeType treeType, u8* buf, std::unique_ptr&& treeBuf, - u32 matCount, u32* materials, u8* vertMats, u8* edgeMats, u8* polyMats, - u32 edgeCount, CCollisionEdge* edges, u32 polyCount, u16* polyEdges, - u32 vertCount, zeus::CVector3f* verts); + CAreaOctTree(const zeus::CAABox& aabb, Node::ETreeType treeType, const u8* buf, std::unique_ptr&& treeBuf, + u32 matCount, const u32* materials, const u8* vertMats, const u8* edgeMats, const u8* polyMats, + u32 edgeCount, const CCollisionEdge* edges, u32 polyCount, const u16* polyEdges, + u32 vertCount, const zeus::CVector3f* verts); Node GetRootNode() const { return Node(x20_treeBuf.get(), x0_aabb, *this, x18_treeType); } const u8* GetTreeMemory() const { return x20_treeBuf.get(); } @@ -129,7 +129,7 @@ public: const u16* GetTriangleVertexIndices(u16 idx) const; const u16* GetTriangleEdgeIndices(u16 idx) const; - static std::unique_ptr MakeFromMemory(void* buf, unsigned int size); + static std::unique_ptr MakeFromMemory(const void* buf, unsigned int size); }; } diff --git a/Runtime/MP1/CInGameGuiManager.cpp b/Runtime/MP1/CInGameGuiManager.cpp index e1ab087ed..5107a39f2 100644 --- a/Runtime/MP1/CInGameGuiManager.cpp +++ b/Runtime/MP1/CInGameGuiManager.cpp @@ -353,5 +353,12 @@ bool CInGameGuiManager::GetIsGameDraw() const return x3c_pauseScreen->GetX50_25(); } +std::string CInGameGuiManager::GetIdentifierForMidiEvent(ResId world, ResId area, + const std::string& midiObj) +{ + return hecl::Format("World %8.8x Area %8.8x MidiObject: %s", + u32(world), u32(area), midiObj.c_str()); +} + } } diff --git a/Runtime/MP1/CInGameGuiManager.hpp b/Runtime/MP1/CInGameGuiManager.hpp index b4524e541..fe62674a0 100644 --- a/Runtime/MP1/CInGameGuiManager.hpp +++ b/Runtime/MP1/CInGameGuiManager.hpp @@ -135,6 +135,7 @@ public: bool IsInGame() const { return x1c0_nextState >= EInGameGuiState::Zero && x1c0_nextState <= EInGameGuiState::InGame; } bool IsInSaveUI() const { return x1f8_27_inSaveUI; } bool GetIsGameDraw() const; + static std::string GetIdentifierForMidiEvent(ResId world, ResId area, const std::string& midiObj); }; } diff --git a/Runtime/MP1/CMFGame.cpp b/Runtime/MP1/CMFGame.cpp index 54866b999..9c884ab28 100644 --- a/Runtime/MP1/CMFGame.cpp +++ b/Runtime/MP1/CMFGame.cpp @@ -379,7 +379,7 @@ CIOWin::EMessageReturn CMFGameLoader::OnMessage(const CArchitectureMessage& msg, wldState.GetLayerState()); } - if (x14_stateMgr->xb3c_initPhase != CStateManager::InitPhase::Done) + if (x14_stateMgr->xb3c_initPhase != CStateManager::EInitPhase::Done) { CWorldState& wldState = g_GameState->CurrentWorldState(); x14_stateMgr->InitializeState(wldState.GetWorldAssetId(), diff --git a/Runtime/MkCastTo.py b/Runtime/MkCastTo.py index 2787930e6..ee1537d01 100644 --- a/Runtime/MkCastTo.py +++ b/Runtime/MkCastTo.py @@ -53,6 +53,7 @@ CENTITY_TYPES = ( ('CScriptPointOfInterest', 'World/CScriptPointOfInterest.hpp'), ('CScriptRoomAcoustics', 'World/CScriptRoomAcoustics.hpp'), ('CScriptSound', 'World/CScriptSound.hpp'), + ('CScriptMidi', 'World/CScriptMidi.hpp'), ('CScriptSpawnPoint', 'World/CScriptSpawnPoint.hpp'), ('CScriptSpecialFunction', 'World/CScriptSpecialFunction.hpp'), ('CScriptSpiderBallAttractionSurface', 'World/CScriptSpiderBallAttractionSurface.hpp'), diff --git a/Runtime/World/CGameArea.cpp b/Runtime/World/CGameArea.cpp index 5c1ef73fd..f7ab9d127 100644 --- a/Runtime/World/CGameArea.cpp +++ b/Runtime/World/CGameArea.cpp @@ -9,27 +9,29 @@ namespace urde { -CAreaRenderOctTree::CAreaRenderOctTree(std::unique_ptr&& buf) -: x0_buf(std::move(buf)) +static logvisor::Module Log("CGameArea"); + +CAreaRenderOctTree::CAreaRenderOctTree(const u8* buf) +: x0_buf(buf) { - athena::io::MemoryReader r(x0_buf.get() + 8, INT32_MAX); + athena::io::MemoryReader r(x0_buf + 8, INT32_MAX); x8_bitmapCount = r.readUint32Big(); xc_meshCount = r.readUint32Big(); x10_nodeCount = r.readUint32Big(); x14_bitmapWordCount = (xc_meshCount + 31) / 32; x18_aabb.readBoundingBoxBig(r); - x30_bitmaps = reinterpret_cast(x0_buf.get() + 64); + x30_bitmaps = reinterpret_cast(x0_buf + 64); u32 wc = x14_bitmapWordCount * x8_bitmapCount; for (u32 i=0 ; i(x30_bitmaps)[i] = hecl::SBig(x30_bitmaps[i]); x34_indirectionTable = x30_bitmaps + wc; - x38_entries = reinterpret_cast(x34_indirectionTable) + x10_nodeCount; + x38_entries = reinterpret_cast(x34_indirectionTable + x10_nodeCount); for (u32 i=0 ; i(x38_entries + x34_indirectionTable[i]); + const_cast(x34_indirectionTable)[i] = hecl::SBig(x34_indirectionTable[i]); + Node* n = reinterpret_cast(const_cast(x38_entries) + x34_indirectionTable[i]); n->x0_bitmapIdx = hecl::SBig(n->x0_bitmapIdx); n->x2_flags = hecl::SBig(n->x2_flags); if (n->x2_flags) @@ -596,42 +598,42 @@ bool CGameArea::StartStreamingMainArea() switch (xf4_phase) { - case Phase::LoadHeader: + case EPhase::LoadHeader: { x110_mreaSecBufs.reserve(3); AllocNewAreaData(0, 96); x12c_postConstructed.reset(new CPostConstructed()); - xf4_phase = Phase::LoadSecSizes; + xf4_phase = EPhase::LoadSecSizes; break; } - case Phase::LoadSecSizes: + case EPhase::LoadSecSizes: { CullDeadAreaRequests(); if (xf8_loadTransactions.size()) break; MREAHeader header = VerifyHeader(); AllocNewAreaData(x110_mreaSecBufs[0].second, ROUND_UP_32(header.secCount * 4)); - xf4_phase = Phase::ReserveSections; + xf4_phase = EPhase::ReserveSections; break; } - case Phase::ReserveSections: + case EPhase::ReserveSections: { CullDeadAreaRequests(); if (xf8_loadTransactions.size()) break; - x110_mreaSecBufs.reserve(GetNumPartSizes() + 2); + //x110_mreaSecBufs.reserve(GetNumPartSizes() + 2); x124_secCount = 0; x128_mreaDataOffset = x110_mreaSecBufs[0].second + x110_mreaSecBufs[1].second; - xf4_phase = Phase::LoadDataSections; + xf4_phase = EPhase::LoadDataSections; break; } - case Phase::LoadDataSections: + case EPhase::LoadDataSections: { CullDeadAreaRequests(); u32 totalSz = 0; u32 secCount = GetNumPartSizes(); - for (u32 i=2 ; i(x110_mreaSecBufs[1].first.get())[i]); AllocNewAreaData(x128_mreaDataOffset, totalSz); @@ -641,17 +643,17 @@ bool CGameArea::StartStreamingMainArea() m_resolvedBufs.emplace_back(x110_mreaSecBufs[1].first.get(), x110_mreaSecBufs[1].second); u32 curOff = 0; - for (u32 i=2 ; i(x110_mreaSecBufs[1].first.get())[i]); m_resolvedBufs.emplace_back(x110_mreaSecBufs[2].first.get() + curOff, size); curOff += size; } - xf4_phase = Phase::WaitForFinish; + xf4_phase = EPhase::WaitForFinish; break; } - case Phase::WaitForFinish: + case EPhase::WaitForFinish: { CullDeadAreaRequests(); if (xf8_loadTransactions.size()) @@ -684,7 +686,7 @@ void CGameArea::AllocNewAreaData(int offset, int size) xf8_loadTransactions.push_back( static_cast(g_ResFactory)-> LoadResourcePartAsync(SObjectTag{FOURCC('MREA'), x84_mrea}, size, offset, - x110_mreaSecBufs.back().first)); + x110_mreaSecBufs.back().first.get())); } bool CGameArea::Invalidate(CStateManager& mgr) @@ -707,6 +709,32 @@ void CGameArea::CullDeadAreaRequests() void CGameArea::StartStreamIn(CStateManager& mgr) { + if (xf0_24_postConstructed || xf0_27_paused) + return; + + VerifyTokenList(mgr); + + if (!xf0_26_tokensReady) + { + u32 notLoaded = 0; + for (CToken& tok : xdc_tokens) + { + tok.Lock(); + if (!tok.IsLoaded()) + ++notLoaded; + } + if (notLoaded) + return; + xf0_26_tokensReady = true; + } + + StartStreamingMainArea(); + if (xf4_phase != EPhase::WaitForFinish) + return; + CullDeadAreaRequests(); + if (xf8_loadTransactions.size()) + return; + Validate(mgr); } void CGameArea::Validate(CStateManager& mgr) @@ -774,7 +802,7 @@ void CGameArea::LoadScriptObjects(CStateManager& mgr) mgr.InitScriptObjects(objIds); } -std::pair CGameArea::GetLayerScriptBuffer(int layer) +std::pair CGameArea::GetLayerScriptBuffer(int layer) { if (!xf0_24_postConstructed) return {}; @@ -785,32 +813,35 @@ void CGameArea::PostConstructArea() { MREAHeader header = VerifyHeader(); - auto secIt = x110_mreaSecBufs.begin() + 2; + auto secIt = m_resolvedBufs.begin() + 2; + + /* Materials */ + ++secIt; + + u32 sec = 3; /* Models */ - if (header.modelCount) + for (u32 i=0 ; i((secIt+6)->first.get())); - secIt += 7 + surfCount; - } + u32 surfCount = hecl::SBig(*reinterpret_cast((secIt+4)->first)); + secIt += 5 + surfCount; + sec += 5 + surfCount; } /* Render octree */ if (header.version == 15 && header.arotSecIdx != -1) { - x12c_postConstructed->xc_octTree.emplace(std::move(secIt->first)); + x12c_postConstructed->xc_octTree.emplace(secIt->first); ++secIt; } /* Scriptable layer section */ - x12c_postConstructed->x10c8_sclyBuf = std::move(secIt->first); + x12c_postConstructed->x10c8_sclyBuf = secIt->first; x12c_postConstructed->x10d0_sclySize = secIt->second; ++secIt; /* Collision section */ - std::unique_ptr collision = CAreaOctTree::MakeFromMemory(secIt->first.get(), secIt->second); + std::unique_ptr collision = CAreaOctTree::MakeFromMemory(secIt->first, secIt->second); if (collision) { x12c_postConstructed->x0_collision = std::move(collision); @@ -824,7 +855,7 @@ void CGameArea::PostConstructArea() /* Lights section */ if (header.version > 6) { - athena::io::MemoryReader r(secIt->first.get(), secIt->second); + athena::io::MemoryReader r(secIt->first, secIt->second); u32 magic = r.readUint32Big(); if (magic == 0xBABEDEAD) { @@ -855,7 +886,7 @@ void CGameArea::PostConstructArea() /* PVS section */ if (header.version > 7) { - athena::io::MemoryReader r(secIt->first.get(), secIt->second); + athena::io::MemoryReader r(secIt->first, secIt->second); u32 magic = r.readUint32Big(); if (magic == 'VISI') { @@ -864,7 +895,7 @@ void CGameArea::PostConstructArea() { x12c_postConstructed->x1108_29_ = r.readBool(); x12c_postConstructed->x1108_30_ = r.readBool(); - x12c_postConstructed->xa0_pvs = std::make_unique(secIt->first.get() + r.position(), + x12c_postConstructed->xa0_pvs = std::make_unique(secIt->first + r.position(), secIt->second - r.position()); } } @@ -875,7 +906,7 @@ void CGameArea::PostConstructArea() /* Pathfinding section */ if (header.version > 9) { - athena::io::MemoryReader r(secIt->first.get(), secIt->second); + athena::io::MemoryReader r(secIt->first, secIt->second); ResId pathId = r.readUint32Big(); x12c_postConstructed->x10ac_path = g_SimplePool->GetObj(SObjectTag{FOURCC('PATH'), pathId}); ++secIt; @@ -889,7 +920,7 @@ void CGameArea::PostConstructArea() /* Resolve layer pointers */ if (x12c_postConstructed->x10c8_sclyBuf) { - athena::io::MemoryReader r(x12c_postConstructed->x10c8_sclyBuf.get(), x12c_postConstructed->x10d0_sclySize); + athena::io::MemoryReader r(x12c_postConstructed->x10c8_sclyBuf, x12c_postConstructed->x10d0_sclySize); u32 magic = r.readUint32Big(); if (magic == 'SCLY') { @@ -898,7 +929,7 @@ void CGameArea::PostConstructArea() x12c_postConstructed->x110c_layerPtrs.resize(layerCount); for (u32 l=0 ; lx110c_layerPtrs[l].second = r.readUint32Big(); - u8* ptr = x12c_postConstructed->x10c8_sclyBuf.get() + r.position(); + const u8* ptr = x12c_postConstructed->x10c8_sclyBuf + r.position(); for (u32 l=0 ; lx110c_layerPtrs[l].first = ptr; @@ -967,6 +998,9 @@ CGameArea::MREAHeader CGameArea::VerifyHeader() const MREAHeader header; athena::io::MemoryReader r(x110_mreaSecBufs[0].first.get() + 4, INT32_MAX); u32 version = r.readUint32Big(); + if (!(version & 0x10000)) + Log.report(logvisor::Fatal, "Attempted to load non-URDE MREA"); + version &= ~0x10000; header.version = (version >= 12 && version <= 15) ? version : 0; if (!header.version) return {}; diff --git a/Runtime/World/CGameArea.hpp b/Runtime/World/CGameArea.hpp index 753e7f916..04c6ab2a8 100644 --- a/Runtime/World/CGameArea.hpp +++ b/Runtime/World/CGameArea.hpp @@ -61,17 +61,17 @@ struct CAreaRenderOctTree const zeus::CAABox& testAABB) const; }; - std::unique_ptr x0_buf; + const u8* x0_buf; u32 x8_bitmapCount; u32 xc_meshCount; u32 x10_nodeCount; u32 x14_bitmapWordCount; zeus::CAABox x18_aabb; - u32* x30_bitmaps; - u32* x34_indirectionTable; - u8* x38_entries; + const u32* x30_bitmaps; + const u32* x34_indirectionTable; + const u8* x38_entries; - CAreaRenderOctTree(std::unique_ptr&& buf); + CAreaRenderOctTree(const u8* buf); void FindOverlappingModels(std::vector& out, const zeus::CAABox& testAABB) const; }; @@ -110,14 +110,14 @@ class CGameArea : public IGameArea u8 _dummy = 0; }; - enum class Phase + enum class EPhase { LoadHeader, LoadSecSizes, ReserveSections, LoadDataSections, WaitForFinish - } xf4_phase = Phase::LoadHeader; + } xf4_phase = EPhase::LoadHeader; std::list> xf8_loadTransactions; @@ -187,7 +187,7 @@ public: u32 x10bc_ = 0; std::unique_ptr x10c0_areaObjs; std::unique_ptr x10c4_areaFog; - std::unique_ptr x10c8_sclyBuf; + const u8* x10c8_sclyBuf = nullptr; u32 x10d0_sclySize = 0; u32 x10d4_ = 0; const CScriptAreaAttributes* x10d8_areaAttributes = nullptr; @@ -213,7 +213,7 @@ public: }; u8 _dummy = 0; }; - std::vector> x110c_layerPtrs; + std::vector> x110c_layerPtrs; float x111c_thermalCurrent = 0.f; float x1120_thermalSpeed = 0.f; float x1124_thermalTarget = 0.f; @@ -226,7 +226,7 @@ public: }; private: std::vector, int>> x110_mreaSecBufs; - std::vector> m_resolvedBufs; + std::vector> m_resolvedBufs; u32 x124_secCount = 0; u32 x128_mreaDataOffset = 0; std::unique_ptr x12c_postConstructed; @@ -303,7 +303,7 @@ public: void StartStreamIn(CStateManager& mgr); void Validate(CStateManager& mgr); void LoadScriptObjects(CStateManager& mgr); - std::pair GetLayerScriptBuffer(int layer); + std::pair GetLayerScriptBuffer(int layer); void PostConstructArea(); void FillInStaticGeometry(); void VerifyTokenList(CStateManager& stateMgr); diff --git a/Runtime/World/CMakeLists.txt b/Runtime/World/CMakeLists.txt index 196fc022a..dd6db68da 100644 --- a/Runtime/World/CMakeLists.txt +++ b/Runtime/World/CMakeLists.txt @@ -74,6 +74,7 @@ set(WORLD_SOURCES CScriptRoomAcoustics.hpp CScriptRoomAcoustics.cpp CScriptColorModulate.hpp CScriptColorModulate.cpp CScriptStreamedMusic.hpp CScriptStreamedMusic.cpp + CScriptMidi.hpp CScriptMidi.cpp CRepulsor.hpp CRepulsor.cpp CScriptGunTurret.hpp CScriptGunTurret.cpp CScriptCameraPitchVolume.hpp CScriptCameraPitchVolume.cpp diff --git a/Runtime/World/CScriptMidi.cpp b/Runtime/World/CScriptMidi.cpp new file mode 100644 index 000000000..f24dc1f68 --- /dev/null +++ b/Runtime/World/CScriptMidi.cpp @@ -0,0 +1,89 @@ +#include "CScriptMidi.hpp" +#include "TCastTo.hpp" +#include "CSimplePool.hpp" +#include "GameGlobalObjects.hpp" +#include "CStateManager.hpp" +#include "MP1/CInGameGuiManager.hpp" +#include "CInGameTweakManagerBase.hpp" + +namespace urde +{ + +CScriptMidi::CScriptMidi(TUniqueId id, const CEntityInfo& info, const std::string& name, + bool active, ResId csng, float fadeIn, float fadeOut, s32 volume) +: CEntity(id, info, active, name), x40_fadeInTime(fadeIn), x44_fadeOutTime(fadeOut), + x48_volume(volume) +{ + x34_song = g_SimplePool->GetObj(SObjectTag{FOURCC('CSNG'), csng}); +} + +void CScriptMidi::StopInternal(float fadeTime) +{ + if (x3c_handle) + { + CMidiManager::Stop(x3c_handle, fadeTime); + x3c_handle.reset(); + } +} + +void CScriptMidi::Stop(CStateManager& mgr, float fadeTime) +{ + const CWorld* wld = mgr.GetWorld(); + const CGameArea* area = wld->GetAreaAlways(x4_areaId); + std::string twkName = MP1::CInGameGuiManager::GetIdentifierForMidiEvent(wld->IGetWorldAssetId(), + area->GetAreaAssetId(), + x10_name); + if (g_TweakManager->HasTweakValue(twkName)) + { + const CTweakValue::Audio& audio = g_TweakManager->GetTweakValue(twkName)->GetAudio(); + fadeTime = audio.GetFadeOut(); + } + + StopInternal(fadeTime); +} + +void CScriptMidi::Play(CStateManager& mgr, float fadeTime) +{ + u32 volume = x48_volume; + const CWorld* wld = mgr.GetWorld(); + const CGameArea* area = wld->GetAreaAlways(x4_areaId); + std::string twkName = MP1::CInGameGuiManager::GetIdentifierForMidiEvent(wld->IGetWorldAssetId(), + area->GetAreaAssetId(), + x10_name); + if (g_TweakManager->HasTweakValue(twkName)) + { + const CTweakValue::Audio& audio = g_TweakManager->GetTweakValue(twkName)->GetAudio(); + x34_song = g_SimplePool->GetObj(SObjectTag{FOURCC('CSNG'), audio.GetResId()}); + fadeTime = audio.GetFadeIn(); + volume = audio.GetVolume() * 127.f; + } + + x3c_handle = CMidiManager::Play(*x34_song, fadeTime, false, volume / 127.f); +} + +void CScriptMidi::Accept(IVisitor& visitor) +{ + visitor.Visit(this); +} + +void CScriptMidi::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId objId, CStateManager& stateMgr) +{ + CEntity::AcceptScriptMsg(msg, objId, stateMgr); + switch (msg) + { + case EScriptObjectMessage::Play: + if (GetActive()) + Play(stateMgr, x40_fadeInTime); + break; + case EScriptObjectMessage::Stop: + if (GetActive()) + Stop(stateMgr, x44_fadeOutTime); + break; + case EScriptObjectMessage::Deactivate: + StopInternal(0.f); + break; + default: break; + } +} + +} diff --git a/Runtime/World/CScriptMidi.hpp b/Runtime/World/CScriptMidi.hpp new file mode 100644 index 000000000..93771f432 --- /dev/null +++ b/Runtime/World/CScriptMidi.hpp @@ -0,0 +1,33 @@ +#ifndef __URDE_CSCRIPTMIDI_HPP__ +#define __URDE_CSCRIPTMIDI_HPP__ + +#include "CEntity.hpp" +#include "CToken.hpp" +#include "Audio/CMidiManager.hpp" + +namespace urde +{ + +class CScriptMidi : public CEntity +{ + TToken x34_song; + CMidiHandle x3c_handle; + float x40_fadeInTime; + float x44_fadeOutTime; + u16 x48_volume; + + void StopInternal(float fadeTime); + +public: + CScriptMidi(TUniqueId id, const CEntityInfo& info, const std::string& name, + bool active, ResId csng, float, float, s32); + + void Stop(CStateManager& mgr, float fadeTime); + void Play(CStateManager& mgr, float fadeTime); + void Accept(IVisitor& visitor); + void AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId objId, CStateManager& stateMgr); +}; + +} + +#endif // __URDE_CSCRIPTSTREAMEDMUSIC_HPP__ diff --git a/Runtime/World/ScriptLoader.cpp b/Runtime/World/ScriptLoader.cpp index e357adcd9..db565e2b5 100644 --- a/Runtime/World/ScriptLoader.cpp +++ b/Runtime/World/ScriptLoader.cpp @@ -64,6 +64,7 @@ #include "MP1/World/CActorContraption.hpp" #include "CScriptShadowProjector.hpp" #include "CScriptStreamedMusic.hpp" +#include "CScriptMidi.hpp" #include "CScriptRoomAcoustics.hpp" #include "CPatternedInfo.hpp" #include "CSimplePool.hpp" @@ -1916,7 +1917,16 @@ CEntity* ScriptLoader::LoadThardusRockProjectile(CStateManager& mgr, CInputStrea CEntity* ScriptLoader::LoadMidi(CStateManager& mgr, CInputStream& in, int propCount, const CEntityInfo& info) { - return nullptr; + if (!EnsurePropertyCount(propCount, 6, "Midi")) + return nullptr; + + std::string name = mgr.HashInstanceName(in); + bool active = in.readBool(); + u32 csng = in.readUint32Big(); + float fadeIn = in.readFloatBig(); + float fadeOut = in.readFloatBig(); + u32 vol = in.readUint32Big(); + return new CScriptMidi(mgr.AllocateUniqueId(), info, name, active, csng, fadeIn, fadeOut, vol); } CEntity* ScriptLoader::LoadStreamedAudio(CStateManager& mgr, CInputStream& in, int propCount, const CEntityInfo& info) diff --git a/amuse b/amuse index 5c8fa2e8a..a23af1634 160000 --- a/amuse +++ b/amuse @@ -1 +1 @@ -Subproject commit 5c8fa2e8ab76cb95dad7a6add9efd8ecb9bfbbfe +Subproject commit a23af16349383be647494e9ae245568cc5194eae diff --git a/visigen/VISIBuilder.cpp b/visigen/VISIBuilder.cpp index 768194051..7fab2658d 100644 --- a/visigen/VISIBuilder.cpp +++ b/visigen/VISIBuilder.cpp @@ -4,7 +4,6 @@ #define VISI_MIN_LENGTH 8.0 static logvisor::Module Log("VISIBuilder"); -const VISIBuilder::Leaf VISIBuilder::NullLeaf = {}; VISIBuilder::PVSRenderCache::PVSRenderCache(VISIRenderer& renderer) : m_renderer(renderer) @@ -245,7 +244,10 @@ void VISIBuilder::Node::calculateSizesAndOffs(size_t& cur, size_t leafSz) } else { - cur += leafSz; + if (!leaf) + flags &= ~0x8; + else + cur += leafSz; } } @@ -294,7 +296,7 @@ void VISIBuilder::Node::writeNodes(athena::io::MemoryWriter& w, size_t leafBytes childNodes[nodeSel].writeNodes(w, leafBytes); } } - else + else if (leaf) { leaf.write(w, leafBytes); } diff --git a/visigen/VISIBuilder.hpp b/visigen/VISIBuilder.hpp index 1694b12f5..7a396c78a 100644 --- a/visigen/VISIBuilder.hpp +++ b/visigen/VISIBuilder.hpp @@ -77,7 +77,6 @@ struct VISIBuilder } } }; - static const Leaf NullLeaf; class PVSRenderCache { @@ -113,7 +112,7 @@ struct VISIBuilder bool operator==(const Node& other) const { - if (!leaf || !other.leaf) + if ((flags & 0x7) || (other.flags & 0x7)) return false; return leaf == other.leaf; } diff --git a/visigen/VISIRenderer.cpp b/visigen/VISIRenderer.cpp index 8c3d56fc5..d1c2cc3d5 100644 --- a/visigen/VISIRenderer.cpp +++ b/visigen/VISIRenderer.cpp @@ -296,6 +296,10 @@ void VISIRenderer::RenderPVSOpaque(RGBA8* bufOut, const zeus::CVector3f& pos, bo zeus::CFrustum frustum; frustum.updatePlanes(mv, g_Proj); + // Fill depth buffer with backfaces initially + glCullFace(GL_FRONT); + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + for (const Model& model : m_models) { if (!frustum.aabbFrustumTest(model.aabb)) @@ -311,6 +315,24 @@ void VISIRenderer::RenderPVSOpaque(RGBA8* bufOut, const zeus::CVector3f& pos, bo needTransparent = true; } } + + // Draw frontfaces + glCullFace(GL_BACK); + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + + for (const Model& model : m_models) + { + if (!frustum.aabbFrustumTest(model.aabb)) + continue; + glBindVertexArray(model.vao); + for (const Model::Surface& surf : model.surfaces) + { + // Non-transparents first + if (!surf.transparent) + glDrawElements(model.topology, surf.count, GL_UNSIGNED_INT, + reinterpret_cast(uintptr_t(surf.first * 4))); + } + } } //m_swapFunc();