diff --git a/build.sh b/build.sh index b9ffcb6..e324a24 100755 --- a/build.sh +++ b/build.sh @@ -16,6 +16,7 @@ if [ -v webgl ] && [ ! -v render_flag ]; then render_flag="-DSTG_WEBGL_RENDERER" if [ -v dx11 ] && [ ! -v render_flag ]; then render_flag="-DSTG_DX11_RENDERER"; echo "[dx11 renderer]"; fi if [ -v dx11 ]; then render_link="-l:libdxvk_d3d11.so.0"; fi if [ ! -v render_flag ]; then render_flag="-DSTG_VULKAN_RENDERER"; vulkan="vulkan"; echo "[default renderer - vulkan]"; fi +if [ -v test ]; then test_build=1; echo "[test build]"; fi # source files source_files="../src/entry_linux.c" @@ -46,16 +47,17 @@ glsl_stage_geom="-fshader-stage=geom" glsl_stage_comp="-fshader-stage=comp" glsl_out="-o./shaders/glsl/" - clang_common="${include_flags} ${render_flag} -g -Xclang -flto-visibility-public-std -Wno-unknown-warning-option -fdiagnostics-absolute-paths -Wall -Wno-missing-braces -Wno-unused-function -Wno-writable-strings -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-register -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-single-bit-bitfield-constant-conversion -Wno-compare-distinct-pointer-types -Wno-initializer-overrides -Wno-incompatible-pointer-types-discards-qualifiers -Wno-for-loop-analysis -DVMA_STATIC_VULKAN_FUNCTIONS=0" clang_debug="$compiler -g -O0 -DBUILD_DEBUG=1 ${clang_common}" clang_release="$compiler -g -O2 ${clang_common}" +clang_test="$compiler -O2 -DBUILD_TEST=1 ${clang_common}" clang_link="-lpthread -lm -lrt -ldl -l:libvma.a" clang_out="-o" gcc_common="${include_flags} ${render_flag} -std=c99 -fuse-ld=mold -g -Wno-unknown-warning-option -Wall -Wno-missing-braces -Wno-unused-function -Wno-attributes -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-compare-distinct-pointer-types -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf -DVMA_STATIC_VULKAN_FUNCTIONS=0" gcc_debug="$compiler -g -O0 -DBUILD_DEBUG=1 ${gcc_common}" -gcc_release="$compiler -g -O2 ${gcc_common} ${render_flag}" +gcc_release="$compiler -O2 ${gcc_common} ${render_flag}" +gcc_test="$compiler -O2 -DBUILD_TEST=1 ${gcc_common} ${render_flag}" gcc_link="-lpthread -lm -lrt -ldl ${render_link} -lstdc++" gcc_out="-o" @@ -64,16 +66,19 @@ link_os_gfx="-lxcb -lX11 -lX11-xcb -lvulkan" if [ -v gcc ]; then compile_debug="$gcc_debug"; fi if [ -v gcc ]; then compile_release="$gcc_release"; fi +if [ -v gcc ]; then compile_test="$gcc_test"; fi if [ -v gcc ]; then compile_link="$gcc_link"; fi if [ -v gcc ]; then out="$gcc_out"; fi if [ -v clang ]; then compile_debug="$clang_debug"; fi if [ -v clang ]; then compile_release="$clang_release"; fi +if [ -v clang ]; then compile_test="$clang_debug"; fi if [ -v clang ]; then compile_link="$clang_link"; fi if [ -v clang ]; then out="$clang_out"; fi if [ -v debug ]; then compile="$compile_debug"; fi if [ -v release ]; then compile="$compile_release"; fi +if [ -v test ]; then compile="$compile_test"; fi mkdir -p build diff --git a/src/allocators.c b/src/allocators.c index f8e5324..1573c42 100644 --- a/src/allocators.c +++ b/src/allocators.c @@ -66,14 +66,14 @@ static Arena * CreateArenaDebug(rawptr buffer, isize length, u32 init_line_no) // ::Allocator::FreeList::Start:: -static FreeListAlloc *CreateFreeListAlloc(isize init_size, isize grow_size) +static Alloc *CreateFreeListAlloc(isize init_size, isize grow_size) { - isize size = init_size + sizeof(FreeListAlloc) + sizeof(FreeListBuffer) + sizeof(rawptr) + sizeof(FLNode); + isize size = init_size + sizeof(Alloc) + sizeof(FreeListBuffer) + sizeof(rawptr) + sizeof(RBNode); u8 *mem = (u8 *)MemAllocZeroed(size); - FreeListAlloc *fl_alloc = (FreeListAlloc *)mem; + Alloc *fl_alloc = (Alloc *)mem; u8 *pre_mem = mem; - mem = (u8 *)PtrAdd(mem, sizeof(FreeListAlloc)); + mem = (u8 *)PtrAdd(mem, sizeof(Alloc)); isize rem_size = (size) - (pre_mem - mem); fl_alloc->buf_len = 1; @@ -84,10 +84,10 @@ static FreeListAlloc *CreateFreeListAlloc(isize init_size, isize grow_size) mem = (u8 *)PtrAdd(mem, sizeof(FreeListBuffer)); rem_size -= pre_mem - mem; - fl_alloc->nil = (FLNode *)mem; + fl_alloc->nil = (RBNode *)mem; pre_mem = mem; - mem = (u8 *)PtrAdd(mem, sizeof(FLNode)); + mem = (u8 *)PtrAdd(mem, sizeof(RBNode)); rem_size -= pre_mem - mem; fl_alloc->buffers[0].buf = mem; @@ -97,7 +97,7 @@ static FreeListAlloc *CreateFreeListAlloc(isize init_size, isize grow_size) return fl_alloc; } -static void DeallocFreeListAlloc(FreeListAlloc *alloc) +static void DeallocFreeListAlloc(Alloc *alloc) { for (u8 i = alloc->buf_len-1; i >= 0; i--) { @@ -108,4 +108,21 @@ static void DeallocFreeListAlloc(FreeListAlloc *alloc) } } +static rawptr FLAlloc(Alloc *alloc, isize size) +{ + return NULL; +} + +static void FLFree(Alloc *alloc, rawptr ptr) +{ + +} + +static void FreeListGrow(Alloc *alloc) +{ + u8 *mem = (u8 *)MemAllocZeroed(alloc->grow_size); + + +} + // ::Allocator::FreeList::End:: diff --git a/src/allocators.h b/src/allocators.h index bd24b6c..090cd08 100644 --- a/src/allocators.h +++ b/src/allocators.h @@ -28,24 +28,6 @@ static Arena *CreateArenaDebug(rawptr buffer, isize length, u32 init_line_no); // ::Allocator::FreeList::Header:: -typedef enum FLNodeColor_e -{ - RB_RED, - RB_BLACK, -} FLNodeColor; - -typedef struct FLNode_t FLNode; - -typedef struct FLNode_t -{ - FLNode *parent; - FLNode *left; - FLNode *right; - i32 value; - rawptr data; - FLNodeColor color; -} FLNode; - typedef struct FreeListBuffer_t { rawptr buf; @@ -53,18 +35,21 @@ typedef struct FreeListBuffer_t u32 free_size; } FreeListBuffer; -typedef struct FreeListAlloc_t +typedef struct Alloc_t { - FLNode *head; - FLNode *nil; + RBNode *head; + RBNode *nil; FreeListBuffer *buffers; isize grow_size; u8 buf_len; -} FreeListAlloc; +} Alloc; -static FreeListAlloc *CreateFreeListAlloc(isize init_size, isize grow_size); -static void DeallocFreeListAlloc(FreeListAlloc *alloc); -static inline b32 FLNodeInsert(FreeListAlloc *alloc, FLNode *node); -static inline void FLNodeDelete(FLNode *node); -static inline void FLNodeLeftRotate(FLNode *node); -static inline void FLNodeRightRotate(FLNode *node); +static Alloc *CreateFreeListAlloc(isize init_size, isize grow_size); +static void DeallocFreeListAlloc(Alloc *alloc); +static void FreeListGrow(Alloc *alloc); +static rawptr FLAlloc(Alloc *alloc, isize size); +static void FLFree(Alloc *alloc, rawptr ptr); +static inline b32 FLNodeInsert(Alloc *alloc, RBNode *node); +static inline void FLNodeDelete(RBNode *node); +static inline void FLNodeLeftRotate(RBNode *node); +static inline void FLNodeRightRotate(RBNode *node); diff --git a/src/assets.h b/src/assets.h index 66b3639..a2e7b80 100644 --- a/src/assets.h +++ b/src/assets.h @@ -52,3 +52,5 @@ typedef enum ModelAssetTag_e { MODEL_ASSET_TAG_MAX, } ModelAssetTag; + + diff --git a/src/ds.c b/src/ds.c index 139597f..304f60a 100644 --- a/src/ds.c +++ b/src/ds.c @@ -1,2 +1,322 @@ +RBNode RB_NIL = { .color = RB_BLACK }; + +static void CreateRBTree(RBTree *tree) +{ + Assert(tree != NULL, "RBTree is null"); + RB_NIL.right = RB_NIL.left = RB_NIL.parent = &RB_NIL; + + tree->root = &RB_NIL; + tree->nil = &RB_NIL; +} + +static void RBTreeInsert(RBTree *tree, RBNode *node) +{ + 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->value < node->value) + { + if (curr_node->right == tree->nil) + { + node->parent = curr_node; + curr_node->right = node; + break; + } + else + { + curr_node = curr_node->right; + } + } + else + { + if (curr_node->left == tree->nil) + { + node->parent = curr_node; + curr_node->left = node; + break; + } + else + { + curr_node = curr_node->left; + } + } + } + } + + if (node->parent->color != RB_BLACK) + 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, i32 value) +{ + RBNode *node = NULL; + Assert(RBTreeSearch(tree, value, &node), "Unable to find node in RBTreeDelete"); + + 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->value = ln->value; + node->data = ln->data; + + 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->value = node->left->value; + node->data = node->left->data; + node->left = tree->nil; + } + else if (node->color == RB_BLACK && node->right != tree->nil) + { + node->value = node->right->value; + node->data = node->right->data; + 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 RBTreeSearch(RBTree *tree, i32 value, RBNode **out_node) +{ + if (tree->root == tree->nil) return false; + + b32 found = false; + RBNode *node = tree->root; + + while (true) + { + if (node->value == value) + { + found = true; + break; + } + + if (node == tree->nil) + break; + + if (node->value < value) + 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; +} + diff --git a/src/ds.h b/src/ds.h index 45dcbb0..d992e5c 100644 --- a/src/ds.h +++ b/src/ds.h @@ -1,3 +1,50 @@ #pragma once +typedef enum RBNodeColor_e +{ + RB_RED, + RB_BLACK, +} RBNodeColor; +typedef enum RBNodeDir_e +{ + RB_LEFT, + RB_RIGHT, +} RBNodeDir; + +typedef struct RBNode_t RBNode; + +typedef struct RBNode_t +{ + RBNode *parent; + union + { + struct + { + RBNode *left; + RBNode *right; + }; + RBNode *child[2]; + }; + i32 value; + rawptr data; + RBNodeColor color; +} RBNode; + +typedef struct RBTree_t +{ + RBNode *root; + RBNode *nil; +} RBTree; + +#define NodeDir(node) (node == node->parent->left ? RB_LEFT : RB_RIGHT) + +static void CreateRBTree(RBTree *tree); +static void RBTreeInsert(RBTree *tree, RBNode *node); +static b32 RBTreeSearch(RBTree *tree, i32 value, RBNode **out_node); +static void RBTreeDelete(RBTree *tree, i32 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 inline void RBTreeTransplant(RBTree *tree, RBNode *node, RBNode *placed_node); diff --git a/src/entry_linux.c b/src/entry_linux.c index d3cdc1c..1b9a676 100644 --- a/src/entry_linux.c +++ b/src/entry_linux.c @@ -12,9 +12,85 @@ #include "allocators.c" #include "renderer.c" #include "game.c" +#ifdef BUILD_TEST +# include "tests.c" +#endif + +void TraverseNode(RBTree *tree, RBNode *node, RBNodeDir *dir) +{ + char *dir_str = dir == NULL ? "Root" : *dir == RB_RIGHT ? "Right" : "Left"; + Printfln("Color: %s Value: %d Dir: %s", node->color == RB_RED ? "Red" : "Black", node->value, dir_str); + if (node->left != tree->nil) + { + RBNodeDir left_dir = RB_LEFT; + TraverseNode(tree, node->left, &left_dir); + } + if (node->right != tree->nil) + { + RBNodeDir right_dir = RB_RIGHT; + TraverseNode(tree, node->right, &right_dir); + } +} + +void Traverse(RBTree *tree) +{ + TraverseNode(tree, tree->root, NULL); +} int main(int argc, char **argv) { +#ifdef BUILD_TEST + RunTests(); + + return 0; +#endif + + RBTree tree; + CreateRBTree(&tree); + RBNode node1 = { .value = 4 }; + RBNode node2 = { .value = 7 }; + RBNode node3 = { .value = 33 }; + RBNode node4 = { .value = 53 }; + RBNode node5 = { .value = 25 }; + RBNode node6 = { .value = 22 }; + RBNode node7 = { .value = 6 }; + RBNode node8 = { .value = 1 }; + + RBTreeInsert(&tree, &node1); + RBTreeInsert(&tree, &node2); + RBTreeInsert(&tree, &node3); + RBTreeInsert(&tree, &node4); + RBTreeInsert(&tree, &node5); + RBTreeInsert(&tree, &node6); + RBTreeInsert(&tree, &node7); + RBTreeInsert(&tree, &node8); + + RBNode *search_node = NULL; + Assert(RBTreeSearch(&tree, 25, &search_node), "Unable to find node"); + Assert(search_node->value == 25, "Node has an invalid value"); + + RBTreeDelete(&tree, 25); + + RBNode node9 = { .value = 57 }; + RBTreeInsert(&tree, &node9); + + RBTreeDelete(&tree, 22); + + RBNode node10 = { .value = 59 }; + RBNode node11 = { .value = 60 }; + RBNode node12 = { .value = 58 }; + + RBTreeInsert(&tree, &node10); + RBTreeInsert(&tree, &node11); + RBTreeInsert(&tree, &node12); + + RBTreeDelete(&tree, 59); + RBTreeDelete(&tree, 33); + + Traverse(&tree); + + return 0; + u8 *mem = (u8 *)MemAllocZeroed(MB(64)); Arena *arena = CreateArenaDebug(mem, MB(64), __LINE__); diff --git a/src/entry_linux.h b/src/entry_linux.h index f834e1a..87c687a 100644 --- a/src/entry_linux.h +++ b/src/entry_linux.h @@ -21,6 +21,10 @@ #include "renderer.h" #include "game.h" +#ifdef BUILD_TEST +# include "tests.h" +#endif + int main(int argc, char **argv); #endif // __linux__ diff --git a/src/packer.c b/src/packer.c index c3fd737..c558bed 100644 --- a/src/packer.c +++ b/src/packer.c @@ -90,7 +90,9 @@ u64 FileLength(FILE *file) u64 WriteData(void *buf, u64 pos, u64 size, FILE *file) { Assert(fseek(file, pos, SEEK_SET) == 0, "WriteData fseek failure"); - return FWrite(buf, size, 1, file); + u64 written = (u64)FWrite(buf, size, 1, file); + fflush(file); + return written; } u64 ReadData(void *buf, u64 pos, u64 size, FILE *file) @@ -293,15 +295,11 @@ void PackFiles(Arena *arena, FileHeader *header) WriteData(shader_assets, header->asset_offsets[SHADER_ASSET], sizeof(AssetFile)*SHADER_ASSET_MAX, file); WriteData(texture_assets, header->asset_offsets[TEXTURE_ASSET], sizeof(AssetFile)*TEXTURE_ASSET_MAX, file); - FileLength(file); - ChangeDir(return_dir); } void PrintBytes(u8 *bytes, u64 len) { - return; - u32 count = 0; while (count + 8 < len) { diff --git a/src/renderer_vulkan_public.c b/src/renderer_vulkan_public.c index c866871..4554b7f 100644 --- a/src/renderer_vulkan_public.c +++ b/src/renderer_vulkan_public.c @@ -47,8 +47,6 @@ b32 InitRenderer(Arena *arena) ArenaFree(renderer.arena); return true; - - return true; } void DestroyRenderer() diff --git a/src/tests.c b/src/tests.c new file mode 100644 index 0000000..2688695 --- /dev/null +++ b/src/tests.c @@ -0,0 +1,5 @@ + +void RunTests() +{ + +} diff --git a/src/tests.h b/src/tests.h new file mode 100644 index 0000000..ad3af62 --- /dev/null +++ b/src/tests.h @@ -0,0 +1,3 @@ +#pragma once + +void RunTests();