Add first utilities

The utilities are grouped into the following categories:

- Math
  Matrices, vectors and special rounding functions are included in the
  math category. This still is severely lacking in functionality.

- Containers
  Datatypes for  storing arbitrary data in a  special way, for example
  for being able to search  through it quickly, in the  case of a map.
  Currently the only function in this category is for testing how long
  a string is, with a maximum number of bytes to check.

- Allocation
  Special-purpose memory allocators with restrictions on what they can
  allocate. The restrictions are used to be faster in those use cases.

- UUID
  Universally-unique  identifiers are  used to  identify one  specific
  object within the engine's lifetime.
This commit is contained in:
Eric-Paul Ickhorn 2024-09-08 17:12:42 +02:00
parent 004f089cf0
commit c3fb07b871
Signed by: epickh
GPG Key ID: 1358818BAA38B104
12 changed files with 857 additions and 0 deletions

View File

@ -0,0 +1,175 @@
#ifndef VOXULA_UTILITY_H
#define VOXULA_UTILITY_H
#include <stdint.h>
#include <stdio.h>
typedef struct vx_uuid_table vx_uuid_table_s;
typedef struct vx_uuid_block vx_uuid_block_s;
typedef struct vx_uuid_entry vx_uuid_entry_s;
typedef uint64_t vx_uuid_d;
typedef struct vx_vec2f vx_vec2f_s;
typedef struct vx_vec3f vx_vec3f_s;
typedef struct vx_vec4f vx_vec4f_s;
typedef struct vx_mat2f vx_mat2f_s;
typedef struct vx_mat3f vx_mat3f_s;
typedef struct vx_mat4f vx_mat4f_s;
typedef struct vx_pool vx_pool_s;
typedef struct vx_pool_slot_header vx_pool_slot_header_s;
typedef struct vx_arena vx_arena_s;
struct vx_uuid_entry
{
vx_uuid_d uuid;
};
struct vx_uuid_block
{
/// @brief Start of the block's UUIDs;
/// this must be multiplied with 4096
/// to get the first ID's number.
uint32_t offset;
uint8_t num_ids;
vx_uuid_entry_s entries[256];
};
struct vx_uuid_table
{
uint32_t block_capacity;
uint32_t num_blocks;
vx_uuid_block_s **blocks;
};
struct vx_vec2f
{
float x;
float y;
};
struct vx_vec3f
{
float x;
float y;
float z;
};
struct vx_vec4f
{
float x;
float y;
float z;
float w;
};
struct vx_mat2f
{
float val[4];
};
struct vx_mat3f
{
float val[9];
};
struct vx_mat4f
{
float val[16];
};
struct vx_pool_slot_header
{
vx_pool_slot_header_s *next;
vx_pool_s *pool;
};
struct vx_pool
{
uint32_t capacity;
uint32_t unit_size;
void *allocation;
vx_pool_slot_header_s *first_free;
vx_pool_s *continuation;
};
struct vx_arena
{
uint32_t capacity;
uint32_t usage;
void *allocation;
vx_arena_s *continuation;
};
vx_uuid_table_s * vx_new_uuid_table();
vx_uuid_d vx_new_uuid(vx_uuid_table_s *table);
uint32_t vx_measure_string_up_to(const char *string, uint32_t maximum);
vx_vec3f_s vx_vec3f_negative(vx_vec3f_s vector);
vx_mat2f_s vx_mat2f_identity();
vx_mat3f_s vx_mat3f_identity();
vx_mat4f_s vx_mat4f_identity();
void vx_mat4f_stringify(FILE *file, vx_mat4f_s matrix);
vx_mat4f_s vx_mat4f_translate(
vx_mat4f_s matrix,
vx_vec3f_s translation
);
vx_mat4f_s vx_mat4f_rotate_x(
vx_mat4f_s matrix,
float rotation
);
vx_mat4f_s vx_mat4f_rotate_y(
vx_mat4f_s matrix,
float rotation
);
vx_mat4f_s vx_mat4f_rotate_z(
vx_mat4f_s matrix,
float rotation
);
vx_mat4f_s vx_mat4f_scale(
vx_mat4f_s matrix,
vx_vec3f_s scaling
);
vx_mat4f_s vx_mat4f_perspective(
float aspect_ratio,
float fov,
float near_plane,
float far_plane
);
uint64_t vx_ceil_to(uint64_t base, uint64_t anchor);
uint64_t vx_ceil_pow2(uint64_t base);
uint64_t vx_min_u64(uint64_t first, uint64_t second);
uint64_t vx_max_u64(uint64_t first, uint64_t second);
// Pool Functions
vx_pool_s * vx_new_pool(uint32_t unit_size, uint32_t capacity);
void vx_free_pool(vx_pool_s *pool);
void * vx_pool(vx_pool_s *pool);
void vx_unpool(void *allocation);
// Arena Functions
vx_arena_s * vx_new_arena(uint32_t capacity);
void vx_free_arena(vx_arena_s *arena);
void * vx_arena_alloc(vx_arena_s *arena, uint32_t length);
char * vx_arena_dupe_string(vx_arena_s *arena, const char *string);
char * vx_arena_dupe_string_up_to(vx_arena_s *arena, const char *string, uint32_t maximum);
#endif // VOXULA_UTILITY_H

