diff --git a/src/game.c b/src/game.c index 2633ba1a..4ec50aff 100644 --- a/src/game.c +++ b/src/game.c @@ -124,10 +124,12 @@ INTERNAL void spawn_test_entities(void) struct v2 pos = V2(-1, -1); struct v2 size = V2(1, 1); f32 r = 0; + f32 skew = PI / 4; struct entity *e = entity_alloc(root); struct xform xf = XFORM_TRS(.t = pos, .r = r, .s = size); + xf = xform_skewed_to(xf, skew); entity_set_xform(e, xf); e->sprite = sprite_tag_from_path(STR("res/graphics/tim.ase")); @@ -463,9 +465,9 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) f32 rot = v2_angle(dir) + PI / 2; struct xform xf = XFORM_IDENT; - xf = xform_rotate(xf, -rot); - xf = xform_scale(xf, sprite_size); - xf = xform_translate(xf, v2_neg(slice.center)); + xf = xform_rotated(xf, -rot); + xf = xform_scaled(xf, sprite_size); + xf = xform_translated(xf, v2_neg(slice.center)); ent->sprite_local_xform = xf; } @@ -491,7 +493,7 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) struct xform xf = entity_get_xform(ent); xf.og = attach_pos; - xf = xform_with_rotation(xf, v2_angle(attach_dir) + PI / 2); + xf = xform_rotated_to(xf, v2_angle(attach_dir) + PI / 2); entity_set_xform(ent, xf); } } @@ -586,8 +588,8 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) struct xform xf = entity_get_local_xform(ent); xf.og = og; - xf = xform_with_rotation(xf, r); - xf = xform_with_scale(xf, s); + xf = xform_rotated_to(xf, r); + xf = xform_scaled_to(xf, s); entity_set_local_xform(ent, xf); } } @@ -797,7 +799,7 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) f32 forward_hold_angle_offset; { - struct xform xf_unrotated = xform_with_rotation(xf, 0); + 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)); } @@ -807,15 +809,15 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) struct v2 hold_pos; { - struct xform hold_pos_xf = xform_translate(ent->sprite_local_xform, slice.center); + 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_with_rotation(hold_pos_xf, v2_angle(hold_pos_xf_dir) + PI / 2); + 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_translate(hold_pos_xf, V2(0, -1)); + hold_pos_xf = xform_translated(hold_pos_xf, V2(0, -1)); } hold_pos = hold_pos_xf.og; } @@ -837,7 +839,7 @@ 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_with_rotation(xf, final_xf_angle); + xf = xform_rotated_to(xf, final_xf_angle); } } diff --git a/src/math.h b/src/math.h index f2815e51..d1d8b149 100644 --- a/src/math.h +++ b/src/math.h @@ -629,6 +629,13 @@ INLINE struct v2 v2_lerp(struct v2 val0, struct v2 val1, f32 t) return res; } +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); +} + INLINE struct v2 v2_from_angle(f32 a) { return V2(math_cos(a), math_sin(a)); @@ -738,15 +745,15 @@ 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_rotate(struct xform xf, f32 angle); -INLINE struct xform xform_scale(struct xform xf, struct v2 v); +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_with_scale(struct xform xf, struct v2 s); +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 struct trs trs_from_xform(struct xform m); -INLINE struct trs trs_lerp(struct trs a, struct trs b, f32 t); +INLINE f32 xform_get_skew(struct xform xf); +INLINE struct xform xform_skewed_to(struct xform xf, f32 s); INLINE b32 xform_eq(struct xform xf1, struct xform xf2) { @@ -765,93 +772,105 @@ INLINE struct xform xform_from_pos(struct v2 v) INLINE struct xform xform_from_trs(struct trs trs) { struct xform xf = XFORM_POS(trs.t); - xf = xform_rotate(xf, trs.r); - xf = xform_scale(xf, trs.s); + xf = xform_rotated(xf, trs.r); + xf = xform_scaled(xf, trs.s); return xf; } -INLINE struct xform xform_translate(struct xform xf, struct v2 v) +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 ); - return xf; } -INLINE struct xform xform_rotate(struct xform xf, f32 angle) +INLINE struct xform xform_rotated(struct xform xf, f32 angle) { 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; - return res; } -INLINE struct xform xform_scale(struct xform xf, struct v2 v) +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_with_rotation(struct xform xf, f32 r) +INLINE struct xform xform_rotated_to(struct xform xf, f32 r) { struct v2 scale = xform_get_scale(xf); + f32 skew = xform_get_skew(xf); f32 c = math_cos(r); f32 s = math_sin(r); xf.bx = V2(c, s); xf.by = V2(-s, c); - xf = xform_with_scale(xf, scale); + xf = xform_scaled_to(xf, scale); + xf = xform_skewed_to(xf, skew); return xf; } -INLINE struct xform xform_with_scale(struct xform xf, struct v2 s) +INLINE struct xform xform_scaled_to(struct xform xf, struct v2 s) { xf.bx = v2_mul(v2_norm(xf.bx), s.x); xf.by = v2_mul(v2_norm(xf.by), s.y); return xf; } +INLINE struct xform xform_skewed_to(struct xform xf, f32 s) +{ + + i32 det_sign = math_fsign(xform_get_determinant(xf)); + struct v2 by = xf.by; + f32 len = v2_len(by); + /* TODO: Is norm & mul by len really necessary? */ + by = v2_mul(v2_norm(v2_rotated(xf.bx, PI * 0.5f + s)), len); + by = v2_mul(by, det_sign); + xf.by = by; + return xf; +} + INLINE struct xform xform_trs(struct xform xf, struct trs trs) { - xf = xform_translate(xf, trs.t); - xf = xform_rotate(xf, trs.r); - xf = xform_scale(xf, trs.s); + 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_translate(xf, trs.t); - xf = xform_rotate(xf, trs.r); - xf = xform_translate(xf, v2_neg(pivot)); - xf = xform_scale(xf, trs.s); + 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_translate(xf, trs.t); - xf = xform_rotate(xf, trs.r); - xf = xform_scale(xf, trs.s); - xf = xform_translate(xf, v2_neg(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 trs trs_a = trs_from_xform(a); - struct trs trs_b = trs_from_xform(b); - struct trs trs = trs_lerp(trs_a, trs_b, t); - return xform_from_trs(trs); + struct xform res; + res.og = v2_lerp(a.og, b.og, t); + res.bx = v2_lerp(a.bx, b.bx, t); + res.by = v2_lerp(a.by, b.by, t); + return res; } INLINE struct xform xform_invert(struct xform xf) @@ -874,13 +893,11 @@ INLINE struct xform xform_invert(struct xform xf) INLINE struct xform xform_mul(struct xform a, struct xform b) { struct xform res; - res.bx.x = a.bx.x * b.bx.x + a.by.x * b.bx.y; res.bx.y = a.bx.y * b.bx.x + a.by.y * b.bx.y; res.by.x = a.bx.x * b.by.x + a.by.x * b.by.y; res.by.y = a.bx.y * b.by.x + a.by.y * b.by.y; res.og = xform_mul_v2(a, b.og); - return res; } @@ -931,15 +948,8 @@ INLINE f32 xform_get_determinant(struct xform xf) INLINE f32 xform_get_skew(struct xform xf) { - f32 det = xform_get_determinant(xf); - i32 det_sign = math_fsign(det); - - struct v2 bx_norm = v2_norm(xf.bx); - struct v2 by_norm = v2_norm(xf.by); - by_norm = v2_mul(by_norm, det_sign); - - f32 dot = v2_dot(bx_norm, by_norm); - + i32 det_sign = math_fsign(xform_get_determinant(xf)); + f32 dot = v2_dot(v2_norm(xf.bx), v2_norm(xf.by)) * det_sign; return math_acos(dot) - (PI / 2.0f); } @@ -974,28 +984,6 @@ INLINE struct v2 xform_get_scale(struct xform xf) return V2(v2_len(xf.bx), det_sign * v2_len(xf.by)); } -/* ========================== * - * Trs - * ========================== */ - -INLINE struct trs trs_lerp(struct trs a, struct trs b, f32 t) -{ - struct trs res; - res.t = v2_lerp(a.t, b.t, t); - res.r = math_lerp_angle(a.r, b.r, t); - res.s = v2_lerp(a.s, b.s, t); - return res; -} - -INLINE struct trs trs_from_xform(struct xform xf) -{ - struct trs trs = { 0 }; - trs.t = xf.og; - trs.r = xform_get_rotation(xf); - trs.s = xform_get_scale(xf); - return trs; -} - /* ========================== * * Quad * ========================== */ diff --git a/src/user.c b/src/user.c index c26081bb..93291c39 100644 --- a/src/user.c +++ b/src/user.c @@ -661,7 +661,7 @@ INTERNAL void user_update(void) * ========================== */ if (G.debug_camera) { - G.world_view = xform_with_rotation(G.world_view, 0); + G.world_view = xform_rotated_to(G.world_view, 0); /* Pan view */ if (G.bind_states[USER_BIND_KIND_PAN].is_held) { @@ -670,7 +670,7 @@ INTERNAL void user_update(void) } G.debug_camera_panning = true; struct v2 offset = v2_sub(G.debug_camera_pan_start, xform_invert_mul_v2(G.world_view, G.viewport_cursor)); - G.world_view = xform_translate(G.world_view, v2_neg(offset)); + G.world_view = xform_translated(G.world_view, v2_neg(offset)); G.debug_camera_pan_start = xform_invert_mul_v2(G.world_view, G.viewport_cursor); } else { G.debug_camera_panning = false; @@ -683,9 +683,9 @@ INTERNAL void user_update(void) f32 zoom_rate = 2; f32 zoom = math_pow(zoom_rate, input_zooms); struct v2 world_cursor = xform_invert_mul_v2(G.world_view, G.viewport_cursor); - G.world_view = xform_translate(G.world_view, world_cursor); - G.world_view = xform_scale(G.world_view, V2(zoom, zoom)); - G.world_view = xform_translate(G.world_view, v2_neg(world_cursor)); + G.world_view = xform_translated(G.world_view, world_cursor); + G.world_view = xform_scaled(G.world_view, V2(zoom, zoom)); + G.world_view = xform_translated(G.world_view, v2_neg(world_cursor)); } } else { struct xform xf = entity_get_xform(active_camera); @@ -712,7 +712,7 @@ INTERNAL void user_update(void) struct v2 pivot = center; G.world_view = XFORM_IDENT; - G.world_view = xform_translate(G.world_view, pivot); + G.world_view = xform_translated(G.world_view, pivot); G.world_view = xform_trs_pivot_rs(G.world_view, trs, pivot); } G.world_cursor = xform_invert_mul_v2(G.world_view, G.viewport_cursor);