diff --git a/include/Hashmap.h b/include/Hashmap.h index 2ea5c76..8144e28 100644 --- a/include/Hashmap.h +++ b/include/Hashmap.h @@ -1,13 +1,23 @@ #ifndef HASHMAP_H #define HASHMAP_H +#include "engine_build_config.h" #include #include +#ifdef DEBUG_ENGINE +#include +#endif /* DEBUG_ENGINE */ + void init_hashmap(); int32_t add_object_to_map(const char *key); int32_t get_object_index(const char *key); -void delete_object_from_map(const char *key); +int32_t delete_object_from_map(const char *key); void destroy_hashmap(); +#ifdef DEBUG_ENGINE +void print_hashmap(); +void print_non_empty(); +#endif // DEBUG_ENGINE + #endif // !HASHMAP_H diff --git a/include/ObjectStore.h b/include/ObjectStore.h index 23c34b9..a2c74bc 100644 --- a/include/ObjectStore.h +++ b/include/ObjectStore.h @@ -3,6 +3,7 @@ #include "Renderer.h" #include "SDL_events.h" +#include "engine_build_config.h" typedef void (*EventHandlerPtr)(const SDL_Event *event, void *object); typedef void (*UpdateFuncPtr)(float delta, void *object); @@ -10,12 +11,18 @@ typedef void (*RenderFuncPtr)(Renderer *renderer, void *object); typedef struct object_store ObjectStore; -void add_object_to_store(ObjectStore *os, const char *object_tag, +ObjectStore *create_object_store(); +void add_object_to_store(ObjectStore *os, void *object, const char *object_tag, EventHandlerPtr eh, UpdateFuncPtr uf, RenderFuncPtr rf); -void handle_all_object_events(ObjectStore *os); -void update_all_objects(ObjectStore *os); -void render_all_objects(ObjectStore *os); void remove_object_from_store(ObjectStore *os, const char *object_tag); +void handle_all_objects_events(ObjectStore *os, const SDL_Event *event); +void update_all_objects(ObjectStore *os, float delta); +void render_all_objects(ObjectStore *os, Renderer *renderer); +void destroy_object_store(ObjectStore *os); + +#ifdef DEBUG_ENGINE +void print_objects(); +#endif /* DEBUG_ENGINE */ #endif // !OBJECT_STORE_H diff --git a/src/Hashmap.c b/src/Hashmap.c index 2d74c95..da15667 100644 --- a/src/Hashmap.c +++ b/src/Hashmap.c @@ -18,11 +18,9 @@ INTERNAL struct objects_hashmap { } map = {}; void init_hashmap() { - // Technically, memset shouldn't be used to set the values of any thing other - // than byte arrays, but since it works in certain cases (e.g. 0 and -1) and - // it is faster than doing a for loop, I am using it here to initialise the - // active_indices array to -1 - memset(map.active_indices, -1, sizeof(map.active_indices)); + for (int i = 0; i < MAX_OBJ_COUNT; ++i) { + map.active_indices[i] = -1; + } } size_t hash_key(const char *key) { @@ -95,13 +93,13 @@ int32_t get_object_index(const char *key) { return (int32_t)index; } -void delete_object_from_map(const char *key) { +int32_t delete_object_from_map(const char *key) { if (map.count == 0) { #ifdef DEBUG_ENGINE printf("Key \"%s\" doesn't exist\n", key); #endif /* DEBUG_ENGINE */ - return; + return -1; } size_t index = hash_key(key); @@ -111,7 +109,7 @@ void delete_object_from_map(const char *key) { printf("Key \"%s\" doesn't exist\n", key); #endif /* DEBUG_ENGINE */ - return; + return -1; } free(map.keys[index]); @@ -140,6 +138,8 @@ void delete_object_from_map(const char *key) { } map.count -= 1; + + return index; } void destroy_hashmap() { @@ -150,15 +150,34 @@ void destroy_hashmap() { continue; } - free(map.keys[index]); - map.keys[index] = NULL; + if (map.keys[index]) { + free(map.keys[index]); + map.keys[index] = NULL; + } + + map.active_indices[i] = -1; } map.count = 0; - - // Technically, memset shouldn't be used to set the values of any thing other - // than byte arrays, but since it works in certain cases (e.g. 0 and -1) and - // it is faster than doing a for loop, I am using it here to initialise the - // active_indices array to -1 - memset(map.active_indices, -1, sizeof(map.active_indices)); } + +#ifdef DEBUG_ENGINE +void print_hashmap() { + if (map.count == 0) { + return; + } + + for (int i = 0; i < map.count; ++i) { + size_t index = map.active_indices[i]; + printf("%d: %s\n", i, map.keys[index]); + } +} + +void print_non_empty() { + for (int i = 0; i < MAX_OBJ_COUNT; ++i) { + if (map.active_indices[i] != -1) { + printf("%d is not set to -1\n", i); + } + } +} +#endif /* DEBUG_ENGINE */ diff --git a/src/ObjectStore.c b/src/ObjectStore.c index 10534f2..2de9c89 100644 --- a/src/ObjectStore.c +++ b/src/ObjectStore.c @@ -1 +1,203 @@ #include "ObjectStore.h" +#include "Hashmap.h" +#include "constants.h" +#include +#include +#include + +struct object_store { + size_t count; + int32_t active_indices[MAX_OBJ_COUNT]; + void **object_ptrs; + EventHandlerPtr *event_handlers; + UpdateFuncPtr *update_funcs; + RenderFuncPtr *render_funcs; +}; + +ObjectStore *create_object_store() { + init_hashmap(); + + bool allocation_complete = true; + + ObjectStore *os = (ObjectStore *)malloc(sizeof(ObjectStore)); + if (!os) { + // If allocating memory to the store fails, we still need to call the + // destroy function to make sure that the memory allocated for the + // hashmap is freed. + destroy_object_store(os); + return NULL; + } + + os->count = 0; + + os->object_ptrs = malloc(sizeof(void *) * MAX_OBJ_COUNT); + if (!(os->object_ptrs)) { + allocation_complete = false; + } + + os->event_handlers = + (EventHandlerPtr *)malloc(sizeof(EventHandlerPtr) * MAX_OBJ_COUNT); + if (!(os->event_handlers)) { + allocation_complete = false; + } + + os->update_funcs = + (UpdateFuncPtr *)malloc(sizeof(UpdateFuncPtr) * MAX_OBJ_COUNT); + if (!(os->update_funcs)) { + allocation_complete = false; + } + + os->render_funcs = + (RenderFuncPtr *)malloc(sizeof(RenderFuncPtr) * MAX_OBJ_COUNT); + if (!(os->render_funcs)) { + allocation_complete = false; + } + + if (!allocation_complete) { + // If any of the allocations failed, we need to call the destroy function + // to free any resources that have been allocated successfully. + destroy_object_store(os); + return NULL; + } + + for (int i = 0; i < MAX_OBJ_COUNT; ++i) { + os->active_indices[i] = -1; + } + + return os; +} + +void add_object_to_store(ObjectStore *os, void *object, const char *object_tag, + EventHandlerPtr eh, UpdateFuncPtr uf, + RenderFuncPtr rf) { + int32_t index = add_object_to_map(object_tag); + + if (index < 0) { + return; + } + + os->active_indices[os->count] = index; + os->count += 1; + os->object_ptrs[index] = object; + os->event_handlers[index] = eh; + os->update_funcs[index] = uf; + os->render_funcs[index] = rf; +} + +void remove_object_from_store(ObjectStore *os, const char *object_tag) { + if (os->count == 0) { + return; + } + + int32_t index = delete_object_from_map(object_tag); + + if (index < 0) { + return; + } + + os->object_ptrs[index] = NULL; + os->event_handlers[index] = NULL; + os->update_funcs[index] = NULL; + os->render_funcs[index] = NULL; + + size_t packing_start_index = 0; + + for (size_t i = 0; i < os->count; ++i) { + if (os->active_indices[i] == index) { + os->active_indices[i] = -1; + packing_start_index = i; + break; + } + } + + // Make sure the indices are packed in the array + for (; packing_start_index < os->count; ++packing_start_index) { + if (packing_start_index + 1 == MAX_OBJ_COUNT) { + // Make sure we don't go out of bounds if we are at the last item + os->active_indices[packing_start_index] = -1; + continue; + } + + os->active_indices[packing_start_index] = + os->active_indices[packing_start_index + 1]; + } + + os->count -= 1; +} + +void handle_all_objects_events(ObjectStore *os, const SDL_Event *event) { + if (os->count == 0) { + return; + } + + for (int i = 0; i < os->count; ++i) { + int32_t index = os->active_indices[i]; + void *object = os->object_ptrs[index]; + (os->event_handlers[index])(event, object); + } +} + +void update_all_objects(ObjectStore *os, float delta) { + if (os->count == 0) { + return; + } + + for (int i = 0; i < os->count; ++i) { + int32_t index = os->active_indices[i]; + void *object = os->object_ptrs[index]; + (os->update_funcs[index])(delta, object); + } +} + +void render_all_objects(ObjectStore *os, Renderer *renderer) { + if (os->count == 0) { + return; + } + + for (int i = 0; i < os->count; ++i) { + int32_t index = os->active_indices[i]; + void *object = os->object_ptrs[index]; + (os->render_funcs[index])(renderer, object); + } +} + +void destroy_object_store(ObjectStore *os) { + destroy_hashmap(); + + if (!os) { + return; + } + + for (int i = 0; i < os->count; ++i) { + os->active_indices[i] = -1; + } + + os->count = 0; + + if (os->event_handlers) { + free(os->event_handlers); + os->event_handlers = NULL; + } + + if (os->update_funcs) { + free(os->update_funcs); + os->update_funcs = NULL; + } + + if (os->render_funcs) { + free(os->render_funcs); + os->render_funcs = NULL; + } + + if (os->object_ptrs) { + free(os->object_ptrs); + os->object_ptrs = NULL; + } + + free(os); + os = NULL; +} + +#ifdef DEBUG_ENGINE +void print_objects() { print_hashmap(); } +#endif /* DEBUG_ENGINE */