View File

@ -0,0 +1,52 @@
#ifndef VOXULA_ALLOCATOR_H
#define VOXULA_ALLOCATOR_H
#include <stdint.h>
typedef struct vx_pool vx_pool_s;
typedef struct vx_pool_slot_header vx_pool_slot_header_s;
typedef struct vx_arena vx_arena_s;
struct vx_pool_slot_header
{
vx_pool_slot_header_s *next;
vx_pool_s *pool;
};
struct vx_pool
{
uint32_t capacity;
uint32_t unit_size;
void *allocation;
vx_pool_slot_header_s *first_free;
vx_pool_s *continuation;
};
struct vx_arena
{
uint32_t capacity;
uint32_t usage;
void *allocation;
vx_arena_s *continuation;
};
// Pool Functions
vx_pool_s * vx_new_pool(uint32_t unit_size, uint32_t capacity);
void vx_free_pool(vx_pool_s *pool);
void * vx_pool(vx_pool_s *pool);
void vx_unpool(void *allocation);
// Arena Functions
vx_arena_s * vx_new_arena(uint32_t capacity);
void vx_free_arena(vx_arena_s *arena);
void * vx_arena_alloc(vx_arena_s *arena, uint32_t length);
char * vx_arena_dupe_string(vx_arena_s *arena, const char *string);
char * vx_arena_dupe_string_up_to(vx_arena_s *arena, const char *string, uint32_t maximum);
#endif // VOXULA_ALLOCATOR_H

View File

@ -0,0 +1,9 @@
#ifndef VOXULA_CONTAINERS_H
#define VOXULA_CONTAINERS_H
#include <stdint.h>
uint32_t vx_measure_string_up_to(const char *string, uint32_t maximum);
#endif // VOXULA_CONTAINERS_H

View File

@ -0,0 +1,92 @@
#ifndef VOXULA_MATH_H
#define VOXULA_MATH_H
#include <stdint.h>
#include <stdio.h>
typedef struct vx_vec2f vx_vec2f_s;
typedef struct vx_vec3f vx_vec3f_s;
typedef struct vx_vec4f vx_vec4f_s;
typedef struct vx_mat2f vx_mat2f_s;
typedef struct vx_mat3f vx_mat3f_s;
typedef struct vx_mat4f vx_mat4f_s;
struct vx_vec2f
{
float x;
float y;
};
struct vx_vec3f
{
float x;
float y;
float z;
};
struct vx_vec4f
{
float x;
float y;
float z;
float w;
};
struct vx_mat2f
{
float val[4];
};
struct vx_mat3f
{
float val[9];
};
struct vx_mat4f
{
float val[16];
};
vx_vec3f_s vx_vec3f_negative(vx_vec3f_s vector);
vx_mat2f_s vx_mat2f_identity();
vx_mat3f_s vx_mat3f_identity();
vx_mat4f_s vx_mat4f_identity();
vx_mat4f_s vx_mat4f_translate(
vx_mat4f_s matrix,
vx_vec3f_s translation
);
vx_mat4f_s vx_mat4f_rotate_x(
vx_mat4f_s matrix,
float rotation
);
vx_mat4f_s vx_mat4f_rotate_y(
vx_mat4f_s matrix,
float rotation
);
vx_mat4f_s vx_mat4f_rotate_z(
vx_mat4f_s matrix,
float rotation
);
vx_mat4f_s vx_mat4f_scale(
vx_mat4f_s matrix,
vx_vec3f_s scaling
);
vx_mat4f_s vx_mat4f_perspective(
float aspect_ratio,
float fov,
float near_plane,
float far_plane
);
void vx_mat4f_stringify(FILE *file, vx_mat4f_s matrix);
uint64_t vx_ceil_to(uint64_t base, uint64_t anchor);
uint64_t vx_ceil_pow2(uint64_t base);
uint64_t vx_min_u64(uint64_t first, uint64_t second);
uint64_t vx_max_u64(uint64_t first, uint64_t second);
#endif // VOXULA_MATH_H

