Automatic texture batching + sprite rendering

This commit is contained in:
2025-06-23 00:15:01 +02:00
parent b02b2b02d5
commit e8516827e1
15 changed files with 758 additions and 4704 deletions

236
src/util.h Normal file
View File

@@ -0,0 +1,236 @@
#ifndef UTIL_H
#define UTIL_H
#include "api.h"
/*typedef struct linked_list_t {
linked_item_t *first, *last;
uint16_t size;
} linked_list_t;
typedef struct linked_item_t {
linked_item_t *next, *prev;
void *data;
} linked_item_t;
typedef void (*linked_list_callback)(void *item);
//Currently, these are the only method required.
//Many more could be implemented but this is unnecessary.
static void l_list_push(linked_list_t *l_list, void *item);
static void l_list_append(linked_list_t *l_list, void *item);
static void* l_list_pop(linked_list_t *l_list);
static void* l_list_unppend(linked_list_t *l_list);
static void l_list_each(linked_list_t *l_list, linked_list_callback callback);
static inline void l_list_push(linked_list_t *l_list, void *item)
{
linked_item_t l_item = (linked_item_t) { .data = item, .prev = l_list->last, .next = nullptr };
if(l_list->first == nullptr)
l_list->first = &l_item;
l_list->last->next = &l_item;
l_list->last = &l_item;
l_list->size++;
}
static inline void l_list_append(linked_list_t *l_list, void *item)
{
linked_item_t l_item = (linked_item_t) { .data = item, .prev = nullptr, .next = l_list->last };
if(l_list->last == nullptr)
l_list->last = &l_item;
l_list->first->prev = &l_item;
l_list->first = &l_item;
l_list->size++;
}
static inline void* l_list_pop(linked_list_t *l_list)
{
if(l_list->last == nullptr)
return;
if(l_list->first == l_list->last)
l_list->first = nullptr;
linked_item_t *item = l_list->last->prev;
l_list->last->prev = nullptr;
l_list->last = item;
l_list->size--;
}
static inline void* l_list_unppend(linked_list_t *l_list)
{
if(l_list->first == nullptr)
return;
if(l_list->last == l_list->first)
l_list->last = nullptr;
linked_item_t *item = l_list->first->next;
l_list->first->next = nullptr;
l_list->first = item;
l_list->size--;
}
static inline void l_list_each(linked_list_t *l_list, linked_list_callback callback)
{
}*/
typedef struct vector_t {
void **data; //Memory pool
uint16_t stripe; //Bit per item
uint32_t size; //Current amount of items
uint32_t capacity; //Max capacity
} vector_t;
#define MAX_BUCKET_SIZE (0xffffffffu)
#define MAX_STRIPE_SIZE (0xffffu)
#define FIXED_START (0xfffu)
static vector_t vector_create(uint16_t stripe); //Create a new vector with a default size
static void vector_clear(vector_t *vector);
static void vector_free(vector_t *vector);
static uint32_t vector_length(vector_t *vector);
static void* vector_get(vector_t *vector, uint32_t index);
static void vector_set(vector_t *vector, uint32_t index, void *data);
static uint32_t vector_push(vector_t *vector, void *data);
static sg_range vector_range(vector_t *vector);
static vector_t vector_create(uint16_t stripe)
{
assert(stripe >= sizeof(uint32_t));
assert(stripe <= MAX_STRIPE_SIZE);
assert(FIXED_START * stripe <= MAX_BUCKET_SIZE);
return (vector_t) {
.capacity = FIXED_START,
.size = 0,
.stripe = stripe,
.data = (void**) malloc(FIXED_START * stripe),
};
}
static void vector_clear(vector_t *vector)
{
vector->size = 0;
}
static void vector_free(vector_t *vector)
{
free(vector->data);
}
static uint32_t vector_length(vector_t *vector)
{
return vector->size;
}
static void* vector_get(vector_t *vector, uint32_t index)
{
assert(index > 0);
assert(index < vector->size);
return vector->data[index * vector->stripe];
}
static void vector_set(vector_t *vector, uint32_t index, void *data)
{
assert(index > 0);
assert(index < vector->size);
vector->data[index * vector->stripe] = data;
}
static uint32_t vector_push(vector_t *vector, void *data)
{
if(vector->size >= vector->capacity)
{
vector->capacity *= 2;
vector->data = (void**) realloc(vector->data, vector->capacity * vector->stripe);
}
return vector->size++;
}
static sg_range vector_range(vector_t *vector)
{
return (sg_range) {
.ptr = vector->data,
.size = vector->size,
};
}
typedef struct mem_pool_t {
void **data; //Memory pool
uint16_t stripe; //Bit per item
uint32_t size; //Current amount of items
uint32_t capacity; //Max capacity
uint32_t free; //Linked list of available indices
} mem_pool_t;
static mem_pool_t pool_create(uint16_t stripe); //Create a new memory pool with a default size
static void pool_clear(mem_pool_t *pool);
static void pool_free(mem_pool_t *pool);
static uint32_t pool_add(mem_pool_t *pool); //Request a new free index
static void* pool_get(mem_pool_t *pool, uint32_t index); //Get the pointer
static void pool_remove(mem_pool_t *pool, uint32_t index); //Flag the given index as free
static mem_pool_t pool_create(uint16_t stripe)
{
assert(stripe >= sizeof(uint32_t));
assert(stripe <= MAX_STRIPE_SIZE);
assert(FIXED_START * stripe <= MAX_BUCKET_SIZE);
return (mem_pool_t) {
.capacity = FIXED_START,
.size = 0,
.stripe = stripe,
.free = UINT32_MAX,
.data = (void**) malloc(FIXED_START * stripe),
};
}
static void pool_clear(mem_pool_t *pool)
{
pool->size = 0;
pool->free = UINT32_MAX;
}
static void pool_free(mem_pool_t *pool)
{
free(pool->data);
}
static uint32_t pool_add(mem_pool_t *pool)
{
if(pool->free != UINT32_MAX)
{
const uint32_t index = pool->free;
pool->free = (uint32_t) pool->data[index * pool->stripe];
return index;
}
else
{
if(pool->size >= pool->capacity)
{
pool->capacity *= 2;
pool->data = (void**) realloc(pool->data, pool->capacity * pool->stripe);
}
return pool->size++;
}
}
static void* pool_get(mem_pool_t *pool, uint32_t index)
{
assert(index > 0);
assert(index < pool->capacity);
return pool->data[index * pool->stripe];
}
static void pool_remove(mem_pool_t *pool, uint32_t index)
{
const uint32_t pos = index * pool->stripe;
pool->data[pos] = (void*) pool->free;
pool->free = index;
}
#endif