From a00fcf3fba74554965a4c69916506f40c9010a36 Mon Sep 17 00:00:00 2001 From: jacob Date: Fri, 9 Jan 2026 06:46:52 -0600 Subject: [PATCH] store level files in textual format --- ppswap/pp_sim.swp.swp | Bin 37152 -> 0 bytes ppswap/pp_vis.swp.swp | Bin 126 -> 0 bytes src/base/base_bitbuff.c | 4 - src/base/base_bitbuff.h | 2 - src/base/base_crum.c | 444 +++++++++++++++++++++++++++++++ src/base/base_crum.h | 30 +++ src/base/base_inc.h | 2 + src/base/base_string.c | 167 +++++------- src/base/base_string.h | 17 +- src/base/base_tweak.c | 4 +- src/meta/meta_lay.c | 2 +- src/pp/pp_sim/pp_sim_core.c | 70 +++-- src/pp/pp_sim/pp_sim_transcode.c | 430 ++++++++++++++++++++---------- src/pp/pp_sim/pp_sim_transcode.h | 15 +- src/pp/pp_vis/pp_vis_core.c | 8 +- src/pp/pp_vis/pp_vis_gpu.g | 3 +- 16 files changed, 904 insertions(+), 294 deletions(-) delete mode 100644 ppswap/pp_sim.swp.swp delete mode 100644 ppswap/pp_vis.swp.swp create mode 100644 src/base/base_crum.c create mode 100644 src/base/base_crum.h diff --git a/ppswap/pp_sim.swp.swp b/ppswap/pp_sim.swp.swp deleted file mode 100644 index b9d1d1b570fa1e5f99bf5a4ce7b273aa3524a7e0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 37152 zcmeIuEp7r)5CGuC^$s3sO~q(yq!1ub~f)D<*P{+@$s70h;e>wrRN|mf&c*m1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5*B4}n8m^C7Zw=XE!`#ccOH zeY~81tC!!kfBUQUeo>2DruzM*v;HZ*8+p{H=tnM7UG}pqZ{GfLSQNE#-tD`;>|@ST UdA?iitw&#<^|Zg9y`87t8Du3h+yDRo diff --git a/ppswap/pp_vis.swp.swp b/ppswap/pp_vis.swp.swp deleted file mode 100644 index 991ada60bb1c0b9c31dfe2b5c2aac169376bc8b2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 126 zcmX?nbI;bBUMr;?7=AY}JU-TNvQVb+0)tk|mLob05Wone{-Xh?6axbn1H%GVFmDP2 Zg9?}dQZEN2KzJSp1A{D39wdeh005m0ATj^| diff --git a/src/base/base_bitbuff.c b/src/base/base_bitbuff.c index 705db5d0..e8da2387 100644 --- a/src/base/base_bitbuff.c +++ b/src/base/base_bitbuff.c @@ -787,8 +787,6 @@ i64 BB_IntFromTwosCompliment(u64 tc, u8 num_bits) //////////////////////////////////////////////////////////// //~ Test -#if BITBUFF_TEST - void BB_Test(void) { TempArena scratch = BeginScratchNoConflict(); @@ -937,5 +935,3 @@ void BB_Test(void) EndScratch(scratch); } - -#endif diff --git a/src/base/base_bitbuff.h b/src/base/base_bitbuff.h index 9c75b409..a5db19a8 100644 --- a/src/base/base_bitbuff.h +++ b/src/base/base_bitbuff.h @@ -187,6 +187,4 @@ i64 BB_IntFromTwosCompliment(u64 tc, u8 num_bits); //////////////////////////////////////////////////////////// //~ Test -#if BITBUFF_TEST void BB_Test(void); -#endif diff --git a/src/base/base_crum.c b/src/base/base_crum.c new file mode 100644 index 00000000..f4095457 --- /dev/null +++ b/src/base/base_crum.c @@ -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; +} diff --git a/src/base/base_crum.h b/src/base/base_crum.h new file mode 100644 index 00000000..43608015 --- /dev/null +++ b/src/base/base_crum.h @@ -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); diff --git a/src/base/base_inc.h b/src/base/base_inc.h index 75f62fc6..7f08d5c1 100644 --- a/src/base/base_inc.h +++ b/src/base/base_inc.h @@ -25,6 +25,7 @@ #include "base_resource.h" #include "base_controller.h" #include "base_async.h" + #include "base_crum.h" #include "base_tweak.h" #include "base_state.h" #elif IsLanguageG @@ -47,6 +48,7 @@ #include "base_bitbuff.c" #include "base_resource.c" #include "base_controller.c" + #include "base_crum.c" #include "base_async.c" #include "base_state.c" #else diff --git a/src/base/base_string.c b/src/base/base_string.c index 3054fc17..f457f8f6 100644 --- a/src/base/base_string.c +++ b/src/base/base_string.c @@ -20,7 +20,7 @@ String StringFromChar(Arena *arena, char c) String StringFromUint(Arena *arena, u64 n, u64 base, u64 zfill) { // Base too large - Assert(base <= (countof(IntChars) - 1)); + Assert(base <= (countof(Base16Chars) - 1)); String result = Zi; 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); do { - StringFromChar(scratch.arena, IntChars[n % base]); + StringFromChar(scratch.arena, Base16Chars[n % base]); ++result.len; n /= base; } while (n > 0); @@ -213,104 +213,6 @@ String StringFromUid(Arena *arena, Uid uid) 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 @@ -653,12 +555,12 @@ String TrimWhitespace(String s) b32 stop = 0; 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.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; } @@ -1057,6 +959,67 @@ String32 String32FromString(Arena *arena, String str8) 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 diff --git a/src/base/base_string.h b/src/base/base_string.h index 835926b7..db90874c 100644 --- a/src/base/base_string.h +++ b/src/base/base_string.h @@ -2,7 +2,7 @@ //~ Formatting types #define DefaultFmtPrecision 3 -#define IntChars ("0123456789abcdef") +#define Base16Chars ("0123456789abcdef") Enum(FmtArgKind) { @@ -84,12 +84,6 @@ String StringFromPtr(Arena *arena, void *ptr); String StringFromhandle(Arena *arena, u64 v); String StringFromUid(Arena *arena, Uid uid); -//////////////////////////////////////////////////////////// -//~ Parsing helpers - -b32 BoolFromString(String str); -f64 FloatFromString(String str); - //////////////////////////////////////////////////////////// //~ String helpers @@ -173,6 +167,15 @@ String StringFromString32(Arena *arena, String32 str32); String16 String16FromString(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 diff --git a/src/base/base_tweak.c b/src/base/base_tweak.c index 6f1c5001..084389f8 100644 --- a/src/base/base_tweak.c +++ b/src/base/base_tweak.c @@ -110,7 +110,7 @@ b32 TweakBool_(String name, b32 initial, TweakBoolDesc desc) var.initial = initial_str; } String tweak_str = TweakEx(scratch.arena, var, 0); - result = BoolFromString(tweak_str); + result = CR_BoolFromString(tweak_str); } EndScratch(scratch); return result; @@ -135,7 +135,7 @@ f64 TweakFloat_(String name, f64 initial, TweakFloatDesc desc) var.precision = desc.precision; } String tweak_str = TweakEx(scratch.arena, var, 0); - result = FloatFromString(tweak_str); + result = CR_FloatFromString(tweak_str); } EndScratch(scratch); return result; diff --git a/src/meta/meta_lay.c b/src/meta/meta_lay.c index bd37f89c..4eca854b 100644 --- a/src/meta/meta_lay.c +++ b/src/meta/meta_lay.c @@ -131,7 +131,7 @@ M_TokenFileList M_TokensFromSrcDirs(Arena *arena, StringList src_dirs) { u8 c = t[p]; 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) { // Whitespace if (cur_ident.len > 0) diff --git a/src/pp/pp_sim/pp_sim_core.c b/src/pp/pp_sim/pp_sim_core.c index 9b6a4e36..44d3bd38 100644 --- a/src/pp/pp_sim/pp_sim_core.c +++ b/src/pp/pp_sim/pp_sim_core.c @@ -1127,17 +1127,41 @@ S_Ent *S_PushTempEnt(Arena *arena, S_EntList *list) 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) { S_Ent *src = &n->ent; - S_Ent *dst = PushStructNoZero(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); - ++world->ents_count; + S_Key key = src->key; + if (!S_IsKeyNil(src->key)) + { + 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); + 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; + } } } @@ -1232,38 +1256,30 @@ void S_TickForever(WaveLaneCtx *lane) { 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); world = PushStruct(world_arena, S_World); - world->seed = tr.unpacked->seed; - world->tick = tr.unpacked->tick; - world->time_ns = tr.unpacked->time_ns; + world->seed = unpacked.seed; + world->tick = unpacked.tick; + world->time_ns = unpacked.time_ns; world->ent_bins_count = Kibi(16); world->ent_bins = PushStructs(world_arena, S_EntBin, world->ent_bins_count); // Copy tiles 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 - world->ents_count = tr.unpacked->ents_count; - 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); - } + S_SpawnEntsFromList(world_arena, world, unpacked.ents); } //- Swap out if (swapout) { - S_TranscodeResult tr = S_TranscodeWorld(frame_arena, world, Zstr, 1); - WriteSwappedState(Lit("pp_sim.swp"), tr.packed); + String packed = S_PackWorld(frame_arena, world); + WriteSwappedState(Lit("pp_sim.swp"), packed); } } @@ -1520,7 +1536,7 @@ void S_TickForever(WaveLaneCtx *lane) // // Vec2 shape0_pt = S_SupportPointFromShape(shape0, 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 shape1_pt = collision_data.closest_p1; @@ -1606,8 +1622,8 @@ void S_TickForever(WaveLaneCtx *lane) S_EntList bullets_to_spawn = Zi; for (S_Ent *firer = S_FirstEnt(world); firer->valid; firer = S_NextEnt(firer)) { - // if (firer->fire_held) - if (firer->fire_presses) + if (firer->fire_held) + // if (firer->fire_presses) { // i64 fire_delta_ns = world->time_ns - firer->last_fire_ns; diff --git a/src/pp/pp_sim/pp_sim_transcode.c b/src/pp/pp_sim/pp_sim_transcode.c index 81a177fa..33ef2729 100644 --- a/src/pp/pp_sim/pp_sim_transcode.c +++ b/src/pp/pp_sim/pp_sim_transcode.c @@ -1,153 +1,307 @@ //////////////////////////////////////////////////////////// //~ Transcode -S_TranscodeResult S_TranscodeWorld(Arena *arena, S_World *src_world, String src_packed, b32 pack) + + +// FIXME: Header + + + +String S_PackWorld(Arena *arena, S_World *src_world) { - S_TranscodeResult result = Zi; - result.ok = 1; - result.version = S_Tv_Latest; + String result = Zi; + result.text = ArenaNext(arena, u8); + TempArena scratch = BeginScratch(arena); - ////////////////////////////// - //- Init bitbuff + result.len += StringF(arena, "version: %F\n", FmtUint(S_Tv_Latest)).len; - u32 level_magic = 0xa2bf209c; - - BB_Buff bb = Zi; - BB_Writer bw = Zi; - BB_Reader br = Zi; - if (pack) + // Pack entities + // FIXME: Precision + result.len += PushString(arena, Lit("\nentities:\n")).len; + result.len += PushString(arena, Lit("{\n")).len; + for (S_Ent *ent = S_FirstEnt(src_world); ent->valid; ent = S_NextEnt(ent)) { - 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); + 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; + } + } + result.len += PushString(arena, Lit(" }\n")).len; } + result.len += PushString(arena, Lit("}\n")).len; - ////////////////////////////// - //- 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 - + // Pack tiles // TODO: Compress tile data - - if (pack) + result.len += PushString(arena, Lit("\ntiles:\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)) - { - 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)); - } - } + 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; + } + } + + for (CR_Item *top_item = root->first; top_item; top_item = top_item->next) + { + // 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 + String tiles_base64 = Zi; + tiles_base64.text = ArenaNext(scratch.arena, u8); + for (CR_Item *tile_item = top_item->first; tile_item; tile_item = tile_item->next) + { + tiles_base64.len += PushString(scratch.arena, tile_item->value).len; + } + if (StringLenFromBase64Len(tiles_base64.len) == S_TilesCount) + { + result.tiles = StringFromBase64(arena, tiles_base64).text; + } + } + + if (!result.tiles) + { + result.tiles = PushStructs(arena, u8, S_TilesCount); + } + + EndScratch(scratch); + 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; +// } diff --git a/src/pp/pp_sim/pp_sim_transcode.h b/src/pp/pp_sim/pp_sim_transcode.h index 548a79e6..e243693b 100644 --- a/src/pp/pp_sim/pp_sim_transcode.h +++ b/src/pp/pp_sim/pp_sim_transcode.h @@ -4,22 +4,27 @@ Enum(S_Tv) { S_Tv_None = 0, + S_Tv_Initial = 1, S_Tv_COUNT }; #define S_Tv_Latest (S_Tv_COUNT - 1) -Struct(S_TranscodeResult) +Struct(S_UnpackedWorld) { - b32 ok; S_Tv version; - String packed; - S_World *unpacked; + u64 seed; + i64 tick; + i64 time_ns; + + S_EntList ents; + u8 *tiles; }; //////////////////////////////////////////////////////////// //~ 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); diff --git a/src/pp/pp_vis/pp_vis_core.c b/src/pp/pp_vis/pp_vis_core.c index 403151b4..7ef09c34 100644 --- a/src/pp/pp_vis/pp_vis_core.c +++ b/src/pp/pp_vis/pp_vis_core.c @@ -939,7 +939,7 @@ void V_TickForever(WaveLaneCtx *lane) frame->draw_cursor = MulXformV2(frame->xf.ui_to_draw, 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; if (frame->is_editing) @@ -1972,7 +1972,7 @@ void V_TickForever(WaveLaneCtx *lane) UI_Key cb_key = UI_KeyF("tweak checkbox"); 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) { tweak_bool = !tweak_bool; @@ -2023,7 +2023,7 @@ void V_TickForever(WaveLaneCtx *lane) range_max = range_min + 1; } - f64 tweak_float = FloatFromString(new_tweak_str); + f64 tweak_float = CR_FloatFromString(new_tweak_str); { 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)) { diff --git a/src/pp/pp_vis/pp_vis_gpu.g b/src/pp/pp_vis/pp_vis_gpu.g index 4c1d4757..563d8109 100644 --- a/src/pp/pp_vis/pp_vis_gpu.g +++ b/src/pp/pp_vis/pp_vis_gpu.g @@ -84,6 +84,7 @@ ComputeShader2D(V_BackdropCS, 8, 8) Vec4 result = Vec4(0.025, 0.025, 0.025, 1); Vec2 world_pos = mul(params.xf.ui_to_world, Vec3(ui_pos, 1)); Vec2I32 tile_pos = S_TilePosFromWorldPos(world_pos); + S_TileKind tile = tiles.Load(Vec3I32(tile_pos, 0)); f32 half_thickness = 1; f32 half_bounds_size = S_WorldPitch * 0.5; @@ -138,7 +139,6 @@ ComputeShader2D(V_BackdropCS, 8, 8) } // Tile { - S_TileKind tile = tiles.Load(Vec3I32(tile_pos, 0)); switch (tile) { default: break; @@ -204,7 +204,6 @@ ComputeShader2D(V_BackdropCS, 8, 8) // cell.rgb *= cell.a; // stain.rgb *= 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));