Enabled SDL_image's support for PNG and TIFF files and improved the
AssetManager with a hashing function, a linked list structure to store the hashes as well as a reference counter to support multiple users sharing the same asset.
This commit is contained in:
1 parent
3f71cf0f3f
commit
dfee36ffe9
12 files changed
+292
-60
No files matched your search
Vendored
+2
@@ -3,8 +3,10 @@ cmake_minimum_required(VERSION 3.10)
|
|||||||
set(SDL_TEST_ENABLED_BY_DEFAULT OFF CACHE BOOL "" FORCE)
|
set(SDL_TEST_ENABLED_BY_DEFAULT OFF CACHE BOOL "" FORCE)
|
||||||
set(SDL2_DISABLE_INSTALL OFF CACHE BOOL "" FORCE)
|
set(SDL2_DISABLE_INSTALL OFF CACHE BOOL "" FORCE)
|
||||||
set(SDL2_DISABLE_UNINSTALL OFF CACHE BOOL "" FORCE)
|
set(SDL2_DISABLE_UNINSTALL OFF CACHE BOOL "" FORCE)
|
||||||
|
set(SDL2IMAGE_VENDORED ON CACHE BOOL "" FORCE)
|
||||||
set(SDL2MIXER_VENDORED ON CACHE BOOL "" FORCE)
|
set(SDL2MIXER_VENDORED ON CACHE BOOL "" FORCE)
|
||||||
set(SDL2TTF_VENDORED ON CACHE BOOL "" FORCE)
|
set(SDL2TTF_VENDORED ON CACHE BOOL "" FORCE)
|
||||||
|
set(SDL2IMAGE_TIF ON CACHE BOOL "" FORCE)
|
||||||
|
|
||||||
add_subdirectory(SDL_image)
|
add_subdirectory(SDL_image)
|
||||||
add_subdirectory(SDL_ttf)
|
add_subdirectory(SDL_ttf)
|
||||||
|
|||||||
+10
-2
@@ -5,7 +5,11 @@
|
|||||||
#include "SDL_mixer.h"
|
#include "SDL_mixer.h"
|
||||||
#include "SDL_render.h"
|
#include "SDL_render.h"
|
||||||
#include "reusable_ids.h"
|
#include "reusable_ids.h"
|
||||||
#include <stdint.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif // !__cplusplus
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
ASSET_TYPE_IMAGE,
|
ASSET_TYPE_IMAGE,
|
||||||
@@ -19,10 +23,14 @@ typedef struct asset_manager AssetManager;
|
|||||||
AssetManager *create_asset_manager();
|
AssetManager *create_asset_manager();
|
||||||
AssetID load_asset_to_manager(AssetManager *am, const char *path,
|
AssetID load_asset_to_manager(AssetManager *am, const char *path,
|
||||||
AssetType type, Renderer *renderer);
|
AssetType type, Renderer *renderer);
|
||||||
void remove_asset_from_manager(AssetManager *am, AssetID id);
|
void remove_asset_from_manager(AssetManager *am, AssetID *id_ptr);
|
||||||
SDL_Texture *get_texture(AssetManager *am, AssetID id);
|
SDL_Texture *get_texture(AssetManager *am, AssetID id);
|
||||||
Mix_Chunk *get_audio_chunk(AssetManager *am, AssetID id);
|
Mix_Chunk *get_audio_chunk(AssetManager *am, AssetID id);
|
||||||
Mix_Music *get_music(AssetManager *am, AssetID id);
|
Mix_Music *get_music(AssetManager *am, AssetID id);
|
||||||
void destroy_asset_manager(AssetManager *am);
|
void destroy_asset_manager(AssetManager *am);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif // !__cplusplus
|
||||||
|
|
||||||
#endif // !ASSET_MANAGER_H
|
#endif // !ASSET_MANAGER_H
|
||||||
+10
-2
@@ -7,18 +7,26 @@
|
|||||||
#include "reusable_ids.h"
|
#include "reusable_ids.h"
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif // !__cplusplus
|
||||||
|
|
||||||
bool init_game(const char *game_name, int window_width, int window_height,
|
bool init_game(const char *game_name, int window_width, int window_height,
|
||||||
SDL_Color window_background_color, bool full_screen);
|
SDL_Color window_background_color, bool full_screen);
|
||||||
bool game_running();
|
bool game_running();
|
||||||
ObjectID add_object(void *object, EventHandlerPtr eh, UpdateFuncPtr uf,
|
ObjectID add_object(void *object, EventHandlerPtr eh, UpdateFuncPtr uf,
|
||||||
RenderFuncPtr rf);
|
RenderFuncPtr rf);
|
||||||
void remove_object(ObjectID id);
|
void remove_object(ObjectID *id);
|
||||||
AssetID load_asset(const char *path, AssetType type);
|
AssetID load_asset(const char *path, AssetType type);
|
||||||
void render_texture_asset(AssetID id, float x, float y, float w, float h);
|
void render_texture_asset(AssetID id, float x, float y, float w, float h);
|
||||||
void close_asset(AssetID id);
|
void close_asset(AssetID *id);
|
||||||
void handle_events();
|
void handle_events();
|
||||||
void update();
|
void update();
|
||||||
void render();
|
void render();
|
||||||
void close_game();
|
void close_game();
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif // !__cplusplus
|
||||||
|
|
||||||
#endif // !GAME_H
|
#endif // !GAME_H
|
||||||
@@ -6,6 +6,10 @@
|
|||||||
#include "engine_build_config.h"
|
#include "engine_build_config.h"
|
||||||
#include "reusable_ids.h"
|
#include "reusable_ids.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif // !__cplusplus
|
||||||
|
|
||||||
typedef void (*EventHandlerPtr)(const SDL_Event *event, void *object);
|
typedef void (*EventHandlerPtr)(const SDL_Event *event, void *object);
|
||||||
typedef void (*UpdateFuncPtr)(float delta, void *object);
|
typedef void (*UpdateFuncPtr)(float delta, void *object);
|
||||||
typedef void (*RenderFuncPtr)(void *object);
|
typedef void (*RenderFuncPtr)(void *object);
|
||||||
@@ -15,7 +19,7 @@ typedef struct object_store ObjectStore;
|
|||||||
ObjectStore *create_object_store();
|
ObjectStore *create_object_store();
|
||||||
ObjectID add_object_to_store(ObjectStore *os, void *object, EventHandlerPtr eh,
|
ObjectID add_object_to_store(ObjectStore *os, void *object, EventHandlerPtr eh,
|
||||||
UpdateFuncPtr uf, RenderFuncPtr rf);
|
UpdateFuncPtr uf, RenderFuncPtr rf);
|
||||||
void remove_object_from_store(ObjectStore *os, ObjectID id);
|
void remove_object_from_store(ObjectStore *os, ObjectID *id_ptr);
|
||||||
void handle_all_objects_events(ObjectStore *os, const SDL_Event *event);
|
void handle_all_objects_events(ObjectStore *os, const SDL_Event *event);
|
||||||
void update_all_objects(ObjectStore *os, float delta);
|
void update_all_objects(ObjectStore *os, float delta);
|
||||||
void render_all_objects(ObjectStore *os);
|
void render_all_objects(ObjectStore *os);
|
||||||
@@ -25,4 +29,8 @@ void destroy_object_store(ObjectStore *os);
|
|||||||
void print_objects(ObjectStore *os);
|
void print_objects(ObjectStore *os);
|
||||||
#endif // !DEBUG_ENGINE
|
#endif // !DEBUG_ENGINE
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif // !__cplusplus
|
||||||
|
|
||||||
#endif // !OBJECT_STORE_H
|
#endif // !OBJECT_STORE_H
|
||||||
@@ -6,6 +6,10 @@
|
|||||||
#include "SDL_video.h"
|
#include "SDL_video.h"
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif // !__cplusplus
|
||||||
|
|
||||||
typedef struct renderer Renderer;
|
typedef struct renderer Renderer;
|
||||||
|
|
||||||
Renderer *create_renderer();
|
Renderer *create_renderer();
|
||||||
@@ -17,4 +21,8 @@ void render_texture(const Renderer *renderer, SDL_Texture *texture, float x,
|
|||||||
void swap_buffers(const Renderer *renderer);
|
void swap_buffers(const Renderer *renderer);
|
||||||
void destroy_renderer(Renderer *renderer);
|
void destroy_renderer(Renderer *renderer);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif // !__cplusplus
|
||||||
|
|
||||||
#endif // !RENDERER_H
|
#endif // !RENDERER_H
|
||||||
@@ -6,6 +6,10 @@
|
|||||||
#include "SDL_pixels.h"
|
#include "SDL_pixels.h"
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif // !__cplusplus
|
||||||
|
|
||||||
typedef struct window {
|
typedef struct window {
|
||||||
int width;
|
int width;
|
||||||
int height;
|
int height;
|
||||||
@@ -20,4 +24,8 @@ void clear_window(const Window *wnd);
|
|||||||
void swap_render_buffers(const Window *wnd);
|
void swap_render_buffers(const Window *wnd);
|
||||||
void destroy_window(Window *wnd);
|
void destroy_window(Window *wnd);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif // !__cplusplus
|
||||||
|
|
||||||
#endif // !WINDOW_H
|
#endif // !WINDOW_H
|
||||||
@@ -1,6 +1,10 @@
|
|||||||
#ifndef CONSTANTS_H
|
#ifndef CONSTANTS_H
|
||||||
#define CONSTANTS_H
|
#define CONSTANTS_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif // !__cplusplus
|
||||||
|
|
||||||
#define INTERNAL static
|
#define INTERNAL static
|
||||||
|
|
||||||
#define MAX_OBJ_COUNT 10000
|
#define MAX_OBJ_COUNT 10000
|
||||||
@@ -8,4 +12,8 @@
|
|||||||
#define HASH_PRIME_01 1987
|
#define HASH_PRIME_01 1987
|
||||||
#define HASH_PRIME_02 7919
|
#define HASH_PRIME_02 7919
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif // !__cplusplus
|
||||||
|
|
||||||
#endif // !CONSTANTS_H
|
#endif // !CONSTANTS_H
|
||||||
@@ -4,9 +4,19 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif // !__cplusplus
|
||||||
|
|
||||||
|
#define INVALID_ID -1
|
||||||
|
|
||||||
typedef int32_t ObjectID;
|
typedef int32_t ObjectID;
|
||||||
typedef int32_t AssetID;
|
typedef int32_t AssetID;
|
||||||
|
|
||||||
int32_t reuse_id(int32_t *ids, size_t count);
|
int32_t reuse_id(int32_t *ids, size_t count);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif // !__cplusplus
|
||||||
|
|
||||||
#endif // !REUSABLE_IDS_H
|
#endif // !REUSABLE_IDS_H
|
||||||
+155
-8
@@ -1,5 +1,6 @@
|
|||||||
#include "AssetManager.h"
|
#include "AssetManager.h"
|
||||||
#include "Renderer.h"
|
#include "Renderer.h"
|
||||||
|
#include "SDL_error.h"
|
||||||
#include "SDL_image.h"
|
#include "SDL_image.h"
|
||||||
#include "SDL_mixer.h"
|
#include "SDL_mixer.h"
|
||||||
#include "SDL_render.h"
|
#include "SDL_render.h"
|
||||||
@@ -8,6 +9,7 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
@@ -21,13 +23,128 @@ typedef struct asset {
|
|||||||
} data;
|
} data;
|
||||||
} Asset;
|
} Asset;
|
||||||
|
|
||||||
|
typedef struct id_node IDNode;
|
||||||
|
struct id_node {
|
||||||
|
AssetID id;
|
||||||
|
IDNode *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct id_node_list {
|
||||||
|
IDNode *start_node;
|
||||||
|
size_t node_count;
|
||||||
|
} IDNodeList;
|
||||||
|
|
||||||
struct asset_manager {
|
struct asset_manager {
|
||||||
size_t count;
|
size_t count;
|
||||||
size_t deleted_count;
|
size_t deleted_count;
|
||||||
AssetID reusable_ids[MAX_ASSET_COUNT];
|
AssetID reusable_ids[MAX_ASSET_COUNT];
|
||||||
Asset assets[MAX_ASSET_COUNT];
|
Asset assets[MAX_ASSET_COUNT];
|
||||||
|
size_t user_counter[MAX_ASSET_COUNT];
|
||||||
|
IDNodeList hashed_path_ids[MAX_ASSET_COUNT];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
size_t hash_path(const char *path) {
|
||||||
|
size_t i = 0;
|
||||||
|
|
||||||
|
for (size_t j = 0; path[j]; ++j) {
|
||||||
|
i += (size_t)path[j] * HASH_PRIME_01 % MAX_ASSET_COUNT;
|
||||||
|
}
|
||||||
|
|
||||||
|
i = (i * HASH_PRIME_02) % MAX_ASSET_COUNT;
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
void insert_id_node(IDNodeList *node_list, AssetID id) {
|
||||||
|
if (node_list->node_count == 0) {
|
||||||
|
node_list->start_node = malloc(sizeof(IDNode));
|
||||||
|
node_list->start_node->id = id;
|
||||||
|
node_list->start_node->next = NULL;
|
||||||
|
|
||||||
|
node_list->node_count = 1;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
IDNode *last_node = node_list->start_node;
|
||||||
|
for (size_t i = 1; i < node_list->node_count; ++i) {
|
||||||
|
last_node = last_node->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
last_node->next = malloc(sizeof(IDNode));
|
||||||
|
last_node->next->id = id;
|
||||||
|
last_node->next->next = NULL;
|
||||||
|
|
||||||
|
++(node_list->node_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
void remove_id_node(IDNodeList *node_list, AssetID id) {
|
||||||
|
if (node_list->node_count == 0) {
|
||||||
|
return;
|
||||||
|
} else if (node_list->node_count == 1) {
|
||||||
|
free(node_list->start_node);
|
||||||
|
node_list->start_node = NULL;
|
||||||
|
|
||||||
|
node_list->node_count = 0;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
IDNode *node = NULL;
|
||||||
|
IDNode *prev = NULL;
|
||||||
|
IDNode *current = node_list->start_node;
|
||||||
|
for (size_t i = 0; i < node_list->node_count; ++i) {
|
||||||
|
if (current->id == id) {
|
||||||
|
node = current;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
prev = current;
|
||||||
|
current = current->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node) {
|
||||||
|
IDNode *next = node->next;
|
||||||
|
if (!prev) {
|
||||||
|
// Handle the case when there is no previous node, which means that node
|
||||||
|
// is actually the start node in the list.
|
||||||
|
free(node_list->start_node);
|
||||||
|
|
||||||
|
node_list->start_node = next;
|
||||||
|
} else {
|
||||||
|
free(prev->next);
|
||||||
|
|
||||||
|
prev->next = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
--(node_list->node_count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AssetID get_asset_id_from_id_node(AssetManager *am, IDNodeList *node_list,
|
||||||
|
const char *path) {
|
||||||
|
if (node_list->node_count == 0) {
|
||||||
|
return INVALID_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
IDNode *id_node = node_list->start_node;
|
||||||
|
for (size_t i = 0; i < node_list->node_count; ++i) {
|
||||||
|
if (!id_node) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Asset asset = am->assets[id_node->id];
|
||||||
|
|
||||||
|
if (strcmp(asset.path, path) == 0) {
|
||||||
|
return id_node->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
id_node = id_node->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return INVALID_ID;
|
||||||
|
}
|
||||||
|
|
||||||
AssetManager *create_asset_manager() {
|
AssetManager *create_asset_manager() {
|
||||||
AssetManager *am = (AssetManager *)malloc(sizeof(AssetManager));
|
AssetManager *am = (AssetManager *)malloc(sizeof(AssetManager));
|
||||||
if (!am) {
|
if (!am) {
|
||||||
@@ -38,6 +155,8 @@ AssetManager *create_asset_manager() {
|
|||||||
am->deleted_count = 0;
|
am->deleted_count = 0;
|
||||||
memset(am->reusable_ids, 0, sizeof(am->reusable_ids));
|
memset(am->reusable_ids, 0, sizeof(am->reusable_ids));
|
||||||
memset(am->assets, 0, sizeof(am->assets));
|
memset(am->assets, 0, sizeof(am->assets));
|
||||||
|
memset(am->user_counter, 0, sizeof(am->user_counter));
|
||||||
|
memset(am->hashed_path_ids, 0, sizeof(am->hashed_path_ids));
|
||||||
|
|
||||||
return am;
|
return am;
|
||||||
}
|
}
|
||||||
@@ -45,16 +164,21 @@ AssetManager *create_asset_manager() {
|
|||||||
AssetID load_asset_to_manager(AssetManager *am, const char *path,
|
AssetID load_asset_to_manager(AssetManager *am, const char *path,
|
||||||
AssetType type, Renderer *renderer) {
|
AssetType type, Renderer *renderer) {
|
||||||
if (!am || type == ASSET_TYPE_COUNT) {
|
if (!am || type == ASSET_TYPE_COUNT) {
|
||||||
return -1;
|
return INVALID_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t hash_index = hash_path(path);
|
||||||
|
|
||||||
|
AssetID existing_id =
|
||||||
|
get_asset_id_from_id_node(am, &(am->hashed_path_ids[hash_index]), path);
|
||||||
|
if (existing_id != INVALID_ID) {
|
||||||
|
++(am->user_counter[existing_id]);
|
||||||
|
return existing_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
Asset asset = {};
|
Asset asset = {};
|
||||||
bool loaded = true;
|
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) {
|
switch (type) {
|
||||||
case ASSET_TYPE_IMAGE:
|
case ASSET_TYPE_IMAGE:
|
||||||
if (!renderer) {
|
if (!renderer) {
|
||||||
@@ -65,6 +189,7 @@ AssetID load_asset_to_manager(AssetManager *am, const char *path,
|
|||||||
asset.data.texture = load_texture(renderer, path);
|
asset.data.texture = load_texture(renderer, path);
|
||||||
|
|
||||||
if (!(asset.data.texture)) {
|
if (!(asset.data.texture)) {
|
||||||
|
printf("Error loading %s: %s\n", path, SDL_GetError());
|
||||||
loaded = false;
|
loaded = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,7 +206,7 @@ AssetID load_asset_to_manager(AssetManager *am, const char *path,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!loaded) {
|
if (!loaded) {
|
||||||
return -1;
|
return INVALID_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
AssetID id;
|
AssetID id;
|
||||||
@@ -94,6 +219,10 @@ AssetID load_asset_to_manager(AssetManager *am, const char *path,
|
|||||||
id = (am->count)++;
|
id = (am->count)++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
insert_id_node(&(am->hashed_path_ids[hash_index]), id);
|
||||||
|
|
||||||
|
am->user_counter[id] = 1;
|
||||||
|
|
||||||
am->assets[id].type = type;
|
am->assets[id].type = type;
|
||||||
|
|
||||||
am->assets[id].path = (char *)malloc(strlen(path) + 1);
|
am->assets[id].path = (char *)malloc(strlen(path) + 1);
|
||||||
@@ -118,11 +247,24 @@ AssetID load_asset_to_manager(AssetManager *am, const char *path,
|
|||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
void remove_asset_from_manager(AssetManager *am, AssetID id) {
|
void remove_asset_from_manager(AssetManager *am, AssetID *id_ptr) {
|
||||||
if (!am || am->count == 0) {
|
AssetID id = *id_ptr;
|
||||||
|
|
||||||
|
if (!am || am->count == 0 || id == INVALID_ID || !(am->assets[id].path)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
--(am->user_counter[id]);
|
||||||
|
*id_ptr = INVALID_ID;
|
||||||
|
|
||||||
|
// If there are still other objects using the asset, don't delete it
|
||||||
|
if (am->user_counter[id] > 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t hash_index = hash_path(am->assets[id].path);
|
||||||
|
remove_id_node(&(am->hashed_path_ids[hash_index]), id);
|
||||||
|
|
||||||
free(am->assets[id].path);
|
free(am->assets[id].path);
|
||||||
am->assets[id].path = 0;
|
am->assets[id].path = 0;
|
||||||
|
|
||||||
@@ -176,6 +318,11 @@ void destroy_asset_manager(AssetManager *am) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < am->count; ++i) {
|
for (size_t i = 0; i < am->count; ++i) {
|
||||||
|
am->user_counter[i] = 0;
|
||||||
|
|
||||||
|
size_t hash_index = hash_path(am->assets[i].path);
|
||||||
|
remove_id_node(&(am->hashed_path_ids[hash_index]), i);
|
||||||
|
|
||||||
free(am->assets[i].path);
|
free(am->assets[i].path);
|
||||||
am->assets[i].path = NULL;
|
am->assets[i].path = NULL;
|
||||||
|
|
||||||
|
|||||||
+63
-44
@@ -8,25 +8,29 @@
|
|||||||
#include "SDL_image.h"
|
#include "SDL_image.h"
|
||||||
#include "SDL_pixels.h"
|
#include "SDL_pixels.h"
|
||||||
#include "SDL_render.h"
|
#include "SDL_render.h"
|
||||||
|
#include "SDL_timer.h"
|
||||||
#include "Window.h"
|
#include "Window.h"
|
||||||
#include "constants.h"
|
#include "constants.h"
|
||||||
#include "engine_build_config.h"
|
#include "engine_build_config.h"
|
||||||
#include "reusable_ids.h"
|
#include "reusable_ids.h"
|
||||||
|
#include <SDL2/SDL_mixer.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#ifdef DEBUG_ENGINE
|
#ifdef DEBUG_ENGINE
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#endif /* DEBUG_ENGINE */
|
#endif /* DEBUG_ENGINE */
|
||||||
|
|
||||||
INTERNAL struct game {
|
INTERNAL struct game_engine {
|
||||||
bool running;
|
bool running;
|
||||||
float delta;
|
float delta;
|
||||||
|
uint64_t last_time;
|
||||||
Window window;
|
Window window;
|
||||||
SDL_Event event;
|
SDL_Event event;
|
||||||
ObjectStore *object_store;
|
ObjectStore *object_store;
|
||||||
AssetManager *asset_manager;
|
AssetManager *asset_manager;
|
||||||
} Game;
|
} GameEngine;
|
||||||
|
|
||||||
bool init_game(const char *game_name, int window_width, int window_height,
|
bool init_game(const char *game_name, int window_width, int window_height,
|
||||||
SDL_Color window_background_color, bool full_screen) {
|
SDL_Color window_background_color, bool full_screen) {
|
||||||
@@ -40,11 +44,15 @@ bool init_game(const char *game_name, int window_width, int window_height,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IMG_Init(IMG_INIT_PNG) != IMG_INIT_PNG) {
|
uint32_t img_flags = IMG_INIT_PNG | IMG_INIT_TIF;
|
||||||
|
if ((IMG_Init(img_flags) & img_flags) != img_flags) {
|
||||||
|
#ifdef DEBUG_ENGINE
|
||||||
|
printf("Failed to initialise SDL. Error: %s\n", IMG_GetError());
|
||||||
|
#endif /* DEBUG_ENGINE */
|
||||||
initialisation_complete = false;
|
initialisation_complete = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!init_window(&(Game.window), game_name, window_width, window_height,
|
if (!init_window(&(GameEngine.window), game_name, window_width, window_height,
|
||||||
window_background_color, full_screen)) {
|
window_background_color, full_screen)) {
|
||||||
#ifdef DEBUG_ENGINE
|
#ifdef DEBUG_ENGINE
|
||||||
printf("Failed to initialise window\n");
|
printf("Failed to initialise window\n");
|
||||||
@@ -53,15 +61,15 @@ bool init_game(const char *game_name, int window_width, int window_height,
|
|||||||
initialisation_complete = false;
|
initialisation_complete = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Game.object_store = create_object_store();
|
GameEngine.object_store = create_object_store();
|
||||||
|
|
||||||
if (!(Game.object_store)) {
|
if (!(GameEngine.object_store)) {
|
||||||
initialisation_complete = false;
|
initialisation_complete = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Game.asset_manager = create_asset_manager();
|
GameEngine.asset_manager = create_asset_manager();
|
||||||
|
|
||||||
if (!(Game.asset_manager)) {
|
if (!(GameEngine.asset_manager)) {
|
||||||
initialisation_complete = false;
|
initialisation_complete = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,9 +79,9 @@ bool init_game(const char *game_name, int window_width, int window_height,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Game.running = true;
|
GameEngine.running = true;
|
||||||
// Game.delta = 0.0f;
|
GameEngine.delta = 0.0f;
|
||||||
Game.delta = 1.0f / 60.0f;
|
GameEngine.last_time = SDL_GetTicks64();
|
||||||
|
|
||||||
#ifdef DEBUG_ENGINE
|
#ifdef DEBUG_ENGINE
|
||||||
printf("Game initialised successfully\n");
|
printf("Game initialised successfully\n");
|
||||||
@@ -82,31 +90,32 @@ bool init_game(const char *game_name, int window_width, int window_height,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool game_running() { return Game.running; }
|
bool game_running() { return GameEngine.running; }
|
||||||
|
|
||||||
ObjectID add_object(void *object, EventHandlerPtr event_handler,
|
ObjectID add_object(void *object, EventHandlerPtr event_handler,
|
||||||
UpdateFuncPtr update_func, RenderFuncPtr render_func) {
|
UpdateFuncPtr update_func, RenderFuncPtr render_func) {
|
||||||
if (!(Game.running) || !(Game.object_store)) {
|
if (!(GameEngine.running) || !(GameEngine.object_store)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return add_object_to_store(Game.object_store, object, event_handler,
|
return add_object_to_store(GameEngine.object_store, object, event_handler,
|
||||||
update_func, render_func);
|
update_func, render_func);
|
||||||
}
|
}
|
||||||
|
|
||||||
void remove_object(ObjectID id) {
|
void remove_object(ObjectID *id) {
|
||||||
if (!(Game.running) || !(Game.object_store)) {
|
if (!(GameEngine.running) || !(GameEngine.object_store)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
remove_object_from_store(Game.object_store, id);
|
remove_object_from_store(GameEngine.object_store, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
AssetID load_asset(const char *path, AssetType type) {
|
AssetID load_asset(const char *path, AssetType type) {
|
||||||
return type == ASSET_TYPE_IMAGE
|
return type == ASSET_TYPE_IMAGE
|
||||||
? load_asset_to_manager(Game.asset_manager, path, type,
|
? load_asset_to_manager(GameEngine.asset_manager, path, type,
|
||||||
Game.window.renderer)
|
GameEngine.window.renderer)
|
||||||
: load_asset_to_manager(Game.asset_manager, path, type, NULL);
|
: load_asset_to_manager(GameEngine.asset_manager, path, type,
|
||||||
|
NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void render_texture_asset(AssetID id, float x, float y, float w, float h) {
|
void render_texture_asset(AssetID id, float x, float y, float w, float h) {
|
||||||
@@ -114,69 +123,79 @@ void render_texture_asset(AssetID id, float x, float y, float w, float h) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_Texture *texture = get_texture(Game.asset_manager, id);
|
SDL_Texture *texture = get_texture(GameEngine.asset_manager, id);
|
||||||
|
|
||||||
render_texture(Game.window.renderer, texture, x, y, w, h);
|
render_texture(GameEngine.window.renderer, texture, x, y, w, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
void close_asset(AssetID id) {
|
void close_asset(AssetID *id) {
|
||||||
remove_asset_from_manager(Game.asset_manager, id);
|
remove_asset_from_manager(GameEngine.asset_manager, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void handle_events() {
|
void handle_events() {
|
||||||
if (!(Game.running)) {
|
if (!(GameEngine.running)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (SDL_PollEvent(&(Game.event))) {
|
while (SDL_PollEvent(&(GameEngine.event))) {
|
||||||
switch (Game.event.type) {
|
switch (GameEngine.event.type) {
|
||||||
case SDL_QUIT:
|
case SDL_QUIT:
|
||||||
Game.running = false;
|
GameEngine.running = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Game.object_store) {
|
if (!GameEngine.object_store) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
handle_all_objects_events(Game.object_store, &(Game.event));
|
handle_all_objects_events(GameEngine.object_store, &(GameEngine.event));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void update() {
|
void update() {
|
||||||
if (!(Game.running) || !(Game.object_store)) {
|
if (!(GameEngine.running) || !(GameEngine.object_store)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
update_all_objects(Game.object_store, Game.delta);
|
uint64_t current_time = SDL_GetTicks64();
|
||||||
|
|
||||||
|
// Get the delta time in seconds since the SDL_GetTicks64() returns the
|
||||||
|
// time in milliseconds
|
||||||
|
GameEngine.delta = (current_time - GameEngine.last_time) / 1000.0f;
|
||||||
|
|
||||||
|
update_all_objects(GameEngine.object_store, GameEngine.delta);
|
||||||
|
|
||||||
|
GameEngine.last_time = current_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
void render() {
|
void render() {
|
||||||
if (!(Game.running)) {
|
if (!(GameEngine.running)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
clear_window(&(Game.window));
|
clear_window(&(GameEngine.window));
|
||||||
|
|
||||||
if (Game.object_store) {
|
if (GameEngine.object_store) {
|
||||||
render_all_objects(Game.object_store);
|
render_all_objects(GameEngine.object_store);
|
||||||
}
|
}
|
||||||
|
|
||||||
swap_render_buffers(&(Game.window));
|
swap_render_buffers(&(GameEngine.window));
|
||||||
}
|
}
|
||||||
|
|
||||||
void close_game() {
|
void close_game() {
|
||||||
destroy_asset_manager(Game.asset_manager);
|
destroy_asset_manager(GameEngine.asset_manager);
|
||||||
Game.asset_manager = NULL;
|
GameEngine.asset_manager = NULL;
|
||||||
|
|
||||||
destroy_object_store(Game.object_store);
|
destroy_object_store(GameEngine.object_store);
|
||||||
Game.object_store = NULL;
|
GameEngine.object_store = NULL;
|
||||||
|
|
||||||
destroy_window(&(Game.window));
|
destroy_window(&(GameEngine.window));
|
||||||
|
|
||||||
Game.delta = 0.0f;
|
GameEngine.last_time = 0.0f;
|
||||||
|
|
||||||
Game.running = false;
|
GameEngine.delta = 0.0f;
|
||||||
|
|
||||||
|
GameEngine.running = false;
|
||||||
|
|
||||||
IMG_Quit();
|
IMG_Quit();
|
||||||
|
|
||||||
|
|||||||
+7
-3
@@ -49,7 +49,7 @@ ObjectID add_object_to_store(ObjectStore *os, void *object, EventHandlerPtr eh,
|
|||||||
printf("Failed to add object\n");
|
printf("Failed to add object\n");
|
||||||
#endif /* DEBUG_ENGINE */
|
#endif /* DEBUG_ENGINE */
|
||||||
|
|
||||||
return -1;
|
return INVALID_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO (Abdelrahman): Need to figure out a way to check that the object
|
// TODO (Abdelrahman): Need to figure out a way to check that the object
|
||||||
@@ -78,11 +78,15 @@ ObjectID add_object_to_store(ObjectStore *os, void *object, EventHandlerPtr eh,
|
|||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
void remove_object_from_store(ObjectStore *os, ObjectID id) {
|
void remove_object_from_store(ObjectStore *os, ObjectID *id_ptr) {
|
||||||
if (!os || os->count == 0 || !(os->object_ptrs[id])) {
|
ObjectID id = *id_ptr;
|
||||||
|
|
||||||
|
if (!os || os->count == 0 || id == INVALID_ID || !(os->object_ptrs[id])) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*id_ptr = INVALID_ID;
|
||||||
|
|
||||||
os->object_ptrs[id] = NULL;
|
os->object_ptrs[id] = NULL;
|
||||||
os->event_handlers[id] = NULL;
|
os->event_handlers[id] = NULL;
|
||||||
os->update_funcs[id] = NULL;
|
os->update_funcs[id] = NULL;
|
||||||
|
|||||||
@@ -8,5 +8,7 @@ int32_t reuse_id(int32_t *ids, size_t count) {
|
|||||||
ids[i] = ids[i + 1];
|
ids[i] = ids[i + 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ids[count - 1] = INVALID_ID;
|
||||||
|
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user