replace byteio with bitbuff
This commit is contained in:
parent
6d58619fbe
commit
be5d10e2b0
129
build.c
129
build.c
@ -60,7 +60,8 @@ typedef struct StepList StepList;
|
|||||||
typedef enum StepStatus {
|
typedef enum StepStatus {
|
||||||
StepStatus_None,
|
StepStatus_None,
|
||||||
StepStatus_Success,
|
StepStatus_Success,
|
||||||
StepStatus_Failure
|
StepStatus_Failure,
|
||||||
|
StepStatus_Skipped
|
||||||
} StepStatus;
|
} StepStatus;
|
||||||
|
|
||||||
typedef struct Step Step;
|
typedef struct Step Step;
|
||||||
@ -195,11 +196,15 @@ String CleanResultOutput(Arena *arena, String output)
|
|||||||
typedef struct BuildStepSimpleCommandArg BuildStepSimpleCommandArg;
|
typedef struct BuildStepSimpleCommandArg BuildStepSimpleCommandArg;
|
||||||
struct BuildStepSimpleCommandArg {
|
struct BuildStepSimpleCommandArg {
|
||||||
String cmd;
|
String cmd;
|
||||||
|
AtomicI32 *skip_flag;
|
||||||
|
AtomicI32 *failure_flag;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct BuildStepMsvcCompileCommandArg BuildStepMsvcCompileCommandArg;
|
typedef struct BuildStepMsvcCompileCommandArg BuildStepMsvcCompileCommandArg;
|
||||||
struct BuildStepMsvcCompileCommandArg {
|
struct BuildStepMsvcCompileCommandArg {
|
||||||
String cmd;
|
String cmd;
|
||||||
|
AtomicI32 *skip_flag;
|
||||||
|
AtomicI32 *failure_flag;
|
||||||
D_Tag depfile_dependent;
|
D_Tag depfile_dependent;
|
||||||
D_Tag output_depfile;
|
D_Tag output_depfile;
|
||||||
D_TagList depfile_force_includes;
|
D_TagList depfile_force_includes;
|
||||||
@ -209,28 +214,42 @@ void BuildStepSimpleCommand(void *arg_raw)
|
|||||||
{
|
{
|
||||||
TempArena scratch = ScratchBeginNoConflict();
|
TempArena scratch = ScratchBeginNoConflict();
|
||||||
Step *s = arg_raw;
|
Step *s = arg_raw;
|
||||||
|
|
||||||
BuildStepSimpleCommandArg *arg = s->arg;
|
BuildStepSimpleCommandArg *arg = s->arg;
|
||||||
SH_CommandResult result = RunCommand(scratch.arena, arg->cmd);
|
|
||||||
|
|
||||||
{
|
|
||||||
OS_Lock res_lock = OS_MutexLockE(&s->res_mutex);
|
|
||||||
|
|
||||||
|
AtomicI32 *skip_flag = arg->skip_flag;
|
||||||
|
AtomicI32 *failure_flag = arg->failure_flag;
|
||||||
|
if (!skip_flag || !AtomicI32Eval(skip_flag)) {
|
||||||
|
SH_CommandResult result = RunCommand(scratch.arena, arg->cmd);
|
||||||
String result_output_cleaned = CleanResultOutput(scratch.arena, result.output);
|
String result_output_cleaned = CleanResultOutput(scratch.arena, result.output);
|
||||||
if (result_output_cleaned.len > 0) {
|
{
|
||||||
OS_Lock sl_lock = OS_MutexLockE(&sl->mutex);
|
OS_Lock res_lock = OS_MutexLockE(&s->res_mutex);
|
||||||
{
|
if (result_output_cleaned.len > 0) {
|
||||||
s->res_output.text = ArenaPushArrayNoZero(&sl->arena, Byte, result_output_cleaned.len);
|
OS_Lock sl_lock = OS_MutexLockE(&sl->mutex);
|
||||||
|
{
|
||||||
|
s->res_output.text = ArenaPushArrayNoZero(&sl->arena, Byte, result_output_cleaned.len);
|
||||||
|
}
|
||||||
|
OS_MutexUnlock(&sl_lock);
|
||||||
|
s->res_output.len = result_output_cleaned.len;
|
||||||
|
MemoryCopy(s->res_output.text, result_output_cleaned.text, result_output_cleaned.len);
|
||||||
}
|
}
|
||||||
OS_MutexUnlock(&sl_lock);
|
s->res_status = result.error ? StepStatus_Failure : StepStatus_Success;
|
||||||
s->res_output.len = result_output_cleaned.len;
|
if (result.error && failure_flag) {
|
||||||
MemoryCopy(s->res_output.text, result_output_cleaned.text, result_output_cleaned.len);
|
AtomicI32EvalExchange(failure_flag, 1);
|
||||||
|
}
|
||||||
|
OS_ConditionVariableBroadcast(&s->res_cv);
|
||||||
|
OS_MutexUnlock(&res_lock);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
OS_Lock res_lock = OS_MutexLockE(&s->res_mutex);
|
||||||
|
s->res_status = StepStatus_Skipped;
|
||||||
|
if (failure_flag) {
|
||||||
|
AtomicI32EvalExchange(failure_flag, 1);
|
||||||
}
|
}
|
||||||
s->res_status = result.error ? StepStatus_Failure : StepStatus_Success;
|
|
||||||
OS_ConditionVariableBroadcast(&s->res_cv);
|
OS_ConditionVariableBroadcast(&s->res_cv);
|
||||||
OS_MutexUnlock(&res_lock);
|
OS_MutexUnlock(&res_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ScratchEnd(scratch);
|
ScratchEnd(scratch);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,28 +257,41 @@ void BuildStepMsvcCompileCommand(void *arg_raw)
|
|||||||
{
|
{
|
||||||
TempArena scratch = ScratchBeginNoConflict();
|
TempArena scratch = ScratchBeginNoConflict();
|
||||||
Step *s = arg_raw;
|
Step *s = arg_raw;
|
||||||
|
|
||||||
BuildStepMsvcCompileCommandArg *arg = s->arg;
|
BuildStepMsvcCompileCommandArg *arg = s->arg;
|
||||||
SH_CommandResult result = RunCommand(scratch.arena, arg->cmd);
|
|
||||||
|
|
||||||
if (!result.error && !D_IsNil(arg->depfile_dependent) && !D_IsNil(arg->output_depfile)) {
|
AtomicI32 *skip_flag = arg->skip_flag;
|
||||||
String depfile_data = D_DepfileTextFromMsvcOutput(scratch.arena, arg->depfile_dependent, arg->depfile_force_includes, result.output);
|
AtomicI32 *failure_flag = arg->failure_flag;
|
||||||
D_ClearWrite(arg->output_depfile, depfile_data);
|
if (!skip_flag || !AtomicI32Eval(skip_flag)) {
|
||||||
}
|
SH_CommandResult result = RunCommand(scratch.arena, arg->cmd);
|
||||||
|
if (!result.error && !D_IsNil(arg->depfile_dependent) && !D_IsNil(arg->output_depfile)) {
|
||||||
String result_output_cleaned = CleanResultOutput(scratch.arena, result.output);
|
String depfile_data = D_DepfileTextFromMsvcOutput(scratch.arena, arg->depfile_dependent, arg->depfile_force_includes, result.output);
|
||||||
{
|
D_ClearWrite(arg->output_depfile, depfile_data);
|
||||||
OS_Lock res_lock = OS_MutexLockE(&s->res_mutex);
|
}
|
||||||
if (result_output_cleaned.len > 0) {
|
String result_output_cleaned = CleanResultOutput(scratch.arena, result.output);
|
||||||
OS_Lock sl_lock = OS_MutexLockE(&sl->mutex);
|
{
|
||||||
{
|
OS_Lock res_lock = OS_MutexLockE(&s->res_mutex);
|
||||||
s->res_output.text = ArenaPushArrayNoZero(&sl->arena, Byte, result_output_cleaned.len);
|
if (result_output_cleaned.len > 0) {
|
||||||
}
|
OS_Lock sl_lock = OS_MutexLockE(&sl->mutex);
|
||||||
OS_MutexUnlock(&sl_lock);
|
{
|
||||||
s->res_output.len = result_output_cleaned.len;
|
s->res_output.text = ArenaPushArrayNoZero(&sl->arena, Byte, result_output_cleaned.len);
|
||||||
MemoryCopy(s->res_output.text, result_output_cleaned.text, result_output_cleaned.len);
|
}
|
||||||
|
OS_MutexUnlock(&sl_lock);
|
||||||
|
s->res_output.len = result_output_cleaned.len;
|
||||||
|
MemoryCopy(s->res_output.text, result_output_cleaned.text, result_output_cleaned.len);
|
||||||
|
}
|
||||||
|
s->res_status = result.error ? StepStatus_Failure : StepStatus_Success;
|
||||||
|
if (result.error && failure_flag) {
|
||||||
|
AtomicI32EvalExchange(failure_flag, 1);
|
||||||
|
}
|
||||||
|
OS_ConditionVariableBroadcast(&s->res_cv);
|
||||||
|
OS_MutexUnlock(&res_lock);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
OS_Lock res_lock = OS_MutexLockE(&s->res_mutex);
|
||||||
|
s->res_status = StepStatus_Skipped;
|
||||||
|
if (failure_flag) {
|
||||||
|
AtomicI32EvalExchange(failure_flag, 1);
|
||||||
}
|
}
|
||||||
s->res_status = result.error ? StepStatus_Failure : StepStatus_Success;
|
|
||||||
OS_ConditionVariableBroadcast(&s->res_cv);
|
OS_ConditionVariableBroadcast(&s->res_cv);
|
||||||
OS_MutexUnlock(&res_lock);
|
OS_MutexUnlock(&res_lock);
|
||||||
}
|
}
|
||||||
@ -605,6 +637,7 @@ void OnBuild(StringList cli_args)
|
|||||||
* Build step: Tar archives
|
* Build step: Tar archives
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
|
AtomicI32 tar_success_flag = { 0 };
|
||||||
{
|
{
|
||||||
AddSyncPoint();
|
AddSyncPoint();
|
||||||
|
|
||||||
@ -628,6 +661,7 @@ void OnBuild(StringList cli_args)
|
|||||||
if (IsDirty(tar_file)) {
|
if (IsDirty(tar_file)) {
|
||||||
BuildStepSimpleCommandArg *bs_arg = ArenaPush(&perm, BuildStepSimpleCommandArg);
|
BuildStepSimpleCommandArg *bs_arg = ArenaPush(&perm, BuildStepSimpleCommandArg);
|
||||||
bs_arg->cmd = StringF(&perm, Lit("cd %F && tar cvf %F ."), FmtStr(input_dir.full_path), FmtStr(tar_file.full_path));
|
bs_arg->cmd = StringF(&perm, Lit("cd %F && tar cvf %F ."), FmtStr(input_dir.full_path), FmtStr(tar_file.full_path));
|
||||||
|
bs_arg->failure_flag = &tar_success_flag;
|
||||||
String step_name = StringF(&perm, Lit("%F -> %F"), FmtStr(D_GetName(input_dir)), FmtStr(D_GetName(tar_file)));
|
String step_name = StringF(&perm, Lit("%F -> %F"), FmtStr(D_GetName(input_dir)), FmtStr(D_GetName(tar_file)));
|
||||||
AddStep(step_name, &BuildStepSimpleCommand, bs_arg);
|
AddStep(step_name, &BuildStepSimpleCommand, bs_arg);
|
||||||
}
|
}
|
||||||
@ -638,6 +672,7 @@ void OnBuild(StringList cli_args)
|
|||||||
* Build step: Compile RC files
|
* Build step: Compile RC files
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
|
AtomicI32 rc_success_flag = { 0 };
|
||||||
if (PlatformWindows) {
|
if (PlatformWindows) {
|
||||||
AddSyncPoint();
|
AddSyncPoint();
|
||||||
|
|
||||||
@ -671,6 +706,8 @@ void OnBuild(StringList cli_args)
|
|||||||
if (IsDirty(rc_res_file)) {
|
if (IsDirty(rc_res_file)) {
|
||||||
BuildStepSimpleCommandArg *bs_arg = ArenaPush(&perm, BuildStepSimpleCommandArg);
|
BuildStepSimpleCommandArg *bs_arg = ArenaPush(&perm, BuildStepSimpleCommandArg);
|
||||||
bs_arg->cmd = StringF(&perm, rc_compile_args_fmt, FmtStr(rc_res_file.full_path), FmtStr(rc_input_file.full_path));
|
bs_arg->cmd = StringF(&perm, rc_compile_args_fmt, FmtStr(rc_res_file.full_path), FmtStr(rc_input_file.full_path));
|
||||||
|
bs_arg->skip_flag = &tar_success_flag;
|
||||||
|
bs_arg->failure_flag = &rc_success_flag;
|
||||||
String step_name = StringF(&perm, Lit("%F -> %F"), FmtStr(D_GetName(rc_input_file)), FmtStr(D_GetName(rc_res_file)));
|
String step_name = StringF(&perm, Lit("%F -> %F"), FmtStr(D_GetName(rc_input_file)), FmtStr(D_GetName(rc_res_file)));
|
||||||
AddStep(step_name, &BuildStepSimpleCommand, bs_arg);
|
AddStep(step_name, &BuildStepSimpleCommand, bs_arg);
|
||||||
}
|
}
|
||||||
@ -683,6 +720,7 @@ void OnBuild(StringList cli_args)
|
|||||||
* Build step: Compile pch files
|
* Build step: Compile pch files
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
|
AtomicI32 pch_success_flag = { 0 };
|
||||||
D_TagList depfile_force_includes = { 0 };
|
D_TagList depfile_force_includes = { 0 };
|
||||||
{
|
{
|
||||||
AddSyncPoint();
|
AddSyncPoint();
|
||||||
@ -731,6 +769,8 @@ void OnBuild(StringList cli_args)
|
|||||||
bs_arg->cmd = StringF(&perm, pch_c_compile_args_fmt, FmtStr(pch_header_file.full_path), FmtStr(pch_c_src_gen_file.full_path));
|
bs_arg->cmd = StringF(&perm, pch_c_compile_args_fmt, FmtStr(pch_header_file.full_path), FmtStr(pch_c_src_gen_file.full_path));
|
||||||
bs_arg->depfile_dependent = pch_header_file;
|
bs_arg->depfile_dependent = pch_header_file;
|
||||||
bs_arg->output_depfile = dep_file;
|
bs_arg->output_depfile = dep_file;
|
||||||
|
bs_arg->skip_flag = &rc_success_flag;
|
||||||
|
bs_arg->failure_flag = &pch_success_flag;
|
||||||
String step_name = StringF(&perm, Lit("%F -> %F"), FmtStr(D_GetName(pch_header_file)), FmtStr(D_GetName(pch_c_file)));
|
String step_name = StringF(&perm, Lit("%F -> %F"), FmtStr(D_GetName(pch_header_file)), FmtStr(D_GetName(pch_c_file)));
|
||||||
AddStep(step_name, &BuildStepMsvcCompileCommand, bs_arg);
|
AddStep(step_name, &BuildStepMsvcCompileCommand, bs_arg);
|
||||||
}
|
}
|
||||||
@ -744,6 +784,8 @@ void OnBuild(StringList cli_args)
|
|||||||
bs_arg->cmd = StringF(&perm, pch_cpp_compile_args_fmt, FmtStr(pch_header_file.full_path), FmtStr(pch_cpp_src_gen_file.full_path));
|
bs_arg->cmd = StringF(&perm, pch_cpp_compile_args_fmt, FmtStr(pch_header_file.full_path), FmtStr(pch_cpp_src_gen_file.full_path));
|
||||||
bs_arg->depfile_dependent = pch_header_file;
|
bs_arg->depfile_dependent = pch_header_file;
|
||||||
bs_arg->output_depfile = dep_file;
|
bs_arg->output_depfile = dep_file;
|
||||||
|
bs_arg->skip_flag = &rc_success_flag;
|
||||||
|
bs_arg->failure_flag = &pch_success_flag;
|
||||||
String step_name = StringF(&perm, Lit("%F -> %F"), FmtStr(D_GetName(pch_header_file)), FmtStr(D_GetName(pch_cpp_file)));
|
String step_name = StringF(&perm, Lit("%F -> %F"), FmtStr(D_GetName(pch_header_file)), FmtStr(D_GetName(pch_cpp_file)));
|
||||||
AddStep(step_name, &BuildStepMsvcCompileCommand, bs_arg);
|
AddStep(step_name, &BuildStepMsvcCompileCommand, bs_arg);
|
||||||
}
|
}
|
||||||
@ -758,6 +800,8 @@ void OnBuild(StringList cli_args)
|
|||||||
if (IsDirty(pch_c_file)) {
|
if (IsDirty(pch_c_file)) {
|
||||||
BuildStepSimpleCommandArg *bs_arg = ArenaPush(&perm, BuildStepSimpleCommandArg);
|
BuildStepSimpleCommandArg *bs_arg = ArenaPush(&perm, BuildStepSimpleCommandArg);
|
||||||
bs_arg->cmd = StringF(&perm, pch_c_compile_args_fmt, FmtStr(pch_header_file.full_path), FmtStr(pch_c_file.full_path));
|
bs_arg->cmd = StringF(&perm, pch_c_compile_args_fmt, FmtStr(pch_header_file.full_path), FmtStr(pch_c_file.full_path));
|
||||||
|
bs_arg->skip_flag = &rc_success_flag;
|
||||||
|
bs_arg->failure_flag = &pch_success_flag;
|
||||||
String step_name = StringF(&perm, Lit("%F -> %F"), FmtStr(D_GetName(pch_header_file)), FmtStr(D_GetName(pch_c_file)));
|
String step_name = StringF(&perm, Lit("%F -> %F"), FmtStr(D_GetName(pch_header_file)), FmtStr(D_GetName(pch_c_file)));
|
||||||
AddStep(step_name, &BuildStepSimpleCommand, bs_arg);
|
AddStep(step_name, &BuildStepSimpleCommand, bs_arg);
|
||||||
}
|
}
|
||||||
@ -766,6 +810,8 @@ void OnBuild(StringList cli_args)
|
|||||||
if (IsDirty(pch_cpp_file)) {
|
if (IsDirty(pch_cpp_file)) {
|
||||||
BuildStepSimpleCommandArg *bs_arg = ArenaPush(&perm, BuildStepSimpleCommandArg);
|
BuildStepSimpleCommandArg *bs_arg = ArenaPush(&perm, BuildStepSimpleCommandArg);
|
||||||
bs_arg->cmd = StringF(&perm, pch_cpp_compile_args_fmt, FmtStr(pch_header_file.full_path), FmtStr(pch_cpp_file.full_path));
|
bs_arg->cmd = StringF(&perm, pch_cpp_compile_args_fmt, FmtStr(pch_header_file.full_path), FmtStr(pch_cpp_file.full_path));
|
||||||
|
bs_arg->skip_flag = &rc_success_flag;
|
||||||
|
bs_arg->failure_flag = &pch_success_flag;
|
||||||
String step_name = StringF(&perm, Lit("%F -> %F"), FmtStr(D_GetName(pch_header_file)), FmtStr(D_GetName(pch_cpp_file)));
|
String step_name = StringF(&perm, Lit("%F -> %F"), FmtStr(D_GetName(pch_header_file)), FmtStr(D_GetName(pch_cpp_file)));
|
||||||
AddStep(step_name, &BuildStepSimpleCommand, bs_arg);
|
AddStep(step_name, &BuildStepSimpleCommand, bs_arg);
|
||||||
}
|
}
|
||||||
@ -776,6 +822,7 @@ void OnBuild(StringList cli_args)
|
|||||||
* Build step: Compile src files
|
* Build step: Compile src files
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
|
AtomicI32 src_success_flag = { 0 };
|
||||||
{
|
{
|
||||||
D_TagList src_input_files = { 0 };
|
D_TagList src_input_files = { 0 };
|
||||||
{
|
{
|
||||||
@ -864,10 +911,14 @@ void OnBuild(StringList cli_args)
|
|||||||
bs_arg->depfile_dependent = obj_file;
|
bs_arg->depfile_dependent = obj_file;
|
||||||
bs_arg->output_depfile = dep_file;
|
bs_arg->output_depfile = dep_file;
|
||||||
bs_arg->depfile_force_includes = depfile_force_includes;
|
bs_arg->depfile_force_includes = depfile_force_includes;
|
||||||
|
bs_arg->skip_flag = &pch_success_flag;
|
||||||
|
bs_arg->failure_flag = &src_success_flag;
|
||||||
AddStep(step_name, &BuildStepMsvcCompileCommand, bs_arg);
|
AddStep(step_name, &BuildStepMsvcCompileCommand, bs_arg);
|
||||||
} else {
|
} else {
|
||||||
BuildStepSimpleCommandArg *bs_arg = ArenaPush(&perm, BuildStepSimpleCommandArg);
|
BuildStepSimpleCommandArg *bs_arg = ArenaPush(&perm, BuildStepSimpleCommandArg);
|
||||||
bs_arg->cmd = StringF(&perm, comp_cmd_fmt, FmtStr(file.full_path), FmtStr(obj_file.full_path));
|
bs_arg->cmd = StringF(&perm, comp_cmd_fmt, FmtStr(file.full_path), FmtStr(obj_file.full_path));
|
||||||
|
bs_arg->skip_flag = &pch_success_flag;
|
||||||
|
bs_arg->failure_flag = &src_success_flag;
|
||||||
AddStep(step_name, &BuildStepSimpleCommand, bs_arg);
|
AddStep(step_name, &BuildStepSimpleCommand, bs_arg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -899,6 +950,7 @@ void OnBuild(StringList cli_args)
|
|||||||
String link_args_fmt = StringFromStringLists(&perm, Lit(" "), link_args, link_warnings, compile_and_link_args);
|
String link_args_fmt = StringFromStringLists(&perm, Lit(" "), link_args, link_warnings, compile_and_link_args);
|
||||||
BuildStepSimpleCommandArg *bs_arg = ArenaPush(&perm, BuildStepSimpleCommandArg);
|
BuildStepSimpleCommandArg *bs_arg = ArenaPush(&perm, BuildStepSimpleCommandArg);
|
||||||
bs_arg->cmd = StringF(&perm, link_args_fmt, FmtStr(link_files_str), FmtStr(executable_file.full_path));
|
bs_arg->cmd = StringF(&perm, link_args_fmt, FmtStr(link_files_str), FmtStr(executable_file.full_path));
|
||||||
|
bs_arg->skip_flag = &src_success_flag;
|
||||||
String step_name = Lit("Linking");
|
String step_name = Lit("Linking");
|
||||||
AddStep(step_name, &BuildStepSimpleCommand, bs_arg);
|
AddStep(step_name, &BuildStepSimpleCommand, bs_arg);
|
||||||
}
|
}
|
||||||
@ -918,8 +970,6 @@ void OnBuild(StringList cli_args)
|
|||||||
while (s) {
|
while (s) {
|
||||||
++step_i;
|
++step_i;
|
||||||
|
|
||||||
SH_PrintF(Lit("[%F/%F] %F\n"), FmtI64(step_i), FmtI64(step_count), FmtStr(s->name));
|
|
||||||
|
|
||||||
{
|
{
|
||||||
OS_Lock lock = OS_MutexLockS(&s->res_mutex);
|
OS_Lock lock = OS_MutexLockS(&s->res_mutex);
|
||||||
while (s->res_status == StepStatus_None) {
|
while (s->res_status == StepStatus_None) {
|
||||||
@ -929,10 +979,11 @@ void OnBuild(StringList cli_args)
|
|||||||
}
|
}
|
||||||
|
|
||||||
String output = s->res_output;
|
String output = s->res_output;
|
||||||
if (s->res_status != StepStatus_Success) {
|
if (s->res_status == StepStatus_Success) {
|
||||||
Assert(false);
|
SH_PrintF(Lit("[%F/%F] %F\n"), FmtI64(step_i), FmtI64(step_count), FmtStr(s->name));
|
||||||
|
} else if (s->res_status == StepStatus_Failure) {
|
||||||
success = false;
|
success = false;
|
||||||
SH_PrintF(Lit("%F\n\n"), FmtStr(output));
|
SH_PrintF(Lit("[%F/%F] %F\n\n%F\n\n"), FmtI64(step_i), FmtI64(step_count), FmtStr(s->name), FmtStr(output));
|
||||||
}
|
}
|
||||||
|
|
||||||
s = s->next;
|
s = s->next;
|
||||||
@ -943,9 +994,11 @@ void OnBuild(StringList cli_args)
|
|||||||
SH_Print(Lit("No work to do\n"));
|
SH_Print(Lit("No work to do\n"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
if (!success) {
|
if (!success) {
|
||||||
Error(Lit("Build failed\n"));
|
Error(Lit("Build failed\n"));
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
T_ShutdownWorkers();
|
T_ShutdownWorkers();
|
||||||
D_WriteStoreToHistFile(&store, hist_path);
|
D_WriteStoreToHistFile(&store, hist_path);
|
||||||
|
|||||||
10
src/app.c
10
src/app.c
@ -131,6 +131,16 @@ void app_entry_point(struct string args_str)
|
|||||||
{
|
{
|
||||||
struct temp_arena scratch = scratch_begin_no_conflict();
|
struct temp_arena scratch = scratch_begin_no_conflict();
|
||||||
|
|
||||||
|
#if !RTC
|
||||||
|
/* Check that test modes aren't left on by accident in release mode */
|
||||||
|
CT_ASSERT(BITBUFF_DEBUG == 0);
|
||||||
|
CT_ASSERT(BITBUFF_TEST == 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if BITBUFF_TEST
|
||||||
|
bitbuff_test();
|
||||||
|
#endif
|
||||||
|
|
||||||
G.exit_sf = sync_flag_alloc();
|
G.exit_sf = sync_flag_alloc();
|
||||||
G.exit_callbacks_mutex = sys_mutex_alloc();
|
G.exit_callbacks_mutex = sys_mutex_alloc();
|
||||||
G.exit_callbacks_arena = arena_alloc(GIGABYTE(64));
|
G.exit_callbacks_arena = arena_alloc(GIGABYTE(64));
|
||||||
|
|||||||
193
src/ase.c
193
src/ase.c
@ -7,7 +7,7 @@
|
|||||||
#include "ase.h"
|
#include "ase.h"
|
||||||
#include "arena.h"
|
#include "arena.h"
|
||||||
#include "scratch.h"
|
#include "scratch.h"
|
||||||
#include "byteio.h"
|
#include "bitbuff.h"
|
||||||
#include "string.h"
|
#include "string.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
|
||||||
@ -15,12 +15,12 @@
|
|||||||
* Bitbuf
|
* Bitbuf
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
struct bitbuf {
|
struct huff_bb {
|
||||||
u8 *data;
|
u8 *data;
|
||||||
u64 cur_bit;
|
u64 cur_bit;
|
||||||
};
|
};
|
||||||
|
|
||||||
INTERNAL u32 peek_bits(struct bitbuf *bb, u32 nbits)
|
INTERNAL u32 peek_bits(struct huff_bb *bb, u32 nbits)
|
||||||
{
|
{
|
||||||
ASSERT(nbits <= 32);
|
ASSERT(nbits <= 32);
|
||||||
|
|
||||||
@ -36,14 +36,14 @@ INTERNAL u32 peek_bits(struct bitbuf *bb, u32 nbits)
|
|||||||
return val32;
|
return val32;
|
||||||
}
|
}
|
||||||
|
|
||||||
INTERNAL u32 consume_bits(struct bitbuf *bb, u32 nbits)
|
INTERNAL u32 consume_bits(struct huff_bb *bb, u32 nbits)
|
||||||
{
|
{
|
||||||
u32 val = peek_bits(bb, nbits);
|
u32 val = peek_bits(bb, nbits);
|
||||||
bb->cur_bit += nbits;
|
bb->cur_bit += nbits;
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
INTERNAL void skip_bits(struct bitbuf *bb, u32 nbits)
|
INTERNAL void skip_bits(struct huff_bb *bb, u32 nbits)
|
||||||
{
|
{
|
||||||
bb->cur_bit += nbits;
|
bb->cur_bit += nbits;
|
||||||
}
|
}
|
||||||
@ -227,7 +227,7 @@ INTERNAL struct huffman huffman_init(struct arena *arena, u32 max_code_bits, u32
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
INTERNAL u16 huffman_decode(struct huffman *huffman, struct bitbuf *bb)
|
INTERNAL u16 huffman_decode(struct huffman *huffman, struct huff_bb *bb)
|
||||||
{
|
{
|
||||||
u32 index = peek_bits(bb, huffman->max_code_bits);
|
u32 index = peek_bits(bb, huffman->max_code_bits);
|
||||||
ASSERT(index < huffman->entries_count);
|
ASSERT(index < huffman->entries_count);
|
||||||
@ -240,12 +240,12 @@ INTERNAL u16 huffman_decode(struct huffman *huffman, struct bitbuf *bb)
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
INTERNAL void inflate(u8 *dest, u8 *encoded)
|
INTERNAL void inflate(u8 *dst, u8 *encoded)
|
||||||
{
|
{
|
||||||
struct temp_arena scratch = scratch_begin_no_conflict();
|
struct temp_arena scratch = scratch_begin_no_conflict();
|
||||||
|
|
||||||
__prof;
|
__prof;
|
||||||
struct bitbuf bb = { .data = encoded };
|
struct huff_bb bb = { .data = encoded };
|
||||||
|
|
||||||
/* ZLIB header */
|
/* ZLIB header */
|
||||||
u32 cm = consume_bits(&bb, 4);
|
u32 cm = consume_bits(&bb, 4);
|
||||||
@ -345,7 +345,7 @@ INTERNAL void inflate(u8 *dest, u8 *encoded)
|
|||||||
while (true) {
|
while (true) {
|
||||||
u32 lit_len = huffman_decode(&lit_len_huffman, &bb);
|
u32 lit_len = huffman_decode(&lit_len_huffman, &bb);
|
||||||
if (lit_len <= 255) {
|
if (lit_len <= 255) {
|
||||||
*dest++ = lit_len & 0xFF;
|
*dst++ = lit_len & 0xFF;
|
||||||
} else if (lit_len >= 257) {
|
} else if (lit_len >= 257) {
|
||||||
u32 length_index = (lit_len - 257);
|
u32 length_index = (lit_len - 257);
|
||||||
struct huffman_entry length_entry = g_length_table[length_index];
|
struct huffman_entry length_entry = g_length_table[length_index];
|
||||||
@ -362,9 +362,9 @@ INTERNAL void inflate(u8 *dest, u8 *encoded)
|
|||||||
u32 extra_bits = consume_bits(&bb, dist_entry.bits_used);
|
u32 extra_bits = consume_bits(&bb, dist_entry.bits_used);
|
||||||
distance += extra_bits;
|
distance += extra_bits;
|
||||||
}
|
}
|
||||||
u8 *source = dest - distance;
|
u8 *source = dst - distance;
|
||||||
while (length--) {
|
while (length--) {
|
||||||
*dest++ = *source++;
|
*dst++ = *source++;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
@ -505,12 +505,12 @@ INTERNAL u32 mul_u8(u32 a, u32 b)
|
|||||||
return ((t >> 8) + t) >> 8;
|
return ((t >> 8) + t) >> 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
INTERNAL u32 blend(u32 src, u32 dest, u8 opacity)
|
INTERNAL u32 blend(u32 src, u32 dst, u8 opacity)
|
||||||
{
|
{
|
||||||
u32 dest_r = (dest & 0xff);
|
u32 dst_r = (dst & 0xff);
|
||||||
u32 dest_g = (dest >> 8) & 0xff;
|
u32 dst_g = (dst >> 8) & 0xff;
|
||||||
u32 dest_b = (dest >> 16) & 0xff;
|
u32 dst_b = (dst >> 16) & 0xff;
|
||||||
u32 dest_a = (dest >> 24) & 0xff;
|
u32 dst_a = (dst >> 24) & 0xff;
|
||||||
|
|
||||||
u32 src_r = (src & 0xff);
|
u32 src_r = (src & 0xff);
|
||||||
u32 src_g = (src >> 8) & 0xff;
|
u32 src_g = (src >> 8) & 0xff;
|
||||||
@ -518,14 +518,14 @@ INTERNAL u32 blend(u32 src, u32 dest, u8 opacity)
|
|||||||
u32 src_a = (src >> 24) & 0xff;
|
u32 src_a = (src >> 24) & 0xff;
|
||||||
|
|
||||||
src_a = (u8)mul_u8(src_a, opacity);
|
src_a = (u8)mul_u8(src_a, opacity);
|
||||||
u32 a = src_a + dest_a - mul_u8(src_a, dest_a);
|
u32 a = src_a + dst_a - mul_u8(src_a, dst_a);
|
||||||
u32 r, g, b;
|
u32 r, g, b;
|
||||||
if (a == 0) {
|
if (a == 0) {
|
||||||
r = g = b = 0;
|
r = g = b = 0;
|
||||||
} else {
|
} else {
|
||||||
r = dest_r + (src_r - dest_r) * src_a / a;
|
r = dst_r + (src_r - dst_r) * src_a / a;
|
||||||
g = dest_g + (src_g - dest_g) * src_a / a;
|
g = dst_g + (src_g - dst_g) * src_a / a;
|
||||||
b = dest_b + (src_b - dest_b) * src_a / a;
|
b = dst_b + (src_b - dst_b) * src_a / a;
|
||||||
}
|
}
|
||||||
|
|
||||||
return r | (g << 8) | (b << 16) | (a << 24);
|
return r | (g << 8) | (b << 16) | (a << 24);
|
||||||
@ -558,9 +558,10 @@ struct ase_decode_image_result ase_decode_image(struct arena *arena, struct stri
|
|||||||
struct temp_arena scratch = scratch_begin(arena);
|
struct temp_arena scratch = scratch_begin(arena);
|
||||||
struct ase_decode_image_result res = ZI;
|
struct ase_decode_image_result res = ZI;
|
||||||
|
|
||||||
struct byte_reader br = br_from_buffer(encoded);
|
struct bitbuff bb = bitbuff_from_string(encoded);
|
||||||
|
struct bitbuff_reader br = br_from_bitbuff_no_debug(&bb);
|
||||||
struct ase_header ase_header;
|
struct ase_header ase_header;
|
||||||
br_read_to_struct(&br, &ase_header);
|
br_read_bytes(&br, STRING_FROM_STRUCT(&ase_header));
|
||||||
|
|
||||||
if (ase_header.magic != 0xA5E0) {
|
if (ase_header.magic != 0xA5E0) {
|
||||||
push_error_copy_msg(arena, &res.errors, LIT("Not a valid aseprite file"));
|
push_error_copy_msg(arena, &res.errors, LIT("Not a valid aseprite file"));
|
||||||
@ -599,7 +600,7 @@ struct ase_decode_image_result ase_decode_image(struct arena *arena, struct stri
|
|||||||
u32 num_frames = 0;
|
u32 num_frames = 0;
|
||||||
for (u16 i = 0; i < ase_header.frames; ++i) {
|
for (u16 i = 0; i < ase_header.frames; ++i) {
|
||||||
struct frame_header frame_header;
|
struct frame_header frame_header;
|
||||||
br_read_to_struct(&br, &frame_header);
|
br_read_bytes(&br, STRING_FROM_STRUCT(&frame_header));
|
||||||
|
|
||||||
u32 num_chunks = frame_header.chunks_new;
|
u32 num_chunks = frame_header.chunks_new;
|
||||||
if (num_chunks == 0) {
|
if (num_chunks == 0) {
|
||||||
@ -609,14 +610,14 @@ struct ase_decode_image_result ase_decode_image(struct arena *arena, struct stri
|
|||||||
|
|
||||||
/* Iterate chunks in frame */
|
/* Iterate chunks in frame */
|
||||||
for (u32 j = 0; j < num_chunks; ++j) {
|
for (u32 j = 0; j < num_chunks; ++j) {
|
||||||
u32 chunk_size = br_read_u32(&br);
|
u32 chunk_size = br_read_ubits(&br, 32);
|
||||||
enum chunk_type chunk_type = br_read_u16(&br);
|
enum chunk_type chunk_type = br_read_ubits(&br, 16);
|
||||||
|
|
||||||
/* Chunk size includes size & type */
|
/* Chunk size includes size & type */
|
||||||
ASSERT(chunk_size >= 6);
|
ASSERT(chunk_size >= 6);
|
||||||
chunk_size -= 6;
|
chunk_size -= 6;
|
||||||
|
|
||||||
u64 chunk_end_pos = br_pos(&br) + chunk_size;
|
u64 chunk_end_pos = br_cur_byte(&br) + chunk_size;
|
||||||
|
|
||||||
switch (chunk_type) {
|
switch (chunk_type) {
|
||||||
case CHUNK_TYPE_LAYER: {
|
case CHUNK_TYPE_LAYER: {
|
||||||
@ -624,14 +625,14 @@ struct ase_decode_image_result ase_decode_image(struct arena *arena, struct stri
|
|||||||
layer->next = layer_head;
|
layer->next = layer_head;
|
||||||
layer_head = layer;
|
layer_head = layer;
|
||||||
|
|
||||||
layer->flags = br_read_u16(&br);
|
layer->flags = br_read_ubits(&br, 16);
|
||||||
layer->type = br_read_u16(&br);
|
layer->type = br_read_ubits(&br, 16);
|
||||||
layer->child_level = br_read_u16(&br);
|
layer->child_level = br_read_ubits(&br, 16);
|
||||||
|
|
||||||
/* Ignoring layer default width & height */
|
/* Ignoring layer default width & height */
|
||||||
br_seek(&br, sizeof(u16) * 2);
|
br_seek_bytes(&br, sizeof(u16) * 2);
|
||||||
|
|
||||||
layer->blend_mode = br_read_u16(&br);
|
layer->blend_mode = br_read_ubits(&br, 16);
|
||||||
if (layer->blend_mode != 0) {
|
if (layer->blend_mode != 0) {
|
||||||
push_error_copy_msg(arena,
|
push_error_copy_msg(arena,
|
||||||
&res.errors,
|
&res.errors,
|
||||||
@ -639,26 +640,19 @@ struct ase_decode_image_result ase_decode_image(struct arena *arena, struct stri
|
|||||||
goto abort;
|
goto abort;
|
||||||
}
|
}
|
||||||
|
|
||||||
layer->opacity = br_read_u8(&br);
|
layer->opacity = br_read_ubits(&br, 8);
|
||||||
if (!(ase_header.flags & 1)) {
|
if (!(ase_header.flags & 1)) {
|
||||||
layer->opacity = 255;
|
layer->opacity = 255;
|
||||||
}
|
}
|
||||||
|
|
||||||
br_seek(&br, sizeof(u8) * 3);
|
br_seek_bytes(&br, sizeof(u8) * 3);
|
||||||
|
|
||||||
u16 str_len = br_read_u16(&br);
|
u16 str_len = br_read_ubits(&br, 16);
|
||||||
u8 *str_bytes = br_seek(&br, str_len);
|
layer->name = (struct string) { str_len, arena_push_array(scratch.arena, u8, str_len) };
|
||||||
if (!str_bytes) {
|
br_read_bytes(&br, layer->name);
|
||||||
str_len = 0;
|
|
||||||
}
|
|
||||||
layer->name = (struct string) {
|
|
||||||
str_len,
|
|
||||||
arena_push_array(scratch.arena, u8, str_len)
|
|
||||||
};
|
|
||||||
MEMCPY(layer->name.text, str_bytes, str_len);
|
|
||||||
|
|
||||||
if (layer->type == 2) {
|
if (layer->type == 2) {
|
||||||
layer->tileset_index = br_read_u32(&br);
|
layer->tileset_index = br_read_ubits(&br, 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
layer->index = num_layers++;
|
layer->index = num_layers++;
|
||||||
@ -673,35 +667,36 @@ struct ase_decode_image_result ase_decode_image(struct arena *arena, struct stri
|
|||||||
}
|
}
|
||||||
cel_tail = cel;
|
cel_tail = cel;
|
||||||
|
|
||||||
cel->layer_index = br_read_u16(&br);
|
cel->layer_index = br_read_ubits(&br, 16);
|
||||||
cel->x_pos = br_read_i16(&br);
|
cel->x_pos = br_read_ibits(&br, 16);
|
||||||
cel->y_pos = br_read_i16(&br);
|
cel->y_pos = br_read_ibits(&br, 16);
|
||||||
cel->opacity = br_read_u8(&br);
|
cel->opacity = br_read_ubits(&br, 8);
|
||||||
cel->type = br_read_u16(&br);
|
cel->type = br_read_ubits(&br, 16);
|
||||||
cel->z_index = br_read_i16(&br);
|
cel->z_index = br_read_ibits(&br, 16);
|
||||||
br_seek(&br, sizeof(u8) * 5);
|
br_seek_bytes(&br, sizeof(u8) * 5);
|
||||||
|
|
||||||
cel->frame_index = num_frames;
|
cel->frame_index = num_frames;
|
||||||
|
|
||||||
switch (cel->type) {
|
switch (cel->type) {
|
||||||
case CEL_TYPE_RAW_IMAGE: {
|
case CEL_TYPE_RAW_IMAGE: {
|
||||||
/* Unsupported */
|
/* Unsupported */
|
||||||
br_seek_to(&br, chunk_end_pos);
|
br_seek_to_byte(&br, chunk_end_pos);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case CEL_TYPE_LINKED: {
|
case CEL_TYPE_LINKED: {
|
||||||
cel->frame_pos = br_read_u16(&br);
|
cel->frame_pos = br_read_ubits(&br, 16);
|
||||||
/* Actual linking happens later after iteration */
|
/* Actual linking happens later after iteration */
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case CEL_TYPE_COMPRESSED_IMAGE: {
|
case CEL_TYPE_COMPRESSED_IMAGE: {
|
||||||
cel->width = br_read_u16(&br);
|
cel->width = br_read_ubits(&br, 16);
|
||||||
cel->height = br_read_u16(&br);
|
cel->height = br_read_ubits(&br, 16);
|
||||||
|
|
||||||
cel->pixels = arena_push_array(scratch.arena, u32, cel->width * cel->height);
|
cel->pixels = arena_push_array(scratch.arena, u32, cel->width * cel->height);
|
||||||
inflate((u8 *)cel->pixels, br.at);
|
u8 *huffman_encoded = br_read_bytes_raw(&br, chunk_end_pos - br_cur_byte(&br));
|
||||||
|
if (huffman_encoded) {
|
||||||
br_seek_to(&br, chunk_end_pos);
|
inflate((u8 *)cel->pixels, huffman_encoded);
|
||||||
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case CEL_TYPE_COMPRESSED_TILEMAP: {
|
case CEL_TYPE_COMPRESSED_TILEMAP: {
|
||||||
@ -713,7 +708,7 @@ struct ase_decode_image_result ase_decode_image(struct arena *arena, struct stri
|
|||||||
} break;
|
} break;
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
br_seek_to(&br, chunk_end_pos);
|
br_seek_to_byte(&br, chunk_end_pos);
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -802,7 +797,7 @@ struct ase_decode_image_result ase_decode_image(struct arena *arena, struct stri
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ASSERT all data was read */
|
/* ASSERT all data was read */
|
||||||
ASSERT(br_bytes_left(&br) == 0);
|
ASSERT(br_num_bytes_left(&br) == 0);
|
||||||
|
|
||||||
abort:
|
abort:
|
||||||
|
|
||||||
@ -820,9 +815,10 @@ struct ase_decode_sheet_result ase_decode_sheet(struct arena *arena, struct stri
|
|||||||
|
|
||||||
struct ase_decode_sheet_result res = ZI;
|
struct ase_decode_sheet_result res = ZI;
|
||||||
|
|
||||||
struct byte_reader br = br_from_buffer(encoded);
|
struct bitbuff bb = bitbuff_from_string(encoded);
|
||||||
|
struct bitbuff_reader br = br_from_bitbuff_no_debug(&bb);
|
||||||
struct ase_header ase_header;
|
struct ase_header ase_header;
|
||||||
br_read_to_struct(&br, &ase_header);
|
br_read_bytes(&br, STRING_FROM_STRUCT(&ase_header));
|
||||||
|
|
||||||
u64 frame_width = ase_header.width;
|
u64 frame_width = ase_header.width;
|
||||||
u64 frame_height = ase_header.height;
|
u64 frame_height = ase_header.height;
|
||||||
@ -845,7 +841,7 @@ struct ase_decode_sheet_result ase_decode_sheet(struct arena *arena, struct stri
|
|||||||
/* Iterate frames */
|
/* Iterate frames */
|
||||||
for (u16 i = 0; i < ase_header.frames; ++i) {
|
for (u16 i = 0; i < ase_header.frames; ++i) {
|
||||||
struct frame_header frame_header;
|
struct frame_header frame_header;
|
||||||
br_read_to_struct(&br, &frame_header);
|
br_read_bytes(&br, STRING_FROM_STRUCT(&frame_header));
|
||||||
|
|
||||||
u32 num_chunks = frame_header.chunks_new;
|
u32 num_chunks = frame_header.chunks_new;
|
||||||
if (num_chunks == 0) {
|
if (num_chunks == 0) {
|
||||||
@ -877,39 +873,33 @@ struct ase_decode_sheet_result ase_decode_sheet(struct arena *arena, struct stri
|
|||||||
|
|
||||||
/* Iterate chunks in frame */
|
/* Iterate chunks in frame */
|
||||||
for (u32 j = 0; j < num_chunks; ++j) {
|
for (u32 j = 0; j < num_chunks; ++j) {
|
||||||
u32 chunk_size = br_read_u32(&br);
|
u32 chunk_size = br_read_ubits(&br, 32);
|
||||||
enum chunk_type chunk_type = br_read_u16(&br);
|
enum chunk_type chunk_type = br_read_ubits(&br, 16);
|
||||||
|
|
||||||
/* Chunk size includes size & type */
|
/* Chunk size includes size & type */
|
||||||
ASSERT(chunk_size >= 6);
|
ASSERT(chunk_size >= 6);
|
||||||
chunk_size -= 6;
|
chunk_size -= 6;
|
||||||
|
|
||||||
u64 chunk_end_pos = br_pos(&br) + chunk_size;
|
u64 chunk_end_pos = br_cur_byte(&br) + chunk_size;
|
||||||
|
|
||||||
switch (chunk_type) {
|
switch (chunk_type) {
|
||||||
case CHUNK_TYPE_TAGS: {
|
case CHUNK_TYPE_TAGS: {
|
||||||
u16 frame_span_count = br_read_u16(&br);
|
u16 frame_span_count = br_read_ubits(&br, 16);
|
||||||
br_seek(&br, 8);
|
br_seek_bytes(&br, 8);
|
||||||
|
|
||||||
for (u16 k = 0; k < frame_span_count; ++k) {
|
for (u16 k = 0; k < frame_span_count; ++k) {
|
||||||
struct ase_span *span = arena_push_zero(arena, struct ase_span);
|
struct ase_span *span = arena_push_zero(arena, struct ase_span);
|
||||||
span->next = span_head;
|
span->next = span_head;
|
||||||
span_head = span;
|
span_head = span;
|
||||||
|
|
||||||
span->start = br_read_u16(&br);
|
span->start = br_read_ubits(&br, 16);
|
||||||
span->end = br_read_u16(&br);
|
span->end = br_read_ubits(&br, 16);
|
||||||
br_seek(&br, 13);
|
br_seek_bytes(&br, 13);
|
||||||
|
|
||||||
|
u16 str_len = br_read_ubits(&br, 16);
|
||||||
|
span->name = (struct string) { str_len, arena_push_array(arena, u8, str_len) };
|
||||||
|
br_read_bytes(&br, span->name);
|
||||||
|
|
||||||
u16 str_len = br_read_u16(&br);
|
|
||||||
u8 *str_bytes = br_seek(&br, str_len);
|
|
||||||
if (!str_bytes) {
|
|
||||||
str_len = 0;
|
|
||||||
}
|
|
||||||
span->name = (struct string) {
|
|
||||||
str_len,
|
|
||||||
arena_push_array(arena, u8, str_len)
|
|
||||||
};
|
|
||||||
MEMCPY(span->name.text, str_bytes, str_len);
|
|
||||||
++num_spans;
|
++num_spans;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -920,44 +910,33 @@ struct ase_decode_sheet_result ase_decode_sheet(struct arena *arena, struct stri
|
|||||||
slice_key->next = slice_key_head;
|
slice_key->next = slice_key_head;
|
||||||
slice_key_head = slice_key;
|
slice_key_head = slice_key;
|
||||||
|
|
||||||
u32 num_slices = br_read_u32(&br);
|
u32 num_slices = br_read_ubits(&br, 32);
|
||||||
slice_key->num_slices = num_slices;
|
slice_key->num_slices = num_slices;
|
||||||
|
|
||||||
u32 flags = br_read_u32(&br);
|
u32 flags = br_read_ubits(&br, 32);
|
||||||
br_seek(&br, 4);
|
br_seek_bytes(&br, 4);
|
||||||
|
|
||||||
struct string name;
|
u16 str_len = br_read_ubits(&br, 16);
|
||||||
{
|
slice_key->name = (struct string) { str_len, arena_push_array(arena, u8, str_len) };
|
||||||
u16 str_len = br_read_u16(&br);
|
br_read_bytes(&br, slice_key->name);
|
||||||
u8 *str_bytes = br_seek(&br, str_len);
|
|
||||||
if (!str_bytes) {
|
|
||||||
str_len = 0;
|
|
||||||
}
|
|
||||||
name = (struct string) {
|
|
||||||
str_len,
|
|
||||||
arena_push_array(arena, u8, str_len)
|
|
||||||
};
|
|
||||||
MEMCPY(name.text, str_bytes, str_len);
|
|
||||||
}
|
|
||||||
slice_key->name = name;
|
|
||||||
|
|
||||||
for (u32 k = 0; k < num_slices; ++k) {
|
for (u32 k = 0; k < num_slices; ++k) {
|
||||||
struct ase_slice *slice = arena_push_zero(arena, struct ase_slice);
|
struct ase_slice *slice = arena_push_zero(arena, struct ase_slice);
|
||||||
slice->next = slice_key->slice_head;
|
slice->next = slice_key->slice_head;
|
||||||
slice_key->slice_head = slice;
|
slice_key->slice_head = slice;
|
||||||
|
|
||||||
u32 start = br_read_u32(&br);
|
u32 start = br_read_ubits(&br, 32);
|
||||||
i32 x = br_read_i32(&br);
|
i32 x = br_read_ibits(&br, 32);
|
||||||
i32 y = br_read_i32(&br);
|
i32 y = br_read_ibits(&br, 32);
|
||||||
u32 width = br_read_u32(&br);
|
u32 width = br_read_ubits(&br, 32);
|
||||||
u32 height = br_read_u32(&br);
|
u32 height = br_read_ubits(&br, 32);
|
||||||
if (flags & 0x01) {
|
if (flags & 0x01) {
|
||||||
/* Skip 9-patches info */
|
/* Skip 9-patches info */
|
||||||
br_seek(&br, 128);
|
br_seek_bytes(&br, 128);
|
||||||
}
|
}
|
||||||
if (flags & 0x02) {
|
if (flags & 0x02) {
|
||||||
/* Skip pivot info */
|
/* Skip pivot info */
|
||||||
br_seek(&br, 64);
|
br_seek_bytes(&br, 64);
|
||||||
}
|
}
|
||||||
|
|
||||||
slice->start = start;
|
slice->start = start;
|
||||||
@ -974,7 +953,7 @@ struct ase_decode_sheet_result ase_decode_sheet(struct arena *arena, struct stri
|
|||||||
//case CHUNK_TYPE_USER_DATA
|
//case CHUNK_TYPE_USER_DATA
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
br_seek_to(&br, chunk_end_pos);
|
br_seek_to_byte(&br, chunk_end_pos);
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -982,7 +961,7 @@ struct ase_decode_sheet_result ase_decode_sheet(struct arena *arena, struct stri
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ASSERT all data was read */
|
/* ASSERT all data was read */
|
||||||
ASSERT(br_bytes_left(&br) == 0);
|
ASSERT(br_num_bytes_left(&br) == 0);
|
||||||
|
|
||||||
res.image_size = V2(image_width, image_height);
|
res.image_size = V2(image_width, image_height);
|
||||||
res.frame_size = V2(frame_width, frame_height);
|
res.frame_size = V2(frame_width, frame_height);
|
||||||
|
|||||||
750
src/bitbuff.c
Normal file
750
src/bitbuff.c
Normal file
@ -0,0 +1,750 @@
|
|||||||
|
#include "bitbuff.h"
|
||||||
|
#include "memory.h"
|
||||||
|
#include "arena.h"
|
||||||
|
|
||||||
|
/* TODO: Safety check that functions taking byte length can't overflow bit conversion (log2(num_bytes) > 61) */
|
||||||
|
|
||||||
|
#define WRITE_OVERFLOW_ARENA_PUSH_SIZE 4096
|
||||||
|
|
||||||
|
/* ========================== *
|
||||||
|
* Debug
|
||||||
|
* ========================== */
|
||||||
|
|
||||||
|
#if BITBUFF_DEBUG
|
||||||
|
/* Magic numbers inserted to verify read/write type & length */
|
||||||
|
enum dbg_magic {
|
||||||
|
DBG_MAGIC_ALIGN = 0x20A4,
|
||||||
|
DBG_MAGIC_UBITS = 0xCB4A,
|
||||||
|
DBG_MAGIC_IBITS = 0xB30D,
|
||||||
|
DBG_MAGIC_UV = 0xE179,
|
||||||
|
DBG_MAGIC_IV = 0x981f,
|
||||||
|
DBG_MAGIC_F32 = 0x56F9,
|
||||||
|
DBG_MAGIC_F64 = 0x7053,
|
||||||
|
DBG_MAGIC_STRING = 0x7866,
|
||||||
|
DBG_MAGIC_BYTES = 0x8B90,
|
||||||
|
};
|
||||||
|
|
||||||
|
INTERNAL void bw_write_ubits_nomagic(struct bitbuff_writer *bw, u64 value, u8 num_bits);
|
||||||
|
INTERNAL void _dbg_write_magic(struct bitbuff_writer *bw, enum dbg_magic magic, u8 num_bits)
|
||||||
|
{
|
||||||
|
if (bw->debug_enabled) {
|
||||||
|
if (bw_check_overflow_bits(bw, 24)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
u64 magic_ubits = (u64)magic | ((u64)num_bits << 16);
|
||||||
|
bw_write_ubits_nomagic(bw, magic_ubits, 24);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
INTERNAL u64 br_read_ubits_nomagic(struct bitbuff_reader *br, u8 num_bits);
|
||||||
|
INTERNAL void _dbg_read_magic(struct bitbuff_reader *br, enum dbg_magic expected_magic, u8 expected_num_bits)
|
||||||
|
{
|
||||||
|
if (br->debug_enabled) {
|
||||||
|
if (br_check_overflow_bits(br, 24)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
u64 stored = br_read_ubits_nomagic(br, 24);
|
||||||
|
enum dbg_magic stored_magic = stored & 0xFFFF;
|
||||||
|
u8 stored_num_bits = (stored >> 16) & 0xFF;
|
||||||
|
|
||||||
|
/* Verify stored magic match */
|
||||||
|
ASSERT(stored_magic == expected_magic);
|
||||||
|
|
||||||
|
/* Verify stored bit count match */
|
||||||
|
ASSERT(stored_num_bits == expected_num_bits);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
# define _dbg_write_magic(a, b, c)
|
||||||
|
# define _dbg_read_magic(a, b, c)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* ========================== *
|
||||||
|
* Utils
|
||||||
|
* ========================== */
|
||||||
|
|
||||||
|
INTERNAL u64 uint_to_twos_compliment(u64 value, u8 num_bits)
|
||||||
|
{
|
||||||
|
u64 mask = U64_MAX;
|
||||||
|
if (num_bits < 64) {
|
||||||
|
mask = ~(U64_MAX << num_bits);
|
||||||
|
}
|
||||||
|
u64 tc = (~value & mask) + 1;
|
||||||
|
tc &= mask;
|
||||||
|
return tc;
|
||||||
|
}
|
||||||
|
|
||||||
|
INTERNAL i64 sint_from_twos_compliment(u64 tc, u8 num_bits)
|
||||||
|
{
|
||||||
|
u64 msb_mask = (u64)1 << (num_bits - 1);
|
||||||
|
i64 value = -(i64)(tc & msb_mask);
|
||||||
|
value += tc & ~msb_mask;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========================== *
|
||||||
|
* Bitbuff
|
||||||
|
* ========================== */
|
||||||
|
|
||||||
|
struct bitbuff bitbuff_alloc(u64 arena_reserve)
|
||||||
|
{
|
||||||
|
struct bitbuff res = ZI;
|
||||||
|
res.arena = arena_alloc(arena_reserve);
|
||||||
|
res.is_backed_by_arena = true;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bitbuff_release(struct bitbuff *bb)
|
||||||
|
{
|
||||||
|
/* Only arena bitbuffs need to be released */
|
||||||
|
if (bb->is_backed_by_arena) {
|
||||||
|
arena_release(&bb->arena);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct bitbuff bitbuff_from_string(struct string s)
|
||||||
|
{
|
||||||
|
struct bitbuff res = ZI;
|
||||||
|
res.fixed_buffer = s;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========================== *
|
||||||
|
* Writer
|
||||||
|
* ========================== */
|
||||||
|
|
||||||
|
struct bitbuff_writer bw_from_bitbuff(struct bitbuff *bb)
|
||||||
|
{
|
||||||
|
struct bitbuff_writer res = ZI;
|
||||||
|
res.bb = bb;
|
||||||
|
if (bb->is_backed_by_arena) {
|
||||||
|
res.base = bb->arena.base;
|
||||||
|
} else {
|
||||||
|
res.base = bb->fixed_buffer.text;
|
||||||
|
}
|
||||||
|
res.cur_bit = 0;
|
||||||
|
#if BITBUFF_DEBUG
|
||||||
|
res.debug_enabled = true;
|
||||||
|
#endif
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Use this when writing external formats that will not verify bitbuff debug symbols / magic numbers */
|
||||||
|
struct bitbuff_writer bw_from_bitbuff_no_debug(struct bitbuff *bb)
|
||||||
|
{
|
||||||
|
struct bitbuff_writer res = bw_from_bitbuff(bb);
|
||||||
|
#if BITBUFF_DEBUG
|
||||||
|
res.debug_enabled = false;
|
||||||
|
#endif
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 bw_num_bits_written(struct bitbuff_writer *bw)
|
||||||
|
{
|
||||||
|
return bw->cur_bit;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 bw_num_bytes_written(struct bitbuff_writer *bw)
|
||||||
|
{
|
||||||
|
return (bw->cur_bit + 7) >> 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct string bw_get_written(struct arena *arena, struct bitbuff_writer *bw)
|
||||||
|
{
|
||||||
|
struct string res = ZI;
|
||||||
|
res.len = (bw->cur_bit + 7) >> 3;
|
||||||
|
res.text = arena_push_array(arena, u8, res.len);
|
||||||
|
MEMCPY(res.text, bw->base, res.len);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns true if num_bits would cause the writer to overflow its fixed buffer size (if writer is not backed by a dynamic arena bitbuff) */
|
||||||
|
b32 bw_check_overflow_bits(struct bitbuff_writer *bw, u64 num_bits)
|
||||||
|
{
|
||||||
|
b32 res = false;
|
||||||
|
struct bitbuff *bb = bw->bb;
|
||||||
|
if (bw->overflowed) {
|
||||||
|
res = true;
|
||||||
|
} else {
|
||||||
|
u64 bytes_needed = (bw->cur_bit + num_bits + 7) >> 3;
|
||||||
|
if (bb->is_backed_by_arena) {
|
||||||
|
struct arena *arena = &bb->arena;
|
||||||
|
if (bytes_needed >= arena->pos) {
|
||||||
|
/* Grow arena */
|
||||||
|
u64 push_size = (((bytes_needed - arena->pos) / WRITE_OVERFLOW_ARENA_PUSH_SIZE) + 1) * WRITE_OVERFLOW_ARENA_PUSH_SIZE;
|
||||||
|
arena_push_array(arena, u8, push_size);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
u64 max_len = bb->fixed_buffer.len;
|
||||||
|
if (bytes_needed >= max_len) {
|
||||||
|
/* Writer overflowed fixed buffer */
|
||||||
|
ASSERT(false);
|
||||||
|
res = true;
|
||||||
|
bw->cur_bit = max_len << 3;
|
||||||
|
bw->overflowed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Align the pos to the next byte */
|
||||||
|
void bw_align(struct bitbuff_writer *bw)
|
||||||
|
{
|
||||||
|
_dbg_write_magic(bw, DBG_MAGIC_ALIGN, 0);
|
||||||
|
bw->cur_bit += (8 - (bw->cur_bit & 7)) & 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if BITBUFF_DEBUG
|
||||||
|
INTERNAL void bw_write_ubits_nomagic(struct bitbuff_writer *bw, u64 value, u8 num_bits)
|
||||||
|
#else
|
||||||
|
void bw_write_ubits(struct bitbuff_writer *bw, u64 value, u8 num_bits)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
ASSERT(num_bits > 0 && (num_bits == 64 || value <= ~(U64_MAX << num_bits))); /* Bit count must be able to hold value */
|
||||||
|
if (bw_check_overflow_bits(bw, num_bits)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
u8 offset = bw->cur_bit & 7;
|
||||||
|
if (offset != 0) {
|
||||||
|
/* Write unaligned bits */
|
||||||
|
u8 *at = bw->base + (bw->cur_bit >> 3);
|
||||||
|
u8 num_mix_bits = min_u8((8 - offset), num_bits);
|
||||||
|
u8 mix_byte = (u8)((value & ((1 << num_mix_bits) - 1)) << offset);
|
||||||
|
*at |= mix_byte;
|
||||||
|
value >>= num_mix_bits;
|
||||||
|
num_bits -= num_mix_bits;
|
||||||
|
bw->cur_bit += num_mix_bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cur_bit is now aligned to byte */
|
||||||
|
u8 *at = bw->base + (bw->cur_bit >> 3);
|
||||||
|
u8 num_bytes = (num_bits + 7) >> 3;
|
||||||
|
MEMCPY(at, &value, num_bytes);
|
||||||
|
bw->cur_bit += num_bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if BITBUFF_DEBUG
|
||||||
|
void bw_write_ubits(struct bitbuff_writer *bw, u64 value, u8 num_bits)
|
||||||
|
{
|
||||||
|
_dbg_write_magic(bw, DBG_MAGIC_UBITS, num_bits);
|
||||||
|
bw_write_ubits_nomagic(bw, value, num_bits);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void bw_write_ibits(struct bitbuff_writer *bw, i64 value, u8 num_bits)
|
||||||
|
{
|
||||||
|
_dbg_write_magic(bw, DBG_MAGIC_IBITS, num_bits);
|
||||||
|
u64 ubits;
|
||||||
|
if (value >= 0) {
|
||||||
|
ubits = value;
|
||||||
|
} else {
|
||||||
|
ubits = uint_to_twos_compliment(-value, num_bits);
|
||||||
|
}
|
||||||
|
bw_write_ubits(bw, ubits, num_bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bw_write_bit(struct bitbuff_writer *bw, u8 value)
|
||||||
|
{
|
||||||
|
bw_write_ubits(bw, value, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Writes a variable length unsigned integer.
|
||||||
|
* Value is written in chunks w/ 8th bit signaling continuation bit. */
|
||||||
|
void bw_write_uv(struct bitbuff_writer *bw, u64 value)
|
||||||
|
{
|
||||||
|
_dbg_write_magic(bw, DBG_MAGIC_UV, 0);
|
||||||
|
while (value > 0x7F) {
|
||||||
|
u8 cont_byte = 0x80 | (value & 0x7F);
|
||||||
|
bw_write_ubits(bw, cont_byte, 8);
|
||||||
|
value >>= 7;
|
||||||
|
}
|
||||||
|
bw_write_ubits(bw, value, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Writes a variable length signed integer.
|
||||||
|
* Similar to bw_write_uv, except the first byte's 7th bit is a sign bit
|
||||||
|
* indicating that the value is stored in twos compliment. */
|
||||||
|
void bw_write_iv(struct bitbuff_writer *bw, i64 value)
|
||||||
|
{
|
||||||
|
_dbg_write_magic(bw, DBG_MAGIC_IV, 0);
|
||||||
|
u8 sign_bit;
|
||||||
|
u64 tc;
|
||||||
|
if (value >= 0) {
|
||||||
|
sign_bit = 0;
|
||||||
|
tc = value;
|
||||||
|
} else {
|
||||||
|
sign_bit = 1;
|
||||||
|
u64 unsigned_value = -value;
|
||||||
|
u8 num_bits = 6;
|
||||||
|
unsigned_value >>= 6;
|
||||||
|
while (unsigned_value > 0) {
|
||||||
|
num_bits += 7;
|
||||||
|
unsigned_value >>= 7;
|
||||||
|
}
|
||||||
|
num_bits = min_u8(num_bits, 64);
|
||||||
|
tc = uint_to_twos_compliment(-value, num_bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* First byte contains not just cont bit, but sign bit as well. */
|
||||||
|
u8 first_byte = (tc & 0x3F);
|
||||||
|
tc >>= 6;
|
||||||
|
first_byte |= (tc > 0) << 7; /* Cont bit */
|
||||||
|
first_byte |= sign_bit << 6; /* Sign bit */
|
||||||
|
bw_write_ubits(bw, first_byte, 8);
|
||||||
|
|
||||||
|
if (tc > 0) {
|
||||||
|
while (tc > 0x7F) {
|
||||||
|
u8 cont_byte = 0x80 | (tc & 0x7F);
|
||||||
|
bw_write_ubits(bw, cont_byte, 8);
|
||||||
|
tc >>= 7;
|
||||||
|
}
|
||||||
|
bw_write_ubits(bw, tc, 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bw_write_f32(struct bitbuff_writer *bw, f32 value)
|
||||||
|
{
|
||||||
|
_dbg_write_magic(bw, DBG_MAGIC_F32, 0);
|
||||||
|
bw_write_ubits(bw, *(u32 *)&value, 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bw_write_f64(struct bitbuff_writer *bw, f64 value)
|
||||||
|
{
|
||||||
|
_dbg_write_magic(bw, DBG_MAGIC_F64, 0);
|
||||||
|
bw_write_ubits(bw, *(u64 *)&value, 64);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bw_write_string(struct bitbuff_writer *bw, struct string s)
|
||||||
|
{
|
||||||
|
_dbg_write_magic(bw, DBG_MAGIC_STRING, 0);
|
||||||
|
bw_write_uv(bw, s.len);
|
||||||
|
bw_write_bytes(bw, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bw_write_bytes(struct bitbuff_writer *bw, struct string bytes)
|
||||||
|
{
|
||||||
|
_dbg_write_magic(bw, DBG_MAGIC_BYTES, 0);
|
||||||
|
|
||||||
|
/* Align start of bytes */
|
||||||
|
bw_align(bw);
|
||||||
|
|
||||||
|
u64 num_bits = bytes.len << 3;
|
||||||
|
if (bw_check_overflow_bits(bw, num_bits)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
u8 *at = bw->base + (bw->cur_bit >> 3);
|
||||||
|
MEMCPY(at, bytes.text, bytes.len);
|
||||||
|
bw->cur_bit += num_bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========================== *
|
||||||
|
* Reader
|
||||||
|
* ========================== */
|
||||||
|
|
||||||
|
struct bitbuff_reader br_from_bitbuff(struct bitbuff *bb)
|
||||||
|
{
|
||||||
|
struct bitbuff_reader res = ZI;
|
||||||
|
if (!bb->is_backed_by_arena) {
|
||||||
|
res.base = bb->fixed_buffer.text;
|
||||||
|
res.base_len = bb->fixed_buffer.len;
|
||||||
|
} else {
|
||||||
|
struct arena *arena = &bb->arena;
|
||||||
|
res.base = arena->base;
|
||||||
|
res.base_len = arena->pos;
|
||||||
|
}
|
||||||
|
res.cur_bit = 0;
|
||||||
|
#if BITBUFF_DEBUG
|
||||||
|
res.debug_enabled = true;
|
||||||
|
#endif
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Use this when reading from external formats that will not contain bitbuff debug symbols / magic numbers */
|
||||||
|
struct bitbuff_reader br_from_bitbuff_no_debug(struct bitbuff *bb)
|
||||||
|
{
|
||||||
|
struct bitbuff_reader res = br_from_bitbuff(bb);
|
||||||
|
#if BITBUFF_DEBUG
|
||||||
|
res.debug_enabled = false;
|
||||||
|
#endif
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns the number of bits read from the bitbuff */
|
||||||
|
u64 br_cur_bit(struct bitbuff_reader *br)
|
||||||
|
{
|
||||||
|
return br->cur_bit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns the number of *full* bytes read from the bitbuff */
|
||||||
|
u64 br_cur_byte(struct bitbuff_reader *br)
|
||||||
|
{
|
||||||
|
return br->cur_bit >> 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns the number of bits left until the bitbuff overflows */
|
||||||
|
u64 br_num_bits_left(struct bitbuff_reader *br)
|
||||||
|
{
|
||||||
|
return (br->base_len << 3) - br->cur_bit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns the number of *full* bytes left until the bitbuff overflows */
|
||||||
|
u64 br_num_bytes_left(struct bitbuff_reader *br)
|
||||||
|
{
|
||||||
|
return br->base_len - (br->cur_bit >> 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
b32 br_check_overflow_bits(struct bitbuff_reader *br, u64 num_bits)
|
||||||
|
{
|
||||||
|
b32 res = false;
|
||||||
|
if (br->overflowed) {
|
||||||
|
res = true;
|
||||||
|
} else {
|
||||||
|
u64 bits_needed = br->cur_bit + num_bits;
|
||||||
|
u64 base_len_bits = br->base_len << 3;
|
||||||
|
if (bits_needed > base_len_bits) {
|
||||||
|
/* Tried to read past bitbuff memory */
|
||||||
|
ASSERT(false);
|
||||||
|
res = true;
|
||||||
|
br->cur_bit = base_len_bits;
|
||||||
|
br->overflowed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Align the pos to the next byte */
|
||||||
|
void br_align(struct bitbuff_reader *br)
|
||||||
|
{
|
||||||
|
_dbg_read_magic(br, DBG_MAGIC_ALIGN, 0);
|
||||||
|
br->cur_bit += (8 - (br->cur_bit & 7)) & 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if BITBUFF_DEBUG
|
||||||
|
INTERNAL u64 br_read_ubits_nomagic(struct bitbuff_reader *br, u8 num_bits)
|
||||||
|
#else
|
||||||
|
u64 br_read_ubits(struct bitbuff_reader *br, u8 num_bits)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
if (br_check_overflow_bits(br, num_bits)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 res = 0;
|
||||||
|
|
||||||
|
u8 offset = br->cur_bit & 7;
|
||||||
|
u8 num_trailing_bits = 0;
|
||||||
|
if (offset) {
|
||||||
|
u8 *at = br->base + (br->cur_bit >> 3);
|
||||||
|
num_trailing_bits = min_u8(8 - offset, num_bits);
|
||||||
|
u8 mix_byte = *at;
|
||||||
|
mix_byte >>= offset;
|
||||||
|
mix_byte &= (1 << num_trailing_bits) - 1;
|
||||||
|
res = mix_byte;
|
||||||
|
num_bits -= num_trailing_bits;
|
||||||
|
br->cur_bit += num_trailing_bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cur_bit is now aligned to byte */
|
||||||
|
u8 *at = br->base + (br->cur_bit >> 3);
|
||||||
|
u8 num_bytes = (num_bits + 7) >> 3;
|
||||||
|
u64 tmp = 0;
|
||||||
|
MEMCPY(&tmp, at, num_bytes);
|
||||||
|
u64 mask = U64_MAX;
|
||||||
|
if (num_bits < 64) {
|
||||||
|
mask = ~(U64_MAX << num_bits);
|
||||||
|
}
|
||||||
|
tmp &= mask;
|
||||||
|
res |= tmp << num_trailing_bits;
|
||||||
|
br->cur_bit += num_bits;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if BITBUFF_DEBUG
|
||||||
|
u64 br_read_ubits(struct bitbuff_reader *br, u8 num_bits)
|
||||||
|
{
|
||||||
|
_dbg_read_magic(br, DBG_MAGIC_UBITS, num_bits);
|
||||||
|
return br_read_ubits_nomagic(br, num_bits);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
i64 br_read_ibits(struct bitbuff_reader *br, u8 num_bits)
|
||||||
|
{
|
||||||
|
ASSERT(num_bits > 1);
|
||||||
|
_dbg_read_magic(br, DBG_MAGIC_IBITS, num_bits);
|
||||||
|
u64 tc = br_read_ubits(br, num_bits);
|
||||||
|
return sint_from_twos_compliment(tc, num_bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
u8 br_read_bit(struct bitbuff_reader *br)
|
||||||
|
{
|
||||||
|
return br_read_ubits(br, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read a variable length unsigned integer.
|
||||||
|
* See bw_write_uv for details. */
|
||||||
|
u64 br_read_uv(struct bitbuff_reader *br)
|
||||||
|
{
|
||||||
|
_dbg_read_magic(br, DBG_MAGIC_UV, 0);
|
||||||
|
|
||||||
|
u64 res = 0;
|
||||||
|
for (u64 i = 0; i <= 9; ++i) {
|
||||||
|
u64 part = br_read_ubits(br, 8);
|
||||||
|
u8 is_last_part = part <= 0x7F;
|
||||||
|
res |= (part & 0x7F) << (i * 7);
|
||||||
|
if (is_last_part) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read a variable length signed integer.
|
||||||
|
* See bw_write_iv for details. */
|
||||||
|
i64 br_read_iv(struct bitbuff_reader *br)
|
||||||
|
{
|
||||||
|
_dbg_read_magic(br, DBG_MAGIC_IV, 0);
|
||||||
|
u8 first_byte = br_read_ubits(br, 8);
|
||||||
|
u8 cont_bit = first_byte & 0x80;
|
||||||
|
u8 sign_bit = first_byte & 0x40;
|
||||||
|
|
||||||
|
u8 num_bits = 6;
|
||||||
|
u64 tc = first_byte & 0x3F;
|
||||||
|
if (cont_bit) {
|
||||||
|
for (u64 i = 0; i <= 9; ++i) {
|
||||||
|
u64 part = br_read_ubits(br, 8);
|
||||||
|
u8 is_last_part = part <= 0x7F;
|
||||||
|
tc |= (part & 0x7F) << num_bits;
|
||||||
|
num_bits += 7;
|
||||||
|
if (is_last_part) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
num_bits = min_u8(num_bits, 64);
|
||||||
|
|
||||||
|
i64 res;
|
||||||
|
if (sign_bit) {
|
||||||
|
/* Sign bit is 1, indicating result is stored in twos compliment */
|
||||||
|
res = sint_from_twos_compliment(tc, num_bits);
|
||||||
|
} else {
|
||||||
|
res = (i64)tc;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
f32 br_read_f32(struct bitbuff_reader *br)
|
||||||
|
{
|
||||||
|
_dbg_read_magic(br, DBG_MAGIC_F32, 0);
|
||||||
|
u32 ubits = br_read_ubits(br, 32);
|
||||||
|
return *(f32 *)&ubits;
|
||||||
|
}
|
||||||
|
|
||||||
|
f64 br_read_f64(struct bitbuff_reader *br)
|
||||||
|
{
|
||||||
|
_dbg_read_magic(br, DBG_MAGIC_F64, 0);
|
||||||
|
u64 ubits = br_read_ubits(br, 64);
|
||||||
|
return *(f64 *)&ubits;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct string br_read_string(struct arena *arena, struct bitbuff_reader *br)
|
||||||
|
{
|
||||||
|
_dbg_read_magic(br, DBG_MAGIC_STRING, 0);
|
||||||
|
struct string res = ZI;
|
||||||
|
u64 len = br_read_uv(br);
|
||||||
|
u8 *src = br_read_bytes_raw(br, len);
|
||||||
|
if (src != NULL) {
|
||||||
|
res.len = len;
|
||||||
|
res.text = arena_push_array(arena, u8, len);
|
||||||
|
MEMCPY(res.text, src, len);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Will fill dst with zeroes if bitbuff overflows */
|
||||||
|
void br_read_bytes(struct bitbuff_reader *br, struct string out)
|
||||||
|
{
|
||||||
|
u8 *src = br_read_bytes_raw(br, out.len);
|
||||||
|
if (src) {
|
||||||
|
MEMCPY(out.text, src, out.len);
|
||||||
|
} else {
|
||||||
|
MEMZERO(out.text, out.len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NULL will return on bitbuff overflow, result should be checked. */
|
||||||
|
u8 *br_read_bytes_raw(struct bitbuff_reader *br, u64 num_bytes)
|
||||||
|
{
|
||||||
|
_dbg_read_magic(br, DBG_MAGIC_BYTES, 0);
|
||||||
|
br_align(br);
|
||||||
|
|
||||||
|
u64 num_bits = num_bytes << 3;
|
||||||
|
if (br_check_overflow_bits(br, num_bits)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
u8 *raw = br->base + (br->cur_bit >> 3);
|
||||||
|
br->cur_bit += num_bits;
|
||||||
|
|
||||||
|
return raw;
|
||||||
|
}
|
||||||
|
|
||||||
|
void br_seek_bytes(struct bitbuff_reader *br, u64 num_bytes)
|
||||||
|
{
|
||||||
|
br_align(br);
|
||||||
|
|
||||||
|
u64 num_bits = num_bytes << 3;
|
||||||
|
if (br_check_overflow_bits(br, num_bits)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
br->cur_bit += num_bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
void br_seek_to_byte(struct bitbuff_reader *br, u64 pos)
|
||||||
|
{
|
||||||
|
u64 cur_byte_pos = br->cur_bit >> 3;
|
||||||
|
if (pos >= cur_byte_pos) {
|
||||||
|
br_seek_bytes(br, pos - cur_byte_pos);
|
||||||
|
} else {
|
||||||
|
/* Tried to seek byte backwards in reader */
|
||||||
|
ASSERT(false);
|
||||||
|
br->overflowed = true;
|
||||||
|
br->cur_bit = (br->base_len << 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========================== *
|
||||||
|
* Test
|
||||||
|
* ========================== */
|
||||||
|
|
||||||
|
#if BITBUFF_TEST
|
||||||
|
|
||||||
|
#include "string.h"
|
||||||
|
#include "scratch.h"
|
||||||
|
|
||||||
|
void bitbuff_test(void)
|
||||||
|
{
|
||||||
|
struct temp_arena scratch = scratch_begin_no_conflict();
|
||||||
|
|
||||||
|
u8 kind_ubits = 0;
|
||||||
|
u8 kind_ibits = 1;
|
||||||
|
u8 kind_uv = 2;
|
||||||
|
u8 kind_iv = 3;
|
||||||
|
u8 kind_string = 4;
|
||||||
|
|
||||||
|
struct test_case_ubits { u64 v; u64 num_bits; };
|
||||||
|
struct test_case_ibits { i64 v; u64 num_bits; };
|
||||||
|
struct test_case_uv { u64 v; };
|
||||||
|
struct test_case_iv { i64 v; };
|
||||||
|
struct test_case_string { struct string v; };
|
||||||
|
struct test_case {
|
||||||
|
u8 kind;
|
||||||
|
union {
|
||||||
|
struct test_case_ubits ubits;
|
||||||
|
struct test_case_ibits ibits;
|
||||||
|
struct test_case_uv uv;
|
||||||
|
struct test_case_iv iv;
|
||||||
|
struct test_case_string s;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct test_case cases[] = {
|
||||||
|
{ kind_ubits, .ubits = { 40, 8 } },
|
||||||
|
{ kind_ubits, .ubits = { 32, 8 } },
|
||||||
|
{ kind_ubits, .ubits = { 100, 7 } },
|
||||||
|
{ kind_ubits, .ubits = { 4, 3 } },
|
||||||
|
{ kind_ubits, .ubits = { 13, 8 } },
|
||||||
|
|
||||||
|
{ kind_ibits, .ibits = { 0, 8 } },
|
||||||
|
{ kind_ibits, .ibits = { -1, 8 } },
|
||||||
|
{ kind_ibits, .ibits = { -2, 8 } },
|
||||||
|
{ kind_ibits, .ibits = { -3, 8 } },
|
||||||
|
{ kind_ibits, .ibits = { -100, 8 } },
|
||||||
|
{ kind_ibits, .ibits = { -50, 7 } },
|
||||||
|
{ kind_ibits, .ibits = { 50, 7 } },
|
||||||
|
{ kind_ibits, .ibits = { 4, 7 } },
|
||||||
|
{ kind_ibits, .ibits = { 1, 7 } },
|
||||||
|
{ kind_ibits, .ibits = { 3, 3 } },
|
||||||
|
|
||||||
|
{ kind_uv, .uv = { 0 } },
|
||||||
|
{ kind_uv, .uv = { 100 } },
|
||||||
|
{ kind_uv, .uv = { 10000 } },
|
||||||
|
{ kind_uv, .uv = { 10000000000000 } },
|
||||||
|
{ kind_uv, .uv = { U64_MAX } },
|
||||||
|
|
||||||
|
{ kind_iv, .iv = { 0 } },
|
||||||
|
{ kind_iv, .iv = { -1 } },
|
||||||
|
{ kind_iv, .iv = { 10000000000000 } },
|
||||||
|
{ kind_iv, .iv = { -10000000000000 } },
|
||||||
|
{ kind_iv, .iv = { I64_MAX } },
|
||||||
|
{ kind_iv, .iv = { I64_MIN } },
|
||||||
|
|
||||||
|
{ kind_string, .s = { LIT("Hello there! Hope you're doing well.") } },
|
||||||
|
{ kind_ibits, .ibits = { 3, 3 } },
|
||||||
|
{ kind_string, .s = { LIT("Alriiiiiiiiiiiiiiiiiiighty then") } },
|
||||||
|
{ kind_string, .s = { LIT("Alriiiiiiiiiiiiiiiiiiighty then") } },
|
||||||
|
};
|
||||||
|
|
||||||
|
struct string encoded = ZI;
|
||||||
|
{
|
||||||
|
struct bitbuff bb = bitbuff_alloc(GIGABYTE(64));
|
||||||
|
struct bitbuff_writer bw = bw_from_bitbuff(&bb);
|
||||||
|
for (u64 i = 0; i < ARRAY_COUNT(cases); ++i) {
|
||||||
|
struct test_case c = cases[i];
|
||||||
|
if (c.kind == kind_ubits) {
|
||||||
|
bw_write_ubits(&bw, c.ubits.v, c.ubits.num_bits);
|
||||||
|
} else if (c.kind == kind_ibits) {
|
||||||
|
bw_write_ibits(&bw, c.ibits.v, c.ibits.num_bits);
|
||||||
|
} else if (c.kind == kind_uv) {
|
||||||
|
bw_write_uv(&bw, c.uv.v);
|
||||||
|
} else if (c.kind == kind_iv) {
|
||||||
|
bw_write_iv(&bw, c.iv.v);
|
||||||
|
} else if (c.kind == kind_string) {
|
||||||
|
bw_write_string(&bw, c.s.v);
|
||||||
|
} else {
|
||||||
|
ASSERT(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
encoded = bw_get_written(scratch.arena, &bw);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
struct bitbuff bb = bitbuff_from_string(encoded);
|
||||||
|
struct bitbuff_reader br = br_from_bitbuff(&bb);
|
||||||
|
for (u64 i = 0; i < ARRAY_COUNT(cases); ++i) {
|
||||||
|
struct test_case c = cases[i];
|
||||||
|
if (c.kind == kind_ubits) {
|
||||||
|
u64 w = c.ubits.v;
|
||||||
|
u64 r = br_read_ubits(&br, c.ubits.num_bits);
|
||||||
|
ASSERT(r == w);
|
||||||
|
} else if (c.kind == kind_ibits) {
|
||||||
|
i64 w = c.ibits.v;
|
||||||
|
i64 r = br_read_ibits(&br, c.ubits.num_bits);
|
||||||
|
ASSERT(r == w);
|
||||||
|
} else if (c.kind == kind_uv) {
|
||||||
|
u64 w = c.uv.v;
|
||||||
|
u64 r = br_read_uv(&br);
|
||||||
|
ASSERT(r == w);
|
||||||
|
} else if (c.kind == kind_iv) {
|
||||||
|
i64 w = c.iv.v;
|
||||||
|
i64 r = br_read_iv(&br);
|
||||||
|
ASSERT(r == w);
|
||||||
|
} else if (c.kind == kind_string) {
|
||||||
|
struct string w = c.s.v;
|
||||||
|
struct string r = br_read_string(scratch.arena, &br);
|
||||||
|
ASSERT(string_eq(r, w));
|
||||||
|
} else {
|
||||||
|
ASSERT(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
scratch_end(scratch);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
112
src/bitbuff.h
Normal file
112
src/bitbuff.h
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
#ifndef BITBUFF_H
|
||||||
|
#define BITBUFF_H
|
||||||
|
|
||||||
|
/* ========================== *
|
||||||
|
* Bitbuff
|
||||||
|
* ========================== */
|
||||||
|
|
||||||
|
struct bitbuff {
|
||||||
|
b32 is_backed_by_arena;
|
||||||
|
|
||||||
|
/* If `is_arena_bitbuff` is true, this dynamically-sized arena will be used for reading & writing (meaning writing cannot overflow) */
|
||||||
|
struct arena arena;
|
||||||
|
|
||||||
|
/* If `is_arena_bitbuff` is false, this fixed-sized buffer willl be used for reading & writing */
|
||||||
|
struct string fixed_buffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bitbuff bitbuff_alloc(u64 arena_reserve);
|
||||||
|
void bitbuff_release(struct bitbuff *bitbuff);
|
||||||
|
|
||||||
|
struct bitbuff bitbuff_from_string(struct string s);
|
||||||
|
|
||||||
|
/* ========================== *
|
||||||
|
* Writer
|
||||||
|
* ========================== */
|
||||||
|
|
||||||
|
/* NOTE: base_len is not stored in writer (as it is in the reader) since a dynamic arena-backed bitbuff could grow meaning len needs to be re-checked */
|
||||||
|
struct bitbuff_writer {
|
||||||
|
b32 overflowed;
|
||||||
|
struct bitbuff *bb;
|
||||||
|
u8 *base;
|
||||||
|
u64 cur_bit;
|
||||||
|
#if BITBUFF_DEBUG
|
||||||
|
b32 debug_enabled;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bitbuff_writer bw_from_bitbuff(struct bitbuff *bb);
|
||||||
|
struct bitbuff_writer bw_from_bitbuff_no_debug(struct bitbuff *bb);
|
||||||
|
|
||||||
|
u64 bw_num_bits_written(struct bitbuff_writer *bw);
|
||||||
|
u64 bw_num_bytes_written(struct bitbuff_writer *bw);
|
||||||
|
|
||||||
|
struct string bw_get_written(struct arena *arena, struct bitbuff_writer *bw);
|
||||||
|
|
||||||
|
b32 bw_check_overflow_bits(struct bitbuff_writer *bw, u64 num_bits);
|
||||||
|
|
||||||
|
void bw_align(struct bitbuff_writer *bw);
|
||||||
|
|
||||||
|
void bw_write_ubits(struct bitbuff_writer *bw, u64 value, u8 num_bits);
|
||||||
|
void bw_write_ibits(struct bitbuff_writer *bw, i64 value, u8 num_bits);
|
||||||
|
void bw_write_bit(struct bitbuff_writer *bw, u8 value);
|
||||||
|
|
||||||
|
void bw_write_uv(struct bitbuff_writer *bw, u64 value);
|
||||||
|
void bw_write_iv(struct bitbuff_writer *bw, i64 value);
|
||||||
|
|
||||||
|
void bw_write_f32(struct bitbuff_writer *bw, f32 value);
|
||||||
|
void bw_write_f64(struct bitbuff_writer *bw, f64 value);
|
||||||
|
|
||||||
|
void bw_write_string(struct bitbuff_writer *bw, struct string s);
|
||||||
|
|
||||||
|
void bw_write_bytes(struct bitbuff_writer *bw, struct string bytes);
|
||||||
|
|
||||||
|
/* ========================== *
|
||||||
|
* Reader
|
||||||
|
* ========================== */
|
||||||
|
|
||||||
|
struct bitbuff_reader {
|
||||||
|
b32 overflowed;
|
||||||
|
u64 base_len;
|
||||||
|
u8 *base;
|
||||||
|
u64 cur_bit;
|
||||||
|
#if BITBUFF_DEBUG
|
||||||
|
b32 debug_enabled;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bitbuff_reader br_from_bitbuff(struct bitbuff *bb);
|
||||||
|
struct bitbuff_reader br_from_bitbuff_no_debug(struct bitbuff *bb);
|
||||||
|
|
||||||
|
u64 br_cur_bit(struct bitbuff_reader *br);
|
||||||
|
u64 br_cur_byte(struct bitbuff_reader *br);
|
||||||
|
|
||||||
|
u64 br_num_bits_left(struct bitbuff_reader *br);
|
||||||
|
u64 br_num_bytes_left(struct bitbuff_reader *br);
|
||||||
|
|
||||||
|
b32 br_check_overflow_bits(struct bitbuff_reader *br, u64 num_bits);
|
||||||
|
|
||||||
|
void br_align(struct bitbuff_reader *br);
|
||||||
|
|
||||||
|
u64 br_read_ubits(struct bitbuff_reader *br, u8 num_bits);
|
||||||
|
i64 br_read_ibits(struct bitbuff_reader *br, u8 num_bits);
|
||||||
|
u8 br_read_bit(struct bitbuff_reader *br);
|
||||||
|
|
||||||
|
u64 br_read_uv(struct bitbuff_reader *br);
|
||||||
|
i64 br_read_iv(struct bitbuff_reader *br);
|
||||||
|
|
||||||
|
f32 br_read_f32(struct bitbuff_reader *br);
|
||||||
|
f64 br_read_f64(struct bitbuff_reader *br);
|
||||||
|
|
||||||
|
struct string br_read_string(struct arena *arena, struct bitbuff_reader *br);
|
||||||
|
|
||||||
|
void br_read_bytes(struct bitbuff_reader *br, struct string dst);
|
||||||
|
u8 *br_read_bytes_raw(struct bitbuff_reader *br, u64 num_bytes);
|
||||||
|
void br_seek_bytes(struct bitbuff_reader *br, u64 num_bytes);
|
||||||
|
void br_seek_to_byte(struct bitbuff_reader *br, u64 pos);
|
||||||
|
|
||||||
|
#if BITBUFF_TEST
|
||||||
|
void bitbuff_test(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -1,6 +1,8 @@
|
|||||||
#include "buddy.h"
|
#include "buddy.h"
|
||||||
#include "arena.h"
|
#include "arena.h"
|
||||||
|
|
||||||
|
/* TODO: Elminiate meta arena. Just store levels in first 4096 bytes of buddy arena, and then zone header data at the beginning of each allocation. */
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Ctx
|
* Ctx
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|||||||
334
src/byteio.c
334
src/byteio.c
@ -1,334 +0,0 @@
|
|||||||
#include "byteio.h"
|
|
||||||
#include "memory.h"
|
|
||||||
#include "arena.h"
|
|
||||||
|
|
||||||
/* ========================== *
|
|
||||||
* Writer
|
|
||||||
* ========================== */
|
|
||||||
|
|
||||||
INTERNAL b32 write_check_overflow(struct byte_writer *bw, i64 amount)
|
|
||||||
{
|
|
||||||
b32 overflowed = bw->overflowed;
|
|
||||||
if (overflowed || amount < 0) {
|
|
||||||
overflowed = true;
|
|
||||||
bw->overflowed = true;
|
|
||||||
} else {
|
|
||||||
u8 *end = bw->buff.text + bw->buff.len;
|
|
||||||
u8 *new_pos = bw->at + amount;
|
|
||||||
i64 new_space_left = end - new_pos;
|
|
||||||
if (new_space_left < 0) {
|
|
||||||
struct arena *arena = bw->arena;
|
|
||||||
if (arena) {
|
|
||||||
if ((arena->base + arena->pos) == end) {
|
|
||||||
arena_push_array(arena, u8, -new_space_left);
|
|
||||||
bw->buff.len += -new_space_left;
|
|
||||||
} else {
|
|
||||||
/* Writer memory must be contiguous in arena */
|
|
||||||
overflowed = true;
|
|
||||||
bw->overflowed = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
overflowed = true;
|
|
||||||
bw->overflowed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ASSERT(!overflowed);
|
|
||||||
return overflowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
INTERNAL void write(struct byte_writer *bw, void *v, u64 size)
|
|
||||||
{
|
|
||||||
if (write_check_overflow(bw, size)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
MEMCPY(bw->at, v, size);
|
|
||||||
bw->at += size;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct byte_writer bw_from_buffer(struct string buff)
|
|
||||||
{
|
|
||||||
struct byte_writer bw = ZI;
|
|
||||||
bw.buff = buff;
|
|
||||||
bw.at = buff.text;
|
|
||||||
return bw;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Returns a writer that will allocate to arena instead of overflowing (writes must stay contiguous in arena) */
|
|
||||||
struct byte_writer bw_from_arena(struct arena *arena)
|
|
||||||
{
|
|
||||||
struct byte_writer bw = ZI;
|
|
||||||
bw.arena = arena;
|
|
||||||
bw.buff.text = arena->base + arena->pos;
|
|
||||||
bw.buff.len = 0;
|
|
||||||
bw.at = bw.buff.text;
|
|
||||||
return bw;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Seeks forward and returns a new writer pointing to the skipped bytes */
|
|
||||||
struct byte_writer bw_branch(struct byte_writer *bw, u64 size)
|
|
||||||
{
|
|
||||||
struct string buff = STRING(size, bw->at);
|
|
||||||
struct byte_writer branch = bw_from_buffer(buff);
|
|
||||||
bw_seek(bw, size);
|
|
||||||
branch.overflowed = bw->overflowed;
|
|
||||||
return branch;
|
|
||||||
}
|
|
||||||
|
|
||||||
void bw_seek(struct byte_writer *bw, u64 amount)
|
|
||||||
{
|
|
||||||
if (write_check_overflow(bw, amount)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
bw->at += amount;
|
|
||||||
}
|
|
||||||
|
|
||||||
void bw_seek_to(struct byte_writer *bw, u64 pos)
|
|
||||||
{
|
|
||||||
if (write_check_overflow(bw, (i64)pos - (i64)(bw->at - bw->buff.text))) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
bw->at = bw->buff.text + pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
void bw_write_bytes(struct byte_writer *bw, struct string bytes)
|
|
||||||
{
|
|
||||||
write(bw, bytes.text, bytes.len);
|
|
||||||
}
|
|
||||||
|
|
||||||
void bw_write_u8(struct byte_writer *bw, u8 v)
|
|
||||||
{
|
|
||||||
write(bw, &v, sizeof(v));
|
|
||||||
}
|
|
||||||
|
|
||||||
void bw_write_u16(struct byte_writer *bw, u16 v)
|
|
||||||
{
|
|
||||||
write(bw, &v, sizeof(v));
|
|
||||||
}
|
|
||||||
|
|
||||||
void bw_write_u32(struct byte_writer *bw, u32 v)
|
|
||||||
{
|
|
||||||
write(bw, &v, sizeof(v));
|
|
||||||
}
|
|
||||||
|
|
||||||
void bw_write_u64(struct byte_writer *bw, u64 v)
|
|
||||||
{
|
|
||||||
write(bw, &v, sizeof(v));
|
|
||||||
}
|
|
||||||
|
|
||||||
void bw_write_i8(struct byte_writer *bw, i8 v)
|
|
||||||
{
|
|
||||||
write(bw, &v, sizeof(v));
|
|
||||||
}
|
|
||||||
|
|
||||||
void bw_write_i16(struct byte_writer *bw, i16 v)
|
|
||||||
{
|
|
||||||
write(bw, &v, sizeof(v));
|
|
||||||
}
|
|
||||||
|
|
||||||
void bw_write_i32(struct byte_writer *bw, i32 v)
|
|
||||||
{
|
|
||||||
write(bw, &v, sizeof(v));
|
|
||||||
}
|
|
||||||
|
|
||||||
void bw_write_i64(struct byte_writer *bw, i64 v)
|
|
||||||
{
|
|
||||||
write(bw, &v, sizeof(v));
|
|
||||||
}
|
|
||||||
|
|
||||||
void bw_write_var_uint(struct byte_writer *bw, u64 v)
|
|
||||||
{
|
|
||||||
/* TODO: real varint write */
|
|
||||||
bw_write_u64(bw, v);
|
|
||||||
}
|
|
||||||
|
|
||||||
void bw_write_var_sint(struct byte_writer *bw, i64 v)
|
|
||||||
{
|
|
||||||
/* TODO: real varint write */
|
|
||||||
bw_write_i64(bw, v);
|
|
||||||
}
|
|
||||||
|
|
||||||
void bw_write_f32(struct byte_writer *bw, f32 v)
|
|
||||||
{
|
|
||||||
write(bw, &v, sizeof(v));
|
|
||||||
}
|
|
||||||
|
|
||||||
void bw_write_f64(struct byte_writer *bw, f64 v)
|
|
||||||
{
|
|
||||||
write(bw, &v, sizeof(v));
|
|
||||||
}
|
|
||||||
|
|
||||||
void bw_write_v2(struct byte_writer *bw, struct v2 v)
|
|
||||||
{
|
|
||||||
bw_write_f32(bw, v.x);
|
|
||||||
bw_write_f32(bw, v.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
void bw_write_string(struct byte_writer *bw, struct string str)
|
|
||||||
{
|
|
||||||
bw_write_var_uint(bw, str.len);
|
|
||||||
bw_write_bytes(bw, str);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ========================== *
|
|
||||||
* Reader
|
|
||||||
* ========================== */
|
|
||||||
|
|
||||||
INTERNAL b32 read_check_overflow(struct byte_reader *br, i64 amount)
|
|
||||||
{
|
|
||||||
b32 overflowed = br->overflowed;
|
|
||||||
if (overflowed || amount < 0 || (br->at + amount) > (br->buff.text + br->buff.len) ){
|
|
||||||
ASSERT(false);
|
|
||||||
br->overflowed = true;
|
|
||||||
overflowed = true;
|
|
||||||
}
|
|
||||||
return overflowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
INTERNAL void read(struct byte_reader *br, void *dst, u64 size)
|
|
||||||
{
|
|
||||||
if (read_check_overflow(br, size)) {
|
|
||||||
MEMZERO(dst, size);
|
|
||||||
}
|
|
||||||
MEMCPY(dst, br->at, size);
|
|
||||||
br->at += size;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct byte_reader br_from_buffer(struct string buff)
|
|
||||||
{
|
|
||||||
struct byte_reader br = ZI;
|
|
||||||
br.buff = buff;
|
|
||||||
br.at = buff.text;
|
|
||||||
return br;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Returns pointer to old position, or NULL on overflow */
|
|
||||||
void *br_seek(struct byte_reader *br, u64 amount)
|
|
||||||
{
|
|
||||||
if (read_check_overflow(br, amount)) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
void *ptr = br->at;
|
|
||||||
br->at += amount;
|
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Returns pointer to old position, or NULL on overflow */
|
|
||||||
void *br_seek_to(struct byte_reader *br, u64 pos)
|
|
||||||
{
|
|
||||||
if (read_check_overflow(br, (i64)pos - (i64)(br->at - br->buff.text))) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
void *ptr = br->at;
|
|
||||||
br->at = br->buff.text + pos;
|
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Will fill buff with zeroes on overflow */
|
|
||||||
void br_read_to_buffer(struct byte_reader *br, struct string buff)
|
|
||||||
{
|
|
||||||
read(br, buff.text, buff.len);
|
|
||||||
}
|
|
||||||
|
|
||||||
u8 br_read_u8(struct byte_reader *br)
|
|
||||||
{
|
|
||||||
u8 res;
|
|
||||||
read(br, &res, sizeof(res));
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
u16 br_read_u16(struct byte_reader *br)
|
|
||||||
{
|
|
||||||
u16 res;
|
|
||||||
read(br, &res, sizeof(res));
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 br_read_u32(struct byte_reader *br)
|
|
||||||
{
|
|
||||||
u32 res;
|
|
||||||
read(br, &res, sizeof(res));
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 br_read_u64(struct byte_reader *br)
|
|
||||||
{
|
|
||||||
u64 res;
|
|
||||||
read(br, &res, sizeof(res));
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
i8 br_read_i8(struct byte_reader *br)
|
|
||||||
{
|
|
||||||
i8 res;
|
|
||||||
read(br, &res, sizeof(res));
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
i16 br_read_i16(struct byte_reader *br)
|
|
||||||
{
|
|
||||||
i16 res = 0;
|
|
||||||
read(br, &res, sizeof(res));
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
i32 br_read_i32(struct byte_reader *br)
|
|
||||||
{
|
|
||||||
i32 res = 0;
|
|
||||||
read(br, &res, sizeof(res));
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
i64 br_read_i64(struct byte_reader *br)
|
|
||||||
{
|
|
||||||
i64 res;
|
|
||||||
read(br, &res, sizeof(res));
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 br_read_var_uint(struct byte_reader *br)
|
|
||||||
{
|
|
||||||
/* TODO: real variable length read */
|
|
||||||
return br_read_u64(br);
|
|
||||||
}
|
|
||||||
|
|
||||||
i64 br_read_var_sint(struct byte_reader *br)
|
|
||||||
{
|
|
||||||
/* TODO: real variable length read */
|
|
||||||
return br_read_i64(br);
|
|
||||||
}
|
|
||||||
|
|
||||||
f32 br_read_f32(struct byte_reader *br)
|
|
||||||
{
|
|
||||||
f32 res;
|
|
||||||
read(br, &res, sizeof(res));
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
f64 br_read_f64(struct byte_reader *br)
|
|
||||||
{
|
|
||||||
f64 res;
|
|
||||||
read(br, &res, sizeof(res));
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct v2 br_read_v2(struct byte_reader *br)
|
|
||||||
{
|
|
||||||
struct v2 res;
|
|
||||||
res.x = br_read_f32(br);
|
|
||||||
res.y = br_read_f32(br);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct string br_read_string(struct arena *arena, struct byte_reader *br)
|
|
||||||
{
|
|
||||||
struct string res = ZI;
|
|
||||||
u64 len = br_read_var_uint(br);
|
|
||||||
u8 *text = br_seek(br, len);
|
|
||||||
if (text != NULL) {
|
|
||||||
res.len = len;
|
|
||||||
res.text = arena_push_array(arena, u8, len);
|
|
||||||
MEMCPY(res.text, text, len);
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
96
src/byteio.h
96
src/byteio.h
@ -1,96 +0,0 @@
|
|||||||
#ifndef BYTEIO_H
|
|
||||||
#define BYTEIO_H
|
|
||||||
|
|
||||||
struct byte_writer {
|
|
||||||
struct arena *arena; /* If arena is set, then the writer cannot overflow and will instead allocate more memory as it grows */
|
|
||||||
struct string buff;
|
|
||||||
b32 overflowed;
|
|
||||||
u8 *at;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct byte_reader {
|
|
||||||
struct string buff;
|
|
||||||
b32 overflowed;
|
|
||||||
u8 *at;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* ========================== *
|
|
||||||
* Writer
|
|
||||||
* ========================== */
|
|
||||||
|
|
||||||
struct byte_writer bw_from_buffer(struct string buff);
|
|
||||||
struct byte_writer bw_from_arena(struct arena *arena);
|
|
||||||
struct byte_writer bw_branch(struct byte_writer *bw, u64 size);
|
|
||||||
|
|
||||||
void bw_seek(struct byte_writer *bw, u64 amount);
|
|
||||||
void bw_seek_to(struct byte_writer *bw, u64 pos);
|
|
||||||
|
|
||||||
void bw_write_bytes(struct byte_writer *bw, struct string bytes);
|
|
||||||
void bw_write_u8(struct byte_writer *bw, u8 v);
|
|
||||||
void bw_write_u16(struct byte_writer *bw, u16 v);
|
|
||||||
void bw_write_u32(struct byte_writer *bw, u32 v);
|
|
||||||
void bw_write_u64(struct byte_writer *bw, u64 v);
|
|
||||||
void bw_write_i8(struct byte_writer *bw, i8 v);
|
|
||||||
void bw_write_i16(struct byte_writer *bw, i16 v);
|
|
||||||
void bw_write_i32(struct byte_writer *bw, i32 v);
|
|
||||||
void bw_write_i64(struct byte_writer *bw, i64 v);
|
|
||||||
void bw_write_var_uint(struct byte_writer *bw, u64 v);
|
|
||||||
void bw_write_var_sint(struct byte_writer *bw, i64 v);
|
|
||||||
void bw_write_f32(struct byte_writer *bw, f32 v);
|
|
||||||
void bw_write_f64(struct byte_writer *bw, f64 v);
|
|
||||||
void bw_write_v2(struct byte_writer *bw, struct v2 v);
|
|
||||||
void bw_write_string(struct byte_writer *bw, struct string str);
|
|
||||||
|
|
||||||
/* Returns a string containing written bytes only */
|
|
||||||
INLINE struct string bw_get_written(struct byte_writer *bw)
|
|
||||||
{
|
|
||||||
struct string buff = ZI;
|
|
||||||
buff.text = bw->buff.text;
|
|
||||||
buff.len = bw->at - bw->buff.text;
|
|
||||||
return buff;
|
|
||||||
}
|
|
||||||
|
|
||||||
INLINE u64 bw_pos(struct byte_writer *bw)
|
|
||||||
{
|
|
||||||
return bw->at - bw->buff.text;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ========================== *
|
|
||||||
* Reader
|
|
||||||
* ========================== */
|
|
||||||
|
|
||||||
/* Will fill struct with zeroes on overflow */
|
|
||||||
#define br_read_to_struct(br_ptr, var_ptr) (br_read_to_buffer(br_ptr, STRING(sizeof(*var_ptr), (u8 *)var_ptr)))
|
|
||||||
|
|
||||||
struct byte_reader br_from_buffer(struct string buff);
|
|
||||||
|
|
||||||
void *br_seek(struct byte_reader *br, u64 amount);
|
|
||||||
void *br_seek_to(struct byte_reader *br, u64 pos);
|
|
||||||
|
|
||||||
void br_read_to_buffer(struct byte_reader *br, struct string s);
|
|
||||||
u8 br_read_u8(struct byte_reader *br);
|
|
||||||
u16 br_read_u16(struct byte_reader *br);
|
|
||||||
u32 br_read_u32(struct byte_reader *br);
|
|
||||||
u64 br_read_u64(struct byte_reader *br);
|
|
||||||
i8 br_read_i8(struct byte_reader *br);
|
|
||||||
i16 br_read_i16(struct byte_reader *br);
|
|
||||||
i32 br_read_i32(struct byte_reader *br);
|
|
||||||
i64 br_read_i64(struct byte_reader *br);
|
|
||||||
u64 br_read_var_uint(struct byte_reader *br);
|
|
||||||
i64 br_read_var_sint(struct byte_reader *br);
|
|
||||||
f32 br_read_f32(struct byte_reader *br);
|
|
||||||
f64 br_read_f64(struct byte_reader *br);
|
|
||||||
struct v2 br_read_v2(struct byte_reader *br);
|
|
||||||
struct string br_read_string(struct arena *arena, struct byte_reader *br);
|
|
||||||
|
|
||||||
INLINE u64 br_bytes_left(const struct byte_reader *br)
|
|
||||||
{
|
|
||||||
return br->overflowed ? 0 : br->buff.len - (br->at - br->buff.text);
|
|
||||||
}
|
|
||||||
|
|
||||||
INLINE u64 br_pos(struct byte_reader *br)
|
|
||||||
{
|
|
||||||
return br->at - br->buff.text;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -346,7 +346,7 @@ typedef i32 b32;
|
|||||||
#define I8_MIN ((i8)-0x80)
|
#define I8_MIN ((i8)-0x80)
|
||||||
#define I16_MIN ((i16)-0x8000)
|
#define I16_MIN ((i16)-0x8000)
|
||||||
#define I32_MIN ((i32)-0x80000000)
|
#define I32_MIN ((i32)-0x80000000)
|
||||||
#define I64_MIN ((i64)-0x8000000000000000LL)
|
#define I64_MIN ((i64)-0x8000000000000000ULL)
|
||||||
|
|
||||||
GLOBAL const u32 _f32_infinity_u32 = 0x7f800000;
|
GLOBAL const u32 _f32_infinity_u32 = 0x7f800000;
|
||||||
GLOBAL const f32 *_f32_infinity = (f32 *)&_f32_infinity_u32;
|
GLOBAL const f32 *_f32_infinity = (f32 *)&_f32_infinity_u32;
|
||||||
@ -656,8 +656,8 @@ struct collider_shape {
|
|||||||
* Common utilities
|
* Common utilities
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
INLINE u8 min_u8(u8 a, u8 b) { return a <= b ? a : b; }
|
INLINE u8 min_u8(u8 a, u8 b) { return a <= b ? a : b; }
|
||||||
INLINE u8 max_u8(u8 a, u8 b) { return a >= b ? a : b; }
|
INLINE u8 max_u8(u8 a, u8 b) { return a >= b ? a : b; }
|
||||||
INLINE u32 min_u32(u32 a, u32 b) { return a <= b ? a : b; }
|
INLINE u32 min_u32(u32 a, u32 b) { return a <= b ? a : b; }
|
||||||
INLINE u32 max_u32(u32 a, u32 b) { return a >= b ? a : b; }
|
INLINE u32 max_u32(u32 a, u32 b) { return a >= b ? a : b; }
|
||||||
INLINE u64 min_u64(u64 a, u64 b) { return a <= b ? a : b; }
|
INLINE u64 min_u64(u64 a, u64 b) { return a <= b ? a : b; }
|
||||||
|
|||||||
@ -61,6 +61,10 @@
|
|||||||
#define COLLIDER_DEBUG_DETAILED 0
|
#define COLLIDER_DEBUG_DETAILED 0
|
||||||
#define COLLIDER_DEBUG_DETAILED_DRAW_MENKOWSKI 0
|
#define COLLIDER_DEBUG_DETAILED_DRAW_MENKOWSKI 0
|
||||||
|
|
||||||
|
/* If enabled, bitbuffs will insert/verify magic numbers & length for each read & write */
|
||||||
|
#define BITBUFF_DEBUG 0
|
||||||
|
#define BITBUFF_TEST 0
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Settings
|
* Settings
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|||||||
130
src/host.c
130
src/host.c
@ -1,7 +1,7 @@
|
|||||||
#include "arena.h"
|
#include "arena.h"
|
||||||
#include "host.h"
|
#include "host.h"
|
||||||
#include "scratch.h"
|
#include "scratch.h"
|
||||||
#include "byteio.h"
|
#include "bitbuff.h"
|
||||||
#include "sys.h"
|
#include "sys.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
@ -400,7 +400,7 @@ INTERNAL struct host_msg_assembler *host_msg_assembler_alloc(struct host_channel
|
|||||||
|
|
||||||
ma->num_chunks_total = chunk_count;
|
ma->num_chunks_total = chunk_count;
|
||||||
|
|
||||||
u64 chunk_bitmap_size = ((chunk_count - 1) / 8) + 1;
|
u64 chunk_bitmap_size = (chunk_count + 7) >> 3;
|
||||||
if ((chunk_bitmap_size % 16) != 0) {
|
if ((chunk_bitmap_size % 16) != 0) {
|
||||||
/* Align chunk bitmap to 16 so msg data is aligned */
|
/* Align chunk bitmap to 16 so msg data is aligned */
|
||||||
chunk_bitmap_size += 16 - (chunk_bitmap_size % 16);
|
chunk_bitmap_size += 16 - (chunk_bitmap_size % 16);
|
||||||
@ -655,15 +655,16 @@ void host_update(struct host *host)
|
|||||||
for (struct host_rcv_packet *packet = rcv_buffer->first_packet; packet; packet = packet->next) {
|
for (struct host_rcv_packet *packet = rcv_buffer->first_packet; packet; packet = packet->next) {
|
||||||
//struct sock *sock = packet->sock;
|
//struct sock *sock = packet->sock;
|
||||||
struct sock_address address = packet->address;
|
struct sock_address address = packet->address;
|
||||||
struct byte_reader br = br_from_buffer(packet->data);
|
struct bitbuff bb = bitbuff_from_string(packet->data);
|
||||||
u32 magic = br_read_u32(&br);
|
struct bitbuff_reader br = br_from_bitbuff(&bb);
|
||||||
|
u32 magic = br_read_ubits(&br, 32);
|
||||||
if (magic == PACKET_MAGIC) {
|
if (magic == PACKET_MAGIC) {
|
||||||
/* TODO: Combine kind byte with flags byte */
|
/* TODO: Combine kind byte with flags byte */
|
||||||
struct host_channel *channel = host_channel_from_address(host, address);
|
struct host_channel *channel = host_channel_from_address(host, address);
|
||||||
enum host_packet_kind host_packet_kind = br_read_i8(&br);
|
enum host_packet_kind host_packet_kind = br_read_ibits(&br, 8);
|
||||||
u8 packet_flags = br_read_u8(&br);
|
u8 packet_flags = br_read_ubits(&br, 8);
|
||||||
|
|
||||||
u64 their_acked_seq = br_read_var_uint(&br);
|
u64 their_acked_seq = br_read_uv(&br);
|
||||||
if (their_acked_seq > channel->their_acked_seq) {
|
if (their_acked_seq > channel->their_acked_seq) {
|
||||||
channel->their_acked_seq = their_acked_seq;
|
channel->their_acked_seq = their_acked_seq;
|
||||||
}
|
}
|
||||||
@ -672,7 +673,7 @@ void host_update(struct host *host)
|
|||||||
b32 is_reliable = packet_flags & HOST_PACKET_FLAG_RELIABLE;
|
b32 is_reliable = packet_flags & HOST_PACKET_FLAG_RELIABLE;
|
||||||
if (channel->valid) {
|
if (channel->valid) {
|
||||||
if (is_reliable) {
|
if (is_reliable) {
|
||||||
u64 packet_seq = br_read_var_uint(&br);
|
u64 packet_seq = br_read_uv(&br);
|
||||||
if (packet_seq == channel->our_acked_seq + 1) {
|
if (packet_seq == channel->our_acked_seq + 1) {
|
||||||
channel->our_acked_seq = packet_seq;
|
channel->our_acked_seq = packet_seq;
|
||||||
} else {
|
} else {
|
||||||
@ -725,11 +726,11 @@ void host_update(struct host *host)
|
|||||||
{
|
{
|
||||||
if (channel->valid && channel->connected) {
|
if (channel->valid && channel->connected) {
|
||||||
/* Packet is chunk <chunk_id> out of <chunk_count> belonging to message <msg_id> */
|
/* Packet is chunk <chunk_id> out of <chunk_count> belonging to message <msg_id> */
|
||||||
u64 msg_id = br_read_var_uint(&br);
|
u64 msg_id = br_read_uv(&br);
|
||||||
u64 chunk_id = br_read_var_uint(&br);
|
u64 chunk_id = br_read_uv(&br);
|
||||||
u64 chunk_count = br_read_var_uint(&br);
|
u64 chunk_count = br_read_uv(&br);
|
||||||
b32 is_last_chunk = (chunk_id + 1) == chunk_count;
|
b32 is_last_chunk = (chunk_id + 1) == chunk_count;
|
||||||
u64 data_len = is_last_chunk ? br_read_var_uint(&br) : PACKET_MSG_CHUNK_MAX_LEN;
|
u64 chunk_len = is_last_chunk ? br_read_uv(&br) : PACKET_MSG_CHUNK_MAX_LEN;
|
||||||
|
|
||||||
struct host_msg_assembler *ma = host_get_msg_assembler(host, channel->id, msg_id);
|
struct host_msg_assembler *ma = host_get_msg_assembler(host, channel->id, msg_id);
|
||||||
if (!ma) {
|
if (!ma) {
|
||||||
@ -738,12 +739,12 @@ void host_update(struct host *host)
|
|||||||
|
|
||||||
if (chunk_count == ma->num_chunks_total && chunk_id < chunk_count) {
|
if (chunk_count == ma->num_chunks_total && chunk_id < chunk_count) {
|
||||||
if (!host_msg_assembler_is_chunk_filled(ma, chunk_id)) {
|
if (!host_msg_assembler_is_chunk_filled(ma, chunk_id)) {
|
||||||
u8 *src = br_seek(&br, data_len);
|
u8 *src = br_read_bytes_raw(&br, chunk_len);
|
||||||
if (src) {
|
if (src) {
|
||||||
u8 *dst = &ma->chunk_data[chunk_id * PACKET_MSG_CHUNK_MAX_LEN];
|
u8 *dst = &ma->chunk_data[chunk_id * PACKET_MSG_CHUNK_MAX_LEN];
|
||||||
MEMCPY(dst, src, data_len);
|
MEMCPY(dst, src, chunk_len);
|
||||||
if (is_last_chunk) {
|
if (is_last_chunk) {
|
||||||
ma->last_chunk_len = data_len;
|
ma->last_chunk_len = chunk_len;
|
||||||
}
|
}
|
||||||
host_msg_assembler_set_chunk_received(ma, chunk_id);
|
host_msg_assembler_set_chunk_received(ma, chunk_id);
|
||||||
++ma->num_chunks_received;
|
++ma->num_chunks_received;
|
||||||
@ -765,10 +766,12 @@ void host_update(struct host *host)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
/* Overflow reading chunk */
|
||||||
ASSERT(false);
|
ASSERT(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
/* Chunk id/count mismatch */
|
||||||
ASSERT(false);
|
ASSERT(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -801,19 +804,19 @@ void host_update(struct host *host)
|
|||||||
/* Release acked reliable packets */
|
/* Release acked reliable packets */
|
||||||
{
|
{
|
||||||
u64 acked_seq = channel->their_acked_seq;
|
u64 acked_seq = channel->their_acked_seq;
|
||||||
struct host_snd_packet *host_packet = channel->first_reliable_packet;
|
struct host_snd_packet *packet = channel->first_reliable_packet;
|
||||||
while (host_packet) {
|
while (packet) {
|
||||||
struct host_snd_packet *next = host_packet->next;
|
struct host_snd_packet *next = packet->next;
|
||||||
u64 seq = host_packet->seq;
|
u64 seq = packet->seq;
|
||||||
if (seq < acked_seq) {
|
if (seq < acked_seq) {
|
||||||
host_packet->next = host->first_free_packet;
|
packet->next = host->first_free_packet;
|
||||||
host->first_free_packet = host_packet;
|
host->first_free_packet = packet;
|
||||||
channel->first_reliable_packet = next;
|
channel->first_reliable_packet = next;
|
||||||
--channel->num_reliable_packets;
|
--channel->num_reliable_packets;
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
host_packet = next;
|
packet = next;
|
||||||
}
|
}
|
||||||
if (channel->first_reliable_packet == NULL) {
|
if (channel->first_reliable_packet == NULL) {
|
||||||
channel->last_reliable_packet = NULL;
|
channel->last_reliable_packet = NULL;
|
||||||
@ -854,37 +857,40 @@ void host_update(struct host *host)
|
|||||||
case HOST_CMD_KIND_TRY_CONNECT:
|
case HOST_CMD_KIND_TRY_CONNECT:
|
||||||
{
|
{
|
||||||
u8 packet_flags = 0;
|
u8 packet_flags = 0;
|
||||||
struct host_snd_packet *host_packet = host_channel_snd_packet_alloc(channel, false);
|
struct host_snd_packet *packet = host_channel_snd_packet_alloc(channel, false);
|
||||||
struct byte_writer bw = bw_from_buffer(STRING_FROM_ARRAY(host_packet->data));
|
struct bitbuff bb = bitbuff_from_string(STRING_FROM_ARRAY(packet->data));
|
||||||
bw_write_u32(&bw, PACKET_MAGIC);
|
struct bitbuff_writer bw = bw_from_bitbuff(&bb);
|
||||||
bw_write_i8(&bw, HOST_PACKET_KIND_TRY_CONNECT);
|
bw_write_ubits(&bw, PACKET_MAGIC, 32);
|
||||||
bw_write_u8(&bw, packet_flags);
|
bw_write_ibits(&bw, HOST_PACKET_KIND_TRY_CONNECT, 8);
|
||||||
bw_write_var_uint(&bw, channel->our_acked_seq);
|
bw_write_ubits(&bw, packet_flags, 8);
|
||||||
host_packet->data_len = bw_pos(&bw);
|
bw_write_uv(&bw, channel->our_acked_seq);
|
||||||
|
packet->data_len = bw_num_bytes_written(&bw);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case HOST_CMD_KIND_CONNECT_SUCCESS:
|
case HOST_CMD_KIND_CONNECT_SUCCESS:
|
||||||
{
|
{
|
||||||
u8 packet_flags = 0;
|
u8 packet_flags = 0;
|
||||||
struct host_snd_packet *host_packet = host_channel_snd_packet_alloc(channel, false);
|
struct host_snd_packet *packet = host_channel_snd_packet_alloc(channel, false);
|
||||||
struct byte_writer bw = bw_from_buffer(STRING_FROM_ARRAY(host_packet->data));
|
struct bitbuff bb = bitbuff_from_string(STRING_FROM_ARRAY(packet->data));
|
||||||
bw_write_u32(&bw, PACKET_MAGIC);
|
struct bitbuff_writer bw = bw_from_bitbuff(&bb);
|
||||||
bw_write_i8(&bw, HOST_PACKET_KIND_CONNECT_SUCCESS);
|
bw_write_ubits(&bw, PACKET_MAGIC, 32);
|
||||||
bw_write_u8(&bw, packet_flags);
|
bw_write_ibits(&bw, HOST_PACKET_KIND_CONNECT_SUCCESS, 8);
|
||||||
bw_write_var_uint(&bw, channel->our_acked_seq);
|
bw_write_ubits(&bw, packet_flags, 8);
|
||||||
host_packet->data_len = bw_pos(&bw);
|
bw_write_uv(&bw, channel->our_acked_seq);
|
||||||
|
packet->data_len = bw_num_bytes_written(&bw);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case HOST_CMD_KIND_DISCONNECT:
|
case HOST_CMD_KIND_DISCONNECT:
|
||||||
{
|
{
|
||||||
u8 packet_flags = 0;
|
u8 packet_flags = 0;
|
||||||
struct host_snd_packet *host_packet = host_channel_snd_packet_alloc(channel, false);
|
struct host_snd_packet *packet = host_channel_snd_packet_alloc(channel, false);
|
||||||
struct byte_writer bw = bw_from_buffer(STRING_FROM_ARRAY(host_packet->data));
|
struct bitbuff bb = bitbuff_from_string(STRING_FROM_ARRAY(packet->data));
|
||||||
bw_write_u32(&bw, PACKET_MAGIC);
|
struct bitbuff_writer bw = bw_from_bitbuff(&bb);
|
||||||
bw_write_i8(&bw, HOST_PACKET_KIND_DISCONNECT);
|
bw_write_ubits(&bw, PACKET_MAGIC, 32);
|
||||||
bw_write_u8(&bw, packet_flags);
|
bw_write_ibits(&bw, HOST_PACKET_KIND_DISCONNECT, 8);
|
||||||
bw_write_var_uint(&bw, channel->our_acked_seq);
|
bw_write_ubits(&bw, packet_flags, 8);
|
||||||
host_packet->data_len = bw_pos(&bw);
|
bw_write_uv(&bw, channel->our_acked_seq);
|
||||||
|
packet->data_len = bw_num_bytes_written(&bw);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case HOST_CMD_KIND_WRITE:
|
case HOST_CMD_KIND_WRITE:
|
||||||
@ -901,33 +907,33 @@ void host_update(struct host *host)
|
|||||||
|
|
||||||
u64 msg_id = ++channel->last_sent_msg_id;
|
u64 msg_id = ++channel->last_sent_msg_id;
|
||||||
for (u64 i = 0; i < chunk_count; ++i) {
|
for (u64 i = 0; i < chunk_count; ++i) {
|
||||||
u64 data_len = PACKET_MSG_CHUNK_MAX_LEN;
|
u64 chunk_len = PACKET_MSG_CHUNK_MAX_LEN;
|
||||||
b32 is_last_chunk = i + 1 == chunk_count;
|
b32 is_last_chunk = i + 1 == chunk_count;
|
||||||
if (is_last_chunk) {
|
if (is_last_chunk) {
|
||||||
data_len = msg.len % PACKET_MSG_CHUNK_MAX_LEN;
|
chunk_len = msg.len % PACKET_MSG_CHUNK_MAX_LEN;
|
||||||
if (data_len == 0) {
|
if (chunk_len == 0) {
|
||||||
data_len = PACKET_MSG_CHUNK_MAX_LEN;
|
chunk_len = PACKET_MSG_CHUNK_MAX_LEN;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
u8 *data = msg.text + (i * PACKET_MSG_CHUNK_MAX_LEN);
|
struct host_snd_packet *packet = host_channel_snd_packet_alloc(channel, is_reliable);
|
||||||
struct host_snd_packet *host_packet = host_channel_snd_packet_alloc(channel, is_reliable);
|
struct bitbuff bb = bitbuff_from_string(STRING_FROM_ARRAY(packet->data));
|
||||||
struct byte_writer bw = bw_from_buffer(STRING_FROM_ARRAY(host_packet->data));
|
struct bitbuff_writer bw = bw_from_bitbuff(&bb);
|
||||||
bw_write_u32(&bw, PACKET_MAGIC);
|
bw_write_ubits(&bw, PACKET_MAGIC, 32);
|
||||||
bw_write_i8(&bw, HOST_PACKET_KIND_MSG_CHUNK);
|
bw_write_ibits(&bw, HOST_PACKET_KIND_MSG_CHUNK, 8);
|
||||||
bw_write_u8(&bw, packet_flags);
|
bw_write_ubits(&bw, packet_flags, 8);
|
||||||
bw_write_var_uint(&bw, channel->our_acked_seq);
|
bw_write_uv(&bw, channel->our_acked_seq);
|
||||||
if (is_reliable) {
|
if (is_reliable) {
|
||||||
bw_write_var_uint(&bw, host_packet->seq);
|
bw_write_uv(&bw, packet->seq);
|
||||||
}
|
}
|
||||||
bw_write_var_uint(&bw, msg_id);
|
bw_write_uv(&bw, msg_id);
|
||||||
bw_write_var_uint(&bw, i);
|
bw_write_uv(&bw, i);
|
||||||
bw_write_var_uint(&bw, chunk_count);
|
bw_write_uv(&bw, chunk_count);
|
||||||
if (is_last_chunk) {
|
if (is_last_chunk) {
|
||||||
/* FIXME: Ensure data_len can never be 0 */
|
bw_write_uv(&bw, chunk_len);
|
||||||
bw_write_var_uint(&bw, data_len);
|
|
||||||
}
|
}
|
||||||
bw_write_bytes(&bw, STRING(data_len, data));
|
u8 *chunk_data = msg.text + (i * PACKET_MSG_CHUNK_MAX_LEN);
|
||||||
host_packet->data_len = bw_pos(&bw);
|
bw_write_bytes(&bw, STRING(chunk_len, chunk_data));
|
||||||
|
packet->data_len = bw_num_bytes_written(&bw);
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
|||||||
12
src/memory.c
12
src/memory.c
@ -3,23 +3,23 @@
|
|||||||
#if !CRTLIB
|
#if !CRTLIB
|
||||||
|
|
||||||
__attribute((section(".text.memcpy")))
|
__attribute((section(".text.memcpy")))
|
||||||
void *memcpy(void *__restrict dest, const void *__restrict src, u64 n)
|
void *memcpy(void *__restrict dst, const void *__restrict src, u64 n)
|
||||||
{
|
{
|
||||||
/* TODO: Faster memcpy */
|
/* TODO: Faster memcpy */
|
||||||
for (u64 i = 0; i < n; ++i) {
|
for (u64 i = 0; i < n; ++i) {
|
||||||
((u8 *)dest)[i] = ((u8 *)src)[i];
|
((u8 *)dst)[i] = ((u8 *)src)[i];
|
||||||
}
|
}
|
||||||
return dest;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute((section(".text.memset")))
|
__attribute((section(".text.memset")))
|
||||||
void *memset(void *dest, i32 c, u64 n)
|
void *memset(void *dst, i32 c, u64 n)
|
||||||
{
|
{
|
||||||
/* TODO: Faster memset */
|
/* TODO: Faster memset */
|
||||||
for (u64 i = 0; i < n; ++i) {
|
for (u64 i = 0; i < n; ++i) {
|
||||||
((u8 *)dest)[i] = c;
|
((u8 *)dst)[i] = c;
|
||||||
}
|
}
|
||||||
return dest;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute((section(".text.memcmp")))
|
__attribute((section(".text.memcmp")))
|
||||||
|
|||||||
@ -5,8 +5,8 @@
|
|||||||
#define MEMZERO_ARRAY(a) MEMZERO((a), sizeof((a)))
|
#define MEMZERO_ARRAY(a) MEMZERO((a), sizeof((a)))
|
||||||
#define MEMZERO(ptr, count) MEMSET((ptr), 0, (count))
|
#define MEMZERO(ptr, count) MEMSET((ptr), 0, (count))
|
||||||
|
|
||||||
#define MEMCPY_STRUCT(ptr_dest, ptr_src) MEMCPY((ptr_dest), (ptr_src), sizeof(*(ptr_dest)));
|
#define MEMCPY_STRUCT(ptr_dst, ptr_src) MEMCPY((ptr_dst), (ptr_src), sizeof(*(ptr_dst)));
|
||||||
#define MEMCPY(dest, src, count) memcpy((dest), (src), (count))
|
#define MEMCPY(dst, src, count) memcpy((dst), (src), (count))
|
||||||
|
|
||||||
#define MEMCMP_STRUCT(p1, p2) MEMCMP((p1), (p2), sizeof(*p1))
|
#define MEMCMP_STRUCT(p1, p2) MEMCMP((p1), (p2), sizeof(*p1))
|
||||||
#define MEMCMP(p1, p2, n) memcmp((p1), (p2), (n))
|
#define MEMCMP(p1, p2, n) memcmp((p1), (p2), (n))
|
||||||
@ -19,8 +19,8 @@
|
|||||||
#if CRTLIB
|
#if CRTLIB
|
||||||
# include <memory.h>
|
# include <memory.h>
|
||||||
#else
|
#else
|
||||||
void *memcpy(void *__restrict dest, const void *__restrict src, u64 n);
|
void *memcpy(void *__restrict dst, const void *__restrict src, u64 n);
|
||||||
void *memset(void *dest, i32 c, u64 n);
|
void *memset(void *dst, i32 c, u64 n);
|
||||||
i32 memcmp(const void *p1, const void *p2, u64 n);
|
i32 memcmp(const void *p1, const void *p2, u64 n);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@ -77,7 +77,7 @@ INLINE struct temp_arena _scratch_begin(struct arena *potential_conflict)
|
|||||||
#define scratch_begin_no_conflict() \
|
#define scratch_begin_no_conflict() \
|
||||||
_scratch_begin_no_conflict(); \
|
_scratch_begin_no_conflict(); \
|
||||||
do { \
|
do { \
|
||||||
struct arena *arena = NULL; \
|
u8 arena = 0; \
|
||||||
(UNUSED)arena; \
|
(UNUSED)arena; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
|||||||
186
src/sim.c
186
src/sim.c
@ -14,7 +14,7 @@
|
|||||||
#include "collider.h"
|
#include "collider.h"
|
||||||
#include "rng.h"
|
#include "rng.h"
|
||||||
#include "space.h"
|
#include "space.h"
|
||||||
#include "byteio.h"
|
#include "bitbuff.h"
|
||||||
#include "host.h"
|
#include "host.h"
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
@ -39,6 +39,9 @@ struct sim_ctx *sim_ctx_alloc(struct sprite_startup_receipt *sprite_sr,
|
|||||||
/* Intialize host */
|
/* Intialize host */
|
||||||
ctx->host = host_alloc(host_port);
|
ctx->host = host_alloc(host_port);
|
||||||
|
|
||||||
|
/* Allocate encoder bitbuff */
|
||||||
|
ctx->encoder_bitbuff = bitbuff_alloc(GIGABYTE(64));
|
||||||
|
|
||||||
/* Create bookkeeping */
|
/* Create bookkeeping */
|
||||||
ctx->contact_lookup = sim_ent_lookup_alloc(4096);
|
ctx->contact_lookup = sim_ent_lookup_alloc(4096);
|
||||||
#if COLLIDER_DEBUG
|
#if COLLIDER_DEBUG
|
||||||
@ -67,7 +70,12 @@ void sim_ctx_release(struct sim_ctx *ctx)
|
|||||||
#endif
|
#endif
|
||||||
sim_ent_lookup_release(&ctx->contact_lookup);
|
sim_ent_lookup_release(&ctx->contact_lookup);
|
||||||
|
|
||||||
|
/* Release encoder bitbuff */
|
||||||
|
bitbuff_release(&ctx->encoder_bitbuff);
|
||||||
|
|
||||||
|
/* Release host */
|
||||||
host_release(ctx->host);
|
host_release(ctx->host);
|
||||||
|
|
||||||
arena_release(&ctx->arena);
|
arena_release(&ctx->arena);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -513,7 +521,7 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
|
|||||||
struct host_event_array host_events = host_pop_events(scratch.arena, ctx->host);
|
struct host_event_array host_events = host_pop_events(scratch.arena, ctx->host);
|
||||||
|
|
||||||
struct sim_cmd_list sim_cmds = ZI;
|
struct sim_cmd_list sim_cmds = ZI;
|
||||||
sim_cmds_from_host_events(scratch.arena, host_events, &sim_cmds);
|
sim_cmds_decode(scratch.arena, host_events, &sim_cmds);
|
||||||
|
|
||||||
/* Create connecting clients */
|
/* Create connecting clients */
|
||||||
for (struct sim_cmd *cmd = sim_cmds.first; cmd; cmd = cmd->next) {
|
for (struct sim_cmd *cmd = sim_cmds.first; cmd; cmd = cmd->next) {
|
||||||
@ -1378,30 +1386,6 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
|
|||||||
* Publish tick
|
* Publish tick
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
#if 0
|
|
||||||
for (u64 i = 0; i < ctx->world->num_clients_reserved; ++i) {
|
|
||||||
struct sim_client *client = &ctx->world->clients[i];
|
|
||||||
if (client->valid) {
|
|
||||||
struct temp_arena temp = arena_temp_begin(scratch.arena);
|
|
||||||
|
|
||||||
/* TODO: Not like this */
|
|
||||||
struct sim_event snapshot_event = ZI;
|
|
||||||
snapshot_event.tick = ctx->world->tick;
|
|
||||||
snapshot_event.kind = SIM_EVENT_KIND_SNAPSHOT;
|
|
||||||
snapshot_event.encoded_snapshot = sim_snapshot_encode(temp.arena, client, ctx->world);
|
|
||||||
|
|
||||||
struct sim_event_list l = ZI;
|
|
||||||
l.first = &snapshot_event;
|
|
||||||
l.last = &snapshot_event;
|
|
||||||
struct string msg = sim_string_from_events(temp.arena, l);
|
|
||||||
|
|
||||||
host_queue_write(ctx->host, client->channel_id, msg, 0);
|
|
||||||
//host_queue_write(ctx->host, HOST_CHANNEL_ID_ALL, msg, 0);
|
|
||||||
|
|
||||||
arena_temp_end(temp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
for (u64 i = 0; i < ctx->world->num_clients_reserved; ++i) {
|
for (u64 i = 0; i < ctx->world->num_clients_reserved; ++i) {
|
||||||
struct sim_client *client = &ctx->world->clients[i];
|
struct sim_client *client = &ctx->world->clients[i];
|
||||||
if (client->valid) {
|
if (client->valid) {
|
||||||
@ -1413,33 +1397,43 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
|
|||||||
struct sim_snapshot *ss1 = ctx->world;
|
struct sim_snapshot *ss1 = ctx->world;
|
||||||
ss0_tick = ss0->tick; /* In case ack tick is no longer in store we need to do a full resend */
|
ss0_tick = ss0->tick; /* In case ack tick is no longer in store we need to do a full resend */
|
||||||
|
|
||||||
struct sim_event snapshot_event = ZI;
|
|
||||||
snapshot_event.kind = SIM_EVENT_KIND_SNAPSHOT;
|
|
||||||
snapshot_event.tick = ctx->world->tick;
|
|
||||||
|
|
||||||
snapshot_event.snapshot_tick_start = ss0_tick;
|
|
||||||
snapshot_event.snapshot_tick_end = ss1_tick;
|
|
||||||
|
|
||||||
struct sim_encoder encoder = ZI;
|
|
||||||
encoder.client = client;
|
|
||||||
/* FIXME: Don't store external arena in bw. Could end up with hidden scratch conflicts. */
|
|
||||||
encoder.bw = bw_from_arena(temp.arena);
|
|
||||||
|
|
||||||
sim_snapshot_encode(&encoder, ss0, ss1);
|
|
||||||
snapshot_event.snapshot_encoded = bw_get_written(&encoder.bw);
|
|
||||||
|
|
||||||
struct sim_event_list l = ZI;
|
struct sim_event_list l = ZI;
|
||||||
l.first = &snapshot_event;
|
|
||||||
l.last = &snapshot_event;
|
|
||||||
struct string msg = sim_string_from_events(temp.arena, l);
|
|
||||||
|
|
||||||
host_queue_write(ctx->host, client->channel_id, msg, 0);
|
/* Create & encode snapshot event */
|
||||||
//host_queue_write(ctx->host, HOST_CHANNEL_ID_ALL, msg, 0);
|
{
|
||||||
|
struct sim_event snapshot_event = ZI;
|
||||||
|
snapshot_event.kind = SIM_EVENT_KIND_SNAPSHOT;
|
||||||
|
snapshot_event.tick = ctx->world->tick;
|
||||||
|
snapshot_event.snapshot_tick_start = ss0_tick;
|
||||||
|
snapshot_event.snapshot_tick_end = ss1_tick;
|
||||||
|
|
||||||
|
{
|
||||||
|
struct bitbuff_writer bw = bw_from_bitbuff(&ctx->encoder_bitbuff);
|
||||||
|
sim_snapshot_encode(&bw, ss0, ss1, client);
|
||||||
|
snapshot_event.snapshot_encoded = bw_get_written(temp.arena, &bw);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (l.last) {
|
||||||
|
l.last->next = &snapshot_event;
|
||||||
|
} else {
|
||||||
|
l.first = &snapshot_event;
|
||||||
|
}
|
||||||
|
l.last = &snapshot_event;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Encode events */
|
||||||
|
struct string events_msg = ZI;
|
||||||
|
{
|
||||||
|
struct bitbuff_writer bw = bw_from_bitbuff(&ctx->encoder_bitbuff);
|
||||||
|
sim_events_encode(&bw, l);
|
||||||
|
events_msg = bw_get_written(temp.arena, &bw);
|
||||||
|
}
|
||||||
|
|
||||||
|
host_queue_write(ctx->host, client->channel_id, events_msg, 0);
|
||||||
|
|
||||||
arena_temp_end(temp);
|
arena_temp_end(temp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
host_update(ctx->host);
|
host_update(ctx->host);
|
||||||
__profframe("Sim");
|
__profframe("Sim");
|
||||||
@ -1457,46 +1451,39 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
|
|||||||
* Sim cmd
|
* Sim cmd
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
struct string sim_string_from_cmds(struct arena *arena, struct sim_cmd_list cmds, u64 ack_tick)
|
void sim_cmds_encode(struct bitbuff_writer *bw, struct sim_cmd_list cmds, u64 ack_tick)
|
||||||
{
|
{
|
||||||
__prof;
|
__prof;
|
||||||
struct byte_writer bw = bw_from_arena(arena);
|
|
||||||
|
|
||||||
for (struct sim_cmd *cmd = cmds.first; cmd; cmd = cmd->next) {
|
for (struct sim_cmd *cmd = cmds.first; cmd; cmd = cmd->next) {
|
||||||
struct byte_writer bw_size = bw_branch(&bw, sizeof(u64));
|
bw_write_ibits(bw, cmd->kind, 8);
|
||||||
u64 start = bw_pos(&bw);
|
bw_write_ibits(bw, cmd->state, 8);
|
||||||
|
bw_write_uv(bw, ack_tick);
|
||||||
bw_write_i8(&bw, cmd->kind);
|
|
||||||
bw_write_i8(&bw, cmd->state);
|
|
||||||
bw_write_var_uint(&bw, ack_tick);
|
|
||||||
|
|
||||||
#if COLLIDER_DEBUG
|
#if COLLIDER_DEBUG
|
||||||
bw_write_u32(&bw, cmd->collider_gjk_steps);
|
bw_write_ubits(bw, cmd->collider_gjk_steps, 32);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
switch (cmd->kind) {
|
switch (cmd->kind) {
|
||||||
case SIM_CMD_KIND_PLAYER_CONTROL:
|
case SIM_CMD_KIND_PLAYER_CONTROL:
|
||||||
{
|
{
|
||||||
bw_write_v2(&bw, cmd->move_dir);
|
bw_write_f32(bw, cmd->move_dir.x);
|
||||||
bw_write_v2(&bw, cmd->aim_dir);
|
bw_write_f32(bw, cmd->move_dir.y);
|
||||||
|
bw_write_f32(bw, cmd->aim_dir.x);
|
||||||
|
bw_write_f32(bw, cmd->aim_dir.y);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case SIM_CMD_KIND_CURSOR_MOVE:
|
case SIM_CMD_KIND_CURSOR_MOVE:
|
||||||
{
|
{
|
||||||
bw_write_v2(&bw, cmd->cursor_pos);
|
bw_write_f32(bw, cmd->cursor_pos.x);
|
||||||
|
bw_write_f32(bw, cmd->cursor_pos.y);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 size = bw_pos(&bw) - start;
|
|
||||||
bw_write_u64(&bw_size, size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return bw_get_written(&bw);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void sim_cmds_from_host_events(struct arena *arena, struct host_event_array host_events, struct sim_cmd_list *cmds_out)
|
void sim_cmds_decode(struct arena *arena, struct host_event_array host_events, struct sim_cmd_list *cmds_out)
|
||||||
{
|
{
|
||||||
__prof;
|
__prof;
|
||||||
for (u64 i = 0; i < host_events.count; ++i) {
|
for (u64 i = 0; i < host_events.count; ++i) {
|
||||||
@ -1531,37 +1518,36 @@ void sim_cmds_from_host_events(struct arena *arena, struct host_event_array host
|
|||||||
|
|
||||||
case HOST_EVENT_KIND_MSG:
|
case HOST_EVENT_KIND_MSG:
|
||||||
{
|
{
|
||||||
struct byte_reader br = br_from_buffer(host_event.msg);
|
struct bitbuff bb = bitbuff_from_string(host_event.msg);
|
||||||
while (br_bytes_left(&br) > 0) {
|
struct bitbuff_reader br = br_from_bitbuff(&bb);
|
||||||
|
while (br_num_bits_left(&br) > 0) {
|
||||||
struct sim_cmd *cmd = arena_push_zero(arena, struct sim_cmd);
|
struct sim_cmd *cmd = arena_push_zero(arena, struct sim_cmd);
|
||||||
u64 cmd_size = br_read_u64(&br);
|
cmd->kind = br_read_ibits(&br, 8);
|
||||||
u64 cmd_pos_end = br_pos(&br) + cmd_size;
|
|
||||||
cmd->kind = br_read_i8(&br);
|
|
||||||
cmd->channel_id = host_event.channel_id;
|
cmd->channel_id = host_event.channel_id;
|
||||||
cmd->state = br_read_i8(&br);
|
cmd->state = br_read_ibits(&br, 8);
|
||||||
cmd->ack_tick = br_read_var_uint(&br);
|
cmd->ack_tick = br_read_uv(&br);
|
||||||
#if COLLIDER_DEBUG
|
#if COLLIDER_DEBUG
|
||||||
cmd->collider_gjk_steps = br_read_u32(&br);
|
cmd->collider_gjk_steps = br_read_ubits(&br, 32);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
switch (cmd->kind) {
|
switch (cmd->kind) {
|
||||||
case SIM_CMD_KIND_PLAYER_CONTROL:
|
case SIM_CMD_KIND_PLAYER_CONTROL:
|
||||||
{
|
{
|
||||||
cmd->move_dir = br_read_v2(&br);
|
cmd->move_dir.x = br_read_f32(&br);
|
||||||
cmd->aim_dir = br_read_v2(&br);
|
cmd->move_dir.y = br_read_f32(&br);
|
||||||
|
cmd->aim_dir.x = br_read_f32(&br);
|
||||||
|
cmd->aim_dir.y = br_read_f32(&br);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case SIM_CMD_KIND_CURSOR_MOVE:
|
case SIM_CMD_KIND_CURSOR_MOVE:
|
||||||
{
|
{
|
||||||
cmd->cursor_pos = br_read_v2(&br);
|
cmd->cursor_pos.x = br_read_f32(&br);
|
||||||
|
cmd->cursor_pos.y = br_read_f32(&br);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT(br_pos(&br) == cmd_pos_end);
|
|
||||||
br_seek_to(&br, cmd_pos_end);
|
|
||||||
|
|
||||||
if (cmds_out->last) {
|
if (cmds_out->last) {
|
||||||
cmds_out->last->next = cmd;
|
cmds_out->last->next = cmd;
|
||||||
} else {
|
} else {
|
||||||
@ -1580,34 +1566,27 @@ void sim_cmds_from_host_events(struct arena *arena, struct host_event_array host
|
|||||||
* Sim event
|
* Sim event
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
struct string sim_string_from_events(struct arena *arena, struct sim_event_list events)
|
void sim_events_encode(struct bitbuff_writer *bw, struct sim_event_list events)
|
||||||
{
|
{
|
||||||
__prof;
|
__prof;
|
||||||
struct byte_writer bw = bw_from_arena(arena);
|
|
||||||
for (struct sim_event *event = events.first; event; event = event->next) {
|
for (struct sim_event *event = events.first; event; event = event->next) {
|
||||||
struct byte_writer bw_size = bw_branch(&bw, sizeof(u64));
|
bw_write_uv(bw, event->tick);
|
||||||
u64 start = bw_pos(&bw);
|
bw_write_ibits(bw, event->kind, 8);
|
||||||
bw_write_var_uint(&bw, event->tick);
|
|
||||||
bw_write_i8(&bw, event->kind);
|
|
||||||
|
|
||||||
switch (event->kind) {
|
switch (event->kind) {
|
||||||
case SIM_EVENT_KIND_SNAPSHOT:
|
case SIM_EVENT_KIND_SNAPSHOT:
|
||||||
{
|
{
|
||||||
bw_write_var_uint(&bw, event->snapshot_tick_start);
|
bw_write_uv(bw, event->snapshot_tick_start);
|
||||||
bw_write_var_uint(&bw, event->snapshot_tick_end);
|
bw_write_uv(bw, event->snapshot_tick_end);
|
||||||
bw_write_string(&bw, event->snapshot_encoded);
|
bw_write_string(bw, event->snapshot_encoded);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 size = bw_pos(&bw) - start;
|
|
||||||
bw_write_u64(&bw_size, size);
|
|
||||||
}
|
}
|
||||||
return bw_get_written(&bw);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void sim_events_from_host_events(struct arena *arena, struct host_event_array host_events, struct sim_event_list *events_out)
|
void sim_events_decode(struct arena *arena, struct host_event_array host_events, struct sim_event_list *events_out)
|
||||||
{
|
{
|
||||||
__prof;
|
__prof;
|
||||||
for (u64 i = 0; i < host_events.count; ++i) {
|
for (u64 i = 0; i < host_events.count; ++i) {
|
||||||
@ -1629,26 +1608,21 @@ void sim_events_from_host_events(struct arena *arena, struct host_event_array ho
|
|||||||
|
|
||||||
case HOST_EVENT_KIND_MSG:
|
case HOST_EVENT_KIND_MSG:
|
||||||
{
|
{
|
||||||
struct byte_reader br = br_from_buffer(host_event.msg);
|
struct bitbuff bb = bitbuff_from_string(host_event.msg);
|
||||||
while (br_bytes_left(&br) > 0) {
|
struct bitbuff_reader br = br_from_bitbuff(&bb);
|
||||||
u64 event_size = br_read_u64(&br);
|
while (br_num_bits_left(&br) > 0) {
|
||||||
u64 event_pos_end = br_pos(&br) + event_size;
|
sim_event->tick = br_read_uv(&br);
|
||||||
|
sim_event->kind = br_read_ibits(&br, 8);
|
||||||
sim_event->tick = br_read_var_uint(&br);
|
|
||||||
sim_event->kind = br_read_i8(&br);
|
|
||||||
switch (sim_event->kind) {
|
switch (sim_event->kind) {
|
||||||
case SIM_EVENT_KIND_SNAPSHOT:
|
case SIM_EVENT_KIND_SNAPSHOT:
|
||||||
{
|
{
|
||||||
sim_event->snapshot_tick_start = br_read_var_uint(&br);
|
sim_event->snapshot_tick_start = br_read_uv(&br);
|
||||||
sim_event->snapshot_tick_end = br_read_var_uint(&br);
|
sim_event->snapshot_tick_end = br_read_uv(&br);
|
||||||
sim_event->snapshot_encoded = br_read_string(arena, &br);
|
sim_event->snapshot_encoded = br_read_string(arena, &br);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT(br_pos(&br) == event_pos_end);
|
|
||||||
br_seek_to(&br, event_pos_end);
|
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
|||||||
25
src/sim.h
25
src/sim.h
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "sim_ent.h"
|
#include "sim_ent.h"
|
||||||
#include "sim_snapshot.h"
|
#include "sim_snapshot.h"
|
||||||
|
#include "bitbuff.h"
|
||||||
|
|
||||||
struct sprite_startup_receipt;
|
struct sprite_startup_receipt;
|
||||||
struct phys_startup_receipt;
|
struct phys_startup_receipt;
|
||||||
@ -124,7 +125,11 @@ struct sim_event_list {
|
|||||||
struct sim_ctx {
|
struct sim_ctx {
|
||||||
struct arena arena;
|
struct arena arena;
|
||||||
|
|
||||||
i64 last_tick_ns; /* When did the last tick simulate in program time */
|
/* Dynamic bitbuff used by encoders */
|
||||||
|
struct bitbuff encoder_bitbuff;
|
||||||
|
|
||||||
|
/* When did the last tick simulate in program time */
|
||||||
|
i64 last_tick_ns;
|
||||||
|
|
||||||
struct sprite_scope *sprite_frame_scope;
|
struct sprite_scope *sprite_frame_scope;
|
||||||
|
|
||||||
@ -166,23 +171,13 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns);
|
|||||||
|
|
||||||
/* TODO: Move this */
|
/* TODO: Move this */
|
||||||
|
|
||||||
#include "byteio.h"
|
|
||||||
#include "host.h"
|
#include "host.h"
|
||||||
|
|
||||||
struct sim_encoder {
|
void sim_cmds_encode(struct bitbuff_writer *bw, struct sim_cmd_list cmds, u64 ack_tick);
|
||||||
struct byte_writer bw;
|
void sim_cmds_decode(struct arena *arena, struct host_event_array host_events, struct sim_cmd_list *cmds_out);
|
||||||
struct sim_client *client;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct sim_decoder {
|
void sim_events_encode(struct bitbuff_writer *bw, struct sim_event_list events);
|
||||||
struct byte_reader br;
|
void sim_events_decode(struct arena *arena, struct host_event_array host_events, struct sim_event_list *events_out);
|
||||||
};
|
|
||||||
|
|
||||||
struct string sim_string_from_cmds(struct arena *arena, struct sim_cmd_list cmds, u64 ack_tick);
|
|
||||||
void sim_cmds_from_host_events(struct arena *arena, struct host_event_array host_events, struct sim_cmd_list *cmds_out);
|
|
||||||
|
|
||||||
struct string sim_string_from_events(struct arena *arena, struct sim_event_list events);
|
|
||||||
void sim_events_from_host_events(struct arena *arena, struct host_event_array host_events, struct sim_event_list *events_out);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -124,19 +124,27 @@ void sim_client_lerp(struct sim_client *c, struct sim_client *c0, struct sim_cli
|
|||||||
* Encode
|
* Encode
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
void sim_client_encode(struct sim_encoder *enc, struct sim_client *c0, struct sim_client *c1)
|
void sim_client_encode(struct bitbuff_writer *bw, struct sim_client *c0, struct sim_client *c1)
|
||||||
{
|
{
|
||||||
struct byte_writer *bw = &enc->bw;
|
|
||||||
struct sim_snapshot *ss = c1->ss;
|
struct sim_snapshot *ss = c1->ss;
|
||||||
|
|
||||||
|
/* TODO: Granular delta encoding */
|
||||||
|
|
||||||
|
u64 pos = 0;
|
||||||
c1->ss = c0->ss;
|
c1->ss = c0->ss;
|
||||||
if (MEMEQ_STRUCT(c0, c1)) {
|
while (pos < sizeof(*c1)) {
|
||||||
bw_write_u8(bw, 0);
|
u64 chunk_size = min_u64(pos + 8, sizeof(*c1)) - pos;
|
||||||
} else {
|
u8 *chunk0 = (u8 *)c0 + pos;
|
||||||
bw_write_u8(bw, 1);
|
u8 *chunk1 = (u8 *)c1 + pos;
|
||||||
struct string bytes = STRING_FROM_STRUCT(c1);
|
if (MEMEQ(chunk0, chunk1, chunk_size)) {
|
||||||
bw_write_var_uint(bw, bytes.len);
|
bw_write_bit(bw, 0);
|
||||||
bw_write_bytes(bw, bytes);
|
} else {
|
||||||
|
bw_write_bit(bw, 1);
|
||||||
|
u64 bits = 0;
|
||||||
|
MEMCPY(&bits, chunk1, chunk_size);
|
||||||
|
bw_write_ubits(bw, bits, 64);
|
||||||
|
}
|
||||||
|
pos += 8;
|
||||||
}
|
}
|
||||||
c1->ss = ss;
|
c1->ss = ss;
|
||||||
}
|
}
|
||||||
@ -145,14 +153,20 @@ void sim_client_encode(struct sim_encoder *enc, struct sim_client *c0, struct si
|
|||||||
* Decode
|
* Decode
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
void sim_client_decode(struct sim_decoder *dec, struct sim_client *c)
|
void sim_client_decode(struct bitbuff_reader *br, struct sim_client *e)
|
||||||
{
|
{
|
||||||
struct byte_reader *br = &dec->br;
|
struct sim_snapshot *ss = e->ss;
|
||||||
struct sim_snapshot *ss = c->ss;
|
|
||||||
|
|
||||||
if (br_read_u8(br)) {
|
u64 pos = 0;
|
||||||
u64 size = br_read_var_uint(br);
|
while (pos < sizeof(*e)) {
|
||||||
*c = *(struct sim_client *)br_seek(br, size);
|
u8 *chunk = (u8 *)e + pos;
|
||||||
c->ss = ss;
|
if (br_read_bit(br)) {
|
||||||
|
u64 chunk_size = min_u64(pos + 8, sizeof(*e)) - pos;
|
||||||
|
u64 bits = br_read_ubits(br, 64);
|
||||||
|
MEMCPY(chunk, &bits, chunk_size);
|
||||||
|
}
|
||||||
|
pos += 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
e->ss = ss;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -45,14 +45,29 @@ INLINE struct sim_client *sim_client_nil(void)
|
|||||||
return *_g_sim_client_nil;
|
return *_g_sim_client_nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ========================== *
|
||||||
|
* Client
|
||||||
|
* ========================== */
|
||||||
|
|
||||||
struct sim_client *sim_client_from_handle(struct sim_snapshot *ss, struct sim_client_handle handle);
|
struct sim_client *sim_client_from_handle(struct sim_snapshot *ss, struct sim_client_handle handle);
|
||||||
struct sim_client *sim_client_from_channel_id(struct sim_snapshot *ss, struct host_channel_id channel_id);
|
struct sim_client *sim_client_from_channel_id(struct sim_snapshot *ss, struct host_channel_id channel_id);
|
||||||
struct sim_client *sim_client_alloc(struct sim_snapshot *ss, struct host_channel_id channel_id);
|
struct sim_client *sim_client_alloc(struct sim_snapshot *ss, struct host_channel_id channel_id);
|
||||||
void sim_client_release(struct sim_client *client);
|
void sim_client_release(struct sim_client *client);
|
||||||
|
|
||||||
|
/* ========================== *
|
||||||
|
* Lerp
|
||||||
|
* ========================== */
|
||||||
|
|
||||||
void sim_client_lerp(struct sim_client *c, struct sim_client *c0, struct sim_client *c1, f64 blend);
|
void sim_client_lerp(struct sim_client *c, struct sim_client *c0, struct sim_client *c1, f64 blend);
|
||||||
|
|
||||||
void sim_client_encode(struct sim_encoder *enc, struct sim_client *c0, struct sim_client *c1);
|
/* ========================== *
|
||||||
void sim_client_decode(struct sim_decoder *dec, struct sim_client *c);
|
* Encode
|
||||||
|
* ========================== */
|
||||||
|
|
||||||
|
struct bitbuff_writer;
|
||||||
|
struct bitbuff_reader;
|
||||||
|
|
||||||
|
void sim_client_encode(struct bitbuff_writer *bw, struct sim_client *c0, struct sim_client *c1);
|
||||||
|
void sim_client_decode(struct bitbuff_reader *br, struct sim_client *c);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -480,36 +480,49 @@ void sim_ent_lerp(struct sim_ent *e, struct sim_ent *e0, struct sim_ent *e1, f64
|
|||||||
* Encode
|
* Encode
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
void sim_ent_encode(struct sim_encoder *enc, struct sim_ent *e0, struct sim_ent *e1)
|
void sim_ent_encode(struct bitbuff_writer *bw, struct sim_ent *e0, struct sim_ent *e1)
|
||||||
{
|
{
|
||||||
struct byte_writer *bw = &enc->bw;
|
|
||||||
struct sim_snapshot *ss = e1->ss;
|
struct sim_snapshot *ss = e1->ss;
|
||||||
|
|
||||||
|
/* TODO: Granular delta encoding */
|
||||||
|
|
||||||
|
u64 pos = 0;
|
||||||
e1->ss = e0->ss;
|
e1->ss = e0->ss;
|
||||||
if (MEMEQ_STRUCT(e0, e1)) {
|
while (pos < sizeof(*e1)) {
|
||||||
bw_write_u8(bw, 0);
|
u64 chunk_size = min_u64(pos + 8, sizeof(*e1)) - pos;
|
||||||
} else {
|
u8 *chunk0 = (u8 *)e0 + pos;
|
||||||
bw_write_u8(bw, 1);
|
u8 *chunk1 = (u8 *)e1 + pos;
|
||||||
struct string bytes = STRING_FROM_STRUCT(e1);
|
if (MEMEQ(chunk0, chunk1, chunk_size)) {
|
||||||
bw_write_var_uint(bw, bytes.len);
|
bw_write_bit(bw, 0);
|
||||||
bw_write_bytes(bw, bytes);
|
} else {
|
||||||
|
bw_write_bit(bw, 1);
|
||||||
|
u64 bits = 0;
|
||||||
|
MEMCPY(&bits, chunk1, chunk_size);
|
||||||
|
bw_write_ubits(bw, bits, 64);
|
||||||
|
}
|
||||||
|
pos += 8;
|
||||||
}
|
}
|
||||||
e1->ss = ss;
|
e1->ss = ss;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Decode
|
* Decode
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
void sim_ent_decode(struct sim_decoder *dec, struct sim_ent *e)
|
void sim_ent_decode(struct bitbuff_reader *br, struct sim_ent *e)
|
||||||
{
|
{
|
||||||
struct byte_reader *br = &dec->br;
|
|
||||||
struct sim_snapshot *ss = e->ss;
|
struct sim_snapshot *ss = e->ss;
|
||||||
|
|
||||||
if (br_read_u8(br)) {
|
u64 pos = 0;
|
||||||
u64 size = br_read_var_uint(br);
|
while (pos < sizeof(*e)) {
|
||||||
*e = *(struct sim_ent *)br_seek(br, size);
|
u8 *chunk = (u8 *)e + pos;
|
||||||
e->ss = ss;
|
if (br_read_bit(br)) {
|
||||||
|
u64 chunk_size = min_u64(pos + 8, sizeof(*e)) - pos;
|
||||||
|
u64 bits = br_read_ubits(br, 64);
|
||||||
|
MEMCPY(chunk, &bits, chunk_size);
|
||||||
|
}
|
||||||
|
pos += 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
e->ss = ss;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,8 +8,8 @@
|
|||||||
#define SIM_ENT_NIL_HANDLE ((struct sim_ent_handle){ .gen = 0, .idx = 0 })
|
#define SIM_ENT_NIL_HANDLE ((struct sim_ent_handle){ .gen = 0, .idx = 0 })
|
||||||
#define SIM_ENT_ROOT_HANDLE ((struct sim_ent_handle){ .gen = 1, .idx = 0 })
|
#define SIM_ENT_ROOT_HANDLE ((struct sim_ent_handle){ .gen = 1, .idx = 0 })
|
||||||
|
|
||||||
struct sim_encoder;
|
struct bitbuff_writer;
|
||||||
struct sim_decoder;
|
struct bitbuff_reader;
|
||||||
|
|
||||||
enum sim_ent_prop {
|
enum sim_ent_prop {
|
||||||
SIM_ENT_PROP_NONE,
|
SIM_ENT_PROP_NONE,
|
||||||
@ -406,7 +406,7 @@ void sim_ent_activate(struct sim_ent *ent, u64 current_tick);
|
|||||||
void sim_ent_lerp(struct sim_ent *e, struct sim_ent *e0, struct sim_ent *e1, f64 blend);
|
void sim_ent_lerp(struct sim_ent *e, struct sim_ent *e0, struct sim_ent *e1, f64 blend);
|
||||||
|
|
||||||
/* Encode / decode */
|
/* Encode / decode */
|
||||||
void sim_ent_encode(struct sim_encoder *enc, struct sim_ent *e0, struct sim_ent *e1);
|
void sim_ent_encode(struct bitbuff_writer *bw, struct sim_ent *e0, struct sim_ent *e1);
|
||||||
void sim_ent_decode(struct sim_decoder *dec, struct sim_ent *e);
|
void sim_ent_decode(struct bitbuff_reader *br, struct sim_ent *e);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -412,36 +412,33 @@ struct sim_snapshot *sim_snapshot_alloc_from_lerp(struct sim_snapshot_store *sto
|
|||||||
* Encode
|
* Encode
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
void sim_snapshot_encode(struct sim_encoder *enc, struct sim_snapshot *ss0, struct sim_snapshot *ss1)
|
void sim_snapshot_encode(struct bitbuff_writer *bw, struct sim_snapshot *ss0, struct sim_snapshot *ss1, struct sim_client *client)
|
||||||
{
|
{
|
||||||
__prof;
|
__prof;
|
||||||
struct byte_writer *bw = &enc->bw;
|
bw_write_uv(bw, ss1->continuity_gen);
|
||||||
struct sim_client *client = enc->client;
|
|
||||||
|
|
||||||
bw_write_var_uint(bw, ss1->continuity_gen);
|
bw_write_iv(bw, ss1->real_dt_ns);
|
||||||
|
bw_write_iv(bw, ss1->real_time_ns);
|
||||||
bw_write_var_sint(bw, ss1->real_dt_ns);
|
|
||||||
bw_write_var_sint(bw, ss1->real_time_ns);
|
|
||||||
|
|
||||||
bw_write_f64(bw, ss1->world_timescale);
|
bw_write_f64(bw, ss1->world_timescale);
|
||||||
bw_write_var_sint(bw, ss1->world_dt_ns);
|
bw_write_iv(bw, ss1->world_dt_ns);
|
||||||
bw_write_var_sint(bw, ss1->world_time_ns);
|
bw_write_iv(bw, ss1->world_time_ns);
|
||||||
|
|
||||||
bw_write_var_uint(bw, client->handle.gen);
|
bw_write_uv(bw, client->handle.gen);
|
||||||
bw_write_var_uint(bw, client->handle.idx);
|
bw_write_uv(bw, client->handle.idx);
|
||||||
|
|
||||||
/* Clients */
|
/* Clients */
|
||||||
if (ss1->num_clients_allocated == ss0->num_clients_allocated) {
|
if (ss1->num_clients_allocated == ss0->num_clients_allocated) {
|
||||||
bw_write_u8(bw, 0);
|
bw_write_bit(bw, 0);
|
||||||
} else {
|
} else {
|
||||||
bw_write_u8(bw, 1);
|
bw_write_bit(bw, 1);
|
||||||
bw_write_var_uint(bw, ss1->num_clients_allocated);
|
bw_write_uv(bw, ss1->num_clients_allocated);
|
||||||
}
|
}
|
||||||
if (ss1->num_clients_reserved == ss0->num_clients_reserved) {
|
if (ss1->num_clients_reserved == ss0->num_clients_reserved) {
|
||||||
bw_write_u8(bw, 0);
|
bw_write_bit(bw, 0);
|
||||||
} else {
|
} else {
|
||||||
bw_write_u8(bw, 1);
|
bw_write_bit(bw, 1);
|
||||||
bw_write_var_uint(bw, ss1->num_clients_reserved);
|
bw_write_uv(bw, ss1->num_clients_reserved);
|
||||||
}
|
}
|
||||||
for (u64 i = 0; i < ss1->num_clients_reserved; ++i) {
|
for (u64 i = 0; i < ss1->num_clients_reserved; ++i) {
|
||||||
struct sim_client *c0 = sim_client_nil();
|
struct sim_client *c0 = sim_client_nil();
|
||||||
@ -449,21 +446,21 @@ void sim_snapshot_encode(struct sim_encoder *enc, struct sim_snapshot *ss0, stru
|
|||||||
c0 = &ss0->clients[i];
|
c0 = &ss0->clients[i];
|
||||||
}
|
}
|
||||||
struct sim_client *c1 = &ss1->clients[i];
|
struct sim_client *c1 = &ss1->clients[i];
|
||||||
sim_client_encode(enc, c0, c1);
|
sim_client_encode(bw, c0, c1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ents */
|
/* Ents */
|
||||||
if (ss1->num_ents_allocated == ss0->num_ents_allocated) {
|
if (ss1->num_ents_allocated == ss0->num_ents_allocated) {
|
||||||
bw_write_u8(bw, 0);
|
bw_write_bit(bw, 0);
|
||||||
} else {
|
} else {
|
||||||
bw_write_u8(bw, 1);
|
bw_write_bit(bw, 1);
|
||||||
bw_write_var_uint(bw, ss1->num_ents_allocated);
|
bw_write_uv(bw, ss1->num_ents_allocated);
|
||||||
}
|
}
|
||||||
if (ss1->num_ents_reserved == ss0->num_ents_reserved) {
|
if (ss1->num_ents_reserved == ss0->num_ents_reserved) {
|
||||||
bw_write_u8(bw, 0);
|
bw_write_bit(bw, 0);
|
||||||
} else {
|
} else {
|
||||||
bw_write_u8(bw, 1);
|
bw_write_bit(bw, 1);
|
||||||
bw_write_var_uint(bw, ss1->num_ents_reserved);
|
bw_write_uv(bw, ss1->num_ents_reserved);
|
||||||
}
|
}
|
||||||
for (u64 i = 0; i < ss1->num_ents_reserved; ++i) {
|
for (u64 i = 0; i < ss1->num_ents_reserved; ++i) {
|
||||||
struct sim_ent *e0 = sim_ent_nil();
|
struct sim_ent *e0 = sim_ent_nil();
|
||||||
@ -471,7 +468,7 @@ void sim_snapshot_encode(struct sim_encoder *enc, struct sim_snapshot *ss0, stru
|
|||||||
e0 = &ss0->ents[i];
|
e0 = &ss0->ents[i];
|
||||||
}
|
}
|
||||||
struct sim_ent *e1 = &ss1->ents[i];
|
struct sim_ent *e1 = &ss1->ents[i];
|
||||||
sim_ent_encode(enc, e0, e1);
|
sim_ent_encode(bw, e0, e1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -479,30 +476,29 @@ void sim_snapshot_encode(struct sim_encoder *enc, struct sim_snapshot *ss0, stru
|
|||||||
* Decode
|
* Decode
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
void sim_snapshot_decode(struct sim_decoder *dec, struct sim_snapshot *ss)
|
void sim_snapshot_decode(struct bitbuff_reader *br, struct sim_snapshot *ss)
|
||||||
{
|
{
|
||||||
__prof;
|
__prof;
|
||||||
struct byte_reader *br = &dec->br;
|
|
||||||
|
|
||||||
ss->continuity_gen = br_read_var_uint(br);
|
ss->continuity_gen = br_read_uv(br);
|
||||||
|
|
||||||
ss->real_dt_ns = br_read_var_sint(br);
|
ss->real_dt_ns = br_read_iv(br);
|
||||||
ss->real_time_ns = br_read_var_sint(br);
|
ss->real_time_ns = br_read_iv(br);
|
||||||
|
|
||||||
ss->world_timescale = br_read_f64(br);
|
ss->world_timescale = br_read_f64(br);
|
||||||
ss->world_dt_ns = br_read_var_sint(br);
|
ss->world_dt_ns = br_read_iv(br);
|
||||||
ss->world_time_ns = br_read_var_sint(br);
|
ss->world_time_ns = br_read_iv(br);
|
||||||
|
|
||||||
ss->local_client.gen = br_read_var_uint(br);
|
ss->local_client.gen = br_read_uv(br);
|
||||||
ss->local_client.idx = br_read_var_uint(br);
|
ss->local_client.idx = br_read_uv(br);
|
||||||
|
|
||||||
/* Clients */
|
/* Clients */
|
||||||
if (br_read_u8(br)) {
|
if (br_read_bit(br)) {
|
||||||
ss->num_clients_allocated = br_read_var_uint(br);
|
ss->num_clients_allocated = br_read_uv(br);
|
||||||
}
|
}
|
||||||
if (br_read_u8(br)) {
|
if (br_read_bit(br)) {
|
||||||
u64 old_num_clients_reserved = ss->num_clients_reserved;
|
u64 old_num_clients_reserved = ss->num_clients_reserved;
|
||||||
ss->num_clients_reserved = br_read_var_uint(br);
|
ss->num_clients_reserved = br_read_uv(br);
|
||||||
i64 reserve_diff = (i64)ss->num_clients_reserved - (i64)old_num_clients_reserved;
|
i64 reserve_diff = (i64)ss->num_clients_reserved - (i64)old_num_clients_reserved;
|
||||||
if (reserve_diff > 0) {
|
if (reserve_diff > 0) {
|
||||||
arena_push_array(&ss->clients_arena, struct sim_client, reserve_diff);
|
arena_push_array(&ss->clients_arena, struct sim_client, reserve_diff);
|
||||||
@ -515,16 +511,16 @@ void sim_snapshot_decode(struct sim_decoder *dec, struct sim_snapshot *ss)
|
|||||||
}
|
}
|
||||||
for (u64 i = 0; i < ss->num_clients_reserved; ++i) {
|
for (u64 i = 0; i < ss->num_clients_reserved; ++i) {
|
||||||
struct sim_client *c = &ss->clients[i];
|
struct sim_client *c = &ss->clients[i];
|
||||||
sim_client_decode(dec, c);
|
sim_client_decode(br, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ents */
|
/* Ents */
|
||||||
if (br_read_u8(br)) {
|
if (br_read_bit(br)) {
|
||||||
ss->num_ents_allocated = br_read_var_uint(br);
|
ss->num_ents_allocated = br_read_uv(br);
|
||||||
}
|
}
|
||||||
if (br_read_u8(br)) {
|
if (br_read_bit(br)) {
|
||||||
u64 old_num_ents_reserved = ss->num_ents_reserved;
|
u64 old_num_ents_reserved = ss->num_ents_reserved;
|
||||||
ss->num_ents_reserved = br_read_var_uint(br);
|
ss->num_ents_reserved = br_read_uv(br);
|
||||||
i64 reserve_diff = (i64)ss->num_ents_reserved - (i64)old_num_ents_reserved;
|
i64 reserve_diff = (i64)ss->num_ents_reserved - (i64)old_num_ents_reserved;
|
||||||
if (reserve_diff > 0) {
|
if (reserve_diff > 0) {
|
||||||
arena_push_array(&ss->ents_arena, struct sim_ent, reserve_diff);
|
arena_push_array(&ss->ents_arena, struct sim_ent, reserve_diff);
|
||||||
@ -537,6 +533,6 @@ void sim_snapshot_decode(struct sim_decoder *dec, struct sim_snapshot *ss)
|
|||||||
}
|
}
|
||||||
for (u64 i = 0; i < ss->num_ents_reserved; ++i) {
|
for (u64 i = 0; i < ss->num_ents_reserved; ++i) {
|
||||||
struct sim_ent *e = &ss->ents[i];
|
struct sim_ent *e = &ss->ents[i];
|
||||||
sim_ent_decode(dec, e);
|
sim_ent_decode(br, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,9 +4,6 @@
|
|||||||
#include "sim_ent.h"
|
#include "sim_ent.h"
|
||||||
#include "sim_client.h"
|
#include "sim_client.h"
|
||||||
|
|
||||||
struct sim_encoder;
|
|
||||||
struct sim_decoder;
|
|
||||||
|
|
||||||
struct sim_snapshot_store {
|
struct sim_snapshot_store {
|
||||||
b32 valid;
|
b32 valid;
|
||||||
struct arena arena;
|
struct arena arena;
|
||||||
@ -106,6 +103,9 @@ INLINE struct sim_snapshot_store *sim_snapshot_store_nil(void)
|
|||||||
* Snapshot
|
* Snapshot
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
|
struct bitbuff_writer;
|
||||||
|
struct bitbuff_reader;
|
||||||
|
|
||||||
/* Alloc */
|
/* Alloc */
|
||||||
struct sim_snapshot *sim_snapshot_alloc(struct sim_snapshot_store *store, struct sim_snapshot *src, u64 tick);
|
struct sim_snapshot *sim_snapshot_alloc(struct sim_snapshot_store *store, struct sim_snapshot *src, u64 tick);
|
||||||
void sim_snapshot_release(struct sim_snapshot *sim_snapshot);
|
void sim_snapshot_release(struct sim_snapshot *sim_snapshot);
|
||||||
@ -117,8 +117,8 @@ struct sim_snapshot *sim_snapshot_from_tick(struct sim_snapshot_store *store, u6
|
|||||||
struct sim_snapshot *sim_snapshot_alloc_from_lerp(struct sim_snapshot_store *store, struct sim_snapshot *ss0, struct sim_snapshot *ss1, f64 blend);
|
struct sim_snapshot *sim_snapshot_alloc_from_lerp(struct sim_snapshot_store *store, struct sim_snapshot *ss0, struct sim_snapshot *ss1, f64 blend);
|
||||||
|
|
||||||
/* Encode / decode */
|
/* Encode / decode */
|
||||||
void sim_snapshot_encode(struct sim_encoder *enc, struct sim_snapshot *ss0, struct sim_snapshot *ss1);
|
void sim_snapshot_encode(struct bitbuff_writer *bw, struct sim_snapshot *ss0, struct sim_snapshot *ss1, struct sim_client *client);
|
||||||
void sim_snapshot_decode(struct sim_decoder *dec, struct sim_snapshot *ss);
|
void sim_snapshot_decode(struct bitbuff_reader *br, struct sim_snapshot *ss);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -2192,7 +2192,7 @@ int CALLBACK wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance,
|
|||||||
abort:
|
abort:
|
||||||
|
|
||||||
if (error_msg) {
|
if (error_msg) {
|
||||||
MessageBoxExW(NULL, error_msg, L"Fatal error", MB_ICONSTOP | MB_SETFOREGROUND, 0);
|
MessageBoxExW(NULL, error_msg, L"Fatal error", MB_ICONSTOP | MB_SETFOREGROUND | MB_TOPMOST, 0);
|
||||||
ASSERT(false);
|
ASSERT(false);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
13
src/tar.c
13
src/tar.c
@ -1,5 +1,5 @@
|
|||||||
#include "tar.h"
|
#include "tar.h"
|
||||||
#include "byteio.h"
|
#include "bitbuff.h"
|
||||||
#include "string.h"
|
#include "string.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
@ -70,13 +70,14 @@ struct tar_archive tar_parse(struct arena *arena, struct string data, struct str
|
|||||||
__prof;
|
__prof;
|
||||||
|
|
||||||
struct tar_archive archive = ZI;
|
struct tar_archive archive = ZI;
|
||||||
struct byte_reader br = br_from_buffer(data);
|
struct bitbuff bb = bitbuff_from_string(data);
|
||||||
|
struct bitbuff_reader br = br_from_bitbuff_no_debug(&bb);
|
||||||
|
|
||||||
u64 num_files = 0;
|
u64 num_files = 0;
|
||||||
while (br_bytes_left(&br) > 1024) {
|
while (br_num_bytes_left(&br) > 1024) {
|
||||||
|
|
||||||
struct tar_header header = ZI;
|
struct tar_header header = ZI;
|
||||||
br_read_to_struct(&br, &header);
|
br_read_bytes(&br, STRING_FROM_STRUCT(&header));
|
||||||
|
|
||||||
if (!string_eq(STRING_FROM_ARRAY(header.ustar_indicator), LIT("ustar\0"))) {
|
if (!string_eq(STRING_FROM_ARRAY(header.ustar_indicator), LIT("ustar\0"))) {
|
||||||
/* Invalid header */
|
/* Invalid header */
|
||||||
@ -93,7 +94,7 @@ struct tar_archive tar_parse(struct arena *arena, struct string data, struct str
|
|||||||
struct string file_size_oct_str = { .len = 11, .text = header.file_size };
|
struct string file_size_oct_str = { .len = 11, .text = header.file_size };
|
||||||
|
|
||||||
u64 file_size = str_oct_to_u64(file_size_oct_str);
|
u64 file_size = str_oct_to_u64(file_size_oct_str);
|
||||||
u8 *file_data_ptr = br_seek(&br, file_size);
|
u8 *file_data_ptr = br_read_bytes_raw(&br, file_size);
|
||||||
if (!file_data_ptr) {
|
if (!file_data_ptr) {
|
||||||
file_size = 0;
|
file_size = 0;
|
||||||
}
|
}
|
||||||
@ -101,7 +102,7 @@ struct tar_archive tar_parse(struct arena *arena, struct string data, struct str
|
|||||||
|
|
||||||
/* Skip sector padding */
|
/* Skip sector padding */
|
||||||
u64 remaining = (512 - (file_size % 512)) % 512;
|
u64 remaining = (512 - (file_size % 512)) % 512;
|
||||||
br_seek(&br, remaining);
|
br_seek_bytes(&br, remaining);
|
||||||
|
|
||||||
b32 is_dir = header.file_type == TAR_TYPE_DIRECTORY;
|
b32 is_dir = header.file_type == TAR_TYPE_DIRECTORY;
|
||||||
if (!is_dir && header.file_type != TAR_TYPE_FILE) {
|
if (!is_dir && header.file_type != TAR_TYPE_FILE) {
|
||||||
|
|||||||
48
src/user.c
48
src/user.c
@ -21,7 +21,7 @@
|
|||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "sock.h"
|
#include "sock.h"
|
||||||
#include "host.h"
|
#include "host.h"
|
||||||
#include "byteio.h"
|
#include "bitbuff.h"
|
||||||
|
|
||||||
struct bind_state {
|
struct bind_state {
|
||||||
b32 is_held; /* Is this bind held down this frame */
|
b32 is_held; /* Is this bind held down this frame */
|
||||||
@ -53,6 +53,9 @@ GLOBAL struct {
|
|||||||
struct sim_snapshot_store *world_snapshot_store; /* Contains single world snapshot from result of blending sim snapshots */
|
struct sim_snapshot_store *world_snapshot_store; /* Contains single world snapshot from result of blending sim snapshots */
|
||||||
struct sim_snapshot *world;
|
struct sim_snapshot *world;
|
||||||
|
|
||||||
|
/* Dynamic bitbuff used by encoders */
|
||||||
|
struct bitbuff encoder_bitbuff;
|
||||||
|
|
||||||
/* Usage stats */
|
/* Usage stats */
|
||||||
i64 last_second_reset_ns;
|
i64 last_second_reset_ns;
|
||||||
struct second_stat client_bytes_read;
|
struct second_stat client_bytes_read;
|
||||||
@ -188,6 +191,8 @@ struct user_startup_receipt user_startup(struct work_startup_receipt *work_sr,
|
|||||||
//struct sock_address bind_addr = sock_address_from_any_local_interface_with_dynamic_port();
|
//struct sock_address bind_addr = sock_address_from_any_local_interface_with_dynamic_port();
|
||||||
G.host = host_alloc(0);
|
G.host = host_alloc(0);
|
||||||
|
|
||||||
|
G.encoder_bitbuff = bitbuff_alloc(GIGABYTE(64));
|
||||||
|
|
||||||
G.world_to_ui_xf = XFORM_IDENT;
|
G.world_to_ui_xf = XFORM_IDENT;
|
||||||
G.world_cmd_buffer = renderer_cmd_buffer_alloc();
|
G.world_cmd_buffer = renderer_cmd_buffer_alloc();
|
||||||
G.ui_cmd_buffer = renderer_cmd_buffer_alloc();
|
G.ui_cmd_buffer = renderer_cmd_buffer_alloc();
|
||||||
@ -405,7 +410,7 @@ INTERNAL void user_update(void)
|
|||||||
{
|
{
|
||||||
host_update(G.host);
|
host_update(G.host);
|
||||||
struct host_event_array host_events = host_pop_events(scratch.arena, G.host);
|
struct host_event_array host_events = host_pop_events(scratch.arena, G.host);
|
||||||
sim_events_from_host_events(scratch.arena, host_events, &sim_events);
|
sim_events_decode(scratch.arena, host_events, &sim_events);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
@ -438,24 +443,6 @@ INTERNAL void user_update(void)
|
|||||||
|
|
||||||
case SIM_EVENT_KIND_SNAPSHOT:
|
case SIM_EVENT_KIND_SNAPSHOT:
|
||||||
{
|
{
|
||||||
#if 0
|
|
||||||
if (event_tick > G.world->tick) {
|
|
||||||
u64 ss0_tick = event->snapshot_tick_start;
|
|
||||||
u64 ss1_tick = event->snapshot_tick_end;
|
|
||||||
struct sim_snapshot *ss0 = sim_snapshot_from_tick(G.sim_snapshot_store, ss0_tick);
|
|
||||||
struct sim_snapshot *ss1 = sim_snapshot_from_tick(G.sim_snapshot_store, ss1_tick);
|
|
||||||
if (ss0->tick == ss0_tick) {
|
|
||||||
if (!ss1->valid) {
|
|
||||||
ss1 = sim_snapshot_alloc(G.sim_snapshot_store, ss0, ss1_tick);
|
|
||||||
sim_snapshot_decode(event->snapshot_encoded, ss1);
|
|
||||||
ss1->received_at_ns = G.real_time_ns;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* User should always have src tick present */
|
|
||||||
ASSERT(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
if (event_tick > G.world->tick) {
|
if (event_tick > G.world->tick) {
|
||||||
u64 ss0_tick = event->snapshot_tick_start;
|
u64 ss0_tick = event->snapshot_tick_start;
|
||||||
u64 ss1_tick = event->snapshot_tick_end;
|
u64 ss1_tick = event->snapshot_tick_end;
|
||||||
@ -465,16 +452,16 @@ INTERNAL void user_update(void)
|
|||||||
if (!ss1->valid) {
|
if (!ss1->valid) {
|
||||||
ss1 = sim_snapshot_alloc(G.sim_snapshot_store, ss0, ss1_tick);
|
ss1 = sim_snapshot_alloc(G.sim_snapshot_store, ss0, ss1_tick);
|
||||||
ss1->received_at_ns = G.real_time_ns;
|
ss1->received_at_ns = G.real_time_ns;
|
||||||
struct sim_decoder decoder = ZI;
|
|
||||||
decoder.br = br_from_buffer(event->snapshot_encoded);
|
struct bitbuff bb = bitbuff_from_string(event->snapshot_encoded);
|
||||||
sim_snapshot_decode(&decoder, ss1);
|
struct bitbuff_reader br = br_from_bitbuff(&bb);
|
||||||
|
sim_snapshot_decode(&br, ss1);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* User should always have src tick present */
|
/* User should always have src tick present */
|
||||||
ASSERT(false);
|
ASSERT(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
default: break;
|
default: break;
|
||||||
@ -1526,6 +1513,11 @@ INTERNAL void user_update(void)
|
|||||||
if (font) {
|
if (font) {
|
||||||
struct temp_arena temp = arena_temp_begin(scratch.arena);
|
struct temp_arena temp = arena_temp_begin(scratch.arena);
|
||||||
|
|
||||||
|
#if BITBUFF_DEBUG
|
||||||
|
draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("(bitbuff debug enabled)")));
|
||||||
|
pos.y += spacing;
|
||||||
|
#endif
|
||||||
|
|
||||||
draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("Read from local sim: %F mbit/s"), FMT_FLOAT_P((f64)G.client_bytes_read.last_second * 8 / 1000 / 1000, 3)));
|
draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("Read from local sim: %F mbit/s"), FMT_FLOAT_P((f64)G.client_bytes_read.last_second * 8 / 1000 / 1000, 3)));
|
||||||
pos.y += spacing;
|
pos.y += spacing;
|
||||||
|
|
||||||
@ -1622,12 +1614,10 @@ INTERNAL void user_update(void)
|
|||||||
|
|
||||||
/* Publish sim cmds */
|
/* Publish sim cmds */
|
||||||
{
|
{
|
||||||
struct temp_arena temp = arena_temp_begin(scratch.arena);
|
struct bitbuff_writer bw = bw_from_bitbuff(&G.encoder_bitbuff);
|
||||||
|
sim_cmds_encode(&bw, cmd_list, G.local_sim_last_known_tick);
|
||||||
struct string cmds_str = sim_string_from_cmds(temp.arena, cmd_list, G.local_sim_last_known_tick);
|
struct string cmds_str = bw_get_written(scratch.arena, &bw);
|
||||||
host_queue_write(G.host, HOST_CHANNEL_ID_ALL, cmds_str, 0);
|
host_queue_write(G.host, HOST_CHANNEL_ID_ALL, cmds_str, 0);
|
||||||
|
|
||||||
arena_temp_end(temp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
host_update(G.host);
|
host_update(G.host);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user