#include "ObjectStore.h" #include "aliases.h" #include "constants.h" #include "engine_build_config.h" #include "reusable_ids.h" #include #include #include #include #include #ifdef DEBUG_ENGINE #include #endif /* DEBUG_ENGINE */ struct object_store { u64 count; u64 deleted_count; void *object_ptrs[MAX_OBJ_COUNT]; EventHandlerPtr event_handlers[MAX_OBJ_COUNT]; UpdateFuncPtr update_funcs[MAX_OBJ_COUNT]; RenderFuncPtr render_funcs[MAX_OBJ_COUNT]; ObjectID reusable_ids[MAX_OBJ_COUNT]; }; bool object_exists(ObjectStore *os, void *object); ObjectStore *create_object_store() { ObjectStore *os = (ObjectStore *)malloc(sizeof(ObjectStore)); if (!os) { // If allocating memory to the store fails, we just return NULL. No need to // continue with the rest of the function or to call any cleanup functions return NULL; } os->count = 0; os->deleted_count = 0; memset(os->object_ptrs, 0, sizeof(os->object_ptrs)); memset(os->event_handlers, 0, sizeof(os->event_handlers)); memset(os->update_funcs, 0, sizeof(os->update_funcs)); memset(os->render_funcs, 0, sizeof(os->render_funcs)); memset(os->reusable_ids, 0, sizeof(os->reusable_ids)); return os; } ObjectID add_object_to_store(ObjectStore *os, void *object, EventHandlerPtr eh, UpdateFuncPtr uf, RenderFuncPtr rf) { // If all function pointers are NULL, no point of adding the object to the // store bool no_funcs_passed = !eh && !uf && !rf; if (!os || !object || object_exists(os, object) || no_funcs_passed || (os->count + 1 == MAX_OBJ_COUNT && os->deleted_count == 0)) { #ifdef DEBUG_ENGINE printf("Failed to add object\n"); #endif /* DEBUG_ENGINE */ return INVALID_ID; } ObjectID id; if (os->deleted_count > 0) { id = (ObjectID)reuse_id((i32 *)os->reusable_ids, os->deleted_count); os->deleted_count -= 1; if (id == os->count) { os->count += 1; } } else { id = (os->count)++; } os->object_ptrs[id] = object; os->event_handlers[id] = eh; os->update_funcs[id] = uf; os->render_funcs[id] = rf; return id; } void remove_object_from_store(ObjectStore *os, ObjectID *id_ptr) { ObjectID id = *id_ptr; if (!os || os->count == 0 || id == INVALID_ID || !(os->object_ptrs[id])) { return; } *id_ptr = INVALID_ID; os->object_ptrs[id] = NULL; os->event_handlers[id] = NULL; os->update_funcs[id] = NULL; os->render_funcs[id] = NULL; os->reusable_ids[(os->deleted_count)++] = id; if (id == (os->count - 1)) { // Only decrement the count if the last object is deleted. Otherwise, the // count shouldn't be decremented since the deleted object would be in the // middle, which means that the functions that loop over all objects in the // store will not actually loop over everything u64 new_count = 0; // Figure out how much we need to decrement the count. Since, a lot of // objects may have been removed, the count needs to equal the last active // object. for (size_t i = id - 1; i >= 0; --i) { if (os->object_ptrs[i]) { new_count = i + 1; break; } } os->count = new_count; } } void handle_all_objects_events(ObjectStore *os, const SDL_Event *event) { if (!os || os->count == 0) { return; } for (int i = 0; i < os->count; ++i) { if (os->event_handlers[i]) { void *object = os->object_ptrs[i]; (os->event_handlers[i])(object, event); } } } void update_all_objects(ObjectStore *os, f32 delta) { if (!os || os->count == 0) { return; } for (int i = 0; i < os->count; ++i) { if (os->update_funcs[i]) { void *object = os->object_ptrs[i]; (os->update_funcs[i])(object, delta); } } } void render_all_objects(ObjectStore *os) { if (!os || os->count == 0) { return; } for (int i = 0; i < os->count; ++i) { if (os->render_funcs[i]) { void *object = os->object_ptrs[i]; (os->render_funcs[i])(object); } } } void destroy_object_store(ObjectStore **os) { if (!(*os)) { return; } memset((*os)->object_ptrs, 0, sizeof((*os)->object_ptrs)); memset((*os)->event_handlers, 0, sizeof((*os)->event_handlers)); memset((*os)->update_funcs, 0, sizeof((*os)->update_funcs)); memset((*os)->render_funcs, 0, sizeof((*os)->render_funcs)); memset((*os)->reusable_ids, 0, sizeof((*os)->reusable_ids)); (*os)->count = 0; (*os)->deleted_count = 0; free(*os); *os = NULL; } bool object_exists(ObjectStore *os, void *object) { // This is a crude implementation for checking that an object has already // been added. // TODO (Abdelrahman): Figure out if there is a better way of doing this for (size_t i = 0; i < MAX_OBJ_COUNT; ++i) { if (object == os->object_ptrs[i]) { return true; } } return false; }