meta layer progress

This commit is contained in:
jacob 2025-08-24 18:08:41 -05:00
parent 86c24dd112
commit 0324866b9c
34 changed files with 671 additions and 340 deletions

View File

@ -7,7 +7,6 @@
@Dep gpu @Dep gpu
@Dep sprite @Dep sprite
@Dep watch @Dep watch
@Dep draw
@Dep sound @Dep sound
@Dep font @Dep font
@Dep asset_cache @Dep asset_cache

View File

@ -35,6 +35,3 @@
//- Win32 impl //- Win32 impl
@DefaultWindowsImpl base_win32 @DefaultWindowsImpl base_win32
//- Startup
@Startup StartupBaseJobs

View File

@ -1,6 +1,13 @@
#ifdef __cplusplus /* TODO: Remove this */
extern "C" { #define RtcIsEnabled 1
#endif #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 //~ Compiler feature flags
@ -59,14 +66,12 @@ extern "C" {
#endif #endif
//- Language //- Language
#if defined(__STDC_VERSION__) #if defined(__HLSL_VERSION)
# define LanguageIsC 1
# define LanguageIsGpu 0
#elif defined(__HLSL_VERSION)
# define LanguageIsC 0 # define LanguageIsC 0
# define LanguageIsGpu 1 # define LanguageIsGpu 1
#else #else
# error Unknown language # define LanguageIsC 1
# define LanguageIsGpu 0
#endif #endif
//- Operating system //- Operating system
@ -102,26 +107,37 @@ extern "C" {
#endif #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 //~ Debug
//- Static assert //- Static assert
#if CompilerIsMsvc || (LanguageIsC && __STDC_VERSION__ < 202311L) || LanguageIsGpu #if CompilerIsMsvc || (LanguageIsC && __STDC_VERSION__ < 202311L) || LanguageIsGpu
# if CompilerIsMsvc # if CompilerIsMsvc
# define StaticAssert2(cond, line) struct STATIC_ASSERT_____##line {int foo[(cond) ? 1 : -1];} # define StaticAssert2(cond, line, counter) struct STATIC_ASSERT_____##line##counter {int foo[(cond) ? 1 : -1];}
# define StaticAssert1(cond, line) StaticAssert2(cond, line) # define StaticAssert1(cond, line, counter) StaticAssert2(cond, line, counter)
# define StaticAssert(cond) StaticAssert1(cond, __LINE__) # define StaticAssert(cond) StaticAssert1(cond, __LINE__, __COUNTER__)
# else # else
# define StaticAssert(cond) _Static_assert(cond, "") # define StaticAssert(cond) _Static_assert(cond, "")
# endif # endif
#else #else
# define StaticAssert(c) static_assert(c, "") # define StaticAssert(cond) static_assert(cond, "")
#endif #endif
//- Debug assert //- Debug assert
#if RtcIsEnabled #if RtcIsEnabled
# if CompilerIsMsvc # 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 # define DEBUGBREAK __debugbreak
# else # else
# define Assert(cond) ((cond) ? 1 : (__builtin_trap(), 0)) # 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 NsFromSeconds(s) ((i64)((s) * 1000000000.0))
#define SecondsFromNs(ns) ((f64)(ns) / 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 //~ Type helper macros
@ -379,7 +453,6 @@ void __asan_unpoison_memory_region(void const volatile *add, size_t);
//~ Scalar types //~ Scalar types
#if LanguageIsC #if LanguageIsC
//- Cpu scalar types //- Cpu scalar types
#include "stdint.h" #include "stdint.h"
typedef int8_t i8; typedef int8_t i8;
@ -438,7 +511,6 @@ Global const f64 *_f64_nan = (f64 *)&_f64_nan_u64;
#define IsF32Nan(x) (x != x) #define IsF32Nan(x) (x != x)
#define IsF64Nan(x) (x != x) #define IsF64Nan(x) (x != x)
#endif #endif
//////////////////////////////// ////////////////////////////////
@ -453,8 +525,8 @@ Struct(Atomic32) { volatile i32 _v; };
Struct(Atomic64) { volatile i64 _v; }; Struct(Atomic64) { volatile i64 _v; };
//- Cache-line isolated aligned atomic types //- Cache-line isolated aligned atomic types
AlignedStruct(Atomic8Padded, 64) { Atomic8 v; u8 _pad[60]; }; AlignedStruct(Atomic8Padded, 64) { Atomic8 v; u8 _pad[63]; };
AlignedStruct(Atomic16Padded, 64) { Atomic16 v; u8 _pad[60]; }; AlignedStruct(Atomic16Padded, 64) { Atomic16 v; u8 _pad[62]; };
AlignedStruct(Atomic32Padded, 64) { Atomic32 v; u8 _pad[60]; }; AlignedStruct(Atomic32Padded, 64) { Atomic32 v; u8 _pad[60]; };
AlignedStruct(Atomic64Padded, 64) { Atomic64 v; u8 _pad[56]; }; AlignedStruct(Atomic64Padded, 64) { Atomic64 v; u8 _pad[56]; };
StaticAssert(sizeof(Atomic8Padded) == 64 && alignof(Atomic8Padded) == 64); StaticAssert(sizeof(Atomic8Padded) == 64 && alignof(Atomic8Padded) == 64);
@ -519,6 +591,41 @@ ForceInline void UnlockTicketMutex(TicketMutex *tm)
} }
#endif #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 //~ Fibers
@ -538,15 +645,28 @@ StaticAssert(MaxFibers < I16Max); /* Fiber id type should fit max fibers */
#endif #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 //~ Config
#include "../config.h" #include "../config.h"
#ifdef __cplusplus
}
#endif

