From 7708b8e5b8b617f43d5bed0a9bd0076dcf9a0849 Mon Sep 17 00:00:00 2001 From: jacob Date: Tue, 22 Oct 2024 15:16:34 -0500 Subject: [PATCH] rework transformation math functions, add separate 'world' transform functions --- src/config.h | 6 +- src/game.c | 173 ++++++++++++--------------------------------------- src/math.h | 167 +++++++++++++++++++++++++------------------------ src/user.c | 9 ++- 4 files changed, 134 insertions(+), 221 deletions(-) diff --git a/src/config.h b/src/config.h index 968895b8..d41de787 100644 --- a/src/config.h +++ b/src/config.h @@ -37,12 +37,12 @@ #define GAME_PHYSICS_ENABLE_RELAXATION 1 #define USER_DRAW_MENKOWSKI 0 -#define GAME_PHYSICS_ENABLE_GROUND_FRICTION 0 -#define GAME_PHYSICS_ENABLE_COLLISION 1 +#define GAME_PHYSICS_ENABLE_GROUND_FRICTION 1 +#define GAME_PHYSICS_ENABLE_COLLISION 0 #define GAME_SPAWN_LOTS 0 #define GAME_SPAWN_TESTENT 0 #define GAME_SPAWN_BOX 1 -#define GAME_PLAYER_AIM 0 +#define GAME_PLAYER_AIM 1 #define GAME_MAX_LINEAR_VELOCITY 100 #define GAME_MAX_ANGULAR_VELOCITY ((2 * PI) * 20) diff --git a/src/game.c b/src/game.c index 5dc4d2db..e7fe1641 100644 --- a/src/game.c +++ b/src/game.c @@ -149,19 +149,20 @@ INTERNAL void spawn_test_entities(f32 offset) pos = v2_add(pos, V2(0, offset_all)); //struct v2 size = V2(1, 1); - struct v2 size = V2(0.5, 0.5); - //struct v2 size = V2(0.5, 0.25); + //struct v2 size = V2(0.5, 0.5); + struct v2 size = V2(0.5, 0.25); //struct v2 size = V2(1.0, 1.0); //struct v2 size = V2(1.5, 1.5); - f32 r = PI; + //f32 r = PI; //f32 r = PI / 4; //f32 r = PI / 3; //f32 r = 0.05; //f32 r = PI / 2; //f32 r = PI; - //f32 r = 0; + f32 r = 0; struct xform xf = XFORM_TRS(.t = pos, .r = r, .s = size); + //xf.bx.y = -1.f; #else struct xform xf = { .bx = {0.0382978655, -0.498547733}, .by = {0.498547733, 0.0382978655}, .og = {2.01672602, -1.06180537}, }; #endif @@ -194,7 +195,7 @@ INTERNAL void spawn_test_entities(f32 offset) e->linear_ground_friction = 200; e->angular_ground_friction = 100; - //entity_enable_prop(e, ENTITY_PROP_TEST); + entity_enable_prop(e, ENTITY_PROP_TEST); player_ent = e; } @@ -821,27 +822,12 @@ INTERNAL void integrate_positions_from_velocities(f32 dt) ent->linear_velocity = v2_clamp_len(ent->linear_velocity, GAME_MAX_LINEAR_VELOCITY); ent->angular_velocity = clamp_f32(ent->angular_velocity, -GAME_MAX_ANGULAR_VELOCITY, GAME_MAX_ANGULAR_VELOCITY); -#if 0 struct xform xf = entity_get_xform(ent); struct v2 tick_linear_velocity = v2_mul(ent->linear_velocity, dt); f32 tick_angular_velocity = ent->angular_velocity * dt; xf.og = v2_add(xf.og, tick_linear_velocity); - xf = xform_rotated(xf, tick_angular_velocity); + xf = xform_basis_rotated_world(xf, tick_angular_velocity); entity_set_xform(ent, xf); -#else - struct xform xf = entity_get_xform(ent); - struct v2 tick_linear_velocity = v2_mul(ent->linear_velocity, dt); - f32 tick_angular_velocity = ent->angular_velocity * dt; - xf.og = v2_add(xf.og, tick_linear_velocity); - - //xf = xform_rotated_to(xf, xform_get_rotation(xf) + tick_angular_velocity); - - f32 old_angle = xform_get_rotation(xf); - f32 new_angle = old_angle + tick_angular_velocity; - xf = xform_rotated_to(xf, new_angle); - - entity_set_xform(ent, xf); -#endif } } @@ -1048,15 +1034,17 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) { struct xform cxf = ent->sprite_local_xform; +#if 0 if (entity_has_prop(ent, ENTITY_PROP_TEST)) { f32 scale = 0.5; cxf = xform_scaled(cxf, V2(scale, scale)); } +#endif struct sprite_sheet_slice slice = sprite_sheet_get_slice(sheet, STR("shape"), ent->animation_frame); ent->local_collider = collider_from_quad(xform_mul_quad(cxf, quad_from_rect(slice.rect))); -#if 1 +#if 0 if (entity_has_prop(ent, ENTITY_PROP_TEST)) { //if ((true)) { #if 1 @@ -1113,7 +1101,7 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) struct xform xf = entity_get_local_xform(ent); xf.og = attach_pos; - xf = xform_rotated_to(xf, v2_angle(attach_dir) + PI / 2); + xf = xform_basis_with_rotation_world(xf, v2_angle(attach_dir) + PI / 2); entity_set_local_xform(ent, xf); } @@ -1222,8 +1210,8 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) (UNUSED)scale; struct xform xf = entity_get_local_xform(ent); - //xf = xform_rotated_to(xf, rot); - //xf = xform_scaled_to(xf, scale); + xf = xform_rotated_to(xf, rot); + xf = xform_scaled_to(xf, scale); entity_set_local_xform(ent, xf); #endif } @@ -1328,39 +1316,39 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) if (entity_has_prop(ent, ENTITY_PROP_PLAYER_CONTROLLED)) { struct xform xf = entity_get_xform(ent); + struct xform sprite_xf = xform_mul(xf, ent->sprite_local_xform); + f32 old_angle = xform_get_rotation(xf); /* Solve for final angle using law of sines */ f32 final_xf_angle; { - struct sprite_sheet *sheet = sprite_sheet_from_tag_await(sprite_frame_scope, ent->sprite); - struct sprite_sheet_slice slice = sprite_sheet_get_slice(sheet, STR("attach.wep"), ent->animation_frame); - - f32 forward_hold_angle_offset; - { - struct xform xf_unrotated = xform_rotated_to(xf, 0); - struct v2 hold_pos_unrotated = xform_mul_v2(xf_unrotated, xform_mul_v2(ent->sprite_local_xform, slice.center)); - forward_hold_angle_offset = v2_angle_from_dirs(V2(0, -1), v2_sub(hold_pos_unrotated, xf_unrotated.og)); - } - struct v2 ent_pos = xf.og; struct v2 focus_pos = v2_add(ent_pos, ent->control.focus); - struct v2 hold_pos; + struct v2 sprite_hold_pos; + struct v2 sprite_hold_dir; { - struct xform hold_pos_xf = xform_translated(ent->sprite_local_xform, slice.center); - hold_pos_xf = xform_mul(xf, hold_pos_xf); - - struct v2 hold_pos_xf_dir = xform_basis_mul_v2(hold_pos_xf, slice.dir); - hold_pos_xf = xform_rotated_to(hold_pos_xf, v2_angle(hold_pos_xf_dir) + PI / 2); - - if (v2_eq(hold_pos_xf.og, ent_pos)) { - /* If hold pos is same as origin (E.G if pivot is being used as hold pos), then move hold pos forward a tad to avoid issue */ - hold_pos_xf = xform_translated(hold_pos_xf, V2(0, -1)); - } - hold_pos = hold_pos_xf.og; + struct sprite_sheet *sheet = sprite_sheet_from_tag_await(sprite_frame_scope, ent->sprite); + struct sprite_sheet_slice slice = sprite_sheet_get_slice(sheet, STR("attach.wep"), ent->animation_frame); + sprite_hold_pos = slice.center; + sprite_hold_dir = slice.dir; + } + + struct v2 hold_dir = xform_basis_mul_v2(sprite_xf, sprite_hold_dir); + struct v2 hold_pos = xform_mul_v2(sprite_xf, sprite_hold_pos); + if (v2_eq(hold_pos, ent_pos)) { + /* If hold pos is same as origin (E.G if pivot is being used as hold pos), then move hold pos forward a tad to avoid issue */ + sprite_hold_pos = v2_add(sprite_hold_pos, V2(0, -1)); + hold_pos = xform_mul_v2(sprite_xf, sprite_hold_pos); + } + + f32 forward_hold_angle_offset; + { + struct xform xf_unrotated = xform_basis_with_rotation_world(xf, 0); + struct v2 hold_pos_unrotated = xform_mul_v2(xf_unrotated, xform_mul_v2(ent->sprite_local_xform, sprite_hold_pos)); + forward_hold_angle_offset = v2_angle_from_dirs(V2(0, -1), v2_sub(hold_pos_unrotated, xf_unrotated.og)); } - struct v2 hold_dir = xform_basis_mul_v2(xf, xform_basis_mul_v2(ent->sprite_local_xform, slice.dir)); struct v2 hold_ent_dir = v2_sub(ent_pos, hold_pos); struct v2 focus_ent_dir = v2_sub(ent_pos, focus_pos); @@ -1376,98 +1364,15 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) if (!F32_IS_NAN(final_xf_angle)) { const f32 angle_error_allowed = 0.001; - if (math_fabs(final_xf_angle - v2_angle(xf.bx)) > angle_error_allowed) { - xf = xform_rotated_to(xf, final_xf_angle); + f32 diff = final_xf_angle - old_angle; + if (math_fabs(diff) > angle_error_allowed) { + xf = xform_basis_rotated_world(xf, diff); } } entity_set_xform(ent, xf); } } -#else - for (u64 entity_index = 0; entity_index < store->reserved; ++entity_index) { - struct entity *ent = &store->entities[entity_index]; - if (!entity_is_valid_and_active(ent)) continue; - - if (entity_has_prop(ent, ENTITY_PROP_PLAYER_CONTROLLED)) { - struct xform xf = entity_get_xform(ent); - - /* Solve for final angle using law of sines */ - f32 final_xf_angle; - { - struct sprite_sheet *sheet = sprite_sheet_from_tag_await(sprite_frame_scope, ent->sprite); - struct sprite_sheet_slice slice = sprite_sheet_get_slice(sheet, STR("attach.wep"), ent->animation_frame); - - f32 forward_hold_angle_offset; - { - struct xform xf_unrotated = xform_rotated_to(xf, 0); - struct v2 hold_pos_unrotated = xform_mul_v2(xf_unrotated, xform_mul_v2(ent->sprite_local_xform, slice.center)); - forward_hold_angle_offset = v2_angle_from_dirs(V2(0, -1), v2_sub(hold_pos_unrotated, xf_unrotated.og)); - } - - struct v2 ent_pos = xf.og; - struct v2 focus_pos = v2_add(ent_pos, ent->control.focus); - - struct v2 hold_pos; - { - struct xform hold_pos_xf = xform_translated(ent->sprite_local_xform, slice.center); - hold_pos_xf = xform_mul(xf, hold_pos_xf); - - struct v2 hold_pos_xf_dir = xform_basis_mul_v2(hold_pos_xf, slice.dir); - hold_pos_xf = xform_rotated_to(hold_pos_xf, v2_angle(hold_pos_xf_dir) + PI / 2); - - if (v2_eq(hold_pos_xf.og, ent_pos)) { - /* If hold pos is same as origin (E.G if pivot is being used as hold pos), then move hold pos forward a tad to avoid issue */ - hold_pos_xf = xform_translated(hold_pos_xf, V2(0, -1)); - } - hold_pos = hold_pos_xf.og; - } - - struct v2 hold_dir = xform_basis_mul_v2(xf, xform_basis_mul_v2(ent->sprite_local_xform, slice.dir)); - struct v2 hold_ent_dir = v2_sub(ent_pos, hold_pos); - struct v2 focus_ent_dir = v2_sub(ent_pos, focus_pos); - - f32 hold_ent_len = v2_len(hold_ent_dir); - f32 focus_ent_len = v2_len(focus_ent_dir); - - f32 final_hold_angle_btw_ent_and_focus = v2_angle_from_dirs(hold_ent_dir, hold_dir); - f32 final_focus_angle_btw_ent_and_hold = math_asin((math_sin(final_hold_angle_btw_ent_and_focus) * hold_ent_len) / focus_ent_len); - f32 final_ent_angle_btw_focus_and_hold = PI - (final_focus_angle_btw_ent_and_hold + final_hold_angle_btw_ent_and_focus); - - final_xf_angle = v2_angle_from_dirs(V2(0, -1), v2_sub(focus_pos, ent_pos)) + final_ent_angle_btw_focus_and_hold - forward_hold_angle_offset; - } - - if (!F32_IS_NAN(final_xf_angle)) { - const f32 angle_error_allowed = 0.001f; - f32 cur_angle = v2_angle(xf.bx); - f32 diff = final_xf_angle - cur_angle; - if (math_fabs(diff) > angle_error_allowed) { - -#if 0 -#if 0 - /* Create force */ - struct entity *f = entity_alloc(ent); - entity_enable_prop(f, ENTITY_PROP_TORQUE); - - i32 dir = math_fsign(diff); - f32 damp = math_fabs(math_fmod(diff, 2 * PI)) / (2 * PI); - f32 torque = ent->control_torque * dir * damp; - - f->torque = torque; - activate_now(f); -#else - /* TODO: Remove this (testing) */ - /* Create force */ - if (!ent->test_torque_applied) { - ent->test_torque_applied = true; - entity_apply_angular_impulse(ent, 10); - } -#endif -#endif - } - } - } - } #endif /* ========================== * diff --git a/src/math.h b/src/math.h index f01f99af..bdfe5de8 100644 --- a/src/math.h +++ b/src/math.h @@ -746,16 +746,11 @@ INLINE b32 v2_is_zero(struct v2 a) return a.x == 0 && a.y == 0; } -INLINE struct v2 v2_lerp(struct v2 val0, struct v2 val1, f32 t) -{ - return V2(math_lerp(val0.x, val1.x, t), math_lerp(val0.y, val1.y, t)); -} - INLINE struct v2 v2_rotated(struct v2 v, f32 a) { - f32 sin = math_sin(a); - f32 cos = math_cos(a); - return V2(v.x * cos - v.y * sin, v.x * sin + v.y * cos); + f32 c = math_cos(a); + f32 s = math_sin(a); + return V2(v.x * c - v.y * s, v.x * s + v.y * c); } INLINE struct v2 v2_from_angle(f32 a) @@ -786,6 +781,20 @@ INLINE struct v2 v2_closest_point_ray(struct v2 ray_pos, struct v2 ray_dir_norm, return v2_add(ray_pos, ray_dir_closest); } +/* Interpolate position vectors */ +INLINE struct v2 v2_lerp(struct v2 val0, struct v2 val1, f32 t) +{ + return V2(math_lerp(val0.x, val1.x, t), math_lerp(val0.y, val1.y, t)); +} + +/* Interpolate direction vectors (spherical lerp) */ +INLINE struct v2 v2_slerp(struct v2 val0, struct v2 val1, f32 t) +{ + f32 rot = math_lerp_angle(v2_angle(val0), v2_angle(val1), t); + f32 len = math_lerp(v2_len(val0), v2_len(val1), t); + return v2_mul(v2_from_angle(rot), len); +} + /* ========================== * * Mat4x4 * ========================== */ @@ -867,11 +876,11 @@ INLINE struct mat4x4 mat4x4_mul(struct mat4x4 m1, struct mat4x4 m2) /* Takes a translation, rotation, and scale as optional parameters for constructing an xform */ #define XFORM_TRS(...) xform_from_trs((struct trs) { .t = V2(0,0), .s = V2(1, 1), .r = 0, __VA_ARGS__ }) +INLINE struct xform xform_mul(struct xform a, struct xform b); INLINE struct xform xform_rotated(struct xform xf, f32 angle); INLINE struct xform xform_scaled(struct xform xf, struct v2 v); INLINE struct v2 xform_basis_mul_v2(struct xform xf, struct v2 v); INLINE struct v2 xform_mul_v2(struct xform xf, struct v2 v); -INLINE struct xform xform_scaled_to(struct xform xf, struct v2 s); INLINE f32 xform_get_determinant(struct xform xf); INLINE struct v2 xform_get_scale(struct xform xf); INLINE f32 xform_get_rotation(struct xform xf); @@ -890,6 +899,26 @@ INLINE struct xform xform_from_pos(struct v2 v) }; } +INLINE struct xform xform_from_rotation(f32 r) +{ + struct xform res; + f32 c = math_cos(r); + f32 s = math_sin(r); + res.bx = V2(c, s); + res.by = V2(-s, c); + res.og = V2(0, 0); + return res; +} + +INLINE struct xform xform_from_scale(struct v2 scale) +{ + struct xform res; + res.bx = V2(scale.x, 0); + res.by = V2(0, scale.y); + res.og = V2(0, 0); + return res; +} + INLINE struct xform xform_from_trs(struct trs trs) { struct xform xf = XFORM_POS(trs.t); @@ -900,87 +929,63 @@ INLINE struct xform xform_from_trs(struct trs trs) INLINE struct xform xform_translated(struct xform xf, struct v2 v) { - xf.og = V2( - xf.bx.x * v.x + xf.by.x * v.y + xf.og.x, - xf.bx.y * v.x + xf.by.y * v.y + xf.og.y - ); + xf.og = V2(xf.bx.x * v.x + xf.by.x * v.y + xf.og.x, xf.bx.y * v.x + xf.by.y * v.y + xf.og.y); return xf; } -INLINE struct xform xform_rotated(struct xform xf, f32 angle) +INLINE struct xform xform_translated_world(struct xform xf, struct v2 v) { - f32 c = math_cos(angle); - f32 s = math_sin(angle); - struct xform res = xf; - res.bx.x = xf.bx.x * c + xf.by.x * s; - res.bx.y = xf.bx.y * c + xf.by.y * s; - res.by.x = xf.bx.x * -s + xf.by.x * c; - res.by.y = xf.bx.y * -s + xf.by.y * c; + xf.og = v2_add(xf.og, v); + return xf; +} + +INLINE struct xform xform_rotated(struct xform xf, f32 r) +{ + return xform_mul(xf, xform_from_rotation(r)); +} + +INLINE struct xform xform_rotated_world(struct xform xf, f32 r) +{ + return xform_mul(xform_from_rotation(r), xf); +} + +INLINE struct xform xform_basis_rotated_world(struct xform xf, f32 r) +{ + f32 diff = r; + f32 c = math_cos(diff); + f32 s = math_sin(diff); + xf.bx = V2(xf.bx.x * c - xf.bx.y * s, xf.bx.x * s + xf.bx.y * c); + xf.by = V2(xf.by.x * c - xf.by.y * s, xf.by.x * s + xf.by.y * c); + return xf; +} + +INLINE struct xform xform_basis_with_rotation_world(struct xform xf, f32 r) +{ + return xform_basis_rotated_world(xf, r - xform_get_rotation(xf)); +} + +INLINE struct xform xform_scaled(struct xform xf, struct v2 scale) +{ + xf.bx = v2_mul(xf.bx, scale.x); + xf.by = v2_mul(xf.by, scale.y); + return xf; +} + +INLINE struct xform xform_scaled_world(struct xform xf, struct v2 scale) +{ + struct xform res; + res.bx = v2_mul_v2(xf.bx, scale); + res.by = v2_mul_v2(xf.by, scale); + res.og = v2_mul_v2(xf.og, scale); return res; } -INLINE struct xform xform_scaled(struct xform xf, struct v2 v) -{ - xf.bx = v2_mul(xf.bx, v.x); - xf.by = v2_mul(xf.by, v.y); - return xf; -} - -INLINE struct xform xform_rotated_to(struct xform xf, f32 r) -{ - /* TODO: Maintain skew/shear? */ - struct v2 scale = xform_get_scale(xf); - f32 c = math_cos(r); - f32 s = math_sin(r); - xf.bx = V2(c, s); - xf.by = V2(-s, c); - xf = xform_scaled_to(xf, scale); - return xf; -} - -INLINE struct xform xform_scaled_to(struct xform xf, struct v2 s) -{ - xf.bx = v2_with_len(xf.bx, s.x); - xf.by = v2_with_len(xf.by, s.y); - return xf; -} - -INLINE struct xform xform_trs(struct xform xf, struct trs trs) -{ - xf = xform_translated(xf, trs.t); - xf = xform_rotated(xf, trs.r); - xf = xform_scaled(xf, trs.s); - return xf; -} - -INLINE struct xform xform_trs_pivot_r(struct xform xf, struct trs trs, struct v2 pivot) -{ - xf = xform_translated(xf, trs.t); - xf = xform_rotated(xf, trs.r); - xf = xform_translated(xf, v2_neg(pivot)); - xf = xform_scaled(xf, trs.s); - return xf; -} - -INLINE struct xform xform_trs_pivot_rs(struct xform xf, struct trs trs, struct v2 pivot) -{ - xf = xform_translated(xf, trs.t); - xf = xform_rotated(xf, trs.r); - xf = xform_scaled(xf, trs.s); - xf = xform_translated(xf, v2_neg(pivot)); - return xf; -} - INLINE struct xform xform_lerp(struct xform a, struct xform b, f32 t) { - struct v2 og = v2_lerp(a.og, b.og, t); - f32 rot = math_lerp_angle(xform_get_rotation(a), xform_get_rotation(b), t); - struct v2 scale = v2_lerp(xform_get_scale(a), xform_get_scale(b), t); - - struct xform res = xform_from_pos(og); - res = xform_rotated(res, rot); - res = xform_scaled(res, scale); - + struct xform res; + res.bx = v2_slerp(a.bx, b.bx, t); + res.by = v2_slerp(a.by, b.by, t); + res.og = v2_lerp(a.og, b.og, t); return res; } diff --git a/src/user.c b/src/user.c index 1baf64a7..702f901c 100644 --- a/src/user.c +++ b/src/user.c @@ -698,7 +698,7 @@ INTERNAL void user_update(void) * ========================== */ if (G.debug_camera) { - G.world_view = xform_rotated_to(G.world_view, 0); + G.world_view = xform_basis_with_rotation_world(G.world_view, 0); /* Pan view */ if (G.bind_states[USER_BIND_KIND_PAN].is_held) { @@ -750,7 +750,10 @@ INTERNAL void user_update(void) struct v2 pivot = center; G.world_view = XFORM_IDENT; G.world_view = xform_translated(G.world_view, pivot); - G.world_view = xform_trs_pivot_rs(G.world_view, trs, pivot); + G.world_view = xform_translated(G.world_view, trs.t); + G.world_view = xform_rotated(G.world_view, trs.r); + G.world_view = xform_scaled(G.world_view, trs.s); + G.world_view = xform_translated(G.world_view, v2_neg(pivot)); } G.world_cursor = xform_invert_mul_v2(G.world_view, G.viewport_cursor); @@ -1282,7 +1285,7 @@ INTERNAL void user_update(void) /* Draw hierarchy */ if (entity_has_prop(parent, ENTITY_PROP_ACTIVE) && !parent->is_root) { u32 color = RGBA_32_F(0.6, 0.6, 1, 0.75); - f32 thickness = 5; + f32 thickness = 2; f32 arrow_height = 15; struct v2 start = xform_mul_v2(G.world_view, xf.og);