UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

147 lines (111 loc) 4.46 kB
import { assert } from "../../assert.js"; import { NULL_NODE } from "./BVH.js"; const CAME_FROM_TYPE_PARENT = 0; const CAME_FROM_TYPE_CHILD_1 = 1; const CAME_FROM_TYPE_CHILD_2 = 2; /** * Traverses the tree bottom-up, updating bounds as it goes * @param {BVH} bvh * @param {number} root * @returns {void} */ export function ebvh_update_hierarchy_bounds(bvh, root = bvh.root) { assert.isNonNegativeInteger(root, 'root'); if (root === NULL_NODE) { // special case return; } if (bvh.node_is_leaf(root)) { // special case return; } // we traverse depth-first using stack-less scheme let came_from_node = root; let came_from_type = CAME_FROM_TYPE_PARENT; let node = bvh.node_get_child1(came_from_node); if (node === NULL_NODE) { node = bvh.node_get_child2(came_from_node); } if (node === NULL_NODE) { // no children, done return; } // do a stackless traversal while (true) { if ( came_from_type === CAME_FROM_TYPE_CHILD_2 ) { // moving up last time, lets calculate const child_1 = bvh.node_get_child1(node); const child_2 = bvh.node_get_child2(node); bvh.node_set_combined_aabb(node, child_1, child_2); } // only add to treelet when traversing up, not down if (bvh.node_is_leaf(node)) { assert.equal(came_from_type, CAME_FROM_TYPE_PARENT); const parent = came_from_node; const parent_child_1 = bvh.node_get_child1(parent); if (parent_child_1 === node) { came_from_type = CAME_FROM_TYPE_CHILD_1; } else { came_from_type = CAME_FROM_TYPE_CHILD_2; } came_from_node = node; node = parent; } else if (came_from_type === CAME_FROM_TYPE_CHILD_2) { // finishing traversal of this branch came_from_node = node; const parent = bvh.node_get_parent(node); if (bvh.node_get_child1(parent) === node) { came_from_type = CAME_FROM_TYPE_CHILD_1; } else { came_from_type = CAME_FROM_TYPE_CHILD_2; } if (node === root) { // traversed all the way back up break; } node = parent; } else if (came_from_type === CAME_FROM_TYPE_CHILD_1) { // traversing up from left child const child2 = bvh.node_get_child2(node); came_from_node = node; if (child2 === NULL_NODE) { // no right child, finish this branch came_from_type = CAME_FROM_TYPE_CHILD_2; // indicate end node = bvh.node_get_parent(node); } else { came_from_type = CAME_FROM_TYPE_PARENT; node = child2; } } else if (came_from_type === CAME_FROM_TYPE_PARENT) { const child1 = bvh.node_get_child1(node); const child2 = bvh.node_get_child1(node); if (child1 !== NULL_NODE) { came_from_type = CAME_FROM_TYPE_PARENT; came_from_node = node; node = child1; } else if (child2 !== NULL_NODE) { came_from_type = CAME_FROM_TYPE_PARENT; came_from_node = node; node = child2; } else { // this should not happen, as this would mean that node is empty and completely pointless // we remove the node and traverse up const parent_child1 = bvh.node_get_child1(came_from_node); bvh.release_node(node); if (parent_child1 === node) { // we are left child bvh.node_set_child1(came_from_node, NULL_NODE); came_from_node = NULL_NODE; came_from_type = CAME_FROM_TYPE_CHILD_1; } else { bvh.node_set_child2(came_from_node, NULL_NODE); came_from_node = NULL_NODE; came_from_type = CAME_FROM_TYPE_CHILD_2; } node = came_from_node; } } } }