From 85cd75aac3489d3555075e03fa01e4458ab01f69 Mon Sep 17 00:00:00 2001 From: Phillip Stephens Date: Wed, 10 Jun 2026 21:54:37 -0700 Subject: [PATCH] COBBTree matches --- config/GM8E01_00/symbols.txt | 6 +- config/GM8E01_01/symbols.txt | 2 +- include/WorldFormat/CCollisionEdge.hpp | 15 +-- include/WorldFormat/COBBTree.hpp | 72 +++++++++++- src/WorldFormat/COBBTree.cpp | 149 ++++++++++++++++++++++++- 5 files changed, 230 insertions(+), 14 deletions(-) diff --git a/config/GM8E01_00/symbols.txt b/config/GM8E01_00/symbols.txt index f1da57b7..f9005551 100644 --- a/config/GM8E01_00/symbols.txt +++ b/config/GM8E01_00/symbols.txt @@ -11684,7 +11684,7 @@ GetTriangleEdgeIndices__8COBBTreeCFUs = .text:0x802A7F4C; // type:function size: GetTriangleVertexIndices__8COBBTreeCFUsPUs = .text:0x802A7F60; // type:function size:0xB0 scope:global BuildOrientedBoundingBoxTree__8COBBTreeFRC9CVector3fRC9CVector3f = .text:0x802A8010; // type:function size:0x6A4 scope:global fn_802A86B4 = .text:0x802A86B4; // type:function size:0xF8 -fn_802A87AC = .text:0x802A87AC; // type:function size:0x238 +__dt__Q28COBBTree10SIndexDataFv = .text:0x802A87AC; // type:function size:0x238 __ct__Q28COBBTree10SIndexDataFv = .text:0x802A89E4; // type:function size:0x5C scope:global GetTransformedSurface__8COBBTreeCFUsRC12CTransform4f = .text:0x802A8A40; // type:function size:0x17C scope:global GetSurface__8COBBTreeCFUs = .text:0x802A8BBC; // type:function size:0xF4 scope:global @@ -17680,7 +17680,7 @@ lbl_803D6008 = .rodata:0x803D6008; // type:object size:0x10 data:4byte lbl_803D6020 = .rodata:0x803D6020; // type:object size:0x7 data:string lbl_803D6028 = .rodata:0x803D6028; // type:object size:0x10 data:4byte lbl_803D6038 = .rodata:0x803D6038; // type:object size:0xB0 data:byte -lbl_803D60E8 = .rodata:0x803D60E8; // type:object size:0x7 data:string +@stringBase0 = .rodata:0x803D60E8; // type:object size:0x7 scope:local data:string lbl_803D60F0 = .rodata:0x803D60F0; // type:object size:0x20 lbl_803D6110 = .rodata:0x803D6110; // type:object size:0x7 data:string lbl_803D6118 = .rodata:0x803D6118; // type:object size:0x20 @@ -21923,7 +21923,7 @@ gRejectedByClip = .sbss:0x805A9184; // type:object size:0x4 scope:global data:4b gTrianglesProcessed = .sbss:0x805A9188; // type:object size:0x4 scope:global data:4byte gDupTrianglesProcessed = .sbss:0x805A918C; // type:object size:0x4 scope:global data:4byte sDupPrimitiveCheckCount__20CMetroidAreaCollider = .sbss:0x805A9190; // type:object size:0x8 scope:global data:2byte -lbl_805A9198 = .sbss:0x805A9198; // type:object size:0x8 data:4byte +spAllocator__Q28COBBTree5CNode = .sbss:0x805A9198; // type:object size:0x8 data:4byte sDefaultRenderer = .sbss:0x805A91A0; // type:object size:0x4 scope:local data:4byte sDecalRandom__6CDecal = .sbss:0x805A91A8; // type:object size:0x4 scope:global sMoveRedToAlphaBuffer__6CDecal = .sbss:0x805A91AC; // type:object size:0x1 scope:global data:byte diff --git a/config/GM8E01_01/symbols.txt b/config/GM8E01_01/symbols.txt index 58a4a7af..f2d4d415 100644 --- a/config/GM8E01_01/symbols.txt +++ b/config/GM8E01_01/symbols.txt @@ -11684,7 +11684,7 @@ GetTriangleEdgeIndices__8COBBTreeCFUs = .text:0x802A7FF8; // type:function size: GetTriangleVertexIndices__8COBBTreeCFUsPUs = .text:0x802A800C; // type:function size:0xB0 scope:global BuildOrientedBoundingBoxTree__8COBBTreeFRC9CVector3fRC9CVector3f = .text:0x802A80BC; // type:function size:0x6A4 scope:global fn_802A86B4 = .text:0x802A8760; // type:function size:0xF8 scope:global -fn_802A87AC = .text:0x802A8858; // type:function size:0x238 scope:global +__dt__Q28COBBTree10SIndexDataFv = .text:0x802A8858; // type:function size:0x238 scope:global __ct__Q28COBBTree10SIndexDataFv = .text:0x802A8A90; // type:function size:0x5C scope:global GetTransformedSurface__8COBBTreeCFUsRC12CTransform4f = .text:0x802A8AEC; // type:function size:0x17C scope:global GetSurface__8COBBTreeCFUs = .text:0x802A8C68; // type:function size:0xF4 scope:global diff --git a/include/WorldFormat/CCollisionEdge.hpp b/include/WorldFormat/CCollisionEdge.hpp index 7255fd66..8e3dcdf4 100644 --- a/include/WorldFormat/CCollisionEdge.hpp +++ b/include/WorldFormat/CCollisionEdge.hpp @@ -7,16 +7,17 @@ class CCollisionEdge { public: - CCollisionEdge(CInputStream& in){ - x0_index1 = in.Get(); - x2_index2 = in.Get(); + CCollisionEdge(CInputStream& in) { + x0_index1 = in.Get< u16 >(); + x2_index2 = in.Get< u16 >(); } - u16 GetVertIndex1() const { return x0_index1; } - u16 GetVertIndex2() const { return x2_index2; } + const ushort GetVertIndex1() const { return x0_index1; } + const ushort GetVertIndex2() const { return x2_index2; } + private: - u16 x0_index1; - u16 x2_index2; + ushort x0_index1; + ushort x2_index2; }; #endif // _CCOLLISIONEDGE diff --git a/include/WorldFormat/COBBTree.hpp b/include/WorldFormat/COBBTree.hpp index b6e36e58..2de67b2c 100644 --- a/include/WorldFormat/COBBTree.hpp +++ b/include/WorldFormat/COBBTree.hpp @@ -1,14 +1,15 @@ #ifndef _COBBTREE #define _COBBTREE +#include "Collision/COBBox.hpp" #include "Kyoto/Math/CVector3f.hpp" #include "WorldFormat/CCollisionEdge.hpp" +#include "rstl/single_ptr.hpp" #include "rstl/vector.hpp" class COBBTree { - class CNode {}; struct SIndexData { rstl::vector< uint > x0_materials; rstl::vector< uchar > x10_vertMaterials; @@ -17,16 +18,83 @@ class COBBTree { rstl::vector< CCollisionEdge > x40_edges; rstl::vector< ushort > x50_surfaceIndices; rstl::vector< CVector3f > x60_vertices; + SIndexData(); SIndexData(CInputStream& in); }; public: + class CSimpleAllocator { + public: + CSimpleAllocator(uint size); + ~CSimpleAllocator(); + + void* Alloc(size_t size); + uint GetPoolMemSize() const { return mPoolSize; } + + private: + char* mPool; + uint mPoolSize; + uint mPoolOffset; + }; + + class CLeafData { + public: + CLeafData(const rstl::vector< ushort >& surface); + CLeafData(CInputStream& in); + + uint GetMemoryUsage() const; + + const rstl::vector< ushort >& GetSurfaceVector() const { return x0_surface; } + + private: + rstl::vector< ushort > x0_surface; + }; + + class CNode { + public: + CNode(const CTransform4f& xf, const CVector3f& point, const CNode* left, const CNode* right, + const CLeafData* leaf); + CNode(CInputStream& in); + ~CNode(); + static void SetAllocator(CSimpleAllocator* allocator); + uint GetMemoryUsage() const; + + const COBBox& GetOBB() const { return x0_obb; } + bool IsLeaf() const { return x3c_isLeaf; } + const CNode* GetLeftNode() const { return x40_left; } + const CNode* GetRightNode() const { return x44_right; } + bool WasHit() const { return x4c_hit; } + void SetHit(bool hit) { x4c_hit = hit; } + + static void* operator new(size_t size, const char* file, int line); + static void operator delete(void* ptr, size_t size); + + private: + COBBox x0_obb; + bool x3c_isLeaf; + const CNode* x40_left; + const CNode* x44_right; + const CLeafData* x48_leaf; + bool x4c_hit; + + static CSimpleAllocator* spAllocator; + }; COBBTree(CInputStream& in); COBBTree(const SIndexData& indexData, const CNode* root); ~COBBTree(); + CAABox CalculateLocalAABox() const; + + void GetTriangleVertexIndices(const ushort index, ushort out[2]) const; + const ushort* GetTriangleEdgeIndices(ushort index) const; + private: - char data[0x8c]; + uint x0_; + uint x4_; + uint x8_memoryUsage; + CSimpleAllocator xc_allocator; + SIndexData x18_indexData; + const CNode* x88_root; }; #endif // _COBBTREE diff --git a/src/WorldFormat/COBBTree.cpp b/src/WorldFormat/COBBTree.cpp index 3df986f4..06fa6e08 100644 --- a/src/WorldFormat/COBBTree.cpp +++ b/src/WorldFormat/COBBTree.cpp @@ -4,6 +4,8 @@ #pragma inline_max_size(250) +COBBTree::CSimpleAllocator* COBBTree::CNode::spAllocator = nullptr; + COBBTree::SIndexData::SIndexData(CInputStream& in) : x0_materials(in) , x10_vertMaterials(in) @@ -13,4 +15,149 @@ COBBTree::SIndexData::SIndexData(CInputStream& in) , x50_surfaceIndices(in) , x60_vertices(in) {} -COBBTree::COBBTree(const SIndexData& indexData, const CNode* root); +COBBTree::COBBTree(const SIndexData& indexData, const CNode* root) +: x8_memoryUsage(root->GetMemoryUsage()) +, xc_allocator(0) +, x18_indexData(indexData) +, x88_root(root) { + CNode::SetAllocator(nullptr); +} + +uint verify_deaf_babe(CInputStream& in) { return in.Get< uint >(); } +uint verify_version(CInputStream& in) { return in.Get< uint >(); } + +COBBTree::COBBTree(CInputStream& in) +: x0_(verify_deaf_babe(in)) +, x4_(verify_version(in)) +, x8_memoryUsage(in.Get< uint >()) +, xc_allocator(x8_memoryUsage) +, x18_indexData(in) +, x88_root(nullptr) { + CNode::SetAllocator(&xc_allocator); + + x88_root = rs_new CNode(in); +} + +COBBTree::~COBBTree() { + if (xc_allocator.GetPoolMemSize() != 0) { + CNode::SetAllocator(&xc_allocator); + } else { + CNode::SetAllocator(nullptr); + } + delete x88_root; +} + +CAABox COBBTree::CalculateLocalAABox() const { + if (x88_root != nullptr) { + return x88_root->GetOBB().CalculateAABox(CTransform4f::Identity()); + } + + return CAABox(0.f, 0.f, 0.f, 0.f, 0.f, 0.f); +} + +COBBTree::SIndexData::SIndexData() {} + +COBBTree::CNode::CNode(const CTransform4f& xf, const CVector3f& point, const CNode* left, + const CNode* right, const CLeafData* leaf) +: x0_obb(xf, point) +, x3c_isLeaf(leaf != nullptr) +, x40_left(left) +, x44_right(right) +, x48_leaf(leaf) {} + +COBBTree::CNode::CNode(CInputStream& in) +: x0_obb(in) +, x3c_isLeaf(in.Get< bool >()) +, x40_left(x3c_isLeaf ? nullptr : rs_new CNode(in)) +, x44_right(x3c_isLeaf ? nullptr : rs_new CNode(in)) +, x48_leaf(x3c_isLeaf ? rs_new CLeafData(in) : nullptr) {} + +COBBTree::CNode::~CNode() { + delete x40_left; + delete x44_right; + delete x48_leaf; +} + +uint COBBTree::CNode::GetMemoryUsage() const { + uint ret = sizeof(CNode); + if (x3c_isLeaf) { + ret += x48_leaf->GetMemoryUsage(); + } else { + ret += x40_left->GetMemoryUsage(); + ret += x44_right->GetMemoryUsage(); + } + + if (ret & 3) { + ret += (4 - (ret & 3)); + } + + return ret; +} + +void COBBTree::CNode::SetAllocator(CSimpleAllocator* allocator) { spAllocator = allocator; } +void* COBBTree::CNode::operator new(size_t size, const char* file, int line) { + if (spAllocator == nullptr) { + return rs_new char[size]; + } + return spAllocator->Alloc(size); +} + +void COBBTree::CNode::operator delete(void* ptr, size_t size) { + if (spAllocator == nullptr && ptr != nullptr) { + delete[] ptr; + } +} + +void COBBTree::GetTriangleVertexIndices(const ushort index, ushort out[2]) const { + const int surfIdx = (index * 3); + const CCollisionEdge& e0 = x18_indexData.x40_edges[x18_indexData.x50_surfaceIndices[surfIdx]]; + const CCollisionEdge& e1 = x18_indexData.x40_edges[x18_indexData.x50_surfaceIndices[surfIdx + 1]]; + + out[2] = (e1.GetVertIndex1() != e0.GetVertIndex1() && e1.GetVertIndex1() != e0.GetVertIndex2()) + ? e1.GetVertIndex1() + : e1.GetVertIndex2(); + + const uint material = x18_indexData.x0_materials[x18_indexData.x30_surfaceMaterials[index]]; + if ((material & 0x2000000) != 0) { + out[0] = e0.GetVertIndex2(); + out[1] = e0.GetVertIndex1(); + } else { + out[0] = e0.GetVertIndex1(); + out[1] = e0.GetVertIndex2(); + } +} + +const ushort* COBBTree::GetTriangleEdgeIndices(const ushort index) const { + return &x18_indexData.x50_surfaceIndices[index * 3]; +} +COBBTree::CLeafData::CLeafData(const rstl::vector< ushort >& surface) : x0_surface(surface) {} +COBBTree::CLeafData::CLeafData(CInputStream& in) : x0_surface(in) {} + +uint COBBTree::CLeafData::GetMemoryUsage() const { + uint ret = sizeof(CLeafData) + x0_surface.size() * sizeof(ushort); + + if (ret & 3) { + ret += (4 - (ret & 3)); + } + + return ret; +} + +COBBTree::CSimpleAllocator::CSimpleAllocator(uint size) +: mPool(rs_new char[size]), mPoolSize(size), mPoolOffset(0) {} + +COBBTree::CSimpleAllocator::~CSimpleAllocator() { + if (mPool) { + delete[] mPool; + } +} + +void* COBBTree::CSimpleAllocator::Alloc(const size_t size) { + void* ret = mPool + mPoolOffset; + mPoolOffset += size; + if (mPoolOffset & 3) { + mPoolOffset += (4 - (mPoolOffset & 3)); + } + + return ret; +} \ No newline at end of file