diff --git a/CMakeLists.txt b/CMakeLists.txt index 06f4e1b..1855874 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,6 +15,11 @@ set(SOURCES src/vector2d.c src/linked_list.c src/texture_manager.c + src/ecs/ecs.c + src/ecs/transform_component.c + src/ecs/sprite_component.c + src/ecs/animation_system.c + src/ecs/player_system.c ) # fx-CG-50-only assets diff --git a/src/ecs/animation_system.c b/src/ecs/animation_system.c new file mode 100644 index 0000000..9f0aace --- /dev/null +++ b/src/ecs/animation_system.c @@ -0,0 +1,111 @@ +#include +#include "animation_system.h" +#include "../game.h" + +// Args : size_t nb_frames, size_t actual_frame, float frame_delay_ms, bool play, bool loop, bool reverse +void animation_system_init(component_t *component, va_list args) +{ + animation_system_data_t *system_data = component->component_data.animation_system_data; + + system_data->sprite_component_data = get_component(component->entity, SPRITE_COMPONENT)->component_data.sprite_component_data; + + system_data->nb_frames = va_arg(args, size_t); + system_data->actual_frame_nb= va_arg(args, size_t); + system_data->frame_delay_ms = (float)va_arg(args, double); + system_data->play = (bool)va_arg(args, int); + system_data->loop = (bool)va_arg(args, int); + system_data->reverse = (bool)va_arg(args, int); + + system_data->frame_timer_ms = 0; + + linked_list_init(&system_data->frames, sizeof(rect_t), NULL); + + animation_system_create_frames_clips(system_data); +} + +void animation_system_update(component_t *component) +{ + animation_system_data_t *system_data = component->component_data.animation_system_data; + + if(system_data->play) + { + system_data->frame_timer_ms += (float)game.delta_time_ms; + + if(system_data->frame_timer_ms >= system_data->frame_delay_ms) + { + system_data->frame_timer_ms = 0; + + if(system_data->reverse) + { + if(system_data->actual_frame->prev) + { + system_data->actual_frame = system_data->actual_frame->prev; + system_data->actual_frame_nb--; + } + else if(!system_data->loop) + { + system_data->play = false; + } + else + { + system_data->actual_frame = system_data->frames.last; + system_data->actual_frame_nb = system_data->frames.size - 1; + } + } + else + { + if(system_data->actual_frame->next) + { + system_data->actual_frame = system_data->actual_frame->next; + system_data->actual_frame_nb++; + } + else if(!system_data->loop) + { + system_data->play = false; + } + else + { + system_data->actual_frame = system_data->frames.first; + system_data->actual_frame_nb = 0; + } + } + } + + system_data->sprite_component_data->srcR = *(rect_t *)system_data->actual_frame->data; + } +} + +inline void animation_system_destroy(component_t *component) +{ + linked_list_clear(&component->component_data.animation_system_data->frames); + kfree(component->component_data.animation_system_data); +} + +void animation_system_create_frames_clips(animation_system_data_t *system_data) +{ + linked_list_clear(&system_data->frames); + + rect_t *sprite_srcR = &system_data->sprite_component_data->srcR; + + for(size_t actual_frame_nb = 0; actual_frame_nb < system_data->nb_frames; actual_frame_nb++) + { + elem_t *frame = elem_create(&system_data->frames); + + ((rect_t *)frame->data)->x = sprite_srcR->w * (float)actual_frame_nb; + ((rect_t *)frame->data)->y = 0; + ((rect_t *)frame->data)->w = sprite_srcR->w; + ((rect_t *)frame->data)->h = sprite_srcR->h; + + linked_list_push_back_elem(&system_data->frames, frame); + } + + system_data->actual_frame = linked_list_get_elem(&system_data->frames, system_data->actual_frame_nb); +} + +inline void animation_system_change_animation(animation_system_data_t *system_data, const char *name, size_t nb_frames) +{ + system_data->nb_frames = nb_frames; + sprite_component_set_texture(system_data->sprite_component_data, name); + animation_system_create_frames_clips(system_data); + system_data->sprite_component_data->srcR = *(rect_t *)system_data->actual_frame->data; +} diff --git a/src/ecs/animation_system.h b/src/ecs/animation_system.h new file mode 100644 index 0000000..da97b44 --- /dev/null +++ b/src/ecs/animation_system.h @@ -0,0 +1,34 @@ +#ifndef ANIMATION_SYSTEM_H +#define ANIMATION_SYSTEM_H + +#include "ecs.h" +#include "sprite_component.h" + +typedef struct animation_system_data_t { + sprite_component_data_t *sprite_component_data; + + bool play :1; + bool loop :1; + bool reverse :1; + + float frame_delay_ms; + float frame_timer_ms; + + elem_t *actual_frame; + size_t actual_frame_nb; + + size_t nb_frames; + linked_list_t frames; +} animation_system_data_t; + +void animation_system_init(component_t *, va_list); + +void animation_system_update(component_t *); + +void animation_system_destroy(component_t *); + +void animation_system_create_frames_clips(animation_system_data_t *); + +void animation_system_change_animation(animation_system_data_t *, const char *, size_t); + +#endif // SPRITE_COMPONENT_H \ No newline at end of file diff --git a/src/ecs/components.h b/src/ecs/components.h new file mode 100644 index 0000000..e842d7d --- /dev/null +++ b/src/ecs/components.h @@ -0,0 +1,10 @@ +#ifndef COMPONENTS_H +#define COMPONENTS_H + +#include "transform_component.h" +#include "sprite_component.h" +#include "animation_system.h" +#include "player_system.h" +// Add new components header file here + +#endif // COMPONENTS_H \ No newline at end of file diff --git a/src/ecs/ecs.c b/src/ecs/ecs.c new file mode 100644 index 0000000..1f02224 --- /dev/null +++ b/src/ecs/ecs.c @@ -0,0 +1,194 @@ +#include +#include +#include "ecs.h" +#include "components.h" + +component_t *create_component(component_type_t component_type) +{ + component_t *component = kmalloc(sizeof(component_t), NULL); + component->component_type = component_type; + + switch(component_type) + { + case TRANSFORM_COMPONENT: + component->component_init = transform_component_init; + component->component_update = transform_component_update; + component->component_draw = NULL; + + component->component_data.transform_component_data = kmalloc(sizeof(transform_component_data_t), NULL); + if(!component->component_data.transform_component_data) return NULL; + + component->component_deleter = transform_component_destroy; + break; + + case SPRITE_COMPONENT: + component->component_init = sprite_component_init; + component->component_update = sprite_component_update; + component->component_draw = sprite_component_draw; + + component->component_data.sprite_component_data = kmalloc(sizeof(sprite_component_data_t), NULL); + if(!component->component_data.sprite_component_data) return NULL; + + component->component_deleter = sprite_component_destroy; + break; + + case ANIMATION_SYSTEM: + component->component_init = animation_system_init; + component->component_update = animation_system_update; + component->component_draw = NULL; + + component->component_data.animation_system_data = kmalloc(sizeof(animation_system_data_t), NULL); + if(!component->component_data.animation_system_data) return NULL; + + component->component_deleter = animation_system_destroy; + break; + + case PLAYER_SYSTEM: + component->component_init = player_system_init; + component->component_update = player_system_update; + component->component_draw = NULL; + + component->component_data.player_system_data = kmalloc(sizeof(player_system_data_t), NULL); + if(!component->component_data.player_system_data) return NULL; + + component->component_deleter = player_system_destroy; + break; + + // Add new components attributions here + + default: + return NULL; + } + + return component; +} + +inline void destroy_component(component_t *component) +{ + component->component_deleter(component); + kfree(component); +} + +entity_t *create_entity(const char *name) +{ + entity_t *entity = kmalloc(sizeof(entity_t), NULL); + if(!entity) return NULL; + + entity->name = name; + 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, ...) +{ + if(!component) return; + + 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) +{ + return linked_list_get_if(&entity->components, condition_is_component_type, component_type); +} + +// Only for this file +// No args +static inline void action_update_component(elem_t *elem, va_list args __attribute__((unused))) +{ + component_t *component = elem->data; + component->component_update(component); +} + +inline void update_entity(entity_t *entity) +{ + linked_list_for_each(&entity->components, action_update_component); +} + +// Only for this file +// No args +static inline void action_draw_component(elem_t *elem, va_list args __attribute__((unused))) +{ + component_t *component = elem->data; + if(component->component_draw) component->component_draw(component); +} + +inline void draw_entity(entity_t *entity) +{ + linked_list_for_each(&entity->components, action_draw_component); +} + +inline void destroy_entity(entity_t *entity) +{ + linked_list_clear(&entity->components); + kfree(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 entity_t *entity_manager_add_entity(entity_manager_t *entity_manager, const char *name) +{ + entity_t *entity = create_entity(name); + linked_list_push_back(&entity_manager->entities, entity); + return entity; +} + +// Only for this file +static inline void action_update_entity(elem_t *elem, va_list args __attribute__((unused))) +{ + update_entity(elem->data); +} + +inline void entity_manager_update(entity_manager_t *entity_manager) +{ + linked_list_for_each(&entity_manager->entities, action_update_entity); +} + +// Only for this file +static inline void action_draw_entity(elem_t *elem, va_list args __attribute__((unused))) +{ + draw_entity(elem->data); +} + +inline void entity_manager_draw(entity_manager_t *entity_manager) +{ + linked_list_for_each(&entity_manager->entities, action_draw_entity); +} + +// Only for this file +static inline bool condition_is_entity_name(elem_t *elem, va_list args) +{ + return ((entity_t *)elem->data)->name == va_arg(args, const char *); +} + +inline void entity_manager_remove_entity(entity_manager_t *entity_manager, const char *name) +{ + linked_list_remove_if(&entity_manager->entities, condition_is_entity_name, name); +} + +inline void entity_manager_clear(entity_manager_t *entity_manager) +{ + linked_list_clear(&entity_manager->entities); +} diff --git a/src/ecs/ecs.h b/src/ecs/ecs.h new file mode 100644 index 0000000..425b6a6 --- /dev/null +++ b/src/ecs/ecs.h @@ -0,0 +1,84 @@ +#ifndef ECS_H +#define ECS_H + +#include +#include "../linked_list.h" + +typedef enum component_type_t { + TRANSFORM_COMPONENT, + SPRITE_COMPONENT, + ANIMATION_SYSTEM, + PLAYER_SYSTEM +} component_type_t; + +typedef struct transform_component_data_t transform_component_data_t; +typedef struct sprite_component_data_t sprite_component_data_t; +typedef struct animation_system_data_t animation_system_data_t; +typedef struct player_system_data_t player_system_data_t; + +typedef struct component_t component_t; + +typedef void (*component_init_t)(component_t *, va_list); +typedef void (*component_update_t)(component_t *); +typedef void (*component_draw_t)(component_t *); + +typedef void (*component_deleter_t)(component_t *); + +typedef struct component_t { + component_type_t component_type; + + struct entity_t *entity; + + component_init_t component_init; + component_update_t component_update; + component_draw_t component_draw; + + union { + transform_component_data_t *transform_component_data; + sprite_component_data_t *sprite_component_data; + animation_system_data_t *animation_system_data; + player_system_data_t *player_system_data; + } component_data; + + component_deleter_t component_deleter; +} component_t; + +component_t *create_component(component_type_t); + +void destroy_component(component_t *); + +typedef struct entity_t { + const char *name; + size_t draw_priority; + linked_list_t components; +} entity_t; + +entity_t *create_entity(const char *name); + +void add_component(entity_t *, component_t *, ...); + +component_t *get_component(entity_t *, component_type_t); + +void update_entity(entity_t *); + +void draw_entity(entity_t *); + +void destroy_entity(entity_t *); + +typedef struct entity_manager_t { + linked_list_t entities; +} entity_manager_t; + +void entity_manager_init(entity_manager_t *); + +entity_t *entity_manager_add_entity(entity_manager_t *, const char *); + +void entity_manager_update(entity_manager_t *); + +void entity_manager_draw(entity_manager_t *); + +void entity_manager_remove_entity(entity_manager_t *, const char *); + +void entity_manager_clear(entity_manager_t *); + +#endif // ECS_H \ No newline at end of file diff --git a/src/ecs/player_system.c b/src/ecs/player_system.c new file mode 100644 index 0000000..cabd27f --- /dev/null +++ b/src/ecs/player_system.c @@ -0,0 +1,79 @@ +#include +#include "player_system.h" +#include "animation_system.h" +#include "sprite_component.h" +#include "transform_component.h" +#include "../game.h" + +// No args +void player_system_init(component_t *component, va_list args __attribute__((unused))) +{ + player_system_data_t *system_data = component->component_data.player_system_data; + + system_data->animation_system_data = get_component(component->entity, ANIMATION_SYSTEM)->component_data.animation_system_data; + system_data->sprite_component_data = system_data->animation_system_data->sprite_component_data; + system_data->transform_component_data = system_data->sprite_component_data->transform_component_data; + + system_data->state = IDLE; +} + +// Only for this file +static void player_system_get_inputs(component_t *component) +{ + player_system_data_t *system_data = component->component_data.player_system_data; + + system_data->last_state = system_data->state; + + system_data->state &= 0xF0; + + system_data->state |= game.event.keys[KEY_UP] * RUNNING_UP; + system_data->state |= game.event.keys[KEY_DOWN] * RUNNING_DOWN; + system_data->state |= game.event.keys[KEY_LEFT] * RUNNING_LEFT; + system_data->state |= game.event.keys[KEY_RIGHT] * RUNNING_RIGHT; +} + +// Only for this file +static void player_system_set_state_velocity_and_animation(component_t *component) +{ + player_system_data_t *system_data = component->component_data.player_system_data; + transform_component_data_t *transform_component_data = system_data->transform_component_data; + sprite_component_data_t *sprite_component_data = system_data->sprite_component_data; + animation_system_data_t *animation_system_data = system_data->animation_system_data; + + transform_component_data->velocity.x = + (float)((system_data->state & RUNNING_RIGHT) >> 3) - (float)((system_data->state & RUNNING_LEFT) >> 2); + transform_component_data->velocity.y = + (float)((system_data->state & RUNNING_DOWN) >> 1) - (float)(system_data->state & RUNNING_UP); + + if(system_data->state & RUNNING_LEFT) sprite_component_data->flip = true; + if(system_data->state & RUNNING_RIGHT) sprite_component_data->flip = false; + + if(is_not_zero(transform_component_data->velocity.x) && is_not_zero(transform_component_data->velocity.y)) + { + transform_component_data->velocity.x *= 0.707106781186548f; + transform_component_data->velocity.y *= 0.707106781186548f; + } + + if((system_data->state & RUNNING) && !(system_data->last_state & RUNNING)) + { + animation_system_data->frame_delay_ms = 200; + animation_system_change_animation(animation_system_data, "player_run_sheet", 6); + } + else if(!(system_data->state & RUNNING) && (system_data->last_state & RUNNING)) + { + animation_system_data->actual_frame_nb = 0; + animation_system_data->frame_delay_ms = 200; + animation_system_change_animation(animation_system_data, "player_idle_sheet", 4); + } +} + +void player_system_update(component_t *component) +{ + player_system_get_inputs(component); + player_system_set_state_velocity_and_animation(component); +} + +void player_system_destroy(component_t *component) +{ + kfree(component->component_data.player_system_data); +} diff --git a/src/ecs/player_system.h b/src/ecs/player_system.h new file mode 100644 index 0000000..d8d87a2 --- /dev/null +++ b/src/ecs/player_system.h @@ -0,0 +1,32 @@ +#ifndef PLAYER_SYSTEM_H +#define PLAYER_SYSTEM_H + +#include "ecs.h" +#include "transform_component.h" + +typedef enum player_state_t { + IDLE = 0x00, // 00000000 + RUNNING_UP = 0x01, // 00000001 + RUNNING_DOWN = 0x02, // 00000010 + RUNNING_LEFT = 0x04, // 00000100 + RUNNING_RIGHT = 0x08, // 00001000 + RUNNING = 0x0F, // 00001111 + DEATH = 0x80 // 10000000 +} player_state_t; + +typedef struct player_system_data_t { + transform_component_data_t *transform_component_data; + sprite_component_data_t *sprite_component_data; + animation_system_data_t *animation_system_data; + + player_state_t state; + player_state_t last_state; +} player_system_data_t; + +void player_system_init(component_t *, va_list); + +void player_system_update(component_t *); + +void player_system_destroy(component_t *); + +#endif // PLAYER_SYSTEM_H \ No newline at end of file diff --git a/src/ecs/sprite_component.c b/src/ecs/sprite_component.c new file mode 100644 index 0000000..3ae3781 --- /dev/null +++ b/src/ecs/sprite_component.c @@ -0,0 +1,41 @@ +#include +#include "sprite_component.h" +#include "../game.h" + +// Arg : const char *name +void sprite_component_init(component_t *component, va_list args) +{ + sprite_component_data_t *component_data = component->component_data.sprite_component_data; + + component_data->transform_component_data = get_component(component->entity, TRANSFORM_COMPONENT)->component_data.transform_component_data; + + component_data->srcR = component_data->transform_component_data->bounds; + component_data->srcR.x = 0; + component_data->srcR.y = 0; + + component_data->flip = false; + + sprite_component_set_texture(component_data, va_arg(args, const char *)); +} + +inline void sprite_component_update(component_t *component) +{ + sprite_component_data_t *component_data = component->component_data.sprite_component_data; + component_data->dstR = component_data->transform_component_data->bounds; +} + +inline void sprite_component_draw(component_t *component) +{ + sprite_component_data_t *component_data = component->component_data.sprite_component_data; + draw_texture(component_data->texture, &component_data->srcR, &component_data->dstR, component_data->flip); +} + +inline void sprite_component_destroy(component_t *component) +{ + kfree(component->component_data.sprite_component_data); +} + +inline void sprite_component_set_texture(sprite_component_data_t *component_data, const char *name) +{ + component_data->texture = texture_manager_get_texture(&game.texture_manager, name); +} diff --git a/src/ecs/sprite_component.h b/src/ecs/sprite_component.h new file mode 100644 index 0000000..476d9f1 --- /dev/null +++ b/src/ecs/sprite_component.h @@ -0,0 +1,29 @@ +#ifndef SPRITE_COMPONENT_H +#define SPRITE_COMPONENT_H + +#include "ecs.h" +#include "transform_component.h" +#include "../texture_manager.h" + +typedef struct sprite_component_data_t { + transform_component_data_t *transform_component_data; + + texture_t *texture; + + rect_t srcR; + rect_t dstR; + + bool flip; +} sprite_component_data_t; + +void sprite_component_init(component_t *, va_list); + +void sprite_component_update(component_t *); + +void sprite_component_draw(component_t *); + +void sprite_component_destroy(component_t *); + +void sprite_component_set_texture(sprite_component_data_t *, const char *); + +#endif // SPRITE_COMPONENT_H \ No newline at end of file diff --git a/src/ecs/transform_component.c b/src/ecs/transform_component.c new file mode 100644 index 0000000..230b135 --- /dev/null +++ b/src/ecs/transform_component.c @@ -0,0 +1,32 @@ +#include +#include "transform_component.h" +#include "../game.h" + +// Args : rect_t bounds, double speed +void transform_component_init(component_t *component, va_list args) +{ + transform_component_data_t *const component_data = component->component_data.transform_component_data; + + rect_t bounds = va_arg(args, rect_t); + float speed = (float)va_arg(args, double); + + component_data->bounds = bounds; + + component_data->velocity.x = 0; + component_data->velocity.y = 0; + + component_data->speed = speed; +} + +void transform_component_update(component_t *component) +{ + transform_component_data_t *component_data = component->component_data.transform_component_data; + + component_data->bounds.x += component_data->velocity.x * component_data->speed * (float)game.delta_time_ms / 1000.0f; + component_data->bounds.y += component_data->velocity.y * component_data->speed * (float)game.delta_time_ms / 1000.0f; +} + +inline void transform_component_destroy(component_t *component) +{ + kfree(component->component_data.transform_component_data); +} diff --git a/src/ecs/transform_component.h b/src/ecs/transform_component.h new file mode 100644 index 0000000..b18f16f --- /dev/null +++ b/src/ecs/transform_component.h @@ -0,0 +1,19 @@ +#ifndef TRANSFORM_COMPONENT_H +#define TRANSFORM_COMPONENT_H + +#include "ecs.h" +#include "../vector2d.h" + +typedef struct transform_component_data_t { + rect_t bounds; + vector2d_t velocity; + float speed; +} transform_component_data_t; + +void transform_component_init(component_t *, va_list); + +void transform_component_update(component_t *); + +void transform_component_destroy(component_t *); + +#endif // TRANSFORM_COMPONENT_H \ No newline at end of file diff --git a/src/event.h b/src/event.h index 7000bc8..63d039b 100644 --- a/src/event.h +++ b/src/event.h @@ -3,7 +3,8 @@ #include -typedef struct { +// Base struct +typedef struct event_t { bool keys[0xa6]; } event_t; diff --git a/src/game.c b/src/game.c index 2b6d5bc..fb83537 100644 --- a/src/game.c +++ b/src/game.c @@ -1,11 +1,69 @@ -#include +#include +#include #include "game.h" +#include "ecs/components.h" -int game_init(game_t *game) +void game_init(void) { - game = kmalloc(sizeof(game_t), NULL); + texture_manager_init(&game.texture_manager); + texture_manager_load_builtin_textures(&game.texture_manager); - if(game == NULL) return 1; + entity_manager_init(&game.entity_manager); - return 0; -} \ No newline at end of file + entity_t *player = entity_manager_add_entity(&game.entity_manager, "player"); + + rect_t player_bounds = {10.0f, 10.0f, 32.0f, 32.0f}; + float player_speed = 50.0f; + + add_component(player, create_component(TRANSFORM_COMPONENT), player_bounds, player_speed); + add_component(player, create_component(SPRITE_COMPONENT), "player_idle_sheet"); + add_component(player, create_component(ANIMATION_SYSTEM), 4, 0, 200.0f, true, true, false); + add_component(player, create_component(PLAYER_SYSTEM)); + + game.last_clock_state = clock(); + + game.is_running = true; +} + +void game_handle_event(void) +{ + key_event_t key_event; + + do + { + key_event = pollevent(); + + if (key_event.type == KEYEV_DOWN) + game.event.keys[key_event.key] = true; + else if (key_event.type == KEYEV_UP) + game.event.keys[key_event.key] = false; + + if (key_event.type == KEYEV_DOWN && key_event.key == KEY_EXIT) + game.is_running = false; + } + while (key_event.type != KEYEV_NONE); +} + +void game_update(void) +{ + clock_t start_clock = clock(); + game.delta_time_ms = (double)(start_clock - game.last_clock_state) * 1000.0f / CLOCKS_PER_SEC; + game.last_clock_state = start_clock; + + entity_manager_update(&game.entity_manager); +} + +void game_render(void) +{ + dclear(C_WHITE); + + entity_manager_draw(&game.entity_manager); + + dupdate(); +} + +void game_exit(void) +{ + entity_manager_clear(&game.entity_manager); + texture_manager_clear(&game.texture_manager); +} diff --git a/src/game.h b/src/game.h index 141779c..214f7b4 100644 --- a/src/game.h +++ b/src/game.h @@ -1,25 +1,31 @@ #ifndef GAME_H #define GAME_H -#include +#include #include "event.h" #include "texture_manager.h" +#include "ecs/ecs.h" -#define WINDOW_WIDTH 396 -#define WINDOW_HEIGHT 224 - -typedef struct { +typedef struct game_t { event_t event; - texture_manager_t *texture_manager; + texture_manager_t texture_manager; + entity_manager_t entity_manager; + bool is_running; + clock_t last_clock_state; + double delta_time_ms; } game_t; -int game_init(game_t*); +extern game_t game; -int game_handle_event(game_t*); -int game_update(game_t*); -int game_render(game_t*); +void game_init(void); -int game_exit(game_t*); +void game_handle_event(void); + +void game_update(void); + +void game_render(void); + +void game_exit(void); #endif // GAME_H \ No newline at end of file diff --git a/src/main.c b/src/main.c index 7623fc8..e86a579 100644 --- a/src/main.c +++ b/src/main.c @@ -1,19 +1,32 @@ -//#include "game.h" -/* +#include + +//#include + +#include "game.h" + +//#define TEXTURE_TEST +//#define LINKED_LIST_TEST + +game_t game; + int main(void) { - game_t *game; + //gdb_start(); - game_init(game); + //__asm__("trapa #42"); - while(game->is_running) + game_init(); + + while(game.is_running) { - game_handle_event(game); - game_update(game); - game_render(game); + game_handle_event(); + game_update(); + game_render(); } - return game_exit(game); + game_exit(); + + return 0; } diff --git a/src/vector2d.c b/src/vector2d.c index dcffcf2..a1ed109 100644 --- a/src/vector2d.c +++ b/src/vector2d.c @@ -1,15 +1,28 @@ #include "vector2d.h" +__attribute__((const)) float fabsf(float x) +{ + union { + float f; + uint32_t i; + } u = { x }; + + u.i &= 0x7FFFFFFF; + return u.f; +} + bool has_intersection(const rect_t * A, const rect_t * B) { - int Amin, Amax, Bmin, Bmax; + float Amin, Amax, Bmin, Bmax; - if (!A || !B) { + if (!A || !B) + { return false; } /* Special cases for empty rects */ - if (rect_empty(A) || rect_empty(B)) { + if (rect_empty(A) || rect_empty(B)) + { return false; } @@ -42,18 +55,20 @@ bool has_intersection(const rect_t * A, const rect_t * B) bool intersect_rect(const rect_t * A, const rect_t * B, rect_t * result) { - int Amin, Amax, Bmin, Bmax; - - if (!A || !B || !result) { + if (!A || !B || !result) + { // TODO error message return false; } /* Special cases for empty rects */ - if (rect_empty(A) || rect_empty(B)) { + if (rect_empty(A) || rect_empty(B)) + { return false; } - + + float Amin, Amax, Bmin, Bmax; + /* Horizontal intersection */ Amin = A->x; Amax = Amin + A->w; diff --git a/src/vector2d.h b/src/vector2d.h index dc9badb..67ea999 100644 --- a/src/vector2d.h +++ b/src/vector2d.h @@ -10,22 +10,67 @@ #include -typedef struct { - int x, y; +/* vector2d_t: A point in space + This struct is the base for storing 2D positions. + + @x X pos of the vector + @y Y pos of the vector */ +typedef struct vector2d_t { + float x, y; } vector2d_t; -typedef struct { - int x, y; - int w, h; +/* vector2d_t: A point in space + This struct is the base for storing 2D positions. + + @x X pos of the rectangle + @y Y pos of the rectangle + @w Width of the rectangle + @h Height of the rectangle */ +typedef struct rect_t { + float x, y; + float w, h; } rect_t; +#define EPSILON 0.000001f + +__attribute__((const)) float fabsf(float x); + +#define is_equal_to_zero(X) (fabsf(X) <= EPSILON) + +#define is_not_zero(X) (fabsf(X) > EPSILON) + +/* point_in_rect(): Verify if a point is in a rectangle + This function is useful for verify if a point is in a rectangle. + + @P A Vector2d + @R A rectangle + Return true if the condition is validated else false. */ #define point_in_rect(P, R) (((P)->x >= (R)->x) && ((P)->x < ((R)->x + (R)->w)) && \ ((P)->y >= (R)->y) && ((P)->y < ((R)->y + (R)->h))) -#define rect_empty(X) ((!(X)) || ((X)->w <= 0) || ((X)->h <= 0)) +/* rect_empty(): Verify if a rectangle is empty + This function is useful for verify if a rectangle exists. -bool has_intersection(const rect_t * A, const rect_t * B); + @R A rectangle + Return true if the condition is validated else false. */ +#define rect_empty(R) ((!(R)) || (is_equal_to_zero((R)->w)) || (is_equal_to_zero((R)->h))) -bool intersect_rect(const rect_t * A, const rect_t * B, rect_t * result); +/* has_intersection(): Verify if there is a intersction between two rectangles + This function is useful for verify intersection between two rectangles. + + @A A rectangle + @B Another rectangle + Return true if the condition is validated else false. */ +bool has_intersection(const rect_t *, const rect_t *); + +/* intersect_rect(): Like has_intersection but has a result rectangle + This function is useful for verify intersection between two rectangles + and get the intersection rectangle. + + @A A rectangle + @B Another rectangle + @result The intersection rectangle + Return true if the condition is validated else false. */ +bool intersect_rect(const rect_t *, const rect_t *, rect_t *); #endif // VECTOR2D_H \ No newline at end of file