View File

@ -0,0 +1,38 @@
#ifndef VOXULA_UUID_H
#define VOXULA_UUID_H
#include <stdint.h>
typedef struct vx_uuid_table vx_uuid_table_s;
typedef struct vx_uuid_block vx_uuid_block_s;
typedef struct vx_uuid_entry vx_uuid_entry_s;
typedef uint64_t vx_uuid_d;
struct vx_uuid_entry
{
vx_uuid_d uuid;
};
struct vx_uuid_block
{
/// @brief Start of the block's UUIDs;
/// this must be multiplied with 4096
/// to get the first ID's number.
uint32_t offset;
uint8_t num_ids;
vx_uuid_entry_s entries[256];
};
struct vx_uuid_table
{
uint32_t block_capacity;
uint32_t num_blocks;
vx_uuid_block_s **blocks;
};
vx_uuid_table_s * vx_new_uuid_table();
vx_uuid_d vx_new_uuid(vx_uuid_table_s *table);
#endif // VOXULA_UUID_H

View File

@ -0,0 +1,57 @@
#include <voxula/internals/utility/allocation.h>
#include <voxula/internals/utility/math.h>
#include <voxula/internals/utility/containers.h>
#include <stdlib.h>
#include <string.h>
vx_arena_s * vx_new_arena(uint32_t capacity)
{
vx_arena_s *arena = malloc(vx_ceil_to(sizeof(vx_arena_s), 32) + capacity);
arena->usage = 0;
arena->capacity = capacity;
arena->allocation = (void *) ((int8_t *) arena) + 32;
arena->continuation = NULL;
return arena;
}
void vx_free_arena(vx_arena_s *arena)
{
if(arena->continuation)
{
vx_free_arena(arena->continuation);
}
free(arena);
}
void * vx_arena_alloc(vx_arena_s *arena, uint32_t length)
{
if((arena->usage + length) >= arena->capacity)
{
if( ! arena->continuation)
{
arena->continuation = vx_new_arena(vx_max_u64(arena->capacity * 2, length * 2));
}
return vx_arena_alloc(arena->continuation, length);
}
void *allocation = (uint8_t *) arena->allocation + arena->usage;
arena->usage += length;
return allocation;
}
char * vx_arena_dupe_string(vx_arena_s *arena, const char *string)
{
uint32_t len_string = strlen(string);
char *string_duplicate = vx_arena_alloc(arena, len_string + 1);
memcpy(string_duplicate, string, len_string);
return string_duplicate;
}
char * vx_arena_dupe_string_up_to(vx_arena_s *arena, const char *string, uint32_t maximum)
{
uint32_t length = vx_measure_string_up_to(string, maximum);
char *string_duplicate = vx_arena_alloc(arena, length + 1);
memcpy(string_duplicate, string, length);
string_duplicate[length] = 0;
return string_duplicate;
}

View File