View File

@ -9,7 +9,6 @@ typedef ExitFuncDef(ExitFunc);
void OnExit(ExitFunc *func); void OnExit(ExitFunc *func);
void Exit(void); void Exit(void);
void Panic(String msg);
//////////////////////////////// ////////////////////////////////
//~ @hookdecl Application defined hooks //~ @hookdecl Application defined hooks

View File

@ -1,17 +1,10 @@
#if CompilerIsMsvc #if CompilerIsMsvc
////////////////////////////////
//~ Windows headers
#define WIN32_LEAN_AND_MEAN
#define UNICODE
#include <Windows.h>
//////////////////////////////// ////////////////////////////////
//~ Incbin //~ Incbin
/* Find first resource with `type` and return the data in `udata`. */ /* 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(); TempArena scratch = BeginScratchNoConflict();
IncbinRcSearchParams *params = (IncbinRcSearchParams *)udata; IncbinRcSearchParams *params = (IncbinRcSearchParams *)udata;

View File

@ -97,6 +97,5 @@ void RunJobEx(GenericJobDesc *desc);
//~ @hookdecl Helpers //~ @hookdecl Helpers
i64 TimeNs(void); i64 TimeNs(void);
u32 ThreadId(void);
u32 GetLogicalProcessorCount(void); u32 GetLogicalProcessorCount(void);
i64 GetCurrentSchedulerPeriodNs(void); i64 GetCurrentSchedulerPeriodNs(void);

View File

@ -3,11 +3,6 @@
#if PlatformIsWindows #if PlatformIsWindows
//- Windows headers
#define WIN32_LEAN_AND_MEAN
#define UNICODE
#include <Windows.h>
//- Reserve //- Reserve
void *ReserveMemory(u64 size) void *ReserveMemory(u64 size)
{ {
@ -47,12 +42,16 @@ void SetMemoryReadWrite(void *address, u64 size)
#else #else
# error Memory allocation not implemented for this platform # 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 *dst_pchar = dst;
char *src_pchar = src; char *src_pchar = src;
@ -63,7 +62,9 @@ void *CopyBytes(void *dst, void *src, u64 count)
return dst; 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; char *dst_pchar = dst;
for (u64 i = 0; i < count; ++i) for (u64 i = 0; i < count; ++i)
@ -73,7 +74,9 @@ void *SetBytes(void *dst, u8 c, u64 count)
return dst; 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; i32 result = 0;
char *p1_pchar = p1; char *p1_pchar = p1;
@ -89,30 +92,4 @@ i32 CmpBytes(void *p1, void *p2, u64 count)
return result; 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 */ #endif /* !CrtlibIsEnabled */

View File

