2026-02-20 16:12:16 +01:00

165 lines
5.4 KiB
C

#ifndef OCTREE_H
#define OCTREE_H
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
//This was vibecoded #FML
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
float x, y, z;
} oct_vec3;
typedef struct {
oct_vec3 min;
oct_vec3 max;
} oct_box;
typedef struct {
uint32_t first_child; // Index of first child in the pool, 0 if leaf
uint16_t count; // Number of items in this node
uint16_t data_offset; // Index into the data array
} oct_node;
typedef struct {
oct_node* nodes;
uint32_t* data; // Indices of your objects
uint32_t node_count;
uint32_t node_capacity;
uint32_t data_count;
uint32_t data_capacity;
oct_box bounds;
int max_depth;
} octree_t;
// --- Public API ---
void octree_init(octree_t* tree, oct_box bounds, int max_depth, uint32_t initial_cap);
void octree_free(octree_t* tree);
bool octree_insert(octree_t* tree, uint32_t item_id, oct_vec3 pos);
// Note: For thread safety, wrap insert in a mutex. Query can be lock-free if no inserts happen.
#ifdef __cplusplus
}
#endif
#endif // OCTREE_H
// --------------------------------------------------------------------------
#ifdef OCTREE_IMPLEMENTATION
static bool oct_box_contains(oct_box b, oct_vec3 p) {
return (p.x >= b.min.x && p.x <= b.max.x &&
p.y >= b.min.y && p.y <= b.max.y &&
p.z >= b.min.z && p.z <= b.max.z);
}
void octree_init(octree_t* tree, oct_box bounds, int max_depth, uint32_t initial_cap) {
tree->bounds = bounds;
tree->max_depth = max_depth;
tree->node_capacity = initial_cap;
tree->nodes = (oct_node*)calloc(initial_cap, sizeof(oct_node));
tree->node_count = 1; // Root is at index 0
tree->data_capacity = initial_cap * 4;
tree->data = (uint32_t*)malloc(tree->data_capacity * sizeof(uint32_t));
tree->data_count = 0;
}
void octree_free(octree_t* tree) {
free(tree->nodes);
free(tree->data);
}
// Internal: Splits a node into 8 children
static void oct_node_split(octree_t* tree, uint32_t node_idx, oct_box node_box) {
if (tree->node_count + 8 > tree->node_capacity) {
tree->node_capacity *= 2;
tree->nodes = (oct_node*)realloc(tree->nodes, tree->node_capacity * sizeof(oct_node));
}
tree->nodes[node_idx].first_child = tree->node_count;
tree->node_count += 8;
// Initialize children...
for(int i = 0; i < 8; ++i) {
tree->nodes[tree->nodes[node_idx].first_child + i] = (oct_node){0};
}
}
// Implementation of octree_insert would go here...
// It would traverse indices and check oct_box_contains.
// Internal helper to get the bounding box of a specific child
static oct_box oct_get_child_box(oct_box parent, int child_idx) {
oct_vec3 center = {
(parent.min.x + parent.max.x) * 0.5f,
(parent.min.y + parent.max.y) * 0.5f,
(parent.min.z + parent.max.z) * 0.5f
};
oct_box child = parent;
// Bit 0: X, Bit 1: Y, Bit 2: Z
if (child_idx & 1) child.min.x = center.x; else child.max.x = center.x;
if (child_idx & 2) child.min.y = center.y; else child.max.y = center.y;
if (child_idx & 4) child.min.z = center.z; else child.max.z = center.z;
return child;
}
// Recursive insert (Internal)
static bool oct_insert_internal(octree_t* tree, uint32_t node_idx, oct_box node_box, uint32_t item_id, oct_vec3 pos, int depth) {
// 1. If we are at max depth or it's a leaf with space, store it
// For simplicity, this version pushes everything to leaves:
if (depth >= tree->max_depth) {
// Handle data array resizing
if (tree->data_count >= tree->data_capacity) {
tree->data_capacity *= 2;
tree->data = (uint32_t*)realloc(tree->data, tree->data_capacity * sizeof(uint32_t));
}
// In a real STB-style, you'd link data to the node here
// For now, we'll just track that the node has data
tree->nodes[node_idx].count++;
tree->data[tree->data_count++] = item_id;
return true;
}
// 2. If leaf, split it
if (tree->nodes[node_idx].first_child == 0) {
oct_node_split(tree, node_idx, node_box);
}
// 3. Determine which child the point belongs to
oct_vec3 center = {
(node_box.min.x + node_box.max.x) * 0.5f,
(node_box.min.y + node_box.max.y) * 0.5f,
(node_box.min.z + node_box.max.z) * 0.5f
};
int child_idx = 0;
if (pos.x >= center.x) child_idx |= 1;
if (pos.y >= center.y) child_idx |= 2;
if (pos.z >= center.z) child_idx |= 4;
uint32_t next_node = tree->nodes[node_idx].first_child + child_idx;
oct_box next_box = oct_get_child_box(node_box, child_idx);
return oct_insert_internal(tree, next_node, next_box, item_id, pos, depth + 1);
}
bool octree_insert(octree_t* tree, uint32_t item_id, oct_vec3 pos) {
if (!oct_box_contains(tree->bounds, pos)) return false;
return oct_insert_internal(tree, 0, tree->bounds, item_id, pos, 0);
}
// Thread-safe query (No writes/allocations)
void octree_query_sphere(const octree_t* tree, oct_vec3 center, float radius, void (*callback)(uint32_t)) {
// This would implement a standard stack-based or recursive search
// checking if the sphere overlaps the node_box.
}
#endif // OCTREE_IMPLEMENTATION