@ -0,0 +1,71 @@
#include <voxula/internals/utility/allocation.h>
#include <voxula/internals/utility/math.h>
#include <stdlib.h>
void vx_reset_pool_allocation(vx_pool_s *pool, uint32_t slot_size)
{
uint32_t slot_index = 0;
while(slot_index > pool->capacity)
{
vx_pool_slot_header_s *header =
pool->allocation + slot_index * slot_size;
header->next =
(void *) ((uint8_t *) pool->allocation
+ (slot_index + 1) * slot_size);
header->pool = pool;
++slot_index;
}
vx_pool_slot_header_s *last_header = (void *)
((uint8_t *) pool->allocation + slot_size * (pool->capacity - 1));
last_header->next = NULL;
}
vx_pool_s * vx_new_pool(uint32_t unit_size, uint32_t capacity)
{
uint32_t len_header = vx_ceil_to(sizeof(vx_pool_slot_header_s), 16);
uint32_t slot_size = vx_ceil_to(unit_size + len_header, 16);
vx_pool_s *pool = malloc(64 + (slot_size * capacity));
pool->allocation = (void *) vx_ceil_to((uint64_t) pool + 32, (uint64_t) 32);
pool->first_free = pool->allocation;
pool->unit_size = unit_size;
pool->capacity = capacity;
vx_reset_pool_allocation(pool, slot_size);
return pool;
}
void vx_free_pool(vx_pool_s *pool)
{
if(pool->continuation)
{
vx_free_pool(pool->continuation);
}
free(pool);
}
void * vx_pool(vx_pool_s *pool)
{
vx_pool_slot_header_s *item = pool->first_free;
if( ! item)
{
if( ! pool->continuation)
{
pool->continuation = vx_new_pool(pool->unit_size, pool->capacity * 2);
}
return vx_pool(pool->allocation);
}
pool->first_free = item->next;
return item + vx_ceil_to(sizeof(vx_pool_slot_header_s), 16);
}
void vx_unpool(void *allocation)
{
vx_pool_slot_header_s *slot_header =
allocation
- vx_ceil_to(sizeof(vx_pool_slot_header_s), 16);
slot_header->next = slot_header->pool->first_free;
slot_header->pool->first_free = slot_header;
}

View File

@ -0,0 +1,15 @@
#include <voxula/internals/utility/containers.h>
uint32_t vx_measure_string_up_to(const char *string, uint32_t maximum)
{
uint32_t index = 0;
while(string[index] != 0)
{
if(index > maximum)
{
break;
}
++index;
}
return index;
}

View File

@ -0,0 +1,54 @@
#include <voxula/internals/utility/math.h>
uint64_t vx_min_u64(uint64_t first, uint64_t second)
{
if(first < second)
{
return first;
}
return second;
}
uint64_t vx_max_u64(uint64_t first, uint64_t second)
{
if(first > second)
{
return first;
}
return second;
}
uint64_t vx_ceil_to(uint64_t base, uint64_t anchor)
{
return base - (base % anchor) + anchor;
}
uint64_t vx_ceil_pow2(uint64_t base)
{
// This function relies on the fact that a
// single set bit is always a power of two.
//
// If the single set bit is the only one that
// is in a number, the number itself is returned.
//
// If there are other bits, the next highest
// power of two is created by returning the
// highest set bit after it was moved one to
// the left.
// Get the most significant bit that is set.
uint64_t highest_set_bit = (uint64_t) 1 << 63;
while(highest_set_bit > 0)
{
if(base & highest_set_bit)
{
break;
}
highest_set_bit >>= 1;
}
if(base == highest_set_bit)
{
return base;
}
return vx_max_u64(highest_set_bit << 1, 1);
}

View File

