diff --git a/CMakeLists.txt b/CMakeLists.txt index 19e9347..8664283 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,11 +22,12 @@ set(CMAKE_INSTALL_RPATH "$ORIGIN;$ORIGIN/../lib") # TARGETS add_library(${PROJECT_NAME} SHARED - src/GameManager.c + src/GameEngine.c src/Window.c src/Renderer.c src/ObjectStore.c - src/Hashmap.c + src/AssetManager.c + src/reusable_ids.c ) target_include_directories(${PROJECT_NAME} PUBLIC @@ -47,11 +48,12 @@ target_link_libraries(${PROJECT_NAME} PUBLIC install(FILES ${CMAKE_CURRENT_BINARY_DIR}/engine_build_config.h include/constants.h - include/GameManager.h + include/GameEngine.h include/Window.h include/Renderer.h include/ObjectStore.h - include/Hashmap.h + include/AssetManager.h + include/reusable_ids.h CONFIGURATIONS Release DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} ) diff --git a/include/AssetManager.h b/include/AssetManager.h new file mode 100644 index 0000000..a541564 --- /dev/null +++ b/include/AssetManager.h @@ -0,0 +1,21 @@ +#ifndef ASSET_MANAGER_H +#define ASSET_MANAGER_H + +#include + +typedef int32_t AssetID; +typedef enum { + ASSET_TYPE_IMAGE, + ASSET_TYPE_AUDIO_FX, + ASSET_TYPE_MUSIC, + + ASSET_TYPE_COUNT +} AssetType; +typedef struct asset_manager AssetManager; + +AssetManager *create_asset_manager(); +AssetID load_asset(AssetManager *am, const char *path, AssetType type); +void close_asset(AssetManager *am, AssetID id); +void destroy_asset_manager(AssetManager *am); + +#endif // !ASSET_MANAGER_H diff --git a/include/GameManager.h b/include/GameEngine.h similarity index 63% rename from include/GameManager.h rename to include/GameEngine.h index c7fd355..7645787 100644 --- a/include/GameManager.h +++ b/include/GameEngine.h @@ -7,9 +7,9 @@ bool init_game(const char *game_name, int window_width, int window_height, bool full_screen); bool game_running(); -void add_object(void *object, const char *object_tag, EventHandlerPtr eh, - UpdateFuncPtr uf, RenderFuncPtr rf); -void remove_object(const char *object_tag); +ObjectID add_object(void *object, EventHandlerPtr eh, UpdateFuncPtr uf, + RenderFuncPtr rf); +void remove_object(ObjectID id); void handle_events(); void update(); void render(); diff --git a/include/Hashmap.h b/include/Hashmap.h deleted file mode 100644 index 0e7de19..0000000 --- a/include/Hashmap.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef HASHMAP_H -#define HASHMAP_H - -#include "engine_build_config.h" -#include -#include - -#ifdef DEBUG_ENGINE -#include -#endif /* DEBUG_ENGINE */ - -typedef struct hashmap Hashmap; - -Hashmap *create_hashmap(); -int32_t add_object_to_map(Hashmap *map, const char *key); -int32_t get_object_index(Hashmap *map, const char *key); -int32_t delete_object_from_map(Hashmap *map, const char *key); -void destroy_hashmap(Hashmap *map); - -#ifdef DEBUG_ENGINE -void print_hashmap(Hashmap *map); -void print_non_empty(Hashmap *map); -#endif // DEBUG_ENGINE - -#endif // !HASHMAP_H diff --git a/include/ObjectStore.h b/include/ObjectStore.h index c7059ac..b36d3f8 100644 --- a/include/ObjectStore.h +++ b/include/ObjectStore.h @@ -5,6 +5,7 @@ #include "SDL_events.h" #include "engine_build_config.h" +typedef int32_t ObjectID; typedef void (*EventHandlerPtr)(const SDL_Event *event, void *object); typedef void (*UpdateFuncPtr)(float delta, void *object); typedef void (*RenderFuncPtr)(Renderer *renderer, void *object); @@ -12,10 +13,9 @@ typedef void (*RenderFuncPtr)(Renderer *renderer, void *object); typedef struct object_store ObjectStore; ObjectStore *create_object_store(); -void add_object_to_store(ObjectStore *os, void *object, const char *object_tag, - EventHandlerPtr eh, UpdateFuncPtr uf, - RenderFuncPtr rf); -void remove_object_from_store(ObjectStore *os, const char *object_tag); +ObjectID add_object_to_store(ObjectStore *os, void *object, EventHandlerPtr eh, + UpdateFuncPtr uf, RenderFuncPtr rf); +void remove_object_from_store(ObjectStore *os, ObjectID id); 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); diff --git a/include/constants.h b/include/constants.h index e7a614a..7d1cd70 100644 --- a/include/constants.h +++ b/include/constants.h @@ -4,6 +4,7 @@ #define INTERNAL static #define MAX_OBJ_COUNT 10000 +#define MAX_ASSET_COUNT 1000 #define HASH_PRIME_01 1987 #define HASH_PRIME_02 7919 diff --git a/include/reusable_ids.h b/include/reusable_ids.h new file mode 100644 index 0000000..bdc6a3f --- /dev/null +++ b/include/reusable_ids.h @@ -0,0 +1,9 @@ +#ifndef REUSABLE_IDS_H +#define REUSABLE_IDS_H + +#include +#include + +int32_t reuse_id(int32_t *ids, size_t count); + +#endif // !REUSABLE_IDS_H diff --git a/src/AssetManager.c b/src/AssetManager.c new file mode 100644 index 0000000..e28fb5d --- /dev/null +++ b/src/AssetManager.c @@ -0,0 +1,167 @@ +#include "AssetManager.h" +#include "SDL_image.h" +#include "SDL_mixer.h" +#include "SDL_surface.h" +#include "constants.h" +#include "reusable_ids.h" +#include +#include +#include +#include +#include +#include + +typedef struct asset { + AssetType type; + char *path; + union { + SDL_Surface *surface; + Mix_Chunk *chunk; + Mix_Music *music; + } data; +} Asset; + +struct asset_manager { + size_t count; + size_t deleted_count; + AssetID reusable_ids[MAX_ASSET_COUNT]; + Asset assets[MAX_ASSET_COUNT]; +}; + +AssetManager *create_asset_manager() { + AssetManager *am = (AssetManager *)malloc(sizeof(AssetManager)); + if (!am) { + return NULL; + } + + am->count = 0; + am->deleted_count = 0; + memset(am->reusable_ids, 0, sizeof(am->reusable_ids)); + memset(am->assets, 0, sizeof(am->assets)); + + return am; +} + +AssetID load_asset(AssetManager *am, const char *path, AssetType type) { + if (!am || type == ASSET_TYPE_COUNT) { + return -1; + } + + Asset asset = {}; + bool loaded = true; + + // TODO (Abdelrahman): Implement a way to make sure that an asset with the + // same path is not already loaded. If the user attempts to load an asset + // that already exists, the function should return -1 to indicate an error + + switch (type) { + case ASSET_TYPE_IMAGE: + asset.data.surface = IMG_Load(path); + + if (!(asset.data.surface)) { + loaded = false; + } + + break; + case ASSET_TYPE_AUDIO_FX: + break; + case ASSET_TYPE_MUSIC: + break; + default: + loaded = false; + break; + } + + if (!loaded) { + return -1; + } + + AssetID id; + + if (am->deleted_count > 0) { + id = (AssetID)reuse_id((int32_t *)am->reusable_ids, am->deleted_count); + am->deleted_count -= 1; + am->count += 1; + } else { + id = (am->count)++; + } + + am->assets[id].type = type; + + am->assets[id].path = (char *)malloc(strlen(path) + 1); + strcpy(am->assets[id].path, path); + + am->assets[id].data = asset.data; + + switch (type) { + case ASSET_TYPE_IMAGE: + asset.data.surface = NULL; + break; + case ASSET_TYPE_AUDIO_FX: + asset.data.chunk = NULL; + break; + case ASSET_TYPE_MUSIC: + asset.data.music = NULL; + break; + default: + break; + } + + return id; +} + +void close_asset(AssetManager *am, AssetID id) { + if (!am || am->count == 0) { + return; + } + + free(am->assets[id].path); + am->assets[id].path = 0; + + switch (am->assets[id].type) { + case ASSET_TYPE_IMAGE: + SDL_FreeSurface(am->assets[id].data.surface); + am->assets[id].data.surface = NULL; + break; + case ASSET_TYPE_AUDIO_FX: + break; + case ASSET_TYPE_MUSIC: + break; + default: + break; + } + + am->reusable_ids[(am->deleted_count)++] = id; + + am->count -= 1; +} + +void destroy_asset_manager(AssetManager *am) { + if (!am) { + return; + } + + for (size_t i = 0; i < am->count; ++i) { + free(am->assets[i].path); + am->assets[i].path = NULL; + + switch (am->assets[i].type) { + case ASSET_TYPE_IMAGE: + SDL_FreeSurface(am->assets[i].data.surface); + am->assets[i].data.surface = NULL; + break; + case ASSET_TYPE_AUDIO_FX: + break; + case ASSET_TYPE_MUSIC: + break; + default: + break; + } + } + + am->count = 0; + am->deleted_count = 0; + + free(am); + am = NULL; +} diff --git a/src/GameManager.c b/src/GameEngine.c similarity index 85% rename from src/GameManager.c rename to src/GameEngine.c index 063d63d..25eaf98 100644 --- a/src/GameManager.c +++ b/src/GameEngine.c @@ -1,4 +1,4 @@ -#include "GameManager.h" +#include "GameEngine.h" #include "ObjectStore.h" #include "SDL.h" #include "SDL_error.h" @@ -66,23 +66,22 @@ bool init_game(const char *game_name, int window_width, int window_height, bool game_running() { return Game.running; } -void add_object(void *object, const char *object_tag, - EventHandlerPtr event_handler, UpdateFuncPtr update_func, - RenderFuncPtr render_func) { +ObjectID add_object(void *object, EventHandlerPtr event_handler, + UpdateFuncPtr update_func, RenderFuncPtr render_func) { if (!(Game.running) || !(Game.object_store)) { - return; + return -1; } - add_object_to_store(Game.object_store, object, object_tag, event_handler, - update_func, render_func); + return add_object_to_store(Game.object_store, object, event_handler, + update_func, render_func); } -void remove_object(const char *object_tag) { +void remove_object(ObjectID id) { if (!(Game.running) || !(Game.object_store)) { return; } - remove_object_from_store(Game.object_store, object_tag); + remove_object_from_store(Game.object_store, id); } void handle_events() { diff --git a/src/Hashmap.c b/src/Hashmap.c deleted file mode 100644 index 0385b3a..0000000 --- a/src/Hashmap.c +++ /dev/null @@ -1,198 +0,0 @@ -#include "Hashmap.h" -#include "constants.h" -#include "engine_build_config.h" -#include -#include -#include -#include -#include - -#ifdef DEBUG_ENGINE -#include -#endif /* DEBUG_ENGINE */ - -struct hashmap { - size_t count; - char *keys[MAX_OBJ_COUNT]; - int32_t active_indices[MAX_OBJ_COUNT]; -}; - -Hashmap *create_hashmap() { - Hashmap *map = malloc(sizeof(Hashmap)); - - map->count = 0; - - memset(map->keys, 0, MAX_OBJ_COUNT); - - for (int i = 0; i < MAX_OBJ_COUNT; ++i) { - map->active_indices[i] = -1; - } - - return map; -} - -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(Hashmap *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(Hashmap *map, 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; -} - -int32_t delete_object_from_map(Hashmap *map, 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; - } - - 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; - - return index; -} - -void destroy_hashmap(Hashmap *map) { - if (!map) { - return; - } - - for (size_t i = 0; i < map->count; ++i) { - size_t index = map->active_indices[i]; - - if (index == -1) { - continue; - } - - if (map->keys[index]) { - free(map->keys[index]); - map->keys[index] = NULL; - } - - map->active_indices[i] = -1; - } - - map->count = 0; - - free(map); - map = NULL; -} - -#ifdef DEBUG_ENGINE -void print_hashmap(Hashmap *map) { - 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(Hashmap *map) { - 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 5a0e08d..6934c82 100644 --- a/src/ObjectStore.c +++ b/src/ObjectStore.c @@ -1,25 +1,28 @@ #include "ObjectStore.h" -#include "Hashmap.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 { size_t count; - int32_t active_indices[MAX_OBJ_COUNT]; - Hashmap *map; - void **object_ptrs; - EventHandlerPtr *event_handlers; - UpdateFuncPtr *update_funcs; - RenderFuncPtr *render_funcs; + size_t deleted_count; + ObjectID reusable_ids[MAX_OBJ_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]; }; ObjectStore *create_object_store() { - bool allocation_complete = true; - ObjectStore *os = (ObjectStore *)malloc(sizeof(ObjectStore)); if (!os) { // If allocating memory to the store fails, we just return NULL. No need to @@ -27,149 +30,104 @@ ObjectStore *create_object_store() { return NULL; } - os->map = create_hashmap(); - if (!(os->map)) { - allocation_complete = false; - } - 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; - } + os->deleted_count = 0; + memset(os->reusable_ids, 0, sizeof(os->reusable_ids)); + 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)); 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(os->map, object_tag); +ObjectID add_object_to_store(ObjectStore *os, void *object, EventHandlerPtr eh, + UpdateFuncPtr uf, RenderFuncPtr rf) { + if (!os || !object || + (os->count + 1 == MAX_OBJ_COUNT && os->deleted_count == 0)) { +#ifdef DEBUG_ENGINE + printf("Failed to add object\n"); +#endif /* DEBUG_ENGINE */ - if (index < 0) { - return; + return -1; } - 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; + // TODO (Abdelrahman): Need to figure out a way to check that the object + // hasn't already been added to the store. If it has been added before, the + // function should return -1 indicating an error to ensure that there aren't + // two references to the same object without the user being aware that they + // refer to the same thing. If the user intentionally copies the ID of one + // object, then it would be their responsibility to make sure they don't + // delete the object using one of the IDs, then try to use it with the other. + + ObjectID id; + + if (os->deleted_count > 0) { + id = (ObjectID)reuse_id((int32_t *)os->reusable_ids, os->deleted_count); + os->deleted_count -= 1; + 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, const char *object_tag) { - if (os->count == 0) { +void remove_object_from_store(ObjectStore *os, ObjectID id) { + if (!os || os->count == 0 || !(os->object_ptrs[id])) { return; } - int32_t index = delete_object_from_map(os->map, object_tag); + os->object_ptrs[id] = NULL; + os->event_handlers[id] = NULL; + os->update_funcs[id] = NULL; + os->render_funcs[id] = NULL; - 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->reusable_ids[(os->deleted_count)++] = id; os->count -= 1; } void handle_all_objects_events(ObjectStore *os, const SDL_Event *event) { - if (os->count == 0) { + if (!os || os->count == 0) { return; } for (int i = 0; i < os->count; ++i) { - int32_t index = os->active_indices[i]; - - if (os->event_handlers[index]) { - void *object = os->object_ptrs[index]; - (os->event_handlers[index])(event, object); + if (os->event_handlers[i]) { + void *object = os->object_ptrs[i]; + (os->event_handlers[i])(event, object); } } } void update_all_objects(ObjectStore *os, float delta) { - if (os->count == 0) { + if (!os || os->count == 0) { return; } for (int i = 0; i < os->count; ++i) { - int32_t index = os->active_indices[i]; - - if (os->update_funcs[index]) { - void *object = os->object_ptrs[index]; - (os->update_funcs[index])(delta, object); + if (os->update_funcs[i]) { + void *object = os->object_ptrs[i]; + (os->update_funcs[i])(delta, object); } } } void render_all_objects(ObjectStore *os, Renderer *renderer) { - if (os->count == 0) { + if (!os || os->count == 0) { return; } for (int i = 0; i < os->count; ++i) { - int32_t index = os->active_indices[i]; - - if (os->render_funcs[index]) { - void *object = os->object_ptrs[index]; - (os->render_funcs[index])(renderer, object); + if (os->render_funcs[i]) { + void *object = os->object_ptrs[i]; + (os->render_funcs[i])(renderer, object); } } } @@ -179,41 +137,20 @@ void destroy_object_store(ObjectStore *os) { return; } - for (int i = 0; i < os->count; ++i) { - os->active_indices[i] = -1; + for (size_t i = 0; i < os->count; ++i) { + os->object_ptrs[i] = NULL; + os->event_handlers[i] = NULL; + os->update_funcs[i] = NULL; + os->render_funcs[i] = NULL; } 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; - } - - if (os->map) { - destroy_hashmap(os->map); - os->map = NULL; - } + os->deleted_count = 0; free(os); os = NULL; } #ifdef DEBUG_ENGINE -void print_objects(ObjectStore *os) { print_hashmap(os->map); } +void print_objects(ObjectStore *os) {} #endif /* DEBUG_ENGINE */ diff --git a/src/Renderer.c b/src/Renderer.c index 1e3fd32..a82e678 100644 --- a/src/Renderer.c +++ b/src/Renderer.c @@ -31,6 +31,10 @@ bool init_renderer(Renderer *renderer, SDL_Window *window) { } void render_clear(const Renderer *renderer, SDL_Color color) { + if (!renderer || !(renderer->SDL_base_renderer)) { + return; + } + SDL_SetRenderDrawColor(renderer->SDL_base_renderer, color.r, color.r, color.b, color.a); @@ -38,6 +42,10 @@ void render_clear(const Renderer *renderer, SDL_Color color) { } void swap_buffers(const Renderer *renderer) { + if (!renderer || !(renderer->SDL_base_renderer)) { + return; + } + SDL_RenderPresent(renderer->SDL_base_renderer); } diff --git a/src/Window.c b/src/Window.c index 31cc4cd..1c0ab8b 100644 --- a/src/Window.c +++ b/src/Window.c @@ -9,6 +9,10 @@ bool init_window(Window *wnd, const char *title, int width, int height, bool full_screen) { + if (!wnd) { + return false; + } + Uint32 window_flags = SDL_WINDOW_ALLOW_HIGHDPI; if (full_screen) { @@ -43,10 +47,20 @@ bool init_window(Window *wnd, const char *title, int width, int height, } void fill_window_with_color(const Window *wnd, SDL_Color color) { + if (!wnd) { + return; + } + render_clear(wnd->renderer, color); } -void swap_render_buffers(const Window *wnd) { swap_buffers(wnd->renderer); } +void swap_render_buffers(const Window *wnd) { + if (!wnd) { + return; + } + + swap_buffers(wnd->renderer); +} void destroy_window(Window *wnd) { if (!wnd) { diff --git a/src/reusable_ids.c b/src/reusable_ids.c new file mode 100644 index 0000000..b18b7c0 --- /dev/null +++ b/src/reusable_ids.c @@ -0,0 +1,12 @@ +#include "reusable_ids.h" + +int32_t reuse_id(int32_t *ids, size_t count) { + int32_t id = ids[0]; + + for (size_t i = 0; i < count; ++i) { + // Remove the first id and make sure the remaining ones are packed + ids[i] = ids[i + 1]; + } + + return id; +}