From 85cd75aac3489d3555075e03fa01e4458ab01f69 Mon Sep 17 00:00:00 2001 From: Phillip Stephens Date: Wed, 10 Jun 2026 21:54:37 -0700 Subject: [PATCH 1/4] 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 f1da57b70..f90055515 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 58a4a7af3..f2d4d415d 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 7255fd665..8e3dcdf46 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 b6e36e587..2de67b2c5 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 3df986f46..06fa6e089 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 From 8f456c9616d3d5e9d519c34cf4fe728a4e61421f Mon Sep 17 00:00:00 2001 From: Phillip Stephens Date: Wed, 10 Jun 2026 23:05:09 -0700 Subject: [PATCH 2/4] COBBTree progress --- config/GM8E01_00/symbols.txt | 7 ++- include/WorldFormat/CCollisionEdge.hpp | 1 + include/WorldFormat/COBBTree.hpp | 4 ++ src/WorldFormat/COBBTree.cpp | 59 ++++++++++++++++++++++++++ 4 files changed, 69 insertions(+), 2 deletions(-) diff --git a/config/GM8E01_00/symbols.txt b/config/GM8E01_00/symbols.txt index f90055515..5691fc485 100644 --- a/config/GM8E01_00/symbols.txt +++ b/config/GM8E01_00/symbols.txt @@ -11683,7 +11683,7 @@ __ct__Q28COBBTree5CNodeFRC12CTransform4fRC9CVector3fPCQ28COBBTree5CNodePCQ28COBB GetTriangleEdgeIndices__8COBBTreeCFUs = .text:0x802A7F4C; // type:function size:0x14 scope:global 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 +__as__Q24rstl37vectorFRCQ24rstl37vector = .text:0x802A86B4; // type:function size:0xF8 __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 @@ -17679,7 +17679,10 @@ lbl_803D6008 = .rodata:0x803D6008; // type:object size:0x10 data:4byte @stringBase0 = .rodata:0x803D6018; // type:object size:0x7 scope:local data:string_table 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 +kEdgeMaterials$594 = .rodata:0x803D6038; // type:object size:0x12 scope:local data:byte +kTriangleMaterials$600 = .rodata:0x803D604C; // type:object size:0xC scope:local data:byte +kEdges$606 = .rodata:0x803D6058; // type:object size:0x48 scope:local data:2byte +kTriangleEdgeMaterials$612 = .rodata:0x803D60A0; // type:object size:0x48 scope:local data:2byte @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 diff --git a/include/WorldFormat/CCollisionEdge.hpp b/include/WorldFormat/CCollisionEdge.hpp index 8e3dcdf46..3543fee2e 100644 --- a/include/WorldFormat/CCollisionEdge.hpp +++ b/include/WorldFormat/CCollisionEdge.hpp @@ -7,6 +7,7 @@ class CCollisionEdge { public: + CCollisionEdge(const ushort x0, const ushort x1) : x0_index1(x0), x2_index2(x1) {} CCollisionEdge(CInputStream& in) { x0_index1 = in.Get< u16 >(); x2_index2 = in.Get< u16 >(); diff --git a/include/WorldFormat/COBBTree.hpp b/include/WorldFormat/COBBTree.hpp index 2de67b2c5..a40cf594f 100644 --- a/include/WorldFormat/COBBTree.hpp +++ b/include/WorldFormat/COBBTree.hpp @@ -5,6 +5,7 @@ #include "Kyoto/Math/CVector3f.hpp" #include "WorldFormat/CCollisionEdge.hpp" +#include "rstl/auto_ptr.hpp" #include "rstl/single_ptr.hpp" #include "rstl/vector.hpp" @@ -83,6 +84,9 @@ class COBBTree { COBBTree(const SIndexData& indexData, const CNode* root); ~COBBTree(); + + static rstl::auto_ptr< COBBTree > BuildOrientedBoundingBoxTree(const CVector3f& extent, const CVector3f& center); + CAABox CalculateLocalAABox() const; void GetTriangleVertexIndices(const ushort index, ushort out[2]) const; diff --git a/src/WorldFormat/COBBTree.cpp b/src/WorldFormat/COBBTree.cpp index 06fa6e089..0a533637e 100644 --- a/src/WorldFormat/COBBTree.cpp +++ b/src/WorldFormat/COBBTree.cpp @@ -1,6 +1,7 @@ #include "WorldFormat/COBBTree.hpp" #include "Kyoto/Streams/CInputStream.hpp" +#include #pragma inline_max_size(250) @@ -108,6 +109,64 @@ void COBBTree::CNode::operator delete(void* ptr, size_t size) { } } +rstl::auto_ptr< COBBTree > COBBTree::BuildOrientedBoundingBoxTree(const CVector3f& extent, + const CVector3f& center) { + CAABox aabb(extent * -0.5f + center, extent * 0.5f + center); + SIndexData indexData; + indexData.x0_materials.reserve(3); + indexData.x0_materials.push_back(0x40180000); + indexData.x0_materials.push_back(0x42180000); + indexData.x0_materials.push_back(0x41180000); + indexData.x10_vertMaterials = rstl::vector< uchar >(8, 0); + static const uchar kEdgeMaterials[] = { + 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 0, 2, 0, 0, 2, 2, + }; + indexData.x20_edgeMaterials.reserve(ARRAY_SIZE(kEdgeMaterials)); + for (size_t i = 0; i < ARRAY_SIZE(kEdgeMaterials); ++i) { + indexData.x20_edgeMaterials.push_back(kEdgeMaterials[i]); + } + + static const uchar kTriangleMaterials[] = { + 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, + }; + indexData.x30_surfaceMaterials.reserve(ARRAY_SIZE(kTriangleMaterials)); + for (size_t i = 0; i < ARRAY_SIZE(kTriangleMaterials); ++i) { + indexData.x30_surfaceMaterials.push_back(kTriangleMaterials[i]); + } + + static const ushort kEdges[] = { + 4, 1, 1, 5, 5, 4, 4, 0, 0, 1, 7, 2, 2, 6, 6, 7, 7, 3, + 3, 2, 6, 0, 4, 6, 2, 0, 5, 3, 7, 5, 1, 3, 6, 5, 0, 3, + }; + indexData.x40_edges.reserve(ARRAY_SIZE(kEdges)); + + for (int i = 0; i < ARRAY_SIZE(kEdges); i += 2) { + indexData.x40_edges.push_back(CCollisionEdge(kEdges[i], kEdges[i + 1])); + } + + static const ushort kTriangleEdgeMaterials[] = { + 0, 1, 2, 0, 3, 4, 5, 6, 7, 5, 8, 9, 10, 3, 11, 10, 6, 12, + 13, 8, 14, 13, 1, 15, 16, 14, 7, 16, 11, 2, 17, 15, 4, 17, 12, 9, + }; + + indexData.x50_surfaceIndices.reserve(ARRAY_SIZE(kTriangleEdgeMaterials)); + for (int i = 0; i < ARRAY_SIZE(kTriangleEdgeMaterials); i++) { + indexData.x50_surfaceIndices.push_back(kTriangleEdgeMaterials[i]); + } + + indexData.x60_vertices.reserve(8); + for (int i = 0; i < 8; ++i) { + indexData.x60_vertices.push_back(aabb.GetPoint(i)); + } + CNode::SetAllocator(nullptr); + + rstl::vector< ushort > surface; + surface.reserve(12); + for (int i = 0; i < 12; ++i) { + surface.push_back(i); + } + +} 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]]; From 4f285bb8e0f404d7e691c8f8f3076dad22c4b1be Mon Sep 17 00:00:00 2001 From: Phillip Stephens Date: Thu, 11 Jun 2026 10:26:52 -0700 Subject: [PATCH 3/4] Match COBBTree::BuildOrientedBoundingBoxTree --- include/WorldFormat/COBBTree.hpp | 27 ++++--- src/WorldFormat/COBBTree.cpp | 134 +++++++++++++++++-------------- 2 files changed, 86 insertions(+), 75 deletions(-) diff --git a/include/WorldFormat/COBBTree.hpp b/include/WorldFormat/COBBTree.hpp index a40cf594f..e85a49daf 100644 --- a/include/WorldFormat/COBBTree.hpp +++ b/include/WorldFormat/COBBTree.hpp @@ -11,18 +11,6 @@ #include "rstl/vector.hpp" class COBBTree { - struct SIndexData { - rstl::vector< uint > x0_materials; - rstl::vector< uchar > x10_vertMaterials; - rstl::vector< uchar > x20_edgeMaterials; - rstl::vector< uchar > x30_surfaceMaterials; - rstl::vector< CCollisionEdge > x40_edges; - rstl::vector< ushort > x50_surfaceIndices; - rstl::vector< CVector3f > x60_vertices; - SIndexData(); - SIndexData(CInputStream& in); - }; - public: class CSimpleAllocator { public: @@ -50,7 +38,7 @@ class COBBTree { private: rstl::vector< ushort > x0_surface; }; - + class CNode { public: CNode(const CTransform4f& xf, const CVector3f& point, const CNode* left, const CNode* right, @@ -80,6 +68,19 @@ class COBBTree { static CSimpleAllocator* spAllocator; }; + + struct SIndexData { + rstl::vector< uint > x0_materials; + rstl::vector< uchar > x10_vertMaterials; + rstl::vector< uchar > x20_edgeMaterials; + rstl::vector< uchar > x30_surfaceMaterials; + rstl::vector< CCollisionEdge > x40_edges; + rstl::vector< ushort > x50_surfaceIndices; + rstl::vector< CVector3f > x60_vertices; + SIndexData() {} + SIndexData(CInputStream& in); + }; + COBBTree(CInputStream& in); COBBTree(const SIndexData& indexData, const CNode* root); ~COBBTree(); diff --git a/src/WorldFormat/COBBTree.cpp b/src/WorldFormat/COBBTree.cpp index 0a533637e..4b1d676a6 100644 --- a/src/WorldFormat/COBBTree.cpp +++ b/src/WorldFormat/COBBTree.cpp @@ -1,5 +1,6 @@ #include "WorldFormat/COBBTree.hpp" +#include "Collision/CMaterialList.hpp" #include "Kyoto/Streams/CInputStream.hpp" #include @@ -56,67 +57,19 @@ CAABox COBBTree::CalculateLocalAABox() const { 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; - } -} - rstl::auto_ptr< COBBTree > COBBTree::BuildOrientedBoundingBoxTree(const CVector3f& extent, const CVector3f& center) { - CAABox aabb(extent * -0.5f + center, extent * 0.5f + center); + const CVector3f halfExtent = (extent * 0.5f); + const CVector3f negHalfExtent = (extent * -0.5f); + const CAABox aabb(negHalfExtent + center, halfExtent + center); SIndexData indexData; +#define BIT(x) ((uint)(1 << x)) indexData.x0_materials.reserve(3); - indexData.x0_materials.push_back(0x40180000); - indexData.x0_materials.push_back(0x42180000); - indexData.x0_materials.push_back(0x41180000); + indexData.x0_materials.push_back(BIT(kMT_Wall) | BIT(kMT_NoPlatformCollision) | BIT(kMT_Solid)); + indexData.x0_materials.push_back(BIT(kMT_Wall) | BIT(kMT_RedundantEdgeOrFlippedTri) | + BIT(kMT_NoPlatformCollision) | BIT(kMT_Solid)); + indexData.x0_materials.push_back(BIT(kMT_Wall) | BIT(kMT_NoEdgeCollision) | + BIT(kMT_NoPlatformCollision) | BIT(kMT_Solid)); indexData.x10_vertMaterials = rstl::vector< uchar >(8, 0); static const uchar kEdgeMaterials[] = { 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 0, 2, 0, 0, 2, 2, @@ -138,9 +91,9 @@ rstl::auto_ptr< COBBTree > COBBTree::BuildOrientedBoundingBoxTree(const CVector3 4, 1, 1, 5, 5, 4, 4, 0, 0, 1, 7, 2, 2, 6, 6, 7, 7, 3, 3, 2, 6, 0, 4, 6, 2, 0, 5, 3, 7, 5, 1, 3, 6, 5, 0, 3, }; - indexData.x40_edges.reserve(ARRAY_SIZE(kEdges)); + indexData.x40_edges.reserve(ARRAY_SIZE(kEdges) / 2); - for (int i = 0; i < ARRAY_SIZE(kEdges); i += 2) { + for (size_t i = 0; i < ARRAY_SIZE(kEdges); i += 2) { indexData.x40_edges.push_back(CCollisionEdge(kEdges[i], kEdges[i + 1])); } @@ -150,7 +103,7 @@ rstl::auto_ptr< COBBTree > COBBTree::BuildOrientedBoundingBoxTree(const CVector3 }; indexData.x50_surfaceIndices.reserve(ARRAY_SIZE(kTriangleEdgeMaterials)); - for (int i = 0; i < ARRAY_SIZE(kTriangleEdgeMaterials); i++) { + for (size_t i = 0; i < ARRAY_SIZE(kTriangleEdgeMaterials); i++) { indexData.x50_surfaceIndices.push_back(kTriangleEdgeMaterials[i]); } @@ -158,14 +111,19 @@ rstl::auto_ptr< COBBTree > COBBTree::BuildOrientedBoundingBoxTree(const CVector3 for (int i = 0; i < 8; ++i) { indexData.x60_vertices.push_back(aabb.GetPoint(i)); } - CNode::SetAllocator(nullptr); rstl::vector< ushort > surface; surface.reserve(12); - for (int i = 0; i < 12; ++i) { + for (ushort i = 0; i < 12; ++i) { surface.push_back(i); } + CNode::SetAllocator(nullptr); + CLeafData* leafData = rs_new CLeafData(surface); + CNode* root = + rs_new CNode(CTransform4f::Translate(center), halfExtent, nullptr, nullptr, leafData); + + return rs_new COBBTree(indexData, root); } void COBBTree::GetTriangleVertexIndices(const ushort index, ushort out[2]) const { const int surfIdx = (index * 3); @@ -189,6 +147,58 @@ void COBBTree::GetTriangleVertexIndices(const ushort index, ushort out[2]) const const ushort* COBBTree::GetTriangleEdgeIndices(const ushort index) const { return &x18_indexData.x50_surfaceIndices[index * 3]; } + +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; + } +} + COBBTree::CLeafData::CLeafData(const rstl::vector< ushort >& surface) : x0_surface(surface) {} COBBTree::CLeafData::CLeafData(CInputStream& in) : x0_surface(in) {} From e5fb4a0ab7c1cbd1b08c3eec189e8a581effe286 Mon Sep 17 00:00:00 2001 From: Phillip Stephens Date: Tue, 23 Jun 2026 15:09:55 -0700 Subject: [PATCH 4/4] More COBBTree --- config/GM8E01_00/symbols.txt | 6 +-- config/GM8E01_01/symbols.txt | 2 +- include/WorldFormat/CCollidableOBBTree.hpp | 28 +++++++++-- include/WorldFormat/COBBTree.hpp | 15 +++--- src/WorldFormat/CCollidableOBBTree.cpp | 55 ++++++++++++++++++++++ 5 files changed, 92 insertions(+), 14 deletions(-) create mode 100644 src/WorldFormat/CCollidableOBBTree.cpp diff --git a/config/GM8E01_00/symbols.txt b/config/GM8E01_00/symbols.txt index 5691fc485..d82e525e9 100644 --- a/config/GM8E01_00/symbols.txt +++ b/config/GM8E01_00/symbols.txt @@ -7660,7 +7660,7 @@ __ct__22CCameraShakerComponentFiRC17SCameraShakePointRC17SCameraShakePoint = .te GetSomething__17SCameraShakePointFv = .text:0x8015D2CC; // type:function size:0x1C scope:global fn_8015D2E8 = .text:0x8015D2E8; // type:function size:0xDC __ct__17SCameraShakePointFv = .text:0x8015D3C4; // type:function size:0x34 scope:global -LoadCameraShakePoint__R12CInputStream = .text:0x8015D3F8; // type:function size:0xAC scope:global +LoadCameraShakePoint__FR12CInputStream = .text:0x8015D3F8; // type:function size:0xAC scope:global __ct__17SCameraShakePointFiffff = .text:0x8015D4A4; // type:function size:0x20 scope:global BuildMissileShakeData__16CCameraShakeDataFfffRC9CVector3f = .text:0x8015D4C4; // type:function size:0x100 scope:global BuildPatternedExplodeShakeData__16CCameraShakeDataFRC9CVector3ffff = .text:0x8015D5C4; // type:function size:0x100 scope:global @@ -18742,7 +18742,7 @@ __vt__17CPoisonProjectile = .data:0x803EC390; // type:object size:0x74 scope:glo jumptable_803EC408 = .data:0x803EC408; // type:object size:0x20 scope:local lbl_803EC428 = .data:0x803EC428; // type:object size:0x10 lbl_803EC438 = .data:0x803EC438; // type:object size:0x10 -lbl_803EC448 = .data:0x803EC448; // type:object size:0x28 +__vt__18CCollidableOBBTree = .data:0x803EC448; // type:object size:0x28 __vt__23CCollidableOBBTreeGroup = .data:0x803EC470; // type:object size:0x28 scope:global __vt__60TObjOwnerDerivedFromIObj<32CCollidableOBBTreeGroupContainer> = .data:0x803EC498; // type:object size:0x10 jumptable_803EC4A8 = .data:0x803EC4A8; // type:object size:0x20 scope:local @@ -21277,7 +21277,7 @@ lbl_805A8620 = .sdata:0x805A8620; // type:object size:0x4 data:4byte lbl_805A8624 = .sdata:0x805A8624; // type:object size:0x4 data:4byte lbl_805A8628 = .sdata:0x805A8628; // type:object size:0x4 data:4byte lbl_805A862C = .sdata:0x805A862C; // type:object size:0x1 data:byte -lbl_805A8630 = .sdata:0x805A8630; // type:object size:0x8 data:4byte +sTableIndex__18CCollidableOBBTree = .sdata:0x805A8630; // type:object size:0x8 data:4byte lbl_805A8638 = .sdata:0x805A8638; // type:object size:0x8 data:4byte lbl_805A8640 = .sdata:0x805A8640; // type:object size:0x8 skGlobalSeed__17CProjectileWeapon = .sdata:0x805A8648; // type:object size:0x4 data:4byte diff --git a/config/GM8E01_01/symbols.txt b/config/GM8E01_01/symbols.txt index f2d4d415d..8e1221707 100644 --- a/config/GM8E01_01/symbols.txt +++ b/config/GM8E01_01/symbols.txt @@ -7660,7 +7660,7 @@ __ct__22CCameraShakerComponentFiRC17SCameraShakePointRC17SCameraShakePoint = .te GetSomething__17SCameraShakePointFv = .text:0x8015D348; // type:function size:0x1C scope:global fn_8015D2E8 = .text:0x8015D364; // type:function size:0xDC scope:global __ct__17SCameraShakePointFv = .text:0x8015D440; // type:function size:0x34 scope:global -LoadCameraShakePoint__R12CInputStream = .text:0x8015D474; // type:function size:0xAC scope:global +LoadCameraShakePoint__FR12CInputStream = .text:0x8015D474; // type:function size:0xAC scope:global __ct__17SCameraShakePointFiffff = .text:0x8015D520; // type:function size:0x20 scope:global BuildMissileShakeData__16CCameraShakeDataFfffRC9CVector3f = .text:0x8015D540; // type:function size:0x100 scope:global BuildPatternedExplodeShakeData__16CCameraShakeDataFRC9CVector3ffff = .text:0x8015D640; // type:function size:0x100 scope:global diff --git a/include/WorldFormat/CCollidableOBBTree.hpp b/include/WorldFormat/CCollidableOBBTree.hpp index 0592a1580..c028de328 100644 --- a/include/WorldFormat/CCollidableOBBTree.hpp +++ b/include/WorldFormat/CCollidableOBBTree.hpp @@ -3,17 +3,39 @@ #include +#include "WorldFormat/COBBTree.hpp" + class COBBTree; +class COBBox; class CCollidableOBBTree : public CCollisionPrimitive { - public: - CCollidableOBBTree(const COBBTree& tree, const CMaterialList& list); + CCollidableOBBTree(COBBTree* tree, const CMaterialList& list); uint GetTableIndex() const override; CAABox CalculateAABox(const CTransform4f& xf) const override; - const CAABox CalculateLocalAABox() const override; + CAABox CalculateLocalAABox() const override; FourCC GetPrimType() const override; CRayCastResult CastRayInternal(const CInternalRayCastStructure& intRayCast) const override; + + bool AABoxCollision(const COBBTree::CNode& node, const CTransform4f& xf, const CAABox& abb, + const COBBox& obb, const CMaterialList& matList, + const CMaterialFilter& matFilter, const CPlane plane[6], + CCollisionInfoList& outList) const; + bool AABoxCollideWithLeaf(const COBBTree::CLeafData&, const CTransform4f&, const CAABox&, + const CMaterialList&, const CMaterialFilter&, const CPlane*, + CCollisionInfoList&) const; + + void ResetTestStats() const {} + + void ResetTestStatsRecurse(const COBBTree::CNode& node) const {} + +private: + COBBTree* x10_tree; + mutable uint x14_tries; + mutable uint x18_misses; + mutable uint x1c_hits; + + static uint sTableIndex; }; #endif // _CCOLLIDABLEOBBTREE diff --git a/include/WorldFormat/COBBTree.hpp b/include/WorldFormat/COBBTree.hpp index e85a49daf..239895a84 100644 --- a/include/WorldFormat/COBBTree.hpp +++ b/include/WorldFormat/COBBTree.hpp @@ -38,7 +38,7 @@ class COBBTree { private: rstl::vector< ushort > x0_surface; }; - + class CNode { public: CNode(const CTransform4f& xf, const CVector3f& point, const CNode* left, const CNode* right, @@ -53,7 +53,8 @@ class COBBTree { 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; } + void SetHit(const bool hit) const { x4c_hit = hit; } + const CLeafData* GetLeafData() const { return x48_leaf; } static void* operator new(size_t size, const char* file, int line); static void operator delete(void* ptr, size_t size); @@ -64,11 +65,11 @@ class COBBTree { const CNode* x40_left; const CNode* x44_right; const CLeafData* x48_leaf; - bool x4c_hit; + mutable bool x4c_hit; static CSimpleAllocator* spAllocator; }; - + struct SIndexData { rstl::vector< uint > x0_materials; rstl::vector< uchar > x10_vertMaterials; @@ -85,9 +86,9 @@ class COBBTree { COBBTree(const SIndexData& indexData, const CNode* root); ~COBBTree(); - - static rstl::auto_ptr< COBBTree > BuildOrientedBoundingBoxTree(const CVector3f& extent, const CVector3f& center); - + static rstl::auto_ptr< COBBTree > BuildOrientedBoundingBoxTree(const CVector3f& extent, + const CVector3f& center); + CAABox CalculateLocalAABox() const; void GetTriangleVertexIndices(const ushort index, ushort out[2]) const; diff --git a/src/WorldFormat/CCollidableOBBTree.cpp b/src/WorldFormat/CCollidableOBBTree.cpp new file mode 100644 index 000000000..78e956ee0 --- /dev/null +++ b/src/WorldFormat/CCollidableOBBTree.cpp @@ -0,0 +1,55 @@ +#include "WorldFormat/CCollidableOBBTree.hpp" + +#include "WorldFormat/COBBTree.hpp" + +uint CCollidableOBBTree::sTableIndex = -1; + +CCollidableOBBTree::CCollidableOBBTree(COBBTree* tree, const CMaterialList& material) +: CCollisionPrimitive(material), x10_tree(tree), x14_tries(0), x18_misses(0), x1c_hits(0) {} + +CAABox CCollidableOBBTree::CalculateAABox(const CTransform4f& xf) const { + const COBBox obbox = COBBox::FromAABox(x10_tree->CalculateLocalAABox(), xf); + return obbox.CalculateAABox(CTransform4f::Identity()); +} + +CAABox CCollidableOBBTree::CalculateLocalAABox() const { return x10_tree->CalculateLocalAABox(); } + +FourCC CCollidableOBBTree::GetPrimType() const { return 'OBBT'; } + +bool CCollidableOBBTree::AABoxCollision(const COBBTree::CNode& node, const CTransform4f& xf, + const CAABox& abb, const COBBox& obb, + const CMaterialList& matList, + const CMaterialFilter& matFilter, const CPlane planes[6], + CCollisionInfoList& outList) const { + + bool ret = false; + + x14_tries++; + + if (obb.OBBIntersectsBox(node.GetOBB())) { + node.SetHit(true); + if (node.IsLeaf()) { + if (AABoxCollideWithLeaf(*node.GetLeafData(), xf, abb, matList, matFilter, planes, outList)) { + ret = true; + } + } else { + if (AABoxCollision(*node.GetLeftNode(), xf, abb, obb, matList, matFilter, planes, outList)) { + ret = true; + } + if (AABoxCollision(*node.GetRightNode(), xf, abb, obb, matList, matFilter, planes, outList)) { + ret = true; + } + } + } else { + x18_misses++; + } + return ret; +} + +CPlane TransformPlane(const CPlane& plane, const CTransform4f& xf) { + const CVector3f dVec = xf * (plane.GetNormal() * plane.GetConstant()); + const CVector3f normal = xf.Rotate(plane.GetNormal()); + return CPlane(dVec, CUnitVector3f(normal.GetX(), normal.GetY(), normal.GetZ())); +} + +uint CCollidableOBBTree::GetTableIndex() const { return sTableIndex; } \ No newline at end of file