@ -0,0 +1,188 @@
#include <voxula/internals/utility/math.h>
#include <math.h>
vx_mat2f_s vx_mat2f_identity()
{
vx_mat2f_s matrix;
matrix.val[0] = 1.0f;
matrix.val[1] = 0.0f;
matrix.val[2] = 0.0f;
matrix.val[3] = 1.0f;
return matrix;
}
vx_mat3f_s vx_mat3f_identity()
{
vx_mat3f_s matrix;
matrix.val[0] = 1.0f;
matrix.val[1] = 0.0f;
matrix.val[2] = 0.0f;
matrix.val[3] = 0.0f;
matrix.val[4] = 1.0f;
matrix.val[5] = 0.0f;
matrix.val[6] = 0.0f;
matrix.val[7] = 0.0f;
matrix.val[8] = 1.0f;
return matrix;
}
vx_mat4f_s vx_mat4f_identity()
{
vx_mat4f_s matrix;
matrix.val[0] = 1.0f;
matrix.val[1] = 0.0f;
matrix.val[2] = 0.0f;
matrix.val[3] = 0.0f;
matrix.val[4] = 0.0f;
matrix.val[5] = 1.0f;
matrix.val[6] = 0.0f;
matrix.val[7] = 0.0f;
matrix.val[8] = 0.0f;
matrix.val[9] = 0.0f;
matrix.val[10] = 1.0f;
matrix.val[11] = 0.0f;
matrix.val[12] = 0.0f;
matrix.val[13] = 0.0f;
matrix.val[14] = 0.0f;
matrix.val[15] = 1.0f;
return matrix;
}
vx_mat4f_s vx_mat4f_translate(
vx_mat4f_s matrix,
vx_vec3f_s translation
) {
matrix.val[12] += translation.x;
matrix.val[13] += translation.y;
matrix.val[14] += translation.z;
return matrix;
}
vx_mat4f_s vx_mat4f_multiply(
vx_mat4f_s first,
vx_mat4f_s second
) {
vx_mat4f_s result;
uint8_t x_index = 0;
uint8_t y_index = 0;
uint8_t level = 0;
while(x_index < 4)
{
y_index = 0;
while(y_index < 4)
{
result.val[y_index * 4 + x_index] = 0.0f;
level = 0;
while(level < 4)
{
result.val[y_index * 4 + x_index] +=
first.val[level * 4 + x_index]
* second.val[y_index * 4 + level];
++level;
}
++y_index;
}
++x_index;
}
return result;
}
vx_mat4f_s vx_mat4f_rotate_x(
vx_mat4f_s matrix,
float rotation
) {
float cosine = cos(rotation);
float sine = sin(rotation);
vx_mat4f_s rotation_matrix;
rotation_matrix.val[0] = 1.0f;
rotation_matrix.val[5] = cosine;
rotation_matrix.val[6] = -sine;
rotation_matrix.val[9] = sine;
rotation_matrix.val[10] = cosine;
rotation_matrix.val[15] = 1.0f;
vx_mat4f_multiply(matrix, rotation_matrix);
return rotation_matrix;
}
vx_mat4f_s vx_mat4f_rotate_y(
vx_mat4f_s matrix,
float rotation
) {
float cosine = cos(rotation);
float sine = sin(rotation);
vx_mat4f_s rotation_matrix;
rotation_matrix.val[0] = cosine;
rotation_matrix.val[2] = sine;
rotation_matrix.val[5] = 1.0f;
rotation_matrix.val[8] = -sine;
rotation_matrix.val[10] = cosine;
rotation_matrix.val[15] = 1.0f;
vx_mat4f_multiply(matrix, rotation_matrix);
return rotation_matrix;
}
vx_mat4f_s vx_mat4f_rotate_z(
vx_mat4f_s matrix,
float rotation
) {
float cosine = cos(rotation);
float sine = sin(rotation);
vx_mat4f_s rotation_matrix;
rotation_matrix.val[0] = cosine;
rotation_matrix.val[1] = -sine;
rotation_matrix.val[4] = sine;
rotation_matrix.val[5] = cosine;
rotation_matrix.val[10] = 1.0f;
vx_mat4f_multiply(matrix, rotation_matrix);
return rotation_matrix;
}
vx_mat4f_s vx_mat4f_scale(
vx_mat4f_s matrix,
vx_vec3f_s scaling
) {
matrix.val[0] *= scaling.x;
matrix.val[5] *= scaling.y;
matrix.val[10] *= scaling.z;
return matrix;
}
vx_mat4f_s vx_mat4f_perspective(
float aspect_ratio,
float fov,
float near_plane,
float far_plane
) {
float plane_range = tanf(fov / 2.0f) * near_plane;
float scale_x = (2.0f * near_plane) / (plane_range * aspect_ratio * 2.0f);
float scale_y = near_plane / plane_range;
float scale_z = (far_plane + near_plane) / (far_plane - near_plane);
float position_z = (2.0f * far_plane * near_plane) / (far_plane - near_plane);
vx_mat4f_s matrix;
matrix.val[0] = scale_x;
matrix.val[1] = 0.0f;
matrix.val[2] = 0.0f;
matrix.val[3] = 0.0f;
matrix.val[4] = 0.0f;
matrix.val[5] = scale_y;
matrix.val[6] = 0.0f;
matrix.val[7] = 0.0f;
matrix.val[8] = 0.0f;
matrix.val[9] = 0.0f;
matrix.val[10] = scale_z;
matrix.val[11] = - 1.0f;
matrix.val[12] = 0.0f;
matrix.val[13] = 0.0f;
matrix.val[14] = position_z;
matrix.val[15] = 0.0f;
return matrix;
}
void vx_mat4f_stringify(FILE *file, vx_mat4f_s matrix)
{
fprintf(file, "ROW 1: %f %f %f %f\n", matrix.val[0], matrix.val[1], matrix.val[2], matrix.val[3]);
fprintf(file, "ROW 2: %f %f %f %f\n", matrix.val[4], matrix.val[5], matrix.val[6], matrix.val[7]);
fprintf(file, "ROW 3: %f %f %f %f\n", matrix.val[8], matrix.val[9], matrix.val[10], matrix.val[11]);
fprintf(file, "ROW 4: %f %f %f %f\n", matrix.val[12], matrix.val[13], matrix.val[14], matrix.val[15]);
}

