diff options
Diffstat (limited to 'src/modules/sparkler/bsp.c')
| -rw-r--r-- | src/modules/sparkler/bsp.c | 56 | 
1 files changed, 56 insertions, 0 deletions
| diff --git a/src/modules/sparkler/bsp.c b/src/modules/sparkler/bsp.c index ae5a20e..f55501a 100644 --- a/src/modules/sparkler/bsp.c +++ b/src/modules/sparkler/bsp.c @@ -574,3 +574,59 @@ void bsp_search_sphere(bsp_t *bsp, v3f_t *center, float radius_min, float radius  	_bsp_search_sphere(bsp, &bsp->root, &search, &aabb_min, &aabb_max);  } + + +static void _bsp_walk_leaves(const bsp_t *bsp, const bsp_node_t *node, unsigned depth, const v3f_t *aabb_min, const v3f_t *aabb_max, void (*cb)(const bsp_t *bsp, const list_head_t *occupants, unsigned depth, const v3f_t *bv_min, const v3f_t *bv_max, void *cb_data), void *cb_data) +{ +	v3f_t	oaabb_min, oaabb_max; + +	/* if node is a leaf, call cb with the occupants, then return. */ +	if (!node->octrants) +		return cb(bsp, &node->occupants, depth, aabb_min, aabb_max, cb_data); + +	/* node is a parent, recur on each octrant with appropriately adjusted aabb_min:aabb_max values */ +	/* if any of the octrants absolutely overlaps the search sphere, skip the others by returning. */ +#define walk_octrant(_oid, _aabb_min, _aabb_max)					\ +	_bsp_walk_leaves(bsp, &node->octrants[_oid], depth + 1, _aabb_min, _aabb_max, cb, cb_data); + +	/* OCT_XL_YL_ZL and OCT_XR_YR_ZR AABBs don't require tedious composition */ +	walk_octrant(OCT_XL_YL_ZL, aabb_min, &node->center); +	walk_octrant(OCT_XR_YR_ZR, &node->center, aabb_max); + +	/* the rest are stitched together requiring temp storage and tedium */ +	v3f_set(&oaabb_min, node->center.x, aabb_min->y, aabb_min->z); +	v3f_set(&oaabb_max, aabb_max->x, node->center.y, node->center.z); +	walk_octrant(OCT_XR_YL_ZL, &oaabb_min, &oaabb_max); + +	v3f_set(&oaabb_min, aabb_min->x, node->center.y, aabb_min->z); +	v3f_set(&oaabb_max, node->center.x, aabb_max->y, node->center.z); +	walk_octrant(OCT_XL_YR_ZL, &oaabb_min, &oaabb_max); + +	v3f_set(&oaabb_min, node->center.x, node->center.y, aabb_min->z); +	v3f_set(&oaabb_max, aabb_max->x, aabb_max->y, node->center.z); +	walk_octrant(OCT_XR_YR_ZL, &oaabb_min, &oaabb_max); + +	v3f_set(&oaabb_min, aabb_min->x, aabb_min->y, node->center.z); +	v3f_set(&oaabb_max, node->center.x, node->center.y, aabb_max->z); +	walk_octrant(OCT_XL_YL_ZR, &oaabb_min, &oaabb_max); + +	v3f_set(&oaabb_min, node->center.x, aabb_min->y, node->center.z); +	v3f_set(&oaabb_max, aabb_max->x, node->center.y, aabb_max->z); +	walk_octrant(OCT_XR_YL_ZR, &oaabb_min, &oaabb_max); + +	v3f_set(&oaabb_min, aabb_min->x, node->center.y, node->center.z); +	v3f_set(&oaabb_max, node->center.x, aabb_max->y, aabb_max->z); +	walk_octrant(OCT_XL_YR_ZR, &oaabb_min, &oaabb_max); + +#undef walk_octrant +} + + +/* traverse the bsp tree calling cb for every leaf node, no discriminating of positions */ +void bsp_walk_leaves(const bsp_t *bsp, void (*cb)(const bsp_t *bsp, const list_head_t *occupants, unsigned depth, const v3f_t *bv_min, const v3f_t *bv_max, void *cb_data), void *cb_data) +{ +	v3f_t	aabb_min = v3f_init(-1.0f, -1.0f, -1.0f); +	v3f_t	aabb_max = v3f_init(1.0f, 1.0f, 1.0f); + +	_bsp_walk_leaves(bsp, &bsp->root, 0, &aabb_min, &aabb_max, cb, cb_data); +} | 