@ -24,9 +24,9 @@ void SetMemoryReadWrite(void *address, u64 size);
#define ZeroBytes(ptr, count) SetBytes((ptr), 0, (count)) #define ZeroBytes(ptr, count) SetBytes((ptr), 0, (count))
#define EqBytes(p1, p2, n) (CmpBytes((p1), (p2), (n)) == 0) #define EqBytes(p1, p2, n) (CmpBytes((p1), (p2), (n)) == 0)
void *CopyBytes(void *dst, void *src, u64 count); #define CopyBytes(dst, src, count) memcpy(dst, src, count)
void *SetBytes(void *dst, u8 c, u64 count); #define SetBytes(dst, c, count) memset(dst, c, count)
i32 CmpBytes(void *p1, void *p2, u64 count); #define CmpBytes(p1, p2, count) memcmp(p1, p2, count)
//////////////////////////////// ////////////////////////////////
//~ Crtlib stubs //~ Crtlib stubs

View File

@ -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 //~ Stateful randomness

View File

@ -13,9 +13,6 @@ Struct(RandState)
//////////////////////////////// ////////////////////////////////
//~ Rand operations //~ Rand operations
//- True randomness
void TrueRand(String buffer);
//- Stateful randomness //- Stateful randomness
u64 RandU64FromState(RandState *state); u64 RandU64FromState(RandState *state);
f64 RandF64FromState(RandState *state, f64 range_start, f64 range_end); f64 RandF64FromState(RandState *state, f64 range_start, f64 range_end);

View File

