diff --git a/src/linked_list.c b/src/linked_list.c index 4edc78b..544bb90 100644 --- a/src/linked_list.c +++ b/src/linked_list.c @@ -1,30 +1,46 @@ +#include +#include #include "linked_list.h" -#include "malloc.h" -void linked_list_init(linked_list_t *linked_list, const size_t data_size) +elem_t *elem_create(const linked_list_t *linked_list) { - linked_list->data_size = data_size; - linked_list->first = NULL; - linked_list->last = NULL; -} + elem_t *tmp; + tmp = kmalloc(sizeof(elem_t), NULL); + if(!tmp) return NULL; -elem_t *elem_create(linked_list_t *linked_list) -{ - elem_t *elem; - elem = malloc(sizeof(elem_t)); - if(!elem) return NULL; - - elem->data = malloc(linked_list->data_size); - if(!elem->data) + tmp->data = kmalloc(linked_list->data_size, NULL); + if(!tmp->data) { - free(elem); + kfree(tmp); return NULL; } - return elem; + return tmp; } -void linked_list_push_back(linked_list_t *linked_list, elem_t *elem) +inline void destroy_elem(elem_t *elem, const deleter_t elem_deleter) +{ + if(!elem) return; + + if(elem_deleter) + elem_deleter(elem->data); + else + kfree(elem->data); + + kfree(elem); +} + +void linked_list_init(linked_list_t *linked_list, const size_t data_size, 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; @@ -37,9 +53,11 @@ void linked_list_push_back(linked_list_t *linked_list, elem_t *elem) linked_list->first = elem; linked_list->last = elem; + + linked_list->size++; } -void linked_list_push_front(linked_list_t *linked_list, elem_t *elem) +void linked_list_push_front_elem(linked_list_t *linked_list, elem_t *elem) { if(!elem) return; @@ -52,6 +70,26 @@ void linked_list_push_front(linked_list_t *linked_list, elem_t *elem) 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 = kmalloc(sizeof(elem_t), NULL); + 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 = kmalloc(sizeof(elem_t), NULL); + if(!tmp) return; + tmp->data = data; + + linked_list_push_front_elem(linked_list, tmp); } void linked_list_pop_back(linked_list_t *linked_list) @@ -66,8 +104,9 @@ void linked_list_pop_back(linked_list_t *linked_list) else linked_list->first = NULL; - free(tmp->data); - free(tmp); + destroy_elem(tmp, linked_list->elem_deleter); + + linked_list->size--; } void linked_list_pop_front(linked_list_t *linked_list) @@ -82,38 +121,50 @@ void linked_list_pop_front(linked_list_t *linked_list) else linked_list->last = NULL; - free(tmp->data); - free(tmp); + destroy_elem(tmp, linked_list->elem_deleter); + + linked_list->size--; } -size_t linked_list_get_size(linked_list_t *linked_list) +void linked_list_clear(linked_list_t *linked_list) { elem_t *actual_elem = linked_list->first; - if(!actual_elem) return 0; + elem_t *tmp; - size_t size = 0; while(actual_elem) { + tmp = actual_elem; + + destroy_elem(tmp, linked_list->elem_deleter); + actual_elem = actual_elem->next; - size++; } - return size; + + linked_list->first = NULL; + linked_list->last = NULL; + + linked_list->size = 0; } -bool linked_list_is_empty(linked_list_t *linked_list) +inline bool linked_list_is_empty(const linked_list_t *linked_list) { return !linked_list->first; } -bool linked_list_is_in_bound(linked_list_t *linked_list, size_t index) +inline bool linked_list_is_in_bound(const linked_list_t *linked_list, const size_t index) { - return index < linked_list_get_size(linked_list); + return index < linked_list->size; } -elem_t *linked_list_get_elem(linked_list_t *linked_list, size_t index) +elem_t *linked_list_get_elem(const linked_list_t *linked_list, const 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; @@ -124,8 +175,202 @@ elem_t *linked_list_get_elem(linked_list_t *linked_list, size_t index) return actual_elem; } -/* -void linked_list_insert(linked_list_t *linked_list, elem_t *elem, size_t index) + +void *linked_list_get(const linked_list_t *linked_list, const size_t index) { - -}*/ \ No newline at end of file + 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, const size_t index) +{ + if(!elem) return; + if(!linked_list_is_in_bound(linked_list, index)) return; + + if(index == 0) + { + linked_list_push_front(linked_list, elem); + } + else if(index == (linked_list->size - 1)) + { + linked_list_push_back(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, const size_t index) +{ + elem_t *tmp = kmalloc(sizeof(elem_t), NULL); + 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->prev && !elem->next) 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, const size_t index) +{ + if(!linked_list_is_in_bound(linked_list, index)) return; + + 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); + + for(elem_t *actual_elem = linked_list->first; actual_elem; actual_elem = actual_elem->next) + { + va_list args_copy; + va_copy(args_copy, args); + + action(actual_elem, args_copy); + + va_end(args_copy); + } + + va_end(args); +} diff --git a/src/linked_list.h b/src/linked_list.h index 05909a3..45dff01 100644 --- a/src/linked_list.h +++ b/src/linked_list.h @@ -15,16 +15,59 @@ typedef struct elem_t { struct elem_t *next; } elem_t; +/* deleter_t: A type for deleters used during the destruction of 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 (kfree(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 kfree the data itself...). + You can define your function with "inline" if the deleting is short. */ +typedef void (*deleter_t)(void *); + +/* condition_t: A type for condition used for conditionned 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 can define your function with "static inline" if the condition is short. */ +typedef bool (*condition_t)(elem_t *, va_list); + +/* action_t: 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 XD. + You can define your function with "static inline" if the condition is short. */ +typedef void (*action_t)(elem_t *, va_list); + /* linked_list_t: Base of linked lists This struct is the base for creating linked lists. @data_size Size of the data stored in the linked list @first Pointer to the first element in the linked list - @last Pointer to the last element in the linked list */ -typedef struct { + @last Pointer to the last element in the linked list + @size Size of the linked list + @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; /* linked_list_init(): Init a linked_list_t @@ -32,64 +75,159 @@ typedef struct { @linked_list Pointer to an linked_list_t @data_size Data size for the linked list */ -void linked_list_init(linked_list_t *linked_list, const size_t data_size); +void linked_list_init(linked_list_t *, const size_t, deleter_t deleter); /* elem_create(): Create an elem to fill with data and insert in a linked list. This function is usefull when you want to initialise an elem with the proper data_size. + 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; @linked_list Pointer to an linked_list_t Return adress of initialised elem, NULL on error. */ -elem_t *elem_create(linked_list_t *linked_list); +elem_t *elem_create(const linked_list_t *); -/* linked_list_push_back(): Insert an elem_t from the back in a linked_list_t. +/* destroy_elem(): 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. + + @elem Pointer to an elem_t + Free the given elem. */ +void destroy_elem(elem_t *, const deleter_t); + +/* linked_list_push_back_elem(): Insert an elem_t from the back in a linked_list_t. @linked_list Pointer to an linked_list_t @elem Pointer to an elem_t Insert elem in the back of the linked list, do nothing on error. */ -void linked_list_push_back(linked_list_t *linked_list, elem_t *elem); +void linked_list_push_back_elem(linked_list_t *, elem_t *); -/* linked_list_push_front(): Insert an elem_t from the front in a linked_list_t. +/* linked_list_push_front_elem(): Insert an elem_t from the front in a linked_list_t. @linked_list Pointer to an linked_list_t @elem Pointer to an elem_t Insert elem in the front of the linked list, do nothing on error. */ -void linked_list_push_front(linked_list_t *linked_list, elem_t *elem); +void linked_list_push_front_elem(linked_list_t *, elem_t *); + +/* linked_list_push_back_elem(): Insert an elem_t filled with data from the back in a linked_list_t. + + @linked_list Pointer to an linked_list_t + @data Pointer to any data + Insert elem filled with data in the back of the linked list, do nothing on error. */ +void linked_list_push_back(linked_list_t *, void *); + +/* linked_list_push_front_elem(): Insert an elem_t filled with data from the front in a linked_list_t. + + @linked_list Pointer to an linked_list_t + @data Pointer to any data + Insert elem filled with data in the front of the linked list, do nothing on error. */ +void linked_list_push_front(linked_list_t *, void *); /* linked_list_pop_back(): Delete the last elem in the given linked list @linked_list Pointer to an linked_list_t Delete last elem of the linked list, do nothing on error. */ -void linked_list_pop_back(linked_list_t *linked_list); +void linked_list_pop_back(linked_list_t *); /* linked_list_pop_front(): Delete the first elem in the given linked list @linked_list Pointer to an linked_list_t Delete first elem of the linked list, do nothing on error. */ -void linked_list_pop_front(linked_list_t *linked_list); +void linked_list_pop_front(linked_list_t *); -/* linked_list_get_size(): Get the size of the given linked list +/* linked_list_clear(): Clear the given linked list @linked_list Pointer to an linked_list_t - Return size of the given linked list, 0 if it's empty. */ -size_t linked_list_get_size(linked_list_t *linked_list); + Clear linked list. */ +void linked_list_clear(linked_list_t *); /* linked_list_is_empty(): Check if the given linked list is empty @linked_list Pointer to an linked_list_t Return true if the given linked list is empty else false. */ -bool linked_list_is_empty(linked_list_t *linked_list); +bool linked_list_is_empty(const linked_list_t *); /* linked_list_is_in_bound(): Check if the given index is whithin the range of the linked list @linked_list Pointer to an linked_list_t Return true if the given linked list is empty else false. */ -bool linked_list_is_in_bound(linked_list_t *linked_list, size_t index); +bool linked_list_is_in_bound(const linked_list_t *, const size_t); /* linked_list_get_elem(): Get element at the given index in the linked list @linked_list Pointer to an linked_list_t @index Index of the wanted element Return the element, NULL on error. */ -elem_t *linked_list_get_elem(linked_list_t *linked_list, size_t index); +elem_t *linked_list_get_elem(const linked_list_t *, const size_t); + +/* linked_list_get(): Get data in the element at the given index in the linked list + + @linked_list Pointer to an linked_list_t + @index Index of the wanted element + Return the data, NULL on error. */ +void *linked_list_get(const linked_list_t *, const size_t); + +/* linked_list_insert_elem(): Insert element at the given index in the linked list + + @linked_list Pointer to an linked_list_t + @elem Pointer to an element + @index Index of the wanted element + Insert the element, do nothing on error. */ +void linked_list_insert_elem(linked_list_t *, elem_t *, const size_t); + +/* linked_list_insert(): Insert element with data at the given index in the linked list + + @linked_list Pointer to an linked_list_t + @data Data to put in the new element + @index Index of the wanted element + Return the element, do nothing on error. */ +void linked_list_insert(linked_list_t *, void *, const size_t); + +/* linked_list_remove_elem(): Remove the given elem in the linked list + + @linked_list Pointer to an linked_list_t + @elem Element to remove + Remove the element, do nothing on error. */ +void linked_list_remove_elem(linked_list_t *, elem_t *); + +/* linked_list_remove(): Remove element at the given index in the linked list + + @linked_list Pointer to an linked_list_t + @index Index of the element + Remove the element, do nothing on error. */ +void linked_list_remove(linked_list_t *, const size_t); + +/* linked_list_get_elem_if(): Return first element that the condition verify + + @linked_list Pointer to an linked_list_t + @condition Condition to verify + @... Argument to pass to the condition + Return the element, NULL on error. */ +elem_t *linked_list_get_elem_if(const linked_list_t *, const condition_t, ...); + +/* linked_list_get_if(): Return data in the first element that the condition verify + + @linked_list Pointer to an linked_list_t + @condition Condition to verify + @... Argument to pass to the condition + Return the element data, NULL on error. */ +void *linked_list_get_if(const linked_list_t *, const condition_t, ...); + +/* linked_list_remove_if(): Remove element(s) that the condition verify + + @linked_list Pointer to an linked_list_t + @condition Condition to verify + @... Argument to pass to the condition + Remove the element(s), do nothing on error. */ +void linked_list_remove_if(linked_list_t *, const condition_t, ...); + +/* linked_list_for_each(): Apply the condition to every elements in the list + Useful for changing a value in every single element data. + The condition can be anything that dont destroy the element. + + @linked_list Pointer to an linked_list_t + @condition Condition to apply + @... Argument to pass to the condition */ +void linked_list_for_each(const linked_list_t *, const action_t, ...); #endif // LINKED_LIST_H \ No newline at end of file diff --git a/src/main.c b/src/main.c index e7e2f43..7623fc8 100644 --- a/src/main.c +++ b/src/main.c @@ -15,43 +15,262 @@ int main(void) return game_exit(game); } -*/ -#include -#include -#include "malloc.h" -#include "linked_list.h" + +// Texture Unit Tests +#ifdef TEXTURE_TEST + +#include "texture_manager.h" int main(void) { - dclear(C_RGB(1, 70, 34)); + dclear(C_WHITE); - linked_list_t linked_list; - linked_list_init(&linked_list, sizeof(int)); + texture_manager_t texture_manager; + texture_manager_init(&texture_manager); + texture_manager_load_builtin_textures(&texture_manager); - elem_t *elem1 = elem_create(&linked_list); - if(!elem1) - { - dtext(1, 1, C_RED, "elem1 is not initialised correctly"); - goto Exit; - } + texture_t *texture = texture_manager_get_texture(&texture_manager, "player_run_sheet"); - linked_list_push_back(&linked_list, elem1); - if( linked_list.first == linked_list.last && - linked_list.first && - linked_list.first->prev == NULL && - linked_list.last->prev == NULL) - { - dtext(1, 1, C_BLACK, "elem1 is correctly inserted in linked list"); - } + rect_t srcR = {0,0,32,32}; + rect_t dstR = srcR; - Exit: + draw_texture(texture, &src, &dst); + + src.x = 33; + dst.x = 33; + + draw_texture(texture, &src, &dst); + + texture_manager_remove_texture(&texture_manager, "player_run_sheet"); + + src.w = 128; + dst.x = 0; + dst.y = 33; + + texture_manager_draw_texture(&texture_manager, "player_idle_sheet", &src, &dst); + + texture_manager_clear(&texture_manager); dupdate(); getkey(); - if(elem1) free(elem1->data); - if(elem1) free(elem1); + return 1; +} + +#endif // TEXTURE_TEST + +// Linked List Unit Tests +#ifdef LINKED_LIST_TEST + +#include "linked_list.h" + +int main(void) +{ + dclear(C_WHITE); + + linked_list_t linked_list; + linked_list_init(&linked_list, sizeof(int)); + if(linked_list.first == linked_list.last && + linked_list.first == NULL) + { + dtext(1, 0, C_BLACK, "linked_list is initialised correctly"); + } + else + { + goto Exit; + } + + elem_t *elem1 = NULL; + elem_t *elem2 = NULL; + elem_t *elem3 = NULL; + elem_t *elem4 = NULL; + + elem1 = elem_create(&linked_list); + if(elem1 && elem1->data) + { + dtext(1, 10, C_BLACK, "elem1 is initalised correctly"); + } + else + { + goto Exit; + } + + linked_list_push_back_elem(&linked_list, elem1); + if(linked_list.first == linked_list.last && + linked_list.first == elem1 && + !linked_list.first->prev && + !linked_list.first->next && + !linked_list.last->prev && + !linked_list.last->next) + { + dtext(1, 20, C_BLACK, "elem1 is correctly pushed back"); + } + else + { + goto Exit; + } + + linked_list_pop_back(&linked_list); + if(linked_list.first == linked_list.last && + linked_list.first == NULL) + { + dtext(1, 30, C_BLACK, "elem1 is correctly poped back"); + } + else + { + goto Exit; + } + + elem1 = elem_create(&linked_list); + elem2 = elem_create(&linked_list); + elem3 = elem_create(&linked_list); + elem4 = elem_create(&linked_list); + + linked_list_push_back_elem(&linked_list, elem1); + linked_list_push_back_elem(&linked_list, elem2); + if(linked_list.first == elem1 && + linked_list.last == elem2 && + !linked_list.first->prev && + linked_list.first->next && + linked_list.last->prev && + !linked_list.last->next && + linked_list.first->next == elem2 && + linked_list.last->prev == elem1) + { + dtext(1, 40, C_BLACK, "elem1 and elem2 are correctly pushed back"); + } + else + { + goto Exit; + } + + linked_list_push_front_elem(&linked_list, elem3); + linked_list_push_front_elem(&linked_list, elem4); + if(!linked_list.first->prev && + !linked_list.last->next && + linked_list.first == elem4 && + linked_list.first->next == elem3 && + linked_list.first->next->next == elem1 && + linked_list.first->next->next->next == elem2 && + linked_list.last == elem2 && + linked_list.last->prev == elem1 && + linked_list.last->prev->prev == elem3 && + linked_list.last->prev->prev->prev == elem4) + { + dtext(1, 50, C_BLACK, "elem3 and elem4 are correctly pushed front"); + } + else + { + goto Exit; + } + + if(linked_list_get_elem(&linked_list, 2) == elem1) + { + dtext(1, 60, C_BLACK, "elem4 is got correctly"); + } + else + { + goto Exit; + } + + linked_list_pop_back(&linked_list); + if(!linked_list.first->prev && + !linked_list.last->next && + linked_list.first == elem4 && + linked_list.first->next == elem3 && + linked_list.first->next->next == elem1 && + linked_list.last == elem1 && + linked_list.last->prev == elem3 && + linked_list.last->prev->prev == elem4) + { + dtext(1, 70, C_BLACK, "elem2 is correctly poped back"); + } + else + { + goto Exit; + } + + linked_list_remove(&linked_list, 1); + if(!linked_list.first->prev && + !linked_list.last->next && + linked_list.first == elem4 && + linked_list.first->next == elem1 && + linked_list.last == elem1 && + linked_list.last->prev == elem4) + { + dtext(1, 80, C_BLACK, "elem3 is correctly removed"); + } + else + { + goto Exit; + } + + linked_list_clear(&linked_list); + if(linked_list.first == linked_list.last && + linked_list.first == NULL) + { + dtext(1, 90, C_BLACK, "linked list is correctly cleared"); + } + else + { + goto Exit; + } + + elem1 = elem_create(&linked_list); + elem2 = elem_create(&linked_list); + elem3 = elem_create(&linked_list); + elem4 = elem_create(&linked_list); + + linked_list_push_back_elem(&linked_list, elem1); + linked_list_push_back_elem(&linked_list, elem2); + linked_list_push_front_elem(&linked_list, elem3); + if(linked_list.first == elem3 && + linked_list.last == elem2 && + !linked_list.first->prev && + linked_list.first->next && + linked_list.last->prev && + !linked_list.last->next && + linked_list.first->next == elem1 && + linked_list.first->next->next == elem2 && + linked_list.last->prev == elem1 && + linked_list.last->prev->prev == elem3) + { + dtext(1, 100, C_BLACK, "elem1, elem2 and elem3 are correctly pushed"); + } + else + { + goto Exit; + } + + linked_list_insert_elem(&linked_list, elem4, 1); + if(linked_list.first == elem3 && + linked_list.last == elem2 && + !linked_list.first->prev && + linked_list.first->next && + linked_list.last->prev && + !linked_list.last->next && + linked_list.first->next == elem4 && + linked_list.first->next->next == elem1 && + linked_list.first->next->next->next == elem2 && + linked_list.last->prev == elem1 && + linked_list.last->prev->prev == elem4 && + linked_list.last->prev->prev->prev == elem3) + { + dtext(1, 110, C_BLACK, "elem3 is correctly inserted"); + } + else + { + goto Exit; + } + + linked_list_clear(&linked_list); + + Exit: + dupdate(); + getkey(); return 1; -} \ No newline at end of file +} + +#endif // LINKED_LIST_TEST diff --git a/src/texture_manager.c b/src/texture_manager.c index e69de29..6a2c033 100644 --- a/src/texture_manager.c +++ b/src/texture_manager.c @@ -0,0 +1,73 @@ +#include +#include +#include "texture_manager.h" +#include "textures.h" + +texture_t *create_texture(image_t *image, const char *name) +{ + if(!image) return NULL; + + texture_t *texture = kmalloc(sizeof(texture_t), NULL); + if (!texture) return NULL; + + texture->name = name; + texture->image = image; + + return texture; +} + +inline void destroy_texture(texture_t *texture) +{ + kfree(texture); +} + +inline void draw_texture(const texture_t *texture, const rect_t *src, const rect_t *dst, bool flip) +{ + dsubimage_rgb16_effect((int)dst->x, (int)dst->y, texture->image, (int)src->x, (int)src->y, (int)src->w, (int)src->h, flip ? IMAGE_HFLIP : DIMAGE_NONE); +} + +inline void texture_manager_init(texture_manager_t *texture_manager) +{ + linked_list_init(&texture_manager->textures, sizeof(texture_t), NULL); +} + +void texture_manager_load_builtin_textures(texture_manager_t *texture_manager) +{ + for(size_t i = 0; i < BUILTIN_TEXTURE_COUNT; i++) + { + texture_t *texture = create_texture((image_t *)builtin_textures[i].image, builtin_textures[i].name); + texture_manager_add_texture(texture_manager, texture); + } +} + +inline void texture_manager_add_texture(texture_manager_t *texture_manager, texture_t *texture) +{ + linked_list_push_back(&texture_manager->textures, texture); +} + +// Only for this file +// Arg : const char *name +static inline bool is_texture_name(elem_t *elem, va_list args) +{ + return !strcmp(((texture_t *)elem->data)->name, va_arg(args, const char*)); +} + +inline texture_t *texture_manager_get_texture(const texture_manager_t *texture_manager, const char *name) +{ + return linked_list_get_if(&texture_manager->textures, is_texture_name, name); +} + +inline void texture_manager_remove_texture(texture_manager_t *texture_manager, const char *name) +{ + linked_list_remove_if(&texture_manager->textures, is_texture_name, name); +} + +inline void texture_manager_clear(texture_manager_t *texture_manager) +{ + linked_list_clear(&texture_manager->textures); +} + +inline void texture_manager_draw_texture(const texture_manager_t *texture_manager, const char *name, const rect_t *src, const rect_t *dst, bool flip) +{ + draw_texture(texture_manager_get_texture(texture_manager, name), src, dst, flip); +} diff --git a/src/texture_manager.h b/src/texture_manager.h index e1988d4..a41d33d 100644 --- a/src/texture_manager.h +++ b/src/texture_manager.h @@ -1,8 +1,86 @@ #ifndef TEXTURE_MANAGER_H #define TEXTURE_MANAGER_H -typedef struct { +#include +#include "vector2d.h" +#include "linked_list.h" +/* texture_t: Texture definition + This struct is the base for textures + + @name Name of the texture + @image Texture of type bopti_image_t */ +typedef struct texture_t { + const char *name; + image_t *image; +} texture_t; + +/* create_texture(): Create a texture with the given image and name + + @name Name of the texture + @image Texture of type bopti_image_t + Return the created texture, NULL on error. */ +texture_t *create_texture(image_t *, const char *); + +/* destroy_texture(): Destroy the given texture + + @texture Texture to destroy */ +void destroy_texture(texture_t *); + +/* draw_texture(): Draw the given texture from given src rect to dst rect + + @texture Texture to draw + @src Source rectangle of the texture to draw + @dst Destination of the drawing */ +void draw_texture(const texture_t *, const rect_t *, const rect_t *, bool); + +/* texture_manager_t: Texture manager + + @textures Textures loaded in memory */ +typedef struct texture_manager_t { + linked_list_t textures; } texture_manager_t; +/* texture_manager_init(): Initialise the given texture_manager + + @texture_manager Pointer to a texture manager */ +void texture_manager_init(texture_manager_t *); + +/* texture_manager_load_builtin_textures(): Load textures declared in "textures.h" + + @texture_manager Pointer to a texture manager */ +void texture_manager_load_builtin_textures(texture_manager_t *); + +/* texture_manager_add_texture(): Add a texture in the texture manager + + @texture_manager Pointer to a texture manager + @texture Texture to add in the texture manager */ +void texture_manager_add_texture(texture_manager_t *, texture_t *); + +/* texture_manager_get_texture(): Get a texture in the texture manager + + @texture_manager Pointer to a texture manager + @name Name of the texture to get + Return the texture, NULL on error or if the texture is not found. */ +texture_t *texture_manager_get_texture(const texture_manager_t *, const char *); + +/* texture_manager_remove_texture(): Remove a texture in the texture manager + + @texture_manager Pointer to a texture manager + @name Name of the texture to remove + Do nothing if the texture is not found. */ +void texture_manager_remove_texture(texture_manager_t *, const char *); + +/* texture_manager_clear(): Clear the texture manager + + @texture_manager Pointer to a texture manager */ +void texture_manager_clear(texture_manager_t *); + +/* texture_manager_draw_texture(): Draw a texture in the texture manager + + @texture_manager Pointer to a texture manager + @name Name of the texture to draw + Do nothing if the texture is not found. */ +void texture_manager_draw_texture(const texture_manager_t *, const char *, const rect_t *, const rect_t *, bool); + #endif // TEXTURE_MANAGER_H \ No newline at end of file diff --git a/src/textures.h b/src/textures.h new file mode 100644 index 0000000..dad398e --- /dev/null +++ b/src/textures.h @@ -0,0 +1,22 @@ +#ifndef TEXTURES_H +#define TEXTURES_H + +#include +#include "texture_manager.h" + +typedef struct builtin_texture_t { + const char *name; + bopti_image_t *image; +} builtin_texture_t; + +extern bopti_image_t img_player_idle_sheet; +extern bopti_image_t img_player_run_sheet; + +static struct builtin_texture_t builtin_textures[] = { + {"player_idle_sheet", &img_player_idle_sheet}, + {"player_run_sheet", &img_player_run_sheet}, +}; + +#define BUILTIN_TEXTURE_COUNT (sizeof(builtin_textures) / sizeof(builtin_texture_t)) + +#endif // TEXTURES_H \ No newline at end of file