diff --git a/CMakeLists.txt b/CMakeLists.txt index bad3757..157d3ec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,6 +25,8 @@ add_library(${PROJECT_NAME} SHARED src/Game.c src/Window.c src/Renderer.c + src/ObjectStore.c + src/Hashmap.c ) target_include_directories(${PROJECT_NAME} PUBLIC @@ -49,6 +51,7 @@ install(FILES include/Window.h include/Renderer.h include/ObjectStore.h + include/Hashmap.h CONFIGURATIONS Release DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} ) diff --git a/include/Hashmap.h b/include/Hashmap.h new file mode 100644 index 0000000..2ea5c76 --- /dev/null +++ b/include/Hashmap.h @@ -0,0 +1,13 @@ +#ifndef HASHMAP_H +#define HASHMAP_H + +#include +#include + +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); +void destroy_hashmap(); + +#endif // !HASHMAP_H diff --git a/include/ObjectStore.h b/include/ObjectStore.h index 384645d..23c34b9 100644 --- a/include/ObjectStore.h +++ b/include/ObjectStore.h @@ -2,12 +2,20 @@ #define OBJECT_STORE_H #include "Renderer.h" +#include "SDL_events.h" +typedef void (*EventHandlerPtr)(const SDL_Event *event, void *object); typedef void (*UpdateFuncPtr)(float delta, void *object); typedef void (*RenderFuncPtr)(Renderer *renderer, void *object); typedef struct object_store ObjectStore; -void add_object_to_store(ObjectStore *os, UpdateFuncPtr uf, RenderFuncPtr rf); +void add_object_to_store(ObjectStore *os, 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); #endif // !OBJECT_STORE_H diff --git a/include/constants.h b/include/constants.h index e4d0063..e7a614a 100644 --- a/include/constants.h +++ b/include/constants.h @@ -3,4 +3,8 @@ #define INTERNAL static +#define MAX_OBJ_COUNT 10000 +#define HASH_PRIME_01 1987 +#define HASH_PRIME_02 7919 + #endif // !CONSTANTS_H diff --git a/src/Hashmap.c b/src/Hashmap.c new file mode 100644 index 0000000..2d74c95 --- /dev/null +++ b/src/Hashmap.c @@ -0,0 +1,164 @@ +#include "Hashmap.h" +#include "constants.h" +#include "engine_build_config.h" +#include +#include +#include +#include +#include + +#ifdef DEBUG_ENGINE +#include +#endif /* DEBUG_ENGINE */ + +INTERNAL struct objects_hashmap { + size_t count; + char *keys[MAX_OBJ_COUNT]; + int32_t active_indices[MAX_OBJ_COUNT]; +} 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)); +} + +size_t hash_key(const char *key) { + size_t i = 0; + + for (size_t j = 0; key[j]; ++j) { + i += (size_t)key[j] * HASH_PRIME_01 % MAX_OBJ_COUNT; + } + + i = (i * HASH_PRIME_02) % MAX_OBJ_COUNT; + + return i; +} + +int32_t add_object_to_map(const char *key) { + if (map.count + 1 == MAX_OBJ_COUNT) { +#ifdef DEBUG_ENGINE + printf("Map full\n"); +#endif /* DEBUG_ENGINE */ + + return -1; + } + + size_t index = hash_key(key); + + if (map.keys[index]) { + if (strcmp(map.keys[index], key) == 0) { +#ifdef DEBUG_ENGINE + printf("Key \"%s\" already exists\n", key); +#endif /* DEBUG_ENGINE */ + } else { + // TODO (Abdelrahman): Implement a way to resolve collisions between + // multiple keys +#ifdef DEBUG_ENGINE + printf("Collision detected. Key \"%s\" collides with key \"%s\"\n", key, + map.keys[index]); +#endif /* DEBUG_ENGINE */ + } + + return -1; + } + + map.keys[index] = malloc(strlen(key) + 1); + strcpy(map.keys[index], key); + map.active_indices[map.count] = index; + map.count += 1; + + return index; +} + +int32_t get_object_index(const char *key) { + if (map.count == 0) { +#ifdef DEBUG_ENGINE + printf("Key \"%s\" doesn't exist\n", key); +#endif /* DEBUG_ENGINE */ + + return -1; + } + + size_t index = hash_key(key); + + if (!(map.keys[index]) || strcmp(map.keys[index], key) != 0) { +#ifdef DEBUG_ENGINE + printf("Key \"%s\" doesn't exist\n", key); +#endif /* DEBUG_ENGINE */ + + return -1; + } + + return (int32_t)index; +} + +void 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; + } + + size_t index = hash_key(key); + + if (!(map.keys[index]) || strcmp(map.keys[index], key) != 0) { +#ifdef DEBUG_ENGINE + printf("Key \"%s\" doesn't exist\n", key); +#endif /* DEBUG_ENGINE */ + + return; + } + + free(map.keys[index]); + map.keys[index] = NULL; + + size_t packing_start_index = 0; + + for (size_t i = 0; i < map.count; ++i) { + if (map.active_indices[i] == index) { + map.active_indices[i] = -1; + packing_start_index = i; + break; + } + } + + // Make sure the indices are packed in the array + for (; packing_start_index < map.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 + map.active_indices[packing_start_index] = -1; + continue; + } + + map.active_indices[packing_start_index] = + map.active_indices[packing_start_index + 1]; + } + + map.count -= 1; +} + +void destroy_hashmap() { + for (size_t i = 0; i < map.count; ++i) { + size_t index = map.active_indices[i]; + + if (index == -1) { + continue; + } + + free(map.keys[index]); + map.keys[index] = NULL; + } + + 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)); +} diff --git a/src/ObjectStore.c b/src/ObjectStore.c new file mode 100644 index 0000000..10534f2 --- /dev/null +++ b/src/ObjectStore.c @@ -0,0 +1 @@ +#include "ObjectStore.h" diff --git a/src/Renderer.c b/src/Renderer.c index d85dd9e..1e3fd32 100644 --- a/src/Renderer.c +++ b/src/Renderer.c @@ -9,9 +9,9 @@ #include #endif /* DEBUG_ENGINE */ -typedef struct renderer { +struct renderer { SDL_Renderer *SDL_base_renderer; -} Renderer; +}; Renderer *create_renderer() { return (Renderer *)malloc(sizeof(Renderer)); }