diff --git a/build.bat b/build.bat index 648d026d..3158f280 100644 --- a/build.bat +++ b/build.bat @@ -2,6 +2,7 @@ setlocal enabledelayedexpansion cd /D "%~dp0" if not exist build mkdir build +pushd build :::::::::::::::::::::::::::::::: ::~ Unpack args @@ -31,8 +32,7 @@ if "%debug%" == "1" echo [Debug] if "%meta%" == "1" ( echo [Building meta] - :: cl.exe /Fe"build/" /Fo"build/" /c src\\meta\\meta.c /link build/meta.obj - "cl" /Zi /DEBUG src/meta/meta.c /Fo:build/meta.obj /Fe:build/meta.exe /nologo + "cl" ../src/meta/meta.c /Od /Z7 /nologo /link /DEBUG:FULL /INCREMENTAL:NO if not "!errorlevel!" == "0" ( echo . @@ -47,7 +47,7 @@ if "%meta%" == "1" ( if "%pp%" == "1" ( echo [Building power play] - "build/meta.exe" pp + "meta.exe" pp if not "!errorlevel!" == "0" ( echo. diff --git a/res/font/fixedsys.ttf b/res/pp/font/fixedsys.ttf similarity index 100% rename from res/font/fixedsys.ttf rename to res/pp/font/fixedsys.ttf diff --git a/res/noise_128x128x64_16.dat b/res/pp/noise_128x128x64_16.dat similarity index 100% rename from res/noise_128x128x64_16.dat rename to res/pp/noise_128x128x64_16.dat diff --git a/res/sound/test.mp3 b/res/pp/sound/test.mp3 similarity index 100% rename from res/sound/test.mp3 rename to res/pp/sound/test.mp3 diff --git a/res/sprite/blood.ase b/res/pp/sprite/blood.ase similarity index 100% rename from res/sprite/blood.ase rename to res/pp/sprite/blood.ase diff --git a/res/sprite/box.ase b/res/pp/sprite/box.ase similarity index 100% rename from res/sprite/box.ase rename to res/pp/sprite/box.ase diff --git a/res/sprite/box_rounded.ase b/res/pp/sprite/box_rounded.ase similarity index 100% rename from res/sprite/box_rounded.ase rename to res/pp/sprite/box_rounded.ase diff --git a/res/sprite/bullet.ase b/res/pp/sprite/bullet.ase similarity index 100% rename from res/sprite/bullet.ase rename to res/pp/sprite/bullet.ase diff --git a/res/sprite/crosshair.ase b/res/pp/sprite/crosshair.ase similarity index 100% rename from res/sprite/crosshair.ase rename to res/pp/sprite/crosshair.ase diff --git a/res/sprite/gun.ase b/res/pp/sprite/gun.ase similarity index 100% rename from res/sprite/gun.ase rename to res/pp/sprite/gun.ase diff --git a/res/sprite/tile.ase b/res/pp/sprite/tile.ase similarity index 100% rename from res/sprite/tile.ase rename to res/pp/sprite/tile.ase diff --git a/res/sprite/tim.ase b/res/pp/sprite/tim.ase similarity index 100% rename from res/sprite/tim.ase rename to res/pp/sprite/tim.ase diff --git a/src/app/app.lay b/src/app/app.lay index 957d354f..d147cc61 100644 --- a/src/app/app.lay +++ b/src/app/app.lay @@ -1,8 +1,6 @@ @Layer app -//////////////////////////////// -//~ Dependencies - +//- Dependencies @Dep base @Dep platform @Dep ttf @@ -20,7 +18,8 @@ @Dep playback @Dep pp -//////////////////////////////// -//~ Api +//- Api +@IncludeC app_core.h -@ApiC app_core +//- Impl +@IncludeC app_core.c diff --git a/src/ase/ase.lay b/src/ase/ase.lay index cc024a10..2b3367e8 100644 --- a/src/ase/ase.lay +++ b/src/ase/ase.lay @@ -1,12 +1,11 @@ @Layer ase -//////////////////////////////// -//~ Dependencies - +//- Dependencies @Dep base @Dep bitbuff -//////////////////////////////// -//~ Api +//- Api +@IncludeC ase_core.h -@ApiC ase_core +//- Impl +@IncludeC ase_core.c diff --git a/src/asset_cache/asset_cache.lay b/src/asset_cache/asset_cache.lay index a6987d73..ddc4b364 100644 --- a/src/asset_cache/asset_cache.lay +++ b/src/asset_cache/asset_cache.lay @@ -1,17 +1,14 @@ @Layer asset_cache -//////////////////////////////// -//~ Dependencies - +//- Dependencies @Dep base @Dep platform -//////////////////////////////// -//~ Api +//- Api +@IncludeC asset_cache_core.h -@ApiC asset_cache_core +//- Impl +@IncludeC asset_cache_core.c -//////////////////////////////// -//~ Init - -@Init AC_StartupCore +//- Startup +@Startup AC_StartupCore diff --git a/src/base/base.lay b/src/base/base.lay index 07e1b5af..45d9e38e 100644 --- a/src/base/base.lay +++ b/src/base/base.lay @@ -1,33 +1,42 @@ @Layer base -//////////////////////////////// -//~ Api +@Dep mp3 -@ApiC base_core -@ApiC base_intrinsics -@ApiC base_memory -@ApiC base_arena -@ApiC base_snc -@ApiC base_job -@ApiC base_uid -@ApiC base_string -@ApiC base_uni -@ApiC base_gstat -@ApiC base_buddy -@ApiC base_math -@ApiC base_rand -@ApiC base_util -@ApiC base_incbin -@ApiC base_entry +//- Api +@IncludeC base_core.h +@IncludeC base_intrinsics.h +@IncludeC base_memory.h +@IncludeC base_arena.h +@IncludeC base_snc.h +@IncludeC base_job.h +@IncludeC base_uid.h +@IncludeC base_string.h +@IncludeC base_uni.h +@IncludeC base_gstat.h +@IncludeC base_buddy.h +@IncludeC base_math.h +@IncludeC base_rand.h +@IncludeC base_util.h +@IncludeC base_incbin.h +@IncludeC base_entry.h +@IncludeGpu base_core.h +@IncludeGpu base_math_gpu.h -@ApiGpu base_core -@ApiGpu base_math_gpu +//- Impl +@IncludeC base_memory.c +@IncludeC base_arena.c +@IncludeC base_snc.c +@IncludeC base_uid.c +@IncludeC base_string.c +@IncludeC base_uni.c +@IncludeC base_gstat.c +@IncludeC base_buddy.c +@IncludeC base_math.c +@IncludeC base_rand.c +@IncludeC base_incbin.c -//- Win32 -@ApiCWindows win32/base_win32_job -@ApiCWindows win32/base_win32_entry +//- Win32 impl +@DefaultWindowsImpl base_win32 -//////////////////////////////// -//~ Init - -@Init StartupBaseJobs +//- Startup +@Startup StartupBaseJobs diff --git a/src/base/base_core.h b/src/base/base_core.h index eea569ac..6ad5b138 100644 --- a/src/base/base_core.h +++ b/src/base/base_core.h @@ -236,9 +236,9 @@ void __asan_unpoison_memory_region(void const volatile *add, size_t); //- Fallthrough #if CompilerIsClang -# define FALLTHROUGH -#else # define FALLTHROUGH __attribute((fallthrough)) +#else +# define FALLTHROUGH #endif //- Preprocessor concatenation @@ -263,7 +263,7 @@ void __asan_unpoison_memory_region(void const volatile *add, size_t); //~ Type helper macros //- alignof -#if (CompilerIsMsvc && LanguageIsC) || (LanguageIsC && (__STDC_VERSION__ < 202311L)) +#if LanguageIsC && (CompilerIsMsvc || __STDC_VERSION__ < 202311L) # define alignof(type) __alignof(type) #endif diff --git a/src/base/base_math.c b/src/base/base_math.c index cb05a245..f77d0625 100644 --- a/src/base/base_math.c +++ b/src/base/base_math.c @@ -1376,7 +1376,7 @@ SoftSpring MakeSpring(f32 hertz, f32 damping_ratio, f32 dt) Mat4x4 Mat4x4FromXform(Xform xf) { - return CppCompatInitListType(Mat4x4) + return (Mat4x4) { .e = { {xf.bx.x, xf.bx.y, 0, 0}, diff --git a/src/base/base_math.h b/src/base/base_math.h index cca831f1..a8c65199 100644 --- a/src/base/base_math.h +++ b/src/base/base_math.h @@ -10,7 +10,7 @@ Struct(Vec2) { f32 x, y; }; -#define VEC2(x, y) CppCompatInitListType(Vec2) { (x), (y) } +#define VEC2(x, y) (Vec2) { (x), (y) } Struct(Vec2Array) { Vec2 *points; @@ -23,7 +23,7 @@ Struct(Vec2Array) { Struct(Vec3) { f32 x, y, z; }; -#define VEC3(x, y, z) CppCompatInitListType(Vec3) { (x), (y), (z) } +#define VEC3(x, y, z) (Vec3) { (x), (y), (z) } Struct(Vec3Array) { Vec3 *points; @@ -49,7 +49,7 @@ Struct(Vec4Array) { Struct(Vec2I32) { i32 x, y; }; -#define VEC2I32(x, y) CppCompatInitListType(Vec2I32) { (x), (y) } +#define VEC2I32(x, y) (Vec2I32) { (x), (y) } //////////////////////////////// //~ Integer vector3 types @@ -57,7 +57,7 @@ Struct(Vec2I32) { Struct(Vec3I32) { i32 x, y, z; }; -#define VEC3I32(x, y, z) CppCompatInitListType(Vec3I32) { (x), (y), (z) } +#define VEC3I32(x, y, z) (Vec3I32) { (x), (y), (z) } //////////////////////////////// //~ Integer vector4 types @@ -66,7 +66,7 @@ Struct(Vec4I32) { i32 x, y, z, w; }; -#define VEC4I32(x, y, z, w) CppCompatInitListType(Vec4I32) { (x), (y), (z), (w) } +#define VEC4I32(x, y, z, w) (Vec4I32) { (x), (y), (z), (w) } //////////////////////////////// //~ Xform types @@ -90,7 +90,8 @@ Struct(Trs) //~ Rect types Struct(Rect) { - union { + union + { struct { f32 x, y, width, height; }; struct { Vec2 pos, size; }; }; @@ -114,7 +115,8 @@ Struct(Aabb) { //~ Quad types Struct(Quad) { - union { + union + { struct { Vec2 p0, p1, p2, p3; }; struct { Vec2 e[4]; }; }; @@ -329,7 +331,7 @@ Vec2I32 SubVec2I32(Vec2I32 a, Vec2I32 b); b32 EqXform(Xform xf1, Xform xf2); //- Initialization -#define XformIdentity CppCompatInitListType(Xform) { .bx = VEC2(1, 0), .by = VEC2(0, 1) } +#define XformIdentity (Xform) { .bx = VEC2(1, 0), .by = VEC2(0, 1) } #define XformIdentityNoCast { .bx = VEC2(1, 0), .by = VEC2(0, 1) } Xform XformFromPos(Vec2 v); Xform XformFromRot(f32 r); diff --git a/src/base/base_string.h b/src/base/base_string.h index 4ebb7077..ba5ef891 100644 --- a/src/base/base_string.h +++ b/src/base/base_string.h @@ -1,30 +1,3 @@ -//////////////////////////////// -//~ String types - -Struct(String) -{ - u64 len; - u8 *text; -}; - -Struct(String16) -{ - u64 len; - u16 *text; -}; - -Struct(String32) -{ - u64 len; - u32 *text; -}; - -Struct(StringArray) -{ - u64 count; - String *strings; -}; - //////////////////////////////// //~ Formatting types @@ -85,8 +58,8 @@ Struct(CodepointIter) //////////////////////////////// //~ String utils -#define StringFromPointers(p0, p1) (CppCompatInitListType(String) { (u8 *)(p1) - (u8 *)(p0), (u8 *)p0 }) -#define StringFromStruct(ptr) (CppCompatInitListType(String) { sizeof(*(ptr)), (u8 *)(ptr) }) +#define StringFromPointers(p0, p1) ((String) { (u8 *)(p1) - (u8 *)(p0), (u8 *)p0 }) +#define StringFromStruct(ptr) ((String) { sizeof(*(ptr)), (u8 *)(ptr) }) #define StringFromArena(arena) (STRING((arena)->pos, ArenaBase(arena))) /* String from static array */ diff --git a/src/bitbuff/bitbuff.lay b/src/bitbuff/bitbuff.lay index e58dfb25..ee8ecaef 100644 --- a/src/bitbuff/bitbuff.lay +++ b/src/bitbuff/bitbuff.lay @@ -1,11 +1,10 @@ @Layer bitbuff -//////////////////////////////// -//~ Dependencies +//- Dependencies +@Dep base -@dep base +//- Api +@IncludeC bitbuff_core.h -//////////////////////////////// -//~ Api - -@ApiC bitbuff_core +//- Impl +@IncludeC bitbuff_core.c diff --git a/src/collider/collider.lay b/src/collider/collider.lay index da3a9f28..4adee776 100644 --- a/src/collider/collider.lay +++ b/src/collider/collider.lay @@ -1,11 +1,10 @@ @Layer collider -//////////////////////////////// -//~ Dependencies - +//- Dependencies @Dep base -//////////////////////////////// -//~ Api +//- Api +@IncludeC collider_core.h -@ApiC collider_core +//- Impl +@IncludeC collider_core.c diff --git a/src/draw/draw.lay b/src/draw/draw.lay index a5f7a4b1..4a9ce459 100644 --- a/src/draw/draw.lay +++ b/src/draw/draw.lay @@ -1,20 +1,17 @@ @Layer draw -//////////////////////////////// -//~ Dependencies - +//- Dependencies @Dep base @Dep gpu @Dep sprite @Dep font @Dep collider -//////////////////////////////// -//~ Api +//- Api +@IncludeC draw_core.h -@ApiC draw_core +//- Impl +@IncludeC draw_core.c -//////////////////////////////// -//~ Init - -@Init D_StartupCore +//- Init +@Startup D_StartupCore diff --git a/src/font/font.lay b/src/font/font.lay index 6a3e5db2..1c27b4a0 100644 --- a/src/font/font.lay +++ b/src/font/font.lay @@ -1,15 +1,14 @@ @Layer font -//////////////////////////////// -//~ Dependencies - +//- Dependencies @Dep base @Dep ttf @Dep gpu @Dep resource @Dep asset_cache -//////////////////////////////// -//~ Api +//- Api +@IncludeC font_core.h -@ApiC font_core +//- Impl +@IncludeC font_core.c diff --git a/src/gpu/gpu.lay b/src/gpu/gpu.lay index e4ec0d17..d351487e 100644 --- a/src/gpu/gpu.lay +++ b/src/gpu/gpu.lay @@ -1,20 +1,14 @@ @Layer gpu -//////////////////////////////// -//~ Dependencies - +//- Dependencies @Dep base @Dep platform -//////////////////////////////// -//~ Api +//- Api +@IncludeC gpu_core.h -@ApiC gpu_core +//- Dx12 impl +@DefaultWindowsImpl gpu_dx12 -//- Dx12 -@ApiCWindows dx12/gpu_dx12 - -//////////////////////////////// -//~ Init - -@Init GPU_StartupCore +//- Startup +@Startup GPU_StartupCore diff --git a/src/inc/inc.lay b/src/inc/inc.lay index 80186c02..335c9b18 100644 --- a/src/inc/inc.lay +++ b/src/inc/inc.lay @@ -1,11 +1,10 @@ @Layer inc -//////////////////////////////// -//~ Dependencies - +//- Dependencies @Dep base -//////////////////////////////// -//~ Api +//- Api +@IncludeC inc_core.h -@ApiC inc_core +//- Impl +@IncludeC inc_core.c diff --git a/src/json/json.lay b/src/json/json.lay index 62e52c5a..402139b3 100644 --- a/src/json/json.lay +++ b/src/json/json.lay @@ -1,11 +1,10 @@ @Layer json -//////////////////////////////// -//~ Dependencies - +//- Dependencies @Dep base -//////////////////////////////// -//~ Api +//- Api +@IncludeC json_core.h -@ApiC json_core +//- Impl +@IncludeC json_core.c diff --git a/src/kernel/kernel.lay b/src/kernel/kernel.lay index 1d905368..cf5a6e2a 100644 --- a/src/kernel/kernel.lay +++ b/src/kernel/kernel.lay @@ -1,12 +1,8 @@ @Layer kernel -//////////////////////////////// -//~ Dependencies - +//- Dependencies @Dep base -//////////////////////////////// -//~ Api - -@ApiC kernel_core -@ApiGpu kernel_core +//- Api +@IncludeC kernel_core.h +@IncludeGpu kernel_core.h diff --git a/src/meta/meta.c b/src/meta/meta.c index cef29159..69695295 100644 --- a/src/meta/meta.c +++ b/src/meta/meta.c @@ -1,30 +1,12 @@ +/* TODO: Move decls to meta.h */ + //////////////////////////////// //~ Includes -//- Header files -#include "meta_core.h" +#include "meta_base/meta_base_inc.h" +#include "meta_os/meta_os_inc.h" +#include "meta_file/meta_file_inc.h" #include "meta.h" -#include "meta_intrinsics.h" -#include "meta_memory.h" -#include "meta_math.h" -#include "meta_arena.h" -#include "meta_string.h" -#include "meta_uni.h" -#include "meta_os.h" -#if PlatformIsWindows -# include "win32/meta_win32.h" -#endif - -//- Source files -#include "meta_core.c" -#include "meta_memory.c" -#include "meta_math.c" -#include "meta_arena.c" -#include "meta_string.c" -#include "meta_uni.c" -#if PlatformIsWindows -# include "win32/meta_win32.c" -#endif //////////////////////////////// //~ Util @@ -41,6 +23,632 @@ void Echo(String msg) fflush(stdout); EndScratch(scratch); } + +Struct(LineCol) +{ + i64 line; + i64 col; +}; + +LineCol LineColFromFilePos(String file, i64 pos) +{ + TempArena scratch = BeginScratchNoConflict(); + LineCol result = ZI; + String data = F_DataFromFile(scratch.arena, file); + for (u64 cur = 0; cur < data.len && cur <= pos; ++cur) + { + u8 c = data.text[cur]; + if (c == '\n') + { + ++result.line; + result.col = 0; + } + else if (c != '\r') + { + ++result.col; + } + } + result.line += 1; + EndScratch(scratch); + return result; +} + +//////////////////////////////// +//~ Lay tokenizer + +Struct(L_Token) +{ + b32 bof; + b32 eof; + i64 pos; + String s; + L_Token *prev; + L_Token *next; +}; + +Struct(L_TokenList) +{ + L_Token *first; + L_Token *last; +}; + +typedef i32 L_TokenizerMode; enum +{ + L_TokenizerMode_None, + L_TokenizerMode_SingleLineComment, + L_TokenizerMode_MultiLineComment +}; + +/* FIXME: Ignore comments */ +L_TokenList L_TokensFromString(Arena *arena, String s) +{ + L_TokenList result = ZI; + /* Push start nil token */ + { + L_Token *beginning = PushStruct(arena, L_Token); + beginning->prev = beginning; /* Self link */ + beginning->pos = -1; + result.first = beginning; + result.last = beginning; + beginning->bof = 1; + } + + /* Tokenize */ + u64 pos = 0; + String cur_text = ZI; + cur_text.text = s.text; + L_TokenizerMode mode = L_TokenizerMode_None; + while (pos < s.len) + { + u8 c = s.text[pos]; + switch (mode) + { + case L_TokenizerMode_None: + { + if (c == ' ' || c == '\n' || c == 0 || pos == s.len - 1) + { /* Whitespace */ + if (cur_text.len > 0) + { + L_Token *t = PushStruct(arena, L_Token); + t->s = PushString(arena, cur_text); + t->pos = (cur_text.text - s.text); + if (result.last) + { + result.last->next = t; + } + else + { + result.first = t; + } + t->prev = result.last; + result.last = t; + cur_text.len = 0; + } + pos += 1; + } + else if (c == '/' && (pos + 1) < s.len && s.text[pos + 1] == '/') + { /* Start single line comment */ + mode = L_TokenizerMode_SingleLineComment; + pos += 2; + } + else if (c == '/' && (pos + 1) < s.len && s.text[pos + 1] == '*') + { /* Start multi line comment */ + mode = L_TokenizerMode_MultiLineComment; + pos += 2; + } + else + { + if (cur_text.len == 0) + { + cur_text.text = &s.text[pos]; + } + ++cur_text.len; + pos += 1; + } + } break; + + case L_TokenizerMode_SingleLineComment: + { + if (c == '\n') + { /* End single line comment */ + mode = L_TokenizerMode_None; + pos += 1; + } + else + { + pos += 1; + } + } break; + + case L_TokenizerMode_MultiLineComment: + { + if (c == '*' && (pos + 1) < s.len && s.text[pos + 1] == '/') + { /* End multi line comment */ + mode = L_TokenizerMode_None; + pos += 2; + } + else + { + pos += 1; + } + } break; + }; + } + + /* Push end nil token */ + { + L_Token *ending = PushStruct(arena, L_Token); + ending->next = ending; /* Self link */ + ending->prev = result.last; + ending->pos = s.len; + result.last->next = ending; + result.last = ending; + ending->eof = 1; + } + return result; +} + +//////////////////////////////// +//~ Blob + +typedef i32 L_ParseMode; enum +{ + L_ParseMode_None, + L_ParseMode_LayerName, + L_ParseMode_Dep, + L_ParseMode_IncludeC, + L_ParseMode_IncludeGpu, + L_ParseMode_ShaderVS, + L_ParseMode_ShaderPS, + L_ParseMode_ShaderCS, + L_ParseMode_Startup, + L_ParseMode_DefaultWindowsImpl, +}; + +typedef i32 L_BlobTopoColor; enum +{ + L_BlobTopoColor_None, + L_BlobTopoColor_Queued, + L_BlobTopoColor_Visiting, + L_BlobTopoColor_Finished, +}; + +Struct(L_BlobItem) +{ + L_BlobItem *next; + String s; + String token_file; + i64 token_pos; +}; + +Struct(L_BlobItemList) +{ + L_BlobItem *first; + L_BlobItem *last; + i64 count; +}; + +Struct(L_Blob) +{ + L_Blob *next; + + L_BlobItemList names; + L_BlobItemList deps; + L_BlobItemList c_includes; + L_BlobItemList gpu_includes; + L_BlobItemList vertex_shaders; + L_BlobItemList pixel_shaders; + L_BlobItemList compute_shaders; + L_BlobItemList startup_functions; + L_BlobItemList default_windows_impls; + + L_BlobItemList errors; + + L_BlobTopoColor topo_color; +}; + +Struct(L_ParseResult) +{ + L_Blob *first_blob; + L_Blob *last_blob; + Dict *blobs_dict; + u64 blobs_count; +}; + +L_BlobItem *L_PushBlobItem(Arena *arena, L_BlobItemList *list, String token_file, i64 token_pos, String item_string) +{ + L_BlobItem *item = PushStruct(arena, L_BlobItem); + item->s = item_string; + item->token_file = token_file; + item->token_pos = token_pos; + if (list->last) + { + list->last->next = item; + } + else + { + list->first = item; + } + list->last = item; + ++list->count; + return item; +} + +L_ParseResult L_ParseBlobsFromPaths(Arena *arena, StringList paths) +{ + TempArena scratch = BeginScratch(arena); + L_ParseResult result = ZI; + result.blobs_dict = InitDict(arena, 1024); + + for (StringListNode *dir_node = paths.first; dir_node; dir_node = dir_node->next) + { + String dir = dir_node->s; + StringList files = ZI; + F_FilesFromDir(scratch.arena, &files, dir, F_IterFlag_Recurse); + for (StringListNode *file_node = files.first; file_node; file_node = file_node->next) + { + if (EqString(F_ExtensionFromFile(file_node->s), Lit("lay"))) + { + String file = PushString(arena, file_node->s); + String data = F_DataFromFile(scratch.arena, file); + L_TokenList tokens = L_TokensFromString(scratch.arena, data); + L_ParseMode mode = L_ParseMode_None; + L_Blob *blob = PushStruct(arena, L_Blob); + if (result.last_blob) + { + result.last_blob->next = blob; + } + else + { + result.first_blob = blob; + } + result.last_blob = blob; + ++result.blobs_count; + for (L_Token *token = tokens.first->next; !token->eof; token = token->next) + { + String s = token->s; + if (mode == L_ParseMode_None) + { + if (EqString(s, Lit("@Layer"))) mode = L_ParseMode_LayerName; + else if (EqString(s, Lit("@Dep"))) mode = L_ParseMode_Dep; + else if (EqString(s, Lit("@IncludeC"))) mode = L_ParseMode_IncludeC; + else if (EqString(s, Lit("@IncludeGpu"))) mode = L_ParseMode_IncludeGpu; + else if (EqString(s, Lit("@ShaderVS"))) mode = L_ParseMode_ShaderVS; + else if (EqString(s, Lit("@ShaderPS"))) mode = L_ParseMode_ShaderPS; + else if (EqString(s, Lit("@ShaderCS"))) mode = L_ParseMode_ShaderCS; + else if (EqString(s, Lit("@Startup"))) mode = L_ParseMode_Startup; + else if (EqString(s, Lit("@DefaultWindowsImpl"))) mode = L_ParseMode_DefaultWindowsImpl; + else + { + /* Encountered unexpected token, stop parsing */ + L_PushBlobItem(arena, &blob->errors, file, token->pos, StringF(arena, "Unexpected token '%F'", FmtString(s))); + break; + } + } + else + { + switch (mode) + { + case L_ParseMode_None: + { + if (EqString(s, Lit("@Layer"))) mode = L_ParseMode_LayerName; + else if (EqString(s, Lit("@Dep"))) mode = L_ParseMode_Dep; + else + { + L_PushBlobItem(arena, &blob->names, file, token->pos, s); + } + } break; + case L_ParseMode_LayerName: + { + L_PushBlobItem(arena, &blob->names, file, token->pos, s); + mode = L_ParseMode_None; + } break; + case L_ParseMode_Dep: + { + L_PushBlobItem(arena, &blob->deps, file, token->pos, s); + mode = L_ParseMode_None; + } break; + case L_ParseMode_IncludeC: + { + L_PushBlobItem(arena, &blob->c_includes, file, token->pos, s); + mode = L_ParseMode_None; + } break; + case L_ParseMode_IncludeGpu: + { + L_PushBlobItem(arena, &blob->gpu_includes, file, token->pos, s); + mode = L_ParseMode_None; + } break; + case L_ParseMode_ShaderVS: + { + L_PushBlobItem(arena, &blob->vertex_shaders, file, token->pos, s); + mode = L_ParseMode_None; + } break; + case L_ParseMode_ShaderPS: + { + L_PushBlobItem(arena, &blob->pixel_shaders, file, token->pos, s); + mode = L_ParseMode_None; + } break; + case L_ParseMode_ShaderCS: + { + L_PushBlobItem(arena, &blob->compute_shaders, file, token->pos, s); + mode = L_ParseMode_None; + } break; + case L_ParseMode_Startup: + { + L_PushBlobItem(arena, &blob->startup_functions, file, token->pos, s); + mode = L_ParseMode_None; + } break; + case L_ParseMode_DefaultWindowsImpl: + { + L_PushBlobItem(arena, &blob->default_windows_impls, file, token->pos, s); + mode = L_ParseMode_None; + } break; + } + } + } + if (mode != L_ParseMode_None) + { + L_PushBlobItem(arena, &blob->errors, file, tokens.last->pos, Lit("Unexpected end of file")); + } + if (blob->names.count == 1) + { + String name = blob->names.first->s; + u64 hash = HashFnv64(Fnv64Basis, name); + SetDictValue(arena, result.blobs_dict, hash, (u64)blob); + } + else if (blob->names.count == 0) + { + L_PushBlobItem(arena, &blob->errors, file, tokens.first->pos, Lit("Mising layer name")); + } + else + { + for (L_BlobItem *item = blob->names.first; item; item = item->next) + { + L_PushBlobItem(arena, &blob->errors, item->token_file, item->token_pos, Lit("Layer contains multiple names")); + } + } + } + } + } + + EndScratch(scratch); + return result; +} + +//////////////////////////////// +//~ Topo + +Struct(L_TopoItem) +{ + L_TopoItem *next; + String s; + String token_file; + i64 token_pos; +}; + +Struct(L_TopoItemList) +{ + L_TopoItem *first; + L_TopoItem *last; + u64 count; +}; + +Struct(L_Topo) +{ + L_TopoItemList c_includes; + L_TopoItemList errors; +}; + +L_TopoItem *L_PushTopoItem(Arena *arena, L_TopoItemList *list, String token_file, i64 token_pos, String item_string) +{ + L_TopoItem *item = PushStruct(arena, L_TopoItem); + item->s = item_string; + item->token_file = token_file; + item->token_pos = token_pos; + if (list->last) + { + list->last->next = item; + } + else + { + list->first = item; + } + list->last = item; + ++list->count; + return item; +} + +L_Topo L_TopoFromLayerName(Arena *arena, StringList starting_layer_names, StringList paths) +{ + TempArena scratch = BeginScratch(arena); + L_Topo result = ZI; + + /* Parse blobs */ + L_ParseResult parsed = L_ParseBlobsFromPaths(scratch.arena, paths); + + /* Topological sort */ + u64 sorted_count = 0; + L_Blob **sorted = PushStructsNoZero(scratch.arena, L_Blob *, parsed.blobs_count); + { + /* Build array from post-order DFS */ + { + u64 queue_count = 0; + L_Blob **queue = PushStructsNoZero(scratch.arena, L_Blob *, parsed.blobs_count); + for (StringListNode *n = starting_layer_names.first; n; n = n->next) + { + String s = n->s; + L_Blob *starting_blob = (L_Blob *)DictValueFromHash(parsed.blobs_dict, HashFnv64(Fnv64Basis, s)); + if (starting_blob) + { + if (starting_blob->topo_color == L_BlobTopoColor_None) + { + queue[queue_count++] = starting_blob; + } + } + else + { + L_PushTopoItem(arena, &result.errors, Lit(""), 0, StringF(arena, "Layer not found with name '%F'", FmtString(s))); + } + } + while (queue_count > 0) + { + L_Blob *blob = queue[--queue_count]; + blob->topo_color = L_BlobTopoColor_Visiting; + b32 has_unvisited_deps = 0; + for (L_BlobItem *dep_item = blob->deps.first; dep_item; dep_item = dep_item->next) + { + String dep_name = dep_item->s; + u64 dep_hash = HashFnv64(Fnv64Basis, dep_name); + L_Blob *dep_blob = (L_Blob *)DictValueFromHash(parsed.blobs_dict, dep_hash); + if (dep_blob) + { + if (dep_blob->topo_color == L_BlobTopoColor_None) + { + has_unvisited_deps = 1; + dep_blob->topo_color = L_BlobTopoColor_Queued; + queue[queue_count++] = dep_blob; + } + else if (dep_blob->topo_color == L_BlobTopoColor_Visiting) + { + String a = ZI; + String b = ZI; + if (blob->names.count > 0) a = blob->names.first->s; + if (dep_blob->names.count > 0) b = dep_blob->names.first->s; + String s = StringF(arena, "Cyclic dependency detected while processing layer '%F' -> '%F'", FmtString(a), FmtString(b)); + String file = PushString(arena, dep_item->token_file); + L_PushTopoItem(arena, &result.errors, file, dep_item->token_pos, s); + } + } + else + { + String s = StringF(arena, "Layer '%F' not found", FmtString(dep_name)); + String file = PushString(arena, dep_item->token_file); + L_PushTopoItem(arena, &result.errors, file, dep_item->token_pos, s); + } + } + if (has_unvisited_deps) + { + queue[queue_count++] = blob; + blob->topo_color = L_BlobTopoColor_Queued; + } + else + { + sorted[sorted_count++] = blob; + blob->topo_color = L_BlobTopoColor_Finished; + } + } + } + /* Reverse sorted array */ + i64 l = 0; + i64 r = sorted_count - 1; + while (l < r) + { + L_Blob *swp = sorted[l]; + sorted[l] = sorted[r]; + sorted[r] = swp; + ++l; + --r; + } + } + + /* Process sorted blobs into result */ + for (u64 i = 0; i < sorted_count; ++i) + { + L_Blob *blob = sorted[i]; + /* C includes */ + for (L_BlobItem *bitem = blob->c_includes.first; bitem; bitem = bitem->next) + { + String file = PushString(arena, bitem->token_file); + String s = PushString(arena, bitem->s); + L_PushTopoItem(arena, &result.c_includes, file, bitem->token_pos, s); + } + /* Errors */ + for (L_BlobItem *bitem = blob->errors.first; bitem; bitem = bitem->next) + { + String file = PushString(arena, bitem->token_file); + String s = PushString(arena, bitem->s); + L_PushTopoItem(arena, &result.errors, file, bitem->token_pos, s); + } + } + + /* Process errors of untouched blobs */ + for (L_Blob *blob = parsed.first_blob; blob; blob = blob->next) + { + if (blob->topo_color == L_BlobTopoColor_None && blob->errors.count > 0) + { + for (L_BlobItem *bitem = blob->errors.first; bitem; bitem = bitem->next) + { + String file = PushString(arena, bitem->token_file); + String s = PushString(arena, bitem->s); + L_PushTopoItem(arena, &result.errors, file, bitem->token_pos, s); + } + } + } + + EndScratch(scratch); + return result; +} + +//////////////////////////////// +//~ Error + +Struct(Error) +{ + String s; + String file; + i64 pos; + Error *next; +}; + +Struct(ErrorList) +{ + Error *first; + Error *last; + i64 count; +}; + +Error *PushError(Arena *arena, ErrorList *list, String file, i64 pos, String s) +{ + Error *e = PushStruct(arena, Error); + e->s = s; + e->file = file; + e->pos = pos; + if (list->last) + { + list->last->next = e; + } + else + { + list->first = e; + } + list->last = e; + ++list->count; + return e; +} + + + + + + + + + + + + + + + + + + + + + + + + //////////////////////////////// //~ Entry point @@ -48,17 +656,18 @@ void Echo(String msg) i32 main(i32 argc, u8 **argv) { //- Startup - StartupOs(); + StartupBase(); + OS_Startup(); Arena *arena = AcquireArena(Gibi(64)); //- Unpack args - StringList exe_layer_names = ZI; + StringList starting_layer_names = ZI; StringList args = ZI; i32 hyphens = 0; for (i32 i = 1; i < argc; ++i) { String arg = StringFromCstrNoLimit(argv[i]); - if (EqString(arg, Lit("-")) + if (EqString(arg, Lit("-"))) { ++hyphens; } @@ -66,397 +675,87 @@ i32 main(i32 argc, u8 **argv) { if (hyphens == 0) { - PushStringToList(perm, &exe_layer_names, arg); + PushStringToList(arena, &starting_layer_names, arg); } else { - PushStringToList(perm, &args, arg); + PushStringToList(arena, &args, arg); } } } - StringList lay_dirs = ZI; - PushStringToList(perm, &lay_dirs, Lit("src")); - LayResult lay_result = ParseLay(lay_dirs, exe_layer_names); + ErrorList errors = ZI; + StringList src_dirs = ZI; + PushStringToList(arena, &src_dirs, Lit("../src")); + L_Topo topo = L_TopoFromLayerName(arena, starting_layer_names, src_dirs); - - - - - // Things to do: - // - For each leaf layer: - // - Walk deps to determine all layers that must be built - - for ( - - for (StringListNode *n = exe_layer_names; n; n = n->next) + //- Process topo errors + if (errors.count <= 0 && topo.errors.count > 0) { - String name = n->s; - Lay *lay = LayFromName(name); - - for (LayItem *dep_objs - - Run("cl.exe obj_files out_path"); + StringList topo_errors = ZI; + u64 max_topo_errors = 50; + for (L_TopoItem *item = topo.errors.first; item && topo_errors.count < max_topo_errors; item = item->next) + { + PushError(arena, &errors, item->token_file, item->token_pos, item->s); + } } - - - - - - - - - for (StringListNode *n = exe_layer_names.first; n; n = n->next) + //- Generate C + if (errors.count <= 0) { - String name = n->s; - Lay *lay = LayFromName(name); - - Dict *visited_dict = InitDict(arena, 64); - - u64 level = 1; - for (LayEntry *dep = lay->deps.first; dep; dep = dep->next) + StringList c_out_lines = ZI; + PushStringToList(arena, &c_out_lines, Lit("// Auto generated file")); + for (L_TopoItem *item = topo.c_includes.first; item; item = item->next) { - String dep_name = dep->name; - u64 dep_hash = dep->name_hash; - SetDictValue(visited_dict, dep_hash, level); - - // Lay *dep_lay = LayFromName(dep_name); + String parent = F_GetParentDir(item->token_file); + String file = StringF(arena, "%F%F", FmtString(parent), FmtString(item->s)); + if (F_IsFile(file)) + { + String line = StringF(arena, "#include \"%F\"", FmtString(file)); + PushStringToList(arena, &c_out_lines, line); + } + else + { + String e = StringF(arena, "File '%F' not found", FmtString(file)); + PushError(arena, &errors, item->token_file, item->token_pos, e); + } } + String c_out = StringFromStringList(arena, c_out_lines, Lit("\n")); + F_ClearWrite(Lit("gen.c"), c_out); + Echo(c_out); } - - - - - - - - - - for (LayNode *leaf_lay_node = leaf_lays.first; leaf_lay_node; leaf_lay_node = leaf_lay_node->next) + //- Print errors + for (Error *e = errors.first; e; e = e->next) { - Lay *lay = leaf_lay_node->l; - String name = lay->name; - - for (LayNode *dep_node = lay->deps.first; + String s = e->s; + String file = e->file; + i64 pos = e->pos; + String error = ZI; + if (file.len > 0) + { + LineCol line_col = LineColFromFilePos(file, pos); + error = StringF(arena, + "%F:%F:%F: error: %F", + FmtString(file), + FmtSint(line_col.line), + FmtSint(line_col.col), + FmtString(s)); + } + else + { + error = StringF(arena, + "error: %F", + FmtString(s)); + } + Echo(error); } - for (StringListNode *n = obj_files.first; n; n = n->next) + //- Compile { - String file = n->s; - String cmd = StringF("cl.exe /c /Zi /DEBUG %F", file); + String cmd = Lit("\"cl\" /Zi /DEBUG src/build/tmp/gen.c /Fo:build/tmp/gen.obj /Fe:build/pp.exe /nologo"); + OS_RunCommand(cmd); } - for (StringListNode *n = gpu_code_files.first; n; n = n->next) - { - } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -#if 0 - StringList src_files; - FilesFromDir(arena, &src_files, Lit("src"), FileIterFlag_Recurse); - - //- Parse layer files in source directory - Dict *lay_info_dict = InitDict(arena, 1024); - for (StringListNode *n = src_files.first; n; n = n->next) - { - String file = n->s; - String extension = GetFileExtension(name); - if (MatchString(extension, Lit("lay")) - { - String file_data = StringFromFile(arena, file); - LayInfo *lay_info = PushStruct(arena, LayInfo); - *lay_info = LayInfoFromString(arena, file_data); - u64 hash = HashFnv64(Fnv64Basis, lay_info->name); - SetDictValue(lay_info_dict, hash, lay_info); - } - } - - for (DictEntry *e = lay_info_dict->first; e; e = e->next) - { - LayInfo *lay_info = (LayInfo *)e->value; - } - - - - - - - for (MetaNode *layer_node = layers.first; layer_node; layer_node = layer_node->next) - { - b32 has_cpu_code = 0; - b32 has_gpu_code = 0; - - Meta *layer = layer_node->m; - StringList cpu_api_header_files = ZI; - StringList gpu_api_header_files = ZI; - StringList c_api_code_files = ZI; - StringList cpp_api_code_files = ZI; - StringList gpu_api_code_files = ZI; - for (MetaNode *api_node = layer->apis.first; api_node; api_node = api_node->next) - { - Meta *api = api_node->m; - String api_name = api->name; - String h_file = StringF(arena, "%F.h", FmtStr(api_name)); - String c_file = StringF(arena, "%F.c", FmtStr(api_name)); - String cpp_file = StringF(arena, "%F.cpp", FmtStr(api_name)); - String gpu_file = StringF(arena, "%F.gpu", FmtStr(api_name)); - if (FileExists(h_file)) - { - if (api->api_kind == MetaApiKind_Cpu) - { - PushStringToList(arena, &cpu_api_header_files, h_file); - } - else if (api->api_kind == MetaApiKind_Gpu) - { - PushStringToList(arena, &gpu_api_header_files, h_file); - } - } - if (FileExists(c_file)) - { - PushStringToList(arena, &c_api_code_files, c_file); - has_cpu_code = 1; - } - if (FileExists(cpp_file)) - { - PushStringToList(arena, &cpp_api_code_files, cpp_file); - has_cpu_code = 1; - } - if (FileExists(gpu_file)) - { - PushStringToList(arena, &gpu_api_code_files, gpu_file); - has_gpu_code = 1; - } - } - - StringList cpu_dep_header_files = ZI; - StringList gpu_dep_header_files = ZI; - if (has_cpu_code || has_gpu_code) - { - for (MetaNode *dep_node = layer->deps.first; dep_node; dep_node = dep_node->next) - { - MetaNode *dep = dep_node->m; - String dep_name = dep->name; - } - } - } -#endif - - - - - - - - - - - - - - - - - - - - - - - -#if 0 - //- Build tree - String graph_file = ZI; - if (args.first) - { - graph_file = args.first->s; - } - MetaTree *tree = MetaTreeFromFile(graph_file); - - Rm("build/layers"); - Mkdir("build/layers"); - - StringList init_funcs = ZI; - for (MetaNode *layer = tree->first_layer; layer; layer = layer->next) - { - StringList cpu_header_files = ZI; - StringList gpu_header_files = ZI; - StringList c_files = ZI; - StringList cpp_files = ZI; - StringList gpu_files = ZI; - for (MetaNode *api = layer->first_api; api; api = api->next) - { - String api_name = api->name; - String h_file = StringF(arena, "%F.h", FmtStr(api_name)); - String c_file = StringF(arena, "%F.c", FmtStr(api_name)); - String cpp_file = StringF(arena, "%F.cpp", FmtStr(api_name)); - String gpu_file = StringF(arena, "%F.gpu", FmtStr(api_name)); - if (FileExists(h_file)) - { - if (api->api_kind == MetaApiKind_Cpu) - { - PushStringToList(arena, &cpu_header_files, h_file); - } - else if (api->api_kind == MetaApiKind_Gpu) - { - PushStringToList(arena, &gpu_header_files, h_file); - } - } - if (FileExists(c_file)) PushStringToList(arena, &c_files, c_file); - if (FileExists(cpp_file)) PushStringToList(arena, &cpp_files, cpp_file); - if (FileExists(gpu_file)) PushStringToList(arena, &gpu_files, gpu_file); - } - - StringList cpu_dep_files = ZI; - StringList gpu_dep_files = ZI; - for (MetaNode *dep = layer->first_dep; dep; dep = dep->next) - { - String dep_name = dep->name; - if (dep->has_cpu_api) - { - String cpu_dep_file = StringF(arena, "%F__cpu_api.h", FmtStr(dep_name)); - PushStringToList(arena, &cpu_dep_files, cpu_dep_file); - } - if (dep->has_gpu_api) - { - String gpu_dep_file = StringF(arena, "%F__gpu_api.h", FmtStr(dep_name)); - PushStringToList(arena, &gpu_dep_files, gpu_dep_file); - } - } - - StringList cpu_header_lines = ZI; - StringList gpu_header_lines = ZI; - StringList c_code_lines = ZI; - StringList cpp_code_lines = ZI; - StringList gpu_code_lines = ZI; - - //- Cpu header file - { - PushStringNodeF(arena, &cpu_header_lines, "// Auto generated Cpu layer header file"); - - PushStringNodeF(arena, &cpu_header_lines, "////////////////////////////////\n//~ Api header includes"); - for (StringListNode *n = cpu_header_files.first; n; n = n->next) - { - String line = StringF(arena, "#include <%F>", FmtStr(n->s)); - PushStringToList(arena, &cpu_header_lines, line); - } - } - - //- Gpu header file - { - PushStringNodeF(arena, &gpu_header_lines, "// Auto generated Gpu layer header file"); - - PushStringNodeF(arena, &gpu_header_lines, "////////////////////////////////\n//~ Api header includes"); - for (StringListNode *n = gpu_header_files.first; n; n = n->next) - { - String line = StringF(arena, "#include <%F>", FmtStr(n->s)); - PushStringToList(arena, &gpu_header_lines, line); - } - } - - //- C code file - { - PushStringNodeF(arena, &c_code_lines, "// Auto generated C layer code file"); - - PushStringNodeF(arena, &c_code_lines, "////////////////////////////////\n//~ Layer dependency includes"); - for (StringListNode *n = cpu_dep_files.first; n; n = n->next) - { - String line = StringF(arena, "#include <%F>", FmtStr(n->s)); - PushStringToList(arena, &c_code_lines, line); - } - - PushStringNodeF(arena, &c_code_lines, "////////////////////////////////\n//~ Api code includes"); - for (StringListNode *n = c_files.first; n; n = n->next) - { - String line = StringF(arena, "#include <%F>", FmtStr(n->s)); - PushStringToList(arena, &c_code_lines, line); - } - } - - //- Gpu code file - { - PushStringNodeF(arena, &gpu_code_lines, "// Auto generated Gpu layer code file"); - - PushStringNodeF(arena, &c_code_lines, "////////////////////////////////\n//~ Layer dependency includes"); - for (StringListNode *n = gpu_dep_files.first; n; n = n->next) - { - String line = StringF(arena, "#include <%F>", FmtStr(n->s)); - PushStringToList(arena, &gpu_code_lines, line); - } - - PushStringNodeF(arena, &gpu_code_lines, "////////////////////////////////\n//~ Api code includes"); - for (StringListNode *n = gpu_files.first; n; n = n->next) - { - String line = StringF(arena, "#include <%F>", FmtStr(n->s)); - PushStringToList(arena, &gpu_code_lines, line); - } - } - - - - - - - - // { - // String init_name = init->name; - // PushStringToList(arena, init_funcs, init_name); - // } - // full_path = n->full_path; - // String line = StringF(arena, "#include <%F>", full_path); - // PushStringToList(arena, &gen_lines, line); - } -#endif - - - - - - - - return 0; + return errors.count > 0; } diff --git a/src/meta/meta_core.h b/src/meta/meta_base/meta_base.h similarity index 95% rename from src/meta/meta_core.h rename to src/meta/meta_base/meta_base.h index c72c7994..4b957f54 100644 --- a/src/meta/meta_core.h +++ b/src/meta/meta_base/meta_base.h @@ -235,9 +235,9 @@ void __asan_unpoison_memory_region(void const volatile *add, size_t); //- Fallthrough #if CompilerIsClang -# define FALLTHROUGH -#else # define FALLTHROUGH __attribute((fallthrough)) +#else +# define FALLTHROUGH #endif //- Preprocessor concatenation @@ -262,7 +262,7 @@ void __asan_unpoison_memory_region(void const volatile *add, size_t); //~ Type helper macros //- alignof -#if (CompilerIsMsvc && LanguageIsC) || (LanguageIsC && (__STDC_VERSION__ < 202311L)) +#if LanguageIsC && (CompilerIsMsvc || __STDC_VERSION__ < 202311L) # define alignof(type) __alignof(type) #endif @@ -450,8 +450,8 @@ Struct(Atomic32) { volatile i32 _v; }; Struct(Atomic64) { volatile i64 _v; }; //- Cache-line isolated aligned atomic types -AlignedStruct(Atomic8Padded, 64) { Atomic8 v; u8 _pad[60]; }; -AlignedStruct(Atomic16Padded, 64) { Atomic16 v; u8 _pad[60]; }; +AlignedStruct(Atomic8Padded, 64) { Atomic8 v; u8 _pad[63]; }; +AlignedStruct(Atomic16Padded, 64) { Atomic16 v; u8 _pad[62]; }; AlignedStruct(Atomic32Padded, 64) { Atomic32 v; u8 _pad[60]; }; AlignedStruct(Atomic64Padded, 64) { Atomic64 v; u8 _pad[56]; }; StaticAssert(sizeof(Atomic8Padded) == 64 && alignof(Atomic8Padded) == 64); @@ -517,11 +517,21 @@ ForceInline void UnlockTicketMutex(TicketMutex *tm) #endif //////////////////////////////// -//~ String types +//~ String utils -#define STRING(size, data) (CppCompatInitListType(String) { (size), (data) }) -#define Lit(cstr_lit) CppCompatInitListType(String) { (sizeof((cstr_lit)) - 1), (u8 *)(cstr_lit) } +#define STRING(size, data) ((String) { (size), (data) }) +#define Lit(cstr_lit) (String) { (sizeof((cstr_lit)) - 1), (u8 *)(cstr_lit) } #define LitNoCast(cstr_lit) { .len = (sizeof((cstr_lit)) - 1), .text = (u8 *)(cstr_lit) } +#define StringFromPointers(p0, p1) ((String) { (u8 *)(p1) - (u8 *)(p0), (u8 *)p0 }) +#define StringFromStruct(ptr) ((String) { sizeof(*(ptr)), (u8 *)(ptr) }) +#define StringFromArena(arena) (STRING((arena)->pos, ArenaBase(arena))) + +/* String from static array */ +#define StringFromArray(a) \ + ( \ + Assert(IsArray(a)), \ + ((String) { .len = sizeof(a), .text = (u8 *)(a) }) \ + ) Struct(String) { @@ -544,7 +554,8 @@ Struct(String32) //////////////////////////////// //~ @hookdecl Core hooks -void Panic(String msg); +void StartupBase(void); +b32 Panic(String msg); b32 IsRunningInDebugger(void); i16 ThreadId(void); diff --git a/src/meta/meta_arena.c b/src/meta/meta_base/meta_base_arena.c similarity index 100% rename from src/meta/meta_arena.c rename to src/meta/meta_base/meta_base_arena.c diff --git a/src/meta/meta_arena.h b/src/meta/meta_base/meta_base_arena.h similarity index 94% rename from src/meta/meta_arena.h rename to src/meta/meta_base/meta_base_arena.h index d980952d..8671aeb2 100644 --- a/src/meta/meta_arena.h +++ b/src/meta/meta_base/meta_base_arena.h @@ -57,6 +57,9 @@ extern SharedArenaCtx shared_arena_ctx; #define PopStruct(a, type, dst) PopBytes((a), sizeof(type), dst) #define PopStructs(a, type, n, dst) PopBytes((a), sizeof(type) * (n), dst) +#define PopStructNoCopy(a, type) PopBytesNoCopy((a), sizeof(type)) +#define PopStructsNoCopy(a, type, n) PopBytesNoCopy((a), sizeof(type) * (n)) + /* Returns a pointer to where the next push would be (at alignment of type). * Equivalent to PushStruct but without actually allocating anything or modifying the arena. */ #define PushDry(a, type) (type *)(_PushDry((a), alignof(type))) @@ -84,6 +87,15 @@ Inline void PopTo(Arena *arena, u64 pos) arena->pos = pos; } +Inline void PopBytesNoCopy(Arena *arena, u64 size) +{ + Assert(arena->pos >= size); + Assert(!arena->readonly); + u64 new_pos = arena->pos - size; + AsanPoison(ArenaBase(arena) + new_pos, arena->pos - new_pos); + arena->pos = new_pos; +} + Inline void PopBytes(Arena *arena, u64 size, void *copy_dst) { Assert(arena->pos >= size); diff --git a/src/meta/meta_base/meta_base_inc.h b/src/meta/meta_base/meta_base_inc.h new file mode 100644 index 00000000..0f191d71 --- /dev/null +++ b/src/meta/meta_base/meta_base_inc.h @@ -0,0 +1,21 @@ +//- Header files +#include "meta_base.h" +#include "meta_base_intrinsics.h" +#include "meta_base_memory.h" +#include "meta_base_arena.h" +#include "meta_base_math.h" +#include "meta_base_uni.h" +#include "meta_base_string.h" +#include "meta_base_util.h" + +//- Source files +#include "meta_base_arena.c" +#include "meta_base_math.c" +#include "meta_base_memory.c" +#include "meta_base_string.c" +#include "meta_base_uni.c" + +//- Win32 +#if PlatformIsWindows +# include "meta_base_win32/meta_base_win32_inc.h" +#endif diff --git a/src/meta/meta_intrinsics.h b/src/meta/meta_base/meta_base_intrinsics.h similarity index 100% rename from src/meta/meta_intrinsics.h rename to src/meta/meta_base/meta_base_intrinsics.h diff --git a/src/meta/meta_math.c b/src/meta/meta_base/meta_base_math.c similarity index 99% rename from src/meta/meta_math.c rename to src/meta/meta_base/meta_base_math.c index 1c11fa63..edc74d78 100644 --- a/src/meta/meta_math.c +++ b/src/meta/meta_base/meta_base_math.c @@ -293,12 +293,12 @@ f32 LnF32(f32 x) if ((x_int & 0x7fffffff) == 0) { /* Return -inf if x is 0 */ - return -two_p25 / 0; + return -F32Infinity; } else if (x_int < 0) { /* Return NaN if x is negative */ - return (x - x) / 0; + return F32Nan; } k -= 25; x *= two_p25; @@ -391,7 +391,7 @@ f32 ExpF32(f32 x) /* Filter out non-finite argument */ if (x_uint >= 0x42b17218) - { /* if |x|>=88.721... */ + { /* if |x| >= 88.721... */ if (x_uint > 0x7f800000) { return x + x; /* NaN */ @@ -1377,7 +1377,7 @@ SoftSpring MakeSpring(f32 hertz, f32 damping_ratio, f32 dt) Mat4x4 Mat4x4FromXform(Xform xf) { - return CppCompatInitListType(Mat4x4) + return (Mat4x4) { .e = { {xf.bx.x, xf.bx.y, 0, 0}, diff --git a/src/meta/meta_math.h b/src/meta/meta_base/meta_base_math.h similarity index 94% rename from src/meta/meta_math.h rename to src/meta/meta_base/meta_base_math.h index cca831f1..a8c65199 100644 --- a/src/meta/meta_math.h +++ b/src/meta/meta_base/meta_base_math.h @@ -10,7 +10,7 @@ Struct(Vec2) { f32 x, y; }; -#define VEC2(x, y) CppCompatInitListType(Vec2) { (x), (y) } +#define VEC2(x, y) (Vec2) { (x), (y) } Struct(Vec2Array) { Vec2 *points; @@ -23,7 +23,7 @@ Struct(Vec2Array) { Struct(Vec3) { f32 x, y, z; }; -#define VEC3(x, y, z) CppCompatInitListType(Vec3) { (x), (y), (z) } +#define VEC3(x, y, z) (Vec3) { (x), (y), (z) } Struct(Vec3Array) { Vec3 *points; @@ -49,7 +49,7 @@ Struct(Vec4Array) { Struct(Vec2I32) { i32 x, y; }; -#define VEC2I32(x, y) CppCompatInitListType(Vec2I32) { (x), (y) } +#define VEC2I32(x, y) (Vec2I32) { (x), (y) } //////////////////////////////// //~ Integer vector3 types @@ -57,7 +57,7 @@ Struct(Vec2I32) { Struct(Vec3I32) { i32 x, y, z; }; -#define VEC3I32(x, y, z) CppCompatInitListType(Vec3I32) { (x), (y), (z) } +#define VEC3I32(x, y, z) (Vec3I32) { (x), (y), (z) } //////////////////////////////// //~ Integer vector4 types @@ -66,7 +66,7 @@ Struct(Vec4I32) { i32 x, y, z, w; }; -#define VEC4I32(x, y, z, w) CppCompatInitListType(Vec4I32) { (x), (y), (z), (w) } +#define VEC4I32(x, y, z, w) (Vec4I32) { (x), (y), (z), (w) } //////////////////////////////// //~ Xform types @@ -90,7 +90,8 @@ Struct(Trs) //~ Rect types Struct(Rect) { - union { + union + { struct { f32 x, y, width, height; }; struct { Vec2 pos, size; }; }; @@ -114,7 +115,8 @@ Struct(Aabb) { //~ Quad types Struct(Quad) { - union { + union + { struct { Vec2 p0, p1, p2, p3; }; struct { Vec2 e[4]; }; }; @@ -329,7 +331,7 @@ Vec2I32 SubVec2I32(Vec2I32 a, Vec2I32 b); b32 EqXform(Xform xf1, Xform xf2); //- Initialization -#define XformIdentity CppCompatInitListType(Xform) { .bx = VEC2(1, 0), .by = VEC2(0, 1) } +#define XformIdentity (Xform) { .bx = VEC2(1, 0), .by = VEC2(0, 1) } #define XformIdentityNoCast { .bx = VEC2(1, 0), .by = VEC2(0, 1) } Xform XformFromPos(Vec2 v); Xform XformFromRot(f32 r); diff --git a/src/meta/meta_memory.c b/src/meta/meta_base/meta_base_memory.c similarity index 100% rename from src/meta/meta_memory.c rename to src/meta/meta_base/meta_base_memory.c diff --git a/src/meta/meta_memory.h b/src/meta/meta_base/meta_base_memory.h similarity index 100% rename from src/meta/meta_memory.h rename to src/meta/meta_base/meta_base_memory.h diff --git a/src/meta/meta_string.c b/src/meta/meta_base/meta_base_string.c similarity index 96% rename from src/meta/meta_string.c rename to src/meta/meta_base/meta_base_string.c index 1e831453..e1c5d9eb 100644 --- a/src/meta/meta_string.c +++ b/src/meta/meta_base/meta_base_string.c @@ -1,5 +1,5 @@ //////////////////////////////// -//~ Conversion +//~ Conversion helpers //- Char conversion @@ -171,7 +171,7 @@ String StringFromF64(Arena *arena, f64 f, u32 precision) } //////////////////////////////// -//~ String operations +//~ String helpers //- Copy @@ -433,11 +433,11 @@ b32 StringEndsWith(String str, String substring) } //////////////////////////////// -//~ String list operations +//~ String list helpers -StringNode *PushStringNode(Arena *arena, StringList *l, String s) +StringListNode *PushStringToList(Arena *arena, StringList *l, String s) { - StringNode *n = PushStruct(arena, StringNode); + StringListNode *n = PushStruct(arena, StringListNode); n->s = s; n->prev = l->last; if (l->last) @@ -449,9 +449,28 @@ StringNode *PushStringNode(Arena *arena, StringList *l, String s) l->first = n; } l->last = n; + ++l->count; return n; } +String StringFromStringList(Arena *arena, StringList l, String separator) +{ + String result = ZI; + result.text = PushDry(arena, u8); + for (StringListNode *n = l.first; n; n = n->next) + { + String s = n->s; + PushString(arena, s); + result.len += s.len; + if (n->next) + { + PushString(arena, separator); + result.len += separator.len; + } + } + return result; +} + //////////////////////////////// //~ Formatting diff --git a/src/meta/meta_string.h b/src/meta/meta_base/meta_base_string.h similarity index 83% rename from src/meta/meta_string.h rename to src/meta/meta_base/meta_base_string.h index 3078eee1..9a4db4e4 100644 --- a/src/meta/meta_string.h +++ b/src/meta/meta_base/meta_base_string.h @@ -7,17 +7,18 @@ Struct(StringArray) String *strings; }; -Struct(StringNode) +Struct(StringListNode) { String s; - StringNode *next; - StringNode *prev; + StringListNode *next; + StringListNode *prev; }; Struct(StringList) { - StringNode *first; - StringNode *last; + StringListNode *first; + StringListNode *last; + u64 count; }; //////////////////////////////// @@ -71,24 +72,7 @@ Struct(CodepointIter) }; //////////////////////////////// -//~ String utils - -#define STRING(size, data) (CppCompatInitListType(String) { (size), (data) }) -#define Lit(cstr_lit) CppCompatInitListType(String) { (sizeof((cstr_lit)) - 1), (u8 *)(cstr_lit) } -#define LitNoCast(cstr_lit) { .len = (sizeof((cstr_lit)) - 1), .text = (u8 *)(cstr_lit) } -#define StringFromPointers(p0, p1) (CppCompatInitListType(String) { (u8 *)(p1) - (u8 *)(p0), (u8 *)p0 }) -#define StringFromStruct(ptr) (CppCompatInitListType(String) { sizeof(*(ptr)), (u8 *)(ptr) }) -#define StringFromArena(arena) (STRING((arena)->pos, ArenaBase(arena))) - -/* String from static array */ -#define StringFromArray(a) \ - ( \ - Assert(IsArray(a)), \ - ((String) { .len = sizeof(a), .text = (u8 *)(a) }) \ - ) - -//////////////////////////////// -//~ Conversion operations +//~ Conversion helpers String StringFromChar(Arena *arena, char c); String StringFromU64(Arena *arena, u64 n, u64 base, u64 zfill); @@ -97,7 +81,7 @@ String StringFromPtr(Arena *arena, void *ptr); String StringFromF64(Arena *arena, f64 f, u32 precision); //////////////////////////////// -//~ String operation +//~ String helpers String PushString(Arena *arena, String src); String PushStringToBuff(String dst, String src); @@ -112,6 +96,12 @@ b32 StringContains(String str, String substring); b32 StringStartsWith(String str, String substring); b32 StringEndsWith(String str, String substring); +//////////////////////////////// +//~ String list helpers + +StringListNode *PushStringToList(Arena *arena, StringList *l, String s); +String StringFromStringList(Arena *arena, StringList l, String separator); + //////////////////////////////// //~ Formatting @@ -130,6 +120,7 @@ b32 StringEndsWith(String str, String substring); #define FmtEnd (FmtArg) {.kind = FmtKind_End} //- Format functions +#define StringF(arena, lit, ...) _StringFormat((arena), Lit(lit), __VA_ARGS__, FmtEnd) #define StringFormat(arena, fmt, ...) _StringFormat((arena), (fmt), __VA_ARGS__, FmtEnd) String _StringFormat(Arena *arena, String fmt, ...); String StringFormatV(Arena *arena, String fmt, va_list args); diff --git a/src/meta/meta_uni.c b/src/meta/meta_base/meta_base_uni.c similarity index 100% rename from src/meta/meta_uni.c rename to src/meta/meta_base/meta_base_uni.c diff --git a/src/meta/meta_uni.h b/src/meta/meta_base/meta_base_uni.h similarity index 100% rename from src/meta/meta_uni.h rename to src/meta/meta_base/meta_base_uni.h diff --git a/src/meta/meta_base/meta_base_util.h b/src/meta/meta_base/meta_base_util.h new file mode 100644 index 00000000..ecd0a761 --- /dev/null +++ b/src/meta/meta_base/meta_base_util.h @@ -0,0 +1,296 @@ +//////////////////////////////// +//~ Hash types + +#define Fnv64Basis 0xCBF29CE484222325 + +//////////////////////////////// +//~ Mergesort types + +/* Compare functions should + * return a positive value if a should go before b + * return a negative value if a should go after b + * return 0 otherwise + */ +#define MergesortCompareFuncDef(name, arg_a, arg_b, arg_udata) i32 name(void *arg_a, void *arg_b, void *arg_udata) +typedef MergesortCompareFuncDef(MergesortCompareFunc, a, b, udata); + +//////////////////////////////// +//~ Dict types + +Struct(DictEntry) +{ + u64 hash; + u64 value; + DictEntry *prev_in_bin; + DictEntry *next_in_bin; + DictEntry *prev; + DictEntry *next; +}; + +Struct(DictBin) +{ + DictEntry *first; + DictEntry *last; +}; + +Struct(Dict) +{ + u64 bins_count; + DictBin *bins; + DictEntry *first_free; + DictEntry *first; + DictEntry *last; +}; + +//////////////////////////////// +//~ Hash utils + +/* FNV-1a parameters for different hash sizes: + * https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function#FNV_hash_parameters + */ +Inline u64 HashFnv64(u64 seed, String s) +{ + u64 hash = seed; + for (u64 i = 0; i < s.len; ++i) + { + hash ^= (u8)s.text[i]; + hash *= 0x100000001B3; + } + return hash; +} + +//////////////////////////////// +//~ Mergesort utils + +Inline void MergesortInternal(u8 *left, u8 *right, u8 *items, u64 left_count, u64 right_count, u64 item_size, MergesortCompareFunc *callback, void *udata) +{ + /* Sort */ + u64 i = 0; + u64 l = 0; + u64 r = 0; + while (l < left_count && r < right_count) + { + u8 *dst = items + (i * item_size); + u8 *left_item = left + (l * item_size); + u8 *right_item = right + (r * item_size); + ++i; + if (callback(left_item, right_item, udata) > 0) + { + CopyBytes(dst, left_item, item_size); + ++l; + } + else + { + CopyBytes(dst, right_item, item_size); + ++r; + } + } + /* Copy remaining */ + if (l != left_count) + { + u64 remaining_count = left_count - l; + u64 remaining_bytes = remaining_count * item_size; + u8 *dst = items + (i * item_size); + u8 *src = left + (l * item_size); + CopyBytes(dst, src, remaining_bytes); + } + else if (r != right_count) + { + u64 remaining_count = right_count - r; + u64 remaining_bytes = remaining_count * item_size; + u8 *dst = items + (i * item_size); + u8 *src = right + (r * item_size); + CopyBytes(dst, src, remaining_bytes); + } +} + +Inline void Mergesort(void *items, u64 item_count, u64 item_size, MergesortCompareFunc *callback, void *udata) +{ + if (item_count > 1) + { + TempArena scratch = BeginScratchNoConflict(); + u64 left_count = item_count / 2; + u64 right_count = item_count - left_count; + + u64 left_size = left_count * item_size; + u64 right_size = right_count * item_size; + + u8 *left = PushStructsNoZero(scratch.arena, u8, left_size); + u8 *right = PushStructsNoZero(scratch.arena, u8, right_size); + CopyBytes(left, items, left_size); + CopyBytes(right, (u8 *)items + left_size, right_size); + + Mergesort(left, left_count, item_size, callback, udata); + Mergesort(right, right_count, item_size, callback, udata); + MergesortInternal(left, right, (u8 *)items, left_count, right_count, item_size, callback, udata); + EndScratch(scratch); + } +} + +//////////////////////////////// +//~ Dict utils + +//- Dict init + +Inline Dict *InitDict(Arena *arena, u64 bins_count) +{ + __prof; + Dict *dict = PushStruct(arena, Dict); + dict->bins_count = MaxU64(bins_count, 1); /* Ensure at least 1 bin */ + dict->bins = PushStructs(arena, DictBin, dict->bins_count); + return dict; +} + +Inline void ResetDict(Dict *dict) +{ + ZeroBytes(dict->bins, sizeof(*dict->bins) * dict->bins_count); + if (dict->first) + { + dict->last->next = dict->first_free; + dict->first_free = dict->first; + } +} + +//- Dict set + +Inline DictEntry *EnsureDictEntry(Arena *arena, Dict *dict, u64 hash) +{ + __prof; + DictBin *bin = &dict->bins[hash % dict->bins_count]; + + DictEntry *entry = bin->first; + while (entry) + { + if (hash == entry->hash) + { + /* Existing match found */ + break; + } + entry = entry->next_in_bin; + } + + /* No match found, create new entry */ + if (!entry) + { + if (dict->first_free) + { + entry = dict->first_free; + dict->first_free = entry->next; + } + else + { + entry = PushStructNoZero(arena, DictEntry); + } + ZeroStruct(entry); + entry->hash = hash; + if (bin->last) + { + bin->last->next_in_bin = entry; + entry->prev_in_bin = bin->last; + } + else + { + bin->first = entry; + } + bin->last = entry; + if (dict->last) + { + dict->last->next = entry; + entry->prev = dict->last; + } + else + { + dict->first = entry; + } + dict->last = entry; + } + + return entry; +} + +Inline void SetDictValue(Arena *arena, Dict *dict, u64 hash, u64 value) +{ + __prof; + DictEntry *entry = EnsureDictEntry(arena, dict, hash); + entry->value = value; +} + +//- Dict remove + +Inline void RemoveDictEntry(Dict *dict, DictEntry *entry) +{ + /* Remove from bin */ + { + DictBin *bin = &dict->bins[entry->hash % dict->bins_count]; + DictEntry *prev_in_bin = entry->prev_in_bin; + DictEntry *next_in_bin = entry->next_in_bin; + if (prev_in_bin) + { + prev_in_bin->next_in_bin = next_in_bin; + } + else + { + bin->first = next_in_bin; + } + if (next_in_bin) + { + next_in_bin->prev_in_bin = prev_in_bin; + } + else + { + bin->last = prev_in_bin; + } + } + /* Remove from list */ + { + DictEntry *prev = entry->prev; + DictEntry *next = entry->next; + if (prev) + { + prev->next = next; + } + else + { + dict->first = next; + } + if (next) + { + next->prev = prev; + } + else + { + dict->last = prev; + } + } + /* Insert into free list */ + { + entry->next = dict->first_free; + dict->first_free = entry; + } +} + +//- Dict index + +Inline DictEntry *DictEntryFromHash(Dict *dict, u64 hash) +{ + __prof; + DictEntry *result = 0; + DictBin *bin = &dict->bins[hash % dict->bins_count]; + for (DictEntry *entry = bin->first; entry; entry = entry->next_in_bin) + { + if (hash == entry->hash) + { + /* Match found */ + result = entry; + break; + } + } + return result; +} + +Inline u64 DictValueFromHash(Dict *dict, u64 hash) +{ + __prof; + DictEntry *entry = DictEntryFromHash(dict, hash); + return entry ? entry->value : 0; +} diff --git a/src/meta/win32/meta_win32.c b/src/meta/meta_base/meta_base_win32/meta_base_win32.c similarity index 50% rename from src/meta/win32/meta_win32.c rename to src/meta/meta_base/meta_base_win32/meta_base_win32.c index 9990094d..0e889fa7 100644 --- a/src/meta/win32/meta_win32.c +++ b/src/meta/meta_base/meta_base_win32/meta_base_win32.c @@ -9,7 +9,7 @@ W32_SharedState W32_shared_state = ZI; //////////////////////////////// //~ @hookdef OS startup hook -void StartupOs(void) +void StartupBase(void) { W32_SharedState *g = &W32_shared_state; g->tls_index = TlsAlloc(); @@ -17,23 +17,30 @@ void StartupOs(void) } //////////////////////////////// -//~ @hookdef Core Panic hooks +//~ @hookdef Core panic hooks /* TODO: Remove stdio & printf */ #include -void Panic(String msg) +b32 Panic(String msg) { char msg_cstr[4096]; CstrFromStringToBuff(StringFromArray(msg_cstr), msg); - ShowMessageBoxCstr("Fatal error", msg_cstr, 1); + { + u32 mb_flags = MB_SETFOREGROUND | MB_ICONERROR; + MessageBoxExA(0, msg_cstr, "Fatal error", mb_flags, 0); + } printf(msg_cstr); fflush(stdout); - ExitProcess(1); + if ((1)) /* Supress unreachable code warning */ + { + ExitProcess(1); + } + return 0; } //////////////////////////////// -//~ @hookdef Core Debugger hooks +//~ @hookdef Debugger hooks b32 IsRunningInDebugger(void) { @@ -41,28 +48,10 @@ b32 IsRunningInDebugger(void) } //////////////////////////////// -//~ @hookdef Core Thread hooks +//~ @hookdef Thread hooks i16 ThreadId(void) { W32_SharedState *g = &W32_shared_state; return (i16)(i64)TlsGetValue(g->tls_index); } - -//////////////////////////////// -//~ @hookdef OS Message box hooks - -void ShowMessageBox(String title, String msg, b32 error) -{ - char title_cstr[256]; - char msg_cstr[4096]; - CstrFromStringToBuff(StringFromArray(title_cstr), title); - CstrFromStringToBuff(StringFromArray(msg_cstr), msg); - ShowMessageBoxCstr(title_cstr, msg_cstr, error); -} - -void ShowMessageBoxCstr(char *title_cstr, char *msg_cstr, b32 error) -{ - u32 mb_flags = MB_SETFOREGROUND | (!!error * MB_ICONERROR) | (!error * MB_ICONINFORMATION); - MessageBoxExA(0, msg_cstr, title_cstr, mb_flags, 0); -} diff --git a/src/meta/win32/meta_win32.h b/src/meta/meta_base/meta_base_win32/meta_base_win32.h similarity index 62% rename from src/meta/win32/meta_win32.h rename to src/meta/meta_base/meta_base_win32/meta_base_win32.h index eb6c10d7..fb335b18 100644 --- a/src/meta/win32/meta_win32.h +++ b/src/meta/meta_base/meta_base_win32/meta_base_win32.h @@ -16,9 +16,3 @@ Struct(W32_SharedState) }; extern W32_SharedState W32_shared_state; - -//////////////////////////////// -//~ @hookdecl Message box - -void ShowMessageBox(String title, String msg, b32 error); -void ShowMessageBoxCstr(char *title_cstr, char *msg_cstr, b32 error); diff --git a/src/meta/meta_base/meta_base_win32/meta_base_win32_inc.h b/src/meta/meta_base/meta_base_win32/meta_base_win32_inc.h new file mode 100644 index 00000000..c32f4de4 --- /dev/null +++ b/src/meta/meta_base/meta_base_win32/meta_base_win32_inc.h @@ -0,0 +1,2 @@ +#include "meta_base_win32.h" +#include "meta_base_win32.c" diff --git a/src/meta/meta_core.c b/src/meta/meta_core.c deleted file mode 100644 index e69de29b..00000000 diff --git a/src/meta/meta_file/meta_file.c b/src/meta/meta_file/meta_file.c new file mode 100644 index 00000000..552110ec --- /dev/null +++ b/src/meta/meta_file/meta_file.c @@ -0,0 +1,125 @@ +//////////////////////////////// +//~ Path helpers + +String F_GetFull(Arena *arena, String path) +{ + return OS_GetFullPath(arena, path); +} + +String F_GetFileName(String path) +{ + String result = ZI; + u64 start = path.len; + for (u64 i = path.len; i-- > 0;) + { + if (path.text[i] == '\\' || path.text[i] == '/') + { + start = i + 1; + break; + } + } + if (start < path.len) + { + result.text = &path.text[start]; + result.len = path.len - start; + + } + return result; +} + +String F_GetParentDir(String path) +{ + String result = ZI; + result.text = path.text; + u64 end = path.len; + for (u64 i = path.len; i-- > 0;) + { + if (path.text[i] == '\\' || path.text[i] == '/') + { + end = i + 1; + break; + } + } + if (end < path.len) + { + result.len = end; + } + return result; +} + +String F_ExtensionFromFile(String path) +{ + String result = ZI; + u64 start = path.len; + for (u64 i = path.len; i-- > 0;) + { + if (path.text[i] == '.') + { + start = i + 1; + break; + } + } + if (start < path.len) + { + result.text = &path.text[start]; + result.len = path.len - start; + + } + return result; +} + +//////////////////////////////// +//~ File read operations + +String F_DataFromFile(Arena *arena, String path) +{ + String result = ZI; + OS_File file = OS_OpenFile(path, OS_FileFlag_Read); + result = OS_ReadEntireFile(arena, file); + OS_CloseFile(file); + return result; +} + +//////////////////////////////// +//~ File write operations + +void F_ClearWrite(String path, String data) +{ + OS_File file = OS_OpenFile(path, OS_FileFlag_Write | OS_FileFlag_Create); + OS_ClearWriteFile(file, data); + OS_CloseFile(file); +} + +//////////////////////////////// +//~ File attribute helpers + +b32 F_IsFile(String path) +{ + return OS_FileExists(path); +} + +b32 F_IsDir(String path) +{ + return OS_DirExists(path); +} + +//////////////////////////////// +//~ File iter operations + +void F_FilesFromDir(Arena *arena, StringList *list, String dir, F_IterFlag flags) +{ + TempArena scratch = BeginScratch(arena); + StringList tmp = ZI; + String dir_full_path = F_GetFull(scratch.arena, dir); + OS_DirContentsFromFullPath(scratch.arena, &tmp, dir_full_path); + for (StringListNode *n = tmp.first; n; n = n->next) + { + String file_joined_path = StringF(arena, "%F/%F", FmtString(dir), FmtString(n->s)); + PushStringToList(arena, list, file_joined_path); + if (flags & F_IterFlag_Recurse && F_IsDir(file_joined_path)) + { + F_FilesFromDir(arena, list, file_joined_path, flags); + } + } + EndScratch(scratch); +} diff --git a/src/meta/meta_file/meta_file.h b/src/meta/meta_file/meta_file.h new file mode 100644 index 00000000..d533a7ed --- /dev/null +++ b/src/meta/meta_file/meta_file.h @@ -0,0 +1,37 @@ +//////////////////////////////// +//~ File iter types + +typedef i32 F_IterFlag; enum +{ + F_IterFlag_None = 0, + F_IterFlag_Recurse = (1 << 0) +}; + +//////////////////////////////// +//~ Path helpers + +String F_GetFull(Arena *arena, String path); +String F_GetFileName(String path); +String F_GetParentDir(String path); +String F_ExtensionFromFile(String path); + +//////////////////////////////// +//~ File read operations + +String F_DataFromFile(Arena *arena, String path); + +//////////////////////////////// +//~ File write operations + +void F_ClearWrite(String path, String data); + +//////////////////////////////// +//~ File attribute helpers + +b32 F_IsFile(String path); +b32 F_IsDir(String path); + +//////////////////////////////// +//~ File iter operations + +void F_FilesFromDir(Arena *arena, StringList *list, String dir, F_IterFlag flags); diff --git a/src/meta/meta_file/meta_file_inc.h b/src/meta/meta_file/meta_file_inc.h new file mode 100644 index 00000000..a8d6ce7d --- /dev/null +++ b/src/meta/meta_file/meta_file_inc.h @@ -0,0 +1,2 @@ +#include "meta_file.h" +#include "meta_file.c" diff --git a/src/meta/meta_os.h b/src/meta/meta_os.h deleted file mode 100644 index 1b0cccb6..00000000 --- a/src/meta/meta_os.h +++ /dev/null @@ -1,4 +0,0 @@ -//////////////////////////////// -//~ @hookdeclStartup hooks - -void StartupOs(void); diff --git a/src/meta/meta_os/meta_os.h b/src/meta/meta_os/meta_os.h new file mode 100644 index 00000000..02aca063 --- /dev/null +++ b/src/meta/meta_os/meta_os.h @@ -0,0 +1,44 @@ +//////////////////////////////// +//~ File types + +typedef i32 OS_FileFlag; enum +{ + OS_FileFlag_None = 0, + OS_FileFlag_Read = (1 << 0), + OS_FileFlag_Write = (1 << 1), + OS_FileFlag_Create = (1 << 2), + OS_FileFlag_NoWait = (1 << 3) +}; + +Struct(OS_File) +{ + u64 handle; +}; + +//////////////////////////////// +//~ @hookdecl Startup hooks + +void OS_Startup(void); + +//////////////////////////////// +//~ @hookdecl File system operations + +OS_File OS_OpenFile(String path, OS_FileFlag flags); +void OS_CloseFile(OS_File file); +String OS_ReadEntireFile(Arena *arena, OS_File file); +void OS_ClearWriteFile(OS_File file, String data); +void OS_DirContentsFromFullPath(Arena *arena, StringList *list, String path); +String OS_GetFullPath(Arena *arena, String path); +b32 OS_FileOrDirExists(String path); +b32 OS_FileExists(String path); +b32 OS_DirExists(String path); + +//////////////////////////////// +//~ @hookdecl Directory helpers + +void OS_Mkdir(String path); + +//////////////////////////////// +//~ @hookdecl Shell operations + +void OS_RunCommand(String cmd); diff --git a/src/meta/meta_os/meta_os_inc.h b/src/meta/meta_os/meta_os_inc.h new file mode 100644 index 00000000..d2fbcc39 --- /dev/null +++ b/src/meta/meta_os/meta_os_inc.h @@ -0,0 +1,5 @@ +#include "meta_os.h" + +#if PlatformIsWindows +# include "meta_os_win32/meta_os_win32_inc.h" +#endif diff --git a/src/meta/meta_os/meta_os_win32/meta_os_win32.c b/src/meta/meta_os/meta_os_win32/meta_os_win32.c new file mode 100644 index 00000000..3581c937 --- /dev/null +++ b/src/meta/meta_os/meta_os_win32/meta_os_win32.c @@ -0,0 +1,163 @@ +//////////////////////////////// +//~ Windows libs + +#pragma comment(lib, "kernel32") +#pragma comment(lib, "user32") + +//////////////////////////////// +//~ @hookdef Startup hook + +void OS_Startup(void) +{ + W32_SharedState *g = &W32_shared_state; + g->tls_index = TlsAlloc(); + TlsSetValue(g->tls_index, 0); +} + +//////////////////////////////// +//~ @hookdef File system hooks + +OS_File OS_OpenFile(String path, OS_FileFlag flags) +{ + TempArena scratch = BeginScratchNoConflict(); + OS_File result = ZI; + wchar_t *path_wstr = WstrFromString(scratch.arena, path); + b32 wait_for_access = 1; + u32 share_mode = FILE_SHARE_READ; + u32 create_mode = OPEN_EXISTING; + u32 access_flags = 0; + if (flags & OS_FileFlag_Read) access_flags |= GENERIC_READ; + if (flags & OS_FileFlag_Write) access_flags |= GENERIC_WRITE; + if (flags & OS_FileFlag_Create) create_mode = OPEN_ALWAYS; + if (flags & OS_FileFlag_NoWait) wait_for_access = 0; + i32 delay_ms = 1; + HANDLE handle; + while ((handle = CreateFileW(path_wstr, access_flags, share_mode, 0, create_mode, FILE_ATTRIBUTE_NORMAL, 0)) == INVALID_HANDLE_VALUE && wait_for_access) + { + if (GetLastError() == ERROR_SHARING_VIOLATION) + { + Sleep(delay_ms); + if (delay_ms < 1024) + { + delay_ms *= 2; + } + } + else + { + break; + } + } + EndScratch(scratch); + result.handle = (u64)handle; + return result; +} + +void OS_CloseFile(OS_File file) +{ + HANDLE handle = (HANDLE)file.handle; + CloseHandle(handle); +} + +String OS_ReadEntireFile(Arena *arena, OS_File file) +{ + String result = ZI; + HANDLE handle = (HANDLE)file.handle; + u32 chunk_size = Kibi(64); + result.text = PushDry(arena, u8); + for (;;) + { + u8 *chunk = PushStructsNoZero(arena, u8, chunk_size); + u32 chunk_bytes_read = 0; + ReadFile(handle, chunk, chunk_size, &chunk_bytes_read, 0); + result.len += chunk_bytes_read; + if (chunk_bytes_read < chunk_size) + { + PopStructsNoCopy(arena, u8, chunk_size - chunk_bytes_read); + break; + } + } + return result; +} + +void OS_ClearWriteFile(OS_File file, String data) +{ + HANDLE handle = (HANDLE)file.handle; + SetFilePointer(handle, 0, 0, FILE_BEGIN); + SetEndOfFile(handle); + WriteFile(handle, data.text, data.len, 0, 0); +} + +void OS_DirContentsFromFullPath(Arena *arena, StringList *list, String path) +{ + TempArena scratch = BeginScratch(arena); + WIN32_FIND_DATAW find_data = ZI; + String filter = StringF(scratch.arena, "%F\\*", FmtString(path)); + wchar_t *filter_wstr = WstrFromString(scratch.arena, filter); + HANDLE find_handle = FindFirstFileExW(filter_wstr, FindExInfoStandard, &find_data, FindExSearchNameMatch, 0, FIND_FIRST_EX_CASE_SENSITIVE | FIND_FIRST_EX_LARGE_FETCH); + b32 found = find_handle && find_handle != INVALID_HANDLE_VALUE; + while (found) { + String file_name = StringFromWstrNoLimit(arena, find_data.cFileName); + if (!EqString(file_name, Lit(".")) && !EqString(file_name, Lit(".."))) { + PushStringToList(arena, list, file_name); + } + found = FindNextFileW(find_handle, &find_data); + } + EndScratch(scratch); +} + +String OS_GetFullPath(Arena *arena, String path) +{ + TempArena scratch = BeginScratch(arena); + wchar_t *rel_path_wstr = WstrFromString(scratch.arena, path); + wchar_t buff[4096]; + wchar_t *full_path_wstr = _wfullpath(buff, rel_path_wstr, countof(buff)); + String res = StringFromWstrNoLimit(arena, full_path_wstr); + EndScratch(scratch); + return res; +} + +//////////////////////////////// +//~ @hookdef Directory helper hooks + +void OS_Mkdir(String path) +{ + TempArena scratch = BeginScratchNoConflict(); + wchar_t *path_wstr = WstrFromString(scratch.arena, path); + CreateDirectoryW(path_wstr, 0); + EndScratch(scratch); +} + +b32 OS_FileOrDirExists(String path) +{ + TempArena scratch = BeginScratchNoConflict(); + wchar_t *path_wstr = WstrFromString(scratch.arena, path); + DWORD attributes = GetFileAttributesW(path_wstr); + EndScratch(scratch); + return attributes != INVALID_FILE_ATTRIBUTES; +} + +b32 OS_FileExists(String path) +{ + TempArena scratch = BeginScratchNoConflict(); + wchar_t *path_wstr = WstrFromString(scratch.arena, path); + DWORD attributes = GetFileAttributesW(path_wstr); + EndScratch(scratch); + return attributes != INVALID_FILE_ATTRIBUTES && !(attributes & FILE_ATTRIBUTE_DIRECTORY); +} + +b32 OS_DirExists(String path) +{ + TempArena scratch = BeginScratchNoConflict(); + wchar_t *path_wstr = WstrFromString(scratch.arena, path); + DWORD attributes = GetFileAttributesW(path_wstr); + EndScratch(scratch); + return attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY); +} + + +//////////////////////////////// +//~ @hookdef Shell hooks + +void OS_RunCommand(String cmd) +{ +} diff --git a/src/meta/meta_os/meta_os_win32/meta_os_win32.h b/src/meta/meta_os/meta_os_win32/meta_os_win32.h new file mode 100644 index 00000000..10c83495 --- /dev/null +++ b/src/meta/meta_os/meta_os_win32/meta_os_win32.h @@ -0,0 +1 @@ +#include /* _wfullpath */ diff --git a/src/meta/meta_os/meta_os_win32/meta_os_win32_inc.h b/src/meta/meta_os/meta_os_win32/meta_os_win32_inc.h new file mode 100644 index 00000000..f3a80068 --- /dev/null +++ b/src/meta/meta_os/meta_os_win32/meta_os_win32_inc.h @@ -0,0 +1,2 @@ +#include "meta_os_win32.h" +#include "meta_os_win32.c" diff --git a/src/mixer/mixer.lay b/src/mixer/mixer.lay index de5affbe..a0a65899 100644 --- a/src/mixer/mixer.lay +++ b/src/mixer/mixer.lay @@ -1,18 +1,15 @@ @Layer mixer -//////////////////////////////// -//~ Dependencies - +//- Dependencies @Dep base @Dep platform @Dep sound -//////////////////////////////// -//~ Api +//- Api +@IncludeC mixer_core.h -@ApiC mixer_core +//- Impl +@IncludeC mixer_core.c -//////////////////////////////// -//~ Init - -@Init MIX_StartupCore +//- Startup +@Startup MIX_StartupCore diff --git a/src/mp3/mp3.lay b/src/mp3/mp3.lay index 89408bec..f99e45ad 100644 --- a/src/mp3/mp3.lay +++ b/src/mp3/mp3.lay @@ -1,14 +1,10 @@ @Layer mp3 -//////////////////////////////// -//~ Dependencies - +//- Dependencies @Dep base -//////////////////////////////// -//~ Api +//- Api +@IncludeC mp3_core.h -@ApiC mp3_core - -//- Mmf -@ApiCWindows mp3_mmf +//- Mmf impl +@DefaultWindowsImpl mp3_mmf diff --git a/src/net/net.lay b/src/net/net.lay index 2122d6ae..c9201e7b 100644 --- a/src/net/net.lay +++ b/src/net/net.lay @@ -1,13 +1,12 @@ @Layer net -//////////////////////////////// -//~ Dependencies - +//- Dependencies @Dep base @Dep platform @Dep bitbuff -//////////////////////////////// -//~ Api +//- Api +@IncludeC net_core.h -@ApiC net_core +//- Impl +@IncludeC net_core.c diff --git a/src/platform/platform.lay b/src/platform/platform.lay index d95e1c4e..ec4550de 100644 --- a/src/platform/platform.lay +++ b/src/platform/platform.lay @@ -1,21 +1,18 @@ @Layer platform -//////////////////////////////// -//~ Dependencies - +//- Dependencies @Dep base -//////////////////////////////// -//~ Api +//- Api +@IncludeC platform_core.h +@IncludeC platform_log.h -@ApiC platform_core -@ApiC platform_log +//- Impl +@IncludeC platform_log.c -//- Win32 -@ApiCWindows platform_win32 +//- Win32 impl +@DefaultWindowsImpl platform_win32 -//////////////////////////////// -//~ Init - -@Init P_StartupCore -@Init P_StartupLog +//- Startup +@Startup P_StartupCore +@Startup P_StartupLog diff --git a/src/playback/playback.lay b/src/playback/playback.lay index e363dace..cc6270c3 100644 --- a/src/playback/playback.lay +++ b/src/playback/playback.lay @@ -1,21 +1,18 @@ @Layer playback -//////////////////////////////// -//~ Dependencies - +//- Dependencies @Dep base @Dep platform @Dep mixer -//////////////////////////////// -//~ Api +//- Api +@IncludeC playback_core.h -@ApiC playback_core +//- Impl +@IncludeC playback_core.c -//- Wasapi -@ApiCWindows wasapi/playback_wasapi +//- Wasapi impl +@DefaultWindowsImpl playback_wasapi -//////////////////////////////// -//~ Init - -@Init PB_StartupCore +//- Startup +@Startup PB_StartupCore diff --git a/src/pp/pp.lay b/src/pp/pp.lay index 8336464d..e2f5beb4 100644 --- a/src/pp/pp.lay +++ b/src/pp/pp.lay @@ -1,8 +1,7 @@ @Layer pp -//////////////////////////////// -//~ Dependencies +//- Dependencies @Dep base @Dep gpu @Dep sprite @@ -14,19 +13,36 @@ @Dep bitbuff @Dep rendertest -//////////////////////////////// -//~ Api +//- Api +@IncludeC pp_sim.h +@IncludeC pp_phys.h +@IncludeC pp_space.h +@IncludeC pp_ent.h +@IncludeC pp_step.h +@IncludeC pp_draw.h +@IncludeC pp_core.h +@IncludeGpu pp_draw.h -@ApiC pp_sim -@ApiC pp_phys -@ApiC pp_space -@ApiC pp_ent -@ApiC pp_step -@ApiC pp_draw -@ApiC pp_core +//- Impl +@IncludeC pp_sim.c +@IncludeC pp_phys.c +@IncludeC pp_space.c +@IncludeC pp_ent.c +@IncludeC pp_step.c +@IncludeC pp_core.c +@IncludeGpu pp_draw.gpu -//////////////////////////////// -//~ Init +//- Shaders +@ShaderVS MaterialVS +@ShaderPS MaterialPS +@ShaderCS FloodCS +@ShaderVS UiBlitVS +@ShaderPS UiBlitPS +@ShaderVS UiRectVS +@ShaderPS UiRectPS +@ShaderVS UiShapeVS +@ShaderPS UiShapePS -@Init StartupSim -@Init StartupUser +//- Startup +@Startup StartupSim +@Startup StartupUser diff --git a/src/rendertest/rendertest.lay b/src/rendertest/rendertest.lay index 7e0ce1a3..ec01a912 100644 --- a/src/rendertest/rendertest.lay +++ b/src/rendertest/rendertest.lay @@ -1,20 +1,17 @@ @Layer rendertest -//////////////////////////////// -//~ Dependencies - +//- Dependencies @Dep base @Dep gpu @Dep sprite @Dep font @Dep collider -//////////////////////////////// -//~ Api +//- Api +@IncludeC rendertest_core.h -@ApiC rendertest_core +//- Impl +@IncludeC rendertest_core.c -//////////////////////////////// -//~ Init - -@Init RT_StartupCore +//- Startup +@Startup RT_StartupCore diff --git a/src/resource/resource.lay b/src/resource/resource.lay index bea551ba..07c87be6 100644 --- a/src/resource/resource.lay +++ b/src/resource/resource.lay @@ -1,19 +1,16 @@ @Layer resource -//////////////////////////////// -//~ Dependencies - +//- Dependencies @Dep base @Dep platform @Dep tar @Dep inc -//////////////////////////////// -//~ Api +//- Api +@IncludeC resource_core.h -@ApiC resource_core +//- Impl +@IncludeC resource_core.c -//////////////////////////////// -//~ Init - -@Init RES_StartupCore +//- Startup +@Startup RES_StartupCore diff --git a/src/settings/settings.lay b/src/settings/settings.lay index 8e77fbad..3c08eb73 100644 --- a/src/settings/settings.lay +++ b/src/settings/settings.lay @@ -1,13 +1,12 @@ @Layer settings -//////////////////////////////// -//~ Dependencies - +//- Dependencies @Dep base @Dep platform @Dep json -//////////////////////////////// -//~ Api +//- Api +@IncludeC settings_core.h -@ApiC settings_core +//- Impl +@IncludeC settings_core.c diff --git a/src/sound/sound.lay b/src/sound/sound.lay index 2b639c18..e033b537 100644 --- a/src/sound/sound.lay +++ b/src/sound/sound.lay @@ -1,15 +1,14 @@ @Layer sound -//////////////////////////////// -//~ Dependencies - +//- Dependencies @Dep base @Dep platform @Dep mp3 @Dep resource @Dep asset_cache -//////////////////////////////// -//~ Api +//- Api +@IncludeC sound_core.h -@ApiC sound_core +//- Impl +@IncludeC sound_core.c diff --git a/src/sprite/sprite.lay b/src/sprite/sprite.lay index aa08c005..517d4907 100644 --- a/src/sprite/sprite.lay +++ b/src/sprite/sprite.lay @@ -1,8 +1,6 @@ @Layer sprite -//////////////////////////////// -//~ Dependencies - +//- Dependencies @Dep base @Dep platform @Dep gpu @@ -10,12 +8,11 @@ @Dep resource @Dep watch -//////////////////////////////// -//~ Api +//- Api +@IncludeC sprite_core.h -@ApiC sprite_core +//- Impl +@IncludeC sprite_core.c -//////////////////////////////// -//~ Init - -@Init S_StartupCore +//- Startup +@Startup S_StartupCore diff --git a/src/tar/tar.lay b/src/tar/tar.lay index 5870fc57..977832f3 100644 --- a/src/tar/tar.lay +++ b/src/tar/tar.lay @@ -1,13 +1,12 @@ @Layer tar -//////////////////////////////// -//~ Dependencies - +//- Dependencies @Dep base @Dep platform @Dep bitbuff -//////////////////////////////// -//~ Api +//- Api +@IncludeC tar_core.h -@ApiC tar_core +//- Impl +@IncludeC tar_core.c diff --git a/src/ttf/ttf.lay b/src/ttf/ttf.lay index d79d49dd..a633e130 100644 --- a/src/ttf/ttf.lay +++ b/src/ttf/ttf.lay @@ -1,41 +1,10 @@ -//////////////////////////////// -//~ Dependencies +@Layer ttf -AddDep("../base/base.h"); -AddDep("../gpu/gpu.h"); -AddDep("../sprite/sprite.h"); -AddDep("../font/font.h"); -AddDep("../collider/collider.h"); -AddDep("../draw/draw.h"); -AddDep("../net/net.h"); -AddDep("../mixer/mixer.h"); -AddDep("../bitbuff/bitbuff.h"); -AddDep("../rendertest/rendertest.h"); +//- Dependencies +@Dep base -//////////////////////////////// -//~ Headers +//- Api +@IncludeC ttf_core.h -AddHeader("pp_sim.h"); -AddHeader("pp_phys.h"); -AddHeader("pp_space.h"); -AddHeader("pp_ent.h"); -AddHeader("pp_step.h"); -AddHeader("pp_draw.h"); -AddHeader("pp_core.h"); - -//////////////////////////////// -//~ Sources - -AddCSource("pp_ent.c"); -AddCSource("pp_phys.c"); -AddCSource("pp_step.c"); -AddCSource("pp_space.c"); -AddCSource("pp_sim.c"); -AddCSource("pp_core.c"); - -//////////////////////////////// -//~ Init - -AddInit(StartupPpDeps); -AddInit(StartupSim); -AddInit(StartupUser); +//- DirectWrite impl +@DefaultWindowsImpl ttf_dwrite diff --git a/src/watch/watch.lay b/src/watch/watch.lay index b3ca3626..bcad839a 100644 --- a/src/watch/watch.lay +++ b/src/watch/watch.lay @@ -1,17 +1,14 @@ @Layer watch -//////////////////////////////// -//~ Dependencies - +//- Dependencies @Dep base @Dep platform -//////////////////////////////// -//~ Api +//- Api +@IncludeC watch_core.h -@ApiC watch_core +//- Impl +@IncludeC watch_core.c -//////////////////////////////// -//~ Init - -@Init W_StartupCore +//- Startup +@Startup W_StartupCore