diff --git a/config/GM8E01_00/symbols.txt b/config/GM8E01_00/symbols.txt index f1da57b7..d82e525e 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 @@ -11683,8 +11683,8 @@ __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 -fn_802A87AC = .text:0x802A87AC; // type:function size:0x238 +__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 GetSurface__8COBBTreeCFUs = .text:0x802A8BBC; // type:function size:0xF4 scope:global @@ -17679,8 +17679,11 @@ 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 -lbl_803D60E8 = .rodata:0x803D60E8; // type:object size:0x7 data:string +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 lbl_803D6118 = .rodata:0x803D6118; // type:object size:0x20 @@ -18739,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 @@ -21274,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 @@ -21923,7 +21926,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..8e122170 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 @@ -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/CCollidableOBBTree.hpp b/include/WorldFormat/CCollidableOBBTree.hpp index 0592a158..c028de32 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/CCollisionEdge.hpp b/include/WorldFormat/CCollisionEdge.hpp index 7255fd66..3543fee2 100644 --- a/include/WorldFormat/CCollisionEdge.hpp +++ b/include/WorldFormat/CCollisionEdge.hpp @@ -7,16 +7,18 @@ class CCollisionEdge { public: - CCollisionEdge(CInputStream& in){ - x0_index1 = in.Get(); - x2_index2 = in.Get(); + 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 >(); } - 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..239895a8 100644 --- a/include/WorldFormat/COBBTree.hpp +++ b/include/WorldFormat/COBBTree.hpp @@ -1,14 +1,75 @@ #ifndef _COBBTREE #define _COBBTREE +#include "Collision/COBBox.hpp" #include "Kyoto/Math/CVector3f.hpp" #include "WorldFormat/CCollisionEdge.hpp" +#include "rstl/auto_ptr.hpp" +#include "rstl/single_ptr.hpp" #include "rstl/vector.hpp" class COBBTree { - class CNode {}; +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(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); + + private: + COBBox x0_obb; + bool x3c_isLeaf; + const CNode* x40_left; + const CNode* x44_right; + const CLeafData* x48_leaf; + mutable bool x4c_hit; + + static CSimpleAllocator* spAllocator; + }; + struct SIndexData { rstl::vector< uint > x0_materials; rstl::vector< uchar > x10_vertMaterials; @@ -17,16 +78,29 @@ class COBBTree { rstl::vector< CCollisionEdge > x40_edges; rstl::vector< ushort > x50_surfaceIndices; rstl::vector< CVector3f > x60_vertices; + SIndexData() {} SIndexData(CInputStream& in); }; -public: COBBTree(CInputStream& in); 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; + 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/CCollidableOBBTree.cpp b/src/WorldFormat/CCollidableOBBTree.cpp new file mode 100644 index 00000000..78e956ee --- /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 diff --git a/src/WorldFormat/COBBTree.cpp b/src/WorldFormat/COBBTree.cpp index 3df986f4..4b1d676a 100644 --- a/src/WorldFormat/COBBTree.cpp +++ b/src/WorldFormat/COBBTree.cpp @@ -1,9 +1,13 @@ #include "WorldFormat/COBBTree.hpp" +#include "Collision/CMaterialList.hpp" #include "Kyoto/Streams/CInputStream.hpp" +#include #pragma inline_max_size(250) +COBBTree::CSimpleAllocator* COBBTree::CNode::spAllocator = nullptr; + COBBTree::SIndexData::SIndexData(CInputStream& in) : x0_materials(in) , x10_vertMaterials(in) @@ -13,4 +17,216 @@ 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); +} + +rstl::auto_ptr< COBBTree > COBBTree::BuildOrientedBoundingBoxTree(const CVector3f& extent, + const CVector3f& 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(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, + }; + 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) / 2); + + for (size_t 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 (size_t 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)); + } + + rstl::vector< ushort > surface; + surface.reserve(12); + 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); + 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::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) {} + +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