@ -1,5 +1,5 @@
//////////////////////////////// ////////////////////////////////
//~ Conversion //~ Conversion helpers
//- Char conversion //- 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 //- Copy
@ -455,6 +432,45 @@ b32 StringEndsWith(String str, String substring)
return 0; 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 //~ Formatting
@ -476,8 +492,6 @@ b32 StringEndsWith(String str, String substring)
* FmtFloatP: Format an f64 with specified precision * FmtFloatP: Format an f64 with specified precision
* FmtHex: Format a u64 in hexadecimal notation * FmtHex: Format a u64 in hexadecimal notation
* FmtPtr: Format a pointer in hexadecimal notation prefixed by "0x" * 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 * 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); parsed_str = StringFromF64(arena, arg.value.f, arg.precision);
} break; } 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: case FmtKind_End:
{ {
/* Unexpected end. Not enough FMT args passed to function. */ /* Unexpected end. Not enough FMT args passed to function. */

View File

@ -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 //~ Formatting types
@ -16,8 +39,8 @@ typedef i32 FmtKind; enum
FmtKind_Hex = 0x0a3d0792, FmtKind_Hex = 0x0a3d0792,
FmtKind_Ptr = 0x0c4519e4, FmtKind_Ptr = 0x0c4519e4,
FmtKind_Float = 0x04814143, FmtKind_Float = 0x04814143,
FmtKind_Handle = 0x0f112992, FmtKind_Uid = 0x9d1cd407,
FmtKind_Uid = 0x0beb23dd, FmtKind_Handle = 0xfead3bec,
FmtKind_End = 0x0ecbc5ae FmtKind_End = 0x0ecbc5ae
}; };
@ -35,11 +58,11 @@ Struct(FmtArg)
i64 sint; i64 sint;
void *ptr; void *ptr;
f64 f; f64 f;
Uid uid;
struct struct
{ {
u64 h64[2]; u64 h64[2];
} handle; } handle;
Uid uid;
} value; } value;
}; };
@ -56,32 +79,16 @@ Struct(CodepointIter)
}; };
//////////////////////////////// ////////////////////////////////
//~ String utils //~ Conversion helpers
#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
String StringFromChar(Arena *arena, char c); String StringFromChar(Arena *arena, char c);
String StringFromU64(Arena *arena, u64 n, u64 base, u64 zfill); String StringFromU64(Arena *arena, u64 n, u64 base, u64 zfill);
String StringFromI64(Arena *arena, i64 n, u64 base, u64 zfill); String StringFromI64(Arena *arena, i64 n, u64 base, u64 zfill);
String StringFromPtr(Arena *arena, void *ptr); String StringFromPtr(Arena *arena, void *ptr);
String StringFromF64(Arena *arena, f64 f, u32 precision); 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 PushString(Arena *arena, String src);
String PushStringToBuff(String dst, 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 StringStartsWith(String str, String substring);
b32 StringEndsWith(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 //~ Formatting
@ -114,6 +127,7 @@ b32 StringEndsWith(String str, String substring);
#define FmtEnd (FmtArg) {.kind = FmtKind_End} #define FmtEnd (FmtArg) {.kind = FmtKind_End}
//- Format functions //- Format functions
#define StringF(arena, lit, ...) _StringFormat((arena), Lit(lit), __VA_ARGS__, FmtEnd)
#define StringFormat(arena, fmt, ...) _StringFormat((arena), (fmt), __VA_ARGS__, FmtEnd) #define StringFormat(arena, fmt, ...) _StringFormat((arena), (fmt), __VA_ARGS__, FmtEnd)
String _StringFormat(Arena *arena, String fmt, ...); String _StringFormat(Arena *arena, String fmt, ...);
String StringFormatV(Arena *arena, String fmt, va_list args); String StringFormatV(Arena *arena, String fmt, va_list args);

View File

@ -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 <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
////////////////////////////////
//~ 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

View File

@ -0,0 +1,9 @@
////////////////////////////////
//~ Shared state
Struct(W32_SharedState)
{
DWORD tls_index;
};
extern W32_SharedState W32_shared_state;

View File

@ -1,9 +1,11 @@
@Layer base_win32 @Layer base_win32
//- Api //- Api
@IncludeC base_win32.h
@IncludeC base_win32_entry.h @IncludeC base_win32_entry.h
@IncludeC base_win32_job.h @IncludeC base_win32_job.h
//- Impl //- Impl
@IncludeC base_win32.c
@IncludeC base_win32_entry.c @IncludeC base_win32_entry.c
@IncludeC base_win32_job.c @IncludeC base_win32_job.c

View File

@ -3,18 +3,18 @@ W32_SharedEntryCtx W32_shared_entry_ctx = ZI;
//////////////////////////////// ////////////////////////////////
//~ Startup / shutdown jobs //~ Startup / shutdown jobs
JobDef(W32_AppStartupJob, UNUSED sig, UNUSED id) JobDef(W32_StartupLayersJob, UNUSED sig, UNUSED id)
{ {
W32_SharedEntryCtx *g = &W32_shared_entry_ctx; W32_SharedEntryCtx *g = &W32_shared_entry_ctx;
TempArena scratch = BeginScratchNoConflict(); TempArena scratch = BeginScratchNoConflict();
{ {
Startup(); StartupLayers();
SetEvent(g->startup_end_event); SetEvent(g->startup_end_event);
} }
EndScratch(scratch); EndScratch(scratch);
} }
JobDef(W32_AppShutdownJob, UNUSED sig, UNUSED id) JobDef(W32_ShutdownLayersJob, UNUSED sig, UNUSED id)
{ {
__prof; __prof;
W32_SharedEntryCtx *g = &W32_shared_entry_ctx; W32_SharedEntryCtx *g = &W32_shared_entry_ctx;
@ -48,60 +48,6 @@ void Exit(void)
SetEvent(g->exit_begin_event); 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 //~ Winmain
@ -205,15 +151,13 @@ int CALLBACK wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance,
/* Query system info */ /* Query system info */
GetSystemInfo(&g->info); GetSystemInfo(&g->info);
/* Initialize base layer */ //- Startup jobs
BaseMain(); StartupBaseJobs();
//- App startup /* Startup layers */
/* Run app start job */
if (!Atomic32Fetch(&g->panicking)) 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 */ /* 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 */ /* Run exit callbacks job */
if (!Atomic32Fetch(&g->panicking)) 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 */ /* Wait for exit end or panic */

View File

@ -29,5 +29,5 @@ extern W32_SharedEntryCtx W32_shared_entry_ctx;
//////////////////////////////// ////////////////////////////////
//~ Startup / shutdown jobs //~ Startup / shutdown jobs
JobDecl(W32_AppStartupJob, EmptySig); JobDecl(W32_StartupLayersJob, EmptySig);
JobDecl(W32_AppShutdownJob, EmptySig); JobDecl(W32_ShutdownLayersJob, EmptySig);

View File

@ -1518,11 +1518,6 @@ i64 TimeNs(void)
return result; return result;
} }
u32 ThreadId(void)
{
return GetCurrentThreadId();
}
u32 GetLogicalProcessorCount(void) u32 GetLogicalProcessorCount(void)
{ {
return GetActiveProcessorCount(ALL_PROCESSOR_GROUPS); return GetActiveProcessorCount(ALL_PROCESSOR_GROUPS);

View File

@ -2,9 +2,6 @@
//~ Win32 headers //~ Win32 headers
#pragma warning(push, 0) #pragma warning(push, 0)
# define UNICODE
# define WIN32_LEAN_AND_MEAN
# include <Windows.h>
# include <WinSock2.h> # include <WinSock2.h>
# include <TlHelp32.h> # include <TlHelp32.h>
# include <WS2tcpip.h> # include <WS2tcpip.h>

View File

@ -87,9 +87,8 @@
#define PROF_THREAD_GROUP_WINDOW -(i64)Mebi(2) #define PROF_THREAD_GROUP_WINDOW -(i64)Mebi(2)
#define PROF_THREAD_GROUP_MAIN -(i64)Mebi(1) #define PROF_THREAD_GROUP_MAIN -(i64)Mebi(1)
/* ========================== * ////////////////////////////////
* Settings //~ Settings
* ========================== */
/* TODO: Move these to user-configurable settings */ /* TODO: Move these to user-configurable settings */

View File

@ -48,7 +48,15 @@ JobDef(F_LoadJob, sig, _)
RES_CloseResource(&res); RES_CloseResource(&res);
/* Send texture to GPU */ /* 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 */ /* Acquire store memory */
F_Font *font = 0; F_Font *font = 0;

View File

@ -543,9 +543,14 @@ L_Topo L_TopoFromLayerName(Arena *arena, StringList starting_layer_names, String
} }
else else
{ {
/* Push blob impls */ /* Push platform impls */
#if PlatformIsWindows {
for (L_BlobItem *impl_item = blob->default_windows_impls.first; impl_item; impl_item = impl_item->next) L_BlobItemList platform_impls = ZI;
if (PlatformIsWindows)
{
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; String impl_name = impl_item->s;
u64 impl_hash = HashFnv64(Fnv64Basis, impl_name); u64 impl_hash = HashFnv64(Fnv64Basis, impl_name);
@ -566,7 +571,7 @@ L_Topo L_TopoFromLayerName(Arena *arena, StringList starting_layer_names, String
L_PushTopoItem(arena, &result.errors, file, impl_item->token_pos, StringF(arena, "Layer '%F' not found", FmtString(impl_name))); L_PushTopoItem(arena, &result.errors, file, impl_item->token_pos, StringF(arena, "Layer '%F' not found", FmtString(impl_name)));
} }
} }
#endif }
/* Push blob exit */ /* Push blob exit */
{ {
entered_blobs[blob->id] = 1; 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 main(i32 argc, u8 **argv)
{ {
i32 ret = 0;
//- Startup //- Startup
StartupBase(); StartupBase();
OS_Startup(); OS_Startup();
@ -761,7 +768,8 @@ i32 main(i32 argc, u8 **argv)
String file = StringF(arena, "%F%F", FmtString(parent), FmtString(item->s)); String file = StringF(arena, "%F%F", FmtString(parent), FmtString(item->s));
if (F_IsFile(file)) 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); PushStringToList(arena, &c_out_lines, line);
} }
else else
@ -772,7 +780,6 @@ i32 main(i32 argc, u8 **argv)
} }
String c_out = StringFromStringList(arena, c_out_lines, Lit("\n")); String c_out = StringFromStringList(arena, c_out_lines, Lit("\n"));
F_ClearWrite(Lit("gen.c"), c_out); F_ClearWrite(Lit("gen.c"), c_out);
Echo(c_out);
} }
//- Print errors //- Print errors
@ -802,10 +809,19 @@ i32 main(i32 argc, u8 **argv)
} }
//- Compile //- Compile
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)
{ {
String cmd = Lit("\"cl\" /Zi /DEBUG src/build/tmp/gen.c /Fo:build/tmp/gen.obj /Fe:build/pp.exe /nologo"); }
OS_RunCommand(cmd); else
{
ret = result.code;
}
Echo(result.output);
} }
return errors.count > 0; return ret != 0 ? ret : errors.count > 0;
} }

