From 3f71cf0f3fe468e0cd98edc7fda8d9de971b7c8f Mon Sep 17 00:00:00 2001 From: Abdelrahman Date: Fri, 23 Sep 2022 04:39:17 +0100 Subject: [PATCH] Connected the AssetManager to the GameEngine and added function in the GameEngine API to allow for loading and removing assets as well as rendering textures using their AssetID --- include/AssetManager.h | 13 ++++++--- include/GameEngine.h | 8 +++++- include/ObjectStore.h | 8 +++--- include/Renderer.h | 4 +++ include/Window.h | 5 ++-- include/reusable_ids.h | 3 +++ src/AssetManager.c | 60 +++++++++++++++++++++++++++++++++--------- src/GameEngine.c | 54 +++++++++++++++++++++++++++++++++---- src/ObjectStore.c | 4 +-- src/Renderer.c | 21 ++++++++++++++- src/Window.c | 9 ++++--- 11 files changed, 156 insertions(+), 33 deletions(-) diff --git a/include/AssetManager.h b/include/AssetManager.h index a541564..26412e1 100644 --- a/include/AssetManager.h +++ b/include/AssetManager.h @@ -1,9 +1,12 @@ #ifndef ASSET_MANAGER_H #define ASSET_MANAGER_H +#include "Renderer.h" +#include "SDL_mixer.h" +#include "SDL_render.h" +#include "reusable_ids.h" #include -typedef int32_t AssetID; typedef enum { ASSET_TYPE_IMAGE, ASSET_TYPE_AUDIO_FX, @@ -14,8 +17,12 @@ typedef enum { 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); +AssetID load_asset_to_manager(AssetManager *am, const char *path, + AssetType type, Renderer *renderer); +void remove_asset_from_manager(AssetManager *am, AssetID id); +SDL_Texture *get_texture(AssetManager *am, AssetID id); +Mix_Chunk *get_audio_chunk(AssetManager *am, AssetID id); +Mix_Music *get_music(AssetManager *am, AssetID id); void destroy_asset_manager(AssetManager *am); #endif // !ASSET_MANAGER_H diff --git a/include/GameEngine.h b/include/GameEngine.h index 7645787..d7b5043 100644 --- a/include/GameEngine.h +++ b/include/GameEngine.h @@ -1,15 +1,21 @@ #ifndef GAME_H #define GAME_H +#include "AssetManager.h" #include "ObjectStore.h" +#include "SDL_pixels.h" +#include "reusable_ids.h" #include bool init_game(const char *game_name, int window_width, int window_height, - bool full_screen); + SDL_Color window_background_color, bool full_screen); bool game_running(); ObjectID add_object(void *object, EventHandlerPtr eh, UpdateFuncPtr uf, RenderFuncPtr rf); void remove_object(ObjectID id); +AssetID load_asset(const char *path, AssetType type); +void render_texture_asset(AssetID id, float x, float y, float w, float h); +void close_asset(AssetID id); void handle_events(); void update(); void render(); diff --git a/include/ObjectStore.h b/include/ObjectStore.h index b36d3f8..b7d2c2a 100644 --- a/include/ObjectStore.h +++ b/include/ObjectStore.h @@ -4,11 +4,11 @@ #include "Renderer.h" #include "SDL_events.h" #include "engine_build_config.h" +#include "reusable_ids.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); +typedef void (*RenderFuncPtr)(void *object); typedef struct object_store ObjectStore; @@ -18,11 +18,11 @@ ObjectID add_object_to_store(ObjectStore *os, void *object, EventHandlerPtr eh, 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); +void render_all_objects(ObjectStore *os); void destroy_object_store(ObjectStore *os); #ifdef DEBUG_ENGINE void print_objects(ObjectStore *os); -#endif /* DEBUG_ENGINE */ +#endif // !DEBUG_ENGINE #endif // !OBJECT_STORE_H diff --git a/include/Renderer.h b/include/Renderer.h index a1face1..8fc8d88 100644 --- a/include/Renderer.h +++ b/include/Renderer.h @@ -2,6 +2,7 @@ #define RENDERER_H #include "SDL.h" +#include "SDL_render.h" #include "SDL_video.h" #include @@ -9,7 +10,10 @@ typedef struct renderer Renderer; Renderer *create_renderer(); bool init_renderer(Renderer *renderer, SDL_Window *window); +SDL_Texture *load_texture(const Renderer *renderer, const char *path); void render_clear(const Renderer *renderer, SDL_Color color); +void render_texture(const Renderer *renderer, SDL_Texture *texture, float x, + float y, float w, float h); void swap_buffers(const Renderer *renderer); void destroy_renderer(Renderer *renderer); diff --git a/include/Window.h b/include/Window.h index 67d1d81..e672de3 100644 --- a/include/Window.h +++ b/include/Window.h @@ -11,11 +11,12 @@ typedef struct window { int height; Renderer *renderer; SDL_Window *SDL_base_window; + SDL_Color background_color; } Window; bool init_window(Window *wnd, const char *title, int width, int height, - bool full_screen); -void fill_window_with_color(const Window *wnd, SDL_Color color); + SDL_Color color, bool full_screen); +void clear_window(const Window *wnd); void swap_render_buffers(const Window *wnd); void destroy_window(Window *wnd); diff --git a/include/reusable_ids.h b/include/reusable_ids.h index bdc6a3f..4ecc6b6 100644 --- a/include/reusable_ids.h +++ b/include/reusable_ids.h @@ -4,6 +4,9 @@ #include #include +typedef int32_t ObjectID; +typedef int32_t AssetID; + int32_t reuse_id(int32_t *ids, size_t count); #endif // !REUSABLE_IDS_H diff --git a/src/AssetManager.c b/src/AssetManager.c index e28fb5d..a2b3d4b 100644 --- a/src/AssetManager.c +++ b/src/AssetManager.c @@ -1,10 +1,10 @@ #include "AssetManager.h" +#include "Renderer.h" #include "SDL_image.h" #include "SDL_mixer.h" -#include "SDL_surface.h" +#include "SDL_render.h" #include "constants.h" #include "reusable_ids.h" -#include #include #include #include @@ -15,7 +15,7 @@ typedef struct asset { AssetType type; char *path; union { - SDL_Surface *surface; + SDL_Texture *texture; Mix_Chunk *chunk; Mix_Music *music; } data; @@ -42,7 +42,8 @@ AssetManager *create_asset_manager() { return am; } -AssetID load_asset(AssetManager *am, const char *path, AssetType type) { +AssetID load_asset_to_manager(AssetManager *am, const char *path, + AssetType type, Renderer *renderer) { if (!am || type == ASSET_TYPE_COUNT) { return -1; } @@ -56,16 +57,23 @@ AssetID load_asset(AssetManager *am, const char *path, AssetType type) { switch (type) { case ASSET_TYPE_IMAGE: - asset.data.surface = IMG_Load(path); + if (!renderer) { + loaded = false; + break; + } - if (!(asset.data.surface)) { + asset.data.texture = load_texture(renderer, path); + + if (!(asset.data.texture)) { loaded = false; } break; case ASSET_TYPE_AUDIO_FX: + // TODO (Abdelrahman): Implement loading audio chunks break; case ASSET_TYPE_MUSIC: + // TODO (Abdelrahman): Implement loading music break; default: loaded = false; @@ -95,7 +103,7 @@ AssetID load_asset(AssetManager *am, const char *path, AssetType type) { switch (type) { case ASSET_TYPE_IMAGE: - asset.data.surface = NULL; + asset.data.texture = NULL; break; case ASSET_TYPE_AUDIO_FX: asset.data.chunk = NULL; @@ -110,7 +118,7 @@ AssetID load_asset(AssetManager *am, const char *path, AssetType type) { return id; } -void close_asset(AssetManager *am, AssetID id) { +void remove_asset_from_manager(AssetManager *am, AssetID id) { if (!am || am->count == 0) { return; } @@ -120,12 +128,14 @@ void close_asset(AssetManager *am, AssetID id) { switch (am->assets[id].type) { case ASSET_TYPE_IMAGE: - SDL_FreeSurface(am->assets[id].data.surface); - am->assets[id].data.surface = NULL; + SDL_DestroyTexture(am->assets[id].data.texture); + am->assets[id].data.texture = NULL; break; case ASSET_TYPE_AUDIO_FX: + // TODO (Abdelrahman): Implement closing audio chunk break; case ASSET_TYPE_MUSIC: + // TODO (Abdelrahman): Implement closing music break; default: break; @@ -136,6 +146,30 @@ void close_asset(AssetManager *am, AssetID id) { am->count -= 1; } +SDL_Texture *get_texture(AssetManager *am, AssetID id) { + if (am->assets[id].type != ASSET_TYPE_IMAGE) { + return NULL; + } + + return am->assets[id].data.texture; +} + +Mix_Chunk *get_audio_chunk(AssetManager *am, AssetID id) { + if (am->assets[id].type != ASSET_TYPE_AUDIO_FX) { + return NULL; + } + + return am->assets[id].data.chunk; +} + +Mix_Music *get_music(AssetManager *am, AssetID id) { + if (am->assets[id].type != ASSET_TYPE_MUSIC) { + return NULL; + } + + return am->assets[id].data.music; +} + void destroy_asset_manager(AssetManager *am) { if (!am) { return; @@ -147,12 +181,14 @@ void destroy_asset_manager(AssetManager *am) { switch (am->assets[i].type) { case ASSET_TYPE_IMAGE: - SDL_FreeSurface(am->assets[i].data.surface); - am->assets[i].data.surface = NULL; + SDL_DestroyTexture(am->assets[i].data.texture); + am->assets[i].data.texture = NULL; break; case ASSET_TYPE_AUDIO_FX: + // TODO (Abdelrahman): Implement closing audio chunk break; case ASSET_TYPE_MUSIC: + // TODO (Abdelrahman): Implement closing music break; default: break; diff --git a/src/GameEngine.c b/src/GameEngine.c index 25eaf98..fd6bfd4 100644 --- a/src/GameEngine.c +++ b/src/GameEngine.c @@ -1,13 +1,19 @@ #include "GameEngine.h" +#include "AssetManager.h" #include "ObjectStore.h" +#include "Renderer.h" #include "SDL.h" #include "SDL_error.h" #include "SDL_events.h" +#include "SDL_image.h" #include "SDL_pixels.h" +#include "SDL_render.h" #include "Window.h" #include "constants.h" #include "engine_build_config.h" +#include "reusable_ids.h" #include +#include #ifdef DEBUG_ENGINE #include @@ -19,10 +25,11 @@ INTERNAL struct game { Window window; SDL_Event event; ObjectStore *object_store; + AssetManager *asset_manager; } Game; bool init_game(const char *game_name, int window_width, int window_height, - bool full_screen) { + SDL_Color window_background_color, bool full_screen) { bool initialisation_complete = true; if (SDL_Init(SDL_INIT_EVERYTHING) != 0) { @@ -33,8 +40,12 @@ bool init_game(const char *game_name, int window_width, int window_height, return false; } + if (IMG_Init(IMG_INIT_PNG) != IMG_INIT_PNG) { + initialisation_complete = false; + } + if (!init_window(&(Game.window), game_name, window_width, window_height, - full_screen)) { + window_background_color, full_screen)) { #ifdef DEBUG_ENGINE printf("Failed to initialise window\n"); #endif /* DEBUG_ENGINE */ @@ -48,6 +59,12 @@ bool init_game(const char *game_name, int window_width, int window_height, initialisation_complete = false; } + Game.asset_manager = create_asset_manager(); + + if (!(Game.asset_manager)) { + initialisation_complete = false; + } + if (!initialisation_complete) { close_game(); @@ -55,7 +72,8 @@ bool init_game(const char *game_name, int window_width, int window_height, } Game.running = true; - Game.delta = 0.0f; + // Game.delta = 0.0f; + Game.delta = 1.0f / 60.0f; #ifdef DEBUG_ENGINE printf("Game initialised successfully\n"); @@ -84,6 +102,27 @@ void remove_object(ObjectID id) { remove_object_from_store(Game.object_store, id); } +AssetID load_asset(const char *path, AssetType type) { + return type == ASSET_TYPE_IMAGE + ? load_asset_to_manager(Game.asset_manager, path, type, + Game.window.renderer) + : load_asset_to_manager(Game.asset_manager, path, type, NULL); +} + +void render_texture_asset(AssetID id, float x, float y, float w, float h) { + if (id < 0) { + return; + } + + SDL_Texture *texture = get_texture(Game.asset_manager, id); + + render_texture(Game.window.renderer, texture, x, y, w, h); +} + +void close_asset(AssetID id) { + remove_asset_from_manager(Game.asset_manager, id); +} + void handle_events() { if (!(Game.running)) { return; @@ -117,16 +156,19 @@ void render() { return; } - fill_window_with_color(&(Game.window), (SDL_Color){255, 255, 255, 255}); + clear_window(&(Game.window)); if (Game.object_store) { - render_all_objects(Game.object_store, Game.window.renderer); + render_all_objects(Game.object_store); } swap_render_buffers(&(Game.window)); } void close_game() { + destroy_asset_manager(Game.asset_manager); + Game.asset_manager = NULL; + destroy_object_store(Game.object_store); Game.object_store = NULL; @@ -136,6 +178,8 @@ void close_game() { Game.running = false; + IMG_Quit(); + SDL_Quit(); #ifdef DEBUG_ENGINE diff --git a/src/ObjectStore.c b/src/ObjectStore.c index 6934c82..7b509ff 100644 --- a/src/ObjectStore.c +++ b/src/ObjectStore.c @@ -119,7 +119,7 @@ void update_all_objects(ObjectStore *os, float delta) { } } -void render_all_objects(ObjectStore *os, Renderer *renderer) { +void render_all_objects(ObjectStore *os) { if (!os || os->count == 0) { return; } @@ -127,7 +127,7 @@ void render_all_objects(ObjectStore *os, Renderer *renderer) { for (int i = 0; i < os->count; ++i) { if (os->render_funcs[i]) { void *object = os->object_ptrs[i]; - (os->render_funcs[i])(renderer, object); + (os->render_funcs[i])(object); } } } diff --git a/src/Renderer.c b/src/Renderer.c index a82e678..2532a6c 100644 --- a/src/Renderer.c +++ b/src/Renderer.c @@ -1,5 +1,7 @@ #include "Renderer.h" #include "SDL.h" +#include "SDL_image.h" +#include "SDL_rect.h" #include "SDL_render.h" #include "engine_build_config.h" #include @@ -35,12 +37,25 @@ void render_clear(const Renderer *renderer, SDL_Color color) { return; } - SDL_SetRenderDrawColor(renderer->SDL_base_renderer, color.r, color.r, color.b, + SDL_SetRenderDrawColor(renderer->SDL_base_renderer, color.r, color.g, color.b, color.a); SDL_RenderClear(renderer->SDL_base_renderer); } +void render_texture(const Renderer *renderer, SDL_Texture *texture, float x, + float y, float w, float h) { + if (!renderer || !texture) { + return; + } + + SDL_FRect dest = {x, y, w, h}; + + // TODO (Abdelrahman): Look into using the SDL_RenderCopyExF instead to + // support rotating the texture + SDL_RenderCopyF(renderer->SDL_base_renderer, texture, NULL, &dest); +} + void swap_buffers(const Renderer *renderer) { if (!renderer || !(renderer->SDL_base_renderer)) { return; @@ -49,6 +64,10 @@ void swap_buffers(const Renderer *renderer) { SDL_RenderPresent(renderer->SDL_base_renderer); } +SDL_Texture *load_texture(const Renderer *renderer, const char *path) { + return IMG_LoadTexture(renderer->SDL_base_renderer, path); +} + void destroy_renderer(Renderer *renderer) { if (renderer) { if (renderer->SDL_base_renderer) { diff --git a/src/Window.c b/src/Window.c index 1c0ab8b..7ac2f23 100644 --- a/src/Window.c +++ b/src/Window.c @@ -8,7 +8,7 @@ #endif /* DEBUG_ENGINE */ bool init_window(Window *wnd, const char *title, int width, int height, - bool full_screen) { + SDL_Color color, bool full_screen) { if (!wnd) { return false; } @@ -29,6 +29,8 @@ bool init_window(Window *wnd, const char *title, int width, int height, SDL_GetWindowSize(wnd->SDL_base_window, &(wnd->width), &(wnd->height)); + wnd->background_color = color; + wnd->renderer = create_renderer(); if (!wnd->renderer || !init_renderer(wnd->renderer, wnd->SDL_base_window)) { @@ -46,12 +48,12 @@ bool init_window(Window *wnd, const char *title, int width, int height, return true; } -void fill_window_with_color(const Window *wnd, SDL_Color color) { +void clear_window(const Window *wnd) { if (!wnd) { return; } - render_clear(wnd->renderer, color); + render_clear(wnd->renderer, wnd->background_color); } void swap_render_buffers(const Window *wnd) { @@ -78,6 +80,7 @@ void destroy_window(Window *wnd) { wnd->width = 0; wnd->height = 0; + wnd->background_color = (SDL_Color){0, 0, 0, 255}; #ifdef DEBUG_ENGINE printf("Window destroyed successfully\n");