diff --git a/oogabooga/examples/growing_array_example.c b/oogabooga/examples/growing_array_example.c new file mode 100644 index 0000000..5ec001a --- /dev/null +++ b/oogabooga/examples/growing_array_example.c @@ -0,0 +1,74 @@ + +typedef struct Circle { + Vector2 pos; + float radius; +} Circle; + +int entry(int argc, char **argv) { + + window.title = STR("Minimal Game Example"); + window.scaled_width = 1280; // We need to set the scaled size if we want to handle system scaling (DPI) + window.scaled_height = 720; + window.x = 200; + window.y = 90; + window.clear_color = hex_to_rgba(0x6495EDff); + + Circle *circles; + growing_array_init((void**)&circles, sizeof(Circle), get_heap_allocator()); + + const int num_circles = 10000; + const float radius_min = 8.0; + const float radius_max = 32.0; + + const float hover_radius = 200; + + os_update(); // We set scaled window size, os_update updates the pixel window size values for us + + for (int i = 0; i < num_circles; i++) { + Circle c; + c.radius = get_random_float32_in_range(radius_min, radius_max); + c.pos.x = get_random_float32_in_range(-(f32)window.width/2.0+c.radius, (f32)window.width/2.0-c.radius); + c.pos.y = get_random_float32_in_range(-(f32)window.height/2.0+c.radius, (f32)window.height/2.0-c.radius); + growing_array_add((void**)&circles, &c); + assert(circles[i].radius == c.radius); + assert(circles[i].pos.x == c.pos.x); + assert(circles[i].pos.y == c.pos.y); + } + + float64 last_time = os_get_current_time_in_seconds(); + while (!window.should_close) { + float64 now = os_get_current_time_in_seconds(); + if ((int)now != (int)last_time) log("%.2f FPS\n%.2fms", 1.0/(now-last_time), (now-last_time)*1000); + last_time = now; + + reset_temporary_storage(); + + draw_frame.projection = m4_make_orthographic_projection(window.pixel_width * -0.5, window.pixel_width * 0.5, window.pixel_height * -0.5, window.pixel_height * 0.5, -1, 10); + + + float mx = input_frame.mouse_x - window.width/2; + float my = input_frame.mouse_y - window.height/2; + + // We build an array on the fly each frame for all the hovered circles + Circle *circles_hovered; + growing_array_init_reserve((void**)&circles_hovered, sizeof(Circle), num_circles, get_temporary_allocator()); + for (int i = 0; i < num_circles; i++) { + float distance = v2_length(v2_sub(v2(mx, my), circles[i].pos)); + if (distance <= hover_radius) { + growing_array_add((void**)&circles_hovered, &circles[i]); + } + } + + + + for (int i = 0; i < growing_array_get_valid_count(circles_hovered); i++) { + Circle c = circles_hovered[i]; + draw_circle(v2_sub(c.pos, v2(c.radius, c.radius)), v2(c.radius, c.radius), COLOR_GREEN); + } + + os_update(); + gfx_update(); + } + + return 0; +} \ No newline at end of file diff --git a/oogabooga/growing_array.c b/oogabooga/growing_array.c new file mode 100644 index 0000000..128a94e --- /dev/null +++ b/oogabooga/growing_array.c @@ -0,0 +1,261 @@ + +/* + + Thing *things; + growing_array_init(&things, sizeof(Thing)); + + growing_array_deinit(&things); + + Thing new_thing; + growing_array_add(&things, &new_thing); // 'thing' is copied + + Thing *nth_thing = &things[n]; + + growing_array_reserve_count(&things, 690); + growing_array_resize_count(&things, 69); + + // "Slow", but stuff in the array keeps the same order + growing_array_ordered_remove_by_index(&things, i); + + // Fast, but will not keep stuff ordered + growing_array_unordered_remove_by_index(&things, i); + + growing_array_ordered_remove_by_pointer(&things, nth_thing); + growing_array_unordered_remove_by_pointer(&things, nth_thing); + + Thing thing_prototype; + growing_array_ordered_remove_one_by_value(&things, thing_prototype); + growing_array_unordered_remove_one_by_value(&things, thing_prototype); + growing_array_ordered_remove_all_by_value(&things, thing_prototype); + growing_array_unordered_remove_all_by_value(&things, thing_prototype); + + growing_array_get_valid_count(&things); + growing_array_get_allocated_count(&things); + +*/ + +typedef struct Growing_Array_Header { + u32 valid_count; + u32 allocated_count; + u32 block_size_in_bytes; + Allocator allocator; +} Growing_Array_Header; + + +void +growing_array_init_reserve(void **array, u64 block_size_in_bytes, u64 count_to_reserve, Allocator allocator) { + + count_to_reserve = get_next_power_of_two(count_to_reserve); + u64 bytes_to_allocate = count_to_reserve*block_size_in_bytes + sizeof(Growing_Array_Header); + + Growing_Array_Header *header = (Growing_Array_Header*)alloc(allocator, bytes_to_allocate); + + header->allocator = allocator; + header->block_size_in_bytes = block_size_in_bytes; + header->valid_count = 0; + header->allocated_count = count_to_reserve; + + *array = header+1; +} +void +growing_array_init(void **array, u64 block_size_in_bytes, Allocator allocator) { + growing_array_init_reserve(array, block_size_in_bytes, 8, allocator); +} +void +growing_array_deinit(void **array) { + Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1; + dealloc(header->allocator, header); +} + +void +growing_array_reserve(void **array, u64 count_to_reserve) { + Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1; + + if (header->allocated_count >= count_to_reserve) return; + + u64 old_allocated_bytes = header->allocated_count*header->block_size_in_bytes+sizeof(Growing_Array_Header); + count_to_reserve = get_next_power_of_two(count_to_reserve); + u64 bytes_to_allocate = count_to_reserve*header->block_size_in_bytes+sizeof(Growing_Array_Header); + Growing_Array_Header *new_header = (Growing_Array_Header*)alloc(header->allocator, bytes_to_allocate); + + memcpy(new_header, header, old_allocated_bytes); + + + *array = new_header+1; + + new_header->allocated_count = count_to_reserve; + + dealloc(header->allocator, header); +} + +void* +growing_array_add_empty(void **array) { + Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1; + growing_array_reserve(array, header->valid_count+1); + + // Pointer might have been invalidated after reserve + header = ((Growing_Array_Header*)*array) - 1; + + void *item = (u8*)*array + header->valid_count*header->block_size_in_bytes; + + header->valid_count += 1; + + return item; +} +void +growing_array_add(void **array, void *item) { + + void *new = growing_array_add_empty(array); + + Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1; + + memcpy(new, item, header->block_size_in_bytes); +} + +void growing_array_resize(void **array, u64 new_count) { + growing_array_reserve(array, new_count); + Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1; + header->valid_count = new_count; +} + +void growing_array_pop(void **array) { + Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1; + assert(header->valid_count > 0, "No items to pop in growing array"); + header->valid_count -= 1; +} + +void growing_array_clear(void **array) { + Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1; + header->valid_count = 0; +} + +void +growing_array_ordered_remove_by_index(void **array, u32 index) { + Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1; + assert(index < header->valid_count, "Growing array index out of range"); + + if (index == header->valid_count-1) { + growing_array_pop(array); + return; + } + + u64 byte_index = header->block_size_in_bytes*index; + + memcpy( + (u8*)*array + byte_index, + (u8*)*array + byte_index + header->block_size_in_bytes, + (header->valid_count-index-1)*header->block_size_in_bytes + ); + header->valid_count -= 1; +} +void +growing_array_unordered_remove_by_index(void **array, u32 index) { + Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1; + assert(index < header->valid_count, "Growing array index out of range"); + + if (index == header->valid_count-1) { + growing_array_pop(array); + return; + } + + u64 byte_index = header->block_size_in_bytes*index; + u64 last_item_index = header->block_size_in_bytes*header->valid_count-header->block_size_in_bytes; + + memcpy( + (u8*)*array + byte_index, + (u8*)*array + last_item_index, + header->block_size_in_bytes + ); + header->valid_count -= 1; +} + +s32 +growing_array_find_index_from_left_by_pointer(void **array, void *p) { + Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1; + + for (u32 i = 0; i < header->valid_count; i++) { + void *next = (u8*)*array + i*header->block_size_in_bytes; + + if (next == p) { + return i; + } + } + return -1; +} +s32 +growing_array_find_index_from_left_by_value(void **array, void *p) { + Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1; + + for (u32 i = 0; i < header->valid_count; i++) { + void *next = (u8*)*array + i*header->block_size_in_bytes; + + if (bytes_match(next, p, header->block_size_in_bytes)) { + return i; + } + } + return -1; +} + +bool +growing_array_ordered_remove_by_pointer(void **array, void *p) { + Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1; + + s32 i = growing_array_find_index_from_left_by_pointer(array, p); + + if (i < 0) return false; + + growing_array_ordered_remove_by_index(array, i); + + return true; +} +bool +growing_array_unordered_remove_by_pointer(void **array, void *p) { + Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1; + + s32 i = growing_array_find_index_from_left_by_pointer(array, p); + + if (i < 0) return false; + + growing_array_unordered_remove_by_index(array, i); + + return true; +} +bool +growing_array_ordered_remove_one_by_value(void **array, void *p) { + Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1; + + s32 i = growing_array_find_index_from_left_by_value(array, p); + + if (i < 0) return false; + + growing_array_ordered_remove_by_index(array, i); + + return true; +} +bool +growing_array_unordered_remove_one_by_value(void **array, void *p) { + Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1; + + s32 i = growing_array_find_index_from_left_by_value(array, p); + + if (i < 0) return false; + + growing_array_unordered_remove_by_index(array, i); + + return true; +} + +// #Incomplete +// s32 growing_array_ordered_remove_one_by_value(void **array, void *p) +// s32 growing_array_unordered_remove_one_by_value(void **array, void *p) + +u32 +growing_array_get_valid_count(void *array) { + Growing_Array_Header *header = ((Growing_Array_Header*)array) - 1; + return header->valid_count; +} +u32 +growing_array_get_allocated_count(void *array) { + Growing_Array_Header *header = ((Growing_Array_Header*)array) - 1; + return header->allocated_count; +} \ No newline at end of file