Compiling with ncurses.

This commit is contained in:
Ulysse Cura 2026-07-22 15:37:29 +02:00
parent 0ef33e0b09
commit 1821d20923
13 changed files with 1172 additions and 3 deletions

View File

@ -8,8 +8,8 @@ CORE_SOURCES := \
# Compiler and flags
CORE_CC = gcc
#CORE_CFLAGS = --std=c17 --pedantic -O3 -DASSET_FILE_NAME=\"$(ASSET_OUTPUT)\" $(shell pkg-config --cflags sdl2) # RELEASE
CORE_CFLAGS = --std=c17 --pedantic -O1 -g -DASSET_FILE_NAME=\"$(ASSET_OUTPUT)\" $(shell pkg-config --cflags sdl2) \
#CORE_CFLAGS = --std=c17 --pedantic -O3 -DASSET_FILE_NAME=\"$(ASSET_OUTPUT)\" $(shell pkg-config --cflags ncurses) # RELEASE
CORE_CFLAGS = --std=c17 --pedantic -O1 -g -DASSET_FILE_NAME=\"$(ASSET_OUTPUT)\" $(shell pkg-config --cflags ncurses) \
-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 \
@ -25,7 +25,7 @@ CORE_AR = ar
CORE_ARFLAGS =
# Used in final linking.
CORE_DEPS_FLAGS = $(shell pkg-config --libs sdl2)
CORE_DEPS_FLAGS = $(shell pkg-config --libs ncurses)
# Deduce objects
CORE_OBJECTS = $(CORE_SOURCES:%.c=$(BUILD_DIR)/$(CORE_DIR)/%.o)

213
src/asset_manager.c Normal file
View File

@ -0,0 +1,213 @@
#include "asset_manager.h"
#include <ncurses.h>
#include <stdarg.h>
#include <string.h>
#include <stdio.h>
#include "linked_list.h"
#include "memory_alloc.h"
#include "display.h"
asset_t *create_asset(asset_type_t asset_type)
{
asset_t *asset = malloc(sizeof(asset_t));
asset->type = asset_type;
asset->nb_refs = 1;
return asset;
}
void destroy_asset(asset_t *asset)
{
free(asset->name);
switch(asset->type)
{
case ASSET_TEXTURE:
free(asset->data.texture->pixels);
free(asset->data.texture);
default:
break;
}
free(asset);
}
void destroy_asset_header_def(asset_header_def_t *asset_header_def)
{
free(asset_header_def->name);
free(asset_header_def);
}
void 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);
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;
}
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;
}
for(size_t i = 0; i < nb_assets; i++)
{
elem_t *elem = elem_create(&asset_manager->assets_header_defs);
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;
}
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;
}
linked_list_push_back_elem(&asset_manager->assets_header_defs, elem);
}
}
void 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);
}
// Only for this file
// No args
static inline bool condition_is_asset_unused(elem_t *elem, va_list args __attribute__((unused)))
{
return !((asset_t *)elem->data)->nb_refs;
}
inline void asset_manager_collect_garbage(asset_manager_t *asset_manager)
{
linked_list_remove_if(&asset_manager->assets, condition_is_asset_unused);
}
// Only for this file
// Arg : const char *asset_name
static inline bool condition_is_asset_name(elem_t *elem, va_list args)
{
return !strcmp(((asset_t *)elem->data)->name, va_arg(args, const char *));
}
//Only for this file
// Arg : const char *asset_name
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)
{
if(fseek(asset_manager->asset_file, asset_header_def->start, SEEK_SET))
{
printf("Couldn't seek in asset file.");
return;
}
size_t width, height;
if(fread(&width, sizeof(width), 1, asset_manager->asset_file) != 1)
{
printf("Failed to read in asset file.");
return;
}
if(fread(&height, sizeof(height), 1, asset_manager->asset_file) != 1)
{
printf("Failed to read in asset file.");
return;
}
asset->data.texture = malloc(sizeof(texture_t));
asset->data.texture->width = width;
asset->data.texture->height = height;
asset->data.texture->pixels = malloc(width * height * sizeof(uint16_t));
if(fread(asset->data.texture->pixels, sizeof(uint16_t), width * height, asset_manager->asset_file) != width * height)
{
printf("Failed to read asset file.");
return;
}
}
void asset_manager_load_asset(asset_manager_t *asset_manager, const char *asset_name, asset_type_t asset_type)
{
asset_t *asset = linked_list_get_if(&asset_manager->assets, condition_is_asset_name, asset_name);
if(asset)
{
asset->nb_refs++;
return;
}
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);
}
void 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)
{
asset->nb_refs--;
}
}
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)
return NULL;
if(asset->type != ASSET_TEXTURE)
return NULL;
return asset->data.texture;
}
void asset_manager_draw_texture(texture_t *texture, rect_t *src_rect, rect_t *dst_rect, bool flip)
{
}

