diff --git a/build.sh b/build.sh index 5bedded..51239ff 100755 --- a/build.sh +++ b/build.sh @@ -35,6 +35,12 @@ packer_include_flags="-I../src/ -I../external/" packer_out_name="Packer" packer_flags="-DBUILD_PACKER" +# codegen +codegen_source_files="../src/codegen.c" +codegen_include_flags="-I../src/ -I../external/" +codegen_out_name="Codegen" +codegen_flags="-DBUILD_CODEGEN" + # glslc glsl_compile="glslc" glsl_flags="--target-spv=spv1.6 -std=460" @@ -113,17 +119,17 @@ if ! [ -f libvma.a ]; then fi # Packer Codegen -$compile $packer_source_files $compile_link $link_os_gfx $packer_flags -DBUILD_ASSET_CODEGEN $packer_include_flags $out PackerCodegen +$compile $codegen_source_files $compile_link $link_os_gfx $codegen_flags $packer_include_flags $out $codegen_out_name # Packer if [ -v packer ] || ! [ -f Packer ]; then $compile $packer_source_files $compile_link $link_os_gfx $packer_flags $packer_include_flags $out $packer_out_name fi -if [ -v pack ] || ! [ -f assets.sgp ]; then - ./Packer -fi +#if [ -v pack ] || ! [ -f assets.sgp ]; then +# ./Packer +#fi -if ! [ -v packer ]; then - $compile $source_files $compile_link $link_os_gfx $out $out_name -fi +#if ! [ -v packer ]; then +# $compile $source_files $compile_link $link_os_gfx $out $out_name +#fi diff --git a/src/allocators.c b/src/allocators.c deleted file mode 100644 index b5b325e..0000000 --- a/src/allocators.c +++ /dev/null @@ -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:: diff --git a/src/allocators.h b/src/allocators.h deleted file mode 100644 index f5c0af4..0000000 --- a/src/allocators.h +++ /dev/null @@ -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); - diff --git a/src/assets.c b/src/assets.c index db434cb..deca81c 100644 --- a/src/assets.c +++ b/src/assets.c @@ -65,11 +65,7 @@ static void apInit() Assert(File_Header.magic_num == CreateMagicValue('s', 't', 'e', 'g'), "Magic value is incorrect"); - MemCpy(Texture_Assets, &ASSET_PACK[File_Header.asset_offsets[TEXTURE_ASSET]], sizeof(AssetFile) * File_Header.asset_counts[TEXTURE_ASSET]); - - MemCpy(Shader_Assets, &ASSET_PACK[File_Header.asset_offsets[SHADER_ASSET]], sizeof(AssetFile) * File_Header.asset_counts[SHADER_ASSET]); - - MemCpy(Model_Assets, &ASSET_PACK[File_Header.asset_offsets[MODEL_ASSET]], sizeof(AssetFile) * File_Header.asset_counts[MODEL_ASSET]); + MemCpy(Texture_Assets, &ASSET_PACK[File_Header.asset_offset], sizeof(AssetFile) * File_Header.asset_counts); ASSET_HEADER_LOADED = true; } @@ -97,9 +93,7 @@ apLoadS8(String8 str) static void apUnload(c8 *str) { - Asset asset = {0}; - return asset; } static void diff --git a/src/assets.h b/src/assets.h index 6353bcc..e07d32b 100644 --- a/src/assets.h +++ b/src/assets.h @@ -7,12 +7,24 @@ #define CreateMagicValue(a, b, c, d) ((u32)(d << 24) | (u32)(c << 16) | (u32)(b << 8) | (u32)(a)) // ::Assets::Globals::Header:: -#ifndef BUILD_ASSET_CODEGEN -# include "codegen_assets.h" -#endif +#include "codegen_assets.h" // ::Assets::Types::Header:: +typedef struct Vertex +{ + Vec4 pos; + Vec4 col; +} Vertex; + +typedef struct m3dModel +{ + Vertex *vertices; + u32 *indices; + u64 v_count; + u64 i_count; +} m3dModel; + typedef struct TexMeta { u32 w; @@ -22,9 +34,18 @@ typedef struct TexMeta typedef struct ModelMeta { - u32 i_count; + u64 i_count; } ModelMeta; +typedef struct AssetMeta +{ + union + { + TexMeta texture; + ModelMeta model; + }; +} AssetMeta; + typedef struct Asset { union @@ -41,24 +62,33 @@ typedef struct AssetTag f32 value; } AssetTag; +typedef enum AssetType_e +{ + AT_NONE, + AT_SHADER, + AT_TEXTURE, + AT_MODEL, +} AssetType; + typedef struct AssetFile { + union + { + TexMeta texture_meta; + ModelMeta model_meta; + }; u64 hash; u64 data_offset; u64 len; - union - { - TexMeta texture_meta; - ModelMeta model_meta; - }; + AssetType type; } AssetFile; typedef struct FileHeader { u32 magic_num; u32 version; - u32 asset_counts[ASSET_TYPE_MAX]; - u64 asset_offsets[ASSET_TYPE_MAX]; + u32 asset_counts; + u64 asset_offset; } FileHeader; // ::Assets::Init::Functions::Header:: diff --git a/src/codegen.c b/src/codegen.c new file mode 100644 index 0000000..105c8b3 --- /dev/null +++ b/src/codegen.c @@ -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); +} diff --git a/src/codegen.h b/src/codegen.h new file mode 100644 index 0000000..31e9353 --- /dev/null +++ b/src/codegen.h @@ -0,0 +1,8 @@ +#pragma once + +#define _GNU_SOURCE + +#define STG_IMPLEMENTATION + +#include "stglib.h" + diff --git a/src/codegen_assets.h b/src/codegen_assets.h index 14539aa..ff7e5d0 100644 --- a/src/codegen_assets.h +++ b/src/codegen_assets.h @@ -1,66 +1,72 @@ static c8 * g_Shader_Asset_Names[] = { - "shaders/gui.frag", - "shaders/pbr.frag", - "shaders/gui.vert", - "shaders/quad.frag", - "shaders/quad.vert", - "shaders/pbr.vert", + "shaders/gui.frag.spv", + "shaders/pbr.frag.spv", + "shaders/gui.vert.spv", + "shaders/quad.frag.spv", + "shaders/quad.vert.spv", + "shaders/pbr.vert.spv", }; static u64 g_Shader_Asset_Hashes[] = { - 4076561469468128204U, - 12546533630435803654U, - 17203805968697784249U, - 1277283055956479971U, - 12273814537638279648U, - 1941995729991819811U, + 12100337026595633089U, + 12100337026595633089U, + 12100337026595633089U, + 12100337026595633089U, + 12100337026595633089U, + 12100337026595633089U, }; #define SHADER_ASSET_MAX 6 +#define SHADER_ASSET 0 + static c8 * g_Model_Asset_Names[] = { - "models/test_char", - "models/yoda", + "models/test_char.m3d", + "models/yoda.m3d", }; static u64 g_Model_Asset_Hashes[] = { - 17106564331948230266U, - 1379945611816585992U, + 2356409063604999112U, + 2356409063604999112U, }; #define MODEL_ASSET_MAX 2 +#define MODEL_ASSET 1 + static c8 * g_Texture_Asset_Names[] = { - "textures/ham_smoke", - "textures/cheesoid", - "textures/hog", - "textures/patamon", - "textures/pattermon", - "textures/hamster", - "textures/purplemon", + "textures/ham_smoke.png", + "textures/cheesoid.png", + "textures/hog.jpg", + "textures/patamon.png", + "textures/pattermon.png", + "textures/hamster.png", + "textures/purplemon.png", }; static u64 g_Texture_Asset_Hashes[] = { - 3672471465693847963U, - 17853259469867187617U, - 12925726572206082157U, - 1223697967736380744U, - 16704275018603890077U, - 13194708417649827129U, - 12400748618931758111U, + 5461253849680765905U, + 5461253849680765905U, + 5461253849680765905U, + 5461253849680765905U, + 5461253849680765905U, + 5461253849680765905U, + 5461253849680765905U, }; #define TEXTURE_ASSET_MAX 7 +#define TEXTURE_ASSET 2 + diff --git a/src/ds.c b/src/ds.c deleted file mode 100644 index 92927dd..0000000 --- a/src/ds.c +++ /dev/null @@ -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:: - - diff --git a/src/ds.h b/src/ds.h deleted file mode 100644 index b355708..0000000 --- a/src/ds.h +++ /dev/null @@ -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); - diff --git a/src/entry_linux.c b/src/entry_linux.c index 3e896ff..6b8fc64 100644 --- a/src/entry_linux.c +++ b/src/entry_linux.c @@ -10,14 +10,9 @@ int PROGRAM_FAILED = false; #include "entry_linux.h" // ::ThirdParty::Include:: -#include "xxhash/xxhash.c" #include "fastlz/fastlz.c" -#include "platform/platform.c" -#include "util.c" #include "assets.c" -#include "ds.c" -#include "allocators.c" #include "renderer.c" #include "game.c" #ifdef BUILD_TEST diff --git a/src/entry_linux.h b/src/entry_linux.h index e46b2a5..cf08a59 100644 --- a/src/entry_linux.h +++ b/src/entry_linux.h @@ -12,17 +12,14 @@ #define WINDOW_NAME "Video Game" -#include "shared_types.h" -#include "platform/platform.h" -#include "util.h" +#define STG_IMPLEMENTATION + +#include "stglib.h" + #include "assets.h" -#include "ds.h" -#include "allocators.h" // ::ThirdParty::Include::Header:: -#include "stb/stb_sprintf.h" #include "stb/stb_image.h" -#include "xxhash/xxhash.h" #include "fastlz/fastlz.h" #include "m3d/m3d.h" diff --git a/src/entry_windows.h b/src/entry_windows.h index 4e10c41..95c6d48 100644 --- a/src/entry_windows.h +++ b/src/entry_windows.h @@ -2,7 +2,6 @@ #pragma once -#define STB_SPRINTF_IMPLEMENTATION #define STB_IMAGE_IMPLEMENTATION @@ -16,7 +15,6 @@ #include "allocators.h" // ::ThirdParty::Include::Header:: -#include "stb/stb_sprintf.h" #include "stb/stb_image.h" #include "xxhash/xxhash.h" #include "fastlz/fastlz.h" diff --git a/src/packer.c b/src/packer.c index 2c6486f..372936e 100644 --- a/src/packer.c +++ b/src/packer.c @@ -2,16 +2,9 @@ #include "packer.h" -#include "xxhash/xxhash.c" #include "fastlz/fastlz.c" -#include "platform/platform.c" #include "assets.c" -#include "util.c" -#include "ds.c" -#include "allocators.c" -#include "renderer.c" -#include "game.c" #ifdef _WIN32 # include @@ -19,168 +12,6 @@ // ::Packer::Packing::Functions::Start:: -#ifdef BUILD_ASSET_CODEGEN - -u64 -WriteArrayToFile(Arena *arena, pFile file, String8 array_name, rawptr elements, u32 count, String8 type, u64 offset) -{ - b32 is_string = StrEq(type.value, "c8 *"); - c8 *decl = MakeArray(arena, c8, 2048); - i32 decl_len = SPrintf(decl, 2048, "static %s\n%s[] = \n{\n\t", type.value, array_name.value); - String8 result = { - .value = decl, - .len = u64(decl_len), - }; - - if (is_string) - { - String8 *strs = (String8 *)elements; - for (u32 i = 0; i < count; i += 1) - { - c8 *f = i == count-1 ? "\"%s\"," : "\"%s\",\n\t"; - c8 buf[512]; - decl_len = SPrintf(buf, 512, f, strs[i].value); - result = String8Concat(arena, result, MakeString8(buf, decl_len)); - } - } - else - { - u64 *ints = (u64 *)elements; - for (u32 i = 0; i < count; i += 1) - { - c8 *f = i == count-1 ? "%lluU," : "%lluU,\n\t"; - c8 buf[512]; - decl_len = SPrintf(buf, 512, f, ints[i]); - result = String8Concat(arena, result, MakeString8(buf, decl_len)); - } - } - - result = String8Concat(arena, result, String8CStr("\n};\n\n")); - - return pFileWrite(file, offset, result.value, result.len); -} - -static String8 * -ConvertCStrs(Arena *arena, c8 **strs, u32 count) -{ - String8 *str8s = MakeArray(arena, String8, count); - - for (u32 i = 0; i < count; i += 1) - { - str8s[i].value = strs[i]; - str8s[i].len = StrLen(strs[i]); - } - - return str8s; -} - -void -CodeGenAssetLookups(Arena *arena) -{ - pFile file = pFileOpen("../src/codegen_assets.h", pFS_WRITE | pFS_CREATE | pFS_TRUNC); - Assert(file > 0, "CodeGenAssetLookups failure: unable to open/create file"); - - Assert(pDirNavigate("../assets") == 0, "Unable to navigate to asset directory"); - - struct AssetDirInfo { - c8 *prefix, *struct_name, *hash_struct_name, *dir, *define; - }; - - struct AssetDirInfo dirs[] = { - { - .prefix = "shaders/", - .struct_name = "g_Shader_Asset_Names", - .hash_struct_name = "g_Shader_Asset_Hashes", - .dir = "shaders", - .define = "SHADER_ASSET", - }, - { - .prefix = "models/", - .struct_name = "g_Model_Asset_Names", - .hash_struct_name = "g_Model_Asset_Hashes", - .dir = "models", - .define = "MODEL_ASSET", - }, - { - .prefix = "textures/", - .struct_name = "g_Texture_Asset_Names", - .hash_struct_name = "g_Texture_Asset_Hashes", - .dir = "textures", - .define = "TEXTURE_ASSET", - }, - }; - - u64 offset = 0; - u32 dir_count = sizeof(dirs) / sizeof(struct AssetDirInfo); - for (u32 i = 0; i < dir_count; i += 1) - { - Assert(pDirNavigate(dirs[i].dir) == 0, "Unable to navigate to asset sub directory."); - - u32 count = 0; - c8 **cstrs = pDirGetFileNames(arena, &count); - u64 *hashes = MakeArray(arena, u64, count); - String8 *strs = ConvertCStrs(arena, cstrs, count); - - for (u32 j = 0; j < count; j += 1) - { - strs[j] = String8Concat(arena, String8CStr(dirs[i].prefix), strs[j]); - i64 offset = String8FindLast(strs[j], '.'); - hashes[j] = XXH3_64bits_withSeed(strs[j].value, strs[j].len - offset, HASH_SEED); - } - - offset += WriteArrayToFile( - arena, - file, - String8CStr(dirs[i].struct_name), - strs, - count, - String8CStr("c8 *"), - offset - ); - - offset += WriteArrayToFile( - arena, - file, - String8CStr(dirs[i].hash_struct_name), - hashes, - count, - String8CStr("u64"), - offset - ); - - c8 buf[128]; - i32 decl_len = SPrintf(buf, 128, "#define %s_MAX %llu\n\n#define %s %llu\n\n", dirs[i].define, count, dirs[i].define, i); - - offset += pFileWrite(file, offset, buf, decl_len); - - Assert(pDirNavigate("..") == 0, "CodeGenAssetLookups failure: unable to move back to build directory"); - } - - pFileClose(file); -} - -int -main(int argc, c8 **argv) -{ - #ifdef _WIN32 - { - _set_fmode(_O_BINARY); - } - #endif - - if (pDirIsVisible("build")) - { - Assert(pDirNavigate("./build") == 0, "Unable to change to build directory"); - } - - void *mem = pMemAllocZeroed(GB(1)); - Arena *arena = ArenaInitDebug(mem, GB(1), __LINE__); - - CodeGenAssetLookups(arena); -} - -#else - i32 WriteHeader(pFile file, FileHeader *header) { @@ -218,23 +49,8 @@ InitHeader(FileHeader *header) header->magic_num = CreateMagicValue('s', 't', 'e', 'g'); header->version = FILE_VERSION; - header->asset_counts[SHADER_ASSET] = SHADER_ASSET_MAX; - header->asset_counts[TEXTURE_ASSET] = TEXTURE_ASSET_MAX; - header->asset_counts[SOUND_ASSET] = SOUND_ASSET_MAX; - header->asset_counts[MODEL_ASSET] = MODEL_ASSET_MAX; - - u64 offset = sizeof(FileHeader); - - for (u32 i = 0; i < ASSET_TYPE_MAX; i++) - { - if (header->asset_counts[i] > 0) - { - header->asset_offsets[i] = offset; - offset += sizeof(AssetFile) * header->asset_counts[i]; - } - else - header->asset_offsets[i] = 0; - } + header->asset_counts = SHADER_ASSET_MAX + TEXTURE_ASSET_MAX + MODEL_ASSET_MAX; + header->asset_offset = sizeof(FileHeader); } void @@ -244,20 +60,16 @@ PackFiles(Arena *arena, FileHeader *header) u64 file_pos = pFileWrite(file, 0, header, sizeof(FileHeader)); - u64 data_offset = 0; - for (u32 i = 0; i < ASSET_TYPE_MAX; i++) - { - u64 asset_offset = header->asset_offsets[i] + (header->asset_counts[i] * sizeof(AssetFile)); - if (asset_offset > data_offset) - data_offset = asset_offset; - } - c8 *return_dir = "."; - u32 file_count; - MoveToShaderDir(&return_dir); + Assert(pDirNavigate("../assets") == 0, "Unable to move to assets directory"); - AssetFile *shader_assets = MakeArray(arena, AssetFile, SHADER_ASSET_MAX); - for (u32 i = 0; i < SHADER_ASSET_MAX; i++) + u64 total_assets = SHADER_ASSET_MAX + TEXTURE_ASSET_MAX + MODEL_ASSET_MAX; + u64 asset_count = 0; + AssetFile *assets = MakeArray(arena, AssetFile, total_assets); + + u64 data_offset = header->asset_offset + (sizeof(AssetFile) + total_assets); + + for (u32 i = 0; i < SHADER_ASSET_MAX; i++, asset_count++) { c8 *asset_name = g_Shader_Asset_Names[i]; @@ -274,17 +86,14 @@ PackFiles(Arena *arena, FileHeader *header) Assert((data_offset - prev_offset) == file_size, "File write size invalid"); - shader_assets[i].data_offset = prev_offset; - shader_assets[i].len = file_size; + assets[asset_count].data_offset = prev_offset; + assets[asset_count].len = file_size; + assets[asset_count].type = AT_SHADER; pFileClose(asset_file); } - Assert(pDirNavigate(return_dir) == 0, "Unable to return to previous directory"); - MoveToTextureDir(&return_dir); - - AssetFile *texture_assets = MakeArray(arena, AssetFile, TEXTURE_ASSET_MAX); - for (u32 i = 0; i < TEXTURE_ASSET_MAX; i++) + for (u32 i = 0; i < TEXTURE_ASSET_MAX; i++, asset_count++) { c8 *asset_name = g_Texture_Asset_Names[i]; @@ -312,22 +121,19 @@ PackFiles(Arena *arena, FileHeader *header) Assert((data_offset - prev_offset) == loaded_length, "File write size invalid"); - texture_assets[i].data_offset = prev_offset; - texture_assets[i].len = loaded_length; - texture_assets[i].texture_meta.w = u32(w); - texture_assets[i].texture_meta.h = u32(h); - texture_assets[i].texture_meta.ch = u32(ch); + assets[asset_count].data_offset = prev_offset; + assets[asset_count].len = loaded_length; + assets[asset_count].type = AT_TEXTURE; + assets[asset_count].texture_meta.w = u32(w); + assets[asset_count].texture_meta.h = u32(h); + assets[asset_count].texture_meta.ch = u32(ch); stbi_image_free(image_bytes); pFileClose(asset_file); } - Assert(pDirNavigate(return_dir) == 0, "Unable to return to previous directory"); - MoveToModelDir(&return_dir); - - AssetFile *model_assets = MakeArray(arena, AssetFile, MODEL_ASSET_MAX); - for (u32 i = 0; i < MODEL_ASSET_MAX; i++) + for (u32 i = 0; i < MODEL_ASSET_MAX; i++, asset_count++) { c8 *asset_name = g_Model_Asset_Names[i]; @@ -344,17 +150,17 @@ PackFiles(Arena *arena, FileHeader *header) Assert((data_offset - prev_offset) == file_size, "File write size invalid"); - model_assets[i].data_offset = prev_offset; - model_assets[i].len = file_size; + m3d_t *model = m3d_load(file_data, NULL, NULL, NULL); + + assets[asset_count].data_offset = prev_offset; + assets[asset_count].type = AT_MODEL; + assets[asset_count].len = file_size; + assets[asset_count].model_meta.i_count = u64(model->numface * 3); pFileClose(asset_file); } - pFileWrite(file, header->asset_offsets[SHADER_ASSET], shader_assets, sizeof(AssetFile)*SHADER_ASSET_MAX); - pFileWrite(file, header->asset_offsets[TEXTURE_ASSET], texture_assets, sizeof(AssetFile)*TEXTURE_ASSET_MAX); - pFileWrite(file, header->asset_offsets[MODEL_ASSET], model_assets, sizeof(AssetFile)*MODEL_ASSET_MAX); - - pDirNavigate(return_dir); + pFileWrite(file, header->asset_offset, assets, sizeof(AssetFile)*asset_count); } // ::Packer::Packing::Functions::End:: @@ -364,7 +170,7 @@ PackFiles(Arena *arena, FileHeader *header) // ::Packer::Tests::Functions::Start:: static inline void -TestAssetIsCorrect(Arena *arena, c8 *file_name, AssetFile *file_info, AssetType type, pFile file) +TestAssetIsCorrect(Arena *arena, c8 *file_name, AssetFile *file_info, pFile file) { pFile asset_file = pFileOpen(file_name, pFS_READ); u64 size = pFileLength(asset_file); @@ -378,7 +184,7 @@ TestAssetIsCorrect(Arena *arena, c8 *file_name, AssetFile *file_info, AssetType u8 *image_bytes; u64 image_length; - if (type == TEXTURE_ASSET) + if (file_info->type == TEXTURE_ASSET) { int ch = 4; int w, h, has_ch; @@ -415,48 +221,30 @@ TestAssetPack(Arena *arena) FileHeader header; i64 offset = pFileRead(file, 0, &header, sizeof(FileHeader)); + u64 asset_count = SHADER_ASSET_MAX + MODEL_ASSET_MAX + TEXTURE_ASSET_MAX; + Assert(header.magic_num == CreateMagicValue('s', 't', 'e', 'g'), "Magic number is incorrect"); Assert(header.version == FILE_VERSION, "File version is incorrect"); - Assert(header.asset_counts[SHADER_ASSET] == SHADER_ASSET_MAX, "Shader count incorrect"); - Assert(header.asset_counts[TEXTURE_ASSET] == TEXTURE_ASSET_MAX, "Texture count incorrect"); - Assert(header.asset_counts[SOUND_ASSET] == SOUND_ASSET_MAX, "Sound count incorrect"); - Assert(header.asset_counts[MODEL_ASSET] == MODEL_ASSET_MAX, "Model count incorrect"); + Assert(header.asset_counts == asset_count, "Asset count incorrect"); - AssetTag *tags[ASSET_TYPE_MAX]; - AssetFile *files[ASSET_TYPE_MAX]; - - for (u32 i = 0; i < ASSET_TYPE_MAX; i++) - { - if (header.asset_counts[i] > 0) - { - files[i] = MakeArray(arena, AssetFile, header.asset_counts[i]); - pFileRead(file, header.asset_offsets[i], files[i], sizeof(AssetFile)*header.asset_counts[i]); - } - } - - c8 *return_dir = "."; - MoveToShaderDir(&return_dir); + AssetFile *files = MakeArray(arena, AssetFile, asset_count); + pFileRead(file, header.asset_offset, files, sizeof(AssetFile)*header.asset_counts); - for (u32 i = 0; i < SHADER_ASSET_MAX; i++) + u64 current_asset = 0; + for (u32 i = 0; i < SHADER_ASSET_MAX; i++, current_asset++) { - TestAssetIsCorrect(arena, g_Shader_Asset_Names[i], &files[SHADER_ASSET][i], SHADER_ASSET, file); + TestAssetIsCorrect(arena, g_Shader_Asset_Names[i], files + current_asset, file); } - pDirNavigate(return_dir); - MoveToTextureDir(&return_dir); - - for (u32 i = 0; i < TEXTURE_ASSET_MAX; i++) + for (u32 i = 0; i < TEXTURE_ASSET_MAX; i++, current_asset++) { - TestAssetIsCorrect(arena, g_Texture_Asset_Names[i], &files[TEXTURE_ASSET][i], TEXTURE_ASSET, file); + TestAssetIsCorrect(arena, g_Texture_Asset_Names[i], files + current_asset, file); } - pDirNavigate(return_dir); - MoveToModelDir(&return_dir); - - for (u32 i = 0; i < MODEL_ASSET_MAX; i++) + for (u32 i = 0; i < MODEL_ASSET_MAX; i++, current_asset++) { - TestAssetIsCorrect(arena, g_Model_Asset_Names[i], &files[MODEL_ASSET][i], MODEL_ASSET, file); + TestAssetIsCorrect(arena, g_Model_Asset_Names[i], files + current_asset, file); } } @@ -496,8 +284,6 @@ main(int argc, c8 **argv) TestAssetPack(arena); } -#endif // BUILD_ASSET_CODEGEN - // ::Packer::Main::Functions::End:: diff --git a/src/packer.h b/src/packer.h index 0c81613..b642fe8 100644 --- a/src/packer.h +++ b/src/packer.h @@ -10,29 +10,21 @@ #define STG_NO_RENDERER -#define STB_SPRINTF_IMPLEMENTATION - #define STB_IMAGE_IMPLEMENTATION #define M3D_IMPLEMENTATION -#include "shared_types.h" -#include "platform/platform.h" -#include "util.h" +#define STG_IMPLEMENTATION + +#include "stglib.h" + #include "assets.h" -#include "ds.h" -#include "allocators.h" // ::ThirdParty::Include::Header:: -#include "stb/stb_sprintf.h" #include "stb/stb_image.h" -#include "xxhash/xxhash.h" #include "fastlz/fastlz.h" #include "m3d/m3d.h" -#include "renderer.h" -#include "game.h" - #include // ::Packer::Macros::Header:: @@ -51,7 +43,6 @@ typedef struct FileMapping // ::Packer::Packing::Functions::Header:: void SetArrayLookups(); -void CodeGenAssetLookups(Arena *arena); void InitHeader(FileHeader *header); i32 WriteHeader(pFile file, FileHeader *header); void PackFiles(Arena *arena, FileHeader *header); @@ -62,7 +53,7 @@ void MoveToModelDir(c8 **return_dir); // ::Packer::Tests::Functions::Header:: void TestAssetPack(Arena *arena); -static inline void TestAssetIsCorrect(Arena *arena, c8 *file_name, AssetFile *file_info, AssetType type, pFile file); +static inline void TestAssetIsCorrect(Arena *arena, c8 *file_name, AssetFile *file_info, pFile file); // ::Packer::Main::Functions::Header:: diff --git a/src/platform/platform.c b/src/platform/platform.c deleted file mode 100644 index 05a1051..0000000 --- a/src/platform/platform.c +++ /dev/null @@ -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 - diff --git a/src/platform/platform.h b/src/platform/platform.h deleted file mode 100644 index 58bc805..0000000 --- a/src/platform/platform.h +++ /dev/null @@ -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); - diff --git a/src/platform/platform_linux.c b/src/platform/platform_linux.c deleted file mode 100644 index bce55dc..0000000 --- a/src/platform/platform_linux.c +++ /dev/null @@ -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" - - diff --git a/src/platform/platform_linux.h b/src/platform/platform_linux.h deleted file mode 100644 index 80af75a..0000000 --- a/src/platform/platform_linux.h +++ /dev/null @@ -1,101 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// ::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); - diff --git a/src/platform/platform_linux_public.c b/src/platform/platform_linux_public.c deleted file mode 100644 index 41d51cc..0000000 --- a/src/platform/platform_linux_public.c +++ /dev/null @@ -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:: diff --git a/src/platform/platform_windows.c b/src/platform/platform_windows.c deleted file mode 100644 index af695bd..0000000 --- a/src/platform/platform_windows.c +++ /dev/null @@ -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" - diff --git a/src/platform/platform_windows.h b/src/platform/platform_windows.h deleted file mode 100644 index 73eb7fd..0000000 --- a/src/platform/platform_windows.h +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -// ::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(); diff --git a/src/platform/platform_windows_public.c b/src/platform/platform_windows_public.c deleted file mode 100644 index eb39145..0000000 --- a/src/platform/platform_windows_public.c +++ /dev/null @@ -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:: diff --git a/src/renderer.h b/src/renderer.h index 666395a..537edd1 100644 --- a/src/renderer.h +++ b/src/renderer.h @@ -110,6 +110,8 @@ void rDestroy(); // ::Renderer::Buffers::Header:: static b32 rBufferMap(); +static rDescHandle rAssetLoad(c8 *name); +static void rAssetUnload(rDescHandle handle); static rDescHandle rTextureLoad(TextureAsset asset_id); static rDescHandle rMeshLoad(ModelAsset asset_id); static void rTextureUnload(rDescHandle handle); diff --git a/src/renderer_vulkan.c b/src/renderer_vulkan.c index c2e5407..c42f6c7 100644 --- a/src/renderer_vulkan.c +++ b/src/renderer_vulkan.c @@ -363,22 +363,6 @@ vImageViewCreate(TexMeta meta) return view; } -static vTransfer * -vTextureTransferInit(Arena *arena, u32 asset_id, VkImage image, rawptr bytes, TexMeta *meta) -{ - vTransfer *transfer = MakeArray(arena, vTransfer, 1); - - transfer->type = vTT_IMAGE; - transfer->data = bytes; - transfer->w = meta->w; - transfer->h = meta->h; - transfer->ch = meta->ch; - transfer->asset_id = asset_id; - transfer->image = image; - - return transfer; -} - static b32 vImageViewInit(vImageView *view, u32 width, u32 height, u32 channels) { @@ -444,86 +428,12 @@ vImageViewInit(vImageView *view, u32 width, u32 height, u32 channels) return success; } -static void -vTextureCleanUp() -{ - VkDevice device = v_Renderer.handles.device; - VmaAllocator vma_alloc = v_Renderer.handles.vma_alloc; - HashTable *table = &v_Renderer.buffers.images; - b8 *queue = vFrameTexDestroyQueue(); - - // NOTE: might need a mutex here at some point, check if crashes related to image access - for (u64 i = 0; i < TEXTURE_ASSET_MAX; i++) - { - if (queue[i]) - { - rDescHandle handle = vDescHandlePop(vDT_SAMPLED_IMAGE, (u32)i); - vDescIndexPush(vDT_SAMPLED_IMAGE, handle.desc_index); - - vImageView *view = vImagePop(i); - Assert(view != NULL, "rTextureUnload failure: value not in hash table"); - - vkDestroyImageView(device, view->view, NULL); - vmaDestroyImage(vma_alloc, view->image.image, view->image.alloc); - - FLMemFree(view); - - queue[i] = false; - } - } - - pAtomicSignalFenceSeqCst(); -} - -static void -vImagePush(TextureAsset asset_id, vImageView *view) -{ - HashTablePushU64Rawptr(&v_Renderer.buffers.images, asset_id, view); -} - -static vImageView * -vImagePop(TextureAsset asset_id) -{ - return (vImageView *)HashTableDeleteU64Rawptr(&v_Renderer.buffers.images, asset_id); -} - -static vImageView * -vImageSearch(TextureAsset asset_id) -{ - vImageView *view = NULL; - - HashTable *table = &v_Renderer.buffers.images; - - KeyValuePair *pair = HashTableSearchU64(table, asset_id); - if (pair != NULL) - { - view = (vImageView *)pair->value_rawptr; - } - - return view; -} - // ::Vulkan::Images::Functions::End:: // ::Vulkan::Descriptors::Functions::Start:: - -static void -vDescPushImageAndHandle(rDescHandle handle, vImageView *view) -{ - vDescHandlePush(vDT_SAMPLED_IMAGE, handle); - vImagePush(handle.asset_id, view); -} - -static void -vDescPushModelAndHandle(rDescHandle handle, vModelBuffers *buffer) -{ - vDescHandlePush(vDT_MESH, handle); - vModelPush(handle.asset_id, buffer); -} - // TODO: batch descriptor writes static u32 vDescPushImageDesc(vImageView *view) @@ -598,89 +508,12 @@ vDescIndexPop(vDescType type) return bindings->free[bindings->free_count]; } -static rDescHandle -vDescHandleSearch(vDescType type, u32 asset_id) -{ - rDescHandle asset_info = { - .asset_id = UINT32_MAX, - }; - - HashTable *table = &v_Renderer.desc_bindings[type].lookup_table; - - KeyValuePair *kv_pair = HashTableSearchU64(table, asset_id); - if (kv_pair != NULL) - { - asset_info.asset_id = kv_pair->value_u64_split.upper; - asset_info.desc_index = kv_pair->value_u64_split.lower; - } - - return asset_info; -} - -static void -vDescHandlePush(vDescType type, rDescHandle handle) -{ - HashTable *table = &v_Renderer.desc_bindings[type].lookup_table; - HashTablePushU64U64Split(table, handle.asset_id, handle.asset_id, handle.desc_index); -} - -static rDescHandle -vDescHandlePop(vDescType type, u32 asset_id) -{ - HashTable *table = &v_Renderer.desc_bindings[type].lookup_table; - - U64Split split = HashTableDeleteU64U64Split(table, (u64)asset_id); - Assert(split.upper != UINT32_MAX, "vDescHandlePop failure: unable to find asset handle"); - - rDescHandle handle = { - .asset_id = split.upper, - .desc_index = split.lower, - }; - - return handle; -} - -static void -vDescHandleDelete(vDescType type, u32 asset_id) -{ - HashTable *table = &v_Renderer.desc_bindings[type].lookup_table; - HashTableDeleteU64(table, asset_id); -} - // ::Vulkan::Descriptors::Functions::End:: // ::Vulkan::Buffers::Functions::Start:: -static vTransfer * -vMeshTransferInit(Arena *arena, u32 asset_id, vMeshBuffer *mesh, rawptr bytes, u64 size) -{ - vTransfer *transfer = MakeArray(arena, vTransfer, 1); - - transfer->type = vTT_MESH; - transfer->data = bytes; - transfer->size = size; - transfer->mesh = mesh; - transfer->asset_id = asset_id; - - return transfer; -} - -static vTransfer * -vBufferTransferInit(Arena *arena, u32 asset_id, vBuffer *index, rawptr bytes, u64 size) -{ - vTransfer *transfer = MakeArray(arena, vTransfer, 1); - - transfer->type = vTT_BUFFER; - transfer->data = bytes; - transfer->asset_id = asset_id; - transfer->size = size; - transfer->buffer = index->buffer; - - return transfer; -} - static VkResult vBufferCreate(vBuffer* buf, rRenderBufferType type, u64 size) { @@ -765,32 +598,6 @@ vMapBuffer(VmaAllocation alloc) return ptr; } -static void -vModelPush(ModelAsset asset_id, vModelBuffers *buffer) -{ - HashTablePushU64Rawptr(&v_Renderer.buffers.buffers, asset_id, buffer); -} - -static vModelBuffers * -vModelPop(ModelAsset asset_id) -{ - return (vModelBuffers *)HashTableDeleteU64Rawptr(&v_Renderer.buffers.buffers, asset_id); -} - -static vModelBuffers * -vModelSearch(ModelAsset asset_id) -{ - vModelBuffers *buffers = NULL; - - KeyValuePair *pair = HashTableSearchU64(&v_Renderer.buffers.buffers, asset_id); - if (pair != NULL) - { - buffers = (vModelBuffers *)pair->value_rawptr; - } - - return buffers; -} - // ::Vulkan::Buffers::Functions::End:: diff --git a/src/renderer_vulkan.h b/src/renderer_vulkan.h index b8f8e02..b6a76fa 100644 --- a/src/renderer_vulkan.h +++ b/src/renderer_vulkan.h @@ -258,6 +258,36 @@ typedef struct vMeshBuffer vBuffer mesh, uniform; } vMeshBuffer; +// group assets +// set boolean for each group for loaded/request unload + +typedef struct vMeshAsset +{ + vMeshBuffer *mesh; + vBuffer *index; +} vMeshAsset; + +typedef enum vAssetType_e +{ + vAT_NONE, + vAT_TEXTURE, + vAT_MESH, +} vAssetType; + +typedef struct vAsset +{ + u64 hash; + rDescHandle handle; + union + { + vMeshAsset *mesh; + vImageView *texture; + }; + AssetMeta meta; +} vAsset; + +ArrayType(vAsset); + typedef struct vSwapchainState { VkFormat format; @@ -358,16 +388,10 @@ typedef struct vMappedBuffer typedef struct vRBuffers { - HashTable buffers; - vBufferPtrArray frame_buffers[FRAME_OVERLAP]; - - HashTable images; - vImageViewPtrArray frame_images[FRAME_OVERLAP]; - b8PtrArray tex_destroy_queue; - - vMappedBuffer transfer; - vMappedBuffer gui_vert; - vMappedBuffer gui_idx; + vAssetArray assets; + vMappedBuffer transfer; + vMappedBuffer gui_vert; + vMappedBuffer gui_idx; } vRBuffers; typedef struct vModelBuffers @@ -555,9 +579,6 @@ static vTransfer *vTextureTransferInit(Arena *arena, u32 asset_id, VkImage image static vImageView *vImageViewCreate(TexMeta meta); static b32 vImageViewInit(vImageView *view, u32 width, u32 height, u32 channels); static void vTextureCleanUp(); -static void vImagePush(TextureAsset asset_id, vImageView *view); -static vImageView *vImagePop(TextureAsset asset_id); -static vImageView *vImageSearch(TextureAsset asset_id); // ::Vulkan::Descriptors::Functions::Header:: @@ -568,7 +589,6 @@ static u32 vDescIndexPop(vDescType type); static rDescHandle vDescHandleSearch(vDescType type, u32 asset_id); static void vDescHandlePush(vDescType type, rDescHandle handle); static rDescHandle vDescHandlePop(vDescType type, u32 asset_id); -static void vDescHandleDelete(vDescType type, u32 asset_id); static u32 vDescPushImageDesc(vImageView *view); static u32 vDescPushMeshDesc(vMeshBuffer *buffer); @@ -578,9 +598,6 @@ static vTransfer *vMeshTransferInit(Arena *arena, u32 asset_id, vMeshBuffer *mes static vTransfer *vBufferTransferInit(Arena *arena, u32 asset_id, vBuffer *index, rawptr bytes, u64 size); static VkResult vBufferCreate(vBuffer* buf, rRenderBufferType type, u64 size); static rawptr vMapBuffer(VmaAllocation alloc); -static void vModelPush(c8 *name, vModelBuffers *buffer); -static vModelBuffers *vModelPop(c8 *name); -static vModelBuffers *vModelSearch(c8 *name); // ::Vulkan::CleanUp::Functions::Header:: diff --git a/src/shared_types.h b/src/shared_types.h deleted file mode 100644 index 7c8fb93..0000000 --- a/src/shared_types.h +++ /dev/null @@ -1,156 +0,0 @@ -#pragma once - -#include - -#ifdef __linux__ -#include -#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; diff --git a/src/stglib.h b/src/stglib.h new file mode 100644 index 0000000..ac3d517 --- /dev/null +++ b/src/stglib.h @@ -0,0 +1,3968 @@ +#pragma once + +#define STB_SPRINTF_IMPLEMENTATION + +#include "stb/stb_sprintf.h" +#include "xxhash/xxhash.h" + +#include "xxhash/xxhash.c" + +#include + +#ifdef __linux__ +#include +#endif + +// ::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 u64 usize; + +# elif defined ( _WIN32 ) + +typedef i32 isize; +typedef u32 usize; + +# endif + +#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]; + +// ::Util::Types::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; + +// ::DataStructures::Types::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; + +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; + +#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; + +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; + +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; + +// ********************* +// ***** PLATFORM ****** +// ********************* + +// ::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; + +// *********************** +// ******** LINUX ******** +// *********************** + +#if __linux__ + +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include + + // ::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::Globals::Start:: + + static pPlatformWindow + linux_window = + { + .w = 1920, + .h = 1080, + }; + + b32 + g_Global_Quit = false; + + // ::Platform::Linux::Globals::End:: + + + + // ::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); + +#endif + +// ************************** +// ******** WINDOWS ********* +// ************************** + +#if _WIN32 + +# include +# include +# include +# include +# include + + + // ::Platform::Windows::Defines::Header:: + +# define WINDOW_CLASS_NAME "GearsWindowClass" + + // ::Platform::Windows::Types::Header:: + + typedef ptrdiff_t ssize_t; + + 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(); + +#endif // _WIN32 + +// ::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 struct pWindowSize +{ + union + { + struct { u16 x, y; }; + struct { u16 w, h; }; + }; +} pWindowSize; + +typedef struct pMouseMotion +{ + union + { + struct { i16 x, y; }; + struct { i16 w, h; }; + }; +} pMouseMotion; + +typedef struct pGameInput +{ + union + { + pKeyboardInput kb_code; + pMouseInput m_code; + pMouseMotion motion_ev; + }; + b32 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:: + +void * pMemAlloc(usize size); +void * pMemAllocZeroed(usize size); +void * pMemRealloc(void * ptr, usize old_size, usize new_size); +void pMemFree(void * 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(char *dir); +char **pDirGetFileNames(Arena *arena, u32 *count); +static pFile pFileOpen(char *file_name, pFSAccess access); +static void pFileClose(pFile file); +static u64 pFileRead(pFile file, u64 offset, void * buf, u64 len); +static u64 pFileWrite(pFile file, u64 offset, void * buf, u64 len); +static u64 pFileSeek(pFile file, u64 pos); +static u64 pFileLength(pFile file); +static b32 pFSIsVisible(char *name, b32 is_dir); +static b32 pDirIsVisible(char *dir_name); +static b32 pFileIsVisible(char *file_name); +static b32 pFileCanAccess(char *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(void * proc, void * 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(uint8_t 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); + +// ::Platform::ConsoleOut::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 ********* +// *********************** + +// ::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::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:: + +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); + +// ************************** +// ******* ALLOCATORS ******* +// ************************** + +// ::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:: + + +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:: + +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:: + +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); + +// **************************** +// ***** DATA STRUCTURES ****** +// **************************** + +// ::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) + +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:: + +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); + +#ifdef STG_IMPLEMENTATION + +#ifdef __linux__ + + // ::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:: + + void * + pMemAlloc(size_t size) + { + void * addr = mmap( + NULL, + size, + PROT_READ | PROT_WRITE, + MAP_ANON | MAP_PRIVATE, + -1, + 0 + ); + + if (pSyscallErrCheck(addr)) addr = NULL; + + return addr; + } + + void * + pMemAllocZeroed(size_t size) + { + void * ptr = pMemAlloc(size); + MemZero(ptr, size); + return ptr; + } + + void * + pMemRealloc(void * ptr, size_t old_size, size_t new_size) + { + void * addr = mremap( + ptr, + old_size, + new_size, + MAP_ANON | MAP_PRIVATE + ); + + if (pSyscallErrCheck(addr)) addr = NULL; + + return addr; + } + + void + pMemFree(void * ptr, size_t size) + { + Assert(munmap(ptr, size) == 0, "munmap failed"); + } + + size_t + pPageSize() + { + return (size_t)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(char *dir) + { + return chdir(dir); + } + + static pFile + pFileOpen(char *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, void * buf, u64 len) + { + lseek(file, (ssize_t)offset, SEEK_SET); + return read(file, buf, (size_t)len); + } + + static u64 + pFileWrite(pFile file, u64 offset, void * buf, u64 len) + { + lseek(file, (ssize_t)offset, SEEK_SET); + return write(file, buf, (size_t)len); + } + + static u64 + pFileSeek(pFile file, u64 pos) + { + return (u64)lseek(file, (ssize_t)pos, SEEK_SET); + } + + static u64 + pFileLength(pFile file) + { + ssize_t offset = lseek(file, 0, SEEK_CUR); + ssize_t size = lseek(file, 0, SEEK_END); + lseek(file, offset, SEEK_SET); + + if (size == -1) + size = UINT64_MAX; + + return (u64)size; + } + + char ** + 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; + } + } + + char **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 (char **)file_names; + } + + static b32 + pFSIsVisible(char *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(char *dir_name) + { + return pFSIsVisible(dir_name, true); + } + + static b32 + pFileIsVisible(char *file_name) + { + return pFSIsVisible(file_name, false); + } + + static b32 + pFileCanAccess(char *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:: + + + + // ::Platform::Linux::Print::Functions::Start:: + + i32 + pWriteStdOut(void * buf, i32 len) + { + return (i32)write(STDOUT, buf, len); + } + + i32 + pWriteStdErr(void * 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(void * proc, void * 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:: + +#endif // __linux__ + +#ifdef _WIN32 + + // ::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:: + + // ::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 }; + } + +#endif // _WIN32 + +// ::Platform::Functions::Start:: + +static i32 +SPrintf(char *buf, int len, void *fmt, ...) +{ + va_list arg; + + va_start(arg, fmt); + int sprf_res = stbsp_vsnprintf(buf, len, fmt, arg); + va_end(arg); + + return sprf_res; +} + +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, 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; +} + +// ::Platform::Functions::End:: + + +// ::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 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 + 1), + .len = str_len, + }; + + MemCpy(str.value, string.value, string.len); + MemCpy(str.value+string.len, append.value, append.len); + + str.value[str_len] = '\0'; + + 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:: + + +// ::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:: + + +// ::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:: + + + +// ::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:: + + + +#endif // STG_IMPLEMENTATION diff --git a/src/util.c b/src/util.c deleted file mode 100644 index 9d69e12..0000000 --- a/src/util.c +++ /dev/null @@ -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:: diff --git a/src/util.h b/src/util.h deleted file mode 100644 index e4adb72..0000000 --- a/src/util.h +++ /dev/null @@ -1,299 +0,0 @@ -#pragma once - -#include - -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);