rework transformation math functions, add separate 'world' transform functions

This commit is contained in:
jacob 2024-10-22 15:16:34 -05:00
parent ed8b03941e
commit 7708b8e5b8
4 changed files with 134 additions and 221 deletions

View File

@ -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)

View File

@ -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 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_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)) {
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 */
hold_pos_xf = xform_translated(hold_pos_xf, V2(0, -1));
}
hold_pos = hold_pos_xf.og;
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
/* ========================== *

View File

@ -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;
}

View File

@ -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);