27
src/display.c Normal file
View File

@ -0,0 +1,27 @@
#include "display.h"
#include <ncurses.h>
#include <stdio.h>
inline void display_init(void)
{
initscr();
raw();
noecho();
keypad(stdscr, TRUE);
}
inline void display_update(void)
{
refresh();
}
inline void display_clear(void)
{
clear();
}
inline void display_exit(void)
{
endwin();
}

6
src/event.c Normal file
View File

@ -0,0 +1,6 @@
#include "event.h"
inline int pollevent(event_t *event)
{
return 0;
}

View File

@ -0,0 +1,57 @@
#ifndef ASSET_MANAGER_H
#define ASSET_MANAGER_H
#include <stdbool.h>
#include <stdio.h>
#include "linked_list.h"
#include "vector2d.h"
typedef struct texture_t {
size_t width, height;
uint16_t *pixels;
} texture_t;
typedef enum asset_type_t {
ASSET_TEXTURE
} asset_type_t;
typedef struct asset_t {
char *name;
union {
texture_t *texture;
} data;
size_t nb_refs;
asset_type_t type;
} asset_t;
asset_t *create_asset(asset_type_t asset_type);
void destroy_asset(asset_t *asset);
typedef struct asset_header_def_t {
char *name;
size_t start;
} asset_header_def_t;
void destroy_asset_header_def(asset_header_def_t *asset_header_def);
typedef struct asset_manager_t {
linked_list_t assets_header_defs;
linked_list_t assets;
FILE *asset_file;
} asset_manager_t;
void asset_manager_init(asset_manager_t *asset_manager);
void 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);
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);
#endif // ASSET_MANAGER_H

20
src/headers/display.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef DISPLAY_H
#define DISPLAY_H
#include "vector2d.h"
#define C_BLACK 0, 0, 0, 255
#define DISPLAY_WIDTH 396
#define DISPLAY_HEIGHT 224
#define RENDER_SCALE 2
void display_init(void);
void display_update(void);
void display_clear(void);
void display_exit(void);
#endif // DISPLAY_H

17
src/headers/event.h Normal file
View File

@ -0,0 +1,17 @@
#ifndef KEYBOARD_H
#define KEYBOARD_H
#include <ncurses.h>
#define EVENT_KEY_UP 1
#define EVENT_KEY_DOWN 2
#define EVENT_QUIT 3
typedef struct event_t {
uint32_t type;
int key;
} event_t;
int pollevent(event_t *event);
#endif // KEYBOARD_H

8
src/headers/keycodes.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef KEYCODES_H
#define KEYCODES_H
#include <ncurses.h>
#define MAX_KEYCODES KEY_MAX - KEY_MIN
#endif // KEYCODES_H

288
src/headers/linked_list.h Normal file
View File

