convert comment style from multi-line to single-line
This commit is contained in:
parent
a4ebc3cb49
commit
4ffb9a8d73
213
src/ase/ase.c
213
src/ase/ase.c
@ -1,7 +1,8 @@
|
||||
/* Aseprite (.ase) file parser
|
||||
*
|
||||
* DEFLATE decoder based on Handmade Hero's png parser
|
||||
*/
|
||||
//
|
||||
// Aseprite (.ase) file parser
|
||||
//
|
||||
// DEFLATE decoder based on Handmade Hero's png parser
|
||||
//
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Shared constants
|
||||
@ -11,68 +12,68 @@ Global Readonly u32 ASE_huff_hclen_order[] = {
|
||||
};
|
||||
|
||||
Global Readonly ASE_HuffEntry ASE_huff_length_table[] = {
|
||||
{3, 0}, /* 257 */
|
||||
{4, 0}, /* 258 */
|
||||
{5, 0}, /* 259 */
|
||||
{6, 0}, /* 260 */
|
||||
{7, 0}, /* 261 */
|
||||
{8, 0}, /* 262 */
|
||||
{9, 0}, /* 263 */
|
||||
{10, 0}, /* 264 */
|
||||
{11, 1}, /* 265 */
|
||||
{13, 1}, /* 266 */
|
||||
{15, 1}, /* 267 */
|
||||
{17, 1}, /* 268 */
|
||||
{19, 2}, /* 269 */
|
||||
{23, 2}, /* 270 */
|
||||
{27, 2}, /* 271 */
|
||||
{31, 2}, /* 272 */
|
||||
{35, 3}, /* 273 */
|
||||
{43, 3}, /* 274 */
|
||||
{51, 3}, /* 275 */
|
||||
{59, 3}, /* 276 */
|
||||
{67, 4}, /* 277 */
|
||||
{83, 4}, /* 278 */
|
||||
{99, 4}, /* 279 */
|
||||
{115, 4}, /* 280 */
|
||||
{131, 5}, /* 281 */
|
||||
{163, 5}, /* 282 */
|
||||
{195, 5}, /* 283 */
|
||||
{227, 5}, /* 284 */
|
||||
{258, 0}, /* 285 */
|
||||
{3, 0}, // 257
|
||||
{4, 0}, // 258
|
||||
{5, 0}, // 259
|
||||
{6, 0}, // 260
|
||||
{7, 0}, // 261
|
||||
{8, 0}, // 262
|
||||
{9, 0}, // 263
|
||||
{10, 0}, // 264
|
||||
{11, 1}, // 265
|
||||
{13, 1}, // 266
|
||||
{15, 1}, // 267
|
||||
{17, 1}, // 268
|
||||
{19, 2}, // 269
|
||||
{23, 2}, // 270
|
||||
{27, 2}, // 271
|
||||
{31, 2}, // 272
|
||||
{35, 3}, // 273
|
||||
{43, 3}, // 274
|
||||
{51, 3}, // 275
|
||||
{59, 3}, // 276
|
||||
{67, 4}, // 277
|
||||
{83, 4}, // 278
|
||||
{99, 4}, // 279
|
||||
{115, 4}, // 280
|
||||
{131, 5}, // 281
|
||||
{163, 5}, // 282
|
||||
{195, 5}, // 283
|
||||
{227, 5}, // 284
|
||||
{258, 0}, // 285
|
||||
};
|
||||
|
||||
Global Readonly ASE_HuffEntry ASE_huff_dist_table[] = {
|
||||
{1, 0}, /* 0 */
|
||||
{2, 0}, /* 1 */
|
||||
{3, 0}, /* 2 */
|
||||
{4, 0}, /* 3 */
|
||||
{5, 1}, /* 4 */
|
||||
{7, 1}, /* 5 */
|
||||
{9, 2}, /* 6 */
|
||||
{13, 2}, /* 7 */
|
||||
{17, 3}, /* 8 */
|
||||
{25, 3}, /* 9 */
|
||||
{33, 4}, /* 10 */
|
||||
{49, 4}, /* 11 */
|
||||
{65, 5}, /* 12 */
|
||||
{97, 5}, /* 13 */
|
||||
{129, 6}, /* 14 */
|
||||
{193, 6}, /* 15 */
|
||||
{257, 7}, /* 16 */
|
||||
{385, 7}, /* 17 */
|
||||
{513, 8}, /* 18 */
|
||||
{769, 8}, /* 19 */
|
||||
{1025, 9}, /* 20 */
|
||||
{1537, 9}, /* 21 */
|
||||
{2049, 10}, /* 22 */
|
||||
{3073, 10}, /* 23 */
|
||||
{4097, 11}, /* 24 */
|
||||
{6145, 11}, /* 25 */
|
||||
{8193, 12}, /* 26 */
|
||||
{12289, 12}, /* 27 */
|
||||
{16385, 13}, /* 28 */
|
||||
{24577, 13}, /* 29 */
|
||||
{1, 0}, // 0
|
||||
{2, 0}, // 1
|
||||
{3, 0}, // 2
|
||||
{4, 0}, // 3
|
||||
{5, 1}, // 4
|
||||
{7, 1}, // 5
|
||||
{9, 2}, // 6
|
||||
{13, 2}, // 7
|
||||
{17, 3}, // 8
|
||||
{25, 3}, // 9
|
||||
{33, 4}, // 10
|
||||
{49, 4}, // 11
|
||||
{65, 5}, // 12
|
||||
{97, 5}, // 13
|
||||
{129, 6}, // 14
|
||||
{193, 6}, // 15
|
||||
{257, 7}, // 16
|
||||
{385, 7}, // 17
|
||||
{513, 8}, // 18
|
||||
{769, 8}, // 19
|
||||
{1025, 9}, // 20
|
||||
{1537, 9}, // 21
|
||||
{2049, 10}, // 22
|
||||
{3073, 10}, // 23
|
||||
{4097, 11}, // 24
|
||||
{6145, 11}, // 25
|
||||
{8193, 12}, // 26
|
||||
{12289, 12}, // 27
|
||||
{16385, 13}, // 28
|
||||
{24577, 13}, // 29
|
||||
};
|
||||
|
||||
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)
|
||||
{
|
||||
/* 7 & 15 seem to be the most common bit_counts, so a
|
||||
* more optimal path is layed out for them. */
|
||||
// 7 & 15 seem to be the most common bit_counts, so a
|
||||
// more optimal path is layed out for them.
|
||||
if (bit_count == 15)
|
||||
{
|
||||
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);
|
||||
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 index = ASE_ReverseBits(base_index, result.max_code_bits);
|
||||
ASE_HuffEntry *entry = &result.entries[index];
|
||||
@ -222,7 +223,7 @@ void ASE_Inflate(u8 *dst, u8 *encoded)
|
||||
|
||||
ASE_Bitbuff bb = { .data = encoded };
|
||||
|
||||
/* ZLIB header */
|
||||
// ZLIB header
|
||||
u32 cm = ASE_ConsumeBits(&bb, 4);
|
||||
u32 cinfo = ASE_ConsumeBits(&bb, 4);
|
||||
Assert(cm == 8);
|
||||
@ -249,7 +250,7 @@ void ASE_Inflate(u8 *dst, u8 *encoded)
|
||||
ASE_SkipBits(&bb, (8 - (bb.cur_bit % 8)) % 8);
|
||||
i16 len = ASE_ConsumeBits(&bb, 16);
|
||||
i16 nlen = ASE_ConsumeBits(&bb, 16);
|
||||
Assert(len == ~nlen); /* Validation */
|
||||
Assert(len == ~nlen); // Validation
|
||||
while (len-- > 0)
|
||||
{
|
||||
*dst++ = ASE_ConsumeBits(&bb, 8);
|
||||
@ -266,14 +267,14 @@ void ASE_Inflate(u8 *dst, u8 *encoded)
|
||||
|
||||
if (btype == ASE_BlockType_CompressedDynamic)
|
||||
{
|
||||
/* Dynamic table */
|
||||
// Dynamic table
|
||||
|
||||
/* Read huffman table */
|
||||
// Read huffman table
|
||||
hlit = ASE_ConsumeBits(&bb, 5) + 257;
|
||||
hdist = ASE_ConsumeBits(&bb, 5) + 1;
|
||||
u32 hclen = ASE_ConsumeBits(&bb, 4) + 4;
|
||||
|
||||
/* Init dict huffman (hclen) */
|
||||
// Init dict huffman (hclen)
|
||||
u32 hclen_bl_counts[19] = Zi;
|
||||
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));
|
||||
|
||||
/* Decode dict huffman */
|
||||
// Decode dict huffman
|
||||
u32 lit_len_count = 0;
|
||||
u32 len_count = hlit + hdist;
|
||||
Assert(len_count <= countof(lit_len_dist_table));
|
||||
@ -311,7 +312,7 @@ void ASE_Inflate(u8 *dst, u8 *encoded)
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Invalid len */
|
||||
// Invalid len
|
||||
Assert(0);
|
||||
}
|
||||
|
||||
@ -324,7 +325,7 @@ void ASE_Inflate(u8 *dst, u8 *encoded)
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Fixed table */
|
||||
// Fixed table
|
||||
hlit = 288;
|
||||
hdist = 32;
|
||||
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 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:
|
||||
{
|
||||
/* TODO */
|
||||
// TODO
|
||||
Assert(0);
|
||||
} 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)
|
||||
{
|
||||
/* Try and get image resolution into as much of a square as possible by
|
||||
* separating frames into multiple rows. */
|
||||
// Try and get image resolution into as much of a square as possible by
|
||||
// separating frames into multiple rows.
|
||||
while (*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.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);
|
||||
|
||||
u32 num_layers = 0;
|
||||
@ -526,7 +527,9 @@ ASE_DecodedImage ASE_DecodeImage(Arena *arena, String encoded)
|
||||
Ace_Cel *cel_head = 0;
|
||||
Ace_Cel *cel_tail = 0;
|
||||
|
||||
//////////////////////////////
|
||||
//- Iterate frames
|
||||
|
||||
u32 num_frames = 0;
|
||||
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;
|
||||
}
|
||||
|
||||
//- Iterate chunks in frame
|
||||
//////////////////////////////
|
||||
//- Iterate chunks
|
||||
|
||||
for (u32 j = 0; j < num_chunks; ++j)
|
||||
{
|
||||
u32 chunk_size = BB_ReadUBits(&br, 32);
|
||||
ASE_ChunkKind chunk_type = BB_ReadUBits(&br, 16);
|
||||
|
||||
/* Chunk size includes size & type */
|
||||
// Chunk size includes size & type
|
||||
Assert(chunk_size >= 6);
|
||||
chunk_size -= 6;
|
||||
|
||||
@ -559,7 +564,9 @@ ASE_DecodedImage ASE_DecodeImage(Arena *arena, String encoded)
|
||||
BB_ReadSeekToByte(&br, chunk_end_pos);
|
||||
} break;
|
||||
|
||||
//////////////////////////////
|
||||
//- Decode layer
|
||||
|
||||
case ASE_ChunkKind_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->child_level = BB_ReadUBits(&br, 16);
|
||||
|
||||
/* Ignoring layer default width & height */
|
||||
// Ignoring layer default width & height
|
||||
BB_ReadSeekBytes(&br, sizeof(u16) * 2);
|
||||
|
||||
layer->blend_mode = BB_ReadUBits(&br, 16);
|
||||
@ -604,7 +611,9 @@ ASE_DecodedImage ASE_DecodeImage(Arena *arena, String encoded)
|
||||
layer->index = num_layers++;
|
||||
} break;
|
||||
|
||||
//////////////////////////////
|
||||
//- Decode cel
|
||||
|
||||
case ASE_ChunkKind_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:
|
||||
{
|
||||
/* Unsupported */
|
||||
// Unsupported
|
||||
BB_ReadSeekToByte(&br, chunk_end_pos);
|
||||
} break;
|
||||
|
||||
case ASE_CelKind_Linked:
|
||||
{
|
||||
cel->frame_pos = BB_ReadUBits(&br, 16);
|
||||
/* Actual linking happens later after iteration */
|
||||
// Actual linking happens later after iteration
|
||||
} break;
|
||||
|
||||
case ASE_CelKind_CompressedImage:
|
||||
@ -657,7 +666,7 @@ ASE_DecodedImage ASE_DecodeImage(Arena *arena, String encoded)
|
||||
|
||||
case ASE_CelKind_CompressedTilemap:
|
||||
{
|
||||
/* Unsupported */
|
||||
// Unsupported
|
||||
ASE_PushError(arena, &result.errors, Lit("Tilemaps are not supported"));
|
||||
goto abort;
|
||||
} break;
|
||||
@ -668,14 +677,18 @@ ASE_DecodedImage ASE_DecodeImage(Arena *arena, String encoded)
|
||||
++num_frames;
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- Create ordered layers array
|
||||
|
||||
ASE_Layer **layers_ordered = PushStructsNoZero(scratch.arena, ASE_Layer *, num_layers);
|
||||
for (ASE_Layer *layer = layer_head; layer; layer = layer->next)
|
||||
{
|
||||
layers_ordered[layer->index] = layer;
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- Link cels
|
||||
|
||||
Ace_Cel **cels_ordered = PushStructsNoZero(scratch.arena, Ace_Cel *, num_frames * num_layers);
|
||||
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
|
||||
|
||||
{
|
||||
for (Ace_Cel *cel = cel_head; cel; cel = cel->next)
|
||||
{
|
||||
ASE_Layer *layer = layers_ordered[cel->layer_index];
|
||||
/* Only draw visible layers */
|
||||
// Only draw visible layers
|
||||
if (layer->flags & 1)
|
||||
{
|
||||
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_top = frame_top + ((cel->frame_index / frames_x) * frame_height);
|
||||
|
||||
/* Adjust bounds to ensure pixels outside of frame boundaries
|
||||
* aren't (aseprite keeps chunks outside of frame around in
|
||||
* project file). */
|
||||
// Adjust bounds to ensure pixels outside of frame boundaries
|
||||
// aren't (aseprite keeps chunks outside of frame around in
|
||||
// project file).
|
||||
{
|
||||
i32 frame_right = cel_width + frame_left;
|
||||
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);
|
||||
|
||||
abort:
|
||||
@ -808,7 +823,9 @@ ASE_DecodedSheet ASE_DecodeSheet(Arena *arena, String encoded)
|
||||
u32 num_slice_keys = 0;
|
||||
ASE_SliceKey *first_slice_key = 0;
|
||||
|
||||
//////////////////////////////
|
||||
//- Iterate frames
|
||||
|
||||
for (u16 i = 0; i < ase_header.frames; ++i)
|
||||
{
|
||||
ASE_FrameHeader frame_header;
|
||||
@ -839,13 +856,15 @@ ASE_DecodedSheet ASE_DecodeSheet(Arena *arena, String encoded)
|
||||
frame->index = i;
|
||||
frame->duration = frame_header.frame_duration_ms / 1000.0;
|
||||
|
||||
//- Iterate chunks in frame
|
||||
//////////////////////////////
|
||||
//- Iterate chunks
|
||||
|
||||
for (u32 j = 0; j < num_chunks; ++j)
|
||||
{
|
||||
u32 chunk_size = BB_ReadUBits(&br, 32);
|
||||
ASE_ChunkKind chunk_type = BB_ReadUBits(&br, 16);
|
||||
|
||||
/* Chunk size includes size & type */
|
||||
// Chunk size includes size & type
|
||||
Assert(chunk_size >= 6);
|
||||
chunk_size -= 6;
|
||||
|
||||
@ -883,7 +902,9 @@ ASE_DecodedSheet ASE_DecodeSheet(Arena *arena, String encoded)
|
||||
|
||||
} break;
|
||||
|
||||
//////////////////////////////
|
||||
//- Decode slice
|
||||
|
||||
case ASE_ChunkKind_Slice:
|
||||
{
|
||||
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);
|
||||
if (flags & 0x01)
|
||||
{
|
||||
/* Skip 9-patches info */
|
||||
// Skip 9-patches info
|
||||
BB_ReadSeekBytes(&br, 128);
|
||||
}
|
||||
if (flags & 0x02)
|
||||
{
|
||||
/* Skip pivot info */
|
||||
// Skip pivot info
|
||||
BB_ReadSeekBytes(&br, 64);
|
||||
}
|
||||
|
||||
@ -930,14 +951,14 @@ ASE_DecodedSheet ASE_DecodeSheet(Arena *arena, String encoded)
|
||||
++num_slice_keys;
|
||||
} break;
|
||||
|
||||
/* TODO */
|
||||
// TODO
|
||||
//case ASE_ChunkKind_Userdata
|
||||
}
|
||||
}
|
||||
++num_frames;
|
||||
}
|
||||
|
||||
/* Assert all data was read */
|
||||
// Assert all data was read
|
||||
Assert(BB_NumBytesRemaining(&br) == 0);
|
||||
|
||||
result.image_size = VEC2(image_width, image_height);
|
||||
|
||||
@ -52,7 +52,7 @@ Struct(ASE_DecodedImage)
|
||||
{
|
||||
u32 width;
|
||||
u32 height;
|
||||
u32 *pixels; /* Array of [width * height] pixels */
|
||||
u32 *pixels; // Array of [width * height] pixels
|
||||
ASE_ErrorList errors;
|
||||
b32 ok;
|
||||
};
|
||||
@ -192,10 +192,10 @@ Struct(Ace_Cel)
|
||||
ASE_CelKind type;
|
||||
i16 z_index;
|
||||
|
||||
/* Linked cel */
|
||||
// Linked cel
|
||||
u16 frame_pos;
|
||||
|
||||
/* Compressed image */
|
||||
// Compressed image
|
||||
u32 width;
|
||||
u32 height;
|
||||
u32 *pixels;
|
||||
|
||||
@ -96,11 +96,11 @@
|
||||
#endif
|
||||
|
||||
//- 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
|
||||
|
||||
//- Windows NTDDI version
|
||||
/* TODO: Remove this */
|
||||
// TODO: Remove this
|
||||
#if 0
|
||||
#if IsCompilerMsvc
|
||||
#define NTDDI_WIN11_DT 0x0C0A0000
|
||||
@ -235,9 +235,8 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Linked list helper macros
|
||||
|
||||
/* Taken from the rad debugger
|
||||
* https://github.com/EpicGamesExt/raddebugger/blob/be5634c44867a2e31f6a109df5e574930992df01/src/base/base_core.h#L239
|
||||
*/
|
||||
// Taken from the rad debugger
|
||||
// https://github.com/EpicGamesExt/raddebugger/blob/be5634c44867a2e31f6a109df5e574930992df01/src/base/base_core.h#L239
|
||||
|
||||
#define CheckNil(nil,p) ((p) == 0 || (p) == nil)
|
||||
#define SetNil(nil,p) ((p) = nil)
|
||||
@ -384,20 +383,19 @@
|
||||
//~ Intrinsic headers
|
||||
|
||||
#if IsLanguageC
|
||||
/* Intrinsic header info:
|
||||
* mmintrin.h MMX
|
||||
* xmmintrin.h SSE
|
||||
* emmintrin.h SSE2
|
||||
* pmmintrin.h SSE3
|
||||
* tmmintrin.h SSSE3
|
||||
* smmintrin.h SSE4.1
|
||||
* nmmintrin.h SSE4.2
|
||||
* ammintrin.h SSE4A
|
||||
* wmmintrin.h AES
|
||||
* immintrin.h AVX, AVX2, FMA
|
||||
*/
|
||||
// Intrinsic header info:
|
||||
// mmintrin.h MMX
|
||||
// xmmintrin.h SSE
|
||||
// emmintrin.h SSE2
|
||||
// pmmintrin.h SSE3
|
||||
// tmmintrin.h SSSE3
|
||||
// smmintrin.h SSE4.1
|
||||
// nmmintrin.h SSE4.2
|
||||
// ammintrin.h SSE4A
|
||||
// wmmintrin.h AES
|
||||
// immintrin.h AVX, AVX2, FMA
|
||||
#include <intrin.h>
|
||||
#include <nmmintrin.h> /* SSE4.2 */
|
||||
#include <nmmintrin.h> // SSE4.2
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -602,7 +600,7 @@
|
||||
|
||||
ForceInline void UnlockTicketMutex(TicketMutex *tm)
|
||||
{
|
||||
/* TODO: Atomic set w/ known ticket + 1 */
|
||||
// TODO: Atomic set w/ known ticket + 1
|
||||
Atomic64FetchAdd(&tm->serving.v, 1);
|
||||
}
|
||||
#endif
|
||||
@ -705,10 +703,10 @@
|
||||
#if IsLanguageC
|
||||
Struct(CpuTopologyInfo)
|
||||
{
|
||||
i32 num_logical_cores; /* Includes P cores, Non-P cores, SMT siblings */
|
||||
i32 num_physical_cores; /* Includes P Cores, Non-P Cores */
|
||||
i32 num_physical_performance_cores; /* Includes P Cores */
|
||||
i32 num_physical_non_performance_cores; /* Includes Non-P cores */
|
||||
i32 num_logical_cores; // Includes P cores, Non-P cores, SMT siblings
|
||||
i32 num_physical_cores; // Includes P Cores, Non-P Cores
|
||||
i32 num_physical_performance_cores; // Includes P Cores
|
||||
i32 num_physical_non_performance_cores; // Includes Non-P cores
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@ Arena *AcquireArena(u64 reserve)
|
||||
{
|
||||
reserve += ArenaHeaderSize;
|
||||
|
||||
/* Round up to nearest block size */
|
||||
// Round up to nearest block size
|
||||
u64 block_remainder = reserve % ArenaBlockSize;
|
||||
if (block_remainder > 0)
|
||||
{
|
||||
@ -20,22 +20,22 @@ Arena *AcquireArena(u64 reserve)
|
||||
u64 reserved = reserve;
|
||||
AddGstat(ArenaMemoryReserved, reserve);
|
||||
|
||||
/* Commit initial block */
|
||||
// Commit initial block
|
||||
base = CommitMemory(base, ArenaBlockSize);
|
||||
if (!base)
|
||||
{
|
||||
Panic(Lit("Failed to commit initial memory block: System may be out of memory"));
|
||||
}
|
||||
|
||||
Assert(((u64)base & 0xFFF) == 0); /* Base should be 4k aligned */
|
||||
StaticAssert(ArenaHeaderSize <= ArenaBlockSize); /* Header must fit in first block */
|
||||
StaticAssert(sizeof(Arena) <= ArenaHeaderSize); /* Arena struct must fit in header */
|
||||
Assert(((u64)base & 0xFFF) == 0); // Base should be 4k aligned
|
||||
StaticAssert(ArenaHeaderSize <= ArenaBlockSize); // Header must fit in first block
|
||||
StaticAssert(sizeof(Arena) <= ArenaHeaderSize); // Arena struct must fit in header
|
||||
|
||||
AsanPoison(base + sizeof(Arena), ArenaBlockSize - sizeof(Arena));
|
||||
AddGstat(ArenaMemoryCommitted, ArenaBlockSize);
|
||||
AddGstat(NumArenas, 1);
|
||||
|
||||
/* Create & return arena header at beginning of block */
|
||||
// Create & return arena header at beginning of block
|
||||
Arena *arena = (Arena *)base;
|
||||
ZeroStruct(arena);
|
||||
arena->committed = ArenaBlockSize - ArenaHeaderSize;
|
||||
@ -52,8 +52,8 @@ void ReleaseArena(Arena *arena)
|
||||
ReleaseMemory(arena);
|
||||
}
|
||||
|
||||
/* Copy the memory from src to dst, replacing old contents.
|
||||
* Dst will expand if necessary. */
|
||||
// Copy the memory from src to dst, replacing old content.
|
||||
// Dst arena will expand if necessary.
|
||||
void CopyArena(Arena *dst, Arena *src)
|
||||
{
|
||||
ResetArena(dst);
|
||||
@ -65,7 +65,7 @@ void CopyArena(Arena *dst, Arena *src)
|
||||
|
||||
void ShrinkArena(Arena *arena)
|
||||
{
|
||||
/* Not implemented */
|
||||
// Not implemented
|
||||
Assert(0);
|
||||
}
|
||||
|
||||
@ -97,7 +97,7 @@ void *PushBytesNoZero(Arena *arena, u64 size, u64 align)
|
||||
u64 end_pos = start_pos + size;
|
||||
void *result = base + start_pos;
|
||||
|
||||
/* Commit new block(s) */
|
||||
// Commit new block(s)
|
||||
if (size > 0 && end_pos > arena->committed)
|
||||
{
|
||||
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;
|
||||
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"));
|
||||
}
|
||||
void *commit_address = base + arena->committed;
|
||||
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"));
|
||||
}
|
||||
arena->committed += commit_bytes;
|
||||
@ -196,10 +196,10 @@ void EndTempArena(TempArena temp)
|
||||
|
||||
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);
|
||||
|
||||
/* Use `BeginScratchNoConflict` if no conflicts are present */
|
||||
// Use `BeginScratchNoConflict` if no conflicts are present
|
||||
Assert(potential_conflict != 0);
|
||||
|
||||
Arena *scratch_arena = Base_tl.arenas.scratch[0];
|
||||
|
||||
@ -67,10 +67,10 @@ TempArena BeginScratch(Arena *potential_conflict);
|
||||
TempArena BeginScratchNoConflict_(void);
|
||||
void EndScratch(TempArena scratch_temp);
|
||||
|
||||
/* This macro declares an unused "arena" variable that will produce a shadowing
|
||||
* warning variable is present (due to shadowing). This is for catching obvious
|
||||
* cases of `BeginScratchNoConflict` getting called when an `arena` variable
|
||||
* already exists in the caller's scope. */
|
||||
// This macro declares an unused "arena" variable that will produce a shadowing
|
||||
// warning variable is present (due to shadowing). This is for catching obvious
|
||||
// cases of `BeginScratchNoConflict` getting called when an `arena` variable
|
||||
// already exists in the caller's scope.
|
||||
#define BeginScratchNoConflict() \
|
||||
BeginScratchNoConflict_(); \
|
||||
do { \
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
|
||||
void BootstrapAsync(void)
|
||||
{
|
||||
/* TODO: Dynamic lane counts */
|
||||
// TODO: Dynamic lane counts
|
||||
DispatchWave(Lit("Async"), 4, AsyncWorkerEntryPoint, 0);
|
||||
}
|
||||
|
||||
@ -39,7 +39,7 @@ void AsyncWorkerEntryPoint(WaveLaneCtx *lane)
|
||||
AsyncTickCtx tick = Zi;
|
||||
tick.arena = AcquireArena(Gibi(64));
|
||||
|
||||
/* Tick forever */
|
||||
// Tick forever
|
||||
for (;;)
|
||||
{
|
||||
AsyncWorkerCtx *w = &Base.async.worker;
|
||||
@ -49,7 +49,7 @@ void AsyncWorkerEntryPoint(WaveLaneCtx *lane)
|
||||
|
||||
if (lane->idx == 0)
|
||||
{
|
||||
/* Wait for signal */
|
||||
// Wait for signal
|
||||
{
|
||||
i64 cur_signal = Atomic64Fetch(&Base.async.signal.v);
|
||||
while (cur_signal <= w->last_seen_signal)
|
||||
@ -59,7 +59,7 @@ void AsyncWorkerEntryPoint(WaveLaneCtx *lane)
|
||||
}
|
||||
w->last_seen_signal = cur_signal;
|
||||
}
|
||||
/* Collect callbacks */
|
||||
// Collect callbacks
|
||||
{
|
||||
Lock lock = LockE(&Base.async.mutex);
|
||||
{
|
||||
|
||||
@ -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
|
||||
@ -13,7 +13,7 @@ BB_Buff BB_AcquireBuff(u64 arena_reserve)
|
||||
|
||||
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)
|
||||
{
|
||||
ReleaseArena(bb->arena);
|
||||
@ -49,7 +49,7 @@ BB_Writer BB_WriterFromBuff(BB_Buff *bb)
|
||||
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 result = BB_WriterFromBuff(bb);
|
||||
@ -59,19 +59,19 @@ BB_Writer BB_WriterFromBuffNoDebug(BB_Buff *bb)
|
||||
return result;
|
||||
}
|
||||
|
||||
/* FIXME: Handle overflowed bw */
|
||||
// FIXME: Handle overflowed bw
|
||||
u64 BB_GetNumBitsWritten(BB_Writer *bw)
|
||||
{
|
||||
return bw->cur_bit;
|
||||
}
|
||||
|
||||
/* FIXME: Handle overflowed bw */
|
||||
// FIXME: Handle overflowed bw
|
||||
u64 BB_GetNumBytesWritten(BB_Writer *bw)
|
||||
{
|
||||
return (bw->cur_bit + 7) >> 3;
|
||||
}
|
||||
|
||||
/* FIXME: Handle overflowed bw */
|
||||
// FIXME: Handle overflowed bw
|
||||
String BB_GetWritten(Arena *arena, BB_Writer *bw)
|
||||
{
|
||||
String result = Zi;
|
||||
@ -81,13 +81,13 @@ String BB_GetWritten(Arena *arena, BB_Writer *bw)
|
||||
return result;
|
||||
}
|
||||
|
||||
/* FIXME: Handle overflowed bw */
|
||||
// FIXME: Handle overflowed bw
|
||||
u8 *BB_GetWrittenRaw(BB_Writer *bw)
|
||||
{
|
||||
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 result = 0;
|
||||
@ -104,7 +104,7 @@ b32 BB_CheckWriterOverflowBits(BB_Writer *bw, u64 num_bits)
|
||||
Arena *arena = bb->arena;
|
||||
if (bytes_needed >= arena->pos)
|
||||
{
|
||||
/* Grow arena */
|
||||
// Grow arena
|
||||
u64 push_size = (((bytes_needed - arena->pos) / BB_WriterOverflowArenaPushSize) + 1) * BB_WriterOverflowArenaPushSize;
|
||||
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;
|
||||
if (bytes_needed > max_len)
|
||||
{
|
||||
/* Writer overflowed fixed buffer */
|
||||
// Writer overflowed fixed buffer
|
||||
#if BITBUFF_DEBUG
|
||||
Assert(0);
|
||||
#endif
|
||||
@ -130,7 +130,7 @@ b32 BB_CheckWriterOverflowBits(BB_Writer *bw, u64 num_bits)
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Align writer
|
||||
|
||||
/* Align the pos to the next byte */
|
||||
// Align the pos to the next byte
|
||||
void BB_WriteAlignToNextByte(BB_Writer *bw)
|
||||
{
|
||||
#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)
|
||||
{
|
||||
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))
|
||||
{
|
||||
return;
|
||||
@ -173,7 +173,7 @@ void BB_WriteUBitsNoMagic(BB_Writer *bw, u64 value, u8 num_bits)
|
||||
u8 offset = bw->cur_bit & 7;
|
||||
if (offset != 0)
|
||||
{
|
||||
/* Write unaligned bits */
|
||||
// Write unaligned bits
|
||||
u8 *at = bw->base + (bw->cur_bit >> 3);
|
||||
u8 num_mix_bits = MinU8((8 - offset), num_bits);
|
||||
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;
|
||||
}
|
||||
|
||||
/* cur_bit is now aligned to byte */
|
||||
// cur_bit is now aligned to byte
|
||||
u8 *at = bw->base + (bw->cur_bit >> 3);
|
||||
u8 num_bytes = (num_bits + 7) >> 3;
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
BB_WriteUBits(bw, value, 1);
|
||||
@ -221,8 +221,8 @@ b32 BB_WriteBit(BB_Writer *bw, u8 value)
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Write variable length integers
|
||||
|
||||
/* Writes a variable length unsigned integer.
|
||||
* Value is written in chunks of 7 bits w/ 8th bit signaling continuation. */
|
||||
// Writes a variable length unsigned integer.
|
||||
// Value is written in chunks of 7 bits w/ 8th bit signaling continuation.
|
||||
void BB_WriteUV(BB_Writer *bw, u64 value)
|
||||
{
|
||||
BB_WriteDebugMagic(bw, BB_DebugMagicKind_UV, 0);
|
||||
@ -235,9 +235,9 @@ void BB_WriteUV(BB_Writer *bw, u64 value)
|
||||
BB_WriteUBits(bw, value, 8);
|
||||
}
|
||||
|
||||
/* Writes a variable length signed integer.
|
||||
* 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. */
|
||||
// Writes a variable length signed integer.
|
||||
// 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.
|
||||
void BB_WriteIV(BB_Writer *bw, i64 value)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
tc >>= 6;
|
||||
first_byte |= (tc > 0) << 7; /* Cont bit */
|
||||
first_byte |= sign_bit << 6; /* Sign bit */
|
||||
first_byte |= (tc > 0) << 7; // Cont bit
|
||||
first_byte |= sign_bit << 6; // Sign bit
|
||||
BB_WriteUBits(bw, first_byte, 8);
|
||||
|
||||
if (tc > 0)
|
||||
@ -319,7 +319,7 @@ void BB_WriteString(BB_Writer *bw, String s)
|
||||
|
||||
void BB_WriteBytes(BB_Writer *bw, String bytes)
|
||||
{
|
||||
/* Align start of bytes */
|
||||
// Align start of bytes
|
||||
BB_WriteAlignToNextByte(bw);
|
||||
|
||||
u64 num_bits = bytes.len << 3;
|
||||
@ -397,7 +397,7 @@ BB_Reader BB_ReaderFromBuff(BB_Buff *bb)
|
||||
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 result = BB_ReaderFromBuff(bb);
|
||||
@ -407,29 +407,29 @@ BB_Reader BB_ReaderFromBuffNoDebug(BB_Buff *bb)
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Returns the number of bits read from the bitbuff */
|
||||
/* FIXME: Handle overflowed br */
|
||||
// Returns the number of bits read from the bitbuff
|
||||
// FIXME: Handle overflowed br
|
||||
u64 BB_GetCurrentReaderBit(BB_Reader *br)
|
||||
{
|
||||
return br->cur_bit;
|
||||
}
|
||||
|
||||
/* Returns the number of *full* bytes read from the bitbuff */
|
||||
/* FIXME: Handle overflowed br */
|
||||
// Returns the number of *full* bytes read from the bitbuff
|
||||
// FIXME: Handle overflowed br
|
||||
u64 BB_GetCurrentReaderByte(BB_Reader *br)
|
||||
{
|
||||
return br->cur_bit >> 3;
|
||||
}
|
||||
|
||||
/* Returns the number of bits left until the bitbuff overflows */
|
||||
/* FIXME: Handle overflowed br */
|
||||
// Returns the number of bits left until the bitbuff overflows
|
||||
// FIXME: Handle overflowed br
|
||||
u64 BB_NumBitsRemaining(BB_Reader *br)
|
||||
{
|
||||
return (br->base_len << 3) - br->cur_bit;
|
||||
}
|
||||
|
||||
/* Returns the number of *full* bytes left until the bitbuff overflows */
|
||||
/* FIXME: Handle overflowed br */
|
||||
// Returns the number of *full* bytes left until the bitbuff overflows
|
||||
// FIXME: Handle overflowed br
|
||||
u64 BB_NumBytesRemaining(BB_Reader *br)
|
||||
{
|
||||
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;
|
||||
if (bits_needed > base_len_bits)
|
||||
{
|
||||
/* Tried to read past bitbuff memory */
|
||||
// Tried to read past bitbuff memory
|
||||
#if BITBUFF_DEBUG
|
||||
Assert(0);
|
||||
#endif
|
||||
@ -463,7 +463,7 @@ b32 BB_CheckReaderOverflowBits(BB_Reader *br, u64 num_bits)
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Align reader
|
||||
|
||||
/* Align the pos to the next byte */
|
||||
// Align the pos to the next byte
|
||||
void BB_ReadAlignToNextByte(BB_Reader *br)
|
||||
{
|
||||
#if BITBUFF_DEBUG
|
||||
@ -518,7 +518,7 @@ u64 BB_ReadUBitsNoMagic(BB_Reader *br, u8 num_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 num_bytes = (num_bits + 7) >> 3;
|
||||
u64 tmp = 0;
|
||||
@ -556,8 +556,8 @@ u8 BB_ReadBit(BB_Reader *br)
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Read variable length integer
|
||||
|
||||
/* Read a variable length unsigned integer.
|
||||
* See BB_WriteUV for details. */
|
||||
// Read a variable length unsigned integer.
|
||||
// See BB_WriteUV for details.
|
||||
u64 BB_ReadUV(BB_Reader *br)
|
||||
{
|
||||
BB_ReadDebugMagic(br, BB_DebugMagicKind_UV, 0);
|
||||
@ -576,8 +576,8 @@ u64 BB_ReadUV(BB_Reader *br)
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Read a variable length signed integer.
|
||||
* See BB_WriteIV for details. */
|
||||
// Read a variable length signed integer.
|
||||
// See BB_WriteIV for details.
|
||||
i64 BB_ReadIV(BB_Reader *br)
|
||||
{
|
||||
BB_ReadDebugMagic(br, BB_DebugMagicKind_IV, 0);
|
||||
@ -606,7 +606,7 @@ i64 BB_ReadIV(BB_Reader *br)
|
||||
i64 result;
|
||||
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);
|
||||
}
|
||||
else
|
||||
@ -663,7 +663,7 @@ String BB_ReadString(Arena *arena, BB_Reader *br)
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
BB_ReadAlignToNextByte(br);
|
||||
@ -716,7 +716,7 @@ void BB_ReadSeekToByte(BB_Reader *br, u64 pos)
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Tried to seek byte backwards in reader */
|
||||
// Tried to seek byte backwards in reader
|
||||
Assert(0);
|
||||
br->overflowed = 1;
|
||||
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;
|
||||
u8 stored_num_bits = (stored >> 16) & 0xFF;
|
||||
|
||||
/* Verify stored magic match */
|
||||
// Verify stored magic match
|
||||
Assert(expected_magic == stored_magic);
|
||||
|
||||
/* Verify stored bit count match */
|
||||
// Verify stored bit count match
|
||||
Assert(expected_num_bits == stored_num_bits);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,20 +1,18 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Bitbuff types
|
||||
|
||||
//- Buff
|
||||
Struct(BB_Buff)
|
||||
{
|
||||
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;
|
||||
|
||||
/* 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;
|
||||
};
|
||||
|
||||
//- 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
|
||||
Struct(BB_Writer)
|
||||
{
|
||||
@ -27,7 +25,6 @@ Struct(BB_Writer)
|
||||
#endif
|
||||
};
|
||||
|
||||
//- Reader
|
||||
Struct(BB_Reader)
|
||||
{
|
||||
b32 overflowed;
|
||||
@ -44,7 +41,7 @@ Struct(BB_Reader)
|
||||
|
||||
#if BITBUFF_DEBUG
|
||||
|
||||
/* Magic numbers inserted to verify read/write type & length */
|
||||
// Magic numbers inserted to verify read/write type & length
|
||||
Enum(BB_DebugMagicKind)
|
||||
{
|
||||
BB_DebugMagicKind_AlignBytes = 0x20A4,
|
||||
|
||||
@ -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
|
||||
|
||||
BuddyCtx *AcquireBuddyCtx(u64 reserve)
|
||||
{
|
||||
/* TODO: Determine meta reserve dynamically */
|
||||
// TODO: Determine meta reserve dynamically
|
||||
Arena *meta_arena = AcquireArena(Gibi(64));
|
||||
BuddyCtx *ctx = PushStruct(meta_arena, BuddyCtx);
|
||||
ctx->meta_arena = meta_arena;
|
||||
ctx->data_arena = AcquireArena(reserve);
|
||||
|
||||
/* TODO: Minimum block size */
|
||||
// TODO: Minimum block size
|
||||
ctx->levels = PushStructs(ctx->meta_arena, BuddyLevel, 64);
|
||||
for (u64 i = 0; i < 64; ++i)
|
||||
{
|
||||
@ -37,7 +37,7 @@ BuddyBlock *GetUnusedBuddyBlock(BuddyCtx *ctx, BuddyLevel *level)
|
||||
{
|
||||
BuddyBlock *block = 0;
|
||||
|
||||
/* TODO: Tier oob check */
|
||||
// TODO: Tier oob check
|
||||
if (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];
|
||||
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);
|
||||
left->is_used = 1;
|
||||
left->level = level;
|
||||
left->parent = parent_block;
|
||||
left->memory = parent_block->memory;
|
||||
|
||||
/* Create right LAX block from parent block */
|
||||
// Create right (unused) block from parent block
|
||||
BuddyBlock *right = PushBuddyBlock(ctx);
|
||||
right->is_used = 0;
|
||||
right->level = level;
|
||||
@ -84,7 +84,7 @@ BuddyBlock *GetUnusedBuddyBlock(BuddyCtx *ctx, BuddyLevel *level)
|
||||
{
|
||||
Arena *arena = ctx->data_arena;
|
||||
|
||||
/* Grow arena */
|
||||
// Grow arena
|
||||
i64 level_commit_diff = (level->size * 2) - arena->pos;
|
||||
if (level_commit_diff > 0)
|
||||
{
|
||||
@ -92,13 +92,13 @@ BuddyBlock *GetUnusedBuddyBlock(BuddyCtx *ctx, BuddyLevel *level)
|
||||
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);
|
||||
left->is_used = 1;
|
||||
left->level = level;
|
||||
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);
|
||||
right->is_used = 0;
|
||||
right->level = level;
|
||||
@ -133,7 +133,7 @@ BuddyBlock *PushBuddyBlock(BuddyCtx *ctx)
|
||||
|
||||
void PopBuddyBlock(BuddyCtx *ctx, BuddyLevel *level, BuddyBlock *block)
|
||||
{
|
||||
/* Remove from unused list */
|
||||
// Remove from unused list
|
||||
{
|
||||
BuddyBlock *prev = block->prev;
|
||||
BuddyBlock *next = block->next;
|
||||
@ -158,13 +158,13 @@ BuddyBlock *AcquireBuddyBlock(BuddyCtx *ctx, u64 size)
|
||||
{
|
||||
if (size > 0x00FFFFFFFFFFFFFFULL)
|
||||
{
|
||||
/* TODO: Error */
|
||||
// TODO: Error
|
||||
Assert(0);
|
||||
}
|
||||
|
||||
/* TODO: Minimum block size */
|
||||
// TODO: Minimum block size
|
||||
|
||||
/* TODO: Faster MSB calculation */
|
||||
// TODO: Faster MSB calculation
|
||||
|
||||
u64 desired_block_size = 1;
|
||||
u64 desired_level_tier = 0;
|
||||
@ -187,11 +187,11 @@ void ReleaseBuddyBlock(BuddyBlock *block)
|
||||
BuddyBlock *sibling = block->sibling;
|
||||
if (!sibling->is_used && parent != 0)
|
||||
{
|
||||
/* Merge siblings */
|
||||
// Merge siblings
|
||||
BuddyCtx *ctx = level->ctx;
|
||||
PopBuddyBlock(ctx, level, block);
|
||||
PopBuddyBlock(ctx, level, sibling);
|
||||
/* Release parent */
|
||||
// Release parent
|
||||
ReleaseBuddyBlock(parent);
|
||||
}
|
||||
else
|
||||
|
||||
@ -9,7 +9,7 @@ Struct(BuddyBlock)
|
||||
BuddyBlock *parent;
|
||||
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 *next;
|
||||
|
||||
@ -20,7 +20,7 @@ Struct(BuddyBlock)
|
||||
Struct(BuddyLevel)
|
||||
{
|
||||
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;
|
||||
u64 size;
|
||||
BuddyBlock *first_unused_block;
|
||||
|
||||
@ -133,18 +133,18 @@ Struct(ControllerEvent)
|
||||
{
|
||||
ControllerEventKind kind;
|
||||
|
||||
/* ControllerEventKind_ButtonDown */
|
||||
/* ControllerEventKind_ButtonUp */
|
||||
// ControllerEventKind_ButtonDown
|
||||
// ControllerEventKind_ButtonUp
|
||||
Button button;
|
||||
b32 is_repeat;
|
||||
|
||||
/* ControllerEventKind_Text */
|
||||
// ControllerEventKind_Text
|
||||
u32 text_codepoint;
|
||||
|
||||
/* ControllerEventKind_CursorMove */
|
||||
// ControllerEventKind_CursorMove
|
||||
Vec2I32 cursor_pos;
|
||||
|
||||
/* ControllerEventKind_MouseMove */
|
||||
// ControllerEventKind_MouseMove
|
||||
Vec2I32 mouse_delta;
|
||||
};
|
||||
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ @hookdecl Not-equal futex ops
|
||||
|
||||
/* Similar to Win32 WaitOnAddress & WakeByAddressAll
|
||||
* i.e. - Suprious wait until value at address != cmp */
|
||||
// Similar to Win32 WaitOnAddress & WakeByAddressAll
|
||||
// i.e. - Suprious wait until value at address != cmp
|
||||
|
||||
void FutexYieldNeq(volatile void *addr, void *cmp, u8 cmp_size);
|
||||
void FutexWakeNeq(void *addr);
|
||||
@ -10,13 +10,11 @@ void FutexWakeNeq(void *addr);
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ @hookdecl Greater-than-or-equal futex ops
|
||||
|
||||
/* Similar to Win32 WaitOnAddress & WakeByAddressAll
|
||||
* 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
|
||||
* wake when the futex progresses past the specified target value, rather than
|
||||
* wake every time the futex is modified.
|
||||
*/
|
||||
// Similar to Win32 WaitOnAddress & WakeByAddressAll
|
||||
// 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
|
||||
// wake when the futex progresses past the specified target value, rather than
|
||||
// wake every time the futex is modified.
|
||||
|
||||
void FutexYieldGte(volatile void *addr, void *cmp, u8 cmp_size);
|
||||
void FutexWakeGte(void *addr);
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
/* Application wide statistics */
|
||||
// Application wide statistics
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Gstat types
|
||||
|
||||
@ -26,7 +26,7 @@ Struct(LogEventsArray)
|
||||
|
||||
#define LogLevel(l) (l <= LogLevel_CompTime)
|
||||
|
||||
/* Log level configuration */
|
||||
// Log level configuration
|
||||
#ifndef LogLevel_CompTime
|
||||
#if IsRtcEnabled
|
||||
#define LogLevel_CompTime LogLevel_Debug
|
||||
@ -132,7 +132,7 @@ Global Readonly LogLevelSettings log_settings[LogLevel_Count] = {
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ @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 Log_(i32 level, String msg);
|
||||
|
||||
@ -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
|
||||
@ -163,7 +163,7 @@ i64 SignF64(f64 f)
|
||||
|
||||
//- Pow u64
|
||||
|
||||
/* Taken from https://gist.github.com/orlp/3551590 */
|
||||
// Taken from https://gist.github.com/orlp/3551590
|
||||
u64 PowU64(u64 base, u8 exp)
|
||||
{
|
||||
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, 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,
|
||||
@ -207,7 +207,7 @@ u64 PowU64(u64 base, u8 exp)
|
||||
{
|
||||
case 255:
|
||||
{
|
||||
/* 255 = overflow, return 0 */
|
||||
// 255 = overflow, return 0
|
||||
if (base == 1)
|
||||
{
|
||||
return 1;
|
||||
@ -258,8 +258,8 @@ u64 PowU64(u64 base, u8 exp)
|
||||
|
||||
//- Logn
|
||||
|
||||
/* Based on FreeBSD's implementation
|
||||
* https://github.com/freebsd/freebsd-src/blob/main/lib/msun/src/e_logf.c */
|
||||
// Based on FreeBSD's implementation
|
||||
// https://github.com/freebsd/freebsd-src/blob/main/lib/msun/src/e_logf.c
|
||||
f32 LnF32(f32 x)
|
||||
{
|
||||
PERSIST const f32 ln2_hi = 6.9313812256e-01f;
|
||||
@ -273,12 +273,12 @@ f32 LnF32(f32 x)
|
||||
f32 two_p25 = 3.3554432000e+07;
|
||||
if ((x_int & 0x7fffffff) == 0)
|
||||
{
|
||||
/* Return -inf if x is 0 */
|
||||
// Return -inf if x is 0
|
||||
return -F32Infinity;
|
||||
}
|
||||
else if (x_int < 0)
|
||||
{
|
||||
/* Return NaN if x is negative */
|
||||
// Return NaN if x is negative
|
||||
return F32Nan;
|
||||
}
|
||||
k -= 25;
|
||||
@ -352,8 +352,8 @@ f32 LnF32(f32 x)
|
||||
|
||||
//- Exp
|
||||
|
||||
/* Based on FreeBSD's implementation
|
||||
* https://github.com/freebsd/freebsd-src/blob/main/lib/msun/src/e_expf.c */
|
||||
// Based on FreeBSD's implementation
|
||||
// https://github.com/freebsd/freebsd-src/blob/main/lib/msun/src/e_expf.c
|
||||
f32 ExpF32(f32 x)
|
||||
{
|
||||
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);
|
||||
x_uint &= 0x7fffffff;
|
||||
|
||||
/* Filter out non-finite argument */
|
||||
// Filter out non-finite argument
|
||||
if (x_uint >= 0x42b17218)
|
||||
{ /* if |x|>=88.721... */
|
||||
{ // if |x|>=88.721...
|
||||
if (x_uint > 0x7f800000)
|
||||
{
|
||||
return x + x; /* NaN */
|
||||
return x + x; // NaN
|
||||
}
|
||||
else if (x_uint == 0x7f800000)
|
||||
{
|
||||
@ -382,17 +382,17 @@ f32 ExpF32(f32 x)
|
||||
}
|
||||
if (x > o_threshold)
|
||||
{
|
||||
/* Overflow */
|
||||
// Overflow
|
||||
return F32Infinity;
|
||||
}
|
||||
else if (x < u_threshold)
|
||||
{
|
||||
/* Underflow */
|
||||
// Underflow
|
||||
return two_m100 * two_m100;
|
||||
}
|
||||
}
|
||||
|
||||
/* Argument reduction */
|
||||
// Argument reduction
|
||||
i32 k = 0;
|
||||
f32 hi = 0;
|
||||
f32 lo = 0;
|
||||
@ -467,12 +467,12 @@ f32 PowF32(f32 a, f32 b)
|
||||
{
|
||||
if (a >= 0)
|
||||
{
|
||||
/* a is positive */
|
||||
// a is positive
|
||||
return ExpF32(LnF32(a) * b);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* a is negative */
|
||||
// a is negative
|
||||
i32 res_sign = RoundF32ToI32(b) % 2 == 0 ? 1 : -1;
|
||||
return ExpF32(LnF32(-a) * b) * res_sign;
|
||||
}
|
||||
@ -526,24 +526,25 @@ u64 AlignU64ToNextPow2(u64 x)
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Trig
|
||||
|
||||
/* Functions based on Cephes implementation (https://www.netlib.org/cephes/):
|
||||
* - SinApproxF32
|
||||
* - CosApproxF32
|
||||
* - ReduceToPio4
|
||||
* - ArcTanF32
|
||||
*/
|
||||
// Functions based on Cephes implementation (https://www.netlib.org/cephes/):
|
||||
// - SinApproxF32
|
||||
// - CosApproxF32
|
||||
// - ReduceToPio4
|
||||
// - ArcTanF32
|
||||
|
||||
//- Reduce
|
||||
/* Reduce postive x to range [0, Pi/4] (Cody-Waite argument reduction).
|
||||
* Returns 0 if x > (2^24 - 1);
|
||||
* Sets octant_out=-1 on error. */
|
||||
//
|
||||
// Reduce postive x to range [0, Pi/4] (Cody-Waite argument reduction)
|
||||
//
|
||||
// Returns 0 if x > (2^24 - 1)
|
||||
// Sets octant_out=-1 on error
|
||||
f32 ReduceToPio4(f32 x, i32 *octant_out)
|
||||
{
|
||||
i32 octant = -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;
|
||||
if (octant & 1)
|
||||
{
|
||||
@ -551,7 +552,7 @@ f32 ReduceToPio4(f32 x, i32 *octant_out)
|
||||
y += 1.0;
|
||||
}
|
||||
|
||||
/* Modulo 360 degrees */
|
||||
// Modulo 360 degrees
|
||||
octant &= 7;
|
||||
|
||||
if (x > 8192)
|
||||
@ -560,7 +561,7 @@ f32 ReduceToPio4(f32 x, i32 *octant_out)
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Extended precision modular arithmetic */
|
||||
// Extended precision modular arithmetic
|
||||
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
|
||||
/* Approximate sin in range [0, Pi/4] */
|
||||
//
|
||||
// Approximate sin in range [0, Pi/4]
|
||||
f32 SinApproxF32(f32 x)
|
||||
{
|
||||
f32 x_sq = x * x;
|
||||
@ -602,7 +604,7 @@ f32 SinF32(f32 x)
|
||||
i32 octant;
|
||||
x = ReduceToPio4(x, &octant);
|
||||
|
||||
/* Reflect in x axis */
|
||||
// Reflect in x axis
|
||||
if (octant > 3)
|
||||
{
|
||||
sign = -sign;
|
||||
@ -634,7 +636,7 @@ f32 CosF32(f32 x)
|
||||
i32 octant;
|
||||
x = ReduceToPio4(x, &octant);
|
||||
|
||||
/* Reflect in x axis */
|
||||
// Reflect in x axis
|
||||
if (octant > 3)
|
||||
{
|
||||
sign = -sign;
|
||||
@ -664,15 +666,15 @@ f32 ArcTanF32(f32 x)
|
||||
x = -x;
|
||||
}
|
||||
|
||||
/* Reduce range */
|
||||
// Reduce range
|
||||
f32 y;
|
||||
if (x > 2.414213562373095)
|
||||
{ /* tan((Pi / 8) * 3) */
|
||||
{ // tan((Pi / 8) * 3)
|
||||
y = Pi / 2;
|
||||
x = -(1.f / x);
|
||||
}
|
||||
else if (x > 0.4142135623730950)
|
||||
{ /* tan(Pi / 8) */
|
||||
{ // tan(Pi / 8)
|
||||
y = Pi / 4;
|
||||
x = (x - 1.f) / (x + 1.f);
|
||||
}
|
||||
@ -740,21 +742,21 @@ f32 ArcTan2F32(f32 y, f32 x)
|
||||
//- ArcSin
|
||||
f32 ArcSinF32(f32 x)
|
||||
{
|
||||
/* TODO: Dedicated arcsin approximation */
|
||||
// TODO: Dedicated arcsin approximation
|
||||
return ArcTan2F32(x, SqrtF32(1.0f - (x * x)));
|
||||
}
|
||||
|
||||
//- ArcCos
|
||||
f32 ArcCosF32(f32 x)
|
||||
{
|
||||
/* TODO: Dedicated arccos approximation */
|
||||
// TODO: Dedicated arccos approximation
|
||||
return (Pi / 2.0f) - ArcTan2F32(x, SqrtF32(1.0f - (x * x)));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Angle unwind
|
||||
|
||||
/* Returns angle in range [-Pi, Pi] */
|
||||
// Returns angle in range [-Pi, Pi]
|
||||
f32 UnwindAngleF32(f32 a)
|
||||
{
|
||||
f32 d = ModF32(a, Tau);
|
||||
@ -987,21 +989,21 @@ f32 DotVec2(Vec2 a, Vec2 b)
|
||||
return a.x * b.x + a.y * b.y;
|
||||
}
|
||||
|
||||
/* Returns signed area between vectors (positive in clockwise direction)
|
||||
* AKA perpendicular dot product
|
||||
* AKA 2d cross-product */
|
||||
// Returns signed area between vectors (positive in clockwise direction)
|
||||
// AKA perpendicular dot product
|
||||
// AKA 2d cross-product
|
||||
f32 WedgeVec2(Vec2 a, Vec2 b)
|
||||
{
|
||||
return a.x * b.y - a.y * b.x;
|
||||
}
|
||||
|
||||
/* Clockwise (right) perpendicular vector */
|
||||
// Clockwise (right) perpendicular vector
|
||||
Vec2 PerpVec2(Vec2 a)
|
||||
{
|
||||
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)
|
||||
{
|
||||
return VEC2(s * -a.y, s * a.x);
|
||||
@ -1047,7 +1049,7 @@ Vec2I32 CeilVec2ToI32(Vec2 a)
|
||||
|
||||
//- 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)
|
||||
{
|
||||
f32 w = WedgeVec2(a, b);
|
||||
@ -1093,7 +1095,7 @@ Vec2 ClosestPointFromRay(Vec2 ray_pos, Vec2 ray_dir_norm, Vec2 p)
|
||||
|
||||
//- Lerp
|
||||
|
||||
/* Interpolate position vectors */
|
||||
// Interpolate position vectors
|
||||
Vec2 LerpVec2(Vec2 val0, Vec2 val1, f32 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));
|
||||
}
|
||||
|
||||
/* Interpolate direction vectors (spherical lerp) */
|
||||
// Interpolate direction vectors (spherical lerp)
|
||||
Vec2 SlerpVec2(Vec2 val0, Vec2 val1, f32 t)
|
||||
{
|
||||
f32 rot = LerpAngleF32(AngleFromVec2(val0), AngleFromVec2(val1), t);
|
||||
@ -1424,7 +1426,7 @@ Vec2 InvertXformBasisMulV2(Xform xf, Vec2 v)
|
||||
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)
|
||||
{
|
||||
Xform inv = InvertXform(xf);
|
||||
@ -1479,7 +1481,7 @@ Vec2 ScaleFromXform(Xform xf)
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ 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 result;
|
||||
|
||||
@ -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 Tau ((f32)6.28318530717958647693)
|
||||
@ -145,12 +145,12 @@ Struct(Rng3U64) { Vec3U64 p0; Vec3U64 p1; };
|
||||
|
||||
Struct(Xform)
|
||||
{
|
||||
Vec2 bx; /* X basis vector (x axis) */
|
||||
Vec2 by; /* Y basis vector (y axis)*/
|
||||
Vec2 og; /* Translation vector (origin) */
|
||||
Vec2 bx; // X basis vector (x axis)
|
||||
Vec2 by; // Y basis vector (y axis)
|
||||
Vec2 og; // Translation vector (origin)
|
||||
};
|
||||
|
||||
/* (T)ranslation, (R)otation, (S)cale */
|
||||
// (T)ranslation, (R)otation, (S)cale
|
||||
Struct(Trs)
|
||||
{
|
||||
Vec2 t;
|
||||
@ -285,7 +285,7 @@ f32 ArcCosF32(f32 x);
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Angle unwind
|
||||
|
||||
/* Returns angle in range [-Pi, Pi] */
|
||||
// Returns angle in range [-Pi, Pi]
|
||||
f32 UnwindAngleF32(f32 a);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
@ -46,4 +46,4 @@ i32 memcmp(const void *p1, const void *p2, u64 count)
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif /* !IsCrtlibEnabled */
|
||||
#endif
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
/* Based on Jon Maiga's "mx3"
|
||||
* https://jonkagstrom.com/mx3/mx3_rev2.html
|
||||
*/
|
||||
// Based on Jon Maiga's "mx3"
|
||||
// https://jonkagstrom.com/mx3/mx3_rev2.html
|
||||
u64 RandU64FromSeed(u64 seed)
|
||||
{
|
||||
seed = (seed ^ (seed >> 32)) * 0xbea225f9eb34556d;
|
||||
|
||||
@ -3,11 +3,11 @@
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
/* 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
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
@ -15,7 +15,7 @@ void BootstrapResources(u64 archive_strings_count, String *archive_strings)
|
||||
u64 magic = BB_ReadUBits(&br, 64);
|
||||
Assert(magic == ResourceEmbeddedMagic);
|
||||
|
||||
/* Create & insert entries */
|
||||
// Create & insert entries
|
||||
u64 num_entries = BB_ReadUBits(&br, 64);
|
||||
for (u64 i = 0; i < num_entries; ++i)
|
||||
{
|
||||
|
||||
@ -161,7 +161,7 @@ Vec2 NdcFromUv(Vec2 uv)
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ String helpers
|
||||
|
||||
/* https://therealmjp.github.io/posts/hlsl-printf/ */
|
||||
// https://therealmjp.github.io/posts/hlsl-printf/
|
||||
template<typename T>
|
||||
u32 U32FromChar(in T c)
|
||||
{
|
||||
|
||||
@ -1,8 +1,6 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Conversion helpers
|
||||
|
||||
//- Char conversion
|
||||
|
||||
String StringFromChar(Arena *arena, char c)
|
||||
{
|
||||
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)
|
||||
{
|
||||
/* Base too large */
|
||||
// Base too large
|
||||
Assert(base <= (countof(IntChars) - 1));
|
||||
String result = Zi;
|
||||
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);
|
||||
do
|
||||
{
|
||||
@ -38,7 +34,7 @@ String StringFromUint(Arena *arena, u64 n, u64 base, u64 zfill)
|
||||
++result.len;
|
||||
}
|
||||
|
||||
/* Reverse text into final string */
|
||||
// Reverse text into final string
|
||||
result.text = PushStructsNoZero(arena, u8, result.len);
|
||||
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;
|
||||
}
|
||||
|
||||
//- Signed int conversion
|
||||
|
||||
String StringFromSint(Arena *arena, i64 n, u64 base, u64 zfill)
|
||||
{
|
||||
String result = Zi;
|
||||
@ -99,8 +93,6 @@ String StringFromSints(Arena *arena, u64 sints_count, i64 *sints, u64 base, u64
|
||||
return result;
|
||||
}
|
||||
|
||||
//- Floating point conversion
|
||||
|
||||
String StringFromFloat(Arena *arena, f64 f, u32 precision)
|
||||
{
|
||||
String result = Zi;
|
||||
@ -128,15 +120,15 @@ String StringFromFloat(Arena *arena, f64 f, u32 precision)
|
||||
++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);
|
||||
|
||||
f64 part_whole = TruncF64(f);
|
||||
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);
|
||||
u64 backwards_text_len = 0;
|
||||
do
|
||||
@ -147,7 +139,7 @@ String StringFromFloat(Arena *arena, f64 f, u32 precision)
|
||||
part_whole = TruncF64(part_whole / 10.0);
|
||||
} while (part_whole > 0);
|
||||
|
||||
/* Reverse text into final string */
|
||||
// Reverse text into final string
|
||||
PushStructsNoZero(arena, u8, backwards_text_len);
|
||||
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)
|
||||
{
|
||||
StringFromChar(arena, '.');
|
||||
@ -191,8 +183,6 @@ String StringFromFloats(Arena *arena, u64 floats_count, f64 *floats, u32 precisi
|
||||
return result;
|
||||
}
|
||||
|
||||
//- Pointer conversion
|
||||
|
||||
String StringFromPtr(Arena *arena, void *ptr)
|
||||
{
|
||||
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 result = Zi;
|
||||
@ -217,8 +205,6 @@ String StringFromhandle(Arena *arena, u64 v0, u64 v1)
|
||||
return result;
|
||||
}
|
||||
|
||||
//- Uid conversion
|
||||
|
||||
String StringFromUid(Arena *arena, Uid uid)
|
||||
{
|
||||
String result = Zi;
|
||||
@ -227,12 +213,9 @@ String StringFromUid(Arena *arena, Uid uid)
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ String helpers
|
||||
|
||||
//- Copy
|
||||
|
||||
String PushString(Arena *arena, String src)
|
||||
{
|
||||
String result = Zi;
|
||||
@ -251,8 +234,6 @@ String CopyString(String dst, String src)
|
||||
return result;
|
||||
}
|
||||
|
||||
//- Repeat
|
||||
|
||||
String RepeatString(Arena *arena, String src, u64 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 new_str = Zi;
|
||||
@ -280,10 +259,8 @@ String CatString(Arena *arena, String str1, String str2)
|
||||
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 pieces = Zi;
|
||||
@ -359,9 +336,7 @@ String ReplaceString(Arena *arena, String str, String old_pattern, String new_pa
|
||||
return result;
|
||||
}
|
||||
|
||||
//- Indent
|
||||
|
||||
/* NOTE: Really slow */
|
||||
// NOTE: Really slow
|
||||
String IndentString(Arena *arena, String str, u32 indent)
|
||||
{
|
||||
TempArena scratch = BeginScratch(arena);
|
||||
@ -396,8 +371,6 @@ String IndentString(Arena *arena, String str, u32 indent)
|
||||
};
|
||||
}
|
||||
|
||||
//- Lower
|
||||
|
||||
String LowerString(Arena *arena, String str)
|
||||
{
|
||||
String result = Zi;
|
||||
@ -417,8 +390,6 @@ String LowerString(Arena *arena, String str)
|
||||
return result;
|
||||
}
|
||||
|
||||
//- Compare
|
||||
|
||||
b32 MatchString(String str1, String str2)
|
||||
{
|
||||
b32 eq = 1;
|
||||
@ -440,8 +411,6 @@ b32 MatchString(String str1, String str2)
|
||||
return eq;
|
||||
}
|
||||
|
||||
//- Match
|
||||
|
||||
b32 StringContains(String str, String substring)
|
||||
{
|
||||
if (substring.len > str.len)
|
||||
@ -606,25 +575,27 @@ String TrimWhitespace(String s)
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ 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).
|
||||
*
|
||||
* Example:
|
||||
* FormatString(arena, Lit("Hello there %F"), FmtString(Lit("George")))
|
||||
*
|
||||
* NOTE: FmtEnd must be passed as the last arg in the va_list
|
||||
*
|
||||
* Format arguments:
|
||||
* FmtChar: Format a single u8 character
|
||||
* FmtString: Format a `string` struct
|
||||
* FmtUint: Format a u64
|
||||
* FmtSint: Format an i64
|
||||
* FmtFloat: Format an f64 with DefaultFmtPrecision
|
||||
* 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
|
||||
*/
|
||||
//
|
||||
// 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")))
|
||||
//
|
||||
// NOTE: FmtEnd must be passed as the last arg in the va_list
|
||||
//
|
||||
// Format arguments:
|
||||
// FmtChar: Format a single u8 character
|
||||
// FmtString: Format a `string` struct
|
||||
// FmtUint: Format a u64
|
||||
// FmtSint: Format an i64
|
||||
// FmtFloat: Format an f64 with DefaultFmtPrecision
|
||||
// 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
|
||||
//
|
||||
|
||||
String FormatString(Arena *arena, String fmt, FmtArgArray args)
|
||||
{
|
||||
String result = Zi;
|
||||
@ -637,11 +608,11 @@ String FormatString(Arena *arena, String fmt, FmtArgArray args)
|
||||
{
|
||||
u8 *next = ((c + 1) < end) ? (c + 1) : (u8 *)"\0";
|
||||
|
||||
/* Escape '%%' */
|
||||
// Escape '%%'
|
||||
b32 escape = !no_more_valid_args && *c == '%' && *next == '%';
|
||||
if (escape)
|
||||
{
|
||||
/* Skip the escaped '%' char from parsing */
|
||||
// Skip the escaped '%' char from parsing
|
||||
++c;
|
||||
}
|
||||
|
||||
@ -664,7 +635,7 @@ String FormatString(Arena *arena, String fmt, FmtArgArray args)
|
||||
{
|
||||
default:
|
||||
{
|
||||
/* Unknown format type */
|
||||
// Unknown format type
|
||||
Assert(0);
|
||||
parsed_arg = PushString(arena, Lit("<?>"));
|
||||
no_more_valid_args = 1;
|
||||
@ -762,22 +733,22 @@ String FormatString(Arena *arena, String fmt, FmtArgArray args)
|
||||
|
||||
case FmtArgKind_End:
|
||||
{
|
||||
/* Unexpected end. Not enough FMT args passed to function. */
|
||||
// Unexpected end. Not enough FMT args passed to function.
|
||||
Assert(0);
|
||||
parsed_arg = PushString(arena, Lit("<?>"));
|
||||
no_more_valid_args = 1;
|
||||
} break;
|
||||
}
|
||||
|
||||
/* Update final string len / start */
|
||||
// Update final string len / start
|
||||
result.len += parsed_arg.len;
|
||||
|
||||
/* Skip 'F' from parsing */
|
||||
// Skip 'F' from parsing
|
||||
++c;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Parse character normally */
|
||||
// Parse character normally
|
||||
StringFromChar(arena, *c);
|
||||
++result.len;
|
||||
}
|
||||
@ -791,7 +762,7 @@ String FormatString(Arena *arena, String fmt, FmtArgArray args)
|
||||
if (arg_idx < args.count)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -829,7 +800,7 @@ FmtArgArray FmtArgsFromVaList(Arena *arena, va_list args)
|
||||
{
|
||||
default:
|
||||
{
|
||||
/* End/Invalid arg reached */
|
||||
// End/Invalid arg reached
|
||||
done = 1;
|
||||
} break;
|
||||
|
||||
@ -852,7 +823,7 @@ FmtArgArray FmtArgsFromVaList(Arena *arena, va_list args)
|
||||
case FmtArgKind_Uid:
|
||||
case FmtArgKind_Handle:
|
||||
{
|
||||
/* Continue */
|
||||
// Continue
|
||||
} break;
|
||||
}
|
||||
}
|
||||
@ -863,8 +834,6 @@ FmtArgArray FmtArgsFromVaList(Arena *arena, va_list args)
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Unicode
|
||||
|
||||
//- Codepoint iteration
|
||||
|
||||
CodepointIter InitCodepointIter(String str)
|
||||
{
|
||||
return (CodepointIter)
|
||||
@ -873,7 +842,7 @@ CodepointIter InitCodepointIter(String str)
|
||||
};
|
||||
}
|
||||
|
||||
/* Returns 0 if done iterating */
|
||||
// Returns 0 if done iterating
|
||||
b32 NextCodepoint(CodepointIter *iter)
|
||||
{
|
||||
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 result = {
|
||||
@ -917,7 +884,7 @@ String StringFromString16(Arena *arena, String16 str16)
|
||||
return result;
|
||||
}
|
||||
|
||||
/* utf8 <- utf32 */
|
||||
// utf8 <- utf32
|
||||
String StringFromString32(Arena *arena, String32 str32)
|
||||
{
|
||||
String result = {
|
||||
@ -942,9 +909,7 @@ String StringFromString32(Arena *arena, String32 str32)
|
||||
return result;
|
||||
}
|
||||
|
||||
//- String encode
|
||||
|
||||
/* utf16 <- utf8 */
|
||||
// utf16 <- utf8
|
||||
String16 String16FromString(Arena *arena, String str8)
|
||||
{
|
||||
String16 result = {
|
||||
@ -969,7 +934,7 @@ String16 String16FromString(Arena *arena, String str8)
|
||||
return result;
|
||||
}
|
||||
|
||||
/* utf32 <- utf8 */
|
||||
// utf32 <- utf8
|
||||
String32 String32FromString(Arena *arena, String str8)
|
||||
{
|
||||
String32 result = {
|
||||
@ -997,8 +962,6 @@ String32 String32FromString(Arena *arena, String str8)
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Null-terminated strings
|
||||
|
||||
//- Narrow C strings
|
||||
|
||||
u64 CstrLenNoLimit(char *cstr)
|
||||
{
|
||||
char *end = cstr;
|
||||
@ -1071,8 +1034,6 @@ String StringFromCstr(char *cstr, u64 limit)
|
||||
};
|
||||
}
|
||||
|
||||
//- Wide C strings
|
||||
|
||||
u64 WstrLenNoLimit(wchar_t *wstr)
|
||||
{
|
||||
wchar_t *end = wstr;
|
||||
|
||||
@ -8,7 +8,7 @@ Enum(FmtArgKind)
|
||||
{
|
||||
FmtArgKind_None,
|
||||
|
||||
/* Arbitrary magic numbers for argument validation */
|
||||
// Arbitrary magic numbers for argument validation
|
||||
FmtArgKind_Char = 0xf5281df,
|
||||
FmtArgKind_String = 0xa5ffa9a,
|
||||
|
||||
@ -38,8 +38,8 @@ Enum(FmtArgKind)
|
||||
Struct(FmtArg)
|
||||
{
|
||||
FmtArgKind kind;
|
||||
u32 p; /* Precision */
|
||||
u32 z; /* Z-fill */
|
||||
u32 p; // Precision
|
||||
u32 z; // Z-fill
|
||||
union
|
||||
{
|
||||
u8 c;
|
||||
@ -69,7 +69,7 @@ Struct(CodepointIter)
|
||||
{
|
||||
u32 codepoint;
|
||||
|
||||
/* Internal */
|
||||
// Internal
|
||||
String src;
|
||||
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 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 StringF_(Arena *arena, String fmt, ...);
|
||||
|
||||
@ -1,8 +1,7 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Mutex
|
||||
|
||||
//- Exclusive mutex lock
|
||||
Lock LockSpinE(Mutex *m, i32 spin)
|
||||
Lock ExclusiveLockEx(Mutex *m, i32 spin)
|
||||
{
|
||||
b32 locked = 0;
|
||||
i32 spin_cnt = 0;
|
||||
@ -16,7 +15,7 @@ Lock LockSpinE(Mutex *m, i32 spin)
|
||||
}
|
||||
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);
|
||||
while (swp != v && swp == 0x40000000)
|
||||
{
|
||||
@ -31,7 +30,7 @@ Lock LockSpinE(Mutex *m, i32 spin)
|
||||
}
|
||||
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);
|
||||
while (swp != v && (swp & 0xC0000000) == 0 && swp != 0)
|
||||
{
|
||||
@ -40,7 +39,7 @@ Lock LockSpinE(Mutex *m, i32 spin)
|
||||
}
|
||||
v = swp;
|
||||
}
|
||||
/* Pause or wait */
|
||||
// Pause or wait
|
||||
if (!locked && v != 0 && v != 0x40000000)
|
||||
{
|
||||
if (spin_cnt < spin)
|
||||
@ -65,8 +64,7 @@ Lock LockSpinE(Mutex *m, i32 spin)
|
||||
return lock;
|
||||
}
|
||||
|
||||
//- Shared mutex lock
|
||||
Lock LockSpinS(Mutex *m, i32 spin)
|
||||
Lock SharedLockEx(Mutex *m, i32 spin)
|
||||
{
|
||||
b32 locked = 0;
|
||||
i32 spin_cnt = 0;
|
||||
@ -76,7 +74,7 @@ Lock LockSpinS(Mutex *m, i32 spin)
|
||||
u32 v = Atomic32Fetch(&m->v);
|
||||
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);
|
||||
if (v == swp)
|
||||
{
|
||||
@ -87,7 +85,7 @@ Lock LockSpinS(Mutex *m, i32 spin)
|
||||
v = swp;
|
||||
}
|
||||
}
|
||||
/* Pause or wait */
|
||||
// Pause or wait
|
||||
if (!locked)
|
||||
{
|
||||
if (spin_cnt < spin)
|
||||
@ -106,15 +104,14 @@ Lock LockSpinS(Mutex *m, i32 spin)
|
||||
return lock;
|
||||
}
|
||||
|
||||
//- Mutex lock wrappers
|
||||
Lock LockE(Mutex *m)
|
||||
{
|
||||
return LockSpinE(m, DefaultMutexSpin);
|
||||
return ExclusiveLockEx(m, DefaultMutexSpin);
|
||||
}
|
||||
|
||||
Lock LockS(Mutex *m)
|
||||
{
|
||||
return LockSpinS(m, DefaultMutexSpin);
|
||||
return SharedLockEx(m, DefaultMutexSpin);
|
||||
}
|
||||
|
||||
void Unlock(Lock *l)
|
||||
|
||||
@ -5,22 +5,21 @@
|
||||
|
||||
AlignedStruct(Mutex, CachelineSize)
|
||||
{
|
||||
/* Bit 31 = Exclusive lock is held
|
||||
* Bit 30 = Exclusive lock is pending
|
||||
* Bit 0-30 = Shared locks count
|
||||
*/
|
||||
Atomic32 v;
|
||||
// Bit 31 = Exclusive lock is held
|
||||
// Bit 30 = Exclusive lock is pending
|
||||
// Bit 0-30 = Shared locks count
|
||||
Atomic32 v;
|
||||
|
||||
#if IsRtcEnabled
|
||||
Atomic32 exclusive_thread_id;
|
||||
Atomic32 exclusive_thread_id;
|
||||
#endif
|
||||
};
|
||||
StaticAssert(alignof(Mutex) == CachelineSize && sizeof(Mutex) % CachelineSize == 0);
|
||||
|
||||
Struct(Lock)
|
||||
{
|
||||
Mutex *mutex;
|
||||
b32 exclusive;
|
||||
Mutex *mutex;
|
||||
b32 exclusive;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -28,7 +27,7 @@ Struct(Lock)
|
||||
|
||||
AlignedStruct(Cv, CachelineSize)
|
||||
{
|
||||
Atomic64 wake_gen;
|
||||
Atomic64 wake_gen;
|
||||
};
|
||||
StaticAssert(alignof(Cv) == CachelineSize && sizeof(Cv) % CachelineSize == 0);
|
||||
|
||||
@ -37,14 +36,14 @@ StaticAssert(alignof(Cv) == CachelineSize && sizeof(Cv) % CachelineSize == 0);
|
||||
|
||||
Struct(Fence)
|
||||
{
|
||||
Atomic64Padded v;
|
||||
Atomic64Padded v;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Mutex
|
||||
|
||||
Lock LockSpinE(Mutex *m, i32 spin);
|
||||
Lock LockSpinS(Mutex *m, i32 spin);
|
||||
Lock ExclusiveLockEx(Mutex *m, i32 spin);
|
||||
Lock SharedLockEx(Mutex *m, i32 spin);
|
||||
|
||||
Lock LockE(Mutex *m);
|
||||
Lock LockS(Mutex *m);
|
||||
|
||||
@ -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 result = Zi;
|
||||
@ -6,7 +6,7 @@ Uid UidFromTrueRand(void)
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Combines 2 uids into a new uid */
|
||||
// Combines 2 uids into a new uid
|
||||
Uid CombineUid(Uid a, Uid b)
|
||||
{
|
||||
Uid result;
|
||||
|
||||
@ -123,7 +123,7 @@ Utf8EncodeResult EncodeUtf8(u32 codepoint)
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Invalid codepoint */
|
||||
// Invalid codepoint
|
||||
result.count8 = 1;
|
||||
result.chars8[0] = '?';
|
||||
}
|
||||
@ -183,7 +183,7 @@ Utf16EncodeResult EncodeUtf16(u32 codepoint)
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Invalid codepoint */
|
||||
// Invalid codepoint
|
||||
result.count16 = 1;
|
||||
result.chars16[0] = '?';
|
||||
}
|
||||
@ -241,7 +241,7 @@ Utf32EncodeResult EncodeUtf32(u32 codepoint)
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Invalid codepoint */
|
||||
// Invalid codepoint
|
||||
result.chars32 = '?';
|
||||
}
|
||||
|
||||
|
||||
@ -6,11 +6,10 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Mergesort types
|
||||
|
||||
/* Compare functions should
|
||||
* return a positive value if a should go before b
|
||||
* return a negative value if a should go after b
|
||||
* return 0 otherwise
|
||||
*/
|
||||
// Compare functions should
|
||||
// return a positive value if a should go before b
|
||||
// return a negative value if a should go after b
|
||||
// return 0 otherwise
|
||||
#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);
|
||||
|
||||
@ -45,9 +44,8 @@ Struct(Dict)
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Hash utils
|
||||
|
||||
/* FNV-1a parameters for different hash sizes:
|
||||
* https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function#FNV_hash_parameters
|
||||
*/
|
||||
// FNV-1a parameters for different hash sizes:
|
||||
// https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function#FNV_hash_parameters
|
||||
Inline u64 HashFnv64(u64 seed, String s)
|
||||
{
|
||||
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)
|
||||
{
|
||||
/* Sort */
|
||||
// Sort
|
||||
u64 i = 0;
|
||||
u64 l = 0;
|
||||
u64 r = 0;
|
||||
@ -103,7 +101,7 @@ Inline void MergesortInternal(u8 *left, u8 *right, u8 *items, u64 left_count, u6
|
||||
++r;
|
||||
}
|
||||
}
|
||||
/* Copy remaining */
|
||||
// Copy remaining
|
||||
if (l != left_count)
|
||||
{
|
||||
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 init
|
||||
|
||||
Inline Dict *InitDict(Arena *arena, u64 bins_count)
|
||||
{
|
||||
Dict *dict = PushStruct(arena, Dict);
|
||||
dict->bins_count = MaxU64(bins_count, 1); /* Ensure at least 1 bin */
|
||||
dict->bins_count = MaxU64(bins_count, 1); // Ensure at least 1 bin
|
||||
dict->bins = PushStructs(arena, DictBin, dict->bins_count);
|
||||
return dict;
|
||||
}
|
||||
@ -168,8 +164,6 @@ Inline void ResetDict(Dict *dict)
|
||||
}
|
||||
}
|
||||
|
||||
//- Dict set
|
||||
|
||||
Inline DictEntry *EnsureDictEntry(Arena *arena, Dict *dict, u64 hash)
|
||||
{
|
||||
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)
|
||||
{
|
||||
/* Existing match found */
|
||||
// Existing match found
|
||||
break;
|
||||
}
|
||||
entry = entry->next_in_bin;
|
||||
}
|
||||
|
||||
/* No match found, create new entry */
|
||||
// No match found, create new entry
|
||||
if (!entry)
|
||||
{
|
||||
if (dict->first_free)
|
||||
@ -230,11 +224,9 @@ Inline void SetDictValue(Arena *arena, Dict *dict, u64 hash, u64 value)
|
||||
entry->value = value;
|
||||
}
|
||||
|
||||
//- Dict remove
|
||||
|
||||
Inline void RemoveDictEntry(Dict *dict, DictEntry *entry)
|
||||
{
|
||||
/* Remove from bin */
|
||||
// Remove from bin
|
||||
{
|
||||
DictBin *bin = &dict->bins[entry->hash % dict->bins_count];
|
||||
DictEntry *prev_in_bin = entry->prev_in_bin;
|
||||
@ -256,7 +248,7 @@ Inline void RemoveDictEntry(Dict *dict, DictEntry *entry)
|
||||
bin->last = prev_in_bin;
|
||||
}
|
||||
}
|
||||
/* Remove from list */
|
||||
// Remove from list
|
||||
{
|
||||
DictEntry *prev = entry->prev;
|
||||
DictEntry *next = entry->next;
|
||||
@ -277,15 +269,13 @@ Inline void RemoveDictEntry(Dict *dict, DictEntry *entry)
|
||||
dict->last = prev;
|
||||
}
|
||||
}
|
||||
/* Add to free list */
|
||||
// Add to free list
|
||||
{
|
||||
entry->next = dict->first_free;
|
||||
dict->first_free = entry;
|
||||
}
|
||||
}
|
||||
|
||||
//- Dict index
|
||||
|
||||
Inline DictEntry *DictEntryFromHash(Dict *dict, u64 hash)
|
||||
{
|
||||
DictEntry *result = 0;
|
||||
@ -294,7 +284,7 @@ Inline DictEntry *DictEntryFromHash(Dict *dict, u64 hash)
|
||||
{
|
||||
if (hash == entry->hash)
|
||||
{
|
||||
/* Match found */
|
||||
// Match found
|
||||
result = entry;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -44,13 +44,13 @@ void WaveSyncBroadcastEx_(WaveLaneCtx *lane, u32 broadcast_lane_idx, void *broad
|
||||
|
||||
if (lane_idx == broadcast_lane_idx)
|
||||
{
|
||||
/* Broadcast */
|
||||
// Broadcast
|
||||
wave->broadcast_data = broadcast_ptr;
|
||||
i64 ack_gen = Atomic64Fetch(&wave->ack_gen.v);
|
||||
lane->seen_broadcast_gen = Atomic64FetchAdd(&wave->broadcast_gen.v, 1) + 1;
|
||||
FutexWakeNeq(&wave->broadcast_gen.v);
|
||||
|
||||
/* Wait for ack */
|
||||
// Wait for ack
|
||||
{
|
||||
u64 remaining_spins = spin_count;
|
||||
while (Atomic64Fetch(&wave->ack_gen.v) == ack_gen)
|
||||
@ -69,7 +69,7 @@ void WaveSyncBroadcastEx_(WaveLaneCtx *lane, u32 broadcast_lane_idx, void *broad
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Wait for broadcast */
|
||||
// Wait for broadcast
|
||||
i64 seen_broadcast_gen = lane->seen_broadcast_gen++;
|
||||
{
|
||||
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);
|
||||
|
||||
/* Ack */
|
||||
// Ack
|
||||
i32 ack_count = Atomic32FetchAdd(&wave->ack_count.v, 1) + 1;
|
||||
if (ack_count == lanes_count - 1)
|
||||
{
|
||||
|
||||
@ -9,11 +9,11 @@ AlignedStruct(WaveCtx, CachelineSize)
|
||||
i32 lanes_count;
|
||||
void *udata;
|
||||
|
||||
/* Sync barrier */
|
||||
// Sync barrier
|
||||
Atomic32Padded sync_count;
|
||||
Atomic64Padded sync_gen;
|
||||
|
||||
/* Broadcast barrier */
|
||||
// Broadcast barrier
|
||||
void *broadcast_data;
|
||||
Atomic64Padded broadcast_gen;
|
||||
Atomic32Padded ack_count;
|
||||
|
||||
@ -118,7 +118,7 @@ CpuTopologyInfo GetCpuTopologyInfo(void)
|
||||
}
|
||||
if (ok)
|
||||
{
|
||||
/* Determine max efficiency class */
|
||||
// Determine max efficiency class
|
||||
i32 max_efficiency_class = 0;
|
||||
{
|
||||
DWORD pos = 0;
|
||||
@ -129,7 +129,7 @@ CpuTopologyInfo GetCpuTopologyInfo(void)
|
||||
pos += info->Size;
|
||||
}
|
||||
}
|
||||
/* Generate physical core info */
|
||||
// Generate physical core info
|
||||
{
|
||||
DWORD pos = 0;
|
||||
while (pos < infos_buff_size)
|
||||
@ -139,17 +139,17 @@ CpuTopologyInfo GetCpuTopologyInfo(void)
|
||||
++res.num_logical_cores;
|
||||
if (info->Processor.Flags & LTP_PC_SMT)
|
||||
{
|
||||
/* Core has SMT sibling */
|
||||
// Core has SMT sibling
|
||||
++res.num_logical_cores;
|
||||
}
|
||||
if (info->Processor.EfficiencyClass == max_efficiency_class)
|
||||
{
|
||||
/* Core is P-core */
|
||||
// Core is P-core
|
||||
++res.num_physical_performance_cores;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Core is not a P-core */
|
||||
// Core is not a P-core
|
||||
++res.num_physical_non_performance_cores;
|
||||
}
|
||||
pos += info->Size;
|
||||
@ -222,7 +222,7 @@ String SwappedStateFromName(Arena *arena, String name)
|
||||
void WriteSwappedState(String name, String data)
|
||||
{
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
/* TODO: Use directory non-relative to executable */
|
||||
// TODO: Use directory non-relative to executable
|
||||
CreateDirectoryW(L"ppswap", 0);
|
||||
String result = Zi;
|
||||
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();
|
||||
i32 thread_id = GetCurrentThreadId();
|
||||
|
||||
// TODO: Log asynchronously
|
||||
|
||||
//- Log message to file
|
||||
/* TODO: Log asynchronously */
|
||||
{
|
||||
String shorthand = settings.shorthand;
|
||||
String msg_formatted = StringF(
|
||||
scratch.arena,
|
||||
"[%F:%F:%F.%F] <%F> [%F] %F\n",
|
||||
|
||||
/* Time */
|
||||
// Time
|
||||
FmtUint(datetime.hour, .z = 2),
|
||||
FmtUint(datetime.minute, .z = 2),
|
||||
FmtUint(datetime.second, .z = 2),
|
||||
FmtUint(datetime.milliseconds, .z = 3),
|
||||
|
||||
/* Thread id */
|
||||
// Thread id
|
||||
FmtUint(thread_id, .z = 5),
|
||||
|
||||
/* Level */
|
||||
// Level
|
||||
FmtString(shorthand),
|
||||
|
||||
/* Message */
|
||||
// Message
|
||||
FmtString(msg)
|
||||
);
|
||||
WriteFile(W32.logfile, msg_formatted.text, msg_formatted.len, 0, 0);
|
||||
}
|
||||
|
||||
//- Log message to queue
|
||||
/* TODO: Log asynchronously */
|
||||
LockTicketMutex(&W32.logs_tm);
|
||||
{
|
||||
/* Get staged data */
|
||||
// Get staged data
|
||||
LogEvent *ev = PushStruct(W32.logs_arena, LogEvent);
|
||||
ev->msg = PushString(W32.log_msgs_arena, msg);
|
||||
ev->datetime = datetime;
|
||||
@ -354,8 +354,8 @@ void W32_Log(i32 level, String msg)
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ @hookimpl Log
|
||||
|
||||
/* Panic log function is separate to enforce zero side effects other than
|
||||
* immediately writing to log file. */
|
||||
// Panic log function is separate to enforce zero side effects other than
|
||||
// immediately writing to log file.
|
||||
void LogPanic(String msg)
|
||||
{
|
||||
if (Atomic32Fetch(&W32.logs_initialized))
|
||||
@ -405,7 +405,7 @@ LogEventsArray GetLogEvents(void)
|
||||
|
||||
i32 W32_Main(void)
|
||||
{
|
||||
/* Init time */
|
||||
// Init time
|
||||
{
|
||||
LARGE_INTEGER qpf;
|
||||
QueryPerformanceFrequency(&qpf);
|
||||
@ -417,20 +417,20 @@ i32 W32_Main(void)
|
||||
W32.timer_start_qpc = qpc.QuadPart;
|
||||
}
|
||||
|
||||
/* Setup events */
|
||||
// Setup events
|
||||
W32.panic_event = CreateEventW(0, 1, 0, 0);
|
||||
W32.exit_event = CreateEventW(0, 1, 0, 0);
|
||||
|
||||
W32.main_thread_id = GetCurrentThreadId();
|
||||
SetThreadDescription(GetCurrentThread(), L"Main thread");
|
||||
|
||||
/* Query system info */
|
||||
// Query system info
|
||||
GetSystemInfo(&W32.info);
|
||||
|
||||
/* Init main thread */
|
||||
// Init main thread
|
||||
W32_InitCurrentThread(Lit("Main"));
|
||||
|
||||
/* Get raw args from command line */
|
||||
// Get raw args from command line
|
||||
{
|
||||
Arena *perm = PermArena();
|
||||
StringList args_list = Zi;
|
||||
@ -451,25 +451,25 @@ i32 W32_Main(void)
|
||||
//////////////////////////////
|
||||
//- Bootstrap
|
||||
|
||||
/* Bootstrap command line */
|
||||
// Bootstrap command line
|
||||
BootstrapCmdline();
|
||||
|
||||
/* Bootstrap log system */
|
||||
/* FIXME: Remove hardcoded log path */
|
||||
// Bootstrap log system
|
||||
// FIXME: Remove hardcoded log path
|
||||
W32_BootstrapLogs(Lit("log.log"));
|
||||
LogInfoF("Main thread ID: %F", FmtUint(ThreadId()));
|
||||
|
||||
/* Bootstrap resource system */
|
||||
// Bootstrap resource system
|
||||
{
|
||||
W32_FindEmbeddedDataCtx ctx = Zi;
|
||||
EnumResourceNamesW(0, RT_RCDATA, &W32_FindEmbeddedRcData, (LONG_PTR)&ctx);
|
||||
BootstrapResources(ctx.embedded_strings_count, ctx.embedded_strings);
|
||||
}
|
||||
|
||||
/* Bootstrap async */
|
||||
// Bootstrap async
|
||||
BootstrapAsync();
|
||||
|
||||
/* Bootstrap layers */
|
||||
// Bootstrap layers
|
||||
if (!Atomic32Fetch(&W32.panicking))
|
||||
{
|
||||
BootstrapLayers();
|
||||
@ -478,7 +478,7 @@ i32 W32_Main(void)
|
||||
//////////////////////////////
|
||||
//- Wait for exit signal
|
||||
|
||||
/* Wait for exit start or panic */
|
||||
// Wait for exit start or panic
|
||||
if (!Atomic32Fetch(&W32.panicking))
|
||||
{
|
||||
HANDLE handles[] = {
|
||||
@ -491,7 +491,7 @@ i32 W32_Main(void)
|
||||
//////////////////////////////
|
||||
//- Shutdown
|
||||
|
||||
/* Run exit callbacks */
|
||||
// Run exit callbacks
|
||||
if (!Atomic32Fetch(&W32.panicking))
|
||||
{
|
||||
i32 num_funcs = Atomic32Fetch(&W32.num_exit_funcs);
|
||||
@ -502,7 +502,7 @@ i32 W32_Main(void)
|
||||
}
|
||||
}
|
||||
|
||||
/* Exit */
|
||||
// Exit
|
||||
if (Atomic32Fetch(&W32.panicking))
|
||||
{
|
||||
WaitForSingleObject(W32.panic_event, INFINITE);
|
||||
@ -526,8 +526,8 @@ i32 W32_Main(void)
|
||||
{
|
||||
return W32_Main();
|
||||
}
|
||||
#endif /* IsConsoleApp */
|
||||
#endif /* IsCrtlibEnabled */
|
||||
#endif // IsConsoleApp
|
||||
#endif // IsCrtlibEnabled
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Crt stub
|
||||
@ -537,7 +537,7 @@ i32 W32_Main(void)
|
||||
#pragma clang diagnostic ignored "-Wmissing-variable-declarations"
|
||||
#pragma clang diagnostic ignored "-Wmissing-prototypes"
|
||||
|
||||
/* Enable floating point */
|
||||
// Enable floating point
|
||||
__attribute((used))
|
||||
int _fltused;
|
||||
|
||||
@ -549,4 +549,4 @@ i32 W32_Main(void)
|
||||
}
|
||||
|
||||
#pragma clang diagnostic pop
|
||||
#endif /* !IsCrtlibEnabled */
|
||||
#endif // !IsCrtlibEnabled
|
||||
|
||||
@ -16,12 +16,12 @@ void FutexWakeNeq(void *addr)
|
||||
|
||||
void FutexYieldGte(volatile void *addr, void *cmp, u8 cmp_size)
|
||||
{
|
||||
/* TODO: Actually implement this. Just emulating via neq for now. */
|
||||
// TODO: Actually implement this. Just emulating via neq for now.
|
||||
FutexYieldNeq(addr, cmp, cmp_size);
|
||||
}
|
||||
|
||||
void FutexWakeGte(void *addr)
|
||||
{
|
||||
/* TODO: Actually implement this. Just emulating via neq for now. */
|
||||
// TODO: Actually implement this. Just emulating via neq for now.
|
||||
FutexWakeNeq(addr);
|
||||
}
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
|
||||
void W32_InitCurrentThread(String name)
|
||||
{
|
||||
/* Init thread arenas */
|
||||
// Init thread arenas
|
||||
{
|
||||
Base_tl.arenas.perm = AcquireArena(Gibi(64));
|
||||
for (i32 i = 0; i < (i32)countof(Base_tl.arenas.scratch); ++i)
|
||||
@ -13,11 +13,11 @@ void W32_InitCurrentThread(String name)
|
||||
}
|
||||
Arena *perm = PermArena();
|
||||
|
||||
/* Set thread name */
|
||||
// Set thread name
|
||||
wchar_t *thread_name_wstr = WstrFromString(perm, name);
|
||||
SetThreadDescription(GetCurrentThread(), thread_name_wstr);
|
||||
|
||||
/* Initialize COM */
|
||||
// Initialize COM
|
||||
CoInitializeEx(0, COINIT_MULTITHREADED);
|
||||
}
|
||||
|
||||
@ -38,7 +38,7 @@ void DispatchWave(String name, u32 num_lanes, WaveLaneEntryFunc *entry, void *ud
|
||||
Arena *perm = PermArena();
|
||||
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 new_num_threads_allocated = old_num_threads_allocated + num_lanes;
|
||||
if (new_num_threads_allocated > MaxThreads)
|
||||
@ -49,7 +49,7 @@ void DispatchWave(String name, u32 num_lanes, WaveLaneEntryFunc *entry, void *ud
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Sleep until panic */
|
||||
// Sleep until panic
|
||||
Sleep(INFINITE);
|
||||
}
|
||||
}
|
||||
|
||||
@ -39,7 +39,7 @@ CLD_SupportPoint CLD_SupportPointFromDirEx(CLD_Shape *shape, Xform xf, Vec2 dir,
|
||||
|
||||
if (count == 1)
|
||||
{
|
||||
/* Skip 'ignore' on single point colliders */
|
||||
// Skip 'ignore' on single point colliders
|
||||
ignore = -1;
|
||||
}
|
||||
|
||||
@ -131,11 +131,11 @@ b32 CLD_TestAabb(Aabb box0, Aabb box1)
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Gjk
|
||||
|
||||
/*
|
||||
* Determine simplex in menkowksi difference that encapsulates origin if shapes
|
||||
* overlap, or closest edge / point to origin on CLD_Menkowski difference if they
|
||||
* do not.
|
||||
*/
|
||||
//
|
||||
// Determine simplex in menkowksi difference that encapsulates origin if shapes
|
||||
// overlap, or closest edge / point to origin on CLD_Menkowski difference if they
|
||||
// do not.
|
||||
//
|
||||
|
||||
#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)
|
||||
@ -148,7 +148,7 @@ CLD_GjkData CLD_GjkDataFromShapes(CLD_Shape *shape0, CLD_Shape *shape1, Xform xf
|
||||
Vec2 dir = 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);
|
||||
if (IsVec2Zero(dir)) dir = VEC2(1, 0);
|
||||
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;
|
||||
for (;;)
|
||||
{
|
||||
//////////////////////////////
|
||||
//- Find initial points in simplex
|
||||
|
||||
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);
|
||||
|
||||
CLD_DBGSTEP;
|
||||
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)
|
||||
{
|
||||
overlapping = 0;
|
||||
@ -177,15 +179,17 @@ CLD_GjkData CLD_GjkDataFromShapes(CLD_Shape *shape0, CLD_Shape *shape1, Xform xf
|
||||
s.a = m;
|
||||
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));
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- Find third piont in simplex
|
||||
|
||||
{
|
||||
//- Find third point in simplex
|
||||
CLD_DBGSTEP;
|
||||
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 (
|
||||
Vec2LenSq(SubVec2(m.p, s.a.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.len = 3;
|
||||
|
||||
if ((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.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))
|
||||
if (
|
||||
(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.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;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//- Determine region of the simplex in which the origin lies
|
||||
//////////////////////////////
|
||||
//- Determine origin region
|
||||
|
||||
CLD_DBGSTEP;
|
||||
Vec2 vab = SubVec2(s.b.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)
|
||||
{
|
||||
//- Region ab, remove c
|
||||
// Region ab, remove c
|
||||
num_removed = 1;
|
||||
removed_a = s.c.p;
|
||||
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)
|
||||
{
|
||||
//- Region ac, remove b
|
||||
// Region ac, remove b
|
||||
num_removed = 1;
|
||||
removed_a = s.b.p;
|
||||
s.len = 2;
|
||||
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)
|
||||
{
|
||||
//- Region bc, remove a
|
||||
// Region bc, remove a
|
||||
num_removed = 1;
|
||||
removed_a = s.a.p;
|
||||
s.len = 2;
|
||||
s.a = s.b;
|
||||
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)
|
||||
{
|
||||
//- Region a, remove bc
|
||||
// Region a, remove bc
|
||||
num_removed = 2;
|
||||
removed_a = s.b.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)
|
||||
{
|
||||
//- Region b, remove ac
|
||||
// Region b, remove ac
|
||||
num_removed = 2;
|
||||
removed_a = s.a.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)
|
||||
{
|
||||
//- Region c, remove ab
|
||||
// Region c, remove ab
|
||||
num_removed = 2;
|
||||
removed_a = s.a.p;
|
||||
removed_b = s.b.p;
|
||||
@ -288,7 +296,7 @@ CLD_GjkData CLD_GjkDataFromShapes(CLD_Shape *shape0, CLD_Shape *shape1, Xform xf
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No region, must be in simplex */
|
||||
// No region, must be in simplex
|
||||
overlapping = 1;
|
||||
break;
|
||||
}
|
||||
@ -313,9 +321,8 @@ CLD_GjkData CLD_GjkDataFromShapes(CLD_Shape *shape0, CLD_Shape *shape1, Xform xf
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Epa
|
||||
|
||||
/* Expands upon result of GJK computation to determine collision normal &
|
||||
* closest edge when shapes are overlapping
|
||||
*/
|
||||
// Expands upon result of GJK computation to determine collision normal &
|
||||
// closest edge when shapes are overlapping
|
||||
|
||||
#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)
|
||||
@ -350,8 +357,8 @@ CLD_EpaData CLD_EpaDataFromShapes(CLD_Shape *shape0, CLD_Shape *shape1, Xform xf
|
||||
{
|
||||
++epa_iterations;
|
||||
|
||||
/* Find dir from origin to closest edge */
|
||||
/* FIXME: Winding order of ps & pe index */
|
||||
// Find dir from origin to closest edge
|
||||
// FIXME: Winding order of ps & pe index
|
||||
f32 closest_len_sq = F32Infinity;
|
||||
CLD_MenkowskiPoint closest_a = 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);
|
||||
|
||||
/* Find new point in dir */
|
||||
// Find new point in dir
|
||||
Vec2 dir = MulVec2(PerpVec2(vab), winding);
|
||||
CLD_MenkowskiPoint m = CLD_MenkowskiPointFromDir(shape0, shape1, xf0, xf1, dir);
|
||||
|
||||
#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);
|
||||
closest_feature.a = closest_a;
|
||||
closest_feature.b = closest_b;
|
||||
@ -394,16 +401,16 @@ CLD_EpaData CLD_EpaDataFromShapes(CLD_Shape *shape0, CLD_Shape *shape1, Xform xf
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Check validity of new point */
|
||||
// Check validity of new point
|
||||
CLD_DBGSTEP;
|
||||
{
|
||||
b32 valid = 1;
|
||||
|
||||
{
|
||||
/* 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 = 0.00000000001f; /* Arbitrary */
|
||||
const f32 validity_epsilon = min_unique_pt_dist_sq; /* Arbitrary */
|
||||
// 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 = 0.00000000001f; // Arbitrary
|
||||
const f32 validity_epsilon = min_unique_pt_dist_sq; // Arbitrary
|
||||
|
||||
Vec2 vam = SubVec2(m.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)
|
||||
{
|
||||
/* New point is not between edge */
|
||||
// New point is not between edge
|
||||
valid = 0;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
++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)
|
||||
{
|
||||
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];
|
||||
}
|
||||
|
||||
/* Insert new point into prototype */
|
||||
// Insert new point into prototype
|
||||
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 vb0b1_w = WedgeVec2(vb0b1, normal);
|
||||
|
||||
/* FIXME: Handle 0 denominator */
|
||||
// FIXME: Handle 0 denominator
|
||||
f32 a0t;
|
||||
f32 b0t;
|
||||
{
|
||||
@ -558,7 +565,7 @@ CLD_CollisionData CLD_CollisionDataFromShapes(CLD_Shape *shape0, CLD_Shape *shap
|
||||
CLD_GjkData gjk_result = Zi;
|
||||
CLD_EpaData epa_result = Zi;
|
||||
|
||||
/* Run GJK */
|
||||
// Run GJK
|
||||
#if COLLIDER_DEBUG
|
||||
gjk_result = CLD_GjkDataFromShapes(shape0, shape1, xf0, xf1, min_unique_pt_dist_sq, dbg_step);
|
||||
dbg_step = gjk_result.dbg_step;
|
||||
@ -567,7 +574,7 @@ CLD_CollisionData CLD_CollisionDataFromShapes(CLD_Shape *shape0, CLD_Shape *shap
|
||||
#endif
|
||||
CLD_DBGSTEP;
|
||||
|
||||
/* Run EPA */
|
||||
// Run EPA
|
||||
#if COLLIDER_DEBUG
|
||||
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;
|
||||
@ -577,7 +584,7 @@ CLD_CollisionData CLD_CollisionDataFromShapes(CLD_Shape *shape0, CLD_Shape *shap
|
||||
normal = epa_result.normal;
|
||||
CLD_DBGSTEP;
|
||||
|
||||
/* Determine collision */
|
||||
// Determine collision
|
||||
if (gjk_result.overlapping)
|
||||
{
|
||||
colliding = 1;
|
||||
@ -585,7 +592,7 @@ CLD_CollisionData CLD_CollisionDataFromShapes(CLD_Shape *shape0, CLD_Shape *shap
|
||||
else
|
||||
{
|
||||
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)
|
||||
{
|
||||
Vec2 p = NegVec2(f.a.p);
|
||||
@ -596,7 +603,7 @@ CLD_CollisionData CLD_CollisionDataFromShapes(CLD_Shape *shape0, CLD_Shape *shap
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Project origin to determine if distance is within tolerance. */
|
||||
// Project origin to determine if distance is within tolerance.
|
||||
Assert(f.len == 2);
|
||||
Vec2 vab = SubVec2(f.b.p, 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)
|
||||
{
|
||||
/* 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);
|
||||
|
||||
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 b0 = f.b.s0;
|
||||
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 (a0.i == b0.i)
|
||||
@ -666,7 +673,7 @@ CLD_CollisionData CLD_CollisionDataFromShapes(CLD_Shape *shape0, CLD_Shape *shap
|
||||
Vec2 vab0_norm = NormVec2(vab0);
|
||||
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)
|
||||
{
|
||||
CLD_SupportPoint tmp = a0;
|
||||
@ -682,12 +689,12 @@ CLD_CollisionData CLD_CollisionDataFromShapes(CLD_Shape *shape0, CLD_Shape *shap
|
||||
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;
|
||||
collapse0 = collapse0 || AbsF32(WedgeVec2(normal, vab0_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 (DotVec2(normal, vab0) > 0)
|
||||
@ -696,7 +703,7 @@ CLD_CollisionData CLD_CollisionDataFromShapes(CLD_Shape *shape0, CLD_Shape *shap
|
||||
}
|
||||
else
|
||||
{
|
||||
/* TODO: Remove this (debugging) */
|
||||
// TODO: Remove this (debugging)
|
||||
b0 = a0;
|
||||
}
|
||||
}
|
||||
@ -708,7 +715,7 @@ CLD_CollisionData CLD_CollisionDataFromShapes(CLD_Shape *shape0, CLD_Shape *shap
|
||||
}
|
||||
else
|
||||
{
|
||||
/* TODO: Remove this (debugging) */
|
||||
// TODO: Remove this (debugging)
|
||||
b1 = a1;
|
||||
}
|
||||
}
|
||||
@ -721,13 +728,13 @@ CLD_CollisionData CLD_CollisionDataFromShapes(CLD_Shape *shape0, CLD_Shape *shap
|
||||
b32 ignore_b = 1;
|
||||
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);
|
||||
Vec2 a0_clipped = clip_result.a0_clipped;
|
||||
Vec2 a1_clipped = clip_result.a1_clipped;
|
||||
Vec2 b0_clipped = clip_result.b0_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 vb0b1_clipped = SubVec2(b1_clipped, b0_clipped);
|
||||
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 p1 = a1.p;
|
||||
/* TODO: Choose ID based on closest clipped point */
|
||||
// TODO: Choose ID based on closest clipped point
|
||||
if (collapse1 && !collapse0)
|
||||
{
|
||||
/* Project a1 onto vab0 */
|
||||
// Project a1 onto vab0
|
||||
p0 = CLD_ClipPointToLine(a0.p, b0.p, a1.p, normal);
|
||||
}
|
||||
if (collapse0 && !collapse1)
|
||||
{
|
||||
/* Project a0 onto vab1 */
|
||||
// Project a0 onto vab1
|
||||
p1 = CLD_ClipPointToLine(a1.p, b1.p, a0.p, normal);
|
||||
}
|
||||
/* Calc midpoint */
|
||||
// Calc midpoint
|
||||
Vec2 vsep = SubVec2(p1, p0);
|
||||
a_midpoint = AddVec2(p0, MulVec2(vsep, 0.5f));
|
||||
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;
|
||||
}
|
||||
|
||||
/* Insert points */
|
||||
// Insert points
|
||||
if (!ignore_a && a_sep < tolerance)
|
||||
{
|
||||
CLD_CollisionPoint *point = &points[num_points++];
|
||||
@ -819,7 +826,7 @@ CLD_CollisionData CLD_CollisionDataFromShapes(CLD_Shape *shape0, CLD_Shape *shap
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ 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)
|
||||
{
|
||||
@ -840,25 +847,31 @@ CLD_ClosestPointData CLD_ClosestPointDataFromShapes(CLD_Shape *shape0, CLD_Shape
|
||||
CLD_GjkData gjk_result = Zi;
|
||||
CLD_EpaData epa_result = Zi;
|
||||
|
||||
//////////////////////////////
|
||||
//- Run GJK
|
||||
|
||||
#if COLLIDER_DEBUG
|
||||
gjk_result = CLD_GjkDataFromShapes(shape0, shape1, xf0, xf1, min_unique_pt_dist_sq, dbg_step);
|
||||
dbg_step = gjk_result.dbg_step;
|
||||
#else
|
||||
#else
|
||||
gjk_result = CLD_GjkDataFromShapes(shape0, shape1, xf0, xf1, min_unique_pt_dist_sq);
|
||||
#endif
|
||||
CLD_DBGSTEP;
|
||||
|
||||
//////////////////////////////
|
||||
//- Run EPA
|
||||
|
||||
#if COLLIDER_DEBUG
|
||||
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;
|
||||
#else
|
||||
#else
|
||||
epa_result = CLD_EpaDataFromShapes(shape0, shape1, xf0, xf1, gjk_result, min_unique_pt_dist_sq, max_epa_iterations);
|
||||
#endif
|
||||
CLD_DBGSTEP;
|
||||
|
||||
//////////////////////////////
|
||||
//- Resolve points
|
||||
|
||||
colliding = gjk_result.overlapping;
|
||||
CLD_MenkowskiFeature f = epa_result.closest_feature;
|
||||
if (f.len == 1)
|
||||
@ -870,19 +883,19 @@ CLD_ClosestPointData CLD_ClosestPointDataFromShapes(CLD_Shape *shape0, CLD_Shape
|
||||
else
|
||||
{
|
||||
Assert(f.len == 2);
|
||||
/* FIXME: Winding order dependent? */
|
||||
// FIXME: Winding order dependent?
|
||||
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 vao = NegVec2(f.a.p);
|
||||
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 = MulVec2(p0, ratio);
|
||||
p0 = AddVec2(p0, f.a.s0.p);
|
||||
/* Shape 1 */
|
||||
// Shape 1
|
||||
p1 = SubVec2(f.b.s1.p, f.a.s1.p);
|
||||
p1 = MulVec2(p1, ratio);
|
||||
p1 = AddVec2(p1, f.a.s1.p);
|
||||
@ -906,8 +919,8 @@ CLD_ClosestPointData CLD_ClosestPointDataFromShapes(CLD_Shape *shape0, CLD_Shape
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Time of impact
|
||||
|
||||
/* Takes 2 shapes and their xforms at t=0 and t=1.
|
||||
* Returns time of impact in range [0, 1]. */
|
||||
// Takes 2 shapes and their xforms at t=0 and t=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 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_sep = F32Infinity;
|
||||
|
||||
/* Find direction p0 -> p1 at t=0 */
|
||||
// Find direction p0 -> p1 at t=0
|
||||
Vec2 dir;
|
||||
Vec2 dir_neg;
|
||||
{
|
||||
CLD_ClosestPointData closest_points = CLD_ClosestPointDataFromShapes(c0, c1, xf0_t0, xf1_t0);
|
||||
if (closest_points.colliding)
|
||||
{
|
||||
/* Shapes are penetrating at t=0 */
|
||||
// Shapes are penetrating at t=0
|
||||
return 0;
|
||||
}
|
||||
dir = SubVec2(closest_points.p1, closest_points.p0);
|
||||
t0_sep = Vec2Len(dir);
|
||||
dir = DivVec2(dir, t0_sep); /* Normalize */
|
||||
dir = DivVec2(dir, t0_sep); // Normalize
|
||||
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));
|
||||
if (t1_sep > 0)
|
||||
{
|
||||
/* Shapes are not penetrating at t=1 */
|
||||
// Shapes are not penetrating at t=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;
|
||||
while (AbsF32(t_sep) > tolerance && iteration < max_iterations)
|
||||
{
|
||||
/* Use mix of bisection & 0 position method to find root
|
||||
* (as described in https://box2d.org/files/ErinCatto_ContinuousCollision_GDC2013.pdf) */
|
||||
// Use mix of bisection & 0 position method to find root
|
||||
// (as described in https://box2d.org/files/ErinCatto_ContinuousCollision_GDC2013.pdf)
|
||||
if (iteration & 1)
|
||||
{
|
||||
/* Bisect */
|
||||
// Bisect
|
||||
t = (t1 + t0) / 2.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* False position (fastest for linear case) */
|
||||
// False position (fastest for linear case)
|
||||
f32 m = (t1_sep - t0_sep) / (t1 - t0);
|
||||
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;
|
||||
t_sep = DotVec2(dir, SubVec2(p1, p0));
|
||||
|
||||
/* Update bracket */
|
||||
// Update bracket
|
||||
if (t_sep > 0)
|
||||
{
|
||||
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
|
||||
|
||||
/* 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 result = { .points = ArenaNext(arena, Vec2) };
|
||||
@ -1007,10 +1020,10 @@ Vec2Array CLD_Menkowski(Arena *arena, CLD_Shape *shape0, CLD_Shape *shape1, Xfor
|
||||
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)
|
||||
{
|
||||
/* FIXME: Account for radius */
|
||||
// FIXME: Account for radius
|
||||
Vec2Array result = { .points = ArenaNext(arena, Vec2) };
|
||||
Vec2 *points0 = shape0->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;
|
||||
|
||||
/* FIXME: Infinite loop when shapes exactly overlap same space? */
|
||||
// FIXME: Infinite loop when shapes exactly overlap same space?
|
||||
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));
|
||||
if (IsVec2Zero(dir)) dir = VEC2(1, 0);
|
||||
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);
|
||||
p = CLD_MenkowskiPointFromDir(shape0, shape1, dir);
|
||||
if (DotVec2(dir, p) >= 0)
|
||||
@ -1054,12 +1067,12 @@ b32 CLD_GjkBoolean(CLD_Shape *shape0, CLD_Shape *shape1)
|
||||
s.a = p;
|
||||
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));
|
||||
p = CLD_MenkowskiPointFromDir(shape0, shape1, dir);
|
||||
if (DotVec2(dir, p) < 0)
|
||||
{
|
||||
/* New point did not cross origin, collision impossible */
|
||||
// New point did not cross origin, collision impossible
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1071,23 +1084,23 @@ b32 CLD_GjkBoolean(CLD_Shape *shape0, CLD_Shape *shape1)
|
||||
Vec2 vac = SubVec2(s.c, 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)
|
||||
{
|
||||
/* 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
|
||||
{
|
||||
/* Point is not in region ab */
|
||||
dir = PerpVec2TowardsDir(vac, NegVec2(vab)); /* Normal of ac pointing away from b */
|
||||
// Point is not in region ab
|
||||
dir = PerpVec2TowardsDir(vac, NegVec2(vab)); // Normal of ac pointing away from b
|
||||
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;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Point is in simplex */
|
||||
// Point is in simplex
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ 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
|
||||
|
||||
/* 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)
|
||||
|
||||
/* 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
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -26,14 +26,14 @@ Struct(CLD_Shape)
|
||||
Struct(CLD_SupportPoint)
|
||||
{
|
||||
Vec2 p;
|
||||
u32 i; /* Index of original point in shape */
|
||||
u32 i; // Index of original point in shape
|
||||
};
|
||||
|
||||
Struct(CLD_MenkowskiPoint)
|
||||
{
|
||||
Vec2 p; /* Menkowski difference point */
|
||||
CLD_SupportPoint s0; /* Support point of first shape in dir */
|
||||
CLD_SupportPoint s1; /* Support point of second shape in -dir */
|
||||
Vec2 p; // Menkowski difference point
|
||||
CLD_SupportPoint s0; // Support point of first shape in dir
|
||||
CLD_SupportPoint s1; // Support point of second shape in -dir
|
||||
};
|
||||
|
||||
Struct(CLD_MenkowskiSimplex)
|
||||
@ -55,7 +55,7 @@ Struct(CLD_CollisionPoint)
|
||||
{
|
||||
Vec2 point;
|
||||
f32 separation;
|
||||
u32 id; /* Based on polygon edge-to-edge */
|
||||
u32 id; // Based on polygon edge-to-edge
|
||||
};
|
||||
|
||||
Struct(CLD_Prototype)
|
||||
@ -70,12 +70,12 @@ Struct(CLD_CollisionData)
|
||||
CLD_CollisionPoint points[2];
|
||||
u32 num_points;
|
||||
|
||||
/* For debugging */
|
||||
// For debugging
|
||||
b32 solved;
|
||||
CLD_MenkowskiSimplex simplex;
|
||||
CLD_Prototype prototype;
|
||||
|
||||
/* For debugging */
|
||||
// For debugging
|
||||
Vec2 a0, b0, a1, b1;
|
||||
Vec2 a0_clipped, b0_clipped, a1_clipped, b1_clipped;
|
||||
};
|
||||
@ -85,7 +85,7 @@ Struct(CLD_ClosestPointData)
|
||||
Vec2 p0, p1;
|
||||
b32 colliding;
|
||||
|
||||
/* For debugging */
|
||||
// For debugging
|
||||
b32 solved;
|
||||
CLD_MenkowskiSimplex simplex;
|
||||
CLD_Prototype prototype;
|
||||
@ -108,9 +108,9 @@ Struct(CLD_GjkData)
|
||||
CLD_MenkowskiSimplex simplex;
|
||||
Vec2 final_dir;
|
||||
|
||||
/* If 1, simplex represents triangle inside of CLD_Menkowski difference
|
||||
* encapsulating the origin. If 0, simplex represents the closest
|
||||
* feature on CLD_Menkowski difference to the origin. */
|
||||
// If 1, simplex represents triangle inside of CLD_Menkowski difference
|
||||
// encapsulating the origin. If 0, simplex represents the closest
|
||||
// feature on CLD_Menkowski difference to the origin.
|
||||
b32 overlapping;
|
||||
|
||||
#if COLLIDER_DEBUG
|
||||
@ -124,7 +124,7 @@ Struct(CLD_GjkData)
|
||||
Struct(CLD_EpaData)
|
||||
{
|
||||
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
|
||||
CLD_Prototype prototype;
|
||||
|
||||
26
src/config.h
26
src/config.h
@ -1,8 +1,8 @@
|
||||
/* Project-wide configurable constants */
|
||||
// Project-wide configurable constants
|
||||
|
||||
#define WRITE_DIR "power_play"
|
||||
|
||||
/* Window title */
|
||||
// Window title
|
||||
#if IsRtcEnabled
|
||||
#if IsDeveloperModeEnabled
|
||||
#define WINDOW_TITLE "Debug (Developer Build)"
|
||||
@ -20,20 +20,19 @@
|
||||
#define DEFAULT_CAMERA_WIDTH (16)
|
||||
#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_HEIGHT (360 + 250)
|
||||
|
||||
#define PIXELS_PER_UNIT ((f64)640 / (f64)DEFAULT_CAMERA_WIDTH)
|
||||
|
||||
/* How many ticks back in time should the user thread blend between?
|
||||
* <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
|
||||
*/
|
||||
// How many ticks back in time should the user thread blend between?
|
||||
// <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
|
||||
#define USER_INTERP_RATIO 1.2
|
||||
#define USER_INTERP_ENABLED 1
|
||||
|
||||
/* 64^2 = 4096 bins */
|
||||
// 64^2 = 4096 bins
|
||||
#define SPACE_CELL_BINS_SQRT (64)
|
||||
#define SPACE_CELL_SIZE (1)
|
||||
|
||||
@ -41,9 +40,8 @@
|
||||
#define SIM_TILES_PER_CHUNK_SQRT (16)
|
||||
|
||||
#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
|
||||
* master sim (how far back in time should the client render the server's state) */
|
||||
// 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)
|
||||
#define SIM_CLIENT_INTERP_RATIO 2.0
|
||||
|
||||
#define SIM_PHYSICS_SUBSTEPS 4
|
||||
@ -76,17 +74,17 @@
|
||||
#define GPU_SHADER_PRINT_BUFFER_SIZE Kibi(64);
|
||||
#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_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
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Settings
|
||||
|
||||
/* TODO: Move these to user-configurable settings */
|
||||
// TODO: Move these to user-configurable settings
|
||||
|
||||
#define VSYNC 1
|
||||
#define AUDIO_ENABLED 0
|
||||
|
||||
@ -39,7 +39,7 @@ void D_DrawPolyEx(GPU_RenderSig *sig, Vec2Array vertices, GPU_Indices indices, u
|
||||
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)
|
||||
{
|
||||
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_indices = num_tris * 3;
|
||||
|
||||
/* Generate indices in a fan pattern */
|
||||
// Generate indices in a fan pattern
|
||||
GPU_Indices indices = ZI;
|
||||
indices.count = 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);
|
||||
D_DrawMaterial(sig, D_MATERIALPARAMS(.texture = g->solid_white_texture, .tint0 = start_color, .tint1 = end_color, .quad = quad));
|
||||
#else
|
||||
/* Placeholder */
|
||||
// Placeholder
|
||||
Quad quad = QuadFromLine(start, end, thickness);
|
||||
D_DrawQuad(sig, quad, start_color);
|
||||
#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)
|
||||
{
|
||||
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);
|
||||
|
||||
Vec2 head_start_dir = SubVec2(start, end);
|
||||
@ -293,7 +293,7 @@ void D_DrawUiRect(GPU_RenderSig *sig, D_UiRectParams params)
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Text
|
||||
|
||||
/* Returns the rect of the text area */
|
||||
// Returns the rect of the text area
|
||||
Rect draw_text(GPU_RenderSig *sig, D_TextParams params)
|
||||
{
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
@ -367,8 +367,8 @@ Rect draw_text(GPU_RenderSig *sig, D_TextParams params)
|
||||
}
|
||||
}
|
||||
|
||||
/* Line ended */
|
||||
/* TODO: Only create nodes for non-empty lines. Embed line number in the node. */
|
||||
// Line ended
|
||||
// TODO: Only create nodes for non-empty lines. Embed line number in the node.
|
||||
D_TextLine *node = PushStruct(scratch.arena, D_TextLine);
|
||||
node->line_width = line_width;
|
||||
node->num_glyphs = num_line_glyphs;
|
||||
@ -398,7 +398,7 @@ Rect draw_text(GPU_RenderSig *sig, D_TextParams params)
|
||||
bounds.width = widest_line;
|
||||
bounds.height = num_lines * line_spacing + first_line_top_offset + last_line_bottom_offset;
|
||||
|
||||
/* Offset bounds X */
|
||||
// Offset bounds X
|
||||
switch (params.offset_x)
|
||||
{
|
||||
case DRAW_TEXT_OFFSET_X_LEFT: break;
|
||||
@ -412,7 +412,7 @@ Rect draw_text(GPU_RenderSig *sig, D_TextParams params)
|
||||
} break;
|
||||
}
|
||||
|
||||
/* Offset bounds Y */
|
||||
// Offset bounds Y
|
||||
switch (params.offset_y)
|
||||
{
|
||||
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;
|
||||
draw_pos.y += line_number * line_spacing - first_line_top_offset;
|
||||
|
||||
/* Alignment */
|
||||
// Alignment
|
||||
switch (params.alignment)
|
||||
{
|
||||
case DRAW_TEXT_ALIGNMENT_LEFT: break;
|
||||
@ -451,7 +451,7 @@ Rect draw_text(GPU_RenderSig *sig, D_TextParams params)
|
||||
} break;
|
||||
}
|
||||
|
||||
/* Draw glyphs in line */
|
||||
// Draw glyphs in line
|
||||
for (u64 i = 0; i < line->num_glyphs; ++i)
|
||||
{
|
||||
D_TextGlyph *tg = &line->glyphs[i];
|
||||
|
||||
@ -35,27 +35,27 @@ Struct(D_UiRectParams)
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Text types
|
||||
|
||||
/* How is text aligned within its area */
|
||||
// How is text aligned within its area
|
||||
Enum(D_TextAlignment)
|
||||
{
|
||||
DRAW_TEXT_ALIGNMENT_LEFT, /* Default */
|
||||
DRAW_TEXT_ALIGNMENT_LEFT, // Default
|
||||
DRAW_TEXT_ALIGNMENT_CENTER,
|
||||
DRAW_TEXT_ALIGNMENT_RIGHT
|
||||
};
|
||||
|
||||
/* 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
|
||||
* the specified position. */
|
||||
// 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
|
||||
// the specified position.
|
||||
Enum(D_TextOffsetX)
|
||||
{
|
||||
DRAW_TEXT_OFFSET_X_LEFT, /* Default */
|
||||
DRAW_TEXT_OFFSET_X_LEFT, // Default
|
||||
DRAW_TEXT_OFFSET_X_CENTER,
|
||||
DRAW_TEXT_OFFSET_X_RIGHT
|
||||
};
|
||||
|
||||
Enum(D_TextOffsetY)
|
||||
{
|
||||
DRAW_TEXT_OFFSET_Y_TOP, /* Default */
|
||||
DRAW_TEXT_OFFSET_Y_TOP, // Default
|
||||
DRAW_TEXT_OFFSET_Y_CENTER,
|
||||
DRAW_TEXT_OFFSET_Y_BOTTOM
|
||||
};
|
||||
|
||||
@ -20,14 +20,14 @@ GC_FontKey GC_FontKeyFromResource(ResourceKey resource)
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ 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 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);
|
||||
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;
|
||||
{
|
||||
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;
|
||||
Atomic64FetchSet(&glyph->async_copy_completion_target, I64Max);
|
||||
SllStackPush(bin->first, glyph);
|
||||
/* Create cmd */
|
||||
// Create cmd
|
||||
{
|
||||
GC_Cmd *cmd = &submit_cmds[submit_cmds_count];
|
||||
cmd->glyph = glyph;
|
||||
@ -229,7 +229,7 @@ void GC_TickAsync(WaveLaneCtx *lane, AsyncTickCtx *tick)
|
||||
//////////////////////////////
|
||||
//- Begin tick
|
||||
|
||||
/* TODO: Limit cmds processed per-tick */
|
||||
// TODO: Limit cmds processed per-tick
|
||||
|
||||
if (lane->idx == 0)
|
||||
{
|
||||
@ -237,7 +237,7 @@ void GC_TickAsync(WaveLaneCtx *lane, AsyncTickCtx *tick)
|
||||
|
||||
Lock lock = LockE(&GC.submit.mutex);
|
||||
{
|
||||
/* Pop cmds from submission queue */
|
||||
// Pop cmds from submission queue
|
||||
async->cmds.count = GC.submit.count;
|
||||
async->cmds.v = PushStructsNoZero(tick->arena, GC_Cmd, GC.submit.count);
|
||||
u64 cmd_idx = 0;
|
||||
@ -246,7 +246,7 @@ void GC_TickAsync(WaveLaneCtx *lane, AsyncTickCtx *tick)
|
||||
async->cmds.v[cmd_idx] = n->cmd;
|
||||
++cmd_idx;
|
||||
}
|
||||
/* Reset submission queue */
|
||||
// Reset submission queue
|
||||
GC.submit.first_free = GC.submit.first;
|
||||
GC.submit.count = 0;
|
||||
GC.submit.first = 0;
|
||||
@ -262,7 +262,7 @@ void GC_TickAsync(WaveLaneCtx *lane, AsyncTickCtx *tick)
|
||||
//////////////////////////////
|
||||
//- 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);
|
||||
@ -283,7 +283,7 @@ void GC_TickAsync(WaveLaneCtx *lane, AsyncTickCtx *tick)
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: Only sync first lane? */
|
||||
// TODO: Only sync first lane?
|
||||
|
||||
WaveSync(lane);
|
||||
|
||||
@ -302,13 +302,13 @@ void GC_TickAsync(WaveLaneCtx *lane, AsyncTickCtx *tick)
|
||||
|
||||
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;
|
||||
b32 can_use_atlas = 0;
|
||||
Vec2I32 pos_in_atlas = Zi;
|
||||
while (can_use_atlas == 0)
|
||||
{
|
||||
/* Create atlas */
|
||||
// Create atlas
|
||||
if (!atlas)
|
||||
{
|
||||
Arena *perm = PermArena();
|
||||
@ -328,7 +328,7 @@ void GC_TickAsync(WaveLaneCtx *lane, AsyncTickCtx *tick)
|
||||
++GC.atlases_count;
|
||||
}
|
||||
|
||||
/* Determine pos in atlas */
|
||||
// Determine pos in atlas
|
||||
pos_in_atlas = atlas->cur_pos;
|
||||
atlas->cur_row_height = MaxI32(atlas->cur_row_height, image_dims.y);
|
||||
if (pos_in_atlas.x + image_dims.x > atlas->dims.x);
|
||||
@ -348,7 +348,7 @@ void GC_TickAsync(WaveLaneCtx *lane, AsyncTickCtx *tick)
|
||||
}
|
||||
}
|
||||
|
||||
/* Atlas info */
|
||||
// Atlas info
|
||||
glyph->atlas = atlas;
|
||||
glyph->tex_slice = RNG2I32(pos_in_atlas, AddVec2I32(pos_in_atlas, image_dims));
|
||||
glyph->tex_slice_uv.p0.x = (f32)glyph->tex_slice.p0.x / (f32)atlas->dims.x;
|
||||
@ -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.y = (f32)glyph->tex_slice.p1.y / (f32)atlas->dims.x;
|
||||
|
||||
/* Copy to atlas */
|
||||
// Copy to atlas
|
||||
u32 *image_pixels = ttf_result.image_pixels;
|
||||
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);
|
||||
|
||||
/* Update completion targets */
|
||||
// Update completion targets
|
||||
for (u64 cmd_idx = 0; cmd_idx < async->cmds.count; ++cmd_idx)
|
||||
{
|
||||
GC_Cmd *cmd = &async->cmds.v[cmd_idx];
|
||||
|
||||
@ -38,17 +38,17 @@ Struct(GC_Glyph)
|
||||
u64 hash;
|
||||
Atomic64 async_copy_completion_target;
|
||||
|
||||
/* Font info */
|
||||
// Font info
|
||||
f32 font_size;
|
||||
f32 font_ascent;
|
||||
f32 font_descent;
|
||||
f32 font_cap;
|
||||
|
||||
/* Layout info */
|
||||
// Layout info
|
||||
f32 advance;
|
||||
Rng2 bounds;
|
||||
|
||||
/* Atlas info */
|
||||
// Atlas info
|
||||
GC_Atlas *atlas;
|
||||
Rng2I32 tex_slice;
|
||||
Rng2 tex_slice_uv;
|
||||
@ -64,8 +64,8 @@ Struct(GC_GlyphBin)
|
||||
|
||||
Struct(GC_RunRect)
|
||||
{
|
||||
Rng2 bounds; /* Visual bounds in relation to the baseline */
|
||||
f32 baseline_pos; /* Horizontal distance from start of baseline */
|
||||
Rng2 bounds; // Visual bounds in relation to the baseline
|
||||
f32 baseline_pos; // Horizontal distance from start of baseline
|
||||
f32 advance;
|
||||
|
||||
G_Texture2DRef tex;
|
||||
@ -75,13 +75,13 @@ Struct(GC_RunRect)
|
||||
|
||||
Struct(GC_Run)
|
||||
{
|
||||
/* Run data */
|
||||
Rng2 bounds; /* Visual bounds of the run in relation to the baseline */
|
||||
// Run data
|
||||
Rng2 bounds; // Visual bounds of the run in relation to the baseline
|
||||
f32 baseline_length;
|
||||
u64 rects_count;
|
||||
GC_RunRect *rects;
|
||||
|
||||
/* Font info */
|
||||
// Font info
|
||||
f32 font_size;
|
||||
f32 font_ascent;
|
||||
f32 font_descent;
|
||||
@ -97,7 +97,7 @@ Struct(GC_Cmd)
|
||||
{
|
||||
GC_Glyph *glyph;
|
||||
|
||||
/* Async temporary data */
|
||||
// Async temporary data
|
||||
TTF_GlyphResult rasterized;
|
||||
};
|
||||
|
||||
|
||||
@ -12,7 +12,7 @@ void G_BootstrapCommon(void)
|
||||
|
||||
G_CommandListHandle cl = G_PrepareCommandList(G_QueueKind_Direct);
|
||||
{
|
||||
/* Init quad index buffer */
|
||||
// Init quad index buffer
|
||||
{
|
||||
G_ResourceHandle quad_indices = Zi;
|
||||
u16 quad_data[6] = { 0, 1, 2, 0, 2, 3 };
|
||||
@ -21,13 +21,13 @@ void G_BootstrapCommon(void)
|
||||
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->basic_sampler = G_PushSamplerStateRef(gpu_perm, pt_sampler);
|
||||
}
|
||||
|
||||
/* Init noise texture */
|
||||
// Init noise texture
|
||||
{
|
||||
G_ResourceHandle noise_tex = Zi;
|
||||
String noise_data = DataFromResource(ResourceKeyFromStore(&G_Resources, Lit("noise_128x128x64_16.dat")));
|
||||
@ -55,7 +55,7 @@ void G_BootstrapCommon(void)
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
|
||||
Struct(G_SharedUtilState)
|
||||
{
|
||||
/* Common shared resources */
|
||||
// Common shared resources
|
||||
G_IndexBufferDesc quad_indices;
|
||||
G_SamplerStateRef basic_sampler;
|
||||
G_Texture3DRef basic_noise;
|
||||
|
||||
@ -46,21 +46,21 @@ Enum(G_QueueMask)
|
||||
|
||||
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)
|
||||
{
|
||||
G_QueueCompletions completions; /* Completions that waiters should wait for */
|
||||
G_QueueMask wait_queues; /* Mask of queues that will wait for completions */
|
||||
b32 wait_cpu; /* Will the cpu wait for completion */
|
||||
G_QueueCompletions completions; // Completions that waiters should wait for
|
||||
G_QueueMask wait_queues; // Mask of queues that will wait for completions
|
||||
b32 wait_cpu; // Will the cpu wait for completion
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Format types
|
||||
|
||||
/* NOTE: Matches DirectX DXGI_FORMAT */
|
||||
// NOTE: Matches DirectX DXGI_FORMAT
|
||||
Enum(G_Format)
|
||||
{
|
||||
G_Format_Unknown = 0,
|
||||
@ -195,23 +195,23 @@ Enum(G_Stage)
|
||||
{
|
||||
G_Stage_None = 0,
|
||||
|
||||
/* Compute stages */
|
||||
// Compute stages
|
||||
G_Stage_ComputeShading = (1 << 1),
|
||||
|
||||
/* Draw stages */
|
||||
// Draw stages
|
||||
G_Stage_IndexAssembly = (1 << 2),
|
||||
G_Stage_VertexShading = (1 << 3),
|
||||
G_Stage_PixelShading = (1 << 4),
|
||||
G_Stage_DepthStencil = (1 << 5),
|
||||
G_Stage_RenderTarget = (1 << 6),
|
||||
|
||||
/* Copy stages */
|
||||
// Copy stages
|
||||
G_Stage_Copy = (1 << 7),
|
||||
|
||||
/* Indirect stages */
|
||||
// Indirect stages
|
||||
G_Stage_Indirect = (1 << 8),
|
||||
|
||||
/* Aggregate stages */
|
||||
// Aggregate stages
|
||||
G_Stage_AllDraw = G_Stage_IndexAssembly |
|
||||
G_Stage_VertexShading |
|
||||
G_Stage_PixelShading |
|
||||
@ -249,61 +249,58 @@ Enum(G_Layout)
|
||||
{
|
||||
G_Layout_NoChange,
|
||||
|
||||
/* 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
|
||||
* any texels currently being read.
|
||||
*
|
||||
* Resources cannot transition to/from this layout. They must be created
|
||||
* with it and are locked to it.
|
||||
*/
|
||||
G_Layout_Simultaneous, /* D3D12_BARRIER_LAYOUT_COMMON + D3D12_RESOURCE_FLAG_ALLOW_SIMULTANEOUS_ACCESS */
|
||||
// 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
|
||||
// any texels currently being read.
|
||||
// Resources cannot transition to/from this layout. They must be created
|
||||
// with it and are locked to it.
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
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_ShaderRead, /* D3D12_BARRIER_LAYOUT_SHADER_RESOURCE */
|
||||
G_Layout_DirectComputeQueue_CopyRead, /* D3D12_BARRIER_LAYOUT_COPY_SOURCE */
|
||||
G_Layout_DirectComputeQueue_ShaderReadWrite, // D3D12_BARRIER_LAYOUT_UNORDERED_ACCESS
|
||||
G_Layout_DirectComputeQueue_ShaderRead, // D3D12_BARRIER_LAYOUT_SHADER_RESOURCE
|
||||
G_Layout_DirectComputeQueue_CopyRead, // D3D12_BARRIER_LAYOUT_COPY_SOURCE
|
||||
|
||||
//////////////////////////////
|
||||
//- Direct queue
|
||||
|
||||
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_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_ShaderReadWrite, /* D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_UNORDERED_ACCESS */
|
||||
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_ShaderReadWrite, // D3D12_BARRIER_LAYOUT_DIRECT_QUEUE_UNORDERED_ACCESS
|
||||
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_DepthStencilRead_DepthStencilWrite, /* D3D12_BARRIER_LAYOUT_DEPTH_STENCIL_WRITE */
|
||||
G_Layout_DirectQueue_DepthStencilRead, /* D3D12_BARRIER_LAYOUT_DEPTH_STENCIL_READ */
|
||||
G_Layout_DirectQueue_RenderTargetWrite, /* D3D12_BARRIER_LAYOUT_RENDER_TARGET */
|
||||
G_Layout_DirectQueue_DepthStencilRead_DepthStencilWrite, // D3D12_BARRIER_LAYOUT_DEPTH_STENCIL_WRITE
|
||||
G_Layout_DirectQueue_DepthStencilRead, // D3D12_BARRIER_LAYOUT_DEPTH_STENCIL_READ
|
||||
G_Layout_DirectQueue_RenderTargetWrite, // D3D12_BARRIER_LAYOUT_RENDER_TARGET
|
||||
|
||||
//////////////////////////////
|
||||
//- Compute queue
|
||||
|
||||
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_ShaderReadWrite_CopyRead_CopyWrite, // D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_COMMON
|
||||
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_ShaderRead, /* D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_SHADER_RESOURCE */
|
||||
G_Layout_ComputeQueue_CopyRead, /* D3D12_BARRIER_LAYOUT_COMPUTE_QUEUE_COPY_SOURCE */
|
||||
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_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`.
|
||||
* When barrier executes:
|
||||
* - Necessary resource flushes will occur based on `access_prev` & `access_next`
|
||||
* - Texture layout will transition based on `layout` (if specified)
|
||||
*/
|
||||
// Barrier will execute after previous stages specified by `stage_prev`, and before next stages specified by `stage_next`.
|
||||
// When barrier executes:
|
||||
// - Necessary resource flushes will occur based on `access_prev` & `access_next`
|
||||
// - Texture layout will transition based on `layout` (if specified)
|
||||
Struct(G_MemoryBarrierDesc)
|
||||
{
|
||||
G_ResourceHandle resource;
|
||||
@ -318,10 +315,10 @@ Struct(G_MemoryBarrierDesc)
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Filter types
|
||||
|
||||
/* NOTE: Matches DirectX D3D12_FILTER */
|
||||
// NOTE: Matches DirectX D3D12_FILTER
|
||||
Enum(G_Filter)
|
||||
{
|
||||
/* Standard filter */
|
||||
// Standard filter
|
||||
G_Filter_MinMagMipPoint = 0,
|
||||
G_Filter_MinMagPointMipLinear = 0x1,
|
||||
G_Filter_MinPointMagLinearMipPoint = 0x4,
|
||||
@ -333,7 +330,7 @@ Enum(G_Filter)
|
||||
G_Filter_MinMagAnisotropicMipPoint = 0x54,
|
||||
G_Filter_Anisotropic = 0x55,
|
||||
|
||||
/* Comparison filter */
|
||||
// Comparison filter
|
||||
G_Filter_Comparison_MinMagMipPoint = 0x80,
|
||||
G_Filter_Comparison_MinMagPointMipLinear = 0x81,
|
||||
G_Filter_Comparison_MinPointMagLinearMipPoint = 0x84,
|
||||
@ -345,7 +342,7 @@ Enum(G_Filter)
|
||||
G_Filter_Comparison_MinMagAnisotropicMipPoint = 0xd4,
|
||||
G_Filter_Comparison_Anisotropic = 0xd5,
|
||||
|
||||
/* Minimum filter */
|
||||
// Minimum filter
|
||||
G_Filter_Minimum_MinMagMipPoint = 0x100,
|
||||
G_Filter_Minimum_MinMagPointMipLinear = 0x101,
|
||||
G_Filter_Minimum_MinPointMagLinearMipPoint = 0x104,
|
||||
@ -357,7 +354,7 @@ Enum(G_Filter)
|
||||
G_Filter_Minimum_MinMagAnisotropicMipPoint = 0x155,
|
||||
G_Filter_Minimum_Anisotropic = 0x155,
|
||||
|
||||
/* Maximum filter */
|
||||
// Maximum filter
|
||||
G_Filter_Maximum_MinMagMipPoint = 0x180,
|
||||
G_Filter_Maximum_MinMagPointMipLinear = 0x181,
|
||||
G_Filter_Maximum_MinPointMagLinearMipPoint = 0x184,
|
||||
@ -370,17 +367,17 @@ Enum(G_Filter)
|
||||
G_Filter_Maximum_Anisotropic = 0x1d5
|
||||
};
|
||||
|
||||
/* NOTE: Matches DirectX D3D12_TEXTURE_ADDRESS_MODE */
|
||||
// NOTE: Matches DirectX D3D12_TEXTURE_ADDRESS_MODE
|
||||
Enum(G_AddressMode)
|
||||
{
|
||||
G_AddressMode_Wrap = 1,
|
||||
G_AddressMode_Mirror = 2,
|
||||
G_AddressMode_Clamp = 3, /* Default */
|
||||
G_AddressMode_Clamp = 3, // Default
|
||||
G_AddressMode_Border = 4,
|
||||
G_AddressMode_MirrorOnce = 5
|
||||
};
|
||||
|
||||
/* NOTE: Matches DirectX D3D12_COMPARISON_FUNC */
|
||||
// NOTE: Matches DirectX D3D12_COMPARISON_FUNC
|
||||
Enum(G_ComparisonFunc)
|
||||
{
|
||||
G_ComparisonFunc_None = 0,
|
||||
@ -412,8 +409,8 @@ Enum(G_ResourceFlag)
|
||||
G_ResourceFlag_AllowShaderReadWrite = (1 << 0),
|
||||
G_ResourceFlag_AllowRenderTarget = (1 << 1),
|
||||
G_ResourceFlag_AllowDepthStencil = (1 << 2),
|
||||
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_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
|
||||
};
|
||||
|
||||
Struct(G_BufferDesc)
|
||||
@ -428,7 +425,7 @@ Struct(G_TextureDesc)
|
||||
G_Format format;
|
||||
Vec3I32 dims;
|
||||
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;
|
||||
};
|
||||
|
||||
@ -485,7 +482,7 @@ Enum(G_RasterMode)
|
||||
Struct(G_IndexBufferDesc)
|
||||
{
|
||||
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;
|
||||
};
|
||||
|
||||
@ -494,17 +491,17 @@ Struct(G_IndexBufferDesc)
|
||||
|
||||
Struct(G_Stats)
|
||||
{
|
||||
/* Memory usage */
|
||||
// Memory usage
|
||||
u64 local_committed;
|
||||
u64 local_budget;
|
||||
u64 non_local_committed;
|
||||
u64 non_local_budget;
|
||||
|
||||
/* Resources */
|
||||
// Resources
|
||||
u64 driver_resources_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);
|
||||
void G_ReleaseSwapchain(G_SwapchainHandle swapchain);
|
||||
|
||||
/* Waits until a new backbuffer is ready from the swapchain.
|
||||
* This should be called before rendering for minimum latency. */
|
||||
// Waits until a new backbuffer is ready from the swapchain.
|
||||
// This should be called before rendering for minimum latency.
|
||||
G_ResourceHandle G_PrepareBackbuffer(G_SwapchainHandle swapchain_handle, G_Format format, Vec2I32 size);
|
||||
|
||||
void G_CommitBackbuffer(G_ResourceHandle backbuffer, i32 vsync);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -71,22 +71,22 @@ Struct(G_D12_Resource)
|
||||
u64 uid;
|
||||
G_ResourceFlag flags;
|
||||
|
||||
/* Buffer info */
|
||||
// Buffer info
|
||||
u64 buffer_size;
|
||||
u64 buffer_size_actual;
|
||||
D3D12_GPU_VIRTUAL_ADDRESS buffer_gpu_address;
|
||||
|
||||
/* Texture info */
|
||||
// Texture info
|
||||
b32 is_texture;
|
||||
G_Format texture_format;
|
||||
Vec3I32 texture_dims;
|
||||
i32 texture_mip_levels;
|
||||
D3D12_BARRIER_LAYOUT texture_layout;
|
||||
|
||||
/* Sampler info */
|
||||
// Sampler info
|
||||
G_SamplerDesc sampler_desc;
|
||||
|
||||
/* Backbuffer info */
|
||||
// Backbuffer info
|
||||
struct G_D12_Swapchain *swapchain;
|
||||
};
|
||||
|
||||
@ -147,12 +147,11 @@ Struct(G_D12_DescriptorList)
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Arena types
|
||||
|
||||
/* TODO:
|
||||
* To support D3D12_RESOURCE_HEAP_TIER_1 devices, create separate heaps for:
|
||||
* - Buffers
|
||||
* - Non-render target & non-depth stencil textures
|
||||
* - Render target or depth stencil textures
|
||||
*/
|
||||
// TODO:
|
||||
// To support D3D12_RESOURCE_HEAP_TIER_1 devices, create separate heaps for:
|
||||
// - Buffers
|
||||
// - Non-render target & non-depth stencil textures
|
||||
// - Render target or depth stencil textures
|
||||
Enum(G_D12_ResourceHeapKind)
|
||||
{
|
||||
G_D12_ResourceHeapKind_Gpu,
|
||||
@ -212,14 +211,14 @@ Struct(G_D12_StagingRegionNode)
|
||||
{
|
||||
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 *next;
|
||||
|
||||
/* Command list links */
|
||||
// Command list links
|
||||
G_D12_StagingRegionNode *next_in_command_list;
|
||||
|
||||
/* Region info */
|
||||
// Region info
|
||||
Atomic64 completion_target;
|
||||
u64 pos;
|
||||
};
|
||||
@ -242,17 +241,17 @@ Struct(G_D12_Queue)
|
||||
ID3D12Fence *commit_fence;
|
||||
u64 commit_fence_target;
|
||||
|
||||
/* Global resources */
|
||||
// Global resources
|
||||
u64 print_buffer_size;
|
||||
G_ResourceHandle print_buffer;
|
||||
G_ResourceHandle print_readback_buffer;
|
||||
G_RWByteAddressBufferRef print_buffer_ref;
|
||||
|
||||
/* Raw command lists */
|
||||
// Raw command lists
|
||||
struct G_D12_RawCommandList *first_committed_cl;
|
||||
struct G_D12_RawCommandList *last_committed_cl;
|
||||
|
||||
/* Staging heap */
|
||||
// Staging heap
|
||||
Mutex staging_mutex;
|
||||
G_D12_StagingRing *staging_ring;
|
||||
|
||||
@ -272,7 +271,7 @@ Struct(G_D12_RawCommandList)
|
||||
ID3D12CommandAllocator *d3d_ca;
|
||||
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_clear_descriptor;
|
||||
};
|
||||
@ -311,7 +310,7 @@ Struct(G_D12_Cmd)
|
||||
{
|
||||
G_MemoryBarrierDesc desc;
|
||||
|
||||
/* Post-batch data */
|
||||
// Post-batch data
|
||||
b32 is_end_of_batch;
|
||||
u64 batch_gen;
|
||||
} barrier;
|
||||
@ -414,35 +413,35 @@ Struct(G_D12_SharedState)
|
||||
{
|
||||
Atomic64Padded resource_creation_gen;
|
||||
|
||||
/* Stats */
|
||||
// Stats
|
||||
Atomic64 driver_resources_allocated;
|
||||
Atomic64 driver_descriptors_allocated;
|
||||
|
||||
/* Queues */
|
||||
// Queues
|
||||
G_D12_Queue queues[G_NumQueues];
|
||||
|
||||
/* Descriptor heaps */
|
||||
// Descriptor heaps
|
||||
G_D12_DescriptorHeap descriptor_heaps[G_D12_DescriptorHeapKind_Count];
|
||||
|
||||
/* Rootsig */
|
||||
// Rootsig
|
||||
ID3D12RootSignature *bindless_rootsig;
|
||||
|
||||
/* Pipelines */
|
||||
// Pipelines
|
||||
G_D12_PipelineBin pipeline_bins[1024];
|
||||
|
||||
/* Command lists */
|
||||
// Command lists
|
||||
Mutex free_cmd_lists_mutex;
|
||||
G_D12_CmdList *first_free_cmd_list;
|
||||
|
||||
/* Command chunks */
|
||||
// Command chunks
|
||||
Mutex free_cmd_chunks_mutex;
|
||||
G_D12_CmdChunk *first_free_cmd_chunk;
|
||||
|
||||
/* Swapchains */
|
||||
// Swapchains
|
||||
Mutex free_swapchains_mutex;
|
||||
G_D12_Swapchain *first_free_swapchain;
|
||||
|
||||
/* Device */
|
||||
// Device
|
||||
IDXGIFactory6 *factory;
|
||||
IDXGIAdapter3 *adapter;
|
||||
ID3D12Device10 *device;
|
||||
|
||||
@ -33,13 +33,13 @@ Struct(G_SamplerStateRef) { u32 v; };
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Constant types
|
||||
|
||||
/*
|
||||
* D3D12 exposes 64 root constants and Vulkan exposes 32 push constants.
|
||||
* Supposedly amd hardware will spill constants to scratch memory once there
|
||||
* are more than 13: https://gpuopen.com/learn/rdna-performance-guide/
|
||||
*/
|
||||
#define G_NumGeneralPurposeConstants (8) /* Constants available for any usage */
|
||||
#define G_NumReservedConstants (1) /* Constants reserved for usage by the GPU layer */
|
||||
//
|
||||
// D3D12 exposes 64 root constants and Vulkan exposes 32 push constants.
|
||||
// Supposedly amd hardware will spill constants to scratch memory once there
|
||||
// are more than 13: https://gpuopen.com/learn/rdna-performance-guide/
|
||||
//
|
||||
#define G_NumGeneralPurposeConstants (8) // Constants available for any usage
|
||||
#define G_NumReservedConstants (1) // Constants reserved for usage by the GPU layer
|
||||
#define G_NumConstants (G_NumGeneralPurposeConstants + G_NumReservedConstants)
|
||||
|
||||
#if IsLanguageC
|
||||
@ -59,9 +59,9 @@ Struct(G_SamplerStateRef) { u32 v; };
|
||||
//~ Resource dereference
|
||||
|
||||
#if IsLanguageG
|
||||
/* TODO: Non-uniform resource access currently is assumed as the default
|
||||
* behavior. We may want to add explicit "uniform" variants for
|
||||
* optimization on amd in the future. */
|
||||
// TODO: Non-uniform resource access currently is assumed as the default
|
||||
// behavior. We may want to add explicit "uniform" variants for
|
||||
// optimization on amd in the future.
|
||||
|
||||
template<typename T> StructuredBuffer<T> G_Dereference(G_StructuredBufferRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; }
|
||||
template<typename T> RWStructuredBuffer<T> G_Dereference(G_RWStructuredBufferRef r) { return ResourceDescriptorHeap[NonUniformResourceIndex(r.v)]; }
|
||||
@ -98,7 +98,7 @@ Struct(G_SamplerStateRef) { u32 v; };
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ 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_NumReservedConstants == 1);
|
||||
|
||||
@ -107,7 +107,7 @@ G_ForceDeclConstant(G_RWByteAddressBufferRef, G_ShaderConst_PrintBufferRef, 8)
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ 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)
|
||||
{
|
||||
@ -165,7 +165,7 @@ Struct(G_FmtArg)
|
||||
|
||||
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 bytes_count;
|
||||
u32 chars_count;
|
||||
@ -181,7 +181,7 @@ Struct(G_FmtArg)
|
||||
u32 byte_idx_in_chunk = buff.bytes_count & 0x03;
|
||||
if (byte_idx_in_chunk == 0)
|
||||
{
|
||||
/* Since buff is not zero initialized, we set the chunk on first write here */
|
||||
// Since buff is not zero initialized, we set the chunk on first write here
|
||||
buff.byte_chunks[chunk_idx] = v & 0xFF;
|
||||
}
|
||||
else
|
||||
@ -209,23 +209,23 @@ Struct(G_FmtArg)
|
||||
|
||||
u32 chunks_count = (buff.bytes_count + 3) / 4;
|
||||
u32 alloc_size = 0;
|
||||
alloc_size += 4; /* Header */
|
||||
alloc_size += chunks_count * 4; /* Chunks */
|
||||
alloc_size += 4; // Header
|
||||
alloc_size += chunks_count * 4; // Chunks
|
||||
|
||||
/* Atomic fetch + add to base counter */
|
||||
// Atomic fetch + add to base counter
|
||||
u32 base;
|
||||
rw.InterlockedAdd(0, alloc_size, base);
|
||||
base += 4; /* Offset for allocation counter */
|
||||
base += 4; /* Offset for success counter */
|
||||
base += 4; /* Offset for overflow counter */
|
||||
base += 4; // Offset for allocation counter
|
||||
base += 4; // Offset for success counter
|
||||
base += 4; // Offset for overflow counter
|
||||
|
||||
if ((base + alloc_size) < countof(rw))
|
||||
{
|
||||
/* Increment success counter */
|
||||
// Increment success counter
|
||||
rw.InterlockedAdd(4, 1);
|
||||
u32 pos = 0;
|
||||
|
||||
/* Write header */
|
||||
// Write header
|
||||
{
|
||||
u32 header = 0;
|
||||
header |= (buff.chars_count << 0) & 0x0000FFFF;
|
||||
@ -235,7 +235,7 @@ Struct(G_FmtArg)
|
||||
pos += 4;
|
||||
}
|
||||
|
||||
/* Write chunks */
|
||||
// Write chunks
|
||||
for (u32 chunk_idx = 0; chunk_idx < chunks_count; ++chunk_idx)
|
||||
{
|
||||
u32 chunk = buff.byte_chunks[chunk_idx];
|
||||
@ -245,7 +245,7 @@ Struct(G_FmtArg)
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Increment overflow counter */
|
||||
// Increment overflow counter
|
||||
rw.InterlockedAdd(8, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
/* TODO (if we want to be JSON standard compliant):
|
||||
* - Support unicode escape sequences in strings (\u)
|
||||
* - Don't allow leading 0s in numbers
|
||||
*/
|
||||
// TODO (if we want to be JSON standard compliant):
|
||||
// - Support unicode escape sequences in strings (\u)
|
||||
// - Don't allow leading 0s in numbers
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Lex
|
||||
@ -32,7 +31,7 @@ JSON_TokenList JSON_TokensFromString(Arena *arena, String src)
|
||||
b32 lexing_done = 0;
|
||||
while (!lexing_done)
|
||||
{
|
||||
/* Skip whitespace */
|
||||
// Skip whitespace
|
||||
b32 whitespace_done = 0;
|
||||
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);
|
||||
t->start = pos;
|
||||
|
||||
if (pos >= src.len)
|
||||
{
|
||||
t->kind = JSON_TokenKind_Eof;
|
||||
t->next = t; /* Self reference */
|
||||
t->next = t; // Self reference
|
||||
lexing_done = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Lex known token kinds */
|
||||
// Lex known token kinds
|
||||
switch (src.text[pos])
|
||||
{
|
||||
default: break;
|
||||
|
||||
/* Symbols */
|
||||
// Symbols
|
||||
case ',':
|
||||
{
|
||||
t->kind = JSON_TokenKind_Comma;
|
||||
@ -105,10 +104,10 @@ JSON_TokenList JSON_TokensFromString(Arena *arena, String src)
|
||||
++pos;
|
||||
} break;
|
||||
|
||||
/* Number */
|
||||
// Number
|
||||
case '-':
|
||||
{
|
||||
/* Verify '-' precedes digit */
|
||||
// Verify '-' precedes digit
|
||||
b32 next_is_digit = 0;
|
||||
if ((pos + 1) < src.len)
|
||||
{
|
||||
@ -157,7 +156,7 @@ JSON_TokenList JSON_TokensFromString(Arena *arena, String src)
|
||||
|
||||
case JSON_Case_Digit0Through9:
|
||||
{
|
||||
/* Consume '.' */
|
||||
// Consume '.'
|
||||
++consume;
|
||||
} break;
|
||||
}
|
||||
@ -184,7 +183,7 @@ JSON_TokenList JSON_TokensFromString(Arena *arena, String src)
|
||||
{
|
||||
case JSON_Case_Digit0Through9:
|
||||
{
|
||||
/* Consume 'E'/'e' */
|
||||
// Consume 'E'/'e'
|
||||
++consume;
|
||||
} break;
|
||||
|
||||
@ -200,7 +199,7 @@ JSON_TokenList JSON_TokensFromString(Arena *arena, String src)
|
||||
|
||||
case JSON_Case_Digit0Through9:
|
||||
{
|
||||
/* Consume 'E'/'e' & '+'/'-' */
|
||||
// Consume 'E'/'e' & '+'/'-'
|
||||
consume += 2;
|
||||
} break;
|
||||
}
|
||||
@ -224,7 +223,7 @@ JSON_TokenList JSON_TokensFromString(Arena *arena, String src)
|
||||
}
|
||||
} break;
|
||||
|
||||
/* String */
|
||||
// String
|
||||
case '"':
|
||||
{
|
||||
++pos;
|
||||
@ -270,7 +269,7 @@ JSON_TokenList JSON_TokensFromString(Arena *arena, String src)
|
||||
}
|
||||
} break;
|
||||
|
||||
/* Keywords */
|
||||
// Keywords
|
||||
case 't':
|
||||
case 'f':
|
||||
case 'n':
|
||||
@ -282,7 +281,7 @@ JSON_TokenList JSON_TokensFromString(Arena *arena, String src)
|
||||
{
|
||||
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])
|
||||
{
|
||||
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)
|
||||
{
|
||||
b32 unknown_done = 0;
|
||||
@ -339,7 +338,7 @@ JSON_TokenList JSON_TokensFromString(Arena *arena, String src)
|
||||
}
|
||||
t->end = pos;
|
||||
|
||||
/* Exit early if unknown token encountered */
|
||||
// Exit early if unknown token encountered
|
||||
return result;
|
||||
}
|
||||
else
|
||||
@ -370,7 +369,7 @@ f64 interpret_number(String src)
|
||||
u64 exponent_right = 0;
|
||||
i32 exponent_sign = 1;
|
||||
|
||||
/* Lex number parts */
|
||||
// Lex number parts
|
||||
{
|
||||
u64 pos = 0;
|
||||
if (src.len > 0 && src.text[0] == '-')
|
||||
@ -386,7 +385,7 @@ f64 interpret_number(String src)
|
||||
{
|
||||
default:
|
||||
{
|
||||
/* Unreachable */
|
||||
// Unreachable
|
||||
Assert(0);
|
||||
++pos;
|
||||
} break;
|
||||
@ -449,7 +448,7 @@ f64 interpret_number(String src)
|
||||
{
|
||||
default:
|
||||
{
|
||||
/* Unreachable */
|
||||
// Unreachable
|
||||
Assert(0);
|
||||
++pos;
|
||||
} break;
|
||||
@ -474,7 +473,7 @@ f64 interpret_number(String src)
|
||||
{
|
||||
default:
|
||||
{
|
||||
/* Unreachable */
|
||||
// Unreachable
|
||||
Assert(0);
|
||||
++pos;
|
||||
} break;
|
||||
@ -492,7 +491,7 @@ f64 interpret_number(String src)
|
||||
|
||||
f64 result = 0;
|
||||
|
||||
/* Process whole part */
|
||||
// Process whole part
|
||||
if (whole_present)
|
||||
{
|
||||
u64 pos = whole_left;
|
||||
@ -506,7 +505,7 @@ f64 interpret_number(String src)
|
||||
result *= whole_sign;
|
||||
}
|
||||
|
||||
/* Process fraction part */
|
||||
// Process fraction part
|
||||
if (fraction_present)
|
||||
{
|
||||
u64 frac_whole = 0;
|
||||
@ -522,7 +521,7 @@ f64 interpret_number(String src)
|
||||
result += (f64)frac_whole / PowU64(10, (fraction_right - fraction_left + 1));
|
||||
}
|
||||
|
||||
/* Process exponent part */
|
||||
// Process exponent part
|
||||
if (exponent_present)
|
||||
{
|
||||
u64 exponent_whole = 0;
|
||||
@ -563,7 +562,7 @@ String interpret_string(Arena *arena, String src, String *error)
|
||||
}
|
||||
return result;
|
||||
}
|
||||
/* Ignore beginning quote */
|
||||
// Ignore beginning quote
|
||||
u64 pos = 1;
|
||||
|
||||
b32 valid_close = 0;
|
||||
@ -596,7 +595,7 @@ String interpret_string(Arena *arena, String src, String *error)
|
||||
++pos;
|
||||
} break;
|
||||
|
||||
/* Backspace */
|
||||
// Backspace
|
||||
case 'b':
|
||||
{
|
||||
*PushStructNoZero(arena, u8) = '\b';
|
||||
@ -604,7 +603,7 @@ String interpret_string(Arena *arena, String src, String *error)
|
||||
++pos;
|
||||
} break;
|
||||
|
||||
/* Formfeed */
|
||||
// Formfeed
|
||||
case 'f':
|
||||
{
|
||||
*PushStructNoZero(arena, u8) = '\f';
|
||||
@ -612,7 +611,7 @@ String interpret_string(Arena *arena, String src, String *error)
|
||||
++pos;
|
||||
} break;
|
||||
|
||||
/* Linefeed */
|
||||
// Linefeed
|
||||
case 'n':
|
||||
{
|
||||
*PushStructNoZero(arena, u8) = '\n';
|
||||
@ -620,7 +619,7 @@ String interpret_string(Arena *arena, String src, String *error)
|
||||
++pos;
|
||||
} break;
|
||||
|
||||
/* Carriage return */
|
||||
// Carriage return
|
||||
case 'r':
|
||||
{
|
||||
*PushStructNoZero(arena, u8) = '\r';
|
||||
@ -628,7 +627,7 @@ String interpret_string(Arena *arena, String src, String *error)
|
||||
++pos;
|
||||
} break;
|
||||
|
||||
/* Horizontal tab */
|
||||
// Horizontal tab
|
||||
case 't':
|
||||
{
|
||||
*PushStructNoZero(arena, u8) = '\t';
|
||||
@ -636,10 +635,10 @@ String interpret_string(Arena *arena, String src, String *error)
|
||||
++pos;
|
||||
} break;
|
||||
|
||||
/* TODO: Unicode escape support */
|
||||
// TODO: Unicode escape support
|
||||
// case 'u':
|
||||
// {
|
||||
// /* TODO */
|
||||
// // TODO
|
||||
// } break;
|
||||
}
|
||||
}
|
||||
@ -717,7 +716,7 @@ void JSON_Parse(Arena *arena, JSON_Parser *p)
|
||||
at = at->next;
|
||||
}
|
||||
|
||||
/* Depth first stack */
|
||||
// Depth first stack
|
||||
*PushStructNoZero(scratch.arena, JSON_Blob *) = root;
|
||||
u64 stack_count = 1;
|
||||
|
||||
@ -731,7 +730,7 @@ void JSON_Parse(Arena *arena, JSON_Parser *p)
|
||||
b32 is_new_parent = 0;
|
||||
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;
|
||||
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)
|
||||
{
|
||||
/* Parse key */
|
||||
// Parse key
|
||||
if (at->kind == JSON_TokenKind_String)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/* Parse colon */
|
||||
// Parse colon
|
||||
if (at->kind == JSON_TokenKind_Colon)
|
||||
{
|
||||
at = at->next;
|
||||
@ -796,7 +795,7 @@ void JSON_Parse(Arena *arena, JSON_Parser *p)
|
||||
parent_json->child_last = json;
|
||||
}
|
||||
|
||||
/* Parse value */
|
||||
// Parse value
|
||||
switch (at->kind)
|
||||
{
|
||||
default:
|
||||
@ -871,11 +870,11 @@ void JSON_Parse(Arena *arena, JSON_Parser *p)
|
||||
|
||||
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;
|
||||
++stack_count;
|
||||
|
||||
/* Create child & push to stack */
|
||||
// Create child & push to stack
|
||||
JSON_Blob *child = PushStruct(arena, JSON_Blob);
|
||||
child->parent = json;
|
||||
*PushStructNoZero(scratch.arena, JSON_Blob *) = child;
|
||||
@ -883,10 +882,10 @@ void JSON_Parse(Arena *arena, JSON_Parser *p)
|
||||
}
|
||||
else if (parent_json)
|
||||
{
|
||||
/* Check for comma */
|
||||
// Check for comma
|
||||
if (at->kind == JSON_TokenKind_Comma)
|
||||
{
|
||||
/* Create sibling & push to stack */
|
||||
// Create sibling & push to stack
|
||||
JSON_Blob *sibling = PushStruct(arena, JSON_Blob);
|
||||
sibling->parent = parent_json;
|
||||
*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);
|
||||
|
||||
/* Parse root */
|
||||
// Parse root
|
||||
JSON_Parser p = ZI;
|
||||
p.src = src;
|
||||
p.at = tl.token_first;
|
||||
JSON_Parse(arena, &p);
|
||||
|
||||
/* Verify end of file */
|
||||
// Verify end of file
|
||||
if (p.errors.count == 0 && p.at->kind != JSON_TokenKind_Eof)
|
||||
{
|
||||
JSON_PushError(arena, &p, p.at, Lit("Expected end of file."));
|
||||
|
||||
@ -130,11 +130,11 @@ Global Readonly JSON_TokenKind JSON_keyword_types[] = {
|
||||
|
||||
Struct(JSON_Parser)
|
||||
{
|
||||
/* Input */
|
||||
// Input
|
||||
String src;
|
||||
JSON_Token *at;
|
||||
|
||||
/* Output */
|
||||
// Output
|
||||
JSON_Blob *root;
|
||||
JSON_ErrorList errors;
|
||||
};
|
||||
|
||||
175
src/meta/meta.c
175
src/meta/meta.c
@ -110,7 +110,7 @@ EmbedObj Embed(String store_name, String dir_path)
|
||||
Arena *perm = PermArena();
|
||||
EmbedObj result = Zi;
|
||||
|
||||
/* Generate resource archive contents */
|
||||
// Generate resource archive contents
|
||||
String arc_contents = Zi;
|
||||
{
|
||||
StringList files = Zi;
|
||||
@ -156,17 +156,18 @@ EmbedObj Embed(String store_name, String dir_path)
|
||||
BB_Buff bb = BB_AcquireBuff(Gibi(2));
|
||||
BB_Writer bw = BB_WriterFromBuff(&bb);
|
||||
|
||||
/* Write magic */
|
||||
// Write magic
|
||||
BB_WriteUBits(&bw, ResourceEmbeddedMagic, 64);
|
||||
|
||||
/* Write header */
|
||||
// Write header
|
||||
BB_WriteUBits(&bw, entries_count, 64);
|
||||
|
||||
/* Reserve entries space */
|
||||
u64 entry_size = 8 /* Name start */
|
||||
+ 8 /* Name end */
|
||||
+ 8 /* Data start */
|
||||
+ 8; /* Data end */
|
||||
// Reserve entries space
|
||||
u64 entry_size = 0
|
||||
+ 8 // Name start
|
||||
+ 8 // Name end
|
||||
+ 8 // Data start
|
||||
+ 8; // Data end
|
||||
u8 *entries_start = BB_GetWrittenRaw(&bw) + BB_GetNumBytesWritten(&bw);
|
||||
u64 entries_size = entry_size * entries_count;
|
||||
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_Writer entries_bw = BB_WriterFromBuff(&entries_bb);
|
||||
|
||||
/* Write entries */
|
||||
// Write entries
|
||||
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);
|
||||
|
||||
/* Write name */
|
||||
// Write name
|
||||
BB_WriteAlignBytes(&bw, 64);
|
||||
u64 name_start = BB_GetNumBytesWritten(&bw) + 1;
|
||||
BB_WriteString(&bw, en->entry_name);
|
||||
u64 name_len = BB_GetNumBytesWritten(&bw) - name_start;
|
||||
|
||||
/* Write data */
|
||||
// Write data
|
||||
BB_WriteAlignBytes(&bw, 64);
|
||||
/* FIXME: Why no +1 here? */
|
||||
// FIXME: Why no +1 here?
|
||||
u64 data_start = BB_GetNumBytesWritten(&bw);
|
||||
BB_WriteBytes(&bw, file_data);
|
||||
u64 data_len = BB_GetNumBytesWritten(&bw) - data_start;
|
||||
|
||||
/* Write entry */
|
||||
// Write entry
|
||||
BB_WriteUBits(&entries_bw, name_start, 64);
|
||||
BB_WriteUBits(&entries_bw, name_len, 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);
|
||||
}
|
||||
|
||||
/* Write archive to file */
|
||||
// Write archive to file
|
||||
String arc_path = StringF(perm, "%F.arc", FmtString(store_name));
|
||||
F_ClearWrite(arc_path, arc_contents);
|
||||
|
||||
/* Generate object file */
|
||||
// Generate object file
|
||||
if (IsPlatformWindows)
|
||||
{
|
||||
/* Generate RC file */
|
||||
// Generate RC file
|
||||
String rc_out_file = StringF(perm, "%F.rc", FmtString(store_name));
|
||||
{
|
||||
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 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);
|
||||
/* Write to file */
|
||||
// Write to file
|
||||
String rc_out = StringFromList(perm, rc_out_lines, Lit("\n"));
|
||||
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, FmtString(F_GetFull(perm, rc_out_file));
|
||||
@ -239,7 +240,7 @@ EmbedObj Embed(String store_name, String dir_path)
|
||||
}
|
||||
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"));
|
||||
}
|
||||
|
||||
@ -256,10 +257,10 @@ void BuildEntryPoint(WaveLaneCtx *lane)
|
||||
//////////////////////////////
|
||||
//- Dirty check
|
||||
|
||||
/* Return rebuild code if metaprogram is dirty */
|
||||
// Return rebuild code if metaprogram is dirty
|
||||
if (lane->idx == 0)
|
||||
{
|
||||
/* Read old metahash */
|
||||
// Read old metahash
|
||||
u64 old_metahash = 0;
|
||||
if (F_IsFile(Lit("metahash.dat")))
|
||||
{
|
||||
@ -271,7 +272,7 @@ void BuildEntryPoint(WaveLaneCtx *lane)
|
||||
OS_Rm(Lit("metahash.dat"));
|
||||
}
|
||||
|
||||
/* Compute new metahash */
|
||||
// Compute new metahash
|
||||
u64 new_metahash = 0;
|
||||
{
|
||||
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)
|
||||
{
|
||||
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("-nologo"));
|
||||
|
||||
/* Optimization */
|
||||
// Optimization
|
||||
PushStringToList(perm, &cp.compiler_only_flags_msvc, Lit("-Od"));
|
||||
|
||||
/* Debug info */
|
||||
// Debug info
|
||||
PushStringToList(perm, &cp.flags_msvc, Lit("-DEBUG:FULL"));
|
||||
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("-WX"));
|
||||
// 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("-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'
|
||||
|
||||
/* 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("-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("-wd4100")); /* unreferenced parameter */
|
||||
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("-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("-wd4305")); /* 'initializing': truncation from 'double' to 'f32' */
|
||||
// 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("-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("-wd4100")); // unreferenced parameter
|
||||
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("-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("-wd4305")); // 'initializing': truncation from 'double' to 'f32'
|
||||
|
||||
// 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("-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("-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("-wd5045")); /* Compiler will insert Spectre mitigation for memory load if /Qspectre switch specified */
|
||||
// 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("-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("-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("-wd5045")); // Compiler will insert Spectre mitigation for memory load if /Qspectre switch specified
|
||||
}
|
||||
|
||||
//- Clang
|
||||
@ -398,7 +399,7 @@ void BuildEntryPoint(WaveLaneCtx *lane)
|
||||
PushStringToList(perm, &cp.flags_clang, Lit("-O0"));
|
||||
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("-Werror"));
|
||||
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("-Wswitch"));
|
||||
|
||||
/* Disable warnings */
|
||||
// Disable warnings
|
||||
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-unused-variable"));
|
||||
@ -429,23 +430,21 @@ void BuildEntryPoint(WaveLaneCtx *lane)
|
||||
//////////////////////////////
|
||||
//- Phase 1/3: Prep
|
||||
|
||||
/*
|
||||
* Phase 1/3: Prep (narrow)
|
||||
* - Parse layers
|
||||
* - Generate final C file
|
||||
* - Generate final HLSL file
|
||||
* - Generate resource dirs info
|
||||
*
|
||||
* Phase 2/3: Compile (wide)
|
||||
* - Compile C
|
||||
* - Compile & embed shaders
|
||||
* - Embed resource dirs
|
||||
*
|
||||
* Phase 3/3: Link (narrow)
|
||||
* - Link
|
||||
*/
|
||||
// Phase 1/3: Prep (narrow)
|
||||
// - Parse layers
|
||||
// - Generate final C file
|
||||
// - Generate final HLSL file
|
||||
// - Generate resource dirs info
|
||||
//
|
||||
// Phase 2/3: Compile (wide)
|
||||
// - Compile C
|
||||
// - Compile & embed shaders
|
||||
// - Embed resource dirs
|
||||
//
|
||||
// Phase 3/3: Link (narrow)
|
||||
// - Link
|
||||
|
||||
/* TODO: Dispatch OS commands asynchronously */
|
||||
// TODO: Dispatch OS commands asynchronously
|
||||
|
||||
String shader_store_name = Lit("ShadersStore");
|
||||
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
|
||||
{
|
||||
/* Lex */
|
||||
// Lex
|
||||
StringList src_dirs = Zi;
|
||||
PushStringToList(perm, &src_dirs, Lit("../src"));
|
||||
M_TokenFileList lexed = M_TokensFromSrcDirs(perm, src_dirs);
|
||||
|
||||
/* Parse */
|
||||
// Parse
|
||||
M_LayerList parsed = M_LayersFromTokenFiles(perm, lexed);;
|
||||
|
||||
/* Flatten */
|
||||
// Flatten
|
||||
StringList starting_layer_names = Zi;
|
||||
PushStringToList(perm, &starting_layer_names, cmdline.leaf_layer_name);
|
||||
Build.layers_parse = M_FlattenEntries(perm, parsed, starting_layer_names);
|
||||
@ -577,14 +576,14 @@ void BuildEntryPoint(WaveLaneCtx *lane)
|
||||
{
|
||||
StringList c_out_lines = Zi;
|
||||
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"));
|
||||
PushStringToList(perm, &c_out_lines, Lit(""));
|
||||
PushStringToList(perm, &c_out_lines, Lit("//- Base layer includes"));
|
||||
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)
|
||||
{
|
||||
PushStringToList(perm, &c_out_lines, Lit(""));
|
||||
@ -594,7 +593,7 @@ void BuildEntryPoint(WaveLaneCtx *lane)
|
||||
PushStringToList(perm, &c_out_lines, n->s);
|
||||
}
|
||||
}
|
||||
/* Define shaders */
|
||||
// Define shaders
|
||||
if (c_shader_lines.count > 0)
|
||||
{
|
||||
PushStringToList(perm, &c_out_lines, Lit(""));
|
||||
@ -604,7 +603,7 @@ void BuildEntryPoint(WaveLaneCtx *lane)
|
||||
PushStringToList(perm, &c_out_lines, n->s);
|
||||
}
|
||||
}
|
||||
/* Include dependency layers */
|
||||
// Include dependency layers
|
||||
if (c_include_lines.count > 0)
|
||||
{
|
||||
PushStringToList(perm, &c_out_lines, Lit(""));
|
||||
@ -614,7 +613,7 @@ void BuildEntryPoint(WaveLaneCtx *lane)
|
||||
PushStringToList(perm, &c_out_lines, n->s);
|
||||
}
|
||||
}
|
||||
/* Define BootstrapLayers */
|
||||
// Define BootstrapLayers
|
||||
{
|
||||
PushStringToList(perm, &c_out_lines, Lit(""));
|
||||
PushStringToList(perm, &c_out_lines, Lit("//- Bootstrap"));
|
||||
@ -626,7 +625,7 @@ void BuildEntryPoint(WaveLaneCtx *lane)
|
||||
}
|
||||
PushStringToList(perm, &c_out_lines, Lit("}"));
|
||||
}
|
||||
/* Write to file */
|
||||
// Write to file
|
||||
PushStringToList(perm, &c_out_lines, Lit(""));
|
||||
String c_out = StringFromList(perm, c_out_lines, Lit("\n"));
|
||||
F_ClearWrite(c_out_file, c_out);
|
||||
@ -637,30 +636,30 @@ void BuildEntryPoint(WaveLaneCtx *lane)
|
||||
|
||||
//- Generate HLSL file
|
||||
{
|
||||
/* Clear shader store */
|
||||
/* TODO: Move to separate artifacts dir that gets cleared, including archive files */
|
||||
// Clear shader store
|
||||
// TODO: Move to separate artifacts dir that gets cleared, including archive files
|
||||
OS_Mkdir(shader_store_name);
|
||||
{
|
||||
/* Remove all old shaders */
|
||||
// Remove all old shaders
|
||||
StringList files = Zi;
|
||||
F_FilesFromDir(perm, &files, shader_store_name, F_IterFlag_None);
|
||||
for (StringListNode *n = files.first; n; n = n->next)
|
||||
{
|
||||
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")))
|
||||
{
|
||||
OS_Rm(n->s);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Unexpected file in shader store */
|
||||
// Unexpected file in shader store
|
||||
Assert(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Generate GPU file & shader entries */
|
||||
// Generate GPU file & shader entries
|
||||
{
|
||||
StringList gpu_include_lines = Zi;
|
||||
{
|
||||
@ -726,14 +725,14 @@ void BuildEntryPoint(WaveLaneCtx *lane)
|
||||
{
|
||||
StringList gpu_out_lines = Zi;
|
||||
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"));
|
||||
PushStringToList(perm, &gpu_out_lines, Lit(""));
|
||||
PushStringToList(perm, &gpu_out_lines, Lit("//- Base layer includes"));
|
||||
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)
|
||||
{
|
||||
PushStringToList(perm, &gpu_out_lines, Lit(""));
|
||||
@ -743,7 +742,7 @@ void BuildEntryPoint(WaveLaneCtx *lane)
|
||||
PushStringToList(perm, &gpu_out_lines, n->s);
|
||||
}
|
||||
}
|
||||
/* Write to file */
|
||||
// Write to file
|
||||
PushStringToList(perm, &gpu_out_lines, Lit(""));
|
||||
String c_out = StringFromList(perm, gpu_out_lines, Lit("\n"));
|
||||
F_ClearWrite(gpu_out_file, c_out);
|
||||
@ -755,7 +754,7 @@ void BuildEntryPoint(WaveLaneCtx *lane)
|
||||
|
||||
//- Generate archive info
|
||||
{
|
||||
/* Push embedded archive dirs */
|
||||
// Push embedded archive dirs
|
||||
for (M_Entry *entry = Build.layers_parse.first; entry->valid; entry = entry->next)
|
||||
{
|
||||
M_EntryKind kind = entry->kind;
|
||||
@ -800,11 +799,11 @@ void BuildEntryPoint(WaveLaneCtx *lane)
|
||||
|
||||
//- Prep obj arrays
|
||||
{
|
||||
/* Gpu objs */
|
||||
// Gpu objs
|
||||
Build.gpu_objs.count = Build.gpu_parse.shader_entries_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;
|
||||
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.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)))
|
||||
{
|
||||
Build.c_obj.output = Zstr;
|
||||
@ -884,7 +883,7 @@ void BuildEntryPoint(WaveLaneCtx *lane)
|
||||
|
||||
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;
|
||||
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));
|
||||
{
|
||||
/* 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;
|
||||
OS_File file = OS_OpenFile(exe_file, OS_FileFlag_Write, NsFromSeconds(timeout));
|
||||
OS_CloseFile(file);
|
||||
|
||||
@ -15,7 +15,7 @@ Readonly M_Entry M_NilEntry = {
|
||||
.arg_tokens[0] = &M_NilToken,
|
||||
.arg_tokens[1] = &M_NilToken,
|
||||
};
|
||||
StaticAssert(countof(M_NilEntry.arg_tokens) == 2); /* NilEntry must define point args to nil tokens */
|
||||
StaticAssert(countof(M_NilEntry.arg_tokens) == 2); // NilEntry must define point args to nil tokens
|
||||
|
||||
Readonly M_Layer M_NilLayer = {
|
||||
.next = &M_NilLayer,
|
||||
@ -84,7 +84,7 @@ M_TokenFileList M_TokensFromSrcDirs(Arena *arena, StringList src_dirs)
|
||||
result.first = &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);
|
||||
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_whitespace = is_eol || c == ' ';
|
||||
if (is_whitespace)
|
||||
{ /* Whitespace */
|
||||
{ // Whitespace
|
||||
if (cur_ident.len > 0)
|
||||
{
|
||||
M_PushToken(arena, tf, cur_ident, M_TokenKind_Ident);
|
||||
@ -146,12 +146,12 @@ M_TokenFileList M_TokensFromSrcDirs(Arena *arena, StringList src_dirs)
|
||||
p += 1;
|
||||
}
|
||||
else if (c == '/' && (p + 1) < l && t[p + 1] == '/')
|
||||
{ /* Start single line comment */
|
||||
{ // Start single line comment
|
||||
mode = TokenizerMode_SingleLineComment;
|
||||
p += 2;
|
||||
}
|
||||
else if (c == '/' && (p + 1) < l && t[p + 1] == '*')
|
||||
{ /* Start multi line comment */
|
||||
{ // Start multi line comment
|
||||
mode = TokenizerMode_MultiLineComment;
|
||||
p += 2;
|
||||
}
|
||||
@ -169,7 +169,7 @@ M_TokenFileList M_TokensFromSrcDirs(Arena *arena, StringList src_dirs)
|
||||
case TokenizerMode_SingleLineComment:
|
||||
{
|
||||
if (t[p] == '\n')
|
||||
{ /* End single line comment */
|
||||
{ // End single line comment
|
||||
mode = TokenizerMode_None;
|
||||
p += 1;
|
||||
}
|
||||
@ -182,7 +182,7 @@ M_TokenFileList M_TokensFromSrcDirs(Arena *arena, StringList src_dirs)
|
||||
case TokenizerMode_MultiLineComment:
|
||||
{
|
||||
if (t[p] == '*' && (p + 1) < l && t[p + 1] == '/')
|
||||
{ /* End multi line comment */
|
||||
{ // End multi line comment
|
||||
mode = TokenizerMode_None;
|
||||
p += 2;
|
||||
}
|
||||
@ -237,7 +237,7 @@ M_LayerList M_LayersFromTokenFiles(Arena *arena, M_TokenFileList lexed)
|
||||
result.first = &M_NilLayer;
|
||||
result.last = &M_NilLayer;
|
||||
|
||||
/* Copy errors */
|
||||
// Copy errors
|
||||
b32 lexer_errors_present = 0;
|
||||
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
|
||||
{
|
||||
/* Parse entry */
|
||||
// Parse entry
|
||||
entry_token = token;
|
||||
token = token->next;
|
||||
/* Parse args */
|
||||
// Parse args
|
||||
while (token->kind != M_TokenKind_Eol)
|
||||
{
|
||||
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);
|
||||
M_Layer result = M_NilLayer;
|
||||
|
||||
/* Copy errors */
|
||||
// Copy errors
|
||||
b32 unflattened_errors_present = 0;
|
||||
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
|
||||
};
|
||||
|
||||
/* Construct state lookups */
|
||||
// Construct state lookups
|
||||
Dict *layer_ptr_to_state = InitDict(scratch.arena, 1021);
|
||||
Dict *layer_name_to_state = InitDict(scratch.arena, 1021);
|
||||
for (M_Layer *layer = unflattened.first; layer->valid; layer = layer->next)
|
||||
@ -414,7 +414,7 @@ M_Layer M_FlattenEntries(Arena *arena, M_LayerList unflattened, StringList start
|
||||
Struct(StackNode) { StackNode *next; IterState *state; b32 exit; };
|
||||
StackNode *stack = 0;
|
||||
|
||||
/* Init stack with starting layers */
|
||||
// Init stack with starting layers
|
||||
for (StringListNode *sln = starting_layer_names.first; sln; sln = sln->next)
|
||||
{
|
||||
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)
|
||||
{
|
||||
StackNode *stack_node = stack;
|
||||
@ -444,7 +444,7 @@ M_Layer M_FlattenEntries(Arena *arena, M_LayerList unflattened, StringList start
|
||||
|
||||
if (stack_node->exit)
|
||||
{
|
||||
/* Push items to sorted root */
|
||||
// Push items to sorted root
|
||||
state->is_entered = 0;
|
||||
state->is_exited = 1;
|
||||
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)
|
||||
{
|
||||
/* Cyclic dependency */
|
||||
/* FIXME: Handle cyclic dependency error */
|
||||
// Cyclic dependency
|
||||
// FIXME: Handle cyclic dependency error
|
||||
Assert(0);
|
||||
}
|
||||
else if (!state->is_exited)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
/* Determine platform match */
|
||||
// Determine platform match
|
||||
b32 should_include = 0;
|
||||
{
|
||||
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)
|
||||
{
|
||||
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;
|
||||
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)
|
||||
{
|
||||
if (entry->kind == M_EntryKind_Dep)
|
||||
|
||||
@ -30,7 +30,7 @@ Struct(M_File)
|
||||
Enum(M_TokenKind)
|
||||
{
|
||||
M_TokenKind_Ident,
|
||||
M_TokenKind_Eol, /* End of line */
|
||||
M_TokenKind_Eol, // End of line
|
||||
};
|
||||
|
||||
Struct(M_Token)
|
||||
|
||||
@ -212,7 +212,7 @@ OS_CommandResult OS_RunCommand(Arena *arena, String cmd)
|
||||
sa.nLength = sizeof(sa);
|
||||
sa.bInheritHandle = 0;
|
||||
|
||||
/* Create pipe */
|
||||
// Create pipe
|
||||
HANDLE pipe_read = 0;
|
||||
HANDLE pipe_write = 0;
|
||||
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;
|
||||
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;
|
||||
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) {
|
||||
HANDLE inherit_list[] = { child_pipe_write };
|
||||
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 */
|
||||
/* TODO: Allow caller to set child process's thread affinity by job pool */
|
||||
// Create process
|
||||
// TODO: Allow caller to set child process's thread affinity by job pool
|
||||
HANDLE process = 0;
|
||||
HANDLE process_thread = 0;
|
||||
if (ok)
|
||||
@ -289,7 +289,7 @@ OS_CommandResult OS_RunCommand(Arena *arena, String cmd)
|
||||
{
|
||||
result.output = W32_StringFromError(arena, GetLastError());
|
||||
}
|
||||
/* Close write pipe handles */
|
||||
// Close write pipe handles
|
||||
{
|
||||
CloseHandle(child_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)
|
||||
{
|
||||
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 (process_thread) CloseHandle(process_thread);
|
||||
if (process) CloseHandle(process);
|
||||
|
||||
@ -1,18 +1,17 @@
|
||||
/* TODO: Cap max sounds playing. */
|
||||
// TODO: Cap max sounds playing.
|
||||
|
||||
/* Terminology:
|
||||
*
|
||||
* `Sample`: Once "PCM" data point representing the smallest unit of audio available for a single channel at a point in time.
|
||||
* 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 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.
|
||||
* Examples:
|
||||
* - 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 32 bit float samples output by mixer and consumed by playback API, one sample for each audio channel
|
||||
*/
|
||||
// Terminology:
|
||||
//
|
||||
// `Sample`: Once "PCM" data point representing the smallest unit of audio available for a single channel at a point in time.
|
||||
// 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 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.
|
||||
// Examples:
|
||||
// - 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 32 bit float samples output by mixer and consumed by playback API, one sample for each audio channel
|
||||
|
||||
MIX_SharedState M_shared_state = ZI;
|
||||
|
||||
@ -59,7 +58,7 @@ MIX_Track *MIX_AcquireTrackLocked(Lock *lock, SND_Sound *sound)
|
||||
MIX_Track *track = 0;
|
||||
if (g->track_first_free)
|
||||
{
|
||||
/* Take from free list */
|
||||
// Take from free list
|
||||
track = g->track_first_free;
|
||||
MIX_Track *next_free = track->next;
|
||||
g->track_first_free = next_free;
|
||||
@ -71,7 +70,7 @@ MIX_Track *MIX_AcquireTrackLocked(Lock *lock, SND_Sound *sound)
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Acquire new */
|
||||
// Acquire new
|
||||
track = PushStruct(g->track_arena, MIX_Track);
|
||||
track->gen = 1;
|
||||
}
|
||||
@ -80,7 +79,7 @@ MIX_Track *MIX_AcquireTrackLocked(Lock *lock, SND_Sound *sound)
|
||||
track->mix.source = sound;
|
||||
track->mix.track_handle = MIX_HandleFromTrack(track);
|
||||
|
||||
/* Append to playing list */
|
||||
// Append to playing list
|
||||
MIX_Track *prev = g->track_last_playing;
|
||||
if (prev)
|
||||
{
|
||||
@ -102,7 +101,7 @@ void MIX_ReleaseTrackLocked(Lock *lock, MIX_Track *track)
|
||||
MIX_SharedState *g = &M_shared_state;
|
||||
AssertLockedE(lock, &g->mutex);
|
||||
|
||||
/* Remove from playing list */
|
||||
// Remove from playing list
|
||||
MIX_Track *prev = track->prev;
|
||||
MIX_Track *next = track->next;
|
||||
if (prev)
|
||||
@ -111,7 +110,7 @@ void MIX_ReleaseTrackLocked(Lock *lock, MIX_Track *track)
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Track was first in list */
|
||||
// Track was first in list
|
||||
g->track_first_playing = next;
|
||||
}
|
||||
if (next)
|
||||
@ -120,13 +119,13 @@ void MIX_ReleaseTrackLocked(Lock *lock, MIX_Track *track)
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Track was last in list */
|
||||
// Track was last in list
|
||||
g->track_last_playing = prev;
|
||||
}
|
||||
--g->track_playing_count;
|
||||
++track->gen;
|
||||
|
||||
/* Add to free list */
|
||||
// Add to free list
|
||||
track->prev = 0;
|
||||
track->next = 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;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
@ -158,7 +157,7 @@ MIX_Handle MIX_PlaySoundEx(SND_Sound *sound, MIX_TrackDesc desc)
|
||||
return MIX_HandleFromTrack(track);
|
||||
}
|
||||
|
||||
/* NOTE: This is quite inefficient. */
|
||||
// NOTE: This is quite inefficient.
|
||||
MIX_TrackDesc MIX_TrackDescFromHandle(MIX_Handle handle)
|
||||
{
|
||||
MIX_SharedState *g = &M_shared_state;
|
||||
@ -167,10 +166,10 @@ MIX_TrackDesc MIX_TrackDescFromHandle(MIX_Handle handle)
|
||||
MIX_Track *track = MIX_TrackFromHandle(handle);
|
||||
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);
|
||||
{
|
||||
/* Confirm handle is still valid now that we're locked */
|
||||
// Confirm handle is still valid now that we're locked
|
||||
track = MIX_TrackFromHandle(handle);
|
||||
if (track)
|
||||
{
|
||||
@ -183,17 +182,17 @@ MIX_TrackDesc MIX_TrackDescFromHandle(MIX_Handle handle)
|
||||
return result;
|
||||
}
|
||||
|
||||
/* NOTE: This is quite inefficient. */
|
||||
// NOTE: This is quite inefficient.
|
||||
void MIX_UpdateTrack(MIX_Handle handle, MIX_TrackDesc desc)
|
||||
{
|
||||
MIX_SharedState *g = &M_shared_state;
|
||||
MIX_Track *track = MIX_TrackFromHandle(handle);
|
||||
if (track)
|
||||
{
|
||||
/* TODO: Only lock mutex on track itself or something */
|
||||
// TODO: Only lock mutex on track itself or something
|
||||
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);
|
||||
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)
|
||||
{
|
||||
TempArena scratch = BeginScratch(arena);
|
||||
@ -254,11 +253,11 @@ MIX_PcmF32 MIX_MixAllTracks(Arena *arena, u64 frame_count)
|
||||
{
|
||||
Lock lock = LockE(&g->mutex);
|
||||
|
||||
/* Read listener info */
|
||||
// Read listener info
|
||||
listener_pos = g->listener_pos;
|
||||
listener_dir = g->listener_dir;
|
||||
|
||||
/* Update & read mixes */
|
||||
// Update & read mixes
|
||||
mixes = PushStructsNoZero(scratch.arena, MIX_MixData *, g->track_playing_count);
|
||||
for (MIX_Track *track = g->track_first_playing; track; track = track->next)
|
||||
{
|
||||
@ -278,7 +277,7 @@ MIX_PcmF32 MIX_MixAllTracks(Arena *arena, u64 frame_count)
|
||||
|
||||
if (mix->source->samples_count <= 0)
|
||||
{
|
||||
/* Skip empty sounds */
|
||||
// Skip empty sounds
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -293,14 +292,14 @@ MIX_PcmF32 MIX_MixAllTracks(Arena *arena, u64 frame_count)
|
||||
if (source_is_stereo)
|
||||
{
|
||||
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 &= ~1;
|
||||
}
|
||||
else
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
@ -329,30 +328,30 @@ MIX_PcmF32 MIX_MixAllTracks(Arena *arena, u64 frame_count)
|
||||
};
|
||||
|
||||
//- 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;
|
||||
|
||||
u64 out_frames_count = mix_pcm.count / 2;
|
||||
|
||||
/* TODO: Fast path for 1:1 copy when speed = 1.0? */
|
||||
/* TODO: Optimize */
|
||||
// TODO: Fast path for 1:1 copy when speed = 1.0?
|
||||
// TODO: Optimize
|
||||
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)
|
||||
{
|
||||
f32 in_frame_pos_exact = source_frame_pos_start + (((f32)out_frame_pos / (f32)out_frames_count) * (f32)source_frames_count);
|
||||
u32 in_frame_pos_prev = FloorF32ToI32(in_frame_pos_exact);
|
||||
u32 in_frame_pos_next = CeilF32ToI32(in_frame_pos_exact);
|
||||
|
||||
/* Sample source */
|
||||
// Sample source
|
||||
f32 sample1_prev = MIX_SampleSound(source, (in_frame_pos_prev * 2) + 0, desc.looping) * (1.f / 32768.f);
|
||||
f32 sample1_next = MIX_SampleSound(source, (in_frame_pos_next * 2) + 0, desc.looping) * (1.f / 32768.f);
|
||||
f32 sample2_prev = MIX_SampleSound(source, (in_frame_pos_prev * 2) + 1, desc.looping) * (1.f / 32768.f);
|
||||
f32 sample2_next = MIX_SampleSound(source, (in_frame_pos_next * 2) + 1, desc.looping) * (1.f / 32768.f);
|
||||
|
||||
/* Lerp */
|
||||
// Lerp
|
||||
f32 t = in_frame_pos_exact - (f32)in_frame_pos_prev;
|
||||
f32 sample1 = LerpF32(sample1_prev, sample1_next, t);
|
||||
f32 sample2 = LerpF32(sample2_prev, sample2_next, t);
|
||||
@ -363,18 +362,18 @@ MIX_PcmF32 MIX_MixAllTracks(Arena *arena, u64 frame_count)
|
||||
}
|
||||
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)
|
||||
{
|
||||
f32 in_frame_pos_exact = source_frame_pos_start + (((f32)out_frame_pos / (f32)out_frames_count) * (f32)source_frames_count);
|
||||
u32 in_frame_pos_prev = FloorF32ToI32(in_frame_pos_exact);
|
||||
u32 in_frame_pos_next = CeilF32ToI32(in_frame_pos_exact);
|
||||
|
||||
/* Sample source */
|
||||
// Sample source
|
||||
f32 sample_prev = MIX_SampleSound(source, in_frame_pos_prev, desc.looping) * (1.f / 32768.f);
|
||||
f32 sample_next = MIX_SampleSound(source, in_frame_pos_next, desc.looping) * (1.f / 32768.f);
|
||||
|
||||
/* Lerp */
|
||||
// Lerp
|
||||
f32 t = (f32)in_frame_pos_exact - in_frame_pos_prev;
|
||||
f32 sample = LerpF32(sample_prev, sample_next, t);
|
||||
|
||||
@ -387,14 +386,14 @@ MIX_PcmF32 MIX_MixAllTracks(Arena *arena, u64 frame_count)
|
||||
//- Spatialize
|
||||
if (desc.flags & MIX_TrackFlag_Spatialize)
|
||||
{
|
||||
/* Algorithm constants */
|
||||
// Algorithm constants
|
||||
const f32 rolloff_height = 1.2f;
|
||||
const f32 rolloff_scale = 6.0f;
|
||||
const f32 pan_scale = 0.75;
|
||||
|
||||
Vec2 pos = desc.pos;
|
||||
|
||||
/* If sound pos = listener pos, pretend sound is close in front of listener. */
|
||||
// If sound pos = listener pos, pretend sound is close in front of listener.
|
||||
if (MatchVec2(listener_pos, pos))
|
||||
{
|
||||
pos = AddVec2(listener_pos, MulVec2(listener_dir, 0.001f));
|
||||
@ -402,26 +401,25 @@ MIX_PcmF32 MIX_MixAllTracks(Arena *arena, u64 frame_count)
|
||||
Vec2 sound_rel = SubVec2(pos, listener_pos);
|
||||
Vec2 sound_rel_dir = NormVec2(sound_rel);
|
||||
|
||||
/* Compute volume */
|
||||
// Compute volume
|
||||
f32 volume_start = effect_data->spatial_volume;
|
||||
f32 volume_end;
|
||||
{
|
||||
/* https://www.desmos.com/calculator/c2h941hobz
|
||||
* h = `rolloff_height`
|
||||
* s = `rolloff_scale`
|
||||
*/
|
||||
// https://www.desmos.com/calculator/c2h941hobz
|
||||
// h = `rolloff_height`
|
||||
// s = `rolloff_scale`
|
||||
f32 dist = Vec2Len(sound_rel);
|
||||
f32 v = (dist / rolloff_scale) + 1.0f;
|
||||
volume_end = rolloff_height * (1.0f / (v * v));
|
||||
}
|
||||
effect_data->spatial_volume = volume_end;
|
||||
|
||||
/* Compute pan */
|
||||
// Compute pan
|
||||
f32 pan_start = effect_data->spatial_pan;
|
||||
f32 pan_end = WedgeVec2(listener_dir, sound_rel_dir) * pan_scale;
|
||||
effect_data->spatial_pan = pan_end;
|
||||
|
||||
/* Spatialize samples */
|
||||
// Spatialize samples
|
||||
for (u64 frame_pos = 0; frame_pos < frame_count; ++frame_pos)
|
||||
{
|
||||
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)
|
||||
{
|
||||
/* Release finished tracks */
|
||||
// Release finished tracks
|
||||
MIX_ReleaseTrackLocked(&lock, track);
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,11 +16,10 @@ Struct(MIX_Handle)
|
||||
Struct(MIX_TrackDesc)
|
||||
{
|
||||
MIX_TrackFlag flags;
|
||||
f32 volume; /* 0 -> 1.0+ */
|
||||
f32 speed; /* 0 -> 1.0+ */
|
||||
f32 volume; // 0 -> 1.0+
|
||||
f32 speed; // 0 -> 1.0+
|
||||
b32 looping;
|
||||
|
||||
/* MIX_TrackFlag_Spatialize */
|
||||
Vec2 pos;
|
||||
};
|
||||
#define M_TRACKDESC(...) ((MIX_TrackDesc) { \
|
||||
@ -35,7 +34,7 @@ Struct(MIX_TrackDesc)
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Mix types
|
||||
|
||||
/* Stereo mix of 32 bit float samples */
|
||||
// Stereo mix of 32 bit float samples
|
||||
Struct(MIX_PcmF32)
|
||||
{
|
||||
u64 count;
|
||||
@ -44,7 +43,7 @@ Struct(MIX_PcmF32)
|
||||
|
||||
Struct(MIX_EffectData)
|
||||
{
|
||||
/* Spatialization */
|
||||
// Spatialization
|
||||
f32 spatial_volume;
|
||||
f32 spatial_pan;
|
||||
};
|
||||
@ -63,11 +62,11 @@ Struct(MIX_MixData)
|
||||
Struct(MIX_Track){
|
||||
u64 gen;
|
||||
|
||||
/* Controlled via interface */
|
||||
// Controlled via interface
|
||||
SND_Sound *sound;
|
||||
MIX_TrackDesc desc;
|
||||
|
||||
/* Internal */
|
||||
// Internal
|
||||
MIX_MixData mix;
|
||||
|
||||
MIX_Track *next;
|
||||
@ -81,11 +80,11 @@ Struct(MIX_SharedState)
|
||||
{
|
||||
Mutex mutex;
|
||||
|
||||
/* Listener */
|
||||
// Listener
|
||||
Vec2 listener_pos;
|
||||
Vec2 listener_dir;
|
||||
|
||||
/* Track list */
|
||||
// Track list
|
||||
Arena *track_arena;
|
||||
MIX_Track *track_first_playing;
|
||||
MIX_Track *track_last_playing;
|
||||
|
||||
@ -19,24 +19,26 @@ MP3_Result MP3_Decode(Arena *arena, String encoded, u32 sample_rate, MP3_DecodeF
|
||||
channel_mask = SPEAKER_FRONT_CENTER;
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- Startup
|
||||
|
||||
MFStartup(MF_VERSION, MFSTARTUP_LITE);
|
||||
|
||||
/* Create IStream from encoded string */
|
||||
// Create IStream from encoded string
|
||||
IStream *i_stream = SHCreateMemStream(encoded.text, encoded.len);
|
||||
|
||||
/* Create IMFByteStream from IStream */
|
||||
// Create IMFByteStream from IStream
|
||||
IMFByteStream *byte_stream = 0;
|
||||
MFCreateMFByteStreamOnStream(i_stream, &byte_stream);
|
||||
|
||||
/* Create reader from IMFByteStream */
|
||||
// Create reader from IMFByteStream
|
||||
IMFSourceReader *reader;
|
||||
MFCreateSourceReaderFromByteStream(byte_stream, 0, &reader);
|
||||
|
||||
//////////////////////////////
|
||||
//- 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_FIRST_AUDIO_STREAM, 1);
|
||||
|
||||
@ -55,13 +57,14 @@ MP3_Result MP3_Decode(Arena *arena, String encoded, u32 sample_rate, MP3_DecodeF
|
||||
.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;
|
||||
MFCreateMediaType(&type);
|
||||
MFInitMediaTypeFromWaveFormatEx(type, &format.Format, sizeof(format));
|
||||
IMFSourceReader_SetCurrentMediaType(reader, (DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, type);
|
||||
IMFMediaType_Release(type);
|
||||
|
||||
//////////////////////////////
|
||||
//- Read
|
||||
|
||||
result.samples = ArenaNext(arena, i16);
|
||||
@ -76,7 +79,7 @@ MP3_Result MP3_Decode(Arena *arena, String encoded, u32 sample_rate, MP3_DecodeF
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check if done */
|
||||
// Check if done
|
||||
if (sample_flags & MF_SOURCE_READERF_ENDOFSTREAM)
|
||||
{
|
||||
result.ok = 1;
|
||||
@ -84,7 +87,7 @@ MP3_Result MP3_Decode(Arena *arena, String encoded, u32 sample_rate, MP3_DecodeF
|
||||
}
|
||||
Assert(sample_flags == 0);
|
||||
|
||||
/* Read samples */
|
||||
// Read samples
|
||||
IMFMediaBuffer *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;
|
||||
|
||||
//////////////////////////////
|
||||
//- Cleanup
|
||||
|
||||
IMFSourceReader_Release(reader);
|
||||
IMFByteStream_Close(byte_stream);
|
||||
/* FIXME: Enable this */
|
||||
// FIXME: Enable this
|
||||
//IStream_Release(i_stream);
|
||||
MFShutdown();
|
||||
|
||||
|
||||
163
src/net/net.c
163
src/net/net.c
@ -1,16 +1,15 @@
|
||||
/* TODO:
|
||||
*
|
||||
* Rate limiting.
|
||||
*
|
||||
* Resequence buffer to order incoming sequenced packets.
|
||||
*
|
||||
* Rolling window for message reassembly.
|
||||
* This would remove the need for random access message buffers.
|
||||
*
|
||||
* Connection timeouts.
|
||||
*
|
||||
* Challenges to verify receiving address.
|
||||
*/
|
||||
// TODO:
|
||||
//
|
||||
// Rate limiting.
|
||||
//
|
||||
// Resequence buffer to order incoming sequenced packets.
|
||||
//
|
||||
// Rolling window for message reassembly.
|
||||
// This would remove the need for random access message buffers.
|
||||
//
|
||||
// Connection timeouts.
|
||||
//
|
||||
// Challenges to verify receiving address.
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Host
|
||||
@ -76,7 +75,7 @@ N_Channel *N_ChannelFromAddress(N_Host *host, P_Address address)
|
||||
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)
|
||||
{
|
||||
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;
|
||||
|
||||
/* Release from lookup table */
|
||||
// Release from lookup table
|
||||
{
|
||||
N_ChannelLookupBin *bin = &host->channel_lookup_bins[channel->address_hash % host->num_channel_lookup_bins];
|
||||
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)
|
||||
{
|
||||
@ -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)
|
||||
{
|
||||
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;
|
||||
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);
|
||||
}
|
||||
u64 chunk_data_size = chunk_count * N_MaxPacketChunkLen;
|
||||
|
||||
/* Acquire msg data using buddy allocator since the assembler has
|
||||
* arbitrary lifetime and data needs to stay contiguous for random
|
||||
* access as packets are received */
|
||||
// Acquire msg data using buddy allocator since the assembler has
|
||||
// arbitrary lifetime and data needs to stay contiguous for random
|
||||
// access as packets are received
|
||||
ma->buddy_block = AcquireBuddyBlock(host->buddy, chunk_bitmap_size + chunk_data_size);
|
||||
ma->chunk_bitmap = ma->buddy_block->memory;
|
||||
ZeroBytes(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;
|
||||
|
||||
/* Add to channel list */
|
||||
// Add to channel list
|
||||
ma->touched_ns = now_ns;
|
||||
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;
|
||||
|
||||
/* Add to lookup table */
|
||||
// Add to lookup table
|
||||
u64 hash = N_HashFromMsg(channel->id, msg_id);
|
||||
ma->hash = hash;
|
||||
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;
|
||||
ReleaseBuddyBlock(ma->buddy_block);
|
||||
|
||||
/* Release from channel list */
|
||||
// Release from channel list
|
||||
{
|
||||
N_MsgAssembler *prev = ma->less_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_MsgAssembler *prev = ma->prev_hash;
|
||||
@ -377,7 +376,7 @@ void N_TouchMessageAssembler(N_MsgAssembler *ma, i64 now_ns)
|
||||
N_Channel *channel = ma->channel;
|
||||
if (ma != channel->most_recent_msg_assembler)
|
||||
{
|
||||
/* Remove from channel list */
|
||||
// Remove from channel list
|
||||
{
|
||||
N_MsgAssembler *prev = ma->less_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)
|
||||
{
|
||||
@ -536,15 +535,18 @@ i64 N_GetChannelLastRttNs(N_Host *host, N_ChannelId channel_id)
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ 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)
|
||||
{
|
||||
TempArena scratch = BeginScratch(arena);
|
||||
|
||||
N_EventList events = ZI;
|
||||
i64 now_ns = TimeNs();
|
||||
|
||||
//////////////////////////////
|
||||
//- Read socket
|
||||
|
||||
{
|
||||
//- Read socket
|
||||
N_RcvPacket *first_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)
|
||||
{
|
||||
@ -580,10 +584,10 @@ N_EventList N_BeginUpdate(Arena *arena, N_Host *host)
|
||||
P_Address address = packet->address;
|
||||
BB_Buff bb = BB_BuffFromString(packet->data);
|
||||
BB_Reader br = BB_ReaderFromBuff(&bb);
|
||||
u32 magic = BB_ReadUBits(&br, 32); /* TODO: implicitly encode magic into crc32 */
|
||||
u32 magic = BB_ReadUBits(&br, 32); // TODO: implicitly encode magic into crc32
|
||||
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_PacketKind packet_kind = BB_ReadIBits(&br, 8);
|
||||
u8 packet_flags = BB_ReadUBits(&br, 8);
|
||||
@ -622,24 +626,29 @@ N_EventList N_BeginUpdate(Arena *arena, N_Host *host)
|
||||
{
|
||||
default: break;
|
||||
|
||||
//////////////////////////////
|
||||
//- Read packet kind: 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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
N_Cmd *cmd = N_PushCmd(host);
|
||||
cmd->kind = N_CmdKind_ConnectSuccess;
|
||||
cmd->channel_id = channel->id;
|
||||
} break;
|
||||
|
||||
//////////////////////////////
|
||||
//- Read packet kind: 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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
} break;
|
||||
|
||||
//////////////////////////////
|
||||
//- Read packet kind: Disconnect
|
||||
|
||||
case N_PacketKind_Disconnect:
|
||||
{
|
||||
/* A foreign host disconnected from us */
|
||||
// A foreign host disconnected from us
|
||||
if (channel->valid)
|
||||
{
|
||||
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;
|
||||
|
||||
//////////////////////////////
|
||||
//- Read packet kind: Heartbeat
|
||||
|
||||
case N_PacketKind_Heartbeat:
|
||||
{
|
||||
if (channel->valid)
|
||||
@ -685,12 +700,15 @@ N_EventList N_BeginUpdate(Arena *arena, N_Host *host)
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
//////////////////////////////
|
||||
//- Read packet kind: MsgChunk
|
||||
|
||||
case N_PacketKind_MsgChunk:
|
||||
{
|
||||
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 chunk_id = 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);
|
||||
if (ma->num_chunks_received == chunk_count)
|
||||
{
|
||||
/* All chunks filled, message has finished assembling */
|
||||
/* TODO: Message ordering */
|
||||
// All chunks filled, message has finished assembling
|
||||
// TODO: Message ordering
|
||||
N_Event *event = N_PushEvent(arena, &events);
|
||||
String data = ZI;
|
||||
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;
|
||||
if (is_reliable)
|
||||
{
|
||||
/* Release assembler if reliable */
|
||||
// Release assembler if reliable
|
||||
N_ReleaseMessageAssembler(ma);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Overflow reading chunk */
|
||||
// Overflow reading chunk
|
||||
Assert(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Chunk id/count mismatch */
|
||||
// Chunk id/count mismatch
|
||||
Assert(0);
|
||||
}
|
||||
}
|
||||
@ -760,22 +778,24 @@ N_EventList N_BeginUpdate(Arena *arena, N_Host *host)
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- Update channels
|
||||
|
||||
{
|
||||
for (u64 i = 0; i < host->num_channels_reserved; ++i)
|
||||
{
|
||||
N_Channel *channel = &host->channels[i];
|
||||
if (channel->valid)
|
||||
{
|
||||
/* Send / resend handshake if not connected */
|
||||
// Send / resend handshake if not connected
|
||||
if (!channel->connected)
|
||||
{
|
||||
N_Cmd *cmd = N_PushCmd(host);
|
||||
cmd->kind = N_CmdKind_TryConnect;
|
||||
cmd->channel_id = channel->id;
|
||||
}
|
||||
/* Send heartbeat */
|
||||
/* TODO: Send this less frequently (once per second or half of timeout or something) */
|
||||
// Send heartbeat
|
||||
// TODO: Send this less frequently (once per second or half of timeout or something)
|
||||
{
|
||||
N_Cmd *cmd = N_PushCmd(host);
|
||||
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->channel_id = channel->id;
|
||||
}
|
||||
/* Release acked reliable packets */
|
||||
// Release acked reliable packets
|
||||
{
|
||||
u64 acked_seq = channel->their_acked_seq;
|
||||
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;
|
||||
}
|
||||
}
|
||||
/* 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);
|
||||
N_MsgAssembler *ma = channel->least_recent_msg_assembler;
|
||||
while (ma)
|
||||
@ -842,13 +862,15 @@ N_EventList N_BeginUpdate(Arena *arena, N_Host *host)
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Update end
|
||||
|
||||
/* Process host cmds & send outgoing packets */
|
||||
// Process host cmds & send outgoing packets
|
||||
void N_EndUpdate(N_Host *host)
|
||||
{
|
||||
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)
|
||||
{
|
||||
@ -862,53 +884,64 @@ void N_EndUpdate(N_Host *host)
|
||||
{
|
||||
default: break;
|
||||
|
||||
//////////////////////////////
|
||||
//- Process command: TryConnect
|
||||
|
||||
case N_CmdKind_TryConnect:
|
||||
{
|
||||
u8 packet_flags = 0;
|
||||
N_SndPacket *packet = N_PushSndPacket(channel, 0);
|
||||
BB_Buff bb = BB_BuffFromString(StringFromFixedArray(packet->data));
|
||||
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_WriteUBits(&bw, packet_flags, 8);
|
||||
BB_WriteUV(&bw, channel->our_acked_seq);
|
||||
packet->data_len = BB_GetNumBytesWritten(&bw);
|
||||
} break;
|
||||
|
||||
//////////////////////////////
|
||||
//- Process command: ConnectSuccess
|
||||
|
||||
case N_CmdKind_ConnectSuccess:
|
||||
{
|
||||
u8 packet_flags = 0;
|
||||
N_SndPacket *packet = N_PushSndPacket(channel, 0);
|
||||
BB_Buff bb = BB_BuffFromString(StringFromFixedArray(packet->data));
|
||||
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_WriteUBits(&bw, packet_flags, 8);
|
||||
BB_WriteUV(&bw, channel->our_acked_seq);
|
||||
packet->data_len = BB_GetNumBytesWritten(&bw);
|
||||
} break;
|
||||
|
||||
//////////////////////////////
|
||||
//- Process command: Disconnect
|
||||
|
||||
case N_CmdKind_Disconnect:
|
||||
{
|
||||
u8 packet_flags = 0;
|
||||
N_SndPacket *packet = N_PushSndPacket(channel, 0);
|
||||
BB_Buff bb = BB_BuffFromString(StringFromFixedArray(packet->data));
|
||||
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_WriteUBits(&bw, packet_flags, 8);
|
||||
BB_WriteUV(&bw, channel->our_acked_seq);
|
||||
packet->data_len = BB_GetNumBytesWritten(&bw);
|
||||
} break;
|
||||
|
||||
//////////////////////////////
|
||||
//- Process command: Heartbeat
|
||||
|
||||
case N_CmdKind_Heartbeat:
|
||||
{
|
||||
u8 packet_flags = 0;
|
||||
N_SndPacket *packet = N_PushSndPacket(channel, 0);
|
||||
BB_Buff bb = BB_BuffFromString(StringFromFixedArray(packet->data));
|
||||
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_WriteUBits(&bw, packet_flags, 8);
|
||||
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);
|
||||
packet->data_len = BB_GetNumBytesWritten(&bw);
|
||||
} break;
|
||||
|
||||
//////////////////////////////
|
||||
//- Process command: Write
|
||||
|
||||
case N_CmdKind_Write:
|
||||
{
|
||||
b32 is_reliable = cmd->write_reliable;
|
||||
@ -946,7 +982,7 @@ void N_EndUpdate(N_Host *host)
|
||||
N_SndPacket *packet = N_PushSndPacket(channel, is_reliable);
|
||||
BB_Buff bb = BB_BuffFromString(StringFromFixedArray(packet->data));
|
||||
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_WriteUBits(&bw, packet_flags, 8);
|
||||
BB_WriteUV(&bw, channel->our_acked_seq);
|
||||
@ -971,8 +1007,10 @@ void N_EndUpdate(N_Host *host)
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- Send packets
|
||||
/* TODO: Aggregate small packets */
|
||||
|
||||
// TODO: Aggregate small packets
|
||||
{
|
||||
for (u64 i = 0; i < host->num_channels_reserved; ++i)
|
||||
{
|
||||
@ -982,19 +1020,19 @@ void N_EndUpdate(N_Host *host)
|
||||
if (channel->valid)
|
||||
{
|
||||
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)
|
||||
{
|
||||
P_WriteSock(sock, address, STRING(packet->data_len, packet->data));
|
||||
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)
|
||||
{
|
||||
P_WriteSock(sock, address, STRING(packet->data_len, packet->data));
|
||||
total_sent += packet->data_len;
|
||||
}
|
||||
/* Release unreliable packets */
|
||||
// Release unreliable packets
|
||||
if (channel->first_unreliable_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->last_cmd = 0;
|
||||
ResetArena(host->cmd_arena);
|
||||
|
||||
@ -77,7 +77,7 @@ Struct(N_ChannelLookupBin)
|
||||
|
||||
#define N_PacketMagic 0xd9e3b8b6
|
||||
#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)
|
||||
{
|
||||
@ -136,7 +136,7 @@ Struct(N_Channel)
|
||||
N_Channel *next_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 *last_reliable_packet;
|
||||
N_SndPacket *first_unreliable_packet;
|
||||
@ -144,7 +144,7 @@ Struct(N_Channel)
|
||||
u64 num_reliable_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 *most_recent_msg_assembler;
|
||||
|
||||
@ -181,14 +181,14 @@ Struct(N_MsgAssembler)
|
||||
N_Channel *channel;
|
||||
b32 is_reliable;
|
||||
|
||||
/* Free list */
|
||||
// Free list
|
||||
N_MsgAssembler *next_free;
|
||||
|
||||
/* Bucket list */
|
||||
// Bucket list
|
||||
N_MsgAssembler *next_hash;
|
||||
N_MsgAssembler *prev_hash;
|
||||
|
||||
/* Channel list */
|
||||
// Channel list
|
||||
N_MsgAssembler *less_recent;
|
||||
N_MsgAssembler *more_recent;
|
||||
|
||||
@ -224,7 +224,7 @@ Struct(N_Host)
|
||||
|
||||
P_Sock *sock;
|
||||
|
||||
BuddyCtx *buddy; /* For storing msg assembler data */
|
||||
BuddyCtx *buddy; // For storing msg assembler data
|
||||
|
||||
Arena *cmd_arena;
|
||||
N_Cmd *first_cmd;
|
||||
@ -236,16 +236,16 @@ Struct(N_Host)
|
||||
N_Channel *first_free_channel;
|
||||
u64 num_channels_reserved;
|
||||
|
||||
N_SndPacket *first_free_packet; /* Acquired in `arena` */
|
||||
N_MsgAssembler *first_free_msg_assembler; /* Acquired in `arena` */
|
||||
N_SndPacket *first_free_packet; // Acquired in `arena`
|
||||
N_MsgAssembler *first_free_msg_assembler; // Acquired in `arena`
|
||||
|
||||
N_ChannelLookupBin *channel_lookup_bins; /* Acquired in `arena` */
|
||||
N_ChannelLookupBin *channel_lookup_bins; // Acquired in `arena`
|
||||
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;
|
||||
|
||||
/* Double buffer for incoming data */
|
||||
// Double buffer for incoming data
|
||||
Mutex rcv_buffer_write_mutex;
|
||||
N_RcvBuffer *rcv_buffer_read;
|
||||
N_RcvBuffer *rcv_buffer_write;
|
||||
|
||||
@ -40,7 +40,7 @@ Struct(P_Address)
|
||||
{
|
||||
b32 valid;
|
||||
P_AddressFamily family;
|
||||
/* NOTE: ipnb & portnb are stored in network byte order */
|
||||
// NOTE: ipnb & portnb are stored in network byte order
|
||||
u8 ipnb[16];
|
||||
u16 portnb;
|
||||
};
|
||||
@ -50,7 +50,7 @@ Struct(P_Address)
|
||||
|
||||
Struct(P_SockReadResult)
|
||||
{
|
||||
b32 valid; /* Since data.len = 0 can be valid */
|
||||
b32 valid; // Since data.len = 0 can be valid
|
||||
P_Address address;
|
||||
String data;
|
||||
};
|
||||
@ -74,7 +74,7 @@ void P_Bootstrap(void);
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ @hookdecl File system
|
||||
|
||||
/* NOTE: File paths use forward slash '/' as delimiter */
|
||||
// NOTE: File paths use forward slash '/' as delimiter
|
||||
|
||||
//- File system helpers
|
||||
String P_GetWritePath(Arena *arena);
|
||||
@ -84,7 +84,7 @@ void P_MkDir(String path);
|
||||
|
||||
//- File creation
|
||||
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_OpenFileAppend(String path);
|
||||
void P_CloseFile(P_File file);
|
||||
|
||||
@ -10,11 +10,11 @@ void P_Bootstrap(void)
|
||||
//- Init watches pool
|
||||
g->watches_arena = AcquireArena(Gibi(64));
|
||||
|
||||
//- Init winsock
|
||||
// Init winsock
|
||||
WSAStartup(MAKEWORD(2, 2), &g->wsa_data);
|
||||
g->socks_arena = AcquireArena(Gibi(64));
|
||||
|
||||
//- Init timer
|
||||
// Init timer
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
if (addr.family == AF_INET)
|
||||
@ -162,7 +162,7 @@ void P_W32_SyncTimerForever(WaveLaneCtx *lane)
|
||||
P_W32_SharedState *g = &P_W32_shared_state;
|
||||
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);
|
||||
if (!timer)
|
||||
{
|
||||
@ -177,11 +177,11 @@ void P_W32_SyncTimerForever(WaveLaneCtx *lane)
|
||||
}
|
||||
|
||||
i64 last_cycle_ns = 0;
|
||||
/* FIXME: shutdown */
|
||||
// FIXME: shutdown
|
||||
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;
|
||||
due.QuadPart = -1;
|
||||
//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;
|
||||
last_cycle_ns = now_ns;
|
||||
|
||||
/* Compute mean period */
|
||||
// Compute mean period
|
||||
{
|
||||
periods[periods_index++] = period_ns;
|
||||
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));
|
||||
}
|
||||
|
||||
/* Update fence */
|
||||
// Update fence
|
||||
SetFence(&g->timer_fence, now_ns);
|
||||
}
|
||||
}
|
||||
@ -219,11 +219,10 @@ void P_W32_SyncTimerForever(WaveLaneCtx *lane)
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ @hookimpl File system
|
||||
|
||||
//- File system helpers
|
||||
String P_GetWritePath(Arena *arena)
|
||||
{
|
||||
u16 *p = 0;
|
||||
/* TODO: cache this? */
|
||||
// TODO: cache this?
|
||||
HRESULT result = SHGetKnownFolderPath(
|
||||
&FOLDERID_LocalAppData,
|
||||
0,
|
||||
@ -300,7 +299,6 @@ void P_MkDir(String path)
|
||||
EndScratch(scratch);
|
||||
}
|
||||
|
||||
//- File creation
|
||||
P_File P_OpenFileRead(String path)
|
||||
{
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
@ -405,7 +403,6 @@ void P_CloseFile(P_File file)
|
||||
}
|
||||
}
|
||||
|
||||
//- File data manipulation
|
||||
String P_ReadFile(Arena *arena, P_File file)
|
||||
{
|
||||
i64 size = 0;
|
||||
@ -418,15 +415,15 @@ String P_ReadFile(Arena *arena, P_File file)
|
||||
|
||||
if (size > 0)
|
||||
{
|
||||
/* ReadFile returns non-zero on success */
|
||||
/* TODO: error checking */
|
||||
// ReadFile returns non-zero on success
|
||||
// TODO: error checking
|
||||
PushAlign(arena, CachelineSize);
|
||||
s.text = PushStructsNoZero(arena, u8, size);
|
||||
ReadFile(
|
||||
(HANDLE)file.handle,
|
||||
s.text,
|
||||
(DWORD)s.len,
|
||||
0, /* lpNumberOfBytesRead */
|
||||
0,
|
||||
0
|
||||
);
|
||||
}
|
||||
@ -436,8 +433,8 @@ String P_ReadFile(Arena *arena, P_File file)
|
||||
|
||||
void P_WriteFile(P_File file, String data)
|
||||
{
|
||||
/* TODO: Check what the real data limit is and chunk sequentially based on
|
||||
* that (rather than failing) */
|
||||
// TODO: Check what the real data limit is and chunk sequentially based on
|
||||
// that (rather than failing)
|
||||
if (data.len >= 0x7FFF)
|
||||
{
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
@ -449,17 +446,16 @@ void P_WriteFile(P_File file, String data)
|
||||
EndScratch(scratch);
|
||||
}
|
||||
|
||||
/* WriteFile returns TRUE on success */
|
||||
// WriteFile returns TRUE on success
|
||||
WriteFile(
|
||||
(HANDLE)file.handle,
|
||||
data.text,
|
||||
(DWORD)data.len,
|
||||
0, /* lpNumberOfBytesWritten */
|
||||
0,
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
//- File info
|
||||
u64 P_GetFileSize(P_File file)
|
||||
{
|
||||
LARGE_INTEGER li_file_size;
|
||||
@ -469,19 +465,19 @@ u64 P_GetFileSize(P_File file)
|
||||
|
||||
P_FileTime P_GetFileTime(P_File file)
|
||||
{
|
||||
/* Get file times */
|
||||
// Get file times
|
||||
FILETIME ft_created;
|
||||
FILETIME ft_accessed;
|
||||
FILETIME ft_modified;
|
||||
b32 ok = !!GetFileTime((HANDLE)file.handle, &ft_created, &ft_accessed, &ft_modified);
|
||||
if (ok)
|
||||
{
|
||||
/* Convert file times to local file time */
|
||||
// Convert file times to local file time
|
||||
FileTimeToLocalFileTime(&ft_created, &ft_created);
|
||||
FileTimeToLocalFileTime(&ft_accessed, &ft_accessed);
|
||||
FileTimeToLocalFileTime(&ft_modified, &ft_modified);
|
||||
|
||||
/* Convert local file times to system times */
|
||||
// Convert local file times to system times
|
||||
SYSTEMTIME st_created;
|
||||
SYSTEMTIME st_accessed;
|
||||
SYSTEMTIME st_modified;
|
||||
@ -534,7 +530,7 @@ P_FileMap P_OpenFileMap(P_File file)
|
||||
);
|
||||
if (base_ptr == 0)
|
||||
{
|
||||
/* Failed to create view */
|
||||
// Failed to create view
|
||||
CloseHandle(map_handle);
|
||||
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)
|
||||
{
|
||||
/* TODO: Enable ipv6 */
|
||||
// TODO: Enable ipv6
|
||||
// struct sockaddr_in6 *sockaddr = (struct sockaddr_in6 *)ai_result->ai_addr;
|
||||
// result.valid = 1;
|
||||
// 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)
|
||||
{
|
||||
/* Parse string into ip & port */
|
||||
// Parse string into ip & port
|
||||
u8 ip_buff[1024];
|
||||
u8 port_buff[countof(ip_buff)];
|
||||
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);
|
||||
if (colon_count > 1 && str.text[0] == '[')
|
||||
{
|
||||
/* Parse ipv6 with port */
|
||||
// Parse ipv6 with port
|
||||
b32 parse_addr = 1;
|
||||
for (u64 i = 1; i < parse_len; ++i)
|
||||
{
|
||||
@ -664,7 +660,7 @@ P_Address P_AddressFromString(String str)
|
||||
}
|
||||
else if (colon_count == 1)
|
||||
{
|
||||
/* Parse address with port */
|
||||
// Parse address with port
|
||||
b32 parse_addr = 1;
|
||||
for (u64 i = 0; i < parse_len; ++i)
|
||||
{
|
||||
@ -690,7 +686,7 @@ P_Address P_AddressFromString(String str)
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Copy address without port */
|
||||
// Copy address without port
|
||||
ip_len = MinU64(str.len, countof(ip_buff) - 1);
|
||||
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)
|
||||
{
|
||||
/* TODO */
|
||||
// TODO
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -845,7 +841,7 @@ P_SockReadResult P_ReadSock(Arena *arena, P_Sock *sock)
|
||||
result.data.len = size;
|
||||
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);
|
||||
}
|
||||
else
|
||||
@ -987,7 +983,7 @@ void P_SleepPrecise(i64 sleep_time_ns)
|
||||
i64 now_ns = TimeNs();
|
||||
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();
|
||||
i64 timer_period_ns = P_GetCurrentTimerPeriodNs();
|
||||
@ -996,7 +992,7 @@ void P_SleepPrecise(i64 sleep_time_ns)
|
||||
YieldOnFence(timer_fence, target_timer_sleep_ns);
|
||||
}
|
||||
|
||||
/* Spin */
|
||||
// Spin
|
||||
now_ns = TimeNs();
|
||||
while (now_ns < target_ns)
|
||||
{
|
||||
|
||||
@ -1,8 +1,7 @@
|
||||
/* WASAPI backend for audio playback
|
||||
*
|
||||
* Based on mmozeiko's WASAPI examples
|
||||
* https://gist.github.com/mmozeiko/5a5b168e61aff4c1eaec0381da62808f#file-win32_wasapi-h
|
||||
*/
|
||||
// WASAPI backend for audio playback
|
||||
//
|
||||
// Based on mmozeiko's WASAPI examples
|
||||
// https://gist.github.com/mmozeiko/5a5b168e61aff4c1eaec0381da62808f#file-win32_wasapi-h
|
||||
|
||||
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_InitializeWasapi();
|
||||
/* Start playback job */
|
||||
// Start playback job
|
||||
JobPoolId playback_pool = InitJobPool(1, Lit("Playback"), JobPoolPriority_Audio);
|
||||
g->shutdown_jobs_count += RunJob(PB_WSP_Playback, .pool = playback_pool, .fence = &g->shutdown_jobs_fence);
|
||||
OnExit(&PB_WSP_Shutdown);
|
||||
@ -36,16 +35,16 @@ void PB_WSP_InitializeWasapi(void)
|
||||
u64 channel_count = 2;
|
||||
u32 channel_mask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
|
||||
|
||||
/* Create enumerator to get audio device */
|
||||
// Create enumerator to get audio device
|
||||
IMMDeviceEnumerator *enumerator;
|
||||
CoCreateInstance(&CLSID_MMDeviceEnumerator, 0, CLSCTX_ALL, &IID_IMMDeviceEnumerator, (LPVOID *)&enumerator);
|
||||
|
||||
/* Get default playback device */
|
||||
// Get default playback device
|
||||
IMMDevice *device;
|
||||
IMMDeviceEnumerator_GetDefaultAudioEndpoint(enumerator, eRender, eConsole, &device);
|
||||
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_Release(device);
|
||||
|
||||
@ -70,10 +69,9 @@ void PB_WSP_InitializeWasapi(void)
|
||||
IAudioClient3 *client3;
|
||||
if (SUCCEEDED(IAudioClient_QueryInterface(g->client, &IID_IAudioClient3, (LPVOID *)&client3)))
|
||||
{
|
||||
/* From Martins: Minimum buffer size will typically be 480 samples (10msec @ 48khz)
|
||||
* but it can be 128 samples (2.66 msec @ 48khz) if driver is properly installed
|
||||
* see bullet-point instructions here: https://learn.microsoft.com/en-us/windows-hardware/drivers/audio/low-latency-audio#measurement-tools
|
||||
*/
|
||||
// From Martins: Minimum buffer size will typically be 480 samples (10msec @ 48khz)
|
||||
// but it can be 128 samples (2.66 msec @ 48khz) if driver is properly installed
|
||||
// see bullet-point instructions here: https://learn.microsoft.com/en-us/windows-hardware/drivers/audio/low-latency-audio#measurement-tools
|
||||
UINT32 default_period_samples, fundamental_period_samples, min_period_samples, max_period_samples;
|
||||
IAudioClient3_GetSharedModeEnginePeriod(client3, wfx, &default_period_samples, &fundamental_period_samples, &min_period_samples, &max_period_samples);
|
||||
|
||||
@ -91,34 +89,33 @@ void PB_WSP_InitializeWasapi(void)
|
||||
|
||||
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;
|
||||
IAudioClient_GetDevicePeriod(g->client, &duration, 0);
|
||||
|
||||
/* Initialize audio playback
|
||||
*
|
||||
* NOTE:
|
||||
* Passing AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM will tell WASAPI to
|
||||
* always convert to native mixing format. This may introduce latency
|
||||
* but allows for any input format.
|
||||
*/
|
||||
// Initialize audio playback
|
||||
//
|
||||
// NOTE:
|
||||
// Passing AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM will tell WASAPI to
|
||||
// always convert to native mixing format. This may introduce latency
|
||||
// but allows for any input format.
|
||||
const DWORD flags = AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY;
|
||||
IAudioClient_Initialize(g->client, AUDCLNT_SHAREMODE_SHARED, flags, duration, 0, wfx, 0);
|
||||
}
|
||||
|
||||
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);
|
||||
IAudioClient_SetEventHandle(g->client, g->event);
|
||||
|
||||
/* Get playback client */
|
||||
// Get playback client
|
||||
IAudioClient_GetService(g->client, &IID_IAudioRenderClient, (LPVOID *)&g->playback);
|
||||
|
||||
/* Start the playback */
|
||||
// Start the playback
|
||||
IAudioClient_Start(g->client);
|
||||
|
||||
/* Get audio buffer size in samples */
|
||||
// Get audio buffer size in samples
|
||||
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_Buff wspbuf = ZI;
|
||||
|
||||
/* Get padding frames */
|
||||
// Get padding frames
|
||||
u32 padding_frames;
|
||||
IAudioClient_GetCurrentPadding(g->client, &padding_frames);
|
||||
|
||||
/* Get output buffer from WASAPI */
|
||||
// Get output buffer from WASAPI
|
||||
wspbuf.frames_count = 0;
|
||||
if (padding_frames <= g->buffer_frames)
|
||||
{
|
||||
@ -154,18 +151,18 @@ void PB_WSP_EndUpdate(PB_WSP_Buff *wspbuf, MIX_PcmF32 src)
|
||||
u32 flags = 0;
|
||||
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 write_size = frames_in_source * 2 * bytes_per_sample;
|
||||
CopyBytes(wspbuf->frames, src.samples, write_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Submit silence if not enough samples */
|
||||
// Submit silence if not enough samples
|
||||
flags |= AUDCLNT_BUFFERFLAGS_SILENT;
|
||||
|
||||
/* This shouldn't occur, mixer should be generating samples equivilent
|
||||
* to value returned from `PB_WSP_BeginUpdate`. */
|
||||
// This shouldn't occur, mixer should be generating samples equivilent
|
||||
// to value returned from `PB_WSP_BeginUpdate`.
|
||||
Assert(0);
|
||||
}
|
||||
|
||||
@ -174,7 +171,7 @@ void PB_WSP_EndUpdate(PB_WSP_Buff *wspbuf, MIX_PcmF32 src)
|
||||
flags |= AUDCLNT_BUFFERFLAGS_SILENT;
|
||||
}
|
||||
|
||||
/* Submit output buffer to WASAPI */
|
||||
// Submit output buffer to WASAPI
|
||||
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;
|
||||
|
||||
/* FIXME: If playback fails at any point and mixer stops advancing, we
|
||||
* need to halt mixer to prevent memory leak when sounds are played. */
|
||||
/* TODO: Signal counter that running job wiats on, rather than scheduling job manually */
|
||||
//
|
||||
// FIXME: If playback fails at any point and mixer stops advancing, we
|
||||
// need to halt mixer to prevent memory leak when sounds are played.
|
||||
//
|
||||
// TODO: Signal counter that running job wiats on, rather than scheduling job manually
|
||||
//
|
||||
while (!Atomic32Fetch(&g->shutdown))
|
||||
{
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
|
||||
@ -11,7 +11,7 @@ Readonly S_ReadonlyCtx S_ro = {
|
||||
|
||||
void S_Bootstrap(void)
|
||||
{
|
||||
/* Initialize shared state */
|
||||
// Initialize shared state
|
||||
for (u64 i = 0; i < countof(S.input_states); ++i)
|
||||
{
|
||||
S_InputState *input = &S.input_states[i];
|
||||
@ -23,7 +23,7 @@ void S_Bootstrap(void)
|
||||
output->arena = AcquireArena(Gibi(64));
|
||||
}
|
||||
|
||||
/* Dispatch sim wave */
|
||||
// Dispatch sim wave
|
||||
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)
|
||||
{
|
||||
/* 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;
|
||||
TrueRand(StringFromStruct(&result));
|
||||
return result;
|
||||
@ -67,7 +67,7 @@ S_Key S_RandKey(void)
|
||||
|
||||
String S_NameFromTileKind(S_TileKind kind)
|
||||
{
|
||||
/* Tile names array */
|
||||
// Tile names array
|
||||
#define X(name, ...) [S_TileKind_##name] = CompLit(#name),
|
||||
PERSIST Readonly String tile_names[] = {
|
||||
S_TilesXMacro(X)
|
||||
@ -242,7 +242,7 @@ S_World *S_WorldFromSnapshot(Arena *arena, S_Snapshot *snapshot)
|
||||
{
|
||||
S_World *world = PushStruct(arena, S_World);
|
||||
|
||||
/* Copy ents */
|
||||
// Copy ents
|
||||
world->ents = PushStructsNoZero(arena, S_Ent, snapshot->ents_count);
|
||||
CopyStructs(world->ents, snapshot->ents, snapshot->ents_count);
|
||||
world->ents_count = snapshot->ents_count;
|
||||
@ -334,7 +334,7 @@ void S_TickForever(WaveLaneCtx *lane)
|
||||
{
|
||||
S_Cmd *cmd = &cmd_node->cmd;
|
||||
|
||||
/* Spawn entity */
|
||||
// Spawn entity
|
||||
if (cmd->kind == S_CmdKind_Spawn)
|
||||
{
|
||||
S_Ent *src = &cmd->ent;
|
||||
@ -364,7 +364,7 @@ void S_TickForever(WaveLaneCtx *lane)
|
||||
}
|
||||
}
|
||||
|
||||
/* Place tiles */
|
||||
// Place tiles
|
||||
if (cmd->kind == S_CmdKind_Tile)
|
||||
{
|
||||
tile_placements_count += 1;
|
||||
@ -413,7 +413,7 @@ void S_TickForever(WaveLaneCtx *lane)
|
||||
//////////////////////////////
|
||||
//- Publish sim state
|
||||
|
||||
/* TODO: Only copy active entities */
|
||||
// TODO: Only copy active entities
|
||||
LockTicketMutex(&S.output_back_tm);
|
||||
{
|
||||
S_OutputState *output = &S.output_states[S.output_back_idx];
|
||||
@ -431,7 +431,7 @@ void S_TickForever(WaveLaneCtx *lane)
|
||||
*dst = *src;
|
||||
}
|
||||
|
||||
/* Forward tile placements */
|
||||
// Forward tile placements
|
||||
snapshot->tile_placements_count = 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
|
||||
|
||||
/* Reset front input state */
|
||||
// Reset front input state
|
||||
{
|
||||
Arena *arena = input->arena;
|
||||
ResetArena(arena);
|
||||
|
||||
@ -33,7 +33,7 @@ Struct(S_Shape)
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Ent types
|
||||
|
||||
/* TODO: Move boolean fields into bitwise property flags */
|
||||
// TODO: Move boolean fields into bitwise property flags
|
||||
|
||||
Struct(S_Ent)
|
||||
{
|
||||
@ -151,13 +151,13 @@ Struct(S_Cmd)
|
||||
{
|
||||
S_CmdKind kind;
|
||||
|
||||
/* Tiles */
|
||||
// Tiles
|
||||
S_TilePlacement tile_placement;
|
||||
|
||||
/* Spawn */
|
||||
// Spawn
|
||||
S_Ent ent;
|
||||
|
||||
/* Control */
|
||||
// Control
|
||||
S_Key target;
|
||||
Vec2 move;
|
||||
Vec2 look;
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
X(Wall) \
|
||||
/* -------------------- */
|
||||
|
||||
/* Tiles enum */
|
||||
// Tiles enum
|
||||
#define X(name, ...) S_TileKind_##name,
|
||||
Enum(S_TileKind)
|
||||
{
|
||||
|
||||
@ -161,7 +161,7 @@ void V_EndCommandsWidget(V_CommandsWidget *widget)
|
||||
UI_SetNext(Flags, UI_BoxFlag_Floating);
|
||||
UI_PushCP(UI_BuildBoxEx(UI_KeyF("titlebar")));
|
||||
{
|
||||
/* Title bar */
|
||||
// Title bar
|
||||
UI_PushCP(UI_NilKey);
|
||||
{
|
||||
UI_Push(BackgroundColor, titlebar_color);
|
||||
@ -176,10 +176,10 @@ void V_EndCommandsWidget(V_CommandsWidget *widget)
|
||||
UI_Push(Width, UI_GROW(1, 0));
|
||||
UI_Push(BorderColor, 0);
|
||||
|
||||
/* Left title box */
|
||||
// Left title box
|
||||
UI_BuildRow();
|
||||
|
||||
/* Title box */
|
||||
// Title box
|
||||
UI_SetNext(FontSize, theme.window_title_font_size);
|
||||
UI_SetNext(ChildAlignment, UI_Alignment_Center);
|
||||
UI_SetNext(Width, UI_SHRINK(0, 1));
|
||||
@ -187,7 +187,7 @@ void V_EndCommandsWidget(V_CommandsWidget *widget)
|
||||
UI_SetNext(Flags, UI_BoxFlag_DrawText);
|
||||
UI_BuildBox();
|
||||
|
||||
/* Right title box */
|
||||
// Right title box
|
||||
UI_BuildRow();
|
||||
}
|
||||
UI_PopCP(UI_TopCP());
|
||||
@ -243,17 +243,17 @@ void V_EndCommandsWidget(V_CommandsWidget *widget)
|
||||
{
|
||||
UI_Push(Tag, btn_key.hash);
|
||||
|
||||
/* Begin spacer */
|
||||
// Begin spacer
|
||||
UI_BuildSpacer(UI_PIX(20, 1), Axis_X);
|
||||
|
||||
/* Command label */
|
||||
// Command label
|
||||
UI_SetNext(ChildAlignment, UI_Alignment_Center);
|
||||
UI_BuildLabel(item->desc.display_name);
|
||||
|
||||
/* Middle spacer */
|
||||
// Middle spacer
|
||||
UI_BuildSpacer(UI_GROW(1, 0), Axis_X);
|
||||
|
||||
/* Command hotkey buttons */
|
||||
// Command hotkey buttons
|
||||
for (u64 i = 0; i < countof(item->desc.hotkeys); ++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_PopCP(UI_TopCP());
|
||||
@ -352,7 +352,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
G_Layout_DirectQueue_ShaderRead_ShaderReadWrite_CopyRead_CopyWrite
|
||||
);
|
||||
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(
|
||||
cl,
|
||||
gpu_tiles, VEC3I32(0, 0, 0),
|
||||
@ -375,7 +375,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
//////////////////////////////
|
||||
//- State
|
||||
|
||||
/* Init shortcuts */
|
||||
// Init shortcuts
|
||||
u64 shortcut_bins_count = 1024;
|
||||
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);
|
||||
G_ResetArena(frame->cl, frame->gpu_arena);
|
||||
|
||||
/* Persist state */
|
||||
// Persist state
|
||||
CopyBytes(frame->held_buttons, last_frame->held_buttons, sizeof(frame->held_buttons));
|
||||
frame->commands_widget = last_frame->commands_widget;
|
||||
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_PushCmd(window_frame, .kind = WND_CmdKind_SetCursor, .cursor = WND_CursorKind_Default);
|
||||
|
||||
/* Restore window */
|
||||
// Restore window
|
||||
{
|
||||
if (frame->window_restore.len > 0)
|
||||
{
|
||||
@ -514,7 +514,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
frame->window_restore = PushString(frame->arena, window_frame.restore);
|
||||
}
|
||||
|
||||
/* Set widget theme */
|
||||
// Set widget theme
|
||||
V_WidgetTheme theme = V_GetWidgetTheme();
|
||||
V_PushWidgetThemeStyles(theme);
|
||||
|
||||
@ -526,7 +526,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
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);
|
||||
frame->ui_dims = RoundVec2ToI32(DimsFromRng2(vis_rep.screen_rect));
|
||||
}
|
||||
@ -634,11 +634,11 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
//////////////////////////////
|
||||
//- Initialize world <-> draw <-> ui transforms
|
||||
|
||||
/* World <-> ui */
|
||||
// World <-> ui
|
||||
frame->world_to_ui_xf = XformIdentity;
|
||||
frame->ui_to_world_xf = XformIdentity;
|
||||
{
|
||||
/* Determine target camera pos */
|
||||
// Determine target camera pos
|
||||
Vec2 target_camera_pos = Zi;
|
||||
f32 target_camera_zoom = 0;
|
||||
if (frame->is_editing)
|
||||
@ -652,7 +652,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
frame->edit_camera_zoom = 3;
|
||||
}
|
||||
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);
|
||||
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_zoom = ClampF32(target_camera_zoom, min_zoom, max_zoom);
|
||||
|
||||
/* Create world <-> ui xforms */
|
||||
// Create world <-> ui xforms
|
||||
{
|
||||
f32 lerp_ratio = 15.0 * frame->dt;
|
||||
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->ui_to_draw_xf = XformIdentity;
|
||||
{
|
||||
frame->ui_to_draw_xf = InvertXform(frame->draw_to_ui_xf);
|
||||
}
|
||||
|
||||
/* World <-> draw */
|
||||
// World <-> draw
|
||||
frame->world_to_draw_xf = XformIdentity;
|
||||
frame->draw_to_world_xf = XformIdentity;
|
||||
{
|
||||
@ -774,13 +774,13 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
//////////////////////////////
|
||||
//- Place tiles
|
||||
|
||||
/* TODO: Push vis cmd */
|
||||
// TODO: Push vis cmd
|
||||
|
||||
if (frame->is_editing && last_frame->is_selecting && !frame->is_selecting)
|
||||
{
|
||||
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;
|
||||
tile_range.p0 = S_TilePosFromWorldPos(last_frame->world_selection.p0);
|
||||
tile_range.p1 = S_TilePosFromWorldPos(last_frame->world_selection.p1);
|
||||
@ -796,13 +796,14 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
//////////////////////////////
|
||||
//- Build editor UI
|
||||
|
||||
/* TODO: Remove this (testing) */
|
||||
// TODO: Remove this (testing)
|
||||
|
||||
//- Init test layout
|
||||
if (!V.root_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->pref_ratio = 1;
|
||||
panel->is_organizing_panel = 1;
|
||||
@ -812,7 +813,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
{
|
||||
V_Panel *panel = PushStruct(perm, V_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;
|
||||
DllQueuePush(panel->parent->first, panel->parent->last, panel);
|
||||
++panel->parent->count;
|
||||
@ -820,7 +821,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
{
|
||||
V_Window *window = PushStruct(perm, V_Window);
|
||||
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;
|
||||
DllQueuePushNP(panel->first_window, panel->last_window, window, next_in_panel, prev_in_panel);
|
||||
++panel->windows_count;
|
||||
@ -828,7 +829,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
{
|
||||
V_Window *window = PushStruct(perm, V_Window);
|
||||
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;
|
||||
DllQueuePushNP(panel->first_window, panel->last_window, window, next_in_panel, prev_in_panel);
|
||||
++panel->windows_count;
|
||||
@ -839,7 +840,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
{
|
||||
V_Panel *panel = PushStruct(perm, V_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;
|
||||
DllQueuePush(panel->parent->first, panel->parent->last, panel);
|
||||
++panel->parent->count;
|
||||
@ -849,7 +850,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
{
|
||||
V_Window *window = PushStruct(perm, V_Window);
|
||||
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;
|
||||
DllQueuePushNP(panel->first_window, panel->last_window, window, next_in_panel, prev_in_panel);
|
||||
++panel->windows_count;
|
||||
@ -859,7 +860,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
{
|
||||
V_Panel *panel = PushStruct(perm, V_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;
|
||||
DllQueuePush(panel->parent->first, panel->parent->last, panel);
|
||||
++panel->parent->count;
|
||||
@ -867,7 +868,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
{
|
||||
V_Window *window = PushStruct(perm, V_Window);
|
||||
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;
|
||||
DllQueuePushNP(panel->first_window, panel->last_window, window, next_in_panel, prev_in_panel);
|
||||
++panel->windows_count;
|
||||
@ -875,7 +876,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
{
|
||||
V_Window *window = PushStruct(perm, V_Window);
|
||||
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;
|
||||
DllQueuePushNP(panel->first_window, panel->last_window, window, next_in_panel, prev_in_panel);
|
||||
++panel->windows_count;
|
||||
@ -899,7 +900,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
{
|
||||
panel_dfs->visited = 1;
|
||||
|
||||
/* Push children to dfs stack */
|
||||
// Push children to dfs stack
|
||||
V_Panel *ratio_diff_panel = 0;
|
||||
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)
|
||||
{
|
||||
f32 min_ratio = 0.05;
|
||||
@ -926,7 +927,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
ratio_diff_panel->pref_ratio_diff = 0;
|
||||
}
|
||||
|
||||
/* Constrain child raitos */
|
||||
// Constrain child raitos
|
||||
f32 ratio_accum = 0;
|
||||
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 parent_rep = UI_ReportFromKey(panel->parent->key);
|
||||
|
||||
/* FIXME: Height */
|
||||
// FIXME: Height
|
||||
f32 parent_size = 0;
|
||||
f32 new_size = 0;
|
||||
if (panel->axis == Axis_X)
|
||||
@ -1176,7 +1177,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
{
|
||||
V_CommandsWidgetItemDesc item_desc = Zi;
|
||||
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)));
|
||||
if (V_PushCommandsWidgetItem(&frame->commands_widget, item_desc).pressed > 0)
|
||||
{
|
||||
@ -1267,7 +1268,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
//////////////////////////////
|
||||
//- Build console UI
|
||||
|
||||
/* TODO: Remove this whole thing */
|
||||
// TODO: Remove this whole thing
|
||||
if (frame->show_console)
|
||||
{
|
||||
b32 minimized = 0;
|
||||
@ -1277,19 +1278,19 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
|
||||
Vec4 colors[LogLevel_Count][2] = Zi;
|
||||
SetBytes(colors, 0xFF, sizeof(colors));
|
||||
/* Debug colors */
|
||||
// Debug colors
|
||||
colors[LogLevel_Debug][0] = Rgb(0.4, 0.1, 0.4);
|
||||
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][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][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][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][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_PushCP(console_box);
|
||||
{
|
||||
/* Gather display logs */
|
||||
// Gather display logs
|
||||
u64 max = 20;
|
||||
u64 display_count = 0;
|
||||
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;)
|
||||
{
|
||||
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);
|
||||
cmd->target = V.player_key;
|
||||
@ -1566,7 +1567,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
//////////////////////////////
|
||||
//- Build render data
|
||||
|
||||
/* Build shape buffers */
|
||||
// Build shape buffers
|
||||
for (S_Ent *ent = S_FirstEnt(&iter, V.world); ent->active; ent = S_NextEnt(&iter))
|
||||
{
|
||||
Xform ent_to_world_xf = ent->xf;
|
||||
@ -1575,14 +1576,14 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
b32 is_visible = 1;
|
||||
if (is_visible)
|
||||
{
|
||||
/* Draw shape */
|
||||
// Draw shape
|
||||
{
|
||||
Vec4 color = Color_Purple;
|
||||
i32 detail = 32;
|
||||
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);
|
||||
}
|
||||
/* Draw weapon */
|
||||
// Draw weapon
|
||||
if (ent->has_weapon)
|
||||
{
|
||||
Vec4 color = Color_Cyan;
|
||||
@ -1606,7 +1607,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
//////////////////////////////
|
||||
//- Push data to GPU
|
||||
|
||||
/* Target */
|
||||
// Target
|
||||
G_ResourceHandle draw_target = G_PushTexture2D(
|
||||
frame->gpu_arena, frame->cl,
|
||||
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));
|
||||
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 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_IndexBufferDesc dvert_idxs_ib = G_IdxBuff32(dvert_idxs_buff);
|
||||
|
||||
/* Params */
|
||||
// Params
|
||||
V_DParams params = Zi;
|
||||
{
|
||||
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(¶ms));
|
||||
G_StructuredBufferRef params_ro = G_PushStructuredBufferRef(frame->gpu_arena, params_buff, V_DParams);
|
||||
|
||||
/* Constants */
|
||||
// Constants
|
||||
G_SetConstant(frame->cl, V_ShaderConst_Params, params_ro);
|
||||
|
||||
/* Sync */
|
||||
// Sync
|
||||
G_DumbGlobalMemorySync(frame->cl);
|
||||
|
||||
//////////////////////////////
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
X(toggle_fullscreen, Toggle Fullscreen Mode, V_CmdDescFlag_None, V_HOTKEY( Button_Enter, .alt = 1 ) ) \
|
||||
X(toggle_window_topmost, Toggle Window Topmost, V_CmdDescFlag_None, V_HOTKEY( Button_F4 ), ) \
|
||||
X(spawn, Spawn, V_CmdDescFlag_None, V_HOTKEY( Button_S, .ctrl = 1 ), ) \
|
||||
/* -------------------------------------------------------------------------------------------------------------------- */
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Theme types
|
||||
@ -131,10 +131,10 @@ Struct(V_CommandsWidgetItem)
|
||||
|
||||
Struct(V_CommandsWidget)
|
||||
{
|
||||
/* Persistent state */
|
||||
// Persistent state
|
||||
Vec2 pos;
|
||||
|
||||
/* Per-build state */
|
||||
// Per-build state
|
||||
struct
|
||||
{
|
||||
UI_Checkpoint cp;
|
||||
@ -147,7 +147,7 @@ Struct(V_CommandsWidget)
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Window types
|
||||
|
||||
/* TODO: Move boolean fields into bitwise property flags */
|
||||
// TODO: Move boolean fields into bitwise property flags
|
||||
|
||||
Struct(V_Panel)
|
||||
{
|
||||
@ -215,17 +215,17 @@ Struct(V_Frame)
|
||||
Vec2I32 ui_dims;
|
||||
Vec2I32 draw_dims;
|
||||
|
||||
/* Modes */
|
||||
// Modes
|
||||
b32 is_editing;
|
||||
b32 ui_debug;
|
||||
b32 show_command_palette;
|
||||
b32 show_console;
|
||||
|
||||
/* Editor state */
|
||||
// Editor state
|
||||
V_EditMode edit_mode;
|
||||
S_TileKind equipped_tile;
|
||||
|
||||
/* Editor */
|
||||
// Editor
|
||||
b32 is_selecting;
|
||||
b32 is_panning;
|
||||
V_SelectionMode selection_mode;
|
||||
@ -233,23 +233,23 @@ Struct(V_Frame)
|
||||
Vec2 edit_camera_pos;
|
||||
f32 edit_camera_zoom;
|
||||
|
||||
/* Camera */
|
||||
// Camera
|
||||
Vec2 camera_pos;
|
||||
f32 camera_zoom;
|
||||
|
||||
/* World <-> ui */
|
||||
// World <-> ui
|
||||
Xform world_to_ui_xf;
|
||||
Xform ui_to_world_xf;
|
||||
|
||||
/* Draw <-> ui */
|
||||
// Draw <-> ui
|
||||
Xform draw_to_ui_xf;
|
||||
Xform ui_to_draw_xf;
|
||||
|
||||
/* World <-> draw */
|
||||
// World <-> draw
|
||||
Xform world_to_draw_xf;
|
||||
Xform draw_to_world_xf;
|
||||
|
||||
/* Cursors */
|
||||
// Cursors
|
||||
Vec2 ui_cursor;
|
||||
Vec2 draw_cursor;
|
||||
Vec2 world_cursor;
|
||||
@ -257,11 +257,11 @@ Struct(V_Frame)
|
||||
Rng2 draw_selection;
|
||||
Rng2 world_selection;
|
||||
|
||||
/* Control */
|
||||
// Control
|
||||
Vec2 move;
|
||||
Vec2 look;
|
||||
|
||||
/* Sim cmds */
|
||||
// Sim cmds
|
||||
u64 sim_cmds_count;
|
||||
S_CmdNode *first_sim_cmd_node;
|
||||
S_CmdNode *last_sim_cmd_node;
|
||||
|
||||
@ -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_offset = ArenaCount(verts_arena, V_DVert);
|
||||
|
||||
/* Push dverts */
|
||||
// Push dverts
|
||||
V_DVert *dverts = PushStructsNoZero(verts_arena, V_DVert, line_verts_count);
|
||||
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 };
|
||||
}
|
||||
|
||||
/* Generate indices */
|
||||
// Generate indices
|
||||
i32 *indices = PushStructsNoZero(idxs_arena, i32, idx_count);
|
||||
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 idx_count = tris_count * 3;
|
||||
|
||||
/* Push dverts */
|
||||
// Push dverts
|
||||
V_DVert *dverts = PushStructsNoZero(verts_arena, V_DVert, verts_count);
|
||||
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;
|
||||
}
|
||||
|
||||
/* Generate indices in a fan pattern */
|
||||
// Generate indices in a fan pattern
|
||||
i32 *indices = PushStructsNoZero(idxs_arena, i32, idx_count);
|
||||
for (i32 i = 0; i < tris_count; ++i)
|
||||
{
|
||||
|
||||
@ -31,7 +31,7 @@ ComputeShader2D(V_BackdropCS, 8, 8)
|
||||
screen_pos.y < (bounds_screen_p1.y + half_thickness);
|
||||
if (is_in_bounds)
|
||||
{
|
||||
/* Grid checker */
|
||||
// Grid checker
|
||||
{
|
||||
i32 color_idx = 0;
|
||||
Vec4 colors[2] = {
|
||||
@ -58,7 +58,7 @@ ComputeShader2D(V_BackdropCS, 8, 8)
|
||||
}
|
||||
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_p1 = mul(params.world_to_draw_xf, Vec3(ceil(world_pos), 1));
|
||||
@ -72,7 +72,7 @@ ComputeShader2D(V_BackdropCS, 8, 8)
|
||||
result = grid_color;
|
||||
}
|
||||
}
|
||||
/* Tile */
|
||||
// Tile
|
||||
{
|
||||
S_TileKind tile = (S_TileKind)tiles.Load(Vec3I32(tile_pos, 0));
|
||||
switch (tile)
|
||||
@ -90,7 +90,7 @@ ComputeShader2D(V_BackdropCS, 8, 8)
|
||||
} break;
|
||||
}
|
||||
}
|
||||
/* Axis */
|
||||
// Axis
|
||||
{
|
||||
Vec2 zero_screen = mul(params.world_to_draw_xf, Vec3(0, 0, 1));
|
||||
f32 x_dist = abs(screen_pos.x - zero_screen.x);
|
||||
@ -104,7 +104,7 @@ ComputeShader2D(V_BackdropCS, 8, 8)
|
||||
result = y_axis_color;
|
||||
}
|
||||
}
|
||||
/* World bounds */
|
||||
// World bounds
|
||||
{
|
||||
f32 bounds_dist = 100000;
|
||||
bounds_dist = min(bounds_dist, abs(screen_pos.x - bounds_screen_p0.x));
|
||||
|
||||
@ -2644,8 +2644,8 @@ JobImpl(PP_UpdateSim, UNUSED sig, UNUSED key)
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We do not have the tick that the incoming delta is based from.
|
||||
* This decode should never have been queued in the first place. */
|
||||
// We do not have the tick that the incoming delta is based from.
|
||||
// This decode should never have been queued in the first place.
|
||||
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.
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
// 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.
|
||||
// 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:
|
||||
// - 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:
|
||||
// - 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;
|
||||
if (cmds_ahead_on_master < -3 || cmds_ahead_on_master > 10)
|
||||
|
||||
@ -254,8 +254,8 @@ Vec3 PP_AccumulatedLightFromPos(Vec2U32 pos)
|
||||
|
||||
//- Tone mapping
|
||||
|
||||
/* ACES approximation by Krzysztof Narkowicz
|
||||
* https://knarkowicz.wordpress.com/2016/01/06/aces-filmic-tone-mapping-curve/ */
|
||||
// ACES approximation by Krzysztof Narkowicz
|
||||
// https://knarkowicz.wordpress.com/2016/01/06/aces-filmic-tone-mapping-curve/
|
||||
Vec3 PP_ToneMap(Vec3 v)
|
||||
{
|
||||
return saturate((v * (2.51f * v + 0.03f)) / (v * (2.43f * v + 0.59f) + 0.14f));
|
||||
|
||||
@ -130,9 +130,10 @@ void PP_ReleaseAllWithProp(PP_Snapshot *ss, PP_Prop prop)
|
||||
}
|
||||
}
|
||||
|
||||
/* Release from snapshot */
|
||||
/* TODO: Breadth first iteration to only release parent entities (since
|
||||
* child entities will be released along with parent anyway) */
|
||||
// Release from snapshot
|
||||
//
|
||||
// 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)
|
||||
{
|
||||
PP_Ent *ent = ents_to_release[i];
|
||||
|
||||
@ -132,7 +132,7 @@ void PP_CreateAndUpdateContacts(PP_PhysStepCtx *ctx, f32 elapsed_dt, u64 phys_it
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
/* Delete contact by replacing with last in array */
|
||||
// Delete contact by replacing with last in array
|
||||
*old = constraint->points[--constraint->num_points];
|
||||
--i;
|
||||
}
|
||||
|
||||
@ -35,14 +35,13 @@ Struct(PP_PhysStepCtx)
|
||||
|
||||
Struct(PP_ContactPoint)
|
||||
{
|
||||
/* Contact point relative to the center of each entity.
|
||||
*
|
||||
* NOTE: We use fixed (non-rotated) points relative to the entities
|
||||
* rather than points fully in local space because contact manifolds
|
||||
* shouldn't really be affected by rotation accross substeps
|
||||
* (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)
|
||||
*/
|
||||
// Contact point relative to the center of each entity.
|
||||
//
|
||||
// NOTE: We use fixed (non-rotated) points relative to the entities
|
||||
// rather than points fully in local space because contact manifolds
|
||||
// shouldn't really be affected by rotation accross substeps
|
||||
// (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)
|
||||
Vec2 vcp0;
|
||||
Vec2 vcp1;
|
||||
|
||||
@ -176,8 +175,8 @@ Struct(PP_WeldJointDesc)
|
||||
PP_EntKey e0;
|
||||
PP_EntKey e1;
|
||||
|
||||
/* 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) */
|
||||
// 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)
|
||||
Xform xf;
|
||||
|
||||
f32 linear_spring_hz;
|
||||
|
||||
@ -1,28 +1,29 @@
|
||||
/* Sim hierarchy is as follows:
|
||||
*
|
||||
* 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 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.
|
||||
* - 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.
|
||||
*
|
||||
* An ent is the smallest unit of simulation state.
|
||||
* - It is assigned a 128 bit unique identifer generated at allocation time.
|
||||
* - This key is used to refer to other ents in the tree and to sync ents accross clients.
|
||||
* - This key is usually random, but can be deterministic under certain conditions.
|
||||
* - For example, instead of storing a contact constraint lookup table, contact constraints are
|
||||
* retrieved by searching for the ent with the key resulting from combining the ent keys of the
|
||||
* two contacting entities (plus a unique 'basis' ent key used for all contact constraints).
|
||||
* - 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.
|
||||
* - 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.
|
||||
*/
|
||||
//
|
||||
// Sim hierarchy is as follows:
|
||||
//
|
||||
// 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 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.
|
||||
// - 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.
|
||||
//
|
||||
// An ent is the smallest unit of simulation state.
|
||||
// - It is assigned a 128 bit unique identifer generated at allocation time.
|
||||
// - This key is used to refer to other ents in the tree and to sync ents accross clients.
|
||||
// - This key is usually random, but can be deterministic under certain conditions.
|
||||
// - For example, instead of storing a contact constraint lookup table, contact constraints are
|
||||
// retrieved by searching for the ent with the key resulting from combining the ent keys of the
|
||||
// two contacting entities (plus a unique 'basis' ent key used for all contact constraints).
|
||||
// - 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.
|
||||
// - 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
|
||||
@ -687,8 +688,8 @@ PP_Snapshot *PP_AcquireSnapshotFromLerp(PP_Client *client, PP_Snapshot *ss0, PP_
|
||||
|
||||
if (!ss0->valid || !ss1->valid)
|
||||
{
|
||||
/* New snapshot allocation caused one of the src snapshots original to release.
|
||||
* ss0 & ss1 should be from a separate client than the allocating one. */
|
||||
// New snapshot allocation caused one of the src snapshots original to release.
|
||||
// ss0 & ss1 should be from a separate client than the allocating one.
|
||||
Assert(0);
|
||||
}
|
||||
|
||||
@ -723,10 +724,9 @@ void PP_SyncSnapshotEnts(PP_Snapshot *local_ss, PP_Snapshot *remote_ss, PP_EntKe
|
||||
{
|
||||
__prof;
|
||||
|
||||
/* FIXME: Don't trust non-master clients:
|
||||
* - Only sync cmd ents
|
||||
* - Determine new UUids for newly created ents
|
||||
*/
|
||||
// FIXME: Don't trust non-master clients:
|
||||
// - Only sync cmd ents
|
||||
// - Determine new UUids for newly created ents
|
||||
|
||||
PP_Ent *local_root = PP_EntFromKey(local_ss, PP_RootEntKey);
|
||||
PP_Ent *remote_root = PP_EntFromKey(remote_ss, PP_RootEntKey);
|
||||
|
||||
@ -80,9 +80,9 @@ Struct(PP_Client)
|
||||
/* This is the highest confirmed tick of ours that we know this client has received */
|
||||
u64 ack;
|
||||
|
||||
/* 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
|
||||
* therefore can be released) */
|
||||
// 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
|
||||
// therefore can be released)
|
||||
u64 double_ack;
|
||||
|
||||
/* This is the highest tick of their's that we have received */
|
||||
|
||||
@ -7,9 +7,9 @@ Readonly PP_Space PP_nil_space = ZI;
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Space
|
||||
|
||||
/* NOTE:
|
||||
* 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. */
|
||||
// NOTE:
|
||||
// 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. */
|
||||
PP_Space *PP_AcquireSpace(f32 cell_size, u32 num_bins_sqrt)
|
||||
{
|
||||
PP_Space *space;
|
||||
|
||||
@ -24,8 +24,8 @@ Struct(PP_SpaceEntry)
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Space cell types
|
||||
|
||||
/* 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. */
|
||||
// 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. */
|
||||
Struct(PP_SpaceCellNode)
|
||||
{
|
||||
PP_SpaceEntry *entry;
|
||||
|
||||
@ -441,9 +441,10 @@ void PP_GenerateTestWalls(PP_Snapshot *world)
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
PP_Ent *root = PP_EntFromKey(world, PP_RootEntKey);
|
||||
|
||||
/* 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 */
|
||||
// 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
|
||||
PP_Ent **x_sorted_tile_chunks = 0;
|
||||
PP_Ent **y_sorted_tile_chunks = 0;
|
||||
u64 sorted_tile_chunks_count = 0;
|
||||
@ -455,7 +456,7 @@ void PP_GenerateTestWalls(PP_Snapshot *world)
|
||||
if (!ent->valid) continue;
|
||||
if (PP_HasProp(ent, PP_Prop_TileChunk))
|
||||
{
|
||||
/* Append chunk to array */
|
||||
// Append chunk to array
|
||||
*PushStructNoZero(scratch.arena, PP_Ent *) = ent;
|
||||
++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);
|
||||
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
|
||||
* should merge with another wall that was generated from a diagonal chunk. */
|
||||
// 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.
|
||||
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);
|
||||
}
|
||||
@ -482,8 +483,8 @@ void PP_GenerateTestWalls(PP_Snapshot *world)
|
||||
struct wall_node *next;
|
||||
};
|
||||
|
||||
/* Dicts containing walls that end on edge of tile chunk, keyed by tile end index.
|
||||
* Used to merge walls accross tile chunks. */
|
||||
// Dicts containing walls that end on edge of tile chunk, keyed by tile end index.
|
||||
// Used to merge walls accross tile chunks.
|
||||
Dict *horizontal_ends_dict = InitDict(scratch.arena, 1024);
|
||||
Dict *vertical_ends_dict = InitDict(scratch.arena, 1024);
|
||||
|
||||
|
||||
@ -18,7 +18,7 @@ void PT_RunForever(WaveLaneCtx *lane)
|
||||
{
|
||||
G_CommandListHandle cl = G_PrepareCommandList(G_QueueKind_Direct);
|
||||
{
|
||||
/* Push resources */
|
||||
// Push resources
|
||||
Vec2I32 final_target_size = window_frame.draw_size;
|
||||
G_ResourceHandle final_target = G_PushTexture2D(
|
||||
gpu_frame_arena,
|
||||
@ -28,11 +28,11 @@ void PT_RunForever(WaveLaneCtx *lane)
|
||||
.flags = G_ResourceFlag_AllowShaderReadWrite
|
||||
);
|
||||
|
||||
/* Push resource handles */
|
||||
// Push resource handles
|
||||
G_Texture2DRef final_target_rhandle = G_PushTexture2DRef(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_TestConst, 3.123);
|
||||
@ -41,19 +41,19 @@ void PT_RunForever(WaveLaneCtx *lane)
|
||||
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_DumbMemorySync(cl, final_target);
|
||||
|
||||
/* Prep blit pass */
|
||||
// Prep blit pass
|
||||
{
|
||||
G_DumbMemoryLayoutSync(cl, final_target, G_Layout_DirectQueue_ShaderRead);
|
||||
G_DumbMemoryLayoutSync(cl, window_frame.backbuffer, G_Layout_DirectQueue_RenderTargetWrite);
|
||||
}
|
||||
|
||||
/* Blit pass */
|
||||
// Blit pass
|
||||
{
|
||||
G_Rasterize(
|
||||
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);
|
||||
}
|
||||
|
||||
/* Reset */
|
||||
// Reset
|
||||
{
|
||||
G_ResetArena(cl, gpu_frame_arena);
|
||||
}
|
||||
|
||||
@ -3,11 +3,11 @@
|
||||
|
||||
G_DeclConstant(G_Texture3DRef, PT_ShaderConst_NoiseTex, 0);
|
||||
|
||||
/* Test shader */
|
||||
// Test shader
|
||||
G_DeclConstant(G_RWTexture2DRef, PT_ShaderConst_TestTarget, 1);
|
||||
G_DeclConstant(G_StructuredBufferRef, PT_ShaderConst_TestBuff, 2);
|
||||
G_DeclConstant(f32, PT_ShaderConst_TestConst, 3);
|
||||
|
||||
/* Blit shader */
|
||||
// Blit shader
|
||||
G_DeclConstant(G_SamplerStateRef, PT_ShaderConst_BlitSampler, 4);
|
||||
G_DeclConstant(G_Texture2DRef, PT_ShaderConst_BlitSrc, 5);
|
||||
|
||||
@ -14,7 +14,7 @@ JobImpl(SND_Load, sig, id)
|
||||
|
||||
String error_msg = Lit("Unknown error");
|
||||
|
||||
/* Decode */
|
||||
// Decode
|
||||
MP3_Result decoded = ZI;
|
||||
String resource_data = DataFromResource(resource);
|
||||
if (resource_data.len > 0)
|
||||
@ -37,7 +37,7 @@ JobImpl(SND_Load, sig, id)
|
||||
|
||||
if (decoded.ok)
|
||||
{
|
||||
/* Store */
|
||||
// Store
|
||||
SND_Sound *sound = 0;
|
||||
u64 samples_count = decoded.samples_count;
|
||||
i16 *samples = 0;
|
||||
@ -48,7 +48,7 @@ JobImpl(SND_Load, sig, id)
|
||||
AC_CloseStore(&store);
|
||||
}
|
||||
|
||||
/* Initialize */
|
||||
// Initialize
|
||||
ZeroStruct(sound);
|
||||
sound->flags = flags;
|
||||
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));
|
||||
|
||||
/* Store */
|
||||
// Store
|
||||
SND_Sound *sound = 0;
|
||||
{
|
||||
AC_Store store = AC_OpenStore();
|
||||
@ -83,7 +83,7 @@ AC_Asset *SND_LoadAsset(ResourceKey resource, SND_SoundFlag flags, b32 wait)
|
||||
{
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
|
||||
/* Generate and append sound flags to name key */
|
||||
// Generate and append sound flags to name key
|
||||
String name = NameFromResource(resource);
|
||||
String key = StringF(
|
||||
scratch.arena,
|
||||
|
||||
@ -20,7 +20,7 @@ JobImpl(SPR_LoadTexture, sig, _)
|
||||
ASE_DecodedImage decoded = ASE_DecodeImage(scratch.arena, data);
|
||||
ok = decoded.ok;
|
||||
|
||||
/* Upload texture to gpu */
|
||||
// Upload texture to gpu
|
||||
if (ok)
|
||||
{
|
||||
GPU_ArenaHandle gpu_perm = GPU_PermArena();
|
||||
@ -74,7 +74,7 @@ JobImpl(SPR_LoadSheet, sig, _)
|
||||
sheet->image_size = image_size;
|
||||
sheet->frame_size = frame_size;
|
||||
|
||||
/* Init frames */
|
||||
// Init frames
|
||||
sheet->frames_count = decoded.num_frames;
|
||||
sheet->frames = PushStructs(perm, SPR_Frame, sheet->frames_count);
|
||||
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);
|
||||
}
|
||||
|
||||
/* Init spans */
|
||||
// Init spans
|
||||
sheet->spans_count = decoded.num_spans;
|
||||
sheet->span_bins_count = MaxU32(AlignU64ToNextPow2(sheet->spans_count * 2), 1);
|
||||
sheet->spans = PushStructs(perm, SPR_Span, sheet->spans_count);
|
||||
@ -100,7 +100,7 @@ JobImpl(SPR_LoadSheet, sig, _)
|
||||
dst->name = PushString(perm, src->name);
|
||||
dst->start = src->start;
|
||||
dst->end = src->end;
|
||||
/* Insert span into bin */
|
||||
// Insert span into bin
|
||||
{
|
||||
SPR_SpanBin *bin = &sheet->span_bins[dst->hash % sheet->span_bins_count];
|
||||
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_group_bins_count = MaxU32(AlignU64ToNextPow2(sheet->slice_groups_count * 2), 1);
|
||||
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->name = PushString(perm, src_group->name);
|
||||
|
||||
/* Init slices */
|
||||
// Init slices
|
||||
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)
|
||||
{
|
||||
f32 x0_px = src_slice->rect.p0.x;
|
||||
@ -142,15 +142,15 @@ JobImpl(SPR_LoadSheet, sig, _)
|
||||
f32 width = x1 - x0;
|
||||
f32 height = y1 - y0;
|
||||
|
||||
/* Rect */
|
||||
// Rect
|
||||
Rng2 rect_px = RNG2(VEC2(x0_px, y0_px), VEC2(x1_px, y1_px));
|
||||
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 = VEC2(x0 + (width * 0.5f), y0 + (height * 0.5f));
|
||||
|
||||
/* Dir */
|
||||
// Dir
|
||||
Vec2 dir_px = VEC2(center_px.x, -1);
|
||||
Vec2 dir = VEC2(0, -1);
|
||||
|
||||
@ -164,7 +164,7 @@ JobImpl(SPR_LoadSheet, sig, _)
|
||||
dst_slice->dir = dir;
|
||||
}
|
||||
|
||||
/* Copy slices forward into frames without a slice */
|
||||
// Copy slices forward into frames without a slice
|
||||
{
|
||||
SPR_Slice *origin = 0;
|
||||
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];
|
||||
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");
|
||||
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
|
||||
|
||||
/* TODO: Per-thread L1 cache */
|
||||
// TODO: Per-thread L1 cache
|
||||
SPR_Entry *SPR_FetchEntry(ResourceKey resource, JobPoolId pool, SPR_FetchFlag flags)
|
||||
{
|
||||
SPR_SharedState *g = &SPR_shared_state;
|
||||
SPR_Entry *entry = 0;
|
||||
{
|
||||
SPR_EntryBin *bin = &g->entry_bins[resource.hash % SPR_EntryBinsCount];
|
||||
/* Search for entry */
|
||||
// Search for entry
|
||||
entry = bin->first;
|
||||
{
|
||||
Lock lock = LockS(&bin->mutex);
|
||||
@ -259,12 +259,12 @@ SPR_Entry *SPR_FetchEntry(ResourceKey resource, JobPoolId pool, SPR_FetchFlag fl
|
||||
}
|
||||
Unlock(&lock);
|
||||
}
|
||||
/* Entry not found: lock, re-search, & create */
|
||||
// Entry not found: lock, re-search, & create
|
||||
if (!entry)
|
||||
{
|
||||
Lock lock = LockE(&bin->mutex);
|
||||
{
|
||||
/* Re-search */
|
||||
// Re-search
|
||||
entry = bin->first;
|
||||
for (; entry; entry = entry->next_in_bin)
|
||||
{
|
||||
@ -273,7 +273,7 @@ SPR_Entry *SPR_FetchEntry(ResourceKey resource, JobPoolId pool, SPR_FetchFlag fl
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Create */
|
||||
// Create
|
||||
if (!entry)
|
||||
{
|
||||
Arena *perm = PermArena();
|
||||
@ -285,7 +285,7 @@ SPR_Entry *SPR_FetchEntry(ResourceKey resource, JobPoolId pool, SPR_FetchFlag fl
|
||||
Unlock(&lock);
|
||||
}
|
||||
}
|
||||
/* Launch load jobs */
|
||||
// Launch load jobs
|
||||
if ((flags & SPR_FetchFlag_Texture)
|
||||
&& !Atomic32Fetch(&entry->texture_touched)
|
||||
&& !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)
|
||||
{
|
||||
SPR_SliceKey pivot_key = SPR_SliceKeyFromName(Lit("pivot"));
|
||||
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_px = MulVec2(sheet->frame_size, 0.5f);
|
||||
result.dir_px = VEC2(result.center_px.x, 0);
|
||||
|
||||
@ -51,18 +51,18 @@ Struct(SPR_SpanBin)
|
||||
|
||||
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;
|
||||
|
||||
/* 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;
|
||||
|
||||
/* 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;
|
||||
Vec2 center;
|
||||
Vec2 dir;
|
||||
|
||||
/* '_px' values retain the original sprite pixel dimensions */
|
||||
// '_px' values retain the original sprite pixel dimensions
|
||||
Rng2 rect_px;
|
||||
Vec2 center_px;
|
||||
Vec2 dir_px;
|
||||
|
||||
@ -11,11 +11,10 @@ u64 TAR_U64FromOctString(String str)
|
||||
return n;
|
||||
}
|
||||
|
||||
/* `prefix` will be prepended to all file names in the archive
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
// `prefix` will be prepended to all file names in the archive
|
||||
//
|
||||
// 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.
|
||||
TAR_Archive TAR_ArchiveFromString(Arena *arena, String data, String prefix)
|
||||
{
|
||||
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")))
|
||||
{
|
||||
/* Invalid header */
|
||||
// Invalid header
|
||||
Assert(0);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (header.file_name_prefix[0] != 0)
|
||||
{
|
||||
/* Header file name prefix not supported */
|
||||
// Header file name prefix not supported
|
||||
Assert(0);
|
||||
continue;
|
||||
}
|
||||
@ -53,14 +52,14 @@ TAR_Archive TAR_ArchiveFromString(Arena *arena, String data, String prefix)
|
||||
}
|
||||
String file_data = STRING(file_size, file_data_ptr);
|
||||
|
||||
/* Skip sector padding */
|
||||
// Skip sector padding
|
||||
u64 remaining = (512 - (file_size % 512)) % 512;
|
||||
BB_SeekBytes(&br, remaining);
|
||||
|
||||
b32 is_dir = header.file_type == TAR_FileKind_Directory;
|
||||
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);
|
||||
continue;
|
||||
}
|
||||
@ -68,7 +67,7 @@ TAR_Archive TAR_ArchiveFromString(Arena *arena, String data, String prefix)
|
||||
String file_name_cstr = StringFromCstrNoLimit((char *)header.file_name);
|
||||
if (file_name_cstr.len >= 2)
|
||||
{
|
||||
/* Chop off './' prefix */
|
||||
// Chop off './' prefix
|
||||
file_name_cstr.len -= 2;
|
||||
file_name_cstr.text += 2;
|
||||
}
|
||||
@ -85,7 +84,7 @@ TAR_Archive TAR_ArchiveFromString(Arena *arena, String data, String prefix)
|
||||
++num_files;
|
||||
}
|
||||
|
||||
/* Build lookup table */
|
||||
// Build lookup table
|
||||
archive.lookup = InitDict(arena, (u64)((f64)num_files * TAR_ArchiveLookupTableCapacityFactor));
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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) */
|
||||
// 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)
|
||||
for (TAR_Entry *entry = archive.head; entry; entry = entry->next)
|
||||
{
|
||||
/* Enter into hierarchy */
|
||||
// Enter into hierarchy
|
||||
if (!entry->is_dir)
|
||||
{
|
||||
/* Find parent entry */
|
||||
// Find parent entry
|
||||
TAR_Entry *parent_entry = 0;
|
||||
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;
|
||||
}
|
||||
}
|
||||
/* Insert child into parent's list */
|
||||
// Insert child into parent's list
|
||||
if (parent_entry)
|
||||
{
|
||||
entry->next_child = parent_entry->next_child;
|
||||
|
||||
@ -11,7 +11,7 @@ Struct(TAR_Entry)
|
||||
|
||||
b32 is_dir;
|
||||
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;
|
||||
|
||||
Struct(TAR_Archive)
|
||||
@ -39,7 +39,7 @@ Enum(TAR_FileKind)
|
||||
|
||||
Packed(Struct(TAR_Header)
|
||||
{
|
||||
/* Pre-posix */
|
||||
// Pre-posix
|
||||
u8 file_name[100];
|
||||
u8 file_mode[8];
|
||||
u8 owner_id[8];
|
||||
@ -48,11 +48,11 @@ Packed(Struct(TAR_Header)
|
||||
u8 last_modified[12];
|
||||
u8 checksum[8];
|
||||
|
||||
/* Both */
|
||||
// Both
|
||||
u8 file_type;
|
||||
u8 linked_file_name[100];
|
||||
|
||||
/* UStar */
|
||||
// UStar
|
||||
u8 ustar_indicator[6];
|
||||
u8 ustar_version[2];
|
||||
u8 owner_user_name[32];
|
||||
|
||||
@ -6,15 +6,15 @@ Struct(TTF_GlyphResult)
|
||||
ResourceKey ttf;
|
||||
u32 codepoint;
|
||||
|
||||
f32 advance; /* How far to advance the baseline position */
|
||||
Rng2 bounds; /* Bounds relative to baseline position */
|
||||
f32 advance; // How far to advance the baseline position
|
||||
Rng2 bounds; // Bounds relative to baseline position
|
||||
|
||||
f32 font_size;
|
||||
f32 font_ascent;
|
||||
f32 font_descent;
|
||||
f32 font_cap;
|
||||
|
||||
/* Rasterization output */
|
||||
// Rasterization output
|
||||
Vec2I32 image_dims;
|
||||
u32 *image_pixels;
|
||||
};
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/* Based on Allen Webster's dwrite rasterizer example -
|
||||
* https://github.com/4th-dimention/examps */
|
||||
// Based on Allen Webster's dwrite rasterizer example -
|
||||
// https://github.com/4th-dimention/examps
|
||||
|
||||
extern TTF_DW_Ctx TTF_DW = Zi;
|
||||
|
||||
@ -8,24 +8,23 @@ extern TTF_DW_Ctx TTF_DW = Zi;
|
||||
|
||||
void TTF_Bootstrap(void)
|
||||
{
|
||||
/* 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
|
||||
* using a factory5 since I think WriteInMemoryFileLoader wasn't
|
||||
* implemented until then)
|
||||
*/
|
||||
// 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
|
||||
// using a factory5 since I think WriteInMemoryFileLoader wasn't
|
||||
// implemented until then)
|
||||
HRESULT hr = 0;
|
||||
{
|
||||
/* Factory */
|
||||
// Factory
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, &IID_IDWriteFactory5, (void **)&TTF_DW.factory);
|
||||
}
|
||||
/* GDI interop */
|
||||
// GDI interop
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = IDWriteFactory5_GetGdiInterop(TTF_DW.factory, &TTF_DW.gdi_interop);
|
||||
}
|
||||
/* Loader */
|
||||
// Loader
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
/* Builder */
|
||||
// Builder
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = IDWriteFactory5_CreateFontSetBuilder1(TTF_DW.factory, &TTF_DW.builder);
|
||||
}
|
||||
/* Rendering params */
|
||||
// Rendering params
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
IDWriteRenderingParams *default_rendering_params = 0;
|
||||
{
|
||||
hr = IDWriteFactory5_CreateRenderingParams(TTF_DW.factory, &default_rendering_params);
|
||||
}
|
||||
//
|
||||
// UNUSED:
|
||||
//
|
||||
// f32 gamma = IDWriteRenderingParams_GetGamma(default_rendering_params);
|
||||
// f32 clear_type_level = IDWriteRenderingParams_GetClearTypeLevel(default_rendering_params);
|
||||
// DWRITE_PIXEL_GEOMETRY pixel_geometry = IDWriteRenderingParams_GetPixelGeometry(default_rendering_params);
|
||||
// DWRITE_RENDERING_MODE rendering_mode = IDWriteRenderingParams_GetRenderingMode(default_rendering_params);
|
||||
//
|
||||
f32 enhanced_contrast = IDWriteRenderingParams_GetEnhancedContrast(default_rendering_params);
|
||||
hr = IDWriteFactory5_CreateCustomRenderingParams2(
|
||||
TTF_DW.factory,
|
||||
@ -123,7 +126,7 @@ TTF_GlyphResult TTF_RasterizeGlyphFromCodepoint(Arena *arena, u32 codepoint, Res
|
||||
font->hash = hash;
|
||||
font->ttf = ttf;
|
||||
font->size = font_size;
|
||||
/* File */
|
||||
// File
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = IDWriteInMemoryFontFileLoader_CreateInMemoryFontFileReference(
|
||||
@ -139,7 +142,7 @@ TTF_GlyphResult TTF_RasterizeGlyphFromCodepoint(Arena *arena, u32 codepoint, Res
|
||||
hr = IDWriteFontSetBuilder1_AddFontFile(TTF_DW.builder, font->file);
|
||||
}
|
||||
}
|
||||
/* Face */
|
||||
// Face
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = IDWriteFactory5_CreateFontFace(
|
||||
@ -152,7 +155,7 @@ TTF_GlyphResult TTF_RasterizeGlyphFromCodepoint(Arena *arena, u32 codepoint, Res
|
||||
&font->face
|
||||
);
|
||||
}
|
||||
/* Metrics */
|
||||
// Metrics
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
IDWriteFontFace_GetMetrics(font->face, &font->design_metrics);
|
||||
@ -179,7 +182,7 @@ TTF_GlyphResult TTF_RasterizeGlyphFromCodepoint(Arena *arena, u32 codepoint, Res
|
||||
{
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
/* TODO: Dynamic render target dimensions? */
|
||||
// TODO: Dynamic render target dimensions?
|
||||
|
||||
//////////////////////////////
|
||||
//- Fetch render target
|
||||
@ -229,14 +232,14 @@ TTF_GlyphResult TTF_RasterizeGlyphFromCodepoint(Arena *arena, u32 codepoint, Res
|
||||
//////////////////////////////
|
||||
//- Render
|
||||
|
||||
/* Glyph idx */
|
||||
// Glyph idx
|
||||
u16 glyph_idx = 0;
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = IDWriteFontFace_GetGlyphIndices(font->face, &codepoint, 1, &glyph_idx);
|
||||
}
|
||||
|
||||
/* Glyph metrics */
|
||||
// Glyph metrics
|
||||
DWRITE_GLYPH_METRICS m = Zi;
|
||||
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;
|
||||
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;
|
||||
rt_baseline.x = (rt_dims.x / 2) - (advance / 2);
|
||||
rt_baseline.y = (rt_dims.y / 2) + (font_cap / 2);
|
||||
|
||||
/* Render */
|
||||
// Render
|
||||
Rng2I32 rt_slice = Zi;
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
/* Clear target */
|
||||
// Clear target
|
||||
{
|
||||
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);
|
||||
}
|
||||
/* Draw glyph */
|
||||
// Draw glyph
|
||||
{
|
||||
DWRITE_GLYPH_RUN glyph_run = Zi;
|
||||
{
|
||||
@ -299,7 +302,7 @@ TTF_GlyphResult TTF_RasterizeGlyphFromCodepoint(Arena *arena, u32 codepoint, Res
|
||||
//////////////////////////////
|
||||
//- Copy result
|
||||
|
||||
/* Copy from target to result */
|
||||
// Copy from target to result
|
||||
Vec2I32 dst_dims = Zi;
|
||||
u32 *dst_pixels = 0;
|
||||
if (SUCCEEDED(hr))
|
||||
@ -329,7 +332,7 @@ TTF_GlyphResult TTF_RasterizeGlyphFromCodepoint(Arena *arena, u32 codepoint, Res
|
||||
result.image_dims = dst_dims;
|
||||
result.image_pixels = dst_pixels;
|
||||
|
||||
/* Free render target */
|
||||
// Free render target
|
||||
{
|
||||
Lock lock = LockE(&TTF_DW.free_render_targets_mutex);
|
||||
SllStackPush(TTF_DW.first_free_render_target, rt);
|
||||
|
||||
@ -7,9 +7,8 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ DirectWrite types
|
||||
|
||||
/* DirectWrite C API stubs are taken from Mārtiņš Možeiko's c_d2d_dwrite
|
||||
* https://github.com/mmozeiko/c_d2d_dwrite/blob/main/cdwrite.h
|
||||
*/
|
||||
// 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
|
||||
|
||||
//- GUIDs
|
||||
|
||||
@ -189,7 +188,7 @@ Struct(TTF_DW_RenderTarget)
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Context types
|
||||
|
||||
/* TODO: Determine font dpi dynamically */
|
||||
// TODO: Determine font dpi dynamically
|
||||
#define TTF_DW_Dpi (96.0f)
|
||||
|
||||
Struct(TTF_DW_Ctx)
|
||||
|
||||
130
src/ui/ui_core.c
130
src/ui/ui_core.c
@ -76,7 +76,7 @@ UI_Box *UI_BoxFromKey(UI_Key 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->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->first = 0;
|
||||
}
|
||||
/* Create root dfs node */
|
||||
// Create root dfs node
|
||||
UI_BoxIterDfsNode *dfs = iter->first_free;
|
||||
if (dfs)
|
||||
{
|
||||
@ -115,11 +115,11 @@ UI_BoxIterResult UI_NextBox(Arena *arena, UI_BoxIter *iter)
|
||||
UI_Box *box = dfs->box;
|
||||
if (!dfs->visited)
|
||||
{
|
||||
/* Pre order */
|
||||
// Pre order
|
||||
dfs->visited = 1;
|
||||
result.box = box;
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
/* Push non-floating children to dfs stack */
|
||||
// Push non-floating children to dfs stack
|
||||
for (UI_Box *child = box->last; child; child = child->prev)
|
||||
{
|
||||
if (!AnyBit(child->desc.flags, UI_BoxFlag_Floating))
|
||||
@ -160,7 +160,7 @@ UI_BoxIterResult UI_NextBox(Arena *arena, UI_BoxIter *iter)
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Post order */
|
||||
// Post order
|
||||
result.box = box;
|
||||
result.pre = 0;
|
||||
SllStackPop(iter->first);
|
||||
@ -292,7 +292,7 @@ void UI_PushStyle(UI_StyleDesc desc)
|
||||
case UI_StyleKind_ChildAlignment:
|
||||
{
|
||||
UI_Alignment alignment = desc.style.ChildAlignment;
|
||||
/* Alignment -> horizontal alignment */
|
||||
// Alignment -> horizontal alignment
|
||||
switch(alignment)
|
||||
{
|
||||
default: break;
|
||||
@ -315,7 +315,7 @@ void UI_PushStyle(UI_StyleDesc desc)
|
||||
UI_PushCopy(ChildAlignmentX, desc, UI_AxisAlignment_End);
|
||||
} break;
|
||||
}
|
||||
/* Alignment -> vertical alignment */
|
||||
// Alignment -> vertical alignment
|
||||
switch(alignment)
|
||||
{
|
||||
default: break;
|
||||
@ -374,7 +374,7 @@ void UI_PushStyle(UI_StyleDesc desc)
|
||||
n->checkpoint = stack->top_checkpoint;
|
||||
}
|
||||
|
||||
/* Initialize style data from desc */
|
||||
// Initialize style data from desc
|
||||
switch (kind)
|
||||
{
|
||||
default: break;
|
||||
@ -553,7 +553,7 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color)
|
||||
if (!UI.box_arena)
|
||||
{
|
||||
UI.box_arena = AcquireArena(Gibi(64));
|
||||
/* Init frames */
|
||||
// Init frames
|
||||
for (u64 i = 0; i < countof(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->gpu_arena = G_AcquireArena();
|
||||
}
|
||||
/* Init root box */
|
||||
// Init root box
|
||||
{
|
||||
UI_Box *box = PushStruct(UI.box_arena, UI_Box);
|
||||
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;
|
||||
}
|
||||
|
||||
/* Init style stack */
|
||||
// Init style stack
|
||||
{
|
||||
frame->top_stack = PushStruct(frame->arena, UI_Stack);
|
||||
UI_PushDefaults();
|
||||
@ -623,11 +623,11 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color)
|
||||
f64 dt = SecondsFromNs(frame->dt_ns);
|
||||
f64 inv_dt = 1.0 / dt;
|
||||
|
||||
/* Locate boxes */
|
||||
// Locate boxes
|
||||
UI_Box *hovered_box = 0;
|
||||
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)
|
||||
{
|
||||
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;)
|
||||
{
|
||||
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;
|
||||
{
|
||||
/* 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 p1 = box->rect.p1;
|
||||
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;
|
||||
}
|
||||
|
||||
/* Update state from controller events */
|
||||
// Update state from controller events
|
||||
for (u64 cev_index = 0; cev_index < controller_events.count; ++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)
|
||||
{
|
||||
UI_Box *box = last_frame->boxes_pre[pre_index];
|
||||
@ -824,10 +824,10 @@ void UI_EndFrame(UI_Frame *frame)
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Allocate new box */
|
||||
// Allocate new box
|
||||
if (box == 0)
|
||||
{
|
||||
/* Allocate new box */
|
||||
// Allocate new box
|
||||
box = UI.first_free_box;
|
||||
if (box)
|
||||
{
|
||||
@ -875,22 +875,22 @@ void UI_EndFrame(UI_Frame *frame)
|
||||
}
|
||||
}
|
||||
|
||||
/* Update parent */
|
||||
// Update parent
|
||||
if (box->parent)
|
||||
{
|
||||
/* Remove from old parent */
|
||||
// Remove from old parent
|
||||
DllQueueRemove(box->parent->first, box->parent->last, box);
|
||||
--box->parent->count;
|
||||
}
|
||||
if (parent)
|
||||
{
|
||||
/* Add to new parent */
|
||||
// Add to new parent
|
||||
DllQueuePush(parent->first, parent->last, box);
|
||||
++parent->count;
|
||||
}
|
||||
box->parent = parent;
|
||||
|
||||
/* Update box */
|
||||
// Update box
|
||||
{
|
||||
box->desc = cmd.box;
|
||||
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 *parent = box->parent;
|
||||
UI_BoxBin *bin = &UI.box_bins[box->key.hash % countof(UI.box_bins)];
|
||||
/* Re-parent children */
|
||||
// Re-parent children
|
||||
if (box->first)
|
||||
{
|
||||
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->count += box->count;
|
||||
}
|
||||
/* Remove from parent */
|
||||
// Remove from parent
|
||||
DllQueueRemove(parent->first, parent->last, box);
|
||||
--parent->count;
|
||||
/* Remove from lookup table */
|
||||
// Remove from lookup table
|
||||
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);
|
||||
--UI.boxes_count;
|
||||
}
|
||||
@ -966,7 +966,7 @@ void UI_EndFrame(UI_Frame *frame)
|
||||
//////////////////////////////
|
||||
//- Layout
|
||||
|
||||
/* Prepare layout data */
|
||||
// Prepare layout data
|
||||
u64 boxes_count = UI.boxes_count;
|
||||
UI_Box **boxes_pre = 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;
|
||||
pre_index += 1;
|
||||
|
||||
/* Reset layout data */
|
||||
// Reset layout data
|
||||
ZeroStruct(&box->layout);
|
||||
}
|
||||
else
|
||||
@ -998,7 +998,7 @@ void UI_EndFrame(UI_Frame *frame)
|
||||
Assert(post_index == boxes_count);
|
||||
}
|
||||
|
||||
/* Compute independent sizes */
|
||||
// Compute independent sizes
|
||||
for (u64 pre_index = 0; pre_index < boxes_count; ++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))
|
||||
{
|
||||
/* TODO: Distinguish between baseline alignment & visual alignment */
|
||||
// TODO: Distinguish between baseline alignment & visual alignment
|
||||
f32 text_size = 0;
|
||||
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)
|
||||
{
|
||||
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];
|
||||
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];
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
UI_Box *box = boxes_pre[pre_index];
|
||||
for (Axis axis = 0; axis < Axis_CountXY; ++axis)
|
||||
{
|
||||
f32 box_size = box->layout.solved_dims[axis];
|
||||
/* Solve non-floating violations */
|
||||
// Solve non-floating violations
|
||||
{
|
||||
f32 size_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;
|
||||
}
|
||||
/* Solve floating violations */
|
||||
// Solve floating violations
|
||||
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))
|
||||
@ -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)
|
||||
{
|
||||
UI_Box *box = boxes_pre[pre_index];
|
||||
UI_Box *parent = box->parent;
|
||||
|
||||
/* Initialize layout cursor based on alignment */
|
||||
// Initialize layout cursor based on alignment
|
||||
{
|
||||
Axis axis = box->desc.child_layout_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;
|
||||
Vec2 dims_vec = VEC2(dims_arr[0], dims_arr[1]);
|
||||
Vec2 final_pos = Zi;
|
||||
|
||||
/* Floating box position */
|
||||
// Floating box position
|
||||
if (AnyBit(box->desc.flags, UI_BoxFlag_Floating))
|
||||
{
|
||||
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)
|
||||
{
|
||||
f32 layout_cursor = parent->layout.cursor;
|
||||
f32 offset[2] = Zi;
|
||||
/* Compute offset in layout direction */
|
||||
// Compute offset in layout direction
|
||||
{
|
||||
Axis axis = parent->desc.child_layout_axis;
|
||||
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;
|
||||
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];
|
||||
}
|
||||
|
||||
/* Submit position */
|
||||
// Submit position
|
||||
Vec2 floored_final_pos = FloorVec2(final_pos);
|
||||
Vec2 ceiled_dims = CeilVec2(dims_vec);
|
||||
box->rect.p0 = FloorVec2(floored_final_pos);
|
||||
box->rect.p1 = AddVec2(floored_final_pos, ceiled_dims);
|
||||
}
|
||||
|
||||
/* Rounding */
|
||||
// Rounding
|
||||
{
|
||||
UI_Round rounding = box->desc.rounding;
|
||||
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));
|
||||
}
|
||||
|
||||
/* Submit rounding */
|
||||
// Submit rounding
|
||||
box->rounding_tl = final_rounding_tl;
|
||||
box->rounding_tr = final_rounding_tr;
|
||||
box->rounding_br = final_rounding_br;
|
||||
@ -1325,7 +1325,7 @@ void UI_EndFrame(UI_Frame *frame)
|
||||
//////////////////////////////
|
||||
//- Build render data
|
||||
|
||||
/* Build rect instance data */
|
||||
// Build rect instance data
|
||||
for (u64 pre_index = 0; pre_index < boxes_count; ++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))
|
||||
{
|
||||
|
||||
/* Box rect */
|
||||
// Box rect
|
||||
{
|
||||
UI_DRect *rect = PushStruct(frame->rects_arena, UI_DRect);
|
||||
rect->bounds = box->rect;
|
||||
@ -1353,23 +1353,23 @@ void UI_EndFrame(UI_Frame *frame)
|
||||
rect->tex_slice_uv = box->raw_texture_slice_uv;
|
||||
}
|
||||
|
||||
/* Text rects */
|
||||
// Text rects
|
||||
GC_Run raw_run = box->glyph_run;
|
||||
if (AnyBit(box->desc.flags, UI_BoxFlag_DrawText) && raw_run.ready)
|
||||
{
|
||||
f32 max_baseline = DimsFromRng2(box->rect).x;
|
||||
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;
|
||||
GC_RunRect *final_rects = 0;
|
||||
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);
|
||||
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);
|
||||
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)
|
||||
{
|
||||
GC_RunRect rr = elipses_run.rects[rect_idx];
|
||||
@ -1406,7 +1406,7 @@ void UI_EndFrame(UI_Frame *frame)
|
||||
x_alignment = UI_AxisAlignment_Start;
|
||||
}
|
||||
|
||||
/* Compute baseline */
|
||||
// Compute baseline
|
||||
f32 ascent = raw_run.font_ascent;
|
||||
f32 font_descent = raw_run.font_descent;
|
||||
f32 cap = raw_run.font_cap;
|
||||
@ -1452,7 +1452,7 @@ void UI_EndFrame(UI_Frame *frame)
|
||||
}
|
||||
baseline = CeilVec2(baseline);
|
||||
|
||||
/* Push text rects */
|
||||
// Push text rects
|
||||
for (u64 rect_idx = 0; rect_idx < final_rects_count; ++rect_idx)
|
||||
{
|
||||
GC_RunRect rr = final_rects[rect_idx];
|
||||
@ -1476,7 +1476,7 @@ void UI_EndFrame(UI_Frame *frame)
|
||||
//////////////////////////////
|
||||
//- Push data to GPU
|
||||
|
||||
/* Target */
|
||||
// Target
|
||||
G_ResourceHandle draw_target = G_PushTexture2D(
|
||||
frame->gpu_arena, frame->cl,
|
||||
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);
|
||||
|
||||
/* Rects */
|
||||
// Rects
|
||||
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_StructuredBufferRef rects_ro = G_PushStructuredBufferRef(frame->gpu_arena, rects_buff, UI_DRect);
|
||||
|
||||
/* Params */
|
||||
// Params
|
||||
UI_DParams params = Zi;
|
||||
{
|
||||
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(¶ms));
|
||||
G_StructuredBufferRef params_ro = G_PushStructuredBufferRef(frame->gpu_arena, params_buff, UI_DParams);
|
||||
|
||||
/* Constants */
|
||||
// Constants
|
||||
G_SetConstant(frame->cl, UI_ShaderConst_Params, params_ro);
|
||||
|
||||
/* Sync */
|
||||
// Sync
|
||||
G_DumbGlobalMemorySync(frame->cl);
|
||||
|
||||
//////////////////////////////
|
||||
@ -1525,7 +1525,7 @@ void UI_EndFrame(UI_Frame *frame)
|
||||
|
||||
if (rects_count > 0)
|
||||
{
|
||||
/* Render rects */
|
||||
// Render rects
|
||||
G_Rasterize(
|
||||
frame->cl,
|
||||
UI_DRectVS, UI_DRectPS,
|
||||
@ -1535,7 +1535,7 @@ void UI_EndFrame(UI_Frame *frame)
|
||||
G_RasterMode_TriangleList
|
||||
);
|
||||
|
||||
/* Render rect wireframes */
|
||||
// Render rect wireframes
|
||||
if (AnyBit(frame->frame_flags, UI_FrameFlag_Debug))
|
||||
{
|
||||
G_SetConstant(frame->cl, UI_ShaderConst_DebugDraw, 1);
|
||||
|
||||
@ -14,9 +14,9 @@ Struct(UI_Key)
|
||||
|
||||
Enum(UI_SizeKind)
|
||||
{
|
||||
UI_SizeKind_Pixel, /* Exact size */
|
||||
UI_SizeKind_Grow, /* Size as percent of parent size */
|
||||
UI_SizeKind_Shrink, /* Size of children + padding in pixels */
|
||||
UI_SizeKind_Pixel, // Exact size
|
||||
UI_SizeKind_Grow, // Size as percent of parent size
|
||||
UI_SizeKind_Shrink, // Size of children + padding in pixels
|
||||
};
|
||||
|
||||
Struct(UI_Size)
|
||||
@ -31,8 +31,8 @@ Struct(UI_Size)
|
||||
|
||||
Enum(UI_RoundKind)
|
||||
{
|
||||
UI_RoundKind_Pixel, /* Exact radius */
|
||||
UI_RoundKind_Grow, /* Radius as percent of size */
|
||||
UI_RoundKind_Pixel, // Exact radius
|
||||
UI_RoundKind_Grow, // Radius as percent of size
|
||||
};
|
||||
|
||||
Struct(UI_Round)
|
||||
@ -111,13 +111,13 @@ Enum(UI_BoxFlag)
|
||||
X(Text, String) \
|
||||
X(BackgroundTexture, G_Texture2DRef) \
|
||||
X(BackgroundTextureSliceUv, Rng2) \
|
||||
/* -------------------------------------------- */ \
|
||||
/* -------------- Virtual styles -------------- */ \
|
||||
/* -------------------------------------------- */ \
|
||||
/* --------------------------------------------- */ \
|
||||
/* --------------- Virtual styles -------------- */ \
|
||||
/* --------------------------------------------- */ \
|
||||
X(BeginVirtualStyles_, i8) \
|
||||
X(ChildAlignment, UI_Alignment) \
|
||||
X(AxisSize, UI_Size) \
|
||||
/* -------------------------------------------------- */
|
||||
/* ------------------------------------------------- */
|
||||
|
||||
Enum(UI_StyleKind)
|
||||
{
|
||||
@ -131,7 +131,7 @@ Enum(UI_StyleKind)
|
||||
Struct(UI_Style)
|
||||
{
|
||||
UI_StyleKind kind;
|
||||
/* Union of all style fields */
|
||||
// Union of all style fields
|
||||
union
|
||||
{
|
||||
#define X(name, type) type name;
|
||||
@ -145,11 +145,11 @@ Struct(UI_StyleDesc)
|
||||
Axis axis;
|
||||
UI_Style style;
|
||||
|
||||
/* Push */
|
||||
// Push
|
||||
b32 pop_when_used;
|
||||
b32 override;
|
||||
|
||||
/* Pop */
|
||||
// Pop
|
||||
b32 force_pop;
|
||||
b32 use;
|
||||
};
|
||||
@ -186,7 +186,7 @@ Struct(UI_Report)
|
||||
i32 m1_presses;
|
||||
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;
|
||||
};
|
||||
|
||||
@ -339,28 +339,28 @@ Struct(UI_Frame)
|
||||
G_ResourceHandle backbuffer;
|
||||
G_CommandListHandle cl;
|
||||
|
||||
/* Time */
|
||||
// Time
|
||||
i64 tick;
|
||||
i64 time_ns;
|
||||
i64 dt_ns;
|
||||
|
||||
/* Control */
|
||||
// Control
|
||||
Vec2 cursor_pos;
|
||||
UI_Key hovered_box;
|
||||
UI_Key active_box;
|
||||
|
||||
/* Cmds */
|
||||
// Cmds
|
||||
Vec4 swapchain_color;
|
||||
UI_FrameFlag frame_flags;
|
||||
UI_CmdNode *first_cmd_node;
|
||||
UI_CmdNode *last_cmd_node;
|
||||
u64 cmds_count;
|
||||
|
||||
/* Style stack */
|
||||
// Style stack
|
||||
UI_Stack *top_stack;
|
||||
UI_StyleNode *first_free_style_node;
|
||||
|
||||
/* Layout */
|
||||
// Layout
|
||||
UI_Box **boxes_pre;
|
||||
UI_Box **boxes_post;
|
||||
};
|
||||
|
||||
@ -42,7 +42,7 @@ PixelShader(UI_DRectPS, UI_DRectPSOutput, UI_DRectPSInput input)
|
||||
Vec2 p0 = rect.bounds.p0;
|
||||
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 tl_radius = rect.tl_rounding;
|
||||
@ -60,7 +60,7 @@ PixelShader(UI_DRectPS, UI_DRectPSOutput, UI_DRectPSInput input)
|
||||
}
|
||||
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_dist = 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;
|
||||
{
|
||||
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;
|
||||
final_color *= input.tint_lin;
|
||||
|
||||
/* Debug color */
|
||||
// Debug color
|
||||
if (UI_ShaderConst_DebugDraw)
|
||||
{
|
||||
final_color = rect.debug_lin;
|
||||
|
||||
@ -7,7 +7,9 @@ void WND_Bootstrap(void)
|
||||
{
|
||||
WND_W32_SharedState *g = &WND_W32_shared_state;
|
||||
|
||||
//- Initialize btn table
|
||||
//////////////////////////////
|
||||
//- Init btn table
|
||||
|
||||
{
|
||||
ZeroFixedArray(g->vk_to_button);
|
||||
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;
|
||||
}
|
||||
|
||||
//- Initialize cursors
|
||||
//////////////////////////////
|
||||
//- Create cursors
|
||||
|
||||
{
|
||||
HCURSOR arrow = LoadCursor(0, IDC_ARROW);
|
||||
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);
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- Create window class
|
||||
|
||||
{
|
||||
HMODULE instance = GetModuleHandle(0);
|
||||
|
||||
/* Register the window class */
|
||||
// Register the window class
|
||||
WNDCLASSEXW *wc = &g->window_class;
|
||||
wc->cbSize = sizeof(WNDCLASSEX);
|
||||
wc->lpszClassName = WND_W32_WindowClassName;
|
||||
@ -83,7 +89,7 @@ void WND_Bootstrap(void)
|
||||
wc->lpfnWndProc = WND_W32_WindowProc;
|
||||
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;
|
||||
GetModuleFileNameW(instance, path, countof(path));
|
||||
ExtractIconExW(path, 0, &wc->hIcon, &wc->hIconSm, 1);
|
||||
@ -94,15 +100,19 @@ void WND_Bootstrap(void)
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- Register raw mouse input
|
||||
|
||||
{
|
||||
RAWINPUTDEVICE rid = Zi;
|
||||
rid.usUsagePage = 0x01; /* HID_USAGE_PAGE_GENERIC */
|
||||
rid.usUsage = 0x02; /* HID_USAGE_GENERIC_MOUSE */
|
||||
rid.usUsagePage = 0x01; // HID_USAGE_PAGE_GENERIC
|
||||
rid.usUsage = 0x02; // HID_USAGE_GENERIC_MOUSE
|
||||
RegisterRawInputDevices(&rid, 1, sizeof(rid));
|
||||
}
|
||||
|
||||
//- Dispatch message processor
|
||||
//////////////////////////////
|
||||
//- Dispatch msg processor
|
||||
|
||||
DispatchWave(Lit("Win32 msg loop"), 1, WND_W32_ProcessMessagesForever, 0);
|
||||
}
|
||||
|
||||
@ -117,7 +127,7 @@ WND_W32_Window *WND_W32_WindowFromHandle(WND_Handle handle)
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ 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)
|
||||
{
|
||||
WND_W32_SharedState *g = &WND_W32_shared_state;
|
||||
@ -126,16 +136,18 @@ void WND_W32_ProcessMessagesForever(WaveLaneCtx *lane)
|
||||
|
||||
//- Initialize hwnd
|
||||
{
|
||||
/*
|
||||
* From martins (https://gist.github.com/mmozeiko/5e727f845db182d468a34d524508ad5f#file-win32_d3d11-c-L66-L70):
|
||||
* WS_EX_NOREDIRECTIONBITMAP flag here is needed to fix ugly bug with Windows 10
|
||||
* 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
|
||||
*/
|
||||
//
|
||||
// From martins -
|
||||
// https://gist.github.com/mmozeiko/5e727f845db182d468a34d524508ad5f#file-win32_d3d11-c-L66-L70
|
||||
//
|
||||
// WS_EX_NOREDIRECTIONBITMAP flag here is needed to fix ugly bug with Windows 10
|
||||
// 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;
|
||||
|
||||
/* TODO: Check for hwnd success */
|
||||
// TODO: Check for hwnd success
|
||||
window->hwnd = CreateWindowExW(
|
||||
exstyle,
|
||||
g->window_class.lpszClassName,
|
||||
@ -151,12 +163,12 @@ void WND_W32_ProcessMessagesForever(WaveLaneCtx *lane)
|
||||
0
|
||||
);
|
||||
|
||||
/* Dark mode */
|
||||
// Dark mode
|
||||
BOOL dark_mode = 1;
|
||||
DwmSetWindowAttribute(window->hwnd, DWMWA_USE_IMMERSIVE_DARK_MODE, (LPCVOID)&dark_mode, sizeof(dark_mode));
|
||||
|
||||
/* Set window as userdata */
|
||||
/* FIXME: Necessary? */
|
||||
// Set window as userdata
|
||||
// FIXME: Necessary?
|
||||
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);
|
||||
}
|
||||
|
||||
@ -301,7 +313,7 @@ LRESULT CALLBACK WND_W32_WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM l
|
||||
{
|
||||
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;
|
||||
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_ButtonUp, .button = btn });
|
||||
}
|
||||
@ -393,7 +405,7 @@ LRESULT CALLBACK WND_W32_WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM l
|
||||
{
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
{
|
||||
/* Read raw input buffer */
|
||||
// Read raw input buffer
|
||||
UINT buff_size;
|
||||
GetRawInputData((HRAWINPUT)lparam, RID_INPUT, 0, &buff_size, sizeof(RAWINPUTHEADER));
|
||||
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;
|
||||
result.window.v = (u64)window;
|
||||
|
||||
/* Grab monitor info */
|
||||
// Grab monitor info
|
||||
RECT monitor_rect = Zi;
|
||||
{
|
||||
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.y = MaxI32(result.monitor_size.y, 1);
|
||||
|
||||
/* Client rect */
|
||||
// Client rect
|
||||
RECT client_rect = Zi;
|
||||
GetClientRect(hwnd, (LPRECT)&client_rect);
|
||||
|
||||
/* Screen rect */
|
||||
// Screen rect
|
||||
RECT screen_rect = client_rect;
|
||||
ClientToScreen(hwnd, (LPPOINT)&screen_rect.left);
|
||||
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.y = MaxI32(result.draw_size.y, 1);
|
||||
|
||||
/* Prepare backbuffer */
|
||||
// Prepare backbuffer
|
||||
Vec2I32 backbuffer_size = Zi;
|
||||
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);
|
||||
|
||||
/* Reset per-frame data */
|
||||
// Reset per-frame data
|
||||
if (!window->frame_arena)
|
||||
{
|
||||
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->last_cmd = 0;
|
||||
|
||||
/* Pop user input */
|
||||
// Pop user input
|
||||
{
|
||||
LockTicketMutex(&window->w2u_tm);
|
||||
{
|
||||
@ -511,7 +523,7 @@ WND_Frame WND_BeginFrame(G_Format backbuffer_format, WND_BackbufferSizeMode back
|
||||
UnlockTicketMutex(&window->w2u_tm);
|
||||
}
|
||||
|
||||
/* Minimized / maximized / fullscreen */
|
||||
// Minimized / maximized / fullscreen
|
||||
DWORD style = (DWORD)GetWindowLongPtr(hwnd, GWL_STYLE);
|
||||
DWORD ex_style = (DWORD)GetWindowLongPtr(hwnd, GWL_EXSTYLE);
|
||||
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.has_focus = GetForegroundWindow() == hwnd;
|
||||
|
||||
/* Generate restore data */
|
||||
// Generate restore data
|
||||
{
|
||||
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);
|
||||
HWND hwnd = window->hwnd;
|
||||
|
||||
/* Process cmds */
|
||||
// Process cmds
|
||||
b32 was_restored = 0;
|
||||
HCURSOR desired_cursor = (HCURSOR)Atomic64Fetch(&window->desired_cursor);
|
||||
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;
|
||||
if (cmd.v)
|
||||
{
|
||||
/* Enter fullscreen */
|
||||
// Enter fullscreen
|
||||
{
|
||||
MONITORINFO monitor_info = { .cbSize = sizeof(monitor_info) };
|
||||
GetMonitorInfo(MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY), &monitor_info);
|
||||
@ -624,7 +636,7 @@ void WND_EndFrame(WND_Frame frame, i32 vsync)
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Exit fullscreen */
|
||||
// Exit fullscreen
|
||||
new_rect = window->fullscreen_restore_rect;
|
||||
new_style &= ~WS_POPUP;
|
||||
new_style |= WS_OVERLAPPEDWINDOW;
|
||||
@ -652,7 +664,7 @@ void WND_EndFrame(WND_Frame frame, i32 vsync)
|
||||
//- Restore
|
||||
case WND_CmdKind_Restore:
|
||||
{
|
||||
/* FIXME: Cap bounds */
|
||||
// FIXME: Cap bounds
|
||||
String restore_str = cmd.restore;
|
||||
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)
|
||||
{
|
||||
ShowWindow(hwnd, SW_SHOW);
|
||||
@ -709,7 +721,7 @@ void WND_EndFrame(WND_Frame frame, i32 vsync)
|
||||
BringWindowToTop(hwnd);
|
||||
}
|
||||
|
||||
/* Set cursor */
|
||||
// Set cursor
|
||||
{
|
||||
HCURSOR old_desired_cursor = (HCURSOR)Atomic64FetchSet(&window->desired_cursor, (i64)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);
|
||||
|
||||
++window->frame_gen;
|
||||
|
||||
@ -8,11 +8,11 @@ Struct(WND_W32_Window)
|
||||
G_ResourceHandle backbuffer;
|
||||
Atomic32 is_ready;
|
||||
|
||||
/* Window proc state */
|
||||
// Window proc state
|
||||
u16 previous_utf16_high_surrogate;
|
||||
HCURSOR active_cursor;
|
||||
|
||||
/* User state */
|
||||
// User state
|
||||
Arena *frame_arena;
|
||||
struct WND_W32_CmdNode *first_cmd;
|
||||
struct WND_W32_CmdNode *last_cmd;
|
||||
@ -21,11 +21,11 @@ Struct(WND_W32_Window)
|
||||
b32 is_fullscreen;
|
||||
RECT fullscreen_restore_rect;
|
||||
|
||||
/* Window proc -> User */
|
||||
// Window proc -> User
|
||||
TicketMutex w2u_tm;
|
||||
Arena *w2u_events_arena;
|
||||
|
||||
/* User -> Window proc */
|
||||
// User -> Window proc
|
||||
Atomic64 desired_cursor;
|
||||
};
|
||||
|
||||
@ -75,7 +75,7 @@ Struct(WND_W32_SharedState)
|
||||
|
||||
WNDCLASSEXW window_class;
|
||||
|
||||
WND_W32_Window window; /* Single-window for now */
|
||||
WND_W32_Window window; // Single-window for now
|
||||
} extern WND_W32_shared_state;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
Loading…
Reference in New Issue
Block a user