public QuadTreeWalker(Terrain *terrain, Aabb aabb) { m_Terrain = terrain; m_LevelIndex = 0; m_Index = 0; m_ChildIndex = 0; Bounds = new FourTransposedAabbs(); // Initialize the stack with a single node fixed(int *stack = m_Stack) { m_Top = stack; // Clamp the query AABB to the terrain bounds int2 min = math.clamp((int2)aabb.Min.xz, 0, terrain->Size - 2); // Size - 1 is number of quads, Size - 2 is the highest valid quad index int2 max = math.clamp((int2)aabb.Max.xz, 0, terrain->Size - 2); // Find the deepest node that fully contains the query AABB, by finding the highest bit in which the AABB min and max differ // We can begin the query from that node instead of the root, and this is much faster than traversing the tree. int level = 0; int2 diffs = min ^ max; int diff = diffs.x | diffs.y; int bit = 1 << (terrain->Levels.Length - 1); while ((diff & bit) == 0 && bit > 1) { level++; bit = bit >> 1; } int2 coord = min >> (terrain->Levels.Length - level); // Push the node onto the stack *m_Top = level; *(m_Top + k_StackSize) = coord.x; *(m_Top + k_StackSize + k_StackSize) = coord.y; m_Top++; } }
// If the stack is not empty, removes the top node and sets the current state from it, then returns true. // Otherwise returns false. public bool Pop() { fixed(int *stack = m_Stack) { if (m_Top == stack) { return(false); // stack is empty } } m_Top--; m_LevelIndex = *m_Top; m_Index = new int2(*(m_Top + k_StackSize), *(m_Top + k_StackSize + k_StackSize)); // Get the node Level level = m_Terrain->Levels[m_LevelIndex]; int levelOffset = (m_Index.y & ~1) * level.Pitch + ((m_Index.y & 1) << 1) + ((m_Index.x & ~1) << 1) + (m_Index.x & 1); // swizzled, see comment on Nodes Node node = m_Terrain->Nodes[level.Base + levelOffset]; // Calculate the AABBs of the node's children m_ChildIndex = m_Index + m_Index; float3 boundsX = (float3)(m_ChildIndex.x + new int3(0, 1, 2)) * level.Scale; float3 boundsZ = (float3)(m_ChildIndex.y + new int3(0, 1, 2)) * level.Scale; Bounds = new FourTransposedAabbs { Lx = boundsX.xyxy, Hx = boundsX.yzyz, Lz = boundsZ.xxyy, Hz = boundsZ.yyzz, Ly = node.Min4, Hy = node.Max4 }; return(true); }