@ -0,0 +1,288 @@
#ifndef LINKED_LIST_H
#define LINKED_LIST_H
#include <stdbool.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
/**
* @brief Element struct for linked lists.
* This struct is the base for storing data in a linked list.
*
* @param data Raw pointer to any type of data
* @param prev Pointer to the prev element in the linked list
* @param next Pointer to the next element in the linked list
*/
typedef struct elem_t {
void *data;
struct elem_t *prev;
struct elem_t *next;
} elem_t;
/**
* @brief A type for deleters used during the destruction of data stored in elements.
*
* During the initialisation of linked lists you can pass in argument a deleter.
* It is used during the destruction of an element.
* You can pass NULL to the initialisation to use the default deleter (free(elem->data)).
* Your deleter_t function declaration must look like this :
*
* void name_of_your_deleter(void *data);
*
* Then do what you need to destroy your data (don't forget to free the data itself...) but not the elements.
* You should always define your function with "inline" if it's no too long.
*/
typedef void (*deleter_t)(void *data);
/**
* @brief A type for condition used for function like linked_list_remove_if
*
* For function like linked_list_remove_if you need a condition.
* 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.
* Your condition_t function declaration must look like this :
*
* bool name_of_your_condition(elem_t *elem, va_list);
*
* Then return true if you want the element to be removed from the list or false if not.
* You should always define your function with "static", and "inline".
*/
typedef bool (*condition_t)(elem_t *elem, va_list args);
/**
* @brief A type for action used for function like linked_list_for_each
*
* 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.
* Your condition_t function declaration must look like this :
*
* void name_of_your_condition(elem_t *elem, va_list);
*
* Then do whatever you want with the element data, just don't remove it.
* You should always define your function with "static", and "inline".
*/
typedef void (*action_t)(elem_t *elem, va_list args);
/**
* @brief Base of linked lists.
* This struct is the base for creating linked lists.
*
* @param data_size Size of the data stored in elements of the linked list (used while creating new elements)
* @param first Pointer to the first element in the linked list
* @param last Pointer to the last element in the linked list
* @param size Size of the linked list
* @param deleter Deleter of the data when removing an element
*/
typedef struct linked_list_t {
size_t data_size;
elem_t *first;
elem_t *last;
size_t size;
deleter_t elem_deleter;
} linked_list_t;
/**
* @brief Init a linked list
* This function is necessary if you create a linked list.
*
* WARNING : It doesn't allocate the memory for you !
*
* @param linked_list Pointer to an linked list
* @param data_size Data size for elements in the linked list
* @param deleter The deleter used during destroyement of an elem
*/
void linked_list_init(linked_list_t *linked_list, const size_t data_size, deleter_t deleter);
/**
* @brief Create an elem to fill with data to insert in a linked list.
* This function is usefull when you want to initialise an elem with the proper data_size strored in the linked list.
*
* WARNING : Don't change the "data" ptr after calling this function or it will lead to memory leaks !
* Instead do something like this : *(int *)elem->data = 42;
*
* @param linked_list Pointer to an linked list
*
* @return Address of initialised elem, NULL on error.
*/
elem_t *elem_create(const linked_list_t *linked_list);
/**
* @brief Destroy the given element and its data.
* This function is usefull when you want to free an element.
* The deleter is used for the data only and you can pass NULL to use the default deleter.
*
* @param elem Pointer to an element
* @param elem_deleter Function to use to free the data
*/
void destroy_elem(elem_t *elem, const deleter_t elem_deleter);
/**
* @brief Insert an element from the back in a linked list, do nothing on error.
*
* @param linked_list Pointer to a linked list
* @param elem Pointer to an element
*/
void linked_list_push_back_elem(linked_list_t *linked_list, elem_t *elem);
/**
* @brief Insert an element from the front in a linked list, do nothing on error.
*
* @param linked_list Pointer to a linked list
* @param elem Pointer to an element
*/
void linked_list_push_front_elem(linked_list_t *linked_list, elem_t *elem);
/**
* @brief Insert an element initialised and filled with data from the back in a linked list, do nothing on error.
*
* @param linked_list Pointer to a linked list
* @param data Pointer to any data
*/
void linked_list_push_back(linked_list_t *linked_list, void *data);
/**
* @brief Insert an element filled with data from the front in a linked list.
*
* @param linked_list Pointer to a linked list
* @param data Pointer to any data
*/
void linked_list_push_front(linked_list_t *linked_list, void *data);
/**
* @brief Delete the last element in the given linked list, do nothing on error.
*
* @param linked_list Pointer to a linked list
*/
void linked_list_pop_back(linked_list_t *linked_list);
/**
* @brief Delete the first element in the given linked list, do nothing on error.
*
* @param linked_list Pointer to a linked list
*/
void linked_list_pop_front(linked_list_t *linked_list);
/**
* @brief Clear the given linked list, do nothing on error.
*
* @brief linked_list Pointer to a linked list
*/
void linked_list_clear(linked_list_t *linked_list);
/**
* @brief Check if the given linked list is empty.
*
* @param linked_list Pointer to a linked list
*
* @return True if the given linked list is empty else false.
*/
bool linked_list_is_empty(const linked_list_t *linked_list);
/**
* @brief Check if the given index is whithin the range of the linked list.
*
* @param linked_list Pointer to an linked_list_t
*
* @return True if index in within the range of the linked list else false.
*/
bool linked_list_is_in_bound(const linked_list_t *linked_list, const size_t index);
/**
* @brief Get element at the given index in the linked list.
*
* @param linked_list Pointer to a linked list
* @param index Index of the element
*
* @return Element, NULL on error.
*/
elem_t *linked_list_get_elem(const linked_list_t *linked_list, const size_t index);
/**
* @brief Get data in the element at the given index in the linked list.
*
* @param linked_list Pointer to an linked list
* @param index Index of the wanted element
*
* @return Data, NULL on error.
*/
void *linked_list_get(const linked_list_t *linked_list, const size_t index);
/**
* @brief Insert element at the given index in the linked list, do nothing on error.
*
* @param linked_list Pointer to a linked list
* @param elem Pointer to an element
* @param index Index to insert element
*/
void linked_list_insert_elem(linked_list_t *linked_list, elem_t *elem, const size_t index);
/**
* @brief Insert element with data at the given index in the linked list, do nothing on error.
*
* @param linked_list Pointer to a linked list
* @param data Data to put in the new element
* @param index Index to insert the element
*/
void linked_list_insert(linked_list_t *linked_list, void *data, const size_t index);
/**
* @brief Remove the given elem in the linked list, do nothing on error.
*
* @param linked_list Pointer to a linked list
* @param elem Element to remove
*/
void linked_list_remove_elem(linked_list_t *linked_list, elem_t *elem);
/**
* @brief Remove element at the given index in the linked list, do nothing on error.
*
* @param linked_list Pointer to a linked list
* @param index Index of the element
*/
void linked_list_remove(linked_list_t *linked_list, const size_t index);
/**
* @brief Return first element that the condition verify
*
* @param linked_list Pointer to a linked list
* @param condition Condition to verify
* @param ... Argument to pass to the condition
*
* @return Element, NULL if no element verify the condition or if an error ocurred.
*/
elem_t *linked_list_get_elem_if(const linked_list_t *linked_list, const condition_t condition, ...);
/**
* @brief Return data in the first element that the condition verify
*
* @param linked_list Pointer to a linked list
* @param condition Condition to verify
* @param ... Argument to pass to the condition
*
* @return Element data, NULL if no element verify the condition or if an error ocurred.
*/
void *linked_list_get_if(const linked_list_t *linked_list, const condition_t condition, ...);
/**
* @brief Remove every elements that the condition verify, do nothing on error.
*
* @param linked_list Pointer to an linked list
* @param condition Condition to verify
* @param ... Argument to pass to the condition
*/
void linked_list_remove_if(linked_list_t *linked_list, const condition_t condition, ...);
/**
* @brief Apply an action to every elements in the list.
* Useful for changing a value in every single element data.
* The action can be anything that doesn't destroy the element.
*
* @param linked_list Pointer to an linked list
* @param action Action to apply
* @param ... Argument to pass to the action
*/
void linked_list_for_each(const linked_list_t *linked_list, const action_t action, ...);
#endif // LINKED_LIST_H

