#include "Runtime/Graphics/CPVSVisSet.hpp" #include "Runtime/Graphics/CPVSVisOctree.hpp" namespace metaforce { void CPVSVisSet::Reset(EPVSVisSetState state) { x0_state = state; x4_numBits = 0; x8_numLights = 0; // xc_ = false; x10_ptr = nullptr; } EPVSVisSetState CPVSVisSet::GetVisible(u32 idx) const { 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 + idx; 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::SetFromMemory(u32 numBits, u32 numLights, const u8* leafPtr) { x0_state = EPVSVisSetState::NodeFound; x4_numBits = numBits; x8_numLights = numLights; x10_ptr = leafPtr; } 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 += 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.GetNumObjects(), octree.GetNumLights(), octCur); break; case 0x10: Reset(EPVSVisSetState::EndOfTree); break; case 0x08: default: Reset(EPVSVisSetState::OutOfBounds); break; } } } // namespace metaforce