store level files in textual format
This commit is contained in:
parent
1c042f1c11
commit
a00fcf3fba
Binary file not shown.
Binary file not shown.
@ -787,8 +787,6 @@ i64 BB_IntFromTwosCompliment(u64 tc, u8 num_bits)
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Test
|
//~ Test
|
||||||
|
|
||||||
#if BITBUFF_TEST
|
|
||||||
|
|
||||||
void BB_Test(void)
|
void BB_Test(void)
|
||||||
{
|
{
|
||||||
TempArena scratch = BeginScratchNoConflict();
|
TempArena scratch = BeginScratchNoConflict();
|
||||||
@ -937,5 +935,3 @@ void BB_Test(void)
|
|||||||
|
|
||||||
EndScratch(scratch);
|
EndScratch(scratch);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|||||||
@ -187,6 +187,4 @@ i64 BB_IntFromTwosCompliment(u64 tc, u8 num_bits);
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Test
|
//~ Test
|
||||||
|
|
||||||
#if BITBUFF_TEST
|
|
||||||
void BB_Test(void);
|
void BB_Test(void);
|
||||||
#endif
|
|
||||||
|
|||||||
444
src/base/base_crum.c
Normal file
444
src/base/base_crum.c
Normal file
@ -0,0 +1,444 @@
|
|||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//~ Value conversion utilities
|
||||||
|
|
||||||
|
i64 CR_IntFromString(String str)
|
||||||
|
{
|
||||||
|
i64 result = 0;
|
||||||
|
|
||||||
|
b32 ok = 1;
|
||||||
|
b32 is_hex = 0;
|
||||||
|
|
||||||
|
u64 pos = 0;
|
||||||
|
if (StringBeginsWith(str, Lit("0x")))
|
||||||
|
{
|
||||||
|
pos += 2;
|
||||||
|
is_hex = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Eat sign
|
||||||
|
i32 sign = 1;
|
||||||
|
if (ok && !is_hex)
|
||||||
|
{
|
||||||
|
if (pos < str.len)
|
||||||
|
{
|
||||||
|
if (str.text[pos] == '-')
|
||||||
|
{
|
||||||
|
sign = -1;
|
||||||
|
pos += 1;
|
||||||
|
}
|
||||||
|
else if (str.text[pos] == '+')
|
||||||
|
{
|
||||||
|
pos += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse number
|
||||||
|
while (ok && pos < str.len)
|
||||||
|
{
|
||||||
|
u8 c = str.text[pos];
|
||||||
|
u8 digit = 0;
|
||||||
|
if (c >= '0' && c <= '9')
|
||||||
|
{
|
||||||
|
digit = c - '0';
|
||||||
|
}
|
||||||
|
else if (is_hex)
|
||||||
|
{
|
||||||
|
if (c >= 'a' && c <= 'f')
|
||||||
|
{
|
||||||
|
digit = 10 + c - 'a';
|
||||||
|
}
|
||||||
|
else if (c >= 'A' && c <= 'F')
|
||||||
|
{
|
||||||
|
digit = 10 + c - 'A';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ok = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ok = 0;
|
||||||
|
}
|
||||||
|
pos += 1;
|
||||||
|
result += digit * PowU64(10 + is_hex * 6, str.len - pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ok)
|
||||||
|
{
|
||||||
|
result *= sign;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Handle hexadecimal
|
||||||
|
f64 CR_FloatFromString(String str)
|
||||||
|
{
|
||||||
|
f64 result = 0;
|
||||||
|
|
||||||
|
b32 ok = 1;
|
||||||
|
|
||||||
|
// Eat sign
|
||||||
|
u64 whole_start_idx = 0;
|
||||||
|
i32 sign = 1;
|
||||||
|
if (ok && str.len > 0)
|
||||||
|
{
|
||||||
|
if (whole_start_idx < str.len)
|
||||||
|
{
|
||||||
|
u8 c = str.text[whole_start_idx];
|
||||||
|
if (c == '-')
|
||||||
|
{
|
||||||
|
sign = -1;
|
||||||
|
whole_start_idx += 1;
|
||||||
|
}
|
||||||
|
else if (c == '+')
|
||||||
|
{
|
||||||
|
whole_start_idx += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find decimal place
|
||||||
|
u64 frac_start_idx = whole_start_idx;
|
||||||
|
for (; ok && frac_start_idx < str.len; ++frac_start_idx)
|
||||||
|
{
|
||||||
|
u8 c = str.text[frac_start_idx];
|
||||||
|
if (c == '.')
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse whole part
|
||||||
|
u64 whole_part = 0;
|
||||||
|
for (u64 char_idx = whole_start_idx; ok && char_idx < frac_start_idx; ++char_idx)
|
||||||
|
{
|
||||||
|
u8 c = str.text[char_idx];
|
||||||
|
if (c >= '0' && c <= '9')
|
||||||
|
{
|
||||||
|
u8 digit = c - '0';
|
||||||
|
whole_part += digit * PowU64(10, frac_start_idx - (char_idx + 1));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ok = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse frac part
|
||||||
|
u64 frac_part = 0;
|
||||||
|
for (u64 char_idx = frac_start_idx + 1; ok && char_idx < str.len; ++char_idx)
|
||||||
|
{
|
||||||
|
u8 c = str.text[char_idx];
|
||||||
|
if (c >= '0' && c <= '9')
|
||||||
|
{
|
||||||
|
u8 digit = c - '0';
|
||||||
|
frac_part += digit * PowU64(10, str.len - (char_idx + 1));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ok = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ok)
|
||||||
|
{
|
||||||
|
if (frac_part != 0)
|
||||||
|
{
|
||||||
|
result = ((f64)whole_part + ((f64)frac_part / PowU64(10, str.len - (frac_start_idx + 1)))) * sign;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = (f64)whole_part * sign;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
b32 CR_BoolFromString(String str)
|
||||||
|
{
|
||||||
|
return MatchString(str, Lit("true"));
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec4 CR_Vec4FromString(String str)
|
||||||
|
{
|
||||||
|
Vec4 result = Zi;
|
||||||
|
|
||||||
|
b32 ok = 1;
|
||||||
|
|
||||||
|
if (StringBeginsWith(str, Lit("(")))
|
||||||
|
{
|
||||||
|
str.text += 1;
|
||||||
|
str.len -= 1;
|
||||||
|
}
|
||||||
|
if (StringEndsWith(str, Lit(")")))
|
||||||
|
{
|
||||||
|
str.len -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 pos = 0;
|
||||||
|
u64 parts_found = 0;
|
||||||
|
String part = Zi;
|
||||||
|
part.text = str.text;
|
||||||
|
while (pos < str.len && parts_found < 4)
|
||||||
|
{
|
||||||
|
u8 c = str.text[pos];
|
||||||
|
if (c == ',' || c == ')' || pos + 1 >= str.len)
|
||||||
|
{
|
||||||
|
part.len = (str.text + pos) - part.text;
|
||||||
|
f64 part_float = CR_FloatFromString(part);
|
||||||
|
result.v[parts_found] = part_float;
|
||||||
|
parts_found += 1;
|
||||||
|
part.text = str.text + pos + 2;
|
||||||
|
pos += 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pos += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec3 CR_Vec3FromString(String str)
|
||||||
|
{
|
||||||
|
Vec4 v4 = CR_Vec4FromString(str);
|
||||||
|
Vec3 result = Zi;
|
||||||
|
result.x = v4.x;
|
||||||
|
result.y = v4.y;
|
||||||
|
result.z = v4.z;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec2 CR_Vec2FromString(String str)
|
||||||
|
{
|
||||||
|
Vec4 v4 = CR_Vec4FromString(str);
|
||||||
|
Vec2 result = Zi;
|
||||||
|
result.x = v4.x;
|
||||||
|
result.y = v4.y;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//~ Parse
|
||||||
|
|
||||||
|
CR_Item *CR_ItemFromString(Arena *arena, String str)
|
||||||
|
{
|
||||||
|
CR_Item *result = PushStruct(arena, CR_Item);
|
||||||
|
TempArena scratch = BeginScratch(arena);
|
||||||
|
|
||||||
|
Enum(Mode)
|
||||||
|
{
|
||||||
|
Mode_None,
|
||||||
|
|
||||||
|
Mode_Text,
|
||||||
|
Mode_SingleLineComment,
|
||||||
|
Mode_MultiLineComment,
|
||||||
|
};
|
||||||
|
Mode mode = Mode_None;
|
||||||
|
|
||||||
|
Struct(ItemNode)
|
||||||
|
{
|
||||||
|
ItemNode *next;
|
||||||
|
CR_Item *item;
|
||||||
|
};
|
||||||
|
// TODO: Reuse these
|
||||||
|
ItemNode *top_item = PushStruct(scratch.arena, ItemNode);
|
||||||
|
top_item->item = result;
|
||||||
|
|
||||||
|
CR_Item *cur_item = 0;
|
||||||
|
|
||||||
|
i64 text_start = 0;
|
||||||
|
b32 text_is_string = 0;
|
||||||
|
b32 text_has_name = 0;
|
||||||
|
|
||||||
|
i64 pos = 0;
|
||||||
|
b32 is_escaped = 0;
|
||||||
|
while (pos < (i64)str.len)
|
||||||
|
{
|
||||||
|
u8 c = str.text[pos];
|
||||||
|
u8 next_c = 0;
|
||||||
|
if (pos + 1 < (i64)str.len)
|
||||||
|
{
|
||||||
|
next_c = str.text[pos + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
b32 is_eol = c == '\n' || c == '\r' || c == 0;
|
||||||
|
b32 is_whitespace = c == ' ' || c == '\t' || is_eol;
|
||||||
|
|
||||||
|
b32 next_is_eol = next_c == '\n' || next_c == '\r' || next_c == 0;
|
||||||
|
b32 next_is_whitespace = next_c == ' ' || next_c == '\t' || next_is_eol;
|
||||||
|
|
||||||
|
switch (mode)
|
||||||
|
{
|
||||||
|
case Mode_None:
|
||||||
|
{
|
||||||
|
if (c == '/' && next_c == '/')
|
||||||
|
{
|
||||||
|
mode = Mode_SingleLineComment;
|
||||||
|
pos += 2;
|
||||||
|
}
|
||||||
|
else if (c == '/' && next_c == '*')
|
||||||
|
{
|
||||||
|
mode = Mode_MultiLineComment;
|
||||||
|
pos += 2;
|
||||||
|
}
|
||||||
|
else if (!is_whitespace)
|
||||||
|
{
|
||||||
|
mode = Mode_Text;
|
||||||
|
text_is_string = 0;
|
||||||
|
text_start = pos;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pos += 1;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case Mode_Text:
|
||||||
|
{
|
||||||
|
i64 text_end = -1;
|
||||||
|
b32 is_name = 0;
|
||||||
|
if (is_escaped)
|
||||||
|
{
|
||||||
|
is_escaped = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (c == '\\')
|
||||||
|
{
|
||||||
|
is_escaped = 1;
|
||||||
|
}
|
||||||
|
else if (c == '\"')
|
||||||
|
{
|
||||||
|
if (pos == text_start)
|
||||||
|
{
|
||||||
|
text_is_string = 1;
|
||||||
|
text_start = pos + 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
text_end = pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (next_c == ':')
|
||||||
|
{
|
||||||
|
text_end = pos + 1;
|
||||||
|
is_name = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!text_is_string && next_is_whitespace)
|
||||||
|
{
|
||||||
|
text_end = pos + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (text_end != -1)
|
||||||
|
{
|
||||||
|
if (!cur_item)
|
||||||
|
{
|
||||||
|
cur_item = PushStruct(arena, CR_Item);
|
||||||
|
cur_item->parent = top_item->item;
|
||||||
|
DllQueuePush(cur_item->parent->first, cur_item->parent->last, cur_item);
|
||||||
|
cur_item->parent->count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
is_escaped = 0;
|
||||||
|
text_is_string = 0;
|
||||||
|
|
||||||
|
String src_text = Zi;
|
||||||
|
if (text_end > text_start)
|
||||||
|
{
|
||||||
|
src_text.len = text_end - text_start;
|
||||||
|
src_text.text = str.text + text_start;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_name)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: Arrays always have an item even if empty
|
||||||
|
|
||||||
|
if (MatchString(src_text, Lit("{")))
|
||||||
|
{
|
||||||
|
ItemNode *n = PushStruct(scratch.arena, ItemNode);
|
||||||
|
n->item = cur_item;
|
||||||
|
SllStackPush(top_item, n);
|
||||||
|
pos += 1;
|
||||||
|
cur_item = 0;
|
||||||
|
}
|
||||||
|
else if (MatchString(src_text, Lit("}")))
|
||||||
|
{
|
||||||
|
SllStackPop(top_item);
|
||||||
|
pos += 1;
|
||||||
|
cur_item = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// FIXME: Resolve escape sequences
|
||||||
|
String final_text = PushString(arena, src_text);
|
||||||
|
|
||||||
|
if (is_name)
|
||||||
|
{
|
||||||
|
cur_item->name = final_text;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cur_item->value = final_text;
|
||||||
|
cur_item = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_name)
|
||||||
|
{
|
||||||
|
pos += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
mode = Mode_None;
|
||||||
|
}
|
||||||
|
|
||||||
|
pos += 1;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case Mode_SingleLineComment:
|
||||||
|
{
|
||||||
|
if (is_eol)
|
||||||
|
{
|
||||||
|
mode = Mode_None;
|
||||||
|
}
|
||||||
|
pos += 1;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case Mode_MultiLineComment:
|
||||||
|
{
|
||||||
|
if (!is_escaped && c == '*' && next_c == '/')
|
||||||
|
{
|
||||||
|
mode = Mode_None;
|
||||||
|
pos += 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pos += 1;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
EndScratch(scratch);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
30
src/base/base_crum.h
Normal file
30
src/base/base_crum.h
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//~ Item types
|
||||||
|
|
||||||
|
Struct(CR_Item)
|
||||||
|
{
|
||||||
|
CR_Item *parent;
|
||||||
|
CR_Item *next;
|
||||||
|
CR_Item *prev;
|
||||||
|
CR_Item *first;
|
||||||
|
CR_Item *last;
|
||||||
|
i64 count;
|
||||||
|
|
||||||
|
String name;
|
||||||
|
String value;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//~ Value conversion utilities
|
||||||
|
|
||||||
|
i64 CR_IntFromString(String str);
|
||||||
|
f64 CR_FloatFromString(String str);
|
||||||
|
b32 CR_BoolFromString(String str);
|
||||||
|
Vec4 CR_Vec4FromString(String str);
|
||||||
|
Vec3 CR_Vec3FromString(String str);
|
||||||
|
Vec2 CR_Vec2FromString(String str);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//~ Parse
|
||||||
|
|
||||||
|
CR_Item *CR_ItemFromString(Arena *arena, String str);
|
||||||
@ -25,6 +25,7 @@
|
|||||||
#include "base_resource.h"
|
#include "base_resource.h"
|
||||||
#include "base_controller.h"
|
#include "base_controller.h"
|
||||||
#include "base_async.h"
|
#include "base_async.h"
|
||||||
|
#include "base_crum.h"
|
||||||
#include "base_tweak.h"
|
#include "base_tweak.h"
|
||||||
#include "base_state.h"
|
#include "base_state.h"
|
||||||
#elif IsLanguageG
|
#elif IsLanguageG
|
||||||
@ -47,6 +48,7 @@
|
|||||||
#include "base_bitbuff.c"
|
#include "base_bitbuff.c"
|
||||||
#include "base_resource.c"
|
#include "base_resource.c"
|
||||||
#include "base_controller.c"
|
#include "base_controller.c"
|
||||||
|
#include "base_crum.c"
|
||||||
#include "base_async.c"
|
#include "base_async.c"
|
||||||
#include "base_state.c"
|
#include "base_state.c"
|
||||||
#else
|
#else
|
||||||
|
|||||||
@ -20,7 +20,7 @@ String StringFromChar(Arena *arena, char c)
|
|||||||
String StringFromUint(Arena *arena, u64 n, u64 base, u64 zfill)
|
String StringFromUint(Arena *arena, u64 n, u64 base, u64 zfill)
|
||||||
{
|
{
|
||||||
// Base too large
|
// Base too large
|
||||||
Assert(base <= (countof(IntChars) - 1));
|
Assert(base <= (countof(Base16Chars) - 1));
|
||||||
String result = Zi;
|
String result = Zi;
|
||||||
TempArena scratch = BeginScratch(arena);
|
TempArena scratch = BeginScratch(arena);
|
||||||
{
|
{
|
||||||
@ -28,7 +28,7 @@ String StringFromUint(Arena *arena, u64 n, u64 base, u64 zfill)
|
|||||||
u8 *backwards_text = ArenaNext(scratch.arena, u8);
|
u8 *backwards_text = ArenaNext(scratch.arena, u8);
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
StringFromChar(scratch.arena, IntChars[n % base]);
|
StringFromChar(scratch.arena, Base16Chars[n % base]);
|
||||||
++result.len;
|
++result.len;
|
||||||
n /= base;
|
n /= base;
|
||||||
} while (n > 0);
|
} while (n > 0);
|
||||||
@ -213,104 +213,6 @@ String StringFromUid(Arena *arena, Uid uid)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Parsing helpers
|
|
||||||
|
|
||||||
b32 BoolFromString(String str)
|
|
||||||
{
|
|
||||||
b32 result = 0;
|
|
||||||
result = MatchString(str, Lit("true"));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
f64 FloatFromString(String str)
|
|
||||||
{
|
|
||||||
f64 result = 0;
|
|
||||||
|
|
||||||
b32 ok = 1;
|
|
||||||
|
|
||||||
// Eat sign
|
|
||||||
u64 whole_start_idx = 0;
|
|
||||||
i32 sign = 1;
|
|
||||||
if (ok && str.len > 0)
|
|
||||||
{
|
|
||||||
if (whole_start_idx < str.len)
|
|
||||||
{
|
|
||||||
u8 c = str.text[whole_start_idx];
|
|
||||||
if (c == '-')
|
|
||||||
{
|
|
||||||
sign = -1;
|
|
||||||
whole_start_idx += 1;
|
|
||||||
}
|
|
||||||
else if (c == '+')
|
|
||||||
{
|
|
||||||
whole_start_idx += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find decimal place
|
|
||||||
u64 frac_start_idx = whole_start_idx;
|
|
||||||
for (; ok && frac_start_idx < str.len; ++frac_start_idx)
|
|
||||||
{
|
|
||||||
u8 c = str.text[frac_start_idx];
|
|
||||||
if (c == '.')
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse whole part
|
|
||||||
u64 whole_part = 0;
|
|
||||||
for (u64 char_idx = whole_start_idx; ok && char_idx < frac_start_idx; ++char_idx)
|
|
||||||
{
|
|
||||||
u8 c = str.text[char_idx];
|
|
||||||
if (c >= '0' && c <= '9')
|
|
||||||
{
|
|
||||||
u8 digit = c - '0';
|
|
||||||
whole_part += digit * PowU64(10, frac_start_idx - (char_idx + 1));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ok = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse frac part
|
|
||||||
u64 frac_part = 0;
|
|
||||||
for (u64 char_idx = frac_start_idx + 1; ok && char_idx < str.len; ++char_idx)
|
|
||||||
{
|
|
||||||
u8 c = str.text[char_idx];
|
|
||||||
if (c >= '0' && c <= '9')
|
|
||||||
{
|
|
||||||
u8 digit = c - '0';
|
|
||||||
frac_part += digit * PowU64(10, str.len - (char_idx + 1));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ok = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ok)
|
|
||||||
{
|
|
||||||
if (frac_part != 0)
|
|
||||||
{
|
|
||||||
result = ((f64)whole_part + ((f64)frac_part / PowU64(10, str.len - (frac_start_idx + 1)))) * sign;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
result = (f64)whole_part * sign;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
result = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ String helpers
|
//~ String helpers
|
||||||
|
|
||||||
@ -653,12 +555,12 @@ String TrimWhitespace(String s)
|
|||||||
b32 stop = 0;
|
b32 stop = 0;
|
||||||
while (!stop)
|
while (!stop)
|
||||||
{
|
{
|
||||||
if (StringBeginsWith(s, Lit("\n")) || StringBeginsWith(s, Lit("\r")) || StringBeginsWith(s, Lit(" ")))
|
if (StringBeginsWith(s, Lit(" ")) || StringBeginsWith(s, Lit("\t")) || StringBeginsWith(s, Lit("\n")) || StringBeginsWith(s, Lit("\r")))
|
||||||
{
|
{
|
||||||
s.text += 1;
|
s.text += 1;
|
||||||
s.len -= 1;
|
s.len -= 1;
|
||||||
}
|
}
|
||||||
else if (StringEndsWith(s, Lit("\n")) || StringEndsWith(s, Lit("\r")) || StringEndsWith(s, Lit(" ")))
|
else if (StringEndsWith(s, Lit(" ")) || StringEndsWith(s, Lit("\t")) || StringEndsWith(s, Lit("\n")) || StringEndsWith(s, Lit("\r")))
|
||||||
{
|
{
|
||||||
s.len -= 1;
|
s.len -= 1;
|
||||||
}
|
}
|
||||||
@ -1057,6 +959,67 @@ String32 String32FromString(Arena *arena, String str8)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//~ Base64
|
||||||
|
|
||||||
|
u64 Base64LenFromStringLen(u64 len)
|
||||||
|
{
|
||||||
|
return (len * 4 + 2) / 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 StringLenFromBase64Len(u64 len)
|
||||||
|
{
|
||||||
|
return len * 3 / 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
String Base64FromString(Arena *arena, String str)
|
||||||
|
{
|
||||||
|
String result = Zi;
|
||||||
|
PERSIST Readonly u8 to_base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
||||||
|
result.len = Base64LenFromStringLen(str.len);
|
||||||
|
result.text = PushStructsNoZero(arena, u8, result.len);
|
||||||
|
u64 src_byte_pos = 0;
|
||||||
|
u64 out_byte_pos = 0;
|
||||||
|
while (src_byte_pos < str.len)
|
||||||
|
{
|
||||||
|
u32 chunk = 0;
|
||||||
|
chunk |= str.text[src_byte_pos] << 16;
|
||||||
|
if (src_byte_pos + 1 < str.len) chunk |= str.text[src_byte_pos + 1] << 8;
|
||||||
|
if (src_byte_pos + 2 < str.len) chunk |= str.text[src_byte_pos + 2] << 0;
|
||||||
|
result.text[out_byte_pos + 0] = to_base64[(chunk >> 18) & 0x3F];
|
||||||
|
result.text[out_byte_pos + 1] = to_base64[(chunk >> 12) & 0x3F];
|
||||||
|
result.text[out_byte_pos + 2] = to_base64[(chunk >> 6) & 0x3F];
|
||||||
|
result.text[out_byte_pos + 3] = to_base64[(chunk >> 0) & 0x3F];
|
||||||
|
src_byte_pos += 3;
|
||||||
|
out_byte_pos += 4;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
String StringFromBase64(Arena *arena, String str)
|
||||||
|
{
|
||||||
|
String result = Zi;
|
||||||
|
result.len = StringLenFromBase64Len(str.len);
|
||||||
|
result.text = PushStructsNoZero(arena, u8, result.len);
|
||||||
|
PERSIST Readonly u8 from_base64[256] = {['A']=0,['B']=1,['C']=2,['D']=3,['E']=4,['F']=5,['G']=6,['H']=7,['I']=8,['J']=9,['K']=10,['L']=11,['M']=12,['N']=13,['O']=14,['P']=15,['Q']=16,['R']=17,['S']=18,['T']=19,['U']=20,['V']=21,['W']=22,['X']=23,['Y']=24,['Z']=25,['a']=26,['b']=27,['c']=28,['d']=29,['e']=30,['f']=31,['g']=32,['h']=33,['i']=34,['j']=35,['k']=36,['l']=37,['m']=38,['n']=39,['o']=40,['p']=41,['q']=42,['r']=43,['s']=44,['t']=45,['u']=46,['v']=47,['w']=48,['x']=49,['y']=50,['z']=51,['0']=52,['1']=53,['2']=54,['3']=55,['4']=56,['5']=57,['6']=58,['7']=59,['8']=60,['9']=61,['-']=62,['_']=63};
|
||||||
|
u64 src_byte_pos = 0;
|
||||||
|
u64 out_byte_pos = 0;
|
||||||
|
while (src_byte_pos < str.len)
|
||||||
|
{
|
||||||
|
u32 chunk = 0;
|
||||||
|
chunk |= (from_base64[str.text[src_byte_pos + 0]]) << 18;
|
||||||
|
chunk |= (from_base64[str.text[src_byte_pos + 1]]) << 12;
|
||||||
|
chunk |= (from_base64[str.text[src_byte_pos + 2]]) << 6;
|
||||||
|
chunk |= (from_base64[str.text[src_byte_pos + 3]]) << 0;
|
||||||
|
result.text[out_byte_pos + 0] = (chunk >> 16) & 0xFF;
|
||||||
|
result.text[out_byte_pos + 1] = (chunk >> 8) & 0xFF;
|
||||||
|
result.text[out_byte_pos + 2] = (chunk >> 0) & 0xFF;
|
||||||
|
src_byte_pos += 4;
|
||||||
|
out_byte_pos += 3;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Null-terminated strings
|
//~ Null-terminated strings
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
//~ Formatting types
|
//~ Formatting types
|
||||||
|
|
||||||
#define DefaultFmtPrecision 3
|
#define DefaultFmtPrecision 3
|
||||||
#define IntChars ("0123456789abcdef")
|
#define Base16Chars ("0123456789abcdef")
|
||||||
|
|
||||||
Enum(FmtArgKind)
|
Enum(FmtArgKind)
|
||||||
{
|
{
|
||||||
@ -84,12 +84,6 @@ String StringFromPtr(Arena *arena, void *ptr);
|
|||||||
String StringFromhandle(Arena *arena, u64 v);
|
String StringFromhandle(Arena *arena, u64 v);
|
||||||
String StringFromUid(Arena *arena, Uid uid);
|
String StringFromUid(Arena *arena, Uid uid);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Parsing helpers
|
|
||||||
|
|
||||||
b32 BoolFromString(String str);
|
|
||||||
f64 FloatFromString(String str);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ String helpers
|
//~ String helpers
|
||||||
|
|
||||||
@ -173,6 +167,15 @@ String StringFromString32(Arena *arena, String32 str32);
|
|||||||
String16 String16FromString(Arena *arena, String str8);
|
String16 String16FromString(Arena *arena, String str8);
|
||||||
String32 String32FromString(Arena *arena, String str8);
|
String32 String32FromString(Arena *arena, String str8);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//~ Base64
|
||||||
|
|
||||||
|
u64 Base64LenFromStringLen(u64 len);
|
||||||
|
u64 StringLenFromBase64Len(u64 len);
|
||||||
|
|
||||||
|
String Base64FromString(Arena *arena, String str);
|
||||||
|
String StringFromBase64(Arena *arena, String str);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Null-terminated strings
|
//~ Null-terminated strings
|
||||||
|
|
||||||
|
|||||||
@ -110,7 +110,7 @@ b32 TweakBool_(String name, b32 initial, TweakBoolDesc desc)
|
|||||||
var.initial = initial_str;
|
var.initial = initial_str;
|
||||||
}
|
}
|
||||||
String tweak_str = TweakEx(scratch.arena, var, 0);
|
String tweak_str = TweakEx(scratch.arena, var, 0);
|
||||||
result = BoolFromString(tweak_str);
|
result = CR_BoolFromString(tweak_str);
|
||||||
}
|
}
|
||||||
EndScratch(scratch);
|
EndScratch(scratch);
|
||||||
return result;
|
return result;
|
||||||
@ -135,7 +135,7 @@ f64 TweakFloat_(String name, f64 initial, TweakFloatDesc desc)
|
|||||||
var.precision = desc.precision;
|
var.precision = desc.precision;
|
||||||
}
|
}
|
||||||
String tweak_str = TweakEx(scratch.arena, var, 0);
|
String tweak_str = TweakEx(scratch.arena, var, 0);
|
||||||
result = FloatFromString(tweak_str);
|
result = CR_FloatFromString(tweak_str);
|
||||||
}
|
}
|
||||||
EndScratch(scratch);
|
EndScratch(scratch);
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@ -131,7 +131,7 @@ M_TokenFileList M_TokensFromSrcDirs(Arena *arena, StringList src_dirs)
|
|||||||
{
|
{
|
||||||
u8 c = t[p];
|
u8 c = t[p];
|
||||||
b32 is_eol = c == '\r' || c == '\n' || c == 0 || (p + 1) >= l;
|
b32 is_eol = c == '\r' || c == '\n' || c == 0 || (p + 1) >= l;
|
||||||
b32 is_whitespace = is_eol || c == ' ';
|
b32 is_whitespace = is_eol || c == ' ' || c == '\t';
|
||||||
if (is_whitespace)
|
if (is_whitespace)
|
||||||
{ // Whitespace
|
{ // Whitespace
|
||||||
if (cur_ident.len > 0)
|
if (cur_ident.len > 0)
|
||||||
|
|||||||
@ -1127,19 +1127,43 @@ S_Ent *S_PushTempEnt(Arena *arena, S_EntList *list)
|
|||||||
|
|
||||||
void S_SpawnEntsFromList(Arena *arena, S_World *world, S_EntList ents)
|
void S_SpawnEntsFromList(Arena *arena, S_World *world, S_EntList ents)
|
||||||
{
|
{
|
||||||
// FIXME: Don't reinsert duplicates
|
|
||||||
// FIXME: Don't insert nil keys
|
|
||||||
for (S_EntListNode *n = ents.first; n; n = n->next)
|
for (S_EntListNode *n = ents.first; n; n = n->next)
|
||||||
{
|
{
|
||||||
S_Ent *src = &n->ent;
|
S_Ent *src = &n->ent;
|
||||||
S_Ent *dst = PushStructNoZero(arena, S_Ent);
|
S_Key key = src->key;
|
||||||
*dst = *src;
|
if (!S_IsKeyNil(src->key))
|
||||||
S_EntBin *bin = &world->ent_bins[dst->key.v % world->ent_bins_count];
|
{
|
||||||
|
S_EntBin *bin = &world->ent_bins[key.v % world->ent_bins_count];
|
||||||
|
S_Ent *dst = bin->first;
|
||||||
|
for (; dst; dst = dst->next_in_bin)
|
||||||
|
{
|
||||||
|
if (S_MatchKey(dst->key, key))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!dst)
|
||||||
|
{
|
||||||
|
// FIXME: Use free list
|
||||||
|
dst = PushStructNoZero(arena, S_Ent);
|
||||||
DllQueuePush(world->first_ent, world->last_ent, dst);
|
DllQueuePush(world->first_ent, world->last_ent, dst);
|
||||||
DllQueuePushNP(bin->first, bin->last, dst, next_in_bin, prev_in_bin);
|
DllQueuePushNP(bin->first, bin->last, dst, next_in_bin, prev_in_bin);
|
||||||
|
}
|
||||||
|
S_Ent *old_next = dst->next;
|
||||||
|
S_Ent *old_prev = dst->prev;
|
||||||
|
S_Ent *old_next_in_bin = dst->next_in_bin;
|
||||||
|
S_Ent *old_prev_in_bin = dst->prev_in_bin;
|
||||||
|
{
|
||||||
|
*dst = *src;
|
||||||
|
}
|
||||||
|
dst->next = old_next;
|
||||||
|
dst->prev = old_prev;
|
||||||
|
dst->next_in_bin = old_next_in_bin;
|
||||||
|
dst->prev_in_bin = old_prev_in_bin;
|
||||||
++world->ents_count;
|
++world->ents_count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Debug draw
|
//~ Debug draw
|
||||||
@ -1232,38 +1256,30 @@ void S_TickForever(WaveLaneCtx *lane)
|
|||||||
{
|
{
|
||||||
packed = SwappedStateFromName(frame_arena, Lit("pp_sim.swp"));
|
packed = SwappedStateFromName(frame_arena, Lit("pp_sim.swp"));
|
||||||
}
|
}
|
||||||
S_TranscodeResult tr = S_TranscodeWorld(frame_arena, 0, packed, 0);
|
S_UnpackedWorld unpacked = S_UnpackWorld(frame_arena, packed);
|
||||||
|
|
||||||
ResetArena(world_arena);
|
ResetArena(world_arena);
|
||||||
world = PushStruct(world_arena, S_World);
|
world = PushStruct(world_arena, S_World);
|
||||||
world->seed = tr.unpacked->seed;
|
world->seed = unpacked.seed;
|
||||||
world->tick = tr.unpacked->tick;
|
world->tick = unpacked.tick;
|
||||||
world->time_ns = tr.unpacked->time_ns;
|
world->time_ns = unpacked.time_ns;
|
||||||
|
|
||||||
world->ent_bins_count = Kibi(16);
|
world->ent_bins_count = Kibi(16);
|
||||||
world->ent_bins = PushStructs(world_arena, S_EntBin, world->ent_bins_count);
|
world->ent_bins = PushStructs(world_arena, S_EntBin, world->ent_bins_count);
|
||||||
|
|
||||||
// Copy tiles
|
// Copy tiles
|
||||||
world->tiles = PushStructsNoZero(world_arena, u8, S_TilesCount);
|
world->tiles = PushStructsNoZero(world_arena, u8, S_TilesCount);
|
||||||
CopyStructs(world->tiles, tr.unpacked->tiles, S_TilesCount);
|
CopyStructs(world->tiles, unpacked.tiles, S_TilesCount);
|
||||||
|
|
||||||
// Copy ents
|
// Copy ents
|
||||||
world->ents_count = tr.unpacked->ents_count;
|
S_SpawnEntsFromList(world_arena, world, unpacked.ents);
|
||||||
for (S_Ent *src = tr.unpacked->first_ent; src; src = src->next)
|
|
||||||
{
|
|
||||||
S_Ent *dst = PushStructNoZero(world_arena, S_Ent);
|
|
||||||
*dst = *src;
|
|
||||||
S_EntBin *bin = &world->ent_bins[dst->key.v % world->ent_bins_count];
|
|
||||||
DllQueuePush(world->first_ent, world->last_ent, dst);
|
|
||||||
DllQueuePushNP(bin->first, bin->last, dst, next_in_bin, prev_in_bin);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//- Swap out
|
//- Swap out
|
||||||
if (swapout)
|
if (swapout)
|
||||||
{
|
{
|
||||||
S_TranscodeResult tr = S_TranscodeWorld(frame_arena, world, Zstr, 1);
|
String packed = S_PackWorld(frame_arena, world);
|
||||||
WriteSwappedState(Lit("pp_sim.swp"), tr.packed);
|
WriteSwappedState(Lit("pp_sim.swp"), packed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1520,7 +1536,7 @@ void S_TickForever(WaveLaneCtx *lane)
|
|||||||
// // Vec2 shape0_pt = S_SupportPointFromShape(shape0, shape_dir);
|
// // Vec2 shape0_pt = S_SupportPointFromShape(shape0, shape_dir);
|
||||||
// // Vec2 shape1_pt = S_SupportPointFromShape(shape1, neg_shape_dir);
|
// // Vec2 shape1_pt = S_SupportPointFromShape(shape1, neg_shape_dir);
|
||||||
|
|
||||||
// S_CollisionResult collision_data = S_CollisionResultFromShapes(shape0, shape1, VEC2(0, 0));
|
// S_CollisionResult collision_data = S_CollisionResultFromShapes(shape0, shape1);
|
||||||
// Vec2 shape0_pt = collision_data.closest_p0;
|
// Vec2 shape0_pt = collision_data.closest_p0;
|
||||||
// Vec2 shape1_pt = collision_data.closest_p1;
|
// Vec2 shape1_pt = collision_data.closest_p1;
|
||||||
|
|
||||||
@ -1606,8 +1622,8 @@ void S_TickForever(WaveLaneCtx *lane)
|
|||||||
S_EntList bullets_to_spawn = Zi;
|
S_EntList bullets_to_spawn = Zi;
|
||||||
for (S_Ent *firer = S_FirstEnt(world); firer->valid; firer = S_NextEnt(firer))
|
for (S_Ent *firer = S_FirstEnt(world); firer->valid; firer = S_NextEnt(firer))
|
||||||
{
|
{
|
||||||
// if (firer->fire_held)
|
if (firer->fire_held)
|
||||||
if (firer->fire_presses)
|
// if (firer->fire_presses)
|
||||||
{
|
{
|
||||||
// i64 fire_delta_ns = world->time_ns - firer->last_fire_ns;
|
// i64 fire_delta_ns = world->time_ns - firer->last_fire_ns;
|
||||||
|
|
||||||
|
|||||||
@ -1,153 +1,307 @@
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Transcode
|
//~ Transcode
|
||||||
|
|
||||||
S_TranscodeResult S_TranscodeWorld(Arena *arena, S_World *src_world, String src_packed, b32 pack)
|
|
||||||
{
|
|
||||||
S_TranscodeResult result = Zi;
|
|
||||||
result.ok = 1;
|
|
||||||
result.version = S_Tv_Latest;
|
|
||||||
|
|
||||||
//////////////////////////////
|
|
||||||
//- Init bitbuff
|
|
||||||
|
|
||||||
u32 level_magic = 0xa2bf209c;
|
// FIXME: Header
|
||||||
|
|
||||||
BB_Buff bb = Zi;
|
|
||||||
BB_Writer bw = Zi;
|
|
||||||
BB_Reader br = Zi;
|
|
||||||
if (pack)
|
|
||||||
{
|
|
||||||
bb = BB_AcquireDynamicBuff(Gibi(4));
|
|
||||||
bw = BB_WriterFromBuff(&bb);
|
|
||||||
BB_WriteUBits(&bw, level_magic, 32);
|
|
||||||
BB_WriteUBits(&bw, result.version, 32);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bb = BB_BuffFromString(src_packed);
|
|
||||||
br = BB_ReaderFromBuff(&bb);
|
|
||||||
result.ok = BB_ReadUBits(&br, 32) == level_magic;
|
|
||||||
result.version = (S_Tv)BB_ReadUBits(&br, 32);
|
|
||||||
result.unpacked = PushStruct(arena, S_World);
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////
|
|
||||||
//- Transcode world metadata
|
|
||||||
|
|
||||||
if (pack)
|
String S_PackWorld(Arena *arena, S_World *src_world)
|
||||||
{
|
{
|
||||||
BB_WriteUBits(&bw, src_world->seed, 64);
|
String result = Zi;
|
||||||
BB_WriteIBits(&bw, src_world->tick, 64);
|
result.text = ArenaNext(arena, u8);
|
||||||
BB_WriteIBits(&bw, src_world->time_ns, 64);
|
TempArena scratch = BeginScratch(arena);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
result.unpacked->seed = BB_ReadUBits(&br, 64);
|
|
||||||
result.unpacked->tick = BB_ReadIBits(&br, 64);
|
|
||||||
result.unpacked->time_ns = BB_ReadIBits(&br, 64);
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////
|
result.len += StringF(arena, "version: %F\n", FmtUint(S_Tv_Latest)).len;
|
||||||
//- Transcode tiles
|
|
||||||
|
|
||||||
// TODO: Compress tile data
|
// Pack entities
|
||||||
|
// FIXME: Precision
|
||||||
if (pack)
|
result.len += PushString(arena, Lit("\nentities:\n")).len;
|
||||||
{
|
result.len += PushString(arena, Lit("{\n")).len;
|
||||||
String tiles_str = Zi;
|
|
||||||
tiles_str.len = S_TilesCount;
|
|
||||||
tiles_str.text = src_world->tiles;
|
|
||||||
BB_WriteUBits(&bw, tiles_str.len, 64);
|
|
||||||
BB_WriteBytes(&bw, tiles_str);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
u64 raw_tiles_count = BB_ReadUBits(&br, 64);
|
|
||||||
u8 *raw_tiles = BB_ReadBytesRaw(&br, raw_tiles_count);
|
|
||||||
if (raw_tiles && raw_tiles_count == S_TilesCount)
|
|
||||||
{
|
|
||||||
result.unpacked->tiles = PushStructsNoZero(arena, u8, raw_tiles_count);
|
|
||||||
CopyBytes(result.unpacked->tiles, raw_tiles, raw_tiles_count);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
result.unpacked->tiles = PushStructs(arena, u8, S_TilesCount);
|
|
||||||
result.ok = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////
|
|
||||||
//- Transcode entities
|
|
||||||
|
|
||||||
// TODO: Compress entity data
|
|
||||||
|
|
||||||
if (result.ok)
|
|
||||||
{
|
|
||||||
if (pack)
|
|
||||||
{
|
|
||||||
u32 ent_size = sizeof(S_Ent);
|
|
||||||
u32 ent_align = alignof(S_Ent);
|
|
||||||
i64 ents_count = src_world->ents_count;
|
|
||||||
BB_WriteUBits(&bw, ent_size, 32);
|
|
||||||
BB_WriteUBits(&bw, ent_align, 32);
|
|
||||||
BB_WriteUBits(&bw, ents_count, 64);
|
|
||||||
for (S_Ent *ent = S_FirstEnt(src_world); ent->valid; ent = S_NextEnt(ent))
|
for (S_Ent *ent = S_FirstEnt(src_world); ent->valid; ent = S_NextEnt(ent))
|
||||||
{
|
{
|
||||||
BB_WriteBytes(&bw, StringFromStruct(ent));
|
result.len += StringF(arena, " 0x%F:\n", FmtHex(ent->key.v)).len;
|
||||||
|
result.len += PushString(arena, Lit(" {\n")).len;
|
||||||
|
{
|
||||||
|
result.len += StringF(arena, " pos: \"%F\"\n", FmtFloat2(ent->xf.og)).len;
|
||||||
|
result.len += StringF(arena, " rot: \"%F\"\n", FmtFloat2(RightFromXform(ent->xf))).len;
|
||||||
|
result.len += StringF(arena, " exists: \"%F\"\n", FmtFloat(ent->exists)).len;
|
||||||
|
result.len += StringF(arena, " look: \"%F\"\n", FmtFloat2(ent->look)).len;
|
||||||
|
if (ent->is_player)
|
||||||
|
{
|
||||||
|
result.len += PushString(arena, Lit(" player: true\n")).len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
result.len += PushString(arena, Lit(" }\n")).len;
|
||||||
{
|
|
||||||
i64 ent_size = BB_ReadUBits(&br, 32);
|
|
||||||
i64 ent_align = BB_ReadUBits(&br, 32);
|
|
||||||
i64 ents_count = BB_ReadUBits(&br, 64);
|
|
||||||
if (ent_size == sizeof(S_Ent) && ent_align == alignof(S_Ent))
|
|
||||||
{
|
|
||||||
for (i64 i = 0; i < ents_count; ++i)
|
|
||||||
{
|
|
||||||
S_Ent *raw_ent = (S_Ent *)BB_ReadBytesRaw(&br, sizeof(S_Ent));
|
|
||||||
if (raw_ent)
|
|
||||||
{
|
|
||||||
S_Ent *ent = PushStructNoZero(arena, S_Ent);
|
|
||||||
{
|
|
||||||
CopyBytes(ent, raw_ent, ent_size);
|
|
||||||
ent->valid = 1;
|
|
||||||
}
|
}
|
||||||
DllQueuePush(result.unpacked->first_ent, result.unpacked->last_ent, ent);
|
result.len += PushString(arena, Lit("}\n")).len;
|
||||||
result.unpacked->ents_count += 1;
|
|
||||||
}
|
// Pack tiles
|
||||||
else
|
// TODO: Compress tile data
|
||||||
|
result.len += PushString(arena, Lit("\ntiles:\n")).len;
|
||||||
|
result.len += PushString(arena, Lit("{\n")).len;
|
||||||
{
|
{
|
||||||
result.ok = 0;
|
String tiles_str = Base64FromString(scratch.arena, STRING(S_TilesCount, src_world->tiles));
|
||||||
|
u64 tile_chars_per_line = 128;
|
||||||
|
u64 tile_char_pos = 0;
|
||||||
|
while (tile_char_pos < tiles_str.len)
|
||||||
|
{
|
||||||
|
result.len += PushString(arena, Lit(" ")).len;
|
||||||
|
String src = STRING(tile_chars_per_line, tiles_str.text + tile_char_pos);
|
||||||
|
src.len = MinU64(tile_chars_per_line, tiles_str.len - tile_char_pos);
|
||||||
|
result.len += PushString(arena, src).len;
|
||||||
|
result.len += PushString(arena, Lit("\n")).len;
|
||||||
|
tile_char_pos += tile_chars_per_line;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
result.len += PushString(arena, Lit("}\n")).len;
|
||||||
|
|
||||||
|
EndScratch(scratch);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
S_UnpackedWorld S_UnpackWorld(Arena *arena, String packed)
|
||||||
|
{
|
||||||
|
S_UnpackedWorld result = Zi;
|
||||||
|
TempArena scratch = BeginScratch(arena);
|
||||||
|
|
||||||
|
CR_Item *root = CR_ItemFromString(scratch.arena, packed);
|
||||||
|
|
||||||
|
// Get version
|
||||||
|
S_Tv version = 0;
|
||||||
|
for (CR_Item *root_item = root->first; root_item; root_item = root_item->next)
|
||||||
|
{
|
||||||
|
if (MatchString(root_item->name, Lit("version")))
|
||||||
|
{
|
||||||
|
version = CR_IntFromString(root_item->value);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
for (CR_Item *top_item = root->first; top_item; top_item = top_item->next)
|
||||||
{
|
{
|
||||||
result.ok = 0;
|
// Parse entities
|
||||||
|
if (MatchString(top_item->name, Lit("entities")))
|
||||||
|
{
|
||||||
|
for (CR_Item *ent_item = top_item->first; ent_item; ent_item = ent_item->next)
|
||||||
|
{
|
||||||
|
S_Ent *ent = S_PushTempEnt(arena, &result.ents);
|
||||||
|
ent->key = (S_Key) { .v = CR_IntFromString(ent_item->name) };
|
||||||
|
for (CR_Item *prop = ent_item->first; prop; prop = prop->next)
|
||||||
|
{
|
||||||
|
if (MatchString(prop->name, Lit("pos")))
|
||||||
|
{
|
||||||
|
Vec2 pos = CR_Vec2FromString(prop->value);
|
||||||
|
ent->xf.og = pos;
|
||||||
|
}
|
||||||
|
if (MatchString(prop->name, Lit("rot")))
|
||||||
|
{
|
||||||
|
Vec2 rot = CR_Vec2FromString(prop->value);
|
||||||
|
ent->xf = XformWithWorldRotation(ent->xf, AngleFromVec2(rot));
|
||||||
|
}
|
||||||
|
if (MatchString(prop->name, Lit("exists")))
|
||||||
|
{
|
||||||
|
ent->exists = CR_FloatFromString(prop->value);
|
||||||
|
}
|
||||||
|
if (MatchString(prop->name, Lit("health")))
|
||||||
|
{
|
||||||
|
ent->health = CR_FloatFromString(prop->value);
|
||||||
|
}
|
||||||
|
if (MatchString(prop->name, Lit("look")))
|
||||||
|
{
|
||||||
|
Vec2 look = CR_Vec2FromString(prop->value);
|
||||||
|
ent->look = look;
|
||||||
|
}
|
||||||
|
if (MatchString(prop->name, Lit("player")) && CR_BoolFromString(prop->value))
|
||||||
|
{
|
||||||
|
ent->is_player = 1;
|
||||||
|
ent->has_weapon = 1;
|
||||||
|
}
|
||||||
|
// if (MatchString(prop->name, Lit("bullet")) && CR_BoolFromString(prop->value))
|
||||||
|
// {
|
||||||
|
// ent->is_bullet = 1;
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////
|
// Parse tiles
|
||||||
//- Finalize
|
String tiles_base64 = Zi;
|
||||||
|
tiles_base64.text = ArenaNext(scratch.arena, u8);
|
||||||
if (result.ok)
|
for (CR_Item *tile_item = top_item->first; tile_item; tile_item = tile_item->next)
|
||||||
{
|
{
|
||||||
if (pack)
|
tiles_base64.len += PushString(scratch.arena, tile_item->value).len;
|
||||||
{
|
|
||||||
result.packed = BB_GetWritten(arena, &bw);
|
|
||||||
BB_ReleaseDynamicBuff(&bb);
|
|
||||||
}
|
}
|
||||||
else
|
if (StringLenFromBase64Len(tiles_base64.len) == S_TilesCount)
|
||||||
{
|
{
|
||||||
if (!result.unpacked->seed)
|
result.tiles = StringFromBase64(arena, tiles_base64).text;
|
||||||
{
|
|
||||||
TrueRand(StringFromStruct(&result.unpacked->seed));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!result.tiles)
|
||||||
|
{
|
||||||
|
result.tiles = PushStructs(arena, u8, S_TilesCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
EndScratch(scratch);
|
||||||
return result;
|
return result;
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// ////////////////////////////////////////////////////////////
|
||||||
|
// //~ Transcode
|
||||||
|
|
||||||
|
// S_TranscodeResult S_TranscodeWorld(Arena *arena, S_World *src_world, String src_packed, b32 pack)
|
||||||
|
// {
|
||||||
|
// S_TranscodeResult result = Zi;
|
||||||
|
// result.ok = 1;
|
||||||
|
// result.version = S_Tv_Latest;
|
||||||
|
|
||||||
|
// //////////////////////////////
|
||||||
|
// //- Init bitbuff
|
||||||
|
|
||||||
|
// u32 level_magic = 0xa2bf209c;
|
||||||
|
|
||||||
|
// BB_Buff bb = Zi;
|
||||||
|
// BB_Writer bw = Zi;
|
||||||
|
// BB_Reader br = Zi;
|
||||||
|
// if (pack)
|
||||||
|
// {
|
||||||
|
// bb = BB_AcquireDynamicBuff(Gibi(4));
|
||||||
|
// bw = BB_WriterFromBuff(&bb);
|
||||||
|
// BB_WriteUBits(&bw, level_magic, 32);
|
||||||
|
// BB_WriteUBits(&bw, result.version, 32);
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// bb = BB_BuffFromString(src_packed);
|
||||||
|
// br = BB_ReaderFromBuff(&bb);
|
||||||
|
// result.ok = BB_ReadUBits(&br, 32) == level_magic;
|
||||||
|
// result.version = (S_Tv)BB_ReadUBits(&br, 32);
|
||||||
|
// result.unpacked = PushStruct(arena, S_World);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// //////////////////////////////
|
||||||
|
// //- Transcode world metadata
|
||||||
|
|
||||||
|
// if (pack)
|
||||||
|
// {
|
||||||
|
// BB_WriteUBits(&bw, src_world->seed, 64);
|
||||||
|
// BB_WriteIBits(&bw, src_world->tick, 64);
|
||||||
|
// BB_WriteIBits(&bw, src_world->time_ns, 64);
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// result.unpacked->seed = BB_ReadUBits(&br, 64);
|
||||||
|
// result.unpacked->tick = BB_ReadIBits(&br, 64);
|
||||||
|
// result.unpacked->time_ns = BB_ReadIBits(&br, 64);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// //////////////////////////////
|
||||||
|
// //- Transcode tiles
|
||||||
|
|
||||||
|
// // TODO: Compress tile data
|
||||||
|
|
||||||
|
// if (pack)
|
||||||
|
// {
|
||||||
|
// String tiles_str = Zi;
|
||||||
|
// tiles_str.len = S_TilesCount;
|
||||||
|
// tiles_str.text = src_world->tiles;
|
||||||
|
// BB_WriteUBits(&bw, tiles_str.len, 64);
|
||||||
|
// BB_WriteBytes(&bw, tiles_str);
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// u64 raw_tiles_count = BB_ReadUBits(&br, 64);
|
||||||
|
// u8 *raw_tiles = BB_ReadBytesRaw(&br, raw_tiles_count);
|
||||||
|
// if (raw_tiles && raw_tiles_count == S_TilesCount)
|
||||||
|
// {
|
||||||
|
// result.unpacked->tiles = PushStructsNoZero(arena, u8, raw_tiles_count);
|
||||||
|
// CopyBytes(result.unpacked->tiles, raw_tiles, raw_tiles_count);
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// result.unpacked->tiles = PushStructs(arena, u8, S_TilesCount);
|
||||||
|
// result.ok = 0;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// //////////////////////////////
|
||||||
|
// //- Transcode entities
|
||||||
|
|
||||||
|
// // TODO: Compress entity data
|
||||||
|
|
||||||
|
// if (result.ok)
|
||||||
|
// {
|
||||||
|
// if (pack)
|
||||||
|
// {
|
||||||
|
// u32 ent_size = sizeof(S_Ent);
|
||||||
|
// u32 ent_align = alignof(S_Ent);
|
||||||
|
// i64 ents_count = src_world->ents_count;
|
||||||
|
// BB_WriteUBits(&bw, ent_size, 32);
|
||||||
|
// BB_WriteUBits(&bw, ent_align, 32);
|
||||||
|
// BB_WriteUBits(&bw, ents_count, 64);
|
||||||
|
// for (S_Ent *ent = S_FirstEnt(src_world); ent->valid; ent = S_NextEnt(ent))
|
||||||
|
// {
|
||||||
|
// BB_WriteBytes(&bw, StringFromStruct(ent));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// i64 ent_size = BB_ReadUBits(&br, 32);
|
||||||
|
// i64 ent_align = BB_ReadUBits(&br, 32);
|
||||||
|
// i64 ents_count = BB_ReadUBits(&br, 64);
|
||||||
|
// if (ent_size == sizeof(S_Ent) && ent_align == alignof(S_Ent))
|
||||||
|
// {
|
||||||
|
// for (i64 i = 0; i < ents_count; ++i)
|
||||||
|
// {
|
||||||
|
// S_Ent *raw_ent = (S_Ent *)BB_ReadBytesRaw(&br, sizeof(S_Ent));
|
||||||
|
// if (raw_ent)
|
||||||
|
// {
|
||||||
|
// S_Ent *ent = PushStructNoZero(arena, S_Ent);
|
||||||
|
// {
|
||||||
|
// CopyBytes(ent, raw_ent, ent_size);
|
||||||
|
// ent->valid = 1;
|
||||||
|
// }
|
||||||
|
// DllQueuePush(result.unpacked->first_ent, result.unpacked->last_ent, ent);
|
||||||
|
// result.unpacked->ents_count += 1;
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// result.ok = 0;
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// result.ok = 0;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// //////////////////////////////
|
||||||
|
// //- Finalize
|
||||||
|
|
||||||
|
// if (result.ok)
|
||||||
|
// {
|
||||||
|
// if (pack)
|
||||||
|
// {
|
||||||
|
// result.packed = BB_GetWritten(arena, &bw);
|
||||||
|
// BB_ReleaseDynamicBuff(&bb);
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// if (!result.unpacked->seed)
|
||||||
|
// {
|
||||||
|
// TrueRand(StringFromStruct(&result.unpacked->seed));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return result;
|
||||||
|
// }
|
||||||
|
|||||||
@ -4,22 +4,27 @@
|
|||||||
Enum(S_Tv)
|
Enum(S_Tv)
|
||||||
{
|
{
|
||||||
S_Tv_None = 0,
|
S_Tv_None = 0,
|
||||||
|
S_Tv_Initial = 1,
|
||||||
|
|
||||||
S_Tv_COUNT
|
S_Tv_COUNT
|
||||||
};
|
};
|
||||||
|
|
||||||
#define S_Tv_Latest (S_Tv_COUNT - 1)
|
#define S_Tv_Latest (S_Tv_COUNT - 1)
|
||||||
|
|
||||||
Struct(S_TranscodeResult)
|
Struct(S_UnpackedWorld)
|
||||||
{
|
{
|
||||||
b32 ok;
|
|
||||||
S_Tv version;
|
S_Tv version;
|
||||||
|
|
||||||
String packed;
|
u64 seed;
|
||||||
S_World *unpacked;
|
i64 tick;
|
||||||
|
i64 time_ns;
|
||||||
|
|
||||||
|
S_EntList ents;
|
||||||
|
u8 *tiles;
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Transcode
|
//~ Transcode
|
||||||
|
|
||||||
S_TranscodeResult S_TranscodeWorld(Arena *arena, S_World *world, String packed, b32 pack);
|
String S_PackWorld(Arena *arena, S_World *src_world);
|
||||||
|
S_UnpackedWorld S_UnpackWorld(Arena *arena, String packed);
|
||||||
|
|||||||
@ -939,7 +939,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
frame->draw_cursor = MulXformV2(frame->xf.ui_to_draw, frame->ui_cursor);
|
frame->draw_cursor = MulXformV2(frame->xf.ui_to_draw, frame->ui_cursor);
|
||||||
frame->world_cursor = MulXformV2(frame->xf.ui_to_world, frame->ui_cursor);
|
frame->world_cursor = MulXformV2(frame->xf.ui_to_world, frame->ui_cursor);
|
||||||
|
|
||||||
b32 show_editor_ui = TweakBool("Show editor UI", 0);
|
b32 show_editor_ui = TweakBool("Show editor UI", 1);
|
||||||
|
|
||||||
frame->world_selection_start = frame->world_cursor;
|
frame->world_selection_start = frame->world_cursor;
|
||||||
if (frame->is_editing)
|
if (frame->is_editing)
|
||||||
@ -1972,7 +1972,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
UI_Key cb_key = UI_KeyF("tweak checkbox");
|
UI_Key cb_key = UI_KeyF("tweak checkbox");
|
||||||
UI_BoxReport cb_rep = UI_ReportsFromKey(cb_key).draw;
|
UI_BoxReport cb_rep = UI_ReportsFromKey(cb_key).draw;
|
||||||
|
|
||||||
b32 tweak_bool = BoolFromString(new_tweak_str);
|
b32 tweak_bool = CR_BoolFromString(new_tweak_str);
|
||||||
if (cb_rep.m1.downs)
|
if (cb_rep.m1.downs)
|
||||||
{
|
{
|
||||||
tweak_bool = !tweak_bool;
|
tweak_bool = !tweak_bool;
|
||||||
@ -2023,7 +2023,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
range_max = range_min + 1;
|
range_max = range_min + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
f64 tweak_float = FloatFromString(new_tweak_str);
|
f64 tweak_float = CR_FloatFromString(new_tweak_str);
|
||||||
{
|
{
|
||||||
if (is_active)
|
if (is_active)
|
||||||
{
|
{
|
||||||
@ -2821,7 +2821,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (0)
|
||||||
{
|
{
|
||||||
for (S_Ent *bullet = S_FirstEnt(world); bullet->valid; bullet = S_NextEnt(bullet))
|
for (S_Ent *bullet = S_FirstEnt(world); bullet->valid; bullet = S_NextEnt(bullet))
|
||||||
{
|
{
|
||||||
|
|||||||
@ -84,6 +84,7 @@ ComputeShader2D(V_BackdropCS, 8, 8)
|
|||||||
Vec4 result = Vec4(0.025, 0.025, 0.025, 1);
|
Vec4 result = Vec4(0.025, 0.025, 0.025, 1);
|
||||||
Vec2 world_pos = mul(params.xf.ui_to_world, Vec3(ui_pos, 1));
|
Vec2 world_pos = mul(params.xf.ui_to_world, Vec3(ui_pos, 1));
|
||||||
Vec2I32 tile_pos = S_TilePosFromWorldPos(world_pos);
|
Vec2I32 tile_pos = S_TilePosFromWorldPos(world_pos);
|
||||||
|
S_TileKind tile = tiles.Load(Vec3I32(tile_pos, 0));
|
||||||
|
|
||||||
f32 half_thickness = 1;
|
f32 half_thickness = 1;
|
||||||
f32 half_bounds_size = S_WorldPitch * 0.5;
|
f32 half_bounds_size = S_WorldPitch * 0.5;
|
||||||
@ -138,7 +139,6 @@ ComputeShader2D(V_BackdropCS, 8, 8)
|
|||||||
}
|
}
|
||||||
// Tile
|
// Tile
|
||||||
{
|
{
|
||||||
S_TileKind tile = tiles.Load(Vec3I32(tile_pos, 0));
|
|
||||||
switch (tile)
|
switch (tile)
|
||||||
{
|
{
|
||||||
default: break;
|
default: break;
|
||||||
@ -204,7 +204,6 @@ ComputeShader2D(V_BackdropCS, 8, 8)
|
|||||||
// cell.rgb *= cell.a;
|
// cell.rgb *= cell.a;
|
||||||
// stain.rgb *= stain.a;
|
// stain.rgb *= stain.a;
|
||||||
|
|
||||||
|
|
||||||
result.rgb = (stain.rgb * stain.a) + (result.rgb * (1.0 - stain.a));
|
result.rgb = (stain.rgb * stain.a) + (result.rgb * (1.0 - stain.a));
|
||||||
result.a = (stain.a * 1) + (result.a * (1.0 - stain.a));
|
result.a = (stain.a * 1) + (result.a * (1.0 - stain.a));
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user