View File

@ -0,0 +1,6 @@
#ifndef MEMORY_ALLOC_H
#define MEMORY_ALLOC_H
#include <stdlib.h>
#endif // MEMORY_ALLOC_H

133
src/headers/vector2d.h Normal file
View File

@ -0,0 +1,133 @@
#ifndef VECTOR2D_H
#define VECTOR2D_H
#include <stdbool.h>
#include <SDL2/SDL_rect.h>
/**
* @brief Point struct. (int)
*
* @param x X pos
* @param y Y pos
*/
typedef SDL_Point vector2d_t;
/**
* @brief Point struct. (float)
*
* @param x X pos
* @param y Y pos
*/
typedef SDL_FPoint fvector2d_t;
/**
* @brief Rectangle struct. (int)
*
* @param x X pos
* @param y Y pos
* @param w Width
* @param h Height
*/
typedef SDL_Rect rect_t;
/**
* @brief Rectangle struct. (float)
*
* @param x X pos
* @param y Y pos
* @param w Width
* @param h Height
*/
typedef SDL_FRect frect_t;
#define EPSILON 0.000001f
#define f_is_zero(X) (fabsf(X) <= EPSILON)
#define f_is_not_zero(X) (fabsf(X) > EPSILON)
void rect_to_frect(const rect_t *rect, frect_t *frect);
void frect_to_rect(const frect_t *frect, rect_t *rect);
/**
* @brief Verify if a point is in a rectangle. (int)
*
* @param P Vector2d
* @param R Rectangle
*
* @return True if the point is in the rectangle, else false.
*/
#define point_in_rect(P, R) SDL_PointInRect(P, R)
/**
* @brief Verify if a point is in a rectangle. (float)
*
* @param P Vector2d
* @param R Rectangle
*
* @return True if the point is in the rectangle, else false.
*/
#define fpoint_in_frect(P, R) SDL_PointInRectF(P, R)
/**
* @brief Verify if a rectangle is empty
*
* @param R Rectangle
*
* @return True if the rectangle is empty, else false.
*/
#define rect_empty(R) SDL_RectEmpty(R)
/**
* @brief Verify if a rectangle is empty
*
* @param R Rectangle
*
* @return True if the rectangle is empty, else false.
*/
#define frect_empty(R) SDL_FRectEmpty(R)
/**
* @brief Verify if there is a intersction between two rectangles. (int)
*
* @param A Rectangle A
* @param B Rectangle B
*
* @return True if there is an intersection, else false.
*/
#define has_intersection(A, B) SDL_HasIntersection(A, B)
/**
* @brief Verify if there is a intersction between two rectangles. (float)
*
* @param A Rectangle A
* @param B Rectangle B
*
* @return True if there is an intersection, else false.
*/
#define fhas_intersection(A, B) SDL_HasIntersectionF(A, B)
/**
* @brief Verify if there is an intersection between two rectangles and get the intersection rectangle. (int)
*
* @param A Rectangle A
* @param B Rectangle B
* @param result The intersection rectangle
*
* @return True if there is an intersection, else false.
*/
#define intersect_rect(A, B, result) SDL_IntersectRect(A, B, result)
/**
* @brief Verify if there is an intersection between two rectangles and get the intersection rectangle. (float)
*
* @param A Rectangle A
* @param B Rectangle B
* @param result The intersection rectangle
*
* @return True if there is an intersection, else false.
*/
#define intersect_frect(A, B, result) SDL_IntersectFRect(A, B, result)
#endif // VECTOR2D_H

