Adding ECS

This commit is contained in:
Ulysse Cura 2025-02-28 17:08:30 +01:00
parent 57192d8b0e
commit 6d5379d2c3
18 changed files with 851 additions and 43 deletions

View File

@ -15,6 +15,11 @@ set(SOURCES
src/vector2d.c src/vector2d.c
src/linked_list.c src/linked_list.c
src/texture_manager.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 # fx-CG-50-only assets

111
src/ecs/animation_system.c Normal file
View File

@ -0,0 +1,111 @@
#include <gint/kmalloc.h>
#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;
}

View File

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

10
src/ecs/components.h Normal file
View File

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

194
src/ecs/ecs.c Normal file
View File

@ -0,0 +1,194 @@
#include <gint/kmalloc.h>
#include <stdarg.h>
#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);
}

84
src/ecs/ecs.h Normal file
View File

@ -0,0 +1,84 @@
#ifndef ECS_H
#define ECS_H
#include <stdarg.h>
#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

79
src/ecs/player_system.c Normal file
View File

@ -0,0 +1,79 @@
#include <gint/kmalloc.h>
#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);
}

32
src/ecs/player_system.h Normal file
View File

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

View File

@ -0,0 +1,41 @@
#include <gint/kmalloc.h>
#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);
}

View File

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

View File

@ -0,0 +1,32 @@
#include <gint/kmalloc.h>
#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);
}

View File

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

View File

@ -3,7 +3,8 @@
#include <gint/keycodes.h> #include <gint/keycodes.h>
typedef struct { // Base struct
typedef struct event_t {
bool keys[0xa6]; bool keys[0xa6];
} event_t; } event_t;

View File

@ -1,11 +1,69 @@
#include <gint/kmalloc.h> #include <gint/keyboard.h>
#include <gint/display.h>
#include "game.h" #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; 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);
}

View File

@ -1,25 +1,31 @@
#ifndef GAME_H #ifndef GAME_H
#define GAME_H #define GAME_H
#include <gint/defs/types.h> #include <time.h>
#include "event.h" #include "event.h"
#include "texture_manager.h" #include "texture_manager.h"
#include "ecs/ecs.h"
#define WINDOW_WIDTH 396 typedef struct game_t {
#define WINDOW_HEIGHT 224
typedef struct {
event_t event; event_t event;
texture_manager_t *texture_manager; texture_manager_t texture_manager;
entity_manager_t entity_manager;
bool is_running; bool is_running;
clock_t last_clock_state;
double delta_time_ms;
} game_t; } game_t;
int game_init(game_t*); extern game_t game;
int game_handle_event(game_t*); void game_init(void);
int game_update(game_t*);
int game_render(game_t*);
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 #endif // GAME_H

View File

@ -1,19 +1,32 @@
//#include "game.h" #include <gint/defs/types.h>
/*
//#include <gint/gdb.h>
#include "game.h"
//#define TEXTURE_TEST
//#define LINKED_LIST_TEST
game_t game;
int main(void) 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_handle_event();
game_update(game); game_update();
game_render(game); game_render();
} }
return game_exit(game); game_exit();
return 0;
} }

View File

@ -1,15 +1,28 @@
#include "vector2d.h" #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) 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; return false;
} }
/* Special cases for empty rects */ /* Special cases for empty rects */
if (rect_empty(A) || rect_empty(B)) { if (rect_empty(A) || rect_empty(B))
{
return false; 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) 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 // TODO error message
return false; return false;
} }
/* Special cases for empty rects */ /* Special cases for empty rects */
if (rect_empty(A) || rect_empty(B)) { if (rect_empty(A) || rect_empty(B))
{
return false; return false;
} }
float Amin, Amax, Bmin, Bmax;
/* Horizontal intersection */ /* Horizontal intersection */
Amin = A->x; Amin = A->x;
Amax = Amin + A->w; Amax = Amin + A->w;

View File

@ -10,22 +10,67 @@
#include <gint/defs/types.h> #include <gint/defs/types.h>
typedef struct { /* vector2d_t: A point in space
int x, y; 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; } vector2d_t;
typedef struct { /* vector2d_t: A point in space
int x, y; This struct is the base for storing 2D positions.
int w, h;
@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; } 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)) && \ #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))) ((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 #endif // VECTOR2D_H