diff --git a/src/config.h b/src/config.h index 19d12830..38c4da58 100644 --- a/src/config.h +++ b/src/config.h @@ -40,7 +40,7 @@ #define SIM_TILES_PER_UNIT_SQRT (4) #define SIM_TILES_PER_CHUNK_SQRT (16) -#define SIM_TICKS_PER_SECOND 50 +#define SIM_TICKS_PER_SECOND 100 //#define SIM_TIMESCALE 1 /* Like USER_INTERP_RATIO, but applies to snapshots received by the local sim from the * master sim (how far back in time should the client render the server's state) */ diff --git a/src/proto/pp_sim/pp_sim_core.c b/src/proto/pp_sim/pp_sim_core.c index acb7416d..179f5f36 100644 --- a/src/proto/pp_sim/pp_sim_core.c +++ b/src/proto/pp_sim/pp_sim_core.c @@ -307,6 +307,7 @@ JobDef(S_SimWorker, _, __) S_World *world = PushStruct(perm, S_World); world->ents = ArenaFirst(ents_arena, S_Ent); i64 first_free_ent_num = 0; + i64 sim_time_ns = 0; ////////////////////////////// //- Sim loop @@ -322,6 +323,8 @@ JobDef(S_SimWorker, _, __) //- Begin sim frame i64 frame_begin_ns = TimeNs(); + i64 sim_dt_ns = NsFromSeconds(1) / SIM_TICKS_PER_SECOND; + f64 sim_dt = SecondsFromNs(sim_dt_ns); ////////////////////////////// //- Create root ent @@ -501,17 +504,48 @@ JobDef(S_SimWorker, _, __) { xf = XformWithWorldRotation(xf, AngleFromVec2(ent->look)); } - xf.og = AddVec2(xf.og, ent->move); + xf.og = AddVec2(xf.og, MulVec2(ent->move, ent->move_speed)); ent->local_xf = xf; } ////////////////////////////// - //- Compute final world transforms + //- Compute pre-solve world transforms for (S_Ent *ent = S_FirstEnt(frame_arena, &iter, &lookup); ent->active; ent = S_NextEnt(frame_arena, &iter)) { - S_Ent *parent = S_EntFromKey(&lookup, ent->parent); - ent->world_xf = MulXform(parent->world_xf, ent->local_xf); + ent->old_world_xf = ent->world_xf; + ent->world_xf = MulXform(S_EntFromKey(&lookup, ent->parent)->world_xf, ent->local_xf); + } + + ////////////////////////////// + //- Solve followers + + for (S_Ent *ent = S_FirstEnt(frame_arena, &iter, &lookup); ent->active; ent = S_NextEnt(frame_arena, &iter)) + { + S_Ent *follow = S_EntFromKey(&lookup, ent->follow); + if (follow->active) + { + f32 follow_speed = 20 * sim_dt; + Vec2 look_ratio = ZI; + look_ratio.x = 0.25; + look_ratio.y = (16.0 / 9.0) * look_ratio.x; + + Vec2 target = MulXformV2(follow->world_xf, follow->local_shape.centroid); + target = AddVec2(target, MulVec2Vec2(follow->look, look_ratio)); + + Xform xf = ent->local_xf; + // xf.og = AddVec2(xf.og, SubVec2(follow->world_xf.og, follow->old_world_xf.og)); + xf.og = LerpVec2(xf.og, target, follow_speed); + ent->local_xf = xf; + } + } + + ////////////////////////////// + //- Compute post-solve world transforms + + for (S_Ent *ent = S_FirstEnt(frame_arena, &iter, &lookup); ent->active; ent = S_NextEnt(frame_arena, &iter)) + { + ent->world_xf = MulXform(S_EntFromKey(&lookup, ent->parent)->world_xf, ent->local_xf); } ////////////////////////////// @@ -550,6 +584,7 @@ JobDef(S_SimWorker, _, __) i64 frame_end_ns = TimeNs(); + sim_time_ns += sim_dt_ns; ++world->tick; ////////////////////////////// diff --git a/src/proto/pp_sim/pp_sim_core.h b/src/proto/pp_sim/pp_sim_core.h index d5abb4a1..0e398829 100644 --- a/src/proto/pp_sim/pp_sim_core.h +++ b/src/proto/pp_sim/pp_sim_core.h @@ -71,6 +71,11 @@ Struct(S_Ent) Vec2 move; Vec2 look; + ////////////////////////////// + //- Pre-solve data + + Xform old_world_xf; + ////////////////////////////// //- Post-solve data diff --git a/src/proto/pp_vis/pp_vis_core.c b/src/proto/pp_vis/pp_vis_core.c index 7fc23399..9df4627b 100644 --- a/src/proto/pp_vis/pp_vis_core.c +++ b/src/proto/pp_vis/pp_vis_core.c @@ -145,6 +145,7 @@ JobDef(V_VisWorker, _, __) ent->tint = Color_Red; ent->key = player_key; ent->camera = camera_key; + ent->move_speed = 10; { ent->local_shape = S_ShapeFromDesc( .mass = 10, @@ -179,7 +180,8 @@ JobDef(V_VisWorker, _, __) /* Test camera */ case 2: { - // ent->key = camera_key; + ent->key = camera_key; + ent->follow = player_key; } break; default: @@ -199,7 +201,6 @@ JobDef(V_VisWorker, _, __) ui_frame_flags |= UI_FrameFlag_Vsync * !!VSYNC; UI_Frame ui_frame = UI_BeginFrame(ui_frame_flags, swapchain_color); WND_Frame window_frame = ui_frame.window_frame; - Vec2 ui_cursor = ui_frame.cursor_pos; /* Restore window */ { @@ -250,7 +251,47 @@ JobDef(V_VisWorker, _, __) } ////////////////////////////// - //- Process controller events vis cmds + //- Initialize camera + + Vec2 camera_pos = ZI; + f32 camera_zoom = 1; + { + S_Ent *player = S_EntFromKey(&lookup, player_key); + S_Ent *camera = S_EntFromKey(&lookup, player->camera); + camera_pos = MulXformV2(camera->world_xf, camera->local_shape.centroid); + } + + ////////////////////////////// + //- Initialize world <-> draw <-> ui transforms + + /* World <-> draw */ + Xform world_to_draw_xf = XformIdentity; + Xform draw_to_world_xf = XformIdentity; + { + world_to_draw_xf.og = AddVec2(NegVec2(camera_pos), MulVec2(Vec2FromFields(draw_size), 0.5)); + draw_to_world_xf = InvertXform(world_to_draw_xf); + } + /* Draw <-> ui */ + Xform draw_to_ui_xf = XformIdentity; + Xform ui_to_draw_xf = XformIdentity; + { + ui_to_draw_xf = InvertXform(draw_to_ui_xf); + } + /* World <-> ui */ + Xform world_to_ui_xf = XformIdentity; + Xform ui_to_world_xf = XformIdentity; + { + world_to_ui_xf = MulXform(world_to_draw_xf, draw_to_ui_xf); + ui_to_world_xf = InvertXform(world_to_ui_xf); + } + + /* Cursors */ + Vec2 ui_cursor = ui_frame.cursor_pos; + Vec2 draw_cursor = MulXformV2(ui_to_draw_xf, ui_cursor); + Vec2 world_cursor = MulXformV2(ui_to_world_xf, ui_cursor); + + ////////////////////////////// + //- Process controller events into vis cmds u64 cmds_count = 0; V_CmdNode *first_cmd_node = 0; @@ -425,7 +466,7 @@ JobDef(V_VisWorker, _, __) { S_Ent *player = S_EntFromKey(&lookup, player_key); Vec2 center = MulXformV2(player->world_xf, player->local_shape.centroid); - look = SubVec2(UI_CursorPos(), center); + look = SubVec2(world_cursor, center); } cmd->target = player_key; cmd->move = move; @@ -462,14 +503,16 @@ JobDef(V_VisWorker, _, __) for (S_Ent *ent = S_FirstEnt(frame_arena, &iter, &lookup); ent->active; ent = S_NextEnt(frame_arena, &iter)) { + Xform ent_to_world_xf = ent->world_xf; + Xform ent_to_draw_xf = MulXform(world_to_draw_xf, ent_to_world_xf); + /* Draw shape */ b32 is_visible = ent->tint.w != 0; if (is_visible) { - Xform xf = ent->world_xf; Vec4 color = ent->tint; i32 detail = 32; - S_Shape shape = S_MulXformShape(ent->world_xf, ent->local_shape); + S_Shape shape = S_MulXformShape(ent_to_draw_xf, ent->local_shape); V_DrawShape(dverts_arena, dvert_idx_arena, shape, LinearFromSrgb(color), detail, V_DrawFlag_Line); } } diff --git a/src/proto/pp_vis/pp_vis_draw.c b/src/proto/pp_vis/pp_vis_draw.c index 414c1f31..ae7e9321 100644 --- a/src/proto/pp_vis/pp_vis_draw.c +++ b/src/proto/pp_vis/pp_vis_draw.c @@ -10,7 +10,7 @@ void V_DrawPoly(Arena *verts_arena, Arena *idx_arena, Vec2Array points, Vec4 col { TempArena scratch = BeginScratchNoConflict(); { - f32 half_thickness = 0.5; + f32 half_thickness = 1; i32 lines_count = verts_count == 2 ? 1 : verts_count; i32 line_verts_count = lines_count * 4; i32 idx_count = lines_count * 6;