Adding linked lists and texture management

This commit is contained in:
Ulysse Cura 2025-02-28 17:08:02 +01:00
parent e2b5044bc5
commit 57192d8b0e
6 changed files with 853 additions and 78 deletions

View File

@ -1,30 +1,46 @@
#include <gint/kmalloc.h>
#include <stdarg.h>
#include "linked_list.h" #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; elem_t *tmp;
linked_list->first = NULL; tmp = kmalloc(sizeof(elem_t), NULL);
linked_list->last = NULL; if(!tmp) return NULL;
}
elem_t *elem_create(linked_list_t *linked_list) tmp->data = kmalloc(linked_list->data_size, NULL);
{ if(!tmp->data)
elem_t *elem;
elem = malloc(sizeof(elem_t));
if(!elem) return NULL;
elem->data = malloc(linked_list->data_size);
if(!elem->data)
{ {
free(elem); kfree(tmp);
return NULL; 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; 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->first = elem;
linked_list->last = 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; 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->last = elem;
linked_list->first = 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) 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 else
linked_list->first = NULL; linked_list->first = NULL;
free(tmp->data); destroy_elem(tmp, linked_list->elem_deleter);
free(tmp);
linked_list->size--;
} }
void linked_list_pop_front(linked_list_t *linked_list) 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 else
linked_list->last = NULL; linked_list->last = NULL;
free(tmp->data); destroy_elem(tmp, linked_list->elem_deleter);
free(tmp);
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; elem_t *actual_elem = linked_list->first;
if(!actual_elem) return 0; elem_t *tmp;
size_t size = 0;
while(actual_elem) while(actual_elem)
{ {
tmp = actual_elem;
destroy_elem(tmp, linked_list->elem_deleter);
actual_elem = actual_elem->next; 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; 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(!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; elem_t *actual_elem = linked_list->first;
if(!actual_elem) return NULL; 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; 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)
{ {
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);
}

View File

@ -15,16 +15,59 @@ typedef struct elem_t {
struct elem_t *next; struct elem_t *next;
} elem_t; } 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 /* linked_list_t: Base of linked lists
This struct is the base for creating linked lists. This struct is the base for creating linked lists.
@data_size Size of the data stored in the linked list @data_size Size of the data stored in the linked list
@first Pointer to the first element in the linked list @first Pointer to the first element in the linked list
@last Pointer to the last element in the linked list */ @last Pointer to the last element in the linked list
typedef struct { @size Size of the linked list
@deleter Deleter of the data when removing an element*/
typedef struct linked_list_t {
size_t data_size; size_t data_size;
elem_t *first; elem_t *first;
elem_t *last; elem_t *last;
size_t size;
deleter_t elem_deleter;
} linked_list_t; } linked_list_t;
/* linked_list_init(): Init a 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 @linked_list Pointer to an linked_list_t
@data_size Data size for the linked list */ @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. /* 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. 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 @linked_list Pointer to an linked_list_t
Return adress of initialised elem, NULL on error. */ 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 @linked_list Pointer to an linked_list_t
@elem Pointer to an elem_t @elem Pointer to an elem_t
Insert elem in the back of the linked list, do nothing on error. */ 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 @linked_list Pointer to an linked_list_t
@elem Pointer to an elem_t @elem Pointer to an elem_t
Insert elem in the front of the linked list, do nothing on error. */ 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_pop_back(): Delete the last elem in the given linked list
@linked_list Pointer to an linked_list_t @linked_list Pointer to an linked_list_t
Delete last elem of the linked list, do nothing on error. */ 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_pop_front(): Delete the first elem in the given linked list
@linked_list Pointer to an linked_list_t @linked_list Pointer to an linked_list_t
Delete first elem of the linked list, do nothing on error. */ 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 @linked_list Pointer to an linked_list_t
Return size of the given linked list, 0 if it's empty. */ Clear linked list. */
size_t linked_list_get_size(linked_list_t *linked_list); void linked_list_clear(linked_list_t *);
/* linked_list_is_empty(): Check if the given linked list is empty /* linked_list_is_empty(): Check if the given linked list is empty
@linked_list Pointer to an linked_list_t @linked_list Pointer to an linked_list_t
Return true if the given linked list is empty else false. */ 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_is_in_bound(): Check if the given index is whithin the range of the linked list
@linked_list Pointer to an linked_list_t @linked_list Pointer to an linked_list_t
Return true if the given linked list is empty else false. */ 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_get_elem(): Get element at the given index in the linked list
@linked_list Pointer to an linked_list_t @linked_list Pointer to an linked_list_t
@index Index of the wanted element @index Index of the wanted element
Return the element, NULL on error. */ 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 #endif // LINKED_LIST_H

View File

@ -15,43 +15,262 @@ int main(void)
return game_exit(game); return game_exit(game);
} }
*/
#include <gint/display.h>
#include <gint/keyboard.h> // Texture Unit Tests
#include "malloc.h" #ifdef TEXTURE_TEST
#include "linked_list.h"
#include "texture_manager.h"
int main(void) int main(void)
{ {
dclear(C_RGB(1, 70, 34)); dclear(C_WHITE);
linked_list_t linked_list; texture_manager_t texture_manager;
linked_list_init(&linked_list, sizeof(int)); texture_manager_init(&texture_manager);
texture_manager_load_builtin_textures(&texture_manager);
elem_t *elem1 = elem_create(&linked_list); texture_t *texture = texture_manager_get_texture(&texture_manager, "player_run_sheet");
if(!elem1)
{
dtext(1, 1, C_RED, "elem1 is not initialised correctly");
goto Exit;
}
linked_list_push_back(&linked_list, elem1); rect_t srcR = {0,0,32,32};
if( linked_list.first == linked_list.last && rect_t dstR = srcR;
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");
}
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(); dupdate();
getkey(); getkey();
if(elem1) free(elem1->data); return 1;
if(elem1) free(elem1); }
#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; return 1;
} }
#endif // LINKED_LIST_TEST

View File

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

View File

@ -1,8 +1,86 @@
#ifndef TEXTURE_MANAGER_H #ifndef TEXTURE_MANAGER_H
#define TEXTURE_MANAGER_H #define TEXTURE_MANAGER_H
typedef struct { #include <gint/image.h>
#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_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 #endif // TEXTURE_MANAGER_H

22
src/textures.h Normal file
View File

@ -0,0 +1,22 @@
#ifndef TEXTURES_H
#define TEXTURES_H
#include <gint/display.h>
#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