allow metaprogram to depend on base layer
This commit is contained in:
parent
cc0896cd93
commit
617df23dfc
@ -1,7 +1,6 @@
|
||||
@Layer ase
|
||||
|
||||
//- Dependencies
|
||||
@Dep base
|
||||
@Dep bitbuff
|
||||
|
||||
//- Api
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
@Layer asset_cache
|
||||
|
||||
//- Dependencies
|
||||
@Dep base
|
||||
@Dep platform
|
||||
|
||||
//- Api
|
||||
|
||||
@ -1,6 +1,10 @@
|
||||
////////////////////////////////
|
||||
//~ Compiler flag checks
|
||||
|
||||
#ifndef IsConsoleApp
|
||||
# error Missing compile time definition for 'IsConsoleApp'
|
||||
#endif
|
||||
|
||||
#ifndef RtcIsEnabled
|
||||
# error Missing compile time definition for 'RtcIsEnabled'
|
||||
#endif
|
||||
@ -573,7 +577,7 @@ ForceInline void UnlockTicketMutex(TicketMutex *tm)
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ String utils
|
||||
//~ String types
|
||||
|
||||
#define STRING(size, data) ((String) { (size), (data) })
|
||||
#define Lit(cstr_lit) (String) { (sizeof((cstr_lit)) - 1), (u8 *)(cstr_lit) }
|
||||
@ -607,38 +611,44 @@ Struct(String32)
|
||||
u32 *text;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ Fibers
|
||||
|
||||
#define MaxFibers 1024
|
||||
|
||||
#if LanguageIsC
|
||||
# if PlatformIsWindows
|
||||
ForceInline i16 FiberId(void)
|
||||
Struct(StringArray)
|
||||
{
|
||||
i16 *v = (void *)(u64)__readgsqword(32);
|
||||
return *v;
|
||||
}
|
||||
# else
|
||||
# error FiberId not implemented
|
||||
# endif
|
||||
StaticAssert(MaxFibers < I16Max); /* Fiber id type should fit max fibers */
|
||||
#endif
|
||||
u64 count;
|
||||
String *strings;
|
||||
};
|
||||
|
||||
Struct(StringListNode)
|
||||
{
|
||||
String s;
|
||||
StringListNode *next;
|
||||
StringListNode *prev;
|
||||
};
|
||||
|
||||
Struct(StringList)
|
||||
{
|
||||
StringListNode *first;
|
||||
StringListNode *last;
|
||||
u64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ @hookdecl Core hooks
|
||||
|
||||
void StartupBase(void);
|
||||
StringList GetCommandLineArgs(void);
|
||||
b32 Panic(String msg);
|
||||
b32 IsRunningInDebugger(void);
|
||||
i16 ThreadId(void);
|
||||
void TrueRand(String buffer);
|
||||
i16 FiberId(void);
|
||||
i16 ThreadId(void);
|
||||
|
||||
#define MaxThreads 1024
|
||||
#define MaxFibers 1024
|
||||
StaticAssert(MaxThreads < I16Max); /* Thread id type should fit max threads */
|
||||
StaticAssert(MaxFibers < I16Max); /* Fiber id type should fit max threads */
|
||||
|
||||
////////////////////////////////
|
||||
//~ @hookdecl Layer startup hook (defined by meta program)
|
||||
//~ @hookdecl Layer startup hook (defined by metaprogram)
|
||||
|
||||
void StartupLayers(void);
|
||||
|
||||
@ -1,37 +0,0 @@
|
||||
@Layer base
|
||||
|
||||
//- 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
|
||||
|
||||
//- 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 impl
|
||||
@DefaultWindowsImpl base_win32
|
||||
@ -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);
|
||||
|
||||
@ -8,7 +8,8 @@ typedef ExitFuncDef(ExitFunc);
|
||||
//~ @hookdecl Exit operations
|
||||
|
||||
void OnExit(ExitFunc *func);
|
||||
void Exit(void);
|
||||
void SignalExit(i32 code);
|
||||
void ExitNow(i32 code);
|
||||
|
||||
////////////////////////////////
|
||||
//~ @hookdecl Application defined hooks
|
||||
|
||||
45
src/base/base_inc.h
Normal file
45
src/base/base_inc.h
Normal file
@ -0,0 +1,45 @@
|
||||
// This is the includable header version of the base layer manifest.
|
||||
// The base layer uses an includable header file rather than a '.lay' file so
|
||||
// that it may be depended on by the metaprogram.
|
||||
|
||||
//- Api
|
||||
#include "base.h"
|
||||
#if LanguageIsC
|
||||
# include "base_intrinsics.h"
|
||||
# include "base_memory.h"
|
||||
# include "base_arena.h"
|
||||
# include "base_snc.h"
|
||||
# include "base_job.h"
|
||||
# include "base_uid.h"
|
||||
# include "base_string.h"
|
||||
# include "base_uni.h"
|
||||
# include "base_gstat.h"
|
||||
# include "base_buddy.h"
|
||||
# include "base_math.h"
|
||||
# include "base_rand.h"
|
||||
# include "base_util.h"
|
||||
# include "base_incbin.h"
|
||||
# include "base_entry.h"
|
||||
#elif LanguageIsGpu
|
||||
# include "base_math_gpu.h"
|
||||
#endif
|
||||
|
||||
//- Impl
|
||||
#if LanguageIsC
|
||||
# include "base_memory.c"
|
||||
# include "base_arena.c"
|
||||
# include "base_snc.c"
|
||||
# include "base_uid.c"
|
||||
# include "base_string.c"
|
||||
# include "base_uni.c"
|
||||
# include "base_gstat.c"
|
||||
# include "base_buddy.c"
|
||||
# include "base_math.c"
|
||||
# include "base_rand.c"
|
||||
# include "base_incbin.c"
|
||||
#endif
|
||||
|
||||
//- Win32 impl
|
||||
#if LanguageIsC && PlatformIsWindows
|
||||
# include "base_win32/base_win32_inc.h"
|
||||
#endif
|
||||
@ -1,26 +1,3 @@
|
||||
////////////////////////////////
|
||||
//~ String types
|
||||
|
||||
Struct(StringArray)
|
||||
{
|
||||
u64 count;
|
||||
String *strings;
|
||||
};
|
||||
|
||||
Struct(StringListNode)
|
||||
{
|
||||
String s;
|
||||
StringListNode *next;
|
||||
StringListNode *prev;
|
||||
};
|
||||
|
||||
Struct(StringList)
|
||||
{
|
||||
StringListNode *first;
|
||||
StringListNode *last;
|
||||
u64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ Formatting types
|
||||
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
W32_SharedState W32_shared_state = ZI;
|
||||
|
||||
////////////////////////////////
|
||||
//~ @hookdef OS startup hook
|
||||
//~ @hookdef Core hooks
|
||||
|
||||
//- Startup
|
||||
void StartupBase(void)
|
||||
{
|
||||
W32_SharedState *g = &W32_shared_state;
|
||||
@ -10,12 +11,14 @@ void StartupBase(void)
|
||||
TlsSetValue(g->tls_index, 0);
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ @hookdef Panic hooks
|
||||
|
||||
/* TODO: Remove stdio & printf */
|
||||
#include <stdio.h>
|
||||
//- Command line args
|
||||
StringList GetCommandLineArgs(void)
|
||||
{
|
||||
StringList result = ZI;
|
||||
return result;
|
||||
}
|
||||
|
||||
//- Panic
|
||||
b32 Panic(String msg)
|
||||
{
|
||||
char msg_cstr[4096];
|
||||
@ -26,33 +29,38 @@ b32 Panic(String msg)
|
||||
}
|
||||
HANDLE console_handle = GetStdHandle(STD_ERROR_HANDLE);
|
||||
WriteConsoleA(console_handle, msg.text, msg.len, 0, 0);
|
||||
if ((1)) /* Supress unreachable code warning */
|
||||
if (IsRunningInDebugger())
|
||||
{
|
||||
Assert(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
ExitProcess(1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ @hookdef Debugger hooks
|
||||
|
||||
//- Debugger check
|
||||
b32 IsRunningInDebugger(void)
|
||||
{
|
||||
return IsDebuggerPresent();
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ @hookdef Thread hooks
|
||||
//- Fiber id
|
||||
ForceInline i16 FiberId(void)
|
||||
{
|
||||
i16 *v = (void *)(u64)__readgsqword(32);
|
||||
return *v;
|
||||
}
|
||||
|
||||
//- Thread id
|
||||
i16 ThreadId(void)
|
||||
{
|
||||
W32_SharedState *g = &W32_shared_state;
|
||||
return (i16)(i64)TlsGetValue(g->tls_index);
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ @hookdef Randomness hooks
|
||||
|
||||
//- True randomness
|
||||
void TrueRand(String buffer)
|
||||
{
|
||||
BCryptGenRandom(BCRYPT_RNG_ALG_HANDLE, (u8 *)buffer.text, buffer.len, 0);
|
||||
|
||||
@ -16,6 +16,7 @@ u32 BCryptGenRandom(void *algorithm, u8 *buffer, u32 buffer_size, u32 flags);
|
||||
Struct(W32_SharedState)
|
||||
{
|
||||
DWORD tls_index;
|
||||
Atomic32 exit_code;
|
||||
};
|
||||
|
||||
extern W32_SharedState W32_shared_state;
|
||||
|
||||
@ -1,11 +0,0 @@
|
||||
@Layer base_win32
|
||||
|
||||
//- Api
|
||||
@IncludeC base_win32.h
|
||||
@IncludeC base_win32_entry.h
|
||||
@IncludeC base_win32_job.h
|
||||
|
||||
//- Impl
|
||||
@IncludeC base_win32.c
|
||||
@IncludeC base_win32_entry.c
|
||||
@IncludeC base_win32_job.c
|
||||
@ -42,22 +42,23 @@ void OnExit(ExitFunc *func)
|
||||
g->exit_funcs[index] = func;
|
||||
}
|
||||
|
||||
void Exit(void)
|
||||
void SignalExit(i32 code)
|
||||
{
|
||||
W32_SharedEntryCtx *g = &W32_shared_entry_ctx;
|
||||
Atomic32FetchSet(&g->exit_code, code);
|
||||
SetEvent(g->exit_begin_event);
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ Winmain
|
||||
|
||||
int CALLBACK wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance, _In_ LPWSTR cmdline_wstr, _In_ int show_code)
|
||||
void ExitNow(i32 code)
|
||||
{
|
||||
LAX instance;
|
||||
LAX prev_instance;
|
||||
LAX cmdline_wstr;
|
||||
LAX show_code;
|
||||
ExitProcess(code);
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ Main
|
||||
|
||||
i32 W32_Main(void)
|
||||
{
|
||||
__profthread("Main thread", PROF_THREAD_GROUP_MAIN);
|
||||
W32_SharedEntryCtx *g = &W32_shared_entry_ctx;
|
||||
|
||||
@ -141,10 +142,6 @@ int CALLBACK wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance,
|
||||
g->exit_begin_event = CreateEventW(0, 1, 0, 0);
|
||||
g->exit_end_event = CreateEventW(0, 1, 0, 0);
|
||||
|
||||
u64 cmdline_len = WstrLen(cmdline_wstr, countof(g->cmdline_args_wstr) - 1);
|
||||
CopyBytes(g->cmdline_args_wstr, cmdline_wstr, cmdline_len * sizeof(*cmdline_wstr));
|
||||
g->cmdline_args_wstr[cmdline_len] = 0;
|
||||
|
||||
g->main_thread_id = GetCurrentThreadId();
|
||||
SetThreadDescription(GetCurrentThread(), L"Main thread");
|
||||
|
||||
@ -199,16 +196,38 @@ int CALLBACK wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance,
|
||||
}
|
||||
|
||||
/* Exit */
|
||||
i32 exit_code = 0;
|
||||
if (Atomic32Fetch(&g->panicking))
|
||||
{
|
||||
WaitForSingleObject(g->panic_event, INFINITE);
|
||||
MessageBoxExW(0, g->panic_wstr, L"Fatal error", MB_ICONSTOP | MB_SETFOREGROUND | MB_TOPMOST, 0);
|
||||
exit_code = 1;
|
||||
Atomic32FetchTestSet(&g->exit_code, 0, 1);
|
||||
}
|
||||
return exit_code;
|
||||
return Atomic32Fetch(&g->exit_code);
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ Crt main
|
||||
|
||||
#if CrtlibIsEnabled
|
||||
# if IsConsoleApp
|
||||
int main(char **argc, int argv)
|
||||
{
|
||||
LAX argc;
|
||||
LAX argv;
|
||||
return W32_Main();
|
||||
}
|
||||
# else
|
||||
int CALLBACK wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance, _In_ LPWSTR cmdline_wstr, _In_ int show_code)
|
||||
{
|
||||
LAX instance;
|
||||
LAX prev_instance;
|
||||
LAX cmdline_wstr;
|
||||
LAX show_code;
|
||||
return W32_Main();
|
||||
}
|
||||
# endif /* IsConsoleApp */
|
||||
#endif /* CrtlibIsEnabled */
|
||||
|
||||
////////////////////////////////
|
||||
//~ Crt stub
|
||||
|
||||
@ -225,7 +244,7 @@ int _fltused;
|
||||
__attribute((used))
|
||||
void __stdcall wWinMainCRTStartup(void)
|
||||
{
|
||||
int result = wWinMain(GetModuleHandle(0), 0, GetCommandLineW(), 0);
|
||||
i32 result = W32_Main();
|
||||
ExitProcess(result);
|
||||
}
|
||||
|
||||
|
||||
@ -8,8 +8,7 @@ Struct(W32_SharedEntryCtx)
|
||||
SYSTEM_INFO info;
|
||||
u32 main_thread_id;
|
||||
Atomic32 shutdown;
|
||||
|
||||
wchar_t cmdline_args_wstr[8192];
|
||||
Atomic32 exit_code;
|
||||
|
||||
//- Application control flow
|
||||
Atomic32 panicking;
|
||||
@ -31,3 +30,8 @@ extern W32_SharedEntryCtx W32_shared_entry_ctx;
|
||||
|
||||
JobDecl(W32_StartupLayersJob, EmptySig);
|
||||
JobDecl(W32_ShutdownLayersJob, EmptySig);
|
||||
|
||||
////////////////////////////////
|
||||
//~ Main
|
||||
|
||||
i32 W32_Main(void);
|
||||
|
||||
9
src/base/base_win32/base_win32_inc.h
Normal file
9
src/base/base_win32/base_win32_inc.h
Normal file
@ -0,0 +1,9 @@
|
||||
//- Api
|
||||
#include "base_win32.h"
|
||||
#include "base_win32_entry.h"
|
||||
#include "base_win32_job.h"
|
||||
|
||||
//- Impl
|
||||
#include "base_win32.c"
|
||||
#include "base_win32_entry.c"
|
||||
#include "base_win32_job.c"
|
||||
@ -1,8 +1,5 @@
|
||||
@Layer bitbuff
|
||||
|
||||
//- Dependencies
|
||||
@Dep base
|
||||
|
||||
//- Api
|
||||
@IncludeC bitbuff_core.h
|
||||
|
||||
|
||||
@ -1,8 +1,5 @@
|
||||
@Layer collider
|
||||
|
||||
//- Dependencies
|
||||
@Dep base
|
||||
|
||||
//- Api
|
||||
@IncludeC collider_core.h
|
||||
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
@Layer font
|
||||
|
||||
//- Dependencies
|
||||
@Dep base
|
||||
@Dep ttf
|
||||
@Dep gpu
|
||||
@Dep resource
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
@Layer gpu
|
||||
|
||||
//- Dependencies
|
||||
@Dep base
|
||||
@Dep platform
|
||||
|
||||
//- Api
|
||||
|
||||
@ -1,8 +1,5 @@
|
||||
@Layer inc
|
||||
|
||||
//- Dependencies
|
||||
@Dep base
|
||||
|
||||
//- Api
|
||||
@IncludeC inc_core.h
|
||||
|
||||
|
||||
@ -5,6 +5,10 @@
|
||||
////////////////////////////////
|
||||
//~ Metaprogram default compiler definitions
|
||||
|
||||
#ifndef IsConsoleApp
|
||||
# define IsConsoleApp 1
|
||||
#endif
|
||||
|
||||
#ifndef RtcIsEnabled
|
||||
# define RtcIsEnabled 1
|
||||
#endif
|
||||
@ -48,7 +52,7 @@
|
||||
////////////////////////////////
|
||||
//~ Includes
|
||||
|
||||
#include "meta_base/meta_base_inc.h"
|
||||
#include "../base/base_inc.h"
|
||||
#include "meta_os/meta_os_inc.h"
|
||||
#include "meta_file/meta_file_inc.h"
|
||||
#include "meta.h"
|
||||
@ -737,20 +741,18 @@ Error *PushError(Arena *arena, ErrorList *list, String file, i64 pos, String s)
|
||||
////////////////////////////////
|
||||
//~ Entry point
|
||||
|
||||
i32 main(i32 argc, u8 **argv)
|
||||
void StartupMeta(void)
|
||||
{
|
||||
//- Startup
|
||||
StartupBase();
|
||||
OS_Startup();
|
||||
Arena *arena = AcquireArena(Gibi(64));
|
||||
|
||||
i32 ret = 0;
|
||||
ErrorList errors = ZI;
|
||||
|
||||
//- Unpack args
|
||||
for (i32 i = 1; i < argc; ++i)
|
||||
StringList args = GetCommandLineArgs();
|
||||
for (StringListNode *n = args.first; n; n = n->next)
|
||||
{
|
||||
String arg = StringFromCstrNoLimit(argv[i]);
|
||||
String arg = n->s;
|
||||
}
|
||||
|
||||
//- Return if metaprogram is dirty
|
||||
@ -771,8 +773,9 @@ i32 main(i32 argc, u8 **argv)
|
||||
u64 new_metahash = 0;
|
||||
{
|
||||
StringList check_files = ZI;
|
||||
F_FilesFromDir(arena, &check_files, Lit("../src/meta"), F_IterFlag_Recurse);
|
||||
F_FilesFromDir(arena, &check_files, Lit("../src/prof"), F_IterFlag_Recurse);
|
||||
F_FilesFromDir(arena, &check_files, Lit("../src/base"), F_IterFlag_Recurse);
|
||||
F_FilesFromDir(arena, &check_files, Lit("../src/meta"), F_IterFlag_Recurse);
|
||||
PushStringToList(arena, &check_files, Lit("../src/config.h"));
|
||||
for (StringListNode *n = check_files.first; n; n = n->next)
|
||||
{
|
||||
@ -789,7 +792,7 @@ i32 main(i32 argc, u8 **argv)
|
||||
else
|
||||
{
|
||||
Echo(Lit("Metaprogram is dirty"));
|
||||
return MetaRebuildCode;
|
||||
ExitNow(MetaRebuildCode);
|
||||
}
|
||||
}
|
||||
|
||||
@ -815,11 +818,19 @@ i32 main(i32 argc, u8 **argv)
|
||||
if (errors.count <= 0)
|
||||
{
|
||||
StringList c_out_lines = ZI;
|
||||
/* Includes */
|
||||
{
|
||||
PushStringToList(arena, &c_out_lines, Lit("// Auto generated file"));
|
||||
/* Include base layer */
|
||||
{
|
||||
String base_inc_path = F_GetFull(arena, Lit("../src/base/base_inc.h"));
|
||||
PushStringToList(arena, &c_out_lines, Lit(""));
|
||||
PushStringToList(arena, &c_out_lines, Lit("//- Includes"));
|
||||
PushStringToList(arena, &c_out_lines, Lit("//- Include base layer"));
|
||||
String line = StringF(arena, "#include \"%F\"", FmtString(base_inc_path));
|
||||
PushStringToList(arena, &c_out_lines, line);
|
||||
}
|
||||
/* Include dependency layers */
|
||||
{
|
||||
PushStringToList(arena, &c_out_lines, Lit(""));
|
||||
PushStringToList(arena, &c_out_lines, Lit("//- Include dependencies"));
|
||||
for (L_TopoItem *item = topo.c_includes.first; item; item = item->next)
|
||||
{
|
||||
String parent = F_GetParentDir(item->token_file);
|
||||
@ -837,7 +848,7 @@ i32 main(i32 argc, u8 **argv)
|
||||
}
|
||||
}
|
||||
}
|
||||
/* StartupLayers definition */
|
||||
/* Define StartupLayers */
|
||||
{
|
||||
PushStringToList(arena, &c_out_lines, Lit(""));
|
||||
PushStringToList(arena, &c_out_lines, Lit("//- Startup"));
|
||||
@ -886,6 +897,7 @@ i32 main(i32 argc, u8 **argv)
|
||||
StringList clang_compiler_flags = ZI;
|
||||
{
|
||||
//- Shared
|
||||
PushStringToList(arena, &shared_compiler_flags, Lit("-DIsConsoleApp=0"));
|
||||
PushStringToList(arena, &shared_compiler_flags, Lit("-DRtcIsEnabled=1"));
|
||||
PushStringToList(arena, &shared_compiler_flags, Lit("-DAsanIsEnabled=0"));
|
||||
PushStringToList(arena, &shared_compiler_flags, Lit("-DCrtlibIsEnabled=1"));
|
||||
@ -963,5 +975,15 @@ i32 main(i32 argc, u8 **argv)
|
||||
}
|
||||
}
|
||||
|
||||
return ret != 0 ? ret : errors.count > 0;
|
||||
ExitNow(ret != 0 ? ret : errors.count > 0);
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ @hookdef Startup
|
||||
|
||||
void StartupLayers(void)
|
||||
{
|
||||
StartupBase();
|
||||
OS_Startup();
|
||||
StartupMeta();
|
||||
}
|
||||
|
||||
@ -1 +0,0 @@
|
||||
i32 main(i32 argc, u8 **argv);
|
||||
@ -1,653 +0,0 @@
|
||||
////////////////////////////////
|
||||
//~ Compiler flag checks
|
||||
|
||||
#ifndef RtcIsEnabled
|
||||
# error Missing compile time definition for 'RtcIsEnabled'
|
||||
#endif
|
||||
|
||||
#ifndef AsanIsEnabled
|
||||
# error Missing compile time definition for 'AsanIsEnabled'
|
||||
#endif
|
||||
|
||||
#ifndef CrtlibIsEnabled
|
||||
# error Missing compile time definition for 'CrtlibIsEnabled'
|
||||
#endif
|
||||
|
||||
#ifndef DebinfoEnabled
|
||||
# error Missing compile time definition for 'DebinfoEnabled'
|
||||
#endif
|
||||
|
||||
#ifndef DeveloperIsEnabled
|
||||
# error Missing compile time definition for 'DeveloperIsEnabled'
|
||||
#endif
|
||||
|
||||
#ifndef ProfilingIsEnabled
|
||||
# error Missing compile time definition for 'ProfilingIsEnabled'
|
||||
#endif
|
||||
|
||||
#ifndef UnoptimizedIsEnabled
|
||||
# error Missing compile time definition for 'UnoptimizedIsEnabled'
|
||||
#endif
|
||||
|
||||
#ifndef TestsAreEnabled
|
||||
# error Missing compile time definition for 'TestsAreEnabled'
|
||||
#endif
|
||||
|
||||
#ifndef IncbinRawDir
|
||||
# error Missing compile time definition for 'IncbinRawDir'
|
||||
#else
|
||||
# define IncbinDir Stringize(IncbinRawDir)
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ Machine context
|
||||
|
||||
//- Compiler
|
||||
#if defined(__clang__)
|
||||
# define CompilerIsClang 1
|
||||
# define CompilerIsMsvc 0
|
||||
#elif defined(_MSC_VER)
|
||||
# define CompilerIsClang 0
|
||||
# define CompilerIsMsvc 1
|
||||
#else
|
||||
# error Unknown compiler
|
||||
#endif
|
||||
|
||||
//- Language
|
||||
#if defined(__HLSL_VERSION)
|
||||
# define LanguageIsC 0
|
||||
# define LanguageIsGpu 1
|
||||
#else
|
||||
# define LanguageIsC 1
|
||||
# define LanguageIsGpu 0
|
||||
#endif
|
||||
|
||||
//- Platform system
|
||||
#if defined(_WIN32)
|
||||
# define PlatformIsWindows 1
|
||||
# define PlatformIsMac 0
|
||||
# define PlatformIsLinux 0
|
||||
#elif defined(__APPLE__) && defined(__MACH__)
|
||||
# define PlatformIsWindows 0
|
||||
# define PlatformIsMac 1
|
||||
# define PlatformIsLinux 0
|
||||
#elif defined(__gnu_linux__)
|
||||
# define PlatformIsWindows 0
|
||||
# define PlatformIsMac 0
|
||||
# define PlatformIsLinux 1
|
||||
#elif LanguageIsGpu
|
||||
# define PlatformIsWindows 0
|
||||
# define PlatformIsMac 0
|
||||
# define PlatformIsLinux 0
|
||||
#else
|
||||
# error Unknown platform
|
||||
#endif
|
||||
|
||||
//- Windows NTDDI version
|
||||
/* FIXME: Remove this */
|
||||
#if 0
|
||||
#if CompilerIsMsvc
|
||||
# define NTDDI_WIN11_DT 0x0C0A0000
|
||||
# define NTDDI_VERSION 0x0A000000
|
||||
# if RtcIsEnabled
|
||||
# define _ALLOW_RTCc_IN_STL 1
|
||||
# endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//- Windows defines
|
||||
#if PlatformIsWindows
|
||||
# define COBJMACROS
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# define UNICODE
|
||||
# pragma warning(push, 0)
|
||||
# include <Windows.h>
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ Debug
|
||||
|
||||
//- Static assert
|
||||
#if LanguageIsC
|
||||
# define StaticAssert2(cond, line, counter) struct STATIC_ASSERT_____##line##counter {int foo[(cond) ? 1 : -1];}
|
||||
# define StaticAssert1(cond, line, counter) StaticAssert2(cond, line, counter)
|
||||
# define StaticAssert(cond) StaticAssert1(cond, __LINE__, __COUNTER__)
|
||||
#else
|
||||
# define StaticAssert(cond) static_assert(cond, "")
|
||||
#endif
|
||||
|
||||
//- Debug assert
|
||||
#if RtcIsEnabled
|
||||
# if CompilerIsMsvc
|
||||
// # define Assert(cond) ((cond) ? 1 : (IsRunningInDebugger() ? (*(volatile i32 *)0 = 0) : Panic(Lit("Assert(" #cond ") failed at " __FILE__ ":" Stringize(__LINE__)))))
|
||||
# define Assert(cond) ((cond) ? 1 : (IsRunningInDebugger() ? (*(volatile i32 *)0 = 0) : Panic(Lit(__FILE__ "(" Stringize(__LINE__) "): error Assert("#cond")"))))
|
||||
# define DEBUGBREAK __debugbreak
|
||||
# else
|
||||
# define Assert(cond) ((cond) ? 1 : (__builtin_trap(), 0))
|
||||
# define DEBUGBREAK __builtin_debugtrap()
|
||||
# endif
|
||||
# define DEBUGBREAKABLE { volatile i32 __DEBUGBREAKABLE_VAR = 0; LAX __DEBUGBREAKABLE_VAR; } (void)0
|
||||
#else
|
||||
# define Assert(cond) (void)(0)
|
||||
#endif
|
||||
|
||||
//- Root constant assert
|
||||
#define AssertRootConst(s, n) StaticAssert((sizeof(s) % 16 == 0) && /* Root constant struct should pad to 16 byte alignment */ \
|
||||
((sizeof(s) / 4) == n) && /* Root constant struct size should match the specified 32-bit-constant count */ \
|
||||
(sizeof(s) <= 256)) /* Root constant struct can only fit 64 DWORDS */
|
||||
|
||||
//- Debug alias
|
||||
/* TODO: Remove this */
|
||||
#if CompilerIsMsvc
|
||||
# if DebinfoEnabled
|
||||
# define DebugAlias(var, alias) *(alias) = &(var)
|
||||
# else
|
||||
# define DebugAlias(var, alias) *(alias) = &(var)
|
||||
# endif
|
||||
#else
|
||||
# if DebinfoEnabled
|
||||
# define DebugAlias(var, alias) __attribute((used)) *(alias) = &(var)
|
||||
# else
|
||||
# define DebugAlias(var, alias) __attribute((unused)) *(alias) = &(var)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
//- Address sanitization
|
||||
#if AsanIsEnabled
|
||||
void __asan_poison_memory_region(void const volatile *, size_t);
|
||||
void __asan_unpoison_memory_region(void const volatile *add, size_t);
|
||||
# define AsanPoison(addr, size) __asan_poison_memory_region((addr), (size))
|
||||
# define AsanUnpoison(addr, size) __asan_unpoison_memory_region((addr), (size))
|
||||
#else
|
||||
# define AsanPoison(addr, size)
|
||||
# define AsanUnpoison(addr, size)
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ Common utility macros
|
||||
|
||||
//- ZeroStruct initialization macro
|
||||
#if LanguageIsC
|
||||
# define ZI { 0 }
|
||||
#else
|
||||
# define ZI { }
|
||||
#endif
|
||||
|
||||
//- Inline
|
||||
#define Inline static inline
|
||||
|
||||
#if CompilerIsMsvc
|
||||
# define ForceInline Inline __forceinline
|
||||
#else
|
||||
# define ForceInline Inline __attribute((always_inline))
|
||||
#endif
|
||||
|
||||
#if CompilerIsMsvc
|
||||
# define ForceNoInline __declspec(noinline)
|
||||
#else
|
||||
# define ForceNoInline __attribute__((noinline))
|
||||
#endif
|
||||
|
||||
//- Static
|
||||
#define LocalPersist static
|
||||
#define Global static
|
||||
/* TODO: Remove this */
|
||||
#define internal static
|
||||
|
||||
//- Read-only
|
||||
#if PlatformIsWindows
|
||||
# if CompilerIsMsvc
|
||||
# pragma section(".rdata$", read)
|
||||
# define Readonly __declspec(allocate(".rdata$"))
|
||||
# else
|
||||
# define Readonly __declspec(allocate(".rdata"))
|
||||
# endif
|
||||
#elif PlatformIsMac
|
||||
# define Readonly __attribute((section("__TEXT,__const")))
|
||||
#else
|
||||
# define Readonly __attribute((section(".rodata")))
|
||||
#endif
|
||||
|
||||
//- Barriers
|
||||
#if CompilerIsMsvc
|
||||
# define WriteBarrier() _WriteBarrier()
|
||||
# define ReadBarrier() _ReadBarrier()
|
||||
#elif defined(__x86_64) || defined(__i386__)
|
||||
# define WriteBarrier() __asm__ volatile("" ::: "memory")
|
||||
# define ReadBarrier() __asm__ volatile("" ::: "memory")
|
||||
#elif LanguageIsGpu
|
||||
# define WriteBarrier()
|
||||
# define ReadBarrier()
|
||||
#else
|
||||
# error Memory barriers not implemented
|
||||
#endif
|
||||
|
||||
//- Unused markup
|
||||
/* Strict unused markup */
|
||||
#if CompilerIsClang
|
||||
# define UNUSED __attribute((unused))
|
||||
#else
|
||||
# define UNUSED
|
||||
#endif
|
||||
|
||||
/* Relaxed unused markup */
|
||||
#define LAX (void)
|
||||
|
||||
//- Fallthrough
|
||||
#if CompilerIsClang
|
||||
# define FALLTHROUGH __attribute((fallthrough))
|
||||
#else
|
||||
# define FALLTHROUGH
|
||||
#endif
|
||||
|
||||
//- Preprocessor concatenation
|
||||
#define Cat1(a, b) a ## b
|
||||
#define Cat(a, b) Cat1(a, b)
|
||||
|
||||
//- Preprocessor stringization
|
||||
#define Stringize1(x) #x
|
||||
#define Stringize(x) Stringize1(x)
|
||||
|
||||
//- Sizes
|
||||
#define Kibi(n) (n*1024ULL)
|
||||
#define Mebi(n) (n*Kibi(1024ULL))
|
||||
#define Gibi(n) (n*Mebi(1024ULL))
|
||||
#define Tebi(n) (n*Gibi(1024ULL))
|
||||
|
||||
//- Time
|
||||
#define NsFromSeconds(s) ((i64)((s) * 1000000000.0))
|
||||
#define SecondsFromNs(ns) ((f64)(ns) / 1000000000.0)
|
||||
|
||||
////////////////////////////////
|
||||
//~ Linked list helper macros
|
||||
|
||||
/* Taken from the rad debugger
|
||||
* https://github.com/EpicGamesExt/raddebugger/blob/be5634c44867a2e31f6a109df5e574930992df01/src/base/base_core.h#L239
|
||||
*/
|
||||
|
||||
#define CheckNil(nil,p) ((p) == 0 || (p) == nil)
|
||||
#define SetNil(nil,p) ((p) = nil)
|
||||
|
||||
//- Singly linked list stack (first & next pointers)
|
||||
#define SllStackPush_N(f,n,next) ((n)->next=(f), (f)=(n))
|
||||
#define SllStackPop_N(f,next) ((f)=(f)->next)
|
||||
#define SllStackPush(f,n) SllStackPush_N(f,n,next)
|
||||
#define SllStackPop(f) SllStackPop_N(f,next)
|
||||
|
||||
//- Singly linked list queue (first, last, & next pointers)
|
||||
#define SllQueuePush_NZ(nil,f,l,n,next) (CheckNil(nil,f)?\
|
||||
((f)=(l)=(n),SetNil(nil,(n)->next)):\
|
||||
((l)->next=(n),(l)=(n),SetNil(nil,(n)->next)))
|
||||
#define SllQueuePushFront_NZ(nil,f,l,n,next) (CheckNil(nil,f)?\
|
||||
((f)=(l)=(n),SetNil(nil,(n)->next)):\
|
||||
((n)->next=(f),(f)=(n)))
|
||||
#define SllQueuePop_NZ(nil,f,l,next) ((f)==(l)?\
|
||||
(SetNil(nil,f),SetNil(nil,l)):\
|
||||
((f)=(f)->next))
|
||||
#define SllQueuePush_N(f,l,n,next) SllQueuePush_NZ(0,f,l,n,next)
|
||||
#define SllQueuePushFront_N(f,l,n,next) SllQueuePushFront_NZ(0,f,l,n,next)
|
||||
#define SllQueuePop_N(f,l,next) SllQueuePop_NZ(0,f,l,next)
|
||||
#define SllQueuePush(f,l,n) SllQueuePush_NZ(0,f,l,n,next)
|
||||
#define SllQueuePushFront(f,l,n) SllQueuePushFront_NZ(0,f,l,n,next)
|
||||
#define SllQueuePop(f,l) SllQueuePop_NZ(0,f,l,next)
|
||||
|
||||
//- Doubly linked list (first, last, next, & prev pointers)
|
||||
#define DllInsert_NPZ(nil,f,l,p,n,next,prev) (CheckNil(nil,f) ? \
|
||||
((f) = (l) = (n), SetNil(nil,(n)->next), SetNil(nil,(n)->prev)) :\
|
||||
CheckNil(nil,p) ? \
|
||||
((n)->next = (f), (f)->prev = (n), (f) = (n), SetNil(nil,(n)->prev)) :\
|
||||
((p)==(l)) ? \
|
||||
((l)->next = (n), (n)->prev = (l), (l) = (n), SetNil(nil, (n)->next)) :\
|
||||
(((!CheckNil(nil,p) && CheckNil(nil,(p)->next)) ? (0) : ((p)->next->prev = (n))), ((n)->next = (p)->next), ((p)->next = (n)), ((n)->prev = (p))))
|
||||
#define DllPushBack_NPZ(nil,f,l,n,next,prev) DllInsert_NPZ(nil,f,l,l,n,next,prev)
|
||||
#define DllPushFront_NPZ(nil,f,l,n,next,prev) DllInsert_NPZ(nil,l,f,f,n,prev,next)
|
||||
#define DllRemove_NPZ(nil,f,l,n,next,prev) (((n) == (f) ? (f) = (n)->next : (0)),\
|
||||
((n) == (l) ? (l) = (l)->prev : (0)),\
|
||||
(CheckNil(nil,(n)->prev) ? (0) :\
|
||||
((n)->prev->next = (n)->next)),\
|
||||
(CheckNil(nil,(n)->next) ? (0) :\
|
||||
((n)->next->prev = (n)->prev)))
|
||||
#define DllInsert_NP(f,l,p,n,next,prev) DllInsert_NPZ(0,f,l,p,n,next,prev)
|
||||
#define DllPushBack_NP(f,l,n,next,prev) DllPushBack_NPZ(0,f,l,n,next,prev)
|
||||
#define DllPushFront_NP(f,l,n,next,prev) DllPushFront_NPZ(0,f,l,n,next,prev)
|
||||
#define DllRemove_NP(f,l,n,next,prev) DllRemove_NPZ(0,f,l,n,next,prev)
|
||||
#define DllInsert(f,l,p,n) DllInsert_NPZ(0,f,l,p,n,next,prev)
|
||||
#define DllPushBack(f,l,n) DllPushBack_NPZ(0,f,l,n,next,prev)
|
||||
#define DllPushFront(f,l,n) DllPushFront_NPZ(0,f,l,n,next,prev)
|
||||
#define DllRemove(f,l,n) DllRemove_NPZ(0,f,l,n,next,prev)
|
||||
|
||||
////////////////////////////////
|
||||
//~ Struct alignment / padding macros
|
||||
|
||||
//- Pack
|
||||
#if CompilerIsMsvc
|
||||
# define Packed(s) __pragma(pack(push, 1)) s __pragma(pack(pop))
|
||||
#elif CompilerIsClang
|
||||
# define Packed(s) s __attribute((__packed__))
|
||||
#elif LanguageIsGpu
|
||||
# define Packed(s) s
|
||||
#endif
|
||||
|
||||
//- alignas
|
||||
#if (CompilerIsMsvc && LanguageIsC) || (LanguageIsC && __STDC_VERSION__ < 202311L)
|
||||
# if CompilerIsMsvc
|
||||
# define alignas(n) __declspec(align(n))
|
||||
# else
|
||||
# define alignas(n) __attribute__((aligned(n)))
|
||||
# endif
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ Color helper macros
|
||||
|
||||
//- Rgba 32 bit helpers
|
||||
#define Rgb32(r, g, b) Rgba32((r), (g), (b), 0xFF)
|
||||
#define Rgba32(r, g, b, a) (u32)((u32)(r) | ((u32)(g) << 8) | ((u32)(b) << 16) | ((u32)(a) << 24))
|
||||
#define Bgr32(rgb) ((((rgb >> 0) & 0xFF) << 16) | (((rgb >> 8) & 0xFF) << 8) | (((rgb >> 16) & 0xFF) << 0))
|
||||
|
||||
//- Rgba 32 bit float float helpers
|
||||
#define _Rgb32U8FromF(fl) ((u8)((fl * 255.0) + 0.5))
|
||||
#define Rgba32F(r, g, b, a) Rgba32(_Rgb32U8FromF((r)), _Rgb32U8FromF((g)), _Rgb32U8FromF((b)), _Rgb32U8FromF((a)))
|
||||
#define Rgb32F(r, g, b) Rgba32F((r), (g), (b), 1.f)
|
||||
|
||||
#define Alpha32F(color, a) ((color) & 0x00FFFFFF) | (_Rgb32U8FromF((a)) << 24)
|
||||
|
||||
//- Pre-defined colors
|
||||
#define ColorWhite Rgb32(0xFF, 0xFF, 0xFF)
|
||||
#define ColorBlack Rgb32(0x00, 0x00, 0x00)
|
||||
#define ColorRed Rgb32(0xFF, 0x00, 0x00)
|
||||
#define ColorGreen Rgb32(0x00, 0xFF, 0x00)
|
||||
#define ColorBlue Rgb32(0x00, 0x00, 0xFF)
|
||||
#define ColorYellow Rgb32(0xFF, 0xFF, 0x00)
|
||||
#define ColorOrange Rgb32(0xFF, 0xA5, 0x00)
|
||||
#define ColorPurple Rgb32(0xFF, 0x00, 0XFF)
|
||||
|
||||
////////////////////////////////
|
||||
//~ Gpu helpers
|
||||
|
||||
#if LanguageIsGpu
|
||||
//- Resource heap index
|
||||
# define GpuResourceFromUrid(urid) ResourceDescriptorHeap[urid]
|
||||
# define GpuResourceFromNurid(nurid) ResourceDescriptorHeap[NonUniformResourceIndex(nurid)]
|
||||
|
||||
//- Semantic declaration
|
||||
# define Semantic(t, n) t n : n
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ Intrinsic headers
|
||||
|
||||
#if LanguageIsC
|
||||
/* Intrinsic header info:
|
||||
* <mmintrin.h" MMX
|
||||
* <xmmintrin.h" SSE
|
||||
* <emmintrin.h" SSE2
|
||||
* <pmmintrin.h" SSE3
|
||||
* <tmmintrin.h" SSSE3
|
||||
* <smmintrin.h" SSE4.1
|
||||
* <nmmintrin.h" SSE4.2
|
||||
* <ammintrin.h" SSE4A
|
||||
* <wmmintrin.h" AES
|
||||
* <immintrin.h" AVX, AVX2, FMA
|
||||
*/
|
||||
#include "intrin.h"
|
||||
#include "nmmintrin.h" /* SSE4.2 */
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ Type helper macros
|
||||
|
||||
//- Struct
|
||||
#define Struct(name) typedef struct name name; struct name
|
||||
#define AlignedStruct(name, n) typedef struct name name; struct alignas(n) name
|
||||
|
||||
//- Enum
|
||||
#define Enum(name) typedef enum name name; enum name
|
||||
|
||||
//- alignof
|
||||
#if LanguageIsC && (CompilerIsMsvc || __STDC_VERSION__ < 202311L)
|
||||
# define alignof(type) __alignof(type)
|
||||
#endif
|
||||
|
||||
//- sizeof_field
|
||||
#define sizeof_field(type, field) sizeof(((type *)0)->field)
|
||||
|
||||
//- countof
|
||||
#define countof(a) (sizeof(a) / sizeof((a)[0]))
|
||||
|
||||
//- IsArray
|
||||
#define IsIndexable(a) (sizeof(a[0]) != 0)
|
||||
#define IsArray(a) (IsIndexable(a) && (((void *)&a) == ((void *)a)))
|
||||
|
||||
//- offsetof
|
||||
#if 0
|
||||
#if !CompilerIsMsvc
|
||||
# if !defined _CRT_USE_BUILTIN_OFFSETOF
|
||||
# define offsetof(type, field) ((u64)&(((type *)0)->field))
|
||||
# else
|
||||
# define offsetof(type, field) __builtin_offsetof(type, field)
|
||||
# endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ Scalar types
|
||||
|
||||
#if LanguageIsC
|
||||
//- Cpu scalar types
|
||||
#include "stdint.h"
|
||||
typedef int8_t i8;
|
||||
typedef int16_t i16;
|
||||
typedef int32_t i32;
|
||||
typedef int64_t i64;
|
||||
typedef uint8_t u8;
|
||||
typedef uint16_t u16;
|
||||
typedef uint32_t u32;
|
||||
typedef uint64_t u64;
|
||||
typedef float f32;
|
||||
typedef double f64;
|
||||
typedef i8 b8;
|
||||
typedef u32 b32;
|
||||
#else
|
||||
//- Gpu scalar types
|
||||
typedef int i32;
|
||||
typedef uint u32;
|
||||
typedef float f32;
|
||||
typedef uint b32;
|
||||
#endif
|
||||
|
||||
//- Min / max constants
|
||||
#define U8Max (0xFF)
|
||||
#define U16Max (0xFFFF)
|
||||
#define U32Max (0xFFFFFFFF)
|
||||
#define U64Max (0xFFFFFFFFFFFFFFFFULL)
|
||||
|
||||
#define I8Max (0x7F)
|
||||
#define I16Max (0x7FFF)
|
||||
#define I32Max (0x7FFFFFFF)
|
||||
#define I64Max (0x7FFFFFFFFFFFFFFFLL)
|
||||
|
||||
#define I8Min ((i8)-0x80)
|
||||
#define I16Min ((i16)0x8000)
|
||||
#define I32Min ((i32)0x80000000)
|
||||
#define I64Min ((i64)0x8000000000000000LL)
|
||||
|
||||
//- Float infinity / nan constants
|
||||
#if LanguageIsC
|
||||
Global const u32 _f32_infinity_u32 = 0x7f800000;
|
||||
Global const f32 *_f32_infinity = (f32 *)&_f32_infinity_u32;
|
||||
#define F32Infinity (*_f32_infinity)
|
||||
|
||||
Global const u64 _f64_infinity_u64 = 0x7ff0000000000000ULL;
|
||||
Global const f64 *_f64_infinity = (f64 *)&_f64_infinity_u64;
|
||||
#define F64Infinity (*_f64_infinity)
|
||||
|
||||
Global const u32 _f32_nan_u32 = 0x7f800001;
|
||||
Global const f32 *_f32_nan = (f32 *)&_f32_nan_u32;
|
||||
#define F32Nan (*_f32_nan)
|
||||
|
||||
Global const u64 _f64_nan_u64 = 0x7ff8000000000001;
|
||||
Global const f64 *_f64_nan = (f64 *)&_f64_nan_u64;
|
||||
#define F64Nan (*_f64_nan)
|
||||
|
||||
#define IsF32Nan(x) (x != x)
|
||||
#define IsF64Nan(x) (x != x)
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ Atomics
|
||||
|
||||
#if LanguageIsC
|
||||
|
||||
//- Atomic types
|
||||
Struct(Atomic8) { volatile i8 _v; };
|
||||
Struct(Atomic16) { volatile i16 _v; };
|
||||
Struct(Atomic32) { volatile i32 _v; };
|
||||
Struct(Atomic64) { volatile i64 _v; };
|
||||
|
||||
//- Cache-line isolated aligned atomic types
|
||||
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);
|
||||
StaticAssert(sizeof(Atomic16Padded) == 64 && alignof(Atomic16Padded) == 64);
|
||||
StaticAssert(sizeof(Atomic32Padded) == 64 && alignof(Atomic32Padded) == 64);
|
||||
StaticAssert(sizeof(Atomic64Padded) == 64 && alignof(Atomic64Padded) == 64);
|
||||
|
||||
#if PlatformIsWindows
|
||||
//- 8 bit atomic operations
|
||||
ForceInline i8 Atomic8Fetch(Atomic8 *x) { return (i8)_InterlockedCompareExchange8((char *)&x->_v, 0, 0); }
|
||||
ForceInline i8 Atomic8FetchSet(Atomic8 *x, i8 e) { return (i8)_InterlockedExchange8((char *)&x->_v, e); }
|
||||
ForceInline i8 Atomic8FetchTestSet(Atomic8 *x, i8 c, i8 e) { return (i8)_InterlockedCompareExchange8((char *)&x->_v, e, c); }
|
||||
ForceInline i8 Atomic8FetchXor(Atomic8 *x, i8 c) { return (i8)_InterlockedXor8((char *)&x->_v, c); }
|
||||
ForceInline i8 Atomic8FetchAdd(Atomic8 *x, i8 a) { return (i8)_InterlockedExchangeAdd8((char *)&x->_v, a); }
|
||||
//- 16 bit atomic operations
|
||||
ForceInline i16 Atomic16Fetch(Atomic16 *x) { return (i16)_InterlockedCompareExchange16(&x->_v, 0, 0); }
|
||||
ForceInline i16 Atomic16FetchSet(Atomic16 *x, i16 e) { return (i16)_InterlockedExchange16(&x->_v, e); }
|
||||
ForceInline i16 Atomic16FetchTestSet(Atomic16 *x, i16 c, i16 e) { return (i16)_InterlockedCompareExchange16(&x->_v, e, c); }
|
||||
ForceInline i16 Atomic16FetchTestXor(Atomic16 *x, i16 c) { return (i16)_InterlockedXor16(&x->_v, c); }
|
||||
ForceInline i16 Atomic16FetchTestAdd(Atomic16 *x, i16 a) { return (i16)_InterlockedExchangeAdd16(&x->_v, a); }
|
||||
//- 32 bit atomic operations
|
||||
ForceInline i32 Atomic32Fetch(Atomic32 *x) { return (i32)_InterlockedCompareExchange((volatile long *)&x->_v, 0, 0); }
|
||||
ForceInline i32 Atomic32FetchSet(Atomic32 *x, i32 e) { return (i32)_InterlockedExchange((volatile long *)&x->_v, e); }
|
||||
ForceInline i32 Atomic32FetchTestSet(Atomic32 *x, i32 c, i32 e) { return (i32)_InterlockedCompareExchange((volatile long *)&x->_v, e, c); }
|
||||
ForceInline i32 Atomic32FetchXor(Atomic32 *x, i32 c) { return (i32)_InterlockedXor((volatile long *)&x->_v, c); }
|
||||
ForceInline i32 Atomic32FetchAdd(Atomic32 *x, i32 a) { return (i32)_InterlockedExchangeAdd((volatile long *)&x->_v, a); }
|
||||
//- 64 bit atomic operations
|
||||
ForceInline i64 Atomic64Fetch(Atomic64 *x) { return (i64)_InterlockedCompareExchange64(&x->_v, 0, 0); }
|
||||
ForceInline i64 Atomic64FetchSet(Atomic64 *x, i64 e) { return (i64)_InterlockedExchange64(&x->_v, e); }
|
||||
ForceInline i64 Atomic64FetchTestSet(Atomic64 *x, i64 c, i64 e) { return (i64)_InterlockedCompareExchange64(&x->_v, e, c); }
|
||||
ForceInline i64 Atomic64FetchXor(Atomic64 *x, i64 c) { return (i64)_InterlockedXor64(&x->_v, c); }
|
||||
ForceInline i64 Atomic64FetchAdd(Atomic64 *x, i64 a) { return (i64)_InterlockedExchangeAdd64(&x->_v, a); }
|
||||
#else
|
||||
# error Atomics not implemented
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ Ticket mutex
|
||||
|
||||
#if LanguageIsC
|
||||
Struct(TicketMutex)
|
||||
{
|
||||
Atomic64Padded ticket;
|
||||
Atomic64Padded serving;
|
||||
};
|
||||
|
||||
ForceInline void LockTicketMutex(TicketMutex *tm)
|
||||
{
|
||||
i64 ticket = Atomic64FetchAdd(&tm->ticket.v, 1);
|
||||
while (Atomic64Fetch(&tm->serving.v) != ticket)
|
||||
{
|
||||
_mm_pause();
|
||||
}
|
||||
}
|
||||
|
||||
ForceInline void UnlockTicketMutex(TicketMutex *tm)
|
||||
{
|
||||
Atomic64FetchAdd(&tm->serving.v, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ String utils
|
||||
|
||||
#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)
|
||||
{
|
||||
u64 len;
|
||||
u8 *text;
|
||||
};
|
||||
|
||||
Struct(String16)
|
||||
{
|
||||
u64 len;
|
||||
u16 *text;
|
||||
};
|
||||
|
||||
Struct(String32)
|
||||
{
|
||||
u64 len;
|
||||
u32 *text;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ Fibers
|
||||
|
||||
#define MaxFibers 1024
|
||||
|
||||
#if LanguageIsC
|
||||
# if PlatformIsWindows
|
||||
ForceInline i16 FiberId(void)
|
||||
{
|
||||
i16 *v = (void *)(u64)__readgsqword(32);
|
||||
return *v;
|
||||
}
|
||||
# else
|
||||
# error FiberId not implemented
|
||||
# endif
|
||||
StaticAssert(MaxFibers < I16Max); /* Fiber id type should fit max fibers */
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ @hookdecl Core hooks
|
||||
|
||||
void StartupBase(void);
|
||||
b32 Panic(String msg);
|
||||
b32 IsRunningInDebugger(void);
|
||||
i16 ThreadId(void);
|
||||
void TrueRand(String buffer);
|
||||
|
||||
#define MaxThreads 1024
|
||||
StaticAssert(MaxThreads < I16Max); /* Thread id type should fit max threads */
|
||||
|
||||
////////////////////////////////
|
||||
//~ @hookdecl Layer startup hook (defined by meta program)
|
||||
|
||||
void StartupLayers(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ Prof
|
||||
|
||||
#include "../prof/prof_tracy.h"
|
||||
|
||||
////////////////////////////////
|
||||
//~ Config
|
||||
|
||||
#include "../config.h"
|
||||
@ -1,139 +0,0 @@
|
||||
SharedArenaCtx shared_arena_ctx = ZI;
|
||||
|
||||
/* NOTE: Application will exit if arena fails to reserve or commit initial memory. */
|
||||
Arena *AcquireArena(u64 reserve)
|
||||
{
|
||||
__prof;
|
||||
reserve += ArenaHeaderSize;
|
||||
|
||||
/* Round up to nearest block size */
|
||||
u64 block_remainder = reserve % ArenaBlockSize;
|
||||
if (block_remainder > 0)
|
||||
{
|
||||
reserve += ArenaBlockSize - block_remainder;
|
||||
}
|
||||
|
||||
u8 *base = ReserveMemory(reserve);
|
||||
if (!base)
|
||||
{
|
||||
/* Hard fail on memory reserve failure for now */
|
||||
Panic(Lit("Failed to reserve memory"));
|
||||
}
|
||||
u64 reserved = reserve;
|
||||
|
||||
/* Commit initial block */
|
||||
base = CommitMemory(base, ArenaBlockSize);
|
||||
if (!base)
|
||||
{
|
||||
/* Hard fail on commit failure */
|
||||
Panic(Lit("Failed to commit initial memory block: System may be out of memory"));
|
||||
}
|
||||
|
||||
Assert(((u64)base & 0xFFF) == 0); /* Base should be 4k aligned */
|
||||
StaticAssert(ArenaHeaderSize <= ArenaBlockSize); /* Header must fit in first block */
|
||||
StaticAssert(sizeof(Arena) <= ArenaHeaderSize); /* Arena struct must fit in header */
|
||||
|
||||
__profalloc(base, ArenaBlockSize);
|
||||
AsanPoison(base + sizeof(Arena), ArenaBlockSize - sizeof(Arena));
|
||||
|
||||
/* Create & return arena header at beginning of block */
|
||||
Arena *arena = (Arena *)base;
|
||||
ZeroStruct(arena);
|
||||
arena->committed = ArenaBlockSize - ArenaHeaderSize;
|
||||
arena->reserved = reserved;
|
||||
return arena;
|
||||
}
|
||||
|
||||
void ReleaseArena(Arena *arena)
|
||||
{
|
||||
AsanUnpoison(arena, arena->committed + ArenaHeaderSize);
|
||||
__prof;
|
||||
__proffree(arena);
|
||||
ReleaseMemory(arena);
|
||||
}
|
||||
|
||||
/* NOTE: Application will exit if arena fails to commit memory */
|
||||
void *PushBytesNoZero(Arena *arena, u64 size, u64 align)
|
||||
{
|
||||
Assert(align > 0);
|
||||
Assert(!arena->readonly);
|
||||
|
||||
void *ptr = 0;
|
||||
u8 *base = ArenaBase(arena);
|
||||
|
||||
/* Check to avoid aligning when size = 0 */
|
||||
if (size > 0)
|
||||
{
|
||||
u64 aligned_start_pos = (arena->pos + (align - 1));
|
||||
aligned_start_pos -= aligned_start_pos % align;
|
||||
|
||||
u64 new_pos = aligned_start_pos + size;
|
||||
if (new_pos > arena->committed)
|
||||
{
|
||||
__profn("Arena commit");
|
||||
/* Commit new block(s) */
|
||||
u64 blocks_needed = (new_pos - arena->committed + ArenaBlockSize - 1) / ArenaBlockSize;
|
||||
u64 commit_bytes = blocks_needed * ArenaBlockSize;
|
||||
u64 new_capacity = arena->committed + commit_bytes;
|
||||
if (new_capacity > arena->reserved)
|
||||
{
|
||||
/* Hard fail if we overflow reserved memory for now */
|
||||
Panic(Lit("Failed to commit new memory block: Overflow of reserved memory"));
|
||||
}
|
||||
void *commit_address = base + arena->committed;
|
||||
if (!CommitMemory(commit_address, commit_bytes))
|
||||
{
|
||||
/* Hard fail on memory allocation failure for now */
|
||||
Panic(Lit("Failed to commit new memory block: System may be out of memory"));
|
||||
}
|
||||
arena->committed += commit_bytes;
|
||||
__proffree(arena);
|
||||
__profalloc(arena, arena->committed + ArenaHeaderSize);
|
||||
AsanPoison(commit_address, commit_bytes);
|
||||
}
|
||||
|
||||
ptr = base + aligned_start_pos;
|
||||
AsanUnpoison(ptr, new_pos - aligned_start_pos);
|
||||
arena->pos = new_pos;
|
||||
}
|
||||
else
|
||||
{
|
||||
ptr = base + arena->pos;
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/* Copies the memory from the source arena into the destination arena,
|
||||
* replacing old contents. Destination arena will be expanded if necessary. */
|
||||
void CopyArena(Arena *dst, Arena *src)
|
||||
{
|
||||
ResetArena(dst);
|
||||
u64 data_size = src->pos;
|
||||
u8 *data_src = ArenaBase(src);
|
||||
u8 *data_dst = PushBytesNoZero(dst, data_size, 1);
|
||||
CopyBytes(data_dst, data_src, data_size);
|
||||
}
|
||||
|
||||
void ShrinkArena(Arena *arena)
|
||||
{
|
||||
/* Not implemented */
|
||||
Assert(0);
|
||||
LAX arena;
|
||||
}
|
||||
|
||||
void SetArenaReadonly(Arena *arena)
|
||||
{
|
||||
#if RtcIsEnabled
|
||||
arena->readonly = 1;
|
||||
#endif
|
||||
SetMemoryReadonly(arena, arena->committed + ArenaHeaderSize);
|
||||
}
|
||||
|
||||
void SetArenaReadWrite(Arena *arena)
|
||||
{
|
||||
SetMemoryReadWrite(arena, arena->committed + ArenaHeaderSize);
|
||||
#if RtcIsEnabled
|
||||
arena->readonly = 0;
|
||||
#endif
|
||||
}
|
||||
@ -1,260 +0,0 @@
|
||||
////////////////////////////////
|
||||
//~ Arena types
|
||||
|
||||
#define ArenaHeaderSize 64
|
||||
#define ArenaBlockSize 16384
|
||||
|
||||
Struct(Arena)
|
||||
{
|
||||
u64 pos;
|
||||
u64 committed;
|
||||
u64 reserved;
|
||||
#if RtcIsEnabled
|
||||
b32 readonly;
|
||||
#endif
|
||||
};
|
||||
|
||||
Struct(TempArena)
|
||||
{
|
||||
Arena *arena;
|
||||
u64 start_pos;
|
||||
|
||||
#if RtcIsEnabled
|
||||
u64 scratch_id;
|
||||
#endif
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ Per-thread arena ctx types
|
||||
|
||||
#define ScratchArenasPerCtx 2
|
||||
|
||||
Struct(ArenaCtx)
|
||||
{
|
||||
Arena *scratch_arenas[ScratchArenasPerCtx];
|
||||
Arena *perm_arena;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ Shared state
|
||||
|
||||
Struct(SharedArenaCtx)
|
||||
{
|
||||
ArenaCtx arena_contexts[MaxThreads];
|
||||
};
|
||||
|
||||
extern SharedArenaCtx shared_arena_ctx;
|
||||
|
||||
////////////////////////////////
|
||||
//~ Arena push/pop
|
||||
|
||||
#define PushStruct(a, type) ((type *)PushBytes((a), sizeof(type), alignof(type)))
|
||||
#define PushStructNoZero(a, type) ((type *)PushBytesNoZero((a), sizeof(type), alignof(type)))
|
||||
|
||||
#define PushStructs(a, type, n) ((type *)PushBytes((a), (sizeof(type) * (n)), alignof(type)))
|
||||
#define PushStructsNoZero(a, type, n) ((type *)PushBytesNoZero((a), (sizeof(type) * (n)), alignof(type)))
|
||||
|
||||
#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)))
|
||||
|
||||
void *PushBytesNoZero(Arena *arena, u64 size, u64 align);
|
||||
|
||||
Inline void *PushBytes(Arena *arena, u64 size, u64 align)
|
||||
{
|
||||
void *p = PushBytesNoZero(arena, size, align);
|
||||
ZeroBytes(p, size);
|
||||
return p;
|
||||
}
|
||||
|
||||
Inline u8 *ArenaBase(Arena *arena)
|
||||
{
|
||||
return (u8 *)arena + ArenaHeaderSize;
|
||||
}
|
||||
|
||||
Inline void PopTo(Arena *arena, u64 pos)
|
||||
{
|
||||
Assert(arena->pos >= pos);
|
||||
Assert(!arena->readonly);
|
||||
|
||||
AsanPoison(ArenaBase(arena) + pos, arena->pos - 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);
|
||||
Assert(!arena->readonly);
|
||||
|
||||
u64 new_pos = arena->pos - size;
|
||||
void *src = (void *)(ArenaBase(arena) + new_pos);
|
||||
CopyBytes(copy_dst, src, size);
|
||||
|
||||
AsanPoison(ArenaBase(arena) + new_pos, arena->pos - new_pos);
|
||||
arena->pos = new_pos;
|
||||
}
|
||||
|
||||
Inline void *_PushDry(Arena *arena, u64 align)
|
||||
{
|
||||
u64 aligned_start_pos = (arena->pos + (align - 1));
|
||||
aligned_start_pos -= aligned_start_pos % align;
|
||||
void *ptr = ArenaBase(arena) + aligned_start_pos;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ Arena management
|
||||
|
||||
Arena *AcquireArena(u64 reserve);
|
||||
void ReleaseArena(Arena *arena);
|
||||
|
||||
void CopyArena(Arena *dst, Arena *src);
|
||||
void ShrinkArena(Arena *arena);
|
||||
void SetArenaReadonly(Arena *arena);
|
||||
void SetArenaReadWrite(Arena *arena);
|
||||
|
||||
Inline void *AlignArena(Arena *arena, u64 align)
|
||||
{
|
||||
Assert(!arena->readonly);
|
||||
if (align > 0)
|
||||
{
|
||||
u64 aligned_start_pos = (arena->pos + (align - 1));
|
||||
aligned_start_pos -= aligned_start_pos % align;
|
||||
u64 align_bytes = aligned_start_pos - (u64)arena->pos;
|
||||
if (align_bytes > 0)
|
||||
{
|
||||
return (void *)PushStructsNoZero(arena, u8, align_bytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
return (void *)(ArenaBase(arena) + arena->pos);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* 0 alignment */
|
||||
Assert(0);
|
||||
return (void *)(ArenaBase(arena) + arena->pos);
|
||||
}
|
||||
}
|
||||
|
||||
Inline void *ResetArena(Arena *arena)
|
||||
{
|
||||
PopTo(arena, 0);
|
||||
return (void *)ArenaBase(arena);
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ Temp arena operations
|
||||
|
||||
Inline TempArena BeginTempArena(Arena *arena)
|
||||
{
|
||||
TempArena t = ZI;
|
||||
t.arena = arena;
|
||||
t.start_pos = arena->pos;
|
||||
return t;
|
||||
}
|
||||
|
||||
Inline void EndTempArena(TempArena temp)
|
||||
{
|
||||
PopTo(temp.arena, temp.start_pos);
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ Arena ctx operations
|
||||
|
||||
Inline ArenaCtx *ArenaCtxFromThreadId(i16 thread_id)
|
||||
{
|
||||
SharedArenaCtx *shared = &shared_arena_ctx;
|
||||
ArenaCtx *ctx = &shared->arena_contexts[thread_id];
|
||||
if (!ctx->scratch_arenas[0])
|
||||
{
|
||||
__profn("Initialize thread arena ctx");
|
||||
for (i32 i = 0; i < (i32)countof(ctx->scratch_arenas); ++i)
|
||||
{
|
||||
ctx->scratch_arenas[i] = AcquireArena(Gibi(64));
|
||||
}
|
||||
ctx->perm_arena = AcquireArena(Gibi(64));
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ Scratch helpers
|
||||
|
||||
/* Any parameterized arenas in the caller's scope should be passed into this
|
||||
* function as a potential "conflict". This is to prevent friction in case the
|
||||
* passed arena is itself a scratch arena from another scope (since
|
||||
* parameterized arenas are often used to allocate persistent results for the
|
||||
* caller).
|
||||
*
|
||||
* Use `BeginScratchNoConflict` instead if there is no arena in the current
|
||||
* scope that could potentially be a scratch arena from another scope. */
|
||||
#define BeginScratch(potential_conflict) _BeginScratch(potential_conflict)
|
||||
|
||||
Inline TempArena _BeginScratch(Arena *potential_conflict)
|
||||
{
|
||||
/* This function is currently hard-coded to support 2 scratch arenas */
|
||||
StaticAssert(ScratchArenasPerCtx == 2);
|
||||
|
||||
/* Use `BeginScratchNoConflict` if no conflicts are present */
|
||||
Assert(potential_conflict != 0);
|
||||
|
||||
ArenaCtx *ctx = ArenaCtxFromThreadId(ThreadId());
|
||||
Arena *scratch_arena = ctx->scratch_arenas[0];
|
||||
if (potential_conflict && scratch_arena == potential_conflict)
|
||||
{
|
||||
scratch_arena = ctx->scratch_arenas[1];
|
||||
}
|
||||
TempArena temp = BeginTempArena(scratch_arena);
|
||||
return temp;
|
||||
}
|
||||
|
||||
/* This macro declares an unused "arena" variable that will error if an existing "arena"
|
||||
* variable is present (due to shadowing). This is for catching obvious cases of
|
||||
* `BeginScratchNoConflict` getting called when an `arena` variable already
|
||||
* exists in the caller's scope (`BeginScratch(arena)` should be called
|
||||
* instead). */
|
||||
#define BeginScratchNoConflict() \
|
||||
BeginScratchNoConflict_(); \
|
||||
do { \
|
||||
u8 arena = 0; \
|
||||
LAX arena; \
|
||||
} while (0)
|
||||
|
||||
Inline TempArena BeginScratchNoConflict_(void)
|
||||
{
|
||||
ArenaCtx *ctx = ArenaCtxFromThreadId(ThreadId());
|
||||
Arena *scratch_arena = ctx->scratch_arenas[0];
|
||||
TempArena temp = BeginTempArena(scratch_arena);
|
||||
return temp;
|
||||
}
|
||||
|
||||
Inline void EndScratch(TempArena scratch_temp)
|
||||
{
|
||||
EndTempArena(scratch_temp);
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ Perm arena helpers
|
||||
|
||||
Inline Arena *GetPermArena(void)
|
||||
{
|
||||
ArenaCtx *ctx = ArenaCtxFromThreadId(ThreadId());
|
||||
return ctx->perm_arena;
|
||||
}
|
||||
@ -1,23 +0,0 @@
|
||||
//- 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_rand.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"
|
||||
#include "meta_base_rand.c"
|
||||
|
||||
//- Win32
|
||||
#if PlatformIsWindows
|
||||
# include "meta_base_win32/meta_base_win32_inc.h"
|
||||
#endif
|
||||
@ -1,105 +0,0 @@
|
||||
////////////////////////////////
|
||||
//~ Sqrt intrinsics
|
||||
|
||||
Inline f32 IxSqrtF32(f32 f)
|
||||
{
|
||||
__m128 n = _mm_set_ss(f);
|
||||
n = _mm_sqrt_ss(n);
|
||||
return _mm_cvtss_f32(n);
|
||||
}
|
||||
|
||||
Inline f64 IxSqrtF64(f64 f)
|
||||
{
|
||||
__m128d n = _mm_set_sd(f);
|
||||
n = _mm_sqrt_sd(_mm_setzero_pd(), n);
|
||||
return _mm_cvtsd_f64(n);
|
||||
}
|
||||
|
||||
Inline f32 IxRsqrtF32(f32 f)
|
||||
{
|
||||
__m128 n = _mm_set_ss(f);
|
||||
n = _mm_rsqrt_ss(n);
|
||||
return _mm_cvtss_f32(n);
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ Round intrinsics
|
||||
|
||||
Inline i32 IxRoundF32ToI32(f32 f)
|
||||
{
|
||||
return _mm_cvtss_si32(_mm_round_ss(_mm_setzero_ps(), _mm_set_ss(f), _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC));
|
||||
}
|
||||
|
||||
Inline f32 IxRoundF32ToF32(f32 f)
|
||||
{
|
||||
return _mm_cvtss_f32(_mm_round_ss(_mm_setzero_ps(), _mm_set_ss(f), _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC));
|
||||
}
|
||||
|
||||
Inline i64 IxRoundF64ToI64(f64 f)
|
||||
{
|
||||
return _mm_cvtsd_si64(_mm_round_sd(_mm_setzero_pd(), _mm_set_sd(f), _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC));
|
||||
}
|
||||
|
||||
Inline f64 IxRoundF64ToF64(f64 f)
|
||||
{
|
||||
return _mm_cvtsd_f64(_mm_round_sd(_mm_setzero_pd(), _mm_set_sd(f), _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC));
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ Floor intrinsics
|
||||
|
||||
Inline i32 IxFloorF32ToI32(f32 f)
|
||||
{
|
||||
return _mm_cvtss_si32(_mm_floor_ss(_mm_setzero_ps(), _mm_set_ss(f)));
|
||||
}
|
||||
|
||||
Inline f32 IxFloorF32ToF32(f32 f)
|
||||
{
|
||||
return _mm_cvtss_f32(_mm_floor_ss(_mm_setzero_ps(), _mm_set_ss(f)));
|
||||
}
|
||||
|
||||
Inline i64 IxFloorF64ToI64(f64 f)
|
||||
{
|
||||
return _mm_cvtsd_si64(_mm_floor_sd(_mm_setzero_pd(), _mm_set_sd(f)));
|
||||
}
|
||||
|
||||
Inline f64 IxFloorF64ToF64(f64 f)
|
||||
{
|
||||
return _mm_cvtsd_f64(_mm_floor_sd(_mm_setzero_pd(), _mm_set_sd(f)));
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ Ceil intrinsics
|
||||
|
||||
Inline i32 IxCeilF32ToI32(f32 f)
|
||||
{
|
||||
return _mm_cvtss_si32(_mm_ceil_ss(_mm_setzero_ps(), _mm_set_ss(f)));
|
||||
}
|
||||
|
||||
Inline f32 IxCeilF32ToF32(f32 f)
|
||||
{
|
||||
return _mm_cvtss_f32(_mm_ceil_ss(_mm_setzero_ps(), _mm_set_ss(f)));
|
||||
}
|
||||
|
||||
Inline i64 IxCeilF64ToI64(f64 f)
|
||||
{
|
||||
return _mm_cvtsd_si64(_mm_ceil_sd(_mm_setzero_pd(), _mm_set_sd(f)));
|
||||
}
|
||||
|
||||
Inline f64 IxCeilF64ToF64(f64 f)
|
||||
{
|
||||
return _mm_cvtsd_f64(_mm_ceil_sd(_mm_setzero_pd(), _mm_set_sd(f)));
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ Truncate intrinsics
|
||||
|
||||
Inline f32 IxTruncF32ToF32(f32 f)
|
||||
{
|
||||
return _mm_cvtss_f32(_mm_round_ss(_mm_setzero_ps(), _mm_set_ss(f), _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC));
|
||||
}
|
||||
|
||||
Inline f64 IxTruncF64ToF64(f64 f)
|
||||
{
|
||||
return _mm_cvtsd_f64(_mm_round_sd(_mm_setzero_pd(), _mm_set_sd(f), _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC));
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,415 +0,0 @@
|
||||
/* Math functions are default 32 bit (f32, i32, etc) unless specified */
|
||||
|
||||
#define Pi ((f32)3.14159265358979323846)
|
||||
#define Tau ((f32)6.28318530717958647693)
|
||||
#define GoldenRatio ((f32)1.61803398874989484820)
|
||||
|
||||
////////////////////////////////
|
||||
//~ Floating point vector2 types
|
||||
|
||||
Struct(Vec2) {
|
||||
f32 x, y;
|
||||
};
|
||||
#define VEC2(x, y) (Vec2) { (x), (y) }
|
||||
|
||||
Struct(Vec2Array) {
|
||||
Vec2 *points;
|
||||
u64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ Floating point vector3 types
|
||||
|
||||
Struct(Vec3) {
|
||||
f32 x, y, z;
|
||||
};
|
||||
#define VEC3(x, y, z) (Vec3) { (x), (y), (z) }
|
||||
|
||||
Struct(Vec3Array) {
|
||||
Vec3 *points;
|
||||
u64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ Floating point vector4 types
|
||||
|
||||
Struct(Vec4) {
|
||||
f32 x, y, z, w;
|
||||
};
|
||||
#define VEC4(x, y, z, w) ((Vec4) { (x), (y), (z), (w) })
|
||||
|
||||
Struct(Vec4Array) {
|
||||
Vec4 *points;
|
||||
u64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ Integer vec2 types
|
||||
|
||||
Struct(Vec2I32) {
|
||||
i32 x, y;
|
||||
};
|
||||
#define VEC2I32(x, y) (Vec2I32) { (x), (y) }
|
||||
|
||||
////////////////////////////////
|
||||
//~ Integer vector3 types
|
||||
|
||||
Struct(Vec3I32) {
|
||||
i32 x, y, z;
|
||||
};
|
||||
#define VEC3I32(x, y, z) (Vec3I32) { (x), (y), (z) }
|
||||
|
||||
////////////////////////////////
|
||||
//~ Integer vector4 types
|
||||
|
||||
Struct(Vec4I32)
|
||||
{
|
||||
i32 x, y, z, w;
|
||||
};
|
||||
#define VEC4I32(x, y, z, w) (Vec4I32) { (x), (y), (z), (w) }
|
||||
|
||||
////////////////////////////////
|
||||
//~ Xform types
|
||||
|
||||
Struct(Xform)
|
||||
{
|
||||
Vec2 bx; /* X basis vector (x axis) */
|
||||
Vec2 by; /* Y basis vector (y axis)*/
|
||||
Vec2 og; /* Translation vector (origin) */
|
||||
};
|
||||
|
||||
/* (T)ranslation, (R)otation, (S)cale */
|
||||
Struct(Trs)
|
||||
{
|
||||
Vec2 t;
|
||||
Vec2 s;
|
||||
f32 r;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ Rect types
|
||||
|
||||
Struct(Rect) {
|
||||
union
|
||||
{
|
||||
struct { f32 x, y, width, height; };
|
||||
struct { Vec2 pos, size; };
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/* Values expected to be normalized 0.0 -> 1.0 */
|
||||
Struct(ClipRect)
|
||||
{
|
||||
Vec2 p0, p1;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ Axis aligned bounding box types
|
||||
|
||||
Struct(Aabb) {
|
||||
Vec2 p0, p1;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ Quad types
|
||||
|
||||
Struct(Quad) {
|
||||
union
|
||||
{
|
||||
struct { Vec2 p0, p1, p2, p3; };
|
||||
struct { Vec2 e[4]; };
|
||||
};
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ Spring types
|
||||
|
||||
Struct(SoftSpring)
|
||||
{
|
||||
f32 bias_rate;
|
||||
f32 mass_scale;
|
||||
f32 impulse_scale;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ Mat4x4 types
|
||||
|
||||
Struct(Mat4x4)
|
||||
{
|
||||
union
|
||||
{
|
||||
struct { Vec4 bx, by, bz, bw; };
|
||||
f32 e[4][4];
|
||||
};
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ Min / max
|
||||
|
||||
//- Min
|
||||
u8 MinU8(u8 a, u8 b);
|
||||
i8 MinI8(i8 a, i8 b);
|
||||
u32 MinU32(u32 a, u32 b);
|
||||
i32 MinI32(i32 a, i32 b);
|
||||
f32 MinF32(f32 a, f32 b);
|
||||
u64 MinU64(u64 a, u64 b);
|
||||
i64 MinI64(i64 a, i64 b);
|
||||
f64 MinF64(f64 a, f64 b);
|
||||
|
||||
//- Max
|
||||
u8 MaxU8(u8 a, u8 b);
|
||||
i8 MaxI8(i8 a, i8 b);
|
||||
u32 MaxU32(u32 a, u32 b);
|
||||
i32 MaxI32(i32 a, i32 b);
|
||||
f32 MaxF32(f32 a, f32 b);
|
||||
u64 MaxU64(u64 a, u64 b);
|
||||
i64 MaxI64(i64 a, i64 b);
|
||||
f64 MaxF64(f64 a, f64 b);
|
||||
|
||||
//- Clamp
|
||||
u32 ClampU32(u32 v, u32 min, u32 max);
|
||||
i32 ClampI32(i32 v, i32 min, i32 max);
|
||||
f32 ClampF32(f32 v, f32 min, f32 max);
|
||||
u64 ClampU64(u64 v, u64 min, u64 max);
|
||||
i64 ClampI64(i64 v, i64 min, i64 max);
|
||||
f64 ClampF64(f64 v, f64 min, f64 max);
|
||||
|
||||
////////////////////////////////
|
||||
//~ Rounding ops
|
||||
|
||||
//- Round
|
||||
f32 RoundF32(f32 f);
|
||||
f64 RoundF64(f64 f);
|
||||
i32 RoundF32ToI32(f32 f);
|
||||
i64 RoundF64ToI64(f64 f);
|
||||
|
||||
//- Floor
|
||||
f32 FloorF32(f32 f);
|
||||
f64 FloorF64(f64 f);
|
||||
i32 FloorF32ToI32(f32 f);
|
||||
i64 FloorF64ToI64(f64 f);
|
||||
|
||||
//- Ceil
|
||||
f32 CeilF32(f32 f);
|
||||
f64 CeilF64(f64 f);
|
||||
i32 CeilF32ToI32(f32 f);
|
||||
i64 CeilF64ToI64(f64 f);
|
||||
|
||||
//- Trunc
|
||||
f32 TruncF32(f32 f);
|
||||
f64 TruncF64(f64 f);
|
||||
|
||||
////////////////////////////////
|
||||
//~ Fmod
|
||||
|
||||
f32 ModF32(f32 x, f32 m);
|
||||
f64 ModF64(f64 x, f64 m);
|
||||
|
||||
////////////////////////////////
|
||||
//~ Abs
|
||||
|
||||
f32 AbsF32(f32 f);
|
||||
f64 AbsF64(f64 f);
|
||||
u32 AbsI32(i32 v);
|
||||
u64 AbsI64(i64 v);
|
||||
i32 SignF32(f32 f);
|
||||
i64 SignF64(f64 f);
|
||||
|
||||
////////////////////////////////
|
||||
//~ Exponential ops
|
||||
|
||||
u64 PowU64(u64 base, u8 exp);
|
||||
u64 AlignU64Pow2(u64 x);
|
||||
f32 LnF32(f32 x);
|
||||
f32 ExpF32(f32 x);
|
||||
f32 PowF32(f32 a, f32 b);
|
||||
f32 SqrtF32(f32 x);
|
||||
f64 SqrtF64(f64 x);
|
||||
f32 RSqrtF32(f32 x);
|
||||
|
||||
////////////////////////////////
|
||||
//~ Trig
|
||||
|
||||
f32 ReduceToPio4(f32 x, i32 *octant_out);
|
||||
f32 SinApproxF32(f32 x);
|
||||
f32 CosApproxF32(f32 x);
|
||||
f32 SinF32(f32 x);
|
||||
f32 CosF32(f32 x);
|
||||
f32 ArcTanF32(f32 x);
|
||||
f32 ArcTan2F32(f32 y, f32 x);
|
||||
f32 ArcSinF32(f32 x);
|
||||
f32 ArcCosF32(f32 x);
|
||||
|
||||
////////////////////////////////
|
||||
//~ Angle unwind
|
||||
|
||||
/* Returns angle in range [-Pi, Pi] */
|
||||
f32 UnwindAngleF32(f32 a);
|
||||
|
||||
////////////////////////////////
|
||||
//~ Float lerp
|
||||
|
||||
f32 LerpF32(f32 val0, f32 val1, f32 t);
|
||||
f64 LerpF64(f64 val0, f64 val1, f64 t);
|
||||
f32 LerpAngleF32(f32 a, f32 b, f32 t);
|
||||
|
||||
////////////////////////////////
|
||||
//~ Int lerp
|
||||
|
||||
i32 LerpI32(i32 val0, i32 val1, f32 t);
|
||||
i64 LerpI64(i64 val0, i64 val1, f64 t);
|
||||
|
||||
////////////////////////////////
|
||||
//~ Vec2 operations
|
||||
|
||||
#define Vec2FromVec2I32(v) VEC2((v).x, (v).y)
|
||||
|
||||
b32 IsVec2Zero(Vec2 a);
|
||||
b32 EqVec2(Vec2 a, Vec2 b);
|
||||
|
||||
//- Mul
|
||||
Vec2 MulVec2(Vec2 a, f32 s);
|
||||
Vec2 MulVec2Vec2(Vec2 a, Vec2 b);
|
||||
Vec2 NegVec2(Vec2 a);
|
||||
|
||||
//- Div
|
||||
Vec2 DivVec2(Vec2 a, f32 s);
|
||||
Vec2 DivVec2Vec2(Vec2 a, Vec2 b);
|
||||
|
||||
//- Add
|
||||
Vec2 AddVec2(Vec2 a, Vec2 b);
|
||||
Vec2 SubVec2(Vec2 a, Vec2 b);
|
||||
|
||||
//- Len
|
||||
f32 Vec2Len(Vec2 a);
|
||||
f32 Vec2LenSq(Vec2 a);
|
||||
Vec2 Vec2WithLen(Vec2 a, f32 len);
|
||||
Vec2 ClampVec2Len(Vec2 a, f32 max);
|
||||
f32 Vec2Distance(Vec2 a, Vec2 b);
|
||||
Vec2 NormVec2(Vec2 a);
|
||||
|
||||
//- Dot
|
||||
f32 DotVec2(Vec2 a, Vec2 b);
|
||||
f32 WedgeVec2(Vec2 a, Vec2 b);
|
||||
Vec2 PerpVec2(Vec2 a);
|
||||
Vec2 MulPerpVec2(Vec2 a, f32 s);
|
||||
Vec2 PerpVec2TowardsDir(Vec2 v, Vec2 dir);
|
||||
|
||||
//- Round / floor / ceil
|
||||
Vec2 RoundVec2(Vec2 a);
|
||||
Vec2I32 RoundVec2ToVec2I32(Vec2 a);
|
||||
Vec2 FloorVec2(Vec2 a);
|
||||
Vec2 CeilVec2(Vec2 a);
|
||||
|
||||
//- Angle
|
||||
i32 WindingFromVec2(Vec2 a, Vec2 b);
|
||||
Vec2 RotateVec2(Vec2 v, f32 a);
|
||||
Vec2 Vec2FromAngle(f32 a);
|
||||
f32 AngleFromVec2(Vec2 v);
|
||||
f32 AngleFromVec2Dirs(Vec2 dir1, Vec2 dir2);
|
||||
f32 AngleFromVec2Points(Vec2 pt1, Vec2 pt2);
|
||||
|
||||
//- Closest point
|
||||
Vec2 ClosestPointFromRay(Vec2 ray_pos, Vec2 ray_dir_norm, Vec2 p);
|
||||
|
||||
//- Lerp
|
||||
Vec2 LerpVec2(Vec2 val0, Vec2 val1, f32 t);
|
||||
Vec2 SlerpVec2(Vec2 val0, Vec2 val1, f32 t);
|
||||
|
||||
////////////////////////////////
|
||||
//~ Vec2I32 Operations
|
||||
|
||||
b32 EqVec2I32(Vec2I32 a, Vec2I32 b);
|
||||
Vec2I32 NegVec2I32(Vec2I32 a);
|
||||
Vec2I32 AddVec2I32(Vec2I32 a, Vec2I32 b);
|
||||
Vec2I32 SubVec2I32(Vec2I32 a, Vec2I32 b);
|
||||
|
||||
////////////////////////////////
|
||||
//~ Xform operations
|
||||
|
||||
b32 EqXform(Xform xf1, Xform xf2);
|
||||
|
||||
//- Initialization
|
||||
#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);
|
||||
Xform XformFromScale(Vec2 scale);
|
||||
Xform XformFromTrs(Trs trs);
|
||||
Xform XformFromRect(Rect rect);
|
||||
|
||||
//- Translation
|
||||
Xform TranslateXform(Xform xf, Vec2 v);
|
||||
Xform WorldTranslateXform(Xform xf, Vec2 v);
|
||||
|
||||
//- Rotation
|
||||
Xform RotateXform(Xform xf, f32 r);
|
||||
Xform WorldRotateXform(Xform xf, f32 r);
|
||||
Xform WorldRotateXformBasis(Xform xf, f32 r);
|
||||
Xform XformWIthWorldRotation(Xform xf, f32 r);
|
||||
|
||||
//- Scale
|
||||
Xform ScaleXform(Xform xf, Vec2 scale);
|
||||
Xform WorldScaleXform(Xform xf, Vec2 scale);
|
||||
|
||||
//- Lerp
|
||||
Xform LerpXform(Xform a, Xform b, f32 t);
|
||||
|
||||
//- Invert
|
||||
Xform InvertXform(Xform xf);
|
||||
|
||||
//- Mul
|
||||
Vec2 MulXformV2(Xform xf, Vec2 v);
|
||||
Xform MulXform(Xform a, Xform b);
|
||||
Quad MulXformQuad(Xform xf, Quad quad);
|
||||
Vec2 MulXformBasisV2(Xform xf, Vec2 v);
|
||||
Vec2 InvertXformMulV2(Xform xf, Vec2 v);
|
||||
Vec2 InvertXformBasisMulV2(Xform xf, Vec2 v);
|
||||
|
||||
//- Helpers
|
||||
Xform BasisFromXform(Xform xf);
|
||||
f32 DeterminantFromXform(Xform xf);
|
||||
Vec2 RightFromXform(Xform xf);
|
||||
Vec2 LeftFromXform(Xform xf);
|
||||
Vec2 UpFromXform(Xform xf);
|
||||
Vec2 DownFromXform(Xform xf);
|
||||
f32 RotationFromXform(Xform xf);
|
||||
Vec2 ScaleFromXform(Xform xf);
|
||||
|
||||
//- Trs
|
||||
#define TRS(...) ((Trs) { .t = VEC2(0,0), .s = VEC2(1, 1), .r = 0, __VA_ARGS__ })
|
||||
|
||||
////////////////////////////////
|
||||
//~ Rect operations
|
||||
|
||||
#define RectFromScalar(_x, _y, _width, _height) (Rect) { .x = (_x), .y = (_y), .width = (_width), .height = (_height) }
|
||||
#define RectFromVec2(_pos, _size) (Rect) { .pos = (_pos), .size = (_size) }
|
||||
#define AllClipped ((ClipRect) { { 0.0f, 0.0f }, { 1.0f, 1.0f } })
|
||||
|
||||
////////////////////////////////
|
||||
//~ Quad operations
|
||||
|
||||
#define UnitSquareQuad (Quad) { .p0 = VEC2(0, 0), .p1 = VEC2(0, 1), .p2 = VEC2(1, 1), .p3 = VEC2(1, 0) }
|
||||
#define CenteredUnitSquareQuad (Quad) { .p0 = VEC2(-0.5f, -0.5f), .p1 = VEC2(0.5f, -0.5f), .p2 = VEC2(0.5f, 0.5f), .p3 = VEC2(-0.5f, 0.5f) }
|
||||
|
||||
Quad QuadFromRect(Rect rect);
|
||||
Quad QuadFromAabb(Aabb aabb);
|
||||
Quad QuadFromLine(Vec2 start, Vec2 end, f32 thickness);
|
||||
Quad QuadFromRay(Vec2 pos, Vec2 rel, f32 thickness);
|
||||
Quad ScaleQuad(Quad q, f32 s);
|
||||
Quad RoundQuad(Quad quad);
|
||||
Quad FloorQuad(Quad quad);
|
||||
|
||||
////////////////////////////////
|
||||
//~ Spring operations
|
||||
|
||||
SoftSpring MakeSpring(f32 hertz, f32 damping_ratio, f32 dt);
|
||||
|
||||
////////////////////////////////
|
||||
//~ Mat4x4 operations
|
||||
|
||||
Mat4x4 Mat4x4FromXform(Xform xf);
|
||||
Mat4x4 Mat4x4FromOrtho(f32 left, f32 right, f32 bottom, f32 top, f32 near_z, f32 far_z);
|
||||
Mat4x4 MulMat4x4(Mat4x4 m1, Mat4x4 m2);
|
||||
Mat4x4 ProjectMat4x4View(Xform view, f32 viewport_width, f32 viewport_height);
|
||||
@ -1,85 +0,0 @@
|
||||
////////////////////////////////
|
||||
//~ Win32 memory allocation
|
||||
|
||||
#if PlatformIsWindows
|
||||
|
||||
//- Reserve
|
||||
void *ReserveMemory(u64 size)
|
||||
{
|
||||
void *ptr = VirtualAlloc(0, size, MEM_RESERVE, PAGE_NOACCESS);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void ReleaseMemory(void *address)
|
||||
{
|
||||
VirtualFree(address, 0, MEM_RELEASE);
|
||||
}
|
||||
|
||||
//- Commit
|
||||
void *CommitMemory(void *address, u64 size)
|
||||
{
|
||||
void *ptr = VirtualAlloc(address, size, MEM_COMMIT, PAGE_READWRITE);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void DecommitMemory(void *address, u64 size)
|
||||
{
|
||||
VirtualFree(address, size, MEM_DECOMMIT);
|
||||
}
|
||||
|
||||
//- Protect
|
||||
void SetMemoryReadonly(void *address, u64 size)
|
||||
{
|
||||
DWORD old;
|
||||
VirtualProtect(address, size, PAGE_READONLY, &old);
|
||||
}
|
||||
|
||||
void SetMemoryReadWrite(void *address, u64 size)
|
||||
{
|
||||
DWORD old;
|
||||
VirtualProtect(address, size, PAGE_READWRITE, &old);
|
||||
}
|
||||
|
||||
#else
|
||||
# error Memory allocation not implemented for this platform
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ Memory operations
|
||||
|
||||
void *CopyBytes(void *dst, void *src, u64 count)
|
||||
{
|
||||
char *dst_pchar = dst;
|
||||
char *src_pchar = src;
|
||||
for (u64 i = 0; i < count; ++i)
|
||||
{
|
||||
dst_pchar[i] = src_pchar[i];
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
void *SetBytes(void *dst, u8 c, u64 count)
|
||||
{
|
||||
char *dst_pchar = dst;
|
||||
for (u64 i = 0; i < count; ++i)
|
||||
{
|
||||
dst_pchar[i] = (char)c;
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
i32 CmpBytes(void *p1, void *p2, u64 count)
|
||||
{
|
||||
i32 result = 0;
|
||||
char *p1_pchar = p1;
|
||||
char *p2_pchar = p2;
|
||||
for (u64 i = 0; i < count; ++i)
|
||||
{
|
||||
result = p1_pchar[i] - p2_pchar[i];
|
||||
if (result != 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -1,29 +0,0 @@
|
||||
////////////////////////////////
|
||||
//~ Memory allocation
|
||||
|
||||
//- Reserve
|
||||
void *ReserveMemory(u64 size);
|
||||
void ReleaseMemory(void *address);
|
||||
|
||||
//- Commit
|
||||
void *CommitMemory(void *address, u64 size);
|
||||
void DecommitMemory(void *address, u64 size);
|
||||
|
||||
//- Protect
|
||||
void SetMemoryReadonly(void *address, u64 size);
|
||||
void SetMemoryReadWrite(void *address, u64 size);
|
||||
|
||||
////////////////////////////////
|
||||
//~ Memory operations
|
||||
|
||||
//- Wrappers
|
||||
#define ZeroStruct(ptr) ZeroBytes((ptr), sizeof(*(ptr)))
|
||||
#define ZeroArray(a) Assert(IsArray(a)); ZeroBytes((a), sizeof((a)))
|
||||
#define CopyStruct(ptr_dst, ptr_src) CopyBytes((ptr_dst), (ptr_src), sizeof(*(ptr_dst)))
|
||||
#define EqStruct(p1, p2) EqBytes((p1), (p2), sizeof(*p1))
|
||||
#define ZeroBytes(ptr, count) SetBytes((ptr), 0, (count))
|
||||
#define EqBytes(p1, p2, n) (CmpBytes((p1), (p2), (n)) == 0)
|
||||
|
||||
void *CopyBytes(void *dst, void *src, u64 count);
|
||||
void *SetBytes(void *dst, u8 c, u64 count);
|
||||
i32 CmpBytes(void *p1, void *p2, u64 count);
|
||||
@ -1,43 +0,0 @@
|
||||
////////////////////////////////
|
||||
//~ Stateful randomness
|
||||
|
||||
u64 RandU64FromState(RandState *state)
|
||||
{
|
||||
u64 seed = state->seed;
|
||||
if (seed == 0)
|
||||
{
|
||||
TrueRand(StringFromStruct(&seed));
|
||||
state->seed = seed;
|
||||
}
|
||||
return seed ^ RandU64FromSeed(++state->counter);
|
||||
}
|
||||
|
||||
f64 RandF64FromState(RandState *state, f64 range_start, f64 range_end)
|
||||
{
|
||||
return range_start + (range_end - range_start) * ((f64)(RandU64FromState(state) % RandMaxF64) / (f64)RandMaxF64);
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ Seeded randomness
|
||||
|
||||
/* Based on Jon Maiga's "mx3"
|
||||
* https://jonkagstrom.com/mx3/mx3_rev2.html
|
||||
*/
|
||||
u64 RandU64FromSeed(u64 seed)
|
||||
{
|
||||
seed = (seed ^ (seed >> 32)) * 0xbea225f9eb34556d;
|
||||
seed = (seed ^ (seed >> 29)) * 0xbea225f9eb34556d;
|
||||
seed = (seed ^ (seed >> 32)) * 0xbea225f9eb34556d;
|
||||
seed = (seed ^ (seed >> 29));
|
||||
return seed;
|
||||
}
|
||||
|
||||
u64 RandU64FromSeeds(u64 seed_a, u64 seed_b)
|
||||
{
|
||||
return RandU64FromSeed((seed_a * 3) + seed_b);
|
||||
}
|
||||
|
||||
f64 RandF64FromSeed(u64 seed, f64 range_start, f64 range_end)
|
||||
{
|
||||
return range_start + (range_end - range_start) * ((f64)(RandU64FromSeed(seed) % RandMaxF64) / (f64)RandMaxF64);
|
||||
}
|
||||
@ -1,23 +0,0 @@
|
||||
////////////////////////////////
|
||||
//~ Rand types
|
||||
|
||||
Struct(RandState)
|
||||
{
|
||||
u64 seed; /* If a state's seed == 0 upon a call to a related function, it will be initialized using platform's true rng source */
|
||||
u64 counter;
|
||||
};
|
||||
|
||||
/* TODO: Use a value that gives good precision when dividing into range 0 -> 1 */
|
||||
#define RandMaxF64 U64Max
|
||||
|
||||
////////////////////////////////
|
||||
//~ Rand operations
|
||||
|
||||
//- Stateful randomness
|
||||
u64 RandU64FromState(RandState *state);
|
||||
f64 RandF64FromState(RandState *state, f64 range_start, f64 range_end);
|
||||
|
||||
//- Seeded randomness
|
||||
u64 RandU64FromSeed(u64 seed);
|
||||
u64 RandU64FromSeeds(u64 seed_a, u64 seed_b);
|
||||
f64 RandF64FromSeed(u64 seed, f64 range_start, f64 range_end);
|
||||
@ -1,919 +0,0 @@
|
||||
////////////////////////////////
|
||||
//~ Conversion helpers
|
||||
|
||||
//- Char conversion
|
||||
|
||||
String StringFromChar(Arena *arena, char c)
|
||||
{
|
||||
u8 *dst = PushStructNoZero(arena, u8);
|
||||
*dst = c;
|
||||
return (String)
|
||||
{
|
||||
.len = 1,
|
||||
.text = dst
|
||||
};
|
||||
}
|
||||
|
||||
//- Unsigned int conversion
|
||||
|
||||
String StringFromU64(Arena *arena, u64 n, u64 base, u64 zfill)
|
||||
{
|
||||
/* Base too large */
|
||||
Assert(base <= (countof(IntChars) - 1));
|
||||
|
||||
TempArena scratch = BeginScratch(arena);
|
||||
|
||||
/* Build backwards text starting from least significant digit */
|
||||
u64 len = 0;
|
||||
u8 *backwards_text = PushDry(scratch.arena, u8);
|
||||
do
|
||||
{
|
||||
StringFromChar(scratch.arena, IntChars[n % base]);
|
||||
++len;
|
||||
n /= base;
|
||||
} while (n > 0);
|
||||
|
||||
while (len < zfill)
|
||||
{
|
||||
StringFromChar(scratch.arena, '0');
|
||||
++len;
|
||||
}
|
||||
|
||||
/* Reverse text into final string */
|
||||
u8 *final_text = PushStructsNoZero(arena, u8, len);
|
||||
for (u64 i = 0; i < len; ++i)
|
||||
{
|
||||
final_text[i] = backwards_text[len - i - 1];
|
||||
}
|
||||
|
||||
EndScratch(scratch);
|
||||
|
||||
return (String)
|
||||
{
|
||||
.len = len,
|
||||
.text = final_text
|
||||
};
|
||||
}
|
||||
|
||||
//- Signed int conversion
|
||||
|
||||
String StringFromI64(Arena *arena, i64 n, u64 base, u64 zfill)
|
||||
{
|
||||
u8 *final_text = PushDry(arena, u8);
|
||||
u8 len = 0;
|
||||
if (n < 0)
|
||||
{
|
||||
/* Push sign */
|
||||
StringFromChar(arena, '-');
|
||||
len = 1;
|
||||
n = -n;
|
||||
}
|
||||
/* Push unsigned number */
|
||||
String uint_str = StringFromU64(arena, n, base, zfill);
|
||||
return (String)
|
||||
{
|
||||
.len = len + uint_str.len,
|
||||
.text = final_text
|
||||
};
|
||||
}
|
||||
|
||||
//- Pointer conversion
|
||||
|
||||
String StringFromPtr(Arena *arena, void *ptr)
|
||||
{
|
||||
String prepend = PushString(arena, Lit("0x"));
|
||||
String uint_str = StringFromU64(arena, (u64)ptr, 16, sizeof(ptr));
|
||||
return (String)
|
||||
{
|
||||
.len = prepend.len + uint_str.len,
|
||||
.text = prepend.text
|
||||
};
|
||||
}
|
||||
|
||||
//- Floating point conversion
|
||||
|
||||
String StringFromF64(Arena *arena, f64 f, u32 precision)
|
||||
{
|
||||
TempArena scratch = BeginScratch(arena);
|
||||
u8 *final_text = PushDry(arena, u8);
|
||||
u64 final_len = 0;
|
||||
|
||||
if (IsF32Nan(f))
|
||||
{
|
||||
final_len += PushString(arena, Lit("NaN")).len;
|
||||
}
|
||||
else if (f == F64Infinity)
|
||||
{
|
||||
final_len += PushString(arena, Lit("inf")).len;
|
||||
}
|
||||
else if (f == -F64Infinity)
|
||||
{
|
||||
final_len += PushString(arena, Lit("-inf")).len;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (f < 0)
|
||||
{
|
||||
StringFromChar(arena, '-');
|
||||
f = -f;
|
||||
++final_len;
|
||||
}
|
||||
|
||||
/* Add one half of next precision level to round up */
|
||||
f += 0.5 / (f64)PowU64(10, (u8)precision);
|
||||
|
||||
f64 part_whole = TruncF64(f);
|
||||
f64 part_decimal = f - part_whole;
|
||||
|
||||
/* Print whole part */
|
||||
{
|
||||
/* Build backwards text starting from least significant digit */
|
||||
u8 *backwards_text = PushDry(scratch.arena, u8);
|
||||
u64 backwards_text_len = 0;
|
||||
do
|
||||
{
|
||||
u64 digit = (u64)RoundF64ToI64(ModF64(part_whole, 10.0));
|
||||
StringFromChar(scratch.arena, IntChars[digit % 10]);
|
||||
++backwards_text_len;
|
||||
part_whole = TruncF64(part_whole / 10.0);
|
||||
} while (part_whole > 0);
|
||||
|
||||
/* Reverse text into final string */
|
||||
PushStructsNoZero(arena, u8, backwards_text_len);
|
||||
for (u64 i = backwards_text_len; i-- > 0;)
|
||||
{
|
||||
final_text[final_len++] = backwards_text[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* Print decimal part */
|
||||
if (precision > 0)
|
||||
{
|
||||
StringFromChar(arena, '.');
|
||||
for (u64 i = 0; i < precision; ++i)
|
||||
{
|
||||
part_decimal *= 10.0;
|
||||
u64 digit = (u64)part_decimal;
|
||||
part_decimal -= digit;
|
||||
StringFromChar(arena, IntChars[digit % 10]);
|
||||
}
|
||||
final_len += (u64)precision + 1;
|
||||
}
|
||||
}
|
||||
|
||||
EndScratch(scratch);
|
||||
|
||||
return (String)
|
||||
{
|
||||
.len = final_len,
|
||||
.text = final_text
|
||||
};
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ String helpers
|
||||
|
||||
//- Copy
|
||||
|
||||
String PushString(Arena *arena, String src)
|
||||
{
|
||||
String str = {
|
||||
.len = src.len,
|
||||
.text = PushStructsNoZero(arena, u8, src.len)
|
||||
};
|
||||
CopyBytes(str.text, src.text, src.len);
|
||||
return str;
|
||||
}
|
||||
|
||||
String PushStringToBuff(String dst, String src)
|
||||
{
|
||||
String result = ZI;
|
||||
result.len = MinU64(dst.len, src.len);
|
||||
result.text = dst.text;
|
||||
CopyBytes(result.text, src.text, result.len);
|
||||
return result;
|
||||
}
|
||||
|
||||
//- Repeat
|
||||
|
||||
String RepeatString(Arena *arena, String src, u64 count)
|
||||
{
|
||||
u64 final_len = src.len * count;
|
||||
u8 *final_text = PushStructsNoZero(arena, u8, final_len);
|
||||
for (u64 i = 0; i < count; ++i)
|
||||
{
|
||||
CopyBytes(final_text + (src.len * i), src.text, src.len);
|
||||
}
|
||||
return (String)
|
||||
{
|
||||
.text = final_text,
|
||||
.len = final_len
|
||||
};
|
||||
}
|
||||
|
||||
//- Concatenate
|
||||
|
||||
String CatString(Arena *arena, String str1, String str2)
|
||||
{
|
||||
String new_str = ZI;
|
||||
new_str.len = str1.len + str2.len;
|
||||
new_str.text = PushStructsNoZero(arena, u8, new_str.len);
|
||||
CopyBytes(new_str.text, str1.text, str1.len);
|
||||
CopyBytes(new_str.text + str1.len, str2.text, str2.len);
|
||||
return new_str;
|
||||
}
|
||||
|
||||
//- Split
|
||||
|
||||
/* `arena` is where pieces will be allocated. These strings point
|
||||
* into the existing string and do not allocate any new text. */
|
||||
StringArray SplitString(Arena *arena, String str, String delim)
|
||||
{
|
||||
StringArray pieces = ZI;
|
||||
pieces.strings = PushDry(arena, String);
|
||||
i64 piece_start = 0;
|
||||
for (i64 i = 0; i < (i64)str.len - (i64)delim.len; ++i)
|
||||
{
|
||||
String cmp = ZI;
|
||||
cmp.text = &str.text[i];
|
||||
cmp.len = MinI64(str.len - i, delim.len);
|
||||
|
||||
b32 is_delimiter = EqString(cmp, delim);
|
||||
if (is_delimiter)
|
||||
{
|
||||
String piece = ZI;
|
||||
piece.text = &str.text[piece_start];
|
||||
piece.len = i - piece_start;
|
||||
i += delim.len;
|
||||
piece_start = i;
|
||||
if (piece.len > 0)
|
||||
{
|
||||
*PushStructNoZero(arena, String) = piece;
|
||||
++pieces.count;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (piece_start < (i64)str.len)
|
||||
{
|
||||
String piece = ZI;
|
||||
piece.text = &str.text[piece_start];
|
||||
piece.len = str.len - piece_start;
|
||||
*PushStructNoZero(arena, String) = piece;
|
||||
++pieces.count;
|
||||
}
|
||||
return pieces;
|
||||
}
|
||||
|
||||
//- Indent
|
||||
|
||||
/* NOTE: Really slow */
|
||||
String IndentString(Arena *arena, String str, u32 indent)
|
||||
{
|
||||
TempArena scratch = BeginScratch(arena);
|
||||
|
||||
u64 final_len = 0;
|
||||
u8 *final_text = PushDry(arena, u8);
|
||||
|
||||
StringArray split = SplitString(scratch.arena, str, Lit("\n"));
|
||||
for (u64 i = 0; i < split.count; ++i)
|
||||
{
|
||||
String piece = split.strings[i];
|
||||
for (u32 j = 0; j < indent; ++j)
|
||||
{
|
||||
StringFromChar(arena, ' ');
|
||||
++final_len;
|
||||
}
|
||||
PushString(arena, piece);
|
||||
final_len += piece.len;
|
||||
if (i < split.count - 1)
|
||||
{
|
||||
StringFromChar(arena, '\n');
|
||||
++final_len;
|
||||
}
|
||||
}
|
||||
|
||||
EndScratch(scratch);
|
||||
|
||||
return (String)
|
||||
{
|
||||
.len = final_len,
|
||||
.text = final_text
|
||||
};
|
||||
}
|
||||
|
||||
//- Lower
|
||||
|
||||
String LowerString(Arena *arena, String str)
|
||||
{
|
||||
String result = ZI;
|
||||
result.text = PushStructsNoZero(arena, u8, str.len);
|
||||
result.len = str.len;
|
||||
|
||||
for (u64 i = 0; i < str.len; ++i)
|
||||
{
|
||||
u8 c = str.text[i];
|
||||
if (65 <= c && c <= 90)
|
||||
{
|
||||
c += 32;
|
||||
}
|
||||
result.text[i] = c;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//- Compare
|
||||
|
||||
b32 EqString(String str1, String str2)
|
||||
{
|
||||
b32 eq = 1;
|
||||
if (str1.len == str2.len)
|
||||
{
|
||||
for (u64 i = 0; i < str1.len; ++i)
|
||||
{
|
||||
if (str1.text[i] != str2.text[i])
|
||||
{
|
||||
eq = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
eq = 0;
|
||||
}
|
||||
return eq;
|
||||
}
|
||||
|
||||
//- Match
|
||||
|
||||
b32 StringContains(String str, String substring)
|
||||
{
|
||||
if (substring.len > str.len)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (u64 i = 0; i <= str.len - substring.len; ++i)
|
||||
{
|
||||
b32 match = 1;
|
||||
for (u64 j = 0; j < substring.len; ++j)
|
||||
{
|
||||
if (str.text[i + j] != substring.text[j])
|
||||
{
|
||||
match = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (match)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
b32 StringStartsWith(String str, String substring)
|
||||
{
|
||||
if (str.len >= substring.len)
|
||||
{
|
||||
for (u64 i = 0; i < substring.len; ++i)
|
||||
{
|
||||
if (str.text[i] != substring.text[i])
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
b32 StringEndsWith(String str, String substring)
|
||||
{
|
||||
if (str.len >= substring.len)
|
||||
{
|
||||
u64 start = str.len - substring.len;
|
||||
for (u64 i = 0; i < substring.len; ++i)
|
||||
{
|
||||
if (str.text[start + i] != substring.text[i])
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ String list helpers
|
||||
|
||||
StringListNode *PushStringToList(Arena *arena, StringList *l, String s)
|
||||
{
|
||||
StringListNode *n = PushStruct(arena, StringListNode);
|
||||
n->s = s;
|
||||
n->prev = l->last;
|
||||
if (l->last)
|
||||
{
|
||||
l->last->next = n;
|
||||
}
|
||||
else
|
||||
{
|
||||
l->first = n;
|
||||
}
|
||||
l->last = n;
|
||||
++l->count;
|
||||
return n;
|
||||
}
|
||||
|
||||
String StringFromList(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;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ Trimming helpers
|
||||
|
||||
String TrimLeft(String s, String pattern)
|
||||
{
|
||||
String result = s;
|
||||
while (StringStartsWith(result, pattern))
|
||||
{
|
||||
result.text += pattern.len;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
String TrimRight(String s, String pattern)
|
||||
{
|
||||
String result = s;
|
||||
while (StringEndsWith(result, pattern))
|
||||
{
|
||||
result.len -= pattern.len;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
String Trim(String s, String pattern)
|
||||
{
|
||||
return TrimLeft(TrimRight(s, pattern), pattern);
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ Formatting
|
||||
|
||||
/* String formatting only has one format specifier: "%F". All specifier info is
|
||||
* included in the arguments (instead of w/ the specifier like in printf).
|
||||
*
|
||||
* Example:
|
||||
* StringFormat(arena, Lit("Hello there %F"), FmtString(Lit("George")))
|
||||
*
|
||||
* NOTE: FmtEnd must be passed as the last arg in the va_list (This is
|
||||
* done automatically by the `StringFormat` macro).
|
||||
*
|
||||
* Format arguments:
|
||||
* FmtChar: Format a single u8 character
|
||||
* FmtString: Format a `string` struct
|
||||
* FmtUint: Format a u64
|
||||
* FmtSint: Format an i64
|
||||
* FmtFloat: Format an f64 with DefaultFmtPrecision
|
||||
* FmtFloatP: Format an f64 with specified precision
|
||||
* FmtHex: Format a u64 in hexadecimal notation
|
||||
* FmtPtr: Format a pointer in hexadecimal notation prefixed by "0x"
|
||||
*
|
||||
* FmtEnd (internal): Denote the end of the va_list
|
||||
*
|
||||
* TODO:
|
||||
* %n equivalent? (nothing)
|
||||
* %e/%E equivalent? (scientific notation of floats)
|
||||
* %o equivalent? (octal representation)
|
||||
*/
|
||||
String StringFormatV(Arena *arena, String fmt, va_list args)
|
||||
{
|
||||
__prof;
|
||||
|
||||
u64 final_len = 0;
|
||||
u8 *final_text = PushDry(arena, u8);
|
||||
|
||||
u8 *end = fmt.text + fmt.len;
|
||||
b32 no_more_args = 0;
|
||||
for (u8 *c = fmt.text; c < end; ++c)
|
||||
{
|
||||
u8 *next = ((c + 1) < end) ? (c + 1) : (u8 *)"\0";
|
||||
|
||||
/* Escape '%%' */
|
||||
b32 escape = !no_more_args && *c == '%' && *next == '%';
|
||||
if (escape)
|
||||
{
|
||||
/* Skip the escape '%' char from parsing */
|
||||
++c;
|
||||
}
|
||||
|
||||
if (!no_more_args && !escape && *c == '%' && *next == 'F')
|
||||
{
|
||||
String parsed_str = ZI;
|
||||
/* Detect arg type and parse to string */
|
||||
FmtArg arg = va_arg(args, FmtArg);
|
||||
switch (arg.kind)
|
||||
{
|
||||
case FmtKind_Char:
|
||||
{
|
||||
parsed_str = StringFromChar(arena, arg.value.c);
|
||||
} break;
|
||||
|
||||
case FmtKind_String:
|
||||
{
|
||||
parsed_str = PushString(arena, arg.value.string);
|
||||
} break;
|
||||
|
||||
case FmtKind_Uint:
|
||||
{
|
||||
parsed_str = StringFromU64(arena, arg.value.uint, 10, arg.zfill);
|
||||
} break;
|
||||
|
||||
case FmtKind_Sint:
|
||||
{
|
||||
parsed_str = StringFromI64(arena, arg.value.sint, 10, arg.zfill);
|
||||
} break;
|
||||
|
||||
case FmtKind_Hex:
|
||||
{
|
||||
parsed_str = StringFromU64(arena, arg.value.sint, 16, arg.zfill);
|
||||
} break;
|
||||
|
||||
case FmtKind_Ptr:
|
||||
{
|
||||
parsed_str = StringFromPtr(arena, arg.value.ptr);
|
||||
} break;
|
||||
|
||||
case FmtKind_Float:
|
||||
{
|
||||
parsed_str = StringFromF64(arena, arg.value.f, arg.precision);
|
||||
} break;
|
||||
|
||||
case FmtKind_End:
|
||||
{
|
||||
/* Unexpected end. Not enough FMT args passed to function. */
|
||||
Assert(0);
|
||||
parsed_str = PushString(arena, Lit("<?>"));
|
||||
no_more_args = 1;
|
||||
} break;
|
||||
|
||||
default:
|
||||
{
|
||||
/* Unknown format type */
|
||||
Assert(0);
|
||||
parsed_str = PushString(arena, Lit("<?>"));
|
||||
no_more_args = 1;
|
||||
} break;
|
||||
}
|
||||
/* Update final string len / start */
|
||||
final_len += parsed_str.len;
|
||||
/* Skip 'F' from parsing */
|
||||
++c;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Parse character normally */
|
||||
StringFromChar(arena, *c);
|
||||
++final_len;
|
||||
}
|
||||
}
|
||||
|
||||
#if RtcIsEnabled
|
||||
if (!no_more_args)
|
||||
{
|
||||
FmtArg last_arg = va_arg(args, FmtArg);
|
||||
/* End arg not reached. Too many FMT values passed to function. */
|
||||
Assert(last_arg.kind == FmtKind_End);
|
||||
}
|
||||
#endif
|
||||
|
||||
return (String)
|
||||
{
|
||||
.len = final_len,
|
||||
.text = final_text
|
||||
};
|
||||
}
|
||||
|
||||
String StringFormat_(Arena *arena, String fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
String new_str = StringFormatV(arena, fmt, args);
|
||||
va_end(args);
|
||||
return new_str;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ Unicode
|
||||
|
||||
//- Codepoint iteration
|
||||
|
||||
CodepointIter BeginCodepointIter(String str)
|
||||
{
|
||||
return (CodepointIter)
|
||||
{
|
||||
.src = str
|
||||
};
|
||||
}
|
||||
|
||||
/* Returns 0 if done iterating */
|
||||
b32 AdvanceCodepointIter(CodepointIter *iter)
|
||||
{
|
||||
if (iter->pos < iter->src.len)
|
||||
{
|
||||
String str_remaining = { .len = (iter->src.len - iter->pos), .text = iter->src.text + iter->pos };
|
||||
Utf8DecodeResult decoded = DecodeUtf8(str_remaining);
|
||||
iter->pos += decoded.advance8;
|
||||
iter->codepoint = decoded.codepoint;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void EndCodepointIter(CodepointIter *iter)
|
||||
{
|
||||
/* Do nothing */
|
||||
LAX iter;
|
||||
}
|
||||
|
||||
//- String decode
|
||||
|
||||
/* utf8 <- utf16 */
|
||||
String StringFromString16(Arena *arena, String16 str16)
|
||||
{
|
||||
String result = {
|
||||
.len = 0,
|
||||
.text = PushDry(arena, u8)
|
||||
};
|
||||
|
||||
u64 pos16 = 0;
|
||||
while (pos16 < str16.len)
|
||||
{
|
||||
String16 str16_remaining = { .len = (str16.len - pos16), .text = str16.text + pos16 };
|
||||
Utf16DecodeResult decoded = DecodeUtf16(str16_remaining);
|
||||
Utf8EncodeResult encoded = EncodeUtf8(decoded.codepoint);
|
||||
|
||||
u8 *dst = PushStructsNoZero(arena, u8, encoded.count8);
|
||||
CopyBytes(dst, encoded.chars8, encoded.count8);
|
||||
|
||||
pos16 += decoded.advance16;
|
||||
result.len += encoded.count8;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* utf8 <- utf32 */
|
||||
String StringFromString32(Arena *arena, String32 str32)
|
||||
{
|
||||
String result = {
|
||||
.len = 0,
|
||||
.text = PushDry(arena, u8)
|
||||
};
|
||||
|
||||
u64 pos32 = 0;
|
||||
while (pos32 < str32.len)
|
||||
{
|
||||
String32 str32_remaining = { .len = (str32.len - pos32), .text = str32.text + pos32 };
|
||||
Utf32DecodeResult decoded = DecodeUtf32(str32_remaining);
|
||||
Utf8EncodeResult encoded = EncodeUtf8(decoded.codepoint);
|
||||
|
||||
u8 *dst = PushStructsNoZero(arena, u8, encoded.count8);
|
||||
CopyBytes(dst, &encoded.chars8, encoded.count8);
|
||||
|
||||
pos32 += 1;
|
||||
result.len += encoded.count8;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//- String encode
|
||||
|
||||
/* utf16 <- utf8 */
|
||||
String16 String16FromString(Arena *arena, String str8)
|
||||
{
|
||||
String16 result = {
|
||||
.len = 0,
|
||||
.text = PushDry(arena, u16)
|
||||
};
|
||||
|
||||
u64 pos8 = 0;
|
||||
while (pos8 < str8.len)
|
||||
{
|
||||
String str8_remaining = { .len = (str8.len - pos8), .text = str8.text + pos8 };
|
||||
Utf8DecodeResult decoded = DecodeUtf8(str8_remaining);
|
||||
Utf16EncodeResult encoded = EncodeUtf16(decoded.codepoint);
|
||||
|
||||
u16 *dst = PushStructsNoZero(arena, u16, encoded.count16);
|
||||
CopyBytes(dst, encoded.chars16, (encoded.count16 << 1));
|
||||
|
||||
pos8 += decoded.advance8;
|
||||
result.len += encoded.count16;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* utf32 <- utf8 */
|
||||
String32 String32FromString(Arena *arena, String str8)
|
||||
{
|
||||
String32 result = {
|
||||
.len = 0,
|
||||
.text = PushDry(arena, u32)
|
||||
};
|
||||
|
||||
u64 pos8 = 0;
|
||||
while (pos8 < str8.len)
|
||||
{
|
||||
String str8_remaining = { .len = (str8.len - pos8), .text = str8.text + pos8 };
|
||||
Utf8DecodeResult decoded = DecodeUtf8(str8_remaining);
|
||||
Utf32EncodeResult encoded = EncodeUtf32(decoded.codepoint);
|
||||
|
||||
u32 *dst = PushStructNoZero(arena, u32);
|
||||
*dst = encoded.chars32;
|
||||
|
||||
pos8 += decoded.advance8;
|
||||
result.len += 1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ Legacy null-terminated C string operations
|
||||
|
||||
//- Narrow C strings
|
||||
|
||||
u64 CstrLenNoLimit(char *cstr)
|
||||
{
|
||||
char *end = cstr;
|
||||
if (cstr)
|
||||
{
|
||||
while (*end)
|
||||
{
|
||||
++end;
|
||||
}
|
||||
}
|
||||
return end - cstr;
|
||||
}
|
||||
|
||||
u64 CstrLen(char *cstr, u64 limit)
|
||||
{
|
||||
char *end = cstr;
|
||||
if (cstr)
|
||||
{
|
||||
for (u64 i = 0; i < limit; ++i)
|
||||
{
|
||||
if (*end)
|
||||
{
|
||||
++end;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return end - cstr;
|
||||
}
|
||||
|
||||
char *CstrFromString(Arena *arena, String src)
|
||||
{
|
||||
u8 *text = PushStructsNoZero(arena, u8, src.len + 1);
|
||||
CopyBytes(text, src.text, src.len);
|
||||
text[src.len] = 0;
|
||||
return (char *)text;
|
||||
}
|
||||
|
||||
char *CstrFromStringToBuff(String dst_buff, String src)
|
||||
{
|
||||
if (dst_buff.len > 0)
|
||||
{
|
||||
u64 len = MinU64(src.len, dst_buff.len - 1);
|
||||
CopyBytes(dst_buff.text, src.text, len);
|
||||
dst_buff.text[len] = 0;
|
||||
}
|
||||
return (char *)dst_buff.text;
|
||||
}
|
||||
|
||||
String StringFromCstrNoLimit(char *cstr)
|
||||
{
|
||||
u64 len = CstrLenNoLimit(cstr);
|
||||
return (String)
|
||||
{
|
||||
.len = len,
|
||||
.text = (u8 *)cstr
|
||||
};
|
||||
}
|
||||
|
||||
String StringFromCstr(char *cstr, u64 limit)
|
||||
{
|
||||
u64 len = CstrLen(cstr, limit);
|
||||
return (String)
|
||||
{
|
||||
.text = (u8 *)cstr,
|
||||
.len = len
|
||||
};
|
||||
}
|
||||
|
||||
//- Wide C strings
|
||||
|
||||
u64 WstrLenNoLimit(wchar_t *wstr)
|
||||
{
|
||||
wchar_t *end = wstr;
|
||||
if (end)
|
||||
{
|
||||
while (*end)
|
||||
{
|
||||
++end;
|
||||
}
|
||||
}
|
||||
return end - wstr;
|
||||
}
|
||||
|
||||
u64 WstrLen(wchar_t *wstr, u64 limit)
|
||||
{
|
||||
wchar_t *end = wstr;
|
||||
if (wstr)
|
||||
{
|
||||
for (u64 i = 0; i < limit; ++i)
|
||||
{
|
||||
if (*end)
|
||||
{
|
||||
++end;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return end - wstr;
|
||||
}
|
||||
|
||||
wchar_t *WstrFromString(Arena *arena, String src)
|
||||
{
|
||||
String16 str16 = String16FromString(arena, src);
|
||||
*PushStructNoZero(arena, u16) = 0;
|
||||
return (wchar_t *)str16.text;
|
||||
}
|
||||
|
||||
wchar_t *WstrFromString16(Arena *arena, String16 src)
|
||||
{
|
||||
u16 *text = PushStructsNoZero(arena, u16, src.len + 1);
|
||||
text[src.len] = 0;
|
||||
return (wchar_t *)text;
|
||||
}
|
||||
|
||||
String StringFromWstrNoLimit(Arena *arena, wchar_t *wstr)
|
||||
{
|
||||
String16 str16 = String16FromWstrNoLimit(wstr);
|
||||
return StringFromString16(arena, str16);
|
||||
}
|
||||
|
||||
String StringFromWstr(Arena *arena, wchar_t *wstr, u64 limit)
|
||||
{
|
||||
String16 str16 = String16FromWstr(wstr, limit);
|
||||
return StringFromString16(arena, str16);
|
||||
}
|
||||
|
||||
String16 String16FromWstrNoLimit(wchar_t *wstr)
|
||||
{
|
||||
u64 len = WstrLenNoLimit(wstr);
|
||||
return (String16)
|
||||
{
|
||||
.len = len,
|
||||
.text = (u16 *)wstr
|
||||
};
|
||||
}
|
||||
|
||||
String16 String16FromWstr(wchar_t *wstr, u64 limit)
|
||||
{
|
||||
u64 len = WstrLen(wstr, limit);
|
||||
return (String16)
|
||||
{
|
||||
.len = len,
|
||||
.text = (u16 *)wstr
|
||||
};
|
||||
}
|
||||
@ -1,169 +0,0 @@
|
||||
////////////////////////////////
|
||||
//~ String types
|
||||
|
||||
Struct(StringArray)
|
||||
{
|
||||
u64 count;
|
||||
String *strings;
|
||||
};
|
||||
|
||||
Struct(StringListNode)
|
||||
{
|
||||
String s;
|
||||
StringListNode *next;
|
||||
StringListNode *prev;
|
||||
};
|
||||
|
||||
Struct(StringList)
|
||||
{
|
||||
StringListNode *first;
|
||||
StringListNode *last;
|
||||
u64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ Formatting types
|
||||
|
||||
#define DefaultFmtPrecision 3
|
||||
#define IntChars ("0123456789abcdef")
|
||||
|
||||
Enum(FmtKind)
|
||||
{
|
||||
FmtKind_None,
|
||||
|
||||
/* Arbitrary magic numbers for argument validation */
|
||||
FmtKind_Char = 0x0f5281df,
|
||||
FmtKind_String = 0x0a5ffa9a,
|
||||
FmtKind_Uint = 0x0746f19b,
|
||||
FmtKind_Sint = 0x08603694,
|
||||
FmtKind_Hex = 0x0a3d0792,
|
||||
FmtKind_Ptr = 0x0c4519e4,
|
||||
FmtKind_Float = 0x04814143,
|
||||
|
||||
FmtKind_End = 0x0ecbc5ae
|
||||
};
|
||||
|
||||
Struct(FmtArg)
|
||||
{
|
||||
FmtKind kind;
|
||||
u32 precision;
|
||||
u32 zfill;
|
||||
union
|
||||
{
|
||||
u8 c;
|
||||
String string;
|
||||
u64 uint;
|
||||
i64 sint;
|
||||
void *ptr;
|
||||
f64 f;
|
||||
} value;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ Unicode types
|
||||
|
||||
Struct(CodepointIter)
|
||||
{
|
||||
u32 codepoint;
|
||||
|
||||
/* Internal */
|
||||
String src;
|
||||
u64 pos;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ Conversion helpers
|
||||
|
||||
String StringFromChar(Arena *arena, char c);
|
||||
String StringFromU64(Arena *arena, u64 n, u64 base, u64 zfill);
|
||||
String StringFromI64(Arena *arena, i64 n, u64 base, u64 zfill);
|
||||
String StringFromPtr(Arena *arena, void *ptr);
|
||||
String StringFromF64(Arena *arena, f64 f, u32 precision);
|
||||
|
||||
////////////////////////////////
|
||||
//~ String helpers
|
||||
|
||||
String PushString(Arena *arena, String src);
|
||||
String PushStringToBuff(String dst, String src);
|
||||
String RepeatString(Arena *arena, String src, u64 count);
|
||||
String CatString(Arena *arena, String str1, String str2);
|
||||
StringArray SplitString(Arena *arena, String str, String delim);
|
||||
String IndentString(Arena *arena, String str, u32 indent);
|
||||
String LowerString(Arena *arena, String str);
|
||||
b32 EqString(String str1, String str2);
|
||||
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 StringFromList(Arena *arena, StringList l, String separator);
|
||||
|
||||
////////////////////////////////
|
||||
//~ Trimming helpers
|
||||
|
||||
String TrimLeft(String s, String pattern);
|
||||
String TrimRight(String s, String pattern);
|
||||
String Trim(String s, String pattern);
|
||||
|
||||
////////////////////////////////
|
||||
//~ Formatting
|
||||
|
||||
//- Format arg helpers
|
||||
#define FmtChar(v) (FmtArg) {.kind = FmtKind_Char, .value.c = (v)}
|
||||
#define FmtString(v) (FmtArg) {.kind = FmtKind_String, .value.string = (v)}
|
||||
#define FmtUint(v) (FmtArg) {.kind = FmtKind_Uint, .value.uint = (v)}
|
||||
#define FmtUintZ(v, z) (FmtArg) {.kind = FmtKind_Uint, .value.uint = (v), .zfill = (z)}
|
||||
#define FmtSint(v) (FmtArg) {.kind = FmtKind_Sint, .value.sint = (v)}
|
||||
#define FmtHex(v) (FmtArg) {.kind = FmtKind_Hex, .value.uint = (v)}
|
||||
#define FmtPtr(v) (FmtArg) {.kind = FmtKind_Ptr, .value.ptr = (v)}
|
||||
#define FmtFloat(v) FmtFloatP(v, DefaultFmtPrecision)
|
||||
#define FmtFloatP(v, p) (FmtArg) {.kind = FmtKind_Float, .value.f = (v), .precision = (p)}
|
||||
#define FmtHandle(v) (FmtArg) {.kind = FmtKind_Handle, .value.handle.h64[0] = (v).idx, .value.handle.h64[1] = (v).gen}
|
||||
#define FmtUid(v) (FmtArg) {.kind = FmtKind_Uid, .value.uid = (v) }
|
||||
#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);
|
||||
|
||||
////////////////////////////////
|
||||
//~ Unicode operations
|
||||
|
||||
//- Iter
|
||||
CodepointIter BeginCodepointIter(String str);
|
||||
b32 AdvanceCodepointIter(CodepointIter *iter);
|
||||
void EndCodepointIter(CodepointIter *iter);
|
||||
|
||||
//- Decode string
|
||||
String StringFromString16(Arena *arena, String16 str16);
|
||||
String StringFromString32(Arena *arena, String32 str32);
|
||||
|
||||
//- Encode string
|
||||
String16 String16FromString(Arena *arena, String str8);
|
||||
String32 String32FromString(Arena *arena, String str8);
|
||||
|
||||
////////////////////////////////
|
||||
//~ Legacy null-terminated C string operations
|
||||
|
||||
//- Narrow strings
|
||||
u64 CstrLenNoLimit(char *cstr);
|
||||
u64 CstrLen(char *cstr, u64 limit);
|
||||
char *CstrFromString(Arena *arena, String src);
|
||||
char *CstrFromStringToBuff(String dest_buff, String src);
|
||||
String StringFromCstrNoLimit(char *cstr);
|
||||
String StringFromCstr(char *cstr, u64 limit);
|
||||
|
||||
//- Wide strings
|
||||
u64 WstrLenNoLimit(wchar_t *wstr);
|
||||
u64 WstrLen(wchar_t *wstr, u64 limit);
|
||||
wchar_t *WstrFromString(Arena *arena, String src);
|
||||
wchar_t *WstrFromString16(Arena *arena, String16 src);
|
||||
String StringFromWstrNoLimit(Arena *arena, wchar_t *wstr);
|
||||
String StringFromWstr(Arena *arena, wchar_t *wstr, u64 limit);
|
||||
String16 String16FromWstrNoLimit(wchar_t *wstr);
|
||||
String16 String16FromWstr(wchar_t *wstr, u64 limit);
|
||||
@ -1,245 +0,0 @@
|
||||
////////////////////////////////
|
||||
//~ Utf8
|
||||
|
||||
//- Decode
|
||||
|
||||
Utf8DecodeResult DecodeUtf8(String str)
|
||||
{
|
||||
LocalPersist const u8 lengths[32] = {
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,2,2,2,2,3,3,4,5
|
||||
};
|
||||
|
||||
Utf8DecodeResult result = ZI;
|
||||
u32 codepoint = U32Max;
|
||||
u32 advance = 0;
|
||||
if (str.len > 0)
|
||||
{
|
||||
u8 c0 = str.text[0];
|
||||
u8 utf8_len = lengths[c0 >> 3];
|
||||
|
||||
advance = 1;
|
||||
switch (utf8_len)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
codepoint = c0;
|
||||
} break;
|
||||
|
||||
case 2:
|
||||
{
|
||||
if (str.len >= 2)
|
||||
{
|
||||
u8 c1 = str.text[1];
|
||||
if (lengths[c1 >> 3] == 0)
|
||||
{
|
||||
codepoint = (c1 & 0x3F) << 0;
|
||||
codepoint |= (c0 & 0x1F) << 6;
|
||||
advance = 2;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case 3:
|
||||
{
|
||||
if (str.len >= 3)
|
||||
{
|
||||
u8 c1 = str.text[1];
|
||||
u8 c2 = str.text[2];
|
||||
if (lengths[c1 >> 3] == 0 &&
|
||||
lengths[c2 >> 3] == 0)
|
||||
{
|
||||
codepoint = (c2 & 0x3F) << 0;
|
||||
codepoint |= (c1 & 0x3F) << 6;
|
||||
codepoint |= (c0 & 0x0F) << 12;
|
||||
advance = 3;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case 4:
|
||||
{
|
||||
if (str.len >= 4)
|
||||
{
|
||||
u8 c1 = str.text[1];
|
||||
u8 c2 = str.text[2];
|
||||
u8 c3 = str.text[3];
|
||||
if (lengths[c1 >> 3] == 0 &&
|
||||
lengths[c2 >> 3] == 0 &&
|
||||
lengths[c3 >> 3] == 0)
|
||||
{
|
||||
codepoint = (c3 & 0x3F) << 0;
|
||||
codepoint |= (c2 & 0x3F) << 6;
|
||||
codepoint |= (c1 & 0x3F) << 12;
|
||||
codepoint |= (c0 & 0x07) << 16;
|
||||
advance = 3;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
result.advance8 = advance;
|
||||
result.codepoint = codepoint;
|
||||
return result;
|
||||
}
|
||||
|
||||
//- Encode
|
||||
|
||||
Utf8EncodeResult EncodeUtf8(u32 codepoint)
|
||||
{
|
||||
Utf8EncodeResult result = ZI;
|
||||
|
||||
if (codepoint <= 0x7F)
|
||||
{
|
||||
result.count8 = 1;
|
||||
result.chars8[0] = codepoint;
|
||||
}
|
||||
else if (codepoint <= 0x7FF)
|
||||
{
|
||||
result.count8 = 2;
|
||||
result.chars8[1] = 0x80 | ((codepoint >> 0) & 0x3F);
|
||||
result.chars8[0] = 0xC0 | ((codepoint >> 6) & 0x1F);
|
||||
}
|
||||
else if (codepoint <= 0xFFFF)
|
||||
{
|
||||
result.count8 = 3;
|
||||
result.chars8[2] = 0x80 | ((codepoint >> 0) & 0x3F);
|
||||
result.chars8[1] = 0x80 | ((codepoint >> 6) & 0x3F);
|
||||
result.chars8[0] = 0xE0 | ((codepoint >> 12) & 0x0F);
|
||||
}
|
||||
else if (codepoint <= 0x10FFFF)
|
||||
{
|
||||
result.count8 = 4;
|
||||
result.chars8[3] = 0x80 | ((codepoint >> 0) & 0x3F);
|
||||
result.chars8[2] = 0x80 | ((codepoint >> 6) & 0x3F);
|
||||
result.chars8[1] = 0x80 | ((codepoint >> 12) & 0x3F);
|
||||
result.chars8[0] = 0xF0 | ((codepoint >> 18) & 0x07);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Invalid codepoint */
|
||||
result.count8 = 1;
|
||||
result.chars8[0] = '?';
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ Utf16
|
||||
|
||||
//- Decode
|
||||
|
||||
Utf16DecodeResult DecodeUtf16(String16 str)
|
||||
{
|
||||
Utf16DecodeResult result = ZI;
|
||||
u32 codepoint = U32Max;
|
||||
u32 advance = 0;
|
||||
|
||||
if (str.len >= 1)
|
||||
{
|
||||
u16 c0 = str.text[0];
|
||||
codepoint = c0;
|
||||
advance = 1;
|
||||
if (str.len >= 2)
|
||||
{
|
||||
u16 c1 = str.text[1];
|
||||
if ((0xD800 <= c0 && c0 < 0xDC00) && (0xDC00 <= c1 && c1 < 0xE000))
|
||||
{
|
||||
codepoint = (c1 & 0x3FF) << 0;
|
||||
codepoint |= (c0 & 0x3FF) << 10;
|
||||
advance = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result.advance16 = advance;
|
||||
result.codepoint = codepoint;
|
||||
return result;
|
||||
}
|
||||
|
||||
//- Encode
|
||||
|
||||
Utf16EncodeResult EncodeUtf16(u32 codepoint)
|
||||
{
|
||||
Utf16EncodeResult result = ZI;
|
||||
|
||||
if (codepoint <= 0xFFFF)
|
||||
{
|
||||
result.count16 = 1;
|
||||
result.chars16[0] = codepoint;
|
||||
}
|
||||
else if (codepoint <= 0x10FFFF)
|
||||
{
|
||||
result.count16 = 2;
|
||||
result.chars16[1] = 0xDC00 | ((codepoint >> 0) & 0x3FF);
|
||||
result.chars16[0] = 0xD800 | ((codepoint >> 10) & 0x3FF);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Invalid codepoint */
|
||||
result.count16 = 1;
|
||||
result.chars16[0] = '?';
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//- Surrogate check
|
||||
|
||||
b32 IsUtf16HighSurrogate(u16 c)
|
||||
{
|
||||
return 0xD800 <= c && c < 0xDC00;
|
||||
}
|
||||
|
||||
b32 IsUtf16LowSurrogate(u16 c)
|
||||
{
|
||||
return 0xDC00 <= c && c < 0xE000;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ Utf32
|
||||
|
||||
//- Decode
|
||||
|
||||
Utf32DecodeResult DecodeUtf32(String32 str)
|
||||
{
|
||||
Utf32DecodeResult result = ZI;
|
||||
u32 codepoint = U32Max;
|
||||
u32 advance = 0;
|
||||
|
||||
if (str.len >= 1)
|
||||
{
|
||||
u32 c = str.text[0];
|
||||
advance = 1;
|
||||
if (c <= 0x10FFFF)
|
||||
{
|
||||
codepoint = c;
|
||||
}
|
||||
}
|
||||
|
||||
result.advance32 = advance;
|
||||
result.codepoint = codepoint;
|
||||
return result;
|
||||
}
|
||||
|
||||
//- Encode
|
||||
|
||||
Utf32EncodeResult EncodeUtf32(u32 codepoint)
|
||||
{
|
||||
Utf32EncodeResult result = ZI;
|
||||
|
||||
if (codepoint <= 0x10FFFF)
|
||||
{
|
||||
result.chars32 = codepoint;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Invalid codepoint */
|
||||
result.chars32 = '?';
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -1,64 +0,0 @@
|
||||
////////////////////////////////
|
||||
//~ Utf8 types
|
||||
|
||||
Struct(Utf8DecodeResult)
|
||||
{
|
||||
u32 advance8;
|
||||
u32 codepoint;
|
||||
};
|
||||
|
||||
Struct(Utf8EncodeResult)
|
||||
{
|
||||
u32 count8;
|
||||
u8 chars8[4];
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ Utf16 types
|
||||
|
||||
Struct(Utf16DecodeResult)
|
||||
{
|
||||
u32 advance16;
|
||||
u32 codepoint;
|
||||
};
|
||||
|
||||
Struct(Utf16EncodeResult)
|
||||
{
|
||||
u32 count16;
|
||||
u16 chars16[2];
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ Utf32 types
|
||||
|
||||
Struct(Utf32DecodeResult)
|
||||
{
|
||||
u32 advance32;
|
||||
u32 codepoint;
|
||||
};
|
||||
|
||||
Struct(Utf32EncodeResult)
|
||||
{
|
||||
u32 chars32;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ Utf8 operations
|
||||
|
||||
Utf8DecodeResult DecodeUtf8(String str);
|
||||
Utf8EncodeResult EncodeUtf8(u32 codepoint);
|
||||
|
||||
////////////////////////////////
|
||||
//~ Utf16 operations
|
||||
|
||||
Utf16DecodeResult DecodeUtf16(String16 str);
|
||||
Utf16EncodeResult EncodeUtf16(u32 codepoint);
|
||||
|
||||
b32 IsUtf16HighSurrogate(u16 c);
|
||||
b32 IsUtf16LowSurrogate(u16 c);
|
||||
|
||||
////////////////////////////////
|
||||
//~ Utf32 operations
|
||||
|
||||
Utf32DecodeResult DecodeUtf32(String32 str);
|
||||
Utf32EncodeResult EncodeUtf32(u32 codepoint);
|
||||
@ -1,296 +0,0 @@
|
||||
////////////////////////////////
|
||||
//~ 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;
|
||||
}
|
||||
@ -1,59 +0,0 @@
|
||||
W32_SharedState W32_shared_state = ZI;
|
||||
|
||||
////////////////////////////////
|
||||
//~ @hookdef OS startup hook
|
||||
|
||||
void StartupBase(void)
|
||||
{
|
||||
W32_SharedState *g = &W32_shared_state;
|
||||
g->tls_index = TlsAlloc();
|
||||
TlsSetValue(g->tls_index, 0);
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ @hookdef Core panic hooks
|
||||
|
||||
/* TODO: Remove stdio & printf */
|
||||
#include <stdio.h>
|
||||
|
||||
b32 Panic(String msg)
|
||||
{
|
||||
char msg_cstr[4096];
|
||||
CstrFromStringToBuff(StringFromArray(msg_cstr), msg);
|
||||
{
|
||||
u32 mb_flags = MB_SETFOREGROUND | MB_ICONERROR;
|
||||
MessageBoxExA(0, msg_cstr, "Fatal error", mb_flags, 0);
|
||||
}
|
||||
printf(msg_cstr);
|
||||
fflush(stdout);
|
||||
if ((1)) /* Supress unreachable code warning */
|
||||
{
|
||||
ExitProcess(1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ @hookdef Debugger hooks
|
||||
|
||||
b32 IsRunningInDebugger(void)
|
||||
{
|
||||
return IsDebuggerPresent();
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ @hookdef Thread hooks
|
||||
|
||||
i16 ThreadId(void)
|
||||
{
|
||||
W32_SharedState *g = &W32_shared_state;
|
||||
return (i16)(i64)TlsGetValue(g->tls_index);
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ @hookdef Randomness hooks
|
||||
|
||||
void TrueRand(String buffer)
|
||||
{
|
||||
BCryptGenRandom(BCRYPT_RNG_ALG_HANDLE, (u8 *)buffer.text, buffer.len, 0);
|
||||
}
|
||||
@ -1,21 +0,0 @@
|
||||
////////////////////////////////
|
||||
//~ Win32 libs
|
||||
|
||||
#ifndef BCRYPT_RNG_ALG_HANDLE
|
||||
#define BCRYPT_RNG_ALG_HANDLE ((void *)0x00000081)
|
||||
u32 BCryptGenRandom(void *algorithm, u8 *buffer, u32 buffer_size, u32 flags);
|
||||
#endif
|
||||
|
||||
#pragma comment(lib, "kernel32")
|
||||
#pragma comment(lib, "user32")
|
||||
#pragma comment(lib, "bcrypt")
|
||||
|
||||
////////////////////////////////
|
||||
//~ Shared state
|
||||
|
||||
Struct(W32_SharedState)
|
||||
{
|
||||
DWORD tls_index;
|
||||
};
|
||||
|
||||
extern W32_SharedState W32_shared_state;
|
||||
@ -1,2 +0,0 @@
|
||||
#include "meta_base_win32.h"
|
||||
#include "meta_base_win32.c"
|
||||
@ -195,7 +195,7 @@ OS_CommandResult OS_RunCommand(Arena *arena, String cmd)
|
||||
|
||||
SECURITY_ATTRIBUTES sa = ZI;
|
||||
sa.nLength = sizeof(sa);
|
||||
sa.bInheritHandle = TRUE;
|
||||
sa.bInheritHandle = 1;
|
||||
|
||||
HANDLE pipe_read, pipe_write;
|
||||
if (!CreatePipe(&pipe_read, &pipe_write, &sa, 0))
|
||||
@ -215,7 +215,7 @@ OS_CommandResult OS_RunCommand(Arena *arena, String cmd)
|
||||
PROCESS_INFORMATION pi = ZI;
|
||||
|
||||
result.output.text = PushDry(arena, u8);
|
||||
if (!CreateProcessW(NULL, cmd_wstr, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
|
||||
if (!CreateProcessW(0, cmd_wstr, 0, 0, 1, 0, 0, 0, &si, &pi))
|
||||
{
|
||||
/* TODO: error handling */
|
||||
Assert(0);
|
||||
@ -228,7 +228,7 @@ OS_CommandResult OS_RunCommand(Arena *arena, String cmd)
|
||||
{
|
||||
u8 buff[4096] = ZI;
|
||||
DWORD bytes_read = 0;
|
||||
if (!ReadFile(pipe_read, buff, countof(buff), &bytes_read, NULL))
|
||||
if (!ReadFile(pipe_read, buff, countof(buff), &bytes_read, 0))
|
||||
{
|
||||
if (GetLastError() == ERROR_BROKEN_PIPE)
|
||||
{
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
@Layer mixer
|
||||
|
||||
//- Dependencies
|
||||
@Dep base
|
||||
@Dep platform
|
||||
@Dep sound
|
||||
|
||||
|
||||
@ -1,8 +1,5 @@
|
||||
@Layer mp3
|
||||
|
||||
//- Dependencies
|
||||
@Dep base
|
||||
|
||||
//- Api
|
||||
@IncludeC mp3_core.h
|
||||
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
@Layer net
|
||||
|
||||
//- Dependencies
|
||||
@Dep base
|
||||
@Dep platform
|
||||
@Dep bitbuff
|
||||
|
||||
|
||||
@ -1,8 +1,5 @@
|
||||
@Layer platform
|
||||
|
||||
//- Dependencies
|
||||
@Dep base
|
||||
|
||||
//- Api
|
||||
@IncludeC platform_core.h
|
||||
@IncludeC platform_log.h
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
@Layer playback
|
||||
|
||||
//- Dependencies
|
||||
@Dep base
|
||||
@Dep platform
|
||||
@Dep mixer
|
||||
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
@Layer pp
|
||||
|
||||
//- Dependencies
|
||||
@Dep base
|
||||
@Dep gpu
|
||||
@Dep sprite
|
||||
@Dep font
|
||||
|
||||
@ -631,7 +631,7 @@ void UpdateUser(P_Window *window)
|
||||
P_WindowEvent *event = &events.events[ent_index];
|
||||
if (event->kind == P_WindowEventKind_Quit)
|
||||
{
|
||||
Exit();
|
||||
SignalExit(0);
|
||||
}
|
||||
|
||||
if (event->kind == P_WindowEventKind_ButtonUp)
|
||||
@ -639,7 +639,7 @@ void UpdateUser(P_Window *window)
|
||||
/* Escape quit */
|
||||
if (event->button == P_Btn_ESC)
|
||||
{
|
||||
Exit();
|
||||
SignalExit(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
@Layer rendertest
|
||||
|
||||
//- Dependencies
|
||||
@Dep base
|
||||
@Dep gpu
|
||||
@Dep sprite
|
||||
@Dep font
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
@Layer resource
|
||||
|
||||
//- Dependencies
|
||||
@Dep base
|
||||
@Dep platform
|
||||
@Dep tar
|
||||
@Dep inc
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
@Layer sound
|
||||
|
||||
//- Dependencies
|
||||
@Dep base
|
||||
@Dep platform
|
||||
@Dep mp3
|
||||
@Dep resource
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
@Layer sprite
|
||||
|
||||
//- Dependencies
|
||||
@Dep base
|
||||
@Dep platform
|
||||
@Dep gpu
|
||||
@Dep ase
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
@Layer tar
|
||||
|
||||
//- Dependencies
|
||||
@Dep base
|
||||
@Dep platform
|
||||
@Dep bitbuff
|
||||
|
||||
|
||||
@ -1,8 +1,5 @@
|
||||
@Layer ttf
|
||||
|
||||
//- Dependencies
|
||||
@Dep base
|
||||
|
||||
//- Api
|
||||
@IncludeC ttf_core.h
|
||||
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
@Layer watch
|
||||
|
||||
//- Dependencies
|
||||
@Dep base
|
||||
@Dep platform
|
||||
|
||||
//- Api
|
||||
|
||||
Loading…
Reference in New Issue
Block a user