View File

@ -0,0 +1,9 @@
#include <voxula/internals/utility/math.h>
vx_vec3f_s vx_vec3f_negative(vx_vec3f_s vector) {
vx_vec3f_s result;
result.x = - vector.x;
result.y = - vector.y;
result.z = - vector.z;
return result;
}

View File

@ -0,0 +1,97 @@
#include <voxula/internals/utility/uuid.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdlib.h>
vx_uuid_table_s * vx_new_uuid_table()
{
vx_uuid_table_s *table = malloc(sizeof(vx_uuid_table_s));
table->num_blocks = 0;
table->block_capacity = 32;
table->blocks = malloc(table->block_capacity * sizeof(vx_uuid_block_s *));
return table;
}
bool vx_uuid_block_exists(vx_uuid_table_s *table, uint32_t offset)
{
uint32_t block_index = 0;
while(block_index < table->num_blocks)
{
if(table->blocks[block_index]->offset == offset)
{
return true;
}
++block_index;
}
return false;
}
bool vx_uuid_exists_in_block(vx_uuid_block_s *block, vx_uuid_d uuid)
{
uint32_t entry_index = 0;
while(entry_index < block->num_ids)
{
if(block->entries[entry_index].uuid == uuid)
{
return true;
}
++entry_index;
}
return false;
}
vx_uuid_d vx_allocate_uuid_in_block(vx_uuid_block_s *block)
{
vx_uuid_d last_id = 0;
if(block->num_ids)
{
last_id = block->entries[block->num_ids - 1].uuid;
}
vx_uuid_d uuid =
block->offset * 4096
+ last_id * 53;
block->entries[block->num_ids].uuid = uuid;
++block->num_ids;
while(vx_uuid_exists_in_block(block, uuid))
{
++uuid;
}
return uuid;
}
vx_uuid_block_s * vx_allocate_new_id_block(vx_uuid_table_s *table)
{
vx_uuid_block_s *block = NULL;
if(table->num_blocks >= table->block_capacity)
{
table->block_capacity *= 2;
table->blocks = malloc(table->block_capacity * sizeof(vx_uuid_block_s *));
}
table->blocks[table->num_blocks] = malloc(sizeof(vx_uuid_block_s));
block = table->blocks[table->num_blocks];
block->num_ids = 0;
block->offset = (table->num_blocks * 7) * 4096;
++table->num_blocks;
return block;
}
vx_uuid_d vx_new_uuid(vx_uuid_table_s *table)
{
vx_uuid_block_s *block = NULL;
uint32_t block_index = 0;
while(block_index < table->num_blocks)
{
if(table->blocks[block_index]->num_ids != 255)
{
block = table->blocks[block_index];
break;
}
++block_index;
}
if( ! block)
{
block = vx_allocate_new_id_block(table);
}
return vx_allocate_uuid_in_block(block);
}