Moved ecs.c into core and added much better error and debug handling.

This commit is contained in:
Ulysse Cura 2026-07-24 03:23:03 +02:00
parent d193aa5fd4
commit 2e1eaf4c1c
14 changed files with 612 additions and 116 deletions

View File

@ -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

View File

@ -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;
}

View File

@ -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();
}

189
src/ecs.c Normal file
View File

@ -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);
}

View File

@ -1,4 +1,4 @@
#include "event.h"
#include "events.h"
#include <SDL2/SDL_events.h>

View File

@ -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

View File

@ -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

78
src/headers/ecs.h Normal file
View File

@ -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

25
src/headers/errors.h Normal file
View File

@ -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

View File

@ -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

46
src/headers/game.h Normal file
View File

@ -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

View File

@ -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

View File

@ -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;
}

21
src/main.c Normal file
View File

@ -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;
}