diff --git a/Code/Deprecated/Dqn.natvis b/Code/Deprecated/Dqn.natvis
deleted file mode 100644
index d5a0801..0000000
--- a/Code/Deprecated/Dqn.natvis
+++ /dev/null
@@ -1,38 +0,0 @@
-
-
-
- {{len={len}/{max}}}
-
- - len
- - max
-
- len
- data
-
-
-
-
-
- {{used={head-tail}/{size} prev_block={prev_block}}}
-
-
-
- {len={len} data={data,[len]}}
- data,s
-
-
-
- {len={len} data={data,[len]}}
- data,s
-
-
-
- {{len={len} {str,s}}}
- str,s
-
-
-
- {{len={len}/{max} {str,s}}}
- str,s
-
-
diff --git a/Code/Deprecated/DqnFixedString.cpp b/Code/Deprecated/DqnFixedString.cpp
deleted file mode 100644
index 2bb6371..0000000
--- a/Code/Deprecated/DqnFixedString.cpp
+++ /dev/null
@@ -1,77 +0,0 @@
-void DqnFixedString_Test()
-{
- LOG_HEADER();
- {
- DqnFixedString<512> str = DQN_BUFFER_STR_LIT("hello world");
- DQN_ASSERT(DqnStr_Cmp(str.str, "hello world") == 0);
-
- Log(Status::Ok, "Copy constructor DqnSlice");
- }
-
- {
- DqnFixedString<512> zero = {};
- DqnFixedString<512> str = DQN_BUFFER_STR_LIT("hello world");
- str = zero;
- DQN_ASSERT(str.len == 0 && str.str[0] == 0);
-
- DqnSlice helloSlice = DQN_BUFFER_STR_LIT("hello");
- str = helloSlice;
- DQN_ASSERT(DqnStr_Cmp(str.str, "hello") == 0);
-
- Log(Status::Ok, "Copy constructor (DqnFixedString<>)");
- }
-
- {
- DqnFixedString<512> str = DQN_BUFFER_STR_LIT("hello world");
- DQN_ASSERT(str.Sprintf("hello %s", "sailor"));
- DQN_ASSERTM(DqnStr_Cmp(str.str, "hello sailor") == 0, "Result: %s", str.str);
-
- Log(Status::Ok, "Sprintf");
- }
-
- {
- {
- DqnFixedString<512> str = DQN_BUFFER_STR_LIT("hello world");
- DQN_ASSERT(str.Sprintf("hello %s", "sailor"));
- str += DQN_BUFFER_STR_LIT(".end");
- DQN_ASSERTM(DqnStr_Cmp(str.str, "hello sailor.end") == 0, "Result: %s", str.str);
- }
-
- {
- DqnFixedString<512> str = DQN_BUFFER_STR_LIT("hello world");
- DQN_ASSERT(str.Sprintf("hello %s", "sailor"));
- DQN_ASSERT(str.SprintfAppend(" %d, %d", 100, 200));
- DQN_ASSERT(DqnStr_Cmp(str.str, "hello sailor 100, 200") == 0);
- }
-
- Log(Status::Ok, "Concatenation, operator +=, SprintfAppend");
- }
-
- {
- DqnFixedString<512> str;
- str = "hello big world";
- DQN_ASSERT(DqnStr_Cmp(str.str, "hello big world") == 0);
- str = DqnFixedString<512>("goodbye", DQN_CHAR_COUNT("goodbye"));
- DQN_ASSERT(DqnStr_Cmp(str.str, "goodbye") == 0);
-
- Log(Status::Ok, "Copy constructor (char const *str, int len)");
- }
-
- {
- DqnFixedString<512> str = DQN_BUFFER_STR_LIT("hello world");
- DQN_ASSERT(str.Sprintf("hello %s", "sailor"));
- str = str + " end" + DQN_BUFFER_STR_LIT(" of");
- DQN_ASSERT(DqnStr_Cmp(str.str, "hello sailor end of") == 0);
-
- Log(Status::Ok, "Operator +");
- }
-
- {
- DqnFixedString<512> str = "localhost";
- str.SprintfAppend(":%d", 16832);
- str += "/json_rpc";
- DQN_ASSERT(str.len == 24 && DqnStr_Cmp("localhost:16832/json_rpc", str.str) == 0);
-
- Log(Status::Ok, "Copy constructor, sprintf, operator +=");
- }
-}
diff --git a/Code/Deprecated/DqnJson.cpp b/Code/Deprecated/DqnJson.cpp
deleted file mode 100644
index 65cb2eb..0000000
--- a/Code/Deprecated/DqnJson.cpp
+++ /dev/null
@@ -1,119 +0,0 @@
-void DqnJson_Test()
-{
- LOG_HEADER();
- char const json[] =
- R"FOO(
- {
- "result": {
- "cumulative_difficulty": 282912831023,
- "difficulty": 18293,
- "name": "Block",
- "array_of_objects": [{
- "hash": "83abdc3f",
- "time": 102981029381,
- }, {
- "hash": "12acf73d",
- "time": 123761239789,
- }],
- "time": 3498573485,
- "embed_object": {
- "proof": "axcbde",
- "signature": "l9382kjabmznmx129aslzejs"
- }
- "bits": [1, 0, 1, 1, 0, 1, 0],
- "hex": ["AF", "BE", "0C", "FF"],
- "extra": [123],
- "serialise": [],
- },
- }
- )FOO";
-
- DqnJson result = DqnJson_Get(DqnSlice(json, DQN_ARRAY_COUNT(json)), DQN_BUFFER_STR_LIT("result"));
- DqnJson cum_difficulty = DqnJson_Get(result, DQN_BUFFER_STR_LIT("cumulative_difficulty"));
- DqnJson difficulty = DqnJson_Get(result, DQN_BUFFER_STR_LIT("difficulty"));
- DqnJson name = DqnJson_Get(result, DQN_BUFFER_STR_LIT("name"));
- DqnJson array_of_objects = DqnJson_Get(result, DQN_BUFFER_STR_LIT("array_of_objects"));
- DqnJson time = DqnJson_Get(result, DQN_BUFFER_STR_LIT("time"));
- DqnJson embed_object = DqnJson_Get(result, DQN_BUFFER_STR_LIT("embed_object"));
- DqnJson bits = DqnJson_Get(result, DQN_BUFFER_STR_LIT("bits"));
- DqnJson hex = DqnJson_Get(result, DQN_BUFFER_STR_LIT("hex"));
- DqnJson extra = DqnJson_Get(result, DQN_BUFFER_STR_LIT("extra"));
- DqnJson serialise = DqnJson_Get(result, DQN_BUFFER_STR_LIT("serialise"));
-
- DQN_ASSERT(DQN_BUFFER_STRCMP(cum_difficulty.value, DQN_BUFFER_STR_LIT("282912831023"), Dqn::IgnoreCase::No));
- DQN_ASSERT(DQN_BUFFER_STRCMP(difficulty.value, DQN_BUFFER_STR_LIT("18293"), Dqn::IgnoreCase::No));
- DQN_ASSERT(DQN_BUFFER_STRCMP(name.value, DQN_BUFFER_STR_LIT("\"Block\""), Dqn::IgnoreCase::No));
-
- {
- DQN_ASSERT(array_of_objects.IsArray() && array_of_objects.num_entries == 2);
- isize count = 0;
- while(DqnJson it = DqnJson_GetNextArrayItem(&array_of_objects))
- {
- DqnJson hash = DqnJson_Get(it, DQN_BUFFER_STR_LIT("hash"));
- DqnJson time2 = DqnJson_Get(it, DQN_BUFFER_STR_LIT("time"));
- if (count == 0)
- {
- DQN_ASSERT(DQN_BUFFER_STRCMP(hash.value, DQN_BUFFER_STR_LIT("\"83abdc3f\""), Dqn::IgnoreCase::No));
- DQN_ASSERT(DQN_BUFFER_STRCMP(time2.value, DQN_BUFFER_STR_LIT("102981029381"), Dqn::IgnoreCase::No));
- }
- else
- {
- DQN_ASSERT(DQN_BUFFER_STRCMP(hash.value, DQN_BUFFER_STR_LIT("\"12acf73d\""), Dqn::IgnoreCase::No));
- DQN_ASSERT(DQN_BUFFER_STRCMP(time2.value, DQN_BUFFER_STR_LIT("123761239789"), Dqn::IgnoreCase::No));
- }
- ++count;
- }
-
- }
-
- {
- DqnJson proof = DqnJson_Get(embed_object, DQN_BUFFER_STR_LIT("proof"));
- DqnJson signature = DqnJson_Get(embed_object, DQN_BUFFER_STR_LIT("signature"));
- DQN_ASSERT(DQN_BUFFER_STRCMP(proof.value, DQN_BUFFER_STR_LIT("\"axcbde\""), Dqn::IgnoreCase::No));
- DQN_ASSERT(DQN_BUFFER_STRCMP(signature.value, DQN_BUFFER_STR_LIT("\"l9382kjabmznmx129aslzejs\""), Dqn::IgnoreCase::No));
- }
-
- DQN_ASSERT(DQN_BUFFER_STRCMP(time.value, DQN_BUFFER_STR_LIT("3498573485"), Dqn::IgnoreCase::No));
-
- {
- DQN_ASSERT(bits.IsArray() && bits.num_entries == 7);
- DqnJson bits_array[7];
- isize bitsIndex = 0;
-
- while(DqnJson it = DqnJson_GetNextArrayItem(&bits))
- bits_array[bitsIndex++] = it;
-
- DQN_ASSERT(bitsIndex == DQN_ARRAY_COUNT(bits_array));
- DQN_ASSERT(DQN_BUFFER_STRCMP(bits_array[0].value, DQN_BUFFER_STR_LIT("1"), Dqn::IgnoreCase::No));
- DQN_ASSERT(DQN_BUFFER_STRCMP(bits_array[1].value, DQN_BUFFER_STR_LIT("0"), Dqn::IgnoreCase::No));
- DQN_ASSERT(DQN_BUFFER_STRCMP(bits_array[2].value, DQN_BUFFER_STR_LIT("1"), Dqn::IgnoreCase::No));
- DQN_ASSERT(DQN_BUFFER_STRCMP(bits_array[3].value, DQN_BUFFER_STR_LIT("1"), Dqn::IgnoreCase::No));
- DQN_ASSERT(DQN_BUFFER_STRCMP(bits_array[4].value, DQN_BUFFER_STR_LIT("0"), Dqn::IgnoreCase::No));
- DQN_ASSERT(DQN_BUFFER_STRCMP(bits_array[5].value, DQN_BUFFER_STR_LIT("1"), Dqn::IgnoreCase::No));
- DQN_ASSERT(DQN_BUFFER_STRCMP(bits_array[6].value, DQN_BUFFER_STR_LIT("0"), Dqn::IgnoreCase::No));
- }
-
- {
- DQN_ASSERT(hex.IsArray() && hex.num_entries == 4);
- DqnJson hex_array[4];
- isize hex_index = 0;
-
- while(DqnJson it = DqnJson_GetNextArrayItem(&hex))
- hex_array[hex_index++] = it;
-
- DQN_ASSERT(hex_index == DQN_ARRAY_COUNT(hex_array));
- DQN_ASSERT(DQN_BUFFER_STRCMP(hex_array[0].value, DQN_BUFFER_STR_LIT("\"AF\""), Dqn::IgnoreCase::No));
- DQN_ASSERT(DQN_BUFFER_STRCMP(hex_array[1].value, DQN_BUFFER_STR_LIT("\"BE\""), Dqn::IgnoreCase::No));
- DQN_ASSERT(DQN_BUFFER_STRCMP(hex_array[2].value, DQN_BUFFER_STR_LIT("\"0C\""), Dqn::IgnoreCase::No));
- DQN_ASSERT(DQN_BUFFER_STRCMP(hex_array[3].value, DQN_BUFFER_STR_LIT("\"FF\""), Dqn::IgnoreCase::No));
- }
-
- {
- DQN_ASSERT(extra.IsArray() && extra.num_entries == 1);
- while(DqnJson it = DqnJson_GetNextArrayItem(&extra))
- {
- DQN_ASSERT(DQN_BUFFER_STRCMP(it.value, DQN_BUFFER_STR_LIT("123"), Dqn::IgnoreCase::No));
- }
- }
- Log(Status::Ok, "DqnJson sample structure parsed");
-}
diff --git a/Code/Deprecated/DqnMemStack.cpp b/Code/Deprecated/DqnMemStack.cpp
deleted file mode 100644
index 358d79d..0000000
--- a/Code/Deprecated/DqnMemStack.cpp
+++ /dev/null
@@ -1,520 +0,0 @@
-FILE_SCOPE void DqnMemStack_Test()
-{
- LOG_HEADER();
-
- // Check Alignment
- if (1)
- {
- auto stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroMem::Yes, 0, DqnMemTracker::Flag::Simple);
-
- i32 const ALIGN64 = 64;
- i32 const ALIGN16 = 16;
- i32 const ALIGN4 = 4;
- DqnMemStack::PushType push_type = DqnMemStack::PushType::Head;
- if (1)
- {
- u8 *result1 = (u8 *)stack.Push_(2, push_type, ALIGN4);
- u8 *result2 = (u8 *)DQN_ALIGN_POW_N(result1, ALIGN4);
- DQN_ASSERT(result1 == result2);
- stack.Pop(result1);
- DQN_ASSERT(stack.block->head == stack.block->memory);
- }
-
- if (1)
- {
- u8 *result1 = (u8 *)stack.Push_(120, push_type, ALIGN16);
- u8 *result2 = (u8 *)DQN_ALIGN_POW_N(result1, ALIGN16);
- DQN_ASSERT(result1 == result2);
- stack.Pop(result1);
- DQN_ASSERT(stack.block->head == stack.block->memory);
- }
-
- if (1)
- {
- u8 *result1 = (u8 *)stack.Push_(12, push_type, ALIGN64);
- u8 *result2 = (u8 *)DQN_ALIGN_POW_N(result1, ALIGN64);
- DQN_ASSERT(result1 == result2);
- stack.Pop(result1);
- DQN_ASSERT(stack.block->head == stack.block->memory);
- }
-
- stack.Free();
- Log(Status::Ok, "Check allocated alignment to 4, 16, 64");
- }
-
- // Check Non-Expandable
- if (1)
- {
- auto stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroMem::Yes, DqnMemStack::Flag::NonExpandable);
- auto *result1 = stack.Push_(DQN_MEGABYTE(2));
- DQN_ASSERT(result1 == nullptr);
- DQN_ASSERT(stack.block->prev_block == nullptr);
-
- stack.Free();
- Log(Status::Ok, "Check non-expandable flag prevents expansion.");
- }
-
- // Check Expansion
- if (1)
- {
- auto stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroMem::Yes);
- auto *old_block = stack.block;
- DQN_ASSERT(old_block);
- DQN_ASSERT(old_block->size == DQN_MEGABYTE(1));
- DQN_ASSERT(old_block->head == old_block->head);
- DQN_ASSERT(old_block->tail == old_block->tail);
- DQN_ASSERT(old_block->prev_block == nullptr);
-
- auto *result1 = stack.Push_(DQN_MEGABYTE(2));
- DQN_ASSERT(result1);
- DQN_ASSERT(stack.block->prev_block == old_block);
- DQN_ASSERT(stack.block != old_block);
-
- Log(Status::Ok, "Check memory stack allocates additional memory blocks.");
- stack.Free();
- }
-
- // Temporary Regions
- if (1)
- {
- // Check temporary regions
- if (1)
- {
- auto stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroMem::Yes, 0, DqnMemTracker::Flag::Simple);
-
- DqnMemStack::Block *block_to_return_to = stack.block;
- auto head_before = block_to_return_to->head;
- auto tail_before = block_to_return_to->tail;
- if (1)
- {
- auto mem_guard1 = stack.MemRegionScope();
- auto *result2 = stack.Push_(100);
- auto *result3 = stack.Push_(100);
- auto *result4 = stack.Push_(100);
- DQN_ASSERT(result2 && result3 && result4);
- DQN_ASSERT(stack.block->head != head_before);
- DQN_ASSERT(stack.block->tail == tail_before);
- DQN_ASSERT(stack.block->memory == block_to_return_to->memory);
-
- // Force allocation of new block
- auto *result5 = stack.Push_(DQN_MEGABYTE(5));
- DQN_ASSERT(result5);
- DQN_ASSERT(stack.block != block_to_return_to);
- DQN_ASSERT(stack.mem_region_count == 1);
- }
-
- DQN_ASSERT(stack.block == block_to_return_to);
- DQN_ASSERT(stack.block->head == head_before);
- DQN_ASSERT(stack.block->tail == tail_before);
-
- stack.Free();
- }
-
- // Check temporary regions keep state
- if (1)
- {
- auto stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroMem::Yes, 0, DqnMemTracker::Flag::Simple);
- DqnMemStack::Block *block_to_return_to = stack.block;
- auto head_before = block_to_return_to->head;
- auto tail_before = block_to_return_to->tail;
- if (1)
- {
- auto mem_guard1 = stack.MemRegionScope();
- auto *result2 = stack.Push_(100);
- auto *result3 = stack.Push_(100);
- auto *result4 = stack.Push_(100);
- DQN_ASSERT(result2 && result3 && result4);
- DQN_ASSERT(stack.block->head != head_before);
- DQN_ASSERT(stack.block->tail == tail_before);
- DQN_ASSERT(stack.block->memory == block_to_return_to->memory);
-
- // Force allocation of new block
- auto *result5 = stack.Push_(DQN_MEGABYTE(5));
- DQN_ASSERT(result5);
- DQN_ASSERT(stack.block != block_to_return_to);
- DQN_ASSERT(stack.mem_region_count == 1);
- stack.MemRegionSave(&mem_guard1);
- }
-
- DQN_ASSERT(stack.block != block_to_return_to);
- DQN_ASSERT(stack.block->prev_block == block_to_return_to);
- DQN_ASSERT(stack.mem_region_count == 0);
-
- stack.Free();
- }
-
- // Check temporary regions with tail and head pushes
- if (1)
- {
- auto stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroMem::Yes, 0, DqnMemTracker::Flag::Simple);
-
- auto *pop1 = stack.Push_(222);
- auto *pop2 = stack.Push_(333, DqnMemStack::PushType::Tail);
-
- DqnMemStack::Block *block_to_return_to = stack.block;
- auto head_before = block_to_return_to->head;
- auto tail_before = block_to_return_to->tail;
- if (1)
- {
- auto mem_guard1 = stack.MemRegionScope();
- auto *result2 = stack.Push_(100);
- auto *result3 = stack.Push_(100, DqnMemStack::PushType::Tail);
- auto *result4 = stack.Push_(100);
- auto *result5 = stack.Push_(100, DqnMemStack::PushType::Tail);
- DQN_ASSERT(result2 && result3 && result4 && result5);
- DQN_ASSERT(result3 > result5);
- DQN_ASSERT(result2 < result4);
- DQN_ASSERT(stack.block->head > head_before && stack.block->head < stack.block->tail);
- DQN_ASSERT(stack.block->tail >= stack.block->head && stack.block->tail < (stack.block->memory + stack.block->size));
- DQN_ASSERT(stack.block->memory == block_to_return_to->memory);
-
- // Force allocation of new block
- auto *result6 = stack.Push_(DQN_MEGABYTE(5));
- DQN_ASSERT(result6);
- DQN_ASSERT(stack.block != block_to_return_to);
- DQN_ASSERT(stack.mem_region_count == 1);
- }
-
- DQN_ASSERT(stack.block == block_to_return_to);
- DQN_ASSERT(stack.block->head == head_before);
- DQN_ASSERT(stack.block->tail == tail_before);
-
- stack.Pop(pop1);
- stack.Pop(pop2);
- DQN_ASSERT(stack.block->head == stack.block->memory);
- DQN_ASSERT(stack.block->tail == stack.block->memory + stack.block->size);
-
- stack.Free();
- }
- Log(Status::Ok, "Temporary regions revert state and save state");
- }
-
- // Check Fixed Mem Init
- if (1)
- {
- // Check success
- if (1)
- {
- isize const buf_size = sizeof(DqnMemStack::Block) * 5;
- char buf[buf_size] = {};
- auto stack = DqnMemStack(&buf, buf_size, Dqn::ZeroMem::No);
-
- DQN_ASSERT(stack.block);
- DQN_ASSERT(stack.block->prev_block == false);
- DQN_ASSERT(stack.mem_region_count == 0);
- DQN_ASSERT(stack.flags == DqnMemStack::Flag::NonExpandable);
-
- auto *result1 = stack.Push_(32);
- DQN_ASSERT(result1);
- stack.Pop(result1);
-
- auto *result2 = stack.Push_(buf_size * 2);
- DQN_ASSERT(result2 == nullptr);
- DQN_ASSERT(stack.block);
- DQN_ASSERT(stack.block->prev_block == false);
- DQN_ASSERT(stack.mem_region_count == 0);
- DQN_ASSERT(stack.flags == DqnMemStack::Flag::NonExpandable);
-
- stack.Free();
- }
-
- Log(Status::Ok, "Checked fixed mem initialisation");
- }
-
- // Check Freeing Blocks
- if (1)
- {
- usize size = 32;
- usize additional_size = DqnMemStack::MINIMUM_BLOCK_SIZE;
-
- auto stack = DqnMemStack(size, Dqn::ZeroMem::Yes, 0);
- auto *block1 = stack.block;
-
- size += additional_size;
- auto *result1 = stack.Push_(size);
- auto *block2 = stack.block;
-
- size += additional_size;
- auto *result2 = stack.Push_(size);
- auto *block3 = stack.block;
-
- size += additional_size;
- auto *result3 = stack.Push_(size);
- auto *block4 = stack.block;
-
- size += additional_size;
- auto *result4 = stack.Push_(size);
- auto *block5 = stack.block;
-
- DQN_ASSERT(result1 && result2 && result3 && result4);
- DQN_ASSERT(block1 && block2 && block3 && block4 && block5);
- DQN_ASSERT(block5->prev_block == block4);
- DQN_ASSERT(block4->prev_block == block3);
- DQN_ASSERT(block3->prev_block == block2);
- DQN_ASSERT(block2->prev_block == block1);
- DQN_ASSERT(block1->prev_block == nullptr);
-
- DQN_ASSERT(stack.FreeBlock(block4));
- DQN_ASSERT(stack.block == block5);
- DQN_ASSERT(block5->prev_block == block3);
- DQN_ASSERT(block3->prev_block == block2);
- DQN_ASSERT(block2->prev_block == block1);
- DQN_ASSERT(block1->prev_block == nullptr);
-
- DQN_ASSERT(stack.FreeBlock(block5));
- DQN_ASSERT(stack.block == block3);
- DQN_ASSERT(block3->prev_block == block2);
- DQN_ASSERT(block2->prev_block == block1);
- DQN_ASSERT(block1->prev_block == nullptr);
-
- stack.Free();
- DQN_ASSERT(stack.block == nullptr);
- Log(Status::Ok, "Check freeing arbitrary blocks and freeing");
- }
-
- // Check bounds guard places magic values
- if (1)
- {
- auto stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroMem::Yes, 0, DqnMemTracker::Flag::Simple);
- char *result = static_cast(stack.Push_(64));
-
- // TODO(doyle): check head and tail are adjacent to the bounds of the allocation
- u32 *head = stack.tracker.PtrToHeadGuard(result);
- u32 *tail = stack.tracker.PtrToTailGuard(result);
- DQN_ASSERT(*head == DqnMemTracker::HEAD_GUARD_VALUE);
- DQN_ASSERT(*tail == DqnMemTracker::TAIL_GUARD_VALUE);
-
- stack.Free();
- Log(Status::Ok, "Bounds guards are placed adjacent and have magic values.");
- }
-
- if (1)
- {
- // Push_ to tail and head
- if (1)
- {
- DqnMemStack stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroMem::Yes, 0, DqnMemTracker::Flag::Simple);
-
- auto *result1 = stack.Push_(100);
- auto *result2 = stack.Push_(100, DqnMemStack::PushType::Tail);
- auto *head_before = stack.block->head;
- auto *tail_before = stack.block->tail;
- DQN_ASSERT(result2 && result1);
- DQN_ASSERT(result2 != result1 && result1 < result2);
-
- stack.Pop(result2);
- DQN_ASSERT(head_before == stack.block->head)
- DQN_ASSERT(tail_before != stack.block->tail)
-
- stack.Pop(result1);
- DQN_ASSERT(stack.block->prev_block == false);
- DQN_ASSERT(stack.block->head == stack.block->memory);
- DQN_ASSERT(stack.block->tail == stack.block->memory + stack.block->size);
- stack.Free();
- Log(Status::Ok, "Push_, pop to tail and head.");
- }
-
- // Expansion with tail
- if (1)
- {
- // Push_ too much to tail causes expansion
- if (1)
- {
- DqnMemStack stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroMem::Yes, 0, DqnMemTracker::Flag::Simple);
-
- auto *result1 = stack.Push_(100);
- DQN_ASSERT(stack.block->prev_block == nullptr);
- DQN_ASSERT(stack.block->head > stack.block->memory && stack.block->head < stack.block->tail);
- DQN_ASSERT(stack.block->tail == stack.block->memory + stack.block->size);
- auto *block_before = stack.block;
-
- auto *result2 = stack.Push_(DQN_MEGABYTE(1), DqnMemStack::PushType::Tail);
- DQN_ASSERT(result2 && result1);
- DQN_ASSERT(result2 != result1);
- DQN_ASSERT(stack.block->prev_block == block_before);
- DQN_ASSERT(stack.block != block_before);
-
- DQN_ASSERT(stack.block->head == stack.block->memory);
- DQN_ASSERT(stack.block->tail < stack.block->memory + stack.block->size &&
- stack.block->tail >= stack.block->head);
-
- stack.Pop(result2);
- DQN_ASSERT(block_before == stack.block);
-
- stack.Pop(result1);
- DQN_ASSERT(block_before == stack.block);
-
- stack.Free();
- }
-
- // Push_ too much to tail fails to expand when non expandable
- if (1)
- {
- DqnMemStack stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroMem::Yes, DqnMemStack::Flag::NonExpandable);
-
- auto *result1 = stack.Push_(100);
- DQN_ASSERT(stack.block->prev_block == nullptr);
- DQN_ASSERT(stack.block->head != stack.block->memory);
- DQN_ASSERT(stack.block->tail == stack.block->memory + stack.block->size);
- auto *block_before = stack.block;
-
- auto *result2 = stack.Push_(DQN_MEGABYTE(1), DqnMemStack::PushType::Tail);
- DQN_ASSERT(result2 == nullptr);
- DQN_ASSERT(stack.block->prev_block == nullptr);
- DQN_ASSERT(stack.block == block_before);
- DQN_ASSERT(stack.block->head > stack.block->memory && stack.block->head < stack.block->tail);
- DQN_ASSERT(stack.block->tail == stack.block->memory + stack.block->size);
-
- stack.Pop(result2);
- DQN_ASSERT(block_before == stack.block);
-
- stack.Pop(result1);
- DQN_ASSERT(block_before == stack.block);
-
- stack.Free();
- }
-
- Log(Status::Ok, "Non-Expanding and expanding stack with tail push.");
- }
- }
-
- // Check stack allocator mem api callbacks
- if (1)
- {
-#if 0
- // Realloc in same block and allow it to grow in place.
- if (1)
- {
- // Using push on head
- if (1)
- {
- DqnMemStack stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroMem::Yes, DqnMemStack::Flag::BoundsGuard);
- auto *api = &stack.myHeadAPI;
-
- auto *block_before = stack.block;
- auto *head_before = stack.block->head;
-
- isize buf_size = 16;
- char *buf = (char *)stack.Push_(buf_size);
- DqnMem_Set(buf, 'X', buf_size);
- for (auto i = 0; i < buf_size; i++) DQN_ASSERT(buf[i] == 'X');
-
- isize old_buf_size = buf_size;
- buf_size = 32;
- buf = (char *)api->Realloc(buf, old_buf_size, buf_size);
- for (auto i = 0; i < old_buf_size; i++) DQN_ASSERT(buf[i] == 'X');
- DqnMem_Set(buf, '@', buf_size);
-
- DQN_ASSERT(block_before == stack.block);
- DQN_ASSERT(head_before < stack.block->head);
- stack.Pop(buf);
-
- DQN_ASSERT(block_before == stack.block);
- DQN_ASSERT(head_before == stack.block->head);
- DQN_ASSERT(head_before == stack.block->memory);
- stack.Free();
- }
-
- // Using push on tail
- if (1)
- {
- DqnMemStack stack(DQN_MEGABYTE(1), Dqn::ZeroMem::Yes, DqnMemStack::Flag::BoundsGuard);
- auto *api = &stack.myHeadAPI;
-
- auto *block_before = stack.block;
- auto *tail_before = stack.block->tail;
-
- isize buf_size = 16;
- char *buf = (char *)stack.Push_(buf_size, DqnMemStack::PushType::Tail);
- DqnMem_Set(buf, 'X', buf_size);
- for (auto i = 0; i < buf_size; i++) DQN_ASSERT(buf[i] == 'X');
-
- isize old_buf_size = buf_size;
- buf_size = 32;
- buf = (char *)api->Realloc(buf, old_buf_size, buf_size);
- for (auto i = 0; i < old_buf_size; i++) DQN_ASSERT(buf[i] == 'X');
- DqnMem_Set(buf, '@', buf_size);
-
- DQN_ASSERT(block_before == stack.block);
- DQN_ASSERT(tail_before > stack.block->tail);
- stack.Pop(buf);
-
- DQN_ASSERT(block_before == stack.block);
- DQN_ASSERT(tail_before == stack.block->tail);
- DQN_ASSERT(stack.block->head == stack.block->memory);
- stack.Free();
- }
- Log(Status::Ok, "Allocator MemAPI callback, realloc grow in place");
- }
-
- // Realloc in same block and insufficient size and expand
- if (1)
- {
- // Using push on head
- if (1)
- {
- auto stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroMem::Yes, DqnMemStack::Flag::BoundsGuard);
- auto *api = &stack.myHeadAPI;
-
- auto *block_before = stack.block;
- auto *head_before = stack.block->head;
-
- isize buf_size = 16;
- char *buf = (char *)stack.Push_(buf_size);
- DqnMem_Set(buf, 'X', buf_size);
- for (auto i = 0; i < buf_size; i++) DQN_ASSERT(buf[i] == 'X');
-
- isize old_buf_size = buf_size;
- buf_size = DQN_MEGABYTE(2);
- buf = (char *)api->Realloc(buf, old_buf_size, buf_size);
- for (auto i = 0; i < old_buf_size; i++) DQN_ASSERT(buf[i] == 'X');
- DqnMem_Set(buf, '@', buf_size);
-
- DQN_ASSERT(block_before == stack.block->prev_block);
- stack.Pop(buf);
-
- DQN_ASSERT(block_before == stack.block);
- DQN_ASSERT(head_before == stack.block->head);
- DQN_ASSERT(head_before == stack.block->memory);
- stack.Free();
- }
-
- // Using push on tail
- if (1)
- {
- DqnMemStack stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroMem::Yes, DqnMemStack::Flag::BoundsGuard);
- auto *api = &stack.myHeadAPI;
-
- auto *block_before = stack.block;
- auto *tail_before = stack.block->tail;
-
- isize buf_size = 16;
- char *buf = (char *)stack.Push_(buf_size, DqnMemStack::PushType::Tail);
- DqnMem_Set(buf, 'X', buf_size);
- for (auto i = 0; i < buf_size; i++) DQN_ASSERT(buf[i] == 'X');
-
- isize old_buf_size = buf_size;
- buf_size = DQN_MEGABYTE(2);
- buf = (char *)api->Realloc(buf, old_buf_size, buf_size);
- for (auto i = 0; i < old_buf_size; i++)
- DQN_ASSERT(buf[i] == 'X');
- DqnMem_Set(buf, '@', buf_size);
-
- DQN_ASSERT(block_before != stack.block);
- DQN_ASSERT(block_before == stack.block->prev_block);
- stack.Pop(buf);
-
- DQN_ASSERT(block_before == stack.block);
- DQN_ASSERT(tail_before == stack.block->tail);
-
- DQN_ASSERT(stack.block->head == stack.block->memory);
- stack.Free();
- }
- Log(Status::Ok, "Allocator MemAPI callback, realloc insufficient size so expand");
- }
-
- // TODO(doyle): Realloc to smaller size logic
-#endif
- }
-}
-
diff --git a/Code/Deprecated/DqnOS.cpp b/Code/Deprecated/DqnOS.cpp
deleted file mode 100644
index 0125232..0000000
--- a/Code/Deprecated/DqnOS.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
-struct DqnProcess
-{
-};
-
-void DqnOS_Test()
-{
- // pid_t pid = vfork();
- // if (pid == 0)
- // {
- // char const *argv[] = {"jim", "jams", NULL};
- // char const *envp[] = {"some", "environment", NULL};
- // chdir("/home/usr/loki/");
- // execve(cmd, argv, envp);
- // perror("Could not execute");
- // }
-#if defined(DQN__IS_WIN32)
- // CreateProcessW();
-
- WSAData wsaData;
- int result = WSAStartup(MAKEWORD(2, 2), &wsaData);
- if (result != 0)
- {
- fprintf(stderr, "WSAStartup failed: %d\n", result);
- return;
- }
-
- addrinfo hints = {};
- hints.ai_family = AF_UNSPEC;
- hints.ai_socktype = SOCK_STREAM;
- hints.ai_protocol = IPPROTO_TCP;
-
- addrinfo *foundAddr = nullptr;
- result = getaddrinfo("127.0.0.1", "38151", &hints, &foundAddr);
- if (result != 0)
- {
- fprintf(stderr, "getaddrinfo failed: %d\n", result);
- WSACleanup();
- return;
- }
-
- SOCKET connectSocket = socket(foundAddr->ai_family, foundAddr->ai_socktype, foundAddr->ai_protocol);
- if (connectSocket == INVALID_SOCKET)
- {
- fprintf(stderr, "socket failed: %d\n", WSAGetLastError());
- freeaddrinfo(foundAddr);
- WSACleanup();
- return;
- }
-#endif
-}
diff --git a/Code/Deprecated/DqnReflect.h b/Code/Deprecated/DqnReflect.h
deleted file mode 100644
index 60ffd33..0000000
--- a/Code/Deprecated/DqnReflect.h
+++ /dev/null
@@ -1,919 +0,0 @@
-#ifndef DQN_REFLECT_H
-#define DQN_REFLECT_H
-
-#define DQN_REFLECT
-#define DQN_REFLECT_META(...)
-
-//
-// HOW TO REFLECT ANNOTATED CODE
-// Define in the preprocessor, DQN_REFLECT_IMPLEMENTATION and compile
-// Dqn_Reflect.h to produce the metaprogram binary. Run the binary on the
-// desired C++ source files which will generate a DqnReflect_Generated.cpp
-//
-
-//
-// DqnReflect.exe .[c|cpp|h] ...
-//
-
-//
-// HOW TO ANNOTATE CODE
-// This header file should be included in all files containing information you
-// wish to reflect, you may reflect C-like data structures, such as in the
-// following example.
-//
-
-//
-// Your Source Code
-//
-
-#if 0
-DQN_REFLECT enum struct OpenGLShader
-{
- Invalid,
- Rect DQN_REFLECT_META(VertexShaderFilePath = "Rect.vert", FragmentShaderFilePath = "Rect.frag"),
- Text DQN_REFLECT_META(VertexShaderFilePath = "Text.vert", FragmentShaderFilePath = "Text.frag"),
-};
-#endif
-
-//
-// Generated code in DqnReflect_Generated.cpp
-//
-
-#if 0
-#ifndef DQN_REFLECT_GENERATED_H
-#define DQN_REFLECT_GENERATED_H
-
-//
-// OpenGL.h
-//
-
-#if !defined(DQN_REFLECT_DISABLE_OPENGL_H)
-char const *DqnReflect_OpenGLShader_Strings[] = {"Invalid", "Bitmap", "Text" };
-
-char const *DqnReflect_EnumString(OpenGLShader val)
-{
- if (val == OpenGLShader::Invalid) return DqnReflect_OpenGLShader_Strings[0]; // "Invalid"
- if (val == OpenGLShader::Rect) return DqnReflect_OpenGLShader_Strings[1]; // "Rect"
- if (val == OpenGLShader::Bitmap) return DqnReflect_OpenGLShader_Strings[2]; // "Bitmap"
- return nullptr;
-}
-
-char const *DqnReflect_VertexFilePathMetadata(OpenGLShader val)
-{
- if (val == OpenGLShader::Rect) return "Rect.vert";
- if (val == OpenGLShader::Bitmap) return "Bitmap.vert";
- return nullptr;
-}
-
-char const *DqnReflect_FragmentFilePathMetadata(OpenGLShader val)
-{
- if (val == OpenGLShader::Rect) return "Rect.frag";
- if (val == OpenGLShader::Bitmap) return "Bitmap.frag";
- return nullptr;
-}
-
-#endif // DQN_REFLECT_DISABLE_OPENGL_H
-
-#endif // DQN_REFLECT_GENERATED_H
-#endif
-
-#ifdef DQN_REFLECT_IMPLEMENTATION
-#include
-#include
-#include
-#include
-#include
-#include
-
-using usize = size_t;
-using isize = ptrdiff_t;
-using i64 = int64_t;
-using i32 = int32_t;
-using b32 = int32_t;
-using u8 = uint8_t;
-
-template
-struct Defer
-{
- Proc proc;
- Defer(Proc p) : proc(p) {}
- ~Defer() { proc(); }
-};
-
-struct DeferHelper
-{
- template
- Defer operator+(Lambda lambda) { return Defer(lambda); }
-};
-
-#define STR_LITERAL(str) {str, CHAR_COUNT(str)}
-struct StringLiteral
-{
- StringLiteral() = default;
- StringLiteral(char *string, int string_len) : str(string) , len(string_len) { }
- char *str;
- int len;
-};
-
-template
-struct LinkedList
-{
- T data;
- LinkedList *next;
-};
-
-#define REFLECT_MAX(a, b) ((a) > (b)) ? (a) : (b)
-#define ARRAY_COUNT(str) sizeof(str)/sizeof(str[0])
-#define CHAR_COUNT(str) (ARRAY_COUNT(str) - 1)
-#define TOKEN_COMBINE(x, y) x ## y
-#define TOKEN_COMBINE2(x, y) TOKEN_COMBINE(x, y)
-#define DEFER auto const TOKEN_COMBINE(defer_lambda_, __COUNTER__) = DeferHelper() + [&]()
-
-#define KILOBYTE(val) (1024ULL * (val))
-#define MEGABYTE(val) (1024ULL * KILOBYTE(val))
-
-//
-// Memory Utilities
-//
-
-struct MemArena
-{
- void *memory;
- usize size;
- usize used;
-};
-
-struct MemArenaScopedRegion
-{
- MemArenaScopedRegion (MemArena *arena_, usize used_) : arena(arena_), used(used_) {}
- ~MemArenaScopedRegion() { arena->used = used; }
- MemArena *arena;
- usize used;
-};
-
-static MemArena global_main_arena;
-
-#define MEM_ARENA_ALLOC_ARRAY(arena, Type, num) static_cast(MemArena_Alloc(arena, sizeof(Type) * num))
-#define MEM_ARENA_ALLOC_STRUCT(arena, Type) static_cast(MemArena_Alloc(arena, sizeof(Type)))
-MemArena MemArena_Init(void *memory, usize size)
-{
- MemArena result = {};
- result.memory = memory;
- result.size = size;
- result.used = 0;
- return result;
-}
-
-MemArenaScopedRegion MemArena_MakeScopedRegion(MemArena *arena)
-{
- return MemArenaScopedRegion(arena, arena->used);
-}
-
-void *MemArena_Alloc(MemArena *arena, usize size)
-{
- assert(arena->used + size <= arena->size);
- void *result = static_cast(arena->memory) + arena->used;
- arena->used += size;
- return result;
-}
-
-template void EraseStableFromCArray(T *array, isize len, isize max, isize index);
-#define FIXED_ARRAY_TEMPLATE_DECL template
-FIXED_ARRAY_TEMPLATE_DECL struct FixedArray
-{
- FixedArray() = default;
- T data[MAX_];
- isize len;
- isize Max() const { return MAX_; }
- T const &operator[] (isize i) const { assert(i >= 0 && i < len); return data[i]; }
- T &operator[] (isize i) { assert(i >= 0 && i < len); return data[i]; }
- T const *begin () const { return data; }
- T const *end () const { return data + len; }
- T *begin () { return data; }
- T *end () { return data + len; }
-};
-FIXED_ARRAY_TEMPLATE_DECL FixedArray FixedArray_Init (T const *item, int num) { FixedArray result = {}; FixedArray_Add(&result, item, num); return result; }
-FIXED_ARRAY_TEMPLATE_DECL T *FixedArray_Add (FixedArray *a, T const *items, int num) { assert(a->len + num <= MAX_); T *result = static_cast(MemCopy(a->data + a->len, items, sizeof(T) * num)); a->len += num; return result; }
-FIXED_ARRAY_TEMPLATE_DECL T *FixedArray_Add (FixedArray *a, T const item) { assert(a->len < MAX_); a->data[a->len++] = item; return &a->data[a->len - 1]; }
-FIXED_ARRAY_TEMPLATE_DECL T *FixedArray_Make (FixedArray *a, int num) { assert(a->len + num <= MAX_); T *result = a->data + a->len; a->len += num; return result;}
-FIXED_ARRAY_TEMPLATE_DECL void FixedArray_Clear (FixedArray *a) { a->len = 0; }
-FIXED_ARRAY_TEMPLATE_DECL void FixedArray_EraseStable (FixedArray *a, isize index) { EraseStableFromCArray(a->data, a->len--, a.Max(), index); }
-FIXED_ARRAY_TEMPLATE_DECL void FixedArray_EraseUnstable(FixedArray *a, isize index) { assert(index >= 0 && index < a->len); if (--a->len == 0) return; a->data[index] = a->data[a->len]; }
-
-//
-// String Utilities
-//
-
-b32 CharIsAlpha (char ch) { return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z'); }
-b32 CharIsDigit (char ch) { return (ch >= '0' && ch <= '9'); }
-b32 CharIsAlphaNum (char ch) { return CharIsAlpha(ch) || CharIsDigit(ch); }
-b32 CharIsWhitespace(char ch) { return (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r'); }
-
-char const *StrSkipToChar(char const *src, char ch)
-{
- char const *result = src;
- while (result && result[0] && result[0] != ch) ++result;
- return result;
-}
-
-char const *StrSkipToNextAlphaNum(char const *src)
-{
- char const *result = src;
- while (result && result[0] && !CharIsAlphaNum(result[0])) ++result;
- return result;
-}
-
-char const *StrSkipToNextDigit(char const *src)
-{
- char const *result = src;
- while (result && result[0] && !CharIsDigit(result[0])) ++result;
- return result;
-}
-
-char const *StrSkipToNextChar(char const *src)
-{
- char const *result = src;
- while (result && result[0] && !CharIsAlpha(result[0])) ++result;
- return result;
-}
-
-char const *StrSkipToNextWord(char const *src)
-{
- char const *result = src;
- while (result && result[0] && !CharIsWhitespace(result[0])) ++result;
- while (result && result[0] && CharIsWhitespace(result[0])) ++result;
- return result;
-}
-
-char const *StrSkipToNextWhitespace(char const *src)
-{
- char const *result = src;
- while (result && result[0] && !CharIsWhitespace(result[0])) ++result;
- return result;
-}
-
-char const *StrSkipWhitespace(char const *src)
-{
- char const *result = src;
- while (result && result[0] && CharIsWhitespace(result[0])) ++result;
- return result;
-}
-
-char const *StrSkipToNextWordInplace(char const **src) { *src = StrSkipToNextWord(*src); return *src; }
-char const *StrSkipWhitespaceInplace(char const **src) { *src = StrSkipWhitespace(*src); return *src; }
-
-char *StrFind(StringLiteral src, StringLiteral find)
-{
- char *buf_ptr = src.str;
- char *buf_end = buf_ptr + src.len;
- char *result = nullptr;
-
- for (;*buf_ptr; ++buf_ptr)
- {
- int len_remaining = static_cast(buf_end - buf_ptr);
- if (len_remaining < find.len) break;
-
- if (strncmp(buf_ptr, find.str, find.len) == 0)
- {
- result = buf_ptr;
- break;
- }
- }
- return result;
-}
-
-b32 StrCmp(StringLiteral a, StringLiteral b)
-{
- if (a.len != b.len)
- return false;
- b32 result = (memcmp(a.str, b.str, a.len) == 0);
- return result;
-}
-
-//
-// CPP Tokenisers/Tokens
-//
-
-#define CPP_TOKEN_TYPE_X_MACRO \
- X(EndOfStream, "End Of Stream") \
- X(LeftBrace, "{") \
- X(RightBrace, "}") \
- X(OpenParen, "(") \
- X(CloseParen, ")") \
- X(Comma, ",") \
- X(Colon, ":") \
- X(FwdSlash, "/") \
- X(Comment, "comment") \
- X(LessThan, "<") \
- X(GreaterThan, ">") \
- X(Equals, "=") \
- X(String, "\"") \
- X(SemiColon, ";") \
- X(Identifier, "Identifier") \
- X(Number, "[0-9]") \
- X(Hash, "#")
-
-#define X(decl, str) decl,
-enum struct CPPTokenType
-{
- CPP_TOKEN_TYPE_X_MACRO
-};
-#undef X
-
-#define X(decl, str) str,
-char const *CPPTokenType_Strings[]
-{
- CPP_TOKEN_TYPE_X_MACRO
-};
-#undef X
-
-struct CPPToken
-{
- CPPTokenType type;
- char *str;
- int len;
-};
-
-struct CPPReflectMetadataEntry
-{
- StringLiteral key;
- StringLiteral value;
-};
-
-using CPPReflectMetadataArray = FixedArray;
-struct CPPEnumValuesLinkedList
-{
- StringLiteral value;
- CPPReflectMetadataArray metadata_array;
- CPPEnumValuesLinkedList *next;
-};
-
-struct CPPTokeniser
-{
- CPPToken *tokens;
- int tokens_index;
- int tokens_len;
- int tokens_max;
-
- int spaces_per_indent;
- int indent_level;
- FILE *output_file;
-};
-
-void CPPTokeniser_SprintfToFile(CPPTokeniser *tokeniser, char const *fmt, ...)
-{
- int const num_spaces = tokeniser->spaces_per_indent * tokeniser->indent_level;
- fprintf(tokeniser->output_file, "%*s", num_spaces, "");
-
- va_list va;
- va_start(va, fmt);
- vfprintf(tokeniser->output_file, fmt, va);
- va_end(va);
-}
-
-void CPPTokeniser_SprintfToFileNoIndenting(CPPTokeniser *tokeniser, char const *fmt, ...)
-{
- va_list va;
- va_start(va, fmt);
- vfprintf(tokeniser->output_file, fmt, va);
- va_end(va);
-}
-
-CPPToken CPPTokeniser_NextToken(CPPTokeniser *tokeniser)
-{
- CPPToken result = tokeniser->tokens[tokeniser->tokens_index++];
- if (result.type == CPPTokenType::LeftBrace) tokeniser->indent_level++;
- else if (result.type == CPPTokenType::RightBrace) tokeniser->indent_level--;
- assert(tokeniser->indent_level >= 0);
- return result;
-}
-
-CPPToken CPPTokeniser_PeekToken(CPPTokeniser *tokeniser)
-{
- CPPToken result = tokeniser->tokens[tokeniser->tokens_index];
- return result;
-}
-
-void CPPTokeniser_RewindToken(CPPTokeniser *tokeniser)
-{
- tokeniser->tokens[--tokeniser->tokens_index];
-}
-
-CPPToken CPPTokeniser_PrevToken(CPPTokeniser *tokeniser)
-{
- CPPToken result = {};
- result.type = CPPTokenType::EndOfStream;
- if (tokeniser->tokens_index > 0)
- result = tokeniser->tokens[tokeniser->tokens_index - 1];
- return result;
-}
-
-CPPToken *CPPTokeniser_MakeToken(CPPTokeniser *tokeniser)
-{
- assert(tokeniser->tokens_len < tokeniser->tokens_max);
- CPPToken *result = tokeniser->tokens + tokeniser->tokens_len++;
- return result;
-}
-
-//
-// CPP Parsing Helpers
-//
-
-b32 IsIdentifierToken(CPPToken token, StringLiteral expect_str)
-{
- b32 result = (token.type == CPPTokenType::Identifier) && (StrCmp(StringLiteral(token.str, token.len), expect_str));
- return result;
-}
-
-b32 ExpectToken(CPPToken token, CPPTokenType type)
-{
- b32 result = token.type == type;
- if (!result)
- {
- fprintf(stdout, "Expected token type: %s received: %.*s\n", CPPTokenType_Strings[(int)type], token.len, token.str);
- fprintf(stdout, "Context: %.*s\n\n", (token.len > 100) ? 100 : token.len, token.str);
- }
- return result;
-}
-
-//
-// CPP Parsing Functions
-//
-
-CPPReflectMetadataArray ParseCPPReflectMeta(CPPTokeniser *tokeniser)
-{
- CPPReflectMetadataArray result = {};
- CPPToken token = CPPTokeniser_NextToken(tokeniser);
- if (!ExpectToken(token, CPPTokenType::OpenParen))
- return result;
-
- for (token = CPPTokeniser_NextToken(tokeniser);
- token.type != CPPTokenType::EndOfStream && token.type != CPPTokenType::CloseParen;
- token = CPPTokeniser_NextToken(tokeniser))
- {
- if (token.type == CPPTokenType::Identifier)
- {
- auto metadata_key = StringLiteral(token.str, token.len);
- CPPToken peek_token = CPPTokeniser_PeekToken(tokeniser);
- if (!ExpectToken(peek_token, CPPTokenType::Equals))
- continue;
-
- token = CPPTokeniser_NextToken(tokeniser);
- peek_token = CPPTokeniser_PeekToken(tokeniser);
-
- if (peek_token.type == CPPTokenType::String || peek_token.type == CPPTokenType::Identifier)
- {
- token = CPPTokeniser_NextToken(tokeniser);
- if (IsIdentifierToken(token, STR_LITERAL("nullptr"))) continue;
-
- CPPReflectMetadataEntry *entry = FixedArray_Make(&result, 1);
- entry->key = metadata_key;
- entry->value = StringLiteral(token.str, token.len);
- }
- }
- }
-
- while (token.type != CPPTokenType::EndOfStream && token.type != CPPTokenType::Comma)
- token = CPPTokeniser_NextToken(tokeniser);
-
- if (token.type == CPPTokenType::EndOfStream)
- CPPTokeniser_RewindToken(tokeniser);
- return result;
-}
-
-void ParseCPPEnum(CPPTokeniser *tokeniser)
-{
- CPPToken token = CPPTokeniser_NextToken(tokeniser);
- b32 enum_is_struct_or_class = false;
-
- if (IsIdentifierToken(token, STR_LITERAL("class")) ||
- IsIdentifierToken(token, STR_LITERAL("struct")))
- {
- enum_is_struct_or_class = true;
- token = CPPTokeniser_NextToken(tokeniser);
- }
-
- if (!ExpectToken(token, CPPTokenType::Identifier))
- return;
-
- CPPToken const enum_name = token;
- token = CPPTokeniser_NextToken(tokeniser);
-
- if (!ExpectToken(token, CPPTokenType::LeftBrace))
- return;
-
- b32 has_metadata = false;
- CPPEnumValuesLinkedList *start_enum_value_token = nullptr, *enum_value_token = nullptr;
- MemArenaScopedRegion mem_region = MemArena_MakeScopedRegion(&global_main_arena);
- for (token = CPPTokeniser_NextToken(tokeniser);
- token.type != CPPTokenType::EndOfStream && token.type != CPPTokenType::SemiColon;
- token = CPPTokeniser_NextToken(tokeniser))
- {
- if (token.type == CPPTokenType::Identifier)
- {
- CPPToken enum_value = token;
- token = CPPTokeniser_NextToken(tokeniser);
- CPPReflectMetadataArray metadata_array = {};
- if (IsIdentifierToken(token, STR_LITERAL("DQN_REFLECT_META")))
- {
- has_metadata = true;
- metadata_array = ParseCPPReflectMeta(tokeniser);
- }
-
- if (!start_enum_value_token)
- {
- start_enum_value_token = MEM_ARENA_ALLOC_STRUCT(&global_main_arena, CPPEnumValuesLinkedList);
- enum_value_token = start_enum_value_token;
- }
- else
- {
- enum_value_token->next = MEM_ARENA_ALLOC_STRUCT(&global_main_arena, CPPEnumValuesLinkedList);
- enum_value_token = enum_value_token->next;
- }
-
- (*enum_value_token) = {};
- enum_value_token->metadata_array = metadata_array;
- enum_value_token->value = StringLiteral(enum_value.str, enum_value.len);
- }
- }
-
- //
- // Write Stringified Enum Array
- //
- {
- CPPTokeniser_SprintfToFile(tokeniser, "char const *DqnReflect_%.*s_Strings[] = {", enum_name.len, enum_name.str);
- tokeniser->indent_level++;
- for (CPPEnumValuesLinkedList *link = start_enum_value_token; link; link = link->next)
- {
- StringLiteral enum_value = link->value;
- CPPTokeniser_SprintfToFileNoIndenting(tokeniser, "\"%.*s\", ", enum_value.len, enum_value.str);
- }
-
- tokeniser->indent_level--;
- CPPTokeniser_SprintfToFile(tokeniser, "};\n\n");
- }
-
- //
- // Write ReflectEnumString Function
- //
- {
- CPPTokeniser_SprintfToFile(tokeniser, "char const *DqnReflect_EnumString(%.*s val)\n{\n", enum_name.len, enum_name.str);
- tokeniser->indent_level++;
- DEFER
- {
- CPPTokeniser_SprintfToFile(tokeniser, "return nullptr;\n");
- tokeniser->indent_level--;
- CPPTokeniser_SprintfToFile(tokeniser, "}\n\n");
- };
-
- struct SourceCode
- {
- StringLiteral decl;
- StringLiteral enum_value;
- };
-
- LinkedList src_code = {};
- int longest_decl_len = 0;
- {
- LinkedList *curr_src_code = nullptr;
- char const *fmt = (enum_is_struct_or_class) ? "if (val == %.*s::%.*s) " : "if (val == %.*s) ";
- for (CPPEnumValuesLinkedList *link = start_enum_value_token; link; link = link->next)
- {
- if (!curr_src_code) curr_src_code = &src_code;
- else
- {
- curr_src_code->next = static_cast *>( MemArena_Alloc(&global_main_arena, sizeof(*curr_src_code)));
- curr_src_code = curr_src_code->next;
- }
-
- StringLiteral enum_value = link->value;
- int required_len = 0;
-
- if (enum_is_struct_or_class) required_len = snprintf(nullptr, 0, fmt, enum_name.len, enum_name.str, enum_value.len, enum_value.str) + 1;
- else required_len = snprintf(nullptr, 0, fmt, enum_value.len, enum_value.str) + 1;
-
- longest_decl_len = REFLECT_MAX(longest_decl_len, required_len);
- curr_src_code->data.decl.str = MEM_ARENA_ALLOC_ARRAY(&global_main_arena, char, required_len);
- curr_src_code->data.decl.len = required_len;
- curr_src_code->data.enum_value = enum_value;
-
- if (enum_is_struct_or_class) snprintf(curr_src_code->data.decl.str, curr_src_code->data.decl.len, fmt, enum_name.len, enum_name.str, enum_value.len, enum_value.str);
- else snprintf(curr_src_code->data.decl.str, curr_src_code->data.decl.len, fmt, enum_value.len, enum_value.str);
- }
- curr_src_code->next = nullptr;
- }
-
- int enum_index = 0;
- for (LinkedList *src_code_ptr = &src_code;
- src_code_ptr;
- src_code_ptr = src_code_ptr->next, ++enum_index)
- {
- StringLiteral enum_value = src_code_ptr->data.enum_value;
- int padding = longest_decl_len - src_code_ptr->data.decl.len;
- CPPTokeniser_SprintfToFile(tokeniser, "%.*s%*s", src_code_ptr->data.decl.len, src_code_ptr->data.decl.str, padding, "");
- CPPTokeniser_SprintfToFileNoIndenting(tokeniser,
- "return DqnReflect_%.*s_Strings[%d]; // \"%.*s\"\n",
- enum_name.len, enum_name.str,
- enum_index,
- enum_value.len, enum_value.str);
- }
- }
-
- //
- // Write User Annotated Metadata Getter Functions
- //
- if (has_metadata)
- {
- struct CPPDeclToValue
- {
- StringLiteral cpp_decl;
- StringLiteral value;
- };
-
- struct MetadataEntry
- {
- StringLiteral key;
- FixedArray cpp_decl_to_val;
- };
-
- FixedArray metadata_entries = {};
- for (CPPEnumValuesLinkedList *link = start_enum_value_token;
- link;
- link = link->next)
- {
- for (CPPReflectMetadataEntry const &reflect_entry : link->metadata_array)
- {
- MetadataEntry *metadata_entry_to_append_to = nullptr;
- for (MetadataEntry &check_metadata_entry : metadata_entries)
- {
- if (StrCmp(check_metadata_entry.key, reflect_entry.key))
- {
- metadata_entry_to_append_to = &check_metadata_entry;
- break;
- }
- }
-
- if (!metadata_entry_to_append_to)
- {
- metadata_entry_to_append_to = FixedArray_Make(&metadata_entries, 1);
- metadata_entry_to_append_to->key = reflect_entry.key;
- }
-
- CPPDeclToValue decl_to_val = {};
- decl_to_val.cpp_decl = StringLiteral(link->value.str, link->value.len);
- decl_to_val.value = reflect_entry.value;
- FixedArray_Add(&metadata_entry_to_append_to->cpp_decl_to_val, decl_to_val);
- }
- }
-
- for (MetadataEntry const &metadata : metadata_entries)
- {
- CPPTokeniser_SprintfToFile(tokeniser,
- "char const *DqnReflect_%.*sMetadata(%.*s val)\n{\n",
- metadata.key.len, metadata.key.str,
- enum_name.len, enum_name.str);
-
- tokeniser->indent_level++;
- DEFER
- {
- CPPTokeniser_SprintfToFile(tokeniser, "return nullptr;\n");
- tokeniser->indent_level--;
- CPPTokeniser_SprintfToFile(tokeniser, "}\n\n");
- };
-
- int enum_index = 0;
- for (CPPDeclToValue const &decl_to_val : metadata.cpp_decl_to_val)
- {
- StringLiteral const *cpp_decl = &decl_to_val.cpp_decl;
- StringLiteral const *value = &decl_to_val.value;
-
- if (enum_is_struct_or_class)
- {
- CPPTokeniser_SprintfToFile(tokeniser,
- "if (val == %.*s::%.*s) ",
- enum_name.len, enum_name.str,
- cpp_decl->len, cpp_decl->str);
- }
- else
- {
- CPPTokeniser_SprintfToFile(tokeniser,
- "if (val == %.*s) ",
- cpp_decl->len, cpp_decl->str);
- }
- CPPTokeniser_SprintfToFileNoIndenting(tokeniser, "return \"%.*s\";\n", value->len, value->str);
- }
- }
- }
-}
-
-int main(int argc, char *argv[])
-{
- if (argc < 1)
- {
- fprintf(stdout, "Usage: %s [, ...]", argv[0]);
- return 0;
- }
-
- usize main_arena_mem_size = MEGABYTE(2);
- void *main_arena_mem = malloc(main_arena_mem_size);
- global_main_arena = MemArena_Init(main_arena_mem, main_arena_mem_size);
- FILE *output_file = fopen("DqnReflect_Generated.cpp", "w");
-
- fprintf(output_file,
- "#ifndef DQN_REFLECT_GENERATED_H\n"
- "#define DQN_REFLECT_GENERATED_H\n\n"
- "// This is an auto generated file using Dqn_Reflect\n"
- "\n");
-
- for (usize arg_index = 1; arg_index < argc; ++arg_index)
- {
- MemArenaScopedRegion mem_region = MemArena_MakeScopedRegion(&global_main_arena);
- char *file_name = argv[arg_index];
- FILE *file = fopen(file_name, "rb");
- fseek(file, 0, SEEK_END);
- usize file_size = ftell(file);
- rewind(file);
-
- char *file_buf = (char *)MemArena_Alloc(&global_main_arena, file_size + 1);
- file_buf[file_size] = 0;
-
- if (fread(file_buf, file_size, 1, file) != 1)
- {
- fprintf(stderr, "Failed to fread: %zu bytes into buffer from file: %s\n", file_size, file_name);
- continue;
- }
-
- int const file_name_len = (int)strlen(file_name);
- int file_include_contents_hash_define_len = 0;
- char *file_include_contents_hash_define = nullptr;
- {
- char *extracted_file_name_buf = static_cast(MemArena_Alloc(&global_main_arena, file_name_len));
- int extracted_file_name_len = 0;
-
- for (int i = file_name_len - 1; i >= 0; i--, extracted_file_name_len++)
- {
- char ch = file_name[i];
- if (ch == '.')
- ch = '_';
-
- if (ch >= 'a' && ch <= 'z') ch -= 'a' - 'A';
-
- if (ch == '\\' || ch == '/')
- break;
-
- extracted_file_name_buf[i] = ch;
- }
-
- file_include_contents_hash_define = extracted_file_name_buf + file_name_len - extracted_file_name_len;
- file_include_contents_hash_define_len = extracted_file_name_len;
- }
-
- fprintf(output_file,
- "//\n"
- "// %s\n"
- "//\n"
- "\n"
- "#if !defined(DQN_REFLECT_DISABLE_%.*s)\n",
- file_name,
- file_include_contents_hash_define_len,
- file_include_contents_hash_define);
-
- CPPTokeniser tokeniser = {};
- tokeniser.spaces_per_indent = 4;
- tokeniser.output_file = output_file;
- tokeniser.tokens_max = 16384;
- tokeniser.tokens = MEM_ARENA_ALLOC_ARRAY(&global_main_arena, CPPToken, tokeniser.tokens_max);
-
- StringLiteral const REFLECT_MARKER = STR_LITERAL("DQN_REFLECT");
- char *file_buf_end = file_buf + file_size;
- StringLiteral buffer = StringLiteral(file_buf, file_size);
-
- for (char *ptr = StrFind(buffer, REFLECT_MARKER);
- ptr;
- ptr = StrFind(buffer, REFLECT_MARKER))
- {
- ptr += REFLECT_MARKER.len;
- for (; ptr;)
- {
- while (CharIsWhitespace(ptr[0])) ptr++;
- if (!ptr[0]) break;
-
- CPPToken *token = CPPTokeniser_MakeToken(&tokeniser);
- token->str = ptr++;
- token->len = 1;
- switch(token->str[0])
- {
- case '{': { token->type = CPPTokenType::LeftBrace; } break;
- case '}': { token->type = CPPTokenType::RightBrace; } break;
- case '(': { token->type = CPPTokenType::OpenParen; } break;
- case ')': { token->type = CPPTokenType::CloseParen; } break;
- case ',': { token->type = CPPTokenType::Comma; } break;
- case ';': { token->type = CPPTokenType::SemiColon; } break;
- case '=': { token->type = CPPTokenType::Equals; } break;
- case '<': { token->type = CPPTokenType::LessThan; } break;
- case '>': { token->type = CPPTokenType::GreaterThan; } break;
- case ':': { token->type = CPPTokenType::Colon; } break;
- case '/':
- {
- token->type = CPPTokenType::FwdSlash;
- if (ptr[0] == '/')
- {
- while (ptr[0] == ' ' || ptr[0] == '\t') ptr++;
- token->str = ptr;
- while (ptr[0] != '\n') ptr++;
- token->type = CPPTokenType::Comment;
- token->len = ptr - token->str;
- }
- }
- break;
-
- default:
- {
- ptr--;
- if (ptr[0] == '"')
- {
- token->type = CPPTokenType::String;
- for (token->str = ++ptr;;)
- {
- while (ptr[0] != '"') ptr++;
- token->len = ptr - token->str;
- if (ptr[-1] != '\\')
- {
- ptr++;
- break;
- }
- }
- }
- else
- {
- if (CharIsDigit(ptr[0]))
- {
- while (CharIsDigit(ptr[0]) || ptr[0] == 'x' || ptr[0] == 'b' || ptr[0] == 'e' || ptr[0] == '.' || ptr[0] == 'f')
- ptr++;
-
- token->type = CPPTokenType::Number;
- }
- else
- {
- token->type = CPPTokenType::Identifier;
- if (CharIsAlpha(ptr[0]) || ptr[0] == '_')
- {
- ptr++;
- while (CharIsAlphaNum(ptr[0]) || ptr[0] == '_') ptr++;
- }
- }
-
- token->len = ptr - token->str;
- }
-
- }
- break;
- }
-
- if (token->len == 0)
- {
- *token = {};
- tokeniser.tokens_len--;
- }
- else if (token->type == CPPTokenType::SemiColon)
- {
- break;
- }
- }
-
- buffer.str = ptr;
- buffer.len = static_cast(file_buf_end - ptr);
- }
-
- CPPToken *sentinel = CPPTokeniser_MakeToken(&tokeniser);
- sentinel->type = CPPTokenType::EndOfStream;
-
- for (CPPToken token = CPPTokeniser_NextToken(&tokeniser);
- token.type != CPPTokenType::EndOfStream;
- token = CPPTokeniser_NextToken(&tokeniser))
- {
-#if 0
- Token const *token = tokens + index;
- fprintf(stdout, "%.*s", token->len, token->str);
- if (index < (tokens_index - 1)) fprintf(stdout, " -> ");
-#endif
- if (token.type == CPPTokenType::Identifier)
- {
- if (StrCmp(StringLiteral(token.str, token.len), STR_LITERAL("enum")))
- ParseCPPEnum(&tokeniser);
- }
- }
-
- fprintf(output_file, "#endif // DQN_REFLECT_DISABLE_%.*s\n\n",
- file_include_contents_hash_define_len,
- file_include_contents_hash_define);
- }
-
- fprintf(output_file, "#endif // DQN_REFLECT_GENERATED_H\n");
- fclose(output_file);
-
- return 0;
-}
-
-#endif // DQN_REFLECT_IMPLEMENTATION
-#endif // DQN_REFLECT_H
diff --git a/Code/Deprecated/DqnUnitTest.cpp b/Code/Deprecated/DqnUnitTest.cpp
deleted file mode 100644
index f2e8113..0000000
--- a/Code/Deprecated/DqnUnitTest.cpp
+++ /dev/null
@@ -1,2024 +0,0 @@
-#if defined(__linux__)
- #define HANDMADE_MATH_NO_SSE
-#endif
-
-#if defined(__GNUC__)
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wfree-nonheap-object"
-#endif
-
-#if defined(_WIN32)
-#define WIN32_MEAN_AND_LEAN
-#include
-#include
-#include
-#endif
-
-#define DQN_PLATFORM_HEADER
-#define DQN_PLATFORM_IMPLEMENTATION
-#define DQN_IMPLEMENTATION
-#include "dqn.h"
-
-#define HANDMADE_MATH_IMPLEMENTATION
-#define HANDMADE_MATH_CPP_MODE
-#include "tests/HandmadeMath.h"
-
-#include
-#include
-
-// TODO(doyle): Replace DQN_ASSERT with a non-halting assert that can connect to
-// some sort of testing framework to track successes and failures.
-
-#define LOG_HEADER() LogHeader(__func__)
-FILE_SCOPE i32 global_indent;
-FILE_SCOPE bool global_new_line;
-
-#define RED "\x1B[31m"
-#define GRN "\x1B[32m"
-#define YEL "\x1B[33m"
-#define BLU "\x1B[34m"
-#define MAG "\x1B[35m"
-#define CYN "\x1B[36m"
-#define WHT "\x1B[37m"
-#define RESET "\x1B[0m"
-
-enum class Status
-{
- None,
- Ok,
- Error
-};
-void Log(Status status, char const *fmt, va_list va)
-{
- DQN_ASSERT(global_indent >= 0);
- LOCAL_PERSIST i32 line_len = 0;
-
- char buf[1024] = {};
- i32 buf_len = 0;
- {
- buf_len = Dqn_vsprintf(buf, fmt, va);
- DQN_ASSERT(buf_len < (i32)DQN_ARRAY_COUNT(buf));
- line_len += buf_len;
- }
-
- char indent_str[] = " ";
- i32 indent_len = DQN_CHAR_COUNT(indent_str);
- {
- line_len += (indent_len * global_indent);
- for (auto i = 0; i < global_indent; i++)
- printf("%s", indent_str);
-
- printf("%s", &(buf[0]));
- }
-
- if (status == Status::Ok || status == Status::Error)
- {
- char ok_status[] = "OK";
- char err_status[] = "ERROR";
-
- char *statusStr;
- i32 status_str_len;
- if (status == Status::Ok)
- {
- statusStr = ok_status;
- status_str_len = DQN_CHAR_COUNT(ok_status);
- }
- else
- {
- statusStr = err_status;
- status_str_len = DQN_CHAR_COUNT(err_status);
- }
- line_len += status_str_len;
-
- i32 target_len = 90;
- i32 remaining = target_len - line_len;
- remaining = DQN_MAX(remaining, 0);
-
- for (auto i = 0; i < remaining; i++)
- putchar('.');
-
- if (status == Status::Ok)
- {
- printf(GRN "%s" RESET, statusStr);
- }
- else
- {
- printf(RED "%s" RESET, statusStr);
- }
- }
-
- if (global_new_line)
- {
- line_len = 0;
- printf("\n");
- }
-}
-
-void Log(Status status, char const *fmt, ...)
-{
- va_list va;
- va_start(va, fmt);
- Log(status, fmt, va);
- va_end(va);
-}
-
-void Log(char const *fmt, ...)
-{
- va_list va;
- va_start(va, fmt);
- Log(Status::None, fmt, va);
- va_end(va);
-}
-
-void LogHeader(char const *func_name)
-{
- global_indent--;
- Log("\n[%s]", func_name);
- global_indent++;
-}
-
-#include "DqnFixedString.cpp"
-#include "DqnOS.cpp"
-#include "DqnJson.cpp"
-#include "DqnVHashTable.cpp"
-#include "DqnMemStack.cpp"
-
-void HandmadeMathVerifyMat4(DqnMat4 dqn_mat, hmm_mat4 hmm_mat)
-{
- f32 *hmm_matf = (f32 *)&hmm_mat;
- f32 *dqn_matf = (f32 *)&dqn_mat;
-
- const u32 EXPECTED_SIZE = 16;
- u32 totalSize = DQN_ARRAY_COUNT(dqn_mat.e) * DQN_ARRAY_COUNT(dqn_mat.e[0]);
- DQN_ASSERT(totalSize == EXPECTED_SIZE);
- DQN_ASSERT(totalSize ==
- (DQN_ARRAY_COUNT(hmm_mat.Elements) * DQN_ARRAY_COUNT(hmm_mat.Elements[0])));
-
- for (u32 i = 0; i < EXPECTED_SIZE; i++)
- {
- const f32 EPSILON = 0.001f;
- f32 diff = hmm_matf[i] - dqn_matf[i];
- diff = DQN_ABS(diff);
- DQN_ASSERTM(diff < EPSILON, "hmm_matf[%d]: %f, dqn_matf[%d]: %f\n", i, hmm_matf[i], i,
- dqn_matf[i]);
- }
-}
-
-void HandmadeMathTestInternal()
-{
- LOG_HEADER();
- // Test Perspective/Projection matrix values
-}
-
-void Dqn_Test()
-{
- LOG_HEADER();
-
- // const u64 LARGEST_NUM = (u64)-1;
- const i64 SMALLEST_NUM = LLONG_MIN;
- // StrToI64
- if (1)
- {
- const char *const a = "123";
- DQN_ASSERT(Dqn_StrToI64(a, DqnStr_Len(a)) == 123);
-
- const char *const b = "-123";
- DQN_ASSERT(Dqn_StrToI64(b, DqnStr_Len(b)) == -123);
- DQN_ASSERT(Dqn_StrToI64(b, 1) == 0);
-
- const char *const c = "-0";
- DQN_ASSERT(Dqn_StrToI64(c, DqnStr_Len(c)) == 0);
-
- const char *const d = "+123";
- DQN_ASSERT(Dqn_StrToI64(d, DqnStr_Len(d)) == 123);
-
-// TODO(doyle): Unsigned conversion
-#if 0
- char *e = "18446744073709551615";
- DQN_ASSERT((u64)(Dqn_StrToI64(e, DqnStr_Len(e))) == LARGEST_NUM);
-#endif
-
- const char *const f = "-9223372036854775808";
- DQN_ASSERT(Dqn_StrToI64(f, DqnStr_Len(f)) == SMALLEST_NUM);
-
- Log("Dqn_StrToI64()");
- }
-
- // i64 to str
- if (1)
- {
- char a[DQN_I64_MAX_STR_SIZE] = {};
- Dqn_I64ToStr(+100, a, DQN_ARRAY_COUNT(a));
- DQN_ASSERT(DqnStr_Cmp(a, "100") == 0);
-
- char b[DQN_I64_MAX_STR_SIZE] = {};
- Dqn_I64ToStr(-100, b, DQN_ARRAY_COUNT(b));
- DQN_ASSERT(DqnStr_Cmp(b, "-100") == 0);
-
- char c[DQN_I64_MAX_STR_SIZE] = {};
- Dqn_I64ToStr(0, c, DQN_ARRAY_COUNT(c));
- DQN_ASSERT(DqnStr_Cmp(c, "0") == 0);
-
-#if 0
- char d[DQN_I64_MAX_STR_SIZE] = {};
- Dqn_I64ToStr(LARGEST_NUM, d, DQN_ARRAY_COUNT(d));
- DQN_ASSERT(DqnStr_Cmp(d, "18446744073709551615") == 0);
-#endif
-
- if (sizeof(size_t) == sizeof(u64))
- {
- char e[DQN_I64_MAX_STR_SIZE] = {};
- Dqn_I64ToStr(SMALLEST_NUM, e, DQN_ARRAY_COUNT(e));
- DQN_ASSERTM(DqnStr_Cmp(e, "-9223372036854775808") == 0, "e: %s", e);
- }
-
- Log("Dqn_I64ToStr()");
- }
-
- // StrToF32
- if (1)
- {
- const f32 EPSILON = 0.001f;
- const char a[] = "-0.66248";
- f32 vA = Dqn_StrToF32(a, DQN_ARRAY_COUNT(a));
- DQN_ASSERT(DQN_ABS(vA) - DQN_ABS(-0.66248f) < EPSILON);
-
- const char b[] = "-0.632053";
- f32 vB = Dqn_StrToF32(b, DQN_ARRAY_COUNT(b));
- DQN_ASSERT(DQN_ABS(vB) - DQN_ABS(-0.632053f) < EPSILON);
-
- const char c[] = "-0.244271";
- f32 vC = Dqn_StrToF32(c, DQN_ARRAY_COUNT(c));
- DQN_ASSERT(DQN_ABS(vC) - DQN_ABS(-0.244271f) < EPSILON);
-
- const char d[] = "-0.511812";
- f32 vD = Dqn_StrToF32(d, DQN_ARRAY_COUNT(d));
- DQN_ASSERT(DQN_ABS(vD) - DQN_ABS(-0.511812f) < EPSILON);
-
- const char e[] = "-0.845392";
- f32 vE = Dqn_StrToF32(e, DQN_ARRAY_COUNT(e));
- DQN_ASSERT(DQN_ABS(vE) - DQN_ABS(-0.845392f) < EPSILON);
-
- const char f[] = "0.127809";
- f32 vF = Dqn_StrToF32(f, DQN_ARRAY_COUNT(f));
- DQN_ASSERT(DQN_ABS(vF) - DQN_ABS(-0.127809f) < EPSILON);
-
- const char g[] = "0.532";
- f32 vG = Dqn_StrToF32(g, DQN_ARRAY_COUNT(g));
- DQN_ASSERT(DQN_ABS(vG) - DQN_ABS(-0.532f) < EPSILON);
-
- const char h[] = "0.923";
- f32 vH = Dqn_StrToF32(h, DQN_ARRAY_COUNT(h));
- DQN_ASSERT(DQN_ABS(vH) - DQN_ABS(-0.923f) < EPSILON);
-
- const char i[] = "0.000";
- f32 vI = Dqn_StrToF32(i, DQN_ARRAY_COUNT(i));
- DQN_ASSERT(DQN_ABS(vI) - DQN_ABS(-0.000f) < EPSILON);
-
- const char j[] = "0.000283538";
- f32 vJ = Dqn_StrToF32(j, DQN_ARRAY_COUNT(j));
- DQN_ASSERT(DQN_ABS(vJ) - DQN_ABS(-0.000283538f) < EPSILON);
-
- const char k[] = "-1.25";
- f32 vK = Dqn_StrToF32(k, DQN_ARRAY_COUNT(k));
- DQN_ASSERT(DQN_ABS(vK) - DQN_ABS(-1.25f) < EPSILON);
-
- const char l[] = "0.286843";
- f32 vL = Dqn_StrToF32(l, DQN_ARRAY_COUNT(l));
- DQN_ASSERT(DQN_ABS(vL) - DQN_ABS(-0.286843f) < EPSILON);
-
- const char m[] = "-0.406";
- f32 vM = Dqn_StrToF32(m, DQN_ARRAY_COUNT(m));
- DQN_ASSERT(DQN_ABS(vM) - DQN_ABS(-0.406f) < EPSILON);
-
- const char n[] = "-0.892";
- f32 vN = Dqn_StrToF32(n, DQN_ARRAY_COUNT(n));
- DQN_ASSERT(DQN_ABS(vN) - DQN_ABS(-0.892f) < EPSILON);
-
- const char o[] = "0.201";
- f32 vO = Dqn_StrToF32(o, DQN_ARRAY_COUNT(o));
- DQN_ASSERT(DQN_ABS(vO) - DQN_ABS(-0.201f) < EPSILON);
-
- const char p[] = "1.25";
- f32 vP = Dqn_StrToF32(p, DQN_ARRAY_COUNT(p));
- DQN_ASSERT(DQN_ABS(vP) - DQN_ABS(1.25f) < EPSILON);
-
- const char q[] = "9.64635e-05";
- f32 vQ = Dqn_StrToF32(q, DQN_ARRAY_COUNT(q));
- DQN_ASSERT(DQN_ABS(vQ) - DQN_ABS(9.64635e-05) < EPSILON);
-
- const char r[] = "9.64635e+05";
- f32 vR = Dqn_StrToF32(r, DQN_ARRAY_COUNT(r));
- DQN_ASSERT(DQN_ABS(vR) - DQN_ABS(9.64635e+05) < EPSILON);
-
- Log("Dqn_StrToF32()");
- }
-
- // UCS <-> UTF8 Checks
- if (1)
- {
- // Test ascii characters
- if (1)
- {
- u32 codepoint = '@';
- u32 string[1] = {};
-
- u32 bytes_used = Dqn_UCSToUTF8(&string[0], codepoint);
- DQN_ASSERT(bytes_used == 1);
- DQN_ASSERT(string[0] == '@');
-
- bytes_used = Dqn_UTF8ToUCS(&string[0], codepoint);
- DQN_ASSERT(string[0] >= 0 && string[0] < 0x80);
- DQN_ASSERT(bytes_used == 1);
-
- Log("Dqn_UTF8ToUCS(): Test ascii characters");
- }
-
- // Test 2 byte characters
- if (1)
- {
- u32 codepoint = 0x278;
- u32 string[1] = {};
-
- u32 bytes_used = Dqn_UCSToUTF8(&string[0], codepoint);
- DQN_ASSERT(bytes_used == 2);
- DQN_ASSERT(string[0] == 0xC9B8);
-
- bytes_used = Dqn_UTF8ToUCS(&string[0], string[0]);
- DQN_ASSERT(string[0] == codepoint);
- DQN_ASSERT(bytes_used == 2);
-
- Log("Dqn_UTF8ToUCS(): Test 2 byte characters");
- }
-
- // Test 3 byte characters
- if (1)
- {
- u32 codepoint = 0x0A0A;
- u32 string[1] = {};
-
- u32 bytes_used = Dqn_UCSToUTF8(&string[0], codepoint);
- DQN_ASSERT(bytes_used == 3);
- DQN_ASSERT(string[0] == 0xE0A88A);
-
- bytes_used = Dqn_UTF8ToUCS(&string[0], string[0]);
- DQN_ASSERT(string[0] == codepoint);
- DQN_ASSERT(bytes_used == 3);
-
- Log("Dqn_UTF8ToUCS(): Test 3 byte characters");
- }
-
- // Test 4 byte characters
- if (1)
- {
- u32 codepoint = 0x10912;
- u32 string[1] = {};
- u32 bytes_used = Dqn_UCSToUTF8(&string[0], codepoint);
-
- DQN_ASSERT(bytes_used == 4);
- DQN_ASSERT(string[0] == 0xF090A492);
-
- bytes_used = Dqn_UTF8ToUCS(&string[0], string[0]);
- DQN_ASSERT(string[0] == codepoint);
- DQN_ASSERT(bytes_used == 4);
-
- Log("Dqn_UTF8ToUCS(): Test 4 byte characters");
- }
-
- if (1)
- {
- u32 codepoint = 0x10912;
- u32 bytes_used = Dqn_UCSToUTF8(NULL, codepoint);
- DQN_ASSERT(bytes_used == 0);
-
- bytes_used = Dqn_UTF8ToUCS(NULL, codepoint);
- DQN_ASSERT(bytes_used == 0);
-
- Log("Dqn_UTF8ToUCS(): Test return result on on NULL output param");
- }
- }
-
-}
-
-void DqnStr_Test()
-{
- // String Checks
- if (1)
- {
- LOG_HEADER();
-
- // strcmp
- if (1)
- {
- const char *const a = "str_a";
-
- // Check simple compares
- if (1)
- {
- DQN_ASSERT(DqnStr_Cmp(a, "str_a") == +0);
- DQN_ASSERT(DqnStr_Cmp(a, "str_b") == -1);
- DQN_ASSERT(DqnStr_Cmp("str_b", a) == +1);
- DQN_ASSERT(DqnStr_Cmp(a, "") == +1);
- DQN_ASSERT(DqnStr_Cmp("", "") == 0);
-
- // NOTE: Check that the string has not been trashed.
- DQN_ASSERT(DqnStr_Cmp(a, "str_a") == +0);
- Log("DqnStr_Cmp(): Check simple compares");
- }
-
- // Check ops against null
- if (1)
- {
- DQN_ASSERT(DqnStr_Cmp(NULL, NULL) != +0);
- DQN_ASSERT(DqnStr_Cmp(a, NULL) != +0);
- DQN_ASSERT(DqnStr_Cmp(NULL, a) != +0);
- Log("DqnStr_Cmp(): Check ops against null");
- }
- }
-
- // strlen
- if (1)
- {
- const char *const a = "str_a";
- DQN_ASSERT(DqnStr_Len(a) == 5);
- DQN_ASSERT(DqnStr_Len("") == 0);
- DQN_ASSERT(DqnStr_Len(" a ") == 6);
- DQN_ASSERT(DqnStr_Len("a\n") == 2);
-
- // NOTE: Check that the string has not been trashed.
- DQN_ASSERT(DqnStr_Cmp(a, "str_a") == 0);
- DQN_ASSERT(DqnStr_Len(NULL) == 0);
-
- Log("DqnStr_Len()");
- }
-
- // StrReverse
- if (1)
- {
- // Basic reverse operations
- if (1)
- {
- char a[] = "aba";
- DqnStr_Reverse(a, DqnStr_Len(a));
- DQN_ASSERT(DqnStr_Cmp(a, "aba") == 0);
-
- DqnStr_Reverse(a, 2);
- DQN_ASSERT(DqnStr_Cmp(a, "baa") == 0);
-
- DqnStr_Reverse(a, DqnStr_Len(a));
- DQN_ASSERT(DqnStr_Cmp(a, "aab") == 0);
-
- DqnStr_Reverse(&a[1], 2);
- DQN_ASSERT(DqnStr_Cmp(a, "aba") == 0);
-
- DqnStr_Reverse(a, 0);
- DQN_ASSERT(DqnStr_Cmp(a, "aba") == 0);
- Log("DqnStr_Reverse(): Basic reverse operations");
- }
-
- // Try reverse empty string
- if (1)
- {
- char a[] = "";
- DqnStr_Reverse(a, DqnStr_Len(a));
- DQN_ASSERT(DqnStr_Cmp(a, "") == 0);
- Log("DqnStr_Reverse(): Reverse empty string");
- }
-
- // Try reverse single char string
- if (1)
- {
- char a[] = "a";
- DqnStr_Reverse(a, DqnStr_Len(a));
- DQN_ASSERT(DqnStr_Cmp(a, "a") == 0);
-
- DqnStr_Reverse(a, 0);
- DQN_ASSERT(DqnStr_Cmp(a, "a") == 0);
- Log("DqnStr_Reverse(): Reverse single char string");
- }
- }
-
- if (1)
- {
- const char *const a = "Microsoft";
- const char *const b = "icro";
- i32 lenA = DqnStr_Len(a);
- i32 lenB = DqnStr_Len(b);
- DQN_ASSERT(DqnStr_HasSubstring(a, lenA, b, lenB) == true);
- DQN_ASSERT(DqnStr_HasSubstring(a, lenA, "iro", DqnStr_Len("iro")) == false);
- DQN_ASSERT(DqnStr_HasSubstring(b, lenB, a, lenA) == false);
- DQN_ASSERT(DqnStr_HasSubstring("iro", DqnStr_Len("iro"), a, lenA) == false);
- DQN_ASSERT(DqnStr_HasSubstring("", 0, "iro", 4) == false);
- DQN_ASSERT(DqnStr_HasSubstring("", 0, "", 0) == false);
- DQN_ASSERT(DqnStr_HasSubstring(NULL, 0, NULL, 0) == false);
- Log("DqnStr_HasSubstring(): Check string with matching substring");
- }
-
- if (1)
- {
- const char *const a = "Micro";
- const char *const b = "irob";
- i32 lenA = DqnStr_Len(a);
- i32 lenB = DqnStr_Len(b);
- DQN_ASSERT(DqnStr_HasSubstring(a, lenA, b, lenB) == false);
- DQN_ASSERT(DqnStr_HasSubstring(b, lenB, a, lenA) == false);
- Log("DqnStr_HasSubstring(): Check string with non-matching substring");
- }
-
- }
-}
-
-void DqnChar_Test()
-{
- LOG_HEADER();
-
- // Char Checks
- if (1)
- {
- DQN_ASSERT(DqnChar_IsAlpha('a') == true);
- DQN_ASSERT(DqnChar_IsAlpha('A') == true);
- DQN_ASSERT(DqnChar_IsAlpha('0') == false);
- DQN_ASSERT(DqnChar_IsAlpha('@') == false);
- DQN_ASSERT(DqnChar_IsAlpha(' ') == false);
- DQN_ASSERT(DqnChar_IsAlpha('\n') == false);
- Log(Status::Ok, "IsAlpha");
-
- DQN_ASSERT(DqnChar_IsDigit('1') == true);
- DQN_ASSERT(DqnChar_IsDigit('n') == false);
- DQN_ASSERT(DqnChar_IsDigit('N') == false);
- DQN_ASSERT(DqnChar_IsDigit('*') == false);
- DQN_ASSERT(DqnChar_IsDigit(' ') == false);
- DQN_ASSERT(DqnChar_IsDigit('\n') == false);
- Log(Status::Ok, "IsDigit");
-
- DQN_ASSERT(DqnChar_IsAlphaNum('1') == true);
- DQN_ASSERT(DqnChar_IsAlphaNum('a') == true);
- DQN_ASSERT(DqnChar_IsAlphaNum('A') == true);
- DQN_ASSERT(DqnChar_IsAlphaNum('*') == false);
- DQN_ASSERT(DqnChar_IsAlphaNum(' ') == false);
- DQN_ASSERT(DqnChar_IsAlphaNum('\n') == false);
- Log(Status::Ok, "IsAlphaNum");
-
- DQN_ASSERT(DqnChar_ToLower(L'A') == L'a');
- DQN_ASSERT(DqnChar_ToLower(L'a') == L'a');
- DQN_ASSERT(DqnChar_ToLower(L' ') == L' ');
- Log(Status::Ok, "ToLower");
-
- DQN_ASSERT(DqnChar_ToUpper(L'A') == L'A');
- DQN_ASSERT(DqnChar_ToUpper(L'a') == L'A');
- DQN_ASSERT(DqnChar_ToUpper(L' ') == L' ');
- Log(Status::Ok, "ToUpper");
-
- DQN_ASSERT(DqnChar_IsWhitespace(' '));
- DQN_ASSERT(DqnChar_IsWhitespace('\r'));
- DQN_ASSERT(DqnChar_IsWhitespace('\n'));
- DQN_ASSERT(DqnChar_IsWhitespace('\t'));
- Log(Status::Ok, "IsWhiteSpace");
- }
-
- // Trim white space test
- if (1)
- {
- if (1)
- {
- char a[] = "";
- i32 newLen = 0;
- auto *result = DqnChar_TrimWhitespaceAround(a, DQN_CHAR_COUNT(a), &newLen);
-
- DQN_ASSERT(newLen == 0);
- DQN_ASSERT(result == nullptr);
- }
-
- if (1)
- {
- char a[] = "a";
- i32 newLen = 0;
- auto *result = DqnChar_TrimWhitespaceAround(a, DQN_CHAR_COUNT(a), &newLen);
-
- DQN_ASSERT(newLen == 1);
- DQN_ASSERT(result == a);
- }
-
- if (1)
- {
- char a[] = " abc";
- i32 newLen = 0;
- auto *result = DqnChar_TrimWhitespaceAround(a, DQN_CHAR_COUNT(a), &newLen);
-
- DQN_ASSERT(newLen == 3);
- DQN_ASSERT(result == (a + 1));
- }
-
- if (1)
- {
- char a[] = "abc ";
- i32 newLen = 0;
- auto *result = DqnChar_TrimWhitespaceAround(a, DQN_CHAR_COUNT(a), &newLen);
-
- DQN_ASSERT(newLen == 3);
- DQN_ASSERT(result == a);
- }
-
- if (1)
- {
- char a[] = " abc ";
- i32 newLen = 0;
- auto *result = DqnChar_TrimWhitespaceAround(a, DQN_CHAR_COUNT(a), &newLen);
-
- DQN_ASSERT(newLen == 3);
- DQN_ASSERT(result == a + 3);
- }
-
- if (1)
- {
- char a[] = " ";
- i32 newLen = 0;
- auto *result = DqnChar_TrimWhitespaceAround(a, DQN_CHAR_COUNT(a), &newLen);
-
- DQN_ASSERT(newLen == 0);
- DQN_ASSERT(result == nullptr);
- }
-
- Log(Status::Ok, "TrimWhitespaceAround");
- }
-}
-
-void DqnString_Test()
-{
- LOG_HEADER();
-
- // Try expanding string
- if (1)
- {
- DqnString str = "hello world";
- DQN_DEFER { str.Free(); };
- str = "hello world2";
- str.Append(", hello again");
- str.Append(", and hello again");
-
- DQN_ASSERT(str.str[str.len] == 0);
- DQN_ASSERT(str.len <= str.max);
- DQN_ASSERTM(DqnStr_Cmp("hello world2, hello again, and hello again", str.str) == 0, "str: %s", str.str);
-
- str.Free();
- Log(Status::Ok, "Check expand on append");
- }
-
- {
- DqnString str = DQN_BUFFER_STR_LIT("hello world");
- DQN_DEFER { str.Free(); };
- DQN_ASSERT(DqnStr_Cmp(str.str, "hello world") == 0);
-
- Log(Status::Ok, "Copy constructor DqnSlice");
- }
-
- {
- DqnString zero = {};
- DqnString str = DQN_BUFFER_STR_LIT("hello world");
- str.Free();
- str = zero;
-
- DqnBuffer helloSlice = DQN_BUFFER_STR_LIT("hello");
- str = helloSlice;
- DQN_DEFER { str.Free(); };
- DQN_ASSERT(DqnStr_Cmp(str.str, "hello") == 0);
-
- Log(Status::Ok, "Copy constructor (DqnFixedString<>)");
- }
-
- {
- DqnString str = DQN_BUFFER_STR_LIT("hello world");
- DQN_DEFER { str.Free(); };
- DQN_ASSERT(str.Sprintf("hello %s", "sailor"));
- DQN_ASSERTM(DqnStr_Cmp(str.str, "hello sailor") == 0, "Result: %s", str.str);
-
- Log(Status::Ok, "Sprintf");
- }
-
- {
- {
- DqnString str = DQN_BUFFER_STR_LIT("hello world");
- DQN_DEFER { str.Free(); };
- DQN_ASSERT(str.Sprintf("hello %s", "sailor"));
- str += DQN_BUFFER_STR_LIT(".end");
- DQN_ASSERTM(DqnStr_Cmp(str.str, "hello sailor.end") == 0, "Result: %s", str.str);
- }
-
- {
- DqnString str = DQN_BUFFER_STR_LIT("hello world");
- DQN_DEFER { str.Free(); };
- DQN_ASSERT(str.Sprintf("hello %s", "sailor"));
- DQN_ASSERT(str.SprintfAppend(" %d, %d", 100, 200));
- DQN_ASSERT(DqnStr_Cmp(str.str, "hello sailor 100, 200") == 0);
- }
-
- Log(Status::Ok, "Concatenation, operator +=, SprintfAppend");
- }
-
- {
- DqnString str;
- str = "hello big world";
- DQN_ASSERT(DqnStr_Cmp(str.str, "hello big world") == 0);
- str.Free();
-
- str = DqnString("goodbye", DQN_CHAR_COUNT("goodbye"));
- DQN_ASSERT(DqnStr_Cmp(str.str, "goodbye") == 0);
- Log(Status::Ok, "Copy constructor (char const *str, int len)");
- }
-
- {
- DqnString str = DQN_BUFFER_STR_LIT("hello world");
- DQN_DEFER { str.Free(); };
- DQN_ASSERT(str.Sprintf("hello %s", "sailor"));
- str = str + " end" + DQN_BUFFER_STR_LIT(" of");
- DQN_ASSERT(DqnStr_Cmp(str.str, "hello sailor end of") == 0);
-
- Log(Status::Ok, "Operator +");
- }
-
- {
- DqnString str = "localhost";
- DQN_DEFER { str.Free(); };
- str.SprintfAppend(":%d", 16832);
- str += "/json_rpc";
- DQN_ASSERT(str.len == 24 && DqnStr_Cmp("localhost:16832/json_rpc", str.str) == 0);
-
- Log(Status::Ok, "Copy constructor, sprintf, operator +=");
- }
-}
-
-void DqnRnd_Test()
-{
- LOG_HEADER();
-
- auto pcg = DqnRndPCG();
- for (i32 i = 0; i < 1000000; i++)
- {
- i32 min = -100;
- i32 max = 1000000000;
- i32 result = pcg.Range(min, max);
- DQN_ASSERT(result >= min && result <= max);
-
- f32 rand_f32 = pcg.Nextf();
- DQN_ASSERT(rand_f32 >= 0.0f && rand_f32 <= 1.0f);
- }
- Log(Status::Ok, "DqnRndPCG");
-}
-
-void DqnMath_Test()
-{
- LOG_HEADER();
-
- // Lerp
- if (1)
- {
- if (1)
- {
- f32 start = 10;
- f32 t = 0.5f;
- f32 end = 20;
- DQN_ASSERT(DqnMath_Lerp(start, t, end) == 15);
- }
-
- if (1)
- {
- f32 start = 10;
- f32 t = 2.0f;
- f32 end = 20;
- DQN_ASSERT(DqnMath_Lerp(start, t, end) == 30);
- }
-
- Log(Status::Ok, "Lerp");
- }
-
- // Sqrtf
- if (1)
- {
- DQN_ASSERT(DqnMath_Sqrtf(4.0f) == 2.0f);
- Log(Status::Ok, "Sqrtf");
- }
-
- // Handmade Math Test
- if (1)
- {
- if (1)
- {
- f32 aspect_ratio = 1;
- DqnMat4 dqn_perspective = DqnMat4_Perspective(90, aspect_ratio, 100, 1000);
- hmm_mat4 hmm_perspective = HMM_Perspective(90, aspect_ratio, 100, 1000);
- HandmadeMathVerifyMat4(dqn_perspective, hmm_perspective);
-
- Log(Status::Ok, "HandmadeMathTest: Perspective");
- }
-
- // Test Mat4 translate * scale
- if (1)
- {
- hmm_vec3 hmm_vec = HMM_Vec3i(1, 2, 3);
- DqnV3 dqn_vec = DqnV3(1, 2, 3);
- DqnMat4 dqn_translate = DqnMat4_Translate3f(dqn_vec.x, dqn_vec.y, dqn_vec.z);
- hmm_mat4 hmm_translate = HMM_Translate(hmm_vec);
- HandmadeMathVerifyMat4(dqn_translate, hmm_translate);
-
- hmm_vec3 hmm_axis = HMM_Vec3(0.5f, 0.2f, 0.7f);
- DqnV3 dqn_axis = DqnV3(0.5f, 0.2f, 0.7f);
- f32 rotation_in_degrees = 80.0f;
-
- DqnMat4 dqn_rotate = DqnMat4_Rotate(DQN_DEGREES_TO_RADIANS(rotation_in_degrees), dqn_axis.x,
- dqn_axis.y, dqn_axis.z);
- hmm_mat4 hmm_rotate = HMM_Rotate(rotation_in_degrees, hmm_axis);
- HandmadeMathVerifyMat4(dqn_rotate, hmm_rotate);
-
- dqn_vec *= 2;
- hmm_vec *= 2;
- DqnMat4 dqn_scale = DqnMat4_Scale(dqn_vec.x, dqn_vec.y, dqn_vec.z);
- hmm_mat4 hmm_scale = HMM_Scale(hmm_vec);
- HandmadeMathVerifyMat4(dqn_scale, hmm_scale);
-
- DqnMat4 dqn_ts_matrix = DqnMat4_Mul(dqn_translate, dqn_scale);
- hmm_mat4 hmm_ts_matrix = HMM_MultiplyMat4(hmm_translate, hmm_scale);
- HandmadeMathVerifyMat4(dqn_ts_matrix, hmm_ts_matrix);
-
- // Test Mat4 * MulV4
- if (1)
- {
- DqnV4 dqn_v4 = DqnV4(1, 2, 3, 4);
- hmm_vec4 hmm_v4 = HMM_Vec4(1, 2, 3, 4);
-
- DqnV4 dqn_result = DqnMat4_MulV4(dqn_ts_matrix, dqn_v4);
- hmm_vec4 hmmResult = HMM_MultiplyMat4ByVec4(hmm_ts_matrix, hmm_v4);
-
- DQN_ASSERT(dqn_result.x == hmmResult.X);
- DQN_ASSERT(dqn_result.y == hmmResult.Y);
- DQN_ASSERT(dqn_result.z == hmmResult.Z);
- DQN_ASSERT(dqn_result.w == hmmResult.W);
-
- Log(Status::Ok, "HandmadeMathTest: Mat4 * MulV4");
- }
- }
- }
-}
-
-void DqnVX_Test()
-{
- LOG_HEADER();
-
- // V2
- if (1)
- {
- // Ctor
- if (1)
- {
- // Ctor with floats
- if (1)
- {
- DqnV2 vec = DqnV2(5.5f, 5.0f);
- DQN_ASSERT(vec.x == 5.5f && vec.y == 5.0f);
- DQN_ASSERT(vec.w == 5.5f && vec.h == 5.0f);
- }
-
- // Ctor with 2 integers
- if (1)
- {
- DqnV2 vec = DqnV2(3, 5);
- DQN_ASSERT(vec.x == 3 && vec.y == 5.0f);
- DQN_ASSERT(vec.w == 3 && vec.h == 5.0f);
- }
- Log(Status::Ok, "DqnV2: Ctor");
- }
-
- // V2 Arithmetic
- if (1)
- {
- DqnV2 vec_a = DqnV2(5, 10);
- DqnV2 vec_b = DqnV2(2, 3);
- DQN_ASSERT(DqnV2_Equals(vec_a, vec_b) == false);
- DQN_ASSERT(DqnV2_Equals(vec_a, DqnV2(5, 10)) == true);
- DQN_ASSERT(DqnV2_Equals(vec_b, DqnV2(2, 3)) == true);
-
- DqnV2 result = DqnV2_Add(vec_a, DqnV2(5, 10));
- DQN_ASSERT(DqnV2_Equals(result, DqnV2(10, 20)) == true);
-
- result = DqnV2_Sub(result, DqnV2(5, 10));
- DQN_ASSERT(DqnV2_Equals(result, DqnV2(5, 10)) == true);
-
- result = DqnV2_Scalef(result, 5);
- DQN_ASSERT(DqnV2_Equals(result, DqnV2(25, 50)) == true);
-
- result = DqnV2_Hadamard(result, DqnV2(10.0f, 0.5f));
- DQN_ASSERT(DqnV2_Equals(result, DqnV2(250, 25)) == true);
-
- f32 dot_result = DqnV2_Dot(DqnV2(5, 10), DqnV2(3, 4));
- DQN_ASSERT(dot_result == 55);
- Log(Status::Ok, "DqnV2: Arithmetic");
- }
-
- // Test operator overloading
- if (1)
- {
- DqnV2 vec_a = DqnV2(5, 10);
- DqnV2 vec_b = DqnV2(2, 3);
- DQN_ASSERT((vec_a == vec_b) == false);
- DQN_ASSERT((vec_a == DqnV2(5, 10)) == true);
- DQN_ASSERT((vec_b == DqnV2(2, 3)) == true);
-
- DqnV2 result = vec_a + DqnV2(5, 10);
- DQN_ASSERT((result == DqnV2(10, 20)) == true);
-
- result -= DqnV2(5, 10);
- DQN_ASSERT((result == DqnV2(5, 10)) == true);
-
- result *= 5;
- DQN_ASSERT((result == DqnV2(25, 50)) == true);
-
- result = result * DqnV2(10.0f, 0.5f);
- DQN_ASSERT((result == DqnV2(250, 25)) == true);
-
- result += DqnV2(1, 1);
- DQN_ASSERT((result == DqnV2(251, 26)) == true);
-
- result = result - DqnV2(1, 1);
- DQN_ASSERT((result == DqnV2(250, 25)) == true);
- Log(Status::Ok, "DqnV2: Operator Overloading");
- }
-
- // V2 Properties
- if (1)
- {
- const f32 EPSILON = 0.001f;
- DqnV2 a = DqnV2(0, 0);
- DqnV2 b = DqnV2(3, 4);
-
- f32 len_sq = DqnV2_LengthSquared(a, b);
- DQN_ASSERT(len_sq == 25);
-
- f32 length = DqnV2_Length(a, b);
- DQN_ASSERT(length == 5);
-
- DqnV2 normalised = DqnV2_Normalise(b);
- f32 norm_x = b.x / 5.0f;
- f32 norm_y = b.y / 5.0f;
- f32 diff_norm_x = normalised.x - norm_x;
- f32 diff_norm_y = normalised.y - norm_y;
- DQN_ASSERTM(diff_norm_x < EPSILON, "normalised.x: %f, norm_x: %f\n", normalised.x, norm_x);
- DQN_ASSERTM(diff_norm_y < EPSILON, "normalised.y: %f, norm_y: %f\n", normalised.y, norm_y);
-
- DqnV2 c = DqnV2(3.5f, 8.0f);
- DQN_ASSERT(DqnV2_Overlaps(b, c) == true);
- DQN_ASSERT(DqnV2_Overlaps(b, a) == false);
-
- DqnV2 d = DqnV2_Perpendicular(c);
- DQN_ASSERT(DqnV2_Dot(c, d) == 0);
-
- Log(Status::Ok, "DqnV2: LengthSquared, Length, Normalize, Overlaps, Perp");
- }
-
- // ConstrainToRatio
- if (1)
- {
- DqnV2 ratio = DqnV2(16, 9);
- DqnV2 dim = DqnV2(2000, 1080);
- DqnV2 result = DqnV2_ConstrainToRatio(dim, ratio);
- DQN_ASSERT(result.w == 1920 && result.h == 1080);
- Log(Status::Ok, "DqnV2: ConstrainToRatio");
- }
- }
-
- // V3
- if (1)
- {
- // Ctor
- if (1)
- {
- // Floats
- if (1)
- {
- DqnV3 vec = DqnV3(5.5f, 5.0f, 5.875f);
- DQN_ASSERT(vec.x == 5.5f && vec.y == 5.0f && vec.z == 5.875f);
- DQN_ASSERT(vec.r == 5.5f && vec.g == 5.0f && vec.b == 5.875f);
- }
-
- // Integers
- if (1)
- {
- DqnV3 vec = DqnV3(3, 4, 5);
- DQN_ASSERT(vec.x == 3 && vec.y == 4 && vec.z == 5);
- DQN_ASSERT(vec.r == 3 && vec.g == 4 && vec.b == 5);
- }
- Log(Status::Ok, "DqnV3: Ctor");
- }
-
- if (1)
- {
- // Arithmetic
- if (1)
- {
- DqnV3 vec_a = DqnV3(5, 10, 15);
- DqnV3 vec_b = DqnV3(2, 3, 6);
- DQN_ASSERT(DqnV3_Equals(vec_a, vec_b) == false);
- DQN_ASSERT(DqnV3_Equals(vec_a, DqnV3(5, 10, 15)) == true);
- DQN_ASSERT(DqnV3_Equals(vec_b, DqnV3(2, 3, 6)) == true);
-
- DqnV3 result = DqnV3_Add(vec_a, DqnV3(5, 10, 15));
- DQN_ASSERT(DqnV3_Equals(result, DqnV3(10, 20, 30)) == true);
-
- result = DqnV3_Sub(result, DqnV3(5, 10, 15));
- DQN_ASSERT(DqnV3_Equals(result, DqnV3(5, 10, 15)) == true);
-
- result = DqnV3_Scalef(result, 5);
- DQN_ASSERT(DqnV3_Equals(result, DqnV3(25, 50, 75)) == true);
-
- result = DqnV3_Hadamard(result, DqnV3(10.0f, 0.5f, 10.0f));
- DQN_ASSERT(DqnV3_Equals(result, DqnV3(250, 25, 750)) == true);
-
- f32 dot_result = DqnV3_Dot(DqnV3(5, 10, 2), DqnV3(3, 4, 6));
- DQN_ASSERT(dot_result == 67);
-
- DqnV3 cross = DqnV3_Cross(vec_a, vec_b);
- DQN_ASSERT(DqnV3_Equals(cross, DqnV3(15, 0, -5)) == true);
- }
-
- // Operator overloading
- if (1)
- {
- DqnV3 vec_a = DqnV3(5, 10, 15);
- DqnV3 vec_b = DqnV3(2, 3, 6);
- DQN_ASSERT((vec_a == vec_b) == false);
- DQN_ASSERT((vec_a == DqnV3(5, 10, 15)) == true);
- DQN_ASSERT((vec_b == DqnV3(2, 3, 6)) == true);
-
- DqnV3 result = vec_a + DqnV3(5, 10, 15);
- DQN_ASSERT((result == DqnV3(10, 20, 30)) == true);
-
- result -= DqnV3(5, 10, 15);
- DQN_ASSERT((result == DqnV3(5, 10, 15)) == true);
-
- result = result * 5;
- DQN_ASSERT((result == DqnV3(25, 50, 75)) == true);
-
- result *= DqnV3(10.0f, 0.5f, 10.0f);
- DQN_ASSERT((result == DqnV3(250, 25, 750)) == true);
-
- result = result - DqnV3(1, 1, 1);
- DQN_ASSERT((result == DqnV3(249, 24, 749)) == true);
-
- result += DqnV3(1, 1, 1);
- DQN_ASSERT((result == DqnV3(250, 25, 750)) == true);
- }
- Log(Status::Ok, "DqnV3: Arithmetic");
- }
- }
-
- // V4
- if (1)
- {
-
- // Ctor
- if (1)
- {
- // Floats
- if (1)
- {
- DqnV4 vec = DqnV4(5.5f, 5.0f, 5.875f, 5.928f);
- DQN_ASSERT(vec.x == 5.5f && vec.y == 5.0f && vec.z == 5.875f && vec.w == 5.928f);
- DQN_ASSERT(vec.r == 5.5f && vec.g == 5.0f && vec.b == 5.875f && vec.a == 5.928f);
- }
-
- // Integers
- if (1)
- {
- DqnV4 vec = DqnV4(3, 4, 5, 6);
- DQN_ASSERT(vec.x == 3 && vec.y == 4 && vec.z == 5 && vec.w == 6);
- DQN_ASSERT(vec.r == 3 && vec.g == 4 && vec.b == 5 && vec.a == 6);
- }
- Log(Status::Ok, "DqnV4: Ctor");
- }
- // V4 Arithmetic
- if (1)
- {
- // Arithmetic
- {
- DqnV4 vec_a = DqnV4(5, 10, 15, 20);
- DqnV4 vec_b = DqnV4(2, 3, 6, 8);
- DQN_ASSERT(DqnV4_Equals(vec_a, vec_b) == false);
- DQN_ASSERT(DqnV4_Equals(vec_a, DqnV4(5, 10, 15, 20)) == true);
- DQN_ASSERT(DqnV4_Equals(vec_b, DqnV4(2, 3, 6, 8)) == true);
-
- DqnV4 result = DqnV4_Add(vec_a, DqnV4(5, 10, 15, 20));
- DQN_ASSERT(DqnV4_Equals(result, DqnV4(10, 20, 30, 40)) == true);
-
- result = DqnV4_Sub(result, DqnV4(5, 10, 15, 20));
- DQN_ASSERT(DqnV4_Equals(result, DqnV4(5, 10, 15, 20)) == true);
-
- result = DqnV4_Scalef(result, 5);
- DQN_ASSERT(DqnV4_Equals(result, DqnV4(25, 50, 75, 100)) == true);
-
- result = DqnV4_Hadamard(result, DqnV4(10.0f, 0.5f, 10.0f, 0.25f));
- DQN_ASSERT(DqnV4_Equals(result, DqnV4(250, 25, 750, 25)) == true);
-
- f32 dot_result = DqnV4_Dot(DqnV4(5, 10, 2, 8), DqnV4(3, 4, 6, 5));
- DQN_ASSERT(dot_result == 107);
- }
-
- // Operator Overloading
- if (1)
- {
- DqnV4 vec_a = DqnV4(5, 10, 15, 20);
- DqnV4 vec_b = DqnV4(2, 3, 6, 8);
- DQN_ASSERT((vec_a == vec_b) == false);
- DQN_ASSERT((vec_a == DqnV4(5, 10, 15, 20)) == true);
- DQN_ASSERT((vec_b == DqnV4(2, 3, 6, 8)) == true);
-
- DqnV4 result = vec_a + DqnV4(5, 10, 15, 20);
- DQN_ASSERT((result == DqnV4(10, 20, 30, 40)) == true);
-
- result = result - DqnV4(5, 10, 15, 20);
- DQN_ASSERT((result == DqnV4(5, 10, 15, 20)) == true);
-
- result = result * 5;
- DQN_ASSERT((result == DqnV4(25, 50, 75, 100)) == true);
-
- result *= DqnV4(10.0f, 0.5f, 10.0f, 0.25f);
- DQN_ASSERT((result == DqnV4(250, 25, 750, 25)) == true);
-
- result += DqnV4(1, 1, 1, 1);
- DQN_ASSERT((result == DqnV4(251, 26, 751, 26)) == true);
-
- result -= DqnV4(1, 1, 1, 1);
- DQN_ASSERT((result == DqnV4(250, 25, 750, 25)) == true);
- }
- Log(Status::Ok, "DqnV4: Arithmetic");
- }
- }
-}
-
-void DqnRect_Test()
-{
- LOG_HEADER();
- // Rect
- if (1)
- {
- // Test rect init functions
- if (1)
- {
- DqnRect rect4f = DqnRect(1.1f, 2.2f, 3.3f, 4.4f);
- DqnRect rect4i = DqnRect(1, 2, 3, 4);
-
- DQN_ASSERT(rect4i.min.x == 1 && rect4i.min.y == 2);
- DQN_ASSERT(rect4i.max.x == 4 && rect4i.max.y == 6);
-
- const f32 EPSILON = 0.001f;
- f32 diff_max_x = rect4f.max.x - 4.4f;
- f32 diff_max_y = rect4f.max.y - 6.6f;
- DQN_ASSERT(rect4f.min.x == 1.1f && rect4f.min.y == 2.2f);
- DQN_ASSERT(DQN_ABS(diff_max_x) < EPSILON && DQN_ABS(diff_max_y) < EPSILON);
-
- DqnRect rect = DqnRect(-10, -10, 20, 20);
- DQN_ASSERT(DqnV2_Equals(rect.min, DqnV2(-10, -10)));
- DQN_ASSERT(DqnV2_Equals(rect.max, DqnV2(10, 10)));
- Log(Status::Ok, "Ctor");
- }
-
- // Test rect get size function
- if (1)
- {
- // Test float rect
- if (1)
- {
- DqnRect rect = DqnRect(DqnV2(-10, -10), DqnV2(20, 20));
-
- f32 width, height;
- rect.GetSize(&width, &height);
- DQN_ASSERT(width == 20);
- DQN_ASSERT(height == 20);
-
- DqnV2 dim = rect.GetSize();
- DQN_ASSERT(DqnV2_Equals(dim, DqnV2(20, 20)));
- Log(Status::Ok, "GetSize");
- }
- }
-
- // Test rect get centre
- DqnRect rect = DqnRect(DqnV2(-10, -10), DqnV2(20, 20));
- DqnV2 rect_centre = rect.GetCenter();
- DQN_ASSERT(DqnV2_Equals(rect_centre, DqnV2(0, 0)));
- Log(Status::Ok, "GetCentre");
-
- // Test clipping rect get centre
- DqnRect clip_rect = DqnRect(DqnV2(-15, -15), DqnV2(10, 10) + DqnV2(15));
- DqnRect clip_result = rect.ClipRect(clip_rect);
- DQN_ASSERT(clip_result.min.x == -10 && clip_result.min.y == -10);
- DQN_ASSERT(clip_result.max.x == 10 && clip_result.max.y == 10);
- Log(Status::Ok, "ClipRect");
-
- // Test shifting rect
- if (1)
- {
- DqnRect shifted_rect = rect.Move(DqnV2(10, 0));
- DQN_ASSERT(DqnV2_Equals(shifted_rect.min, DqnV2(0, -10)));
- DQN_ASSERT(DqnV2_Equals(shifted_rect.max, DqnV2(20, 10)));
-
- // Ensure dimensions have remained the same
- if (1)
- {
- f32 width, height;
- shifted_rect.GetSize(&width, &height);
- DQN_ASSERT(width == 20);
- DQN_ASSERT(height == 20);
-
- DqnV2 dim = shifted_rect.GetSize();
- DQN_ASSERT(DqnV2_Equals(dim, DqnV2(20, 20)));
- }
-
- // Test rect contains p
- if (1)
- {
- DqnV2 inP = DqnV2(5, 5);
- DqnV2 outP = DqnV2(100, 100);
- DQN_ASSERT(shifted_rect.ContainsP(inP));
- DQN_ASSERT(!shifted_rect.ContainsP(outP));
- }
-
- Log(Status::Ok, "Move");
- }
- }
-}
-
-void DqnArray_TestRealDataInternal(DqnArray *array)
-{
- (void)array;
-#ifdef DQN_PLATFORM_HEADER
- size_t buf_size = 0;
- u8 *buf = DqnFile_ReadAll("tests/google-10000-english.txt", &buf_size);
- DQN_ASSERT(buf);
-
- for (usize i = 0; i < buf_size; i++)
- array->Push(buf[i]);
-
- DQN_ASSERT((size_t)array->len == buf_size);
- for (auto i = 0; i < array->len; i++)
- DQN_ASSERT(array->data[i] == buf[i]);
-
- array->Free();
- free(buf);
-
- Log(Status::Ok, "Testing real data");
-#endif
-}
-
-void DqnArray_Test()
-{
- LOG_HEADER();
- if (1)
- {
- if (1)
- {
- DqnArray array1 = {};
- array1.Reserve(3);
- DQN_ASSERT(array1.len == 0);
- DQN_ASSERT(array1.max == 3);
- array1.Free();
-
- array1.Reserve(0);
- DQN_ASSERT(array1.len == 0);
- DQN_ASSERT(array1.max == 0);
-
- array1.Push('c');
- DQN_ASSERT(array1.len == 1);
- array1.Free();
-
- Log(Status::Ok, "Testing faux-array constructors DqnArray_()");
- }
-
- if (1)
- {
- DqnArray array = {};
- array.Reserve(1);
- DqnArray_TestRealDataInternal(&array);
- }
-
- if (1)
- {
- auto stack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroMem::Yes, 0, DqnMemTracker::Flag::Simple);
- DQN_DEFER { stack.Free(); };
-#if 0
- if (1)
- {
- auto memGuard0 = stack.TempRegionGuard();
- DqnArray array(&stack.myHeadAPI);
- array.Reserve(1);
- DqnArray_TestRealDataInternal(&array);
- }
-
- // Test reallocing strategies for memory stacks
- if (1)
- {
- auto memGuard0 = stack.TempRegionGuard();
- DqnArray array(&stack.myHeadAPI);
- array.Reserve(128);
- stack.Push(1024);
- DqnArray_TestRealDataInternal(&array);
- }
-#endif
- }
- }
-}
-
-#ifdef DQN_PLATFORM_HEADER
-void DqnFile_Test()
-{
- LOG_HEADER();
- // File i/o
- if (1)
- {
-
- // Test file open
- if (1)
- {
- const char *const FILE_TO_OPEN = ".clang-format";
- u32 expectedSize = 0;
-#if defined(DQN__IS_UNIX)
- {
- struct stat fileStat = {0};
- DQN_ASSERT(stat(FILE_TO_OPEN, &fileStat) == 0);
- expectedSize = fileStat.st_size;
- }
-
- if (1)
- {
- // NOTE: cpuinfo is generated when queried, so a normal 'stat'
- // should give us zero, but we fall back to manual byte checking
- // which should give us the proper size.
- size_t size = 0;
- DQN_ASSERT(DqnFile_Size("/proc/cpuinfo", &size));
- DQN_ASSERT(size > 0);
- }
-
-#else
- {
- HANDLE handle = CreateFile(FILE_TO_OPEN, GENERIC_READ, 0, NULL, OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL, NULL);
- if (handle == INVALID_HANDLE_VALUE)
- {
- DqnWin32_DisplayLastError("CreateFile() failed");
- }
- DQN_ASSERT(handle != INVALID_HANDLE_VALUE);
-
- LARGE_INTEGER size;
- DQN_ASSERT(GetFileSizeEx(handle, &size));
-
- CloseHandle(handle);
- expectedSize = size.LowPart;
- }
-#endif
-
- if (1)
- {
- size_t size = 0;
- DQN_ASSERT(DqnFile_Size(FILE_TO_OPEN, &size));
- DQN_ASSERT(size == expectedSize);
- }
-
- DqnFile file = {};
- DQN_ASSERT(file.Open(
- ".clang-format", DqnFile::Flag::FileReadWrite, DqnFile::Action::OpenOnly));
-
- DQN_ASSERTM(file.size == expectedSize,
- "DqnFileOpen() failed: file.size: %d, expected:%d\n", file.size,
- expectedSize);
-
- u8 *buffer = (u8 *)calloc(1, (size_t)file.size * sizeof(u8));
- DQN_ASSERT(file.Read(buffer, (u32)file.size) == file.size);
- free(buffer);
-
- file.Close();
- DQN_ASSERT(!file.handle && file.size == 0 && file.flags == 0);
-
- Log(Status::Ok, "General test");
- }
-
- // Test invalid file
- if (1)
- {
- DqnFile file = {};
- DQN_ASSERT(!file.Open(
- "asdljasdnel;kajdf", DqnFile::Flag::FileReadWrite, DqnFile::Action::OpenOnly));
- DQN_ASSERT(file.size == 0);
- DQN_ASSERT(file.flags == 0);
- DQN_ASSERT(!file.handle);
- Log(Status::Ok, "Invalid file test");
- }
- }
-
- // Write Test
- if (1)
- {
- const char *file_names[] = {"dqn_1", "dqn_2", "dqn_3", "dqn_4", "dqn_5"};
- const char *writeData[] = {"1234", "2468", "36912", "481216", "5101520"};
- DqnFile files[DQN_ARRAY_COUNT(file_names)] = {};
-
- // Write data out to some files
- for (u32 i = 0; i < DQN_ARRAY_COUNT(file_names); i++)
- {
- u32 permissions = DqnFile::Flag::FileReadWrite;
- DqnFile *file = files + i;
- if (!file->Open(file_names[i], permissions, DqnFile::Action::ClearIfExist))
- {
- bool result =
- file->Open(file_names[i], permissions, DqnFile::Action::CreateIfNotExist);
- DQN_ASSERT(result);
- }
-
- size_t bytesToWrite = DqnStr_Len(writeData[i]);
- u8 *dataToWrite = (u8 *)(writeData[i]);
- size_t bytesWritten = file->Write(dataToWrite, bytesToWrite);
- DQN_ASSERT(bytesWritten == bytesToWrite);
- file->Close();
- }
-
- auto memstack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroMem::Yes, DqnMemTracker::Flag::Simple);
- // Read data back in
- for (u32 i = 0; i < DQN_ARRAY_COUNT(file_names); i++)
- {
- // Manual read the file contents
- {
- u32 permissions = DqnFile::Flag::FileRead;
- DqnFile *file = files + i;
- bool result = file->Open(file_names[i], permissions, DqnFile::Action::OpenOnly);
- DQN_ASSERT(result);
-
- u8 *buffer = (u8 *)memstack.Push_(file->size);
- DQN_ASSERT(buffer);
-
- size_t bytesRead = file->Read(buffer, file->size);
- DQN_ASSERT(bytesRead == file->size);
-
- // Verify the data is the same as we wrote out
- DQN_ASSERT(DqnStr_Cmp((char *)buffer, (writeData[i]), (i32)bytesRead) == 0);
-
- // Delete when we're done with it
- memstack.Pop(buffer);
- file->Close();
- }
-
- // Read using the ReadEntireFile api which doesn't need a file handle as an argument
- {
- size_t reqSize = 0;
- DQN_ASSERT(DqnFile_Size(file_names[i], &reqSize));
-
- u8 *buffer = (u8 *)memstack.Push_(reqSize);
- DQN_ASSERT(buffer);
-
- DQN_ASSERT(DqnFile_ReadAll(file_names[i], buffer, reqSize));
-
- // Verify the data is the same as we wrote out
- DQN_ASSERT(DqnStr_Cmp((char *)buffer, (writeData[i]), (i32)reqSize) == 0);
- memstack.Pop(buffer);
- }
-
- DQN_ASSERT(DqnFile_Delete(file_names[i]));
- }
-
- // Then check delete actually worked, files should not exist.
- for (u32 i = 0; i < DQN_ARRAY_COUNT(file_names); i++)
- {
- DqnFile dummy = {};
- u32 permissions = DqnFile::Flag::FileRead;
- bool fileExists = dummy.Open(file_names[i], permissions, DqnFile::Action::OpenOnly);
- DQN_ASSERT(!fileExists);
- }
- memstack.Free();
-
- Log(Status::Ok, "Write file");
- }
-
- // Test directory listing
- if (1)
- {
- i32 num_files;
-#if defined(DQN___IS_UNIX)
- char **file_list = DqnFile_ListDir(".", &num_files);
-#else
- char **file_list = DqnFile_ListDir("*", &num_files);
-#endif
-
- Log("Test directory listing");
- global_indent++;
- for (auto i = 0; i < num_files; i++)
- Log("%02d: %s", i, file_list[i]);
-
- DqnFile_ListDirFree(file_list, num_files);
- global_indent--;
- Log(Status::Ok, "List directory files");
- }
-
-}
-
-void PlatformSleep(int milliseconds)
-{
-#if defined(DQN__IS_UNIX)
- usleep(milliseconds * 1000);
-#else
- Sleep(milliseconds);
-#endif
-}
-
-void DqnTimer_Test()
-{
- LOG_HEADER();
-
- if (1)
- {
-
- int sleepTimeInMs = 250;
- f64 start_in_ms = DqnTimer_NowInMs();
- PlatformSleep(sleepTimeInMs);
- f64 end_in_ms = DqnTimer_NowInMs();
-
- DQN_ASSERT((start_in_ms + sleepTimeInMs) <= end_in_ms);
- Log("start: %f, end: %f", start_in_ms, end_in_ms);
-
- Log(Status::Ok, "Timer advanced in time over 1 second");
- global_indent++;
- Log("Start: %f, End: %f", start_in_ms, end_in_ms);
- global_indent--;
- }
-}
-
-
-FILE_SCOPE u32 volatile global_debug_counter;
-FILE_SCOPE DqnLock global_job_queue_lock;
-const u32 QUEUE_SIZE = 256;
-FILE_SCOPE void JobQueueDebugCallbackIncrementCounter(DqnJobQueue *const queue, void *const user_data)
-{
- (void)user_data;
- DQN_ASSERT(queue->size == QUEUE_SIZE);
- {
- auto guard = global_job_queue_lock.Guard();
- global_debug_counter++;
-
- // u32 number = global_debug_counter;
-#if defined(DQN__IS_WIN32)
- // Log("JobQueueDebugCallbackIncrementCounter(): Thread %d: Incrementing Number: %d", GetCurrentThreadId(), number);
-#else
- // Log("JobQueueDebugCallbackIncrementCounter(): Thread unix: Incrementing Number: %d", number);
-#endif
- }
-
-}
-
-FILE_SCOPE void DqnJobQueue_Test()
-{
- LOG_HEADER();
- global_debug_counter = 0;
-
- auto memstack = DqnMemStack(DQN_MEGABYTE(1), Dqn::ZeroMem::Yes, 0, DqnMemTracker::Flag::Simple);
-
- u32 num_threads, num_cores;
- DqnOS_GetThreadsAndCores(&num_cores, &num_threads);
- DQN_ASSERT(num_threads > 0 && num_cores > 0);
-
- u32 total_threads = (num_cores - 1) * num_threads;
- if (total_threads == 0) total_threads = 1;
-
- DqnJobQueue job_queue = {};
- DqnJob *job_list = (DqnJob *)memstack.Push_(sizeof(*job_queue.job_list) * QUEUE_SIZE);
- DQN_ASSERT(DqnJobQueue_Init(&job_queue, job_list, QUEUE_SIZE, total_threads));
-
- const u32 WORK_ENTRIES = 2048;
- DQN_ASSERT(global_job_queue_lock.Init());
- for (u32 i = 0; i < WORK_ENTRIES; i++)
- {
- DqnJob job = {};
- job.callback = JobQueueDebugCallbackIncrementCounter;
- while (!DqnJobQueue_AddJob(&job_queue, job))
- {
- DqnJobQueue_TryExecuteNextJob(&job_queue);
- }
- }
-
- DqnJobQueue_BlockAndCompleteAllJobs(&job_queue);
- DQN_ASSERT(global_debug_counter == WORK_ENTRIES);
- global_job_queue_lock.Delete();
-
- Log("Final incremented value: %d\n", global_debug_counter);
-}
-
-#else
-f64 DqnTimer_NowInMs() { return 0; }
-f64 DqnTimer_NowInS() { return 0; }
-#endif // DQN_PLATFORM_HEADER
-
-#include
-void DqnQuickSort_Test()
-{
- LOG_HEADER();
- auto state = DqnRndPCG();
- if (1)
- {
- auto stack = DqnMemStack(DQN_KILOBYTE(1), Dqn::ZeroMem::Yes, 0, DqnMemTracker::Flag::Simple);
-
- // Create array of ints
- u32 num_ints = 1000000;
- u32 size_in_bytes = sizeof(u32) * num_ints;
- u32 *dqn_cpp_array = (u32 *)stack.Push_(size_in_bytes);
- u32 *std_array = (u32 *)stack.Push_(size_in_bytes);
- DQN_ASSERT(dqn_cpp_array && std_array);
-
- f64 dqn_cpp_timings[2] = {};
- f64 std_timings[DQN_ARRAY_COUNT(dqn_cpp_timings)] = {};
-
- f64 dqn_cpp_avg = 0;
- f64 std_avg = 0;
-
- Log("Timings"); global_indent++;
- for (u32 timingsIndex = 0; timingsIndex < DQN_ARRAY_COUNT(dqn_cpp_timings); timingsIndex++)
- {
- // Populate with random numbers
- for (u32 i = 0; i < num_ints; i++)
- {
- dqn_cpp_array[i] = state.Next();
- std_array[i] = dqn_cpp_array[i];
- }
-
- global_new_line = false;
- Log("%02d: ", timingsIndex);
- global_indent -= 2;
- // Time Dqn_QuickSort
- {
- f64 start = DqnTimer_NowInS();
- DqnQuickSort(dqn_cpp_array, num_ints);
-
- f64 duration = DqnTimer_NowInS() - start;
- dqn_cpp_timings[timingsIndex] = duration;
- dqn_cpp_avg += duration;
- Log("Dqn_QuickSort: %f vs ", dqn_cpp_timings[timingsIndex]);
- }
-
- // Time std::sort
- global_new_line = true;
- {
- f64 start = DqnTimer_NowInS();
- std::sort(std_array, std_array + num_ints);
- f64 duration = DqnTimer_NowInS() - start;
-
- std_timings[timingsIndex] = duration;
- std_avg += duration;
-
- Log("std::sort: %f", std_timings[timingsIndex]);
- }
- global_indent += 2;
-
- // Validate algorithm is correct
- for (u32 i = 0; i < num_ints; i++)
- {
- DQN_ASSERTM(dqn_cpp_array[i] == std_array[i], "DqnArray[%d]: %d, std_array[%d]: %d", i,
- dqn_cpp_array[i], std_array[i], i);
- }
- }
- global_indent--;
-
- // Print averages
- if (1)
- {
- dqn_cpp_avg /= (f64)DQN_ARRAY_COUNT(dqn_cpp_timings);
- std_avg /= (f64)DQN_ARRAY_COUNT(std_timings);
- Log("Average Timings");
- global_indent++;
- Log("Dqn_QuickSort: %f vs std::sort: %f\n", dqn_cpp_avg, std_avg);
- global_indent--;
- }
- stack.Free();
- Log(Status::Ok, "QuickSort");
- }
-}
-
-void DqnBSearch_Test()
-{
- LOG_HEADER();
- if (1)
- {
- u32 array[] = {1, 2, 3};
- i64 result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 1);
- DQN_ASSERT(result == 0);
-
- result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 2);
- DQN_ASSERT(result == 1);
-
- result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 3);
- DQN_ASSERT(result == 2);
-
- result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 4);
- DQN_ASSERT(result == -1);
- Log(Status::Ok, "With odd sized array and custom compare");
- }
-
- if (1)
- {
- i64 array[] = {1, 2, 3, 4};
- i64 result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 1);
- DQN_ASSERT(result == 0);
-
- result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 2);
- DQN_ASSERT(result == 1);
-
- result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 3);
- DQN_ASSERT(result == 2);
-
- result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 4);
- DQN_ASSERT(result == 3);
-
- result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 5);
- DQN_ASSERT(result == -1);
- Log(Status::Ok, "With even sized array");
- }
-
- if (1)
- {
- i64 array[] = {1, 2, 3};
- i64 result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 0, DqnBSearchType::MinusOne);
- DQN_ASSERT(result == -1);
-
- result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 1, DqnBSearchType::MinusOne);
- DQN_ASSERT(result == -1);
-
- result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 2, DqnBSearchType::MinusOne);
- DQN_ASSERT(result == 0);
-
- result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 3, DqnBSearchType::MinusOne);
- DQN_ASSERT(result == 1);
-
- result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 4, DqnBSearchType::MinusOne);
- DQN_ASSERT(result == 2);
-
- result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 5, DqnBSearchType::MinusOne);
- DQN_ASSERT(result == 2);
- Log(Status::Ok, "Lower bound with odd sized array");
- }
-
- if (1)
- {
- i64 array[] = {1, 2, 3, 4};
-
- i64 result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 0, DqnBSearchType::MinusOne);
- DQN_ASSERT(result == -1);
-
- result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 1, DqnBSearchType::MinusOne);
- DQN_ASSERT(result == -1);
-
- result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 2, DqnBSearchType::MinusOne);
- DQN_ASSERT(result == 0);
-
- result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 3, DqnBSearchType::MinusOne);
- DQN_ASSERT(result == 1);
-
- result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 4, DqnBSearchType::MinusOne);
- DQN_ASSERT(result == 2);
-
- result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 5, DqnBSearchType::MinusOne);
- DQN_ASSERT(result == 3);
-
- result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 6, DqnBSearchType::MinusOne);
- DQN_ASSERT(result == 3);
- Log(Status::Ok, "Lower bound with even sized array");
- }
-
- if (1)
- {
- i64 array[] = {1, 2, 3};
- i64 result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 0, DqnBSearchType::PlusOne);
- DQN_ASSERT(result == 0);
-
- result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 1, DqnBSearchType::PlusOne);
- DQN_ASSERT(result == 1);
-
- result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 2, DqnBSearchType::PlusOne);
- DQN_ASSERT(result == 2);
-
- result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 3, DqnBSearchType::PlusOne);
- DQN_ASSERT(result == -1);
-
- result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 4, DqnBSearchType::PlusOne);
- DQN_ASSERT(result == -1);
-
- result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 5, DqnBSearchType::PlusOne);
- DQN_ASSERT(result == -1);
- Log(Status::Ok, "Higher bound with odd sized array");
- }
-
- if (1)
- {
- i64 array[] = {1, 2, 3, 4};
-
- i64 result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 0, DqnBSearchType::PlusOne);
- DQN_ASSERT(result == 0);
-
- result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 1, DqnBSearchType::PlusOne);
- DQN_ASSERT(result == 1);
-
- result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 2, DqnBSearchType::PlusOne);
- DQN_ASSERT(result == 2);
-
- result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 3, DqnBSearchType::PlusOne);
- DQN_ASSERT(result == 3);
-
- result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 4, DqnBSearchType::PlusOne);
- DQN_ASSERT(result == -1);
-
- result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 5, DqnBSearchType::PlusOne);
- DQN_ASSERT(result == -1);
-
- result = DqnBSearch(array, DQN_ARRAY_COUNT(array), 6, DqnBSearchType::PlusOne);
- DQN_ASSERT(result == -1);
- Log(Status::Ok, "Higher bound with even sized array");
- }
-}
-
-void DqnMemSet_Test()
-{
- LOG_HEADER();
- auto rnd = DqnRndPCG();
-
- const int NUM_TIMINGS = 5;
- f64 timings[2][NUM_TIMINGS] = {};
- f64 avg_timings[DQN_ARRAY_COUNT(timings)] = {};
- void *buffers[DQN_ARRAY_COUNT(timings)] = {};
-
- const i32 NUM_ITERATIONS = DQN_ARRAY_COUNT(timings[0]);
- Log("Timings");
- for (auto i = 0; i < NUM_ITERATIONS; i++)
- {
- i32 size = rnd.Range(DQN_MEGABYTE(16), DQN_MEGABYTE(32));
- u8 value = (u8)rnd.Range(0, 255);
-
- global_indent++;
- global_new_line = false;
- Log("%02d: ", i);
- global_indent--;
- global_indent--;
-
- i32 timingsIndex = 0;
- // DqnMem_Set
- {
- buffers[timingsIndex] = malloc(size); DQN_ASSERT(buffers[timingsIndex]);
-
- f64 start = DqnTimer_NowInMs();
- DqnMem_Set(buffers[timingsIndex], value, size);
- f64 duration = DqnTimer_NowInMs() - start;
-
- timings[timingsIndex++][i] = duration;
- Log("DqnMem_Set: %5.3f vs ", duration);
- }
-
-
- // crt memset
- {
- buffers[timingsIndex] = malloc(size); DQN_ASSERT(buffers[timingsIndex]);
-
- f64 start = DqnTimer_NowInMs();
- memset(buffers[timingsIndex], value, size);
- f64 duration = DqnTimer_NowInMs() - start;
-
- timings[timingsIndex++][i] = duration;
- Log("memset: %5.3f\n", duration);
- }
- global_indent++;
- global_new_line = true;
-
- for (auto test_index = 0; test_index < size; test_index++)
- {
- DQN_ASSERT(((u8 *)buffers[0])[test_index] == ((u8 *)buffers[1])[test_index]);
- }
-
- for (usize bufferIndex = 0; bufferIndex < DQN_ARRAY_COUNT(buffers); bufferIndex++)
- {
- free(buffers[bufferIndex]);
- }
- }
-
- for (usize timingsIndex = 0; timingsIndex < DQN_ARRAY_COUNT(timings); timingsIndex++)
- {
- f64 total_time = 0;
- for (auto iteration_index = 0; iteration_index < NUM_ITERATIONS; iteration_index++)
- {
- total_time += timings[timingsIndex][iteration_index];
- }
- avg_timings[timingsIndex] = total_time / (f64)NUM_ITERATIONS;
- }
-
- Log("Average Timings");
- global_indent++;
- Log("DqnMem_Set: %f vs memset: %f\n", avg_timings[0], avg_timings[1]);
- global_indent--;
-
- Log(Status::Ok, "MemSet");
-}
-
-struct RawBuf
-{
- char *buffer;
- int len;
-};
-
-DQN_CATALOG_LOAD_PROC(CatalogRawLoad, RawBuf)
-{
- usize buf_size;
- u8 *buf = DqnFile_ReadAll(file.str, &buf_size);
-
- if (!buf)
- return false;
-
- data->buffer = reinterpret_cast(buf);
- data->len = static_cast(buf_size);
- return true;
-}
-
-void DqnCatalog_Test()
-{
- LOG_HEADER();
-
- DqnCatalog catalog = {};
- catalog.PollAssets();
-
- DqnCatalogPath path = "DqnCatalog_TrackFile";
- DqnFile_Delete(path.str);
-
- // Initially write the file and check the catalog is able to open it up
- {
- char const write_buf[] = "aaaa";
- DqnFile_WriteAll(path.str, reinterpret_cast(write_buf), DQN_CHAR_COUNT(write_buf));
- RawBuf *buf = catalog.GetIfUpdated(path);
- DQN_ASSERT(DqnMem_Cmp(buf->buffer, write_buf, DQN_CHAR_COUNT(write_buf)) == 0);
- Log(Status::Ok, "Catalog finds and loads on demand new file");
- }
-
- // Update the file and check that the GetIfUpdated returns a non-nullptr (because the entry is updated)
- {
- PlatformSleep(1000);
- char const write_buf[] = "xxxx";
- DqnFile_WriteAll(path.str, reinterpret_cast(write_buf), DQN_CHAR_COUNT(write_buf));
- RawBuf *buf = catalog.GetIfUpdated(path);
- DQN_ASSERT(DqnMem_Cmp(buf->buffer, write_buf, DQN_CHAR_COUNT(write_buf)) == 0);
- Log(Status::Ok, "Catalog finds updated file after subsequent write");
- }
-
- // Update the file and get the catalog to poll the entries and check it has been updated
- {
- PlatformSleep(1000);
- char const write_buf[] = "abcd";
- DqnFile_WriteAll(path.str, reinterpret_cast(write_buf), DQN_CHAR_COUNT(write_buf));
- catalog.PollAssets();
-
- RawBuf *buf = catalog.GetIfUpdated(path);
- DQN_ASSERT(DqnMem_Cmp(buf->buffer, write_buf, DQN_CHAR_COUNT(write_buf)) == 0);
- Log(Status::Ok, "Catalog finds updated file using the poll asset interface");
- }
-
- // Update the file and get the catalog to poll the entries and check it has been updated
- {
- catalog.Erase(path.str);
- RawBuf *buf = catalog.Get(path);
- DQN_ASSERT(buf == nullptr);
- Log(Status::Ok, "Catalog erase removes file from catalog");
- }
-
- DqnFile_Delete(path.str);
-}
-
-int main(void)
-{
- global_indent = 1;
- global_new_line = true;
- DqnString_Test();
- DqnMemStack_Test();
- DqnChar_Test();
- DqnRnd_Test();
- DqnMath_Test();
- DqnVX_Test();
- DqnRect_Test();
- DqnArray_Test();
- DqnQuickSort_Test();
- DqnBSearch_Test();
- DqnMemSet_Test();
- DqnFixedString_Test();
- DqnJson_Test();
-
-#ifdef DQN_PLATFORM_HEADER
- DqnVHashTable_Test();
- DqnOS_Test();
- DqnFile_Test();
- DqnCatalog_Test();
- DqnTimer_Test();
- DqnJobQueue_Test();
-#endif
-
- // Log("\nPress 'Enter' Key to Exit\n");
- // getchar();
-
- return 0;
-}
-
-#if defined(__GNUC__)
- #pragma GCC diagnostic pop
-#endif
-
diff --git a/Code/Deprecated/DqnUnitTest.sln b/Code/Deprecated/DqnUnitTest.sln
deleted file mode 100644
index cadd90f..0000000
--- a/Code/Deprecated/DqnUnitTest.sln
+++ /dev/null
@@ -1,32 +0,0 @@
-
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.27428.2037
-MinimumVisualStudioVersion = 10.0.40219.1
-Project("{911E67C6-3D85-4FCE-B560-20A9C3E3FF48}") = "DqnUnitTest", "bin\DqnUnitTest.exe", "{F1606403-E704-4C35-8354-8E33DE4F5CCF}"
- ProjectSection(DebuggerProjectSystem) = preProject
- PortSupplier = 00000000-0000-0000-0000-000000000000
- Executable = F:\dev\dqn\bin\DqnUnitTest.exe
- RemoteMachine = THAI-XPS13
- StartingDirectory = F:\dev\dqn\
- Environment = Default
- LaunchingEngine = 00000000-0000-0000-0000-000000000000
- UseLegacyDebugEngines = No
- LaunchSQLEngine = No
- AttachLaunchAction = No
- EndProjectSection
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Release|x64 = Release|x64
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {F1606403-E704-4C35-8354-8E33DE4F5CCF}.Release|x64.ActiveCfg = Release|x64
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
- GlobalSection(ExtensibilityGlobals) = postSolution
- SolutionGuid = {8DD71C86-534C-4A9C-A217-CBA13DE8DA5A}
- EndGlobalSection
-EndGlobal
diff --git a/Code/Deprecated/DqnVHashTable.cpp b/Code/Deprecated/DqnVHashTable.cpp
deleted file mode 100644
index 516a124..0000000
--- a/Code/Deprecated/DqnVHashTable.cpp
+++ /dev/null
@@ -1,88 +0,0 @@
-void DqnVHashTable_Test()
-{
- LOG_HEADER();
- struct Block
- {
- int x;
- };
- using Height = u32;
-
- {
- Block block = {};
-
- DqnVHashTable table = {};
- DQN_DEFER { table.Free(); };
- table.Set(12, block);
-
- Block *getResult = table.Get(12);
- Block *operatorResult = table[12];
- DQN_ASSERT(operatorResult == getResult);
- DQN_ASSERT(operatorResult != nullptr);
- Log(Status::Ok, "Set and get element using key");
-
- table.Erase(12);
- getResult = table.Get(12);
- operatorResult = table[12];
-
- DQN_ASSERT(operatorResult == getResult);
- DQN_ASSERT(operatorResult == nullptr);
- Log(Status::Ok, "Erase element using key");
- }
-
- {
- Block blocks[] = {{0}, {1}, {2}, {3}, {4}};
- DqnVHashTable table = {};
- DQN_DEFER { table.Free(); };
-
- table.Set(1, blocks[0]);
- table.Set(2, blocks[1]);
- table.Set(3, blocks[2]);
- table.Set(4, blocks[3]);
- table.Set(5, blocks[4]);
-
- {
- bool blockSeen[DQN_ARRAY_COUNT(blocks)] = {};
- isize blocksSeen = 0;
- for (auto const &entry : table)
- {
- Block const *block = &entry.item;
- DQN_ASSERT(blockSeen[block->x] == false);
- blockSeen[block->x] = true;
- blocksSeen++;
- }
- DQN_ASSERT(blocksSeen == DQN_ARRAY_COUNT(blockSeen));
- Log(Status::Ok, "Auto iterator using prefix operator++");
- }
-
- {
- bool blockSeen[DQN_ARRAY_COUNT(blocks)] = {};
- isize blocksSeen = 0;
- for (auto it = table.begin(); it != table.end();)
- {
- Block *block = &it.entry->item;
-
- DQN_ASSERT(blockSeen[block->x] == false);
- blockSeen[block->x] = true;
- blocksSeen++;
- it = it + 1;
- }
- DQN_ASSERT(blocksSeen == DQN_ARRAY_COUNT(blockSeen));
- Log(Status::Ok, "Auto iterator using operator+");
- }
-
- {
- bool blockSeen[DQN_ARRAY_COUNT(blocks)] = {};
- isize blocksSeen = 0;
- for (auto it = table.begin(); it != table.end(); it++)
- {
- Block *block = &it.entry->item;
-
- DQN_ASSERT(blockSeen[block->x] == false);
- blockSeen[block->x] = true;
- blocksSeen++;
- }
- DQN_ASSERT(blocksSeen == DQN_ARRAY_COUNT(blockSeen));
- Log(Status::Ok, "Auto iterator using postfix operator++");
- }
- }
-}
diff --git a/Code/Deprecated/HandmadeMath.h b/Code/Deprecated/HandmadeMath.h
deleted file mode 100644
index 9617995..0000000
--- a/Code/Deprecated/HandmadeMath.h
+++ /dev/null
@@ -1,2667 +0,0 @@
-#ifdef __GNUC__
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wpsabi"
-#endif
-/*
- HandmadeMath.h v1.1.2
-
- This is a single header file with a bunch of useful functions for
- basic game math operations.
-
- ==========================================================================
-
- You MUST
-
- #define HANDMADE_MATH_IMPLEMENTATION
-
- in EXACTLY one C or C++ file that includes this header, BEFORE the
- include, like this:
-
- #define HANDMADE_MATH_IMPLEMENTATION
- #include "HandmadeMath.h"
-
- All other files should just #include "HandmadeMath.h" without the #define.
-
- ==========================================================================
-
- For overloaded and operator overloaded versions of the base C functions,
- you MUST
-
- #define HANDMADE_MATH_CPP_MODE
-
- in EXACTLY one C or C++ file that includes this header, BEFORE the
- include, like this:
-
- #define HANDMADE_MATH_IMPLEMENTATION
- #define HANDMADE_MATH_CPP_MODE
- #include "HandmadeMath.h"
-
- All other files should just #include "HandmadeMath.h" without the #define.
-
- ==========================================================================
-
- To disable SSE intrinsics, you MUST
-
- #define HANDMADE_MATH_NO_SSE
-
- in EXACTLY one C or C++ file that includes this header, BEFORE the
- include, like this:
-
- #define HANDMADE_MATH_IMPLEMENTATION
- #define HANDMADE_MATH_CPP_MODE
- #define HANDMADE_MATH_NO_SSE
- #include "HandmadeMath.h"
-
- or
-
- #define HANDMADE_MATH_IMPLEMENTATION
- #define HANDMADE_MATH_NO_SSE
- #include "HandmadeMath.h"
-
- ==========================================================================
-
- To disable inlining functions, you MUST
-
- #define HANDMADE_MATH_NO_INLINE
-
- in EXACTLY one C or C++ file that includes this header, BEFORE the
- include, like this:
-
- #define HANDMADE_MATH_IMPLEMENTATION
- #define HANDMADE_MATH_CPP_MODE
- #define HANDMADE_MATH_NO_INLINE
- #include "HandmadeMath.h"
-
- All other files should just #include "HandmadeMath.h" without the #define.
-
- ==========================================================================
-
- To Disable the CRT, you MUST
-
- #define HMM_SINF MySinF
- #define HMM_COSF MyCosF
- #define HMM_TANF MyTanF
- #define HMM_EXPF MyExpF
- #define HMM_LOGF MyLogF
- #define HMM_ACOSF MyACosF
- #define HMM_ATANF MyATanF
- #define HMM_ATAN2F MYATan2F
-
- Provide your own implementations of SinF, CosF, TanF, ACosF, ATanF, ATan2F, ExpF and LogF
- in EXACTLY one C or C++ file that includes this header, BEFORE the
- include, like this:
-
- #define HMM_SINF MySinF
- #define HMM_COSF MyCosF
- #define HMM_TANF MyTanF
- #define HMM_EXPF MyExpF
- #define HMM_LOGF MyLogF
- #define HMM_ACOSF MyACosF
- #define HMM_ATANF MyATanF
- #define HMM_ATAN2F MyATan2F
- #define HANDMADE_MATH_IMPLEMENTATION
- #define HANDMADE_MATH_CPP_MODE
- #include "HandmadeMath.h"
-
- If you do not define all five of these, HandmadeMath.h will use the
- versions of these functions that are provided by the CRT.
-
- ==========================================================================
-
- Version History:
- 0.2 (*) Updated documentation
- (*) Better C compliance
- (*) Prefix all handmade math functions
- (*) Better operator overloading
- 0.2a
- (*) Prefixed Macros
- 0.2b
- (*) Disabled warning 4201 on MSVC as it is legal is C11
- (*) Removed the f at the end of HMM_PI to get 64bit precision
- 0.3
- (*) Added +=, -=, *=, /= for hmm_vec2, hmm_vec3, hmm_vec4
- 0.4
- (*) SSE Optimized HMM_SqrtF
- (*) SSE Optimized HMM_RSqrtF
- (*) Removed CRT
- 0.5
- (*) Added scalar multiplication and division for vectors
- and matrices
- (*) Added matrix subtraction and += for hmm_mat4
- (*) Reconciled all headers and implementations
- (*) Tidied up, and filled in a few missing operators
- 0.5.1
- (*) Ensured column-major order for matrices throughout
- (*) Fixed HMM_Translate producing row-major matrices
- 0.5.2
- (*) Fixed SSE code in HMM_SqrtF
- (*) Fixed SSE code in HMM_RSqrtF
- 0.6
- (*) Added Unit testing
- (*) Made HMM_Power faster
- (*) Fixed possible efficiency problem with HMM_Normalize
- (*) RENAMED HMM_LengthSquareRoot to HMM_LengthSquared
- (*) RENAMED HMM_RSqrtF to HMM_RSquareRootF
- (*) RENAMED HMM_SqrtF to HMM_SquareRootF
- (*) REMOVED Inner function (user should use Dot now)
- (*) REMOVED HMM_FastInverseSquareRoot function declaration
- 0.7
- (*) REMOVED HMM_LengthSquared in HANDMADE_MATH_IMPLEMENTATION (should use
- HMM_LengthSquaredVec3, or HANDMADE_MATH_CPP_MODE for function overloaded version)
- (*) REMOVED HMM_Length in HANDMADE_MATH_IMPLEMENTATION (should use HMM_LengthVec3,
- HANDMADE_MATH_CPP_MODE for function overloaded version)
- (*) REMOVED HMM_Normalize in HANDMADE_MATH_IMPLEMENTATION (should use HMM_NormalizeVec3,
- or HANDMADE_MATH_CPP_MODE for function overloaded version)
- (*) Added HMM_LengthSquaredVec2
- (*) Added HMM_LengthSquaredVec4
- (*) Addd HMM_LengthVec2
- (*) Added HMM_LengthVec4
- (*) Added HMM_NormalizeVec2
- (*) Added HMM_NormalizeVec4
- 1.0
- (*) Lots of testing!
- 1.1
- (*) Quaternion support
- (*) Added type hmm_quaternion
- (*) Added HMM_Quaternion
- (*) Added HMM_QuaternionV4
- (*) Added HMM_AddQuaternion
- (*) Added HMM_SubtractQuaternion
- (*) Added HMM_MultiplyQuaternion
- (*) Added HMM_MultiplyQuaternionF
- (*) Added HMM_DivideQuaternionF
- (*) Added HMM_InverseQuaternion
- (*) Added HMM_DotQuaternion
- (*) Added HMM_NormalizeQuaternion
- (*) Added HMM_Slerp
- (*) Added HMM_QuaternionToMat4
- (*) Added HMM_QuaternionFromAxisAngle
- 1.1.1
- (*) Resolved compiler warnings on gcc and g++
- 1.1.2
- (*) Fixed invalid HMMDEF's in the function definitions
- 1.1.3
- (*) Fixed compile error in C mode
-
- LICENSE
-
- This software is in the public domain. Where that dedication is not
- recognized, you are granted a perpetual, irrevocable license to copy,
- distribute, and modify this file as you see fit.
-
- CREDITS
-
- Written by Zakary Strange (zak@handmade.network && @strangezak)
-
- Functionality:
- Matt Mascarenhas (@miblo_)
- Aleph
- FieryDrake (@fierydrake)
- Gingerbill (@TheGingerBill)
- Ben Visness (@bvisness)
- Trinton Bullard (@Peliex_Dev)
-
- Fixes:
- Jeroen van Rijn (@J_vanRijn)
- Kiljacken (@Kiljacken)
- Insofaras (@insofaras)
-*/
-
-#ifndef HANDMADE_NO_SSE
-#include
-#endif
-
-#ifndef HANDMADE_MATH_H
-#define HANDMADE_MATH_H
-
-#ifdef _MSC_VER
-#pragma warning(disable:4201)
-#endif
-
-#ifdef __clang__
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wgnu-anonymous-struct"
-#endif
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif
-
-#ifdef HANDMADE_MATH_STATIC
-#define HMMDEF static
-#else
-#define HMMDEF extern
-#endif
-
-#ifdef HANDMADE_MATH_NO_INLINE
-#define HINLINE
-#elif _MSC_VER && !__INTEL_COMPILER
-#define HINLINE __inline
-#else
-#define HINLINE inline
-#endif
-
-#if !defined(HMM_SINF) || !defined(HMM_COSF) || !defined(HMM_TANF) || \
- !defined(HMM_EXPF) || !defined(HMM_LOGF) || !defined(HMM_ACOSF) || \
- !defined(HMM_ATANF)|| !defined(HMM_ATAN2F)
-#include
-#endif
-
-#ifndef HMM_SINF
-#define HMM_SINF sinf
-#endif
-
-#ifndef HMM_COSF
-#define HMM_COSF cosf
-#endif
-
-#ifndef HMM_TANF
-#define HMM_TANF tanf
-#endif
-
-#ifndef HMM_EXPF
-#define HMM_EXPF expf
-#endif
-
-#ifndef HMM_LOGF
-#define HMM_LOGF logf
-#endif
-
-#ifndef HMM_ACOSF
-#define HMM_ACOSF acosf
-#endif
-
-#ifndef HMM_ATANF
-#define HMM_ATANF atanf
-#endif
-
-#ifndef HMM_ATAN2F
-#define HMM_ATAN2F atan2f
-#endif
-
-#define HMM_PI32 3.14159265359f
-#define HMM_PI 3.14159265358979323846
-
-#define HMM_MIN(a, b) (a) > (b) ? (b) : (a)
-#define HMM_MAX(a, b) (a) < (b) ? (b) : (a)
-#define HMM_ABS(a) ((a) > 0 ? (a) : -(a))
-#define HMM_MOD(a, m) ((a) % (m)) >= 0 ? ((a) % (m)) : (((a) % (m)) + (m))
-#define HMM_SQUARE(x) ((x) * (x))
-
-typedef union hmm_vec2
-{
- struct
- {
- float X, Y;
- };
-
- struct
- {
- float U, V;
- };
-
- struct
- {
- float Left, Right;
- };
-
- float Elements[2];
-} hmm_vec2;
-
-typedef union hmm_vec3
-{
- struct
- {
- float X, Y, Z;
- };
-
- struct
- {
- float U, V, W;
- };
-
- struct
- {
- float R, G, B;
- };
-
- struct
- {
- hmm_vec2 XY;
- float Ignored0_;
- };
-
- struct
- {
- float Ignored1_;
- hmm_vec2 YZ;
- };
-
- struct
- {
- hmm_vec2 UV;
- float Ignored2_;
- };
-
- struct
- {
- float Ignored3_;
- hmm_vec2 VW;
- };
-
- float Elements[3];
-} hmm_vec3;
-
-typedef union hmm_vec4
-{
- struct
- {
- union
- {
- hmm_vec3 XYZ;
- struct
- {
- float X, Y, Z;
- };
- };
-
- float W;
- };
- struct
- {
- union
- {
- hmm_vec3 RGB;
- struct
- {
- float R, G, B;
- };
- };
-
- float A;
- };
-
- struct
- {
- hmm_vec2 XY;
- float Ignored0_;
- float Ignored1_;
- };
-
- struct
- {
- float Ignored2_;
- hmm_vec2 YZ;
- float Ignored3_;
- };
-
- struct
- {
- float Ignored4_;
- float Ignored5_;
- hmm_vec2 ZW;
- };
-
- float Elements[4];
-} hmm_vec4;
-
-typedef union hmm_mat4
-{
- float Elements[4][4];
-} hmm_mat4;
-
-typedef union hmm_quaternion
-{
- struct
- {
- union
- {
- hmm_vec3 XYZ;
- struct
- {
- float X, Y, Z;
- };
- };
-
- float W;
- };
-
- float Elements[4];
-} hmm_quaternion;
-
-typedef hmm_vec2 hmm_v2;
-typedef hmm_vec3 hmm_v3;
-typedef hmm_vec4 hmm_v4;
-typedef hmm_mat4 hmm_m4;
-
-HMMDEF float HMM_SinF(float Angle);
-HMMDEF float HMM_TanF(float Angle);
-HMMDEF float HMM_ATanF(float Theta);
-HMMDEF float HMM_ATan2F(float Theta, float Theta2);
-HMMDEF float HMM_CosF(float Angle);
-HMMDEF float HMM_ACosF(float Theta);
-HMMDEF float HMM_ExpF(float Float);
-HMMDEF float HMM_LogF(float Float);
-
-HMMDEF float HMM_ToRadians(float Degrees);
-HMMDEF float HMM_SquareRootF(float Float);
-HMMDEF float HMM_RSquareRootF(float Float);
-
-HMMDEF float HMM_LengthSquaredVec2(hmm_vec2 A);
-HMMDEF float HMM_LengthSquaredVec3(hmm_vec3 A);
-HMMDEF float HMM_LengthSquaredVec4(hmm_vec4 A);
-
-HMMDEF float HMM_LengthVec2(hmm_vec2 A);
-HMMDEF float HMM_LengthVec3(hmm_vec3 A);
-HMMDEF float HMM_LengthVec4(hmm_vec4 A);
-
-HMMDEF float HMM_Power(float Base, int Exponent);
-HMMDEF float HMM_PowerF(float Base, float Exponent);
-HMMDEF float HMM_Lerp(float A, float Time, float B);
-HMMDEF float HMM_Clamp(float Min, float Value, float Max);
-
-HMMDEF hmm_vec2 HMM_NormalizeVec2(hmm_vec2 A);
-HMMDEF hmm_vec3 HMM_NormalizeVec3(hmm_vec3 A);
-HMMDEF hmm_vec4 HMM_NormalizeVec4(hmm_vec4 A);
-
-HMMDEF float HMM_DotVec2(hmm_vec2 VecOne, hmm_vec2 VecTwo);
-HMMDEF float HMM_DotVec3(hmm_vec3 VecOne, hmm_vec3 VecTwo);
-HMMDEF float HMM_DotVec4(hmm_vec4 VecOne, hmm_vec4 VecTwo);
-
-HMMDEF hmm_vec3 HMM_Cross(hmm_vec3 VecOne, hmm_vec3 VecTwo);
-
-HMMDEF hmm_vec2 HMM_Vec2(float X, float Y);
-HMMDEF hmm_vec2 HMM_Vec2i(int X, int Y);
-HMMDEF hmm_vec3 HMM_Vec3(float X, float Y, float Z);
-HMMDEF hmm_vec3 HMM_Vec3i(int X, int Y, int Z);
-HMMDEF hmm_vec4 HMM_Vec4(float X, float Y, float Z, float W);
-HMMDEF hmm_vec4 HMM_Vec4i(int X, int Y, int Z, int W);
-HMMDEF hmm_vec4 HMM_Vec4v(hmm_vec3 Vector, float W);
-
-HMMDEF hmm_vec2 HMM_AddVec2(hmm_vec2 Left, hmm_vec2 Right);
-HMMDEF hmm_vec3 HMM_AddVec3(hmm_vec3 Left, hmm_vec3 Right);
-HMMDEF hmm_vec4 HMM_AddVec4(hmm_vec4 Left, hmm_vec4 Right);
-
-HMMDEF hmm_vec2 HMM_SubtractVec2(hmm_vec2 Left, hmm_vec2 Right);
-HMMDEF hmm_vec3 HMM_SubtractVec3(hmm_vec3 Left, hmm_vec3 Right);
-HMMDEF hmm_vec4 HMM_SubtractVec4(hmm_vec4 Left, hmm_vec4 Right);
-
-HMMDEF hmm_vec2 HMM_MultiplyVec2(hmm_vec2 Left, hmm_vec2 Right);
-HMMDEF hmm_vec2 HMM_MultiplyVec2f(hmm_vec2 Left, float Right);
-HMMDEF hmm_vec3 HMM_MultiplyVec3(hmm_vec3 Left, hmm_vec3 Right);
-HMMDEF hmm_vec3 HMM_MultiplyVec3f(hmm_vec3 Left, float Right);
-HMMDEF hmm_vec4 HMM_MultiplyVec4(hmm_vec4 Left, hmm_vec4 Right);
-HMMDEF hmm_vec4 HMM_MultiplyVec4f(hmm_vec4 Left, float Right);
-
-HMMDEF hmm_vec2 HMM_DivideVec2(hmm_vec2 Left, hmm_vec2 Right);
-HMMDEF hmm_vec2 HMM_DivideVec2f(hmm_vec2 Left, float Right);
-HMMDEF hmm_vec3 HMM_DivideVec3(hmm_vec3 Left, hmm_vec3 Right);
-HMMDEF hmm_vec3 HMM_DivideVec3f(hmm_vec3 Left, float Right);
-HMMDEF hmm_vec4 HMM_DivideVec4(hmm_vec4 Left, hmm_vec4 Right);
-HMMDEF hmm_vec4 HMM_DivideVec4f(hmm_vec4 Left, float Right);
-
-HMMDEF hmm_mat4 HMM_Mat4(void);
-HMMDEF hmm_mat4 HMM_Mat4d(float Diagonal);
-HMMDEF hmm_mat4 HMM_AddMat4(hmm_mat4 Left, hmm_mat4 Right);
-HMMDEF hmm_mat4 HMM_SubtractMat4(hmm_mat4 Left, hmm_mat4 Right);
-HMMDEF hmm_mat4 HMM_MultiplyMat4(hmm_mat4 Left, hmm_mat4 Right);
-HMMDEF hmm_mat4 HMM_MultiplyMat4f(hmm_mat4 Matrix, float Scalar);
-HMMDEF hmm_vec4 HMM_MultiplyMat4ByVec4(hmm_mat4 Matrix, hmm_vec4 Vector);
-HMMDEF hmm_mat4 HMM_DivideMat4f(hmm_mat4 Matrix, float Scalar);
-
-HMMDEF hmm_mat4 HMM_Transpose(hmm_mat4 Matrix);
-
-HMMDEF hmm_mat4 HMM_Orthographic(float Left, float Right, float Bottom, float Top, float Near, float Far);
-HMMDEF hmm_mat4 HMM_Perspective(float FOV, float AspectRatio, float Near, float Far);
-
-HMMDEF hmm_mat4 HMM_Translate(hmm_vec3 Translation);
-HMMDEF hmm_mat4 HMM_Rotate(float Angle, hmm_vec3 Axis);
-HMMDEF hmm_mat4 HMM_Scale(hmm_vec3 Scale);
-
-HMMDEF hmm_mat4 HMM_LookAt(hmm_vec3 Eye, hmm_vec3 Center, hmm_vec3 Up);
-
-HMMDEF hmm_quaternion HMM_Quaternion(float X, float Y, float Z, float W);
-HMMDEF hmm_quaternion HMM_QuaternionV4(hmm_vec4 Vector);
-HMMDEF hmm_quaternion HMM_AddQuaternion(hmm_quaternion Left, hmm_quaternion Right);
-HMMDEF hmm_quaternion HMM_SubtractQuaternion(hmm_quaternion Left, hmm_quaternion Right);
-HMMDEF hmm_quaternion HMM_MultiplyQuaternion(hmm_quaternion Left, hmm_quaternion Right);
-HMMDEF hmm_quaternion HMM_MultiplyQuaternionF(hmm_quaternion Left, float Multiplicative);
-HMMDEF hmm_quaternion HMM_DivideQuaternionF(hmm_quaternion Left, float Dividend);
-HMMDEF hmm_quaternion HMM_InverseQuaternion(hmm_quaternion Left);
-HMMDEF float HMM_DotQuaternion(hmm_quaternion Left, hmm_quaternion Right);
-HMMDEF hmm_quaternion HMM_NormalizeQuaternion(hmm_quaternion Left);
-HMMDEF hmm_quaternion HMM_NLerp(hmm_quaternion Left, float Time, hmm_quaternion Right);
-HMMDEF hmm_quaternion HMM_Slerp(hmm_quaternion Left, float Time, hmm_quaternion Right);
-HMMDEF hmm_mat4 HMM_QuaternionToMat4(hmm_quaternion Left);
-HMMDEF hmm_quaternion HMM_QuaternionFromAxisAngle(hmm_vec3 Axis, float AngleOfRotation);
-
-#ifdef __cplusplus
-}
-#endif
-
-#ifdef HANDMADE_MATH_CPP_MODE
-
-HMMDEF float HMM_Length(hmm_vec2 A);
-HMMDEF float HMM_Length(hmm_vec3 A);
-HMMDEF float HMM_Length(hmm_vec4 A);
-
-HMMDEF float HMM_LengthSquared(hmm_vec2 A);
-HMMDEF float HMM_LengthSquared(hmm_vec3 A);
-HMMDEF float HMM_LengthSquared(hmm_vec4 A);
-
-HMMDEF hmm_vec2 HMM_Normalize(hmm_vec2 A);
-HMMDEF hmm_vec3 HMM_Normalize(hmm_vec3 A);
-HMMDEF hmm_vec4 HMM_Normalize(hmm_vec4 A);
-HMMDEF hmm_quaternion HMM_Normalize(hmm_quaternion A);
-
-HMMDEF float HMM_Dot(hmm_vec2 VecOne, hmm_vec2 VecTwo);
-HMMDEF float HMM_Dot(hmm_vec3 VecOne, hmm_vec3 VecTwo);
-HMMDEF float HMM_Dot(hmm_vec4 VecOne, hmm_vec4 VecTwo);
-HMMDEF float HMM_Dot(hmm_quaternion QuatOne, hmm_quaternion QuatTwo);
-
-HMMDEF hmm_vec2 HMM_Add(hmm_vec2 Left, hmm_vec2 Right);
-HMMDEF hmm_vec3 HMM_Add(hmm_vec3 Left, hmm_vec3 Right);
-HMMDEF hmm_vec4 HMM_Add(hmm_vec4 Left, hmm_vec4 Right);
-HMMDEF hmm_mat4 HMM_Add(hmm_mat4 Left, hmm_mat4 Right);
-HMMDEF hmm_quaternion HMM_Add(hmm_quaternion Left, hmm_quaternion Right);
-
-HMMDEF hmm_vec2 HMM_Subtract(hmm_vec2 Left, hmm_vec2 Right);
-HMMDEF hmm_vec3 HMM_Subtract(hmm_vec3 Left, hmm_vec3 Right);
-HMMDEF hmm_vec4 HMM_Subtract(hmm_vec4 Left, hmm_vec4 Right);
-HMMDEF hmm_mat4 HMM_Subtract(hmm_mat4 Left, hmm_mat4 Right);
-HMMDEF hmm_quaternion HMM_Subtract(hmm_quaternion Left, hmm_quaternion Right);
-
-HMMDEF hmm_vec2 HMM_Multiply(hmm_vec2 Left, hmm_vec2 Right);
-HMMDEF hmm_vec2 HMM_Multiply(hmm_vec2 Left, float Right);
-HMMDEF hmm_vec3 HMM_Multiply(hmm_vec3 Left, hmm_vec3 Right);
-HMMDEF hmm_vec3 HMM_Multiply(hmm_vec3 Left, float Right);
-HMMDEF hmm_vec4 HMM_Multiply(hmm_vec4 Left, hmm_vec4 Right);
-HMMDEF hmm_vec4 HMM_Multiply(hmm_vec4 Left, float Right);
-HMMDEF hmm_mat4 HMM_Multiply(hmm_mat4 Left, hmm_mat4 Right);
-HMMDEF hmm_mat4 HMM_Multiply(hmm_mat4 Left, float Right);
-HMMDEF hmm_vec4 HMM_Multiply(hmm_mat4 Matrix, hmm_vec4 Vector);
-HMMDEF hmm_quaternion HMM_Multiply(hmm_quaternion Left, hmm_quaternion Right);
-HMMDEF hmm_quaternion HMM_Multiply(hmm_quaternion Left, float Right);
-
-HMMDEF hmm_vec2 HMM_Divide(hmm_vec2 Left, hmm_vec2 Right);
-HMMDEF hmm_vec2 HMM_Divide(hmm_vec2 Left, float Right);
-HMMDEF hmm_vec3 HMM_Divide(hmm_vec3 Left, hmm_vec3 Right);
-HMMDEF hmm_vec3 HMM_Divide(hmm_vec3 Left, float Right);
-HMMDEF hmm_vec4 HMM_Divide(hmm_vec4 Left, hmm_vec4 Right);
-HMMDEF hmm_vec4 HMM_Divide(hmm_vec4 Left, float Right);
-HMMDEF hmm_mat4 HMM_Divide(hmm_mat4 Left, float Right);
-HMMDEF hmm_quaternion HMM_Divide(hmm_quaternion Left, hmm_quaternion Right);
-HMMDEF hmm_quaternion HMM_Divide(hmm_quaternion Left, float Right);
-
-HMMDEF hmm_vec2 operator+(hmm_vec2 Left, hmm_vec2 Right);
-HMMDEF hmm_vec3 operator+(hmm_vec3 Left, hmm_vec3 Right);
-HMMDEF hmm_vec4 operator+(hmm_vec4 Left, hmm_vec4 Right);
-HMMDEF hmm_mat4 operator+(hmm_mat4 Left, hmm_mat4 Right);
-HMMDEF hmm_quaternion operator+(hmm_quaternion Left, hmm_quaternion Right);
-
-HMMDEF hmm_vec2 operator-(hmm_vec2 Left, hmm_vec2 Right);
-HMMDEF hmm_vec3 operator-(hmm_vec3 Left, hmm_vec3 Right);
-HMMDEF hmm_vec4 operator-(hmm_vec4 Left, hmm_vec4 Right);
-HMMDEF hmm_mat4 operator-(hmm_mat4 Left, hmm_mat4 Right);
-HMMDEF hmm_quaternion operator-(hmm_quaternion Left, hmm_quaternion Right);
-
-HMMDEF hmm_vec2 operator*(hmm_vec2 Left, hmm_vec2 Right);
-HMMDEF hmm_vec3 operator*(hmm_vec3 Left, hmm_vec3 Right);
-HMMDEF hmm_vec4 operator*(hmm_vec4 Left, hmm_vec4 Right);
-HMMDEF hmm_mat4 operator*(hmm_mat4 Left, hmm_mat4 Right);
-HMMDEF hmm_quaternion operator*(hmm_quaternion Left, hmm_quaternion Right);
-
-HMMDEF hmm_vec2 operator*(hmm_vec2 Left, float Right);
-HMMDEF hmm_vec3 operator*(hmm_vec3 Left, float Right);
-HMMDEF hmm_vec4 operator*(hmm_vec4 Left, float Right);
-HMMDEF hmm_mat4 operator*(hmm_mat4 Left, float Right);
-HMMDEF hmm_quaternion operator*(hmm_quaternion Left, float Right);
-
-HMMDEF hmm_vec2 operator*(float Left, hmm_vec2 Right);
-HMMDEF hmm_vec3 operator*(float Left, hmm_vec3 Right);
-HMMDEF hmm_vec4 operator*(float Left, hmm_vec4 Right);
-HMMDEF hmm_mat4 operator*(float Left, hmm_mat4 Right);
-HMMDEF hmm_quaternion operator*(float Left, hmm_quaternion Right);
-
-HMMDEF hmm_vec4 operator*(hmm_mat4 Matrix, hmm_vec4 Vector);
-
-HMMDEF hmm_vec2 operator/(hmm_vec2 Left, hmm_vec2 Right);
-HMMDEF hmm_vec3 operator/(hmm_vec3 Left, hmm_vec3 Right);
-HMMDEF hmm_vec4 operator/(hmm_vec4 Left, hmm_vec4 Right);
-
-HMMDEF hmm_vec2 operator/(hmm_vec2 Left, float Right);
-HMMDEF hmm_vec3 operator/(hmm_vec3 Left, float Right);
-HMMDEF hmm_vec4 operator/(hmm_vec4 Left, float Right);
-HMMDEF hmm_mat4 operator/(hmm_mat4 Left, float Right);
-HMMDEF hmm_quaternion operator/(hmm_quaternion Left, float Right);
-
-HMMDEF hmm_vec2 &operator+=(hmm_vec2 &Left, hmm_vec2 Right);
-HMMDEF hmm_vec3 &operator+=(hmm_vec3 &Left, hmm_vec3 Right);
-HMMDEF hmm_vec4 &operator+=(hmm_vec4 &Left, hmm_vec4 Right);
-HMMDEF hmm_mat4 &operator+=(hmm_mat4 &Left, hmm_mat4 Right);
-HMMDEF hmm_quaternion &operator+=(hmm_quaternion &Left, hmm_quaternion Right);
-
-HMMDEF hmm_vec2 &operator-=(hmm_vec2 &Left, hmm_vec2 Right);
-HMMDEF hmm_vec3 &operator-=(hmm_vec3 &Left, hmm_vec3 Right);
-HMMDEF hmm_vec4 &operator-=(hmm_vec4 &Left, hmm_vec4 Right);
-HMMDEF hmm_mat4 &operator-=(hmm_mat4 &Left, hmm_mat4 Right);
-HMMDEF hmm_quaternion &operator-=(hmm_quaternion &Left, hmm_quaternion Right);
-
-HMMDEF hmm_vec2 &operator*=(hmm_vec2 &Left, hmm_vec2 Right);
-HMMDEF hmm_vec3 &operator*=(hmm_vec3 &Left, hmm_vec3 Right);
-HMMDEF hmm_vec4 &operator*=(hmm_vec4 &Left, hmm_vec4 Right);
-
-HMMDEF hmm_vec2 &operator*=(hmm_vec2 &Left, float Right);
-HMMDEF hmm_vec3 &operator*=(hmm_vec3 &Left, float Right);
-HMMDEF hmm_vec4 &operator*=(hmm_vec4 &Left, float Right);
-HMMDEF hmm_mat4 &operator*=(hmm_mat4 &Left, float Right);
-HMMDEF hmm_quaternion &operator*=(hmm_quaternion &Left, float Right);
-
-HMMDEF hmm_vec2 &operator/=(hmm_vec2 &Left, hmm_vec2 Right);
-HMMDEF hmm_vec3 &operator/=(hmm_vec3 &Left, hmm_vec3 Right);
-HMMDEF hmm_vec4 &operator/=(hmm_vec4 &Left, hmm_vec4 Right);
-
-HMMDEF hmm_vec2 &operator/=(hmm_vec2 &Left, float Right);
-HMMDEF hmm_vec3 &operator/=(hmm_vec3 &Left, float Right);
-HMMDEF hmm_vec4 &operator/=(hmm_vec4 &Left, float Right);
-HMMDEF hmm_mat4 &operator/=(hmm_mat4 &Left, float Right);
-HMMDEF hmm_quaternion &operator/=(hmm_quaternion &Left, float Right);
-
-#endif /* HANDMADE_MATH_CPP */
-
-#ifdef __clang__
-#pragma GCC diagnostic pop
-#endif
-
-#endif /* HANDMADE_MATH_H */
-
-#ifdef HANDMADE_MATH_IMPLEMENTATION
-
-HINLINE float
-HMM_SinF(float Angle)
-{
- float Result = 0.0f;
-
- Result = HMM_SINF(Angle);
- return (Result);
-}
-
-HINLINE float
-HMM_CosF(float Angle)
-{
- float Result = 0.0f;
-
- Result = HMM_COSF(Angle);
- return (Result);
-}
-
-HINLINE float
-HMM_TanF(float Radians)
-{
- float Result = 0.0f;
-
- Result = HMM_TANF(Radians);
- return (Result);
-}
-
-HINLINE float
-HMM_ACosF(float Radians)
-{
- float Result = 0.0f;
-
- Result = HMM_ACOSF(Radians);
- return (Result);
-}
-
-HINLINE float
-HMM_ATanF(float Radians)
-{
- float Result = 0.0f;
-
- Result = HMM_ATANF(Radians);
- return (Result);
-}
-
-HINLINE float
-HMM_Atan2F(float Left, float Right)
-{
- float Result = 0.0f;
-
- Result = HMM_ATAN2F(Left, Right);
- return (Result);
-}
-
-HINLINE float
-HMM_ExpF(float Float)
-{
- float Result = 0.0f;
-
- Result = HMM_EXPF(Float);
- return (Result);
-}
-
-HINLINE float
-HMM_LogF(float Float)
-{
- float Result = 0.0f;
-
- Result = HMM_LOGF(Float);
- return (Result);
-}
-
-HINLINE float
-HMM_ToRadians(float Degrees)
-{
- float Result = 0.0f;
-
- Result = Degrees * (HMM_PI32 / 180.0f);
- return (Result);
-}
-
-HINLINE float
-HMM_SquareRootF(float Value)
-{
- float Result = 0.0f;
-
-#ifdef HANDMADE_MATH_NO_SSE
- Result = sqrtf(Value);
-#else
- __m128 In = _mm_set_ss(Value);
- __m128 Out = _mm_sqrt_ss(In);
- Result = _mm_cvtss_f32(Out);
-#endif
-
- return(Result);
-}
-
-HINLINE float
-HMM_RSquareRootF(float Value)
-{
- float Result = 0.0f;
-
-#ifdef HANDMADE_MATH_NO_SSE
- Result = 1.0f/HMM_SquareRootF(Value);
-#else
- __m128 In = _mm_set_ss(Value);
- __m128 Out = _mm_rsqrt_ss(In);
- Result = _mm_cvtss_f32(Out);
-#endif
-
- return(Result);
-}
-
-HINLINE float
-HMM_LengthSquaredVec2(hmm_vec2 A)
-{
- float Result = 0.0f;
-
- Result = HMM_DotVec2(A, A);
-
- return(Result);
-}
-
-HINLINE float
-HMM_LengthSquaredVec3(hmm_vec3 A)
-{
- float Result = 0.0f;
-
- Result = HMM_DotVec3(A, A);
-
- return (Result);
-}
-
-HINLINE float
-HMM_LengthSquaredVec4(hmm_vec4 A)
-{
- float Result = 0.0f;
-
- Result = HMM_DotVec4(A, A);
-
- return(Result);
-}
-
-HINLINE float
-HMM_LengthVec2(hmm_vec2 A)
-{
- float Result = 0.0f;
-
- Result = HMM_SquareRootF(HMM_LengthSquaredVec2(A));
-
- return(Result);
-}
-
-HINLINE float
-HMM_LengthVec3(hmm_vec3 A)
-{
- float Result = 0.0f;
-
- Result = HMM_SquareRootF(HMM_LengthSquaredVec3(A));
-
- return (Result);
-}
-
-HINLINE float
-HMM_LengthVec4(hmm_vec4 A)
-{
- float Result = 0.0f;
-
- Result = HMM_SquareRootF(HMM_LengthSquaredVec4(A));
-
- return(Result);
-}
-
-HINLINE float
-HMM_Power(float Base, int Exponent)
-{
- float Result = 1.0f;
- float Mul = Exponent < 0 ? 1.f / Base : Base;
- unsigned int X = Exponent < 0 ? -Exponent : Exponent;
- while (X)
- {
- if (X & 1)
- {
- Result *= Mul;
- }
-
- Mul *= Mul;
- X >>= 1;
- }
-
- return (Result);
-}
-
-HINLINE float
-HMM_PowerF(float Base, float Exponent)
-{
- return HMM_EXPF(Exponent * HMM_LOGF(Base));
-}
-
-HINLINE float
-HMM_Lerp(float A, float Time, float B)
-{
- float Result = 0;
-
- Result = (1.0f - Time) * A + Time * B;
- return (Result);
-}
-
-HINLINE float
-HMM_Clamp(float Min, float Value, float Max)
-{
- float Result = Value;
-
- if(Result < Min)
- {
- Result = Min;
- }
- else if(Result > Max)
- {
- Result = Max;
- }
-
- return (Result);
-}
-
-HINLINE hmm_vec2
-HMM_NormalizeVec2(hmm_vec2 A)
-{
- hmm_vec2 Result = {0};
-
- float VectorLength = HMM_LengthVec2(A);
-
- Result.X = A.X * (1.0f / VectorLength);
- Result.Y = A.Y * (1.0f / VectorLength);
-
- return (Result);
-}
-
-HINLINE hmm_vec3
-HMM_NormalizeVec3(hmm_vec3 A)
-{
- hmm_vec3 Result = {0};
-
- float VectorLength = HMM_LengthVec3(A);
-
- Result.X = A.X * (1.0f / VectorLength);
- Result.Y = A.Y * (1.0f / VectorLength);
- Result.Z = A.Z * (1.0f / VectorLength);
-
- return (Result);
-}
-
-HINLINE hmm_vec4
-HMM_NormalizeVec4(hmm_vec4 A)
-{
- hmm_vec4 Result = {0};
-
- float VectorLength = HMM_LengthVec4(A);
-
- Result.X = A.X * (1.0f / VectorLength);
- Result.Y = A.Y * (1.0f / VectorLength);
- Result.Z = A.Z * (1.0f / VectorLength);
- Result.W = A.W * (1.0f / VectorLength);
-
- return (Result);
-}
-
-HINLINE float
-HMM_DotVec2(hmm_vec2 VecOne, hmm_vec2 VecTwo)
-{
- float Result = 0.0f;
-
- Result = (VecOne.X * VecTwo.X) + (VecOne.Y * VecTwo.Y);
-
- return (Result);
-}
-
-HINLINE float
-HMM_DotVec3(hmm_vec3 VecOne, hmm_vec3 VecTwo)
-{
- float Result = 0.0f;
-
- Result = (VecOne.X * VecTwo.X) + (VecOne.Y * VecTwo.Y) + (VecOne.Z * VecTwo.Z);
-
- return (Result);
-}
-
-HINLINE float
-HMM_DotVec4(hmm_vec4 VecOne, hmm_vec4 VecTwo)
-{
- float Result = 0.0f;
-
- Result = (VecOne.X * VecTwo.X) + (VecOne.Y * VecTwo.Y) + (VecOne.Z * VecTwo.Z) + (VecOne.W * VecTwo.W);
-
- return (Result);
-}
-
-HINLINE hmm_vec3
-HMM_Cross(hmm_vec3 VecOne, hmm_vec3 VecTwo)
-{
- hmm_vec3 Result = {0};
-
- Result.X = (VecOne.Y * VecTwo.Z) - (VecOne.Z * VecTwo.Y);
- Result.Y = (VecOne.Z * VecTwo.X) - (VecOne.X * VecTwo.Z);
- Result.Z = (VecOne.X * VecTwo.Y) - (VecOne.Y * VecTwo.X);
-
- return (Result);
-}
-
-HINLINE hmm_vec2
-HMM_Vec2(float X, float Y)
-{
- hmm_vec2 Result = {0};
-
- Result.X = X;
- Result.Y = Y;
-
- return (Result);
-}
-
-HINLINE hmm_vec2
-HMM_Vec2i(int X, int Y)
-{
- hmm_vec2 Result = {0};
-
- Result.X = (float)X;
- Result.Y = (float)Y;
-
- return (Result);
-}
-
-HINLINE hmm_vec3
-HMM_Vec3(float X, float Y, float Z)
-{
- hmm_vec3 Result = {0};
-
- Result.X = X;
- Result.Y = Y;
- Result.Z = Z;
-
- return (Result);
-}
-
-HINLINE hmm_vec3
-HMM_Vec3i(int X, int Y, int Z)
-{
- hmm_vec3 Result = {0};
-
- Result.X = (float)X;
- Result.Y = (float)Y;
- Result.Z = (float)Z;
-
- return (Result);
-}
-
-HINLINE hmm_vec4
-HMM_Vec4(float X, float Y, float Z, float W)
-{
- hmm_vec4 Result = {0};
-
- Result.X = X;
- Result.Y = Y;
- Result.Z = Z;
- Result.W = W;
-
- return (Result);
-}
-
-HINLINE hmm_vec4
-HMM_Vec4i(int X, int Y, int Z, int W)
-{
- hmm_vec4 Result = {0};
-
- Result.X = (float)X;
- Result.Y = (float)Y;
- Result.Z = (float)Z;
- Result.W = (float)W;
-
- return (Result);
-}
-
-HINLINE hmm_vec4
-HMM_Vec4v(hmm_vec3 Vector, float W)
-{
- hmm_vec4 Result = {0};
-
- Result.XYZ = Vector;
- Result.W = W;
-
- return (Result);
-}
-
-HINLINE hmm_vec2
-HMM_AddVec2(hmm_vec2 Left, hmm_vec2 Right)
-{
- hmm_vec2 Result = {0};
-
- Result.X = Left.X + Right.X;
- Result.Y = Left.Y + Right.Y;
-
- return (Result);
-}
-
-HINLINE hmm_vec3
-HMM_AddVec3(hmm_vec3 Left, hmm_vec3 Right)
-{
- hmm_vec3 Result = {0};
-
- Result.X = Left.X + Right.X;
- Result.Y = Left.Y + Right.Y;
- Result.Z = Left.Z + Right.Z;
-
- return (Result);
-}
-
-HINLINE hmm_vec4
-HMM_AddVec4(hmm_vec4 Left, hmm_vec4 Right)
-{
- hmm_vec4 Result = {0};
-
- Result.X = Left.X + Right.X;
- Result.Y = Left.Y + Right.Y;
- Result.Z = Left.Z + Right.Z;
- Result.W = Left.W + Right.W;
-
- return (Result);
-}
-
-HINLINE hmm_vec2
-HMM_SubtractVec2(hmm_vec2 Left, hmm_vec2 Right)
-{
- hmm_vec2 Result = {0};
-
- Result.X = Left.X - Right.X;
- Result.Y = Left.Y - Right.Y;
-
- return (Result);
-}
-
-HINLINE hmm_vec3
-HMM_SubtractVec3(hmm_vec3 Left, hmm_vec3 Right)
-{
- hmm_vec3 Result = {0};
-
- Result.X = Left.X - Right.X;
- Result.Y = Left.Y - Right.Y;
- Result.Z = Left.Z - Right.Z;
-
- return (Result);
-}
-
-HINLINE hmm_vec4
-HMM_SubtractVec4(hmm_vec4 Left, hmm_vec4 Right)
-{
- hmm_vec4 Result = {0};
-
- Result.X = Left.X - Right.X;
- Result.Y = Left.Y - Right.Y;
- Result.Z = Left.Z - Right.Z;
- Result.W = Left.W - Right.W;
-
- return (Result);
-}
-
-HINLINE hmm_vec2
-HMM_MultiplyVec2(hmm_vec2 Left, hmm_vec2 Right)
-{
- hmm_vec2 Result = {0};
-
- Result.X = Left.X * Right.X;
- Result.Y = Left.Y * Right.Y;
-
- return (Result);
-}
-
-HINLINE hmm_vec2
-HMM_MultiplyVec2f(hmm_vec2 Left, float Right)
-{
- hmm_vec2 Result = {0};
-
- Result.X = Left.X * Right;
- Result.Y = Left.Y * Right;
-
- return (Result);
-}
-
-HINLINE hmm_vec3
-HMM_MultiplyVec3(hmm_vec3 Left, hmm_vec3 Right)
-{
- hmm_vec3 Result = {0};
-
- Result.X = Left.X * Right.X;
- Result.Y = Left.Y * Right.Y;
- Result.Z = Left.Z * Right.Z;
-
- return (Result);
-}
-
-HINLINE hmm_vec3
-HMM_MultiplyVec3f(hmm_vec3 Left, float Right)
-{
- hmm_vec3 Result = {0};
-
- Result.X = Left.X * Right;
- Result.Y = Left.Y * Right;
- Result.Z = Left.Z * Right;
-
- return (Result);
-}
-
-HINLINE hmm_vec4
-HMM_MultiplyVec4(hmm_vec4 Left, hmm_vec4 Right)
-{
- hmm_vec4 Result = {0};
-
- Result.X = Left.X * Right.X;
- Result.Y = Left.Y * Right.Y;
- Result.Z = Left.Z * Right.Z;
- Result.W = Left.W * Right.W;
-
- return (Result);
-}
-
-HINLINE hmm_vec4
-HMM_MultiplyVec4f(hmm_vec4 Left, float Right)
-{
- hmm_vec4 Result = {0};
-
- Result.X = Left.X * Right;
- Result.Y = Left.Y * Right;
- Result.Z = Left.Z * Right;
- Result.W = Left.W * Right;
-
- return (Result);
-}
-
-HINLINE hmm_vec2
-HMM_DivideVec2(hmm_vec2 Left, hmm_vec2 Right)
-{
- hmm_vec2 Result = {0};
-
- Result.X = Left.X / Right.X;
- Result.Y = Left.Y / Right.Y;
-
- return (Result);
-}
-
-HINLINE hmm_vec2
-HMM_DivideVec2f(hmm_vec2 Left, float Right)
-{
- hmm_vec2 Result = {0};
-
- Result.X = Left.X / Right;
- Result.Y = Left.Y / Right;
-
- return (Result);
-}
-
-HINLINE hmm_vec3
-HMM_DivideVec3(hmm_vec3 Left, hmm_vec3 Right)
-{
- hmm_vec3 Result = {0};
-
- Result.X = Left.X / Right.X;
- Result.Y = Left.Y / Right.Y;
- Result.Z = Left.Z / Right.Z;
-
- return (Result);
-}
-
-HINLINE hmm_vec3
-HMM_DivideVec3f(hmm_vec3 Left, float Right)
-{
- hmm_vec3 Result = {0};
-
- Result.X = Left.X / Right;
- Result.Y = Left.Y / Right;
- Result.Z = Left.Z / Right;
-
- return (Result);
-}
-
-HINLINE hmm_vec4
-HMM_DivideVec4(hmm_vec4 Left, hmm_vec4 Right)
-{
- hmm_vec4 Result = {0};
-
- Result.X = Left.X / Right.X;
- Result.Y = Left.Y / Right.Y;
- Result.Z = Left.Z / Right.Z;
- Result.W = Left.W / Right.W;
-
- return (Result);
-}
-
-HINLINE hmm_vec4
-HMM_DivideVec4f(hmm_vec4 Left, float Right)
-{
- hmm_vec4 Result = {0};
-
- Result.X = Left.X / Right;
- Result.Y = Left.Y / Right;
- Result.Z = Left.Z / Right;
- Result.W = Left.W / Right;
-
- return (Result);
-}
-
-HINLINE hmm_mat4
-HMM_Mat4(void)
-{
- hmm_mat4 Result = {0};
-
- return (Result);
-}
-
-HINLINE hmm_mat4
-HMM_Mat4d(float Diagonal)
-{
- hmm_mat4 Result = HMM_Mat4();
-
- Result.Elements[0][0] = Diagonal;
- Result.Elements[1][1] = Diagonal;
- Result.Elements[2][2] = Diagonal;
- Result.Elements[3][3] = Diagonal;
-
- return (Result);
-}
-
-HINLINE hmm_mat4
-HMM_AddMat4(hmm_mat4 Left, hmm_mat4 Right)
-{
- hmm_mat4 Result = HMM_Mat4();
-
- int Columns;
- for(Columns = 0; Columns < 4; ++Columns)
- {
- int Rows;
- for(Rows = 0; Rows < 4; ++Rows)
- {
- Result.Elements[Columns][Rows] = Left.Elements[Columns][Rows] + Right.Elements[Columns][Rows];
- }
- }
-
- return (Result);
-}
-
-HINLINE hmm_mat4
-HMM_SubtractMat4(hmm_mat4 Left, hmm_mat4 Right)
-{
- hmm_mat4 Result = HMM_Mat4();
-
- int Columns;
- for(Columns = 0; Columns < 4; ++Columns)
- {
- int Rows;
- for(Rows = 0; Rows < 4; ++Rows)
- {
- Result.Elements[Columns][Rows] = Left.Elements[Columns][Rows] - Right.Elements[Columns][Rows];
- }
- }
-
- return (Result);
-}
-
-HINLINE hmm_mat4
-HMM_MultiplyMat4(hmm_mat4 Left, hmm_mat4 Right)
-{
- hmm_mat4 Result = HMM_Mat4();
-
- int Columns;
- for(Columns = 0; Columns < 4; ++Columns)
- {
- int Rows;
- for(Rows = 0; Rows < 4; ++Rows)
- {
- float Sum = 0;
- int CurrentMatrice;
- for(CurrentMatrice = 0; CurrentMatrice < 4; ++CurrentMatrice)
- {
- Sum += Left.Elements[CurrentMatrice][Rows] * Right.Elements[Columns][CurrentMatrice];
- }
-
- Result.Elements[Columns][Rows] = Sum;
- }
- }
-
- return (Result);
-}
-
-HINLINE hmm_mat4
-HMM_MultiplyMat4f(hmm_mat4 Matrix, float Scalar)
-{
- hmm_mat4 Result = HMM_Mat4();
-
- int Columns;
- for(Columns = 0; Columns < 4; ++Columns)
- {
- int Rows;
- for(Rows = 0; Rows < 4; ++Rows)
- {
- Result.Elements[Columns][Rows] = Matrix.Elements[Columns][Rows] * Scalar;
- }
- }
-
- return (Result);
-}
-
-HINLINE hmm_vec4
-HMM_MultiplyMat4ByVec4(hmm_mat4 Matrix, hmm_vec4 Vector)
-{
- hmm_vec4 Result = {0};
-
- int Columns, Rows;
- for(Rows = 0; Rows < 4; ++Rows)
- {
- float Sum = 0;
- for(Columns = 0; Columns < 4; ++Columns)
- {
- Sum += Matrix.Elements[Columns][Rows] * Vector.Elements[Columns];
- }
-
- Result.Elements[Rows] = Sum;
- }
-
- return (Result);
-}
-
-HINLINE hmm_mat4
-HMM_DivideMat4f(hmm_mat4 Matrix, float Scalar)
-{
- hmm_mat4 Result = HMM_Mat4();
-
- int Columns;
- for(Columns = 0; Columns < 4; ++Columns)
- {
- int Rows;
- for(Rows = 0; Rows < 4; ++Rows)
- {
- Result.Elements[Columns][Rows] = Matrix.Elements[Columns][Rows] / Scalar;
- }
- }
-
- return (Result);
-}
-
-HINLINE hmm_mat4
-HMM_Transpose(hmm_mat4 Matrix)
-{
- hmm_mat4 Result = HMM_Mat4();
-
- int Columns;
- for(Columns = 0; Columns < 4; ++Columns)
- {
- int Rows;
- for(Rows = 0; Rows < 4; ++Rows)
- {
- Result.Elements[Rows][Columns] = Matrix.Elements[Columns][Rows];
- }
- }
-
- return (Result);
-}
-
-HINLINE hmm_mat4
-HMM_Orthographic(float Left, float Right, float Bottom, float Top, float Near, float Far)
-{
- hmm_mat4 Result = HMM_Mat4d(1.0f);
-
- Result.Elements[0][0] = 2.0f / (Right - Left);
- Result.Elements[1][1] = 2.0f / (Top - Bottom);
- Result.Elements[2][2] = 2.0f / (Near - Far);
-
- Result.Elements[3][0] = (Left + Right) / (Left - Right);
- Result.Elements[3][1] = (Bottom + Top) / (Bottom - Top);
- Result.Elements[3][2] = (Far + Near) / (Near - Far);
-
- return (Result);
-}
-
-HINLINE hmm_mat4
-HMM_Perspective(float FOV, float AspectRatio, float Near, float Far)
-{
- hmm_mat4 Result = HMM_Mat4d(1.0f);
-
- float TanThetaOver2 = HMM_TanF(FOV * (HMM_PI32 / 360.0f));
-
- Result.Elements[0][0] = 1.0f / TanThetaOver2;
- Result.Elements[1][1] = AspectRatio / TanThetaOver2;
- Result.Elements[2][3] = -1.0f;
- Result.Elements[2][2] = (Near + Far) / (Near - Far);
- Result.Elements[3][2] = (2.0f * Near * Far) / (Near - Far);
- Result.Elements[3][3] = 0.0f;
-
- return (Result);
-}
-
-HINLINE hmm_mat4
-HMM_Translate(hmm_vec3 Translation)
-{
- hmm_mat4 Result = HMM_Mat4d(1.0f);
-
- Result.Elements[3][0] = Translation.X;
- Result.Elements[3][1] = Translation.Y;
- Result.Elements[3][2] = Translation.Z;
-
- return (Result);
-}
-
-HINLINE hmm_mat4
-HMM_Rotate(float Angle, hmm_vec3 Axis)
-{
- hmm_mat4 Result = HMM_Mat4d(1.0f);
-
- Axis = HMM_NormalizeVec3(Axis);
-
- float SinTheta = HMM_SinF(HMM_ToRadians(Angle));
- float CosTheta = HMM_CosF(HMM_ToRadians(Angle));
- float CosValue = 1.0f - CosTheta;
-
- Result.Elements[0][0] = (Axis.X * Axis.X * CosValue) + CosTheta;
- Result.Elements[0][1] = (Axis.X * Axis.Y * CosValue) + (Axis.Z * SinTheta);
- Result.Elements[0][2] = (Axis.X * Axis.Z * CosValue) - (Axis.Y * SinTheta);
-
- Result.Elements[1][0] = (Axis.Y * Axis.X * CosValue) - (Axis.Z * SinTheta);
- Result.Elements[1][1] = (Axis.Y * Axis.Y * CosValue) + CosTheta;
- Result.Elements[1][2] = (Axis.Y * Axis.Z * CosValue) + (Axis.X * SinTheta);
-
- Result.Elements[2][0] = (Axis.Z * Axis.X * CosValue) + (Axis.Y * SinTheta);
- Result.Elements[2][1] = (Axis.Z * Axis.Y * CosValue) - (Axis.X * SinTheta);
- Result.Elements[2][2] = (Axis.Z * Axis.Z * CosValue) + CosTheta;
-
- return (Result);
-}
-
-HINLINE hmm_mat4
-HMM_Scale(hmm_vec3 Scale)
-{
- hmm_mat4 Result = HMM_Mat4d(1.0f);
-
- Result.Elements[0][0] = Scale.X;
- Result.Elements[1][1] = Scale.Y;
- Result.Elements[2][2] = Scale.Z;
-
- return (Result);
-}
-
-HINLINE hmm_mat4
-HMM_LookAt(hmm_vec3 Eye, hmm_vec3 Center, hmm_vec3 Up)
-{
- hmm_mat4 Result = {0};
-
- hmm_vec3 F = HMM_NormalizeVec3(HMM_SubtractVec3(Center, Eye));
- hmm_vec3 S = HMM_NormalizeVec3(HMM_Cross(F, Up));
- hmm_vec3 U = HMM_Cross(S, F);
-
- Result.Elements[0][0] = S.X;
- Result.Elements[0][1] = U.X;
- Result.Elements[0][2] = -F.X;
-
- Result.Elements[1][0] = S.Y;
- Result.Elements[1][1] = U.Y;
- Result.Elements[1][2] = -F.Y;
-
- Result.Elements[2][0] = S.Z;
- Result.Elements[2][1] = U.Z;
- Result.Elements[2][2] = -F.Z;
-
- Result.Elements[3][0] = -HMM_DotVec3(S, Eye);
- Result.Elements[3][1] = -HMM_DotVec3(U, Eye);
- Result.Elements[3][2] = HMM_DotVec3(F, Eye);
- Result.Elements[3][3] = 1.0f;
-
- return (Result);
-}
-
-
-HINLINE hmm_quaternion
-HMM_Quaternion(float X, float Y, float Z, float W)
-{
- hmm_quaternion Result = {0};
-
- Result.X = X;
- Result.Y = Y;
- Result.Z = Z;
- Result.W = W;
-
- return(Result);
-}
-
-HINLINE hmm_quaternion
-HMM_QuaternionV4(hmm_vec4 Vector)
-{
- hmm_quaternion Result = {0};
-
- Result.X = Vector.X;
- Result.Y = Vector.Y;
- Result.Z = Vector.Z;
- Result.W = Vector.W;
-
- return(Result);
-}
-
-HINLINE hmm_quaternion
-HMM_AddQuaternion(hmm_quaternion Left, hmm_quaternion Right)
-{
- hmm_quaternion Result = {0};
-
- Result.X = Left.X + Right.X;
- Result.Y = Left.Y + Right.Y;
- Result.Z = Left.Z + Right.Z;
- Result.W = Left.W + Right.W;
-
- return(Result);
-}
-
-HINLINE hmm_quaternion
-HMM_SubtractQuaternion(hmm_quaternion Left, hmm_quaternion Right)
-{
- hmm_quaternion Result = {0};
-
- Result.X = Left.X - Right.X;
- Result.Y = Left.Y - Right.Y;
- Result.Z = Left.Z - Right.Z;
- Result.W = Left.W - Right.W;
-
- return(Result);
-}
-
-HINLINE hmm_quaternion
-HMM_MultiplyQuaternion(hmm_quaternion Left, hmm_quaternion Right)
-{
- hmm_quaternion Result = {0};
-
- Result.X = (Left.X * Right.W) + (Left.Y * Right.Z) - (Left.Z * Right.Y) + (Left.W * Right.X);
- Result.Y = (-Left.X * Right.Z) + (Left.Y * Right.W) + (Left.Z * Right.X) + (Left.W * Right.Y);
- Result.Z = (Left.X * Right.Y) - (Left.Y * Right.X) + (Left.Z * Right.W) + (Left.W * Right.Z);
- Result.W = (-Left.X * Right.X) - (Left.Y * Right.Y) - (Left.Z * Right.Z) + (Left.W * Right.W);
-
- return(Result);
-}
-
-HINLINE hmm_quaternion
-HMM_MultiplyQuaternionF(hmm_quaternion Left, float Multiplicative)
-{
- hmm_quaternion Result = {0};
-
- Result.X = Left.X * Multiplicative;
- Result.Y = Left.Y * Multiplicative;
- Result.Z = Left.Z * Multiplicative;
- Result.W = Left.W * Multiplicative;
-
- return(Result);
-}
-
-HINLINE hmm_quaternion
-HMM_DivideQuaternionF(hmm_quaternion Left, float Dividend)
-{
- hmm_quaternion Result = {0};
-
- Result.X = Left.X / Dividend;
- Result.Y = Left.Y / Dividend;
- Result.Z = Left.Z / Dividend;
- Result.W = Left.W / Dividend;
-
- return(Result);
-}
-
-HINLINE hmm_quaternion
-HMM_InverseQuaternion(hmm_quaternion Left)
-{
- hmm_quaternion Conjugate = {0};
- hmm_quaternion Result = {0};
- float Norm = 0;
- float NormSquared = 0;
-
- Conjugate.X = -Left.X;
- Conjugate.Y = -Left.Y;
- Conjugate.Z = -Left.Z;
- Conjugate.W = Left.W;
-
- Norm = HMM_SquareRootF(HMM_DotQuaternion(Left, Left));
- NormSquared = Norm * Norm;
-
- Result.X = Conjugate.X / NormSquared;
- Result.Y = Conjugate.Y / NormSquared;
- Result.Z = Conjugate.Z / NormSquared;
- Result.W = Conjugate.W / NormSquared;
-
- return(Result);
-}
-
-HINLINE float
-HMM_DotQuaternion(hmm_quaternion Left, hmm_quaternion Right)
-{
- float Result = 0.0f;
-
- Result = (Left.X * Right.X) + (Left.Y * Right.Y) + (Left.Z * Right.Z) + (Left.W * Right.W);
-
- return(Result);
-}
-
-HINLINE hmm_quaternion
-HMM_NormalizeQuaternion(hmm_quaternion Left)
-{
- hmm_quaternion Result = {0};
-
- float Length = HMM_SquareRootF(HMM_DotQuaternion(Left, Left));
- Result = HMM_DivideQuaternionF(Left, Length);
-
- return(Result);
-}
-
-HINLINE hmm_quaternion
-HMM_NLerp(hmm_quaternion Left, float Time, hmm_quaternion Right)
-{
- hmm_quaternion Result = {0};
-
- Result.X = HMM_Lerp(Left.X, Time, Right.X);
- Result.Y = HMM_Lerp(Left.Y, Time, Right.Y);
- Result.Z = HMM_Lerp(Left.Z, Time, Right.Z);
- Result.W = HMM_Lerp(Left.W, Time, Right.W);
-
- Result = HMM_NormalizeQuaternion(Result);
-
- return(Result);
-}
-
-HINLINE hmm_quaternion
-HMM_Slerp(hmm_quaternion Left, float Time, hmm_quaternion Right)
-{
- hmm_quaternion Result = {0};
- hmm_quaternion QuaternionLeft = {0};
- hmm_quaternion QuaternionRight = {0};
-
- float Cos_Theta = HMM_DotQuaternion(Left, Right);
- float Angle = HMM_ACosF(Cos_Theta);
-
- float S1 = HMM_SinF((1.0f - Time) * Angle);
- float S2 = HMM_SinF(Time * Angle);
- float Is = 1.0f / HMM_SinF(Angle);
-
- QuaternionLeft = HMM_MultiplyQuaternionF(Left, S1);
- QuaternionRight = HMM_MultiplyQuaternionF(Right, S2);
-
- Result = HMM_AddQuaternion(QuaternionLeft, QuaternionRight);
- Result = HMM_MultiplyQuaternionF(Result, Is);
-
- return(Result);
-}
-
-HINLINE hmm_mat4
-HMM_QuaternionToMat4(hmm_quaternion Left)
-{
- hmm_mat4 Result = {0};
- Result = HMM_Mat4d(1);
-
- hmm_quaternion NormalizedQuaternion = HMM_NormalizeQuaternion(Left);
-
- float XX, YY, ZZ,
- XY, XZ, YZ,
- WX, WY, WZ;
-
- XX = NormalizedQuaternion.X * NormalizedQuaternion.X;
- YY = NormalizedQuaternion.Y * NormalizedQuaternion.Y;
- ZZ = NormalizedQuaternion.Z * NormalizedQuaternion.Z;
- XY = NormalizedQuaternion.X * NormalizedQuaternion.Y;
- XZ = NormalizedQuaternion.X * NormalizedQuaternion.Z;
- YZ = NormalizedQuaternion.Y * NormalizedQuaternion.Z;
- WX = NormalizedQuaternion.W * NormalizedQuaternion.X;
- WY = NormalizedQuaternion.W * NormalizedQuaternion.Y;
- WZ = NormalizedQuaternion.W * NormalizedQuaternion.Z;
-
- Result.Elements[0][0] = 1.0f - 2.0f * (YY + ZZ);
- Result.Elements[0][1] = 2.0f * (XY + WZ);
- Result.Elements[0][2] = 2.0f * (XZ - WY);
-
- Result.Elements[1][0] = 2.0f * (XY - WZ);
- Result.Elements[1][1] = 1.0f - 2.0f * (XX + ZZ);
- Result.Elements[1][2] = 2.0f * (YZ + WX);
-
- Result.Elements[2][0] = 2.0f * (XZ + WY);
- Result.Elements[2][1] = 2.0f * (YZ - WX);
- Result.Elements[2][2] = 1.0f - 2.0f * (XX + YY);
-
- return(Result);
-}
-
-HINLINE hmm_quaternion
-HMM_QuaternionFromAxisAngle(hmm_vec3 Axis, float AngleOfRotation)
-{
- hmm_quaternion Result = {0};
- float AxisNorm = 0;
- float SineOfRotation = 0;
- hmm_vec3 RotatedVector = {0};
-
- AxisNorm = HMM_SquareRootF(HMM_DotVec3(Axis, Axis));
- SineOfRotation = HMM_SinF(AngleOfRotation / 2.0f);
- RotatedVector = HMM_MultiplyVec3f(Axis, SineOfRotation);
-
- Result.W = HMM_CosF(AngleOfRotation / 2.0f);
- Result.XYZ = HMM_DivideVec3f(RotatedVector, AxisNorm);
-
- return(Result);
-}
-
-#ifdef HANDMADE_MATH_CPP_MODE
-
-HINLINE float
-HMM_Length(hmm_vec2 A)
-{
- float Result = 0.0f;
-
- Result = HMM_LengthVec2(A);
-
- return(Result);
-}
-
-HINLINE float
-HMM_Length(hmm_vec3 A)
-{
- float Result = 0.0f;
-
- Result = HMM_LengthVec3(A);
-
- return(Result);
-}
-
-HINLINE float
-HMM_Length(hmm_vec4 A)
-{
- float Result = 0.0f;
-
- Result = HMM_LengthVec4(A);
-
- return(Result);
-}
-
-HINLINE float
-HMM_LengthSquared(hmm_vec2 A)
-{
- float Result = 0.0f;
-
- Result = HMM_LengthSquaredVec2(A);
-
- return(Result);
-}
-
-HINLINE float
-HMM_LengthSquared(hmm_vec3 A)
-{
- float Result = 0.0f;
-
- Result = HMM_LengthSquaredVec3(A);
-
- return(Result);
-}
-
-HINLINE float
-HMM_LengthSquared(hmm_vec4 A)
-{
- float Result = 0.0f;
-
- Result = HMM_LengthSquaredVec4(A);
-
- return(Result);
-}
-
-HINLINE hmm_vec2
-HMM_Normalize(hmm_vec2 A)
-{
- hmm_vec2 Result = {0};
-
- Result = HMM_NormalizeVec2(A);
-
- return(Result);
-}
-
-HINLINE hmm_vec3
-HMM_Normalize(hmm_vec3 A)
-{
- hmm_vec3 Result = {0};
-
- Result = HMM_NormalizeVec3(A);
-
- return(Result);
-}
-
-HINLINE hmm_vec4
-HMM_Normalize(hmm_vec4 A)
-{
- hmm_vec4 Result = {0};
-
- Result = HMM_NormalizeVec4(A);
-
- return(Result);
-}
-
-HINLINE hmm_quaternion
-HMM_Normalize(hmm_quaternion A)
-{
- hmm_quaternion Result = {0};
-
- Result = HMM_NormalizeQuaternion(A);
-
- return(Result);
-}
-
-HINLINE float
-HMM_Dot(hmm_vec2 VecOne, hmm_vec2 VecTwo)
-{
- float Result = 0;
-
- Result = HMM_DotVec2(VecOne, VecTwo);
-
- return(Result);
-}
-
-HINLINE float
-HMM_Dot(hmm_vec3 VecOne, hmm_vec3 VecTwo)
-{
- float Result = 0;
-
- Result = HMM_DotVec3(VecOne, VecTwo);
-
- return(Result);
-}
-
-HINLINE float
-HMM_Dot(hmm_vec4 VecOne, hmm_vec4 VecTwo)
-{
- float Result = 0;
-
- Result = HMM_DotVec4(VecOne, VecTwo);
-
- return(Result);
-}
-
-HINLINE float
-HMM_Dot(hmm_quaternion QuatOne, hmm_quaternion QuatTwo)
-{
- float Result = 0;
-
- Result = HMM_DotQuaternion(QuatOne, QuatTwo);
-
- return(Result);
-}
-
-HINLINE hmm_vec2
-HMM_Add(hmm_vec2 Left, hmm_vec2 Right)
-{
- hmm_vec2 Result = {0};
-
- Result = HMM_AddVec2(Left, Right);
- return (Result);
-}
-
-HINLINE hmm_vec3
-HMM_Add(hmm_vec3 Left, hmm_vec3 Right)
-{
- hmm_vec3 Result = {0};
-
- Result = HMM_AddVec3(Left, Right);
- return (Result);
-}
-
-HINLINE hmm_vec4
-HMM_Add(hmm_vec4 Left, hmm_vec4 Right)
-{
- hmm_vec4 Result = {0};
-
- Result = HMM_AddVec4(Left, Right);
- return (Result);
-}
-
-HINLINE hmm_mat4
-HMM_Add(hmm_mat4 Left, hmm_mat4 Right)
-{
- hmm_mat4 Result = {0};
-
- Result = HMM_AddMat4(Left, Right);
- return (Result);
-}
-
-HINLINE hmm_quaternion
-HMM_Add(hmm_quaternion Left, hmm_quaternion Right)
-{
- hmm_quaternion Result = {0};
-
- Result = HMM_AddQuaternion(Left, Right);
- return(Result);
-}
-
-HINLINE hmm_vec2
-HMM_Subtract(hmm_vec2 Left, hmm_vec2 Right)
-{
- hmm_vec2 Result = {0};
-
- Result = HMM_SubtractVec2(Left, Right);
- return (Result);
-}
-
-HINLINE hmm_vec3
-HMM_Subtract(hmm_vec3 Left, hmm_vec3 Right)
-{
- hmm_vec3 Result = {0};
-
- Result = HMM_SubtractVec3(Left, Right);
- return (Result);
-}
-
-HINLINE hmm_vec4
-HMM_Subtract(hmm_vec4 Left, hmm_vec4 Right)
-{
- hmm_vec4 Result = {0};
-
- Result = HMM_SubtractVec4(Left, Right);
- return (Result);
-}
-
-HINLINE hmm_mat4
-HMM_Subtract(hmm_mat4 Left, hmm_mat4 Right)
-{
- hmm_mat4 Result = {0};
-
- Result = HMM_SubtractMat4(Left, Right);
- return (Result);
-}
-
-HINLINE hmm_quaternion
-HMM_Subtract(hmm_quaternion Left, hmm_quaternion Right)
-{
- hmm_quaternion Result = {0};
-
- Result = HMM_SubtractQuaternion(Left, Right);
- return (Result);
-}
-
-HINLINE hmm_vec2
-HMM_Multiply(hmm_vec2 Left, hmm_vec2 Right)
-{
- hmm_vec2 Result = {0};
-
- Result = HMM_MultiplyVec2(Left, Right);
- return (Result);
-}
-
-HINLINE hmm_vec2
-HMM_Multiply(hmm_vec2 Left, float Right)
-{
- hmm_vec2 Result = {0};
-
- Result = HMM_MultiplyVec2f(Left, Right);
- return (Result);
-}
-
-HINLINE hmm_vec3
-HMM_Multiply(hmm_vec3 Left, hmm_vec3 Right)
-{
- hmm_vec3 Result = {0};
-
- Result = HMM_MultiplyVec3(Left, Right);
- return (Result);
-}
-
-HINLINE hmm_vec3
-HMM_Multiply(hmm_vec3 Left, float Right)
-{
- hmm_vec3 Result = {0};
-
- Result = HMM_MultiplyVec3f(Left, Right);
- return (Result);
-}
-
-HINLINE hmm_vec4
-HMM_Multiply(hmm_vec4 Left, hmm_vec4 Right)
-{
- hmm_vec4 Result = {0};
-
- Result = HMM_MultiplyVec4(Left, Right);
- return (Result);
-}
-
-HINLINE hmm_vec4
-HMM_Multiply(hmm_vec4 Left, float Right)
-{
- hmm_vec4 Result = {0};
-
- Result = HMM_MultiplyVec4f(Left, Right);
- return (Result);
-}
-
-HINLINE hmm_mat4
-HMM_Multiply(hmm_mat4 Left, hmm_mat4 Right)
-{
- hmm_mat4 Result = {0};
-
- Result = HMM_MultiplyMat4(Left, Right);
- return (Result);
-}
-
-HINLINE hmm_mat4
-HMM_Multiply(hmm_mat4 Left, float Right)
-{
- hmm_mat4 Result = {0};
-
- Result = HMM_MultiplyMat4f(Left, Right);
- return (Result);
-}
-
-HINLINE hmm_vec4
-HMM_Multiply(hmm_mat4 Matrix, hmm_vec4 Vector)
-{
- hmm_vec4 Result = {0};
-
- Result = HMM_MultiplyMat4ByVec4(Matrix, Vector);
- return (Result);
-}
-
-HINLINE hmm_quaternion
-HMM_Multiply(hmm_quaternion Left, hmm_quaternion Right)
-{
- hmm_quaternion Result = {0};
-
- Result = HMM_MultiplyQuaternion(Left, Right);
- return (Result);
-}
-
-HINLINE hmm_quaternion
-HMM_Multiply(hmm_quaternion Left, float Right)
-{
- hmm_quaternion Result = {0};
-
- Result = HMM_MultiplyQuaternionF(Left, Right);
- return (Result);
-}
-
-HINLINE hmm_quaternion
-HMM_Multiply(float Left, hmm_quaternion Right)
-{
- hmm_quaternion Result = {0};
-
- Result = HMM_MultiplyQuaternionF(Right, Left);
- return (Result);
-}
-
-HINLINE hmm_vec2
-HMM_Divide(hmm_vec2 Left, hmm_vec2 Right)
-{
- hmm_vec2 Result = {0};
-
- Result = HMM_DivideVec2(Left, Right);
- return (Result);
-}
-
-HINLINE hmm_vec2
-HMM_Divide(hmm_vec2 Left, float Right)
-{
- hmm_vec2 Result = {0};
-
- Result = HMM_DivideVec2f(Left, Right);
- return (Result);
-}
-
-HINLINE hmm_vec3
-HMM_Divide(hmm_vec3 Left, hmm_vec3 Right)
-{
- hmm_vec3 Result = {0};
-
- Result = HMM_DivideVec3(Left, Right);
- return (Result);
-}
-
-HINLINE hmm_vec3
-HMM_Divide(hmm_vec3 Left, float Right)
-{
- hmm_vec3 Result = {0};
-
- Result = HMM_DivideVec3f(Left, Right);
- return (Result);
-}
-
-HINLINE hmm_vec4
-HMM_Divide(hmm_vec4 Left, hmm_vec4 Right)
-{
- hmm_vec4 Result = {0};
-
- Result = HMM_DivideVec4(Left, Right);
- return (Result);
-}
-
-HINLINE hmm_vec4
-HMM_Divide(hmm_vec4 Left, float Right)
-{
- hmm_vec4 Result = {0};
-
- Result = HMM_DivideVec4f(Left, Right);
- return (Result);
-}
-
-HINLINE hmm_mat4
-HMM_Divide(hmm_mat4 Left, float Right)
-{
- hmm_mat4 Result = {0};
-
- Result = HMM_DivideMat4f(Left, Right);
- return (Result);
-}
-
-HINLINE hmm_quaternion
-HMM_Divide(hmm_quaternion Left, float Right)
-{
- hmm_quaternion Result = {0};
-
- Result = HMM_DivideQuaternionF(Left, Right);
- return (Result);
-}
-
-HINLINE hmm_vec2
-operator+(hmm_vec2 Left, hmm_vec2 Right)
-{
- hmm_vec2 Result = {0};
-
- Result = HMM_Add(Left, Right);
- return (Result);
-}
-
-HINLINE hmm_vec3
-operator+(hmm_vec3 Left, hmm_vec3 Right)
-{
- hmm_vec3 Result = {0};
-
- Result = HMM_Add(Left, Right);
- return (Result);
-}
-
-HINLINE hmm_vec4
-operator+(hmm_vec4 Left, hmm_vec4 Right)
-{
- hmm_vec4 Result = {0};
-
- Result = HMM_Add(Left, Right);
- return (Result);
-}
-
-HINLINE hmm_mat4
-operator+(hmm_mat4 Left, hmm_mat4 Right)
-{
- hmm_mat4 Result = {0};
-
- Result = HMM_Add(Left, Right);
- return (Result);
-}
-
-HINLINE hmm_quaternion
-operator+(hmm_quaternion Left, hmm_quaternion Right)
-{
- hmm_quaternion Result = {0};
-
- Result = HMM_Add(Left, Right);
- return (Result);
-}
-
-HINLINE hmm_vec2
-operator-(hmm_vec2 Left, hmm_vec2 Right)
-{
- hmm_vec2 Result = {0};
-
- Result = HMM_Subtract(Left, Right);
- return (Result);
-}
-
-HINLINE hmm_vec3
-operator-(hmm_vec3 Left, hmm_vec3 Right)
-{
- hmm_vec3 Result = {0};
-
- Result = HMM_Subtract(Left, Right);
- return (Result);
-}
-
-HINLINE hmm_vec4
-operator-(hmm_vec4 Left, hmm_vec4 Right)
-{
- hmm_vec4 Result = {0};
-
- Result = HMM_Subtract(Left, Right);
- return (Result);
-}
-
-HINLINE hmm_mat4
-operator-(hmm_mat4 Left, hmm_mat4 Right)
-{
- hmm_mat4 Result = {0};
-
- Result = HMM_Subtract(Left, Right);
- return (Result);
-}
-
-HINLINE hmm_quaternion
-operator-(hmm_quaternion Left, hmm_quaternion Right)
-{
- hmm_quaternion Result = {0};
-
- Result = HMM_Subtract(Left, Right);
- return (Result);
-}
-
-HINLINE hmm_vec2
-operator*(hmm_vec2 Left, hmm_vec2 Right)
-{
- hmm_vec2 Result = {0};
-
- Result = HMM_Multiply(Left, Right);
- return (Result);
-}
-
-HINLINE hmm_vec3
-operator*(hmm_vec3 Left, hmm_vec3 Right)
-{
- hmm_vec3 Result = {0};
-
- Result = HMM_Multiply(Left, Right);
- return (Result);
-}
-
-HINLINE hmm_vec4
-operator*(hmm_vec4 Left, hmm_vec4 Right)
-{
- hmm_vec4 Result = HMM_Multiply(Left, Right);
-
- return (Result);
-}
-
-HINLINE hmm_vec2
-operator*(hmm_vec2 Left, float Right)
-{
- hmm_vec2 Result = {0};
-
- Result = HMM_Multiply(Left, Right);
- return (Result);
-}
-
-HINLINE hmm_vec3
-operator*(hmm_vec3 Left, float Right)
-{
- hmm_vec3 Result = {0};
-
- Result = HMM_Multiply(Left, Right);
- return (Result);
-}
-
-HINLINE hmm_vec4
-operator*(hmm_vec4 Left, float Right)
-{
- hmm_vec4 Result = {0};
-
- Result = HMM_Multiply(Left, Right);
- return (Result);
-}
-
-HINLINE hmm_mat4
-operator*(hmm_mat4 Left, float Right)
-{
- hmm_mat4 Result = {0};
-
- Result = HMM_Multiply(Left, Right);
- return (Result);
-}
-
-HINLINE hmm_vec2
-operator*(float Left, hmm_vec2 Right)
-{
- hmm_vec2 Result = {0};
-
- Result = HMM_Multiply(Right, Left);
- return (Result);
-}
-
-HINLINE hmm_vec3
-operator*(float Left, hmm_vec3 Right)
-{
- hmm_vec3 Result = {0};
-
- Result = HMM_Multiply(Right, Left);
- return (Result);
-}
-
-HINLINE hmm_vec4
-operator*(float Left, hmm_vec4 Right)
-{
- hmm_vec4 Result = {0};
-
- Result = HMM_Multiply(Right, Left);
- return (Result);
-}
-
-HINLINE hmm_mat4
-operator*(float Left, hmm_mat4 Right)
-{
- hmm_mat4 Result = {0};
-
- Result = HMM_Multiply(Right, Left);
- return (Result);
-}
-
-HINLINE hmm_mat4
-operator*(hmm_mat4 Left, hmm_mat4 Right)
-{
- hmm_mat4 Result = {0};
-
- Result = HMM_Multiply(Left, Right);
- return (Result);
-}
-
-HINLINE hmm_vec4
-operator*(hmm_mat4 Matrix, hmm_vec4 Vector)
-{
- hmm_vec4 Result = {0};
-
- Result = HMM_Multiply(Matrix, Vector);
- return (Result);
-}
-
-HINLINE hmm_quaternion
-operator*(hmm_quaternion Left, hmm_quaternion Right)
-{
- hmm_quaternion Result = {0};
-
- Result = HMM_Multiply(Left, Right);
- return (Result);
-}
-
-HINLINE hmm_quaternion
-operator*(hmm_quaternion Left, float Right)
-{
- hmm_quaternion Result = {0};
-
- Result = HMM_Multiply(Left, Right);
- return (Result);
-}
-
-HINLINE hmm_quaternion
-operator*(float Left, hmm_quaternion Right)
-{
- hmm_quaternion Result = {0};
-
- Result = HMM_Multiply(Right, Left);
- return (Result);
-}
-
-HINLINE hmm_vec2
-operator/(hmm_vec2 Left, hmm_vec2 Right)
-{
- hmm_vec2 Result = {0};
-
- Result = HMM_Divide(Left, Right);
- return (Result);
-}
-
-HINLINE hmm_vec3
-operator/(hmm_vec3 Left, hmm_vec3 Right)
-{
- hmm_vec3 Result = {0};
-
- Result = HMM_Divide(Left, Right);
-
- return (Result);
-}
-
-HINLINE hmm_vec4
-operator/(hmm_vec4 Left, hmm_vec4 Right)
-{
- hmm_vec4 Result = {0};
-
- Result = HMM_Divide(Left, Right);
- return (Result);
-}
-
-HINLINE hmm_vec2
-operator/(hmm_vec2 Left, float Right)
-{
- hmm_vec2 Result = {0};
-
- Result = HMM_Divide(Left, Right);
- return (Result);
-}
-
-HINLINE hmm_vec3
-operator/(hmm_vec3 Left, float Right)
-{
- hmm_vec3 Result = {0};
-
- Result = HMM_Divide(Left, Right);
- return (Result);
-}
-
-HINLINE hmm_vec4
-operator/(hmm_vec4 Left, float Right)
-{
- hmm_vec4 Result = {0};
-
- Result = HMM_Divide(Left, Right);
- return (Result);
-}
-
-HINLINE hmm_mat4
-operator/(hmm_mat4 Left, float Right)
-{
- hmm_mat4 Result = {0};
-
- Result = HMM_Divide(Left, Right);
- return (Result);
-}
-
-HINLINE hmm_quaternion
-operator/(hmm_quaternion Left, float Right)
-{
- hmm_quaternion Result = {0};
-
- Result = HMM_Divide(Left, Right);
- return (Result);
-}
-
-HINLINE hmm_vec2 &
-operator+=(hmm_vec2 &Left, hmm_vec2 Right)
-{
- return (Left = Left + Right);
-}
-
-HINLINE hmm_vec3 &
-operator+=(hmm_vec3 &Left, hmm_vec3 Right)
-{
- return (Left = Left + Right);
-}
-
-HINLINE hmm_vec4 &
-operator+=(hmm_vec4 &Left, hmm_vec4 Right)
-{
- return (Left = Left + Right);
-}
-
-HINLINE hmm_mat4 &
-operator+=(hmm_mat4 &Left, hmm_mat4 Right)
-{
- return (Left = Left + Right);
-}
-
-HINLINE hmm_quaternion &
-operator+=(hmm_quaternion &Left, hmm_quaternion Right)
-{
- return (Left = Left + Right);
-}
-
-HINLINE hmm_vec2 &
-operator-=(hmm_vec2 &Left, hmm_vec2 Right)
-{
- return (Left = Left - Right);
-}
-
-HINLINE hmm_vec3 &
-operator-=(hmm_vec3 &Left, hmm_vec3 Right)
-{
- return (Left = Left - Right);
-}
-
-HINLINE hmm_vec4 &
-operator-=(hmm_vec4 &Left, hmm_vec4 Right)
-{
- return (Left = Left - Right);
-}
-
-HINLINE hmm_mat4 &
-operator-=(hmm_mat4 &Left, hmm_mat4 Right)
-{
- return (Left = Left - Right);
-}
-
-HINLINE hmm_quaternion &
-operator-=(hmm_quaternion &Left, hmm_quaternion Right)
-{
- return (Left = Left - Right);
-}
-
-HINLINE hmm_vec2 &
-operator/=(hmm_vec2 &Left, hmm_vec2 Right)
-{
- return (Left = Left / Right);
-}
-
-HINLINE hmm_vec3 &
-operator/=(hmm_vec3 &Left, hmm_vec3 Right)
-{
- return (Left = Left / Right);
-}
-
-HINLINE hmm_vec4 &
-operator/=(hmm_vec4 &Left, hmm_vec4 Right)
-{
- return (Left = Left / Right);
-}
-
-HINLINE hmm_vec2 &
-operator/=(hmm_vec2 &Left, float Right)
-{
- return (Left = Left / Right);
-}
-
-HINLINE hmm_vec3 &
-operator/=(hmm_vec3 &Left, float Right)
-{
- return (Left = Left / Right);
-}
-
-HINLINE hmm_vec4 &
-operator/=(hmm_vec4 &Left, float Right)
-{
- return (Left = Left / Right);
-}
-
-HINLINE hmm_mat4 &
-operator/=(hmm_mat4 &Left, float Right)
-{
- return (Left = Left / Right);
-}
-
-HINLINE hmm_quaternion &
-operator/=(hmm_quaternion &Left, float Right)
-{
- return (Left = Left / Right);
-}
-
-HINLINE hmm_vec2 &
-operator*=(hmm_vec2 &Left, hmm_vec2 Right)
-{
- return (Left = Left * Right);
-}
-
-HINLINE hmm_vec3 &
-operator*=(hmm_vec3 &Left, hmm_vec3 Right)
-{
- return (Left = Left * Right);
-}
-
-HINLINE hmm_vec4 &
-operator*=(hmm_vec4 &Left, hmm_vec4 Right)
-{
- return (Left = Left * Right);
-}
-
-HINLINE hmm_vec2 &
-operator*=(hmm_vec2 &Left, float Right)
-{
- return (Left = Left * Right);
-}
-
-HINLINE hmm_vec3 &
-operator*=(hmm_vec3 &Left, float Right)
-{
- return (Left = Left * Right);
-}
-
-HINLINE hmm_vec4 &
-operator*=(hmm_vec4 &Left, float Right)
-{
- return (Left = Left * Right);
-}
-
-HINLINE hmm_mat4 &
-operator*=(hmm_mat4 &Left, float Right)
-{
- return (Left = Left * Right);
-}
-
-HINLINE hmm_quaternion &
-operator*=(hmm_quaternion &Left, float Right)
-{
- return (Left = Left * Right);
-}
-
-#endif /* HANDMADE_MATH_CPP_MODE */
-
-#endif /* HANDMADE_MATH_IMPLEMENTATION */
-
-#ifdef __GNUC__
- #pragma GCC diagnostic pop
-#endif
diff --git a/Code/Deprecated/build.bat b/Code/Deprecated/build.bat
deleted file mode 100644
index bbafb7f..0000000
--- a/Code/Deprecated/build.bat
+++ /dev/null
@@ -1,71 +0,0 @@
-@REM Build for Visual Studio compiler. Run your copy of vcvars32.bat or
-@REM vcvarsall.bat to setup command-line compiler.
-
-@echo OFF
-set ProjectName=DqnUnitTest
-set CompileEntryPoint=..\DqnUnitTest.cpp
-
-REM Build tags file if you have ctags in path
-where /q ctags
-if %errorlevel%==0 (
-REM When parsing a C++ member function definition (e.g. "className::function"),
-REM ctags cannot determine whether the scope specifier is a class name or
-REM a namespace specifier and always lists it as a class name in the scope
-REM portion of the extension fields. Also, if a C++ function is defined outside
-REM of the class declaration (the usual case), the access specification (i.e.
-REM public, protected, or private) and implementation information (e.g. virtual,
-REM pure virtual) contained in the function declaration are not known when the
-REM tag is generated for the function definition. -c++-kinds=+p fixes that
-
-REM The --fields=+iaS option:
-REM a Access (or export) of class members
-REM i Inheritance information
-REM S Signature of routine (e.g. prototype or parameter list)
-REM
-REM The --extra=+q option:
-REM By default, ctags only generates tags for separate identifiers found in
-REM the source files. With --extras=+q option, then ctags will also generate
-REM a second, class-qualified tag for each class member
- ctags -R --c++-kinds=+p --fields=+iaS --extras=+q
-)
-
-REM Check if build tool is on path
-REM >nul, 2>nul will remove the output text from the where command
-where cl.exe >nul 2>nul
-if %errorlevel%==1 call msvc86.bat
-
-REM Drop compilation files into build folder
-IF NOT EXIST bin mkdir bin
-pushd bin
-
-REM EHa- disable exception handling (but we use for algorithms so /EHsc)
-REM GR- disable c runtime type information (we don't use)
-
-REM MD use dynamic runtime library
-REM MT use static runtime library, so build and link it into exe
-
-REM Oi enable intrinsics optimisation, let us use CPU intrinsics if there is one
-REM instead of generating a call to external library (i.e. CRT).
-
-REM Zi enables debug data, Z7 combines the debug files into one.
-
-REM W4 warning level 4
-REM WX treat warnings as errors
-REM wd4201 ignore: nonstandard extension used: nameless struct/union
-set CompileFlags=-EHsc -GR- -Oi -MT -Z7 -W4 -WX -wd4201 -FC -Od -wd4127 /P
-
-REM Include directories
-set IncludeFlags=
-
-REM Link libraries
-set LinkLibraries=user32.lib ws2_32.lib
-
-REM incrmenetal:no, turn incremental builds off
-REM opt:ref, try to remove functions from libs that are referenced at all
-set LinkFlags=-incremental:no -opt:ref -machine:x64
-
-cl %CompileFlags% %CompileEntryPoint% %IncludeFlags% /link %LinkLibraries% %LinkFlags% /nologo /OUT:"%ProjectName%.exe"
-REM cl /P /c %CompileFlags% %CompileEntryPoint%
-
-popd
-
diff --git a/Code/Deprecated/dqn.h b/Code/Deprecated/dqn.h
deleted file mode 100644
index cca5847..0000000
--- a/Code/Deprecated/dqn.h
+++ /dev/null
@@ -1,8862 +0,0 @@
-// Dqn.h Usage
-// =================================================================================================
-/*
- // Define this wherever you want access to DQN code that uses the platform.
- #define DQN_PLATFORM_HEADER // Enable function prototypes for xplatform/platform code
- #define DQN_IMPLEMENTATION // Enable the implementation
- #define DQN_PLATFORM_IMPLEMENTATION // Enable platform specific implementation on Win32 you must link against user32.lib and kernel32.lib
- #define DQN_MAKE_STATIC // Make all functions be static
- #include "dqn.h"
- */
-
-// Conventions
-// All data structures fields are exposed by default, with exceptions here and there. The rationale
-// is I rarely go into libraries and start changing values around in fields unless I know the
-// implementation OR we're required to fill out a struct for some function.
-
-// Just treat all struct fields to be internal and read-only unless explicitly stated otherwise.
-
-// Table Of Contents #TOC #TableOfContents
-// =================================================================================================
-// You can search by # to jump straight to the section.
-// The first match is the public API, the next matche(s) are the implementation
-
-// #Preprocessor Checks
-// #Portable Code
-// #Library Settings
-// #Win32 Prototypes
-// #DqnSprintf Cross-platform Sprintf Implementation (Public Domain lib stb_sprintf)
-// #DqnDefer Macro helper/template to implement defer in C++
-// #DqnAssert Assertions and Logging
-// #DqnAllocator Generic allocation API for Dqn Data Structures
-// #DqnSlice A ptr and length into memory but doesn't imply ownership of memory
-// #DqnBuffer Typedef to slices, but indicates ownership of the memory
-// #DqnFixedString Fixed sized strings at compile time.
-// #DqnMem Memory Allocation
-// #DqnMemStack Memory Allocator, Push, Pop Style
-// #DqnLogger
-// #DqnArray Dynamic Array using Templates
-// #DqnChar Char Operations (IsDigit(), IsAlpha() etc)
-// #DqnStr Str Operations (Str_Len(), Str_Copy() etc)
-// #DqnWChar WChar Operations (IsDigit(), IsAlpha() etc)
-// #DqnWStr WStr Operations (Str_Len(), Str_Copy() etc)
-// #DqnString String library
-// #DqnRndPCG 32 bit Random Number Generator using PCG (ints and floats)
-// #Dqn_* Random utility functions
-// #DqnFixedPool Pool objects
-// #DqnPool Pool objects
-// #DqnHash Hashing using Murmur
-// #DqnMath Simple Math Helpers (Lerp etc.)
-// #DqnV2 2D Math Vectors
-// #DqnV3 3D Math Vectors
-// #DqnV4 4D Math Vectors
-// #DqnMat4 4x4 Math Matrix
-// #DqnRect Rectangles
-// #DqnJson Zero Allocation Json Parser
-
-// #XPlatform (Win32 & Unix)
-// #DqnVArray Array backed by virtual memory
-// #DqnVHashTable Hash Table using templates backed by virtual memory
-// #DqnFile File I/O (Read, Write, Delete)
-// #DqnTimer High Resolution Timer
-// #DqnLock Mutex Synchronisation
-// #DqnJobQueue Multithreaded Job Queue
-// #DqnAtomic Interlocks/Atomic Operations
-// #DqnOS Common Platform API helpers
-
-// #Platform
-// - #DqnWin32 Common Win32 API Helpers
-
-// TODO
-// - Win32
-// - Get rid of reliance on MAX_PATH
-//
-// - Mbuildake lib compile and run on Linux with GCC using -03
-// - Make DqnV* operations be static to class for consistency?
-
-// #Preprocessor Checks
-// =================================================================================================
-// This needs to be above the portable layer so that, if the user requests a platform
-// implementation, platform specific implementations in the portable layer will get activated.
-#if (defined(_WIN32) || defined(_WIN64))
- #define DQN_IS_WIN32 1
-#else
- #define DQN_IS_UNIX 1
-#endif
-
-#if defined(DQN_PLATFORM_IMPLEMENTATION)
- #define DQN__XPLATFORM_LAYER 1
-#endif
-
-// #Portable Code
-// =================================================================================================
-#ifndef DQN_H
-#define DQN_H
-
-#ifdef DQN_MAKE_STATIC
- #define DQN_FILE_SCOPE static
-#else
- #define DQN_FILE_SCOPE
-#endif
-
-#include // For standard types
-#include // For standard types
-#include // memmove
-#include // va_list
-#include // FLT_MAX
-#define LOCAL_PERSIST static
-#define FILE_SCOPE static
-
-using usize = size_t;
-using isize = ptrdiff_t;
-
-using uint = unsigned int;
-using u64 = uint64_t;
-using u32 = uint32_t;
-using u16 = uint16_t;
-using u8 = uint8_t;
-
-using i64 = int64_t;
-using i32 = int32_t;
-using i16 = int16_t;
-using i8 = int8_t;
-
-using b32 = i32;
-
-using f64 = double;
-using f32 = float;
-
-#define DQN_F32_MIN -FLT_MAX
-#define DQN_I64_MAX INT64_MAX
-#define DQN_U64_MAX UINT64_MAX
-
-#define DQN_TERABYTE(val) (DQN_GIGABYTE(val) * 1024LL)
-
-#define DQN_TERABYTE(val) (DQN_GIGABYTE(val) * 1024LL)
-#define DQN_GIGABYTE(val) (DQN_MEGABYTE(val) * 1024LL)
-#define DQN_MEGABYTE(val) (DQN_KILOBYTE(val) * 1024LL)
-#define DQN_KILOBYTE(val) ((val) * 1024LL)
-
-#define DQN_DAY_TO_S(val) ((DQN_HOUR_TO_S(val)) * 24)
-#define DQN_HOUR_TO_S(val) ((DQN_MINUTE_TO_S(val)) * 60)
-#define DQN_MINUTE_TO_S(val) ((val) * 60)
-
-#define DQN_ALIGN_POW_N(val, align) ((((usize)val) + ((usize)align-1)) & (~(usize)(align-1)))
-#define DQN_ALIGN_POW_4(val) DQN_ALIGN_POW_N(val, 4)
-
-#define DQN_INVALID_CODE_PATH 0
-#define DQN_CHAR_COUNT(charArray) DQN_ARRAY_COUNT(charArray) - 1
-#define DQN_ARRAY_COUNT(array) (sizeof(array) / sizeof(array[0]))
-
-#define DQN_PI 3.14159265359f
-#define DQN_SQUARED(x) ((x) * (x))
-#define DQN_ABS(x) (((x) < 0) ? (-(x)) : (x))
-#define DQN_DEGREES_TO_RADIANS(x) ((x * (DQN_PI / 180.0f)))
-#define DQN_RADIANS_TO_DEGREES(x) ((x * (180.0f / DQN_PI)))
-
-#define DQN_CLAMP(value, min, max) DQN_MIN(DQN_MAX(value, min), max)
-#define DQN_MAX(a, b) ((a) < (b) ? (b) : (a))
-#define DQN_MIN(a, b) ((a) < (b) ? (a) : (b))
-#define DQN_SWAP(type, a, b) do { type tmp = a; a = b; b = tmp; } while(0)
-
-// NOTE: Directives don't get replaced if there's a stringify or paste (# or ##) so TOKEN_COMBINE2 is needed
-// to let directives get expanded (i.e. __COUNTER__), then we can combine.
-#define DQN_TOKEN_COMBINE(x, y) x ## y
-#define DQN_TOKEN_COMBINE2(x, y) DQN_TOKEN_COMBINE(x, y)
-
-// Produce a unique name with prefix and counter. i.e. where prefix is "data" then it gives "data1"
-#define DQN_UNIQUE_NAME(prefix) DQN_TOKEN_COMBINE2(prefix, __COUNTER__)
-#define DQN_FOR_EACH(i, lim) for (isize (i) = 0; (i) < (isize)(lim); ++(i))
-
-// #Library Settings
-// =================================================================================================
-namespace Dqn
-{
-enum struct ZeroMem { No = 0, Yes = 1};
-enum struct IgnoreCase { No = 0, Yes = 1};
-
-FILE_SCOPE const bool is_debug = true;
-FILE_SCOPE const bool allow_allocation_tagging = true;
-}; // namespace Dqn
-
-
-// #Win32 Prototypes
-// =================================================================================================
-#if defined(DQN_PLATFORM_HEADER) && defined(DQN_IS_WIN32) && !defined(_WINDOWS_)
-using WORD = unsigned short;
-using DWORD = unsigned long;
-using BOOL = int;
-using LONG = long;
-using LONGLONG = long long;
-using HANDLE = void *;
-using HMODULE = HANDLE;
-using HWND = HANDLE;
-using UINT = unsigned int;
-using ULONG = unsigned long;
-using ULONGLONG = unsigned long long;
-using DWORD64 = unsigned long long;
-using BYTE = unsigned char;
-
-u32 const MB_OK = 0x00000000L;
-HANDLE const INVALID_HANDLE_VALUE = ((HANDLE)(LONG *)-1);
-u32 const MAX_PATH = 260;
-u32 const INFINITE = 0xFFFFFFFF;
-u32 const CP_UTF8 = 65001;
-u32 const FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200;
-u32 const FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000;
-u32 const MEM_COMMIT = 0x00001000;
-u32 const MEM_RESERVE = 0x00002000;
-u32 const PAGE_READWRITE = 0x04;
-u32 const MEM_DECOMMIT = 0x4000;
-u32 const MEM_RELEASE = 0x8000;
-u32 const GENERIC_READ = 0x80000000L;
-u32 const GENERIC_WRITE = 0x40000000L;
-u32 const GENERIC_EXECUTE = 0x20000000L;
-u32 const GENERIC_ALL = 0x10000000L;
-u32 const CREATE_NEW = 1;
-u32 const CREATE_ALWAYS = 2;
-u32 const OPEN_EXISTING = 3;
-u32 const OPEN_ALWAYS = 4;
-u32 const TRUNCATE_EXISTING = 5;
-u32 const FILE_ATTRIBUTE_NORMAL = 0x00000080;
-
-struct RECT
-{
- LONG left;
- LONG top;
- LONG right;
- LONG bottom;
-};
-
-union LARGE_INTEGER
-{
- struct { DWORD LowPart; LONG HighPart; };
- struct { DWORD LowPart; LONG HighPart; } u;
- LONGLONG QuadPart;
-};
-
-union ULARGE_INTEGER
-{
- struct { DWORD LowPart; DWORD HighPart; };
- struct { DWORD LowPart; DWORD HighPart; } u;
- ULONGLONG QuadPart;
-};
-
-struct SECURITY_ATTRIBUTES
-{
- DWORD length;
- void *securityDescriptor;
- BOOL inheritHandle;
-};
-
-struct PROCESS_INFORMATION
-{
- void *hProcess;
- void *hThread;
- DWORD dwProcessId;
- DWORD dwThreadId;
-};
-
-
-struct FILETIME
-{
- DWORD dwLowDateTime;
- DWORD dwHighDateTime;
-};
-
-struct WIN32_FILE_ATTRIBUTE_DATA
-{
- DWORD dwFileAttributes;
- FILETIME ftCreationTime;
- FILETIME ftLastAccessTime;
- FILETIME ftLastWriteTime;
- DWORD nFileSizeHigh;
- DWORD nFileSizeLow;
-};
-
-enum GET_FILEEX_INFO_LEVELS
-{
- GetFileExInfoStandard,
- GetFileExMaxInfoLevel
-};
-
-struct WIN32_FIND_DATAW
-{
- DWORD dwFileAttributes;
- FILETIME ftCreationTime;
- FILETIME ftLastAccessTime;
- FILETIME ftLastWriteTime;
- DWORD nFileSizeHigh;
- DWORD nFileSizeLow;
- DWORD dwReserved0;
- DWORD dwReserved1;
- wchar_t cFileName[MAX_PATH];
- wchar_t cAlternateFileName[14];
-};
-
-struct LIST_ENTRY {
- struct LIST_ENTRY *Flink;
- struct LIST_ENTRY *Blink;
-};
-
-struct RTL_CRITICAL_SECTION_DEBUG
-{
- WORD Type;
- WORD CreatorBackTraceIndex;
- struct CRITICAL_SECTION *CriticalSection;
- LIST_ENTRY ProcessLocksList;
- DWORD EntryCount;
- DWORD ContentionCount;
- DWORD Flags;
- WORD CreatorBackTraceIndexHigh;
- WORD SpareWORD;
-};
-
-struct CRITICAL_SECTION
-{
- RTL_CRITICAL_SECTION_DEBUG *DebugInfo;
- LONG LockCount;
- LONG RecursionCount;
- HANDLE OwningThread;
- HANDLE LockSemaphore;
- ULONG *SpinCount;
-};
-
-struct OVERLAPPED {
- ULONG *Internal;
- ULONG *InternalHigh;
- union {
- struct {
- DWORD Offset;
- DWORD OffsetHigh;
- };
- void *Pointer;
- };
- HANDLE hEvent;
-};
-
-struct SYSTEM_INFO {
- union
- {
- DWORD dwOemId;
- struct
- {
- WORD wProcessorArchitecture;
- WORD wReserved;
- };
- };
- DWORD dwPageSize;
- void *lpMinimumApplicationAddress;
- void *lpMaximumApplicationAddress;
- DWORD *dwActiveProcessorMask;
- DWORD dwNumberOfProcessors;
- DWORD dwProcessorType;
- DWORD dwAllocationGranularity;
- WORD wProcessorLevel;
- WORD wProcessorRevision;
-};
-
-enum LOGICAL_PROCESSOR_RELATIONSHIP
-{
- RelationProcessorCore,
- RelationNumaNode,
- RelationCache,
- RelationProcessorPackage,
- RelationGroup,
- RelationAll = 0xffff
-};
-
-typedef unsigned long *KAFFINITY;
-struct GROUP_AFFINITY {
- KAFFINITY Mask;
- WORD Group;
- WORD Reserved[3];
-};
-
-struct PROCESSOR_RELATIONSHIP
-{
- BYTE Flags;
- BYTE EfficiencyClass;
- BYTE Reserved[20];
- WORD GroupCount;
- GROUP_AFFINITY GroupMask[1];
-};
-
-struct NUMA_NODE_RELATIONSHIP {
- DWORD NodeNumber;
- BYTE Reserved[20];
- GROUP_AFFINITY GroupMask;
-};
-
-enum PROCESSOR_CACHE_TYPE
-{
- CacheUnified,
- CacheInstruction,
- CacheData,
- CacheTrace
-};
-
-struct CACHE_RELATIONSHIP
-{
- BYTE Level;
- BYTE Associativity;
- WORD LineSize;
- DWORD CacheSize;
- PROCESSOR_CACHE_TYPE Type;
- BYTE Reserved[20];
- GROUP_AFFINITY GroupMask;
-};
-
-struct PROCESSOR_GROUP_INFO
-{
- BYTE MaximumProcessorCount;
- BYTE ActiveProcessorCount;
- BYTE Reserved[38];
- KAFFINITY ActiveProcessorMask;
-};
-
-struct GROUP_RELATIONSHIP
-{
- WORD MaximumGroupCount;
- WORD ActiveGroupCount;
- BYTE Reserved[20];
- PROCESSOR_GROUP_INFO GroupInfo[1];
-};
-
-struct SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
-{
- LOGICAL_PROCESSOR_RELATIONSHIP Relationship;
- DWORD Size;
- union
- {
- PROCESSOR_RELATIONSHIP Processor;
- NUMA_NODE_RELATIONSHIP NumaNode;
- CACHE_RELATIONSHIP Cache;
- GROUP_RELATIONSHIP Group;
- };
-};
-
-struct SYSTEMTIME
-{
- WORD wYear;
- WORD wMonth;
- WORD wDayOfWeek;
- WORD wDay;
- WORD wHour;
- WORD wMinute;
- WORD wSecond;
- WORD wMilliseconds;
-};
-
-struct FILETIME
-{
- DWORD dwLowDateTime;
- DWORD dwHighDateTime;
-};
-
-typedef DWORD (*LPTHREAD_START_ROUTINE)(void *lpThreadParameter);
-
-DWORD64 __rdtsc();
-
-void DeleteCriticalSection (CRITICAL_SECTION *lpCriticalSection);
-BOOL DeleteFileA (char const *lpFileName); // TODO(doyle): Wide versions only
-BOOL DeleteFileW (wchar_t const *lpFileName);
-BOOL CloseHandle (HANDLE hObject);
-BOOL CopyFileA (char const *lpExistingFileName, char const *lpNewFileName, BOOL bFailIfExists);
-BOOL CopyFileW (wchar_t const *lpExistingFileName, wchar_t const *lpNewFileName, BOOL bFailIfExists);
-BOOL CloseHandle (HANDLE *hObject);
-HANDLE CreateFileW (wchar_t const *lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, SECURITY_ATTRIBUTES *lpSecurityAttributes,
- DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile);
-HANDLE CreateSemaphoreA (SECURITY_ATTRIBUTES *lpSemaphoreAttributes, long lInitialCount, long lMaximumCount, char const *lpName);
-HANDLE CreateThread (SECURITY_ATTRIBUTES *lpThreadAttributes, size_t dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress,
- void *lpParameter, DWORD dwCreationFlags, DWORD *lpThreadId);
-void EnterCriticalSection (CRITICAL_SECTION *lpCriticalSection);
-BOOL FindClose (HANDLE hFindFile);
-HANDLE FindFirstFileW (wchar_t const *lpFileName, WIN32_FIND_DATAW *lpFindFileData);
-BOOL FindNextFileW (HANDLE hFindFile, WIN32_FIND_DATAW *lpFindFileData);
-DWORD FormatMessageA (DWORD dwFlags, void const *lpSource, DWORD dwMessageId, DWORD dwLanguageId, char *lpBuffer, DWORD nSize, va_list *Arguments);
-BOOL GetClientRect (HWND hWnd, RECT *lpRect);
-BOOL GetExitCodeProcess (HANDLE *hProcess, DWORD *lpExitCode);
-BOOL GetFileSizeEx (HANDLE hFile, LARGE_INTEGER *lpFileSize);
-BOOL GetFileAttributesExW (wchar_t const *lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId, void *lpFileInformation);
-DWORD GetLastError (void);
-void GetLocalTime (SYSTEMTIME *lpSystemTime);
-DWORD GetModuleFileNameA (HMODULE hModule, char *lpFilename, DWORD nSize);
-void GetNativeSystemInfo (SYSTEM_INFO *lpSystemInfo);
-BOOL GetLogicalProcessorInformationEx(LOGICAL_PROCESSOR_RELATIONSHIP RelationshipType, SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *Buffer, DWORD *ReturnedLength);
-BOOL InitializeCriticalSectionEx (CRITICAL_SECTION *lpCriticalSection, DWORD dwSpinCount, DWORD Flags);
-long InterlockedAdd (long volatile *Addend, long Value);
-long InterlockedCompareExchange (long volatile *Destination, long Exchange, long Comparand);
-void LeaveCriticalSection (CRITICAL_SECTION *lpCriticalSection);
-int MessageBoxA (HWND hWnd, char const *lpText, char const *lpCaption, UINT uType);
-int MultiByteToWideChar (unsigned int CodePage, DWORD dwFlags, char const *lpMultiByteStr, int cbMultiByte, wchar_t *lpWideCharStr, int cchWideChar);
-void OutputDebugStringA (char const *lpOutputString);
-BOOL ReadFile (HANDLE hFile, void *lpBuffer, DWORD nNumberOfBytesToRead, DWORD *lpNumberOfBytesRead, OVERLAPPED *lpOverlapped);
-BOOL ReleaseSemaphore (HANDLE hSemaphore, long lReleaseCount, long *lpPreviousCount);
-BOOL QueryPerformanceFrequency (LARGE_INTEGER *lpFrequency);
-BOOL QueryPerformanceCounter (LARGE_INTEGER *lpPerformanceCount);
-DWORD WaitForSingleObject (HANDLE *hHandle, DWORD dwMilliseconds);
-DWORD WaitForSingleObjectEx (HANDLE hHandle, DWORD dwMilliseconds, BOOL bAlertable);
-int WideCharToMultiByte (unsigned int CodePage, DWORD dwFlags, wchar_t const *lpWideCharStr, int cchWideChar,
- char *lpMultiByteStr, int cbMultiByte, char const *lpDefaultChar, BOOL *lpUsedDefaultChar);
-void Sleep (DWORD dwMilliseconds);
-BOOL WriteFile (HANDLE hFile, void *const lpBuffer, DWORD nNumberOfBytesToWrite, DWORD *lpNumberOfBytesWritten, OVERLAPPED *lpOverlapped);
-void *VirtualAlloc (void *lpAddress, size_t dwSize, DWORD flAllocationType, DWORD flProtect);
-BOOL VirtualFree (void *lpAddress, size_t dwSize, DWORD dwFreeType);
-#endif // defined(DQN_PLATFORM_HEADER) && defined(DQN_IS_WIN32) && !defined(_WINDOWS_)
-#ifndef STB_SPRINTF_H_INCLUDE
-#define STB_SPRINTF_H_INCLUDE
-
-////////////////////////////////////////////////////////////////////////////////
-// #DqnSprintf Public API - Cross-platform Sprintf Implementation
-////////////////////////////////////////////////////////////////////////////////
-// stb_sprintf - v1.05 - public domain snprintf() implementation
-// originally by Jeff Roberts / RAD Game Tools, 2015/10/20
-// http://github.com/nothings/stb
-//
-// allowed types: sc uidBboXx p AaGgEef n
-// lengths : h ll j z t I64 I32 I
-//
-// Contributors:
-// Fabian "ryg" Giesen (reformatting)
-//
-// Contributors (bugfixes):
-// github:d26435
-// github:trex78
-// Jari Komppa (SI suffixes)
-// Rohit Nirmal
-// Marcin Wojdyr
-// Leonard Ritter
-//
-// LICENSE:
-//
-// See end of file for license information.
-
-/*
-Single file sprintf replacement.
-Originally written by Jeff Roberts at RAD Game Tools - 2015/10/20.
-Hereby placed in public domain.
-This is a full sprintf replacement that supports everything that
-the C runtime sprintfs support, including float/double, 64-bit integers,
-hex floats, field parameters (%*.*d stuff), length reads backs, etc.
-Why would you need this if sprintf already exists? Well, first off,
-it's *much* faster (see below). It's also much smaller than the CRT
-versions code-space-wise. We've also added some simple improvements
-that are super handy (commas in thousands, callbacks at buffer full,
-for example). Finally, the format strings for MSVC and GCC differ
-for 64-bit integers (among other small things), so this lets you use
-the same format strings in cross platform code.
-It uses the standard single file trick of being both the header file
-and the source itself. If you just include it normally, you just get
-the header file function definitions. To get the code, you include
-it from a C or C++ file and define STB_SPRINTF_IMPLEMENTATION first.
-It only uses va_args macros from the C runtime to do it's work. It
-does cast doubles to S64s and shifts and divides U64s, which does
-drag in CRT code on most platforms.
-It compiles to roughly 8K with float support, and 4K without.
-As a comparison, when using MSVC static libs, calling sprintf drags
-in 16K.
-API:
-====
-int stbsp_sprintf( char * buf, char const * fmt, ... )
-int stbsp_snprintf( char * buf, int count, char const * fmt, ... )
- Convert an arg list into a buffer. stbsp_snprintf always returns
- a zero-terminated string (unlike regular snprintf).
-int stbsp_vsprintf( char * buf, char const * fmt, va_list va )
-int stbsp_vsnprintf( char * buf, int count, char const * fmt, va_list va )
- Convert a va_list arg list into a buffer. stbsp_vsnprintf always returns
- a zero-terminated string (unlike regular snprintf).
-int stbsp_vsprintfcb( STBSP_SPRINTFCB * callback, void * user, char * buf, char const * fmt, va_list va )
- typedef char * STBSP_SPRINTFCB( char const * buf, void * user, int len );
- Convert into a buffer, calling back every STB_SPRINTF_MIN chars.
- Your callback can then copy the chars out, print them or whatever.
- This function is actually the workhorse for everything else.
- The buffer you pass in must hold at least STB_SPRINTF_MIN characters.
- // you return the next buffer to use or 0 to stop converting
-void stbsp_set_separators( char comma, char period )
- Set the comma and period characters to use.
-FLOATS/DOUBLES:
-===============
-This code uses a internal float->ascii conversion method that uses
-doubles with error correction (double-doubles, for ~105 bits of
-precision). This conversion is round-trip perfect - that is, an atof
-of the values output here will give you the bit-exact double back.
-One difference is that our insignificant digits will be different than
-with MSVC or GCC (but they don't match each other either). We also
-don't attempt to find the minimum length matching float (pre-MSVC15
-doesn't either).
-If you don't need float or doubles at all, define STB_SPRINTF_NOFLOAT
-and you'll save 4K of code space.
-64-BIT INTS:
-============
-This library also supports 64-bit integers and you can use MSVC style or
-GCC style indicators (%I64d or %lld). It supports the C99 specifiers
-for size_t and ptr_diff_t (%jd %zd) as well.
-EXTRAS:
-=======
-Like some GCCs, for integers and floats, you can use a ' (single quote)
-specifier and commas will be inserted on the thousands: "%'d" on 12345
-would print 12,345.
-For integers and floats, you can use a "$" specifier and the number
-will be converted to float and then divided to get kilo, mega, giga or
-tera and then printed, so "%$d" 1000 is "1.0 k", "%$.2d" 2536000 is
-"2.53 M", etc. For byte values, use two $:s, like "%$$d" to turn
-2536000 to "2.42 Mi". If you prefer JEDEC suffixes to SI ones, use three
-$:s: "%$$$d" -> "2.42 M". To remove the space between the number and the
-suffix, add "_" specifier: "%_$d" -> "2.53M".
-In addition to octal and hexadecimal conversions, you can print
-integers in binary: "%b" for 256 would print 100.
-PERFORMANCE vs MSVC 2008 32-/64-bit (GCC is even slower than MSVC):
-===================================================================
-"%d" across all 32-bit ints (4.8x/4.0x faster than 32-/64-bit MSVC)
-"%24d" across all 32-bit ints (4.5x/4.2x faster)
-"%x" across all 32-bit ints (4.5x/3.8x faster)
-"%08x" across all 32-bit ints (4.3x/3.8x faster)
-"%f" across e-10 to e+10 floats (7.3x/6.0x faster)
-"%e" across e-10 to e+10 floats (8.1x/6.0x faster)
-"%g" across e-10 to e+10 floats (10.0x/7.1x faster)
-"%f" for values near e-300 (7.9x/6.5x faster)
-"%f" for values near e+300 (10.0x/9.1x faster)
-"%e" for values near e-300 (10.1x/7.0x faster)
-"%e" for values near e+300 (9.2x/6.0x faster)
-"%.320f" for values near e-300 (12.6x/11.2x faster)
-"%a" for random values (8.6x/4.3x faster)
-"%I64d" for 64-bits with 32-bit values (4.8x/3.4x faster)
-"%I64d" for 64-bits > 32-bit values (4.9x/5.5x faster)
-"%s%s%s" for 64 char strings (7.1x/7.3x faster)
-"...512 char string..." ( 35.0x/32.5x faster!)
-*/
-
-#if defined(__has_feature)
- #if __has_feature(address_sanitizer)
- #define STBI__ASAN __attribute__((no_sanitize("address")))
- #endif
-#endif
-#ifndef STBI__ASAN
-#define STBI__ASAN
-#endif
-
-#ifdef STB_SPRINTF_STATIC
-#define STBSP__PUBLICDEC static
-#define STBSP__PUBLICDEF static STBI__ASAN
-#else
-#ifdef __cplusplus
-#define STBSP__PUBLICDEC extern "C"
-#define STBSP__PUBLICDEF extern "C" STBI__ASAN
-#else
-#define STBSP__PUBLICDEC extern
-#define STBSP__PUBLICDEF STBI__ASAN
-#endif
-#endif
-
-#include // for va_list()
-
-#ifndef STB_SPRINTF_MIN
-#define STB_SPRINTF_MIN 512 // how many characters per callback
-#endif
-typedef char *STBSP_SPRINTFCB(char *buf, void *user, int len);
-
-#ifndef STB_SPRINTF_DECORATE
-#define STB_SPRINTF_DECORATE(name) stbsp_##name // define this before including if you want to change the names
-#endif
-
-// Convert a va_list arg list into a buffer. vsnprintf always returns a zero-terminated string (unlike regular snprintf).
-// return: The number of characters copied into the buffer
-STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintf)(char *buf, char const *fmt, va_list va);
-STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsnprintf)(char *buf, int count, char const *fmt, va_list va);
-
-// Write format string to buffer. It always writes the whole string and appends a null.
-// return: The number of characters copied into the buffer not including the null terminator.
-STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(sprintf)(char *buf, char const *fmt, ...);
-STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(snprintf)(char *buf, int count, char const *fmt, ...);
-
-// snprintf() always returns a zero-terminated string (unlike regular snprintf).
-// Convert into a buffer, calling back every STB_SPRINTF_MIN chars.
-// Your callback can then copy the chars out, print them or whatever.
-// This function is actually the workhorse for everything else.
-// The buffer you pass in must hold at least STB_SPRINTF_MIN characters.
-// You return the next buffer to use or 0 to stop converting
-STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, void *user, char *buf, char const *fmt, va_list va);
-
-// Set the comma and period characters to use.
-STBSP__PUBLICDEF void STB_SPRINTF_DECORATE(set_separators)(char comma, char period);
-#endif // STB_SPRINTF_H_INCLUDE
-
-// #DqnDefer
-// =================================================================================================
-template
-struct DqnDefer_
-{
- DqnDefer_(Proc p) : proc(p) { }
- ~DqnDefer_() { proc(); }
- Proc proc;
-};
-
-struct DqnDeferHelper_
-{
- template
- DqnDefer_ operator+(Proc proc) { return DqnDefer_(proc); };
-};
-
-#define DQN_DEFER const auto DQN_UNIQUE_NAME(dqn_defer_lambda_) = DqnDeferHelper_() + [&]()
-
-// #DqnAssert API
-// =================================================================================================
-// NOTE: "## __VA_ARGS__" is a GCC hack. Zero variadic arguments won't compile
-// because there will be a trailing ',' at the end. Pasting it swallows it. MSVC
-// implicitly swallows the trailing comma.
-
-// Always assert are enabled in release mode.
-#define DQN_ALWAYS_ASSERT(expr) DQN_ASSERT_MSG(expr, "")
-#define DQN_ALWAYS_ASSERTM(expr, msg, ...) DQN_ASSERT_MSG(expr, msg, ## __VA_ARGS__)
-
-// Generate a DqnLogger::Context structure
-#define DQN_LOGGER_MAKE_CONTEXT_ \
- { \
- (char *)__FILE__, DQN_CHAR_COUNT(__FILE__), (char *)__func__, DQN_CHAR_COUNT(__func__), __LINE__ \
- }
-
-#define DQN_ASSERT(expr) DQN_ASSERT_MSG(expr, "asserted.")
-#define DQN_ASSERT_MSG(expr, msg, ...) \
- do \
- { \
- if (!(expr)) \
- { \
- dqn_lib_context_.logger->Log(DqnLogger::Type::Error, DQN_LOGGER_MAKE_CONTEXT_, "[" #expr "] " msg, ##__VA_ARGS__); \
- (*((int *)0)) = 0; \
- } \
- } while (0)
-
-// Assert at compile time by making a type that is invalid depending on the expression result
-#define DQN_COMPILE_ASSERT(expr) DQN_COMPILE_ASSERT_INTERNAL(expr, DQN_UNIQUE_NAME(DqnCompileAssertInternal_))
-#define DQN_COMPILE_ASSERT_INTERNAL(expr, name) typedef char name[((int)(expr)) * 2 - 1];
-
-struct DqnLibContext
-{
- struct DqnAllocator *xallocator;
- struct DqnAllocator *allocator;
- struct DqnLogger *logger;
-};
-extern DqnLibContext dqn_lib_context_;
-
-DQN_COMPILE_ASSERT(sizeof(isize) == sizeof(usize));
-
-// #DqnAllocator
-// =================================================================================================
-// A generic structure for managing memory allocations for different Dqn data structures.
-struct DqnAllocator
-{
- enum struct Type
- {
- Default, // Malloc, realloc, free
- XAllocator, // Malloc, realloc, free, crash on failure
- VirtualMemory, // VirtualAlloc, VirtualFree, mmap, munmap
- DqnMemStack,
- };
-
- Type type;
- void *user_context;
-
- DqnAllocator() = default;
- DqnAllocator(Type type_) { *this = {}; type = type_; }
- DqnAllocator(struct DqnMemStack *mem_stack) { *this = {}; type = Type::DqnMemStack; user_context = mem_stack; }
-
- void *Malloc (size_t size, Dqn::ZeroMem zero = Dqn::ZeroMem::No);
- void *Realloc(void *ptr, size_t new_size);
- void Free (void *ptr, size_t old_size);
-};
-
-// #DqnSlice/#DqnBuffer
-// =================================================================================================
-// NOTE: A slice and buffer is the same thing but, slices have the pre-existing concepts of being a
-// a ptr and length into pre-existing allocated memory. So instead, I use buffer to indicate the
-// data structure it self owns the memory it's holding.
-template
-struct DqnSlice
-{
- union { T *data; T *str; };
- int len;
-
- inline int SizeInBytes() const { return len * sizeof(T); }
- operator bool() const { bool result = (str != nullptr); return result; }
- DqnSlice() = default;
- DqnSlice(T *data_, int len_) : data(data_), len(len_) {}
-};
-
-template
-using DqnBuffer = DqnSlice;
-
-#define DQN_BUFFER_STR_LIT(literal) DqnBuffer(literal, DQN_CHAR_COUNT(literal))
-#define DQN_BUFFER_STRCMP(a, b, ignore_case) ((a).len == (b).len && (DqnStr_Cmp((char *)((a).str), (char *)((b).str), (a).len, ignore_case) == 0))
-#define DQN_BUFFER_MEMCMP(a, b) ((a).len == (b).len && (DqnMem_Cmp((void *)((a).str), (void *)((b).str), (a).len) == 0))
-
-#define DQN_SLICE_STRCMP(a, b, ignore_case) ((a).len == (b).len && (DqnStr_Cmp((char *)((a).str), (char *)((b).str), (a).len, ignore_case) == 0))
-#define DQN_SLICE_MEMCMP(a, b) ((a).len == (b).len && (DqnMem_Cmp((void *)((a).str), (void *)((b).str), (a).len) == 0))
-
-template
-DQN_FILE_SCOPE DqnBuffer DqnBuffer_Make(DqnAllocator *allocator, int num, Dqn::ZeroMem clear = Dqn::ZeroMem::Yes)
-{
- DqnBuffer result = {};
- result.len = num;
- result.data = static_cast(allocator->Malloc(num * sizeof(T), clear));
- return result;
-}
-
-template
-DQN_FILE_SCOPE DqnBuffer DqnBuffer_Copy(DqnAllocator *allocator, T const *data, int len)
-{
- DqnBuffer result;
- result.len = len;
- result.data = static_cast(allocator->Malloc(len * sizeof(T), Dqn::ZeroMem::No));
- DqnMem_Copy(result.data, data, len * sizeof(T));
- return result;
-}
-
-template
-DQN_FILE_SCOPE DqnBuffer DqnBuffer_CopyAndNullTerminate(DqnAllocator *allocator, T const *data, int len)
-{
- DqnBuffer result;
- result.len = len;
- result.data = static_cast(allocator->Malloc((len + 1) * sizeof(T), Dqn::ZeroMem::No));
- DqnMem_Copy(result.data, data, len * sizeof(T));
- result.data[len] = 0;
- return result;
-}
-
-// #DqnFixedString Public API - Fixed sized strings at compile time
-// =================================================================================================
-template
-struct DqnFixedString
-{
- int len;
- char str[MAX];
-
- DqnFixedString(): len(0) { this->str[0] = 0; }
- DqnFixedString(char const *fmt, ...) { va_list va; va_start(va, fmt); len = stbsp_vsnprintf(str, MAX, fmt, va); va_end(va); DQN_ASSERT(len < MAX); }
- DqnFixedString(char const *fmt, va_list va) { len = stbsp_vsnprintf(str, MAX, fmt, va); DQN_ASSERT(len < MAX); }
- DqnFixedString(DqnSlice const &other) { DqnMem_Copy(str, other.str, other.len); len = other.len; str[len] = 0; }
- DqnFixedString(DqnSlice const &other) { DqnMem_Copy(str, other.str, other.len); len = other.len; str[len] = 0; }
- DqnFixedString(DqnFixedString const &other) { if (this != &other) { DqnMem_Copy(str, other.str, other.len); len = other.len; str[len] = 0; } }
-
- DqnFixedString &operator+=(char const *other) { int other_len = Dqn_StrLen(other); DqnMem_Copy(str + len, other, other_len); len += other_len; str[len] = 0; DQN_ASSERT(len < MAX); return *this; }
- DqnFixedString &operator+=(DqnSlice const &other) { DqnMem_Copy(str + len, other.str, other.len); len += other.len; str[len] = 0; DQN_ASSERT(len < MAX); return *this; }
- DqnFixedString &operator+=(DqnSlice const &other) { DqnMem_Copy(str + len, other.str, other.len); len += other.len; str[len] = 0; DQN_ASSERT(len < MAX); return *this; }
- DqnFixedString &operator+=(DqnFixedString const &other) { DqnMem_Copy(str + len, other.str, other.len); len += other.len; str[len] = 0; DQN_ASSERT(len < MAX); return *this; }
-
- DqnFixedString operator+ (char const *other) { auto result = *this; int other_len = Dqn_StrLen(other); DqnMem_Copy(str + len, other, other_len); len += other_len; str[len] = 0; DQN_ASSERT(len < MAX); return result; }
- DqnFixedString operator+ (DqnSlice const &other) { auto result = *this; DqnMem_Copy(str + len, other.str, other.len); len += other.len; str[len] = 0; DQN_ASSERT(len < MAX); return result; }
- DqnFixedString operator+ (DqnSlice const &other) { auto result = *this; DqnMem_Copy(str + len, other.str, other.len); len += other.len; str[len] = 0; DQN_ASSERT(len < MAX); return result; }
- DqnFixedString operator+ (DqnFixedString const &other) { auto result = *this; DqnMem_Copy(str + len, other.str, other.len); len += other.len; str[len] = 0; DQN_ASSERT(len < MAX); return result; }
-
- // Xprintf functions always modifies buffer and null-terminates even with insufficient buffer size.
- // Asserts on failure if DQN_ASSERT is defined.
- // return: The number of characters copied to the buffer
- int SprintfAppend (char const *fmt, ...) { va_list va; va_start(va, fmt); int extra = stbsp_sprintf (str + len, MAX, fmt, va); len += extra; DQN_ASSERT(len < MAX); va_end(va); return extra; }
- int VSprintfAppend(char const *fmt, va_list va) { int extra = stbsp_vsnprintf(str + len, MAX, fmt, va); len += extra; DQN_ASSERT(len < MAX); return extra; }
- void NullTerminate () { str[len] = 0; } // NOTE: If you modify the storage directly, this can be handy.
- void Clear (Dqn::ZeroMem clear = Dqn::ZeroMem::No) { if (clear == Dqn::ZeroMem::Yes) DqnMem_Set(str, 0, MAX); *this = {}; }
-};
-
-using DqnFixedString16 = DqnFixedString<16>;
-using DqnFixedString32 = DqnFixedString<32>;
-using DqnFixedString64 = DqnFixedString<64>;
-using DqnFixedString128 = DqnFixedString<128>;
-using DqnFixedString256 = DqnFixedString<256>;
-using DqnFixedString512 = DqnFixedString<512>;
-using DqnFixedString1024 = DqnFixedString<1024>;
-using DqnFixedString2048 = DqnFixedString<2048>;
-
-// #DqnMem
-// =================================================================================================
-// TODO(doyle): Use platform allocation, fallback to malloc if platform not defined
-DQN_FILE_SCOPE void *DqnMem_Alloc (usize size);
-DQN_FILE_SCOPE void *DqnMem_XAlloc (usize size);
-DQN_FILE_SCOPE void *DqnMem_XCalloc (usize size);
-DQN_FILE_SCOPE void DqnMem_Clear (void *memory, u8 clear_val, usize size);
-DQN_FILE_SCOPE void *DqnMem_Realloc (void *memory, usize new_size);
-DQN_FILE_SCOPE void *DqnMem_XRealloc(void *memory, usize new_size);
-DQN_FILE_SCOPE void DqnMem_Free (void *memory);
-DQN_FILE_SCOPE void DqnMem_Copy (void *dest, void const *src, usize num_bytes_to_copy);
-DQN_FILE_SCOPE void *DqnMem_Set (void *dest, u8 value, usize num_bytes_to_set);
-DQN_FILE_SCOPE int DqnMem_Cmp (void const *src, void const *dest, usize num_bytes);
-
-// #DqnMemTracker
-// =================================================================================================
-// Allocation Layout
-// +--------------------+-------------------------------------------------------------------------+------------------------+-----------------+
-// | Ptr From Allocator | Offset To Src | Alignment | Alloc Type | Alloc Amount | B. Guard (Opt.) | Aligned Ptr For Client | B. Guard (Opt.) |
-// +--------------------+-------------------------------------------------------------------------+------------------------+-----------------+
-// Ptr From Allocator: The pointer returned by the allocator, not aligned
-// Offset To Src: Number of bytes to subtract from the "Aligned Ptr For Client" to return to the "Ptr From Allocator"
-// Alignment: The pointer given to the client is aligned to this power of two boundary
-// Alloc Type: If the allocation was allocated from the head or tail of the memory block (mainly for memstacks).
-// Alloc Amount: The requested allocation amount by the client (so does not include metadata)
-// B. Guard: Bounds Guard value.
-// Aligned Ptr For Client: The allocated memory for the client.
-
-#pragma pack(push, 1)
-struct DqnPtrHeader
-{
- u8 offset_to_src_ptr; // Offset to subtract from the client ptr to receive the allocation ptr
- u8 alignment;
- u8 alloc_type; // TODO(doyle): alloc_type is a memstack specific thing
- usize alloc_amount;
-};
-#pragma pack(pop)
-
-struct DqnMemTracker
-{
- enum Flag
- {
- None = 0,
- TrackPtr = (1 << 0),
- BoundsGuard = (1 << 1),
- TagAllocation = (1 << 2),
- Simple = (TrackPtr | BoundsGuard),
- All = (TrackPtr | BoundsGuard | TagAllocation),
- };
-
- struct TaggedAllocation
- {
- DqnBuffer filename;
- DqnBuffer function;
- size_t line_num;
- isize bytes_allocated;
- TaggedAllocation *next;
- };
-
- static u32 const HEAD_GUARD_VALUE = 0xCAFEBABE;
- static u32 const TAIL_GUARD_VALUE = 0xDEADBEEF;
-
- void **ptrs; // If track_ptr was set, ptrs is an array to all the pointers that get passed through SetupPtr, otherwise null
- int ptrs_len;
- int ptrs_max;
- u32 bounds_guard_size; // If bounds_guard was set, sizeof(GUARD_VALUE) otherwise 0
-
- u16 tagged_allocs_max;
- TaggedAllocation **tagged_allocs;
- u16 *tagged_allocs_used_list;
- u16 tagged_allocs_used_index;
-
- void Init (Flag flag);
- void Free ();
- bool IsTrackingPtrs () const { return (ptrs != nullptr); }
- bool IsGuardingBounds () const { return (bounds_guard_size > 0); }
- bool IsTaggingAllocations() const { return (tagged_allocs_used_index > 0); } // TODO(doyle): Just store the flags instead of these unreasonable checks
-
-#define DQN_STRINGIFY(val) DQN_STRINGIFY2(val)
-#define DQN_STRINGIFY2(val) #val
-#define DQN_MEMTRACKER_TAG_ALLOC(tracker, size) (tracker)->Tag_(DQN_BUFFER_STR_LIT(__FILE__), DQN_BUFFER_STR_LIT(__func__), __LINE__, DQN_BUFFER_STR_LIT(__FILE__ DQN_STRINGIFY(__LINE__)), (isize)size)
- void Tag_(DqnBuffer filename, DqnBuffer function, int line_num, DqnBuffer filename_line_num_data, isize bytes);
-
- // MemTracker setups up the ptr by adding a DqnPtrHeader to each given ptr. When the client
- // requests an allocation, use GetAllocationSize() to get the adjusted size necessary for adding
- // the tracking metadata, then pass in the allocated ptr into SetupPtr.
-
- // If MemTracker was init with
- // - track_ptr: it also tracks each ptr passed in
- // - bounds_guard: it also adds a 4 byte magic value on both sides of the ptr
- // size: The original size requested, i.e. before GetAllocationSize adjusted it
- void *SetupPtr (void *ptr, isize size, u8 alignment);
-
- void RemovePtr (void *ptr);
- void RemovePtrRange (void *begin, void *end);
- void CheckPtrs () const;
- usize GetAllocationSize (usize size, u8 alignment = 1) const { return sizeof(DqnPtrHeader) + bounds_guard_size + (alignment - 1) + size + bounds_guard_size; }
-
- // ptr: The ptr given to the client when allocating.
- u32 *PtrToHeadGuard (char *ptr) const { return reinterpret_cast(ptr - bounds_guard_size); }
- u32 *PtrToTailGuard (char *ptr) const { return reinterpret_cast(ptr + PtrToHeader(ptr)->alloc_amount); }
- DqnPtrHeader *PtrToHeader (char *ptr) const { return reinterpret_cast(ptr - bounds_guard_size - sizeof(DqnPtrHeader)); }
-};
-
-// #DqnMemStack
-// =================================================================================================
-// DqnMemStack is a memory allocator in a stack like, push-pop style. It
-// pre-allocates a block of memory at init and sub-allocates from this block to
-// take advantage of memory locality. You can allocate and grow the stack from
-// the bottom and/or allocate from the top and grow downwards until space is
-// insufficient in the memory block.
-
-// When an allocation requires a larger amount of memory than available in the
-// block then the MemStack will allocate a new block of sufficient size for you
-// in Push(..). This DOES mean that occasionally there will be wasted space at
-// the end of each block and is a tradeoff for memory locality against optimal
-// space usage.
-
-// My convention with using a memory stack is, any function that takes a memory
-// stack must revert all allocations from the the end of the stack in the scope
-// it was used in. If the function takes an allocator, then it must always do
-// some operation that allocates persistent data into the head of the allocator.
-
-// If a function requires an allocator purely for temporary purposes, then there
-// always exists some non-user facing global allocator that is accessible which
-// it can use.
-
-#define DQN_MEMSTACK_PUSH(stack, size) DQN_MEMSTACK_PUSH_ARRAY(stack, char, size)
-#define DQN_MEMSTACK_PUSH_STRUCT(stack, Type) DQN_MEMSTACK_PUSH_ARRAY(stack, Type, 1)
-#define DQN_MEMSTACK_PUSH_ARRAY(stack, Type, num) (Type *)(stack)->Push_(sizeof(Type) * (num)); DQN_MEMTRACKER_TAG_ALLOC(&(stack)->tracker, sizeof(Type) * num)
-
-#define DQN_MEMSTACK_PUSH_BACK(stack, size) DQN_MEMSTACK_PUSH_BACK_ARRAY(stack, char, size)
-#define DQN_MEMSTACK_PUSH_BACK_STRUCT(stack, Type) DQN_MEMSTACK_PUSH_BACK_ARRAY(stack, Type, 1)
-#define DQN_MEMSTACK_PUSH_BACK_ARRAY(stack, Type, num) (Type *)(stack)->Push_(sizeof(Type) * (num), DqnMemStack::PushType::Opposite); DQN_MEMTRACKER_TAG_ALLOC(&(stack)->tracker, sizeof(Type) * num)
-
-struct DqnMemStack
-{
- static const i32 MINIMUM_BLOCK_SIZE = DQN_KILOBYTE(64);
-
- enum Flag
- {
- NonExpandable = (1 << 0), // Disallow additional memory blocks when full.
- NonExpandableAssert = (1 << 1), // Assert when non-expandable is set and we run out of space
- DefaultAllocateTail = (1 << 2), // Allocate to tail when push_type is unspecified, otherwise allocate to head
- };
-
- struct Info // Statistics of the memory stack.
- {
- isize total_used;
- isize total_size;
- isize wasted_size;
- i32 num_blocks;
- };
-
- struct Block
- {
- char *memory;
- isize size;
- char *head;
- char *tail;
- Block *prev_block;
-
- Block() = default;
- Block(void *memory_, isize size_) { *this = {}; memory = (char *)memory_; size = size_; head = memory; tail = memory + size; }
- isize Usage() const { return size - (tail - head); }
- };
-
- DqnMemTracker tracker; // Metadata for managing ptr allocation
- DqnAllocator *block_allocator; // Memory block allocator
- Block *block; // Backing memory storage
- u32 flags;
- i32 mem_region_count; // The number of memory regions in use
-
- // Initialisation
- // =============================================================================================
- DqnMemStack() = default; // Zero Is Initialisation, on first allocation LazyInit() is called.
- DqnMemStack(void *mem, isize size, Dqn::ZeroMem clear, u32 flags_ = 0, DqnMemTracker::Flag flags = DqnMemTracker::Flag::Simple); // Use fixed memory from the given buffer. Assert after buffer is full.
-
- // Init and alloc additional memory blocks when full, but only if NonExpandable flag is not set.
- DqnMemStack (isize size, Dqn::ZeroMem clear, u32 flags_ = 0, DqnMemTracker::Flag tracker_flags = DqnMemTracker::Simple, DqnAllocator *block_allocator_ = dqn_lib_context_.allocator) { LazyInit(size, clear, flags_, tracker_flags, block_allocator_); }
- void LazyInit(isize size, Dqn::ZeroMem clear, u32 flags_ = 0, DqnMemTracker::Flag tracker_flags = DqnMemTracker::Simple, DqnAllocator *block_allocator_ = dqn_lib_context_.allocator);
-
- // Allocation
- // =============================================================================================
- enum struct AllocMode
- {
- Head, // Set the default to allocating to the start of the memory block
- Tail, // Set the default to allocating from the end of the memory block
- };
-
- enum struct PushType
- {
- Default, // Allocation defaults to the AllocMode set in SetAllocMode(), by default this is initialised to be from the start of the memory stack.
- Opposite, // Opposite is always the opposite side of the current default allocation mode.
-
- // TODO(doyle): Head and Tail are possibly redundant modes now. When the
- // client changes the default allocation mode outside of functions that
- // take a memory stack as an allocator, it means if the function wants
- // to use the "temporary" side of the memory stack, they need to be
- // aware of what the opposite side of the memory stack is as to not
- // trample over the memory that the client wants allocated memory from.
-
- // This is what the 2 new PushType options above facilitate. I can't
- // immediately see a situation now where you want to actually specify
- // the side and override the allocation mode which could make for
- // unintuitive behaviour, but I'm going to sit on this for awhile and
- // see how the actual real world use cases pan out.
-
- Head, // Ignores the AllocMode, always allocate from the start of the memory block
- Tail, // Ignores the AllocMode, always allocate from the end of the memory block
- };
-
- // NOTE: Prefer the macro to enable allocation tagging if defined.
- // Allocate memory from the MemStack.
- // alignment: Must be a power of 2, ptr returned from allocator is address aligned to this value.
- // return: Ptr to memory, nullptr if out of space and is disallowed to expand OR the stack is full and malloc fails
- void *Push_ (usize size, PushType push_type = PushType::Default, u8 alignment = 4);
-
- // On Push, if push_type is PushType::Default, it will behave according to the AllocMode last set.
- void SetAllocMode (AllocMode mode) { if (mode == AllocMode::Head) flags &= ~Flag::DefaultAllocateTail; else flags |= Flag::DefaultAllocateTail; }
-
- // TODO(doyle): Edge case where Pop fails. If you Push to the head and it
- // fits in the existing block. Then push to the tail a size larger than the
- // remaining space and generate a new block, then, if you try to Pop the ptr
- // from the head, it will not find the right block to pop from and assert.
- void Pop (void *ptr, Dqn::ZeroMem zero = Dqn::ZeroMem::No); // Free the ptr. MUST be the last allocated ptr on the block head or tail, assert otherwise.
- void PopBlock () { FreeBlock(block); }
- void Free () { tracker.Free(); while (block_allocator && block) PopBlock(); }
- bool FreeBlock (DqnMemStack::Block *mem_block);
- void Reset (Dqn::ZeroMem zero) { while(block && block->prev_block) PopBlock(); ClearCurrBlock(zero); }
- void ResetTail (); // Reset just the tail
- void ClearCurrBlock (Dqn::ZeroMem zero = Dqn::ZeroMem::No); // Reset the current memory block usage to 0.
- Info GetInfo () const;
-
- // Temporary Memory Regions
- // =============================================================================================
- // Revert all allocations between the Begin() and End() regions. Scope version is RAII'ed.
- struct MemRegion
- {
- DqnMemStack *stack; // Stack associated with this MemRegion
- Block *starting_block; // The block to revert back to
- char *starting_block_head;
- char *starting_block_tail;
- };
-
- struct MemRegionScoped
- {
- MemRegionScoped(DqnMemStack *stack) { region = stack->MemRegionBegin(); }
- ~MemRegionScoped() { if (region.stack) region.stack->MemRegionEnd(region); }
- MemRegion region;
- };
-
- MemRegion MemRegionBegin ();
- void MemRegionEnd (MemRegion region);
- MemRegionScoped MemRegionScope () { return MemRegionScoped(this); };
-
- // Keep allocations that have occurred since Begin(). End() does not need to be called anymore.
- void MemRegionSave (MemRegion *region);
- void MemRegionSave (MemRegionScoped *scope) { MemRegionSave(&scope->region); }
-};
-
-// #DqnLogger Public
-// =================================================================================================
-struct DqnLogger
-{
-#define LOG_TYPES \
- X(Warning, "WRN") \
- X(Error, "ERR") \
- X(Debug, "DBG") \
- X(Memory, "MEM") \
- X(Message, "MSG")
-
-#define X(type, prefix) type,
- enum struct Type { LOG_TYPES };
-#undef X
-
-#define X(type, prefix) prefix,
- static char const *TypePrefix(Type type)
- {
- LOCAL_PERSIST char const *type_string[] = {LOG_TYPES};
- return type_string[static_cast(type)];
- }
-#undef X
-#undef LOG_TYPES
-
- struct Context
- {
- char *filename;
- int filename_len;
- char *function;
- int function_len;
- int line_num;
- };
-
- #define DQN_LOGGER(logger, type, fmt, ...) (logger)->Log(type, DQN_LOGGER_MAKE_CONTEXT_, fmt, ## __VA_ARGS__)
- #define DQN_LOGGER_E(logger, fmt, ...) (logger)->Log(DqnLogger::Type::Error, DQN_LOGGER_MAKE_CONTEXT_, fmt, ## __VA_ARGS__)
- #define DQN_LOGGER_W(logger, fmt, ...) (logger)->Log(DqnLogger::Type::Warning, DQN_LOGGER_MAKE_CONTEXT_, fmt, ## __VA_ARGS__)
- #define DQN_LOGGER_D(logger, fmt, ...) (logger)->Log(DqnLogger::Type::Debug, DQN_LOGGER_MAKE_CONTEXT_, fmt, ## __VA_ARGS__)
- #define DQN_LOGGER_M(logger, fmt, ...) (logger)->Log(DqnLogger::Type::Message, DQN_LOGGER_MAKE_CONTEXT_, fmt, ## __VA_ARGS__)
-
- DqnMemStack allocator;
- DqnFixedString1024 log_builder;
- DqnBuffer log_buf;
- int log_buf_index;
-
- // TODO(doyle): Switch to bit flags
- b32 no_console; // Log to console if false.
- b32 no_print_error;
- b32 no_print_debug;
- b32 no_print_warning;
-
- // Build up a log line that gets prepended to the next log. When Log() is called and is then reset.
- //
- void PrependToLog(char const *fmt, ...) { va_list va; va_start (va, fmt); log_builder.VSprintfAppend(fmt, va); va_end(va); }
-
- // return: A static string whose lifetime persists until the next log call.
- char const *LogNoContext(Type type, char const *fmt, ...);
- char const *Log (Type type, Context log_context, char const *fmt, ...);
- char const *LogVA (Type type, Context log_context, char const *fmt, va_list va);
-};
-
-// #DqnArray
-// =================================================================================================
-template
-struct DqnArray
-{
- DqnAllocator *allocator = dqn_lib_context_.allocator;
- isize len;
- isize max;
- T *data;
-
- DqnArray () = default;
- DqnArray (DqnAllocator *allocator) { *this = {}; this->allocator = allocator; }
- DqnArray (T *data_, isize max_, isize len_ = 0) { *this = {}; this->allocator = nullptr; this->data = data_; this->max = max_; this->len = len_; }
-
- void Clear (Dqn::ZeroMem clear = Dqn::ZeroMem::No) { if (!data) return; len = 0; if (clear == Dqn::ZeroMem::Yes) DqnMem_Clear(data, 0, sizeof(T) * max); }
- void Free () { if (data) { allocator->Free(data, sizeof(*data) * max); } *this = {}; }
- T *Front () { DQN_ASSERT_MSG(len > 0, "len: %zu", len); return data + 0; }
- T *Back () { DQN_ASSERT_MSG(len > 0, "len: %zu", len); return data + (len - 1); }
- void Resize (isize new_len) { if (new_len > max) Reserve(GrowCapacity_(new_len)); len = new_len; }
- void Resize (isize new_len, T const *v) { if (new_len > max) Reserve(GrowCapacity_(new_len)); if (new_len > len) for (isize n = len; n < new_len; n++) data[n] = *v; len = new_len; }
- void Reserve (isize new_max);
- T *Make (isize len_ = 1) { len += len_; if (len > max) Reserve(GrowCapacity_(len)); return &data[len - len_]; }
- T *Add (T const &v) { if (len + 1 > max) Reserve(GrowCapacity_(len + 1)); data[len++] = v; return data + (len-1); }
- T *Add (T const *v, isize v_len) { isize new_len = len + v_len; if (new_len > max) Reserve(GrowCapacity_(new_len)); T *result = data + len; for (isize i = 0; i < v_len; ++i) data[len++] = v[i]; return result; }
- void Pop () { if (len > 0) len--; }
- void Erase (isize index) { DQN_ASSERT_MSG(index >= 0 && index < len, "index: %zu, len: %zu", index, len); data[index] = data[--len]; }
- void EraseStable(isize index);
- T *Insert (isize index, T const *v) { return Insert(index, v, 1); }
- T *Insert (isize index, T const &v) { return Insert(index, &v, 1); }
- T *Insert (isize index, T const *v, isize len_items);
- bool Contains (T const *v) const { T const *ptr = data; T const *end = data + len; while (ptr < end) if (*ptr++ == *v) return true; return false; }
-
- T &operator[] (isize i) const { DQN_ASSERT_MSG(i >= 0 && i < len, "i: %zu, len: %zu", i, len); return this->data[i]; }
- T *begin () { return data; }
- T *begin () const { return data; }
- T *end () { return data + len; }
- T *end () const { return data + len; }
-
-private:
- isize GrowCapacity_(isize size) const { isize new_max = max ? (max * 2) : 8; return new_max > size ? new_max : size; }
-};
-
-template T *DqnArray::Insert(isize index, T const *v, isize len_items)
-{
- index = DQN_MIN(DQN_MAX(index, 0), len);
- isize const new_len = len + len_items;
-
- if (new_len >= max)
- Reserve(GrowCapacity_(new_len));
-
- T *src = data + index;
- T *dest = src + len_items;
-
- if (src < dest)
- memmove(dest, src, ((data + len) - src) * sizeof(T));
-
- len = new_len;
- for (isize i = 0; i < len_items; i++)
- src[i] = v[i];
-
- return src;
-}
-
-template void DqnArray::EraseStable(isize index)
-{
- DQN_ASSERT(index >= 0 && index < len);
- isize const off = (data + index) - data;
- memmove(data + off, data + off + 1, ((usize)len - (usize)off - 1) * sizeof(T));
- len--;
-}
-
-template void DqnArray::Reserve(isize new_max)
-{
- if (new_max <= max) return;
-
- if (data)
- {
- T *newData = (T *)allocator->Realloc(data, new_max * sizeof(T));
- data = newData;
- max = new_max;
- }
- else
- {
- data = (T *)allocator->Malloc(new_max * sizeof(T));
- max = new_max;
- }
-
- DQN_ASSERT(data);
-}
-
-// #DqnChar
-// =================================================================================================
-DQN_FILE_SCOPE char DqnChar_ToLower (char c);
-DQN_FILE_SCOPE char DqnChar_ToUpper (char c);
-DQN_FILE_SCOPE bool DqnChar_IsDigit (char c);
-DQN_FILE_SCOPE bool DqnChar_IsAlpha (char c);
-DQN_FILE_SCOPE bool DqnChar_IsAlphaNum (char c);
-DQN_FILE_SCOPE bool DqnChar_IsEndOfLine (char c);
-DQN_FILE_SCOPE bool DqnChar_IsWhitespace(char c);
-
-DQN_FILE_SCOPE char *DqnChar_TrimWhitespaceAround(char const *src, i32 src_len, i32 *new_len);
-DQN_FILE_SCOPE char *DqnChar_SkipWhitespace (char const *ptr);
-
-// TODO(doyle): this is NOT UTF8 safe
-// ch: Char to find
-// len: The length of the string stored in ptr, (doesn't care if it includes null terminator)
-// len_to_char: The length to the char from end of the ptr, i.e. (ptr + len)
-// return: The ptr to the last char, null if it could not find.
-DQN_FILE_SCOPE char *DqnChar_FindLastChar (char *ptr, char ch, i32 len, u32 *len_to_char);
-
-// #DqnStr
-// =================================================================================================
-// num_bytes_to_cmp: If -1, cmp runs until \0 is encountered.
-// return: 0 if equal. 0 < if a is before b, > 0 if a is after b
-DQN_FILE_SCOPE i32 DqnStr_Cmp (char const *a, char const *b, i32 num_bytes_to_cmp = -1, Dqn::IgnoreCase ignore = Dqn::IgnoreCase::No);
-
-// str_len: Len of string, if -1, StrLen is used.
-// return: Pointer in str to the last slash, if none then the original string.
-DQN_FILE_SCOPE char *DqnStr_GetPtrToLastSlash (char const *str, i32 str_len = -1);
-
-// return: String length not including the nullptr terminator. 0 if invalid args.
-DQN_FILE_SCOPE i32 DqnStr_Len (char const *a);
-DQN_FILE_SCOPE i32 DqnStr_LenUTF8 (u32 const *a, i32 *len_in_bytes = nullptr);
-
-// return: String length starting from a, up to and not including the first delimiter character.
-DQN_FILE_SCOPE i32 DqnStr_LenDelimitWith (char const *a, char delimiter);
-
-// return: The dest argument, nullptr if args invalid (i.e. nullptr pointers or numChars < 0)
-DQN_FILE_SCOPE void DqnStr_Reverse (char *buf, isize buf_size);
-
-// return: Number of bytes in codepoint, 0 if *a becomes invalid or end of stream.
-DQN_FILE_SCOPE i32 DqnStr_ReadUTF8Codepoint (u32 const *a, u32 *out_codepoint);
-
-// return: The offset into the src to first char of the found string. Returns -1 if not found
-DQN_FILE_SCOPE i32 DqnStr_FindFirstOccurence (char const *src, i32 src_len, char const *find, i32 find_len, Dqn::IgnoreCase ignore = Dqn::IgnoreCase::No);
-DQN_FILE_SCOPE bool DqnStr_EndsWith (char const *src, i32 src_len, char const *find, i32 find_len, Dqn::IgnoreCase ignore = Dqn::IgnoreCase::No);
-
-// return: Helper function that returns the pointer to the first occurence, nullptr if not found.
-DQN_FILE_SCOPE char *DqnStr_GetFirstOccurence (char const *src, i32 src_len, char const *find, i32 find_len, Dqn::IgnoreCase ignore = Dqn::IgnoreCase::No);
-DQN_FILE_SCOPE bool DqnStr_HasSubstring (char const *src, i32 src_len, char const *find, i32 find_len, Dqn::IgnoreCase ignore = Dqn::IgnoreCase::No);
-
-DQN_FILE_SCOPE DqnSlice DqnStr_RemoveLeadTrailChar (char const *str, i32 str_len, char lead_char, char trail_char);
-DQN_FILE_SCOPE inline DqnSlice DqnStr_RemoveLeadTrailQuotes (DqnSlice slice);
-DQN_FILE_SCOPE inline DqnSlice DqnStr_RemoveLeadTrailBraces (DqnSlice slice);
-DQN_FILE_SCOPE inline DqnSlice DqnStr_RemoveLeadTrailQuotes (char const *str, i32 str_len);
-DQN_FILE_SCOPE inline DqnSlice DqnStr_RemoveLeadTrailBraces (char const *str, i32 str_len);
-
-// #DqnWChar
-// =================================================================================================
-// NOTE: See above for documentation
-DQN_FILE_SCOPE bool DqnWChar_IsDigit (wchar_t c);
-DQN_FILE_SCOPE wchar_t DqnWChar_ToLower (wchar_t c);
-
-DQN_FILE_SCOPE wchar_t *DqnWChar_SkipWhitespace (wchar_t *ptr);
-DQN_FILE_SCOPE wchar_t *DqnWChar_FindLastChar (wchar_t *ptr, wchar_t ch, i32 len, u32 *len_to_char);
-DQN_FILE_SCOPE i32 DqnWChar_GetNextLine (wchar_t *ptr, i32 *line_len);
-
-// #DqnWStr
-// =================================================================================================
-DQN_FILE_SCOPE i32 DqnWStr_Cmp (wchar_t const *a, wchar_t const *b);
-DQN_FILE_SCOPE i32 DqnWStr_FindFirstOccurence(wchar_t const *src, i32 src_len, wchar_t const *find, i32 find_len);
-DQN_FILE_SCOPE bool DqnWStr_HasSubstring (wchar_t const *src, i32 src_len, wchar_t const *find, i32 find_len);
-DQN_FILE_SCOPE i32 DqnWStr_Len (wchar_t const *a);
-DQN_FILE_SCOPE i32 DqnWStr_LenDelimitWith (wchar_t const *a, wchar_t delimiter);
-DQN_FILE_SCOPE void DqnWStr_Reverse (wchar_t *buf, i32 buf_size);
-
-// #DqnString
-// =================================================================================================
-struct DqnString
-{
- DqnAllocator *allocator = dqn_lib_context_.allocator;
- int len = 0;
- int max = 0;
- char *str = nullptr;
-
- DqnString() = default;
- DqnString(char *buf, int max_) : len(0), str(buf) { max = max_; NullTerminate(); }
- DqnString(char const *str_) { Append(str_); }
- DqnString(char const *str_, int len_) { Append(str_, len_); }
- DqnString(DqnSlice const &other) { Append(other.data, other.len); }
- DqnString(DqnSlice const &other) { Append(other.data, other.len); }
- DqnString(DqnString const &other) { if (this == &other) return; *this = other; } // TODO(doyle): I can't decide on copy semantics
-
- DqnString &operator+=(char const *other) { Append(other); return *this; }
- DqnString &operator+=(DqnSlice const &other) { Append(other.data, other.len); return *this; }
- DqnString &operator+=(DqnSlice const &other) { Append(other.data, other.len); return *this; }
- DqnString &operator+=(DqnString const &other) { Append(other.str, other.len); return *this; }
-
- DqnString operator+ (char const *other) { auto result = *this; result.Append(other); return result; }
- DqnString operator+ (DqnSlice const &other) { auto result = *this; result.Append(other.data, other.len); return result; }
- DqnString operator+ (DqnSlice const &other) { auto result = *this; result.Append(other.data, other.len); return result; }
- DqnString operator+ (DqnString const &other) { auto result = *this; result.Append(other.str, other.len); return result; }
-
- // Xprintf functions always modifies buffer and null-terminates even with insufficient buffer size.
- // return: The number of characters copied to the buffer
- int Sprintf (char const *fmt, ...) { va_list va; va_start(va, fmt); int result = VSprintf (fmt, va); va_end(va); return result; }
- int SprintfAppend (char const *fmt, ...) { va_list va; va_start(va, fmt); int result = VSprintfAppend(fmt, va); va_end(va); return result; }
-
- int VSprintf (char const *fmt, va_list va) { return VSprintfAtOffset(fmt, va, 0 /*offset*/); }
- int VSprintfAppend (char const *fmt, va_list va) { return VSprintfAtOffset(fmt, va, len/*offset*/); }
-
- void NullTerminate () { str[len] = 0; } // NOTE: If you modify the storage directly, this can be handy.
- void Clear (Dqn::ZeroMem clear = Dqn::ZeroMem::No) { if (clear == Dqn::ZeroMem::Yes) DqnMem_Set(str, 0, max); len = max = 0; NullTerminate(); }
- void Free () { if (str) allocator->Free(str, sizeof(*str) * len); str = nullptr; }
- void Resize (int new_max) { if (new_max > max) Reserve(new_max); len = DQN_MIN(new_max, len); NullTerminate(); }
- void Reserve (int new_max);
-
- void Append (char const *src, int len_ = -1);
- int VSprintfAtOffset(char const *fmt, va_list va, int offset) { Reserve(len + stbsp_vsnprintf(nullptr, 0, fmt, va) + 1); int result = stbsp_vsnprintf(str + offset, max - len, fmt, va); len = (offset + result); return result; }
-
- static bool Cmp (DqnString const *a, DqnString const *b, Dqn::IgnoreCase ignore = Dqn::IgnoreCase::No) { return (a->len == b->len) && (DqnStr_Cmp(a->str, b->str, a->len, ignore) == 0); }
- static bool Cmp (DqnString const *a, DqnSlice const b, Dqn::IgnoreCase ignore = Dqn::IgnoreCase::No) { return (a->len == b.len) && (DqnStr_Cmp(a->str, b.data, b.len, ignore) == 0); }
- static bool Cmp (DqnString const *a, DqnSlice const b, Dqn::IgnoreCase ignore = Dqn::IgnoreCase::No) { return (a->len == b.len) && (DqnStr_Cmp(a->str, b.data, b.len, ignore) == 0); }
-
- // return: -1 if invalid, or if buf_size is 0 the required buffer length in wchar_t characters
- i32 ToWChar(wchar_t *const buf, i32 const buf_size) const;
- // return: String allocated using api.
- wchar_t *ToWChar(DqnAllocator *allocator = dqn_lib_context_.allocator) const;
-
-};
-
-// #DqnRnd
-// =================================================================================================
-struct DqnRndPCG // PCG (Permuted Congruential Generator)
-{
- u64 state[2];
-
- DqnRndPCG();
- DqnRndPCG(u32 seed);
-
- u32 Next (); // return: A random number N between [0, 0xFFFFFFFF]
- f32 Nextf(); // return: A random float N between [0.0, 1.0f]
- i32 Range(i32 min, i32 max); // return: A random integer N between [min, max]
-};
-
-// #Dqn_*
-// =================================================================================================
-// return: The number of splits in the array. If array is null this returns the required size of the array.
-i32 Dqn_SplitString(char const *src, i32 src_len, char split_char, DqnSlice *array = nullptr, i32 size = 0);
-
-// Util function that uses Dqn_SplitString
-// return: The number of splits, splitting by "split_char" would generate.
-i32 Dqn_GetNumSplits(char const *src, i32 src_len, char split_char);
-
-// Skips whitespace then reads UTF8 rune upto first \r or \n and null terminates at that point. Advances input to the start of the next line.
-// line_len: (Optional) Returns the length of the null terminated line returned
-// return : The immediate null terminated line, nullptr if no more lines are to be read.
-DQN_FILE_SCOPE char *Dqn_EatLine(char **input, int *line_len);
-DQN_FILE_SCOPE wchar_t *Dqn_EatLine(wchar_t **input, int *line_len);
-
-DQN_FILE_SCOPE inline bool Dqn_BitIsSet (u32 bits, u32 flag);
-DQN_FILE_SCOPE inline u32 Dqn_BitSet (u32 bits, u32 flag);
-DQN_FILE_SCOPE inline u32 Dqn_BitUnset (u32 bits, u32 flag);
-DQN_FILE_SCOPE inline u32 Dqn_BitToggle(u32 bits, u32 flag);
-
-template using DqnQuickSort_LessThanProc = bool (*) (T const &a, T const &b, void *user_context);
-#define DQN_QUICK_SORT_LESS_THAN_PROC(name) template inline bool name(T const &a, T const &b, void *user_context)
-DQN_QUICK_SORT_LESS_THAN_PROC(DqnQuickSort_DefaultLessThan)
-{
- (void)user_context;
- bool result = a < b;
- return result;
-}
-
-template IsLessThan = DqnQuickSort_DefaultLessThan>
-DQN_FILE_SCOPE void DqnQuickSort(T *array, isize size, void *user_context)
-{
- if (!array || size <= 1) return;
-
-#if 1
- // Insertion Sort, under 24->32 is an optimal amount
- const i32 QUICK_SORT_THRESHOLD = 24;
- if (size < QUICK_SORT_THRESHOLD)
- {
- i32 item_to_insert_index = 1;
- while (item_to_insert_index < size)
- {
- for (i32 check_index = 0; check_index < item_to_insert_index; check_index++)
- {
- if (!IsLessThan(array[check_index], array[item_to_insert_index], user_context))
- {
- T item_to_insert = array[item_to_insert_index];
- for (i32 i = item_to_insert_index; i > check_index; i--)
- array[i] = array[i - 1];
-
- array[check_index] = item_to_insert;
- break;
- }
- }
- item_to_insert_index++;
- }
-
- return;
- }
-#endif
-
- auto state = DqnRndPCG();
- auto last_index = size - 1;
- auto pivot_index = (i64)state.Range(0, (i32)last_index);
- auto partition_index = 0;
- auto start_index = 0;
-
- // Swap pivot with last index, so pivot is always at the end of the array.
- // This makes logic much simpler.
- DQN_SWAP(T, array[last_index], array[pivot_index]);
- pivot_index = last_index;
-
- // 4^, 8, 7, 5, 2, 3, 6
- if (IsLessThan(array[start_index], array[pivot_index], user_context)) partition_index++;
- start_index++;
-
- // 4, |8, 7, 5^, 2, 3, 6*
- // 4, 5, |7, 8, 2^, 3, 6*
- // 4, 5, 2, |8, 7, ^3, 6*
- // 4, 5, 2, 3, |7, 8, ^6*
- for (auto check_index = start_index; check_index < last_index; check_index++)
- {
- if (IsLessThan(array[check_index], array[pivot_index], user_context))
- {
- DQN_SWAP(T, array[partition_index], array[check_index]);
- partition_index++;
- }
- }
-
- // Move pivot to right of partition
- // 4, 5, 2, 3, |6, 8, ^7*
- DQN_SWAP(T, array[partition_index], array[pivot_index]);
- DqnQuickSort(array, partition_index, user_context);
-
- // Skip the value at partion index since that is guaranteed to be sorted.
- // 4, 5, 2, 3, (x), 8, 7
- i32 one_after_partition_index = partition_index + 1;
- DqnQuickSort(array + one_after_partition_index, (size - one_after_partition_index), user_context);
-}
-
-template
-DQN_FILE_SCOPE void DqnQuickSort(T *array, isize size)
-{
- if (!array || size <= 1) return;
-
-#if 1
- // Insertion Sort, under 24->32 is an optimal amount
- const i32 QUICK_SORT_THRESHOLD = 24;
- if (size < QUICK_SORT_THRESHOLD)
- {
- i32 item_to_insert_index = 1;
- while (item_to_insert_index < size)
- {
- for (i32 check_index = 0; check_index < item_to_insert_index; check_index++)
- {
- if (!(array[check_index] < array[item_to_insert_index]))
- {
- T item_to_insert = array[item_to_insert_index];
- for (i32 i = item_to_insert_index; i > check_index; i--)
- array[i] = array[i - 1];
-
- array[check_index] = item_to_insert;
- break;
- }
- }
- item_to_insert_index++;
- }
-
- return;
- }
-#endif
-
- auto state = DqnRndPCG();
- auto last_index = size - 1;
- auto pivot_index = (i64)state.Range(0, (i32)last_index);
- auto partition_index = 0;
- auto start_index = 0;
-
- // Swap pivot with last index, so pivot is always at the end of the array.
- // This makes logic much simpler.
- DQN_SWAP(T, array[last_index], array[pivot_index]);
- pivot_index = last_index;
-
- // 4^, 8, 7, 5, 2, 3, 6
- if (array[start_index] < array[pivot_index]) partition_index++;
- start_index++;
-
- // 4, |8, 7, 5^, 2, 3, 6*
- // 4, 5, |7, 8, 2^, 3, 6*
- // 4, 5, 2, |8, 7, ^3, 6*
- // 4, 5, 2, 3, |7, 8, ^6*
- for (auto check_index = start_index; check_index < last_index; check_index++)
- {
- if (array[check_index] < array[pivot_index])
- {
- DQN_SWAP(T, array[partition_index], array[check_index]);
- partition_index++;
- }
- }
-
- // Move pivot to right of partition
- // 4, 5, 2, 3, |6, 8, ^7*
- DQN_SWAP(T, array[partition_index], array[pivot_index]);
- DqnQuickSort(array, partition_index);
-
- // Skip the value at partion index since that is guaranteed to be sorted.
- // 4, 5, 2, 3, (x), 8, 7
- i32 one_after_partition_index = partition_index + 1;
- DqnQuickSort(array + one_after_partition_index, (size - one_after_partition_index));
-}
-
-
-template using DqnBSearch_LessThanProc = bool (*)(const T&, const T&);
-template using DqnBSearch_EqualsProc = bool (*)(const T&, const T&);
-#define DQN_BSEARCH_LESS_THAN_PROC(name) template inline bool name(T const &a, T const &b)
-#define DQN_BSEARCH_EQUALS_PROC(name) template inline bool name(T const &a, T const &b)
-DQN_BSEARCH_LESS_THAN_PROC(DqnBSearch_DefaultLessThan) { return a < b; }
-DQN_BSEARCH_EQUALS_PROC (DqnBSearch_DefaultEquals) { return a == b; }
-
-enum struct DqnBSearchType
-{
- Match, // Return the index of the first item that matches the find value
- MinusOne, // Return the index of the first item lower than the find value
- PlusOne, // Return the index of the first item higher than the find value
-
- MatchOrMinusOne, // Return the index of the matching item if not found the first item lower
- MatchOrPlusOne, // Return the index of the matching item if not found the first item higher
-};
-
-// type: The matching behaviour of the binary search,
-// return: -1 if element not found, otherwise index of the element.
-// For higher and lower bounds return -1 if there is no element higher/lower than the
-// find value (i.e. -1 if the 0th element is the find val for lower bound).
-template IsLessThan = DqnBSearch_DefaultLessThan,
- DqnBSearch_EqualsProc Equals = DqnBSearch_DefaultEquals>
-DQN_FILE_SCOPE i64
-DqnBSearch(T const *array, isize size, T const &find, DqnBSearchType type = DqnBSearchType::Match)
-{
- if (size == 0 || !array)
- {
- return -1;
- }
-
- isize start = 0;
- isize end = size - 1;
- isize mid = static_cast((start + end) * 0.5f);
-
- while (start <= end)
- {
- if (Equals(array[mid], find))
- {
- if (type == DqnBSearchType::Match ||
- type == DqnBSearchType::MatchOrMinusOne ||
- type == DqnBSearchType::MatchOrPlusOne)
- {
- return mid;
- }
- else if (type == DqnBSearchType::MinusOne)
- {
- // NOTE: We can always -1 because at worst case, 0 index will go to -1 which is
- // correct behaviour.
- return mid - 1;
- }
- else
- {
- return ((mid + 1) >= size) ? -1 : mid + 1;
- }
- }
- else if (IsLessThan(array[mid], find)) start = mid + 1;
- else end = mid - 1;
- mid = static_cast((start + end) * 0.5f);
- }
-
- if (type == DqnBSearchType::Match)
- {
- return -1;
- }
- if (type == DqnBSearchType::MinusOne || type == DqnBSearchType::MatchOrMinusOne)
- {
- return (IsLessThan(find, array[mid])) ? -1 : mid;
- }
- else
- {
- return (IsLessThan(find, array[mid])) ? mid : -1;
- }
-}
-
-DQN_FILE_SCOPE inline i64 DqnBSearch(i64 const *array, i64 size, i64 find, DqnBSearchType type = DqnBSearchType::Match) { return DqnBSearch(array, size, find, type); }
-
-const size_t DQN_I32_MAX_STR_SIZE = 11;
-const size_t DQN_I64_MAX_STR_SIZE = 21;
-// Return the len of the derived string. If buf is nullptr and or buf_size is 0 the function returns the
-// required string length for the integer
-// TODO NOTE(doyle): Parsing stops when a non-digit is encountered, so numbers with ',' don't work atm.
-DQN_FILE_SCOPE i32 Dqn_I64ToStr (i64 const value, char *buf, i32 buf_size);
-DQN_FILE_SCOPE i64 Dqn_StrToI64 (char const *buf, i64 buf_size);
-DQN_FILE_SCOPE inline i64 Dqn_StrToI64 (DqnSlice buf) { return Dqn_StrToI64(buf.data, buf.len); }
-DQN_FILE_SCOPE inline i64 Dqn_StrToI64 (DqnSlice buf) { return Dqn_StrToI64(buf.data, buf.len); }
-
-// WARNING: Not robust, precision errors and whatnot but good enough!
-DQN_FILE_SCOPE f32 Dqn_StrToF32 (char const *buf, i64 buf_size);
-
-// Both return the number of bytes read, return 0 if invalid codepoint or UTF8
-DQN_FILE_SCOPE u32 Dqn_UCSToUTF8(u32 *dest, u32 character);
-DQN_FILE_SCOPE u32 Dqn_UTF8ToUCS(u32 *dest, u32 character);
-
-DQN_FILE_SCOPE i32 Dqn_WStrToI32(wchar_t const *buf, i32 buf_size);
-DQN_FILE_SCOPE i32 Dqn_I32ToWStr(i32 value, wchar_t *buf, i32 buf_size);
-
-// #DqnPool
-// =================================================================================================
-template
-struct DqnFixedPool
-{
- struct Entry : public T
- {
- u16 nextIndex;
- };
-
- const static isize SENTINEL_INDEX = SIZE;
-
- Entry pool[SIZE];
- i16 freeIndex;
- i16 numFree;
-
- DqnFixedPool() : freeIndex(0) , numFree(SIZE)
- {
- DQN_FOR_EACH(i, SIZE - 1)
- {
- Entry *entry = pool + i;
- entry->nextIndex = i + 1;
- }
- Entry *last = pool + (SIZE - 1);
- last->nextIndex = SENTINEL_INDEX;
- }
-
- T *GetNext()
- {
- if (freeIndex == SENTINEL_INDEX) return nullptr;
- Entry *result = pool + freeIndex;
- freeIndex = result->nextIndex;
- numFree--;
- return result;
- }
-
- void Return(T *item)
- {
- auto *entry = reinterpret_cast(item);
- entry->nextIndex = freeIndex;
- freeIndex = entry - pool;
- numFree++;
- }
-};
-
-// #DqnPool
-// =================================================================================================
-template
-struct DqnPool
-{
- struct Entry : public T
- {
- u16 nextIndex;
- };
-
- Entry *pool;
- i16 freeIndex;
- i16 numFree;
- i32 size;
-
- void UseMemory(Entry *pool_, isize size)
- {
- pool = pool_;
- freeIndex = 0;
- numFree = size;
-
- DQN_FOR_EACH(i, size - 1)
- {
- Entry *entry = pool + i;
- entry->nextIndex = i + 1;
- }
- Entry *last = pool + (size - 1);
- last->nextIndex = size;
- }
-
- T *GetNext()
- {
- if (freeIndex == size) return nullptr;
- Entry *result = pool + freeIndex;
- freeIndex = result->nextIndex;
- numFree--;
- return result;
- }
-
- void Return(T *item)
- {
- auto *entry = reinterpret_cast(item);
- entry->nextIndex = freeIndex;
- freeIndex = entry - pool;
- numFree++;
- }
-};
-
-// #DqnHash
-// =================================================================================================
-DQN_FILE_SCOPE u32 DqnHash_Murmur32Seed(void const *data, usize len, u32 seed);
-DQN_FILE_SCOPE u64 DqnHash_Murmur64Seed(void const *data_, usize len, u64 seed);
-
-DQN_FILE_SCOPE inline u32 DqnHash_Murmur32(void const *data, usize len)
-{
- return DqnHash_Murmur32Seed(data, len, 0x9747b28c);
-}
-
-DQN_FILE_SCOPE inline u64 DqnHash_Murmur64(void const *data, usize len)
-{
- return DqnHash_Murmur64Seed(data, len, 0x9747b28c);
-}
-
-// #DqnMath
-// =================================================================================================
-DQN_FILE_SCOPE f32 DqnMath_Lerp (f32 a, f32 t, f32 b);
-DQN_FILE_SCOPE f32 DqnMath_Sqrtf (f32 a);
-DQN_FILE_SCOPE f32 DqnMath_Clampf(f32 val, f32 min, f32 max);
-
-// #DqnV2
-// =================================================================================================
-union DqnV2i
-{
- struct { i32 x, y; };
- struct { i32 w, h; };
- struct { i32 min, max; };
- i32 e[2];
-
- DqnV2i() = default;
- DqnV2i(i32 x_, i32 y_): x(x_), y(y_) {}
- DqnV2i(f32 x_, f32 y_): x((i32)x_), y((i32)y_) {}
-
- bool operator==(DqnV2i const &b) const { return (this->x == b.x) && (this->y == b.y); }
- bool operator!=(DqnV2i const &b) const { return !(*this == b); }
- bool operator>=(DqnV2i const &b) const { return (this->x >= b.x) && (this->y >= b.y); }
- bool operator<=(DqnV2i const &b) const { return (this->x <= b.x) && (this->y <= b.y); }
- bool operator< (DqnV2i const &b) const { return (this->x < b.x) && (this->y < b.y); }
- bool operator> (DqnV2i const &b) const { return (this->x > b.x) && (this->y > b.y); }
-};
-
-union DqnV2
-{
- struct { f32 x, y; };
- struct { f32 w, h; };
- struct { f32 min, max; };
- f32 e[2];
-
- DqnV2() = default;
- DqnV2(f32 xy) : x(xy), y(xy) {}
- DqnV2(f32 x_, f32 y_): x(x_), y(y_) {}
- DqnV2(i32 x_, i32 y_): x((f32)x_), y((f32)y_) {}
- DqnV2(DqnV2i a) : x((f32)a.x), y((f32)a.y) {}
-
- bool operator==(DqnV2 const &b) const { return (this->x == b.x) && (this->y == b.y); }
- bool operator!=(DqnV2 const &b) const { return !(*this == b); }
- bool operator>=(DqnV2 const &b) const { return (this->x >= b.x) && (this->y >= b.y); }
- bool operator<=(DqnV2 const &b) const { return (this->x <= b.x) && (this->y <= b.y); }
- bool operator< (DqnV2 const &b) const { return (this->x < b.x) && (this->y < b.y); }
- bool operator> (DqnV2 const &b) const { return (this->x > b.x) && (this->y > b.y); }
-};
-
-DQN_FILE_SCOPE DqnV2 DqnV2_Add (DqnV2 a, DqnV2 b);
-DQN_FILE_SCOPE DqnV2 DqnV2_Sub (DqnV2 a, DqnV2 b);
-DQN_FILE_SCOPE DqnV2 DqnV2_Scalei (DqnV2 a, i32 b);
-DQN_FILE_SCOPE DqnV2 DqnV2_Scalef (DqnV2 a, f32 b);
-DQN_FILE_SCOPE DqnV2 DqnV2_Hadamard(DqnV2 a, DqnV2 b);
-DQN_FILE_SCOPE f32 DqnV2_Dot (DqnV2 a, DqnV2 b);
-DQN_FILE_SCOPE bool DqnV2_Equals (DqnV2 a, DqnV2 b);
-
-DQN_FILE_SCOPE f32 DqnV2_LengthSquared(const DqnV2 a, const DqnV2 b);
-DQN_FILE_SCOPE f32 DqnV2_Length (const DqnV2 a, const DqnV2 b);
-DQN_FILE_SCOPE DqnV2 DqnV2_Normalise (const DqnV2 a);
-DQN_FILE_SCOPE bool DqnV2_Overlaps ( DqnV2 a, DqnV2 b);
-DQN_FILE_SCOPE DqnV2 DqnV2_Perpendicular(const DqnV2 a);
-
-DQN_FILE_SCOPE DqnV2 DqnV2_ResizeKeepAspectRatio(DqnV2 src_size, DqnV2 target_size);
-DQN_FILE_SCOPE DqnV2 DqnV2_ConstrainToRatio (DqnV2 dim, DqnV2 ratio); // Resize the dimension to fit the aspect ratio provided. Downscale only.
-
-DQN_FILE_SCOPE inline DqnV2 operator- (DqnV2 a, DqnV2 b) { return DqnV2_Sub (a, b); }
-DQN_FILE_SCOPE inline DqnV2 operator+ (DqnV2 a, DqnV2 b) { return DqnV2_Add (a, b); }
-DQN_FILE_SCOPE inline DqnV2 operator* (DqnV2 a, DqnV2 b) { return DqnV2_Hadamard(a, b); }
-DQN_FILE_SCOPE inline DqnV2 operator* (DqnV2 a, f32 b) { return DqnV2_Scalef (a, b); }
-DQN_FILE_SCOPE inline DqnV2 operator* (DqnV2 a, i32 b) { return DqnV2_Scalei (a, b); }
-DQN_FILE_SCOPE inline DqnV2 &operator*=(DqnV2 &a, DqnV2 b) { return (a = DqnV2_Hadamard(a, b)); }
-DQN_FILE_SCOPE inline DqnV2 &operator*=(DqnV2 &a, f32 b) { return (a = DqnV2_Scalef (a, b)); }
-DQN_FILE_SCOPE inline DqnV2 &operator*=(DqnV2 &a, i32 b) { return (a = DqnV2_Scalei (a, b)); }
-DQN_FILE_SCOPE inline DqnV2 &operator-=(DqnV2 &a, DqnV2 b) { return (a = DqnV2_Sub (a, b)); }
-DQN_FILE_SCOPE inline DqnV2 &operator+=(DqnV2 &a, DqnV2 b) { return (a = DqnV2_Add (a, b)); }
-
-// DqnV2i
-DQN_FILE_SCOPE DqnV2i DqnV2i_Add (DqnV2i a, DqnV2i b);
-DQN_FILE_SCOPE DqnV2i DqnV2i_Sub (DqnV2i a, DqnV2i b);
-DQN_FILE_SCOPE DqnV2i DqnV2i_Scalei (DqnV2i a, i32 b);
-DQN_FILE_SCOPE DqnV2i DqnV2i_Scalef (DqnV2i a, f32 b);
-DQN_FILE_SCOPE DqnV2i DqnV2i_Hadamard(DqnV2i a, DqnV2i b);
-DQN_FILE_SCOPE f32 DqnV2i_Dot (DqnV2i a, DqnV2i b);
-DQN_FILE_SCOPE bool DqnV2i_Equals (DqnV2i a, DqnV2i b);
-
-DQN_FILE_SCOPE inline DqnV2i operator- (DqnV2i a, DqnV2i b) { return DqnV2i_Sub (a, b); }
-DQN_FILE_SCOPE inline DqnV2i operator+ (DqnV2i a, DqnV2i b) { return DqnV2i_Add (a, b); }
-DQN_FILE_SCOPE inline DqnV2i operator* (DqnV2i a, DqnV2i b) { return DqnV2i_Hadamard(a, b); }
-DQN_FILE_SCOPE inline DqnV2i operator* (DqnV2i a, f32 b) { return DqnV2i_Scalef (a, b); }
-DQN_FILE_SCOPE inline DqnV2i operator* (DqnV2i a, i32 b) { return DqnV2i_Scalei (a, b); }
-DQN_FILE_SCOPE inline DqnV2i &operator*=(DqnV2i &a, DqnV2i b) { return (a = DqnV2i_Hadamard(a, b)); }
-DQN_FILE_SCOPE inline DqnV2i &operator-=(DqnV2i &a, DqnV2i b) { return (a = DqnV2i_Sub (a, b)); }
-DQN_FILE_SCOPE inline DqnV2i &operator+=(DqnV2i &a, DqnV2i b) { return (a = DqnV2i_Add (a, b)); }
-
-// #DqnV3
-// =================================================================================================
-union DqnV3
-{
- struct { f32 x, y, z; };
- struct { f32 r, g, b; };
- DqnV2 xy;
- f32 e[3];
-
- DqnV3() = default;
- DqnV3(f32 xyz) : x(xyz), y(xyz), z(xyz) {}
- DqnV3(f32 x_, f32 y_, f32 z_): x(x_), y(y_), z(z_) {}
- DqnV3(i32 x_, i32 y_, i32 z_): x((f32)x_), y((f32)y_), z((f32)z_) {}
-};
-
-union DqnV3i
-{
- struct { i32 x, y, z; };
- struct { i32 r, g, b; };
- i32 e[3];
-
- DqnV3i() = default;
- DqnV3i(i32 x_, i32 y_, i32 z_): x(x_), y(y_), z(z_) {}
- DqnV3i(f32 x_, f32 y_, f32 z_): x((i32)x_), y((i32)y_), z((i32)z_) {}
-};
-
-// DqnV3
-DQN_FILE_SCOPE DqnV3 DqnV3_Add (DqnV3 a, DqnV3 b);
-DQN_FILE_SCOPE DqnV3 DqnV3_Sub (DqnV3 a, DqnV3 b);
-DQN_FILE_SCOPE DqnV3 DqnV3_Scalei (DqnV3 a, i32 b);
-DQN_FILE_SCOPE DqnV3 DqnV3_Scalef (DqnV3 a, f32 b);
-DQN_FILE_SCOPE DqnV3 DqnV3_Hadamard(DqnV3 a, DqnV3 b);
-DQN_FILE_SCOPE f32 DqnV3_Dot (DqnV3 a, DqnV3 b);
-DQN_FILE_SCOPE bool DqnV3_Equals (DqnV3 a, DqnV3 b);
-DQN_FILE_SCOPE DqnV3 DqnV3_Cross (DqnV3 a, DqnV3 b);
-
-DQN_FILE_SCOPE DqnV3 DqnV3_Normalise (DqnV3 a);
-DQN_FILE_SCOPE f32 DqnV3_Length (DqnV3 a, DqnV3 b);
-DQN_FILE_SCOPE f32 DqnV3_LengthSquared(DqnV3 a, DqnV3 b);
-
-DQN_FILE_SCOPE inline DqnV3 operator- (DqnV3 a, DqnV3 b) { return DqnV3_Sub (a, b); }
-DQN_FILE_SCOPE inline DqnV3 operator+ (DqnV3 a, DqnV3 b) { return DqnV3_Add (a, b); }
-DQN_FILE_SCOPE inline DqnV3 operator+ (DqnV3 a, f32 b) { return DqnV3_Add (a, DqnV3(b)); }
-DQN_FILE_SCOPE inline DqnV3 operator* (DqnV3 a, DqnV3 b) { return DqnV3_Hadamard(a, b); }
-DQN_FILE_SCOPE inline DqnV3 operator* (DqnV3 a, f32 b) { return DqnV3_Scalef (a, b); }
-DQN_FILE_SCOPE inline DqnV3 operator* (DqnV3 a, i32 b) { return DqnV3_Scalei (a, b); }
-DQN_FILE_SCOPE inline DqnV3 operator/ (DqnV3 a, f32 b) { return DqnV3_Scalef (a, (1.0f/b)); }
-DQN_FILE_SCOPE inline DqnV3 &operator*=(DqnV3 &a, DqnV3 b) { return (a = DqnV3_Hadamard(a, b)); }
-DQN_FILE_SCOPE inline DqnV3 &operator*=(DqnV3 &a, f32 b) { return (a = DqnV3_Scalef (a, b)); }
-DQN_FILE_SCOPE inline DqnV3 &operator*=(DqnV3 &a, i32 b) { return (a = DqnV3_Scalei (a, b)); }
-DQN_FILE_SCOPE inline DqnV3 &operator-=(DqnV3 &a, DqnV3 b) { return (a = DqnV3_Sub (a, b)); }
-DQN_FILE_SCOPE inline DqnV3 &operator+=(DqnV3 &a, DqnV3 b) { return (a = DqnV3_Add (a, b)); }
-DQN_FILE_SCOPE inline bool operator==(DqnV3 a, DqnV3 b) { return DqnV3_Equals (a, b); }
-
-// #DqnV4
-// =================================================================================================
-union DqnV4
-{
- struct { f32 x, y, z, w; };
- DqnV3 xyz;
- DqnV2 xy;
-
- struct { f32 r, g, b, a; };
- DqnV3 rgb;
-
- f32 e[4];
- DqnV2 v2[2];
-
- DqnV4() = default;
- DqnV4(f32 xyzw) : x(xyzw), y(xyzw), z(xyzw), w(xyzw) {}
- DqnV4(f32 x_, f32 y_, f32 z_, f32 w_): x(x_), y(y_), z(z_), w(w_) {}
- DqnV4(i32 x_, i32 y_, i32 z_, i32 w_): x((f32)x_), y((f32)y_), z((f32)z_), w((f32)w_) {}
- DqnV4(DqnV3 a, f32 w_) : x(a.x), y(a.y), z(a.z), w(w_) {}
-
-};
-
-DQN_FILE_SCOPE DqnV4 DqnV4_Add (DqnV4 a, DqnV4 b);
-DQN_FILE_SCOPE DqnV4 DqnV4_Sub (DqnV4 a, DqnV4 b);
-DQN_FILE_SCOPE DqnV4 DqnV4_Scalef (DqnV4 a, f32 b);
-DQN_FILE_SCOPE DqnV4 DqnV4_Scalei (DqnV4 a, i32 b);
-DQN_FILE_SCOPE DqnV4 DqnV4_Hadamard(DqnV4 a, DqnV4 b);
-DQN_FILE_SCOPE f32 DqnV4_Dot (DqnV4 a, DqnV4 b);
-DQN_FILE_SCOPE bool DqnV4_Equals (DqnV4 a, DqnV4 b);
-
-DQN_FILE_SCOPE inline DqnV4 operator- (DqnV4 a, DqnV4 b) { return DqnV4_Sub (a, b); }
-DQN_FILE_SCOPE inline DqnV4 operator+ (DqnV4 a, DqnV4 b) { return DqnV4_Add (a, b); }
-DQN_FILE_SCOPE inline DqnV4 operator+ (DqnV4 a, f32 b) { return DqnV4_Add (a, DqnV4(b)); }
-DQN_FILE_SCOPE inline DqnV4 operator* (DqnV4 a, DqnV4 b) { return DqnV4_Hadamard(a, b); }
-DQN_FILE_SCOPE inline DqnV4 operator* (DqnV4 a, f32 b) { return DqnV4_Scalef (a, b); }
-DQN_FILE_SCOPE inline DqnV4 operator* (DqnV4 a, i32 b) { return DqnV4_Scalei (a, b); }
-DQN_FILE_SCOPE inline DqnV4 &operator*=(DqnV4 &a, DqnV4 b) { return (a = DqnV4_Hadamard(a, b)); }
-DQN_FILE_SCOPE inline DqnV4 &operator*=(DqnV4 &a, f32 b) { return (a = DqnV4_Scalef (a, b)); }
-DQN_FILE_SCOPE inline DqnV4 &operator*=(DqnV4 &a, i32 b) { return (a = DqnV4_Scalei (a, b)); }
-DQN_FILE_SCOPE inline DqnV4 &operator-=(DqnV4 &a, DqnV4 b) { return (a = DqnV4_Sub (a, b)); }
-DQN_FILE_SCOPE inline DqnV4 &operator+=(DqnV4 &a, DqnV4 b) { return (a = DqnV4_Add (a, b)); }
-DQN_FILE_SCOPE inline bool operator==(DqnV4 &a, DqnV4 b) { return DqnV4_Equals (a, b); }
-
-// #DqnMat4
-// =================================================================================================
-typedef union DqnMat4
-{
- // TODO(doyle): Row/column instead? More cache friendly since multiplication
- // prefers rows.
- DqnV4 col[4];
- f32 e[4][4]; // Column/row
-} DqnMat4;
-
-DQN_FILE_SCOPE DqnMat4 DqnMat4_Identity ();
-
-DQN_FILE_SCOPE DqnMat4 DqnMat4_Orthographic(f32 left, f32 right, f32 bottom, f32 top, f32 znear, f32 zfar);
-DQN_FILE_SCOPE DqnMat4 DqnMat4_Perspective (f32 fov_y_degrees, f32 aspect_ratio, f32 znear, f32 zfar);
-DQN_FILE_SCOPE DqnMat4 DqnMat4_LookAt (DqnV3 eye, DqnV3 center, DqnV3 up);
-
-DQN_FILE_SCOPE DqnMat4 DqnMat4_Translate3f (f32 x, f32 y, f32 z);
-DQN_FILE_SCOPE DqnMat4 DqnMat4_TranslateV3 (DqnV3 vec);
-DQN_FILE_SCOPE DqnMat4 DqnMat4_Rotate (f32 radians, f32 x, f32 y, f32 z);
-DQN_FILE_SCOPE DqnMat4 DqnMat4_Scale (f32 x, f32 y, f32 z);
-DQN_FILE_SCOPE DqnMat4 DqnMat4_ScaleV3 (DqnV3 scale);
-DQN_FILE_SCOPE DqnMat4 DqnMat4_Mul (DqnMat4 a, DqnMat4 b);
-DQN_FILE_SCOPE DqnV4 DqnMat4_MulV4 (DqnMat4 a, DqnV4 b);
-
-// #DqnRect
-// =================================================================================================
-struct DqnRect
-{
- DqnV2 min;
- DqnV2 max;
-
- DqnRect() = default;
- DqnRect(DqnV2 origin, DqnV2 size) { this->min = origin; this->max = origin + size; }
- DqnRect(f32 x, f32 y, f32 w, f32 h) { this->min = DqnV2(x, y); this->max = DqnV2(x + w, y + h); }
- DqnRect(i32 x, i32 y, i32 w, i32 h) { this->min = DqnV2(x, y); this->max = DqnV2(x + w, y + h); }
-
- f32 GetWidth () const { return max.w - min.w; }
- f32 GetHeight() const { return max.h - min.h; }
- DqnV2 GetSize () const { return max - min; }
- void GetSize (f32 *const width, f32 *const height) const;
- DqnV2 GetCenter() const;
-
- DqnRect ClipRect (DqnRect const clip) const;
- DqnRect Move (DqnV2 const shift) const;
- bool ContainsP(DqnV2 const p) const;
-};
-
-struct DqnJson
-{
- enum struct Type
- {
- Object,
- ArrayOfObjects,
- ArrayOfPrimitives,
- };
-
- Type type;
- DqnSlice value;
- i32 num_entries;
-
- operator bool () const { return (value.data != nullptr); }
- bool IsArray() const { return (type == Type::ArrayOfObjects || type == Type::ArrayOfPrimitives); }
- i64 ToI64() const { return Dqn_StrToI64(value.data, value.len); }
-};
-
-// Zero allocation json finder. Returns the data of the value.
-// If array, it returns a slice from [..] not-inclusive, if object, it returns a slice from {..} not-inclusive
-// If just name value pair, it returns the literal with quotes or just the value if it is a primitive with quotes.
-DQN_FILE_SCOPE DqnJson DqnJson_Get (char const *buf, i32 buf_len, char const *find_property, i32 find_property_len);
-DQN_FILE_SCOPE DqnJson DqnJson_Get (DqnSlice const buf, DqnSlice const find_property);
-DQN_FILE_SCOPE DqnJson DqnJson_Get (DqnSlice const buf, DqnSlice const find_property);
-DQN_FILE_SCOPE DqnJson DqnJson_Get (DqnSlice const buf, DqnSlice const find_property);
-DQN_FILE_SCOPE DqnJson DqnJson_Get (DqnJson const input, DqnSlice const find_property);
-DQN_FILE_SCOPE DqnJson DqnJson_Get (DqnJson const input, DqnSlice const find_property);
-
-// return: The array item.
-DQN_FILE_SCOPE DqnJson DqnJson_GetNextArrayItem(DqnJson *iterator);
-
-#endif /* DQN_H */
-
-// #XPlatform (Win32 & Unix)
-// =================================================================================================
-// Functions in the Cross Platform are guaranteed to be supported in both Unix
-// and Win32
-
-// NOTE(doyle): DQN_PLATFORM_HEADER is enabled by the user to have the function prototypes be
-// visible. DQN_PLATFORM_H is like a normal header guard that ensures singular declaration of
-// functions.
-#ifdef DQN_PLATFORM_HEADER
-
-#ifndef DQN_PLATFORM_H
-#define DQN_PLATFORM_H
-
-#if defined(DQN_IS_UNIX)
- #include
- #include
-#endif
-
-// XPlatform > #DqnOS
-// =================================================================================================
-DQN_FILE_SCOPE void *DqnOS_VAlloc(isize size, void *base_addr = nullptr);
-DQN_FILE_SCOPE void DqnOS_VFree (void *address, isize size);
-
-// Uses a single call to DqnMem_Calloc() and DqnMem_Free(). Not completely platform "independent" for Unix.
-// num_cores: num_threads_per_core: Can be nullptr, the function will just skip it.
-DQN_FILE_SCOPE void DqnOS_GetThreadsAndCores(u32 *const num_cores, u32 *const num_threads_per_core);
-
-// #XPlatform > #DqnVArray Array backed by virtual memory
-// =================================================================================================
-template
-struct DqnVArray
-{
- isize len; // Read
- isize max; // Read
- T *data; // Read
-
- DqnVArray () = default; // Zero is initialisation
- DqnVArray (isize size) { LazyInit(size); }
- void LazyInit (isize size) { *this = {}; if (data) return; len = 0; max = size; data = (T *)DqnOS_VAlloc(max * sizeof(T)); DQN_ALWAYS_ASSERT(data); }
- // ~DqnVArray () { if (data) DqnOS_VFree(data, sizeof(T) * max); }
-
- void Clear (Dqn::ZeroMem clear = Dqn::ZeroMem::No) { if (data) { len = 0; if (clear == Dqn::ZeroMem::Yes) DqnMem_Clear(data, 0, sizeof(T) * max); } }
- void Free () { if (data) { DqnOS_VFree(data, sizeof(T) * max); } *this = {}; }
- T *Front () { return (len > 0) ? (data + 0) : nullptr; }
- T *Back () { return (len > 0) ? (data + (len - 1)) : nullptr; }
- T *Make (isize num = 1) { if (!data) LazyInit(1024); len += num; DQN_ASSERT(len <= max); return &data[len - num]; }
- T *Add (T const &v) { data[len++] = v; return data + (len - 1); }
- T *Add (T const *v, isize v_len = 1) { T *result = data + len; for (isize i = 0; i < v_len; ++i) data[len++] = v[i]; return result; }
- void Pop () { if (len > 0) len--; }
- void Erase (isize index) { if (!data) return; DQN_ASSERT(index >= 0 && index < len); data[index] = data[--len]; }
- void EraseStable(isize index);
- T *Insert (isize index, T const *v) { return Insert(index, v, 1); }
- T *Insert (isize index, T const &v) { return Insert(index, &v, 1); }
- T *Insert (isize index, T const *v, isize num_items);
- bool Contains (T const *v) const { T const *ptr = data; T const *end = data + len; while (ptr < end) { if (*ptr++ == *v) return true; } return false; }
-
- T &operator[] (isize i) const { DQN_ASSERT(i < len && i > 0); return this->data[i]; }
- T *begin () { return data; }
- T *end () { return data + len; }
-};
-
-template T *DqnVArray::Insert(isize index, T const *v, isize num_items)
-{
- if (!data) LazyInit(1024);
-
- index = DQN_CLAMP(index, 0, len);
- isize const new_len = len + num_items;
- DQN_ASSERT(new_len <= max);
-
- T *src = data + index;
- T *dest = src + num_items;
-
- if (src < dest)
- memmove(dest, src, ((data + len) - src) * sizeof(T));
-
- len = new_len;
- for (isize i = 0; i < num_items; i++)
- src[i] = v[i];
-
- return src;
-}
-
-template void DqnVArray::EraseStable(isize index)
-{
- if (!data) return;
- DQN_ASSERT(index >= 0 && index < len);
- isize const off = (data + index) - data;
- memmove(data + off, data + off + 1, ((usize)len - (usize)off - 1) * sizeof(T));
- len--;
-}
-
-// #XPlatform > #DqnVHashTable
-// =================================================================================================
-template using DqnVHashTableHashingProc = isize(*)(isize count, Key const &data);
-template using DqnVHashTableEqualsProc = bool (*)(Key const &a, Key const &b);
-
-const u64 DQN_VHASH_TABLE_DEFAULT_SEED = 0x9747B28CAB3F8A7B;
-#define DQN_VHASH_TABLE_HASHING_PROC(name, Type) inline isize name(isize count, Type const &key)
-#define DQN_VHASH_TABLE_EQUALS_PROC(name, Type) inline bool name(Type const &a, Type const &b)
-
-template DQN_VHASH_TABLE_HASHING_PROC(DqnVHashTableDefaultHash, T) { return DqnHash_Murmur64Seed(&key, sizeof(key), DQN_VHASH_TABLE_DEFAULT_SEED) % count; }
-template DQN_VHASH_TABLE_EQUALS_PROC (DqnVHashTableDefaultEquals, T) { return (DqnMem_Cmp(&a, &b, sizeof(a)) == 0); }
-
-template <> DQN_VHASH_TABLE_HASHING_PROC(DqnVHashTableDefaultHash, DqnString) { return DqnHash_Murmur64Seed(&key.str, key.len, DQN_VHASH_TABLE_DEFAULT_SEED) % count; }
-template <> DQN_VHASH_TABLE_EQUALS_PROC (DqnVHashTableDefaultEquals, DqnString) { return (a.len == b.len) && (DqnStr_Cmp(a.str, b.str, a.len) == 0); }
-template <> DQN_VHASH_TABLE_HASHING_PROC(DqnVHashTableDefaultHash>, DqnBuffer) { return DqnHash_Murmur64Seed(&key.str, key.len, DQN_VHASH_TABLE_DEFAULT_SEED) % count; }
-template <> DQN_VHASH_TABLE_EQUALS_PROC (DqnVHashTableDefaultEquals>, DqnBuffer) { return DQN_BUFFER_STRCMP(a, b, Dqn::IgnoreCase::No); }
-
-// TODO(doyle): Fix this so we don't have to manually declare the fixed string sizes for hashing and equals
-#define DQN_VHASH_TABLE_DEFAULT_FIXED_STRING_PROCS(StringCapacity) \
- template <> \
- DQN_VHASH_TABLE_HASHING_PROC(DqnVHashTableDefaultHash>, \
- DqnFixedString) \
- { \
- return DqnHash_Murmur64Seed(key.str, key.len, DQN_VHASH_TABLE_DEFAULT_SEED) % count; \
- } \
- template <> \
- DQN_VHASH_TABLE_EQUALS_PROC(DqnVHashTableDefaultEquals>, \
- DqnFixedString) \
- { \
- return (a.len == b.len) && (DqnStr_Cmp(a.str, b.str, a.len, Dqn::IgnoreCase::No) == 0); \
- }
-
-DQN_VHASH_TABLE_DEFAULT_FIXED_STRING_PROCS(1024)
-DQN_VHASH_TABLE_DEFAULT_FIXED_STRING_PROCS(512)
-DQN_VHASH_TABLE_DEFAULT_FIXED_STRING_PROCS(256)
-DQN_VHASH_TABLE_DEFAULT_FIXED_STRING_PROCS(128)
-DQN_VHASH_TABLE_DEFAULT_FIXED_STRING_PROCS(64)
-DQN_VHASH_TABLE_DEFAULT_FIXED_STRING_PROCS(32)
-DQN_VHASH_TABLE_DEFAULT_FIXED_STRING_PROCS(16)
-DQN_VHASH_TABLE_DEFAULT_FIXED_STRING_PROCS(8)
-
-
-#define DQN_VHASH_TABLE_TEMPLATE \
- template Hash, \
- DqnVHashTableEqualsProc Equals>
-
-#define DQN_VHASH_TABLE_DECL DqnVHashTable
-
-template Hash = DqnVHashTableDefaultHash,
- DqnVHashTableEqualsProc Equals = DqnVHashTableDefaultEquals>
-struct DqnVHashTable
-{
- struct Entry
- {
- union { Key key; Key first; };
- union { Item item; Item second; };
- };
-
- struct Bucket
- {
- Entry entries[4];
- isize entry_index;
- };
-
- Bucket *buckets;
- isize num_buckets;
- isize *indexes_of_used_buckets;
- isize num_used_entries;
- isize num_used_buckets;
-
- DqnVHashTable () = default;
- DqnVHashTable (isize size) { LazyInit(size); }
-
- void LazyInit (isize size = DQN_MAX(DQN_MEGABYTE(1)/sizeof(Bucket), 1024) );
- void Free () { if (buckets) DqnOS_VFree(buckets, sizeof(buckets) * num_buckets); *this = {}; }
-
- void Erase (Key const &key); // Delete the element matching key, does nothing if key not found.
- Entry *GetEntry (Key const &key); // return: The (key, item) entry associated with the key, nullptr if key not in table yet.
- Item *GetOrMake(Key const &key, bool *existed = nullptr); // return: Item if found, otherwise make an entry (key, item) and return the ptr to the uninitialised item
- Item *Get (Key const &key) { Entry *entry = GetEntry(key); return (entry) ? &entry->item : nullptr; }
- Item *Set (Key const &key, Item const &item) { Item *result = GetOrMake(key); *result = item; return result; }
-
- Item *operator[](Key const &key) { return Get(key); }
-
- struct Iterator
- {
- Entry *entry;
- Iterator(DqnVHashTable *table_, isize num_used_buckets_ = 0, isize index_in_bucket_ = 0);
- Bucket *GetCurrBucket() const { return (table->buckets + table->indexes_of_used_buckets[num_used_buckets]); }
- Entry *GetCurrEntry() const { return GetCurrBucket()->entries + index_in_bucket; }
- Item *GetCurrItem () const { return &(GetCurrEntry()->item); }
-
- bool operator!=(Iterator const &other) const { return !(num_used_buckets == other.num_used_buckets && index_in_bucket == other.index_in_bucket); }
- Entry &operator* () const { return *GetCurrEntry(); }
- Iterator &operator++();
- Iterator &operator--() { if (--index_in_bucket < 0) { index_in_bucket = 0; num_used_buckets = DQN_MAX(--num_used_buckets, 0); } entry = GetCurrEntry(); return *this; }
- Iterator operator++(int) { Iterator result = *this; ++(*this); return result; } // postfix
- Iterator operator--(int) { Iterator result = *this; --(*this); return result; } // postfix
- Iterator operator+ (int offset) const { Iterator result = *this; DQN_FOR_EACH(i, DQN_ABS(offset)) { (offset > 0) ? ++result : --result; } return result; } // TODO(doyle): Improve
- Iterator operator- (int offset) const { Iterator result = *this; DQN_FOR_EACH(i, DQN_ABS(offset)) { (offset > 0) ? --result : ++result; } return result; } // TODO(doyle): Improve
-
- private:
- DqnVHashTable *table;
- isize num_used_buckets;
- isize index_in_bucket;
- };
-
- Iterator begin() { return Iterator(this); }
- Iterator end() { return Iterator(this, num_buckets, DQN_ARRAY_COUNT(this->buckets[0].entries)); }
-};
-
-DQN_VHASH_TABLE_TEMPLATE DQN_VHASH_TABLE_DECL::Iterator::Iterator(DqnVHashTable *table_,
- isize num_used_buckets_,
- isize index_in_bucket_)
-: table(table_)
-, num_used_buckets(num_used_buckets_)
-, index_in_bucket(index_in_bucket_)
-, entry(nullptr)
-{
- bool sentinel_index = (num_used_buckets == table->num_buckets &&
- index_in_bucket == DQN_ARRAY_COUNT(table->buckets[0].entries));
- bool empty_table = (table->num_used_buckets == 0);
- if (empty_table || sentinel_index)
- {
- if (empty_table)
- {
- this->num_used_buckets = table->num_buckets;
- this->index_in_bucket = DQN_ARRAY_COUNT(table->buckets[0].entries);
- }
- }
- else
- {
- entry = GetCurrEntry();
- }
-}
-
-DQN_VHASH_TABLE_TEMPLATE typename DQN_VHASH_TABLE_DECL::Iterator &DQN_VHASH_TABLE_DECL::Iterator::operator++()
-{
- if (++index_in_bucket >= GetCurrBucket()->entry_index)
- {
- index_in_bucket = 0;
- num_used_buckets++;
- }
-
- if (num_used_buckets < table->num_used_buckets)
- entry = GetCurrEntry();
- else
- *this = table->end();
-
- return *this;
-}
-
-DQN_VHASH_TABLE_TEMPLATE void DQN_VHASH_TABLE_DECL::LazyInit(isize size)
-{
- *this = {};
- this->num_buckets = size;
- this->buckets = static_cast(DqnOS_VAlloc(size * sizeof(*this->buckets)));
- this->indexes_of_used_buckets = static_cast (DqnOS_VAlloc(size * sizeof(*this->indexes_of_used_buckets)));
- DQN_ASSERT(this->buckets && this->indexes_of_used_buckets);
-}
-
-DQN_VHASH_TABLE_TEMPLATE typename DQN_VHASH_TABLE_DECL::Entry *
-DQN_VHASH_TABLE_DECL::GetEntry(Key const &key)
-{
- if (!buckets) return nullptr;
-
- isize index = Hash(this->num_buckets, key);
- Bucket *bucket = this->buckets + index;
-
- Entry *result = nullptr;
- for (isize i = 0; i < bucket->entry_index && !result; i++)
- {
- Entry *entry = bucket->entries + i;
- result = Equals(entry->key, key) ? entry : nullptr;
- }
-
- return result;
-}
-
-DQN_VHASH_TABLE_TEMPLATE Item *DQN_VHASH_TABLE_DECL::GetOrMake(Key const &key, bool *existed)
-{
- if (!this->buckets) LazyInit();
-
- isize index = Hash(this->num_buckets, key);
- Bucket *bucket = this->buckets + index;
-
- Entry *entry = nullptr;
- for (isize i = 0; i < bucket->entry_index && !entry; i++)
- {
- Entry *check = bucket->entries + i;
- entry = Equals(check->key, key) ? check : nullptr;
- }
-
- if (existed)
- *existed = (entry != nullptr);
-
- if (!entry)
- {
- DQN_ALWAYS_ASSERTM(bucket->entry_index < DQN_ARRAY_COUNT(bucket->entries),
- "More than %zu collisions in hash table, increase the size of the table or buckets",
- DQN_ARRAY_COUNT(bucket->entries));
-
- if (bucket->entry_index == 0)
- this->indexes_of_used_buckets[this->num_used_buckets++] = index;
-
- entry = bucket->entries + bucket->entry_index++;
- entry->key = key;
- ++this->num_used_entries;
-
- // TODO(doyle): A maybe case. We're using virtual memory, so you should
- // just initialise a larger size. It's essentially free ... maybe one
- // day we care about resizing the table but at the cost of a lot more code
- // complexity.
- isize const threshold = static_cast(0.75f * this->num_buckets);
- DQN_ALWAYS_ASSERTM(this->num_used_buckets < threshold, "%zu >= %zu", this->num_used_buckets, threshold);
- }
-
- Item *result = &entry->item;
- return result;
-}
-
-DQN_VHASH_TABLE_TEMPLATE void DQN_VHASH_TABLE_DECL::Erase(Key const &key)
-{
- if (!buckets)
- return;
-
- isize index = Hash(this->num_buckets, key);
- Bucket *bucket = this->buckets + index;
-
- DQN_FOR_EACH(i, bucket->entry_index)
- {
- Entry *check = bucket->entries + i;
- if (!Equals(check->key, key))
- {
- continue;
- }
-
- for (isize j = i; j < (bucket->entry_index - 1); ++j)
- bucket->entries[j] = bucket->entries[j + 1];
-
- --this->num_used_entries;
- if (--bucket->entry_index == 0)
- {
- DQN_FOR_EACH(bucketIndex, this->num_used_buckets)
- {
- if (this->indexes_of_used_buckets[bucketIndex] == index)
- {
- indexes_of_used_buckets[bucketIndex] =
- indexes_of_used_buckets[--this->num_used_buckets];
- }
- }
- }
-
- DQN_ASSERT(this->num_used_entries >= 0);
- DQN_ASSERT(this->num_used_buckets >= 0);
- DQN_ASSERT(bucket->entry_index >= 0);
- return;
- }
-}
-
-// XPlatform > #DqnFile
-// =================================================================================================
-struct DqnFile
-{
- enum Flag
- {
- FileRead = (1 << 0),
- FileWrite = (1 << 1),
- Execute = (1 << 2),
- All = (1 << 3),
- FileReadWrite = FileRead | FileWrite
- };
-
- enum struct Action
- {
- OpenOnly, // Only open file if it exists. Fails and returns false if file did not exist or could not open.
- CreateIfNotExist, // Try and create file. Return true if it was able to create. If it already exists, this fails.
- ClearIfExist, // Clear the file contents to zero if it exists. Fails and returns false if file does not exist.
- ForceCreate, // Always create, even if it exists
- };
-
- u32 flags;
- void *handle;
- usize size;
- int curr_write_offset;
-
- // API
- // ==============================================================================================
- // NOTE: W(ide) versions of functions only work on Win32, since Unix is already UTF-8 compatible.
-
- // Open a handle for file read and writing. Deleting files does not need a handle. Handles should be
- // closed before deleting files otherwise the OS may not be able to delete the file.
- // return: FALSE if invalid args or failed to get handle (i.e. insufficient permission)
- bool Open(char const *path, u32 const flags_, Action const action);
- bool Open(wchar_t const *path, u32 const flags_, Action const action);
-
- // file_offset: The byte offset to starting writing from.
- // return: The number of bytes written. 0 if invalid args or it failed to write.
- usize Write(u8 const *buf, usize const num_bytes_to_write);
-
- // IMPORTANT: You may want to allocate size+1 for null-terminating the file contents when reading into a buffer.
- // return: The number of bytes read. 0 if invalid args or it failed to read.
- usize Read (u8 *buf, usize const num_bytes_to_read);
-
- // File close invalidates the handle after it is called.
- void Close();
-};
-
-struct DqnFileInfo
-{
- usize size;
- u64 create_time_in_s;
- u64 last_write_time_in_s;
- u64 last_access_time_in_s;
-};
-
-// Read entire file into the given buffer. To determine required buf_size size, use GetFileSize.
-// NOTE: You want size + 1 and add the null-terminator yourself if you want a null terminated buffer.
-// bytes_read: Pass in to get how many bytes of the buf was used. Basically the return value of Read
-// return: False if insufficient buf_size OR file access failure OR nullptr arguments.
-DQN_FILE_SCOPE bool DqnFile_ReadAll(char const *path, u8 *buf, usize buf_size);
-DQN_FILE_SCOPE bool DqnFile_ReadAll(wchar_t const *path, u8 *buf, usize buf_size);
-
-// Buffer is null-terminated and should be freed when done with.
-// return: False if file access failure OR nullptr arguments.
-DQN_FILE_SCOPE u8 *DqnFile_ReadAll(char const *path, usize *buf_size, DqnAllocator *allocator = dqn_lib_context_.allocator);
-DQN_FILE_SCOPE u8 *DqnFile_ReadAll(wchar_t const *path, usize *buf_size, DqnAllocator *allocator = dqn_lib_context_.allocator);
-DQN_FILE_SCOPE u8 *DqnFile_ReadAll(wchar_t const *path, usize *buf_size, DqnMemStack *stack);
-DQN_FILE_SCOPE u8 *DqnFile_ReadAll(char const *path, usize *buf_size, DqnMemStack *stack);
-
-DQN_FILE_SCOPE bool DqnFile_WriteAll(char const *path, u8 const *buf, usize const buf_size);
-DQN_FILE_SCOPE bool DqnFile_WriteAll(wchar_t const *path, u8 const *buf, usize const buf_size);
-
-// return: False if file access failure
-DQN_FILE_SCOPE bool DqnFile_Size(char const *path, usize *size);
-DQN_FILE_SCOPE bool DqnFile_Size(wchar_t const *path, usize *size);
-
-DQN_FILE_SCOPE bool DqnFile_MakeDir(char const *path);
-
-// info: (Optional) Pass in to fill with file attributes
-// return: False if file access failure
-DQN_FILE_SCOPE bool DqnFile_GetInfo(char const *path, DqnFileInfo *info);
-DQN_FILE_SCOPE bool DqnFile_GetInfo(wchar_t const *path, DqnFileInfo *info);
-
-// NOTE: You can't delete a file unless the handle has been closed to it on Win32.
-// return: False if file access failure
-DQN_FILE_SCOPE bool DqnFile_Delete (char const *path);
-DQN_FILE_SCOPE bool DqnFile_Delete (wchar_t const *path);
-DQN_FILE_SCOPE bool DqnFile_Copy (char const *src, char const *dest);
-DQN_FILE_SCOPE bool DqnFile_Copy (wchar_t const *src, wchar_t const *dest);
-
-// NOTE: Win32: Current directory is "*", Unix: "."
-// num_files: Pass in a ref to a i32. The function fills it out with the number of entries.
-// return: An array of strings of the files in the directory in UTF-8. The directory lisiting is
-// allocated with malloc and must be freed using free() or the helper function ListDirFree()
-DQN_FILE_SCOPE char **DqnFile_ListDir (char const *dir, i32 *num_files, DqnAllocator *allocator = dqn_lib_context_.allocator);
-DQN_FILE_SCOPE void DqnFile_ListDirFree (char **file_list, i32 num_files, DqnAllocator *allocator = dqn_lib_context_.allocator);
-
-// XPlatform > #DqnCatalog
-// =================================================================================================
-using DqnCatalogPath = DqnFixedString1024;
-template using DqnCatalogLoadProc = bool (*)(DqnCatalogPath const &file, T *data);
-#define DQN_CATALOG_LOAD_PROC(name, type) bool name(DqnCatalogPath const &file, type *data)
-
-#define DQN_CATALOG_TEMPLATE template LoadAsset>
-#define DQN_CATALOG_DECL DqnCatalog
-
-#if 0
-struct RawBuf { char *buffer; int len; };
-DQN_CATALOG_LOAD_PROC(CatalogRawLoad, RawBuf)
-{
- size_t buf_size;
- uint8_t *buf = DqnFile_ReadAll(file.str, &buf_size);
- if (!buf) return false;
- data->buffer = reinterpret_cast(buf);
- data->len = static_cast(buf_size);
- return true;
-}
-
-int main(int, char)
-{
- DqnCatalog catalog = {};
- RawBuf *file = catalog.GetIfUpdated("path/to/file/");
- if (file) { (void)file; // do work on file }
- else { // file not updated since last query }
-
- while (true) // Or event loop, poll the assets in the catalog
- {
- catalog.PollAssets();
- }
- catalog.Free();
-}
-#endif
-
-DQN_CATALOG_TEMPLATE struct DqnCatalog
-{
- struct Entry
- {
- T data;
- u64 last_write_time_in_s;
- bool updated;
- };
-
- DqnVHashTable asset_table;
-
- // Adds the file to the catalog if it has not been added yet.
- // return: Asset if an update has been detected and not consumed yet otherwise nullptr. Update is consumed after called.
- T *GetIfUpdated(DqnCatalogPath const &file);
- Entry *GetEntry (DqnCatalogPath const &file) { Entry *entry = asset_table.Get(file); return entry; }
- T *Get (DqnCatalogPath const &file) { Entry *entry = asset_table.Get(file); return (entry) ? &entry->data : nullptr; }
- void Erase (DqnCatalogPath const &file) { asset_table.Erase(file); };
-
- // return: Iterate all loaded assets for updates, true if atleast 1 asset was updated.
- bool PollAssets ();
- void Free () { asset_table.Free(); }
-
- // NOTE: Unlikely you will need to use. Prefer GetIfUpdated.
- // Manually invoke an update on the entry by querying its last write time on disk and updating accordingly.
- bool QueryAndUpdateAsset(DqnCatalogPath const &file, Entry *entry);
-};
-
-DQN_CATALOG_TEMPLATE bool DQN_CATALOG_DECL::QueryAndUpdateAsset(DqnCatalogPath const &file, Entry *entry)
-{
- DqnFileInfo info = {};
- if (!DqnFile_GetInfo(file.str, &info))
- {
- DQN_LOGGER_W(dqn_lib_context_.logger, "Catalog could not get file info for: %s\n", file.str);
- return false;
- }
-
- if (entry->last_write_time_in_s == info.last_write_time_in_s)
- return true;
-
- T newData = {};
- if (LoadAsset(file, &newData))
- {
- entry->last_write_time_in_s = info.last_write_time_in_s;
- entry->data = newData;
- entry->updated = true;
- }
- else
- {
- DQN_LOGGER_W(dqn_lib_context_.logger, "Catalog could not load file: %s\n", file.str);
- return false;
- }
-
- return true;
-}
-
-DQN_CATALOG_TEMPLATE T *DQN_CATALOG_DECL::GetIfUpdated(DqnCatalogPath const &file)
-{
- Entry *entry = this->asset_table.GetOrMake(file);
- if (QueryAndUpdateAsset(file, entry))
- {
- if (entry->updated) entry->updated = false;
- else entry = nullptr;
- }
- else
- {
- entry = nullptr;
- }
-
- return &entry->data;
-}
-
-DQN_CATALOG_TEMPLATE bool DQN_CATALOG_DECL::PollAssets()
-{
- bool result = false;
- for (auto it = this->asset_table.begin(); it != this->asset_table.end(); ++it)
- {
- DqnCatalogPath const *file = &it.entry->key;
- Entry *entry = &it.entry->item;
- result |= QueryAndUpdateAsset(*file, entry);
- }
-
- return result;
-}
-
-
-// XPlatform > #DqnTimer
-// =================================================================================================
-DQN_FILE_SCOPE f64 DqnTimer_NowInMs();
-DQN_FILE_SCOPE f64 DqnTimer_NowInS ();
-
-// XPlatform > #DqnLock
-// =================================================================================================
-struct DqnLock
-{
-#if defined(DQN_IS_WIN32)
- CRITICAL_SECTION win32_handle;
-#else
- pthread_mutex_t unix_handle;
-#endif
-
- // Win32 only, when trying to acquire a locked lock, it is the number of spins permitted
- // spinlocking on the lock before being blocked. Set before init if you want a different value.
- u32 win32_spin_count = 16000;
-
- bool Init ();
- void Acquire();
- void Release();
- void Delete ();
-
- struct Guard_
- {
- Guard_(DqnLock *lock_) : lock(lock_) { lock->Acquire(); }
- ~Guard_() { lock->Release(); }
-
- private:
- DqnLock *lock;
- };
-
- // Create a lock guard on the lock this is invoked on.
- Guard_ Guard() { return Guard_(this); }
-};
-
-// XPlatform > #DqnJobQueue
-// =================================================================================================
-// DqnJobQueue is a platform abstracted "lockless" multithreaded work queue. It will create threads
-// and assign threads to complete the job via the job "callback" using the "user_data" supplied.
-
-// Usage
-// 1. Prepare your callback function for threads to execute following the 'DqnJob_Callback' function
-// signature.
-// 2. Create a job queue with DqnJobQueue_InitWithMem()
-// 3. Add jobs with DqnJobQueue_AddJob() and threads will be dispatched automatically.
-
-// When all jobs are sent you can also utilise the main executing thread to complete jobs whilst you
-// wait for all jobs to complete using DqnJobQueue_TryExecuteNextJob() or spinlock on
-// DqnJobQueue_AllJobsComplete(). Alternatively you can combine both for the main thread to help
-// complete work and not move on until all tasks are complete.
-
-typedef void DqnJob_Callback(struct DqnJobQueue *const queue, void *const user_data);
-struct DqnJob
-{
- DqnJob_Callback *callback;
- void *user_data;
-};
-
-struct DqnJobQueue
-{
- // JobList Circular Array, is setup in Init()
- DqnJob *job_list;
- u32 size;
-
- // NOTE(doyle): Modified by main+worker threads
- i32 volatile jobToExecuteIndex;
- i32 volatile num_jobs_queued;
-
-#if defined(DQN_IS_WIN32)
- void *semaphore;
-#else
- sem_t semaphore;
-#endif
-
- // NOTE: Modified by main thread ONLY
- i32 volatile jobInsertIndex;
-
- bool Init (DqnJob *const job_list_, const u32 job_list_size, const u32 num_threads);
- bool AddJob (const DqnJob job);
-
- void BlockAndCompleteAllJobs();
- bool TryExecuteNextJob();
- bool AllJobsComplete ();
-};
-
-// TODO(doyle): Queue delete, thread delete
-
-// queue: Pass a pointer to a zero cleared DqnJobQueue struct
-// job_list: Pass in a pointer to an array of DqnJob's
-// job_list_size: The number of elements in the job_list array
-// num_threads: The number of threads the queue should request from the OS for working on the queue
-// return: FALSE if invalid args i.e. nullptr ptrs or job_list_size & num_threads == 0
-DQN_FILE_SCOPE bool DqnJobQueue_Init(DqnJobQueue *const queue, const DqnJob *const job_list,
- const u32 job_list_size, const u32 num_threads);
-
-// return: FALSE if the job is not able to be added, this occurs if the queue is full.
-DQN_FILE_SCOPE bool DqnJobQueue_AddJob(DqnJobQueue *const queue, const DqnJob job);
-
-// Helper function that combines TryExecuteNextJob() and AllJobsComplete(), i.e.
-// complete all work before moving on. Does nothing if queue is nullptr.
-DQN_FILE_SCOPE void DqnJobQueue_BlockAndCompleteAllJobs(DqnJobQueue *const queue);
-
-// return: TRUE if there was a job to execute (the calling thread executes it). FALSE if it could
-// not get a job. It may return FALSE whilst there are still jobs, this means that another thread
-// has taken the job before the calling thread could and should NOT be used to determine if there
-// are any remaining jobs left. That can only be definitively known using
-// DqnJobQueue_AllJobsComplete(). This is typically combined like so ..
-// while (DqnJobQueue_TryExecuteNextJob(queue) || !DqnJobQueue_AllJobsComplete(queue));
-// Return FALSE also if queue is a nullptr pointer.
-DQN_FILE_SCOPE bool DqnJobQueue_TryExecuteNextJob(DqnJobQueue *const queue);
-DQN_FILE_SCOPE bool DqnJobQueue_AllJobsComplete (DqnJobQueue *const queue);
-
-// XPlatform > #DqnAtomic
-// =================================================================================================
-// All atomic operations generate a full read/write barrier. This is implicitly enforced by the
-// OS calls, not explicitly in my code.
-
-// swap_val: The value to put into "dest", IF at point of read, "dest" has the value of "compare_val"
-// compare_val: The value to check in "dest"
-// return: Return the original value that was in "dest"
-DQN_FILE_SCOPE i32 DqnAtomic_CompareSwap32(i32 volatile *const dest, const i32 swap_val, const i32 compare_val);
-
-// Add "value" to src
-// return: The new value at src
-DQN_FILE_SCOPE i32 DqnAtomic_Add32(i32 volatile *const src, const i32 value);
-
-// #Platform Specific
-// =================================================================================================
-// Functions here are only available for the #defined sections (i.e. all functions in
-// DQN_IS_WIN32 only have a valid implementation in Win32.
-
-#if defined(DQN_IS_WIN32)
-// Platform > #DqnWin32
-// =================================================================================================
-#define DQN__WIN32_ERROR_BOX(text, title) MessageBoxA(nullptr, text, title, MB_OK);
-
-// The function automatically null-terminates the output string.
-// out: A pointer to the buffer to receive the characters.
-// out_len: The length/capacity of the buffer "out". If 0, the function returns the required length including null terminator.
-// return: -1 if invalid, or if out_len is 0 the required buffer length.
-DQN_FILE_SCOPE i32 DqnWin32_UTF8ToWChar(const char *const in, wchar_t *const out, const i32 out_len);
-DQN_FILE_SCOPE i32 DqnWin32_WCharToUTF8(const wchar_t *const in, char *const out, const i32 out_len);
-
-// "width" and "height" are optional and won't be used if not given by user.
-// width & height: Pass in a pointer for function to fill out.
-DQN_FILE_SCOPE void DqnWin32_GetClientDim (HWND const window, LONG *width, LONG *height);
-DQN_FILE_SCOPE void DqnWin32_GetRectDim (RECT const rect, LONG *width, LONG *height);
-
-DQN_FILE_SCOPE char const *DqnWin32_GetLastError();
-
-// TODO(doyle): #deprecate #delete Display Last Error is mostly useless.
-// Displays error in the format : in a Win32 Dialog Box.
-// err_prefix: The message before the Win32 error, can be nullptr
-DQN_FILE_SCOPE void DqnWin32_DisplayLastError (const char *const err_prefix);
-
-// Asimilar to DqnWin32_DisplayLastError() a particular error can be specified in a Win32 Dialog Box.
-DQN_FILE_SCOPE void DqnWin32_DisplayErrorCode (const DWORD error, const char *const err_prefix);
-
-// Output text to the debug console. For visual studio this is the output window and not the console.
-// ...: Variable args alike printf, powered by stb_sprintf
-DQN_FILE_SCOPE void DqnWin32_OutputDebugString(const char *const fmt_str, ...);
-
-DQN_FILE_SCOPE void DqnWin32_GetExeNameAndDirectory(DqnMemStack *allocator, DqnBuffer *exe_name, DqnBuffer *exe_directory);
-DQN_FILE_SCOPE u64 DqnWin32_EpochTimeUTC ();
-DQN_FILE_SCOPE u64 DqnWin32_EpochTimeLocal ();
-#endif // DQN_IS_WIN32
-#endif // DQN_PLATFORM_H
-#endif // DQN_PLATFORM_HEADER
-
-
-#ifdef DQN_IMPLEMENTATION
-// DQN_IMPLEMENTATION
-// =================================================================================================
-#include // TODO(doyle): For trigonometry functions (for now)
-#include // For calloc, malloc, free
-#include // For printf
-
-DqnAllocator xallocator_;
-DqnAllocator allocator_;
-DqnLogger logger_;
-DqnLibContext dqn_lib_context_ = {&xallocator_, &allocator_, &logger_};
-
-// NOTE: STB_SPRINTF is included when DQN_IMPLEMENTATION defined
-// #define STB_SPRINTF_IMPLEMENTATION
-
-// NOTE: DQN_INI_IMPLEMENTATION modified to be included when DQN_IMPLEMENTATION defined
-// #define DQN_INI_IMPLEMENTATION
-#define DQN_INI_STRLEN(s) DqnStr_Len(s)
-
-// #DqnMemory
-// =================================================================================================
-// NOTE: All memory allocations in dqn.h go through these functions. So they can
-// be rerouted fairly easily especially for platform specific mallocs.
-DQN_FILE_SCOPE void *DqnMem_Alloc(usize size)
-{
- void *result = malloc(size);
- return result;
-}
-
-DQN_FILE_SCOPE void *DqnMem_XAlloc(usize size)
-{
- void *result = malloc(size);
- DQN_ALWAYS_ASSERT(result);
- return result;
-}
-
-
-DQN_FILE_SCOPE void *DqnMem_Calloc(usize size)
-{
- void *result = calloc(1, size);
- return result;
-}
-
-DQN_FILE_SCOPE void *DqnMem_XCalloc(usize size)
-{
- void *result = calloc(1, size);
- DQN_ALWAYS_ASSERT(result);
- return result;
-}
-
-DQN_FILE_SCOPE void DqnMem_Clear(void *memory, u8 clear_val, usize size)
-{
- if (memory)
- {
- DqnMem_Set(memory, clear_val, size);
- }
-}
-
-DQN_FILE_SCOPE void *DqnMem_Realloc(void *memory, usize new_size)
-{
- void *result = realloc(memory, new_size);
- return result;
-}
-
-DQN_FILE_SCOPE void *DqnMem_XRealloc(void *memory, usize new_size)
-{
- void *result = realloc(memory, new_size);
- DQN_ALWAYS_ASSERT(result);
- return result;
-}
-
-DQN_FILE_SCOPE void DqnMem_Free(void *memory)
-{
- if (memory) free(memory);
-}
-
-DQN_FILE_SCOPE void DqnMem_Copy(void *dest, void const *src, usize num_bytes_to_copy)
-{
- auto *to = (u8 *)dest;
- auto *from = (u8 *)src;
- for (usize i = 0; i < num_bytes_to_copy; i++)
- to[i] = from[i];
-}
-
-DQN_FILE_SCOPE void *DqnMem_Set(void *dest, u8 value, usize num_bytes_to_set)
-{
- auto volatile *ptr = (u8 *)dest; // NOTE: Volatile so memset is not optimised out.
- for (usize i = 0; i < num_bytes_to_set; i++)
- ptr[i] = value;
-
- return dest;
-}
-
-DQN_FILE_SCOPE int DqnMem_Cmp(void const *src, void const *dest, usize num_bytes)
-{
- auto const *src_ptr = static_cast(src);
- auto const *dest_ptr = static_cast(dest);
-
- usize i;
- for (i = 0; i < num_bytes; ++i)
- {
- if (src_ptr[i] != dest_ptr[i])
- break;
- }
-
- i = DQN_MIN(i, (num_bytes - 1));
- return (src_ptr[i] - dest_ptr[i]);
-}
-
-// #DqnMemTracker
-// =================================================================================================
-DQN_FILE_SCOPE void *DqnAllocator::Malloc(size_t size, Dqn::ZeroMem zero)
-{
- void *result = nullptr;
- switch(this->type)
- {
- case Type::Default: (zero == Dqn::ZeroMem::Yes) ? result = DqnMem_Alloc(size) : result = DqnMem_Calloc(size); break;
- case Type::XAllocator:
- {
- (zero == Dqn::ZeroMem::Yes) ? result = DqnMem_Alloc(size) : result = DqnMem_Calloc(size);
- DQN_ASSERT(result);
- }
- break;
-
- case Type::VirtualMemory:
- {
- #if defined(DQN_PLATFORM_HEADER)
- result = DqnOS_VAlloc(size);
- #else
- DQN_ASSERT_MSG(DQN_INVALID_CODE_PATH,
- "Dqn library hasn't been built with the platform header. I don't know how "
- "to allocate virtual memory!");
- #endif
- }
- break;
- case Type::DqnMemStack:
- {
- auto *mem_stack = reinterpret_cast(user_context);
- result = DQN_MEMSTACK_PUSH(mem_stack, size);
- if (zero == Dqn::ZeroMem::Yes) DqnMem_Clear(result, 0, size);
- }
- break;
- default: DQN_ASSERT_MSG(DQN_INVALID_CODE_PATH, "New context type not handled."); break;
- }
- return result;
-}
-
-DQN_FILE_SCOPE void *DqnAllocator::Realloc(void *ptr, size_t new_size)
-{
- void *result = nullptr;
- switch(this->type)
- {
- case Type::Default: result = DqnMem_Realloc(ptr, new_size); break;
- case Type::XAllocator:
- {
- result = DqnMem_Realloc(ptr, new_size);
- DQN_ASSERT(result);
- }
- break;
- case Type::VirtualMemory: DQN_ASSERT_MSG(DQN_INVALID_CODE_PATH, "Realloc is disallowed on virtual memory! Reserve a bigger range!"); break;
- case Type::DqnMemStack:
- {
- auto *mem_stack = reinterpret_cast(user_context);
- DqnPtrHeader *ptr_header = mem_stack->tracker.PtrToHeader(static_cast(ptr));
- result = DQN_MEMSTACK_PUSH(mem_stack, new_size);
- DqnMem_Copy(result, ptr, ptr_header->alloc_amount);
- DQN_LOGGER_W(dqn_lib_context_.logger, "Memory stack used realloc and ptr: %p with: %zu bytes has been lost", ptr, ptr_header->alloc_amount);
- }
- break;
- default: DQN_ASSERT_MSG(DQN_INVALID_CODE_PATH, "New context type not handled."); break;
- }
- return result;
-}
-
-DQN_FILE_SCOPE void DqnAllocator::Free(void *ptr, size_t old_size)
-{
- (void)old_size;
- switch(this->type)
- {
- case Type::XAllocator:
- case Type::Default: DqnMem_Free(ptr); break;
- case Type::VirtualMemory:
- {
- #if defined(DQN_PLATFORM_HEADER)
- DqnOS_VFree(ptr, old_size);
- #else
- DQN_ASSERT_MSG(DQN_INVALID_CODE_PATH,
- "Dqn library hasn't been built with the platform header. I don't know how to free virtual memory!");
- #endif
- }
- break;
- case Type::DqnMemStack: /*do nothing*/ break;
- default: DQN_ASSERT_MSG(DQN_INVALID_CODE_PATH, "New context type not handled."); break;
- }
-}
-
-// #DqnMemTracker
-// =================================================================================================
-// TODO(doyle): We shouldn't be using the library context for allocations since this is per
-// allocator or actually maybe yes? I think we want more granularity then that
-void DqnMemTracker::Init(DqnMemTracker::Flag flag)
-{
- *this = {};
- this->bounds_guard_size = (flag & DqnMemTracker::BoundsGuard) ? sizeof(HEAD_GUARD_VALUE) : 0;
-
- if (flag & DqnMemTracker::TrackPtr)
- {
- this->ptrs_max = 8192;
- this->ptrs = (void **)dqn_lib_context_.allocator->Malloc(this->ptrs_max * sizeof(this->ptrs));
- }
-
- if (flag & DqnMemTracker::TagAllocation)
- {
- this->tagged_allocs_max = 4096;
- this->tagged_allocs = (decltype(this->tagged_allocs))dqn_lib_context_.allocator->Malloc(this->tagged_allocs_max * sizeof(*this->tagged_allocs));
- this->tagged_allocs_used_list = (decltype(this->tagged_allocs_used_list))dqn_lib_context_.allocator->Malloc(this->tagged_allocs_max * sizeof(*this->tagged_allocs_used_list));
- }
-}
-
-void DqnMemTracker::Free()
-{
- if (this->IsTaggingAllocations())
- {
- DQN_FOR_EACH(i, this->tagged_allocs_used_index)
- {
- u16 used_index = this->tagged_allocs_used_list[i];
- for (TaggedAllocation *tagged_alloc = this->tagged_allocs[used_index]; tagged_alloc;)
- {
- TaggedAllocation *tag_to_free = tagged_alloc;
- tagged_alloc = tagged_alloc->next;
- dqn_lib_context_.allocator->Free(tag_to_free->filename.str, tag_to_free->filename.len);
- dqn_lib_context_.allocator->Free(tag_to_free->function.str, tag_to_free->function.len);
- dqn_lib_context_.allocator->Free(tag_to_free, sizeof(tag_to_free));
- }
- }
- }
-
- if (this->IsTrackingPtrs())
- dqn_lib_context_.allocator->Free(this->ptrs, sizeof(*this->ptrs) * ptrs_max);
-}
-
-void DqnMemTracker::Tag_(DqnBuffer filename, DqnBuffer function, int line_num, DqnBuffer filename_line_num_data, isize bytes)
-{
- if (!Dqn::allow_allocation_tagging || !this->IsTaggingAllocations())
- return;
-
- u16 index = DqnHash_Murmur32(filename_line_num_data.data, filename_line_num_data.len) % this->tagged_allocs_max;
- TaggedAllocation **entry = this->tagged_allocs + index;
- for (; *entry && (*entry)->filename.len > 0; entry = &((*entry)->next))
- {
- if (line_num == (*entry)->line_num && DQN_BUFFER_STRCMP(filename, (*entry)->filename, Dqn::IgnoreCase::Yes))
- break;
- }
-
- if (!(*entry))
- *entry = (TaggedAllocation *)dqn_lib_context_.allocator->Malloc(sizeof(**entry), Dqn::ZeroMem::Yes);
-
- if ((*entry)->filename.len == 0)
- {
- this->tagged_allocs_used_list[this->tagged_allocs_used_index++] = index;
- (*entry)->filename = DqnBuffer_CopyAndNullTerminate(dqn_lib_context_.allocator, filename.str, filename.len);
- (*entry)->function = DqnBuffer_CopyAndNullTerminate(dqn_lib_context_.allocator, function.str, function.len);
- (*entry)->line_num = line_num;
- }
-
- (*entry)->bytes_allocated += bytes;
- DQN_ALWAYS_ASSERT((*entry)->bytes_allocated >= 0);
-
- DqnLogger::Context context = {};
- context.filename = (*entry)->filename.str;
- context.filename_len = (*entry)->filename.len;
- context.function = (*entry)->function.str;
- context.function_len = (*entry)->function.len;
- context.line_num = line_num;
- dqn_lib_context_.logger->Log(DqnLogger::Type::Memory, context, "Currently allocated: %zu bytes", (*entry)->bytes_allocated);
-}
-
-void *DqnMemTracker::SetupPtr(void *ptr, isize size, u8 alignment)
-{
- // Calculate the aligned ptr
- auto *byte_ptr = static_cast(ptr);
- auto *unaligned_result = static_cast(ptr) + sizeof(DqnPtrHeader) + this->bounds_guard_size;
- auto *aligned_result = reinterpret_cast(DQN_ALIGN_POW_N(unaligned_result, alignment));
- isize const offset_to_ptr_header = aligned_result - unaligned_result;
- DQN_ASSERT(offset_to_ptr_header >= 0 && offset_to_ptr_header <= (alignment - 1));
-
- char *check_allignment = reinterpret_cast(DQN_ALIGN_POW_N(aligned_result, alignment));
- DQN_ASSERT_MSG(check_allignment == aligned_result, "Adding bounds guard should not destroy alignment! %p != %p", aligned_result, check_allignment);
- // Instrument allocation with guards and tracker
- {
- auto *ptr_header = reinterpret_cast(byte_ptr + offset_to_ptr_header);
- ptr_header->offset_to_src_ptr = static_cast(aligned_result - byte_ptr);
- ptr_header->alignment = alignment;
- ptr_header->alloc_amount = size;
- }
-
- if (this->IsGuardingBounds())
- {
- u32 *head_guard = reinterpret_cast(aligned_result - sizeof(DqnMemTracker::HEAD_GUARD_VALUE));
- u32 *tail_guard = reinterpret_cast(aligned_result + size);
- *head_guard = DqnMemTracker::HEAD_GUARD_VALUE;
- *tail_guard = DqnMemTracker::TAIL_GUARD_VALUE;
- }
-
- if (this->IsTrackingPtrs())
- {
- if (this->ptrs_len + 1 > this->ptrs_max)
- {
- this->ptrs_max *= 2;
- this->ptrs = (void **)DqnMem_XRealloc(this->ptrs, sizeof(this->ptrs) * this->ptrs_max);
- }
- this->ptrs[this->ptrs_len++] = aligned_result;
- this->CheckPtrs();
- }
-
- return aligned_result;
-}
-
-void DqnMemTracker::RemovePtr(void *ptr)
-{
- if (!this->IsTrackingPtrs())
- return;
-
- DQN_ASSERT(this->ptrs_len > 0);
-
- b32 found = false;
- DQN_FOR_EACH(i, this->ptrs_len)
- {
- if (this->ptrs[i] == ptr)
- {
- this->ptrs[i] = this->ptrs[--this->ptrs_len];
- found = true;
- break;
- }
- }
-
- DQN_ALWAYS_ASSERTM(found, "Ptr %p was not in the tracked pointers list", ptr);
-}
-
-void DqnMemTracker::RemovePtrRange(void *start, void *end)
-{
- if (!this->IsTrackingPtrs())
- return;
-
- if (start >= end) return;
- DQN_FOR_EACH(i, this->ptrs_len)
- {
- void *ptr = this->ptrs[i];
- if (ptr >= start && ptr < end)
- this->ptrs[i--] = this->ptrs[--this->ptrs_len];
- }
-}
-
-void DqnMemTracker::CheckPtrs() const
-{
- if (!this->IsGuardingBounds())
- return;
-
- DQN_FOR_EACH(i, this->ptrs_len)
- {
- char *ptr = static_cast(this->ptrs[i]);
- u32 const *head_guard = this->PtrToHeadGuard(ptr);
- u32 const *tail_guard = this->PtrToTailGuard(ptr);
-
- DQN_ASSERT_MSG(*head_guard == HEAD_GUARD_VALUE,
- "Bounds guard has been destroyed at the head end of the allocation! Expected: "
- "%x, received: %x",
- HEAD_GUARD_VALUE, *head_guard);
-
- DQN_ASSERT_MSG(*tail_guard == TAIL_GUARD_VALUE,
- "Bounds guard has been destroyed at the tail end of the allocation! Expected: "
- "%x, received: %x",
- TAIL_GUARD_VALUE, *tail_guard);
- }
-}
-
-// #DqnMemStack
-// =================================================================================================
-DQN_FILE_SCOPE DqnMemStack::Block *
-DqnMemStack__AllocateBlock(isize size, Dqn::ZeroMem zero, DqnAllocator *allocator)
-{
- isize total_size = sizeof(DqnMemStack::Block) + size;
- auto *result = static_cast(allocator->Malloc(total_size, zero));
- DQN_ALWAYS_ASSERTM(result, "Allocated memory block was null");
-
- char *block_offset = reinterpret_cast(result) + sizeof(*result);
- *result = DqnMemStack::Block(block_offset, size);
- return result;
-}
-
-DqnMemStack::DqnMemStack(void *mem, isize size, Dqn::ZeroMem clear, u32 flags_, DqnMemTracker::Flag flags)
-{
- DQN_ALWAYS_ASSERTM(mem, "Supplied fixed memory buffer is nullptr, initialise with fixed memory failed");
- DQN_ALWAYS_ASSERTM(size > sizeof(DqnMemStack::Block), "[%zu < %zu] Buffer too small for block metadata", size, sizeof(DqnMemStack::Block));
- *this = {};
-
- if (clear == Dqn::ZeroMem::Yes)
- DqnMem_Set(mem, 0, size);
-
- char *block_offset = static_cast(mem) + sizeof(*this->block);
- isize const block_size = size - sizeof(*this->block);
-
- this->block = static_cast(mem);
- *this->block = Block(block_offset, block_size);
- this->flags = (flags_ | Flag::NonExpandable);
- this->tracker.Init(flags);
-}
-
-void DqnMemStack::LazyInit(isize size, Dqn::ZeroMem clear, u32 flags_, DqnMemTracker::Flag tracker_flags, DqnAllocator *block_allocator_)
-{
- DQN_ALWAYS_ASSERTM(size > 0, "%zu <= 0", size);
- *this = {};
- this->block = DqnMemStack__AllocateBlock(size, clear, block_allocator_);
- this->flags = flags_;
- this->block_allocator = block_allocator_;
- this->tracker.Init(tracker_flags);
-}
-
-void *DqnMemStack::Push_(usize size, PushType push_type, u8 alignment)
-{
- DQN_ASSERT(size >= 0 && (alignment % 2 == 0));
- DQN_ALWAYS_ASSERTM(alignment <= 128, "Alignment _not_ supported. Update metadata to use u16 for storing the offset!");
-
- if (size == 0)
- return nullptr;
-
- if (!this->block)
- this->LazyInit(MINIMUM_BLOCK_SIZE, Dqn::ZeroMem::Yes);
-
- usize size_to_alloc = this->tracker.GetAllocationSize(size, alignment);
- bool push_to_head = true;
- if (push_type == PushType::Default || push_type == PushType::Opposite)
- {
- push_to_head = !(this->flags & Flag::DefaultAllocateTail);
- if (push_type == PushType::Opposite) push_to_head = !push_to_head;
- }
- else
- {
- push_to_head = (push_type == PushType::Head);
- }
-
-
- // Allocate New Block If Full
- // =============================================================================================
- bool need_new_block = true;
- if (push_to_head) need_new_block = ((this->block->head + size_to_alloc) > this->block->tail);
- else need_new_block = ((this->block->tail - size_to_alloc) < this->block->head);
-
- if (need_new_block)
- {
- if ((this->flags & Flag::NonExpandable) && this->block)
- {
- DQN_ASSERT_MSG(!(this->flags & Flag::NonExpandableAssert), "Allocator is non-expandable and has run out of memory");
- return nullptr;
- }
-
- isize new_block_size = DQN_MAX(size_to_alloc, MINIMUM_BLOCK_SIZE);
- Block *new_block = DqnMemStack__AllocateBlock(new_block_size, Dqn::ZeroMem::No, this->block_allocator);
- new_block->prev_block = this->block;
- this->block = new_block;
- }
-
- // Calculate Ptr To Give Client
- // =============================================================================================
- char *src_ptr = (push_to_head) ? (this->block->head) : (this->block->tail - size_to_alloc);
- void *aligned_result = this->tracker.SetupPtr(src_ptr, size, alignment);
- this->tracker.PtrToHeader((char *)aligned_result)->alloc_type = (push_to_head) ? 0 : 1;
-
- if (push_to_head)
- {
- this->block->head += size_to_alloc;
- DQN_ASSERT(this->block->head <= this->block->tail);
- }
- else
- {
- this->block->tail -= size_to_alloc;
- DQN_ASSERT(this->block->tail >= this->block->head);
- }
-
- return aligned_result;
-}
-
-void DqnMemStack::Pop(void *ptr, Dqn::ZeroMem clear)
-{
- if (!ptr) return;
-
- char *byte_ptr = static_cast(ptr);
- DqnPtrHeader *ptr_header = reinterpret_cast(byte_ptr - sizeof(*ptr_header) - this->tracker.bounds_guard_size);
-
- // Check instrumented data
- this->tracker.CheckPtrs();
- this->tracker.RemovePtr(byte_ptr);
-
- isize full_alloc_size = this->tracker.GetAllocationSize(ptr_header->alloc_amount, ptr_header->alignment);
- char *start = byte_ptr - ptr_header->offset_to_src_ptr;
- char *end = start + full_alloc_size;
- char const *block_end = this->block->memory + this->block->size;
-
- if (ptr_header->alloc_type == 0)
- {
- DQN_ASSERT_MSG(end == this->block->head, "Pointer to pop was not the last allocation! %p != %p", end, this->block->head);
- this->block->head -= full_alloc_size;
- DQN_ASSERT(this->block->head >= this->block->memory);
- }
- else
- {
- DQN_ASSERT_MSG(start == this->block->tail, "Pointer to pop was not the last allocation! %p != %p", start, this->block->tail);
- this->block->tail += full_alloc_size;
- DQN_ASSERT(this->block->tail <= block_end);
- }
-
- if (clear == Dqn::ZeroMem::Yes)
- DqnMem_Set(start, 0, end - start);
-
- if (this->block->tail == block_end && this->block->head == this->block->memory)
- {
- if (this->block->prev_block)
- this->PopBlock();
- }
-}
-
-bool DqnMemStack::FreeBlock(DqnMemStack::Block *mem_block)
-{
- if (!mem_block || !this->block)
- return false;
-
- DqnMemStack::Block **block_ptr = &this->block;
-
- while (*block_ptr && (*block_ptr) != mem_block)
- block_ptr = &((*block_ptr)->prev_block);
-
- if (*block_ptr)
- {
- DqnMemStack::Block *block_to_free = *block_ptr;
- (*block_ptr) = block_to_free->prev_block;
-
- this->tracker.RemovePtrRange(block_to_free->memory, block_to_free->memory + block_to_free->size);
- isize real_size = block_to_free->size + sizeof(DqnMemStack::Block);
- this->block_allocator->Free(block_to_free, real_size);
-
- // No more blocks, then last block has been freed
- if (!this->block) DQN_ASSERT(this->mem_region_count == 0);
- return true;
- }
-
- return false;
-}
-
-void DqnMemStack::ResetTail()
-{
- char *start = this->block->tail;
- char *end = this->block->memory + this->block->size;
- this->tracker.RemovePtrRange(start, end);
- this->block->tail = end;
-}
-
-void DqnMemStack::ClearCurrBlock(Dqn::ZeroMem zero)
-{
- if (this->block)
- {
- this->tracker.RemovePtrRange(this->block->memory, this->block->memory + this->block->size);
- this->block->head = this->block->memory;
- this->block->tail = this->block->memory + this->block->size;
- if (zero == Dqn::ZeroMem::Yes)
- {
- DqnMem_Clear(this->block->memory, 0, this->block->size);
- }
- }
-}
-
-DqnMemStack::Info DqnMemStack::GetInfo() const
-{
- Info result = {};
- for (Block *block_ = this->block; block_; block_ = block_->prev_block)
- {
- char const *block_end = block_->memory + block_->size;
- isize usage_from_head = block_->head - block_->memory;
- isize usage_from_tail = block_end - block_->tail;
-
- result.total_used += usage_from_head + usage_from_tail;
- result.total_size += block_->size;
- result.wasted_size += (block_->size - usage_from_head - usage_from_tail);
- result.num_blocks++;
- }
-
- char const *block_end = this->block->memory + this->block->size;
- isize usage_from_head = this->block->head - this->block->memory;
- isize usage_from_tail = block_end - this->block->tail;
- result.wasted_size -= (this->block->size - usage_from_head - usage_from_tail); // Don't include the curr block
-
- return result;
-}
-
-DqnMemStack::MemRegion DqnMemStack::MemRegionBegin()
-{
- MemRegion result = {};
- result.stack = this;
- if (this->block)
- {
- result.starting_block = this->block;
- result.starting_block_head = this->block->head;
- result.starting_block_tail = this->block->tail;
- }
-
- this->mem_region_count++;
- return result;
-}
-
-void DqnMemStack::MemRegionEnd(MemRegion region)
-{
- DQN_ASSERT(region.stack == this);
-
- this->mem_region_count--;
- DQN_ASSERT(this->mem_region_count >= 0);
-
- while (this->block != region.starting_block)
- this->PopBlock();
-
- if (this->block)
- {
- this->block->head = region.starting_block_head;
- this->block->tail = region.starting_block_tail;
-
- char *start = this->block->head;
- char *end = this->block->tail;
- this->tracker.RemovePtrRange(start, end);
- }
-}
-
-void DqnMemStack::MemRegionSave(MemRegion *region)
-{
- DQN_ASSERT(region->stack == this);
- region->stack = nullptr;
- this->mem_region_count--;
- DQN_ASSERT(this->mem_region_count >= 0);
-}
-
-// #DqnHash
-// =================================================================================================
-// Taken from GingerBill single file library @ github.com/gingerbill/gb
-u32 DqnHash_Murmur32Seed(void const *data, usize len, u32 seed)
-{
- u32 const c1 = 0xcc9e2d51; u32 const c2 = 0x1b873593; u32 const r1 = 15;
- u32 const r2 = 13; u32 const m = 5; u32 const n = 0xe6546b64;
-
- usize i, nblocks = len / 4;
- u32 hash = seed, k1 = 0;
- u32 const *blocks = (u32 const *)data;
- u8 const *tail = (u8 const *)(data) + nblocks * 4;
-
- for (i = 0; i < nblocks; i++) {
- u32 k = blocks[i];
- k *= c1;
- k = (k << r1) | (k >> (32 - r1));
- k *= c2;
-
- hash ^= k;
- hash = ((hash << r2) | (hash >> (32 - r2))) * m + n;
- }
-
- switch (len & 3) {
- case 3: k1 ^= tail[2] << 16;
- case 2: k1 ^= tail[1] << 8;
- case 1: k1 ^= tail[0];
-
- k1 *= c1;
- k1 = (k1 << r1) | (k1 >> (32 - r1));
- k1 *= c2;
- hash ^= k1;
- }
-
- hash ^= len; hash ^= (hash >> 16);
- hash *= 0x85ebca6b; hash ^= (hash >> 13);
- hash *= 0xc2b2ae35; hash ^= (hash >> 16);
-
- return hash;
-}
-
-u64 DqnHash_Murmur64Seed(void const *data_, usize len, u64 seed)
-{
- u64 const m = 0xc6a4a7935bd1e995ULL;
- i32 const r = 47;
-
- u64 h = seed ^ (len * m);
-
- u64 const *data = (u64 const *)data_;
- u8 const *data2 = (u8 const *)data_;
- u64 const *end = data + (len / 8);
-
- while (data != end) {
- u64 k = *data++;
- k *= m; k ^= k >> r; k *= m;
- h ^= k; h *= m;
- }
-
- switch (len & 7) {
- case 7: h ^= (u64)(data2[6]) << 48;
- case 6: h ^= (u64)(data2[5]) << 40;
- case 5: h ^= (u64)(data2[4]) << 32;
- case 4: h ^= (u64)(data2[3]) << 24;
- case 3: h ^= (u64)(data2[2]) << 16;
- case 2: h ^= (u64)(data2[1]) << 8;
- case 1: h ^= (u64)(data2[0]);
- h *= m;
- };
-
- h ^= h >> r; h *= m; h ^= h >> r;
- return h;
-}
-
-// #DqnMath
-// =================================================================================================
-DQN_FILE_SCOPE f32 DqnMath_Lerp(f32 a, f32 t, f32 b)
-{
- /*
- Linear blend between two values. We having a starting point "a", and
- the distance to "b" is defined as (b - a). Then we can say
-
- a + t(b - a)
-
- As our linear blend fn. We start from "a" and choosing a t from 0->1
- will vary the value of (b - a) towards b. If we expand this, this
- becomes
-
- a + (t * b) - (a * t) == (1 - t)a + t*b
- */
- f32 result = a + (b - a) * t;
- return result;
-}
-
-DQN_FILE_SCOPE f32 DqnMath_Sqrtf(f32 a)
-{
- f32 result = sqrtf(a);
- return result;
-}
-
-DQN_FILE_SCOPE f32 DqnMath_Clampf(f32 val, f32 min, f32 max)
-{
- if (val < min) return min;
- if (val > max) return max;
- return val;
-}
-
-// #DqnV2
-// =================================================================================================
-DQN_FILE_SCOPE DqnV2 DqnV2_Add(DqnV2 a, DqnV2 b)
-{
- DqnV2 result = {};
- for (u32 i = 0; i < DQN_ARRAY_COUNT(a.e); i++)
- result.e[i] = a.e[i] + b.e[i];
-
- return result;
-}
-
-DQN_FILE_SCOPE DqnV2 DqnV2_Sub(DqnV2 a, DqnV2 b)
-{
- DqnV2 result = {};
- for (u32 i = 0; i < DQN_ARRAY_COUNT(a.e); i++)
- result.e[i] = a.e[i] - b.e[i];
-
- return result;
-}
-
-DQN_FILE_SCOPE DqnV2 DqnV2_Scalei(DqnV2 a, i32 b)
-{
- DqnV2 result = {};
- for (u32 i = 0; i < DQN_ARRAY_COUNT(a.e); i++)
- result.e[i] = a.e[i] * b;
-
- return result;
-}
-
-DQN_FILE_SCOPE DqnV2 DqnV2_Scalef(DqnV2 a, f32 b)
-{
- DqnV2 result = {};
- for (u32 i = 0; i < DQN_ARRAY_COUNT(a.e); i++)
- result.e[i] = a.e[i] * b;
-
- return result;
-}
-
-DQN_FILE_SCOPE DqnV2 DqnV2_Hadamard(DqnV2 a, DqnV2 b)
-{
- DqnV2 result = {};
- for (u32 i = 0; i < DQN_ARRAY_COUNT(a.e); i++)
- result.e[i] = a.e[i] * b.e[i];
-
- return result;
-}
-
-DQN_FILE_SCOPE f32 DqnV2_Dot(DqnV2 a, DqnV2 b)
-{
- /*
- DOT PRODUCT
- Two vectors with dot product equals |a||b|cos(theta)
- |a| |d|
- |b| . |e| = (ad + be + cf)
- |c| |f|
- */
- f32 result = 0;
- for (u32 i = 0; i < DQN_ARRAY_COUNT(a.e); i++)
- result += (a.e[i] * b.e[i]);
-
- return result;
-}
-
-DQN_FILE_SCOPE bool DqnV2_Equals(DqnV2 a, DqnV2 b)
-{
- bool result = true;
- for (u32 i = 0; i < DQN_ARRAY_COUNT(a.e); i++)
- if (a.e[i] != b.e[i]) result = false;
- return result;
-}
-
-DQN_FILE_SCOPE f32 DqnV2_LengthSquared(DqnV2 a, DqnV2 b)
-{
- f32 x_ = b.x - a.x;
- f32 y_ = b.y - a.y;
- f32 result = (DQN_SQUARED(x_) + DQN_SQUARED(y_));
- return result;
-}
-
-DQN_FILE_SCOPE f32 DqnV2_Length(DqnV2 a, DqnV2 b)
-{
- f32 len_sq = DqnV2_LengthSquared(a, b);
- if (len_sq == 0) return 0;
-
- f32 result = DqnMath_Sqrtf(len_sq);
- return result;
-}
-
-DQN_FILE_SCOPE DqnV2 DqnV2_Normalise(DqnV2 a)
-{
- f32 magnitude = DqnV2_Length(DqnV2(0, 0), a);
- if (magnitude == 0) return DqnV2(0.0f);
-
- DqnV2 result = a * (1.0f / magnitude);
- return result;
-}
-
-DQN_FILE_SCOPE bool DqnV2_Overlaps(DqnV2 a, DqnV2 b)
-{
- bool result = false;
-
- f32 lenOfA = a.max - a.min;
- f32 lenOfB = b.max - b.min;
-
- if (lenOfA > lenOfB)
- {
- DqnV2 tmp = a;
- a = b;
- b = tmp;
- }
-
- if ((a.min >= b.min && a.min <= b.max) || (a.max >= b.min && a.max <= b.max))
- {
- result = true;
- }
-
- return result;
-}
-
-DQN_FILE_SCOPE DqnV2 DqnV2_Perpendicular(DqnV2 a)
-{
- DqnV2 result = DqnV2(a.y, -a.x);
- return result;
-}
-
-DQN_FILE_SCOPE DqnV2 DqnV2_ResizeKeepAspectRatio(DqnV2 src_size, DqnV2 target_size)
-{
- f32 ratio_a = src_size.w / target_size.w;
- f32 ratio_b = src_size.h / target_size.h;
- f32 ratio = DQN_MIN(ratio_a, ratio_b);
- DqnV2 result = DqnV2_Scalef(target_size, ratio);
- return result;
-}
-
-DQN_FILE_SCOPE DqnV2 DqnV2_ConstrainToRatio(DqnV2 dim, DqnV2 ratio)
-{
- DqnV2 result = {0};
- f32 num_ratio_increments_to_width = (f32)(dim.w / ratio.w);
- f32 num_ratio_increments_to_height = (f32)(dim.h / ratio.h);
-
- f32 least_increments_to_side =
- DQN_MIN(num_ratio_increments_to_height, num_ratio_increments_to_width);
-
- result.w = (f32)(ratio.w * least_increments_to_side);
- result.h = (f32)(ratio.h * least_increments_to_side);
- return result;
-}
-
-// #DqnV2i
-// =================================================================================================
-DQN_FILE_SCOPE DqnV2i DqnV2i_Add(DqnV2i a, DqnV2i b)
-{
- DqnV2i result = {};
- for (u32 i = 0; i < DQN_ARRAY_COUNT(a.e); i++)
- result.e[i] = a.e[i] + b.e[i];
-
- return result;
-}
-
-DQN_FILE_SCOPE DqnV2i DqnV2i_Sub(DqnV2i a, DqnV2i b)
-{
- DqnV2i result = {};
- for (u32 i = 0; i < DQN_ARRAY_COUNT(a.e); i++)
- result.e[i] = a.e[i] - b.e[i];
-
- return result;
-}
-
-DQN_FILE_SCOPE DqnV2i DqnV2i_Scalef(DqnV2i a, f32 b)
-{
- DqnV2i result = {};
- for (u32 i = 0; i < DQN_ARRAY_COUNT(a.e); i++)
- result.e[i] = (i32)(a.e[i] * b);
-
- return result;
-}
-
-DQN_FILE_SCOPE DqnV2i DqnV2i_Scalei(DqnV2i a, i32 b)
-{
- DqnV2i result = {};
- for (u32 i = 0; i < DQN_ARRAY_COUNT(a.e); i++)
- result.e[i] = a.e[i] * b;
-
- return result;
-}
-
-DQN_FILE_SCOPE DqnV2i DqnV2i_Hadamard(DqnV2i a, DqnV2i b)
-{
- DqnV2i result = {};
- for (u32 i = 0; i < DQN_ARRAY_COUNT(a.e); i++)
- result.e[i] = a.e[i] * b.e[i];
-
- return result;
-}
-
-DQN_FILE_SCOPE f32 DqnV2i_Dot(DqnV2i a, DqnV2i b)
-{
- /*
- DOT PRODUCT
- Two vectors with dot product equals |a||b|cos(theta)
- |a| |d|
- |b| . |e| = (ad + be + cf)
- |c| |f|
- */
- f32 result = 0;
- for (u32 i = 0; i < DQN_ARRAY_COUNT(a.e); i++)
- result += (a.e[i] * b.e[i]);
-
- return result;
-}
-
-DQN_FILE_SCOPE bool DqnV2i_Equals(DqnV2i a, DqnV2i b)
-{
- bool result = true;
- for (u32 i = 0; i < DQN_ARRAY_COUNT(a.e); i++)
- if (a.e[i] != b.e[i]) result = false;
- return result;
-}
-
-// #DqnV3
-// =================================================================================================
-DQN_FILE_SCOPE DqnV3 DqnV3_Add(DqnV3 a, DqnV3 b)
-{
- DqnV3 result = {0};
- for (u32 i = 0; i < DQN_ARRAY_COUNT(a.e); i++)
- result.e[i] = a.e[i] + b.e[i];
-
- return result;
-}
-
-DQN_FILE_SCOPE DqnV3 DqnV3_Sub(DqnV3 a, DqnV3 b)
-{
- DqnV3 result = {0};
- for (u32 i = 0; i < DQN_ARRAY_COUNT(a.e); i++)
- result.e[i] = a.e[i] - b.e[i];
-
- return result;
-}
-
-DQN_FILE_SCOPE DqnV3 DqnV3_Scalei(DqnV3 a, i32 b)
-{
- DqnV3 result = {0};
- for (u32 i = 0; i < DQN_ARRAY_COUNT(a.e); i++)
- result.e[i] = a.e[i] * b;
-
- return result;
-}
-
-DQN_FILE_SCOPE DqnV3 DqnV3_Scalef(DqnV3 a, f32 b)
-{
- DqnV3 result = {0};
- for (u32 i = 0; i < DQN_ARRAY_COUNT(a.e); i++)
- result.e[i] = a.e[i] * b;
-
- return result;
-}
-
-DQN_FILE_SCOPE DqnV3 DqnV3_Hadamard(DqnV3 a, DqnV3 b)
-{
- DqnV3 result = {0};
- for (u32 i = 0; i < DQN_ARRAY_COUNT(a.e); i++)
- result.e[i] = a.e[i] * b.e[i];
-
- return result;
-}
-
-DQN_FILE_SCOPE f32 DqnV3_Dot(DqnV3 a, DqnV3 b)
-{
- /*
- DOT PRODUCT
- Two vectors with dot product equals |a||b|cos(theta)
- |a| |d|
- |b| . |e| = (ad + be + cf)
- |c| |f|
- */
- f32 result = 0;
- for (u32 i = 0; i < DQN_ARRAY_COUNT(a.e); i++)
- result += (a.e[i] * b.e[i]);
-
- return result;
-}
-
-DQN_FILE_SCOPE bool DqnV3_Equals(DqnV3 a, DqnV3 b)
-{
- bool result = true;
- for (u32 i = 0; i < DQN_ARRAY_COUNT(a.e); i++)
- if (a.e[i] != b.e[i]) result = false;
- return result;
-}
-
-DQN_FILE_SCOPE DqnV3 DqnV3_Cross(DqnV3 a, DqnV3 b)
-{
- /*
- CROSS PRODUCT
- Generate a perpendicular vector to the 2 vectors
- |a| |d| |bf - ce|
- |b| x |e| = |cd - af|
- |c| |f| |ae - be|
- */
- DqnV3 result = {0};
- result.e[0] = (a.e[1] * b.e[2]) - (a.e[2] * b.e[1]);
- result.e[1] = (a.e[2] * b.e[0]) - (a.e[0] * b.e[2]);
- result.e[2] = (a.e[0] * b.e[1]) - (a.e[1] * b.e[0]);
- return result;
-}
-
-DQN_FILE_SCOPE DqnV3 DqnV3_Normalise(DqnV3 a)
-{
- f32 length = DqnMath_Sqrtf(DQN_SQUARED(a.x) + DQN_SQUARED(a.y) + DQN_SQUARED(a.z));
- f32 inv_len = 1 / length;
- DqnV3 result = a * inv_len;
-
- return result;
-}
-
-DQN_FILE_SCOPE f32 DqnV3_LengthSquared(DqnV3 a, DqnV3 b)
-{
- f32 x = b.x - a.x;
- f32 y = b.y - a.y;
- f32 z = b.z - a.z;
- f32 result = (DQN_SQUARED(x) + DQN_SQUARED(y) + DQN_SQUARED(z));
- return result;
-}
-
-DQN_FILE_SCOPE f32 DqnV3_Length(DqnV3 a, DqnV3 b)
-{
- f32 len_sq = DqnV3_LengthSquared(a, b);
- if (len_sq == 0) return 0;
-
- f32 result = DqnMath_Sqrtf(len_sq);
- return result;
-}
-
-// #DqnV4
-// =================================================================================================
-DQN_FILE_SCOPE DqnV4 DqnV4_Add(DqnV4 a, DqnV4 b)
-{
- DqnV4 result = {0};
- for (u32 i = 0; i < DQN_ARRAY_COUNT(a.e); i++)
- result.e[i] = a.e[i] + b.e[i];
-
- return result;
-}
-
-DQN_FILE_SCOPE DqnV4 DqnV4_Sub(DqnV4 a, DqnV4 b)
-{
- DqnV4 result = {0};
- for (u32 i = 0; i < DQN_ARRAY_COUNT(a.e); i++)
- result.e[i] = a.e[i] - b.e[i];
-
- return result;
-}
-
-DQN_FILE_SCOPE DqnV4 DqnV4_Scalei(DqnV4 a, i32 b)
-{
- DqnV4 result = {0};
- for (u32 i = 0; i < DQN_ARRAY_COUNT(a.e); i++)
- result.e[i] = a.e[i] * b;
-
- return result;
-}
-
-DQN_FILE_SCOPE DqnV4 DqnV4_Scalef(DqnV4 a, f32 b)
-{
- DqnV4 result = {0};
- for (u32 i = 0; i < DQN_ARRAY_COUNT(a.e); i++)
- result.e[i] = a.e[i] * b;
-
- return result;
-}
-
-DQN_FILE_SCOPE DqnV4 DqnV4_Hadamard(DqnV4 a, DqnV4 b)
-{
- DqnV4 result = {0};
- for (u32 i = 0; i < DQN_ARRAY_COUNT(a.e); i++)
- result.e[i] = a.e[i] * b.e[i];
-
- return result;
-}
-
-DQN_FILE_SCOPE f32 DqnV4_Dot(DqnV4 a, DqnV4 b)
-{
- /*
- DOT PRODUCT
- Two vectors with dot product equals |a||b|cos(theta)
- |a| |d|
- |b| . |e| = (ad + be + cf)
- |c| |f|
- */
- f32 result = 0;
- for (u32 i = 0; i < DQN_ARRAY_COUNT(a.e); i++)
- result += (a.e[i] * b.e[i]);
-
- return result;
-}
-
-DQN_FILE_SCOPE bool DqnV4_Equals(DqnV4 a, DqnV4 b)
-{
- bool result = true;
- for (u32 i = 0; i < DQN_ARRAY_COUNT(a.e); i++)
- if (a.e[i] != b.e[i]) result = false;
- return result;
-}
-
-// #DqnMat4 Implementation
-// =================================================================================================
-DQN_FILE_SCOPE DqnMat4 DqnMat4_Identity()
-{
- DqnMat4 result = {0, 0, 0, 0};
- result.e[0][0] = 1;
- result.e[1][1] = 1;
- result.e[2][2] = 1;
- result.e[3][3] = 1;
- return result;
-}
-
-DQN_FILE_SCOPE DqnMat4 DqnMat4_Orthographic(f32 left, f32 right, f32 bottom, f32 top, f32 znear,
- f32 zfar)
-{
- DqnMat4 result = DqnMat4_Identity();
- result.e[0][0] = +2.0f / (right - left);
- result.e[1][1] = +2.0f / (top - bottom);
- result.e[2][2] = -2.0f / (zfar - znear);
-
- result.e[3][0] = -(right + left) / (right - left);
- result.e[3][1] = -(top + bottom) / (top - bottom);
- result.e[3][2] = -(zfar + znear) / (zfar - znear);
-
- return result;
-}
-
-DQN_FILE_SCOPE DqnMat4 DqnMat4_Perspective(f32 fov_y_degrees, f32 aspect_ratio, f32 znear, f32 zfar)
-{
- f32 fov_y_radians = DQN_DEGREES_TO_RADIANS(fov_y_degrees);
- f32 fov_y_radians_over_2 = fov_y_radians * 0.5f;
- f32 tan_fov_y_radians_over_2 = tanf(fov_y_radians_over_2);
- f32 znear_sub_zfar = znear - zfar;
-
- DqnMat4 result = DqnMat4_Identity();
- result.e[0][0] = 1.0f / (aspect_ratio * tan_fov_y_radians_over_2);
- result.e[1][1] = 1.0f / tan_fov_y_radians_over_2;
- result.e[2][2] = (znear + zfar) / znear_sub_zfar;
- result.e[2][3] = -1.0f;
- result.e[3][2] = (2.0f * znear * zfar) / znear_sub_zfar;
- result.e[3][3] = 0.0f;
-
- return result;
-}
-
-DQN_FILE_SCOPE DqnMat4 DqnMat4_LookAt(DqnV3 eye, DqnV3 center, DqnV3 up)
-{
- DqnMat4 result = {0, 0, 0, 0};
-
- DqnV3 f = DqnV3_Normalise(DqnV3_Sub(eye, center));
- DqnV3 s = DqnV3_Normalise(DqnV3_Cross(up, f));
- DqnV3 u = DqnV3_Cross(f, s);
-
- result.e[0][0] = s.x;
- result.e[0][1] = u.x;
- result.e[0][2] = -f.x;
-
- result.e[1][0] = s.y;
- result.e[1][1] = u.y;
- result.e[1][2] = -f.y;
-
- result.e[2][0] = s.z;
- result.e[2][1] = u.z;
- result.e[2][2] = -f.z;
-
- result.e[3][0] = -DqnV3_Dot(s, eye);
- result.e[3][1] = -DqnV3_Dot(u, eye);
- result.e[3][2] = DqnV3_Dot(f, eye);
- result.e[3][3] = 1.0f;
- return result;
-}
-
-DQN_FILE_SCOPE DqnMat4 DqnMat4_Translate3f(f32 x, f32 y, f32 z)
-{
- DqnMat4 result = DqnMat4_Identity();
- result.e[3][0] = x;
- result.e[3][1] = y;
- result.e[3][2] = z;
- return result;
-}
-
-DQN_FILE_SCOPE DqnMat4 DqnMat4_TranslateV3(DqnV3 vec)
-{
- DqnMat4 result = DqnMat4_Identity();
- result.e[3][0] = vec.x;
- result.e[3][1] = vec.y;
- result.e[3][2] = vec.z;
- return result;
-}
-
-DQN_FILE_SCOPE DqnMat4 DqnMat4_Rotate(f32 radians, f32 x, f32 y, f32 z)
-{
- DqnMat4 result = DqnMat4_Identity();
- f32 sin_val = sinf(radians);
- f32 cos_val = cosf(radians);
- f32 one_minux_cos_val = 1 - cos_val;
-
- DqnV3 axis = DqnV3_Normalise(DqnV3(x, y, z));
-
- result.e[0][0] = (axis.x * axis.x * one_minux_cos_val) + cos_val;
- result.e[0][1] = (axis.x * axis.y * one_minux_cos_val) + (axis.z * sin_val);
- result.e[0][2] = (axis.x * axis.z * one_minux_cos_val) - (axis.y * sin_val);
-
- result.e[1][0] = (axis.y * axis.x * one_minux_cos_val) - (axis.z * sin_val);
- result.e[1][1] = (axis.y * axis.y * one_minux_cos_val) + cos_val;
- result.e[1][2] = (axis.y * axis.z * one_minux_cos_val) + (axis.x * sin_val);
-
- result.e[2][0] = (axis.z * axis.x * one_minux_cos_val) + (axis.y * sin_val);
- result.e[2][1] = (axis.z * axis.y * one_minux_cos_val) - (axis.x * sin_val);
- result.e[2][2] = (axis.z * axis.z * one_minux_cos_val) + cos_val;
-
- return result;
-}
-
-DQN_FILE_SCOPE DqnMat4 DqnMat4_Scale(f32 x, f32 y, f32 z)
-{
- DqnMat4 result = {0, 0, 0, 0};
- result.e[0][0] = x;
- result.e[1][1] = y;
- result.e[2][2] = z;
- result.e[3][3] = 1;
- return result;
-}
-
-DQN_FILE_SCOPE DqnMat4 DqnMat4_ScaleV3(DqnV3 scale)
-{
- DqnMat4 result = {0, 0, 0, 0};
- result.e[0][0] = scale.x;
- result.e[1][1] = scale.y;
- result.e[2][2] = scale.z;
- result.e[3][3] = 1;
- return result;
-}
-
-DQN_FILE_SCOPE DqnMat4 DqnMat4_Mul(DqnMat4 a, DqnMat4 b)
-{
- DqnMat4 result = {0};
- for (u32 j = 0; j < 4; j++) {
- for (u32 i = 0; i < 4; i++)
- {
- result.e[j][i] = a.e[0][i] * b.e[j][0]
- + a.e[1][i] * b.e[j][1]
- + a.e[2][i] * b.e[j][2]
- + a.e[3][i] * b.e[j][3];
- }
- }
-
- return result;
-}
-
-DQN_FILE_SCOPE DqnV4 DqnMat4_MulV4(DqnMat4 a, DqnV4 b)
-{
- DqnV4 result = {0};
- result.x = (a.e[0][0] * b.x) + (a.e[1][0] * b.y) + (a.e[2][0] * b.z) + (a.e[3][0] * b.w);
- result.y = (a.e[0][1] * b.x) + (a.e[1][1] * b.y) + (a.e[2][1] * b.z) + (a.e[3][1] * b.w);
- result.z = (a.e[0][2] * b.x) + (a.e[1][2] * b.y) + (a.e[2][2] * b.z) + (a.e[3][2] * b.w);
- result.w = (a.e[0][3] * b.x) + (a.e[1][3] * b.y) + (a.e[2][3] * b.z) + (a.e[3][3] * b.w);
-
- return result;
-}
-
-// #DqnRect Implementation
-// =================================================================================================
-void DqnRect::GetSize(f32 *width, f32 *height) const
-{
- DQN_ASSERT(this->min <= this->max);
- if (width) *width = this->max.x - this->min.x;
- if (height) *height = this->max.y - this->min.y;
-}
-
-DqnV2 DqnRect::GetCenter() const
-{
- DQN_ASSERT(this->min <= this->max);
- f32 sumX = this->min.x + this->max.x;
- f32 sumY = this->min.y + this->max.y;
- DqnV2 result = DqnV2(sumX, sumY) * 0.5f;
- return result;
-}
-
-DqnRect DqnRect::ClipRect(DqnRect clip) const
-{
- DQN_ASSERT(this->min <= this->max);
- DQN_ASSERT(clip.min <= clip.max);
- DqnRect result = *this;
-
- if (clip.min.x > this->min.x && clip.min.x < this->max.x)
- {
- if (clip.min.y > this->min.y && clip.min.y < this->max.y)
- {
- result.min = clip.min;
- }
- else if (clip.max.y > this->min.y)
- {
- result.min.x = clip.min.x;
- }
- }
-
- if (clip.max.x > this->min.x && clip.max.x < this->max.x)
- {
- if (clip.max.y > this->min.y && clip.max.y < this->max.y)
- {
- result.max = clip.max;
- }
- else if (clip.min.y < this->max.y)
- {
- result.max.x = clip.max.x;
- }
- }
-
- return result;
-}
-
-DqnRect DqnRect::Move(DqnV2 shift) const
-{
- DQN_ASSERT(this->min <= this->max);
-
- DqnRect result;
- result.min = this->min + shift;
- result.max = this->max + shift;
- return result;
-}
-
-bool DqnRect::ContainsP(DqnV2 p) const
-{
- DQN_ASSERT(this->min <= this->max);
-
- bool outside_of_rect_x = false;
- if (p.x < this->min.x || p.x > this->max.w)
- outside_of_rect_x = true;
-
- bool outside_of_rect_y = false;
- if (p.y < this->min.y || p.y > this->max.h)
- outside_of_rect_y = true;
-
- if (outside_of_rect_x || outside_of_rect_y) return false;
-
- return true;
-}
-
-// #DqnChar Implementation
-// =================================================================================================
-DQN_FILE_SCOPE char DqnChar_ToLower(char c)
-{
- if (c >= 'A' && c <= 'Z')
- {
- i32 shift_offset = 'a' - 'A';
- return (c + (char)shift_offset);
- }
- return c;
-}
-
-DQN_FILE_SCOPE char DqnChar_ToUpper(char c)
-{
- if (c >= 'a' && c <= 'z')
- {
- i32 shift_offset = 'a' - 'A';
- return (c - (char)shift_offset);
- }
- return c;
-}
-
-DQN_FILE_SCOPE bool DqnChar_IsEndOfLine(char c)
-{
- bool result = (c == '\n');
- return result;
-}
-
-DQN_FILE_SCOPE bool DqnChar_IsWhitespace(char c)
-{
- bool result = (c == ' ' || c == '\r' || c == '\n' || c == '\t');
- return result;
-}
-
-DQN_FILE_SCOPE char *DqnChar_TrimWhitespaceAround(char const *src, i32 src_len, i32 *new_len)
-{
- if (!src) return nullptr;
- if (src_len < 0) return (char *)src;
-
- char const *start = src;
- char const *end = start + (src_len - 1);
- while(start[0] && DqnChar_IsWhitespace(start[0]))
- {
- start++;
- }
-
- i32 chars_skipped = (i32)(start - src);
- i32 updated_len = src_len - chars_skipped;
- if (updated_len <= 0)
- {
- if (new_len) *new_len = 0;
- return nullptr;
- }
-
- while(end[0] && DqnChar_IsWhitespace(end[0]))
- {
- end--;
- }
-
- chars_skipped = (i32)((src + src_len - 1) - end);
- updated_len = updated_len - chars_skipped;
-
- if (new_len) *new_len = updated_len;
- return (char *)start;
-}
-
-DQN_FILE_SCOPE bool DqnChar_IsDigit(char c)
-{
- if (c >= '0' && c <= '9') return true;
- return false;
-}
-
-DQN_FILE_SCOPE bool DqnChar_IsAlpha(char c)
-{
- if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) return true;
- return false;
-}
-
-DQN_FILE_SCOPE bool DqnChar_IsAlphaNum(char c)
-{
- if (DqnChar_IsAlpha(c) || DqnChar_IsDigit(c)) return true;
- return false;
-}
-
-DQN_FILE_SCOPE char *DqnChar_SkipWhitespace(char const *ptr)
-{
- while (ptr && (*ptr == ' ' || *ptr == '\r' || *ptr == '\n' || *ptr == '\t')) ptr++;
- return (char *)ptr;
-}
-
-DQN_FILE_SCOPE char *DqnChar_FindLastChar(char *ptr, char ch, i32 len, u32 *len_to_char)
-{
- for (i32 i = len - 1; i >= 0; i--)
- {
- if (ptr[i] == ch)
- {
- if (len_to_char) *len_to_char = (u32)len - i;
- return &ptr[i];
- }
- }
-
- return nullptr;
-}
-
-DQN_FILE_SCOPE char *Dqn_EatLine(char **input, int *line_len)
-{
- *input = DqnChar_SkipWhitespace(*input);
- char *result = *input;
-
- for (int rune_len = -1;; rune_len = -1)
- {
- u32 rune = 0;
- for (; rune_len != 0 && rune_len != 1; *input += rune_len)
- rune_len = DqnStr_ReadUTF8Codepoint(reinterpret_cast(*input), &rune);
-
- if (rune_len == 1)
- {
- if (rune == '\r' || rune == '\n')
- {
- char *ptr_to_rune = (*input - rune_len);
- *ptr_to_rune = 0;
- if (line_len) *line_len = static_cast(ptr_to_rune - result);
- return result;
- }
- }
- else if (rune_len == 0)
- {
- if (line_len) *line_len = static_cast(*input - result);
- *input = nullptr;
- return result;
- }
- }
-}
-
-DQN_FILE_SCOPE wchar_t *Dqn_EatLine(wchar_t **input, int *line_len)
-{
- *input = DqnWChar_SkipWhitespace(*input);
- wchar_t *result = *input;
-
- for (;; (*input)++)
- {
- if (!(*input))
- {
- if (line_len) *line_len = static_cast(*input - result);
- return result;
- }
-
- wchar_t ch = (*input)[0];
- if (ch == '\r' || ch == '\n')
- {
- (*input)[0] = 0;
- if (line_len) *line_len = static_cast(*input - result);
- (*input)++;
- return result;
- }
- }
-}
-
-// #DqnStr Implementation
-// =================================================================================================
-DQN_FILE_SCOPE i32 DqnStr_Cmp(char const *a, char const *b, i32 num_bytes_to_cmp, Dqn::IgnoreCase ignore)
-{
- if (!a || !b) return -1;
- if (!a) return -b[0];
- if (!b) return -a[0];
- if (num_bytes_to_cmp == 0) return 0;
-
- i32 bytes_cmped = 0;
- i32 result = 0;
- if (ignore == Dqn::IgnoreCase::Yes)
- {
- while (a[0] && (DqnChar_ToLower(a[0]) == DqnChar_ToLower(b[0])))
- {
- a++; b++;
- if (++bytes_cmped == num_bytes_to_cmp) return 0;
- }
- result = DqnChar_ToLower(a[0]) - DqnChar_ToLower(b[0]);
- }
- else
- {
- while (a[0] && (a[0] == b[0]))
- {
- a++; b++;
- if (++bytes_cmped == num_bytes_to_cmp) return 0;
- }
- result = a[0] - b[0];
- }
-
- return result;
-}
-
-DQN_FILE_SCOPE char *DqnStr_GetPtrToLastSlash(char const *str, i32 str_len)
-{
- char const *result = str;
- if (str_len == -1) str_len = DqnStr_Len(str);
-
- for (auto i = str_len - 1; i >= 0; i--)
- {
- if (result[i] == '\\' || result[i] == '/')
- {
- result = result + i + 1;
- break;
- }
- }
- return (char *)result;
-}
-
-DQN_FILE_SCOPE i32 DqnStr_Len(char const *a)
-{
- i32 result = 0;
- while (a && a[result]) result++;
- return result;
-}
-
-DQN_FILE_SCOPE i32 DqnStr_LenUTF8(u32 const *a, i32 *len_in_bytes)
-{
- i32 utf8_len = 0;
- i32 utf8_len_in_bytes = 0;
- u8 *byte_ptr = (u8 *)a;
- while (true)
- {
- u32 codepoint = 0;
- i32 num_bytes_in_codepoint = DqnStr_ReadUTF8Codepoint((u32 *)byte_ptr, &codepoint);
-
- if (num_bytes_in_codepoint == 0) break;
- utf8_len++;
- byte_ptr += num_bytes_in_codepoint;
- utf8_len_in_bytes += num_bytes_in_codepoint;
- }
-
- if (len_in_bytes) *len_in_bytes = utf8_len_in_bytes;
- return utf8_len;
-}
-
-DQN_FILE_SCOPE i32 DqnStr_LenDelimitWith(char const *a, char delimiter)
-{
- i32 result = 0;
- while (a && a[result] && a[result] != delimiter) result++;
- return result;
-}
-
-DQN_FILE_SCOPE i32 DqnStr_ReadUTF8Codepoint(u32 const *a, u32 *out_codepoint)
-{
- u8 *byte = (u8 *)a;
- if (a && byte[0])
- {
- i32 num_bytes_in_char = 0;
- u32 actual_char = 0;
-
- if (byte[0] <= 128)
- {
- actual_char = byte[0];
- num_bytes_in_char = 1;
- }
- else if ((byte[0] & 0xE0) == 0xC0)
- {
- // Header 110xxxxx 10xxxxxx
- actual_char = ((u32)(byte[0] & 0x3F) << 6)
- | ((u32)(byte[1] & 0x1F) << 0);
- num_bytes_in_char = 2;
- }
- else if ((byte[0] & 0xF0) == 0xE0)
- {
- // Header 1110xxxx 10xxxxxx 10xxxxxx
- actual_char = ((u32)(byte[0] & 0x0F) << 12)
- | ((u32)(byte[1] & 0x3F) << 6 )
- | ((u32)(byte[2] & 0x3F) << 0 );
- num_bytes_in_char = 3;
- }
- else if ((byte[0] & 0xF8) == 0xF0)
- {
- // Header 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
- actual_char = ((u32)(byte[0] & 0x07) << 18)
- | ((u32)(byte[1] & 0x3F) << 12)
- | ((u32)(byte[2] & 0x3F) << 6 )
- | ((u32)(byte[3] & 0x3F) << 0 );
- num_bytes_in_char = 4;
- }
- else
- {
- // NOTE: Malformed utf8 stream
- }
-
- if (out_codepoint) *out_codepoint = actual_char;
- return num_bytes_in_char;
- }
-
- return 0;
-}
-
-DQN_FILE_SCOPE void DqnStr_Reverse(char *buf, isize buf_size)
-{
- if (!buf) return;
- isize mid = buf_size / 2;
-
- for (isize i = 0; i < mid; i++)
- {
- char tmp = buf[i];
- buf[i] = buf[(buf_size - 1) - i];
- buf[(buf_size - 1) - i] = tmp;
- }
-}
-
-DQN_FILE_SCOPE bool DqnStr_EndsWith(char const *src, i32 src_len, char const *find, i32 find_len,
- Dqn::IgnoreCase ignore)
-{
- if (!src || !find || find_len < 0 || src_len < 0) return false;
-
- if (src_len < find_len)
- return false;
-
- char const *src_end = src + (src_len);
- char const *check_src_from = src_end - find_len;
-
- bool result = (DqnStr_Cmp(check_src_from, find, find_len, ignore) == 0);
- return result;
-}
-
-DQN_FILE_SCOPE i32 DqnStr_FindFirstOccurence(char const *src, i32 src_len,
- char const *find, i32 find_len, Dqn::IgnoreCase ignore)
-{
- if (!src || !find) return -1;
- if (src_len == 0 || find_len == 0) return -1;
- if (src_len < find_len) return -1;
-
- for (i32 index_in_src = 0; index_in_src < src_len; index_in_src++)
- {
- // NOTE: As we scan through, if the src string we index into becomes
- // shorter than the substring we're checking then the substring is not
- // contained in the src string.
- i32 remaining_len_in_src = src_len - index_in_src;
- if (remaining_len_in_src < find_len) break;
-
- const char *src_substr = src + index_in_src;
- if (DqnStr_Cmp(src_substr, find, find_len, ignore) == 0)
- {
- return index_in_src;
- }
- }
-
- // NOTE(doyle): We have early exit, if we reach here, then the substring was
- // not found.
- return -1;
-}
-
-DQN_FILE_SCOPE char *DqnStr_GetFirstOccurence(char const *src, i32 src_len, char const *find,
- i32 find_len, Dqn::IgnoreCase ignore)
-{
- i32 offset = DqnStr_FindFirstOccurence(src, src_len, find, find_len, ignore);
- if (offset == -1) return nullptr;
-
- char *result = (char *)(src + offset);
- return result;
-}
-
-DQN_FILE_SCOPE bool DqnStr_HasSubstring(char const *src, i32 src_len,
- char const *find, i32 find_len, Dqn::IgnoreCase ignore)
-{
- if (DqnStr_FindFirstOccurence(src, src_len, find, find_len, ignore) == -1)
- return false;
-
- return true;
-}
-
-DQN_FILE_SCOPE i32 Dqn_I64ToStr(i64 value, char *buf, i32 buf_size)
-{
- bool valid_buf = true;
- if (!buf || buf_size == 0) valid_buf = false;
-
- if (value == 0)
- {
- if (valid_buf)
- {
- buf[0] = '0';
- buf[1] = 0;
- }
-
- return 1;
- }
-
- i32 char_index = 0;
- bool negative = false;
- if (value < 0) negative = true;
-
- if (negative)
- {
- if (valid_buf) buf[char_index] = '-';
- char_index++;
- }
-
- bool last_digit_decremented = false;
- i64 val = DQN_ABS(value);
- if (val < 0)
- {
- // TODO(doyle): This will occur if we are checking the smallest number
- // possible in i64 since the range of negative numbers is one more than
- // it is for positives, so ABS will fail.
- last_digit_decremented = true;
- val = DQN_ABS(val - 1);
- DQN_ASSERT(val >= 0);
- }
-
- if (valid_buf)
- {
- if (last_digit_decremented)
- {
- i64 rem = (val % 10) + 1;
- buf[char_index++] = (u8)rem + '0';
- val /= 10;
- }
-
- while (val != 0 && char_index < buf_size)
- {
- i64 rem = val % 10;
- buf[char_index++] = (u8)rem + '0';
- val /= 10;
- }
-
- // NOTE(doyle): If string is negative, we only want to reverse starting
- // from the second character, so we don't put the negative sign at the
- // end
- if (negative)
- {
- DqnStr_Reverse(buf + 1, char_index - 1);
- }
- else
- {
- DqnStr_Reverse(buf, char_index);
- }
- }
- else
- {
- while (val != 0)
- {
- val /= 10;
- char_index++;
- }
- }
-
- buf[char_index] = 0;
- return char_index;
-}
-
-DQN_FILE_SCOPE i64 Dqn_StrToI64(char const *buf, i64 buf_size)
-{
- if (!buf || buf_size == 0) return 0;
-
- i64 index = 0;
- while (buf[index] == ' ')
- {
- index++;
- }
-
- bool is_minus = false;
- if (buf[index] == '-' || buf[index] == '+')
- {
- if (buf[index] == '-') is_minus = true;
- index++;
- }
- else if (!DqnChar_IsDigit(buf[index]))
- {
- return 0;
- }
-
- i64 result = 0;
- for (auto i = index; i < buf_size; i++)
- {
- if (DqnChar_IsDigit(buf[i]))
- {
- result *= 10;
- result += (buf[i] - '0');
- }
- else
- {
- break;
- }
- }
-
- if (is_minus) result *= -1;
-
- return result;
-}
-
-DQN_FILE_SCOPE f32 Dqn_StrToF32(char const *buf, i64 buf_size)
-{
- if (!buf || buf_size == 0) return 0;
-
- i64 index = 0;
- bool is_minus = false;
- if (buf[index] == '-')
- {
- index++;
- is_minus = true;
- }
-
- bool is_past_decimal = false;
- i64 num_digits_after_decimal = 0;
- i64 raw_num = 0;
-
- f32 digit_shift_val = 1.0f;
- f32 digit_shift_multiplier = 0.1f;
- for (auto i = index; i < buf_size; i++)
- {
- char ch = buf[i];
- if (ch == '.')
- {
- is_past_decimal = true;
- continue;
- }
- // Handle scientific notation
- else if (ch == 'e')
- {
- bool digit_shift_is_positive = true;
- if (i < buf_size)
- {
- if (buf[i + 1] == '-') digit_shift_is_positive = false;
- DQN_ASSERT(buf[i + 1] == '-' || buf[i + 1] == '+');
- i += 2;
- }
-
- i32 exponent_pow = 0;
- bool scientific_notation = false;
- while (i < buf_size)
- {
- scientific_notation = true;
- char exponent_char = buf[i];
- if (DqnChar_IsDigit(exponent_char))
- {
- exponent_pow *= 10;
- exponent_pow += (buf[i] - '0');
- }
- else
- {
- i = buf_size;
- }
-
- i++;
- }
-
- // NOTE(doyle): If exponent not specified but this branch occurred,
- // the float string has a malformed scientific notation in the
- // string, i.e. "e" followed by no number.
- DQN_ASSERT(scientific_notation);
-
- if (digit_shift_is_positive)
- {
- num_digits_after_decimal -= exponent_pow;
- }
- else
- {
- num_digits_after_decimal += exponent_pow;
- }
- }
- else if (DqnChar_IsDigit(ch))
- {
- num_digits_after_decimal += (i32)is_past_decimal;
- raw_num *= 10;
- raw_num += (ch - '0');
- }
- else
- {
- break;
- }
- }
-
- for (isize i = 0; i < num_digits_after_decimal; i++)
- digit_shift_val *= digit_shift_multiplier;
-
- f32 result = (f32)raw_num;
- if (num_digits_after_decimal > 0) result *= digit_shift_val;
- if (is_minus) result *= -1;
-
- return result;
-}
-
-/*
- Encoding
- The following byte sequences are used to represent a character. The sequence
- to be used depends on the UCS code number of the character:
-
- The extra 1's are the headers used to identify the string as a UTF-8 string.
- UCS [0x00000000, 0x0000007F] -> UTF-8 0xxxxxxx
- UCS [0x00000080, 0x000007FF] -> UTF-8 110xxxxx 10xxxxxx
- UCS [0x00000800, 0x0000FFFF] -> UTF-8 1110xxxx 10xxxxxx 10xxxxxx
- UCS [0x00010000, 0x001FFFFF] -> UTF-8 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
- UCS [0x00200000, 0x03FFFFFF] -> N/A 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
- UCS [0x04000000, 0x7FFFFFFF] -> N/A 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
-
- The xxx bit positions are filled with the bits of the character code number
- in binary representation. Only the shortest possible multibyte sequence
- which can represent the code number of the character can be used.
-
- The UCS code values 0xd800–0xdfff (UTF-16 surrogates) as well as 0xfffe and
- 0xffff (UCS noncharacters) should not appear in conforming UTF-8 streams.
-*/
-DQN_FILE_SCOPE u32 Dqn_UCSToUTF8(u32 *dest, u32 character)
-{
- if (!dest) return 0;
-
- u8 *byte_ptr = (u8 *)dest;
-
- // Character is within ASCII range, so it's an ascii character
- // UTF Bit Arrangement: 0xxxxxxx
- // Character : 0xxxxxxx
- if (character >= 0 && character < 0x80)
- {
- byte_ptr[0] = (u8)character;
- return 1;
- }
-
- // UTF Header Bits : 11000000 00xxxxxx
- // UTF Bit Arrangement: 000xxxxx 00xxxxxx
- // Character : 00000xxx xxxxxxxx
- if (character < 0x800)
- {
- // Add the 2nd byte, 6 bits, OR the 0xC0 (11000000) header bits
- byte_ptr[1] = (u8)((character >> 6) | 0xC0);
-
- // Add the 1st byte, 6 bits, plus the 0x80 (10000000) header bits
- byte_ptr[0] = (u8)((character & 0x3F) | 0x80);
-
- return 2;
- }
-
- // UTF Header Bits : 11100000 10000000 10000000
- // UTF Bit Arrangement : 0000xxxx 00xxxxxx 00xxxxxx
- // Character : 00000000 xxxxxxxx xxxxxxxx
- if (character < 0x10000)
- {
- // Add the 3rd byte, 4 bits, OR the 0xE0 (11100000) header bits
- byte_ptr[2] = (u8)((character >> 12) | 0xE0);
-
- // Add the 2nd byte, 6 bits, OR the 0x80 (10000000) header bits
- byte_ptr[1] = (u8)((character >> 6) | 0x80);
-
- // Add the 1st byte, 6 bits, plus the 0x80 (10000000) header bits
- byte_ptr[0] = (u8)((character & 0x3F) | 0x80);
-
- return 3;
- }
-
- // UTF Header Bits : 11110000 10000000 10000000 10000000
- // UTF Bit Arrangement : 00000xxx 00xxxxxx 00xxxxxx 00xxxxxx
- // Character : 00000000 00000xxx xxxxxxxx xxxxxxxx
- if (character < 0x110000)
- {
- // Add the 4th byte, 3 bits, OR the 0xF0 (11110000) header bits
- byte_ptr[3] = (u8)((character >> 18) | 0xF0);
-
- // Add the 3rd byte, 6 bits, OR the 0x80 (10000000) header bits
- byte_ptr[2] = (u8)(((character >> 12) & 0x3F) | 0x80);
-
- // Add the 2nd byte, 6 bits, plus the 0x80 (10000000) header bits
- byte_ptr[1] = (u8)(((character >> 6) & 0x3F) | 0x80);
-
- // Add the 2nd byte, 6 bits, plus the 0x80 (10000000) header bits
- byte_ptr[0] = (u8)((character & 0x3F) | 0x80);
-
- return 4;
- }
-
- return 0;
-}
-
-DQN_FILE_SCOPE u32 Dqn_UTF8ToUCS(u32 *dest, u32 character)
-{
- if (!dest) return 0;
-
- const u32 HEADER_BITS_4_BYTES = 0xF0808080u;
- const u32 HEADER_BITS_3_BYTES = 0xE08080u;
- const u32 HEADER_BITS_2_BYTES = 0xC000u;
- const u32 HEADER_BITS_1_BYTE = 0x80u;
-
- // UTF Header Bits : 11110000 10000000 10000000 10000000
- // UTF Bit Arrangement : 00000xxx 00xxxxxx 00xxxxxx 00xxxxxx
- // UCS : 00000000 00000xxx xxxxxxxx xxxxxxxx
- if ((character & HEADER_BITS_4_BYTES) == HEADER_BITS_4_BYTES)
- {
- u32 utf_without_header = HEADER_BITS_4_BYTES ^ character;
-
- u32 first_byte = utf_without_header & 0x3F;
- u32 second_byte = (utf_without_header >> 8) & 0x3F;
- u32 third_byte = (utf_without_header >> 16) & 0x3F;
- u32 fourth_byte = utf_without_header >> 24;
-
- u32 result =
- (fourth_byte << 18 | third_byte << 12 | second_byte << 6 | first_byte);
- *dest = result;
-
- return 4;
- }
-
- // UTF Header Bits : 11100000 10000000 10000000
- // UTF Bit Arrangement : 0000xxxx 00xxxxxx 00xxxxxx
- // UCS : 00000000 xxxxxxxx xxxxxxxx
- if ((character & HEADER_BITS_3_BYTES) == HEADER_BITS_3_BYTES)
- {
- u32 utf_without_header = HEADER_BITS_3_BYTES ^ character;
-
- u32 first_byte = utf_without_header & 0x3F;
- u32 second_byte = (utf_without_header >> 8) & 0x3F;
- u32 third_byte = utf_without_header >> 16;
-
- u32 result = (third_byte << 12 | second_byte << 6 | first_byte);
- *dest = result;
-
- return 3;
- }
-
- // UTF Header Bits : 11000000 00xxxxxx
- // UTF Bit Arrangement: 000xxxxx 00xxxxxx
- // UCS : 00000xxx xxxxxxxx
- if ((character & HEADER_BITS_2_BYTES) == HEADER_BITS_2_BYTES)
- {
- u32 utf_without_header = HEADER_BITS_2_BYTES ^ character;
-
- u32 first_byte = utf_without_header & 0x3F;
- u32 second_byte = utf_without_header >> 8;
-
- u32 result = (second_byte << 6 | first_byte);
- *dest = result;
-
- return 2;
- }
-
- // Character is within ASCII range, so it's an ascii character
- // UTF Bit Arrangement: 0xxxxxxx
- // UCS : 0xxxxxxx
- if ((character & HEADER_BITS_1_BYTE) == 0)
- {
- u32 first_byte = (character & 0x3F);
- *dest = first_byte;
-
- return 1;
- }
-
- return 0;
-}
-
-DQN_FILE_SCOPE DqnSlice DqnStr_RemoveLeadTrailChar(char const *str, i32 str_len, char lead_char, char trail_char)
-{
- str = DqnChar_TrimWhitespaceAround(str, str_len, &str_len);
-
- if (str[0] == lead_char)
- {
- str++;
- str_len--;
- }
-
- if (str[str_len - 1] == trail_char)
- {
- str_len--;
- }
-
- str = DqnChar_TrimWhitespaceAround(str, str_len, &str_len);
- DqnSlice result = {(char *)str, str_len};
- return result;
-}
-
-DQN_FILE_SCOPE inline DqnSlice DqnStr_RemoveLeadTrailBraces(char const *str, i32 str_len)
-{
- DqnSlice result = DqnStr_RemoveLeadTrailChar(str, str_len, '{', '}');
- return result;
-}
-
-DQN_FILE_SCOPE inline DqnSlice DqnStr_RemoveLeadTrailQuotes(char const *str, i32 str_len)
-{
- DqnSlice result = DqnStr_RemoveLeadTrailChar(str, str_len, '"', '"');
- return result;
-}
-
-DQN_FILE_SCOPE inline DqnSlice DqnStr_RemoveLeadTrailBraces(DqnSlice slice)
-{
- DqnSlice result = DqnStr_RemoveLeadTrailBraces(slice.data, slice.len);
- return result;
-}
-
-DQN_FILE_SCOPE inline DqnSlice