#ifndef OCTREE_H #define OCTREE_H #include #include #include #include //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