@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
147 lines (111 loc) • 4.46 kB
JavaScript
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;
}
}
}
}