sprite refactor progress

This commit is contained in:
jacob 2025-09-04 00:05:24 -05:00
parent 4cb7006de9
commit b14ce157b8
44 changed files with 1813 additions and 1147 deletions

View File

@ -4,8 +4,9 @@ cd /D "%~dp0"
if not exist build mkdir build
pushd build
for %%a in (%*) do set "%%a=1"
set program_build_cmd=meta.exe %*
set meta_build_cmd=cl.exe ../src/meta/meta.c /Od /Z7 /nologo /diagnostics:column /link /DEBUG:FULL /INCREMENTAL:NO
set meta_build_cmd=cl.exe ../src/meta/meta.c /Od /Z7 /nologo /diagnostics:column /WX /link /DEBUG:FULL /INCREMENTAL:NO
set meta_rebuild_code=1317212284
::- Meta build
@ -20,6 +21,7 @@ if not exist meta.exe (
)
::- Program build
if not "%norun%"=="1" (
echo ======== Build ========
%program_build_cmd%
set "rc=!errorlevel!"
@ -30,3 +32,4 @@ if !rc! NEQ 0 (
)
exit /b !rc!
)
)

View File

@ -489,7 +489,7 @@ ASE_DecodedImage ASE_DecodeImage(Arena *arena, String encoded)
TempArena scratch = BeginScratch(arena);
ASE_DecodedImage result = ZI;
BB_Buff bb = BitbuffFromString(encoded);
BB_Buff bb = BB_BuffFromString(encoded);
BB_Reader br = BB_ReaderFromBuffNoDebug(&bb);
ASE_Header ase_header;
BB_ReadBytes(&br, StringFromStruct(&ase_header));
@ -559,7 +559,7 @@ ASE_DecodedImage ASE_DecodeImage(Arena *arena, String encoded)
{
default:
{
BB_SeekToByte(&br, chunk_end_pos);
BB_ReadSeekToByte(&br, chunk_end_pos);
} break;
//- Decode layer
@ -574,7 +574,7 @@ ASE_DecodedImage ASE_DecodeImage(Arena *arena, String encoded)
layer->child_level = BB_ReadUBits(&br, 16);
/* Ignoring layer default width & height */
BB_SeekBytes(&br, sizeof(u16) * 2);
BB_ReadSeekBytes(&br, sizeof(u16) * 2);
layer->blend_mode = BB_ReadUBits(&br, 16);
if (layer->blend_mode != 0)
@ -591,7 +591,7 @@ ASE_DecodedImage ASE_DecodeImage(Arena *arena, String encoded)
layer->opacity = 255;
}
BB_SeekBytes(&br, sizeof(u8) * 3);
BB_ReadSeekBytes(&br, sizeof(u8) * 3);
u16 str_len = BB_ReadUBits(&br, 16);
layer->name = (String) { str_len, PushStructsNoZero(scratch.arena, u8, str_len) };
@ -625,7 +625,7 @@ ASE_DecodedImage ASE_DecodeImage(Arena *arena, String encoded)
cel->opacity = BB_ReadUBits(&br, 8);
cel->type = BB_ReadUBits(&br, 16);
cel->z_index = BB_ReadIBits(&br, 16);
BB_SeekBytes(&br, sizeof(u8) * 5);
BB_ReadSeekBytes(&br, sizeof(u8) * 5);
cel->frame_index = num_frames;
@ -634,7 +634,7 @@ ASE_DecodedImage ASE_DecodeImage(Arena *arena, String encoded)
case ASE_CelKind_RawImage:
{
/* Unsupported */
BB_SeekToByte(&br, chunk_end_pos);
BB_ReadSeekToByte(&br, chunk_end_pos);
} break;
case ASE_CelKind_Linked:
@ -783,7 +783,7 @@ ASE_DecodedSheet ASE_DecodeSheet(Arena *arena, String encoded)
ASE_DecodedSheet result = ZI;
BB_Buff bb = BitbuffFromString(encoded);
BB_Buff bb = BB_BuffFromString(encoded);
BB_Reader br = BB_ReaderFromBuffNoDebug(&bb);
ASE_Header ase_header;
BB_ReadBytes(&br, StringFromStruct(&ase_header));
@ -857,14 +857,14 @@ ASE_DecodedSheet ASE_DecodeSheet(Arena *arena, String encoded)
{
default:
{
BB_SeekToByte(&br, chunk_end_pos);
BB_ReadSeekToByte(&br, chunk_end_pos);
} break;
//- Decode tags
case ASE_ChunkKind_Tags:
{
u16 frame_span_count = BB_ReadUBits(&br, 16);
BB_SeekBytes(&br, 8);
BB_ReadSeekBytes(&br, 8);
for (u16 k = 0; k < frame_span_count; ++k)
{
@ -874,7 +874,7 @@ ASE_DecodedSheet ASE_DecodeSheet(Arena *arena, String encoded)
span->start = BB_ReadUBits(&br, 16);
span->end = BB_ReadUBits(&br, 16);
BB_SeekBytes(&br, 13);
BB_ReadSeekBytes(&br, 13);
u16 str_len = BB_ReadUBits(&br, 16);
span->name = (String) { str_len, PushStructsNoZero(arena, u8, str_len) };
@ -896,7 +896,7 @@ ASE_DecodedSheet ASE_DecodeSheet(Arena *arena, String encoded)
slice_key->num_slices = num_slices;
u32 flags = BB_ReadUBits(&br, 32);
BB_SeekBytes(&br, 4);
BB_ReadSeekBytes(&br, 4);
u16 str_len = BB_ReadUBits(&br, 16);
slice_key->name = (String) { str_len, PushStructsNoZero(arena, u8, str_len) };
@ -916,12 +916,12 @@ ASE_DecodedSheet ASE_DecodeSheet(Arena *arena, String encoded)
if (flags & 0x01)
{
/* Skip 9-patches info */
BB_SeekBytes(&br, 128);
BB_ReadSeekBytes(&br, 128);
}
if (flags & 0x02)
{
/* Skip pivot info */
BB_SeekBytes(&br, 64);
BB_ReadSeekBytes(&br, 64);
}
slice->start = start;

View File

@ -1,8 +1,5 @@
@Layer ase
//- Dependencies
@Dep bitbuff
//- Api
@IncludeC ase.h

View File

@ -81,6 +81,17 @@
# error Unknown platform
#endif
//- Architecture
# if defined(_M_AMD64) || defined(__amd64__)
# define ArchIsX64 1
# define ArchIsArm64 0
# elif defined(_M_ARM64) || defined(__aarch64__)
# define ArchIsX64 0
# define ArchIsArm64 1
# else
# error Unknown architecture
# endif
//- Windows NTDDI version
/* TODO: Remove this */
#if 0
@ -118,8 +129,7 @@
//- Debug assert
#if RtcIsEnabled
# if CompilerIsMsvc
// # define Assert(cond) ((cond) ? 1 : (IsRunningInDebugger() ? (*(volatile i32 *)0 = 0) : Panic(Lit("Assert(" #cond ") failed at " __FILE__ ":" Stringize(__LINE__)))))
# define Assert(cond) ((cond) ? 1 : (IsRunningInDebugger() ? (*(volatile i32 *)0 = 0) : Panic(Lit(__FILE__ "(" Stringize(__LINE__) "): error Assert("#cond")"))))
# define Assert(cond) ((cond) ? 1 : (IsRunningInDebugger() ? (*(volatile i32 *)0 = 0) : Panic(Lit(__FILE__ ":" Stringize(__LINE__) ":0: assertion failed: "#cond""))))
# define DEBUGBREAK __debugbreak
# else
# define Assert(cond) ((cond) ? 1 : (__builtin_trap(), 0))
@ -268,29 +278,35 @@ void __asan_unpoison_memory_region(void const volatile *add, size_t);
#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)
#define StackPush_N(f,n,next) ((n)->next=(f), (f)=(n))
#define StackPop_N(f,next) ((f)=(f)->next)
#define StackPush(f,n) StackPush_N(f,n,next)
#define StackPop(f) StackPop_N(f,next)
//- Singly linked list queue (first, last, & next pointers)
#define SllQueuePush_NZ(nil,f,l,n,next) (CheckNil(nil,f)?\
#define QueuePush_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)?\
#define QueuePushFront_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)?\
#define QueuePop_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)
#define QueuePush_N(f,l,n,next) QueuePush_NZ(0,f,l,n,next)
#define QueuePushFront_N(f,l,n,next) QueuePushFront_NZ(0,f,l,n,next)
#define QueuePop_N(f,l,next) QueuePop_NZ(0,f,l,next)
#define QueuePush(f,l,n) QueuePush_NZ(0,f,l,n,next)
#define QueuePushFront(f,l,n) QueuePushFront_NZ(0,f,l,n,next)
#define QueuePop(f,l) QueuePop_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) ? \
@ -298,14 +314,16 @@ void __asan_unpoison_memory_region(void const volatile *add, size_t);
((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 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 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)
@ -368,8 +386,8 @@ void __asan_unpoison_memory_region(void const volatile *add, size_t);
* wmmintrin.h AES
* immintrin.h AVX, AVX2, FMA
*/
#include "intrin.h"
#include "nmmintrin.h" /* SSE4.2 */
#include <intrin.h>
#include <nmmintrin.h> /* SSE4.2 */
#endif
////////////////////////////////
@ -512,27 +530,27 @@ StaticAssert(sizeof(Atomic16Padded) == 64 && alignof(Atomic16Padded) == 64);
StaticAssert(sizeof(Atomic32Padded) == 64 && alignof(Atomic32Padded) == 64);
StaticAssert(sizeof(Atomic64Padded) == 64 && alignof(Atomic64Padded) == 64);
#if PlatformIsWindows
#if PlatformIsWindows && ArchIsX64
//- 8 bit atomic operations
ForceInline i8 Atomic8Fetch(Atomic8 *x) { return (i8)_InterlockedCompareExchange8((char *)&x->_v, 0, 0); }
ForceInline i8 Atomic8FetchSet(Atomic8 *x, i8 e) { return (i8)_InterlockedExchange8((char *)&x->_v, e); }
ForceInline i8 Atomic8FetchTestSet(Atomic8 *x, i8 c, i8 e) { return (i8)_InterlockedCompareExchange8((char *)&x->_v, e, c); }
ForceInline i8 Atomic8FetchXor(Atomic8 *x, i8 c) { return (i8)_InterlockedXor8((char *)&x->_v, c); }
ForceInline i8 Atomic8FetchAdd(Atomic8 *x, i8 a) { return (i8)_InterlockedExchangeAdd8((char *)&x->_v, a); }
ForceInline i8 Atomic8Fetch(Atomic8 *x) { return x->_v; }
ForceInline i8 Atomic8FetchSet(Atomic8 *x, i8 e) { return (i8)_InterlockedExchange8((volatile char *)&x->_v, e); }
ForceInline i8 Atomic8FetchTestSet(Atomic8 *x, i8 c, i8 e) { return (i8)_InterlockedCompareExchange8((volatile char *)&x->_v, e, c); }
ForceInline i8 Atomic8FetchXor(Atomic8 *x, i8 c) { return (i8)_InterlockedXor8((volatile char *)&x->_v, c); }
ForceInline i8 Atomic8FetchAdd(Atomic8 *x, i8 a) { return (i8)_InterlockedExchangeAdd8((volatile char *)&x->_v, a); }
//- 16 bit atomic operations
ForceInline i16 Atomic16Fetch(Atomic16 *x) { return (i16)_InterlockedCompareExchange16(&x->_v, 0, 0); }
ForceInline i16 Atomic16Fetch(Atomic16 *x) { return x->_v; }
ForceInline i16 Atomic16FetchSet(Atomic16 *x, i16 e) { return (i16)_InterlockedExchange16(&x->_v, e); }
ForceInline i16 Atomic16FetchTestSet(Atomic16 *x, i16 c, i16 e) { return (i16)_InterlockedCompareExchange16(&x->_v, e, c); }
ForceInline i16 Atomic16FetchTestXor(Atomic16 *x, i16 c) { return (i16)_InterlockedXor16(&x->_v, c); }
ForceInline i16 Atomic16FetchTestAdd(Atomic16 *x, i16 a) { return (i16)_InterlockedExchangeAdd16(&x->_v, a); }
//- 32 bit atomic operations
ForceInline i32 Atomic32Fetch(Atomic32 *x) { return (i32)_InterlockedCompareExchange((volatile long *)&x->_v, 0, 0); }
ForceInline i32 Atomic32Fetch(Atomic32 *x) { return x->_v; }
ForceInline i32 Atomic32FetchSet(Atomic32 *x, i32 e) { return (i32)_InterlockedExchange((volatile long *)&x->_v, e); }
ForceInline i32 Atomic32FetchTestSet(Atomic32 *x, i32 c, i32 e) { return (i32)_InterlockedCompareExchange((volatile long *)&x->_v, e, c); }
ForceInline i32 Atomic32FetchXor(Atomic32 *x, i32 c) { return (i32)_InterlockedXor((volatile long *)&x->_v, c); }
ForceInline i32 Atomic32FetchAdd(Atomic32 *x, i32 a) { return (i32)_InterlockedExchangeAdd((volatile long *)&x->_v, a); }
//- 64 bit atomic operations
ForceInline i64 Atomic64Fetch(Atomic64 *x) { return (i64)_InterlockedCompareExchange64(&x->_v, 0, 0); }
ForceInline i64 Atomic64Fetch(Atomic64 *x) { return x->_v; }
ForceInline i64 Atomic64FetchSet(Atomic64 *x, i64 e) { return (i64)_InterlockedExchange64(&x->_v, e); }
ForceInline i64 Atomic64FetchTestSet(Atomic64 *x, i64 c, i64 e) { return (i64)_InterlockedCompareExchange64(&x->_v, e, c); }
ForceInline i64 Atomic64FetchXor(Atomic64 *x, i64 c) { return (i64)_InterlockedXor64(&x->_v, c); }
@ -627,7 +645,7 @@ Struct(StringList)
//~ Fiber id
#if PlatformIsWindows
# define FiberId (*(i16 *)(void *)(volatile u64)__readgsqword(32))
# define FiberId() (*(i16 *)(void *)(volatile u64)__readgsqword(32))
#else
# error FiberId not implemented
#endif

View File

@ -194,7 +194,7 @@ Inline ArenaCtx *ArenaCtxFromFiberId(i16 fiber_id)
return ctx;
}
#define PermArena (ArenaCtxFromFiberId(FiberId)->perm_arena)
#define PermArena (ArenaCtxFromFiberId(FiberId())->perm_arena)
////////////////////////////////
//~ Scratch helpers
@ -215,7 +215,7 @@ Inline TempArena BeginScratch(Arena *potential_conflict)
/* Use `BeginScratchNoConflict` if no conflicts are present */
Assert(potential_conflict != 0);
ArenaCtx *ctx = ArenaCtxFromFiberId(FiberId);
ArenaCtx *ctx = ArenaCtxFromFiberId(FiberId());
Arena *scratch_arena = ctx->scratch_arenas[0];
if (scratch_arena == potential_conflict)
{
@ -239,7 +239,7 @@ Inline TempArena BeginScratch(Arena *potential_conflict)
Inline TempArena BeginScratchNoConflict_(void)
{
ArenaCtx *ctx = ArenaCtxFromFiberId(FiberId);
ArenaCtx *ctx = ArenaCtxFromFiberId(FiberId());
Arena *scratch_arena = ctx->scratch_arenas[0];
TempArena temp = BeginTempArena(scratch_arena);
return temp;

View File

@ -3,7 +3,7 @@
////////////////////////////////
//~ Buff management
BB_Buff AcquireBitbuff(u64 arena_reserve)
BB_Buff BB_AcquireBuff(u64 arena_reserve)
{
BB_Buff result = ZI;
result.arena = AcquireArena(arena_reserve);
@ -11,7 +11,7 @@ BB_Buff AcquireBitbuff(u64 arena_reserve)
return result;
}
void ReleaseBitbuff(BB_Buff *bb)
void BB_ReleaseBuff(BB_Buff *bb)
{
/* Only arena bitbuffs need to be released */
if (bb->is_backed_by_arena)
@ -20,7 +20,7 @@ void ReleaseBitbuff(BB_Buff *bb)
}
}
BB_Buff BitbuffFromString(String s)
BB_Buff BB_BuffFromString(String s)
{
BB_Buff result = ZI;
result.fixed_buffer = s;
@ -112,7 +112,7 @@ b32 BB_CheckWriterOverflowBits(BB_Writer *bw, u64 num_bits)
else
{
u64 max_len = bb->fixed_buffer.len;
if (bytes_needed >= max_len)
if (bytes_needed > max_len)
{
/* Writer overflowed fixed buffer */
Assert(0);
@ -129,17 +129,34 @@ b32 BB_CheckWriterOverflowBits(BB_Writer *bw, u64 num_bits)
//~ Align writer
/* Align the pos to the next byte */
void BB_AlignWriter(BB_Writer *bw)
void BB_WriteAlignToNextByte(BB_Writer *bw)
{
#if BITBUFF_DEBUG
if ((bw->cur_bit & 7) != 0)
{
BB_WriteDebugMagic(bw, BB_DebugMagicKind_Align, 0);
BB_WriteDebugMagic(bw, BB_DebugMagicKind_AlignNextByte, 0);
}
#endif
bw->cur_bit += (8 - (bw->cur_bit & 7)) & 7;
}
void BB_WriteAlign(BB_Writer *bw, u64 align)
{
BB_WriteAlignToNextByte(bw);
BB_WriteDebugMagic(bw, BB_DebugMagicKind_Align, align);
if (align > 0)
{
u64 new_pos = (bw->cur_bit >> 3);
new_pos += (align - 1);
new_pos -= new_pos % align;
if (BB_CheckWriterOverflowBits(bw, new_pos << 3))
{
return;
}
bw->cur_bit = new_pos << 3;
}
}
////////////////////////////////
//~ Write bits
@ -301,7 +318,7 @@ void BB_WriteString(BB_Writer *bw, String s)
void BB_WriteBytes(BB_Writer *bw, String bytes)
{
/* Align start of bytes */
BB_AlignWriter(bw);
BB_WriteAlignToNextByte(bw);
u64 num_bits = bytes.len << 3;
if (BB_CheckWriterOverflowBits(bw, num_bits))
@ -314,6 +331,19 @@ void BB_WriteBytes(BB_Writer *bw, String bytes)
bw->cur_bit += num_bits;
}
void BB_WriteSeekBytes(BB_Writer *bw, u64 num_bytes)
{
BB_WriteAlignToNextByte(bw);
u64 num_bits = num_bytes << 3;
if (BB_CheckWriterOverflowBits(bw, num_bits))
{
return;
}
bw->cur_bit += num_bits;
}
////////////////////////////////
//~ Writer debug
@ -430,17 +460,34 @@ b32 BB_CheckReaderOverflowBits(BB_Reader *br, u64 num_bits)
//~ Align reader
/* Align the pos to the next byte */
void BB_AlignReader(BB_Reader *br)
void BB_ReadAlignToNextByte(BB_Reader *br)
{
#if BITBUFF_DEBUG
if ((br->cur_bit & 7) != 0)
{
BB_ReadDebugMagic(br, BB_DebugMagicKind_Align, 0);
BB_ReadDebugMagic(br, BB_DebugMagicKind_AlignNextByte, 0);
}
#endif
br->cur_bit += (8 - (br->cur_bit & 7)) & 7;
}
void BB_ReadAlign(BB_Reader *br, u64 align)
{
BB_ReadAlignToNextByte(br);
BB_ReadDebugMagic(br, BB_DebugMagicKind_Align, align);
if (align > 0)
{
u64 new_pos = (br->cur_bit >> 3);
new_pos += (align - 1);
new_pos -= new_pos % align;
if (BB_CheckReaderOverflowBits(br, new_pos << 3))
{
return;
}
br->cur_bit = new_pos << 3;
}
}
////////////////////////////////
//~ Read bits
@ -629,7 +676,7 @@ void BB_ReadBytes(BB_Reader *br, String out)
/* Will return 0 on bitbuff overflow. Result should be checked. */
u8 *BB_ReadBytesRaw(BB_Reader *br, u64 num_bytes)
{
BB_AlignReader(br);
BB_ReadAlignToNextByte(br);
u64 num_bits = num_bytes << 3;
if (BB_CheckReaderOverflowBits(br, num_bits))
@ -643,9 +690,9 @@ u8 *BB_ReadBytesRaw(BB_Reader *br, u64 num_bytes)
return raw;
}
void BB_SeekBytes(BB_Reader *br, u64 num_bytes)
void BB_ReadSeekBytes(BB_Reader *br, u64 num_bytes)
{
BB_AlignReader(br);
BB_ReadAlignToNextByte(br);
u64 num_bits = num_bytes << 3;
if (BB_CheckReaderOverflowBits(br, num_bits))
@ -656,12 +703,12 @@ void BB_SeekBytes(BB_Reader *br, u64 num_bytes)
br->cur_bit += num_bits;
}
void BB_SeekToByte(BB_Reader *br, u64 pos)
void BB_ReadSeekToByte(BB_Reader *br, u64 pos)
{
u64 cur_byte_pos = br->cur_bit >> 3;
if (pos >= cur_byte_pos)
{
BB_SeekBytes(br, pos - cur_byte_pos);
BB_ReadSeekBytes(br, pos - cur_byte_pos);
}
else
{
@ -670,7 +717,6 @@ void BB_SeekToByte(BB_Reader *br, u64 pos)
br->overflowed = 1;
br->cur_bit = (br->base_len << 3);
}
}
////////////////////////////////
@ -809,7 +855,7 @@ void BB_Test(void)
String encoded = ZI;
{
BB_Buff bb = AcquireBitbuff(Gibi(64));
BB_Buff bb = BB_AcquireBuff(Gibi(64));
BB_Writer bw = BB_WriterFromBuff(&bb);
for (u64 i = 0; i < countof(cases); ++i)
{
@ -843,7 +889,7 @@ void BB_Test(void)
}
{
BB_Buff bb = BitbuffFromString(encoded);
BB_Buff bb = BB_BuffFromString(encoded);
BB_Reader br = BB_ReaderFromBuff(&bb);
for (u64 i = 0; i < countof(cases); ++i)
{

View File

@ -48,6 +48,7 @@ Struct(BB_Reader)
Enum(BB_DebugMagicKind)
{
BB_DebugMagicKind_Align = 0x20A4,
BB_DebugMagicKind_AlignToNextByte = 0x379A,
BB_DebugMagicKind_UBits = 0xCB4A,
BB_DebugMagicKind_IBits = 0xB30D,
BB_DebugMagicKind_UV = 0xE179,
@ -63,10 +64,12 @@ Enum(BB_DebugMagicKind)
////////////////////////////////
//~ Buff management
BB_Buff AcquireBitbuff(u64 arena_reserve);
void ReleaseBitbuff(BB_Buff *bitbuff);
//- Growable-arena backed bitbuff
BB_Buff BB_AcquireBuff(u64 arena_reserve);
void BB_ReleaseBuff(BB_Buff *bitbuff);
BB_Buff BitbuffFromString(String s);
//- Fixed-buffer backed bitbuff
BB_Buff BB_BuffFromString(String s);
////////////////////////////////
//~ Writer management
@ -86,7 +89,8 @@ b32 BB_CheckWriterOverflowBits(BB_Writer *bw, u64 num_bits);
//~ Writer ops
//- Align
void BB_AlignWriter(BB_Writer *bw);
void BB_WriteAlignToNextByte(BB_Writer *bw);
void BB_WriteAlign(BB_Writer *bw, u64 align);
//- Bits
void BB_WriteUBitsNoMagic(BB_Writer *bw, u64 value, u8 num_bits);
@ -108,6 +112,7 @@ void BB_WriteUid(BB_Writer *bw, Uid value);
//- Raw data
void BB_WriteString(BB_Writer *bw, String s);
void BB_WriteBytes(BB_Writer *bw, String bytes);
void BB_WriteSeekBytes(BB_Writer *bw, u64 num_bytes);
////////////////////////////////
//~ Writer debug
@ -138,7 +143,8 @@ b32 BB_CheckReaderOverflowBits(BB_Reader *br, u64 num_bits);
//~ Reader ops
//- Align
void BB_AlignReader(BB_Reader *br);
void BB_ReadAlignToNextByte(BB_Reader *br);
void BB_ReadAlign(BB_Reader *br, u64 align);
//- Bits
u64 BB_ReadUBitsNoMagic(BB_Reader *br, u8 num_bits);
@ -161,8 +167,8 @@ Uid BB_ReadUid(BB_Reader *br);
String BB_ReadString(Arena *arena, BB_Reader *br);
void BB_ReadBytes(BB_Reader *br, String dst);
u8 *BB_ReadBytesRaw(BB_Reader *br, u64 num_bytes);
void BB_SeekBytes(BB_Reader *br, u64 num_bytes);
void BB_SeekToByte(BB_Reader *br, u64 pos);
void BB_ReadSeekBytes(BB_Reader *br, u64 num_bytes);
void BB_ReadSeekToByte(BB_Reader *br, u64 pos);
////////////////////////////////
//~ Reader debug

View File

@ -19,6 +19,8 @@
# include "base_rand.h"
# include "base_util.h"
# include "base_entry.h"
# include "base_bitbuff.h"
# include "base_resource.h"
#elif LanguageIsGpu
# include "base_math_gpu.h"
#endif
@ -35,9 +37,11 @@
# include "base_buddy.c"
# include "base_math.c"
# include "base_rand.c"
# include "base_bitbuff.c"
# include "base_resource.c"
#endif
//- Win32 impl
//- Include base_win32
#if LanguageIsC && PlatformIsWindows
# include "base_win32/base_win32_inc.h"
#endif

View File

@ -55,8 +55,6 @@ void FutexWake(void *addr, i32 count);
////////////////////////////////
//~ @hookdecl Job operations
#define EmptySig { i32 _; }
typedef void GenericJobFunc(void *, i32);
Struct(GenericJobDesc)
@ -82,6 +80,11 @@ Struct(JobDescParams)
Counter *counter;
};
#define EmptySig { i32 _; }
#define PushJobDesc(job, ...) (job##_Desc *)PushJobDesc_(sizeof(job##_Sig), alignof(job##_Sig), job##_Generic, (JobDescParams) { .count = 1, .pool = JobPool_Inherit, .priority = JobPriority_Inherit, .counter = 0, __VA_ARGS__ })
GenericJobDesc *PushJobDesc_(u64 sig_size, u64 sig_align, GenericJobFunc *func, JobDescParams params);
#define JobDecl(job, sigdef) \
typedef struct job##_Sig sigdef job##_Sig; \
Struct(job##_Desc) { Arena *arena; job##_Sig *sig; GenericJobFunc *func; i32 count; JobPool pool; JobPriority priority; Counter *counter; }; \
@ -89,16 +92,28 @@ Struct(JobDescParams)
inline void job##_Generic(void *sig, i32 id) { job((job##_Sig *)sig, id); } \
StaticAssert(1)
#define PushJobDesc(job, ...) (job##_Desc *)PushJobDesc_(sizeof(job##_Sig), alignof(job##_Sig), job##_Generic, (JobDescParams) { .count = 1, .pool = JobPool_Inherit, .priority = JobPriority_Inherit, .counter = 0, __VA_ARGS__ })
GenericJobDesc *PushJobDesc_(u64 sig_size, u64 sig_align, GenericJobFunc *func, JobDescParams params);
#define JobDef(job, sig_arg, id_arg) void job(job##_Sig *sig_arg, i32 id_arg)
#define RunJob(_count, job, _pool, _priority, _counter, ...) do { \
/* RunJob example usage:
*
* This example pushes a single 'LoadTextureJob' onto the background job
* pool, copying 'sprite' into the job signature. 'counter' is also passed
* and then immediately yielded on in this example, effectively making
* the operation synchronous as the caller will block until the job completes:
* {
* Counter counter = {0};
* RunJob(1, LoadTextureJob, JobPool_Background, JobPriority_Low, &counter, .resource = sprite);
* YieldOnCounter(&counter);
* }
*
*/
#define RunJob(_count, job, _pool, _priority, _counter, ...) \
do { \
job##_Desc *__job_desc = (job##_Desc *)PushJobDesc_(sizeof(job##_Sig), alignof(job##_Sig), job##_Generic, (JobDescParams) { .count = _count, .pool = _pool, .priority = _priority, .counter = _counter,}); \
*__job_desc->sig = (job##_Sig) { __VA_ARGS__ }; \
RunJobEx((GenericJobDesc *)__job_desc); \
} while (0)
void RunJobEx(GenericJobDesc *desc);
////////////////////////////////

View File

@ -45,7 +45,7 @@ void SetMemoryReadWrite(void *address, u64 size)
#endif /* PlatformIsWindows */
////////////////////////////////
//~ Crtlib memory.h stubs
//~ Crtlib mem op stubs
#if !CrtlibIsEnabled

95
src/base/base_resource.c Normal file
View File

@ -0,0 +1,95 @@
SharedResourceState shared_resource_state = ZI;
////////////////////////////////
//~ Startup
void InitBaseResources(String archive)
{
SharedResourceState *g = &shared_resource_state;
if (archive.len <= 0) return;
BB_Buff bb = BB_BuffFromString(archive);
BB_Reader br = BB_ReaderFromBuff(&bb);
u64 magic = BB_ReadUBits(&br, 64);
Assert(magic == ResourceEmbeddedMagic);
/* Create & insert entries */
u64 num_entries = BB_ReadUBits(&br, 64);
for (u64 i = 0; i < num_entries; ++i)
{
u64 name_start = BB_ReadUBits(&br, 64);
u64 name_len = BB_ReadUBits(&br, 64);
u64 data_start = BB_ReadUBits(&br, 64);
u64 data_len = BB_ReadUBits(&br, 64);
ResourceEntry *entry = PushStruct(PermArena, ResourceEntry);
entry->name = STRING(name_len, archive.text + name_start);
entry->data = STRING(data_len, archive.text + data_start);
entry->hash = HashFnv64(Fnv64Basis, entry->name);
ResourceEntryBin *bin = &g->bins[entry->hash % NumResourceEntryBins];
QueuePush_N(bin->first, bin->last, entry, next_in_bin);
QueuePush_N(g->first_entry, g->last_entry, entry, next);
}
g->entries_count = num_entries;
}
////////////////////////////////
//~ Resource helpers
b32 IsResourceNil(Resource resource)
{
return resource.hash == 0;
}
Resource ResourceFromStore(ResourceStore *store, String name)
{
Resource result = ZI;
result.hash = HashFnv64(store->hash, name);
return result;
}
////////////////////////////////
//~ Resource cache operations
ResourceEntry *ResourceEntryFromHash(u64 hash)
{
ResourceEntry *result = 0;
SharedResourceState *g = &shared_resource_state;
ResourceEntryBin *bin = &g->bins[hash % NumResourceEntryBins];
for (ResourceEntry *e = bin->first; e; e = e->next_in_bin)
{
if (e->hash == hash)
{
result = e;
break;
}
}
return result;
}
////////////////////////////////
//~ Resource operations
String DataFromResource(Resource resource)
{
String result = ZI;
ResourceEntry *entry = ResourceEntryFromHash(resource.hash);
if (entry)
{
result = entry->data;
}
return result;
}
String NameFromResource(Resource resource)
{
String result = ZI;
ResourceEntry *entry = ResourceEntryFromHash(resource.hash);
if (entry)
{
result = entry->name;
}
return result;
}

72
src/base/base_resource.h Normal file
View File

@ -0,0 +1,72 @@
////////////////////////////////
//~ Resource types
#define ResourceEmbeddedMagic 0xfc060937194f4406
#define DeclResourceStore(name) extern ResourceStore name
Struct(ResourceStore)
{
u64 hash;
};
Struct(Resource)
{
u64 hash;
};
////////////////////////////////
//~ Resource cache types
Struct(ResourceEntry)
{
ResourceEntry *next;
ResourceEntry *next_in_bin;
u64 hash;
String name;
String data;
};
Struct(ResourceEntryBin)
{
ResourceEntry *first;
ResourceEntry *last;
};
////////////////////////////////
//~ Shared state
#define NumResourceEntryBins 4096
Struct(SharedResourceState)
{
ResourceEntry *first_entry;
ResourceEntry *last_entry;
u64 entries_count;
ResourceEntryBin bins[NumResourceEntryBins];
};
extern SharedResourceState shared_resource_state;
////////////////////////////////
//~ Startup
void InitBaseResources(String archive);
////////////////////////////////
//~ Resource operations
b32 IsResourceNil(Resource resource);
Resource ResourceFromStore(ResourceStore *store, String name);
////////////////////////////////
//~ Resource cache operations
ResourceEntry *ResourceEntryFromHash(u64 hash);
////////////////////////////////
//~ Resource data operations
String DataFromResource(Resource resource);
String NameFromResource(Resource resource);

View File

@ -56,7 +56,7 @@ Lock LockSpinE(Mutex *m, i32 spin)
}
#if RtcIsEnabled
Atomic32FetchSet(&m->exclusive_fiber_id, FiberId);
Atomic32FetchSet(&m->exclusive_fiber_id, FiberId());
#endif
Lock lock = ZI;
@ -173,6 +173,11 @@ void SignalCv(Cv *cv, i32 count)
////////////////////////////////
//~ Counter
u64 ValueFromCounter(Counter *counter)
{
return Atomic64Fetch(&counter->v);
}
void AddCounter(Counter *counter, i64 x)
{
i64 old_v = Atomic64FetchAdd(&counter->v, x);

View File

@ -79,5 +79,6 @@ void SignalCv(Cv *cv, i32 count);
////////////////////////////////
//~ Counter operations
u64 ValueFromCounter(Counter *counter);
void AddCounter(Counter *counter, i64 x);
void YieldOnCounter(Counter *counter);

View File

@ -294,3 +294,10 @@ Inline u64 DictValueFromHash(Dict *dict, u64 hash)
DictEntry *entry = DictEntryFromHash(dict, hash);
return entry ? entry->value : 0;
}
Inline u64 DictValueOrNilFromHash(Dict *dict, u64 hash, u64 nil)
{
__prof;
DictEntry *entry = DictEntryFromHash(dict, hash);
return entry ? entry->value : nil;
}

View File

@ -1,5 +1,34 @@
W32_SharedState W32_shared_state = ZI;
////////////////////////////////
//~ Win32 embedded data
/* Find first resource with `type` and return the data in `udata`. */
BOOL W32_FindEmbeddedRcData(HMODULE module, LPCWSTR type, LPWSTR wstr_entry_name, LONG_PTR udata)
{
W32_SharedState *g = &W32_shared_state;
TempArena scratch = BeginScratchNoConflict();
String *out = (String *)udata;
b32 found = 0;
String entry_name_lower = LowerString(scratch.arena, StringFromWstrNoLimit(scratch.arena, (LPWSTR)wstr_entry_name));
if (EqString(entry_name_lower, Lit(Stringize(W32_EmbeddedDataName))))
{
HRSRC hres = FindResourceW(module, wstr_entry_name, type);
if (hres)
{
HGLOBAL hg = LoadResource(module, hres);
if (hg)
{
found = 1;
out->len = SizeofResource(module, hres);
out->text = LockResource(hg);
}
}
}
EndScratch(scratch);
return !found;
}
////////////////////////////////
//~ @hookdef Core hooks
@ -187,9 +216,18 @@ i32 W32_Main(void)
/* Query system info */
GetSystemInfo(&g->info);
//- Startup workers
/* Startup workers */
InitJobWorkers();
/* Init resources */
{
String embedded = ZI;
EnumResourceNamesW(0, RT_RCDATA, &W32_FindEmbeddedRcData, (LONG_PTR)&embedded);
InitBaseResources(embedded);
}
//- App startup
/* Startup layers */
if (!Atomic32Fetch(&g->panicking))
{

View File

@ -13,7 +13,7 @@ u32 BCryptGenRandom(void *algorithm, u8 *buffer, u32 buffer_size, u32 flags);
////////////////////////////////
//~ Shared state
#define W32_MaxOnExitFuncs 1024
#define W32_MaxOnExitFuncs 4096
Struct(W32_SharedState)
{
@ -37,6 +37,12 @@ Struct(W32_SharedState)
extern W32_SharedState W32_shared_state;
////////////////////////////////
//~ Embedded data initialization
#define W32_EmbeddedDataName embedded_resource_data
BOOL W32_FindEmbeddedRcData(HMODULE module, LPCWSTR type, LPWSTR wstr_entry_name, LONG_PTR udata);
////////////////////////////////
//~ Startup / shutdown jobs

View File

@ -19,7 +19,6 @@ void InitJobWorkers(void)
g->timer_start_qpc = qpc.QuadPart;
}
/* Init fibers */
g->num_fibers = 1; /* Fiber at index 0 always nil */
g->fiber_names_arena = AcquireArena(Gibi(64));
@ -104,7 +103,6 @@ void InitJobWorkers(void)
{
name_fmt = Lit("Floating worker #%F");
pool->num_worker_threads = 8;
pool->thread_affinity_mask = 0x0000000000000FFFull;
pool->thread_priority = THREAD_PRIORITY_NORMAL;
} break;
@ -112,7 +110,6 @@ void InitJobWorkers(void)
{
name_fmt = Lit("Floating worker #%F");
pool->num_worker_threads = 8;
pool->thread_affinity_mask = 0x0000000000000FFFull;
pool->thread_priority = THREAD_PRIORITY_HIGHEST;
} break;
}
@ -840,7 +837,7 @@ ForceNoInline void W32_FiberResume(W32_Fiber *fiber)
void W32_YieldFiber(W32_Fiber *fiber, W32_Fiber *parent_fiber)
{
LAX fiber;
Assert(fiber->id == FiberId);
Assert(fiber->id == FiberId());
Assert(parent_fiber->id == fiber->parent_id);
Assert(parent_fiber->id > 0);
{
@ -959,7 +956,7 @@ W32_ThreadDef(W32_JobWorkerEntryFunc, worker_ctx_arg)
}
}
i32 worker_fiber_id = FiberId;
i32 worker_fiber_id = FiberId();
W32_Fiber *job_fiber = 0;
b32 shutdown = 0;
@ -1354,7 +1351,7 @@ W32_ThreadDef(W32_JobSchedulerEntryFunc, UNUSED arg)
void FutexYield(volatile void *addr, void *cmp, u32 size, i64 timeout_ns)
{
W32_Fiber *fiber = W32_FiberFromId(FiberId);
W32_Fiber *fiber = W32_FiberFromId(FiberId());
i16 parent_id = fiber->parent_id;
if (parent_id != 0)
{
@ -1446,7 +1443,7 @@ void RunJobEx(GenericJobDesc *desc)
{
AddCounter(counter, 1);
}
W32_Fiber *fiber = W32_FiberFromId(FiberId);
W32_Fiber *fiber = W32_FiberFromId(FiberId());
priority = ClampI32(priority, fiber->job_priority, JobPriority_Count - 1); /* A job cannot create a job with a higher priority than itself */
if (pool_kind == JobPool_Inherit)
{

View File

@ -1,7 +0,0 @@
@Layer bitbuff
//- Api
@IncludeC bitbuff.h
//- Impl
@IncludeC bitbuff.c

View File

@ -25,8 +25,8 @@ JobDef(F_LoadJob, sig, _)
0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF
};
R_Tag resource = sig->resource;
String name = R_NameFromTag(resource);
Resource resource = sig->resource;
String name = NameFromResource(resource);
f32 point_size = sig->point_size;
AC_Asset *asset = sig->asset;
@ -37,7 +37,7 @@ JobDef(F_LoadJob, sig, _)
Assert(countof(font_codes) < F_LookupTableSize);
/* Decode */
String resource_data = R_DataFromTag(resource);
String resource_data = DataFromResource(resource);
if (resource_data.len == 0)
{
/* FIME: Load baked font instead of panicking */
@ -104,11 +104,11 @@ JobDef(F_LoadJob, sig, _)
//~ Load
/* Returns the asset from the asset cache */
AC_Asset *F_LoadAsset(R_Tag resource, f32 point_size, b32 wait)
AC_Asset *F_LoadAsset(Resource resource, f32 point_size, b32 wait)
{
__prof;
TempArena scratch = BeginScratchNoConflict();
String name = R_NameFromTag(resource);
String name = NameFromResource(resource);
/* Concatenate point_size to name for key */
String key = StringF(scratch.arena,
@ -137,7 +137,7 @@ AC_Asset *F_LoadAsset(R_Tag resource, f32 point_size, b32 wait)
return asset;
}
F_Font *F_LoadFontAsync(R_Tag resource, f32 point_size)
F_Font *F_LoadFontAsync(Resource resource, f32 point_size)
{
__prof;
AC_Asset *asset = F_LoadAsset(resource, point_size, 0);
@ -145,7 +145,7 @@ F_Font *F_LoadFontAsync(R_Tag resource, f32 point_size)
return f;
}
F_Font *F_LoadFontWait(R_Tag resource, f32 point_size)
F_Font *F_LoadFontWait(Resource resource, f32 point_size)
{
__prof;
AC_Asset *asset = F_LoadAsset(resource, point_size, 1);

View File

@ -27,14 +27,14 @@ Struct(F_Font)
////////////////////////////////
//~ Font load job
JobDecl(F_LoadJob, { AC_Asset *asset; f32 point_size; R_Tag resource; });
JobDecl(F_LoadJob, { AC_Asset *asset; f32 point_size; Resource resource; });
////////////////////////////////
//~ Font load operations
AC_Asset *F_LoadAsset(R_Tag resource, f32 point_size, b32 wait);
F_Font *F_LoadFontAsync(R_Tag resource, f32 point_size);
F_Font *F_LoadFontWait(R_Tag resource, f32 point_size);
AC_Asset *F_LoadAsset(Resource resource, f32 point_size, b32 wait);
F_Font *F_LoadFontAsync(Resource resource, f32 point_size);
F_Font *F_LoadFontWait(Resource resource, f32 point_size);
////////////////////////////////
//~ Font data operations

View File

@ -4,7 +4,6 @@
@Dep ttf
@Dep gpu
@Dep asset_cache
@Dep res
//- Api
@IncludeC font.h

View File

@ -2,7 +2,6 @@
//- Dependencies
@Dep platform
@Dep res
//- Api
@IncludeC gpu.h

File diff suppressed because it is too large Load Diff

View File

@ -6,6 +6,19 @@ String F_GetFull(Arena *arena, String path)
return OS_GetFullPath(arena, path);
}
String F_GetFullCrossPlatform(Arena *arena, String path)
{
String result = OS_GetFullPath(arena, path);
for (u64 i = 0; i < result.len; ++i)
{
if (result.text[i] == '\\')
{
result.text[i] = '/';
}
}
return result;
}
String F_GetFileName(String path)
{
String result = ZI;

View File

@ -11,6 +11,7 @@ Enum(F_IterFlag)
//~ Path helpers
String F_GetFull(Arena *arena, String path);
String F_GetFullCrossPlatform(Arena *arena, String path);
String F_GetFileName(String path);
String F_GetParentDir(String path);
String F_ExtensionFromFile(String path);

541
src/meta/meta_lay.c Normal file
View File

@ -0,0 +1,541 @@
Readonly M_Token M_NilToken = {
.next = &M_NilToken,
.file = &M_NilTokenFile,
};
Readonly M_TokenFile M_NilTokenFile = {
.next = &M_NilTokenFile,
.first_token = &M_NilToken,
.last_token = &M_NilToken,
};
Readonly M_Entry M_NilEntry = {
.next = &M_NilEntry,
.name_token = &M_NilToken,
.arg_tokens[0] = &M_NilToken,
.arg_tokens[1] = &M_NilToken,
};
StaticAssert(countof(M_NilEntry.arg_tokens) == 2); /* NilEntry must define point args to nil tokens */
Readonly M_Layer M_NilLayer = {
.next = &M_NilLayer,
.file = &M_NilTokenFile,
.first = &M_NilEntry,
.last = &M_NilEntry,
};
////////////////////////////////
//~ Error helpers
M_Error *M_PushError(Arena *arena, M_ErrorList *l, M_Token *token, String msg)
{
M_Error *e = PushStruct(arena, M_Error);
e->msg = msg;
e->token = token ? token : &M_NilToken;
QueuePush(l->first, l->last, e);
++l->count;
return e;
}
void M_AppendErrors(Arena *arena, M_ErrorList *dst, M_ErrorList src)
{
for (M_Error *e = src.first; e; e = e->next)
{
M_PushError(arena, dst, e->token, e->msg);
}
}
////////////////////////////////
//~ Lexer operations
M_TokenFile *M_PushTokenFile(Arena *arena, M_TokenFileList *l, String name, String data)
{
M_TokenFile *tf = PushStruct(arena, M_TokenFile);
*tf = M_NilTokenFile;
tf->valid = 1;
tf->name = name;
tf->data = data;
M_PushToken(arena, tf, Lit(""), M_TokenKind_Eol);
QueuePush_NZ(&M_NilTokenFile, l->first, l->last, tf, next);
++l->count;
return tf;
}
M_Token *M_PushToken(Arena *arena, M_TokenFile *file, String s, M_TokenKind kind)
{
M_Token *t = PushStruct(arena, M_Token);
*t = M_NilToken;
t->valid = 1;
t->s = s;
t->kind = kind;
if (file)
{
t->file = file;
}
QueuePush_NZ(&M_NilToken, file->first_token, file->last_token, t, next);
++file->tokens_count;
return t;
}
M_TokenFileList M_TokensFromSrcDirs(Arena *arena, StringList src_dirs)
{
TempArena scratch = BeginScratch(arena);
M_TokenFileList result = ZI;
/* Build token file list from src dirs */
Dict *dedup_dict = InitDict(scratch.arena, 1021);
for (StringListNode *dir_name_node = src_dirs.first; dir_name_node; dir_name_node = dir_name_node->next)
{
String dir_name = dir_name_node->s;
StringList files = ZI;
F_FilesFromDir(arena, &files, dir_name, F_IterFlag_Recurse);
for (StringListNode *file_name_node = files.first; file_name_node; file_name_node = file_name_node->next)
{
String file_name = file_name_node->s;
if (StringEndsWith(file_name, Lit(".lay")))
{
String tmp_full = F_GetFull(scratch.arena, file_name);
u64 hash = HashFnv64(Fnv64Basis, tmp_full);
if (DictValueFromHash(dedup_dict, hash) == 0)
{
SetDictValue(scratch.arena, dedup_dict, hash, 1);
String full = PushString(arena, tmp_full);
String data = F_DataFromFile(arena, full);
M_PushTokenFile(arena, &result, full, data);
}
}
}
}
for (M_TokenFile *tf = result.first; tf->valid; tf = tf->next)
{
Enum(TokenizerMode)
{
TokenizerMode_None,
TokenizerMode_SingleLineComment,
TokenizerMode_MultiLineComment,
};
TokenizerMode mode = TokenizerMode_None;
u8 *t = tf->data.text;
u64 l = tf->data.len;
u64 p = 0;
String cur_ident = STRING(0, t);
while (p < l)
{
switch (mode)
{
case TokenizerMode_None:
{
u8 c = t[p];
b32 is_eol = c == '\r' || c == '\n' || c == 0 || (p + 1) >= l;
b32 is_whitespace = is_eol || c == ' ';
if (is_whitespace)
{ /* Whitespace */
if (cur_ident.len > 0)
{
M_PushToken(arena, tf, cur_ident, M_TokenKind_Ident);
cur_ident.len = 0;
}
if (is_eol)
{
M_PushToken(arena, tf, STRING(1, &t[p]), M_TokenKind_Eol);
}
p += 1;
}
else if (c == '/' && (p + 1) < l && t[p + 1] == '/')
{ /* Start single line comment */
mode = TokenizerMode_SingleLineComment;
p += 2;
}
else if (c == '/' && (p + 1) < l && t[p + 1] == '*')
{ /* Start multi line comment */
mode = TokenizerMode_MultiLineComment;
p += 2;
}
else
{
if (cur_ident.len == 0)
{
cur_ident.text = &t[p];
}
++cur_ident.len;
p += 1;
}
} break;
case TokenizerMode_SingleLineComment:
{
if (t[p] == '\n')
{ /* End single line comment */
mode = TokenizerMode_None;
p += 1;
}
else
{
p += 1;
}
} break;
case TokenizerMode_MultiLineComment:
{
if (t[p] == '*' && (p + 1) < l && t[p + 1] == '/')
{ /* End multi line comment */
mode = TokenizerMode_None;
p += 2;
}
else
{
p += 1;
}
} break;
}
}
}
return result;
}
////////////////////////////////
//~ Parser operations
M_Layer *M_PushLayer(Arena *arena, M_LayerList *list, M_TokenFile *file)
{
M_Layer *layer = PushStruct(arena, M_Layer);
*layer = M_NilLayer;
layer->valid = 1;
layer->file = file;
QueuePush_NZ(&M_NilLayer, list->first, list->last, layer, next);
++list->count;
return layer;
}
M_Entry *M_PushEntry(Arena *arena, M_Layer *l, M_EntryKind kind, M_Token *entry_token, u64 args_count, M_Token **args)
{
M_Entry *e = PushStruct(arena, M_Entry);
*e = M_NilEntry;
e->valid = 1;
e->kind = kind;
if (entry_token) e->name_token = entry_token;
for (u64 i = 0; i < MinU64(args_count, countof(e->arg_tokens)); ++i)
{
e->arg_tokens[i] = args[i];
}
e->args_count = args_count;
QueuePush_NZ(&M_NilEntry, l->first, l->last, e, next);
++l->count;
return e;
}
M_LayerList M_LayersFromTokenFiles(Arena *arena, M_TokenFileList lexed)
{
TempArena scratch = BeginScratch(arena);
M_LayerList result = ZI;
result.first = &M_NilLayer;
result.last = &M_NilLayer;
/* Copy errors */
b32 lexer_errors_present = 0;
for (M_TokenFile *lf = lexed.first; lf->valid; lf = lf->next)
{
if (lf->errors.count > 0)
{
M_Layer *layer = M_PushLayer(arena, &result, lf);
M_AppendErrors(arena, &layer->errors, lf->errors);
lexer_errors_present = 1;
}
}
if (!lexer_errors_present)
{
Dict *rules_dict = InitDict(scratch.arena, 1024);
for (u64 i = 0; i < countof(M_entry_kind_rules); ++i)
{
char *rule_cstr = M_entry_kind_rules[i];
u64 rule_hash = HashFnv64(Fnv64Basis, StringFromCstrNoLimit(rule_cstr));
SetDictValue(scratch.arena, rules_dict, rule_hash, i + 1);
}
for (M_TokenFile *lf = lexed.first; lf->valid; lf = lf->next)
{
M_Layer *layer = M_PushLayer(arena, &result, lf);
M_Token *entry_token = &M_NilToken;
M_Token *arg_tokens[countof(M_NilEntry.arg_tokens) + 1];
u64 args_count = 0;
for (u64 i = 0; i < countof(arg_tokens); ++i)
{
arg_tokens[i] = &M_NilToken;
}
M_Token *token = lf->first_token;
while (token->valid)
{
if (token->kind == M_TokenKind_Eol)
{
if (entry_token->valid)
{
M_Entry *entry = M_PushEntry(arena, layer, M_EntryKind_Unknown, entry_token, args_count, arg_tokens);
{
u64 entry_hash = HashFnv64(Fnv64Basis, entry_token->s);
u64 kind_plus_1 = DictValueFromHash(rules_dict, entry_hash);
if (kind_plus_1 > 0)
{
entry->kind = kind_plus_1 - 1;
}
}
}
token = token->next;
entry_token = &M_NilToken;
args_count = 0;
for (u64 i = 0; i < countof(arg_tokens); ++i)
{
arg_tokens[i] = &M_NilToken;
}
}
else
{
/* Parse entry */
entry_token = token;
token = token->next;
/* Parse args */
while (token->kind != M_TokenKind_Eol)
{
if (args_count < countof(arg_tokens))
{
arg_tokens[args_count++] = token;
}
token = token->next;
}
}
}
}
}
EndScratch(scratch);
return result;
}
////////////////////////////////
//~ Flatten operations
M_Layer M_GetFlattenedEntries(Arena *arena, M_LayerList unflattened, StringList starting_layer_names)
{
TempArena scratch = BeginScratch(arena);
M_Layer result = M_NilLayer;
/* Copy errors */
b32 unflattened_errors_present = 0;
for (M_Layer *layer = unflattened.first; layer->valid; layer = layer->next)
{
if (layer->errors.count > 0)
{
M_AppendErrors(arena, &result.errors, layer->errors);
unflattened_errors_present = 1;
}
}
if (!unflattened_errors_present)
{
Enum(IterStateMode)
{
IterStateMode_None,
IterStateMode_Entered,
IterStateMode_Exited
};
Struct(IterState)
{
M_Layer *layer;
b32 is_entered;
b32 is_exited;
} NilIterState = {
.layer = &M_NilLayer
};
/* Construct state lookups */
Dict *layer_ptr_to_state = InitDict(scratch.arena, 1021);
Dict *layer_name_to_state = InitDict(scratch.arena, 1021);
for (M_Layer *layer = unflattened.first; layer->valid; layer = layer->next)
{
M_Entry *name_entry = &M_NilEntry;
u64 num_name_entries = 0;
for (M_Entry *entry = layer->first; entry->valid; entry = entry->next)
{
if (entry->kind == M_EntryKind_Layer)
{
if (num_name_entries == 0)
{
name_entry = entry;
}
else
{
String err = StringF(arena, "Layer already has name \"%F\"", FmtString(name_entry->arg_tokens[0]->s));
M_PushError(arena, &result.errors, entry->name_token, err);
}
++num_name_entries;
}
}
if (num_name_entries == 1 && name_entry->arg_tokens[0]->s.len > 0)
{
IterState *state = PushStruct(scratch.arena, IterState);
state->layer = layer;
String name = name_entry->arg_tokens[0]->s;
u64 name_hash = HashFnv64(Fnv64Basis, name);
DictEntry *ptr_dict_entry = EnsureDictEntry(scratch.arena, layer_ptr_to_state, (u64)layer);
DictEntry *name_dict_entry = EnsureDictEntry(scratch.arena, layer_name_to_state, name_hash);
ptr_dict_entry->value = (u64)state;
if (name_dict_entry->value == 0)
{
name_dict_entry->value = (u64)state;
}
else
{
String err = StringF(arena, "Layer with name \"%F\" already exists", FmtString(name));
M_PushError(arena, &result.errors, name_entry->arg_tokens[0], err);
}
}
else if (num_name_entries == 0)
{
M_PushError(arena, &result.errors, layer->file->first_token, Lit("Layer is missing a name"));
}
}
Struct(StackNode) { StackNode *next; IterState *state; b32 exit; };
StackNode *stack = 0;
/* Init stack with starting layers */
for (StringListNode *sln = starting_layer_names.first; sln; sln = sln->next)
{
String name = sln->s;
u64 name_hash = HashFnv64(Fnv64Basis, name);
IterState *state = (IterState *)DictValueOrNilFromHash(layer_name_to_state, name_hash, (u64)&NilIterState);
M_Layer *layer = state->layer;
if (layer->valid)
{
StackNode *n = PushStruct(scratch.arena, StackNode);
n->state = state;
StackPush(stack, n);
}
else
{
String err = StringF(arena, "Starting layer \"%F\" not found", FmtString(name));
M_PushError(arena, &result.errors, 0, err);
}
}
/* Flatten via post-order DFS */
while (stack)
{
StackNode *stack_node = stack;
IterState *state = stack->state;
M_Layer *layer = state->layer;
StackPop(stack);
if (stack_node->exit)
{
/* Push items to sorted root */
state->is_entered = 0;
state->is_exited = 1;
for (M_Entry *entry = layer->first; entry->valid; entry = entry->next)
{
M_PushEntry(arena, &result, entry->kind, entry->name_token, entry->args_count, entry->arg_tokens);
}
}
else
{
if (state->is_entered)
{
/* Cyclic dependency */
/* FIXME: Handle cyclic dependency error */
Assert(0);
}
else if (!state->is_exited)
{
state->is_entered = 1;
/* Push downstream impl enters to stack */
for (M_Entry *entry = layer->first; entry->valid; entry = entry->next)
{
b32 include = (PlatformIsWindows && entry->kind == M_EntryKind_DefaultWindowsImpl);
if (include)
{
M_Token *impl_token = entry->arg_tokens[0];
if (impl_token->valid)
{
String impl_name = impl_token->s;
u64 hash = HashFnv64(Fnv64Basis, impl_name);
IterState *impl_layer_state = (IterState *)DictValueOrNilFromHash(layer_name_to_state, hash, (u64)&NilIterState);
M_Layer *impl_layer = impl_layer_state->layer;
if (impl_layer->valid)
{
if (!impl_layer_state->is_exited)
{
StackNode *n = PushStruct(scratch.arena, StackNode);
n->state = impl_layer_state;
StackPush(stack, n);
}
}
else
{
String err = StringF(arena, "Layer \"%F\" not found", FmtString(impl_name));
M_PushError(arena, &result.errors, impl_token, err);
}
}
else
{
M_PushError(arena, &result.errors, entry->name_token, Lit("Expected layer argument"));
}
}
}
/* Push node exit to stack */
{
stack_node->exit = 1;
StackPush(stack, stack_node);
}
/* Push upstream dep enters to stack */
for (M_Entry *entry = layer->first; entry->valid; entry = entry->next)
{
if (entry->kind == M_EntryKind_Dep)
{
M_Token *dep_token = entry->arg_tokens[0];
if (dep_token->valid)
{
String dep_name = dep_token->s;
u64 hash = HashFnv64(Fnv64Basis, dep_name);
IterState *dep_layer_state = (IterState *)DictValueOrNilFromHash(layer_name_to_state, hash, (u64)&NilIterState);
M_Layer *dep_layer = dep_layer_state->layer;
if (dep_layer->valid)
{
if (!dep_layer_state->is_exited)
{
StackNode *n = PushStruct(scratch.arena, StackNode);
n->state = dep_layer_state;
StackPush(stack, n);
}
}
else
{
String err = StringF(arena, "Layer \"%F\" not found", FmtString(dep_name));
M_PushError(arena, &result.errors, dep_token, err);
}
}
else
{
M_PushError(arena, &result.errors, entry->name_token, Lit("Expected layer argument"));
}
}
}
}
}
}
}
EndScratch(scratch);
return result;
}

154
src/meta/meta_lay.h Normal file
View File

@ -0,0 +1,154 @@
////////////////////////////////
//~ Error types
Struct(M_Error)
{
M_Error *next;
String msg;
struct M_Token *token;
};
Struct(M_ErrorList)
{
M_Error *first;
M_Error *last;
u64 count;
};
////////////////////////////////
//~ File types
Struct(M_File)
{
String name;
String data;
};
////////////////////////////////
//~ Token types
Enum(M_TokenKind)
{
M_TokenKind_Ident,
M_TokenKind_Eol, /* End of line */
};
Struct(M_Token)
{
b32 valid;
M_Token *next;
M_TokenKind kind;
struct M_TokenFile *file;
String s;
} extern Readonly M_NilToken;
Struct(M_TokenFile)
{
b32 valid;
M_TokenFile *next;
String name;
String data;
M_Token *first_token;
M_Token *last_token;
u64 tokens_count;
M_ErrorList errors;
} extern Readonly M_NilTokenFile;
Struct(M_TokenFileList)
{
M_TokenFile *first;
M_TokenFile *last;
u64 count;
};
////////////////////////////////
//~ Entry types
Enum(M_EntryKind)
{
M_EntryKind_Unknown,
M_EntryKind_Layer,
M_EntryKind_Dep,
M_EntryKind_IncludeC,
M_EntryKind_IncludeGpu,
M_EntryKind_DefaultWindowsImpl,
M_EntryKind_Startup,
M_EntryKind_EmbedDir,
};
Struct(M_EntryKindMatch)
{
char *match_cstr;
u64 max_args;
};
Global Readonly char *M_entry_kind_rules[] = {
[M_EntryKind_Layer] = "@Layer",
[M_EntryKind_Dep] = "@Dep",
[M_EntryKind_IncludeC] = "@IncludeC",
[M_EntryKind_IncludeGpu] = "@IncludeGpu",
[M_EntryKind_DefaultWindowsImpl] = "@DefaultWindowsImpl",
[M_EntryKind_Startup] = "@Startup",
[M_EntryKind_EmbedDir] = "@EmbedDir",
};
Struct(M_Entry)
{
b32 valid;
M_Entry *next;
M_EntryKind kind;
M_Token *name_token;
M_Token *arg_tokens[2];
u64 args_count;
} extern Readonly M_NilEntry;
Struct(M_Layer)
{
b32 valid;
M_Layer *next;
M_TokenFile *file;
M_Entry *first;
M_Entry *last;
u64 count;
M_ErrorList errors;
} extern Readonly M_NilLayer;
Struct(M_LayerList)
{
M_Layer *first;
M_Layer *last;
u64 count;
};
////////////////////////////////
//~ Error helpers
M_Error *M_PushError(Arena *arena, M_ErrorList *l, M_Token *token, String msg);
void M_AppendErrors(Arena *arena, M_ErrorList *dst, M_ErrorList src);
////////////////////////////////
//~ Lexer operations
M_Token *M_PushToken(Arena *arena, M_TokenFile *file, String s, M_TokenKind kind);
M_TokenFileList M_TokensFromSrcDirs(Arena *arena, StringList src_dirs);
////////////////////////////////
//~ Parser operations
M_Layer *M_PushLayer(Arena *arena, M_LayerList *list, M_TokenFile *file);
M_Entry *M_PushEntry(Arena *arena, M_Layer *l, M_EntryKind kind, M_Token *entry_token, u64 args_count, M_Token **args);
M_LayerList M_LayersFromTokenFiles(Arena *arena, M_TokenFileList token_files);
////////////////////////////////
//~ Flatten operations
M_Layer M_GetFlattenedEntries(Arena *arena, M_LayerList unflattened, StringList starting_layer_names);

View File

@ -582,7 +582,7 @@ N_EventList N_BeginUpdate(Arena *arena, N_Host *host)
{
//struct sock *sock = packet->sock;
P_Address address = packet->address;
BB_Buff bb = BitbuffFromString(packet->data);
BB_Buff bb = BB_BuffFromString(packet->data);
BB_Reader br = BB_ReaderFromBuff(&bb);
u32 magic = BB_ReadUBits(&br, 32); /* TODO: implicitly encode magic into crc32 */
if (magic == N_PacketMagic)
@ -874,7 +874,7 @@ void N_EndUpdate(N_Host *host)
{
u8 packet_flags = 0;
N_SndPacket *packet = N_PushSndPacket(channel, 0);
BB_Buff bb = BitbuffFromString(StringFromArray(packet->data));
BB_Buff bb = BB_BuffFromString(StringFromArray(packet->data));
BB_Writer bw = BB_WriterFromBuff(&bb);
BB_WriteUBits(&bw, N_PacketMagic, 32); /* TODO: implicitly encode magic into crc32 */
BB_WriteIBits(&bw, N_PacketKind_TryConnect, 8);
@ -887,7 +887,7 @@ void N_EndUpdate(N_Host *host)
{
u8 packet_flags = 0;
N_SndPacket *packet = N_PushSndPacket(channel, 0);
BB_Buff bb = BitbuffFromString(StringFromArray(packet->data));
BB_Buff bb = BB_BuffFromString(StringFromArray(packet->data));
BB_Writer bw = BB_WriterFromBuff(&bb);
BB_WriteUBits(&bw, N_PacketMagic, 32); /* TODO: implicitly encode magic into crc32 */
BB_WriteIBits(&bw, N_PacketKind_ConnectSuccess, 8);
@ -900,7 +900,7 @@ void N_EndUpdate(N_Host *host)
{
u8 packet_flags = 0;
N_SndPacket *packet = N_PushSndPacket(channel, 0);
BB_Buff bb = BitbuffFromString(StringFromArray(packet->data));
BB_Buff bb = BB_BuffFromString(StringFromArray(packet->data));
BB_Writer bw = BB_WriterFromBuff(&bb);
BB_WriteUBits(&bw, N_PacketMagic, 32); /* TODO: implicitly encode magic into crc32 */
BB_WriteIBits(&bw, N_PacketKind_Disconnect, 8);
@ -913,7 +913,7 @@ void N_EndUpdate(N_Host *host)
{
u8 packet_flags = 0;
N_SndPacket *packet = N_PushSndPacket(channel, 0);
BB_Buff bb = BitbuffFromString(StringFromArray(packet->data));
BB_Buff bb = BB_BuffFromString(StringFromArray(packet->data));
BB_Writer bw = BB_WriterFromBuff(&bb);
BB_WriteUBits(&bw, N_PacketMagic, 32); /* TODO: implicitly encode magic into crc32 */
BB_WriteIBits(&bw, N_PacketKind_Heartbeat, 8);
@ -951,7 +951,7 @@ void N_EndUpdate(N_Host *host)
}
}
N_SndPacket *packet = N_PushSndPacket(channel, is_reliable);
BB_Buff bb = BitbuffFromString(StringFromArray(packet->data));
BB_Buff bb = BB_BuffFromString(StringFromArray(packet->data));
BB_Writer bw = BB_WriterFromBuff(&bb);
BB_WriteUBits(&bw, N_PacketMagic, 32); /* TODO: implicitly encode magic into crc32 */
BB_WriteIBits(&bw, N_PacketKind_MsgChunk, 8);

View File

@ -2,7 +2,6 @@
//- Dependencies
@Dep platform
@Dep bitbuff
//- Api
@IncludeC net.h

View File

@ -1150,9 +1150,9 @@ void UpdateUser(P_Window *window)
{
Entity *ent = sorted[sorted_index];
if (!IsValidAndActive(ent)) continue;
//if (S_IsTagNil(ent->sprite)) continue;
//if (S_IsNil(ent->sprite)) continue;
R_Tag sprite = ent->sprite;
Resource sprite = ent->sprite;
Entity *parent = EntityFromId(g->ss_blended, ent->parent);
@ -1214,7 +1214,7 @@ void UpdateUser(P_Window *window)
#endif
/* Draw sprite */
if (!R_IsTagNil(sprite))
if (!IsResourceNil(sprite))
{
S_Sheet *sheet = S_SheetFromResourceAsync(sprite);
S_Texture *texture = S_TextureFromResourceAsync(sprite);
@ -1244,7 +1244,7 @@ void UpdateUser(P_Window *window)
if (HasProp(ent, Prop_TileChunk))
{
Vec2I32 chunk_index = ent->tile_chunk_index;
R_Tag tile_sprite = R_TagFromStore(&GameResources, Lit("sprite/tile.ase"));
Resource tile_sprite = ResourceFromStore(&GameResources, Lit("sprite/tile.ase"));
S_Texture *tile_texture = S_TextureFromResourceAsync(tile_sprite);
if (tile_texture->loaded)
{
@ -1323,7 +1323,7 @@ void UpdateUser(P_Window *window)
#if 0
/* Draw slices */
if (!S_IsTagNil(ent->sprite))
if (!S_IsNil(ent->sprite))
{
S_Sheet *sheet = S_SheetFromResourceAsync(sprite);
@ -1754,7 +1754,7 @@ void UpdateUser(P_Window *window)
{
__profn("Draw crosshair");
Vec2 crosshair_pos = g->ui_cursor;
R_Tag crosshair = R_TagFromStore(GameResources, Lit("sprite/crosshair.ase"));
Resource crosshair = ResourceFromStore(GameResources, Lit("sprite/crosshair.ase"));
S_Texture *t = S_TextureFromResourceAsync(crosshair);
Vec2 size = VEC2(t->width, t->height);
Xform xf = XformFromTrs(TRS(.t = crosshair_pos, .s = size));
@ -1773,7 +1773,7 @@ void UpdateUser(P_Window *window)
}
else
{
S_Texture *t = S_TextureFromResourceAsync(R_TagFromStore(GameResources, Lit("sprite/crosshair.ase")));
S_Texture *t = S_TextureFromResourceAsync(ResourceFromStore(GameResources, Lit("sprite/crosshair.ase")));
Vec2 size = VEC2(t->width, t->height);
Rect cursor_clip = RectFromVec2(g->ui_screen_offset, g->ui_size);
cursor_clip.pos = AddVec2(cursor_clip.pos, MulVec2(size, 0.5f));
@ -2536,8 +2536,8 @@ JobDef(SimJob, UNUSED sig, UNUSED id)
is_master = 1;
}
BB_Buff msg_writer_bb = AcquireBitbuff(Gibi(64));
BB_Buff snapshot_writer_bb = AcquireBitbuff(Gibi(64));
BB_Buff msg_writer_bb = BB_AcquireBuff(Gibi(64));
BB_Buff snapshot_writer_bb = BB_AcquireBuff(Gibi(64));
SimAccel accel = AcquireSimAccel();
ClientStore *store = AcquireClientStore();
@ -2646,7 +2646,7 @@ JobDef(SimJob, UNUSED sig, UNUSED id)
{
if (client->valid)
{
BB_Buff msg_bb = BitbuffFromString(event->msg);
BB_Buff msg_bb = BB_BuffFromString(event->msg);
BB_Reader msg_br = BB_ReaderFromBuff(&msg_bb);
u64 ack = BB_ReadUV(&msg_br);
@ -2667,7 +2667,7 @@ JobDef(SimJob, UNUSED sig, UNUSED id)
u8 *tmp_encoded_bytes = BB_ReadBytesRaw(&msg_br, tmp_encoded_len);
if (!tmp_encoded_bytes) break;
BB_Buff decoder_bb = BitbuffFromString(STRING(tmp_encoded_len, tmp_encoded_bytes));
BB_Buff decoder_bb = BB_BuffFromString(STRING(tmp_encoded_len, tmp_encoded_bytes));
BB_Reader decoder_br = BB_ReaderFromBuff(&decoder_bb);
u64 base_tick = BB_ReadUV(&decoder_br);
u64 tick = BB_ReadUV(&decoder_br);
@ -2762,7 +2762,7 @@ JobDef(SimJob, UNUSED sig, UNUSED id)
Snapshot *base_ss = SnapshotFromTick(client, base_tick);
if (base_ss->tick == base_tick)
{
BB_Buff bb = BitbuffFromString(n->tmp_encoded);
BB_Buff bb = BB_BuffFromString(n->tmp_encoded);
BB_Reader br = BB_ReaderFromBuff(&bb);
/* Acquire & decode snapshot */
@ -3203,7 +3203,7 @@ JobDef(SimJob, UNUSED sig, UNUSED id)
ReleaseClientStore(store);
ReleaseSimAccel(&accel);
ReleaseBitbuff(&snapshot_writer_bb);
ReleaseBitbuff(&msg_writer_bb);
BB_ReleaseBuff(&snapshot_writer_bb);
BB_ReleaseBuff(&msg_writer_bb);
N_ReleaseHost(host);
}

View File

@ -273,7 +273,7 @@ extern SharedUserState shared_user_state;
////////////////////////////////
//~ Resources
R_DeclStore(GameResources);
DeclResourceStore(GameResources);
////////////////////////////////
//~ Startup

View File

@ -7,7 +7,6 @@
@Dep collider
@Dep net
@Dep mixer
@Dep bitbuff
@Dep rendertest
@Dep playback

View File

@ -247,7 +247,7 @@ Struct(Entity)
//- Sprite
R_Tag sprite;
Resource sprite;
String sprite_span_name;
u32 sprite_tint;
Vec3 sprite_emittance;

View File

@ -36,7 +36,7 @@ void ResetSimAccel(Snapshot *ss, SimAccel *accel)
Entity *SpawnTestSmg(Entity *parent)
{
Entity *e = AcquireSyncSrc(parent);
e->sprite = R_TagFromStore(&GameResources, Lit("sprite/gun.ase"));
e->sprite = ResourceFromStore(&GameResources, Lit("sprite/gun.ase"));
EnableProp(e, Prop_Attached);
e->attach_slice = Lit("attach.wep");
@ -52,7 +52,7 @@ Entity *SpawnTestSmg(Entity *parent)
Entity *SpawnTestLauncher(Entity *parent)
{
Entity *e = AcquireSyncSrc(parent);
e->sprite = R_TagFromStore(&GameResources, Lit("sprite/gun.ase"));
e->sprite = ResourceFromStore(&GameResources, Lit("sprite/gun.ase"));
EnableProp(e, Prop_Attached);
e->attach_slice = Lit("attach.wep");
@ -68,7 +68,7 @@ Entity *SpawnTestLauncher(Entity *parent)
Entity *SpawnTestChucker(Entity *parent)
{
Entity *chucker = AcquireSyncSrc(parent);
chucker->sprite = R_TagFromStore(&GameResources, Lit("sprite/gun.ase"));
chucker->sprite = ResourceFromStore(&GameResources, Lit("sprite/gun.ase"));
EnableProp(chucker, Prop_Attached);
chucker->attach_slice = Lit("attach.wep");
@ -119,12 +119,12 @@ Entity *SpawnTestEmployee(Entity *parent)
{
EnableProp(e, Prop_Test);
e->sprite = R_TagFromStore(&GameResources, Lit("sprite/tim.ase"));
e->sprite = ResourceFromStore(&GameResources, Lit("sprite/tim.ase"));
e->mass_unscaled = 10;
e->inertia_unscaled = 5;
}
//e->sprite = R_TagFromStore(GameResources, Lit("sprite/box_rounded.ase"));
//e->sprite = ResourceFromStore(GameResources, Lit("sprite/box_rounded.ase"));
//e->sprite_span_name = Lit("idle.unarmed");
//e->sprite_span_name = Lit("idle.one_handed");
e->sprite_span_name = Lit("idle.two_handed");
@ -257,7 +257,7 @@ void SpawnTestEntities2(Entity *parent, Vec2 pos)
Xform xf = XformFromTrs(TRS(.t = pos, .r = rot, .s = size));
SetXform(e, xf);
e->sprite = R_TagFromStore(&GameResources, Lit("sprite/tile.ase"));
e->sprite = ResourceFromStore(&GameResources, Lit("sprite/tile.ase"));
e->layer = Layer_Shoulders;
//e->sprite_tint = Alpha32F(ColorBlue, 0.75);
@ -299,7 +299,7 @@ void SpawnTestEntities2(Entity *parent, Vec2 pos)
Xform xf = XformFromTrs(.t = pos, .r = r, .s = size);
SetXform(e, xf);
e->sprite = R_TagFromStore(GameResources, Lit("sprite/bullet.ase"));
e->sprite = ResourceFromStore(GameResources, Lit("sprite/bullet.ase"));
e->sprite_collider_slice = Lit("shape");
e->layer = Layer_Shoulders;
@ -327,7 +327,7 @@ void SpawnTestEntities3(Entity *parent, Vec2 pos)
Xform xf = XformFromTrs(TRS(.t = pos, .r = r, .s = size));
SetXform(e, xf);
e->sprite = R_TagFromStore(&GameResources, Lit("sprite/box.ase"));
e->sprite = ResourceFromStore(&GameResources, Lit("sprite/box.ase"));
e->layer = Layer_Shoulders;
e->sprite_tint = ColorRed;
@ -350,8 +350,8 @@ void SpawnTestEntities4(Entity *parent, Vec2 pos)
Xform xf = XformFromTrs(TRS(.t = pos, .r = r, .s = size));
SetXform(e, xf);
//e->sprite = R_TagFromStore(GameResources, Lit("sprite/box.ase"));
e->sprite = R_TagFromStore(&GameResources, Lit("sprite/tile.ase"));
//e->sprite = ResourceFromStore(GameResources, Lit("sprite/box.ase"));
e->sprite = ResourceFromStore(&GameResources, Lit("sprite/tile.ase"));
e->layer = Layer_Shoulders;
EnableProp(e, Prop_LightTest);
@ -380,10 +380,10 @@ void SpawnTestTile(Snapshot *world, Vec2 world_pos)
SetXform(e, xf);
e->layer = Layer_Walls;
e->sprite = R_TagFromStore(GameResources, Lit("sprite/tile.ase"));
e->sprite = ResourceFromStore(GameResources, Lit("sprite/tile.ase"));
e->sprite_tint = ColorRed;
S_Sheet *sheet = S_SheetFromResourceAwait(e->sprite);
S_Sheet *sheet = S_SheetFromResource(e->sprite);
e->sprite_local_xform = XformFromTrs(.s = DivVec2(sheet->frame_size, PIXELS_PER_UNIT));
EnableProp(e, Prop_Solid);
@ -783,7 +783,7 @@ CollisionCallbackFuncDef(OnEntityCollision, data, step_ctx)
{
Xform xf = XformFromTrs(TRS(.t = point, .r = RandF64FromState(&step_ctx->rand, 0, Tau)));
Entity *decal = AcquireSyncSrc(root);
decal->sprite = R_TagFromStore(&GameResources, Lit("sprite/blood.ase"));
decal->sprite = ResourceFromStore(&GameResources, Lit("sprite/blood.ase"));
decal->sprite_tint = Rgba32F(1, 1, 1, 0.25f);
decal->layer = Layer_FloorDecals;
SetXform(decal, xf);
@ -1249,9 +1249,9 @@ void StepSim(SimStepCtx *ctx)
{
Entity *ent = &world->ents[ent_index];
if (!ShouldSimulate(ent)) continue;
if (R_IsTagNil(ent->sprite)) continue;
if (IsResourceNil(ent->sprite)) continue;
S_Sheet *sheet = S_SheetFromResourceAwait(ent->sprite);
S_Sheet *sheet = S_SheetFromResource(ent->sprite);
/* Update animation */
{
@ -1359,8 +1359,8 @@ void StepSim(SimStepCtx *ctx)
if (!HasProp(ent, Prop_Attached)) continue;
Entity *parent = EntityFromId(world, ent->parent);
R_Tag parent_sprite = parent->sprite;
S_Sheet *parent_sheet = S_SheetFromResourceAwait(parent_sprite);
Resource parent_sprite = parent->sprite;
S_Sheet *parent_sheet = S_SheetFromResource(parent_sprite);
Xform parent_sprite_xf = parent->sprite_local_xform;
@ -1450,9 +1450,9 @@ void StepSim(SimStepCtx *ctx)
{
if (primary_triggered)
{
R_Tag sprite = ent->sprite;
Resource sprite = ent->sprite;
u32 animation_frame = ent->animation_frame;
S_Sheet *sheet = S_SheetFromResourceAwait(sprite);
S_Sheet *sheet = S_SheetFromResource(sprite);
Xform sprite_local_xform = ent->sprite_local_xform;
S_Slice out_slice = S_SliceFromName(sheet, Lit("out"), animation_frame);
Vec2 rel_pos = MulXformV2(sprite_local_xform, out_slice.center);
@ -1477,7 +1477,7 @@ void StepSim(SimStepCtx *ctx)
bullet->local_collider.points[0] = VEC2(0, 0);
bullet->local_collider.count = 1;
#else
bullet->sprite = R_TagFromStore(GameResources, Lit("sprite/bullet.ase"));
bullet->sprite = ResourceFromStore(GameResources, Lit("sprite/bullet.ase"));
bullet->sprite_collider_slice = Lit("shape");
#endif
}
@ -1499,9 +1499,9 @@ void StepSim(SimStepCtx *ctx)
{
if (primary_triggered)
{
R_Tag sprite = ent->sprite;
Resource sprite = ent->sprite;
u32 animation_frame = ent->animation_frame;
S_Sheet *sheet = S_SheetFromResourceAwait(sprite);
S_Sheet *sheet = S_SheetFromResource(sprite);
Xform sprite_local_xform = ent->sprite_local_xform;
S_Slice out_slice = S_SliceFromName(sheet, Lit("out"), animation_frame);
Vec2 rel_pos = MulXformV2(sprite_local_xform, out_slice.center);
@ -1673,7 +1673,7 @@ void StepSim(SimStepCtx *ctx)
Vec2 sprite_hold_pos;
Vec2 sprite_hold_dir;
{
S_Sheet *sheet = S_SheetFromResourceAwait(ent->sprite);
S_Sheet *sheet = S_SheetFromResource(ent->sprite);
S_Slice slice = S_SliceFromName(sheet, Lit("attach.wep"), ent->animation_frame);
sprite_hold_pos = slice.center;
sprite_hold_dir = slice.dir;

View File

@ -1,29 +0,0 @@
////////////////////////////////
//~ Tag helpers
b32 R_IsTagNil(R_Tag tag)
{
return tag.hash == 0;
}
R_Tag R_TagFromStore(R_Store *store, String name)
{
R_Tag result = ZI;
return result;
}
////////////////////////////////
//~ Resource operations
String R_DataFromTag(R_Tag tag)
{
String result = ZI;
return result;
}
String R_NameFromTag(R_Tag tag)
{
String result = ZI;
return result;
}

View File

@ -1,29 +0,0 @@
////////////////////////////////
//~ Tag types
Struct(R_Tag)
{
u64 hash;
};
////////////////////////////////
//~ Store types
#define R_DeclStore(name) extern R_Store name
Struct(R_Store)
{
i32 _;
};
////////////////////////////////
//~ Tag helpers
b32 R_IsTagNil(R_Tag tag);
R_Tag R_TagFromStore(R_Store *store, String name);
////////////////////////////////
//~ Resource operations
String R_DataFromTag(R_Tag tag);
String R_NameFromTag(R_Tag tag);

View File

@ -1,7 +0,0 @@
@Layer res
//- Api
@IncludeC res.h
//- Impl
@IncludeC res.c

View File

@ -5,8 +5,8 @@ JobDef(SND_LoadJob, sig, UNUSED id)
{
__prof;
TempArena scratch = BeginScratchNoConflict();
R_Tag resource = sig->resource;
String name = R_NameFromTag(resource);
Resource resource = sig->resource;
String name = NameFromResource(resource);
AC_Asset *asset = sig->asset;
SND_SoundFlag flags = sig->flags;
@ -17,7 +17,7 @@ JobDef(SND_LoadJob, sig, UNUSED id)
/* Decode */
MP3_Result decoded = ZI;
String resource_data = R_DataFromTag(resource);
String resource_data = DataFromResource(resource);
if (resource_data.len > 0)
{
u64 decode_flags = 0;
@ -80,13 +80,13 @@ JobDef(SND_LoadJob, sig, UNUSED id)
////////////////////////////////
//~ Load sound
AC_Asset *SND_LoadAsset(R_Tag resource, SND_SoundFlag flags, b32 wait)
AC_Asset *SND_LoadAsset(Resource resource, SND_SoundFlag flags, b32 wait)
{
__prof;
TempArena scratch = BeginScratchNoConflict();
/* Generate and append sound flags to name key */
String name = R_NameFromTag(resource);
String name = NameFromResource(resource);
String key = StringF(scratch.arena,
"%F%F_sound",
FmtString(name),
@ -113,7 +113,7 @@ AC_Asset *SND_LoadAsset(R_Tag resource, SND_SoundFlag flags, b32 wait)
return asset;
}
SND_Sound *SND_LoadSoundAsync(R_Tag resource, SND_SoundFlag flags)
SND_Sound *SND_LoadSoundAsync(Resource resource, SND_SoundFlag flags)
{
__prof;
AC_Asset *asset = SND_LoadAsset(resource, flags, 0);
@ -121,7 +121,7 @@ SND_Sound *SND_LoadSoundAsync(R_Tag resource, SND_SoundFlag flags)
return sound;
}
SND_Sound *SND_LoadSoundWait(R_Tag resource, SND_SoundFlag flags)
SND_Sound *SND_LoadSoundWait(Resource resource, SND_SoundFlag flags)
{
__prof;
AC_Asset *asset = SND_LoadAsset(resource, flags, 1);

View File

@ -19,7 +19,7 @@ Struct(SND_Sound)
////////////////////////////////
//~ Sound load operations
JobDecl(SND_LoadJob, { SND_SoundFlag flags; AC_Asset *asset; R_Tag resource; });
AC_Asset *SND_LoadAsset(R_Tag resource, SND_SoundFlag flags, b32 wait);
SND_Sound *SND_LoadSoundAsync(R_Tag resource, SND_SoundFlag flags);
SND_Sound *SND_LoadSoundWait(R_Tag resource, SND_SoundFlag flags);
JobDecl(SND_LoadJob, { SND_SoundFlag flags; AC_Asset *asset; Resource resource; });
AC_Asset *SND_LoadAsset(Resource resource, SND_SoundFlag flags, b32 wait);
SND_Sound *SND_LoadSoundAsync(Resource resource, SND_SoundFlag flags);
SND_Sound *SND_LoadSoundWait(Resource resource, SND_SoundFlag flags);

View File

@ -4,7 +4,6 @@
@Dep platform
@Dep mp3
@Dep asset_cache
@Dep res
//- Api
@IncludeC sound.h

View File

@ -10,34 +10,132 @@ void S_Startup(void)
}
////////////////////////////////
//~ Texture operations
//~ Load texture job
S_Texture *S_TextureFromResourceAwait(R_Tag resource)
JobDef(S_LoadTextureJob, sig, _)
{
S_Entry *entry = sig->entry;
AddCounter(&entry->texture_load_counter, -1);
}
JobDef(S_LoadSheetJob, sig, _)
{
S_Entry *entry = sig->entry;
AddCounter(&entry->sheet_load_counter, -1);
}
////////////////////////////////
//~ Cache
S_Entry *S_FetchEntry(Resource resource, JobPool pool, S_FetchFlag flags)
{
S_SharedState *g = &S_shared_state;
S_Entry *entry = 0;
{
S_EntryBin *bin = &g->entry_bins[resource.hash % S_EntryBinsCount];
/* Search for entry */
entry = bin->first;
{
Lock lock = LockS(&bin->mutex);
{
for (; entry; entry = entry->next_in_bin)
{
if (entry->resource.hash == resource.hash)
{
entry = entry;
break;
}
}
}
Unlock(&lock);
}
/* Entry not found, re-check & create */
if (!entry)
{
Lock lock = LockE(&bin->mutex);
{
/* Re-check */
entry = bin->first;
for (; entry; entry = entry->next_in_bin)
{
if (entry->resource.hash == resource.hash)
{
entry = entry;
break;
}
}
/* Create */
if (!entry)
{
entry = PushStruct(PermArena, S_Entry);
entry->resource = resource;
entry->texture = &S_NilTexture;
entry->sheet = &S_NilSheet;
AddCounter(&entry->texture_load_counter, 1);
AddCounter(&entry->sheet_load_counter, 1);
QueuePush_N(bin->first, bin->last, entry, next_in_bin);
}
}
Unlock(&lock);
}
}
/* Launch load jobs */
if ((flags & S_FetchFlag_Texture)
&& !Atomic32Fetch(&entry->texture_touched)
&& !Atomic32FetchTestSet(&entry->texture_touched, 0, 1))
{
RunJob(1, S_LoadTextureJob, pool, JobPriority_Inherit, 0, .entry = entry);
}
if ((flags & S_FetchFlag_Sheet)
&& !Atomic32Fetch(&entry->sheet_touched)
&& !Atomic32FetchTestSet(&entry->sheet_touched, 0, 1))
{
RunJob(1, S_LoadSheetJob, pool, JobPriority_Inherit, 0, .entry = entry);
}
return entry;
}
////////////////////////////////
//~ Sprite data retrieval operations
S_Texture *S_TextureFromResource(Resource resource)
{
S_Entry *entry = S_FetchEntry(resource, JobPool_Inherit, S_FetchFlag_Texture);
YieldOnCounter(&entry->texture_load_counter);
return entry->texture;
}
S_Texture *S_TextureFromResourceAsync(Resource resource)
{
S_Texture *result = &S_NilTexture;
S_Entry *entry = S_FetchEntry(resource, JobPool_Inherit, S_FetchFlag_Texture);
if (ValueFromCounter(&entry->texture_load_counter) <= 0)
{
result = entry->texture;
}
return result;
}
S_Texture *S_TextureFromResourceAsync(R_Tag resource)
S_Sheet *S_SheetFromResource(Resource resource)
{
S_Texture *result = &S_NilTexture;
S_Entry *entry = S_FetchEntry(resource, JobPool_Inherit, S_FetchFlag_Sheet);
YieldOnCounter(&entry->sheet_load_counter);
return entry->sheet;
}
S_Sheet *S_SheetFromResourceAsync(Resource resource)
{
S_Sheet *result = &S_NilSheet;
S_Entry *entry = S_FetchEntry(resource, JobPool_Inherit, S_FetchFlag_Sheet);
if (ValueFromCounter(&entry->sheet_load_counter) <= 0)
{
result = entry->sheet;
}
return result;
}
////////////////////////////////
//~ Sheet operations
S_Sheet *S_SheetFromResourceAwait(R_Tag resource)
{
S_Sheet *result = &S_NilSheet;
return result;
}
S_Sheet *S_SheetFromResourceAsync(R_Tag resource)
{
S_Sheet *result = &S_NilSheet;
return result;
}
//~ Sheet access operations
S_Span S_SpanFromName(S_Sheet *sheet, String name)
{

View File

@ -1,3 +1,28 @@
////////////////////////////////
//~ Cache types
Struct(S_Entry)
{
S_Entry *next_in_bin;
struct S_Texture *texture;
struct S_Sheet *sheet;
Atomic32 texture_touched;
Atomic32 sheet_touched;
Resource resource;
Counter texture_load_counter;
Counter sheet_load_counter;
};
Struct(S_EntryBin)
{
S_Entry *first;
S_Entry *last;
Mutex mutex;
};
////////////////////////////////
//~ Texture types
@ -88,9 +113,11 @@ extern Readonly S_Sheet S_NilSheet;
////////////////////////////////
//~ Shared state
#define S_EntryBinsCount 1024
Struct(S_SharedState)
{
i32 _;
S_EntryBin entry_bins[S_EntryBinsCount];
};
extern S_SharedState S_shared_state;
@ -101,16 +128,34 @@ extern S_SharedState S_shared_state;
void S_Startup(void);
////////////////////////////////
//~ Texture operations
//~ Load jobs
S_Texture *S_TextureFromResource(R_Tag resource);
S_Texture *S_TextureFromResourceAsync(R_Tag resource);
JobDecl(S_LoadTextureJob, { S_Entry *entry; });
JobDecl(S_LoadSheetJob, { S_Entry *entry; });
////////////////////////////////
//~ Sheet operations
//~ Cache operations
S_Sheet *S_SheetFromResourceAwait(R_Tag resource);
S_Sheet *S_SheetFromResourceAsync(R_Tag resource);
Enum(S_FetchFlag)
{
S_FetchFlag_None = 0,
S_FetchFlag_Texture = (1 << 0),
S_FetchFlag_Sheet = (1 << 1),
};
S_Entry *S_FetchEntry(Resource resource, JobPool pool, S_FetchFlag flags);
////////////////////////////////
//~ Sprite data retrieval operations
S_Texture *S_TextureFromResource(Resource resource);
S_Texture *S_TextureFromResourceAsync(Resource resource);
S_Sheet *S_SheetFromResource(Resource resource);
S_Sheet *S_SheetFromResourceAsync(Resource resource);
////////////////////////////////
//~ Sheet access operations
S_Span S_SpanFromName(S_Sheet *sheet, String name);
S_Frame S_FrameFromIndex(S_Sheet *sheet, u64 index);