convert indentation to 2 spaces
This commit is contained in:
parent
c1b768282f
commit
3377e3f94c
62
build.bat
62
build.bat
@ -11,7 +11,7 @@ set meta_build_cmd=cl.exe ../src/meta/meta.c -Od -Z7 -nologo -diagnostics:column
|
||||
set meta_rebuild_code=1317212284
|
||||
|
||||
if "%--force_meta_build%"=="1" (
|
||||
if exist meta.exe del meta.exe
|
||||
if exist meta.exe del meta.exe
|
||||
)
|
||||
|
||||
echo build_cmd: %program_build_cmd%
|
||||
@ -19,48 +19,48 @@ echo build_cmd: %program_build_cmd%
|
||||
::- Try to activate Visual Studio if devenv not detected
|
||||
:: Taken from wcap: https://github.com/mmozeiko/wcap/blob/aa25ccb806d7a6e1c0bfdcca863aabcd8e9badfa/build.cmd#L21-L29
|
||||
if "%PROCESSOR_ARCHITECTURE%" equ "AMD64" (
|
||||
set HOST_ARCH=x64
|
||||
set HOST_ARCH=x64
|
||||
) else if "%PROCESSOR_ARCHITECTURE%" equ "ARM64" (
|
||||
set HOST_ARCH=arm64
|
||||
set HOST_ARCH=arm64
|
||||
)
|
||||
where /Q cl.exe || (
|
||||
echo **************************************************************************
|
||||
echo WARNING: cl.exe not found, attempting to locate Visual Studio installation
|
||||
echo **************************************************************************
|
||||
echo WARNING: cl.exe not found, attempting to locate Visual Studio installation
|
||||
|
||||
set __VSCMD_ARG_NO_LOGO=1
|
||||
for /f "tokens=*" %%i in ('"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe" -latest -requires Microsoft.VisualStudio.Workload.NativeDesktop -property installationPath') do set VS=%%i
|
||||
if "!VS!" equ "" (
|
||||
echo ERROR: Visual Studio installation not found
|
||||
exit /b 1
|
||||
)
|
||||
echo Visual Studio installation located, activating development environment...
|
||||
call "!VS!\Common7\Tools\VsDevCmd.bat" -arch=%HOST_ARCH% -host_arch=%HOST_ARCH% -startdir=none -no_logo || exit /b 1
|
||||
echo Visual studio development environment activated
|
||||
echo **************************************************************************
|
||||
set __VSCMD_ARG_NO_LOGO=1
|
||||
for /f "tokens=*" %%i in ('"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe" -latest -requires Microsoft.VisualStudio.Workload.NativeDesktop -property installationPath') do set VS=%%i
|
||||
if "!VS!" equ "" (
|
||||
echo ERROR: Visual Studio installation not found
|
||||
exit /b 1
|
||||
)
|
||||
echo Visual Studio installation located, activating development environment...
|
||||
call "!VS!\Common7\Tools\VsDevCmd.bat" -arch=%HOST_ARCH% -host_arch=%HOST_ARCH% -startdir=none -no_logo || exit /b 1
|
||||
echo Visual studio development environment activated
|
||||
echo **************************************************************************
|
||||
)
|
||||
|
||||
::- Meta build
|
||||
:meta_build
|
||||
if not exist meta.exe (
|
||||
echo ====== Meta build =====
|
||||
%meta_build_cmd%
|
||||
set "rc=!errorlevel!"
|
||||
if !rc! NEQ 0 (
|
||||
if exist meta.exe del meta.exe
|
||||
exit /b !rc!
|
||||
)
|
||||
echo ====== Meta build =====
|
||||
%meta_build_cmd%
|
||||
set "rc=!errorlevel!"
|
||||
if !rc! NEQ 0 (
|
||||
if exist meta.exe del meta.exe
|
||||
exit /b !rc!
|
||||
)
|
||||
)
|
||||
|
||||
::- Program build
|
||||
if not "%--no_program_build%"=="1" (
|
||||
echo ======== Build ========
|
||||
%program_build_cmd%
|
||||
set "rc=!errorlevel!"
|
||||
if !rc! NEQ 0 (
|
||||
if !rc! EQU %meta_rebuild_code% (
|
||||
del meta.exe
|
||||
goto meta_build
|
||||
)
|
||||
exit /b !rc!
|
||||
echo ======== Build ========
|
||||
%program_build_cmd%
|
||||
set "rc=!errorlevel!"
|
||||
if !rc! NEQ 0 (
|
||||
if !rc! EQU %meta_rebuild_code% (
|
||||
del meta.exe
|
||||
goto meta_build
|
||||
)
|
||||
exit /b !rc!
|
||||
)
|
||||
)
|
||||
|
||||
1564
src/ase/ase.c
1564
src/ase/ase.c
File diff suppressed because it is too large
Load Diff
226
src/ase/ase.h
226
src/ase/ase.h
@ -3,33 +3,33 @@
|
||||
|
||||
Struct(ASE_Slice)
|
||||
{
|
||||
u32 start;
|
||||
Rng2I32 rect;
|
||||
ASE_Slice *next;
|
||||
u32 start;
|
||||
Rng2I32 rect;
|
||||
ASE_Slice *next;
|
||||
};
|
||||
|
||||
Struct(ASE_Span)
|
||||
{
|
||||
String name;
|
||||
u32 start;
|
||||
u32 end;
|
||||
ASE_Span *next;
|
||||
String name;
|
||||
u32 start;
|
||||
u32 end;
|
||||
ASE_Span *next;
|
||||
};
|
||||
|
||||
Struct(ASE_Frame)
|
||||
{
|
||||
u32 index;
|
||||
Rng2I32 rect;
|
||||
f64 duration;
|
||||
ASE_Frame *next;
|
||||
u32 index;
|
||||
Rng2I32 rect;
|
||||
f64 duration;
|
||||
ASE_Frame *next;
|
||||
};
|
||||
|
||||
Struct(ASE_SliceKey)
|
||||
{
|
||||
String name;
|
||||
u32 num_slices;
|
||||
ASE_Slice *first_slice;
|
||||
ASE_SliceKey *next;
|
||||
String name;
|
||||
u32 num_slices;
|
||||
ASE_Slice *first_slice;
|
||||
ASE_SliceKey *next;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -37,38 +37,38 @@ Struct(ASE_SliceKey)
|
||||
|
||||
Struct(ASE_Error)
|
||||
{
|
||||
String msg;
|
||||
ASE_Error *next;
|
||||
String msg;
|
||||
ASE_Error *next;
|
||||
};
|
||||
|
||||
Struct(ASE_ErrorList)
|
||||
{
|
||||
u64 count;
|
||||
ASE_Error *first;
|
||||
ASE_Error *last;
|
||||
u64 count;
|
||||
ASE_Error *first;
|
||||
ASE_Error *last;
|
||||
};
|
||||
|
||||
Struct(ASE_DecodedImage)
|
||||
{
|
||||
u32 width;
|
||||
u32 height;
|
||||
u32 *pixels; /* Array of [width * height] pixels */
|
||||
ASE_ErrorList errors;
|
||||
b32 ok;
|
||||
u32 width;
|
||||
u32 height;
|
||||
u32 *pixels; /* Array of [width * height] pixels */
|
||||
ASE_ErrorList errors;
|
||||
b32 ok;
|
||||
};
|
||||
|
||||
Struct(ASE_DecodedSheet)
|
||||
{
|
||||
Vec2 image_size;
|
||||
Vec2 frame_size;
|
||||
u32 num_frames;
|
||||
u32 num_spans;
|
||||
u32 num_slice_keys;
|
||||
ASE_Frame *first_frame;
|
||||
ASE_Span *first_span;
|
||||
ASE_SliceKey *first_slice_key;
|
||||
ASE_ErrorList errors;
|
||||
b32 ok;
|
||||
Vec2 image_size;
|
||||
Vec2 frame_size;
|
||||
u32 num_frames;
|
||||
u32 num_spans;
|
||||
u32 num_slice_keys;
|
||||
ASE_Frame *first_frame;
|
||||
ASE_Span *first_span;
|
||||
ASE_SliceKey *first_slice_key;
|
||||
ASE_ErrorList errors;
|
||||
b32 ok;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -78,29 +78,29 @@ Struct(ASE_DecodedSheet)
|
||||
|
||||
Struct(ASE_Bitbuff)
|
||||
{
|
||||
u8 *data;
|
||||
u64 cur_bit;
|
||||
u8 *data;
|
||||
u64 cur_bit;
|
||||
};
|
||||
|
||||
Enum(ASE_BlockType)
|
||||
{
|
||||
ASE_BlockType_Uncompressed = 0,
|
||||
ASE_BlockType_CompressedFixed = 1,
|
||||
ASE_BlockType_CompressedDynamic = 2,
|
||||
ASE_BlockType_Reserved = 3
|
||||
ASE_BlockType_Uncompressed = 0,
|
||||
ASE_BlockType_CompressedFixed = 1,
|
||||
ASE_BlockType_CompressedDynamic = 2,
|
||||
ASE_BlockType_Reserved = 3
|
||||
};
|
||||
|
||||
Struct(ASE_HuffEntry)
|
||||
{
|
||||
u16 symbol;
|
||||
u16 bits_used;
|
||||
u16 symbol;
|
||||
u16 bits_used;
|
||||
};
|
||||
|
||||
Struct(ASE_HuffDict)
|
||||
{
|
||||
u32 max_code_bits;
|
||||
u32 entries_count;
|
||||
ASE_HuffEntry *entries;
|
||||
u32 max_code_bits;
|
||||
u32 entries_count;
|
||||
ASE_HuffEntry *entries;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -108,36 +108,36 @@ Struct(ASE_HuffDict)
|
||||
|
||||
Packed(Struct(ASE_Header)
|
||||
{
|
||||
u32 file_size;
|
||||
u16 magic;
|
||||
u16 frames;
|
||||
u16 width;
|
||||
u16 height;
|
||||
u16 color_depth;
|
||||
u32 flags;
|
||||
u16 speed;
|
||||
u32 _1;
|
||||
u32 _2;
|
||||
u8 palette_entry;
|
||||
u8 _3[3];
|
||||
u16 num_colors;
|
||||
u8 pixel_width;
|
||||
u8 pixel_height;
|
||||
i16 grid_x;
|
||||
i16 grid_y;
|
||||
u16 grid_width;
|
||||
u16 grid_height;
|
||||
u8 _4[84];
|
||||
u32 file_size;
|
||||
u16 magic;
|
||||
u16 frames;
|
||||
u16 width;
|
||||
u16 height;
|
||||
u16 color_depth;
|
||||
u32 flags;
|
||||
u16 speed;
|
||||
u32 _1;
|
||||
u32 _2;
|
||||
u8 palette_entry;
|
||||
u8 _3[3];
|
||||
u16 num_colors;
|
||||
u8 pixel_width;
|
||||
u8 pixel_height;
|
||||
i16 grid_x;
|
||||
i16 grid_y;
|
||||
u16 grid_width;
|
||||
u16 grid_height;
|
||||
u8 _4[84];
|
||||
});
|
||||
|
||||
Packed(Struct(ASE_FrameHeader)
|
||||
{
|
||||
u32 bytes;
|
||||
u16 magic;
|
||||
u16 chunks_old;
|
||||
u16 frame_duration_ms;
|
||||
u8 _[2];
|
||||
u32 chunks_new;
|
||||
u32 bytes;
|
||||
u16 magic;
|
||||
u16 chunks_old;
|
||||
u16 frame_duration_ms;
|
||||
u8 _[2];
|
||||
u32 chunks_new;
|
||||
});
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -145,63 +145,63 @@ Packed(Struct(ASE_FrameHeader)
|
||||
|
||||
Enum(ASE_ChunkKind)
|
||||
{
|
||||
ASE_ChunkKind_OldPalette1 = 0x0004,
|
||||
ASE_ChunkKind_OldPalette2 = 0x0011,
|
||||
ASE_ChunkKind_Layer = 0x2004,
|
||||
ASE_ChunkKind_Cel = 0x2005,
|
||||
ASE_ChunkKind_CelExtra = 0x2006,
|
||||
ASE_ChunkKind_ColorProfile = 0x2007,
|
||||
ASE_ChunkKind_ExternalFiles = 0x2008,
|
||||
ASE_ChunkKind_Mask = 0x2016,
|
||||
ASE_ChunkKind_Path = 0x2017,
|
||||
ASE_ChunkKind_Tags = 0x2018,
|
||||
ASE_ChunkKind_Palette = 0x2019,
|
||||
ASE_ChunkKind_Userdata = 0x2020,
|
||||
ASE_ChunkKind_Slice = 0x2022,
|
||||
ASE_ChunkKind_Tileset = 0x2023
|
||||
ASE_ChunkKind_OldPalette1 = 0x0004,
|
||||
ASE_ChunkKind_OldPalette2 = 0x0011,
|
||||
ASE_ChunkKind_Layer = 0x2004,
|
||||
ASE_ChunkKind_Cel = 0x2005,
|
||||
ASE_ChunkKind_CelExtra = 0x2006,
|
||||
ASE_ChunkKind_ColorProfile = 0x2007,
|
||||
ASE_ChunkKind_ExternalFiles = 0x2008,
|
||||
ASE_ChunkKind_Mask = 0x2016,
|
||||
ASE_ChunkKind_Path = 0x2017,
|
||||
ASE_ChunkKind_Tags = 0x2018,
|
||||
ASE_ChunkKind_Palette = 0x2019,
|
||||
ASE_ChunkKind_Userdata = 0x2020,
|
||||
ASE_ChunkKind_Slice = 0x2022,
|
||||
ASE_ChunkKind_Tileset = 0x2023
|
||||
};
|
||||
|
||||
Enum(ASE_CelKind)
|
||||
{
|
||||
ASE_CelKind_RawImage = 0,
|
||||
ASE_CelKind_Linked = 1,
|
||||
ASE_CelKind_CompressedImage = 2,
|
||||
ASE_CelKind_CompressedTilemap = 3
|
||||
ASE_CelKind_RawImage = 0,
|
||||
ASE_CelKind_Linked = 1,
|
||||
ASE_CelKind_CompressedImage = 2,
|
||||
ASE_CelKind_CompressedTilemap = 3
|
||||
};
|
||||
|
||||
Struct(ASE_Layer)
|
||||
{
|
||||
u16 flags;
|
||||
u16 type;
|
||||
u16 child_level;
|
||||
u16 blend_mode;
|
||||
u8 opacity;
|
||||
String name;
|
||||
u32 tileset_index;
|
||||
u16 flags;
|
||||
u16 type;
|
||||
u16 child_level;
|
||||
u16 blend_mode;
|
||||
u8 opacity;
|
||||
String name;
|
||||
u32 tileset_index;
|
||||
|
||||
u32 index;
|
||||
ASE_Layer *next;
|
||||
u32 index;
|
||||
ASE_Layer *next;
|
||||
};
|
||||
|
||||
Struct(Ace_Cel)
|
||||
{
|
||||
u16 layer_index;
|
||||
i16 x_pos;
|
||||
i16 y_pos;
|
||||
u8 opacity;
|
||||
ASE_CelKind type;
|
||||
i16 z_index;
|
||||
u16 layer_index;
|
||||
i16 x_pos;
|
||||
i16 y_pos;
|
||||
u8 opacity;
|
||||
ASE_CelKind type;
|
||||
i16 z_index;
|
||||
|
||||
/* Linked cel */
|
||||
u16 frame_pos;
|
||||
/* Linked cel */
|
||||
u16 frame_pos;
|
||||
|
||||
/* Compressed image */
|
||||
u32 width;
|
||||
u32 height;
|
||||
u32 *pixels;
|
||||
/* Compressed image */
|
||||
u32 width;
|
||||
u32 height;
|
||||
u32 *pixels;
|
||||
|
||||
u16 frame_index;
|
||||
Ace_Cel *next;
|
||||
u16 frame_index;
|
||||
Ace_Cel *next;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
@ -2,39 +2,39 @@
|
||||
//~ Compiler flag checks
|
||||
|
||||
#ifndef IsConsoleApp
|
||||
#error Missing compile time definition for 'IsConsoleApp'
|
||||
#error Missing compile time definition for 'IsConsoleApp'
|
||||
#endif
|
||||
|
||||
#ifndef IsRtcEnabled
|
||||
#error Missing compile time definition for 'IsRtcEnabled'
|
||||
#error Missing compile time definition for 'IsRtcEnabled'
|
||||
#endif
|
||||
|
||||
#ifndef IsAsanEnabled
|
||||
#error Missing compile time definition for 'IsAsanEnabled'
|
||||
#error Missing compile time definition for 'IsAsanEnabled'
|
||||
#endif
|
||||
|
||||
#ifndef IsCrtlibEnabled
|
||||
#error Missing compile time definition for 'IsCrtlibEnabled'
|
||||
#error Missing compile time definition for 'IsCrtlibEnabled'
|
||||
#endif
|
||||
|
||||
#ifndef IsDebinfoEnabled
|
||||
#error Missing compile time definition for 'IsDebinfoEnabled'
|
||||
#error Missing compile time definition for 'IsDebinfoEnabled'
|
||||
#endif
|
||||
|
||||
#ifndef IsDeveloperModeEnabled
|
||||
#error Missing compile time definition for 'IsDeveloperModeEnabled'
|
||||
#error Missing compile time definition for 'IsDeveloperModeEnabled'
|
||||
#endif
|
||||
|
||||
#ifndef IsUnoptimized
|
||||
#error Missing compile time definition for 'IsUnoptimized'
|
||||
#error Missing compile time definition for 'IsUnoptimized'
|
||||
#endif
|
||||
|
||||
#ifndef IsTestingEnabled
|
||||
#error Missing compile time definition for 'IsTestingEnabled'
|
||||
#error Missing compile time definition for 'IsTestingEnabled'
|
||||
#endif
|
||||
|
||||
#ifndef IsHotSwappingEnabled
|
||||
#error Missing compile time definition for 'IsHotSwappingEnabled'
|
||||
#error Missing compile time definition for 'IsHotSwappingEnabled'
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -42,57 +42,57 @@
|
||||
|
||||
//- Compiler
|
||||
#if defined(__clang__)
|
||||
#define IsCompilerClang 1
|
||||
#define IsCompilerMsvc 0
|
||||
#define IsCompilerClang 1
|
||||
#define IsCompilerMsvc 0
|
||||
#elif defined(_MSC_VER)
|
||||
#define IsCompilerClang 0
|
||||
#define IsCompilerMsvc 1
|
||||
#define IsCompilerClang 0
|
||||
#define IsCompilerMsvc 1
|
||||
#else
|
||||
#error Unknown compiler
|
||||
#error Unknown compiler
|
||||
#endif
|
||||
|
||||
//- Language
|
||||
#if defined(__HLSL_VERSION)
|
||||
#define IsLanguageC 0
|
||||
#define IsLanguageG 1
|
||||
#define IsLanguageC 0
|
||||
#define IsLanguageG 1
|
||||
#else
|
||||
#define IsLanguageC 1
|
||||
#define IsLanguageG 0
|
||||
#define IsLanguageC 1
|
||||
#define IsLanguageG 0
|
||||
#endif
|
||||
|
||||
//- Platform system
|
||||
#if defined(_WIN32)
|
||||
#define IsPlatformWindows 1
|
||||
#define IsPlatformMac 0
|
||||
#define IsPlatformLinux 0
|
||||
#define IsPlatformWindows 1
|
||||
#define IsPlatformMac 0
|
||||
#define IsPlatformLinux 0
|
||||
#elif defined(__APPLE__) && defined(__MACH__)
|
||||
#define IsPlatformWindows 0
|
||||
#define IsPlatformMac 1
|
||||
#define IsPlatformLinux 0
|
||||
#define IsPlatformWindows 0
|
||||
#define IsPlatformMac 1
|
||||
#define IsPlatformLinux 0
|
||||
#elif defined(__gnu_linux__)
|
||||
#define IsPlatformWindows 0
|
||||
#define IsPlatformMac 0
|
||||
#define IsPlatformLinux 1
|
||||
#define IsPlatformWindows 0
|
||||
#define IsPlatformMac 0
|
||||
#define IsPlatformLinux 1
|
||||
#elif IsLanguageG
|
||||
#define IsPlatformWindows 0
|
||||
#define IsPlatformMac 0
|
||||
#define IsPlatformLinux 0
|
||||
#define IsPlatformWindows 0
|
||||
#define IsPlatformMac 0
|
||||
#define IsPlatformLinux 0
|
||||
#else
|
||||
#error Unknown platform
|
||||
#error Unknown platform
|
||||
#endif
|
||||
|
||||
//- Architecture
|
||||
#if defined(_M_AMD64) || defined(__amd64__)
|
||||
#define IsArchX64 1
|
||||
#define IsArchArm64 0
|
||||
#define IsArchX64 1
|
||||
#define IsArchArm64 0
|
||||
#elif defined(_M_ARM64) || defined(__aarch64__)
|
||||
#define IsArchX64 0
|
||||
#define IsArchArm64 1
|
||||
#define IsArchX64 0
|
||||
#define IsArchArm64 1
|
||||
#elif IsLanguageG
|
||||
#define IsArchX64 0
|
||||
#define IsArchArm64 0
|
||||
#define IsArchX64 0
|
||||
#define IsArchArm64 0
|
||||
#else
|
||||
#error Unknown architecture
|
||||
#error Unknown architecture
|
||||
#endif
|
||||
|
||||
//- Cache line size
|
||||
@ -102,21 +102,21 @@
|
||||
//- Windows NTDDI version
|
||||
/* TODO: Remove this */
|
||||
#if 0
|
||||
#if IsCompilerMsvc
|
||||
#define NTDDI_WIN11_DT 0x0C0A0000
|
||||
#define NTDDI_VERSION 0x0A000000
|
||||
#if IsRtcEnabled
|
||||
#define _ALLOW_RTCc_IN_STL 1
|
||||
#endif
|
||||
#endif
|
||||
#if IsCompilerMsvc
|
||||
#define NTDDI_WIN11_DT 0x0C0A0000
|
||||
#define NTDDI_VERSION 0x0A000000
|
||||
#if IsRtcEnabled
|
||||
#define _ALLOW_RTCc_IN_STL 1
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ C headers
|
||||
|
||||
#if IsLanguageC
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -129,27 +129,27 @@
|
||||
|
||||
//- Debug assert
|
||||
#if IsRtcEnabled
|
||||
#if IsCompilerMsvc
|
||||
#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))
|
||||
#define DEBUGBREAK __builtin_debugtrap()
|
||||
#endif
|
||||
#define DEBUGBREAKABLE { volatile i32 __DEBUGBREAKABLE_VAR = 0; __DEBUGBREAKABLE_VAR; } (void)0
|
||||
#if IsCompilerMsvc
|
||||
#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))
|
||||
#define DEBUGBREAK __builtin_debugtrap()
|
||||
#endif
|
||||
#define DEBUGBREAKABLE { volatile i32 __DEBUGBREAKABLE_VAR = 0; __DEBUGBREAKABLE_VAR; } (void)0
|
||||
#else
|
||||
#define Assert(cond) (void)(0)
|
||||
#define Assert(cond) (void)(0)
|
||||
#endif
|
||||
|
||||
//- Address sanitization
|
||||
#if IsAsanEnabled
|
||||
void __asan_poison_memory_region(void const volatile *, size_t);
|
||||
void __asan_unpoison_memory_region(void const volatile *add, size_t);
|
||||
#define AsanPoison(addr, size) __asan_poison_memory_region((addr), (size))
|
||||
#define AsanUnpoison(addr, size) __asan_unpoison_memory_region((addr), (size))
|
||||
void __asan_poison_memory_region(void const volatile *, size_t);
|
||||
void __asan_unpoison_memory_region(void const volatile *add, size_t);
|
||||
#define AsanPoison(addr, size) __asan_poison_memory_region((addr), (size))
|
||||
#define AsanUnpoison(addr, size) __asan_unpoison_memory_region((addr), (size))
|
||||
#else
|
||||
#define AsanPoison(addr, size)
|
||||
#define AsanUnpoison(addr, size)
|
||||
#define AsanPoison(addr, size)
|
||||
#define AsanUnpoison(addr, size)
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -157,24 +157,24 @@
|
||||
|
||||
//- Zero initialization
|
||||
#if IsLanguageC
|
||||
#define Zi { 0 }
|
||||
#define Zi { 0 }
|
||||
#else
|
||||
#define Zi { }
|
||||
#define Zi { }
|
||||
#endif
|
||||
|
||||
//- Inline
|
||||
#define Inline static inline
|
||||
|
||||
#if IsCompilerMsvc
|
||||
#define ForceInline Inline __forceinline
|
||||
#define ForceInline Inline __forceinline
|
||||
#else
|
||||
#define ForceInline Inline __attribute((always_inline))
|
||||
#define ForceInline Inline __attribute((always_inline))
|
||||
#endif
|
||||
|
||||
#if IsCompilerMsvc
|
||||
#define ForceNoInline __declspec(noinline)
|
||||
#define ForceNoInline __declspec(noinline)
|
||||
#else
|
||||
#define ForceNoInline __attribute__((noinline))
|
||||
#define ForceNoInline __attribute__((noinline))
|
||||
#endif
|
||||
|
||||
//- Static
|
||||
@ -183,35 +183,35 @@
|
||||
|
||||
//- Read-only
|
||||
#if IsPlatformWindows
|
||||
#if IsCompilerMsvc
|
||||
#pragma section(".rdata$", read)
|
||||
#define Readonly __declspec(allocate(".rdata$"))
|
||||
#else
|
||||
#define Readonly __declspec(allocate(".rdata$"))
|
||||
#endif
|
||||
#if IsCompilerMsvc
|
||||
#pragma section(".rdata$", read)
|
||||
#define Readonly __declspec(allocate(".rdata$"))
|
||||
#else
|
||||
#define Readonly __declspec(allocate(".rdata$"))
|
||||
#endif
|
||||
#elif IsPlatformMac
|
||||
#define Readonly __attribute((section("__TEXT,__const")))
|
||||
#define Readonly __attribute((section("__TEXT,__const")))
|
||||
#else
|
||||
#define Readonly __attribute((section(".rodata")))
|
||||
#define Readonly __attribute((section(".rodata")))
|
||||
#endif
|
||||
|
||||
//- Thread-local
|
||||
#if IsCompilerMsvc
|
||||
#define ThreadLocal __declspec(thread)
|
||||
#define ThreadLocal __declspec(thread)
|
||||
#endif
|
||||
|
||||
//- Compiler memory barriers
|
||||
#if IsCompilerMsvc
|
||||
#define CompilerBarrier() _ReadWriteBarrier()
|
||||
#define CompilerBarrier() _ReadWriteBarrier()
|
||||
#elif IsArchX64
|
||||
#define CompilerBarrier() __asm__ volatile("" ::: "memory")
|
||||
#define CompilerBarrier() __asm__ volatile("" ::: "memory")
|
||||
#endif
|
||||
|
||||
//- Fallthrough
|
||||
#if IsCompilerClang
|
||||
#define FALLTHROUGH __attribute((fallthrough))
|
||||
#define FALLTHROUGH __attribute((fallthrough))
|
||||
#else
|
||||
#define FALLTHROUGH
|
||||
#define FALLTHROUGH
|
||||
#endif
|
||||
|
||||
//- Preprocessor concatenation
|
||||
@ -253,23 +253,23 @@
|
||||
|
||||
#define SllQueuePushNZ(nil,f,l,n,next) \
|
||||
( \
|
||||
CheckNil(nil,f) ? \
|
||||
((f)=(l)=(n),SetNil(nil,(n)->next)) : \
|
||||
((l)->next=(n),(l)=(n),SetNil(nil,(n)->next)) \
|
||||
CheckNil(nil,f) ? \
|
||||
((f)=(l)=(n),SetNil(nil,(n)->next)) : \
|
||||
((l)->next=(n),(l)=(n),SetNil(nil,(n)->next)) \
|
||||
)
|
||||
|
||||
#define SllQueuePushFrontNZ(nil,f,l,n,next) \
|
||||
( \
|
||||
CheckNil(nil,f) ? \
|
||||
((f)=(l)=(n),SetNil(nil,(n)->next)) : \
|
||||
((n)->next=(f),(f)=(n)) \
|
||||
CheckNil(nil,f) ? \
|
||||
((f)=(l)=(n),SetNil(nil,(n)->next)) : \
|
||||
((n)->next=(f),(f)=(n)) \
|
||||
)
|
||||
|
||||
#define SllQueuePopNZ(nil,f,l,next) \
|
||||
( \
|
||||
(f)==(l) ? \
|
||||
(SetNil(nil,f),SetNil(nil,l)) : \
|
||||
((f)=(f)->next) \
|
||||
(f)==(l) ? \
|
||||
(SetNil(nil,f),SetNil(nil,l)) : \
|
||||
((f)=(f)->next) \
|
||||
)
|
||||
|
||||
#define SllQueuePushN(f,l,n,next) SllQueuePushNZ(0,f,l,n,next)
|
||||
@ -283,28 +283,28 @@
|
||||
|
||||
#define DllStackPushNPZ(nil,f,n,next,prev) \
|
||||
( \
|
||||
SetNil(nil,(n)->prev), \
|
||||
((n)->next = (f)), \
|
||||
CheckNil(nil,f) ? (0) : ((f)->prev = (n)), \
|
||||
((f) = (n)) \
|
||||
SetNil(nil,(n)->prev), \
|
||||
((n)->next = (f)), \
|
||||
CheckNil(nil,f) ? (0) : ((f)->prev = (n)), \
|
||||
((f) = (n)) \
|
||||
)
|
||||
|
||||
#define DllStackInsertNPZ(nil,f,p,n,next,prev) \
|
||||
( \
|
||||
(CheckNil(nil,f) || CheckNil(nil,p)) ? (DllStackPushNPZ(nil,(f),(n),next,prev)) : \
|
||||
( \
|
||||
((n)->prev = (p)), \
|
||||
((n)->next = (p)->next), \
|
||||
((p)->next = (n)), \
|
||||
CheckNil(nil,(p)->next) ? (0) : ((p)->next->prev = (n)) \
|
||||
) \
|
||||
(CheckNil(nil,f) || CheckNil(nil,p)) ? (DllStackPushNPZ(nil,(f),(n),next,prev)) : \
|
||||
( \
|
||||
((n)->prev = (p)), \
|
||||
((n)->next = (p)->next), \
|
||||
((p)->next = (n)), \
|
||||
CheckNil(nil,(p)->next) ? (0) : ((p)->next->prev = (n)) \
|
||||
) \
|
||||
)
|
||||
|
||||
#define DllStackRemoveNPZ(nil,f,n,next,prev) \
|
||||
( \
|
||||
((n) == (f) ? ((f) = (n)->next) : (0)), \
|
||||
(CheckNil(nil,(n)->next) ? (0) : ((n)->next->prev = (n)->prev)), \
|
||||
(CheckNil(nil,(n)->prev) ? (0) : ((n)->prev->next = (n)->next)) \
|
||||
((n) == (f) ? ((f) = (n)->next) : (0)), \
|
||||
(CheckNil(nil,(n)->next) ? (0) : ((n)->next->prev = (n)->prev)), \
|
||||
(CheckNil(nil,(n)->prev) ? (0) : ((n)->prev->next = (n)->next)) \
|
||||
)
|
||||
|
||||
#define DllStackPushNP(f,n,next,prev) DllStackPushNPZ(0,f,n,next,prev)
|
||||
@ -318,29 +318,29 @@
|
||||
|
||||
#define DllQueueInsertNPZ(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)) \
|
||||
) \
|
||||
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 DllQueueRemoveNPZ(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)) \
|
||||
((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 DllQueuePushNPZ(nil,f,l,n,next,prev) DllQueueInsertNPZ(nil,f,l,l,n,next,prev)
|
||||
@ -384,20 +384,20 @@
|
||||
//~ Intrinsic headers
|
||||
|
||||
#if IsLanguageC
|
||||
/* Intrinsic header info:
|
||||
* mmintrin.h MMX
|
||||
* xmmintrin.h SSE
|
||||
* emmintrin.h SSE2
|
||||
* pmmintrin.h SSE3
|
||||
* tmmintrin.h SSSE3
|
||||
* smmintrin.h SSE4.1
|
||||
* nmmintrin.h SSE4.2
|
||||
* ammintrin.h SSE4A
|
||||
* wmmintrin.h AES
|
||||
* immintrin.h AVX, AVX2, FMA
|
||||
*/
|
||||
#include <intrin.h>
|
||||
#include <nmmintrin.h> /* SSE4.2 */
|
||||
/* Intrinsic header info:
|
||||
* mmintrin.h MMX
|
||||
* xmmintrin.h SSE
|
||||
* emmintrin.h SSE2
|
||||
* pmmintrin.h SSE3
|
||||
* tmmintrin.h SSSE3
|
||||
* smmintrin.h SSE4.1
|
||||
* nmmintrin.h SSE4.2
|
||||
* ammintrin.h SSE4A
|
||||
* wmmintrin.h AES
|
||||
* immintrin.h AVX, AVX2, FMA
|
||||
*/
|
||||
#include <intrin.h>
|
||||
#include <nmmintrin.h> /* SSE4.2 */
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -410,14 +410,14 @@
|
||||
|
||||
//- Enum
|
||||
#if IsLanguageC
|
||||
#define Enum(name) typedef enum name name; enum name
|
||||
#define Enum(name) typedef enum name name; enum name
|
||||
#else
|
||||
#define Enum(name) enum name
|
||||
#define Enum(name) enum name
|
||||
#endif
|
||||
|
||||
//- alignof
|
||||
#if IsLanguageC && (IsCompilerMsvc || __STDC_VERSION__ < 202311L)
|
||||
#define alignof(type) __alignof(type)
|
||||
#define alignof(type) __alignof(type)
|
||||
#endif
|
||||
|
||||
//- field sizeof
|
||||
@ -425,7 +425,7 @@
|
||||
|
||||
//- countof
|
||||
#if IsLanguageC
|
||||
#define countof(a) (sizeof(a) / sizeof((a)[0]))
|
||||
#define countof(a) (sizeof(a) / sizeof((a)[0]))
|
||||
#endif
|
||||
|
||||
//- IsFixedArray
|
||||
@ -434,11 +434,11 @@
|
||||
|
||||
//- offsetof
|
||||
#if !IsCompilerMsvc
|
||||
#ifdef _CRT_USE_BUILTIN_OFFSETOF
|
||||
#define offsetof(type, field) __builtin_offsetof(type, field)
|
||||
#else
|
||||
#define offsetof(type, field) ((u64)&(((type *)0)->field))
|
||||
#endif
|
||||
#ifdef _CRT_USE_BUILTIN_OFFSETOF
|
||||
#define offsetof(type, field) __builtin_offsetof(type, field)
|
||||
#else
|
||||
#define offsetof(type, field) ((u64)&(((type *)0)->field))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//- struct region
|
||||
@ -449,44 +449,44 @@
|
||||
|
||||
//- Packed
|
||||
#if IsCompilerMsvc
|
||||
#define Packed(s) __pragma(pack(push, 1)) s __pragma(pack(pop))
|
||||
#define Packed(s) __pragma(pack(push, 1)) s __pragma(pack(pop))
|
||||
#elif IsCompilerClang
|
||||
#define Packed(s) s __attribute((__packed__))
|
||||
#define Packed(s) s __attribute((__packed__))
|
||||
#elif IsLanguageG
|
||||
#define Packed(s) s
|
||||
#define Packed(s) s
|
||||
#endif
|
||||
|
||||
//- alignas
|
||||
#if (IsCompilerMsvc && IsLanguageC) || (IsLanguageC && __STDC_VERSION__ < 202311L)
|
||||
#if IsCompilerMsvc
|
||||
#define alignas(n) __declspec(align(n))
|
||||
#else
|
||||
#define alignas(n) __attribute__((aligned(n)))
|
||||
#endif
|
||||
#if IsCompilerMsvc
|
||||
#define alignas(n) __declspec(align(n))
|
||||
#else
|
||||
#define alignas(n) __attribute__((aligned(n)))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Scalar types
|
||||
|
||||
#if IsLanguageC
|
||||
typedef int8_t i8;
|
||||
typedef int16_t i16;
|
||||
typedef int32_t i32;
|
||||
typedef int64_t i64;
|
||||
typedef uint8_t u8;
|
||||
typedef uint16_t u16;
|
||||
typedef uint32_t u32;
|
||||
typedef uint64_t u64;
|
||||
typedef float f32;
|
||||
typedef double f64;
|
||||
typedef i8 b8;
|
||||
typedef u32 b32;
|
||||
Struct(U128) { u64 hi; u64 lo; };
|
||||
typedef int8_t i8;
|
||||
typedef int16_t i16;
|
||||
typedef int32_t i32;
|
||||
typedef int64_t i64;
|
||||
typedef uint8_t u8;
|
||||
typedef uint16_t u16;
|
||||
typedef uint32_t u32;
|
||||
typedef uint64_t u64;
|
||||
typedef float f32;
|
||||
typedef double f64;
|
||||
typedef i8 b8;
|
||||
typedef u32 b32;
|
||||
Struct(U128) { u64 hi; u64 lo; };
|
||||
#elif IsLanguageG
|
||||
typedef int i32;
|
||||
typedef uint u32;
|
||||
typedef float f32;
|
||||
typedef uint b32;
|
||||
typedef int i32;
|
||||
typedef uint u32;
|
||||
typedef float f32;
|
||||
typedef uint b32;
|
||||
#endif
|
||||
|
||||
//- Min / max constants
|
||||
@ -507,274 +507,274 @@
|
||||
|
||||
//- Float infinity / nan constants
|
||||
#if IsLanguageC
|
||||
Global const u32 _f32_infinity_u32 = 0x7f800000;
|
||||
Global const f32 *_f32_infinity = (f32 *)&_f32_infinity_u32;
|
||||
#define F32Infinity (*_f32_infinity)
|
||||
Global const u32 _f32_infinity_u32 = 0x7f800000;
|
||||
Global const f32 *_f32_infinity = (f32 *)&_f32_infinity_u32;
|
||||
#define F32Infinity (*_f32_infinity)
|
||||
|
||||
Global const u64 _f64_infinity_u64 = 0x7ff0000000000000ULL;
|
||||
Global const f64 *_f64_infinity = (f64 *)&_f64_infinity_u64;
|
||||
#define F64Infinity (*_f64_infinity)
|
||||
Global const u64 _f64_infinity_u64 = 0x7ff0000000000000ULL;
|
||||
Global const f64 *_f64_infinity = (f64 *)&_f64_infinity_u64;
|
||||
#define F64Infinity (*_f64_infinity)
|
||||
|
||||
Global const u32 _f32_nan_u32 = 0x7f800001;
|
||||
Global const f32 *_f32_nan = (f32 *)&_f32_nan_u32;
|
||||
#define F32Nan (*_f32_nan)
|
||||
Global const u32 _f32_nan_u32 = 0x7f800001;
|
||||
Global const f32 *_f32_nan = (f32 *)&_f32_nan_u32;
|
||||
#define F32Nan (*_f32_nan)
|
||||
|
||||
Global const u64 _f64_nan_u64 = 0x7ff8000000000001;
|
||||
Global const f64 *_f64_nan = (f64 *)&_f64_nan_u64;
|
||||
#define F64Nan (*_f64_nan)
|
||||
Global const u64 _f64_nan_u64 = 0x7ff8000000000001;
|
||||
Global const f64 *_f64_nan = (f64 *)&_f64_nan_u64;
|
||||
#define F64Nan (*_f64_nan)
|
||||
|
||||
#define IsF32Nan(x) (x != x)
|
||||
#define IsF64Nan(x) (x != x)
|
||||
#define IsF32Nan(x) (x != x)
|
||||
#define IsF64Nan(x) (x != x)
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Atomics
|
||||
|
||||
#if IsLanguageC
|
||||
//- Atomic types
|
||||
Struct(Atomic8) { volatile i8 _v; };
|
||||
Struct(Atomic16) { volatile i16 _v; };
|
||||
Struct(Atomic32) { volatile i32 _v; };
|
||||
Struct(Atomic64) { volatile i64 _v; };
|
||||
//- Atomic types
|
||||
Struct(Atomic8) { volatile i8 _v; };
|
||||
Struct(Atomic16) { volatile i16 _v; };
|
||||
Struct(Atomic32) { volatile i32 _v; };
|
||||
Struct(Atomic64) { volatile i64 _v; };
|
||||
|
||||
//- Cache-line isolated aligned atomic types
|
||||
AlignedStruct(Atomic8Padded, CachelineSize) { Atomic8 v; };
|
||||
AlignedStruct(Atomic16Padded, CachelineSize) { Atomic16 v; };
|
||||
AlignedStruct(Atomic32Padded, CachelineSize) { Atomic32 v; };
|
||||
AlignedStruct(Atomic64Padded, CachelineSize) { Atomic64 v; };
|
||||
StaticAssert(alignof(Atomic8Padded) == CachelineSize && sizeof(Atomic8Padded) % CachelineSize == 0);
|
||||
StaticAssert(alignof(Atomic16Padded) == CachelineSize && sizeof(Atomic16Padded) % CachelineSize == 0);
|
||||
StaticAssert(alignof(Atomic32Padded) == CachelineSize && sizeof(Atomic32Padded) % CachelineSize == 0);
|
||||
StaticAssert(alignof(Atomic64Padded) == CachelineSize && sizeof(Atomic64Padded) % CachelineSize == 0);
|
||||
//- Cache-line isolated aligned atomic types
|
||||
AlignedStruct(Atomic8Padded, CachelineSize) { Atomic8 v; };
|
||||
AlignedStruct(Atomic16Padded, CachelineSize) { Atomic16 v; };
|
||||
AlignedStruct(Atomic32Padded, CachelineSize) { Atomic32 v; };
|
||||
AlignedStruct(Atomic64Padded, CachelineSize) { Atomic64 v; };
|
||||
StaticAssert(alignof(Atomic8Padded) == CachelineSize && sizeof(Atomic8Padded) % CachelineSize == 0);
|
||||
StaticAssert(alignof(Atomic16Padded) == CachelineSize && sizeof(Atomic16Padded) % CachelineSize == 0);
|
||||
StaticAssert(alignof(Atomic32Padded) == CachelineSize && sizeof(Atomic32Padded) % CachelineSize == 0);
|
||||
StaticAssert(alignof(Atomic64Padded) == CachelineSize && sizeof(Atomic64Padded) % CachelineSize == 0);
|
||||
|
||||
#if IsPlatformWindows && IsArchX64
|
||||
//- 8 bit atomic ops
|
||||
ForceInline i8 Atomic8Fetch (Atomic8 *x) { CompilerBarrier(); i8 result = x->_v; CompilerBarrier(); return result; }
|
||||
ForceInline void Atomic8Set (Atomic8 *x, i8 e) { CompilerBarrier(); x->_v = e; CompilerBarrier(); }
|
||||
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 ops
|
||||
ForceInline i16 Atomic16Fetch (Atomic16 *x) { CompilerBarrier(); i16 result = x->_v; CompilerBarrier(); return result; }
|
||||
ForceInline void Atomic16Set (Atomic16 *x, i16 e) { CompilerBarrier(); x->_v = e; CompilerBarrier(); }
|
||||
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 Atomic16FetchXor (Atomic16 *x, i16 c) { return (i16)_InterlockedXor16(&x->_v, c); }
|
||||
ForceInline i16 Atomic16FetchAdd (Atomic16 *x, i16 a) { return (i16)_InterlockedExchangeAdd16(&x->_v, a); }
|
||||
//- 32 bit atomic ops
|
||||
ForceInline i32 Atomic32Fetch (Atomic32 *x) { CompilerBarrier(); i32 result = x->_v; CompilerBarrier(); return result; }
|
||||
ForceInline void Atomic32Set (Atomic32 *x, i32 e) { CompilerBarrier(); x->_v = e; CompilerBarrier(); }
|
||||
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 ops
|
||||
ForceInline i64 Atomic64Fetch (Atomic64 *x) { CompilerBarrier(); i64 result = x->_v; CompilerBarrier(); return result; }
|
||||
ForceInline void Atomic64Set (Atomic64 *x, i64 e) { CompilerBarrier(); x->_v = e; CompilerBarrier(); }
|
||||
ForceInline i64 Atomic64FetchSet (Atomic64 *x, i64 e) { return (i64)_InterlockedExchange64(&x->_v, e); }
|
||||
ForceInline i64 Atomic64FetchTestSet (Atomic64 *x, i64 c, i64 e) { return (i64)_InterlockedCompareExchange64(&x->_v, e, c); }
|
||||
ForceInline i64 Atomic64FetchXor (Atomic64 *x, i64 c) { return (i64)_InterlockedXor64(&x->_v, c); }
|
||||
ForceInline i64 Atomic64FetchAdd (Atomic64 *x, i64 a) { return (i64)_InterlockedExchangeAdd64(&x->_v, a); }
|
||||
#else
|
||||
#error Atomics not implemented
|
||||
#endif
|
||||
#if IsPlatformWindows && IsArchX64
|
||||
//- 8 bit atomic ops
|
||||
ForceInline i8 Atomic8Fetch (Atomic8 *x) { CompilerBarrier(); i8 result = x->_v; CompilerBarrier(); return result; }
|
||||
ForceInline void Atomic8Set (Atomic8 *x, i8 e) { CompilerBarrier(); x->_v = e; CompilerBarrier(); }
|
||||
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 ops
|
||||
ForceInline i16 Atomic16Fetch (Atomic16 *x) { CompilerBarrier(); i16 result = x->_v; CompilerBarrier(); return result; }
|
||||
ForceInline void Atomic16Set (Atomic16 *x, i16 e) { CompilerBarrier(); x->_v = e; CompilerBarrier(); }
|
||||
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 Atomic16FetchXor (Atomic16 *x, i16 c) { return (i16)_InterlockedXor16(&x->_v, c); }
|
||||
ForceInline i16 Atomic16FetchAdd (Atomic16 *x, i16 a) { return (i16)_InterlockedExchangeAdd16(&x->_v, a); }
|
||||
//- 32 bit atomic ops
|
||||
ForceInline i32 Atomic32Fetch (Atomic32 *x) { CompilerBarrier(); i32 result = x->_v; CompilerBarrier(); return result; }
|
||||
ForceInline void Atomic32Set (Atomic32 *x, i32 e) { CompilerBarrier(); x->_v = e; CompilerBarrier(); }
|
||||
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 ops
|
||||
ForceInline i64 Atomic64Fetch (Atomic64 *x) { CompilerBarrier(); i64 result = x->_v; CompilerBarrier(); return result; }
|
||||
ForceInline void Atomic64Set (Atomic64 *x, i64 e) { CompilerBarrier(); x->_v = e; CompilerBarrier(); }
|
||||
ForceInline i64 Atomic64FetchSet (Atomic64 *x, i64 e) { return (i64)_InterlockedExchange64(&x->_v, e); }
|
||||
ForceInline i64 Atomic64FetchTestSet (Atomic64 *x, i64 c, i64 e) { return (i64)_InterlockedCompareExchange64(&x->_v, e, c); }
|
||||
ForceInline i64 Atomic64FetchXor (Atomic64 *x, i64 c) { return (i64)_InterlockedXor64(&x->_v, c); }
|
||||
ForceInline i64 Atomic64FetchAdd (Atomic64 *x, i64 a) { return (i64)_InterlockedExchangeAdd64(&x->_v, a); }
|
||||
#else
|
||||
#error Atomics not implemented
|
||||
#endif
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Ticket mutex
|
||||
|
||||
#if IsLanguageC
|
||||
Struct(TicketMutex)
|
||||
{
|
||||
Atomic64Padded ticket;
|
||||
Atomic64Padded serving;
|
||||
};
|
||||
Struct(TicketMutex)
|
||||
{
|
||||
Atomic64Padded ticket;
|
||||
Atomic64Padded serving;
|
||||
};
|
||||
|
||||
ForceInline void LockTicketMutex(TicketMutex *tm)
|
||||
ForceInline void LockTicketMutex(TicketMutex *tm)
|
||||
{
|
||||
i64 ticket = Atomic64FetchAdd(&tm->ticket.v, 1);
|
||||
while (Atomic64Fetch(&tm->serving.v) != ticket)
|
||||
{
|
||||
i64 ticket = Atomic64FetchAdd(&tm->ticket.v, 1);
|
||||
while (Atomic64Fetch(&tm->serving.v) != ticket)
|
||||
{
|
||||
_mm_pause();
|
||||
}
|
||||
_mm_pause();
|
||||
}
|
||||
}
|
||||
|
||||
ForceInline void UnlockTicketMutex(TicketMutex *tm)
|
||||
{
|
||||
/* TODO: Atomic set w/ known ticket + 1 */
|
||||
Atomic64FetchAdd(&tm->serving.v, 1);
|
||||
}
|
||||
ForceInline void UnlockTicketMutex(TicketMutex *tm)
|
||||
{
|
||||
/* TODO: Atomic set w/ known ticket + 1 */
|
||||
Atomic64FetchAdd(&tm->serving.v, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ String types
|
||||
|
||||
#if IsLanguageC
|
||||
#define STRING(size, data) ((String) { (size), (data) })
|
||||
#define Zstr ((String) { 0, 0})
|
||||
#define Lit(cstr_lit) (String) { (sizeof((cstr_lit)) - 1), (u8 *)(cstr_lit) }
|
||||
#define CompLit(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, ArenaFirst(arena, u8)))
|
||||
#define STRING(size, data) ((String) { (size), (data) })
|
||||
#define Zstr ((String) { 0, 0})
|
||||
#define Lit(cstr_lit) (String) { (sizeof((cstr_lit)) - 1), (u8 *)(cstr_lit) }
|
||||
#define CompLit(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, ArenaFirst(arena, u8)))
|
||||
|
||||
#define StringFromFixedArray(a) \
|
||||
( \
|
||||
Assert(IsFixedArray(a)), \
|
||||
((String) { .len = sizeof(a), .text = (u8 *)(a) }) \
|
||||
)
|
||||
#define StringFromFixedArray(a) \
|
||||
( \
|
||||
Assert(IsFixedArray(a)), \
|
||||
((String) { .len = sizeof(a), .text = (u8 *)(a) }) \
|
||||
)
|
||||
|
||||
Struct(String)
|
||||
{
|
||||
u64 len;
|
||||
u8 *text;
|
||||
};
|
||||
Struct(String)
|
||||
{
|
||||
u64 len;
|
||||
u8 *text;
|
||||
};
|
||||
|
||||
Struct(String16)
|
||||
{
|
||||
u64 len;
|
||||
u16 *text;
|
||||
};
|
||||
Struct(String16)
|
||||
{
|
||||
u64 len;
|
||||
u16 *text;
|
||||
};
|
||||
|
||||
Struct(String32)
|
||||
{
|
||||
u64 len;
|
||||
u32 *text;
|
||||
};
|
||||
Struct(String32)
|
||||
{
|
||||
u64 len;
|
||||
u32 *text;
|
||||
};
|
||||
|
||||
Struct(StringArray)
|
||||
{
|
||||
u64 count;
|
||||
String *strings;
|
||||
};
|
||||
Struct(StringArray)
|
||||
{
|
||||
u64 count;
|
||||
String *strings;
|
||||
};
|
||||
|
||||
Struct(StringListNode)
|
||||
{
|
||||
String s;
|
||||
StringListNode *next;
|
||||
StringListNode *prev;
|
||||
};
|
||||
Struct(StringListNode)
|
||||
{
|
||||
String s;
|
||||
StringListNode *next;
|
||||
StringListNode *prev;
|
||||
};
|
||||
|
||||
Struct(StringList)
|
||||
{
|
||||
StringListNode *first;
|
||||
StringListNode *last;
|
||||
u64 count;
|
||||
};
|
||||
Struct(StringList)
|
||||
{
|
||||
StringListNode *first;
|
||||
StringListNode *last;
|
||||
u64 count;
|
||||
};
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Arena types
|
||||
|
||||
#if IsLanguageC
|
||||
Struct(Arena)
|
||||
{
|
||||
u64 pos;
|
||||
u64 committed;
|
||||
u64 reserved;
|
||||
};
|
||||
Struct(Arena)
|
||||
{
|
||||
u64 pos;
|
||||
u64 committed;
|
||||
u64 reserved;
|
||||
};
|
||||
|
||||
Struct(TempArena)
|
||||
{
|
||||
Arena *arena;
|
||||
u64 start_pos;
|
||||
};
|
||||
Struct(TempArena)
|
||||
{
|
||||
Arena *arena;
|
||||
u64 start_pos;
|
||||
};
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Resource types
|
||||
|
||||
#if IsLanguageC
|
||||
#define ResourceEmbeddedMagic 0xfc060937194f4406
|
||||
#define ResourceEmbeddedMagic 0xfc060937194f4406
|
||||
|
||||
Struct(ResourceStore)
|
||||
{
|
||||
u64 v;
|
||||
};
|
||||
Struct(ResourceStore)
|
||||
{
|
||||
u64 v;
|
||||
};
|
||||
|
||||
Struct(ResourceKey)
|
||||
{
|
||||
u64 v;
|
||||
};
|
||||
Struct(ResourceKey)
|
||||
{
|
||||
u64 v;
|
||||
};
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Cpu topology types
|
||||
|
||||
#if IsLanguageC
|
||||
Struct(CpuTopologyInfo)
|
||||
{
|
||||
i32 num_logical_cores; /* Includes P cores, Non-P cores, SMT siblings */
|
||||
i32 num_physical_cores; /* Includes P Cores, Non-P Cores */
|
||||
i32 num_physical_performance_cores; /* Includes P Cores */
|
||||
i32 num_physical_non_performance_cores; /* Includes Non-P cores */
|
||||
};
|
||||
Struct(CpuTopologyInfo)
|
||||
{
|
||||
i32 num_logical_cores; /* Includes P cores, Non-P cores, SMT siblings */
|
||||
i32 num_physical_cores; /* Includes P Cores, Non-P Cores */
|
||||
i32 num_physical_performance_cores; /* Includes P Cores */
|
||||
i32 num_physical_non_performance_cores; /* Includes Non-P cores */
|
||||
};
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Shader linkage types
|
||||
|
||||
#if IsLanguageC
|
||||
Struct(VertexShader) { ResourceKey resource; };
|
||||
Struct(PixelShader) { ResourceKey resource; };
|
||||
Struct(ComputeShader) { ResourceKey resource; };
|
||||
Struct(VertexShader) { ResourceKey resource; };
|
||||
Struct(PixelShader) { ResourceKey resource; };
|
||||
Struct(ComputeShader) { ResourceKey resource; };
|
||||
#elif IsLanguageG
|
||||
#define Semantic(t, n) t n : n
|
||||
#define ComputeShader(name, x) [numthreads(x, 1, 1)] void name(Semantic(u32, SV_DispatchThreadID))
|
||||
#define ComputeShader2D(name, x, y) [numthreads(x, y, 1)] void name(Semantic(Vec2U32, SV_DispatchThreadID))
|
||||
#define ComputeShader3D(name, x, y, z) [numthreads(x, y, z)] void name(Semantic(Vec3U32, SV_DispatchThreadID))
|
||||
#define VertexShader(name, return_type) return_type name(Semantic(u32, SV_InstanceID), Semantic(u32, SV_VertexID))
|
||||
#define PixelShader(name, return_type, ...) return_type name(__VA_ARGS__)
|
||||
#define Semantic(t, n) t n : n
|
||||
#define ComputeShader(name, x) [numthreads(x, 1, 1)] void name(Semantic(u32, SV_DispatchThreadID))
|
||||
#define ComputeShader2D(name, x, y) [numthreads(x, y, 1)] void name(Semantic(Vec2U32, SV_DispatchThreadID))
|
||||
#define ComputeShader3D(name, x, y, z) [numthreads(x, y, z)] void name(Semantic(Vec3U32, SV_DispatchThreadID))
|
||||
#define VertexShader(name, return_type) return_type name(Semantic(u32, SV_InstanceID), Semantic(u32, SV_VertexID))
|
||||
#define PixelShader(name, return_type, ...) return_type name(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Exit callback types
|
||||
|
||||
#if IsLanguageC
|
||||
#define ExitFuncDef(name) void name(void)
|
||||
typedef ExitFuncDef(ExitFunc);
|
||||
#define ExitFuncDef(name) void name(void)
|
||||
typedef ExitFuncDef(ExitFunc);
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ @hookdecl Core api
|
||||
|
||||
#if IsLanguageC
|
||||
StringList GetRawCommandline(void);
|
||||
void Echo(String msg);
|
||||
b32 Panic(String msg);
|
||||
b32 IsRunningInDebugger(void);
|
||||
i64 TimeNs(void);
|
||||
void TrueRand(String buffer);
|
||||
CpuTopologyInfo GetCpuTopologyInfo(void);
|
||||
void SleepSeconds(f64 seconds);
|
||||
StringList GetRawCommandline(void);
|
||||
void Echo(String msg);
|
||||
b32 Panic(String msg);
|
||||
b32 IsRunningInDebugger(void);
|
||||
i64 TimeNs(void);
|
||||
void TrueRand(String buffer);
|
||||
CpuTopologyInfo GetCpuTopologyInfo(void);
|
||||
void SleepSeconds(f64 seconds);
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ @hookdecl Swap
|
||||
|
||||
#if IsLanguageC
|
||||
b32 IsSwappedIn(void);
|
||||
b32 IsSwappingOut(void);
|
||||
b32 IsSwappedIn(void);
|
||||
b32 IsSwappingOut(void);
|
||||
|
||||
String SwappedStateFromName(Arena *arena, String name);
|
||||
void WriteSwappedState(String name, String data);
|
||||
String SwappedStateFromName(Arena *arena, String name);
|
||||
void WriteSwappedState(String name, String data);
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ @hookdecl Exit
|
||||
|
||||
#if IsLanguageC
|
||||
void OnExit(ExitFunc *func);
|
||||
void SignalExit(i32 code);
|
||||
void ExitNow(i32 code);
|
||||
void OnExit(ExitFunc *func);
|
||||
void SignalExit(i32 code);
|
||||
void ExitNow(i32 code);
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ @hookdecl Bootstrap layers
|
||||
|
||||
#if IsLanguageC
|
||||
void BootstrapLayers(void);
|
||||
void BootstrapLayers(void);
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
@ -3,86 +3,86 @@
|
||||
|
||||
Arena *AcquireArena(u64 reserve)
|
||||
{
|
||||
reserve += ArenaHeaderSize;
|
||||
reserve += ArenaHeaderSize;
|
||||
|
||||
/* Round up to nearest block size */
|
||||
u64 block_remainder = reserve % ArenaBlockSize;
|
||||
if (block_remainder > 0)
|
||||
{
|
||||
reserve += ArenaBlockSize - block_remainder;
|
||||
}
|
||||
/* Round up to nearest block size */
|
||||
u64 block_remainder = reserve % ArenaBlockSize;
|
||||
if (block_remainder > 0)
|
||||
{
|
||||
reserve += ArenaBlockSize - block_remainder;
|
||||
}
|
||||
|
||||
u8 *base = ReserveMemory(reserve);
|
||||
if (!base)
|
||||
{
|
||||
Panic(Lit("Failed to reserve memory"));
|
||||
}
|
||||
u64 reserved = reserve;
|
||||
AddGstat(ArenaMemoryReserved, reserve);
|
||||
u8 *base = ReserveMemory(reserve);
|
||||
if (!base)
|
||||
{
|
||||
Panic(Lit("Failed to reserve memory"));
|
||||
}
|
||||
u64 reserved = reserve;
|
||||
AddGstat(ArenaMemoryReserved, reserve);
|
||||
|
||||
/* Commit initial block */
|
||||
base = CommitMemory(base, ArenaBlockSize);
|
||||
if (!base)
|
||||
{
|
||||
Panic(Lit("Failed to commit initial memory block: System may be out of memory"));
|
||||
}
|
||||
/* Commit initial block */
|
||||
base = CommitMemory(base, ArenaBlockSize);
|
||||
if (!base)
|
||||
{
|
||||
Panic(Lit("Failed to commit initial memory block: System may be out of memory"));
|
||||
}
|
||||
|
||||
Assert(((u64)base & 0xFFF) == 0); /* Base should be 4k aligned */
|
||||
StaticAssert(ArenaHeaderSize <= ArenaBlockSize); /* Header must fit in first block */
|
||||
StaticAssert(sizeof(Arena) <= ArenaHeaderSize); /* Arena struct must fit in header */
|
||||
Assert(((u64)base & 0xFFF) == 0); /* Base should be 4k aligned */
|
||||
StaticAssert(ArenaHeaderSize <= ArenaBlockSize); /* Header must fit in first block */
|
||||
StaticAssert(sizeof(Arena) <= ArenaHeaderSize); /* Arena struct must fit in header */
|
||||
|
||||
AsanPoison(base + sizeof(Arena), ArenaBlockSize - sizeof(Arena));
|
||||
AddGstat(ArenaMemoryCommitted, ArenaBlockSize);
|
||||
AddGstat(NumArenas, 1);
|
||||
AsanPoison(base + sizeof(Arena), ArenaBlockSize - sizeof(Arena));
|
||||
AddGstat(ArenaMemoryCommitted, ArenaBlockSize);
|
||||
AddGstat(NumArenas, 1);
|
||||
|
||||
/* Create & return arena header at beginning of block */
|
||||
Arena *arena = (Arena *)base;
|
||||
ZeroStruct(arena);
|
||||
arena->committed = ArenaBlockSize - ArenaHeaderSize;
|
||||
arena->reserved = reserved;
|
||||
return arena;
|
||||
/* Create & return arena header at beginning of block */
|
||||
Arena *arena = (Arena *)base;
|
||||
ZeroStruct(arena);
|
||||
arena->committed = ArenaBlockSize - ArenaHeaderSize;
|
||||
arena->reserved = reserved;
|
||||
return arena;
|
||||
}
|
||||
|
||||
void ReleaseArena(Arena *arena)
|
||||
{
|
||||
AsanUnpoison(arena, arena->committed + ArenaHeaderSize);
|
||||
AddGstat(ArenaMemoryCommitted, -(i64)(arena->committed - ArenaHeaderSize));
|
||||
AddGstat(ArenaMemoryReserved, -(i64)(arena->reserved));
|
||||
AddGstat(NumArenas, -1);
|
||||
ReleaseMemory(arena);
|
||||
AsanUnpoison(arena, arena->committed + ArenaHeaderSize);
|
||||
AddGstat(ArenaMemoryCommitted, -(i64)(arena->committed - ArenaHeaderSize));
|
||||
AddGstat(ArenaMemoryReserved, -(i64)(arena->reserved));
|
||||
AddGstat(NumArenas, -1);
|
||||
ReleaseMemory(arena);
|
||||
}
|
||||
|
||||
/* Copy the memory from src to dst, replacing old contents.
|
||||
* Dst will expand if necessary. */
|
||||
* Dst will expand if necessary. */
|
||||
void CopyArena(Arena *dst, Arena *src)
|
||||
{
|
||||
ResetArena(dst);
|
||||
u64 data_size = src->pos;
|
||||
u8 *data_src = ArenaFirst(src, u8);
|
||||
u8 *data_dst = PushBytesNoZero(dst, data_size, 1);
|
||||
CopyBytes(data_dst, data_src, data_size);
|
||||
ResetArena(dst);
|
||||
u64 data_size = src->pos;
|
||||
u8 *data_src = ArenaFirst(src, u8);
|
||||
u8 *data_dst = PushBytesNoZero(dst, data_size, 1);
|
||||
CopyBytes(data_dst, data_src, data_size);
|
||||
}
|
||||
|
||||
void ShrinkArena(Arena *arena)
|
||||
{
|
||||
/* Not implemented */
|
||||
Assert(0);
|
||||
/* Not implemented */
|
||||
Assert(0);
|
||||
}
|
||||
|
||||
void SetArenaReadonly(Arena *arena)
|
||||
{
|
||||
SetMemoryReadonly(arena, arena->committed + ArenaHeaderSize);
|
||||
SetMemoryReadonly(arena, arena->committed + ArenaHeaderSize);
|
||||
}
|
||||
|
||||
void SetArenaReadWrite(Arena *arena)
|
||||
{
|
||||
SetMemoryReadWrite(arena, arena->committed + ArenaHeaderSize);
|
||||
SetMemoryReadWrite(arena, arena->committed + ArenaHeaderSize);
|
||||
}
|
||||
|
||||
void *ResetArena(Arena *arena)
|
||||
{
|
||||
PopTo(arena, 0);
|
||||
return ArenaFirst(arena, u8);
|
||||
PopTo(arena, 0);
|
||||
return ArenaFirst(arena, u8);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -90,89 +90,89 @@ void *ResetArena(Arena *arena)
|
||||
|
||||
void *PushBytesNoZero(Arena *arena, u64 size, u64 align)
|
||||
{
|
||||
Assert(align > 0);
|
||||
Assert(align > 0);
|
||||
|
||||
u8 *base = ArenaFirst(arena, u8);
|
||||
u64 start_pos = AlignU64(arena->pos, align);
|
||||
u64 end_pos = start_pos + size;
|
||||
void *result = base + start_pos;
|
||||
u8 *base = ArenaFirst(arena, u8);
|
||||
u64 start_pos = AlignU64(arena->pos, align);
|
||||
u64 end_pos = start_pos + size;
|
||||
void *result = base + start_pos;
|
||||
|
||||
/* Commit new block(s) */
|
||||
if (size > 0 && end_pos > arena->committed)
|
||||
/* Commit new block(s) */
|
||||
if (size > 0 && end_pos > arena->committed)
|
||||
{
|
||||
u64 blocks_needed = (end_pos - arena->committed + ArenaBlockSize - 1) / ArenaBlockSize;
|
||||
u64 commit_bytes = blocks_needed * ArenaBlockSize;
|
||||
u64 new_capacity = arena->committed + commit_bytes;
|
||||
if (new_capacity > arena->reserved)
|
||||
{
|
||||
u64 blocks_needed = (end_pos - arena->committed + ArenaBlockSize - 1) / ArenaBlockSize;
|
||||
u64 commit_bytes = blocks_needed * ArenaBlockSize;
|
||||
u64 new_capacity = arena->committed + commit_bytes;
|
||||
if (new_capacity > arena->reserved)
|
||||
{
|
||||
/* Hard fail if we overflow reserved memory for now */
|
||||
Panic(Lit("Failed to commit new memory block: Overflow of reserved memory"));
|
||||
}
|
||||
void *commit_address = base + arena->committed;
|
||||
if (!CommitMemory(commit_address, commit_bytes))
|
||||
{
|
||||
/* Hard fail on memory allocation failure for now */
|
||||
Panic(Lit("Failed to commit new memory block: System may be out of memory"));
|
||||
}
|
||||
arena->committed += commit_bytes;
|
||||
AddGstat(ArenaMemoryCommitted, commit_bytes);
|
||||
AsanPoison(commit_address, commit_bytes);
|
||||
/* Hard fail if we overflow reserved memory for now */
|
||||
Panic(Lit("Failed to commit new memory block: Overflow of reserved memory"));
|
||||
}
|
||||
void *commit_address = base + arena->committed;
|
||||
if (!CommitMemory(commit_address, commit_bytes))
|
||||
{
|
||||
/* Hard fail on memory allocation failure for now */
|
||||
Panic(Lit("Failed to commit new memory block: System may be out of memory"));
|
||||
}
|
||||
arena->committed += commit_bytes;
|
||||
AddGstat(ArenaMemoryCommitted, commit_bytes);
|
||||
AsanPoison(commit_address, commit_bytes);
|
||||
}
|
||||
|
||||
AsanUnpoison(result, size);
|
||||
arena->pos = end_pos;
|
||||
AsanUnpoison(result, size);
|
||||
arena->pos = end_pos;
|
||||
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
|
||||
void *PushBytes(Arena *arena, u64 size, u64 align)
|
||||
{
|
||||
void *p = PushBytesNoZero(arena, size, align);
|
||||
ZeroBytes(p, size);
|
||||
return p;
|
||||
void *p = PushBytesNoZero(arena, size, align);
|
||||
ZeroBytes(p, size);
|
||||
return p;
|
||||
}
|
||||
|
||||
void *PushAlign(Arena *arena, u64 align)
|
||||
{
|
||||
u64 push_count = AlignU64(arena->pos, align) - arena->pos;
|
||||
return PushStructsNoZero(arena, u8, push_count);
|
||||
u64 push_count = AlignU64(arena->pos, align) - arena->pos;
|
||||
return PushStructsNoZero(arena, u8, push_count);
|
||||
}
|
||||
|
||||
void PopTo(Arena *arena, u64 pos)
|
||||
{
|
||||
Assert(arena->pos >= pos);
|
||||
AsanPoison(ArenaFirst(arena, u8) + pos, arena->pos - pos);
|
||||
arena->pos = pos;
|
||||
Assert(arena->pos >= pos);
|
||||
AsanPoison(ArenaFirst(arena, u8) + pos, arena->pos - pos);
|
||||
arena->pos = pos;
|
||||
}
|
||||
|
||||
void PopBytesNoCopy(Arena *arena, u64 size)
|
||||
{
|
||||
Assert(arena->pos >= size);
|
||||
u64 new_pos = arena->pos - size;
|
||||
AsanPoison(ArenaFirst(arena, u8) + new_pos, arena->pos - new_pos);
|
||||
arena->pos = new_pos;
|
||||
Assert(arena->pos >= size);
|
||||
u64 new_pos = arena->pos - size;
|
||||
AsanPoison(ArenaFirst(arena, u8) + new_pos, arena->pos - new_pos);
|
||||
arena->pos = new_pos;
|
||||
}
|
||||
|
||||
void PopBytes(Arena *arena, u64 size, void *copy_dst)
|
||||
{
|
||||
Assert(arena->pos >= size);
|
||||
u64 new_pos = arena->pos - size;
|
||||
void *src = (void *)(ArenaFirst(arena, u8) + new_pos);
|
||||
CopyBytes(copy_dst, src, size);
|
||||
AsanPoison(ArenaFirst(arena, u8) + new_pos, arena->pos - new_pos);
|
||||
arena->pos = new_pos;
|
||||
Assert(arena->pos >= size);
|
||||
u64 new_pos = arena->pos - size;
|
||||
void *src = (void *)(ArenaFirst(arena, u8) + new_pos);
|
||||
CopyBytes(copy_dst, src, size);
|
||||
AsanPoison(ArenaFirst(arena, u8) + new_pos, arena->pos - new_pos);
|
||||
arena->pos = new_pos;
|
||||
}
|
||||
|
||||
void *ArenaFirst_(Arena *arena, u64 align)
|
||||
{
|
||||
void *result = (void *)AlignU64((u64)arena + ArenaHeaderSize, align);
|
||||
return result;
|
||||
void *result = (void *)AlignU64((u64)arena + ArenaHeaderSize, align);
|
||||
return result;
|
||||
}
|
||||
|
||||
void *ArenaNext_(Arena *arena, u64 align)
|
||||
{
|
||||
void *result = (void *)AlignU64((u64)arena + ArenaHeaderSize + arena->pos, align);
|
||||
return result;
|
||||
void *result = (void *)AlignU64((u64)arena + ArenaHeaderSize + arena->pos, align);
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -180,15 +180,15 @@ void *ArenaNext_(Arena *arena, u64 align)
|
||||
|
||||
TempArena BeginTempArena(Arena *arena)
|
||||
{
|
||||
TempArena t = Zi;
|
||||
t.arena = arena;
|
||||
t.start_pos = arena->pos;
|
||||
return t;
|
||||
TempArena t = Zi;
|
||||
t.arena = arena;
|
||||
t.start_pos = arena->pos;
|
||||
return t;
|
||||
}
|
||||
|
||||
void EndTempArena(TempArena temp)
|
||||
{
|
||||
PopTo(temp.arena, temp.start_pos);
|
||||
PopTo(temp.arena, temp.start_pos);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -196,29 +196,29 @@ void EndTempArena(TempArena temp)
|
||||
|
||||
TempArena BeginScratch(Arena *potential_conflict)
|
||||
{
|
||||
/* This function is currently hard-coded for 2 thread-local scratch arenas */
|
||||
StaticAssert(countof(Base_tl.arenas.scratch) == 2);
|
||||
/* This function is currently hard-coded for 2 thread-local scratch arenas */
|
||||
StaticAssert(countof(Base_tl.arenas.scratch) == 2);
|
||||
|
||||
/* Use `BeginScratchNoConflict` if no conflicts are present */
|
||||
Assert(potential_conflict != 0);
|
||||
/* Use `BeginScratchNoConflict` if no conflicts are present */
|
||||
Assert(potential_conflict != 0);
|
||||
|
||||
Arena *scratch_arena = Base_tl.arenas.scratch[0];
|
||||
if (scratch_arena == potential_conflict)
|
||||
{
|
||||
scratch_arena = Base_tl.arenas.scratch[1];
|
||||
}
|
||||
TempArena temp = BeginTempArena(scratch_arena);
|
||||
return temp;
|
||||
Arena *scratch_arena = Base_tl.arenas.scratch[0];
|
||||
if (scratch_arena == potential_conflict)
|
||||
{
|
||||
scratch_arena = Base_tl.arenas.scratch[1];
|
||||
}
|
||||
TempArena temp = BeginTempArena(scratch_arena);
|
||||
return temp;
|
||||
}
|
||||
|
||||
TempArena BeginScratchNoConflict_(void)
|
||||
{
|
||||
Arena *scratch_arena = Base_tl.arenas.scratch[0];
|
||||
TempArena temp = BeginTempArena(scratch_arena);
|
||||
return temp;
|
||||
Arena *scratch_arena = Base_tl.arenas.scratch[0];
|
||||
TempArena temp = BeginTempArena(scratch_arena);
|
||||
return temp;
|
||||
}
|
||||
|
||||
void EndScratch(TempArena scratch_temp)
|
||||
{
|
||||
EndTempArena(scratch_temp);
|
||||
EndTempArena(scratch_temp);
|
||||
}
|
||||
|
||||
@ -6,8 +6,8 @@
|
||||
|
||||
Struct(ThreadLocalArenaCtx)
|
||||
{
|
||||
Arena *perm;
|
||||
Arena *scratch[2];
|
||||
Arena *perm;
|
||||
Arena *scratch[2];
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -68,11 +68,11 @@ TempArena BeginScratchNoConflict_(void);
|
||||
void EndScratch(TempArena scratch_temp);
|
||||
|
||||
/* This macro declares an unused "arena" variable that will produce a shadowing
|
||||
* warning variable is present (due to shadowing). This is for catching obvious
|
||||
* cases of `BeginScratchNoConflict` getting called when an `arena` variable
|
||||
* already exists in the caller's scope. */
|
||||
* warning variable is present (due to shadowing). This is for catching obvious
|
||||
* cases of `BeginScratchNoConflict` getting called when an `arena` variable
|
||||
* already exists in the caller's scope. */
|
||||
#define BeginScratchNoConflict() \
|
||||
BeginScratchNoConflict_(); \
|
||||
do { \
|
||||
u8 arena = 0; \
|
||||
} while (0)
|
||||
BeginScratchNoConflict_(); \
|
||||
do { \
|
||||
u8 arena = 0; \
|
||||
} while (0)
|
||||
|
||||
@ -3,8 +3,8 @@
|
||||
|
||||
void BootstrapAsync(void)
|
||||
{
|
||||
/* TODO: Dynamic lane counts */
|
||||
DispatchWave(Lit("Async"), 4, AsyncWorkerEntryPoint, 0);
|
||||
/* TODO: Dynamic lane counts */
|
||||
DispatchWave(Lit("Async"), 4, AsyncWorkerEntryPoint, 0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -12,23 +12,23 @@ void BootstrapAsync(void)
|
||||
|
||||
void OnAsyncTick(AsyncTickCallbackFunc *func)
|
||||
{
|
||||
Arena *perm = PermArena();
|
||||
Arena *perm = PermArena();
|
||||
|
||||
AsyncTickCallbackNode *n = PushStruct(perm, AsyncTickCallbackNode);
|
||||
n->callback.func = func;
|
||||
AsyncTickCallbackNode *n = PushStruct(perm, AsyncTickCallbackNode);
|
||||
n->callback.func = func;
|
||||
|
||||
Lock lock = LockE(&Base.async.mutex);
|
||||
{
|
||||
SllQueuePush(Base.async.first_callback_node, Base.async.last_callback_node, n);
|
||||
Base.async.callback_nodes_count += 1;
|
||||
}
|
||||
Unlock(&lock);
|
||||
Lock lock = LockE(&Base.async.mutex);
|
||||
{
|
||||
SllQueuePush(Base.async.first_callback_node, Base.async.last_callback_node, n);
|
||||
Base.async.callback_nodes_count += 1;
|
||||
}
|
||||
Unlock(&lock);
|
||||
}
|
||||
|
||||
void SignalAsyncTick(void)
|
||||
{
|
||||
Atomic64FetchAdd(&Base.async.signal.v, 1);
|
||||
FutexWakeNeq(&Base.async.signal.v);
|
||||
Atomic64FetchAdd(&Base.async.signal.v, 1);
|
||||
FutexWakeNeq(&Base.async.signal.v);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -36,67 +36,67 @@ void SignalAsyncTick(void)
|
||||
|
||||
void AsyncWorkerEntryPoint(WaveLaneCtx *lane)
|
||||
{
|
||||
AsyncTickCtx tick = Zi;
|
||||
tick.arena = AcquireArena(Gibi(64));
|
||||
AsyncTickCtx tick = Zi;
|
||||
tick.arena = AcquireArena(Gibi(64));
|
||||
|
||||
/* Tick forever */
|
||||
for (;;)
|
||||
/* Tick forever */
|
||||
for (;;)
|
||||
{
|
||||
AsyncWorkerCtx *w = &Base.async.worker;
|
||||
|
||||
//////////////////////////////
|
||||
//- Begin tick
|
||||
|
||||
if (lane->idx == 0)
|
||||
{
|
||||
AsyncWorkerCtx *w = &Base.async.worker;
|
||||
|
||||
//////////////////////////////
|
||||
//- Begin tick
|
||||
|
||||
if (lane->idx == 0)
|
||||
/* Wait for signal */
|
||||
{
|
||||
i64 cur_signal = Atomic64Fetch(&Base.async.signal.v);
|
||||
while (cur_signal <= w->last_seen_signal)
|
||||
{
|
||||
/* Wait for signal */
|
||||
{
|
||||
i64 cur_signal = Atomic64Fetch(&Base.async.signal.v);
|
||||
while (cur_signal <= w->last_seen_signal)
|
||||
{
|
||||
FutexYieldNeq(&Base.async.signal.v, &cur_signal, sizeof(cur_signal));
|
||||
cur_signal = Atomic64Fetch(&Base.async.signal.v);
|
||||
}
|
||||
w->last_seen_signal = cur_signal;
|
||||
}
|
||||
/* Collect callbacks */
|
||||
{
|
||||
Lock lock = LockE(&Base.async.mutex);
|
||||
{
|
||||
w->callbacks_count = Base.async.callback_nodes_count;
|
||||
w->callbacks = PushStructsNoZero(tick.arena, AsyncTickCallback, w->callbacks_count);
|
||||
u64 callback_idx = 0;
|
||||
for (AsyncTickCallbackNode *n = Base.async.first_callback_node; n; n = n->next)
|
||||
{
|
||||
w->callbacks[callback_idx] = n->callback;
|
||||
++callback_idx;
|
||||
}
|
||||
}
|
||||
Unlock(&lock);
|
||||
}
|
||||
FutexYieldNeq(&Base.async.signal.v, &cur_signal, sizeof(cur_signal));
|
||||
cur_signal = Atomic64Fetch(&Base.async.signal.v);
|
||||
}
|
||||
|
||||
WaveSync(lane);
|
||||
|
||||
//////////////////////////////
|
||||
//- Run async callbacks
|
||||
|
||||
for (u64 callback_idx = 0; callback_idx < w->callbacks_count; ++callback_idx)
|
||||
w->last_seen_signal = cur_signal;
|
||||
}
|
||||
/* Collect callbacks */
|
||||
{
|
||||
Lock lock = LockE(&Base.async.mutex);
|
||||
{
|
||||
AsyncTickCallback *callback = &w->callbacks[callback_idx];
|
||||
callback->func(lane, &tick);
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- End tick
|
||||
|
||||
WaveSync(lane);
|
||||
|
||||
ResetArena(tick.arena);
|
||||
{
|
||||
Arena *tick_arena = tick.arena;
|
||||
ZeroStruct(&tick);
|
||||
tick.arena = tick_arena;
|
||||
w->callbacks_count = Base.async.callback_nodes_count;
|
||||
w->callbacks = PushStructsNoZero(tick.arena, AsyncTickCallback, w->callbacks_count);
|
||||
u64 callback_idx = 0;
|
||||
for (AsyncTickCallbackNode *n = Base.async.first_callback_node; n; n = n->next)
|
||||
{
|
||||
w->callbacks[callback_idx] = n->callback;
|
||||
++callback_idx;
|
||||
}
|
||||
}
|
||||
Unlock(&lock);
|
||||
}
|
||||
}
|
||||
|
||||
WaveSync(lane);
|
||||
|
||||
//////////////////////////////
|
||||
//- Run async callbacks
|
||||
|
||||
for (u64 callback_idx = 0; callback_idx < w->callbacks_count; ++callback_idx)
|
||||
{
|
||||
AsyncTickCallback *callback = &w->callbacks[callback_idx];
|
||||
callback->func(lane, &tick);
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- End tick
|
||||
|
||||
WaveSync(lane);
|
||||
|
||||
ResetArena(tick.arena);
|
||||
{
|
||||
Arena *tick_arena = tick.arena;
|
||||
ZeroStruct(&tick);
|
||||
tick.arena = tick_arena;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,37 +6,37 @@ typedef void AsyncTickCallbackFunc(WaveLaneCtx *lane, AsyncTickCtx *tick);
|
||||
|
||||
Struct(AsyncTickCallback)
|
||||
{
|
||||
AsyncTickCallbackFunc *func;
|
||||
AsyncTickCallbackFunc *func;
|
||||
};
|
||||
|
||||
Struct(AsyncTickCallbackNode)
|
||||
{
|
||||
AsyncTickCallbackNode *next;
|
||||
AsyncTickCallback callback;
|
||||
AsyncTickCallbackNode *next;
|
||||
AsyncTickCallback callback;
|
||||
};
|
||||
|
||||
Struct(AsyncTickCtx)
|
||||
{
|
||||
Arena *arena;
|
||||
Arena *arena;
|
||||
};
|
||||
|
||||
Struct(AsyncWorkerCtx)
|
||||
{
|
||||
i64 last_seen_signal;
|
||||
i64 last_seen_signal;
|
||||
|
||||
u64 callbacks_count;
|
||||
AsyncTickCallback *callbacks;
|
||||
u64 callbacks_count;
|
||||
AsyncTickCallback *callbacks;
|
||||
};
|
||||
|
||||
Struct(AsyncCtx)
|
||||
{
|
||||
Mutex mutex;
|
||||
u64 callback_nodes_count;
|
||||
AsyncTickCallbackNode *first_callback_node;
|
||||
AsyncTickCallbackNode *last_callback_node;
|
||||
Mutex mutex;
|
||||
u64 callback_nodes_count;
|
||||
AsyncTickCallbackNode *first_callback_node;
|
||||
AsyncTickCallbackNode *last_callback_node;
|
||||
|
||||
AsyncWorkerCtx worker;
|
||||
Atomic64Padded signal;
|
||||
AsyncWorkerCtx worker;
|
||||
Atomic64Padded signal;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -4,13 +4,13 @@
|
||||
//- Buff
|
||||
Struct(BB_Buff)
|
||||
{
|
||||
b32 is_backed_by_arena;
|
||||
b32 is_backed_by_arena;
|
||||
|
||||
/* If `is_arena_bitbuff` is 1, this dynamically-sized arena will be used for reading & writing (meaning writing cannot overflow) */
|
||||
Arena *arena;
|
||||
/* If `is_arena_bitbuff` is 1, this dynamically-sized arena will be used for reading & writing (meaning writing cannot overflow) */
|
||||
Arena *arena;
|
||||
|
||||
/* If `is_arena_bitbuff` is 0, this fixed-sized buffer willl be used for reading & writing */
|
||||
String fixed_buffer;
|
||||
/* If `is_arena_bitbuff` is 0, this fixed-sized buffer willl be used for reading & writing */
|
||||
String fixed_buffer;
|
||||
};
|
||||
|
||||
//- Writer
|
||||
@ -18,24 +18,24 @@ Struct(BB_Buff)
|
||||
#define BB_WriterOverflowArenaPushSize 4096
|
||||
Struct(BB_Writer)
|
||||
{
|
||||
b32 overflowed;
|
||||
BB_Buff *bb;
|
||||
u8 *base;
|
||||
u64 cur_bit;
|
||||
b32 overflowed;
|
||||
BB_Buff *bb;
|
||||
u8 *base;
|
||||
u64 cur_bit;
|
||||
#if BITBUFF_DEBUG
|
||||
b32 debug_enabled;
|
||||
b32 debug_enabled;
|
||||
#endif
|
||||
};
|
||||
|
||||
//- Reader
|
||||
Struct(BB_Reader)
|
||||
{
|
||||
b32 overflowed;
|
||||
u64 base_len;
|
||||
u8 *base;
|
||||
u64 cur_bit;
|
||||
b32 overflowed;
|
||||
u64 base_len;
|
||||
u8 *base;
|
||||
u64 cur_bit;
|
||||
#if BITBUFF_DEBUG
|
||||
b32 debug_enabled;
|
||||
b32 debug_enabled;
|
||||
#endif
|
||||
};
|
||||
|
||||
@ -47,16 +47,16 @@ Struct(BB_Reader)
|
||||
/* Magic numbers inserted to verify read/write type & length */
|
||||
Enum(BB_DebugMagicKind)
|
||||
{
|
||||
BB_DebugMagicKind_AlignBytes = 0x20A4,
|
||||
BB_DebugMagicKind_AlignToNextByte = 0x379A,
|
||||
BB_DebugMagicKind_UBits = 0xCB4A,
|
||||
BB_DebugMagicKind_IBits = 0xB30D,
|
||||
BB_DebugMagicKind_UV = 0xE179,
|
||||
BB_DebugMagicKind_IV = 0x981f,
|
||||
BB_DebugMagicKind_F32 = 0x56F9,
|
||||
BB_DebugMagicKind_F64 = 0x7053,
|
||||
BB_DebugMagicKind_Uid = 0xA24E,
|
||||
BB_DebugMagicKind_String = 0x7866
|
||||
BB_DebugMagicKind_AlignBytes = 0x20A4,
|
||||
BB_DebugMagicKind_AlignToNextByte = 0x379A,
|
||||
BB_DebugMagicKind_UBits = 0xCB4A,
|
||||
BB_DebugMagicKind_IBits = 0xB30D,
|
||||
BB_DebugMagicKind_UV = 0xE179,
|
||||
BB_DebugMagicKind_IV = 0x981f,
|
||||
BB_DebugMagicKind_F32 = 0x56F9,
|
||||
BB_DebugMagicKind_F64 = 0x7053,
|
||||
BB_DebugMagicKind_Uid = 0xA24E,
|
||||
BB_DebugMagicKind_String = 0x7866
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -118,11 +118,11 @@ void BB_WriteSeekBytes(BB_Writer *bw, u64 num_bytes);
|
||||
//~ Writer debug
|
||||
|
||||
#if BITBUFF_DEBUG
|
||||
void BB_WriteDebugMagic(BB_Writer *bw, BB_DebugMagicKind magic, u8 num_bits);
|
||||
void BB_WriteDebugMarker(BB_Writer *bw, String name);
|
||||
void BB_WriteDebugMagic(BB_Writer *bw, BB_DebugMagicKind magic, u8 num_bits);
|
||||
void BB_WriteDebugMarker(BB_Writer *bw, String name);
|
||||
#else
|
||||
#define BB_WriteDebugMagic(bw, magic, num_bits)
|
||||
#define BB_WriteDebugMarker(bw, name)
|
||||
#define BB_WriteDebugMagic(bw, magic, num_bits)
|
||||
#define BB_WriteDebugMarker(bw, name)
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
@ -5,29 +5,29 @@
|
||||
|
||||
BuddyCtx *AcquireBuddyCtx(u64 reserve)
|
||||
{
|
||||
/* TODO: Determine meta reserve dynamically */
|
||||
Arena *meta_arena = AcquireArena(Gibi(64));
|
||||
BuddyCtx *ctx = PushStruct(meta_arena, BuddyCtx);
|
||||
ctx->meta_arena = meta_arena;
|
||||
ctx->data_arena = AcquireArena(reserve);
|
||||
/* TODO: Determine meta reserve dynamically */
|
||||
Arena *meta_arena = AcquireArena(Gibi(64));
|
||||
BuddyCtx *ctx = PushStruct(meta_arena, BuddyCtx);
|
||||
ctx->meta_arena = meta_arena;
|
||||
ctx->data_arena = AcquireArena(reserve);
|
||||
|
||||
/* TODO: Minimum block size */
|
||||
ctx->levels = PushStructs(ctx->meta_arena, BuddyLevel, 64);
|
||||
for (u64 i = 0; i < 64; ++i)
|
||||
{
|
||||
BuddyLevel *level = &ctx->levels[i];
|
||||
level->ctx = ctx;
|
||||
level->tier = i;
|
||||
level->size = (u64)1 << i;
|
||||
}
|
||||
/* TODO: Minimum block size */
|
||||
ctx->levels = PushStructs(ctx->meta_arena, BuddyLevel, 64);
|
||||
for (u64 i = 0; i < 64; ++i)
|
||||
{
|
||||
BuddyLevel *level = &ctx->levels[i];
|
||||
level->ctx = ctx;
|
||||
level->tier = i;
|
||||
level->size = (u64)1 << i;
|
||||
}
|
||||
|
||||
return ctx;
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void ReleaseBuddyCtx(BuddyCtx *ctx)
|
||||
{
|
||||
ReleaseArena(ctx->data_arena);
|
||||
ReleaseArena(ctx->meta_arena);
|
||||
ReleaseArena(ctx->data_arena);
|
||||
ReleaseArena(ctx->meta_arena);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -35,172 +35,172 @@ void ReleaseBuddyCtx(BuddyCtx *ctx)
|
||||
|
||||
BuddyBlock *GetUnusedBuddyBlock(BuddyCtx *ctx, BuddyLevel *level)
|
||||
{
|
||||
BuddyBlock *block = 0;
|
||||
BuddyBlock *block = 0;
|
||||
|
||||
/* TODO: Tier oob check */
|
||||
/* TODO: Tier oob check */
|
||||
if (level->first_unused_block)
|
||||
{
|
||||
block = level->first_unused_block;
|
||||
level->first_unused_block = block->next;
|
||||
if (level->first_unused_block)
|
||||
{
|
||||
block = level->first_unused_block;
|
||||
level->first_unused_block = block->next;
|
||||
if (level->first_unused_block)
|
||||
{
|
||||
level->first_unused_block->prev = 0;
|
||||
}
|
||||
block->is_used = 1;
|
||||
block->next = 0;
|
||||
level->first_unused_block->prev = 0;
|
||||
}
|
||||
block->is_used = 1;
|
||||
block->next = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (level->backed)
|
||||
{
|
||||
BuddyLevel *parent_level = &ctx->levels[level->tier + 1];
|
||||
BuddyBlock *parent_block = GetUnusedBuddyBlock(ctx, parent_level);
|
||||
|
||||
/* Create left (used) block from parent block */
|
||||
BuddyBlock *left = PushBuddyBlock(ctx);
|
||||
left->is_used = 1;
|
||||
left->level = level;
|
||||
left->parent = parent_block;
|
||||
left->memory = parent_block->memory;
|
||||
|
||||
/* Create right LAX block from parent block */
|
||||
BuddyBlock *right = PushBuddyBlock(ctx);
|
||||
right->is_used = 0;
|
||||
right->level = level;
|
||||
right->parent = parent_block;
|
||||
right->memory = left->memory + level->size;
|
||||
if (level->first_unused_block)
|
||||
{
|
||||
right->next = level->first_unused_block;
|
||||
level->first_unused_block->prev = right;
|
||||
}
|
||||
level->first_unused_block = right;
|
||||
|
||||
left->sibling = right;
|
||||
right->sibling = left;
|
||||
block = left;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (level->backed)
|
||||
{
|
||||
BuddyLevel *parent_level = &ctx->levels[level->tier + 1];
|
||||
BuddyBlock *parent_block = GetUnusedBuddyBlock(ctx, parent_level);
|
||||
Arena *arena = ctx->data_arena;
|
||||
|
||||
/* Create left (used) block from parent block */
|
||||
BuddyBlock *left = PushBuddyBlock(ctx);
|
||||
left->is_used = 1;
|
||||
left->level = level;
|
||||
left->parent = parent_block;
|
||||
left->memory = parent_block->memory;
|
||||
/* Grow arena */
|
||||
i64 level_commit_diff = (level->size * 2) - arena->pos;
|
||||
if (level_commit_diff > 0)
|
||||
{
|
||||
PushStructsNoZero(arena, u8, level_commit_diff);
|
||||
Assert(arena->pos == (level->size * 2));
|
||||
}
|
||||
|
||||
/* Create right LAX block from parent block */
|
||||
BuddyBlock *right = PushBuddyBlock(ctx);
|
||||
right->is_used = 0;
|
||||
right->level = level;
|
||||
right->parent = parent_block;
|
||||
right->memory = left->memory + level->size;
|
||||
if (level->first_unused_block)
|
||||
{
|
||||
right->next = level->first_unused_block;
|
||||
level->first_unused_block->prev = right;
|
||||
}
|
||||
level->first_unused_block = right;
|
||||
/* Create left (used) block from existing child block memory */
|
||||
BuddyBlock *left = PushBuddyBlock(ctx);
|
||||
left->is_used = 1;
|
||||
left->level = level;
|
||||
left->memory = ArenaFirst(arena, u8);
|
||||
|
||||
left->sibling = right;
|
||||
right->sibling = left;
|
||||
block = left;
|
||||
}
|
||||
else
|
||||
{
|
||||
Arena *arena = ctx->data_arena;
|
||||
/* Create right LAX block from new arena memory */
|
||||
BuddyBlock *right = PushBuddyBlock(ctx);
|
||||
right->is_used = 0;
|
||||
right->level = level;
|
||||
right->memory = left->memory + level->size;
|
||||
|
||||
/* Grow arena */
|
||||
i64 level_commit_diff = (level->size * 2) - arena->pos;
|
||||
if (level_commit_diff > 0)
|
||||
{
|
||||
PushStructsNoZero(arena, u8, level_commit_diff);
|
||||
Assert(arena->pos == (level->size * 2));
|
||||
}
|
||||
left->sibling = right;
|
||||
right->sibling = left;
|
||||
block = left;
|
||||
|
||||
/* Create left (used) block from existing child block memory */
|
||||
BuddyBlock *left = PushBuddyBlock(ctx);
|
||||
left->is_used = 1;
|
||||
left->level = level;
|
||||
left->memory = ArenaFirst(arena, u8);
|
||||
|
||||
/* Create right LAX block from new arena memory */
|
||||
BuddyBlock *right = PushBuddyBlock(ctx);
|
||||
right->is_used = 0;
|
||||
right->level = level;
|
||||
right->memory = left->memory + level->size;
|
||||
|
||||
left->sibling = right;
|
||||
right->sibling = left;
|
||||
block = left;
|
||||
|
||||
level->backed = 1;
|
||||
}
|
||||
level->backed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return block;
|
||||
return block;
|
||||
}
|
||||
|
||||
BuddyBlock *PushBuddyBlock(BuddyCtx *ctx)
|
||||
{
|
||||
BuddyBlock *block;
|
||||
if (ctx->first_free_block)
|
||||
{
|
||||
block = ctx->first_free_block;
|
||||
ctx->first_free_block = block->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
block = PushStructNoZero(ctx->meta_arena, BuddyBlock);
|
||||
}
|
||||
ZeroStruct(block);
|
||||
return block;
|
||||
BuddyBlock *block;
|
||||
if (ctx->first_free_block)
|
||||
{
|
||||
block = ctx->first_free_block;
|
||||
ctx->first_free_block = block->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
block = PushStructNoZero(ctx->meta_arena, BuddyBlock);
|
||||
}
|
||||
ZeroStruct(block);
|
||||
return block;
|
||||
}
|
||||
|
||||
void PopBuddyBlock(BuddyCtx *ctx, BuddyLevel *level, BuddyBlock *block)
|
||||
{
|
||||
/* Remove from unused list */
|
||||
/* Remove from unused list */
|
||||
{
|
||||
BuddyBlock *prev = block->prev;
|
||||
BuddyBlock *next = block->next;
|
||||
if (prev)
|
||||
{
|
||||
BuddyBlock *prev = block->prev;
|
||||
BuddyBlock *next = block->next;
|
||||
if (prev)
|
||||
{
|
||||
prev->next = next;
|
||||
}
|
||||
else
|
||||
{
|
||||
level->first_unused_block = next;
|
||||
}
|
||||
if (next)
|
||||
{
|
||||
next->prev = prev;
|
||||
}
|
||||
prev->next = next;
|
||||
}
|
||||
block->next = ctx->first_free_block;
|
||||
ctx->first_free_block = block;
|
||||
else
|
||||
{
|
||||
level->first_unused_block = next;
|
||||
}
|
||||
if (next)
|
||||
{
|
||||
next->prev = prev;
|
||||
}
|
||||
}
|
||||
block->next = ctx->first_free_block;
|
||||
ctx->first_free_block = block;
|
||||
}
|
||||
|
||||
BuddyBlock *AcquireBuddyBlock(BuddyCtx *ctx, u64 size)
|
||||
{
|
||||
if (size > 0x00FFFFFFFFFFFFFFULL)
|
||||
{
|
||||
/* TODO: Error */
|
||||
Assert(0);
|
||||
}
|
||||
if (size > 0x00FFFFFFFFFFFFFFULL)
|
||||
{
|
||||
/* TODO: Error */
|
||||
Assert(0);
|
||||
}
|
||||
|
||||
/* TODO: Minimum block size */
|
||||
/* TODO: Minimum block size */
|
||||
|
||||
/* TODO: Faster MSB calculation */
|
||||
/* TODO: Faster MSB calculation */
|
||||
|
||||
u64 desired_block_size = 1;
|
||||
u64 desired_level_tier = 0;
|
||||
while (desired_block_size < size && desired_level_tier < 64)
|
||||
{
|
||||
desired_block_size <<= 1;
|
||||
++desired_level_tier;
|
||||
}
|
||||
u64 desired_block_size = 1;
|
||||
u64 desired_level_tier = 0;
|
||||
while (desired_block_size < size && desired_level_tier < 64)
|
||||
{
|
||||
desired_block_size <<= 1;
|
||||
++desired_level_tier;
|
||||
}
|
||||
|
||||
BuddyBlock *block = GetUnusedBuddyBlock(ctx, &ctx->levels[desired_level_tier]);
|
||||
BuddyBlock *block = GetUnusedBuddyBlock(ctx, &ctx->levels[desired_level_tier]);
|
||||
|
||||
return block;
|
||||
return block;
|
||||
}
|
||||
|
||||
void ReleaseBuddyBlock(BuddyBlock *block)
|
||||
{
|
||||
block->is_used = 0;
|
||||
BuddyLevel *level = block->level;
|
||||
BuddyBlock *parent = block->parent;
|
||||
BuddyBlock *sibling = block->sibling;
|
||||
if (!sibling->is_used && parent != 0)
|
||||
block->is_used = 0;
|
||||
BuddyLevel *level = block->level;
|
||||
BuddyBlock *parent = block->parent;
|
||||
BuddyBlock *sibling = block->sibling;
|
||||
if (!sibling->is_used && parent != 0)
|
||||
{
|
||||
/* Merge siblings */
|
||||
BuddyCtx *ctx = level->ctx;
|
||||
PopBuddyBlock(ctx, level, block);
|
||||
PopBuddyBlock(ctx, level, sibling);
|
||||
/* Release parent */
|
||||
ReleaseBuddyBlock(parent);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (level->first_unused_block)
|
||||
{
|
||||
/* Merge siblings */
|
||||
BuddyCtx *ctx = level->ctx;
|
||||
PopBuddyBlock(ctx, level, block);
|
||||
PopBuddyBlock(ctx, level, sibling);
|
||||
/* Release parent */
|
||||
ReleaseBuddyBlock(parent);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (level->first_unused_block)
|
||||
{
|
||||
block->next = level->first_unused_block;
|
||||
level->first_unused_block->prev = block;
|
||||
}
|
||||
level->first_unused_block = block;
|
||||
block->next = level->first_unused_block;
|
||||
level->first_unused_block->prev = block;
|
||||
}
|
||||
level->first_unused_block = block;
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,35 +4,35 @@
|
||||
//- Block
|
||||
Struct(BuddyBlock)
|
||||
{
|
||||
b32 is_used;
|
||||
struct BuddyLevel *level;
|
||||
BuddyBlock *parent;
|
||||
BuddyBlock *sibling;
|
||||
b32 is_used;
|
||||
struct BuddyLevel *level;
|
||||
BuddyBlock *parent;
|
||||
BuddyBlock *sibling;
|
||||
|
||||
/* Links to block in level's unused list or in ctx's free list */
|
||||
BuddyBlock *prev;
|
||||
BuddyBlock *next;
|
||||
/* Links to block in level's unused list or in ctx's free list */
|
||||
BuddyBlock *prev;
|
||||
BuddyBlock *next;
|
||||
|
||||
u8 *memory;
|
||||
u8 *memory;
|
||||
};
|
||||
|
||||
//- Level
|
||||
Struct(BuddyLevel)
|
||||
{
|
||||
struct BuddyCtx *ctx;
|
||||
b32 backed; /* Signals whether this level is backed by memory in the ctx arena */
|
||||
u32 tier;
|
||||
u64 size;
|
||||
BuddyBlock *first_unused_block;
|
||||
struct BuddyCtx *ctx;
|
||||
b32 backed; /* Signals whether this level is backed by memory in the ctx arena */
|
||||
u32 tier;
|
||||
u64 size;
|
||||
BuddyBlock *first_unused_block;
|
||||
};
|
||||
|
||||
//- Ctx
|
||||
Struct(BuddyCtx)
|
||||
{
|
||||
Arena *meta_arena;
|
||||
Arena *data_arena;
|
||||
BuddyLevel *levels;
|
||||
BuddyBlock *first_free_block;
|
||||
Arena *meta_arena;
|
||||
Arena *data_arena;
|
||||
BuddyLevel *levels;
|
||||
BuddyBlock *first_free_block;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
@ -3,70 +3,70 @@
|
||||
|
||||
void BootstrapCmdline(void)
|
||||
{
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
{
|
||||
StringList raw = GetRawCommandline();
|
||||
|
||||
u64 tmp_args_count = 0;
|
||||
u64 tmp_positionals_count = 0;
|
||||
CommandlineArg *tmp_args = PushStructs(scratch.arena, CommandlineArg, raw.count);
|
||||
String *tmp_positionals = PushStructs(scratch.arena, String, raw.count);
|
||||
{
|
||||
StringList raw = GetRawCommandline();
|
||||
|
||||
u64 tmp_args_count = 0;
|
||||
u64 tmp_positionals_count = 0;
|
||||
CommandlineArg *tmp_args = PushStructs(scratch.arena, CommandlineArg, raw.count);
|
||||
String *tmp_positionals = PushStructs(scratch.arena, String, raw.count);
|
||||
String name = Zi;
|
||||
for (StringListNode *n = raw.first; n; n = n->next)
|
||||
{
|
||||
String s = n->s;
|
||||
if (StringBeginsWith(s, Lit("--")))
|
||||
{
|
||||
String name = Zi;
|
||||
for (StringListNode *n = raw.first; n; n = n->next)
|
||||
{
|
||||
String s = n->s;
|
||||
if (StringBeginsWith(s, Lit("--")))
|
||||
{
|
||||
if (name.len > 0)
|
||||
{
|
||||
CommandlineArg *arg = &tmp_args[tmp_args_count++];
|
||||
arg->name = name;
|
||||
arg->exists = 1;
|
||||
}
|
||||
name = TrimLeft(s, Lit("--"));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (name.len > 0)
|
||||
{
|
||||
CommandlineArg *arg = &tmp_args[tmp_args_count++];
|
||||
arg->name = name;
|
||||
arg->value = s;
|
||||
arg->exists = 1;
|
||||
name = Zstr;
|
||||
}
|
||||
else
|
||||
{
|
||||
tmp_positionals[tmp_positionals_count++] = s;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (name.len > 0)
|
||||
{
|
||||
CommandlineArg *arg = &tmp_args[tmp_args_count++];
|
||||
arg->name = name;
|
||||
arg->exists = 1;
|
||||
}
|
||||
if (name.len > 0)
|
||||
{
|
||||
CommandlineArg *arg = &tmp_args[tmp_args_count++];
|
||||
arg->name = name;
|
||||
arg->exists = 1;
|
||||
}
|
||||
name = TrimLeft(s, Lit("--"));
|
||||
}
|
||||
|
||||
Arena *perm = PermArena();
|
||||
Base.cmdline.positional_args_count = tmp_positionals_count;
|
||||
Base.cmdline.positional_args = PushStructsNoZero(perm, String, tmp_positionals_count);
|
||||
CopyStructs(Base.cmdline.positional_args, tmp_positionals, tmp_positionals_count);
|
||||
for (u64 i = 0; i < tmp_args_count; ++i)
|
||||
else
|
||||
{
|
||||
CommandlineArg arg = tmp_args[i];
|
||||
CommandlineArgNode *n = PushStruct(perm, CommandlineArgNode);
|
||||
u64 hash = HashFnv64(Fnv64Basis, arg.name);
|
||||
u64 bin_idx = hash % countof(Base.cmdline.arg_bins);
|
||||
n->arg = arg;
|
||||
n->hash = hash;
|
||||
n->next = Base.cmdline.arg_bins[bin_idx];
|
||||
Base.cmdline.arg_bins[bin_idx] = n;
|
||||
if (name.len > 0)
|
||||
{
|
||||
CommandlineArg *arg = &tmp_args[tmp_args_count++];
|
||||
arg->name = name;
|
||||
arg->value = s;
|
||||
arg->exists = 1;
|
||||
name = Zstr;
|
||||
}
|
||||
else
|
||||
{
|
||||
tmp_positionals[tmp_positionals_count++] = s;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (name.len > 0)
|
||||
{
|
||||
CommandlineArg *arg = &tmp_args[tmp_args_count++];
|
||||
arg->name = name;
|
||||
arg->exists = 1;
|
||||
}
|
||||
}
|
||||
EndScratch(scratch);
|
||||
|
||||
Arena *perm = PermArena();
|
||||
Base.cmdline.positional_args_count = tmp_positionals_count;
|
||||
Base.cmdline.positional_args = PushStructsNoZero(perm, String, tmp_positionals_count);
|
||||
CopyStructs(Base.cmdline.positional_args, tmp_positionals, tmp_positionals_count);
|
||||
for (u64 i = 0; i < tmp_args_count; ++i)
|
||||
{
|
||||
CommandlineArg arg = tmp_args[i];
|
||||
CommandlineArgNode *n = PushStruct(perm, CommandlineArgNode);
|
||||
u64 hash = HashFnv64(Fnv64Basis, arg.name);
|
||||
u64 bin_idx = hash % countof(Base.cmdline.arg_bins);
|
||||
n->arg = arg;
|
||||
n->hash = hash;
|
||||
n->next = Base.cmdline.arg_bins[bin_idx];
|
||||
Base.cmdline.arg_bins[bin_idx] = n;
|
||||
}
|
||||
}
|
||||
EndScratch(scratch);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -74,25 +74,25 @@ void BootstrapCmdline(void)
|
||||
|
||||
String StringFromCommandlineIdx(i32 idx)
|
||||
{
|
||||
String result = Zi;
|
||||
if (idx < Base.cmdline.positional_args_count)
|
||||
{
|
||||
result = Base.cmdline.positional_args[idx];
|
||||
}
|
||||
return result;
|
||||
String result = Zi;
|
||||
if (idx < Base.cmdline.positional_args_count)
|
||||
{
|
||||
result = Base.cmdline.positional_args[idx];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
CommandlineArg CommandlineArgFromName(String name)
|
||||
{
|
||||
CommandlineArg result = Zi;
|
||||
u64 hash = HashFnv64(Fnv64Basis, name);
|
||||
for (CommandlineArgNode *n = Base.cmdline.arg_bins[hash % countof(Base.cmdline.arg_bins)]; n; n = n->next)
|
||||
CommandlineArg result = Zi;
|
||||
u64 hash = HashFnv64(Fnv64Basis, name);
|
||||
for (CommandlineArgNode *n = Base.cmdline.arg_bins[hash % countof(Base.cmdline.arg_bins)]; n; n = n->next)
|
||||
{
|
||||
if (n->hash == hash && MatchString(n->arg.name, name))
|
||||
{
|
||||
if (n->hash == hash && MatchString(n->arg.name, name))
|
||||
{
|
||||
result = n->arg;
|
||||
break;
|
||||
}
|
||||
result = n->arg;
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -3,23 +3,23 @@
|
||||
|
||||
Struct(CommandlineArg)
|
||||
{
|
||||
b32 exists;
|
||||
String name;
|
||||
String value;
|
||||
b32 exists;
|
||||
String name;
|
||||
String value;
|
||||
};
|
||||
|
||||
Struct(CommandlineArgNode)
|
||||
{
|
||||
CommandlineArgNode *next;
|
||||
u64 hash;
|
||||
CommandlineArg arg;
|
||||
CommandlineArgNode *next;
|
||||
u64 hash;
|
||||
CommandlineArg arg;
|
||||
};
|
||||
|
||||
Struct(CmdLineCtx)
|
||||
{
|
||||
String *positional_args;
|
||||
u64 positional_args_count;
|
||||
CommandlineArgNode *arg_bins[1024];
|
||||
String *positional_args;
|
||||
u64 positional_args_count;
|
||||
CommandlineArgNode *arg_bins[1024];
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
@ -3,107 +3,107 @@
|
||||
|
||||
String StringFromButton(Button button)
|
||||
{
|
||||
PERSIST Readonly String names[Button_Count] = {
|
||||
[Button_M1] = CompLit("Mouse 1"),
|
||||
[Button_M2] = CompLit("Mouse 2"),
|
||||
[Button_M3] = CompLit("Mouse 3"),
|
||||
[Button_M4] = CompLit("Mouse 4"),
|
||||
[Button_M5] = CompLit("Mouse 5"),
|
||||
[Button_MWheelUp] = CompLit("Wheel Up"),
|
||||
[Button_MWheelDown] = CompLit("Wheel Down"),
|
||||
[Button_Escape] = CompLit("Escape"),
|
||||
[Button_F1] = CompLit("F1"),
|
||||
[Button_F2] = CompLit("F2"),
|
||||
[Button_F3] = CompLit("F3"),
|
||||
[Button_F4] = CompLit("F4"),
|
||||
[Button_F5] = CompLit("F5"),
|
||||
[Button_F6] = CompLit("F6"),
|
||||
[Button_F7] = CompLit("F7"),
|
||||
[Button_F8] = CompLit("F8"),
|
||||
[Button_F9] = CompLit("F9"),
|
||||
[Button_F10] = CompLit("F10"),
|
||||
[Button_F11] = CompLit("F11"),
|
||||
[Button_F12] = CompLit("F12"),
|
||||
[Button_F13] = CompLit("F13"),
|
||||
[Button_F14] = CompLit("F14"),
|
||||
[Button_F15] = CompLit("F15"),
|
||||
[Button_F16] = CompLit("F16"),
|
||||
[Button_F17] = CompLit("F17"),
|
||||
[Button_F18] = CompLit("F18"),
|
||||
[Button_F19] = CompLit("F19"),
|
||||
[Button_F20] = CompLit("F20"),
|
||||
[Button_F21] = CompLit("F21"),
|
||||
[Button_F22] = CompLit("F22"),
|
||||
[Button_F23] = CompLit("F23"),
|
||||
[Button_F24] = CompLit("F24"),
|
||||
[Button_GraveAccent] = CompLit("~"),
|
||||
[Button_0] = CompLit("0"),
|
||||
[Button_1] = CompLit("1"),
|
||||
[Button_2] = CompLit("2"),
|
||||
[Button_3] = CompLit("3"),
|
||||
[Button_4] = CompLit("4"),
|
||||
[Button_5] = CompLit("5"),
|
||||
[Button_6] = CompLit("6"),
|
||||
[Button_7] = CompLit("7"),
|
||||
[Button_8] = CompLit("8"),
|
||||
[Button_9] = CompLit("9"),
|
||||
[Button_Minus] = CompLit("Minus"),
|
||||
[Button_Equal] = CompLit("Equal"),
|
||||
[Button_Backspace] = CompLit("Backspace"),
|
||||
[Button_Delete] = CompLit("Delete"),
|
||||
[Button_Tab] = CompLit("Tab"),
|
||||
[Button_A] = CompLit("A"),
|
||||
[Button_B] = CompLit("B"),
|
||||
[Button_C] = CompLit("C"),
|
||||
[Button_D] = CompLit("D"),
|
||||
[Button_E] = CompLit("E"),
|
||||
[Button_F] = CompLit("F"),
|
||||
[Button_G] = CompLit("G"),
|
||||
[Button_H] = CompLit("H"),
|
||||
[Button_I] = CompLit("I"),
|
||||
[Button_J] = CompLit("J"),
|
||||
[Button_K] = CompLit("K"),
|
||||
[Button_L] = CompLit("L"),
|
||||
[Button_M] = CompLit("M"),
|
||||
[Button_N] = CompLit("N"),
|
||||
[Button_O] = CompLit("O"),
|
||||
[Button_P] = CompLit("P"),
|
||||
[Button_Q] = CompLit("Q"),
|
||||
[Button_R] = CompLit("R"),
|
||||
[Button_S] = CompLit("S"),
|
||||
[Button_T] = CompLit("T"),
|
||||
[Button_U] = CompLit("U"),
|
||||
[Button_V] = CompLit("V"),
|
||||
[Button_W] = CompLit("W"),
|
||||
[Button_X] = CompLit("X"),
|
||||
[Button_Y] = CompLit("Y"),
|
||||
[Button_Z] = CompLit("Z"),
|
||||
[Button_Space] = CompLit("Space"),
|
||||
[Button_Enter] = CompLit("Enter"),
|
||||
[Button_Ctrl] = CompLit("Ctrl"),
|
||||
[Button_Shift] = CompLit("Shift"),
|
||||
[Button_Alt] = CompLit("Alt"),
|
||||
[Button_Up] = CompLit("Up"),
|
||||
[Button_Left] = CompLit("Left"),
|
||||
[Button_Down] = CompLit("Down"),
|
||||
[Button_Right] = CompLit("Right"),
|
||||
[Button_PageUp] = CompLit("PageUp"),
|
||||
[Button_PageDown] = CompLit("PageDown"),
|
||||
[Button_Home] = CompLit("Home"),
|
||||
[Button_End] = CompLit("End"),
|
||||
[Button_ForwardSlash] = CompLit("Slash"),
|
||||
[Button_Period] = CompLit("Period"),
|
||||
[Button_Comma] = CompLit("Comma"),
|
||||
[Button_Quote] = CompLit("Quote"),
|
||||
[Button_LeftBracket] = CompLit("Left Bracket"),
|
||||
[Button_RightBracket] = CompLit("Right Bracket"),
|
||||
[Button_Insert] = CompLit("Insert"),
|
||||
[Button_Semicolon] = CompLit("Semicolon"),
|
||||
};
|
||||
String name = Lit("None");
|
||||
if (button > 0 && button < countof(names))
|
||||
{
|
||||
name = names[button];
|
||||
}
|
||||
return name;
|
||||
PERSIST Readonly String names[Button_Count] = {
|
||||
[Button_M1] = CompLit("Mouse 1"),
|
||||
[Button_M2] = CompLit("Mouse 2"),
|
||||
[Button_M3] = CompLit("Mouse 3"),
|
||||
[Button_M4] = CompLit("Mouse 4"),
|
||||
[Button_M5] = CompLit("Mouse 5"),
|
||||
[Button_MWheelUp] = CompLit("Wheel Up"),
|
||||
[Button_MWheelDown] = CompLit("Wheel Down"),
|
||||
[Button_Escape] = CompLit("Escape"),
|
||||
[Button_F1] = CompLit("F1"),
|
||||
[Button_F2] = CompLit("F2"),
|
||||
[Button_F3] = CompLit("F3"),
|
||||
[Button_F4] = CompLit("F4"),
|
||||
[Button_F5] = CompLit("F5"),
|
||||
[Button_F6] = CompLit("F6"),
|
||||
[Button_F7] = CompLit("F7"),
|
||||
[Button_F8] = CompLit("F8"),
|
||||
[Button_F9] = CompLit("F9"),
|
||||
[Button_F10] = CompLit("F10"),
|
||||
[Button_F11] = CompLit("F11"),
|
||||
[Button_F12] = CompLit("F12"),
|
||||
[Button_F13] = CompLit("F13"),
|
||||
[Button_F14] = CompLit("F14"),
|
||||
[Button_F15] = CompLit("F15"),
|
||||
[Button_F16] = CompLit("F16"),
|
||||
[Button_F17] = CompLit("F17"),
|
||||
[Button_F18] = CompLit("F18"),
|
||||
[Button_F19] = CompLit("F19"),
|
||||
[Button_F20] = CompLit("F20"),
|
||||
[Button_F21] = CompLit("F21"),
|
||||
[Button_F22] = CompLit("F22"),
|
||||
[Button_F23] = CompLit("F23"),
|
||||
[Button_F24] = CompLit("F24"),
|
||||
[Button_GraveAccent] = CompLit("~"),
|
||||
[Button_0] = CompLit("0"),
|
||||
[Button_1] = CompLit("1"),
|
||||
[Button_2] = CompLit("2"),
|
||||
[Button_3] = CompLit("3"),
|
||||
[Button_4] = CompLit("4"),
|
||||
[Button_5] = CompLit("5"),
|
||||
[Button_6] = CompLit("6"),
|
||||
[Button_7] = CompLit("7"),
|
||||
[Button_8] = CompLit("8"),
|
||||
[Button_9] = CompLit("9"),
|
||||
[Button_Minus] = CompLit("Minus"),
|
||||
[Button_Equal] = CompLit("Equal"),
|
||||
[Button_Backspace] = CompLit("Backspace"),
|
||||
[Button_Delete] = CompLit("Delete"),
|
||||
[Button_Tab] = CompLit("Tab"),
|
||||
[Button_A] = CompLit("A"),
|
||||
[Button_B] = CompLit("B"),
|
||||
[Button_C] = CompLit("C"),
|
||||
[Button_D] = CompLit("D"),
|
||||
[Button_E] = CompLit("E"),
|
||||
[Button_F] = CompLit("F"),
|
||||
[Button_G] = CompLit("G"),
|
||||
[Button_H] = CompLit("H"),
|
||||
[Button_I] = CompLit("I"),
|
||||
[Button_J] = CompLit("J"),
|
||||
[Button_K] = CompLit("K"),
|
||||
[Button_L] = CompLit("L"),
|
||||
[Button_M] = CompLit("M"),
|
||||
[Button_N] = CompLit("N"),
|
||||
[Button_O] = CompLit("O"),
|
||||
[Button_P] = CompLit("P"),
|
||||
[Button_Q] = CompLit("Q"),
|
||||
[Button_R] = CompLit("R"),
|
||||
[Button_S] = CompLit("S"),
|
||||
[Button_T] = CompLit("T"),
|
||||
[Button_U] = CompLit("U"),
|
||||
[Button_V] = CompLit("V"),
|
||||
[Button_W] = CompLit("W"),
|
||||
[Button_X] = CompLit("X"),
|
||||
[Button_Y] = CompLit("Y"),
|
||||
[Button_Z] = CompLit("Z"),
|
||||
[Button_Space] = CompLit("Space"),
|
||||
[Button_Enter] = CompLit("Enter"),
|
||||
[Button_Ctrl] = CompLit("Ctrl"),
|
||||
[Button_Shift] = CompLit("Shift"),
|
||||
[Button_Alt] = CompLit("Alt"),
|
||||
[Button_Up] = CompLit("Up"),
|
||||
[Button_Left] = CompLit("Left"),
|
||||
[Button_Down] = CompLit("Down"),
|
||||
[Button_Right] = CompLit("Right"),
|
||||
[Button_PageUp] = CompLit("PageUp"),
|
||||
[Button_PageDown] = CompLit("PageDown"),
|
||||
[Button_Home] = CompLit("Home"),
|
||||
[Button_End] = CompLit("End"),
|
||||
[Button_ForwardSlash] = CompLit("Slash"),
|
||||
[Button_Period] = CompLit("Period"),
|
||||
[Button_Comma] = CompLit("Comma"),
|
||||
[Button_Quote] = CompLit("Quote"),
|
||||
[Button_LeftBracket] = CompLit("Left Bracket"),
|
||||
[Button_RightBracket] = CompLit("Right Bracket"),
|
||||
[Button_Insert] = CompLit("Insert"),
|
||||
[Button_Semicolon] = CompLit("Semicolon"),
|
||||
};
|
||||
String name = Lit("None");
|
||||
if (button > 0 && button < countof(names))
|
||||
{
|
||||
name = names[button];
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
@ -3,110 +3,110 @@
|
||||
|
||||
Enum(Button)
|
||||
{
|
||||
Button_None,
|
||||
Button_None,
|
||||
|
||||
//- Mouse buttons
|
||||
Button_M1,
|
||||
Button_M2,
|
||||
Button_M3,
|
||||
Button_M4,
|
||||
Button_M5,
|
||||
//- Mouse buttons
|
||||
Button_M1,
|
||||
Button_M2,
|
||||
Button_M3,
|
||||
Button_M4,
|
||||
Button_M5,
|
||||
|
||||
//- Mouse wheel
|
||||
Button_MWheelUp,
|
||||
Button_MWheelDown,
|
||||
//- Mouse wheel
|
||||
Button_MWheelUp,
|
||||
Button_MWheelDown,
|
||||
|
||||
//- Keyboard buttons
|
||||
Button_Escape,
|
||||
Button_F1,
|
||||
Button_F2,
|
||||
Button_F3,
|
||||
Button_F4,
|
||||
Button_F5,
|
||||
Button_F6,
|
||||
Button_F7,
|
||||
Button_F8,
|
||||
Button_F9,
|
||||
Button_F10,
|
||||
Button_F11,
|
||||
Button_F12,
|
||||
Button_F13,
|
||||
Button_F14,
|
||||
Button_F15,
|
||||
Button_F16,
|
||||
Button_F17,
|
||||
Button_F18,
|
||||
Button_F19,
|
||||
Button_F20,
|
||||
Button_F21,
|
||||
Button_F22,
|
||||
Button_F23,
|
||||
Button_F24,
|
||||
Button_GraveAccent,
|
||||
Button_0,
|
||||
Button_1,
|
||||
Button_2,
|
||||
Button_3,
|
||||
Button_4,
|
||||
Button_5,
|
||||
Button_6,
|
||||
Button_7,
|
||||
Button_8,
|
||||
Button_9,
|
||||
Button_Minus,
|
||||
Button_Equal,
|
||||
Button_Backspace,
|
||||
Button_Delete,
|
||||
Button_Tab,
|
||||
Button_A,
|
||||
Button_B,
|
||||
Button_C,
|
||||
Button_D,
|
||||
Button_E,
|
||||
Button_F,
|
||||
Button_G,
|
||||
Button_H,
|
||||
Button_I,
|
||||
Button_J,
|
||||
Button_K,
|
||||
Button_L,
|
||||
Button_M,
|
||||
Button_N,
|
||||
Button_O,
|
||||
Button_P,
|
||||
Button_Q,
|
||||
Button_R,
|
||||
Button_S,
|
||||
Button_T,
|
||||
Button_U,
|
||||
Button_V,
|
||||
Button_W,
|
||||
Button_X,
|
||||
Button_Y,
|
||||
Button_Z,
|
||||
Button_Space,
|
||||
Button_Enter,
|
||||
Button_Ctrl,
|
||||
Button_Shift,
|
||||
Button_Alt,
|
||||
Button_Up,
|
||||
Button_Left,
|
||||
Button_Down,
|
||||
Button_Right,
|
||||
Button_PageUp,
|
||||
Button_PageDown,
|
||||
Button_Home,
|
||||
Button_End,
|
||||
Button_ForwardSlash,
|
||||
Button_Period,
|
||||
Button_Comma,
|
||||
Button_Quote,
|
||||
Button_LeftBracket,
|
||||
Button_RightBracket,
|
||||
Button_Insert,
|
||||
Button_Semicolon,
|
||||
//- Keyboard buttons
|
||||
Button_Escape,
|
||||
Button_F1,
|
||||
Button_F2,
|
||||
Button_F3,
|
||||
Button_F4,
|
||||
Button_F5,
|
||||
Button_F6,
|
||||
Button_F7,
|
||||
Button_F8,
|
||||
Button_F9,
|
||||
Button_F10,
|
||||
Button_F11,
|
||||
Button_F12,
|
||||
Button_F13,
|
||||
Button_F14,
|
||||
Button_F15,
|
||||
Button_F16,
|
||||
Button_F17,
|
||||
Button_F18,
|
||||
Button_F19,
|
||||
Button_F20,
|
||||
Button_F21,
|
||||
Button_F22,
|
||||
Button_F23,
|
||||
Button_F24,
|
||||
Button_GraveAccent,
|
||||
Button_0,
|
||||
Button_1,
|
||||
Button_2,
|
||||
Button_3,
|
||||
Button_4,
|
||||
Button_5,
|
||||
Button_6,
|
||||
Button_7,
|
||||
Button_8,
|
||||
Button_9,
|
||||
Button_Minus,
|
||||
Button_Equal,
|
||||
Button_Backspace,
|
||||
Button_Delete,
|
||||
Button_Tab,
|
||||
Button_A,
|
||||
Button_B,
|
||||
Button_C,
|
||||
Button_D,
|
||||
Button_E,
|
||||
Button_F,
|
||||
Button_G,
|
||||
Button_H,
|
||||
Button_I,
|
||||
Button_J,
|
||||
Button_K,
|
||||
Button_L,
|
||||
Button_M,
|
||||
Button_N,
|
||||
Button_O,
|
||||
Button_P,
|
||||
Button_Q,
|
||||
Button_R,
|
||||
Button_S,
|
||||
Button_T,
|
||||
Button_U,
|
||||
Button_V,
|
||||
Button_W,
|
||||
Button_X,
|
||||
Button_Y,
|
||||
Button_Z,
|
||||
Button_Space,
|
||||
Button_Enter,
|
||||
Button_Ctrl,
|
||||
Button_Shift,
|
||||
Button_Alt,
|
||||
Button_Up,
|
||||
Button_Left,
|
||||
Button_Down,
|
||||
Button_Right,
|
||||
Button_PageUp,
|
||||
Button_PageDown,
|
||||
Button_Home,
|
||||
Button_End,
|
||||
Button_ForwardSlash,
|
||||
Button_Period,
|
||||
Button_Comma,
|
||||
Button_Quote,
|
||||
Button_LeftBracket,
|
||||
Button_RightBracket,
|
||||
Button_Insert,
|
||||
Button_Semicolon,
|
||||
|
||||
Button_Count
|
||||
Button_Count
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -114,44 +114,44 @@ Enum(Button)
|
||||
|
||||
Enum(ControllerEventKind)
|
||||
{
|
||||
ControllerEventKind_None,
|
||||
ControllerEventKind_None,
|
||||
|
||||
ControllerEventKind_ButtonDown,
|
||||
ControllerEventKind_ButtonUp,
|
||||
ControllerEventKind_ButtonDown,
|
||||
ControllerEventKind_ButtonUp,
|
||||
|
||||
ControllerEventKind_CursorMove,
|
||||
ControllerEventKind_MouseMove,
|
||||
ControllerEventKind_CursorMove,
|
||||
ControllerEventKind_MouseMove,
|
||||
|
||||
ControllerEventKind_Text,
|
||||
ControllerEventKind_Text,
|
||||
|
||||
ControllerEventKind_Quit,
|
||||
ControllerEventKind_Quit,
|
||||
|
||||
ControllerEventKind_Count
|
||||
ControllerEventKind_Count
|
||||
};
|
||||
|
||||
Struct(ControllerEvent)
|
||||
{
|
||||
ControllerEventKind kind;
|
||||
ControllerEventKind kind;
|
||||
|
||||
/* ControllerEventKind_ButtonDown */
|
||||
/* ControllerEventKind_ButtonUp */
|
||||
Button button;
|
||||
b32 is_repeat;
|
||||
/* ControllerEventKind_ButtonDown */
|
||||
/* ControllerEventKind_ButtonUp */
|
||||
Button button;
|
||||
b32 is_repeat;
|
||||
|
||||
/* ControllerEventKind_Text */
|
||||
u32 text_codepoint;
|
||||
/* ControllerEventKind_Text */
|
||||
u32 text_codepoint;
|
||||
|
||||
/* ControllerEventKind_CursorMove */
|
||||
Vec2I32 cursor_pos;
|
||||
/* ControllerEventKind_CursorMove */
|
||||
Vec2I32 cursor_pos;
|
||||
|
||||
/* ControllerEventKind_MouseMove */
|
||||
Vec2I32 mouse_delta;
|
||||
/* ControllerEventKind_MouseMove */
|
||||
Vec2I32 mouse_delta;
|
||||
};
|
||||
|
||||
Struct(ControllerEventsArray)
|
||||
{
|
||||
u64 count;
|
||||
ControllerEvent *events;
|
||||
u64 count;
|
||||
ControllerEvent *events;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
@ -3,15 +3,15 @@
|
||||
|
||||
Enum(OS_FileFlag)
|
||||
{
|
||||
OS_FileFlag_None = 0,
|
||||
OS_FileFlag_Read = (1 << 0),
|
||||
OS_FileFlag_Write = (1 << 1),
|
||||
OS_FileFlag_Create = (1 << 2),
|
||||
OS_FileFlag_None = 0,
|
||||
OS_FileFlag_Read = (1 << 0),
|
||||
OS_FileFlag_Write = (1 << 1),
|
||||
OS_FileFlag_Create = (1 << 2),
|
||||
};
|
||||
|
||||
Struct(OS_File)
|
||||
{
|
||||
u64 handle;
|
||||
u64 handle;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
@ -5,17 +5,17 @@
|
||||
|
||||
Struct(GstatCtx)
|
||||
{
|
||||
Atomic64Padded SockBytesSent;
|
||||
Atomic64Padded SockBytesReceived;
|
||||
Atomic64Padded DebugSteps;
|
||||
Atomic64Padded SockBytesSent;
|
||||
Atomic64Padded SockBytesReceived;
|
||||
Atomic64Padded DebugSteps;
|
||||
|
||||
Atomic64Padded NumArenas;
|
||||
Atomic64Padded ArenaMemoryCommitted;
|
||||
Atomic64Padded ArenaMemoryReserved;
|
||||
Atomic64Padded NumArenas;
|
||||
Atomic64Padded ArenaMemoryCommitted;
|
||||
Atomic64Padded ArenaMemoryReserved;
|
||||
|
||||
Atomic64Padded NumGpuArenas;
|
||||
Atomic64Padded DedicatedGpuArenaMemoryCommitted;
|
||||
Atomic64Padded SharedGpuArenaMemoryCommitted;
|
||||
Atomic64Padded NumGpuArenas;
|
||||
Atomic64Padded DedicatedGpuArenaMemoryCommitted;
|
||||
Atomic64Padded SharedGpuArenaMemoryCommitted;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@ -5,53 +5,53 @@
|
||||
//- Api
|
||||
#include "base.cgh"
|
||||
#if IsLanguageC
|
||||
# include "base_intrinsics.h"
|
||||
# include "base_memory.h"
|
||||
# include "base_arena.h"
|
||||
# include "base_futex.h"
|
||||
# include "base_sync.h"
|
||||
# include "base_time.h"
|
||||
# include "base_uid.h"
|
||||
# include "base_math.h"
|
||||
# include "base_wave.h"
|
||||
# include "base_string.h"
|
||||
# include "base_cmdline.h"
|
||||
# include "base_log.h"
|
||||
# include "base_uni.h"
|
||||
# include "base_gstat.h"
|
||||
# include "base_buddy.h"
|
||||
# include "base_rand.h"
|
||||
# include "base_util.h"
|
||||
# include "base_bitbuff.h"
|
||||
# include "base_resource.h"
|
||||
# include "base_controller.h"
|
||||
# include "base_async.h"
|
||||
# include "base_state.h"
|
||||
#include "base_intrinsics.h"
|
||||
#include "base_memory.h"
|
||||
#include "base_arena.h"
|
||||
#include "base_futex.h"
|
||||
#include "base_sync.h"
|
||||
#include "base_time.h"
|
||||
#include "base_uid.h"
|
||||
#include "base_math.h"
|
||||
#include "base_wave.h"
|
||||
#include "base_string.h"
|
||||
#include "base_cmdline.h"
|
||||
#include "base_log.h"
|
||||
#include "base_uni.h"
|
||||
#include "base_gstat.h"
|
||||
#include "base_buddy.h"
|
||||
#include "base_rand.h"
|
||||
#include "base_util.h"
|
||||
#include "base_bitbuff.h"
|
||||
#include "base_resource.h"
|
||||
#include "base_controller.h"
|
||||
#include "base_async.h"
|
||||
#include "base_state.h"
|
||||
#elif IsLanguageG
|
||||
# include "base_shader.gh"
|
||||
#include "base_shader.gh"
|
||||
#endif
|
||||
|
||||
//- Impl
|
||||
#if IsLanguageC
|
||||
# include "base_memory.c"
|
||||
# include "base_arena.c"
|
||||
# include "base_sync.c"
|
||||
# include "base_uid.c"
|
||||
# include "base_string.c"
|
||||
# include "base_cmdline.c"
|
||||
# include "base_uni.c"
|
||||
# include "base_buddy.c"
|
||||
# include "base_math.c"
|
||||
# include "base_wave.c"
|
||||
# include "base_rand.c"
|
||||
# include "base_bitbuff.c"
|
||||
# include "base_resource.c"
|
||||
# include "base_controller.c"
|
||||
# include "base_async.c"
|
||||
# include "base_state.c"
|
||||
#include "base_memory.c"
|
||||
#include "base_arena.c"
|
||||
#include "base_sync.c"
|
||||
#include "base_uid.c"
|
||||
#include "base_string.c"
|
||||
#include "base_cmdline.c"
|
||||
#include "base_uni.c"
|
||||
#include "base_buddy.c"
|
||||
#include "base_math.c"
|
||||
#include "base_wave.c"
|
||||
#include "base_rand.c"
|
||||
#include "base_bitbuff.c"
|
||||
#include "base_resource.c"
|
||||
#include "base_controller.c"
|
||||
#include "base_async.c"
|
||||
#include "base_state.c"
|
||||
#endif
|
||||
|
||||
//- Include base_win32
|
||||
#if IsLanguageC && IsPlatformWindows
|
||||
# include "base_win32/base_win32_inc.h"
|
||||
#include "base_win32/base_win32_inc.h"
|
||||
#endif
|
||||
|
||||
@ -3,23 +3,23 @@
|
||||
|
||||
Inline f32 IxSqrtF32(f32 f)
|
||||
{
|
||||
__m128 n = _mm_set_ss(f);
|
||||
n = _mm_sqrt_ss(n);
|
||||
return _mm_cvtss_f32(n);
|
||||
__m128 n = _mm_set_ss(f);
|
||||
n = _mm_sqrt_ss(n);
|
||||
return _mm_cvtss_f32(n);
|
||||
}
|
||||
|
||||
Inline f64 IxSqrtF64(f64 f)
|
||||
{
|
||||
__m128d n = _mm_set_sd(f);
|
||||
n = _mm_sqrt_sd(_mm_setzero_pd(), n);
|
||||
return _mm_cvtsd_f64(n);
|
||||
__m128d n = _mm_set_sd(f);
|
||||
n = _mm_sqrt_sd(_mm_setzero_pd(), n);
|
||||
return _mm_cvtsd_f64(n);
|
||||
}
|
||||
|
||||
Inline f32 IxRsqrtF32(f32 f)
|
||||
{
|
||||
__m128 n = _mm_set_ss(f);
|
||||
n = _mm_rsqrt_ss(n);
|
||||
return _mm_cvtss_f32(n);
|
||||
__m128 n = _mm_set_ss(f);
|
||||
n = _mm_rsqrt_ss(n);
|
||||
return _mm_cvtss_f32(n);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -27,22 +27,22 @@ Inline f32 IxRsqrtF32(f32 f)
|
||||
|
||||
Inline i32 IxRoundF32ToI32(f32 f)
|
||||
{
|
||||
return _mm_cvtss_si32(_mm_round_ss(_mm_setzero_ps(), _mm_set_ss(f), _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC));
|
||||
return _mm_cvtss_si32(_mm_round_ss(_mm_setzero_ps(), _mm_set_ss(f), _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC));
|
||||
}
|
||||
|
||||
Inline f32 IxRoundF32ToF32(f32 f)
|
||||
{
|
||||
return _mm_cvtss_f32(_mm_round_ss(_mm_setzero_ps(), _mm_set_ss(f), _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC));
|
||||
return _mm_cvtss_f32(_mm_round_ss(_mm_setzero_ps(), _mm_set_ss(f), _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC));
|
||||
}
|
||||
|
||||
Inline i64 IxRoundF64ToI64(f64 f)
|
||||
{
|
||||
return _mm_cvtsd_si64(_mm_round_sd(_mm_setzero_pd(), _mm_set_sd(f), _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC));
|
||||
return _mm_cvtsd_si64(_mm_round_sd(_mm_setzero_pd(), _mm_set_sd(f), _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC));
|
||||
}
|
||||
|
||||
Inline f64 IxRoundF64ToF64(f64 f)
|
||||
{
|
||||
return _mm_cvtsd_f64(_mm_round_sd(_mm_setzero_pd(), _mm_set_sd(f), _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC));
|
||||
return _mm_cvtsd_f64(_mm_round_sd(_mm_setzero_pd(), _mm_set_sd(f), _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -50,22 +50,22 @@ Inline f64 IxRoundF64ToF64(f64 f)
|
||||
|
||||
Inline i32 IxFloorF32ToI32(f32 f)
|
||||
{
|
||||
return _mm_cvtss_si32(_mm_floor_ss(_mm_setzero_ps(), _mm_set_ss(f)));
|
||||
return _mm_cvtss_si32(_mm_floor_ss(_mm_setzero_ps(), _mm_set_ss(f)));
|
||||
}
|
||||
|
||||
Inline f32 IxFloorF32ToF32(f32 f)
|
||||
{
|
||||
return _mm_cvtss_f32(_mm_floor_ss(_mm_setzero_ps(), _mm_set_ss(f)));
|
||||
return _mm_cvtss_f32(_mm_floor_ss(_mm_setzero_ps(), _mm_set_ss(f)));
|
||||
}
|
||||
|
||||
Inline i64 IxFloorF64ToI64(f64 f)
|
||||
{
|
||||
return _mm_cvtsd_si64(_mm_floor_sd(_mm_setzero_pd(), _mm_set_sd(f)));
|
||||
return _mm_cvtsd_si64(_mm_floor_sd(_mm_setzero_pd(), _mm_set_sd(f)));
|
||||
}
|
||||
|
||||
Inline f64 IxFloorF64ToF64(f64 f)
|
||||
{
|
||||
return _mm_cvtsd_f64(_mm_floor_sd(_mm_setzero_pd(), _mm_set_sd(f)));
|
||||
return _mm_cvtsd_f64(_mm_floor_sd(_mm_setzero_pd(), _mm_set_sd(f)));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -73,22 +73,22 @@ Inline f64 IxFloorF64ToF64(f64 f)
|
||||
|
||||
Inline i32 IxCeilF32ToI32(f32 f)
|
||||
{
|
||||
return _mm_cvtss_si32(_mm_ceil_ss(_mm_setzero_ps(), _mm_set_ss(f)));
|
||||
return _mm_cvtss_si32(_mm_ceil_ss(_mm_setzero_ps(), _mm_set_ss(f)));
|
||||
}
|
||||
|
||||
Inline f32 IxCeilF32ToF32(f32 f)
|
||||
{
|
||||
return _mm_cvtss_f32(_mm_ceil_ss(_mm_setzero_ps(), _mm_set_ss(f)));
|
||||
return _mm_cvtss_f32(_mm_ceil_ss(_mm_setzero_ps(), _mm_set_ss(f)));
|
||||
}
|
||||
|
||||
Inline i64 IxCeilF64ToI64(f64 f)
|
||||
{
|
||||
return _mm_cvtsd_si64(_mm_ceil_sd(_mm_setzero_pd(), _mm_set_sd(f)));
|
||||
return _mm_cvtsd_si64(_mm_ceil_sd(_mm_setzero_pd(), _mm_set_sd(f)));
|
||||
}
|
||||
|
||||
Inline f64 IxCeilF64ToF64(f64 f)
|
||||
{
|
||||
return _mm_cvtsd_f64(_mm_ceil_sd(_mm_setzero_pd(), _mm_set_sd(f)));
|
||||
return _mm_cvtsd_f64(_mm_ceil_sd(_mm_setzero_pd(), _mm_set_sd(f)));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -96,10 +96,10 @@ Inline f64 IxCeilF64ToF64(f64 f)
|
||||
|
||||
Inline f32 IxTruncF32ToF32(f32 f)
|
||||
{
|
||||
return _mm_cvtss_f32(_mm_round_ss(_mm_setzero_ps(), _mm_set_ss(f), _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC));
|
||||
return _mm_cvtss_f32(_mm_round_ss(_mm_setzero_ps(), _mm_set_ss(f), _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC));
|
||||
}
|
||||
|
||||
Inline f64 IxTruncF64ToF64(f64 f)
|
||||
{
|
||||
return _mm_cvtsd_f64(_mm_round_sd(_mm_setzero_pd(), _mm_set_sd(f), _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC));
|
||||
return _mm_cvtsd_f64(_mm_round_sd(_mm_setzero_pd(), _mm_set_sd(f), _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC));
|
||||
}
|
||||
|
||||
@ -3,22 +3,22 @@
|
||||
|
||||
Struct(LogEvent)
|
||||
{
|
||||
u64 id;
|
||||
u64 level_id;
|
||||
u64 id;
|
||||
u64 level_id;
|
||||
|
||||
DateTime datetime;
|
||||
i64 time_ns;
|
||||
DateTime datetime;
|
||||
i64 time_ns;
|
||||
|
||||
String msg;
|
||||
i32 level;
|
||||
String msg;
|
||||
i32 level;
|
||||
|
||||
i32 thread_id;
|
||||
i32 thread_id;
|
||||
};
|
||||
|
||||
Struct(LogEventsArray)
|
||||
{
|
||||
u64 count;
|
||||
LogEvent *logs;
|
||||
u64 count;
|
||||
LogEvent *logs;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -28,11 +28,11 @@ Struct(LogEventsArray)
|
||||
|
||||
/* Log level configuration */
|
||||
#ifndef LogLevel_CompTime
|
||||
# if IsRtcEnabled
|
||||
# define LogLevel_CompTime LogLevel_Debug
|
||||
# else
|
||||
# define LogLevel_CompTime LogLevel_Info
|
||||
# endif
|
||||
#if IsRtcEnabled
|
||||
#define LogLevel_CompTime LogLevel_Debug
|
||||
#else
|
||||
#define LogLevel_CompTime LogLevel_Info
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define LogLevel_None -1
|
||||
@ -49,84 +49,84 @@ Struct(LogEventsArray)
|
||||
|
||||
Struct(LogLevelSettings)
|
||||
{
|
||||
String shorthand;
|
||||
String shorthand;
|
||||
};
|
||||
|
||||
Global Readonly LogLevelSettings log_settings[LogLevel_Count] = {
|
||||
[LogLevel_Critical] = {
|
||||
CompLit("CRITICAL"),
|
||||
},
|
||||
[LogLevel_Critical] = {
|
||||
CompLit("CRITICAL"),
|
||||
},
|
||||
|
||||
[LogLevel_Error] = {
|
||||
CompLit("ERROR"),
|
||||
},
|
||||
[LogLevel_Error] = {
|
||||
CompLit("ERROR"),
|
||||
},
|
||||
|
||||
[LogLevel_Warning] = {
|
||||
CompLit("WARNING"),
|
||||
},
|
||||
[LogLevel_Warning] = {
|
||||
CompLit("WARNING"),
|
||||
},
|
||||
|
||||
[LogLevel_Success] = {
|
||||
CompLit("SUCCESS"),
|
||||
},
|
||||
[LogLevel_Success] = {
|
||||
CompLit("SUCCESS"),
|
||||
},
|
||||
|
||||
[LogLevel_Info] = {
|
||||
CompLit("INFO"),
|
||||
},
|
||||
[LogLevel_Info] = {
|
||||
CompLit("INFO"),
|
||||
},
|
||||
|
||||
[LogLevel_Debug] = {
|
||||
CompLit("DEBUG"),
|
||||
}
|
||||
[LogLevel_Debug] = {
|
||||
CompLit("DEBUG"),
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Compile-time logging macros
|
||||
|
||||
#if LogLevel(LogLevel_Critical)
|
||||
# define LogCritical(msg) Log_(LogLevel_Critical, msg)
|
||||
# define LogCriticalF(fmt_lit, ...) LogF_(LogLevel_Critical, Lit(fmt_lit) , ## __VA_ARGS__, FmtEnd)
|
||||
#define LogCritical(msg) Log_(LogLevel_Critical, msg)
|
||||
#define LogCriticalF(fmt_lit, ...) LogF_(LogLevel_Critical, Lit(fmt_lit) , ## __VA_ARGS__, FmtEnd)
|
||||
#else
|
||||
# define LogCritical(msg)
|
||||
# define LogCriticalF(...)
|
||||
#define LogCritical(msg)
|
||||
#define LogCriticalF(...)
|
||||
#endif
|
||||
|
||||
#if LogLevel(LogLevel_Error)
|
||||
# define LogError(msg) Log_(LogLevel_Error, msg)
|
||||
# define LogErrorF(fmt_lit, ...) LogF_(LogLevel_Error, Lit(fmt_lit) , ## __VA_ARGS__, FmtEnd)
|
||||
#define LogError(msg) Log_(LogLevel_Error, msg)
|
||||
#define LogErrorF(fmt_lit, ...) LogF_(LogLevel_Error, Lit(fmt_lit) , ## __VA_ARGS__, FmtEnd)
|
||||
#else
|
||||
# define LogError(msg)
|
||||
# define LogErrorF(...)
|
||||
#define LogError(msg)
|
||||
#define LogErrorF(...)
|
||||
#endif
|
||||
|
||||
#if LogLevel(LogLevel_Warning)
|
||||
# define LogWarning(msg) Log_(LogLevel_Warning, msg)
|
||||
# define LogWarningF(fmt_lit, ...) LogF_(LogLevel_Warning, Lit(fmt_lit) , ## __VA_ARGS__, FmtEnd)
|
||||
#define LogWarning(msg) Log_(LogLevel_Warning, msg)
|
||||
#define LogWarningF(fmt_lit, ...) LogF_(LogLevel_Warning, Lit(fmt_lit) , ## __VA_ARGS__, FmtEnd)
|
||||
#else
|
||||
# define LogWarning(msg)
|
||||
# define LogWarningF(...)
|
||||
#define LogWarning(msg)
|
||||
#define LogWarningF(...)
|
||||
#endif
|
||||
|
||||
#if LogLevel(LogLevel_Success)
|
||||
# define LogSuccess(msg) Log_(LogLevel_Success, msg)
|
||||
# define LogSuccessF(fmt_lit, ...) LogF_(LogLevel_Success, Lit(fmt_lit) , ## __VA_ARGS__, FmtEnd)
|
||||
#define LogSuccess(msg) Log_(LogLevel_Success, msg)
|
||||
#define LogSuccessF(fmt_lit, ...) LogF_(LogLevel_Success, Lit(fmt_lit) , ## __VA_ARGS__, FmtEnd)
|
||||
#else
|
||||
# define LogSuccess(msg)
|
||||
# define LogSuccessF(...)
|
||||
#define LogSuccess(msg)
|
||||
#define LogSuccessF(...)
|
||||
#endif
|
||||
|
||||
#if LogLevel(LogLevel_Info)
|
||||
# define LogInfo(msg) Log_(LogLevel_Info, msg)
|
||||
# define LogInfoF(fmt_lit, ...) LogF_(LogLevel_Info, Lit(fmt_lit) , ## __VA_ARGS__, FmtEnd)
|
||||
#define LogInfo(msg) Log_(LogLevel_Info, msg)
|
||||
#define LogInfoF(fmt_lit, ...) LogF_(LogLevel_Info, Lit(fmt_lit) , ## __VA_ARGS__, FmtEnd)
|
||||
#else
|
||||
# define LogInfo(msg)
|
||||
# define LogInfoF(...)
|
||||
#define LogInfo(msg)
|
||||
#define LogInfoF(...)
|
||||
#endif
|
||||
|
||||
#if LogLevel(LogLevel_Debug)
|
||||
# define LogDebug(msg) Log_(LogLevel_Debug, msg)
|
||||
# define LogDebugF(fmt_lit, ...) LogF_(LogLevel_Debug, Lit(fmt_lit) , ## __VA_ARGS__, FmtEnd)
|
||||
#define LogDebug(msg) Log_(LogLevel_Debug, msg)
|
||||
#define LogDebugF(fmt_lit, ...) LogF_(LogLevel_Debug, Lit(fmt_lit) , ## __VA_ARGS__, FmtEnd)
|
||||
#else
|
||||
# define LogDebug(msg)
|
||||
# define LogDebugF(...)
|
||||
#define LogDebug(msg)
|
||||
#define LogDebugF(...)
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
1562
src/base/base_math.c
1562
src/base/base_math.c
File diff suppressed because it is too large
Load Diff
@ -9,12 +9,12 @@
|
||||
|
||||
Enum(Axis)
|
||||
{
|
||||
Axis_X = 0,
|
||||
Axis_Y = 1,
|
||||
Axis_Z = 2,
|
||||
Axis_X = 0,
|
||||
Axis_Y = 1,
|
||||
Axis_Z = 2,
|
||||
|
||||
Axis_CountXY = 2,
|
||||
Axis_CountXYZ = 3
|
||||
Axis_CountXY = 2,
|
||||
Axis_CountXYZ = 3
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -145,17 +145,17 @@ Struct(Rng3U64) { Vec3U64 p0; Vec3U64 p1; };
|
||||
|
||||
Struct(Xform)
|
||||
{
|
||||
Vec2 bx; /* X basis vector (x axis) */
|
||||
Vec2 by; /* Y basis vector (y axis)*/
|
||||
Vec2 og; /* Translation vector (origin) */
|
||||
Vec2 bx; /* X basis vector (x axis) */
|
||||
Vec2 by; /* Y basis vector (y axis)*/
|
||||
Vec2 og; /* Translation vector (origin) */
|
||||
};
|
||||
|
||||
/* (T)ranslation, (R)otation, (S)cale */
|
||||
Struct(Trs)
|
||||
{
|
||||
Vec2 t;
|
||||
Vec2 s;
|
||||
f32 r;
|
||||
Vec2 t;
|
||||
Vec2 s;
|
||||
f32 r;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -163,9 +163,9 @@ Struct(Trs)
|
||||
|
||||
Struct(SoftSpring)
|
||||
{
|
||||
f32 bias_rate;
|
||||
f32 mass_scale;
|
||||
f32 impulse_scale;
|
||||
f32 bias_rate;
|
||||
f32 mass_scale;
|
||||
f32 impulse_scale;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -173,11 +173,11 @@ Struct(SoftSpring)
|
||||
|
||||
Struct(Mat4x4)
|
||||
{
|
||||
union
|
||||
{
|
||||
struct { Vec4 bx, by, bz, bw; };
|
||||
f32 e[4][4];
|
||||
};
|
||||
union
|
||||
{
|
||||
struct { Vec4 bx, by, bz, bw; };
|
||||
f32 e[4][4];
|
||||
};
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
@ -7,43 +7,43 @@
|
||||
__attribute((section(".text.memcpy")))
|
||||
void *memcpy(void *__restrict dst, const void *__restrict src, u64 count)
|
||||
{
|
||||
char *dst_pchar = dst;
|
||||
char *src_pchar = src;
|
||||
for (u64 i = 0; i < count; ++i)
|
||||
{
|
||||
dst_pchar[i] = src_pchar[i];
|
||||
}
|
||||
return dst;
|
||||
char *dst_pchar = dst;
|
||||
char *src_pchar = src;
|
||||
for (u64 i = 0; i < count; ++i)
|
||||
{
|
||||
dst_pchar[i] = src_pchar[i];
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
//- memset
|
||||
__attribute((section(".text.memset")))
|
||||
void *memset(void *dst, i32 c, u64 count)
|
||||
{
|
||||
char *dst_pchar = dst;
|
||||
for (u64 i = 0; i < count; ++i)
|
||||
{
|
||||
dst_pchar[i] = (char)c;
|
||||
}
|
||||
return dst;
|
||||
char *dst_pchar = dst;
|
||||
for (u64 i = 0; i < count; ++i)
|
||||
{
|
||||
dst_pchar[i] = (char)c;
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
//- memcmp
|
||||
__attribute((section(".text.memcmp")))
|
||||
i32 memcmp(const void *p1, const void *p2, u64 count)
|
||||
{
|
||||
i32 result = 0;
|
||||
char *p1_pchar = p1;
|
||||
char *p2_pchar = p2;
|
||||
for (u64 i = 0; i < count; ++i)
|
||||
i32 result = 0;
|
||||
char *p1_pchar = p1;
|
||||
char *p2_pchar = p2;
|
||||
for (u64 i = 0; i < count; ++i)
|
||||
{
|
||||
result = p1_pchar[i] - p2_pchar[i];
|
||||
if (result != 0)
|
||||
{
|
||||
result = p1_pchar[i] - p2_pchar[i];
|
||||
if (result != 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif /* !IsCrtlibEnabled */
|
||||
|
||||
@ -34,9 +34,9 @@ void SetMemoryReadWrite(void *address, u64 size);
|
||||
//~ Crtlib stubs
|
||||
|
||||
#if IsCrtlibEnabled
|
||||
# include <memory.h>
|
||||
#include <memory.h>
|
||||
#else
|
||||
void *memcpy(void *__restrict dst, const void *__restrict src, u64 n);
|
||||
void *memset(void *dst, i32 c, u64 n);
|
||||
i32 memcmp(const void *p1, const void *p2, u64 n);
|
||||
void *memcpy(void *__restrict dst, const void *__restrict src, u64 n);
|
||||
void *memset(void *dst, i32 c, u64 n);
|
||||
i32 memcmp(const void *p1, const void *p2, u64 n);
|
||||
#endif
|
||||
|
||||
@ -1,17 +1,17 @@
|
||||
u64 RandU64FromState(RandState *state)
|
||||
{
|
||||
u64 seed = state->seed;
|
||||
if (seed == 0)
|
||||
{
|
||||
TrueRand(StringFromStruct(&seed));
|
||||
state->seed = seed;
|
||||
}
|
||||
return seed ^ RandU64FromSeed(++state->counter);
|
||||
u64 seed = state->seed;
|
||||
if (seed == 0)
|
||||
{
|
||||
TrueRand(StringFromStruct(&seed));
|
||||
state->seed = seed;
|
||||
}
|
||||
return seed ^ RandU64FromSeed(++state->counter);
|
||||
}
|
||||
|
||||
f64 RandF64FromState(RandState *state, f64 range_start, f64 range_end)
|
||||
{
|
||||
return range_start + (range_end - range_start) * ((f64)(RandU64FromState(state) % RandMaxF64) / (f64)RandMaxF64);
|
||||
return range_start + (range_end - range_start) * ((f64)(RandU64FromState(state) % RandMaxF64) / (f64)RandMaxF64);
|
||||
}
|
||||
|
||||
/* Based on Jon Maiga's "mx3"
|
||||
@ -19,19 +19,19 @@ f64 RandF64FromState(RandState *state, f64 range_start, f64 range_end)
|
||||
*/
|
||||
u64 RandU64FromSeed(u64 seed)
|
||||
{
|
||||
seed = (seed ^ (seed >> 32)) * 0xbea225f9eb34556d;
|
||||
seed = (seed ^ (seed >> 29)) * 0xbea225f9eb34556d;
|
||||
seed = (seed ^ (seed >> 32)) * 0xbea225f9eb34556d;
|
||||
seed = (seed ^ (seed >> 29));
|
||||
return seed;
|
||||
seed = (seed ^ (seed >> 32)) * 0xbea225f9eb34556d;
|
||||
seed = (seed ^ (seed >> 29)) * 0xbea225f9eb34556d;
|
||||
seed = (seed ^ (seed >> 32)) * 0xbea225f9eb34556d;
|
||||
seed = (seed ^ (seed >> 29));
|
||||
return seed;
|
||||
}
|
||||
|
||||
u64 RandU64FromSeeds(u64 seed_a, u64 seed_b)
|
||||
{
|
||||
return RandU64FromSeed((seed_a * 3) + seed_b);
|
||||
return RandU64FromSeed((seed_a * 3) + seed_b);
|
||||
}
|
||||
|
||||
f64 RandF64FromSeed(u64 seed, f64 range_start, f64 range_end)
|
||||
{
|
||||
return range_start + (range_end - range_start) * ((f64)(RandU64FromSeed(seed) % RandMaxF64) / (f64)RandMaxF64);
|
||||
return range_start + (range_end - range_start) * ((f64)(RandU64FromSeed(seed) % RandMaxF64) / (f64)RandMaxF64);
|
||||
}
|
||||
|
||||
@ -3,8 +3,8 @@
|
||||
|
||||
Struct(RandState)
|
||||
{
|
||||
u64 seed; /* If a state's seed == 0 upon a call to a related function, it will be initialized using platform's true rng source */
|
||||
u64 counter;
|
||||
u64 seed; /* If a state's seed == 0 upon a call to a related function, it will be initialized using platform's true rng source */
|
||||
u64 counter;
|
||||
};
|
||||
|
||||
/* TODO: Use a value that gives good precision when dividing into range 0 -> 1 */
|
||||
|
||||
@ -3,39 +3,39 @@
|
||||
|
||||
void BootstrapResources(u64 archive_strings_count, String *archive_strings)
|
||||
{
|
||||
Arena *perm = PermArena();
|
||||
for (u64 archive_string_index = 0; archive_string_index < archive_strings_count; ++archive_string_index)
|
||||
Arena *perm = PermArena();
|
||||
for (u64 archive_string_index = 0; archive_string_index < archive_strings_count; ++archive_string_index)
|
||||
{
|
||||
String archive = archive_strings[archive_string_index];
|
||||
if (archive.len > 0)
|
||||
{
|
||||
String archive = archive_strings[archive_string_index];
|
||||
if (archive.len > 0)
|
||||
{
|
||||
BB_Buff bb = BB_BuffFromString(archive);
|
||||
BB_Reader br = BB_ReaderFromBuff(&bb);
|
||||
BB_Buff bb = BB_BuffFromString(archive);
|
||||
BB_Reader br = BB_ReaderFromBuff(&bb);
|
||||
|
||||
u64 magic = BB_ReadUBits(&br, 64);
|
||||
Assert(magic == ResourceEmbeddedMagic);
|
||||
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);
|
||||
/* 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(perm, 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);
|
||||
ResourceEntry *entry = PushStruct(perm, 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 = &Base.resource.bins[entry->hash % countof(Base.resource.bins)];
|
||||
SllQueuePushN(bin->first, bin->last, entry, next_in_bin);
|
||||
SllQueuePushN(Base.resource.first_entry, Base.resource.last_entry, entry, next);
|
||||
}
|
||||
Base.resource.entries_count += num_entries;
|
||||
}
|
||||
ResourceEntryBin *bin = &Base.resource.bins[entry->hash % countof(Base.resource.bins)];
|
||||
SllQueuePushN(bin->first, bin->last, entry, next_in_bin);
|
||||
SllQueuePushN(Base.resource.first_entry, Base.resource.last_entry, entry, next);
|
||||
}
|
||||
Base.resource.entries_count += num_entries;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -44,49 +44,49 @@ void BootstrapResources(u64 archive_strings_count, String *archive_strings)
|
||||
|
||||
b32 IsResourceNil(ResourceKey resource)
|
||||
{
|
||||
return resource.v == 0;
|
||||
return resource.v == 0;
|
||||
}
|
||||
|
||||
ResourceKey ResourceKeyFromStore(ResourceStore *store, String name)
|
||||
{
|
||||
ResourceKey result = Zi;
|
||||
result.v = HashFnv64(store->v, name);
|
||||
return result;
|
||||
ResourceKey result = Zi;
|
||||
result.v = HashFnv64(store->v, name);
|
||||
return result;
|
||||
}
|
||||
|
||||
ResourceEntry *ResourceEntryFromHash(u64 hash)
|
||||
{
|
||||
ResourceEntry *result = 0;
|
||||
ResourceEntryBin *bin = &Base.resource.bins[hash % countof(Base.resource.bins)];
|
||||
for (ResourceEntry *e = bin->first; e; e = e->next_in_bin)
|
||||
ResourceEntry *result = 0;
|
||||
ResourceEntryBin *bin = &Base.resource.bins[hash % countof(Base.resource.bins)];
|
||||
for (ResourceEntry *e = bin->first; e; e = e->next_in_bin)
|
||||
{
|
||||
if (e->hash == hash)
|
||||
{
|
||||
if (e->hash == hash)
|
||||
{
|
||||
result = e;
|
||||
break;
|
||||
}
|
||||
result = e;
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
String DataFromResource(ResourceKey resource)
|
||||
{
|
||||
String result = Zi;
|
||||
ResourceEntry *entry = ResourceEntryFromHash(resource.v);
|
||||
if (entry)
|
||||
{
|
||||
result = entry->data;
|
||||
}
|
||||
return result;
|
||||
String result = Zi;
|
||||
ResourceEntry *entry = ResourceEntryFromHash(resource.v);
|
||||
if (entry)
|
||||
{
|
||||
result = entry->data;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
String NameFromResource(ResourceKey resource)
|
||||
{
|
||||
String result = Zi;
|
||||
ResourceEntry *entry = ResourceEntryFromHash(resource.v);
|
||||
if (entry)
|
||||
{
|
||||
result = entry->name;
|
||||
}
|
||||
return result;
|
||||
String result = Zi;
|
||||
ResourceEntry *entry = ResourceEntryFromHash(resource.v);
|
||||
if (entry)
|
||||
{
|
||||
result = entry->name;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -3,26 +3,26 @@
|
||||
|
||||
Struct(ResourceEntry)
|
||||
{
|
||||
ResourceEntry *next;
|
||||
ResourceEntry *next_in_bin;
|
||||
ResourceEntry *next;
|
||||
ResourceEntry *next_in_bin;
|
||||
|
||||
u64 hash;
|
||||
String name;
|
||||
String data;
|
||||
u64 hash;
|
||||
String name;
|
||||
String data;
|
||||
};
|
||||
|
||||
Struct(ResourceEntryBin)
|
||||
{
|
||||
ResourceEntry *first;
|
||||
ResourceEntry *last;
|
||||
ResourceEntry *first;
|
||||
ResourceEntry *last;
|
||||
};
|
||||
|
||||
Struct(ResourceCtx)
|
||||
{
|
||||
u64 entries_count;
|
||||
ResourceEntry *first_entry;
|
||||
ResourceEntry *last_entry;
|
||||
ResourceEntryBin bins[4096];
|
||||
u64 entries_count;
|
||||
ResourceEntry *first_entry;
|
||||
ResourceEntry *last_entry;
|
||||
ResourceEntryBin bins[4096];
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
@ -42,7 +42,7 @@ Struct(Rng3U32) { Vec3U32 p0; Vec3U32 p1; };
|
||||
template<typename T, u32 N>
|
||||
u32 countof(T arr[N])
|
||||
{
|
||||
return N;
|
||||
return N;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -81,46 +81,46 @@ u32 countof(T arr[N])
|
||||
|
||||
Vec4 Vec4FromU32(u32 v)
|
||||
{
|
||||
Vec4 result;
|
||||
result.x = ((v >> 0) & 0xFF) / 255.0;
|
||||
result.y = ((v >> 8) & 0xFF) / 255.0;
|
||||
result.z = ((v >> 16) & 0xFF) / 255.0;
|
||||
result.w = ((v >> 24) & 0xFF) / 255.0;
|
||||
return result;
|
||||
Vec4 result;
|
||||
result.x = ((v >> 0) & 0xFF) / 255.0;
|
||||
result.y = ((v >> 8) & 0xFF) / 255.0;
|
||||
result.z = ((v >> 16) & 0xFF) / 255.0;
|
||||
result.w = ((v >> 24) & 0xFF) / 255.0;
|
||||
return result;
|
||||
}
|
||||
|
||||
u32 U32FromVec4(Vec4 v)
|
||||
{
|
||||
u32 result;
|
||||
result |= (((u32)(v.x * 255.0)) & 0xFF) << 0;
|
||||
result |= (((u32)(v.y * 255.0)) & 0xFF) << 8;
|
||||
result |= (((u32)(v.z * 255.0)) & 0xFF) << 16;
|
||||
result |= (((u32)(v.w * 255.0)) & 0xFF) << 24;
|
||||
return result;
|
||||
u32 result;
|
||||
result |= (((u32)(v.x * 255.0)) & 0xFF) << 0;
|
||||
result |= (((u32)(v.y * 255.0)) & 0xFF) << 8;
|
||||
result |= (((u32)(v.z * 255.0)) & 0xFF) << 16;
|
||||
result |= (((u32)(v.w * 255.0)) & 0xFF) << 24;
|
||||
return result;
|
||||
}
|
||||
|
||||
f32 LinearFromSrgbF32(f32 srgb)
|
||||
{
|
||||
f32 result;
|
||||
if (srgb <= 0.04045f)
|
||||
{
|
||||
result = srgb / 12.92f;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = pow((srgb + 0.055f) / 1.055f, 2.4f);
|
||||
}
|
||||
return result;
|
||||
f32 result;
|
||||
if (srgb <= 0.04045f)
|
||||
{
|
||||
result = srgb / 12.92f;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = pow((srgb + 0.055f) / 1.055f, 2.4f);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Vec4 LinearFromSrgb(Vec4 srgb)
|
||||
{
|
||||
Vec4 result;
|
||||
result.x = LinearFromSrgbF32(srgb.x);
|
||||
result.y = LinearFromSrgbF32(srgb.y);
|
||||
result.z = LinearFromSrgbF32(srgb.z);
|
||||
result.w = srgb.w;
|
||||
return result;
|
||||
Vec4 result;
|
||||
result.x = LinearFromSrgbF32(srgb.x);
|
||||
result.y = LinearFromSrgbF32(srgb.y);
|
||||
result.z = LinearFromSrgbF32(srgb.z);
|
||||
result.w = srgb.w;
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -128,13 +128,13 @@ Vec4 LinearFromSrgb(Vec4 srgb)
|
||||
|
||||
Vec2 RectUvFromVertexId(u32 id)
|
||||
{
|
||||
static const Vec2 uvs[4] = {
|
||||
Vec2(0, 0),
|
||||
Vec2(1, 0),
|
||||
Vec2(1, 1),
|
||||
Vec2(0, 1)
|
||||
};
|
||||
return uvs[id];
|
||||
static const Vec2 uvs[4] = {
|
||||
Vec2(0, 0),
|
||||
Vec2(1, 0),
|
||||
Vec2(1, 1),
|
||||
Vec2(0, 1)
|
||||
};
|
||||
return uvs[id];
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -142,20 +142,20 @@ Vec2 RectUvFromVertexId(u32 id)
|
||||
|
||||
Vec2 NdcFromPos(Vec2 pos, Vec2 size)
|
||||
{
|
||||
Vec2 result;
|
||||
result = pos / size;
|
||||
result *= Vec2(2, -2);
|
||||
result += Vec2(-1, 1);
|
||||
return result;
|
||||
Vec2 result;
|
||||
result = pos / size;
|
||||
result *= Vec2(2, -2);
|
||||
result += Vec2(-1, 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
Vec2 NdcFromUv(Vec2 uv)
|
||||
{
|
||||
Vec2 result;
|
||||
result = uv;
|
||||
result *= Vec2(2, -2);
|
||||
result += Vec2(-1, 1);
|
||||
return result;
|
||||
Vec2 result;
|
||||
result = uv;
|
||||
result *= Vec2(2, -2);
|
||||
result += Vec2(-1, 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -165,195 +165,195 @@ Vec2 NdcFromUv(Vec2 uv)
|
||||
template<typename T>
|
||||
u32 U32FromChar(in T c)
|
||||
{
|
||||
if(c == ' ')
|
||||
return 32;
|
||||
if(c == '!')
|
||||
return 33;
|
||||
if(c == '\"' || c == '\"')
|
||||
return 34;
|
||||
if(c == '#')
|
||||
return 35;
|
||||
if(c == '$')
|
||||
return 36;
|
||||
if(c == '%')
|
||||
return 37;
|
||||
if(c == '&')
|
||||
return 38;
|
||||
if(c == '\'')
|
||||
return 39;
|
||||
if(c == '(')
|
||||
return 40;
|
||||
if(c == ')')
|
||||
return 41;
|
||||
if(c == '*')
|
||||
return 42;
|
||||
if(c == '+')
|
||||
return 43;
|
||||
if(c == ',')
|
||||
return 44;
|
||||
if(c == '-')
|
||||
return 45;
|
||||
if(c == '.')
|
||||
return 46;
|
||||
if(c == '/')
|
||||
return 47;
|
||||
if(c == '0')
|
||||
return 48;
|
||||
if(c == '1')
|
||||
return 49;
|
||||
if(c == '2')
|
||||
return 50;
|
||||
if(c == '3')
|
||||
return 51;
|
||||
if(c == '4')
|
||||
return 52;
|
||||
if(c == '5')
|
||||
return 53;
|
||||
if(c == '6')
|
||||
return 54;
|
||||
if(c == '7')
|
||||
return 55;
|
||||
if(c == '8')
|
||||
return 56;
|
||||
if(c == '9')
|
||||
return 57;
|
||||
if(c == ':')
|
||||
return 58;
|
||||
if(c == ';')
|
||||
return 59;
|
||||
if(c == '<')
|
||||
return 60;
|
||||
if(c == '=')
|
||||
return 61;
|
||||
if(c == '>')
|
||||
return 62;
|
||||
if(c == '?')
|
||||
return 63;
|
||||
if(c == '@')
|
||||
return 64;
|
||||
if(c == 'A')
|
||||
return 65;
|
||||
if(c == 'B')
|
||||
return 66;
|
||||
if(c == 'C')
|
||||
return 67;
|
||||
if(c == 'D')
|
||||
return 68;
|
||||
if(c == 'E')
|
||||
return 69;
|
||||
if(c == 'F')
|
||||
return 70;
|
||||
if(c == 'G')
|
||||
return 71;
|
||||
if(c == 'H')
|
||||
return 72;
|
||||
if(c == 'I')
|
||||
return 73;
|
||||
if(c == 'J')
|
||||
return 74;
|
||||
if(c == 'K')
|
||||
return 75;
|
||||
if(c == 'L')
|
||||
return 76;
|
||||
if(c == 'M')
|
||||
return 77;
|
||||
if(c == 'N')
|
||||
return 78;
|
||||
if(c == 'O')
|
||||
return 79;
|
||||
if(c == 'P')
|
||||
return 80;
|
||||
if(c == 'Q')
|
||||
return 81;
|
||||
if(c == 'R')
|
||||
return 82;
|
||||
if(c == 'S')
|
||||
return 83;
|
||||
if(c == 'T')
|
||||
return 84;
|
||||
if(c == 'U')
|
||||
return 85;
|
||||
if(c == 'V')
|
||||
return 86;
|
||||
if(c == 'W')
|
||||
return 87;
|
||||
if(c == 'X')
|
||||
return 88;
|
||||
if(c == 'Y')
|
||||
return 89;
|
||||
if(c == 'Z')
|
||||
return 90;
|
||||
if(c == '[')
|
||||
return 91;
|
||||
if(c == '\\')
|
||||
return 92;
|
||||
if(c == ']')
|
||||
return 93;
|
||||
if(c == '^')
|
||||
return 94;
|
||||
if(c == '_')
|
||||
return 95;
|
||||
if(c == '`')
|
||||
return 96;
|
||||
if(c == 'a')
|
||||
return 97;
|
||||
if(c == 'b')
|
||||
return 98;
|
||||
if(c == 'c')
|
||||
return 99;
|
||||
if(c == 'd')
|
||||
return 100;
|
||||
if(c == 'e')
|
||||
return 101;
|
||||
if(c == 'f')
|
||||
return 102;
|
||||
if(c == 'g')
|
||||
return 103;
|
||||
if(c == 'h')
|
||||
return 104;
|
||||
if(c == 'i')
|
||||
return 105;
|
||||
if(c == 'j')
|
||||
return 106;
|
||||
if(c == 'k')
|
||||
return 107;
|
||||
if(c == 'l')
|
||||
return 108;
|
||||
if(c == 'm')
|
||||
return 109;
|
||||
if(c == 'n')
|
||||
return 110;
|
||||
if(c == 'o')
|
||||
return 111;
|
||||
if(c == 'p')
|
||||
return 112;
|
||||
if(c == 'q')
|
||||
return 113;
|
||||
if(c == 'r')
|
||||
return 114;
|
||||
if(c == 's')
|
||||
return 115;
|
||||
if(c == 't')
|
||||
return 116;
|
||||
if(c == 'u')
|
||||
return 117;
|
||||
if(c == 'v')
|
||||
return 118;
|
||||
if(c == 'w')
|
||||
return 119;
|
||||
if(c == 'x')
|
||||
return 120;
|
||||
if(c == 'y')
|
||||
return 121;
|
||||
if(c == 'z')
|
||||
return 122;
|
||||
if(c == '{')
|
||||
return 123;
|
||||
if(c == '|')
|
||||
return 124;
|
||||
if(c == '}')
|
||||
return 125;
|
||||
if(c == '~')
|
||||
return 126;
|
||||
return 0;
|
||||
if(c == ' ')
|
||||
return 32;
|
||||
if(c == '!')
|
||||
return 33;
|
||||
if(c == '\"' || c == '\"')
|
||||
return 34;
|
||||
if(c == '#')
|
||||
return 35;
|
||||
if(c == '$')
|
||||
return 36;
|
||||
if(c == '%')
|
||||
return 37;
|
||||
if(c == '&')
|
||||
return 38;
|
||||
if(c == '\'')
|
||||
return 39;
|
||||
if(c == '(')
|
||||
return 40;
|
||||
if(c == ')')
|
||||
return 41;
|
||||
if(c == '*')
|
||||
return 42;
|
||||
if(c == '+')
|
||||
return 43;
|
||||
if(c == ',')
|
||||
return 44;
|
||||
if(c == '-')
|
||||
return 45;
|
||||
if(c == '.')
|
||||
return 46;
|
||||
if(c == '/')
|
||||
return 47;
|
||||
if(c == '0')
|
||||
return 48;
|
||||
if(c == '1')
|
||||
return 49;
|
||||
if(c == '2')
|
||||
return 50;
|
||||
if(c == '3')
|
||||
return 51;
|
||||
if(c == '4')
|
||||
return 52;
|
||||
if(c == '5')
|
||||
return 53;
|
||||
if(c == '6')
|
||||
return 54;
|
||||
if(c == '7')
|
||||
return 55;
|
||||
if(c == '8')
|
||||
return 56;
|
||||
if(c == '9')
|
||||
return 57;
|
||||
if(c == ':')
|
||||
return 58;
|
||||
if(c == ';')
|
||||
return 59;
|
||||
if(c == '<')
|
||||
return 60;
|
||||
if(c == '=')
|
||||
return 61;
|
||||
if(c == '>')
|
||||
return 62;
|
||||
if(c == '?')
|
||||
return 63;
|
||||
if(c == '@')
|
||||
return 64;
|
||||
if(c == 'A')
|
||||
return 65;
|
||||
if(c == 'B')
|
||||
return 66;
|
||||
if(c == 'C')
|
||||
return 67;
|
||||
if(c == 'D')
|
||||
return 68;
|
||||
if(c == 'E')
|
||||
return 69;
|
||||
if(c == 'F')
|
||||
return 70;
|
||||
if(c == 'G')
|
||||
return 71;
|
||||
if(c == 'H')
|
||||
return 72;
|
||||
if(c == 'I')
|
||||
return 73;
|
||||
if(c == 'J')
|
||||
return 74;
|
||||
if(c == 'K')
|
||||
return 75;
|
||||
if(c == 'L')
|
||||
return 76;
|
||||
if(c == 'M')
|
||||
return 77;
|
||||
if(c == 'N')
|
||||
return 78;
|
||||
if(c == 'O')
|
||||
return 79;
|
||||
if(c == 'P')
|
||||
return 80;
|
||||
if(c == 'Q')
|
||||
return 81;
|
||||
if(c == 'R')
|
||||
return 82;
|
||||
if(c == 'S')
|
||||
return 83;
|
||||
if(c == 'T')
|
||||
return 84;
|
||||
if(c == 'U')
|
||||
return 85;
|
||||
if(c == 'V')
|
||||
return 86;
|
||||
if(c == 'W')
|
||||
return 87;
|
||||
if(c == 'X')
|
||||
return 88;
|
||||
if(c == 'Y')
|
||||
return 89;
|
||||
if(c == 'Z')
|
||||
return 90;
|
||||
if(c == '[')
|
||||
return 91;
|
||||
if(c == '\\')
|
||||
return 92;
|
||||
if(c == ']')
|
||||
return 93;
|
||||
if(c == '^')
|
||||
return 94;
|
||||
if(c == '_')
|
||||
return 95;
|
||||
if(c == '`')
|
||||
return 96;
|
||||
if(c == 'a')
|
||||
return 97;
|
||||
if(c == 'b')
|
||||
return 98;
|
||||
if(c == 'c')
|
||||
return 99;
|
||||
if(c == 'd')
|
||||
return 100;
|
||||
if(c == 'e')
|
||||
return 101;
|
||||
if(c == 'f')
|
||||
return 102;
|
||||
if(c == 'g')
|
||||
return 103;
|
||||
if(c == 'h')
|
||||
return 104;
|
||||
if(c == 'i')
|
||||
return 105;
|
||||
if(c == 'j')
|
||||
return 106;
|
||||
if(c == 'k')
|
||||
return 107;
|
||||
if(c == 'l')
|
||||
return 108;
|
||||
if(c == 'm')
|
||||
return 109;
|
||||
if(c == 'n')
|
||||
return 110;
|
||||
if(c == 'o')
|
||||
return 111;
|
||||
if(c == 'p')
|
||||
return 112;
|
||||
if(c == 'q')
|
||||
return 113;
|
||||
if(c == 'r')
|
||||
return 114;
|
||||
if(c == 's')
|
||||
return 115;
|
||||
if(c == 't')
|
||||
return 116;
|
||||
if(c == 'u')
|
||||
return 117;
|
||||
if(c == 'v')
|
||||
return 118;
|
||||
if(c == 'w')
|
||||
return 119;
|
||||
if(c == 'x')
|
||||
return 120;
|
||||
if(c == 'y')
|
||||
return 121;
|
||||
if(c == 'z')
|
||||
return 122;
|
||||
if(c == '{')
|
||||
return 123;
|
||||
if(c == '|')
|
||||
return 124;
|
||||
if(c == '}')
|
||||
return 125;
|
||||
if(c == '~')
|
||||
return 126;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -3,10 +3,10 @@
|
||||
|
||||
Struct(BaseCtx)
|
||||
{
|
||||
CmdLineCtx cmdline;
|
||||
ResourceCtx resource;
|
||||
GstatCtx gstat;
|
||||
AsyncCtx async;
|
||||
CmdLineCtx cmdline;
|
||||
ResourceCtx resource;
|
||||
GstatCtx gstat;
|
||||
AsyncCtx async;
|
||||
};
|
||||
|
||||
extern BaseCtx Base;
|
||||
@ -16,7 +16,7 @@ extern BaseCtx Base;
|
||||
|
||||
Struct(BaseThreadLocalCtx)
|
||||
{
|
||||
ThreadLocalArenaCtx arenas;
|
||||
ThreadLocalArenaCtx arenas;
|
||||
};
|
||||
|
||||
extern ThreadLocal BaseThreadLocalCtx Base_tl;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -6,60 +6,60 @@
|
||||
|
||||
Enum(FmtArgKind)
|
||||
{
|
||||
FmtArgKind_None,
|
||||
FmtArgKind_None,
|
||||
|
||||
/* Arbitrary magic numbers for argument validation */
|
||||
FmtArgKind_Char = 0xf5281df,
|
||||
FmtArgKind_String = 0xa5ffa9a,
|
||||
/* Arbitrary magic numbers for argument validation */
|
||||
FmtArgKind_Char = 0xf5281df,
|
||||
FmtArgKind_String = 0xa5ffa9a,
|
||||
|
||||
FmtArgKind_Uint = 0x746f19b,
|
||||
FmtArgKind_Uint2 = 0x83429d9,
|
||||
FmtArgKind_Uint3 = 0x1b4b749,
|
||||
FmtArgKind_Uint4 = 0xf8eb3cf,
|
||||
FmtArgKind_Uint = 0x746f19b,
|
||||
FmtArgKind_Uint2 = 0x83429d9,
|
||||
FmtArgKind_Uint3 = 0x1b4b749,
|
||||
FmtArgKind_Uint4 = 0xf8eb3cf,
|
||||
|
||||
FmtArgKind_Sint = 0x8603694,
|
||||
FmtArgKind_Sint2 = 0x335a803,
|
||||
FmtArgKind_Sint3 = 0xe5e4ab1,
|
||||
FmtArgKind_Sint4 = 0xe1fd7ad,
|
||||
FmtArgKind_Sint = 0x8603694,
|
||||
FmtArgKind_Sint2 = 0x335a803,
|
||||
FmtArgKind_Sint3 = 0xe5e4ab1,
|
||||
FmtArgKind_Sint4 = 0xe1fd7ad,
|
||||
|
||||
FmtArgKind_Float = 0x4814143,
|
||||
FmtArgKind_Float2 = 0x4260065,
|
||||
FmtArgKind_Float3 = 0x0d28ab7,
|
||||
FmtArgKind_Float4 = 0x76fe314,
|
||||
FmtArgKind_Float = 0x4814143,
|
||||
FmtArgKind_Float2 = 0x4260065,
|
||||
FmtArgKind_Float3 = 0x0d28ab7,
|
||||
FmtArgKind_Float4 = 0x76fe314,
|
||||
|
||||
FmtArgKind_Hex = 0xa3d0792,
|
||||
FmtArgKind_Ptr = 0xc4519e4,
|
||||
FmtArgKind_Uid = 0xd1cd407,
|
||||
FmtArgKind_Handle = 0xead3bec,
|
||||
FmtArgKind_Hex = 0xa3d0792,
|
||||
FmtArgKind_Ptr = 0xc4519e4,
|
||||
FmtArgKind_Uid = 0xd1cd407,
|
||||
FmtArgKind_Handle = 0xead3bec,
|
||||
|
||||
FmtArgKind_End = 0xecbc5ae
|
||||
FmtArgKind_End = 0xecbc5ae
|
||||
};
|
||||
|
||||
Struct(FmtArg)
|
||||
{
|
||||
FmtArgKind kind;
|
||||
u32 p; /* Precision */
|
||||
u32 z; /* Z-fill */
|
||||
union
|
||||
FmtArgKind kind;
|
||||
u32 p; /* Precision */
|
||||
u32 z; /* Z-fill */
|
||||
union
|
||||
{
|
||||
u8 c;
|
||||
String string;
|
||||
Vec4U64 uints;
|
||||
Vec4I64 sints;
|
||||
Vec4F64 floats;
|
||||
void *ptr;
|
||||
Uid uid;
|
||||
struct
|
||||
{
|
||||
u8 c;
|
||||
String string;
|
||||
Vec4U64 uints;
|
||||
Vec4I64 sints;
|
||||
Vec4F64 floats;
|
||||
void *ptr;
|
||||
Uid uid;
|
||||
struct
|
||||
{
|
||||
u64 h64[2];
|
||||
} handle;
|
||||
} value;
|
||||
u64 h64[2];
|
||||
} handle;
|
||||
} value;
|
||||
};
|
||||
|
||||
Struct(FmtArgArray)
|
||||
{
|
||||
u64 count;
|
||||
FmtArg *args;
|
||||
u64 count;
|
||||
FmtArg *args;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -67,11 +67,11 @@ Struct(FmtArgArray)
|
||||
|
||||
Struct(CodepointIter)
|
||||
{
|
||||
u32 codepoint;
|
||||
u32 codepoint;
|
||||
|
||||
/* Internal */
|
||||
String src;
|
||||
u64 pos;
|
||||
/* Internal */
|
||||
String src;
|
||||
u64 pos;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
@ -4,135 +4,135 @@
|
||||
//- Exclusive mutex lock
|
||||
Lock LockSpinE(Mutex *m, i32 spin)
|
||||
{
|
||||
b32 locked = 0;
|
||||
i32 spin_cnt = 0;
|
||||
while (!locked)
|
||||
b32 locked = 0;
|
||||
i32 spin_cnt = 0;
|
||||
while (!locked)
|
||||
{
|
||||
++spin_cnt;
|
||||
u32 v = Atomic32FetchTestSet(&m->v, 0, 0x80000000);
|
||||
if (v == 0)
|
||||
{
|
||||
++spin_cnt;
|
||||
u32 v = Atomic32FetchTestSet(&m->v, 0, 0x80000000);
|
||||
if (v == 0)
|
||||
{
|
||||
locked = 1;
|
||||
}
|
||||
else if (v == 0x40000000)
|
||||
{
|
||||
/* Lock has pending bit set, try to lock */
|
||||
u32 swp = Atomic32FetchTestSet(&m->v, v, 0x80000000);
|
||||
while (swp != v && swp == 0x40000000)
|
||||
{
|
||||
v = swp;
|
||||
swp = Atomic32FetchTestSet(&m->v, v, 0x80000000);
|
||||
}
|
||||
v = swp;
|
||||
if (v == 0x40000000)
|
||||
{
|
||||
locked = 1;
|
||||
}
|
||||
}
|
||||
if (!locked && (v & 0xC0000000) == 0)
|
||||
{
|
||||
/* Lock has shared lockers and no pending waiter, set pending bit */
|
||||
u32 swp = Atomic32FetchTestSet(&m->v, v, v | 0x40000000);
|
||||
while (swp != v && (swp & 0xC0000000) == 0 && swp != 0)
|
||||
{
|
||||
v = swp;
|
||||
swp = Atomic32FetchTestSet(&m->v, v, v | 0x40000000);
|
||||
}
|
||||
v = swp;
|
||||
}
|
||||
/* Pause or wait */
|
||||
if (!locked && v != 0 && v != 0x40000000)
|
||||
{
|
||||
if (spin_cnt < spin)
|
||||
{
|
||||
_mm_pause();
|
||||
}
|
||||
else
|
||||
{
|
||||
FutexYieldNeq(&m->v, &v, 4);
|
||||
spin_cnt = 0;
|
||||
}
|
||||
}
|
||||
locked = 1;
|
||||
}
|
||||
else if (v == 0x40000000)
|
||||
{
|
||||
/* Lock has pending bit set, try to lock */
|
||||
u32 swp = Atomic32FetchTestSet(&m->v, v, 0x80000000);
|
||||
while (swp != v && swp == 0x40000000)
|
||||
{
|
||||
v = swp;
|
||||
swp = Atomic32FetchTestSet(&m->v, v, 0x80000000);
|
||||
}
|
||||
v = swp;
|
||||
if (v == 0x40000000)
|
||||
{
|
||||
locked = 1;
|
||||
}
|
||||
}
|
||||
if (!locked && (v & 0xC0000000) == 0)
|
||||
{
|
||||
/* Lock has shared lockers and no pending waiter, set pending bit */
|
||||
u32 swp = Atomic32FetchTestSet(&m->v, v, v | 0x40000000);
|
||||
while (swp != v && (swp & 0xC0000000) == 0 && swp != 0)
|
||||
{
|
||||
v = swp;
|
||||
swp = Atomic32FetchTestSet(&m->v, v, v | 0x40000000);
|
||||
}
|
||||
v = swp;
|
||||
}
|
||||
/* Pause or wait */
|
||||
if (!locked && v != 0 && v != 0x40000000)
|
||||
{
|
||||
if (spin_cnt < spin)
|
||||
{
|
||||
_mm_pause();
|
||||
}
|
||||
else
|
||||
{
|
||||
FutexYieldNeq(&m->v, &v, 4);
|
||||
spin_cnt = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if IsRtcEnabled
|
||||
Atomic32Set(&m->exclusive_thread_id, ThreadId());
|
||||
#endif
|
||||
#if IsRtcEnabled
|
||||
Atomic32Set(&m->exclusive_thread_id, ThreadId());
|
||||
#endif
|
||||
|
||||
Lock lock = Zi;
|
||||
lock.exclusive = 1;
|
||||
lock.mutex = m;
|
||||
return lock;
|
||||
Lock lock = Zi;
|
||||
lock.exclusive = 1;
|
||||
lock.mutex = m;
|
||||
return lock;
|
||||
}
|
||||
|
||||
//- Shared mutex lock
|
||||
Lock LockSpinS(Mutex *m, i32 spin)
|
||||
{
|
||||
b32 locked = 0;
|
||||
i32 spin_cnt = 0;
|
||||
while (!locked)
|
||||
b32 locked = 0;
|
||||
i32 spin_cnt = 0;
|
||||
while (!locked)
|
||||
{
|
||||
++spin_cnt;
|
||||
u32 v = Atomic32Fetch(&m->v);
|
||||
while (!locked && (v & 0xC0000000) == 0)
|
||||
{
|
||||
++spin_cnt;
|
||||
u32 v = Atomic32Fetch(&m->v);
|
||||
while (!locked && (v & 0xC0000000) == 0)
|
||||
{
|
||||
/* Lock has no exclusive or pending exclusive lock, increment shared count */
|
||||
u32 swp = Atomic32FetchTestSet(&m->v, v, v + 1);
|
||||
if (v == swp)
|
||||
{
|
||||
locked = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
v = swp;
|
||||
}
|
||||
}
|
||||
/* Pause or wait */
|
||||
if (!locked)
|
||||
{
|
||||
if (spin_cnt < spin)
|
||||
{
|
||||
_mm_pause();
|
||||
}
|
||||
else
|
||||
{
|
||||
FutexYieldNeq(&m->v, &v, 4);
|
||||
spin_cnt = 0;
|
||||
}
|
||||
}
|
||||
/* Lock has no exclusive or pending exclusive lock, increment shared count */
|
||||
u32 swp = Atomic32FetchTestSet(&m->v, v, v + 1);
|
||||
if (v == swp)
|
||||
{
|
||||
locked = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
v = swp;
|
||||
}
|
||||
}
|
||||
Lock lock = Zi;
|
||||
lock.mutex = m;
|
||||
return lock;
|
||||
/* Pause or wait */
|
||||
if (!locked)
|
||||
{
|
||||
if (spin_cnt < spin)
|
||||
{
|
||||
_mm_pause();
|
||||
}
|
||||
else
|
||||
{
|
||||
FutexYieldNeq(&m->v, &v, 4);
|
||||
spin_cnt = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
Lock lock = Zi;
|
||||
lock.mutex = m;
|
||||
return lock;
|
||||
}
|
||||
|
||||
//- Mutex lock wrappers
|
||||
Lock LockE(Mutex *m)
|
||||
{
|
||||
return LockSpinE(m, DefaultMutexSpin);
|
||||
return LockSpinE(m, DefaultMutexSpin);
|
||||
}
|
||||
|
||||
Lock LockS(Mutex *m)
|
||||
{
|
||||
return LockSpinS(m, DefaultMutexSpin);
|
||||
return LockSpinS(m, DefaultMutexSpin);
|
||||
}
|
||||
|
||||
void Unlock(Lock *l)
|
||||
{
|
||||
Mutex *m = l->mutex;
|
||||
if (l->exclusive)
|
||||
{
|
||||
#if IsRtcEnabled
|
||||
Atomic32Set(&m->exclusive_thread_id, 0);
|
||||
#endif
|
||||
Atomic32Set(&m->v, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
Atomic32FetchAdd(&m->v, -1);
|
||||
}
|
||||
FutexWakeNeq(&m->v);
|
||||
ZeroStruct(l);
|
||||
Mutex *m = l->mutex;
|
||||
if (l->exclusive)
|
||||
{
|
||||
#if IsRtcEnabled
|
||||
Atomic32Set(&m->exclusive_thread_id, 0);
|
||||
#endif
|
||||
Atomic32Set(&m->v, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
Atomic32FetchAdd(&m->v, -1);
|
||||
}
|
||||
FutexWakeNeq(&m->v);
|
||||
ZeroStruct(l);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -140,29 +140,29 @@ void Unlock(Lock *l)
|
||||
|
||||
void YieldOnCv(Cv *cv, Lock *l)
|
||||
{
|
||||
u64 old_wake_gen = Atomic64Fetch(&cv->wake_gen);
|
||||
Mutex *mutex = l->mutex;
|
||||
b32 exclusive = l->exclusive;
|
||||
u64 old_wake_gen = Atomic64Fetch(&cv->wake_gen);
|
||||
Mutex *mutex = l->mutex;
|
||||
b32 exclusive = l->exclusive;
|
||||
{
|
||||
Unlock(l);
|
||||
{
|
||||
Unlock(l);
|
||||
{
|
||||
FutexYieldNeq(&cv->wake_gen, &old_wake_gen, sizeof(old_wake_gen));
|
||||
}
|
||||
if (exclusive)
|
||||
{
|
||||
*l = LockE(mutex);
|
||||
}
|
||||
else
|
||||
{
|
||||
*l = LockS(mutex);
|
||||
}
|
||||
FutexYieldNeq(&cv->wake_gen, &old_wake_gen, sizeof(old_wake_gen));
|
||||
}
|
||||
if (exclusive)
|
||||
{
|
||||
*l = LockE(mutex);
|
||||
}
|
||||
else
|
||||
{
|
||||
*l = LockS(mutex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SignalCv(Cv *cv)
|
||||
{
|
||||
Atomic64FetchAdd(&cv->wake_gen, 1);
|
||||
FutexWakeNeq(&cv->wake_gen);
|
||||
Atomic64FetchAdd(&cv->wake_gen, 1);
|
||||
FutexWakeNeq(&cv->wake_gen);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -170,36 +170,36 @@ void SignalCv(Cv *cv)
|
||||
|
||||
i64 FetchFence(Fence *fence)
|
||||
{
|
||||
return Atomic64Fetch(&fence->v.v);
|
||||
return Atomic64Fetch(&fence->v.v);
|
||||
}
|
||||
|
||||
void SetFence(Fence *fence, i64 x)
|
||||
{
|
||||
Atomic64Set(&fence->v.v, x);
|
||||
FutexWakeGte(&fence->v.v);
|
||||
Atomic64Set(&fence->v.v, x);
|
||||
FutexWakeGte(&fence->v.v);
|
||||
}
|
||||
|
||||
i64 FetchSetFence(Fence *fence, i64 x)
|
||||
{
|
||||
i64 fetch = Atomic64FetchSet(&fence->v.v, x);
|
||||
FutexWakeGte(&fence->v.v);
|
||||
return fetch;
|
||||
i64 fetch = Atomic64FetchSet(&fence->v.v, x);
|
||||
FutexWakeGte(&fence->v.v);
|
||||
return fetch;
|
||||
}
|
||||
|
||||
i64 FetchAddFence(Fence *fence, i64 x)
|
||||
{
|
||||
i64 fetch = Atomic64FetchAdd(&fence->v.v, x);
|
||||
FutexWakeGte(&fence->v.v);
|
||||
return fetch;
|
||||
i64 fetch = Atomic64FetchAdd(&fence->v.v, x);
|
||||
FutexWakeGte(&fence->v.v);
|
||||
return fetch;
|
||||
}
|
||||
|
||||
i64 YieldOnFence(Fence *fence, i64 target)
|
||||
{
|
||||
i64 v = Atomic64Fetch(&fence->v.v);
|
||||
while (v < target)
|
||||
{
|
||||
FutexYieldGte(&fence->v.v, &v, sizeof(v));
|
||||
v = Atomic64Fetch(&fence->v.v);
|
||||
}
|
||||
return v;
|
||||
i64 v = Atomic64Fetch(&fence->v.v);
|
||||
while (v < target)
|
||||
{
|
||||
FutexYieldGte(&fence->v.v, &v, sizeof(v));
|
||||
v = Atomic64Fetch(&fence->v.v);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
@ -53,11 +53,11 @@ void Unlock(Lock *lock);
|
||||
|
||||
//- Lock assertion
|
||||
#if IsRtcEnabled
|
||||
# define AssertLockedE(l, m) Assert((l)->mutex == (m) && (l)->exclusive == 1)
|
||||
# define AssertLockedES(l, m) Assert((l)->mutex == (m))
|
||||
#define AssertLockedE(l, m) Assert((l)->mutex == (m) && (l)->exclusive == 1)
|
||||
#define AssertLockedES(l, m) Assert((l)->mutex == (m))
|
||||
#else
|
||||
# define AssertLockedE(l, m)
|
||||
# define AssertLockedES(l, m)
|
||||
#define AssertLockedE(l, m)
|
||||
#define AssertLockedES(l, m)
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
@ -3,14 +3,14 @@
|
||||
|
||||
Struct(DateTime)
|
||||
{
|
||||
u32 year;
|
||||
u32 month;
|
||||
u32 day_of_week;
|
||||
u32 day;
|
||||
u32 hour;
|
||||
u32 minute;
|
||||
u32 second;
|
||||
u32 milliseconds;
|
||||
u32 year;
|
||||
u32 month;
|
||||
u32 day_of_week;
|
||||
u32 day;
|
||||
u32 hour;
|
||||
u32 minute;
|
||||
u32 second;
|
||||
u32 milliseconds;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
@ -1,22 +1,22 @@
|
||||
/* Returns a uid generated from the system's random number generator */
|
||||
Uid UidFromTrueRand(void)
|
||||
{
|
||||
Uid result = Zi;
|
||||
TrueRand(StringFromStruct(&result));
|
||||
return result;
|
||||
Uid result = Zi;
|
||||
TrueRand(StringFromStruct(&result));
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Combines 2 uids into a new uid */
|
||||
Uid CombineUid(Uid a, Uid b)
|
||||
{
|
||||
Uid result;
|
||||
result.hi = (a.hi * 3) + b.hi;
|
||||
result.lo = (a.lo * 3) + b.lo;
|
||||
result.hi += result.lo;
|
||||
result.lo += result.hi;
|
||||
result.hi = RandU64FromSeed(result.hi);
|
||||
result.lo = RandU64FromSeed(result.lo);
|
||||
result.hi += result.lo;
|
||||
result.lo += result.hi;
|
||||
return result;
|
||||
Uid result;
|
||||
result.hi = (a.hi * 3) + b.hi;
|
||||
result.lo = (a.lo * 3) + b.lo;
|
||||
result.hi += result.lo;
|
||||
result.lo += result.hi;
|
||||
result.hi = RandU64FromSeed(result.hi);
|
||||
result.lo = RandU64FromSeed(result.lo);
|
||||
result.hi += result.lo;
|
||||
result.lo += result.hi;
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -3,8 +3,8 @@
|
||||
|
||||
Struct(Uid)
|
||||
{
|
||||
u64 hi;
|
||||
u64 lo;
|
||||
u64 hi;
|
||||
u64 lo;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
@ -5,126 +5,130 @@
|
||||
|
||||
Utf8DecodeResult DecodeUtf8(String str)
|
||||
{
|
||||
const u8 lengths[32] = {
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,2,2,2,2,3,3,4,5
|
||||
};
|
||||
const u8 lengths[32] = {
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,2,2,2,2,3,3,4,5
|
||||
};
|
||||
|
||||
Utf8DecodeResult result = Zi;
|
||||
u32 codepoint = U32Max;
|
||||
u32 advance = 0;
|
||||
if (str.len > 0)
|
||||
Utf8DecodeResult result = Zi;
|
||||
u32 codepoint = U32Max;
|
||||
u32 advance = 0;
|
||||
if (str.len > 0)
|
||||
{
|
||||
u8 c0 = str.text[0];
|
||||
u8 utf8_len = lengths[c0 >> 3];
|
||||
|
||||
advance = 1;
|
||||
switch (utf8_len)
|
||||
{
|
||||
u8 c0 = str.text[0];
|
||||
u8 utf8_len = lengths[c0 >> 3];
|
||||
default: break;
|
||||
|
||||
advance = 1;
|
||||
switch (utf8_len)
|
||||
case 1:
|
||||
{
|
||||
codepoint = c0;
|
||||
} break;
|
||||
|
||||
case 2:
|
||||
{
|
||||
if (str.len >= 2)
|
||||
{
|
||||
default: break;
|
||||
|
||||
case 1:
|
||||
{
|
||||
codepoint = c0;
|
||||
} break;
|
||||
|
||||
case 2:
|
||||
{
|
||||
if (str.len >= 2)
|
||||
{
|
||||
u8 c1 = str.text[1];
|
||||
if (lengths[c1 >> 3] == 0)
|
||||
{
|
||||
codepoint = (c1 & 0x3F) << 0;
|
||||
codepoint |= (c0 & 0x1F) << 6;
|
||||
advance = 2;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case 3:
|
||||
{
|
||||
if (str.len >= 3)
|
||||
{
|
||||
u8 c1 = str.text[1];
|
||||
u8 c2 = str.text[2];
|
||||
if (lengths[c1 >> 3] == 0 &&
|
||||
lengths[c2 >> 3] == 0)
|
||||
{
|
||||
codepoint = (c2 & 0x3F) << 0;
|
||||
codepoint |= (c1 & 0x3F) << 6;
|
||||
codepoint |= (c0 & 0x0F) << 12;
|
||||
advance = 3;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case 4:
|
||||
{
|
||||
if (str.len >= 4)
|
||||
{
|
||||
u8 c1 = str.text[1];
|
||||
u8 c2 = str.text[2];
|
||||
u8 c3 = str.text[3];
|
||||
if (lengths[c1 >> 3] == 0 &&
|
||||
lengths[c2 >> 3] == 0 &&
|
||||
lengths[c3 >> 3] == 0)
|
||||
{
|
||||
codepoint = (c3 & 0x3F) << 0;
|
||||
codepoint |= (c2 & 0x3F) << 6;
|
||||
codepoint |= (c1 & 0x3F) << 12;
|
||||
codepoint |= (c0 & 0x07) << 16;
|
||||
advance = 3;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
u8 c1 = str.text[1];
|
||||
if (lengths[c1 >> 3] == 0)
|
||||
{
|
||||
codepoint = (c1 & 0x3F) << 0;
|
||||
codepoint |= (c0 & 0x1F) << 6;
|
||||
advance = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
result.advance8 = advance;
|
||||
result.codepoint = codepoint;
|
||||
return result;
|
||||
case 3:
|
||||
{
|
||||
if (str.len >= 3)
|
||||
{
|
||||
u8 c1 = str.text[1];
|
||||
u8 c2 = str.text[2];
|
||||
if (
|
||||
lengths[c1 >> 3] == 0 &&
|
||||
lengths[c2 >> 3] == 0
|
||||
)
|
||||
{
|
||||
codepoint = (c2 & 0x3F) << 0;
|
||||
codepoint |= (c1 & 0x3F) << 6;
|
||||
codepoint |= (c0 & 0x0F) << 12;
|
||||
advance = 3;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case 4:
|
||||
{
|
||||
if (str.len >= 4)
|
||||
{
|
||||
u8 c1 = str.text[1];
|
||||
u8 c2 = str.text[2];
|
||||
u8 c3 = str.text[3];
|
||||
if (
|
||||
lengths[c1 >> 3] == 0 &&
|
||||
lengths[c2 >> 3] == 0 &&
|
||||
lengths[c3 >> 3] == 0
|
||||
)
|
||||
{
|
||||
codepoint = (c3 & 0x3F) << 0;
|
||||
codepoint |= (c2 & 0x3F) << 6;
|
||||
codepoint |= (c1 & 0x3F) << 12;
|
||||
codepoint |= (c0 & 0x07) << 16;
|
||||
advance = 3;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
result.advance8 = advance;
|
||||
result.codepoint = codepoint;
|
||||
return result;
|
||||
}
|
||||
|
||||
//- Encode
|
||||
|
||||
Utf8EncodeResult EncodeUtf8(u32 codepoint)
|
||||
{
|
||||
Utf8EncodeResult result = Zi;
|
||||
Utf8EncodeResult result = Zi;
|
||||
|
||||
if (codepoint <= 0x7F)
|
||||
{
|
||||
result.count8 = 1;
|
||||
result.chars8[0] = codepoint;
|
||||
}
|
||||
else if (codepoint <= 0x7FF)
|
||||
{
|
||||
result.count8 = 2;
|
||||
result.chars8[1] = 0x80 | ((codepoint >> 0) & 0x3F);
|
||||
result.chars8[0] = 0xC0 | ((codepoint >> 6) & 0x1F);
|
||||
}
|
||||
else if (codepoint <= 0xFFFF)
|
||||
{
|
||||
result.count8 = 3;
|
||||
result.chars8[2] = 0x80 | ((codepoint >> 0) & 0x3F);
|
||||
result.chars8[1] = 0x80 | ((codepoint >> 6) & 0x3F);
|
||||
result.chars8[0] = 0xE0 | ((codepoint >> 12) & 0x0F);
|
||||
}
|
||||
else if (codepoint <= 0x10FFFF)
|
||||
{
|
||||
result.count8 = 4;
|
||||
result.chars8[3] = 0x80 | ((codepoint >> 0) & 0x3F);
|
||||
result.chars8[2] = 0x80 | ((codepoint >> 6) & 0x3F);
|
||||
result.chars8[1] = 0x80 | ((codepoint >> 12) & 0x3F);
|
||||
result.chars8[0] = 0xF0 | ((codepoint >> 18) & 0x07);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Invalid codepoint */
|
||||
result.count8 = 1;
|
||||
result.chars8[0] = '?';
|
||||
}
|
||||
if (codepoint <= 0x7F)
|
||||
{
|
||||
result.count8 = 1;
|
||||
result.chars8[0] = codepoint;
|
||||
}
|
||||
else if (codepoint <= 0x7FF)
|
||||
{
|
||||
result.count8 = 2;
|
||||
result.chars8[1] = 0x80 | ((codepoint >> 0) & 0x3F);
|
||||
result.chars8[0] = 0xC0 | ((codepoint >> 6) & 0x1F);
|
||||
}
|
||||
else if (codepoint <= 0xFFFF)
|
||||
{
|
||||
result.count8 = 3;
|
||||
result.chars8[2] = 0x80 | ((codepoint >> 0) & 0x3F);
|
||||
result.chars8[1] = 0x80 | ((codepoint >> 6) & 0x3F);
|
||||
result.chars8[0] = 0xE0 | ((codepoint >> 12) & 0x0F);
|
||||
}
|
||||
else if (codepoint <= 0x10FFFF)
|
||||
{
|
||||
result.count8 = 4;
|
||||
result.chars8[3] = 0x80 | ((codepoint >> 0) & 0x3F);
|
||||
result.chars8[2] = 0x80 | ((codepoint >> 6) & 0x3F);
|
||||
result.chars8[1] = 0x80 | ((codepoint >> 12) & 0x3F);
|
||||
result.chars8[0] = 0xF0 | ((codepoint >> 18) & 0x07);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Invalid codepoint */
|
||||
result.count8 = 1;
|
||||
result.chars8[0] = '?';
|
||||
}
|
||||
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -134,69 +138,69 @@ Utf8EncodeResult EncodeUtf8(u32 codepoint)
|
||||
|
||||
Utf16DecodeResult DecodeUtf16(String16 str)
|
||||
{
|
||||
Utf16DecodeResult result = Zi;
|
||||
u32 codepoint = U32Max;
|
||||
u32 advance = 0;
|
||||
Utf16DecodeResult result = Zi;
|
||||
u32 codepoint = U32Max;
|
||||
u32 advance = 0;
|
||||
|
||||
if (str.len >= 1)
|
||||
if (str.len >= 1)
|
||||
{
|
||||
u16 c0 = str.text[0];
|
||||
codepoint = c0;
|
||||
advance = 1;
|
||||
if (str.len >= 2)
|
||||
{
|
||||
u16 c0 = str.text[0];
|
||||
codepoint = c0;
|
||||
advance = 1;
|
||||
if (str.len >= 2)
|
||||
{
|
||||
u16 c1 = str.text[1];
|
||||
if ((0xD800 <= c0 && c0 < 0xDC00) && (0xDC00 <= c1 && c1 < 0xE000))
|
||||
{
|
||||
codepoint = (c1 & 0x3FF) << 0;
|
||||
codepoint |= (c0 & 0x3FF) << 10;
|
||||
advance = 2;
|
||||
}
|
||||
}
|
||||
u16 c1 = str.text[1];
|
||||
if ((0xD800 <= c0 && c0 < 0xDC00) && (0xDC00 <= c1 && c1 < 0xE000))
|
||||
{
|
||||
codepoint = (c1 & 0x3FF) << 0;
|
||||
codepoint |= (c0 & 0x3FF) << 10;
|
||||
advance = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result.advance16 = advance;
|
||||
result.codepoint = codepoint;
|
||||
return result;
|
||||
result.advance16 = advance;
|
||||
result.codepoint = codepoint;
|
||||
return result;
|
||||
}
|
||||
|
||||
//- Encode
|
||||
|
||||
Utf16EncodeResult EncodeUtf16(u32 codepoint)
|
||||
{
|
||||
Utf16EncodeResult result = Zi;
|
||||
Utf16EncodeResult result = Zi;
|
||||
|
||||
if (codepoint <= 0xFFFF)
|
||||
{
|
||||
result.count16 = 1;
|
||||
result.chars16[0] = codepoint;
|
||||
}
|
||||
else if (codepoint <= 0x10FFFF)
|
||||
{
|
||||
result.count16 = 2;
|
||||
result.chars16[1] = 0xDC00 | ((codepoint >> 0) & 0x3FF);
|
||||
result.chars16[0] = 0xD800 | ((codepoint >> 10) & 0x3FF);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Invalid codepoint */
|
||||
result.count16 = 1;
|
||||
result.chars16[0] = '?';
|
||||
}
|
||||
if (codepoint <= 0xFFFF)
|
||||
{
|
||||
result.count16 = 1;
|
||||
result.chars16[0] = codepoint;
|
||||
}
|
||||
else if (codepoint <= 0x10FFFF)
|
||||
{
|
||||
result.count16 = 2;
|
||||
result.chars16[1] = 0xDC00 | ((codepoint >> 0) & 0x3FF);
|
||||
result.chars16[0] = 0xD800 | ((codepoint >> 10) & 0x3FF);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Invalid codepoint */
|
||||
result.count16 = 1;
|
||||
result.chars16[0] = '?';
|
||||
}
|
||||
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
|
||||
//- Surrogate check
|
||||
|
||||
b32 IsUtf16HighSurrogate(u16 c)
|
||||
{
|
||||
return 0xD800 <= c && c < 0xDC00;
|
||||
return 0xD800 <= c && c < 0xDC00;
|
||||
}
|
||||
|
||||
b32 IsUtf16LowSurrogate(u16 c)
|
||||
{
|
||||
return 0xDC00 <= c && c < 0xE000;
|
||||
return 0xDC00 <= c && c < 0xE000;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -206,40 +210,40 @@ b32 IsUtf16LowSurrogate(u16 c)
|
||||
|
||||
Utf32DecodeResult DecodeUtf32(String32 str)
|
||||
{
|
||||
Utf32DecodeResult result = Zi;
|
||||
u32 codepoint = U32Max;
|
||||
u32 advance = 0;
|
||||
Utf32DecodeResult result = Zi;
|
||||
u32 codepoint = U32Max;
|
||||
u32 advance = 0;
|
||||
|
||||
if (str.len >= 1)
|
||||
if (str.len >= 1)
|
||||
{
|
||||
u32 c = str.text[0];
|
||||
advance = 1;
|
||||
if (c <= 0x10FFFF)
|
||||
{
|
||||
u32 c = str.text[0];
|
||||
advance = 1;
|
||||
if (c <= 0x10FFFF)
|
||||
{
|
||||
codepoint = c;
|
||||
}
|
||||
codepoint = c;
|
||||
}
|
||||
}
|
||||
|
||||
result.advance32 = advance;
|
||||
result.codepoint = codepoint;
|
||||
return result;
|
||||
result.advance32 = advance;
|
||||
result.codepoint = codepoint;
|
||||
return result;
|
||||
}
|
||||
|
||||
//- Encode
|
||||
|
||||
Utf32EncodeResult EncodeUtf32(u32 codepoint)
|
||||
{
|
||||
Utf32EncodeResult result = Zi;
|
||||
Utf32EncodeResult result = Zi;
|
||||
|
||||
if (codepoint <= 0x10FFFF)
|
||||
{
|
||||
result.chars32 = codepoint;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Invalid codepoint */
|
||||
result.chars32 = '?';
|
||||
}
|
||||
if (codepoint <= 0x10FFFF)
|
||||
{
|
||||
result.chars32 = codepoint;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Invalid codepoint */
|
||||
result.chars32 = '?';
|
||||
}
|
||||
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -3,14 +3,14 @@
|
||||
|
||||
Struct(Utf8DecodeResult)
|
||||
{
|
||||
u32 advance8;
|
||||
u32 codepoint;
|
||||
u32 advance8;
|
||||
u32 codepoint;
|
||||
};
|
||||
|
||||
Struct(Utf8EncodeResult)
|
||||
{
|
||||
u32 count8;
|
||||
u8 chars8[4];
|
||||
u32 count8;
|
||||
u8 chars8[4];
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -18,14 +18,14 @@ Struct(Utf8EncodeResult)
|
||||
|
||||
Struct(Utf16DecodeResult)
|
||||
{
|
||||
u32 advance16;
|
||||
u32 codepoint;
|
||||
u32 advance16;
|
||||
u32 codepoint;
|
||||
};
|
||||
|
||||
Struct(Utf16EncodeResult)
|
||||
{
|
||||
u32 count16;
|
||||
u16 chars16[2];
|
||||
u32 count16;
|
||||
u16 chars16[2];
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -33,13 +33,13 @@ Struct(Utf16EncodeResult)
|
||||
|
||||
Struct(Utf32DecodeResult)
|
||||
{
|
||||
u32 advance32;
|
||||
u32 codepoint;
|
||||
u32 advance32;
|
||||
u32 codepoint;
|
||||
};
|
||||
|
||||
Struct(Utf32EncodeResult)
|
||||
{
|
||||
u32 chars32;
|
||||
u32 chars32;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
@ -19,27 +19,27 @@ typedef MergesortCompareFuncDef(MergesortCompareFunc, a, b, udata);
|
||||
|
||||
Struct(DictEntry)
|
||||
{
|
||||
u64 hash;
|
||||
u64 value;
|
||||
DictEntry *prev_in_bin;
|
||||
DictEntry *next_in_bin;
|
||||
DictEntry *prev;
|
||||
DictEntry *next;
|
||||
u64 hash;
|
||||
u64 value;
|
||||
DictEntry *prev_in_bin;
|
||||
DictEntry *next_in_bin;
|
||||
DictEntry *prev;
|
||||
DictEntry *next;
|
||||
};
|
||||
|
||||
Struct(DictBin)
|
||||
{
|
||||
DictEntry *first;
|
||||
DictEntry *last;
|
||||
DictEntry *first;
|
||||
DictEntry *last;
|
||||
};
|
||||
|
||||
Struct(Dict)
|
||||
{
|
||||
u64 bins_count;
|
||||
DictBin *bins;
|
||||
DictEntry *first_free;
|
||||
DictEntry *first;
|
||||
DictEntry *last;
|
||||
u64 bins_count;
|
||||
DictBin *bins;
|
||||
DictEntry *first_free;
|
||||
DictEntry *first;
|
||||
DictEntry *last;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -50,31 +50,31 @@ Struct(Dict)
|
||||
*/
|
||||
Inline u64 HashFnv64(u64 seed, String s)
|
||||
{
|
||||
u64 hash = seed;
|
||||
for (u64 i = 0; i < s.len; ++i)
|
||||
{
|
||||
hash ^= (u8)s.text[i];
|
||||
hash *= 0x100000001B3;
|
||||
}
|
||||
return hash;
|
||||
u64 hash = seed;
|
||||
for (u64 i = 0; i < s.len; ++i)
|
||||
{
|
||||
hash ^= (u8)s.text[i];
|
||||
hash *= 0x100000001B3;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
#define HashF(fmt_cstr, ...) HashF_(StringFromCstrNoLimit(fmt_cstr), __VA_ARGS__, FmtEnd)
|
||||
Inline u64 HashF_(String fmt, ...)
|
||||
{
|
||||
u64 result = 0;
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
u64 result = 0;
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
{
|
||||
String str = FormatString(scratch.arena, fmt, FmtArgsFromVaList(scratch.arena, args));
|
||||
result = HashFnv64(Fnv64Basis, str);
|
||||
}
|
||||
va_end(args);
|
||||
String str = FormatString(scratch.arena, fmt, FmtArgsFromVaList(scratch.arena, args));
|
||||
result = HashFnv64(Fnv64Basis, str);
|
||||
}
|
||||
EndScratch(scratch);
|
||||
return result;
|
||||
va_end(args);
|
||||
}
|
||||
EndScratch(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -82,67 +82,67 @@ Inline u64 HashF_(String fmt, ...)
|
||||
|
||||
Inline void MergesortInternal(u8 *left, u8 *right, u8 *items, u64 left_count, u64 right_count, u64 item_size, MergesortCompareFunc *callback, void *udata)
|
||||
{
|
||||
/* Sort */
|
||||
u64 i = 0;
|
||||
u64 l = 0;
|
||||
u64 r = 0;
|
||||
while (l < left_count && r < right_count)
|
||||
/* Sort */
|
||||
u64 i = 0;
|
||||
u64 l = 0;
|
||||
u64 r = 0;
|
||||
while (l < left_count && r < right_count)
|
||||
{
|
||||
u8 *dst = items + (i * item_size);
|
||||
u8 *left_item = left + (l * item_size);
|
||||
u8 *right_item = right + (r * item_size);
|
||||
++i;
|
||||
if (callback(left_item, right_item, udata) > 0)
|
||||
{
|
||||
u8 *dst = items + (i * item_size);
|
||||
u8 *left_item = left + (l * item_size);
|
||||
u8 *right_item = right + (r * item_size);
|
||||
++i;
|
||||
if (callback(left_item, right_item, udata) > 0)
|
||||
{
|
||||
CopyBytes(dst, left_item, item_size);
|
||||
++l;
|
||||
}
|
||||
else
|
||||
{
|
||||
CopyBytes(dst, right_item, item_size);
|
||||
++r;
|
||||
}
|
||||
CopyBytes(dst, left_item, item_size);
|
||||
++l;
|
||||
}
|
||||
/* Copy remaining */
|
||||
if (l != left_count)
|
||||
else
|
||||
{
|
||||
u64 remaining_count = left_count - l;
|
||||
u64 remaining_bytes = remaining_count * item_size;
|
||||
u8 *dst = items + (i * item_size);
|
||||
u8 *src = left + (l * item_size);
|
||||
CopyBytes(dst, src, remaining_bytes);
|
||||
}
|
||||
else if (r != right_count)
|
||||
{
|
||||
u64 remaining_count = right_count - r;
|
||||
u64 remaining_bytes = remaining_count * item_size;
|
||||
u8 *dst = items + (i * item_size);
|
||||
u8 *src = right + (r * item_size);
|
||||
CopyBytes(dst, src, remaining_bytes);
|
||||
CopyBytes(dst, right_item, item_size);
|
||||
++r;
|
||||
}
|
||||
}
|
||||
/* Copy remaining */
|
||||
if (l != left_count)
|
||||
{
|
||||
u64 remaining_count = left_count - l;
|
||||
u64 remaining_bytes = remaining_count * item_size;
|
||||
u8 *dst = items + (i * item_size);
|
||||
u8 *src = left + (l * item_size);
|
||||
CopyBytes(dst, src, remaining_bytes);
|
||||
}
|
||||
else if (r != right_count)
|
||||
{
|
||||
u64 remaining_count = right_count - r;
|
||||
u64 remaining_bytes = remaining_count * item_size;
|
||||
u8 *dst = items + (i * item_size);
|
||||
u8 *src = right + (r * item_size);
|
||||
CopyBytes(dst, src, remaining_bytes);
|
||||
}
|
||||
}
|
||||
|
||||
Inline void Mergesort(void *items, u64 item_count, u64 item_size, MergesortCompareFunc *callback, void *udata)
|
||||
{
|
||||
if (item_count > 1)
|
||||
{
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
u64 left_count = item_count / 2;
|
||||
u64 right_count = item_count - left_count;
|
||||
if (item_count > 1)
|
||||
{
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
u64 left_count = item_count / 2;
|
||||
u64 right_count = item_count - left_count;
|
||||
|
||||
u64 left_size = left_count * item_size;
|
||||
u64 right_size = right_count * item_size;
|
||||
u64 left_size = left_count * item_size;
|
||||
u64 right_size = right_count * item_size;
|
||||
|
||||
u8 *left = PushStructsNoZero(scratch.arena, u8, left_size);
|
||||
u8 *right = PushStructsNoZero(scratch.arena, u8, right_size);
|
||||
CopyBytes(left, items, left_size);
|
||||
CopyBytes(right, (u8 *)items + left_size, right_size);
|
||||
u8 *left = PushStructsNoZero(scratch.arena, u8, left_size);
|
||||
u8 *right = PushStructsNoZero(scratch.arena, u8, right_size);
|
||||
CopyBytes(left, items, left_size);
|
||||
CopyBytes(right, (u8 *)items + left_size, right_size);
|
||||
|
||||
Mergesort(left, left_count, item_size, callback, udata);
|
||||
Mergesort(right, right_count, item_size, callback, udata);
|
||||
MergesortInternal(left, right, (u8 *)items, left_count, right_count, item_size, callback, udata);
|
||||
EndScratch(scratch);
|
||||
}
|
||||
Mergesort(left, left_count, item_size, callback, udata);
|
||||
Mergesort(right, right_count, item_size, callback, udata);
|
||||
MergesortInternal(left, right, (u8 *)items, left_count, right_count, item_size, callback, udata);
|
||||
EndScratch(scratch);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -152,164 +152,164 @@ Inline void Mergesort(void *items, u64 item_count, u64 item_size, MergesortCompa
|
||||
|
||||
Inline Dict *InitDict(Arena *arena, u64 bins_count)
|
||||
{
|
||||
Dict *dict = PushStruct(arena, Dict);
|
||||
dict->bins_count = MaxU64(bins_count, 1); /* Ensure at least 1 bin */
|
||||
dict->bins = PushStructs(arena, DictBin, dict->bins_count);
|
||||
return dict;
|
||||
Dict *dict = PushStruct(arena, Dict);
|
||||
dict->bins_count = MaxU64(bins_count, 1); /* Ensure at least 1 bin */
|
||||
dict->bins = PushStructs(arena, DictBin, dict->bins_count);
|
||||
return dict;
|
||||
}
|
||||
|
||||
Inline void ResetDict(Dict *dict)
|
||||
{
|
||||
ZeroBytes(dict->bins, sizeof(*dict->bins) * dict->bins_count);
|
||||
if (dict->first)
|
||||
{
|
||||
dict->last->next = dict->first_free;
|
||||
dict->first_free = dict->first;
|
||||
}
|
||||
ZeroBytes(dict->bins, sizeof(*dict->bins) * dict->bins_count);
|
||||
if (dict->first)
|
||||
{
|
||||
dict->last->next = dict->first_free;
|
||||
dict->first_free = dict->first;
|
||||
}
|
||||
}
|
||||
|
||||
//- Dict set
|
||||
|
||||
Inline DictEntry *EnsureDictEntry(Arena *arena, Dict *dict, u64 hash)
|
||||
{
|
||||
DictBin *bin = &dict->bins[hash % dict->bins_count];
|
||||
DictBin *bin = &dict->bins[hash % dict->bins_count];
|
||||
|
||||
DictEntry *entry = bin->first;
|
||||
while (entry)
|
||||
DictEntry *entry = bin->first;
|
||||
while (entry)
|
||||
{
|
||||
if (hash == entry->hash)
|
||||
{
|
||||
if (hash == entry->hash)
|
||||
{
|
||||
/* Existing match found */
|
||||
break;
|
||||
}
|
||||
entry = entry->next_in_bin;
|
||||
/* Existing match found */
|
||||
break;
|
||||
}
|
||||
entry = entry->next_in_bin;
|
||||
}
|
||||
|
||||
/* No match found, create new entry */
|
||||
if (!entry)
|
||||
/* No match found, create new entry */
|
||||
if (!entry)
|
||||
{
|
||||
if (dict->first_free)
|
||||
{
|
||||
if (dict->first_free)
|
||||
{
|
||||
entry = dict->first_free;
|
||||
dict->first_free = entry->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
entry = PushStructNoZero(arena, DictEntry);
|
||||
}
|
||||
ZeroStruct(entry);
|
||||
entry->hash = hash;
|
||||
if (bin->last)
|
||||
{
|
||||
bin->last->next_in_bin = entry;
|
||||
entry->prev_in_bin = bin->last;
|
||||
}
|
||||
else
|
||||
{
|
||||
bin->first = entry;
|
||||
}
|
||||
bin->last = entry;
|
||||
if (dict->last)
|
||||
{
|
||||
dict->last->next = entry;
|
||||
entry->prev = dict->last;
|
||||
}
|
||||
else
|
||||
{
|
||||
dict->first = entry;
|
||||
}
|
||||
dict->last = entry;
|
||||
entry = dict->first_free;
|
||||
dict->first_free = entry->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
entry = PushStructNoZero(arena, DictEntry);
|
||||
}
|
||||
ZeroStruct(entry);
|
||||
entry->hash = hash;
|
||||
if (bin->last)
|
||||
{
|
||||
bin->last->next_in_bin = entry;
|
||||
entry->prev_in_bin = bin->last;
|
||||
}
|
||||
else
|
||||
{
|
||||
bin->first = entry;
|
||||
}
|
||||
bin->last = entry;
|
||||
if (dict->last)
|
||||
{
|
||||
dict->last->next = entry;
|
||||
entry->prev = dict->last;
|
||||
}
|
||||
else
|
||||
{
|
||||
dict->first = entry;
|
||||
}
|
||||
dict->last = entry;
|
||||
}
|
||||
|
||||
return entry;
|
||||
return entry;
|
||||
}
|
||||
|
||||
Inline void SetDictValue(Arena *arena, Dict *dict, u64 hash, u64 value)
|
||||
{
|
||||
DictEntry *entry = EnsureDictEntry(arena, dict, hash);
|
||||
entry->value = value;
|
||||
DictEntry *entry = EnsureDictEntry(arena, dict, hash);
|
||||
entry->value = value;
|
||||
}
|
||||
|
||||
//- Dict remove
|
||||
|
||||
Inline void RemoveDictEntry(Dict *dict, DictEntry *entry)
|
||||
{
|
||||
/* Remove from bin */
|
||||
/* Remove from bin */
|
||||
{
|
||||
DictBin *bin = &dict->bins[entry->hash % dict->bins_count];
|
||||
DictEntry *prev_in_bin = entry->prev_in_bin;
|
||||
DictEntry *next_in_bin = entry->next_in_bin;
|
||||
if (prev_in_bin)
|
||||
{
|
||||
DictBin *bin = &dict->bins[entry->hash % dict->bins_count];
|
||||
DictEntry *prev_in_bin = entry->prev_in_bin;
|
||||
DictEntry *next_in_bin = entry->next_in_bin;
|
||||
if (prev_in_bin)
|
||||
{
|
||||
prev_in_bin->next_in_bin = next_in_bin;
|
||||
}
|
||||
else
|
||||
{
|
||||
bin->first = next_in_bin;
|
||||
}
|
||||
if (next_in_bin)
|
||||
{
|
||||
next_in_bin->prev_in_bin = prev_in_bin;
|
||||
}
|
||||
else
|
||||
{
|
||||
bin->last = prev_in_bin;
|
||||
}
|
||||
prev_in_bin->next_in_bin = next_in_bin;
|
||||
}
|
||||
/* Remove from list */
|
||||
else
|
||||
{
|
||||
DictEntry *prev = entry->prev;
|
||||
DictEntry *next = entry->next;
|
||||
if (prev)
|
||||
{
|
||||
prev->next = next;
|
||||
}
|
||||
else
|
||||
{
|
||||
dict->first = next;
|
||||
}
|
||||
if (next)
|
||||
{
|
||||
next->prev = prev;
|
||||
}
|
||||
else
|
||||
{
|
||||
dict->last = prev;
|
||||
}
|
||||
bin->first = next_in_bin;
|
||||
}
|
||||
/* Insert into free list */
|
||||
if (next_in_bin)
|
||||
{
|
||||
entry->next = dict->first_free;
|
||||
dict->first_free = entry;
|
||||
next_in_bin->prev_in_bin = prev_in_bin;
|
||||
}
|
||||
else
|
||||
{
|
||||
bin->last = prev_in_bin;
|
||||
}
|
||||
}
|
||||
/* Remove from list */
|
||||
{
|
||||
DictEntry *prev = entry->prev;
|
||||
DictEntry *next = entry->next;
|
||||
if (prev)
|
||||
{
|
||||
prev->next = next;
|
||||
}
|
||||
else
|
||||
{
|
||||
dict->first = next;
|
||||
}
|
||||
if (next)
|
||||
{
|
||||
next->prev = prev;
|
||||
}
|
||||
else
|
||||
{
|
||||
dict->last = prev;
|
||||
}
|
||||
}
|
||||
/* Insert into free list */
|
||||
{
|
||||
entry->next = dict->first_free;
|
||||
dict->first_free = entry;
|
||||
}
|
||||
}
|
||||
|
||||
//- Dict index
|
||||
|
||||
Inline DictEntry *DictEntryFromHash(Dict *dict, u64 hash)
|
||||
{
|
||||
DictEntry *result = 0;
|
||||
DictBin *bin = &dict->bins[hash % dict->bins_count];
|
||||
for (DictEntry *entry = bin->first; entry; entry = entry->next_in_bin)
|
||||
DictEntry *result = 0;
|
||||
DictBin *bin = &dict->bins[hash % dict->bins_count];
|
||||
for (DictEntry *entry = bin->first; entry; entry = entry->next_in_bin)
|
||||
{
|
||||
if (hash == entry->hash)
|
||||
{
|
||||
if (hash == entry->hash)
|
||||
{
|
||||
/* Match found */
|
||||
result = entry;
|
||||
break;
|
||||
}
|
||||
/* Match found */
|
||||
result = entry;
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Inline u64 DictValueFromHash(Dict *dict, u64 hash)
|
||||
{
|
||||
DictEntry *entry = DictEntryFromHash(dict, hash);
|
||||
return entry ? entry->value : 0;
|
||||
DictEntry *entry = DictEntryFromHash(dict, hash);
|
||||
return entry ? entry->value : 0;
|
||||
}
|
||||
|
||||
Inline u64 DictValueOrNilFromHash(Dict *dict, u64 hash, u64 nil)
|
||||
{
|
||||
DictEntry *entry = DictEntryFromHash(dict, hash);
|
||||
return entry ? entry->value : nil;
|
||||
DictEntry *entry = DictEntryFromHash(dict, hash);
|
||||
return entry ? entry->value : nil;
|
||||
}
|
||||
|
||||
@ -3,108 +3,108 @@
|
||||
|
||||
void WaveSyncEx(WaveLaneCtx *lane, u64 spin_count)
|
||||
{
|
||||
WaveCtx *wave = lane->wave;
|
||||
i32 lanes_count = wave->lanes_count;
|
||||
if (lanes_count > 1)
|
||||
WaveCtx *wave = lane->wave;
|
||||
i32 lanes_count = wave->lanes_count;
|
||||
if (lanes_count > 1)
|
||||
{
|
||||
i64 sync_gen = Atomic64Fetch(&wave->sync_gen.v);
|
||||
i32 blocked_count = Atomic32FetchAdd(&wave->sync_count.v, 1) + 1;
|
||||
if (blocked_count == lanes_count)
|
||||
{
|
||||
i64 sync_gen = Atomic64Fetch(&wave->sync_gen.v);
|
||||
i32 blocked_count = Atomic32FetchAdd(&wave->sync_count.v, 1) + 1;
|
||||
if (blocked_count == lanes_count)
|
||||
Atomic32Set(&wave->sync_count.v, 0);
|
||||
Atomic64Set(&wave->sync_gen.v, sync_gen + 1);
|
||||
FutexWakeNeq(&wave->sync_gen.v);
|
||||
}
|
||||
else
|
||||
{
|
||||
u64 remaining_spins = spin_count;
|
||||
while (Atomic64Fetch(&wave->sync_gen.v) == sync_gen)
|
||||
{
|
||||
if (remaining_spins > 0)
|
||||
{
|
||||
Atomic32Set(&wave->sync_count.v, 0);
|
||||
Atomic64Set(&wave->sync_gen.v, sync_gen + 1);
|
||||
FutexWakeNeq(&wave->sync_gen.v);
|
||||
--remaining_spins;
|
||||
_mm_pause();
|
||||
}
|
||||
else
|
||||
{
|
||||
u64 remaining_spins = spin_count;
|
||||
while (Atomic64Fetch(&wave->sync_gen.v) == sync_gen)
|
||||
{
|
||||
if (remaining_spins > 0)
|
||||
{
|
||||
--remaining_spins;
|
||||
_mm_pause();
|
||||
}
|
||||
else
|
||||
{
|
||||
FutexYieldNeq(&wave->sync_gen.v, &sync_gen, sizeof(sync_gen));
|
||||
}
|
||||
}
|
||||
FutexYieldNeq(&wave->sync_gen.v, &sync_gen, sizeof(sync_gen));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WaveSyncBroadcastEx_(WaveLaneCtx *lane, u32 broadcast_lane_idx, void *broadcast_ptr, u64 broadcast_size, u64 spin_count)
|
||||
{
|
||||
WaveCtx *wave = lane->wave;
|
||||
i32 lanes_count = wave->lanes_count;
|
||||
if (lanes_count > 1)
|
||||
WaveCtx *wave = lane->wave;
|
||||
i32 lanes_count = wave->lanes_count;
|
||||
if (lanes_count > 1)
|
||||
{
|
||||
u32 lane_idx = lane->idx;
|
||||
|
||||
if (lane_idx == broadcast_lane_idx)
|
||||
{
|
||||
u32 lane_idx = lane->idx;
|
||||
/* Broadcast */
|
||||
wave->broadcast_data = broadcast_ptr;
|
||||
i64 ack_gen = Atomic64Fetch(&wave->ack_gen.v);
|
||||
lane->seen_broadcast_gen = Atomic64FetchAdd(&wave->broadcast_gen.v, 1) + 1;
|
||||
FutexWakeNeq(&wave->broadcast_gen.v);
|
||||
|
||||
if (lane_idx == broadcast_lane_idx)
|
||||
/* Wait for ack */
|
||||
{
|
||||
u64 remaining_spins = spin_count;
|
||||
while (Atomic64Fetch(&wave->ack_gen.v) == ack_gen)
|
||||
{
|
||||
/* Broadcast */
|
||||
wave->broadcast_data = broadcast_ptr;
|
||||
i64 ack_gen = Atomic64Fetch(&wave->ack_gen.v);
|
||||
lane->seen_broadcast_gen = Atomic64FetchAdd(&wave->broadcast_gen.v, 1) + 1;
|
||||
FutexWakeNeq(&wave->broadcast_gen.v);
|
||||
|
||||
/* Wait for ack */
|
||||
{
|
||||
u64 remaining_spins = spin_count;
|
||||
while (Atomic64Fetch(&wave->ack_gen.v) == ack_gen)
|
||||
{
|
||||
if (remaining_spins > 0)
|
||||
{
|
||||
--remaining_spins;
|
||||
_mm_pause();
|
||||
}
|
||||
else
|
||||
{
|
||||
FutexYieldNeq(&wave->ack_gen.v, &ack_gen, sizeof(ack_gen));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Wait for broadcast */
|
||||
i64 seen_broadcast_gen = lane->seen_broadcast_gen++;
|
||||
{
|
||||
u64 remaining_spins = spin_count;
|
||||
while (Atomic64Fetch(&wave->broadcast_gen.v) == seen_broadcast_gen)
|
||||
{
|
||||
if (remaining_spins > 0)
|
||||
{
|
||||
--remaining_spins;
|
||||
_mm_pause();
|
||||
}
|
||||
else
|
||||
{
|
||||
FutexYieldNeq(&wave->broadcast_gen.v, &seen_broadcast_gen, sizeof(seen_broadcast_gen));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy broadcast data */
|
||||
CopyBytes(broadcast_ptr, wave->broadcast_data, broadcast_size);
|
||||
|
||||
/* Ack */
|
||||
i32 ack_count = Atomic32FetchAdd(&wave->ack_count.v, 1) + 1;
|
||||
if (ack_count == lanes_count - 1)
|
||||
{
|
||||
Atomic32Set(&wave->ack_count.v, 0);
|
||||
Atomic64FetchAdd(&wave->ack_gen.v, 1);
|
||||
FutexWakeNeq(&wave->ack_gen.v);
|
||||
}
|
||||
if (remaining_spins > 0)
|
||||
{
|
||||
--remaining_spins;
|
||||
_mm_pause();
|
||||
}
|
||||
else
|
||||
{
|
||||
FutexYieldNeq(&wave->ack_gen.v, &ack_gen, sizeof(ack_gen));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Wait for broadcast */
|
||||
i64 seen_broadcast_gen = lane->seen_broadcast_gen++;
|
||||
{
|
||||
u64 remaining_spins = spin_count;
|
||||
while (Atomic64Fetch(&wave->broadcast_gen.v) == seen_broadcast_gen)
|
||||
{
|
||||
if (remaining_spins > 0)
|
||||
{
|
||||
--remaining_spins;
|
||||
_mm_pause();
|
||||
}
|
||||
else
|
||||
{
|
||||
FutexYieldNeq(&wave->broadcast_gen.v, &seen_broadcast_gen, sizeof(seen_broadcast_gen));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy broadcast data */
|
||||
CopyBytes(broadcast_ptr, wave->broadcast_data, broadcast_size);
|
||||
|
||||
/* Ack */
|
||||
i32 ack_count = Atomic32FetchAdd(&wave->ack_count.v, 1) + 1;
|
||||
if (ack_count == lanes_count - 1)
|
||||
{
|
||||
Atomic32Set(&wave->ack_count.v, 0);
|
||||
Atomic64FetchAdd(&wave->ack_gen.v, 1);
|
||||
FutexWakeNeq(&wave->ack_gen.v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SetWaveLaneDefaultSpin(WaveLaneCtx *lane, u64 n)
|
||||
{
|
||||
lane->default_spin_count = n;
|
||||
lane->default_spin_count = n;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -112,30 +112,30 @@ void SetWaveLaneDefaultSpin(WaveLaneCtx *lane, u64 n)
|
||||
|
||||
i32 WaveLaneIdxFromTaskIdx(WaveLaneCtx *lane, u64 task_idx)
|
||||
{
|
||||
WaveCtx *wave = lane->wave;
|
||||
return task_idx % wave->lanes_count;
|
||||
WaveCtx *wave = lane->wave;
|
||||
return task_idx % wave->lanes_count;
|
||||
}
|
||||
|
||||
RngU64 WaveIdxRangeFromCount(WaveLaneCtx *lane, u64 tasks_count)
|
||||
{
|
||||
u64 lanes_count = lane->wave->lanes_count;
|
||||
u64 lane_idx = lane->idx;
|
||||
u64 lanes_count = lane->wave->lanes_count;
|
||||
u64 lane_idx = lane->idx;
|
||||
|
||||
u64 tasks_per_lane = tasks_count / lanes_count;
|
||||
u64 tasks_overflow = tasks_count % lanes_count;
|
||||
u64 tasks_per_lane = tasks_count / lanes_count;
|
||||
u64 tasks_overflow = tasks_count % lanes_count;
|
||||
|
||||
u64 start = lane_idx * tasks_per_lane;
|
||||
u64 end = start + tasks_per_lane;
|
||||
if (lane_idx < tasks_overflow)
|
||||
{
|
||||
start += lane_idx;
|
||||
end += lane_idx + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
start += tasks_overflow;
|
||||
end += tasks_overflow;
|
||||
}
|
||||
u64 start = lane_idx * tasks_per_lane;
|
||||
u64 end = start + tasks_per_lane;
|
||||
if (lane_idx < tasks_overflow)
|
||||
{
|
||||
start += lane_idx;
|
||||
end += lane_idx + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
start += tasks_overflow;
|
||||
end += tasks_overflow;
|
||||
}
|
||||
|
||||
return RNGU64(start, end);
|
||||
return RNGU64(start, end);
|
||||
}
|
||||
|
||||
@ -6,26 +6,26 @@
|
||||
|
||||
AlignedStruct(WaveCtx, CachelineSize)
|
||||
{
|
||||
i32 lanes_count;
|
||||
void *udata;
|
||||
i32 lanes_count;
|
||||
void *udata;
|
||||
|
||||
/* Sync barrier */
|
||||
Atomic32Padded sync_count;
|
||||
Atomic64Padded sync_gen;
|
||||
/* Sync barrier */
|
||||
Atomic32Padded sync_count;
|
||||
Atomic64Padded sync_gen;
|
||||
|
||||
/* Broadcast barrier */
|
||||
void *broadcast_data;
|
||||
Atomic64Padded broadcast_gen;
|
||||
Atomic32Padded ack_count;
|
||||
Atomic64Padded ack_gen;
|
||||
/* Broadcast barrier */
|
||||
void *broadcast_data;
|
||||
Atomic64Padded broadcast_gen;
|
||||
Atomic32Padded ack_count;
|
||||
Atomic64Padded ack_gen;
|
||||
};
|
||||
|
||||
AlignedStruct(WaveLaneCtx, CachelineSize)
|
||||
{
|
||||
i32 idx;
|
||||
WaveCtx *wave;
|
||||
u64 default_spin_count;
|
||||
i64 seen_broadcast_gen;
|
||||
i32 idx;
|
||||
WaveCtx *wave;
|
||||
u64 default_spin_count;
|
||||
i64 seen_broadcast_gen;
|
||||
};
|
||||
|
||||
typedef void WaveLaneEntryFunc(WaveLaneCtx *lane);
|
||||
@ -34,14 +34,16 @@ typedef void WaveLaneEntryFunc(WaveLaneCtx *lane);
|
||||
//~ Wave sync ops
|
||||
|
||||
void WaveSyncEx(WaveLaneCtx *lane, u64 spin_count);
|
||||
#define WaveSync(lane) \
|
||||
WaveSyncEx((lane), (lane)->default_spin_count)
|
||||
|
||||
void WaveSyncBroadcastEx_(WaveLaneCtx *lane, u32 broadcast_lane_idx, void *broadcast_ptr, u64 broadcast_size, u64 spin_count);
|
||||
|
||||
#define WaveSync(lane) \
|
||||
WaveSyncEx((lane), (lane)->default_spin_count)
|
||||
|
||||
#define WaveSyncBroadcastEx(lane, broadcast_lane_idx, broadcast_ptr, spin_count) \
|
||||
WaveSyncBroadcastEx_((lane), (broadcast_lane_idx), (broadcast_ptr), sizeof(*(broadcast_ptr)), (spin_count))
|
||||
WaveSyncBroadcastEx_((lane), (broadcast_lane_idx), (broadcast_ptr), sizeof(*(broadcast_ptr)), (spin_count))
|
||||
|
||||
#define WaveSyncBroadcast(lane, broadcast_lane_idx, broadcast_ptr) \
|
||||
WaveSyncBroadcastEx_((lane), (broadcast_lane_idx), (broadcast_ptr), sizeof(*(broadcast_ptr)), (lane)->default_spin_count)
|
||||
WaveSyncBroadcastEx_((lane), (broadcast_lane_idx), (broadcast_ptr), sizeof(*(broadcast_ptr)), (lane)->default_spin_count)
|
||||
|
||||
void SetWaveLaneDefaultSpin(WaveLaneCtx *lane, u64 n);
|
||||
|
||||
|
||||
@ -5,34 +5,34 @@ W32_Ctx W32 = Zi;
|
||||
|
||||
BOOL W32_FindEmbeddedRcData(HMODULE module, LPCWSTR type, LPWSTR wstr_entry_name, LONG_PTR udata)
|
||||
{
|
||||
W32_FindEmbeddedDataCtx *ctx = (W32_FindEmbeddedDataCtx *)udata;
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
String entry_name = StringFromWstrNoLimit(scratch.arena, (LPWSTR)wstr_entry_name);
|
||||
String embedded_data_prefix = Lit(Stringize(W32_EmbeddedDataPrefix));
|
||||
if (StringBeginsWith(entry_name, embedded_data_prefix))
|
||||
W32_FindEmbeddedDataCtx *ctx = (W32_FindEmbeddedDataCtx *)udata;
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
String entry_name = StringFromWstrNoLimit(scratch.arena, (LPWSTR)wstr_entry_name);
|
||||
String embedded_data_prefix = Lit(Stringize(W32_EmbeddedDataPrefix));
|
||||
if (StringBeginsWith(entry_name, embedded_data_prefix))
|
||||
{
|
||||
HRSRC hres = FindResourceW(module, wstr_entry_name, type);
|
||||
if (hres)
|
||||
{
|
||||
HRSRC hres = FindResourceW(module, wstr_entry_name, type);
|
||||
if (hres)
|
||||
HGLOBAL hg = LoadResource(module, hres);
|
||||
if (hg)
|
||||
{
|
||||
if (ctx->embedded_strings_count < countof(ctx->embedded_strings))
|
||||
{
|
||||
HGLOBAL hg = LoadResource(module, hres);
|
||||
if (hg)
|
||||
{
|
||||
if (ctx->embedded_strings_count < countof(ctx->embedded_strings))
|
||||
{
|
||||
String embedded = Zi;
|
||||
embedded.len = SizeofResource(module, hres);
|
||||
embedded.text = LockResource(hg);
|
||||
ctx->embedded_strings[ctx->embedded_strings_count++] = embedded;
|
||||
}
|
||||
else
|
||||
{
|
||||
Panic(Lit("Maximum number of embedded resource entries exceeded"));
|
||||
}
|
||||
}
|
||||
String embedded = Zi;
|
||||
embedded.len = SizeofResource(module, hres);
|
||||
embedded.text = LockResource(hg);
|
||||
ctx->embedded_strings[ctx->embedded_strings_count++] = embedded;
|
||||
}
|
||||
else
|
||||
{
|
||||
Panic(Lit("Maximum number of embedded resource entries exceeded"));
|
||||
}
|
||||
}
|
||||
}
|
||||
EndScratch(scratch);
|
||||
return 1;
|
||||
}
|
||||
EndScratch(scratch);
|
||||
return 1;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -40,141 +40,141 @@ BOOL W32_FindEmbeddedRcData(HMODULE module, LPCWSTR type, LPWSTR wstr_entry_name
|
||||
|
||||
StringList GetRawCommandline(void)
|
||||
{
|
||||
return W32.raw_command_line;
|
||||
return W32.raw_command_line;
|
||||
}
|
||||
|
||||
void Echo(String msg)
|
||||
{
|
||||
HANDLE console_handle = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
if (console_handle && console_handle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
WriteFile(console_handle, msg.text, msg.len, 0, 0);
|
||||
}
|
||||
else if (IsRunningInDebugger())
|
||||
{
|
||||
char msg_cstr[16384];
|
||||
u64 len = MinU64(countof(msg_cstr) - 1, msg.len);
|
||||
CopyBytes(msg_cstr, msg.text, len);
|
||||
msg_cstr[len] = 0;
|
||||
OutputDebugStringA(msg_cstr);
|
||||
}
|
||||
HANDLE console_handle = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
if (console_handle && console_handle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
WriteFile(console_handle, msg.text, msg.len, 0, 0);
|
||||
}
|
||||
else if (IsRunningInDebugger())
|
||||
{
|
||||
char msg_cstr[16384];
|
||||
u64 len = MinU64(countof(msg_cstr) - 1, msg.len);
|
||||
CopyBytes(msg_cstr, msg.text, len);
|
||||
msg_cstr[len] = 0;
|
||||
OutputDebugStringA(msg_cstr);
|
||||
}
|
||||
}
|
||||
|
||||
b32 Panic(String msg)
|
||||
{
|
||||
LogPanic(msg);
|
||||
char msg_cstr[4096];
|
||||
CstrFromStringToBuff(StringFromFixedArray(msg_cstr), msg);
|
||||
{
|
||||
u32 mb_flags = MB_SETFOREGROUND | MB_ICONERROR;
|
||||
MessageBoxExA(0, msg_cstr, "Fatal error", mb_flags, 0);
|
||||
}
|
||||
HANDLE console_handle = GetStdHandle(STD_ERROR_HANDLE);
|
||||
if (console_handle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
WriteFile(console_handle, msg.text, msg.len, 0, 0);
|
||||
}
|
||||
if (IsRunningInDebugger())
|
||||
{
|
||||
Assert(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
ExitProcess(1);
|
||||
}
|
||||
return 0;
|
||||
LogPanic(msg);
|
||||
char msg_cstr[4096];
|
||||
CstrFromStringToBuff(StringFromFixedArray(msg_cstr), msg);
|
||||
{
|
||||
u32 mb_flags = MB_SETFOREGROUND | MB_ICONERROR;
|
||||
MessageBoxExA(0, msg_cstr, "Fatal error", mb_flags, 0);
|
||||
}
|
||||
HANDLE console_handle = GetStdHandle(STD_ERROR_HANDLE);
|
||||
if (console_handle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
WriteFile(console_handle, msg.text, msg.len, 0, 0);
|
||||
}
|
||||
if (IsRunningInDebugger())
|
||||
{
|
||||
Assert(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
ExitProcess(1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
b32 IsRunningInDebugger(void)
|
||||
{
|
||||
return IsDebuggerPresent();
|
||||
return IsDebuggerPresent();
|
||||
}
|
||||
|
||||
i64 TimeNs(void)
|
||||
{
|
||||
LARGE_INTEGER qpc;
|
||||
QueryPerformanceCounter(&qpc);
|
||||
i64 result = (qpc.QuadPart - W32.timer_start_qpc) * W32.ns_per_qpc;
|
||||
return result;
|
||||
LARGE_INTEGER qpc;
|
||||
QueryPerformanceCounter(&qpc);
|
||||
i64 result = (qpc.QuadPart - W32.timer_start_qpc) * W32.ns_per_qpc;
|
||||
return result;
|
||||
}
|
||||
|
||||
void TrueRand(String buffer)
|
||||
{
|
||||
BCryptGenRandom(BCRYPT_RNG_ALG_HANDLE, (u8 *)buffer.text, buffer.len, 0);
|
||||
BCryptGenRandom(BCRYPT_RNG_ALG_HANDLE, (u8 *)buffer.text, buffer.len, 0);
|
||||
}
|
||||
|
||||
CpuTopologyInfo GetCpuTopologyInfo(void)
|
||||
{
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
CpuTopologyInfo res = Zi;
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
CpuTopologyInfo res = Zi;
|
||||
{
|
||||
DWORD infos_buff_size = 0;
|
||||
u8 *infos_buff = 0;
|
||||
b32 ok = 0;
|
||||
{
|
||||
DWORD infos_buff_size = 0;
|
||||
u8 *infos_buff = 0;
|
||||
b32 ok = 0;
|
||||
{
|
||||
GetLogicalProcessorInformationEx(RelationProcessorCore, 0, &infos_buff_size);
|
||||
infos_buff = PushStructsNoZero(scratch.arena, u8, infos_buff_size);
|
||||
ok = GetLogicalProcessorInformationEx(RelationProcessorCore, (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)infos_buff, &infos_buff_size);
|
||||
}
|
||||
if (ok)
|
||||
{
|
||||
/* Determine max efficiency class */
|
||||
i32 max_efficiency_class = 0;
|
||||
{
|
||||
DWORD pos = 0;
|
||||
while (pos < infos_buff_size)
|
||||
{
|
||||
SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *info = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)&infos_buff[pos];
|
||||
max_efficiency_class = MaxI32(max_efficiency_class, info->Processor.EfficiencyClass);
|
||||
pos += info->Size;
|
||||
}
|
||||
}
|
||||
/* Generate physical core info */
|
||||
{
|
||||
DWORD pos = 0;
|
||||
while (pos < infos_buff_size)
|
||||
{
|
||||
SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *info = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)&infos_buff[pos];
|
||||
++res.num_physical_cores;
|
||||
++res.num_logical_cores;
|
||||
if (info->Processor.Flags & LTP_PC_SMT)
|
||||
{
|
||||
/* Core has SMT sibling */
|
||||
++res.num_logical_cores;
|
||||
}
|
||||
if (info->Processor.EfficiencyClass == max_efficiency_class)
|
||||
{
|
||||
/* Core is P-core */
|
||||
++res.num_physical_performance_cores;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Core is not a P-core */
|
||||
++res.num_physical_non_performance_cores;
|
||||
}
|
||||
pos += info->Size;
|
||||
}
|
||||
}
|
||||
}
|
||||
GetLogicalProcessorInformationEx(RelationProcessorCore, 0, &infos_buff_size);
|
||||
infos_buff = PushStructsNoZero(scratch.arena, u8, infos_buff_size);
|
||||
ok = GetLogicalProcessorInformationEx(RelationProcessorCore, (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)infos_buff, &infos_buff_size);
|
||||
}
|
||||
res.num_logical_cores = MaxI32(res.num_logical_cores, 1);
|
||||
res.num_physical_cores = MaxI32(res.num_physical_cores, 1);
|
||||
res.num_physical_performance_cores = MaxI32(res.num_physical_performance_cores, 1);
|
||||
EndScratch(scratch);
|
||||
return res;
|
||||
if (ok)
|
||||
{
|
||||
/* Determine max efficiency class */
|
||||
i32 max_efficiency_class = 0;
|
||||
{
|
||||
DWORD pos = 0;
|
||||
while (pos < infos_buff_size)
|
||||
{
|
||||
SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *info = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)&infos_buff[pos];
|
||||
max_efficiency_class = MaxI32(max_efficiency_class, info->Processor.EfficiencyClass);
|
||||
pos += info->Size;
|
||||
}
|
||||
}
|
||||
/* Generate physical core info */
|
||||
{
|
||||
DWORD pos = 0;
|
||||
while (pos < infos_buff_size)
|
||||
{
|
||||
SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *info = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)&infos_buff[pos];
|
||||
++res.num_physical_cores;
|
||||
++res.num_logical_cores;
|
||||
if (info->Processor.Flags & LTP_PC_SMT)
|
||||
{
|
||||
/* Core has SMT sibling */
|
||||
++res.num_logical_cores;
|
||||
}
|
||||
if (info->Processor.EfficiencyClass == max_efficiency_class)
|
||||
{
|
||||
/* Core is P-core */
|
||||
++res.num_physical_performance_cores;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Core is not a P-core */
|
||||
++res.num_physical_non_performance_cores;
|
||||
}
|
||||
pos += info->Size;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
res.num_logical_cores = MaxI32(res.num_logical_cores, 1);
|
||||
res.num_physical_cores = MaxI32(res.num_physical_cores, 1);
|
||||
res.num_physical_performance_cores = MaxI32(res.num_physical_performance_cores, 1);
|
||||
EndScratch(scratch);
|
||||
return res;
|
||||
}
|
||||
|
||||
void SleepSeconds(f64 seconds)
|
||||
{
|
||||
f64 ms = seconds * 1000.0;
|
||||
if (ms > 4000000000)
|
||||
{
|
||||
Sleep(INFINITE);
|
||||
}
|
||||
else
|
||||
{
|
||||
Sleep((u32)ms);
|
||||
}
|
||||
f64 ms = seconds * 1000.0;
|
||||
if (ms > 4000000000)
|
||||
{
|
||||
Sleep(INFINITE);
|
||||
}
|
||||
else
|
||||
{
|
||||
Sleep((u32)ms);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -182,60 +182,60 @@ void SleepSeconds(f64 seconds)
|
||||
|
||||
b32 IsSwappedIn(void)
|
||||
{
|
||||
return IsHotSwappingEnabled;
|
||||
return IsHotSwappingEnabled;
|
||||
}
|
||||
|
||||
b32 IsSwappingOut(void)
|
||||
{
|
||||
return IsHotSwappingEnabled;
|
||||
return IsHotSwappingEnabled;
|
||||
}
|
||||
|
||||
String SwappedStateFromName(Arena *arena, String name)
|
||||
{
|
||||
TempArena scratch = BeginScratch(arena);
|
||||
String result = Zi;
|
||||
String path = StringF(scratch.arena, "ppswap/%F.swp", FmtString(name));
|
||||
wchar_t *path_wstr = WstrFromString(scratch.arena, path);
|
||||
HANDLE handle = CreateFileW(path_wstr, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
|
||||
if (handle != INVALID_HANDLE_VALUE)
|
||||
TempArena scratch = BeginScratch(arena);
|
||||
String result = Zi;
|
||||
String path = StringF(scratch.arena, "ppswap/%F.swp", FmtString(name));
|
||||
wchar_t *path_wstr = WstrFromString(scratch.arena, path);
|
||||
HANDLE handle = CreateFileW(path_wstr, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
|
||||
if (handle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
u32 chunk_size = Kibi(64);
|
||||
result.text = ArenaNext(arena, u8);
|
||||
for (;;)
|
||||
{
|
||||
u32 chunk_size = Kibi(64);
|
||||
result.text = ArenaNext(arena, u8);
|
||||
for (;;)
|
||||
{
|
||||
u8 *chunk = PushStructsNoZero(arena, u8, chunk_size);
|
||||
u32 chunk_bytes_read = 0;
|
||||
ReadFile(handle, chunk, chunk_size, (LPDWORD)&chunk_bytes_read, 0);
|
||||
result.len += chunk_bytes_read;
|
||||
if (chunk_bytes_read < chunk_size)
|
||||
{
|
||||
PopStructsNoCopy(arena, u8, chunk_size - chunk_bytes_read);
|
||||
break;
|
||||
}
|
||||
}
|
||||
u8 *chunk = PushStructsNoZero(arena, u8, chunk_size);
|
||||
u32 chunk_bytes_read = 0;
|
||||
ReadFile(handle, chunk, chunk_size, (LPDWORD)&chunk_bytes_read, 0);
|
||||
result.len += chunk_bytes_read;
|
||||
if (chunk_bytes_read < chunk_size)
|
||||
{
|
||||
PopStructsNoCopy(arena, u8, chunk_size - chunk_bytes_read);
|
||||
break;
|
||||
}
|
||||
}
|
||||
CloseHandle(handle);
|
||||
EndScratch(scratch);
|
||||
return result;
|
||||
}
|
||||
CloseHandle(handle);
|
||||
EndScratch(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
void WriteSwappedState(String name, String data)
|
||||
{
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
/* TODO: Use directory non-relative to executable */
|
||||
CreateDirectoryW(L"ppswap", 0);
|
||||
String result = Zi;
|
||||
String path = StringF(scratch.arena, "ppswap/%F.swp", FmtString(name));
|
||||
wchar_t *path_wstr = WstrFromString(scratch.arena, path);
|
||||
HANDLE handle = CreateFileW(path_wstr, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
|
||||
if (handle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
SetFilePointer(handle, 0, 0, FILE_BEGIN);
|
||||
SetEndOfFile(handle);
|
||||
WriteFile(handle, data.text, data.len, 0, 0);
|
||||
}
|
||||
CloseHandle(handle);
|
||||
EndScratch(scratch);
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
/* TODO: Use directory non-relative to executable */
|
||||
CreateDirectoryW(L"ppswap", 0);
|
||||
String result = Zi;
|
||||
String path = StringF(scratch.arena, "ppswap/%F.swp", FmtString(name));
|
||||
wchar_t *path_wstr = WstrFromString(scratch.arena, path);
|
||||
HANDLE handle = CreateFileW(path_wstr, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
|
||||
if (handle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
SetFilePointer(handle, 0, 0, FILE_BEGIN);
|
||||
SetEndOfFile(handle);
|
||||
WriteFile(handle, data.text, data.len, 0, 0);
|
||||
}
|
||||
CloseHandle(handle);
|
||||
EndScratch(scratch);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -243,23 +243,23 @@ void WriteSwappedState(String name, String data)
|
||||
|
||||
void OnExit(ExitFunc *func)
|
||||
{
|
||||
i32 index = Atomic32FetchAdd(&W32.num_exit_funcs, 1);
|
||||
if (index >= countof(W32.exit_funcs))
|
||||
{
|
||||
Panic(Lit("Maximum on exit functions registered"));
|
||||
}
|
||||
W32.exit_funcs[index] = func;
|
||||
i32 index = Atomic32FetchAdd(&W32.num_exit_funcs, 1);
|
||||
if (index >= countof(W32.exit_funcs))
|
||||
{
|
||||
Panic(Lit("Maximum on exit functions registered"));
|
||||
}
|
||||
W32.exit_funcs[index] = func;
|
||||
}
|
||||
|
||||
void SignalExit(i32 code)
|
||||
{
|
||||
Atomic32Set(&W32.exit_code, code);
|
||||
SetEvent(W32.exit_event);
|
||||
Atomic32Set(&W32.exit_code, code);
|
||||
SetEvent(W32.exit_event);
|
||||
}
|
||||
|
||||
void ExitNow(i32 code)
|
||||
{
|
||||
ExitProcess(code);
|
||||
ExitProcess(code);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -267,88 +267,88 @@ void ExitNow(i32 code)
|
||||
|
||||
void W32_BootstrapLogs(String logfile_path)
|
||||
{
|
||||
W32.logs_arena = AcquireArena(Gibi(64));
|
||||
W32.log_msgs_arena = AcquireArena(Gibi(64));
|
||||
W32.readable_log_events = ArenaNext(W32.logs_arena, LogEvent);
|
||||
if (logfile_path.len > 0)
|
||||
W32.logs_arena = AcquireArena(Gibi(64));
|
||||
W32.log_msgs_arena = AcquireArena(Gibi(64));
|
||||
W32.readable_log_events = ArenaNext(W32.logs_arena, LogEvent);
|
||||
if (logfile_path.len > 0)
|
||||
{
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
{
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
{
|
||||
wchar_t *path_wstr = WstrFromString(scratch.arena, logfile_path);
|
||||
W32.logfile = CreateFileW(
|
||||
path_wstr,
|
||||
FILE_APPEND_DATA,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
0,
|
||||
CREATE_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
0
|
||||
);
|
||||
}
|
||||
EndScratch(scratch);
|
||||
wchar_t *path_wstr = WstrFromString(scratch.arena, logfile_path);
|
||||
W32.logfile = CreateFileW(
|
||||
path_wstr,
|
||||
FILE_APPEND_DATA,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
0,
|
||||
CREATE_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
0
|
||||
);
|
||||
}
|
||||
Atomic32Set(&W32.logs_initialized, 1);
|
||||
EndScratch(scratch);
|
||||
}
|
||||
Atomic32Set(&W32.logs_initialized, 1);
|
||||
}
|
||||
|
||||
void W32_Log(i32 level, String msg)
|
||||
{
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
if (Atomic32Fetch(&W32.logs_initialized))
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
if (Atomic32Fetch(&W32.logs_initialized))
|
||||
{
|
||||
LogLevelSettings settings = log_settings[level];
|
||||
if (level < 0 || level >= LogLevel_Count)
|
||||
{
|
||||
LogLevelSettings settings = log_settings[level];
|
||||
if (level < 0 || level >= LogLevel_Count)
|
||||
{
|
||||
Panic(Lit("Invalid log level"));
|
||||
}
|
||||
|
||||
DateTime datetime = LocalDateTime();
|
||||
i64 now_ns = TimeNs();
|
||||
i32 thread_id = GetCurrentThreadId();
|
||||
|
||||
//- Log message to file
|
||||
/* TODO: Log asynchronously */
|
||||
{
|
||||
String shorthand = settings.shorthand;
|
||||
String msg_formatted = StringF(
|
||||
scratch.arena,
|
||||
"[%F:%F:%F.%F] <%F> [%F] %F\n",
|
||||
|
||||
/* Time */
|
||||
FmtUint(datetime.hour, .z = 2),
|
||||
FmtUint(datetime.minute, .z = 2),
|
||||
FmtUint(datetime.second, .z = 2),
|
||||
FmtUint(datetime.milliseconds, .z = 3),
|
||||
|
||||
/* Thread id */
|
||||
FmtUint(thread_id, .z = 5),
|
||||
|
||||
/* Level */
|
||||
FmtString(shorthand),
|
||||
|
||||
/* Message */
|
||||
FmtString(msg)
|
||||
);
|
||||
WriteFile(W32.logfile, msg_formatted.text, msg_formatted.len, 0, 0);
|
||||
}
|
||||
|
||||
//- Log message to queue
|
||||
/* TODO: Log asynchronously */
|
||||
LockTicketMutex(&W32.logs_tm);
|
||||
{
|
||||
/* Get staged data */
|
||||
LogEvent *ev = PushStruct(W32.logs_arena, LogEvent);
|
||||
ev->msg = PushString(W32.log_msgs_arena, msg);
|
||||
ev->datetime = datetime;
|
||||
ev->time_ns = now_ns;
|
||||
ev->level = level;
|
||||
ev->thread_id = thread_id;
|
||||
ev->id = W32.logs_count++;
|
||||
ev->level_id = W32.log_level_counts[level]++;
|
||||
Atomic64Set(&W32.readable_logs_count, W32.logs_count);
|
||||
}
|
||||
UnlockTicketMutex(&W32.logs_tm);
|
||||
Panic(Lit("Invalid log level"));
|
||||
}
|
||||
EndScratch(scratch);
|
||||
|
||||
DateTime datetime = LocalDateTime();
|
||||
i64 now_ns = TimeNs();
|
||||
i32 thread_id = GetCurrentThreadId();
|
||||
|
||||
//- Log message to file
|
||||
/* TODO: Log asynchronously */
|
||||
{
|
||||
String shorthand = settings.shorthand;
|
||||
String msg_formatted = StringF(
|
||||
scratch.arena,
|
||||
"[%F:%F:%F.%F] <%F> [%F] %F\n",
|
||||
|
||||
/* Time */
|
||||
FmtUint(datetime.hour, .z = 2),
|
||||
FmtUint(datetime.minute, .z = 2),
|
||||
FmtUint(datetime.second, .z = 2),
|
||||
FmtUint(datetime.milliseconds, .z = 3),
|
||||
|
||||
/* Thread id */
|
||||
FmtUint(thread_id, .z = 5),
|
||||
|
||||
/* Level */
|
||||
FmtString(shorthand),
|
||||
|
||||
/* Message */
|
||||
FmtString(msg)
|
||||
);
|
||||
WriteFile(W32.logfile, msg_formatted.text, msg_formatted.len, 0, 0);
|
||||
}
|
||||
|
||||
//- Log message to queue
|
||||
/* TODO: Log asynchronously */
|
||||
LockTicketMutex(&W32.logs_tm);
|
||||
{
|
||||
/* Get staged data */
|
||||
LogEvent *ev = PushStruct(W32.logs_arena, LogEvent);
|
||||
ev->msg = PushString(W32.log_msgs_arena, msg);
|
||||
ev->datetime = datetime;
|
||||
ev->time_ns = now_ns;
|
||||
ev->level = level;
|
||||
ev->thread_id = thread_id;
|
||||
ev->id = W32.logs_count++;
|
||||
ev->level_id = W32.log_level_counts[level]++;
|
||||
Atomic64Set(&W32.readable_logs_count, W32.logs_count);
|
||||
}
|
||||
UnlockTicketMutex(&W32.logs_tm);
|
||||
}
|
||||
EndScratch(scratch);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -358,46 +358,46 @@ void W32_Log(i32 level, String msg)
|
||||
* immediately writing to log file. */
|
||||
void LogPanic(String msg)
|
||||
{
|
||||
if (Atomic32Fetch(&W32.logs_initialized))
|
||||
{
|
||||
String beg = Lit("******** PANICKING ********\n");
|
||||
String end = Lit("\n***************************\n");
|
||||
WriteFile(W32.logfile, beg.text, beg.len, 0, 0);
|
||||
WriteFile(W32.logfile, msg.text, msg.len, 0, 0);
|
||||
WriteFile(W32.logfile, end.text, end.len, 0, 0);
|
||||
}
|
||||
if (Atomic32Fetch(&W32.logs_initialized))
|
||||
{
|
||||
String beg = Lit("******** PANICKING ********\n");
|
||||
String end = Lit("\n***************************\n");
|
||||
WriteFile(W32.logfile, beg.text, beg.len, 0, 0);
|
||||
WriteFile(W32.logfile, msg.text, msg.len, 0, 0);
|
||||
WriteFile(W32.logfile, end.text, end.len, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void Log_(i32 level, String msg)
|
||||
{
|
||||
W32_Log(level, msg);
|
||||
W32_Log(level, msg);
|
||||
}
|
||||
|
||||
void LogF_(i32 level, String fmt, ...)
|
||||
{
|
||||
if (Atomic32Fetch(&W32.logs_initialized))
|
||||
if (Atomic32Fetch(&W32.logs_initialized))
|
||||
{
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
{
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
{
|
||||
String msg = FormatString(scratch.arena, fmt, FmtArgsFromVaList(scratch.arena, args));
|
||||
W32_Log(level, msg);
|
||||
}
|
||||
va_end(args);
|
||||
EndScratch(scratch);
|
||||
String msg = FormatString(scratch.arena, fmt, FmtArgsFromVaList(scratch.arena, args));
|
||||
W32_Log(level, msg);
|
||||
}
|
||||
va_end(args);
|
||||
EndScratch(scratch);
|
||||
}
|
||||
}
|
||||
|
||||
LogEventsArray GetLogEvents(void)
|
||||
{
|
||||
LogEventsArray result = Zi;
|
||||
result.count = Atomic64Fetch(&W32.readable_logs_count);
|
||||
if (result.count > 0)
|
||||
{
|
||||
result.logs = W32.readable_log_events;
|
||||
}
|
||||
return result;
|
||||
LogEventsArray result = Zi;
|
||||
result.count = Atomic64Fetch(&W32.readable_logs_count);
|
||||
if (result.count > 0)
|
||||
{
|
||||
result.logs = W32.readable_log_events;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -405,150 +405,148 @@ LogEventsArray GetLogEvents(void)
|
||||
|
||||
i32 W32_Main(void)
|
||||
{
|
||||
/* Init time */
|
||||
/* Init time */
|
||||
{
|
||||
LARGE_INTEGER qpf;
|
||||
QueryPerformanceFrequency(&qpf);
|
||||
W32.ns_per_qpc = 1000000000 / qpf.QuadPart;
|
||||
}
|
||||
{
|
||||
LARGE_INTEGER qpc;
|
||||
QueryPerformanceCounter(&qpc);
|
||||
W32.timer_start_qpc = qpc.QuadPart;
|
||||
}
|
||||
|
||||
/* Setup events */
|
||||
W32.panic_event = CreateEventW(0, 1, 0, 0);
|
||||
W32.exit_event = CreateEventW(0, 1, 0, 0);
|
||||
|
||||
W32.main_thread_id = GetCurrentThreadId();
|
||||
SetThreadDescription(GetCurrentThread(), L"Main thread");
|
||||
|
||||
/* Query system info */
|
||||
GetSystemInfo(&W32.info);
|
||||
|
||||
/* Init main thread */
|
||||
W32_InitCurrentThread(Lit("Main"));
|
||||
|
||||
/* Get raw args from command line */
|
||||
{
|
||||
Arena *perm = PermArena();
|
||||
StringList args_list = Zi;
|
||||
{
|
||||
LARGE_INTEGER qpf;
|
||||
QueryPerformanceFrequency(&qpf);
|
||||
W32.ns_per_qpc = 1000000000 / qpf.QuadPart;
|
||||
LPCWSTR cmdline_wstr = GetCommandLineW();
|
||||
i32 argc = 0;
|
||||
LPWSTR *argv = CommandLineToArgvW(cmdline_wstr, &argc);
|
||||
for (i32 i = 0; i < argc; ++i)
|
||||
{
|
||||
wchar_t *arg_wstr = argv[i];
|
||||
String arg = StringFromWstrNoLimit(perm, arg_wstr);
|
||||
PushStringToList(perm, &args_list, arg);
|
||||
}
|
||||
}
|
||||
W32.raw_command_line = args_list;
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- Bootstrap
|
||||
|
||||
/* Bootstrap command line */
|
||||
BootstrapCmdline();
|
||||
|
||||
/* Bootstrap log system */
|
||||
/* FIXME: Remove hardcoded log path */
|
||||
W32_BootstrapLogs(Lit("log.log"));
|
||||
LogInfoF("Main thread ID: %F", FmtUint(ThreadId()));
|
||||
|
||||
/* Bootstrap resource system */
|
||||
{
|
||||
W32_FindEmbeddedDataCtx ctx = Zi;
|
||||
EnumResourceNamesW(0, RT_RCDATA, &W32_FindEmbeddedRcData, (LONG_PTR)&ctx);
|
||||
BootstrapResources(ctx.embedded_strings_count, ctx.embedded_strings);
|
||||
}
|
||||
|
||||
/* Bootstrap async */
|
||||
BootstrapAsync();
|
||||
|
||||
/* Bootstrap layers */
|
||||
if (!Atomic32Fetch(&W32.panicking))
|
||||
{
|
||||
BootstrapLayers();
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- Wait for exit signal
|
||||
|
||||
/* Wait for exit start or panic */
|
||||
if (!Atomic32Fetch(&W32.panicking))
|
||||
{
|
||||
HANDLE handles[] = {
|
||||
W32.exit_event,
|
||||
W32.panic_event,
|
||||
};
|
||||
DWORD wake = WaitForMultipleObjects(countof(handles), handles, 0, INFINITE);
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- Shutdown
|
||||
|
||||
/* Run exit callbacks */
|
||||
if (!Atomic32Fetch(&W32.panicking))
|
||||
{
|
||||
i32 num_funcs = Atomic32Fetch(&W32.num_exit_funcs);
|
||||
for (i32 idx = num_funcs - 1; idx >= 0; --idx)
|
||||
{
|
||||
LARGE_INTEGER qpc;
|
||||
QueryPerformanceCounter(&qpc);
|
||||
W32.timer_start_qpc = qpc.QuadPart;
|
||||
ExitFunc *func = W32.exit_funcs[idx];
|
||||
func();
|
||||
}
|
||||
}
|
||||
|
||||
/* Setup events */
|
||||
W32.panic_event = CreateEventW(0, 1, 0, 0);
|
||||
W32.exit_event = CreateEventW(0, 1, 0, 0);
|
||||
|
||||
W32.main_thread_id = GetCurrentThreadId();
|
||||
SetThreadDescription(GetCurrentThread(), L"Main thread");
|
||||
|
||||
/* Query system info */
|
||||
GetSystemInfo(&W32.info);
|
||||
|
||||
/* Init main thread */
|
||||
W32_InitCurrentThread(Lit("Main"));
|
||||
|
||||
/* Get raw args from command line */
|
||||
{
|
||||
Arena *perm = PermArena();
|
||||
StringList args_list = Zi;
|
||||
{
|
||||
LPCWSTR cmdline_wstr = GetCommandLineW();
|
||||
i32 argc = 0;
|
||||
LPWSTR *argv = CommandLineToArgvW(cmdline_wstr, &argc);
|
||||
for (i32 i = 0; i < argc; ++i)
|
||||
{
|
||||
wchar_t *arg_wstr = argv[i];
|
||||
String arg = StringFromWstrNoLimit(perm, arg_wstr);
|
||||
PushStringToList(perm, &args_list, arg);
|
||||
}
|
||||
}
|
||||
W32.raw_command_line = args_list;
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- Bootstrap
|
||||
|
||||
/* Bootstrap command line */
|
||||
BootstrapCmdline();
|
||||
|
||||
/* Bootstrap log system */
|
||||
/* FIXME: Remove hardcoded log path */
|
||||
W32_BootstrapLogs(Lit("log.log"));
|
||||
LogInfoF("Main thread ID: %F", FmtUint(ThreadId()));
|
||||
|
||||
/* Bootstrap resource system */
|
||||
{
|
||||
W32_FindEmbeddedDataCtx ctx = Zi;
|
||||
EnumResourceNamesW(0, RT_RCDATA, &W32_FindEmbeddedRcData, (LONG_PTR)&ctx);
|
||||
BootstrapResources(ctx.embedded_strings_count, ctx.embedded_strings);
|
||||
}
|
||||
|
||||
/* Bootstrap async */
|
||||
BootstrapAsync();
|
||||
|
||||
/* Bootstrap layers */
|
||||
if (!Atomic32Fetch(&W32.panicking))
|
||||
{
|
||||
BootstrapLayers();
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- Wait for exit signal
|
||||
|
||||
/* Wait for exit start or panic */
|
||||
if (!Atomic32Fetch(&W32.panicking))
|
||||
{
|
||||
HANDLE handles[] = {
|
||||
W32.exit_event,
|
||||
W32.panic_event,
|
||||
};
|
||||
DWORD wake = WaitForMultipleObjects(countof(handles), handles, 0, INFINITE);
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- Shutdown
|
||||
|
||||
/* Run exit callbacks */
|
||||
if (!Atomic32Fetch(&W32.panicking))
|
||||
{
|
||||
i32 num_funcs = Atomic32Fetch(&W32.num_exit_funcs);
|
||||
for (i32 idx = num_funcs - 1; idx >= 0; --idx)
|
||||
{
|
||||
ExitFunc *func = W32.exit_funcs[idx];
|
||||
func();
|
||||
}
|
||||
}
|
||||
|
||||
/* Exit */
|
||||
if (Atomic32Fetch(&W32.panicking))
|
||||
{
|
||||
WaitForSingleObject(W32.panic_event, INFINITE);
|
||||
MessageBoxExW(0, W32.panic_wstr, L"Fatal error", MB_ICONSTOP | MB_SETFOREGROUND | MB_TOPMOST, 0);
|
||||
Atomic32FetchTestSet(&W32.exit_code, 0, 1);
|
||||
}
|
||||
return Atomic32Fetch(&W32.exit_code);
|
||||
/* Exit */
|
||||
if (Atomic32Fetch(&W32.panicking))
|
||||
{
|
||||
WaitForSingleObject(W32.panic_event, INFINITE);
|
||||
MessageBoxExW(0, W32.panic_wstr, L"Fatal error", MB_ICONSTOP | MB_SETFOREGROUND | MB_TOPMOST, 0);
|
||||
Atomic32FetchTestSet(&W32.exit_code, 0, 1);
|
||||
}
|
||||
return Atomic32Fetch(&W32.exit_code);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Crt main
|
||||
|
||||
#if IsCrtlibEnabled
|
||||
# if IsConsoleApp
|
||||
int main(char **argc, int argv)
|
||||
{
|
||||
return W32_Main();
|
||||
}
|
||||
# else
|
||||
int CALLBACK wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance, _In_ LPWSTR cmdline_wstr, _In_ int show_code)
|
||||
{
|
||||
return W32_Main();
|
||||
}
|
||||
# endif /* IsConsoleApp */
|
||||
#if IsConsoleApp
|
||||
int main(char **argc, int argv)
|
||||
{
|
||||
return W32_Main();
|
||||
}
|
||||
#else
|
||||
int CALLBACK wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance, _In_ LPWSTR cmdline_wstr, _In_ int show_code)
|
||||
{
|
||||
return W32_Main();
|
||||
}
|
||||
#endif /* IsConsoleApp */
|
||||
#endif /* IsCrtlibEnabled */
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Crt stub
|
||||
|
||||
#if !IsCrtlibEnabled
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wmissing-variable-declarations"
|
||||
#pragma clang diagnostic ignored "-Wmissing-prototypes"
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wmissing-variable-declarations"
|
||||
#pragma clang diagnostic ignored "-Wmissing-prototypes"
|
||||
/* Enable floating point */
|
||||
__attribute((used))
|
||||
int _fltused;
|
||||
|
||||
/* Enable floating point */
|
||||
__attribute((used))
|
||||
int _fltused;
|
||||
|
||||
__attribute((used))
|
||||
void __stdcall wWinMainCRTStartup(void)
|
||||
{
|
||||
__attribute((used))
|
||||
void __stdcall wWinMainCRTStartup(void)
|
||||
{
|
||||
i32 result = W32_Main();
|
||||
ExitProcess(result);
|
||||
}
|
||||
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
|
||||
#pragma clang diagnostic pop
|
||||
#endif /* !IsCrtlibEnabled */
|
||||
|
||||
@ -7,28 +7,28 @@
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define UNICODE
|
||||
#pragma warning(push, 0)
|
||||
#include <Windows.h>
|
||||
#include <combaseapi.h>
|
||||
#include <dcommon.h>
|
||||
#include <initguid.h>
|
||||
#include <unknwn.h>
|
||||
#include <objbase.h>
|
||||
#include <uuids.h>
|
||||
#include <Knownfolders.h>
|
||||
#include <WinSock2.h>
|
||||
#include <TlHelp32.h>
|
||||
#include <WS2tcpip.h>
|
||||
#include <windowsx.h>
|
||||
#include <ShlObj_core.h>
|
||||
#include <fileapi.h>
|
||||
#include <dwmapi.h>
|
||||
#include <avrt.h>
|
||||
#include <shellapi.h>
|
||||
#include <Windows.h>
|
||||
#include <combaseapi.h>
|
||||
#include <dcommon.h>
|
||||
#include <initguid.h>
|
||||
#include <unknwn.h>
|
||||
#include <objbase.h>
|
||||
#include <uuids.h>
|
||||
#include <Knownfolders.h>
|
||||
#include <WinSock2.h>
|
||||
#include <TlHelp32.h>
|
||||
#include <WS2tcpip.h>
|
||||
#include <windowsx.h>
|
||||
#include <ShlObj_core.h>
|
||||
#include <fileapi.h>
|
||||
#include <dwmapi.h>
|
||||
#include <avrt.h>
|
||||
#include <shellapi.h>
|
||||
#pragma warning(pop)
|
||||
|
||||
#ifndef BCRYPT_RNG_ALG_HANDLE
|
||||
#define BCRYPT_RNG_ALG_HANDLE ((void *)0x00000081)
|
||||
u32 BCryptGenRandom(void *algorithm, u8 *buffer, u32 buffer_size, u32 flags);
|
||||
#define BCRYPT_RNG_ALG_HANDLE ((void *)0x00000081)
|
||||
u32 BCryptGenRandom(void *algorithm, u8 *buffer, u32 buffer_size, u32 flags);
|
||||
#endif
|
||||
|
||||
//- Windows libs
|
||||
@ -49,8 +49,8 @@ u32 BCryptGenRandom(void *algorithm, u8 *buffer, u32 buffer_size, u32 flags);
|
||||
|
||||
Struct(W32_FindEmbeddedDataCtx)
|
||||
{
|
||||
u64 embedded_strings_count;
|
||||
String embedded_strings[64];
|
||||
u64 embedded_strings_count;
|
||||
String embedded_strings[64];
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -58,41 +58,41 @@ Struct(W32_FindEmbeddedDataCtx)
|
||||
|
||||
Struct(W32_Ctx)
|
||||
{
|
||||
SYSTEM_INFO info;
|
||||
u32 main_thread_id;
|
||||
Atomic32 shutdown;
|
||||
Atomic32 exit_code;
|
||||
SYSTEM_INFO info;
|
||||
u32 main_thread_id;
|
||||
Atomic32 shutdown;
|
||||
Atomic32 exit_code;
|
||||
|
||||
i64 timer_start_qpc;
|
||||
i64 ns_per_qpc;
|
||||
i64 timer_start_qpc;
|
||||
i64 ns_per_qpc;
|
||||
|
||||
StringList raw_command_line;
|
||||
StringList raw_command_line;
|
||||
|
||||
//- Application control flow
|
||||
//- Application control flow
|
||||
|
||||
Atomic32 panicking;
|
||||
wchar_t panic_wstr[4096];
|
||||
HANDLE panic_event;
|
||||
HANDLE exit_event;
|
||||
Atomic32 panicking;
|
||||
wchar_t panic_wstr[4096];
|
||||
HANDLE panic_event;
|
||||
HANDLE exit_event;
|
||||
|
||||
//- Exit funcs
|
||||
//- Exit funcs
|
||||
|
||||
Atomic32 num_exit_funcs;
|
||||
ExitFunc *exit_funcs[4096];
|
||||
Atomic32 num_exit_funcs;
|
||||
ExitFunc *exit_funcs[4096];
|
||||
|
||||
//- Logs
|
||||
//- Logs
|
||||
|
||||
HANDLE logfile;
|
||||
Atomic32 logs_initialized;
|
||||
HANDLE logfile;
|
||||
Atomic32 logs_initialized;
|
||||
|
||||
TicketMutex logs_tm;
|
||||
Arena *log_msgs_arena;
|
||||
Arena *logs_arena;
|
||||
TicketMutex logs_tm;
|
||||
Arena *log_msgs_arena;
|
||||
Arena *logs_arena;
|
||||
|
||||
u64 logs_count;
|
||||
u64 log_level_counts[LogLevel_Count];
|
||||
LogEvent *readable_log_events;
|
||||
Atomic64 readable_logs_count;
|
||||
u64 logs_count;
|
||||
u64 log_level_counts[LogLevel_Count];
|
||||
LogEvent *readable_log_events;
|
||||
Atomic64 readable_logs_count;
|
||||
};
|
||||
|
||||
extern W32_Ctx W32;
|
||||
|
||||
@ -3,12 +3,12 @@
|
||||
|
||||
void FutexYieldNeq(volatile void *addr, void *cmp, u8 cmp_size)
|
||||
{
|
||||
WaitOnAddress(addr, cmp, cmp_size, INFINITE);
|
||||
WaitOnAddress(addr, cmp, cmp_size, INFINITE);
|
||||
}
|
||||
|
||||
void FutexWakeNeq(void *addr)
|
||||
{
|
||||
WakeByAddressAll(addr);
|
||||
WakeByAddressAll(addr);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -16,12 +16,12 @@ void FutexWakeNeq(void *addr)
|
||||
|
||||
void FutexYieldGte(volatile void *addr, void *cmp, u8 cmp_size)
|
||||
{
|
||||
/* TODO: Actually implement this. Just emulating via neq for now. */
|
||||
FutexYieldNeq(addr, cmp, cmp_size);
|
||||
/* TODO: Actually implement this. Just emulating via neq for now. */
|
||||
FutexYieldNeq(addr, cmp, cmp_size);
|
||||
}
|
||||
|
||||
void FutexWakeGte(void *addr)
|
||||
{
|
||||
/* TODO: Actually implement this. Just emulating via neq for now. */
|
||||
FutexWakeNeq(addr);
|
||||
/* TODO: Actually implement this. Just emulating via neq for now. */
|
||||
FutexWakeNeq(addr);
|
||||
}
|
||||
|
||||
@ -5,38 +5,38 @@
|
||||
|
||||
void *ReserveMemory(u64 size)
|
||||
{
|
||||
void *ptr = VirtualAlloc(0, size, MEM_RESERVE, PAGE_NOACCESS);
|
||||
return ptr;
|
||||
void *ptr = VirtualAlloc(0, size, MEM_RESERVE, PAGE_NOACCESS);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void ReleaseMemory(void *address)
|
||||
{
|
||||
VirtualFree(address, 0, MEM_RELEASE);
|
||||
VirtualFree(address, 0, MEM_RELEASE);
|
||||
}
|
||||
|
||||
//- Commit
|
||||
|
||||
void *CommitMemory(void *address, u64 size)
|
||||
{
|
||||
void *ptr = VirtualAlloc(address, size, MEM_COMMIT, PAGE_READWRITE);
|
||||
return ptr;
|
||||
void *ptr = VirtualAlloc(address, size, MEM_COMMIT, PAGE_READWRITE);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void DecommitMemory(void *address, u64 size)
|
||||
{
|
||||
VirtualFree(address, size, MEM_DECOMMIT);
|
||||
VirtualFree(address, size, MEM_DECOMMIT);
|
||||
}
|
||||
|
||||
//- Protect
|
||||
|
||||
void SetMemoryReadonly(void *address, u64 size)
|
||||
{
|
||||
DWORD old;
|
||||
VirtualProtect(address, size, PAGE_READONLY, &old);
|
||||
DWORD old;
|
||||
VirtualProtect(address, size, PAGE_READONLY, &old);
|
||||
}
|
||||
|
||||
void SetMemoryReadWrite(void *address, u64 size)
|
||||
{
|
||||
DWORD old;
|
||||
VirtualProtect(address, size, PAGE_READWRITE, &old);
|
||||
DWORD old;
|
||||
VirtualProtect(address, size, PAGE_READWRITE, &old);
|
||||
}
|
||||
|
||||
@ -3,18 +3,18 @@
|
||||
|
||||
DateTime LocalDateTime(void)
|
||||
{
|
||||
DateTime result = Zi;
|
||||
{
|
||||
SYSTEMTIME lt;
|
||||
GetLocalTime(<);
|
||||
result.year = lt.wYear;
|
||||
result.month = lt.wMonth;
|
||||
result.day_of_week = lt.wDayOfWeek;
|
||||
result.day = lt.wDay;
|
||||
result.hour = lt.wHour;
|
||||
result.minute = lt.wMinute;
|
||||
result.second = lt.wSecond;
|
||||
result.milliseconds = lt.wMilliseconds;
|
||||
}
|
||||
return result;
|
||||
DateTime result = Zi;
|
||||
{
|
||||
SYSTEMTIME lt;
|
||||
GetLocalTime(<);
|
||||
result.year = lt.wYear;
|
||||
result.month = lt.wMonth;
|
||||
result.day_of_week = lt.wDayOfWeek;
|
||||
result.day = lt.wDay;
|
||||
result.hour = lt.wHour;
|
||||
result.minute = lt.wMinute;
|
||||
result.second = lt.wSecond;
|
||||
result.milliseconds = lt.wMilliseconds;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -3,31 +3,31 @@
|
||||
|
||||
void W32_InitCurrentThread(String name)
|
||||
{
|
||||
/* Init thread arenas */
|
||||
/* Init thread arenas */
|
||||
{
|
||||
Base_tl.arenas.perm = AcquireArena(Gibi(64));
|
||||
for (i32 i = 0; i < (i32)countof(Base_tl.arenas.scratch); ++i)
|
||||
{
|
||||
Base_tl.arenas.perm = AcquireArena(Gibi(64));
|
||||
for (i32 i = 0; i < (i32)countof(Base_tl.arenas.scratch); ++i)
|
||||
{
|
||||
Base_tl.arenas.scratch[i] = AcquireArena(Gibi(64));
|
||||
}
|
||||
Base_tl.arenas.scratch[i] = AcquireArena(Gibi(64));
|
||||
}
|
||||
Arena *perm = PermArena();
|
||||
}
|
||||
Arena *perm = PermArena();
|
||||
|
||||
/* Set thread name */
|
||||
wchar_t *thread_name_wstr = WstrFromString(perm, name);
|
||||
SetThreadDescription(GetCurrentThread(), thread_name_wstr);
|
||||
/* Set thread name */
|
||||
wchar_t *thread_name_wstr = WstrFromString(perm, name);
|
||||
SetThreadDescription(GetCurrentThread(), thread_name_wstr);
|
||||
|
||||
/* Initialize COM */
|
||||
CoInitializeEx(0, COINIT_MULTITHREADED);
|
||||
/* Initialize COM */
|
||||
CoInitializeEx(0, COINIT_MULTITHREADED);
|
||||
}
|
||||
|
||||
DWORD WINAPI W32_ThreadProc(LPVOID thread_args_vp)
|
||||
{
|
||||
W32_ThreadArgs *thread_args = (W32_ThreadArgs *)thread_args_vp;
|
||||
W32_InitCurrentThread(thread_args->name);
|
||||
LogInfoF("New thread \"%F\" created with ID %F", FmtString(thread_args->name), FmtUint(ThreadId()));
|
||||
thread_args->entry(thread_args->lane);
|
||||
return 0;
|
||||
W32_ThreadArgs *thread_args = (W32_ThreadArgs *)thread_args_vp;
|
||||
W32_InitCurrentThread(thread_args->name);
|
||||
LogInfoF("New thread \"%F\" created with ID %F", FmtString(thread_args->name), FmtUint(ThreadId()));
|
||||
thread_args->entry(thread_args->lane);
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -35,58 +35,58 @@ DWORD WINAPI W32_ThreadProc(LPVOID thread_args_vp)
|
||||
|
||||
void DispatchWave(String name, u32 num_lanes, WaveLaneEntryFunc *entry, void *udata)
|
||||
{
|
||||
Arena *perm = PermArena();
|
||||
PERSIST Atomic64 num_threads_allocated = Zi;
|
||||
Arena *perm = PermArena();
|
||||
PERSIST Atomic64 num_threads_allocated = Zi;
|
||||
|
||||
/* Catch high lane count to prevent OS crash */
|
||||
i64 old_num_threads_allocated = Atomic64FetchAdd(&num_threads_allocated, num_lanes);
|
||||
i64 new_num_threads_allocated = old_num_threads_allocated + num_lanes;
|
||||
if (new_num_threads_allocated > MaxThreads)
|
||||
/* Catch high lane count to prevent OS crash */
|
||||
i64 old_num_threads_allocated = Atomic64FetchAdd(&num_threads_allocated, num_lanes);
|
||||
i64 new_num_threads_allocated = old_num_threads_allocated + num_lanes;
|
||||
if (new_num_threads_allocated > MaxThreads)
|
||||
{
|
||||
if (old_num_threads_allocated < MaxThreads)
|
||||
{
|
||||
if (old_num_threads_allocated < MaxThreads)
|
||||
{
|
||||
Panic(StringF(perm, "Maximum number of threads reached (%F)", FmtUint(MaxThreads)));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Sleep until panic */
|
||||
Sleep(INFINITE);
|
||||
}
|
||||
Panic(StringF(perm, "Maximum number of threads reached (%F)", FmtUint(MaxThreads)));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Sleep until panic */
|
||||
Sleep(INFINITE);
|
||||
}
|
||||
}
|
||||
|
||||
WaveCtx *wave_ctx = PushStruct(perm, WaveCtx);
|
||||
wave_ctx->lanes_count = num_lanes;
|
||||
wave_ctx->udata = udata;
|
||||
|
||||
for (u32 lane_idx = 0; lane_idx < num_lanes; ++lane_idx)
|
||||
{
|
||||
WaveLaneCtx *lane_ctx = PushStruct(perm, WaveLaneCtx);
|
||||
lane_ctx->idx = lane_idx;
|
||||
lane_ctx->wave = wave_ctx;
|
||||
lane_ctx->default_spin_count = DefaultWaveLaneSpinCount;
|
||||
|
||||
String thread_name = Zi;
|
||||
if (num_lanes > 1)
|
||||
{
|
||||
thread_name = StringF(perm, "%F:%F", FmtString(name), FmtUint(lane_idx));
|
||||
}
|
||||
else
|
||||
{
|
||||
thread_name = PushString(perm, name);
|
||||
}
|
||||
|
||||
WaveCtx *wave_ctx = PushStruct(perm, WaveCtx);
|
||||
wave_ctx->lanes_count = num_lanes;
|
||||
wave_ctx->udata = udata;
|
||||
W32_ThreadArgs *thread_args = PushStruct(perm, W32_ThreadArgs);
|
||||
thread_args->lane = lane_ctx;
|
||||
thread_args->udata = udata;
|
||||
thread_args->entry = entry;
|
||||
thread_args->name = thread_name;
|
||||
|
||||
for (u32 lane_idx = 0; lane_idx < num_lanes; ++lane_idx)
|
||||
HANDLE handle = CreateThread(0, Mebi(4), W32_ThreadProc, thread_args, 0, 0);
|
||||
if (!handle)
|
||||
{
|
||||
WaveLaneCtx *lane_ctx = PushStruct(perm, WaveLaneCtx);
|
||||
lane_ctx->idx = lane_idx;
|
||||
lane_ctx->wave = wave_ctx;
|
||||
lane_ctx->default_spin_count = DefaultWaveLaneSpinCount;
|
||||
|
||||
String thread_name = Zi;
|
||||
if (num_lanes > 1)
|
||||
{
|
||||
thread_name = StringF(perm, "%F:%F", FmtString(name), FmtUint(lane_idx));
|
||||
}
|
||||
else
|
||||
{
|
||||
thread_name = PushString(perm, name);
|
||||
}
|
||||
|
||||
W32_ThreadArgs *thread_args = PushStruct(perm, W32_ThreadArgs);
|
||||
thread_args->lane = lane_ctx;
|
||||
thread_args->udata = udata;
|
||||
thread_args->entry = entry;
|
||||
thread_args->name = thread_name;
|
||||
|
||||
HANDLE handle = CreateThread(0, Mebi(4), W32_ThreadProc, thread_args, 0, 0);
|
||||
if (!handle)
|
||||
{
|
||||
Panic(Lit("Failed to create thread"));
|
||||
}
|
||||
Panic(Lit("Failed to create thread"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -94,5 +94,5 @@ void DispatchWave(String name, u32 num_lanes, WaveLaneEntryFunc *entry, void *ud
|
||||
|
||||
i32 ThreadId(void)
|
||||
{
|
||||
return GetCurrentThreadId();
|
||||
return GetCurrentThreadId();
|
||||
}
|
||||
|
||||
@ -3,10 +3,10 @@
|
||||
|
||||
Struct(W32_ThreadArgs)
|
||||
{
|
||||
void *udata;
|
||||
WaveLaneCtx *lane;
|
||||
WaveLaneEntryFunc *entry;
|
||||
String name;
|
||||
void *udata;
|
||||
WaveLaneCtx *lane;
|
||||
WaveLaneEntryFunc *entry;
|
||||
String name;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -15,9 +15,9 @@
|
||||
|
||||
Struct(CLD_Shape)
|
||||
{
|
||||
Vec2 points[8];
|
||||
u32 count;
|
||||
f32 radius;
|
||||
Vec2 points[8];
|
||||
u32 count;
|
||||
f32 radius;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -25,27 +25,27 @@ Struct(CLD_Shape)
|
||||
|
||||
Struct(CLD_SupportPoint)
|
||||
{
|
||||
Vec2 p;
|
||||
u32 i; /* Index of original point in shape */
|
||||
Vec2 p;
|
||||
u32 i; /* Index of original point in shape */
|
||||
};
|
||||
|
||||
Struct(CLD_MenkowskiPoint)
|
||||
{
|
||||
Vec2 p; /* Menkowski difference point */
|
||||
CLD_SupportPoint s0; /* Support point of first shape in dir */
|
||||
CLD_SupportPoint s1; /* Support point of second shape in -dir */
|
||||
Vec2 p; /* Menkowski difference point */
|
||||
CLD_SupportPoint s0; /* Support point of first shape in dir */
|
||||
CLD_SupportPoint s1; /* Support point of second shape in -dir */
|
||||
};
|
||||
|
||||
Struct(CLD_MenkowskiSimplex)
|
||||
{
|
||||
u32 len;
|
||||
CLD_MenkowskiPoint a, b, c;
|
||||
u32 len;
|
||||
CLD_MenkowskiPoint a, b, c;
|
||||
};
|
||||
|
||||
Struct(CLD_MenkowskiFeature)
|
||||
{
|
||||
u32 len;
|
||||
CLD_MenkowskiPoint a, b;
|
||||
u32 len;
|
||||
CLD_MenkowskiPoint a, b;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -53,42 +53,42 @@ Struct(CLD_MenkowskiFeature)
|
||||
|
||||
Struct(CLD_CollisionPoint)
|
||||
{
|
||||
Vec2 point;
|
||||
f32 separation;
|
||||
u32 id; /* Based on polygon edge-to-edge */
|
||||
Vec2 point;
|
||||
f32 separation;
|
||||
u32 id; /* Based on polygon edge-to-edge */
|
||||
};
|
||||
|
||||
Struct(CLD_Prototype)
|
||||
{
|
||||
Vec2 points[64];
|
||||
u32 len;
|
||||
Vec2 points[64];
|
||||
u32 len;
|
||||
};
|
||||
|
||||
Struct(CLD_CollisionData)
|
||||
{
|
||||
Vec2 normal;
|
||||
CLD_CollisionPoint points[2];
|
||||
u32 num_points;
|
||||
Vec2 normal;
|
||||
CLD_CollisionPoint points[2];
|
||||
u32 num_points;
|
||||
|
||||
/* For debugging */
|
||||
b32 solved;
|
||||
CLD_MenkowskiSimplex simplex;
|
||||
CLD_Prototype prototype;
|
||||
/* For debugging */
|
||||
b32 solved;
|
||||
CLD_MenkowskiSimplex simplex;
|
||||
CLD_Prototype prototype;
|
||||
|
||||
/* For debugging */
|
||||
Vec2 a0, b0, a1, b1;
|
||||
Vec2 a0_clipped, b0_clipped, a1_clipped, b1_clipped;
|
||||
/* For debugging */
|
||||
Vec2 a0, b0, a1, b1;
|
||||
Vec2 a0_clipped, b0_clipped, a1_clipped, b1_clipped;
|
||||
};
|
||||
|
||||
Struct(CLD_ClosestPointData)
|
||||
{
|
||||
Vec2 p0, p1;
|
||||
b32 colliding;
|
||||
Vec2 p0, p1;
|
||||
b32 colliding;
|
||||
|
||||
/* For debugging */
|
||||
b32 solved;
|
||||
CLD_MenkowskiSimplex simplex;
|
||||
CLD_Prototype prototype;
|
||||
/* For debugging */
|
||||
b32 solved;
|
||||
CLD_MenkowskiSimplex simplex;
|
||||
CLD_Prototype prototype;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -96,8 +96,8 @@ Struct(CLD_ClosestPointData)
|
||||
|
||||
Struct(CLD_ClippedLine)
|
||||
{
|
||||
Vec2 a0_clipped, b0_clipped;
|
||||
Vec2 a1_clipped, b1_clipped;
|
||||
Vec2 a0_clipped, b0_clipped;
|
||||
Vec2 a1_clipped, b1_clipped;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -105,16 +105,16 @@ Struct(CLD_ClippedLine)
|
||||
|
||||
Struct(CLD_GjkData)
|
||||
{
|
||||
CLD_MenkowskiSimplex simplex;
|
||||
Vec2 final_dir;
|
||||
CLD_MenkowskiSimplex simplex;
|
||||
Vec2 final_dir;
|
||||
|
||||
/* If 1, simplex represents triangle inside of CLD_Menkowski difference
|
||||
* encapsulating the origin. If 0, simplex represents the closest
|
||||
* feature on CLD_Menkowski difference to the origin. */
|
||||
b32 overlapping;
|
||||
/* If 1, simplex represents triangle inside of CLD_Menkowski difference
|
||||
* encapsulating the origin. If 0, simplex represents the closest
|
||||
* feature on CLD_Menkowski difference to the origin. */
|
||||
b32 overlapping;
|
||||
|
||||
#if COLLIDER_DEBUG
|
||||
u32 dbg_step;
|
||||
u32 dbg_step;
|
||||
#endif
|
||||
};
|
||||
|
||||
@ -123,12 +123,12 @@ Struct(CLD_GjkData)
|
||||
|
||||
Struct(CLD_EpaData)
|
||||
{
|
||||
Vec2 normal;
|
||||
CLD_MenkowskiFeature closest_feature; /* Represents closest feature (edge or point) to origin on CLD_Menkowski difference */
|
||||
Vec2 normal;
|
||||
CLD_MenkowskiFeature closest_feature; /* Represents closest feature (edge or point) to origin on CLD_Menkowski difference */
|
||||
|
||||
#if COLLIDER_DEBUG
|
||||
CLD_Prototype prototype;
|
||||
u32 dbg_step;
|
||||
CLD_Prototype prototype;
|
||||
u32 dbg_step;
|
||||
#endif
|
||||
};
|
||||
|
||||
@ -139,17 +139,17 @@ Struct(CLD_EpaData)
|
||||
void CLD_DebugBreakable(void);
|
||||
|
||||
#define CLD_DBGSTEP \
|
||||
dbg_step++; \
|
||||
if (dbg_step >= GetGstat(DebugSteps)) \
|
||||
{ \
|
||||
goto abort; \
|
||||
} \
|
||||
else if (dbg_step >= GetGstat(DebugSteps) - 1) \
|
||||
{ \
|
||||
CLD_DebugBreakable(); \
|
||||
} (void)0
|
||||
dbg_step++; \
|
||||
if (dbg_step >= GetGstat(DebugSteps)) \
|
||||
{ \
|
||||
goto abort; \
|
||||
} \
|
||||
else if (dbg_step >= GetGstat(DebugSteps) - 1) \
|
||||
{ \
|
||||
CLD_DebugBreakable(); \
|
||||
} (void)0
|
||||
#else
|
||||
#define CLD_DBGSTEP
|
||||
#define CLD_DBGSTEP
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
30
src/config.h
30
src/config.h
@ -4,17 +4,17 @@
|
||||
|
||||
/* Window title */
|
||||
#if IsRtcEnabled
|
||||
# if IsDeveloperModeEnabled
|
||||
# define WINDOW_TITLE "Debug (Developer Build)"
|
||||
# else
|
||||
# define WINDOW_TITLE "Debug"
|
||||
# endif
|
||||
#if IsDeveloperModeEnabled
|
||||
#define WINDOW_TITLE "Debug (Developer Build)"
|
||||
#else
|
||||
#define WINDOW_TITLE "Debug"
|
||||
#endif
|
||||
#else
|
||||
# if IsDeveloperModeEnabled
|
||||
# define WINDOW_TITLE "Power Play (Developer Build)"
|
||||
# else
|
||||
# define WINDOW_TITLE "Power Play"
|
||||
# endif
|
||||
#if IsDeveloperModeEnabled
|
||||
#define WINDOW_TITLE "Power Play (Developer Build)"
|
||||
#else
|
||||
#define WINDOW_TITLE "Power Play"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define DEFAULT_CAMERA_WIDTH (16)
|
||||
@ -33,7 +33,7 @@
|
||||
#define USER_INTERP_RATIO 1.2
|
||||
#define USER_INTERP_ENABLED 1
|
||||
|
||||
/* 64^2 = 4096 bins */
|
||||
/* 64^2 = 4096 bins */
|
||||
#define SPACE_CELL_BINS_SQRT (64)
|
||||
#define SPACE_CELL_SIZE (1)
|
||||
|
||||
@ -56,11 +56,11 @@
|
||||
#define SIM_PLAYER_AIM 1
|
||||
|
||||
#if 0
|
||||
# define SIM_MAX_LINEAR_VELOCITY 500
|
||||
# define SIM_MAX_ANGULAR_VELOCITY (Tau * 20)
|
||||
#define SIM_MAX_LINEAR_VELOCITY 500
|
||||
#define SIM_MAX_ANGULAR_VELOCITY (Tau * 20)
|
||||
#else
|
||||
# define SIM_MAX_LINEAR_VELOCITY F32Infinity
|
||||
# define SIM_MAX_ANGULAR_VELOCITY F32Infinity
|
||||
#define SIM_MAX_LINEAR_VELOCITY F32Infinity
|
||||
#define SIM_MAX_ANGULAR_VELOCITY F32Infinity
|
||||
#endif
|
||||
|
||||
#define COLLIDER_DEBUG 0
|
||||
|
||||
672
src/draw/draw.c
672
src/draw/draw.c
@ -5,9 +5,9 @@ D_SharedState D_shared_state = ZI;
|
||||
|
||||
void D_Bootstrap(void)
|
||||
{
|
||||
D_SharedState *g = &D_shared_state;
|
||||
u32 pixel_white = 0xFFFFFFFF;
|
||||
g->solid_white_texture = GPU_AcquireTexture(GP_TEXTURE_FORMAT_R8G8B8A8_UNORM, 0, VEC2I32(1, 1), &pixel_white);
|
||||
D_SharedState *g = &D_shared_state;
|
||||
u32 pixel_white = 0xFFFFFFFF;
|
||||
g->solid_white_texture = GPU_AcquireTexture(GP_TEXTURE_FORMAT_R8G8B8A8_UNORM, 0, VEC2I32(1, 1), &pixel_white);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -15,15 +15,15 @@ void D_Bootstrap(void)
|
||||
|
||||
void D_DrawMaterial(GPU_RenderSig *sig, D_MaterialParams params)
|
||||
{
|
||||
GPU_RenderCmdDesc cmd = ZI;
|
||||
cmd.kind = GP_RENDER_CMD_KIND_DRAW_MATERIAL;
|
||||
cmd.material.xf = params.xf;
|
||||
cmd.material.texture = params.texture;
|
||||
cmd.material.clip = params.clip;
|
||||
cmd.material.tint = params.tint;
|
||||
cmd.material.is_light = params.is_light;
|
||||
cmd.material.light_emittance = params.light_emittance;
|
||||
GPU_PushRenderCmd(sig, &cmd);
|
||||
GPU_RenderCmdDesc cmd = ZI;
|
||||
cmd.kind = GP_RENDER_CMD_KIND_DRAW_MATERIAL;
|
||||
cmd.material.xf = params.xf;
|
||||
cmd.material.texture = params.texture;
|
||||
cmd.material.clip = params.clip;
|
||||
cmd.material.tint = params.tint;
|
||||
cmd.material.is_light = params.is_light;
|
||||
cmd.material.light_emittance = params.light_emittance;
|
||||
GPU_PushRenderCmd(sig, &cmd);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -31,75 +31,75 @@ void D_DrawMaterial(GPU_RenderSig *sig, D_MaterialParams params)
|
||||
|
||||
void D_DrawPolyEx(GPU_RenderSig *sig, Vec2Array vertices, GPU_Indices indices, u32 color)
|
||||
{
|
||||
GPU_RenderCmdDesc cmd = ZI;
|
||||
cmd.kind = GP_RENDER_CMD_KIND_DRAW_UI_SHAPE;
|
||||
cmd.ui_shape.vertices = vertices;
|
||||
cmd.ui_shape.indices = indices;
|
||||
cmd.ui_shape.color = color;
|
||||
GPU_PushRenderCmd(sig, &cmd);
|
||||
GPU_RenderCmdDesc cmd = ZI;
|
||||
cmd.kind = GP_RENDER_CMD_KIND_DRAW_UI_SHAPE;
|
||||
cmd.ui_shape.vertices = vertices;
|
||||
cmd.ui_shape.indices = indices;
|
||||
cmd.ui_shape.color = color;
|
||||
GPU_PushRenderCmd(sig, &cmd);
|
||||
}
|
||||
|
||||
/* Draws a filled polygon using triangles in a fan pattern */
|
||||
void D_DrawPoly(GPU_RenderSig *sig, Vec2Array vertices, u32 color)
|
||||
{
|
||||
if (vertices.count >= 3)
|
||||
if (vertices.count >= 3)
|
||||
{
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
|
||||
u32 num_tris = vertices.count - 2;
|
||||
u32 num_indices = num_tris * 3;
|
||||
|
||||
/* Generate indices in a fan pattern */
|
||||
GPU_Indices indices = ZI;
|
||||
indices.count = num_indices;
|
||||
indices.indices = PushStructsNoZero(scratch.arena, u32, num_indices);
|
||||
for (u32 i = 0; i < num_tris; ++i)
|
||||
{
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
|
||||
u32 num_tris = vertices.count - 2;
|
||||
u32 num_indices = num_tris * 3;
|
||||
|
||||
/* Generate indices in a fan pattern */
|
||||
GPU_Indices indices = ZI;
|
||||
indices.count = num_indices;
|
||||
indices.indices = PushStructsNoZero(scratch.arena, u32, num_indices);
|
||||
for (u32 i = 0; i < num_tris; ++i)
|
||||
{
|
||||
u32 tri_offset = i * 3;
|
||||
indices.indices[tri_offset + 0] = 0;
|
||||
indices.indices[tri_offset + 1] = (i + 1);
|
||||
indices.indices[tri_offset + 2] = (i + 2);
|
||||
}
|
||||
|
||||
D_DrawPolyEx(sig, vertices, indices, color);
|
||||
|
||||
EndScratch(scratch);
|
||||
u32 tri_offset = i * 3;
|
||||
indices.indices[tri_offset + 0] = 0;
|
||||
indices.indices[tri_offset + 1] = (i + 1);
|
||||
indices.indices[tri_offset + 2] = (i + 2);
|
||||
}
|
||||
|
||||
D_DrawPolyEx(sig, vertices, indices, color);
|
||||
|
||||
EndScratch(scratch);
|
||||
}
|
||||
}
|
||||
|
||||
void D_DrawCircle(GPU_RenderSig *sig, Vec2 pos, f32 radius, u32 color, u32 detail)
|
||||
{
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
|
||||
Vec2 *points = PushStructsNoZero(scratch.arena, Vec2, detail);
|
||||
for (u32 i = 0; i < detail; ++i)
|
||||
{
|
||||
f32 angle = ((f32)i / (f32)detail) * Tau;
|
||||
Vec2 p = VEC2(
|
||||
radius * CosF32(angle),
|
||||
radius * SinF32(angle)
|
||||
);
|
||||
points[i] = AddVec2(pos, p);
|
||||
}
|
||||
Vec2 *points = PushStructsNoZero(scratch.arena, Vec2, detail);
|
||||
for (u32 i = 0; i < detail; ++i)
|
||||
{
|
||||
f32 angle = ((f32)i / (f32)detail) * Tau;
|
||||
Vec2 p = VEC2(
|
||||
radius * CosF32(angle),
|
||||
radius * SinF32(angle)
|
||||
);
|
||||
points[i] = AddVec2(pos, p);
|
||||
}
|
||||
|
||||
Vec2Array vertices = {
|
||||
.points = points,
|
||||
.count = detail
|
||||
};
|
||||
D_DrawPoly(sig, vertices, color);
|
||||
Vec2Array vertices = {
|
||||
.points = points,
|
||||
.count = detail
|
||||
};
|
||||
D_DrawPoly(sig, vertices, color);
|
||||
|
||||
EndScratch(scratch);
|
||||
EndScratch(scratch);
|
||||
}
|
||||
|
||||
void D_DrawQuad(GPU_RenderSig *sig, Quad quad, u32 color)
|
||||
{
|
||||
PERSIST const u32 indices_array[6] = {
|
||||
0, 1, 2,
|
||||
0, 2, 3
|
||||
};
|
||||
Vec2Array vertices = { .count = 4, .points = quad.e };
|
||||
GPU_Indices indices = { .count = 6, .indices = indices_array };
|
||||
D_DrawPolyEx(sig, vertices, indices, color);
|
||||
PERSIST const u32 indices_array[6] = {
|
||||
0, 1, 2,
|
||||
0, 2, 3
|
||||
};
|
||||
Vec2Array vertices = { .count = 4, .points = quad.e };
|
||||
GPU_Indices indices = { .count = 6, .indices = indices_array };
|
||||
D_DrawPolyEx(sig, vertices, indices, color);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -108,144 +108,144 @@ void D_DrawQuad(GPU_RenderSig *sig, Quad quad, u32 color)
|
||||
void D_DrawLineGradient(GPU_RenderSig *sig, Vec2 start, Vec2 end, f32 thickness, u32 start_color, u32 end_color)
|
||||
{
|
||||
#if 0
|
||||
D_SharedState *g = &D_shared_state;
|
||||
Quad quad = QuadFromLine(start, end, thickness);
|
||||
D_DrawMaterial(sig, D_MATERIALPARAMS(.texture = g->solid_white_texture, .tint0 = start_color, .tint1 = end_color, .quad = quad));
|
||||
D_SharedState *g = &D_shared_state;
|
||||
Quad quad = QuadFromLine(start, end, thickness);
|
||||
D_DrawMaterial(sig, D_MATERIALPARAMS(.texture = g->solid_white_texture, .tint0 = start_color, .tint1 = end_color, .quad = quad));
|
||||
#else
|
||||
/* Placeholder */
|
||||
Quad quad = QuadFromLine(start, end, thickness);
|
||||
D_DrawQuad(sig, quad, start_color);
|
||||
/* Placeholder */
|
||||
Quad quad = QuadFromLine(start, end, thickness);
|
||||
D_DrawQuad(sig, quad, start_color);
|
||||
#endif
|
||||
}
|
||||
|
||||
void D_DrawLine(GPU_RenderSig *sig, Vec2 start, Vec2 end, f32 thickness, u32 color)
|
||||
{
|
||||
Quad quad = QuadFromLine(start, end, thickness);
|
||||
D_DrawQuad(sig, quad, color);
|
||||
Quad quad = QuadFromLine(start, end, thickness);
|
||||
D_DrawQuad(sig, quad, color);
|
||||
}
|
||||
|
||||
void D_DrawRay(GPU_RenderSig *sig, Vec2 pos, Vec2 rel, f32 thickness, u32 color)
|
||||
{
|
||||
Quad quad = QuadFromRay(pos, rel, thickness);
|
||||
D_DrawQuad(sig, quad, color);
|
||||
Quad quad = QuadFromRay(pos, rel, thickness);
|
||||
D_DrawQuad(sig, quad, color);
|
||||
}
|
||||
|
||||
void D_DrawPolyLine(GPU_RenderSig *sig, Vec2Array points, b32 loop, f32 thickness, u32 color)
|
||||
{
|
||||
if (points.count >= 2)
|
||||
if (points.count >= 2)
|
||||
{
|
||||
for (u64 i = 1; i < points.count; ++i)
|
||||
{
|
||||
for (u64 i = 1; i < points.count; ++i)
|
||||
{
|
||||
Vec2 p1 = points.points[i - 1];
|
||||
Vec2 p2 = points.points[i];
|
||||
Quad q = QuadFromLine(p1, p2, thickness);
|
||||
D_DrawQuad(sig, q, color);
|
||||
}
|
||||
if (loop && points.count > 2)
|
||||
{
|
||||
Vec2 p1 = points.points[points.count - 1];
|
||||
Vec2 p2 = points.points[0];
|
||||
Quad q = QuadFromLine(p1, p2, thickness);
|
||||
D_DrawQuad(sig, q, color);
|
||||
}
|
||||
Vec2 p1 = points.points[i - 1];
|
||||
Vec2 p2 = points.points[i];
|
||||
Quad q = QuadFromLine(p1, p2, thickness);
|
||||
D_DrawQuad(sig, q, color);
|
||||
}
|
||||
if (loop && points.count > 2)
|
||||
{
|
||||
Vec2 p1 = points.points[points.count - 1];
|
||||
Vec2 p2 = points.points[0];
|
||||
Quad q = QuadFromLine(p1, p2, thickness);
|
||||
D_DrawQuad(sig, q, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void D_DrawCircleLine(GPU_RenderSig *sig, Vec2 pos, f32 radius, f32 thickness, u32 color, u32 detail)
|
||||
{
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
|
||||
Vec2 *points = PushStructsNoZero(scratch.arena, Vec2, detail);
|
||||
for (u32 i = 0; i < detail; ++i)
|
||||
{
|
||||
f32 angle = ((f32)i / (f32)detail) * Tau;
|
||||
Vec2 p = VEC2(
|
||||
radius * CosF32(angle),
|
||||
radius * SinF32(angle)
|
||||
);
|
||||
points[i] = AddVec2(pos, p);
|
||||
}
|
||||
Vec2 *points = PushStructsNoZero(scratch.arena, Vec2, detail);
|
||||
for (u32 i = 0; i < detail; ++i)
|
||||
{
|
||||
f32 angle = ((f32)i / (f32)detail) * Tau;
|
||||
Vec2 p = VEC2(
|
||||
radius * CosF32(angle),
|
||||
radius * SinF32(angle)
|
||||
);
|
||||
points[i] = AddVec2(pos, p);
|
||||
}
|
||||
|
||||
Vec2Array a = {
|
||||
.points = points,
|
||||
.count = detail
|
||||
};
|
||||
D_DrawPolyLine(sig, a, 1, thickness, color);
|
||||
Vec2Array a = {
|
||||
.points = points,
|
||||
.count = detail
|
||||
};
|
||||
D_DrawPolyLine(sig, a, 1, thickness, color);
|
||||
|
||||
EndScratch(scratch);
|
||||
EndScratch(scratch);
|
||||
}
|
||||
|
||||
void D_DrawQuadLine(GPU_RenderSig *sig, Quad quad, f32 thickness, u32 color)
|
||||
{
|
||||
Vec2 points[] = { quad.p0, quad.p1, quad.p2, quad.p3 };
|
||||
Vec2Array a = { .points = points, .count = countof(points) };
|
||||
D_DrawPolyLine(sig, a, 1, thickness, color);
|
||||
Vec2 points[] = { quad.p0, quad.p1, quad.p2, quad.p3 };
|
||||
Vec2Array a = { .points = points, .count = countof(points) };
|
||||
D_DrawPolyLine(sig, a, 1, thickness, color);
|
||||
}
|
||||
|
||||
void D_DrawArrowLine(GPU_RenderSig *sig, Vec2 start, Vec2 end, f32 thickness, f32 arrowhead_height, u32 color)
|
||||
{
|
||||
const f32 head_width_ratio = 0.5f; /* Width of arrowhead relative to its length */
|
||||
const f32 head_width_ratio = 0.5f; /* Width of arrowhead relative to its length */
|
||||
|
||||
const f32 max_height_to_line_ratio = 0.9f; /* Maximum length of arrowhead relative to total line length */
|
||||
arrowhead_height = MinF32(arrowhead_height, Vec2Len(SubVec2(end, start)) * max_height_to_line_ratio);
|
||||
const f32 max_height_to_line_ratio = 0.9f; /* Maximum length of arrowhead relative to total line length */
|
||||
arrowhead_height = MinF32(arrowhead_height, Vec2Len(SubVec2(end, start)) * max_height_to_line_ratio);
|
||||
|
||||
Vec2 head_start_dir = SubVec2(start, end);
|
||||
head_start_dir = NormVec2(head_start_dir);
|
||||
head_start_dir = MulVec2(head_start_dir, arrowhead_height);
|
||||
Vec2 head_start_dir = SubVec2(start, end);
|
||||
head_start_dir = NormVec2(head_start_dir);
|
||||
head_start_dir = MulVec2(head_start_dir, arrowhead_height);
|
||||
|
||||
Vec2 head_start = AddVec2(end, head_start_dir);
|
||||
Vec2 head_start = AddVec2(end, head_start_dir);
|
||||
|
||||
Vec2 head_p1_dir = MulPerpVec2(head_start_dir, head_width_ratio);
|
||||
Vec2 head_p2_dir = NegVec2(head_p1_dir);
|
||||
Vec2 head_p1_dir = MulPerpVec2(head_start_dir, head_width_ratio);
|
||||
Vec2 head_p2_dir = NegVec2(head_p1_dir);
|
||||
|
||||
Vec2 head_p1 = AddVec2(head_start, head_p1_dir);
|
||||
Vec2 head_p2 = AddVec2(head_start, head_p2_dir);
|
||||
Vec2 head_p1 = AddVec2(head_start, head_p1_dir);
|
||||
Vec2 head_p2 = AddVec2(head_start, head_p2_dir);
|
||||
|
||||
Vec2 head_points[] = { end, head_p1, head_p2 };
|
||||
Vec2Array head_points_v2_array = {
|
||||
.points = head_points,
|
||||
.count = countof(head_points)
|
||||
};
|
||||
D_DrawPoly(sig, head_points_v2_array, color);
|
||||
Vec2 head_points[] = { end, head_p1, head_p2 };
|
||||
Vec2Array head_points_v2_array = {
|
||||
.points = head_points,
|
||||
.count = countof(head_points)
|
||||
};
|
||||
D_DrawPoly(sig, head_points_v2_array, color);
|
||||
|
||||
Quad line_quad = QuadFromLine(start, head_start, thickness);
|
||||
D_DrawQuad(sig, line_quad, color);
|
||||
Quad line_quad = QuadFromLine(start, head_start, thickness);
|
||||
D_DrawQuad(sig, line_quad, color);
|
||||
}
|
||||
|
||||
void D_DrawArrowRay(GPU_RenderSig *sig, Vec2 pos, Vec2 rel, f32 thickness, f32 arrowhead_height, u32 color)
|
||||
{
|
||||
Vec2 end = AddVec2(pos, rel);
|
||||
D_DrawArrowLine(sig, pos, end, thickness, arrowhead_height, color);
|
||||
Vec2 end = AddVec2(pos, rel);
|
||||
D_DrawArrowLine(sig, pos, end, thickness, arrowhead_height, color);
|
||||
}
|
||||
|
||||
void D_DrawColliderLine(GPU_RenderSig *sig, CLD_Shape shape, Xform shape_xf, f32 thickness, u32 color, u32 detail)
|
||||
{
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
Vec2Array poly = ZI;
|
||||
if (shape.radius == 0)
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
Vec2Array poly = ZI;
|
||||
if (shape.radius == 0)
|
||||
{
|
||||
poly.count = shape.count;
|
||||
poly.points = PushStructsNoZero(scratch.arena, Vec2, shape.count);
|
||||
for (u32 i = 0; i < shape.count; ++i)
|
||||
{
|
||||
poly.count = shape.count;
|
||||
poly.points = PushStructsNoZero(scratch.arena, Vec2, shape.count);
|
||||
for (u32 i = 0; i < shape.count; ++i)
|
||||
{
|
||||
Vec2 p = MulXformV2(shape_xf, shape.points[i]);
|
||||
poly.points[i] = p;
|
||||
}
|
||||
Vec2 p = MulXformV2(shape_xf, shape.points[i]);
|
||||
poly.points[i] = p;
|
||||
}
|
||||
else
|
||||
}
|
||||
else
|
||||
{
|
||||
poly.count = detail;
|
||||
poly.points = PushStructsNoZero(scratch.arena, Vec2, detail);
|
||||
for (u32 i = 0; i < detail; ++i)
|
||||
{
|
||||
poly.count = detail;
|
||||
poly.points = PushStructsNoZero(scratch.arena, Vec2, detail);
|
||||
for (u32 i = 0; i < detail; ++i)
|
||||
{
|
||||
f32 angle = ((f32)i / (f32)detail) * Tau;
|
||||
Vec2 dir = VEC2(CosF32(angle), SinF32(angle));
|
||||
Vec2 p = CLD_SupportPointFromDir(&shape, shape_xf, dir).p;
|
||||
poly.points[i] = p;
|
||||
}
|
||||
f32 angle = ((f32)i / (f32)detail) * Tau;
|
||||
Vec2 dir = VEC2(CosF32(angle), SinF32(angle));
|
||||
Vec2 p = CLD_SupportPointFromDir(&shape, shape_xf, dir).p;
|
||||
poly.points[i] = p;
|
||||
}
|
||||
D_DrawPolyLine(sig, poly, 1, thickness, color);
|
||||
EndScratch(scratch);
|
||||
}
|
||||
D_DrawPolyLine(sig, poly, 1, thickness, color);
|
||||
EndScratch(scratch);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -253,27 +253,27 @@ void D_DrawColliderLine(GPU_RenderSig *sig, CLD_Shape shape, Xform shape_xf, f32
|
||||
|
||||
void D_DrawGrid(GPU_RenderSig *sig, Xform xf, u32 bg0_color, u32 bg1_color, u32 line_color, u32 x_color, u32 y_color, f32 thickness, f32 spacing, Vec2 offset)
|
||||
{
|
||||
i32 grid_id = 0;
|
||||
{
|
||||
GPU_RenderCmdDesc cmd = ZI;
|
||||
cmd.kind = GP_RENDER_CMD_KIND_PUSH_GRID;
|
||||
cmd.grid.bg0_color = bg0_color;
|
||||
cmd.grid.bg1_color = bg1_color;
|
||||
cmd.grid.line_color = line_color;
|
||||
cmd.grid.x_color = x_color;
|
||||
cmd.grid.y_color = y_color;
|
||||
cmd.grid.line_thickness = thickness;
|
||||
cmd.grid.line_spacing = spacing;
|
||||
cmd.grid.offset = offset;
|
||||
grid_id = GPU_PushRenderCmd(sig, &cmd);
|
||||
}
|
||||
|
||||
i32 grid_id = 0;
|
||||
{
|
||||
GPU_RenderCmdDesc cmd = ZI;
|
||||
cmd.kind = GP_RENDER_CMD_KIND_DRAW_MATERIAL;
|
||||
cmd.material.xf = xf;
|
||||
cmd.material.tint = Color_White;
|
||||
cmd.material.grid_cmd_id = grid_id;
|
||||
GPU_PushRenderCmd(sig, &cmd);
|
||||
cmd.kind = GP_RENDER_CMD_KIND_PUSH_GRID;
|
||||
cmd.grid.bg0_color = bg0_color;
|
||||
cmd.grid.bg1_color = bg1_color;
|
||||
cmd.grid.line_color = line_color;
|
||||
cmd.grid.x_color = x_color;
|
||||
cmd.grid.y_color = y_color;
|
||||
cmd.grid.line_thickness = thickness;
|
||||
cmd.grid.line_spacing = spacing;
|
||||
cmd.grid.offset = offset;
|
||||
grid_id = GPU_PushRenderCmd(sig, &cmd);
|
||||
}
|
||||
|
||||
GPU_RenderCmdDesc cmd = ZI;
|
||||
cmd.kind = GP_RENDER_CMD_KIND_DRAW_MATERIAL;
|
||||
cmd.material.xf = xf;
|
||||
cmd.material.tint = Color_White;
|
||||
cmd.material.grid_cmd_id = grid_id;
|
||||
GPU_PushRenderCmd(sig, &cmd);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -281,190 +281,190 @@ void D_DrawGrid(GPU_RenderSig *sig, Xform xf, u32 bg0_color, u32 bg1_color, u32
|
||||
|
||||
void D_DrawUiRect(GPU_RenderSig *sig, D_UiRectParams params)
|
||||
{
|
||||
GPU_RenderCmdDesc cmd = ZI;
|
||||
cmd.kind = GP_RENDER_CMD_KIND_DRAW_UI_RECT;
|
||||
cmd.ui_rect.xf = params.xf;
|
||||
cmd.ui_rect.texture = params.texture;
|
||||
cmd.ui_rect.clip = params.clip;
|
||||
cmd.ui_rect.tint = params.tint;
|
||||
GPU_PushRenderCmd(sig, &cmd);
|
||||
GPU_RenderCmdDesc cmd = ZI;
|
||||
cmd.kind = GP_RENDER_CMD_KIND_DRAW_UI_RECT;
|
||||
cmd.ui_rect.xf = params.xf;
|
||||
cmd.ui_rect.texture = params.texture;
|
||||
cmd.ui_rect.clip = params.clip;
|
||||
cmd.ui_rect.tint = params.tint;
|
||||
GPU_PushRenderCmd(sig, &cmd);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Text
|
||||
|
||||
/* Returns the rect of the text area */
|
||||
/* Returns the rect of the text area */
|
||||
Rect draw_text(GPU_RenderSig *sig, D_TextParams params)
|
||||
{
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
|
||||
f32 inv_font_image_width = 1.0 / (f32)params.font->image_width;
|
||||
f32 inv_font_image_height = 1.0 / (f32)params.font->image_height;
|
||||
f32 line_spacing = params.font->point_size * 1.5f * params.scale;
|
||||
f32 inv_font_image_width = 1.0 / (f32)params.font->image_width;
|
||||
f32 inv_font_image_height = 1.0 / (f32)params.font->image_height;
|
||||
f32 line_spacing = params.font->point_size * 1.5f * params.scale;
|
||||
|
||||
//- Build line glyphs
|
||||
//- Build line glyphs
|
||||
|
||||
u64 num_lines = 0;
|
||||
f32 widest_line = 0;
|
||||
u64 num_lines = 0;
|
||||
f32 widest_line = 0;
|
||||
|
||||
D_TextLine *first_line = 0;
|
||||
D_TextLine *last_line = 0;
|
||||
f32 first_line_top_offset = 0;
|
||||
f32 last_line_bottom_offset = 0;
|
||||
D_TextLine *first_line = 0;
|
||||
D_TextLine *last_line = 0;
|
||||
f32 first_line_top_offset = 0;
|
||||
f32 last_line_bottom_offset = 0;
|
||||
|
||||
if (params.str.len > 0)
|
||||
if (params.str.len > 0)
|
||||
{
|
||||
b32 string_done = 0;
|
||||
CodepointIter iter = BeginCodepointIter(params.str);
|
||||
while (!string_done)
|
||||
{
|
||||
b32 string_done = 0;
|
||||
CodepointIter iter = BeginCodepointIter(params.str);
|
||||
while (!string_done)
|
||||
f32 line_width = 0;
|
||||
f32 top_offset = 0;
|
||||
f32 bottom_offset = 0;
|
||||
u64 num_line_glyphs = 0;
|
||||
D_TextGlyph *line_glyphs = PushDry(scratch.arena, D_TextGlyph);
|
||||
|
||||
b32 line_done = 0;
|
||||
while (!line_done)
|
||||
{
|
||||
string_done = !AdvanceCodepointIter(&iter);
|
||||
if (string_done)
|
||||
{
|
||||
f32 line_width = 0;
|
||||
f32 top_offset = 0;
|
||||
f32 bottom_offset = 0;
|
||||
u64 num_line_glyphs = 0;
|
||||
D_TextGlyph *line_glyphs = PushDry(scratch.arena, D_TextGlyph);
|
||||
|
||||
b32 line_done = 0;
|
||||
while (!line_done)
|
||||
{
|
||||
string_done = !AdvanceCodepointIter(&iter);
|
||||
if (string_done)
|
||||
{
|
||||
line_done = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
u32 codepoint = iter.codepoint;
|
||||
if (codepoint == '\n')
|
||||
{
|
||||
line_done = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
D_TextGlyph *tg = PushStruct(scratch.arena, D_TextGlyph);
|
||||
++num_line_glyphs;
|
||||
F_Glyph *glyph = F_GetGlyph(params.font, codepoint);
|
||||
tg->off_x = glyph->off_x * params.scale;
|
||||
tg->off_y = glyph->off_y * params.scale;
|
||||
tg->width = glyph->width * params.scale;
|
||||
tg->height = glyph->height * params.scale;
|
||||
tg->advance = glyph->advance * params.scale;
|
||||
Rect glyph_atlas_rect = glyph->atlas_rect;
|
||||
tg->clip = (ClipRect) {
|
||||
{
|
||||
glyph_atlas_rect.x * inv_font_image_width,
|
||||
glyph_atlas_rect.y * inv_font_image_height
|
||||
},
|
||||
{
|
||||
(glyph_atlas_rect.x + glyph_atlas_rect.width) * inv_font_image_width,
|
||||
(glyph_atlas_rect.y + glyph_atlas_rect.height) * inv_font_image_height
|
||||
}
|
||||
};
|
||||
line_width += tg->advance;
|
||||
top_offset = MinF32(top_offset, tg->off_y);
|
||||
bottom_offset = MaxF32(bottom_offset, tg->off_y + tg->height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Line ended */
|
||||
/* TODO: Only create nodes for non-empty lines. Embed line number in the node. */
|
||||
D_TextLine *node = PushStruct(scratch.arena, D_TextLine);
|
||||
node->line_width = line_width;
|
||||
node->num_glyphs = num_line_glyphs;
|
||||
node->glyphs = line_glyphs;
|
||||
if (last_line)
|
||||
{
|
||||
last_line->next = node;
|
||||
}
|
||||
else
|
||||
{
|
||||
first_line = node;
|
||||
first_line_top_offset = top_offset;
|
||||
}
|
||||
last_line = node;
|
||||
last_line_bottom_offset = bottom_offset;
|
||||
widest_line = MaxF32(widest_line, line_width);
|
||||
++num_lines;
|
||||
line_done = 1;
|
||||
}
|
||||
EndCodepointIter(&iter);
|
||||
}
|
||||
|
||||
//- Determine text bounds
|
||||
|
||||
Rect bounds = ZI;
|
||||
bounds.x = params.pos.x;
|
||||
bounds.y = params.pos.y;
|
||||
bounds.width = widest_line;
|
||||
bounds.height = num_lines * line_spacing + first_line_top_offset + last_line_bottom_offset;
|
||||
|
||||
/* Offset bounds X */
|
||||
switch (params.offset_x)
|
||||
{
|
||||
case DRAW_TEXT_OFFSET_X_LEFT: break;
|
||||
case DRAW_TEXT_OFFSET_X_CENTER:
|
||||
else
|
||||
{
|
||||
bounds.x -= bounds.width / 2.f;
|
||||
} break;
|
||||
case DRAW_TEXT_OFFSET_X_RIGHT:
|
||||
{
|
||||
bounds.x -= bounds.width;
|
||||
} break;
|
||||
}
|
||||
|
||||
/* Offset bounds Y */
|
||||
switch (params.offset_y)
|
||||
{
|
||||
case DRAW_TEXT_OFFSET_Y_TOP: break;
|
||||
case DRAW_TEXT_OFFSET_Y_CENTER:
|
||||
{
|
||||
bounds.y -= bounds.height / 2.f;
|
||||
} break;
|
||||
case DRAW_TEXT_OFFSET_Y_BOTTOM:
|
||||
{
|
||||
if (last_line)
|
||||
{
|
||||
bounds.y -= bounds.height + last_line_bottom_offset;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
//- Draw lines
|
||||
|
||||
u64 line_number = 0;
|
||||
for (D_TextLine *line = first_line; line; line = line->next)
|
||||
{
|
||||
Vec2 draw_pos = bounds.pos;
|
||||
draw_pos.y += line_number * line_spacing - first_line_top_offset;
|
||||
|
||||
/* Alignment */
|
||||
switch (params.alignment)
|
||||
{
|
||||
case DRAW_TEXT_ALIGNMENT_LEFT: break;
|
||||
case DRAW_TEXT_ALIGNMENT_CENTER:
|
||||
{
|
||||
draw_pos.x += (bounds.width - line->line_width) / 2.f;
|
||||
} break;
|
||||
case DRAW_TEXT_ALIGNMENT_RIGHT:
|
||||
{
|
||||
draw_pos.x += bounds.width - line->line_width;
|
||||
} break;
|
||||
u32 codepoint = iter.codepoint;
|
||||
if (codepoint == '\n')
|
||||
{
|
||||
line_done = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
D_TextGlyph *tg = PushStruct(scratch.arena, D_TextGlyph);
|
||||
++num_line_glyphs;
|
||||
F_Glyph *glyph = F_GetGlyph(params.font, codepoint);
|
||||
tg->off_x = glyph->off_x * params.scale;
|
||||
tg->off_y = glyph->off_y * params.scale;
|
||||
tg->width = glyph->width * params.scale;
|
||||
tg->height = glyph->height * params.scale;
|
||||
tg->advance = glyph->advance * params.scale;
|
||||
Rect glyph_atlas_rect = glyph->atlas_rect;
|
||||
tg->clip = (ClipRect) {
|
||||
{
|
||||
glyph_atlas_rect.x * inv_font_image_width,
|
||||
glyph_atlas_rect.y * inv_font_image_height
|
||||
},
|
||||
{
|
||||
(glyph_atlas_rect.x + glyph_atlas_rect.width) * inv_font_image_width,
|
||||
(glyph_atlas_rect.y + glyph_atlas_rect.height) * inv_font_image_height
|
||||
}
|
||||
};
|
||||
line_width += tg->advance;
|
||||
top_offset = MinF32(top_offset, tg->off_y);
|
||||
bottom_offset = MaxF32(bottom_offset, tg->off_y + tg->height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Draw glyphs in line */
|
||||
for (u64 i = 0; i < line->num_glyphs; ++i)
|
||||
{
|
||||
D_TextGlyph *tg = &line->glyphs[i];
|
||||
Vec2 pos = VEC2(draw_pos.x + tg->off_x, draw_pos.y + tg->off_y);
|
||||
Vec2 size = VEC2(tg->width, tg->height);
|
||||
Xform xf = XformFromRect(RectFromVec2(pos, size));
|
||||
D_DrawUiRect(sig, D_UIRECTPARAMS(.xf = xf, .texture = params.font->texture, .tint = params.color, .clip = tg->clip));
|
||||
draw_pos.x += tg->advance;
|
||||
/* Line ended */
|
||||
/* TODO: Only create nodes for non-empty lines. Embed line number in the node. */
|
||||
D_TextLine *node = PushStruct(scratch.arena, D_TextLine);
|
||||
node->line_width = line_width;
|
||||
node->num_glyphs = num_line_glyphs;
|
||||
node->glyphs = line_glyphs;
|
||||
if (last_line)
|
||||
{
|
||||
last_line->next = node;
|
||||
}
|
||||
else
|
||||
{
|
||||
first_line = node;
|
||||
first_line_top_offset = top_offset;
|
||||
}
|
||||
last_line = node;
|
||||
last_line_bottom_offset = bottom_offset;
|
||||
widest_line = MaxF32(widest_line, line_width);
|
||||
++num_lines;
|
||||
}
|
||||
EndCodepointIter(&iter);
|
||||
}
|
||||
|
||||
}
|
||||
++line_number;
|
||||
//- Determine text bounds
|
||||
|
||||
Rect bounds = ZI;
|
||||
bounds.x = params.pos.x;
|
||||
bounds.y = params.pos.y;
|
||||
bounds.width = widest_line;
|
||||
bounds.height = num_lines * line_spacing + first_line_top_offset + last_line_bottom_offset;
|
||||
|
||||
/* Offset bounds X */
|
||||
switch (params.offset_x)
|
||||
{
|
||||
case DRAW_TEXT_OFFSET_X_LEFT: break;
|
||||
case DRAW_TEXT_OFFSET_X_CENTER:
|
||||
{
|
||||
bounds.x -= bounds.width / 2.f;
|
||||
} break;
|
||||
case DRAW_TEXT_OFFSET_X_RIGHT:
|
||||
{
|
||||
bounds.x -= bounds.width;
|
||||
} break;
|
||||
}
|
||||
|
||||
/* Offset bounds Y */
|
||||
switch (params.offset_y)
|
||||
{
|
||||
case DRAW_TEXT_OFFSET_Y_TOP: break;
|
||||
case DRAW_TEXT_OFFSET_Y_CENTER:
|
||||
{
|
||||
bounds.y -= bounds.height / 2.f;
|
||||
} break;
|
||||
case DRAW_TEXT_OFFSET_Y_BOTTOM:
|
||||
{
|
||||
if (last_line)
|
||||
{
|
||||
bounds.y -= bounds.height + last_line_bottom_offset;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
//- Draw lines
|
||||
|
||||
u64 line_number = 0;
|
||||
for (D_TextLine *line = first_line; line; line = line->next)
|
||||
{
|
||||
Vec2 draw_pos = bounds.pos;
|
||||
draw_pos.y += line_number * line_spacing - first_line_top_offset;
|
||||
|
||||
/* Alignment */
|
||||
switch (params.alignment)
|
||||
{
|
||||
case DRAW_TEXT_ALIGNMENT_LEFT: break;
|
||||
case DRAW_TEXT_ALIGNMENT_CENTER:
|
||||
{
|
||||
draw_pos.x += (bounds.width - line->line_width) / 2.f;
|
||||
} break;
|
||||
case DRAW_TEXT_ALIGNMENT_RIGHT:
|
||||
{
|
||||
draw_pos.x += bounds.width - line->line_width;
|
||||
} break;
|
||||
}
|
||||
|
||||
EndScratch(scratch);
|
||||
return bounds;
|
||||
/* Draw glyphs in line */
|
||||
for (u64 i = 0; i < line->num_glyphs; ++i)
|
||||
{
|
||||
D_TextGlyph *tg = &line->glyphs[i];
|
||||
Vec2 pos = VEC2(draw_pos.x + tg->off_x, draw_pos.y + tg->off_y);
|
||||
Vec2 size = VEC2(tg->width, tg->height);
|
||||
Xform xf = XformFromRect(RectFromVec2(pos, size));
|
||||
D_DrawUiRect(sig, D_UIRECTPARAMS(.xf = xf, .texture = params.font->texture, .tint = params.color, .clip = tg->clip));
|
||||
draw_pos.x += tg->advance;
|
||||
|
||||
}
|
||||
++line_number;
|
||||
}
|
||||
|
||||
EndScratch(scratch);
|
||||
return bounds;
|
||||
}
|
||||
|
||||
100
src/draw/draw.h
100
src/draw/draw.h
@ -3,17 +3,17 @@
|
||||
|
||||
Struct(D_MaterialParams)
|
||||
{
|
||||
Xform xf;
|
||||
GPU_Resource *texture;
|
||||
ClipRect clip;
|
||||
u32 tint;
|
||||
b32 is_light;
|
||||
Vec3 light_emittance;
|
||||
Xform xf;
|
||||
GPU_Resource *texture;
|
||||
ClipRect clip;
|
||||
u32 tint;
|
||||
b32 is_light;
|
||||
Vec3 light_emittance;
|
||||
};
|
||||
#define D_MATERIALPARAMS(...) ((D_MaterialParams) { \
|
||||
.tint = Color_White, \
|
||||
.clip = AllClipped, \
|
||||
__VA_ARGS__ \
|
||||
.tint = Color_White, \
|
||||
.clip = AllClipped, \
|
||||
__VA_ARGS__ \
|
||||
})
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -21,15 +21,15 @@ Struct(D_MaterialParams)
|
||||
|
||||
Struct(D_UiRectParams)
|
||||
{
|
||||
Xform xf;
|
||||
GPU_Resource *texture;
|
||||
ClipRect clip;
|
||||
u32 tint;
|
||||
Xform xf;
|
||||
GPU_Resource *texture;
|
||||
ClipRect clip;
|
||||
u32 tint;
|
||||
};
|
||||
#define D_UIRECTPARAMS(...) ((D_UiRectParams) { \
|
||||
.tint = Color_White, \
|
||||
.clip = AllClipped, \
|
||||
__VA_ARGS__ \
|
||||
.tint = Color_White, \
|
||||
.clip = AllClipped, \
|
||||
__VA_ARGS__ \
|
||||
})
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -38,9 +38,9 @@ Struct(D_UiRectParams)
|
||||
/* How is text aligned within its area */
|
||||
Enum(D_TextAlignment)
|
||||
{
|
||||
DRAW_TEXT_ALIGNMENT_LEFT, /* Default */
|
||||
DRAW_TEXT_ALIGNMENT_CENTER,
|
||||
DRAW_TEXT_ALIGNMENT_RIGHT
|
||||
DRAW_TEXT_ALIGNMENT_LEFT, /* Default */
|
||||
DRAW_TEXT_ALIGNMENT_CENTER,
|
||||
DRAW_TEXT_ALIGNMENT_RIGHT
|
||||
};
|
||||
|
||||
/* How does the specified text position relate to the text area.
|
||||
@ -48,54 +48,54 @@ Enum(D_TextAlignment)
|
||||
* the specified position. */
|
||||
Enum(D_TextOffsetX)
|
||||
{
|
||||
DRAW_TEXT_OFFSET_X_LEFT, /* Default */
|
||||
DRAW_TEXT_OFFSET_X_CENTER,
|
||||
DRAW_TEXT_OFFSET_X_RIGHT
|
||||
DRAW_TEXT_OFFSET_X_LEFT, /* Default */
|
||||
DRAW_TEXT_OFFSET_X_CENTER,
|
||||
DRAW_TEXT_OFFSET_X_RIGHT
|
||||
};
|
||||
|
||||
Enum(D_TextOffsetY)
|
||||
{
|
||||
DRAW_TEXT_OFFSET_Y_TOP, /* Default */
|
||||
DRAW_TEXT_OFFSET_Y_CENTER,
|
||||
DRAW_TEXT_OFFSET_Y_BOTTOM
|
||||
DRAW_TEXT_OFFSET_Y_TOP, /* Default */
|
||||
DRAW_TEXT_OFFSET_Y_CENTER,
|
||||
DRAW_TEXT_OFFSET_Y_BOTTOM
|
||||
};
|
||||
|
||||
Struct(D_TextGlyph)
|
||||
{
|
||||
f32 off_x;
|
||||
f32 off_y;
|
||||
f32 width;
|
||||
f32 height;
|
||||
f32 advance;
|
||||
ClipRect clip;
|
||||
f32 off_x;
|
||||
f32 off_y;
|
||||
f32 width;
|
||||
f32 height;
|
||||
f32 advance;
|
||||
ClipRect clip;
|
||||
};
|
||||
|
||||
Struct(D_TextLine)
|
||||
{
|
||||
f32 line_width;
|
||||
u32 num_glyphs;
|
||||
D_TextGlyph *glyphs;
|
||||
D_TextLine *next;
|
||||
f32 line_width;
|
||||
u32 num_glyphs;
|
||||
D_TextGlyph *glyphs;
|
||||
D_TextLine *next;
|
||||
};
|
||||
|
||||
Struct(D_TextParams)
|
||||
{
|
||||
F_Font *font;
|
||||
Vec2 pos;
|
||||
f32 scale;
|
||||
u32 color;
|
||||
D_TextAlignment alignment;
|
||||
D_TextOffsetX offset_x;
|
||||
D_TextOffsetY offset_y;
|
||||
String str;
|
||||
F_Font *font;
|
||||
Vec2 pos;
|
||||
f32 scale;
|
||||
u32 color;
|
||||
D_TextAlignment alignment;
|
||||
D_TextOffsetX offset_x;
|
||||
D_TextOffsetY offset_y;
|
||||
String str;
|
||||
};
|
||||
#define D_TEXTPARAMS(...) ((D_TextParams) { \
|
||||
.scale = 1.0, \
|
||||
.alignment = DRAW_TEXT_ALIGNMENT_LEFT, \
|
||||
.offset_x = DRAW_TEXT_OFFSET_X_LEFT, \
|
||||
.offset_y = DRAW_TEXT_OFFSET_Y_TOP, \
|
||||
.color = Color_White, \
|
||||
__VA_ARGS__ \
|
||||
.scale = 1.0, \
|
||||
.alignment = DRAW_TEXT_ALIGNMENT_LEFT, \
|
||||
.offset_x = DRAW_TEXT_OFFSET_X_LEFT, \
|
||||
.offset_y = DRAW_TEXT_OFFSET_Y_TOP, \
|
||||
.color = Color_White, \
|
||||
__VA_ARGS__ \
|
||||
})
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -103,7 +103,7 @@ Struct(D_TextParams)
|
||||
|
||||
Struct(D_SharedState)
|
||||
{
|
||||
GPU_Resource *solid_white_texture;
|
||||
GPU_Resource *solid_white_texture;
|
||||
} extern D_shared_state;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
@ -5,7 +5,7 @@ GC_Ctx GC = Zi;
|
||||
|
||||
void GC_Bootstrap(void)
|
||||
{
|
||||
OnAsyncTick(GC_TickAsync);
|
||||
OnAsyncTick(GC_TickAsync);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -13,15 +13,15 @@ void GC_Bootstrap(void)
|
||||
|
||||
GC_FontKey GC_FontKeyFromResource(ResourceKey resource)
|
||||
{
|
||||
GC_FontKey result = Zi;
|
||||
result.r = resource;
|
||||
return result;
|
||||
GC_FontKey result = Zi;
|
||||
result.r = resource;
|
||||
return result;
|
||||
}
|
||||
|
||||
u64 GC_HashFromGlyphDesc(GC_GlyphDesc desc)
|
||||
{
|
||||
/* TODO: Lower font-size precision to prevent unique hashes for slightly-different font sizes */
|
||||
return RandU64FromSeeds(desc.font.r.v, ((u64)desc.codepoint << 32) | *(u32 *)&desc.font_size);
|
||||
/* TODO: Lower font-size precision to prevent unique hashes for slightly-different font sizes */
|
||||
return RandU64FromSeeds(desc.font.r.v, ((u64)desc.codepoint << 32) | *(u32 *)&desc.font_size);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -30,189 +30,189 @@ u64 GC_HashFromGlyphDesc(GC_GlyphDesc desc)
|
||||
/* TODO: Thread-local cache */
|
||||
GC_Run GC_RunFromString(Arena *arena, String str, GC_FontKey font, f32 font_size)
|
||||
{
|
||||
GC_Run result = Zi;
|
||||
TempArena scratch = BeginScratch(arena);
|
||||
Arena *perm = PermArena();
|
||||
GC_Run result = Zi;
|
||||
TempArena scratch = BeginScratch(arena);
|
||||
Arena *perm = PermArena();
|
||||
|
||||
u64 codepoints_count = 0;
|
||||
u32 *codepoints = 0;
|
||||
u64 codepoints_count = 0;
|
||||
u32 *codepoints = 0;
|
||||
{
|
||||
String32 str32 = String32FromString(scratch.arena, str);
|
||||
codepoints_count = str32.len;
|
||||
codepoints = str32.text;
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- Grab glyphs from cache
|
||||
|
||||
u64 ready_glyphs_count = 0;
|
||||
GC_Glyph **ready_glyphs = PushStructsNoZero(scratch.arena, GC_Glyph *, codepoints_count);
|
||||
|
||||
u32 *uncached_codepoints = PushStructsNoZero(scratch.arena, u32, codepoints_count);
|
||||
u64 uncached_codepoints_count = 0;
|
||||
|
||||
/* TODO: Include advances for glyphs in run that have rasterized but not finished uploading to atlas */
|
||||
u64 pending_glyphs_count = 0;
|
||||
{
|
||||
if (codepoints_count > 0)
|
||||
{
|
||||
String32 str32 = String32FromString(scratch.arena, str);
|
||||
codepoints_count = str32.len;
|
||||
codepoints = str32.text;
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- Grab glyphs from cache
|
||||
|
||||
u64 ready_glyphs_count = 0;
|
||||
GC_Glyph **ready_glyphs = PushStructsNoZero(scratch.arena, GC_Glyph *, codepoints_count);
|
||||
|
||||
u32 *uncached_codepoints = PushStructsNoZero(scratch.arena, u32, codepoints_count);
|
||||
u64 uncached_codepoints_count = 0;
|
||||
|
||||
/* TODO: Include advances for glyphs in run that have rasterized but not finished uploading to atlas */
|
||||
u64 pending_glyphs_count = 0;
|
||||
{
|
||||
if (codepoints_count > 0)
|
||||
Lock lock = LockS(&GC.glyphs_mutex);
|
||||
{
|
||||
i64 completion = G_CompletionValueFromQueue(G_QueueKind_AsyncCopy);
|
||||
for (u64 codepoint_idx = 0; codepoint_idx < codepoints_count; ++codepoint_idx)
|
||||
{
|
||||
Lock lock = LockS(&GC.glyphs_mutex);
|
||||
{
|
||||
i64 completion = G_CompletionValueFromQueue(G_QueueKind_AsyncCopy);
|
||||
for (u64 codepoint_idx = 0; codepoint_idx < codepoints_count; ++codepoint_idx)
|
||||
{
|
||||
u32 codepoint = codepoints[codepoint_idx];
|
||||
u32 codepoint = codepoints[codepoint_idx];
|
||||
|
||||
GC_GlyphDesc desc = Zi;
|
||||
desc.font = font;
|
||||
desc.font_size = font_size;
|
||||
desc.codepoint = codepoint;
|
||||
GC_GlyphDesc desc = Zi;
|
||||
desc.font = font;
|
||||
desc.font_size = font_size;
|
||||
desc.codepoint = codepoint;
|
||||
|
||||
u64 hash = GC_HashFromGlyphDesc(desc);
|
||||
GC_GlyphBin *bin = &GC.glyph_bins[hash % countof(GC.glyph_bins)];
|
||||
GC_Glyph *glyph = bin->first;
|
||||
for (; glyph; glyph = glyph->next)
|
||||
{
|
||||
if (glyph->hash == hash) break;
|
||||
}
|
||||
u64 hash = GC_HashFromGlyphDesc(desc);
|
||||
GC_GlyphBin *bin = &GC.glyph_bins[hash % countof(GC.glyph_bins)];
|
||||
GC_Glyph *glyph = bin->first;
|
||||
for (; glyph; glyph = glyph->next)
|
||||
{
|
||||
if (glyph->hash == hash) break;
|
||||
}
|
||||
|
||||
if (glyph == 0)
|
||||
{
|
||||
uncached_codepoints[uncached_codepoints_count] = codepoint;
|
||||
uncached_codepoints_count += 1;
|
||||
}
|
||||
else if (completion < Atomic64Fetch(&glyph->async_copy_completion_target))
|
||||
{
|
||||
pending_glyphs_count += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ready_glyphs[ready_glyphs_count] = glyph;
|
||||
ready_glyphs_count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
Unlock(&lock);
|
||||
if (glyph == 0)
|
||||
{
|
||||
uncached_codepoints[uncached_codepoints_count] = codepoint;
|
||||
uncached_codepoints_count += 1;
|
||||
}
|
||||
else if (completion < Atomic64Fetch(&glyph->async_copy_completion_target))
|
||||
{
|
||||
pending_glyphs_count += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ready_glyphs[ready_glyphs_count] = glyph;
|
||||
ready_glyphs_count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
Unlock(&lock);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- Create cache entries
|
||||
//////////////////////////////
|
||||
//- Create cache entries
|
||||
|
||||
u64 submit_cmds_count = 0;
|
||||
GC_Cmd *submit_cmds = PushStructsNoZero(scratch.arena, GC_Cmd, uncached_codepoints_count);
|
||||
if (uncached_codepoints_count > 0)
|
||||
u64 submit_cmds_count = 0;
|
||||
GC_Cmd *submit_cmds = PushStructsNoZero(scratch.arena, GC_Cmd, uncached_codepoints_count);
|
||||
if (uncached_codepoints_count > 0)
|
||||
{
|
||||
Lock lock = LockE(&GC.glyphs_mutex);
|
||||
{
|
||||
Lock lock = LockE(&GC.glyphs_mutex);
|
||||
for (u64 uncached_codepoint_idx = 0; uncached_codepoint_idx < uncached_codepoints_count; ++uncached_codepoint_idx)
|
||||
{
|
||||
GC_GlyphDesc desc = Zi;
|
||||
desc.font = font;
|
||||
desc.font_size = font_size;
|
||||
desc.codepoint = uncached_codepoints[uncached_codepoint_idx];
|
||||
|
||||
u64 hash = GC_HashFromGlyphDesc(desc);
|
||||
GC_GlyphBin *bin = &GC.glyph_bins[hash % countof(GC.glyph_bins)];
|
||||
GC_Glyph *glyph = bin->first;
|
||||
for (; glyph; glyph = glyph->next)
|
||||
{
|
||||
for (u64 uncached_codepoint_idx = 0; uncached_codepoint_idx < uncached_codepoints_count; ++uncached_codepoint_idx)
|
||||
{
|
||||
GC_GlyphDesc desc = Zi;
|
||||
desc.font = font;
|
||||
desc.font_size = font_size;
|
||||
desc.codepoint = uncached_codepoints[uncached_codepoint_idx];
|
||||
|
||||
u64 hash = GC_HashFromGlyphDesc(desc);
|
||||
GC_GlyphBin *bin = &GC.glyph_bins[hash % countof(GC.glyph_bins)];
|
||||
GC_Glyph *glyph = bin->first;
|
||||
for (; glyph; glyph = glyph->next)
|
||||
{
|
||||
if (glyph->hash == hash) break;
|
||||
}
|
||||
|
||||
if (glyph == 0)
|
||||
{
|
||||
glyph = PushStruct(perm, GC_Glyph);
|
||||
glyph->desc = desc;
|
||||
glyph->hash = hash;
|
||||
Atomic64FetchSet(&glyph->async_copy_completion_target, I64Max);
|
||||
SllStackPush(bin->first, glyph);
|
||||
/* Create cmd */
|
||||
{
|
||||
GC_Cmd *cmd = &submit_cmds[submit_cmds_count];
|
||||
cmd->glyph = glyph;
|
||||
++submit_cmds_count;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Unlock(&lock);
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- Submit cmds
|
||||
|
||||
if (submit_cmds_count > 0)
|
||||
{
|
||||
Lock lock = LockE(&GC.submit.mutex);
|
||||
for (u64 cmd_idx = 0; cmd_idx < submit_cmds_count; ++cmd_idx)
|
||||
{
|
||||
GC_Cmd *src = &submit_cmds[cmd_idx];
|
||||
GC_CmdNode *n = GC.submit.first_free;
|
||||
if (n)
|
||||
{
|
||||
SllStackPop(GC.submit.first_free);
|
||||
ZeroStruct(n);
|
||||
}
|
||||
else
|
||||
{
|
||||
n = PushStruct(perm, GC_CmdNode);
|
||||
}
|
||||
n->cmd = *src;
|
||||
GC.submit.count += 1;
|
||||
SllQueuePush(GC.submit.first, GC.submit.last, n);
|
||||
}
|
||||
Unlock(&lock);
|
||||
SignalAsyncTick();
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- Create run from glyphs
|
||||
|
||||
f32 baseline_pos = 0;
|
||||
result.rects = PushStructs(arena, GC_RunRect, ready_glyphs_count);
|
||||
result.rects_count = ready_glyphs_count;
|
||||
for (u64 glyph_idx = 0; glyph_idx < ready_glyphs_count; ++glyph_idx)
|
||||
{
|
||||
GC_Glyph *glyph = ready_glyphs[glyph_idx];
|
||||
GC_RunRect *rect = &result.rects[glyph_idx];
|
||||
|
||||
rect->tex = glyph->atlas->tex_ref;
|
||||
rect->tex_slice = glyph->tex_slice;
|
||||
rect->tex_slice_uv = glyph->tex_slice_uv;
|
||||
|
||||
rect->baseline_pos = baseline_pos;
|
||||
rect->advance = glyph->advance;
|
||||
|
||||
rect->bounds = glyph->bounds;
|
||||
|
||||
if (glyph_idx == 0)
|
||||
{
|
||||
result.bounds = rect->bounds;
|
||||
}
|
||||
else
|
||||
{
|
||||
result.bounds = UnionRng2(result.bounds, rect->bounds);
|
||||
if (glyph->hash == hash) break;
|
||||
}
|
||||
|
||||
baseline_pos += rect->advance;
|
||||
result.baseline_length = MaxF32(result.baseline_length, baseline_pos);
|
||||
if (glyph == 0)
|
||||
{
|
||||
glyph = PushStruct(perm, GC_Glyph);
|
||||
glyph->desc = desc;
|
||||
glyph->hash = hash;
|
||||
Atomic64FetchSet(&glyph->async_copy_completion_target, I64Max);
|
||||
SllStackPush(bin->first, glyph);
|
||||
/* Create cmd */
|
||||
{
|
||||
GC_Cmd *cmd = &submit_cmds[submit_cmds_count];
|
||||
cmd->glyph = glyph;
|
||||
++submit_cmds_count;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Unlock(&lock);
|
||||
}
|
||||
|
||||
if (ready_glyphs_count > 0)
|
||||
//////////////////////////////
|
||||
//- Submit cmds
|
||||
|
||||
if (submit_cmds_count > 0)
|
||||
{
|
||||
Lock lock = LockE(&GC.submit.mutex);
|
||||
for (u64 cmd_idx = 0; cmd_idx < submit_cmds_count; ++cmd_idx)
|
||||
{
|
||||
GC_Glyph *glyph = ready_glyphs[0];
|
||||
result.font_size = glyph->font_size;
|
||||
result.font_ascent = glyph->font_ascent;
|
||||
result.font_descent = glyph->font_descent;
|
||||
result.font_cap = glyph->font_cap;
|
||||
GC_Cmd *src = &submit_cmds[cmd_idx];
|
||||
GC_CmdNode *n = GC.submit.first_free;
|
||||
if (n)
|
||||
{
|
||||
SllStackPop(GC.submit.first_free);
|
||||
ZeroStruct(n);
|
||||
}
|
||||
else
|
||||
{
|
||||
n = PushStruct(perm, GC_CmdNode);
|
||||
}
|
||||
n->cmd = *src;
|
||||
GC.submit.count += 1;
|
||||
SllQueuePush(GC.submit.first, GC.submit.last, n);
|
||||
}
|
||||
Unlock(&lock);
|
||||
SignalAsyncTick();
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- Create run from glyphs
|
||||
|
||||
f32 baseline_pos = 0;
|
||||
result.rects = PushStructs(arena, GC_RunRect, ready_glyphs_count);
|
||||
result.rects_count = ready_glyphs_count;
|
||||
for (u64 glyph_idx = 0; glyph_idx < ready_glyphs_count; ++glyph_idx)
|
||||
{
|
||||
GC_Glyph *glyph = ready_glyphs[glyph_idx];
|
||||
GC_RunRect *rect = &result.rects[glyph_idx];
|
||||
|
||||
rect->tex = glyph->atlas->tex_ref;
|
||||
rect->tex_slice = glyph->tex_slice;
|
||||
rect->tex_slice_uv = glyph->tex_slice_uv;
|
||||
|
||||
rect->baseline_pos = baseline_pos;
|
||||
rect->advance = glyph->advance;
|
||||
|
||||
rect->bounds = glyph->bounds;
|
||||
|
||||
if (glyph_idx == 0)
|
||||
{
|
||||
result.bounds = rect->bounds;
|
||||
}
|
||||
else
|
||||
{
|
||||
result.bounds = UnionRng2(result.bounds, rect->bounds);
|
||||
}
|
||||
|
||||
// result.ready = uncached_codepoints_count == 0 && pending_glyphs_count == 0;
|
||||
result.ready = 1;
|
||||
baseline_pos += rect->advance;
|
||||
result.baseline_length = MaxF32(result.baseline_length, baseline_pos);
|
||||
}
|
||||
|
||||
EndScratch(scratch);
|
||||
return result;
|
||||
if (ready_glyphs_count > 0)
|
||||
{
|
||||
GC_Glyph *glyph = ready_glyphs[0];
|
||||
result.font_size = glyph->font_size;
|
||||
result.font_ascent = glyph->font_ascent;
|
||||
result.font_descent = glyph->font_descent;
|
||||
result.font_cap = glyph->font_cap;
|
||||
}
|
||||
|
||||
// result.ready = uncached_codepoints_count == 0 && pending_glyphs_count == 0;
|
||||
result.ready = 1;
|
||||
|
||||
EndScratch(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -220,162 +220,162 @@ GC_Run GC_RunFromString(Arena *arena, String str, GC_FontKey font, f32 font_size
|
||||
|
||||
void GC_TickAsync(WaveLaneCtx *lane, AsyncTickCtx *tick)
|
||||
{
|
||||
GC_AsyncCtx *async = &GC.async_ctx;
|
||||
GC_AsyncCtx *async = &GC.async_ctx;
|
||||
|
||||
//////////////////////////////
|
||||
//- Begin tick
|
||||
//////////////////////////////
|
||||
//- Begin tick
|
||||
|
||||
/* TODO: Limit cmds processed per-tick */
|
||||
/* TODO: Limit cmds processed per-tick */
|
||||
|
||||
if (lane->idx == 0)
|
||||
if (lane->idx == 0)
|
||||
{
|
||||
ZeroStruct(&async->cmds);
|
||||
|
||||
Lock lock = LockE(&GC.submit.mutex);
|
||||
{
|
||||
ZeroStruct(&async->cmds);
|
||||
|
||||
Lock lock = LockE(&GC.submit.mutex);
|
||||
{
|
||||
/* Pop cmds from submission queue */
|
||||
async->cmds.count = GC.submit.count;
|
||||
async->cmds.v = PushStructsNoZero(tick->arena, GC_Cmd, GC.submit.count);
|
||||
u64 cmd_idx = 0;
|
||||
for (GC_CmdNode *n = GC.submit.first; n; n = n->next)
|
||||
{
|
||||
async->cmds.v[cmd_idx] = n->cmd;
|
||||
++cmd_idx;
|
||||
}
|
||||
/* Reset submission queue */
|
||||
GC.submit.first_free = GC.submit.first;
|
||||
GC.submit.count = 0;
|
||||
GC.submit.first = 0;
|
||||
GC.submit.last = 0;
|
||||
}
|
||||
Unlock(&lock);
|
||||
/* Pop cmds from submission queue */
|
||||
async->cmds.count = GC.submit.count;
|
||||
async->cmds.v = PushStructsNoZero(tick->arena, GC_Cmd, GC.submit.count);
|
||||
u64 cmd_idx = 0;
|
||||
for (GC_CmdNode *n = GC.submit.first; n; n = n->next)
|
||||
{
|
||||
async->cmds.v[cmd_idx] = n->cmd;
|
||||
++cmd_idx;
|
||||
}
|
||||
/* Reset submission queue */
|
||||
GC.submit.first_free = GC.submit.first;
|
||||
GC.submit.count = 0;
|
||||
GC.submit.first = 0;
|
||||
GC.submit.last = 0;
|
||||
}
|
||||
Unlock(&lock);
|
||||
}
|
||||
|
||||
WaveSync(lane);
|
||||
|
||||
if (async->cmds.count > 0)
|
||||
{
|
||||
//////////////////////////////
|
||||
//- Rasterize glyphs
|
||||
|
||||
/* TODO: Process cmds unevenly to account for varying work size */
|
||||
|
||||
{
|
||||
RngU64 cmd_idxs = WaveIdxRangeFromCount(lane, async->cmds.count);
|
||||
for (u64 cmd_idx = cmd_idxs.min; cmd_idx < cmd_idxs.max; ++cmd_idx)
|
||||
{
|
||||
GC_Cmd *cmd = &async->cmds.v[cmd_idx];
|
||||
GC_Glyph *glyph = cmd->glyph;
|
||||
ResourceKey resource = glyph->desc.font.r;
|
||||
GC_GlyphDesc desc = glyph->desc;
|
||||
TTF_GlyphResult ttf_result = TTF_RasterizeGlyphFromCodepoint(tick->arena, desc.codepoint, resource, desc.font_size);;
|
||||
glyph->font_size = desc.font_size;
|
||||
glyph->font_ascent = ttf_result.font_ascent;
|
||||
glyph->font_descent = ttf_result.font_descent;
|
||||
glyph->font_cap = ttf_result.font_cap;
|
||||
glyph->advance = ttf_result.advance;
|
||||
glyph->bounds = ttf_result.bounds;
|
||||
cmd->rasterized = ttf_result;
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: Only sync first lane? */
|
||||
|
||||
WaveSync(lane);
|
||||
|
||||
if (async->cmds.count > 0)
|
||||
////////////////////////////
|
||||
//- Allocate atlas slices
|
||||
|
||||
if (lane->idx == 0)
|
||||
{
|
||||
//////////////////////////////
|
||||
//- Rasterize glyphs
|
||||
G_CommandListHandle cl = G_PrepareCommandList(G_QueueKind_AsyncCopy);
|
||||
for (u64 cmd_idx = 0; cmd_idx < async->cmds.count; ++cmd_idx)
|
||||
{
|
||||
GC_Cmd *cmd = &async->cmds.v[cmd_idx];
|
||||
GC_Glyph *glyph = cmd->glyph;
|
||||
GC_GlyphDesc desc = glyph->desc;
|
||||
TTF_GlyphResult ttf_result = cmd->rasterized;
|
||||
|
||||
/* TODO: Process cmds unevenly to account for varying work size */
|
||||
Vec2I32 image_dims = ttf_result.image_dims;
|
||||
|
||||
/* TODO: Use a more efficient atlas packing algorithm for less wasted space `*/
|
||||
GC_Atlas *atlas = GC.first_atlas;
|
||||
b32 can_use_atlas = 0;
|
||||
Vec2I32 pos_in_atlas = Zi;
|
||||
while (can_use_atlas == 0)
|
||||
{
|
||||
RngU64 cmd_idxs = WaveIdxRangeFromCount(lane, async->cmds.count);
|
||||
for (u64 cmd_idx = cmd_idxs.min; cmd_idx < cmd_idxs.max; ++cmd_idx)
|
||||
/* Create atlas */
|
||||
if (!atlas)
|
||||
{
|
||||
Arena *perm = PermArena();
|
||||
atlas = PushStruct(perm, GC_Atlas);
|
||||
atlas->dims = VEC2I32(1024, 1024);
|
||||
{
|
||||
GC_Cmd *cmd = &async->cmds.v[cmd_idx];
|
||||
GC_Glyph *glyph = cmd->glyph;
|
||||
ResourceKey resource = glyph->desc.font.r;
|
||||
GC_GlyphDesc desc = glyph->desc;
|
||||
TTF_GlyphResult ttf_result = TTF_RasterizeGlyphFromCodepoint(tick->arena, desc.codepoint, resource, desc.font_size);;
|
||||
glyph->font_size = desc.font_size;
|
||||
glyph->font_ascent = ttf_result.font_ascent;
|
||||
glyph->font_descent = ttf_result.font_descent;
|
||||
glyph->font_cap = ttf_result.font_cap;
|
||||
glyph->advance = ttf_result.advance;
|
||||
glyph->bounds = ttf_result.bounds;
|
||||
cmd->rasterized = ttf_result;
|
||||
G_ArenaHandle gpu_perm = G_PermArena();
|
||||
atlas->tex = G_PushTexture2D(
|
||||
gpu_perm, cl,
|
||||
G_Format_R8G8B8A8_Unorm_Srgb,
|
||||
atlas->dims,
|
||||
G_Layout_AnyQueue_ShaderRead_CopyRead_CopyWrite_Present,
|
||||
);
|
||||
atlas->tex_ref = G_PushTexture2DRef(gpu_perm, atlas->tex);
|
||||
}
|
||||
SllStackPush(GC.first_atlas, atlas);
|
||||
++GC.atlases_count;
|
||||
}
|
||||
|
||||
/* Determine pos in atlas */
|
||||
pos_in_atlas = atlas->cur_pos;
|
||||
atlas->cur_row_height = MaxI32(atlas->cur_row_height, image_dims.y);
|
||||
if (pos_in_atlas.x + image_dims.x > atlas->dims.x);
|
||||
{
|
||||
atlas->cur_pos.x = 0;
|
||||
atlas->cur_pos.y += atlas->cur_row_height;
|
||||
atlas->cur_row_height = image_dims.y;
|
||||
}
|
||||
atlas->cur_pos.x += image_dims.x;
|
||||
if (atlas->cur_pos.x < atlas->dims.x && atlas->cur_pos.y < atlas->dims.y)
|
||||
{
|
||||
can_use_atlas = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
atlas = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: Only sync first lane? */
|
||||
/* Atlas info */
|
||||
glyph->atlas = atlas;
|
||||
glyph->tex_slice = RNG2I32(pos_in_atlas, AddVec2I32(pos_in_atlas, image_dims));
|
||||
glyph->tex_slice_uv.p0.x = (f32)glyph->tex_slice.p0.x / (f32)atlas->dims.x;
|
||||
glyph->tex_slice_uv.p0.y = (f32)glyph->tex_slice.p0.y / (f32)atlas->dims.x;
|
||||
glyph->tex_slice_uv.p1.x = (f32)glyph->tex_slice.p1.x / (f32)atlas->dims.x;
|
||||
glyph->tex_slice_uv.p1.y = (f32)glyph->tex_slice.p1.y / (f32)atlas->dims.x;
|
||||
|
||||
WaveSync(lane);
|
||||
|
||||
////////////////////////////
|
||||
//- Allocate atlas slices
|
||||
|
||||
if (lane->idx == 0)
|
||||
/* Copy to atlas */
|
||||
u32 *image_pixels = ttf_result.image_pixels;
|
||||
if (image_dims.x > 0 && image_dims.y > 0)
|
||||
{
|
||||
G_CommandListHandle cl = G_PrepareCommandList(G_QueueKind_AsyncCopy);
|
||||
for (u64 cmd_idx = 0; cmd_idx < async->cmds.count; ++cmd_idx)
|
||||
{
|
||||
GC_Cmd *cmd = &async->cmds.v[cmd_idx];
|
||||
GC_Glyph *glyph = cmd->glyph;
|
||||
GC_GlyphDesc desc = glyph->desc;
|
||||
TTF_GlyphResult ttf_result = cmd->rasterized;
|
||||
|
||||
Vec2I32 image_dims = ttf_result.image_dims;
|
||||
|
||||
/* TODO: Use a more efficient atlas packing algorithm for less wasted space `*/
|
||||
GC_Atlas *atlas = GC.first_atlas;
|
||||
b32 can_use_atlas = 0;
|
||||
Vec2I32 pos_in_atlas = Zi;
|
||||
while (can_use_atlas == 0)
|
||||
{
|
||||
/* Create atlas */
|
||||
if (!atlas)
|
||||
{
|
||||
Arena *perm = PermArena();
|
||||
atlas = PushStruct(perm, GC_Atlas);
|
||||
atlas->dims = VEC2I32(1024, 1024);
|
||||
{
|
||||
G_ArenaHandle gpu_perm = G_PermArena();
|
||||
atlas->tex = G_PushTexture2D(
|
||||
gpu_perm, cl,
|
||||
G_Format_R8G8B8A8_Unorm_Srgb,
|
||||
atlas->dims,
|
||||
G_Layout_AnyQueue_ShaderRead_CopyRead_CopyWrite_Present,
|
||||
);
|
||||
atlas->tex_ref = G_PushTexture2DRef(gpu_perm, atlas->tex);
|
||||
}
|
||||
SllStackPush(GC.first_atlas, atlas);
|
||||
++GC.atlases_count;
|
||||
}
|
||||
|
||||
/* Determine pos in atlas */
|
||||
pos_in_atlas = atlas->cur_pos;
|
||||
atlas->cur_row_height = MaxI32(atlas->cur_row_height, image_dims.y);
|
||||
if (pos_in_atlas.x + image_dims.x > atlas->dims.x);
|
||||
{
|
||||
atlas->cur_pos.x = 0;
|
||||
atlas->cur_pos.y += atlas->cur_row_height;
|
||||
atlas->cur_row_height = image_dims.y;
|
||||
}
|
||||
atlas->cur_pos.x += image_dims.x;
|
||||
if (atlas->cur_pos.x < atlas->dims.x && atlas->cur_pos.y < atlas->dims.y)
|
||||
{
|
||||
can_use_atlas = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
atlas = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Atlas info */
|
||||
glyph->atlas = atlas;
|
||||
glyph->tex_slice = RNG2I32(pos_in_atlas, AddVec2I32(pos_in_atlas, image_dims));
|
||||
glyph->tex_slice_uv.p0.x = (f32)glyph->tex_slice.p0.x / (f32)atlas->dims.x;
|
||||
glyph->tex_slice_uv.p0.y = (f32)glyph->tex_slice.p0.y / (f32)atlas->dims.x;
|
||||
glyph->tex_slice_uv.p1.x = (f32)glyph->tex_slice.p1.x / (f32)atlas->dims.x;
|
||||
glyph->tex_slice_uv.p1.y = (f32)glyph->tex_slice.p1.y / (f32)atlas->dims.x;
|
||||
|
||||
/* Copy to atlas */
|
||||
u32 *image_pixels = ttf_result.image_pixels;
|
||||
if (image_dims.x > 0 && image_dims.y > 0)
|
||||
{
|
||||
G_CopyCpuToTexture(
|
||||
cl,
|
||||
glyph->atlas->tex, VEC3I32(glyph->tex_slice.p0.x, glyph->tex_slice.p0.y, 0),
|
||||
image_pixels, VEC3I32(image_dims.x, image_dims.y, 1),
|
||||
RNG3I32(
|
||||
VEC3I32(0, 0, 0),
|
||||
VEC3I32(image_dims.x, image_dims.y, 1)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
i64 completion_target = G_CommitCommandList(cl);
|
||||
|
||||
/* Update completion targets */
|
||||
for (u64 cmd_idx = 0; cmd_idx < async->cmds.count; ++cmd_idx)
|
||||
{
|
||||
GC_Cmd *cmd = &async->cmds.v[cmd_idx];
|
||||
GC_Glyph *glyph = cmd->glyph;
|
||||
Atomic64Set(&glyph->async_copy_completion_target, completion_target);
|
||||
}
|
||||
G_CopyCpuToTexture(
|
||||
cl,
|
||||
glyph->atlas->tex, VEC3I32(glyph->tex_slice.p0.x, glyph->tex_slice.p0.y, 0),
|
||||
image_pixels, VEC3I32(image_dims.x, image_dims.y, 1),
|
||||
RNG3I32(
|
||||
VEC3I32(0, 0, 0),
|
||||
VEC3I32(image_dims.x, image_dims.y, 1)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
i64 completion_target = G_CommitCommandList(cl);
|
||||
|
||||
/* Update completion targets */
|
||||
for (u64 cmd_idx = 0; cmd_idx < async->cmds.count; ++cmd_idx)
|
||||
{
|
||||
GC_Cmd *cmd = &async->cmds.v[cmd_idx];
|
||||
GC_Glyph *glyph = cmd->glyph;
|
||||
Atomic64Set(&glyph->async_copy_completion_target, completion_target);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
|
||||
Struct(GC_FontKey)
|
||||
{
|
||||
ResourceKey r;
|
||||
ResourceKey r;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -11,13 +11,13 @@ Struct(GC_FontKey)
|
||||
|
||||
Struct(GC_Atlas)
|
||||
{
|
||||
GC_Atlas *next;
|
||||
GC_Atlas *next;
|
||||
|
||||
Vec2I32 dims;
|
||||
G_ResourceHandle tex;
|
||||
G_Texture2DRef tex_ref;
|
||||
Vec2I32 cur_pos;
|
||||
i32 cur_row_height;
|
||||
Vec2I32 dims;
|
||||
G_ResourceHandle tex;
|
||||
G_Texture2DRef tex_ref;
|
||||
Vec2I32 cur_pos;
|
||||
i32 cur_row_height;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -25,38 +25,38 @@ Struct(GC_Atlas)
|
||||
|
||||
Struct(GC_GlyphDesc)
|
||||
{
|
||||
GC_FontKey font;
|
||||
f32 font_size;
|
||||
u32 codepoint;
|
||||
GC_FontKey font;
|
||||
f32 font_size;
|
||||
u32 codepoint;
|
||||
};
|
||||
|
||||
Struct(GC_Glyph)
|
||||
{
|
||||
GC_Glyph *next;
|
||||
GC_Glyph *next;
|
||||
|
||||
GC_GlyphDesc desc;
|
||||
u64 hash;
|
||||
Atomic64 async_copy_completion_target;
|
||||
GC_GlyphDesc desc;
|
||||
u64 hash;
|
||||
Atomic64 async_copy_completion_target;
|
||||
|
||||
/* Font info */
|
||||
f32 font_size;
|
||||
f32 font_ascent;
|
||||
f32 font_descent;
|
||||
f32 font_cap;
|
||||
/* Font info */
|
||||
f32 font_size;
|
||||
f32 font_ascent;
|
||||
f32 font_descent;
|
||||
f32 font_cap;
|
||||
|
||||
/* Layout info */
|
||||
f32 advance;
|
||||
Rng2 bounds;
|
||||
/* Layout info */
|
||||
f32 advance;
|
||||
Rng2 bounds;
|
||||
|
||||
/* Atlas info */
|
||||
GC_Atlas *atlas;
|
||||
Rng2I32 tex_slice;
|
||||
Rng2 tex_slice_uv;
|
||||
/* Atlas info */
|
||||
GC_Atlas *atlas;
|
||||
Rng2I32 tex_slice;
|
||||
Rng2 tex_slice_uv;
|
||||
};
|
||||
|
||||
Struct(GC_GlyphBin)
|
||||
{
|
||||
GC_Glyph *first;
|
||||
GC_Glyph *first;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -64,30 +64,30 @@ Struct(GC_GlyphBin)
|
||||
|
||||
Struct(GC_RunRect)
|
||||
{
|
||||
Rng2 bounds; /* Visual bounds in relation to the baseline */
|
||||
f32 baseline_pos; /* Horizontal distance from start of baseline */
|
||||
f32 advance;
|
||||
Rng2 bounds; /* Visual bounds in relation to the baseline */
|
||||
f32 baseline_pos; /* Horizontal distance from start of baseline */
|
||||
f32 advance;
|
||||
|
||||
G_Texture2DRef tex;
|
||||
Rng2I32 tex_slice;
|
||||
Rng2 tex_slice_uv;
|
||||
G_Texture2DRef tex;
|
||||
Rng2I32 tex_slice;
|
||||
Rng2 tex_slice_uv;
|
||||
};
|
||||
|
||||
Struct(GC_Run)
|
||||
{
|
||||
/* Run data */
|
||||
Rng2 bounds; /* Visual bounds of the run in relation to the baseline */
|
||||
f32 baseline_length;
|
||||
u64 rects_count;
|
||||
GC_RunRect *rects;
|
||||
/* Run data */
|
||||
Rng2 bounds; /* Visual bounds of the run in relation to the baseline */
|
||||
f32 baseline_length;
|
||||
u64 rects_count;
|
||||
GC_RunRect *rects;
|
||||
|
||||
/* Font info */
|
||||
f32 font_size;
|
||||
f32 font_ascent;
|
||||
f32 font_descent;
|
||||
f32 font_cap;
|
||||
/* Font info */
|
||||
f32 font_size;
|
||||
f32 font_ascent;
|
||||
f32 font_descent;
|
||||
f32 font_cap;
|
||||
|
||||
b32 ready;
|
||||
b32 ready;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -95,16 +95,16 @@ Struct(GC_Run)
|
||||
|
||||
Struct(GC_Cmd)
|
||||
{
|
||||
GC_Glyph *glyph;
|
||||
GC_Glyph *glyph;
|
||||
|
||||
/* Async temporary data */
|
||||
TTF_GlyphResult rasterized;
|
||||
/* Async temporary data */
|
||||
TTF_GlyphResult rasterized;
|
||||
};
|
||||
|
||||
Struct(GC_CmdNode)
|
||||
{
|
||||
GC_CmdNode *next;
|
||||
GC_Cmd cmd;
|
||||
GC_CmdNode *next;
|
||||
GC_Cmd cmd;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -112,31 +112,31 @@ Struct(GC_CmdNode)
|
||||
|
||||
Struct(GC_AsyncCtx)
|
||||
{
|
||||
struct
|
||||
{
|
||||
u64 count;
|
||||
GC_Cmd *v;
|
||||
} cmds;
|
||||
struct
|
||||
{
|
||||
u64 count;
|
||||
GC_Cmd *v;
|
||||
} cmds;
|
||||
};
|
||||
|
||||
Struct(GC_Ctx)
|
||||
{
|
||||
Mutex glyphs_mutex;
|
||||
GC_GlyphBin glyph_bins[16384];
|
||||
Mutex glyphs_mutex;
|
||||
GC_GlyphBin glyph_bins[16384];
|
||||
|
||||
u64 atlases_count;
|
||||
GC_Atlas *first_atlas;
|
||||
u64 atlases_count;
|
||||
GC_Atlas *first_atlas;
|
||||
|
||||
struct
|
||||
{
|
||||
Mutex mutex;
|
||||
u64 count;
|
||||
GC_CmdNode *first;
|
||||
GC_CmdNode *last;
|
||||
GC_CmdNode *first_free;
|
||||
} submit;
|
||||
struct
|
||||
{
|
||||
Mutex mutex;
|
||||
u64 count;
|
||||
GC_CmdNode *first;
|
||||
GC_CmdNode *last;
|
||||
GC_CmdNode *first_free;
|
||||
} submit;
|
||||
|
||||
GC_AsyncCtx async_ctx;
|
||||
GC_AsyncCtx async_ctx;
|
||||
};
|
||||
|
||||
extern GC_Ctx GC;
|
||||
|
||||
@ -6,57 +6,57 @@ ThreadLocal G_ArenaHandle G_t_perm_arena = Zi;
|
||||
|
||||
void G_BootstrapCommon(void)
|
||||
{
|
||||
G_SharedUtilState *g = &G_shared_util_state;
|
||||
G_SharedUtilState *g = &G_shared_util_state;
|
||||
|
||||
G_ArenaHandle gpu_perm = G_PermArena();
|
||||
G_ArenaHandle gpu_perm = G_PermArena();
|
||||
|
||||
G_CommandListHandle cl = G_PrepareCommandList(G_QueueKind_Direct);
|
||||
G_CommandListHandle cl = G_PrepareCommandList(G_QueueKind_Direct);
|
||||
{
|
||||
/* Init quad index buffer */
|
||||
{
|
||||
/* Init quad index buffer */
|
||||
{
|
||||
G_ResourceHandle quad_indices = Zi;
|
||||
u16 quad_data[6] = { 0, 1, 2, 0, 2, 3 };
|
||||
quad_indices = G_PushBuffer(gpu_perm, cl, u16, countof(quad_data));
|
||||
G_CopyCpuToBuffer(cl, quad_indices, 0, quad_data, RNGU64(0, sizeof(quad_data)));
|
||||
g->quad_indices = G_IdxBuff16(quad_indices);
|
||||
}
|
||||
|
||||
/* Init point sampler */
|
||||
{
|
||||
G_ResourceHandle pt_sampler = G_PushSampler(gpu_perm, cl, .filter = G_Filter_MinMagMipPoint);
|
||||
g->basic_sampler = G_PushSamplerStateRef(gpu_perm, pt_sampler);
|
||||
}
|
||||
|
||||
/* Init noise texture */
|
||||
{
|
||||
G_ResourceHandle noise_tex = Zi;
|
||||
String noise_data = DataFromResource(ResourceKeyFromStore(&G_Resources, Lit("noise_128x128x64_16.dat")));
|
||||
Vec3I32 noise_dims = VEC3I32(128, 128, 64);
|
||||
if (noise_data.len != noise_dims.x * noise_dims.y * noise_dims.z * 2)
|
||||
{
|
||||
Panic(Lit("Unexpected noise texture size"));
|
||||
}
|
||||
noise_tex = G_PushTexture3D(
|
||||
gpu_perm, cl,
|
||||
G_Format_R16_Uint,
|
||||
noise_dims,
|
||||
G_Layout_AnyQueue_ShaderRead_CopyRead_CopyWrite_Present
|
||||
);
|
||||
G_CopyCpuToTexture(
|
||||
cl,
|
||||
noise_tex, VEC3I32(0, 0, 0),
|
||||
noise_data.text, noise_dims,
|
||||
RNG3I32(VEC3I32(0, 0, 0), noise_dims)
|
||||
);
|
||||
|
||||
g->basic_noise = G_PushTexture3DRef(gpu_perm, noise_tex);
|
||||
}
|
||||
|
||||
G_ResourceHandle quad_indices = Zi;
|
||||
u16 quad_data[6] = { 0, 1, 2, 0, 2, 3 };
|
||||
quad_indices = G_PushBuffer(gpu_perm, cl, u16, countof(quad_data));
|
||||
G_CopyCpuToBuffer(cl, quad_indices, 0, quad_data, RNGU64(0, sizeof(quad_data)));
|
||||
g->quad_indices = G_IdxBuff16(quad_indices);
|
||||
}
|
||||
G_CommitCommandList(cl);
|
||||
|
||||
/* Barrier all queues until direct queue finishes initializing resources */
|
||||
G_Sync(G_QueueMask_Direct, G_QueueMask_All);
|
||||
/* Init point sampler */
|
||||
{
|
||||
G_ResourceHandle pt_sampler = G_PushSampler(gpu_perm, cl, .filter = G_Filter_MinMagMipPoint);
|
||||
g->basic_sampler = G_PushSamplerStateRef(gpu_perm, pt_sampler);
|
||||
}
|
||||
|
||||
/* Init noise texture */
|
||||
{
|
||||
G_ResourceHandle noise_tex = Zi;
|
||||
String noise_data = DataFromResource(ResourceKeyFromStore(&G_Resources, Lit("noise_128x128x64_16.dat")));
|
||||
Vec3I32 noise_dims = VEC3I32(128, 128, 64);
|
||||
if (noise_data.len != noise_dims.x * noise_dims.y * noise_dims.z * 2)
|
||||
{
|
||||
Panic(Lit("Unexpected noise texture size"));
|
||||
}
|
||||
noise_tex = G_PushTexture3D(
|
||||
gpu_perm, cl,
|
||||
G_Format_R16_Uint,
|
||||
noise_dims,
|
||||
G_Layout_AnyQueue_ShaderRead_CopyRead_CopyWrite_Present
|
||||
);
|
||||
G_CopyCpuToTexture(
|
||||
cl,
|
||||
noise_tex, VEC3I32(0, 0, 0),
|
||||
noise_data.text, noise_dims,
|
||||
RNG3I32(VEC3I32(0, 0, 0), noise_dims)
|
||||
);
|
||||
|
||||
g->basic_noise = G_PushTexture3DRef(gpu_perm, noise_tex);
|
||||
}
|
||||
|
||||
}
|
||||
G_CommitCommandList(cl);
|
||||
|
||||
/* Barrier all queues until direct queue finishes initializing resources */
|
||||
G_Sync(G_QueueMask_Direct, G_QueueMask_All);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -66,56 +66,56 @@ void G_BootstrapCommon(void)
|
||||
|
||||
G_ArenaHandle G_PermArena(void)
|
||||
{
|
||||
G_ArenaHandle perm = G_t_perm_arena;
|
||||
if (G_IsArenaNil(perm))
|
||||
{
|
||||
G_t_perm_arena = G_AcquireArena();
|
||||
perm = G_t_perm_arena;
|
||||
}
|
||||
return perm;
|
||||
G_ArenaHandle perm = G_t_perm_arena;
|
||||
if (G_IsArenaNil(perm))
|
||||
{
|
||||
G_t_perm_arena = G_AcquireArena();
|
||||
perm = G_t_perm_arena;
|
||||
}
|
||||
return perm;
|
||||
}
|
||||
|
||||
//- Cpu -> Gpu upload
|
||||
|
||||
G_ResourceHandle G_PushBufferFromString_(G_ArenaHandle gpu_arena, G_CommandListHandle cl, String src, G_BufferDesc desc)
|
||||
{
|
||||
G_ResourceHandle buffer = G_PushResource(gpu_arena, cl, (G_ResourceDesc) { .kind = G_ResourceKind_Buffer, .buffer = desc });
|
||||
G_CopyCpuToBuffer(cl, buffer, 0, src.text, RNGU64(0, src.len));
|
||||
G_MemorySync(
|
||||
cl, buffer,
|
||||
G_Stage_Copy, G_Access_CopyWrite,
|
||||
G_Stage_All, G_Access_All
|
||||
);
|
||||
return buffer;
|
||||
G_ResourceHandle buffer = G_PushResource(gpu_arena, cl, (G_ResourceDesc) { .kind = G_ResourceKind_Buffer, .buffer = desc });
|
||||
G_CopyCpuToBuffer(cl, buffer, 0, src.text, RNGU64(0, src.len));
|
||||
G_MemorySync(
|
||||
cl, buffer,
|
||||
G_Stage_Copy, G_Access_CopyWrite,
|
||||
G_Stage_All, G_Access_All
|
||||
);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
//- Viewport / scissor
|
||||
|
||||
Rng3 G_ViewportFromTexture(G_ResourceHandle texture)
|
||||
{
|
||||
Vec2I32 dims = G_Count2D(texture);
|
||||
return RNG3(VEC3(0, 0, 0), VEC3(dims.x, dims.y, 1));
|
||||
Vec2I32 dims = G_Count2D(texture);
|
||||
return RNG3(VEC3(0, 0, 0), VEC3(dims.x, dims.y, 1));
|
||||
}
|
||||
|
||||
Rng2 G_ScissorFromTexture(G_ResourceHandle texture)
|
||||
{
|
||||
Vec2I32 dims = G_Count2D(texture);
|
||||
return RNG2(VEC2(0, 0), VEC2(dims.x, dims.y));
|
||||
Vec2I32 dims = G_Count2D(texture);
|
||||
return RNG2(VEC2(0, 0), VEC2(dims.x, dims.y));
|
||||
}
|
||||
|
||||
//- Shared resources
|
||||
|
||||
G_IndexBufferDesc G_QuadIndices(void)
|
||||
{
|
||||
return G_shared_util_state.quad_indices;
|
||||
return G_shared_util_state.quad_indices;
|
||||
}
|
||||
|
||||
G_SamplerStateRef G_BasicSampler(void)
|
||||
{
|
||||
return G_shared_util_state.basic_sampler;
|
||||
return G_shared_util_state.basic_sampler;
|
||||
}
|
||||
|
||||
G_Texture3DRef G_BasicNoiseTexture(void)
|
||||
{
|
||||
return G_shared_util_state.basic_noise;
|
||||
return G_shared_util_state.basic_noise;
|
||||
}
|
||||
|
||||
@ -3,10 +3,10 @@
|
||||
|
||||
Struct(G_SharedUtilState)
|
||||
{
|
||||
/* Common shared resources */
|
||||
G_IndexBufferDesc quad_indices;
|
||||
G_SamplerStateRef basic_sampler;
|
||||
G_Texture3DRef basic_noise;
|
||||
/* Common shared resources */
|
||||
G_IndexBufferDesc quad_indices;
|
||||
G_SamplerStateRef basic_sampler;
|
||||
G_Texture3DRef basic_noise;
|
||||
} extern G_shared_util_state;
|
||||
|
||||
extern ThreadLocal G_ArenaHandle G_t_perm_arena;
|
||||
@ -27,7 +27,7 @@ G_ArenaHandle G_PermArena(void);
|
||||
|
||||
G_ResourceHandle G_PushBufferFromString_(G_ArenaHandle gpu_arena, G_CommandListHandle cl, String src, G_BufferDesc desc);
|
||||
#define G_PushBufferFromString(_arena, _cl, _src, ...) \
|
||||
G_PushBufferFromString_((_arena), (_cl), (_src), (G_BufferDesc) { .size = (_src).len, __VA_ARGS__ })
|
||||
G_PushBufferFromString_((_arena), (_cl), (_src), (G_BufferDesc) { .size = (_src).len, __VA_ARGS__ })
|
||||
|
||||
//- Viewport / scissor
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -2,9 +2,9 @@
|
||||
//~ DirectX12 libs
|
||||
|
||||
#pragma warning(push, 0)
|
||||
# include <d3d12.h>
|
||||
# include <dxgidebug.h>
|
||||
# include <dxgi1_6.h>
|
||||
#include <d3d12.h>
|
||||
#include <dxgidebug.h>
|
||||
#include <dxgi1_6.h>
|
||||
#pragma warning(pop)
|
||||
|
||||
#pragma comment(lib, "d3d12")
|
||||
@ -16,9 +16,10 @@
|
||||
#define G_D12_TearingIsAllowed 1
|
||||
#define G_D12_FrameLatency 1
|
||||
#define G_D12_SwapchainBufferCount 3
|
||||
#define G_D12_SwapchainFlags (((G_D12_TearingIsAllowed != 0) * DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING) \
|
||||
| ((G_D12_FrameLatency != 0) * DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT))
|
||||
|
||||
#define G_D12_SwapchainFlags (0 \
|
||||
| ((G_D12_TearingIsAllowed != 0) * DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING) \
|
||||
| ((G_D12_FrameLatency != 0) * DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT) \
|
||||
)
|
||||
|
||||
#define G_D12_MaxCbvSrvUavDescriptors (1024 * 128)
|
||||
#define G_D12_MaxSamplerDescriptors (1024 * 1)
|
||||
@ -29,30 +30,30 @@
|
||||
|
||||
Struct(G_D12_PipelineDesc)
|
||||
{
|
||||
VertexShader vs;
|
||||
PixelShader ps;
|
||||
ComputeShader cs;
|
||||
b32 is_wireframe;
|
||||
D3D12_PRIMITIVE_TOPOLOGY_TYPE topology_type;
|
||||
G_Format render_target_formats[G_MaxRenderTargets];
|
||||
VertexShader vs;
|
||||
PixelShader ps;
|
||||
ComputeShader cs;
|
||||
b32 is_wireframe;
|
||||
D3D12_PRIMITIVE_TOPOLOGY_TYPE topology_type;
|
||||
G_Format render_target_formats[G_MaxRenderTargets];
|
||||
};
|
||||
|
||||
Struct(G_D12_Pipeline)
|
||||
{
|
||||
G_D12_Pipeline *next_in_bin;
|
||||
u64 hash;
|
||||
G_D12_Pipeline *next_in_bin;
|
||||
u64 hash;
|
||||
|
||||
G_D12_PipelineDesc desc;
|
||||
ID3D12PipelineState *pso;
|
||||
G_D12_PipelineDesc desc;
|
||||
ID3D12PipelineState *pso;
|
||||
|
||||
b32 ok;
|
||||
String error;
|
||||
b32 ok;
|
||||
String error;
|
||||
};
|
||||
|
||||
Struct(G_D12_PipelineBin)
|
||||
{
|
||||
Mutex mutex;
|
||||
G_D12_Pipeline *first;
|
||||
Mutex mutex;
|
||||
G_D12_Pipeline *first;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -60,40 +61,40 @@ Struct(G_D12_PipelineBin)
|
||||
|
||||
Struct(G_D12_Resource)
|
||||
{
|
||||
G_D12_Resource *next;
|
||||
G_D12_Resource *next;
|
||||
|
||||
struct G_D12_ResourceHeap *heap;
|
||||
u64 pos_in_heap;
|
||||
u64 size_in_heap;
|
||||
struct G_D12_ResourceHeap *heap;
|
||||
u64 pos_in_heap;
|
||||
u64 size_in_heap;
|
||||
|
||||
ID3D12Resource *d3d_resource;
|
||||
u64 uid;
|
||||
G_ResourceFlag flags;
|
||||
ID3D12Resource *d3d_resource;
|
||||
u64 uid;
|
||||
G_ResourceFlag flags;
|
||||
|
||||
/* Buffer info */
|
||||
u64 buffer_size;
|
||||
u64 buffer_size_actual;
|
||||
D3D12_GPU_VIRTUAL_ADDRESS buffer_gpu_address;
|
||||
/* Buffer info */
|
||||
u64 buffer_size;
|
||||
u64 buffer_size_actual;
|
||||
D3D12_GPU_VIRTUAL_ADDRESS buffer_gpu_address;
|
||||
|
||||
/* Texture info */
|
||||
b32 is_texture;
|
||||
G_Format texture_format;
|
||||
Vec3I32 texture_dims;
|
||||
i32 texture_mip_levels;
|
||||
D3D12_BARRIER_LAYOUT texture_layout;
|
||||
/* Texture info */
|
||||
b32 is_texture;
|
||||
G_Format texture_format;
|
||||
Vec3I32 texture_dims;
|
||||
i32 texture_mip_levels;
|
||||
D3D12_BARRIER_LAYOUT texture_layout;
|
||||
|
||||
/* Sampler info */
|
||||
G_SamplerDesc sampler_desc;
|
||||
/* Sampler info */
|
||||
G_SamplerDesc sampler_desc;
|
||||
|
||||
/* Backbuffer info */
|
||||
struct G_D12_Swapchain *swapchain;
|
||||
/* Backbuffer info */
|
||||
struct G_D12_Swapchain *swapchain;
|
||||
};
|
||||
|
||||
Struct(G_D12_ResourceList)
|
||||
{
|
||||
u64 count;
|
||||
G_D12_Resource *first;
|
||||
G_D12_Resource *last;
|
||||
u64 count;
|
||||
G_D12_Resource *first;
|
||||
G_D12_Resource *last;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -101,46 +102,46 @@ Struct(G_D12_ResourceList)
|
||||
|
||||
Enum(G_D12_DescriptorHeapKind)
|
||||
{
|
||||
G_D12_DescriptorHeapKind_CbvSrvUav,
|
||||
G_D12_DescriptorHeapKind_Rtv,
|
||||
G_D12_DescriptorHeapKind_Sampler,
|
||||
G_D12_DescriptorHeapKind_CbvSrvUav,
|
||||
G_D12_DescriptorHeapKind_Rtv,
|
||||
G_D12_DescriptorHeapKind_Sampler,
|
||||
|
||||
G_D12_DescriptorHeapKind_Count
|
||||
G_D12_DescriptorHeapKind_Count
|
||||
};
|
||||
|
||||
Struct(G_D12_DescriptorHeap)
|
||||
{
|
||||
Arena *descriptors_arena;
|
||||
G_D12_DescriptorHeapKind kind;
|
||||
Arena *descriptors_arena;
|
||||
G_D12_DescriptorHeapKind kind;
|
||||
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE type;
|
||||
u32 descriptor_size;
|
||||
ID3D12DescriptorHeap *d3d_heap;
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE start_handle;
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE type;
|
||||
u32 descriptor_size;
|
||||
ID3D12DescriptorHeap *d3d_heap;
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE start_handle;
|
||||
|
||||
Mutex mutex;
|
||||
struct G_D12_Descriptor *first_free;
|
||||
u32 max_count;
|
||||
Mutex mutex;
|
||||
struct G_D12_Descriptor *first_free;
|
||||
u32 max_count;
|
||||
};
|
||||
|
||||
Struct(G_D12_Descriptor)
|
||||
{
|
||||
G_D12_Descriptor *next;
|
||||
G_D12_Descriptor *next;
|
||||
|
||||
struct G_D12_Arena *gpu_arena;
|
||||
G_QueueKind completion_queue_kind;
|
||||
i64 completion_queue_target;
|
||||
struct G_D12_Arena *gpu_arena;
|
||||
G_QueueKind completion_queue_kind;
|
||||
i64 completion_queue_target;
|
||||
|
||||
G_D12_DescriptorHeap *heap;
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE handle;
|
||||
u32 index;
|
||||
G_D12_DescriptorHeap *heap;
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE handle;
|
||||
u32 index;
|
||||
};
|
||||
|
||||
Struct(G_D12_DescriptorList)
|
||||
{
|
||||
u64 count;
|
||||
G_D12_Descriptor *first;
|
||||
G_D12_Descriptor *last;
|
||||
u64 count;
|
||||
G_D12_Descriptor *first;
|
||||
G_D12_Descriptor *last;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -154,40 +155,40 @@ Struct(G_D12_DescriptorList)
|
||||
*/
|
||||
Enum(G_D12_ResourceHeapKind)
|
||||
{
|
||||
G_D12_ResourceHeapKind_Gpu,
|
||||
G_D12_ResourceHeapKind_Cpu,
|
||||
G_D12_ResourceHeapKind_CpuWriteCombined,
|
||||
G_D12_ResourceHeapKind_Gpu,
|
||||
G_D12_ResourceHeapKind_Cpu,
|
||||
G_D12_ResourceHeapKind_CpuWriteCombined,
|
||||
|
||||
G_D12_ResourceHeapKind_Count,
|
||||
G_D12_ResourceHeapKind_Count,
|
||||
};
|
||||
|
||||
Struct(G_D12_ResourceHeap)
|
||||
{
|
||||
G_D12_ResourceHeapKind kind;
|
||||
G_D12_ResourceHeapKind kind;
|
||||
|
||||
struct GPU_D12_Arena *gpu_arena;
|
||||
struct GPU_D12_Arena *gpu_arena;
|
||||
|
||||
ID3D12Heap *d3d_heap;
|
||||
ID3D12Resource *d3d_mapped_resource;
|
||||
void *mapped;
|
||||
ID3D12Heap *d3d_heap;
|
||||
ID3D12Resource *d3d_mapped_resource;
|
||||
void *mapped;
|
||||
|
||||
G_D12_ResourceList resources;
|
||||
G_D12_ResourceList reset_resources;
|
||||
G_D12_ResourceList resources;
|
||||
G_D12_ResourceList reset_resources;
|
||||
|
||||
u64 pos;
|
||||
u64 size;
|
||||
u64 pos;
|
||||
u64 size;
|
||||
};
|
||||
|
||||
Struct(G_D12_Arena)
|
||||
{
|
||||
Arena *arena;
|
||||
Arena *arena;
|
||||
|
||||
G_D12_DescriptorList descriptors;
|
||||
G_D12_DescriptorList reset_descriptors_by_heap[G_D12_DescriptorHeapKind_Count];
|
||||
G_D12_DescriptorList descriptors;
|
||||
G_D12_DescriptorList reset_descriptors_by_heap[G_D12_DescriptorHeapKind_Count];
|
||||
|
||||
G_D12_ResourceList free_resources;
|
||||
G_D12_ResourceList free_resources;
|
||||
|
||||
G_D12_ResourceHeap resource_heaps[G_D12_ResourceHeapKind_Count];
|
||||
G_D12_ResourceHeap resource_heaps[G_D12_ResourceHeapKind_Count];
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -195,32 +196,32 @@ Struct(G_D12_Arena)
|
||||
|
||||
Struct(G_D12_StagingRing)
|
||||
{
|
||||
Arena *arena;
|
||||
G_D12_Arena *gpu_arena;
|
||||
u64 size;
|
||||
Arena *arena;
|
||||
G_D12_Arena *gpu_arena;
|
||||
u64 size;
|
||||
|
||||
G_D12_Resource *resource;
|
||||
u8 *base;
|
||||
G_D12_Resource *resource;
|
||||
u8 *base;
|
||||
|
||||
struct G_D12_StagingRegionNode *head_region_node;
|
||||
struct G_D12_StagingRegionNode *first_free_region_node;
|
||||
struct G_D12_StagingRegionNode *head_region_node;
|
||||
struct G_D12_StagingRegionNode *first_free_region_node;
|
||||
|
||||
};
|
||||
|
||||
Struct(G_D12_StagingRegionNode)
|
||||
{
|
||||
G_D12_StagingRing *ring;
|
||||
G_D12_StagingRing *ring;
|
||||
|
||||
/* Ring links (requires ring lock to read) */
|
||||
G_D12_StagingRegionNode *prev;
|
||||
G_D12_StagingRegionNode *next;
|
||||
/* Ring links (requires ring lock to read) */
|
||||
G_D12_StagingRegionNode *prev;
|
||||
G_D12_StagingRegionNode *next;
|
||||
|
||||
/* Command list links */
|
||||
G_D12_StagingRegionNode *next_in_command_list;
|
||||
/* Command list links */
|
||||
G_D12_StagingRegionNode *next_in_command_list;
|
||||
|
||||
/* Region info */
|
||||
Atomic64 completion_target;
|
||||
u64 pos;
|
||||
/* Region info */
|
||||
Atomic64 completion_target;
|
||||
u64 pos;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -228,34 +229,34 @@ Struct(G_D12_StagingRegionNode)
|
||||
|
||||
Struct(G_D12_CommandQueueDesc)
|
||||
{
|
||||
D3D12_COMMAND_LIST_TYPE type;
|
||||
D3D12_COMMAND_QUEUE_PRIORITY priority;
|
||||
D3D12_COMMAND_LIST_TYPE type;
|
||||
D3D12_COMMAND_QUEUE_PRIORITY priority;
|
||||
};
|
||||
|
||||
Struct(G_D12_Queue)
|
||||
{
|
||||
ID3D12CommandQueue *d3d_queue;
|
||||
G_D12_CommandQueueDesc desc;
|
||||
ID3D12CommandQueue *d3d_queue;
|
||||
G_D12_CommandQueueDesc desc;
|
||||
|
||||
Mutex commit_mutex;
|
||||
ID3D12Fence *commit_fence;
|
||||
u64 commit_fence_target;
|
||||
Mutex commit_mutex;
|
||||
ID3D12Fence *commit_fence;
|
||||
u64 commit_fence_target;
|
||||
|
||||
/* Global resources */
|
||||
u64 print_buffer_size;
|
||||
G_ResourceHandle print_buffer;
|
||||
G_ResourceHandle print_readback_buffer;
|
||||
G_RWByteAddressBufferRef print_buffer_ref;
|
||||
/* Global resources */
|
||||
u64 print_buffer_size;
|
||||
G_ResourceHandle print_buffer;
|
||||
G_ResourceHandle print_readback_buffer;
|
||||
G_RWByteAddressBufferRef print_buffer_ref;
|
||||
|
||||
/* Raw command lists */
|
||||
struct G_D12_RawCommandList *first_committed_cl;
|
||||
struct G_D12_RawCommandList *last_committed_cl;
|
||||
/* Raw command lists */
|
||||
struct G_D12_RawCommandList *first_committed_cl;
|
||||
struct G_D12_RawCommandList *last_committed_cl;
|
||||
|
||||
/* Staging heap */
|
||||
Mutex staging_mutex;
|
||||
G_D12_StagingRing *staging_ring;
|
||||
/* Staging heap */
|
||||
Mutex staging_mutex;
|
||||
G_D12_StagingRing *staging_ring;
|
||||
|
||||
Fence sync_fence;
|
||||
Fence sync_fence;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -263,17 +264,17 @@ Struct(G_D12_Queue)
|
||||
|
||||
Struct(G_D12_RawCommandList)
|
||||
{
|
||||
G_D12_Queue *queue;
|
||||
G_D12_RawCommandList *next;
|
||||
G_D12_Queue *queue;
|
||||
G_D12_RawCommandList *next;
|
||||
|
||||
u64 commit_fence_target;
|
||||
u64 commit_fence_target;
|
||||
|
||||
ID3D12CommandAllocator *d3d_ca;
|
||||
ID3D12GraphicsCommandList7 *d3d_cl;
|
||||
ID3D12CommandAllocator *d3d_ca;
|
||||
ID3D12GraphicsCommandList7 *d3d_cl;
|
||||
|
||||
/* Direct queue command lists keep a constant list of CPU-only descriptors */
|
||||
G_D12_Descriptor *rtv_descriptors[G_MaxRenderTargets];
|
||||
G_D12_Descriptor *rtv_clear_descriptor;
|
||||
/* Direct queue command lists keep a constant list of CPU-only descriptors */
|
||||
G_D12_Descriptor *rtv_descriptors[G_MaxRenderTargets];
|
||||
G_D12_Descriptor *rtv_clear_descriptor;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -283,108 +284,108 @@ Struct(G_D12_RawCommandList)
|
||||
|
||||
Enum(G_D12_CmdKind)
|
||||
{
|
||||
G_D12_CmdKind_None,
|
||||
G_D12_CmdKind_Barrier,
|
||||
G_D12_CmdKind_Constant,
|
||||
G_D12_CmdKind_CopyBytes,
|
||||
G_D12_CmdKind_CopyTexels,
|
||||
G_D12_CmdKind_Compute,
|
||||
G_D12_CmdKind_Rasterize,
|
||||
G_D12_CmdKind_ClearRtv,
|
||||
G_D12_CmdKind_DiscardRtv,
|
||||
G_D12_CmdKind_None,
|
||||
G_D12_CmdKind_Barrier,
|
||||
G_D12_CmdKind_Constant,
|
||||
G_D12_CmdKind_CopyBytes,
|
||||
G_D12_CmdKind_CopyTexels,
|
||||
G_D12_CmdKind_Compute,
|
||||
G_D12_CmdKind_Rasterize,
|
||||
G_D12_CmdKind_ClearRtv,
|
||||
G_D12_CmdKind_DiscardRtv,
|
||||
};
|
||||
|
||||
Struct(G_D12_Cmd)
|
||||
{
|
||||
G_D12_CmdKind kind;
|
||||
b32 skip;
|
||||
union
|
||||
G_D12_CmdKind kind;
|
||||
b32 skip;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
struct
|
||||
{
|
||||
i32 slot;
|
||||
u32 value;
|
||||
} constant;
|
||||
i32 slot;
|
||||
u32 value;
|
||||
} constant;
|
||||
|
||||
struct
|
||||
{
|
||||
G_MemoryBarrierDesc desc;
|
||||
struct
|
||||
{
|
||||
G_MemoryBarrierDesc desc;
|
||||
|
||||
/* Post-batch data */
|
||||
b32 is_end_of_batch;
|
||||
u64 batch_gen;
|
||||
} barrier;
|
||||
/* Post-batch data */
|
||||
b32 is_end_of_batch;
|
||||
u64 batch_gen;
|
||||
} barrier;
|
||||
|
||||
struct
|
||||
{
|
||||
G_D12_Resource *dst;
|
||||
G_D12_Resource *src;
|
||||
u64 dst_offset;
|
||||
RngU64 src_range;
|
||||
} copy_bytes;
|
||||
struct
|
||||
{
|
||||
G_D12_Resource *dst;
|
||||
G_D12_Resource *src;
|
||||
u64 dst_offset;
|
||||
RngU64 src_range;
|
||||
} copy_bytes;
|
||||
|
||||
struct
|
||||
{
|
||||
G_D12_Resource *dst;
|
||||
G_D12_Resource *src;
|
||||
D3D12_TEXTURE_COPY_LOCATION dst_loc;
|
||||
D3D12_TEXTURE_COPY_LOCATION src_loc;
|
||||
Vec3I32 dst_texture_offset;
|
||||
Rng3I32 src_texture_range;
|
||||
} copy_texels;
|
||||
struct
|
||||
{
|
||||
G_D12_Resource *dst;
|
||||
G_D12_Resource *src;
|
||||
D3D12_TEXTURE_COPY_LOCATION dst_loc;
|
||||
D3D12_TEXTURE_COPY_LOCATION src_loc;
|
||||
Vec3I32 dst_texture_offset;
|
||||
Rng3I32 src_texture_range;
|
||||
} copy_texels;
|
||||
|
||||
struct
|
||||
{
|
||||
ComputeShader cs;
|
||||
Vec3I32 groups;
|
||||
} compute;
|
||||
struct
|
||||
{
|
||||
ComputeShader cs;
|
||||
Vec3I32 groups;
|
||||
} compute;
|
||||
|
||||
struct
|
||||
{
|
||||
VertexShader vs;
|
||||
PixelShader ps;
|
||||
u32 instances_count;
|
||||
G_IndexBufferDesc index_buffer_desc;
|
||||
G_D12_Resource *render_targets[G_MaxRenderTargets];
|
||||
Rng3 viewport;
|
||||
Rng2 scissor;
|
||||
G_RasterMode mode;
|
||||
} rasterize;
|
||||
struct
|
||||
{
|
||||
VertexShader vs;
|
||||
PixelShader ps;
|
||||
u32 instances_count;
|
||||
G_IndexBufferDesc index_buffer_desc;
|
||||
G_D12_Resource *render_targets[G_MaxRenderTargets];
|
||||
Rng3 viewport;
|
||||
Rng2 scissor;
|
||||
G_RasterMode mode;
|
||||
} rasterize;
|
||||
|
||||
struct
|
||||
{
|
||||
G_D12_Resource *render_target;
|
||||
Vec4 color;
|
||||
} clear_rtv;
|
||||
struct
|
||||
{
|
||||
G_D12_Resource *render_target;
|
||||
Vec4 color;
|
||||
} clear_rtv;
|
||||
|
||||
struct
|
||||
{
|
||||
G_D12_Resource *render_target;
|
||||
} discard_rtv;
|
||||
};
|
||||
struct
|
||||
{
|
||||
G_D12_Resource *render_target;
|
||||
} discard_rtv;
|
||||
};
|
||||
};
|
||||
|
||||
Struct(G_D12_CmdChunk)
|
||||
{
|
||||
G_D12_CmdChunk *next;
|
||||
struct G_D12_CmdList *cl;
|
||||
G_D12_Cmd *cmds;
|
||||
u64 cmds_count;
|
||||
G_D12_CmdChunk *next;
|
||||
struct G_D12_CmdList *cl;
|
||||
G_D12_Cmd *cmds;
|
||||
u64 cmds_count;
|
||||
};
|
||||
|
||||
Struct(G_D12_CmdList)
|
||||
{
|
||||
G_D12_CmdList *next;
|
||||
G_QueueKind queue_kind;
|
||||
G_D12_CmdList *next;
|
||||
G_QueueKind queue_kind;
|
||||
|
||||
G_D12_DescriptorList reset_descriptors;
|
||||
G_D12_StagingRegionNode *first_staging_region;
|
||||
G_D12_StagingRegionNode *last_staging_region;
|
||||
G_D12_DescriptorList reset_descriptors;
|
||||
G_D12_StagingRegionNode *first_staging_region;
|
||||
G_D12_StagingRegionNode *last_staging_region;
|
||||
|
||||
G_D12_CmdChunk *first_cmd_chunk;
|
||||
G_D12_CmdChunk *last_cmd_chunk;
|
||||
u64 chunks_count;
|
||||
u64 cmds_count;
|
||||
G_D12_CmdChunk *first_cmd_chunk;
|
||||
G_D12_CmdChunk *last_cmd_chunk;
|
||||
u64 chunks_count;
|
||||
u64 cmds_count;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -393,17 +394,17 @@ Struct(G_D12_CmdList)
|
||||
Struct(G_D12_Swapchain)
|
||||
{
|
||||
|
||||
IDXGISwapChain3 *d3d_swapchain;
|
||||
HWND window_hwnd;
|
||||
HANDLE waitable;
|
||||
IDXGISwapChain3 *d3d_swapchain;
|
||||
HWND window_hwnd;
|
||||
HANDLE waitable;
|
||||
|
||||
HANDLE present_event;
|
||||
ID3D12Fence *present_fence;
|
||||
u64 present_fence_target;
|
||||
HANDLE present_event;
|
||||
ID3D12Fence *present_fence;
|
||||
u64 present_fence_target;
|
||||
|
||||
G_Format backbuffers_format;
|
||||
Vec2I32 backbuffers_resolution;
|
||||
G_D12_Resource backbuffers[G_D12_SwapchainBufferCount];
|
||||
G_Format backbuffers_format;
|
||||
Vec2I32 backbuffers_resolution;
|
||||
G_D12_Resource backbuffers[G_D12_SwapchainBufferCount];
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -411,45 +412,45 @@ Struct(G_D12_Swapchain)
|
||||
|
||||
Struct(G_D12_SharedState)
|
||||
{
|
||||
Atomic64Padded resource_creation_gen;
|
||||
Atomic64Padded resource_creation_gen;
|
||||
|
||||
/* Stats */
|
||||
Atomic64 driver_resources_allocated;
|
||||
Atomic64 driver_descriptors_allocated;
|
||||
/* Stats */
|
||||
Atomic64 driver_resources_allocated;
|
||||
Atomic64 driver_descriptors_allocated;
|
||||
|
||||
/* Queues */
|
||||
G_D12_Queue queues[G_NumQueues];
|
||||
/* Queues */
|
||||
G_D12_Queue queues[G_NumQueues];
|
||||
|
||||
/* Descriptor heaps */
|
||||
G_D12_DescriptorHeap descriptor_heaps[G_D12_DescriptorHeapKind_Count];
|
||||
/* Descriptor heaps */
|
||||
G_D12_DescriptorHeap descriptor_heaps[G_D12_DescriptorHeapKind_Count];
|
||||
|
||||
/* Rootsig */
|
||||
ID3D12RootSignature *bindless_rootsig;
|
||||
/* Rootsig */
|
||||
ID3D12RootSignature *bindless_rootsig;
|
||||
|
||||
/* Pipelines */
|
||||
G_D12_PipelineBin pipeline_bins[1024];
|
||||
/* Pipelines */
|
||||
G_D12_PipelineBin pipeline_bins[1024];
|
||||
|
||||
/* Command lists */
|
||||
Mutex free_cmd_lists_mutex;
|
||||
G_D12_CmdList *first_free_cmd_list;
|
||||
/* Command lists */
|
||||
Mutex free_cmd_lists_mutex;
|
||||
G_D12_CmdList *first_free_cmd_list;
|
||||
|
||||
/* Command chunks */
|
||||
Mutex free_cmd_chunks_mutex;
|
||||
G_D12_CmdChunk *first_free_cmd_chunk;
|
||||
/* Command chunks */
|
||||
Mutex free_cmd_chunks_mutex;
|
||||
G_D12_CmdChunk *first_free_cmd_chunk;
|
||||
|
||||
/* Swapchains */
|
||||
Mutex free_swapchains_mutex;
|
||||
G_D12_Swapchain *first_free_swapchain;
|
||||
/* Swapchains */
|
||||
Mutex free_swapchains_mutex;
|
||||
G_D12_Swapchain *first_free_swapchain;
|
||||
|
||||
/* Device */
|
||||
IDXGIFactory6 *factory;
|
||||
IDXGIAdapter3 *adapter;
|
||||
ID3D12Device10 *device;
|
||||
/* Device */
|
||||
IDXGIFactory6 *factory;
|
||||
IDXGIAdapter3 *adapter;
|
||||
ID3D12Device10 *device;
|
||||
} extern G_D12_shared_state;
|
||||
|
||||
Struct(G_D12_ThreadLocalState)
|
||||
{
|
||||
HANDLE sync_event;
|
||||
HANDLE sync_event;
|
||||
} extern ThreadLocal G_D12_tl;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
@ -3,17 +3,17 @@
|
||||
|
||||
Enum(G_RefKind)
|
||||
{
|
||||
G_RefKind_StructuredBuffer,
|
||||
G_RefKind_RWStructuredBuffer,
|
||||
G_RefKind_ByteAddressBuffer,
|
||||
G_RefKind_RWByteAddressBuffer,
|
||||
G_RefKind_Texture1D,
|
||||
G_RefKind_RWTexture1D,
|
||||
G_RefKind_Texture2D,
|
||||
G_RefKind_RWTexture2D,
|
||||
G_RefKind_Texture3D,
|
||||
G_RefKind_RWTexture3D,
|
||||
G_RefKind_SamplerState,
|
||||
G_RefKind_StructuredBuffer,
|
||||
G_RefKind_RWStructuredBuffer,
|
||||
G_RefKind_ByteAddressBuffer,
|
||||
G_RefKind_RWByteAddressBuffer,
|
||||
G_RefKind_Texture1D,
|
||||
G_RefKind_RWTexture1D,
|
||||
G_RefKind_Texture2D,
|
||||
G_RefKind_RWTexture2D,
|
||||
G_RefKind_Texture3D,
|
||||
G_RefKind_RWTexture3D,
|
||||
G_RefKind_SamplerState,
|
||||
};
|
||||
|
||||
Struct(G_StructuredBufferRef) { u32 v; };
|
||||
@ -43,56 +43,56 @@ Struct(G_SamplerStateRef) { u32 v; };
|
||||
#define G_NumConstants (G_NumGeneralPurposeConstants + G_NumReservedConstants)
|
||||
|
||||
#if IsLanguageC
|
||||
#define G_ForceDeclConstant(type, name, slot) \
|
||||
Enum(name##__shaderconstantenum) { name = slot }; \
|
||||
Struct(name##__shaderconstanttype) { type v; }
|
||||
#define G_DeclConstant(type, name, slot) \
|
||||
StaticAssert(sizeof(type) <= 4); \
|
||||
StaticAssert(slot < G_NumGeneralPurposeConstants); \
|
||||
G_ForceDeclConstant(type, name, slot)
|
||||
#define G_ForceDeclConstant(type, name, slot) \
|
||||
Enum(name##__shaderconstantenum) { name = slot }; \
|
||||
Struct(name##__shaderconstanttype) { type v; }
|
||||
#define G_DeclConstant(type, name, slot) \
|
||||
StaticAssert(sizeof(type) <= 4); \
|
||||
StaticAssert(slot < G_NumGeneralPurposeConstants); \
|
||||
G_ForceDeclConstant(type, name, slot)
|
||||
#elif IsLanguageG
|
||||
#define G_ForceDeclConstant(type, name, slot) cbuffer name : register(b##slot) { type name; }
|
||||
#define G_DeclConstant(type, name, slot) G_ForceDeclConstant(type, name, slot)
|
||||
#define G_ForceDeclConstant(type, name, slot) cbuffer name : register(b##slot) { type name; }
|
||||
#define G_DeclConstant(type, name, slot) G_ForceDeclConstant(type, name, slot)
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Resource dereference
|
||||
|
||||
#if IsLanguageG
|
||||
/* TODO: Non-uniform resource access currently is assumed as the default
|
||||
* behavior. We may want to add explicit "uniform" variants for
|
||||
* optimization on amd in the future. */
|
||||
/* TODO: Non-uniform resource access currently is assumed as the default
|
||||
* behavior. We may want to add explicit "uniform" variants for
|
||||
* optimization on amd in the future. */
|
||||
|
||||
template<typename T> StructuredBuffer<T> G_Dereference(G_StructuredBufferRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; }
|
||||
template<typename T> RWStructuredBuffer<T> G_Dereference(G_RWStructuredBufferRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; }
|
||||
template<typename T> StructuredBuffer<T> G_Dereference(G_StructuredBufferRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; }
|
||||
template<typename T> RWStructuredBuffer<T> G_Dereference(G_RWStructuredBufferRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; }
|
||||
|
||||
ByteAddressBuffer G_Dereference(G_ByteAddressBufferRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; }
|
||||
RWByteAddressBuffer G_Dereference(G_RWByteAddressBufferRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; }
|
||||
ByteAddressBuffer G_Dereference(G_ByteAddressBufferRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; }
|
||||
RWByteAddressBuffer G_Dereference(G_RWByteAddressBufferRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; }
|
||||
|
||||
template<typename T> Texture1D<T> G_Dereference(G_Texture1DRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; }
|
||||
template<typename T> Texture2D<T> G_Dereference(G_Texture2DRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; }
|
||||
template<typename T> Texture3D<T> G_Dereference(G_Texture3DRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; }
|
||||
template<typename T> RWTexture1D<T> G_Dereference(G_RWTexture1DRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; }
|
||||
template<typename T> RWTexture2D<T> G_Dereference(G_RWTexture2DRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; }
|
||||
template<typename T> RWTexture3D<T> G_Dereference(G_RWTexture3DRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; }
|
||||
template<typename T> Texture1D<T> G_Dereference(G_Texture1DRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; }
|
||||
template<typename T> Texture2D<T> G_Dereference(G_Texture2DRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; }
|
||||
template<typename T> Texture3D<T> G_Dereference(G_Texture3DRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; }
|
||||
template<typename T> RWTexture1D<T> G_Dereference(G_RWTexture1DRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; }
|
||||
template<typename T> RWTexture2D<T> G_Dereference(G_RWTexture2DRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; }
|
||||
template<typename T> RWTexture3D<T> G_Dereference(G_RWTexture3DRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; }
|
||||
|
||||
SamplerState G_Dereference(G_SamplerStateRef r) { return SamplerDescriptorHeap[NonUniformResourceIndex(r.v)]; }
|
||||
SamplerState G_Dereference(G_SamplerStateRef r) { return SamplerDescriptorHeap[NonUniformResourceIndex(r.v)]; }
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Size helpers
|
||||
|
||||
#if IsLanguageG
|
||||
template<typename T> u32 countof(StructuredBuffer<T> buff) { u32 result; buff.GetDimensions(result); return result; }
|
||||
template<typename T> u32 countof(RWStructuredBuffer<T> buff) { u32 result; buff.GetDimensions(result); return result; }
|
||||
u32 countof(ByteAddressBuffer buff) { u32 result; buff.GetDimensions(result); return result; }
|
||||
u32 countof(RWByteAddressBuffer buff) { u32 result; buff.GetDimensions(result); return result; }
|
||||
u32 countof(Texture1D tex) { u32 result; tex.GetDimensions(result); return result; }
|
||||
template<typename T> u32 countof(RWTexture1D<T> tex) { u32 result; tex.GetDimensions(result); return result; }
|
||||
Vec2U32 countof(Texture2D tex) { Vec2U32 result; tex.GetDimensions(result.x, result.y); return result; }
|
||||
template<typename T> Vec2U32 countof(RWTexture2D<T> tex) { Vec2U32 result; tex.GetDimensions(result.x, result.y); return result; }
|
||||
Vec3U32 countof(Texture3D tex) { Vec3U32 result; tex.GetDimensions(result.x, result.y, result.z); return result; }
|
||||
template<typename T> Vec3U32 countof(RWTexture3D<T> tex) { Vec3U32 result; tex.GetDimensions(result.x, result.y, result.z); return result; }
|
||||
template<typename T> u32 countof(StructuredBuffer<T> buff) { u32 result; buff.GetDimensions(result); return result; }
|
||||
template<typename T> u32 countof(RWStructuredBuffer<T> buff) { u32 result; buff.GetDimensions(result); return result; }
|
||||
u32 countof(ByteAddressBuffer buff) { u32 result; buff.GetDimensions(result); return result; }
|
||||
u32 countof(RWByteAddressBuffer buff) { u32 result; buff.GetDimensions(result); return result; }
|
||||
u32 countof(Texture1D tex) { u32 result; tex.GetDimensions(result); return result; }
|
||||
template<typename T> u32 countof(RWTexture1D<T> tex) { u32 result; tex.GetDimensions(result); return result; }
|
||||
Vec2U32 countof(Texture2D tex) { Vec2U32 result; tex.GetDimensions(result.x, result.y); return result; }
|
||||
template<typename T> Vec2U32 countof(RWTexture2D<T> tex) { Vec2U32 result; tex.GetDimensions(result.x, result.y); return result; }
|
||||
Vec3U32 countof(Texture3D tex) { Vec3U32 result; tex.GetDimensions(result.x, result.y, result.z); return result; }
|
||||
template<typename T> Vec3U32 countof(RWTexture3D<T> tex) { Vec3U32 result; tex.GetDimensions(result.x, result.y, result.z); return result; }
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -111,196 +111,196 @@ G_ForceDeclConstant(G_RWByteAddressBufferRef, G_ShaderConst_PrintBufferRef, 8)
|
||||
|
||||
Enum(G_FmtArgKind)
|
||||
{
|
||||
G_FmtArgKind_None,
|
||||
G_FmtArgKind_End,
|
||||
G_FmtArgKind_None,
|
||||
G_FmtArgKind_End,
|
||||
|
||||
G_FmtArgKind_BEGINSIZE1,
|
||||
G_FmtArgKind_BEGINSIZE1,
|
||||
|
||||
G_FmtArgKind_Uint,
|
||||
G_FmtArgKind_Sint,
|
||||
G_FmtArgKind_Float,
|
||||
G_FmtArgKind_Uint,
|
||||
G_FmtArgKind_Sint,
|
||||
G_FmtArgKind_Float,
|
||||
|
||||
G_FmtArgKind_BEGINSIZE2,
|
||||
G_FmtArgKind_BEGINSIZE2,
|
||||
|
||||
G_FmtArgKind_Uint2,
|
||||
G_FmtArgKind_Sint2,
|
||||
G_FmtArgKind_Float2,
|
||||
G_FmtArgKind_Uint2,
|
||||
G_FmtArgKind_Sint2,
|
||||
G_FmtArgKind_Float2,
|
||||
|
||||
G_FmtArgKind_BEGINSIZE3,
|
||||
G_FmtArgKind_BEGINSIZE3,
|
||||
|
||||
G_FmtArgKind_Uint3,
|
||||
G_FmtArgKind_Sint3,
|
||||
G_FmtArgKind_Float3,
|
||||
G_FmtArgKind_Uint3,
|
||||
G_FmtArgKind_Sint3,
|
||||
G_FmtArgKind_Float3,
|
||||
|
||||
G_FmtArgKind_BEGINSIZE4,
|
||||
G_FmtArgKind_BEGINSIZE4,
|
||||
|
||||
G_FmtArgKind_Uint4,
|
||||
G_FmtArgKind_Sint4,
|
||||
G_FmtArgKind_Float4,
|
||||
G_FmtArgKind_Uint4,
|
||||
G_FmtArgKind_Sint4,
|
||||
G_FmtArgKind_Float4,
|
||||
};
|
||||
|
||||
Struct(G_FmtArg)
|
||||
{
|
||||
G_FmtArgKind kind;
|
||||
Vec4U32 v;
|
||||
G_FmtArgKind kind;
|
||||
Vec4U32 v;
|
||||
};
|
||||
|
||||
#if IsLanguageG && GPU_SHADER_PRINT
|
||||
G_FmtArg G_Fmt(u32 v) { G_FmtArg result; result.kind = G_FmtArgKind_Uint; result.v.x = v; return result; }
|
||||
G_FmtArg G_Fmt(Vec2U32 v) { G_FmtArg result; result.kind = G_FmtArgKind_Uint2; result.v.xy = v.xy; return result; }
|
||||
G_FmtArg G_Fmt(Vec3U32 v) { G_FmtArg result; result.kind = G_FmtArgKind_Uint3; result.v.xyz = v.xyz; return result; }
|
||||
G_FmtArg G_Fmt(Vec4U32 v) { G_FmtArg result; result.kind = G_FmtArgKind_Uint4; result.v.xyzw = v.xyzw; return result; }
|
||||
G_FmtArg G_Fmt(u32 v) { G_FmtArg result; result.kind = G_FmtArgKind_Uint; result.v.x = v; return result; }
|
||||
G_FmtArg G_Fmt(Vec2U32 v) { G_FmtArg result; result.kind = G_FmtArgKind_Uint2; result.v.xy = v.xy; return result; }
|
||||
G_FmtArg G_Fmt(Vec3U32 v) { G_FmtArg result; result.kind = G_FmtArgKind_Uint3; result.v.xyz = v.xyz; return result; }
|
||||
G_FmtArg G_Fmt(Vec4U32 v) { G_FmtArg result; result.kind = G_FmtArgKind_Uint4; result.v.xyzw = v.xyzw; return result; }
|
||||
|
||||
G_FmtArg G_Fmt(i32 v) { G_FmtArg result; result.kind = G_FmtArgKind_Sint; result.v.x = v; return result; }
|
||||
G_FmtArg G_Fmt(Vec2I32 v) { G_FmtArg result; result.kind = G_FmtArgKind_Sint2; result.v.xy = v.xy; return result; }
|
||||
G_FmtArg G_Fmt(Vec3I32 v) { G_FmtArg result; result.kind = G_FmtArgKind_Sint3; result.v.xyz = v.xyz; return result; }
|
||||
G_FmtArg G_Fmt(Vec4I32 v) { G_FmtArg result; result.kind = G_FmtArgKind_Sint4; result.v.xyzw = v.xyzw; return result; }
|
||||
G_FmtArg G_Fmt(i32 v) { G_FmtArg result; result.kind = G_FmtArgKind_Sint; result.v.x = v; return result; }
|
||||
G_FmtArg G_Fmt(Vec2I32 v) { G_FmtArg result; result.kind = G_FmtArgKind_Sint2; result.v.xy = v.xy; return result; }
|
||||
G_FmtArg G_Fmt(Vec3I32 v) { G_FmtArg result; result.kind = G_FmtArgKind_Sint3; result.v.xyz = v.xyz; return result; }
|
||||
G_FmtArg G_Fmt(Vec4I32 v) { G_FmtArg result; result.kind = G_FmtArgKind_Sint4; result.v.xyzw = v.xyzw; return result; }
|
||||
|
||||
G_FmtArg G_Fmt(f32 v) { G_FmtArg result; result.kind = G_FmtArgKind_Float; result.v.x = asuint(v); return result; }
|
||||
G_FmtArg G_Fmt(Vec2 v) { G_FmtArg result; result.kind = G_FmtArgKind_Float2; result.v.xy = asuint(v.xy); return result; }
|
||||
G_FmtArg G_Fmt(Vec3 v) { G_FmtArg result; result.kind = G_FmtArgKind_Float3; result.v.xyz = asuint(v.xyz); return result; }
|
||||
G_FmtArg G_Fmt(Vec4 v) { G_FmtArg result; result.kind = G_FmtArgKind_Float4; result.v.xyzw = asuint(v.xyzw); return result; }
|
||||
G_FmtArg G_Fmt(f32 v) { G_FmtArg result; result.kind = G_FmtArgKind_Float; result.v.x = asuint(v); return result; }
|
||||
G_FmtArg G_Fmt(Vec2 v) { G_FmtArg result; result.kind = G_FmtArgKind_Float2; result.v.xy = asuint(v.xy); return result; }
|
||||
G_FmtArg G_Fmt(Vec3 v) { G_FmtArg result; result.kind = G_FmtArgKind_Float3; result.v.xyz = asuint(v.xyz); return result; }
|
||||
G_FmtArg G_Fmt(Vec4 v) { G_FmtArg result; result.kind = G_FmtArgKind_Float4; result.v.xyzw = asuint(v.xyzw); return result; }
|
||||
|
||||
G_FmtArg G_FmtEnd(void) { G_FmtArg result; result.kind = G_FmtArgKind_End; return result; }
|
||||
G_FmtArg G_FmtEnd(void) { G_FmtArg result; result.kind = G_FmtArgKind_End; return result; }
|
||||
|
||||
Struct(G_TempPrintBuffer)
|
||||
Struct(G_TempPrintBuffer)
|
||||
{
|
||||
/* NOTE: The larger the array size, the longer the compilation time */
|
||||
u32 byte_chunks[64];
|
||||
u32 bytes_count;
|
||||
u32 chars_count;
|
||||
u32 args_count;
|
||||
b32 overflowed;
|
||||
};
|
||||
|
||||
void G_PushPrintByte(inout G_TempPrintBuffer buff, u32 v)
|
||||
{
|
||||
u32 chunk_idx = buff.bytes_count / 4;
|
||||
if (chunk_idx < countof(buff.byte_chunks))
|
||||
{
|
||||
/* NOTE: The larger the array size, the longer the compilation time */
|
||||
u32 byte_chunks[64];
|
||||
u32 bytes_count;
|
||||
u32 chars_count;
|
||||
u32 args_count;
|
||||
b32 overflowed;
|
||||
};
|
||||
|
||||
void G_PushPrintByte(inout G_TempPrintBuffer buff, u32 v)
|
||||
u32 byte_idx_in_chunk = buff.bytes_count & 0x03;
|
||||
if (byte_idx_in_chunk == 0)
|
||||
{
|
||||
/* Since buff is not zero initialized, we set the chunk on first write here */
|
||||
buff.byte_chunks[chunk_idx] = v & 0xFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
buff.byte_chunks[chunk_idx] |= (v & 0xFF) << (byte_idx_in_chunk * 8);
|
||||
}
|
||||
buff.bytes_count += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
u32 chunk_idx = buff.bytes_count / 4;
|
||||
if (chunk_idx < countof(buff.byte_chunks))
|
||||
{
|
||||
u32 byte_idx_in_chunk = buff.bytes_count & 0x03;
|
||||
if (byte_idx_in_chunk == 0)
|
||||
{
|
||||
/* Since buff is not zero initialized, we set the chunk on first write here */
|
||||
buff.byte_chunks[chunk_idx] = v & 0xFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
buff.byte_chunks[chunk_idx] |= (v & 0xFF) << (byte_idx_in_chunk * 8);
|
||||
}
|
||||
buff.bytes_count += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
buff.overflowed = 1;
|
||||
}
|
||||
buff.overflowed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void G_CommitPrint(G_TempPrintBuffer buff)
|
||||
{
|
||||
RWByteAddressBuffer rw = G_Dereference(G_ShaderConst_PrintBufferRef);
|
||||
|
||||
if (buff.overflowed)
|
||||
{
|
||||
buff.bytes_count = 0;
|
||||
buff.chars_count = 0;
|
||||
buff.args_count = 0;
|
||||
}
|
||||
|
||||
void G_CommitPrint(G_TempPrintBuffer buff)
|
||||
u32 chunks_count = (buff.bytes_count + 3) / 4;
|
||||
u32 alloc_size = 0;
|
||||
alloc_size += 4; /* Header */
|
||||
alloc_size += chunks_count * 4; /* Chunks */
|
||||
|
||||
/* Atomic fetch + add to base counter */
|
||||
u32 base;
|
||||
rw.InterlockedAdd(0, alloc_size, base);
|
||||
base += 4; /* Offset for allocation counter */
|
||||
base += 4; /* Offset for success counter */
|
||||
base += 4; /* Offset for overflow counter */
|
||||
|
||||
if ((base + alloc_size) < countof(rw))
|
||||
{
|
||||
RWByteAddressBuffer rw = G_Dereference(G_ShaderConst_PrintBufferRef);
|
||||
/* Increment success counter */
|
||||
rw.InterlockedAdd(4, 1);
|
||||
u32 pos = 0;
|
||||
|
||||
if (buff.overflowed)
|
||||
{
|
||||
buff.bytes_count = 0;
|
||||
buff.chars_count = 0;
|
||||
buff.args_count = 0;
|
||||
}
|
||||
/* Write header */
|
||||
{
|
||||
u32 header = 0;
|
||||
header |= (buff.chars_count << 0) & 0x0000FFFF;
|
||||
header |= (buff.args_count << 16) & 0x7FFF0000;
|
||||
header |= (buff.overflowed << 31) & 0xF0000000;
|
||||
rw.Store(base + pos, header);
|
||||
pos += 4;
|
||||
}
|
||||
|
||||
u32 chunks_count = (buff.bytes_count + 3) / 4;
|
||||
u32 alloc_size = 0;
|
||||
alloc_size += 4; /* Header */
|
||||
alloc_size += chunks_count * 4; /* Chunks */
|
||||
|
||||
/* Atomic fetch + add to base counter */
|
||||
u32 base;
|
||||
rw.InterlockedAdd(0, alloc_size, base);
|
||||
base += 4; /* Offset for allocation counter */
|
||||
base += 4; /* Offset for success counter */
|
||||
base += 4; /* Offset for overflow counter */
|
||||
|
||||
if ((base + alloc_size) < countof(rw))
|
||||
{
|
||||
/* Increment success counter */
|
||||
rw.InterlockedAdd(4, 1);
|
||||
u32 pos = 0;
|
||||
|
||||
/* Write header */
|
||||
{
|
||||
u32 header = 0;
|
||||
header |= (buff.chars_count << 0) & 0x0000FFFF;
|
||||
header |= (buff.args_count << 16) & 0x7FFF0000;
|
||||
header |= (buff.overflowed << 31) & 0xF0000000;
|
||||
rw.Store(base + pos, header);
|
||||
pos += 4;
|
||||
}
|
||||
|
||||
/* Write chunks */
|
||||
for (u32 chunk_idx = 0; chunk_idx < chunks_count; ++chunk_idx)
|
||||
{
|
||||
u32 chunk = buff.byte_chunks[chunk_idx];
|
||||
rw.Store(base + pos, chunk);
|
||||
pos += 4;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Increment overflow counter */
|
||||
rw.InterlockedAdd(8, 1);
|
||||
}
|
||||
/* Write chunks */
|
||||
for (u32 chunk_idx = 0; chunk_idx < chunks_count; ++chunk_idx)
|
||||
{
|
||||
u32 chunk = buff.byte_chunks[chunk_idx];
|
||||
rw.Store(base + pos, chunk);
|
||||
pos += 4;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Increment overflow counter */
|
||||
rw.InterlockedAdd(8, 1);
|
||||
}
|
||||
}
|
||||
|
||||
#define G_PrintF_(fmt, ...) do { \
|
||||
G_TempPrintBuffer __tmp; \
|
||||
__tmp.bytes_count = 0; \
|
||||
__tmp.overflowed = 0; \
|
||||
u32 __char_idx = 0; \
|
||||
while (U32FromChar(fmt[__char_idx]) != 0) \
|
||||
{ \
|
||||
G_PushPrintByte(__tmp, U32FromChar(fmt[__char_idx])); \
|
||||
++__char_idx; \
|
||||
} \
|
||||
G_FmtArg __args[] = { __VA_ARGS__ }; \
|
||||
__tmp.chars_count = __char_idx; \
|
||||
__tmp.args_count = (countof(__args) - 1); \
|
||||
for (u32 __arg_idx = 0; __arg_idx < __tmp.args_count; ++__arg_idx) \
|
||||
{ \
|
||||
G_FmtArg __arg = __args[__arg_idx]; \
|
||||
G_PushPrintByte(__tmp, __arg.kind); \
|
||||
if (__arg.kind > G_FmtArgKind_BEGINSIZE1) \
|
||||
{ \
|
||||
G_PushPrintByte(__tmp, __arg.v.x >> 0); \
|
||||
G_PushPrintByte(__tmp, __arg.v.x >> 8); \
|
||||
G_PushPrintByte(__tmp, __arg.v.x >> 16); \
|
||||
G_PushPrintByte(__tmp, __arg.v.x >> 24); \
|
||||
} \
|
||||
if (__arg.kind > G_FmtArgKind_BEGINSIZE2) \
|
||||
{ \
|
||||
G_PushPrintByte(__tmp, __arg.v.y >> 0); \
|
||||
G_PushPrintByte(__tmp, __arg.v.y >> 8); \
|
||||
G_PushPrintByte(__tmp, __arg.v.y >> 16); \
|
||||
G_PushPrintByte(__tmp, __arg.v.y >> 24); \
|
||||
} \
|
||||
if (__arg.kind > G_FmtArgKind_BEGINSIZE3) \
|
||||
{ \
|
||||
G_PushPrintByte(__tmp, __arg.v.z >> 0); \
|
||||
G_PushPrintByte(__tmp, __arg.v.z >> 8); \
|
||||
G_PushPrintByte(__tmp, __arg.v.z >> 16); \
|
||||
G_PushPrintByte(__tmp, __arg.v.z >> 24); \
|
||||
} \
|
||||
if (__arg.kind > G_FmtArgKind_BEGINSIZE4) \
|
||||
{ \
|
||||
G_PushPrintByte(__tmp, __arg.v.w >> 0); \
|
||||
G_PushPrintByte(__tmp, __arg.v.w >> 8); \
|
||||
G_PushPrintByte(__tmp, __arg.v.w >> 16); \
|
||||
G_PushPrintByte(__tmp, __arg.v.w >> 24); \
|
||||
} \
|
||||
} \
|
||||
G_CommitPrint(__tmp); \
|
||||
} while (0)
|
||||
#define G_PrintF_(fmt, ...) do { \
|
||||
G_TempPrintBuffer __tmp; \
|
||||
__tmp.bytes_count = 0; \
|
||||
__tmp.overflowed = 0; \
|
||||
u32 __char_idx = 0; \
|
||||
while (U32FromChar(fmt[__char_idx]) != 0) \
|
||||
{ \
|
||||
G_PushPrintByte(__tmp, U32FromChar(fmt[__char_idx])); \
|
||||
++__char_idx; \
|
||||
} \
|
||||
G_FmtArg __args[] = { __VA_ARGS__ }; \
|
||||
__tmp.chars_count = __char_idx; \
|
||||
__tmp.args_count = (countof(__args) - 1); \
|
||||
for (u32 __arg_idx = 0; __arg_idx < __tmp.args_count; ++__arg_idx) \
|
||||
{ \
|
||||
G_FmtArg __arg = __args[__arg_idx]; \
|
||||
G_PushPrintByte(__tmp, __arg.kind); \
|
||||
if (__arg.kind > G_FmtArgKind_BEGINSIZE1) \
|
||||
{ \
|
||||
G_PushPrintByte(__tmp, __arg.v.x >> 0); \
|
||||
G_PushPrintByte(__tmp, __arg.v.x >> 8); \
|
||||
G_PushPrintByte(__tmp, __arg.v.x >> 16); \
|
||||
G_PushPrintByte(__tmp, __arg.v.x >> 24); \
|
||||
} \
|
||||
if (__arg.kind > G_FmtArgKind_BEGINSIZE2) \
|
||||
{ \
|
||||
G_PushPrintByte(__tmp, __arg.v.y >> 0); \
|
||||
G_PushPrintByte(__tmp, __arg.v.y >> 8); \
|
||||
G_PushPrintByte(__tmp, __arg.v.y >> 16); \
|
||||
G_PushPrintByte(__tmp, __arg.v.y >> 24); \
|
||||
} \
|
||||
if (__arg.kind > G_FmtArgKind_BEGINSIZE3) \
|
||||
{ \
|
||||
G_PushPrintByte(__tmp, __arg.v.z >> 0); \
|
||||
G_PushPrintByte(__tmp, __arg.v.z >> 8); \
|
||||
G_PushPrintByte(__tmp, __arg.v.z >> 16); \
|
||||
G_PushPrintByte(__tmp, __arg.v.z >> 24); \
|
||||
} \
|
||||
if (__arg.kind > G_FmtArgKind_BEGINSIZE4) \
|
||||
{ \
|
||||
G_PushPrintByte(__tmp, __arg.v.w >> 0); \
|
||||
G_PushPrintByte(__tmp, __arg.v.w >> 8); \
|
||||
G_PushPrintByte(__tmp, __arg.v.w >> 16); \
|
||||
G_PushPrintByte(__tmp, __arg.v.w >> 24); \
|
||||
} \
|
||||
} \
|
||||
G_CommitPrint(__tmp); \
|
||||
} while (0)
|
||||
|
||||
#define G_PrintF(fmt, ...) G_PrintF_(fmt, ##__VA_ARGS__, G_FmtEnd())
|
||||
#define G_PrintF(fmt, ...) G_PrintF_(fmt, ##__VA_ARGS__, G_FmtEnd())
|
||||
|
||||
#else
|
||||
#define G_PrintF(fmt)
|
||||
#define G_PrintF(fmt)
|
||||
#endif
|
||||
|
||||
1642
src/json/json.c
1642
src/json/json.c
File diff suppressed because it is too large
Load Diff
138
src/json/json.h
138
src/json/json.h
@ -3,126 +3,126 @@
|
||||
|
||||
Enum(JSON_Type)
|
||||
{
|
||||
JSON_Type_Null,
|
||||
JSON_Type_Bool,
|
||||
JSON_Type_Number,
|
||||
JSON_Type_String,
|
||||
JSON_Type_Array,
|
||||
JSON_Type_Object
|
||||
JSON_Type_Null,
|
||||
JSON_Type_Bool,
|
||||
JSON_Type_Number,
|
||||
JSON_Type_String,
|
||||
JSON_Type_Array,
|
||||
JSON_Type_Object
|
||||
};
|
||||
|
||||
Struct(JSON_Blob)
|
||||
{
|
||||
JSON_Type type;
|
||||
String key;
|
||||
JSON_Type type;
|
||||
String key;
|
||||
|
||||
JSON_Blob *parent;
|
||||
JSON_Blob *next;
|
||||
JSON_Blob *child_first;
|
||||
JSON_Blob *child_last;
|
||||
JSON_Blob *parent;
|
||||
JSON_Blob *next;
|
||||
JSON_Blob *child_first;
|
||||
JSON_Blob *child_last;
|
||||
|
||||
union
|
||||
{
|
||||
String string;
|
||||
f64 number;
|
||||
b32 boolean;
|
||||
} value;
|
||||
union
|
||||
{
|
||||
String string;
|
||||
f64 number;
|
||||
b32 boolean;
|
||||
} value;
|
||||
};
|
||||
|
||||
Struct(JSON_Error)
|
||||
{
|
||||
String msg;
|
||||
u64 start;
|
||||
u64 end;
|
||||
JSON_Error *next;
|
||||
String msg;
|
||||
u64 start;
|
||||
u64 end;
|
||||
JSON_Error *next;
|
||||
};
|
||||
|
||||
Struct(JSON_ErrorList)
|
||||
{
|
||||
u64 count;
|
||||
JSON_Error *first;
|
||||
JSON_Error *last;
|
||||
u64 count;
|
||||
JSON_Error *first;
|
||||
JSON_Error *last;
|
||||
};
|
||||
|
||||
Struct(JSON_Result)
|
||||
{
|
||||
JSON_Blob *root;
|
||||
JSON_ErrorList errors;
|
||||
JSON_Blob *root;
|
||||
JSON_ErrorList errors;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Lexer types
|
||||
|
||||
#define JSON_Case_Newline \
|
||||
0x0A: /* Line feed or New line */ \
|
||||
case 0x0D /* Carriage return */
|
||||
0x0A: /* Line feed or New line */ \
|
||||
case 0x0D /* Carriage return */
|
||||
|
||||
#define JSON_Case_Space \
|
||||
0x20: /* Space */ \
|
||||
case 0x09 /* Horizontal tab */
|
||||
0x20: /* Space */ \
|
||||
case 0x09 /* Horizontal tab */
|
||||
|
||||
#define JSON_Case_Digit0Through9 \
|
||||
'0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9'
|
||||
'0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9'
|
||||
|
||||
#define JSON_Case_Digit1Through9 \
|
||||
'1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9'
|
||||
'1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9'
|
||||
|
||||
#define JSON_Case_Symbol \
|
||||
',': case ':': case '[': case ']': case '{': case '}'
|
||||
',': case ':': case '[': case ']': case '{': case '}'
|
||||
|
||||
Enum(JSON_TokenKind)
|
||||
{
|
||||
JSON_TokenKind_Unknown,
|
||||
JSON_TokenKind_Unknown,
|
||||
|
||||
JSON_TokenKind_Number,
|
||||
JSON_TokenKind_String,
|
||||
JSON_TokenKind_Number,
|
||||
JSON_TokenKind_String,
|
||||
|
||||
JSON_TokenKind_KeywordTrue,
|
||||
JSON_TokenKind_KeywordFalse,
|
||||
JSON_TokenKind_KeywordNull,
|
||||
JSON_TokenKind_KeywordTrue,
|
||||
JSON_TokenKind_KeywordFalse,
|
||||
JSON_TokenKind_KeywordNull,
|
||||
|
||||
JSON_TokenKind_Comma,
|
||||
JSON_TokenKind_Colon,
|
||||
JSON_TokenKind_SquareBraceOpen,
|
||||
JSON_TokenKind_SquareBraceClose,
|
||||
JSON_TokenKind_CurlyBraceOpen,
|
||||
JSON_TokenKind_CurlyBraceClose,
|
||||
JSON_TokenKind_Comma,
|
||||
JSON_TokenKind_Colon,
|
||||
JSON_TokenKind_SquareBraceOpen,
|
||||
JSON_TokenKind_SquareBraceClose,
|
||||
JSON_TokenKind_CurlyBraceOpen,
|
||||
JSON_TokenKind_CurlyBraceClose,
|
||||
|
||||
JSON_TokenKind_Bof,
|
||||
JSON_TokenKind_Eof
|
||||
JSON_TokenKind_Bof,
|
||||
JSON_TokenKind_Eof
|
||||
};
|
||||
|
||||
Struct(JSON_Token)
|
||||
{
|
||||
JSON_TokenKind kind;
|
||||
u64 start;
|
||||
u64 end;
|
||||
JSON_Token *next;
|
||||
JSON_TokenKind kind;
|
||||
u64 start;
|
||||
u64 end;
|
||||
JSON_Token *next;
|
||||
};
|
||||
|
||||
Struct(JSON_TokenList)
|
||||
{
|
||||
JSON_Token *token_first;
|
||||
JSON_Token *token_last;
|
||||
JSON_Token *token_first;
|
||||
JSON_Token *token_last;
|
||||
};
|
||||
|
||||
Enum(JSON_LexNumberState)
|
||||
{
|
||||
JSON_LexNumberState_Whole,
|
||||
JSON_LexNumberState_Fraction,
|
||||
JSON_LexNumberState_Exponent
|
||||
JSON_LexNumberState_Whole,
|
||||
JSON_LexNumberState_Fraction,
|
||||
JSON_LexNumberState_Exponent
|
||||
};
|
||||
|
||||
Global Readonly String JSON_keyword_strings[] = {
|
||||
['t'] = CompLit("true"),
|
||||
['f'] = CompLit("false"),
|
||||
['n'] = CompLit("null")
|
||||
['t'] = CompLit("true"),
|
||||
['f'] = CompLit("false"),
|
||||
['n'] = CompLit("null")
|
||||
};
|
||||
|
||||
Global Readonly JSON_TokenKind JSON_keyword_types[] = {
|
||||
['t'] = JSON_TokenKind_KeywordTrue,
|
||||
['f'] = JSON_TokenKind_KeywordFalse,
|
||||
['n'] = JSON_TokenKind_KeywordNull
|
||||
['t'] = JSON_TokenKind_KeywordTrue,
|
||||
['f'] = JSON_TokenKind_KeywordFalse,
|
||||
['n'] = JSON_TokenKind_KeywordNull
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -130,13 +130,13 @@ Global Readonly JSON_TokenKind JSON_keyword_types[] = {
|
||||
|
||||
Struct(JSON_Parser)
|
||||
{
|
||||
/* Input */
|
||||
String src;
|
||||
JSON_Token *at;
|
||||
/* Input */
|
||||
String src;
|
||||
JSON_Token *at;
|
||||
|
||||
/* Output */
|
||||
JSON_Blob *root;
|
||||
JSON_ErrorList errors;
|
||||
/* Output */
|
||||
JSON_Blob *root;
|
||||
JSON_ErrorList errors;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
1812
src/meta/meta.c
1812
src/meta/meta.c
File diff suppressed because it is too large
Load Diff
158
src/meta/meta.h
158
src/meta/meta.h
@ -4,43 +4,43 @@
|
||||
//~ Base layer definitions
|
||||
|
||||
#ifndef IsConsoleApp
|
||||
# define IsConsoleApp 1
|
||||
#define IsConsoleApp 1
|
||||
#endif
|
||||
|
||||
#ifndef IsRtcEnabled
|
||||
# define IsRtcEnabled 1
|
||||
#define IsRtcEnabled 1
|
||||
#endif
|
||||
|
||||
#ifndef IsUnoptimized
|
||||
# define IsUnoptimized 1
|
||||
#define IsUnoptimized 1
|
||||
#endif
|
||||
|
||||
#ifndef IsAsanEnabled
|
||||
# define IsAsanEnabled 0
|
||||
#define IsAsanEnabled 0
|
||||
#endif
|
||||
|
||||
#ifndef IsCrtlibEnabled
|
||||
# define IsCrtlibEnabled 1
|
||||
#define IsCrtlibEnabled 1
|
||||
#endif
|
||||
|
||||
#ifndef IsDebinfoEnabled
|
||||
# define IsDebinfoEnabled 1
|
||||
#define IsDebinfoEnabled 1
|
||||
#endif
|
||||
|
||||
#ifndef IsDeveloperModeEnabled
|
||||
# define IsDeveloperModeEnabled 1
|
||||
#define IsDeveloperModeEnabled 1
|
||||
#endif
|
||||
|
||||
#ifndef IsUnoptimized
|
||||
# define IsUnoptimized 1
|
||||
#define IsUnoptimized 1
|
||||
#endif
|
||||
|
||||
#ifndef IsTestingEnabled
|
||||
# define IsTestingEnabled 0
|
||||
#define IsTestingEnabled 0
|
||||
#endif
|
||||
|
||||
#ifndef IsHotSwappingEnabled
|
||||
# define IsHotSwappingEnabled 0
|
||||
#define IsHotSwappingEnabled 0
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -60,8 +60,8 @@
|
||||
|
||||
Struct(LineCol)
|
||||
{
|
||||
i64 line;
|
||||
i64 col;
|
||||
i64 line;
|
||||
i64 col;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -69,109 +69,109 @@ Struct(LineCol)
|
||||
|
||||
Struct(CompilerParams)
|
||||
{
|
||||
StringList defs;
|
||||
StringList defs;
|
||||
|
||||
StringList warnings_msvc;
|
||||
StringList warnings_clang;
|
||||
StringList warnings_dxc;
|
||||
StringList warnings_msvc;
|
||||
StringList warnings_clang;
|
||||
StringList warnings_dxc;
|
||||
|
||||
StringList flags_msvc;
|
||||
StringList flags_clang;
|
||||
StringList flags_dxc;
|
||||
StringList flags_msvc;
|
||||
StringList flags_clang;
|
||||
StringList flags_dxc;
|
||||
|
||||
StringList compiler_only_flags_msvc;
|
||||
StringList compiler_only_flags_clang;
|
||||
StringList compiler_only_flags_msvc;
|
||||
StringList compiler_only_flags_clang;
|
||||
|
||||
StringList linker_only_flags_msvc;
|
||||
StringList linker_only_flags_clang;
|
||||
StringList linker_only_flags_msvc;
|
||||
StringList linker_only_flags_clang;
|
||||
};
|
||||
|
||||
Enum(ShaderEntryKind)
|
||||
{
|
||||
ShaderEntryKind_VS,
|
||||
ShaderEntryKind_PS,
|
||||
ShaderEntryKind_CS,
|
||||
ShaderEntryKind_VS,
|
||||
ShaderEntryKind_PS,
|
||||
ShaderEntryKind_CS,
|
||||
};
|
||||
|
||||
Struct(ShaderEntry)
|
||||
{
|
||||
ShaderEntry *next;
|
||||
ShaderEntryKind kind;
|
||||
String name;
|
||||
ShaderEntry *next;
|
||||
ShaderEntryKind kind;
|
||||
String name;
|
||||
};
|
||||
|
||||
Struct(ResDir)
|
||||
{
|
||||
ResDir *next;
|
||||
String dir_path;
|
||||
String store_name;
|
||||
ResDir *next;
|
||||
String dir_path;
|
||||
String store_name;
|
||||
};
|
||||
|
||||
Struct(GpuObj)
|
||||
{
|
||||
String output;
|
||||
i32 return_code;
|
||||
String output;
|
||||
i32 return_code;
|
||||
};
|
||||
|
||||
Struct(EmbedObj)
|
||||
{
|
||||
String obj_file;
|
||||
String output;
|
||||
i32 return_code;
|
||||
String obj_file;
|
||||
String output;
|
||||
i32 return_code;
|
||||
};
|
||||
|
||||
Struct(BuildCtx)
|
||||
{
|
||||
Atomic32 status;
|
||||
Atomic32 status;
|
||||
|
||||
M_Layer layers_parse;
|
||||
M_Layer layers_parse;
|
||||
|
||||
struct
|
||||
{
|
||||
M_ErrorList errors;
|
||||
} c_parse;
|
||||
struct
|
||||
{
|
||||
M_ErrorList errors;
|
||||
} c_parse;
|
||||
|
||||
struct
|
||||
{
|
||||
M_ErrorList errors;
|
||||
ShaderEntry *first_shader_entry;
|
||||
ShaderEntry *last_shader_entry;
|
||||
u64 shader_entries_count;
|
||||
} gpu_parse;
|
||||
struct
|
||||
{
|
||||
M_ErrorList errors;
|
||||
ShaderEntry *first_shader_entry;
|
||||
ShaderEntry *last_shader_entry;
|
||||
u64 shader_entries_count;
|
||||
} gpu_parse;
|
||||
|
||||
struct
|
||||
{
|
||||
M_ErrorList errors;
|
||||
ResDir *first_res_dir;
|
||||
ResDir *last_res_dir;
|
||||
u64 res_dirs_count;
|
||||
} res_dir_parse;
|
||||
struct
|
||||
{
|
||||
M_ErrorList errors;
|
||||
ResDir *first_res_dir;
|
||||
ResDir *last_res_dir;
|
||||
u64 res_dirs_count;
|
||||
} res_dir_parse;
|
||||
|
||||
struct
|
||||
{
|
||||
String obj_file;
|
||||
String output;
|
||||
i32 return_code;
|
||||
} c_obj;
|
||||
struct
|
||||
{
|
||||
String obj_file;
|
||||
String output;
|
||||
i32 return_code;
|
||||
} c_obj;
|
||||
|
||||
struct
|
||||
{
|
||||
GpuObj *array;
|
||||
u32 count;
|
||||
Atomic32 finished_count;
|
||||
} gpu_objs;
|
||||
struct
|
||||
{
|
||||
GpuObj *array;
|
||||
u32 count;
|
||||
Atomic32 finished_count;
|
||||
} gpu_objs;
|
||||
|
||||
struct
|
||||
{
|
||||
EmbedObj *array;
|
||||
u32 count;
|
||||
} embed_objs;
|
||||
struct
|
||||
{
|
||||
EmbedObj *array;
|
||||
u32 count;
|
||||
} embed_objs;
|
||||
|
||||
struct
|
||||
{
|
||||
String output;
|
||||
i32 return_code;
|
||||
} link;
|
||||
struct
|
||||
{
|
||||
String output;
|
||||
i32 return_code;
|
||||
} link;
|
||||
};
|
||||
|
||||
extern BuildCtx Build;
|
||||
|
||||
@ -3,82 +3,82 @@
|
||||
|
||||
String F_GetFull(Arena *arena, String path)
|
||||
{
|
||||
return OS_GetFullPath(arena, 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)
|
||||
String result = OS_GetFullPath(arena, path);
|
||||
for (u64 i = 0; i < result.len; ++i)
|
||||
{
|
||||
if (result.text[i] == '\\')
|
||||
{
|
||||
if (result.text[i] == '\\')
|
||||
{
|
||||
result.text[i] = '/';
|
||||
}
|
||||
result.text[i] = '/';
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
String F_GetFileName(String path)
|
||||
{
|
||||
String result = path;
|
||||
u64 start = path.len;
|
||||
for (u64 i = path.len; i-- > 0;)
|
||||
String result = path;
|
||||
u64 start = path.len;
|
||||
for (u64 i = path.len; i-- > 0;)
|
||||
{
|
||||
if (path.text[i] == '\\' || path.text[i] == '/')
|
||||
{
|
||||
if (path.text[i] == '\\' || path.text[i] == '/')
|
||||
{
|
||||
start = i + 1;
|
||||
break;
|
||||
}
|
||||
start = i + 1;
|
||||
break;
|
||||
}
|
||||
if (start < path.len)
|
||||
{
|
||||
result.text = &path.text[start];
|
||||
result.len = path.len - start;
|
||||
}
|
||||
if (start < path.len)
|
||||
{
|
||||
result.text = &path.text[start];
|
||||
result.len = path.len - start;
|
||||
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
String F_GetParentDir(String path)
|
||||
{
|
||||
String result = Zi;
|
||||
result.text = path.text;
|
||||
u64 end = path.len;
|
||||
for (u64 i = path.len; i-- > 0;)
|
||||
String result = Zi;
|
||||
result.text = path.text;
|
||||
u64 end = path.len;
|
||||
for (u64 i = path.len; i-- > 0;)
|
||||
{
|
||||
if (path.text[i] == '\\' || path.text[i] == '/')
|
||||
{
|
||||
if (path.text[i] == '\\' || path.text[i] == '/')
|
||||
{
|
||||
end = i + 1;
|
||||
break;
|
||||
}
|
||||
end = i + 1;
|
||||
break;
|
||||
}
|
||||
if (end < path.len)
|
||||
{
|
||||
result.len = end;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
if (end < path.len)
|
||||
{
|
||||
result.len = end;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
String F_ExtensionFromFile(String path)
|
||||
{
|
||||
String result = Zi;
|
||||
u64 start = path.len;
|
||||
for (u64 i = path.len; i-- > 0;)
|
||||
String result = Zi;
|
||||
u64 start = path.len;
|
||||
for (u64 i = path.len; i-- > 0;)
|
||||
{
|
||||
if (path.text[i] == '.')
|
||||
{
|
||||
if (path.text[i] == '.')
|
||||
{
|
||||
start = i + 1;
|
||||
break;
|
||||
}
|
||||
start = i + 1;
|
||||
break;
|
||||
}
|
||||
if (start < path.len)
|
||||
{
|
||||
result.text = &path.text[start];
|
||||
result.len = path.len - start;
|
||||
}
|
||||
if (start < path.len)
|
||||
{
|
||||
result.text = &path.text[start];
|
||||
result.len = path.len - start;
|
||||
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -86,11 +86,11 @@ String F_ExtensionFromFile(String path)
|
||||
|
||||
String F_DataFromFile(Arena *arena, String path)
|
||||
{
|
||||
String result = Zi;
|
||||
OS_File file = OS_OpenFile(path, OS_FileFlag_Read, I64Max);
|
||||
result = OS_ReadEntireFile(arena, file);
|
||||
OS_CloseFile(file);
|
||||
return result;
|
||||
String result = Zi;
|
||||
OS_File file = OS_OpenFile(path, OS_FileFlag_Read, I64Max);
|
||||
result = OS_ReadEntireFile(arena, file);
|
||||
OS_CloseFile(file);
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -98,9 +98,9 @@ String F_DataFromFile(Arena *arena, String path)
|
||||
|
||||
void F_ClearWrite(String path, String data)
|
||||
{
|
||||
OS_File file = OS_OpenFile(path, OS_FileFlag_Write | OS_FileFlag_Create, I64Max);
|
||||
OS_ClearWriteFile(file, data);
|
||||
OS_CloseFile(file);
|
||||
OS_File file = OS_OpenFile(path, OS_FileFlag_Write | OS_FileFlag_Create, I64Max);
|
||||
OS_ClearWriteFile(file, data);
|
||||
OS_CloseFile(file);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -108,12 +108,12 @@ void F_ClearWrite(String path, String data)
|
||||
|
||||
b32 F_IsFile(String path)
|
||||
{
|
||||
return OS_FileExists(path);
|
||||
return OS_FileExists(path);
|
||||
}
|
||||
|
||||
b32 F_IsDir(String path)
|
||||
{
|
||||
return OS_DirExists(path);
|
||||
return OS_DirExists(path);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -121,18 +121,18 @@ b32 F_IsDir(String path)
|
||||
|
||||
void F_FilesFromDir(Arena *arena, StringList *list, String dir, F_IterFlag flags)
|
||||
{
|
||||
TempArena scratch = BeginScratch(arena);
|
||||
StringList tmp = Zi;
|
||||
String dir_full_path = F_GetFull(scratch.arena, dir);
|
||||
OS_DirContentsFromFullPath(scratch.arena, &tmp, dir_full_path);
|
||||
for (StringListNode *n = tmp.first; n; n = n->next)
|
||||
TempArena scratch = BeginScratch(arena);
|
||||
StringList tmp = Zi;
|
||||
String dir_full_path = F_GetFull(scratch.arena, dir);
|
||||
OS_DirContentsFromFullPath(scratch.arena, &tmp, dir_full_path);
|
||||
for (StringListNode *n = tmp.first; n; n = n->next)
|
||||
{
|
||||
String file_joined_path = StringF(arena, "%F/%F", FmtString(dir), FmtString(n->s));
|
||||
PushStringToList(arena, list, file_joined_path);
|
||||
if (flags & F_IterFlag_Recurse && F_IsDir(file_joined_path))
|
||||
{
|
||||
String file_joined_path = StringF(arena, "%F/%F", FmtString(dir), FmtString(n->s));
|
||||
PushStringToList(arena, list, file_joined_path);
|
||||
if (flags & F_IterFlag_Recurse && F_IsDir(file_joined_path))
|
||||
{
|
||||
F_FilesFromDir(arena, list, file_joined_path, flags);
|
||||
}
|
||||
F_FilesFromDir(arena, list, file_joined_path, flags);
|
||||
}
|
||||
EndScratch(scratch);
|
||||
}
|
||||
EndScratch(scratch);
|
||||
}
|
||||
|
||||
@ -3,8 +3,8 @@
|
||||
|
||||
Enum(F_IterFlag)
|
||||
{
|
||||
F_IterFlag_None = 0,
|
||||
F_IterFlag_Recurse = (1 << 0)
|
||||
F_IterFlag_None = 0,
|
||||
F_IterFlag_Recurse = (1 << 0)
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -3,16 +3,16 @@
|
||||
|
||||
Struct(M_Error)
|
||||
{
|
||||
M_Error *next;
|
||||
String msg;
|
||||
struct M_Token *token;
|
||||
M_Error *next;
|
||||
String msg;
|
||||
struct M_Token *token;
|
||||
};
|
||||
|
||||
Struct(M_ErrorList)
|
||||
{
|
||||
M_Error *first;
|
||||
M_Error *last;
|
||||
u64 count;
|
||||
M_Error *first;
|
||||
M_Error *last;
|
||||
u64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -20,8 +20,8 @@ Struct(M_ErrorList)
|
||||
|
||||
Struct(M_File)
|
||||
{
|
||||
String name;
|
||||
String data;
|
||||
String name;
|
||||
String data;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -29,41 +29,41 @@ Struct(M_File)
|
||||
|
||||
Enum(M_TokenKind)
|
||||
{
|
||||
M_TokenKind_Ident,
|
||||
M_TokenKind_Eol, /* End of line */
|
||||
M_TokenKind_Ident,
|
||||
M_TokenKind_Eol, /* End of line */
|
||||
};
|
||||
|
||||
Struct(M_Token)
|
||||
{
|
||||
b32 valid;
|
||||
M_Token *next;
|
||||
b32 valid;
|
||||
M_Token *next;
|
||||
|
||||
M_TokenKind kind;
|
||||
struct M_TokenFile *file;
|
||||
M_TokenKind kind;
|
||||
struct M_TokenFile *file;
|
||||
|
||||
String s;
|
||||
String s;
|
||||
} extern Readonly M_NilToken;
|
||||
|
||||
Struct(M_TokenFile)
|
||||
{
|
||||
b32 valid;
|
||||
M_TokenFile *next;
|
||||
b32 valid;
|
||||
M_TokenFile *next;
|
||||
|
||||
String name;
|
||||
String data;
|
||||
String name;
|
||||
String data;
|
||||
|
||||
M_Token *first_token;
|
||||
M_Token *last_token;
|
||||
u64 tokens_count;
|
||||
M_Token *first_token;
|
||||
M_Token *last_token;
|
||||
u64 tokens_count;
|
||||
|
||||
M_ErrorList errors;
|
||||
M_ErrorList errors;
|
||||
} extern Readonly M_NilTokenFile;
|
||||
|
||||
Struct(M_TokenFileList)
|
||||
{
|
||||
M_TokenFile *first;
|
||||
M_TokenFile *last;
|
||||
u64 count;
|
||||
M_TokenFile *first;
|
||||
M_TokenFile *last;
|
||||
u64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -71,68 +71,68 @@ Struct(M_TokenFileList)
|
||||
|
||||
Enum(M_EntryKind)
|
||||
{
|
||||
M_EntryKind_Unknown,
|
||||
M_EntryKind_Layer,
|
||||
M_EntryKind_Dep,
|
||||
M_EntryKind_IncludeC,
|
||||
M_EntryKind_IncludeG,
|
||||
M_EntryKind_DefaultDownstream,
|
||||
M_EntryKind_Bootstrap,
|
||||
M_EntryKind_VertexShader,
|
||||
M_EntryKind_PixelShader,
|
||||
M_EntryKind_ComputeShader,
|
||||
M_EntryKind_EmbedDir,
|
||||
M_EntryKind_Unknown,
|
||||
M_EntryKind_Layer,
|
||||
M_EntryKind_Dep,
|
||||
M_EntryKind_IncludeC,
|
||||
M_EntryKind_IncludeG,
|
||||
M_EntryKind_DefaultDownstream,
|
||||
M_EntryKind_Bootstrap,
|
||||
M_EntryKind_VertexShader,
|
||||
M_EntryKind_PixelShader,
|
||||
M_EntryKind_ComputeShader,
|
||||
M_EntryKind_EmbedDir,
|
||||
};
|
||||
|
||||
Enum(M_PlatformKind)
|
||||
{
|
||||
M_PlatformKind_Any,
|
||||
M_PlatformKind_Win32,
|
||||
M_PlatformKind_Any,
|
||||
M_PlatformKind_Win32,
|
||||
};
|
||||
|
||||
Global Readonly char *M_entry_kind_rules[] = {
|
||||
[M_EntryKind_Layer] = "@Layer",
|
||||
[M_EntryKind_Dep] = "@Dep",
|
||||
[M_EntryKind_IncludeC] = "@IncludeC",
|
||||
[M_EntryKind_IncludeG] = "@IncludeG",
|
||||
[M_EntryKind_DefaultDownstream] = "@DefaultDownstream",
|
||||
[M_EntryKind_Bootstrap] = "@Bootstrap",
|
||||
[M_EntryKind_VertexShader] = "@VertexShader",
|
||||
[M_EntryKind_PixelShader] = "@PixelShader",
|
||||
[M_EntryKind_ComputeShader] = "@ComputeShader",
|
||||
[M_EntryKind_EmbedDir] = "@EmbedDir",
|
||||
[M_EntryKind_Layer] = "@Layer",
|
||||
[M_EntryKind_Dep] = "@Dep",
|
||||
[M_EntryKind_IncludeC] = "@IncludeC",
|
||||
[M_EntryKind_IncludeG] = "@IncludeG",
|
||||
[M_EntryKind_DefaultDownstream] = "@DefaultDownstream",
|
||||
[M_EntryKind_Bootstrap] = "@Bootstrap",
|
||||
[M_EntryKind_VertexShader] = "@VertexShader",
|
||||
[M_EntryKind_PixelShader] = "@PixelShader",
|
||||
[M_EntryKind_ComputeShader] = "@ComputeShader",
|
||||
[M_EntryKind_EmbedDir] = "@EmbedDir",
|
||||
};
|
||||
|
||||
Struct(M_Entry)
|
||||
{
|
||||
b32 valid;
|
||||
M_Entry *next;
|
||||
b32 valid;
|
||||
M_Entry *next;
|
||||
|
||||
M_EntryKind kind;
|
||||
M_Token *name_token;
|
||||
M_EntryKind kind;
|
||||
M_Token *name_token;
|
||||
|
||||
M_Token *arg_tokens[2];
|
||||
u64 args_count;
|
||||
M_Token *arg_tokens[2];
|
||||
u64 args_count;
|
||||
} extern Readonly M_NilEntry;
|
||||
|
||||
Struct(M_Layer)
|
||||
{
|
||||
b32 valid;
|
||||
M_Layer *next;
|
||||
b32 valid;
|
||||
M_Layer *next;
|
||||
|
||||
M_TokenFile *file;
|
||||
M_TokenFile *file;
|
||||
|
||||
M_Entry *first;
|
||||
M_Entry *last;
|
||||
u64 count;
|
||||
M_ErrorList errors;
|
||||
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;
|
||||
M_Layer *first;
|
||||
M_Layer *last;
|
||||
u64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
@ -3,15 +3,15 @@
|
||||
|
||||
Enum(OS_FileFlag)
|
||||
{
|
||||
OS_FileFlag_None = 0,
|
||||
OS_FileFlag_Read = (1 << 0),
|
||||
OS_FileFlag_Write = (1 << 1),
|
||||
OS_FileFlag_Create = (1 << 2),
|
||||
OS_FileFlag_None = 0,
|
||||
OS_FileFlag_Read = (1 << 0),
|
||||
OS_FileFlag_Write = (1 << 1),
|
||||
OS_FileFlag_Create = (1 << 2),
|
||||
};
|
||||
|
||||
Struct(OS_File)
|
||||
{
|
||||
u64 handle;
|
||||
u64 handle;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -19,8 +19,8 @@ Struct(OS_File)
|
||||
|
||||
Struct(OS_CommandResult)
|
||||
{
|
||||
i32 code;
|
||||
String output;
|
||||
i32 code;
|
||||
String output;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
#include "meta_os.h"
|
||||
|
||||
#if IsPlatformWindows
|
||||
# include "meta_os_win32/meta_os_win32_inc.h"
|
||||
#include "meta_os_win32/meta_os_win32_inc.h"
|
||||
#endif
|
||||
|
||||
@ -3,27 +3,27 @@
|
||||
|
||||
String W32_StringFromError(Arena *arena, DWORD err)
|
||||
{
|
||||
String result = Zi;
|
||||
char *msg_cstr = 0;
|
||||
i64 len = FormatMessageA(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
0,
|
||||
err,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPSTR)&msg_cstr,
|
||||
0,
|
||||
0
|
||||
);
|
||||
if (len > 0)
|
||||
{
|
||||
result = PushString(arena, TrimWhitespace(StringFromCstr(msg_cstr, len)));
|
||||
LocalFree(msg_cstr);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = StringF(arena, "Unknown win32 error - %F", FmtHex(err));
|
||||
}
|
||||
return result;
|
||||
String result = Zi;
|
||||
char *msg_cstr = 0;
|
||||
i64 len = FormatMessageA(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
0,
|
||||
err,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPSTR)&msg_cstr,
|
||||
0,
|
||||
0
|
||||
);
|
||||
if (len > 0)
|
||||
{
|
||||
result = PushString(arena, TrimWhitespace(StringFromCstr(msg_cstr, len)));
|
||||
LocalFree(msg_cstr);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = StringF(arena, "Unknown win32 error - %F", FmtHex(err));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -38,117 +38,117 @@ void OS_Bootstrap(void)
|
||||
|
||||
OS_File OS_OpenFile(String path, OS_FileFlag flags, i64 timeout_ns)
|
||||
{
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
OS_File result = Zi;
|
||||
wchar_t *path_wstr = WstrFromString(scratch.arena, path);
|
||||
u32 share_mode = FILE_SHARE_READ;
|
||||
u32 create_mode = OPEN_EXISTING;
|
||||
u32 access_flags = 0;
|
||||
if (flags & OS_FileFlag_Read) access_flags |= GENERIC_READ;
|
||||
if (flags & OS_FileFlag_Write) access_flags |= GENERIC_WRITE;
|
||||
if (flags & OS_FileFlag_Create) create_mode = OPEN_ALWAYS;
|
||||
i32 timeout_ms = timeout_ns / 1000000;
|
||||
i32 elapsed_ms = 0;
|
||||
i32 delay_ms = 1;
|
||||
HANDLE handle = INVALID_HANDLE_VALUE;
|
||||
for (;;)
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
OS_File result = Zi;
|
||||
wchar_t *path_wstr = WstrFromString(scratch.arena, path);
|
||||
u32 share_mode = FILE_SHARE_READ;
|
||||
u32 create_mode = OPEN_EXISTING;
|
||||
u32 access_flags = 0;
|
||||
if (flags & OS_FileFlag_Read) access_flags |= GENERIC_READ;
|
||||
if (flags & OS_FileFlag_Write) access_flags |= GENERIC_WRITE;
|
||||
if (flags & OS_FileFlag_Create) create_mode = OPEN_ALWAYS;
|
||||
i32 timeout_ms = timeout_ns / 1000000;
|
||||
i32 elapsed_ms = 0;
|
||||
i32 delay_ms = 1;
|
||||
HANDLE handle = INVALID_HANDLE_VALUE;
|
||||
for (;;)
|
||||
{
|
||||
handle = CreateFileW(path_wstr, access_flags, share_mode, 0, create_mode, FILE_ATTRIBUTE_NORMAL, 0);
|
||||
if (handle == INVALID_HANDLE_VALUE && elapsed_ms < timeout_ms && GetLastError() == ERROR_SHARING_VIOLATION)
|
||||
{
|
||||
handle = CreateFileW(path_wstr, access_flags, share_mode, 0, create_mode, FILE_ATTRIBUTE_NORMAL, 0);
|
||||
if (handle == INVALID_HANDLE_VALUE && elapsed_ms < timeout_ms && GetLastError() == ERROR_SHARING_VIOLATION)
|
||||
{
|
||||
Sleep(delay_ms);
|
||||
elapsed_ms += delay_ms;
|
||||
delay_ms = MinI32(delay_ms * 2, 1024);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
Sleep(delay_ms);
|
||||
elapsed_ms += delay_ms;
|
||||
delay_ms = MinI32(delay_ms * 2, 1024);
|
||||
}
|
||||
EndScratch(scratch);
|
||||
result.handle = (u64)handle;
|
||||
return result;
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
EndScratch(scratch);
|
||||
result.handle = (u64)handle;
|
||||
return result;
|
||||
}
|
||||
|
||||
void OS_CloseFile(OS_File file)
|
||||
{
|
||||
HANDLE handle = (HANDLE)file.handle;
|
||||
CloseHandle(handle);
|
||||
HANDLE handle = (HANDLE)file.handle;
|
||||
CloseHandle(handle);
|
||||
}
|
||||
|
||||
String OS_ReadEntireFile(Arena *arena, OS_File file)
|
||||
{
|
||||
String result = Zi;
|
||||
HANDLE handle = (HANDLE)file.handle;
|
||||
u32 chunk_size = Kibi(64);
|
||||
result.text = ArenaNext(arena, u8);
|
||||
for (;;)
|
||||
String result = Zi;
|
||||
HANDLE handle = (HANDLE)file.handle;
|
||||
u32 chunk_size = Kibi(64);
|
||||
result.text = ArenaNext(arena, u8);
|
||||
for (;;)
|
||||
{
|
||||
u8 *chunk = PushStructsNoZero(arena, u8, chunk_size);
|
||||
DWORD chunk_bytes_read = 0;
|
||||
ReadFile(handle, chunk, chunk_size, &chunk_bytes_read, 0);
|
||||
result.len += chunk_bytes_read;
|
||||
if (chunk_bytes_read < chunk_size)
|
||||
{
|
||||
u8 *chunk = PushStructsNoZero(arena, u8, chunk_size);
|
||||
DWORD chunk_bytes_read = 0;
|
||||
ReadFile(handle, chunk, chunk_size, &chunk_bytes_read, 0);
|
||||
result.len += chunk_bytes_read;
|
||||
if (chunk_bytes_read < chunk_size)
|
||||
{
|
||||
PopStructsNoCopy(arena, u8, chunk_size - chunk_bytes_read);
|
||||
break;
|
||||
}
|
||||
PopStructsNoCopy(arena, u8, chunk_size - chunk_bytes_read);
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void OS_ClearWriteFile(OS_File file, String data)
|
||||
{
|
||||
HANDLE handle = (HANDLE)file.handle;
|
||||
SetFilePointer(handle, 0, 0, FILE_BEGIN);
|
||||
SetEndOfFile(handle);
|
||||
WriteFile(handle, data.text, data.len, 0, 0);
|
||||
HANDLE handle = (HANDLE)file.handle;
|
||||
SetFilePointer(handle, 0, 0, FILE_BEGIN);
|
||||
SetEndOfFile(handle);
|
||||
WriteFile(handle, data.text, data.len, 0, 0);
|
||||
}
|
||||
|
||||
void OS_DirContentsFromFullPath(Arena *arena, StringList *list, String path)
|
||||
{
|
||||
TempArena scratch = BeginScratch(arena);
|
||||
WIN32_FIND_DATAW find_data = Zi;
|
||||
String filter = StringF(scratch.arena, "%F\\*", FmtString(path));
|
||||
wchar_t *filter_wstr = WstrFromString(scratch.arena, filter);
|
||||
HANDLE find_handle = FindFirstFileExW(filter_wstr, FindExInfoStandard, &find_data, FindExSearchNameMatch, 0, FIND_FIRST_EX_CASE_SENSITIVE | FIND_FIRST_EX_LARGE_FETCH);
|
||||
b32 found = find_handle && find_handle != INVALID_HANDLE_VALUE;
|
||||
while (found)
|
||||
TempArena scratch = BeginScratch(arena);
|
||||
WIN32_FIND_DATAW find_data = Zi;
|
||||
String filter = StringF(scratch.arena, "%F\\*", FmtString(path));
|
||||
wchar_t *filter_wstr = WstrFromString(scratch.arena, filter);
|
||||
HANDLE find_handle = FindFirstFileExW(filter_wstr, FindExInfoStandard, &find_data, FindExSearchNameMatch, 0, FIND_FIRST_EX_CASE_SENSITIVE | FIND_FIRST_EX_LARGE_FETCH);
|
||||
b32 found = find_handle && find_handle != INVALID_HANDLE_VALUE;
|
||||
while (found)
|
||||
{
|
||||
String file_name = StringFromWstrNoLimit(arena, find_data.cFileName);
|
||||
if (!MatchString(file_name, Lit(".")) && !MatchString(file_name, Lit("..")))
|
||||
{
|
||||
String file_name = StringFromWstrNoLimit(arena, find_data.cFileName);
|
||||
if (!MatchString(file_name, Lit(".")) && !MatchString(file_name, Lit("..")))
|
||||
{
|
||||
PushStringToList(arena, list, file_name);
|
||||
}
|
||||
found = FindNextFileW(find_handle, &find_data);
|
||||
PushStringToList(arena, list, file_name);
|
||||
}
|
||||
EndScratch(scratch);
|
||||
found = FindNextFileW(find_handle, &find_data);
|
||||
}
|
||||
EndScratch(scratch);
|
||||
}
|
||||
|
||||
String OS_GetFullPath(Arena *arena, String path)
|
||||
{
|
||||
TempArena scratch = BeginScratch(arena);
|
||||
wchar_t *rel_path_wstr = WstrFromString(scratch.arena, path);
|
||||
wchar_t full_path_wstr_buff[4096];
|
||||
GetFullPathNameW(rel_path_wstr, countof(full_path_wstr_buff), full_path_wstr_buff, 0);
|
||||
String res = StringFromWstr(arena, full_path_wstr_buff, countof(full_path_wstr_buff));
|
||||
EndScratch(scratch);
|
||||
return res;
|
||||
TempArena scratch = BeginScratch(arena);
|
||||
wchar_t *rel_path_wstr = WstrFromString(scratch.arena, path);
|
||||
wchar_t full_path_wstr_buff[4096];
|
||||
GetFullPathNameW(rel_path_wstr, countof(full_path_wstr_buff), full_path_wstr_buff, 0);
|
||||
String res = StringFromWstr(arena, full_path_wstr_buff, countof(full_path_wstr_buff));
|
||||
EndScratch(scratch);
|
||||
return res;
|
||||
}
|
||||
|
||||
u64 OS_LastWriteTimestampFromPath(String path)
|
||||
{
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
u64 result = 0;
|
||||
WIN32_FILE_ATTRIBUTE_DATA a = Zi;
|
||||
wchar_t *path_wstr = WstrFromString(scratch.arena, path);
|
||||
if (GetFileAttributesExW(path_wstr, GetFileExInfoStandard, &a))
|
||||
{
|
||||
result = ((ULONGLONG)a.ftLastWriteTime.dwHighDateTime << 32) |
|
||||
(ULONGLONG)a.ftLastWriteTime.dwLowDateTime;
|
||||
}
|
||||
EndScratch(scratch);
|
||||
return result;
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
u64 result = 0;
|
||||
WIN32_FILE_ATTRIBUTE_DATA a = Zi;
|
||||
wchar_t *path_wstr = WstrFromString(scratch.arena, path);
|
||||
if (GetFileAttributesExW(path_wstr, GetFileExInfoStandard, &a))
|
||||
{
|
||||
result = ((ULONGLONG)a.ftLastWriteTime.dwHighDateTime << 32) |
|
||||
(ULONGLONG)a.ftLastWriteTime.dwLowDateTime;
|
||||
}
|
||||
EndScratch(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -156,45 +156,45 @@ u64 OS_LastWriteTimestampFromPath(String path)
|
||||
|
||||
b32 OS_FileOrDirExists(String path)
|
||||
{
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
wchar_t *path_wstr = WstrFromString(scratch.arena, path);
|
||||
DWORD attributes = GetFileAttributesW(path_wstr);
|
||||
EndScratch(scratch);
|
||||
return attributes != INVALID_FILE_ATTRIBUTES;
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
wchar_t *path_wstr = WstrFromString(scratch.arena, path);
|
||||
DWORD attributes = GetFileAttributesW(path_wstr);
|
||||
EndScratch(scratch);
|
||||
return attributes != INVALID_FILE_ATTRIBUTES;
|
||||
}
|
||||
|
||||
b32 OS_FileExists(String path)
|
||||
{
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
wchar_t *path_wstr = WstrFromString(scratch.arena, path);
|
||||
DWORD attributes = GetFileAttributesW(path_wstr);
|
||||
EndScratch(scratch);
|
||||
return attributes != INVALID_FILE_ATTRIBUTES && !(attributes & FILE_ATTRIBUTE_DIRECTORY);
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
wchar_t *path_wstr = WstrFromString(scratch.arena, path);
|
||||
DWORD attributes = GetFileAttributesW(path_wstr);
|
||||
EndScratch(scratch);
|
||||
return attributes != INVALID_FILE_ATTRIBUTES && !(attributes & FILE_ATTRIBUTE_DIRECTORY);
|
||||
}
|
||||
|
||||
b32 OS_DirExists(String path)
|
||||
{
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
wchar_t *path_wstr = WstrFromString(scratch.arena, path);
|
||||
DWORD attributes = GetFileAttributesW(path_wstr);
|
||||
EndScratch(scratch);
|
||||
return attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY);
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
wchar_t *path_wstr = WstrFromString(scratch.arena, path);
|
||||
DWORD attributes = GetFileAttributesW(path_wstr);
|
||||
EndScratch(scratch);
|
||||
return attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY);
|
||||
}
|
||||
|
||||
void OS_Mkdir(String path)
|
||||
{
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
wchar_t *path_wstr = WstrFromString(scratch.arena, path);
|
||||
CreateDirectoryW(path_wstr, 0);
|
||||
EndScratch(scratch);
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
wchar_t *path_wstr = WstrFromString(scratch.arena, path);
|
||||
CreateDirectoryW(path_wstr, 0);
|
||||
EndScratch(scratch);
|
||||
}
|
||||
|
||||
void OS_Rm(String path)
|
||||
{
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
wchar_t *path_wstr = WstrFromString(scratch.arena, path);
|
||||
DeleteFile(path_wstr);
|
||||
EndScratch(scratch);
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
wchar_t *path_wstr = WstrFromString(scratch.arena, path);
|
||||
DeleteFile(path_wstr);
|
||||
EndScratch(scratch);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -202,150 +202,150 @@ void OS_Rm(String path)
|
||||
|
||||
OS_CommandResult OS_RunCommand(Arena *arena, String cmd)
|
||||
{
|
||||
TempArena scratch = BeginScratch(arena);
|
||||
OS_CommandResult result = Zi;
|
||||
b32 ok = 1;
|
||||
TempArena scratch = BeginScratch(arena);
|
||||
OS_CommandResult result = Zi;
|
||||
b32 ok = 1;
|
||||
|
||||
wchar_t *cmd_wstr = WstrFromString(scratch.arena, cmd);
|
||||
wchar_t *cmd_wstr = WstrFromString(scratch.arena, cmd);
|
||||
|
||||
SECURITY_ATTRIBUTES sa = Zi;
|
||||
sa.nLength = sizeof(sa);
|
||||
sa.bInheritHandle = 0;
|
||||
SECURITY_ATTRIBUTES sa = Zi;
|
||||
sa.nLength = sizeof(sa);
|
||||
sa.bInheritHandle = 0;
|
||||
|
||||
/* Create pipe */
|
||||
HANDLE pipe_read = 0;
|
||||
HANDLE pipe_write = 0;
|
||||
/* Create pipe */
|
||||
HANDLE pipe_read = 0;
|
||||
HANDLE pipe_write = 0;
|
||||
if (ok)
|
||||
{
|
||||
ok = CreatePipe(&pipe_read, &pipe_write, &sa, 0) != 0;
|
||||
if (!ok)
|
||||
{
|
||||
result.output = Lit("Failed to create pipe");
|
||||
pipe_read = 0;
|
||||
pipe_write = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Duplicate pipe for child process */
|
||||
HANDLE child_pipe_write = 0;
|
||||
if (ok)
|
||||
{
|
||||
ok = DuplicateHandle(GetCurrentProcess(), pipe_write, GetCurrentProcess(), &child_pipe_write, 0, 1, DUPLICATE_SAME_ACCESS) != 0;
|
||||
if (!ok)
|
||||
{
|
||||
result.output = Lit("Failed to create child pipe");
|
||||
child_pipe_write = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize attrs list */
|
||||
LPPROC_THREAD_ATTRIBUTE_LIST attrs = Zi;
|
||||
if (ok)
|
||||
{
|
||||
u64 attrs_size = 0;
|
||||
InitializeProcThreadAttributeList(0, 1, 0, &attrs_size);
|
||||
ok = attrs_size > 0;
|
||||
if (ok)
|
||||
{
|
||||
ok = CreatePipe(&pipe_read, &pipe_write, &sa, 0) != 0;
|
||||
if (!ok)
|
||||
{
|
||||
result.output = Lit("Failed to create pipe");
|
||||
pipe_read = 0;
|
||||
pipe_write = 0;
|
||||
}
|
||||
attrs = PushBytes(scratch.arena, attrs_size, 64);
|
||||
ok = InitializeProcThreadAttributeList(attrs, 1, 0, &attrs_size) != 0;
|
||||
}
|
||||
if (!ok)
|
||||
{
|
||||
result.output = Lit("Failed to initialize attrs list");
|
||||
}
|
||||
}
|
||||
|
||||
/* Duplicate pipe for child process */
|
||||
HANDLE child_pipe_write = 0;
|
||||
/* Build the handle inheritance whitelist */
|
||||
if (ok) {
|
||||
HANDLE inherit_list[] = { child_pipe_write };
|
||||
ok = UpdateProcThreadAttribute(attrs, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST, inherit_list, sizeof(inherit_list), 0, 0) != 0;
|
||||
if (!ok)
|
||||
{
|
||||
result.output = Lit("Failed to update attributes");
|
||||
}
|
||||
}
|
||||
|
||||
/* Create process */
|
||||
/* TODO: Allow caller to set child process's thread affinity by job pool */
|
||||
HANDLE process = 0;
|
||||
HANDLE process_thread = 0;
|
||||
if (ok)
|
||||
{
|
||||
PROCESS_INFORMATION pi = Zi;
|
||||
STARTUPINFOEXW si = Zi;
|
||||
si.StartupInfo.cb = sizeof(si);
|
||||
si.StartupInfo.dwFlags = STARTF_USESTDHANDLES;
|
||||
si.StartupInfo.hStdOutput = child_pipe_write;
|
||||
si.StartupInfo.hStdError = child_pipe_write;
|
||||
si.lpAttributeList = attrs;
|
||||
ok = CreateProcessW(0, cmd_wstr, 0, 0, 1, EXTENDED_STARTUPINFO_PRESENT, 0, 0, &si.StartupInfo, &pi) != 0;
|
||||
if (ok)
|
||||
{
|
||||
ok = DuplicateHandle(GetCurrentProcess(), pipe_write, GetCurrentProcess(), &child_pipe_write, 0, 1, DUPLICATE_SAME_ACCESS) != 0;
|
||||
if (!ok)
|
||||
{
|
||||
result.output = Lit("Failed to create child pipe");
|
||||
child_pipe_write = 0;
|
||||
}
|
||||
process = pi.hProcess;
|
||||
process_thread = pi.hThread;
|
||||
}
|
||||
|
||||
/* Initialize attrs list */
|
||||
LPPROC_THREAD_ATTRIBUTE_LIST attrs = Zi;
|
||||
if (ok)
|
||||
else
|
||||
{
|
||||
u64 attrs_size = 0;
|
||||
InitializeProcThreadAttributeList(0, 1, 0, &attrs_size);
|
||||
ok = attrs_size > 0;
|
||||
if (ok)
|
||||
{
|
||||
attrs = PushBytes(scratch.arena, attrs_size, 64);
|
||||
ok = InitializeProcThreadAttributeList(attrs, 1, 0, &attrs_size) != 0;
|
||||
}
|
||||
if (!ok)
|
||||
{
|
||||
result.output = Lit("Failed to initialize attrs list");
|
||||
}
|
||||
result.output = W32_StringFromError(arena, GetLastError());
|
||||
}
|
||||
|
||||
/* Build the handle inheritance whitelist */
|
||||
if (ok) {
|
||||
HANDLE inherit_list[] = { child_pipe_write };
|
||||
ok = UpdateProcThreadAttribute(attrs, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST, inherit_list, sizeof(inherit_list), 0, 0) != 0;
|
||||
if (!ok)
|
||||
{
|
||||
result.output = Lit("Failed to update attributes");
|
||||
}
|
||||
}
|
||||
|
||||
/* Create process */
|
||||
/* TODO: Allow caller to set child process's thread affinity by job pool */
|
||||
HANDLE process = 0;
|
||||
HANDLE process_thread = 0;
|
||||
if (ok)
|
||||
/* Close write pipe handles */
|
||||
{
|
||||
PROCESS_INFORMATION pi = Zi;
|
||||
STARTUPINFOEXW si = Zi;
|
||||
si.StartupInfo.cb = sizeof(si);
|
||||
si.StartupInfo.dwFlags = STARTF_USESTDHANDLES;
|
||||
si.StartupInfo.hStdOutput = child_pipe_write;
|
||||
si.StartupInfo.hStdError = child_pipe_write;
|
||||
si.lpAttributeList = attrs;
|
||||
ok = CreateProcessW(0, cmd_wstr, 0, 0, 1, EXTENDED_STARTUPINFO_PRESENT, 0, 0, &si.StartupInfo, &pi) != 0;
|
||||
if (ok)
|
||||
CloseHandle(child_pipe_write);
|
||||
CloseHandle(pipe_write);
|
||||
child_pipe_write = 0;
|
||||
pipe_write = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Read process output */
|
||||
if (ok)
|
||||
{
|
||||
result.output.text = ArenaNext(arena, u8);
|
||||
b32 exit_code_valid = 0;
|
||||
DWORD 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, 0))
|
||||
{
|
||||
DWORD err = GetLastError();
|
||||
if (err == ERROR_BROKEN_PIPE)
|
||||
{
|
||||
process = pi.hProcess;
|
||||
process_thread = pi.hThread;
|
||||
GetExitCodeProcess(process, &exit_code);
|
||||
exit_code_valid = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
result.output = W32_StringFromError(arena, GetLastError());
|
||||
}
|
||||
/* Close write pipe handles */
|
||||
{
|
||||
CloseHandle(child_pipe_write);
|
||||
CloseHandle(pipe_write);
|
||||
child_pipe_write = 0;
|
||||
pipe_write = 0;
|
||||
result.output.len += W32_StringFromError(arena, err).len;
|
||||
}
|
||||
stdout_finished = 1;
|
||||
}
|
||||
PushStructsNoZero(arena, u8, bytes_read);
|
||||
CopyBytes(result.output.text + result.output.len, buff, bytes_read);
|
||||
result.output.len += bytes_read;
|
||||
}
|
||||
|
||||
/* Read process output */
|
||||
if (ok)
|
||||
if (exit_code_valid)
|
||||
{
|
||||
result.output.text = ArenaNext(arena, u8);
|
||||
b32 exit_code_valid = 0;
|
||||
DWORD 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, 0))
|
||||
{
|
||||
DWORD err = GetLastError();
|
||||
if (err == ERROR_BROKEN_PIPE)
|
||||
{
|
||||
GetExitCodeProcess(process, &exit_code);
|
||||
exit_code_valid = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
result.output.len += W32_StringFromError(arena, err).len;
|
||||
}
|
||||
stdout_finished = 1;
|
||||
}
|
||||
PushStructsNoZero(arena, u8, bytes_read);
|
||||
CopyBytes(result.output.text + result.output.len, buff, bytes_read);
|
||||
result.output.len += bytes_read;
|
||||
}
|
||||
if (exit_code_valid)
|
||||
{
|
||||
result.code = exit_code;
|
||||
}
|
||||
result.code = exit_code;
|
||||
}
|
||||
}
|
||||
|
||||
/* Close handles */
|
||||
if (attrs) DeleteProcThreadAttributeList(attrs);
|
||||
if (process_thread) CloseHandle(process_thread);
|
||||
if (process) CloseHandle(process);
|
||||
if (child_pipe_write) CloseHandle(child_pipe_write);
|
||||
if (pipe_read) CloseHandle(pipe_read);
|
||||
if (pipe_write) CloseHandle(pipe_write);
|
||||
/* Close handles */
|
||||
if (attrs) DeleteProcThreadAttributeList(attrs);
|
||||
if (process_thread) CloseHandle(process_thread);
|
||||
if (process) CloseHandle(process);
|
||||
if (child_pipe_write) CloseHandle(child_pipe_write);
|
||||
if (pipe_read) CloseHandle(pipe_read);
|
||||
if (pipe_write) CloseHandle(pipe_write);
|
||||
|
||||
if (!ok && result.code == 0)
|
||||
{
|
||||
result.code = -1;
|
||||
}
|
||||
if (!ok && result.code == 0)
|
||||
{
|
||||
result.code = -1;
|
||||
}
|
||||
|
||||
EndScratch(scratch);
|
||||
return result;
|
||||
EndScratch(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -21,10 +21,10 @@ MIX_SharedState M_shared_state = ZI;
|
||||
|
||||
void MIX_Bootstrap(void)
|
||||
{
|
||||
MIX_SharedState *g = &M_shared_state;
|
||||
g->track_arena = AcquireArena(Gibi(64));
|
||||
g->listener_pos = VEC2(0, 0);
|
||||
g->listener_dir = VEC2(0, -1);
|
||||
MIX_SharedState *g = &M_shared_state;
|
||||
g->track_arena = AcquireArena(Gibi(64));
|
||||
g->listener_pos = VEC2(0, 0);
|
||||
g->listener_dir = VEC2(0, -1);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -32,187 +32,187 @@ void MIX_Bootstrap(void)
|
||||
|
||||
MIX_Handle MIX_HandleFromTrack(MIX_Track *track)
|
||||
{
|
||||
MIX_Handle result = ZI;
|
||||
result.gen = track->gen;
|
||||
result.data = track;
|
||||
return result;
|
||||
MIX_Handle result = ZI;
|
||||
result.gen = track->gen;
|
||||
result.data = track;
|
||||
return result;
|
||||
}
|
||||
|
||||
MIX_Track *MIX_TrackFromHandle(MIX_Handle handle)
|
||||
{
|
||||
MIX_Track *track = (MIX_Track *)handle.data;
|
||||
if (track && track->gen == handle.gen)
|
||||
{
|
||||
return track;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
MIX_Track *track = (MIX_Track *)handle.data;
|
||||
if (track && track->gen == handle.gen)
|
||||
{
|
||||
return track;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
MIX_Track *MIX_AcquireTrackLocked(Lock *lock, SND_Sound *sound)
|
||||
{
|
||||
MIX_SharedState *g = &M_shared_state;
|
||||
AssertLockedE(lock, &g->mutex);
|
||||
MIX_SharedState *g = &M_shared_state;
|
||||
AssertLockedE(lock, &g->mutex);
|
||||
|
||||
MIX_Track *track = 0;
|
||||
if (g->track_first_free)
|
||||
MIX_Track *track = 0;
|
||||
if (g->track_first_free)
|
||||
{
|
||||
/* Take from free list */
|
||||
track = g->track_first_free;
|
||||
MIX_Track *next_free = track->next;
|
||||
g->track_first_free = next_free;
|
||||
if (next_free)
|
||||
{
|
||||
/* Take from free list */
|
||||
track = g->track_first_free;
|
||||
MIX_Track *next_free = track->next;
|
||||
g->track_first_free = next_free;
|
||||
if (next_free)
|
||||
{
|
||||
next_free->prev = 0;
|
||||
}
|
||||
*track = (MIX_Track) { .gen = track->gen + 1 };
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Acquire new */
|
||||
track = PushStruct(g->track_arena, MIX_Track);
|
||||
track->gen = 1;
|
||||
next_free->prev = 0;
|
||||
}
|
||||
*track = (MIX_Track) { .gen = track->gen + 1 };
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Acquire new */
|
||||
track = PushStruct(g->track_arena, MIX_Track);
|
||||
track->gen = 1;
|
||||
}
|
||||
|
||||
track->sound = sound;
|
||||
track->mix.source = sound;
|
||||
track->mix.track_handle = MIX_HandleFromTrack(track);
|
||||
track->sound = sound;
|
||||
track->mix.source = sound;
|
||||
track->mix.track_handle = MIX_HandleFromTrack(track);
|
||||
|
||||
/* Append to playing list */
|
||||
MIX_Track *prev = g->track_last_playing;
|
||||
if (prev)
|
||||
{
|
||||
prev->next = track;
|
||||
}
|
||||
else
|
||||
{
|
||||
g->track_first_playing = track;
|
||||
}
|
||||
g->track_last_playing = track;
|
||||
track->prev = prev;
|
||||
++g->track_playing_count;
|
||||
/* Append to playing list */
|
||||
MIX_Track *prev = g->track_last_playing;
|
||||
if (prev)
|
||||
{
|
||||
prev->next = track;
|
||||
}
|
||||
else
|
||||
{
|
||||
g->track_first_playing = track;
|
||||
}
|
||||
g->track_last_playing = track;
|
||||
track->prev = prev;
|
||||
++g->track_playing_count;
|
||||
|
||||
return track;
|
||||
return track;
|
||||
}
|
||||
|
||||
void MIX_ReleaseTrackLocked(Lock *lock, MIX_Track *track)
|
||||
{
|
||||
MIX_SharedState *g = &M_shared_state;
|
||||
AssertLockedE(lock, &g->mutex);
|
||||
MIX_SharedState *g = &M_shared_state;
|
||||
AssertLockedE(lock, &g->mutex);
|
||||
|
||||
/* Remove from playing list */
|
||||
MIX_Track *prev = track->prev;
|
||||
MIX_Track *next = track->next;
|
||||
if (prev)
|
||||
{
|
||||
prev->next = next;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Track was first in list */
|
||||
g->track_first_playing = next;
|
||||
}
|
||||
if (next)
|
||||
{
|
||||
next->prev = prev;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Track was last in list */
|
||||
g->track_last_playing = prev;
|
||||
}
|
||||
--g->track_playing_count;
|
||||
++track->gen;
|
||||
/* Remove from playing list */
|
||||
MIX_Track *prev = track->prev;
|
||||
MIX_Track *next = track->next;
|
||||
if (prev)
|
||||
{
|
||||
prev->next = next;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Track was first in list */
|
||||
g->track_first_playing = next;
|
||||
}
|
||||
if (next)
|
||||
{
|
||||
next->prev = prev;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Track was last in list */
|
||||
g->track_last_playing = prev;
|
||||
}
|
||||
--g->track_playing_count;
|
||||
++track->gen;
|
||||
|
||||
/* Add to free list */
|
||||
track->prev = 0;
|
||||
track->next = g->track_first_free;
|
||||
if (g->track_first_free)
|
||||
{
|
||||
g->track_first_free->prev = track;
|
||||
}
|
||||
g->track_first_free = track;
|
||||
/* Add to free list */
|
||||
track->prev = 0;
|
||||
track->next = g->track_first_free;
|
||||
if (g->track_first_free)
|
||||
{
|
||||
g->track_first_free->prev = track;
|
||||
}
|
||||
g->track_first_free = track;
|
||||
}
|
||||
|
||||
/* TODO: Rework interface to be command based instead of directly modifying tracks. */
|
||||
|
||||
MIX_Handle MIX_PlaySound(SND_Sound *sound)
|
||||
{
|
||||
return MIX_PlaySoundEx(sound, M_TRACKDESC());
|
||||
return MIX_PlaySoundEx(sound, M_TRACKDESC());
|
||||
}
|
||||
|
||||
MIX_Handle MIX_PlaySoundEx(SND_Sound *sound, MIX_TrackDesc desc)
|
||||
{
|
||||
MIX_SharedState *g = &M_shared_state;
|
||||
MIX_Track *track;
|
||||
MIX_SharedState *g = &M_shared_state;
|
||||
MIX_Track *track;
|
||||
{
|
||||
Lock lock = LockE(&g->mutex);
|
||||
{
|
||||
Lock lock = LockE(&g->mutex);
|
||||
{
|
||||
track = MIX_AcquireTrackLocked(&lock, sound);
|
||||
track->desc = desc;
|
||||
}
|
||||
Unlock(&lock);
|
||||
track = MIX_AcquireTrackLocked(&lock, sound);
|
||||
track->desc = desc;
|
||||
}
|
||||
return MIX_HandleFromTrack(track);
|
||||
Unlock(&lock);
|
||||
}
|
||||
return MIX_HandleFromTrack(track);
|
||||
}
|
||||
|
||||
/* NOTE: This is quite inefficient. */
|
||||
MIX_TrackDesc MIX_TrackDescFromHandle(MIX_Handle handle)
|
||||
{
|
||||
MIX_SharedState *g = &M_shared_state;
|
||||
MIX_TrackDesc result = ZI;
|
||||
MIX_SharedState *g = &M_shared_state;
|
||||
MIX_TrackDesc result = ZI;
|
||||
|
||||
MIX_Track *track = MIX_TrackFromHandle(handle);
|
||||
if (track)
|
||||
MIX_Track *track = MIX_TrackFromHandle(handle);
|
||||
if (track)
|
||||
{
|
||||
/* TODO: Only lock mutex on track itself or something */
|
||||
Lock lock = LockE(&g->mutex);
|
||||
{
|
||||
/* TODO: Only lock mutex on track itself or something */
|
||||
Lock lock = LockE(&g->mutex);
|
||||
{
|
||||
/* Confirm handle is still valid now that we're locked */
|
||||
track = MIX_TrackFromHandle(handle);
|
||||
if (track)
|
||||
{
|
||||
result = track->desc;
|
||||
}
|
||||
}
|
||||
Unlock(&lock);
|
||||
/* Confirm handle is still valid now that we're locked */
|
||||
track = MIX_TrackFromHandle(handle);
|
||||
if (track)
|
||||
{
|
||||
result = track->desc;
|
||||
}
|
||||
}
|
||||
Unlock(&lock);
|
||||
}
|
||||
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* NOTE: This is quite inefficient. */
|
||||
void MIX_UpdateTrack(MIX_Handle handle, MIX_TrackDesc desc)
|
||||
{
|
||||
MIX_SharedState *g = &M_shared_state;
|
||||
MIX_Track *track = MIX_TrackFromHandle(handle);
|
||||
if (track)
|
||||
MIX_SharedState *g = &M_shared_state;
|
||||
MIX_Track *track = MIX_TrackFromHandle(handle);
|
||||
if (track)
|
||||
{
|
||||
/* TODO: Only lock mutex on track itself or something */
|
||||
Lock lock = LockE(&g->mutex);
|
||||
{
|
||||
/* TODO: Only lock mutex on track itself or something */
|
||||
Lock lock = LockE(&g->mutex);
|
||||
{
|
||||
/* Confirm handle is still valid now that we're locked */
|
||||
track = MIX_TrackFromHandle(handle);
|
||||
if (track)
|
||||
{
|
||||
track->desc = desc;
|
||||
}
|
||||
}
|
||||
Unlock(&lock);
|
||||
/* Confirm handle is still valid now that we're locked */
|
||||
track = MIX_TrackFromHandle(handle);
|
||||
if (track)
|
||||
{
|
||||
track->desc = desc;
|
||||
}
|
||||
}
|
||||
Unlock(&lock);
|
||||
}
|
||||
}
|
||||
|
||||
void MIX_UpdateListener(Vec2 pos, Vec2 dir)
|
||||
{
|
||||
MIX_SharedState *g = &M_shared_state;
|
||||
Lock lock = LockE(&g->mutex);
|
||||
{
|
||||
g->listener_pos = pos;
|
||||
g->listener_dir = NormVec2(dir);
|
||||
}
|
||||
Unlock(&lock);
|
||||
MIX_SharedState *g = &M_shared_state;
|
||||
Lock lock = LockE(&g->mutex);
|
||||
{
|
||||
g->listener_pos = pos;
|
||||
g->listener_dir = NormVec2(dir);
|
||||
}
|
||||
Unlock(&lock);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -220,250 +220,250 @@ void MIX_UpdateListener(Vec2 pos, Vec2 dir)
|
||||
|
||||
i16 MIX_SampleSound(SND_Sound *sound, u64 sample_pos, b32 wrap)
|
||||
{
|
||||
if (wrap)
|
||||
{
|
||||
return sound->samples[sample_pos % sound->samples_count];
|
||||
}
|
||||
else if (sample_pos < sound->samples_count)
|
||||
{
|
||||
return sound->samples[sample_pos];
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (wrap)
|
||||
{
|
||||
return sound->samples[sample_pos % sound->samples_count];
|
||||
}
|
||||
else if (sample_pos < sound->samples_count)
|
||||
{
|
||||
return sound->samples[sample_pos];
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* To be called once per audio playback interval */
|
||||
MIX_PcmF32 MIX_MixAllTracks(Arena *arena, u64 frame_count)
|
||||
{
|
||||
TempArena scratch = BeginScratch(arena);
|
||||
MIX_SharedState *g = &M_shared_state;
|
||||
TempArena scratch = BeginScratch(arena);
|
||||
MIX_SharedState *g = &M_shared_state;
|
||||
|
||||
MIX_PcmF32 result = ZI;
|
||||
result.count = frame_count * 2;
|
||||
result.samples = PushStructs(arena, f32, result.count);
|
||||
MIX_PcmF32 result = ZI;
|
||||
result.count = frame_count * 2;
|
||||
result.samples = PushStructs(arena, f32, result.count);
|
||||
|
||||
Vec2 listener_pos = VEC2(0, 0);
|
||||
Vec2 listener_dir = VEC2(0, 0);
|
||||
Vec2 listener_pos = VEC2(0, 0);
|
||||
Vec2 listener_dir = VEC2(0, 0);
|
||||
|
||||
//- Create temp mix array
|
||||
//- Create temp mix array
|
||||
|
||||
MIX_MixData **mixes = 0;
|
||||
u64 mixes_count = 0;
|
||||
MIX_MixData **mixes = 0;
|
||||
u64 mixes_count = 0;
|
||||
{
|
||||
Lock lock = LockE(&g->mutex);
|
||||
|
||||
/* Read listener info */
|
||||
listener_pos = g->listener_pos;
|
||||
listener_dir = g->listener_dir;
|
||||
|
||||
/* Update & read mixes */
|
||||
mixes = PushStructsNoZero(scratch.arena, MIX_MixData *, g->track_playing_count);
|
||||
for (MIX_Track *track = g->track_first_playing; track; track = track->next)
|
||||
{
|
||||
Lock lock = LockE(&g->mutex);
|
||||
|
||||
/* Read listener info */
|
||||
listener_pos = g->listener_pos;
|
||||
listener_dir = g->listener_dir;
|
||||
|
||||
/* Update & read mixes */
|
||||
mixes = PushStructsNoZero(scratch.arena, MIX_MixData *, g->track_playing_count);
|
||||
for (MIX_Track *track = g->track_first_playing; track; track = track->next)
|
||||
{
|
||||
MIX_MixData *mix = &track->mix;
|
||||
mix->desc = track->desc;
|
||||
mixes[mixes_count++] = mix;
|
||||
}
|
||||
|
||||
Unlock(&lock);
|
||||
MIX_MixData *mix = &track->mix;
|
||||
mix->desc = track->desc;
|
||||
mixes[mixes_count++] = mix;
|
||||
}
|
||||
|
||||
//- Process mix data
|
||||
Unlock(&lock);
|
||||
}
|
||||
|
||||
for (u64 mix_index = 0; mix_index < mixes_count; ++mix_index)
|
||||
//- Process mix data
|
||||
|
||||
for (u64 mix_index = 0; mix_index < mixes_count; ++mix_index)
|
||||
{
|
||||
MIX_MixData *mix = mixes[mix_index];
|
||||
|
||||
if (mix->source->samples_count <= 0)
|
||||
{
|
||||
MIX_MixData *mix = mixes[mix_index];
|
||||
|
||||
if (mix->source->samples_count <= 0)
|
||||
{
|
||||
/* Skip empty sounds */
|
||||
continue;
|
||||
}
|
||||
|
||||
SND_Sound *source = mix->source;
|
||||
MIX_TrackDesc desc = mix->desc;
|
||||
MIX_EffectData *effect_data = &mix->effect_data;
|
||||
b32 source_is_stereo = source->flags & SND_SoundFlag_Stereo;
|
||||
f32 speed = MaxF32(0, desc.speed);
|
||||
|
||||
//- Determine sample range
|
||||
u64 source_samples_count = 0;
|
||||
if (source_is_stereo)
|
||||
{
|
||||
source_samples_count = frame_count * 2;
|
||||
/* Round <samples_count * speed> to nearest frame boundary (nearest multiple of 2) */
|
||||
source_samples_count = (u64)CeilF32ToI32((f32)source_samples_count * speed);
|
||||
source_samples_count &= ~1;
|
||||
}
|
||||
else
|
||||
{
|
||||
source_samples_count = frame_count;
|
||||
/* Round <samples_count * speed> to nearest sample */
|
||||
source_samples_count = (u64)RoundF32ToI32((f32)source_samples_count * speed);
|
||||
}
|
||||
|
||||
u64 source_sample_pos_start = mix->source_pos;
|
||||
u64 source_sample_pos_end = source_sample_pos_start + source_samples_count;
|
||||
if (source_sample_pos_end >= source->samples_count)
|
||||
{
|
||||
if (desc.looping)
|
||||
{
|
||||
source_sample_pos_end = source_sample_pos_end % source->samples_count;
|
||||
}
|
||||
else
|
||||
{
|
||||
source_sample_pos_end = source->samples_count;
|
||||
mix->track_finished = 1;
|
||||
}
|
||||
}
|
||||
u64 source_frames_count = source_is_stereo ? source_samples_count / 2 : source_samples_count;
|
||||
u64 source_frame_pos_start = source_is_stereo ? source_sample_pos_start / 2 : source_sample_pos_start;
|
||||
|
||||
mix->source_pos = source_sample_pos_end;
|
||||
|
||||
MIX_PcmF32 mix_pcm = {
|
||||
.count = result.count,
|
||||
.samples = PushStructs(scratch.arena, f32, result.count)
|
||||
};
|
||||
|
||||
//- Resample
|
||||
/* Transform 16 bit source -> 32 bit stereo at output duration */
|
||||
{
|
||||
f32 *out_samples = mix_pcm.samples;
|
||||
|
||||
u64 out_frames_count = mix_pcm.count / 2;
|
||||
|
||||
/* TODO: Fast path for 1:1 copy when speed = 1.0? */
|
||||
/* TODO: Optimize */
|
||||
if (source_is_stereo)
|
||||
{
|
||||
/* 16 bit Stereo -> 32 bit Stereo */
|
||||
for (u64 out_frame_pos = 0; out_frame_pos < out_frames_count; ++out_frame_pos)
|
||||
{
|
||||
f32 in_frame_pos_exact = source_frame_pos_start + (((f32)out_frame_pos / (f32)out_frames_count) * (f32)source_frames_count);
|
||||
u32 in_frame_pos_prev = FloorF32ToI32(in_frame_pos_exact);
|
||||
u32 in_frame_pos_next = CeilF32ToI32(in_frame_pos_exact);
|
||||
|
||||
/* Sample source */
|
||||
f32 sample1_prev = MIX_SampleSound(source, (in_frame_pos_prev * 2) + 0, desc.looping) * (1.f / 32768.f);
|
||||
f32 sample1_next = MIX_SampleSound(source, (in_frame_pos_next * 2) + 0, desc.looping) * (1.f / 32768.f);
|
||||
f32 sample2_prev = MIX_SampleSound(source, (in_frame_pos_prev * 2) + 1, desc.looping) * (1.f / 32768.f);
|
||||
f32 sample2_next = MIX_SampleSound(source, (in_frame_pos_next * 2) + 1, desc.looping) * (1.f / 32768.f);
|
||||
|
||||
/* Lerp */
|
||||
f32 t = in_frame_pos_exact - (f32)in_frame_pos_prev;
|
||||
f32 sample1 = LerpF32(sample1_prev, sample1_next, t);
|
||||
f32 sample2 = LerpF32(sample2_prev, sample2_next, t);
|
||||
|
||||
out_samples[(out_frame_pos * 2) + 0] += sample1;
|
||||
out_samples[(out_frame_pos * 2) + 1] += sample2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* 16 bit Mono -> 32 bit Stereo */
|
||||
for (u64 out_frame_pos = 0; out_frame_pos < out_frames_count; ++out_frame_pos)
|
||||
{
|
||||
f32 in_frame_pos_exact = source_frame_pos_start + (((f32)out_frame_pos / (f32)out_frames_count) * (f32)source_frames_count);
|
||||
u32 in_frame_pos_prev = FloorF32ToI32(in_frame_pos_exact);
|
||||
u32 in_frame_pos_next = CeilF32ToI32(in_frame_pos_exact);
|
||||
|
||||
/* Sample source */
|
||||
f32 sample_prev = MIX_SampleSound(source, in_frame_pos_prev, desc.looping) * (1.f / 32768.f);
|
||||
f32 sample_next = MIX_SampleSound(source, in_frame_pos_next, desc.looping) * (1.f / 32768.f);
|
||||
|
||||
/* Lerp */
|
||||
f32 t = (f32)in_frame_pos_exact - in_frame_pos_prev;
|
||||
f32 sample = LerpF32(sample_prev, sample_next, t);
|
||||
|
||||
out_samples[(out_frame_pos * 2) + 0] += sample;
|
||||
out_samples[(out_frame_pos * 2) + 1] += sample;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//- Spatialize
|
||||
if (desc.flags & MIX_TrackFlag_Spatialize)
|
||||
{
|
||||
/* Algorithm constants */
|
||||
const f32 rolloff_height = 1.2f;
|
||||
const f32 rolloff_scale = 6.0f;
|
||||
const f32 pan_scale = 0.75;
|
||||
|
||||
Vec2 pos = desc.pos;
|
||||
|
||||
/* If sound pos = listener pos, pretend sound is close in front of listener. */
|
||||
if (MatchVec2(listener_pos, pos))
|
||||
{
|
||||
pos = AddVec2(listener_pos, MulVec2(listener_dir, 0.001f));
|
||||
}
|
||||
Vec2 sound_rel = SubVec2(pos, listener_pos);
|
||||
Vec2 sound_rel_dir = NormVec2(sound_rel);
|
||||
|
||||
/* Compute volume */
|
||||
f32 volume_start = effect_data->spatial_volume;
|
||||
f32 volume_end;
|
||||
{
|
||||
/* https://www.desmos.com/calculator/c2h941hobz
|
||||
* h = `rolloff_height`
|
||||
* s = `rolloff_scale`
|
||||
*/
|
||||
f32 dist = Vec2Len(sound_rel);
|
||||
f32 v = (dist / rolloff_scale) + 1.0f;
|
||||
volume_end = rolloff_height * (1.0f / (v * v));
|
||||
}
|
||||
effect_data->spatial_volume = volume_end;
|
||||
|
||||
/* Compute pan */
|
||||
f32 pan_start = effect_data->spatial_pan;
|
||||
f32 pan_end = WedgeVec2(listener_dir, sound_rel_dir) * pan_scale;
|
||||
effect_data->spatial_pan = pan_end;
|
||||
|
||||
/* Spatialize samples */
|
||||
for (u64 frame_pos = 0; frame_pos < frame_count; ++frame_pos)
|
||||
{
|
||||
f32 t = (f32)frame_pos / (f32)(frame_count - 1);
|
||||
f32 volume = LerpF32(volume_start, volume_end, t);
|
||||
f32 pan = LerpF32(pan_start, pan_end, t);
|
||||
|
||||
u64 sample1_index = frame_pos * 2;
|
||||
u64 sample2_index = sample1_index + 1;
|
||||
|
||||
f32 sample_mono = ((mix_pcm.samples[sample1_index + 0] / 2.0f) + (mix_pcm.samples[sample2_index] / 2.0f)) * volume;
|
||||
|
||||
mix_pcm.samples[sample1_index] = sample_mono * (1.0f - pan);
|
||||
mix_pcm.samples[sample2_index] = sample_mono * (1.0f + pan);
|
||||
}
|
||||
}
|
||||
|
||||
//- Mix into result
|
||||
for (u64 i = 0; i < mix_pcm.count; ++i)
|
||||
{
|
||||
result.samples[i] += mix_pcm.samples[i] * desc.volume;
|
||||
}
|
||||
/* Skip empty sounds */
|
||||
continue;
|
||||
}
|
||||
|
||||
//- Update track effect data
|
||||
SND_Sound *source = mix->source;
|
||||
MIX_TrackDesc desc = mix->desc;
|
||||
MIX_EffectData *effect_data = &mix->effect_data;
|
||||
b32 source_is_stereo = source->flags & SND_SoundFlag_Stereo;
|
||||
f32 speed = MaxF32(0, desc.speed);
|
||||
|
||||
//- Determine sample range
|
||||
u64 source_samples_count = 0;
|
||||
if (source_is_stereo)
|
||||
{
|
||||
Lock lock = LockE(&g->mutex);
|
||||
for (u64 i = 0; i < mixes_count; ++i)
|
||||
{
|
||||
MIX_MixData *mix = mixes[i];
|
||||
MIX_Track *track = MIX_TrackFromHandle(mix->track_handle);
|
||||
if (track)
|
||||
{
|
||||
if (mix->track_finished)
|
||||
{
|
||||
/* Release finished tracks */
|
||||
MIX_ReleaseTrackLocked(&lock, track);
|
||||
}
|
||||
}
|
||||
}
|
||||
Unlock(&lock);
|
||||
source_samples_count = frame_count * 2;
|
||||
/* Round <samples_count * speed> to nearest frame boundary (nearest multiple of 2) */
|
||||
source_samples_count = (u64)CeilF32ToI32((f32)source_samples_count * speed);
|
||||
source_samples_count &= ~1;
|
||||
}
|
||||
else
|
||||
{
|
||||
source_samples_count = frame_count;
|
||||
/* Round <samples_count * speed> to nearest sample */
|
||||
source_samples_count = (u64)RoundF32ToI32((f32)source_samples_count * speed);
|
||||
}
|
||||
|
||||
EndScratch(scratch);
|
||||
return result;
|
||||
u64 source_sample_pos_start = mix->source_pos;
|
||||
u64 source_sample_pos_end = source_sample_pos_start + source_samples_count;
|
||||
if (source_sample_pos_end >= source->samples_count)
|
||||
{
|
||||
if (desc.looping)
|
||||
{
|
||||
source_sample_pos_end = source_sample_pos_end % source->samples_count;
|
||||
}
|
||||
else
|
||||
{
|
||||
source_sample_pos_end = source->samples_count;
|
||||
mix->track_finished = 1;
|
||||
}
|
||||
}
|
||||
u64 source_frames_count = source_is_stereo ? source_samples_count / 2 : source_samples_count;
|
||||
u64 source_frame_pos_start = source_is_stereo ? source_sample_pos_start / 2 : source_sample_pos_start;
|
||||
|
||||
mix->source_pos = source_sample_pos_end;
|
||||
|
||||
MIX_PcmF32 mix_pcm = {
|
||||
.count = result.count,
|
||||
.samples = PushStructs(scratch.arena, f32, result.count)
|
||||
};
|
||||
|
||||
//- Resample
|
||||
/* Transform 16 bit source -> 32 bit stereo at output duration */
|
||||
{
|
||||
f32 *out_samples = mix_pcm.samples;
|
||||
|
||||
u64 out_frames_count = mix_pcm.count / 2;
|
||||
|
||||
/* TODO: Fast path for 1:1 copy when speed = 1.0? */
|
||||
/* TODO: Optimize */
|
||||
if (source_is_stereo)
|
||||
{
|
||||
/* 16 bit Stereo -> 32 bit Stereo */
|
||||
for (u64 out_frame_pos = 0; out_frame_pos < out_frames_count; ++out_frame_pos)
|
||||
{
|
||||
f32 in_frame_pos_exact = source_frame_pos_start + (((f32)out_frame_pos / (f32)out_frames_count) * (f32)source_frames_count);
|
||||
u32 in_frame_pos_prev = FloorF32ToI32(in_frame_pos_exact);
|
||||
u32 in_frame_pos_next = CeilF32ToI32(in_frame_pos_exact);
|
||||
|
||||
/* Sample source */
|
||||
f32 sample1_prev = MIX_SampleSound(source, (in_frame_pos_prev * 2) + 0, desc.looping) * (1.f / 32768.f);
|
||||
f32 sample1_next = MIX_SampleSound(source, (in_frame_pos_next * 2) + 0, desc.looping) * (1.f / 32768.f);
|
||||
f32 sample2_prev = MIX_SampleSound(source, (in_frame_pos_prev * 2) + 1, desc.looping) * (1.f / 32768.f);
|
||||
f32 sample2_next = MIX_SampleSound(source, (in_frame_pos_next * 2) + 1, desc.looping) * (1.f / 32768.f);
|
||||
|
||||
/* Lerp */
|
||||
f32 t = in_frame_pos_exact - (f32)in_frame_pos_prev;
|
||||
f32 sample1 = LerpF32(sample1_prev, sample1_next, t);
|
||||
f32 sample2 = LerpF32(sample2_prev, sample2_next, t);
|
||||
|
||||
out_samples[(out_frame_pos * 2) + 0] += sample1;
|
||||
out_samples[(out_frame_pos * 2) + 1] += sample2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* 16 bit Mono -> 32 bit Stereo */
|
||||
for (u64 out_frame_pos = 0; out_frame_pos < out_frames_count; ++out_frame_pos)
|
||||
{
|
||||
f32 in_frame_pos_exact = source_frame_pos_start + (((f32)out_frame_pos / (f32)out_frames_count) * (f32)source_frames_count);
|
||||
u32 in_frame_pos_prev = FloorF32ToI32(in_frame_pos_exact);
|
||||
u32 in_frame_pos_next = CeilF32ToI32(in_frame_pos_exact);
|
||||
|
||||
/* Sample source */
|
||||
f32 sample_prev = MIX_SampleSound(source, in_frame_pos_prev, desc.looping) * (1.f / 32768.f);
|
||||
f32 sample_next = MIX_SampleSound(source, in_frame_pos_next, desc.looping) * (1.f / 32768.f);
|
||||
|
||||
/* Lerp */
|
||||
f32 t = (f32)in_frame_pos_exact - in_frame_pos_prev;
|
||||
f32 sample = LerpF32(sample_prev, sample_next, t);
|
||||
|
||||
out_samples[(out_frame_pos * 2) + 0] += sample;
|
||||
out_samples[(out_frame_pos * 2) + 1] += sample;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//- Spatialize
|
||||
if (desc.flags & MIX_TrackFlag_Spatialize)
|
||||
{
|
||||
/* Algorithm constants */
|
||||
const f32 rolloff_height = 1.2f;
|
||||
const f32 rolloff_scale = 6.0f;
|
||||
const f32 pan_scale = 0.75;
|
||||
|
||||
Vec2 pos = desc.pos;
|
||||
|
||||
/* If sound pos = listener pos, pretend sound is close in front of listener. */
|
||||
if (MatchVec2(listener_pos, pos))
|
||||
{
|
||||
pos = AddVec2(listener_pos, MulVec2(listener_dir, 0.001f));
|
||||
}
|
||||
Vec2 sound_rel = SubVec2(pos, listener_pos);
|
||||
Vec2 sound_rel_dir = NormVec2(sound_rel);
|
||||
|
||||
/* Compute volume */
|
||||
f32 volume_start = effect_data->spatial_volume;
|
||||
f32 volume_end;
|
||||
{
|
||||
/* https://www.desmos.com/calculator/c2h941hobz
|
||||
* h = `rolloff_height`
|
||||
* s = `rolloff_scale`
|
||||
*/
|
||||
f32 dist = Vec2Len(sound_rel);
|
||||
f32 v = (dist / rolloff_scale) + 1.0f;
|
||||
volume_end = rolloff_height * (1.0f / (v * v));
|
||||
}
|
||||
effect_data->spatial_volume = volume_end;
|
||||
|
||||
/* Compute pan */
|
||||
f32 pan_start = effect_data->spatial_pan;
|
||||
f32 pan_end = WedgeVec2(listener_dir, sound_rel_dir) * pan_scale;
|
||||
effect_data->spatial_pan = pan_end;
|
||||
|
||||
/* Spatialize samples */
|
||||
for (u64 frame_pos = 0; frame_pos < frame_count; ++frame_pos)
|
||||
{
|
||||
f32 t = (f32)frame_pos / (f32)(frame_count - 1);
|
||||
f32 volume = LerpF32(volume_start, volume_end, t);
|
||||
f32 pan = LerpF32(pan_start, pan_end, t);
|
||||
|
||||
u64 sample1_index = frame_pos * 2;
|
||||
u64 sample2_index = sample1_index + 1;
|
||||
|
||||
f32 sample_mono = ((mix_pcm.samples[sample1_index + 0] / 2.0f) + (mix_pcm.samples[sample2_index] / 2.0f)) * volume;
|
||||
|
||||
mix_pcm.samples[sample1_index] = sample_mono * (1.0f - pan);
|
||||
mix_pcm.samples[sample2_index] = sample_mono * (1.0f + pan);
|
||||
}
|
||||
}
|
||||
|
||||
//- Mix into result
|
||||
for (u64 i = 0; i < mix_pcm.count; ++i)
|
||||
{
|
||||
result.samples[i] += mix_pcm.samples[i] * desc.volume;
|
||||
}
|
||||
}
|
||||
|
||||
//- Update track effect data
|
||||
{
|
||||
Lock lock = LockE(&g->mutex);
|
||||
for (u64 i = 0; i < mixes_count; ++i)
|
||||
{
|
||||
MIX_MixData *mix = mixes[i];
|
||||
MIX_Track *track = MIX_TrackFromHandle(mix->track_handle);
|
||||
if (track)
|
||||
{
|
||||
if (mix->track_finished)
|
||||
{
|
||||
/* Release finished tracks */
|
||||
MIX_ReleaseTrackLocked(&lock, track);
|
||||
}
|
||||
}
|
||||
}
|
||||
Unlock(&lock);
|
||||
}
|
||||
|
||||
EndScratch(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -3,33 +3,33 @@
|
||||
|
||||
Enum(MIX_TrackFlag)
|
||||
{
|
||||
MIX_TrackFlag_None = 0,
|
||||
MIX_TrackFlag_Spatialize = (1 << 0)
|
||||
MIX_TrackFlag_None = 0,
|
||||
MIX_TrackFlag_Spatialize = (1 << 0)
|
||||
};
|
||||
|
||||
Struct(MIX_Handle)
|
||||
{
|
||||
u64 gen;
|
||||
void *data;
|
||||
u64 gen;
|
||||
void *data;
|
||||
};
|
||||
|
||||
Struct(MIX_TrackDesc)
|
||||
{
|
||||
MIX_TrackFlag flags;
|
||||
f32 volume; /* 0 -> 1.0+ */
|
||||
f32 speed; /* 0 -> 1.0+ */
|
||||
b32 looping;
|
||||
MIX_TrackFlag flags;
|
||||
f32 volume; /* 0 -> 1.0+ */
|
||||
f32 speed; /* 0 -> 1.0+ */
|
||||
b32 looping;
|
||||
|
||||
/* MIX_TrackFlag_Spatialize */
|
||||
Vec2 pos;
|
||||
/* MIX_TrackFlag_Spatialize */
|
||||
Vec2 pos;
|
||||
};
|
||||
#define M_TRACKDESC(...) ((MIX_TrackDesc) { \
|
||||
.flags = 0, \
|
||||
.volume = 1.0, \
|
||||
.speed = 1.0, \
|
||||
.looping = 0, \
|
||||
.pos = VEC2(0, 0), \
|
||||
__VA_ARGS__ \
|
||||
.flags = 0, \
|
||||
.volume = 1.0, \
|
||||
.speed = 1.0, \
|
||||
.looping = 0, \
|
||||
.pos = VEC2(0, 0), \
|
||||
__VA_ARGS__ \
|
||||
})
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -38,40 +38,40 @@ Struct(MIX_TrackDesc)
|
||||
/* Stereo mix of 32 bit float samples */
|
||||
Struct(MIX_PcmF32)
|
||||
{
|
||||
u64 count;
|
||||
f32 *samples;
|
||||
u64 count;
|
||||
f32 *samples;
|
||||
};
|
||||
|
||||
Struct(MIX_EffectData)
|
||||
{
|
||||
/* Spatialization */
|
||||
f32 spatial_volume;
|
||||
f32 spatial_pan;
|
||||
/* Spatialization */
|
||||
f32 spatial_volume;
|
||||
f32 spatial_pan;
|
||||
};
|
||||
|
||||
Struct(MIX_MixData)
|
||||
{
|
||||
MIX_Handle track_handle;
|
||||
b32 track_finished;
|
||||
MIX_Handle track_handle;
|
||||
b32 track_finished;
|
||||
|
||||
MIX_TrackDesc desc;
|
||||
MIX_EffectData effect_data;
|
||||
SND_Sound *source;
|
||||
u64 source_pos;
|
||||
MIX_TrackDesc desc;
|
||||
MIX_EffectData effect_data;
|
||||
SND_Sound *source;
|
||||
u64 source_pos;
|
||||
};
|
||||
|
||||
Struct(MIX_Track){
|
||||
u64 gen;
|
||||
u64 gen;
|
||||
|
||||
/* Controlled via interface */
|
||||
SND_Sound *sound;
|
||||
MIX_TrackDesc desc;
|
||||
/* Controlled via interface */
|
||||
SND_Sound *sound;
|
||||
MIX_TrackDesc desc;
|
||||
|
||||
/* Internal */
|
||||
MIX_MixData mix;
|
||||
/* Internal */
|
||||
MIX_MixData mix;
|
||||
|
||||
MIX_Track *next;
|
||||
MIX_Track *prev;
|
||||
MIX_Track *next;
|
||||
MIX_Track *prev;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -79,18 +79,18 @@ Struct(MIX_Track){
|
||||
|
||||
Struct(MIX_SharedState)
|
||||
{
|
||||
Mutex mutex;
|
||||
Mutex mutex;
|
||||
|
||||
/* Listener */
|
||||
Vec2 listener_pos;
|
||||
Vec2 listener_dir;
|
||||
/* Listener */
|
||||
Vec2 listener_pos;
|
||||
Vec2 listener_dir;
|
||||
|
||||
/* Track list */
|
||||
Arena *track_arena;
|
||||
MIX_Track *track_first_playing;
|
||||
MIX_Track *track_last_playing;
|
||||
u64 track_playing_count;
|
||||
MIX_Track *track_first_free;
|
||||
/* Track list */
|
||||
Arena *track_arena;
|
||||
MIX_Track *track_first_playing;
|
||||
MIX_Track *track_last_playing;
|
||||
u64 track_playing_count;
|
||||
MIX_Track *track_first_free;
|
||||
} extern M_shared_state;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
@ -3,15 +3,15 @@
|
||||
|
||||
Enum(MP3_DecodeFlag)
|
||||
{
|
||||
MP3_DecodeFlag_None = 0,
|
||||
MP3_DecodeFlag_Stereo = (1 << 0),
|
||||
MP3_DecodeFlag_None = 0,
|
||||
MP3_DecodeFlag_Stereo = (1 << 0),
|
||||
};
|
||||
|
||||
Struct(MP3_Result)
|
||||
{
|
||||
u64 samples_count;
|
||||
i16 *samples;
|
||||
b32 ok;
|
||||
u64 samples_count;
|
||||
i16 *samples;
|
||||
b32 ok;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
@ -3,114 +3,114 @@
|
||||
|
||||
MP3_Result MP3_Decode(Arena *arena, String encoded, u32 sample_rate, MP3_DecodeFlag flags)
|
||||
{
|
||||
MP3_Result result = ZI;
|
||||
u64 bytes_per_sample = 2;
|
||||
MP3_Result result = ZI;
|
||||
u64 bytes_per_sample = 2;
|
||||
|
||||
u64 channel_count;
|
||||
u32 channel_mask;
|
||||
if (flags & MP3_DecodeFlag_Stereo)
|
||||
u64 channel_count;
|
||||
u32 channel_mask;
|
||||
if (flags & MP3_DecodeFlag_Stereo)
|
||||
{
|
||||
channel_count = 2;
|
||||
channel_mask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
|
||||
}
|
||||
else
|
||||
{
|
||||
channel_count = 1;
|
||||
channel_mask = SPEAKER_FRONT_CENTER;
|
||||
}
|
||||
|
||||
//- Startup
|
||||
|
||||
MFStartup(MF_VERSION, MFSTARTUP_LITE);
|
||||
|
||||
/* Create IStream from encoded string */
|
||||
IStream *i_stream = SHCreateMemStream(encoded.text, encoded.len);
|
||||
|
||||
/* Create IMFByteStream from IStream */
|
||||
IMFByteStream *byte_stream = 0;
|
||||
MFCreateMFByteStreamOnStream(i_stream, &byte_stream);
|
||||
|
||||
/* Create reader from IMFByteStream */
|
||||
IMFSourceReader *reader;
|
||||
MFCreateSourceReaderFromByteStream(byte_stream, 0, &reader);
|
||||
|
||||
//- Get media type
|
||||
|
||||
/* Read only first audio stream */
|
||||
IMFSourceReader_SetStreamSelection(reader, (DWORD)MF_SOURCE_READER_ALL_STREAMS, 0);
|
||||
IMFSourceReader_SetStreamSelection(reader, (DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, 1);
|
||||
|
||||
WAVEFORMATEXTENSIBLE format = {
|
||||
.Format = {
|
||||
.wFormatTag = WAVE_FORMAT_EXTENSIBLE,
|
||||
.nChannels = (WORD)channel_count,
|
||||
.nSamplesPerSec = (WORD)sample_rate,
|
||||
.nAvgBytesPerSec = (DWORD)(sample_rate * channel_count * bytes_per_sample),
|
||||
.nBlockAlign = (WORD)(channel_count * bytes_per_sample),
|
||||
.wBitsPerSample = (WORD)(8 * bytes_per_sample),
|
||||
.cbSize = sizeof(format) - sizeof(format.Format)
|
||||
},
|
||||
.Samples.wValidBitsPerSample = 8 * bytes_per_sample,
|
||||
.dwChannelMask = channel_mask,
|
||||
.SubFormat = MEDIASUBTYPE_PCM
|
||||
};
|
||||
|
||||
/* Media Foundation in Windows 8+ allows reader to convert output to different format than native */
|
||||
IMFMediaType *type;
|
||||
MFCreateMediaType(&type);
|
||||
MFInitMediaTypeFromWaveFormatEx(type, &format.Format, sizeof(format));
|
||||
IMFSourceReader_SetCurrentMediaType(reader, (DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, type);
|
||||
IMFMediaType_Release(type);
|
||||
|
||||
//- Read
|
||||
|
||||
result.samples = ArenaNext(arena, i16);
|
||||
u64 sample_bytes_read = 0;
|
||||
for (;;)
|
||||
{
|
||||
IMFSample *sample;
|
||||
DWORD sample_flags = 0;
|
||||
HRESULT hr = IMFSourceReader_ReadSample(reader, (DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, 0, &sample_flags, 0, &sample);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
channel_count = 2;
|
||||
channel_mask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
|
||||
}
|
||||
else
|
||||
{
|
||||
channel_count = 1;
|
||||
channel_mask = SPEAKER_FRONT_CENTER;
|
||||
break;
|
||||
}
|
||||
|
||||
//- Startup
|
||||
|
||||
MFStartup(MF_VERSION, MFSTARTUP_LITE);
|
||||
|
||||
/* Create IStream from encoded string */
|
||||
IStream *i_stream = SHCreateMemStream(encoded.text, encoded.len);
|
||||
|
||||
/* Create IMFByteStream from IStream */
|
||||
IMFByteStream *byte_stream = 0;
|
||||
MFCreateMFByteStreamOnStream(i_stream, &byte_stream);
|
||||
|
||||
/* Create reader from IMFByteStream */
|
||||
IMFSourceReader *reader;
|
||||
MFCreateSourceReaderFromByteStream(byte_stream, 0, &reader);
|
||||
|
||||
//- Get media type
|
||||
|
||||
/* Read only first audio stream */
|
||||
IMFSourceReader_SetStreamSelection(reader, (DWORD)MF_SOURCE_READER_ALL_STREAMS, 0);
|
||||
IMFSourceReader_SetStreamSelection(reader, (DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, 1);
|
||||
|
||||
WAVEFORMATEXTENSIBLE format = {
|
||||
.Format = {
|
||||
.wFormatTag = WAVE_FORMAT_EXTENSIBLE,
|
||||
.nChannels = (WORD)channel_count,
|
||||
.nSamplesPerSec = (WORD)sample_rate,
|
||||
.nAvgBytesPerSec = (DWORD)(sample_rate * channel_count * bytes_per_sample),
|
||||
.nBlockAlign = (WORD)(channel_count * bytes_per_sample),
|
||||
.wBitsPerSample = (WORD)(8 * bytes_per_sample),
|
||||
.cbSize = sizeof(format) - sizeof(format.Format)
|
||||
},
|
||||
.Samples.wValidBitsPerSample = 8 * bytes_per_sample,
|
||||
.dwChannelMask = channel_mask,
|
||||
.SubFormat = MEDIASUBTYPE_PCM
|
||||
};
|
||||
|
||||
/* Media Foundation in Windows 8+ allows reader to convert output to different format than native */
|
||||
IMFMediaType *type;
|
||||
MFCreateMediaType(&type);
|
||||
MFInitMediaTypeFromWaveFormatEx(type, &format.Format, sizeof(format));
|
||||
IMFSourceReader_SetCurrentMediaType(reader, (DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, type);
|
||||
IMFMediaType_Release(type);
|
||||
|
||||
//- Read
|
||||
|
||||
result.samples = ArenaNext(arena, i16);
|
||||
u64 sample_bytes_read = 0;
|
||||
for (;;)
|
||||
/* Check if done */
|
||||
if (sample_flags & MF_SOURCE_READERF_ENDOFSTREAM)
|
||||
{
|
||||
IMFSample *sample;
|
||||
DWORD sample_flags = 0;
|
||||
HRESULT hr = IMFSourceReader_ReadSample(reader, (DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, 0, &sample_flags, 0, &sample);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check if done */
|
||||
if (sample_flags & MF_SOURCE_READERF_ENDOFSTREAM)
|
||||
{
|
||||
result.ok = 1;
|
||||
break;
|
||||
}
|
||||
Assert(sample_flags == 0);
|
||||
|
||||
/* Read samples */
|
||||
IMFMediaBuffer *buffer;
|
||||
IMFSample_ConvertToContiguousBuffer(sample, &buffer);
|
||||
|
||||
BYTE *src;
|
||||
DWORD size_bytes;
|
||||
IMFMediaBuffer_Lock(buffer, &src, 0, &size_bytes);
|
||||
{
|
||||
i16 *dst = PushStructsNoZero(arena, i16, (size_bytes + 1) >> 1);
|
||||
CopyBytes(dst, src, size_bytes);
|
||||
sample_bytes_read += size_bytes;
|
||||
}
|
||||
IMFMediaBuffer_Unlock(buffer);
|
||||
|
||||
IMediaBuffer_Release(buffer);
|
||||
IMFSample_Release(sample);
|
||||
result.ok = 1;
|
||||
break;
|
||||
}
|
||||
Assert(sample_flags == 0);
|
||||
|
||||
result.samples_count = sample_bytes_read / bytes_per_sample;
|
||||
/* Read samples */
|
||||
IMFMediaBuffer *buffer;
|
||||
IMFSample_ConvertToContiguousBuffer(sample, &buffer);
|
||||
|
||||
//- Cleanup
|
||||
BYTE *src;
|
||||
DWORD size_bytes;
|
||||
IMFMediaBuffer_Lock(buffer, &src, 0, &size_bytes);
|
||||
{
|
||||
i16 *dst = PushStructsNoZero(arena, i16, (size_bytes + 1) >> 1);
|
||||
CopyBytes(dst, src, size_bytes);
|
||||
sample_bytes_read += size_bytes;
|
||||
}
|
||||
IMFMediaBuffer_Unlock(buffer);
|
||||
|
||||
IMFSourceReader_Release(reader);
|
||||
IMFByteStream_Close(byte_stream);
|
||||
/* FIXME: Enable this */
|
||||
//IStream_Release(i_stream);
|
||||
MFShutdown();
|
||||
IMediaBuffer_Release(buffer);
|
||||
IMFSample_Release(sample);
|
||||
}
|
||||
|
||||
return result;
|
||||
result.samples_count = sample_bytes_read / bytes_per_sample;
|
||||
|
||||
//- Cleanup
|
||||
|
||||
IMFSourceReader_Release(reader);
|
||||
IMFByteStream_Close(byte_stream);
|
||||
/* FIXME: Enable this */
|
||||
//IStream_Release(i_stream);
|
||||
MFShutdown();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -2,11 +2,11 @@
|
||||
//~ Windows headers
|
||||
|
||||
#pragma warning(push, 0)
|
||||
# include <mfapi.h>
|
||||
# include <mfidl.h>
|
||||
# include <mfreadwrite.h>
|
||||
# include <Shlwapi.h>
|
||||
# include <objidl.h>
|
||||
#include <mfapi.h>
|
||||
#include <mfidl.h>
|
||||
#include <mfreadwrite.h>
|
||||
#include <Shlwapi.h>
|
||||
#include <objidl.h>
|
||||
#pragma warning(pop)
|
||||
|
||||
#pragma comment(lib, "mfplat")
|
||||
|
||||
1650
src/net/net.c
1650
src/net/net.c
File diff suppressed because it is too large
Load Diff
248
src/net/net.h
248
src/net/net.h
@ -3,8 +3,8 @@
|
||||
|
||||
Struct(N_ChannelId)
|
||||
{
|
||||
u32 gen;
|
||||
u32 idx;
|
||||
u32 gen;
|
||||
u32 idx;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -12,32 +12,32 @@ Struct(N_ChannelId)
|
||||
|
||||
Enum(N_CmdKind)
|
||||
{
|
||||
N_CmdKind_None,
|
||||
N_CmdKind_TryConnect,
|
||||
N_CmdKind_ConnectSuccess,
|
||||
N_CmdKind_Disconnect,
|
||||
N_CmdKind_Heartbeat,
|
||||
N_CmdKind_Write
|
||||
N_CmdKind_None,
|
||||
N_CmdKind_TryConnect,
|
||||
N_CmdKind_ConnectSuccess,
|
||||
N_CmdKind_Disconnect,
|
||||
N_CmdKind_Heartbeat,
|
||||
N_CmdKind_Write
|
||||
};
|
||||
|
||||
Enum(N_WriteFlag)
|
||||
{
|
||||
N_WriteFlag_None = 0,
|
||||
N_WriteFlag_Reliable = (1 << 0)
|
||||
N_WriteFlag_None = 0,
|
||||
N_WriteFlag_Reliable = (1 << 0)
|
||||
};
|
||||
|
||||
Struct(N_Cmd)
|
||||
{
|
||||
N_CmdKind kind;
|
||||
N_ChannelId channel_id;
|
||||
N_CmdKind kind;
|
||||
N_ChannelId channel_id;
|
||||
|
||||
u16 heartbeat_id;
|
||||
u16 heartbeat_ack_id;
|
||||
u16 heartbeat_id;
|
||||
u16 heartbeat_ack_id;
|
||||
|
||||
b32 write_reliable;
|
||||
String write_msg;
|
||||
b32 write_reliable;
|
||||
String write_msg;
|
||||
|
||||
N_Cmd *next;
|
||||
N_Cmd *next;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -45,31 +45,31 @@ Struct(N_Cmd)
|
||||
|
||||
Enum(N_EventKind)
|
||||
{
|
||||
N_EventKind_None,
|
||||
N_EventKind_ChannelOpened,
|
||||
N_EventKind_ChannelClosed,
|
||||
N_EventKind_Msg
|
||||
N_EventKind_None,
|
||||
N_EventKind_ChannelOpened,
|
||||
N_EventKind_ChannelClosed,
|
||||
N_EventKind_Msg
|
||||
};
|
||||
|
||||
Struct(N_Event)
|
||||
{
|
||||
N_EventKind kind;
|
||||
N_ChannelId channel_id;
|
||||
String msg;
|
||||
N_EventKind kind;
|
||||
N_ChannelId channel_id;
|
||||
String msg;
|
||||
|
||||
N_Event *next;
|
||||
N_Event *next;
|
||||
};
|
||||
|
||||
Struct(N_EventList)
|
||||
{
|
||||
N_Event *first;
|
||||
N_Event *last;
|
||||
N_Event *first;
|
||||
N_Event *last;
|
||||
};
|
||||
|
||||
Struct(N_ChannelLookupBin)
|
||||
{
|
||||
struct N_Channel *first;
|
||||
struct N_Channel *last;
|
||||
struct N_Channel *first;
|
||||
struct N_Channel *last;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -81,42 +81,42 @@ Struct(N_ChannelLookupBin)
|
||||
|
||||
Enum(N_PacketKind)
|
||||
{
|
||||
N_PacketKind_None,
|
||||
N_PacketKind_TryConnect,
|
||||
N_PacketKind_ConnectSuccess,
|
||||
N_PacketKind_Disconnect,
|
||||
N_PacketKind_Heartbeat,
|
||||
N_PacketKind_MsgChunk
|
||||
N_PacketKind_None,
|
||||
N_PacketKind_TryConnect,
|
||||
N_PacketKind_ConnectSuccess,
|
||||
N_PacketKind_Disconnect,
|
||||
N_PacketKind_Heartbeat,
|
||||
N_PacketKind_MsgChunk
|
||||
};
|
||||
|
||||
Enum(N_PacketFlag)
|
||||
{
|
||||
N_PacketFlag_None = 0,
|
||||
N_PacketFlag_Reliable = (1 << 0)
|
||||
N_PacketFlag_None = 0,
|
||||
N_PacketFlag_Reliable = (1 << 0)
|
||||
};
|
||||
|
||||
Struct(N_SndPacket)
|
||||
{
|
||||
N_SndPacket *next;
|
||||
u64 seq;
|
||||
N_SndPacket *next;
|
||||
u64 seq;
|
||||
|
||||
u64 data_len;
|
||||
u8 data[N_MaxPacketLen];
|
||||
u64 data_len;
|
||||
u8 data[N_MaxPacketLen];
|
||||
};
|
||||
|
||||
Struct(N_RcvPacket)
|
||||
{
|
||||
P_Sock *sock;
|
||||
P_Address address;
|
||||
String data;
|
||||
N_RcvPacket *next;
|
||||
P_Sock *sock;
|
||||
P_Address address;
|
||||
String data;
|
||||
N_RcvPacket *next;
|
||||
};
|
||||
|
||||
Struct(N_RcvBuffer)
|
||||
{
|
||||
Arena *arena;
|
||||
N_RcvPacket *first_packet;
|
||||
N_RcvPacket *last_packet;
|
||||
Arena *arena;
|
||||
N_RcvPacket *first_packet;
|
||||
N_RcvPacket *last_packet;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -124,53 +124,53 @@ Struct(N_RcvBuffer)
|
||||
|
||||
Struct(N_Channel)
|
||||
{
|
||||
N_ChannelId id;
|
||||
b32 valid;
|
||||
b32 connected;
|
||||
struct N_Host *host;
|
||||
N_ChannelId id;
|
||||
b32 valid;
|
||||
b32 connected;
|
||||
struct N_Host *host;
|
||||
|
||||
N_Channel *next_free;
|
||||
N_Channel *next_free;
|
||||
|
||||
P_Address address;
|
||||
u64 address_hash;
|
||||
N_Channel *next_address_hash;
|
||||
N_Channel *prev_address_hash;
|
||||
P_Address address;
|
||||
u64 address_hash;
|
||||
N_Channel *next_address_hash;
|
||||
N_Channel *prev_address_hash;
|
||||
|
||||
/* NOTE: Packets are allocated in host's `arena` */
|
||||
N_SndPacket *first_reliable_packet;
|
||||
N_SndPacket *last_reliable_packet;
|
||||
N_SndPacket *first_unreliable_packet;
|
||||
N_SndPacket *last_unreliable_packet;
|
||||
u64 num_reliable_packets;
|
||||
u64 num_unreliable_packets;
|
||||
/* NOTE: Packets are allocated in host's `arena` */
|
||||
N_SndPacket *first_reliable_packet;
|
||||
N_SndPacket *last_reliable_packet;
|
||||
N_SndPacket *first_unreliable_packet;
|
||||
N_SndPacket *last_unreliable_packet;
|
||||
u64 num_reliable_packets;
|
||||
u64 num_unreliable_packets;
|
||||
|
||||
/* NOTE: Msg assemblers are allocated in host's `arena` */
|
||||
struct N_MsgAssembler *least_recent_msg_assembler;
|
||||
struct N_MsgAssembler *most_recent_msg_assembler;
|
||||
/* NOTE: Msg assemblers are allocated in host's `arena` */
|
||||
struct N_MsgAssembler *least_recent_msg_assembler;
|
||||
struct N_MsgAssembler *most_recent_msg_assembler;
|
||||
|
||||
u16 last_heartbeat_received_id;
|
||||
u16 last_heartbeat_acked_id;
|
||||
i64 last_heartbeat_acked_ns;
|
||||
i64 last_heartbeat_rtt_ns;
|
||||
u16 last_heartbeat_received_id;
|
||||
u16 last_heartbeat_acked_id;
|
||||
i64 last_heartbeat_acked_ns;
|
||||
i64 last_heartbeat_rtt_ns;
|
||||
|
||||
u64 last_sent_msg_id;
|
||||
u64 their_acked_seq;
|
||||
u64 our_acked_seq;
|
||||
u64 last_sent_seq;
|
||||
u64 last_sent_msg_id;
|
||||
u64 their_acked_seq;
|
||||
u64 our_acked_seq;
|
||||
u64 last_sent_seq;
|
||||
|
||||
i64 last_packet_received_ns;
|
||||
i64 last_packet_received_ns;
|
||||
};
|
||||
|
||||
Struct(N_ChannelNode)
|
||||
{
|
||||
N_Channel *channel;
|
||||
N_ChannelNode *next;
|
||||
N_Channel *channel;
|
||||
N_ChannelNode *next;
|
||||
};
|
||||
|
||||
Struct(N_ChannelList)
|
||||
{
|
||||
N_ChannelNode *first;
|
||||
N_ChannelNode *last;
|
||||
N_ChannelNode *first;
|
||||
N_ChannelNode *last;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -178,38 +178,38 @@ Struct(N_ChannelList)
|
||||
|
||||
Struct(N_MsgAssembler)
|
||||
{
|
||||
N_Channel *channel;
|
||||
b32 is_reliable;
|
||||
N_Channel *channel;
|
||||
b32 is_reliable;
|
||||
|
||||
/* Free list */
|
||||
N_MsgAssembler *next_free;
|
||||
/* Free list */
|
||||
N_MsgAssembler *next_free;
|
||||
|
||||
/* Bucket list */
|
||||
N_MsgAssembler *next_hash;
|
||||
N_MsgAssembler *prev_hash;
|
||||
/* Bucket list */
|
||||
N_MsgAssembler *next_hash;
|
||||
N_MsgAssembler *prev_hash;
|
||||
|
||||
/* Channel list */
|
||||
N_MsgAssembler *less_recent;
|
||||
N_MsgAssembler *more_recent;
|
||||
/* Channel list */
|
||||
N_MsgAssembler *less_recent;
|
||||
N_MsgAssembler *more_recent;
|
||||
|
||||
u64 msg_id;
|
||||
u64 hash;
|
||||
u64 msg_id;
|
||||
u64 hash;
|
||||
|
||||
u64 last_chunk_len;
|
||||
u64 num_chunks_total;
|
||||
u64 num_chunks_received;
|
||||
u64 last_chunk_len;
|
||||
u64 num_chunks_total;
|
||||
u64 num_chunks_received;
|
||||
|
||||
i64 touched_ns;
|
||||
i64 touched_ns;
|
||||
|
||||
BuddyBlock *buddy_block;
|
||||
u8 *chunk_bitmap;
|
||||
u8 *chunk_data;
|
||||
BuddyBlock *buddy_block;
|
||||
u8 *chunk_bitmap;
|
||||
u8 *chunk_data;
|
||||
};
|
||||
|
||||
Struct(N_MsgAssemblerLookupBin)
|
||||
{
|
||||
N_MsgAssembler *first;
|
||||
N_MsgAssembler *last;
|
||||
N_MsgAssembler *first;
|
||||
N_MsgAssembler *last;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -220,38 +220,38 @@ Struct(N_MsgAssemblerLookupBin)
|
||||
|
||||
Struct(N_Host)
|
||||
{
|
||||
Arena *arena;
|
||||
Arena *arena;
|
||||
|
||||
P_Sock *sock;
|
||||
P_Sock *sock;
|
||||
|
||||
BuddyCtx *buddy; /* For storing msg assembler data */
|
||||
BuddyCtx *buddy; /* For storing msg assembler data */
|
||||
|
||||
Arena *cmd_arena;
|
||||
N_Cmd *first_cmd;
|
||||
N_Cmd *last_cmd;
|
||||
N_Cmd *first_free_cmd;
|
||||
Arena *cmd_arena;
|
||||
N_Cmd *first_cmd;
|
||||
N_Cmd *last_cmd;
|
||||
N_Cmd *first_free_cmd;
|
||||
|
||||
Arena *channel_arena;
|
||||
N_Channel *channels;
|
||||
N_Channel *first_free_channel;
|
||||
u64 num_channels_reserved;
|
||||
Arena *channel_arena;
|
||||
N_Channel *channels;
|
||||
N_Channel *first_free_channel;
|
||||
u64 num_channels_reserved;
|
||||
|
||||
N_SndPacket *first_free_packet; /* Acquired in `arena` */
|
||||
N_MsgAssembler *first_free_msg_assembler; /* Acquired in `arena` */
|
||||
N_SndPacket *first_free_packet; /* Acquired in `arena` */
|
||||
N_MsgAssembler *first_free_msg_assembler; /* Acquired in `arena` */
|
||||
|
||||
N_ChannelLookupBin *channel_lookup_bins; /* Acquired in `arena` */
|
||||
u64 num_channel_lookup_bins;
|
||||
N_ChannelLookupBin *channel_lookup_bins; /* Acquired in `arena` */
|
||||
u64 num_channel_lookup_bins;
|
||||
|
||||
N_MsgAssemblerLookupBin *msg_assembler_lookup_bins; /* Acquired in `arena` */
|
||||
u64 num_msg_assembler_lookup_bins;
|
||||
N_MsgAssemblerLookupBin *msg_assembler_lookup_bins; /* Acquired in `arena` */
|
||||
u64 num_msg_assembler_lookup_bins;
|
||||
|
||||
/* Double buffer for incoming data */
|
||||
Mutex rcv_buffer_write_mutex;
|
||||
N_RcvBuffer *rcv_buffer_read;
|
||||
N_RcvBuffer *rcv_buffer_write;
|
||||
/* Double buffer for incoming data */
|
||||
Mutex rcv_buffer_write_mutex;
|
||||
N_RcvBuffer *rcv_buffer_read;
|
||||
N_RcvBuffer *rcv_buffer_write;
|
||||
|
||||
u64 bytes_received;
|
||||
u64 bytes_sent;
|
||||
u64 bytes_received;
|
||||
u64 bytes_sent;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
@ -9,22 +9,22 @@ Struct(P_Sock);
|
||||
|
||||
Struct(P_File)
|
||||
{
|
||||
u64 handle;
|
||||
b32 valid;
|
||||
u64 handle;
|
||||
b32 valid;
|
||||
};
|
||||
|
||||
Struct(P_FileTime)
|
||||
{
|
||||
DateTime created;
|
||||
DateTime accessed;
|
||||
DateTime modified;
|
||||
DateTime created;
|
||||
DateTime accessed;
|
||||
DateTime modified;
|
||||
};
|
||||
|
||||
Struct(P_FileMap)
|
||||
{
|
||||
String mapped_memory;
|
||||
u64 handle;
|
||||
b32 valid;
|
||||
String mapped_memory;
|
||||
u64 handle;
|
||||
b32 valid;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -32,17 +32,17 @@ Struct(P_FileMap)
|
||||
|
||||
Enum(P_AddressFamily)
|
||||
{
|
||||
P_AddressFamily_Ipv4,
|
||||
P_AddressFamily_Ipv6
|
||||
P_AddressFamily_Ipv4,
|
||||
P_AddressFamily_Ipv6
|
||||
};
|
||||
|
||||
Struct(P_Address)
|
||||
{
|
||||
b32 valid;
|
||||
P_AddressFamily family;
|
||||
/* NOTE: ipnb & portnb are stored in network byte order */
|
||||
u8 ipnb[16];
|
||||
u16 portnb;
|
||||
b32 valid;
|
||||
P_AddressFamily family;
|
||||
/* NOTE: ipnb & portnb are stored in network byte order */
|
||||
u8 ipnb[16];
|
||||
u16 portnb;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -50,9 +50,9 @@ Struct(P_Address)
|
||||
|
||||
Struct(P_SockReadResult)
|
||||
{
|
||||
b32 valid; /* Since data.len = 0 can be valid */
|
||||
P_Address address;
|
||||
String data;
|
||||
b32 valid; /* Since data.len = 0 can be valid */
|
||||
P_Address address;
|
||||
String data;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -60,10 +60,10 @@ Struct(P_SockReadResult)
|
||||
|
||||
Enum(P_MessageBoxKind)
|
||||
{
|
||||
P_MessageBoxKind_Ok,
|
||||
P_MessageBoxKind_Warning,
|
||||
P_MessageBoxKind_Error,
|
||||
P_MessageBoxKind_Fatal
|
||||
P_MessageBoxKind_Ok,
|
||||
P_MessageBoxKind_Warning,
|
||||
P_MessageBoxKind_Error,
|
||||
P_MessageBoxKind_Fatal
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -2,15 +2,15 @@
|
||||
//~ Win32 libs
|
||||
|
||||
#pragma warning(push, 0)
|
||||
# include <WinSock2.h>
|
||||
# include <TlHelp32.h>
|
||||
# include <WS2tcpip.h>
|
||||
# include <windowsx.h>
|
||||
# include <ShlObj_core.h>
|
||||
# include <fileapi.h>
|
||||
# include <dwmapi.h>
|
||||
# include <avrt.h>
|
||||
# include <shellapi.h>
|
||||
#include <WinSock2.h>
|
||||
#include <TlHelp32.h>
|
||||
#include <WS2tcpip.h>
|
||||
#include <windowsx.h>
|
||||
#include <ShlObj_core.h>
|
||||
#include <fileapi.h>
|
||||
#include <dwmapi.h>
|
||||
#include <avrt.h>
|
||||
#include <shellapi.h>
|
||||
#pragma warning(pop)
|
||||
|
||||
#pragma comment(lib, "kernel32")
|
||||
@ -28,10 +28,10 @@
|
||||
|
||||
Struct(P_W32_Watch)
|
||||
{
|
||||
HANDLE dir_handle;
|
||||
HANDLE wake_handle;
|
||||
P_W32_Watch *next_free;
|
||||
u8 results_buff[Kibi(64)];
|
||||
HANDLE dir_handle;
|
||||
HANDLE wake_handle;
|
||||
P_W32_Watch *next_free;
|
||||
u8 results_buff[Kibi(64)];
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -39,15 +39,15 @@ Struct(P_W32_Watch)
|
||||
|
||||
Struct(P_W32_Address)
|
||||
{
|
||||
i32 size;
|
||||
i32 family;
|
||||
union
|
||||
{
|
||||
struct sockaddr_storage sas;
|
||||
struct sockaddr sa;
|
||||
struct sockaddr_in sin;
|
||||
struct sockaddr_in6 sin6;
|
||||
};
|
||||
i32 size;
|
||||
i32 family;
|
||||
union
|
||||
{
|
||||
struct sockaddr_storage sas;
|
||||
struct sockaddr sa;
|
||||
struct sockaddr_in sin;
|
||||
struct sockaddr_in6 sin6;
|
||||
};
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -55,8 +55,8 @@ Struct(P_W32_Address)
|
||||
|
||||
Struct(P_W32_Sock)
|
||||
{
|
||||
SOCKET sock;
|
||||
P_W32_Sock *next_free;
|
||||
SOCKET sock;
|
||||
P_W32_Sock *next_free;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -67,20 +67,20 @@ Struct(P_W32_Sock)
|
||||
|
||||
Struct(P_W32_SharedState)
|
||||
{
|
||||
//- Watches pool
|
||||
Mutex watches_mutex;
|
||||
Arena *watches_arena;
|
||||
P_W32_Watch *watches_first_free;
|
||||
//- Watches pool
|
||||
Mutex watches_mutex;
|
||||
Arena *watches_arena;
|
||||
P_W32_Watch *watches_first_free;
|
||||
|
||||
//- Socket pool
|
||||
WSADATA wsa_data;
|
||||
Arena *socks_arena;
|
||||
Mutex socks_mutex;
|
||||
P_W32_Sock *first_free_sock;
|
||||
//- Socket pool
|
||||
WSADATA wsa_data;
|
||||
Arena *socks_arena;
|
||||
Mutex socks_mutex;
|
||||
P_W32_Sock *first_free_sock;
|
||||
|
||||
//- Timer
|
||||
Fence timer_fence;
|
||||
Atomic64Padded average_timer_period_ns;
|
||||
//- Timer
|
||||
Fence timer_fence;
|
||||
Atomic64Padded average_timer_period_ns;
|
||||
} extern P_W32_shared_state;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
@ -11,12 +11,12 @@ PB_WSP_SharedState PB_WSP_shared_state = ZI;
|
||||
|
||||
void PB_Bootstrap(void)
|
||||
{
|
||||
PB_WSP_SharedState *g = &PB_WSP_shared_state;
|
||||
PB_WSP_InitializeWasapi();
|
||||
/* Start playback job */
|
||||
JobPoolId playback_pool = InitJobPool(1, Lit("Playback"), JobPoolPriority_Audio);
|
||||
g->shutdown_jobs_count += RunJob(PB_WSP_Playback, .pool = playback_pool, .fence = &g->shutdown_jobs_fence);
|
||||
OnExit(&PB_WSP_Shutdown);
|
||||
PB_WSP_SharedState *g = &PB_WSP_shared_state;
|
||||
PB_WSP_InitializeWasapi();
|
||||
/* Start playback job */
|
||||
JobPoolId playback_pool = InitJobPool(1, Lit("Playback"), JobPoolPriority_Audio);
|
||||
g->shutdown_jobs_count += RunJob(PB_WSP_Playback, .pool = playback_pool, .fence = &g->shutdown_jobs_fence);
|
||||
OnExit(&PB_WSP_Shutdown);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -24,102 +24,102 @@ void PB_Bootstrap(void)
|
||||
|
||||
ExitFuncDef(PB_WSP_Shutdown)
|
||||
{
|
||||
PB_WSP_SharedState *g = &PB_WSP_shared_state;
|
||||
Atomic32Set(&g->shutdown, 1);
|
||||
YieldOnFence(&g->shutdown_jobs_fence, g->shutdown_jobs_count);
|
||||
PB_WSP_SharedState *g = &PB_WSP_shared_state;
|
||||
Atomic32Set(&g->shutdown, 1);
|
||||
YieldOnFence(&g->shutdown_jobs_fence, g->shutdown_jobs_count);
|
||||
}
|
||||
|
||||
void PB_WSP_InitializeWasapi(void)
|
||||
{
|
||||
PB_WSP_SharedState *g = &PB_WSP_shared_state;
|
||||
u64 sample_rate = PB_SampleRate;
|
||||
u64 channel_count = 2;
|
||||
u32 channel_mask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
|
||||
PB_WSP_SharedState *g = &PB_WSP_shared_state;
|
||||
u64 sample_rate = PB_SampleRate;
|
||||
u64 channel_count = 2;
|
||||
u32 channel_mask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
|
||||
|
||||
/* Create enumerator to get audio device */
|
||||
IMMDeviceEnumerator *enumerator;
|
||||
CoCreateInstance(&CLSID_MMDeviceEnumerator, 0, CLSCTX_ALL, &IID_IMMDeviceEnumerator, (LPVOID *)&enumerator);
|
||||
/* Create enumerator to get audio device */
|
||||
IMMDeviceEnumerator *enumerator;
|
||||
CoCreateInstance(&CLSID_MMDeviceEnumerator, 0, CLSCTX_ALL, &IID_IMMDeviceEnumerator, (LPVOID *)&enumerator);
|
||||
|
||||
/* Get default playback device */
|
||||
IMMDevice *device;
|
||||
IMMDeviceEnumerator_GetDefaultAudioEndpoint(enumerator, eRender, eConsole, &device);
|
||||
IMMDeviceEnumerator_Release(enumerator);
|
||||
/* Get default playback device */
|
||||
IMMDevice *device;
|
||||
IMMDeviceEnumerator_GetDefaultAudioEndpoint(enumerator, eRender, eConsole, &device);
|
||||
IMMDeviceEnumerator_Release(enumerator);
|
||||
|
||||
/* Create audio client for device */
|
||||
IMMDevice_Activate(device, &IID_IAudioClient, CLSCTX_ALL, 0, (LPVOID *)&g->client);
|
||||
IMMDevice_Release(device);
|
||||
/* Create audio client for device */
|
||||
IMMDevice_Activate(device, &IID_IAudioClient, CLSCTX_ALL, 0, (LPVOID *)&g->client);
|
||||
IMMDevice_Release(device);
|
||||
|
||||
WAVEFORMATEXTENSIBLE format_ex = {
|
||||
.Format = {
|
||||
.wFormatTag = WAVE_FORMAT_EXTENSIBLE,
|
||||
.nChannels = (WORD)channel_count,
|
||||
.nSamplesPerSec = (WORD)sample_rate,
|
||||
.nAvgBytesPerSec = (DWORD)(sample_rate * channel_count * sizeof(f32)),
|
||||
.nBlockAlign = (WORD)(channel_count * sizeof(f32)),
|
||||
.wBitsPerSample = (WORD)(8 * sizeof(f32)),
|
||||
.cbSize = sizeof(format_ex) - sizeof(format_ex.Format),
|
||||
},
|
||||
.Samples.wValidBitsPerSample = 8 * sizeof(f32),
|
||||
.dwChannelMask = channel_mask,
|
||||
.SubFormat = MEDIASUBTYPE_IEEE_FLOAT,
|
||||
};
|
||||
WAVEFORMATEX *wfx = &format_ex.Format;
|
||||
WAVEFORMATEXTENSIBLE format_ex = {
|
||||
.Format = {
|
||||
.wFormatTag = WAVE_FORMAT_EXTENSIBLE,
|
||||
.nChannels = (WORD)channel_count,
|
||||
.nSamplesPerSec = (WORD)sample_rate,
|
||||
.nAvgBytesPerSec = (DWORD)(sample_rate * channel_count * sizeof(f32)),
|
||||
.nBlockAlign = (WORD)(channel_count * sizeof(f32)),
|
||||
.wBitsPerSample = (WORD)(8 * sizeof(f32)),
|
||||
.cbSize = sizeof(format_ex) - sizeof(format_ex.Format),
|
||||
},
|
||||
.Samples.wValidBitsPerSample = 8 * sizeof(f32),
|
||||
.dwChannelMask = channel_mask,
|
||||
.SubFormat = MEDIASUBTYPE_IEEE_FLOAT,
|
||||
};
|
||||
WAVEFORMATEX *wfx = &format_ex.Format;
|
||||
|
||||
#if 0
|
||||
b32 client_initialized = 0;
|
||||
IAudioClient3 *client3;
|
||||
if (SUCCEEDED(IAudioClient_QueryInterface(g->client, &IID_IAudioClient3, (LPVOID *)&client3)))
|
||||
#if 0
|
||||
b32 client_initialized = 0;
|
||||
IAudioClient3 *client3;
|
||||
if (SUCCEEDED(IAudioClient_QueryInterface(g->client, &IID_IAudioClient3, (LPVOID *)&client3)))
|
||||
{
|
||||
/* From Martins: Minimum buffer size will typically be 480 samples (10msec @ 48khz)
|
||||
* but it can be 128 samples (2.66 msec @ 48khz) if driver is properly installed
|
||||
* see bullet-point instructions here: https://learn.microsoft.com/en-us/windows-hardware/drivers/audio/low-latency-audio#measurement-tools
|
||||
*/
|
||||
UINT32 default_period_samples, fundamental_period_samples, min_period_samples, max_period_samples;
|
||||
IAudioClient3_GetSharedModeEnginePeriod(client3, wfx, &default_period_samples, &fundamental_period_samples, &min_period_samples, &max_period_samples);
|
||||
|
||||
const DWORD flags = AUDCLNT_STREAMFLAGS_EVENTCALLBACK;
|
||||
if (SUCCEEDED(IAudioClient3_InitializeSharedAudioStream(client3, flags, min_period_samples, wfx, 0)))
|
||||
{
|
||||
/* From Martins: Minimum buffer size will typically be 480 samples (10msec @ 48khz)
|
||||
* but it can be 128 samples (2.66 msec @ 48khz) if driver is properly installed
|
||||
* see bullet-point instructions here: https://learn.microsoft.com/en-us/windows-hardware/drivers/audio/low-latency-audio#measurement-tools
|
||||
*/
|
||||
UINT32 default_period_samples, fundamental_period_samples, min_period_samples, max_period_samples;
|
||||
IAudioClient3_GetSharedModeEnginePeriod(client3, wfx, &default_period_samples, &fundamental_period_samples, &min_period_samples, &max_period_samples);
|
||||
|
||||
const DWORD flags = AUDCLNT_STREAMFLAGS_EVENTCALLBACK;
|
||||
if (SUCCEEDED(IAudioClient3_InitializeSharedAudioStream(client3, flags, min_period_samples, wfx, 0)))
|
||||
{
|
||||
client_initialized = 1;
|
||||
}
|
||||
|
||||
IAudioClient3_Release(client3);
|
||||
}
|
||||
#else
|
||||
b32 client_initialized = 0;
|
||||
#endif
|
||||
|
||||
if (!client_initialized)
|
||||
{
|
||||
/* Get duration for shared-mode streams, this will typically be 480 samples (10msec @ 48khz) */
|
||||
REFERENCE_TIME duration;
|
||||
IAudioClient_GetDevicePeriod(g->client, &duration, 0);
|
||||
|
||||
/* Initialize audio playback
|
||||
*
|
||||
* NOTE:
|
||||
* Passing AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM will tell WASAPI to
|
||||
* always convert to native mixing format. This may introduce latency
|
||||
* but allows for any input format.
|
||||
*/
|
||||
const DWORD flags = AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY;
|
||||
IAudioClient_Initialize(g->client, AUDCLNT_SHAREMODE_SHARED, flags, duration, 0, wfx, 0);
|
||||
client_initialized = 1;
|
||||
}
|
||||
|
||||
IAudioClient_GetMixFormat(g->client, &g->buffer_format);
|
||||
IAudioClient3_Release(client3);
|
||||
}
|
||||
#else
|
||||
b32 client_initialized = 0;
|
||||
#endif
|
||||
|
||||
/* Set up event handler to wait on */
|
||||
g->event = CreateEventW(0, 0, 0, 0);
|
||||
IAudioClient_SetEventHandle(g->client, g->event);
|
||||
if (!client_initialized)
|
||||
{
|
||||
/* Get duration for shared-mode streams, this will typically be 480 samples (10msec @ 48khz) */
|
||||
REFERENCE_TIME duration;
|
||||
IAudioClient_GetDevicePeriod(g->client, &duration, 0);
|
||||
|
||||
/* Get playback client */
|
||||
IAudioClient_GetService(g->client, &IID_IAudioRenderClient, (LPVOID *)&g->playback);
|
||||
/* Initialize audio playback
|
||||
*
|
||||
* NOTE:
|
||||
* Passing AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM will tell WASAPI to
|
||||
* always convert to native mixing format. This may introduce latency
|
||||
* but allows for any input format.
|
||||
*/
|
||||
const DWORD flags = AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY;
|
||||
IAudioClient_Initialize(g->client, AUDCLNT_SHAREMODE_SHARED, flags, duration, 0, wfx, 0);
|
||||
}
|
||||
|
||||
/* Start the playback */
|
||||
IAudioClient_Start(g->client);
|
||||
IAudioClient_GetMixFormat(g->client, &g->buffer_format);
|
||||
|
||||
/* Get audio buffer size in samples */
|
||||
IAudioClient_GetBufferSize(g->client, &g->buffer_frames);
|
||||
/* Set up event handler to wait on */
|
||||
g->event = CreateEventW(0, 0, 0, 0);
|
||||
IAudioClient_SetEventHandle(g->client, g->event);
|
||||
|
||||
/* Get playback client */
|
||||
IAudioClient_GetService(g->client, &IID_IAudioRenderClient, (LPVOID *)&g->playback);
|
||||
|
||||
/* Start the playback */
|
||||
IAudioClient_Start(g->client);
|
||||
|
||||
/* Get audio buffer size in samples */
|
||||
IAudioClient_GetBufferSize(g->client, &g->buffer_frames);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -127,54 +127,55 @@ void PB_WSP_InitializeWasapi(void)
|
||||
|
||||
PB_WSP_Buff PB_WSP_BeginUpdate(void)
|
||||
{
|
||||
PB_WSP_SharedState *g = &PB_WSP_shared_state;
|
||||
PB_WSP_Buff wspbuf = ZI;
|
||||
PB_WSP_SharedState *g = &PB_WSP_shared_state;
|
||||
PB_WSP_Buff wspbuf = ZI;
|
||||
|
||||
/* Get padding frames */
|
||||
u32 padding_frames;
|
||||
IAudioClient_GetCurrentPadding(g->client, &padding_frames);
|
||||
/* Get padding frames */
|
||||
u32 padding_frames;
|
||||
IAudioClient_GetCurrentPadding(g->client, &padding_frames);
|
||||
|
||||
/* Get output buffer from WASAPI */
|
||||
wspbuf.frames_count = 0;
|
||||
if (padding_frames <= g->buffer_frames)
|
||||
{
|
||||
wspbuf.frames_count = g->buffer_frames - padding_frames;
|
||||
}
|
||||
IAudioRenderClient_GetBuffer(g->playback, wspbuf.frames_count, &wspbuf.frames);
|
||||
/* Get output buffer from WASAPI */
|
||||
wspbuf.frames_count = 0;
|
||||
if (padding_frames <= g->buffer_frames)
|
||||
{
|
||||
wspbuf.frames_count = g->buffer_frames - padding_frames;
|
||||
}
|
||||
IAudioRenderClient_GetBuffer(g->playback, wspbuf.frames_count, &wspbuf.frames);
|
||||
|
||||
return wspbuf;
|
||||
return wspbuf;
|
||||
}
|
||||
|
||||
void PB_WSP_EndUpdate(PB_WSP_Buff *wspbuf, MIX_PcmF32 src)
|
||||
{
|
||||
PB_WSP_SharedState *g = &PB_WSP_shared_state;
|
||||
u32 frames_in_source = src.count / 2;
|
||||
u32 frames_in_output = wspbuf->frames_count;
|
||||
PB_WSP_SharedState *g = &PB_WSP_shared_state;
|
||||
u32 frames_in_source = src.count / 2;
|
||||
u32 frames_in_output = wspbuf->frames_count;
|
||||
|
||||
u32 flags = 0;
|
||||
if (frames_in_source == frames_in_output)
|
||||
{
|
||||
/* Copy bytes to output */
|
||||
u32 bytes_per_sample = g->buffer_format->nBlockAlign / g->buffer_format->nChannels;
|
||||
u32 write_size = frames_in_source * 2 * bytes_per_sample;
|
||||
CopyBytes(wspbuf->frames, src.samples, write_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Submit silence if not enough samples */
|
||||
flags = AUDCLNT_BUFFERFLAGS_SILENT;
|
||||
u32 flags = 0;
|
||||
if (frames_in_source == frames_in_output)
|
||||
{
|
||||
/* Copy bytes to output */
|
||||
u32 bytes_per_sample = g->buffer_format->nBlockAlign / g->buffer_format->nChannels;
|
||||
u32 write_size = frames_in_source * 2 * bytes_per_sample;
|
||||
CopyBytes(wspbuf->frames, src.samples, write_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Submit silence if not enough samples */
|
||||
flags |= AUDCLNT_BUFFERFLAGS_SILENT;
|
||||
|
||||
/* This shouldn't occur, mixer should be generating samples equivilent
|
||||
* to value returned from `PB_WSP_BeginUpdate`. */
|
||||
Assert(0);
|
||||
}
|
||||
/* This shouldn't occur, mixer should be generating samples equivilent
|
||||
* to value returned from `PB_WSP_BeginUpdate`. */
|
||||
Assert(0);
|
||||
}
|
||||
|
||||
#if !AUDIO_ENABLED
|
||||
flags = AUDCLNT_BUFFERFLAGS_SILENT;
|
||||
#endif
|
||||
if (!AUDIO_ENABLED)
|
||||
{
|
||||
flags |= AUDCLNT_BUFFERFLAGS_SILENT;
|
||||
}
|
||||
|
||||
/* Submit output buffer to WASAPI */
|
||||
IAudioRenderClient_ReleaseBuffer(g->playback, frames_in_source, flags);
|
||||
/* Submit output buffer to WASAPI */
|
||||
IAudioRenderClient_ReleaseBuffer(g->playback, frames_in_source, flags);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -182,22 +183,22 @@ void PB_WSP_EndUpdate(PB_WSP_Buff *wspbuf, MIX_PcmF32 src)
|
||||
|
||||
JobImpl(PB_WSP_Playback, sig, id)
|
||||
{
|
||||
PB_WSP_SharedState *g = &PB_WSP_shared_state;
|
||||
PB_WSP_SharedState *g = &PB_WSP_shared_state;
|
||||
|
||||
/* FIXME: If playback fails at any point and mixer stops advancing, we
|
||||
* need to halt mixer to prevent memory leak when sounds are played. */
|
||||
/* TODO: Signal counter that running job wiats on, rather than scheduling job manually */
|
||||
while (!Atomic32Fetch(&g->shutdown))
|
||||
/* FIXME: If playback fails at any point and mixer stops advancing, we
|
||||
* need to halt mixer to prevent memory leak when sounds are played. */
|
||||
/* TODO: Signal counter that running job wiats on, rather than scheduling job manually */
|
||||
while (!Atomic32Fetch(&g->shutdown))
|
||||
{
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
{
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
{
|
||||
WaitForSingleObject(g->event, INFINITE);
|
||||
}
|
||||
{
|
||||
PB_WSP_Buff wspbuf = PB_WSP_BeginUpdate();
|
||||
MIX_PcmF32 pcm = MIX_MixAllTracks(scratch.arena, wspbuf.frames_count);
|
||||
PB_WSP_EndUpdate(&wspbuf, pcm);
|
||||
}
|
||||
EndScratch(scratch);
|
||||
WaitForSingleObject(g->event, INFINITE);
|
||||
}
|
||||
{
|
||||
PB_WSP_Buff wspbuf = PB_WSP_BeginUpdate();
|
||||
MIX_PcmF32 pcm = MIX_MixAllTracks(scratch.arena, wspbuf.frames_count);
|
||||
PB_WSP_EndUpdate(&wspbuf, pcm);
|
||||
}
|
||||
EndScratch(scratch);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,8 +2,8 @@
|
||||
//~ Win32 libs
|
||||
|
||||
#pragma warning(push, 0)
|
||||
# include <Audioclient.h>
|
||||
# include <mmdeviceapi.h>
|
||||
#include <Audioclient.h>
|
||||
#include <mmdeviceapi.h>
|
||||
#pragma warning(pop)
|
||||
|
||||
DEFINE_GUID(CLSID_MMDeviceEnumerator, 0xbcde0395, 0xe52f, 0x467c, 0x8e, 0x3d, 0xc4, 0x57, 0x92, 0x91, 0x69, 0x2e);
|
||||
@ -17,8 +17,8 @@ DEFINE_GUID(IID_IAudioRenderClient, 0xf294acfc, 0x3146, 0x4483, 0xa7, 0xbf, 0x
|
||||
|
||||
Struct(PB_WSP_Buff)
|
||||
{
|
||||
u32 frames_count;
|
||||
u8 *frames;
|
||||
u32 frames_count;
|
||||
u8 *frames;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -26,14 +26,14 @@ Struct(PB_WSP_Buff)
|
||||
|
||||
Struct(PB_WSP_SharedState)
|
||||
{
|
||||
Atomic32 shutdown;
|
||||
IAudioClient *client;
|
||||
HANDLE event;
|
||||
IAudioRenderClient *playback;
|
||||
WAVEFORMATEX *buffer_format;
|
||||
u32 buffer_frames;
|
||||
Fence shutdown_jobs_fence;
|
||||
u32 shutdown_jobs_count;
|
||||
Atomic32 shutdown;
|
||||
IAudioClient *client;
|
||||
HANDLE event;
|
||||
IAudioRenderClient *playback;
|
||||
WAVEFORMATEX *buffer_format;
|
||||
u32 buffer_frames;
|
||||
Fence shutdown_jobs_fence;
|
||||
u32 shutdown_jobs_count;
|
||||
} extern PB_WSP_shared_state;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
S_Ctx S = Zi;
|
||||
|
||||
Readonly S_ReadonlyCtx S_ro = {
|
||||
.nil_ent = {
|
||||
.xf = CompXformIdentity
|
||||
}
|
||||
.nil_ent = {
|
||||
.xf = CompXformIdentity
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -11,26 +11,26 @@ Readonly S_ReadonlyCtx S_ro = {
|
||||
|
||||
void S_Bootstrap(void)
|
||||
{
|
||||
/* Initialize shared state */
|
||||
for (u64 i = 0; i < countof(S.input_states); ++i)
|
||||
{
|
||||
S_InputState *input = &S.input_states[i];
|
||||
input->arena = AcquireArena(Gibi(64));
|
||||
}
|
||||
for (u64 i = 0; i < countof(S.output_states); ++i)
|
||||
{
|
||||
S_OutputState *output = &S.output_states[i];
|
||||
output->arena = AcquireArena(Gibi(64));
|
||||
}
|
||||
/* Initialize shared state */
|
||||
for (u64 i = 0; i < countof(S.input_states); ++i)
|
||||
{
|
||||
S_InputState *input = &S.input_states[i];
|
||||
input->arena = AcquireArena(Gibi(64));
|
||||
}
|
||||
for (u64 i = 0; i < countof(S.output_states); ++i)
|
||||
{
|
||||
S_OutputState *output = &S.output_states[i];
|
||||
output->arena = AcquireArena(Gibi(64));
|
||||
}
|
||||
|
||||
/* Dispatch sim wave */
|
||||
DispatchWave(Lit("Sim"), 1, S_TickForever, 0);
|
||||
/* Dispatch sim wave */
|
||||
DispatchWave(Lit("Sim"), 1, S_TickForever, 0);
|
||||
}
|
||||
|
||||
void S_Shutdown(void)
|
||||
{
|
||||
Atomic32Set(&S.shutdown, 1);
|
||||
YieldOnFence(&S.worker_completion_fence, S.workers_count);
|
||||
Atomic32Set(&S.shutdown, 1);
|
||||
YieldOnFence(&S.worker_completion_fence, S.workers_count);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -38,17 +38,17 @@ void S_Shutdown(void)
|
||||
|
||||
b32 S_IsKeyNil(S_Key key)
|
||||
{
|
||||
return key.v.hi == 0 && key.v.lo == 0;
|
||||
return key.v.hi == 0 && key.v.lo == 0;
|
||||
}
|
||||
|
||||
b32 S_IsEntNil(S_Ent *ent)
|
||||
{
|
||||
return ent == 0 || ent == &S_ro.nil_ent;
|
||||
return ent == 0 || ent == &S_ro.nil_ent;
|
||||
}
|
||||
|
||||
b32 S_MatchKey(S_Key a, S_Key b)
|
||||
{
|
||||
return a.v.hi == b.v.hi && a.v.lo == b.v.lo;
|
||||
return a.v.hi == b.v.hi && a.v.lo == b.v.lo;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -56,10 +56,10 @@ b32 S_MatchKey(S_Key a, S_Key b)
|
||||
|
||||
S_Key S_RandKey(void)
|
||||
{
|
||||
/* TODO: Don't use true randomness for entity keys. It's overkill & non-deterministic. */
|
||||
S_Key result = Zi;
|
||||
TrueRand(StringFromStruct(&result));
|
||||
return result;
|
||||
/* TODO: Don't use true randomness for entity keys. It's overkill & non-deterministic. */
|
||||
S_Key result = Zi;
|
||||
TrueRand(StringFromStruct(&result));
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -67,26 +67,26 @@ S_Key S_RandKey(void)
|
||||
|
||||
Rng2I32 S_UpdateTilesInPlaceFromPlacement(u8 *tiles, S_TilePlacement placement)
|
||||
{
|
||||
Rng2I32 dirty_rect = Zi;
|
||||
switch (placement.placement_kind)
|
||||
Rng2I32 dirty_rect = Zi;
|
||||
switch (placement.placement_kind)
|
||||
{
|
||||
case S_TilePlacementKind_Range:
|
||||
{
|
||||
case S_TilePlacementKind_Range:
|
||||
S_TileKind tile = placement.tile_kind;
|
||||
Rng2I32 range = placement.range;
|
||||
for (i32 tile_y = range.p0.y; tile_y < range.p1.y; ++tile_y)
|
||||
{
|
||||
for (i32 tile_x = range.p0.x; tile_x < range.p1.x; ++tile_x)
|
||||
{
|
||||
S_TileKind tile = placement.tile_kind;
|
||||
Rng2I32 range = placement.range;
|
||||
for (i32 tile_y = range.p0.y; tile_y < range.p1.y; ++tile_y)
|
||||
{
|
||||
for (i32 tile_x = range.p0.x; tile_x < range.p1.x; ++tile_x)
|
||||
{
|
||||
Vec2I32 tile_pos = VEC2I32(tile_x, tile_y);
|
||||
i32 tile_idx = S_TileIdxFromTilePos(tile_pos);
|
||||
tiles[tile_idx] = (u8)tile;
|
||||
}
|
||||
}
|
||||
dirty_rect = range;
|
||||
} break;
|
||||
}
|
||||
return dirty_rect;
|
||||
Vec2I32 tile_pos = VEC2I32(tile_x, tile_y);
|
||||
i32 tile_idx = S_TileIdxFromTilePos(tile_pos);
|
||||
tiles[tile_idx] = (u8)tile;
|
||||
}
|
||||
}
|
||||
dirty_rect = range;
|
||||
} break;
|
||||
}
|
||||
return dirty_rect;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -94,52 +94,52 @@ Rng2I32 S_UpdateTilesInPlaceFromPlacement(u8 *tiles, S_TilePlacement placement)
|
||||
|
||||
S_Shape S_ShapeFromDescEx(S_ShapeDesc desc)
|
||||
{
|
||||
desc.count = MaxI32(desc.count, 1);
|
||||
S_Shape result = Zi;
|
||||
desc.count = MaxI32(desc.count, 1);
|
||||
S_Shape result = Zi;
|
||||
{
|
||||
result.points_count = desc.count;
|
||||
CopyStructs(result.points, desc.points, result.points_count);
|
||||
Vec2 accum = Zi;
|
||||
for (i32 p_idx = 0; p_idx < result.points_count; ++p_idx)
|
||||
{
|
||||
result.points_count = desc.count;
|
||||
CopyStructs(result.points, desc.points, result.points_count);
|
||||
Vec2 accum = Zi;
|
||||
for (i32 p_idx = 0; p_idx < result.points_count; ++p_idx)
|
||||
{
|
||||
accum = AddVec2(accum, result.points[p_idx]);
|
||||
}
|
||||
result.centroid = DivVec2(accum, result.points_count);
|
||||
result.center_of_mass = result.centroid;
|
||||
result.radius = desc.radius;
|
||||
result.mass = desc.mass;
|
||||
accum = AddVec2(accum, result.points[p_idx]);
|
||||
}
|
||||
return result;
|
||||
result.centroid = DivVec2(accum, result.points_count);
|
||||
result.center_of_mass = result.centroid;
|
||||
result.radius = desc.radius;
|
||||
result.mass = desc.mass;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
S_Shape S_MulXformShape(Xform xf, S_Shape shape)
|
||||
{
|
||||
S_Shape result = shape;
|
||||
for (i32 i = 0; i < shape.points_count; ++i)
|
||||
{
|
||||
result.points[i] = MulXformV2(xf, shape.points[i]);
|
||||
}
|
||||
Vec2 scale = ScaleFromXform(xf);
|
||||
result.radius *= MaxF32(scale.x, scale.y);
|
||||
return result;
|
||||
S_Shape result = shape;
|
||||
for (i32 i = 0; i < shape.points_count; ++i)
|
||||
{
|
||||
result.points[i] = MulXformV2(xf, shape.points[i]);
|
||||
}
|
||||
Vec2 scale = ScaleFromXform(xf);
|
||||
result.radius *= MaxF32(scale.x, scale.y);
|
||||
return result;
|
||||
}
|
||||
|
||||
Vec2 S_SupportPointFromShape(S_Shape shape, Vec2 dir)
|
||||
{
|
||||
Vec2 result = Zi;
|
||||
f32 max_dot = -F32Infinity;
|
||||
for (i32 i = 0; i < shape.points_count; ++i)
|
||||
Vec2 result = Zi;
|
||||
f32 max_dot = -F32Infinity;
|
||||
for (i32 i = 0; i < shape.points_count; ++i)
|
||||
{
|
||||
Vec2 p = shape.points[i];
|
||||
f32 dot = DotVec2(p, dir);
|
||||
if (dot > max_dot)
|
||||
{
|
||||
Vec2 p = shape.points[i];
|
||||
f32 dot = DotVec2(p, dir);
|
||||
if (dot > max_dot)
|
||||
{
|
||||
max_dot = dot;
|
||||
result = p;
|
||||
}
|
||||
max_dot = dot;
|
||||
result = p;
|
||||
}
|
||||
result = AddVec2(result, MulVec2(dir, shape.radius));
|
||||
return result;
|
||||
}
|
||||
result = AddVec2(result, MulVec2(dir, shape.radius));
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -147,46 +147,46 @@ Vec2 S_SupportPointFromShape(S_Shape shape, Vec2 dir)
|
||||
|
||||
S_Lookup S_LookupFromWorld(Arena *arena, S_World *world)
|
||||
{
|
||||
S_Lookup lookup = Zi;
|
||||
S_Lookup lookup = Zi;
|
||||
|
||||
lookup.bins_count = 4096;
|
||||
lookup.bins = PushStructs(arena, S_LookupEntNode *, lookup.bins_count);
|
||||
for (i64 ent_idx = 0; ent_idx < world->ents_count; ++ent_idx)
|
||||
lookup.bins_count = 4096;
|
||||
lookup.bins = PushStructs(arena, S_LookupEntNode *, lookup.bins_count);
|
||||
for (i64 ent_idx = 0; ent_idx < world->ents_count; ++ent_idx)
|
||||
{
|
||||
S_Ent *ent = &world->ents[ent_idx];
|
||||
if (ent->active)
|
||||
{
|
||||
S_Ent *ent = &world->ents[ent_idx];
|
||||
if (ent->active)
|
||||
{
|
||||
S_Key key = ent->key;
|
||||
S_LookupEntNode *n = PushStruct(arena, S_LookupEntNode);
|
||||
n->ent = ent;
|
||||
S_LookupEntNode **bin = &lookup.bins[ent->key.v.lo % lookup.bins_count];
|
||||
SllStackPush(*bin, n);
|
||||
}
|
||||
S_Key key = ent->key;
|
||||
S_LookupEntNode *n = PushStruct(arena, S_LookupEntNode);
|
||||
n->ent = ent;
|
||||
S_LookupEntNode **bin = &lookup.bins[ent->key.v.lo % lookup.bins_count];
|
||||
SllStackPush(*bin, n);
|
||||
}
|
||||
}
|
||||
|
||||
return lookup;
|
||||
return lookup;
|
||||
}
|
||||
|
||||
S_Ent *S_EntFromKey(S_Lookup *lookup, S_Key key)
|
||||
{
|
||||
S_Ent *result = &S_ro.nil_ent;
|
||||
if (!S_IsKeyNil(key))
|
||||
S_Ent *result = &S_ro.nil_ent;
|
||||
if (!S_IsKeyNil(key))
|
||||
{
|
||||
i64 bins_count = lookup->bins_count;
|
||||
if (bins_count > 0)
|
||||
{
|
||||
i64 bins_count = lookup->bins_count;
|
||||
if (bins_count > 0)
|
||||
S_LookupEntNode *n = lookup->bins[key.v.lo % bins_count];
|
||||
for (; n; n = n->next)
|
||||
{
|
||||
if (S_MatchKey(n->ent->key, key))
|
||||
{
|
||||
S_LookupEntNode *n = lookup->bins[key.v.lo % bins_count];
|
||||
for (; n; n = n->next)
|
||||
{
|
||||
if (S_MatchKey(n->ent->key, key))
|
||||
{
|
||||
result = n->ent;
|
||||
break;
|
||||
}
|
||||
}
|
||||
result = n->ent;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -194,29 +194,29 @@ S_Ent *S_EntFromKey(S_Lookup *lookup, S_Key key)
|
||||
|
||||
S_Ent *S_FirstEnt(S_Iter *iter, S_World *world)
|
||||
{
|
||||
ZeroStruct(iter);
|
||||
iter->world = world;
|
||||
return S_NextEnt(iter);
|
||||
ZeroStruct(iter);
|
||||
iter->world = world;
|
||||
return S_NextEnt(iter);
|
||||
}
|
||||
|
||||
S_Ent *S_NextEnt(S_Iter *iter)
|
||||
{
|
||||
S_World *world = iter->world;
|
||||
S_Ent *result = &S_ro.nil_ent;
|
||||
S_World *world = iter->world;
|
||||
S_Ent *result = &S_ro.nil_ent;
|
||||
|
||||
i64 ent_idx = iter->cur_idx;
|
||||
for (; ent_idx < world->ents_count; ++ent_idx)
|
||||
i64 ent_idx = iter->cur_idx;
|
||||
for (; ent_idx < world->ents_count; ++ent_idx)
|
||||
{
|
||||
S_Ent *ent = &world->ents[ent_idx];
|
||||
if (ent->active)
|
||||
{
|
||||
S_Ent *ent = &world->ents[ent_idx];
|
||||
if (ent->active)
|
||||
{
|
||||
result = ent;
|
||||
break;
|
||||
}
|
||||
result = ent;
|
||||
break;
|
||||
}
|
||||
iter->cur_idx = ent_idx + 1;
|
||||
}
|
||||
iter->cur_idx = ent_idx + 1;
|
||||
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -224,15 +224,15 @@ S_Ent *S_NextEnt(S_Iter *iter)
|
||||
|
||||
S_World *S_WorldFromSnapshot(Arena *arena, S_Snapshot *snapshot)
|
||||
{
|
||||
S_World *world = PushStruct(arena, S_World);
|
||||
S_World *world = PushStruct(arena, S_World);
|
||||
|
||||
/* Copy ents */
|
||||
world->ents = PushStructsNoZero(arena, S_Ent, snapshot->ents_count);
|
||||
CopyStructs(world->ents, snapshot->ents, snapshot->ents_count);
|
||||
world->ents_count = snapshot->ents_count;
|
||||
world->tick = snapshot->tick;
|
||||
/* Copy ents */
|
||||
world->ents = PushStructsNoZero(arena, S_Ent, snapshot->ents_count);
|
||||
CopyStructs(world->ents, snapshot->ents, snapshot->ents_count);
|
||||
world->ents_count = snapshot->ents_count;
|
||||
world->tick = snapshot->tick;
|
||||
|
||||
return world;
|
||||
return world;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -240,20 +240,20 @@ S_World *S_WorldFromSnapshot(Arena *arena, S_Snapshot *snapshot)
|
||||
|
||||
MergesortCompareFuncDef(S_SortEntsByKeyCmp, arg_a, arg_b, _)
|
||||
{
|
||||
S_Ent *a = *(S_Ent **)arg_a;
|
||||
S_Ent *b = *(S_Ent **)arg_b;
|
||||
S_Key a_key = a->key;
|
||||
S_Key b_key = b->key;
|
||||
i32 result = 0;
|
||||
if (result == 0)
|
||||
{
|
||||
result = ((a_key.v.lo < b_key.v.lo) - (a_key.v.lo > b_key.v.lo));
|
||||
}
|
||||
if (result == 0)
|
||||
{
|
||||
result = ((a_key.v.hi < b_key.v.hi) - (a_key.v.hi > b_key.v.hi));
|
||||
}
|
||||
return result;
|
||||
S_Ent *a = *(S_Ent **)arg_a;
|
||||
S_Ent *b = *(S_Ent **)arg_b;
|
||||
S_Key a_key = a->key;
|
||||
S_Key b_key = b->key;
|
||||
i32 result = 0;
|
||||
if (result == 0)
|
||||
{
|
||||
result = ((a_key.v.lo < b_key.v.lo) - (a_key.v.lo > b_key.v.lo));
|
||||
}
|
||||
if (result == 0)
|
||||
{
|
||||
result = ((a_key.v.hi < b_key.v.hi) - (a_key.v.hi > b_key.v.hi));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -261,204 +261,204 @@ MergesortCompareFuncDef(S_SortEntsByKeyCmp, arg_a, arg_b, _)
|
||||
|
||||
void S_TickForever(WaveLaneCtx *lane)
|
||||
{
|
||||
Arena *frame_arena = AcquireArena(Gibi(64));
|
||||
Arena *perm = PermArena();
|
||||
Arena *frame_arena = AcquireArena(Gibi(64));
|
||||
Arena *perm = PermArena();
|
||||
|
||||
const i32 world_size = S_WorldSize;
|
||||
const i32 world_size = S_WorldSize;
|
||||
|
||||
//- World data
|
||||
Arena *ents_arena = AcquireArena(Gibi(64));
|
||||
S_World *world = PushStruct(perm, S_World);
|
||||
world->ents = ArenaFirst(ents_arena, S_Ent);
|
||||
i64 first_free_ent_num = 0;
|
||||
i64 sim_time_ns = 0;
|
||||
//- World data
|
||||
Arena *ents_arena = AcquireArena(Gibi(64));
|
||||
S_World *world = PushStruct(perm, S_World);
|
||||
world->ents = ArenaFirst(ents_arena, S_Ent);
|
||||
i64 first_free_ent_num = 0;
|
||||
i64 sim_time_ns = 0;
|
||||
|
||||
u8 *tiles = PushBytes(perm, world_size * world_size * 4, alignof(S_TileKind));
|
||||
u8 *tiles = PushBytes(perm, world_size * world_size * 4, alignof(S_TileKind));
|
||||
|
||||
//////////////////////////////
|
||||
//- Sim loop
|
||||
|
||||
b32 shutdown = 0;
|
||||
while (!shutdown)
|
||||
{
|
||||
ResetArena(frame_arena);
|
||||
S_Iter iter = Zi;
|
||||
S_Lookup lookup = Zi;
|
||||
|
||||
//////////////////////////////
|
||||
//- Sim loop
|
||||
//- Begin sim frame
|
||||
|
||||
b32 shutdown = 0;
|
||||
while (!shutdown)
|
||||
i64 frame_begin_ns = TimeNs();
|
||||
i64 sim_dt_ns = NsFromSeconds(1) / SIM_TICKS_PER_SECOND;
|
||||
f64 sim_dt = SecondsFromNs(sim_dt_ns);
|
||||
world->tick += 1;
|
||||
|
||||
lookup = S_LookupFromWorld(frame_arena, world);
|
||||
|
||||
//////////////////////////////
|
||||
//- Pop sim commands
|
||||
|
||||
S_InputState *input = 0;
|
||||
LockTicketMutex(&S.input_back_tm);
|
||||
{
|
||||
ResetArena(frame_arena);
|
||||
S_Iter iter = Zi;
|
||||
S_Lookup lookup = Zi;
|
||||
|
||||
//////////////////////////////
|
||||
//- Begin sim frame
|
||||
|
||||
i64 frame_begin_ns = TimeNs();
|
||||
i64 sim_dt_ns = NsFromSeconds(1) / SIM_TICKS_PER_SECOND;
|
||||
f64 sim_dt = SecondsFromNs(sim_dt_ns);
|
||||
world->tick += 1;
|
||||
|
||||
lookup = S_LookupFromWorld(frame_arena, world);
|
||||
|
||||
//////////////////////////////
|
||||
//- Pop sim commands
|
||||
|
||||
S_InputState *input = 0;
|
||||
LockTicketMutex(&S.input_back_tm);
|
||||
{
|
||||
input = &S.input_states[S.input_back_idx];
|
||||
++S.input_back_idx;
|
||||
if (S.input_back_idx >= countof(S.input_states))
|
||||
{
|
||||
S.input_back_idx = 0;
|
||||
}
|
||||
}
|
||||
UnlockTicketMutex(&S.input_back_tm);
|
||||
|
||||
//////////////////////////////
|
||||
//- Process world edit commands
|
||||
|
||||
u64 tile_placements_count = 0;
|
||||
for (S_CmdNode *cmd_node = input->first_cmd_node; cmd_node; cmd_node = cmd_node->next)
|
||||
{
|
||||
S_Cmd *cmd = &cmd_node->cmd;
|
||||
|
||||
/* Spawn entity */
|
||||
if (cmd->kind == S_CmdKind_Spawn)
|
||||
{
|
||||
S_Ent *src = &cmd->ent;
|
||||
S_Key key = src->key;
|
||||
if (!S_IsKeyNil(key))
|
||||
{
|
||||
S_Ent *dst = S_EntFromKey(&lookup, key);
|
||||
if (S_IsEntNil(dst))
|
||||
{
|
||||
if (first_free_ent_num > 0)
|
||||
{
|
||||
dst = &world->ents[first_free_ent_num - 1];
|
||||
first_free_ent_num = dst->next_free_ent_num;
|
||||
}
|
||||
else
|
||||
{
|
||||
dst = PushStructNoZero(ents_arena, S_Ent);
|
||||
}
|
||||
*dst = S_ro.nil_ent;
|
||||
dst->key = key;
|
||||
++world->ents_count;
|
||||
}
|
||||
*dst = *src;
|
||||
dst->local_shape.points_count = MaxI32(dst->local_shape.points_count, 1);
|
||||
|
||||
dst->active = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Place tiles */
|
||||
if (cmd->kind == S_CmdKind_Tile)
|
||||
{
|
||||
tile_placements_count += 1;
|
||||
S_TilePlacement placement = cmd->tile_placement;
|
||||
S_UpdateTilesInPlaceFromPlacement(tiles, placement);
|
||||
}
|
||||
}
|
||||
lookup = S_LookupFromWorld(frame_arena, world);
|
||||
|
||||
//////////////////////////////
|
||||
//- Update ent controls
|
||||
|
||||
for (S_CmdNode *cmd_node = input->first_cmd_node; cmd_node; cmd_node = cmd_node->next)
|
||||
{
|
||||
S_Cmd cmd = cmd_node->cmd;
|
||||
if (cmd.kind == S_CmdKind_Control)
|
||||
{
|
||||
S_Ent *target = S_EntFromKey(&lookup, cmd.target);
|
||||
if (target->active)
|
||||
{
|
||||
target->move = ClampVec2Len(cmd.move, 1);
|
||||
target->look = cmd.look;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- Apply control forces
|
||||
|
||||
for (S_Ent *ent = S_FirstEnt(&iter, world); ent->active; ent = S_NextEnt(&iter))
|
||||
{
|
||||
if (!IsVec2Zero(ent->move))
|
||||
{
|
||||
DEBUGBREAKABLE;
|
||||
}
|
||||
|
||||
Xform xf = ent->xf;
|
||||
if (!IsVec2Zero(ent->look))
|
||||
{
|
||||
xf = XformWithWorldRotation(xf, AngleFromVec2(ent->look));
|
||||
}
|
||||
xf.og = AddVec2(xf.og, MulVec2(ent->move, ent->move_speed));
|
||||
ent->xf = xf;
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- Publish sim state
|
||||
|
||||
/* TODO: Only copy active entities */
|
||||
LockTicketMutex(&S.output_back_tm);
|
||||
{
|
||||
S_OutputState *output = &S.output_states[S.output_back_idx];
|
||||
ResetArena(output->arena);
|
||||
S_SnapshotNode *snapshot_node = PushStruct(output->arena, S_SnapshotNode);
|
||||
S_Snapshot *snapshot = &snapshot_node->snapshot;
|
||||
SllQueuePush(output->first_snapshot_node, output->last_snapshot_node, snapshot_node);
|
||||
++output->snapshots_count;
|
||||
snapshot->ents_count = world->ents_count;
|
||||
snapshot->tick = world->tick;
|
||||
snapshot->ents = PushStructsNoZero(output->arena, S_Ent, snapshot->ents_count);
|
||||
for (i64 ent_idx = 0; ent_idx < snapshot->ents_count; ++ent_idx)
|
||||
{
|
||||
S_Ent *src = &world->ents[ent_idx];
|
||||
S_Ent *dst = &snapshot->ents[ent_idx];
|
||||
*dst = *src;
|
||||
}
|
||||
|
||||
/* Forward tile placements */
|
||||
snapshot->tile_placements_count = tile_placements_count;
|
||||
snapshot->tile_placements = PushStructs(output->arena, S_TilePlacement, tile_placements_count);
|
||||
{
|
||||
u64 tile_placement_idx = 0;
|
||||
for (S_CmdNode *cmd_node = input->first_cmd_node; cmd_node && tile_placement_idx < tile_placements_count; cmd_node = cmd_node->next)
|
||||
{
|
||||
S_Cmd *cmd = &cmd_node->cmd;
|
||||
if (cmd->kind == S_CmdKind_Tile)
|
||||
{
|
||||
S_TilePlacement *dst_placement = &snapshot->tile_placements[tile_placement_idx];
|
||||
*dst_placement = cmd->tile_placement;
|
||||
tile_placement_idx += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
UnlockTicketMutex(&S.output_back_tm);
|
||||
|
||||
//////////////////////////////
|
||||
//- End sim frame
|
||||
|
||||
/* Reset front input state */
|
||||
{
|
||||
Arena *arena = input->arena;
|
||||
ResetArena(arena);
|
||||
ZeroStruct(input);
|
||||
input->arena = arena;
|
||||
}
|
||||
|
||||
|
||||
i64 frame_end_ns = TimeNs();
|
||||
sim_time_ns += sim_dt_ns;
|
||||
|
||||
//////////////////////////////
|
||||
//- Sleep
|
||||
|
||||
if (!Atomic32Fetch(&S.shutdown))
|
||||
{
|
||||
i64 step_dt_ns = NsFromSeconds(1) / SIM_TICKS_PER_SECOND;
|
||||
P_SleepFrame(frame_begin_ns, step_dt_ns);
|
||||
}
|
||||
shutdown = Atomic32Fetch(&S.shutdown);
|
||||
input = &S.input_states[S.input_back_idx];
|
||||
++S.input_back_idx;
|
||||
if (S.input_back_idx >= countof(S.input_states))
|
||||
{
|
||||
S.input_back_idx = 0;
|
||||
}
|
||||
}
|
||||
UnlockTicketMutex(&S.input_back_tm);
|
||||
|
||||
//////////////////////////////
|
||||
//- Process world edit commands
|
||||
|
||||
u64 tile_placements_count = 0;
|
||||
for (S_CmdNode *cmd_node = input->first_cmd_node; cmd_node; cmd_node = cmd_node->next)
|
||||
{
|
||||
S_Cmd *cmd = &cmd_node->cmd;
|
||||
|
||||
/* Spawn entity */
|
||||
if (cmd->kind == S_CmdKind_Spawn)
|
||||
{
|
||||
S_Ent *src = &cmd->ent;
|
||||
S_Key key = src->key;
|
||||
if (!S_IsKeyNil(key))
|
||||
{
|
||||
S_Ent *dst = S_EntFromKey(&lookup, key);
|
||||
if (S_IsEntNil(dst))
|
||||
{
|
||||
if (first_free_ent_num > 0)
|
||||
{
|
||||
dst = &world->ents[first_free_ent_num - 1];
|
||||
first_free_ent_num = dst->next_free_ent_num;
|
||||
}
|
||||
else
|
||||
{
|
||||
dst = PushStructNoZero(ents_arena, S_Ent);
|
||||
}
|
||||
*dst = S_ro.nil_ent;
|
||||
dst->key = key;
|
||||
++world->ents_count;
|
||||
}
|
||||
*dst = *src;
|
||||
dst->local_shape.points_count = MaxI32(dst->local_shape.points_count, 1);
|
||||
|
||||
dst->active = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Place tiles */
|
||||
if (cmd->kind == S_CmdKind_Tile)
|
||||
{
|
||||
tile_placements_count += 1;
|
||||
S_TilePlacement placement = cmd->tile_placement;
|
||||
S_UpdateTilesInPlaceFromPlacement(tiles, placement);
|
||||
}
|
||||
}
|
||||
lookup = S_LookupFromWorld(frame_arena, world);
|
||||
|
||||
//////////////////////////////
|
||||
//- Update ent controls
|
||||
|
||||
for (S_CmdNode *cmd_node = input->first_cmd_node; cmd_node; cmd_node = cmd_node->next)
|
||||
{
|
||||
S_Cmd cmd = cmd_node->cmd;
|
||||
if (cmd.kind == S_CmdKind_Control)
|
||||
{
|
||||
S_Ent *target = S_EntFromKey(&lookup, cmd.target);
|
||||
if (target->active)
|
||||
{
|
||||
target->move = ClampVec2Len(cmd.move, 1);
|
||||
target->look = cmd.look;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- Apply control forces
|
||||
|
||||
for (S_Ent *ent = S_FirstEnt(&iter, world); ent->active; ent = S_NextEnt(&iter))
|
||||
{
|
||||
if (!IsVec2Zero(ent->move))
|
||||
{
|
||||
DEBUGBREAKABLE;
|
||||
}
|
||||
|
||||
Xform xf = ent->xf;
|
||||
if (!IsVec2Zero(ent->look))
|
||||
{
|
||||
xf = XformWithWorldRotation(xf, AngleFromVec2(ent->look));
|
||||
}
|
||||
xf.og = AddVec2(xf.og, MulVec2(ent->move, ent->move_speed));
|
||||
ent->xf = xf;
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- Publish sim state
|
||||
|
||||
/* TODO: Only copy active entities */
|
||||
LockTicketMutex(&S.output_back_tm);
|
||||
{
|
||||
S_OutputState *output = &S.output_states[S.output_back_idx];
|
||||
ResetArena(output->arena);
|
||||
S_SnapshotNode *snapshot_node = PushStruct(output->arena, S_SnapshotNode);
|
||||
S_Snapshot *snapshot = &snapshot_node->snapshot;
|
||||
SllQueuePush(output->first_snapshot_node, output->last_snapshot_node, snapshot_node);
|
||||
++output->snapshots_count;
|
||||
snapshot->ents_count = world->ents_count;
|
||||
snapshot->tick = world->tick;
|
||||
snapshot->ents = PushStructsNoZero(output->arena, S_Ent, snapshot->ents_count);
|
||||
for (i64 ent_idx = 0; ent_idx < snapshot->ents_count; ++ent_idx)
|
||||
{
|
||||
S_Ent *src = &world->ents[ent_idx];
|
||||
S_Ent *dst = &snapshot->ents[ent_idx];
|
||||
*dst = *src;
|
||||
}
|
||||
|
||||
/* Forward tile placements */
|
||||
snapshot->tile_placements_count = tile_placements_count;
|
||||
snapshot->tile_placements = PushStructs(output->arena, S_TilePlacement, tile_placements_count);
|
||||
{
|
||||
u64 tile_placement_idx = 0;
|
||||
for (S_CmdNode *cmd_node = input->first_cmd_node; cmd_node && tile_placement_idx < tile_placements_count; cmd_node = cmd_node->next)
|
||||
{
|
||||
S_Cmd *cmd = &cmd_node->cmd;
|
||||
if (cmd->kind == S_CmdKind_Tile)
|
||||
{
|
||||
S_TilePlacement *dst_placement = &snapshot->tile_placements[tile_placement_idx];
|
||||
*dst_placement = cmd->tile_placement;
|
||||
tile_placement_idx += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
UnlockTicketMutex(&S.output_back_tm);
|
||||
|
||||
//////////////////////////////
|
||||
//- End sim frame
|
||||
|
||||
/* Reset front input state */
|
||||
{
|
||||
Arena *arena = input->arena;
|
||||
ResetArena(arena);
|
||||
ZeroStruct(input);
|
||||
input->arena = arena;
|
||||
}
|
||||
|
||||
|
||||
i64 frame_end_ns = TimeNs();
|
||||
sim_time_ns += sim_dt_ns;
|
||||
|
||||
//////////////////////////////
|
||||
//- Sleep
|
||||
|
||||
if (!Atomic32Fetch(&S.shutdown))
|
||||
{
|
||||
i64 step_dt_ns = NsFromSeconds(1) / SIM_TICKS_PER_SECOND;
|
||||
P_SleepFrame(frame_begin_ns, step_dt_ns);
|
||||
}
|
||||
shutdown = Atomic32Fetch(&S.shutdown);
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
|
||||
Struct(S_Key)
|
||||
{
|
||||
U128 v;
|
||||
U128 v;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -13,21 +13,21 @@ Struct(S_Key)
|
||||
|
||||
Struct(S_ShapeDesc)
|
||||
{
|
||||
f32 radius;
|
||||
f32 mass;
|
||||
i32 count;
|
||||
Vec2 points[8];
|
||||
f32 radius;
|
||||
f32 mass;
|
||||
i32 count;
|
||||
Vec2 points[8];
|
||||
};
|
||||
|
||||
Struct(S_Shape)
|
||||
{
|
||||
f32 mass;
|
||||
Vec2 centroid;
|
||||
Vec2 center_of_mass;
|
||||
f32 mass;
|
||||
Vec2 centroid;
|
||||
Vec2 center_of_mass;
|
||||
|
||||
f32 radius;
|
||||
i32 points_count;
|
||||
Vec2 points[8];
|
||||
f32 radius;
|
||||
i32 points_count;
|
||||
Vec2 points[8];
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -37,28 +37,28 @@ Struct(S_Shape)
|
||||
|
||||
Struct(S_Ent)
|
||||
{
|
||||
//////////////////////////////
|
||||
//- Persistent data
|
||||
//////////////////////////////
|
||||
//- Persistent data
|
||||
|
||||
b32 active;
|
||||
S_Key key;
|
||||
b32 active;
|
||||
S_Key key;
|
||||
|
||||
//////////////////////////////
|
||||
//- Build data
|
||||
//////////////////////////////
|
||||
//- Build data
|
||||
|
||||
Xform xf;
|
||||
S_Shape local_shape;
|
||||
Xform xf;
|
||||
S_Shape local_shape;
|
||||
|
||||
f32 move_speed;
|
||||
Vec2 move;
|
||||
Vec2 look;
|
||||
f32 move_speed;
|
||||
Vec2 move;
|
||||
Vec2 look;
|
||||
|
||||
b32 has_weapon;
|
||||
b32 has_weapon;
|
||||
|
||||
//////////////////////////////
|
||||
//- Internal sim data
|
||||
//////////////////////////////
|
||||
//- Internal sim data
|
||||
|
||||
i64 next_free_ent_num;
|
||||
i64 next_free_ent_num;
|
||||
|
||||
};
|
||||
|
||||
@ -67,21 +67,21 @@ Struct(S_Ent)
|
||||
|
||||
Struct(S_EntArray)
|
||||
{
|
||||
u64 count;
|
||||
S_Ent *ents;
|
||||
u64 count;
|
||||
S_Ent *ents;
|
||||
};
|
||||
|
||||
Struct(S_EntListNode)
|
||||
{
|
||||
S_EntListNode *next;
|
||||
S_Ent ent;
|
||||
S_EntListNode *next;
|
||||
S_Ent ent;
|
||||
};
|
||||
|
||||
Struct(S_EntList)
|
||||
{
|
||||
S_EntListNode *first;
|
||||
S_EntListNode *last;
|
||||
u64 count;
|
||||
S_EntListNode *first;
|
||||
S_EntListNode *last;
|
||||
u64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -89,14 +89,14 @@ Struct(S_EntList)
|
||||
|
||||
Struct(S_LookupEntNode)
|
||||
{
|
||||
S_LookupEntNode *next;
|
||||
S_Ent *ent;
|
||||
S_LookupEntNode *next;
|
||||
S_Ent *ent;
|
||||
};
|
||||
|
||||
Struct(S_Lookup)
|
||||
{
|
||||
S_LookupEntNode **bins;
|
||||
i64 bins_count;
|
||||
S_LookupEntNode **bins;
|
||||
i64 bins_count;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -104,27 +104,27 @@ Struct(S_Lookup)
|
||||
|
||||
Struct(S_World)
|
||||
{
|
||||
i64 tick;
|
||||
i64 tick;
|
||||
|
||||
S_Ent *ents;
|
||||
i64 ents_count;
|
||||
S_Ent *ents;
|
||||
i64 ents_count;
|
||||
};
|
||||
|
||||
Struct(S_Snapshot)
|
||||
{
|
||||
i64 tick;
|
||||
i64 tick;
|
||||
|
||||
S_Ent *ents;
|
||||
i64 ents_count;
|
||||
S_Ent *ents;
|
||||
i64 ents_count;
|
||||
|
||||
S_TilePlacement *tile_placements;
|
||||
u64 tile_placements_count;
|
||||
S_TilePlacement *tile_placements;
|
||||
u64 tile_placements_count;
|
||||
};
|
||||
|
||||
Struct(S_SnapshotNode)
|
||||
{
|
||||
S_SnapshotNode *next;
|
||||
S_Snapshot snapshot;
|
||||
S_SnapshotNode *next;
|
||||
S_Snapshot snapshot;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -132,8 +132,8 @@ Struct(S_SnapshotNode)
|
||||
|
||||
Struct(S_Iter)
|
||||
{
|
||||
S_World *world;
|
||||
i64 cur_idx;
|
||||
S_World *world;
|
||||
i64 cur_idx;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -141,32 +141,32 @@ Struct(S_Iter)
|
||||
|
||||
Enum(S_CmdKind)
|
||||
{
|
||||
S_CmdKind_Nop,
|
||||
S_CmdKind_Tile,
|
||||
S_CmdKind_Spawn,
|
||||
S_CmdKind_Control,
|
||||
S_CmdKind_Nop,
|
||||
S_CmdKind_Tile,
|
||||
S_CmdKind_Spawn,
|
||||
S_CmdKind_Control,
|
||||
};
|
||||
|
||||
Struct(S_Cmd)
|
||||
{
|
||||
S_CmdKind kind;
|
||||
S_CmdKind kind;
|
||||
|
||||
/* Tiles */
|
||||
S_TilePlacement tile_placement;
|
||||
/* Tiles */
|
||||
S_TilePlacement tile_placement;
|
||||
|
||||
/* Spawn */
|
||||
S_Ent ent;
|
||||
/* Spawn */
|
||||
S_Ent ent;
|
||||
|
||||
/* Control */
|
||||
S_Key target;
|
||||
Vec2 move;
|
||||
Vec2 look;
|
||||
/* Control */
|
||||
S_Key target;
|
||||
Vec2 move;
|
||||
Vec2 look;
|
||||
};
|
||||
|
||||
Struct(S_CmdNode)
|
||||
{
|
||||
S_CmdNode *next;
|
||||
S_Cmd cmd;
|
||||
S_CmdNode *next;
|
||||
S_Cmd cmd;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -177,41 +177,41 @@ Struct(S_CmdNode)
|
||||
|
||||
Struct(S_InputState)
|
||||
{
|
||||
Arena *arena;
|
||||
S_CmdNode *first_cmd_node;
|
||||
S_CmdNode *last_cmd_node;
|
||||
u64 cmds_count;
|
||||
Arena *arena;
|
||||
S_CmdNode *first_cmd_node;
|
||||
S_CmdNode *last_cmd_node;
|
||||
u64 cmds_count;
|
||||
};
|
||||
|
||||
Struct(S_OutputState)
|
||||
{
|
||||
Arena *arena;
|
||||
S_SnapshotNode *first_snapshot_node;
|
||||
S_SnapshotNode *last_snapshot_node;
|
||||
u64 snapshots_count;
|
||||
Arena *arena;
|
||||
S_SnapshotNode *first_snapshot_node;
|
||||
S_SnapshotNode *last_snapshot_node;
|
||||
u64 snapshots_count;
|
||||
};
|
||||
|
||||
Struct(S_Ctx)
|
||||
{
|
||||
Atomic32 shutdown;
|
||||
Fence worker_completion_fence;
|
||||
i64 workers_count;
|
||||
Atomic32 shutdown;
|
||||
Fence worker_completion_fence;
|
||||
i64 workers_count;
|
||||
|
||||
//- Sim input
|
||||
TicketMutex input_back_tm;
|
||||
i32 input_back_idx;
|
||||
S_InputState input_states[S_InputStatesCount];
|
||||
//- Sim input
|
||||
TicketMutex input_back_tm;
|
||||
i32 input_back_idx;
|
||||
S_InputState input_states[S_InputStatesCount];
|
||||
|
||||
//- Sim output
|
||||
TicketMutex output_back_tm;
|
||||
i32 output_back_idx;
|
||||
S_OutputState output_states[S_OutputStatesCount];
|
||||
//- Sim output
|
||||
TicketMutex output_back_tm;
|
||||
i32 output_back_idx;
|
||||
S_OutputState output_states[S_OutputStatesCount];
|
||||
|
||||
};
|
||||
|
||||
Struct(S_ReadonlyCtx)
|
||||
{
|
||||
S_Ent nil_ent;
|
||||
S_Ent nil_ent;
|
||||
};
|
||||
|
||||
extern S_Ctx S;
|
||||
|
||||
@ -3,14 +3,14 @@
|
||||
|
||||
Vec2I32 S_TilePosFromWorldPos(Vec2 p)
|
||||
{
|
||||
Vec2I32 result;
|
||||
result.x = ClampI32((p.x + S_WorldSize / 2) * 2, 0, (S_WorldSize * 2) - 1);
|
||||
result.y = ClampI32((p.y + S_WorldSize / 2) * 2, 0, (S_WorldSize * 2) - 1);
|
||||
return result;
|
||||
Vec2I32 result;
|
||||
result.x = ClampI32((p.x + S_WorldSize / 2) * 2, 0, (S_WorldSize * 2) - 1);
|
||||
result.y = ClampI32((p.y + S_WorldSize / 2) * 2, 0, (S_WorldSize * 2) - 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
i32 S_TileIdxFromTilePos(Vec2I32 p)
|
||||
{
|
||||
i32 result = ClampI32(p.x + (p.y * S_WorldSize * 2), 0, S_WorldSize * S_WorldSize * 4);
|
||||
return result;
|
||||
i32 result = ClampI32(p.x + (p.y * S_WorldSize * 2), 0, S_WorldSize * S_WorldSize * 4);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -5,21 +5,21 @@
|
||||
|
||||
Enum(S_TileKind)
|
||||
{
|
||||
S_TileKind_None,
|
||||
S_TileKind_Floor,
|
||||
S_TileKind_Wall,
|
||||
S_TileKind_None,
|
||||
S_TileKind_Floor,
|
||||
S_TileKind_Wall,
|
||||
};
|
||||
|
||||
Enum(S_TilePlacementKind)
|
||||
{
|
||||
S_TilePlacementKind_Range
|
||||
S_TilePlacementKind_Range
|
||||
};
|
||||
|
||||
Struct(S_TilePlacement)
|
||||
{
|
||||
S_TilePlacementKind placement_kind;
|
||||
S_TileKind tile_kind;
|
||||
Rng2I32 range;
|
||||
S_TilePlacementKind placement_kind;
|
||||
S_TileKind tile_kind;
|
||||
Rng2I32 range;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,38 +1,38 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Command table
|
||||
|
||||
#define V_CmdsTableXMacro(X) \
|
||||
X(nop, NOP, V_CmdDescFlag_HideFromPalette, V_HOTKEY(0), ) \
|
||||
X(exit_program, Exit Program, V_CmdDescFlag_HideFromPalette, V_HOTKEY( Button_Escape ) ) \
|
||||
X(toggle_command_palette, Toggle Command Palette, V_CmdDescFlag_HideFromPalette, V_HOTKEY( Button_P, .ctrl = 1, .shift = 1 ), ) \
|
||||
X(zoom_in, Zoom In, V_CmdDescFlag_HideFromPalette, V_HOTKEY( Button_MWheelUp ), ) \
|
||||
X(zoom_out, Zoom Out, V_CmdDescFlag_HideFromPalette, V_HOTKEY( Button_MWheelDown ), ) \
|
||||
X(toggle_editor, Toggle Editor, V_CmdDescFlag_None, V_HOTKEY( Button_F1 ), ) \
|
||||
X(toggle_ui_debug, Toggle UI Debug, V_CmdDescFlag_None, V_HOTKEY( Button_F5 ), ) \
|
||||
X(toggle_console, Toggle Developer Console, V_CmdDescFlag_None, V_HOTKEY( Button_GraveAccent ), ) \
|
||||
X(toggle_fullscreen, Toggle Fullscreen Mode, V_CmdDescFlag_None, V_HOTKEY( Button_Enter, .alt = 1 ) ) \
|
||||
X(toggle_window_topmost, Toggle Window Topmost, V_CmdDescFlag_None, V_HOTKEY( Button_F4 ), ) \
|
||||
X(spawn, Spawn, V_CmdDescFlag_None, V_HOTKEY( Button_S, .ctrl = 1 ), ) \
|
||||
/* -------------------------------------------------------------------------------------------------------------------- */
|
||||
#define V_CmdsTableXMacro(X) \
|
||||
X(nop, NOP, V_CmdDescFlag_HideFromPalette, V_HOTKEY(0), ) \
|
||||
X(exit_program, Exit Program, V_CmdDescFlag_HideFromPalette, V_HOTKEY( Button_Escape ) ) \
|
||||
X(toggle_command_palette, Toggle Command Palette, V_CmdDescFlag_HideFromPalette, V_HOTKEY( Button_P, .ctrl = 1, .shift = 1 ), ) \
|
||||
X(zoom_in, Zoom In, V_CmdDescFlag_HideFromPalette, V_HOTKEY( Button_MWheelUp ), ) \
|
||||
X(zoom_out, Zoom Out, V_CmdDescFlag_HideFromPalette, V_HOTKEY( Button_MWheelDown ), ) \
|
||||
X(toggle_editor, Toggle Editor, V_CmdDescFlag_None, V_HOTKEY( Button_F1 ), ) \
|
||||
X(toggle_ui_debug, Toggle UI Debug, V_CmdDescFlag_None, V_HOTKEY( Button_F5 ), ) \
|
||||
X(toggle_console, Toggle Developer Console, V_CmdDescFlag_None, V_HOTKEY( Button_GraveAccent ), ) \
|
||||
X(toggle_fullscreen, Toggle Fullscreen Mode, V_CmdDescFlag_None, V_HOTKEY( Button_Enter, .alt = 1 ) ) \
|
||||
X(toggle_window_topmost, Toggle Window Topmost, V_CmdDescFlag_None, V_HOTKEY( Button_F4 ), ) \
|
||||
X(spawn, Spawn, V_CmdDescFlag_None, V_HOTKEY( Button_S, .ctrl = 1 ), ) \
|
||||
/* -------------------------------------------------------------------------------------------------------------------- */
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Theme types
|
||||
|
||||
Struct(V_WidgetTheme)
|
||||
{
|
||||
GC_FontKey font;
|
||||
f32 font_size;
|
||||
f32 window_title_font_size;
|
||||
GC_FontKey font;
|
||||
f32 font_size;
|
||||
f32 window_title_font_size;
|
||||
|
||||
Vec4 window_background_color;
|
||||
Vec4 window_border_color;
|
||||
Vec4 divider_color;
|
||||
f32 window_border;
|
||||
f32 window_padding;
|
||||
f32 window_width;
|
||||
Vec4 window_background_color;
|
||||
Vec4 window_border_color;
|
||||
Vec4 divider_color;
|
||||
f32 window_border;
|
||||
f32 window_padding;
|
||||
f32 window_width;
|
||||
|
||||
f32 text_padding_x;
|
||||
f32 text_padding_y;
|
||||
f32 text_padding_x;
|
||||
f32 text_padding_y;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -41,10 +41,10 @@ Struct(V_WidgetTheme)
|
||||
#define V_HOTKEY(_button, ...) { .button = _button, __VA_ARGS__ }
|
||||
Struct(V_Hotkey)
|
||||
{
|
||||
Button button;
|
||||
b32 ctrl;
|
||||
b32 alt;
|
||||
b32 shift;
|
||||
Button button;
|
||||
b32 ctrl;
|
||||
b32 alt;
|
||||
b32 shift;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -52,57 +52,57 @@ Struct(V_Hotkey)
|
||||
|
||||
Enum(V_CmdKind)
|
||||
{
|
||||
#define X(name, ...) V_CmdKind_##name,
|
||||
V_CmdsTableXMacro(X)
|
||||
#undef X
|
||||
#define X(name, ...) V_CmdKind_##name,
|
||||
V_CmdsTableXMacro(X)
|
||||
#undef X
|
||||
|
||||
V_CmdKind_Count,
|
||||
V_CmdKind_Count,
|
||||
};
|
||||
|
||||
Struct(V_Shortcut)
|
||||
{
|
||||
V_Shortcut *next_in_bin;
|
||||
V_Shortcut *prev_in_bin;
|
||||
u64 hotkey_hash;
|
||||
V_Hotkey hotkey;
|
||||
String cmd_name;
|
||||
V_Shortcut *next_in_bin;
|
||||
V_Shortcut *prev_in_bin;
|
||||
u64 hotkey_hash;
|
||||
V_Hotkey hotkey;
|
||||
String cmd_name;
|
||||
};
|
||||
|
||||
Struct(V_ShortcutBin)
|
||||
{
|
||||
V_Shortcut *first;
|
||||
V_Shortcut *last;
|
||||
V_Shortcut *first;
|
||||
V_Shortcut *last;
|
||||
};
|
||||
|
||||
Enum(V_CmdDescFlag)
|
||||
{
|
||||
V_CmdDescFlag_None = 0,
|
||||
V_CmdDescFlag_HideFromPalette = (1 << 0),
|
||||
V_CmdDescFlag_None = 0,
|
||||
V_CmdDescFlag_HideFromPalette = (1 << 0),
|
||||
};
|
||||
|
||||
Struct(V_CmdDesc)
|
||||
{
|
||||
String name;
|
||||
String display_name;
|
||||
V_CmdDescFlag flags;
|
||||
V_Hotkey default_hotkeys[8];
|
||||
String name;
|
||||
String display_name;
|
||||
V_CmdDescFlag flags;
|
||||
V_Hotkey default_hotkeys[8];
|
||||
};
|
||||
|
||||
Struct(V_Cmd)
|
||||
{
|
||||
String name;
|
||||
String name;
|
||||
};
|
||||
|
||||
Struct(V_CmdNode)
|
||||
{
|
||||
V_CmdNode *next;
|
||||
V_Cmd cmd;
|
||||
V_CmdNode *next;
|
||||
V_Cmd cmd;
|
||||
};
|
||||
|
||||
Global Readonly V_CmdDesc V_cmd_descs[V_CmdKind_Count] = {
|
||||
#define X(_name, _display_name, _flags, ...) { .name = CompLit(#_name), .display_name = CompLit(#_display_name), .flags = _flags, .default_hotkeys = { __VA_ARGS__ } },
|
||||
V_CmdsTableXMacro(X)
|
||||
#undef X
|
||||
#define X(_name, _display_name, _flags, ...) { .name = CompLit(#_name), .display_name = CompLit(#_display_name), .flags = _flags, .default_hotkeys = { __VA_ARGS__ } },
|
||||
V_CmdsTableXMacro(X)
|
||||
#undef X
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -110,38 +110,38 @@ Global Readonly V_CmdDesc V_cmd_descs[V_CmdKind_Count] = {
|
||||
|
||||
Struct(V_CommandsWidgetItemReport)
|
||||
{
|
||||
b32 pressed;
|
||||
b32 hotkey_changed;
|
||||
UI_Report ui_report;
|
||||
V_Hotkey new_hotkeys[8];
|
||||
b32 pressed;
|
||||
b32 hotkey_changed;
|
||||
UI_Report ui_report;
|
||||
V_Hotkey new_hotkeys[8];
|
||||
};
|
||||
|
||||
Struct(V_CommandsWidgetItemDesc)
|
||||
{
|
||||
String display_name;
|
||||
V_Hotkey hotkeys[8];
|
||||
String display_name;
|
||||
V_Hotkey hotkeys[8];
|
||||
};
|
||||
|
||||
Struct(V_CommandsWidgetItem)
|
||||
{
|
||||
V_CommandsWidgetItem *next;
|
||||
UI_Key key;
|
||||
V_CommandsWidgetItemDesc desc;
|
||||
V_CommandsWidgetItem *next;
|
||||
UI_Key key;
|
||||
V_CommandsWidgetItemDesc desc;
|
||||
};
|
||||
|
||||
Struct(V_CommandsWidget)
|
||||
{
|
||||
/* Persistent state */
|
||||
Vec2 pos;
|
||||
/* Persistent state */
|
||||
Vec2 pos;
|
||||
|
||||
/* Per-build state */
|
||||
struct
|
||||
{
|
||||
UI_Checkpoint cp;
|
||||
V_CommandsWidgetItem *first_item;
|
||||
V_CommandsWidgetItem *last_item;
|
||||
u64 num_items;
|
||||
} build;
|
||||
/* Per-build state */
|
||||
struct
|
||||
{
|
||||
UI_Checkpoint cp;
|
||||
V_CommandsWidgetItem *first_item;
|
||||
V_CommandsWidgetItem *last_item;
|
||||
u64 num_items;
|
||||
} build;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -151,38 +151,38 @@ Struct(V_CommandsWidget)
|
||||
|
||||
Struct(V_Space)
|
||||
{
|
||||
V_Space *parent;
|
||||
V_Space *next;
|
||||
V_Space *prev;
|
||||
V_Space *first;
|
||||
V_Space *last;
|
||||
V_Space *parent;
|
||||
V_Space *next;
|
||||
V_Space *prev;
|
||||
V_Space *first;
|
||||
V_Space *last;
|
||||
|
||||
i64 panels_count;
|
||||
struct V_Panel *first_panel;
|
||||
struct V_Panel *last_panel;
|
||||
i64 panels_count;
|
||||
struct V_Panel *first_panel;
|
||||
struct V_Panel *last_panel;
|
||||
|
||||
Axis axis;
|
||||
Axis axis;
|
||||
};
|
||||
|
||||
Struct(V_Panel)
|
||||
{
|
||||
V_Space *space;
|
||||
V_Panel *next_in_space;
|
||||
V_Panel *prev_in_space;
|
||||
V_Space *space;
|
||||
V_Panel *next_in_space;
|
||||
V_Panel *prev_in_space;
|
||||
|
||||
i64 active_window_idx;
|
||||
i64 windows_count;
|
||||
struct V_Window *first_window;
|
||||
struct V_Window *last_window;
|
||||
i64 active_window_idx;
|
||||
i64 windows_count;
|
||||
struct V_Window *first_window;
|
||||
struct V_Window *last_window;
|
||||
};
|
||||
|
||||
Struct(V_Window)
|
||||
{
|
||||
V_Panel *panel;
|
||||
V_Window *next_in_panel;
|
||||
V_Window *prev_in_panel;
|
||||
V_Panel *panel;
|
||||
V_Window *next_in_panel;
|
||||
V_Window *prev_in_panel;
|
||||
|
||||
b32 is_tile_window;
|
||||
b32 is_tile_window;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -190,97 +190,97 @@ Struct(V_Window)
|
||||
|
||||
Enum(V_EditMode)
|
||||
{
|
||||
V_EditMode_Tile,
|
||||
V_EditMode_Tile,
|
||||
};
|
||||
|
||||
Struct(V_Frame)
|
||||
{
|
||||
Arena *arena;
|
||||
Arena *dverts_arena;
|
||||
Arena *dvert_idxs_arena;
|
||||
G_ArenaHandle gpu_arena;
|
||||
G_CommandListHandle cl;
|
||||
Arena *arena;
|
||||
Arena *dverts_arena;
|
||||
Arena *dvert_idxs_arena;
|
||||
G_ArenaHandle gpu_arena;
|
||||
G_CommandListHandle cl;
|
||||
|
||||
i64 tick;
|
||||
i64 time_ns;
|
||||
i64 dt_ns;
|
||||
f64 dt;
|
||||
i64 tick;
|
||||
i64 time_ns;
|
||||
i64 dt_ns;
|
||||
f64 dt;
|
||||
|
||||
Button held_buttons[Button_Count];
|
||||
V_CommandsWidget commands_widget;
|
||||
Button held_buttons[Button_Count];
|
||||
V_CommandsWidget commands_widget;
|
||||
|
||||
String window_restore;
|
||||
i32 zooms;
|
||||
String window_restore;
|
||||
i32 zooms;
|
||||
|
||||
Vec2I32 ui_dims;
|
||||
Vec2I32 draw_dims;
|
||||
Vec2I32 ui_dims;
|
||||
Vec2I32 draw_dims;
|
||||
|
||||
/* Modes */
|
||||
b32 is_editing;
|
||||
b32 ui_debug;
|
||||
b32 show_command_palette;
|
||||
b32 show_console;
|
||||
/* Modes */
|
||||
b32 is_editing;
|
||||
b32 ui_debug;
|
||||
b32 show_command_palette;
|
||||
b32 show_console;
|
||||
|
||||
/* Editor state */
|
||||
V_EditMode edit_mode;
|
||||
S_TileKind equipped_tile;
|
||||
/* Editor state */
|
||||
V_EditMode edit_mode;
|
||||
S_TileKind equipped_tile;
|
||||
|
||||
/* Editor */
|
||||
b32 is_selecting;
|
||||
b32 is_panning;
|
||||
V_SelectionMode selection_mode;
|
||||
Vec2 world_selection_start;
|
||||
Vec2 edit_camera_pos;
|
||||
f32 edit_camera_zoom;
|
||||
/* Editor */
|
||||
b32 is_selecting;
|
||||
b32 is_panning;
|
||||
V_SelectionMode selection_mode;
|
||||
Vec2 world_selection_start;
|
||||
Vec2 edit_camera_pos;
|
||||
f32 edit_camera_zoom;
|
||||
|
||||
/* Camera */
|
||||
Vec2 camera_pos;
|
||||
f32 camera_zoom;
|
||||
/* Camera */
|
||||
Vec2 camera_pos;
|
||||
f32 camera_zoom;
|
||||
|
||||
/* World <-> ui */
|
||||
Xform world_to_ui_xf;
|
||||
Xform ui_to_world_xf;
|
||||
/* World <-> ui */
|
||||
Xform world_to_ui_xf;
|
||||
Xform ui_to_world_xf;
|
||||
|
||||
/* Draw <-> ui */
|
||||
Xform draw_to_ui_xf;
|
||||
Xform ui_to_draw_xf;
|
||||
/* Draw <-> ui */
|
||||
Xform draw_to_ui_xf;
|
||||
Xform ui_to_draw_xf;
|
||||
|
||||
/* World <-> draw */
|
||||
Xform world_to_draw_xf;
|
||||
Xform draw_to_world_xf;
|
||||
/* World <-> draw */
|
||||
Xform world_to_draw_xf;
|
||||
Xform draw_to_world_xf;
|
||||
|
||||
/* Cursors */
|
||||
Vec2 ui_cursor;
|
||||
Vec2 draw_cursor;
|
||||
Vec2 world_cursor;
|
||||
Rng2 ui_selection;
|
||||
Rng2 draw_selection;
|
||||
Rng2 world_selection;
|
||||
/* Cursors */
|
||||
Vec2 ui_cursor;
|
||||
Vec2 draw_cursor;
|
||||
Vec2 world_cursor;
|
||||
Rng2 ui_selection;
|
||||
Rng2 draw_selection;
|
||||
Rng2 world_selection;
|
||||
|
||||
/* Control */
|
||||
Vec2 move;
|
||||
Vec2 look;
|
||||
/* Control */
|
||||
Vec2 move;
|
||||
Vec2 look;
|
||||
|
||||
/* Sim cmds */
|
||||
u64 sim_cmds_count;
|
||||
S_CmdNode *first_sim_cmd_node;
|
||||
S_CmdNode *last_sim_cmd_node;
|
||||
/* Sim cmds */
|
||||
u64 sim_cmds_count;
|
||||
S_CmdNode *first_sim_cmd_node;
|
||||
S_CmdNode *last_sim_cmd_node;
|
||||
};
|
||||
|
||||
Struct(V_Ctx)
|
||||
{
|
||||
Arena *world_arena;
|
||||
S_World *world;
|
||||
S_Lookup lookup;
|
||||
S_Key player_key;
|
||||
Arena *world_arena;
|
||||
S_World *world;
|
||||
S_Lookup lookup;
|
||||
S_Key player_key;
|
||||
|
||||
V_Space *root_space;
|
||||
V_Space *root_space;
|
||||
|
||||
Atomic32 shutdown;
|
||||
Fence shutdown_complete;
|
||||
Atomic32 shutdown;
|
||||
Fence shutdown_complete;
|
||||
|
||||
u64 current_frame_idx;
|
||||
V_Frame frames[2];
|
||||
u64 current_frame_idx;
|
||||
V_Frame frames[2];
|
||||
};
|
||||
|
||||
extern V_Ctx V;
|
||||
|
||||
@ -3,121 +3,121 @@
|
||||
|
||||
void V_DrawPoly(Arena *verts_arena, Arena *idxs_arena, Vec2Array points, Vec4 color_lin, V_DrawFlag flags)
|
||||
{
|
||||
if (flags & V_DrawFlag_Line)
|
||||
if (flags & V_DrawFlag_Line)
|
||||
{
|
||||
i32 verts_count = points.count;
|
||||
if (verts_count >= 2)
|
||||
{
|
||||
i32 verts_count = points.count;
|
||||
if (verts_count >= 2)
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
{
|
||||
f32 half_thickness = 1;
|
||||
i32 lines_count = verts_count == 2 ? 1 : verts_count;
|
||||
i32 line_verts_count = lines_count * 4;
|
||||
i32 idx_count = lines_count * 6;
|
||||
i32 idx_offset = ArenaCount(verts_arena, V_DVert);
|
||||
|
||||
/* Push dverts */
|
||||
V_DVert *dverts = PushStructsNoZero(verts_arena, V_DVert, line_verts_count);
|
||||
for (i32 line_idx = 0; line_idx < lines_count; ++line_idx)
|
||||
{
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
{
|
||||
f32 half_thickness = 1;
|
||||
i32 lines_count = verts_count == 2 ? 1 : verts_count;
|
||||
i32 line_verts_count = lines_count * 4;
|
||||
i32 idx_count = lines_count * 6;
|
||||
i32 idx_offset = ArenaCount(verts_arena, V_DVert);
|
||||
i32 a_idx = line_idx;
|
||||
i32 b_idx = line_idx + 1;
|
||||
if (b_idx >= lines_count)
|
||||
{
|
||||
b_idx = 0;
|
||||
}
|
||||
|
||||
/* Push dverts */
|
||||
V_DVert *dverts = PushStructsNoZero(verts_arena, V_DVert, line_verts_count);
|
||||
for (i32 line_idx = 0; line_idx < lines_count; ++line_idx)
|
||||
{
|
||||
i32 a_idx = line_idx;
|
||||
i32 b_idx = line_idx + 1;
|
||||
if (b_idx >= lines_count)
|
||||
{
|
||||
b_idx = 0;
|
||||
}
|
||||
Vec2 a = points.points[a_idx];
|
||||
Vec2 b = points.points[b_idx];
|
||||
|
||||
Vec2 a = points.points[a_idx];
|
||||
Vec2 b = points.points[b_idx];
|
||||
Vec2 a_to_b = SubVec2(b, a);
|
||||
Vec2 perp = Vec2WithLen(PerpVec2(a_to_b), half_thickness);
|
||||
|
||||
Vec2 a_to_b = SubVec2(b, a);
|
||||
Vec2 perp = Vec2WithLen(PerpVec2(a_to_b), half_thickness);
|
||||
Vec2 p0 = AddVec2(a, perp);
|
||||
Vec2 p1 = SubVec2(a, perp);
|
||||
Vec2 p2 = SubVec2(b, perp);
|
||||
Vec2 p3 = AddVec2(b, perp);
|
||||
|
||||
Vec2 p0 = AddVec2(a, perp);
|
||||
Vec2 p1 = SubVec2(a, perp);
|
||||
Vec2 p2 = SubVec2(b, perp);
|
||||
Vec2 p3 = AddVec2(b, perp);
|
||||
|
||||
i32 offset = line_idx * 4;
|
||||
dverts[offset + 0] = (V_DVert) { .pos = p0, .color_lin = color_lin };
|
||||
dverts[offset + 1] = (V_DVert) { .pos = p1, .color_lin = color_lin };
|
||||
dverts[offset + 2] = (V_DVert) { .pos = p2, .color_lin = color_lin };
|
||||
dverts[offset + 3] = (V_DVert) { .pos = p3, .color_lin = color_lin };
|
||||
}
|
||||
|
||||
/* Generate indices */
|
||||
i32 *indices = PushStructsNoZero(idxs_arena, i32, idx_count);
|
||||
for (i32 line_idx = 0; line_idx < lines_count; ++line_idx)
|
||||
{
|
||||
i32 indices_offset = line_idx * 6;
|
||||
i32 vert_idx_offset = idx_offset + (line_idx * 4);
|
||||
indices[indices_offset + 0] = vert_idx_offset + 0;
|
||||
indices[indices_offset + 1] = vert_idx_offset + 1;
|
||||
indices[indices_offset + 2] = vert_idx_offset + 2;
|
||||
indices[indices_offset + 3] = vert_idx_offset + 0;
|
||||
indices[indices_offset + 4] = vert_idx_offset + 2;
|
||||
indices[indices_offset + 5] = vert_idx_offset + 3;
|
||||
}
|
||||
}
|
||||
EndScratch(scratch);
|
||||
i32 offset = line_idx * 4;
|
||||
dverts[offset + 0] = (V_DVert) { .pos = p0, .color_lin = color_lin };
|
||||
dverts[offset + 1] = (V_DVert) { .pos = p1, .color_lin = color_lin };
|
||||
dverts[offset + 2] = (V_DVert) { .pos = p2, .color_lin = color_lin };
|
||||
dverts[offset + 3] = (V_DVert) { .pos = p3, .color_lin = color_lin };
|
||||
}
|
||||
|
||||
/* Generate indices */
|
||||
i32 *indices = PushStructsNoZero(idxs_arena, i32, idx_count);
|
||||
for (i32 line_idx = 0; line_idx < lines_count; ++line_idx)
|
||||
{
|
||||
i32 indices_offset = line_idx * 6;
|
||||
i32 vert_idx_offset = idx_offset + (line_idx * 4);
|
||||
indices[indices_offset + 0] = vert_idx_offset + 0;
|
||||
indices[indices_offset + 1] = vert_idx_offset + 1;
|
||||
indices[indices_offset + 2] = vert_idx_offset + 2;
|
||||
indices[indices_offset + 3] = vert_idx_offset + 0;
|
||||
indices[indices_offset + 4] = vert_idx_offset + 2;
|
||||
indices[indices_offset + 5] = vert_idx_offset + 3;
|
||||
}
|
||||
}
|
||||
EndScratch(scratch);
|
||||
}
|
||||
else
|
||||
}
|
||||
else
|
||||
{
|
||||
i32 verts_count = points.count;
|
||||
if (verts_count >= 3)
|
||||
{
|
||||
i32 verts_count = points.count;
|
||||
if (verts_count >= 3)
|
||||
{
|
||||
i32 idx_offset = ArenaCount(verts_arena, V_DVert);
|
||||
i32 tris_count = verts_count - 2;
|
||||
i32 idx_count = tris_count * 3;
|
||||
i32 idx_offset = ArenaCount(verts_arena, V_DVert);
|
||||
i32 tris_count = verts_count - 2;
|
||||
i32 idx_count = tris_count * 3;
|
||||
|
||||
/* Push dverts */
|
||||
V_DVert *dverts = PushStructsNoZero(verts_arena, V_DVert, verts_count);
|
||||
for (i32 point_idx = 0; point_idx < (i32)points.count; ++point_idx)
|
||||
{
|
||||
V_DVert *dvert = &dverts[point_idx];
|
||||
dvert->pos = points.points[point_idx];
|
||||
dvert->color_lin = color_lin;
|
||||
}
|
||||
/* Push dverts */
|
||||
V_DVert *dverts = PushStructsNoZero(verts_arena, V_DVert, verts_count);
|
||||
for (i32 point_idx = 0; point_idx < (i32)points.count; ++point_idx)
|
||||
{
|
||||
V_DVert *dvert = &dverts[point_idx];
|
||||
dvert->pos = points.points[point_idx];
|
||||
dvert->color_lin = color_lin;
|
||||
}
|
||||
|
||||
/* Generate indices in a fan pattern */
|
||||
i32 *indices = PushStructsNoZero(idxs_arena, i32, idx_count);
|
||||
for (i32 i = 0; i < tris_count; ++i)
|
||||
{
|
||||
i32 tri_offset = i * 3;
|
||||
indices[tri_offset + 0] = idx_offset;
|
||||
indices[tri_offset + 1] = idx_offset + i + 1;
|
||||
indices[tri_offset + 2] = idx_offset + i + 2;
|
||||
}
|
||||
}
|
||||
/* Generate indices in a fan pattern */
|
||||
i32 *indices = PushStructsNoZero(idxs_arena, i32, idx_count);
|
||||
for (i32 i = 0; i < tris_count; ++i)
|
||||
{
|
||||
i32 tri_offset = i * 3;
|
||||
indices[tri_offset + 0] = idx_offset;
|
||||
indices[tri_offset + 1] = idx_offset + i + 1;
|
||||
indices[tri_offset + 2] = idx_offset + i + 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void V_DrawShape(Arena *verts_arena, Arena *idxs_arena, S_Shape shape, Vec4 color_lin, i32 detail, V_DrawFlag flags)
|
||||
{
|
||||
if (shape.radius == 0)
|
||||
if (shape.radius == 0)
|
||||
{
|
||||
Vec2Array draw_points = Zi;
|
||||
draw_points.points = shape.points;
|
||||
draw_points.count = shape.points_count;
|
||||
V_DrawPoly(verts_arena, idxs_arena, draw_points, color_lin, flags);
|
||||
}
|
||||
else
|
||||
{
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
{
|
||||
Vec2Array draw_points = Zi;
|
||||
draw_points.points = shape.points;
|
||||
draw_points.count = shape.points_count;
|
||||
V_DrawPoly(verts_arena, idxs_arena, draw_points, color_lin, flags);
|
||||
}
|
||||
else
|
||||
{
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
{
|
||||
Vec2Array draw_points = Zi;
|
||||
draw_points.points = PushStructsNoZero(scratch.arena, Vec2, detail);
|
||||
draw_points.count = detail;
|
||||
for (i32 i = 0; i < detail; ++i)
|
||||
{
|
||||
f32 rad = ((f32)i / (f32)detail) * Tau;
|
||||
Vec2 dir = Vec2FromAngle(rad);
|
||||
Vec2 sp = S_SupportPointFromShape(shape, dir);
|
||||
draw_points.points[i] = sp;
|
||||
}
|
||||
V_DrawPoly(verts_arena, idxs_arena, draw_points, color_lin, flags);
|
||||
}
|
||||
EndScratch(scratch);
|
||||
Vec2Array draw_points = Zi;
|
||||
draw_points.points = PushStructsNoZero(scratch.arena, Vec2, detail);
|
||||
draw_points.count = detail;
|
||||
for (i32 i = 0; i < detail; ++i)
|
||||
{
|
||||
f32 rad = ((f32)i / (f32)detail) * Tau;
|
||||
Vec2 dir = Vec2FromAngle(rad);
|
||||
Vec2 sp = S_SupportPointFromShape(shape, dir);
|
||||
draw_points.points[i] = sp;
|
||||
}
|
||||
V_DrawPoly(verts_arena, idxs_arena, draw_points, color_lin, flags);
|
||||
}
|
||||
EndScratch(scratch);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,8 +3,8 @@
|
||||
|
||||
Enum(V_DrawFlag)
|
||||
{
|
||||
V_DrawFlag_None = 0,
|
||||
V_DrawFlag_Line = (1 << 0),
|
||||
V_DrawFlag_None = 0,
|
||||
V_DrawFlag_Line = (1 << 0),
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
@ -5,36 +5,36 @@ G_DeclConstant(G_StructuredBufferRef, V_ShaderConst_Params, 0);
|
||||
|
||||
Enum(V_SelectionMode)
|
||||
{
|
||||
V_SelectionMode_None,
|
||||
V_SelectionMode_Tile,
|
||||
V_SelectionMode_None,
|
||||
V_SelectionMode_Tile,
|
||||
};
|
||||
|
||||
Struct(V_DParams)
|
||||
{
|
||||
Vec2I32 target_size;
|
||||
G_Texture2DRef target_ro;
|
||||
G_RWTexture2DRef target_rw;
|
||||
Vec2I32 target_size;
|
||||
G_Texture2DRef target_ro;
|
||||
G_RWTexture2DRef target_rw;
|
||||
|
||||
Xform world_to_draw_xf;
|
||||
Xform draw_to_world_xf;
|
||||
Xform world_to_draw_xf;
|
||||
Xform draw_to_world_xf;
|
||||
|
||||
V_SelectionMode selection_mode;
|
||||
S_TileKind equipped_tile;
|
||||
V_SelectionMode selection_mode;
|
||||
S_TileKind equipped_tile;
|
||||
|
||||
Vec2 ui_cursor;
|
||||
Vec2 draw_cursor;
|
||||
Vec2 world_cursor;
|
||||
Rng2 ui_selection;
|
||||
Rng2 draw_selection;
|
||||
Rng2 world_selection;
|
||||
Vec2 ui_cursor;
|
||||
Vec2 draw_cursor;
|
||||
Vec2 world_cursor;
|
||||
Rng2 ui_selection;
|
||||
Rng2 draw_selection;
|
||||
Rng2 world_selection;
|
||||
|
||||
Vec2 camera_pos;
|
||||
f32 camera_zoom;
|
||||
Vec2 camera_pos;
|
||||
f32 camera_zoom;
|
||||
|
||||
f32 world_size;
|
||||
G_Texture2DRef tiles;
|
||||
G_StructuredBufferRef quads;
|
||||
G_StructuredBufferRef shape_verts;
|
||||
f32 world_size;
|
||||
G_Texture2DRef tiles;
|
||||
G_StructuredBufferRef quads;
|
||||
G_StructuredBufferRef shape_verts;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -47,13 +47,13 @@ Struct(V_DParams)
|
||||
|
||||
Enum(V_DQuadFlag)
|
||||
{
|
||||
V_DQuadFlag_None = 0,
|
||||
V_DQuadFlag_DrawGrid = (1 << 0),
|
||||
V_DQuadFlag_None = 0,
|
||||
V_DQuadFlag_DrawGrid = (1 << 0),
|
||||
};
|
||||
|
||||
Struct(V_DQuad)
|
||||
{
|
||||
V_DQuadFlag flags;
|
||||
V_DQuadFlag flags;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -61,6 +61,6 @@ Struct(V_DQuad)
|
||||
|
||||
Struct(V_DVert)
|
||||
{
|
||||
Vec2 pos;
|
||||
Vec4 color_lin;
|
||||
Vec2 pos;
|
||||
Vec4 color_lin;
|
||||
};
|
||||
|
||||
@ -3,124 +3,124 @@
|
||||
|
||||
ComputeShader2D(V_BackdropCS, 8, 8)
|
||||
{
|
||||
V_DParams params = G_Dereference<V_DParams>(V_ShaderConst_Params)[0];
|
||||
RWTexture2D<Vec4> target = G_Dereference<Vec4>(params.target_rw);
|
||||
Texture2D<uint> tiles = G_Dereference<uint>(params.tiles);
|
||||
V_DParams params = G_Dereference<V_DParams>(V_ShaderConst_Params)[0];
|
||||
RWTexture2D<Vec4> target = G_Dereference<Vec4>(params.target_rw);
|
||||
Texture2D<uint> tiles = G_Dereference<uint>(params.tiles);
|
||||
|
||||
const Vec4 background_color_a = LinearFromSrgb(Vec4(0.30, 0.30, 0.30, 1));
|
||||
const Vec4 background_color_b = LinearFromSrgb(Vec4(0.15, 0.15, 0.15, 1));
|
||||
const Vec4 grid_color = LinearFromSrgb(Vec4(0, 0, 0, 1));
|
||||
const Vec4 x_axis_color = LinearFromSrgb(Vec4(0.75, 0, 0, 1));
|
||||
const Vec4 y_axis_color = LinearFromSrgb(Vec4(0, 0.75, 0, 1));
|
||||
const Vec4 bounds_color = LinearFromSrgb(Vec4(0.75, 0.75, 0, 1));
|
||||
const Vec4 background_color_a = LinearFromSrgb(Vec4(0.30, 0.30, 0.30, 1));
|
||||
const Vec4 background_color_b = LinearFromSrgb(Vec4(0.15, 0.15, 0.15, 1));
|
||||
const Vec4 grid_color = LinearFromSrgb(Vec4(0, 0, 0, 1));
|
||||
const Vec4 x_axis_color = LinearFromSrgb(Vec4(0.75, 0, 0, 1));
|
||||
const Vec4 y_axis_color = LinearFromSrgb(Vec4(0, 0.75, 0, 1));
|
||||
const Vec4 bounds_color = LinearFromSrgb(Vec4(0.75, 0.75, 0, 1));
|
||||
|
||||
Vec2 screen_pos = Vec2(SV_DispatchThreadID) + Vec2(0.5, 0.5);
|
||||
if (screen_pos.x < params.target_size.x && screen_pos.y < params.target_size.y)
|
||||
Vec2 screen_pos = Vec2(SV_DispatchThreadID) + Vec2(0.5, 0.5);
|
||||
if (screen_pos.x < params.target_size.x && screen_pos.y < params.target_size.y)
|
||||
{
|
||||
Vec4 result = Vec4(0.025, 0.025, 0.025, 1);
|
||||
Vec2 world_pos = mul(params.draw_to_world_xf, Vec3(screen_pos, 1));
|
||||
Vec2I32 tile_pos = S_TilePosFromWorldPos(world_pos);
|
||||
|
||||
f32 half_thickness = 1;
|
||||
f32 half_bounds_size = params.world_size * 0.5;
|
||||
Vec2 bounds_screen_p0 = mul(params.world_to_draw_xf, Vec3(-half_bounds_size, -half_bounds_size, 1));
|
||||
Vec2 bounds_screen_p1 = mul(params.world_to_draw_xf, Vec3(half_bounds_size, half_bounds_size, 1));
|
||||
b32 is_in_bounds = screen_pos.x > (bounds_screen_p0.x - half_thickness) &&
|
||||
screen_pos.y > (bounds_screen_p0.y - half_thickness) &&
|
||||
screen_pos.x < (bounds_screen_p1.x + half_thickness) &&
|
||||
screen_pos.y < (bounds_screen_p1.y + half_thickness);
|
||||
if (is_in_bounds)
|
||||
{
|
||||
Vec4 result = Vec4(0.025, 0.025, 0.025, 1);
|
||||
Vec2 world_pos = mul(params.draw_to_world_xf, Vec3(screen_pos, 1));
|
||||
Vec2I32 tile_pos = S_TilePosFromWorldPos(world_pos);
|
||||
|
||||
f32 half_thickness = 1;
|
||||
f32 half_bounds_size = params.world_size * 0.5;
|
||||
Vec2 bounds_screen_p0 = mul(params.world_to_draw_xf, Vec3(-half_bounds_size, -half_bounds_size, 1));
|
||||
Vec2 bounds_screen_p1 = mul(params.world_to_draw_xf, Vec3(half_bounds_size, half_bounds_size, 1));
|
||||
b32 is_in_bounds = screen_pos.x > (bounds_screen_p0.x - half_thickness) &&
|
||||
screen_pos.y > (bounds_screen_p0.y - half_thickness) &&
|
||||
screen_pos.x < (bounds_screen_p1.x + half_thickness) &&
|
||||
screen_pos.y < (bounds_screen_p1.y + half_thickness);
|
||||
if (is_in_bounds)
|
||||
/* Grid checker */
|
||||
{
|
||||
i32 color_idx = 0;
|
||||
Vec4 colors[2] = {
|
||||
background_color_a,
|
||||
background_color_b
|
||||
};
|
||||
const f32 checker_size = 0.5;
|
||||
Vec2 world_pos_modded = fmod(abs(world_pos), Vec2(checker_size * 2, checker_size * 2));
|
||||
if (world_pos_modded.x < checker_size)
|
||||
{
|
||||
/* Grid checker */
|
||||
{
|
||||
i32 color_idx = 0;
|
||||
Vec4 colors[2] = {
|
||||
background_color_a,
|
||||
background_color_b
|
||||
};
|
||||
const f32 checker_size = 0.5;
|
||||
Vec2 world_pos_modded = fmod(abs(world_pos), Vec2(checker_size * 2, checker_size * 2));
|
||||
if (world_pos_modded.x < checker_size)
|
||||
{
|
||||
color_idx = !color_idx;
|
||||
}
|
||||
if (world_pos_modded.y < checker_size)
|
||||
{
|
||||
color_idx = !color_idx;
|
||||
}
|
||||
if (world_pos.x < 0)
|
||||
{
|
||||
color_idx = !color_idx;
|
||||
}
|
||||
if (world_pos.y < 0)
|
||||
{
|
||||
color_idx = !color_idx;
|
||||
}
|
||||
result = colors[color_idx];
|
||||
}
|
||||
/* Grid outline */
|
||||
{
|
||||
Vec2 grid_screen_p0 = mul(params.world_to_draw_xf, Vec3(floor(world_pos), 1));
|
||||
Vec2 grid_screen_p1 = mul(params.world_to_draw_xf, Vec3(ceil(world_pos), 1));
|
||||
f32 grid_dist = 100000;
|
||||
grid_dist = min(grid_dist, abs(screen_pos.x - grid_screen_p0.x));
|
||||
grid_dist = min(grid_dist, abs(screen_pos.x - grid_screen_p1.x));
|
||||
grid_dist = min(grid_dist, abs(screen_pos.y - grid_screen_p0.y));
|
||||
grid_dist = min(grid_dist, abs(screen_pos.y - grid_screen_p1.y));
|
||||
if (grid_dist <= half_thickness)
|
||||
{
|
||||
result = grid_color;
|
||||
}
|
||||
}
|
||||
/* Tile */
|
||||
{
|
||||
S_TileKind tile = (S_TileKind)tiles.Load(Vec3I32(tile_pos, 0));
|
||||
switch (tile)
|
||||
{
|
||||
default: break;
|
||||
|
||||
case S_TileKind_Floor:
|
||||
{
|
||||
result = Color_Blue;
|
||||
} break;
|
||||
|
||||
case S_TileKind_Wall:
|
||||
{
|
||||
result = Color_Red;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
/* Axis */
|
||||
{
|
||||
Vec2 zero_screen = mul(params.world_to_draw_xf, Vec3(0, 0, 1));
|
||||
f32 x_dist = abs(screen_pos.x - zero_screen.x);
|
||||
f32 y_dist = abs(screen_pos.y - zero_screen.y);
|
||||
if (y_dist <= half_thickness)
|
||||
{
|
||||
result = x_axis_color;
|
||||
}
|
||||
else if (x_dist <= half_thickness)
|
||||
{
|
||||
result = y_axis_color;
|
||||
}
|
||||
}
|
||||
/* World bounds */
|
||||
{
|
||||
f32 bounds_dist = 100000;
|
||||
bounds_dist = min(bounds_dist, abs(screen_pos.x - bounds_screen_p0.x));
|
||||
bounds_dist = min(bounds_dist, abs(screen_pos.x - bounds_screen_p1.x));
|
||||
bounds_dist = min(bounds_dist, abs(screen_pos.y - bounds_screen_p0.y));
|
||||
bounds_dist = min(bounds_dist, abs(screen_pos.y - bounds_screen_p1.y));
|
||||
if (bounds_dist <= half_thickness)
|
||||
{
|
||||
result = bounds_color;
|
||||
}
|
||||
}
|
||||
color_idx = !color_idx;
|
||||
}
|
||||
if (world_pos_modded.y < checker_size)
|
||||
{
|
||||
color_idx = !color_idx;
|
||||
}
|
||||
if (world_pos.x < 0)
|
||||
{
|
||||
color_idx = !color_idx;
|
||||
}
|
||||
if (world_pos.y < 0)
|
||||
{
|
||||
color_idx = !color_idx;
|
||||
}
|
||||
result = colors[color_idx];
|
||||
}
|
||||
/* Grid outline */
|
||||
{
|
||||
Vec2 grid_screen_p0 = mul(params.world_to_draw_xf, Vec3(floor(world_pos), 1));
|
||||
Vec2 grid_screen_p1 = mul(params.world_to_draw_xf, Vec3(ceil(world_pos), 1));
|
||||
f32 grid_dist = 100000;
|
||||
grid_dist = min(grid_dist, abs(screen_pos.x - grid_screen_p0.x));
|
||||
grid_dist = min(grid_dist, abs(screen_pos.x - grid_screen_p1.x));
|
||||
grid_dist = min(grid_dist, abs(screen_pos.y - grid_screen_p0.y));
|
||||
grid_dist = min(grid_dist, abs(screen_pos.y - grid_screen_p1.y));
|
||||
if (grid_dist <= half_thickness)
|
||||
{
|
||||
result = grid_color;
|
||||
}
|
||||
}
|
||||
/* Tile */
|
||||
{
|
||||
S_TileKind tile = (S_TileKind)tiles.Load(Vec3I32(tile_pos, 0));
|
||||
switch (tile)
|
||||
{
|
||||
default: break;
|
||||
|
||||
case S_TileKind_Floor:
|
||||
{
|
||||
result = Color_Blue;
|
||||
} break;
|
||||
|
||||
target[trunc(screen_pos)] = result;
|
||||
case S_TileKind_Wall:
|
||||
{
|
||||
result = Color_Red;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
/* Axis */
|
||||
{
|
||||
Vec2 zero_screen = mul(params.world_to_draw_xf, Vec3(0, 0, 1));
|
||||
f32 x_dist = abs(screen_pos.x - zero_screen.x);
|
||||
f32 y_dist = abs(screen_pos.y - zero_screen.y);
|
||||
if (y_dist <= half_thickness)
|
||||
{
|
||||
result = x_axis_color;
|
||||
}
|
||||
else if (x_dist <= half_thickness)
|
||||
{
|
||||
result = y_axis_color;
|
||||
}
|
||||
}
|
||||
/* World bounds */
|
||||
{
|
||||
f32 bounds_dist = 100000;
|
||||
bounds_dist = min(bounds_dist, abs(screen_pos.x - bounds_screen_p0.x));
|
||||
bounds_dist = min(bounds_dist, abs(screen_pos.x - bounds_screen_p1.x));
|
||||
bounds_dist = min(bounds_dist, abs(screen_pos.y - bounds_screen_p0.y));
|
||||
bounds_dist = min(bounds_dist, abs(screen_pos.y - bounds_screen_p1.y));
|
||||
if (bounds_dist <= half_thickness)
|
||||
{
|
||||
result = bounds_color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
target[trunc(screen_pos)] = result;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -131,21 +131,21 @@ ComputeShader2D(V_BackdropCS, 8, 8)
|
||||
|
||||
VertexShader(V_DQuadVS, V_DQuadPSInput)
|
||||
{
|
||||
V_DParams params = G_Dereference<V_DParams>(V_ShaderConst_Params)[0];
|
||||
StructuredBuffer<V_DQuad> quads = G_Dereference<V_DQuad>(params.quads);
|
||||
RWTexture2D<Vec4> target = G_Dereference<Vec4>(params.target_rw);
|
||||
V_DParams params = G_Dereference<V_DParams>(V_ShaderConst_Params)[0];
|
||||
StructuredBuffer<V_DQuad> quads = G_Dereference<V_DQuad>(params.quads);
|
||||
RWTexture2D<Vec4> target = G_Dereference<Vec4>(params.target_rw);
|
||||
|
||||
V_DQuad quad = quads[SV_InstanceID];
|
||||
V_DQuad quad = quads[SV_InstanceID];
|
||||
|
||||
Vec2 rect_uv = RectUvFromVertexId(SV_VertexID);
|
||||
// Vec2 tex_uv = lerp(quad.tex_uv0, quad.tex_uv1, rect_uv);
|
||||
// Vec2 target_pos = lerp(quad.p0, quad.p1, rect_uv);
|
||||
Vec2 target_pos = 0;
|
||||
Vec2 rect_uv = RectUvFromVertexId(SV_VertexID);
|
||||
// Vec2 tex_uv = lerp(quad.tex_uv0, quad.tex_uv1, rect_uv);
|
||||
// Vec2 target_pos = lerp(quad.p0, quad.p1, rect_uv);
|
||||
Vec2 target_pos = 0;
|
||||
|
||||
V_DQuadPSInput result;
|
||||
result.sv_position = Vec4(NdcFromPos(target_pos, countof(target)).xy, 0, 1);
|
||||
result.quad_idx = SV_InstanceID;
|
||||
return result;
|
||||
V_DQuadPSInput result;
|
||||
result.sv_position = Vec4(NdcFromPos(target_pos, countof(target)).xy, 0, 1);
|
||||
result.quad_idx = SV_InstanceID;
|
||||
return result;
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
@ -153,15 +153,15 @@ VertexShader(V_DQuadVS, V_DQuadPSInput)
|
||||
|
||||
PixelShader(V_DQuadPS, V_DQuadPSOutput, V_DQuadPSInput input)
|
||||
{
|
||||
V_DParams params = G_Dereference<V_DParams>(V_ShaderConst_Params)[0];
|
||||
StructuredBuffer<V_DQuad> quads = G_Dereference<V_DQuad>(params.quads);
|
||||
V_DQuad quad = quads[input.quad_idx];
|
||||
V_DParams params = G_Dereference<V_DParams>(V_ShaderConst_Params)[0];
|
||||
StructuredBuffer<V_DQuad> quads = G_Dereference<V_DQuad>(params.quads);
|
||||
V_DQuad quad = quads[input.quad_idx];
|
||||
|
||||
Vec4 final_color = 0;
|
||||
Vec4 final_color = 0;
|
||||
|
||||
V_DQuadPSOutput output;
|
||||
output.sv_target0 = final_color;
|
||||
return output;
|
||||
V_DQuadPSOutput output;
|
||||
output.sv_target0 = final_color;
|
||||
return output;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -172,18 +172,18 @@ PixelShader(V_DQuadPS, V_DQuadPSOutput, V_DQuadPSInput input)
|
||||
|
||||
VertexShader(V_DVertVS, V_DVertPSInput)
|
||||
{
|
||||
V_DParams params = G_Dereference<V_DParams>(V_ShaderConst_Params)[0];
|
||||
StructuredBuffer<V_DVert> verts = G_Dereference<V_DVert>(params.shape_verts);
|
||||
RWTexture2D<Vec4> target = G_Dereference<Vec4>(params.target_rw);
|
||||
V_DParams params = G_Dereference<V_DParams>(V_ShaderConst_Params)[0];
|
||||
StructuredBuffer<V_DVert> verts = G_Dereference<V_DVert>(params.shape_verts);
|
||||
RWTexture2D<Vec4> target = G_Dereference<Vec4>(params.target_rw);
|
||||
|
||||
V_DVert vert = verts[SV_VertexID];
|
||||
V_DVert vert = verts[SV_VertexID];
|
||||
|
||||
Vec2 target_pos = vert.pos;
|
||||
Vec2 target_pos = vert.pos;
|
||||
|
||||
V_DVertPSInput result;
|
||||
result.sv_position = Vec4(NdcFromPos(target_pos, countof(target)).xy, 0, 1);
|
||||
result.color_lin = vert.color_lin;
|
||||
return result;
|
||||
V_DVertPSInput result;
|
||||
result.sv_position = Vec4(NdcFromPos(target_pos, countof(target)).xy, 0, 1);
|
||||
result.color_lin = vert.color_lin;
|
||||
return result;
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
@ -191,9 +191,9 @@ VertexShader(V_DVertVS, V_DVertPSInput)
|
||||
|
||||
PixelShader(V_DVertPS, V_DVertPSOutput, V_DVertPSInput input)
|
||||
{
|
||||
V_DVertPSOutput output;
|
||||
output.sv_target0 = input.color_lin;
|
||||
return output;
|
||||
V_DVertPSOutput output;
|
||||
output.sv_target0 = input.color_lin;
|
||||
return output;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -204,10 +204,10 @@ PixelShader(V_DVertPS, V_DVertPSOutput, V_DVertPSInput input)
|
||||
|
||||
VertexShader(V_OverlayVS, V_OverlayPSInput)
|
||||
{
|
||||
Vec2 uv = RectUvFromVertexId(SV_VertexID);
|
||||
V_OverlayPSInput result;
|
||||
result.sv_position = Vec4(NdcFromUv(uv).xy, 0, 1);
|
||||
return result;
|
||||
Vec2 uv = RectUvFromVertexId(SV_VertexID);
|
||||
V_OverlayPSInput result;
|
||||
result.sv_position = Vec4(NdcFromUv(uv).xy, 0, 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
@ -215,59 +215,59 @@ VertexShader(V_OverlayVS, V_OverlayPSInput)
|
||||
|
||||
PixelShader(V_OverlayPS, V_OverlayPSOutput, V_OverlayPSInput input)
|
||||
{
|
||||
V_DParams params = G_Dereference<V_DParams>(V_ShaderConst_Params)[0];
|
||||
Texture2D<uint> tiles = G_Dereference<uint>(params.tiles);
|
||||
Vec2 screen_pos = input.sv_position.xy;
|
||||
Vec4 result = 0;
|
||||
V_DParams params = G_Dereference<V_DParams>(V_ShaderConst_Params)[0];
|
||||
Texture2D<uint> tiles = G_Dereference<uint>(params.tiles);
|
||||
Vec2 screen_pos = input.sv_position.xy;
|
||||
Vec4 result = 0;
|
||||
|
||||
Vec2 world_pos = mul(params.draw_to_world_xf, Vec3(screen_pos, 1));
|
||||
Vec2I32 tile_pos = S_TilePosFromWorldPos(world_pos);
|
||||
S_TileKind equipped_tile = params.equipped_tile;
|
||||
Vec2 world_pos = mul(params.draw_to_world_xf, Vec3(screen_pos, 1));
|
||||
Vec2I32 tile_pos = S_TilePosFromWorldPos(world_pos);
|
||||
S_TileKind equipped_tile = params.equipped_tile;
|
||||
|
||||
f32 half_thickness = 1;
|
||||
Vec4 border_color = LinearFromSrgb(Vec4(1, 1, 1, 1));
|
||||
// Vec4 inner_color = LinearFromSrgb(Vec4(0.4, 0.4, 0.4, 0.25));
|
||||
f32 half_thickness = 1;
|
||||
Vec4 border_color = LinearFromSrgb(Vec4(1, 1, 1, 1));
|
||||
// Vec4 inner_color = LinearFromSrgb(Vec4(0.4, 0.4, 0.4, 0.25));
|
||||
|
||||
Vec4 inner_color = LinearFromSrgb(Vec4(0.4, 0.8, 0.4, 0.6));
|
||||
Vec4 inner_color = LinearFromSrgb(Vec4(0.4, 0.8, 0.4, 0.6));
|
||||
|
||||
Rng2 screen_selection = params.draw_selection;
|
||||
Rng2 world_selection = params.world_selection;
|
||||
Rng2 screen_selection = params.draw_selection;
|
||||
Rng2 world_selection = params.world_selection;
|
||||
|
||||
Rng2I32 tile_selection;
|
||||
tile_selection.p0 = S_TilePosFromWorldPos(world_selection.p0);
|
||||
tile_selection.p1 = S_TilePosFromWorldPos(world_selection.p1);
|
||||
Rng2I32 tile_selection;
|
||||
tile_selection.p0 = S_TilePosFromWorldPos(world_selection.p0);
|
||||
tile_selection.p1 = S_TilePosFromWorldPos(world_selection.p1);
|
||||
|
||||
if (params.selection_mode == V_SelectionMode_Tile)
|
||||
if (params.selection_mode == V_SelectionMode_Tile)
|
||||
{
|
||||
f32 dist = 100000000;
|
||||
dist = min(dist, screen_pos.x - screen_selection.p0.x);
|
||||
dist = min(dist, screen_pos.y - screen_selection.p0.y);
|
||||
dist = min(dist, screen_selection.p1.x - screen_pos.x);
|
||||
dist = min(dist, screen_selection.p1.y - screen_pos.y);
|
||||
dist = -dist;
|
||||
|
||||
// if (dist >= -half_thickness && dist <= half_thickness)
|
||||
// {
|
||||
// result = border_color;
|
||||
// }
|
||||
// else
|
||||
{
|
||||
f32 dist = 100000000;
|
||||
dist = min(dist, screen_pos.x - screen_selection.p0.x);
|
||||
dist = min(dist, screen_pos.y - screen_selection.p0.y);
|
||||
dist = min(dist, screen_selection.p1.x - screen_pos.x);
|
||||
dist = min(dist, screen_selection.p1.y - screen_pos.y);
|
||||
dist = -dist;
|
||||
|
||||
// if (dist >= -half_thickness && dist <= half_thickness)
|
||||
// {
|
||||
// result = border_color;
|
||||
// }
|
||||
// else
|
||||
{
|
||||
if (world_pos.x > -(S_WorldSize / 2) &&
|
||||
world_pos.y > -(S_WorldSize / 2) &&
|
||||
world_pos.x < (S_WorldSize / 2) &&
|
||||
world_pos.y < (S_WorldSize / 2) &&
|
||||
tile_pos.x >= tile_selection.p0.x &&
|
||||
tile_pos.x <= tile_selection.p1.x &&
|
||||
tile_pos.y >= tile_selection.p0.y &&
|
||||
tile_pos.y <= tile_selection.p1.y)
|
||||
{
|
||||
result = inner_color;
|
||||
}
|
||||
}
|
||||
if (world_pos.x > -(S_WorldSize / 2) &&
|
||||
world_pos.y > -(S_WorldSize / 2) &&
|
||||
world_pos.x < (S_WorldSize / 2) &&
|
||||
world_pos.y < (S_WorldSize / 2) &&
|
||||
tile_pos.x >= tile_selection.p0.x &&
|
||||
tile_pos.x <= tile_selection.p1.x &&
|
||||
tile_pos.y >= tile_selection.p0.y &&
|
||||
tile_pos.y <= tile_selection.p1.y)
|
||||
{
|
||||
result = inner_color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
V_OverlayPSOutput output;
|
||||
output.sv_target0 = result;
|
||||
return output;
|
||||
V_OverlayPSOutput output;
|
||||
output.sv_target0 = result;
|
||||
return output;
|
||||
}
|
||||
|
||||
@ -3,13 +3,13 @@
|
||||
|
||||
Struct(V_DQuadPSInput)
|
||||
{
|
||||
Semantic(Vec4, sv_position);
|
||||
Semantic(nointerpolation u32, quad_idx);
|
||||
Semantic(Vec4, sv_position);
|
||||
Semantic(nointerpolation u32, quad_idx);
|
||||
};
|
||||
|
||||
Struct(V_DQuadPSOutput)
|
||||
{
|
||||
Semantic(Vec4, sv_target0);
|
||||
Semantic(Vec4, sv_target0);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -18,13 +18,13 @@ Struct(V_DQuadPSOutput)
|
||||
Struct(V_DVertPSInput)
|
||||
{
|
||||
|
||||
Semantic(Vec4, sv_position);
|
||||
Semantic(Vec4, color_lin);
|
||||
Semantic(Vec4, sv_position);
|
||||
Semantic(Vec4, color_lin);
|
||||
};
|
||||
|
||||
Struct(V_DVertPSOutput)
|
||||
{
|
||||
Semantic(Vec4, sv_target0);
|
||||
Semantic(Vec4, sv_target0);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -33,12 +33,12 @@ Struct(V_DVertPSOutput)
|
||||
Struct(V_OverlayPSInput)
|
||||
{
|
||||
|
||||
Semantic(Vec4, sv_position);
|
||||
Semantic(Vec4, sv_position);
|
||||
};
|
||||
|
||||
Struct(V_OverlayPSOutput)
|
||||
{
|
||||
Semantic(Vec4, sv_target0);
|
||||
Semantic(Vec4, sv_target0);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
5551
src/pp_old/pp.c
5551
src/pp_old/pp.c
File diff suppressed because it is too large
Load Diff
372
src/pp_old/pp.h
372
src/pp_old/pp.h
@ -4,98 +4,98 @@
|
||||
//- Bind kinds
|
||||
Enum(PP_BindKind)
|
||||
{
|
||||
PP_BindKind_None,
|
||||
PP_BindKind_None,
|
||||
|
||||
PP_BindKind_MoveUp,
|
||||
PP_BindKind_MoveDown,
|
||||
PP_BindKind_MoveLeft,
|
||||
PP_BindKind_MoveRight,
|
||||
PP_BindKind_Walk,
|
||||
PP_BindKind_Fire,
|
||||
PP_BindKind_AltFire,
|
||||
PP_BindKind_MoveUp,
|
||||
PP_BindKind_MoveDown,
|
||||
PP_BindKind_MoveLeft,
|
||||
PP_BindKind_MoveRight,
|
||||
PP_BindKind_Walk,
|
||||
PP_BindKind_Fire,
|
||||
PP_BindKind_AltFire,
|
||||
|
||||
PP_BindKind_TestTile,
|
||||
PP_BindKind_DebugClear,
|
||||
PP_BindKind_DebugSpawn1,
|
||||
PP_BindKind_DebugSpawn2,
|
||||
PP_BindKind_DebugSpawn3,
|
||||
PP_BindKind_DebugSpawn4,
|
||||
PP_BindKind_DebugWalls,
|
||||
PP_BindKind_DebugFollow,
|
||||
PP_BindKind_DebugDraw,
|
||||
PP_BindKind_DebugConsole,
|
||||
PP_BindKind_DebugCamera,
|
||||
PP_BindKind_DebugLister,
|
||||
PP_BindKind_DebugPause,
|
||||
PP_BindKind_DebugStep,
|
||||
PP_BindKind_DebugDrag,
|
||||
PP_BindKind_DebugDelete,
|
||||
PP_BindKind_DebugTeleport,
|
||||
PP_BindKind_DebugExplode,
|
||||
PP_BindKind_DebugToggleTopmost,
|
||||
PP_BindKind_DebugUi,
|
||||
PP_BindKind_FullscreenMod,
|
||||
PP_BindKind_Fullscreen,
|
||||
PP_BindKind_ZoomIn,
|
||||
PP_BindKind_ZoomOut,
|
||||
PP_BindKind_Pan,
|
||||
PP_BindKind_TestTile,
|
||||
PP_BindKind_DebugClear,
|
||||
PP_BindKind_DebugSpawn1,
|
||||
PP_BindKind_DebugSpawn2,
|
||||
PP_BindKind_DebugSpawn3,
|
||||
PP_BindKind_DebugSpawn4,
|
||||
PP_BindKind_DebugWalls,
|
||||
PP_BindKind_DebugFollow,
|
||||
PP_BindKind_DebugDraw,
|
||||
PP_BindKind_DebugConsole,
|
||||
PP_BindKind_DebugCamera,
|
||||
PP_BindKind_DebugLister,
|
||||
PP_BindKind_DebugPause,
|
||||
PP_BindKind_DebugStep,
|
||||
PP_BindKind_DebugDrag,
|
||||
PP_BindKind_DebugDelete,
|
||||
PP_BindKind_DebugTeleport,
|
||||
PP_BindKind_DebugExplode,
|
||||
PP_BindKind_DebugToggleTopmost,
|
||||
PP_BindKind_DebugUi,
|
||||
PP_BindKind_FullscreenMod,
|
||||
PP_BindKind_Fullscreen,
|
||||
PP_BindKind_ZoomIn,
|
||||
PP_BindKind_ZoomOut,
|
||||
PP_BindKind_Pan,
|
||||
|
||||
#if IsRtcEnabled
|
||||
/* Debug */
|
||||
/* Debug */
|
||||
|
||||
PP_BindKind_ResetDebugSteps,
|
||||
PP_BindKind_IncrementDebugSteps,
|
||||
PP_BindKind_DecrementDebugSteps,
|
||||
PP_BindKind_ResetDebugSteps,
|
||||
PP_BindKind_IncrementDebugSteps,
|
||||
PP_BindKind_DecrementDebugSteps,
|
||||
#endif
|
||||
|
||||
PP_BindKind_Count
|
||||
PP_BindKind_Count
|
||||
};
|
||||
|
||||
//- Test bindings
|
||||
|
||||
/* TODO: Remove this */
|
||||
Global Readonly PP_BindKind g_binds[Btn_Count] = {
|
||||
[Btn_W] = PP_BindKind_MoveUp,
|
||||
[Btn_S] = PP_BindKind_MoveDown,
|
||||
[Btn_A] = PP_BindKind_MoveLeft,
|
||||
[Btn_D] = PP_BindKind_MoveRight,
|
||||
[Btn_M1] = PP_BindKind_Fire,
|
||||
[Btn_M2] = PP_BindKind_AltFire,
|
||||
[Btn_W] = PP_BindKind_MoveUp,
|
||||
[Btn_S] = PP_BindKind_MoveDown,
|
||||
[Btn_A] = PP_BindKind_MoveLeft,
|
||||
[Btn_D] = PP_BindKind_MoveRight,
|
||||
[Btn_M1] = PP_BindKind_Fire,
|
||||
[Btn_M2] = PP_BindKind_AltFire,
|
||||
#if 0
|
||||
[Btn_Alt] = PP_BindKind_Walk,
|
||||
[Btn_Alt] = PP_BindKind_Walk,
|
||||
#endif
|
||||
|
||||
/* Testing */
|
||||
[Btn_Z] = PP_BindKind_TestTile,
|
||||
[Btn_M5] = PP_BindKind_DebugDrag,
|
||||
[Btn_M4] = PP_BindKind_DebugDelete,
|
||||
[Btn_F] = PP_BindKind_DebugExplode,
|
||||
[Btn_T] = PP_BindKind_DebugTeleport,
|
||||
[Btn_C] = PP_BindKind_DebugClear,
|
||||
[Btn_1] = PP_BindKind_DebugSpawn1,
|
||||
[Btn_2] = PP_BindKind_DebugSpawn2,
|
||||
[Btn_3] = PP_BindKind_DebugSpawn3,
|
||||
[Btn_4] = PP_BindKind_DebugSpawn4,
|
||||
[Btn_G] = PP_BindKind_DebugWalls,
|
||||
[Btn_N] = PP_BindKind_DebugStep,
|
||||
[Btn_Q] = PP_BindKind_DebugFollow,
|
||||
[Btn_F1] = PP_BindKind_DebugPause,
|
||||
[Btn_F2] = PP_BindKind_DebugCamera,
|
||||
[Btn_F3] = PP_BindKind_DebugDraw,
|
||||
[Btn_Tab] = PP_BindKind_DebugLister,
|
||||
[Btn_F4] = PP_BindKind_DebugToggleTopmost,
|
||||
[Btn_F5] = PP_BindKind_DebugUi,
|
||||
[Btn_GraveAccent] = PP_BindKind_DebugConsole,
|
||||
[Btn_Alt] = PP_BindKind_FullscreenMod,
|
||||
[Btn_Enter] = PP_BindKind_Fullscreen,
|
||||
[Btn_MWheelUp] = PP_BindKind_ZoomIn,
|
||||
[Btn_MWheelDown] = PP_BindKind_ZoomOut,
|
||||
[Btn_M3] = PP_BindKind_Pan,
|
||||
/* Testing */
|
||||
[Btn_Z] = PP_BindKind_TestTile,
|
||||
[Btn_M5] = PP_BindKind_DebugDrag,
|
||||
[Btn_M4] = PP_BindKind_DebugDelete,
|
||||
[Btn_F] = PP_BindKind_DebugExplode,
|
||||
[Btn_T] = PP_BindKind_DebugTeleport,
|
||||
[Btn_C] = PP_BindKind_DebugClear,
|
||||
[Btn_1] = PP_BindKind_DebugSpawn1,
|
||||
[Btn_2] = PP_BindKind_DebugSpawn2,
|
||||
[Btn_3] = PP_BindKind_DebugSpawn3,
|
||||
[Btn_4] = PP_BindKind_DebugSpawn4,
|
||||
[Btn_G] = PP_BindKind_DebugWalls,
|
||||
[Btn_N] = PP_BindKind_DebugStep,
|
||||
[Btn_Q] = PP_BindKind_DebugFollow,
|
||||
[Btn_F1] = PP_BindKind_DebugPause,
|
||||
[Btn_F2] = PP_BindKind_DebugCamera,
|
||||
[Btn_F3] = PP_BindKind_DebugDraw,
|
||||
[Btn_Tab] = PP_BindKind_DebugLister,
|
||||
[Btn_F4] = PP_BindKind_DebugToggleTopmost,
|
||||
[Btn_F5] = PP_BindKind_DebugUi,
|
||||
[Btn_GraveAccent] = PP_BindKind_DebugConsole,
|
||||
[Btn_Alt] = PP_BindKind_FullscreenMod,
|
||||
[Btn_Enter] = PP_BindKind_Fullscreen,
|
||||
[Btn_MWheelUp] = PP_BindKind_ZoomIn,
|
||||
[Btn_MWheelDown] = PP_BindKind_ZoomOut,
|
||||
[Btn_M3] = PP_BindKind_Pan,
|
||||
|
||||
#if IsRtcEnabled
|
||||
[Btn_ForwardSlash] = PP_BindKind_ResetDebugSteps,
|
||||
[Btn_Comma] = PP_BindKind_DecrementDebugSteps,
|
||||
[Btn_Period] = PP_BindKind_IncrementDebugSteps
|
||||
[Btn_ForwardSlash] = PP_BindKind_ResetDebugSteps,
|
||||
[Btn_Comma] = PP_BindKind_DecrementDebugSteps,
|
||||
[Btn_Period] = PP_BindKind_IncrementDebugSteps
|
||||
#endif
|
||||
};
|
||||
|
||||
@ -104,9 +104,9 @@ Global Readonly PP_BindKind g_binds[Btn_Count] = {
|
||||
|
||||
Struct(PP_SecondsStat)
|
||||
{
|
||||
u64 last_second_start;
|
||||
u64 last_second_end;
|
||||
u64 last_second;
|
||||
u64 last_second_start;
|
||||
u64 last_second_end;
|
||||
u64 last_second;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -114,12 +114,12 @@ Struct(PP_SecondsStat)
|
||||
|
||||
Struct(PP_ConsoleLog)
|
||||
{
|
||||
String msg;
|
||||
i32 level;
|
||||
i32 color_index;
|
||||
DateTime datetime;
|
||||
PP_ConsoleLog *prev;
|
||||
PP_ConsoleLog *next;
|
||||
String msg;
|
||||
i32 level;
|
||||
i32 color_index;
|
||||
DateTime datetime;
|
||||
PP_ConsoleLog *prev;
|
||||
PP_ConsoleLog *next;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -127,17 +127,17 @@ Struct(PP_ConsoleLog)
|
||||
|
||||
Struct(PP_DecodeQueueNode)
|
||||
{
|
||||
PP_Client *client;
|
||||
u64 tick;
|
||||
u64 base_tick;
|
||||
String tmp_encoded;
|
||||
PP_DecodeQueueNode *next;
|
||||
PP_Client *client;
|
||||
u64 tick;
|
||||
u64 base_tick;
|
||||
String tmp_encoded;
|
||||
PP_DecodeQueueNode *next;
|
||||
};
|
||||
|
||||
Struct(PP_DecodeQueue)
|
||||
{
|
||||
PP_DecodeQueueNode *first;
|
||||
PP_DecodeQueueNode *last;
|
||||
PP_DecodeQueueNode *first;
|
||||
PP_DecodeQueueNode *last;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -145,137 +145,137 @@ Struct(PP_DecodeQueue)
|
||||
|
||||
Struct(PP_BindState)
|
||||
{
|
||||
b32 is_held; /* Is this bind held down this frame */
|
||||
u32 num_presses; /* How many times was this bind's pressed since last frame */
|
||||
u32 num_repeats; /* How many times was this bind's key repeated since last frame */
|
||||
u32 num_presses_and_repeats; /* Same as `num_presses` but includes key repeats as well */
|
||||
u32 num_releases; /* How many times was this bind released since last frame */
|
||||
b32 is_held; /* Is this bind held down this frame */
|
||||
u32 num_presses; /* How many times was this bind's pressed since last frame */
|
||||
u32 num_repeats; /* How many times was this bind's key repeated since last frame */
|
||||
u32 num_presses_and_repeats; /* Same as `num_presses` but includes key repeats as well */
|
||||
u32 num_releases; /* How many times was this bind released since last frame */
|
||||
};
|
||||
|
||||
Struct(PP_SharedUserState)
|
||||
{
|
||||
Atomic32 shutdown;
|
||||
Atomic32 shutdown;
|
||||
|
||||
Fence shutdown_jobs_fence;
|
||||
u64 shutdown_jobs_count;
|
||||
Fence shutdown_jobs_fence;
|
||||
u64 shutdown_jobs_count;
|
||||
|
||||
Arena *arena;
|
||||
String connect_address_str;
|
||||
Arena *arena;
|
||||
String connect_address_str;
|
||||
|
||||
PP_ClientStore *user_client_store;
|
||||
PP_Client *user_unblended_client; /* Contains snapshots received from local sim */
|
||||
PP_Client *user_blended_client; /* Contains single snapshot from result of blending local sim snapshots */
|
||||
PP_Snapshot *ss_blended; /* Points to blended snapshot contained in blended client */
|
||||
PP_ClientStore *user_client_store;
|
||||
PP_Client *user_unblended_client; /* Contains snapshots received from local sim */
|
||||
PP_Client *user_blended_client; /* Contains single snapshot from result of blending local sim snapshots */
|
||||
PP_Snapshot *ss_blended; /* Points to blended snapshot contained in blended client */
|
||||
|
||||
u64 user_tick;
|
||||
u64 window_os_gen;
|
||||
u64 user_tick;
|
||||
u64 window_os_gen;
|
||||
|
||||
//- Usage stats
|
||||
i64 last_second_reset_ns;
|
||||
PP_SecondsStat net_bytes_read;
|
||||
PP_SecondsStat net_bytes_sent;
|
||||
//- Usage stats
|
||||
i64 last_second_reset_ns;
|
||||
PP_SecondsStat net_bytes_read;
|
||||
PP_SecondsStat net_bytes_sent;
|
||||
|
||||
//- Renderer gbuffers
|
||||
GPU_Resource *albedo;
|
||||
GPU_Resource *emittance;
|
||||
GPU_Resource *emittance_flood_read;
|
||||
GPU_Resource *emittance_flood_target;
|
||||
GPU_Resource *shade_read;
|
||||
GPU_Resource *shade_target;
|
||||
//- Renderer gbuffers
|
||||
GPU_Resource *albedo;
|
||||
GPU_Resource *emittance;
|
||||
GPU_Resource *emittance_flood_read;
|
||||
GPU_Resource *emittance_flood_target;
|
||||
GPU_Resource *shade_read;
|
||||
GPU_Resource *shade_target;
|
||||
|
||||
//- Renderer transient buffers
|
||||
GPU_TransientBuffer material_instances_tbuff;
|
||||
GPU_TransientBuffer grids_tbuff;
|
||||
Arena *material_instances_arena;
|
||||
Arena *grids_arena;
|
||||
//- Renderer transient buffers
|
||||
GPU_TransientBuffer material_instances_tbuff;
|
||||
GPU_TransientBuffer grids_tbuff;
|
||||
Arena *material_instances_arena;
|
||||
Arena *grids_arena;
|
||||
|
||||
//- Renderer state
|
||||
RandState frame_rand;
|
||||
u64 frame_index;
|
||||
i64 gpu_submit_fence_target;
|
||||
//- Renderer state
|
||||
RandState frame_rand;
|
||||
u64 frame_index;
|
||||
i64 gpu_submit_fence_target;
|
||||
|
||||
//- Bind state
|
||||
PP_BindState bind_states[PP_BindKind_Count];
|
||||
//- Bind state
|
||||
PP_BindState bind_states[PP_BindKind_Count];
|
||||
|
||||
//- Window -> user
|
||||
Mutex sys_window_events_mutex;
|
||||
Arena *sys_window_events_arena;
|
||||
//- Window -> user
|
||||
Mutex sys_window_events_mutex;
|
||||
Arena *sys_window_events_arena;
|
||||
|
||||
//- User -> sim
|
||||
Mutex user_sim_cmd_mutex;
|
||||
PP_ControlData user_sim_cmd_control;
|
||||
PP_EntKey user_hovered_ent;
|
||||
u64 last_user_sim_cmd_gen;
|
||||
u64 user_sim_cmd_gen;
|
||||
//- User -> sim
|
||||
Mutex user_sim_cmd_mutex;
|
||||
PP_ControlData user_sim_cmd_control;
|
||||
PP_EntKey user_hovered_ent;
|
||||
u64 last_user_sim_cmd_gen;
|
||||
u64 user_sim_cmd_gen;
|
||||
|
||||
Atomic32 user_paused;
|
||||
Atomic32 user_paused_steps;
|
||||
Atomic32 user_paused;
|
||||
Atomic32 user_paused_steps;
|
||||
|
||||
//- Sim -> user
|
||||
Mutex local_to_user_client_mutex;
|
||||
PP_ClientStore *local_to_user_client_store;
|
||||
PP_Client *local_to_user_client;
|
||||
i64 local_to_user_client_publish_dt_ns;
|
||||
i64 local_to_user_client_publish_time_ns;
|
||||
//- Sim -> user
|
||||
Mutex local_to_user_client_mutex;
|
||||
PP_ClientStore *local_to_user_client_store;
|
||||
PP_Client *local_to_user_client;
|
||||
i64 local_to_user_client_publish_dt_ns;
|
||||
i64 local_to_user_client_publish_time_ns;
|
||||
|
||||
//- Local sim -> user rolling window of publish time deltas
|
||||
i64 last_local_to_user_snapshot_published_at_ns;
|
||||
i64 average_local_to_user_snapshot_publish_dt_ns;
|
||||
//- Local sim -> user rolling window of publish time deltas
|
||||
i64 last_local_to_user_snapshot_published_at_ns;
|
||||
i64 average_local_to_user_snapshot_publish_dt_ns;
|
||||
|
||||
i64 local_sim_predicted_time_ns; /* Calculated from <last local sim to user pubilsh time> + <time since last local sim to user publish> */
|
||||
i64 render_time_target_ns; /* Claculated from <local_sim_rpedicted_time_ns> - <render interp delay> */
|
||||
i64 render_time_ns; /* Incremented at a constant rate based on average local to user publish delta, but snaps to render_time_target_ns if it gets too distant */
|
||||
i64 local_sim_predicted_time_ns; /* Calculated from <last local sim to user pubilsh time> + <time since last local sim to user publish> */
|
||||
i64 render_time_target_ns; /* Claculated from <local_sim_rpedicted_time_ns> - <render interp delay> */
|
||||
i64 render_time_ns; /* Incremented at a constant rate based on average local to user publish delta, but snaps to render_time_target_ns if it gets too distant */
|
||||
|
||||
u64 local_sim_last_known_tick;
|
||||
i64 local_sim_last_known_time_ns;
|
||||
u64 local_sim_last_known_tick;
|
||||
i64 local_sim_last_known_time_ns;
|
||||
|
||||
i64 real_dt_ns;
|
||||
i64 real_time_ns;
|
||||
i64 real_dt_ns;
|
||||
i64 real_time_ns;
|
||||
|
||||
//- Window
|
||||
//- Window
|
||||
|
||||
String window_restore;
|
||||
String window_restore;
|
||||
|
||||
//////////////////////////////
|
||||
//- Persist start
|
||||
StructRegion(AUTO_PERSIST_START);
|
||||
//////////////////////////////
|
||||
//- Persist start
|
||||
StructRegion(AUTO_PERSIST_START);
|
||||
|
||||
//- Debug ui
|
||||
//- Debug ui
|
||||
|
||||
b32 ui_debug;
|
||||
b32 ui_debug;
|
||||
|
||||
PP_EntKey debug_following;
|
||||
Vec2 debug_camera_pan_start;
|
||||
b32 debug_camera_panning;
|
||||
b32 debug_camera;
|
||||
PP_EntKey debug_following;
|
||||
Vec2 debug_camera_pan_start;
|
||||
b32 debug_camera_panning;
|
||||
b32 debug_camera;
|
||||
|
||||
b32 lister_active;
|
||||
Vec2 lister_pos;
|
||||
b32 lister_active;
|
||||
Vec2 lister_pos;
|
||||
|
||||
b32 debug_draw;
|
||||
b32 debug_console;
|
||||
b32 debug_draw;
|
||||
b32 debug_console;
|
||||
|
||||
//- Per frame
|
||||
//- Per frame
|
||||
|
||||
Vec2I32 screen_size;
|
||||
Vec2 screen_cursor;
|
||||
Vec2I32 screen_size;
|
||||
Vec2 screen_cursor;
|
||||
|
||||
Xform ui_to_screen_xf;
|
||||
Vec2I32 ui_size;
|
||||
Vec2 ui_cursor;
|
||||
Xform ui_to_screen_xf;
|
||||
Vec2I32 ui_size;
|
||||
Vec2 ui_cursor;
|
||||
|
||||
Xform render_to_ui_xf;
|
||||
Vec2I32 render_size;
|
||||
Xform render_to_ui_xf;
|
||||
Vec2I32 render_size;
|
||||
|
||||
Xform world_to_render_xf;
|
||||
Xform world_to_ui_xf;
|
||||
Vec2 world_cursor;
|
||||
Xform world_to_render_xf;
|
||||
Xform world_to_ui_xf;
|
||||
Vec2 world_cursor;
|
||||
|
||||
Vec2 focus_send;
|
||||
Vec2 focus_send;
|
||||
|
||||
StructRegion(AUTO_PERSIST_END);
|
||||
//- Persist end
|
||||
//////////////////////////////
|
||||
StructRegion(AUTO_PERSIST_END);
|
||||
//- Persist end
|
||||
//////////////////////////////
|
||||
|
||||
} extern PP_shared_user_state;
|
||||
|
||||
@ -284,7 +284,7 @@ Struct(PP_SharedUserState)
|
||||
|
||||
Struct(PP_SwappedUserState)
|
||||
{
|
||||
PP_SharedUserState s;
|
||||
PP_SharedUserState s;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
@ -3,52 +3,52 @@
|
||||
|
||||
Struct(PP_MaterialSig)
|
||||
{
|
||||
/* ----------------------------------------------------- */
|
||||
Mat4x4 projection; /* 16 consts */
|
||||
/* ----------------------------------------------------- */
|
||||
SamplerStateRid sampler; /* 01 consts */
|
||||
StructuredBufferRid instances; /* 01 consts */
|
||||
StructuredBufferRid grids; /* 01 consts */
|
||||
u32 _pad0; /* 01 consts (padding) */
|
||||
/* ----------------------------------------------------- */
|
||||
/* ----------------------------------------------------- */
|
||||
Mat4x4 projection; /* 16 consts */
|
||||
/* ----------------------------------------------------- */
|
||||
SamplerStateRid sampler; /* 01 consts */
|
||||
StructuredBufferRid instances; /* 01 consts */
|
||||
StructuredBufferRid grids; /* 01 consts */
|
||||
u32 _pad0; /* 01 consts (padding) */
|
||||
/* ----------------------------------------------------- */
|
||||
};
|
||||
AssertRootConst(PP_MaterialSig, 20);
|
||||
|
||||
Struct(PP_MaterialInstance)
|
||||
{
|
||||
Texture2DRid tex;
|
||||
u32 grid_id;
|
||||
Xform xf;
|
||||
Vec2 tex_uv0;
|
||||
Vec2 tex_uv1;
|
||||
u32 tint_srgb;
|
||||
u32 is_light;
|
||||
Vec3 light_emittance_srgb;
|
||||
Texture2DRid tex;
|
||||
u32 grid_id;
|
||||
Xform xf;
|
||||
Vec2 tex_uv0;
|
||||
Vec2 tex_uv1;
|
||||
u32 tint_srgb;
|
||||
u32 is_light;
|
||||
Vec3 light_emittance_srgb;
|
||||
};
|
||||
#define PP_DefaultMaterialInstance (PP_MaterialInstance) { \
|
||||
.tex = { U32Max }, \
|
||||
.grid_id = U32Max, \
|
||||
.xf = XformIdentity, \
|
||||
.tex_uv1 = VEC2(1, 1), \
|
||||
.tint_srgb = Color_White, \
|
||||
.tex = { U32Max }, \
|
||||
.grid_id = U32Max, \
|
||||
.xf = XformIdentity, \
|
||||
.tex_uv1 = VEC2(1, 1), \
|
||||
.tint_srgb = Color_White, \
|
||||
}
|
||||
|
||||
Struct(PP_MaterialGrid)
|
||||
{
|
||||
f32 line_thickness;
|
||||
f32 line_spacing;
|
||||
Vec2 offset;
|
||||
u32 bg0_srgb;
|
||||
u32 bg1_srgb;
|
||||
u32 line_srgb;
|
||||
u32 x_srgb;
|
||||
u32 y_srgb;
|
||||
f32 line_thickness;
|
||||
f32 line_spacing;
|
||||
Vec2 offset;
|
||||
u32 bg0_srgb;
|
||||
u32 bg1_srgb;
|
||||
u32 line_srgb;
|
||||
u32 x_srgb;
|
||||
u32 y_srgb;
|
||||
};
|
||||
#define PP_DefaultMaterialGrid (PP_MaterialGrid) { \
|
||||
.line_thickness = 1, \
|
||||
.line_spacing = 1, \
|
||||
.bg0_srgb = Color_Black, \
|
||||
.bg0_srgb = Color_White \
|
||||
.line_thickness = 1, \
|
||||
.line_spacing = 1, \
|
||||
.bg0_srgb = Color_Black, \
|
||||
.bg0_srgb = Color_White \
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -56,17 +56,17 @@ Struct(PP_MaterialGrid)
|
||||
|
||||
Struct(PP_FloodSig)
|
||||
{
|
||||
/* ----------------------------------------------------- */
|
||||
i32 step_len; /* 01 consts */
|
||||
Texture2DRid emittance; /* 01 consts */
|
||||
RWTexture2DRid read; /* 01 consts */
|
||||
RWTexture2DRid target; /* 01 consts */
|
||||
/* ----------------------------------------------------- */
|
||||
u32 tex_width; /* 01 consts */
|
||||
u32 tex_height; /* 01 consts */
|
||||
u32 _pad0; /* 01 consts (padding) */
|
||||
u32 _pad1; /* 01 consts (padding) */
|
||||
/* ----------------------------------------------------- */
|
||||
/* ----------------------------------------------------- */
|
||||
i32 step_len; /* 01 consts */
|
||||
Texture2DRid emittance; /* 01 consts */
|
||||
RWTexture2DRid read; /* 01 consts */
|
||||
RWTexture2DRid target; /* 01 consts */
|
||||
/* ----------------------------------------------------- */
|
||||
u32 tex_width; /* 01 consts */
|
||||
u32 tex_height; /* 01 consts */
|
||||
u32 _pad0; /* 01 consts (padding) */
|
||||
u32 _pad1; /* 01 consts (padding) */
|
||||
/* ----------------------------------------------------- */
|
||||
};
|
||||
AssertRootConst(PP_FloodSig, 8);
|
||||
|
||||
@ -79,27 +79,27 @@ AssertRootConst(PP_FloodSig, 8);
|
||||
|
||||
Struct(PP_ShadeSig)
|
||||
{
|
||||
/* ----------------------------------------------------- */
|
||||
Vec4U32 frame_seed; /* 04 consts */
|
||||
/* ----------------------------------------------------- */
|
||||
u32 flags; /* 01 consts */
|
||||
u32 tex_width; /* 01 consts */
|
||||
u32 tex_height; /* 01 consts */
|
||||
f32 exposure; /* 01 consts */
|
||||
/* ----------------------------------------------------- */
|
||||
Vec2 camera_offset; /* 02 consts */
|
||||
u32 frame_index; /* 01 consts */
|
||||
Texture2DRid albedo; /* 01 consts */
|
||||
/* ----------------------------------------------------- */
|
||||
Texture2DRid emittance; /* 01 consts */
|
||||
Texture2DRid emittance_flood; /* 01 consts */
|
||||
Texture2DRid read; /* 01 consts */
|
||||
RWTexture2DRid target; /* 01 consts */
|
||||
/* ----------------------------------------------------- */
|
||||
Texture3DRid noise; /* 01 consts */
|
||||
u32 noise_tex_width; /* 01 consts */
|
||||
u32 noise_tex_height; /* 01 consts */
|
||||
u32 noise_tex_depth; /* 01 consts */
|
||||
/* ----------------------------------------------------- */
|
||||
/* ----------------------------------------------------- */
|
||||
Vec4U32 frame_seed; /* 04 consts */
|
||||
/* ----------------------------------------------------- */
|
||||
u32 flags; /* 01 consts */
|
||||
u32 tex_width; /* 01 consts */
|
||||
u32 tex_height; /* 01 consts */
|
||||
f32 exposure; /* 01 consts */
|
||||
/* ----------------------------------------------------- */
|
||||
Vec2 camera_offset; /* 02 consts */
|
||||
u32 frame_index; /* 01 consts */
|
||||
Texture2DRid albedo; /* 01 consts */
|
||||
/* ----------------------------------------------------- */
|
||||
Texture2DRid emittance; /* 01 consts */
|
||||
Texture2DRid emittance_flood; /* 01 consts */
|
||||
Texture2DRid read; /* 01 consts */
|
||||
RWTexture2DRid target; /* 01 consts */
|
||||
/* ----------------------------------------------------- */
|
||||
Texture3DRid noise; /* 01 consts */
|
||||
u32 noise_tex_width; /* 01 consts */
|
||||
u32 noise_tex_height; /* 01 consts */
|
||||
u32 noise_tex_depth; /* 01 consts */
|
||||
/* ----------------------------------------------------- */
|
||||
};
|
||||
AssertRootConst(PP_ShadeSig, 20);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user