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_out_name="Packer"
|
||||||
packer_flags="-DBUILD_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
|
# glslc
|
||||||
glsl_compile="glslc"
|
glsl_compile="glslc"
|
||||||
glsl_flags="--target-spv=spv1.6 -std=460"
|
glsl_flags="--target-spv=spv1.6 -std=460"
|
||||||
@ -113,17 +119,17 @@ if ! [ -f libvma.a ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Packer Codegen
|
# 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
|
# Packer
|
||||||
if [ -v packer ] || ! [ -f Packer ]; then
|
if [ -v packer ] || ! [ -f Packer ]; then
|
||||||
$compile $packer_source_files $compile_link $link_os_gfx $packer_flags $packer_include_flags $out $packer_out_name
|
$compile $packer_source_files $compile_link $link_os_gfx $packer_flags $packer_include_flags $out $packer_out_name
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -v pack ] || ! [ -f assets.sgp ]; then
|
#if [ -v pack ] || ! [ -f assets.sgp ]; then
|
||||||
./Packer
|
# ./Packer
|
||||||
fi
|
#fi
|
||||||
|
|
||||||
if ! [ -v packer ]; then
|
#if ! [ -v packer ]; then
|
||||||
$compile $source_files $compile_link $link_os_gfx $out $out_name
|
# $compile $source_files $compile_link $link_os_gfx $out $out_name
|
||||||
fi
|
#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");
|
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(Texture_Assets, &ASSET_PACK[File_Header.asset_offset], sizeof(AssetFile) * File_Header.asset_counts);
|
||||||
|
|
||||||
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]);
|
|
||||||
|
|
||||||
ASSET_HEADER_LOADED = true;
|
ASSET_HEADER_LOADED = true;
|
||||||
}
|
}
|
||||||
@ -97,9 +93,7 @@ apLoadS8(String8 str)
|
|||||||
static void
|
static void
|
||||||
apUnload(c8 *str)
|
apUnload(c8 *str)
|
||||||
{
|
{
|
||||||
Asset asset = {0};
|
|
||||||
|
|
||||||
return asset;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|||||||
48
src/assets.h
48
src/assets.h
@ -7,12 +7,24 @@
|
|||||||
#define CreateMagicValue(a, b, c, d) ((u32)(d << 24) | (u32)(c << 16) | (u32)(b << 8) | (u32)(a))
|
#define CreateMagicValue(a, b, c, d) ((u32)(d << 24) | (u32)(c << 16) | (u32)(b << 8) | (u32)(a))
|
||||||
|
|
||||||
// ::Assets::Globals::Header::
|
// ::Assets::Globals::Header::
|
||||||
#ifndef BUILD_ASSET_CODEGEN
|
#include "codegen_assets.h"
|
||||||
# include "codegen_assets.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// ::Assets::Types::Header::
|
// ::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
|
typedef struct TexMeta
|
||||||
{
|
{
|
||||||
u32 w;
|
u32 w;
|
||||||
@ -22,9 +34,18 @@ typedef struct TexMeta
|
|||||||
|
|
||||||
typedef struct ModelMeta
|
typedef struct ModelMeta
|
||||||
{
|
{
|
||||||
u32 i_count;
|
u64 i_count;
|
||||||
} ModelMeta;
|
} ModelMeta;
|
||||||
|
|
||||||
|
typedef struct AssetMeta
|
||||||
|
{
|
||||||
|
union
|
||||||
|
{
|
||||||
|
TexMeta texture;
|
||||||
|
ModelMeta model;
|
||||||
|
};
|
||||||
|
} AssetMeta;
|
||||||
|
|
||||||
typedef struct Asset
|
typedef struct Asset
|
||||||
{
|
{
|
||||||
union
|
union
|
||||||
@ -41,24 +62,33 @@ typedef struct AssetTag
|
|||||||
f32 value;
|
f32 value;
|
||||||
} AssetTag;
|
} AssetTag;
|
||||||
|
|
||||||
|
typedef enum AssetType_e
|
||||||
|
{
|
||||||
|
AT_NONE,
|
||||||
|
AT_SHADER,
|
||||||
|
AT_TEXTURE,
|
||||||
|
AT_MODEL,
|
||||||
|
} AssetType;
|
||||||
|
|
||||||
typedef struct AssetFile
|
typedef struct AssetFile
|
||||||
{
|
{
|
||||||
u64 hash;
|
|
||||||
u64 data_offset;
|
|
||||||
u64 len;
|
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
TexMeta texture_meta;
|
TexMeta texture_meta;
|
||||||
ModelMeta model_meta;
|
ModelMeta model_meta;
|
||||||
};
|
};
|
||||||
|
u64 hash;
|
||||||
|
u64 data_offset;
|
||||||
|
u64 len;
|
||||||
|
AssetType type;
|
||||||
} AssetFile;
|
} AssetFile;
|
||||||
|
|
||||||
typedef struct FileHeader
|
typedef struct FileHeader
|
||||||
{
|
{
|
||||||
u32 magic_num;
|
u32 magic_num;
|
||||||
u32 version;
|
u32 version;
|
||||||
u32 asset_counts[ASSET_TYPE_MAX];
|
u32 asset_counts;
|
||||||
u64 asset_offsets[ASSET_TYPE_MAX];
|
u64 asset_offset;
|
||||||
} FileHeader;
|
} FileHeader;
|
||||||
|
|
||||||
// ::Assets::Init::Functions::Header::
|
// ::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 *
|
static c8 *
|
||||||
g_Shader_Asset_Names[] =
|
g_Shader_Asset_Names[] =
|
||||||
{
|
{
|
||||||
"shaders/gui.frag",
|
"shaders/gui.frag.spv",
|
||||||
"shaders/pbr.frag",
|
"shaders/pbr.frag.spv",
|
||||||
"shaders/gui.vert",
|
"shaders/gui.vert.spv",
|
||||||
"shaders/quad.frag",
|
"shaders/quad.frag.spv",
|
||||||
"shaders/quad.vert",
|
"shaders/quad.vert.spv",
|
||||||
"shaders/pbr.vert",
|
"shaders/pbr.vert.spv",
|
||||||
};
|
};
|
||||||
|
|
||||||
static u64
|
static u64
|
||||||
g_Shader_Asset_Hashes[] =
|
g_Shader_Asset_Hashes[] =
|
||||||
{
|
{
|
||||||
4076561469468128204U,
|
12100337026595633089U,
|
||||||
12546533630435803654U,
|
12100337026595633089U,
|
||||||
17203805968697784249U,
|
12100337026595633089U,
|
||||||
1277283055956479971U,
|
12100337026595633089U,
|
||||||
12273814537638279648U,
|
12100337026595633089U,
|
||||||
1941995729991819811U,
|
12100337026595633089U,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define SHADER_ASSET_MAX 6
|
#define SHADER_ASSET_MAX 6
|
||||||
|
|
||||||
|
#define SHADER_ASSET 0
|
||||||
|
|
||||||
static c8 *
|
static c8 *
|
||||||
g_Model_Asset_Names[] =
|
g_Model_Asset_Names[] =
|
||||||
{
|
{
|
||||||
"models/test_char",
|
"models/test_char.m3d",
|
||||||
"models/yoda",
|
"models/yoda.m3d",
|
||||||
};
|
};
|
||||||
|
|
||||||
static u64
|
static u64
|
||||||
g_Model_Asset_Hashes[] =
|
g_Model_Asset_Hashes[] =
|
||||||
{
|
{
|
||||||
17106564331948230266U,
|
2356409063604999112U,
|
||||||
1379945611816585992U,
|
2356409063604999112U,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MODEL_ASSET_MAX 2
|
#define MODEL_ASSET_MAX 2
|
||||||
|
|
||||||
|
#define MODEL_ASSET 1
|
||||||
|
|
||||||
static c8 *
|
static c8 *
|
||||||
g_Texture_Asset_Names[] =
|
g_Texture_Asset_Names[] =
|
||||||
{
|
{
|
||||||
"textures/ham_smoke",
|
"textures/ham_smoke.png",
|
||||||
"textures/cheesoid",
|
"textures/cheesoid.png",
|
||||||
"textures/hog",
|
"textures/hog.jpg",
|
||||||
"textures/patamon",
|
"textures/patamon.png",
|
||||||
"textures/pattermon",
|
"textures/pattermon.png",
|
||||||
"textures/hamster",
|
"textures/hamster.png",
|
||||||
"textures/purplemon",
|
"textures/purplemon.png",
|
||||||
};
|
};
|
||||||
|
|
||||||
static u64
|
static u64
|
||||||
g_Texture_Asset_Hashes[] =
|
g_Texture_Asset_Hashes[] =
|
||||||
{
|
{
|
||||||
3672471465693847963U,
|
5461253849680765905U,
|
||||||
17853259469867187617U,
|
5461253849680765905U,
|
||||||
12925726572206082157U,
|
5461253849680765905U,
|
||||||
1223697967736380744U,
|
5461253849680765905U,
|
||||||
16704275018603890077U,
|
5461253849680765905U,
|
||||||
13194708417649827129U,
|
5461253849680765905U,
|
||||||
12400748618931758111U,
|
5461253849680765905U,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define TEXTURE_ASSET_MAX 7
|
#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"
|
#include "entry_linux.h"
|
||||||
|
|
||||||
// ::ThirdParty::Include::
|
// ::ThirdParty::Include::
|
||||||
#include "xxhash/xxhash.c"
|
|
||||||
#include "fastlz/fastlz.c"
|
#include "fastlz/fastlz.c"
|
||||||
|
|
||||||
#include "platform/platform.c"
|
|
||||||
#include "util.c"
|
|
||||||
#include "assets.c"
|
#include "assets.c"
|
||||||
#include "ds.c"
|
|
||||||
#include "allocators.c"
|
|
||||||
#include "renderer.c"
|
#include "renderer.c"
|
||||||
#include "game.c"
|
#include "game.c"
|
||||||
#ifdef BUILD_TEST
|
#ifdef BUILD_TEST
|
||||||
|
|||||||
@ -12,17 +12,14 @@
|
|||||||
|
|
||||||
#define WINDOW_NAME "Video Game"
|
#define WINDOW_NAME "Video Game"
|
||||||
|
|
||||||
#include "shared_types.h"
|
#define STG_IMPLEMENTATION
|
||||||
#include "platform/platform.h"
|
|
||||||
#include "util.h"
|
#include "stglib.h"
|
||||||
|
|
||||||
#include "assets.h"
|
#include "assets.h"
|
||||||
#include "ds.h"
|
|
||||||
#include "allocators.h"
|
|
||||||
|
|
||||||
// ::ThirdParty::Include::Header::
|
// ::ThirdParty::Include::Header::
|
||||||
#include "stb/stb_sprintf.h"
|
|
||||||
#include "stb/stb_image.h"
|
#include "stb/stb_image.h"
|
||||||
#include "xxhash/xxhash.h"
|
|
||||||
#include "fastlz/fastlz.h"
|
#include "fastlz/fastlz.h"
|
||||||
#include "m3d/m3d.h"
|
#include "m3d/m3d.h"
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define STB_SPRINTF_IMPLEMENTATION
|
|
||||||
|
|
||||||
#define STB_IMAGE_IMPLEMENTATION
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
|
|
||||||
@ -16,7 +15,6 @@
|
|||||||
#include "allocators.h"
|
#include "allocators.h"
|
||||||
|
|
||||||
// ::ThirdParty::Include::Header::
|
// ::ThirdParty::Include::Header::
|
||||||
#include "stb/stb_sprintf.h"
|
|
||||||
#include "stb/stb_image.h"
|
#include "stb/stb_image.h"
|
||||||
#include "xxhash/xxhash.h"
|
#include "xxhash/xxhash.h"
|
||||||
#include "fastlz/fastlz.h"
|
#include "fastlz/fastlz.h"
|
||||||
|
|||||||
298
src/packer.c
298
src/packer.c
@ -2,16 +2,9 @@
|
|||||||
|
|
||||||
#include "packer.h"
|
#include "packer.h"
|
||||||
|
|
||||||
#include "xxhash/xxhash.c"
|
|
||||||
#include "fastlz/fastlz.c"
|
#include "fastlz/fastlz.c"
|
||||||
|
|
||||||
#include "platform/platform.c"
|
|
||||||
#include "assets.c"
|
#include "assets.c"
|
||||||
#include "util.c"
|
|
||||||
#include "ds.c"
|
|
||||||
#include "allocators.c"
|
|
||||||
#include "renderer.c"
|
|
||||||
#include "game.c"
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
# include <fcntl.h>
|
# include <fcntl.h>
|
||||||
@ -19,168 +12,6 @@
|
|||||||
|
|
||||||
// ::Packer::Packing::Functions::Start::
|
// ::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
|
i32
|
||||||
WriteHeader(pFile file, FileHeader *header)
|
WriteHeader(pFile file, FileHeader *header)
|
||||||
{
|
{
|
||||||
@ -218,23 +49,8 @@ InitHeader(FileHeader *header)
|
|||||||
header->magic_num = CreateMagicValue('s', 't', 'e', 'g');
|
header->magic_num = CreateMagicValue('s', 't', 'e', 'g');
|
||||||
header->version = FILE_VERSION;
|
header->version = FILE_VERSION;
|
||||||
|
|
||||||
header->asset_counts[SHADER_ASSET] = SHADER_ASSET_MAX;
|
header->asset_counts = SHADER_ASSET_MAX + TEXTURE_ASSET_MAX + MODEL_ASSET_MAX;
|
||||||
header->asset_counts[TEXTURE_ASSET] = TEXTURE_ASSET_MAX;
|
header->asset_offset = sizeof(FileHeader);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -244,20 +60,16 @@ PackFiles(Arena *arena, FileHeader *header)
|
|||||||
|
|
||||||
u64 file_pos = pFileWrite(file, 0, header, sizeof(FileHeader));
|
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 = ".";
|
c8 *return_dir = ".";
|
||||||
u32 file_count;
|
Assert(pDirNavigate("../assets") == 0, "Unable to move to assets directory");
|
||||||
MoveToShaderDir(&return_dir);
|
|
||||||
|
|
||||||
AssetFile *shader_assets = MakeArray(arena, AssetFile, SHADER_ASSET_MAX);
|
u64 total_assets = SHADER_ASSET_MAX + TEXTURE_ASSET_MAX + MODEL_ASSET_MAX;
|
||||||
for (u32 i = 0; i < SHADER_ASSET_MAX; i++)
|
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];
|
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");
|
Assert((data_offset - prev_offset) == file_size, "File write size invalid");
|
||||||
|
|
||||||
shader_assets[i].data_offset = prev_offset;
|
assets[asset_count].data_offset = prev_offset;
|
||||||
shader_assets[i].len = file_size;
|
assets[asset_count].len = file_size;
|
||||||
|
assets[asset_count].type = AT_SHADER;
|
||||||
|
|
||||||
pFileClose(asset_file);
|
pFileClose(asset_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
Assert(pDirNavigate(return_dir) == 0, "Unable to return to previous directory");
|
for (u32 i = 0; i < TEXTURE_ASSET_MAX; i++, asset_count++)
|
||||||
MoveToTextureDir(&return_dir);
|
|
||||||
|
|
||||||
AssetFile *texture_assets = MakeArray(arena, AssetFile, TEXTURE_ASSET_MAX);
|
|
||||||
for (u32 i = 0; i < TEXTURE_ASSET_MAX; i++)
|
|
||||||
{
|
{
|
||||||
c8 *asset_name = g_Texture_Asset_Names[i];
|
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");
|
Assert((data_offset - prev_offset) == loaded_length, "File write size invalid");
|
||||||
|
|
||||||
texture_assets[i].data_offset = prev_offset;
|
assets[asset_count].data_offset = prev_offset;
|
||||||
texture_assets[i].len = loaded_length;
|
assets[asset_count].len = loaded_length;
|
||||||
texture_assets[i].texture_meta.w = u32(w);
|
assets[asset_count].type = AT_TEXTURE;
|
||||||
texture_assets[i].texture_meta.h = u32(h);
|
assets[asset_count].texture_meta.w = u32(w);
|
||||||
texture_assets[i].texture_meta.ch = u32(ch);
|
assets[asset_count].texture_meta.h = u32(h);
|
||||||
|
assets[asset_count].texture_meta.ch = u32(ch);
|
||||||
|
|
||||||
stbi_image_free(image_bytes);
|
stbi_image_free(image_bytes);
|
||||||
|
|
||||||
pFileClose(asset_file);
|
pFileClose(asset_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
Assert(pDirNavigate(return_dir) == 0, "Unable to return to previous directory");
|
for (u32 i = 0; i < MODEL_ASSET_MAX; i++, asset_count++)
|
||||||
MoveToModelDir(&return_dir);
|
|
||||||
|
|
||||||
AssetFile *model_assets = MakeArray(arena, AssetFile, MODEL_ASSET_MAX);
|
|
||||||
for (u32 i = 0; i < MODEL_ASSET_MAX; i++)
|
|
||||||
{
|
{
|
||||||
c8 *asset_name = g_Model_Asset_Names[i];
|
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");
|
Assert((data_offset - prev_offset) == file_size, "File write size invalid");
|
||||||
|
|
||||||
model_assets[i].data_offset = prev_offset;
|
m3d_t *model = m3d_load(file_data, NULL, NULL, NULL);
|
||||||
model_assets[i].len = file_size;
|
|
||||||
|
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);
|
pFileClose(asset_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
pFileWrite(file, header->asset_offsets[SHADER_ASSET], shader_assets, sizeof(AssetFile)*SHADER_ASSET_MAX);
|
pFileWrite(file, header->asset_offset, assets, sizeof(AssetFile)*asset_count);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ::Packer::Packing::Functions::End::
|
// ::Packer::Packing::Functions::End::
|
||||||
@ -364,7 +170,7 @@ PackFiles(Arena *arena, FileHeader *header)
|
|||||||
// ::Packer::Tests::Functions::Start::
|
// ::Packer::Tests::Functions::Start::
|
||||||
|
|
||||||
static inline void
|
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);
|
pFile asset_file = pFileOpen(file_name, pFS_READ);
|
||||||
u64 size = pFileLength(asset_file);
|
u64 size = pFileLength(asset_file);
|
||||||
@ -378,7 +184,7 @@ TestAssetIsCorrect(Arena *arena, c8 *file_name, AssetFile *file_info, AssetType
|
|||||||
|
|
||||||
u8 *image_bytes;
|
u8 *image_bytes;
|
||||||
u64 image_length;
|
u64 image_length;
|
||||||
if (type == TEXTURE_ASSET)
|
if (file_info->type == TEXTURE_ASSET)
|
||||||
{
|
{
|
||||||
int ch = 4;
|
int ch = 4;
|
||||||
int w, h, has_ch;
|
int w, h, has_ch;
|
||||||
@ -415,48 +221,30 @@ TestAssetPack(Arena *arena)
|
|||||||
FileHeader header;
|
FileHeader header;
|
||||||
i64 offset = pFileRead(file, 0, &header, sizeof(FileHeader));
|
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.magic_num == CreateMagicValue('s', 't', 'e', 'g'), "Magic number is incorrect");
|
||||||
Assert(header.version == FILE_VERSION, "File version 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 == asset_count, "Asset 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");
|
|
||||||
|
|
||||||
AssetTag *tags[ASSET_TYPE_MAX];
|
AssetFile *files = MakeArray(arena, AssetFile, asset_count);
|
||||||
AssetFile *files[ASSET_TYPE_MAX];
|
pFileRead(file, header.asset_offset, files, sizeof(AssetFile)*header.asset_counts);
|
||||||
|
|
||||||
for (u32 i = 0; i < ASSET_TYPE_MAX; i++)
|
u64 current_asset = 0;
|
||||||
|
for (u32 i = 0; i < SHADER_ASSET_MAX; i++, current_asset++)
|
||||||
{
|
{
|
||||||
if (header.asset_counts[i] > 0)
|
TestAssetIsCorrect(arena, g_Shader_Asset_Names[i], files + current_asset, file);
|
||||||
{
|
|
||||||
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 = ".";
|
for (u32 i = 0; i < TEXTURE_ASSET_MAX; i++, current_asset++)
|
||||||
MoveToShaderDir(&return_dir);
|
|
||||||
|
|
||||||
for (u32 i = 0; i < SHADER_ASSET_MAX; i++)
|
|
||||||
{
|
{
|
||||||
TestAssetIsCorrect(arena, g_Shader_Asset_Names[i], &files[SHADER_ASSET][i], SHADER_ASSET, file);
|
TestAssetIsCorrect(arena, g_Texture_Asset_Names[i], files + current_asset, file);
|
||||||
}
|
}
|
||||||
|
|
||||||
pDirNavigate(return_dir);
|
for (u32 i = 0; i < MODEL_ASSET_MAX; i++, current_asset++)
|
||||||
MoveToTextureDir(&return_dir);
|
|
||||||
|
|
||||||
for (u32 i = 0; i < TEXTURE_ASSET_MAX; i++)
|
|
||||||
{
|
{
|
||||||
TestAssetIsCorrect(arena, g_Texture_Asset_Names[i], &files[TEXTURE_ASSET][i], TEXTURE_ASSET, file);
|
TestAssetIsCorrect(arena, g_Model_Asset_Names[i], files + current_asset, file);
|
||||||
}
|
|
||||||
|
|
||||||
pDirNavigate(return_dir);
|
|
||||||
MoveToModelDir(&return_dir);
|
|
||||||
|
|
||||||
for (u32 i = 0; i < MODEL_ASSET_MAX; i++)
|
|
||||||
{
|
|
||||||
TestAssetIsCorrect(arena, g_Model_Asset_Names[i], &files[MODEL_ASSET][i], MODEL_ASSET, file);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -496,8 +284,6 @@ main(int argc, c8 **argv)
|
|||||||
TestAssetPack(arena);
|
TestAssetPack(arena);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // BUILD_ASSET_CODEGEN
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ::Packer::Main::Functions::End::
|
// ::Packer::Main::Functions::End::
|
||||||
|
|||||||
19
src/packer.h
19
src/packer.h
@ -10,29 +10,21 @@
|
|||||||
|
|
||||||
#define STG_NO_RENDERER
|
#define STG_NO_RENDERER
|
||||||
|
|
||||||
#define STB_SPRINTF_IMPLEMENTATION
|
|
||||||
|
|
||||||
#define STB_IMAGE_IMPLEMENTATION
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
|
|
||||||
#define M3D_IMPLEMENTATION
|
#define M3D_IMPLEMENTATION
|
||||||
|
|
||||||
#include "shared_types.h"
|
#define STG_IMPLEMENTATION
|
||||||
#include "platform/platform.h"
|
|
||||||
#include "util.h"
|
#include "stglib.h"
|
||||||
|
|
||||||
#include "assets.h"
|
#include "assets.h"
|
||||||
#include "ds.h"
|
|
||||||
#include "allocators.h"
|
|
||||||
|
|
||||||
// ::ThirdParty::Include::Header::
|
// ::ThirdParty::Include::Header::
|
||||||
#include "stb/stb_sprintf.h"
|
|
||||||
#include "stb/stb_image.h"
|
#include "stb/stb_image.h"
|
||||||
#include "xxhash/xxhash.h"
|
|
||||||
#include "fastlz/fastlz.h"
|
#include "fastlz/fastlz.h"
|
||||||
#include "m3d/m3d.h"
|
#include "m3d/m3d.h"
|
||||||
|
|
||||||
#include "renderer.h"
|
|
||||||
#include "game.h"
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
// ::Packer::Macros::Header::
|
// ::Packer::Macros::Header::
|
||||||
@ -51,7 +43,6 @@ typedef struct FileMapping
|
|||||||
// ::Packer::Packing::Functions::Header::
|
// ::Packer::Packing::Functions::Header::
|
||||||
|
|
||||||
void SetArrayLookups();
|
void SetArrayLookups();
|
||||||
void CodeGenAssetLookups(Arena *arena);
|
|
||||||
void InitHeader(FileHeader *header);
|
void InitHeader(FileHeader *header);
|
||||||
i32 WriteHeader(pFile file, FileHeader *header);
|
i32 WriteHeader(pFile file, FileHeader *header);
|
||||||
void PackFiles(Arena *arena, FileHeader *header);
|
void PackFiles(Arena *arena, FileHeader *header);
|
||||||
@ -62,7 +53,7 @@ void MoveToModelDir(c8 **return_dir);
|
|||||||
// ::Packer::Tests::Functions::Header::
|
// ::Packer::Tests::Functions::Header::
|
||||||
|
|
||||||
void TestAssetPack(Arena *arena);
|
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::
|
// ::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::
|
// ::Renderer::Buffers::Header::
|
||||||
|
|
||||||
static b32 rBufferMap();
|
static b32 rBufferMap();
|
||||||
|
static rDescHandle rAssetLoad(c8 *name);
|
||||||
|
static void rAssetUnload(rDescHandle handle);
|
||||||
static rDescHandle rTextureLoad(TextureAsset asset_id);
|
static rDescHandle rTextureLoad(TextureAsset asset_id);
|
||||||
static rDescHandle rMeshLoad(ModelAsset asset_id);
|
static rDescHandle rMeshLoad(ModelAsset asset_id);
|
||||||
static void rTextureUnload(rDescHandle handle);
|
static void rTextureUnload(rDescHandle handle);
|
||||||
|
|||||||
@ -363,22 +363,6 @@ vImageViewCreate(TexMeta meta)
|
|||||||
return view;
|
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
|
static b32
|
||||||
vImageViewInit(vImageView *view, u32 width, u32 height, u32 channels)
|
vImageViewInit(vImageView *view, u32 width, u32 height, u32 channels)
|
||||||
{
|
{
|
||||||
@ -444,86 +428,12 @@ vImageViewInit(vImageView *view, u32 width, u32 height, u32 channels)
|
|||||||
return success;
|
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::Images::Functions::End::
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ::Vulkan::Descriptors::Functions::Start::
|
// ::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
|
// TODO: batch descriptor writes
|
||||||
static u32
|
static u32
|
||||||
vDescPushImageDesc(vImageView *view)
|
vDescPushImageDesc(vImageView *view)
|
||||||
@ -598,89 +508,12 @@ vDescIndexPop(vDescType type)
|
|||||||
return bindings->free[bindings->free_count];
|
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::Descriptors::Functions::End::
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ::Vulkan::Buffers::Functions::Start::
|
// ::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
|
static VkResult
|
||||||
vBufferCreate(vBuffer* buf, rRenderBufferType type, u64 size)
|
vBufferCreate(vBuffer* buf, rRenderBufferType type, u64 size)
|
||||||
{
|
{
|
||||||
@ -765,32 +598,6 @@ vMapBuffer(VmaAllocation alloc)
|
|||||||
return ptr;
|
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::
|
// ::Vulkan::Buffers::Functions::End::
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -258,6 +258,36 @@ typedef struct vMeshBuffer
|
|||||||
vBuffer mesh, uniform;
|
vBuffer mesh, uniform;
|
||||||
} vMeshBuffer;
|
} 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
|
typedef struct vSwapchainState
|
||||||
{
|
{
|
||||||
VkFormat format;
|
VkFormat format;
|
||||||
@ -358,13 +388,7 @@ typedef struct vMappedBuffer
|
|||||||
|
|
||||||
typedef struct vRBuffers
|
typedef struct vRBuffers
|
||||||
{
|
{
|
||||||
HashTable buffers;
|
vAssetArray assets;
|
||||||
vBufferPtrArray frame_buffers[FRAME_OVERLAP];
|
|
||||||
|
|
||||||
HashTable images;
|
|
||||||
vImageViewPtrArray frame_images[FRAME_OVERLAP];
|
|
||||||
b8PtrArray tex_destroy_queue;
|
|
||||||
|
|
||||||
vMappedBuffer transfer;
|
vMappedBuffer transfer;
|
||||||
vMappedBuffer gui_vert;
|
vMappedBuffer gui_vert;
|
||||||
vMappedBuffer gui_idx;
|
vMappedBuffer gui_idx;
|
||||||
@ -555,9 +579,6 @@ static vTransfer *vTextureTransferInit(Arena *arena, u32 asset_id, VkImage image
|
|||||||
static vImageView *vImageViewCreate(TexMeta meta);
|
static vImageView *vImageViewCreate(TexMeta meta);
|
||||||
static b32 vImageViewInit(vImageView *view, u32 width, u32 height, u32 channels);
|
static b32 vImageViewInit(vImageView *view, u32 width, u32 height, u32 channels);
|
||||||
static void vTextureCleanUp();
|
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::
|
// ::Vulkan::Descriptors::Functions::Header::
|
||||||
|
|
||||||
@ -568,7 +589,6 @@ static u32 vDescIndexPop(vDescType type);
|
|||||||
static rDescHandle vDescHandleSearch(vDescType type, u32 asset_id);
|
static rDescHandle vDescHandleSearch(vDescType type, u32 asset_id);
|
||||||
static void vDescHandlePush(vDescType type, rDescHandle handle);
|
static void vDescHandlePush(vDescType type, rDescHandle handle);
|
||||||
static rDescHandle vDescHandlePop(vDescType type, u32 asset_id);
|
static rDescHandle vDescHandlePop(vDescType type, u32 asset_id);
|
||||||
static void vDescHandleDelete(vDescType type, u32 asset_id);
|
|
||||||
static u32 vDescPushImageDesc(vImageView *view);
|
static u32 vDescPushImageDesc(vImageView *view);
|
||||||
static u32 vDescPushMeshDesc(vMeshBuffer *buffer);
|
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 vTransfer *vBufferTransferInit(Arena *arena, u32 asset_id, vBuffer *index, rawptr bytes, u64 size);
|
||||||
static VkResult vBufferCreate(vBuffer* buf, rRenderBufferType type, u64 size);
|
static VkResult vBufferCreate(vBuffer* buf, rRenderBufferType type, u64 size);
|
||||||
static rawptr vMapBuffer(VmaAllocation alloc);
|
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::
|
// ::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