refactor utility/platform files into one header, packer/codegen compiling but packer is broken
This commit is contained in:
parent
2054fad364
commit
0b9f802451
20
build.sh
20
build.sh
@ -35,6 +35,12 @@ packer_include_flags="-I../src/ -I../external/"
|
||||
packer_out_name="Packer"
|
||||
packer_flags="-DBUILD_PACKER"
|
||||
|
||||
# codegen
|
||||
codegen_source_files="../src/codegen.c"
|
||||
codegen_include_flags="-I../src/ -I../external/"
|
||||
codegen_out_name="Codegen"
|
||||
codegen_flags="-DBUILD_CODEGEN"
|
||||
|
||||
# glslc
|
||||
glsl_compile="glslc"
|
||||
glsl_flags="--target-spv=spv1.6 -std=460"
|
||||
@ -113,17 +119,17 @@ if ! [ -f libvma.a ]; then
|
||||
fi
|
||||
|
||||
# Packer Codegen
|
||||
$compile $packer_source_files $compile_link $link_os_gfx $packer_flags -DBUILD_ASSET_CODEGEN $packer_include_flags $out PackerCodegen
|
||||
$compile $codegen_source_files $compile_link $link_os_gfx $codegen_flags $packer_include_flags $out $codegen_out_name
|
||||
|
||||
# Packer
|
||||
if [ -v packer ] || ! [ -f Packer ]; then
|
||||
$compile $packer_source_files $compile_link $link_os_gfx $packer_flags $packer_include_flags $out $packer_out_name
|
||||
fi
|
||||
|
||||
if [ -v pack ] || ! [ -f assets.sgp ]; then
|
||||
./Packer
|
||||
fi
|
||||
#if [ -v pack ] || ! [ -f assets.sgp ]; then
|
||||
# ./Packer
|
||||
#fi
|
||||
|
||||
if ! [ -v packer ]; then
|
||||
$compile $source_files $compile_link $link_os_gfx $out $out_name
|
||||
fi
|
||||
#if ! [ -v packer ]; then
|
||||
# $compile $source_files $compile_link $link_os_gfx $out $out_name
|
||||
#fi
|
||||
|
||||
618
src/allocators.c
618
src/allocators.c
@ -1,618 +0,0 @@
|
||||
// ::Allocator::Globals::
|
||||
|
||||
FLAlloc
|
||||
FL_ALLOC = {0};
|
||||
Allocator
|
||||
ALLOC = {0};
|
||||
read_only FLNode
|
||||
FL_NIL_NODE = {0};
|
||||
read_only FreeList
|
||||
FL_NIL_LIST = {0};
|
||||
|
||||
constexpr usize
|
||||
FL_GLOBAL_SIZE = MB(32);
|
||||
static b32
|
||||
FL_GLOBAL_INIT = false;
|
||||
|
||||
// ::Allocator::Util::Header::
|
||||
|
||||
static inline usize
|
||||
CalcPaddingWithHeader(uintptr ptr, uintptr alignment, usize header_size)
|
||||
{
|
||||
Assert(IsPow2(alignment), "Alignment provided to CalcPaddingWithHeader is not a power of two");
|
||||
|
||||
uintptr padding = CalcPadding(ptr, alignment);
|
||||
uintptr needed_space = (uintptr)header_size;
|
||||
|
||||
if (padding < needed_space)
|
||||
{
|
||||
needed_space -= padding;
|
||||
|
||||
if ((needed_space & (alignment-1)) != 0)
|
||||
padding += alignment * (1 + (needed_space/alignment));
|
||||
else
|
||||
padding += alignment * (needed_space/alignment);
|
||||
}
|
||||
|
||||
return (usize)padding;
|
||||
}
|
||||
|
||||
static inline usize
|
||||
CalcPadding(uintptr ptr, uintptr alignment)
|
||||
{
|
||||
Assert(IsPow2(alignment), "CalcPadding failure: IsPow2 failed");
|
||||
|
||||
uintptr padding = 0;
|
||||
uintptr modulo = ptr & (alignment-1);
|
||||
if (modulo != 0)
|
||||
padding = alignment - modulo;
|
||||
|
||||
return (usize)padding;
|
||||
}
|
||||
|
||||
// ::Allocator::Arena::Start::
|
||||
|
||||
static Arena *
|
||||
ArenaInit(rawptr buffer, usize size)
|
||||
{
|
||||
Arena *arena = (Arena *)buffer;
|
||||
buffer = PtrAdd(buffer, ARENA_HEADER_SIZE);
|
||||
|
||||
arena->buffer = buffer;
|
||||
arena->length = size;
|
||||
arena->pos = 0;
|
||||
|
||||
return arena;
|
||||
}
|
||||
|
||||
static Arena *
|
||||
ArenaCreate(usize size)
|
||||
{
|
||||
u8 *mem = pMemAllocZeroed(size);
|
||||
return ArenaInit(mem, size);
|
||||
}
|
||||
|
||||
static Arena *
|
||||
ArenaCreateDebug(usize size, u32 init_line_no)
|
||||
{
|
||||
u8 *mem = pMemAllocZeroed(size);
|
||||
return ArenaInitDebug(mem, size, init_line_no);
|
||||
}
|
||||
|
||||
// TODO: investigate overflows when out of memory because something bad is going on
|
||||
static rawptr
|
||||
ArenaAllocAlign(Arena *arena, usize size, usize align)
|
||||
{
|
||||
rawptr ptr = NULL;
|
||||
|
||||
uintptr curr_ptr = (uintptr)arena->buffer + (uintptr)arena->pos;
|
||||
uintptr offset = AlignPow2(curr_ptr, align);
|
||||
offset -= (uintptr)arena->buffer;
|
||||
|
||||
if (offset+size <= arena->length)
|
||||
{
|
||||
ptr = &arena->buffer[offset];
|
||||
arena->pos = offset+size;
|
||||
}
|
||||
else
|
||||
{
|
||||
Printfln("Out of memory: %d", arena->init_line_no);
|
||||
Assert(0, "Memory Failure");
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static rawptr
|
||||
ArenaAlloc(Arena *arena, usize size)
|
||||
{
|
||||
return ArenaAllocAlign(arena, size, DEFAULT_ALIGNMENT);
|
||||
}
|
||||
|
||||
static void
|
||||
ArenaFree(Arena *arena)
|
||||
{
|
||||
arena->pos = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
ArenaFreeZeroed(Arena *arena)
|
||||
{
|
||||
MemZero(arena->buffer, arena->pos);
|
||||
ArenaFree(arena);
|
||||
}
|
||||
|
||||
static void
|
||||
DeallocArena(Arena *arena)
|
||||
{
|
||||
pMemFree(arena, arena->length);
|
||||
}
|
||||
|
||||
static Arena *
|
||||
ArenaInitDebug(rawptr buffer, usize size, u32 init_line_no)
|
||||
{
|
||||
Arena *arena = ArenaInit(buffer, size);
|
||||
arena->init_line_no = init_line_no;
|
||||
return arena;
|
||||
}
|
||||
|
||||
// ::Allocator::Arena::End::
|
||||
|
||||
|
||||
|
||||
// ::Allocator::GlobalAlloc::Start::
|
||||
|
||||
static void
|
||||
InitAllocator(usize init_size)
|
||||
{
|
||||
ALLOC.grow_size = init_size;
|
||||
ALLOC.buffer = pMemAllocZeroed(init_size);
|
||||
ALLOC.size = init_size;
|
||||
ALLOC.free_size = init_size;
|
||||
|
||||
ALLOC.hash_table = FLMemAlloc(sizeof(HashTable));
|
||||
HashTableInit(ALLOC.hash_table, 32);
|
||||
|
||||
ALLOC.tree = FLMemAlloc(sizeof(RBTree));
|
||||
RBTreeInit(ALLOC.tree);
|
||||
|
||||
RBTreeInsert(ALLOC.tree, init_size, ALLOC.buffer);
|
||||
}
|
||||
|
||||
static void
|
||||
DeinitAlloc()
|
||||
{
|
||||
pMemFree(ALLOC.buffer, ALLOC.size);
|
||||
}
|
||||
|
||||
static rawptr
|
||||
Alloc(usize size)
|
||||
{
|
||||
return AllocAlign(size, DEFAULT_ALIGNMENT);
|
||||
}
|
||||
|
||||
static rawptr
|
||||
AllocAlign(usize size, usize alignment)
|
||||
{
|
||||
if (size == 0) return NULL;
|
||||
|
||||
RBNode *node = P_RB_NIL;
|
||||
rawptr mem = NULL;
|
||||
if (!RBTreeSearchNearest(ALLOC.tree, size + alignment, &node))
|
||||
{
|
||||
AllocGrow(size);
|
||||
RBTreeSearchNearest(ALLOC.tree, size + alignment, &node);
|
||||
}
|
||||
|
||||
u64 alloc_size = node->key;
|
||||
rawptr free_alloc = node->bucket.last->data;
|
||||
RBTreeDelete(ALLOC.tree, alloc_size, free_alloc);
|
||||
|
||||
usize padding = CalcPadding(uintptr(free_alloc), alignment);
|
||||
uintptr new_addr = uintptr(free_alloc) + size + padding;
|
||||
RBTreeInsert(ALLOC.tree, alloc_size - size - padding, rawptr(new_addr));
|
||||
|
||||
HashTablePushRawptrU64(ALLOC.hash_table, free_alloc, size + padding);
|
||||
|
||||
return free_alloc;
|
||||
}
|
||||
|
||||
// TODO: finish allocator
|
||||
// need an idea
|
||||
static void
|
||||
Free(rawptr ptr)
|
||||
{
|
||||
if (ptr == NULL) return;
|
||||
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
AllocGrow(usize size)
|
||||
{
|
||||
usize grow_size = size < ALLOC.grow_size ? ALLOC.grow_size : ALLOC.grow_size + size;
|
||||
pMemRealloc(ALLOC.buffer, ALLOC.size, ALLOC.size + grow_size);
|
||||
|
||||
RBTreeInsert(ALLOC.tree, grow_size, ALLOC.buffer + ALLOC.size); // TODO: check this if things fuck up it could be wrong
|
||||
|
||||
ALLOC.size += grow_size;
|
||||
ALLOC.free_size += grow_size;
|
||||
}
|
||||
|
||||
// ::Allocator::GlobalAlloc::End::
|
||||
|
||||
|
||||
|
||||
// ::Allocator::FreeList::Start::
|
||||
|
||||
static void
|
||||
GlobalFreeListInit(usize size)
|
||||
{
|
||||
FreeListInit(&FL_ALLOC, size);
|
||||
FL_GLOBAL_INIT = true;
|
||||
}
|
||||
|
||||
static rawptr
|
||||
FLMemAlloc(usize size)
|
||||
{
|
||||
if (!FL_GLOBAL_INIT)
|
||||
{
|
||||
GlobalFreeListInit(FL_GLOBAL_SIZE);
|
||||
}
|
||||
|
||||
return FreeListAlloc(&FL_ALLOC, size);
|
||||
}
|
||||
|
||||
static rawptr
|
||||
FLMemAllocZeroed(usize size)
|
||||
{
|
||||
rawptr ptr = FLMemAlloc(size);
|
||||
MemZero(ptr, size);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static rawptr
|
||||
FLMemRealloc(rawptr old_ptr, usize size)
|
||||
{
|
||||
if (!FL_GLOBAL_INIT)
|
||||
{
|
||||
GlobalFreeListInit(FL_GLOBAL_SIZE);
|
||||
}
|
||||
|
||||
rawptr ptr = NULL;
|
||||
if (old_ptr == NULL)
|
||||
ptr = FLMemAlloc(size);
|
||||
else
|
||||
ptr = FreeListRealloc(&FL_ALLOC, old_ptr, size);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static void
|
||||
FLMemFree(rawptr ptr)
|
||||
{
|
||||
if (!FL_GLOBAL_INIT)
|
||||
{
|
||||
GlobalFreeListInit(FL_GLOBAL_SIZE);
|
||||
}
|
||||
|
||||
FreeListFree(&FL_ALLOC, ptr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Should be async safe given no other thread frees a pointer in the middle of a realloc
|
||||
*/
|
||||
static rawptr
|
||||
FreeListRealloc(FLAlloc *alloc, rawptr old_ptr, usize size)
|
||||
{
|
||||
rawptr ptr = FreeListAlloc(alloc, size);
|
||||
usize old_size = FreeListPtrSize(alloc, old_ptr);
|
||||
|
||||
MemCpy(ptr, old_ptr, old_size);
|
||||
|
||||
FreeListFree(alloc, old_ptr);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static usize
|
||||
FreeListPtrSize(FLAlloc *alloc, rawptr ptr)
|
||||
{
|
||||
if (ptr == NULL) return 0;
|
||||
|
||||
usize size = 0;
|
||||
|
||||
TicketMutLock(&alloc->mut);
|
||||
|
||||
FreeList *list = _FreeListFindList(alloc, ptr);
|
||||
if (list != NULL)
|
||||
{
|
||||
FLAllocHeader *header = cast(FLAllocHeader *, u8ptr(ptr) - sizeof(FLAllocHeader));
|
||||
size = header->size + header->padding;
|
||||
}
|
||||
|
||||
TicketMutUnlock(&alloc->mut);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static void
|
||||
FreeListInit(FLAlloc *alloc, usize size)
|
||||
{
|
||||
alloc->list_head = pMemAllocZeroed(sizeof(FreeList));
|
||||
alloc->nil = &FL_NIL_NODE;
|
||||
alloc->grow_size = size;
|
||||
|
||||
_FreeListInit(&alloc->list_head, size);
|
||||
|
||||
FreeListFreeAll(alloc);
|
||||
}
|
||||
|
||||
static void
|
||||
_FreeListInit(FreeList **alloc, usize size)
|
||||
{
|
||||
*alloc = (FreeList *)pMemAllocZeroed(size);
|
||||
(*alloc)->data = (rawptr)(((uintptr)*alloc) + ((uintptr)sizeof(FreeList)));
|
||||
(*alloc)->size = size;
|
||||
(*alloc)->used = sizeof(FreeList);
|
||||
(*alloc)->next = &FL_NIL_LIST;
|
||||
}
|
||||
|
||||
static void
|
||||
FreeListFreeAll(FLAlloc *alloc)
|
||||
{
|
||||
TicketMutLock(&alloc->mut);
|
||||
|
||||
FreeList *current = alloc->list_head->next;
|
||||
FreeList *next = &FL_NIL_LIST;
|
||||
while (current != &FL_NIL_LIST)
|
||||
{
|
||||
next = current->next;
|
||||
pMemFree(current, current->size);
|
||||
current = next;
|
||||
}
|
||||
|
||||
current = alloc->list_head;
|
||||
|
||||
FLNode *node = (FLNode *)current->data;
|
||||
node->size = current->size;
|
||||
node->next = &FL_NIL_NODE;
|
||||
|
||||
current->head = node;
|
||||
current->used = sizeof(FreeList);
|
||||
|
||||
TicketMutUnlock(&alloc->mut);
|
||||
}
|
||||
|
||||
static FLNode *
|
||||
FreeListSearch(FreeList *alloc, usize size, usize alignment, usize *out_padding, FLNode **prev_node)
|
||||
{
|
||||
FLNode *node = alloc->head;
|
||||
FLNode *prev = &FL_NIL_NODE;
|
||||
|
||||
usize padding = 0;
|
||||
|
||||
while (node != &FL_NIL_NODE)
|
||||
{
|
||||
padding = CalcPaddingWithHeader((uintptr)node, (uintptr)alignment, sizeof(FLNode));
|
||||
usize required_size = size + padding;
|
||||
if (node->size >= required_size)
|
||||
break;
|
||||
|
||||
prev = node;
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
if (out_padding)
|
||||
*out_padding = padding;
|
||||
|
||||
if (prev_node)
|
||||
*prev_node = prev;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/*
|
||||
* NOT SAFE TO CALL OUTSIDE OF FreeListAlloc
|
||||
*/
|
||||
static FreeList *
|
||||
FreeListGrow(FLAlloc *alloc, usize alloc_size)
|
||||
{
|
||||
usize grow_size = alloc->grow_size;
|
||||
if (alloc_size > grow_size)
|
||||
grow_size += alloc_size;
|
||||
|
||||
FreeList *list = NULL;
|
||||
|
||||
_FreeListInit(&list, grow_size);
|
||||
|
||||
FLNode *node = (FLNode *)list->data;
|
||||
node->size = list->size;
|
||||
node->next = alloc->nil;
|
||||
|
||||
list->head = node;
|
||||
|
||||
FreeList *current = alloc->list_head;
|
||||
while (current != &FL_NIL_LIST)
|
||||
{
|
||||
if (current->next == &FL_NIL_LIST)
|
||||
{
|
||||
current->next = list;
|
||||
break;
|
||||
}
|
||||
|
||||
current = current->next;
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
static rawptr
|
||||
_FreeListAllocAlign(FreeList *alloc, usize size, usize alignment)
|
||||
{
|
||||
if (size == 0) return NULL;
|
||||
|
||||
usize padding = 0;
|
||||
FLNode *prev_node = &FL_NIL_NODE;
|
||||
|
||||
FLAllocHeader *header;
|
||||
|
||||
if (size < sizeof(FLNode))
|
||||
size = sizeof(FLNode);
|
||||
|
||||
if (alignment < 8)
|
||||
alignment = 8;
|
||||
|
||||
FLNode *node = FreeListSearch(alloc, size, alignment, &padding, &prev_node);
|
||||
|
||||
if (node == &FL_NIL_NODE)
|
||||
Assert(0, "FreeListAllocAlign failed to allocate, oom");
|
||||
|
||||
usize alignment_padding = padding - sizeof(FLAllocHeader);
|
||||
usize required_space = size + padding;
|
||||
usize remaining = node->size - required_space;
|
||||
|
||||
if (remaining > 0)
|
||||
{
|
||||
FLNode *new_node = (FLNode *)(((c8 *)node) + required_space);
|
||||
new_node->size = remaining;
|
||||
FreeListInsert(&alloc->head, node, new_node);
|
||||
}
|
||||
|
||||
FreeListRemove(&alloc->head, prev_node, node);
|
||||
|
||||
header = (FLAllocHeader *)(((c8 *)node) + alignment_padding);
|
||||
header->size = required_space;
|
||||
header->padding = alignment_padding;
|
||||
|
||||
alloc->used += required_space;
|
||||
|
||||
return (rawptr)(((c8 *)header) + sizeof(FLAllocHeader));
|
||||
}
|
||||
|
||||
static rawptr
|
||||
FreeListAlloc(FLAlloc *alloc, usize size)
|
||||
{
|
||||
return FreeListAllocAlign(alloc, size, DEFAULT_ALIGNMENT);
|
||||
}
|
||||
|
||||
static rawptr
|
||||
FreeListAllocAlign(FLAlloc *alloc, usize size, usize alignment)
|
||||
{
|
||||
TicketMutLock(&alloc->mut);
|
||||
|
||||
FreeList *fl = &FL_NIL_LIST;
|
||||
FreeList *current = alloc->list_head;
|
||||
while (current != &FL_NIL_LIST)
|
||||
{
|
||||
usize remaining = current->size - current->used;
|
||||
if (size < remaining)
|
||||
{
|
||||
fl = current;
|
||||
break;
|
||||
}
|
||||
|
||||
current = current->next;
|
||||
}
|
||||
|
||||
if (fl == &FL_NIL_LIST)
|
||||
{
|
||||
fl = FreeListGrow(alloc, size);
|
||||
}
|
||||
|
||||
rawptr ptr = _FreeListAllocAlign(fl, size, alignment);
|
||||
|
||||
TicketMutUnlock(&alloc->mut);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static FreeList *
|
||||
_FreeListFindList(FLAlloc *alloc, rawptr ptr)
|
||||
{
|
||||
FreeList *list = NULL;
|
||||
FreeList *current = alloc->list_head;
|
||||
while (current != &FL_NIL_LIST)
|
||||
{
|
||||
uintptr ptr_addr = uintptr(ptr);
|
||||
uintptr start = uintptr(current->data);
|
||||
uintptr end = uintptr(current->data) + uintptr(current->size);
|
||||
if (ptr_addr >= start && ptr_addr < end)
|
||||
{
|
||||
list = current;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
static void
|
||||
_FreeListFree(FreeList *alloc, rawptr ptr)
|
||||
{
|
||||
FLAllocHeader *header = cast(FLAllocHeader *, u8ptr(ptr) - sizeof(FLAllocHeader));
|
||||
FLNode *free_node = cast(FLNode *,header);
|
||||
free_node->size = header->size + header->padding;
|
||||
free_node->next = &FL_NIL_NODE;
|
||||
|
||||
FLNode *prev_node = &FL_NIL_NODE;
|
||||
FLNode *node = alloc->head;
|
||||
while (node != &FL_NIL_NODE)
|
||||
{
|
||||
if (ptr < node)
|
||||
{
|
||||
FreeListInsert(&alloc->head, prev_node, free_node);
|
||||
break;
|
||||
}
|
||||
|
||||
prev_node = node;
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
alloc->used -= free_node->size;
|
||||
|
||||
FreeListCoalescence(alloc, prev_node, free_node);
|
||||
}
|
||||
|
||||
static void
|
||||
FreeListFree(FLAlloc *alloc, rawptr ptr)
|
||||
{
|
||||
if (ptr == NULL) return;
|
||||
|
||||
TicketMutLock(&alloc->mut);
|
||||
|
||||
FreeList *list = _FreeListFindList(alloc, ptr);
|
||||
if (list != NULL)
|
||||
{
|
||||
_FreeListFree(list, ptr);
|
||||
}
|
||||
|
||||
TicketMutUnlock(&alloc->mut);
|
||||
}
|
||||
|
||||
static void
|
||||
FreeListCoalescence(FreeList *alloc, FLNode *prev_node, FLNode *free_node)
|
||||
{
|
||||
if (free_node->next != &FL_NIL_NODE && (rawptr)(((c8 *)free_node) + free_node->size) == free_node->next)
|
||||
{
|
||||
free_node->size += free_node->next->size;
|
||||
FreeListRemove(&alloc->head, free_node, free_node->next);
|
||||
}
|
||||
|
||||
if (prev_node->next != &FL_NIL_NODE && (rawptr)(((c8 *)prev_node) + prev_node->size) == free_node)
|
||||
{
|
||||
prev_node->size += free_node->next->size;
|
||||
FreeListRemove(&alloc->head, prev_node, free_node);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
FreeListRemove(FLNode **head, FLNode *prev_node, FLNode *del_node)
|
||||
{
|
||||
if (prev_node == &FL_NIL_NODE)
|
||||
*head = del_node->next;
|
||||
else
|
||||
prev_node->next = del_node->next;
|
||||
}
|
||||
|
||||
static void
|
||||
FreeListInsert(FLNode **head, FLNode *prev_node, FLNode *new_node)
|
||||
{
|
||||
if (prev_node == &FL_NIL_NODE)
|
||||
{
|
||||
if (*head != &FL_NIL_NODE)
|
||||
{
|
||||
new_node->next = *head;
|
||||
*head = new_node;
|
||||
}
|
||||
else
|
||||
*head = new_node;
|
||||
}
|
||||
else
|
||||
{
|
||||
new_node->next = prev_node->next;
|
||||
prev_node->next = new_node;
|
||||
}
|
||||
}
|
||||
|
||||
// ::Allocator::FreeList::End::
|
||||
114
src/allocators.h
114
src/allocators.h
@ -1,114 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// ::Allocator::Util::Header::
|
||||
|
||||
static inline usize CalcPaddingWithHeader(uintptr ptr, uintptr alignment, usize header_size);
|
||||
static inline usize CalcPadding(uintptr ptr, uintptr alignment);
|
||||
|
||||
// ::Allocator::Arena::Header::
|
||||
|
||||
#define ARENA_HEADER_SIZE 32
|
||||
|
||||
typedef struct Arena
|
||||
{
|
||||
u8 *buffer;
|
||||
usize length;
|
||||
usize pos;
|
||||
u32 init_line_no;
|
||||
} Arena;
|
||||
|
||||
typedef struct TempArena
|
||||
{
|
||||
Arena *arena;
|
||||
u64 pos;
|
||||
} TempArena;
|
||||
|
||||
static Arena *ArenaInit(rawptr buffer, usize size);
|
||||
static Arena *ArenaCreate(usize size);
|
||||
static Arena *ArenaCreateDebug(usize size, u32 init_line_no);
|
||||
static Arena *ArenaInitDebug(rawptr buffer, usize size, u32 init_line_no);
|
||||
static rawptr ArenaAllocAlign(Arena *arena, usize size, usize align);
|
||||
static rawptr ArenaAlloc(Arena *arena, usize size);
|
||||
static void ArenaFree(Arena *arena);
|
||||
static void ArenaFreeZeroed(Arena *arena);
|
||||
static void DeallocArena(Arena *arena);
|
||||
|
||||
// ::Allocator::GlobalAlloc::Header::
|
||||
|
||||
typedef struct AllocInfo
|
||||
{
|
||||
rawptr ptr;
|
||||
struct AllocInfo *next;
|
||||
} AllocInfo;
|
||||
|
||||
typedef struct Allocator
|
||||
{
|
||||
RBTree *tree;
|
||||
RBTree *used_tree;
|
||||
HashTable *hash_table;
|
||||
rawptr buffer;
|
||||
u64 size;
|
||||
u64 free_size;
|
||||
u64 grow_size;
|
||||
} Allocator;
|
||||
|
||||
static void InitAllocator(usize init_size);
|
||||
static void DeinitAlloc();
|
||||
static void AllocGrow(usize size);
|
||||
static rawptr Alloc(usize size);
|
||||
static rawptr AllocAlign(usize size, usize alignment);
|
||||
static void Free(rawptr ptr);
|
||||
|
||||
// ::Allocator::FreeList::Header::
|
||||
|
||||
typedef struct FLAllocHeader
|
||||
{
|
||||
usize size;
|
||||
usize padding;
|
||||
} FLAllocHeader;
|
||||
|
||||
typedef struct FLNode
|
||||
{
|
||||
struct FLNode *next;
|
||||
usize size;
|
||||
} FLNode;
|
||||
|
||||
typedef struct FreeList
|
||||
{
|
||||
rawptr data;
|
||||
FLNode *head;
|
||||
usize size;
|
||||
usize used;
|
||||
struct FreeList *next;
|
||||
} FreeList;
|
||||
|
||||
typedef struct FLAlloc
|
||||
{
|
||||
FreeList *list_head;
|
||||
TicketMut mut;
|
||||
FLNode *nil;
|
||||
usize grow_size;
|
||||
} FLAlloc;
|
||||
|
||||
static void GlobalFreeListInit(usize size);
|
||||
static rawptr FLMemAlloc(usize size);
|
||||
static rawptr FLMemAllocZeroed(usize size);
|
||||
static rawptr FLMemRealloc(rawptr old_ptr, usize size);
|
||||
static void FLMemFree(rawptr ptr);
|
||||
static usize FreeListPtrSize(FLAlloc *alloc, rawptr ptr);
|
||||
static void FreeListInit(FLAlloc *alloc, usize size);
|
||||
static rawptr FreeListAllocAlign(FLAlloc *alloc, usize size, usize alignment);
|
||||
static rawptr FreeListAlloc(FLAlloc *alloc, usize size);
|
||||
static void FreeListFree(FLAlloc *alloc, rawptr ptr);
|
||||
static void FreeListFreeAll(FLAlloc *alloc);
|
||||
static FreeList *FreeListGrow(FLAlloc *alloc, usize alloc_size);
|
||||
static rawptr FreeListRealloc(FLAlloc *alloc, rawptr old_ptr, usize size);
|
||||
static FLNode *FreeListSearch(FreeList *alloc, usize size, usize alignment, usize *out_padding, FLNode **prev_node);
|
||||
static void FreeListCoalescence(FreeList *alloc, FLNode *prev_node, FLNode *free_node);
|
||||
static void FreeListRemove(FLNode **head, FLNode *prev_node, FLNode *del_node);
|
||||
static void FreeListInsert(FLNode **head, FLNode *prev_node, FLNode *new_node);
|
||||
static FreeList *_FreeListFindList(FLAlloc *alloc, rawptr ptr);
|
||||
static void _FreeListInit(FreeList **alloc, usize size);
|
||||
static rawptr _FreeListAllocAlign(FreeList *alloc, usize size, usize alignment);
|
||||
static void _FreeListFree(FreeList *alloc, rawptr ptr);
|
||||
|
||||
@ -65,11 +65,7 @@ static void apInit()
|
||||
|
||||
Assert(File_Header.magic_num == CreateMagicValue('s', 't', 'e', 'g'), "Magic value is incorrect");
|
||||
|
||||
MemCpy(Texture_Assets, &ASSET_PACK[File_Header.asset_offsets[TEXTURE_ASSET]], sizeof(AssetFile) * File_Header.asset_counts[TEXTURE_ASSET]);
|
||||
|
||||
MemCpy(Shader_Assets, &ASSET_PACK[File_Header.asset_offsets[SHADER_ASSET]], sizeof(AssetFile) * File_Header.asset_counts[SHADER_ASSET]);
|
||||
|
||||
MemCpy(Model_Assets, &ASSET_PACK[File_Header.asset_offsets[MODEL_ASSET]], sizeof(AssetFile) * File_Header.asset_counts[MODEL_ASSET]);
|
||||
MemCpy(Texture_Assets, &ASSET_PACK[File_Header.asset_offset], sizeof(AssetFile) * File_Header.asset_counts);
|
||||
|
||||
ASSET_HEADER_LOADED = true;
|
||||
}
|
||||
@ -97,9 +93,7 @@ apLoadS8(String8 str)
|
||||
static void
|
||||
apUnload(c8 *str)
|
||||
{
|
||||
Asset asset = {0};
|
||||
|
||||
return asset;
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
52
src/assets.h
52
src/assets.h
@ -7,12 +7,24 @@
|
||||
#define CreateMagicValue(a, b, c, d) ((u32)(d << 24) | (u32)(c << 16) | (u32)(b << 8) | (u32)(a))
|
||||
|
||||
// ::Assets::Globals::Header::
|
||||
#ifndef BUILD_ASSET_CODEGEN
|
||||
# include "codegen_assets.h"
|
||||
#endif
|
||||
#include "codegen_assets.h"
|
||||
|
||||
// ::Assets::Types::Header::
|
||||
|
||||
typedef struct Vertex
|
||||
{
|
||||
Vec4 pos;
|
||||
Vec4 col;
|
||||
} Vertex;
|
||||
|
||||
typedef struct m3dModel
|
||||
{
|
||||
Vertex *vertices;
|
||||
u32 *indices;
|
||||
u64 v_count;
|
||||
u64 i_count;
|
||||
} m3dModel;
|
||||
|
||||
typedef struct TexMeta
|
||||
{
|
||||
u32 w;
|
||||
@ -22,9 +34,18 @@ typedef struct TexMeta
|
||||
|
||||
typedef struct ModelMeta
|
||||
{
|
||||
u32 i_count;
|
||||
u64 i_count;
|
||||
} ModelMeta;
|
||||
|
||||
typedef struct AssetMeta
|
||||
{
|
||||
union
|
||||
{
|
||||
TexMeta texture;
|
||||
ModelMeta model;
|
||||
};
|
||||
} AssetMeta;
|
||||
|
||||
typedef struct Asset
|
||||
{
|
||||
union
|
||||
@ -41,24 +62,33 @@ typedef struct AssetTag
|
||||
f32 value;
|
||||
} AssetTag;
|
||||
|
||||
typedef enum AssetType_e
|
||||
{
|
||||
AT_NONE,
|
||||
AT_SHADER,
|
||||
AT_TEXTURE,
|
||||
AT_MODEL,
|
||||
} AssetType;
|
||||
|
||||
typedef struct AssetFile
|
||||
{
|
||||
union
|
||||
{
|
||||
TexMeta texture_meta;
|
||||
ModelMeta model_meta;
|
||||
};
|
||||
u64 hash;
|
||||
u64 data_offset;
|
||||
u64 len;
|
||||
union
|
||||
{
|
||||
TexMeta texture_meta;
|
||||
ModelMeta model_meta;
|
||||
};
|
||||
AssetType type;
|
||||
} AssetFile;
|
||||
|
||||
typedef struct FileHeader
|
||||
{
|
||||
u32 magic_num;
|
||||
u32 version;
|
||||
u32 asset_counts[ASSET_TYPE_MAX];
|
||||
u64 asset_offsets[ASSET_TYPE_MAX];
|
||||
u32 asset_counts;
|
||||
u64 asset_offset;
|
||||
} FileHeader;
|
||||
|
||||
// ::Assets::Init::Functions::Header::
|
||||
|
||||
159
src/codegen.c
Normal file
159
src/codegen.c
Normal file
@ -0,0 +1,159 @@
|
||||
#include "codegen.h"
|
||||
|
||||
u64
|
||||
WriteArrayToFile(Arena *arena, pFile file, String8 array_name, rawptr elements, u32 count, String8 type, u64 offset)
|
||||
{
|
||||
b32 is_string = StrEq(type.value, "c8 *");
|
||||
c8 *decl = MakeArray(arena, c8, 2048);
|
||||
i32 decl_len = SPrintf(decl, 2048, "static %s\n%s[] = \n{\n\t", type.value, array_name.value);
|
||||
String8 result = {
|
||||
.value = decl,
|
||||
.len = u64(decl_len),
|
||||
};
|
||||
|
||||
if (is_string)
|
||||
{
|
||||
String8 *strs = (String8 *)elements;
|
||||
for (u32 i = 0; i < count; i += 1)
|
||||
{
|
||||
c8 *f = i == count-1 ? "\"%s\"," : "\"%s\",\n\t";
|
||||
c8 buf[512];
|
||||
decl_len = SPrintf(buf, 512, f, strs[i].value);
|
||||
result = String8Concat(arena, result, MakeString8(buf, decl_len));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
u64 *ints = (u64 *)elements;
|
||||
for (u32 i = 0; i < count; i += 1)
|
||||
{
|
||||
c8 *f = i == count-1 ? "%lluU," : "%lluU,\n\t";
|
||||
c8 buf[512];
|
||||
decl_len = SPrintf(buf, 512, f, ints[i]);
|
||||
result = String8Concat(arena, result, MakeString8(buf, decl_len));
|
||||
}
|
||||
}
|
||||
|
||||
result = String8Concat(arena, result, String8CStr("\n};\n\n"));
|
||||
|
||||
return pFileWrite(file, offset, result.value, result.len);
|
||||
}
|
||||
|
||||
static String8 *
|
||||
ConvertCStrs(Arena *arena, c8 **strs, u32 count)
|
||||
{
|
||||
String8 *str8s = MakeArray(arena, String8, count);
|
||||
|
||||
for (u32 i = 0; i < count; i += 1)
|
||||
{
|
||||
str8s[i].value = strs[i];
|
||||
str8s[i].len = StrLen(strs[i]);
|
||||
}
|
||||
|
||||
return str8s;
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenAssetLookups(Arena *arena)
|
||||
{
|
||||
pFile file = pFileOpen("../src/codegen_assets.h", pFS_WRITE | pFS_CREATE | pFS_TRUNC);
|
||||
Assert(file > 0, "CodeGenAssetLookups failure: unable to open/create file");
|
||||
|
||||
Assert(pDirNavigate("../assets") == 0, "Unable to navigate to asset directory");
|
||||
|
||||
struct AssetDirInfo {
|
||||
c8 *prefix, *struct_name, *hash_struct_name, *dir, *define;
|
||||
};
|
||||
|
||||
struct AssetDirInfo dirs[] = {
|
||||
{
|
||||
.prefix = "shaders/",
|
||||
.struct_name = "g_Shader_Asset_Names",
|
||||
.hash_struct_name = "g_Shader_Asset_Hashes",
|
||||
.dir = "shaders",
|
||||
.define = "SHADER_ASSET",
|
||||
},
|
||||
{
|
||||
.prefix = "models/",
|
||||
.struct_name = "g_Model_Asset_Names",
|
||||
.hash_struct_name = "g_Model_Asset_Hashes",
|
||||
.dir = "models",
|
||||
.define = "MODEL_ASSET",
|
||||
},
|
||||
{
|
||||
.prefix = "textures/",
|
||||
.struct_name = "g_Texture_Asset_Names",
|
||||
.hash_struct_name = "g_Texture_Asset_Hashes",
|
||||
.dir = "textures",
|
||||
.define = "TEXTURE_ASSET",
|
||||
},
|
||||
};
|
||||
|
||||
u64 offset = 0;
|
||||
u32 dir_count = sizeof(dirs) / sizeof(struct AssetDirInfo);
|
||||
for (u32 i = 0; i < dir_count; i += 1)
|
||||
{
|
||||
Assert(pDirNavigate(dirs[i].dir) == 0, "Unable to navigate to asset sub directory.");
|
||||
|
||||
u32 count = 0;
|
||||
c8 **cstrs = pDirGetFileNames(arena, &count);
|
||||
u64 *hashes = MakeArray(arena, u64, count);
|
||||
String8 *strs = ConvertCStrs(arena, cstrs, count);
|
||||
|
||||
for (u32 j = 0; j < count; j += 1)
|
||||
{
|
||||
strs[j] = String8Concat(arena, String8CStr(dirs[i].prefix), strs[j]);
|
||||
i64 offset = String8FindLast(strs[j], '.');
|
||||
hashes[j] = XXH3_64bits_withSeed(strs[j].value, strs[j].len - offset, HASH_SEED);
|
||||
}
|
||||
|
||||
offset += WriteArrayToFile(
|
||||
arena,
|
||||
file,
|
||||
String8CStr(dirs[i].struct_name),
|
||||
strs,
|
||||
count,
|
||||
String8CStr("c8 *"),
|
||||
offset
|
||||
);
|
||||
|
||||
offset += WriteArrayToFile(
|
||||
arena,
|
||||
file,
|
||||
String8CStr(dirs[i].hash_struct_name),
|
||||
hashes,
|
||||
count,
|
||||
String8CStr("u64"),
|
||||
offset
|
||||
);
|
||||
|
||||
c8 buf[256];
|
||||
i32 decl_len = SPrintf(buf, 256, "#define %s_MAX %llu\n\n#define %s %d\n\n", dirs[i].define, count, dirs[i].define, i);
|
||||
|
||||
offset += pFileWrite(file, offset, buf, decl_len);
|
||||
|
||||
Assert(pDirNavigate("..") == 0, "CodeGenAssetLookups failure: unable to move back to build directory");
|
||||
}
|
||||
|
||||
pFileClose(file);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, c8 **argv)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
{
|
||||
_set_fmode(_O_BINARY);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (pDirIsVisible("build"))
|
||||
{
|
||||
Assert(pDirNavigate("./build") == 0, "Unable to change to build directory");
|
||||
}
|
||||
|
||||
void *mem = pMemAllocZeroed(GB(1));
|
||||
Arena *arena = ArenaInitDebug(mem, GB(1), __LINE__);
|
||||
|
||||
CodeGenAssetLookups(arena);
|
||||
}
|
||||
8
src/codegen.h
Normal file
8
src/codegen.h
Normal file
@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#define STG_IMPLEMENTATION
|
||||
|
||||
#include "stglib.h"
|
||||
|
||||
@ -1,66 +1,72 @@
|
||||
static c8 *
|
||||
g_Shader_Asset_Names[] =
|
||||
{
|
||||
"shaders/gui.frag",
|
||||
"shaders/pbr.frag",
|
||||
"shaders/gui.vert",
|
||||
"shaders/quad.frag",
|
||||
"shaders/quad.vert",
|
||||
"shaders/pbr.vert",
|
||||
"shaders/gui.frag.spv",
|
||||
"shaders/pbr.frag.spv",
|
||||
"shaders/gui.vert.spv",
|
||||
"shaders/quad.frag.spv",
|
||||
"shaders/quad.vert.spv",
|
||||
"shaders/pbr.vert.spv",
|
||||
};
|
||||
|
||||
static u64
|
||||
g_Shader_Asset_Hashes[] =
|
||||
{
|
||||
4076561469468128204U,
|
||||
12546533630435803654U,
|
||||
17203805968697784249U,
|
||||
1277283055956479971U,
|
||||
12273814537638279648U,
|
||||
1941995729991819811U,
|
||||
12100337026595633089U,
|
||||
12100337026595633089U,
|
||||
12100337026595633089U,
|
||||
12100337026595633089U,
|
||||
12100337026595633089U,
|
||||
12100337026595633089U,
|
||||
};
|
||||
|
||||
#define SHADER_ASSET_MAX 6
|
||||
|
||||
#define SHADER_ASSET 0
|
||||
|
||||
static c8 *
|
||||
g_Model_Asset_Names[] =
|
||||
{
|
||||
"models/test_char",
|
||||
"models/yoda",
|
||||
"models/test_char.m3d",
|
||||
"models/yoda.m3d",
|
||||
};
|
||||
|
||||
static u64
|
||||
g_Model_Asset_Hashes[] =
|
||||
{
|
||||
17106564331948230266U,
|
||||
1379945611816585992U,
|
||||
2356409063604999112U,
|
||||
2356409063604999112U,
|
||||
};
|
||||
|
||||
#define MODEL_ASSET_MAX 2
|
||||
|
||||
#define MODEL_ASSET 1
|
||||
|
||||
static c8 *
|
||||
g_Texture_Asset_Names[] =
|
||||
{
|
||||
"textures/ham_smoke",
|
||||
"textures/cheesoid",
|
||||
"textures/hog",
|
||||
"textures/patamon",
|
||||
"textures/pattermon",
|
||||
"textures/hamster",
|
||||
"textures/purplemon",
|
||||
"textures/ham_smoke.png",
|
||||
"textures/cheesoid.png",
|
||||
"textures/hog.jpg",
|
||||
"textures/patamon.png",
|
||||
"textures/pattermon.png",
|
||||
"textures/hamster.png",
|
||||
"textures/purplemon.png",
|
||||
};
|
||||
|
||||
static u64
|
||||
g_Texture_Asset_Hashes[] =
|
||||
{
|
||||
3672471465693847963U,
|
||||
17853259469867187617U,
|
||||
12925726572206082157U,
|
||||
1223697967736380744U,
|
||||
16704275018603890077U,
|
||||
13194708417649827129U,
|
||||
12400748618931758111U,
|
||||
5461253849680765905U,
|
||||
5461253849680765905U,
|
||||
5461253849680765905U,
|
||||
5461253849680765905U,
|
||||
5461253849680765905U,
|
||||
5461253849680765905U,
|
||||
5461253849680765905U,
|
||||
};
|
||||
|
||||
#define TEXTURE_ASSET_MAX 7
|
||||
|
||||
#define TEXTURE_ASSET 2
|
||||
|
||||
|
||||
674
src/ds.c
674
src/ds.c
@ -1,674 +0,0 @@
|
||||
// ::DataStructures::Globals::Start::
|
||||
|
||||
RBNode
|
||||
RB_NIL = { .color = RB_BLACK };
|
||||
RBNode *
|
||||
P_RB_NIL = &RB_NIL;
|
||||
|
||||
RBDataNode
|
||||
RB_DN_NIL = {0};
|
||||
RBDataNode *
|
||||
P_RB_DN_NIL = &RB_DN_NIL;
|
||||
|
||||
HashNode
|
||||
HT_NIL = {0};
|
||||
HashNode *
|
||||
P_HT_NIL = &HT_NIL;
|
||||
|
||||
// ::DataStructures::Globals::End::
|
||||
|
||||
|
||||
|
||||
// ::DataStructures::RedBlackTree::Functions::Start::
|
||||
|
||||
static void
|
||||
RBTreeInit(RBTree *tree)
|
||||
{
|
||||
Assert(tree != NULL, "RBTree is null");
|
||||
RB_NIL.right = RB_NIL.left = RB_NIL.parent = P_RB_NIL;
|
||||
RB_DN_NIL.next = P_RB_DN_NIL;
|
||||
|
||||
tree->root = P_RB_NIL;
|
||||
tree->nil = P_RB_NIL;
|
||||
}
|
||||
|
||||
static inline void
|
||||
RBTreePushDataNode(RBDataNode *first, RBDataNode *last, rawptr value)
|
||||
{
|
||||
RBDataNode *data_node = FLMemAllocZeroed(sizeof(RBDataNode));
|
||||
data_node->data = value;
|
||||
RBQueuePush(first, last, data_node);
|
||||
}
|
||||
|
||||
static inline RBNode *
|
||||
RBTreeInitNode(u64 key, rawptr value)
|
||||
{
|
||||
RBNode *node = FLMemAllocZeroed(sizeof(RBNode));
|
||||
node->parent = node->left = node->right = P_RB_NIL;
|
||||
node->color = RB_BLACK;
|
||||
node->key = key;
|
||||
|
||||
RBTreePushDataNode(node->bucket.first, node->bucket.last, value);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static void
|
||||
RBTreeInsert(RBTree *tree, u64 key, rawptr value)
|
||||
{
|
||||
RBNode *node = P_RB_NIL;
|
||||
|
||||
node->left = node->right = tree->nil;
|
||||
node->color = RB_RED;
|
||||
|
||||
if (tree->root == tree->nil)
|
||||
{
|
||||
node->color = RB_BLACK;
|
||||
node->parent = tree->nil;
|
||||
tree->root = node;
|
||||
}
|
||||
else
|
||||
{
|
||||
RBNode *curr_node = tree->root;
|
||||
while (true)
|
||||
{
|
||||
Assert(curr_node != tree->nil, "Current Node is NIL");
|
||||
|
||||
if (curr_node->key == key)
|
||||
{
|
||||
RBTreePushDataNode(curr_node->bucket.first, curr_node->bucket.last, value);
|
||||
break;
|
||||
}
|
||||
else if (curr_node->key < key)
|
||||
{
|
||||
if (curr_node->right == tree->nil)
|
||||
{
|
||||
node = RBTreeInitNode(key, value);
|
||||
node->parent = curr_node;
|
||||
curr_node->right = node;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
curr_node = curr_node->right;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (curr_node->left == tree->nil)
|
||||
{
|
||||
node = RBTreeInitNode(key, value);
|
||||
node->parent = curr_node;
|
||||
curr_node->left = node;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
curr_node = curr_node->left;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (node->parent->color != RB_BLACK && node != P_RB_NIL)
|
||||
RBTreeCorrect(tree, node);
|
||||
}
|
||||
|
||||
static void
|
||||
RBTreeCorrect(RBTree *tree, RBNode *node)
|
||||
{
|
||||
RBNode *gp = node->parent->parent;
|
||||
RBNode *p = node->parent;
|
||||
do
|
||||
{
|
||||
if (node == tree->root)
|
||||
{
|
||||
node->color = RB_BLACK;
|
||||
break;
|
||||
}
|
||||
|
||||
if (gp == tree->nil)
|
||||
{
|
||||
p->color = RB_BLACK;
|
||||
break;
|
||||
}
|
||||
|
||||
RBNodeDir dir = NodeDir(p);
|
||||
RBNode *unc = gp->child[1 - dir];
|
||||
if (unc == tree->nil || unc->color == RB_BLACK)
|
||||
{
|
||||
if (node == p->child[1 - dir])
|
||||
{
|
||||
RBTreeRotate(tree, p, dir);
|
||||
node = p;
|
||||
p = gp->child[dir];
|
||||
}
|
||||
|
||||
RBTreeRotate(tree, gp, 1 - dir);
|
||||
p->color = RB_BLACK;
|
||||
gp->color = RB_RED;
|
||||
break;
|
||||
}
|
||||
|
||||
p->color = RB_BLACK;
|
||||
unc->color = RB_BLACK;
|
||||
gp->color = RB_RED;
|
||||
node = gp;
|
||||
gp = node->parent->parent;
|
||||
} while ((p = node->parent));
|
||||
}
|
||||
|
||||
static void
|
||||
RBTreeDelete(RBTree *tree, u64 key, rawptr value)
|
||||
{
|
||||
RBNode *node = NULL;
|
||||
Assert(RBTreeSearch(tree, key, &node), "Unable to find node in RBTreeDelete");
|
||||
|
||||
if (node->bucket.first->data != value)
|
||||
{
|
||||
Assert(node->bucket.first->next != P_RB_DN_NIL, "RBTreeDelete Failure: unable to find value to delete");
|
||||
RBDataNode *data_node = node->bucket.first->next;
|
||||
RBDataNode *prev_node = node->bucket.first;
|
||||
|
||||
while (data_node != P_RB_DN_NIL)
|
||||
{
|
||||
if (data_node->data == value)
|
||||
{
|
||||
prev_node->next = data_node->next;
|
||||
if (data_node == node->bucket.last)
|
||||
node->bucket.last = prev_node;
|
||||
|
||||
FLMemFree(data_node);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FLMemFree(node->bucket.first);
|
||||
|
||||
if (node == tree->root && node->left == tree->nil && node->right == tree->nil)
|
||||
{
|
||||
tree->root = tree->nil;
|
||||
}
|
||||
else if (node->left != tree->nil && node->right != tree->nil)
|
||||
{
|
||||
RBNode *ln = node->right;
|
||||
|
||||
while (ln->left != tree->nil)
|
||||
ln = ln->left;
|
||||
|
||||
node->key = ln->key;
|
||||
node->bucket = ln->bucket;
|
||||
|
||||
if (node->right == ln)
|
||||
node->right = tree->nil;
|
||||
else
|
||||
ln->parent->left = tree->nil;
|
||||
|
||||
ln->parent = tree->nil;
|
||||
}
|
||||
else if (node->color == RB_BLACK && node->left != tree->nil)
|
||||
{
|
||||
node->key = node->left->key;
|
||||
node->bucket = node->left->bucket;
|
||||
node->left = tree->nil;
|
||||
}
|
||||
else if (node->color == RB_BLACK && node->right != tree->nil)
|
||||
{
|
||||
node->key = node->right->key;
|
||||
node->bucket = node->right->bucket;
|
||||
node->right = tree->nil;
|
||||
}
|
||||
else if (node->color == RB_RED && node->right == tree->nil && node->left == tree->nil)
|
||||
{
|
||||
RBNodeDir dir = NodeDir(node);
|
||||
node->parent->child[dir] = tree->nil;
|
||||
}
|
||||
else
|
||||
{
|
||||
RBNode *p = node->parent;
|
||||
RBNodeColor col = node->color;
|
||||
RBNode *s, *cn, *dn;
|
||||
|
||||
RBNodeDir dir = NodeDir(node);
|
||||
p->child[dir] = tree->nil;
|
||||
|
||||
goto start_deletion;
|
||||
|
||||
do
|
||||
{
|
||||
dir = NodeDir(node);
|
||||
start_deletion:
|
||||
s = p->child[1 - dir];
|
||||
dn = s->child[1 - dir];
|
||||
cn = s->child[dir];
|
||||
|
||||
if (s->color == RB_RED)
|
||||
{
|
||||
RBTreeRotate(tree, p, dir);
|
||||
p->color = RB_RED;
|
||||
s->color = RB_BLACK;
|
||||
s = cn;
|
||||
|
||||
dn = s->child[1 - dir];
|
||||
if (dn->color == RB_RED)
|
||||
goto rotate_sibling;
|
||||
cn = s->child[dir];
|
||||
if (cn->color == RB_RED)
|
||||
goto rotate_parent;
|
||||
|
||||
s->color = RB_RED;
|
||||
p->color = RB_BLACK;
|
||||
return;
|
||||
}
|
||||
|
||||
if (dn->color == RB_RED)
|
||||
goto rotate_parent;
|
||||
|
||||
if (cn->color == RB_RED)
|
||||
goto rotate_sibling;
|
||||
|
||||
if (p->color == RB_RED)
|
||||
{
|
||||
s->color = RB_RED;
|
||||
p->color = RB_BLACK;
|
||||
return;
|
||||
}
|
||||
|
||||
if (p == tree->nil)
|
||||
return;
|
||||
|
||||
s->color = RB_RED;
|
||||
node = p;
|
||||
} while ((p = node->parent));
|
||||
|
||||
rotate_sibling:
|
||||
RBTreeRotate(tree, s, 1 - dir);
|
||||
s->color = RB_RED;
|
||||
cn->color = RB_BLACK;
|
||||
dn = s;
|
||||
s = cn;
|
||||
|
||||
rotate_parent:
|
||||
RBTreeRotate(tree, p, dir);
|
||||
s->color = p->color;
|
||||
p->color = RB_BLACK;
|
||||
dn->color = RB_BLACK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static b32
|
||||
RBTreeSearchNearest(RBTree *tree, u64 key, RBNode **out_node)
|
||||
{
|
||||
if (tree->root == tree->nil) return false;
|
||||
|
||||
RBNode *node = tree->root;
|
||||
RBNode *nearest = tree->root;
|
||||
u64 nearest_diff = UINT64_MAX;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (node == tree->nil)
|
||||
break;
|
||||
|
||||
u64 diff = node->key - key;
|
||||
diff = Absu64(diff);
|
||||
|
||||
if (diff == 0)
|
||||
{
|
||||
nearest = node;
|
||||
break;
|
||||
}
|
||||
|
||||
if (diff < nearest_diff)
|
||||
{
|
||||
nearest_diff = diff;
|
||||
nearest = node;
|
||||
}
|
||||
|
||||
if (node->key < key)
|
||||
node = node->right;
|
||||
else
|
||||
node = node->left;
|
||||
}
|
||||
|
||||
*out_node = nearest != tree->nil ? nearest : tree->nil;
|
||||
|
||||
return *out_node != tree->nil;
|
||||
}
|
||||
|
||||
static b32
|
||||
RBTreeSearch(RBTree *tree, u64 key, RBNode **out_node)
|
||||
{
|
||||
if (tree->root == tree->nil) return false;
|
||||
|
||||
b32 found = false;
|
||||
RBNode *node = tree->root;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (node->key == key)
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (node == tree->nil)
|
||||
break;
|
||||
|
||||
if (node->key < key)
|
||||
node = node->right;
|
||||
else
|
||||
node = node->left;
|
||||
}
|
||||
|
||||
if (found)
|
||||
*out_node = node;
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
static inline void
|
||||
RBTreeTransplant(RBTree *tree, RBNode *node, RBNode *placed_node)
|
||||
{
|
||||
if (node->parent == tree->nil)
|
||||
tree->root = placed_node;
|
||||
else if (node == node->parent->left)
|
||||
node->parent->left = placed_node;
|
||||
else
|
||||
node->parent->right = placed_node;
|
||||
|
||||
placed_node->parent = node->parent;
|
||||
}
|
||||
|
||||
static void
|
||||
RBTreeRotate(RBTree *tree, RBNode *node, RBNodeDir dir)
|
||||
{
|
||||
RBNode *p = node->parent;
|
||||
RBNode *root = node->child[1 - dir];
|
||||
RBNode *child = root->child[dir];
|
||||
|
||||
node->child[1 - dir] = child;
|
||||
|
||||
if (child != tree->nil)
|
||||
child->parent = node;
|
||||
|
||||
root->child[dir] = node;
|
||||
root->parent = p;
|
||||
node->parent = root;
|
||||
|
||||
if (p != tree->nil)
|
||||
p->child[node == p->right] = root;
|
||||
else
|
||||
tree->root = root;
|
||||
}
|
||||
|
||||
static void
|
||||
RBTreeLeftRotate(RBTree *tree, RBNode *node)
|
||||
{
|
||||
RBNode *right = node->right;
|
||||
if (right->left != tree->nil)
|
||||
node->right = right->left;
|
||||
|
||||
if (node->parent == tree->nil)
|
||||
tree->root = right;
|
||||
else if (node->parent->left == node)
|
||||
node->parent->left = right;
|
||||
else
|
||||
node->parent->right = right;
|
||||
|
||||
right->parent = node->parent;
|
||||
right->left = node;
|
||||
node->parent = right;
|
||||
}
|
||||
|
||||
static void
|
||||
RBTreeRightRotate(RBTree *tree, RBNode *node)
|
||||
{
|
||||
RBNode *left = node->left;
|
||||
if (left->right != tree->nil)
|
||||
node->left = left->right;
|
||||
|
||||
if (node->parent == tree->nil)
|
||||
tree->root = left;
|
||||
else if (node->parent->left == node)
|
||||
node->parent->left = left;
|
||||
else
|
||||
node->parent->right = left;
|
||||
|
||||
left->parent = node->parent;
|
||||
left->right = node;
|
||||
node->parent = left;
|
||||
}
|
||||
|
||||
// ::DataStructures::RedBlackTree::Functions::End::
|
||||
|
||||
|
||||
|
||||
// ::DataStructures::HashTable::Functions::Start::
|
||||
|
||||
static void
|
||||
HashTableInit(HashTable *table, u32 init_size)
|
||||
{
|
||||
table->cap = init_size;
|
||||
table->count = 0;
|
||||
table->free_lists.first = P_HT_NIL;
|
||||
table->free_lists.last = P_HT_NIL;
|
||||
|
||||
table->lists = FLMemAlloc(sizeof(HashList) * init_size);
|
||||
for (u32 i = 0; i < init_size; i++)
|
||||
{
|
||||
table->lists[i].first = P_HT_NIL;
|
||||
table->lists[i].last = P_HT_NIL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
HashTableConcatInPlace(HashList *list, HashList *to_concat)
|
||||
{
|
||||
SLLConcatInPlaceNoCount(list, to_concat);
|
||||
}
|
||||
|
||||
static void
|
||||
HashTableClear(HashTable *table)
|
||||
{
|
||||
table->count = 0;
|
||||
for (u32 i = 0; i < table->count; i++)
|
||||
{
|
||||
HashTableConcatInPlace(&table->free_lists, &table->lists[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static HashNode *
|
||||
HashListPop(HashList *list)
|
||||
{
|
||||
HashNode *result = list->first;
|
||||
HTQueuePop(list->first, list->last);
|
||||
return result;
|
||||
}
|
||||
|
||||
static HashNode *
|
||||
HashTablePush(HashTable *table, u64 hash, KeyValuePair value)
|
||||
{
|
||||
HashNode *node = NULL;
|
||||
if (table->free_lists.first != P_HT_NIL)
|
||||
node = HashListPop(&table->free_lists);
|
||||
else
|
||||
node = FLMemAlloc(sizeof(HashNode));
|
||||
|
||||
node->next = P_HT_NIL;
|
||||
node->v = value;
|
||||
|
||||
u64 index = hash % table->cap;
|
||||
HTQueuePush(table->lists[index].first, table->lists[index].last, node);
|
||||
table->count += 1;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static HashNode *
|
||||
HashTablePushU64U32(HashTable *table, u64 key, u32 value)
|
||||
{
|
||||
u64 hash = HashFromString(String8Struct(&key));
|
||||
return HashTablePush(table, hash, (KeyValuePair){ .key_u64 = key, .value_u32 = value });
|
||||
}
|
||||
|
||||
static HashNode *
|
||||
HashTablePushU64U64(HashTable *table, u64 key, u64 value)
|
||||
{
|
||||
u64 hash = HashFromString(String8Struct(&key));
|
||||
return HashTablePush(table, hash, (KeyValuePair){ .key_u64 = key, .value_u64 = value });
|
||||
}
|
||||
|
||||
static HashNode *
|
||||
HashTablePushU64String8(HashTable *table, u64 key, String8 value)
|
||||
{
|
||||
u64 hash = HashFromString(String8Struct(&key));
|
||||
return HashTablePush(table, hash, (KeyValuePair){ .key_u64 = key, .value_string = value });
|
||||
}
|
||||
|
||||
static HashNode *
|
||||
HashTablePushU64Rawptr(HashTable *table, u64 key, rawptr value)
|
||||
{
|
||||
u64 hash = HashFromString(String8Struct(&key));
|
||||
return HashTablePush(table, hash, (KeyValuePair){ .key_u64 = key, .value_rawptr = value });
|
||||
}
|
||||
|
||||
static HashNode *
|
||||
HashTablePushU64U64Split(HashTable *table, u64 key, u32 upper, u32 lower)
|
||||
{
|
||||
u64 hash = HashFromString(String8Struct(&key));
|
||||
return HashTablePush(table, hash, (KeyValuePair){ .key_u64 = key, .value_u64_split = { .upper = upper, .lower = lower }});
|
||||
}
|
||||
|
||||
static HashNode *
|
||||
HashTablePushRawptrU64(HashTable *table, rawptr key, u64 value)
|
||||
{
|
||||
u64 hash = HashFromString(String8Struct(&key));
|
||||
return HashTablePush(table, hash, (KeyValuePair){ .key_rawptr = key, .value_u64 = value });
|
||||
}
|
||||
|
||||
static KeyValuePair *
|
||||
HashTableSearchU64(HashTable *table, u64 key)
|
||||
{
|
||||
KeyValuePair *result = NULL;
|
||||
|
||||
u64 hash = HashFromString(String8Struct(&key));
|
||||
u64 index = hash % table->cap;
|
||||
HashList *list = table->lists + index;
|
||||
for (HashNode *node = list->first; node != P_HT_NIL; node = node->next)
|
||||
{
|
||||
if (node->v.key_u64 == key)
|
||||
{
|
||||
result = &node->v;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static KeyValuePair *
|
||||
HashTableSearchRawptr(HashTable *table, rawptr key)
|
||||
{
|
||||
KeyValuePair *result = NULL;
|
||||
|
||||
u64 hash = HashFromString(String8Struct(&key));
|
||||
u64 index = hash % table->cap;
|
||||
HashList *list = table->lists + index;
|
||||
for (HashNode *node = list->first; node != P_HT_NIL; node = node->next)
|
||||
{
|
||||
if (node->v.key_rawptr == key)
|
||||
{
|
||||
result = &node->v;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
HashTableDeleteU64(HashTable *table, u64 key)
|
||||
{
|
||||
u64 hash = HashFromString(String8Struct(&key));
|
||||
u64 index = hash % table->cap;
|
||||
HashList *list = table->lists + index;
|
||||
HashNode *prev = P_HT_NIL;
|
||||
for (HashNode *node = list->first; node != P_HT_NIL; node = node->next)
|
||||
{
|
||||
if (node->v.key_u64 == key)
|
||||
{
|
||||
if (prev != P_HT_NIL)
|
||||
prev->next = node->next;
|
||||
|
||||
node->v.key_u64 = 0;
|
||||
node->v.value_u64 = 0;
|
||||
HTQueuePush(table->free_lists.first, table->free_lists.last, node);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static rawptr
|
||||
HashTableDeleteU64Rawptr(HashTable *table, u64 key)
|
||||
{
|
||||
rawptr value = NULL;
|
||||
|
||||
u64 hash = HashFromString(String8Struct(&key));
|
||||
u64 index = hash % table->cap;
|
||||
HashList *list = table->lists + index;
|
||||
HashNode *prev = P_HT_NIL;
|
||||
for (HashNode *node = list->first; node != P_HT_NIL; node = node->next)
|
||||
{
|
||||
if (node->v.key_u64 == key)
|
||||
{
|
||||
if (prev != P_HT_NIL)
|
||||
prev->next = node->next;
|
||||
|
||||
value = node->v.value_rawptr;
|
||||
|
||||
node->v.key_u64 = 0;
|
||||
node->v.value_rawptr = NULL;
|
||||
HTQueuePush(table->free_lists.first, table->free_lists.last, node);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static U64Split
|
||||
HashTableDeleteU64U64Split(HashTable *table, u64 key)
|
||||
{
|
||||
U64Split value = { .upper = UINT32_MAX };
|
||||
|
||||
u64 hash = HashFromString(String8Struct(&key));
|
||||
u64 index = hash % table->cap;
|
||||
HashList *list = table->lists + index;
|
||||
HashNode *prev = P_HT_NIL;
|
||||
for (HashNode *node = list->first; node != P_HT_NIL; node = node->next)
|
||||
{
|
||||
if (node->v.key_u64 == key)
|
||||
{
|
||||
if (prev != P_HT_NIL)
|
||||
prev->next = node->next;
|
||||
|
||||
value.upper = node->v.value_u64_split.upper;
|
||||
value.lower = node->v.value_u64_split.lower;
|
||||
|
||||
node->v.key_u64 = 0;
|
||||
node->v.value_u64_split.upper = 0;
|
||||
node->v.value_u64_split.lower = 0;
|
||||
HTQueuePush(table->free_lists.first, table->free_lists.last, node);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
// ::DataStructures::HashTable::Functions::End::
|
||||
|
||||
|
||||
128
src/ds.h
128
src/ds.h
@ -1,128 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// ::DataStructures::RedBlackTree::Header::
|
||||
|
||||
#define NodeDir(node) (node == node->parent->left ? RB_LEFT : RB_RIGHT)
|
||||
#define RBQueuePop(f, l) SLLQueuePop(P_RB_DN_NIL, f, l)
|
||||
#define RBQueuePush(f, l, n) SLLQueuePush(P_RB_DN_NIL, f, l, n)
|
||||
#define RBQueuePushFront(f, l, n) SLLQueuePush(P_RB_DN_NIL, f, l, n)
|
||||
|
||||
typedef enum RBNodeColor_e
|
||||
{
|
||||
RB_RED,
|
||||
RB_BLACK,
|
||||
} RBNodeColor;
|
||||
|
||||
typedef enum RBNodeDir_e
|
||||
{
|
||||
RB_LEFT,
|
||||
RB_RIGHT,
|
||||
} RBNodeDir;
|
||||
|
||||
typedef struct RBDataNode
|
||||
{
|
||||
rawptr data;
|
||||
struct RBDataNode *next;
|
||||
} RBDataNode;
|
||||
|
||||
typedef struct RBBucket
|
||||
{
|
||||
RBDataNode *first;
|
||||
RBDataNode *last;
|
||||
} RBBucket;
|
||||
|
||||
typedef struct RBNode
|
||||
{
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
struct RBNode *left;
|
||||
struct RBNode *right;
|
||||
};
|
||||
struct RBNode *child[2];
|
||||
};
|
||||
struct RBNode *parent;
|
||||
u64 key;
|
||||
RBBucket bucket;
|
||||
RBNodeColor color;
|
||||
} RBNode;
|
||||
|
||||
typedef struct RBTree
|
||||
{
|
||||
RBNode *root;
|
||||
RBNode *nil;
|
||||
} RBTree;
|
||||
|
||||
static void RBTreeInit (RBTree *tree);
|
||||
static inline RBNode *RBTreeInitNode(u64 key, rawptr value);
|
||||
static inline void RBTreePushDataNode(RBDataNode *first, RBDataNode *last, rawptr value);
|
||||
static void RBTreeInsert(RBTree *tree, u64 key, rawptr value);
|
||||
static b32 RBTreeSearchNearest(RBTree *tree, u64 key, RBNode **node);
|
||||
static b32 RBTreeSearch (RBTree *tree, u64 key, RBNode **node);
|
||||
static void RBTreeDelete (RBTree *tree, u64 key, rawptr value);
|
||||
static void RBTreeLeftRotate (RBTree *tree, RBNode *node);
|
||||
static void RBTreeRightRotate(RBTree *tree, RBNode *node);
|
||||
static void RBTreeRotate (RBTree *tree, RBNode *node, RBNodeDir dir);
|
||||
static void RBTreeCorrect (RBTree *tree, RBNode *node);
|
||||
static void RBTreeTransplant (RBTree *tree, RBNode *node, RBNode *placed_node);
|
||||
|
||||
// ::DataStructures::HashTable::Functions::Header::
|
||||
|
||||
#define HTQueuePop(f, l) SLLQueuePop(P_HT_NIL, f, l)
|
||||
#define HTQueuePush(f, l, n) SLLQueuePush(P_HT_NIL, f, l, n)
|
||||
#define HTQueuePushFront(f, l, n) SLLQueuePush(P_HT_NIL, f, l, n)
|
||||
|
||||
typedef struct KeyValuePair
|
||||
{
|
||||
union
|
||||
{
|
||||
u64 key_u64;
|
||||
rawptr key_rawptr;
|
||||
};
|
||||
union
|
||||
{
|
||||
String8 value_string;
|
||||
rawptr value_rawptr;
|
||||
u32 value_u32;
|
||||
u64 value_u64;
|
||||
U64Split value_u64_split;
|
||||
};
|
||||
} KeyValuePair;
|
||||
|
||||
typedef struct HashNode
|
||||
{
|
||||
struct HashNode *next;
|
||||
KeyValuePair v;
|
||||
} HashNode;
|
||||
|
||||
typedef struct HashList
|
||||
{
|
||||
HashNode *first;
|
||||
HashNode *last;
|
||||
} HashList;
|
||||
|
||||
typedef struct HashTable
|
||||
{
|
||||
HashList *lists;
|
||||
HashList free_lists;
|
||||
u64 count;
|
||||
u32 cap;
|
||||
} HashTable;
|
||||
|
||||
static void HashTableInit(HashTable *table, u32 init_size);
|
||||
static void HashTableClear(HashTable *table);
|
||||
static void HashTableConcatInPlace(HashList *list, HashList *to_concat);
|
||||
static u64 HashTableHash(String8 str);
|
||||
static HashNode *HashListPop(HashList *list);
|
||||
static KeyValuePair *HashTableSearchU64(HashTable *table, u64 key);
|
||||
static KeyValuePair *HashTableSearchRawptr(HashTable *table, rawptr key);
|
||||
static HashNode *HashTablePush(HashTable *table, u64 hash, KeyValuePair value);
|
||||
static HashNode *HashTablePushU64U32(HashTable *table, u64 key, u32 value);
|
||||
static HashNode *HashTablePushU64U64(HashTable *table, u64 key, u64 value);
|
||||
static HashNode *HashTablePushU64String8(HashTable *table, u64 key, String8 value);
|
||||
static HashNode *HashTablePushU64Rawptr(HashTable *table, u64 key, rawptr value);
|
||||
static HashNode *HashTablePushU64U64Split(HashTable *table, u64 key, u32 upper, u32 lower);
|
||||
static rawptr HashTableDeleteU64Rawptr(HashTable *table, u64 key);
|
||||
static void HashTableDeleteU64(HashTable *table, u64 key);
|
||||
|
||||
@ -10,14 +10,9 @@ int PROGRAM_FAILED = false;
|
||||
#include "entry_linux.h"
|
||||
|
||||
// ::ThirdParty::Include::
|
||||
#include "xxhash/xxhash.c"
|
||||
#include "fastlz/fastlz.c"
|
||||
|
||||
#include "platform/platform.c"
|
||||
#include "util.c"
|
||||
#include "assets.c"
|
||||
#include "ds.c"
|
||||
#include "allocators.c"
|
||||
#include "renderer.c"
|
||||
#include "game.c"
|
||||
#ifdef BUILD_TEST
|
||||
|
||||
@ -12,17 +12,14 @@
|
||||
|
||||
#define WINDOW_NAME "Video Game"
|
||||
|
||||
#include "shared_types.h"
|
||||
#include "platform/platform.h"
|
||||
#include "util.h"
|
||||
#define STG_IMPLEMENTATION
|
||||
|
||||
#include "stglib.h"
|
||||
|
||||
#include "assets.h"
|
||||
#include "ds.h"
|
||||
#include "allocators.h"
|
||||
|
||||
// ::ThirdParty::Include::Header::
|
||||
#include "stb/stb_sprintf.h"
|
||||
#include "stb/stb_image.h"
|
||||
#include "xxhash/xxhash.h"
|
||||
#include "fastlz/fastlz.h"
|
||||
#include "m3d/m3d.h"
|
||||
|
||||
|
||||
@ -2,7 +2,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#define STB_SPRINTF_IMPLEMENTATION
|
||||
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
|
||||
@ -16,7 +15,6 @@
|
||||
#include "allocators.h"
|
||||
|
||||
// ::ThirdParty::Include::Header::
|
||||
#include "stb/stb_sprintf.h"
|
||||
#include "stb/stb_image.h"
|
||||
#include "xxhash/xxhash.h"
|
||||
#include "fastlz/fastlz.h"
|
||||
|
||||
298
src/packer.c
298
src/packer.c
@ -2,16 +2,9 @@
|
||||
|
||||
#include "packer.h"
|
||||
|
||||
#include "xxhash/xxhash.c"
|
||||
#include "fastlz/fastlz.c"
|
||||
|
||||
#include "platform/platform.c"
|
||||
#include "assets.c"
|
||||
#include "util.c"
|
||||
#include "ds.c"
|
||||
#include "allocators.c"
|
||||
#include "renderer.c"
|
||||
#include "game.c"
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <fcntl.h>
|
||||
@ -19,168 +12,6 @@
|
||||
|
||||
// ::Packer::Packing::Functions::Start::
|
||||
|
||||
#ifdef BUILD_ASSET_CODEGEN
|
||||
|
||||
u64
|
||||
WriteArrayToFile(Arena *arena, pFile file, String8 array_name, rawptr elements, u32 count, String8 type, u64 offset)
|
||||
{
|
||||
b32 is_string = StrEq(type.value, "c8 *");
|
||||
c8 *decl = MakeArray(arena, c8, 2048);
|
||||
i32 decl_len = SPrintf(decl, 2048, "static %s\n%s[] = \n{\n\t", type.value, array_name.value);
|
||||
String8 result = {
|
||||
.value = decl,
|
||||
.len = u64(decl_len),
|
||||
};
|
||||
|
||||
if (is_string)
|
||||
{
|
||||
String8 *strs = (String8 *)elements;
|
||||
for (u32 i = 0; i < count; i += 1)
|
||||
{
|
||||
c8 *f = i == count-1 ? "\"%s\"," : "\"%s\",\n\t";
|
||||
c8 buf[512];
|
||||
decl_len = SPrintf(buf, 512, f, strs[i].value);
|
||||
result = String8Concat(arena, result, MakeString8(buf, decl_len));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
u64 *ints = (u64 *)elements;
|
||||
for (u32 i = 0; i < count; i += 1)
|
||||
{
|
||||
c8 *f = i == count-1 ? "%lluU," : "%lluU,\n\t";
|
||||
c8 buf[512];
|
||||
decl_len = SPrintf(buf, 512, f, ints[i]);
|
||||
result = String8Concat(arena, result, MakeString8(buf, decl_len));
|
||||
}
|
||||
}
|
||||
|
||||
result = String8Concat(arena, result, String8CStr("\n};\n\n"));
|
||||
|
||||
return pFileWrite(file, offset, result.value, result.len);
|
||||
}
|
||||
|
||||
static String8 *
|
||||
ConvertCStrs(Arena *arena, c8 **strs, u32 count)
|
||||
{
|
||||
String8 *str8s = MakeArray(arena, String8, count);
|
||||
|
||||
for (u32 i = 0; i < count; i += 1)
|
||||
{
|
||||
str8s[i].value = strs[i];
|
||||
str8s[i].len = StrLen(strs[i]);
|
||||
}
|
||||
|
||||
return str8s;
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenAssetLookups(Arena *arena)
|
||||
{
|
||||
pFile file = pFileOpen("../src/codegen_assets.h", pFS_WRITE | pFS_CREATE | pFS_TRUNC);
|
||||
Assert(file > 0, "CodeGenAssetLookups failure: unable to open/create file");
|
||||
|
||||
Assert(pDirNavigate("../assets") == 0, "Unable to navigate to asset directory");
|
||||
|
||||
struct AssetDirInfo {
|
||||
c8 *prefix, *struct_name, *hash_struct_name, *dir, *define;
|
||||
};
|
||||
|
||||
struct AssetDirInfo dirs[] = {
|
||||
{
|
||||
.prefix = "shaders/",
|
||||
.struct_name = "g_Shader_Asset_Names",
|
||||
.hash_struct_name = "g_Shader_Asset_Hashes",
|
||||
.dir = "shaders",
|
||||
.define = "SHADER_ASSET",
|
||||
},
|
||||
{
|
||||
.prefix = "models/",
|
||||
.struct_name = "g_Model_Asset_Names",
|
||||
.hash_struct_name = "g_Model_Asset_Hashes",
|
||||
.dir = "models",
|
||||
.define = "MODEL_ASSET",
|
||||
},
|
||||
{
|
||||
.prefix = "textures/",
|
||||
.struct_name = "g_Texture_Asset_Names",
|
||||
.hash_struct_name = "g_Texture_Asset_Hashes",
|
||||
.dir = "textures",
|
||||
.define = "TEXTURE_ASSET",
|
||||
},
|
||||
};
|
||||
|
||||
u64 offset = 0;
|
||||
u32 dir_count = sizeof(dirs) / sizeof(struct AssetDirInfo);
|
||||
for (u32 i = 0; i < dir_count; i += 1)
|
||||
{
|
||||
Assert(pDirNavigate(dirs[i].dir) == 0, "Unable to navigate to asset sub directory.");
|
||||
|
||||
u32 count = 0;
|
||||
c8 **cstrs = pDirGetFileNames(arena, &count);
|
||||
u64 *hashes = MakeArray(arena, u64, count);
|
||||
String8 *strs = ConvertCStrs(arena, cstrs, count);
|
||||
|
||||
for (u32 j = 0; j < count; j += 1)
|
||||
{
|
||||
strs[j] = String8Concat(arena, String8CStr(dirs[i].prefix), strs[j]);
|
||||
i64 offset = String8FindLast(strs[j], '.');
|
||||
hashes[j] = XXH3_64bits_withSeed(strs[j].value, strs[j].len - offset, HASH_SEED);
|
||||
}
|
||||
|
||||
offset += WriteArrayToFile(
|
||||
arena,
|
||||
file,
|
||||
String8CStr(dirs[i].struct_name),
|
||||
strs,
|
||||
count,
|
||||
String8CStr("c8 *"),
|
||||
offset
|
||||
);
|
||||
|
||||
offset += WriteArrayToFile(
|
||||
arena,
|
||||
file,
|
||||
String8CStr(dirs[i].hash_struct_name),
|
||||
hashes,
|
||||
count,
|
||||
String8CStr("u64"),
|
||||
offset
|
||||
);
|
||||
|
||||
c8 buf[128];
|
||||
i32 decl_len = SPrintf(buf, 128, "#define %s_MAX %llu\n\n#define %s %llu\n\n", dirs[i].define, count, dirs[i].define, i);
|
||||
|
||||
offset += pFileWrite(file, offset, buf, decl_len);
|
||||
|
||||
Assert(pDirNavigate("..") == 0, "CodeGenAssetLookups failure: unable to move back to build directory");
|
||||
}
|
||||
|
||||
pFileClose(file);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, c8 **argv)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
{
|
||||
_set_fmode(_O_BINARY);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (pDirIsVisible("build"))
|
||||
{
|
||||
Assert(pDirNavigate("./build") == 0, "Unable to change to build directory");
|
||||
}
|
||||
|
||||
void *mem = pMemAllocZeroed(GB(1));
|
||||
Arena *arena = ArenaInitDebug(mem, GB(1), __LINE__);
|
||||
|
||||
CodeGenAssetLookups(arena);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
i32
|
||||
WriteHeader(pFile file, FileHeader *header)
|
||||
{
|
||||
@ -218,23 +49,8 @@ InitHeader(FileHeader *header)
|
||||
header->magic_num = CreateMagicValue('s', 't', 'e', 'g');
|
||||
header->version = FILE_VERSION;
|
||||
|
||||
header->asset_counts[SHADER_ASSET] = SHADER_ASSET_MAX;
|
||||
header->asset_counts[TEXTURE_ASSET] = TEXTURE_ASSET_MAX;
|
||||
header->asset_counts[SOUND_ASSET] = SOUND_ASSET_MAX;
|
||||
header->asset_counts[MODEL_ASSET] = MODEL_ASSET_MAX;
|
||||
|
||||
u64 offset = sizeof(FileHeader);
|
||||
|
||||
for (u32 i = 0; i < ASSET_TYPE_MAX; i++)
|
||||
{
|
||||
if (header->asset_counts[i] > 0)
|
||||
{
|
||||
header->asset_offsets[i] = offset;
|
||||
offset += sizeof(AssetFile) * header->asset_counts[i];
|
||||
}
|
||||
else
|
||||
header->asset_offsets[i] = 0;
|
||||
}
|
||||
header->asset_counts = SHADER_ASSET_MAX + TEXTURE_ASSET_MAX + MODEL_ASSET_MAX;
|
||||
header->asset_offset = sizeof(FileHeader);
|
||||
}
|
||||
|
||||
void
|
||||
@ -244,20 +60,16 @@ PackFiles(Arena *arena, FileHeader *header)
|
||||
|
||||
u64 file_pos = pFileWrite(file, 0, header, sizeof(FileHeader));
|
||||
|
||||
u64 data_offset = 0;
|
||||
for (u32 i = 0; i < ASSET_TYPE_MAX; i++)
|
||||
{
|
||||
u64 asset_offset = header->asset_offsets[i] + (header->asset_counts[i] * sizeof(AssetFile));
|
||||
if (asset_offset > data_offset)
|
||||
data_offset = asset_offset;
|
||||
}
|
||||
|
||||
c8 *return_dir = ".";
|
||||
u32 file_count;
|
||||
MoveToShaderDir(&return_dir);
|
||||
Assert(pDirNavigate("../assets") == 0, "Unable to move to assets directory");
|
||||
|
||||
AssetFile *shader_assets = MakeArray(arena, AssetFile, SHADER_ASSET_MAX);
|
||||
for (u32 i = 0; i < SHADER_ASSET_MAX; i++)
|
||||
u64 total_assets = SHADER_ASSET_MAX + TEXTURE_ASSET_MAX + MODEL_ASSET_MAX;
|
||||
u64 asset_count = 0;
|
||||
AssetFile *assets = MakeArray(arena, AssetFile, total_assets);
|
||||
|
||||
u64 data_offset = header->asset_offset + (sizeof(AssetFile) + total_assets);
|
||||
|
||||
for (u32 i = 0; i < SHADER_ASSET_MAX; i++, asset_count++)
|
||||
{
|
||||
c8 *asset_name = g_Shader_Asset_Names[i];
|
||||
|
||||
@ -274,17 +86,14 @@ PackFiles(Arena *arena, FileHeader *header)
|
||||
|
||||
Assert((data_offset - prev_offset) == file_size, "File write size invalid");
|
||||
|
||||
shader_assets[i].data_offset = prev_offset;
|
||||
shader_assets[i].len = file_size;
|
||||
assets[asset_count].data_offset = prev_offset;
|
||||
assets[asset_count].len = file_size;
|
||||
assets[asset_count].type = AT_SHADER;
|
||||
|
||||
pFileClose(asset_file);
|
||||
}
|
||||
|
||||
Assert(pDirNavigate(return_dir) == 0, "Unable to return to previous directory");
|
||||
MoveToTextureDir(&return_dir);
|
||||
|
||||
AssetFile *texture_assets = MakeArray(arena, AssetFile, TEXTURE_ASSET_MAX);
|
||||
for (u32 i = 0; i < TEXTURE_ASSET_MAX; i++)
|
||||
for (u32 i = 0; i < TEXTURE_ASSET_MAX; i++, asset_count++)
|
||||
{
|
||||
c8 *asset_name = g_Texture_Asset_Names[i];
|
||||
|
||||
@ -312,22 +121,19 @@ PackFiles(Arena *arena, FileHeader *header)
|
||||
|
||||
Assert((data_offset - prev_offset) == loaded_length, "File write size invalid");
|
||||
|
||||
texture_assets[i].data_offset = prev_offset;
|
||||
texture_assets[i].len = loaded_length;
|
||||
texture_assets[i].texture_meta.w = u32(w);
|
||||
texture_assets[i].texture_meta.h = u32(h);
|
||||
texture_assets[i].texture_meta.ch = u32(ch);
|
||||
assets[asset_count].data_offset = prev_offset;
|
||||
assets[asset_count].len = loaded_length;
|
||||
assets[asset_count].type = AT_TEXTURE;
|
||||
assets[asset_count].texture_meta.w = u32(w);
|
||||
assets[asset_count].texture_meta.h = u32(h);
|
||||
assets[asset_count].texture_meta.ch = u32(ch);
|
||||
|
||||
stbi_image_free(image_bytes);
|
||||
|
||||
pFileClose(asset_file);
|
||||
}
|
||||
|
||||
Assert(pDirNavigate(return_dir) == 0, "Unable to return to previous directory");
|
||||
MoveToModelDir(&return_dir);
|
||||
|
||||
AssetFile *model_assets = MakeArray(arena, AssetFile, MODEL_ASSET_MAX);
|
||||
for (u32 i = 0; i < MODEL_ASSET_MAX; i++)
|
||||
for (u32 i = 0; i < MODEL_ASSET_MAX; i++, asset_count++)
|
||||
{
|
||||
c8 *asset_name = g_Model_Asset_Names[i];
|
||||
|
||||
@ -344,17 +150,17 @@ PackFiles(Arena *arena, FileHeader *header)
|
||||
|
||||
Assert((data_offset - prev_offset) == file_size, "File write size invalid");
|
||||
|
||||
model_assets[i].data_offset = prev_offset;
|
||||
model_assets[i].len = file_size;
|
||||
m3d_t *model = m3d_load(file_data, NULL, NULL, NULL);
|
||||
|
||||
assets[asset_count].data_offset = prev_offset;
|
||||
assets[asset_count].type = AT_MODEL;
|
||||
assets[asset_count].len = file_size;
|
||||
assets[asset_count].model_meta.i_count = u64(model->numface * 3);
|
||||
|
||||
pFileClose(asset_file);
|
||||
}
|
||||
|
||||
pFileWrite(file, header->asset_offsets[SHADER_ASSET], shader_assets, sizeof(AssetFile)*SHADER_ASSET_MAX);
|
||||
pFileWrite(file, header->asset_offsets[TEXTURE_ASSET], texture_assets, sizeof(AssetFile)*TEXTURE_ASSET_MAX);
|
||||
pFileWrite(file, header->asset_offsets[MODEL_ASSET], model_assets, sizeof(AssetFile)*MODEL_ASSET_MAX);
|
||||
|
||||
pDirNavigate(return_dir);
|
||||
pFileWrite(file, header->asset_offset, assets, sizeof(AssetFile)*asset_count);
|
||||
}
|
||||
|
||||
// ::Packer::Packing::Functions::End::
|
||||
@ -364,7 +170,7 @@ PackFiles(Arena *arena, FileHeader *header)
|
||||
// ::Packer::Tests::Functions::Start::
|
||||
|
||||
static inline void
|
||||
TestAssetIsCorrect(Arena *arena, c8 *file_name, AssetFile *file_info, AssetType type, pFile file)
|
||||
TestAssetIsCorrect(Arena *arena, c8 *file_name, AssetFile *file_info, pFile file)
|
||||
{
|
||||
pFile asset_file = pFileOpen(file_name, pFS_READ);
|
||||
u64 size = pFileLength(asset_file);
|
||||
@ -378,7 +184,7 @@ TestAssetIsCorrect(Arena *arena, c8 *file_name, AssetFile *file_info, AssetType
|
||||
|
||||
u8 *image_bytes;
|
||||
u64 image_length;
|
||||
if (type == TEXTURE_ASSET)
|
||||
if (file_info->type == TEXTURE_ASSET)
|
||||
{
|
||||
int ch = 4;
|
||||
int w, h, has_ch;
|
||||
@ -415,48 +221,30 @@ TestAssetPack(Arena *arena)
|
||||
FileHeader header;
|
||||
i64 offset = pFileRead(file, 0, &header, sizeof(FileHeader));
|
||||
|
||||
u64 asset_count = SHADER_ASSET_MAX + MODEL_ASSET_MAX + TEXTURE_ASSET_MAX;
|
||||
|
||||
Assert(header.magic_num == CreateMagicValue('s', 't', 'e', 'g'), "Magic number is incorrect");
|
||||
Assert(header.version == FILE_VERSION, "File version is incorrect");
|
||||
|
||||
Assert(header.asset_counts[SHADER_ASSET] == SHADER_ASSET_MAX, "Shader count incorrect");
|
||||
Assert(header.asset_counts[TEXTURE_ASSET] == TEXTURE_ASSET_MAX, "Texture count incorrect");
|
||||
Assert(header.asset_counts[SOUND_ASSET] == SOUND_ASSET_MAX, "Sound count incorrect");
|
||||
Assert(header.asset_counts[MODEL_ASSET] == MODEL_ASSET_MAX, "Model count incorrect");
|
||||
Assert(header.asset_counts == asset_count, "Asset count incorrect");
|
||||
|
||||
AssetTag *tags[ASSET_TYPE_MAX];
|
||||
AssetFile *files[ASSET_TYPE_MAX];
|
||||
|
||||
for (u32 i = 0; i < ASSET_TYPE_MAX; i++)
|
||||
{
|
||||
if (header.asset_counts[i] > 0)
|
||||
{
|
||||
files[i] = MakeArray(arena, AssetFile, header.asset_counts[i]);
|
||||
pFileRead(file, header.asset_offsets[i], files[i], sizeof(AssetFile)*header.asset_counts[i]);
|
||||
}
|
||||
}
|
||||
|
||||
c8 *return_dir = ".";
|
||||
MoveToShaderDir(&return_dir);
|
||||
AssetFile *files = MakeArray(arena, AssetFile, asset_count);
|
||||
pFileRead(file, header.asset_offset, files, sizeof(AssetFile)*header.asset_counts);
|
||||
|
||||
for (u32 i = 0; i < SHADER_ASSET_MAX; i++)
|
||||
u64 current_asset = 0;
|
||||
for (u32 i = 0; i < SHADER_ASSET_MAX; i++, current_asset++)
|
||||
{
|
||||
TestAssetIsCorrect(arena, g_Shader_Asset_Names[i], &files[SHADER_ASSET][i], SHADER_ASSET, file);
|
||||
TestAssetIsCorrect(arena, g_Shader_Asset_Names[i], files + current_asset, file);
|
||||
}
|
||||
|
||||
pDirNavigate(return_dir);
|
||||
MoveToTextureDir(&return_dir);
|
||||
|
||||
for (u32 i = 0; i < TEXTURE_ASSET_MAX; i++)
|
||||
for (u32 i = 0; i < TEXTURE_ASSET_MAX; i++, current_asset++)
|
||||
{
|
||||
TestAssetIsCorrect(arena, g_Texture_Asset_Names[i], &files[TEXTURE_ASSET][i], TEXTURE_ASSET, file);
|
||||
TestAssetIsCorrect(arena, g_Texture_Asset_Names[i], files + current_asset, file);
|
||||
}
|
||||
|
||||
pDirNavigate(return_dir);
|
||||
MoveToModelDir(&return_dir);
|
||||
|
||||
for (u32 i = 0; i < MODEL_ASSET_MAX; i++)
|
||||
for (u32 i = 0; i < MODEL_ASSET_MAX; i++, current_asset++)
|
||||
{
|
||||
TestAssetIsCorrect(arena, g_Model_Asset_Names[i], &files[MODEL_ASSET][i], MODEL_ASSET, file);
|
||||
TestAssetIsCorrect(arena, g_Model_Asset_Names[i], files + current_asset, file);
|
||||
}
|
||||
}
|
||||
|
||||
@ -496,8 +284,6 @@ main(int argc, c8 **argv)
|
||||
TestAssetPack(arena);
|
||||
}
|
||||
|
||||
#endif // BUILD_ASSET_CODEGEN
|
||||
|
||||
|
||||
|
||||
// ::Packer::Main::Functions::End::
|
||||
|
||||
19
src/packer.h
19
src/packer.h
@ -10,29 +10,21 @@
|
||||
|
||||
#define STG_NO_RENDERER
|
||||
|
||||
#define STB_SPRINTF_IMPLEMENTATION
|
||||
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
|
||||
#define M3D_IMPLEMENTATION
|
||||
|
||||
#include "shared_types.h"
|
||||
#include "platform/platform.h"
|
||||
#include "util.h"
|
||||
#define STG_IMPLEMENTATION
|
||||
|
||||
#include "stglib.h"
|
||||
|
||||
#include "assets.h"
|
||||
#include "ds.h"
|
||||
#include "allocators.h"
|
||||
|
||||
// ::ThirdParty::Include::Header::
|
||||
#include "stb/stb_sprintf.h"
|
||||
#include "stb/stb_image.h"
|
||||
#include "xxhash/xxhash.h"
|
||||
#include "fastlz/fastlz.h"
|
||||
#include "m3d/m3d.h"
|
||||
|
||||
#include "renderer.h"
|
||||
#include "game.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
// ::Packer::Macros::Header::
|
||||
@ -51,7 +43,6 @@ typedef struct FileMapping
|
||||
// ::Packer::Packing::Functions::Header::
|
||||
|
||||
void SetArrayLookups();
|
||||
void CodeGenAssetLookups(Arena *arena);
|
||||
void InitHeader(FileHeader *header);
|
||||
i32 WriteHeader(pFile file, FileHeader *header);
|
||||
void PackFiles(Arena *arena, FileHeader *header);
|
||||
@ -62,7 +53,7 @@ void MoveToModelDir(c8 **return_dir);
|
||||
// ::Packer::Tests::Functions::Header::
|
||||
|
||||
void TestAssetPack(Arena *arena);
|
||||
static inline void TestAssetIsCorrect(Arena *arena, c8 *file_name, AssetFile *file_info, AssetType type, pFile file);
|
||||
static inline void TestAssetIsCorrect(Arena *arena, c8 *file_name, AssetFile *file_info, pFile file);
|
||||
|
||||
// ::Packer::Main::Functions::Header::
|
||||
|
||||
|
||||
@ -1,16 +0,0 @@
|
||||
#if __linux__
|
||||
#include "platform/platform_linux.c"
|
||||
#endif
|
||||
|
||||
#if _WIN32
|
||||
#include "platform/platform_windows.c"
|
||||
#endif
|
||||
|
||||
#if __APPLE__ || __MACH__
|
||||
#error Not yet implemented
|
||||
#endif
|
||||
|
||||
#if __unix__ && !__linux__
|
||||
#error Not yet implemented
|
||||
#endif
|
||||
|
||||
@ -1,165 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
// ::Platform::Types::Header::
|
||||
|
||||
typedef struct pLibrary pLibrary;
|
||||
typedef struct pFunction pFunction;
|
||||
|
||||
// ::Platform::Declarations::Header::
|
||||
|
||||
typedef struct pGameInput pGameInput;
|
||||
|
||||
typedef enum KeyboardInput_e
|
||||
{
|
||||
KB_NONE,
|
||||
KB_A, KB_B, KB_C, KB_D, KB_E, KB_F, KB_G, KB_H, KB_I, KB_J, KB_K, KB_L, KB_M,
|
||||
KB_N, KB_O, KB_P, KB_Q, KB_R, KB_S, KB_T, KB_U, KB_V, KB_W, KB_X, KB_Y, KB_Z,
|
||||
KB_0, KB_1, KB_2, KB_3, KB_4, KB_5, KB_6, KB_7, KB_8, KB_9,
|
||||
KB_NUM_0, KB_NUM_1, KB_NUM_2, KB_NUM_3, KB_NUM_4, KB_NUM_5, KB_NUM_6, KB_NUM_7, KB_NUM_8, KB_NUM_9,
|
||||
KB_NUM_LOCK, KB_NUM_SLASH, KB_NUM_STAR, KB_NUM_MINUS, KB_NUM_PLUS, KB_NUM_ENTER, KB_NUM_PERIOD,
|
||||
KB_INSERT, KB_DELETE, KB_HOME, KB_END, KB_PAGE_UP, KB_PAGE_DOWN,
|
||||
KB_PRINT_SCREEN, KB_SCROLL_LOCK, KB_PAUSE,
|
||||
KB_COMMA, KB_PERIOD, KB_BACK_SLASH, KB_BACKSPACE, KB_FORWARD_SLASH, KB_MINUS, KB_PLUS,
|
||||
KB_F1, KB_F2, KB_F3, KB_F4, KB_F5, KB_F6, KB_F7, KB_F8, KB_F9, KB_F10, KB_F11, KB_F12,
|
||||
KB_UP, KB_DOWN, KB_LEFT, KB_RIGHT,
|
||||
KB_LEFT_CTRL, KB_LEFT_ALT, KB_LEFT_SHIFT, KB_LEFT_SUPER,
|
||||
KB_TAB, KB_CAPS_LOCK,
|
||||
KB_RIGHT_CTRL, KB_RIGHT_ALT, KB_RIGHT_SUPER, KB_RIGHT_SHIFT,
|
||||
KB_ENTER, KB_SPACE,
|
||||
KB_TILDE, KB_ESC,
|
||||
KB_SEMICOLON, KB_QUOTE, KB_LEFT_BRACE, KB_RIGHT_BRACE, KB_BACK_SPACE,
|
||||
|
||||
KB_MAX
|
||||
} pKeyboardInput;
|
||||
|
||||
// ::Platform::Includes::Header::
|
||||
|
||||
#if __linux__
|
||||
#include "platform/platform_linux.h"
|
||||
#endif
|
||||
|
||||
#if _WIN32
|
||||
#include "platform/platform_windows.h"
|
||||
#endif
|
||||
|
||||
#if __APPLE__ || __MACH__
|
||||
#error Not yet implemented
|
||||
#endif
|
||||
|
||||
#if __unix__ && !__linux__
|
||||
#error Not yet implemented
|
||||
#endif
|
||||
|
||||
// ::Platform::Enum::Header::
|
||||
|
||||
typedef enum MouseInput_e
|
||||
{
|
||||
M_NONE,
|
||||
M_LEFT_CLICK,
|
||||
M_MIDDLE_CLICK,
|
||||
M_RIGHT_CLICK,
|
||||
} pMouseInput;
|
||||
|
||||
typedef enum GameInputType_e
|
||||
{
|
||||
GI_NONE,
|
||||
GI_KEYBOARD,
|
||||
GI_MOUSE,
|
||||
GI_MOTION,
|
||||
GI_GAMEPAD,
|
||||
} pGameInputType;
|
||||
|
||||
// ::Platform::Types::Header::
|
||||
|
||||
|
||||
typedef u16Vec2 pWindowSize;
|
||||
|
||||
typedef i16Vec2 pMouseMotion;
|
||||
|
||||
typedef struct pGameInput
|
||||
{
|
||||
union
|
||||
{
|
||||
pKeyboardInput kb_code;
|
||||
pMouseInput m_code;
|
||||
pMouseMotion motion_ev;
|
||||
};
|
||||
b8 pressed;
|
||||
pGameInputType type;
|
||||
} pGameInput; // TODO: add gamepad input
|
||||
|
||||
typedef struct pThread pThread;
|
||||
|
||||
// ::Platform::ConsoleOut::Functions::Header::
|
||||
|
||||
i32 pWriteStdOut(void *buf, i32 len);
|
||||
i32 pWriteStdErr(void *buf, i32 len);
|
||||
|
||||
// ::Platform::pLibrary::Functions::Header::
|
||||
|
||||
b32 pLibraryLoad(const char *name, pLibrary *out_lib);
|
||||
b32 pFunctionLoad(const char *name, pLibrary *lib, pFunction *out_fn);
|
||||
|
||||
// ::Platform::Memory::Functions::Header::
|
||||
|
||||
rawptr pMemAlloc(usize size);
|
||||
rawptr pMemAllocZeroed(usize size);
|
||||
rawptr pMemRealloc(rawptr ptr, usize old_size, usize new_size);
|
||||
void pMemFree(rawptr ptr, usize size);
|
||||
usize pPageSize();
|
||||
|
||||
// ::Platform::Window::Functions::Header::
|
||||
|
||||
b32 pWindowInit(const char *window_name);
|
||||
pWindowSize pWindowGetSize();
|
||||
b32 pWindowShouldQuit();
|
||||
pPlatformWindow *pWindowGet();
|
||||
|
||||
// ::Platform::FileSystem::Functions::Header::
|
||||
|
||||
typedef enum e_pFSAccess
|
||||
{
|
||||
pFS_READ = 0x01,
|
||||
pFS_WRITE = 0x02,
|
||||
pFS_TRUNC = 0x04,
|
||||
pFS_APPEND = 0x08,
|
||||
pFS_CREATE = 0x10,
|
||||
} pFSAccess;
|
||||
|
||||
b32 pDirNavigate(c8 *dir);
|
||||
c8 **pDirGetFileNames(Arena *arena, u32 *count);
|
||||
static pFile pFileOpen(c8 *file_name, pFSAccess access);
|
||||
static void pFileClose(pFile file);
|
||||
static u64 pFileRead(pFile file, u64 offset, rawptr buf, u64 len);
|
||||
static u64 pFileWrite(pFile file, u64 offset, rawptr buf, u64 len);
|
||||
static u64 pFileSeek(pFile file, u64 pos);
|
||||
static u64 pFileLength(pFile file);
|
||||
static b32 pFSIsVisible(c8 *name, b32 is_dir);
|
||||
static b32 pDirIsVisible(c8 *dir_name);
|
||||
static b32 pFileIsVisible(c8 *file_name);
|
||||
static b32 pFileCanAccess(c8 *file_name, pFSAccess access);
|
||||
|
||||
// ::Platform::Profiling::Functions::Header::
|
||||
|
||||
static u64 pOSTimerFreq();
|
||||
static u64 pOSTimerRead();
|
||||
static inline u64 pCPUTimerRead();
|
||||
|
||||
// ::Platform::Async::Functions::Header::
|
||||
|
||||
static pThread pThreadInit(rawptr proc, rawptr param);
|
||||
static void pThreadSuspend(pThread *thread);
|
||||
static void pThreadWake(pThread *thread);
|
||||
static void pThreadKill();
|
||||
|
||||
// ::Platform::Atomics::Header::
|
||||
|
||||
static inline void pAtomicSignalFenceSeqCst();
|
||||
static inline u32 pAtomicFetchSubU32(u32 volatile *ptr, u32 count);
|
||||
static inline u32 pAtomicFetchIncrU32(u32 volatile *ptr);
|
||||
static inline void pAtomicIncrU8(u8 volatile *ptr);
|
||||
static inline void pAtomicIncrU32(u32 volatile *ptr);
|
||||
static inline u32 pAtomicLoadU32(u32 volatile *ptr);
|
||||
static inline void pAtomicStoreB32(b32 volatile *ptr, b32 value);
|
||||
static inline b32 pAtomicCompareExchangeB32(b32 volatile *ptr, b32 *expect, b32 desired);
|
||||
|
||||
@ -1,350 +0,0 @@
|
||||
// ::Platform::Linux::Globals::Start::
|
||||
|
||||
static pPlatformWindow
|
||||
linux_window =
|
||||
{
|
||||
.w = 1920,
|
||||
.h = 1080,
|
||||
};
|
||||
|
||||
b32
|
||||
g_Global_Quit = false;
|
||||
|
||||
// ::Platform::Linux::Globals::End::
|
||||
|
||||
// ::Platform::Linux::Print::Functions::Start::
|
||||
|
||||
i32
|
||||
pWriteStdOut(rawptr buf, i32 len)
|
||||
{
|
||||
return (i32)write(STDOUT, buf, len);
|
||||
}
|
||||
|
||||
i32
|
||||
pWriteStdErr(rawptr buf, i32 len)
|
||||
{
|
||||
return (i32)write(STDERR, buf, len);
|
||||
}
|
||||
|
||||
// ::Platform::Linux::Window::Functions::Start::
|
||||
|
||||
void
|
||||
pWindowEventsGet(pGameInput *inputs, u32 *i_count)
|
||||
{
|
||||
pWindowEventHandle(inputs, i_count, false);
|
||||
}
|
||||
|
||||
b32
|
||||
pWindowEventWaitFor(pGameInput *input)
|
||||
{
|
||||
u32 i_count;
|
||||
pWindowEventHandle(input, &i_count, true);
|
||||
return i_count > 0;
|
||||
}
|
||||
|
||||
void
|
||||
pWindowEventHandle(pGameInput *inputs, u32 *i_count, b32 wait_for_event)
|
||||
{
|
||||
b32 has_max_inputs = false;
|
||||
*i_count = 0;
|
||||
|
||||
do
|
||||
{
|
||||
xcb_generic_event_t *e;
|
||||
if (wait_for_event)
|
||||
e = xcb_wait_for_event(linux_window.connection);
|
||||
else
|
||||
e = xcb_poll_for_event(linux_window.connection);
|
||||
|
||||
// XCB_UNMAP_NOTIFY
|
||||
if (e != NULL)
|
||||
{
|
||||
switch (e->response_type & ~0x80)
|
||||
{
|
||||
case XCB_CLIENT_MESSAGE:
|
||||
{
|
||||
xcb_client_message_event_t *msg = (xcb_client_message_event_t *)e;
|
||||
if (msg->window != linux_window.window)
|
||||
break;
|
||||
|
||||
if (msg->data.data32[0] == linux_window.close_event)
|
||||
g_Global_Quit = true;
|
||||
} break;
|
||||
case XCB_CONFIGURE_NOTIFY:
|
||||
{
|
||||
xcb_configure_notify_event_t *configure_event = (xcb_configure_notify_event_t *)e;
|
||||
|
||||
if (linux_window.w != configure_event->width || linux_window.h != configure_event->height)
|
||||
{
|
||||
linux_window.w = configure_event->width;
|
||||
linux_window.h = configure_event->height;
|
||||
}
|
||||
} break;
|
||||
case XCB_KEY_RELEASE:
|
||||
case XCB_KEY_PRESS:
|
||||
{
|
||||
xcb_key_press_event_t *keyboard_e = (xcb_key_press_event_t *)e;
|
||||
b8 pressed = e->response_type == XCB_KEY_PRESS;
|
||||
xcb_keycode_t code = keyboard_e->detail;
|
||||
KeySym keysym = XkbKeycodeToKeysym(linux_window.display, (KeyCode)code, 0, 0);
|
||||
pKeyboardInput input = pInputEventConvert(keysym);
|
||||
if (input != KB_NONE)
|
||||
{
|
||||
inputs[*i_count].kb_code = input;
|
||||
inputs[*i_count].pressed = pressed;
|
||||
inputs[*i_count].type = GI_KEYBOARD;
|
||||
*i_count += 1;
|
||||
|
||||
if (*i_count == 10)
|
||||
has_max_inputs = true;
|
||||
}
|
||||
|
||||
} break;
|
||||
case XCB_BUTTON_PRESS:
|
||||
case XCB_BUTTON_RELEASE:
|
||||
{
|
||||
xcb_button_press_event_t *mouse_ev = (xcb_button_press_event_t *)e;
|
||||
b8 pressed = e->response_type == XCB_BUTTON_PRESS;
|
||||
pMouseInput input = M_NONE;
|
||||
|
||||
if (mouse_ev->detail == XCB_BUTTON_INDEX_1)
|
||||
input = M_LEFT_CLICK;
|
||||
else if (mouse_ev->detail == XCB_BUTTON_INDEX_2)
|
||||
input = M_MIDDLE_CLICK;
|
||||
else if (mouse_ev->detail == XCB_BUTTON_INDEX_3)
|
||||
input = M_RIGHT_CLICK;
|
||||
|
||||
if (input != M_NONE)
|
||||
{
|
||||
inputs[*i_count].m_code = input;
|
||||
inputs[*i_count].pressed = pressed;
|
||||
inputs[*i_count].type = GI_MOUSE;
|
||||
*i_count += 1;
|
||||
|
||||
if (*i_count == 10)
|
||||
has_max_inputs = true;
|
||||
}
|
||||
} break;
|
||||
case XCB_MOTION_NOTIFY:
|
||||
{
|
||||
xcb_motion_notify_event_t *move_ev = (xcb_motion_notify_event_t *)e;
|
||||
|
||||
if (move_ev->event_x > 0 || move_ev->event_y > 0)
|
||||
{
|
||||
inputs[*i_count].motion_ev.x = move_ev->event_x;
|
||||
inputs[*i_count].motion_ev.y = move_ev->event_y;
|
||||
inputs[*i_count].type = GI_MOTION;
|
||||
|
||||
*i_count += 1;
|
||||
if (*i_count == 10)
|
||||
has_max_inputs = true;
|
||||
}
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
free(e);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
} while(!wait_for_event && !has_max_inputs);
|
||||
}
|
||||
|
||||
pKeyboardInput
|
||||
pInputEventConvert(u32 x_key)
|
||||
{
|
||||
switch (x_key)
|
||||
{
|
||||
case XK_BackSpace: return KB_BACKSPACE;
|
||||
case XK_Return: return KB_ENTER;
|
||||
case XK_Tab: return KB_TAB;
|
||||
case XK_Pause: return KB_PAUSE;
|
||||
case XK_Caps_Lock: return KB_CAPS_LOCK;
|
||||
case XK_Escape: return KB_ESC;
|
||||
case XK_space: return KB_SPACE;
|
||||
case XK_Prior: return KB_PAGE_UP;
|
||||
case XK_Next: return KB_PAGE_DOWN;
|
||||
case XK_End: return KB_END;
|
||||
case XK_Home: return KB_HOME;
|
||||
case XK_Left: return KB_LEFT;
|
||||
case XK_Up: return KB_UP;
|
||||
case XK_Right: return KB_RIGHT;
|
||||
case XK_Down: return KB_DOWN;
|
||||
case XK_Print: return KB_PRINT_SCREEN;
|
||||
case XK_Insert: return KB_INSERT;
|
||||
case XK_Delete: return KB_DELETE;
|
||||
case XK_Meta_L:
|
||||
case XK_Super_L: return KB_LEFT_SUPER;
|
||||
case XK_Meta_R:
|
||||
case XK_Super_R: return KB_RIGHT_SUPER;
|
||||
case XK_KP_0: return KB_NUM_0;
|
||||
case XK_KP_1: return KB_NUM_1;
|
||||
case XK_KP_2: return KB_NUM_2;
|
||||
case XK_KP_3: return KB_NUM_3;
|
||||
case XK_KP_4: return KB_NUM_4;
|
||||
case XK_KP_5: return KB_NUM_5;
|
||||
case XK_KP_6: return KB_NUM_6;
|
||||
case XK_KP_7: return KB_NUM_7;
|
||||
case XK_KP_8: return KB_NUM_8;
|
||||
case XK_KP_9: return KB_NUM_9;
|
||||
case XK_multiply: return KB_NUM_STAR;
|
||||
case XK_KP_Subtract: return KB_NUM_MINUS;
|
||||
case XK_KP_Decimal: return KB_NUM_PERIOD;
|
||||
case XK_KP_Divide: return KB_NUM_SLASH;
|
||||
case XK_KP_Add: return KB_NUM_PLUS;
|
||||
case XK_F1: return KB_F1;
|
||||
case XK_F2: return KB_F2;
|
||||
case XK_F3: return KB_F3;
|
||||
case XK_F4: return KB_F4;
|
||||
case XK_F5: return KB_F5;
|
||||
case XK_F6: return KB_F6;
|
||||
case XK_F7: return KB_F7;
|
||||
case XK_F8: return KB_F8;
|
||||
case XK_F9: return KB_F9;
|
||||
case XK_F10: return KB_F10;
|
||||
case XK_F11: return KB_F11;
|
||||
case XK_F12: return KB_F12;
|
||||
case XK_Num_Lock: return KB_NUM_LOCK;
|
||||
case XK_Scroll_Lock: return KB_SCROLL_LOCK;
|
||||
case XK_Shift_L: return KB_LEFT_SHIFT;
|
||||
case XK_Shift_R: return KB_RIGHT_SHIFT;
|
||||
case XK_Control_L: return KB_LEFT_CTRL;
|
||||
case XK_Control_R: return KB_RIGHT_CTRL;
|
||||
case XK_Alt_L: return KB_LEFT_ALT;
|
||||
case XK_Alt_R: return KB_RIGHT_ALT;
|
||||
case XK_semicolon: return KB_SEMICOLON;
|
||||
case XK_bracketleft: return KB_LEFT_BRACE;
|
||||
case XK_bracketright: return KB_RIGHT_BRACE;
|
||||
case XK_plus: return KB_PLUS;
|
||||
case XK_comma: return KB_COMMA;
|
||||
case XK_minus: return KB_MINUS;
|
||||
case XK_backslash: return KB_BACK_SLASH;
|
||||
case XK_slash: return KB_FORWARD_SLASH;
|
||||
case XK_grave: return KB_TILDE;
|
||||
case XK_0: return KB_0;
|
||||
case XK_1: return KB_1;
|
||||
case XK_2: return KB_2;
|
||||
case XK_3: return KB_3;
|
||||
case XK_4: return KB_4;
|
||||
case XK_5: return KB_5;
|
||||
case XK_6: return KB_6;
|
||||
case XK_7: return KB_7;
|
||||
case XK_8: return KB_8;
|
||||
case XK_9: return KB_9;
|
||||
case XK_a:
|
||||
case XK_A: return KB_A;
|
||||
case XK_b:
|
||||
case XK_B: return KB_B;
|
||||
case XK_c:
|
||||
case XK_C: return KB_C;
|
||||
case XK_d:
|
||||
case XK_D: return KB_D;
|
||||
case XK_e:
|
||||
case XK_E: return KB_E;
|
||||
case XK_f:
|
||||
case XK_F: return KB_F;
|
||||
case XK_g:
|
||||
case XK_G: return KB_G;
|
||||
case XK_h:
|
||||
case XK_H: return KB_H;
|
||||
case XK_i:
|
||||
case XK_I: return KB_I;
|
||||
case XK_j:
|
||||
case XK_J: return KB_J;
|
||||
case XK_k:
|
||||
case XK_K: return KB_K;
|
||||
case XK_l:
|
||||
case XK_L: return KB_L;
|
||||
case XK_m:
|
||||
case XK_M: return KB_M;
|
||||
case XK_n:
|
||||
case XK_N: return KB_N;
|
||||
case XK_o:
|
||||
case XK_O: return KB_O;
|
||||
case XK_p:
|
||||
case XK_P: return KB_P;
|
||||
case XK_q:
|
||||
case XK_Q: return KB_Q;
|
||||
case XK_r:
|
||||
case XK_R: return KB_R;
|
||||
case XK_s:
|
||||
case XK_S: return KB_S;
|
||||
case XK_t:
|
||||
case XK_T: return KB_T;
|
||||
case XK_u:
|
||||
case XK_U: return KB_U;
|
||||
case XK_v:
|
||||
case XK_V: return KB_V;
|
||||
case XK_w:
|
||||
case XK_W: return KB_W;
|
||||
case XK_x:
|
||||
case XK_X: return KB_X;
|
||||
case XK_y:
|
||||
case XK_Y: return KB_Y;
|
||||
case XK_z:
|
||||
case XK_Z: return KB_Z;
|
||||
default: return KB_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
// ::Platform::Linux::Window::Functions::Start::
|
||||
|
||||
|
||||
|
||||
// ::Platform::Linux::Utils::Functions::Start::
|
||||
|
||||
b32
|
||||
pSyscallErrCheck(void *ptr)
|
||||
{
|
||||
return (isize)ptr == SYS_ERR ? true : false;
|
||||
}
|
||||
|
||||
// ::Platform::Linux::Utils::Functions::End::
|
||||
|
||||
|
||||
|
||||
// ::Platform::Linux::Async::Start::
|
||||
|
||||
static pThread
|
||||
pThreadInit(rawptr proc, rawptr param)
|
||||
{
|
||||
pThread thread = {0};
|
||||
Assert(pthread_mutex_init(&thread.mut, NULL) == 0, "pthread_mutex_init failure");
|
||||
Assert(pthread_cond_init(&thread.cond, NULL) == 0, "pthread_cond_init failure");
|
||||
Assert(pthread_create(&thread.handle, NULL, proc, param) == 0, "pthread_create failure");
|
||||
|
||||
return thread;
|
||||
}
|
||||
|
||||
static void
|
||||
pThreadSuspend(pThread *thread)
|
||||
{
|
||||
pthread_mutex_lock(&thread->mut);
|
||||
pthread_cond_wait(&thread->cond, &thread->mut);
|
||||
pthread_mutex_unlock(&thread->mut);
|
||||
}
|
||||
|
||||
static void
|
||||
pThreadWake(pThread *thread)
|
||||
{
|
||||
pthread_cond_signal(&thread->cond);
|
||||
}
|
||||
|
||||
static void
|
||||
pThreadKill()
|
||||
{
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
// ::Platform::Linux::Async::Start::
|
||||
|
||||
|
||||
|
||||
// ::Platform::Linux::Includes::CFile::
|
||||
|
||||
#include "platform_linux_public.c"
|
||||
|
||||
|
||||
@ -1,101 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <xcb/xcb.h>
|
||||
#include <X11/XKBlib.h>
|
||||
#include <X11/Xlib-xcb.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/keysym.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/types.h>
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <dlfcn.h>
|
||||
#include <nmmintrin.h>
|
||||
#include <immintrin.h>
|
||||
#include <sched.h>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include <x86intrin.h>
|
||||
#include <sys/time.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
// ::Platform::Linux::Defines::Header::
|
||||
|
||||
#define SYS_ERR -1
|
||||
|
||||
#define STDIN 0
|
||||
#define STDOUT 1
|
||||
#define STDERR 2
|
||||
|
||||
// ::Platform::Linux::Macros::Header::
|
||||
|
||||
#define XCB_CHECK_CURRENT_ERROR(window, error, message) do { \
|
||||
error = xcb_request_check(window->connection, cookie); \
|
||||
if (error != NULL) { \
|
||||
EPrintf("%s ERROR CODE: %d\n", message, error->error_code); \
|
||||
free(error); \
|
||||
return false; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define XCB_CHECK_ERROR(window, cookie, error, message) do { \
|
||||
error = xcb_request_check(window->connection, cookie); \
|
||||
XCB_CHECK_CURRENT_ERROR(window, error, message); \
|
||||
} while (0)
|
||||
|
||||
// ::Platform::Linux::Types::Header
|
||||
|
||||
typedef int pFile;
|
||||
|
||||
typedef struct pThread
|
||||
{
|
||||
pthread_t handle;
|
||||
pthread_cond_t cond;
|
||||
pthread_mutex_t mut;
|
||||
} pThread;
|
||||
|
||||
typedef struct pPlatformWindow
|
||||
{
|
||||
Display *display;
|
||||
xcb_connection_t *connection;
|
||||
xcb_window_t window;
|
||||
xcb_atom_t close_event;
|
||||
xcb_atom_t minimize_event;
|
||||
u16 w, h;
|
||||
} pPlatformWindow;
|
||||
|
||||
typedef struct pLibrary
|
||||
{
|
||||
void *lib;
|
||||
} pLibrary;
|
||||
|
||||
typedef struct pFunction
|
||||
{
|
||||
void *fn;
|
||||
} pFunction;
|
||||
|
||||
typedef int pFile;
|
||||
|
||||
// ::Platform::Linux::Print::Functions::Header::
|
||||
|
||||
i32 pWrite(int fd, void const *str, isize count);
|
||||
|
||||
// ::Platform::Linux::Window::Functions::Header::
|
||||
|
||||
void pWindowEventsGet(pGameInput *inputs, u32 *i_count);
|
||||
b32 pWindowEventWaitFor(pGameInput *input);
|
||||
void pWindowEventHandle(pGameInput *inputs, u32 *input_count, b32 wait_for_event);
|
||||
pKeyboardInput pInputEventConvert(u32 x_key);
|
||||
|
||||
// ::Platform::Linux::Utils::Functions::Header::
|
||||
|
||||
b32 pSyscallErrCheck(void *ptr);
|
||||
|
||||
@ -1,472 +0,0 @@
|
||||
// ::Platform::Functions::pLibrary::Start::
|
||||
|
||||
b32
|
||||
pLibraryLoad(const char *name, pLibrary *out_lib)
|
||||
{
|
||||
if (!name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
out_lib->lib = dlopen(name, RTLD_NOW);
|
||||
if (!out_lib->lib) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
b32
|
||||
pFunctionLoad(const char *name, pLibrary *lib, pFunction *out_fn)
|
||||
{
|
||||
if (!name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
out_fn->fn = dlsym(lib->lib, name);
|
||||
if (!out_fn->fn) {
|
||||
Printf("unable to find function\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ::Platform::Functions::pLibrary::End::
|
||||
|
||||
|
||||
|
||||
// ::Platform::Functions::Print::Start::
|
||||
|
||||
|
||||
// ::Platform::Functions::Print::End::
|
||||
|
||||
|
||||
|
||||
// ::Platform::Functions::Memory::Start::
|
||||
|
||||
rawptr
|
||||
pMemAlloc(usize size)
|
||||
{
|
||||
rawptr addr = mmap(
|
||||
NULL,
|
||||
size,
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_ANON | MAP_PRIVATE,
|
||||
-1,
|
||||
0
|
||||
);
|
||||
|
||||
if (pSyscallErrCheck(addr)) addr = NULL;
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
rawptr
|
||||
pMemAllocZeroed(usize size)
|
||||
{
|
||||
rawptr ptr = pMemAlloc(size);
|
||||
MemZero(ptr, size);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
rawptr
|
||||
pMemRealloc(rawptr ptr, usize old_size, usize new_size)
|
||||
{
|
||||
rawptr addr = mremap(
|
||||
ptr,
|
||||
old_size,
|
||||
new_size,
|
||||
MAP_ANON | MAP_PRIVATE
|
||||
);
|
||||
|
||||
if (pSyscallErrCheck(addr)) addr = NULL;
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
void
|
||||
pMemFree(rawptr ptr, usize size)
|
||||
{
|
||||
Assert(munmap(ptr, size) == 0, "munmap failed");
|
||||
}
|
||||
|
||||
usize
|
||||
pPageSize()
|
||||
{
|
||||
return (usize)sysconf(_SC_PAGESIZE);
|
||||
}
|
||||
|
||||
// ::Platform::Functions::Memory::End::
|
||||
|
||||
|
||||
|
||||
// ::Platform::Functions::Window::Start::
|
||||
|
||||
b32
|
||||
pWindowInit(const char *window_name)
|
||||
{
|
||||
pPlatformWindow *window = &linux_window;
|
||||
|
||||
window->display = XOpenDisplay(NULL);
|
||||
if (!window->display)
|
||||
return false;
|
||||
|
||||
window->connection = XGetXCBConnection(window->display);
|
||||
|
||||
if (!window->connection)
|
||||
return false;
|
||||
|
||||
xcb_void_cookie_t cookie;
|
||||
xcb_generic_error_t *error;
|
||||
|
||||
const xcb_setup_t *setup = xcb_get_setup(window->connection);
|
||||
xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup);
|
||||
xcb_screen_t *screen = iter.data;
|
||||
|
||||
const int event_mask = XCB_EVENT_MASK_EXPOSURE |
|
||||
XCB_EVENT_MASK_KEY_PRESS |
|
||||
XCB_EVENT_MASK_KEY_RELEASE |
|
||||
XCB_EVENT_MASK_BUTTON_PRESS |
|
||||
XCB_EVENT_MASK_BUTTON_RELEASE |
|
||||
XCB_EVENT_MASK_POINTER_MOTION |
|
||||
XCB_EVENT_MASK_STRUCTURE_NOTIFY;
|
||||
|
||||
const int val_win[] = {screen->black_pixel, event_mask};
|
||||
const int val_mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
|
||||
|
||||
window->window = xcb_generate_id(window->connection);
|
||||
|
||||
cookie = xcb_create_window(
|
||||
window->connection,
|
||||
XCB_COPY_FROM_PARENT,
|
||||
window->window,
|
||||
screen->root,
|
||||
0, // x pos
|
||||
0, // y pos
|
||||
window->w, // width
|
||||
window->h, // height
|
||||
0,
|
||||
XCB_WINDOW_CLASS_INPUT_OUTPUT,
|
||||
screen->root_visual,
|
||||
val_mask,
|
||||
val_win
|
||||
);
|
||||
XCB_CHECK_ERROR(window, cookie, error, "Failed to create window.");
|
||||
|
||||
cookie = xcb_map_window_checked(window->connection, window->window);
|
||||
XCB_CHECK_ERROR(window, cookie, error, "Failed to map window.");
|
||||
|
||||
cookie = xcb_change_property_checked(
|
||||
window->connection,
|
||||
XCB_PROP_MODE_REPLACE,
|
||||
window->window,
|
||||
XCB_ATOM_WM_NAME,
|
||||
XCB_ATOM_STRING,
|
||||
8,
|
||||
StrLen(window_name),
|
||||
window_name
|
||||
);
|
||||
XCB_CHECK_ERROR(window, cookie, error, "Failed to rename window.");
|
||||
|
||||
xcb_intern_atom_cookie_t c_proto = xcb_intern_atom(window->connection, 1, 12, "WM_PROTOCOLS");
|
||||
xcb_intern_atom_reply_t *r_proto = xcb_intern_atom_reply(window->connection, c_proto, &error);
|
||||
XCB_CHECK_CURRENT_ERROR(window, error, "Failed to get WM_PROTOCOLS.");
|
||||
|
||||
xcb_intern_atom_cookie_t c_close = xcb_intern_atom(window->connection, 0, 16, "WM_DELETE_WINDOW");
|
||||
xcb_intern_atom_reply_t *r_close = xcb_intern_atom_reply(window->connection, c_close, &error);
|
||||
XCB_CHECK_CURRENT_ERROR(window, error, "Failed to get WM_DELETE_WINDOW.");
|
||||
|
||||
xcb_intern_atom_cookie_t c_minimize = xcb_intern_atom(window->connection, 0, 20, "_NET_WM_STATE_HIDDEN");
|
||||
xcb_intern_atom_reply_t *r_minimize = xcb_intern_atom_reply(window->connection, c_minimize, &error);
|
||||
XCB_CHECK_CURRENT_ERROR(window, error, "Failed to get _NET_WM_STATE_HIDDEN");
|
||||
|
||||
cookie = xcb_change_property_checked(
|
||||
window->connection,
|
||||
XCB_PROP_MODE_REPLACE,
|
||||
window->window,
|
||||
r_proto->atom,
|
||||
XCB_ATOM_ATOM,
|
||||
32,
|
||||
1,
|
||||
&r_close->atom
|
||||
);
|
||||
XCB_CHECK_ERROR(window, cookie, error, "Failed to set window close event.");
|
||||
|
||||
window->close_event = r_close->atom;
|
||||
window->minimize_event = r_minimize->atom;
|
||||
|
||||
free(r_proto);
|
||||
free(r_close);
|
||||
free(r_minimize);
|
||||
|
||||
xcb_map_window(window->connection, window->window);
|
||||
|
||||
i32 stream_result = xcb_flush(window->connection);
|
||||
if (stream_result <= 0)
|
||||
{
|
||||
Printfln("Error flushing the stream: %d", stream_result);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
pWindowSize
|
||||
pWindowGetSize()
|
||||
{
|
||||
return (pWindowSize) {
|
||||
.w = linux_window.w,
|
||||
.h = linux_window.h,
|
||||
};
|
||||
}
|
||||
|
||||
pPlatformWindow
|
||||
*pWindowGet()
|
||||
{
|
||||
return &linux_window;
|
||||
}
|
||||
|
||||
b32
|
||||
pWindowShouldQuit()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// ::Platform::Functions::Window::End::
|
||||
|
||||
|
||||
|
||||
// ::Platform::FileSystem::Functions::Start::
|
||||
|
||||
b32
|
||||
pDirNavigate(c8 *dir)
|
||||
{
|
||||
return chdir(dir);
|
||||
}
|
||||
|
||||
static pFile
|
||||
pFileOpen(c8 *file_name, pFSAccess acc)
|
||||
{
|
||||
int flags = 0;
|
||||
if (BitEq(acc, pFS_READ) && BitEq(acc, pFS_WRITE))
|
||||
flags = O_RDWR;
|
||||
else if (BitEq(acc, pFS_READ))
|
||||
flags = O_RDONLY;
|
||||
else if (BitEq(acc, pFS_WRITE))
|
||||
flags = O_WRONLY;
|
||||
|
||||
if (BitEq(acc, pFS_TRUNC))
|
||||
{
|
||||
flags |= O_TRUNC;
|
||||
}
|
||||
else if (BitEq(acc, pFS_APPEND))
|
||||
flags |= O_APPEND;
|
||||
|
||||
if (BitEq(acc, pFS_CREATE))
|
||||
flags |= O_CREAT;
|
||||
|
||||
return open(file_name, flags, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP);
|
||||
}
|
||||
|
||||
static void
|
||||
pFileClose(pFile file)
|
||||
{
|
||||
close(file);
|
||||
}
|
||||
|
||||
// TODO: make these more resilient
|
||||
static u64
|
||||
pFileRead(pFile file, u64 offset, rawptr buf, u64 len)
|
||||
{
|
||||
lseek(file, (isize)offset, SEEK_SET);
|
||||
return read(file, buf, (usize)len);
|
||||
}
|
||||
|
||||
static u64
|
||||
pFileWrite(pFile file, u64 offset, rawptr buf, u64 len)
|
||||
{
|
||||
lseek(file, (isize)offset, SEEK_SET);
|
||||
return write(file, buf, (usize)len);
|
||||
}
|
||||
|
||||
static u64
|
||||
pFileSeek(pFile file, u64 pos)
|
||||
{
|
||||
return (u64)lseek(file, (isize)pos, SEEK_SET);
|
||||
}
|
||||
|
||||
static u64
|
||||
pFileLength(pFile file)
|
||||
{
|
||||
isize offset = lseek(file, 0, SEEK_CUR);
|
||||
isize size = lseek(file, 0, SEEK_END);
|
||||
lseek(file, offset, SEEK_SET);
|
||||
|
||||
if (size == -1)
|
||||
size = UINT64_MAX;
|
||||
|
||||
return (u64)size;
|
||||
}
|
||||
|
||||
c8 **
|
||||
pDirGetFileNames(Arena *arena, u32 *count)
|
||||
{
|
||||
struct dirent *dir;
|
||||
|
||||
DIR *d = opendir(".");
|
||||
|
||||
*count = 0;
|
||||
if (d)
|
||||
{
|
||||
while ((dir = readdir(d)) != NULL)
|
||||
{
|
||||
if (!StrEq(dir->d_name, ".") && !StrEq(dir->d_name, ".."))
|
||||
*count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
c8 **file_names = MakeArray(arena, u8*, *count);
|
||||
|
||||
d = opendir(".");
|
||||
*count = 0;
|
||||
if (d)
|
||||
{
|
||||
while ((dir = readdir(d)) != NULL)
|
||||
{
|
||||
if (!StrEq(dir->d_name, ".") && !StrEq(dir->d_name, ".."))
|
||||
{
|
||||
i32 str_len = StrLen(dir->d_name);
|
||||
file_names[*count] = MakeArray(arena, u8, str_len);
|
||||
MemCpy(file_names[*count], dir->d_name, str_len);
|
||||
*count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (c8 **)file_names;
|
||||
}
|
||||
|
||||
static b32
|
||||
pFSIsVisible(c8 *name, b32 is_dir)
|
||||
{
|
||||
b32 found = false;
|
||||
|
||||
struct dirent *dir;
|
||||
DIR *d = opendir(".");
|
||||
u8 type = is_dir ? DT_DIR : DT_REG;
|
||||
|
||||
if (d)
|
||||
{
|
||||
while ((dir = readdir(d)) != NULL)
|
||||
{
|
||||
if (StrEq(name, dir->d_name) && dir->d_type == type)
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
static b32
|
||||
pDirIsVisible(c8 *dir_name)
|
||||
{
|
||||
return pFSIsVisible(dir_name, true);
|
||||
}
|
||||
|
||||
static b32
|
||||
pFileIsVisible(c8 *file_name)
|
||||
{
|
||||
return pFSIsVisible(file_name, false);
|
||||
}
|
||||
|
||||
static b32
|
||||
pFileCanAccess(c8 *file_name, pFSAccess file_access)
|
||||
{
|
||||
int a = 0;
|
||||
if (BitEq(file_access, pFS_READ))
|
||||
a |= R_OK;
|
||||
if (BitEq(file_access, pFS_WRITE))
|
||||
a |= W_OK;
|
||||
|
||||
return access(file_name, a) == 0;
|
||||
}
|
||||
|
||||
// ::Platform::FileSystem::Functions::End::
|
||||
|
||||
|
||||
|
||||
// ::Platform::Profiling::Functions::Start::
|
||||
|
||||
static u64
|
||||
pOSTimerFreq()
|
||||
{
|
||||
return 1000000;
|
||||
}
|
||||
|
||||
static u64
|
||||
pOSTimerRead()
|
||||
{
|
||||
struct timeval value;
|
||||
gettimeofday(&value, 0);
|
||||
|
||||
return pOSTimerFreq() * u64(value.tv_sec) + u64(value.tv_usec);
|
||||
}
|
||||
|
||||
static inline u64
|
||||
pCPUTimerRead()
|
||||
{
|
||||
return __rdtsc();
|
||||
}
|
||||
|
||||
// ::Platform::Profiling::Functions::End::
|
||||
|
||||
|
||||
|
||||
// ::Platform::Atomics::Functions::Start::
|
||||
|
||||
static inline void
|
||||
pAtomicSignalFenceSeqCst()
|
||||
{
|
||||
__atomic_signal_fence(__ATOMIC_SEQ_CST);
|
||||
}
|
||||
|
||||
static inline u32
|
||||
pAtomicFetchSubU32(u32 volatile *ptr, u32 count)
|
||||
{
|
||||
return __atomic_fetch_sub(ptr, count, __ATOMIC_ACQUIRE);
|
||||
}
|
||||
|
||||
static inline u32
|
||||
pAtomicFetchIncrU32(u32 volatile *ptr)
|
||||
{
|
||||
return __atomic_fetch_add(ptr, (u32)1, __ATOMIC_ACQUIRE);
|
||||
}
|
||||
|
||||
static inline void
|
||||
pAtomicIncrU32(u32 volatile *ptr)
|
||||
{
|
||||
__atomic_fetch_add(ptr, (u32)1, __ATOMIC_RELEASE);
|
||||
}
|
||||
|
||||
static inline u32
|
||||
pAtomicLoadU32(u32 volatile *ptr)
|
||||
{
|
||||
return __atomic_load_n(ptr, __ATOMIC_ACQUIRE);
|
||||
}
|
||||
|
||||
static inline void
|
||||
pAtomicStoreB32(b32 volatile *ptr, b32 value)
|
||||
{
|
||||
__atomic_store_n(ptr, value, __ATOMIC_RELEASE);
|
||||
}
|
||||
|
||||
static inline b32
|
||||
pAtomicCompareExchangeB32(b32 volatile *ptr, b32 *expected, b32 desired)
|
||||
{
|
||||
return __atomic_compare_exchange_n(ptr, expected, desired, true, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED);
|
||||
}
|
||||
|
||||
// ::Platform::Atomics::Functions::End::
|
||||
@ -1,175 +0,0 @@
|
||||
// ::Platform::Windows::Globals::Start::
|
||||
|
||||
HINSTANCE
|
||||
g_Win32_Instance = {0};
|
||||
pPlatformWindow
|
||||
g_Win32_Window = {0};
|
||||
b32
|
||||
g_Global_Quit = false;
|
||||
|
||||
// ::Platform::Windows::Globals::End::
|
||||
|
||||
LRESULT CALLBACK
|
||||
WindowProc(HWND window, UINT message, WPARAM w_param, LPARAM l_param)
|
||||
{
|
||||
LRESULT result = 0;
|
||||
|
||||
switch (message)
|
||||
{
|
||||
case WM_SIZE:
|
||||
{
|
||||
Printfln("Window resizing");
|
||||
g_Win32_Window.w = LOWORD(l_param);
|
||||
g_Win32_Window.h = HIWORD(l_param);
|
||||
rResolutionSet(g_Win32_Window.w, g_Win32_Window.h);
|
||||
} break;
|
||||
case WM_DESTROY: // TODO(MA): Probably handle these separately but for now, they're together
|
||||
case WM_CLOSE:
|
||||
{
|
||||
Printf("quitting");
|
||||
g_Global_Quit = true;
|
||||
} break;
|
||||
case WM_ACTIVATEAPP:
|
||||
{
|
||||
OutputDebugStringA("WM_ACTIVATEAPP\n");
|
||||
} break;
|
||||
default:
|
||||
{
|
||||
result = DefWindowProc(window, message, w_param, l_param);
|
||||
} break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
b32
|
||||
pLibraryLoad(const char *name, pLibrary *out_lib)
|
||||
{
|
||||
b32 success = true;
|
||||
|
||||
out_lib->module = LoadLibraryA("vulkan-1.dll");
|
||||
if (!out_lib->module)
|
||||
success = false;
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
b32
|
||||
pFunctionLoad(const char *name, pLibrary *lib, pFunction *out_fn)
|
||||
{
|
||||
b32 success = true;
|
||||
|
||||
out_fn->fn = GetProcAddress(lib->module, name);
|
||||
if (!out_fn->fn)
|
||||
success = false;
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
usize
|
||||
pPageSize()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
i32
|
||||
_Write(void const *str, DWORD std_handle)
|
||||
{
|
||||
DWORD written;
|
||||
BOOL success = WriteFile(GetStdHandle(std_handle), str, StrLen(str), &written, NULL);
|
||||
return success ? (i32)written : -1;
|
||||
}
|
||||
|
||||
b32
|
||||
pWindowInit(const char *window_name)
|
||||
{
|
||||
b32 success = true;
|
||||
|
||||
WNDCLASS window_class = {
|
||||
.style = CS_OWNDC|CS_HREDRAW|CS_VREDRAW,
|
||||
.lpfnWndProc = WindowProc,
|
||||
.hInstance = g_Win32_Instance,
|
||||
.lpszClassName = WINDOW_CLASS_NAME,
|
||||
};
|
||||
|
||||
ATOM r_class_atom = RegisterClass(&window_class);
|
||||
if (!r_class_atom)
|
||||
success = false;
|
||||
|
||||
if (success)
|
||||
{
|
||||
HWND window_handle = CreateWindowExA(
|
||||
0,
|
||||
window_class.lpszClassName,
|
||||
window_name,
|
||||
WS_OVERLAPPEDWINDOW|WS_VISIBLE,
|
||||
CW_USEDEFAULT,
|
||||
CW_USEDEFAULT,
|
||||
CW_USEDEFAULT,
|
||||
CW_USEDEFAULT,
|
||||
0,
|
||||
0,
|
||||
g_Win32_Instance,
|
||||
0
|
||||
);
|
||||
|
||||
if (!window_handle)
|
||||
success = false;
|
||||
else
|
||||
g_Win32_Window.handle = window_handle;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
pPlatformWindow *
|
||||
pWindowGet()
|
||||
{
|
||||
return &g_Win32_Window;
|
||||
}
|
||||
|
||||
void
|
||||
pWindowEventsGet()
|
||||
{
|
||||
BOOL has_msg = false;
|
||||
MSG message;
|
||||
do
|
||||
{
|
||||
has_msg = PeekMessage(&message, 0, 0, 0, PM_REMOVE);
|
||||
if (has_msg > 0)
|
||||
{
|
||||
TranslateMessage(&message);
|
||||
DispatchMessage(&message);
|
||||
}
|
||||
}
|
||||
while (has_msg);
|
||||
}
|
||||
|
||||
void
|
||||
pWindowEventWaitFor()
|
||||
{
|
||||
MSG message;
|
||||
BOOL message_result = GetMessageA(&message, 0, 0, 0);
|
||||
if (message_result > 0)
|
||||
{
|
||||
TranslateMessage(&message);
|
||||
DispatchMessage(&message);
|
||||
}
|
||||
}
|
||||
|
||||
b32
|
||||
pWindowShouldQuit()
|
||||
{
|
||||
return g_Global_Quit;
|
||||
}
|
||||
|
||||
pWindowSize
|
||||
pWindowGetSize()
|
||||
{
|
||||
return (pWindowSize){ .w = g_Win32_Window.w, .h = g_Win32_Window.h };
|
||||
}
|
||||
|
||||
// ::Platform::Windows::Includes::CFile::
|
||||
|
||||
#include "platform_windows_public.c"
|
||||
|
||||
@ -1,40 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <immintrin.h>
|
||||
|
||||
// ::Platform::Windows::Defines::Header::
|
||||
|
||||
#define WINDOW_CLASS_NAME "GearsWindowClass"
|
||||
|
||||
// ::Platform::Windows::Types::Header::
|
||||
|
||||
typedef struct pPlatformWindow
|
||||
{
|
||||
HINSTANCE instance;
|
||||
HWND handle;
|
||||
u16 h, w;
|
||||
b32 resize_requested;
|
||||
} pPlatformWindow;
|
||||
|
||||
typedef struct pLibrary
|
||||
{
|
||||
HMODULE module;
|
||||
} pLibrary;
|
||||
|
||||
typedef struct pFunction
|
||||
{
|
||||
FARPROC fn;
|
||||
} pFunction;
|
||||
|
||||
typedef struct pThread
|
||||
{
|
||||
HANDLE handle;
|
||||
} pThread;
|
||||
|
||||
// ::Platform::Windows::Functions::::Header::
|
||||
|
||||
void pWindowEventsGet();
|
||||
void pWindowEventWaitFor();
|
||||
@ -1,163 +0,0 @@
|
||||
|
||||
// ::Platform::Windows::Memory::Start::
|
||||
|
||||
rawptr
|
||||
pMemAlloc(usize size)
|
||||
{
|
||||
return (rawptr)VirtualAlloc(0, size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
|
||||
}
|
||||
|
||||
rawptr
|
||||
pMemAllocZeroed(usize size)
|
||||
{
|
||||
rawptr mem = pMemAlloc(size);
|
||||
MemZero(mem, size);
|
||||
return mem;
|
||||
}
|
||||
|
||||
void
|
||||
pMemFree(rawptr ptr, usize size)
|
||||
{
|
||||
Assert(VirtualFree(ptr, size, MEM_RELEASE), "pMemFree failure");
|
||||
}
|
||||
|
||||
// ::Platform::Windows::Memory::End::
|
||||
|
||||
|
||||
|
||||
// ::Platform::Windows::Print::Start::
|
||||
|
||||
i32
|
||||
pWriteStdOut(rawptr buf, i32 len)
|
||||
{
|
||||
return WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), buf, len, NULL, NULL);
|
||||
}
|
||||
|
||||
i32
|
||||
pWriteStdErr(rawptr buf, i32 len)
|
||||
{
|
||||
return WriteConsole(GetStdHandle(STD_ERROR_HANDLE), buf, len, NULL, NULL);
|
||||
}
|
||||
|
||||
// ::Platform::Windows::Print::End::
|
||||
|
||||
|
||||
|
||||
// ::Platform::Functions::Directory::Start::
|
||||
|
||||
b32
|
||||
pDirNavigate(c8 *dir)
|
||||
{
|
||||
return !(b32)SetCurrentDirectory(dir);
|
||||
}
|
||||
|
||||
// ::Platform::Functions::Directory::End::
|
||||
|
||||
|
||||
|
||||
// ::Platform::Windows::Profiling::Functions::Start::
|
||||
|
||||
static inline u64
|
||||
pCPUTimerRead()
|
||||
{
|
||||
return __rdtsc();
|
||||
}
|
||||
|
||||
// ::Platform::Windows::Profiling::Functions::End::
|
||||
|
||||
|
||||
|
||||
// ::Platform::Windows::Async::Start::
|
||||
|
||||
static pThread
|
||||
pThreadInit(rawptr proc, rawptr param)
|
||||
{
|
||||
pThread thread = {0};
|
||||
CreateThread(NULL, 0, proc, param, 0, NULL);
|
||||
|
||||
return thread;
|
||||
}
|
||||
|
||||
static void
|
||||
pThreadSuspend(pThread *thread)
|
||||
{
|
||||
SuspendThread(thread->handle);
|
||||
}
|
||||
|
||||
static void
|
||||
pThreadWake(pThread *thread)
|
||||
{
|
||||
ResumeThread(thread->handle);
|
||||
}
|
||||
|
||||
static void
|
||||
pThreadKill()
|
||||
{
|
||||
ExitThread(0);
|
||||
}
|
||||
|
||||
// ::Platform::Windows::Async::End::
|
||||
|
||||
|
||||
|
||||
// ::Platform::Windows::Atomics::Start::
|
||||
|
||||
|
||||
static inline void
|
||||
pAtomicSignalFenceSeqCst()
|
||||
{
|
||||
_ReadWriteBarrier();
|
||||
}
|
||||
|
||||
static inline u32
|
||||
pAtomicFetchSubU32(u32 volatile *ptr, u32 count)
|
||||
{
|
||||
LONG decrement = (LONG)count;
|
||||
return (u32)InterlockedAddAcquire((LONG volatile *)ptr, -decrement) + decrement;
|
||||
}
|
||||
|
||||
static inline u32
|
||||
pAtomicFetchIncrU32(u32 volatile *ptr)
|
||||
{
|
||||
return (u32)InterlockedIncrementAcquire((LONG volatile *)ptr) - 1;
|
||||
}
|
||||
|
||||
static inline void
|
||||
pAtomicIncrU32(u32 volatile *ptr)
|
||||
{
|
||||
InterlockedIncrementRelease((LONG volatile *)ptr);
|
||||
}
|
||||
|
||||
static inline u32
|
||||
pAtomicLoadU32(u32 volatile *ptr)
|
||||
{
|
||||
return (u32)InterlockedOrAcquire((LONG volatile *)ptr, 0);
|
||||
}
|
||||
|
||||
static inline void
|
||||
pAtomicStoreB32(b32 volatile *ptr, b32 value)
|
||||
{
|
||||
_InterlockedExchange_HLERelease((LONG volatile *)ptr, (LONG)value);
|
||||
}
|
||||
|
||||
static inline b32
|
||||
pAtomicCompareExchangeB32(b32 volatile *ptr, b32 *expect, b32 desired)
|
||||
{
|
||||
return (b32)InterlockedCompareExchangeAcquire((LONG volatile *)ptr, (LONG)desired, (LONG)*expect);
|
||||
}
|
||||
|
||||
// ::Platform::Windows::Atomics::End::
|
||||
|
||||
|
||||
|
||||
// ::Platform::Windows::Files::Start::
|
||||
|
||||
static b8
|
||||
pDirIsVisible(c8 *dir_name)
|
||||
{
|
||||
WIN32_FIND_DATA find_data;
|
||||
HANDLE handle;
|
||||
return (handle = FindFirstFile(dir_name, &find_data)) != INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
// ::Platform::Windows::Files::End::
|
||||
@ -110,6 +110,8 @@ void rDestroy();
|
||||
// ::Renderer::Buffers::Header::
|
||||
|
||||
static b32 rBufferMap();
|
||||
static rDescHandle rAssetLoad(c8 *name);
|
||||
static void rAssetUnload(rDescHandle handle);
|
||||
static rDescHandle rTextureLoad(TextureAsset asset_id);
|
||||
static rDescHandle rMeshLoad(ModelAsset asset_id);
|
||||
static void rTextureUnload(rDescHandle handle);
|
||||
|
||||
@ -363,22 +363,6 @@ vImageViewCreate(TexMeta meta)
|
||||
return view;
|
||||
}
|
||||
|
||||
static vTransfer *
|
||||
vTextureTransferInit(Arena *arena, u32 asset_id, VkImage image, rawptr bytes, TexMeta *meta)
|
||||
{
|
||||
vTransfer *transfer = MakeArray(arena, vTransfer, 1);
|
||||
|
||||
transfer->type = vTT_IMAGE;
|
||||
transfer->data = bytes;
|
||||
transfer->w = meta->w;
|
||||
transfer->h = meta->h;
|
||||
transfer->ch = meta->ch;
|
||||
transfer->asset_id = asset_id;
|
||||
transfer->image = image;
|
||||
|
||||
return transfer;
|
||||
}
|
||||
|
||||
static b32
|
||||
vImageViewInit(vImageView *view, u32 width, u32 height, u32 channels)
|
||||
{
|
||||
@ -444,86 +428,12 @@ vImageViewInit(vImageView *view, u32 width, u32 height, u32 channels)
|
||||
return success;
|
||||
}
|
||||
|
||||
static void
|
||||
vTextureCleanUp()
|
||||
{
|
||||
VkDevice device = v_Renderer.handles.device;
|
||||
VmaAllocator vma_alloc = v_Renderer.handles.vma_alloc;
|
||||
HashTable *table = &v_Renderer.buffers.images;
|
||||
b8 *queue = vFrameTexDestroyQueue();
|
||||
|
||||
// NOTE: might need a mutex here at some point, check if crashes related to image access
|
||||
for (u64 i = 0; i < TEXTURE_ASSET_MAX; i++)
|
||||
{
|
||||
if (queue[i])
|
||||
{
|
||||
rDescHandle handle = vDescHandlePop(vDT_SAMPLED_IMAGE, (u32)i);
|
||||
vDescIndexPush(vDT_SAMPLED_IMAGE, handle.desc_index);
|
||||
|
||||
vImageView *view = vImagePop(i);
|
||||
Assert(view != NULL, "rTextureUnload failure: value not in hash table");
|
||||
|
||||
vkDestroyImageView(device, view->view, NULL);
|
||||
vmaDestroyImage(vma_alloc, view->image.image, view->image.alloc);
|
||||
|
||||
FLMemFree(view);
|
||||
|
||||
queue[i] = false;
|
||||
}
|
||||
}
|
||||
|
||||
pAtomicSignalFenceSeqCst();
|
||||
}
|
||||
|
||||
static void
|
||||
vImagePush(TextureAsset asset_id, vImageView *view)
|
||||
{
|
||||
HashTablePushU64Rawptr(&v_Renderer.buffers.images, asset_id, view);
|
||||
}
|
||||
|
||||
static vImageView *
|
||||
vImagePop(TextureAsset asset_id)
|
||||
{
|
||||
return (vImageView *)HashTableDeleteU64Rawptr(&v_Renderer.buffers.images, asset_id);
|
||||
}
|
||||
|
||||
static vImageView *
|
||||
vImageSearch(TextureAsset asset_id)
|
||||
{
|
||||
vImageView *view = NULL;
|
||||
|
||||
HashTable *table = &v_Renderer.buffers.images;
|
||||
|
||||
KeyValuePair *pair = HashTableSearchU64(table, asset_id);
|
||||
if (pair != NULL)
|
||||
{
|
||||
view = (vImageView *)pair->value_rawptr;
|
||||
}
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
// ::Vulkan::Images::Functions::End::
|
||||
|
||||
|
||||
|
||||
// ::Vulkan::Descriptors::Functions::Start::
|
||||
|
||||
|
||||
static void
|
||||
vDescPushImageAndHandle(rDescHandle handle, vImageView *view)
|
||||
{
|
||||
vDescHandlePush(vDT_SAMPLED_IMAGE, handle);
|
||||
vImagePush(handle.asset_id, view);
|
||||
}
|
||||
|
||||
static void
|
||||
vDescPushModelAndHandle(rDescHandle handle, vModelBuffers *buffer)
|
||||
{
|
||||
vDescHandlePush(vDT_MESH, handle);
|
||||
vModelPush(handle.asset_id, buffer);
|
||||
}
|
||||
|
||||
// TODO: batch descriptor writes
|
||||
static u32
|
||||
vDescPushImageDesc(vImageView *view)
|
||||
@ -598,89 +508,12 @@ vDescIndexPop(vDescType type)
|
||||
return bindings->free[bindings->free_count];
|
||||
}
|
||||
|
||||
static rDescHandle
|
||||
vDescHandleSearch(vDescType type, u32 asset_id)
|
||||
{
|
||||
rDescHandle asset_info = {
|
||||
.asset_id = UINT32_MAX,
|
||||
};
|
||||
|
||||
HashTable *table = &v_Renderer.desc_bindings[type].lookup_table;
|
||||
|
||||
KeyValuePair *kv_pair = HashTableSearchU64(table, asset_id);
|
||||
if (kv_pair != NULL)
|
||||
{
|
||||
asset_info.asset_id = kv_pair->value_u64_split.upper;
|
||||
asset_info.desc_index = kv_pair->value_u64_split.lower;
|
||||
}
|
||||
|
||||
return asset_info;
|
||||
}
|
||||
|
||||
static void
|
||||
vDescHandlePush(vDescType type, rDescHandle handle)
|
||||
{
|
||||
HashTable *table = &v_Renderer.desc_bindings[type].lookup_table;
|
||||
HashTablePushU64U64Split(table, handle.asset_id, handle.asset_id, handle.desc_index);
|
||||
}
|
||||
|
||||
static rDescHandle
|
||||
vDescHandlePop(vDescType type, u32 asset_id)
|
||||
{
|
||||
HashTable *table = &v_Renderer.desc_bindings[type].lookup_table;
|
||||
|
||||
U64Split split = HashTableDeleteU64U64Split(table, (u64)asset_id);
|
||||
Assert(split.upper != UINT32_MAX, "vDescHandlePop failure: unable to find asset handle");
|
||||
|
||||
rDescHandle handle = {
|
||||
.asset_id = split.upper,
|
||||
.desc_index = split.lower,
|
||||
};
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
static void
|
||||
vDescHandleDelete(vDescType type, u32 asset_id)
|
||||
{
|
||||
HashTable *table = &v_Renderer.desc_bindings[type].lookup_table;
|
||||
HashTableDeleteU64(table, asset_id);
|
||||
}
|
||||
|
||||
// ::Vulkan::Descriptors::Functions::End::
|
||||
|
||||
|
||||
|
||||
// ::Vulkan::Buffers::Functions::Start::
|
||||
|
||||
static vTransfer *
|
||||
vMeshTransferInit(Arena *arena, u32 asset_id, vMeshBuffer *mesh, rawptr bytes, u64 size)
|
||||
{
|
||||
vTransfer *transfer = MakeArray(arena, vTransfer, 1);
|
||||
|
||||
transfer->type = vTT_MESH;
|
||||
transfer->data = bytes;
|
||||
transfer->size = size;
|
||||
transfer->mesh = mesh;
|
||||
transfer->asset_id = asset_id;
|
||||
|
||||
return transfer;
|
||||
}
|
||||
|
||||
static vTransfer *
|
||||
vBufferTransferInit(Arena *arena, u32 asset_id, vBuffer *index, rawptr bytes, u64 size)
|
||||
{
|
||||
vTransfer *transfer = MakeArray(arena, vTransfer, 1);
|
||||
|
||||
transfer->type = vTT_BUFFER;
|
||||
transfer->data = bytes;
|
||||
transfer->asset_id = asset_id;
|
||||
transfer->size = size;
|
||||
transfer->buffer = index->buffer;
|
||||
|
||||
return transfer;
|
||||
}
|
||||
|
||||
static VkResult
|
||||
vBufferCreate(vBuffer* buf, rRenderBufferType type, u64 size)
|
||||
{
|
||||
@ -765,32 +598,6 @@ vMapBuffer(VmaAllocation alloc)
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static void
|
||||
vModelPush(ModelAsset asset_id, vModelBuffers *buffer)
|
||||
{
|
||||
HashTablePushU64Rawptr(&v_Renderer.buffers.buffers, asset_id, buffer);
|
||||
}
|
||||
|
||||
static vModelBuffers *
|
||||
vModelPop(ModelAsset asset_id)
|
||||
{
|
||||
return (vModelBuffers *)HashTableDeleteU64Rawptr(&v_Renderer.buffers.buffers, asset_id);
|
||||
}
|
||||
|
||||
static vModelBuffers *
|
||||
vModelSearch(ModelAsset asset_id)
|
||||
{
|
||||
vModelBuffers *buffers = NULL;
|
||||
|
||||
KeyValuePair *pair = HashTableSearchU64(&v_Renderer.buffers.buffers, asset_id);
|
||||
if (pair != NULL)
|
||||
{
|
||||
buffers = (vModelBuffers *)pair->value_rawptr;
|
||||
}
|
||||
|
||||
return buffers;
|
||||
}
|
||||
|
||||
// ::Vulkan::Buffers::Functions::End::
|
||||
|
||||
|
||||
|
||||
@ -258,6 +258,36 @@ typedef struct vMeshBuffer
|
||||
vBuffer mesh, uniform;
|
||||
} vMeshBuffer;
|
||||
|
||||
// group assets
|
||||
// set boolean for each group for loaded/request unload
|
||||
|
||||
typedef struct vMeshAsset
|
||||
{
|
||||
vMeshBuffer *mesh;
|
||||
vBuffer *index;
|
||||
} vMeshAsset;
|
||||
|
||||
typedef enum vAssetType_e
|
||||
{
|
||||
vAT_NONE,
|
||||
vAT_TEXTURE,
|
||||
vAT_MESH,
|
||||
} vAssetType;
|
||||
|
||||
typedef struct vAsset
|
||||
{
|
||||
u64 hash;
|
||||
rDescHandle handle;
|
||||
union
|
||||
{
|
||||
vMeshAsset *mesh;
|
||||
vImageView *texture;
|
||||
};
|
||||
AssetMeta meta;
|
||||
} vAsset;
|
||||
|
||||
ArrayType(vAsset);
|
||||
|
||||
typedef struct vSwapchainState
|
||||
{
|
||||
VkFormat format;
|
||||
@ -358,16 +388,10 @@ typedef struct vMappedBuffer
|
||||
|
||||
typedef struct vRBuffers
|
||||
{
|
||||
HashTable buffers;
|
||||
vBufferPtrArray frame_buffers[FRAME_OVERLAP];
|
||||
|
||||
HashTable images;
|
||||
vImageViewPtrArray frame_images[FRAME_OVERLAP];
|
||||
b8PtrArray tex_destroy_queue;
|
||||
|
||||
vMappedBuffer transfer;
|
||||
vMappedBuffer gui_vert;
|
||||
vMappedBuffer gui_idx;
|
||||
vAssetArray assets;
|
||||
vMappedBuffer transfer;
|
||||
vMappedBuffer gui_vert;
|
||||
vMappedBuffer gui_idx;
|
||||
} vRBuffers;
|
||||
|
||||
typedef struct vModelBuffers
|
||||
@ -555,9 +579,6 @@ static vTransfer *vTextureTransferInit(Arena *arena, u32 asset_id, VkImage image
|
||||
static vImageView *vImageViewCreate(TexMeta meta);
|
||||
static b32 vImageViewInit(vImageView *view, u32 width, u32 height, u32 channels);
|
||||
static void vTextureCleanUp();
|
||||
static void vImagePush(TextureAsset asset_id, vImageView *view);
|
||||
static vImageView *vImagePop(TextureAsset asset_id);
|
||||
static vImageView *vImageSearch(TextureAsset asset_id);
|
||||
|
||||
// ::Vulkan::Descriptors::Functions::Header::
|
||||
|
||||
@ -568,7 +589,6 @@ static u32 vDescIndexPop(vDescType type);
|
||||
static rDescHandle vDescHandleSearch(vDescType type, u32 asset_id);
|
||||
static void vDescHandlePush(vDescType type, rDescHandle handle);
|
||||
static rDescHandle vDescHandlePop(vDescType type, u32 asset_id);
|
||||
static void vDescHandleDelete(vDescType type, u32 asset_id);
|
||||
static u32 vDescPushImageDesc(vImageView *view);
|
||||
static u32 vDescPushMeshDesc(vMeshBuffer *buffer);
|
||||
|
||||
@ -578,9 +598,6 @@ static vTransfer *vMeshTransferInit(Arena *arena, u32 asset_id, vMeshBuffer *mes
|
||||
static vTransfer *vBufferTransferInit(Arena *arena, u32 asset_id, vBuffer *index, rawptr bytes, u64 size);
|
||||
static VkResult vBufferCreate(vBuffer* buf, rRenderBufferType type, u64 size);
|
||||
static rawptr vMapBuffer(VmaAllocation alloc);
|
||||
static void vModelPush(c8 *name, vModelBuffers *buffer);
|
||||
static vModelBuffers *vModelPop(c8 *name);
|
||||
static vModelBuffers *vModelSearch(c8 *name);
|
||||
|
||||
// ::Vulkan::CleanUp::Functions::Header::
|
||||
|
||||
|
||||
@ -1,156 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __linux__
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
// ::SharedTypes::Declarations::Header::
|
||||
|
||||
typedef struct Arena Arena;
|
||||
|
||||
// ::SharedTypes::Attributes::Header::
|
||||
|
||||
#if COMPILER_MSVC || (COMPILER_CLANG && _WIN32)
|
||||
# pragma section(".rdata$", read)
|
||||
# define read_only __declspec(allocate(".rdata$"))
|
||||
#elif (COMPILER_CLANG && __linux__)
|
||||
# define read_only __attribute__((section(".rodata")))
|
||||
#elif (COMPILER_GCC && __linux__)
|
||||
# define read_only
|
||||
#else
|
||||
# error read_only not implemented for compiler/target
|
||||
#endif
|
||||
|
||||
// ::SharedTypes::Types::Header::
|
||||
|
||||
typedef int8_t i8;
|
||||
typedef int16_t i16;
|
||||
typedef int32_t i32;
|
||||
typedef int64_t i64;
|
||||
|
||||
typedef uint8_t u8;
|
||||
typedef uint16_t u16;
|
||||
typedef uint32_t u32;
|
||||
typedef uint64_t u64;
|
||||
|
||||
typedef char c8;
|
||||
|
||||
typedef intptr_t intptr;
|
||||
typedef uintptr_t uintptr;
|
||||
|
||||
typedef float f32;
|
||||
typedef double f64;
|
||||
|
||||
typedef uint8_t b8;
|
||||
typedef uint32_t b32;
|
||||
|
||||
typedef void * rawptr;
|
||||
|
||||
typedef struct String8
|
||||
{
|
||||
c8 *value;
|
||||
u64 len;
|
||||
} String8;
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
typedef ssize_t isize;
|
||||
typedef size_t usize;
|
||||
|
||||
#elif _WIN32
|
||||
|
||||
#if defined ( _WIN64 )
|
||||
|
||||
typedef int64_t isize;
|
||||
typedef uint64_t usize;
|
||||
|
||||
#elif defined ( _WIN32 )
|
||||
|
||||
typedef int32_t isize;
|
||||
typedef uint32_t usize;
|
||||
|
||||
#endif
|
||||
|
||||
#else // unix
|
||||
|
||||
#endif
|
||||
|
||||
typedef union
|
||||
{
|
||||
struct { u32 upper, lower; };
|
||||
u64 full;
|
||||
} U64Split;
|
||||
|
||||
typedef union
|
||||
{
|
||||
struct { f32 r, g; };
|
||||
struct { f32 x, y; };
|
||||
} Vec2;
|
||||
|
||||
typedef union
|
||||
{
|
||||
struct { f32 x, y, z; };
|
||||
struct { f32 r, g, b; };
|
||||
} Vec3;
|
||||
|
||||
typedef union
|
||||
{
|
||||
struct { f32 x, y, z, w; };
|
||||
struct { f32 r, g, b, a; };
|
||||
} Vec4;
|
||||
|
||||
typedef union
|
||||
{
|
||||
struct { u16 x, y; };
|
||||
struct { u16 r, g; };
|
||||
struct { u16 w, h; };
|
||||
} u16Vec2;
|
||||
|
||||
typedef union
|
||||
{
|
||||
struct { i32 x, y; };
|
||||
struct { i32 r, g; };
|
||||
} iVec2;
|
||||
|
||||
typedef union
|
||||
{
|
||||
struct { i32 x, y, z; };
|
||||
struct { i32 r, g, b; };
|
||||
} iVec3;
|
||||
|
||||
typedef union
|
||||
{
|
||||
struct { i32 x, y, z, w; };
|
||||
struct { i32 r, g, b, a; };
|
||||
} iVec4;
|
||||
|
||||
typedef union
|
||||
{
|
||||
struct { i16 x, y; };
|
||||
struct { i16 r, g; };
|
||||
struct { i16 w, h; };
|
||||
} i16Vec2;
|
||||
|
||||
typedef f32 Mat2[4];
|
||||
typedef f32 Mat3[9];
|
||||
typedef f32 Mat4[16];
|
||||
|
||||
typedef f64 dMat2[4];
|
||||
typedef f64 dMat3[9];
|
||||
typedef f64 dMat4[16];
|
||||
|
||||
typedef struct Vertex
|
||||
{
|
||||
Vec4 pos;
|
||||
Vec4 col;
|
||||
} Vertex;
|
||||
|
||||
typedef struct m3dModel
|
||||
{
|
||||
Vertex *vertices;
|
||||
u32 *indices;
|
||||
u64 v_count;
|
||||
u64 i_count;
|
||||
} m3dModel;
|
||||
3968
src/stglib.h
Normal file
3968
src/stglib.h
Normal file
File diff suppressed because it is too large
Load Diff
484
src/util.c
484
src/util.c
@ -1,484 +0,0 @@
|
||||
// ::Util::Globals::Start::
|
||||
|
||||
static Profiler
|
||||
g_Global_Profiler;
|
||||
|
||||
// ::Util::Globals::End::
|
||||
|
||||
|
||||
|
||||
// ::Util::Strings::Functions::Start::
|
||||
|
||||
|
||||
static void
|
||||
StrConcat(c8 *str, c8 *append)
|
||||
{
|
||||
u32 len = StrLen(str);
|
||||
u32 i = 0;
|
||||
for (; append[i] != '\0'; i += 1)
|
||||
{
|
||||
str[i] = append[i];
|
||||
}
|
||||
|
||||
str[i] = '\0';
|
||||
}
|
||||
|
||||
static b32
|
||||
StrEqL(const char *l, const char *r, u64 len)
|
||||
{
|
||||
for (u64 i = 0; *l == *r && *l && i < len; l++, r++, i++);
|
||||
return *l == *r;
|
||||
}
|
||||
|
||||
static b32
|
||||
StrEq(const char *l, const char *r)
|
||||
{
|
||||
for (; *l == *r && *l; l++, r++);
|
||||
return *l == '\0' && *r == '\0';
|
||||
}
|
||||
|
||||
static u32
|
||||
StrLen(const char *str)
|
||||
{
|
||||
const char *start;
|
||||
|
||||
for (start = str; *str != '\0'; ++str)
|
||||
/* Iterate only */;
|
||||
|
||||
return (u32)(str - start);
|
||||
}
|
||||
|
||||
static i32
|
||||
SPrintf(char *buf, int len, rawptr fmt, ...)
|
||||
{
|
||||
va_list arg;
|
||||
|
||||
va_start(arg, fmt);
|
||||
int sprf_res = stbsp_vsnprintf(buf, len, fmt, arg);
|
||||
va_end(arg);
|
||||
|
||||
return sprf_res;
|
||||
}
|
||||
|
||||
static String8
|
||||
MakeString8(c8 *str, u64 len)
|
||||
{
|
||||
return (String8){ .len = len, .value = str };
|
||||
}
|
||||
|
||||
static String8
|
||||
String8Concat(Arena *arena, String8 string, String8 append)
|
||||
{
|
||||
u64 str_len = string.len + append.len;
|
||||
String8 str = {
|
||||
.value = MakeArray(arena, c8, str_len),
|
||||
.len = str_len,
|
||||
};
|
||||
|
||||
MemCpy(str.value, string.value, string.len);
|
||||
MemCpy(str.value+string.len, append.value, append.len);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
static void
|
||||
String8TrimSuffix(String8 *str, c8 delimiter)
|
||||
{
|
||||
if (!str || str->len == 0) return;
|
||||
|
||||
for (i64 i = i64(str->len)-1; i > 0; i -= 1)
|
||||
{
|
||||
if (str->value[i] == delimiter)
|
||||
{
|
||||
str->value[i] = '\0';
|
||||
str->len = i == 0 ? 0 : u64(i - 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static i64
|
||||
String8FindLast(String8 str, c8 delimiter)
|
||||
{
|
||||
if (str.len == 0) return -1;
|
||||
|
||||
i64 result = 1;
|
||||
|
||||
for (i64 i = i64(str.len)-1; i >= 0; i -= 1)
|
||||
{
|
||||
if (str.value[i] == delimiter)
|
||||
{
|
||||
result = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static b32
|
||||
String8Eq(String8 l, String8 r)
|
||||
{
|
||||
return StrEqL(l.value, r.value, l.len);
|
||||
}
|
||||
|
||||
static b32
|
||||
String8StartsWith(String8 string, String8 cmp)
|
||||
{
|
||||
return StrEqL(string.value, cmp.value, cmp.len);
|
||||
}
|
||||
|
||||
static String8
|
||||
PreSplitString8(String8 string, String8 delimiter)
|
||||
{
|
||||
if (string.len == 0 || delimiter.len == 0) return string;
|
||||
|
||||
u32 new_len = 0;
|
||||
u32 matched_chars = 0;
|
||||
|
||||
for (u32 i = 0; i < string.len; i++)
|
||||
{
|
||||
|
||||
if (string.value[i] == delimiter.value[matched_chars])
|
||||
matched_chars += 1;
|
||||
else
|
||||
matched_chars = 0;
|
||||
|
||||
if (matched_chars == delimiter.len || delimiter.value[matched_chars+1] == '\0')
|
||||
{
|
||||
new_len = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (String8){ .len = new_len, .value = string.value };
|
||||
}
|
||||
|
||||
static String8
|
||||
PreSplitNewString8(Arena *arena, String8 string, String8 delimiter)
|
||||
{
|
||||
String8 result = PreSplitString8(string, delimiter);
|
||||
|
||||
if (result.len > 0)
|
||||
{
|
||||
result.value = MakeArray(arena, char, result.len+1);
|
||||
MemCpy(result.value, string.value, result.len);
|
||||
result.value[result.len] = '\0';
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// ::Util::Strings::Functions::End::
|
||||
|
||||
|
||||
|
||||
// ::Util::Memory::Functions::Start::
|
||||
|
||||
void
|
||||
MemZero(void *ptr, isize size)
|
||||
{
|
||||
if (!size || !ptr) return;
|
||||
|
||||
isize iter_size = size > sizeof(u64) ? 8 : 1;
|
||||
iter_size *= 4;
|
||||
isize iter_len = size / iter_size;
|
||||
|
||||
u64 *mem = (u64 *)ptr;
|
||||
|
||||
if (iter_size > sizeof(u64))
|
||||
{
|
||||
while (iter_len > 0)
|
||||
{
|
||||
mem[0] = 0;
|
||||
mem[1] = 0;
|
||||
mem[2] = 0;
|
||||
mem[3] = 0;
|
||||
mem += 4;
|
||||
iter_len--;
|
||||
}
|
||||
}
|
||||
|
||||
u8 *byte_mem = (u8 *)mem;
|
||||
isize rem_len = size % iter_size;
|
||||
while (rem_len > 0)
|
||||
{
|
||||
byte_mem[0] = 0;
|
||||
byte_mem++;
|
||||
rem_len--;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MemCpy(rawptr dst, rawptr src, usize size)
|
||||
{
|
||||
if (size == 0) return;
|
||||
|
||||
isize iter_size = size > sizeof(u64) ? 8 : 1;
|
||||
iter_size *= 4;
|
||||
isize iter_len = size / iter_size;
|
||||
isize rem_len = 0;
|
||||
|
||||
u64 *mem_dst = (u64 *)dst;
|
||||
u64 *mem_src = (u64 *)src;
|
||||
|
||||
|
||||
if (iter_size > sizeof(size))
|
||||
{
|
||||
while (iter_len > 0)
|
||||
{
|
||||
mem_dst[0] = mem_src[0];
|
||||
mem_dst[1] = mem_src[1];
|
||||
mem_dst[2] = mem_src[2];
|
||||
mem_dst[3] = mem_src[3];
|
||||
mem_dst += 4;
|
||||
mem_src += 4;
|
||||
iter_len--;
|
||||
}
|
||||
|
||||
rem_len = size % iter_size;
|
||||
}
|
||||
else
|
||||
rem_len = size;
|
||||
|
||||
|
||||
u8 *byte_dst = (u8 *)mem_dst;
|
||||
u8 *byte_src = (u8 *)mem_src;
|
||||
while (rem_len > 0)
|
||||
{
|
||||
byte_dst[0] = byte_src[0];
|
||||
byte_dst++;
|
||||
byte_src++;
|
||||
rem_len--;
|
||||
}
|
||||
}
|
||||
|
||||
// ::Util::Memory::Functions::End::
|
||||
|
||||
|
||||
|
||||
// ::Util::Math::Functions::Start::
|
||||
|
||||
DefMathImpl(Min);
|
||||
DefMathImpl(Max);
|
||||
DefMathImpl(Clamp);
|
||||
DefMathImpl(Abs);
|
||||
|
||||
// ::Util::Math::Functions::End::
|
||||
|
||||
|
||||
|
||||
// ::Util::Hashing::Functions::Start::
|
||||
|
||||
u64 static inline
|
||||
HashFromString(String8 string)
|
||||
{
|
||||
return XXH3_64bits_withSeed(string.value, string.len, HASH_SEED);
|
||||
}
|
||||
|
||||
// ::Util::Hashing::Functions::End::
|
||||
|
||||
|
||||
|
||||
// ::Util::Print::Functions::Start::
|
||||
|
||||
i32
|
||||
Printf(char *fmt, ...)
|
||||
{
|
||||
va_list arg;
|
||||
|
||||
va_start(arg, fmt);
|
||||
i32 result = _Printf(fmt, arg);
|
||||
va_end(arg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
i32
|
||||
Printfln(char *fmt, ...)
|
||||
{
|
||||
va_list arg;
|
||||
|
||||
va_start(arg, fmt);
|
||||
i32 result = _Printfln(fmt, arg);
|
||||
va_end(arg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
i32
|
||||
EPrintf(char *fmt, ...)
|
||||
{
|
||||
va_list arg;
|
||||
|
||||
va_start(arg, fmt);
|
||||
i32 result = _EPrintf(fmt, arg);
|
||||
va_end(arg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
i32
|
||||
EPrint(void *str)
|
||||
{
|
||||
return pWriteStdErr(str, (isize)StrLen(str));
|
||||
}
|
||||
|
||||
i32
|
||||
_EPrintf(char *fmt, va_list arg)
|
||||
{
|
||||
char buffer[1024];
|
||||
|
||||
int sprf_res = stbsp_vsnprintf(&buffer[0], 1024, fmt, arg);
|
||||
|
||||
if (sprf_res < 0) return sprf_res;
|
||||
|
||||
return EPrint(&buffer);
|
||||
}
|
||||
|
||||
i32
|
||||
_Printf(char *fmt, va_list arg)
|
||||
{
|
||||
char buffer[1024];
|
||||
|
||||
int sprf_res = stbsp_vsnprintf(&buffer[0], 1024, fmt, arg);
|
||||
|
||||
i32 pr_res;
|
||||
if (sprf_res < 0)
|
||||
pr_res = sprf_res;
|
||||
else
|
||||
pr_res = pWriteStdOut(&buffer, sprf_res);
|
||||
|
||||
return pr_res;
|
||||
}
|
||||
|
||||
i32
|
||||
_Printfln(char *fmt, va_list arg)
|
||||
{
|
||||
char buffer[1024];
|
||||
|
||||
int sprf_res = stbsp_vsnprintf(&buffer[0], 1023, fmt, arg);
|
||||
|
||||
i32 pr_res;
|
||||
if (sprf_res < 0)
|
||||
{
|
||||
pr_res = sprf_res;
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer[sprf_res] = '\n';
|
||||
buffer[sprf_res+1] = '\0';
|
||||
pr_res = pWriteStdOut(&buffer, sprf_res+1);
|
||||
}
|
||||
|
||||
return pr_res;
|
||||
}
|
||||
|
||||
// ::Util::Print::Functions::End::
|
||||
|
||||
|
||||
|
||||
// ::Util::Profiling::Functions::Start::
|
||||
|
||||
static inline void
|
||||
StartProfileBlock(ProfileBlock *block, c8 *label, u32 anchor_index)
|
||||
{
|
||||
block->anchor_index = anchor_index;
|
||||
block->label = label;
|
||||
block->start_tsc = pCPUTimerRead();
|
||||
}
|
||||
|
||||
static inline void
|
||||
EndProfileBlock(ProfileBlock *block)
|
||||
{
|
||||
u64 elapsed = pCPUTimerRead() - block->start_tsc;
|
||||
|
||||
ProfileAnchor *anchor = g_Global_Profiler.anchors + block->anchor_index;
|
||||
anchor->tsc_elapsed += elapsed;
|
||||
anchor->hit_count += 1;
|
||||
anchor->label = block->label;
|
||||
}
|
||||
|
||||
// ::Util::Profiling::Functions::End::
|
||||
|
||||
|
||||
|
||||
// ::Util::Async::Functions::Start::
|
||||
|
||||
static inline b32
|
||||
MutTryLock(Mut *mut)
|
||||
{
|
||||
b32 lock = false;
|
||||
return pAtomicCompareExchangeB32(&mut->lock, &lock, 1);
|
||||
}
|
||||
|
||||
static inline void
|
||||
MutUnlock(Mut *mut)
|
||||
{
|
||||
pAtomicStoreB32(&mut->lock, 0);
|
||||
}
|
||||
|
||||
static inline void
|
||||
TicketMutInit(TicketMut *mut)
|
||||
{
|
||||
mut->ticket = 0;
|
||||
mut->next_ticket = 1;
|
||||
}
|
||||
|
||||
static inline void
|
||||
TicketMutLock(TicketMut *mut)
|
||||
{
|
||||
u32 ticket = pAtomicFetchIncrU32(&mut->ticket);
|
||||
while (ticket != mut->next_ticket);
|
||||
}
|
||||
|
||||
static inline void
|
||||
TicketMutUnlock(TicketMut *mut)
|
||||
{
|
||||
pAtomicIncrU32(&mut->next_ticket);
|
||||
}
|
||||
|
||||
static inline u32
|
||||
JobQueueAdd(JobQueue *queue, u32 count)
|
||||
{
|
||||
u32 job_idx = pAtomicFetchIncrU32(&queue->queued);
|
||||
pAtomicFetchIncrU32(&queue->remaining);
|
||||
|
||||
return job_idx;
|
||||
}
|
||||
|
||||
static inline u32
|
||||
JobQueueGetCount(JobQueue *queue)
|
||||
{
|
||||
return pAtomicLoadU32(&queue->queued);
|
||||
}
|
||||
|
||||
static inline void
|
||||
JobQueueMarkUnqueued(JobQueue *queue, u32 count)
|
||||
{
|
||||
Assert(queue->queued != 0, "queue queued is 0 before trying to mark dequeued");
|
||||
pAtomicFetchSubU32(&queue->queued, count);
|
||||
}
|
||||
|
||||
static inline void
|
||||
JobQueueMarkCompleted(JobQueue *queue, u32 count)
|
||||
{
|
||||
Assert(queue->remaining != 0, "queue remaining is 0 before trying to mark completed");
|
||||
pAtomicFetchSubU32(&queue->remaining, count);
|
||||
}
|
||||
|
||||
static inline void
|
||||
JobQueueReset(JobQueue *queue)
|
||||
{
|
||||
pAtomicFetchSubU32(&queue->queued, queue->queued);
|
||||
pAtomicFetchSubU32(&queue->remaining, queue->remaining);
|
||||
}
|
||||
|
||||
static inline b32
|
||||
JobQueueCompleted(JobQueue *queue)
|
||||
{
|
||||
u32 remaining = pAtomicLoadU32(&queue->remaining);
|
||||
return remaining == 0;
|
||||
}
|
||||
|
||||
// ::Util::Async::Functions::End::
|
||||
299
src/util.h
299
src/util.h
@ -1,299 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
typedef struct Arena Arena;
|
||||
|
||||
// ::Util::Macros::Header::
|
||||
|
||||
#define Assert(condition, message) do { assert((condition) && (message)); } while(0)
|
||||
|
||||
#define KB(n) n * 1024LL
|
||||
#define MB(n) KB(n) * 1024LL
|
||||
#define GB(n) MB(n) * 1024LL
|
||||
#define TB(n) GB(n) * 1024LL
|
||||
|
||||
#define BitEq(var, bits) (((var) & (bits)) == (bits))
|
||||
#define AlignPow2(x, b) (((x) + (b) - 1) & (~((b) - 1)))
|
||||
#define IsPow2(x) ((x) != 0 && ((x) &((x) - 1)) == 0)
|
||||
#define PtrAdd(ptr, add) (((u8 *)ptr) + add)
|
||||
#define PtrAddAdjustLen(ptr, len, add) \
|
||||
ptr = PtrAdd(ptr, add); \
|
||||
len -= add
|
||||
|
||||
#define Diff(value, sub) (value - sub)
|
||||
#define MakeArray(arena, type, count) ArenaAlloc(arena, (isize)(sizeof(type)) * (isize)(count))
|
||||
#define Len(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x])))))
|
||||
|
||||
#define MakeString(x) #x
|
||||
|
||||
#define i8(x) ((i8)(x))
|
||||
#define i16(x) ((i16)(x))
|
||||
#define i32(x) ((i32)(x))
|
||||
#define i64(x) ((i64)(x))
|
||||
|
||||
#define u8(x) ((u8)(x))
|
||||
#define u16(x) ((u16)(x))
|
||||
#define u32(x) ((u32)(x))
|
||||
#define u64(x) ((u64)(x))
|
||||
|
||||
#define c8(x) ((c8)(x))
|
||||
#define c8ptr(x) ((c8 *)(x))
|
||||
#define u8ptr(x) ((u8 *)(x))
|
||||
#define i8ptr(x) ((i8 *)(x))
|
||||
|
||||
#define intptr(x) ((intptr)(x))
|
||||
#define uintptr(x) ((uintptr)(x))
|
||||
|
||||
#define f32(x) ((f32)(x))
|
||||
#define f64(x) ((f64)(x))
|
||||
|
||||
#define rawptr(x) ((rawptr)(x))
|
||||
|
||||
#define cast(T, x) ((T)(x))
|
||||
|
||||
#define DefScalarSig(def) \
|
||||
DefSig##def(i8); \
|
||||
DefSig##def(i16); \
|
||||
DefSig##def(i32); \
|
||||
DefSig##def(i64); \
|
||||
DefSig##def(u8); \
|
||||
DefSig##def(u16); \
|
||||
DefSig##def(u32); \
|
||||
DefSig##def(u64); \
|
||||
DefSig##def(b8); \
|
||||
DefSig##def(b32)
|
||||
|
||||
#define DefScalarImpl(def) \
|
||||
Def##def(i8); \
|
||||
Def##def(i16); \
|
||||
Def##def(i32); \
|
||||
Def##def(i64); \
|
||||
Def##def(u8); \
|
||||
Def##def(u16); \
|
||||
Def##def(u32); \
|
||||
Def##def(u64); \
|
||||
Def##def(b8); \
|
||||
Def##def(b32)
|
||||
|
||||
#define ArrayType(T) \
|
||||
typedef struct T##Array \
|
||||
{ \
|
||||
T *data; \
|
||||
u64 length; \
|
||||
u64 cap; \
|
||||
} T##Array
|
||||
|
||||
#define PtrArrayType(T) \
|
||||
typedef struct T##PtrArray \
|
||||
{ \
|
||||
T **data; \
|
||||
u64 length; \
|
||||
u64 cap; \
|
||||
} T##PtrArray
|
||||
|
||||
#define InitArrayType(arr, arena, T, len) \
|
||||
arr.data = MakeArray(arena, T, len); \
|
||||
arr.length = 0; \
|
||||
arr.cap = len
|
||||
|
||||
// ::Util::LinkedList::Macros::
|
||||
|
||||
#define CheckNil(nil, p) ((p) == 0 || (p) == nil)
|
||||
#define SetNil(nil, p) ((p) = nil)
|
||||
|
||||
// ::Util::DoubleHeadedLinkedList::Macros::
|
||||
|
||||
#define SLLConcatInPlaceNoCount(list, to_concat) do { \
|
||||
if ((to_concat)->first) \
|
||||
{ \
|
||||
if ((list)->first) \
|
||||
{ \
|
||||
(list)->last->next = (to_concat)->first; \
|
||||
(list)->last = (to_concat)->last; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
(list)->first = (to_concat)->first; \
|
||||
(list)->last = (to_concat)->last; \
|
||||
} \
|
||||
MemZero(to_concat, sizeof(*to_concat)); \
|
||||
} \
|
||||
} while (0)
|
||||
#define _SLLQueuePop(nil, f, l, next) ((f) == (l) ? \
|
||||
(SetNil(nil, f), SetNil(nil, l)) : \
|
||||
((f) = (f)->next))
|
||||
#define _SLLQueuePushFront(nil, f, l, n, next) (CheckNil(nil, f) ? \
|
||||
((f) = (l) = (n), SetNil(nil, (n)->next)) : \
|
||||
((n)->next = (f), (f) = (n)))
|
||||
#define _SLLQueuePush(nil, f, l, n, next) (CheckNil(nil, f) ? \
|
||||
((f) = (l) = (n), SetNil(nil, (n)->next)) : \
|
||||
((l)->next = (n), (l) = (n), SetNil(nil, (n)->next)))
|
||||
|
||||
#define SLLQueuePop(nil, f, l) _SLLQueuePop(nil, f, l, next)
|
||||
#define SLLQueuePush(nil, f, l, n) _SLLQueuePush(nil, f, l, n, next)
|
||||
#define SLLQueuePushFront(nil, f, l, n) _SLLQueuePushFront(nil, f, l, n, next)
|
||||
|
||||
// ::Util::String8::Macros::
|
||||
|
||||
#define String8Array(v, c) MakeString8((c8 *)(v), sizeof(*(v))*(c))
|
||||
#define String8Struct(v) MakeString8((c8 *)(v), sizeof(*(v)))
|
||||
#define String8CStr(v) MakeString8((c8 *)v, StrLen(v))
|
||||
|
||||
// ::Util::Defines::Header::
|
||||
|
||||
constexpr u32 HM_MAX_SYMBOLS = 256;
|
||||
constexpr usize DEFAULT_ALIGNMENT = (2*sizeof(rawptr));
|
||||
constexpr u64 HASH_SEED = 5995;
|
||||
|
||||
// ::Util::Strings::Functions::Header::
|
||||
|
||||
static b32 String8Eq(String8 l, String8 r);
|
||||
static u32 StrLen(const char *str);
|
||||
static b32 StrEqL(const char *l, const char *r, u64 len);
|
||||
static b32 StrEq(const char *l, const char *r);
|
||||
static i32 SPrintf(char *buf, int len, rawptr fmt, ...);
|
||||
static void StrConcat(c8 *str, c8 *append);
|
||||
static String8 MakeString8(c8 *str, u64 len);
|
||||
static String8 String8Concat(Arena *arena, String8 string, String8 append);
|
||||
static void String8TrimSuffix(String8 *str, c8 delimiter);
|
||||
static i64 String8FindLast(String8 str, c8 delimiter);
|
||||
static String8 PreSplitString8(String8 string, String8 delimiter);
|
||||
static String8 PreSplitNewString8(Arena *arena, String8 string, String8 delimiter);
|
||||
|
||||
// ::Util::Memory::Functions::Header::
|
||||
|
||||
void MemZero(void *ptr, isize size);
|
||||
void MemCpy(rawptr dst, rawptr src, usize len);
|
||||
|
||||
// ::Util::Math::Functions::Header::
|
||||
|
||||
#define DefIntegerImpl(def) \
|
||||
Def##def(i8); \
|
||||
Def##def(i16); \
|
||||
Def##def(i32); \
|
||||
Def##def(i64); \
|
||||
Def##def(u8); \
|
||||
Def##def(u16); \
|
||||
Def##def(u32); \
|
||||
Def##def(u64)
|
||||
|
||||
#define DefFloatImpl(def) \
|
||||
Def##def(f32); \
|
||||
Def##def(f64)
|
||||
|
||||
#define DefMathImpl(def) \
|
||||
DefIntegerImpl(def); \
|
||||
DefFloatImpl(def)
|
||||
|
||||
#define DefMin(T) \
|
||||
T Min##T(T l, T r) \
|
||||
{ \
|
||||
return l < r ? l : r; \
|
||||
}
|
||||
|
||||
#define DefMax(T) \
|
||||
T Max##T(T l, T r) \
|
||||
{ \
|
||||
return l > r ? l : r; \
|
||||
}
|
||||
|
||||
#define DefClamp(T) \
|
||||
T Clamp##T(T v, T min, T max) \
|
||||
{ \
|
||||
return Min##T(max, Max##T(v, min)); \
|
||||
}
|
||||
|
||||
#define DefAbs(T) \
|
||||
T Abs##T(T v) \
|
||||
{ \
|
||||
return v < (T)0 ? -v : v; \
|
||||
}
|
||||
|
||||
// ::Util::Hashing::Functions::Header::
|
||||
|
||||
u64 static inline HashFromString(String8 string);
|
||||
|
||||
// ::Util::Print::Functions::Header::
|
||||
|
||||
i32 EPrint(void *str);
|
||||
i32 Printf(char *fmt, ...);
|
||||
i32 Printfln(char *fmt, ...);
|
||||
i32 EPrintf(char *fmt, ...);
|
||||
i32 _EPrint(void *str);
|
||||
i32 _Printf(char *fmt, va_list arg);
|
||||
i32 _Printfln(char *fmt, va_list arg);
|
||||
i32 _EPrintf(char *fmt, va_list arg);
|
||||
|
||||
// ::Util::Profiling::Header::
|
||||
|
||||
#define NameConcat2(a, b) a##b
|
||||
|
||||
#define NameConcat(a, b) NameConcat2(a, b)
|
||||
|
||||
#define TimeBlockStart(name) ProfileBlock NameConcat(Block, name) = {0}; \
|
||||
StartProfileBlock(&NameConcat(Block, name), #name, __COUNTER__ + 1)
|
||||
|
||||
#define TimeBlockEnd(name) EndProfileBlock(&NameConcat(Block, name))
|
||||
|
||||
#define TimeBlockFuncStart(name) ProfileBlock NameConcat(Block, function) = {0}; \
|
||||
StartProfileBlock(& NameConcat(Block, function), name, __COUNTER__ + 1)
|
||||
|
||||
#define TimeFunctionStart TimeBlockFuncStart(__func__)
|
||||
|
||||
#define TimeFunctionEnd TimeBlockEnd(function)
|
||||
|
||||
typedef struct ProfileAnchor
|
||||
{
|
||||
u64 tsc_elapsed;
|
||||
u64 hit_count;
|
||||
c8 *label;
|
||||
} ProfileAnchor;
|
||||
|
||||
typedef struct ProfileBlock
|
||||
{
|
||||
c8 *label;
|
||||
u64 start_tsc;
|
||||
u32 anchor_index;
|
||||
} ProfileBlock;
|
||||
|
||||
typedef struct Profiler
|
||||
{
|
||||
ProfileAnchor anchors[4096];
|
||||
u64 start_tsc;
|
||||
u64 end_tsc;
|
||||
} Profiler;
|
||||
|
||||
static inline void StartProfileBlock(ProfileBlock *block, c8 *label, u32 anchor_index);
|
||||
static inline void EndProfileBlock(ProfileBlock *block);
|
||||
|
||||
|
||||
// ::Util::Async::Header::
|
||||
|
||||
typedef struct TicketMut
|
||||
{
|
||||
u32 volatile ticket;
|
||||
u32 volatile next_ticket;
|
||||
} TicketMut;
|
||||
|
||||
typedef struct Mut
|
||||
{
|
||||
b32 volatile lock;
|
||||
} Mut;
|
||||
|
||||
typedef struct JobQueue
|
||||
{
|
||||
u32 volatile queued;
|
||||
u32 volatile remaining;
|
||||
} JobQueue;
|
||||
|
||||
static inline b32 MutTryLock(Mut *mut);
|
||||
static inline void MutUnlock(Mut *mut);
|
||||
static inline void TicketMutLock(TicketMut *mut);
|
||||
static inline void TicketMutUnlock(TicketMut *mut);
|
||||
static inline u32 JobQueueAdd(JobQueue *queue, u32 count);
|
||||
static inline u32 JobQueueGetCount(JobQueue *queue);
|
||||
static inline void JobQueueMarkUnqueued(JobQueue *queue, u32 count);
|
||||
static inline void JobQueueMarkCompleted(JobQueue *queue, u32 count);
|
||||
static inline void JobQueueReset(JobQueue *queue);
|
||||
static inline b32 JobQueueCompleted(JobQueue *queue);
|
||||
Loading…
x
Reference in New Issue
Block a user