Files
punchie-engine/src/ObjectStore.c
T

190 lines
4.8 KiB
C

#include "ObjectStore.h"
#include "aliases.h"
#include "constants.h"
#include "engine_build_config.h"
#include "reusable_ids.h"
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#ifdef DEBUG_ENGINE
#include <stdio.h>
#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;
}