View File

@ -100,6 +100,16 @@
#endif #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 //~ Debug
@ -609,6 +619,24 @@ Struct(String32)
u32 *text; 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 //~ @hookdecl Core hooks

View File

@ -1,15 +1,8 @@
////////////////////////////////
//~ Win32 memory allocation
#if PlatformIsWindows #if PlatformIsWindows
////////////////////////////////
//~ Windows headers
#define WIN32_LEAN_AND_MEAN
#define UNICODE
#include <Windows.h>
////////////////////////////////
//~ Memory allocation
//- Reserve //- Reserve
void *ReserveMemory(u64 size) void *ReserveMemory(u64 size)
{ {

View File

@ -1,12 +1,3 @@
////////////////////////////////
//~ Windows headers
#pragma warning(push, 0)
# define UNICODE
# define WIN32_LEAN_AND_MEAN
# include <Windows.h>
#pragma warning(pop)
//////////////////////////////// ////////////////////////////////
//~ Shared state //~ Shared state

View File

@ -15,6 +15,15 @@ Struct(OS_File)
u64 handle; u64 handle;
}; };
////////////////////////////////
//~ Command types
Struct(OS_CommandResult)
{
i32 code;
String output;
};
//////////////////////////////// ////////////////////////////////
//~ @hookdecl Startup hooks //~ @hookdecl Startup hooks
@ -41,4 +50,4 @@ void OS_Mkdir(String path);
//////////////////////////////// ////////////////////////////////
//~ @hookdecl Shell operations //~ @hookdecl Shell operations
void OS_RunCommand(String cmd); OS_CommandResult OS_RunCommand(Arena *arena, String cmd);

