From 0324866b9c076079569eadcbacd9267f45f72cf1 Mon Sep 17 00:00:00 2001 From: jacob Date: Sun, 24 Aug 2025 18:08:41 -0500 Subject: [PATCH] meta layer progress --- src/app/app.lay | 1 - src/base/base.lay | 3 - src/base/base_core.h | 166 +++++++++++++++--- src/base/base_entry.h | 1 - src/base/base_incbin.c | 9 +- src/base/base_job.h | 1 - src/base/base_memory.c | 49 ++---- src/base/base_memory.h | 6 +- src/base/base_rand.c | 16 -- src/base/base_rand.h | 3 - src/base/base_string.c | 78 ++++---- src/base/base_string.h | 56 +++--- src/base/base_win32/base_win32.c | 75 ++++++++ src/base/base_win32/base_win32.h | 9 + src/base/base_win32/base_win32.lay | 2 + src/base/base_win32/base_win32_entry.c | 72 +------- src/base/base_win32/base_win32_entry.h | 4 +- src/base/base_win32/base_win32_job.c | 5 - src/base/base_win32/base_win32_job.h | 3 - src/config.h | 5 +- src/font/font_core.c | 10 +- src/meta/meta.c | 64 ++++--- src/meta/meta_base/meta_base.h | 28 +++ src/meta/meta_base/meta_base_memory.c | 13 +- .../meta_base_win32/meta_base_win32.h | 9 - src/meta/meta_os/meta_os.h | 11 +- .../meta_os/meta_os_win32/meta_os_win32.c | 78 +++++++- src/mp3/mp3_mmf/mp3_mmf.c | 4 - src/platform/platform_core.h | 7 - src/platform/platform_win32/platform_win32.h | 3 - .../playback_wasapi/playback_wasapi.h | 4 - src/pp/pp.lay | 1 - src/ttf/ttf_dwrite/ttf_dwrite.c | 78 ++++---- src/ttf/ttf_dwrite/ttf_dwrite.h | 137 +++++++++++++++ 34 files changed, 671 insertions(+), 340 deletions(-) create mode 100644 src/base/base_win32/base_win32.c create mode 100644 src/base/base_win32/base_win32.h diff --git a/src/app/app.lay b/src/app/app.lay index d147cc61..9a4aabfd 100644 --- a/src/app/app.lay +++ b/src/app/app.lay @@ -7,7 +7,6 @@ @Dep gpu @Dep sprite @Dep watch -@Dep draw @Dep sound @Dep font @Dep asset_cache diff --git a/src/base/base.lay b/src/base/base.lay index 446127e9..767a0cec 100644 --- a/src/base/base.lay +++ b/src/base/base.lay @@ -35,6 +35,3 @@ //- Win32 impl @DefaultWindowsImpl base_win32 - -//- Startup -@Startup StartupBaseJobs diff --git a/src/base/base_core.h b/src/base/base_core.h index 6ad5b138..1c273c42 100644 --- a/src/base/base_core.h +++ b/src/base/base_core.h @@ -1,6 +1,13 @@ -#ifdef __cplusplus -extern "C" { -#endif +/* TODO: Remove this */ +#define RtcIsEnabled 1 +#define UnoptimizedIsEnabled 1 +#define AsanIsEnabled 0 +#define CrtlibIsEnabled 1 +#define DebinfoEnabled 1 +#define DeveloperIsEnabled 1 +#define ProfilingIsEnabled 0 +#define UnoptimizedIsEnabled 1 +#define TestsAreEnabled 0 //////////////////////////////// //~ Compiler feature flags @@ -59,14 +66,12 @@ extern "C" { #endif //- Language -#if defined(__STDC_VERSION__) -# define LanguageIsC 1 -# define LanguageIsGpu 0 -#elif defined(__HLSL_VERSION) +#if defined(__HLSL_VERSION) # define LanguageIsC 0 # define LanguageIsGpu 1 #else -# error Unknown language +# define LanguageIsC 1 +# define LanguageIsGpu 0 #endif //- Operating system @@ -102,26 +107,37 @@ extern "C" { #endif #endif +//- Windows defines +#if PlatformIsWindows +# define COBJMACROS +# define WIN32_LEAN_AND_MEAN +# define UNICODE +# pragma warning(push, 0) +# include +# pragma warning(pop) +#endif + //////////////////////////////// //~ Debug //- Static assert #if CompilerIsMsvc || (LanguageIsC && __STDC_VERSION__ < 202311L) || LanguageIsGpu # if CompilerIsMsvc -# define StaticAssert2(cond, line) struct STATIC_ASSERT_____##line {int foo[(cond) ? 1 : -1];} -# define StaticAssert1(cond, line) StaticAssert2(cond, line) -# define StaticAssert(cond) StaticAssert1(cond, __LINE__) +# 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 #else -# define StaticAssert(c) static_assert(c, "") +# define StaticAssert(cond) static_assert(cond, "") #endif //- Debug assert #if RtcIsEnabled # if CompilerIsMsvc -# define Assert(cond) ((cond) ? 1 : ((*(volatile int *)0) = 0, 0)) +// # 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)) @@ -259,6 +275,64 @@ void __asan_unpoison_memory_region(void const volatile *add, size_t); #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) + //////////////////////////////// //~ Type helper macros @@ -379,7 +453,6 @@ void __asan_unpoison_memory_region(void const volatile *add, size_t); //~ Scalar types #if LanguageIsC - //- Cpu scalar types #include "stdint.h" typedef int8_t i8; @@ -438,7 +511,6 @@ Global const f64 *_f64_nan = (f64 *)&_f64_nan_u64; #define IsF32Nan(x) (x != x) #define IsF64Nan(x) (x != x) - #endif //////////////////////////////// @@ -453,8 +525,8 @@ Struct(Atomic32) { volatile i32 _v; }; Struct(Atomic64) { volatile i64 _v; }; //- Cache-line isolated aligned atomic types -AlignedStruct(Atomic8Padded, 64) { Atomic8 v; u8 _pad[60]; }; -AlignedStruct(Atomic16Padded, 64) { Atomic16 v; u8 _pad[60]; }; +AlignedStruct(Atomic8Padded, 64) { Atomic8 v; u8 _pad[63]; }; +AlignedStruct(Atomic16Padded, 64) { Atomic16 v; u8 _pad[62]; }; AlignedStruct(Atomic32Padded, 64) { Atomic32 v; u8 _pad[60]; }; AlignedStruct(Atomic64Padded, 64) { Atomic64 v; u8 _pad[56]; }; StaticAssert(sizeof(Atomic8Padded) == 64 && alignof(Atomic8Padded) == 64); @@ -519,6 +591,41 @@ ForceInline void UnlockTicketMutex(TicketMutex *tm) } #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 @@ -538,15 +645,28 @@ StaticAssert(MaxFibers < I16Max); /* Fiber id type should fit max fibers */ #endif //////////////////////////////// -//~ Startup +//~ @hookdecl Core hooks -#define RunOnce() do { LocalPersist b32 r = 0; if (r) return; r = 1; } while (0) +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" - -#ifdef __cplusplus -} -#endif diff --git a/src/base/base_entry.h b/src/base/base_entry.h index 5e0c3565..c33b9713 100644 --- a/src/base/base_entry.h +++ b/src/base/base_entry.h @@ -9,7 +9,6 @@ typedef ExitFuncDef(ExitFunc); void OnExit(ExitFunc *func); void Exit(void); -void Panic(String msg); //////////////////////////////// //~ @hookdecl Application defined hooks diff --git a/src/base/base_incbin.c b/src/base/base_incbin.c index 6964f85a..ec710236 100644 --- a/src/base/base_incbin.c +++ b/src/base/base_incbin.c @@ -1,17 +1,10 @@ #if CompilerIsMsvc -//////////////////////////////// -//~ Windows headers - -#define WIN32_LEAN_AND_MEAN -#define UNICODE -#include - //////////////////////////////// //~ Incbin /* Find first resource with `type` and return the data in `udata`. */ -BOOL CALLBACK IncbinEnumerateResourceNamesFunc(HMODULE module, LPCWSTR type, LPCWSTR wstr_entry_name, LONG_PTR udata) +b32 CALLBACK IncbinEnumerateResourceNamesFunc(HMODULE module, LPCWSTR type, LPCWSTR wstr_entry_name, LONG_PTR udata) { TempArena scratch = BeginScratchNoConflict(); IncbinRcSearchParams *params = (IncbinRcSearchParams *)udata; diff --git a/src/base/base_job.h b/src/base/base_job.h index 324a1ae0..eb9b7e27 100644 --- a/src/base/base_job.h +++ b/src/base/base_job.h @@ -97,6 +97,5 @@ void RunJobEx(GenericJobDesc *desc); //~ @hookdecl Helpers i64 TimeNs(void); -u32 ThreadId(void); u32 GetLogicalProcessorCount(void); i64 GetCurrentSchedulerPeriodNs(void); diff --git a/src/base/base_memory.c b/src/base/base_memory.c index c6f78c5f..a847a90d 100644 --- a/src/base/base_memory.c +++ b/src/base/base_memory.c @@ -3,11 +3,6 @@ #if PlatformIsWindows -//- Windows headers -#define WIN32_LEAN_AND_MEAN -#define UNICODE -#include - //- Reserve void *ReserveMemory(u64 size) { @@ -47,12 +42,16 @@ void SetMemoryReadWrite(void *address, u64 size) #else # error Memory allocation not implemented for this platform -#endif +#endif /* PlatformIsWindows */ //////////////////////////////// -//~ Memory operations +//~ Crtlib memory.h stubs -void *CopyBytes(void *dst, void *src, u64 count) +#if !CrtlibIsEnabled + +//- memcpy +__attribute((section(".text.memcpy"))) +void *memcpy(void *__restrict dst, const void *__restrict src, u64 count) { char *dst_pchar = dst; char *src_pchar = src; @@ -63,7 +62,9 @@ void *CopyBytes(void *dst, void *src, u64 count) return dst; } -void *SetBytes(void *dst, u8 c, u64 count) +//- memset +__attribute((section(".text.memset"))) +void *memset(void *dst, i32 c, u64 count) { char *dst_pchar = dst; for (u64 i = 0; i < count; ++i) @@ -73,7 +74,9 @@ void *SetBytes(void *dst, u8 c, u64 count) return dst; } -i32 CmpBytes(void *p1, void *p2, u64 count) +//- memcmp +__attribute((section(".text.memcmp"))) +i32 memcmp(const void *p1, const void *p2, u64 count) { i32 result = 0; char *p1_pchar = p1; @@ -89,30 +92,4 @@ i32 CmpBytes(void *p1, void *p2, u64 count) return result; } -//////////////////////////////// -//~ Crtlib memory.h stubs - -#if !CrtlibIsEnabled - -//- memcpy -__attribute((section(".text.memcpy"))) -void *memcpy(void *__restrict dst, const void *__restrict src, u64 count) -{ - return CopyBytes(dst, src, count); -} - -//- memset -__attribute((section(".text.memset"))) -void *memset(void *dst, i32 c, u64 count) -{ - return SetBytes(dst, c, count); -} - -//- memcmp -__attribute((section(".text.memcmp"))) -i32 memcmp(const void *p1, const void *p2, u64 count) -{ - return CmpBytes(p1, p2, count); -} - #endif /* !CrtlibIsEnabled */ diff --git a/src/base/base_memory.h b/src/base/base_memory.h index 876a6e0d..d77a6958 100644 --- a/src/base/base_memory.h +++ b/src/base/base_memory.h @@ -24,9 +24,9 @@ void SetMemoryReadWrite(void *address, u64 size); #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); +#define CopyBytes(dst, src, count) memcpy(dst, src, count) +#define SetBytes(dst, c, count) memset(dst, c, count) +#define CmpBytes(p1, p2, count) memcmp(p1, p2, count) //////////////////////////////// //~ Crtlib stubs diff --git a/src/base/base_rand.c b/src/base/base_rand.c index 9cb1e809..05c6fb13 100644 --- a/src/base/base_rand.c +++ b/src/base/base_rand.c @@ -1,19 +1,3 @@ -//////////////////////////////// -//~ True randomness - -#if PlatformIsWindows -#if 0 -# define BCRYPT_RNG_ALG_HANDLE ((void *)0x00000081) -u32 BCryptGenRandom(void *algorithm, u8 *buffer, u32 buffer_size, u32 flags); -#endif -void TrueRand(String buffer) -{ - BCryptGenRandom(BCRYPT_RNG_ALG_HANDLE, (u8 *)buffer.text, buffer.len, 0); -} -#else -# error TrueRand not implemented for this platform -#endif - //////////////////////////////// //~ Stateful randomness diff --git a/src/base/base_rand.h b/src/base/base_rand.h index 6b3ebc65..c2c79cb8 100644 --- a/src/base/base_rand.h +++ b/src/base/base_rand.h @@ -13,9 +13,6 @@ Struct(RandState) //////////////////////////////// //~ Rand operations -//- True randomness -void TrueRand(String buffer); - //- Stateful randomness u64 RandU64FromState(RandState *state); f64 RandF64FromState(RandState *state, f64 range_start, f64 range_end); diff --git a/src/base/base_string.c b/src/base/base_string.c index bf0c4593..e1c5d9eb 100644 --- a/src/base/base_string.c +++ b/src/base/base_string.c @@ -1,5 +1,5 @@ //////////////////////////////// -//~ Conversion +//~ Conversion helpers //- Char conversion @@ -170,31 +170,8 @@ String StringFromF64(Arena *arena, f64 f, u32 precision) }; } -//- Handle conversion - -String StringFromhandle(Arena *arena, u64 v0, u64 v1) -{ - String result = ZI; - result.text = PushDry(arena, u8); - result.len += PushString(arena, Lit("h")).len; - result.len += StringFromU64(arena, v0, 16, 0).len; - result.len += PushString(arena, Lit("x")).len; - result.len += StringFromU64(arena, v1, 16, 0).len; - return result; -} - -//- Uid conversion - -String StringFromUid(Arena *arena, Uid uid) -{ - String result = ZI; - result.text = PushDry(arena, u8); - result.len += StringFromU64(arena, (uid.hi >> 32), 16, 8).len; - return result; -} - //////////////////////////////// -//~ String operations +//~ String helpers //- Copy @@ -455,6 +432,45 @@ b32 StringEndsWith(String str, String substring) 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 StringFromStringList(Arena *arena, StringList l, String separator) +{ + String result = ZI; + result.text = PushDry(arena, u8); + for (StringListNode *n = l.first; n; n = n->next) + { + String s = n->s; + PushString(arena, s); + result.len += s.len; + if (n->next) + { + PushString(arena, separator); + result.len += separator.len; + } + } + return result; +} + //////////////////////////////// //~ Formatting @@ -476,8 +492,6 @@ b32 StringEndsWith(String str, String substring) * FmtFloatP: Format an f64 with specified precision * FmtHex: Format a u64 in hexadecimal notation * FmtPtr: Format a pointer in hexadecimal notation prefixed by "0x" - * FmtHandle: Format a 128 bit handle - * FmtUid: Format a 128 bit uid * * FmtEnd (internal): Denote the end of the va_list * @@ -549,16 +563,6 @@ String StringFormatV(Arena *arena, String fmt, va_list args) parsed_str = StringFromF64(arena, arg.value.f, arg.precision); } break; - case FmtKind_Handle: - { - parsed_str = StringFromhandle(arena, arg.value.handle.h64[0], arg.value.handle.h64[1]); - } break; - - case FmtKind_Uid: - { - parsed_str = StringFromUid(arena, arg.value.uid); - } break; - case FmtKind_End: { /* Unexpected end. Not enough FMT args passed to function. */ diff --git a/src/base/base_string.h b/src/base/base_string.h index ba5ef891..f8f43367 100644 --- a/src/base/base_string.h +++ b/src/base/base_string.h @@ -1,3 +1,26 @@ +//////////////////////////////// +//~ 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 @@ -16,8 +39,8 @@ typedef i32 FmtKind; enum FmtKind_Hex = 0x0a3d0792, FmtKind_Ptr = 0x0c4519e4, FmtKind_Float = 0x04814143, - FmtKind_Handle = 0x0f112992, - FmtKind_Uid = 0x0beb23dd, + FmtKind_Uid = 0x9d1cd407, + FmtKind_Handle = 0xfead3bec, FmtKind_End = 0x0ecbc5ae }; @@ -35,11 +58,11 @@ Struct(FmtArg) i64 sint; void *ptr; f64 f; + Uid uid; struct { u64 h64[2]; } handle; - Uid uid; } value; }; @@ -56,32 +79,16 @@ Struct(CodepointIter) }; //////////////////////////////// -//~ String utils - -#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) }) \ - ) - -//////////////////////////////// -//~ Conversion operations +//~ 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 StringFromhandle(Arena *arena, u64 v0, u64 v1); -String StringFromUid(Arena *arena, Uid uid); //////////////////////////////// -//~ String operations +//~ String helpers String PushString(Arena *arena, String src); String PushStringToBuff(String dst, String src); @@ -96,6 +103,12 @@ b32 StringContains(String str, String substring); b32 StringStartsWith(String str, String substring); b32 StringEndsWith(String str, String substring); +//////////////////////////////// +//~ String list helpers + +StringListNode *PushStringToList(Arena *arena, StringList *l, String s); +String StringFromStringList(Arena *arena, StringList l, String separator); + //////////////////////////////// //~ Formatting @@ -114,6 +127,7 @@ b32 StringEndsWith(String str, String substring); #define FmtEnd (FmtArg) {.kind = FmtKind_End} //- Format functions +#define StringF(arena, lit, ...) _StringFormat((arena), Lit(lit), __VA_ARGS__, FmtEnd) #define StringFormat(arena, fmt, ...) _StringFormat((arena), (fmt), __VA_ARGS__, FmtEnd) String _StringFormat(Arena *arena, String fmt, ...); String StringFormatV(Arena *arena, String fmt, va_list args); diff --git a/src/base/base_win32/base_win32.c b/src/base/base_win32/base_win32.c new file mode 100644 index 00000000..71fd1402 --- /dev/null +++ b/src/base/base_win32/base_win32.c @@ -0,0 +1,75 @@ +W32_SharedState W32_shared_state = ZI; + +//////////////////////////////// +//~ Windows libs + +#pragma comment(lib, "kernel32") +#pragma comment(lib, "user32") + +//////////////////////////////// +//~ @hookdef OS startup hook + +void StartupBase(void) +{ + W32_SharedState *g = &W32_shared_state; + g->tls_index = TlsAlloc(); + TlsSetValue(g->tls_index, 0); +} + +//////////////////////////////// +//~ @hookdef Panic hooks + +/* TODO: Remove stdio & printf */ +#include + +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 +//////////////////////////////// +//~ True randomness + +#if PlatformIsWindows +#if 0 +# define BCRYPT_RNG_ALG_HANDLE ((void *)0x00000081) +u32 BCryptGenRandom(void *algorithm, u8 *buffer, u32 buffer_size, u32 flags); +#endif +void TrueRand(String buffer) +{ + BCryptGenRandom(BCRYPT_RNG_ALG_HANDLE, (u8 *)buffer.text, buffer.len, 0); +} +#else +# error TrueRand not implemented for this platform +#endif diff --git a/src/base/base_win32/base_win32.h b/src/base/base_win32/base_win32.h new file mode 100644 index 00000000..67837b7b --- /dev/null +++ b/src/base/base_win32/base_win32.h @@ -0,0 +1,9 @@ +//////////////////////////////// +//~ Shared state + +Struct(W32_SharedState) +{ + DWORD tls_index; +}; + +extern W32_SharedState W32_shared_state; diff --git a/src/base/base_win32/base_win32.lay b/src/base/base_win32/base_win32.lay index ac65cc0e..f42bdb3d 100644 --- a/src/base/base_win32/base_win32.lay +++ b/src/base/base_win32/base_win32.lay @@ -1,9 +1,11 @@ @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 diff --git a/src/base/base_win32/base_win32_entry.c b/src/base/base_win32/base_win32_entry.c index 57ca12f9..e19ab75e 100644 --- a/src/base/base_win32/base_win32_entry.c +++ b/src/base/base_win32/base_win32_entry.c @@ -3,18 +3,18 @@ W32_SharedEntryCtx W32_shared_entry_ctx = ZI; //////////////////////////////// //~ Startup / shutdown jobs -JobDef(W32_AppStartupJob, UNUSED sig, UNUSED id) +JobDef(W32_StartupLayersJob, UNUSED sig, UNUSED id) { W32_SharedEntryCtx *g = &W32_shared_entry_ctx; TempArena scratch = BeginScratchNoConflict(); { - Startup(); + StartupLayers(); SetEvent(g->startup_end_event); } EndScratch(scratch); } -JobDef(W32_AppShutdownJob, UNUSED sig, UNUSED id) +JobDef(W32_ShutdownLayersJob, UNUSED sig, UNUSED id) { __prof; W32_SharedEntryCtx *g = &W32_shared_entry_ctx; @@ -48,60 +48,6 @@ void Exit(void) SetEvent(g->exit_begin_event); } -void Panic(String msg) -{ - W32_SharedEntryCtx *g = &W32_shared_entry_ctx; - if (Atomic32FetchTestSet(&g->panicking, 0, 1) == 0) - { - //LogPanic(msg); - - wchar_t *wstr = g->panic_wstr; - u64 WstrLen = 0; - - wchar_t prefix[] = L"A fatal error has occured and the application needs to exit:\n\n"; - CopyBytes(wstr, prefix, MinU64(countof(g->panic_wstr), (countof(prefix) << 1))); - WstrLen += countof(prefix) - 1; - - /* Perform manual string encode to avoid any implicit memory - * allocation (in case allocation is unreliable) */ - String str8 = msg; - 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); - u64 wstr_new_len = WstrLen + encoded.count16; - if (wstr_new_len < (countof(g->panic_wstr) - 1)) - { - u16 *dest = wstr + WstrLen; - CopyBytes(dest, encoded.chars16, (encoded.count16 << 1)); - WstrLen = wstr_new_len; - pos8 += decoded.advance8; - } - else - { - break; - } - } - - wstr[WstrLen] = 0; - -#if RtcIsEnabled - MessageBoxExW(0, wstr, L"Fatal error", MB_ICONSTOP | MB_SETFOREGROUND | MB_TOPMOST, 0); - Assert(0); -#endif - - SetEvent(g->panic_event); - - /* Wait for process termination */ - if (GetCurrentThreadId() != g->main_thread_id) - { - Sleep(INFINITE); - } - } -} - //////////////////////////////// //~ Winmain @@ -205,15 +151,13 @@ int CALLBACK wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance, /* Query system info */ GetSystemInfo(&g->info); - /* Initialize base layer */ - BaseMain(); + //- Startup jobs + StartupBaseJobs(); - //- App startup - - /* Run app start job */ + /* Startup layers */ if (!Atomic32Fetch(&g->panicking)) { - RunJob(1, W32_AppStartupJob, JobPool_Floating, JobPriority_High, 0, 0); + RunJob(1, W32_StartupLayersJob, JobPool_Floating, JobPriority_High, 0, 0); } /* Wait for startup end or panic */ @@ -241,7 +185,7 @@ int CALLBACK wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance, /* Run exit callbacks job */ if (!Atomic32Fetch(&g->panicking)) { - RunJob(1, W32_AppShutdownJob, JobPool_Floating, JobPriority_High, 0, 0); + RunJob(1, W32_ShutdownLayersJob, JobPool_Floating, JobPriority_High, 0, 0); } /* Wait for exit end or panic */ diff --git a/src/base/base_win32/base_win32_entry.h b/src/base/base_win32/base_win32_entry.h index e1d6b9bd..e6c172c8 100644 --- a/src/base/base_win32/base_win32_entry.h +++ b/src/base/base_win32/base_win32_entry.h @@ -29,5 +29,5 @@ extern W32_SharedEntryCtx W32_shared_entry_ctx; //////////////////////////////// //~ Startup / shutdown jobs -JobDecl(W32_AppStartupJob, EmptySig); -JobDecl(W32_AppShutdownJob, EmptySig); +JobDecl(W32_StartupLayersJob, EmptySig); +JobDecl(W32_ShutdownLayersJob, EmptySig); diff --git a/src/base/base_win32/base_win32_job.c b/src/base/base_win32/base_win32_job.c index a8d4efe3..8cf6e6e2 100644 --- a/src/base/base_win32/base_win32_job.c +++ b/src/base/base_win32/base_win32_job.c @@ -1518,11 +1518,6 @@ i64 TimeNs(void) return result; } -u32 ThreadId(void) -{ - return GetCurrentThreadId(); -} - u32 GetLogicalProcessorCount(void) { return GetActiveProcessorCount(ALL_PROCESSOR_GROUPS); diff --git a/src/base/base_win32/base_win32_job.h b/src/base/base_win32/base_win32_job.h index 5fb4090e..8a99c438 100644 --- a/src/base/base_win32/base_win32_job.h +++ b/src/base/base_win32/base_win32_job.h @@ -2,9 +2,6 @@ //~ Win32 headers #pragma warning(push, 0) -# define UNICODE -# define WIN32_LEAN_AND_MEAN -# include # include # include # include diff --git a/src/config.h b/src/config.h index 692fa6f7..c713eb2f 100644 --- a/src/config.h +++ b/src/config.h @@ -87,9 +87,8 @@ #define PROF_THREAD_GROUP_WINDOW -(i64)Mebi(2) #define PROF_THREAD_GROUP_MAIN -(i64)Mebi(1) -/* ========================== * - * Settings - * ========================== */ +//////////////////////////////// +//~ Settings /* TODO: Move these to user-configurable settings */ diff --git a/src/font/font_core.c b/src/font/font_core.c index 064011b4..2bda7dbf 100644 --- a/src/font/font_core.c +++ b/src/font/font_core.c @@ -48,7 +48,15 @@ JobDef(F_LoadJob, sig, _) RES_CloseResource(&res); /* Send texture to GPU */ - GPU_Resource *texture = GPU_AcquireTexture(GP_TEXTURE_FORMAT_R8G8B8A8_UNORM, 0, VEC2I32(result.image_width, result.image_height), result.image_pixels); + GPU_Resource *texture = 0; + { + GPU_ResourceDesc desc = ZI; + desc.kind = GPU_ResourceKind_Texture2D; + desc.texture.format = GPU_Format_R8G8B8A8_Unorm; + desc.texture.size = VEC3I32(64, 64, 1); + texture = GPU_AcquireResource(desc); + GPU_PushString(0, texture, STRING(desc.texture.size.x * desc.texture.size.y * 4, (u8 *)result.image_pixels)); + } /* Acquire store memory */ F_Font *font = 0; diff --git a/src/meta/meta.c b/src/meta/meta.c index 6f427fca..a12c6499 100644 --- a/src/meta/meta.c +++ b/src/meta/meta.c @@ -543,30 +543,35 @@ L_Topo L_TopoFromLayerName(Arena *arena, StringList starting_layer_names, String } else { - /* Push blob impls */ -#if PlatformIsWindows - for (L_BlobItem *impl_item = blob->default_windows_impls.first; impl_item; impl_item = impl_item->next) + /* Push platform impls */ { - String impl_name = impl_item->s; - u64 impl_hash = HashFnv64(Fnv64Basis, impl_name); - L_Blob *impl = (L_Blob *)DictValueFromHash(parsed.blobs_dict, impl_hash); - if (impl) + L_BlobItemList platform_impls = ZI; + if (PlatformIsWindows) { - if (!seen_blobs[impl->id]) + platform_impls = blob->default_windows_impls; + } + for (L_BlobItem *impl_item = platform_impls.first; impl_item; impl_item = impl_item->next) + { + String impl_name = impl_item->s; + u64 impl_hash = HashFnv64(Fnv64Basis, impl_name); + L_Blob *impl = (L_Blob *)DictValueFromHash(parsed.blobs_dict, impl_hash); + if (impl) { - Node *n = PushStruct(scratch.arena, Node); - n->blob = impl; - n->state = 0; - SllStackPush(first_stack, n); + if (!seen_blobs[impl->id]) + { + Node *n = PushStruct(scratch.arena, Node); + n->blob = impl; + n->state = 0; + SllStackPush(first_stack, n); + } + } + else + { + String file = PushString(arena, impl_item->token_file); + L_PushTopoItem(arena, &result.errors, file, impl_item->token_pos, StringF(arena, "Layer '%F' not found", FmtString(impl_name))); } } - else - { - String file = PushString(arena, impl_item->token_file); - L_PushTopoItem(arena, &result.errors, file, impl_item->token_pos, StringF(arena, "Layer '%F' not found", FmtString(impl_name))); - } } -#endif /* Push blob exit */ { entered_blobs[blob->id] = 1; @@ -705,6 +710,8 @@ Error *PushError(Arena *arena, ErrorList *list, String file, i64 pos, String s) i32 main(i32 argc, u8 **argv) { + i32 ret = 0; + //- Startup StartupBase(); OS_Startup(); @@ -761,7 +768,8 @@ i32 main(i32 argc, u8 **argv) String file = StringF(arena, "%F%F", FmtString(parent), FmtString(item->s)); if (F_IsFile(file)) { - String line = StringF(arena, "#include \"%F\"", FmtString(file)); + String full = F_GetFull(arena, file); + String line = StringF(arena, "#include \"%F\"", FmtString(full)); PushStringToList(arena, &c_out_lines, line); } else @@ -772,7 +780,6 @@ i32 main(i32 argc, u8 **argv) } String c_out = StringFromStringList(arena, c_out_lines, Lit("\n")); F_ClearWrite(Lit("gen.c"), c_out); - Echo(c_out); } //- Print errors @@ -802,10 +809,19 @@ i32 main(i32 argc, u8 **argv) } //- Compile - { - String cmd = Lit("\"cl\" /Zi /DEBUG src/build/tmp/gen.c /Fo:build/tmp/gen.obj /Fe:build/pp.exe /nologo"); - OS_RunCommand(cmd); + if (ret == 0) { + String cmd = Lit("\"cl\" /Zi /DEBUG gen.c /Fo:gen.obj /Fe:pp.exe /nologo"); + + OS_CommandResult result = OS_RunCommand(arena, cmd); + if (result.code == 0) + { + } + else + { + ret = result.code; + } + Echo(result.output); } - return errors.count > 0; + return ret != 0 ? ret : errors.count > 0; } diff --git a/src/meta/meta_base/meta_base.h b/src/meta/meta_base/meta_base.h index b800d7c2..5da28392 100644 --- a/src/meta/meta_base/meta_base.h +++ b/src/meta/meta_base/meta_base.h @@ -100,6 +100,16 @@ #endif #endif +//- Windows defines +#if PlatformIsWindows +# define COBJMACROS +# define WIN32_LEAN_AND_MEAN +# define UNICODE +# pragma warning(push, 0) +# include +# pragma warning(pop) +#endif + //////////////////////////////// //~ Debug @@ -609,6 +619,24 @@ Struct(String32) u32 *text; }; +//////////////////////////////// +//~ Fibers + +#define MaxFibers 1024 + +#if LanguageIsC +# if PlatformIsWindows +ForceInline i16 FiberId(void) +{ + i16 *v = (void *)__readgsqword(32); + return *v; +} +# else +# error FiberId not implemented +# endif +StaticAssert(MaxFibers < I16Max); /* Fiber id type should fit max fibers */ +#endif + //////////////////////////////// //~ @hookdecl Core hooks diff --git a/src/meta/meta_base/meta_base_memory.c b/src/meta/meta_base/meta_base_memory.c index 5f2cbd98..fbb5eb3e 100644 --- a/src/meta/meta_base/meta_base_memory.c +++ b/src/meta/meta_base/meta_base_memory.c @@ -1,15 +1,8 @@ +//////////////////////////////// +//~ Win32 memory allocation + #if PlatformIsWindows -//////////////////////////////// -//~ Windows headers - -#define WIN32_LEAN_AND_MEAN -#define UNICODE -#include - -//////////////////////////////// -//~ Memory allocation - //- Reserve void *ReserveMemory(u64 size) { diff --git a/src/meta/meta_base/meta_base_win32/meta_base_win32.h b/src/meta/meta_base/meta_base_win32/meta_base_win32.h index fb335b18..67837b7b 100644 --- a/src/meta/meta_base/meta_base_win32/meta_base_win32.h +++ b/src/meta/meta_base/meta_base_win32/meta_base_win32.h @@ -1,12 +1,3 @@ -//////////////////////////////// -//~ Windows headers - -#pragma warning(push, 0) -# define UNICODE -# define WIN32_LEAN_AND_MEAN -# include -#pragma warning(pop) - //////////////////////////////// //~ Shared state diff --git a/src/meta/meta_os/meta_os.h b/src/meta/meta_os/meta_os.h index 02aca063..b08f6384 100644 --- a/src/meta/meta_os/meta_os.h +++ b/src/meta/meta_os/meta_os.h @@ -15,6 +15,15 @@ Struct(OS_File) u64 handle; }; +//////////////////////////////// +//~ Command types + +Struct(OS_CommandResult) +{ + i32 code; + String output; +}; + //////////////////////////////// //~ @hookdecl Startup hooks @@ -41,4 +50,4 @@ void OS_Mkdir(String path); //////////////////////////////// //~ @hookdecl Shell operations -void OS_RunCommand(String cmd); +OS_CommandResult OS_RunCommand(Arena *arena, String cmd); diff --git a/src/meta/meta_os/meta_os_win32/meta_os_win32.c b/src/meta/meta_os/meta_os_win32/meta_os_win32.c index 3581c937..e5080bd1 100644 --- a/src/meta/meta_os/meta_os_win32/meta_os_win32.c +++ b/src/meta/meta_os/meta_os_win32/meta_os_win32.c @@ -95,9 +95,11 @@ void OS_DirContentsFromFullPath(Arena *arena, StringList *list, String path) wchar_t *filter_wstr = WstrFromString(scratch.arena, filter); HANDLE find_handle = FindFirstFileExW(filter_wstr, FindExInfoStandard, &find_data, FindExSearchNameMatch, 0, FIND_FIRST_EX_CASE_SENSITIVE | FIND_FIRST_EX_LARGE_FETCH); b32 found = find_handle && find_handle != INVALID_HANDLE_VALUE; - while (found) { + while (found) + { String file_name = StringFromWstrNoLimit(arena, find_data.cFileName); - if (!EqString(file_name, Lit(".")) && !EqString(file_name, Lit(".."))) { + if (!EqString(file_name, Lit(".")) && !EqString(file_name, Lit(".."))) + { PushStringToList(arena, list, file_name); } found = FindNextFileW(find_handle, &find_data); @@ -158,6 +160,76 @@ b32 OS_DirExists(String path) //////////////////////////////// //~ @hookdef Shell hooks -void OS_RunCommand(String cmd) +OS_CommandResult OS_RunCommand(Arena *arena, String cmd) { + TempArena scratch = BeginScratch(arena); + OS_CommandResult result = ZI; + + i32 res = -1; + + wchar_t *cmd_wstr = WstrFromString(scratch.arena, cmd); + + SECURITY_ATTRIBUTES sa = ZI; + sa.nLength = sizeof(sa); + sa.bInheritHandle = TRUE; + + HANDLE pipe_read, pipe_write; + if (!CreatePipe(&pipe_read, &pipe_write, &sa, 0)) + { + /* TODO: error handling */ + Assert(0); + } + SetHandleInformation(pipe_read, HANDLE_FLAG_INHERIT, 0); + + STARTUPINFO si = ZI; + si.cb = sizeof(si); + si.dwFlags = STARTF_USESTDHANDLES; + si.hStdInput = GetStdHandle(STD_INPUT_HANDLE); + si.hStdOutput = pipe_write; + si.hStdError = pipe_write; + + PROCESS_INFORMATION pi = ZI; + + result.output.text = PushDry(arena, u8); + if (!CreateProcessW(NULL, cmd_wstr, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) + { + /* TODO: error handling */ + Assert(0); + } else { + CloseHandle(pipe_write); + b32 exit_code_valid = 0; + i32 exit_code = 0; + b32 stdout_finished = 0; + while (!stdout_finished) + { + u8 buff[4096] = ZI; + DWORD bytes_read = 0; + if (!ReadFile(pipe_read, buff, countof(buff), &bytes_read, NULL)) + { + if (GetLastError() == ERROR_BROKEN_PIPE) + { + GetExitCodeProcess(pi.hProcess, &exit_code); + exit_code_valid = 1; + } + stdout_finished = 1; + } + PushStructsNoZero(arena, u8, bytes_read); + CopyBytes(result.output.text + result.output.len, buff, bytes_read); + result.output.len += bytes_read; + } + + CloseHandle(pi.hThread); + CloseHandle(pi.hProcess); + + if (exit_code_valid) + { + result.code = exit_code; + } else { + result.code = -1; + } + } + + CloseHandle(pipe_read); + EndScratch(scratch); + return result; } diff --git a/src/mp3/mp3_mmf/mp3_mmf.c b/src/mp3/mp3_mmf/mp3_mmf.c index 17abdc90..e951262c 100644 --- a/src/mp3/mp3_mmf/mp3_mmf.c +++ b/src/mp3/mp3_mmf/mp3_mmf.c @@ -2,10 +2,6 @@ //~ Windows headers #pragma warning(push, 0) -# define COBJMACROS -# define WIN32_LEAN_AND_MEAN -# define UNICODE -# include # include # include # include diff --git a/src/platform/platform_core.h b/src/platform/platform_core.h index fb07fca3..4360dd5a 100644 --- a/src/platform/platform_core.h +++ b/src/platform/platform_core.h @@ -408,13 +408,6 @@ String P_GetClipboardText(Arena *arena); void P_SleepPrecise(i64 sleep_time_ns); void P_SleepFrame(i64 last_frame_time_ns, i64 target_dt_ns); -//////////////////////////////// -//~ @hookdecl Program exit - -void OnExit(ExitFunc *func); -void Exit(void); -void Panic(String msg); - //////////////////////////////// //~ @hookdecl Entry point (implemented per application) diff --git a/src/platform/platform_win32/platform_win32.h b/src/platform/platform_win32/platform_win32.h index ea2a967b..88c23016 100644 --- a/src/platform/platform_win32/platform_win32.h +++ b/src/platform/platform_win32/platform_win32.h @@ -2,9 +2,6 @@ //~ Win32 headers #pragma warning(push, 0) -# define UNICODE -# define WIN32_LEAN_AND_MEAN -# include # include # include # include diff --git a/src/playback/playback_wasapi/playback_wasapi.h b/src/playback/playback_wasapi/playback_wasapi.h index 169617b2..fa0ea963 100644 --- a/src/playback/playback_wasapi/playback_wasapi.h +++ b/src/playback/playback_wasapi/playback_wasapi.h @@ -2,10 +2,6 @@ //~ Win32 headers #pragma warning(push, 0) -# define COBJMACROS -# define WIN32_LEAN_AND_MEAN -# define UNICODE -# include # include # include # include diff --git a/src/pp/pp.lay b/src/pp/pp.lay index 6ff2f827..178cee1f 100644 --- a/src/pp/pp.lay +++ b/src/pp/pp.lay @@ -6,7 +6,6 @@ @Dep sprite @Dep font @Dep collider -@Dep draw @Dep net @Dep mixer @Dep bitbuff diff --git a/src/ttf/ttf_dwrite/ttf_dwrite.c b/src/ttf/ttf_dwrite/ttf_dwrite.c index 5785e8b6..eccfa555 100644 --- a/src/ttf/ttf_dwrite/ttf_dwrite.c +++ b/src/ttf/ttf_dwrite/ttf_dwrite.c @@ -6,19 +6,11 @@ extern TTF_DW_SharedState TTF_DW_shared_state = ZI; //////////////////////////////// //~ Win32 libs -#define WIN32_LEAN_AND_MEAN -#define UNICODE -#pragma warning(push, 0) -# include -# include -# include -#pragma warning(pop) - #pragma comment(lib, "dwrite") #pragma comment(lib, "gdi32") //////////////////////////////// -//~ Startup +//~ @hookdef Startup /* Call this during font system startup */ void TTF_StartupCore(void) @@ -36,7 +28,7 @@ void TTF_StartupCore(void) #endif HRESULT error = DWriteCreateFactory( DWRITE_FACTORY_TYPE_SHARED, - __uuidof(IDWriteFactory5), + &IID_IDWriteFactory5, (IUnknown **)&g->factory ); #if CompilerIsClang @@ -51,7 +43,7 @@ void TTF_StartupCore(void) } //////////////////////////////// -//~ Decode +//~ @hookdef Decode TTF_Result TTF_Decode(Arena *arena, String encoded, f32 point_size, u32 *cache_codes, u32 cache_codes_count) { @@ -71,42 +63,42 @@ TTF_Result TTF_Decode(Arena *arena, String encoded, f32 point_size, u32 *cache_c { /* Create in memory loader */ IDWriteInMemoryFontFileLoader *loader = 0; - error = factory->CreateInMemoryFontFileLoader(&loader); - error = factory->RegisterFontFileLoader(loader); + error = IDWriteFactory5_CreateInMemoryFontFileLoader(factory, &loader); + error = IDWriteFactory5_RegisterFontFileLoader(factory, (IDWriteFontFileLoader *)loader); IDWriteFontSetBuilder1 *builder = 0; - error = factory->CreateFontSetBuilder(&builder); - error = loader->CreateInMemoryFontFileReference(factory, encoded.text, (u32)encoded.len, 0, &font_file); - error = builder->AddFontFile(font_file); + error = IDWriteFactory5_CreateFontSetBuilder1(factory, &builder); + error = IDWriteInMemoryFontFileLoader_CreateInMemoryFontFileReference(loader, (IDWriteFactory *)factory, encoded.text, (u32)encoded.len, 0, &font_file); + error = IDWriteFontSetBuilder1_AddFontFile(builder, font_file); } //- Create face IDWriteFontFace *font_face = 0; - error = factory->CreateFontFace(DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &font_file, 0, DWRITE_FONT_SIMULATIONS_NONE, &font_face); + error = IDWriteFactory5_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &font_file, 0, DWRITE_FONT_SIMULATIONS_NONE, &font_face); //- Setup rendering params IDWriteRenderingParams *default_rendering_params = 0; - error = factory->CreateRenderingParams(&default_rendering_params); + error = IDWriteFactory5_CreateRenderingParams(factory, &default_rendering_params); IDWriteRenderingParams *rendering_params = 0; - FLOAT gamma = default_rendering_params->GetGamma(); - FLOAT enhanced_contrast = default_rendering_params->GetEnhancedContrast(); - FLOAT clear_type_level = default_rendering_params->GetClearTypeLevel(); - error = factory->CreateCustomRenderingParams(gamma, - enhanced_contrast, - clear_type_level, - DWRITE_PIXEL_GEOMETRY_FLAT, - DWRITE_RENDERING_MODE_DEFAULT, - &rendering_params); + FLOAT gamma = IDWriteRenderingParams_GetGamma(default_rendering_params); + FLOAT enhanced_contrast = IDWriteRenderingParams_GetEnhancedContrast(default_rendering_params); + FLOAT clear_type_level = IDWriteRenderingParams_GetClearTypeLevel(default_rendering_params); + error = IDWriteFactory5_CreateCustomRenderingParams(factory, gamma, + enhanced_contrast, + clear_type_level, + DWRITE_PIXEL_GEOMETRY_FLAT, + DWRITE_RENDERING_MODE_DEFAULT, + &rendering_params); //- Setup interop IDWriteGdiInterop *dwrite_gdi_interop = 0; - error = factory->GetGdiInterop(&dwrite_gdi_interop); + error = IDWriteFactory5_GetGdiInterop(factory, &dwrite_gdi_interop); //- Get metrics DWRITE_FONT_METRICS metrics = ZI; - font_face->GetMetrics(&metrics); + IDWriteFontFace_GetMetrics(font_face, &metrics); - u16 glyph_count = font_face->GetGlyphCount(); + u16 glyph_count = IDWriteFontFace_GetGlyphCount(font_face); f32 pixel_per_em = point_size * (TTF_DW_Dpi / 72.0f); f32 pixel_per_design_unit = pixel_per_em / ((f32)metrics.designUnitsPerEm); @@ -123,13 +115,13 @@ TTF_Result TTF_Decode(Arena *arena, String encoded, f32 point_size, u32 *cache_c //- Setup render target IDWriteBitmapRenderTarget *render_target = 0; /* FIXME: errors when point_size too high */ - error = dwrite_gdi_interop->CreateBitmapRenderTarget(0, (UINT32)raster_target_w, (UINT32)raster_target_h, &render_target); - render_target->SetPixelsPerDip(1.0); + error = IDWriteGdiInterop_CreateBitmapRenderTarget(dwrite_gdi_interop, 0, (UINT32)raster_target_w, (UINT32)raster_target_h, &render_target); + IDWriteBitmapRenderTarget_SetPixelsPerDip(render_target, 1.0); /* Clear the render target */ HDC dc = 0; { - dc = render_target->GetMemoryDC(); + dc = IDWriteBitmapRenderTarget_GetMemoryDC(render_target); HGDIOBJ original = SelectObject(dc, GetStockObject(DC_PEN)); SetDCPenColor(dc, bg_color); SelectObject(dc, GetStockObject(DC_BRUSH)); @@ -166,7 +158,7 @@ TTF_Result TTF_Decode(Arena *arena, String encoded, f32 point_size, u32 *cache_c glyph_run.glyphIndices = &i; RECT bounding_box = ZI; - error = render_target->DrawGlyphRun( + error = IDWriteBitmapRenderTarget_DrawGlyphRun(render_target, raster_target_x, raster_target_y, DWRITE_MEASURING_MODE_NATURAL, @@ -187,7 +179,7 @@ TTF_Result TTF_Decode(Arena *arena, String encoded, f32 point_size, u32 *cache_c //- Compute glyph metrics DWRITE_GLYPH_METRICS glyph_metrics = ZI; - error = font_face->GetDesignGlyphMetrics(&i, 1, &glyph_metrics, 0); + error = IDWriteFontFace_GetDesignGlyphMetrics(font_face, &i, 1, &glyph_metrics, 0); f32 off_x = (f32)bounding_box.left - raster_target_x; f32 off_y = (f32)bounding_box.top - raster_target_y; @@ -226,7 +218,7 @@ TTF_Result TTF_Decode(Arena *arena, String encoded, f32 point_size, u32 *cache_c } /* Set bounding box metrics (now that we know atlas x & y) */ - glyph->atlas_rect = ZI; + ZeroStruct(&glyph->atlas_rect); glyph->atlas_rect.x = (f32)out_offset_x; glyph->atlas_rect.y = (f32)out_offset_y; glyph->atlas_rect.width = (f32)tex_w; @@ -274,19 +266,19 @@ TTF_Result TTF_Decode(Arena *arena, String encoded, f32 point_size, u32 *cache_c if (cache_codes_count > 0) { cache_indices = PushStructs(arena, u16, cache_codes_count); - font_face->GetGlyphIndices(cache_codes, cache_codes_count, cache_indices); + IDWriteFontFace_GetGlyphIndices(font_face, cache_codes, cache_codes_count, cache_indices); } //- Release /* FIXME: Check for leaks */ - dwrite_gdi_interop->Release(); - rendering_params->Release(); - default_rendering_params->Release(); + IDWriteGdiInterop_Release(dwrite_gdi_interop); + IDWriteRenderingParams_Release(rendering_params); + IDWriteRenderingParams_Release(default_rendering_params); // NOTE FROM ALLEN: We don't release font face because we intend to keep the font face around after the baking process - // font_face->Release(); - font_file->Release(); + // IDWriteFontFace_Release(font_face); + IDWriteFontFile_Release(font_file); //loader->Release(); - factory->Release(); + IDWriteFactory5_Release(factory); /* Return */ TTF_Result result = ZI; diff --git a/src/ttf/ttf_dwrite/ttf_dwrite.h b/src/ttf/ttf_dwrite/ttf_dwrite.h index b56cadf2..1e9150d9 100644 --- a/src/ttf/ttf_dwrite/ttf_dwrite.h +++ b/src/ttf/ttf_dwrite/ttf_dwrite.h @@ -1,3 +1,140 @@ +//////////////////////////////// +//~ DirectWrite types + +/* DirectWrite C API stubs are taken from Mārtiņš Možeiko's c_d2d_dwrite + * https://github.com/mmozeiko/c_d2d_dwrite/blob/main/cdwrite.h + */ + +//- Windows headers +#include +#include +#include + +//- GUIDs +DEFINE_GUID(IID_IDWriteFactory5, 0x958db99a, 0xbe2a, 0x4f09, 0xaf, 0x7d, 0x65, 0x18, 0x98, 0x03, 0xd1, 0xd3); + +//- Interfaces +typedef struct IDWriteFactory { struct { void* tbl[]; }* v; } IDWriteFactory; +typedef struct IDWriteFactory5 { struct { void* tbl[]; }* v; } IDWriteFactory5; +typedef struct IDWriteFontFile { struct { void* tbl[]; }* v; } IDWriteFontFile; +typedef struct IDWriteInMemoryFontFileLoader { struct { void* tbl[]; }* v; } IDWriteInMemoryFontFileLoader; +typedef struct IDWriteFontFileLoader { struct { void* tbl[]; }* v; } IDWriteFontFileLoader; +typedef struct IDWriteFontFace { struct { void* tbl[]; }* v; } IDWriteFontFace; +typedef struct IDWriteRenderingParams { struct { void* tbl[]; }* v; } IDWriteRenderingParams; +typedef struct IDWriteGdiInterop { struct { void* tbl[]; }* v; } IDWriteGdiInterop; +typedef struct IDWriteFontSetBuilder { struct { void* tbl[]; }* v; } IDWriteFontSetBuilder; +typedef struct IDWriteFontSetBuilder1 { struct { void* tbl[]; }* v; } IDWriteFontSetBuilder1; +typedef struct IDWriteBitmapRenderTarget { struct { void* tbl[]; }* v; } IDWriteBitmapRenderTarget; + +//- Enums +typedef enum DWRITE_FACTORY_TYPE { + DWRITE_FACTORY_TYPE_SHARED = 0, + DWRITE_FACTORY_TYPE_ISOLATED = 1, +} DWRITE_FACTORY_TYPE; + +typedef enum DWRITE_FONT_FACE_TYPE { + DWRITE_FONT_FACE_TYPE_CFF = 0, + DWRITE_FONT_FACE_TYPE_TRUETYPE = 1, + DWRITE_FONT_FACE_TYPE_OPENTYPE_COLLECTION = 2, + DWRITE_FONT_FACE_TYPE_TYPE1 = 3, + DWRITE_FONT_FACE_TYPE_VECTOR = 4, + DWRITE_FONT_FACE_TYPE_BITMAP = 5, + DWRITE_FONT_FACE_TYPE_UNKNOWN = 6, + DWRITE_FONT_FACE_TYPE_RAW_CFF = 7, + DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION = 2, +} DWRITE_FONT_FACE_TYPE; + +typedef enum DWRITE_FONT_SIMULATIONS { + DWRITE_FONT_SIMULATIONS_NONE = 0, + DWRITE_FONT_SIMULATIONS_BOLD = 1, + DWRITE_FONT_SIMULATIONS_OBLIQUE = 2, +} DWRITE_FONT_SIMULATIONS; + +typedef enum DWRITE_PIXEL_GEOMETRY { + DWRITE_PIXEL_GEOMETRY_FLAT = 0, + DWRITE_PIXEL_GEOMETRY_RGB = 1, + DWRITE_PIXEL_GEOMETRY_BGR = 2, +} DWRITE_PIXEL_GEOMETRY; + +typedef enum DWRITE_RENDERING_MODE { + DWRITE_RENDERING_MODE_DEFAULT = 0, + DWRITE_RENDERING_MODE_ALIASED = 1, + DWRITE_RENDERING_MODE_GDI_CLASSIC = 2, + DWRITE_RENDERING_MODE_GDI_NATURAL = 3, + DWRITE_RENDERING_MODE_NATURAL = 4, + DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC = 5, + DWRITE_RENDERING_MODE_OUTLINE = 6, + DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC = 2, + DWRITE_RENDERING_MODE_CLEARTYPE_GDI_NATURAL = 3, + DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL = 4, + DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC = 5, +} DWRITE_RENDERING_MODE; + +//- Structs +typedef struct DWRITE_FONT_METRICS { + UINT16 designUnitsPerEm; + UINT16 ascent; + UINT16 descent; + INT16 lineGap; + UINT16 capHeight; + UINT16 xHeight; + INT16 underlinePosition; + UINT16 underlineThickness; + INT16 strikethroughPosition; + UINT16 strikethroughThickness; +} DWRITE_FONT_METRICS; + +typedef struct DWRITE_GLYPH_OFFSET { + FLOAT advanceOffset; + FLOAT ascenderOffset; +} DWRITE_GLYPH_OFFSET; + +typedef struct DWRITE_GLYPH_RUN { + IDWriteFontFace* fontFace; + FLOAT fontEmSize; + UINT32 glyphCount; + UINT16* glyphIndices; + FLOAT* glyphAdvances; + DWRITE_GLYPH_OFFSET* glyphOffsets; + BOOL isSideways; + UINT32 bidiLevel; +} DWRITE_GLYPH_RUN; + +typedef struct DWRITE_GLYPH_METRICS { + INT32 leftSideBearing; + UINT32 advanceWidth; + INT32 rightSideBearing; + INT32 topSideBearing; + UINT32 advanceHeight; + INT32 bottomSideBearing; + INT32 verticalOriginY; +} DWRITE_GLYPH_METRICS; + +//- Methods +static inline HRESULT IDWriteFactory5_CreateInMemoryFontFileLoader (IDWriteFactory5* this, IDWriteInMemoryFontFileLoader** newLoader) { return ((HRESULT (WINAPI*)(IDWriteFactory5*, IDWriteInMemoryFontFileLoader**))this->v->tbl[44])(this, newLoader); } +static inline HRESULT IDWriteFactory5_RegisterFontFileLoader (IDWriteFactory5* this, IDWriteFontFileLoader* fontFileLoader) { return ((HRESULT (WINAPI*)(IDWriteFactory5*, IDWriteFontFileLoader*))this->v->tbl[13])(this, fontFileLoader); } +static inline HRESULT IDWriteFactory5_CreateFontFace (IDWriteFactory5* this, DWRITE_FONT_FACE_TYPE fontFaceType, UINT32 numberOfFiles, IDWriteFontFile** fontFiles, UINT32 faceIndex, DWRITE_FONT_SIMULATIONS fontFaceSimulationFlags, IDWriteFontFace** fontFace) { return ((HRESULT (WINAPI*)(IDWriteFactory5*, DWRITE_FONT_FACE_TYPE, UINT32, IDWriteFontFile**, UINT32, DWRITE_FONT_SIMULATIONS, IDWriteFontFace**))this->v->tbl[9])(this, fontFaceType, numberOfFiles, fontFiles, faceIndex, fontFaceSimulationFlags, fontFace); } +static inline HRESULT IDWriteFactory5_CreateRenderingParams (IDWriteFactory5* this, IDWriteRenderingParams** renderingParams) { return ((HRESULT (WINAPI*)(IDWriteFactory5*, IDWriteRenderingParams**))this->v->tbl[10])(this, renderingParams); } +static inline HRESULT IDWriteFactory5_CreateCustomRenderingParams (IDWriteFactory5* this, FLOAT gamma, FLOAT enhancedContrast, FLOAT clearTypeLevel, DWRITE_PIXEL_GEOMETRY pixelGeometry, DWRITE_RENDERING_MODE renderingMode, IDWriteRenderingParams** renderingParams) { return ((HRESULT (WINAPI*)(IDWriteFactory5*, FLOAT, FLOAT, FLOAT, DWRITE_PIXEL_GEOMETRY, DWRITE_RENDERING_MODE, IDWriteRenderingParams**))this->v->tbl[12])(this, gamma, enhancedContrast, clearTypeLevel, pixelGeometry, renderingMode, renderingParams); } +static inline HRESULT IDWriteFactory5_GetGdiInterop (IDWriteFactory5* this, IDWriteGdiInterop** gdiInterop) { return ((HRESULT (WINAPI*)(IDWriteFactory5*, IDWriteGdiInterop**))this->v->tbl[17])(this, gdiInterop); } +static inline UINT32 IDWriteFactory5_Release (IDWriteFactory5* this) { return ((UINT32 (WINAPI*)(IDWriteFactory5*))this->v->tbl[2])(this); } +static inline HRESULT IDWriteInMemoryFontFileLoader_CreateInMemoryFontFileReference(IDWriteInMemoryFontFileLoader* this, IDWriteFactory* factory, const void* fontData, UINT32 fontDataSize, IUnknown* ownerObject, IDWriteFontFile** fontFile) { return ((HRESULT (WINAPI*)(IDWriteInMemoryFontFileLoader*, IDWriteFactory*, const void*, UINT32, IUnknown*, IDWriteFontFile**))this->v->tbl[4])(this, factory, fontData, fontDataSize, ownerObject, fontFile); } +static inline HRESULT IDWriteFontSetBuilder1_AddFontFile (IDWriteFontSetBuilder1* this, IDWriteFontFile* fontFile) { return ((HRESULT (WINAPI*)(IDWriteFontSetBuilder1*, IDWriteFontFile*))this->v->tbl[7])(this, fontFile); } +static inline UINT32 IDWriteRenderingParams_Release (IDWriteRenderingParams* this) { return ((UINT32 (WINAPI*)(IDWriteRenderingParams*))this->v->tbl[2])(this); } +static inline FLOAT IDWriteRenderingParams_GetGamma (IDWriteRenderingParams* this) { return ((FLOAT (WINAPI*)(IDWriteRenderingParams*))this->v->tbl[3])(this); } +static inline HDC IDWriteBitmapRenderTarget_GetMemoryDC (IDWriteBitmapRenderTarget* this) { return ((HDC (WINAPI*)(IDWriteBitmapRenderTarget*))this->v->tbl[4])(this); } +static inline UINT32 IDWriteFontFile_Release (IDWriteFontFile* this) { return ((UINT32 (WINAPI*)(IDWriteFontFile*))this->v->tbl[2])(this); } +static inline HRESULT IDWriteFactory5_CreateFontSetBuilder1 (IDWriteFactory5* this, IDWriteFontSetBuilder1** fontSetBuilder) { return ((HRESULT (WINAPI*)(IDWriteFactory5*, IDWriteFontSetBuilder1**))this->v->tbl[43])(this, fontSetBuilder); }static inline FLOAT IDWriteRenderingParams_GetEnhancedContrast (IDWriteRenderingParams* this) { return ((FLOAT (WINAPI*)(IDWriteRenderingParams*))this->v->tbl[4])(this); } +static inline FLOAT IDWriteRenderingParams_GetClearTypeLevel (IDWriteRenderingParams* this) { return ((FLOAT (WINAPI*)(IDWriteRenderingParams*))this->v->tbl[5])(this); } +static inline void IDWriteFontFace_GetMetrics (IDWriteFontFace* this, DWRITE_FONT_METRICS* fontFaceMetrics) { ((void (WINAPI*)(IDWriteFontFace*, DWRITE_FONT_METRICS*))this->v->tbl[8])(this, fontFaceMetrics); } +static inline UINT16 IDWriteFontFace_GetGlyphCount (IDWriteFontFace* this) { return ((UINT16 (WINAPI*)(IDWriteFontFace*))this->v->tbl[9])(this); } +static inline HRESULT IDWriteGdiInterop_CreateBitmapRenderTarget (IDWriteGdiInterop* this, HDC hdc, UINT32 width, UINT32 height, IDWriteBitmapRenderTarget** renderTarget) { return ((HRESULT (WINAPI*)(IDWriteGdiInterop*, HDC, UINT32, UINT32, IDWriteBitmapRenderTarget**))this->v->tbl[7])(this, hdc, width, height, renderTarget); } +static inline HRESULT IDWriteBitmapRenderTarget_SetPixelsPerDip (IDWriteBitmapRenderTarget* this, FLOAT pixelsPerDip) { return ((HRESULT (WINAPI*)(IDWriteBitmapRenderTarget*, FLOAT))this->v->tbl[6])(this, pixelsPerDip); } +static inline HRESULT IDWriteBitmapRenderTarget_DrawGlyphRun (IDWriteBitmapRenderTarget* this, FLOAT baselineOriginX, FLOAT baselineOriginY, DWRITE_MEASURING_MODE measuringMode, const DWRITE_GLYPH_RUN* glyphRun, IDWriteRenderingParams* renderingParams, COLORREF textColor, RECT* blackBoxRect) { return ((HRESULT (WINAPI*)(IDWriteBitmapRenderTarget*, FLOAT, FLOAT, DWRITE_MEASURING_MODE, const DWRITE_GLYPH_RUN*, IDWriteRenderingParams*, COLORREF, RECT*))this->v->tbl[3])(this, baselineOriginX, baselineOriginY, measuringMode, glyphRun, renderingParams, textColor, blackBoxRect); } +static inline HRESULT IDWriteFontFace_GetDesignGlyphMetrics (IDWriteFontFace* this, const UINT16* glyphIndices, UINT32 glyphCount, DWRITE_GLYPH_METRICS* glyphMetrics, BOOL isSideways) { return ((HRESULT (WINAPI*)(IDWriteFontFace*, const UINT16*, UINT32, DWRITE_GLYPH_METRICS*, BOOL))this->v->tbl[10])(this, glyphIndices, glyphCount, glyphMetrics, isSideways); } +static inline HRESULT IDWriteFontFace_GetGlyphIndices (IDWriteFontFace* this, const UINT32* codePoints, UINT32 codePointCount, UINT16* glyphIndices) { return ((HRESULT (WINAPI*)(IDWriteFontFace*, const UINT32*, UINT32, UINT16*))this->v->tbl[11])(this, codePoints, codePointCount, glyphIndices); } +static inline UINT32 IDWriteGdiInterop_Release (IDWriteGdiInterop* this) { return ((UINT32 (WINAPI*)(IDWriteGdiInterop*))this->v->tbl[2])(this); } + //////////////////////////////// //~ Shared state