377
src/linked_list.c Normal file
View File

@ -0,0 +1,377 @@
#include <stdarg.h>
#include "memory_alloc.h"
#include "linked_list.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)
{
free(tmp);
return NULL;
}
return tmp;
}
inline void destroy_elem(elem_t *elem, const deleter_t elem_deleter)
{
if(!elem) return;
if(elem_deleter)
elem_deleter(elem->data);
else
free(elem->data);
free(elem);
}
void linked_list_init(linked_list_t *linked_list, const size_t data_size, const deleter_t elem_deleter)
{
linked_list->first = NULL;
linked_list->last = NULL;
linked_list->size = 0;
linked_list->data_size = data_size;
linked_list->elem_deleter = elem_deleter;
}
void linked_list_push_back_elem(linked_list_t *linked_list, elem_t *elem)
{
if(!elem) return;
elem->prev = linked_list->last;
elem->next = NULL;
if(linked_list->last)
linked_list->last->next = elem;
else
linked_list->first = elem;
linked_list->last = elem;
linked_list->size++;
}
void linked_list_push_front_elem(linked_list_t *linked_list, elem_t *elem)
{
if(!elem) return;
elem->next = linked_list->first;
elem->prev = NULL;
if(linked_list->first)
linked_list->first->prev = elem;
else
linked_list->last = elem;
linked_list->first = elem;
linked_list->size++;
}
void linked_list_push_back(linked_list_t *linked_list, void *data)
{
elem_t *tmp = malloc(sizeof(elem_t));
if(!tmp) return;
tmp->data = data;
linked_list_push_back_elem(linked_list, tmp);
}
void linked_list_push_front(linked_list_t *linked_list, void *data)
{
elem_t *tmp = malloc(sizeof(elem_t));
if(!tmp) return;
tmp->data = data;
linked_list_push_front_elem(linked_list, tmp);
}
void linked_list_pop_back(linked_list_t *linked_list)
{
elem_t *tmp = linked_list->last;
if(!tmp) return;
linked_list->last = tmp->prev;
if(linked_list->last)
linked_list->last->next = NULL;
else
linked_list->first = NULL;
destroy_elem(tmp, linked_list->elem_deleter);
linked_list->size--;
}
void linked_list_pop_front(linked_list_t *linked_list)
{
elem_t *tmp = linked_list->first;
if(!tmp) return;
linked_list->first = tmp->next;
if(linked_list->first)
linked_list->first->prev = NULL;
else
linked_list->last = NULL;
destroy_elem(tmp, linked_list->elem_deleter);
linked_list->size--;
}
void linked_list_clear(linked_list_t *linked_list)
{
elem_t *actual_elem = linked_list->first;
elem_t *tmp;
while(actual_elem)
{
tmp = actual_elem;
actual_elem = actual_elem->next;
destroy_elem(tmp, linked_list->elem_deleter);
}
linked_list->first = NULL;
linked_list->last = NULL;
linked_list->size = 0;
}
inline bool linked_list_is_empty(const linked_list_t *linked_list)
{
return !linked_list->first;
}
inline bool linked_list_is_in_bound(const linked_list_t *linked_list, size_t index)
{
return index < linked_list->size;
}
elem_t *linked_list_get_elem(const linked_list_t *linked_list, size_t index)
{
if(!linked_list_is_in_bound(linked_list, index)) return NULL;
if(index == 0)
return linked_list->first;
if(index == linked_list->size - 1)
return linked_list->last;
elem_t *actual_elem = linked_list->first;
if(!actual_elem) return NULL;
for (size_t i = 0; i < index; i++)
{
actual_elem = actual_elem->next;
}
return actual_elem;
}
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;
return tmp->data;
}
void linked_list_insert_elem(linked_list_t *linked_list, elem_t *elem, size_t index)
{
if(!elem) return;
if(!linked_list_is_in_bound(linked_list, index)) return;
if(index == 0)
{
linked_list_push_front_elem(linked_list, elem);
}
else if(index == (linked_list->size - 1))
{
linked_list_push_back_elem(linked_list, elem);
}
else
{
elem_t *next_insert_elem = linked_list_get_elem(linked_list, index);
elem_t *prev_insert_elem = next_insert_elem->prev;
elem->prev = prev_insert_elem;
elem->next = next_insert_elem;
prev_insert_elem->next = elem;
next_insert_elem->prev = elem;
linked_list->size++;
}
}
void linked_list_insert(linked_list_t *linked_list, void *data, size_t index)
{
elem_t *tmp = malloc(sizeof(elem_t));
if(!tmp) return;
tmp->data = data;
linked_list_insert_elem(linked_list, tmp, index);
}
void linked_list_remove_elem(linked_list_t *linked_list, elem_t *elem)
{
if(!elem) return;
if(elem == linked_list->first)
{
linked_list_pop_front(linked_list);
}
else if(elem == linked_list->last)
{
linked_list_pop_back(linked_list);
}
else
{
elem_t *prev_insert_elem = elem->prev;
elem_t *next_insert_elem = elem->next;
prev_insert_elem->next = next_insert_elem;
next_insert_elem->prev = prev_insert_elem;
destroy_elem(elem, linked_list->elem_deleter);
linked_list->size--;
}
}
void linked_list_remove(linked_list_t *linked_list, size_t index)
{
elem_t *tmp = linked_list_get_elem(linked_list, index);
if(tmp) linked_list_remove_elem(linked_list, tmp);
}
elem_t *linked_list_get_elem_if(const linked_list_t *linked_list, const condition_t condition, ...)
{
if(!condition) return NULL;
va_list args;
va_start(args, condition);
elem_t *actual_elem = linked_list->first;
elem_t *next_elem;
while(actual_elem)
{
next_elem = actual_elem->next;
va_list args_copy;
va_copy(args_copy, args);
if(condition(actual_elem, args_copy))
{
va_end(args_copy);
va_end(args);
return actual_elem;
}
va_end(args_copy);
actual_elem = next_elem;
}
va_end(args);
return NULL;
}
void *linked_list_get_if(const linked_list_t *linked_list, const condition_t condition, ...)
{
if(!condition) return NULL;
va_list args;
va_start(args, condition);
elem_t *actual_elem = linked_list->first;
elem_t *next_elem;
while(actual_elem)
{
next_elem = actual_elem->next;
va_list args_copy;
va_copy(args_copy, args);
if(condition(actual_elem, args_copy))
{
va_end(args_copy);
va_end(args);
return actual_elem->data;
}
va_end(args_copy);
actual_elem = next_elem;
}
va_end(args);
return NULL;
}
void linked_list_remove_if(linked_list_t *linked_list, const condition_t condition, ...)
{
if(!condition) return;
va_list args;
va_start(args, condition);
elem_t *actual_elem = linked_list->first;
elem_t *next_elem;
while(actual_elem)
{
next_elem = actual_elem->next;
va_list args_copy;
va_copy(args_copy, args);
if(condition(actual_elem, args_copy))
{
linked_list_remove_elem(linked_list, actual_elem);
}
va_end(args_copy);
actual_elem = next_elem;
}
va_end(args);
}
void linked_list_for_each(const linked_list_t *linked_list, const action_t action, ...)
{
if(!action) return;
va_list args;
va_start(args, action);
elem_t *actual_elem = linked_list->first;
while(actual_elem)
{
va_list args_copy;
va_copy(args_copy, args);
action(actual_elem, args_copy);
va_end(args_copy);
actual_elem = actual_elem->next;
}
va_end(args);
}

17
src/vector2d.c Normal file
View File

@ -0,0 +1,17 @@
#include "vector2d.h"
void rect_to_frect(const rect_t *rect, frect_t *frect)
{
frect->x = (float)rect->x;
frect->y = (float)rect->y;
frect->w = (float)rect->w;
frect->h = (float)rect->h;
}
void frect_to_rect(const frect_t *frect, rect_t *rect)
{
rect->x = (int)frect->x;
rect->y = (int)frect->y;
rect->w = (int)frect->w;
rect->h = (int)frect->h;
}