View File

@ -95,9 +95,11 @@ void OS_DirContentsFromFullPath(Arena *arena, StringList *list, String path)
wchar_t *filter_wstr = WstrFromString(scratch.arena, filter); 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); 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; b32 found = find_handle && find_handle != INVALID_HANDLE_VALUE;
while (found) { while (found)
{
String file_name = StringFromWstrNoLimit(arena, find_data.cFileName); 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); PushStringToList(arena, list, file_name);
} }
found = FindNextFileW(find_handle, &find_data); found = FindNextFileW(find_handle, &find_data);
@ -158,6 +160,76 @@ b32 OS_DirExists(String path)
//////////////////////////////// ////////////////////////////////
//~ @hookdef Shell hooks //~ @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;
} }

View File

@ -2,10 +2,6 @@
//~ Windows headers //~ Windows headers
#pragma warning(push, 0) #pragma warning(push, 0)
# define COBJMACROS
# define WIN32_LEAN_AND_MEAN
# define UNICODE
# include <Windows.h>
# include <uuids.h> # include <uuids.h>
# include <mfapi.h> # include <mfapi.h>
# include <mfidl.h> # include <mfidl.h>

View File

@ -408,13 +408,6 @@ String P_GetClipboardText(Arena *arena);
void P_SleepPrecise(i64 sleep_time_ns); void P_SleepPrecise(i64 sleep_time_ns);
void P_SleepFrame(i64 last_frame_time_ns, i64 target_dt_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) //~ @hookdecl Entry point (implemented per application)

View File

@ -2,9 +2,6 @@
//~ Win32 headers //~ Win32 headers
#pragma warning(push, 0) #pragma warning(push, 0)
# define UNICODE
# define WIN32_LEAN_AND_MEAN
# include <Windows.h>
# include <WinSock2.h> # include <WinSock2.h>
# include <TlHelp32.h> # include <TlHelp32.h>
# include <WS2tcpip.h> # include <WS2tcpip.h>

View File

@ -2,10 +2,6 @@
//~ Win32 headers //~ Win32 headers
#pragma warning(push, 0) #pragma warning(push, 0)
# define COBJMACROS
# define WIN32_LEAN_AND_MEAN
# define UNICODE
# include <Windows.h>
# include <initguid.h> # include <initguid.h>
# include <objbase.h> # include <objbase.h>
# include <uuids.h> # include <uuids.h>

