diff --git a/src/pp/pp.c b/src/pp/pp.c index bdb6997b..5c61148c 100644 --- a/src/pp/pp.c +++ b/src/pp/pp.c @@ -2460,34 +2460,60 @@ void P_StepFrame(P_Frame *frame) { P_Shape firer_world_shape = P_WorldShapeFromEnt(firer); - Vec2 base_pos = P_EdgePointFromShape(firer_world_shape, firer->control.look); - Vec2 base_dir = firer->control.look; + // Vec2 fire_pos = P_EdgePointFromShape(firer_world_shape, firer->control.look); + // Vec2 fire_dir = firer->control.look; - // Xform base_xf = Zi; - // { - // P_Anim anim = P_AnimFromEnt(firer, frame->time_ns); + Vec2 fire_pos = Zi; + Vec2 fire_dir = Zi; + { + Vec2 look = firer->control.look; + P_Anim anim = P_AnimFromEnt(firer, frame->time_ns); + SPR_Sprite body = SPR_SpriteFromSheet(anim.sheet, anim.span, anim.frame_seq); + SPR_Sprite wep = SPR_SpriteFromSheet(anim.wep_sheet, anim.span, anim.frame_seq); - // SPR_LayerKey origin_layer = SPR_LayerKeyFromName(Lit(".origin")); - // SPR_LayerKey ap_layer = SPR_LayerKeyFromName(Lit(".ap")); + //- Compute sprite transforms + Affine ent_to_world_af = MulAffineXform(AffineIdentity, firer->xf); + Affine body_pix_to_world_af = AffineIdentity; + Affine wep_pix_to_world_af = AffineIdentity; + { + Vec2 pix_scale = VEC2(1.0 / P_CellsPerMeter, 1.0 / P_CellsPerMeter); - // Xform firer_to_body_origin_xf = SPR_XformFromSheet(anim.sheet, origin_layer, anim.span, anim.frame_seq); - // Xform firer_to_body_ap_xf = SPR_XformFromSheet(anim.sheet, ap_layer, anim.span, anim.frame_seq); + //- Compute body transform + Affine body_pix_to_ent_af = AffineIdentity; + { + body_pix_to_ent_af = ScaleAffine(body_pix_to_ent_af, pix_scale); - // Xform body_ap_to_wep_origin_xf = SPR_XformFromSheet(anim.wep_sheet, origin_layer, anim.span, anim.frame_seq); - // Xform body_ap_to_wep_ap_xf = SPR_XformFromSheet(anim.wep_sheet, ap_layer, anim.span, anim.frame_seq); + SPR_Ray anchor_ray = body.rays[SPR_RayKind_Anchor]; + body_pix_to_ent_af = RotateAffine(body_pix_to_ent_af, InvertRot(anchor_ray.dir)); + body_pix_to_ent_af = TranslateAffine(body_pix_to_ent_af, NegVec2(anchor_ray.pos)); + } - // // Xform fo2w = SubVec2(firer_ - // Xform firer_to_world_xf = firer->xf; - // Xform bullet_xf = MulXform(firer_to_world_xf, firer_to_body_ap_xf); - // base_pos = bullet_xf.t; + //- Compute weapon transform + Affine wep_pix_to_ent_af = AffineIdentity; + { + wep_pix_to_ent_af = ScaleAffine(wep_pix_to_ent_af, pix_scale); - // // FIXME: Real dir - // // base_dir = firer->control.look; - // base_dir = bullet_xf.r; - // } + SPR_Ray body_anchor_ray = body.rays[SPR_RayKind_Anchor]; + SPR_Ray body_ap_ray = body.rays[SPR_RayKind_Ap]; + wep_pix_to_ent_af = RotateAffine(wep_pix_to_ent_af, InvertRot(body_anchor_ray.dir)); + wep_pix_to_ent_af = TranslateAffine(wep_pix_to_ent_af, SubVec2(body_ap_ray.pos, body_anchor_ray.pos)); + wep_pix_to_ent_af = RotateAffine(wep_pix_to_ent_af, InvertRot(body_ap_ray.dir)); + SPR_Ray anchor_ray = wep.rays[SPR_RayKind_Anchor]; + wep_pix_to_ent_af = RotateAffine(wep_pix_to_ent_af, anchor_ray.dir); + wep_pix_to_ent_af = TranslateAffine(wep_pix_to_ent_af, NegVec2(anchor_ray.pos)); + } + body_pix_to_world_af = MulAffine(ent_to_world_af, body_pix_to_ent_af); + wep_pix_to_world_af = MulAffine(ent_to_world_af, wep_pix_to_ent_af); + } + SPR_Ray fire_ray = wep.rays[SPR_RayKind_Ap]; + fire_pos = MulAffineVec2(wep_pix_to_world_af, fire_ray.pos); + fire_dir = NormRot(MulAffineBasisVec2(wep_pix_to_world_af, fire_ray.dir)); + } + + // FIXME: Prevent obstructed weapons from firing through walls for (i64 bullet_idx = 0; bullet_idx < tick_bullets_count; ++bullet_idx) { P_Ent *bullet = P_PushTempEnt(scratch.arena, &bullets_to_spawn); @@ -2498,14 +2524,14 @@ void P_StepFrame(P_Frame *frame) f32 rand_angle = ((f32)P_RandU64FromEnt(firer) / (f32)0xFFFFFFFFFFFFFFFFull) - 0.5; f32 speed = tweak_speed * sim_dt; - f32 angle = AngleFromVec2(base_dir); + f32 angle = AngleFromVec2(fire_dir); speed += (speed * 0.5) * rand_speed; angle += rand_angle * spread; Vec2 dir = Vec2FromAngle(angle); - bullet->bullet_start = base_pos; + bullet->bullet_start = fire_pos; bullet->bullet_end = AddVec2(bullet->bullet_start, MulVec2(dir, speed)); bullet->bullet_firer = firer->key; } diff --git a/src/pp/pp_vis/pp_vis_core.c b/src/pp/pp_vis/pp_vis_core.c index 1ba971e7..29c32db6 100644 --- a/src/pp/pp_vis/pp_vis_core.c +++ b/src/pp/pp_vis/pp_vis_core.c @@ -577,6 +577,7 @@ void V_TickForever(WaveLaneCtx *lane) frame->sim_key = prev_frame->sim_key; frame->desired_sim_key = prev_frame->desired_sim_key; frame->predict_tick_accum = prev_frame->predict_tick_accum; + frame->af = prev_frame->af; frame->tick = V.current_frame_tick; frame->time_ns = TimeNs(); @@ -830,6 +831,17 @@ void V_TickForever(WaveLaneCtx *lane) ////////////////////////////// //- Compute movement & look + f32 look_radius = 0; + { + Vec2 world_screen_dims = MulAffineBasisVec2(prev_frame->af.screen_to_world, prev_frame->screen_dims); + // look_radius = MinF32(world_screen_dims.x, world_screen_dims.y) * 0.5; + look_radius = MinF32(world_screen_dims.x, world_screen_dims.y) * 0.75; + + // FIXME: Lower + f32 max_look_radius = 10; + look_radius = ClampF32(look_radius, 1, max_look_radius); + } + if (!frame->is_editing && !frame->palette.is_showing) { WND_PushCmd(window_frame, .kind = WND_CmdKind_SetLockedCursor, .v = 1); @@ -849,14 +861,11 @@ void V_TickForever(WaveLaneCtx *lane) Vec2 look = Zi; f32 fire_presses = fire_held && !prev_frame->held_buttons[Button_M1]; { - // Vec2 center = P_WorldShapeFromEnt(local_guy).centroid; - // look = SubVec2(frame->world_cursor, center); - // TODO: Adjustable sensitivity f32 mouse_scale_factor = 0.005; - look = frame->look; look = AddVec2(look, MulVec2(mouse_delta, mouse_scale_factor)); + look = ClampVec2Len(look, look_radius); } if (frame->is_editing) { @@ -923,14 +932,63 @@ void V_TickForever(WaveLaneCtx *lane) } else { + // // Vec2 look_ratio = VEC2(0.5, 0.5); + // Vec2 look_ratio = VEC2(0.75, 0.75); + // // Vec2 look_ratio = VEC2(1.0, 1.0); + // { + // // look_ratio.y = 0.5; + // // look_ratio.x = look_ratio.y / (16.0 / 9.0); + // } + + // Vec2 look_ratio = Zi; + // { + // Vec2 max_look = Vec2WithLen(frame->look, look_radius); + + // Vec2 look_ratio_of_max = DivVec2Vec2(frame->look, Vec2WithLen(frame->look, look_radius)); + + // look_ratio = look_ratio_of_max; + + // // Vec2 screen_look = MulAffineVec2(frame->af.world_to_screen, frame->look); + // // Vec2 screen_max_look = MulAffineVec2(frame->af.world_to_screen, frame->look) + + // // look_ratio.x = screen_look.x / frame->screen_dims.x; + // // look_ratio.x = frame->look.x / look_radius; + + + // if (IsNan(look_ratio.x) || IsNan(look_ratio.y)) + // { + // look_ratio = VEC2(0, 0); + // } + // } + Vec2 look_ratio = Zi; - look_ratio.y = 0.5; - look_ratio.x = look_ratio.y / (16.0 / 9.0); + { + Vec2 max_look = Vec2WithLen(frame->look, look_radius); + + Vec2 look_ratio_of_radius = DivVec2Vec2(frame->look, Vec2WithLen(frame->look, look_radius)); + + look_ratio = look_ratio_of_radius; + + // Vec2 screen_look = MulAffineVec2(frame->af.world_to_screen, frame->look); + // Vec2 screen_max_look = MulAffineVec2(frame->af.world_to_screen, frame->look) + + // look_ratio.x = screen_look.x / frame->screen_dims.x; + // look_ratio.x = frame->look.x / look_radius; + + + if (IsNan(look_ratio.x) || IsNan(look_ratio.y)) + { + look_ratio = VEC2(0, 0); + } + + // look_ratio = MulVec2(look_ratio, 0.5); + look_ratio = VEC2(0.5, 0.5); + } + P_Ent *player = P_EntFromKey(local_world->last_frame, V.player_key); P_Ent *guy = P_EntFromKey(local_world->last_frame, player->guy); Vec2 guy_center = P_WorldShapeFromEnt(guy).centroid; Vec2 screen_center = MulVec2(frame->screen_dims, 0.5); - // Vec2 look = MulAffineBasisVec2(prev_frame->af.screen_to_world, SubVec2(ui_frame->cursor_pos, screen_center)); target_camera_pos = guy_center; target_camera_pos = AddVec2(target_camera_pos, MulVec2Vec2(frame->look, look_ratio)); target_camera_zoom = 1; @@ -1932,6 +1990,93 @@ void V_TickForever(WaveLaneCtx *lane) ////////////////////////////// //- Draw crosshair + // // TODO: Alive / weapon check + // if (!P_IsEntNil(local_guy)) + // { + // P_Ent *ent = local_guy; + + // P_Anim anim = P_AnimFromEnt(ent, local_frame->time_ns); + // SPR_Sprite body = SPR_SpriteFromSheet(anim.sheet, anim.span, anim.frame_seq); + // SPR_Sprite wep = SPR_SpriteFromSheet(anim.wep_sheet, anim.span, anim.frame_seq); + + // Vec2 look = ent->control.look; + // if (P_MatchKey(ent->key, local_guy->key)) + // { + // // Late latch local player aim direction for lower-latency + // look = frame->look; + // } + + // //- Compute sprite transforms + // Affine cur_ent_to_world_af = MulAffineXform(AffineIdentity, ent->xf); + // Affine desired_ent_to_world_af = MulAffineXform(AffineIdentity, XformTR(ent->xf.t, NormRot(look))); + // Affine cur_body_pix_to_world_af = AffineIdentity; + // Affine cur_wep_pix_to_world_af = AffineIdentity; + // Affine desired_body_pix_to_world_af = AffineIdentity; + // Affine desired_wep_pix_to_world_af = AffineIdentity; + // { + // Vec2 pix_scale = VEC2(1.0 / P_CellsPerMeter, 1.0 / P_CellsPerMeter); + + // //- Compute body transform + // Affine body_pix_to_ent_af = AffineIdentity; + // { + // body_pix_to_ent_af = ScaleAffine(body_pix_to_ent_af, pix_scale); + + // SPR_Ray anchor_ray = body.rays[SPR_RayKind_Anchor]; + // body_pix_to_ent_af = RotateAffine(body_pix_to_ent_af, InvertRot(anchor_ray.dir)); + // body_pix_to_ent_af = TranslateAffine(body_pix_to_ent_af, NegVec2(anchor_ray.pos)); + // } + + // //- Compute weapon transform + // Affine wep_pix_to_ent_af = AffineIdentity; + // { + // wep_pix_to_ent_af = ScaleAffine(wep_pix_to_ent_af, pix_scale); + + // SPR_Ray body_anchor_ray = body.rays[SPR_RayKind_Anchor]; + // SPR_Ray body_ap_ray = body.rays[SPR_RayKind_Ap]; + // wep_pix_to_ent_af = RotateAffine(wep_pix_to_ent_af, InvertRot(body_anchor_ray.dir)); + // wep_pix_to_ent_af = TranslateAffine(wep_pix_to_ent_af, SubVec2(body_ap_ray.pos, body_anchor_ray.pos)); + // wep_pix_to_ent_af = RotateAffine(wep_pix_to_ent_af, InvertRot(body_ap_ray.dir)); + + // SPR_Ray anchor_ray = wep.rays[SPR_RayKind_Anchor]; + // wep_pix_to_ent_af = RotateAffine(wep_pix_to_ent_af, anchor_ray.dir); + // wep_pix_to_ent_af = TranslateAffine(wep_pix_to_ent_af, NegVec2(anchor_ray.pos)); + // } + + // cur_body_pix_to_world_af = MulAffine(cur_ent_to_world_af, body_pix_to_ent_af); + // cur_wep_pix_to_world_af = MulAffine(cur_ent_to_world_af, wep_pix_to_ent_af); + // desired_body_pix_to_world_af = MulAffine(desired_ent_to_world_af, body_pix_to_ent_af); + // desired_wep_pix_to_world_af = MulAffine(desired_ent_to_world_af, wep_pix_to_ent_af); + // } + + // SPR_Ray fire_ray = wep.rays[SPR_RayKind_Ap]; + + // Vec2 cur_fire_pos = MulAffineVec2(cur_wep_pix_to_world_af, fire_ray.pos); + // Vec2 cur_fire_dir = NormRot(MulAffineBasisVec2(cur_wep_pix_to_world_af, fire_ray.dir)); + // Vec2 desired_fire_pos = MulAffineVec2(desired_wep_pix_to_world_af, fire_ray.pos); + // Vec2 desired_fire_dir = NormRot(MulAffineBasisVec2(desired_wep_pix_to_world_af, fire_ray.dir)); + + // Vec2 look_rot = NormRot(look); + + // Vec2 line_start = cur_fire_pos; + // Vec2 line_end = AddVec2(line_start, cur_fire_dir); + // P_DebugDrawLine(line_start, line_end, Color_Yellow); + + // // Vec2 cross = fire_pos; + // // Vec2 cross = MulAffineVec2(frame->af.screen_to_world, look); + + // // f32 cross_dist = 1.0; + // f32 cross_dist = Vec2Len(look); + + // Vec2 cross = AddVec2(desired_fire_pos, MulVec2(look_rot, cross_dist)); + + // // P_DebugDrawPoint(AddVec2(MulAffineVec2(frame->af.screen_to_world, MulVec2(frame->screen_dims, 0.5)), look), Color_Red); + // P_DebugDrawPoint(AddVec2(cur_ent_to_world_af.og, look), Color_Red); + // P_DebugDrawPoint(cross, Color_Green); + // } + + + + // TODO: Alive / weapon check if (!P_IsEntNil(local_guy)) { @@ -1941,8 +2086,16 @@ void V_TickForever(WaveLaneCtx *lane) SPR_Sprite body = SPR_SpriteFromSheet(anim.sheet, anim.span, anim.frame_seq); SPR_Sprite wep = SPR_SpriteFromSheet(anim.wep_sheet, anim.span, anim.frame_seq); - //- Compute sprite transforms + Vec2 look = ent->control.look; + if (P_MatchKey(ent->key, local_guy->key)) + { + // Late latch local player aim direction for lower-latency + look = frame->look; + } + //- Compute sprite transforms + Affine cur_ent_to_world_af = MulAffineXform(AffineIdentity, ent->xf); + Affine desired_ent_to_world_af = MulAffineXform(AffineIdentity, XformTR(ent->xf.t, NormRot(look))); Affine cur_body_pix_to_world_af = AffineIdentity; Affine cur_wep_pix_to_world_af = AffineIdentity; Affine desired_body_pix_to_world_af = AffineIdentity; @@ -1950,9 +2103,6 @@ void V_TickForever(WaveLaneCtx *lane) { Vec2 pix_scale = VEC2(1.0 / P_CellsPerMeter, 1.0 / P_CellsPerMeter); - Affine cur_ent_to_world_af = MulAffineXform(AffineIdentity, ent->xf); - Affine desired_ent_to_world_af = MulAffineXform(AffineIdentity, XformTR(ent->xf.t, NormRot(ent->control.look))); - //- Compute body transform Affine body_pix_to_ent_af = AffineIdentity; { @@ -1992,26 +2142,31 @@ void V_TickForever(WaveLaneCtx *lane) Vec2 desired_fire_pos = MulAffineVec2(desired_wep_pix_to_world_af, fire_ray.pos); Vec2 desired_fire_dir = NormRot(MulAffineBasisVec2(desired_wep_pix_to_world_af, fire_ray.dir)); - Vec2 look_dir = NormRot(frame->look); + Vec2 look_rot = NormRot(look); Vec2 line_start = cur_fire_pos; Vec2 line_end = AddVec2(line_start, cur_fire_dir); - P_DebugDrawLine(line_start, line_end, Color_Yellow); + // P_DebugDrawLine(line_start, line_end, Color_Yellow); // Vec2 cross = fire_pos; - // Vec2 cross = MulAffineVec2(frame->af.screen_to_world, frame->look); + // Vec2 cross = MulAffineVec2(frame->af.screen_to_world, look); // f32 cross_dist = 1.0; - f32 cross_dist = Vec2Len(frame->look); + f32 cross_dist = Vec2Len(look) - Vec2Len(SubVec2(desired_fire_pos, desired_ent_to_world_af.og)); - Vec2 cross = AddVec2(desired_fire_pos, MulVec2(look_dir, cross_dist)); + Vec2 cross = AddVec2(desired_fire_pos, MulVec2(look_rot, cross_dist)); - // P_DebugDrawPoint(AddVec2(MulAffineVec2(frame->af.screen_to_world, MulVec2(frame->screen_dims, 0.5)), frame->look), Color_Red); + // P_DebugDrawPoint(AddVec2(MulAffineVec2(frame->af.screen_to_world, MulVec2(frame->screen_dims, 0.5)), look), Color_Red); + // P_DebugDrawPoint(AddVec2(desired_ent_to_world_af.og, look), Color_Red); P_DebugDrawPoint(cross, Color_Green); } + + + + ////////////////////////////// //- Push test bullet particles