diff --git a/DataSpec/DNAMP1/HINT.hpp b/DataSpec/DNAMP1/HINT.hpp index cc4e54e64..b2b621124 100644 --- a/DataSpec/DNAMP1/HINT.hpp +++ b/DataSpec/DNAMP1/HINT.hpp @@ -21,7 +21,7 @@ struct HINT : BigYAML Value immediateTime; Value normalTime; UniqueID32 stringID; - Value continueDelayTime; + Value textPageCount; struct Location : BigYAML { DECL_YAML diff --git a/Editor/ProjectResourceFactoryBase.cpp b/Editor/ProjectResourceFactoryBase.cpp index eb0b89db0..fbd9f2310 100644 --- a/Editor/ProjectResourceFactoryBase.cpp +++ b/Editor/ProjectResourceFactoryBase.cpp @@ -560,6 +560,16 @@ bool ProjectResourceFactoryBase::AsyncTask::AsyncPump() return m_failed; } +void ProjectResourceFactoryBase::AsyncTask::WaitForComplete() +{ + using ItType = std::unordered_map>::iterator; + ItType search = m_parent.m_asyncLoadList.find(x0_tag); + if (search == m_parent.m_asyncLoadList.end()) + return; + for (ItType tmp = search ; !m_parent.AsyncPumpTask(tmp) ; tmp = search) + {std::this_thread::sleep_for(std::chrono::milliseconds(2));} +} + bool ProjectResourceFactoryBase::WaitForTagReady(const urde::SObjectTag& tag, const hecl::ProjectPath*& pathOut) { @@ -921,6 +931,70 @@ void ProjectResourceFactoryBase::EnumerateNamedResources( } } +bool ProjectResourceFactoryBase::AsyncPumpTask( + std::unordered_map>::iterator& it) +{ + /* Ensure requested resource is in the index */ + std::unique_lock lk(m_backgroundIndexMutex); + AsyncTask& task = *it->second; + auto search = m_tagToPath.find(task.x0_tag); + if (search == m_tagToPath.end()) + { + if (!m_backgroundRunning) + { + Log.report(logvisor::Error, _S("unable to find async load resource (%s, %08X)"), + task.x0_tag.type.toString().c_str(), task.x0_tag.id); + it = m_asyncLoadList.erase(it); + } + return true; + } + lk.unlock(); + task.EnsurePath(task.x0_tag, search->second); + + /* Pump load pipeline (cooking if needed) */ + if (task.AsyncPump()) + { + if (task.m_complete) + { + /* Load complete, build resource */ + if (task.xc_targetObjPtr) + { + /* Factory build */ + std::unique_ptr newObj; + if (m_factoryMgr.CanMakeMemory(task.x0_tag)) + { + newObj = m_factoryMgr.MakeObjectFromMemory(task.x0_tag, std::move(task.x10_loadBuffer), + task.x14_resSize, false, task.x18_cvXfer, + task.m_selfRef); + } + else + { + athena::io::MemoryReader mr(task.x10_loadBuffer.get(), task.x14_resSize); + newObj = m_factoryMgr.MakeObject(task.x0_tag, mr, task.x18_cvXfer, task.m_selfRef); + } + + *task.xc_targetObjPtr = newObj.release(); + Log.report(logvisor::Info, "async-built %.4s %08X", + task.x0_tag.type.toString().c_str(), + u32(task.x0_tag.id)); + } + else if (task.xc_targetDataPtr) + { + /* Buffer only */ + *task.xc_targetDataPtr = std::move(task.x10_loadBuffer); + 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); + return true; + } + ++it; + return false; +} + void ProjectResourceFactoryBase::AsyncIdle() { /* Consume completed transactions, they will be processed this cycle at the latest */ @@ -936,64 +1010,7 @@ void ProjectResourceFactoryBase::AsyncIdle() if (std::chrono::duration_cast(resStart - start).count() > 8) break; - /* Ensure requested resource is in the index */ - std::unique_lock lk(m_backgroundIndexMutex); - AsyncTask& task = *it->second; - auto search = m_tagToPath.find(task.x0_tag); - if (search == m_tagToPath.end()) - { - if (!m_backgroundRunning) - { - Log.report(logvisor::Error, _S("unable to find async load resource (%s, %08X)"), - task.x0_tag.type.toString().c_str(), task.x0_tag.id); - it = m_asyncLoadList.erase(it); - } - continue; - } - lk.unlock(); - task.EnsurePath(task.x0_tag, search->second); - - /* Pump load pipeline (cooking if needed) */ - if (task.AsyncPump()) - { - if (task.m_complete) - { - /* Load complete, build resource */ - if (task.xc_targetObjPtr) - { - /* Factory build */ - std::unique_ptr newObj; - if (m_factoryMgr.CanMakeMemory(task.x0_tag)) - { - newObj = m_factoryMgr.MakeObjectFromMemory(task.x0_tag, std::move(task.x10_loadBuffer), - task.x14_resSize, false, task.x18_cvXfer, - task.m_selfRef); - } - else - { - athena::io::MemoryReader mr(task.x10_loadBuffer.get(), task.x14_resSize); - newObj = m_factoryMgr.MakeObject(task.x0_tag, mr, task.x18_cvXfer, task.m_selfRef); - } - - *task.xc_targetObjPtr = newObj.release(); - Log.report(logvisor::Info, "async-built %.4s %08X", - task.x0_tag.type.toString().c_str(), - u32(task.x0_tag.id)); - } - else if (task.xc_targetDataPtr) - { - /* Buffer only */ - *task.xc_targetDataPtr = std::move(task.x10_loadBuffer); - 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); - continue; - } - ++it; + AsyncPumpTask(it); } } diff --git a/Editor/ProjectResourceFactoryBase.hpp b/Editor/ProjectResourceFactoryBase.hpp index 27b1d5739..52074974c 100644 --- a/Editor/ProjectResourceFactoryBase.hpp +++ b/Editor/ProjectResourceFactoryBase.hpp @@ -58,6 +58,7 @@ public: const hecl::ProjectPath& path); void CookComplete(); bool AsyncPump(); + void WaitForComplete(); }; protected: @@ -133,6 +134,7 @@ public: std::unique_ptr LoadResourceSync(const urde::SObjectTag& tag); std::unique_ptr LoadResourcePartSync(const urde::SObjectTag& tag, u32 size, u32 off); + bool AsyncPumpTask(std::unordered_map>::iterator& it); void AsyncIdle(); void Shutdown() {CancelBackgroundIndex();} diff --git a/Runtime/CGameHintInfo.cpp b/Runtime/CGameHintInfo.cpp index 5f0030d0e..957c630d2 100644 --- a/Runtime/CGameHintInfo.cpp +++ b/Runtime/CGameHintInfo.cpp @@ -19,7 +19,7 @@ CGameHintInfo::CGameHint::CGameHint(CInputStream& in, s32 version) , x10_immediateTime(in.readFloatBig()) , x14_normalTime(in.readFloatBig()) , x18_stringId(in.readUint32Big()) -, x1c_continueDelayTime(3.f * float(version <= 0 ? 1 : in.readUint32Big())) +, x1c_textTime(3.f * float(version <= 0 ? 1 : in.readUint32Big())) { u32 locationCount = in.readUint32Big(); x20_locations.reserve(locationCount); diff --git a/Runtime/CGameHintInfo.hpp b/Runtime/CGameHintInfo.hpp index 163e07cf8..47edad4de 100644 --- a/Runtime/CGameHintInfo.hpp +++ b/Runtime/CGameHintInfo.hpp @@ -24,14 +24,14 @@ public: float x10_immediateTime; float x14_normalTime; ResId x18_stringId; - float x1c_continueDelayTime; + float x1c_textTime; std::vector x20_locations; public: CGameHint(CInputStream&, s32); float GetNormalTime() const { return x14_normalTime; } float GetImmediateTime() const { return x10_immediateTime; } - float GetContinueDelayTime() const { return x1c_continueDelayTime; } + float GetTextTime() const { return x1c_textTime; } const std::string& GetName() const { return x0_name; } ResId GetStringID() const { return x18_stringId; } const std::vector& GetLocations() const { return x20_locations; } diff --git a/Runtime/CGameOptions.cpp b/Runtime/CGameOptions.cpp index d9bddf7c6..3638e059e 100644 --- a/Runtime/CGameOptions.cpp +++ b/Runtime/CGameOptions.cpp @@ -564,7 +564,7 @@ void CHintOptions::SetNextHintTime() if (x10_nextHintIdx == -1) return; x0_hintStates[x10_nextHintIdx].x4_time = - g_MemoryCardSys->GetHints()[x10_nextHintIdx].GetContinueDelayTime() + 5.f; + g_MemoryCardSys->GetHints()[x10_nextHintIdx].GetTextTime() + 5.f; } void CHintOptions::InitializeMemoryState() @@ -583,7 +583,7 @@ const CHintOptions::SHintState* CHintOptions::GetCurrentDisplayedHint() const const SHintState& hintState = x0_hintStates[x10_nextHintIdx]; const CGameHintInfo::CGameHint& hint = g_MemoryCardSys->GetHints()[x10_nextHintIdx]; - if (hintState.x4_time >= hint.GetContinueDelayTime()) + if (hintState.x4_time >= hint.GetTextTime()) return nullptr; if (hintState.x4_time < 3.f) @@ -602,12 +602,9 @@ void CHintOptions::DelayHint(const char* name) return; if (x10_nextHintIdx == idx) - { for (SHintState& state : x0_hintStates) state.x4_time += 60.f; - } - x0_hintStates[idx].x0_state = EHintState::Delayed; } @@ -639,7 +636,7 @@ void CHintOptions::ActivateContinueDelayHintTimer(const char* name) if (hintState.x0_state != EHintState::Two) return; - hintState.x4_time = hint.GetContinueDelayTime(); + hintState.x4_time = hint.GetTextTime(); } } diff --git a/Runtime/CStateManager.cpp b/Runtime/CStateManager.cpp index d059db0e7..623ec0d81 100644 --- a/Runtime/CStateManager.cpp +++ b/Runtime/CStateManager.cpp @@ -366,7 +366,64 @@ void CStateManager::SetupFogForArea(const CGameArea& area) const {} void CStateManager::PreRender() {} -void CStateManager::GetVisSetForArea(TAreaId, TAreaId) const {} +bool CStateManager::GetVisSetForArea(TAreaId a, TAreaId b, CPVSVisSet& setOut) const +{ + if (b == kInvalidAreaId) + return false; + + zeus::CVector3f viewPoint = CGraphics::g_ViewMatrix.origin; + zeus::CVector3f closestDockPoint = viewPoint; + bool hasClosestDock = false; + if (a != b) + { + CGameArea& area = *x850_world->GetGameAreas()[b]; + if (area.IsPostConstructed()) + { + for (const CGameArea::Dock& dock : area.GetDocks()) + { + for (int i=0 ; i= + (closestDockPoint - viewPoint).magSquared()) + continue; + closestDockPoint = dockCenter; + hasClosestDock = true; + } + } + } + } + } + else + { + hasClosestDock = true; + } + + if (hasClosestDock) + { + if (CPVSAreaSet* pvs = x850_world->GetGameAreas()[a]->GetPostConstructed()->xa0_pvs.get()) + { + const CPVSVisOctree& octree = pvs->GetVisOctree(); + zeus::CVector3f closestDockLocal = + x850_world->GetGameAreas()[a]->GetInverseTransform() * closestDockPoint; + CPVSVisSet set; + set.SetTestPoint(octree, closestDockLocal); + + if (set.GetState() == EPVSVisSetState::NodeFound) + { + setOut = set; + return true; + } + } + } + + return false; +} void CStateManager::RecursiveDrawTree(TUniqueId) const {} @@ -557,14 +614,14 @@ std::pair CStateManager::GenerateObject(TEditorId) return {kInvalidEditorId, kInvalidUniqueId}; } -void CStateManager::InitScriptObjects(std::vector& ids) +void CStateManager::InitScriptObjects(const std::vector& ids) { for (TEditorId id : ids) { if (id == kInvalidEditorId) continue; TUniqueId uid = GetIdForScript(id); - SendScriptMsg(uid, kInvalidUniqueId, EScriptObjectMessage::InternalMessage13); + SendScriptMsg(uid, kInvalidUniqueId, EScriptObjectMessage::Constructed); } MurderScriptInstanceNames(); } diff --git a/Runtime/CStateManager.hpp b/Runtime/CStateManager.hpp index 344e834f8..6a475e80b 100644 --- a/Runtime/CStateManager.hpp +++ b/Runtime/CStateManager.hpp @@ -269,7 +269,7 @@ public: void DrawWorld() const; void SetupFogForArea(const CGameArea& area) const; void PreRender(); - void GetVisSetForArea(TAreaId, TAreaId) const; + bool GetVisSetForArea(TAreaId, TAreaId, CPVSVisSet& setOut) const; void RecursiveDrawTree(TUniqueId) const; void SendScriptMsg(CEntity* dest, TUniqueId src, EScriptObjectMessage msg); void SendScriptMsg(TUniqueId dest, TUniqueId src, EScriptObjectMessage msg); @@ -285,9 +285,10 @@ public: std::multimap::const_iterator> GetIdListForScript(TEditorId) const; void LoadScriptObjects(TAreaId, CInputStream& in, std::vector& idsOut); + void InitializeScriptObjects(const std::vector& objIds); std::pair LoadScriptObject(TAreaId, EScriptObjectType, u32, CInputStream& in); std::pair GenerateObject(TEditorId); - void InitScriptObjects(std::vector& ids); + void InitScriptObjects(const std::vector& ids); void InformListeners(const zeus::CVector3f&, EListenNoiseType); bool ApplyKnockBack(CActor& actor, const CDamageInfo& info, const CDamageVulnerability&, const zeus::CVector3f&, float); diff --git a/Runtime/Graphics/CBooRenderer.cpp b/Runtime/Graphics/CBooRenderer.cpp index 6a4d3bb31..5433d6062 100644 --- a/Runtime/Graphics/CBooRenderer.cpp +++ b/Runtime/Graphics/CBooRenderer.cpp @@ -386,13 +386,13 @@ void CBooRenderer::DrawUnsortedGeometry(int areaIdx, int mask, int targetMask) if (xe0_pvsModelCount != item.x10_models.size()) pvs = nullptr; - int idx = 0; + u32 idx = 0; for (auto it = item.x10_models.begin() ; it != item.x10_models.end() ; ++it, ++idx) { CBooModel* model = *it; if (pvs) { - bool vis = pvs->GetVisible(idx); + bool vis = pvs->GetVisible(idx) != EPVSVisSetState::EndOfTree; switch (xc4_pvsMode) { case EPVSMode::PVS: diff --git a/Runtime/Graphics/CMakeLists.txt b/Runtime/Graphics/CMakeLists.txt index 4212cadc9..446412fbc 100644 --- a/Runtime/Graphics/CMakeLists.txt +++ b/Runtime/Graphics/CMakeLists.txt @@ -41,7 +41,6 @@ set(GRAPHICS_SOURCES CGraphicsPalette.hpp CGraphicsPalette.cpp CPVSVisSet.hpp CPVSVisSet.cpp CPVSVisOctree.hpp CPVSVisOctree.cpp - CPVSBounds.hpp CPVSBounds.cpp CPVSAreaSet.hpp CPVSAreaSet.cpp CGraphics.hpp CGraphics.cpp CSimpleShadow.hpp CSimpleShadow.cpp diff --git a/Runtime/Graphics/CPVSAreaSet.cpp b/Runtime/Graphics/CPVSAreaSet.cpp index 44609e4a3..e2138020c 100644 --- a/Runtime/Graphics/CPVSAreaSet.cpp +++ b/Runtime/Graphics/CPVSAreaSet.cpp @@ -3,12 +3,19 @@ namespace urde { -CPVSAreaSet::CPVSAreaHolder::CPVSAreaHolder(CInputStream& in) -{ -} - -CPVSAreaSet::CPVSAreaSet(CInputStream& in) +CPVSAreaSet::CPVSAreaSet(const u8* data, u32 len) { + CMemoryInStream r(data, len); + x0_numFeatures = r.readUint32Big(); + x4_numLights = r.readUint32Big(); + x8_c = r.readUint32Big(); + xc_numActors = r.readUint32Big(); + x10_leafSize = r.readUint32Big(); + x14_lightIndexCount = r.readUint32Big(); + x18_entityIndex = data + r.position(); + x1c_lightLeaves = x18_entityIndex + xc_numActors * 4; + const u8* octreeData = x1c_lightLeaves + x14_lightIndexCount * x10_leafSize; + x20_octree = CPVSVisOctree::MakePVSVisOctree(octreeData); } } diff --git a/Runtime/Graphics/CPVSAreaSet.hpp b/Runtime/Graphics/CPVSAreaSet.hpp index b1a890303..f837c3ab9 100644 --- a/Runtime/Graphics/CPVSAreaSet.hpp +++ b/Runtime/Graphics/CPVSAreaSet.hpp @@ -2,21 +2,29 @@ #define __URDE_CPVSAREASET_HPP__ #include "RetroTypes.hpp" +#include "CPVSVisOctree.hpp" namespace urde { class CPVSAreaSet { + u32 x0_numFeatures; + u32 x4_numLights; + u32 x8_c; + u32 xc_numActors; + u32 x10_leafSize; + u32 x14_lightIndexCount; + const u8* x18_entityIndex; + const u8* x1c_lightLeaves; + CPVSVisOctree x20_octree; + public: - struct CPVSAreaHolder - { - CPVSAreaHolder(CInputStream& in); - }; -private: - std::vector xunk; -public: - CPVSAreaSet(CInputStream& in); + CPVSAreaSet(const u8* data, u32 len); + u32 GetNumFeatures() const { return x0_numFeatures; } + u32 GetNumActors() const { return xc_numActors; } + u32 GetEntityIdByIndex(int idx) const { return x18_entityIndex[idx]; } + const CPVSVisOctree& GetVisOctree() { return x20_octree; } }; } diff --git a/Runtime/Graphics/CPVSBounds.cpp b/Runtime/Graphics/CPVSBounds.cpp deleted file mode 100644 index 5c2ca08a0..000000000 --- a/Runtime/Graphics/CPVSBounds.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "CPVSBounds.hpp" - -namespace urde -{ - -CPVSBounds::CPVSBounds(CInputStream& in) -{ -} - -u32 CPVSBounds::GetBoundsFileSize() -{ - return 0; -} - -bool CPVSBounds::PointInBounds(const zeus::CVector3f&) const -{ - return false; -} - -} diff --git a/Runtime/Graphics/CPVSBounds.hpp b/Runtime/Graphics/CPVSBounds.hpp deleted file mode 100644 index 59f9b9847..000000000 --- a/Runtime/Graphics/CPVSBounds.hpp +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef __URDE_CPVSBOUNDS_HPP__ -#define __URDE_CPVSBOUNDS_HPP__ - -#include "RetroTypes.hpp" -#include "zeus/CVector3f.hpp" - -namespace urde -{ - -class CPVSBounds -{ -public: - CPVSBounds(CInputStream& in); - u32 GetBoundsFileSize(); - bool PointInBounds(const zeus::CVector3f&) const; -}; - -} - -#endif // __URDE_CPVSBOUNDS_HPP__ diff --git a/Runtime/Graphics/CPVSVisOctree.cpp b/Runtime/Graphics/CPVSVisOctree.cpp index a9c74393c..8e72ba40d 100644 --- a/Runtime/Graphics/CPVSVisOctree.cpp +++ b/Runtime/Graphics/CPVSVisOctree.cpp @@ -3,23 +3,111 @@ namespace urde { -CPVSVisOctree::CPVSVisOctree(CInputStream& in) +CPVSVisOctree CPVSVisOctree::MakePVSVisOctree(const u8* data) { + CMemoryInStream r(data, 68); + zeus::CAABox aabb = aabb.ReadBoundingBoxBig(r); + u32 a = r.readUint32Big(); + u32 b = r.readUint32Big(); + r.readUint32Big(); + return CPVSVisOctree(aabb, a, b, data + r.position()); } -u32 CPVSVisOctree::GetNumChildren(const unsigned char*) const +CPVSVisOctree::CPVSVisOctree(const zeus::CAABox& aabb, u32 a, u32 b, const u8* c) +: x0_aabb(aabb), x18_totalBits(a), x1c_lightBits(b), x20_bufferFlag(c != nullptr), x24_octreeData(c) +{ + x2c_searchAabb = x0_aabb; + x20_bufferFlag = 0; +} + +static const u32 NumChildTable[] = +{ + 0, 2, 2, 4, 2, 4, 4, 8 +}; + +u32 CPVSVisOctree::GetNumChildren(u8 byte) const +{ + return NumChildTable[byte & 0x7]; +} + +u32 CPVSVisOctree::GetChildIndex(const u8*, const zeus::CVector3f&) const { return 0; } -u32 CPVSVisOctree::GetChildIndex(const unsigned char*, const zeus::CVector3f&) const +s32 CPVSVisOctree::IterateSearch(u8 nodeData, const zeus::CVector3f& tp) const { - return 0; -} + if (!(nodeData & 0x7)) + return -1; // Leaf node -u32 CPVSVisOctree::SetTestPoint(const zeus::CVector3f&) const -{ - return 0; + zeus::CVector3f newMin = x2c_searchAabb.center(); + zeus::CVector3f newMax; + bool highFlags[3]; + + if (tp.x > newMin.x) + { + newMax.x = x2c_searchAabb.max.x; + highFlags[0] = true; + } + else + { + newMax.x = newMin.x; + newMin.x = x2c_searchAabb.min.x; + highFlags[0] = false; + } + + if (tp.y > newMin.y) + { + newMax.y = x2c_searchAabb.max.y; + highFlags[1] = true; + } + else + { + newMax.y = newMin.y; + newMin.y = x2c_searchAabb.min.y; + highFlags[1] = false; + } + + if (tp.z > newMin.z) + { + newMax.z = x2c_searchAabb.max.z; + highFlags[2] = true; + } + else + { + newMax.z = newMin.z; + newMin.z = x2c_searchAabb.min.z; + highFlags[2] = false; + } + + u8 axisCounts[2] = {1, 1}; + if (nodeData & 0x1) + axisCounts[0] = 2; + if (nodeData & 0x2) + axisCounts[1] = 2; + + zeus::CAABox& newSearch = const_cast(x2c_searchAabb); + if (nodeData & 0x1) + { + newSearch.min.x = newMin.x; + newSearch.max.x = newMax.x; + } + if (nodeData & 0x2) + { + newSearch.min.y = newMin.y; + newSearch.max.y = newMax.y; + } + if (nodeData & 0x4) + { + newSearch.min.z = newMin.z; + newSearch.max.z = newMax.z; + } + + // Branch node - calculate next relative pointer + return + highFlags[0] * bool(nodeData & 0x1) + + highFlags[1] * axisCounts[0] * bool(nodeData & 0x2) + + highFlags[2] * axisCounts[0] * axisCounts[1] * bool(nodeData & 0x4); } } diff --git a/Runtime/Graphics/CPVSVisOctree.hpp b/Runtime/Graphics/CPVSVisOctree.hpp index 4d75f2581..94f75f84f 100644 --- a/Runtime/Graphics/CPVSVisOctree.hpp +++ b/Runtime/Graphics/CPVSVisOctree.hpp @@ -3,17 +3,32 @@ #include "RetroTypes.hpp" #include "zeus/CVector3f.hpp" +#include "CPVSVisSet.hpp" namespace urde { class CPVSVisOctree { + zeus::CAABox x0_aabb; + u32 x18_totalBits; + u32 x1c_lightBits; + bool x20_bufferFlag; + const u8* x24_octreeData; + zeus::CAABox x2c_searchAabb; public: - CPVSVisOctree(CInputStream& in); - u32 GetNumChildren(const unsigned char*) const; - u32 GetChildIndex(const unsigned char*, const zeus::CVector3f&) const; - u32 SetTestPoint(const zeus::CVector3f&) const; + static CPVSVisOctree MakePVSVisOctree(const u8* data); + CPVSVisOctree() = default; + CPVSVisOctree(const zeus::CAABox& aabb, u32 a, u32 b, const u8* c); + u32 GetNumChildren(u8 byte) const; + u32 GetChildIndex(const u8*, const zeus::CVector3f&) const; + const zeus::CAABox& GetBounds() const { return x0_aabb; } + const u8* GetOctreeData() const { return x24_octreeData; } + + u32 GetTotalBits() const { return x18_totalBits; } + u32 GetLightBits() const { return x1c_lightBits; } + void ResetSearch() const { const_cast(*this).x2c_searchAabb = x0_aabb; } + s32 IterateSearch(u8 nodeData, const zeus::CVector3f& tp) const; }; } diff --git a/Runtime/Graphics/CPVSVisSet.cpp b/Runtime/Graphics/CPVSVisSet.cpp index 327bc0b24..90c4bde62 100644 --- a/Runtime/Graphics/CPVSVisSet.cpp +++ b/Runtime/Graphics/CPVSVisSet.cpp @@ -1,23 +1,110 @@ #include "CPVSVisSet.hpp" +#include "CPVSVisOctree.hpp" namespace urde { -void CPVSVisSet::Reset(bool) +void CPVSVisSet::Reset(EPVSVisSetState state) { + x0_state = state; + x4_numBits = 0; + x8_numLights = 0; + //xc_ = false; + x10_ptr = nullptr; } -bool CPVSVisSet::GetVisible(int) +EPVSVisSetState CPVSVisSet::GetVisible(u32 idx) const { - return false; + if (x0_state != EPVSVisSetState::NodeFound) + return x0_state; + + u32 numFeatures = x4_numBits - x8_numLights; + if (idx < numFeatures) + { + /* This is a feature lookup */ + if (!x10_ptr[idx / 8] & (1 << (idx & 0x7))) + return EPVSVisSetState::EndOfTree; + return EPVSVisSetState::OutOfBounds; + } + + /* This is a light lookup */ + u32 lightTest = idx - numFeatures + x4_numBits; + const u8* ptr = &x10_ptr[lightTest / 8]; + lightTest &= 0x7; + if (lightTest != 0x7) + return EPVSVisSetState((ptr[0] & (0x3 << lightTest)) >> lightTest); + return EPVSVisSetState((ptr[0] >> 7) | ((ptr[1] & 0x1) << 1)); } -void CPVSVisSet::SetVisible(int,bool) +void CPVSVisSet::SetFromMemory(u32 numBits, u32 numLights, const u8* leafPtr) { + x0_state = EPVSVisSetState::NodeFound; + x4_numBits = numBits; + x8_numLights = numLights; + x10_ptr = leafPtr; } -void CPVSVisSet::SetFromMemory(const unsigned char*) +void CPVSVisSet::SetTestPoint(const CPVSVisOctree& octree, const zeus::CVector3f& point) { + if (!octree.GetBounds().pointInside(point)) + { + Reset(EPVSVisSetState::OutOfBounds); + return; + } + + const u8* octCur = octree.GetOctreeData(); + octree.ResetSearch(); + s32 nextNodeRel; + u8 curNode; + while ((nextNodeRel = octree.IterateSearch((curNode = *octCur++), point)) != -1) + { + if (nextNodeRel) + { + /* Skip node data */ + if (!(curNode & 0x60)) + { + octCur += hecl::SBig(reinterpret_cast(octCur)[nextNodeRel - 1]); + } + else if (curNode & 0x20) + { + octCur += *(octCur + nextNodeRel - 1); + } + else + { + const u8* tmp = octCur + (nextNodeRel - 1) * 3; + octCur += (tmp[0] << 16) + (tmp[1] << 8) + tmp[2]; + } + } + + /* Skip children data */ + if (!(curNode & 0x60)) + { + octCur += (octree.GetNumChildren(curNode) - 1) * 2; + } + else if (curNode & 0x20) + { + octCur += octree.GetNumChildren(curNode) - 1; + } + else + { + octCur += (octree.GetNumChildren(curNode) - 1) * 3; + } + } + + /* Handle leaf type */ + switch (curNode & 0x18) + { + case 0x18: + SetFromMemory(octree.GetTotalBits(), octree.GetLightBits(), octCur); + break; + case 0x10: + Reset(EPVSVisSetState::EndOfTree); + break; + case 0x08: + default: + Reset(EPVSVisSetState::OutOfBounds); + break; + } } } diff --git a/Runtime/Graphics/CPVSVisSet.hpp b/Runtime/Graphics/CPVSVisSet.hpp index 892a9c4cd..cd2aec30b 100644 --- a/Runtime/Graphics/CPVSVisSet.hpp +++ b/Runtime/Graphics/CPVSVisSet.hpp @@ -2,24 +2,33 @@ #define __URDE_CPVSVISSET_HPP__ #include "RetroTypes.hpp" +#include "zeus/CAABox.hpp" #include namespace urde { +class CPVSVisOctree; + +enum class EPVSVisSetState +{ + EndOfTree, + NodeFound, + OutOfBounds +}; class CPVSVisSet { - int x0_bitCount; - int x4_setCount = 0; - std::vector x8_bitset; + EPVSVisSetState x0_state; + u32 x4_numBits; + u32 x8_numLights; + //bool xc_; Used to be part of auto_ptr + const u8* x10_ptr; public: - CPVSVisSet(int count) : x0_bitCount(count) {} - CPVSVisSet(int a, std::vector&& bitset) - : x0_bitCount(1), x4_setCount(a), x8_bitset(std::move(bitset)) {} - void Reset(bool); - bool GetVisible(int); - void SetVisible(int,bool); - void SetFromMemory(const unsigned char*); + void Reset(EPVSVisSetState state); + EPVSVisSetState GetState() const { return x0_state; } + EPVSVisSetState GetVisible(u32 idx) const; + void SetFromMemory(u32 numBits, u32 numLights, const u8* leafPtr); + void SetTestPoint(const CPVSVisOctree& octree, const zeus::CVector3f&); }; } diff --git a/Runtime/MP1/CFrontEndUI.cpp b/Runtime/MP1/CFrontEndUI.cpp index f4be46bc8..63d4d8928 100644 --- a/Runtime/MP1/CFrontEndUI.cpp +++ b/Runtime/MP1/CFrontEndUI.cpp @@ -2008,7 +2008,7 @@ CFrontEndUI::CFrontEndUI() m_touchBar = NewFrontEndUITouchBar(); m_touchBar->SetPhase(CFrontEndUITouchBar::EPhase::None); - //x14_phase = EPhase::ExitFrontEnd; + x14_phase = EPhase::ExitFrontEnd; } void CFrontEndUI::StartSlideShow(CArchitectureQueue& queue) diff --git a/Runtime/World/CActor.cpp b/Runtime/World/CActor.cpp index 7b8038bbf..9d11ae7e6 100644 --- a/Runtime/World/CActor.cpp +++ b/Runtime/World/CActor.cpp @@ -65,7 +65,7 @@ void CActor::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateMana #endif } break; - case EScriptObjectMessage::InternalMessage13: // 35 + case EScriptObjectMessage::Constructed: // 35 { for (const SConnection& conn : x20_conns) { diff --git a/Runtime/World/CGameArea.cpp b/Runtime/World/CGameArea.cpp index 5643bb713..5c1ef73fd 100644 --- a/Runtime/World/CGameArea.cpp +++ b/Runtime/World/CGameArea.cpp @@ -709,9 +709,76 @@ void CGameArea::StartStreamIn(CStateManager& mgr) { } -bool CGameArea::Validate(CStateManager& mgr) +void CGameArea::Validate(CStateManager& mgr) { - return false; + if (xf0_24_postConstructed) + return; + + while (StartStreamingMainArea()) {} + + for (auto& req : xf8_loadTransactions) + req->WaitForComplete(); + + if (xdc_tokens.empty()) + { + VerifyTokenList(mgr); + for (CToken& tok : xdc_tokens) + tok.Lock(); + for (CToken& tok : xdc_tokens) + tok.GetObj(); + xf0_26_tokensReady = true; + } + + xf8_loadTransactions.clear(); + + PostConstructArea(); + if (x4_selfIdx != kInvalidAreaId) + mgr.WorldNC()->MoveAreaToChain3(x4_selfIdx); + + LoadScriptObjects(mgr); + + CPVSAreaSet* pvs = x12c_postConstructed->xa0_pvs.get(); + if (pvs && x12c_postConstructed->x1108_29_) + { + for (int i=0 ; iGetNumActors() ; ++i) + { + TEditorId entId = pvs->GetEntityIdByIndex(i) | (x4_selfIdx << 16); + TUniqueId id = mgr.GetIdForScript(entId); + if (id != kInvalidUniqueId) + { + CPostConstructed::MapEntry& ent = x12c_postConstructed->xa8_pvsEntityMap[id & 0x3ff]; + ent.x0_id = i + (pvs->GetNumFeatures() - pvs->GetNumActors()); + ent.x4_uid = id; + } + } + } + + xf0_28_validated = true; + mgr.AreaLoaded(x4_selfIdx); +} + +void CGameArea::LoadScriptObjects(CStateManager& mgr) +{ + CWorldLayerState& layerState = *mgr.LayerState(); + u32 layerCount = layerState.GetAreaLayerCount(x4_selfIdx); + std::vector objIds; + for (u32 i=0 ; i CGameArea::GetLayerScriptBuffer(int layer) +{ + if (!xf0_24_postConstructed) + return {}; + return x12c_postConstructed->x110c_layerPtrs[layer]; } void CGameArea::PostConstructArea() @@ -797,7 +864,8 @@ void CGameArea::PostConstructArea() { x12c_postConstructed->x1108_29_ = r.readBool(); x12c_postConstructed->x1108_30_ = r.readBool(); - x12c_postConstructed->xa0_pvs.reset(new CPVSAreaSet::CPVSAreaHolder(r)); + x12c_postConstructed->xa0_pvs = std::make_unique(secIt->first.get() + r.position(), + secIt->second - r.position()); } } @@ -848,7 +916,7 @@ void CGameArea::FillInStaticGeometry() void CGameArea::VerifyTokenList(CStateManager& stateMgr) { - if (xdc_tokens.empty()) + if (xdc_tokens.size()) return; ClearTokenList(); @@ -881,7 +949,7 @@ void CGameArea::ClearTokenList() else xdc_tokens.clear(); - xf0_26_tokensReady = 0; + xf0_26_tokensReady = false; } u32 CGameArea::GetPreConstructedSize() const diff --git a/Runtime/World/CGameArea.hpp b/Runtime/World/CGameArea.hpp index 99b386de2..753e7f916 100644 --- a/Runtime/World/CGameArea.hpp +++ b/Runtime/World/CGameArea.hpp @@ -105,7 +105,7 @@ class CGameArea : public IGameArea bool xf0_25_active : 1; bool xf0_26_tokensReady : 1; bool xf0_27_paused : 1; - bool xf0_28_ : 1; + bool xf0_28_validated : 1; }; u8 _dummy = 0; }; @@ -174,13 +174,13 @@ public: std::vector x70_gfxLightsA; std::vector x80_lightsB; std::vector x90_gfxLightsB; - std::unique_ptr xa0_pvs; + std::unique_ptr xa0_pvs; u32 xa4_elemCount = 1024; struct MapEntry { s16 x0_id = -1; TUniqueId x4_uid = kInvalidUniqueId; - } xa8_map[1024]; + } xa8_pvsEntityMap[1024]; u32 x10a8_pvsVersion = 0; TLockedToken x10ac_path; // bool x10b8_ = 0; optional flag for CToken @@ -301,7 +301,9 @@ public: bool Invalidate(CStateManager& mgr); void CullDeadAreaRequests(); void StartStreamIn(CStateManager& mgr); - bool Validate(CStateManager& mgr); + void Validate(CStateManager& mgr); + void LoadScriptObjects(CStateManager& mgr); + std::pair GetLayerScriptBuffer(int layer); void PostConstructArea(); void FillInStaticGeometry(); void VerifyTokenList(CStateManager& stateMgr); @@ -313,7 +315,7 @@ public: const zeus::CTransform& GetInverseTransform() const {return x3c_invTransform;} const zeus::CAABox& GetAABB() const {return x6c_aabb;} - const std::vector GetDocks() const {return xcc_docks;} + const std::vector& GetDocks() const {return xcc_docks;} const Dock* GetDock(s32 dock) const { return &xcc_docks[dock]; } s32 GetDockCount() const { return xcc_docks.size(); } Dock* DockNC(s32 dock) { return &xcc_docks[dock]; } diff --git a/Runtime/World/CScriptActor.cpp b/Runtime/World/CScriptActor.cpp index 7b56e6862..9393296ba 100644 --- a/Runtime/World/CScriptActor.cpp +++ b/Runtime/World/CScriptActor.cpp @@ -57,7 +57,7 @@ void CScriptActor::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CSta { CScriptColorModulate::FadeOutHelper(mgr, x8_uid, x2d4_alphaMin); } - else if (msg == EScriptObjectMessage::InternalMessage13) + else if (msg == EScriptObjectMessage::Constructed) { for (const SConnection& conn : x20_conns) { diff --git a/Runtime/World/CScriptAiJumpPoint.cpp b/Runtime/World/CScriptAiJumpPoint.cpp index 47a6412f1..5c6ef61d6 100644 --- a/Runtime/World/CScriptAiJumpPoint.cpp +++ b/Runtime/World/CScriptAiJumpPoint.cpp @@ -32,7 +32,7 @@ void CScriptAiJumpPoint::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId oth { AcceptScriptMsg(msg, other, mgr); - if (msg != EScriptObjectMessage::InternalMessage13) + if (msg != EScriptObjectMessage::Constructed) return; for (SConnection& conn : x20_conns) diff --git a/Runtime/World/CScriptAreaAttributes.cpp b/Runtime/World/CScriptAreaAttributes.cpp index c63b47bc2..2fb650451 100644 --- a/Runtime/World/CScriptAreaAttributes.cpp +++ b/Runtime/World/CScriptAreaAttributes.cpp @@ -33,7 +33,7 @@ void CScriptAreaAttributes::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId if (x4_areaId == kInvalidAreaId) return; - if (msg == EScriptObjectMessage::InternalMessage13) + if (msg == EScriptObjectMessage::Constructed) { CGameArea* area = stateMgr.WorldNC()->GetArea(x4_areaId); area->SetAreaAttributes(this); diff --git a/Runtime/World/CScriptDistanceFog.cpp b/Runtime/World/CScriptDistanceFog.cpp index eec60c85d..f20d97230 100644 --- a/Runtime/World/CScriptDistanceFog.cpp +++ b/Runtime/World/CScriptDistanceFog.cpp @@ -41,7 +41,7 @@ void CScriptDistanceFog::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId obj if (x4_areaId == kInvalidAreaId || !GetActive()) return; - if (msg == EScriptObjectMessage::InternalMessage13) + if (msg == EScriptObjectMessage::Constructed) { if (!x60_explicit) return; diff --git a/Runtime/World/CScriptDock.cpp b/Runtime/World/CScriptDock.cpp index 45b179aa4..6afb2ed38 100644 --- a/Runtime/World/CScriptDock.cpp +++ b/Runtime/World/CScriptDock.cpp @@ -103,7 +103,7 @@ void CScriptDock::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStat case EScriptObjectMessage::Deleted: CleanUp(); break; - case EScriptObjectMessage::InternalMessage13: + case EScriptObjectMessage::Constructed: AreaLoaded(mgr); break; case EScriptObjectMessage::InternalMessage14: diff --git a/Runtime/World/CScriptShadowProjector.cpp b/Runtime/World/CScriptShadowProjector.cpp index f9eb8aa1c..f521f9ae4 100644 --- a/Runtime/World/CScriptShadowProjector.cpp +++ b/Runtime/World/CScriptShadowProjector.cpp @@ -64,7 +64,7 @@ void CScriptShadowProjector::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId x110_25_shadowInvalidated = true; } - else if (msg == EScriptObjectMessage::InternalMessage13) + else if (msg == EScriptObjectMessage::Constructed) { for (const SConnection& conn : x20_conns) { diff --git a/Runtime/World/CWorld.cpp b/Runtime/World/CWorld.cpp index 768a5c41e..64c8c4631 100644 --- a/Runtime/World/CWorld.cpp +++ b/Runtime/World/CWorld.cpp @@ -235,6 +235,11 @@ void CWorld::MoveToChain(CGameArea* area, EChain chain) x4c_chainHeads[int(chain)] = area; } +void CWorld::MoveAreaToChain3(TAreaId aid) +{ + MoveToChain(x18_areas[aid].get(), EChain::Three); +} + void CWorld::LoadSoundGroup(int groupId, ResId agscId, CSoundGroupData& data) {} void CWorld::LoadSoundGroups() {} diff --git a/Runtime/World/CWorld.hpp b/Runtime/World/CWorld.hpp index 29a5027b6..a389aa49b 100644 --- a/Runtime/World/CWorld.hpp +++ b/Runtime/World/CWorld.hpp @@ -152,6 +152,7 @@ private: public: void MoveToChain(CGameArea* area, EChain chain); + void MoveAreaToChain3(TAreaId aid); bool CheckWorldComplete(CStateManager* mgr, TAreaId id, ResId mreaId); bool ScheduleAreaToLoad(CGameArea* area, CStateManager& mgr); void TravelToArea(TAreaId aid, CStateManager& mgr, bool); diff --git a/Runtime/World/ScriptObjectSupport.hpp b/Runtime/World/ScriptObjectSupport.hpp index ed749d2bb..387bf3699 100644 --- a/Runtime/World/ScriptObjectSupport.hpp +++ b/Runtime/World/ScriptObjectSupport.hpp @@ -212,7 +212,7 @@ enum class EScriptObjectMessage InternalMessage10 = 32, InternalMessage11 = 33, Deleted = 34, - InternalMessage13 = 35, + Constructed = 35, InternalMessage14 = 36, InternalMessage15 = 37, InternalMessage16 = 38,