View File

@ -6,7 +6,6 @@
@Dep sprite @Dep sprite
@Dep font @Dep font
@Dep collider @Dep collider
@Dep draw
@Dep net @Dep net
@Dep mixer @Dep mixer
@Dep bitbuff @Dep bitbuff

View File

@ -6,19 +6,11 @@ extern TTF_DW_SharedState TTF_DW_shared_state = ZI;
//////////////////////////////// ////////////////////////////////
//~ Win32 libs //~ Win32 libs
#define WIN32_LEAN_AND_MEAN
#define UNICODE
#pragma warning(push, 0)
# include <Windows.h>
# include <dwrite.h>
# include <dwrite_3.h>
#pragma warning(pop)
#pragma comment(lib, "dwrite") #pragma comment(lib, "dwrite")
#pragma comment(lib, "gdi32") #pragma comment(lib, "gdi32")
//////////////////////////////// ////////////////////////////////
//~ Startup //~ @hookdef Startup
/* Call this during font system startup */ /* Call this during font system startup */
void TTF_StartupCore(void) void TTF_StartupCore(void)
@ -36,7 +28,7 @@ void TTF_StartupCore(void)
#endif #endif
HRESULT error = DWriteCreateFactory( HRESULT error = DWriteCreateFactory(
DWRITE_FACTORY_TYPE_SHARED, DWRITE_FACTORY_TYPE_SHARED,
__uuidof(IDWriteFactory5), &IID_IDWriteFactory5,
(IUnknown **)&g->factory (IUnknown **)&g->factory
); );
#if CompilerIsClang #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) TTF_Result TTF_Decode(Arena *arena, String encoded, f32 point_size, u32 *cache_codes, u32 cache_codes_count)
{ {
@ -71,27 +63,27 @@ TTF_Result TTF_Decode(Arena *arena, String encoded, f32 point_size, u32 *cache_c
{ {
/* Create in memory loader */ /* Create in memory loader */
IDWriteInMemoryFontFileLoader *loader = 0; IDWriteInMemoryFontFileLoader *loader = 0;
error = factory->CreateInMemoryFontFileLoader(&loader); error = IDWriteFactory5_CreateInMemoryFontFileLoader(factory, &loader);
error = factory->RegisterFontFileLoader(loader); error = IDWriteFactory5_RegisterFontFileLoader(factory, (IDWriteFontFileLoader *)loader);
IDWriteFontSetBuilder1 *builder = 0; IDWriteFontSetBuilder1 *builder = 0;
error = factory->CreateFontSetBuilder(&builder); error = IDWriteFactory5_CreateFontSetBuilder1(factory, &builder);
error = loader->CreateInMemoryFontFileReference(factory, encoded.text, (u32)encoded.len, 0, &font_file); error = IDWriteInMemoryFontFileLoader_CreateInMemoryFontFileReference(loader, (IDWriteFactory *)factory, encoded.text, (u32)encoded.len, 0, &font_file);
error = builder->AddFontFile(font_file); error = IDWriteFontSetBuilder1_AddFontFile(builder, font_file);
} }
//- Create face //- Create face
IDWriteFontFace *font_face = 0; 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 //- Setup rendering params
IDWriteRenderingParams *default_rendering_params = 0; IDWriteRenderingParams *default_rendering_params = 0;
error = factory->CreateRenderingParams(&default_rendering_params); error = IDWriteFactory5_CreateRenderingParams(factory, &default_rendering_params);
IDWriteRenderingParams *rendering_params = 0; IDWriteRenderingParams *rendering_params = 0;
FLOAT gamma = default_rendering_params->GetGamma(); FLOAT gamma = IDWriteRenderingParams_GetGamma(default_rendering_params);
FLOAT enhanced_contrast = default_rendering_params->GetEnhancedContrast(); FLOAT enhanced_contrast = IDWriteRenderingParams_GetEnhancedContrast(default_rendering_params);
FLOAT clear_type_level = default_rendering_params->GetClearTypeLevel(); FLOAT clear_type_level = IDWriteRenderingParams_GetClearTypeLevel(default_rendering_params);
error = factory->CreateCustomRenderingParams(gamma, error = IDWriteFactory5_CreateCustomRenderingParams(factory, gamma,
enhanced_contrast, enhanced_contrast,
clear_type_level, clear_type_level,
DWRITE_PIXEL_GEOMETRY_FLAT, DWRITE_PIXEL_GEOMETRY_FLAT,
@ -100,13 +92,13 @@ TTF_Result TTF_Decode(Arena *arena, String encoded, f32 point_size, u32 *cache_c
//- Setup interop //- Setup interop
IDWriteGdiInterop *dwrite_gdi_interop = 0; IDWriteGdiInterop *dwrite_gdi_interop = 0;
error = factory->GetGdiInterop(&dwrite_gdi_interop); error = IDWriteFactory5_GetGdiInterop(factory, &dwrite_gdi_interop);
//- Get metrics //- Get metrics
DWRITE_FONT_METRICS metrics = ZI; 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_em = point_size * (TTF_DW_Dpi / 72.0f);
f32 pixel_per_design_unit = pixel_per_em / ((f32)metrics.designUnitsPerEm); 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 //- Setup render target
IDWriteBitmapRenderTarget *render_target = 0; IDWriteBitmapRenderTarget *render_target = 0;
/* FIXME: errors when point_size too high */ /* FIXME: errors when point_size too high */
error = dwrite_gdi_interop->CreateBitmapRenderTarget(0, (UINT32)raster_target_w, (UINT32)raster_target_h, &render_target); error = IDWriteGdiInterop_CreateBitmapRenderTarget(dwrite_gdi_interop, 0, (UINT32)raster_target_w, (UINT32)raster_target_h, &render_target);
render_target->SetPixelsPerDip(1.0); IDWriteBitmapRenderTarget_SetPixelsPerDip(render_target, 1.0);
/* Clear the render target */ /* Clear the render target */
HDC dc = 0; HDC dc = 0;
{ {
dc = render_target->GetMemoryDC(); dc = IDWriteBitmapRenderTarget_GetMemoryDC(render_target);
HGDIOBJ original = SelectObject(dc, GetStockObject(DC_PEN)); HGDIOBJ original = SelectObject(dc, GetStockObject(DC_PEN));
SetDCPenColor(dc, bg_color); SetDCPenColor(dc, bg_color);
SelectObject(dc, GetStockObject(DC_BRUSH)); 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; glyph_run.glyphIndices = &i;
RECT bounding_box = ZI; RECT bounding_box = ZI;
error = render_target->DrawGlyphRun( error = IDWriteBitmapRenderTarget_DrawGlyphRun(render_target,
raster_target_x, raster_target_x,
raster_target_y, raster_target_y,
DWRITE_MEASURING_MODE_NATURAL, 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 //- Compute glyph metrics
DWRITE_GLYPH_METRICS glyph_metrics = ZI; 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_x = (f32)bounding_box.left - raster_target_x;
f32 off_y = (f32)bounding_box.top - raster_target_y; 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) */ /* 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.x = (f32)out_offset_x;
glyph->atlas_rect.y = (f32)out_offset_y; glyph->atlas_rect.y = (f32)out_offset_y;
glyph->atlas_rect.width = (f32)tex_w; 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) if (cache_codes_count > 0)
{ {
cache_indices = PushStructs(arena, u16, cache_codes_count); 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 //- Release
/* FIXME: Check for leaks */ /* FIXME: Check for leaks */
dwrite_gdi_interop->Release(); IDWriteGdiInterop_Release(dwrite_gdi_interop);
rendering_params->Release(); IDWriteRenderingParams_Release(rendering_params);
default_rendering_params->Release(); 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 // 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(); // IDWriteFontFace_Release(font_face);
font_file->Release(); IDWriteFontFile_Release(font_file);
//loader->Release(); //loader->Release();
factory->Release(); IDWriteFactory5_Release(factory);
/* Return */ /* Return */
TTF_Result result = ZI; TTF_Result result = ZI;

View File

@ -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 <combaseapi.h>
#include <dcommon.h>
#include <initguid.h>
//- 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 //~ Shared state