convert comment style from multi-line to single-line

This commit is contained in:
jacob 2025-12-28 12:06:08 -06:00
parent a4ebc3cb49
commit 4ffb9a8d73
92 changed files with 1724 additions and 1712 deletions

View File

@ -1,7 +1,8 @@
/* Aseprite (.ase) file parser //
* // Aseprite (.ase) file parser
* DEFLATE decoder based on Handmade Hero's png parser //
*/ // DEFLATE decoder based on Handmade Hero's png parser
//
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Shared constants //~ Shared constants
@ -11,68 +12,68 @@ Global Readonly u32 ASE_huff_hclen_order[] = {
}; };
Global Readonly ASE_HuffEntry ASE_huff_length_table[] = { Global Readonly ASE_HuffEntry ASE_huff_length_table[] = {
{3, 0}, /* 257 */ {3, 0}, // 257
{4, 0}, /* 258 */ {4, 0}, // 258
{5, 0}, /* 259 */ {5, 0}, // 259
{6, 0}, /* 260 */ {6, 0}, // 260
{7, 0}, /* 261 */ {7, 0}, // 261
{8, 0}, /* 262 */ {8, 0}, // 262
{9, 0}, /* 263 */ {9, 0}, // 263
{10, 0}, /* 264 */ {10, 0}, // 264
{11, 1}, /* 265 */ {11, 1}, // 265
{13, 1}, /* 266 */ {13, 1}, // 266
{15, 1}, /* 267 */ {15, 1}, // 267
{17, 1}, /* 268 */ {17, 1}, // 268
{19, 2}, /* 269 */ {19, 2}, // 269
{23, 2}, /* 270 */ {23, 2}, // 270
{27, 2}, /* 271 */ {27, 2}, // 271
{31, 2}, /* 272 */ {31, 2}, // 272
{35, 3}, /* 273 */ {35, 3}, // 273
{43, 3}, /* 274 */ {43, 3}, // 274
{51, 3}, /* 275 */ {51, 3}, // 275
{59, 3}, /* 276 */ {59, 3}, // 276
{67, 4}, /* 277 */ {67, 4}, // 277
{83, 4}, /* 278 */ {83, 4}, // 278
{99, 4}, /* 279 */ {99, 4}, // 279
{115, 4}, /* 280 */ {115, 4}, // 280
{131, 5}, /* 281 */ {131, 5}, // 281
{163, 5}, /* 282 */ {163, 5}, // 282
{195, 5}, /* 283 */ {195, 5}, // 283
{227, 5}, /* 284 */ {227, 5}, // 284
{258, 0}, /* 285 */ {258, 0}, // 285
}; };
Global Readonly ASE_HuffEntry ASE_huff_dist_table[] = { Global Readonly ASE_HuffEntry ASE_huff_dist_table[] = {
{1, 0}, /* 0 */ {1, 0}, // 0
{2, 0}, /* 1 */ {2, 0}, // 1
{3, 0}, /* 2 */ {3, 0}, // 2
{4, 0}, /* 3 */ {4, 0}, // 3
{5, 1}, /* 4 */ {5, 1}, // 4
{7, 1}, /* 5 */ {7, 1}, // 5
{9, 2}, /* 6 */ {9, 2}, // 6
{13, 2}, /* 7 */ {13, 2}, // 7
{17, 3}, /* 8 */ {17, 3}, // 8
{25, 3}, /* 9 */ {25, 3}, // 9
{33, 4}, /* 10 */ {33, 4}, // 10
{49, 4}, /* 11 */ {49, 4}, // 11
{65, 5}, /* 12 */ {65, 5}, // 12
{97, 5}, /* 13 */ {97, 5}, // 13
{129, 6}, /* 14 */ {129, 6}, // 14
{193, 6}, /* 15 */ {193, 6}, // 15
{257, 7}, /* 16 */ {257, 7}, // 16
{385, 7}, /* 17 */ {385, 7}, // 17
{513, 8}, /* 18 */ {513, 8}, // 18
{769, 8}, /* 19 */ {769, 8}, // 19
{1025, 9}, /* 20 */ {1025, 9}, // 20
{1537, 9}, /* 21 */ {1537, 9}, // 21
{2049, 10}, /* 22 */ {2049, 10}, // 22
{3073, 10}, /* 23 */ {3073, 10}, // 23
{4097, 11}, /* 24 */ {4097, 11}, // 24
{6145, 11}, /* 25 */ {6145, 11}, // 25
{8193, 12}, /* 26 */ {8193, 12}, // 26
{12289, 12}, /* 27 */ {12289, 12}, // 27
{16385, 13}, /* 28 */ {16385, 13}, // 28
{24577, 13}, /* 29 */ {24577, 13}, // 29
}; };
Global Readonly u32 ASE_huff_bl_counts[][2] = { Global Readonly u32 ASE_huff_bl_counts[][2] = {
@ -119,8 +120,8 @@ void ASE_SkipBits(ASE_Bitbuff *bb, u32 nbits)
u32 ASE_ReverseBits(u32 v, u32 bit_count) u32 ASE_ReverseBits(u32 v, u32 bit_count)
{ {
/* 7 & 15 seem to be the most common bit_counts, so a // 7 & 15 seem to be the most common bit_counts, so a
* more optimal path is layed out for them. */ // more optimal path is layed out for them.
if (bit_count == 15) if (bit_count == 15)
{ {
u32 b1 = v & 0xFF; u32 b1 = v & 0xFF;
@ -191,7 +192,7 @@ ASE_HuffDict ASE_InitHuffDict(Arena *arena, u32 max_code_bits, u32 *bl_counts, u
u32 entry_count = (1 << arbitrary_bits); u32 entry_count = (1 << arbitrary_bits);
for (u32 entry_index = 0; entry_index < entry_count; ++entry_index) for (u32 entry_index = 0; entry_index < entry_count; ++entry_index)
{ {
/* TODO: Optimize this. It's bloating up the loading times. */ // TODO: Optimize this. It's bloating up the loading times.
u32 base_index = (code << arbitrary_bits) | entry_index; u32 base_index = (code << arbitrary_bits) | entry_index;
u32 index = ASE_ReverseBits(base_index, result.max_code_bits); u32 index = ASE_ReverseBits(base_index, result.max_code_bits);
ASE_HuffEntry *entry = &result.entries[index]; ASE_HuffEntry *entry = &result.entries[index];
@ -222,7 +223,7 @@ void ASE_Inflate(u8 *dst, u8 *encoded)
ASE_Bitbuff bb = { .data = encoded }; ASE_Bitbuff bb = { .data = encoded };
/* ZLIB header */ // ZLIB header
u32 cm = ASE_ConsumeBits(&bb, 4); u32 cm = ASE_ConsumeBits(&bb, 4);
u32 cinfo = ASE_ConsumeBits(&bb, 4); u32 cinfo = ASE_ConsumeBits(&bb, 4);
Assert(cm == 8); Assert(cm == 8);
@ -249,7 +250,7 @@ void ASE_Inflate(u8 *dst, u8 *encoded)
ASE_SkipBits(&bb, (8 - (bb.cur_bit % 8)) % 8); ASE_SkipBits(&bb, (8 - (bb.cur_bit % 8)) % 8);
i16 len = ASE_ConsumeBits(&bb, 16); i16 len = ASE_ConsumeBits(&bb, 16);
i16 nlen = ASE_ConsumeBits(&bb, 16); i16 nlen = ASE_ConsumeBits(&bb, 16);
Assert(len == ~nlen); /* Validation */ Assert(len == ~nlen); // Validation
while (len-- > 0) while (len-- > 0)
{ {
*dst++ = ASE_ConsumeBits(&bb, 8); *dst++ = ASE_ConsumeBits(&bb, 8);
@ -266,14 +267,14 @@ void ASE_Inflate(u8 *dst, u8 *encoded)
if (btype == ASE_BlockType_CompressedDynamic) if (btype == ASE_BlockType_CompressedDynamic)
{ {
/* Dynamic table */ // Dynamic table
/* Read huffman table */ // Read huffman table
hlit = ASE_ConsumeBits(&bb, 5) + 257; hlit = ASE_ConsumeBits(&bb, 5) + 257;
hdist = ASE_ConsumeBits(&bb, 5) + 1; hdist = ASE_ConsumeBits(&bb, 5) + 1;
u32 hclen = ASE_ConsumeBits(&bb, 4) + 4; u32 hclen = ASE_ConsumeBits(&bb, 4) + 4;
/* Init dict huffman (hclen) */ // Init dict huffman (hclen)
u32 hclen_bl_counts[19] = Zi; u32 hclen_bl_counts[19] = Zi;
for (u32 i = 0; i < hclen; ++i) for (u32 i = 0; i < hclen; ++i)
{ {
@ -282,7 +283,7 @@ void ASE_Inflate(u8 *dst, u8 *encoded)
} }
ASE_HuffDict dict_huffman = ASE_InitHuffDict(temp.arena, 7, hclen_bl_counts, countof(hclen_bl_counts)); ASE_HuffDict dict_huffman = ASE_InitHuffDict(temp.arena, 7, hclen_bl_counts, countof(hclen_bl_counts));
/* Decode dict huffman */ // Decode dict huffman
u32 lit_len_count = 0; u32 lit_len_count = 0;
u32 len_count = hlit + hdist; u32 len_count = hlit + hdist;
Assert(len_count <= countof(lit_len_dist_table)); Assert(len_count <= countof(lit_len_dist_table));
@ -311,7 +312,7 @@ void ASE_Inflate(u8 *dst, u8 *encoded)
} }
else else
{ {
/* Invalid len */ // Invalid len
Assert(0); Assert(0);
} }
@ -324,7 +325,7 @@ void ASE_Inflate(u8 *dst, u8 *encoded)
} }
else else
{ {
/* Fixed table */ // Fixed table
hlit = 288; hlit = 288;
hdist = 32; hdist = 32;
u32 index = 0; u32 index = 0;
@ -339,7 +340,7 @@ void ASE_Inflate(u8 *dst, u8 *encoded)
} }
} }
/* Decode */ // Decode
ASE_HuffDict lit_len_huffman = ASE_InitHuffDict(temp.arena, 15, lit_len_dist_table, hlit); ASE_HuffDict lit_len_huffman = ASE_InitHuffDict(temp.arena, 15, lit_len_dist_table, hlit);
ASE_HuffDict dist_huffman = ASE_InitHuffDict(temp.arena, 15, lit_len_dist_table + hlit, hdist); ASE_HuffDict dist_huffman = ASE_InitHuffDict(temp.arena, 15, lit_len_dist_table + hlit, hdist);
@ -386,7 +387,7 @@ void ASE_Inflate(u8 *dst, u8 *encoded)
case ASE_BlockType_Reserved: case ASE_BlockType_Reserved:
{ {
/* TODO */ // TODO
Assert(0); Assert(0);
} break; } break;
} }
@ -454,8 +455,8 @@ u32 ASE_Blend(u32 src, u32 dst, u8 opacity)
void ASE_MakeDimensionsSquareish(ASE_Header *header, u32 *frames_x, u32 *frames_y, u64 *image_width, u64 *image_height) void ASE_MakeDimensionsSquareish(ASE_Header *header, u32 *frames_x, u32 *frames_y, u64 *image_width, u64 *image_height)
{ {
/* Try and get image resolution into as much of a square as possible by // Try and get image resolution into as much of a square as possible by
* separating frames into multiple rows. */ // separating frames into multiple rows.
while (*frames_x > 1) while (*frames_x > 1)
{ {
u64 new_frames_x = *frames_x - 1; u64 new_frames_x = *frames_x - 1;
@ -517,7 +518,7 @@ ASE_DecodedImage ASE_DecodeImage(Arena *arena, String encoded)
result.width = image_width; result.width = image_width;
result.height = image_height; result.height = image_height;
/* TODO: Optimize this. Naive memzero is bloating the decode time for large images. */ // TODO: Optimize this. Naive memzero is bloating the decode time for large images.
result.pixels = PushStructs(arena, u32, image_width * image_height); result.pixels = PushStructs(arena, u32, image_width * image_height);
u32 num_layers = 0; u32 num_layers = 0;
@ -526,7 +527,9 @@ ASE_DecodedImage ASE_DecodeImage(Arena *arena, String encoded)
Ace_Cel *cel_head = 0; Ace_Cel *cel_head = 0;
Ace_Cel *cel_tail = 0; Ace_Cel *cel_tail = 0;
//////////////////////////////
//- Iterate frames //- Iterate frames
u32 num_frames = 0; u32 num_frames = 0;
for (u16 i = 0; i < ase_header.frames; ++i) for (u16 i = 0; i < ase_header.frames; ++i)
{ {
@ -540,13 +543,15 @@ ASE_DecodedImage ASE_DecodeImage(Arena *arena, String encoded)
num_chunks = frame_header.chunks_old; num_chunks = frame_header.chunks_old;
} }
//- Iterate chunks in frame //////////////////////////////
//- Iterate chunks
for (u32 j = 0; j < num_chunks; ++j) for (u32 j = 0; j < num_chunks; ++j)
{ {
u32 chunk_size = BB_ReadUBits(&br, 32); u32 chunk_size = BB_ReadUBits(&br, 32);
ASE_ChunkKind chunk_type = BB_ReadUBits(&br, 16); ASE_ChunkKind chunk_type = BB_ReadUBits(&br, 16);
/* Chunk size includes size & type */ // Chunk size includes size & type
Assert(chunk_size >= 6); Assert(chunk_size >= 6);
chunk_size -= 6; chunk_size -= 6;
@ -559,7 +564,9 @@ ASE_DecodedImage ASE_DecodeImage(Arena *arena, String encoded)
BB_ReadSeekToByte(&br, chunk_end_pos); BB_ReadSeekToByte(&br, chunk_end_pos);
} break; } break;
//////////////////////////////
//- Decode layer //- Decode layer
case ASE_ChunkKind_Layer: case ASE_ChunkKind_Layer:
{ {
ASE_Layer *layer = PushStruct(scratch.arena, ASE_Layer); ASE_Layer *layer = PushStruct(scratch.arena, ASE_Layer);
@ -570,7 +577,7 @@ ASE_DecodedImage ASE_DecodeImage(Arena *arena, String encoded)
layer->type = BB_ReadUBits(&br, 16); layer->type = BB_ReadUBits(&br, 16);
layer->child_level = BB_ReadUBits(&br, 16); layer->child_level = BB_ReadUBits(&br, 16);
/* Ignoring layer default width & height */ // Ignoring layer default width & height
BB_ReadSeekBytes(&br, sizeof(u16) * 2); BB_ReadSeekBytes(&br, sizeof(u16) * 2);
layer->blend_mode = BB_ReadUBits(&br, 16); layer->blend_mode = BB_ReadUBits(&br, 16);
@ -604,7 +611,9 @@ ASE_DecodedImage ASE_DecodeImage(Arena *arena, String encoded)
layer->index = num_layers++; layer->index = num_layers++;
} break; } break;
//////////////////////////////
//- Decode cel //- Decode cel
case ASE_ChunkKind_Cel: case ASE_ChunkKind_Cel:
{ {
Ace_Cel *cel = PushStruct(scratch.arena, Ace_Cel); Ace_Cel *cel = PushStruct(scratch.arena, Ace_Cel);
@ -632,14 +641,14 @@ ASE_DecodedImage ASE_DecodeImage(Arena *arena, String encoded)
{ {
case ASE_CelKind_RawImage: case ASE_CelKind_RawImage:
{ {
/* Unsupported */ // Unsupported
BB_ReadSeekToByte(&br, chunk_end_pos); BB_ReadSeekToByte(&br, chunk_end_pos);
} break; } break;
case ASE_CelKind_Linked: case ASE_CelKind_Linked:
{ {
cel->frame_pos = BB_ReadUBits(&br, 16); cel->frame_pos = BB_ReadUBits(&br, 16);
/* Actual linking happens later after iteration */ // Actual linking happens later after iteration
} break; } break;
case ASE_CelKind_CompressedImage: case ASE_CelKind_CompressedImage:
@ -657,7 +666,7 @@ ASE_DecodedImage ASE_DecodeImage(Arena *arena, String encoded)
case ASE_CelKind_CompressedTilemap: case ASE_CelKind_CompressedTilemap:
{ {
/* Unsupported */ // Unsupported
ASE_PushError(arena, &result.errors, Lit("Tilemaps are not supported")); ASE_PushError(arena, &result.errors, Lit("Tilemaps are not supported"));
goto abort; goto abort;
} break; } break;
@ -668,14 +677,18 @@ ASE_DecodedImage ASE_DecodeImage(Arena *arena, String encoded)
++num_frames; ++num_frames;
} }
//////////////////////////////
//- Create ordered layers array //- Create ordered layers array
ASE_Layer **layers_ordered = PushStructsNoZero(scratch.arena, ASE_Layer *, num_layers); ASE_Layer **layers_ordered = PushStructsNoZero(scratch.arena, ASE_Layer *, num_layers);
for (ASE_Layer *layer = layer_head; layer; layer = layer->next) for (ASE_Layer *layer = layer_head; layer; layer = layer->next)
{ {
layers_ordered[layer->index] = layer; layers_ordered[layer->index] = layer;
} }
//////////////////////////////
//- Link cels //- Link cels
Ace_Cel **cels_ordered = PushStructsNoZero(scratch.arena, Ace_Cel *, num_frames * num_layers); Ace_Cel **cels_ordered = PushStructsNoZero(scratch.arena, Ace_Cel *, num_frames * num_layers);
for (Ace_Cel *cel = cel_head; cel; cel = cel->next) for (Ace_Cel *cel = cel_head; cel; cel = cel->next)
{ {
@ -689,12 +702,14 @@ ASE_DecodedImage ASE_DecodeImage(Arena *arena, String encoded)
} }
} }
//////////////////////////////
//- Assemble image from cels //- Assemble image from cels
{ {
for (Ace_Cel *cel = cel_head; cel; cel = cel->next) for (Ace_Cel *cel = cel_head; cel; cel = cel->next)
{ {
ASE_Layer *layer = layers_ordered[cel->layer_index]; ASE_Layer *layer = layers_ordered[cel->layer_index];
/* Only draw visible layers */ // Only draw visible layers
if (layer->flags & 1) if (layer->flags & 1)
{ {
u8 opacity = (cel->opacity / 255.0f) * (layer->opacity / 255.0f) * 255.0f; u8 opacity = (cel->opacity / 255.0f) * (layer->opacity / 255.0f) * 255.0f;
@ -713,9 +728,9 @@ ASE_DecodedImage ASE_DecodeImage(Arena *arena, String encoded)
i32 image_left = frame_left + ((cel->frame_index % frames_x) * frame_width); i32 image_left = frame_left + ((cel->frame_index % frames_x) * frame_width);
i32 image_top = frame_top + ((cel->frame_index / frames_x) * frame_height); i32 image_top = frame_top + ((cel->frame_index / frames_x) * frame_height);
/* Adjust bounds to ensure pixels outside of frame boundaries // Adjust bounds to ensure pixels outside of frame boundaries
* aren't (aseprite keeps chunks outside of frame around in // aren't (aseprite keeps chunks outside of frame around in
* project file). */ // project file).
{ {
i32 frame_right = cel_width + frame_left; i32 frame_right = cel_width + frame_left;
i32 frame_bottom = frame_top + cel_height; i32 frame_bottom = frame_top + cel_height;
@ -758,7 +773,7 @@ ASE_DecodedImage ASE_DecodeImage(Arena *arena, String encoded)
} }
} }
/* Assert all data was read */ // Assert all data was read
Assert(BB_NumBytesRemaining(&br) == 0); Assert(BB_NumBytesRemaining(&br) == 0);
abort: abort:
@ -808,7 +823,9 @@ ASE_DecodedSheet ASE_DecodeSheet(Arena *arena, String encoded)
u32 num_slice_keys = 0; u32 num_slice_keys = 0;
ASE_SliceKey *first_slice_key = 0; ASE_SliceKey *first_slice_key = 0;
//////////////////////////////
//- Iterate frames //- Iterate frames
for (u16 i = 0; i < ase_header.frames; ++i) for (u16 i = 0; i < ase_header.frames; ++i)
{ {
ASE_FrameHeader frame_header; ASE_FrameHeader frame_header;
@ -839,13 +856,15 @@ ASE_DecodedSheet ASE_DecodeSheet(Arena *arena, String encoded)
frame->index = i; frame->index = i;
frame->duration = frame_header.frame_duration_ms / 1000.0; frame->duration = frame_header.frame_duration_ms / 1000.0;
//- Iterate chunks in frame //////////////////////////////
//- Iterate chunks
for (u32 j = 0; j < num_chunks; ++j) for (u32 j = 0; j < num_chunks; ++j)
{ {
u32 chunk_size = BB_ReadUBits(&br, 32); u32 chunk_size = BB_ReadUBits(&br, 32);
ASE_ChunkKind chunk_type = BB_ReadUBits(&br, 16); ASE_ChunkKind chunk_type = BB_ReadUBits(&br, 16);
/* Chunk size includes size & type */ // Chunk size includes size & type
Assert(chunk_size >= 6); Assert(chunk_size >= 6);
chunk_size -= 6; chunk_size -= 6;
@ -883,7 +902,9 @@ ASE_DecodedSheet ASE_DecodeSheet(Arena *arena, String encoded)
} break; } break;
//////////////////////////////
//- Decode slice //- Decode slice
case ASE_ChunkKind_Slice: case ASE_ChunkKind_Slice:
{ {
ASE_SliceKey *slice_key = PushStruct(arena, ASE_SliceKey); ASE_SliceKey *slice_key = PushStruct(arena, ASE_SliceKey);
@ -913,12 +934,12 @@ ASE_DecodedSheet ASE_DecodeSheet(Arena *arena, String encoded)
u32 height = BB_ReadUBits(&br, 32); u32 height = BB_ReadUBits(&br, 32);
if (flags & 0x01) if (flags & 0x01)
{ {
/* Skip 9-patches info */ // Skip 9-patches info
BB_ReadSeekBytes(&br, 128); BB_ReadSeekBytes(&br, 128);
} }
if (flags & 0x02) if (flags & 0x02)
{ {
/* Skip pivot info */ // Skip pivot info
BB_ReadSeekBytes(&br, 64); BB_ReadSeekBytes(&br, 64);
} }
@ -930,14 +951,14 @@ ASE_DecodedSheet ASE_DecodeSheet(Arena *arena, String encoded)
++num_slice_keys; ++num_slice_keys;
} break; } break;
/* TODO */ // TODO
//case ASE_ChunkKind_Userdata //case ASE_ChunkKind_Userdata
} }
} }
++num_frames; ++num_frames;
} }
/* Assert all data was read */ // Assert all data was read
Assert(BB_NumBytesRemaining(&br) == 0); Assert(BB_NumBytesRemaining(&br) == 0);
result.image_size = VEC2(image_width, image_height); result.image_size = VEC2(image_width, image_height);

View File

@ -52,7 +52,7 @@ Struct(ASE_DecodedImage)
{ {
u32 width; u32 width;
u32 height; u32 height;
u32 *pixels; /* Array of [width * height] pixels */ u32 *pixels; // Array of [width * height] pixels
ASE_ErrorList errors; ASE_ErrorList errors;
b32 ok; b32 ok;
}; };
@ -192,10 +192,10 @@ Struct(Ace_Cel)
ASE_CelKind type; ASE_CelKind type;
i16 z_index; i16 z_index;
/* Linked cel */ // Linked cel
u16 frame_pos; u16 frame_pos;
/* Compressed image */ // Compressed image
u32 width; u32 width;
u32 height; u32 height;
u32 *pixels; u32 *pixels;

View File

@ -96,11 +96,11 @@
#endif #endif
//- Cache line size //- Cache line size
/* TODO: Just hard-code to something like 128 or 256 if Apple silicon is ever supported */ // TODO: Just hard-code to something like 128 or 256 if Apple silicon is ever supported
#define CachelineSize 64 #define CachelineSize 64
//- Windows NTDDI version //- Windows NTDDI version
/* TODO: Remove this */ // TODO: Remove this
#if 0 #if 0
#if IsCompilerMsvc #if IsCompilerMsvc
#define NTDDI_WIN11_DT 0x0C0A0000 #define NTDDI_WIN11_DT 0x0C0A0000
@ -235,9 +235,8 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Linked list helper macros //~ Linked list helper macros
/* Taken from the rad debugger // Taken from the rad debugger
* https://github.com/EpicGamesExt/raddebugger/blob/be5634c44867a2e31f6a109df5e574930992df01/src/base/base_core.h#L239 // https://github.com/EpicGamesExt/raddebugger/blob/be5634c44867a2e31f6a109df5e574930992df01/src/base/base_core.h#L239
*/
#define CheckNil(nil,p) ((p) == 0 || (p) == nil) #define CheckNil(nil,p) ((p) == 0 || (p) == nil)
#define SetNil(nil,p) ((p) = nil) #define SetNil(nil,p) ((p) = nil)
@ -384,20 +383,19 @@
//~ Intrinsic headers //~ Intrinsic headers
#if IsLanguageC #if IsLanguageC
/* Intrinsic header info: // Intrinsic header info:
* mmintrin.h MMX // mmintrin.h MMX
* xmmintrin.h SSE // xmmintrin.h SSE
* emmintrin.h SSE2 // emmintrin.h SSE2
* pmmintrin.h SSE3 // pmmintrin.h SSE3
* tmmintrin.h SSSE3 // tmmintrin.h SSSE3
* smmintrin.h SSE4.1 // smmintrin.h SSE4.1
* nmmintrin.h SSE4.2 // nmmintrin.h SSE4.2
* ammintrin.h SSE4A // ammintrin.h SSE4A
* wmmintrin.h AES // wmmintrin.h AES
* immintrin.h AVX, AVX2, FMA // immintrin.h AVX, AVX2, FMA
*/
#include <intrin.h> #include <intrin.h>
#include <nmmintrin.h> /* SSE4.2 */ #include <nmmintrin.h> // SSE4.2
#endif #endif
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -602,7 +600,7 @@
ForceInline void UnlockTicketMutex(TicketMutex *tm) ForceInline void UnlockTicketMutex(TicketMutex *tm)
{ {
/* TODO: Atomic set w/ known ticket + 1 */ // TODO: Atomic set w/ known ticket + 1
Atomic64FetchAdd(&tm->serving.v, 1); Atomic64FetchAdd(&tm->serving.v, 1);
} }
#endif #endif
@ -705,10 +703,10 @@
#if IsLanguageC #if IsLanguageC
Struct(CpuTopologyInfo) Struct(CpuTopologyInfo)
{ {
i32 num_logical_cores; /* Includes P cores, Non-P cores, SMT siblings */ 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_cores; // Includes P Cores, Non-P Cores
i32 num_physical_performance_cores; /* Includes P Cores */ i32 num_physical_performance_cores; // Includes P Cores
i32 num_physical_non_performance_cores; /* Includes Non-P cores */ i32 num_physical_non_performance_cores; // Includes Non-P cores
}; };
#endif #endif

View File

@ -5,7 +5,7 @@ Arena *AcquireArena(u64 reserve)
{ {
reserve += ArenaHeaderSize; reserve += ArenaHeaderSize;
/* Round up to nearest block size */ // Round up to nearest block size
u64 block_remainder = reserve % ArenaBlockSize; u64 block_remainder = reserve % ArenaBlockSize;
if (block_remainder > 0) if (block_remainder > 0)
{ {
@ -20,22 +20,22 @@ Arena *AcquireArena(u64 reserve)
u64 reserved = reserve; u64 reserved = reserve;
AddGstat(ArenaMemoryReserved, reserve); AddGstat(ArenaMemoryReserved, reserve);
/* Commit initial block */ // Commit initial block
base = CommitMemory(base, ArenaBlockSize); base = CommitMemory(base, ArenaBlockSize);
if (!base) if (!base)
{ {
Panic(Lit("Failed to commit initial memory block: System may be out of memory")); Panic(Lit("Failed to commit initial memory block: System may be out of memory"));
} }
Assert(((u64)base & 0xFFF) == 0); /* Base should be 4k aligned */ Assert(((u64)base & 0xFFF) == 0); // Base should be 4k aligned
StaticAssert(ArenaHeaderSize <= ArenaBlockSize); /* Header must fit in first block */ StaticAssert(ArenaHeaderSize <= ArenaBlockSize); // Header must fit in first block
StaticAssert(sizeof(Arena) <= ArenaHeaderSize); /* Arena struct must fit in header */ StaticAssert(sizeof(Arena) <= ArenaHeaderSize); // Arena struct must fit in header
AsanPoison(base + sizeof(Arena), ArenaBlockSize - sizeof(Arena)); AsanPoison(base + sizeof(Arena), ArenaBlockSize - sizeof(Arena));
AddGstat(ArenaMemoryCommitted, ArenaBlockSize); AddGstat(ArenaMemoryCommitted, ArenaBlockSize);
AddGstat(NumArenas, 1); AddGstat(NumArenas, 1);
/* Create & return arena header at beginning of block */ // Create & return arena header at beginning of block
Arena *arena = (Arena *)base; Arena *arena = (Arena *)base;
ZeroStruct(arena); ZeroStruct(arena);
arena->committed = ArenaBlockSize - ArenaHeaderSize; arena->committed = ArenaBlockSize - ArenaHeaderSize;
@ -52,8 +52,8 @@ void ReleaseArena(Arena *arena)
ReleaseMemory(arena); ReleaseMemory(arena);
} }
/* Copy the memory from src to dst, replacing old contents. // Copy the memory from src to dst, replacing old content.
* Dst will expand if necessary. */ // Dst arena will expand if necessary.
void CopyArena(Arena *dst, Arena *src) void CopyArena(Arena *dst, Arena *src)
{ {
ResetArena(dst); ResetArena(dst);
@ -65,7 +65,7 @@ void CopyArena(Arena *dst, Arena *src)
void ShrinkArena(Arena *arena) void ShrinkArena(Arena *arena)
{ {
/* Not implemented */ // Not implemented
Assert(0); Assert(0);
} }
@ -97,7 +97,7 @@ void *PushBytesNoZero(Arena *arena, u64 size, u64 align)
u64 end_pos = start_pos + size; u64 end_pos = start_pos + size;
void *result = base + start_pos; void *result = base + start_pos;
/* Commit new block(s) */ // Commit new block(s)
if (size > 0 && end_pos > arena->committed) if (size > 0 && end_pos > arena->committed)
{ {
u64 blocks_needed = (end_pos - arena->committed + ArenaBlockSize - 1) / ArenaBlockSize; u64 blocks_needed = (end_pos - arena->committed + ArenaBlockSize - 1) / ArenaBlockSize;
@ -105,13 +105,13 @@ void *PushBytesNoZero(Arena *arena, u64 size, u64 align)
u64 new_capacity = arena->committed + commit_bytes; u64 new_capacity = arena->committed + commit_bytes;
if (new_capacity > arena->reserved) if (new_capacity > arena->reserved)
{ {
/* Hard fail if we overflow reserved memory for now */ // Hard fail if we overflow reserved memory for now
Panic(Lit("Failed to commit new memory block: Overflow of reserved memory")); Panic(Lit("Failed to commit new memory block: Overflow of reserved memory"));
} }
void *commit_address = base + arena->committed; void *commit_address = base + arena->committed;
if (!CommitMemory(commit_address, commit_bytes)) if (!CommitMemory(commit_address, commit_bytes))
{ {
/* Hard fail on memory allocation failure for now */ // Hard fail on memory allocation failure for now
Panic(Lit("Failed to commit new memory block: System may be out of memory")); Panic(Lit("Failed to commit new memory block: System may be out of memory"));
} }
arena->committed += commit_bytes; arena->committed += commit_bytes;
@ -196,10 +196,10 @@ void EndTempArena(TempArena temp)
TempArena BeginScratch(Arena *potential_conflict) TempArena BeginScratch(Arena *potential_conflict)
{ {
/* This function is currently hard-coded for 2 thread-local scratch arenas */ // This function is currently hard-coded for 2 thread-local scratch arenas
StaticAssert(countof(Base_tl.arenas.scratch) == 2); StaticAssert(countof(Base_tl.arenas.scratch) == 2);
/* Use `BeginScratchNoConflict` if no conflicts are present */ // Use `BeginScratchNoConflict` if no conflicts are present
Assert(potential_conflict != 0); Assert(potential_conflict != 0);
Arena *scratch_arena = Base_tl.arenas.scratch[0]; Arena *scratch_arena = Base_tl.arenas.scratch[0];

View File

@ -67,10 +67,10 @@ TempArena BeginScratch(Arena *potential_conflict);
TempArena BeginScratchNoConflict_(void); TempArena BeginScratchNoConflict_(void);
void EndScratch(TempArena scratch_temp); void EndScratch(TempArena scratch_temp);
/* This macro declares an unused "arena" variable that will produce a shadowing // This macro declares an unused "arena" variable that will produce a shadowing
* warning variable is present (due to shadowing). This is for catching obvious // warning variable is present (due to shadowing). This is for catching obvious
* cases of `BeginScratchNoConflict` getting called when an `arena` variable // cases of `BeginScratchNoConflict` getting called when an `arena` variable
* already exists in the caller's scope. */ // already exists in the caller's scope.
#define BeginScratchNoConflict() \ #define BeginScratchNoConflict() \
BeginScratchNoConflict_(); \ BeginScratchNoConflict_(); \
do { \ do { \

View File

@ -3,7 +3,7 @@
void BootstrapAsync(void) void BootstrapAsync(void)
{ {
/* TODO: Dynamic lane counts */ // TODO: Dynamic lane counts
DispatchWave(Lit("Async"), 4, AsyncWorkerEntryPoint, 0); DispatchWave(Lit("Async"), 4, AsyncWorkerEntryPoint, 0);
} }
@ -39,7 +39,7 @@ void AsyncWorkerEntryPoint(WaveLaneCtx *lane)
AsyncTickCtx tick = Zi; AsyncTickCtx tick = Zi;
tick.arena = AcquireArena(Gibi(64)); tick.arena = AcquireArena(Gibi(64));
/* Tick forever */ // Tick forever
for (;;) for (;;)
{ {
AsyncWorkerCtx *w = &Base.async.worker; AsyncWorkerCtx *w = &Base.async.worker;
@ -49,7 +49,7 @@ void AsyncWorkerEntryPoint(WaveLaneCtx *lane)
if (lane->idx == 0) if (lane->idx == 0)
{ {
/* Wait for signal */ // Wait for signal
{ {
i64 cur_signal = Atomic64Fetch(&Base.async.signal.v); i64 cur_signal = Atomic64Fetch(&Base.async.signal.v);
while (cur_signal <= w->last_seen_signal) while (cur_signal <= w->last_seen_signal)
@ -59,7 +59,7 @@ void AsyncWorkerEntryPoint(WaveLaneCtx *lane)
} }
w->last_seen_signal = cur_signal; w->last_seen_signal = cur_signal;
} }
/* Collect callbacks */ // Collect callbacks
{ {
Lock lock = LockE(&Base.async.mutex); Lock lock = LockE(&Base.async.mutex);
{ {

View File

@ -1,4 +1,4 @@
/* TODO: Safety check that functions taking byte length can't overflow bit conversion (log2(num_bytes) > 61) */ // TODO: Safety check that functions taking byte length can't overflow bit conversion (log2(num_bytes) > 61)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Buff management //~ Buff management
@ -13,7 +13,7 @@ BB_Buff BB_AcquireBuff(u64 arena_reserve)
void BB_ReleaseBuff(BB_Buff *bb) void BB_ReleaseBuff(BB_Buff *bb)
{ {
/* Only arena bitbuffs need to be released */ // Only arena bitbuffs need to be released
if (bb->is_backed_by_arena) if (bb->is_backed_by_arena)
{ {
ReleaseArena(bb->arena); ReleaseArena(bb->arena);
@ -49,7 +49,7 @@ BB_Writer BB_WriterFromBuff(BB_Buff *bb)
return result; return result;
} }
/* Use this when writing external formats that will not verify bitbuff debug symbols / magic numbers */ // Use this when writing external formats that will not verify bitbuff debug symbols / magic numbers
BB_Writer BB_WriterFromBuffNoDebug(BB_Buff *bb) BB_Writer BB_WriterFromBuffNoDebug(BB_Buff *bb)
{ {
BB_Writer result = BB_WriterFromBuff(bb); BB_Writer result = BB_WriterFromBuff(bb);
@ -59,19 +59,19 @@ BB_Writer BB_WriterFromBuffNoDebug(BB_Buff *bb)
return result; return result;
} }
/* FIXME: Handle overflowed bw */ // FIXME: Handle overflowed bw
u64 BB_GetNumBitsWritten(BB_Writer *bw) u64 BB_GetNumBitsWritten(BB_Writer *bw)
{ {
return bw->cur_bit; return bw->cur_bit;
} }
/* FIXME: Handle overflowed bw */ // FIXME: Handle overflowed bw
u64 BB_GetNumBytesWritten(BB_Writer *bw) u64 BB_GetNumBytesWritten(BB_Writer *bw)
{ {
return (bw->cur_bit + 7) >> 3; return (bw->cur_bit + 7) >> 3;
} }
/* FIXME: Handle overflowed bw */ // FIXME: Handle overflowed bw
String BB_GetWritten(Arena *arena, BB_Writer *bw) String BB_GetWritten(Arena *arena, BB_Writer *bw)
{ {
String result = Zi; String result = Zi;
@ -81,13 +81,13 @@ String BB_GetWritten(Arena *arena, BB_Writer *bw)
return result; return result;
} }
/* FIXME: Handle overflowed bw */ // FIXME: Handle overflowed bw
u8 *BB_GetWrittenRaw(BB_Writer *bw) u8 *BB_GetWrittenRaw(BB_Writer *bw)
{ {
return bw->base; return bw->base;
} }
/* Returns 1 if num_bits would cause the writer to overflow its fixed buffer size (if writer is not backed by a dynamic arena bitbuff) */ // Returns 1 if num_bits would cause the writer to overflow its fixed buffer size (if writer is not backed by a dynamic arena bitbuff)
b32 BB_CheckWriterOverflowBits(BB_Writer *bw, u64 num_bits) b32 BB_CheckWriterOverflowBits(BB_Writer *bw, u64 num_bits)
{ {
b32 result = 0; b32 result = 0;
@ -104,7 +104,7 @@ b32 BB_CheckWriterOverflowBits(BB_Writer *bw, u64 num_bits)
Arena *arena = bb->arena; Arena *arena = bb->arena;
if (bytes_needed >= arena->pos) if (bytes_needed >= arena->pos)
{ {
/* Grow arena */ // Grow arena
u64 push_size = (((bytes_needed - arena->pos) / BB_WriterOverflowArenaPushSize) + 1) * BB_WriterOverflowArenaPushSize; u64 push_size = (((bytes_needed - arena->pos) / BB_WriterOverflowArenaPushSize) + 1) * BB_WriterOverflowArenaPushSize;
PushStructsNoZero(arena, u8, push_size); PushStructsNoZero(arena, u8, push_size);
} }
@ -114,7 +114,7 @@ b32 BB_CheckWriterOverflowBits(BB_Writer *bw, u64 num_bits)
u64 max_len = bb->fixed_buffer.len; u64 max_len = bb->fixed_buffer.len;
if (bytes_needed > max_len) if (bytes_needed > max_len)
{ {
/* Writer overflowed fixed buffer */ // Writer overflowed fixed buffer
#if BITBUFF_DEBUG #if BITBUFF_DEBUG
Assert(0); Assert(0);
#endif #endif
@ -130,7 +130,7 @@ b32 BB_CheckWriterOverflowBits(BB_Writer *bw, u64 num_bits)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Align writer //~ Align writer
/* Align the pos to the next byte */ // Align the pos to the next byte
void BB_WriteAlignToNextByte(BB_Writer *bw) void BB_WriteAlignToNextByte(BB_Writer *bw)
{ {
#if BITBUFF_DEBUG #if BITBUFF_DEBUG
@ -164,7 +164,7 @@ void BB_WriteAlignBytes(BB_Writer *bw, u64 align)
void BB_WriteUBitsNoMagic(BB_Writer *bw, u64 value, u8 num_bits) void BB_WriteUBitsNoMagic(BB_Writer *bw, u64 value, u8 num_bits)
{ {
Assert(num_bits > 0 && (num_bits == 64 || value <= ~(U64Max << num_bits))); /* Bit count must be able to hold value */ Assert(num_bits > 0 && (num_bits == 64 || value <= ~(U64Max << num_bits))); // Bit count must be able to hold value
if (BB_CheckWriterOverflowBits(bw, num_bits)) if (BB_CheckWriterOverflowBits(bw, num_bits))
{ {
return; return;
@ -173,7 +173,7 @@ void BB_WriteUBitsNoMagic(BB_Writer *bw, u64 value, u8 num_bits)
u8 offset = bw->cur_bit & 7; u8 offset = bw->cur_bit & 7;
if (offset != 0) if (offset != 0)
{ {
/* Write unaligned bits */ // Write unaligned bits
u8 *at = bw->base + (bw->cur_bit >> 3); u8 *at = bw->base + (bw->cur_bit >> 3);
u8 num_mix_bits = MinU8((8 - offset), num_bits); u8 num_mix_bits = MinU8((8 - offset), num_bits);
u8 mix_byte = (u8)((value & ((1 << num_mix_bits) - 1)) << offset); u8 mix_byte = (u8)((value & ((1 << num_mix_bits) - 1)) << offset);
@ -183,7 +183,7 @@ void BB_WriteUBitsNoMagic(BB_Writer *bw, u64 value, u8 num_bits)
bw->cur_bit += num_mix_bits; bw->cur_bit += num_mix_bits;
} }
/* cur_bit is now aligned to byte */ // cur_bit is now aligned to byte
u8 *at = bw->base + (bw->cur_bit >> 3); u8 *at = bw->base + (bw->cur_bit >> 3);
u8 num_bytes = (num_bits + 7) >> 3; u8 num_bytes = (num_bits + 7) >> 3;
CopyBytes(at, &value, num_bytes); CopyBytes(at, &value, num_bytes);
@ -211,7 +211,7 @@ void BB_WriteIBits(BB_Writer *bw, i64 value, u8 num_bits)
BB_WriteUBits(bw, ubits, num_bits); BB_WriteUBits(bw, ubits, num_bits);
} }
/* Returns written bit to make writing delta encoding logic cleaner */ // Returns written bit to make writing delta encoding logic cleaner
b32 BB_WriteBit(BB_Writer *bw, u8 value) b32 BB_WriteBit(BB_Writer *bw, u8 value)
{ {
BB_WriteUBits(bw, value, 1); BB_WriteUBits(bw, value, 1);
@ -221,8 +221,8 @@ b32 BB_WriteBit(BB_Writer *bw, u8 value)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Write variable length integers //~ Write variable length integers
/* Writes a variable length unsigned integer. // Writes a variable length unsigned integer.
* Value is written in chunks of 7 bits w/ 8th bit signaling continuation. */ // Value is written in chunks of 7 bits w/ 8th bit signaling continuation.
void BB_WriteUV(BB_Writer *bw, u64 value) void BB_WriteUV(BB_Writer *bw, u64 value)
{ {
BB_WriteDebugMagic(bw, BB_DebugMagicKind_UV, 0); BB_WriteDebugMagic(bw, BB_DebugMagicKind_UV, 0);
@ -235,9 +235,9 @@ void BB_WriteUV(BB_Writer *bw, u64 value)
BB_WriteUBits(bw, value, 8); BB_WriteUBits(bw, value, 8);
} }
/* Writes a variable length signed integer. // Writes a variable length signed integer.
* Similar to BB_WriteUV, except the 7th bit of the first byte is a sign bit // Similar to BB_WriteUV, except the 7th bit of the first byte is a sign bit
* indicating that the value is stored in twos compliment. */ // indicating that the value is stored in twos compliment.
void BB_WriteIV(BB_Writer *bw, i64 value) void BB_WriteIV(BB_Writer *bw, i64 value)
{ {
BB_WriteDebugMagic(bw, BB_DebugMagicKind_IV, 0); BB_WriteDebugMagic(bw, BB_DebugMagicKind_IV, 0);
@ -263,11 +263,11 @@ void BB_WriteIV(BB_Writer *bw, i64 value)
tc = BB_TwosComplimentFromUint(-value, num_bits); tc = BB_TwosComplimentFromUint(-value, num_bits);
} }
/* First byte contains not just cont bit, but sign bit as well. */ // First byte contains not just cont bit, but sign bit as well.
u8 first_byte = (tc & 0x3F); u8 first_byte = (tc & 0x3F);
tc >>= 6; tc >>= 6;
first_byte |= (tc > 0) << 7; /* Cont bit */ first_byte |= (tc > 0) << 7; // Cont bit
first_byte |= sign_bit << 6; /* Sign bit */ first_byte |= sign_bit << 6; // Sign bit
BB_WriteUBits(bw, first_byte, 8); BB_WriteUBits(bw, first_byte, 8);
if (tc > 0) if (tc > 0)
@ -319,7 +319,7 @@ void BB_WriteString(BB_Writer *bw, String s)
void BB_WriteBytes(BB_Writer *bw, String bytes) void BB_WriteBytes(BB_Writer *bw, String bytes)
{ {
/* Align start of bytes */ // Align start of bytes
BB_WriteAlignToNextByte(bw); BB_WriteAlignToNextByte(bw);
u64 num_bits = bytes.len << 3; u64 num_bits = bytes.len << 3;
@ -397,7 +397,7 @@ BB_Reader BB_ReaderFromBuff(BB_Buff *bb)
return result; return result;
} }
/* Use this when reading from external formats that will not contain bitbuff debug symbols / magic numbers */ // Use this when reading from external formats that will not contain bitbuff debug symbols / magic numbers
BB_Reader BB_ReaderFromBuffNoDebug(BB_Buff *bb) BB_Reader BB_ReaderFromBuffNoDebug(BB_Buff *bb)
{ {
BB_Reader result = BB_ReaderFromBuff(bb); BB_Reader result = BB_ReaderFromBuff(bb);
@ -407,29 +407,29 @@ BB_Reader BB_ReaderFromBuffNoDebug(BB_Buff *bb)
return result; return result;
} }
/* Returns the number of bits read from the bitbuff */ // Returns the number of bits read from the bitbuff
/* FIXME: Handle overflowed br */ // FIXME: Handle overflowed br
u64 BB_GetCurrentReaderBit(BB_Reader *br) u64 BB_GetCurrentReaderBit(BB_Reader *br)
{ {
return br->cur_bit; return br->cur_bit;
} }
/* Returns the number of *full* bytes read from the bitbuff */ // Returns the number of *full* bytes read from the bitbuff
/* FIXME: Handle overflowed br */ // FIXME: Handle overflowed br
u64 BB_GetCurrentReaderByte(BB_Reader *br) u64 BB_GetCurrentReaderByte(BB_Reader *br)
{ {
return br->cur_bit >> 3; return br->cur_bit >> 3;
} }
/* Returns the number of bits left until the bitbuff overflows */ // Returns the number of bits left until the bitbuff overflows
/* FIXME: Handle overflowed br */ // FIXME: Handle overflowed br
u64 BB_NumBitsRemaining(BB_Reader *br) u64 BB_NumBitsRemaining(BB_Reader *br)
{ {
return (br->base_len << 3) - br->cur_bit; return (br->base_len << 3) - br->cur_bit;
} }
/* Returns the number of *full* bytes left until the bitbuff overflows */ // Returns the number of *full* bytes left until the bitbuff overflows
/* FIXME: Handle overflowed br */ // FIXME: Handle overflowed br
u64 BB_NumBytesRemaining(BB_Reader *br) u64 BB_NumBytesRemaining(BB_Reader *br)
{ {
return br->base_len - (br->cur_bit >> 3); return br->base_len - (br->cur_bit >> 3);
@ -448,7 +448,7 @@ b32 BB_CheckReaderOverflowBits(BB_Reader *br, u64 num_bits)
u64 base_len_bits = br->base_len << 3; u64 base_len_bits = br->base_len << 3;
if (bits_needed > base_len_bits) if (bits_needed > base_len_bits)
{ {
/* Tried to read past bitbuff memory */ // Tried to read past bitbuff memory
#if BITBUFF_DEBUG #if BITBUFF_DEBUG
Assert(0); Assert(0);
#endif #endif
@ -463,7 +463,7 @@ b32 BB_CheckReaderOverflowBits(BB_Reader *br, u64 num_bits)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Align reader //~ Align reader
/* Align the pos to the next byte */ // Align the pos to the next byte
void BB_ReadAlignToNextByte(BB_Reader *br) void BB_ReadAlignToNextByte(BB_Reader *br)
{ {
#if BITBUFF_DEBUG #if BITBUFF_DEBUG
@ -518,7 +518,7 @@ u64 BB_ReadUBitsNoMagic(BB_Reader *br, u8 num_bits)
br->cur_bit += num_trailing_bits; br->cur_bit += num_trailing_bits;
} }
/* cur_bit is now aligned to byte */ // cur_bit is now aligned to byte
u8 *at = br->base + (br->cur_bit >> 3); u8 *at = br->base + (br->cur_bit >> 3);
u8 num_bytes = (num_bits + 7) >> 3; u8 num_bytes = (num_bits + 7) >> 3;
u64 tmp = 0; u64 tmp = 0;
@ -556,8 +556,8 @@ u8 BB_ReadBit(BB_Reader *br)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Read variable length integer //~ Read variable length integer
/* Read a variable length unsigned integer. // Read a variable length unsigned integer.
* See BB_WriteUV for details. */ // See BB_WriteUV for details.
u64 BB_ReadUV(BB_Reader *br) u64 BB_ReadUV(BB_Reader *br)
{ {
BB_ReadDebugMagic(br, BB_DebugMagicKind_UV, 0); BB_ReadDebugMagic(br, BB_DebugMagicKind_UV, 0);
@ -576,8 +576,8 @@ u64 BB_ReadUV(BB_Reader *br)
return result; return result;
} }
/* Read a variable length signed integer. // Read a variable length signed integer.
* See BB_WriteIV for details. */ // See BB_WriteIV for details.
i64 BB_ReadIV(BB_Reader *br) i64 BB_ReadIV(BB_Reader *br)
{ {
BB_ReadDebugMagic(br, BB_DebugMagicKind_IV, 0); BB_ReadDebugMagic(br, BB_DebugMagicKind_IV, 0);
@ -606,7 +606,7 @@ i64 BB_ReadIV(BB_Reader *br)
i64 result; i64 result;
if (sign_bit) if (sign_bit)
{ {
/* Sign bit is 1, indicating result is stored in twos compliment */ // Sign bit is 1, indicating result is stored in twos compliment
result = BB_IntFromTwosCompliment(tc, num_bits); result = BB_IntFromTwosCompliment(tc, num_bits);
} }
else else
@ -663,7 +663,7 @@ String BB_ReadString(Arena *arena, BB_Reader *br)
return result; return result;
} }
/* Will fill dst with zeroes if bitbuff overflows */ // Will fill dst with zeroes if bitbuff overflows
void BB_ReadBytes(BB_Reader *br, String out) void BB_ReadBytes(BB_Reader *br, String out)
{ {
u8 *src = BB_ReadBytesRaw(br, out.len); u8 *src = BB_ReadBytesRaw(br, out.len);
@ -677,7 +677,7 @@ void BB_ReadBytes(BB_Reader *br, String out)
} }
} }
/* Will return 0 on bitbuff overflow. Result should be checked. */ // Will return 0 on bitbuff overflow. Result should be checked.
u8 *BB_ReadBytesRaw(BB_Reader *br, u64 num_bytes) u8 *BB_ReadBytesRaw(BB_Reader *br, u64 num_bytes)
{ {
BB_ReadAlignToNextByte(br); BB_ReadAlignToNextByte(br);
@ -716,7 +716,7 @@ void BB_ReadSeekToByte(BB_Reader *br, u64 pos)
} }
else else
{ {
/* Tried to seek byte backwards in reader */ // Tried to seek byte backwards in reader
Assert(0); Assert(0);
br->overflowed = 1; br->overflowed = 1;
br->cur_bit = (br->base_len << 3); br->cur_bit = (br->base_len << 3);
@ -740,10 +740,10 @@ void BB_ReadDebugMagic(BB_Reader *br, BB_DebugMagicKind expected_magic, u8 expec
BB_DebugMagicKind stored_magic = stored & 0xFFFF; BB_DebugMagicKind stored_magic = stored & 0xFFFF;
u8 stored_num_bits = (stored >> 16) & 0xFF; u8 stored_num_bits = (stored >> 16) & 0xFF;
/* Verify stored magic match */ // Verify stored magic match
Assert(expected_magic == stored_magic); Assert(expected_magic == stored_magic);
/* Verify stored bit count match */ // Verify stored bit count match
Assert(expected_num_bits == stored_num_bits); Assert(expected_num_bits == stored_num_bits);
} }
} }

View File

@ -1,20 +1,18 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Bitbuff types //~ Bitbuff types
//- Buff
Struct(BB_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) */ // If `is_arena_bitbuff` is 1, this dynamically-sized arena will be used for reading & writing (meaning writing cannot overflow)
Arena *arena; Arena *arena;
/* If `is_arena_bitbuff` is 0, this fixed-sized buffer willl be used for reading & writing */ // If `is_arena_bitbuff` is 0, this fixed-sized buffer willl be used for reading & writing
String fixed_buffer; String fixed_buffer;
}; };
//- Writer // NOTE: base_len is not stored with the writer (as it is with the reader) since a dynamic arena-backed bitbuff could grow, meaning len needs to be re-checked
/* NOTE: base_len is not stored with the writer (as it is with the reader) since a dynamic arena-backed bitbuff could grow, meaning len needs to be re-checked */
#define BB_WriterOverflowArenaPushSize 4096 #define BB_WriterOverflowArenaPushSize 4096
Struct(BB_Writer) Struct(BB_Writer)
{ {
@ -27,7 +25,6 @@ Struct(BB_Writer)
#endif #endif
}; };
//- Reader
Struct(BB_Reader) Struct(BB_Reader)
{ {
b32 overflowed; b32 overflowed;
@ -44,7 +41,7 @@ Struct(BB_Reader)
#if BITBUFF_DEBUG #if BITBUFF_DEBUG
/* Magic numbers inserted to verify read/write type & length */ // Magic numbers inserted to verify read/write type & length
Enum(BB_DebugMagicKind) Enum(BB_DebugMagicKind)
{ {
BB_DebugMagicKind_AlignBytes = 0x20A4, BB_DebugMagicKind_AlignBytes = 0x20A4,

View File

@ -1,17 +1,17 @@
/* TODO: Elminiate meta arena. Just store levels in first 4096 bytes of buddy arena, and then zone header data at the beginning of each allocation. */ // TODO: Elminiate meta arena. Just store levels in first 4096 bytes of buddy arena, and then zone header data at the beginning of each allocation.
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Buddy context //~ Buddy context
BuddyCtx *AcquireBuddyCtx(u64 reserve) BuddyCtx *AcquireBuddyCtx(u64 reserve)
{ {
/* TODO: Determine meta reserve dynamically */ // TODO: Determine meta reserve dynamically
Arena *meta_arena = AcquireArena(Gibi(64)); Arena *meta_arena = AcquireArena(Gibi(64));
BuddyCtx *ctx = PushStruct(meta_arena, BuddyCtx); BuddyCtx *ctx = PushStruct(meta_arena, BuddyCtx);
ctx->meta_arena = meta_arena; ctx->meta_arena = meta_arena;
ctx->data_arena = AcquireArena(reserve); ctx->data_arena = AcquireArena(reserve);
/* TODO: Minimum block size */ // TODO: Minimum block size
ctx->levels = PushStructs(ctx->meta_arena, BuddyLevel, 64); ctx->levels = PushStructs(ctx->meta_arena, BuddyLevel, 64);
for (u64 i = 0; i < 64; ++i) for (u64 i = 0; i < 64; ++i)
{ {
@ -37,7 +37,7 @@ 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) if (level->first_unused_block)
{ {
block = level->first_unused_block; block = level->first_unused_block;
@ -56,14 +56,14 @@ BuddyBlock *GetUnusedBuddyBlock(BuddyCtx *ctx, BuddyLevel *level)
BuddyLevel *parent_level = &ctx->levels[level->tier + 1]; BuddyLevel *parent_level = &ctx->levels[level->tier + 1];
BuddyBlock *parent_block = GetUnusedBuddyBlock(ctx, parent_level); BuddyBlock *parent_block = GetUnusedBuddyBlock(ctx, parent_level);
/* Create left (used) block from parent block */ // Create left (used) block from parent block
BuddyBlock *left = PushBuddyBlock(ctx); BuddyBlock *left = PushBuddyBlock(ctx);
left->is_used = 1; left->is_used = 1;
left->level = level; left->level = level;
left->parent = parent_block; left->parent = parent_block;
left->memory = parent_block->memory; left->memory = parent_block->memory;
/* Create right LAX block from parent block */ // Create right (unused) block from parent block
BuddyBlock *right = PushBuddyBlock(ctx); BuddyBlock *right = PushBuddyBlock(ctx);
right->is_used = 0; right->is_used = 0;
right->level = level; right->level = level;
@ -84,7 +84,7 @@ BuddyBlock *GetUnusedBuddyBlock(BuddyCtx *ctx, BuddyLevel *level)
{ {
Arena *arena = ctx->data_arena; Arena *arena = ctx->data_arena;
/* Grow arena */ // Grow arena
i64 level_commit_diff = (level->size * 2) - arena->pos; i64 level_commit_diff = (level->size * 2) - arena->pos;
if (level_commit_diff > 0) if (level_commit_diff > 0)
{ {
@ -92,13 +92,13 @@ BuddyBlock *GetUnusedBuddyBlock(BuddyCtx *ctx, BuddyLevel *level)
Assert(arena->pos == (level->size * 2)); Assert(arena->pos == (level->size * 2));
} }
/* Create left (used) block from existing child block memory */ // Create left (used) block from existing child block memory
BuddyBlock *left = PushBuddyBlock(ctx); BuddyBlock *left = PushBuddyBlock(ctx);
left->is_used = 1; left->is_used = 1;
left->level = level; left->level = level;
left->memory = ArenaFirst(arena, u8); left->memory = ArenaFirst(arena, u8);
/* Create right LAX block from new arena memory */ // Create right (unused) block from new arena memory
BuddyBlock *right = PushBuddyBlock(ctx); BuddyBlock *right = PushBuddyBlock(ctx);
right->is_used = 0; right->is_used = 0;
right->level = level; right->level = level;
@ -133,7 +133,7 @@ BuddyBlock *PushBuddyBlock(BuddyCtx *ctx)
void PopBuddyBlock(BuddyCtx *ctx, BuddyLevel *level, BuddyBlock *block) void PopBuddyBlock(BuddyCtx *ctx, BuddyLevel *level, BuddyBlock *block)
{ {
/* Remove from unused list */ // Remove from unused list
{ {
BuddyBlock *prev = block->prev; BuddyBlock *prev = block->prev;
BuddyBlock *next = block->next; BuddyBlock *next = block->next;
@ -158,13 +158,13 @@ BuddyBlock *AcquireBuddyBlock(BuddyCtx *ctx, u64 size)
{ {
if (size > 0x00FFFFFFFFFFFFFFULL) if (size > 0x00FFFFFFFFFFFFFFULL)
{ {
/* TODO: Error */ // TODO: Error
Assert(0); 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_block_size = 1;
u64 desired_level_tier = 0; u64 desired_level_tier = 0;
@ -187,11 +187,11 @@ void ReleaseBuddyBlock(BuddyBlock *block)
BuddyBlock *sibling = block->sibling; BuddyBlock *sibling = block->sibling;
if (!sibling->is_used && parent != 0) if (!sibling->is_used && parent != 0)
{ {
/* Merge siblings */ // Merge siblings
BuddyCtx *ctx = level->ctx; BuddyCtx *ctx = level->ctx;
PopBuddyBlock(ctx, level, block); PopBuddyBlock(ctx, level, block);
PopBuddyBlock(ctx, level, sibling); PopBuddyBlock(ctx, level, sibling);
/* Release parent */ // Release parent
ReleaseBuddyBlock(parent); ReleaseBuddyBlock(parent);
} }
else else

View File

@ -9,7 +9,7 @@ Struct(BuddyBlock)
BuddyBlock *parent; BuddyBlock *parent;
BuddyBlock *sibling; BuddyBlock *sibling;
/* Links to block in level's unused list or in ctx's free list */ // Links to block in level's unused list or in ctx's free list
BuddyBlock *prev; BuddyBlock *prev;
BuddyBlock *next; BuddyBlock *next;
@ -20,7 +20,7 @@ Struct(BuddyBlock)
Struct(BuddyLevel) Struct(BuddyLevel)
{ {
struct BuddyCtx *ctx; struct BuddyCtx *ctx;
b32 backed; /* Signals whether this level is backed by memory in the ctx arena */ b32 backed; // Signals whether this level is backed by memory in the ctx arena
u32 tier; u32 tier;
u64 size; u64 size;
BuddyBlock *first_unused_block; BuddyBlock *first_unused_block;

View File

@ -133,18 +133,18 @@ Struct(ControllerEvent)
{ {
ControllerEventKind kind; ControllerEventKind kind;
/* ControllerEventKind_ButtonDown */ // ControllerEventKind_ButtonDown
/* ControllerEventKind_ButtonUp */ // ControllerEventKind_ButtonUp
Button button; Button button;
b32 is_repeat; b32 is_repeat;
/* ControllerEventKind_Text */ // ControllerEventKind_Text
u32 text_codepoint; u32 text_codepoint;
/* ControllerEventKind_CursorMove */ // ControllerEventKind_CursorMove
Vec2I32 cursor_pos; Vec2I32 cursor_pos;
/* ControllerEventKind_MouseMove */ // ControllerEventKind_MouseMove
Vec2I32 mouse_delta; Vec2I32 mouse_delta;
}; };

View File

@ -1,8 +1,8 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ @hookdecl Not-equal futex ops //~ @hookdecl Not-equal futex ops
/* Similar to Win32 WaitOnAddress & WakeByAddressAll // Similar to Win32 WaitOnAddress & WakeByAddressAll
* i.e. - Suprious wait until value at address != cmp */ // i.e. - Suprious wait until value at address != cmp
void FutexYieldNeq(volatile void *addr, void *cmp, u8 cmp_size); void FutexYieldNeq(volatile void *addr, void *cmp, u8 cmp_size);
void FutexWakeNeq(void *addr); void FutexWakeNeq(void *addr);
@ -10,13 +10,11 @@ void FutexWakeNeq(void *addr);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ @hookdecl Greater-than-or-equal futex ops //~ @hookdecl Greater-than-or-equal futex ops
/* Similar to Win32 WaitOnAddress & WakeByAddressAll // Similar to Win32 WaitOnAddress & WakeByAddressAll
* i.e. - Spurious wait until monotonically increasing value at address >= cmp (used for fences) // i.e. - Spurious wait until monotonically increasing value at address >= cmp (used for fences)
* // NOTE: This API is offered for fence-like semantics, where waiters only want to
* NOTE: This API is offered for fence-like semantics, where waiters only want to // wake when the futex progresses past the specified target value, rather than
* wake when the futex progresses past the specified target value, rather than // wake every time the futex is modified.
* wake every time the futex is modified.
*/
void FutexYieldGte(volatile void *addr, void *cmp, u8 cmp_size); void FutexYieldGte(volatile void *addr, void *cmp, u8 cmp_size);
void FutexWakeGte(void *addr); void FutexWakeGte(void *addr);

View File

@ -1,4 +1,4 @@
/* Application wide statistics */ // Application wide statistics
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Gstat types //~ Gstat types

View File

@ -26,7 +26,7 @@ Struct(LogEventsArray)
#define LogLevel(l) (l <= LogLevel_CompTime) #define LogLevel(l) (l <= LogLevel_CompTime)
/* Log level configuration */ // Log level configuration
#ifndef LogLevel_CompTime #ifndef LogLevel_CompTime
#if IsRtcEnabled #if IsRtcEnabled
#define LogLevel_CompTime LogLevel_Debug #define LogLevel_CompTime LogLevel_Debug
@ -132,7 +132,7 @@ Global Readonly LogLevelSettings log_settings[LogLevel_Count] = {
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ @hookdecl Log //~ @hookdecl Log
/* NOTE: Calling these functions rather than using the logging macros may result in logs that are compiled regardless of log level. */ // NOTE: Calling these functions rather than using the logging macros may result in logs that are compiled regardless of log level.
void LogPanic(String msg); void LogPanic(String msg);
void Log_(i32 level, String msg); void Log_(i32 level, String msg);

View File

@ -1,4 +1,4 @@
/* Math functions are default 32 bit (f32, i32, etc) unless specified */ // Math functions are default 32 bit (f32, i32, etc) unless specified
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Min / max //~ Min / max
@ -163,7 +163,7 @@ i64 SignF64(f64 f)
//- Pow u64 //- Pow u64
/* Taken from https://gist.github.com/orlp/3551590 */ // Taken from https://gist.github.com/orlp/3551590
u64 PowU64(u64 base, u8 exp) u64 PowU64(u64 base, u8 exp)
{ {
PERSIST const u8 highest_bit_set[] = { PERSIST const u8 highest_bit_set[] = {
@ -174,7 +174,7 @@ u64 PowU64(u64 base, u8 exp)
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 255, /* Anything past 63 is a guaranteed overflow with base > 1 */ 6, 6, 6, 6, 6, 6, 6, 255, // Anything past 63 is a guaranteed overflow with base > 1
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
@ -207,7 +207,7 @@ u64 PowU64(u64 base, u8 exp)
{ {
case 255: case 255:
{ {
/* 255 = overflow, return 0 */ // 255 = overflow, return 0
if (base == 1) if (base == 1)
{ {
return 1; return 1;
@ -258,8 +258,8 @@ u64 PowU64(u64 base, u8 exp)
//- Logn //- Logn
/* Based on FreeBSD's implementation // Based on FreeBSD's implementation
* https://github.com/freebsd/freebsd-src/blob/main/lib/msun/src/e_logf.c */ // https://github.com/freebsd/freebsd-src/blob/main/lib/msun/src/e_logf.c
f32 LnF32(f32 x) f32 LnF32(f32 x)
{ {
PERSIST const f32 ln2_hi = 6.9313812256e-01f; PERSIST const f32 ln2_hi = 6.9313812256e-01f;
@ -273,12 +273,12 @@ f32 LnF32(f32 x)
f32 two_p25 = 3.3554432000e+07; f32 two_p25 = 3.3554432000e+07;
if ((x_int & 0x7fffffff) == 0) if ((x_int & 0x7fffffff) == 0)
{ {
/* Return -inf if x is 0 */ // Return -inf if x is 0
return -F32Infinity; return -F32Infinity;
} }
else if (x_int < 0) else if (x_int < 0)
{ {
/* Return NaN if x is negative */ // Return NaN if x is negative
return F32Nan; return F32Nan;
} }
k -= 25; k -= 25;
@ -352,8 +352,8 @@ f32 LnF32(f32 x)
//- Exp //- Exp
/* Based on FreeBSD's implementation // Based on FreeBSD's implementation
* https://github.com/freebsd/freebsd-src/blob/main/lib/msun/src/e_expf.c */ // https://github.com/freebsd/freebsd-src/blob/main/lib/msun/src/e_expf.c
f32 ExpF32(f32 x) f32 ExpF32(f32 x)
{ {
PERSIST const f32 half[2] = { 0.5, -0.5 }; PERSIST const f32 half[2] = { 0.5, -0.5 };
@ -369,12 +369,12 @@ f32 ExpF32(f32 x)
i32 x_sign_bit = (i32)((x_uint >> 31) & 1); i32 x_sign_bit = (i32)((x_uint >> 31) & 1);
x_uint &= 0x7fffffff; x_uint &= 0x7fffffff;
/* Filter out non-finite argument */ // Filter out non-finite argument
if (x_uint >= 0x42b17218) if (x_uint >= 0x42b17218)
{ /* if |x|>=88.721... */ { // if |x|>=88.721...
if (x_uint > 0x7f800000) if (x_uint > 0x7f800000)
{ {
return x + x; /* NaN */ return x + x; // NaN
} }
else if (x_uint == 0x7f800000) else if (x_uint == 0x7f800000)
{ {
@ -382,17 +382,17 @@ f32 ExpF32(f32 x)
} }
if (x > o_threshold) if (x > o_threshold)
{ {
/* Overflow */ // Overflow
return F32Infinity; return F32Infinity;
} }
else if (x < u_threshold) else if (x < u_threshold)
{ {
/* Underflow */ // Underflow
return two_m100 * two_m100; return two_m100 * two_m100;
} }
} }
/* Argument reduction */ // Argument reduction
i32 k = 0; i32 k = 0;
f32 hi = 0; f32 hi = 0;
f32 lo = 0; f32 lo = 0;
@ -467,12 +467,12 @@ f32 PowF32(f32 a, f32 b)
{ {
if (a >= 0) if (a >= 0)
{ {
/* a is positive */ // a is positive
return ExpF32(LnF32(a) * b); return ExpF32(LnF32(a) * b);
} }
else else
{ {
/* a is negative */ // a is negative
i32 res_sign = RoundF32ToI32(b) % 2 == 0 ? 1 : -1; i32 res_sign = RoundF32ToI32(b) % 2 == 0 ? 1 : -1;
return ExpF32(LnF32(-a) * b) * res_sign; return ExpF32(LnF32(-a) * b) * res_sign;
} }
@ -526,24 +526,25 @@ u64 AlignU64ToNextPow2(u64 x)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Trig //~ Trig
/* Functions based on Cephes implementation (https://www.netlib.org/cephes/): // Functions based on Cephes implementation (https://www.netlib.org/cephes/):
* - SinApproxF32 // - SinApproxF32
* - CosApproxF32 // - CosApproxF32
* - ReduceToPio4 // - ReduceToPio4
* - ArcTanF32 // - ArcTanF32
*/
//- Reduce //- Reduce
/* Reduce postive x to range [0, Pi/4] (Cody-Waite argument reduction). //
* Returns 0 if x > (2^24 - 1); // Reduce postive x to range [0, Pi/4] (Cody-Waite argument reduction)
* Sets octant_out=-1 on error. */ //
// Returns 0 if x > (2^24 - 1)
// Sets octant_out=-1 on error
f32 ReduceToPio4(f32 x, i32 *octant_out) f32 ReduceToPio4(f32 x, i32 *octant_out)
{ {
i32 octant = -1; i32 octant = -1;
if (x <= ((1 << 24) - 1)) if (x <= ((1 << 24) - 1))
{ {
octant = (i32)(x * (4 / Pi)); /* Integer part of x/(Pi/4) */ octant = (i32)(x * (4 / Pi)); // Integer part of x/(Pi/4)
f32 y = (f32)octant; f32 y = (f32)octant;
if (octant & 1) if (octant & 1)
{ {
@ -551,7 +552,7 @@ f32 ReduceToPio4(f32 x, i32 *octant_out)
y += 1.0; y += 1.0;
} }
/* Modulo 360 degrees */ // Modulo 360 degrees
octant &= 7; octant &= 7;
if (x > 8192) if (x > 8192)
@ -560,7 +561,7 @@ f32 ReduceToPio4(f32 x, i32 *octant_out)
} }
else else
{ {
/* Extended precision modular arithmetic */ // Extended precision modular arithmetic
x = ((x - y * 0.78515625) - y * 2.4187564849853515625e-4) - y * 3.77489497744594108e-8; x = ((x - y * 0.78515625) - y * 2.4187564849853515625e-4) - y * 3.77489497744594108e-8;
} }
} }
@ -570,7 +571,8 @@ f32 ReduceToPio4(f32 x, i32 *octant_out)
} }
//- Sin approximation //- Sin approximation
/* Approximate sin in range [0, Pi/4] */ //
// Approximate sin in range [0, Pi/4]
f32 SinApproxF32(f32 x) f32 SinApproxF32(f32 x)
{ {
f32 x_sq = x * x; f32 x_sq = x * x;
@ -602,7 +604,7 @@ f32 SinF32(f32 x)
i32 octant; i32 octant;
x = ReduceToPio4(x, &octant); x = ReduceToPio4(x, &octant);
/* Reflect in x axis */ // Reflect in x axis
if (octant > 3) if (octant > 3)
{ {
sign = -sign; sign = -sign;
@ -634,7 +636,7 @@ f32 CosF32(f32 x)
i32 octant; i32 octant;
x = ReduceToPio4(x, &octant); x = ReduceToPio4(x, &octant);
/* Reflect in x axis */ // Reflect in x axis
if (octant > 3) if (octant > 3)
{ {
sign = -sign; sign = -sign;
@ -664,15 +666,15 @@ f32 ArcTanF32(f32 x)
x = -x; x = -x;
} }
/* Reduce range */ // Reduce range
f32 y; f32 y;
if (x > 2.414213562373095) if (x > 2.414213562373095)
{ /* tan((Pi / 8) * 3) */ { // tan((Pi / 8) * 3)
y = Pi / 2; y = Pi / 2;
x = -(1.f / x); x = -(1.f / x);
} }
else if (x > 0.4142135623730950) else if (x > 0.4142135623730950)
{ /* tan(Pi / 8) */ { // tan(Pi / 8)
y = Pi / 4; y = Pi / 4;
x = (x - 1.f) / (x + 1.f); x = (x - 1.f) / (x + 1.f);
} }
@ -740,21 +742,21 @@ f32 ArcTan2F32(f32 y, f32 x)
//- ArcSin //- ArcSin
f32 ArcSinF32(f32 x) f32 ArcSinF32(f32 x)
{ {
/* TODO: Dedicated arcsin approximation */ // TODO: Dedicated arcsin approximation
return ArcTan2F32(x, SqrtF32(1.0f - (x * x))); return ArcTan2F32(x, SqrtF32(1.0f - (x * x)));
} }
//- ArcCos //- ArcCos
f32 ArcCosF32(f32 x) f32 ArcCosF32(f32 x)
{ {
/* TODO: Dedicated arccos approximation */ // TODO: Dedicated arccos approximation
return (Pi / 2.0f) - ArcTan2F32(x, SqrtF32(1.0f - (x * x))); return (Pi / 2.0f) - ArcTan2F32(x, SqrtF32(1.0f - (x * x)));
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Angle unwind //~ Angle unwind
/* Returns angle in range [-Pi, Pi] */ // Returns angle in range [-Pi, Pi]
f32 UnwindAngleF32(f32 a) f32 UnwindAngleF32(f32 a)
{ {
f32 d = ModF32(a, Tau); f32 d = ModF32(a, Tau);
@ -987,21 +989,21 @@ f32 DotVec2(Vec2 a, Vec2 b)
return a.x * b.x + a.y * b.y; return a.x * b.x + a.y * b.y;
} }
/* Returns signed area between vectors (positive in clockwise direction) // Returns signed area between vectors (positive in clockwise direction)
* AKA perpendicular dot product // AKA perpendicular dot product
* AKA 2d cross-product */ // AKA 2d cross-product
f32 WedgeVec2(Vec2 a, Vec2 b) f32 WedgeVec2(Vec2 a, Vec2 b)
{ {
return a.x * b.y - a.y * b.x; return a.x * b.y - a.y * b.x;
} }
/* Clockwise (right) perpendicular vector */ // Clockwise (right) perpendicular vector
Vec2 PerpVec2(Vec2 a) Vec2 PerpVec2(Vec2 a)
{ {
return VEC2(-a.y, a.x); return VEC2(-a.y, a.x);
} }
/* Clockwise (right) perpendicular vector scaled by s */ // Clockwise (right) perpendicular vector scaled by s
Vec2 MulPerpVec2(Vec2 a, f32 s) Vec2 MulPerpVec2(Vec2 a, f32 s)
{ {
return VEC2(s * -a.y, s * a.x); return VEC2(s * -a.y, s * a.x);
@ -1047,7 +1049,7 @@ Vec2I32 CeilVec2ToI32(Vec2 a)
//- Angle //- Angle
/* Returns 1 if winding between vectors a & b is clockwise or straight, -1 if counter-clockwise */ // Returns 1 if winding between vectors a & b is clockwise or straight, -1 if counter-clockwise
i32 WindingFromVec2(Vec2 a, Vec2 b) i32 WindingFromVec2(Vec2 a, Vec2 b)
{ {
f32 w = WedgeVec2(a, b); f32 w = WedgeVec2(a, b);
@ -1093,7 +1095,7 @@ Vec2 ClosestPointFromRay(Vec2 ray_pos, Vec2 ray_dir_norm, Vec2 p)
//- Lerp //- Lerp
/* Interpolate position vectors */ // Interpolate position vectors
Vec2 LerpVec2(Vec2 val0, Vec2 val1, f32 t) Vec2 LerpVec2(Vec2 val0, Vec2 val1, f32 t)
{ {
return VEC2(LerpF32(val0.x, val1.x, t), LerpF32(val0.y, val1.y, t)); return VEC2(LerpF32(val0.x, val1.x, t), LerpF32(val0.y, val1.y, t));
@ -1104,7 +1106,7 @@ Vec2 LerpVec2Vec2(Vec2 val0, Vec2 val1, Vec2 t)
return VEC2(LerpF32(val0.x, val1.x, t.x), LerpF32(val0.y, val1.y, t.y)); return VEC2(LerpF32(val0.x, val1.x, t.x), LerpF32(val0.y, val1.y, t.y));
} }
/* Interpolate direction vectors (spherical lerp) */ // Interpolate direction vectors (spherical lerp)
Vec2 SlerpVec2(Vec2 val0, Vec2 val1, f32 t) Vec2 SlerpVec2(Vec2 val0, Vec2 val1, f32 t)
{ {
f32 rot = LerpAngleF32(AngleFromVec2(val0), AngleFromVec2(val1), t); f32 rot = LerpAngleF32(AngleFromVec2(val0), AngleFromVec2(val1), t);
@ -1424,7 +1426,7 @@ Vec2 InvertXformBasisMulV2(Xform xf, Vec2 v)
return result; return result;
} }
/* TODO: Get rid of this? Just force caller to use invert manually since it's expensive. */ // TODO: Get rid of this? Just force caller to use invert manually since it's expensive.
Vec2 InvertXformMulV2(Xform xf, Vec2 v) Vec2 InvertXformMulV2(Xform xf, Vec2 v)
{ {
Xform inv = InvertXform(xf); Xform inv = InvertXform(xf);
@ -1479,7 +1481,7 @@ Vec2 ScaleFromXform(Xform xf)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Spring //~ Spring
/* https://box2d.org/files/ErinCatto_SoftConstraints_GDC2011.pdf */ // https://box2d.org/files/ErinCatto_SoftConstraints_GDC2011.pdf
SoftSpring MakeSpring(f32 hertz, f32 damping_ratio, f32 dt) SoftSpring MakeSpring(f32 hertz, f32 damping_ratio, f32 dt)
{ {
SoftSpring result; SoftSpring result;

View File

@ -1,4 +1,4 @@
/* Math functions are default 32 bit (f32, i32, etc) unless specified */ // Math functions are default 32 bit (f32, i32, etc) unless specified
#define Pi ((f32)3.14159265358979323846) #define Pi ((f32)3.14159265358979323846)
#define Tau ((f32)6.28318530717958647693) #define Tau ((f32)6.28318530717958647693)
@ -145,12 +145,12 @@ Struct(Rng3U64) { Vec3U64 p0; Vec3U64 p1; };
Struct(Xform) Struct(Xform)
{ {
Vec2 bx; /* X basis vector (x axis) */ Vec2 bx; // X basis vector (x axis)
Vec2 by; /* Y basis vector (y axis)*/ Vec2 by; // Y basis vector (y axis)
Vec2 og; /* Translation vector (origin) */ Vec2 og; // Translation vector (origin)
}; };
/* (T)ranslation, (R)otation, (S)cale */ // (T)ranslation, (R)otation, (S)cale
Struct(Trs) Struct(Trs)
{ {
Vec2 t; Vec2 t;
@ -285,7 +285,7 @@ f32 ArcCosF32(f32 x);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Angle unwind //~ Angle unwind
/* Returns angle in range [-Pi, Pi] */ // Returns angle in range [-Pi, Pi]
f32 UnwindAngleF32(f32 a); f32 UnwindAngleF32(f32 a);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////

View File

@ -46,4 +46,4 @@ i32 memcmp(const void *p1, const void *p2, u64 count)
return result; return result;
} }
#endif /* !IsCrtlibEnabled */ #endif

View File

@ -14,9 +14,8 @@ 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" // Based on Jon Maiga's "mx3"
* https://jonkagstrom.com/mx3/mx3_rev2.html // https://jonkagstrom.com/mx3/mx3_rev2.html
*/
u64 RandU64FromSeed(u64 seed) u64 RandU64FromSeed(u64 seed)
{ {
seed = (seed ^ (seed >> 32)) * 0xbea225f9eb34556d; seed = (seed ^ (seed >> 32)) * 0xbea225f9eb34556d;

View File

@ -3,11 +3,11 @@
Struct(RandState) 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 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 counter;
}; };
/* TODO: Use a value that gives good precision when dividing into range 0 -> 1 */ // TODO: Use a value that gives good precision when dividing into range 0 -> 1
#define RandMaxF64 U64Max #define RandMaxF64 U64Max
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////

View File

@ -15,7 +15,7 @@ void BootstrapResources(u64 archive_strings_count, String *archive_strings)
u64 magic = BB_ReadUBits(&br, 64); u64 magic = BB_ReadUBits(&br, 64);
Assert(magic == ResourceEmbeddedMagic); Assert(magic == ResourceEmbeddedMagic);
/* Create & insert entries */ // Create & insert entries
u64 num_entries = BB_ReadUBits(&br, 64); u64 num_entries = BB_ReadUBits(&br, 64);
for (u64 i = 0; i < num_entries; ++i) for (u64 i = 0; i < num_entries; ++i)
{ {

View File

@ -161,7 +161,7 @@ Vec2 NdcFromUv(Vec2 uv)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ String helpers //~ String helpers
/* https://therealmjp.github.io/posts/hlsl-printf/ */ // https://therealmjp.github.io/posts/hlsl-printf/
template<typename T> template<typename T>
u32 U32FromChar(in T c) u32 U32FromChar(in T c)
{ {

View File

@ -1,8 +1,6 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Conversion helpers //~ Conversion helpers
//- Char conversion
String StringFromChar(Arena *arena, char c) String StringFromChar(Arena *arena, char c)
{ {
u8 *dst = PushStructNoZero(arena, u8); u8 *dst = PushStructNoZero(arena, u8);
@ -14,16 +12,14 @@ String StringFromChar(Arena *arena, char c)
}; };
} }
//- Unsigned int conversion
String StringFromUint(Arena *arena, u64 n, u64 base, u64 zfill) String StringFromUint(Arena *arena, u64 n, u64 base, u64 zfill)
{ {
/* Base too large */ // Base too large
Assert(base <= (countof(IntChars) - 1)); Assert(base <= (countof(IntChars) - 1));
String result = Zi; String result = Zi;
TempArena scratch = BeginScratch(arena); TempArena scratch = BeginScratch(arena);
{ {
/* Build backwards text starting from least significant digit */ // Build backwards text starting from least significant digit
u8 *backwards_text = ArenaNext(scratch.arena, u8); u8 *backwards_text = ArenaNext(scratch.arena, u8);
do do
{ {
@ -38,7 +34,7 @@ String StringFromUint(Arena *arena, u64 n, u64 base, u64 zfill)
++result.len; ++result.len;
} }
/* Reverse text into final string */ // Reverse text into final string
result.text = PushStructsNoZero(arena, u8, result.len); result.text = PushStructsNoZero(arena, u8, result.len);
for (u64 i = 0; i < result.len; ++i) for (u64 i = 0; i < result.len; ++i)
{ {
@ -67,8 +63,6 @@ String StringFromUints(Arena *arena, u64 uints_count, u64 *uints, u64 base, u64
return result; return result;
} }
//- Signed int conversion
String StringFromSint(Arena *arena, i64 n, u64 base, u64 zfill) String StringFromSint(Arena *arena, i64 n, u64 base, u64 zfill)
{ {
String result = Zi; String result = Zi;
@ -99,8 +93,6 @@ String StringFromSints(Arena *arena, u64 sints_count, i64 *sints, u64 base, u64
return result; return result;
} }
//- Floating point conversion
String StringFromFloat(Arena *arena, f64 f, u32 precision) String StringFromFloat(Arena *arena, f64 f, u32 precision)
{ {
String result = Zi; String result = Zi;
@ -128,15 +120,15 @@ String StringFromFloat(Arena *arena, f64 f, u32 precision)
++result.len; ++result.len;
} }
/* Add one half of next precision level to round up */ // Add one half of next precision level to round up
f += 0.5 / (f64)PowU64(10, (u8)precision); f += 0.5 / (f64)PowU64(10, (u8)precision);
f64 part_whole = TruncF64(f); f64 part_whole = TruncF64(f);
f64 part_decimal = f - part_whole; f64 part_decimal = f - part_whole;
/* Print whole part */ // Print whole part
{ {
/* Build backwards text starting from least significant digit */ // Build backwards text starting from least significant digit
u8 *backwards_text = ArenaNext(scratch.arena, u8); u8 *backwards_text = ArenaNext(scratch.arena, u8);
u64 backwards_text_len = 0; u64 backwards_text_len = 0;
do do
@ -147,7 +139,7 @@ String StringFromFloat(Arena *arena, f64 f, u32 precision)
part_whole = TruncF64(part_whole / 10.0); part_whole = TruncF64(part_whole / 10.0);
} while (part_whole > 0); } while (part_whole > 0);
/* Reverse text into final string */ // Reverse text into final string
PushStructsNoZero(arena, u8, backwards_text_len); PushStructsNoZero(arena, u8, backwards_text_len);
for (u64 i = backwards_text_len; i-- > 0;) for (u64 i = backwards_text_len; i-- > 0;)
{ {
@ -155,7 +147,7 @@ String StringFromFloat(Arena *arena, f64 f, u32 precision)
} }
} }
/* Print decimal part */ // Print decimal part
if (precision > 0) if (precision > 0)
{ {
StringFromChar(arena, '.'); StringFromChar(arena, '.');
@ -191,8 +183,6 @@ String StringFromFloats(Arena *arena, u64 floats_count, f64 *floats, u32 precisi
return result; return result;
} }
//- Pointer conversion
String StringFromPtr(Arena *arena, void *ptr) String StringFromPtr(Arena *arena, void *ptr)
{ {
String prepend = PushString(arena, Lit("0x")); String prepend = PushString(arena, Lit("0x"));
@ -204,8 +194,6 @@ String StringFromPtr(Arena *arena, void *ptr)
}; };
} }
//- Handle conversion
String StringFromhandle(Arena *arena, u64 v0, u64 v1) String StringFromhandle(Arena *arena, u64 v0, u64 v1)
{ {
String result = Zi; String result = Zi;
@ -217,8 +205,6 @@ String StringFromhandle(Arena *arena, u64 v0, u64 v1)
return result; return result;
} }
//- Uid conversion
String StringFromUid(Arena *arena, Uid uid) String StringFromUid(Arena *arena, Uid uid)
{ {
String result = Zi; String result = Zi;
@ -227,12 +213,9 @@ String StringFromUid(Arena *arena, Uid uid)
return result; return result;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ String helpers //~ String helpers
//- Copy
String PushString(Arena *arena, String src) String PushString(Arena *arena, String src)
{ {
String result = Zi; String result = Zi;
@ -251,8 +234,6 @@ String CopyString(String dst, String src)
return result; return result;
} }
//- Repeat
String RepeatString(Arena *arena, String src, u64 count) String RepeatString(Arena *arena, String src, u64 count)
{ {
u64 final_len = src.len * count; u64 final_len = src.len * count;
@ -268,8 +249,6 @@ String RepeatString(Arena *arena, String src, u64 count)
}; };
} }
//- Concatenate
String CatString(Arena *arena, String str1, String str2) String CatString(Arena *arena, String str1, String str2)
{ {
String new_str = Zi; String new_str = Zi;
@ -280,10 +259,8 @@ String CatString(Arena *arena, String str1, String str2)
return new_str; return new_str;
} }
//- Split // `arena` is where pieces will be allocated. These strings point
// into the existing string and do not allocate any new text.
/* `arena` is where pieces will be allocated. These strings point
* into the existing string and do not allocate any new text. */
StringArray SplitString(Arena *arena, String str, String delim) StringArray SplitString(Arena *arena, String str, String delim)
{ {
StringArray pieces = Zi; StringArray pieces = Zi;
@ -359,9 +336,7 @@ String ReplaceString(Arena *arena, String str, String old_pattern, String new_pa
return result; return result;
} }
//- Indent // NOTE: Really slow
/* NOTE: Really slow */
String IndentString(Arena *arena, String str, u32 indent) String IndentString(Arena *arena, String str, u32 indent)
{ {
TempArena scratch = BeginScratch(arena); TempArena scratch = BeginScratch(arena);
@ -396,8 +371,6 @@ String IndentString(Arena *arena, String str, u32 indent)
}; };
} }
//- Lower
String LowerString(Arena *arena, String str) String LowerString(Arena *arena, String str)
{ {
String result = Zi; String result = Zi;
@ -417,8 +390,6 @@ String LowerString(Arena *arena, String str)
return result; return result;
} }
//- Compare
b32 MatchString(String str1, String str2) b32 MatchString(String str1, String str2)
{ {
b32 eq = 1; b32 eq = 1;
@ -440,8 +411,6 @@ b32 MatchString(String str1, String str2)
return eq; return eq;
} }
//- Match
b32 StringContains(String str, String substring) b32 StringContains(String str, String substring)
{ {
if (substring.len > str.len) if (substring.len > str.len)
@ -606,25 +575,27 @@ String TrimWhitespace(String s)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Formatting //~ Formatting
/* String formatting only has one format specifier: "%F". All specifier info is //
* included in the arguments (instead of w/ the specifier like in printf). // String formatting only has one format specifier: "%F". All specifier info is
* // included in the arguments (instead of w/ the specifier like in printf).
* Example: //
* FormatString(arena, Lit("Hello there %F"), FmtString(Lit("George"))) // Example:
* // FormatString(arena, Lit("Hello there %F"), FmtString(Lit("George")))
* NOTE: FmtEnd must be passed as the last arg in the va_list //
* // NOTE: FmtEnd must be passed as the last arg in the va_list
* Format arguments: //
* FmtChar: Format a single u8 character // Format arguments:
* FmtString: Format a `string` struct // FmtChar: Format a single u8 character
* FmtUint: Format a u64 // FmtString: Format a `string` struct
* FmtSint: Format an i64 // FmtUint: Format a u64
* FmtFloat: Format an f64 with DefaultFmtPrecision // FmtSint: Format an i64
* FmtHex: Format a u64 in hexadecimal notation // FmtFloat: Format an f64 with DefaultFmtPrecision
* FmtPtr: Format a pointer in hexadecimal notation prefixed by "0x" // FmtHex: Format a u64 in hexadecimal notation
* // FmtPtr: Format a pointer in hexadecimal notation prefixed by "0x"
* FmtEnd (internal): Denote the end of the va_list //
*/ // FmtEnd (internal): Denote the end of the va_list
//
String FormatString(Arena *arena, String fmt, FmtArgArray args) String FormatString(Arena *arena, String fmt, FmtArgArray args)
{ {
String result = Zi; String result = Zi;
@ -637,11 +608,11 @@ String FormatString(Arena *arena, String fmt, FmtArgArray args)
{ {
u8 *next = ((c + 1) < end) ? (c + 1) : (u8 *)"\0"; u8 *next = ((c + 1) < end) ? (c + 1) : (u8 *)"\0";
/* Escape '%%' */ // Escape '%%'
b32 escape = !no_more_valid_args && *c == '%' && *next == '%'; b32 escape = !no_more_valid_args && *c == '%' && *next == '%';
if (escape) if (escape)
{ {
/* Skip the escaped '%' char from parsing */ // Skip the escaped '%' char from parsing
++c; ++c;
} }
@ -664,7 +635,7 @@ String FormatString(Arena *arena, String fmt, FmtArgArray args)
{ {
default: default:
{ {
/* Unknown format type */ // Unknown format type
Assert(0); Assert(0);
parsed_arg = PushString(arena, Lit("<?>")); parsed_arg = PushString(arena, Lit("<?>"));
no_more_valid_args = 1; no_more_valid_args = 1;
@ -762,22 +733,22 @@ String FormatString(Arena *arena, String fmt, FmtArgArray args)
case FmtArgKind_End: case FmtArgKind_End:
{ {
/* Unexpected end. Not enough FMT args passed to function. */ // Unexpected end. Not enough FMT args passed to function.
Assert(0); Assert(0);
parsed_arg = PushString(arena, Lit("<?>")); parsed_arg = PushString(arena, Lit("<?>"));
no_more_valid_args = 1; no_more_valid_args = 1;
} break; } break;
} }
/* Update final string len / start */ // Update final string len / start
result.len += parsed_arg.len; result.len += parsed_arg.len;
/* Skip 'F' from parsing */ // Skip 'F' from parsing
++c; ++c;
} }
else else
{ {
/* Parse character normally */ // Parse character normally
StringFromChar(arena, *c); StringFromChar(arena, *c);
++result.len; ++result.len;
} }
@ -791,7 +762,7 @@ String FormatString(Arena *arena, String fmt, FmtArgArray args)
if (arg_idx < args.count) if (arg_idx < args.count)
{ {
last_arg = args.args[arg_idx]; last_arg = args.args[arg_idx];
/* End arg not reached. Too many args supplied. */ // End arg not reached. Too many args supplied.
Assert(last_arg.kind == FmtArgKind_End); Assert(last_arg.kind == FmtArgKind_End);
} }
} }
@ -829,7 +800,7 @@ FmtArgArray FmtArgsFromVaList(Arena *arena, va_list args)
{ {
default: default:
{ {
/* End/Invalid arg reached */ // End/Invalid arg reached
done = 1; done = 1;
} break; } break;
@ -852,7 +823,7 @@ FmtArgArray FmtArgsFromVaList(Arena *arena, va_list args)
case FmtArgKind_Uid: case FmtArgKind_Uid:
case FmtArgKind_Handle: case FmtArgKind_Handle:
{ {
/* Continue */ // Continue
} break; } break;
} }
} }
@ -863,8 +834,6 @@ FmtArgArray FmtArgsFromVaList(Arena *arena, va_list args)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Unicode //~ Unicode
//- Codepoint iteration
CodepointIter InitCodepointIter(String str) CodepointIter InitCodepointIter(String str)
{ {
return (CodepointIter) return (CodepointIter)
@ -873,7 +842,7 @@ CodepointIter InitCodepointIter(String str)
}; };
} }
/* Returns 0 if done iterating */ // Returns 0 if done iterating
b32 NextCodepoint(CodepointIter *iter) b32 NextCodepoint(CodepointIter *iter)
{ {
if (iter->pos < iter->src.len) if (iter->pos < iter->src.len)
@ -890,9 +859,7 @@ b32 NextCodepoint(CodepointIter *iter)
} }
} }
//- String decode // utf8 <- utf16
/* utf8 <- utf16 */
String StringFromString16(Arena *arena, String16 str16) String StringFromString16(Arena *arena, String16 str16)
{ {
String result = { String result = {
@ -917,7 +884,7 @@ String StringFromString16(Arena *arena, String16 str16)
return result; return result;
} }
/* utf8 <- utf32 */ // utf8 <- utf32
String StringFromString32(Arena *arena, String32 str32) String StringFromString32(Arena *arena, String32 str32)
{ {
String result = { String result = {
@ -942,9 +909,7 @@ String StringFromString32(Arena *arena, String32 str32)
return result; return result;
} }
//- String encode // utf16 <- utf8
/* utf16 <- utf8 */
String16 String16FromString(Arena *arena, String str8) String16 String16FromString(Arena *arena, String str8)
{ {
String16 result = { String16 result = {
@ -969,7 +934,7 @@ String16 String16FromString(Arena *arena, String str8)
return result; return result;
} }
/* utf32 <- utf8 */ // utf32 <- utf8
String32 String32FromString(Arena *arena, String str8) String32 String32FromString(Arena *arena, String str8)
{ {
String32 result = { String32 result = {
@ -997,8 +962,6 @@ String32 String32FromString(Arena *arena, String str8)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Null-terminated strings //~ Null-terminated strings
//- Narrow C strings
u64 CstrLenNoLimit(char *cstr) u64 CstrLenNoLimit(char *cstr)
{ {
char *end = cstr; char *end = cstr;
@ -1071,8 +1034,6 @@ String StringFromCstr(char *cstr, u64 limit)
}; };
} }
//- Wide C strings
u64 WstrLenNoLimit(wchar_t *wstr) u64 WstrLenNoLimit(wchar_t *wstr)
{ {
wchar_t *end = wstr; wchar_t *end = wstr;

View File

@ -8,7 +8,7 @@ Enum(FmtArgKind)
{ {
FmtArgKind_None, FmtArgKind_None,
/* Arbitrary magic numbers for argument validation */ // Arbitrary magic numbers for argument validation
FmtArgKind_Char = 0xf5281df, FmtArgKind_Char = 0xf5281df,
FmtArgKind_String = 0xa5ffa9a, FmtArgKind_String = 0xa5ffa9a,
@ -38,8 +38,8 @@ Enum(FmtArgKind)
Struct(FmtArg) Struct(FmtArg)
{ {
FmtArgKind kind; FmtArgKind kind;
u32 p; /* Precision */ u32 p; // Precision
u32 z; /* Z-fill */ u32 z; // Z-fill
union union
{ {
u8 c; u8 c;
@ -69,7 +69,7 @@ Struct(CodepointIter)
{ {
u32 codepoint; u32 codepoint;
/* Internal */ // Internal
String src; String src;
u64 pos; u64 pos;
}; };
@ -146,7 +146,7 @@ String StringFromList(Arena *arena, StringList l, String separator);
#define FmtHandle(v, ...) FMTARG(FmtArgKind_Handle, .value.handle.h64[0] = (v).idx, .value.handle.h64[1] = (v).gen, __VA_ARGS__) #define FmtHandle(v, ...) FMTARG(FmtArgKind_Handle, .value.handle.h64[0] = (v).idx, .value.handle.h64[1] = (v).gen, __VA_ARGS__)
#define FmtUid(v, ...) FMTARG(FmtArgKind_Uid, .value.uid = (v), __VA_ARGS__) #define FmtUid(v, ...) FMTARG(FmtArgKind_Uid, .value.uid = (v), __VA_ARGS__)
#define FmtEnd FMTARG(FmtArgKind_End) /* Denotes end of VA list */ #define FmtEnd FMTARG(FmtArgKind_End) // Denotes end of VA list
String FormatString(Arena *arena, String fmt, FmtArgArray args); String FormatString(Arena *arena, String fmt, FmtArgArray args);
String StringF_(Arena *arena, String fmt, ...); String StringF_(Arena *arena, String fmt, ...);

View File

@ -1,8 +1,7 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Mutex //~ Mutex
//- Exclusive mutex lock Lock ExclusiveLockEx(Mutex *m, i32 spin)
Lock LockSpinE(Mutex *m, i32 spin)
{ {
b32 locked = 0; b32 locked = 0;
i32 spin_cnt = 0; i32 spin_cnt = 0;
@ -16,7 +15,7 @@ Lock LockSpinE(Mutex *m, i32 spin)
} }
else if (v == 0x40000000) else if (v == 0x40000000)
{ {
/* Lock has pending bit set, try to lock */ // Lock has pending bit set, try to lock
u32 swp = Atomic32FetchTestSet(&m->v, v, 0x80000000); u32 swp = Atomic32FetchTestSet(&m->v, v, 0x80000000);
while (swp != v && swp == 0x40000000) while (swp != v && swp == 0x40000000)
{ {
@ -31,7 +30,7 @@ Lock LockSpinE(Mutex *m, i32 spin)
} }
if (!locked && (v & 0xC0000000) == 0) if (!locked && (v & 0xC0000000) == 0)
{ {
/* Lock has shared lockers and no pending waiter, set pending bit */ // Lock has shared lockers and no pending waiter, set pending bit
u32 swp = Atomic32FetchTestSet(&m->v, v, v | 0x40000000); u32 swp = Atomic32FetchTestSet(&m->v, v, v | 0x40000000);
while (swp != v && (swp & 0xC0000000) == 0 && swp != 0) while (swp != v && (swp & 0xC0000000) == 0 && swp != 0)
{ {
@ -40,7 +39,7 @@ Lock LockSpinE(Mutex *m, i32 spin)
} }
v = swp; v = swp;
} }
/* Pause or wait */ // Pause or wait
if (!locked && v != 0 && v != 0x40000000) if (!locked && v != 0 && v != 0x40000000)
{ {
if (spin_cnt < spin) if (spin_cnt < spin)
@ -65,8 +64,7 @@ Lock LockSpinE(Mutex *m, i32 spin)
return lock; return lock;
} }
//- Shared mutex lock Lock SharedLockEx(Mutex *m, i32 spin)
Lock LockSpinS(Mutex *m, i32 spin)
{ {
b32 locked = 0; b32 locked = 0;
i32 spin_cnt = 0; i32 spin_cnt = 0;
@ -76,7 +74,7 @@ Lock LockSpinS(Mutex *m, i32 spin)
u32 v = Atomic32Fetch(&m->v); u32 v = Atomic32Fetch(&m->v);
while (!locked && (v & 0xC0000000) == 0) while (!locked && (v & 0xC0000000) == 0)
{ {
/* Lock has no exclusive or pending exclusive lock, increment shared count */ // Lock has no exclusive or pending exclusive lock, increment shared count
u32 swp = Atomic32FetchTestSet(&m->v, v, v + 1); u32 swp = Atomic32FetchTestSet(&m->v, v, v + 1);
if (v == swp) if (v == swp)
{ {
@ -87,7 +85,7 @@ Lock LockSpinS(Mutex *m, i32 spin)
v = swp; v = swp;
} }
} }
/* Pause or wait */ // Pause or wait
if (!locked) if (!locked)
{ {
if (spin_cnt < spin) if (spin_cnt < spin)
@ -106,15 +104,14 @@ Lock LockSpinS(Mutex *m, i32 spin)
return lock; return lock;
} }
//- Mutex lock wrappers
Lock LockE(Mutex *m) Lock LockE(Mutex *m)
{ {
return LockSpinE(m, DefaultMutexSpin); return ExclusiveLockEx(m, DefaultMutexSpin);
} }
Lock LockS(Mutex *m) Lock LockS(Mutex *m)
{ {
return LockSpinS(m, DefaultMutexSpin); return SharedLockEx(m, DefaultMutexSpin);
} }
void Unlock(Lock *l) void Unlock(Lock *l)

View File

@ -5,22 +5,21 @@
AlignedStruct(Mutex, CachelineSize) AlignedStruct(Mutex, CachelineSize)
{ {
/* Bit 31 = Exclusive lock is held // Bit 31 = Exclusive lock is held
* Bit 30 = Exclusive lock is pending // Bit 30 = Exclusive lock is pending
* Bit 0-30 = Shared locks count // Bit 0-30 = Shared locks count
*/ Atomic32 v;
Atomic32 v;
#if IsRtcEnabled #if IsRtcEnabled
Atomic32 exclusive_thread_id; Atomic32 exclusive_thread_id;
#endif #endif
}; };
StaticAssert(alignof(Mutex) == CachelineSize && sizeof(Mutex) % CachelineSize == 0); StaticAssert(alignof(Mutex) == CachelineSize && sizeof(Mutex) % CachelineSize == 0);
Struct(Lock) Struct(Lock)
{ {
Mutex *mutex; Mutex *mutex;
b32 exclusive; b32 exclusive;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -28,7 +27,7 @@ Struct(Lock)
AlignedStruct(Cv, CachelineSize) AlignedStruct(Cv, CachelineSize)
{ {
Atomic64 wake_gen; Atomic64 wake_gen;
}; };
StaticAssert(alignof(Cv) == CachelineSize && sizeof(Cv) % CachelineSize == 0); StaticAssert(alignof(Cv) == CachelineSize && sizeof(Cv) % CachelineSize == 0);
@ -37,14 +36,14 @@ StaticAssert(alignof(Cv) == CachelineSize && sizeof(Cv) % CachelineSize == 0);
Struct(Fence) Struct(Fence)
{ {
Atomic64Padded v; Atomic64Padded v;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Mutex //~ Mutex
Lock LockSpinE(Mutex *m, i32 spin); Lock ExclusiveLockEx(Mutex *m, i32 spin);
Lock LockSpinS(Mutex *m, i32 spin); Lock SharedLockEx(Mutex *m, i32 spin);
Lock LockE(Mutex *m); Lock LockE(Mutex *m);
Lock LockS(Mutex *m); Lock LockS(Mutex *m);

View File

@ -1,4 +1,4 @@
/* Returns a uid generated from the system's random number generator */ // Returns a uid generated from the system's random number generator
Uid UidFromTrueRand(void) Uid UidFromTrueRand(void)
{ {
Uid result = Zi; Uid result = Zi;
@ -6,7 +6,7 @@ Uid UidFromTrueRand(void)
return result; return result;
} }
/* Combines 2 uids into a new uid */ // Combines 2 uids into a new uid
Uid CombineUid(Uid a, Uid b) Uid CombineUid(Uid a, Uid b)
{ {
Uid result; Uid result;

View File

@ -123,7 +123,7 @@ Utf8EncodeResult EncodeUtf8(u32 codepoint)
} }
else else
{ {
/* Invalid codepoint */ // Invalid codepoint
result.count8 = 1; result.count8 = 1;
result.chars8[0] = '?'; result.chars8[0] = '?';
} }
@ -183,7 +183,7 @@ Utf16EncodeResult EncodeUtf16(u32 codepoint)
} }
else else
{ {
/* Invalid codepoint */ // Invalid codepoint
result.count16 = 1; result.count16 = 1;
result.chars16[0] = '?'; result.chars16[0] = '?';
} }
@ -241,7 +241,7 @@ Utf32EncodeResult EncodeUtf32(u32 codepoint)
} }
else else
{ {
/* Invalid codepoint */ // Invalid codepoint
result.chars32 = '?'; result.chars32 = '?';
} }

View File

@ -6,11 +6,10 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Mergesort types //~ Mergesort types
/* Compare functions should // Compare functions should
* return a positive value if a should go before b // return a positive value if a should go before b
* return a negative value if a should go after b // return a negative value if a should go after b
* return 0 otherwise // return 0 otherwise
*/
#define MergesortCompareFuncDef(name, arg_a, arg_b, arg_udata) i32 name(void *arg_a, void *arg_b, void *arg_udata) #define MergesortCompareFuncDef(name, arg_a, arg_b, arg_udata) i32 name(void *arg_a, void *arg_b, void *arg_udata)
typedef MergesortCompareFuncDef(MergesortCompareFunc, a, b, udata); typedef MergesortCompareFuncDef(MergesortCompareFunc, a, b, udata);
@ -45,9 +44,8 @@ Struct(Dict)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Hash utils //~ Hash utils
/* FNV-1a parameters for different hash sizes: // FNV-1a parameters for different hash sizes:
* https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function#FNV_hash_parameters // https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function#FNV_hash_parameters
*/
Inline u64 HashFnv64(u64 seed, String s) Inline u64 HashFnv64(u64 seed, String s)
{ {
u64 hash = seed; u64 hash = seed;
@ -82,7 +80,7 @@ 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) Inline void MergesortInternal(u8 *left, u8 *right, u8 *items, u64 left_count, u64 right_count, u64 item_size, MergesortCompareFunc *callback, void *udata)
{ {
/* Sort */ // Sort
u64 i = 0; u64 i = 0;
u64 l = 0; u64 l = 0;
u64 r = 0; u64 r = 0;
@ -103,7 +101,7 @@ Inline void MergesortInternal(u8 *left, u8 *right, u8 *items, u64 left_count, u6
++r; ++r;
} }
} }
/* Copy remaining */ // Copy remaining
if (l != left_count) if (l != left_count)
{ {
u64 remaining_count = left_count - l; u64 remaining_count = left_count - l;
@ -148,12 +146,10 @@ Inline void Mergesort(void *items, u64 item_count, u64 item_size, MergesortCompa
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Dict utils //~ Dict utils
//- Dict init
Inline Dict *InitDict(Arena *arena, u64 bins_count) Inline Dict *InitDict(Arena *arena, u64 bins_count)
{ {
Dict *dict = PushStruct(arena, Dict); Dict *dict = PushStruct(arena, Dict);
dict->bins_count = MaxU64(bins_count, 1); /* Ensure at least 1 bin */ dict->bins_count = MaxU64(bins_count, 1); // Ensure at least 1 bin
dict->bins = PushStructs(arena, DictBin, dict->bins_count); dict->bins = PushStructs(arena, DictBin, dict->bins_count);
return dict; return dict;
} }
@ -168,8 +164,6 @@ Inline void ResetDict(Dict *dict)
} }
} }
//- Dict set
Inline DictEntry *EnsureDictEntry(Arena *arena, Dict *dict, u64 hash) 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];
@ -179,13 +173,13 @@ Inline DictEntry *EnsureDictEntry(Arena *arena, Dict *dict, u64 hash)
{ {
if (hash == entry->hash) if (hash == entry->hash)
{ {
/* Existing match found */ // Existing match found
break; break;
} }
entry = entry->next_in_bin; entry = entry->next_in_bin;
} }
/* No match found, create new entry */ // No match found, create new entry
if (!entry) if (!entry)
{ {
if (dict->first_free) if (dict->first_free)
@ -230,11 +224,9 @@ Inline void SetDictValue(Arena *arena, Dict *dict, u64 hash, u64 value)
entry->value = value; entry->value = value;
} }
//- Dict remove
Inline void RemoveDictEntry(Dict *dict, DictEntry *entry) Inline void RemoveDictEntry(Dict *dict, DictEntry *entry)
{ {
/* Remove from bin */ // Remove from bin
{ {
DictBin *bin = &dict->bins[entry->hash % dict->bins_count]; DictBin *bin = &dict->bins[entry->hash % dict->bins_count];
DictEntry *prev_in_bin = entry->prev_in_bin; DictEntry *prev_in_bin = entry->prev_in_bin;
@ -256,7 +248,7 @@ Inline void RemoveDictEntry(Dict *dict, DictEntry *entry)
bin->last = prev_in_bin; bin->last = prev_in_bin;
} }
} }
/* Remove from list */ // Remove from list
{ {
DictEntry *prev = entry->prev; DictEntry *prev = entry->prev;
DictEntry *next = entry->next; DictEntry *next = entry->next;
@ -277,15 +269,13 @@ Inline void RemoveDictEntry(Dict *dict, DictEntry *entry)
dict->last = prev; dict->last = prev;
} }
} }
/* Add to free list */ // Add to free list
{ {
entry->next = dict->first_free; entry->next = dict->first_free;
dict->first_free = entry; dict->first_free = entry;
} }
} }
//- Dict index
Inline DictEntry *DictEntryFromHash(Dict *dict, u64 hash) Inline DictEntry *DictEntryFromHash(Dict *dict, u64 hash)
{ {
DictEntry *result = 0; DictEntry *result = 0;
@ -294,7 +284,7 @@ Inline DictEntry *DictEntryFromHash(Dict *dict, u64 hash)
{ {
if (hash == entry->hash) if (hash == entry->hash)
{ {
/* Match found */ // Match found
result = entry; result = entry;
break; break;
} }

View File

@ -44,13 +44,13 @@ void WaveSyncBroadcastEx_(WaveLaneCtx *lane, u32 broadcast_lane_idx, void *broad
if (lane_idx == broadcast_lane_idx) if (lane_idx == broadcast_lane_idx)
{ {
/* Broadcast */ // Broadcast
wave->broadcast_data = broadcast_ptr; wave->broadcast_data = broadcast_ptr;
i64 ack_gen = Atomic64Fetch(&wave->ack_gen.v); i64 ack_gen = Atomic64Fetch(&wave->ack_gen.v);
lane->seen_broadcast_gen = Atomic64FetchAdd(&wave->broadcast_gen.v, 1) + 1; lane->seen_broadcast_gen = Atomic64FetchAdd(&wave->broadcast_gen.v, 1) + 1;
FutexWakeNeq(&wave->broadcast_gen.v); FutexWakeNeq(&wave->broadcast_gen.v);
/* Wait for ack */ // Wait for ack
{ {
u64 remaining_spins = spin_count; u64 remaining_spins = spin_count;
while (Atomic64Fetch(&wave->ack_gen.v) == ack_gen) while (Atomic64Fetch(&wave->ack_gen.v) == ack_gen)
@ -69,7 +69,7 @@ void WaveSyncBroadcastEx_(WaveLaneCtx *lane, u32 broadcast_lane_idx, void *broad
} }
else else
{ {
/* Wait for broadcast */ // Wait for broadcast
i64 seen_broadcast_gen = lane->seen_broadcast_gen++; i64 seen_broadcast_gen = lane->seen_broadcast_gen++;
{ {
u64 remaining_spins = spin_count; u64 remaining_spins = spin_count;
@ -87,10 +87,10 @@ void WaveSyncBroadcastEx_(WaveLaneCtx *lane, u32 broadcast_lane_idx, void *broad
} }
} }
/* Copy broadcast data */ // Copy broadcast data
CopyBytes(broadcast_ptr, wave->broadcast_data, broadcast_size); CopyBytes(broadcast_ptr, wave->broadcast_data, broadcast_size);
/* Ack */ // Ack
i32 ack_count = Atomic32FetchAdd(&wave->ack_count.v, 1) + 1; i32 ack_count = Atomic32FetchAdd(&wave->ack_count.v, 1) + 1;
if (ack_count == lanes_count - 1) if (ack_count == lanes_count - 1)
{ {

View File

@ -9,11 +9,11 @@ AlignedStruct(WaveCtx, CachelineSize)
i32 lanes_count; i32 lanes_count;
void *udata; void *udata;
/* Sync barrier */ // Sync barrier
Atomic32Padded sync_count; Atomic32Padded sync_count;
Atomic64Padded sync_gen; Atomic64Padded sync_gen;
/* Broadcast barrier */ // Broadcast barrier
void *broadcast_data; void *broadcast_data;
Atomic64Padded broadcast_gen; Atomic64Padded broadcast_gen;
Atomic32Padded ack_count; Atomic32Padded ack_count;

View File

@ -118,7 +118,7 @@ CpuTopologyInfo GetCpuTopologyInfo(void)
} }
if (ok) if (ok)
{ {
/* Determine max efficiency class */ // Determine max efficiency class
i32 max_efficiency_class = 0; i32 max_efficiency_class = 0;
{ {
DWORD pos = 0; DWORD pos = 0;
@ -129,7 +129,7 @@ CpuTopologyInfo GetCpuTopologyInfo(void)
pos += info->Size; pos += info->Size;
} }
} }
/* Generate physical core info */ // Generate physical core info
{ {
DWORD pos = 0; DWORD pos = 0;
while (pos < infos_buff_size) while (pos < infos_buff_size)
@ -139,17 +139,17 @@ CpuTopologyInfo GetCpuTopologyInfo(void)
++res.num_logical_cores; ++res.num_logical_cores;
if (info->Processor.Flags & LTP_PC_SMT) if (info->Processor.Flags & LTP_PC_SMT)
{ {
/* Core has SMT sibling */ // Core has SMT sibling
++res.num_logical_cores; ++res.num_logical_cores;
} }
if (info->Processor.EfficiencyClass == max_efficiency_class) if (info->Processor.EfficiencyClass == max_efficiency_class)
{ {
/* Core is P-core */ // Core is P-core
++res.num_physical_performance_cores; ++res.num_physical_performance_cores;
} }
else else
{ {
/* Core is not a P-core */ // Core is not a P-core
++res.num_physical_non_performance_cores; ++res.num_physical_non_performance_cores;
} }
pos += info->Size; pos += info->Size;
@ -222,7 +222,7 @@ String SwappedStateFromName(Arena *arena, String name)
void WriteSwappedState(String name, String data) void WriteSwappedState(String name, String data)
{ {
TempArena scratch = BeginScratchNoConflict(); TempArena scratch = BeginScratchNoConflict();
/* TODO: Use directory non-relative to executable */ // TODO: Use directory non-relative to executable
CreateDirectoryW(L"ppswap", 0); CreateDirectoryW(L"ppswap", 0);
String result = Zi; String result = Zi;
String path = StringF(scratch.arena, "ppswap/%F.swp", FmtString(name)); String path = StringF(scratch.arena, "ppswap/%F.swp", FmtString(name));
@ -305,37 +305,37 @@ void W32_Log(i32 level, String msg)
i64 now_ns = TimeNs(); i64 now_ns = TimeNs();
i32 thread_id = GetCurrentThreadId(); i32 thread_id = GetCurrentThreadId();
// TODO: Log asynchronously
//- Log message to file //- Log message to file
/* TODO: Log asynchronously */
{ {
String shorthand = settings.shorthand; String shorthand = settings.shorthand;
String msg_formatted = StringF( String msg_formatted = StringF(
scratch.arena, scratch.arena,
"[%F:%F:%F.%F] <%F> [%F] %F\n", "[%F:%F:%F.%F] <%F> [%F] %F\n",
/* Time */ // Time
FmtUint(datetime.hour, .z = 2), FmtUint(datetime.hour, .z = 2),
FmtUint(datetime.minute, .z = 2), FmtUint(datetime.minute, .z = 2),
FmtUint(datetime.second, .z = 2), FmtUint(datetime.second, .z = 2),
FmtUint(datetime.milliseconds, .z = 3), FmtUint(datetime.milliseconds, .z = 3),
/* Thread id */ // Thread id
FmtUint(thread_id, .z = 5), FmtUint(thread_id, .z = 5),
/* Level */ // Level
FmtString(shorthand), FmtString(shorthand),
/* Message */ // Message
FmtString(msg) FmtString(msg)
); );
WriteFile(W32.logfile, msg_formatted.text, msg_formatted.len, 0, 0); WriteFile(W32.logfile, msg_formatted.text, msg_formatted.len, 0, 0);
} }
//- Log message to queue //- Log message to queue
/* TODO: Log asynchronously */
LockTicketMutex(&W32.logs_tm); LockTicketMutex(&W32.logs_tm);
{ {
/* Get staged data */ // Get staged data
LogEvent *ev = PushStruct(W32.logs_arena, LogEvent); LogEvent *ev = PushStruct(W32.logs_arena, LogEvent);
ev->msg = PushString(W32.log_msgs_arena, msg); ev->msg = PushString(W32.log_msgs_arena, msg);
ev->datetime = datetime; ev->datetime = datetime;
@ -354,8 +354,8 @@ void W32_Log(i32 level, String msg)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ @hookimpl Log //~ @hookimpl Log
/* Panic log function is separate to enforce zero side effects other than // Panic log function is separate to enforce zero side effects other than
* immediately writing to log file. */ // immediately writing to log file.
void LogPanic(String msg) void LogPanic(String msg)
{ {
if (Atomic32Fetch(&W32.logs_initialized)) if (Atomic32Fetch(&W32.logs_initialized))
@ -405,7 +405,7 @@ LogEventsArray GetLogEvents(void)
i32 W32_Main(void) i32 W32_Main(void)
{ {
/* Init time */ // Init time
{ {
LARGE_INTEGER qpf; LARGE_INTEGER qpf;
QueryPerformanceFrequency(&qpf); QueryPerformanceFrequency(&qpf);
@ -417,20 +417,20 @@ i32 W32_Main(void)
W32.timer_start_qpc = qpc.QuadPart; W32.timer_start_qpc = qpc.QuadPart;
} }
/* Setup events */ // Setup events
W32.panic_event = CreateEventW(0, 1, 0, 0); W32.panic_event = CreateEventW(0, 1, 0, 0);
W32.exit_event = CreateEventW(0, 1, 0, 0); W32.exit_event = CreateEventW(0, 1, 0, 0);
W32.main_thread_id = GetCurrentThreadId(); W32.main_thread_id = GetCurrentThreadId();
SetThreadDescription(GetCurrentThread(), L"Main thread"); SetThreadDescription(GetCurrentThread(), L"Main thread");
/* Query system info */ // Query system info
GetSystemInfo(&W32.info); GetSystemInfo(&W32.info);
/* Init main thread */ // Init main thread
W32_InitCurrentThread(Lit("Main")); W32_InitCurrentThread(Lit("Main"));
/* Get raw args from command line */ // Get raw args from command line
{ {
Arena *perm = PermArena(); Arena *perm = PermArena();
StringList args_list = Zi; StringList args_list = Zi;
@ -451,25 +451,25 @@ i32 W32_Main(void)
////////////////////////////// //////////////////////////////
//- Bootstrap //- Bootstrap
/* Bootstrap command line */ // Bootstrap command line
BootstrapCmdline(); BootstrapCmdline();
/* Bootstrap log system */ // Bootstrap log system
/* FIXME: Remove hardcoded log path */ // FIXME: Remove hardcoded log path
W32_BootstrapLogs(Lit("log.log")); W32_BootstrapLogs(Lit("log.log"));
LogInfoF("Main thread ID: %F", FmtUint(ThreadId())); LogInfoF("Main thread ID: %F", FmtUint(ThreadId()));
/* Bootstrap resource system */ // Bootstrap resource system
{ {
W32_FindEmbeddedDataCtx ctx = Zi; W32_FindEmbeddedDataCtx ctx = Zi;
EnumResourceNamesW(0, RT_RCDATA, &W32_FindEmbeddedRcData, (LONG_PTR)&ctx); EnumResourceNamesW(0, RT_RCDATA, &W32_FindEmbeddedRcData, (LONG_PTR)&ctx);
BootstrapResources(ctx.embedded_strings_count, ctx.embedded_strings); BootstrapResources(ctx.embedded_strings_count, ctx.embedded_strings);
} }
/* Bootstrap async */ // Bootstrap async
BootstrapAsync(); BootstrapAsync();
/* Bootstrap layers */ // Bootstrap layers
if (!Atomic32Fetch(&W32.panicking)) if (!Atomic32Fetch(&W32.panicking))
{ {
BootstrapLayers(); BootstrapLayers();
@ -478,7 +478,7 @@ i32 W32_Main(void)
////////////////////////////// //////////////////////////////
//- Wait for exit signal //- Wait for exit signal
/* Wait for exit start or panic */ // Wait for exit start or panic
if (!Atomic32Fetch(&W32.panicking)) if (!Atomic32Fetch(&W32.panicking))
{ {
HANDLE handles[] = { HANDLE handles[] = {
@ -491,7 +491,7 @@ i32 W32_Main(void)
////////////////////////////// //////////////////////////////
//- Shutdown //- Shutdown
/* Run exit callbacks */ // Run exit callbacks
if (!Atomic32Fetch(&W32.panicking)) if (!Atomic32Fetch(&W32.panicking))
{ {
i32 num_funcs = Atomic32Fetch(&W32.num_exit_funcs); i32 num_funcs = Atomic32Fetch(&W32.num_exit_funcs);
@ -502,7 +502,7 @@ i32 W32_Main(void)
} }
} }
/* Exit */ // Exit
if (Atomic32Fetch(&W32.panicking)) if (Atomic32Fetch(&W32.panicking))
{ {
WaitForSingleObject(W32.panic_event, INFINITE); WaitForSingleObject(W32.panic_event, INFINITE);
@ -526,8 +526,8 @@ i32 W32_Main(void)
{ {
return W32_Main(); return W32_Main();
} }
#endif /* IsConsoleApp */ #endif // IsConsoleApp
#endif /* IsCrtlibEnabled */ #endif // IsCrtlibEnabled
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Crt stub //~ Crt stub
@ -537,7 +537,7 @@ i32 W32_Main(void)
#pragma clang diagnostic ignored "-Wmissing-variable-declarations" #pragma clang diagnostic ignored "-Wmissing-variable-declarations"
#pragma clang diagnostic ignored "-Wmissing-prototypes" #pragma clang diagnostic ignored "-Wmissing-prototypes"
/* Enable floating point */ // Enable floating point
__attribute((used)) __attribute((used))
int _fltused; int _fltused;
@ -549,4 +549,4 @@ i32 W32_Main(void)
} }
#pragma clang diagnostic pop #pragma clang diagnostic pop
#endif /* !IsCrtlibEnabled */ #endif // !IsCrtlibEnabled

View File

@ -16,12 +16,12 @@ void FutexWakeNeq(void *addr)
void FutexYieldGte(volatile void *addr, void *cmp, u8 cmp_size) void FutexYieldGte(volatile void *addr, void *cmp, u8 cmp_size)
{ {
/* TODO: Actually implement this. Just emulating via neq for now. */ // TODO: Actually implement this. Just emulating via neq for now.
FutexYieldNeq(addr, cmp, cmp_size); FutexYieldNeq(addr, cmp, cmp_size);
} }
void FutexWakeGte(void *addr) void FutexWakeGte(void *addr)
{ {
/* TODO: Actually implement this. Just emulating via neq for now. */ // TODO: Actually implement this. Just emulating via neq for now.
FutexWakeNeq(addr); FutexWakeNeq(addr);
} }

View File

@ -3,7 +3,7 @@
void W32_InitCurrentThread(String name) void W32_InitCurrentThread(String name)
{ {
/* Init thread arenas */ // Init thread arenas
{ {
Base_tl.arenas.perm = AcquireArena(Gibi(64)); Base_tl.arenas.perm = AcquireArena(Gibi(64));
for (i32 i = 0; i < (i32)countof(Base_tl.arenas.scratch); ++i) for (i32 i = 0; i < (i32)countof(Base_tl.arenas.scratch); ++i)
@ -13,11 +13,11 @@ void W32_InitCurrentThread(String name)
} }
Arena *perm = PermArena(); Arena *perm = PermArena();
/* Set thread name */ // Set thread name
wchar_t *thread_name_wstr = WstrFromString(perm, name); wchar_t *thread_name_wstr = WstrFromString(perm, name);
SetThreadDescription(GetCurrentThread(), thread_name_wstr); SetThreadDescription(GetCurrentThread(), thread_name_wstr);
/* Initialize COM */ // Initialize COM
CoInitializeEx(0, COINIT_MULTITHREADED); CoInitializeEx(0, COINIT_MULTITHREADED);
} }
@ -38,7 +38,7 @@ void DispatchWave(String name, u32 num_lanes, WaveLaneEntryFunc *entry, void *ud
Arena *perm = PermArena(); Arena *perm = PermArena();
PERSIST Atomic64 num_threads_allocated = Zi; PERSIST Atomic64 num_threads_allocated = Zi;
/* Catch high lane count to prevent OS crash */ // Catch high lane count to prevent OS crash
i64 old_num_threads_allocated = Atomic64FetchAdd(&num_threads_allocated, num_lanes); i64 old_num_threads_allocated = Atomic64FetchAdd(&num_threads_allocated, num_lanes);
i64 new_num_threads_allocated = old_num_threads_allocated + num_lanes; i64 new_num_threads_allocated = old_num_threads_allocated + num_lanes;
if (new_num_threads_allocated > MaxThreads) if (new_num_threads_allocated > MaxThreads)
@ -49,7 +49,7 @@ void DispatchWave(String name, u32 num_lanes, WaveLaneEntryFunc *entry, void *ud
} }
else else
{ {
/* Sleep until panic */ // Sleep until panic
Sleep(INFINITE); Sleep(INFINITE);
} }
} }

View File

@ -39,7 +39,7 @@ CLD_SupportPoint CLD_SupportPointFromDirEx(CLD_Shape *shape, Xform xf, Vec2 dir,
if (count == 1) if (count == 1)
{ {
/* Skip 'ignore' on single point colliders */ // Skip 'ignore' on single point colliders
ignore = -1; ignore = -1;
} }
@ -131,11 +131,11 @@ b32 CLD_TestAabb(Aabb box0, Aabb box1)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Gjk //~ Gjk
/* //
* Determine simplex in menkowksi difference that encapsulates origin if shapes // Determine simplex in menkowksi difference that encapsulates origin if shapes
* overlap, or closest edge / point to origin on CLD_Menkowski difference if they // overlap, or closest edge / point to origin on CLD_Menkowski difference if they
* do not. // do not.
*/ //
#if COLLIDER_DEBUG #if COLLIDER_DEBUG
CLD_GjkData CLD_GjkDataFromShapes(CLD_Shape *shape0, CLD_Shape *shape1, Xform xf0, Xform xf1, f32 min_unique_pt_dist_sq, u32 dbg_step) CLD_GjkData CLD_GjkDataFromShapes(CLD_Shape *shape0, CLD_Shape *shape1, Xform xf0, Xform xf1, f32 min_unique_pt_dist_sq, u32 dbg_step)
@ -148,7 +148,7 @@ CLD_GjkData CLD_GjkDataFromShapes(CLD_Shape *shape0, CLD_Shape *shape1, Xform xf
Vec2 dir = Zi; Vec2 dir = Zi;
CLD_MenkowskiPoint m = Zi; CLD_MenkowskiPoint m = Zi;
/* First point is support point in shape's general directions to eachother */ // First point is support point in shape's general directions to eachother
dir = SubVec2(xf1.og, xf0.og); dir = SubVec2(xf1.og, xf0.og);
if (IsVec2Zero(dir)) dir = VEC2(1, 0); if (IsVec2Zero(dir)) dir = VEC2(1, 0);
s.a = CLD_MenkowskiPointFromDir(shape0, shape1, xf0, xf1, dir); s.a = CLD_MenkowskiPointFromDir(shape0, shape1, xf0, xf1, dir);
@ -159,15 +159,17 @@ CLD_GjkData CLD_GjkDataFromShapes(CLD_Shape *shape0, CLD_Shape *shape1, Xform xf
u32 num_removed = 0; u32 num_removed = 0;
for (;;) for (;;)
{ {
//////////////////////////////
//- Find initial points in simplex
if (s.len == 1) if (s.len == 1)
{ {
//- Find second point in simplex // Second point is support point towards origin
/* Second point is support point towards origin */
dir = NegVec2(s.a.p); dir = NegVec2(s.a.p);
CLD_DBGSTEP; CLD_DBGSTEP;
m = CLD_MenkowskiPointFromDir(shape0, shape1, xf0, xf1, dir); m = CLD_MenkowskiPointFromDir(shape0, shape1, xf0, xf1, dir);
/* Check that new point is far enough away from existing point */ // Check that new point is far enough away from existing point
if (Vec2LenSq(SubVec2(m.p, s.a.p)) < min_unique_pt_dist_sq) if (Vec2LenSq(SubVec2(m.p, s.a.p)) < min_unique_pt_dist_sq)
{ {
overlapping = 0; overlapping = 0;
@ -177,15 +179,17 @@ CLD_GjkData CLD_GjkDataFromShapes(CLD_Shape *shape0, CLD_Shape *shape1, Xform xf
s.a = m; s.a = m;
s.len = 2; s.len = 2;
/* Third point is support point in direction of line normal towards origin */ // Third point is support point in direction of line normal towards origin
dir = PerpVec2TowardsDir(SubVec2(s.b.p, s.a.p), NegVec2(s.a.p)); dir = PerpVec2TowardsDir(SubVec2(s.b.p, s.a.p), NegVec2(s.a.p));
} }
//////////////////////////////
//- Find third piont in simplex
{ {
//- Find third point in simplex
CLD_DBGSTEP; CLD_DBGSTEP;
m = CLD_MenkowskiPointFromDir(shape0, shape1, xf0, xf1, dir); m = CLD_MenkowskiPointFromDir(shape0, shape1, xf0, xf1, dir);
/* Check that new point is far enough away from existing points */ // Check that new point is far enough away from existing points
if ( if (
Vec2LenSq(SubVec2(m.p, s.a.p)) < min_unique_pt_dist_sq || Vec2LenSq(SubVec2(m.p, s.a.p)) < min_unique_pt_dist_sq ||
Vec2LenSq(SubVec2(m.p, s.b.p)) < min_unique_pt_dist_sq || ( Vec2LenSq(SubVec2(m.p, s.b.p)) < min_unique_pt_dist_sq || (
@ -205,17 +209,21 @@ CLD_GjkData CLD_GjkDataFromShapes(CLD_Shape *shape0, CLD_Shape *shape1, Xform xf
s.a = m; s.a = m;
s.len = 3; s.len = 3;
if ((AbsF32(WedgeVec2(SubVec2(s.b.p, s.a.p), NegVec2(s.a.p))) <= min_unique_pt_dist_sq) || if (
(AbsF32(WedgeVec2(SubVec2(s.c.p, s.b.p), NegVec2(s.b.p))) <= min_unique_pt_dist_sq) || (AbsF32(WedgeVec2(SubVec2(s.b.p, s.a.p), NegVec2(s.a.p))) <= min_unique_pt_dist_sq) ||
(AbsF32(WedgeVec2(SubVec2(s.c.p, s.a.p), NegVec2(s.a.p))) <= min_unique_pt_dist_sq)) (AbsF32(WedgeVec2(SubVec2(s.c.p, s.b.p), NegVec2(s.b.p))) <= min_unique_pt_dist_sq) ||
(AbsF32(WedgeVec2(SubVec2(s.c.p, s.a.p), NegVec2(s.a.p))) <= min_unique_pt_dist_sq)
)
{ {
/* Simplex lies on origin */ // Simplex lies on origin
overlapping = 1; overlapping = 1;
break; break;
} }
} }
//- Determine region of the simplex in which the origin lies //////////////////////////////
//- Determine origin region
CLD_DBGSTEP; CLD_DBGSTEP;
Vec2 vab = SubVec2(s.b.p, s.a.p); Vec2 vab = SubVec2(s.b.p, s.a.p);
Vec2 vac = SubVec2(s.c.p, s.a.p); Vec2 vac = SubVec2(s.c.p, s.a.p);
@ -235,34 +243,34 @@ CLD_GjkData CLD_GjkDataFromShapes(CLD_Shape *shape0, CLD_Shape *shape1, Xform xf
if (rab_dot >= 0 && vab_dot >= 0 && vab_dot <= 1) if (rab_dot >= 0 && vab_dot >= 0 && vab_dot <= 1)
{ {
//- Region ab, remove c // Region ab, remove c
num_removed = 1; num_removed = 1;
removed_a = s.c.p; removed_a = s.c.p;
s.len = 2; s.len = 2;
dir = rab_dir; /* Next third point is in direction of region ab */ dir = rab_dir; // Next third point is in direction of region ab
} }
else if (rac_dot >= 0 && vac_dot >= 0 && vac_dot <= 1) else if (rac_dot >= 0 && vac_dot >= 0 && vac_dot <= 1)
{ {
//- Region ac, remove b // Region ac, remove b
num_removed = 1; num_removed = 1;
removed_a = s.b.p; removed_a = s.b.p;
s.len = 2; s.len = 2;
s.b = s.c; s.b = s.c;
dir = rac_dir; /* Next third point is in direction of region ac */ dir = rac_dir; // Next third point is in direction of region ac
} }
else if (rbc_dot >= 0 && vbc_dot >= 0 && vbc_dot <= 1) else if (rbc_dot >= 0 && vbc_dot >= 0 && vbc_dot <= 1)
{ {
//- Region bc, remove a // Region bc, remove a
num_removed = 1; num_removed = 1;
removed_a = s.a.p; removed_a = s.a.p;
s.len = 2; s.len = 2;
s.a = s.b; s.a = s.b;
s.b = s.c; s.b = s.c;
dir = rbc_dir; /* Next third point is in direction of region bc */ dir = rbc_dir; // Next third point is in direction of region bc
} }
else if (vab_dot <= 0 && vac_dot <= 0) else if (vab_dot <= 0 && vac_dot <= 0)
{ {
//- Region a, remove bc // Region a, remove bc
num_removed = 2; num_removed = 2;
removed_a = s.b.p; removed_a = s.b.p;
removed_b = s.c.p; removed_b = s.c.p;
@ -270,7 +278,7 @@ CLD_GjkData CLD_GjkDataFromShapes(CLD_Shape *shape0, CLD_Shape *shape1, Xform xf
} }
else if (vab_dot >= 1 && vbc_dot <= 0) else if (vab_dot >= 1 && vbc_dot <= 0)
{ {
//- Region b, remove ac // Region b, remove ac
num_removed = 2; num_removed = 2;
removed_a = s.a.p; removed_a = s.a.p;
removed_b = s.c.p; removed_b = s.c.p;
@ -279,7 +287,7 @@ CLD_GjkData CLD_GjkDataFromShapes(CLD_Shape *shape0, CLD_Shape *shape1, Xform xf
} }
else if (vac_dot >= 1 && vbc_dot >= 1) else if (vac_dot >= 1 && vbc_dot >= 1)
{ {
//- Region c, remove ab // Region c, remove ab
num_removed = 2; num_removed = 2;
removed_a = s.a.p; removed_a = s.a.p;
removed_b = s.b.p; removed_b = s.b.p;
@ -288,7 +296,7 @@ CLD_GjkData CLD_GjkDataFromShapes(CLD_Shape *shape0, CLD_Shape *shape1, Xform xf
} }
else else
{ {
/* No region, must be in simplex */ // No region, must be in simplex
overlapping = 1; overlapping = 1;
break; break;
} }
@ -313,9 +321,8 @@ CLD_GjkData CLD_GjkDataFromShapes(CLD_Shape *shape0, CLD_Shape *shape1, Xform xf
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Epa //~ Epa
/* Expands upon result of GJK computation to determine collision normal & // Expands upon result of GJK computation to determine collision normal &
* closest edge when shapes are overlapping // closest edge when shapes are overlapping
*/
#if COLLIDER_DEBUG #if COLLIDER_DEBUG
CLD_EpaData CLD_EpaDataFromShapes(CLD_Shape *shape0, CLD_Shape *shape1, Xform xf0, Xform xf1, CLD_GjkData gjk_result, f32 min_unique_pt_dist_sq, u32 max_iterations, u32 dbg_step) CLD_EpaData CLD_EpaDataFromShapes(CLD_Shape *shape0, CLD_Shape *shape1, Xform xf0, Xform xf1, CLD_GjkData gjk_result, f32 min_unique_pt_dist_sq, u32 max_iterations, u32 dbg_step)
@ -350,8 +357,8 @@ CLD_EpaData CLD_EpaDataFromShapes(CLD_Shape *shape0, CLD_Shape *shape1, Xform xf
{ {
++epa_iterations; ++epa_iterations;
/* Find dir from origin to closest edge */ // Find dir from origin to closest edge
/* FIXME: Winding order of ps & pe index */ // FIXME: Winding order of ps & pe index
f32 closest_len_sq = F32Infinity; f32 closest_len_sq = F32Infinity;
CLD_MenkowskiPoint closest_a = Zi; CLD_MenkowskiPoint closest_a = Zi;
CLD_MenkowskiPoint closest_b = Zi; CLD_MenkowskiPoint closest_b = Zi;
@ -380,13 +387,13 @@ CLD_EpaData CLD_EpaDataFromShapes(CLD_Shape *shape0, CLD_Shape *shape1, Xform xf
} }
Vec2 vab = SubVec2(closest_b.p, closest_a.p); Vec2 vab = SubVec2(closest_b.p, closest_a.p);
/* Find new point in dir */ // Find new point in dir
Vec2 dir = MulVec2(PerpVec2(vab), winding); Vec2 dir = MulVec2(PerpVec2(vab), winding);
CLD_MenkowskiPoint m = CLD_MenkowskiPointFromDir(shape0, shape1, xf0, xf1, dir); CLD_MenkowskiPoint m = CLD_MenkowskiPointFromDir(shape0, shape1, xf0, xf1, dir);
#if COLLIDER_DEBUG #if COLLIDER_DEBUG
{ {
/* If debug step count is reached, we still want to inspect the normal at the step */ // If debug step count is reached, we still want to inspect the normal at the step
normal = NormVec2(dir); normal = NormVec2(dir);
closest_feature.a = closest_a; closest_feature.a = closest_a;
closest_feature.b = closest_b; closest_feature.b = closest_b;
@ -394,16 +401,16 @@ CLD_EpaData CLD_EpaDataFromShapes(CLD_Shape *shape0, CLD_Shape *shape1, Xform xf
} }
#endif #endif
/* Check validity of new point */ // Check validity of new point
CLD_DBGSTEP; CLD_DBGSTEP;
{ {
b32 valid = 1; b32 valid = 1;
{ {
/* NOTE: Changing this value affects how stable normals are for circular colliders */ // NOTE: Changing this value affects how stable normals are for circular colliders
//const f32 validity_epsilon = min_unique_pt_dist_sq; /* Arbitrary */ //const f32 validity_epsilon = min_unique_pt_dist_sq; // Arbitrary
//const f32 validity_epsilon = 0.00000000001f; /* Arbitrary */ //const f32 validity_epsilon = 0.00000000001f; // Arbitrary
const f32 validity_epsilon = min_unique_pt_dist_sq; /* Arbitrary */ const f32 validity_epsilon = min_unique_pt_dist_sq; // Arbitrary
Vec2 vam = SubVec2(m.p, closest_a.p); Vec2 vam = SubVec2(m.p, closest_a.p);
Vec2 vbm = SubVec2(closest_b.p, closest_a.p); Vec2 vbm = SubVec2(closest_b.p, closest_a.p);
@ -412,12 +419,12 @@ CLD_EpaData CLD_EpaDataFromShapes(CLD_Shape *shape0, CLD_Shape *shape1, Xform xf
if (dot >= -validity_epsilon && dot <= 1 - validity_epsilon && (WedgeVec2(vab, vam) * -winding) >= -validity_epsilon) if (dot >= -validity_epsilon && dot <= 1 - validity_epsilon && (WedgeVec2(vab, vam) * -winding) >= -validity_epsilon)
{ {
/* New point is not between edge */ // New point is not between edge
valid = 0; valid = 0;
} }
else if (Vec2LenSq(vam) < min_unique_pt_dist_sq || Vec2LenSq(vbm) < min_unique_pt_dist_sq) else if (Vec2LenSq(vam) < min_unique_pt_dist_sq || Vec2LenSq(vbm) < min_unique_pt_dist_sq)
{ {
/* New point is too close to existing */ // New point is too close to existing
valid = 0; valid = 0;
} }
} }
@ -432,11 +439,11 @@ CLD_EpaData CLD_EpaDataFromShapes(CLD_Shape *shape0, CLD_Shape *shape1, Xform xf
} }
} }
/* Expand prototype */ // Expand prototype
PushStructNoZero(scratch.arena, CLD_MenkowskiPoint); PushStructNoZero(scratch.arena, CLD_MenkowskiPoint);
++proto_count; ++proto_count;
/* Shift points in prototype to make room */ // Shift points in prototype to make room
for (u32 i = proto_count - 1; i > closest_b_index; --i) for (u32 i = proto_count - 1; i > closest_b_index; --i)
{ {
u32 shift_from = (i > 0) ? i - 1 : proto_count - 1; u32 shift_from = (i > 0) ? i - 1 : proto_count - 1;
@ -444,7 +451,7 @@ CLD_EpaData CLD_EpaDataFromShapes(CLD_Shape *shape0, CLD_Shape *shape1, Xform xf
proto[shift_to] = proto[shift_from]; proto[shift_to] = proto[shift_from];
} }
/* Insert new point into prototype */ // Insert new point into prototype
proto[closest_b_index] = m; proto[closest_b_index] = m;
} }
} }
@ -493,7 +500,7 @@ CLD_ClippedLine CLD_ClipLineToLine(Vec2 a0, Vec2 b0, Vec2 a1, Vec2 b1, Vec2 norm
f32 va0a1_w = WedgeVec2(va0a1, normal); f32 va0a1_w = WedgeVec2(va0a1, normal);
f32 vb0b1_w = WedgeVec2(vb0b1, normal); f32 vb0b1_w = WedgeVec2(vb0b1, normal);
/* FIXME: Handle 0 denominator */ // FIXME: Handle 0 denominator
f32 a0t; f32 a0t;
f32 b0t; f32 b0t;
{ {
@ -558,7 +565,7 @@ CLD_CollisionData CLD_CollisionDataFromShapes(CLD_Shape *shape0, CLD_Shape *shap
CLD_GjkData gjk_result = Zi; CLD_GjkData gjk_result = Zi;
CLD_EpaData epa_result = Zi; CLD_EpaData epa_result = Zi;
/* Run GJK */ // Run GJK
#if COLLIDER_DEBUG #if COLLIDER_DEBUG
gjk_result = CLD_GjkDataFromShapes(shape0, shape1, xf0, xf1, min_unique_pt_dist_sq, dbg_step); gjk_result = CLD_GjkDataFromShapes(shape0, shape1, xf0, xf1, min_unique_pt_dist_sq, dbg_step);
dbg_step = gjk_result.dbg_step; dbg_step = gjk_result.dbg_step;
@ -567,7 +574,7 @@ CLD_CollisionData CLD_CollisionDataFromShapes(CLD_Shape *shape0, CLD_Shape *shap
#endif #endif
CLD_DBGSTEP; CLD_DBGSTEP;
/* Run EPA */ // Run EPA
#if COLLIDER_DEBUG #if COLLIDER_DEBUG
epa_result = CLD_EpaDataFromShapes(shape0, shape1, xf0, xf1, gjk_result, min_unique_pt_dist_sq, max_epa_iterations, dbg_step); epa_result = CLD_EpaDataFromShapes(shape0, shape1, xf0, xf1, gjk_result, min_unique_pt_dist_sq, max_epa_iterations, dbg_step);
dbg_step = epa_result.dbg_step; dbg_step = epa_result.dbg_step;
@ -577,7 +584,7 @@ CLD_CollisionData CLD_CollisionDataFromShapes(CLD_Shape *shape0, CLD_Shape *shap
normal = epa_result.normal; normal = epa_result.normal;
CLD_DBGSTEP; CLD_DBGSTEP;
/* Determine collision */ // Determine collision
if (gjk_result.overlapping) if (gjk_result.overlapping)
{ {
colliding = 1; colliding = 1;
@ -585,7 +592,7 @@ CLD_CollisionData CLD_CollisionDataFromShapes(CLD_Shape *shape0, CLD_Shape *shap
else else
{ {
CLD_MenkowskiFeature f = epa_result.closest_feature; CLD_MenkowskiFeature f = epa_result.closest_feature;
/* Shapes not overlapping, determine if distance between shapes within tolerance */ // Shapes not overlapping, determine if distance between shapes within tolerance
if (f.len == 1) if (f.len == 1)
{ {
Vec2 p = NegVec2(f.a.p); Vec2 p = NegVec2(f.a.p);
@ -596,7 +603,7 @@ CLD_CollisionData CLD_CollisionDataFromShapes(CLD_Shape *shape0, CLD_Shape *shap
} }
else else
{ {
/* Project origin to determine if distance is within tolerance. */ // Project origin to determine if distance is within tolerance.
Assert(f.len == 2); Assert(f.len == 2);
Vec2 vab = SubVec2(f.b.p, f.a.p); Vec2 vab = SubVec2(f.b.p, f.a.p);
Vec2 vao = NegVec2(f.a.p); Vec2 vao = NegVec2(f.a.p);
@ -609,10 +616,10 @@ CLD_CollisionData CLD_CollisionDataFromShapes(CLD_Shape *shape0, CLD_Shape *shap
} }
} }
/* Clip to determine final points */ // Clip to determine final points
if (colliding) if (colliding)
{ {
/* Max vertices must be < 16 to fit in 4 bit ids */ // Max vertices must be < 16 to fit in 4 bit ids
StaticAssert(countof(shape0->points) <= 16); StaticAssert(countof(shape0->points) <= 16);
CLD_MenkowskiFeature f = epa_result.closest_feature; CLD_MenkowskiFeature f = epa_result.closest_feature;
@ -625,7 +632,7 @@ CLD_CollisionData CLD_CollisionDataFromShapes(CLD_Shape *shape0, CLD_Shape *shap
CLD_SupportPoint a1 = f.a.s1; CLD_SupportPoint a1 = f.a.s1;
CLD_SupportPoint b0 = f.b.s0; CLD_SupportPoint b0 = f.b.s0;
CLD_SupportPoint b1 = f.b.s1; CLD_SupportPoint b1 = f.b.s1;
/* FIXME: Manually account for shapes w/ 1 & 2 points */ // FIXME: Manually account for shapes w/ 1 & 2 points
if (f.len == 2) if (f.len == 2)
{ {
if (a0.i == b0.i) if (a0.i == b0.i)
@ -666,7 +673,7 @@ CLD_CollisionData CLD_CollisionDataFromShapes(CLD_Shape *shape0, CLD_Shape *shap
Vec2 vab0_norm = NormVec2(vab0); Vec2 vab0_norm = NormVec2(vab0);
Vec2 vab1_norm = NormVec2(vab1); Vec2 vab1_norm = NormVec2(vab1);
/* Swap points based on normal direction for consistent clipping */ // Swap points based on normal direction for consistent clipping
if (WedgeVec2(normal, vab0) < 0) if (WedgeVec2(normal, vab0) < 0)
{ {
CLD_SupportPoint tmp = a0; CLD_SupportPoint tmp = a0;
@ -682,12 +689,12 @@ CLD_CollisionData CLD_CollisionDataFromShapes(CLD_Shape *shape0, CLD_Shape *shap
vab1 = NegVec2(vab1); vab1 = NegVec2(vab1);
} }
/* Collapse lines that are too far in the direction of the normal to be accurately clipped */ // Collapse lines that are too far in the direction of the normal to be accurately clipped
f32 collapse_epsilon = 0.05f; f32 collapse_epsilon = 0.05f;
collapse0 = collapse0 || AbsF32(WedgeVec2(normal, vab0_norm)) < collapse_epsilon; collapse0 = collapse0 || AbsF32(WedgeVec2(normal, vab0_norm)) < collapse_epsilon;
collapse1 = collapse1 || AbsF32(WedgeVec2(normal, vab1_norm)) < collapse_epsilon; collapse1 = collapse1 || AbsF32(WedgeVec2(normal, vab1_norm)) < collapse_epsilon;
/* Collapse lines into deepest point */ // Collapse lines into deepest point
if (collapse0) if (collapse0)
{ {
if (DotVec2(normal, vab0) > 0) if (DotVec2(normal, vab0) > 0)
@ -696,7 +703,7 @@ CLD_CollisionData CLD_CollisionDataFromShapes(CLD_Shape *shape0, CLD_Shape *shap
} }
else else
{ {
/* TODO: Remove this (debugging) */ // TODO: Remove this (debugging)
b0 = a0; b0 = a0;
} }
} }
@ -708,7 +715,7 @@ CLD_CollisionData CLD_CollisionDataFromShapes(CLD_Shape *shape0, CLD_Shape *shap
} }
else else
{ {
/* TODO: Remove this (debugging) */ // TODO: Remove this (debugging)
b1 = a1; b1 = a1;
} }
} }
@ -721,13 +728,13 @@ CLD_CollisionData CLD_CollisionDataFromShapes(CLD_Shape *shape0, CLD_Shape *shap
b32 ignore_b = 1; b32 ignore_b = 1;
if (!collapse0 && !collapse1) if (!collapse0 && !collapse1)
{ {
/* Clip line to line */ // Clip line to line
CLD_ClippedLine clip_result = CLD_ClipLineToLine(a0.p, b0.p, a1.p, b1.p, normal); CLD_ClippedLine clip_result = CLD_ClipLineToLine(a0.p, b0.p, a1.p, b1.p, normal);
Vec2 a0_clipped = clip_result.a0_clipped; Vec2 a0_clipped = clip_result.a0_clipped;
Vec2 a1_clipped = clip_result.a1_clipped; Vec2 a1_clipped = clip_result.a1_clipped;
Vec2 b0_clipped = clip_result.b0_clipped; Vec2 b0_clipped = clip_result.b0_clipped;
Vec2 b1_clipped = clip_result.b1_clipped; Vec2 b1_clipped = clip_result.b1_clipped;
/* Calc midpoint between clipped a & b */ // Calc midpoint between clipped a & b
Vec2 va0a1_clipped = SubVec2(a1_clipped, a0_clipped); Vec2 va0a1_clipped = SubVec2(a1_clipped, a0_clipped);
Vec2 vb0b1_clipped = SubVec2(b1_clipped, b0_clipped); Vec2 vb0b1_clipped = SubVec2(b1_clipped, b0_clipped);
a_sep = DotVec2(va0a1_clipped, normal); a_sep = DotVec2(va0a1_clipped, normal);
@ -757,18 +764,18 @@ CLD_CollisionData CLD_CollisionDataFromShapes(CLD_Shape *shape0, CLD_Shape *shap
{ {
Vec2 p0 = a0.p; Vec2 p0 = a0.p;
Vec2 p1 = a1.p; Vec2 p1 = a1.p;
/* TODO: Choose ID based on closest clipped point */ // TODO: Choose ID based on closest clipped point
if (collapse1 && !collapse0) if (collapse1 && !collapse0)
{ {
/* Project a1 onto vab0 */ // Project a1 onto vab0
p0 = CLD_ClipPointToLine(a0.p, b0.p, a1.p, normal); p0 = CLD_ClipPointToLine(a0.p, b0.p, a1.p, normal);
} }
if (collapse0 && !collapse1) if (collapse0 && !collapse1)
{ {
/* Project a0 onto vab1 */ // Project a0 onto vab1
p1 = CLD_ClipPointToLine(a1.p, b1.p, a0.p, normal); p1 = CLD_ClipPointToLine(a1.p, b1.p, a0.p, normal);
} }
/* Calc midpoint */ // Calc midpoint
Vec2 vsep = SubVec2(p1, p0); Vec2 vsep = SubVec2(p1, p0);
a_midpoint = AddVec2(p0, MulVec2(vsep, 0.5f)); a_midpoint = AddVec2(p0, MulVec2(vsep, 0.5f));
a_sep = DotVec2(normal, p1) - DotVec2(normal, p0); a_sep = DotVec2(normal, p1) - DotVec2(normal, p0);
@ -779,7 +786,7 @@ CLD_CollisionData CLD_CollisionDataFromShapes(CLD_Shape *shape0, CLD_Shape *shap
result.b1_clipped = p1; result.b1_clipped = p1;
} }
/* Insert points */ // Insert points
if (!ignore_a && a_sep < tolerance) if (!ignore_a && a_sep < tolerance)
{ {
CLD_CollisionPoint *point = &points[num_points++]; CLD_CollisionPoint *point = &points[num_points++];
@ -819,7 +826,7 @@ CLD_CollisionData CLD_CollisionDataFromShapes(CLD_Shape *shape0, CLD_Shape *shap
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Closest points //~ Closest points
/* TODO: De-duplicate code between CLD_ClosestPointDataFromShapes & CLD_CollisionDataFromShapes */ // TODO: De-duplicate code between CLD_ClosestPointDataFromShapes & CLD_CollisionDataFromShapes
CLD_ClosestPointData CLD_ClosestPointDataFromShapes(CLD_Shape *shape0, CLD_Shape *shape1, Xform xf0, Xform xf1) CLD_ClosestPointData CLD_ClosestPointDataFromShapes(CLD_Shape *shape0, CLD_Shape *shape1, Xform xf0, Xform xf1)
{ {
@ -840,25 +847,31 @@ CLD_ClosestPointData CLD_ClosestPointDataFromShapes(CLD_Shape *shape0, CLD_Shape
CLD_GjkData gjk_result = Zi; CLD_GjkData gjk_result = Zi;
CLD_EpaData epa_result = Zi; CLD_EpaData epa_result = Zi;
//////////////////////////////
//- Run GJK //- Run GJK
#if COLLIDER_DEBUG #if COLLIDER_DEBUG
gjk_result = CLD_GjkDataFromShapes(shape0, shape1, xf0, xf1, min_unique_pt_dist_sq, dbg_step); gjk_result = CLD_GjkDataFromShapes(shape0, shape1, xf0, xf1, min_unique_pt_dist_sq, dbg_step);
dbg_step = gjk_result.dbg_step; dbg_step = gjk_result.dbg_step;
#else #else
gjk_result = CLD_GjkDataFromShapes(shape0, shape1, xf0, xf1, min_unique_pt_dist_sq); gjk_result = CLD_GjkDataFromShapes(shape0, shape1, xf0, xf1, min_unique_pt_dist_sq);
#endif #endif
CLD_DBGSTEP; CLD_DBGSTEP;
//////////////////////////////
//- Run EPA //- Run EPA
#if COLLIDER_DEBUG #if COLLIDER_DEBUG
epa_result = CLD_EpaDataFromShapes(shape0, shape1, xf0, xf1, gjk_result, min_unique_pt_dist_sq, max_epa_iterations, dbg_step); epa_result = CLD_EpaDataFromShapes(shape0, shape1, xf0, xf1, gjk_result, min_unique_pt_dist_sq, max_epa_iterations, dbg_step);
dbg_step = epa_result.dbg_step; dbg_step = epa_result.dbg_step;
#else #else
epa_result = CLD_EpaDataFromShapes(shape0, shape1, xf0, xf1, gjk_result, min_unique_pt_dist_sq, max_epa_iterations); epa_result = CLD_EpaDataFromShapes(shape0, shape1, xf0, xf1, gjk_result, min_unique_pt_dist_sq, max_epa_iterations);
#endif #endif
CLD_DBGSTEP; CLD_DBGSTEP;
//////////////////////////////
//- Resolve points //- Resolve points
colliding = gjk_result.overlapping; colliding = gjk_result.overlapping;
CLD_MenkowskiFeature f = epa_result.closest_feature; CLD_MenkowskiFeature f = epa_result.closest_feature;
if (f.len == 1) if (f.len == 1)
@ -870,19 +883,19 @@ CLD_ClosestPointData CLD_ClosestPointDataFromShapes(CLD_Shape *shape0, CLD_Shape
else else
{ {
Assert(f.len == 2); Assert(f.len == 2);
/* FIXME: Winding order dependent? */ // FIXME: Winding order dependent?
f32 ratio; f32 ratio;
{ {
/* Determine ratio between edge a & b that projected origin lies */ // Determine ratio between edge a & b that projected origin lies
Vec2 vab = SubVec2(f.b.p, f.a.p); Vec2 vab = SubVec2(f.b.p, f.a.p);
Vec2 vao = NegVec2(f.a.p); Vec2 vao = NegVec2(f.a.p);
ratio = ClampF32(DotVec2(vab, vao) / DotVec2(vab, vab), 0, 1); ratio = ClampF32(DotVec2(vab, vao) / DotVec2(vab, vab), 0, 1);
} }
/* Shape 0 */ // Shape 0
p0 = SubVec2(f.b.s0.p, f.a.s0.p); p0 = SubVec2(f.b.s0.p, f.a.s0.p);
p0 = MulVec2(p0, ratio); p0 = MulVec2(p0, ratio);
p0 = AddVec2(p0, f.a.s0.p); p0 = AddVec2(p0, f.a.s0.p);
/* Shape 1 */ // Shape 1
p1 = SubVec2(f.b.s1.p, f.a.s1.p); p1 = SubVec2(f.b.s1.p, f.a.s1.p);
p1 = MulVec2(p1, ratio); p1 = MulVec2(p1, ratio);
p1 = AddVec2(p1, f.a.s1.p); p1 = AddVec2(p1, f.a.s1.p);
@ -906,8 +919,8 @@ CLD_ClosestPointData CLD_ClosestPointDataFromShapes(CLD_Shape *shape0, CLD_Shape
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Time of impact //~ Time of impact
/* Takes 2 shapes and their xforms at t=0 and t=1. // Takes 2 shapes and their xforms at t=0 and t=1.
* Returns time of impact in range [0, 1]. */ // Returns time of impact in range [0, 1].
f32 CLD_TimeOfImpact(CLD_Shape *c0, CLD_Shape *c1, Xform xf0_t0, Xform xf1_t0, Xform xf0_t1, Xform xf1_t1, f32 tolerance, u32 max_iterations) f32 CLD_TimeOfImpact(CLD_Shape *c0, CLD_Shape *c1, Xform xf0_t0, Xform xf1_t0, Xform xf0_t1, Xform xf1_t1, f32 tolerance, u32 max_iterations)
{ {
f32 t0 = 0; f32 t0 = 0;
@ -917,19 +930,19 @@ f32 CLD_TimeOfImpact(CLD_Shape *c0, CLD_Shape *c1, Xform xf0_t0, Xform xf1_t0, X
f32 t = 0; f32 t = 0;
f32 t_sep = F32Infinity; f32 t_sep = F32Infinity;
/* Find direction p0 -> p1 at t=0 */ // Find direction p0 -> p1 at t=0
Vec2 dir; Vec2 dir;
Vec2 dir_neg; Vec2 dir_neg;
{ {
CLD_ClosestPointData closest_points = CLD_ClosestPointDataFromShapes(c0, c1, xf0_t0, xf1_t0); CLD_ClosestPointData closest_points = CLD_ClosestPointDataFromShapes(c0, c1, xf0_t0, xf1_t0);
if (closest_points.colliding) if (closest_points.colliding)
{ {
/* Shapes are penetrating at t=0 */ // Shapes are penetrating at t=0
return 0; return 0;
} }
dir = SubVec2(closest_points.p1, closest_points.p0); dir = SubVec2(closest_points.p1, closest_points.p0);
t0_sep = Vec2Len(dir); t0_sep = Vec2Len(dir);
dir = DivVec2(dir, t0_sep); /* Normalize */ dir = DivVec2(dir, t0_sep); // Normalize
dir_neg = NegVec2(dir); dir_neg = NegVec2(dir);
} }
@ -939,7 +952,7 @@ f32 CLD_TimeOfImpact(CLD_Shape *c0, CLD_Shape *c1, Xform xf0_t0, Xform xf1_t0, X
t1_sep = DotVec2(dir, SubVec2(p1, p0)); t1_sep = DotVec2(dir, SubVec2(p1, p0));
if (t1_sep > 0) if (t1_sep > 0)
{ {
/* Shapes are not penetrating at t=1 */ // Shapes are not penetrating at t=1
return 1; return 1;
} }
} }
@ -947,16 +960,16 @@ f32 CLD_TimeOfImpact(CLD_Shape *c0, CLD_Shape *c1, Xform xf0_t0, Xform xf1_t0, X
u32 iteration = 0; u32 iteration = 0;
while (AbsF32(t_sep) > tolerance && iteration < max_iterations) while (AbsF32(t_sep) > tolerance && iteration < max_iterations)
{ {
/* Use mix of bisection & 0 position method to find root // Use mix of bisection & 0 position method to find root
* (as described in https://box2d.org/files/ErinCatto_ContinuousCollision_GDC2013.pdf) */ // (as described in https://box2d.org/files/ErinCatto_ContinuousCollision_GDC2013.pdf)
if (iteration & 1) if (iteration & 1)
{ {
/* Bisect */ // Bisect
t = (t1 + t0) / 2.0; t = (t1 + t0) / 2.0;
} }
else else
{ {
/* False position (fastest for linear case) */ // False position (fastest for linear case)
f32 m = (t1_sep - t0_sep) / (t1 - t0); f32 m = (t1_sep - t0_sep) / (t1 - t0);
t = (-t1_sep / m) + t1; t = (-t1_sep / m) + t1;
} }
@ -968,7 +981,7 @@ f32 CLD_TimeOfImpact(CLD_Shape *c0, CLD_Shape *c1, Xform xf0_t0, Xform xf1_t0, X
Vec2 p1 = CLD_SupportPointFromDir(c1, xf1, dir_neg).p; Vec2 p1 = CLD_SupportPointFromDir(c1, xf1, dir_neg).p;
t_sep = DotVec2(dir, SubVec2(p1, p0)); t_sep = DotVec2(dir, SubVec2(p1, p0));
/* Update bracket */ // Update bracket
if (t_sep > 0) if (t_sep > 0)
{ {
t0 = t; t0 = t;
@ -989,7 +1002,7 @@ f32 CLD_TimeOfImpact(CLD_Shape *c0, CLD_Shape *c1, Xform xf0_t0, Xform xf1_t0, X
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Point cloud debug //~ Point cloud debug
/* TODO: Remove this (debugging) */ // TODO: Remove this (debugging)
Vec2Array CLD_Menkowski(Arena *arena, CLD_Shape *shape0, CLD_Shape *shape1, Xform xf0, Xform xf1, u32 detail) Vec2Array CLD_Menkowski(Arena *arena, CLD_Shape *shape0, CLD_Shape *shape1, Xform xf0, Xform xf1, u32 detail)
{ {
Vec2Array result = { .points = ArenaNext(arena, Vec2) }; Vec2Array result = { .points = ArenaNext(arena, Vec2) };
@ -1007,10 +1020,10 @@ Vec2Array CLD_Menkowski(Arena *arena, CLD_Shape *shape0, CLD_Shape *shape1, Xfor
return result; return result;
} }
/* TODO: Remove this (debugging) */ // TODO: Remove this (debugging)
Vec2Array CLD_PointCloud(Arena *arena, CLD_Shape *shape0, CLD_Shape *shape1, Xform xf0, Xform xf1) Vec2Array CLD_PointCloud(Arena *arena, CLD_Shape *shape0, CLD_Shape *shape1, Xform xf0, Xform xf1)
{ {
/* FIXME: Account for radius */ // FIXME: Account for radius
Vec2Array result = { .points = ArenaNext(arena, Vec2) }; Vec2Array result = { .points = ArenaNext(arena, Vec2) };
Vec2 *points0 = shape0->points; Vec2 *points0 = shape0->points;
Vec2 *points1 = shape1->points; Vec2 *points1 = shape1->points;
@ -1037,15 +1050,15 @@ b32 CLD_GjkBoolean(CLD_Shape *shape0, CLD_Shape *shape1)
{ {
struct { Vec2 a, b, c; } s = Zi; struct { Vec2 a, b, c; } s = Zi;
/* FIXME: Infinite loop when shapes exactly overlap same space? */ // FIXME: Infinite loop when shapes exactly overlap same space?
Vec2 dir, p; Vec2 dir, p;
/* First point is support point in shape's general directions to eachother */ // First point is support point in shape's general directions to eachother
dir = SubVec2(starting_point(shape1), starting_point(shape0)); dir = SubVec2(starting_point(shape1), starting_point(shape0));
if (IsVec2Zero(dir)) dir = VEC2(1, 0); if (IsVec2Zero(dir)) dir = VEC2(1, 0);
s.a = CLD_MenkowskiPointFromDir(shape0, shape1, dir); s.a = CLD_MenkowskiPointFromDir(shape0, shape1, dir);
/* Second point is support point towards origin */ // Second point is support point towards origin
dir = NegVec2(s.a); dir = NegVec2(s.a);
p = CLD_MenkowskiPointFromDir(shape0, shape1, dir); p = CLD_MenkowskiPointFromDir(shape0, shape1, dir);
if (DotVec2(dir, p) >= 0) if (DotVec2(dir, p) >= 0)
@ -1054,12 +1067,12 @@ b32 CLD_GjkBoolean(CLD_Shape *shape0, CLD_Shape *shape1)
s.a = p; s.a = p;
for (;;) for (;;)
{ {
/* Third point is support point in direction of line normal towards origin */ // Third point is support point in direction of line normal towards origin
dir = PerpVec2TowardsDir(SubVec2(s.b, s.a), NegVec2(s.a)); dir = PerpVec2TowardsDir(SubVec2(s.b, s.a), NegVec2(s.a));
p = CLD_MenkowskiPointFromDir(shape0, shape1, dir); p = CLD_MenkowskiPointFromDir(shape0, shape1, dir);
if (DotVec2(dir, p) < 0) if (DotVec2(dir, p) < 0)
{ {
/* New point did not cross origin, collision impossible */ // New point did not cross origin, collision impossible
break; break;
} }
@ -1071,23 +1084,23 @@ b32 CLD_GjkBoolean(CLD_Shape *shape0, CLD_Shape *shape1)
Vec2 vac = SubVec2(s.c, s.a); Vec2 vac = SubVec2(s.c, s.a);
Vec2 a_to_origin = NegVec2(s.a); Vec2 a_to_origin = NegVec2(s.a);
dir = PerpVec2TowardsDir(vab, NegVec2(vac)); /* Normal of ab pointing away from c */ dir = PerpVec2TowardsDir(vab, NegVec2(vac)); // Normal of ab pointing away from c
if (DotVec2(dir, a_to_origin) >= 0) if (DotVec2(dir, a_to_origin) >= 0)
{ {
/* Point is in region ab, remove c from simplex (will happen automatically next iteration) */ // Point is in region ab, remove c from simplex (will happen automatically next iteration)
} }
else else
{ {
/* Point is not in region ab */ // Point is not in region ab
dir = PerpVec2TowardsDir(vac, NegVec2(vab)); /* Normal of ac pointing away from b */ dir = PerpVec2TowardsDir(vac, NegVec2(vab)); // Normal of ac pointing away from b
if (DotVec2(dir, a_to_origin) >= 0) if (DotVec2(dir, a_to_origin) >= 0)
{ {
/* Point is in region ac, remove b from simplex */ // Point is in region ac, remove b from simplex
s.b = s.c; s.b = s.c;
} }
else else
{ {
/* Point is in simplex */ // Point is in simplex
return 1; return 1;
} }
} }

View File

@ -1,13 +1,13 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Tweakable defines //~ Tweakable defines
/* How close can non-overlapping shapes be before collision is considered */ // How close can non-overlapping shapes be before collision is considered
#define CLD_CollisionTolerance 0.005f #define CLD_CollisionTolerance 0.005f
/* NOTE: Should always be less than tolerance, since colliding = 1 if origin is within this distance. */ // NOTE: Should always be less than tolerance, since colliding = 1 if origin is within this distance.
#define CLD_MinUniquePtDistSq (0.001f * 0.001f) #define CLD_MinUniquePtDistSq (0.001f * 0.001f)
/* To prevent extremely large prototypes when origin is in exact center of rounded feature */ // To prevent extremely large prototypes when origin is in exact center of rounded feature
#define CLD_MaxEpaIterations 64 #define CLD_MaxEpaIterations 64
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -26,14 +26,14 @@ Struct(CLD_Shape)
Struct(CLD_SupportPoint) Struct(CLD_SupportPoint)
{ {
Vec2 p; Vec2 p;
u32 i; /* Index of original point in shape */ u32 i; // Index of original point in shape
}; };
Struct(CLD_MenkowskiPoint) Struct(CLD_MenkowskiPoint)
{ {
Vec2 p; /* Menkowski difference point */ Vec2 p; // Menkowski difference point
CLD_SupportPoint s0; /* Support point of first shape in dir */ CLD_SupportPoint s0; // Support point of first shape in dir
CLD_SupportPoint s1; /* Support point of second shape in -dir */ CLD_SupportPoint s1; // Support point of second shape in -dir
}; };
Struct(CLD_MenkowskiSimplex) Struct(CLD_MenkowskiSimplex)
@ -55,7 +55,7 @@ Struct(CLD_CollisionPoint)
{ {
Vec2 point; Vec2 point;
f32 separation; f32 separation;
u32 id; /* Based on polygon edge-to-edge */ u32 id; // Based on polygon edge-to-edge
}; };
Struct(CLD_Prototype) Struct(CLD_Prototype)
@ -70,12 +70,12 @@ Struct(CLD_CollisionData)
CLD_CollisionPoint points[2]; CLD_CollisionPoint points[2];
u32 num_points; u32 num_points;
/* For debugging */ // For debugging
b32 solved; b32 solved;
CLD_MenkowskiSimplex simplex; CLD_MenkowskiSimplex simplex;
CLD_Prototype prototype; CLD_Prototype prototype;
/* For debugging */ // For debugging
Vec2 a0, b0, a1, b1; Vec2 a0, b0, a1, b1;
Vec2 a0_clipped, b0_clipped, a1_clipped, b1_clipped; Vec2 a0_clipped, b0_clipped, a1_clipped, b1_clipped;
}; };
@ -85,7 +85,7 @@ Struct(CLD_ClosestPointData)
Vec2 p0, p1; Vec2 p0, p1;
b32 colliding; b32 colliding;
/* For debugging */ // For debugging
b32 solved; b32 solved;
CLD_MenkowskiSimplex simplex; CLD_MenkowskiSimplex simplex;
CLD_Prototype prototype; CLD_Prototype prototype;
@ -108,9 +108,9 @@ Struct(CLD_GjkData)
CLD_MenkowskiSimplex simplex; CLD_MenkowskiSimplex simplex;
Vec2 final_dir; Vec2 final_dir;
/* If 1, simplex represents triangle inside of CLD_Menkowski difference // If 1, simplex represents triangle inside of CLD_Menkowski difference
* encapsulating the origin. If 0, simplex represents the closest // encapsulating the origin. If 0, simplex represents the closest
* feature on CLD_Menkowski difference to the origin. */ // feature on CLD_Menkowski difference to the origin.
b32 overlapping; b32 overlapping;
#if COLLIDER_DEBUG #if COLLIDER_DEBUG
@ -124,7 +124,7 @@ Struct(CLD_GjkData)
Struct(CLD_EpaData) Struct(CLD_EpaData)
{ {
Vec2 normal; Vec2 normal;
CLD_MenkowskiFeature closest_feature; /* Represents closest feature (edge or point) to origin on CLD_Menkowski difference */ CLD_MenkowskiFeature closest_feature; // Represents closest feature (edge or point) to origin on CLD_Menkowski difference
#if COLLIDER_DEBUG #if COLLIDER_DEBUG
CLD_Prototype prototype; CLD_Prototype prototype;

View File

@ -1,8 +1,8 @@
/* Project-wide configurable constants */ // Project-wide configurable constants
#define WRITE_DIR "power_play" #define WRITE_DIR "power_play"
/* Window title */ // Window title
#if IsRtcEnabled #if IsRtcEnabled
#if IsDeveloperModeEnabled #if IsDeveloperModeEnabled
#define WINDOW_TITLE "Debug (Developer Build)" #define WINDOW_TITLE "Debug (Developer Build)"
@ -20,20 +20,19 @@
#define DEFAULT_CAMERA_WIDTH (16) #define DEFAULT_CAMERA_WIDTH (16)
#define DEFAULT_CAMERA_HEIGHT ((f64)DEFAULT_CAMERA_WIDTH / (16.0 / 9.0)) #define DEFAULT_CAMERA_HEIGHT ((f64)DEFAULT_CAMERA_WIDTH / (16.0 / 9.0))
/* Rendered texture size + extra room for off-screen light falloff */ // Rendered texture size + extra room for off-screen light falloff
#define RENDER_WIDTH (640 + 250) #define RENDER_WIDTH (640 + 250)
#define RENDER_HEIGHT (360 + 250) #define RENDER_HEIGHT (360 + 250)
#define PIXELS_PER_UNIT ((f64)640 / (f64)DEFAULT_CAMERA_WIDTH) #define PIXELS_PER_UNIT ((f64)640 / (f64)DEFAULT_CAMERA_WIDTH)
/* How many ticks back in time should the user thread blend between? // How many ticks back in time should the user thread blend between?
* <Delay> = <USER_INTERP_RATIO> * <Tick interval> // <Delay> = <USER_INTERP_RATIO> * <Tick interval>
* E.g: At 1.5, the user thread will render 75ms back in time if the sim runs at 50tps // E.g: At 1.5, the user thread will render 75ms back in time if the sim runs at 50tps
*/
#define USER_INTERP_RATIO 1.2 #define USER_INTERP_RATIO 1.2
#define USER_INTERP_ENABLED 1 #define USER_INTERP_ENABLED 1
/* 64^2 = 4096 bins */ // 64^2 = 4096 bins
#define SPACE_CELL_BINS_SQRT (64) #define SPACE_CELL_BINS_SQRT (64)
#define SPACE_CELL_SIZE (1) #define SPACE_CELL_SIZE (1)
@ -41,9 +40,8 @@
#define SIM_TILES_PER_CHUNK_SQRT (16) #define SIM_TILES_PER_CHUNK_SQRT (16)
#define SIM_TICKS_PER_SECOND 100 #define SIM_TICKS_PER_SECOND 100
//#define SIM_TIMESCALE 1 // Like USER_INTERP_RATIO, but applies to snapshots received by the local sim from the
/* Like USER_INTERP_RATIO, but applies to snapshots received by the local sim from the // master sim (how far back in time should the client render the server's state)
* master sim (how far back in time should the client render the server's state) */
#define SIM_CLIENT_INTERP_RATIO 2.0 #define SIM_CLIENT_INTERP_RATIO 2.0
#define SIM_PHYSICS_SUBSTEPS 4 #define SIM_PHYSICS_SUBSTEPS 4
@ -76,17 +74,17 @@
#define GPU_SHADER_PRINT_BUFFER_SIZE Kibi(64); #define GPU_SHADER_PRINT_BUFFER_SIZE Kibi(64);
#define GPU_SHADER_PRINT_LOG 1 #define GPU_SHADER_PRINT_LOG 1
/* If enabled, bitbuffs will insert/verify magic numbers & length for each read & write */ // If enabled, bitbuffs will insert/verify magic numbers & length for each read & write
#define BITBUFF_DEBUG 0 #define BITBUFF_DEBUG 0
#define BITBUFF_TEST IsRtcEnabled #define BITBUFF_TEST IsRtcEnabled
/* If enabled, things like network writes & memory allocations will be tracked in a global statistics struct */ // If enabled, things like network writes & memory allocations will be tracked in a global statistics struct
#define GstatIsEnabled 1 #define GstatIsEnabled 1
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Settings //~ Settings
/* TODO: Move these to user-configurable settings */ // TODO: Move these to user-configurable settings
#define VSYNC 1 #define VSYNC 1
#define AUDIO_ENABLED 0 #define AUDIO_ENABLED 0

View File

@ -39,7 +39,7 @@ void D_DrawPolyEx(GPU_RenderSig *sig, Vec2Array vertices, GPU_Indices indices, u
GPU_PushRenderCmd(sig, &cmd); GPU_PushRenderCmd(sig, &cmd);
} }
/* Draws a filled polygon using triangles in a fan pattern */ // Draws a filled polygon using triangles in a fan pattern
void D_DrawPoly(GPU_RenderSig *sig, Vec2Array vertices, u32 color) void D_DrawPoly(GPU_RenderSig *sig, Vec2Array vertices, u32 color)
{ {
if (vertices.count >= 3) if (vertices.count >= 3)
@ -49,7 +49,7 @@ void D_DrawPoly(GPU_RenderSig *sig, Vec2Array vertices, u32 color)
u32 num_tris = vertices.count - 2; u32 num_tris = vertices.count - 2;
u32 num_indices = num_tris * 3; u32 num_indices = num_tris * 3;
/* Generate indices in a fan pattern */ // Generate indices in a fan pattern
GPU_Indices indices = ZI; GPU_Indices indices = ZI;
indices.count = num_indices; indices.count = num_indices;
indices.indices = PushStructsNoZero(scratch.arena, u32, num_indices); indices.indices = PushStructsNoZero(scratch.arena, u32, num_indices);
@ -112,7 +112,7 @@ void D_DrawLineGradient(GPU_RenderSig *sig, Vec2 start, Vec2 end, f32 thickness,
Quad quad = QuadFromLine(start, end, thickness); 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_DrawMaterial(sig, D_MATERIALPARAMS(.texture = g->solid_white_texture, .tint0 = start_color, .tint1 = end_color, .quad = quad));
#else #else
/* Placeholder */ // Placeholder
Quad quad = QuadFromLine(start, end, thickness); Quad quad = QuadFromLine(start, end, thickness);
D_DrawQuad(sig, quad, start_color); D_DrawQuad(sig, quad, start_color);
#endif #endif
@ -184,9 +184,9 @@ void D_DrawQuadLine(GPU_RenderSig *sig, Quad quad, f32 thickness, u32 color)
void D_DrawArrowLine(GPU_RenderSig *sig, Vec2 start, Vec2 end, f32 thickness, f32 arrowhead_height, u32 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 */ 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); arrowhead_height = MinF32(arrowhead_height, Vec2Len(SubVec2(end, start)) * max_height_to_line_ratio);
Vec2 head_start_dir = SubVec2(start, end); Vec2 head_start_dir = SubVec2(start, end);
@ -293,7 +293,7 @@ void D_DrawUiRect(GPU_RenderSig *sig, D_UiRectParams params)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Text //~ Text
/* Returns the rect of the text area */ // Returns the rect of the text area
Rect draw_text(GPU_RenderSig *sig, D_TextParams params) Rect draw_text(GPU_RenderSig *sig, D_TextParams params)
{ {
TempArena scratch = BeginScratchNoConflict(); TempArena scratch = BeginScratchNoConflict();
@ -367,8 +367,8 @@ Rect draw_text(GPU_RenderSig *sig, D_TextParams params)
} }
} }
/* Line ended */ // Line ended
/* TODO: Only create nodes for non-empty lines. Embed line number in the node. */ // TODO: Only create nodes for non-empty lines. Embed line number in the node.
D_TextLine *node = PushStruct(scratch.arena, D_TextLine); D_TextLine *node = PushStruct(scratch.arena, D_TextLine);
node->line_width = line_width; node->line_width = line_width;
node->num_glyphs = num_line_glyphs; node->num_glyphs = num_line_glyphs;
@ -398,7 +398,7 @@ Rect draw_text(GPU_RenderSig *sig, D_TextParams params)
bounds.width = widest_line; bounds.width = widest_line;
bounds.height = num_lines * line_spacing + first_line_top_offset + last_line_bottom_offset; bounds.height = num_lines * line_spacing + first_line_top_offset + last_line_bottom_offset;
/* Offset bounds X */ // Offset bounds X
switch (params.offset_x) switch (params.offset_x)
{ {
case DRAW_TEXT_OFFSET_X_LEFT: break; case DRAW_TEXT_OFFSET_X_LEFT: break;
@ -412,7 +412,7 @@ Rect draw_text(GPU_RenderSig *sig, D_TextParams params)
} break; } break;
} }
/* Offset bounds Y */ // Offset bounds Y
switch (params.offset_y) switch (params.offset_y)
{ {
case DRAW_TEXT_OFFSET_Y_TOP: break; case DRAW_TEXT_OFFSET_Y_TOP: break;
@ -437,7 +437,7 @@ Rect draw_text(GPU_RenderSig *sig, D_TextParams params)
Vec2 draw_pos = bounds.pos; Vec2 draw_pos = bounds.pos;
draw_pos.y += line_number * line_spacing - first_line_top_offset; draw_pos.y += line_number * line_spacing - first_line_top_offset;
/* Alignment */ // Alignment
switch (params.alignment) switch (params.alignment)
{ {
case DRAW_TEXT_ALIGNMENT_LEFT: break; case DRAW_TEXT_ALIGNMENT_LEFT: break;
@ -451,7 +451,7 @@ Rect draw_text(GPU_RenderSig *sig, D_TextParams params)
} break; } break;
} }
/* Draw glyphs in line */ // Draw glyphs in line
for (u64 i = 0; i < line->num_glyphs; ++i) for (u64 i = 0; i < line->num_glyphs; ++i)
{ {
D_TextGlyph *tg = &line->glyphs[i]; D_TextGlyph *tg = &line->glyphs[i];

View File

@ -35,27 +35,27 @@ Struct(D_UiRectParams)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Text types //~ Text types
/* How is text aligned within its area */ // How is text aligned within its area
Enum(D_TextAlignment) Enum(D_TextAlignment)
{ {
DRAW_TEXT_ALIGNMENT_LEFT, /* Default */ DRAW_TEXT_ALIGNMENT_LEFT, // Default
DRAW_TEXT_ALIGNMENT_CENTER, DRAW_TEXT_ALIGNMENT_CENTER,
DRAW_TEXT_ALIGNMENT_RIGHT DRAW_TEXT_ALIGNMENT_RIGHT
}; };
/* How does the specified text position relate to the text area. // How does the specified text position relate to the text area.
* E.g. BOTTOM & RIGHT means the bottom-right of the text area will snap to // E.g. BOTTOM & RIGHT means the bottom-right of the text area will snap to
* the specified position. */ // the specified position.
Enum(D_TextOffsetX) Enum(D_TextOffsetX)
{ {
DRAW_TEXT_OFFSET_X_LEFT, /* Default */ DRAW_TEXT_OFFSET_X_LEFT, // Default
DRAW_TEXT_OFFSET_X_CENTER, DRAW_TEXT_OFFSET_X_CENTER,
DRAW_TEXT_OFFSET_X_RIGHT DRAW_TEXT_OFFSET_X_RIGHT
}; };
Enum(D_TextOffsetY) Enum(D_TextOffsetY)
{ {
DRAW_TEXT_OFFSET_Y_TOP, /* Default */ DRAW_TEXT_OFFSET_Y_TOP, // Default
DRAW_TEXT_OFFSET_Y_CENTER, DRAW_TEXT_OFFSET_Y_CENTER,
DRAW_TEXT_OFFSET_Y_BOTTOM DRAW_TEXT_OFFSET_Y_BOTTOM
}; };

View File

@ -20,14 +20,14 @@ GC_FontKey GC_FontKeyFromResource(ResourceKey resource)
u64 GC_HashFromGlyphDesc(GC_GlyphDesc desc) u64 GC_HashFromGlyphDesc(GC_GlyphDesc desc)
{ {
/* TODO: Lower font-size precision to prevent unique hashes for slightly-different font sizes */ // 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); return RandU64FromSeeds(desc.font.r.v, ((u64)desc.codepoint << 32) | *(u32 *)&desc.font_size);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Run //~ Run
/* TODO: Thread-local cache */ // TODO: Thread-local cache
GC_Run GC_RunFromString(Arena *arena, String str, GC_FontKey font, f32 font_size) GC_Run GC_RunFromString(Arena *arena, String str, GC_FontKey font, f32 font_size)
{ {
GC_Run result = Zi; GC_Run result = Zi;
@ -53,7 +53,7 @@ GC_Run GC_RunFromString(Arena *arena, String str, GC_FontKey font, f32 font_size
u32 *uncached_codepoints = PushStructsNoZero(scratch.arena, u32, codepoints_count); u32 *uncached_codepoints = PushStructsNoZero(scratch.arena, u32, codepoints_count);
u64 uncached_codepoints_count = 0; u64 uncached_codepoints_count = 0;
/* TODO: Include advances for glyphs in run that have rasterized but not finished uploading to atlas */ // TODO: Include advances for glyphs in run that have rasterized but not finished uploading to atlas
u64 pending_glyphs_count = 0; u64 pending_glyphs_count = 0;
{ {
if (codepoints_count > 0) if (codepoints_count > 0)
@ -129,7 +129,7 @@ GC_Run GC_RunFromString(Arena *arena, String str, GC_FontKey font, f32 font_size
glyph->hash = hash; glyph->hash = hash;
Atomic64FetchSet(&glyph->async_copy_completion_target, I64Max); Atomic64FetchSet(&glyph->async_copy_completion_target, I64Max);
SllStackPush(bin->first, glyph); SllStackPush(bin->first, glyph);
/* Create cmd */ // Create cmd
{ {
GC_Cmd *cmd = &submit_cmds[submit_cmds_count]; GC_Cmd *cmd = &submit_cmds[submit_cmds_count];
cmd->glyph = glyph; cmd->glyph = glyph;
@ -229,7 +229,7 @@ void GC_TickAsync(WaveLaneCtx *lane, AsyncTickCtx *tick)
////////////////////////////// //////////////////////////////
//- Begin tick //- Begin tick
/* TODO: Limit cmds processed per-tick */ // TODO: Limit cmds processed per-tick
if (lane->idx == 0) if (lane->idx == 0)
{ {
@ -237,7 +237,7 @@ void GC_TickAsync(WaveLaneCtx *lane, AsyncTickCtx *tick)
Lock lock = LockE(&GC.submit.mutex); Lock lock = LockE(&GC.submit.mutex);
{ {
/* Pop cmds from submission queue */ // Pop cmds from submission queue
async->cmds.count = GC.submit.count; async->cmds.count = GC.submit.count;
async->cmds.v = PushStructsNoZero(tick->arena, GC_Cmd, GC.submit.count); async->cmds.v = PushStructsNoZero(tick->arena, GC_Cmd, GC.submit.count);
u64 cmd_idx = 0; u64 cmd_idx = 0;
@ -246,7 +246,7 @@ void GC_TickAsync(WaveLaneCtx *lane, AsyncTickCtx *tick)
async->cmds.v[cmd_idx] = n->cmd; async->cmds.v[cmd_idx] = n->cmd;
++cmd_idx; ++cmd_idx;
} }
/* Reset submission queue */ // Reset submission queue
GC.submit.first_free = GC.submit.first; GC.submit.first_free = GC.submit.first;
GC.submit.count = 0; GC.submit.count = 0;
GC.submit.first = 0; GC.submit.first = 0;
@ -262,7 +262,7 @@ void GC_TickAsync(WaveLaneCtx *lane, AsyncTickCtx *tick)
////////////////////////////// //////////////////////////////
//- Rasterize glyphs //- Rasterize glyphs
/* TODO: Process cmds unevenly to account for varying work size */ // TODO: Process cmds unevenly to account for varying work size
{ {
RngU64 cmd_idxs = WaveIdxRangeFromCount(lane, async->cmds.count); RngU64 cmd_idxs = WaveIdxRangeFromCount(lane, async->cmds.count);
@ -283,7 +283,7 @@ void GC_TickAsync(WaveLaneCtx *lane, AsyncTickCtx *tick)
} }
} }
/* TODO: Only sync first lane? */ // TODO: Only sync first lane?
WaveSync(lane); WaveSync(lane);
@ -302,13 +302,13 @@ void GC_TickAsync(WaveLaneCtx *lane, AsyncTickCtx *tick)
Vec2I32 image_dims = ttf_result.image_dims; Vec2I32 image_dims = ttf_result.image_dims;
/* TODO: Use a more efficient atlas packing algorithm for less wasted space `*/ // TODO: Use a more efficient atlas packing algorithm for less wasted space
GC_Atlas *atlas = GC.first_atlas; GC_Atlas *atlas = GC.first_atlas;
b32 can_use_atlas = 0; b32 can_use_atlas = 0;
Vec2I32 pos_in_atlas = Zi; Vec2I32 pos_in_atlas = Zi;
while (can_use_atlas == 0) while (can_use_atlas == 0)
{ {
/* Create atlas */ // Create atlas
if (!atlas) if (!atlas)
{ {
Arena *perm = PermArena(); Arena *perm = PermArena();
@ -328,7 +328,7 @@ void GC_TickAsync(WaveLaneCtx *lane, AsyncTickCtx *tick)
++GC.atlases_count; ++GC.atlases_count;
} }
/* Determine pos in atlas */ // Determine pos in atlas
pos_in_atlas = atlas->cur_pos; pos_in_atlas = atlas->cur_pos;
atlas->cur_row_height = MaxI32(atlas->cur_row_height, image_dims.y); atlas->cur_row_height = MaxI32(atlas->cur_row_height, image_dims.y);
if (pos_in_atlas.x + image_dims.x > atlas->dims.x); if (pos_in_atlas.x + image_dims.x > atlas->dims.x);
@ -348,7 +348,7 @@ void GC_TickAsync(WaveLaneCtx *lane, AsyncTickCtx *tick)
} }
} }
/* Atlas info */ // Atlas info
glyph->atlas = atlas; glyph->atlas = atlas;
glyph->tex_slice = RNG2I32(pos_in_atlas, AddVec2I32(pos_in_atlas, image_dims)); 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.x = (f32)glyph->tex_slice.p0.x / (f32)atlas->dims.x;
@ -356,7 +356,7 @@ void GC_TickAsync(WaveLaneCtx *lane, AsyncTickCtx *tick)
glyph->tex_slice_uv.p1.x = (f32)glyph->tex_slice.p1.x / (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; glyph->tex_slice_uv.p1.y = (f32)glyph->tex_slice.p1.y / (f32)atlas->dims.x;
/* Copy to atlas */ // Copy to atlas
u32 *image_pixels = ttf_result.image_pixels; u32 *image_pixels = ttf_result.image_pixels;
if (image_dims.x > 0 && image_dims.y > 0) if (image_dims.x > 0 && image_dims.y > 0)
{ {
@ -373,7 +373,7 @@ void GC_TickAsync(WaveLaneCtx *lane, AsyncTickCtx *tick)
} }
i64 completion_target = G_CommitCommandList(cl); i64 completion_target = G_CommitCommandList(cl);
/* Update completion targets */ // Update completion targets
for (u64 cmd_idx = 0; cmd_idx < async->cmds.count; ++cmd_idx) for (u64 cmd_idx = 0; cmd_idx < async->cmds.count; ++cmd_idx)
{ {
GC_Cmd *cmd = &async->cmds.v[cmd_idx]; GC_Cmd *cmd = &async->cmds.v[cmd_idx];

View File

@ -38,17 +38,17 @@ Struct(GC_Glyph)
u64 hash; u64 hash;
Atomic64 async_copy_completion_target; Atomic64 async_copy_completion_target;
/* Font info */ // Font info
f32 font_size; f32 font_size;
f32 font_ascent; f32 font_ascent;
f32 font_descent; f32 font_descent;
f32 font_cap; f32 font_cap;
/* Layout info */ // Layout info
f32 advance; f32 advance;
Rng2 bounds; Rng2 bounds;
/* Atlas info */ // Atlas info
GC_Atlas *atlas; GC_Atlas *atlas;
Rng2I32 tex_slice; Rng2I32 tex_slice;
Rng2 tex_slice_uv; Rng2 tex_slice_uv;
@ -64,8 +64,8 @@ Struct(GC_GlyphBin)
Struct(GC_RunRect) Struct(GC_RunRect)
{ {
Rng2 bounds; /* Visual bounds in relation to the baseline */ Rng2 bounds; // Visual bounds in relation to the baseline
f32 baseline_pos; /* Horizontal distance from start of baseline */ f32 baseline_pos; // Horizontal distance from start of baseline
f32 advance; f32 advance;
G_Texture2DRef tex; G_Texture2DRef tex;
@ -75,13 +75,13 @@ Struct(GC_RunRect)
Struct(GC_Run) Struct(GC_Run)
{ {
/* Run data */ // Run data
Rng2 bounds; /* Visual bounds of the run in relation to the baseline */ Rng2 bounds; // Visual bounds of the run in relation to the baseline
f32 baseline_length; f32 baseline_length;
u64 rects_count; u64 rects_count;
GC_RunRect *rects; GC_RunRect *rects;
/* Font info */ // Font info
f32 font_size; f32 font_size;
f32 font_ascent; f32 font_ascent;
f32 font_descent; f32 font_descent;
@ -97,7 +97,7 @@ Struct(GC_Cmd)
{ {
GC_Glyph *glyph; GC_Glyph *glyph;
/* Async temporary data */ // Async temporary data
TTF_GlyphResult rasterized; TTF_GlyphResult rasterized;
}; };

View File

@ -12,7 +12,7 @@ void G_BootstrapCommon(void)
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; G_ResourceHandle quad_indices = Zi;
u16 quad_data[6] = { 0, 1, 2, 0, 2, 3 }; u16 quad_data[6] = { 0, 1, 2, 0, 2, 3 };
@ -21,13 +21,13 @@ void G_BootstrapCommon(void)
g->quad_indices = G_IdxBuff16(quad_indices); g->quad_indices = G_IdxBuff16(quad_indices);
} }
/* Init point sampler */ // Init point sampler
{ {
G_ResourceHandle pt_sampler = G_PushSampler(gpu_perm, cl, .filter = G_Filter_MinMagMipPoint); G_ResourceHandle pt_sampler = G_PushSampler(gpu_perm, cl, .filter = G_Filter_MinMagMipPoint);
g->basic_sampler = G_PushSamplerStateRef(gpu_perm, pt_sampler); g->basic_sampler = G_PushSamplerStateRef(gpu_perm, pt_sampler);
} }
/* Init noise texture */ // Init noise texture
{ {
G_ResourceHandle noise_tex = Zi; G_ResourceHandle noise_tex = Zi;
String noise_data = DataFromResource(ResourceKeyFromStore(&G_Resources, Lit("noise_128x128x64_16.dat"))); String noise_data = DataFromResource(ResourceKeyFromStore(&G_Resources, Lit("noise_128x128x64_16.dat")));
@ -55,7 +55,7 @@ void G_BootstrapCommon(void)
} }
G_CommitCommandList(cl); G_CommitCommandList(cl);
/* Barrier all queues until direct queue finishes initializing resources */ // Barrier all queues until direct queue finishes initializing resources
G_Sync(G_QueueMask_Direct, G_QueueMask_All); G_Sync(G_QueueMask_Direct, G_QueueMask_All);
} }

View File

@ -3,7 +3,7 @@
Struct(G_SharedUtilState) Struct(G_SharedUtilState)
{ {
/* Common shared resources */ // Common shared resources
G_IndexBufferDesc quad_indices; G_IndexBufferDesc quad_indices;
G_SamplerStateRef basic_sampler; G_SamplerStateRef basic_sampler;
G_Texture3DRef basic_noise; G_Texture3DRef basic_noise;

View File

@ -46,21 +46,21 @@ Enum(G_QueueMask)
Struct(G_QueueCompletions) Struct(G_QueueCompletions)
{ {
i64 v[G_NumQueues]; /* Array of completions indexed by queue kind */ i64 v[G_NumQueues]; // Array of completions indexed by queue kind
}; };
/* All waiters will wait until specified queues reach their value in the `completions` array */ // All waiters will wait until specified queues reach their value in the `completions` array
Struct(G_QueueBarrierDesc) Struct(G_QueueBarrierDesc)
{ {
G_QueueCompletions completions; /* Completions that waiters should wait for */ G_QueueCompletions completions; // Completions that waiters should wait for
G_QueueMask wait_queues; /* Mask of queues that will wait for completions */ G_QueueMask wait_queues; // Mask of queues that will wait for completions
b32 wait_cpu; /* Will the cpu wait for completion */ b32 wait_cpu; // Will the cpu wait for completion
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Format types //~ Format types
/* NOTE: Matches DirectX DXGI_FORMAT */ // NOTE: Matches DirectX DXGI_FORMAT
Enum(G_Format) Enum(G_Format)
{ {
G_Format_Unknown = 0, G_Format_Unknown = 0,
@ -195,23 +195,23 @@ Enum(G_Stage)
{ {
G_Stage_None = 0, G_Stage_None = 0,
/* Compute stages */ // Compute stages
G_Stage_ComputeShading = (1 << 1), G_Stage_ComputeShading = (1 << 1),
/* Draw stages */ // Draw stages
G_Stage_IndexAssembly = (1 << 2), G_Stage_IndexAssembly = (1 << 2),
G_Stage_VertexShading = (1 << 3), G_Stage_VertexShading = (1 << 3),
G_Stage_PixelShading = (1 << 4), G_Stage_PixelShading = (1 << 4),
G_Stage_DepthStencil = (1 << 5), G_Stage_DepthStencil = (1 << 5),
G_Stage_RenderTarget = (1 << 6), G_Stage_RenderTarget = (1 << 6),
/* Copy stages */ // Copy stages
G_Stage_Copy = (1 << 7), G_Stage_Copy = (1 << 7),
/* Indirect stages */ // Indirect stages
G_Stage_Indirect = (1 << 8), G_Stage_Indirect = (1 << 8),
/* Aggregate stages */ // Aggregate stages
G_Stage_AllDraw = G_Stage_IndexAssembly | G_Stage_AllDraw = G_Stage_IndexAssembly |
G_Stage_VertexShading | G_Stage_VertexShading |
G_Stage_PixelShading | G_Stage_PixelShading |
@ -249,61 +249,58 @@ Enum(G_Layout)
{ {
G_Layout_NoChange, G_Layout_NoChange,
/* Allows a resource to be used on any queue with any access type, as long // Allows a resource to be used on any queue with any access type, as long
* as there is only one writer at a time, and the writer is not writing to // as there is only one writer at a time, and the writer is not writing to
* any texels currently being read. // any texels currently being read.
* // Resources cannot transition to/from this layout. They must be created
* Resources cannot transition to/from this layout. They must be created // with it and are locked to it.
* with it and are locked to it. G_Layout_Simultaneous, // D3D12_BARRIER_LAYOUT_COMMON + D3D12_RESOURCE_FLAG_ALLOW_SIMULTANEOUS_ACCESS
*/
G_Layout_Simultaneous, /* D3D12_BARRIER_LAYOUT_COMMON + D3D12_RESOURCE_FLAG_ALLOW_SIMULTANEOUS_ACCESS */
G_Layout_Undefined, /* D3D12_BARRIER_LAYOUT_UNDEFINED */ G_Layout_Undefined, // D3D12_BARRIER_LAYOUT_UNDEFINED
////////////////////////////// //////////////////////////////
//- Queue-agnostic //- Queue-agnostic
G_Layout_AnyQueue_ShaderRead_CopyRead_CopyWrite_Present, /* D3D12_BARRIER_LAYOUT_COMMON */ G_Layout_AnyQueue_ShaderRead_CopyRead_CopyWrite_Present, // D3D12_BARRIER_LAYOUT_COMMON
////////////////////////////// //////////////////////////////
//- Direct & Compute queue //- Direct & Compute queue
G_Layout_DirectComputeQueue_ShaderRead_CopyRead, /* D3D12_BARRIER_LAYOUT_GENERIC_READ */ G_Layout_DirectComputeQueue_ShaderRead_CopyRead, // D3D12_BARRIER_LAYOUT_GENERIC_READ
G_Layout_DirectComputeQueue_ShaderReadWrite, /* D3D12_BARRIER_LAYOUT_UNORDERED_ACCESS */ G_Layout_DirectComputeQueue_ShaderReadWrite, // D3D12_BARRIER_LAYOUT_UNORDERED_ACCESS
G_Layout_DirectComputeQueue_ShaderRead, /* D3D12_BARRIER_LAYOUT_SHADER_RESOURCE */ G_Layout_DirectComputeQueue_ShaderRead, // D3D12_BARRIER_LAYOUT_SHADER_RESOURCE
G_Layout_DirectComputeQueue_CopyRead, /* D3D12_BARRIER_LAYOUT_COPY_SOURCE */ G_Layout_DirectComputeQueue_CopyRead, // D3D12_BARRIER_LAYOUT_COPY_SOURCE
////////////////////////////// //////////////////////////////
//- Direct queue //- Direct queue
G_Layout_DirectQueue_ShaderRead_ShaderReadWrite_CopyRead_CopyWrite, /* D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_COMMON */ G_Layout_DirectQueue_ShaderRead_ShaderReadWrite_CopyRead_CopyWrite, // D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_COMMON
G_Layout_DirectQueue_ShaderRead_CopyRead_DepthStencilRead, /* D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_GENERIC_READ */ G_Layout_DirectQueue_ShaderRead_CopyRead_DepthStencilRead, // D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_GENERIC_READ
G_Layout_DirectQueue_ShaderReadWrite, /* D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_UNORDERED_ACCESS */ G_Layout_DirectQueue_ShaderReadWrite, // D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_UNORDERED_ACCESS
G_Layout_DirectQueue_ShaderRead, /* D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_SHADER_RESOURCE */ G_Layout_DirectQueue_ShaderRead, // D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_SHADER_RESOURCE
G_Layout_DirectQueue_CopyRead, /* D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_COPY_SOURCE */ G_Layout_DirectQueue_CopyRead, // D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_COPY_SOURCE
G_Layout_DirectQueue_DepthStencilRead_DepthStencilWrite, /* D3D12_BARRIER_LAYOUT_DEPTH_STENCIL_WRITE */ G_Layout_DirectQueue_DepthStencilRead_DepthStencilWrite, // D3D12_BARRIER_LAYOUT_DEPTH_STENCIL_WRITE
G_Layout_DirectQueue_DepthStencilRead, /* D3D12_BARRIER_LAYOUT_DEPTH_STENCIL_READ */ G_Layout_DirectQueue_DepthStencilRead, // D3D12_BARRIER_LAYOUT_DEPTH_STENCIL_READ
G_Layout_DirectQueue_RenderTargetWrite, /* D3D12_BARRIER_LAYOUT_RENDER_TARGET */ G_Layout_DirectQueue_RenderTargetWrite, // D3D12_BARRIER_LAYOUT_RENDER_TARGET
////////////////////////////// //////////////////////////////
//- Compute queue //- Compute queue
G_Layout_ComputeQueue_ShaderRead_ShaderReadWrite_CopyRead_CopyWrite, /* D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_COMMON */ G_Layout_ComputeQueue_ShaderRead_ShaderReadWrite_CopyRead_CopyWrite, // D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_COMMON
G_Layout_ComputeQueue_ShaderRead_CopyRead, /* D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_GENERIC_READ */ G_Layout_ComputeQueue_ShaderRead_CopyRead, // D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_GENERIC_READ
G_Layout_ComputeQueue_ShaderReadWrite, /* D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_UNORDERED_ACCESS */ G_Layout_ComputeQueue_ShaderReadWrite, // D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_UNORDERED_ACCESS
G_Layout_ComputeQueue_ShaderRead, /* D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_SHADER_RESOURCE */ G_Layout_ComputeQueue_ShaderRead, // D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_SHADER_RESOURCE
G_Layout_ComputeQueue_CopyRead, /* D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_COPY_SOURCE */ G_Layout_ComputeQueue_CopyRead, // D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_COPY_SOURCE
}; };
/* Barrier will execute after previous stages specified by `stage_prev`, and before next stages specified by `stage_next`. // Barrier will execute after previous stages specified by `stage_prev`, and before next stages specified by `stage_next`.
* When barrier executes: // When barrier executes:
* - Necessary resource flushes will occur based on `access_prev` & `access_next` // - Necessary resource flushes will occur based on `access_prev` & `access_next`
* - Texture layout will transition based on `layout` (if specified) // - Texture layout will transition based on `layout` (if specified)
*/
Struct(G_MemoryBarrierDesc) Struct(G_MemoryBarrierDesc)
{ {
G_ResourceHandle resource; G_ResourceHandle resource;
@ -318,10 +315,10 @@ Struct(G_MemoryBarrierDesc)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Filter types //~ Filter types
/* NOTE: Matches DirectX D3D12_FILTER */ // NOTE: Matches DirectX D3D12_FILTER
Enum(G_Filter) Enum(G_Filter)
{ {
/* Standard filter */ // Standard filter
G_Filter_MinMagMipPoint = 0, G_Filter_MinMagMipPoint = 0,
G_Filter_MinMagPointMipLinear = 0x1, G_Filter_MinMagPointMipLinear = 0x1,
G_Filter_MinPointMagLinearMipPoint = 0x4, G_Filter_MinPointMagLinearMipPoint = 0x4,
@ -333,7 +330,7 @@ Enum(G_Filter)
G_Filter_MinMagAnisotropicMipPoint = 0x54, G_Filter_MinMagAnisotropicMipPoint = 0x54,
G_Filter_Anisotropic = 0x55, G_Filter_Anisotropic = 0x55,
/* Comparison filter */ // Comparison filter
G_Filter_Comparison_MinMagMipPoint = 0x80, G_Filter_Comparison_MinMagMipPoint = 0x80,
G_Filter_Comparison_MinMagPointMipLinear = 0x81, G_Filter_Comparison_MinMagPointMipLinear = 0x81,
G_Filter_Comparison_MinPointMagLinearMipPoint = 0x84, G_Filter_Comparison_MinPointMagLinearMipPoint = 0x84,
@ -345,7 +342,7 @@ Enum(G_Filter)
G_Filter_Comparison_MinMagAnisotropicMipPoint = 0xd4, G_Filter_Comparison_MinMagAnisotropicMipPoint = 0xd4,
G_Filter_Comparison_Anisotropic = 0xd5, G_Filter_Comparison_Anisotropic = 0xd5,
/* Minimum filter */ // Minimum filter
G_Filter_Minimum_MinMagMipPoint = 0x100, G_Filter_Minimum_MinMagMipPoint = 0x100,
G_Filter_Minimum_MinMagPointMipLinear = 0x101, G_Filter_Minimum_MinMagPointMipLinear = 0x101,
G_Filter_Minimum_MinPointMagLinearMipPoint = 0x104, G_Filter_Minimum_MinPointMagLinearMipPoint = 0x104,
@ -357,7 +354,7 @@ Enum(G_Filter)
G_Filter_Minimum_MinMagAnisotropicMipPoint = 0x155, G_Filter_Minimum_MinMagAnisotropicMipPoint = 0x155,
G_Filter_Minimum_Anisotropic = 0x155, G_Filter_Minimum_Anisotropic = 0x155,
/* Maximum filter */ // Maximum filter
G_Filter_Maximum_MinMagMipPoint = 0x180, G_Filter_Maximum_MinMagMipPoint = 0x180,
G_Filter_Maximum_MinMagPointMipLinear = 0x181, G_Filter_Maximum_MinMagPointMipLinear = 0x181,
G_Filter_Maximum_MinPointMagLinearMipPoint = 0x184, G_Filter_Maximum_MinPointMagLinearMipPoint = 0x184,
@ -370,17 +367,17 @@ Enum(G_Filter)
G_Filter_Maximum_Anisotropic = 0x1d5 G_Filter_Maximum_Anisotropic = 0x1d5
}; };
/* NOTE: Matches DirectX D3D12_TEXTURE_ADDRESS_MODE */ // NOTE: Matches DirectX D3D12_TEXTURE_ADDRESS_MODE
Enum(G_AddressMode) Enum(G_AddressMode)
{ {
G_AddressMode_Wrap = 1, G_AddressMode_Wrap = 1,
G_AddressMode_Mirror = 2, G_AddressMode_Mirror = 2,
G_AddressMode_Clamp = 3, /* Default */ G_AddressMode_Clamp = 3, // Default
G_AddressMode_Border = 4, G_AddressMode_Border = 4,
G_AddressMode_MirrorOnce = 5 G_AddressMode_MirrorOnce = 5
}; };
/* NOTE: Matches DirectX D3D12_COMPARISON_FUNC */ // NOTE: Matches DirectX D3D12_COMPARISON_FUNC
Enum(G_ComparisonFunc) Enum(G_ComparisonFunc)
{ {
G_ComparisonFunc_None = 0, G_ComparisonFunc_None = 0,
@ -412,8 +409,8 @@ Enum(G_ResourceFlag)
G_ResourceFlag_AllowShaderReadWrite = (1 << 0), G_ResourceFlag_AllowShaderReadWrite = (1 << 0),
G_ResourceFlag_AllowRenderTarget = (1 << 1), G_ResourceFlag_AllowRenderTarget = (1 << 1),
G_ResourceFlag_AllowDepthStencil = (1 << 2), G_ResourceFlag_AllowDepthStencil = (1 << 2),
G_ResourceFlag_HostMemory = (1 << 3), /* Resource will be mapped into the cpu's address space */ G_ResourceFlag_HostMemory = (1 << 3), // Resource will be mapped into the cpu's address space
G_ResourceFlag_Uncached = (1 << 4), /* Cpu writes will be combined & reads will be uncached */ G_ResourceFlag_Uncached = (1 << 4), // Cpu writes will be combined & reads will be uncached
}; };
Struct(G_BufferDesc) Struct(G_BufferDesc)
@ -428,7 +425,7 @@ Struct(G_TextureDesc)
G_Format format; G_Format format;
Vec3I32 dims; Vec3I32 dims;
G_Layout initial_layout; G_Layout initial_layout;
i32 mip_levels; /* Will be clamped to range [1, inf) */ i32 mip_levels; // Will be clamped to range [1, inf)
Vec4 clear_color; Vec4 clear_color;
}; };
@ -485,7 +482,7 @@ Enum(G_RasterMode)
Struct(G_IndexBufferDesc) Struct(G_IndexBufferDesc)
{ {
G_ResourceHandle resource; G_ResourceHandle resource;
u32 index_size; /* Either 2 for u16 indices, or 4 for u32 indices */ u32 index_size; // Either 2 for u16 indices, or 4 for u32 indices
u32 index_count; u32 index_count;
}; };
@ -494,17 +491,17 @@ Struct(G_IndexBufferDesc)
Struct(G_Stats) Struct(G_Stats)
{ {
/* Memory usage */ // Memory usage
u64 local_committed; u64 local_committed;
u64 local_budget; u64 local_budget;
u64 non_local_committed; u64 non_local_committed;
u64 non_local_budget; u64 non_local_budget;
/* Resources */ // Resources
u64 driver_resources_allocated; u64 driver_resources_allocated;
u64 driver_descriptors_allocated; u64 driver_descriptors_allocated;
/* TODO: Arena stats (committed, reserved, etc) */ // TODO: Arena stats (committed, reserved, etc)
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -811,8 +808,8 @@ G_Stats G_QueryStats(void);
G_SwapchainHandle G_AcquireSwapchain(u64 os_window_handle); G_SwapchainHandle G_AcquireSwapchain(u64 os_window_handle);
void G_ReleaseSwapchain(G_SwapchainHandle swapchain); void G_ReleaseSwapchain(G_SwapchainHandle swapchain);
/* Waits until a new backbuffer is ready from the swapchain. // Waits until a new backbuffer is ready from the swapchain.
* This should be called before rendering for minimum latency. */ // This should be called before rendering for minimum latency.
G_ResourceHandle G_PrepareBackbuffer(G_SwapchainHandle swapchain_handle, G_Format format, Vec2I32 size); G_ResourceHandle G_PrepareBackbuffer(G_SwapchainHandle swapchain_handle, G_Format format, Vec2I32 size);
void G_CommitBackbuffer(G_ResourceHandle backbuffer, i32 vsync); void G_CommitBackbuffer(G_ResourceHandle backbuffer, i32 vsync);

File diff suppressed because it is too large Load Diff

View File

@ -71,22 +71,22 @@ Struct(G_D12_Resource)
u64 uid; u64 uid;
G_ResourceFlag flags; G_ResourceFlag flags;
/* Buffer info */ // Buffer info
u64 buffer_size; u64 buffer_size;
u64 buffer_size_actual; u64 buffer_size_actual;
D3D12_GPU_VIRTUAL_ADDRESS buffer_gpu_address; D3D12_GPU_VIRTUAL_ADDRESS buffer_gpu_address;
/* Texture info */ // Texture info
b32 is_texture; b32 is_texture;
G_Format texture_format; G_Format texture_format;
Vec3I32 texture_dims; Vec3I32 texture_dims;
i32 texture_mip_levels; i32 texture_mip_levels;
D3D12_BARRIER_LAYOUT texture_layout; D3D12_BARRIER_LAYOUT texture_layout;
/* Sampler info */ // Sampler info
G_SamplerDesc sampler_desc; G_SamplerDesc sampler_desc;
/* Backbuffer info */ // Backbuffer info
struct G_D12_Swapchain *swapchain; struct G_D12_Swapchain *swapchain;
}; };
@ -147,12 +147,11 @@ Struct(G_D12_DescriptorList)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Arena types //~ Arena types
/* TODO: // TODO:
* To support D3D12_RESOURCE_HEAP_TIER_1 devices, create separate heaps for: // To support D3D12_RESOURCE_HEAP_TIER_1 devices, create separate heaps for:
* - Buffers // - Buffers
* - Non-render target & non-depth stencil textures // - Non-render target & non-depth stencil textures
* - Render target or depth stencil textures // - Render target or depth stencil textures
*/
Enum(G_D12_ResourceHeapKind) Enum(G_D12_ResourceHeapKind)
{ {
G_D12_ResourceHeapKind_Gpu, G_D12_ResourceHeapKind_Gpu,
@ -212,14 +211,14 @@ Struct(G_D12_StagingRegionNode)
{ {
G_D12_StagingRing *ring; G_D12_StagingRing *ring;
/* Ring links (requires ring lock to read) */ // Ring links (requires ring lock to read)
G_D12_StagingRegionNode *prev; G_D12_StagingRegionNode *prev;
G_D12_StagingRegionNode *next; G_D12_StagingRegionNode *next;
/* Command list links */ // Command list links
G_D12_StagingRegionNode *next_in_command_list; G_D12_StagingRegionNode *next_in_command_list;
/* Region info */ // Region info
Atomic64 completion_target; Atomic64 completion_target;
u64 pos; u64 pos;
}; };
@ -242,17 +241,17 @@ Struct(G_D12_Queue)
ID3D12Fence *commit_fence; ID3D12Fence *commit_fence;
u64 commit_fence_target; u64 commit_fence_target;
/* Global resources */ // Global resources
u64 print_buffer_size; u64 print_buffer_size;
G_ResourceHandle print_buffer; G_ResourceHandle print_buffer;
G_ResourceHandle print_readback_buffer; G_ResourceHandle print_readback_buffer;
G_RWByteAddressBufferRef print_buffer_ref; G_RWByteAddressBufferRef print_buffer_ref;
/* Raw command lists */ // Raw command lists
struct G_D12_RawCommandList *first_committed_cl; struct G_D12_RawCommandList *first_committed_cl;
struct G_D12_RawCommandList *last_committed_cl; struct G_D12_RawCommandList *last_committed_cl;
/* Staging heap */ // Staging heap
Mutex staging_mutex; Mutex staging_mutex;
G_D12_StagingRing *staging_ring; G_D12_StagingRing *staging_ring;
@ -272,7 +271,7 @@ Struct(G_D12_RawCommandList)
ID3D12CommandAllocator *d3d_ca; ID3D12CommandAllocator *d3d_ca;
ID3D12GraphicsCommandList7 *d3d_cl; ID3D12GraphicsCommandList7 *d3d_cl;
/* Direct queue command lists keep a constant list of CPU-only descriptors */ // Direct queue command lists keep a constant list of CPU-only descriptors
G_D12_Descriptor *rtv_descriptors[G_MaxRenderTargets]; G_D12_Descriptor *rtv_descriptors[G_MaxRenderTargets];
G_D12_Descriptor *rtv_clear_descriptor; G_D12_Descriptor *rtv_clear_descriptor;
}; };
@ -311,7 +310,7 @@ Struct(G_D12_Cmd)
{ {
G_MemoryBarrierDesc desc; G_MemoryBarrierDesc desc;
/* Post-batch data */ // Post-batch data
b32 is_end_of_batch; b32 is_end_of_batch;
u64 batch_gen; u64 batch_gen;
} barrier; } barrier;
@ -414,35 +413,35 @@ Struct(G_D12_SharedState)
{ {
Atomic64Padded resource_creation_gen; Atomic64Padded resource_creation_gen;
/* Stats */ // Stats
Atomic64 driver_resources_allocated; Atomic64 driver_resources_allocated;
Atomic64 driver_descriptors_allocated; Atomic64 driver_descriptors_allocated;
/* Queues */ // Queues
G_D12_Queue queues[G_NumQueues]; G_D12_Queue queues[G_NumQueues];
/* Descriptor heaps */ // Descriptor heaps
G_D12_DescriptorHeap descriptor_heaps[G_D12_DescriptorHeapKind_Count]; G_D12_DescriptorHeap descriptor_heaps[G_D12_DescriptorHeapKind_Count];
/* Rootsig */ // Rootsig
ID3D12RootSignature *bindless_rootsig; ID3D12RootSignature *bindless_rootsig;
/* Pipelines */ // Pipelines
G_D12_PipelineBin pipeline_bins[1024]; G_D12_PipelineBin pipeline_bins[1024];
/* Command lists */ // Command lists
Mutex free_cmd_lists_mutex; Mutex free_cmd_lists_mutex;
G_D12_CmdList *first_free_cmd_list; G_D12_CmdList *first_free_cmd_list;
/* Command chunks */ // Command chunks
Mutex free_cmd_chunks_mutex; Mutex free_cmd_chunks_mutex;
G_D12_CmdChunk *first_free_cmd_chunk; G_D12_CmdChunk *first_free_cmd_chunk;
/* Swapchains */ // Swapchains
Mutex free_swapchains_mutex; Mutex free_swapchains_mutex;
G_D12_Swapchain *first_free_swapchain; G_D12_Swapchain *first_free_swapchain;
/* Device */ // Device
IDXGIFactory6 *factory; IDXGIFactory6 *factory;
IDXGIAdapter3 *adapter; IDXGIAdapter3 *adapter;
ID3D12Device10 *device; ID3D12Device10 *device;

View File

@ -33,13 +33,13 @@ Struct(G_SamplerStateRef) { u32 v; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Constant types //~ Constant types
/* //
* D3D12 exposes 64 root constants and Vulkan exposes 32 push constants. // D3D12 exposes 64 root constants and Vulkan exposes 32 push constants.
* Supposedly amd hardware will spill constants to scratch memory once there // Supposedly amd hardware will spill constants to scratch memory once there
* are more than 13: https://gpuopen.com/learn/rdna-performance-guide/ // are more than 13: https://gpuopen.com/learn/rdna-performance-guide/
*/ //
#define G_NumGeneralPurposeConstants (8) /* Constants available for any usage */ #define G_NumGeneralPurposeConstants (8) // Constants available for any usage
#define G_NumReservedConstants (1) /* Constants reserved for usage by the GPU layer */ #define G_NumReservedConstants (1) // Constants reserved for usage by the GPU layer
#define G_NumConstants (G_NumGeneralPurposeConstants + G_NumReservedConstants) #define G_NumConstants (G_NumGeneralPurposeConstants + G_NumReservedConstants)
#if IsLanguageC #if IsLanguageC
@ -59,9 +59,9 @@ Struct(G_SamplerStateRef) { u32 v; };
//~ Resource dereference //~ Resource dereference
#if IsLanguageG #if IsLanguageG
/* TODO: Non-uniform resource access currently is assumed as the default // TODO: Non-uniform resource access currently is assumed as the default
* behavior. We may want to add explicit "uniform" variants for // behavior. We may want to add explicit "uniform" variants for
* optimization on amd in the future. */ // optimization on amd in the future.
template<typename T> StructuredBuffer<T> G_Dereference(G_StructuredBufferRef 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)]; } template<typename T> RWStructuredBuffer<T> G_Dereference(G_RWStructuredBufferRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; }
@ -98,7 +98,7 @@ Struct(G_SamplerStateRef) { u32 v; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Reserved constants //~ Reserved constants
/* The constants declared below assume this configuration is accurate for slot usage */ // The constants declared below assume this configuration is accurate for slot usage
StaticAssert(G_NumGeneralPurposeConstants == 8); StaticAssert(G_NumGeneralPurposeConstants == 8);
StaticAssert(G_NumReservedConstants == 1); StaticAssert(G_NumReservedConstants == 1);
@ -107,7 +107,7 @@ G_ForceDeclConstant(G_RWByteAddressBufferRef, G_ShaderConst_PrintBufferRef, 8)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Debug printf //~ Debug printf
/* This technique is based on MJP's article - https://therealmjp.github.io/posts/hlsl-printf/ */ // This technique is based on MJP's article - https://therealmjp.github.io/posts/hlsl-printf/
Enum(G_FmtArgKind) Enum(G_FmtArgKind)
{ {
@ -165,7 +165,7 @@ Struct(G_FmtArg)
Struct(G_TempPrintBuffer) Struct(G_TempPrintBuffer)
{ {
/* NOTE: The larger the array size, the longer the compilation time */ // NOTE: The larger the array size, the longer the compilation time
u32 byte_chunks[64]; u32 byte_chunks[64];
u32 bytes_count; u32 bytes_count;
u32 chars_count; u32 chars_count;
@ -181,7 +181,7 @@ Struct(G_FmtArg)
u32 byte_idx_in_chunk = buff.bytes_count & 0x03; u32 byte_idx_in_chunk = buff.bytes_count & 0x03;
if (byte_idx_in_chunk == 0) if (byte_idx_in_chunk == 0)
{ {
/* Since buff is not zero initialized, we set the chunk on first write here */ // Since buff is not zero initialized, we set the chunk on first write here
buff.byte_chunks[chunk_idx] = v & 0xFF; buff.byte_chunks[chunk_idx] = v & 0xFF;
} }
else else
@ -209,23 +209,23 @@ Struct(G_FmtArg)
u32 chunks_count = (buff.bytes_count + 3) / 4; u32 chunks_count = (buff.bytes_count + 3) / 4;
u32 alloc_size = 0; u32 alloc_size = 0;
alloc_size += 4; /* Header */ alloc_size += 4; // Header
alloc_size += chunks_count * 4; /* Chunks */ alloc_size += chunks_count * 4; // Chunks
/* Atomic fetch + add to base counter */ // Atomic fetch + add to base counter
u32 base; u32 base;
rw.InterlockedAdd(0, alloc_size, base); rw.InterlockedAdd(0, alloc_size, base);
base += 4; /* Offset for allocation counter */ base += 4; // Offset for allocation counter
base += 4; /* Offset for success counter */ base += 4; // Offset for success counter
base += 4; /* Offset for overflow counter */ base += 4; // Offset for overflow counter
if ((base + alloc_size) < countof(rw)) if ((base + alloc_size) < countof(rw))
{ {
/* Increment success counter */ // Increment success counter
rw.InterlockedAdd(4, 1); rw.InterlockedAdd(4, 1);
u32 pos = 0; u32 pos = 0;
/* Write header */ // Write header
{ {
u32 header = 0; u32 header = 0;
header |= (buff.chars_count << 0) & 0x0000FFFF; header |= (buff.chars_count << 0) & 0x0000FFFF;
@ -235,7 +235,7 @@ Struct(G_FmtArg)
pos += 4; pos += 4;
} }
/* Write chunks */ // Write chunks
for (u32 chunk_idx = 0; chunk_idx < chunks_count; ++chunk_idx) for (u32 chunk_idx = 0; chunk_idx < chunks_count; ++chunk_idx)
{ {
u32 chunk = buff.byte_chunks[chunk_idx]; u32 chunk = buff.byte_chunks[chunk_idx];
@ -245,7 +245,7 @@ Struct(G_FmtArg)
} }
else else
{ {
/* Increment overflow counter */ // Increment overflow counter
rw.InterlockedAdd(8, 1); rw.InterlockedAdd(8, 1);
} }
} }

View File

@ -1,7 +1,6 @@
/* TODO (if we want to be JSON standard compliant): // TODO (if we want to be JSON standard compliant):
* - Support unicode escape sequences in strings (\u) // - Support unicode escape sequences in strings (\u)
* - Don't allow leading 0s in numbers // - Don't allow leading 0s in numbers
*/
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Lex //~ Lex
@ -32,7 +31,7 @@ JSON_TokenList JSON_TokensFromString(Arena *arena, String src)
b32 lexing_done = 0; b32 lexing_done = 0;
while (!lexing_done) while (!lexing_done)
{ {
/* Skip whitespace */ // Skip whitespace
b32 whitespace_done = 0; b32 whitespace_done = 0;
while (!whitespace_done && pos < src.len) while (!whitespace_done && pos < src.len)
{ {
@ -51,24 +50,24 @@ JSON_TokenList JSON_TokensFromString(Arena *arena, String src)
} }
} }
/* Create token */ // Create token
JSON_Token *t = JSON_PushToken(arena, &result); JSON_Token *t = JSON_PushToken(arena, &result);
t->start = pos; t->start = pos;
if (pos >= src.len) if (pos >= src.len)
{ {
t->kind = JSON_TokenKind_Eof; t->kind = JSON_TokenKind_Eof;
t->next = t; /* Self reference */ t->next = t; // Self reference
lexing_done = 1; lexing_done = 1;
} }
else else
{ {
/* Lex known token kinds */ // Lex known token kinds
switch (src.text[pos]) switch (src.text[pos])
{ {
default: break; default: break;
/* Symbols */ // Symbols
case ',': case ',':
{ {
t->kind = JSON_TokenKind_Comma; t->kind = JSON_TokenKind_Comma;
@ -105,10 +104,10 @@ JSON_TokenList JSON_TokensFromString(Arena *arena, String src)
++pos; ++pos;
} break; } break;
/* Number */ // Number
case '-': case '-':
{ {
/* Verify '-' precedes digit */ // Verify '-' precedes digit
b32 next_is_digit = 0; b32 next_is_digit = 0;
if ((pos + 1) < src.len) if ((pos + 1) < src.len)
{ {
@ -157,7 +156,7 @@ JSON_TokenList JSON_TokensFromString(Arena *arena, String src)
case JSON_Case_Digit0Through9: case JSON_Case_Digit0Through9:
{ {
/* Consume '.' */ // Consume '.'
++consume; ++consume;
} break; } break;
} }
@ -184,7 +183,7 @@ JSON_TokenList JSON_TokensFromString(Arena *arena, String src)
{ {
case JSON_Case_Digit0Through9: case JSON_Case_Digit0Through9:
{ {
/* Consume 'E'/'e' */ // Consume 'E'/'e'
++consume; ++consume;
} break; } break;
@ -200,7 +199,7 @@ JSON_TokenList JSON_TokensFromString(Arena *arena, String src)
case JSON_Case_Digit0Through9: case JSON_Case_Digit0Through9:
{ {
/* Consume 'E'/'e' & '+'/'-' */ // Consume 'E'/'e' & '+'/'-'
consume += 2; consume += 2;
} break; } break;
} }
@ -224,7 +223,7 @@ JSON_TokenList JSON_TokensFromString(Arena *arena, String src)
} }
} break; } break;
/* String */ // String
case '"': case '"':
{ {
++pos; ++pos;
@ -270,7 +269,7 @@ JSON_TokenList JSON_TokensFromString(Arena *arena, String src)
} }
} break; } break;
/* Keywords */ // Keywords
case 't': case 't':
case 'f': case 'f':
case 'n': case 'n':
@ -282,7 +281,7 @@ JSON_TokenList JSON_TokensFromString(Arena *arena, String src)
{ {
if ((pos + keyword.len) < src.len) if ((pos + keyword.len) < src.len)
{ {
/* Don't match if word continues past keyword */ // Don't match if word continues past keyword
switch (src.text[pos + keyword.len]) switch (src.text[pos + keyword.len])
{ {
default: default:
@ -316,7 +315,7 @@ JSON_TokenList JSON_TokensFromString(Arena *arena, String src)
} }
} }
/* Lex unknown token */ // Lex unknown token
if (t->kind == JSON_TokenKind_Unknown) if (t->kind == JSON_TokenKind_Unknown)
{ {
b32 unknown_done = 0; b32 unknown_done = 0;
@ -339,7 +338,7 @@ JSON_TokenList JSON_TokensFromString(Arena *arena, String src)
} }
t->end = pos; t->end = pos;
/* Exit early if unknown token encountered */ // Exit early if unknown token encountered
return result; return result;
} }
else else
@ -370,7 +369,7 @@ f64 interpret_number(String src)
u64 exponent_right = 0; u64 exponent_right = 0;
i32 exponent_sign = 1; i32 exponent_sign = 1;
/* Lex number parts */ // Lex number parts
{ {
u64 pos = 0; u64 pos = 0;
if (src.len > 0 && src.text[0] == '-') if (src.len > 0 && src.text[0] == '-')
@ -386,7 +385,7 @@ f64 interpret_number(String src)
{ {
default: default:
{ {
/* Unreachable */ // Unreachable
Assert(0); Assert(0);
++pos; ++pos;
} break; } break;
@ -449,7 +448,7 @@ f64 interpret_number(String src)
{ {
default: default:
{ {
/* Unreachable */ // Unreachable
Assert(0); Assert(0);
++pos; ++pos;
} break; } break;
@ -474,7 +473,7 @@ f64 interpret_number(String src)
{ {
default: default:
{ {
/* Unreachable */ // Unreachable
Assert(0); Assert(0);
++pos; ++pos;
} break; } break;
@ -492,7 +491,7 @@ f64 interpret_number(String src)
f64 result = 0; f64 result = 0;
/* Process whole part */ // Process whole part
if (whole_present) if (whole_present)
{ {
u64 pos = whole_left; u64 pos = whole_left;
@ -506,7 +505,7 @@ f64 interpret_number(String src)
result *= whole_sign; result *= whole_sign;
} }
/* Process fraction part */ // Process fraction part
if (fraction_present) if (fraction_present)
{ {
u64 frac_whole = 0; u64 frac_whole = 0;
@ -522,7 +521,7 @@ f64 interpret_number(String src)
result += (f64)frac_whole / PowU64(10, (fraction_right - fraction_left + 1)); result += (f64)frac_whole / PowU64(10, (fraction_right - fraction_left + 1));
} }
/* Process exponent part */ // Process exponent part
if (exponent_present) if (exponent_present)
{ {
u64 exponent_whole = 0; u64 exponent_whole = 0;
@ -563,7 +562,7 @@ String interpret_string(Arena *arena, String src, String *error)
} }
return result; return result;
} }
/* Ignore beginning quote */ // Ignore beginning quote
u64 pos = 1; u64 pos = 1;
b32 valid_close = 0; b32 valid_close = 0;
@ -596,7 +595,7 @@ String interpret_string(Arena *arena, String src, String *error)
++pos; ++pos;
} break; } break;
/* Backspace */ // Backspace
case 'b': case 'b':
{ {
*PushStructNoZero(arena, u8) = '\b'; *PushStructNoZero(arena, u8) = '\b';
@ -604,7 +603,7 @@ String interpret_string(Arena *arena, String src, String *error)
++pos; ++pos;
} break; } break;
/* Formfeed */ // Formfeed
case 'f': case 'f':
{ {
*PushStructNoZero(arena, u8) = '\f'; *PushStructNoZero(arena, u8) = '\f';
@ -612,7 +611,7 @@ String interpret_string(Arena *arena, String src, String *error)
++pos; ++pos;
} break; } break;
/* Linefeed */ // Linefeed
case 'n': case 'n':
{ {
*PushStructNoZero(arena, u8) = '\n'; *PushStructNoZero(arena, u8) = '\n';
@ -620,7 +619,7 @@ String interpret_string(Arena *arena, String src, String *error)
++pos; ++pos;
} break; } break;
/* Carriage return */ // Carriage return
case 'r': case 'r':
{ {
*PushStructNoZero(arena, u8) = '\r'; *PushStructNoZero(arena, u8) = '\r';
@ -628,7 +627,7 @@ String interpret_string(Arena *arena, String src, String *error)
++pos; ++pos;
} break; } break;
/* Horizontal tab */ // Horizontal tab
case 't': case 't':
{ {
*PushStructNoZero(arena, u8) = '\t'; *PushStructNoZero(arena, u8) = '\t';
@ -636,10 +635,10 @@ String interpret_string(Arena *arena, String src, String *error)
++pos; ++pos;
} break; } break;
/* TODO: Unicode escape support */ // TODO: Unicode escape support
// case 'u': // case 'u':
// { // {
// /* TODO */ // // TODO
// } break; // } break;
} }
} }
@ -717,7 +716,7 @@ void JSON_Parse(Arena *arena, JSON_Parser *p)
at = at->next; at = at->next;
} }
/* Depth first stack */ // Depth first stack
*PushStructNoZero(scratch.arena, JSON_Blob *) = root; *PushStructNoZero(scratch.arena, JSON_Blob *) = root;
u64 stack_count = 1; u64 stack_count = 1;
@ -731,7 +730,7 @@ void JSON_Parse(Arena *arena, JSON_Parser *p)
b32 is_new_parent = 0; b32 is_new_parent = 0;
if (json->type == JSON_Type_Object || json->type == JSON_Type_Array) if (json->type == JSON_Type_Object || json->type == JSON_Type_Array)
{ {
/* No more children to parse for object/array, check for closing brace. */ // No more children to parse for object/array, check for closing brace.
JSON_TokenKind tok_close_kind = json->type == JSON_Type_Object ? JSON_TokenKind_CurlyBraceClose : JSON_TokenKind_SquareBraceClose; JSON_TokenKind tok_close_kind = json->type == JSON_Type_Object ? JSON_TokenKind_CurlyBraceClose : JSON_TokenKind_SquareBraceClose;
if (at->kind == tok_close_kind) if (at->kind == tok_close_kind)
{ {
@ -750,7 +749,7 @@ void JSON_Parse(Arena *arena, JSON_Parser *p)
{ {
if (parent_json->type == JSON_Type_Object) if (parent_json->type == JSON_Type_Object)
{ {
/* Parse key */ // Parse key
if (at->kind == JSON_TokenKind_String) if (at->kind == JSON_TokenKind_String)
{ {
String t_text = (String) { .len = at->end - at->start, .text = &src.text[at->start] }; String t_text = (String) { .len = at->end - at->start, .text = &src.text[at->start] };
@ -773,7 +772,7 @@ void JSON_Parse(Arena *arena, JSON_Parser *p)
goto abort; goto abort;
} }
/* Parse colon */ // Parse colon
if (at->kind == JSON_TokenKind_Colon) if (at->kind == JSON_TokenKind_Colon)
{ {
at = at->next; at = at->next;
@ -796,7 +795,7 @@ void JSON_Parse(Arena *arena, JSON_Parser *p)
parent_json->child_last = json; parent_json->child_last = json;
} }
/* Parse value */ // Parse value
switch (at->kind) switch (at->kind)
{ {
default: default:
@ -871,11 +870,11 @@ void JSON_Parse(Arena *arena, JSON_Parser *p)
if (is_new_parent) if (is_new_parent)
{ {
/* Push self back to stack to re-check for closing brace later */ // Push self back to stack to re-check for closing brace later
*PushStructNoZero(scratch.arena, JSON_Blob *) = json; *PushStructNoZero(scratch.arena, JSON_Blob *) = json;
++stack_count; ++stack_count;
/* Create child & push to stack */ // Create child & push to stack
JSON_Blob *child = PushStruct(arena, JSON_Blob); JSON_Blob *child = PushStruct(arena, JSON_Blob);
child->parent = json; child->parent = json;
*PushStructNoZero(scratch.arena, JSON_Blob *) = child; *PushStructNoZero(scratch.arena, JSON_Blob *) = child;
@ -883,10 +882,10 @@ void JSON_Parse(Arena *arena, JSON_Parser *p)
} }
else if (parent_json) else if (parent_json)
{ {
/* Check for comma */ // Check for comma
if (at->kind == JSON_TokenKind_Comma) if (at->kind == JSON_TokenKind_Comma)
{ {
/* Create sibling & push to stack */ // Create sibling & push to stack
JSON_Blob *sibling = PushStruct(arena, JSON_Blob); JSON_Blob *sibling = PushStruct(arena, JSON_Blob);
sibling->parent = parent_json; sibling->parent = parent_json;
*PushStructNoZero(scratch.arena, JSON_Blob *) = sibling; *PushStructNoZero(scratch.arena, JSON_Blob *) = sibling;
@ -910,13 +909,13 @@ JSON_Result JSON_BlobFromString(Arena *arena, String src)
JSON_TokenList tl = JSON_TokensFromString(scratch.arena, src); JSON_TokenList tl = JSON_TokensFromString(scratch.arena, src);
/* Parse root */ // Parse root
JSON_Parser p = ZI; JSON_Parser p = ZI;
p.src = src; p.src = src;
p.at = tl.token_first; p.at = tl.token_first;
JSON_Parse(arena, &p); JSON_Parse(arena, &p);
/* Verify end of file */ // Verify end of file
if (p.errors.count == 0 && p.at->kind != JSON_TokenKind_Eof) if (p.errors.count == 0 && p.at->kind != JSON_TokenKind_Eof)
{ {
JSON_PushError(arena, &p, p.at, Lit("Expected end of file.")); JSON_PushError(arena, &p, p.at, Lit("Expected end of file."));

View File

@ -130,11 +130,11 @@ Global Readonly JSON_TokenKind JSON_keyword_types[] = {
Struct(JSON_Parser) Struct(JSON_Parser)
{ {
/* Input */ // Input
String src; String src;
JSON_Token *at; JSON_Token *at;
/* Output */ // Output
JSON_Blob *root; JSON_Blob *root;
JSON_ErrorList errors; JSON_ErrorList errors;
}; };

View File

@ -110,7 +110,7 @@ EmbedObj Embed(String store_name, String dir_path)
Arena *perm = PermArena(); Arena *perm = PermArena();
EmbedObj result = Zi; EmbedObj result = Zi;
/* Generate resource archive contents */ // Generate resource archive contents
String arc_contents = Zi; String arc_contents = Zi;
{ {
StringList files = Zi; StringList files = Zi;
@ -156,17 +156,18 @@ EmbedObj Embed(String store_name, String dir_path)
BB_Buff bb = BB_AcquireBuff(Gibi(2)); BB_Buff bb = BB_AcquireBuff(Gibi(2));
BB_Writer bw = BB_WriterFromBuff(&bb); BB_Writer bw = BB_WriterFromBuff(&bb);
/* Write magic */ // Write magic
BB_WriteUBits(&bw, ResourceEmbeddedMagic, 64); BB_WriteUBits(&bw, ResourceEmbeddedMagic, 64);
/* Write header */ // Write header
BB_WriteUBits(&bw, entries_count, 64); BB_WriteUBits(&bw, entries_count, 64);
/* Reserve entries space */ // Reserve entries space
u64 entry_size = 8 /* Name start */ u64 entry_size = 0
+ 8 /* Name end */ + 8 // Name start
+ 8 /* Data start */ + 8 // Name end
+ 8; /* Data end */ + 8 // Data start
+ 8; // Data end
u8 *entries_start = BB_GetWrittenRaw(&bw) + BB_GetNumBytesWritten(&bw); u8 *entries_start = BB_GetWrittenRaw(&bw) + BB_GetNumBytesWritten(&bw);
u64 entries_size = entry_size * entries_count; u64 entries_size = entry_size * entries_count;
String entries_str = STRING(entries_size, entries_start); String entries_str = STRING(entries_size, entries_start);
@ -174,26 +175,26 @@ EmbedObj Embed(String store_name, String dir_path)
BB_Buff entries_bb = BB_BuffFromString(entries_str); BB_Buff entries_bb = BB_BuffFromString(entries_str);
BB_Writer entries_bw = BB_WriterFromBuff(&entries_bb); BB_Writer entries_bw = BB_WriterFromBuff(&entries_bb);
/* Write entries */ // Write entries
for (EntryNode *en = first_entry; en; en = en->next) for (EntryNode *en = first_entry; en; en = en->next)
{ {
/* TODO: Copy file data directly into archive file */ // TODO: Copy file data directly into archive file
String file_data = F_DataFromFile(perm, en->file_name); String file_data = F_DataFromFile(perm, en->file_name);
/* Write name */ // Write name
BB_WriteAlignBytes(&bw, 64); BB_WriteAlignBytes(&bw, 64);
u64 name_start = BB_GetNumBytesWritten(&bw) + 1; u64 name_start = BB_GetNumBytesWritten(&bw) + 1;
BB_WriteString(&bw, en->entry_name); BB_WriteString(&bw, en->entry_name);
u64 name_len = BB_GetNumBytesWritten(&bw) - name_start; u64 name_len = BB_GetNumBytesWritten(&bw) - name_start;
/* Write data */ // Write data
BB_WriteAlignBytes(&bw, 64); BB_WriteAlignBytes(&bw, 64);
/* FIXME: Why no +1 here? */ // FIXME: Why no +1 here?
u64 data_start = BB_GetNumBytesWritten(&bw); u64 data_start = BB_GetNumBytesWritten(&bw);
BB_WriteBytes(&bw, file_data); BB_WriteBytes(&bw, file_data);
u64 data_len = BB_GetNumBytesWritten(&bw) - data_start; u64 data_len = BB_GetNumBytesWritten(&bw) - data_start;
/* Write entry */ // Write entry
BB_WriteUBits(&entries_bw, name_start, 64); BB_WriteUBits(&entries_bw, name_start, 64);
BB_WriteUBits(&entries_bw, name_len, 64); BB_WriteUBits(&entries_bw, name_len, 64);
BB_WriteUBits(&entries_bw, data_start, 64); BB_WriteUBits(&entries_bw, data_start, 64);
@ -204,14 +205,14 @@ EmbedObj Embed(String store_name, String dir_path)
arc_contents.text = BB_GetWrittenRaw(&bw); arc_contents.text = BB_GetWrittenRaw(&bw);
} }
/* Write archive to file */ // Write archive to file
String arc_path = StringF(perm, "%F.arc", FmtString(store_name)); String arc_path = StringF(perm, "%F.arc", FmtString(store_name));
F_ClearWrite(arc_path, arc_contents); F_ClearWrite(arc_path, arc_contents);
/* Generate object file */ // Generate object file
if (IsPlatformWindows) if (IsPlatformWindows)
{ {
/* Generate RC file */ // Generate RC file
String rc_out_file = StringF(perm, "%F.rc", FmtString(store_name)); String rc_out_file = StringF(perm, "%F.rc", FmtString(store_name));
{ {
RandState rs = Zi; RandState rs = Zi;
@ -219,12 +220,12 @@ EmbedObj Embed(String store_name, String dir_path)
String arc_file_cp = F_GetFullCrossPlatform(perm, arc_path); String arc_file_cp = F_GetFullCrossPlatform(perm, arc_path);
String line = StringF(perm, "%F_%F RCDATA \"%F\"", FmtString(Lit(Stringize(W32_EmbeddedDataPrefix))), FmtHex(RandU64FromState(&rs)), FmtString(arc_file_cp)); String line = StringF(perm, "%F_%F RCDATA \"%F\"", FmtString(Lit(Stringize(W32_EmbeddedDataPrefix))), FmtHex(RandU64FromState(&rs)), FmtString(arc_file_cp));
PushStringToList(perm, &rc_out_lines, line); PushStringToList(perm, &rc_out_lines, line);
/* Write to file */ // Write to file
String rc_out = StringFromList(perm, rc_out_lines, Lit("\n")); String rc_out = StringFromList(perm, rc_out_lines, Lit("\n"));
F_ClearWrite(rc_out_file, rc_out); F_ClearWrite(rc_out_file, rc_out);
} }
/* Compile RC file */ // Compile RC file
result.obj_file = StringF(perm, "%F.res", FmtString(store_name)); result.obj_file = StringF(perm, "%F.res", FmtString(store_name));
{ {
result.obj_file, FmtString(F_GetFull(perm, rc_out_file)); result.obj_file, FmtString(F_GetFull(perm, rc_out_file));
@ -239,7 +240,7 @@ EmbedObj Embed(String store_name, String dir_path)
} }
else else
{ {
/* TODO: Generate object files using .incbin on non-windows platforms */ // TODO: Generate object files using .incbin on non-windows platforms
Panic(Lit("Resource embedding not implemented for this platform")); Panic(Lit("Resource embedding not implemented for this platform"));
} }
@ -256,10 +257,10 @@ void BuildEntryPoint(WaveLaneCtx *lane)
////////////////////////////// //////////////////////////////
//- Dirty check //- Dirty check
/* Return rebuild code if metaprogram is dirty */ // Return rebuild code if metaprogram is dirty
if (lane->idx == 0) if (lane->idx == 0)
{ {
/* Read old metahash */ // Read old metahash
u64 old_metahash = 0; u64 old_metahash = 0;
if (F_IsFile(Lit("metahash.dat"))) if (F_IsFile(Lit("metahash.dat")))
{ {
@ -271,7 +272,7 @@ void BuildEntryPoint(WaveLaneCtx *lane)
OS_Rm(Lit("metahash.dat")); OS_Rm(Lit("metahash.dat"));
} }
/* Compute new metahash */ // Compute new metahash
u64 new_metahash = 0; u64 new_metahash = 0;
{ {
StringList check_files = Zi; StringList check_files = Zi;
@ -285,7 +286,7 @@ void BuildEntryPoint(WaveLaneCtx *lane)
} }
} }
/* Exit if metaprogram needs recompilation */ // Exit if metaprogram needs recompilation
if (old_metahash == 0 || old_metahash == new_metahash) if (old_metahash == 0 || old_metahash == new_metahash)
{ {
F_ClearWrite(Lit("metahash.dat"), StringFromStruct(&new_metahash)); F_ClearWrite(Lit("metahash.dat"), StringFromStruct(&new_metahash));
@ -356,37 +357,37 @@ void BuildEntryPoint(WaveLaneCtx *lane)
PushStringToList(perm, &cp.flags_msvc, Lit("-INCREMENTAL:NO")); PushStringToList(perm, &cp.flags_msvc, Lit("-INCREMENTAL:NO"));
PushStringToList(perm, &cp.flags_msvc, Lit("-nologo")); PushStringToList(perm, &cp.flags_msvc, Lit("-nologo"));
/* Optimization */ // Optimization
PushStringToList(perm, &cp.compiler_only_flags_msvc, Lit("-Od")); PushStringToList(perm, &cp.compiler_only_flags_msvc, Lit("-Od"));
/* Debug info */ // Debug info
PushStringToList(perm, &cp.flags_msvc, Lit("-DEBUG:FULL")); PushStringToList(perm, &cp.flags_msvc, Lit("-DEBUG:FULL"));
PushStringToList(perm, &cp.compiler_only_flags_msvc, Lit("-Z7")); PushStringToList(perm, &cp.compiler_only_flags_msvc, Lit("-Z7"));
/* Enable warnings */ // Enable warnings
PushStringToList(perm, &cp.warnings_msvc, Lit("-W4")); PushStringToList(perm, &cp.warnings_msvc, Lit("-W4"));
PushStringToList(perm, &cp.warnings_msvc, Lit("-WX")); PushStringToList(perm, &cp.warnings_msvc, Lit("-WX"));
// PushStringToList(perm, &cp.warnings_msvc, Lit("-we4013")); /* function undefined; assuming extern returning int */ // PushStringToList(perm, &cp.warnings_msvc, Lit("-we4013")); // function undefined; assuming extern returning int
PushStringToList(perm, &cp.warnings_msvc, Lit("-we4668")); /* 'X' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */ PushStringToList(perm, &cp.warnings_msvc, Lit("-we4668")); // 'X' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif'
/* Disable warnings */ // Disable warnings
PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4244")); /* 'function': conversion from 'int' to 'f32', possible loss of data */ PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4244")); // 'function': conversion from 'int' to 'f32', possible loss of data
PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4201")); /* nonstandard extension used: nameless struct/union */ PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4201")); // nonstandard extension used: nameless struct/union
PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4324")); /* structure was padded due to alignment specifier */ PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4324")); // structure was padded due to alignment specifier
PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4100")); /* unreferenced parameter */ PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4100")); // unreferenced parameter
PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4101")); /* unreferenced local variable */ PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4101")); // unreferenced local variable
PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4189")); /* local variable is initialized but not referenced */ PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4189")); // local variable is initialized but not referenced
PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4200")); /* nonstandard extension used: zero-sized array in struct/union */ PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4200")); // nonstandard extension used: zero-sized array in struct/union
PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4702")); /* unreachable code */ PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4702")); // unreachable code
PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4305")); /* 'initializing': truncation from 'double' to 'f32' */ PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4305")); // 'initializing': truncation from 'double' to 'f32'
// PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4127")); /* conditional expression is constant */ // PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4127")); // conditional expression is constant
// PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4820")); /* bytes padding added after data member */ // PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4820")); // bytes padding added after data member
// PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4464")); /* relative include path contains '..' */ // PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4464")); // relative include path contains '..'
// PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4061")); /* enumerator is not explicitly handled by a case label */ // PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4061")); // enumerator is not explicitly handled by a case label
// PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4242")); /* conversion from X to Y, possible loss of data */ // PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4242")); // conversion from X to Y, possible loss of data
// PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4388")); /* signed/unsigned mismatch */ // PushStringToList(perm, &cp.warnings_msvc, Lit("-wd4388")); // signed/unsigned mismatch
// PushStringToList(perm, &cp.warnings_msvc, Lit("-wd5045")); /* Compiler will insert Spectre mitigation for memory load if /Qspectre switch specified */ // PushStringToList(perm, &cp.warnings_msvc, Lit("-wd5045")); // Compiler will insert Spectre mitigation for memory load if /Qspectre switch specified
} }
//- Clang //- Clang
@ -398,7 +399,7 @@ void BuildEntryPoint(WaveLaneCtx *lane)
PushStringToList(perm, &cp.flags_clang, Lit("-O0")); PushStringToList(perm, &cp.flags_clang, Lit("-O0"));
PushStringToList(perm, &cp.flags_clang, Lit("-msse4.2")); PushStringToList(perm, &cp.flags_clang, Lit("-msse4.2"));
/* Enable warnings */ // Enable warnings
PushStringToList(perm, &cp.warnings_clang, Lit("-Wall")); PushStringToList(perm, &cp.warnings_clang, Lit("-Wall"));
PushStringToList(perm, &cp.warnings_clang, Lit("-Werror")); PushStringToList(perm, &cp.warnings_clang, Lit("-Werror"));
PushStringToList(perm, &cp.warnings_clang, Lit("-Wframe-larger-than=65536")); PushStringToList(perm, &cp.warnings_clang, Lit("-Wframe-larger-than=65536"));
@ -410,7 +411,7 @@ void BuildEntryPoint(WaveLaneCtx *lane)
PushStringToList(perm, &cp.warnings_clang, Lit("-Wimplicit-fallthrough")); PushStringToList(perm, &cp.warnings_clang, Lit("-Wimplicit-fallthrough"));
PushStringToList(perm, &cp.warnings_clang, Lit("-Wswitch")); PushStringToList(perm, &cp.warnings_clang, Lit("-Wswitch"));
/* Disable warnings */ // Disable warnings
PushStringToList(perm, &cp.warnings_clang, Lit("-Wno-initializer-overrides")); PushStringToList(perm, &cp.warnings_clang, Lit("-Wno-initializer-overrides"));
PushStringToList(perm, &cp.warnings_clang, Lit("-Wno-microsoft-enum-forward-reference")); PushStringToList(perm, &cp.warnings_clang, Lit("-Wno-microsoft-enum-forward-reference"));
PushStringToList(perm, &cp.warnings_clang, Lit("-Wno-unused-variable")); PushStringToList(perm, &cp.warnings_clang, Lit("-Wno-unused-variable"));
@ -429,23 +430,21 @@ void BuildEntryPoint(WaveLaneCtx *lane)
////////////////////////////// //////////////////////////////
//- Phase 1/3: Prep //- Phase 1/3: Prep
/* // Phase 1/3: Prep (narrow)
* Phase 1/3: Prep (narrow) // - Parse layers
* - Parse layers // - Generate final C file
* - Generate final C file // - Generate final HLSL file
* - Generate final HLSL file // - Generate resource dirs info
* - Generate resource dirs info //
* // Phase 2/3: Compile (wide)
* Phase 2/3: Compile (wide) // - Compile C
* - Compile C // - Compile & embed shaders
* - Compile & embed shaders // - Embed resource dirs
* - Embed resource dirs //
* // Phase 3/3: Link (narrow)
* Phase 3/3: Link (narrow) // - Link
* - Link
*/
/* TODO: Dispatch OS commands asynchronously */ // TODO: Dispatch OS commands asynchronously
String shader_store_name = Lit("ShadersStore"); String shader_store_name = Lit("ShadersStore");
String c_out_file = F_GetFull(perm, StringF(perm, "%F_gen.c", FmtString(cmdline.leaf_layer_name))); String c_out_file = F_GetFull(perm, StringF(perm, "%F_gen.c", FmtString(cmdline.leaf_layer_name)));
@ -455,15 +454,15 @@ void BuildEntryPoint(WaveLaneCtx *lane)
{ {
//- Parse layers //- Parse layers
{ {
/* Lex */ // Lex
StringList src_dirs = Zi; StringList src_dirs = Zi;
PushStringToList(perm, &src_dirs, Lit("../src")); PushStringToList(perm, &src_dirs, Lit("../src"));
M_TokenFileList lexed = M_TokensFromSrcDirs(perm, src_dirs); M_TokenFileList lexed = M_TokensFromSrcDirs(perm, src_dirs);
/* Parse */ // Parse
M_LayerList parsed = M_LayersFromTokenFiles(perm, lexed);; M_LayerList parsed = M_LayersFromTokenFiles(perm, lexed);;
/* Flatten */ // Flatten
StringList starting_layer_names = Zi; StringList starting_layer_names = Zi;
PushStringToList(perm, &starting_layer_names, cmdline.leaf_layer_name); PushStringToList(perm, &starting_layer_names, cmdline.leaf_layer_name);
Build.layers_parse = M_FlattenEntries(perm, parsed, starting_layer_names); Build.layers_parse = M_FlattenEntries(perm, parsed, starting_layer_names);
@ -577,14 +576,14 @@ void BuildEntryPoint(WaveLaneCtx *lane)
{ {
StringList c_out_lines = Zi; StringList c_out_lines = Zi;
PushStringToList(perm, &c_out_lines, Lit("// Auto generated file")); PushStringToList(perm, &c_out_lines, Lit("// Auto generated file"));
/* Include base layer */ // Include base layer
{ {
String base_inc_path = F_GetFull(perm, Lit("../src/base/base_inc.h")); String base_inc_path = F_GetFull(perm, Lit("../src/base/base_inc.h"));
PushStringToList(perm, &c_out_lines, Lit("")); PushStringToList(perm, &c_out_lines, Lit(""));
PushStringToList(perm, &c_out_lines, Lit("//- Base layer includes")); PushStringToList(perm, &c_out_lines, Lit("//- Base layer includes"));
PushStringToList(perm, &c_out_lines, StringF(perm, "#include \"%F\"", FmtString(base_inc_path))); PushStringToList(perm, &c_out_lines, StringF(perm, "#include \"%F\"", FmtString(base_inc_path)));
} }
/* Define resource stores */ // Define resource stores
if (c_store_lines.count > 0) if (c_store_lines.count > 0)
{ {
PushStringToList(perm, &c_out_lines, Lit("")); PushStringToList(perm, &c_out_lines, Lit(""));
@ -594,7 +593,7 @@ void BuildEntryPoint(WaveLaneCtx *lane)
PushStringToList(perm, &c_out_lines, n->s); PushStringToList(perm, &c_out_lines, n->s);
} }
} }
/* Define shaders */ // Define shaders
if (c_shader_lines.count > 0) if (c_shader_lines.count > 0)
{ {
PushStringToList(perm, &c_out_lines, Lit("")); PushStringToList(perm, &c_out_lines, Lit(""));
@ -604,7 +603,7 @@ void BuildEntryPoint(WaveLaneCtx *lane)
PushStringToList(perm, &c_out_lines, n->s); PushStringToList(perm, &c_out_lines, n->s);
} }
} }
/* Include dependency layers */ // Include dependency layers
if (c_include_lines.count > 0) if (c_include_lines.count > 0)
{ {
PushStringToList(perm, &c_out_lines, Lit("")); PushStringToList(perm, &c_out_lines, Lit(""));
@ -614,7 +613,7 @@ void BuildEntryPoint(WaveLaneCtx *lane)
PushStringToList(perm, &c_out_lines, n->s); PushStringToList(perm, &c_out_lines, n->s);
} }
} }
/* Define BootstrapLayers */ // Define BootstrapLayers
{ {
PushStringToList(perm, &c_out_lines, Lit("")); PushStringToList(perm, &c_out_lines, Lit(""));
PushStringToList(perm, &c_out_lines, Lit("//- Bootstrap")); PushStringToList(perm, &c_out_lines, Lit("//- Bootstrap"));
@ -626,7 +625,7 @@ void BuildEntryPoint(WaveLaneCtx *lane)
} }
PushStringToList(perm, &c_out_lines, Lit("}")); PushStringToList(perm, &c_out_lines, Lit("}"));
} }
/* Write to file */ // Write to file
PushStringToList(perm, &c_out_lines, Lit("")); PushStringToList(perm, &c_out_lines, Lit(""));
String c_out = StringFromList(perm, c_out_lines, Lit("\n")); String c_out = StringFromList(perm, c_out_lines, Lit("\n"));
F_ClearWrite(c_out_file, c_out); F_ClearWrite(c_out_file, c_out);
@ -637,30 +636,30 @@ void BuildEntryPoint(WaveLaneCtx *lane)
//- Generate HLSL file //- Generate HLSL file
{ {
/* Clear shader store */ // Clear shader store
/* TODO: Move to separate artifacts dir that gets cleared, including archive files */ // TODO: Move to separate artifacts dir that gets cleared, including archive files
OS_Mkdir(shader_store_name); OS_Mkdir(shader_store_name);
{ {
/* Remove all old shaders */ // Remove all old shaders
StringList files = Zi; StringList files = Zi;
F_FilesFromDir(perm, &files, shader_store_name, F_IterFlag_None); F_FilesFromDir(perm, &files, shader_store_name, F_IterFlag_None);
for (StringListNode *n = files.first; n; n = n->next) for (StringListNode *n = files.first; n; n = n->next)
{ {
String file = n->s; String file = n->s;
/* Safety check to prevent non-shader files from being removed */ // Safety check to prevent non-shader files from being removed
if (StringEndsWith(file, Lit("VS")) || StringEndsWith(file, Lit("CS")) || StringEndsWith(file, Lit("PS"))) if (StringEndsWith(file, Lit("VS")) || StringEndsWith(file, Lit("CS")) || StringEndsWith(file, Lit("PS")))
{ {
OS_Rm(n->s); OS_Rm(n->s);
} }
else else
{ {
/* Unexpected file in shader store */ // Unexpected file in shader store
Assert(0); Assert(0);
} }
} }
} }
/* Generate GPU file & shader entries */ // Generate GPU file & shader entries
{ {
StringList gpu_include_lines = Zi; StringList gpu_include_lines = Zi;
{ {
@ -726,14 +725,14 @@ void BuildEntryPoint(WaveLaneCtx *lane)
{ {
StringList gpu_out_lines = Zi; StringList gpu_out_lines = Zi;
PushStringToList(perm, &gpu_out_lines, Lit("// Auto generated file")); PushStringToList(perm, &gpu_out_lines, Lit("// Auto generated file"));
/* Include base layer */ // Include base layer
{ {
String base_inc_path = F_GetFull(perm, Lit("../src/base/base_inc.h")); String base_inc_path = F_GetFull(perm, Lit("../src/base/base_inc.h"));
PushStringToList(perm, &gpu_out_lines, Lit("")); PushStringToList(perm, &gpu_out_lines, Lit(""));
PushStringToList(perm, &gpu_out_lines, Lit("//- Base layer includes")); PushStringToList(perm, &gpu_out_lines, Lit("//- Base layer includes"));
PushStringToList(perm, &gpu_out_lines, StringF(perm, "#include \"%F\"", FmtString(base_inc_path))); PushStringToList(perm, &gpu_out_lines, StringF(perm, "#include \"%F\"", FmtString(base_inc_path)));
} }
/* Include dependency layers */ // Include dependency layers
if (gpu_out_lines.count > 0) if (gpu_out_lines.count > 0)
{ {
PushStringToList(perm, &gpu_out_lines, Lit("")); PushStringToList(perm, &gpu_out_lines, Lit(""));
@ -743,7 +742,7 @@ void BuildEntryPoint(WaveLaneCtx *lane)
PushStringToList(perm, &gpu_out_lines, n->s); PushStringToList(perm, &gpu_out_lines, n->s);
} }
} }
/* Write to file */ // Write to file
PushStringToList(perm, &gpu_out_lines, Lit("")); PushStringToList(perm, &gpu_out_lines, Lit(""));
String c_out = StringFromList(perm, gpu_out_lines, Lit("\n")); String c_out = StringFromList(perm, gpu_out_lines, Lit("\n"));
F_ClearWrite(gpu_out_file, c_out); F_ClearWrite(gpu_out_file, c_out);
@ -755,7 +754,7 @@ void BuildEntryPoint(WaveLaneCtx *lane)
//- Generate archive info //- Generate archive info
{ {
/* Push embedded archive dirs */ // Push embedded archive dirs
for (M_Entry *entry = Build.layers_parse.first; entry->valid; entry = entry->next) for (M_Entry *entry = Build.layers_parse.first; entry->valid; entry = entry->next)
{ {
M_EntryKind kind = entry->kind; M_EntryKind kind = entry->kind;
@ -800,11 +799,11 @@ void BuildEntryPoint(WaveLaneCtx *lane)
//- Prep obj arrays //- Prep obj arrays
{ {
/* Gpu objs */ // Gpu objs
Build.gpu_objs.count = Build.gpu_parse.shader_entries_count; Build.gpu_objs.count = Build.gpu_parse.shader_entries_count;
Build.gpu_objs.array = PushStructs(perm, GpuObj, Build.gpu_objs.count); Build.gpu_objs.array = PushStructs(perm, GpuObj, Build.gpu_objs.count);
/* Embed objs */ // Embed objs
Build.embed_objs.count += Build.res_dir_parse.res_dirs_count; Build.embed_objs.count += Build.res_dir_parse.res_dirs_count;
if (Build.gpu_parse.shader_entries_count > 0) if (Build.gpu_parse.shader_entries_count > 0)
{ {
@ -843,7 +842,7 @@ void BuildEntryPoint(WaveLaneCtx *lane)
Build.c_obj.output = cmd_output; Build.c_obj.output = cmd_output;
Build.c_obj.return_code = cmd_result.code; Build.c_obj.return_code = cmd_result.code;
/* Ignore MSVC file-name echo */ // Ignore MSVC file-name echo
if (MatchString(TrimWhitespace(Build.c_obj.output), F_GetFileName(c_out_file))) if (MatchString(TrimWhitespace(Build.c_obj.output), F_GetFileName(c_out_file)))
{ {
Build.c_obj.output = Zstr; Build.c_obj.output = Zstr;
@ -884,7 +883,7 @@ void BuildEntryPoint(WaveLaneCtx *lane)
SetBuildStatus(gpu_obj->return_code); SetBuildStatus(gpu_obj->return_code);
/* Final shader compilation lane embeds shader archive */ // Final shader compilation lane embeds shader archive
u32 finished_count = Atomic32FetchAdd(&Build.gpu_objs.finished_count, 1) + 1; u32 finished_count = Atomic32FetchAdd(&Build.gpu_objs.finished_count, 1) + 1;
if (finished_count == Build.gpu_objs.count && GetBuildStatus() == 0) if (finished_count == Build.gpu_objs.count && GetBuildStatus() == 0)
{ {
@ -925,7 +924,7 @@ void BuildEntryPoint(WaveLaneCtx *lane)
{ {
String exe_file = StringF(perm, "%F.exe", FmtString(cmdline.leaf_layer_name)); String exe_file = StringF(perm, "%F.exe", FmtString(cmdline.leaf_layer_name));
{ {
/* Wait for exe to become writable (wait for program to close) */ // Wait for exe to become writable (wait for program to close)
f32 timeout = 1.0; f32 timeout = 1.0;
OS_File file = OS_OpenFile(exe_file, OS_FileFlag_Write, NsFromSeconds(timeout)); OS_File file = OS_OpenFile(exe_file, OS_FileFlag_Write, NsFromSeconds(timeout));
OS_CloseFile(file); OS_CloseFile(file);

View File

@ -15,7 +15,7 @@ Readonly M_Entry M_NilEntry = {
.arg_tokens[0] = &M_NilToken, .arg_tokens[0] = &M_NilToken,
.arg_tokens[1] = &M_NilToken, .arg_tokens[1] = &M_NilToken,
}; };
StaticAssert(countof(M_NilEntry.arg_tokens) == 2); /* NilEntry must define point args to nil tokens */ StaticAssert(countof(M_NilEntry.arg_tokens) == 2); // NilEntry must define point args to nil tokens
Readonly M_Layer M_NilLayer = { Readonly M_Layer M_NilLayer = {
.next = &M_NilLayer, .next = &M_NilLayer,
@ -84,7 +84,7 @@ M_TokenFileList M_TokensFromSrcDirs(Arena *arena, StringList src_dirs)
result.first = &M_NilTokenFile; result.first = &M_NilTokenFile;
result.last = &M_NilTokenFile; result.last = &M_NilTokenFile;
/* Build token file list from src dirs */ // Build token file list from src dirs
Dict *dedup_dict = InitDict(scratch.arena, 1021); Dict *dedup_dict = InitDict(scratch.arena, 1021);
for (StringListNode *dir_name_node = src_dirs.first; dir_name_node; dir_name_node = dir_name_node->next) for (StringListNode *dir_name_node = src_dirs.first; dir_name_node; dir_name_node = dir_name_node->next)
{ {
@ -133,7 +133,7 @@ M_TokenFileList M_TokensFromSrcDirs(Arena *arena, StringList src_dirs)
b32 is_eol = c == '\r' || c == '\n' || c == 0 || (p + 1) >= l; b32 is_eol = c == '\r' || c == '\n' || c == 0 || (p + 1) >= l;
b32 is_whitespace = is_eol || c == ' '; b32 is_whitespace = is_eol || c == ' ';
if (is_whitespace) if (is_whitespace)
{ /* Whitespace */ { // Whitespace
if (cur_ident.len > 0) if (cur_ident.len > 0)
{ {
M_PushToken(arena, tf, cur_ident, M_TokenKind_Ident); M_PushToken(arena, tf, cur_ident, M_TokenKind_Ident);
@ -146,12 +146,12 @@ M_TokenFileList M_TokensFromSrcDirs(Arena *arena, StringList src_dirs)
p += 1; p += 1;
} }
else if (c == '/' && (p + 1) < l && t[p + 1] == '/') else if (c == '/' && (p + 1) < l && t[p + 1] == '/')
{ /* Start single line comment */ { // Start single line comment
mode = TokenizerMode_SingleLineComment; mode = TokenizerMode_SingleLineComment;
p += 2; p += 2;
} }
else if (c == '/' && (p + 1) < l && t[p + 1] == '*') else if (c == '/' && (p + 1) < l && t[p + 1] == '*')
{ /* Start multi line comment */ { // Start multi line comment
mode = TokenizerMode_MultiLineComment; mode = TokenizerMode_MultiLineComment;
p += 2; p += 2;
} }
@ -169,7 +169,7 @@ M_TokenFileList M_TokensFromSrcDirs(Arena *arena, StringList src_dirs)
case TokenizerMode_SingleLineComment: case TokenizerMode_SingleLineComment:
{ {
if (t[p] == '\n') if (t[p] == '\n')
{ /* End single line comment */ { // End single line comment
mode = TokenizerMode_None; mode = TokenizerMode_None;
p += 1; p += 1;
} }
@ -182,7 +182,7 @@ M_TokenFileList M_TokensFromSrcDirs(Arena *arena, StringList src_dirs)
case TokenizerMode_MultiLineComment: case TokenizerMode_MultiLineComment:
{ {
if (t[p] == '*' && (p + 1) < l && t[p + 1] == '/') if (t[p] == '*' && (p + 1) < l && t[p + 1] == '/')
{ /* End multi line comment */ { // End multi line comment
mode = TokenizerMode_None; mode = TokenizerMode_None;
p += 2; p += 2;
} }
@ -237,7 +237,7 @@ M_LayerList M_LayersFromTokenFiles(Arena *arena, M_TokenFileList lexed)
result.first = &M_NilLayer; result.first = &M_NilLayer;
result.last = &M_NilLayer; result.last = &M_NilLayer;
/* Copy errors */ // Copy errors
b32 lexer_errors_present = 0; b32 lexer_errors_present = 0;
for (M_TokenFile *lf = lexed.first; lf->valid; lf = lf->next) for (M_TokenFile *lf = lexed.first; lf->valid; lf = lf->next)
{ {
@ -303,10 +303,10 @@ M_LayerList M_LayersFromTokenFiles(Arena *arena, M_TokenFileList lexed)
} }
else else
{ {
/* Parse entry */ // Parse entry
entry_token = token; entry_token = token;
token = token->next; token = token->next;
/* Parse args */ // Parse args
while (token->kind != M_TokenKind_Eol) while (token->kind != M_TokenKind_Eol)
{ {
if (args_count < countof(arg_tokens)) if (args_count < countof(arg_tokens))
@ -332,7 +332,7 @@ M_Layer M_FlattenEntries(Arena *arena, M_LayerList unflattened, StringList start
TempArena scratch = BeginScratch(arena); TempArena scratch = BeginScratch(arena);
M_Layer result = M_NilLayer; M_Layer result = M_NilLayer;
/* Copy errors */ // Copy errors
b32 unflattened_errors_present = 0; b32 unflattened_errors_present = 0;
for (M_Layer *layer = unflattened.first; layer->valid; layer = layer->next) for (M_Layer *layer = unflattened.first; layer->valid; layer = layer->next)
{ {
@ -360,7 +360,7 @@ M_Layer M_FlattenEntries(Arena *arena, M_LayerList unflattened, StringList start
.layer = &M_NilLayer .layer = &M_NilLayer
}; };
/* Construct state lookups */ // Construct state lookups
Dict *layer_ptr_to_state = InitDict(scratch.arena, 1021); Dict *layer_ptr_to_state = InitDict(scratch.arena, 1021);
Dict *layer_name_to_state = InitDict(scratch.arena, 1021); Dict *layer_name_to_state = InitDict(scratch.arena, 1021);
for (M_Layer *layer = unflattened.first; layer->valid; layer = layer->next) for (M_Layer *layer = unflattened.first; layer->valid; layer = layer->next)
@ -414,7 +414,7 @@ M_Layer M_FlattenEntries(Arena *arena, M_LayerList unflattened, StringList start
Struct(StackNode) { StackNode *next; IterState *state; b32 exit; }; Struct(StackNode) { StackNode *next; IterState *state; b32 exit; };
StackNode *stack = 0; StackNode *stack = 0;
/* Init stack with starting layers */ // Init stack with starting layers
for (StringListNode *sln = starting_layer_names.first; sln; sln = sln->next) for (StringListNode *sln = starting_layer_names.first; sln; sln = sln->next)
{ {
String name = sln->s; String name = sln->s;
@ -434,7 +434,7 @@ M_Layer M_FlattenEntries(Arena *arena, M_LayerList unflattened, StringList start
} }
} }
/* Flatten via post-order DFS */ // Flatten via post-order DFS
while (stack) while (stack)
{ {
StackNode *stack_node = stack; StackNode *stack_node = stack;
@ -444,7 +444,7 @@ M_Layer M_FlattenEntries(Arena *arena, M_LayerList unflattened, StringList start
if (stack_node->exit) if (stack_node->exit)
{ {
/* Push items to sorted root */ // Push items to sorted root
state->is_entered = 0; state->is_entered = 0;
state->is_exited = 1; state->is_exited = 1;
for (M_Entry *entry = layer->first; entry->valid; entry = entry->next) for (M_Entry *entry = layer->first; entry->valid; entry = entry->next)
@ -456,15 +456,15 @@ M_Layer M_FlattenEntries(Arena *arena, M_LayerList unflattened, StringList start
{ {
if (state->is_entered) if (state->is_entered)
{ {
/* Cyclic dependency */ // Cyclic dependency
/* FIXME: Handle cyclic dependency error */ // FIXME: Handle cyclic dependency error
Assert(0); Assert(0);
} }
else if (!state->is_exited) else if (!state->is_exited)
{ {
state->is_entered = 1; state->is_entered = 1;
/* Push downstream impl entries to stack */ // Push downstream impl entries to stack
for (M_Entry *entry = layer->first; entry->valid; entry = entry->next) for (M_Entry *entry = layer->first; entry->valid; entry = entry->next)
{ {
if (entry->kind == M_EntryKind_DefaultDownstream) if (entry->kind == M_EntryKind_DefaultDownstream)
@ -474,7 +474,7 @@ M_Layer M_FlattenEntries(Arena *arena, M_LayerList unflattened, StringList start
if (platform_token->valid && downstream_layer_token->valid) if (platform_token->valid && downstream_layer_token->valid)
{ {
/* Determine platform match */ // Determine platform match
b32 should_include = 0; b32 should_include = 0;
{ {
String platform_name = platform_token->s; String platform_name = platform_token->s;
@ -493,7 +493,7 @@ M_Layer M_FlattenEntries(Arena *arena, M_LayerList unflattened, StringList start
} }
} }
/* Include layer downstream */ // Include layer downstream
if (should_include) if (should_include)
{ {
String downstream_layer_name = downstream_layer_token->s; String downstream_layer_name = downstream_layer_token->s;
@ -523,13 +523,13 @@ M_Layer M_FlattenEntries(Arena *arena, M_LayerList unflattened, StringList start
} }
} }
/* Push node exit to stack */ // Push node exit to stack
{ {
stack_node->exit = 1; stack_node->exit = 1;
SllStackPush(stack, stack_node); SllStackPush(stack, stack_node);
} }
/* Push upstream dep entries to stack */ // Push upstream dep entries to stack
for (M_Entry *entry = layer->first; entry->valid; entry = entry->next) for (M_Entry *entry = layer->first; entry->valid; entry = entry->next)
{ {
if (entry->kind == M_EntryKind_Dep) if (entry->kind == M_EntryKind_Dep)

View File

@ -30,7 +30,7 @@ Struct(M_File)
Enum(M_TokenKind) Enum(M_TokenKind)
{ {
M_TokenKind_Ident, M_TokenKind_Ident,
M_TokenKind_Eol, /* End of line */ M_TokenKind_Eol, // End of line
}; };
Struct(M_Token) Struct(M_Token)

View File

@ -212,7 +212,7 @@ OS_CommandResult OS_RunCommand(Arena *arena, String cmd)
sa.nLength = sizeof(sa); sa.nLength = sizeof(sa);
sa.bInheritHandle = 0; sa.bInheritHandle = 0;
/* Create pipe */ // Create pipe
HANDLE pipe_read = 0; HANDLE pipe_read = 0;
HANDLE pipe_write = 0; HANDLE pipe_write = 0;
if (ok) if (ok)
@ -226,7 +226,7 @@ OS_CommandResult OS_RunCommand(Arena *arena, String cmd)
} }
} }
/* Duplicate pipe for child process */ // Duplicate pipe for child process
HANDLE child_pipe_write = 0; HANDLE child_pipe_write = 0;
if (ok) if (ok)
{ {
@ -238,7 +238,7 @@ OS_CommandResult OS_RunCommand(Arena *arena, String cmd)
} }
} }
/* Initialize attrs list */ // Initialize attrs list
LPPROC_THREAD_ATTRIBUTE_LIST attrs = Zi; LPPROC_THREAD_ATTRIBUTE_LIST attrs = Zi;
if (ok) if (ok)
{ {
@ -256,7 +256,7 @@ OS_CommandResult OS_RunCommand(Arena *arena, String cmd)
} }
} }
/* Build the handle inheritance whitelist */ // Build the handle inheritance whitelist
if (ok) { if (ok) {
HANDLE inherit_list[] = { child_pipe_write }; HANDLE inherit_list[] = { child_pipe_write };
ok = UpdateProcThreadAttribute(attrs, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST, inherit_list, sizeof(inherit_list), 0, 0) != 0; ok = UpdateProcThreadAttribute(attrs, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST, inherit_list, sizeof(inherit_list), 0, 0) != 0;
@ -266,8 +266,8 @@ OS_CommandResult OS_RunCommand(Arena *arena, String cmd)
} }
} }
/* Create process */ // Create process
/* TODO: Allow caller to set child process's thread affinity by job pool */ // TODO: Allow caller to set child process's thread affinity by job pool
HANDLE process = 0; HANDLE process = 0;
HANDLE process_thread = 0; HANDLE process_thread = 0;
if (ok) if (ok)
@ -289,7 +289,7 @@ OS_CommandResult OS_RunCommand(Arena *arena, String cmd)
{ {
result.output = W32_StringFromError(arena, GetLastError()); result.output = W32_StringFromError(arena, GetLastError());
} }
/* Close write pipe handles */ // Close write pipe handles
{ {
CloseHandle(child_pipe_write); CloseHandle(child_pipe_write);
CloseHandle(pipe_write); CloseHandle(pipe_write);
@ -298,7 +298,7 @@ OS_CommandResult OS_RunCommand(Arena *arena, String cmd)
} }
} }
/* Read process output */ // Read process output
if (ok) if (ok)
{ {
result.output.text = ArenaNext(arena, u8); result.output.text = ArenaNext(arena, u8);
@ -333,7 +333,7 @@ OS_CommandResult OS_RunCommand(Arena *arena, String cmd)
} }
} }
/* Close handles */ // Close handles
if (attrs) DeleteProcThreadAttributeList(attrs); if (attrs) DeleteProcThreadAttributeList(attrs);
if (process_thread) CloseHandle(process_thread); if (process_thread) CloseHandle(process_thread);
if (process) CloseHandle(process); if (process) CloseHandle(process);

View File

@ -1,18 +1,17 @@
/* TODO: Cap max sounds playing. */ // TODO: Cap max sounds playing.
/* Terminology: // Terminology:
* //
* `Sample`: Once "PCM" data point representing the smallest unit of audio available for a single channel at a point in time. // `Sample`: Once "PCM" data point representing the smallest unit of audio available for a single channel at a point in time.
* Examples: // Examples:
* - Single 32 bit float output by mixer and consumed by playback API, that the API interprets as a sound sample for a single channel // - Single 32 bit float output by mixer and consumed by playback API, that the API interprets as a sound sample for a single channel
* - Single 16 bit integer output by audio file decoder, that may represent a mono sound sample // - Single 16 bit integer output by audio file decoder, that may represent a mono sound sample
* //
* `Frame`: Represents a single data point of audio for all audio channels at a point in time. // `Frame`: Represents a single data point of audio for all audio channels at a point in time.
* Examples: // Examples:
* - Single 16 bit integer output by audio file decoder representing one mono sound sample // - Single 16 bit integer output by audio file decoder representing one mono sound sample
* - 2 16 bit integer samples output by audio file decoder representing two sound samples, one sample for each audio channel // - 2 16 bit integer samples output by audio file decoder representing two sound samples, one sample for each audio channel
* - 2 32 bit float samples output by mixer and consumed by playback API, one sample for each audio channel // - 2 32 bit float samples output by mixer and consumed by playback API, one sample for each audio channel
*/
MIX_SharedState M_shared_state = ZI; MIX_SharedState M_shared_state = ZI;
@ -59,7 +58,7 @@ MIX_Track *MIX_AcquireTrackLocked(Lock *lock, SND_Sound *sound)
MIX_Track *track = 0; MIX_Track *track = 0;
if (g->track_first_free) if (g->track_first_free)
{ {
/* Take from free list */ // Take from free list
track = g->track_first_free; track = g->track_first_free;
MIX_Track *next_free = track->next; MIX_Track *next_free = track->next;
g->track_first_free = next_free; g->track_first_free = next_free;
@ -71,7 +70,7 @@ MIX_Track *MIX_AcquireTrackLocked(Lock *lock, SND_Sound *sound)
} }
else else
{ {
/* Acquire new */ // Acquire new
track = PushStruct(g->track_arena, MIX_Track); track = PushStruct(g->track_arena, MIX_Track);
track->gen = 1; track->gen = 1;
} }
@ -80,7 +79,7 @@ MIX_Track *MIX_AcquireTrackLocked(Lock *lock, SND_Sound *sound)
track->mix.source = sound; track->mix.source = sound;
track->mix.track_handle = MIX_HandleFromTrack(track); track->mix.track_handle = MIX_HandleFromTrack(track);
/* Append to playing list */ // Append to playing list
MIX_Track *prev = g->track_last_playing; MIX_Track *prev = g->track_last_playing;
if (prev) if (prev)
{ {
@ -102,7 +101,7 @@ void MIX_ReleaseTrackLocked(Lock *lock, MIX_Track *track)
MIX_SharedState *g = &M_shared_state; MIX_SharedState *g = &M_shared_state;
AssertLockedE(lock, &g->mutex); AssertLockedE(lock, &g->mutex);
/* Remove from playing list */ // Remove from playing list
MIX_Track *prev = track->prev; MIX_Track *prev = track->prev;
MIX_Track *next = track->next; MIX_Track *next = track->next;
if (prev) if (prev)
@ -111,7 +110,7 @@ void MIX_ReleaseTrackLocked(Lock *lock, MIX_Track *track)
} }
else else
{ {
/* Track was first in list */ // Track was first in list
g->track_first_playing = next; g->track_first_playing = next;
} }
if (next) if (next)
@ -120,13 +119,13 @@ void MIX_ReleaseTrackLocked(Lock *lock, MIX_Track *track)
} }
else else
{ {
/* Track was last in list */ // Track was last in list
g->track_last_playing = prev; g->track_last_playing = prev;
} }
--g->track_playing_count; --g->track_playing_count;
++track->gen; ++track->gen;
/* Add to free list */ // Add to free list
track->prev = 0; track->prev = 0;
track->next = g->track_first_free; track->next = g->track_first_free;
if (g->track_first_free) if (g->track_first_free)
@ -136,7 +135,7 @@ void MIX_ReleaseTrackLocked(Lock *lock, MIX_Track *track)
g->track_first_free = track; g->track_first_free = track;
} }
/* TODO: Rework interface to be command based instead of directly modifying tracks. */ // TODO: Rework interface to be command based instead of directly modifying tracks.
MIX_Handle MIX_PlaySound(SND_Sound *sound) MIX_Handle MIX_PlaySound(SND_Sound *sound)
{ {
@ -158,7 +157,7 @@ MIX_Handle MIX_PlaySoundEx(SND_Sound *sound, MIX_TrackDesc desc)
return MIX_HandleFromTrack(track); return MIX_HandleFromTrack(track);
} }
/* NOTE: This is quite inefficient. */ // NOTE: This is quite inefficient.
MIX_TrackDesc MIX_TrackDescFromHandle(MIX_Handle handle) MIX_TrackDesc MIX_TrackDescFromHandle(MIX_Handle handle)
{ {
MIX_SharedState *g = &M_shared_state; MIX_SharedState *g = &M_shared_state;
@ -167,10 +166,10 @@ MIX_TrackDesc MIX_TrackDescFromHandle(MIX_Handle handle)
MIX_Track *track = MIX_TrackFromHandle(handle); MIX_Track *track = MIX_TrackFromHandle(handle);
if (track) if (track)
{ {
/* TODO: Only lock mutex on track itself or something */ // TODO: Only lock mutex on track itself or something
Lock lock = LockE(&g->mutex); Lock lock = LockE(&g->mutex);
{ {
/* Confirm handle is still valid now that we're locked */ // Confirm handle is still valid now that we're locked
track = MIX_TrackFromHandle(handle); track = MIX_TrackFromHandle(handle);
if (track) if (track)
{ {
@ -183,17 +182,17 @@ MIX_TrackDesc MIX_TrackDescFromHandle(MIX_Handle handle)
return result; return result;
} }
/* NOTE: This is quite inefficient. */ // NOTE: This is quite inefficient.
void MIX_UpdateTrack(MIX_Handle handle, MIX_TrackDesc desc) void MIX_UpdateTrack(MIX_Handle handle, MIX_TrackDesc desc)
{ {
MIX_SharedState *g = &M_shared_state; MIX_SharedState *g = &M_shared_state;
MIX_Track *track = MIX_TrackFromHandle(handle); MIX_Track *track = MIX_TrackFromHandle(handle);
if (track) if (track)
{ {
/* TODO: Only lock mutex on track itself or something */ // TODO: Only lock mutex on track itself or something
Lock lock = LockE(&g->mutex); Lock lock = LockE(&g->mutex);
{ {
/* Confirm handle is still valid now that we're locked */ // Confirm handle is still valid now that we're locked
track = MIX_TrackFromHandle(handle); track = MIX_TrackFromHandle(handle);
if (track) if (track)
{ {
@ -234,7 +233,7 @@ i16 MIX_SampleSound(SND_Sound *sound, u64 sample_pos, b32 wrap)
} }
} }
/* To be called once per audio playback interval */ // To be called once per audio playback interval
MIX_PcmF32 MIX_MixAllTracks(Arena *arena, u64 frame_count) MIX_PcmF32 MIX_MixAllTracks(Arena *arena, u64 frame_count)
{ {
TempArena scratch = BeginScratch(arena); TempArena scratch = BeginScratch(arena);
@ -254,11 +253,11 @@ MIX_PcmF32 MIX_MixAllTracks(Arena *arena, u64 frame_count)
{ {
Lock lock = LockE(&g->mutex); Lock lock = LockE(&g->mutex);
/* Read listener info */ // Read listener info
listener_pos = g->listener_pos; listener_pos = g->listener_pos;
listener_dir = g->listener_dir; listener_dir = g->listener_dir;
/* Update & read mixes */ // Update & read mixes
mixes = PushStructsNoZero(scratch.arena, MIX_MixData *, g->track_playing_count); mixes = PushStructsNoZero(scratch.arena, MIX_MixData *, g->track_playing_count);
for (MIX_Track *track = g->track_first_playing; track; track = track->next) for (MIX_Track *track = g->track_first_playing; track; track = track->next)
{ {
@ -278,7 +277,7 @@ MIX_PcmF32 MIX_MixAllTracks(Arena *arena, u64 frame_count)
if (mix->source->samples_count <= 0) if (mix->source->samples_count <= 0)
{ {
/* Skip empty sounds */ // Skip empty sounds
continue; continue;
} }
@ -293,14 +292,14 @@ MIX_PcmF32 MIX_MixAllTracks(Arena *arena, u64 frame_count)
if (source_is_stereo) if (source_is_stereo)
{ {
source_samples_count = frame_count * 2; source_samples_count = frame_count * 2;
/* Round <samples_count * speed> to nearest frame boundary (nearest multiple of 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 = (u64)CeilF32ToI32((f32)source_samples_count * speed);
source_samples_count &= ~1; source_samples_count &= ~1;
} }
else else
{ {
source_samples_count = frame_count; source_samples_count = frame_count;
/* Round <samples_count * speed> to nearest sample */ // Round <samples_count * speed> to nearest sample
source_samples_count = (u64)RoundF32ToI32((f32)source_samples_count * speed); source_samples_count = (u64)RoundF32ToI32((f32)source_samples_count * speed);
} }
@ -329,30 +328,30 @@ MIX_PcmF32 MIX_MixAllTracks(Arena *arena, u64 frame_count)
}; };
//- Resample //- Resample
/* Transform 16 bit source -> 32 bit stereo at output duration */ // Transform 16 bit source -> 32 bit stereo at output duration
{ {
f32 *out_samples = mix_pcm.samples; f32 *out_samples = mix_pcm.samples;
u64 out_frames_count = mix_pcm.count / 2; u64 out_frames_count = mix_pcm.count / 2;
/* TODO: Fast path for 1:1 copy when speed = 1.0? */ // TODO: Fast path for 1:1 copy when speed = 1.0?
/* TODO: Optimize */ // TODO: Optimize
if (source_is_stereo) if (source_is_stereo)
{ {
/* 16 bit Stereo -> 32 bit Stereo */ // 16 bit Stereo -> 32 bit Stereo
for (u64 out_frame_pos = 0; out_frame_pos < out_frames_count; ++out_frame_pos) 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); 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_prev = FloorF32ToI32(in_frame_pos_exact);
u32 in_frame_pos_next = CeilF32ToI32(in_frame_pos_exact); u32 in_frame_pos_next = CeilF32ToI32(in_frame_pos_exact);
/* Sample source */ // Sample source
f32 sample1_prev = MIX_SampleSound(source, (in_frame_pos_prev * 2) + 0, desc.looping) * (1.f / 32768.f); 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 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_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); f32 sample2_next = MIX_SampleSound(source, (in_frame_pos_next * 2) + 1, desc.looping) * (1.f / 32768.f);
/* Lerp */ // Lerp
f32 t = in_frame_pos_exact - (f32)in_frame_pos_prev; f32 t = in_frame_pos_exact - (f32)in_frame_pos_prev;
f32 sample1 = LerpF32(sample1_prev, sample1_next, t); f32 sample1 = LerpF32(sample1_prev, sample1_next, t);
f32 sample2 = LerpF32(sample2_prev, sample2_next, t); f32 sample2 = LerpF32(sample2_prev, sample2_next, t);
@ -363,18 +362,18 @@ MIX_PcmF32 MIX_MixAllTracks(Arena *arena, u64 frame_count)
} }
else else
{ {
/* 16 bit Mono -> 32 bit Stereo */ // 16 bit Mono -> 32 bit Stereo
for (u64 out_frame_pos = 0; out_frame_pos < out_frames_count; ++out_frame_pos) 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); 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_prev = FloorF32ToI32(in_frame_pos_exact);
u32 in_frame_pos_next = CeilF32ToI32(in_frame_pos_exact); u32 in_frame_pos_next = CeilF32ToI32(in_frame_pos_exact);
/* Sample source */ // Sample source
f32 sample_prev = MIX_SampleSound(source, in_frame_pos_prev, desc.looping) * (1.f / 32768.f); 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); f32 sample_next = MIX_SampleSound(source, in_frame_pos_next, desc.looping) * (1.f / 32768.f);
/* Lerp */ // Lerp
f32 t = (f32)in_frame_pos_exact - in_frame_pos_prev; f32 t = (f32)in_frame_pos_exact - in_frame_pos_prev;
f32 sample = LerpF32(sample_prev, sample_next, t); f32 sample = LerpF32(sample_prev, sample_next, t);
@ -387,14 +386,14 @@ MIX_PcmF32 MIX_MixAllTracks(Arena *arena, u64 frame_count)
//- Spatialize //- Spatialize
if (desc.flags & MIX_TrackFlag_Spatialize) if (desc.flags & MIX_TrackFlag_Spatialize)
{ {
/* Algorithm constants */ // Algorithm constants
const f32 rolloff_height = 1.2f; const f32 rolloff_height = 1.2f;
const f32 rolloff_scale = 6.0f; const f32 rolloff_scale = 6.0f;
const f32 pan_scale = 0.75; const f32 pan_scale = 0.75;
Vec2 pos = desc.pos; Vec2 pos = desc.pos;
/* If sound pos = listener pos, pretend sound is close in front of listener. */ // If sound pos = listener pos, pretend sound is close in front of listener.
if (MatchVec2(listener_pos, pos)) if (MatchVec2(listener_pos, pos))
{ {
pos = AddVec2(listener_pos, MulVec2(listener_dir, 0.001f)); pos = AddVec2(listener_pos, MulVec2(listener_dir, 0.001f));
@ -402,26 +401,25 @@ MIX_PcmF32 MIX_MixAllTracks(Arena *arena, u64 frame_count)
Vec2 sound_rel = SubVec2(pos, listener_pos); Vec2 sound_rel = SubVec2(pos, listener_pos);
Vec2 sound_rel_dir = NormVec2(sound_rel); Vec2 sound_rel_dir = NormVec2(sound_rel);
/* Compute volume */ // Compute volume
f32 volume_start = effect_data->spatial_volume; f32 volume_start = effect_data->spatial_volume;
f32 volume_end; f32 volume_end;
{ {
/* https://www.desmos.com/calculator/c2h941hobz // https://www.desmos.com/calculator/c2h941hobz
* h = `rolloff_height` // h = `rolloff_height`
* s = `rolloff_scale` // s = `rolloff_scale`
*/
f32 dist = Vec2Len(sound_rel); f32 dist = Vec2Len(sound_rel);
f32 v = (dist / rolloff_scale) + 1.0f; f32 v = (dist / rolloff_scale) + 1.0f;
volume_end = rolloff_height * (1.0f / (v * v)); volume_end = rolloff_height * (1.0f / (v * v));
} }
effect_data->spatial_volume = volume_end; effect_data->spatial_volume = volume_end;
/* Compute pan */ // Compute pan
f32 pan_start = effect_data->spatial_pan; f32 pan_start = effect_data->spatial_pan;
f32 pan_end = WedgeVec2(listener_dir, sound_rel_dir) * pan_scale; f32 pan_end = WedgeVec2(listener_dir, sound_rel_dir) * pan_scale;
effect_data->spatial_pan = pan_end; effect_data->spatial_pan = pan_end;
/* Spatialize samples */ // Spatialize samples
for (u64 frame_pos = 0; frame_pos < frame_count; ++frame_pos) for (u64 frame_pos = 0; frame_pos < frame_count; ++frame_pos)
{ {
f32 t = (f32)frame_pos / (f32)(frame_count - 1); f32 t = (f32)frame_pos / (f32)(frame_count - 1);
@ -456,7 +454,7 @@ MIX_PcmF32 MIX_MixAllTracks(Arena *arena, u64 frame_count)
{ {
if (mix->track_finished) if (mix->track_finished)
{ {
/* Release finished tracks */ // Release finished tracks
MIX_ReleaseTrackLocked(&lock, track); MIX_ReleaseTrackLocked(&lock, track);
} }
} }

View File

@ -16,11 +16,10 @@ Struct(MIX_Handle)
Struct(MIX_TrackDesc) Struct(MIX_TrackDesc)
{ {
MIX_TrackFlag flags; MIX_TrackFlag flags;
f32 volume; /* 0 -> 1.0+ */ f32 volume; // 0 -> 1.0+
f32 speed; /* 0 -> 1.0+ */ f32 speed; // 0 -> 1.0+
b32 looping; b32 looping;
/* MIX_TrackFlag_Spatialize */
Vec2 pos; Vec2 pos;
}; };
#define M_TRACKDESC(...) ((MIX_TrackDesc) { \ #define M_TRACKDESC(...) ((MIX_TrackDesc) { \
@ -35,7 +34,7 @@ Struct(MIX_TrackDesc)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Mix types //~ Mix types
/* Stereo mix of 32 bit float samples */ // Stereo mix of 32 bit float samples
Struct(MIX_PcmF32) Struct(MIX_PcmF32)
{ {
u64 count; u64 count;
@ -44,7 +43,7 @@ Struct(MIX_PcmF32)
Struct(MIX_EffectData) Struct(MIX_EffectData)
{ {
/* Spatialization */ // Spatialization
f32 spatial_volume; f32 spatial_volume;
f32 spatial_pan; f32 spatial_pan;
}; };
@ -63,11 +62,11 @@ Struct(MIX_MixData)
Struct(MIX_Track){ Struct(MIX_Track){
u64 gen; u64 gen;
/* Controlled via interface */ // Controlled via interface
SND_Sound *sound; SND_Sound *sound;
MIX_TrackDesc desc; MIX_TrackDesc desc;
/* Internal */ // Internal
MIX_MixData mix; MIX_MixData mix;
MIX_Track *next; MIX_Track *next;
@ -81,11 +80,11 @@ Struct(MIX_SharedState)
{ {
Mutex mutex; Mutex mutex;
/* Listener */ // Listener
Vec2 listener_pos; Vec2 listener_pos;
Vec2 listener_dir; Vec2 listener_dir;
/* Track list */ // Track list
Arena *track_arena; Arena *track_arena;
MIX_Track *track_first_playing; MIX_Track *track_first_playing;
MIX_Track *track_last_playing; MIX_Track *track_last_playing;

View File

@ -19,24 +19,26 @@ MP3_Result MP3_Decode(Arena *arena, String encoded, u32 sample_rate, MP3_DecodeF
channel_mask = SPEAKER_FRONT_CENTER; channel_mask = SPEAKER_FRONT_CENTER;
} }
//////////////////////////////
//- Startup //- Startup
MFStartup(MF_VERSION, MFSTARTUP_LITE); MFStartup(MF_VERSION, MFSTARTUP_LITE);
/* Create IStream from encoded string */ // Create IStream from encoded string
IStream *i_stream = SHCreateMemStream(encoded.text, encoded.len); IStream *i_stream = SHCreateMemStream(encoded.text, encoded.len);
/* Create IMFByteStream from IStream */ // Create IMFByteStream from IStream
IMFByteStream *byte_stream = 0; IMFByteStream *byte_stream = 0;
MFCreateMFByteStreamOnStream(i_stream, &byte_stream); MFCreateMFByteStreamOnStream(i_stream, &byte_stream);
/* Create reader from IMFByteStream */ // Create reader from IMFByteStream
IMFSourceReader *reader; IMFSourceReader *reader;
MFCreateSourceReaderFromByteStream(byte_stream, 0, &reader); MFCreateSourceReaderFromByteStream(byte_stream, 0, &reader);
//////////////////////////////
//- Get media type //- Get media type
/* Read only first audio stream */ // Read only first audio stream
IMFSourceReader_SetStreamSelection(reader, (DWORD)MF_SOURCE_READER_ALL_STREAMS, 0); IMFSourceReader_SetStreamSelection(reader, (DWORD)MF_SOURCE_READER_ALL_STREAMS, 0);
IMFSourceReader_SetStreamSelection(reader, (DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, 1); IMFSourceReader_SetStreamSelection(reader, (DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, 1);
@ -55,13 +57,14 @@ MP3_Result MP3_Decode(Arena *arena, String encoded, u32 sample_rate, MP3_DecodeF
.SubFormat = MEDIASUBTYPE_PCM .SubFormat = MEDIASUBTYPE_PCM
}; };
/* Media Foundation in Windows 8+ allows reader to convert output to different format than native */ // Media Foundation in Windows 8+ allows reader to convert output to different format than native
IMFMediaType *type; IMFMediaType *type;
MFCreateMediaType(&type); MFCreateMediaType(&type);
MFInitMediaTypeFromWaveFormatEx(type, &format.Format, sizeof(format)); MFInitMediaTypeFromWaveFormatEx(type, &format.Format, sizeof(format));
IMFSourceReader_SetCurrentMediaType(reader, (DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, type); IMFSourceReader_SetCurrentMediaType(reader, (DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, type);
IMFMediaType_Release(type); IMFMediaType_Release(type);
//////////////////////////////
//- Read //- Read
result.samples = ArenaNext(arena, i16); result.samples = ArenaNext(arena, i16);
@ -76,7 +79,7 @@ MP3_Result MP3_Decode(Arena *arena, String encoded, u32 sample_rate, MP3_DecodeF
break; break;
} }
/* Check if done */ // Check if done
if (sample_flags & MF_SOURCE_READERF_ENDOFSTREAM) if (sample_flags & MF_SOURCE_READERF_ENDOFSTREAM)
{ {
result.ok = 1; result.ok = 1;
@ -84,7 +87,7 @@ MP3_Result MP3_Decode(Arena *arena, String encoded, u32 sample_rate, MP3_DecodeF
} }
Assert(sample_flags == 0); Assert(sample_flags == 0);
/* Read samples */ // Read samples
IMFMediaBuffer *buffer; IMFMediaBuffer *buffer;
IMFSample_ConvertToContiguousBuffer(sample, &buffer); IMFSample_ConvertToContiguousBuffer(sample, &buffer);
@ -104,11 +107,12 @@ MP3_Result MP3_Decode(Arena *arena, String encoded, u32 sample_rate, MP3_DecodeF
result.samples_count = sample_bytes_read / bytes_per_sample; result.samples_count = sample_bytes_read / bytes_per_sample;
//////////////////////////////
//- Cleanup //- Cleanup
IMFSourceReader_Release(reader); IMFSourceReader_Release(reader);
IMFByteStream_Close(byte_stream); IMFByteStream_Close(byte_stream);
/* FIXME: Enable this */ // FIXME: Enable this
//IStream_Release(i_stream); //IStream_Release(i_stream);
MFShutdown(); MFShutdown();

View File

@ -1,16 +1,15 @@
/* TODO: // TODO:
* //
* Rate limiting. // Rate limiting.
* //
* Resequence buffer to order incoming sequenced packets. // Resequence buffer to order incoming sequenced packets.
* //
* Rolling window for message reassembly. // Rolling window for message reassembly.
* This would remove the need for random access message buffers. // This would remove the need for random access message buffers.
* //
* Connection timeouts. // Connection timeouts.
* //
* Challenges to verify receiving address. // Challenges to verify receiving address.
*/
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Host //~ Host
@ -76,7 +75,7 @@ N_Channel *N_ChannelFromAddress(N_Host *host, P_Address address)
return &N_nil_channel; return &N_nil_channel;
} }
/* Returns nil channel if id = N_AllChannelsId */ // Returns nil channel if id = N_AllChannelsId
N_Channel *N_ChannelFromId(N_Host *host, N_ChannelId channel_id) N_Channel *N_ChannelFromId(N_Host *host, N_ChannelId channel_id)
{ {
if (channel_id.gen > 0 && channel_id.idx < host->num_channels_reserved) if (channel_id.gen > 0 && channel_id.idx < host->num_channels_reserved)
@ -174,7 +173,7 @@ void N_ReleaseChannel(N_Channel *channel)
{ {
N_Host *host = channel->host; N_Host *host = channel->host;
/* Release from lookup table */ // Release from lookup table
{ {
N_ChannelLookupBin *bin = &host->channel_lookup_bins[channel->address_hash % host->num_channel_lookup_bins]; N_ChannelLookupBin *bin = &host->channel_lookup_bins[channel->address_hash % host->num_channel_lookup_bins];
N_Channel *prev = channel->prev_address_hash; N_Channel *prev = channel->prev_address_hash;
@ -197,7 +196,7 @@ void N_ReleaseChannel(N_Channel *channel)
} }
} }
/* Release packets */ // Release packets
{ {
if (channel->first_unreliable_packet) if (channel->first_unreliable_packet)
{ {
@ -211,7 +210,7 @@ void N_ReleaseChannel(N_Channel *channel)
} }
} }
/* Release msg assemblers */ // Release msg assemblers
for (N_MsgAssembler *ma = channel->least_recent_msg_assembler; ma; ma = ma->more_recent) for (N_MsgAssembler *ma = channel->least_recent_msg_assembler; ma; ma = ma->more_recent)
{ {
N_ReleaseMessageAssembler(ma); N_ReleaseMessageAssembler(ma);
@ -270,23 +269,23 @@ N_MsgAssembler *N_AcquireMsgAssembler(N_Channel *channel, u64 msg_id, u64 chunk_
u64 chunk_bitmap_size = (chunk_count + 7) >> 3; u64 chunk_bitmap_size = (chunk_count + 7) >> 3;
if ((chunk_bitmap_size % 16) != 0) if ((chunk_bitmap_size % 16) != 0)
{ {
/* Align chunk bitmap to 16 so msg data is aligned */ // Align chunk bitmap to 16 so msg data is aligned
chunk_bitmap_size += 16 - (chunk_bitmap_size % 16); chunk_bitmap_size += 16 - (chunk_bitmap_size % 16);
} }
u64 chunk_data_size = chunk_count * N_MaxPacketChunkLen; u64 chunk_data_size = chunk_count * N_MaxPacketChunkLen;
/* Acquire msg data using buddy allocator since the assembler has // Acquire msg data using buddy allocator since the assembler has
* arbitrary lifetime and data needs to stay contiguous for random // arbitrary lifetime and data needs to stay contiguous for random
* access as packets are received */ // access as packets are received
ma->buddy_block = AcquireBuddyBlock(host->buddy, chunk_bitmap_size + chunk_data_size); ma->buddy_block = AcquireBuddyBlock(host->buddy, chunk_bitmap_size + chunk_data_size);
ma->chunk_bitmap = ma->buddy_block->memory; ma->chunk_bitmap = ma->buddy_block->memory;
ZeroBytes(ma->chunk_bitmap, chunk_bitmap_size); ZeroBytes(ma->chunk_bitmap, chunk_bitmap_size);
ma->chunk_data = ma->chunk_bitmap + chunk_bitmap_size; ma->chunk_data = ma->chunk_bitmap + chunk_bitmap_size;
/* FIXME: Ensure chunk_count > 0 */ // FIXME: Ensure chunk_count > 0
ma->is_reliable = is_reliable; ma->is_reliable = is_reliable;
/* Add to channel list */ // Add to channel list
ma->touched_ns = now_ns; ma->touched_ns = now_ns;
if (channel->most_recent_msg_assembler) if (channel->most_recent_msg_assembler)
{ {
@ -299,7 +298,7 @@ N_MsgAssembler *N_AcquireMsgAssembler(N_Channel *channel, u64 msg_id, u64 chunk_
} }
channel->most_recent_msg_assembler = ma; channel->most_recent_msg_assembler = ma;
/* Add to lookup table */ // Add to lookup table
u64 hash = N_HashFromMsg(channel->id, msg_id); u64 hash = N_HashFromMsg(channel->id, msg_id);
ma->hash = hash; ma->hash = hash;
N_MsgAssemblerLookupBin *bin = &host->msg_assembler_lookup_bins[hash % host->num_msg_assembler_lookup_bins]; N_MsgAssemblerLookupBin *bin = &host->msg_assembler_lookup_bins[hash % host->num_msg_assembler_lookup_bins];
@ -323,7 +322,7 @@ void N_ReleaseMessageAssembler(N_MsgAssembler *ma)
N_Host *host = channel->host; N_Host *host = channel->host;
ReleaseBuddyBlock(ma->buddy_block); ReleaseBuddyBlock(ma->buddy_block);
/* Release from channel list */ // Release from channel list
{ {
N_MsgAssembler *prev = ma->less_recent; N_MsgAssembler *prev = ma->less_recent;
N_MsgAssembler *next = ma->more_recent; N_MsgAssembler *next = ma->more_recent;
@ -345,7 +344,7 @@ void N_ReleaseMessageAssembler(N_MsgAssembler *ma)
} }
} }
/* Release from lookup table */ // Release from lookup table
N_MsgAssemblerLookupBin *bin = &host->msg_assembler_lookup_bins[ma->hash % host->num_msg_assembler_lookup_bins]; N_MsgAssemblerLookupBin *bin = &host->msg_assembler_lookup_bins[ma->hash % host->num_msg_assembler_lookup_bins];
{ {
N_MsgAssembler *prev = ma->prev_hash; N_MsgAssembler *prev = ma->prev_hash;
@ -377,7 +376,7 @@ void N_TouchMessageAssembler(N_MsgAssembler *ma, i64 now_ns)
N_Channel *channel = ma->channel; N_Channel *channel = ma->channel;
if (ma != channel->most_recent_msg_assembler) if (ma != channel->most_recent_msg_assembler)
{ {
/* Remove from channel list */ // Remove from channel list
{ {
N_MsgAssembler *prev = ma->less_recent; N_MsgAssembler *prev = ma->less_recent;
N_MsgAssembler *next = ma->more_recent; N_MsgAssembler *next = ma->more_recent;
@ -399,7 +398,7 @@ void N_TouchMessageAssembler(N_MsgAssembler *ma, i64 now_ns)
} }
} }
/* Insert at end of channel list */ // Insert at end of channel list
{ {
if (channel->most_recent_msg_assembler) if (channel->most_recent_msg_assembler)
{ {
@ -536,15 +535,18 @@ i64 N_GetChannelLastRttNs(N_Host *host, N_ChannelId channel_id)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Update begin //~ Update begin
/* Read incoming packets, update channels, and return events */ // Read incoming packets, update channels, and return events
N_EventList N_BeginUpdate(Arena *arena, N_Host *host) N_EventList N_BeginUpdate(Arena *arena, N_Host *host)
{ {
TempArena scratch = BeginScratch(arena); TempArena scratch = BeginScratch(arena);
N_EventList events = ZI; N_EventList events = ZI;
i64 now_ns = TimeNs(); i64 now_ns = TimeNs();
//////////////////////////////
//- Read socket
{ {
//- Read socket
N_RcvPacket *first_packet = 0; N_RcvPacket *first_packet = 0;
N_RcvPacket *last_packet = 0; N_RcvPacket *last_packet = 0;
{ {
@ -572,7 +574,9 @@ N_EventList N_BeginUpdate(Arena *arena, N_Host *host)
} }
} }
//- Read incoming packets //////////////////////////////
//- Process incoming packets
{ {
for (N_RcvPacket *packet = first_packet; packet; packet = packet->next) for (N_RcvPacket *packet = first_packet; packet; packet = packet->next)
{ {
@ -580,10 +584,10 @@ N_EventList N_BeginUpdate(Arena *arena, N_Host *host)
P_Address address = packet->address; P_Address address = packet->address;
BB_Buff bb = BB_BuffFromString(packet->data); BB_Buff bb = BB_BuffFromString(packet->data);
BB_Reader br = BB_ReaderFromBuff(&bb); BB_Reader br = BB_ReaderFromBuff(&bb);
u32 magic = BB_ReadUBits(&br, 32); /* TODO: implicitly encode magic into crc32 */ u32 magic = BB_ReadUBits(&br, 32); // TODO: implicitly encode magic into crc32
if (magic == N_PacketMagic) if (magic == N_PacketMagic)
{ {
/* TODO: Combine kind byte with flags byte */ // TODO: Combine kind byte with flags byte
N_Channel *channel = N_ChannelFromAddress(host, address); N_Channel *channel = N_ChannelFromAddress(host, address);
N_PacketKind packet_kind = BB_ReadIBits(&br, 8); N_PacketKind packet_kind = BB_ReadIBits(&br, 8);
u8 packet_flags = BB_ReadUBits(&br, 8); u8 packet_flags = BB_ReadUBits(&br, 8);
@ -622,24 +626,29 @@ N_EventList N_BeginUpdate(Arena *arena, N_Host *host)
{ {
default: break; default: break;
//////////////////////////////
//- Read packet kind: TryConnect //- Read packet kind: TryConnect
case N_PacketKind_TryConnect: case N_PacketKind_TryConnect:
{ {
/* A foreign host is trying to connect to us */ // A foreign host is trying to connect to us
if (!channel->valid) if (!channel->valid)
{ {
LogInfoF("Host received conection attempt from %F", FmtString(P_StringFromAddress(scratch.arena, address))); LogInfoF("Host received conection attempt from %F", FmtString(P_StringFromAddress(scratch.arena, address)));
/* TODO: Verify that some per-host uuid isn't present in a rolling window to prevent reconnects right after a disconnect? */ // TODO: Verify that some per-host uuid isn't present in a rolling window to prevent reconnects right after a disconnect?
channel = N_AcquireChannel(host, address); channel = N_AcquireChannel(host, address);
} }
N_Cmd *cmd = N_PushCmd(host); N_Cmd *cmd = N_PushCmd(host);
cmd->kind = N_CmdKind_ConnectSuccess; cmd->kind = N_CmdKind_ConnectSuccess;
cmd->channel_id = channel->id; cmd->channel_id = channel->id;
} break; } break;
//////////////////////////////
//- Read packet kind: ConnectSuccess //- Read packet kind: ConnectSuccess
case N_PacketKind_ConnectSuccess: case N_PacketKind_ConnectSuccess:
{ {
/* We successfully connected to a foreign host and they are ready to receive messages */ // We successfully connected to a foreign host and they are ready to receive messages
if (channel->valid && !channel->connected) if (channel->valid && !channel->connected)
{ {
LogInfoF("Host received connection from %F", FmtString(P_StringFromAddress(scratch.arena, address))); LogInfoF("Host received connection from %F", FmtString(P_StringFromAddress(scratch.arena, address)));
@ -649,10 +658,13 @@ N_EventList N_BeginUpdate(Arena *arena, N_Host *host)
channel->connected = 1; channel->connected = 1;
} }
} break; } break;
//////////////////////////////
//- Read packet kind: Disconnect //- Read packet kind: Disconnect
case N_PacketKind_Disconnect: case N_PacketKind_Disconnect:
{ {
/* A foreign host disconnected from us */ // A foreign host disconnected from us
if (channel->valid) if (channel->valid)
{ {
LogInfoF("Host received disconnection from %F", FmtString(P_StringFromAddress(scratch.arena, address))); LogInfoF("Host received disconnection from %F", FmtString(P_StringFromAddress(scratch.arena, address)));
@ -663,7 +675,10 @@ N_EventList N_BeginUpdate(Arena *arena, N_Host *host)
} }
} break; } break;
//////////////////////////////
//- Read packet kind: Heartbeat //- Read packet kind: Heartbeat
case N_PacketKind_Heartbeat: case N_PacketKind_Heartbeat:
{ {
if (channel->valid) if (channel->valid)
@ -685,12 +700,15 @@ N_EventList N_BeginUpdate(Arena *arena, N_Host *host)
} }
} }
} break; } break;
//////////////////////////////
//- Read packet kind: MsgChunk //- Read packet kind: MsgChunk
case N_PacketKind_MsgChunk: case N_PacketKind_MsgChunk:
{ {
if (channel->valid && channel->connected) if (channel->valid && channel->connected)
{ {
/* Packet is chunk <chunk_id> out of <chunk_count> belonging to message <msg_id> */ // Packet is chunk <chunk_id> out of <chunk_count> belonging to message <msg_id>
u64 msg_id = BB_ReadUV(&br); u64 msg_id = BB_ReadUV(&br);
u64 chunk_id = BB_ReadUV(&br); u64 chunk_id = BB_ReadUV(&br);
u64 chunk_count = BB_ReadUV(&br); u64 chunk_count = BB_ReadUV(&br);
@ -721,8 +739,8 @@ N_EventList N_BeginUpdate(Arena *arena, N_Host *host)
N_TouchMessageAssembler(ma, now_ns); N_TouchMessageAssembler(ma, now_ns);
if (ma->num_chunks_received == chunk_count) if (ma->num_chunks_received == chunk_count)
{ {
/* All chunks filled, message has finished assembling */ // All chunks filled, message has finished assembling
/* TODO: Message ordering */ // TODO: Message ordering
N_Event *event = N_PushEvent(arena, &events); N_Event *event = N_PushEvent(arena, &events);
String data = ZI; String data = ZI;
data.len = ((chunk_count - 1) * N_MaxPacketChunkLen) + ma->last_chunk_len; data.len = ((chunk_count - 1) * N_MaxPacketChunkLen) + ma->last_chunk_len;
@ -733,21 +751,21 @@ N_EventList N_BeginUpdate(Arena *arena, N_Host *host)
event->channel_id = channel->id; event->channel_id = channel->id;
if (is_reliable) if (is_reliable)
{ {
/* Release assembler if reliable */ // Release assembler if reliable
N_ReleaseMessageAssembler(ma); N_ReleaseMessageAssembler(ma);
} }
} }
} }
else else
{ {
/* Overflow reading chunk */ // Overflow reading chunk
Assert(0); Assert(0);
} }
} }
} }
else else
{ {
/* Chunk id/count mismatch */ // Chunk id/count mismatch
Assert(0); Assert(0);
} }
} }
@ -760,22 +778,24 @@ N_EventList N_BeginUpdate(Arena *arena, N_Host *host)
} }
} }
//////////////////////////////
//- Update channels //- Update channels
{ {
for (u64 i = 0; i < host->num_channels_reserved; ++i) for (u64 i = 0; i < host->num_channels_reserved; ++i)
{ {
N_Channel *channel = &host->channels[i]; N_Channel *channel = &host->channels[i];
if (channel->valid) if (channel->valid)
{ {
/* Send / resend handshake if not connected */ // Send / resend handshake if not connected
if (!channel->connected) if (!channel->connected)
{ {
N_Cmd *cmd = N_PushCmd(host); N_Cmd *cmd = N_PushCmd(host);
cmd->kind = N_CmdKind_TryConnect; cmd->kind = N_CmdKind_TryConnect;
cmd->channel_id = channel->id; cmd->channel_id = channel->id;
} }
/* Send heartbeat */ // Send heartbeat
/* TODO: Send this less frequently (once per second or half of timeout or something) */ // TODO: Send this less frequently (once per second or half of timeout or something)
{ {
N_Cmd *cmd = N_PushCmd(host); N_Cmd *cmd = N_PushCmd(host);
cmd->kind = N_CmdKind_Heartbeat; cmd->kind = N_CmdKind_Heartbeat;
@ -783,7 +803,7 @@ N_EventList N_BeginUpdate(Arena *arena, N_Host *host)
cmd->heartbeat_ack_id = channel->last_heartbeat_received_id; cmd->heartbeat_ack_id = channel->last_heartbeat_received_id;
cmd->channel_id = channel->id; cmd->channel_id = channel->id;
} }
/* Release acked reliable packets */ // Release acked reliable packets
{ {
u64 acked_seq = channel->their_acked_seq; u64 acked_seq = channel->their_acked_seq;
N_SndPacket *packet = channel->first_reliable_packet; N_SndPacket *packet = channel->first_reliable_packet;
@ -809,9 +829,9 @@ N_EventList N_BeginUpdate(Arena *arena, N_Host *host)
channel->last_reliable_packet = 0; channel->last_reliable_packet = 0;
} }
} }
/* Release timed out unreliable msg buffers */ // Release timed out unreliable msg buffers
{ {
/* TODO: Configurable timeout */ // TODO: Configurable timeout
i64 unreliable_msg_timeout_ns = NsFromSeconds(0.1); i64 unreliable_msg_timeout_ns = NsFromSeconds(0.1);
N_MsgAssembler *ma = channel->least_recent_msg_assembler; N_MsgAssembler *ma = channel->least_recent_msg_assembler;
while (ma) while (ma)
@ -842,13 +862,15 @@ N_EventList N_BeginUpdate(Arena *arena, N_Host *host)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Update end //~ Update end
/* Process host cmds & send outgoing packets */ // Process host cmds & send outgoing packets
void N_EndUpdate(N_Host *host) void N_EndUpdate(N_Host *host)
{ {
TempArena scratch = BeginScratchNoConflict(); TempArena scratch = BeginScratchNoConflict();
/* Process cmds into sendable packets */ //////////////////////////////
/* TODO: Unreliable packets don't need to be allocated into unreliable packet queue, should just send them and forget */ //- Process cmds
// TODO: Unreliable packets don't need to be allocated into unreliable packet queue, should just send them and forget
{ {
for (N_Cmd *cmd = host->first_cmd; cmd; cmd = cmd->next) for (N_Cmd *cmd = host->first_cmd; cmd; cmd = cmd->next)
{ {
@ -862,53 +884,64 @@ void N_EndUpdate(N_Host *host)
{ {
default: break; default: break;
//////////////////////////////
//- Process command: TryConnect //- Process command: TryConnect
case N_CmdKind_TryConnect: case N_CmdKind_TryConnect:
{ {
u8 packet_flags = 0; u8 packet_flags = 0;
N_SndPacket *packet = N_PushSndPacket(channel, 0); N_SndPacket *packet = N_PushSndPacket(channel, 0);
BB_Buff bb = BB_BuffFromString(StringFromFixedArray(packet->data)); BB_Buff bb = BB_BuffFromString(StringFromFixedArray(packet->data));
BB_Writer bw = BB_WriterFromBuff(&bb); BB_Writer bw = BB_WriterFromBuff(&bb);
BB_WriteUBits(&bw, N_PacketMagic, 32); /* TODO: implicitly encode magic into crc32 */ BB_WriteUBits(&bw, N_PacketMagic, 32); // TODO: implicitly encode magic into crc32
BB_WriteIBits(&bw, N_PacketKind_TryConnect, 8); BB_WriteIBits(&bw, N_PacketKind_TryConnect, 8);
BB_WriteUBits(&bw, packet_flags, 8); BB_WriteUBits(&bw, packet_flags, 8);
BB_WriteUV(&bw, channel->our_acked_seq); BB_WriteUV(&bw, channel->our_acked_seq);
packet->data_len = BB_GetNumBytesWritten(&bw); packet->data_len = BB_GetNumBytesWritten(&bw);
} break; } break;
//////////////////////////////
//- Process command: ConnectSuccess //- Process command: ConnectSuccess
case N_CmdKind_ConnectSuccess: case N_CmdKind_ConnectSuccess:
{ {
u8 packet_flags = 0; u8 packet_flags = 0;
N_SndPacket *packet = N_PushSndPacket(channel, 0); N_SndPacket *packet = N_PushSndPacket(channel, 0);
BB_Buff bb = BB_BuffFromString(StringFromFixedArray(packet->data)); BB_Buff bb = BB_BuffFromString(StringFromFixedArray(packet->data));
BB_Writer bw = BB_WriterFromBuff(&bb); BB_Writer bw = BB_WriterFromBuff(&bb);
BB_WriteUBits(&bw, N_PacketMagic, 32); /* TODO: implicitly encode magic into crc32 */ BB_WriteUBits(&bw, N_PacketMagic, 32); // TODO: implicitly encode magic into crc32
BB_WriteIBits(&bw, N_PacketKind_ConnectSuccess, 8); BB_WriteIBits(&bw, N_PacketKind_ConnectSuccess, 8);
BB_WriteUBits(&bw, packet_flags, 8); BB_WriteUBits(&bw, packet_flags, 8);
BB_WriteUV(&bw, channel->our_acked_seq); BB_WriteUV(&bw, channel->our_acked_seq);
packet->data_len = BB_GetNumBytesWritten(&bw); packet->data_len = BB_GetNumBytesWritten(&bw);
} break; } break;
//////////////////////////////
//- Process command: Disconnect //- Process command: Disconnect
case N_CmdKind_Disconnect: case N_CmdKind_Disconnect:
{ {
u8 packet_flags = 0; u8 packet_flags = 0;
N_SndPacket *packet = N_PushSndPacket(channel, 0); N_SndPacket *packet = N_PushSndPacket(channel, 0);
BB_Buff bb = BB_BuffFromString(StringFromFixedArray(packet->data)); BB_Buff bb = BB_BuffFromString(StringFromFixedArray(packet->data));
BB_Writer bw = BB_WriterFromBuff(&bb); BB_Writer bw = BB_WriterFromBuff(&bb);
BB_WriteUBits(&bw, N_PacketMagic, 32); /* TODO: implicitly encode magic into crc32 */ BB_WriteUBits(&bw, N_PacketMagic, 32); // TODO: implicitly encode magic into crc32
BB_WriteIBits(&bw, N_PacketKind_Disconnect, 8); BB_WriteIBits(&bw, N_PacketKind_Disconnect, 8);
BB_WriteUBits(&bw, packet_flags, 8); BB_WriteUBits(&bw, packet_flags, 8);
BB_WriteUV(&bw, channel->our_acked_seq); BB_WriteUV(&bw, channel->our_acked_seq);
packet->data_len = BB_GetNumBytesWritten(&bw); packet->data_len = BB_GetNumBytesWritten(&bw);
} break; } break;
//////////////////////////////
//- Process command: Heartbeat //- Process command: Heartbeat
case N_CmdKind_Heartbeat: case N_CmdKind_Heartbeat:
{ {
u8 packet_flags = 0; u8 packet_flags = 0;
N_SndPacket *packet = N_PushSndPacket(channel, 0); N_SndPacket *packet = N_PushSndPacket(channel, 0);
BB_Buff bb = BB_BuffFromString(StringFromFixedArray(packet->data)); BB_Buff bb = BB_BuffFromString(StringFromFixedArray(packet->data));
BB_Writer bw = BB_WriterFromBuff(&bb); BB_Writer bw = BB_WriterFromBuff(&bb);
BB_WriteUBits(&bw, N_PacketMagic, 32); /* TODO: implicitly encode magic into crc32 */ BB_WriteUBits(&bw, N_PacketMagic, 32); // TODO: implicitly encode magic into crc32
BB_WriteIBits(&bw, N_PacketKind_Heartbeat, 8); BB_WriteIBits(&bw, N_PacketKind_Heartbeat, 8);
BB_WriteUBits(&bw, packet_flags, 8); BB_WriteUBits(&bw, packet_flags, 8);
BB_WriteUV(&bw, channel->our_acked_seq); BB_WriteUV(&bw, channel->our_acked_seq);
@ -916,7 +949,10 @@ void N_EndUpdate(N_Host *host)
BB_WriteUBits(&bw, cmd->heartbeat_ack_id, 16); BB_WriteUBits(&bw, cmd->heartbeat_ack_id, 16);
packet->data_len = BB_GetNumBytesWritten(&bw); packet->data_len = BB_GetNumBytesWritten(&bw);
} break; } break;
//////////////////////////////
//- Process command: Write //- Process command: Write
case N_CmdKind_Write: case N_CmdKind_Write:
{ {
b32 is_reliable = cmd->write_reliable; b32 is_reliable = cmd->write_reliable;
@ -946,7 +982,7 @@ void N_EndUpdate(N_Host *host)
N_SndPacket *packet = N_PushSndPacket(channel, is_reliable); N_SndPacket *packet = N_PushSndPacket(channel, is_reliable);
BB_Buff bb = BB_BuffFromString(StringFromFixedArray(packet->data)); BB_Buff bb = BB_BuffFromString(StringFromFixedArray(packet->data));
BB_Writer bw = BB_WriterFromBuff(&bb); BB_Writer bw = BB_WriterFromBuff(&bb);
BB_WriteUBits(&bw, N_PacketMagic, 32); /* TODO: implicitly encode magic into crc32 */ BB_WriteUBits(&bw, N_PacketMagic, 32); // TODO: implicitly encode magic into crc32
BB_WriteIBits(&bw, N_PacketKind_MsgChunk, 8); BB_WriteIBits(&bw, N_PacketKind_MsgChunk, 8);
BB_WriteUBits(&bw, packet_flags, 8); BB_WriteUBits(&bw, packet_flags, 8);
BB_WriteUV(&bw, channel->our_acked_seq); BB_WriteUV(&bw, channel->our_acked_seq);
@ -971,8 +1007,10 @@ void N_EndUpdate(N_Host *host)
} }
} }
//////////////////////////////
//- Send packets //- Send packets
/* TODO: Aggregate small packets */
// TODO: Aggregate small packets
{ {
for (u64 i = 0; i < host->num_channels_reserved; ++i) for (u64 i = 0; i < host->num_channels_reserved; ++i)
{ {
@ -982,19 +1020,19 @@ void N_EndUpdate(N_Host *host)
if (channel->valid) if (channel->valid)
{ {
P_Address address = channel->address; P_Address address = channel->address;
/* Send reliable packets to channel */ // Send reliable packets to channel
for (N_SndPacket *packet = channel->first_reliable_packet; packet; packet = packet->next) for (N_SndPacket *packet = channel->first_reliable_packet; packet; packet = packet->next)
{ {
P_WriteSock(sock, address, STRING(packet->data_len, packet->data)); P_WriteSock(sock, address, STRING(packet->data_len, packet->data));
total_sent += packet->data_len; total_sent += packet->data_len;
} }
/* Send unreliable packets to channel */ // Send unreliable packets to channel
for (N_SndPacket *packet = channel->first_unreliable_packet; packet; packet = packet->next) for (N_SndPacket *packet = channel->first_unreliable_packet; packet; packet = packet->next)
{ {
P_WriteSock(sock, address, STRING(packet->data_len, packet->data)); P_WriteSock(sock, address, STRING(packet->data_len, packet->data));
total_sent += packet->data_len; total_sent += packet->data_len;
} }
/* Release unreliable packets */ // Release unreliable packets
if (channel->first_unreliable_packet) if (channel->first_unreliable_packet)
{ {
channel->last_unreliable_packet->next = host->first_free_packet; channel->last_unreliable_packet->next = host->first_free_packet;
@ -1008,8 +1046,9 @@ void N_EndUpdate(N_Host *host)
} }
} }
//////////////////////////////
//- Reset command list
//- Reset commands list
host->first_cmd = 0; host->first_cmd = 0;
host->last_cmd = 0; host->last_cmd = 0;
ResetArena(host->cmd_arena); ResetArena(host->cmd_arena);

View File

@ -77,7 +77,7 @@ Struct(N_ChannelLookupBin)
#define N_PacketMagic 0xd9e3b8b6 #define N_PacketMagic 0xd9e3b8b6
#define N_MaxPacketChunkLen 1024 #define N_MaxPacketChunkLen 1024
#define N_MaxPacketLen 1280 /* Give enough space for msg chunk + header */ #define N_MaxPacketLen 1280 // Give enough space for msg chunk + header
Enum(N_PacketKind) Enum(N_PacketKind)
{ {
@ -136,7 +136,7 @@ Struct(N_Channel)
N_Channel *next_address_hash; N_Channel *next_address_hash;
N_Channel *prev_address_hash; N_Channel *prev_address_hash;
/* NOTE: Packets are allocated in host's `arena` */ // NOTE: Packets are allocated in host's `arena`
N_SndPacket *first_reliable_packet; N_SndPacket *first_reliable_packet;
N_SndPacket *last_reliable_packet; N_SndPacket *last_reliable_packet;
N_SndPacket *first_unreliable_packet; N_SndPacket *first_unreliable_packet;
@ -144,7 +144,7 @@ Struct(N_Channel)
u64 num_reliable_packets; u64 num_reliable_packets;
u64 num_unreliable_packets; u64 num_unreliable_packets;
/* NOTE: Msg assemblers are allocated in host's `arena` */ // NOTE: Msg assemblers are allocated in host's `arena`
struct N_MsgAssembler *least_recent_msg_assembler; struct N_MsgAssembler *least_recent_msg_assembler;
struct N_MsgAssembler *most_recent_msg_assembler; struct N_MsgAssembler *most_recent_msg_assembler;
@ -181,14 +181,14 @@ Struct(N_MsgAssembler)
N_Channel *channel; N_Channel *channel;
b32 is_reliable; b32 is_reliable;
/* Free list */ // Free list
N_MsgAssembler *next_free; N_MsgAssembler *next_free;
/* Bucket list */ // Bucket list
N_MsgAssembler *next_hash; N_MsgAssembler *next_hash;
N_MsgAssembler *prev_hash; N_MsgAssembler *prev_hash;
/* Channel list */ // Channel list
N_MsgAssembler *less_recent; N_MsgAssembler *less_recent;
N_MsgAssembler *more_recent; N_MsgAssembler *more_recent;
@ -224,7 +224,7 @@ Struct(N_Host)
P_Sock *sock; P_Sock *sock;
BuddyCtx *buddy; /* For storing msg assembler data */ BuddyCtx *buddy; // For storing msg assembler data
Arena *cmd_arena; Arena *cmd_arena;
N_Cmd *first_cmd; N_Cmd *first_cmd;
@ -236,16 +236,16 @@ Struct(N_Host)
N_Channel *first_free_channel; N_Channel *first_free_channel;
u64 num_channels_reserved; u64 num_channels_reserved;
N_SndPacket *first_free_packet; /* Acquired in `arena` */ N_SndPacket *first_free_packet; // Acquired in `arena`
N_MsgAssembler *first_free_msg_assembler; /* Acquired in `arena` */ N_MsgAssembler *first_free_msg_assembler; // Acquired in `arena`
N_ChannelLookupBin *channel_lookup_bins; /* Acquired in `arena` */ N_ChannelLookupBin *channel_lookup_bins; // Acquired in `arena`
u64 num_channel_lookup_bins; u64 num_channel_lookup_bins;
N_MsgAssemblerLookupBin *msg_assembler_lookup_bins; /* Acquired in `arena` */ N_MsgAssemblerLookupBin *msg_assembler_lookup_bins; // Acquired in `arena`
u64 num_msg_assembler_lookup_bins; u64 num_msg_assembler_lookup_bins;
/* Double buffer for incoming data */ // Double buffer for incoming data
Mutex rcv_buffer_write_mutex; Mutex rcv_buffer_write_mutex;
N_RcvBuffer *rcv_buffer_read; N_RcvBuffer *rcv_buffer_read;
N_RcvBuffer *rcv_buffer_write; N_RcvBuffer *rcv_buffer_write;

View File

@ -40,7 +40,7 @@ Struct(P_Address)
{ {
b32 valid; b32 valid;
P_AddressFamily family; P_AddressFamily family;
/* NOTE: ipnb & portnb are stored in network byte order */ // NOTE: ipnb & portnb are stored in network byte order
u8 ipnb[16]; u8 ipnb[16];
u16 portnb; u16 portnb;
}; };
@ -50,7 +50,7 @@ Struct(P_Address)
Struct(P_SockReadResult) Struct(P_SockReadResult)
{ {
b32 valid; /* Since data.len = 0 can be valid */ b32 valid; // Since data.len = 0 can be valid
P_Address address; P_Address address;
String data; String data;
}; };
@ -74,7 +74,7 @@ void P_Bootstrap(void);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ @hookdecl File system //~ @hookdecl File system
/* NOTE: File paths use forward slash '/' as delimiter */ // NOTE: File paths use forward slash '/' as delimiter
//- File system helpers //- File system helpers
String P_GetWritePath(Arena *arena); String P_GetWritePath(Arena *arena);
@ -84,7 +84,7 @@ void P_MkDir(String path);
//- File creation //- File creation
P_File P_OpenFileRead(String path); P_File P_OpenFileRead(String path);
P_File P_OpenFileReadWait(String path); /* Waits until file is not being used by another program */ P_File P_OpenFileReadWait(String path); // Waits until file is not being used by another program
P_File P_OpenFileWrite(String path); P_File P_OpenFileWrite(String path);
P_File P_OpenFileAppend(String path); P_File P_OpenFileAppend(String path);
void P_CloseFile(P_File file); void P_CloseFile(P_File file);

View File

@ -10,11 +10,11 @@ void P_Bootstrap(void)
//- Init watches pool //- Init watches pool
g->watches_arena = AcquireArena(Gibi(64)); g->watches_arena = AcquireArena(Gibi(64));
//- Init winsock // Init winsock
WSAStartup(MAKEWORD(2, 2), &g->wsa_data); WSAStartup(MAKEWORD(2, 2), &g->wsa_data);
g->socks_arena = AcquireArena(Gibi(64)); g->socks_arena = AcquireArena(Gibi(64));
//- Init timer // Init timer
DispatchWave(Lit("Win32 timer sync"), 1, P_W32_SyncTimerForever, 0); DispatchWave(Lit("Win32 timer sync"), 1, P_W32_SyncTimerForever, 0);
} }
@ -93,7 +93,7 @@ P_W32_Address P_W32_Win32AddressFromPlatformAddress(P_Address addr)
return result; return result;
} }
/* If supplied address has ip INADDR_ANY (0), convert ip to localhost */ // If supplied address has ip INADDR_ANY (0), convert ip to localhost
P_W32_Address P_W32_ConvertAnyaddrToLocalhost(P_W32_Address addr) P_W32_Address P_W32_ConvertAnyaddrToLocalhost(P_W32_Address addr)
{ {
if (addr.family == AF_INET) if (addr.family == AF_INET)
@ -162,7 +162,7 @@ void P_W32_SyncTimerForever(WaveLaneCtx *lane)
P_W32_SharedState *g = &P_W32_shared_state; P_W32_SharedState *g = &P_W32_shared_state;
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
/* Create high resolution timer */ // Create high resolution timer
HANDLE timer = CreateWaitableTimerExW(0, 0, CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS); HANDLE timer = CreateWaitableTimerExW(0, 0, CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS);
if (!timer) if (!timer)
{ {
@ -177,11 +177,11 @@ void P_W32_SyncTimerForever(WaveLaneCtx *lane)
} }
i64 last_cycle_ns = 0; i64 last_cycle_ns = 0;
/* FIXME: shutdown */ // FIXME: shutdown
for (;;) for (;;)
{ {
{ {
/* TODO: Minimum timer frequency in case timers ever become ultra precise in the future */ // TODO: Minimum timer frequency in case timers ever become ultra precise in the future
LARGE_INTEGER due = Zi; LARGE_INTEGER due = Zi;
due.QuadPart = -1; due.QuadPart = -1;
//due.QuadPart = -10000; //due.QuadPart = -10000;
@ -195,7 +195,7 @@ void P_W32_SyncTimerForever(WaveLaneCtx *lane)
i64 period_ns = last_cycle_ns == 0 ? P_W32_DefaultTimerPeriodNs : now_ns - last_cycle_ns; i64 period_ns = last_cycle_ns == 0 ? P_W32_DefaultTimerPeriodNs : now_ns - last_cycle_ns;
last_cycle_ns = now_ns; last_cycle_ns = now_ns;
/* Compute mean period */ // Compute mean period
{ {
periods[periods_index++] = period_ns; periods[periods_index++] = period_ns;
if (periods_index == countof(periods)) if (periods_index == countof(periods))
@ -211,7 +211,7 @@ void P_W32_SyncTimerForever(WaveLaneCtx *lane)
Atomic64Set(&g->average_timer_period_ns.v, RoundF64ToI64(mean_ns)); Atomic64Set(&g->average_timer_period_ns.v, RoundF64ToI64(mean_ns));
} }
/* Update fence */ // Update fence
SetFence(&g->timer_fence, now_ns); SetFence(&g->timer_fence, now_ns);
} }
} }
@ -219,11 +219,10 @@ void P_W32_SyncTimerForever(WaveLaneCtx *lane)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ @hookimpl File system //~ @hookimpl File system
//- File system helpers
String P_GetWritePath(Arena *arena) String P_GetWritePath(Arena *arena)
{ {
u16 *p = 0; u16 *p = 0;
/* TODO: cache this? */ // TODO: cache this?
HRESULT result = SHGetKnownFolderPath( HRESULT result = SHGetKnownFolderPath(
&FOLDERID_LocalAppData, &FOLDERID_LocalAppData,
0, 0,
@ -300,7 +299,6 @@ void P_MkDir(String path)
EndScratch(scratch); EndScratch(scratch);
} }
//- File creation
P_File P_OpenFileRead(String path) P_File P_OpenFileRead(String path)
{ {
TempArena scratch = BeginScratchNoConflict(); TempArena scratch = BeginScratchNoConflict();
@ -405,7 +403,6 @@ void P_CloseFile(P_File file)
} }
} }
//- File data manipulation
String P_ReadFile(Arena *arena, P_File file) String P_ReadFile(Arena *arena, P_File file)
{ {
i64 size = 0; i64 size = 0;
@ -418,15 +415,15 @@ String P_ReadFile(Arena *arena, P_File file)
if (size > 0) if (size > 0)
{ {
/* ReadFile returns non-zero on success */ // ReadFile returns non-zero on success
/* TODO: error checking */ // TODO: error checking
PushAlign(arena, CachelineSize); PushAlign(arena, CachelineSize);
s.text = PushStructsNoZero(arena, u8, size); s.text = PushStructsNoZero(arena, u8, size);
ReadFile( ReadFile(
(HANDLE)file.handle, (HANDLE)file.handle,
s.text, s.text,
(DWORD)s.len, (DWORD)s.len,
0, /* lpNumberOfBytesRead */ 0,
0 0
); );
} }
@ -436,8 +433,8 @@ String P_ReadFile(Arena *arena, P_File file)
void P_WriteFile(P_File file, String data) void P_WriteFile(P_File file, String data)
{ {
/* TODO: Check what the real data limit is and chunk sequentially based on // TODO: Check what the real data limit is and chunk sequentially based on
* that (rather than failing) */ // that (rather than failing)
if (data.len >= 0x7FFF) if (data.len >= 0x7FFF)
{ {
TempArena scratch = BeginScratchNoConflict(); TempArena scratch = BeginScratchNoConflict();
@ -449,17 +446,16 @@ void P_WriteFile(P_File file, String data)
EndScratch(scratch); EndScratch(scratch);
} }
/* WriteFile returns TRUE on success */ // WriteFile returns TRUE on success
WriteFile( WriteFile(
(HANDLE)file.handle, (HANDLE)file.handle,
data.text, data.text,
(DWORD)data.len, (DWORD)data.len,
0, /* lpNumberOfBytesWritten */ 0,
0 0
); );
} }
//- File info
u64 P_GetFileSize(P_File file) u64 P_GetFileSize(P_File file)
{ {
LARGE_INTEGER li_file_size; LARGE_INTEGER li_file_size;
@ -469,19 +465,19 @@ u64 P_GetFileSize(P_File file)
P_FileTime P_GetFileTime(P_File file) P_FileTime P_GetFileTime(P_File file)
{ {
/* Get file times */ // Get file times
FILETIME ft_created; FILETIME ft_created;
FILETIME ft_accessed; FILETIME ft_accessed;
FILETIME ft_modified; FILETIME ft_modified;
b32 ok = !!GetFileTime((HANDLE)file.handle, &ft_created, &ft_accessed, &ft_modified); b32 ok = !!GetFileTime((HANDLE)file.handle, &ft_created, &ft_accessed, &ft_modified);
if (ok) if (ok)
{ {
/* Convert file times to local file time */ // Convert file times to local file time
FileTimeToLocalFileTime(&ft_created, &ft_created); FileTimeToLocalFileTime(&ft_created, &ft_created);
FileTimeToLocalFileTime(&ft_accessed, &ft_accessed); FileTimeToLocalFileTime(&ft_accessed, &ft_accessed);
FileTimeToLocalFileTime(&ft_modified, &ft_modified); FileTimeToLocalFileTime(&ft_modified, &ft_modified);
/* Convert local file times to system times */ // Convert local file times to system times
SYSTEMTIME st_created; SYSTEMTIME st_created;
SYSTEMTIME st_accessed; SYSTEMTIME st_accessed;
SYSTEMTIME st_modified; SYSTEMTIME st_modified;
@ -534,7 +530,7 @@ P_FileMap P_OpenFileMap(P_File file)
); );
if (base_ptr == 0) if (base_ptr == 0)
{ {
/* Failed to create view */ // Failed to create view
CloseHandle(map_handle); CloseHandle(map_handle);
map_handle = INVALID_HANDLE_VALUE; map_handle = INVALID_HANDLE_VALUE;
} }
@ -599,7 +595,7 @@ P_Address P_AddressFromIpPortCstr(char *ip_cstr, char *port_cstr)
} }
else if (ai_result->ai_family == AF_INET6) else if (ai_result->ai_family == AF_INET6)
{ {
/* TODO: Enable ipv6 */ // TODO: Enable ipv6
// struct sockaddr_in6 *sockaddr = (struct sockaddr_in6 *)ai_result->ai_addr; // struct sockaddr_in6 *sockaddr = (struct sockaddr_in6 *)ai_result->ai_addr;
// result.valid = 1; // result.valid = 1;
// result.family = P_AddressFamily_Ipv6; // result.family = P_AddressFamily_Ipv6;
@ -618,7 +614,7 @@ P_Address P_AddressFromIpPortCstr(char *ip_cstr, char *port_cstr)
P_Address P_AddressFromString(String str) P_Address P_AddressFromString(String str)
{ {
/* Parse string into ip & port */ // Parse string into ip & port
u8 ip_buff[1024]; u8 ip_buff[1024];
u8 port_buff[countof(ip_buff)]; u8 port_buff[countof(ip_buff)];
char *ip_cstr = 0; char *ip_cstr = 0;
@ -638,7 +634,7 @@ P_Address P_AddressFromString(String str)
u64 parse_len = MinU64(MinU64(str.len, countof(ip_buff) - 1), countof(port_buff) - 1); u64 parse_len = MinU64(MinU64(str.len, countof(ip_buff) - 1), countof(port_buff) - 1);
if (colon_count > 1 && str.text[0] == '[') if (colon_count > 1 && str.text[0] == '[')
{ {
/* Parse ipv6 with port */ // Parse ipv6 with port
b32 parse_addr = 1; b32 parse_addr = 1;
for (u64 i = 1; i < parse_len; ++i) for (u64 i = 1; i < parse_len; ++i)
{ {
@ -664,7 +660,7 @@ P_Address P_AddressFromString(String str)
} }
else if (colon_count == 1) else if (colon_count == 1)
{ {
/* Parse address with port */ // Parse address with port
b32 parse_addr = 1; b32 parse_addr = 1;
for (u64 i = 0; i < parse_len; ++i) for (u64 i = 0; i < parse_len; ++i)
{ {
@ -690,7 +686,7 @@ P_Address P_AddressFromString(String str)
} }
else else
{ {
/* Copy address without port */ // Copy address without port
ip_len = MinU64(str.len, countof(ip_buff) - 1); ip_len = MinU64(str.len, countof(ip_buff) - 1);
CopyBytes(ip_buff, str.text, ip_len); CopyBytes(ip_buff, str.text, ip_len);
} }
@ -748,7 +744,7 @@ String P_StringFromAddress(Arena *arena, P_Address address)
if (address.family == P_AddressFamily_Ipv6) if (address.family == P_AddressFamily_Ipv6)
{ {
/* TODO */ // TODO
} }
else else
{ {
@ -845,7 +841,7 @@ P_SockReadResult P_ReadSock(Arena *arena, P_Sock *sock)
result.data.len = size; result.data.len = size;
result.valid = 1; result.valid = 1;
/* PopStruct arena back to end of msg */ // PopStruct arena back to end of msg
PopTo(arena, arena->pos - read_buff_size + size); PopTo(arena, arena->pos - read_buff_size + size);
} }
else else
@ -987,7 +983,7 @@ void P_SleepPrecise(i64 sleep_time_ns)
i64 now_ns = TimeNs(); i64 now_ns = TimeNs();
i64 target_ns = now_ns + sleep_time_ns; i64 target_ns = now_ns + sleep_time_ns;
/* Sleep on timer to conserve power */ // Sleep on timer to conserve power
{ {
Fence *timer_fence = P_GetTimerFence(); Fence *timer_fence = P_GetTimerFence();
i64 timer_period_ns = P_GetCurrentTimerPeriodNs(); i64 timer_period_ns = P_GetCurrentTimerPeriodNs();
@ -996,7 +992,7 @@ void P_SleepPrecise(i64 sleep_time_ns)
YieldOnFence(timer_fence, target_timer_sleep_ns); YieldOnFence(timer_fence, target_timer_sleep_ns);
} }
/* Spin */ // Spin
now_ns = TimeNs(); now_ns = TimeNs();
while (now_ns < target_ns) while (now_ns < target_ns)
{ {

View File

@ -1,8 +1,7 @@
/* WASAPI backend for audio playback // WASAPI backend for audio playback
* //
* Based on mmozeiko's WASAPI examples // Based on mmozeiko's WASAPI examples
* https://gist.github.com/mmozeiko/5a5b168e61aff4c1eaec0381da62808f#file-win32_wasapi-h // https://gist.github.com/mmozeiko/5a5b168e61aff4c1eaec0381da62808f#file-win32_wasapi-h
*/
PB_WSP_SharedState PB_WSP_shared_state = ZI; PB_WSP_SharedState PB_WSP_shared_state = ZI;
@ -13,7 +12,7 @@ void PB_Bootstrap(void)
{ {
PB_WSP_SharedState *g = &PB_WSP_shared_state; PB_WSP_SharedState *g = &PB_WSP_shared_state;
PB_WSP_InitializeWasapi(); PB_WSP_InitializeWasapi();
/* Start playback job */ // Start playback job
JobPoolId playback_pool = InitJobPool(1, Lit("Playback"), JobPoolPriority_Audio); 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); g->shutdown_jobs_count += RunJob(PB_WSP_Playback, .pool = playback_pool, .fence = &g->shutdown_jobs_fence);
OnExit(&PB_WSP_Shutdown); OnExit(&PB_WSP_Shutdown);
@ -36,16 +35,16 @@ void PB_WSP_InitializeWasapi(void)
u64 channel_count = 2; u64 channel_count = 2;
u32 channel_mask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT; u32 channel_mask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
/* Create enumerator to get audio device */ // Create enumerator to get audio device
IMMDeviceEnumerator *enumerator; IMMDeviceEnumerator *enumerator;
CoCreateInstance(&CLSID_MMDeviceEnumerator, 0, CLSCTX_ALL, &IID_IMMDeviceEnumerator, (LPVOID *)&enumerator); CoCreateInstance(&CLSID_MMDeviceEnumerator, 0, CLSCTX_ALL, &IID_IMMDeviceEnumerator, (LPVOID *)&enumerator);
/* Get default playback device */ // Get default playback device
IMMDevice *device; IMMDevice *device;
IMMDeviceEnumerator_GetDefaultAudioEndpoint(enumerator, eRender, eConsole, &device); IMMDeviceEnumerator_GetDefaultAudioEndpoint(enumerator, eRender, eConsole, &device);
IMMDeviceEnumerator_Release(enumerator); IMMDeviceEnumerator_Release(enumerator);
/* Create audio client for device */ // Create audio client for device
IMMDevice_Activate(device, &IID_IAudioClient, CLSCTX_ALL, 0, (LPVOID *)&g->client); IMMDevice_Activate(device, &IID_IAudioClient, CLSCTX_ALL, 0, (LPVOID *)&g->client);
IMMDevice_Release(device); IMMDevice_Release(device);
@ -70,10 +69,9 @@ void PB_WSP_InitializeWasapi(void)
IAudioClient3 *client3; IAudioClient3 *client3;
if (SUCCEEDED(IAudioClient_QueryInterface(g->client, &IID_IAudioClient3, (LPVOID *)&client3))) if (SUCCEEDED(IAudioClient_QueryInterface(g->client, &IID_IAudioClient3, (LPVOID *)&client3)))
{ {
/* From Martins: Minimum buffer size will typically be 480 samples (10msec @ 48khz) // 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 // 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 // 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; 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); IAudioClient3_GetSharedModeEnginePeriod(client3, wfx, &default_period_samples, &fundamental_period_samples, &min_period_samples, &max_period_samples);
@ -91,34 +89,33 @@ void PB_WSP_InitializeWasapi(void)
if (!client_initialized) if (!client_initialized)
{ {
/* Get duration for shared-mode streams, this will typically be 480 samples (10msec @ 48khz) */ // Get duration for shared-mode streams, this will typically be 480 samples (10msec @ 48khz)
REFERENCE_TIME duration; REFERENCE_TIME duration;
IAudioClient_GetDevicePeriod(g->client, &duration, 0); IAudioClient_GetDevicePeriod(g->client, &duration, 0);
/* Initialize audio playback // Initialize audio playback
* //
* NOTE: // NOTE:
* Passing AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM will tell WASAPI to // Passing AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM will tell WASAPI to
* always convert to native mixing format. This may introduce latency // always convert to native mixing format. This may introduce latency
* but allows for any input format. // but allows for any input format.
*/
const DWORD flags = AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY; 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); IAudioClient_Initialize(g->client, AUDCLNT_SHAREMODE_SHARED, flags, duration, 0, wfx, 0);
} }
IAudioClient_GetMixFormat(g->client, &g->buffer_format); IAudioClient_GetMixFormat(g->client, &g->buffer_format);
/* Set up event handler to wait on */ // Set up event handler to wait on
g->event = CreateEventW(0, 0, 0, 0); g->event = CreateEventW(0, 0, 0, 0);
IAudioClient_SetEventHandle(g->client, g->event); IAudioClient_SetEventHandle(g->client, g->event);
/* Get playback client */ // Get playback client
IAudioClient_GetService(g->client, &IID_IAudioRenderClient, (LPVOID *)&g->playback); IAudioClient_GetService(g->client, &IID_IAudioRenderClient, (LPVOID *)&g->playback);
/* Start the playback */ // Start the playback
IAudioClient_Start(g->client); IAudioClient_Start(g->client);
/* Get audio buffer size in samples */ // Get audio buffer size in samples
IAudioClient_GetBufferSize(g->client, &g->buffer_frames); IAudioClient_GetBufferSize(g->client, &g->buffer_frames);
} }
@ -130,11 +127,11 @@ PB_WSP_Buff PB_WSP_BeginUpdate(void)
PB_WSP_SharedState *g = &PB_WSP_shared_state; PB_WSP_SharedState *g = &PB_WSP_shared_state;
PB_WSP_Buff wspbuf = ZI; PB_WSP_Buff wspbuf = ZI;
/* Get padding frames */ // Get padding frames
u32 padding_frames; u32 padding_frames;
IAudioClient_GetCurrentPadding(g->client, &padding_frames); IAudioClient_GetCurrentPadding(g->client, &padding_frames);
/* Get output buffer from WASAPI */ // Get output buffer from WASAPI
wspbuf.frames_count = 0; wspbuf.frames_count = 0;
if (padding_frames <= g->buffer_frames) if (padding_frames <= g->buffer_frames)
{ {
@ -154,18 +151,18 @@ void PB_WSP_EndUpdate(PB_WSP_Buff *wspbuf, MIX_PcmF32 src)
u32 flags = 0; u32 flags = 0;
if (frames_in_source == frames_in_output) if (frames_in_source == frames_in_output)
{ {
/* Copy bytes to output */ // Copy bytes to output
u32 bytes_per_sample = g->buffer_format->nBlockAlign / g->buffer_format->nChannels; u32 bytes_per_sample = g->buffer_format->nBlockAlign / g->buffer_format->nChannels;
u32 write_size = frames_in_source * 2 * bytes_per_sample; u32 write_size = frames_in_source * 2 * bytes_per_sample;
CopyBytes(wspbuf->frames, src.samples, write_size); CopyBytes(wspbuf->frames, src.samples, write_size);
} }
else else
{ {
/* Submit silence if not enough samples */ // Submit silence if not enough samples
flags |= AUDCLNT_BUFFERFLAGS_SILENT; flags |= AUDCLNT_BUFFERFLAGS_SILENT;
/* This shouldn't occur, mixer should be generating samples equivilent // This shouldn't occur, mixer should be generating samples equivilent
* to value returned from `PB_WSP_BeginUpdate`. */ // to value returned from `PB_WSP_BeginUpdate`.
Assert(0); Assert(0);
} }
@ -174,7 +171,7 @@ void PB_WSP_EndUpdate(PB_WSP_Buff *wspbuf, MIX_PcmF32 src)
flags |= AUDCLNT_BUFFERFLAGS_SILENT; flags |= AUDCLNT_BUFFERFLAGS_SILENT;
} }
/* Submit output buffer to WASAPI */ // Submit output buffer to WASAPI
IAudioRenderClient_ReleaseBuffer(g->playback, frames_in_source, flags); IAudioRenderClient_ReleaseBuffer(g->playback, frames_in_source, flags);
} }
@ -185,9 +182,12 @@ 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. */ // FIXME: If playback fails at any point and mixer stops advancing, we
/* TODO: Signal counter that running job wiats on, rather than scheduling job manually */ // 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)) while (!Atomic32Fetch(&g->shutdown))
{ {
TempArena scratch = BeginScratchNoConflict(); TempArena scratch = BeginScratchNoConflict();

View File

@ -11,7 +11,7 @@ Readonly S_ReadonlyCtx S_ro = {
void S_Bootstrap(void) void S_Bootstrap(void)
{ {
/* Initialize shared state */ // Initialize shared state
for (u64 i = 0; i < countof(S.input_states); ++i) for (u64 i = 0; i < countof(S.input_states); ++i)
{ {
S_InputState *input = &S.input_states[i]; S_InputState *input = &S.input_states[i];
@ -23,7 +23,7 @@ void S_Bootstrap(void)
output->arena = AcquireArena(Gibi(64)); output->arena = AcquireArena(Gibi(64));
} }
/* Dispatch sim wave */ // Dispatch sim wave
DispatchWave(Lit("Sim"), 1, S_TickForever, 0); DispatchWave(Lit("Sim"), 1, S_TickForever, 0);
} }
@ -56,7 +56,7 @@ b32 S_MatchKey(S_Key a, S_Key b)
S_Key S_RandKey(void) S_Key S_RandKey(void)
{ {
/* TODO: Don't use true randomness for entity keys. It's overkill & non-deterministic. */ // TODO: Don't use true randomness for entity keys. It's overkill & non-deterministic.
S_Key result = Zi; S_Key result = Zi;
TrueRand(StringFromStruct(&result)); TrueRand(StringFromStruct(&result));
return result; return result;
@ -67,7 +67,7 @@ S_Key S_RandKey(void)
String S_NameFromTileKind(S_TileKind kind) String S_NameFromTileKind(S_TileKind kind)
{ {
/* Tile names array */ // Tile names array
#define X(name, ...) [S_TileKind_##name] = CompLit(#name), #define X(name, ...) [S_TileKind_##name] = CompLit(#name),
PERSIST Readonly String tile_names[] = { PERSIST Readonly String tile_names[] = {
S_TilesXMacro(X) S_TilesXMacro(X)
@ -242,7 +242,7 @@ 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 */ // Copy ents
world->ents = PushStructsNoZero(arena, S_Ent, snapshot->ents_count); world->ents = PushStructsNoZero(arena, S_Ent, snapshot->ents_count);
CopyStructs(world->ents, snapshot->ents, snapshot->ents_count); CopyStructs(world->ents, snapshot->ents, snapshot->ents_count);
world->ents_count = snapshot->ents_count; world->ents_count = snapshot->ents_count;
@ -334,7 +334,7 @@ void S_TickForever(WaveLaneCtx *lane)
{ {
S_Cmd *cmd = &cmd_node->cmd; S_Cmd *cmd = &cmd_node->cmd;
/* Spawn entity */ // Spawn entity
if (cmd->kind == S_CmdKind_Spawn) if (cmd->kind == S_CmdKind_Spawn)
{ {
S_Ent *src = &cmd->ent; S_Ent *src = &cmd->ent;
@ -364,7 +364,7 @@ void S_TickForever(WaveLaneCtx *lane)
} }
} }
/* Place tiles */ // Place tiles
if (cmd->kind == S_CmdKind_Tile) if (cmd->kind == S_CmdKind_Tile)
{ {
tile_placements_count += 1; tile_placements_count += 1;
@ -413,7 +413,7 @@ void S_TickForever(WaveLaneCtx *lane)
////////////////////////////// //////////////////////////////
//- Publish sim state //- Publish sim state
/* TODO: Only copy active entities */ // TODO: Only copy active entities
LockTicketMutex(&S.output_back_tm); LockTicketMutex(&S.output_back_tm);
{ {
S_OutputState *output = &S.output_states[S.output_back_idx]; S_OutputState *output = &S.output_states[S.output_back_idx];
@ -431,7 +431,7 @@ void S_TickForever(WaveLaneCtx *lane)
*dst = *src; *dst = *src;
} }
/* Forward tile placements */ // Forward tile placements
snapshot->tile_placements_count = tile_placements_count; snapshot->tile_placements_count = tile_placements_count;
snapshot->tile_placements = PushStructs(output->arena, S_TilePlacement, tile_placements_count); snapshot->tile_placements = PushStructs(output->arena, S_TilePlacement, tile_placements_count);
{ {
@ -454,7 +454,7 @@ void S_TickForever(WaveLaneCtx *lane)
////////////////////////////// //////////////////////////////
//- End sim frame //- End sim frame
/* Reset front input state */ // Reset front input state
{ {
Arena *arena = input->arena; Arena *arena = input->arena;
ResetArena(arena); ResetArena(arena);

View File

@ -33,7 +33,7 @@ Struct(S_Shape)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Ent types //~ Ent types
/* TODO: Move boolean fields into bitwise property flags */ // TODO: Move boolean fields into bitwise property flags
Struct(S_Ent) Struct(S_Ent)
{ {
@ -151,13 +151,13 @@ Struct(S_Cmd)
{ {
S_CmdKind kind; S_CmdKind kind;
/* Tiles */ // Tiles
S_TilePlacement tile_placement; S_TilePlacement tile_placement;
/* Spawn */ // Spawn
S_Ent ent; S_Ent ent;
/* Control */ // Control
S_Key target; S_Key target;
Vec2 move; Vec2 move;
Vec2 look; Vec2 look;

View File

@ -9,7 +9,7 @@
X(Wall) \ X(Wall) \
/* -------------------- */ /* -------------------- */
/* Tiles enum */ // Tiles enum
#define X(name, ...) S_TileKind_##name, #define X(name, ...) S_TileKind_##name,
Enum(S_TileKind) Enum(S_TileKind)
{ {

View File

@ -161,7 +161,7 @@ void V_EndCommandsWidget(V_CommandsWidget *widget)
UI_SetNext(Flags, UI_BoxFlag_Floating); UI_SetNext(Flags, UI_BoxFlag_Floating);
UI_PushCP(UI_BuildBoxEx(UI_KeyF("titlebar"))); UI_PushCP(UI_BuildBoxEx(UI_KeyF("titlebar")));
{ {
/* Title bar */ // Title bar
UI_PushCP(UI_NilKey); UI_PushCP(UI_NilKey);
{ {
UI_Push(BackgroundColor, titlebar_color); UI_Push(BackgroundColor, titlebar_color);
@ -176,10 +176,10 @@ void V_EndCommandsWidget(V_CommandsWidget *widget)
UI_Push(Width, UI_GROW(1, 0)); UI_Push(Width, UI_GROW(1, 0));
UI_Push(BorderColor, 0); UI_Push(BorderColor, 0);
/* Left title box */ // Left title box
UI_BuildRow(); UI_BuildRow();
/* Title box */ // Title box
UI_SetNext(FontSize, theme.window_title_font_size); UI_SetNext(FontSize, theme.window_title_font_size);
UI_SetNext(ChildAlignment, UI_Alignment_Center); UI_SetNext(ChildAlignment, UI_Alignment_Center);
UI_SetNext(Width, UI_SHRINK(0, 1)); UI_SetNext(Width, UI_SHRINK(0, 1));
@ -187,7 +187,7 @@ void V_EndCommandsWidget(V_CommandsWidget *widget)
UI_SetNext(Flags, UI_BoxFlag_DrawText); UI_SetNext(Flags, UI_BoxFlag_DrawText);
UI_BuildBox(); UI_BuildBox();
/* Right title box */ // Right title box
UI_BuildRow(); UI_BuildRow();
} }
UI_PopCP(UI_TopCP()); UI_PopCP(UI_TopCP());
@ -243,17 +243,17 @@ void V_EndCommandsWidget(V_CommandsWidget *widget)
{ {
UI_Push(Tag, btn_key.hash); UI_Push(Tag, btn_key.hash);
/* Begin spacer */ // Begin spacer
UI_BuildSpacer(UI_PIX(20, 1), Axis_X); UI_BuildSpacer(UI_PIX(20, 1), Axis_X);
/* Command label */ // Command label
UI_SetNext(ChildAlignment, UI_Alignment_Center); UI_SetNext(ChildAlignment, UI_Alignment_Center);
UI_BuildLabel(item->desc.display_name); UI_BuildLabel(item->desc.display_name);
/* Middle spacer */ // Middle spacer
UI_BuildSpacer(UI_GROW(1, 0), Axis_X); UI_BuildSpacer(UI_GROW(1, 0), Axis_X);
/* Command hotkey buttons */ // Command hotkey buttons
for (u64 i = 0; i < countof(item->desc.hotkeys); ++i) for (u64 i = 0; i < countof(item->desc.hotkeys); ++i)
{ {
UI_Key hotkey_key = UI_KeyF("hotkey%F", FmtUint(i)); UI_Key hotkey_key = UI_KeyF("hotkey%F", FmtUint(i));
@ -299,7 +299,7 @@ void V_EndCommandsWidget(V_CommandsWidget *widget)
} }
} }
/* End spacer */ // End spacer
UI_BuildSpacer(UI_PIX(20, 1), Axis_X); UI_BuildSpacer(UI_PIX(20, 1), Axis_X);
} }
UI_PopCP(UI_TopCP()); UI_PopCP(UI_TopCP());
@ -352,7 +352,7 @@ void V_TickForever(WaveLaneCtx *lane)
G_Layout_DirectQueue_ShaderRead_ShaderReadWrite_CopyRead_CopyWrite G_Layout_DirectQueue_ShaderRead_ShaderReadWrite_CopyRead_CopyWrite
); );
gpu_tiles_ref = G_PushTexture2DRef(gpu_perm, gpu_tiles); gpu_tiles_ref = G_PushTexture2DRef(gpu_perm, gpu_tiles);
/* TODO: Clear tiles from GPU (instead of copy from cpu) */ // TODO: Clear tiles from GPU (instead of copy from cpu)
G_CopyCpuToTexture( G_CopyCpuToTexture(
cl, cl,
gpu_tiles, VEC3I32(0, 0, 0), gpu_tiles, VEC3I32(0, 0, 0),
@ -375,7 +375,7 @@ void V_TickForever(WaveLaneCtx *lane)
////////////////////////////// //////////////////////////////
//- State //- State
/* Init shortcuts */ // Init shortcuts
u64 shortcut_bins_count = 1024; u64 shortcut_bins_count = 1024;
V_ShortcutBin *shortcut_bins = PushStructs(perm, V_ShortcutBin, shortcut_bins_count); V_ShortcutBin *shortcut_bins = PushStructs(perm, V_ShortcutBin, shortcut_bins_count);
{ {
@ -453,7 +453,7 @@ void V_TickForever(WaveLaneCtx *lane)
ResetArena(frame->dvert_idxs_arena); ResetArena(frame->dvert_idxs_arena);
G_ResetArena(frame->cl, frame->gpu_arena); G_ResetArena(frame->cl, frame->gpu_arena);
/* Persist state */ // Persist state
CopyBytes(frame->held_buttons, last_frame->held_buttons, sizeof(frame->held_buttons)); CopyBytes(frame->held_buttons, last_frame->held_buttons, sizeof(frame->held_buttons));
frame->commands_widget = last_frame->commands_widget; frame->commands_widget = last_frame->commands_widget;
frame->is_editing = last_frame->is_editing; frame->is_editing = last_frame->is_editing;
@ -505,7 +505,7 @@ void V_TickForever(WaveLaneCtx *lane)
WND_Frame window_frame = ui_frame->window_frame; WND_Frame window_frame = ui_frame->window_frame;
WND_PushCmd(window_frame, .kind = WND_CmdKind_SetCursor, .cursor = WND_CursorKind_Default); WND_PushCmd(window_frame, .kind = WND_CmdKind_SetCursor, .cursor = WND_CursorKind_Default);
/* Restore window */ // Restore window
{ {
if (frame->window_restore.len > 0) if (frame->window_restore.len > 0)
{ {
@ -514,7 +514,7 @@ void V_TickForever(WaveLaneCtx *lane)
frame->window_restore = PushString(frame->arena, window_frame.restore); frame->window_restore = PushString(frame->arena, window_frame.restore);
} }
/* Set widget theme */ // Set widget theme
V_WidgetTheme theme = V_GetWidgetTheme(); V_WidgetTheme theme = V_GetWidgetTheme();
V_PushWidgetThemeStyles(theme); V_PushWidgetThemeStyles(theme);
@ -526,7 +526,7 @@ void V_TickForever(WaveLaneCtx *lane)
UI_Push(Parent, UI_BuildColumnEx(vis_box)); UI_Push(Parent, UI_BuildColumnEx(vis_box));
{ {
/* TODO: Don't rely on ui report for draw size since it introduces one frame of delay when resizing */ // TODO: Don't rely on ui report for draw size since it introduces one frame of delay when resizing
UI_Report vis_rep = UI_ReportFromKey(vis_box); UI_Report vis_rep = UI_ReportFromKey(vis_box);
frame->ui_dims = RoundVec2ToI32(DimsFromRng2(vis_rep.screen_rect)); frame->ui_dims = RoundVec2ToI32(DimsFromRng2(vis_rep.screen_rect));
} }
@ -634,11 +634,11 @@ void V_TickForever(WaveLaneCtx *lane)
////////////////////////////// //////////////////////////////
//- Initialize world <-> draw <-> ui transforms //- Initialize world <-> draw <-> ui transforms
/* World <-> ui */ // World <-> ui
frame->world_to_ui_xf = XformIdentity; frame->world_to_ui_xf = XformIdentity;
frame->ui_to_world_xf = XformIdentity; frame->ui_to_world_xf = XformIdentity;
{ {
/* Determine target camera pos */ // Determine target camera pos
Vec2 target_camera_pos = Zi; Vec2 target_camera_pos = Zi;
f32 target_camera_zoom = 0; f32 target_camera_zoom = 0;
if (frame->is_editing) if (frame->is_editing)
@ -652,7 +652,7 @@ void V_TickForever(WaveLaneCtx *lane)
frame->edit_camera_zoom = 3; frame->edit_camera_zoom = 3;
} }
frame->edit_camera_zoom = ClampF32(frame->edit_camera_zoom, min_zoom, max_zoom); frame->edit_camera_zoom = ClampF32(frame->edit_camera_zoom, min_zoom, max_zoom);
/* Offset edit camera based on cursor if panning / zooming */ // Offset edit camera based on cursor if panning / zooming
b32 is_zooming = last_frame->zooms != 0 && (frame->edit_camera_zoom != last_frame->edit_camera_zoom); b32 is_zooming = last_frame->zooms != 0 && (frame->edit_camera_zoom != last_frame->edit_camera_zoom);
if (last_frame->is_editing && (is_zooming || (frame->is_panning && last_frame->is_panning))) if (last_frame->is_editing && (is_zooming || (frame->is_panning && last_frame->is_panning)))
{ {
@ -692,7 +692,7 @@ void V_TickForever(WaveLaneCtx *lane)
target_camera_pos.y = ClampF32(target_camera_pos.y, -world_size / 2, world_size / 2); target_camera_pos.y = ClampF32(target_camera_pos.y, -world_size / 2, world_size / 2);
target_camera_zoom = ClampF32(target_camera_zoom, min_zoom, max_zoom); target_camera_zoom = ClampF32(target_camera_zoom, min_zoom, max_zoom);
/* Create world <-> ui xforms */ // Create world <-> ui xforms
{ {
f32 lerp_ratio = 15.0 * frame->dt; f32 lerp_ratio = 15.0 * frame->dt;
if (last_frame->tick == 0) if (last_frame->tick == 0)
@ -715,14 +715,14 @@ void V_TickForever(WaveLaneCtx *lane)
} }
} }
/* Draw <-> ui */ // Draw <-> ui
frame->draw_to_ui_xf = XformIdentity; frame->draw_to_ui_xf = XformIdentity;
frame->ui_to_draw_xf = XformIdentity; frame->ui_to_draw_xf = XformIdentity;
{ {
frame->ui_to_draw_xf = InvertXform(frame->draw_to_ui_xf); frame->ui_to_draw_xf = InvertXform(frame->draw_to_ui_xf);
} }
/* World <-> draw */ // World <-> draw
frame->world_to_draw_xf = XformIdentity; frame->world_to_draw_xf = XformIdentity;
frame->draw_to_world_xf = XformIdentity; frame->draw_to_world_xf = XformIdentity;
{ {
@ -774,13 +774,13 @@ void V_TickForever(WaveLaneCtx *lane)
////////////////////////////// //////////////////////////////
//- Place tiles //- Place tiles
/* TODO: Push vis cmd */ // TODO: Push vis cmd
if (frame->is_editing && last_frame->is_selecting && !frame->is_selecting) if (frame->is_editing && last_frame->is_selecting && !frame->is_selecting)
{ {
if (last_frame->selection_mode == V_SelectionMode_Tile) if (last_frame->selection_mode == V_SelectionMode_Tile)
{ {
/* TODO: Fix clamp when both start & end are outside of world */ // TODO: Fix clamp when both start & end are outside of world
Rng2I32 tile_range = Zi; Rng2I32 tile_range = Zi;
tile_range.p0 = S_TilePosFromWorldPos(last_frame->world_selection.p0); tile_range.p0 = S_TilePosFromWorldPos(last_frame->world_selection.p0);
tile_range.p1 = S_TilePosFromWorldPos(last_frame->world_selection.p1); tile_range.p1 = S_TilePosFromWorldPos(last_frame->world_selection.p1);
@ -796,13 +796,14 @@ void V_TickForever(WaveLaneCtx *lane)
////////////////////////////// //////////////////////////////
//- Build editor UI //- Build editor UI
/* TODO: Remove this (testing) */ // TODO: Remove this (testing)
//- Init test layout //- Init test layout
if (!V.root_panel) if (!V.root_panel)
{ {
{ {
V_Panel *panel = PushStruct(perm, V_Panel); V_Panel *panel = PushStruct(perm, V_Panel);
panel->key = UI_TransKey(); /* TODO: Don't use transient keys for panels */ panel->key = UI_TransKey(); // TODO: Don't use transient keys for panels
panel->axis = Axis_X; panel->axis = Axis_X;
panel->pref_ratio = 1; panel->pref_ratio = 1;
panel->is_organizing_panel = 1; panel->is_organizing_panel = 1;
@ -812,7 +813,7 @@ void V_TickForever(WaveLaneCtx *lane)
{ {
V_Panel *panel = PushStruct(perm, V_Panel); V_Panel *panel = PushStruct(perm, V_Panel);
panel->parent = V.root_panel; panel->parent = V.root_panel;
panel->key = UI_TransKey(); /* TODO: Don't use transient keys */ panel->key = UI_TransKey(); // TODO: Don't use transient keys
panel->axis = !panel->parent->axis; panel->axis = !panel->parent->axis;
DllQueuePush(panel->parent->first, panel->parent->last, panel); DllQueuePush(panel->parent->first, panel->parent->last, panel);
++panel->parent->count; ++panel->parent->count;
@ -820,7 +821,7 @@ void V_TickForever(WaveLaneCtx *lane)
{ {
V_Window *window = PushStruct(perm, V_Window); V_Window *window = PushStruct(perm, V_Window);
window->panel = panel; window->panel = panel;
window->key = UI_TransKey(); /* TODO: Don't use transient keys */ window->key = UI_TransKey(); // TODO: Don't use transient keys
// window->is_tile_window = 1; // window->is_tile_window = 1;
DllQueuePushNP(panel->first_window, panel->last_window, window, next_in_panel, prev_in_panel); DllQueuePushNP(panel->first_window, panel->last_window, window, next_in_panel, prev_in_panel);
++panel->windows_count; ++panel->windows_count;
@ -828,7 +829,7 @@ void V_TickForever(WaveLaneCtx *lane)
{ {
V_Window *window = PushStruct(perm, V_Window); V_Window *window = PushStruct(perm, V_Window);
window->panel = panel; window->panel = panel;
window->key = UI_TransKey(); /* TODO: Don't use transient keys */ window->key = UI_TransKey(); // TODO: Don't use transient keys
window->is_tile_window = 1; window->is_tile_window = 1;
DllQueuePushNP(panel->first_window, panel->last_window, window, next_in_panel, prev_in_panel); DllQueuePushNP(panel->first_window, panel->last_window, window, next_in_panel, prev_in_panel);
++panel->windows_count; ++panel->windows_count;
@ -839,7 +840,7 @@ void V_TickForever(WaveLaneCtx *lane)
{ {
V_Panel *panel = PushStruct(perm, V_Panel); V_Panel *panel = PushStruct(perm, V_Panel);
panel->parent = V.root_panel; panel->parent = V.root_panel;
panel->key = UI_TransKey(); /* TODO: Don't use transient keys */ panel->key = UI_TransKey(); // TODO: Don't use transient keys
panel->axis = !panel->parent->axis; panel->axis = !panel->parent->axis;
DllQueuePush(panel->parent->first, panel->parent->last, panel); DllQueuePush(panel->parent->first, panel->parent->last, panel);
++panel->parent->count; ++panel->parent->count;
@ -849,7 +850,7 @@ void V_TickForever(WaveLaneCtx *lane)
{ {
V_Window *window = PushStruct(perm, V_Window); V_Window *window = PushStruct(perm, V_Window);
window->panel = panel; window->panel = panel;
window->key = UI_TransKey(); /* TODO: Don't use transient keys */ window->key = UI_TransKey(); // TODO: Don't use transient keys
window->is_viewport_window = 1; window->is_viewport_window = 1;
DllQueuePushNP(panel->first_window, panel->last_window, window, next_in_panel, prev_in_panel); DllQueuePushNP(panel->first_window, panel->last_window, window, next_in_panel, prev_in_panel);
++panel->windows_count; ++panel->windows_count;
@ -859,7 +860,7 @@ void V_TickForever(WaveLaneCtx *lane)
{ {
V_Panel *panel = PushStruct(perm, V_Panel); V_Panel *panel = PushStruct(perm, V_Panel);
panel->parent = V.root_panel; panel->parent = V.root_panel;
panel->key = UI_TransKey(); /* TODO: Don't use transient keys */ panel->key = UI_TransKey(); // TODO: Don't use transient keys
panel->axis = !panel->parent->axis; panel->axis = !panel->parent->axis;
DllQueuePush(panel->parent->first, panel->parent->last, panel); DllQueuePush(panel->parent->first, panel->parent->last, panel);
++panel->parent->count; ++panel->parent->count;
@ -867,7 +868,7 @@ void V_TickForever(WaveLaneCtx *lane)
{ {
V_Window *window = PushStruct(perm, V_Window); V_Window *window = PushStruct(perm, V_Window);
window->panel = panel; window->panel = panel;
window->key = UI_TransKey(); /* TODO: Don't use transient keys */ window->key = UI_TransKey(); // TODO: Don't use transient keys
// window->is_tile_window = 1; // window->is_tile_window = 1;
DllQueuePushNP(panel->first_window, panel->last_window, window, next_in_panel, prev_in_panel); DllQueuePushNP(panel->first_window, panel->last_window, window, next_in_panel, prev_in_panel);
++panel->windows_count; ++panel->windows_count;
@ -875,7 +876,7 @@ void V_TickForever(WaveLaneCtx *lane)
{ {
V_Window *window = PushStruct(perm, V_Window); V_Window *window = PushStruct(perm, V_Window);
window->panel = panel; window->panel = panel;
window->key = UI_TransKey(); /* TODO: Don't use transient keys */ window->key = UI_TransKey(); // TODO: Don't use transient keys
window->is_tile_window = 1; window->is_tile_window = 1;
DllQueuePushNP(panel->first_window, panel->last_window, window, next_in_panel, prev_in_panel); DllQueuePushNP(panel->first_window, panel->last_window, window, next_in_panel, prev_in_panel);
++panel->windows_count; ++panel->windows_count;
@ -899,7 +900,7 @@ void V_TickForever(WaveLaneCtx *lane)
{ {
panel_dfs->visited = 1; panel_dfs->visited = 1;
/* Push children to dfs stack */ // Push children to dfs stack
V_Panel *ratio_diff_panel = 0; V_Panel *ratio_diff_panel = 0;
for (V_Panel *child = panel->last; child; child = child->prev) for (V_Panel *child = panel->last; child; child = child->prev)
{ {
@ -912,7 +913,7 @@ void V_TickForever(WaveLaneCtx *lane)
} }
} }
/* Apply ratio diff */ // Apply ratio diff
if (ratio_diff_panel) if (ratio_diff_panel)
{ {
f32 min_ratio = 0.05; f32 min_ratio = 0.05;
@ -926,7 +927,7 @@ void V_TickForever(WaveLaneCtx *lane)
ratio_diff_panel->pref_ratio_diff = 0; ratio_diff_panel->pref_ratio_diff = 0;
} }
/* Constrain child raitos */ // Constrain child raitos
f32 ratio_accum = 0; f32 ratio_accum = 0;
for (V_Panel *child = panel->last; child; child = child->prev) for (V_Panel *child = panel->last; child; child = child->prev)
{ {
@ -1136,7 +1137,7 @@ void V_TickForever(WaveLaneCtx *lane)
UI_Report panel_rep = UI_ReportFromKey(panel->key); UI_Report panel_rep = UI_ReportFromKey(panel->key);
UI_Report parent_rep = UI_ReportFromKey(panel->parent->key); UI_Report parent_rep = UI_ReportFromKey(panel->parent->key);
/* FIXME: Height */ // FIXME: Height
f32 parent_size = 0; f32 parent_size = 0;
f32 new_size = 0; f32 new_size = 0;
if (panel->axis == Axis_X) if (panel->axis == Axis_X)
@ -1176,7 +1177,7 @@ void V_TickForever(WaveLaneCtx *lane)
{ {
V_CommandsWidgetItemDesc item_desc = Zi; V_CommandsWidgetItemDesc item_desc = Zi;
item_desc.display_name = desc.display_name; item_desc.display_name = desc.display_name;
/* FIXME: Attach active shortcuts instead of default hotkeys */ // FIXME: Attach active shortcuts instead of default hotkeys
CopyStructs(item_desc.hotkeys, desc.default_hotkeys, MinU32(countof(item_desc.hotkeys), countof(desc.default_hotkeys))); CopyStructs(item_desc.hotkeys, desc.default_hotkeys, MinU32(countof(item_desc.hotkeys), countof(desc.default_hotkeys)));
if (V_PushCommandsWidgetItem(&frame->commands_widget, item_desc).pressed > 0) if (V_PushCommandsWidgetItem(&frame->commands_widget, item_desc).pressed > 0)
{ {
@ -1267,7 +1268,7 @@ void V_TickForever(WaveLaneCtx *lane)
////////////////////////////// //////////////////////////////
//- Build console UI //- Build console UI
/* TODO: Remove this whole thing */ // TODO: Remove this whole thing
if (frame->show_console) if (frame->show_console)
{ {
b32 minimized = 0; b32 minimized = 0;
@ -1277,19 +1278,19 @@ void V_TickForever(WaveLaneCtx *lane)
Vec4 colors[LogLevel_Count][2] = Zi; Vec4 colors[LogLevel_Count][2] = Zi;
SetBytes(colors, 0xFF, sizeof(colors)); SetBytes(colors, 0xFF, sizeof(colors));
/* Debug colors */ // Debug colors
colors[LogLevel_Debug][0] = Rgb(0.4, 0.1, 0.4); colors[LogLevel_Debug][0] = Rgb(0.4, 0.1, 0.4);
colors[LogLevel_Debug][1] = Rgb(0.5, 0.2, 0.5); colors[LogLevel_Debug][1] = Rgb(0.5, 0.2, 0.5);
/* Info colors */ // Info colors
colors[LogLevel_Info][0] = Rgb(0.4, 0.4, 0.4); colors[LogLevel_Info][0] = Rgb(0.4, 0.4, 0.4);
colors[LogLevel_Info][1] = Rgb(0.5, 0.5, 0.5); colors[LogLevel_Info][1] = Rgb(0.5, 0.5, 0.5);
/* Success colors */ // Success colors
colors[LogLevel_Success][0] = Rgb(0.1, 0.3, 0.1); colors[LogLevel_Success][0] = Rgb(0.1, 0.3, 0.1);
colors[LogLevel_Success][1] = Rgb(0.2, 0.4, 0.2); colors[LogLevel_Success][1] = Rgb(0.2, 0.4, 0.2);
/* Warning colors */ // Warning colors
colors[LogLevel_Warning][0] = Rgb(0.4, 0.4, 0.1); colors[LogLevel_Warning][0] = Rgb(0.4, 0.4, 0.1);
colors[LogLevel_Warning][1] = Rgb(0.5, 0.5, 0.2); colors[LogLevel_Warning][1] = Rgb(0.5, 0.5, 0.2);
/* Error colors */ // Error colors
colors[LogLevel_Error][0] = Rgb(0.4, 0.1, 0.1); colors[LogLevel_Error][0] = Rgb(0.4, 0.1, 0.1);
colors[LogLevel_Error][1] = Rgb(0.5, 0.2, 0.2); colors[LogLevel_Error][1] = Rgb(0.5, 0.2, 0.2);
@ -1322,7 +1323,7 @@ void V_TickForever(WaveLaneCtx *lane)
UI_Key console_box = UI_BuildColumnEx(UI_KeyF("Console box")); UI_Key console_box = UI_BuildColumnEx(UI_KeyF("Console box"));
UI_PushCP(console_box); UI_PushCP(console_box);
{ {
/* Gather display logs */ // Gather display logs
u64 max = 20; u64 max = 20;
u64 display_count = 0; u64 display_count = 0;
LogEvent *display_logs = PushStructs(frame->arena, LogEvent, max); LogEvent *display_logs = PushStructs(frame->arena, LogEvent, max);
@ -1350,7 +1351,7 @@ void V_TickForever(WaveLaneCtx *lane)
} }
} }
} }
/* Display logs in reverse */ // Display logs in reverse
for (u64 i = display_count; i-- > 0;) for (u64 i = display_count; i-- > 0;)
{ {
LogEvent log = display_logs[i]; LogEvent log = display_logs[i];
@ -1535,7 +1536,7 @@ void V_TickForever(WaveLaneCtx *lane)
} }
} }
/* Push control cmd */ // Push control cmd
{ {
S_Cmd *cmd = V_PushSimCmd(S_CmdKind_Control); S_Cmd *cmd = V_PushSimCmd(S_CmdKind_Control);
cmd->target = V.player_key; cmd->target = V.player_key;
@ -1566,7 +1567,7 @@ void V_TickForever(WaveLaneCtx *lane)
////////////////////////////// //////////////////////////////
//- Build render data //- Build render data
/* Build shape buffers */ // Build shape buffers
for (S_Ent *ent = S_FirstEnt(&iter, V.world); ent->active; ent = S_NextEnt(&iter)) for (S_Ent *ent = S_FirstEnt(&iter, V.world); ent->active; ent = S_NextEnt(&iter))
{ {
Xform ent_to_world_xf = ent->xf; Xform ent_to_world_xf = ent->xf;
@ -1575,14 +1576,14 @@ void V_TickForever(WaveLaneCtx *lane)
b32 is_visible = 1; b32 is_visible = 1;
if (is_visible) if (is_visible)
{ {
/* Draw shape */ // Draw shape
{ {
Vec4 color = Color_Purple; Vec4 color = Color_Purple;
i32 detail = 32; i32 detail = 32;
S_Shape shape = S_MulXformShape(ent_to_draw_xf, ent->local_shape); S_Shape shape = S_MulXformShape(ent_to_draw_xf, ent->local_shape);
V_DrawShape(frame->dverts_arena, frame->dvert_idxs_arena, shape, LinearFromSrgb(color), detail, V_DrawFlag_Line); V_DrawShape(frame->dverts_arena, frame->dvert_idxs_arena, shape, LinearFromSrgb(color), detail, V_DrawFlag_Line);
} }
/* Draw weapon */ // Draw weapon
if (ent->has_weapon) if (ent->has_weapon)
{ {
Vec4 color = Color_Cyan; Vec4 color = Color_Cyan;
@ -1606,7 +1607,7 @@ void V_TickForever(WaveLaneCtx *lane)
////////////////////////////// //////////////////////////////
//- Push data to GPU //- Push data to GPU
/* Target */ // Target
G_ResourceHandle draw_target = G_PushTexture2D( G_ResourceHandle draw_target = G_PushTexture2D(
frame->gpu_arena, frame->cl, frame->gpu_arena, frame->cl,
G_Format_R16G16B16A16_Float, G_Format_R16G16B16A16_Float,
@ -1619,13 +1620,13 @@ void V_TickForever(WaveLaneCtx *lane)
Rng3 viewport = RNG3(VEC3(0, 0, 0), VEC3(frame->draw_dims.x, frame->draw_dims.y, 1)); Rng3 viewport = RNG3(VEC3(0, 0, 0), VEC3(frame->draw_dims.x, frame->draw_dims.y, 1));
Rng2 scissor = RNG2(VEC2(viewport.p0.x, viewport.p0.y), VEC2(viewport.p1.x, viewport.p1.y)); Rng2 scissor = RNG2(VEC2(viewport.p0.x, viewport.p0.y), VEC2(viewport.p1.x, viewport.p1.y));
/* Verts */ // Verts
G_ResourceHandle dverts_buff = G_PushBufferFromString(frame->gpu_arena, frame->cl, StringFromArena(frame->dverts_arena)); G_ResourceHandle dverts_buff = G_PushBufferFromString(frame->gpu_arena, frame->cl, StringFromArena(frame->dverts_arena));
G_ResourceHandle dvert_idxs_buff = G_PushBufferFromString(frame->gpu_arena, frame->cl, StringFromArena(frame->dvert_idxs_arena)); G_ResourceHandle dvert_idxs_buff = G_PushBufferFromString(frame->gpu_arena, frame->cl, StringFromArena(frame->dvert_idxs_arena));
G_StructuredBufferRef dverts_ro = G_PushStructuredBufferRef(frame->gpu_arena, dverts_buff, V_DVert); G_StructuredBufferRef dverts_ro = G_PushStructuredBufferRef(frame->gpu_arena, dverts_buff, V_DVert);
G_IndexBufferDesc dvert_idxs_ib = G_IdxBuff32(dvert_idxs_buff); G_IndexBufferDesc dvert_idxs_ib = G_IdxBuff32(dvert_idxs_buff);
/* Params */ // Params
V_DParams params = Zi; V_DParams params = Zi;
{ {
params.target_size = frame->draw_dims; params.target_size = frame->draw_dims;
@ -1655,10 +1656,10 @@ void V_TickForever(WaveLaneCtx *lane)
G_ResourceHandle params_buff = G_PushBufferFromString(frame->gpu_arena, frame->cl, StringFromStruct(&params)); G_ResourceHandle params_buff = G_PushBufferFromString(frame->gpu_arena, frame->cl, StringFromStruct(&params));
G_StructuredBufferRef params_ro = G_PushStructuredBufferRef(frame->gpu_arena, params_buff, V_DParams); G_StructuredBufferRef params_ro = G_PushStructuredBufferRef(frame->gpu_arena, params_buff, V_DParams);
/* Constants */ // Constants
G_SetConstant(frame->cl, V_ShaderConst_Params, params_ro); G_SetConstant(frame->cl, V_ShaderConst_Params, params_ro);
/* Sync */ // Sync
G_DumbGlobalMemorySync(frame->cl); G_DumbGlobalMemorySync(frame->cl);
////////////////////////////// //////////////////////////////

View File

@ -13,7 +13,7 @@
X(toggle_fullscreen, Toggle Fullscreen Mode, V_CmdDescFlag_None, V_HOTKEY( Button_Enter, .alt = 1 ) ) \ 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(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 ), ) \ X(spawn, Spawn, V_CmdDescFlag_None, V_HOTKEY( Button_S, .ctrl = 1 ), ) \
/* -------------------------------------------------------------------------------------------------------------------- */ // --------------------------------------------------------------------------------------------------------------------
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Theme types //~ Theme types
@ -131,10 +131,10 @@ Struct(V_CommandsWidgetItem)
Struct(V_CommandsWidget) Struct(V_CommandsWidget)
{ {
/* Persistent state */ // Persistent state
Vec2 pos; Vec2 pos;
/* Per-build state */ // Per-build state
struct struct
{ {
UI_Checkpoint cp; UI_Checkpoint cp;
@ -147,7 +147,7 @@ Struct(V_CommandsWidget)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Window types //~ Window types
/* TODO: Move boolean fields into bitwise property flags */ // TODO: Move boolean fields into bitwise property flags
Struct(V_Panel) Struct(V_Panel)
{ {
@ -215,17 +215,17 @@ Struct(V_Frame)
Vec2I32 ui_dims; Vec2I32 ui_dims;
Vec2I32 draw_dims; Vec2I32 draw_dims;
/* Modes */ // Modes
b32 is_editing; b32 is_editing;
b32 ui_debug; b32 ui_debug;
b32 show_command_palette; b32 show_command_palette;
b32 show_console; b32 show_console;
/* Editor state */ // Editor state
V_EditMode edit_mode; V_EditMode edit_mode;
S_TileKind equipped_tile; S_TileKind equipped_tile;
/* Editor */ // Editor
b32 is_selecting; b32 is_selecting;
b32 is_panning; b32 is_panning;
V_SelectionMode selection_mode; V_SelectionMode selection_mode;
@ -233,23 +233,23 @@ Struct(V_Frame)
Vec2 edit_camera_pos; Vec2 edit_camera_pos;
f32 edit_camera_zoom; f32 edit_camera_zoom;
/* Camera */ // Camera
Vec2 camera_pos; Vec2 camera_pos;
f32 camera_zoom; f32 camera_zoom;
/* World <-> ui */ // World <-> ui
Xform world_to_ui_xf; Xform world_to_ui_xf;
Xform ui_to_world_xf; Xform ui_to_world_xf;
/* Draw <-> ui */ // Draw <-> ui
Xform draw_to_ui_xf; Xform draw_to_ui_xf;
Xform ui_to_draw_xf; Xform ui_to_draw_xf;
/* World <-> draw */ // World <-> draw
Xform world_to_draw_xf; Xform world_to_draw_xf;
Xform draw_to_world_xf; Xform draw_to_world_xf;
/* Cursors */ // Cursors
Vec2 ui_cursor; Vec2 ui_cursor;
Vec2 draw_cursor; Vec2 draw_cursor;
Vec2 world_cursor; Vec2 world_cursor;
@ -257,11 +257,11 @@ Struct(V_Frame)
Rng2 draw_selection; Rng2 draw_selection;
Rng2 world_selection; Rng2 world_selection;
/* Control */ // Control
Vec2 move; Vec2 move;
Vec2 look; Vec2 look;
/* Sim cmds */ // Sim cmds
u64 sim_cmds_count; u64 sim_cmds_count;
S_CmdNode *first_sim_cmd_node; S_CmdNode *first_sim_cmd_node;
S_CmdNode *last_sim_cmd_node; S_CmdNode *last_sim_cmd_node;

View File

@ -16,7 +16,7 @@ void V_DrawPoly(Arena *verts_arena, Arena *idxs_arena, Vec2Array points, Vec4 co
i32 idx_count = lines_count * 6; i32 idx_count = lines_count * 6;
i32 idx_offset = ArenaCount(verts_arena, V_DVert); i32 idx_offset = ArenaCount(verts_arena, V_DVert);
/* Push dverts */ // Push dverts
V_DVert *dverts = PushStructsNoZero(verts_arena, V_DVert, line_verts_count); V_DVert *dverts = PushStructsNoZero(verts_arena, V_DVert, line_verts_count);
for (i32 line_idx = 0; line_idx < lines_count; ++line_idx) for (i32 line_idx = 0; line_idx < lines_count; ++line_idx)
{ {
@ -45,7 +45,7 @@ void V_DrawPoly(Arena *verts_arena, Arena *idxs_arena, Vec2Array points, Vec4 co
dverts[offset + 3] = (V_DVert) { .pos = p3, .color_lin = color_lin }; dverts[offset + 3] = (V_DVert) { .pos = p3, .color_lin = color_lin };
} }
/* Generate indices */ // Generate indices
i32 *indices = PushStructsNoZero(idxs_arena, i32, idx_count); i32 *indices = PushStructsNoZero(idxs_arena, i32, idx_count);
for (i32 line_idx = 0; line_idx < lines_count; ++line_idx) for (i32 line_idx = 0; line_idx < lines_count; ++line_idx)
{ {
@ -71,7 +71,7 @@ void V_DrawPoly(Arena *verts_arena, Arena *idxs_arena, Vec2Array points, Vec4 co
i32 tris_count = verts_count - 2; i32 tris_count = verts_count - 2;
i32 idx_count = tris_count * 3; i32 idx_count = tris_count * 3;
/* Push dverts */ // Push dverts
V_DVert *dverts = PushStructsNoZero(verts_arena, V_DVert, verts_count); V_DVert *dverts = PushStructsNoZero(verts_arena, V_DVert, verts_count);
for (i32 point_idx = 0; point_idx < (i32)points.count; ++point_idx) for (i32 point_idx = 0; point_idx < (i32)points.count; ++point_idx)
{ {
@ -80,7 +80,7 @@ void V_DrawPoly(Arena *verts_arena, Arena *idxs_arena, Vec2Array points, Vec4 co
dvert->color_lin = color_lin; dvert->color_lin = color_lin;
} }
/* Generate indices in a fan pattern */ // Generate indices in a fan pattern
i32 *indices = PushStructsNoZero(idxs_arena, i32, idx_count); i32 *indices = PushStructsNoZero(idxs_arena, i32, idx_count);
for (i32 i = 0; i < tris_count; ++i) for (i32 i = 0; i < tris_count; ++i)
{ {

View File

@ -31,7 +31,7 @@ ComputeShader2D(V_BackdropCS, 8, 8)
screen_pos.y < (bounds_screen_p1.y + half_thickness); screen_pos.y < (bounds_screen_p1.y + half_thickness);
if (is_in_bounds) if (is_in_bounds)
{ {
/* Grid checker */ // Grid checker
{ {
i32 color_idx = 0; i32 color_idx = 0;
Vec4 colors[2] = { Vec4 colors[2] = {
@ -58,7 +58,7 @@ ComputeShader2D(V_BackdropCS, 8, 8)
} }
result = colors[color_idx]; result = colors[color_idx];
} }
/* Grid outline */ // Grid outline
{ {
Vec2 grid_screen_p0 = mul(params.world_to_draw_xf, Vec3(floor(world_pos), 1)); 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)); Vec2 grid_screen_p1 = mul(params.world_to_draw_xf, Vec3(ceil(world_pos), 1));
@ -72,7 +72,7 @@ ComputeShader2D(V_BackdropCS, 8, 8)
result = grid_color; result = grid_color;
} }
} }
/* Tile */ // Tile
{ {
S_TileKind tile = (S_TileKind)tiles.Load(Vec3I32(tile_pos, 0)); S_TileKind tile = (S_TileKind)tiles.Load(Vec3I32(tile_pos, 0));
switch (tile) switch (tile)
@ -90,7 +90,7 @@ ComputeShader2D(V_BackdropCS, 8, 8)
} break; } break;
} }
} }
/* Axis */ // Axis
{ {
Vec2 zero_screen = mul(params.world_to_draw_xf, Vec3(0, 0, 1)); Vec2 zero_screen = mul(params.world_to_draw_xf, Vec3(0, 0, 1));
f32 x_dist = abs(screen_pos.x - zero_screen.x); f32 x_dist = abs(screen_pos.x - zero_screen.x);
@ -104,7 +104,7 @@ ComputeShader2D(V_BackdropCS, 8, 8)
result = y_axis_color; result = y_axis_color;
} }
} }
/* World bounds */ // World bounds
{ {
f32 bounds_dist = 100000; 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_p0.x));

View File

@ -2644,8 +2644,8 @@ JobImpl(PP_UpdateSim, UNUSED sig, UNUSED key)
} }
else else
{ {
/* We do not have the tick that the incoming delta is based from. // We do not have the tick that the incoming delta is based from.
* This decode should never have been queued in the first place. */ // This decode should never have been queued in the first place.
Assert(0); Assert(0);
} }
} }
@ -2900,16 +2900,15 @@ JobImpl(PP_UpdateSim, UNUSED sig, UNUSED key)
} }
} }
/* We want to simulate the ahead of the server to predict client input. // We want to simulate the ahead of the server to predict client input.
* How many ticks ahead we want to simulate is a balance between added latency and the server not receiving our inputs on time. // How many ticks ahead we want to simulate is a balance between added latency and the server not receiving our inputs on time.
* We can take the server's ack minus the server's tick to determine how many cmds of ours the server has buffered. // We can take the server's ack minus the server's tick to determine how many cmds of ours the server has buffered.
* //
* If this buffer gets too low (because we are lagging behind or the connection is unstable), meaning the server is not getting our input on time: // If this buffer gets too low (because we are lagging behind or the connection is unstable), meaning the server is not getting our input on time:
* - Shorten local compute rate to increase the rate at which we predict ahead & produce cmds, until the server's ack indicates a buffer size within desired range. // - Shorten local compute rate to increase the rate at which we predict ahead & produce cmds, until the server's ack indicates a buffer size within desired range.
* //
* If this buffer gets too large (because the client predicts too far ahead), meaning unneeded latency is being introduced: // If this buffer gets too large (because the client predicts too far ahead), meaning unneeded latency is being introduced:
* - Dilate local compute rate to decrease the rate at which we predict ahead & produce cmds until the server's ack indicates a buffer size within desired range. // - Dilate local compute rate to decrease the rate at which we predict ahead & produce cmds until the server's ack indicates a buffer size within desired range.
*/
{ {
i64 cmds_ahead_on_master = (i64)master_client->ack - (i64)master_client->last_tick; i64 cmds_ahead_on_master = (i64)master_client->ack - (i64)master_client->last_tick;
if (cmds_ahead_on_master < -3 || cmds_ahead_on_master > 10) if (cmds_ahead_on_master < -3 || cmds_ahead_on_master > 10)

View File

@ -254,8 +254,8 @@ Vec3 PP_AccumulatedLightFromPos(Vec2U32 pos)
//- Tone mapping //- Tone mapping
/* ACES approximation by Krzysztof Narkowicz // ACES approximation by Krzysztof Narkowicz
* https://knarkowicz.wordpress.com/2016/01/06/aces-filmic-tone-mapping-curve/ */ // https://knarkowicz.wordpress.com/2016/01/06/aces-filmic-tone-mapping-curve/
Vec3 PP_ToneMap(Vec3 v) Vec3 PP_ToneMap(Vec3 v)
{ {
return saturate((v * (2.51f * v + 0.03f)) / (v * (2.43f * v + 0.59f) + 0.14f)); return saturate((v * (2.51f * v + 0.03f)) / (v * (2.43f * v + 0.59f) + 0.14f));

View File

@ -130,9 +130,10 @@ void PP_ReleaseAllWithProp(PP_Snapshot *ss, PP_Prop prop)
} }
} }
/* Release from snapshot */ // Release from snapshot
/* TODO: Breadth first iteration to only release parent entities (since //
* child entities will be released along with parent anyway) */ // TODO: Breadth first iteration to only release parent entities (since
// child entities will be released along with parent anyway)
for (u64 i = 0; i < ents_to_release_count; ++i) for (u64 i = 0; i < ents_to_release_count; ++i)
{ {
PP_Ent *ent = ents_to_release[i]; PP_Ent *ent = ents_to_release[i];

View File

@ -132,7 +132,7 @@ void PP_CreateAndUpdateContacts(PP_PhysStepCtx *ctx, f32 elapsed_dt, u64 phys_it
} }
if (!found) if (!found)
{ {
/* Delete contact by replacing with last in array */ // Delete contact by replacing with last in array
*old = constraint->points[--constraint->num_points]; *old = constraint->points[--constraint->num_points];
--i; --i;
} }

View File

@ -35,14 +35,13 @@ Struct(PP_PhysStepCtx)
Struct(PP_ContactPoint) Struct(PP_ContactPoint)
{ {
/* Contact point relative to the center of each entity. // Contact point relative to the center of each entity.
* //
* NOTE: We use fixed (non-rotated) points relative to the entities // NOTE: We use fixed (non-rotated) points relative to the entities
* rather than points fully in local space because contact manifolds // rather than points fully in local space because contact manifolds
* shouldn't really be affected by rotation accross substeps // shouldn't really be affected by rotation accross substeps
* (imagine re-building the manifold of a rotated shape, it would still be // (imagine re-building the manifold of a rotated shape, it would still be
* on the same side of the shape that it originally occured on) // on the same side of the shape that it originally occured on)
*/
Vec2 vcp0; Vec2 vcp0;
Vec2 vcp1; Vec2 vcp1;
@ -176,8 +175,8 @@ Struct(PP_WeldJointDesc)
PP_EntKey e0; PP_EntKey e0;
PP_EntKey e1; PP_EntKey e1;
/* The xform that transforms a point in e0's space into the desired e1 space // The xform that transforms a point in e0's space into the desired e1 space
* (IE `xf` * VEC2(0, 0) should evaluate to the local point that e1's origin will lie) */ // (IE `xf` * VEC2(0, 0) should evaluate to the local point that e1's origin will lie)
Xform xf; Xform xf;
f32 linear_spring_hz; f32 linear_spring_hz;

View File

@ -1,28 +1,29 @@
/* Sim hierarchy is as follows: //
* // Sim hierarchy is as follows:
* PP_Client store -> clients -> snapshots -> ents //
* // PP_Client store -> clients -> snapshots -> ents
* A client store holds clients, which can be retrieved by client key or by a host channel id (if one is assigned). //
* // A client store holds clients, which can be retrieved by client key or by a host channel id (if one is assigned).
* A client holds snapshots, which can be retrieved by tick number. //
* - The snapshots stored in clients & the contents of those snapshots are determined from data transmitted by the client. // A client holds snapshots, which can be retrieved by tick number.
* - Different kinds of clients will transmit different subsets of snapshot data (e.g. a master client will transmit most ent state, while slave clients may just transmit 1 or more command ents) // - The snapshots stored in clients & the contents of those snapshots are determined from data transmitted by the client.
* - A client will never hold more than one snapshot for the same tick (e.g. a client will never have 2 snapshots at tick 5) // - Different kinds of clients will transmit different subsets of snapshot data (e.g. a master client will transmit most ent state, while slave clients may just transmit 1 or more command ents)
* // - A client will never hold more than one snapshot for the same tick (e.g. a client will never have 2 snapshots at tick 5)
* A snapshot holds the ent tree for a particular tick, in which ents can be retrieved by ent key. //
* - A tick is the quantized time step that all clients implicitly conform to. // A snapshot holds the ent tree for a particular tick, in which ents can be retrieved by ent key.
* // - A tick is the quantized time step that all clients implicitly conform to.
* An ent is the smallest unit of simulation state. //
* - It is assigned a 128 bit unique identifer generated at allocation time. // An ent is the smallest unit of simulation state.
* - This key is used to refer to other ents in the tree and to sync ents accross clients. // - It is assigned a 128 bit unique identifer generated at allocation time.
* - This key is usually random, but can be deterministic under certain conditions. // - This key is used to refer to other ents in the tree and to sync ents accross clients.
* - For example, instead of storing a contact constraint lookup table, contact constraints are // - This key is usually random, but can be deterministic under certain conditions.
* retrieved by searching for the ent with the key resulting from combining the ent keys of the // - For example, instead of storing a contact constraint lookup table, contact constraints are
* two contacting entities (plus a unique 'basis' ent key used for all contact constraints). // retrieved by searching for the ent with the key resulting from combining the ent keys of the
* - The ent also implicitly has a 32 bit index, which is just its offset from the start of the entity array in the local snapshot. // two contacting entities (plus a unique 'basis' ent key used for all contact constraints).
* - Since index is based on offset which remains stable regardless of snapshot memory location, it // - The ent also implicitly has a 32 bit index, which is just its offset from the start of the entity array in the local snapshot.
* is used when working in contexts where key is irrelevant. // - Since index is based on offset which remains stable regardless of snapshot memory location, it
*/ // is used when working in contexts where key is irrelevant.
//
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Startup //~ Startup
@ -687,8 +688,8 @@ PP_Snapshot *PP_AcquireSnapshotFromLerp(PP_Client *client, PP_Snapshot *ss0, PP_
if (!ss0->valid || !ss1->valid) if (!ss0->valid || !ss1->valid)
{ {
/* New snapshot allocation caused one of the src snapshots original to release. // New snapshot allocation caused one of the src snapshots original to release.
* ss0 & ss1 should be from a separate client than the allocating one. */ // ss0 & ss1 should be from a separate client than the allocating one.
Assert(0); Assert(0);
} }
@ -723,10 +724,9 @@ void PP_SyncSnapshotEnts(PP_Snapshot *local_ss, PP_Snapshot *remote_ss, PP_EntKe
{ {
__prof; __prof;
/* FIXME: Don't trust non-master clients: // FIXME: Don't trust non-master clients:
* - Only sync cmd ents // - Only sync cmd ents
* - Determine new UUids for newly created ents // - Determine new UUids for newly created ents
*/
PP_Ent *local_root = PP_EntFromKey(local_ss, PP_RootEntKey); PP_Ent *local_root = PP_EntFromKey(local_ss, PP_RootEntKey);
PP_Ent *remote_root = PP_EntFromKey(remote_ss, PP_RootEntKey); PP_Ent *remote_root = PP_EntFromKey(remote_ss, PP_RootEntKey);

View File

@ -80,9 +80,9 @@ Struct(PP_Client)
/* This is the highest confirmed tick of ours that we know this client has received */ /* This is the highest confirmed tick of ours that we know this client has received */
u64 ack; u64 ack;
/* This is the highest confirmed ack of ours that we know this client has received (this // This is the highest confirmed ack of ours that we know this client has received (this
* can be used to determine which client ticks will no longer be delta encoded from and // can be used to determine which client ticks will no longer be delta encoded from and
* therefore can be released) */ // therefore can be released)
u64 double_ack; u64 double_ack;
/* This is the highest tick of their's that we have received */ /* This is the highest tick of their's that we have received */

View File

@ -7,9 +7,9 @@ Readonly PP_Space PP_nil_space = ZI;
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Space //~ Space
/* NOTE: // NOTE:
* The number of bins determines how often tiles will collide in the spatial hash. // The number of bins determines how often tiles will collide in the spatial hash.
* For example, at `num_bins_sqrt` = 256 (65536 bins), tiles <1, 1>, <1, 257>, and <257, 257> will collide. */ // For example, at `num_bins_sqrt` = 256 (65536 bins), tiles <1, 1>, <1, 257>, and <257, 257> will collide. */
PP_Space *PP_AcquireSpace(f32 cell_size, u32 num_bins_sqrt) PP_Space *PP_AcquireSpace(f32 cell_size, u32 num_bins_sqrt)
{ {
PP_Space *space; PP_Space *space;

View File

@ -24,8 +24,8 @@ Struct(PP_SpaceEntry)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Space cell types //~ Space cell types
/* Links a cell to a entry. // Links a cell to a entry.
* Acts as both a node in the list of entries contained by the cell, and a node in the list of cells containing the entry. */ // Acts as both a node in the list of entries contained by the cell, and a node in the list of cells containing the entry. */
Struct(PP_SpaceCellNode) Struct(PP_SpaceCellNode)
{ {
PP_SpaceEntry *entry; PP_SpaceEntry *entry;

View File

@ -441,9 +441,10 @@ void PP_GenerateTestWalls(PP_Snapshot *world)
TempArena scratch = BeginScratchNoConflict(); TempArena scratch = BeginScratchNoConflict();
PP_Ent *root = PP_EntFromKey(world, PP_RootEntKey); PP_Ent *root = PP_EntFromKey(world, PP_RootEntKey);
/* Release existing walls and gather tile chunks. // Release existing walls and gather tile chunks.
* NOTE: We sort tile chunks before iterating so that chunk-edge tiles only //
* need to check for adjacent walls to merge with in one direction */ // NOTE: We sort tile chunks before iterating so that chunk-edge tiles only
// need to check for adjacent walls to merge with in one direction
PP_Ent **x_sorted_tile_chunks = 0; PP_Ent **x_sorted_tile_chunks = 0;
PP_Ent **y_sorted_tile_chunks = 0; PP_Ent **y_sorted_tile_chunks = 0;
u64 sorted_tile_chunks_count = 0; u64 sorted_tile_chunks_count = 0;
@ -455,7 +456,7 @@ void PP_GenerateTestWalls(PP_Snapshot *world)
if (!ent->valid) continue; if (!ent->valid) continue;
if (PP_HasProp(ent, PP_Prop_TileChunk)) if (PP_HasProp(ent, PP_Prop_TileChunk))
{ {
/* Append chunk to array */ // Append chunk to array
*PushStructNoZero(scratch.arena, PP_Ent *) = ent; *PushStructNoZero(scratch.arena, PP_Ent *) = ent;
++sorted_tile_chunks_count; ++sorted_tile_chunks_count;
} }
@ -468,8 +469,8 @@ void PP_GenerateTestWalls(PP_Snapshot *world)
y_sorted_tile_chunks = PushStructsNoZero(scratch.arena, PP_Ent *, sorted_tile_chunks_count); y_sorted_tile_chunks = PushStructsNoZero(scratch.arena, PP_Ent *, sorted_tile_chunks_count);
CopyBytes(y_sorted_tile_chunks, x_sorted_tile_chunks, sizeof(*x_sorted_tile_chunks) * sorted_tile_chunks_count); CopyBytes(y_sorted_tile_chunks, x_sorted_tile_chunks, sizeof(*x_sorted_tile_chunks) * sorted_tile_chunks_count);
/* NOTE: We sort x & y separately because it's possible that a wall // NOTE: We sort x & y separately because it's possible that a wall
* should merge with another wall that was generated from a diagonal chunk. */ // should merge with another wall that was generated from a diagonal chunk.
Mergesort(x_sorted_tile_chunks, sorted_tile_chunks_count, sizeof(*x_sorted_tile_chunks), PP_SortTileXCmp, 0); Mergesort(x_sorted_tile_chunks, sorted_tile_chunks_count, sizeof(*x_sorted_tile_chunks), PP_SortTileXCmp, 0);
Mergesort(y_sorted_tile_chunks, sorted_tile_chunks_count, sizeof(*y_sorted_tile_chunks), PP_SortTileYCmp, 0); Mergesort(y_sorted_tile_chunks, sorted_tile_chunks_count, sizeof(*y_sorted_tile_chunks), PP_SortTileYCmp, 0);
} }
@ -482,8 +483,8 @@ void PP_GenerateTestWalls(PP_Snapshot *world)
struct wall_node *next; struct wall_node *next;
}; };
/* Dicts containing walls that end on edge of tile chunk, keyed by tile end index. // Dicts containing walls that end on edge of tile chunk, keyed by tile end index.
* Used to merge walls accross tile chunks. */ // Used to merge walls accross tile chunks.
Dict *horizontal_ends_dict = InitDict(scratch.arena, 1024); Dict *horizontal_ends_dict = InitDict(scratch.arena, 1024);
Dict *vertical_ends_dict = InitDict(scratch.arena, 1024); Dict *vertical_ends_dict = InitDict(scratch.arena, 1024);

View File

@ -18,7 +18,7 @@ void PT_RunForever(WaveLaneCtx *lane)
{ {
G_CommandListHandle cl = G_PrepareCommandList(G_QueueKind_Direct); G_CommandListHandle cl = G_PrepareCommandList(G_QueueKind_Direct);
{ {
/* Push resources */ // Push resources
Vec2I32 final_target_size = window_frame.draw_size; Vec2I32 final_target_size = window_frame.draw_size;
G_ResourceHandle final_target = G_PushTexture2D( G_ResourceHandle final_target = G_PushTexture2D(
gpu_frame_arena, gpu_frame_arena,
@ -28,11 +28,11 @@ void PT_RunForever(WaveLaneCtx *lane)
.flags = G_ResourceFlag_AllowShaderReadWrite .flags = G_ResourceFlag_AllowShaderReadWrite
); );
/* Push resource handles */ // Push resource handles
G_Texture2DRef final_target_rhandle = G_PushTexture2DRef(gpu_frame_arena, final_target); G_Texture2DRef final_target_rhandle = G_PushTexture2DRef(gpu_frame_arena, final_target);
G_RWTexture2DRef final_target_rwhandle = G_PushRWTexture2DRef(gpu_frame_arena, final_target); G_RWTexture2DRef final_target_rwhandle = G_PushRWTexture2DRef(gpu_frame_arena, final_target);
/* Prep test pass */ // Prep test pass
{ {
G_SetConstant(cl, PT_ShaderConst_TestTarget, final_target_rwhandle); G_SetConstant(cl, PT_ShaderConst_TestTarget, final_target_rwhandle);
G_SetConstant(cl, PT_ShaderConst_TestConst, 3.123); G_SetConstant(cl, PT_ShaderConst_TestConst, 3.123);
@ -41,19 +41,19 @@ void PT_RunForever(WaveLaneCtx *lane)
G_SetConstant(cl, PT_ShaderConst_NoiseTex, G_BasicNoiseTexture()); G_SetConstant(cl, PT_ShaderConst_NoiseTex, G_BasicNoiseTexture());
} }
/* Test pass */ // Test pass
{ {
G_Compute(cl, PT_TestCS, VEC3I32((final_target_size.x + 7) / 8, (final_target_size.y + 7) / 8, 1)); G_Compute(cl, PT_TestCS, VEC3I32((final_target_size.x + 7) / 8, (final_target_size.y + 7) / 8, 1));
} }
G_DumbMemorySync(cl, final_target); G_DumbMemorySync(cl, final_target);
/* Prep blit pass */ // Prep blit pass
{ {
G_DumbMemoryLayoutSync(cl, final_target, G_Layout_DirectQueue_ShaderRead); G_DumbMemoryLayoutSync(cl, final_target, G_Layout_DirectQueue_ShaderRead);
G_DumbMemoryLayoutSync(cl, window_frame.backbuffer, G_Layout_DirectQueue_RenderTargetWrite); G_DumbMemoryLayoutSync(cl, window_frame.backbuffer, G_Layout_DirectQueue_RenderTargetWrite);
} }
/* Blit pass */ // Blit pass
{ {
G_Rasterize( G_Rasterize(
cl, cl,
@ -65,12 +65,12 @@ void PT_RunForever(WaveLaneCtx *lane)
); );
} }
/* Finalize backbuffer layout */ // Finalize backbuffer layout
{ {
G_DumbMemoryLayoutSync(cl, window_frame.backbuffer, G_Layout_AnyQueue_ShaderRead_CopyRead_CopyWrite_Present); G_DumbMemoryLayoutSync(cl, window_frame.backbuffer, G_Layout_AnyQueue_ShaderRead_CopyRead_CopyWrite_Present);
} }
/* Reset */ // Reset
{ {
G_ResetArena(cl, gpu_frame_arena); G_ResetArena(cl, gpu_frame_arena);
} }

View File

@ -3,11 +3,11 @@
G_DeclConstant(G_Texture3DRef, PT_ShaderConst_NoiseTex, 0); G_DeclConstant(G_Texture3DRef, PT_ShaderConst_NoiseTex, 0);
/* Test shader */ // Test shader
G_DeclConstant(G_RWTexture2DRef, PT_ShaderConst_TestTarget, 1); G_DeclConstant(G_RWTexture2DRef, PT_ShaderConst_TestTarget, 1);
G_DeclConstant(G_StructuredBufferRef, PT_ShaderConst_TestBuff, 2); G_DeclConstant(G_StructuredBufferRef, PT_ShaderConst_TestBuff, 2);
G_DeclConstant(f32, PT_ShaderConst_TestConst, 3); G_DeclConstant(f32, PT_ShaderConst_TestConst, 3);
/* Blit shader */ // Blit shader
G_DeclConstant(G_SamplerStateRef, PT_ShaderConst_BlitSampler, 4); G_DeclConstant(G_SamplerStateRef, PT_ShaderConst_BlitSampler, 4);
G_DeclConstant(G_Texture2DRef, PT_ShaderConst_BlitSrc, 5); G_DeclConstant(G_Texture2DRef, PT_ShaderConst_BlitSrc, 5);

View File

@ -14,7 +14,7 @@ JobImpl(SND_Load, sig, id)
String error_msg = Lit("Unknown error"); String error_msg = Lit("Unknown error");
/* Decode */ // Decode
MP3_Result decoded = ZI; MP3_Result decoded = ZI;
String resource_data = DataFromResource(resource); String resource_data = DataFromResource(resource);
if (resource_data.len > 0) if (resource_data.len > 0)
@ -37,7 +37,7 @@ JobImpl(SND_Load, sig, id)
if (decoded.ok) if (decoded.ok)
{ {
/* Store */ // Store
SND_Sound *sound = 0; SND_Sound *sound = 0;
u64 samples_count = decoded.samples_count; u64 samples_count = decoded.samples_count;
i16 *samples = 0; i16 *samples = 0;
@ -48,7 +48,7 @@ JobImpl(SND_Load, sig, id)
AC_CloseStore(&store); AC_CloseStore(&store);
} }
/* Initialize */ // Initialize
ZeroStruct(sound); ZeroStruct(sound);
sound->flags = flags; sound->flags = flags;
sound->samples_count = samples_count; sound->samples_count = samples_count;
@ -62,7 +62,7 @@ JobImpl(SND_Load, sig, id)
{ {
LogErrorF("Error loading sound \"%F\": %F", FmtString(name), FmtString(error_msg)); LogErrorF("Error loading sound \"%F\": %F", FmtString(name), FmtString(error_msg));
/* Store */ // Store
SND_Sound *sound = 0; SND_Sound *sound = 0;
{ {
AC_Store store = AC_OpenStore(); AC_Store store = AC_OpenStore();
@ -83,7 +83,7 @@ AC_Asset *SND_LoadAsset(ResourceKey resource, SND_SoundFlag flags, b32 wait)
{ {
TempArena scratch = BeginScratchNoConflict(); TempArena scratch = BeginScratchNoConflict();
/* Generate and append sound flags to name key */ // Generate and append sound flags to name key
String name = NameFromResource(resource); String name = NameFromResource(resource);
String key = StringF( String key = StringF(
scratch.arena, scratch.arena,

View File

@ -20,7 +20,7 @@ JobImpl(SPR_LoadTexture, sig, _)
ASE_DecodedImage decoded = ASE_DecodeImage(scratch.arena, data); ASE_DecodedImage decoded = ASE_DecodeImage(scratch.arena, data);
ok = decoded.ok; ok = decoded.ok;
/* Upload texture to gpu */ // Upload texture to gpu
if (ok) if (ok)
{ {
GPU_ArenaHandle gpu_perm = GPU_PermArena(); GPU_ArenaHandle gpu_perm = GPU_PermArena();
@ -74,7 +74,7 @@ JobImpl(SPR_LoadSheet, sig, _)
sheet->image_size = image_size; sheet->image_size = image_size;
sheet->frame_size = frame_size; sheet->frame_size = frame_size;
/* Init frames */ // Init frames
sheet->frames_count = decoded.num_frames; sheet->frames_count = decoded.num_frames;
sheet->frames = PushStructs(perm, SPR_Frame, sheet->frames_count); sheet->frames = PushStructs(perm, SPR_Frame, sheet->frames_count);
for (ASE_Frame *src = decoded.first_frame; src; src = src->next) for (ASE_Frame *src = decoded.first_frame; src; src = src->next)
@ -86,7 +86,7 @@ JobImpl(SPR_LoadSheet, sig, _)
dst->clip.p1 = VEC2((f32)src->rect.p1.x / (f32)image_size.x, (f32)src->rect.p1.y / (f32)image_size.y); dst->clip.p1 = VEC2((f32)src->rect.p1.x / (f32)image_size.x, (f32)src->rect.p1.y / (f32)image_size.y);
} }
/* Init spans */ // Init spans
sheet->spans_count = decoded.num_spans; sheet->spans_count = decoded.num_spans;
sheet->span_bins_count = MaxU32(AlignU64ToNextPow2(sheet->spans_count * 2), 1); sheet->span_bins_count = MaxU32(AlignU64ToNextPow2(sheet->spans_count * 2), 1);
sheet->spans = PushStructs(perm, SPR_Span, sheet->spans_count); sheet->spans = PushStructs(perm, SPR_Span, sheet->spans_count);
@ -100,7 +100,7 @@ JobImpl(SPR_LoadSheet, sig, _)
dst->name = PushString(perm, src->name); dst->name = PushString(perm, src->name);
dst->start = src->start; dst->start = src->start;
dst->end = src->end; dst->end = src->end;
/* Insert span into bin */ // Insert span into bin
{ {
SPR_SpanBin *bin = &sheet->span_bins[dst->hash % sheet->span_bins_count]; SPR_SpanBin *bin = &sheet->span_bins[dst->hash % sheet->span_bins_count];
SllQueuePushN(bin->first, bin->last, dst, next_in_bin); SllQueuePushN(bin->first, bin->last, dst, next_in_bin);
@ -109,7 +109,7 @@ JobImpl(SPR_LoadSheet, sig, _)
} }
} }
/* Init slice groups */ // Init slice groups
sheet->slice_groups_count = decoded.num_slice_keys; sheet->slice_groups_count = decoded.num_slice_keys;
sheet->slice_group_bins_count = MaxU32(AlignU64ToNextPow2(sheet->slice_groups_count * 2), 1); sheet->slice_group_bins_count = MaxU32(AlignU64ToNextPow2(sheet->slice_groups_count * 2), 1);
sheet->slice_groups = PushStructs(perm, SPR_SliceGroup, sheet->slice_groups_count); sheet->slice_groups = PushStructs(perm, SPR_SliceGroup, sheet->slice_groups_count);
@ -122,10 +122,10 @@ JobImpl(SPR_LoadSheet, sig, _)
dst_group->hash = HashFnv64(Fnv64Basis, src_group->name); dst_group->hash = HashFnv64(Fnv64Basis, src_group->name);
dst_group->name = PushString(perm, src_group->name); dst_group->name = PushString(perm, src_group->name);
/* Init slices */ // Init slices
dst_group->slices = PushStructs(perm, SPR_Slice, sheet->frames_count); dst_group->slices = PushStructs(perm, SPR_Slice, sheet->frames_count);
{ {
/* Fill is_original slices */ // Fill is_original slices
for (ASE_Slice *src_slice = src_group->first_slice; src_slice; src_slice = src_slice->next) for (ASE_Slice *src_slice = src_group->first_slice; src_slice; src_slice = src_slice->next)
{ {
f32 x0_px = src_slice->rect.p0.x; f32 x0_px = src_slice->rect.p0.x;
@ -142,15 +142,15 @@ JobImpl(SPR_LoadSheet, sig, _)
f32 width = x1 - x0; f32 width = x1 - x0;
f32 height = y1 - y0; f32 height = y1 - y0;
/* Rect */ // Rect
Rng2 rect_px = RNG2(VEC2(x0_px, y0_px), VEC2(x1_px, y1_px)); Rng2 rect_px = RNG2(VEC2(x0_px, y0_px), VEC2(x1_px, y1_px));
Rng2 rect = RNG2(VEC2(x0, y0), VEC2(x1, y1)); Rng2 rect = RNG2(VEC2(x0, y0), VEC2(x1, y1));
/* Center */ // Center
Vec2 center_px = VEC2(x0_px + (width_px * 0.5f), y0_px + (height_px * 0.5f)); Vec2 center_px = VEC2(x0_px + (width_px * 0.5f), y0_px + (height_px * 0.5f));
Vec2 center = VEC2(x0 + (width * 0.5f), y0 + (height * 0.5f)); Vec2 center = VEC2(x0 + (width * 0.5f), y0 + (height * 0.5f));
/* Dir */ // Dir
Vec2 dir_px = VEC2(center_px.x, -1); Vec2 dir_px = VEC2(center_px.x, -1);
Vec2 dir = VEC2(0, -1); Vec2 dir = VEC2(0, -1);
@ -164,7 +164,7 @@ JobImpl(SPR_LoadSheet, sig, _)
dst_slice->dir = dir; dst_slice->dir = dir;
} }
/* Copy slices forward into frames without a slice */ // Copy slices forward into frames without a slice
{ {
SPR_Slice *origin = 0; SPR_Slice *origin = 0;
for (u32 frame_index = 0; frame_index < sheet->frames_count; ++frame_index) for (u32 frame_index = 0; frame_index < sheet->frames_count; ++frame_index)
@ -183,7 +183,7 @@ JobImpl(SPR_LoadSheet, sig, _)
} }
} }
/* Insert group into bin */ // Insert group into bin
{ {
SPR_SliceGroupBin *bin = &sheet->slice_group_bins[dst_group->hash % sheet->slice_group_bins_count]; SPR_SliceGroupBin *bin = &sheet->slice_group_bins[dst_group->hash % sheet->slice_group_bins_count];
SllQueuePushN(bin->first, bin->last, dst_group, next_in_bin); SllQueuePushN(bin->first, bin->last, dst_group, next_in_bin);
@ -192,7 +192,7 @@ JobImpl(SPR_LoadSheet, sig, _)
} }
} }
/* Init slice ray directions */ // Init slice ray directions
{ {
String ray_suffix = Lit(".ray"); String ray_suffix = Lit(".ray");
for (u32 slice_group_index = 0; slice_group_index < sheet->slice_groups_count; ++slice_group_index) for (u32 slice_group_index = 0; slice_group_index < sheet->slice_groups_count; ++slice_group_index)
@ -237,14 +237,14 @@ JobImpl(SPR_LoadSheet, sig, _)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Cache //~ Cache
/* TODO: Per-thread L1 cache */ // TODO: Per-thread L1 cache
SPR_Entry *SPR_FetchEntry(ResourceKey resource, JobPoolId pool, SPR_FetchFlag flags) SPR_Entry *SPR_FetchEntry(ResourceKey resource, JobPoolId pool, SPR_FetchFlag flags)
{ {
SPR_SharedState *g = &SPR_shared_state; SPR_SharedState *g = &SPR_shared_state;
SPR_Entry *entry = 0; SPR_Entry *entry = 0;
{ {
SPR_EntryBin *bin = &g->entry_bins[resource.hash % SPR_EntryBinsCount]; SPR_EntryBin *bin = &g->entry_bins[resource.hash % SPR_EntryBinsCount];
/* Search for entry */ // Search for entry
entry = bin->first; entry = bin->first;
{ {
Lock lock = LockS(&bin->mutex); Lock lock = LockS(&bin->mutex);
@ -259,12 +259,12 @@ SPR_Entry *SPR_FetchEntry(ResourceKey resource, JobPoolId pool, SPR_FetchFlag fl
} }
Unlock(&lock); Unlock(&lock);
} }
/* Entry not found: lock, re-search, & create */ // Entry not found: lock, re-search, & create
if (!entry) if (!entry)
{ {
Lock lock = LockE(&bin->mutex); Lock lock = LockE(&bin->mutex);
{ {
/* Re-search */ // Re-search
entry = bin->first; entry = bin->first;
for (; entry; entry = entry->next_in_bin) for (; entry; entry = entry->next_in_bin)
{ {
@ -273,7 +273,7 @@ SPR_Entry *SPR_FetchEntry(ResourceKey resource, JobPoolId pool, SPR_FetchFlag fl
break; break;
} }
} }
/* Create */ // Create
if (!entry) if (!entry)
{ {
Arena *perm = PermArena(); Arena *perm = PermArena();
@ -285,7 +285,7 @@ SPR_Entry *SPR_FetchEntry(ResourceKey resource, JobPoolId pool, SPR_FetchFlag fl
Unlock(&lock); Unlock(&lock);
} }
} }
/* Launch load jobs */ // Launch load jobs
if ((flags & SPR_FetchFlag_Texture) if ((flags & SPR_FetchFlag_Texture)
&& !Atomic32Fetch(&entry->texture_touched) && !Atomic32Fetch(&entry->texture_touched)
&& !Atomic32FetchTestSet(&entry->texture_touched, 0, 1)) && !Atomic32FetchTestSet(&entry->texture_touched, 0, 1))
@ -412,13 +412,13 @@ SPR_Slice SPR_SliceFromKey(SPR_Sheet *sheet, SPR_SliceKey key, u64 frame_index)
} }
} }
/* Return 'pivot' by default */ // Return 'pivot' by default
if (!match) if (!match)
{ {
SPR_SliceKey pivot_key = SPR_SliceKeyFromName(Lit("pivot")); SPR_SliceKey pivot_key = SPR_SliceKeyFromName(Lit("pivot"));
if (key.hash == pivot_key.hash) if (key.hash == pivot_key.hash)
{ {
/* 'pivot' slice does not exist, return center */ // 'pivot' slice does not exist, return center
result.center = VEC2(0, 0); result.center = VEC2(0, 0);
result.center_px = MulVec2(sheet->frame_size, 0.5f); result.center_px = MulVec2(sheet->frame_size, 0.5f);
result.dir_px = VEC2(result.center_px.x, 0); result.dir_px = VEC2(result.center_px.x, 0);

View File

@ -51,18 +51,18 @@ Struct(SPR_SpanBin)
Struct(SPR_Slice) Struct(SPR_Slice)
{ {
/* If 1, this slice was not copied over from another frame in the sprite sheet */ // If 1, this slice was not copied over from another frame in the sprite sheet
b32 is_original; b32 is_original;
/* If 1, the slice has a corresponding '.ray' slice affecting the 'dir' fields */ // If 1, the slice has a corresponding '.ray' slice affecting the 'dir' fields
b32 has_dir; b32 has_dir;
/* Values are in the range -0.5 (top / left edge) -> +0.5 (bottom / right edge) */ // Values are in the range -0.5 (top / left edge) -> +0.5 (bottom / right edge)
Rng2 rect; Rng2 rect;
Vec2 center; Vec2 center;
Vec2 dir; Vec2 dir;
/* '_px' values retain the original sprite pixel dimensions */ // '_px' values retain the original sprite pixel dimensions
Rng2 rect_px; Rng2 rect_px;
Vec2 center_px; Vec2 center_px;
Vec2 dir_px; Vec2 dir_px;

View File

@ -11,11 +11,10 @@ u64 TAR_U64FromOctString(String str)
return n; return n;
} }
/* `prefix` will be prepended to all file names in the archive // `prefix` will be prepended to all file names in the archive
* //
* NOTE: The resulting archive merely points into the supplied tar data, no // NOTE: The resulting archive merely points into the supplied tar data, no
* copying is done. Accessing the archive assumes that the data string is still valid. // copying is done. Accessing the archive assumes that the data string is still valid.
*/
TAR_Archive TAR_ArchiveFromString(Arena *arena, String data, String prefix) TAR_Archive TAR_ArchiveFromString(Arena *arena, String data, String prefix)
{ {
TAR_Archive archive = ZI; TAR_Archive archive = ZI;
@ -31,14 +30,14 @@ TAR_Archive TAR_ArchiveFromString(Arena *arena, String data, String prefix)
if (!MatchString(StringFromFixedArray(header.ustar_indicator), Lit("ustar\0"))) if (!MatchString(StringFromFixedArray(header.ustar_indicator), Lit("ustar\0")))
{ {
/* Invalid header */ // Invalid header
Assert(0); Assert(0);
continue; continue;
} }
if (header.file_name_prefix[0] != 0) if (header.file_name_prefix[0] != 0)
{ {
/* Header file name prefix not supported */ // Header file name prefix not supported
Assert(0); Assert(0);
continue; continue;
} }
@ -53,14 +52,14 @@ TAR_Archive TAR_ArchiveFromString(Arena *arena, String data, String prefix)
} }
String file_data = STRING(file_size, file_data_ptr); String file_data = STRING(file_size, file_data_ptr);
/* Skip sector padding */ // Skip sector padding
u64 remaining = (512 - (file_size % 512)) % 512; u64 remaining = (512 - (file_size % 512)) % 512;
BB_SeekBytes(&br, remaining); BB_SeekBytes(&br, remaining);
b32 is_dir = header.file_type == TAR_FileKind_Directory; b32 is_dir = header.file_type == TAR_FileKind_Directory;
if (!is_dir && header.file_type != TAR_FileKind_File) if (!is_dir && header.file_type != TAR_FileKind_File)
{ {
/* Unsupported type */ // Unsupported type
Assert(header.file_type == TAR_FileKind_PaxHeaderX || header.file_type == TAR_FileKind_PaxHeaderG); Assert(header.file_type == TAR_FileKind_PaxHeaderX || header.file_type == TAR_FileKind_PaxHeaderG);
continue; continue;
} }
@ -68,7 +67,7 @@ TAR_Archive TAR_ArchiveFromString(Arena *arena, String data, String prefix)
String file_name_cstr = StringFromCstrNoLimit((char *)header.file_name); String file_name_cstr = StringFromCstrNoLimit((char *)header.file_name);
if (file_name_cstr.len >= 2) if (file_name_cstr.len >= 2)
{ {
/* Chop off './' prefix */ // Chop off './' prefix
file_name_cstr.len -= 2; file_name_cstr.len -= 2;
file_name_cstr.text += 2; file_name_cstr.text += 2;
} }
@ -85,7 +84,7 @@ TAR_Archive TAR_ArchiveFromString(Arena *arena, String data, String prefix)
++num_files; ++num_files;
} }
/* Build lookup table */ // Build lookup table
archive.lookup = InitDict(arena, (u64)((f64)num_files * TAR_ArchiveLookupTableCapacityFactor)); archive.lookup = InitDict(arena, (u64)((f64)num_files * TAR_ArchiveLookupTableCapacityFactor));
for (TAR_Entry *entry = archive.head; entry; entry = entry->next) for (TAR_Entry *entry = archive.head; entry; entry = entry->next)
{ {
@ -93,15 +92,16 @@ TAR_Archive TAR_ArchiveFromString(Arena *arena, String data, String prefix)
SetDictValue(arena, archive.lookup, hash, (u64)entry); SetDictValue(arena, archive.lookup, hash, (u64)entry);
} }
/* Build hierarchy */ // Build hierarchy
/* NOTE: This is a separate pass because tar entry order is not guaranteed //
* (IE file entries may be encountered before their parent directory entry) */ // NOTE: This is a separate pass because tar entry order is not guaranteed
// (IE file entries may be encountered before their parent directory entry)
for (TAR_Entry *entry = archive.head; entry; entry = entry->next) for (TAR_Entry *entry = archive.head; entry; entry = entry->next)
{ {
/* Enter into hierarchy */ // Enter into hierarchy
if (!entry->is_dir) if (!entry->is_dir)
{ {
/* Find parent entry */ // Find parent entry
TAR_Entry *parent_entry = 0; TAR_Entry *parent_entry = 0;
for (String parent_dir_name = entry->file_name; parent_dir_name.len > 0; --parent_dir_name.len) for (String parent_dir_name = entry->file_name; parent_dir_name.len > 0; --parent_dir_name.len)
{ {
@ -112,7 +112,7 @@ TAR_Archive TAR_ArchiveFromString(Arena *arena, String data, String prefix)
break; break;
} }
} }
/* Insert child into parent's list */ // Insert child into parent's list
if (parent_entry) if (parent_entry)
{ {
entry->next_child = parent_entry->next_child; entry->next_child = parent_entry->next_child;

View File

@ -11,7 +11,7 @@ Struct(TAR_Entry)
b32 is_dir; b32 is_dir;
TAR_Entry *next; TAR_Entry *next;
TAR_Entry *next_child; /* If entry is dir, points to first child. Otherwise points to next sibling. */ TAR_Entry *next_child; // If entry is dir, points to first child. Otherwise points to next sibling.
} extern Readonly TAR_nil_entry; } extern Readonly TAR_nil_entry;
Struct(TAR_Archive) Struct(TAR_Archive)
@ -39,7 +39,7 @@ Enum(TAR_FileKind)
Packed(Struct(TAR_Header) Packed(Struct(TAR_Header)
{ {
/* Pre-posix */ // Pre-posix
u8 file_name[100]; u8 file_name[100];
u8 file_mode[8]; u8 file_mode[8];
u8 owner_id[8]; u8 owner_id[8];
@ -48,11 +48,11 @@ Packed(Struct(TAR_Header)
u8 last_modified[12]; u8 last_modified[12];
u8 checksum[8]; u8 checksum[8];
/* Both */ // Both
u8 file_type; u8 file_type;
u8 linked_file_name[100]; u8 linked_file_name[100];
/* UStar */ // UStar
u8 ustar_indicator[6]; u8 ustar_indicator[6];
u8 ustar_version[2]; u8 ustar_version[2];
u8 owner_user_name[32]; u8 owner_user_name[32];

View File

@ -6,15 +6,15 @@ Struct(TTF_GlyphResult)
ResourceKey ttf; ResourceKey ttf;
u32 codepoint; u32 codepoint;
f32 advance; /* How far to advance the baseline position */ f32 advance; // How far to advance the baseline position
Rng2 bounds; /* Bounds relative to baseline position */ Rng2 bounds; // Bounds relative to baseline position
f32 font_size; f32 font_size;
f32 font_ascent; f32 font_ascent;
f32 font_descent; f32 font_descent;
f32 font_cap; f32 font_cap;
/* Rasterization output */ // Rasterization output
Vec2I32 image_dims; Vec2I32 image_dims;
u32 *image_pixels; u32 *image_pixels;
}; };

View File

@ -1,5 +1,5 @@
/* Based on Allen Webster's dwrite rasterizer example - // Based on Allen Webster's dwrite rasterizer example -
* https://github.com/4th-dimention/examps */ // https://github.com/4th-dimention/examps
extern TTF_DW_Ctx TTF_DW = Zi; extern TTF_DW_Ctx TTF_DW = Zi;
@ -8,24 +8,23 @@ extern TTF_DW_Ctx TTF_DW = Zi;
void TTF_Bootstrap(void) void TTF_Bootstrap(void)
{ {
/* TODO: I think IDWriteFactory5 only exists on later updates of windows // TODO: I think IDWriteFactory5 only exists on later updates of windows
* 10? Need to verify. Maybe should just use a custom loader. (We're only // 10? Need to verify. Maybe should just use a custom loader. (We're only
* using a factory5 since I think WriteInMemoryFileLoader wasn't // using a factory5 since I think WriteInMemoryFileLoader wasn't
* implemented until then) // implemented until then)
*/
HRESULT hr = 0; HRESULT hr = 0;
{ {
/* Factory */ // Factory
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, &IID_IDWriteFactory5, (void **)&TTF_DW.factory); hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, &IID_IDWriteFactory5, (void **)&TTF_DW.factory);
} }
/* GDI interop */ // GDI interop
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
hr = IDWriteFactory5_GetGdiInterop(TTF_DW.factory, &TTF_DW.gdi_interop); hr = IDWriteFactory5_GetGdiInterop(TTF_DW.factory, &TTF_DW.gdi_interop);
} }
/* Loader */ // Loader
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
hr = IDWriteFactory5_CreateInMemoryFontFileLoader(TTF_DW.factory, &TTF_DW.loader); hr = IDWriteFactory5_CreateInMemoryFontFileLoader(TTF_DW.factory, &TTF_DW.loader);
@ -34,22 +33,26 @@ void TTF_Bootstrap(void)
hr = IDWriteFactory5_RegisterFontFileLoader(TTF_DW.factory, (IDWriteFontFileLoader *)TTF_DW.loader); hr = IDWriteFactory5_RegisterFontFileLoader(TTF_DW.factory, (IDWriteFontFileLoader *)TTF_DW.loader);
} }
} }
/* Builder */ // Builder
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
hr = IDWriteFactory5_CreateFontSetBuilder1(TTF_DW.factory, &TTF_DW.builder); hr = IDWriteFactory5_CreateFontSetBuilder1(TTF_DW.factory, &TTF_DW.builder);
} }
/* Rendering params */ // Rendering params
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
IDWriteRenderingParams *default_rendering_params = 0; IDWriteRenderingParams *default_rendering_params = 0;
{ {
hr = IDWriteFactory5_CreateRenderingParams(TTF_DW.factory, &default_rendering_params); hr = IDWriteFactory5_CreateRenderingParams(TTF_DW.factory, &default_rendering_params);
} }
//
// UNUSED:
//
// f32 gamma = IDWriteRenderingParams_GetGamma(default_rendering_params); // f32 gamma = IDWriteRenderingParams_GetGamma(default_rendering_params);
// f32 clear_type_level = IDWriteRenderingParams_GetClearTypeLevel(default_rendering_params); // f32 clear_type_level = IDWriteRenderingParams_GetClearTypeLevel(default_rendering_params);
// DWRITE_PIXEL_GEOMETRY pixel_geometry = IDWriteRenderingParams_GetPixelGeometry(default_rendering_params); // DWRITE_PIXEL_GEOMETRY pixel_geometry = IDWriteRenderingParams_GetPixelGeometry(default_rendering_params);
// DWRITE_RENDERING_MODE rendering_mode = IDWriteRenderingParams_GetRenderingMode(default_rendering_params); // DWRITE_RENDERING_MODE rendering_mode = IDWriteRenderingParams_GetRenderingMode(default_rendering_params);
//
f32 enhanced_contrast = IDWriteRenderingParams_GetEnhancedContrast(default_rendering_params); f32 enhanced_contrast = IDWriteRenderingParams_GetEnhancedContrast(default_rendering_params);
hr = IDWriteFactory5_CreateCustomRenderingParams2( hr = IDWriteFactory5_CreateCustomRenderingParams2(
TTF_DW.factory, TTF_DW.factory,
@ -123,7 +126,7 @@ TTF_GlyphResult TTF_RasterizeGlyphFromCodepoint(Arena *arena, u32 codepoint, Res
font->hash = hash; font->hash = hash;
font->ttf = ttf; font->ttf = ttf;
font->size = font_size; font->size = font_size;
/* File */ // File
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
hr = IDWriteInMemoryFontFileLoader_CreateInMemoryFontFileReference( hr = IDWriteInMemoryFontFileLoader_CreateInMemoryFontFileReference(
@ -139,7 +142,7 @@ TTF_GlyphResult TTF_RasterizeGlyphFromCodepoint(Arena *arena, u32 codepoint, Res
hr = IDWriteFontSetBuilder1_AddFontFile(TTF_DW.builder, font->file); hr = IDWriteFontSetBuilder1_AddFontFile(TTF_DW.builder, font->file);
} }
} }
/* Face */ // Face
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
hr = IDWriteFactory5_CreateFontFace( hr = IDWriteFactory5_CreateFontFace(
@ -152,7 +155,7 @@ TTF_GlyphResult TTF_RasterizeGlyphFromCodepoint(Arena *arena, u32 codepoint, Res
&font->face &font->face
); );
} }
/* Metrics */ // Metrics
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
IDWriteFontFace_GetMetrics(font->face, &font->design_metrics); IDWriteFontFace_GetMetrics(font->face, &font->design_metrics);
@ -179,7 +182,7 @@ TTF_GlyphResult TTF_RasterizeGlyphFromCodepoint(Arena *arena, u32 codepoint, Res
{ {
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
/* TODO: Dynamic render target dimensions? */ // TODO: Dynamic render target dimensions?
////////////////////////////// //////////////////////////////
//- Fetch render target //- Fetch render target
@ -229,14 +232,14 @@ TTF_GlyphResult TTF_RasterizeGlyphFromCodepoint(Arena *arena, u32 codepoint, Res
////////////////////////////// //////////////////////////////
//- Render //- Render
/* Glyph idx */ // Glyph idx
u16 glyph_idx = 0; u16 glyph_idx = 0;
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
hr = IDWriteFontFace_GetGlyphIndices(font->face, &codepoint, 1, &glyph_idx); hr = IDWriteFontFace_GetGlyphIndices(font->face, &codepoint, 1, &glyph_idx);
} }
/* Glyph metrics */ // Glyph metrics
DWRITE_GLYPH_METRICS m = Zi; DWRITE_GLYPH_METRICS m = Zi;
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
@ -245,16 +248,16 @@ TTF_GlyphResult TTF_RasterizeGlyphFromCodepoint(Arena *arena, u32 codepoint, Res
f32 advance = (f32)m.advanceWidth * pixels_per_design_unit; f32 advance = (f32)m.advanceWidth * pixels_per_design_unit;
advance = RoundF32(advance); advance = RoundF32(advance);
/* Best-guess a position in the middle of the render target based on metrics */ // Best-guess a position in the middle of the render target based on metrics
Vec2I32 rt_baseline = Zi; Vec2I32 rt_baseline = Zi;
rt_baseline.x = (rt_dims.x / 2) - (advance / 2); rt_baseline.x = (rt_dims.x / 2) - (advance / 2);
rt_baseline.y = (rt_dims.y / 2) + (font_cap / 2); rt_baseline.y = (rt_dims.y / 2) + (font_cap / 2);
/* Render */ // Render
Rng2I32 rt_slice = Zi; Rng2I32 rt_slice = Zi;
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
/* Clear target */ // Clear target
{ {
HGDIOBJ original = SelectObject(rt->dc, GetStockObject(DC_PEN)); HGDIOBJ original = SelectObject(rt->dc, GetStockObject(DC_PEN));
{ {
@ -265,7 +268,7 @@ TTF_GlyphResult TTF_RasterizeGlyphFromCodepoint(Arena *arena, u32 codepoint, Res
} }
SelectObject(rt->dc, original); SelectObject(rt->dc, original);
} }
/* Draw glyph */ // Draw glyph
{ {
DWRITE_GLYPH_RUN glyph_run = Zi; DWRITE_GLYPH_RUN glyph_run = Zi;
{ {
@ -299,7 +302,7 @@ TTF_GlyphResult TTF_RasterizeGlyphFromCodepoint(Arena *arena, u32 codepoint, Res
////////////////////////////// //////////////////////////////
//- Copy result //- Copy result
/* Copy from target to result */ // Copy from target to result
Vec2I32 dst_dims = Zi; Vec2I32 dst_dims = Zi;
u32 *dst_pixels = 0; u32 *dst_pixels = 0;
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
@ -329,7 +332,7 @@ TTF_GlyphResult TTF_RasterizeGlyphFromCodepoint(Arena *arena, u32 codepoint, Res
result.image_dims = dst_dims; result.image_dims = dst_dims;
result.image_pixels = dst_pixels; result.image_pixels = dst_pixels;
/* Free render target */ // Free render target
{ {
Lock lock = LockE(&TTF_DW.free_render_targets_mutex); Lock lock = LockE(&TTF_DW.free_render_targets_mutex);
SllStackPush(TTF_DW.first_free_render_target, rt); SllStackPush(TTF_DW.first_free_render_target, rt);

View File

@ -7,9 +7,8 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ DirectWrite types //~ DirectWrite types
/* DirectWrite C API stubs are taken from Mārtiņš Možeiko's c_d2d_dwrite // DirectWrite C API stubs are taken from Mārtiņš Možeiko's c_d2d_dwrite
* https://github.com/mmozeiko/c_d2d_dwrite/blob/main/cdwrite.h // https://github.com/mmozeiko/c_d2d_dwrite/blob/main/cdwrite.h
*/
//- GUIDs //- GUIDs
@ -189,7 +188,7 @@ Struct(TTF_DW_RenderTarget)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Context types //~ Context types
/* TODO: Determine font dpi dynamically */ // TODO: Determine font dpi dynamically
#define TTF_DW_Dpi (96.0f) #define TTF_DW_Dpi (96.0f)
Struct(TTF_DW_Ctx) Struct(TTF_DW_Ctx)

View File

@ -76,7 +76,7 @@ UI_Box *UI_BoxFromKey(UI_Key key)
UI_BoxIterResult UI_FirstBox(Arena *arena, UI_BoxIter *iter, UI_Key start_key) UI_BoxIterResult UI_FirstBox(Arena *arena, UI_BoxIter *iter, UI_Key start_key)
{ {
/* Free old stack */ // Free old stack
if (iter->first) if (iter->first)
{ {
if (iter->last_free) if (iter->last_free)
@ -90,7 +90,7 @@ UI_BoxIterResult UI_FirstBox(Arena *arena, UI_BoxIter *iter, UI_Key start_key)
iter->last_free = iter->first; iter->last_free = iter->first;
iter->first = 0; iter->first = 0;
} }
/* Create root dfs node */ // Create root dfs node
UI_BoxIterDfsNode *dfs = iter->first_free; UI_BoxIterDfsNode *dfs = iter->first_free;
if (dfs) if (dfs)
{ {
@ -115,11 +115,11 @@ UI_BoxIterResult UI_NextBox(Arena *arena, UI_BoxIter *iter)
UI_Box *box = dfs->box; UI_Box *box = dfs->box;
if (!dfs->visited) if (!dfs->visited)
{ {
/* Pre order */ // Pre order
dfs->visited = 1; dfs->visited = 1;
result.box = box; result.box = box;
result.pre = 1; result.pre = 1;
/* Push floating children to dfs stack */ // Push floating children to dfs stack
for (UI_Box *child = box->last; child; child = child->prev) for (UI_Box *child = box->last; child; child = child->prev)
{ {
if (AnyBit(child->desc.flags, UI_BoxFlag_Floating)) if (AnyBit(child->desc.flags, UI_BoxFlag_Floating))
@ -138,7 +138,7 @@ UI_BoxIterResult UI_NextBox(Arena *arena, UI_BoxIter *iter)
SllStackPush(iter->first, child_dfs); SllStackPush(iter->first, child_dfs);
} }
} }
/* Push non-floating children to dfs stack */ // Push non-floating children to dfs stack
for (UI_Box *child = box->last; child; child = child->prev) for (UI_Box *child = box->last; child; child = child->prev)
{ {
if (!AnyBit(child->desc.flags, UI_BoxFlag_Floating)) if (!AnyBit(child->desc.flags, UI_BoxFlag_Floating))
@ -160,7 +160,7 @@ UI_BoxIterResult UI_NextBox(Arena *arena, UI_BoxIter *iter)
} }
else else
{ {
/* Post order */ // Post order
result.box = box; result.box = box;
result.pre = 0; result.pre = 0;
SllStackPop(iter->first); SllStackPop(iter->first);
@ -292,7 +292,7 @@ void UI_PushStyle(UI_StyleDesc desc)
case UI_StyleKind_ChildAlignment: case UI_StyleKind_ChildAlignment:
{ {
UI_Alignment alignment = desc.style.ChildAlignment; UI_Alignment alignment = desc.style.ChildAlignment;
/* Alignment -> horizontal alignment */ // Alignment -> horizontal alignment
switch(alignment) switch(alignment)
{ {
default: break; default: break;
@ -315,7 +315,7 @@ void UI_PushStyle(UI_StyleDesc desc)
UI_PushCopy(ChildAlignmentX, desc, UI_AxisAlignment_End); UI_PushCopy(ChildAlignmentX, desc, UI_AxisAlignment_End);
} break; } break;
} }
/* Alignment -> vertical alignment */ // Alignment -> vertical alignment
switch(alignment) switch(alignment)
{ {
default: break; default: break;
@ -374,7 +374,7 @@ void UI_PushStyle(UI_StyleDesc desc)
n->checkpoint = stack->top_checkpoint; n->checkpoint = stack->top_checkpoint;
} }
/* Initialize style data from desc */ // Initialize style data from desc
switch (kind) switch (kind)
{ {
default: break; default: break;
@ -553,7 +553,7 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color)
if (!UI.box_arena) if (!UI.box_arena)
{ {
UI.box_arena = AcquireArena(Gibi(64)); UI.box_arena = AcquireArena(Gibi(64));
/* Init frames */ // Init frames
for (u64 i = 0; i < countof(UI.frames); ++i) for (u64 i = 0; i < countof(UI.frames); ++i)
{ {
UI_Frame *frame = &UI.frames[i]; UI_Frame *frame = &UI.frames[i];
@ -561,7 +561,7 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color)
frame->rects_arena = AcquireArena(Gibi(64)); frame->rects_arena = AcquireArena(Gibi(64));
frame->gpu_arena = G_AcquireArena(); frame->gpu_arena = G_AcquireArena();
} }
/* Init root box */ // Init root box
{ {
UI_Box *box = PushStruct(UI.box_arena, UI_Box); UI_Box *box = PushStruct(UI.box_arena, UI_Box);
box->key = UI_RootKey; box->key = UI_RootKey;
@ -603,7 +603,7 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color)
frame->tick = UI.current_frame_tick; frame->tick = UI.current_frame_tick;
} }
/* Init style stack */ // Init style stack
{ {
frame->top_stack = PushStruct(frame->arena, UI_Stack); frame->top_stack = PushStruct(frame->arena, UI_Stack);
UI_PushDefaults(); UI_PushDefaults();
@ -623,11 +623,11 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color)
f64 dt = SecondsFromNs(frame->dt_ns); f64 dt = SecondsFromNs(frame->dt_ns);
f64 inv_dt = 1.0 / dt; f64 inv_dt = 1.0 / dt;
/* Locate boxes */ // Locate boxes
UI_Box *hovered_box = 0; UI_Box *hovered_box = 0;
UI_Box *active_box = UI_BoxFromKey(last_frame->active_box); UI_Box *active_box = UI_BoxFromKey(last_frame->active_box);
/* Update cursor pos */ // Update cursor pos
for (u64 cev_index = 0; cev_index < controller_events.count; ++cev_index) for (u64 cev_index = 0; cev_index < controller_events.count; ++cev_index)
{ {
ControllerEvent cev = controller_events.events[cev_index]; ControllerEvent cev = controller_events.events[cev_index];
@ -637,7 +637,7 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color)
} }
} }
/* Init box reports */ // Init box reports
for (u64 pre_index = UI.boxes_count; pre_index-- > 0;) for (u64 pre_index = UI.boxes_count; pre_index-- > 0;)
{ {
UI_Box *box = last_frame->boxes_pre[pre_index]; UI_Box *box = last_frame->boxes_pre[pre_index];
@ -645,7 +645,7 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color)
{ {
b32 is_cursor_in_box = 0; b32 is_cursor_in_box = 0;
{ {
/* TODO: More efficient test. This logic is just copied from the renderer's SDF function for now. */ // TODO: More efficient test. This logic is just copied from the renderer's SDF function for now.
Vec2 p0 = box->rect.p0; Vec2 p0 = box->rect.p0;
Vec2 p1 = box->rect.p1; Vec2 p1 = box->rect.p1;
Vec2 point = frame->cursor_pos; Vec2 point = frame->cursor_pos;
@ -680,7 +680,7 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color)
box->report.m1_presses = 0; box->report.m1_presses = 0;
} }
/* Update state from controller events */ // Update state from controller events
for (u64 cev_index = 0; cev_index < controller_events.count; ++cev_index) for (u64 cev_index = 0; cev_index < controller_events.count; ++cev_index)
{ {
ControllerEvent cev = controller_events.events[cev_index]; ControllerEvent cev = controller_events.events[cev_index];
@ -726,7 +726,7 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color)
} }
} }
/* Update box hot & active states */ // Update box hot & active states
for (u64 pre_index = 0; pre_index < UI.boxes_count; ++pre_index) for (u64 pre_index = 0; pre_index < UI.boxes_count; ++pre_index)
{ {
UI_Box *box = last_frame->boxes_pre[pre_index]; UI_Box *box = last_frame->boxes_pre[pre_index];
@ -824,10 +824,10 @@ void UI_EndFrame(UI_Frame *frame)
break; break;
} }
} }
/* Allocate new box */ // Allocate new box
if (box == 0) if (box == 0)
{ {
/* Allocate new box */ // Allocate new box
box = UI.first_free_box; box = UI.first_free_box;
if (box) if (box)
{ {
@ -875,22 +875,22 @@ void UI_EndFrame(UI_Frame *frame)
} }
} }
/* Update parent */ // Update parent
if (box->parent) if (box->parent)
{ {
/* Remove from old parent */ // Remove from old parent
DllQueueRemove(box->parent->first, box->parent->last, box); DllQueueRemove(box->parent->first, box->parent->last, box);
--box->parent->count; --box->parent->count;
} }
if (parent) if (parent)
{ {
/* Add to new parent */ // Add to new parent
DllQueuePush(parent->first, parent->last, box); DllQueuePush(parent->first, parent->last, box);
++parent->count; ++parent->count;
} }
box->parent = parent; box->parent = parent;
/* Update box */ // Update box
{ {
box->desc = cmd.box; box->desc = cmd.box;
box->glyph_run = GC_RunFromString(frame->arena, box->desc.text, box->desc.font, box->desc.font_size); box->glyph_run = GC_RunFromString(frame->arena, box->desc.text, box->desc.font, box->desc.font_size);
@ -933,7 +933,7 @@ void UI_EndFrame(UI_Frame *frame)
UI_Box *box = prunes[prune_idx]; UI_Box *box = prunes[prune_idx];
UI_Box *parent = box->parent; UI_Box *parent = box->parent;
UI_BoxBin *bin = &UI.box_bins[box->key.hash % countof(UI.box_bins)]; UI_BoxBin *bin = &UI.box_bins[box->key.hash % countof(UI.box_bins)];
/* Re-parent children */ // Re-parent children
if (box->first) if (box->first)
{ {
for (UI_Box *child = box->first; child; child = child->next) for (UI_Box *child = box->first; child; child = child->next)
@ -952,12 +952,12 @@ void UI_EndFrame(UI_Frame *frame)
parent->last = box->last; parent->last = box->last;
parent->count += box->count; parent->count += box->count;
} }
/* Remove from parent */ // Remove from parent
DllQueueRemove(parent->first, parent->last, box); DllQueueRemove(parent->first, parent->last, box);
--parent->count; --parent->count;
/* Remove from lookup table */ // Remove from lookup table
DllQueueRemoveNP(bin->first, bin->last, box, next_in_bin, prev_in_bin); DllQueueRemoveNP(bin->first, bin->last, box, next_in_bin, prev_in_bin);
/* Add to free list */ // Add to free list
SllStackPush(UI.first_free_box, box); SllStackPush(UI.first_free_box, box);
--UI.boxes_count; --UI.boxes_count;
} }
@ -966,7 +966,7 @@ void UI_EndFrame(UI_Frame *frame)
////////////////////////////// //////////////////////////////
//- Layout //- Layout
/* Prepare layout data */ // Prepare layout data
u64 boxes_count = UI.boxes_count; u64 boxes_count = UI.boxes_count;
UI_Box **boxes_pre = PushStructsNoZero(frame->arena, UI_Box *, boxes_count); UI_Box **boxes_pre = PushStructsNoZero(frame->arena, UI_Box *, boxes_count);
UI_Box **boxes_post = PushStructsNoZero(frame->arena, UI_Box *, boxes_count); UI_Box **boxes_post = PushStructsNoZero(frame->arena, UI_Box *, boxes_count);
@ -984,7 +984,7 @@ void UI_EndFrame(UI_Frame *frame)
boxes_pre[pre_index] = box; boxes_pre[pre_index] = box;
pre_index += 1; pre_index += 1;
/* Reset layout data */ // Reset layout data
ZeroStruct(&box->layout); ZeroStruct(&box->layout);
} }
else else
@ -998,7 +998,7 @@ void UI_EndFrame(UI_Frame *frame)
Assert(post_index == boxes_count); Assert(post_index == boxes_count);
} }
/* Compute independent sizes */ // Compute independent sizes
for (u64 pre_index = 0; pre_index < boxes_count; ++pre_index) for (u64 pre_index = 0; pre_index < boxes_count; ++pre_index)
{ {
UI_Box *box = boxes_pre[pre_index]; UI_Box *box = boxes_pre[pre_index];
@ -1011,7 +1011,7 @@ void UI_EndFrame(UI_Frame *frame)
} }
else if (pref_size.kind == UI_SizeKind_Shrink && AnyBit(box->desc.flags, UI_BoxFlag_DrawText)) else if (pref_size.kind == UI_SizeKind_Shrink && AnyBit(box->desc.flags, UI_BoxFlag_DrawText))
{ {
/* TODO: Distinguish between baseline alignment & visual alignment */ // TODO: Distinguish between baseline alignment & visual alignment
f32 text_size = 0; f32 text_size = 0;
if (axis == Axis_X) if (axis == Axis_X)
{ {
@ -1026,7 +1026,7 @@ void UI_EndFrame(UI_Frame *frame)
} }
} }
/* Compute upwards-dependent sizes along layout axis */ // Compute upwards-dependent sizes along layout axis
for (u64 pre_index = 0; pre_index < boxes_count; ++pre_index) for (u64 pre_index = 0; pre_index < boxes_count; ++pre_index)
{ {
UI_Box *box = boxes_pre[pre_index]; UI_Box *box = boxes_pre[pre_index];
@ -1043,7 +1043,7 @@ void UI_EndFrame(UI_Frame *frame)
UI_Size ancestor_size = ancestor->desc.pref_size[axis]; UI_Size ancestor_size = ancestor->desc.pref_size[axis];
if (ancestor_size.kind == UI_SizeKind_Pixel || (ancestor_size.kind == UI_SizeKind_Shrink && AnyBit(box->desc.flags, UI_BoxFlag_DrawText))) if (ancestor_size.kind == UI_SizeKind_Pixel || (ancestor_size.kind == UI_SizeKind_Shrink && AnyBit(box->desc.flags, UI_BoxFlag_DrawText)))
{ {
/* Match independent ancestor */ // Match independent ancestor
match_size = ancestor->layout.solved_dims[axis]; match_size = ancestor->layout.solved_dims[axis];
found_match = 1; found_match = 1;
} }
@ -1053,7 +1053,7 @@ void UI_EndFrame(UI_Frame *frame)
} }
} }
/* Compute downwards-dependent sizes */ // Compute downwards-dependent sizes
for (u64 post_index = 0; post_index < boxes_count; ++post_index) for (u64 post_index = 0; post_index < boxes_count; ++post_index)
{ {
UI_Box *box = boxes_post[post_index]; UI_Box *box = boxes_post[post_index];
@ -1082,7 +1082,7 @@ void UI_EndFrame(UI_Frame *frame)
} }
} }
/* Compute upwards-dependent sizes along non-layout axis */ // Compute upwards-dependent sizes along non-layout axis
for (u64 pre_index = 0; pre_index < boxes_count; ++pre_index) for (u64 pre_index = 0; pre_index < boxes_count; ++pre_index)
{ {
UI_Box *box = boxes_pre[pre_index]; UI_Box *box = boxes_pre[pre_index];
@ -1097,14 +1097,14 @@ void UI_EndFrame(UI_Frame *frame)
} }
} }
/* Solve violations */ // Solve violations
for (u64 pre_index = 0; pre_index < boxes_count; ++pre_index) for (u64 pre_index = 0; pre_index < boxes_count; ++pre_index)
{ {
UI_Box *box = boxes_pre[pre_index]; UI_Box *box = boxes_pre[pre_index];
for (Axis axis = 0; axis < Axis_CountXY; ++axis) for (Axis axis = 0; axis < Axis_CountXY; ++axis)
{ {
f32 box_size = box->layout.solved_dims[axis]; f32 box_size = box->layout.solved_dims[axis];
/* Solve non-floating violations */ // Solve non-floating violations
{ {
f32 size_accum = 0; f32 size_accum = 0;
f32 flex_accum = 0; f32 flex_accum = 0;
@ -1159,7 +1159,7 @@ void UI_EndFrame(UI_Frame *frame)
} }
box->layout.final_children_size_accum[axis] = size_accum; box->layout.final_children_size_accum[axis] = size_accum;
} }
/* Solve floating violations */ // Solve floating violations
for (UI_Box *child = box->first; child; child = child->next) for (UI_Box *child = box->first; child; child = child->next)
{ {
if (AnyBit(child->desc.flags, UI_BoxFlag_Floating) && !AnyBit(child->desc.flags, UI_BoxFlag_NoFloatingClamp)) if (AnyBit(child->desc.flags, UI_BoxFlag_Floating) && !AnyBit(child->desc.flags, UI_BoxFlag_NoFloatingClamp))
@ -1176,13 +1176,13 @@ void UI_EndFrame(UI_Frame *frame)
} }
} }
/* Compute final positions */ // Compute final positions
for (u64 pre_index = 0; pre_index < boxes_count; ++pre_index) for (u64 pre_index = 0; pre_index < boxes_count; ++pre_index)
{ {
UI_Box *box = boxes_pre[pre_index]; UI_Box *box = boxes_pre[pre_index];
UI_Box *parent = box->parent; UI_Box *parent = box->parent;
/* Initialize layout cursor based on alignment */ // Initialize layout cursor based on alignment
{ {
Axis axis = box->desc.child_layout_axis; Axis axis = box->desc.child_layout_axis;
UI_AxisAlignment alignment = box->desc.child_alignment[axis]; UI_AxisAlignment alignment = box->desc.child_alignment[axis];
@ -1202,13 +1202,13 @@ void UI_EndFrame(UI_Frame *frame)
} }
} }
/* Position */ // Position
{ {
f32 *dims_arr = box->layout.solved_dims; f32 *dims_arr = box->layout.solved_dims;
Vec2 dims_vec = VEC2(dims_arr[0], dims_arr[1]); Vec2 dims_vec = VEC2(dims_arr[0], dims_arr[1]);
Vec2 final_pos = Zi; Vec2 final_pos = Zi;
/* Floating box position */ // Floating box position
if (AnyBit(box->desc.flags, UI_BoxFlag_Floating)) if (AnyBit(box->desc.flags, UI_BoxFlag_Floating))
{ {
Vec2 offset = box->desc.floating_pos; Vec2 offset = box->desc.floating_pos;
@ -1225,17 +1225,17 @@ void UI_EndFrame(UI_Frame *frame)
} }
} }
} }
/* Non-floating box position */ // Non-floating box position
else if (parent) else if (parent)
{ {
f32 layout_cursor = parent->layout.cursor; f32 layout_cursor = parent->layout.cursor;
f32 offset[2] = Zi; f32 offset[2] = Zi;
/* Compute offset in layout direction */ // Compute offset in layout direction
{ {
Axis axis = parent->desc.child_layout_axis; Axis axis = parent->desc.child_layout_axis;
offset[axis] = layout_cursor; offset[axis] = layout_cursor;
} }
/* Compute offset in non-layout direction (based on alignment) */ // Compute offset in non-layout direction (based on alignment)
{ {
Axis axis = !parent->desc.child_layout_axis; Axis axis = !parent->desc.child_layout_axis;
UI_AxisAlignment alignment = parent->desc.child_alignment[axis]; UI_AxisAlignment alignment = parent->desc.child_alignment[axis];
@ -1261,14 +1261,14 @@ void UI_EndFrame(UI_Frame *frame)
parent->layout.cursor += dims_arr[parent->desc.child_layout_axis]; parent->layout.cursor += dims_arr[parent->desc.child_layout_axis];
} }
/* Submit position */ // Submit position
Vec2 floored_final_pos = FloorVec2(final_pos); Vec2 floored_final_pos = FloorVec2(final_pos);
Vec2 ceiled_dims = CeilVec2(dims_vec); Vec2 ceiled_dims = CeilVec2(dims_vec);
box->rect.p0 = FloorVec2(floored_final_pos); box->rect.p0 = FloorVec2(floored_final_pos);
box->rect.p1 = AddVec2(floored_final_pos, ceiled_dims); box->rect.p1 = AddVec2(floored_final_pos, ceiled_dims);
} }
/* Rounding */ // Rounding
{ {
UI_Round rounding = box->desc.rounding; UI_Round rounding = box->desc.rounding;
Vec2 half_dims = MulVec2(SubVec2(box->rect.p1, box->rect.p0), 0.5); Vec2 half_dims = MulVec2(SubVec2(box->rect.p1, box->rect.p0), 0.5);
@ -1309,7 +1309,7 @@ void UI_EndFrame(UI_Frame *frame)
final_rounding_bl = MaxF32(final_rounding_bl, parent->rounding_bl - Vec2Len(vbl)); final_rounding_bl = MaxF32(final_rounding_bl, parent->rounding_bl - Vec2Len(vbl));
} }
/* Submit rounding */ // Submit rounding
box->rounding_tl = final_rounding_tl; box->rounding_tl = final_rounding_tl;
box->rounding_tr = final_rounding_tr; box->rounding_tr = final_rounding_tr;
box->rounding_br = final_rounding_br; box->rounding_br = final_rounding_br;
@ -1325,7 +1325,7 @@ void UI_EndFrame(UI_Frame *frame)
////////////////////////////// //////////////////////////////
//- Build render data //- Build render data
/* Build rect instance data */ // Build rect instance data
for (u64 pre_index = 0; pre_index < boxes_count; ++pre_index) for (u64 pre_index = 0; pre_index < boxes_count; ++pre_index)
{ {
UI_Box *box = boxes_pre[pre_index]; UI_Box *box = boxes_pre[pre_index];
@ -1336,7 +1336,7 @@ void UI_EndFrame(UI_Frame *frame)
if (is_visible || AnyBit(frame->frame_flags, UI_FrameFlag_Debug)) if (is_visible || AnyBit(frame->frame_flags, UI_FrameFlag_Debug))
{ {
/* Box rect */ // Box rect
{ {
UI_DRect *rect = PushStruct(frame->rects_arena, UI_DRect); UI_DRect *rect = PushStruct(frame->rects_arena, UI_DRect);
rect->bounds = box->rect; rect->bounds = box->rect;
@ -1353,23 +1353,23 @@ void UI_EndFrame(UI_Frame *frame)
rect->tex_slice_uv = box->raw_texture_slice_uv; rect->tex_slice_uv = box->raw_texture_slice_uv;
} }
/* Text rects */ // Text rects
GC_Run raw_run = box->glyph_run; GC_Run raw_run = box->glyph_run;
if (AnyBit(box->desc.flags, UI_BoxFlag_DrawText) && raw_run.ready) if (AnyBit(box->desc.flags, UI_BoxFlag_DrawText) && raw_run.ready)
{ {
f32 max_baseline = DimsFromRng2(box->rect).x; f32 max_baseline = DimsFromRng2(box->rect).x;
b32 should_truncate = raw_run.baseline_length > max_baseline && !AnyBit(box->desc.flags, UI_BoxFlag_NoTextTruncation); b32 should_truncate = raw_run.baseline_length > max_baseline && !AnyBit(box->desc.flags, UI_BoxFlag_NoTextTruncation);
/* Truncate run */ // Truncate run
u64 final_rects_count = 0; u64 final_rects_count = 0;
GC_RunRect *final_rects = 0; GC_RunRect *final_rects = 0;
if (should_truncate) if (should_truncate)
{ {
/* Get elipses run */ // Get elipses run
GC_Run elipses_run = GC_RunFromString(scratch.arena, Lit("..."), box->desc.font, box->desc.font_size); GC_Run elipses_run = GC_RunFromString(scratch.arena, Lit("..."), box->desc.font, box->desc.font_size);
f32 elipses_start_pos = max_baseline - elipses_run.baseline_length; f32 elipses_start_pos = max_baseline - elipses_run.baseline_length;
/* Append non-overflowed rects */ // Append non-overflowed rects
final_rects = PushStructsNoZero(scratch.arena, GC_RunRect, raw_run.rects_count); final_rects = PushStructsNoZero(scratch.arena, GC_RunRect, raw_run.rects_count);
for (u64 rect_idx = 0; rect_idx < raw_run.rects_count; ++rect_idx) for (u64 rect_idx = 0; rect_idx < raw_run.rects_count; ++rect_idx)
{ {
@ -1381,7 +1381,7 @@ void UI_EndFrame(UI_Frame *frame)
} }
} }
/* Append elipses */ // Append elipses
for (u64 rect_idx = 0; rect_idx < elipses_run.rects_count; ++rect_idx) for (u64 rect_idx = 0; rect_idx < elipses_run.rects_count; ++rect_idx)
{ {
GC_RunRect rr = elipses_run.rects[rect_idx]; GC_RunRect rr = elipses_run.rects[rect_idx];
@ -1406,7 +1406,7 @@ void UI_EndFrame(UI_Frame *frame)
x_alignment = UI_AxisAlignment_Start; x_alignment = UI_AxisAlignment_Start;
} }
/* Compute baseline */ // Compute baseline
f32 ascent = raw_run.font_ascent; f32 ascent = raw_run.font_ascent;
f32 font_descent = raw_run.font_descent; f32 font_descent = raw_run.font_descent;
f32 cap = raw_run.font_cap; f32 cap = raw_run.font_cap;
@ -1452,7 +1452,7 @@ void UI_EndFrame(UI_Frame *frame)
} }
baseline = CeilVec2(baseline); baseline = CeilVec2(baseline);
/* Push text rects */ // Push text rects
for (u64 rect_idx = 0; rect_idx < final_rects_count; ++rect_idx) for (u64 rect_idx = 0; rect_idx < final_rects_count; ++rect_idx)
{ {
GC_RunRect rr = final_rects[rect_idx]; GC_RunRect rr = final_rects[rect_idx];
@ -1476,7 +1476,7 @@ void UI_EndFrame(UI_Frame *frame)
////////////////////////////// //////////////////////////////
//- Push data to GPU //- Push data to GPU
/* Target */ // Target
G_ResourceHandle draw_target = G_PushTexture2D( G_ResourceHandle draw_target = G_PushTexture2D(
frame->gpu_arena, frame->cl, frame->gpu_arena, frame->cl,
G_Format_R16G16B16A16_Float, G_Format_R16G16B16A16_Float,
@ -1486,12 +1486,12 @@ void UI_EndFrame(UI_Frame *frame)
); );
G_Texture2DRef draw_target_ro = G_PushTexture2DRef(frame->gpu_arena, draw_target); G_Texture2DRef draw_target_ro = G_PushTexture2DRef(frame->gpu_arena, draw_target);
/* Rects */ // Rects
u64 rects_count = ArenaCount(frame->rects_arena, UI_DRect); u64 rects_count = ArenaCount(frame->rects_arena, UI_DRect);
G_ResourceHandle rects_buff = G_PushBufferFromString(frame->gpu_arena, frame->cl, StringFromArena(frame->rects_arena)); G_ResourceHandle rects_buff = G_PushBufferFromString(frame->gpu_arena, frame->cl, StringFromArena(frame->rects_arena));
G_StructuredBufferRef rects_ro = G_PushStructuredBufferRef(frame->gpu_arena, rects_buff, UI_DRect); G_StructuredBufferRef rects_ro = G_PushStructuredBufferRef(frame->gpu_arena, rects_buff, UI_DRect);
/* Params */ // Params
UI_DParams params = Zi; UI_DParams params = Zi;
{ {
params.target_size = draw_size; params.target_size = draw_size;
@ -1503,10 +1503,10 @@ void UI_EndFrame(UI_Frame *frame)
G_ResourceHandle params_buff = G_PushBufferFromString(frame->gpu_arena, frame->cl, StringFromStruct(&params)); G_ResourceHandle params_buff = G_PushBufferFromString(frame->gpu_arena, frame->cl, StringFromStruct(&params));
G_StructuredBufferRef params_ro = G_PushStructuredBufferRef(frame->gpu_arena, params_buff, UI_DParams); G_StructuredBufferRef params_ro = G_PushStructuredBufferRef(frame->gpu_arena, params_buff, UI_DParams);
/* Constants */ // Constants
G_SetConstant(frame->cl, UI_ShaderConst_Params, params_ro); G_SetConstant(frame->cl, UI_ShaderConst_Params, params_ro);
/* Sync */ // Sync
G_DumbGlobalMemorySync(frame->cl); G_DumbGlobalMemorySync(frame->cl);
////////////////////////////// //////////////////////////////
@ -1525,7 +1525,7 @@ void UI_EndFrame(UI_Frame *frame)
if (rects_count > 0) if (rects_count > 0)
{ {
/* Render rects */ // Render rects
G_Rasterize( G_Rasterize(
frame->cl, frame->cl,
UI_DRectVS, UI_DRectPS, UI_DRectVS, UI_DRectPS,
@ -1535,7 +1535,7 @@ void UI_EndFrame(UI_Frame *frame)
G_RasterMode_TriangleList G_RasterMode_TriangleList
); );
/* Render rect wireframes */ // Render rect wireframes
if (AnyBit(frame->frame_flags, UI_FrameFlag_Debug)) if (AnyBit(frame->frame_flags, UI_FrameFlag_Debug))
{ {
G_SetConstant(frame->cl, UI_ShaderConst_DebugDraw, 1); G_SetConstant(frame->cl, UI_ShaderConst_DebugDraw, 1);

View File

@ -14,9 +14,9 @@ Struct(UI_Key)
Enum(UI_SizeKind) Enum(UI_SizeKind)
{ {
UI_SizeKind_Pixel, /* Exact size */ UI_SizeKind_Pixel, // Exact size
UI_SizeKind_Grow, /* Size as percent of parent size */ UI_SizeKind_Grow, // Size as percent of parent size
UI_SizeKind_Shrink, /* Size of children + padding in pixels */ UI_SizeKind_Shrink, // Size of children + padding in pixels
}; };
Struct(UI_Size) Struct(UI_Size)
@ -31,8 +31,8 @@ Struct(UI_Size)
Enum(UI_RoundKind) Enum(UI_RoundKind)
{ {
UI_RoundKind_Pixel, /* Exact radius */ UI_RoundKind_Pixel, // Exact radius
UI_RoundKind_Grow, /* Radius as percent of size */ UI_RoundKind_Grow, // Radius as percent of size
}; };
Struct(UI_Round) Struct(UI_Round)
@ -111,13 +111,13 @@ Enum(UI_BoxFlag)
X(Text, String) \ X(Text, String) \
X(BackgroundTexture, G_Texture2DRef) \ X(BackgroundTexture, G_Texture2DRef) \
X(BackgroundTextureSliceUv, Rng2) \ X(BackgroundTextureSliceUv, Rng2) \
/* -------------------------------------------- */ \ /* --------------------------------------------- */ \
/* -------------- Virtual styles -------------- */ \ /* --------------- Virtual styles -------------- */ \
/* -------------------------------------------- */ \ /* --------------------------------------------- */ \
X(BeginVirtualStyles_, i8) \ X(BeginVirtualStyles_, i8) \
X(ChildAlignment, UI_Alignment) \ X(ChildAlignment, UI_Alignment) \
X(AxisSize, UI_Size) \ X(AxisSize, UI_Size) \
/* -------------------------------------------------- */ /* ------------------------------------------------- */
Enum(UI_StyleKind) Enum(UI_StyleKind)
{ {
@ -131,7 +131,7 @@ Enum(UI_StyleKind)
Struct(UI_Style) Struct(UI_Style)
{ {
UI_StyleKind kind; UI_StyleKind kind;
/* Union of all style fields */ // Union of all style fields
union union
{ {
#define X(name, type) type name; #define X(name, type) type name;
@ -145,11 +145,11 @@ Struct(UI_StyleDesc)
Axis axis; Axis axis;
UI_Style style; UI_Style style;
/* Push */ // Push
b32 pop_when_used; b32 pop_when_used;
b32 override; b32 override;
/* Pop */ // Pop
b32 force_pop; b32 force_pop;
b32 use; b32 use;
}; };
@ -186,7 +186,7 @@ Struct(UI_Report)
i32 m1_presses; i32 m1_presses;
Vec2 last_m1_offset; Vec2 last_m1_offset;
/* Where was this box last rendered in screen coordinates */ // Where was this box last rendered in screen coordinates
Rng2 screen_rect; Rng2 screen_rect;
}; };
@ -339,28 +339,28 @@ Struct(UI_Frame)
G_ResourceHandle backbuffer; G_ResourceHandle backbuffer;
G_CommandListHandle cl; G_CommandListHandle cl;
/* Time */ // Time
i64 tick; i64 tick;
i64 time_ns; i64 time_ns;
i64 dt_ns; i64 dt_ns;
/* Control */ // Control
Vec2 cursor_pos; Vec2 cursor_pos;
UI_Key hovered_box; UI_Key hovered_box;
UI_Key active_box; UI_Key active_box;
/* Cmds */ // Cmds
Vec4 swapchain_color; Vec4 swapchain_color;
UI_FrameFlag frame_flags; UI_FrameFlag frame_flags;
UI_CmdNode *first_cmd_node; UI_CmdNode *first_cmd_node;
UI_CmdNode *last_cmd_node; UI_CmdNode *last_cmd_node;
u64 cmds_count; u64 cmds_count;
/* Style stack */ // Style stack
UI_Stack *top_stack; UI_Stack *top_stack;
UI_StyleNode *first_free_style_node; UI_StyleNode *first_free_style_node;
/* Layout */ // Layout
UI_Box **boxes_pre; UI_Box **boxes_pre;
UI_Box **boxes_post; UI_Box **boxes_post;
}; };

View File

@ -42,7 +42,7 @@ PixelShader(UI_DRectPS, UI_DRectPSOutput, UI_DRectPSInput input)
Vec2 p0 = rect.bounds.p0; Vec2 p0 = rect.bounds.p0;
Vec2 p1 = rect.bounds.p1; Vec2 p1 = rect.bounds.p1;
/* Compute rect sdf (negative means pixel is inside of rect) */ // Compute rect sdf (negative means pixel is inside of rect)
f32 rect_dist = min(min(p.x - p0.x, p1.x - p.x), min(p.y - p0.y, p1.y - p.y)); f32 rect_dist = min(min(p.x - p0.x, p1.x - p.x), min(p.y - p0.y, p1.y - p.y));
{ {
f32 tl_radius = rect.tl_rounding; f32 tl_radius = rect.tl_rounding;
@ -60,7 +60,7 @@ PixelShader(UI_DRectPS, UI_DRectPSOutput, UI_DRectPSInput input)
} }
rect_dist = -rect_dist; rect_dist = -rect_dist;
/* Compute border sdf (negative means pixel is inside of border) */ // Compute border sdf (negative means pixel is inside of border)
f32 border_width = 0; f32 border_width = 0;
f32 border_dist = 0; f32 border_dist = 0;
Vec4 border_color = 0; Vec4 border_color = 0;
@ -82,7 +82,7 @@ PixelShader(UI_DRectPS, UI_DRectPSOutput, UI_DRectPSInput input)
} }
} }
/* Background color */ // Background color
Vec4 background_color = 0; Vec4 background_color = 0;
{ {
if (rect_dist <= 0) if (rect_dist <= 0)
@ -103,11 +103,11 @@ PixelShader(UI_DRectPS, UI_DRectPSOutput, UI_DRectPSInput input)
} }
} }
/* Final color */ // Final color
Vec4 final_color = background_color; Vec4 final_color = background_color;
final_color *= input.tint_lin; final_color *= input.tint_lin;
/* Debug color */ // Debug color
if (UI_ShaderConst_DebugDraw) if (UI_ShaderConst_DebugDraw)
{ {
final_color = rect.debug_lin; final_color = rect.debug_lin;

View File

@ -7,7 +7,9 @@ void WND_Bootstrap(void)
{ {
WND_W32_SharedState *g = &WND_W32_shared_state; WND_W32_SharedState *g = &WND_W32_shared_state;
//- Initialize btn table //////////////////////////////
//- Init btn table
{ {
ZeroFixedArray(g->vk_to_button); ZeroFixedArray(g->vk_to_button);
for (u32 i = 'A', j = Button_A; i <= 'Z'; ++i, ++j) for (u32 i = 'A', j = Button_A; i <= 'Z'; ++i, ++j)
@ -52,7 +54,9 @@ void WND_Bootstrap(void)
g->vk_to_button[VK_OEM_1] = Button_Semicolon; g->vk_to_button[VK_OEM_1] = Button_Semicolon;
} }
//- Initialize cursors //////////////////////////////
//- Create cursors
{ {
HCURSOR arrow = LoadCursor(0, IDC_ARROW); HCURSOR arrow = LoadCursor(0, IDC_ARROW);
for (u64 cursor_idx = 0; cursor_idx < countof(g->cursors); ++cursor_idx) for (u64 cursor_idx = 0; cursor_idx < countof(g->cursors); ++cursor_idx)
@ -69,11 +73,13 @@ void WND_Bootstrap(void)
g->cursors[WND_CursorKind_TrBlResize] = LoadCursor(0, IDC_SIZENESW); g->cursors[WND_CursorKind_TrBlResize] = LoadCursor(0, IDC_SIZENESW);
} }
//////////////////////////////
//- Create window class //- Create window class
{ {
HMODULE instance = GetModuleHandle(0); HMODULE instance = GetModuleHandle(0);
/* Register the window class */ // Register the window class
WNDCLASSEXW *wc = &g->window_class; WNDCLASSEXW *wc = &g->window_class;
wc->cbSize = sizeof(WNDCLASSEX); wc->cbSize = sizeof(WNDCLASSEX);
wc->lpszClassName = WND_W32_WindowClassName; wc->lpszClassName = WND_W32_WindowClassName;
@ -83,7 +89,7 @@ void WND_Bootstrap(void)
wc->lpfnWndProc = WND_W32_WindowProc; wc->lpfnWndProc = WND_W32_WindowProc;
wc->hInstance = instance; wc->hInstance = instance;
/* Use first icon resource as window icon (same as explorer) */ // Use first icon resource as window icon (same as explorer)
wchar_t path[4096] = Zi; wchar_t path[4096] = Zi;
GetModuleFileNameW(instance, path, countof(path)); GetModuleFileNameW(instance, path, countof(path));
ExtractIconExW(path, 0, &wc->hIcon, &wc->hIconSm, 1); ExtractIconExW(path, 0, &wc->hIcon, &wc->hIconSm, 1);
@ -94,15 +100,19 @@ void WND_Bootstrap(void)
} }
} }
//////////////////////////////
//- Register raw mouse input //- Register raw mouse input
{ {
RAWINPUTDEVICE rid = Zi; RAWINPUTDEVICE rid = Zi;
rid.usUsagePage = 0x01; /* HID_USAGE_PAGE_GENERIC */ rid.usUsagePage = 0x01; // HID_USAGE_PAGE_GENERIC
rid.usUsage = 0x02; /* HID_USAGE_GENERIC_MOUSE */ rid.usUsage = 0x02; // HID_USAGE_GENERIC_MOUSE
RegisterRawInputDevices(&rid, 1, sizeof(rid)); RegisterRawInputDevices(&rid, 1, sizeof(rid));
} }
//- Dispatch message processor //////////////////////////////
//- Dispatch msg processor
DispatchWave(Lit("Win32 msg loop"), 1, WND_W32_ProcessMessagesForever, 0); DispatchWave(Lit("Win32 msg loop"), 1, WND_W32_ProcessMessagesForever, 0);
} }
@ -117,7 +127,7 @@ WND_W32_Window *WND_W32_WindowFromHandle(WND_Handle handle)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Initialization //~ Initialization
/* Win32 limitation: Window must be initialized on same thread that processes events */ // Win32 limitation: Window must be initialized on same thread that processes events
void WND_W32_ProcessMessagesForever(WaveLaneCtx *lane) void WND_W32_ProcessMessagesForever(WaveLaneCtx *lane)
{ {
WND_W32_SharedState *g = &WND_W32_shared_state; WND_W32_SharedState *g = &WND_W32_shared_state;
@ -126,16 +136,18 @@ void WND_W32_ProcessMessagesForever(WaveLaneCtx *lane)
//- Initialize hwnd //- Initialize hwnd
{ {
/* //
* From martins (https://gist.github.com/mmozeiko/5e727f845db182d468a34d524508ad5f#file-win32_d3d11-c-L66-L70): // From martins -
* WS_EX_NOREDIRECTIONBITMAP flag here is needed to fix ugly bug with Windows 10 // https://gist.github.com/mmozeiko/5e727f845db182d468a34d524508ad5f#file-win32_d3d11-c-L66-L70
* when window is resized and DXGI swap chain uses FLIP presentation model //
* DO NOT use it if you choose to use non-FLIP presentation model // WS_EX_NOREDIRECTIONBITMAP flag here is needed to fix ugly bug with Windows 10
* read about the bug here: https://stackoverflow.com/q/63096226 and here: https://stackoverflow.com/q/53000291 // when window is resized and DXGI swap chain uses FLIP presentation model
*/ // DO NOT use it if you choose to use non-FLIP presentation model
// read about the bug here: https://stackoverflow.com/q/63096226 and here: https://stackoverflow.com/q/53000291
//
DWORD exstyle = WS_EX_APPWINDOW | WS_EX_NOREDIRECTIONBITMAP; DWORD exstyle = WS_EX_APPWINDOW | WS_EX_NOREDIRECTIONBITMAP;
/* TODO: Check for hwnd success */ // TODO: Check for hwnd success
window->hwnd = CreateWindowExW( window->hwnd = CreateWindowExW(
exstyle, exstyle,
g->window_class.lpszClassName, g->window_class.lpszClassName,
@ -151,12 +163,12 @@ void WND_W32_ProcessMessagesForever(WaveLaneCtx *lane)
0 0
); );
/* Dark mode */ // Dark mode
BOOL dark_mode = 1; BOOL dark_mode = 1;
DwmSetWindowAttribute(window->hwnd, DWMWA_USE_IMMERSIVE_DARK_MODE, (LPCVOID)&dark_mode, sizeof(dark_mode)); DwmSetWindowAttribute(window->hwnd, DWMWA_USE_IMMERSIVE_DARK_MODE, (LPCVOID)&dark_mode, sizeof(dark_mode));
/* Set window as userdata */ // Set window as userdata
/* FIXME: Necessary? */ // FIXME: Necessary?
SetWindowLongPtrW(window->hwnd, GWLP_USERDATA, (LONG_PTR)window); SetWindowLongPtrW(window->hwnd, GWLP_USERDATA, (LONG_PTR)window);
} }
@ -178,7 +190,7 @@ void WND_W32_ProcessMessagesForever(WaveLaneCtx *lane)
} }
} }
/* Destroy window */ //- Destroy window
DestroyWindow(window->hwnd); DestroyWindow(window->hwnd);
} }
@ -301,7 +313,7 @@ LRESULT CALLBACK WND_W32_WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM l
{ {
if (codepoint == '\r') if (codepoint == '\r')
{ {
codepoint = '\n'; /* Just treat all \r as newline */ codepoint = '\n'; // Just treat all \r as newline
} }
} }
} }
@ -371,7 +383,7 @@ LRESULT CALLBACK WND_W32_WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM l
Button btn = dir >= 0 ? Button_MWheelUp : Button_MWheelDown; Button btn = dir >= 0 ? Button_MWheelUp : Button_MWheelDown;
for (i32 i = 0; i < (dir * delta); i += WHEEL_DELTA) for (i32 i = 0; i < (dir * delta); i += WHEEL_DELTA)
{ {
/* Send a button down & button up event simultaneously */ // Send a button down & button up event simultaneously
WND_W32_PushEvent(window, (ControllerEvent) { .kind = ControllerEventKind_ButtonDown, .button = btn }); WND_W32_PushEvent(window, (ControllerEvent) { .kind = ControllerEventKind_ButtonDown, .button = btn });
WND_W32_PushEvent(window, (ControllerEvent) { .kind = ControllerEventKind_ButtonUp, .button = btn }); WND_W32_PushEvent(window, (ControllerEvent) { .kind = ControllerEventKind_ButtonUp, .button = btn });
} }
@ -393,7 +405,7 @@ LRESULT CALLBACK WND_W32_WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM l
{ {
TempArena scratch = BeginScratchNoConflict(); TempArena scratch = BeginScratchNoConflict();
{ {
/* Read raw input buffer */ // Read raw input buffer
UINT buff_size; UINT buff_size;
GetRawInputData((HRAWINPUT)lparam, RID_INPUT, 0, &buff_size, sizeof(RAWINPUTHEADER)); GetRawInputData((HRAWINPUT)lparam, RID_INPUT, 0, &buff_size, sizeof(RAWINPUTHEADER));
u8 *buff = PushStructs(scratch.arena, u8, buff_size); u8 *buff = PushStructs(scratch.arena, u8, buff_size);
@ -454,7 +466,7 @@ WND_Frame WND_BeginFrame(G_Format backbuffer_format, WND_BackbufferSizeMode back
HWND hwnd = window->hwnd; HWND hwnd = window->hwnd;
result.window.v = (u64)window; result.window.v = (u64)window;
/* Grab monitor info */ // Grab monitor info
RECT monitor_rect = Zi; RECT monitor_rect = Zi;
{ {
MONITORINFO monitor_info = { .cbSize = sizeof(monitor_info) }; MONITORINFO monitor_info = { .cbSize = sizeof(monitor_info) };
@ -465,11 +477,11 @@ WND_Frame WND_BeginFrame(G_Format backbuffer_format, WND_BackbufferSizeMode back
result.monitor_size.x = MaxI32(result.monitor_size.x, 1); result.monitor_size.x = MaxI32(result.monitor_size.x, 1);
result.monitor_size.y = MaxI32(result.monitor_size.y, 1); result.monitor_size.y = MaxI32(result.monitor_size.y, 1);
/* Client rect */ // Client rect
RECT client_rect = Zi; RECT client_rect = Zi;
GetClientRect(hwnd, (LPRECT)&client_rect); GetClientRect(hwnd, (LPRECT)&client_rect);
/* Screen rect */ // Screen rect
RECT screen_rect = client_rect; RECT screen_rect = client_rect;
ClientToScreen(hwnd, (LPPOINT)&screen_rect.left); ClientToScreen(hwnd, (LPPOINT)&screen_rect.left);
ClientToScreen(hwnd, (LPPOINT)&screen_rect.right); ClientToScreen(hwnd, (LPPOINT)&screen_rect.right);
@ -477,7 +489,7 @@ WND_Frame WND_BeginFrame(G_Format backbuffer_format, WND_BackbufferSizeMode back
result.draw_size.x = MaxI32(result.draw_size.x, 1); result.draw_size.x = MaxI32(result.draw_size.x, 1);
result.draw_size.y = MaxI32(result.draw_size.y, 1); result.draw_size.y = MaxI32(result.draw_size.y, 1);
/* Prepare backbuffer */ // Prepare backbuffer
Vec2I32 backbuffer_size = Zi; Vec2I32 backbuffer_size = Zi;
if (backbuffer_size_mode == WND_BackbufferSizeMode_MatchWindow) if (backbuffer_size_mode == WND_BackbufferSizeMode_MatchWindow)
{ {
@ -489,7 +501,7 @@ WND_Frame WND_BeginFrame(G_Format backbuffer_format, WND_BackbufferSizeMode back
} }
result.backbuffer = G_PrepareBackbuffer(window->swapchain, backbuffer_format, backbuffer_size); result.backbuffer = G_PrepareBackbuffer(window->swapchain, backbuffer_format, backbuffer_size);
/* Reset per-frame data */ // Reset per-frame data
if (!window->frame_arena) if (!window->frame_arena)
{ {
window->frame_arena = AcquireArena(Gibi(64)); window->frame_arena = AcquireArena(Gibi(64));
@ -498,7 +510,7 @@ WND_Frame WND_BeginFrame(G_Format backbuffer_format, WND_BackbufferSizeMode back
window->first_cmd = 0; window->first_cmd = 0;
window->last_cmd = 0; window->last_cmd = 0;
/* Pop user input */ // Pop user input
{ {
LockTicketMutex(&window->w2u_tm); LockTicketMutex(&window->w2u_tm);
{ {
@ -511,7 +523,7 @@ WND_Frame WND_BeginFrame(G_Format backbuffer_format, WND_BackbufferSizeMode back
UnlockTicketMutex(&window->w2u_tm); UnlockTicketMutex(&window->w2u_tm);
} }
/* Minimized / maximized / fullscreen */ // Minimized / maximized / fullscreen
DWORD style = (DWORD)GetWindowLongPtr(hwnd, GWL_STYLE); DWORD style = (DWORD)GetWindowLongPtr(hwnd, GWL_STYLE);
DWORD ex_style = (DWORD)GetWindowLongPtr(hwnd, GWL_EXSTYLE); DWORD ex_style = (DWORD)GetWindowLongPtr(hwnd, GWL_EXSTYLE);
WINDOWPLACEMENT placement = { .length = sizeof(placement) }; WINDOWPLACEMENT placement = { .length = sizeof(placement) };
@ -540,7 +552,7 @@ WND_Frame WND_BeginFrame(G_Format backbuffer_format, WND_BackbufferSizeMode back
result.fullscreen = window->is_fullscreen; result.fullscreen = window->is_fullscreen;
result.has_focus = GetForegroundWindow() == hwnd; result.has_focus = GetForegroundWindow() == hwnd;
/* Generate restore data */ // Generate restore data
{ {
WND_W32_RestorableData restore = Zi; WND_W32_RestorableData restore = Zi;
{ {
@ -571,7 +583,7 @@ void WND_EndFrame(WND_Frame frame, i32 vsync)
WND_W32_Window *window = WND_W32_WindowFromHandle(frame.window); WND_W32_Window *window = WND_W32_WindowFromHandle(frame.window);
HWND hwnd = window->hwnd; HWND hwnd = window->hwnd;
/* Process cmds */ // Process cmds
b32 was_restored = 0; b32 was_restored = 0;
HCURSOR desired_cursor = (HCURSOR)Atomic64Fetch(&window->desired_cursor); HCURSOR desired_cursor = (HCURSOR)Atomic64Fetch(&window->desired_cursor);
for (WND_W32_CmdNode *n = window->first_cmd; n; n = n->next) for (WND_W32_CmdNode *n = window->first_cmd; n; n = n->next)
@ -611,7 +623,7 @@ void WND_EndFrame(WND_Frame frame, i32 vsync)
DWORD new_style = old_style; DWORD new_style = old_style;
if (cmd.v) if (cmd.v)
{ {
/* Enter fullscreen */ // Enter fullscreen
{ {
MONITORINFO monitor_info = { .cbSize = sizeof(monitor_info) }; MONITORINFO monitor_info = { .cbSize = sizeof(monitor_info) };
GetMonitorInfo(MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY), &monitor_info); GetMonitorInfo(MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY), &monitor_info);
@ -624,7 +636,7 @@ void WND_EndFrame(WND_Frame frame, i32 vsync)
} }
else else
{ {
/* Exit fullscreen */ // Exit fullscreen
new_rect = window->fullscreen_restore_rect; new_rect = window->fullscreen_restore_rect;
new_style &= ~WS_POPUP; new_style &= ~WS_POPUP;
new_style |= WS_OVERLAPPEDWINDOW; new_style |= WS_OVERLAPPEDWINDOW;
@ -652,7 +664,7 @@ void WND_EndFrame(WND_Frame frame, i32 vsync)
//- Restore //- Restore
case WND_CmdKind_Restore: case WND_CmdKind_Restore:
{ {
/* FIXME: Cap bounds */ // FIXME: Cap bounds
String restore_str = cmd.restore; String restore_str = cmd.restore;
if (restore_str.len == sizeof(WND_W32_RestorableData)) if (restore_str.len == sizeof(WND_W32_RestorableData))
{ {
@ -701,7 +713,7 @@ void WND_EndFrame(WND_Frame frame, i32 vsync)
} }
} }
/* Bring window to front on first frame */ // Bring window to front on first frame
if (!was_restored && window->frame_gen == 0) if (!was_restored && window->frame_gen == 0)
{ {
ShowWindow(hwnd, SW_SHOW); ShowWindow(hwnd, SW_SHOW);
@ -709,7 +721,7 @@ void WND_EndFrame(WND_Frame frame, i32 vsync)
BringWindowToTop(hwnd); BringWindowToTop(hwnd);
} }
/* Set cursor */ // Set cursor
{ {
HCURSOR old_desired_cursor = (HCURSOR)Atomic64FetchSet(&window->desired_cursor, (i64)desired_cursor); HCURSOR old_desired_cursor = (HCURSOR)Atomic64FetchSet(&window->desired_cursor, (i64)desired_cursor);
if (old_desired_cursor != desired_cursor) if (old_desired_cursor != desired_cursor)
@ -718,7 +730,7 @@ void WND_EndFrame(WND_Frame frame, i32 vsync)
} }
} }
/* Commit backbuffer */ // Commit backbuffer
G_CommitBackbuffer(frame.backbuffer, vsync); G_CommitBackbuffer(frame.backbuffer, vsync);
++window->frame_gen; ++window->frame_gen;

View File

@ -8,11 +8,11 @@ Struct(WND_W32_Window)
G_ResourceHandle backbuffer; G_ResourceHandle backbuffer;
Atomic32 is_ready; Atomic32 is_ready;
/* Window proc state */ // Window proc state
u16 previous_utf16_high_surrogate; u16 previous_utf16_high_surrogate;
HCURSOR active_cursor; HCURSOR active_cursor;
/* User state */ // User state
Arena *frame_arena; Arena *frame_arena;
struct WND_W32_CmdNode *first_cmd; struct WND_W32_CmdNode *first_cmd;
struct WND_W32_CmdNode *last_cmd; struct WND_W32_CmdNode *last_cmd;
@ -21,11 +21,11 @@ Struct(WND_W32_Window)
b32 is_fullscreen; b32 is_fullscreen;
RECT fullscreen_restore_rect; RECT fullscreen_restore_rect;
/* Window proc -> User */ // Window proc -> User
TicketMutex w2u_tm; TicketMutex w2u_tm;
Arena *w2u_events_arena; Arena *w2u_events_arena;
/* User -> Window proc */ // User -> Window proc
Atomic64 desired_cursor; Atomic64 desired_cursor;
}; };
@ -75,7 +75,7 @@ Struct(WND_W32_SharedState)
WNDCLASSEXW window_class; WNDCLASSEXW window_class;
WND_W32_Window window; /* Single-window for now */ WND_W32_Window window; // Single-window for now
} extern WND_W32_shared_state; } extern WND_W32_shared_state;
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////