Moved ecs.c into core and added much better error and debug handling.
This commit is contained in:
parent
d193aa5fd4
commit
2e1eaf4c1c
|
|
@ -2,16 +2,18 @@
|
|||
CORE_SOURCES := \
|
||||
linked_list.c \
|
||||
vector2d.c \
|
||||
events.c \
|
||||
asset_manager.c \
|
||||
ecs.c \
|
||||
display.c \
|
||||
event.c
|
||||
main.c
|
||||
|
||||
# Compiler and flags
|
||||
CORE_CC = gcc
|
||||
ifeq ($(RELEASE), 1)
|
||||
CORE_CFLAGS = --std=c17 --pedantic -O3 -DASSET_FILE_NAME=\"$(ASSET_OUTPUT)\" $(shell pkg-config --cflags sdl2) # RELEASE
|
||||
else
|
||||
CORE_CFLAGS = --std=c17 --pedantic -O0 -g -DASSET_FILE_NAME=\"$(ASSET_OUTPUT)\" $(shell pkg-config --cflags sdl2) \
|
||||
CORE_CFLAGS = --std=c17 --pedantic -O0 -g -DDEBUG=1 -DASSET_FILE_NAME=\"$(ASSET_OUTPUT)\" $(shell pkg-config --cflags sdl2) \
|
||||
-Wall -Wno-missing-braces -Wextra -Wno-missing-field-initializers \
|
||||
-Wformat=2 -Wswitch-default -Wswitch-enum -Wcast-align \
|
||||
-Wpointer-arith -Wbad-function-cast -Wstrict-overflow=5 \
|
||||
|
|
@ -21,7 +23,7 @@ CORE_CFLAGS = --std=c17 --pedantic -O0 -g -DASSET_FILE_NAME=\"$(ASSET_OUTPUT)\"
|
|||
-Wold-style-definition # DEVELOPEMENT
|
||||
endif
|
||||
|
||||
CORE_INCLUDE_DIRS = $(CORE_DIR)/headers
|
||||
CORE_INCLUDE_DIRS = $(CORE_DIR)/headers $(SOURCE_DIR)/components/headers
|
||||
CORE_INCLUDE_DIRS := $(addprefix -I, $(CORE_INCLUDE_DIRS))
|
||||
|
||||
CORE_AR = ar
|
||||
|
|
|
|||
|
|
@ -3,17 +3,22 @@
|
|||
#include <SDL2/SDL_render.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "linked_list.h"
|
||||
#include "memory_alloc.h"
|
||||
#include "linked_list.h"
|
||||
#include "display.h"
|
||||
#include "errors.h"
|
||||
|
||||
asset_t *create_asset(asset_type_t asset_type)
|
||||
{
|
||||
asset_t *asset = malloc(sizeof(asset_t));
|
||||
if(!asset)
|
||||
{
|
||||
error_printf("Failed to allocate memory : %d", errno);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
asset->type = asset_type;
|
||||
asset->nb_refs = 1;
|
||||
asset->nb_refs = 0;
|
||||
|
||||
return asset;
|
||||
}
|
||||
|
|
@ -26,8 +31,10 @@ void destroy_asset(asset_t *asset)
|
|||
{
|
||||
case ASSET_TEXTURE:
|
||||
SDL_DestroyTexture(asset->data.texture);
|
||||
break;
|
||||
|
||||
default:
|
||||
error_printf("Asset type not valid : %d", asset->type);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -40,7 +47,7 @@ void destroy_asset_header_def(asset_header_def_t *asset_header_def)
|
|||
free(asset_header_def);
|
||||
}
|
||||
|
||||
void asset_manager_init(asset_manager_t *asset_manager)
|
||||
int asset_manager_init(asset_manager_t *asset_manager)
|
||||
{
|
||||
linked_list_init(&asset_manager->assets, sizeof(asset_t), (deleter_t)destroy_asset);
|
||||
linked_list_init(&asset_manager->assets_header_defs, sizeof(asset_header_def_t), (deleter_t)destroy_asset_header_def);
|
||||
|
|
@ -48,47 +55,59 @@ void asset_manager_init(asset_manager_t *asset_manager)
|
|||
asset_manager->asset_file = fopen(ASSET_FILE_NAME, "rb");
|
||||
if(!asset_manager->asset_file)
|
||||
{
|
||||
printf("can't open asset file : %s.\n", ASSET_FILE_NAME);
|
||||
return;
|
||||
error_printf("Failed to open asset file : %d", errno);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
size_t nb_assets;
|
||||
size_t ret = fread(&nb_assets, sizeof(nb_assets), 1, asset_manager->asset_file);
|
||||
if(ret != 1)
|
||||
{
|
||||
printf("can't read asset file.");
|
||||
return;
|
||||
error_printf("Failed to read asset file.");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < nb_assets; i++)
|
||||
{
|
||||
elem_t *elem = elem_create(&asset_manager->assets_header_defs);
|
||||
if(!elem) return EXIT_FAILURE;
|
||||
|
||||
size_t cap = 0;
|
||||
|
||||
ret = getdelim(&((asset_header_def_t *)elem->data)->name, &cap, '\0', asset_manager->asset_file);
|
||||
if(ret == SIZE_MAX)
|
||||
{
|
||||
printf("can't read asset file.");
|
||||
return;
|
||||
error_printf("Failed to read asset file.");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
ret = fread(&((asset_header_def_t *)elem->data)->start, sizeof(((asset_header_def_t *)elem->data)->start), 1, asset_manager->asset_file);
|
||||
if(ret != 1)
|
||||
{
|
||||
printf("can't read asset file.");
|
||||
return;
|
||||
error_printf("Failed to read asset file.");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
linked_list_push_back_elem(&asset_manager->assets_header_defs, elem);
|
||||
}
|
||||
|
||||
debug_printf("Initialized asset manager.");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
void asset_manager_exit(asset_manager_t *asset_manager)
|
||||
int asset_manager_exit(asset_manager_t *asset_manager)
|
||||
{
|
||||
linked_list_clear(&asset_manager->assets_header_defs);
|
||||
linked_list_clear(&asset_manager->assets);
|
||||
fclose(asset_manager->asset_file);
|
||||
|
||||
if(fclose(asset_manager->asset_file))
|
||||
{
|
||||
error_printf("Failed to close asset file : %d", errno);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
debug_printf("Exited asset manager.");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
// Only for this file
|
||||
|
|
@ -117,105 +136,148 @@ static inline bool condition_is_asset_header_def_name(elem_t *elem, va_list args
|
|||
return !strcmp(((asset_header_def_t *)elem->data)->name, va_arg(args, const char *));
|
||||
}
|
||||
|
||||
static inline void load_texture(asset_manager_t *asset_manager, asset_t *asset, asset_header_def_t *asset_header_def)
|
||||
static inline int load_texture(asset_manager_t *asset_manager, asset_t *asset, asset_header_def_t *asset_header_def)
|
||||
{
|
||||
if(fseek(asset_manager->asset_file, asset_header_def->start, SEEK_SET))
|
||||
{
|
||||
printf("Couldn't seek in asset file.");
|
||||
return;
|
||||
error_printf("Failed to seek in asset file : %d", errno);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
size_t width, height;
|
||||
|
||||
if(fread(&width, sizeof(width), 1, asset_manager->asset_file) != 1)
|
||||
{
|
||||
printf("Failed to read in asset file.");
|
||||
return;
|
||||
error_printf("Failed to read in asset file.");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if(fread(&height, sizeof(height), 1, asset_manager->asset_file) != 1)
|
||||
{
|
||||
printf("Failed to read in asset file.");
|
||||
return;
|
||||
error_printf("Failed to read in asset file.");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
SDL_Surface *tmp_surface = SDL_CreateRGBSurfaceWithFormat(0, width, height, 16, SDL_PIXELFORMAT_RGB565);
|
||||
if(!tmp_surface)
|
||||
{
|
||||
error_printf("Failed to create temporary surface : %s", SDL_GetError());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if(SDL_LockSurface(tmp_surface))
|
||||
{
|
||||
printf("Couldn't lock surface : %s\n", SDL_GetError());
|
||||
return;
|
||||
printf("Failed to lock temporary surface : %s", SDL_GetError());
|
||||
SDL_FreeSurface(tmp_surface);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if(fread(tmp_surface->pixels, sizeof(uint16_t), width * height, asset_manager->asset_file) != width * height)
|
||||
{
|
||||
printf("Failed to read asset file.");
|
||||
return;
|
||||
SDL_FreeSurface(tmp_surface);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
SDL_SetColorKey(tmp_surface, SDL_TRUE, SDL_MapRGB(tmp_surface->format, 0xFF, 0x00, 0xFF));
|
||||
if(SDL_SetColorKey(tmp_surface, SDL_TRUE, SDL_MapRGB(tmp_surface->format, 0xFF, 0x00, 0xFF)))
|
||||
{
|
||||
error_printf("Failed to set color key of temporary surface : %s", SDL_GetError());
|
||||
SDL_FreeSurface(tmp_surface);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
asset->data.texture = SDL_CreateTextureFromSurface(renderer, tmp_surface);
|
||||
if(!asset->data.texture)
|
||||
{
|
||||
error_printf("Failed to create texture from temporary surface : %s", SDL_GetError());
|
||||
SDL_FreeSurface(tmp_surface);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
SDL_FreeSurface(tmp_surface);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
void asset_manager_load_asset(asset_manager_t *asset_manager, const char *asset_name, asset_type_t asset_type)
|
||||
int asset_manager_load_asset(asset_manager_t *asset_manager, const char *asset_name, asset_type_t asset_type)
|
||||
{
|
||||
// Check if asset has alread been loaded.
|
||||
asset_t *asset = linked_list_get_if(&asset_manager->assets, condition_is_asset_name, asset_name);
|
||||
if(asset)
|
||||
if(!asset)
|
||||
{
|
||||
asset->nb_refs++;
|
||||
return;
|
||||
// If it didn't, load it
|
||||
asset_header_def_t *asset_header_def = linked_list_get_if(&asset_manager->assets_header_defs, condition_is_asset_header_def_name, asset_name);
|
||||
if(!asset_header_def)
|
||||
{
|
||||
error_printf("Asset doesn't exist in asset file : %s", asset_name);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
asset = create_asset(asset_type);
|
||||
if(!asset) return EXIT_FAILURE;
|
||||
|
||||
asset->name = malloc(strlen(asset_name) + 1);
|
||||
if(!asset->name)
|
||||
{
|
||||
error_printf("Failed to allocate memory for asset name : %d", errno);
|
||||
destroy_asset(asset);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
strcpy(asset->name, asset_name);
|
||||
asset->type = asset_type;
|
||||
|
||||
switch(asset_type)
|
||||
{
|
||||
case ASSET_TEXTURE:
|
||||
if(load_texture(asset_manager, asset, asset_header_def)) return EXIT_FAILURE;
|
||||
break;
|
||||
|
||||
default:
|
||||
error_printf("Asset type doesn't exists : %d", asset_type);
|
||||
destroy_asset(asset);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
linked_list_push_back(&asset_manager->assets, asset);
|
||||
}
|
||||
|
||||
asset_header_def_t *asset_header_def = linked_list_get_if(&asset_manager->assets_header_defs, condition_is_asset_header_def_name, asset_name);
|
||||
if(!asset_header_def)
|
||||
{
|
||||
printf("Asset doesn't exist in asset file : %s\n", asset_name);
|
||||
return;
|
||||
}
|
||||
|
||||
asset = create_asset(asset_type);
|
||||
asset->name = malloc(strlen(asset_name) + 1);
|
||||
strcpy(asset->name, asset_name);
|
||||
asset->type = asset_type;
|
||||
|
||||
switch(asset_type)
|
||||
{
|
||||
case ASSET_TEXTURE:
|
||||
load_texture(asset_manager, asset, asset_header_def);
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
linked_list_push_back(&asset_manager->assets, asset);
|
||||
asset->nb_refs++;
|
||||
debug_printf("Asset \"%s\" has been loaded, nb refs : %lu", asset->name, asset->nb_refs);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
void asset_manager_let_go_asset(asset_manager_t *asset_manager, const char *asset_name)
|
||||
int asset_manager_let_go_asset(asset_manager_t *asset_manager, const char *asset_name)
|
||||
{
|
||||
asset_t *asset = linked_list_get_if(&asset_manager->assets, condition_is_asset_name, asset_name);
|
||||
if(asset)
|
||||
if(!asset)
|
||||
{
|
||||
asset->nb_refs--;
|
||||
error_printf("Asset doesn't exists : %s", asset_name);
|
||||
}
|
||||
|
||||
asset->nb_refs--;
|
||||
debug_printf("Asset \"%s\" has been let go, nb refs : %lu", asset->name, asset->nb_refs);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
texture_t *asset_manager_get_texture(asset_manager_t *asset_manager, const char *asset_name)
|
||||
{
|
||||
asset_t *asset = linked_list_get_if(&asset_manager->assets, condition_is_asset_name, asset_name);
|
||||
if(!asset)
|
||||
{
|
||||
error_printf("Asset \"%s\" hasn't been loaded yet.", asset_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(asset->type != ASSET_TEXTURE)
|
||||
{
|
||||
error_printf("Asset \"%s\" isn't of type ASSET_TEXTURE.", asset_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return asset->data.texture;
|
||||
}
|
||||
|
||||
void asset_manager_draw_texture(texture_t *texture, rect_t *src_rect, rect_t *dst_rect, bool flip)
|
||||
int asset_manager_draw_texture(texture_t *texture, rect_t *src_rect, rect_t *dst_rect, bool flip)
|
||||
{
|
||||
if(flip)
|
||||
{
|
||||
|
|
@ -223,5 +285,11 @@ void asset_manager_draw_texture(texture_t *texture, rect_t *src_rect, rect_t *ds
|
|||
dst_rect->w = -dst_rect->w;
|
||||
}
|
||||
|
||||
SDL_RenderCopy(renderer, texture, src_rect, dst_rect);
|
||||
if(SDL_RenderCopy(renderer, texture, src_rect, dst_rect))
|
||||
{
|
||||
error_printf("Failed to copy texture to renderer : %s", SDL_GetError());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,49 +2,70 @@
|
|||
|
||||
#include <SDL2/SDL.h>
|
||||
#include <stdio.h>
|
||||
#include "errors.h"
|
||||
|
||||
SDL_Window *window = NULL;
|
||||
SDL_Renderer *renderer = NULL;
|
||||
|
||||
inline void display_init(void)
|
||||
inline int display_init(void)
|
||||
{
|
||||
if(SDL_Init(SDL_INIT_EVERYTHING))
|
||||
if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS))
|
||||
{
|
||||
printf("Couldn't initialize SDL: %s\n", SDL_GetError());
|
||||
return;
|
||||
printf("SDL failed to initialised : %s\n", SDL_GetError());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
window = SDL_CreateWindow("2D_Engine", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, DISPLAY_WIDTH * RENDER_SCALE, DISPLAY_HEIGHT * RENDER_SCALE, SDL_WINDOW_SHOWN);
|
||||
if(!window)
|
||||
{
|
||||
printf("Couldn't create window : %s\n", SDL_GetError());
|
||||
return;
|
||||
printf("Failed to create window : %s\n", SDL_GetError());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
|
||||
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
|
||||
if(!renderer)
|
||||
{
|
||||
printf("Couldn't create renderer : %s\n", SDL_GetError());
|
||||
return;
|
||||
error_printf("Failed to create renderer : %s\n", SDL_GetError());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
SDL_RenderSetScale(renderer, RENDER_SCALE, RENDER_SCALE);
|
||||
if(SDL_RenderSetScale(renderer, RENDER_SCALE, RENDER_SCALE))
|
||||
{
|
||||
error_printf("Failed to change renderer scale : %s\n", SDL_GetError());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
debug_printf("Initialized display.");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
inline void display_exit(void)
|
||||
{
|
||||
if(renderer) SDL_DestroyRenderer(renderer);
|
||||
if(window) SDL_DestroyWindow(window);
|
||||
SDL_Quit();
|
||||
|
||||
debug_printf("Exited display.");
|
||||
}
|
||||
|
||||
inline int display_clear(void)
|
||||
{
|
||||
if(SDL_SetRenderDrawColor(renderer, C_WHITE))
|
||||
{
|
||||
error_printf("Failed to change renderer draw color : %s\n", SDL_GetError());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if(SDL_RenderClear(renderer))
|
||||
{
|
||||
error_printf("Failed to clear renderer : %s\n", SDL_GetError());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
inline void display_update(void)
|
||||
{
|
||||
SDL_RenderPresent(renderer);
|
||||
}
|
||||
|
||||
inline void display_clear(void)
|
||||
{
|
||||
SDL_SetRenderDrawColor(renderer, C_WHITE);
|
||||
SDL_RenderClear(renderer);
|
||||
}
|
||||
|
||||
inline void display_exit(void)
|
||||
{
|
||||
SDL_DestroyRenderer(renderer);
|
||||
SDL_DestroyWindow(window);
|
||||
SDL_Quit();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,189 @@
|
|||
#include <stdarg.h>
|
||||
#include "memory_alloc.h"
|
||||
#include "ecs.h"
|
||||
#include "components.h"
|
||||
#include "errors.h"
|
||||
|
||||
component_t *create_component(component_type_t component_type)
|
||||
{
|
||||
component_t *component = malloc(sizeof(component_t));
|
||||
if(!component)
|
||||
{
|
||||
error_printf("Failed to allocate memory : %d", errno);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
component->component_type = component_type;
|
||||
|
||||
switch(component_type)
|
||||
{
|
||||
#define COMPONENT(NAME, PREFIX, DRAW) \
|
||||
case NAME: \
|
||||
component->component_init = PREFIX##_init; \
|
||||
component->component_update = PREFIX##_update; \
|
||||
component->component_draw = DRAW(PREFIX); \
|
||||
component->component_data = malloc(sizeof(PREFIX##_data_t)); \
|
||||
if(!component->component_data) \
|
||||
{ \
|
||||
free(component); \
|
||||
error_printf("Failed to allocate memory : %d", errno); \
|
||||
return NULL; \
|
||||
} \
|
||||
component->component_deleter = PREFIX##_destroy; \
|
||||
break;
|
||||
#include "components.def"
|
||||
|
||||
default:
|
||||
free(component);
|
||||
error_printf("Component type doesn't exists : %d", component_type);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return component;
|
||||
}
|
||||
|
||||
inline void destroy_component(component_t *component)
|
||||
{
|
||||
component->component_deleter(component);
|
||||
free(component);
|
||||
}
|
||||
|
||||
entity_t *create_entity(const unsigned int id)
|
||||
{
|
||||
entity_t *entity = malloc(sizeof(entity_t));
|
||||
if(!entity)
|
||||
{
|
||||
error_printf("Failed to allocate memory : %d", errno);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
entity->id = id;
|
||||
entity->draw_priority = 0;
|
||||
|
||||
linked_list_init(&entity->components, sizeof(component_t), (deleter_t)destroy_component);
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
void add_component(entity_t *entity, component_t *component, ...)
|
||||
{
|
||||
component->entity = entity;
|
||||
|
||||
va_list args, args_copy;
|
||||
|
||||
va_start(args, component);
|
||||
va_copy(args_copy, args);
|
||||
|
||||
component->component_init(component, args_copy);
|
||||
|
||||
va_end(args_copy);
|
||||
va_end(args);
|
||||
|
||||
linked_list_push_back(&entity->components, component);
|
||||
}
|
||||
|
||||
// Only for this file
|
||||
// Arg : component_type_t component_type
|
||||
static inline bool condition_is_component_type(elem_t *elem, va_list args)
|
||||
{
|
||||
return ((component_t *)elem->data)->component_type == va_arg(args, component_type_t);
|
||||
}
|
||||
|
||||
inline component_t *get_component(entity_t *entity, component_type_t component_type)
|
||||
{
|
||||
component_t *component = linked_list_get_if(&entity->components, condition_is_component_type, component_type);
|
||||
if(!component)
|
||||
{
|
||||
error_printf("Entity doesn't have componant of type : %d", component_type);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return component;
|
||||
}
|
||||
|
||||
// Only for this file
|
||||
// No args
|
||||
static inline int action_update_component(elem_t *elem, va_list args __attribute__((unused)))
|
||||
{
|
||||
component_t *component = elem->data;
|
||||
component->component_update(component);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
inline void update_entity(entity_t *entity)
|
||||
{
|
||||
linked_list_for_each(&entity->components, action_update_component);
|
||||
}
|
||||
|
||||
// Only for this file
|
||||
// No args
|
||||
static inline int action_draw_component(elem_t *elem, va_list args __attribute__((unused)))
|
||||
{
|
||||
component_t *component = elem->data;
|
||||
if(component->component_draw) component->component_draw(component);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
inline int draw_entity(entity_t *entity)
|
||||
{
|
||||
return linked_list_for_each(&entity->components, action_draw_component);
|
||||
}
|
||||
|
||||
inline void destroy_entity(entity_t *entity)
|
||||
{
|
||||
linked_list_clear(&entity->components);
|
||||
free(entity);
|
||||
}
|
||||
|
||||
inline void entity_manager_init(entity_manager_t *entity_manager)
|
||||
{
|
||||
linked_list_init(&entity_manager->entities, sizeof(entity_t), (deleter_t)destroy_entity);
|
||||
}
|
||||
|
||||
inline void entity_manager_add_entity(entity_manager_t *entity_manager, entity_t *entity)
|
||||
{
|
||||
linked_list_push_back(&entity_manager->entities, entity);
|
||||
}
|
||||
|
||||
// Only for this file
|
||||
// No args
|
||||
static inline int action_update_entity(elem_t *elem, va_list args __attribute__((unused)))
|
||||
{
|
||||
update_entity((entity_t *)elem->data);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
inline void entity_manager_update(entity_manager_t *entity_manager)
|
||||
{
|
||||
linked_list_for_each(&entity_manager->entities, action_update_entity);
|
||||
}
|
||||
|
||||
// Only for this file
|
||||
// No args
|
||||
static inline int action_draw_entity(elem_t *elem, va_list args __attribute__((unused)))
|
||||
{
|
||||
return draw_entity((entity_t *)elem->data);
|
||||
}
|
||||
|
||||
inline int entity_manager_draw(entity_manager_t *entity_manager)
|
||||
{
|
||||
return linked_list_for_each(&entity_manager->entities, action_draw_entity);
|
||||
}
|
||||
|
||||
// Only for this file
|
||||
// Arg : unsigned int id
|
||||
static inline bool condition_is_entity_name(elem_t *elem, va_list args)
|
||||
{
|
||||
return ((entity_t *)elem->data)->id == va_arg(args, unsigned int);
|
||||
}
|
||||
|
||||
inline void entity_manager_remove_entity(entity_manager_t *entity_manager, unsigned int id)
|
||||
{
|
||||
linked_list_remove_if(&entity_manager->entities, condition_is_entity_name, id);
|
||||
}
|
||||
|
||||
inline void entity_manager_exit(entity_manager_t *entity_manager)
|
||||
{
|
||||
linked_list_clear(&entity_manager->entities);
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
#include "event.h"
|
||||
#include "events.h"
|
||||
|
||||
#include <SDL2/SDL_events.h>
|
||||
|
||||
|
|
@ -42,14 +42,14 @@ typedef struct asset_manager_t {
|
|||
FILE *asset_file;
|
||||
} asset_manager_t;
|
||||
|
||||
void asset_manager_init(asset_manager_t *asset_manager);
|
||||
void asset_manager_exit(asset_manager_t *asset_manager);
|
||||
int asset_manager_init(asset_manager_t *asset_manager);
|
||||
int asset_manager_exit(asset_manager_t *asset_manager);
|
||||
void asset_manager_collect_garbage(asset_manager_t *asset_manager);
|
||||
|
||||
void asset_manager_load_asset(asset_manager_t *asset_manager, const char *asset_name, asset_type_t asset_type);
|
||||
void asset_manager_let_go_asset(asset_manager_t *asset_manager, const char *asset_name);
|
||||
int asset_manager_load_asset(asset_manager_t *asset_manager, const char *asset_name, asset_type_t asset_type);
|
||||
int asset_manager_let_go_asset(asset_manager_t *asset_manager, const char *asset_name);
|
||||
|
||||
texture_t *asset_manager_get_texture(asset_manager_t *asset_manager, const char *asset_name);
|
||||
void asset_manager_draw_texture(texture_t *texture, rect_t *src_rect, rect_t *dst_rect, bool flip);
|
||||
int asset_manager_draw_texture(texture_t *texture, rect_t *src_rect, rect_t *dst_rect, bool flip);
|
||||
|
||||
#endif // ASSET_MANAGER_H
|
||||
|
|
@ -2,7 +2,6 @@
|
|||
#define DISPLAY_H
|
||||
|
||||
#include <SDL2/SDL_render.h>
|
||||
#include "vector2d.h"
|
||||
|
||||
#define C_BLACK 0, 0, 0, 255
|
||||
#define C_WHITE 255, 255, 255, 255
|
||||
|
|
@ -14,12 +13,11 @@
|
|||
extern SDL_Window *window;
|
||||
extern SDL_Renderer *renderer;
|
||||
|
||||
void display_init(void);
|
||||
|
||||
void display_update(void);
|
||||
|
||||
void display_clear(void);
|
||||
|
||||
int display_init(void);
|
||||
void display_exit(void);
|
||||
|
||||
int display_clear(void);
|
||||
void display_update(void);
|
||||
|
||||
|
||||
#endif // DISPLAY_H
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
#ifndef ECS_H
|
||||
#define ECS_H
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include "linked_list.h"
|
||||
|
||||
typedef enum component_type_t {
|
||||
#define COMPONENT(NAME, PREFIX, DRAW) NAME,
|
||||
#include "components.def"
|
||||
} component_type_t;
|
||||
|
||||
// Component forwarding
|
||||
typedef struct component_t component_t;
|
||||
|
||||
// Component init function. It is called when component added to entity. This function is necessary.
|
||||
typedef void (*component_init_t)(component_t *component, va_list args);
|
||||
// Component update function. It is called in the main loop to update the component. This function is necessary.
|
||||
typedef void (*component_update_t)(component_t *component);
|
||||
// Component draw function. It is called in the main loop to draw the component on screen. This function is not necessary.
|
||||
typedef int (*component_draw_t)(component_t *component);
|
||||
// Component deleter function. It is called when the component is removed. It should free the data in the component data but not the component itself.
|
||||
typedef void (*component_deleter_t)(component_t *component);
|
||||
|
||||
typedef struct component_t {
|
||||
component_init_t component_init;
|
||||
component_update_t component_update;
|
||||
component_draw_t component_draw;
|
||||
|
||||
void *component_data;
|
||||
|
||||
component_deleter_t component_deleter;
|
||||
|
||||
struct entity_t *entity;
|
||||
|
||||
component_type_t component_type;
|
||||
|
||||
} component_t;
|
||||
|
||||
component_t *create_component(component_type_t component_type);
|
||||
|
||||
void destroy_component(component_t *component);
|
||||
|
||||
typedef struct entity_t {
|
||||
unsigned int id;
|
||||
size_t draw_priority;
|
||||
linked_list_t components;
|
||||
} entity_t;
|
||||
|
||||
entity_t *create_entity(const unsigned int id);
|
||||
|
||||
void add_component(entity_t *entity, component_t *component, ...);
|
||||
|
||||
component_t *get_component(entity_t *entity, component_type_t component_type);
|
||||
|
||||
void update_entity(entity_t *entity);
|
||||
|
||||
int draw_entity(entity_t *entity);
|
||||
|
||||
void destroy_entity(entity_t *entity);
|
||||
|
||||
typedef struct entity_manager_t {
|
||||
linked_list_t entities;
|
||||
} entity_manager_t;
|
||||
|
||||
void entity_manager_init(entity_manager_t *entity_manager);
|
||||
|
||||
void entity_manager_add_entity(entity_manager_t *entity_manager, entity_t *entity);
|
||||
|
||||
void entity_manager_update(entity_manager_t *entity_manager);
|
||||
|
||||
int entity_manager_draw(entity_manager_t *entity_manager);
|
||||
|
||||
void entity_manager_remove_entity(entity_manager_t *entity_manager, const unsigned int id);
|
||||
|
||||
void entity_manager_exit(entity_manager_t *entity_manager);
|
||||
|
||||
#endif // ECS_H
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
#ifndef ERRORS_H
|
||||
#define ERRORS_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#ifndef DEBUG
|
||||
#define DEBUG 0
|
||||
#endif
|
||||
|
||||
#if DEBUG > 0
|
||||
#define debug_printf(fmt, ...) \
|
||||
do { \
|
||||
fprintf(stderr, "\033[33mINFO\033[m: %s:%d:%s(): " fmt "\n", __FILE__, __LINE__, __func__, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
#else
|
||||
#define debug_printf(fmt, ...) do {} while (0)
|
||||
#endif
|
||||
|
||||
#define error_printf(fmt, ...) \
|
||||
do { \
|
||||
fprintf(stderr, "\033[31mERROR\033[m: %s:%d:%s(): " fmt "\n", __FILE__, __LINE__, __func__, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#endif // ERRORS_H
|
||||
|
|
@ -2,6 +2,8 @@
|
|||
#define KEYBOARD_H
|
||||
|
||||
#include <SDL2/SDL_events.h>
|
||||
#include "vector2d.h"
|
||||
#include "keycodes.h"
|
||||
|
||||
#define EVENT_KEY_UP SDL_KEYUP
|
||||
#define EVENT_KEY_DOWN SDL_KEYDOWN
|
||||
|
|
@ -14,4 +16,9 @@ typedef struct event_t {
|
|||
|
||||
int pollevent(event_t *event);
|
||||
|
||||
typedef struct events_t {
|
||||
vector2d_t cursor_pos;
|
||||
bool keys[MAX_KEYCODES];
|
||||
} events_t;
|
||||
|
||||
#endif // KEYBOARD_H
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
#ifndef GAME_H
|
||||
#define GAME_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "asset_manager.h"
|
||||
#include "ecs.h"
|
||||
#include "events.h"
|
||||
|
||||
/**
|
||||
* @brief Game data.
|
||||
* There should be only one instance of this struct.
|
||||
*
|
||||
* @param event Events data
|
||||
* @param texture_manager Texture manager instance
|
||||
* @param entity_manager Entity manager instance
|
||||
* @param is_running Game running state
|
||||
* @param delta_time_ms Frame time
|
||||
*/
|
||||
typedef struct game_t {
|
||||
asset_manager_t asset_manager;
|
||||
entity_manager_t entity_manager;
|
||||
events_t events;
|
||||
|
||||
float delta_time_ms;
|
||||
bool is_running;
|
||||
} game_t;
|
||||
|
||||
// Global game instance
|
||||
extern game_t game;
|
||||
|
||||
// Initialise game
|
||||
int game_init(void);
|
||||
|
||||
// Handle event like inputs
|
||||
void game_handle_event(void);
|
||||
|
||||
// Update game
|
||||
void game_update(void);
|
||||
|
||||
// Render game
|
||||
int game_render(void);
|
||||
|
||||
// Free game instance
|
||||
int game_exit(void);
|
||||
|
||||
#endif // GAME_H
|
||||
|
|
@ -56,14 +56,15 @@ typedef bool (*condition_t)(elem_t *elem, va_list args);
|
|||
* For function like linked_list_for_each you need an action to do.
|
||||
* It have two argument which are "elem_t *" and "va_list", that is because it passes the element on the actual index
|
||||
* and the args passed to the function.
|
||||
* You can use the return value to indicate an error with EXIT_SUCCESS or EXIT_FAILURE.
|
||||
* Your condition_t function declaration must look like this :
|
||||
*
|
||||
* void name_of_your_condition(elem_t *elem, va_list);
|
||||
* int name_of_your_condition(elem_t *elem, va_list);
|
||||
*
|
||||
* Then do whatever you want with the element data, just don't remove it.
|
||||
* Then do whatever you want with the element data, just don't free it.
|
||||
* You should always define your function with "static", and "inline".
|
||||
*/
|
||||
typedef void (*action_t)(elem_t *elem, va_list args);
|
||||
typedef int (*action_t)(elem_t *elem, va_list args);
|
||||
|
||||
/**
|
||||
* @brief Base of linked lists.
|
||||
|
|
@ -282,7 +283,9 @@ void linked_list_remove_if(linked_list_t *linked_list, const condition_t conditi
|
|||
* @param linked_list Pointer to an linked list
|
||||
* @param action Action to apply
|
||||
* @param ... Argument to pass to the action
|
||||
*
|
||||
* @return The success of the action if supported by the action.
|
||||
*/
|
||||
void linked_list_for_each(const linked_list_t *linked_list, const action_t action, ...);
|
||||
int linked_list_for_each(const linked_list_t *linked_list, const action_t action, ...);
|
||||
|
||||
#endif // LINKED_LIST_H
|
||||
|
|
|
|||
|
|
@ -1,21 +1,27 @@
|
|||
#include <stdarg.h>
|
||||
#include "memory_alloc.h"
|
||||
#include "linked_list.h"
|
||||
#include "errors.h"
|
||||
|
||||
elem_t *elem_create(const linked_list_t *linked_list)
|
||||
{
|
||||
elem_t *tmp;
|
||||
tmp = malloc(sizeof(elem_t));
|
||||
if(!tmp) return NULL;
|
||||
|
||||
tmp->data = malloc(linked_list->data_size);
|
||||
if(!tmp->data)
|
||||
elem_t *elem;
|
||||
elem = malloc(sizeof(elem_t));
|
||||
if(!elem)
|
||||
{
|
||||
free(tmp);
|
||||
error_printf("Failed to allocate memory : %d", errno);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return tmp;
|
||||
elem->data = malloc(linked_list->data_size);
|
||||
if(!elem->data)
|
||||
{
|
||||
error_printf("Failed to allocate memory : %d", errno);
|
||||
free(elem);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return elem;
|
||||
}
|
||||
|
||||
inline void destroy_elem(elem_t *elem, const deleter_t elem_deleter)
|
||||
|
|
@ -77,7 +83,11 @@ void linked_list_push_front_elem(linked_list_t *linked_list, elem_t *elem)
|
|||
void linked_list_push_back(linked_list_t *linked_list, void *data)
|
||||
{
|
||||
elem_t *tmp = malloc(sizeof(elem_t));
|
||||
if(!tmp) return;
|
||||
if(!tmp)
|
||||
{
|
||||
error_printf("Failed to allocate memory : %d", errno);
|
||||
return;
|
||||
}
|
||||
tmp->data = data;
|
||||
|
||||
linked_list_push_back_elem(linked_list, tmp);
|
||||
|
|
@ -86,7 +96,11 @@ void linked_list_push_back(linked_list_t *linked_list, void *data)
|
|||
void linked_list_push_front(linked_list_t *linked_list, void *data)
|
||||
{
|
||||
elem_t *tmp = malloc(sizeof(elem_t));
|
||||
if(!tmp) return;
|
||||
if(!tmp)
|
||||
{
|
||||
error_printf("Failed to allocate memory : %d", errno);
|
||||
return;
|
||||
}
|
||||
tmp->data = data;
|
||||
|
||||
linked_list_push_front_elem(linked_list, tmp);
|
||||
|
|
@ -179,7 +193,11 @@ elem_t *linked_list_get_elem(const linked_list_t *linked_list, size_t index)
|
|||
void *linked_list_get(const linked_list_t *linked_list, size_t index)
|
||||
{
|
||||
elem_t *tmp = linked_list_get_elem(linked_list, index);
|
||||
if(!tmp) return NULL;
|
||||
if(!tmp)
|
||||
{
|
||||
error_printf("Failed to get elem.");
|
||||
return NULL;
|
||||
}
|
||||
return tmp->data;
|
||||
}
|
||||
|
||||
|
|
@ -214,7 +232,11 @@ void linked_list_insert_elem(linked_list_t *linked_list, elem_t *elem, size_t in
|
|||
void linked_list_insert(linked_list_t *linked_list, void *data, size_t index)
|
||||
{
|
||||
elem_t *tmp = malloc(sizeof(elem_t));
|
||||
if(!tmp) return;
|
||||
if(!tmp)
|
||||
{
|
||||
error_printf("Failed to allocate memory : %d", errno);
|
||||
return;
|
||||
}
|
||||
tmp->data = data;
|
||||
|
||||
linked_list_insert_elem(linked_list, tmp, index);
|
||||
|
|
@ -324,7 +346,11 @@ void *linked_list_get_if(const linked_list_t *linked_list, const condition_t con
|
|||
|
||||
void linked_list_remove_if(linked_list_t *linked_list, const condition_t condition, ...)
|
||||
{
|
||||
if(!condition) return;
|
||||
if(!condition)
|
||||
{
|
||||
error_printf("Condition cannot be NULL.");
|
||||
return;
|
||||
}
|
||||
|
||||
va_list args;
|
||||
va_start(args, condition);
|
||||
|
|
@ -352,9 +378,13 @@ void linked_list_remove_if(linked_list_t *linked_list, const condition_t conditi
|
|||
va_end(args);
|
||||
}
|
||||
|
||||
void linked_list_for_each(const linked_list_t *linked_list, const action_t action, ...)
|
||||
int linked_list_for_each(const linked_list_t *linked_list, const action_t action, ...)
|
||||
{
|
||||
if(!action) return;
|
||||
if(!action)
|
||||
{
|
||||
error_printf("Action cannot be NULL.");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
va_list args;
|
||||
va_start(args, action);
|
||||
|
|
@ -366,7 +396,13 @@ void linked_list_for_each(const linked_list_t *linked_list, const action_t actio
|
|||
va_list args_copy;
|
||||
va_copy(args_copy, args);
|
||||
|
||||
action(actual_elem, args_copy);
|
||||
if(action(actual_elem, args_copy))
|
||||
{
|
||||
va_end(args_copy);
|
||||
va_end(args);
|
||||
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
va_end(args_copy);
|
||||
|
||||
|
|
@ -374,4 +410,6 @@ void linked_list_for_each(const linked_list_t *linked_list, const action_t actio
|
|||
}
|
||||
|
||||
va_end(args);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
#include "game.h"
|
||||
|
||||
game_t game;
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int exit_status = EXIT_SUCCESS;
|
||||
|
||||
if(game_init()) exit_status = EXIT_FAILURE;
|
||||
|
||||
while(game.is_running)
|
||||
{
|
||||
game_handle_event();
|
||||
game_update();
|
||||
if(game_render()) exit_status = EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if(game_exit()) exit_status = EXIT_FAILURE;
|
||||
|
||||
return exit_status;
|
||||
}
|
||||
Loading…
Reference in New Issue