ln, exp, pow, camera lerping

This commit is contained in:
jacob 2024-03-15 01:10:24 -05:00
parent fa6df3152c
commit 39f7b09036
9 changed files with 261 additions and 68 deletions

View File

@ -278,6 +278,10 @@ typedef u64 umm;
#define I32_MIN ((i32)-0x80000000) #define I32_MIN ((i32)-0x80000000)
#define I64_MIN ((i64)-0x8000000000000000LL) #define I64_MIN ((i64)-0x8000000000000000LL)
#define F32_INFINITY (1.0 / 0.0f)
#define F32_MAX (3.402823466e+38F)
#define F32_MIN (1.175494351e-38F)
#define PI ((f32)3.14159265358979323846) #define PI ((f32)3.14159265358979323846)
#define TAU ((f32)6.28318530717958647693) #define TAU ((f32)6.28318530717958647693)

View File

@ -94,7 +94,11 @@ struct entity {
/* ENTITY_PROP_CAMERA */ /* ENTITY_PROP_CAMERA */
struct entity_handle camera_follow; struct entity_handle camera_follow;
struct xform camera_target_xform; /* Calculated from camera_follow */
f32 camera_zoom; f32 camera_zoom;
f32 camera_lerp; /* Rate at which camera xform approaches target xform */
u32 camera_lerp_gen;
u32 camera_applied_lerp_gen_plus_one; /* Calculated */
}; };
struct entity_array { struct entity_array {

View File

@ -119,7 +119,7 @@ INTERNAL void game_update(void)
e->sprite_tint = COLOR_WHITE; e->sprite_tint = COLOR_WHITE;
entity_enable_prop(e, ENTITY_PROP_PLAYER_CONTROLLED); entity_enable_prop(e, ENTITY_PROP_PLAYER_CONTROLLED);
e->player_max_speed = 5.f; e->player_max_speed = 4.f;
e->player_acceleration = 20.0f; e->player_acceleration = 20.0f;
e->player_focus_dir = V2(0, -1); e->player_focus_dir = V2(0, -1);
@ -452,18 +452,41 @@ INTERNAL void game_update(void)
* Update camera position * Update camera position
* ========================== */ * ========================== */
/* Camera follow */
if (entity_has_prop(ent, ENTITY_PROP_CAMERA)) { if (entity_has_prop(ent, ENTITY_PROP_CAMERA)) {
struct entity *follow = entity_from_handle(&L.world.entity_store, ent->camera_follow); struct entity *follow = entity_from_handle(&L.world.entity_store, ent->camera_follow);
ent->world_xform = follow->world_xform; ent->camera_target_xform = follow->world_xform;
ent->world_xform = xform_with_rotation(ent->world_xform, 0); ent->camera_target_xform = xform_with_rotation(ent->camera_target_xform, 0);
ent->world_xform = xform_with_scale(ent->world_xform, V2(1, 1)); ent->camera_target_xform = xform_with_scale(ent->camera_target_xform, V2(1, 1));
if (entity_has_prop(follow, ENTITY_PROP_PLAYER_CONTROLLED)) { if (entity_has_prop(follow, ENTITY_PROP_PLAYER_CONTROLLED)) {
#if 1
/* Regular style camera */
f32 target_dist_x = 0.5;
f32 target_dist_y = target_dist_x * (16.0f / 9.0f);
struct v2 focus_dir = follow->player_focus_dir;
struct v2 target_dir = v2_mul_v2(v2_norm(focus_dir), V2(target_dist_x, target_dist_y));
struct v2 target_pos = v2_add(ent->camera_target_xform.og, target_dir);
ent->camera_target_xform.og = target_pos;
#else
/* "Look" style camera */
struct v2 focus_dir = follow->player_focus_dir; struct v2 focus_dir = follow->player_focus_dir;
struct v2 focus_half_dir = v2_mul(focus_dir, 0.5f); struct v2 focus_half_dir = v2_mul(focus_dir, 0.5f);
struct v2 focus_half_pos = v2_add(follow->world_xform.og, focus_half_dir); struct v2 focus_half_pos = v2_add(follow->world_xform.og, focus_half_dir);
ent->world_xform.og = focus_half_pos; ent->camera_target_xform.og = focus_half_pos;
#endif
} }
/* Lerp camera */
if (ent->camera_applied_lerp_gen_plus_one == ent->camera_lerp_gen + 1) {
f32 t = 1 - math_pow(2.f, -10.f * (f32)L.world.dt);
ent->rel_xform = xform_lerp(ent->rel_xform, ent->camera_target_xform, t);
} else {
/* Skip lerp */
ent->rel_xform = ent->camera_target_xform;
}
ent->camera_applied_lerp_gen_plus_one = ent->camera_lerp_gen + 1;
ent->world_xform = ent->rel_xform;
} }
/* ========================== * /* ========================== *

View File

@ -3,6 +3,8 @@
#include "intrinsics.h" #include "intrinsics.h"
INLINE f32 math_sqrt(f32 x);
/* ========================== * /* ========================== *
* Rounding * Rounding
* ========================== */ * ========================== */
@ -37,9 +39,8 @@ INLINE f32 math_fabs(f32 f)
INLINE i32 math_fsign(f32 f) INLINE i32 math_fsign(f32 f)
{ {
u32 bits = *(u32 *)&f; u32 sign_bit = (*(u32 *)&f >> 31) & 1;
i32 sign_bit = bits & ((u32)1 << 31); return 1 + -(sign_bit << 1);
return 1 + (sign_bit * -2);
} }
/* ========================== * /* ========================== *
@ -128,6 +129,174 @@ INLINE u64 math_pow_u64(u64 base, u8 exp) {
} }
} }
/* Based on FreeBSD's implementation
* https://github.com/freebsd/freebsd-src/blob/main/lib/msun/src/e_logf.c */
INLINE f32 math_ln(f32 x)
{
static const f32 ln2_hi = 6.9313812256e-01;
static const f32 ln2_lo = 9.0580006145e-06;
i32 x_int = *(u32 *)&x;
i32 k = 0;
if (x_int < 0x00800000) {
f32 two_p25 = 3.3554432000e+07;
if ((x_int & 0x7fffffff) == 0) {
/* Return -inf if x is 0 */
return -two_p25 / 0;
} else if (x_int < 0) {
/* Return NaN if x is negative */
return (x - x) / 0;
}
k -= 25;
x *= two_p25;
x_int = *(u32 *)&x;
} else if (x_int >= 0x7f800000) {
return x + x;
}
k += (x_int >> 23) - 127;
x_int &= 0x007fffff;
i32 i = (x_int + (0x95f64 << 3)) & 0x800000;
i32 x_int_normalized = x_int | (i ^ 0x3f800000);
x = *(f32 *)&x_int_normalized - 1.0f;
k += (i >> 23);
if ((0x007fffff & (0x8000 + x_int)) < 0xc000) {
if (x == 0.0f) {
if (k == 0) {
return 0;
} else {
return (f32)k * ln2_hi + (f32)k * ln2_lo;
}
}
f32 r = x * x * (0.5f - 0.33333333333333333f * x);
if (k == 0) {
return x - r;
} else {
return (f32)k * ln2_hi - ((r - (f32)k * ln2_lo) - x);
}
}
f32 s = x / (2.0f + x);
f32 z = s * s;
f32 w = z * z;
f32 r = (z * (0.66666662693f + w * 0.28498786688f)) + (w * (0.40000972152f + w * 0.24279078841f));
if (((x_int - (0x6147a << 3)) | ((0x6b851 << 3) - x_int)) > 0) {
f32 hfsq = 0.5f * x * x;
if (k == 0) {
return x - (hfsq - s * (hfsq + r));
} else {
return (f32)k * ln2_hi - ((hfsq - (s * (hfsq + r) + (f32)k * ln2_lo)) - x);
}
} else {
if (k == 0) {
return x - s * (x - r);
} else {
return (f32)k * ln2_hi - ((s * (x - r) - (f32)k * ln2_lo) - x);
}
}
}
/* Based on FreeBSD's implementation
* https://github.com/freebsd/freebsd-src/blob/main/lib/msun/src/e_expf.c */
INLINE f32 math_exp(f32 x)
{
static const f32 half[2] = { 0.5, -0.5 };
static const f32 o_threshold = 8.8721679688e+01;
static const f32 u_threshold = -1.0397208405e+02;
static const f32 ln2_hi[2] = { 6.9314575195e-01, -6.9314575195e-01 };
static const f32 ln2_lo[2] = { 1.4286067653e-06, -1.4286067653e-06 };
static const f32 inv_ln2 = 1.4426950216e+00;
static const f32 huge = 1.0e+30;
static const f32 two_m100 = 7.8886090522e-31;
u32 x_uint = *(u32 *)&x;
i32 x_sign_bit = (x_uint >> 31) & 1;
x_uint &= 0x7fffffff;
/* Filter out non-finite argument */
if (x_uint >= 0x42b17218) { /* if |x|>=88.721... */
if (x_uint > 0x7f800000) {
return x + x; /* NaN */
} else if (x_uint == 0x7f800000) {
return (x_sign_bit == 0) ? x : 0.0;
}
if (x > o_threshold) {
/* Overflow */
return huge * huge;
} else if (x < u_threshold) {
/* Underflow */
return two_m100 * two_m100;
}
}
/* Argument reduction */
i32 k = 0;
f32 hi = 0;
f32 lo = 0;
if (x_uint > 0x3eb17218) {
if (x_uint < 0x3F851592) {
hi = x - ln2_hi[x_sign_bit];
lo = ln2_lo[x_sign_bit];
k = 1 - x_sign_bit - x_sign_bit;
} else {
k = inv_ln2 * x + half[x_sign_bit];
hi = x - (f32)k * ln2_hi[0];
lo = (f32)k * ln2_lo[0];
}
x = hi - lo;
} else if (x_uint < 0x39000000) {
if (huge + x > 1.0f) {
return 1.0f + x;
}
} else {
k = 0;
}
f32 two_pk;
if (k >= -125) {
u32 temp = ((u32)(0x7f + k)) << 23;
two_pk = *(f32 *)&temp;
} else {
u32 temp = ((u32)(0x7f + (k + 100))) << 23;
two_pk = *(f32 *)&temp;
}
f32 t = x * x;
f32 c = x - t * (1.6666625440e-1f + t * -2.7667332906e-3f);
if (k == 0) {
return 1.0f - ((x * c) / (c - 2.0f) - x);
} else {
f32 y = 1.0f - ((lo - (x * c)/(2.0f - c))-hi);
if (k >= -125) {
if (k==128) {
u32 temp = 0x7f800000;
return y * 2.0f * (*(f32 *)&temp);
}
return y * two_pk;
} else {
return y * two_pk * two_m100;
}
}
}
INLINE f32 math_pow(f32 a, f32 b)
{
if (a >= 0) {
/* a is positive */
return math_exp(math_ln(a) * b);
} else {
/* a is negative */
i32 res_sign = math_round(b) % 2 == 0 ? 1 : -1;
return math_exp(math_ln(-a) * b) * res_sign;
}
}
INLINE f32 math_sqrt(f32 x)
{
return ix_sqrt_f32(x);
}
INLINE f32 math_rsqrt(f32 x) INLINE f32 math_rsqrt(f32 x)
{ {
@ -145,15 +314,10 @@ INLINE f32 math_rsqrt_fast(f32 x)
i32 i = *(i32 *)&y; i32 i = *(i32 *)&y;
i = 0x5f3759df - (i >> 1); i = 0x5f3759df - (i >> 1);
y = *(f32 *)&i; y = *(f32 *)&i;
y *= three_halfs - (x2 * y * y); /* 1st iteration */ y *= three_halfs - (x2 * y * y);
return y; return y;
} }
INLINE f32 math_sqrt(f32 x)
{
return ix_sqrt_f32(x);
}
/* ========================== * /* ========================== *
* Trig * Trig
* ========================== */ * ========================== */
@ -224,7 +388,7 @@ INLINE f32 math_acos(f32 x)
* Lerp * Lerp
* ========================== */ * ========================== */
INLINE f32 math_lerp_f32(f32 val0, f32 val1, f32 t) INLINE f32 math_lerp(f32 val0, f32 val1, f32 t)
{ {
return val0 + ((val1 - val0) * t); return val0 + ((val1 - val0) * t);
} }
@ -364,8 +528,8 @@ INLINE b32 v2_eq(struct v2 a, struct v2 b)
INLINE struct v2 v2_lerp(struct v2 val0, struct v2 val1, f32 t) INLINE struct v2 v2_lerp(struct v2 val0, struct v2 val1, f32 t)
{ {
struct v2 res; struct v2 res;
res.x = math_lerp_f32(val0.x, val1.x, t); res.x = math_lerp(val0.x, val1.x, t);
res.y = math_lerp_f32(val0.y, val1.y, t); res.y = math_lerp(val0.y, val1.y, t);
return res; return res;
} }
@ -532,9 +696,9 @@ INLINE struct xform xform_scale(struct xform xf, struct v2 v)
INLINE struct xform xform_with_rotation(struct xform xf, f32 r) INLINE struct xform xform_with_rotation(struct xform xf, f32 r)
{ {
struct v2 scale = xform_get_scale(xf); struct v2 scale = xform_get_scale(xf);
f32 c = math_cos(r); f32 c = math_cos(r);
f32 s = math_sin(r); f32 s = math_sin(r);
xf.bx = V2(c, s); xf.bx = V2(c, s);
xf.by = V2(-s, c); xf.by = V2(-s, c);
xf = xform_with_scale(xf, scale); xf = xform_with_scale(xf, scale);
@ -543,8 +707,8 @@ INLINE struct xform xform_with_rotation(struct xform xf, f32 r)
INLINE struct xform xform_with_scale(struct xform xf, struct v2 s) INLINE struct xform xform_with_scale(struct xform xf, struct v2 s)
{ {
xf.bx = v2_mul(v2_norm(xf.bx), s.x); xf.bx = v2_mul(v2_norm(xf.bx), s.x);
xf.by = v2_mul(v2_norm(xf.by), s.y); xf.by = v2_mul(v2_norm(xf.by), s.y);
return xf; return xf;
} }
@ -586,8 +750,8 @@ INLINE struct xform xform_lerp(struct xform a, struct xform b, f32 t)
INLINE struct xform xform_invert(struct xform xf) INLINE struct xform xform_invert(struct xform xf)
{ {
f32 det = xform_get_determinant(xf); f32 det = xform_get_determinant(xf);
f32 inv_det = 1.0f / det; f32 inv_det = 1.0f / det;
f32 old_bx_x = xf.bx.x; f32 old_bx_x = xf.bx.x;
xf.bx.x = xf.by.y; xf.bx.x = xf.by.y;
@ -691,7 +855,7 @@ INLINE f32 xform_get_rotation(struct xform xf)
INLINE struct v2 xform_get_scale(struct xform xf) INLINE struct v2 xform_get_scale(struct xform xf)
{ {
f32 det_sign = math_fsign(xform_get_determinant(xf)); f32 det_sign = math_fsign(xform_get_determinant(xf));
return V2(v2_len(xf.bx), det_sign * v2_len(xf.by)); return V2(v2_len(xf.bx), det_sign * v2_len(xf.by));
} }
/* ========================== * /* ========================== *

View File

@ -370,8 +370,8 @@ struct mixed_pcm_f32 mixer_update(struct arena *arena, u64 frame_count)
/* Lerp */ /* Lerp */
f32 t = in_frame_pos_exact - (f32)in_frame_pos_prev; f32 t = in_frame_pos_exact - (f32)in_frame_pos_prev;
f32 sample1 = math_lerp_f32(sample1_prev, sample1_next, t); f32 sample1 = math_lerp(sample1_prev, sample1_next, t);
f32 sample2 = math_lerp_f32(sample2_prev, sample2_next, t); f32 sample2 = math_lerp(sample2_prev, sample2_next, t);
out_samples[(out_frame_pos * 2) + 0] += sample1; out_samples[(out_frame_pos * 2) + 0] += sample1;
out_samples[(out_frame_pos * 2) + 1] += sample2; out_samples[(out_frame_pos * 2) + 1] += sample2;
@ -389,7 +389,7 @@ struct mixed_pcm_f32 mixer_update(struct arena *arena, u64 frame_count)
/* Lerp */ /* Lerp */
f32 t = (f32)in_frame_pos_exact - in_frame_pos_prev; f32 t = (f32)in_frame_pos_exact - in_frame_pos_prev;
f32 sample = math_lerp_f32(sample_prev, sample_next, t); f32 sample = math_lerp(sample_prev, sample_next, t);
out_samples[(out_frame_pos * 2) + 0] += sample; out_samples[(out_frame_pos * 2) + 0] += sample;
out_samples[(out_frame_pos * 2) + 1] += sample; out_samples[(out_frame_pos * 2) + 1] += sample;
@ -440,8 +440,8 @@ struct mixed_pcm_f32 mixer_update(struct arena *arena, u64 frame_count)
/* Spatialize samples */ /* Spatialize samples */
for (u64 frame_pos = 0; frame_pos < frame_count; ++frame_pos) { for (u64 frame_pos = 0; frame_pos < frame_count; ++frame_pos) {
f32 t = (f32)frame_pos / (f32)(frame_count - 1); f32 t = (f32)frame_pos / (f32)(frame_count - 1);
f32 volume = math_lerp_f32(volume_start, volume_end, t); f32 volume = math_lerp(volume_start, volume_end, t);
f32 pan = math_lerp_f32(pan_start, pan_end, t); f32 pan = math_lerp(pan_start, pan_end, t);
u64 sample1_index = frame_pos * 2; u64 sample1_index = frame_pos * 2;
u64 sample2_index = sample1_index + 1; u64 sample2_index = sample1_index + 1;

View File

@ -13,8 +13,8 @@ enum sys_event_kind {
SYS_EVENT_KIND_BUTTON_DOWN, SYS_EVENT_KIND_BUTTON_DOWN,
SYS_EVENT_KIND_BUTTON_UP, SYS_EVENT_KIND_BUTTON_UP,
SYS_EVENT_KIND_CURSOR_MOVE,
SYS_EVENT_KIND_MOUSE_MOVE, SYS_EVENT_KIND_MOUSE_MOVE,
SYS_EVENT_KIND_RAW_MOUSE_MOVE,
SYS_EVENT_KIND_TEXT, SYS_EVENT_KIND_TEXT,
SYS_EVENT_KIND_QUIT, SYS_EVENT_KIND_QUIT,
@ -128,15 +128,19 @@ enum sys_btn {
struct sys_event { struct sys_event {
enum sys_event_kind kind; enum sys_event_kind kind;
/* SYS_EVENT_KIND_BUTTON_DOWN */
/* SYS_EVENT_KIND_BUTTON_UP */
enum sys_btn button; enum sys_btn button;
b32 is_repeat; b32 is_repeat;
/* SYS_EVENT_KIND_TEXT */
u32 text_character; u32 text_character;
struct v2 mouse_position; /* SYS_EVENT_KIND_CURSOR_MOVE */
struct v2 mouse_delta; struct v2 cursor_position;
struct v2 raw_mouse_delta; /* SYS_EVENT_KIND_MOUSE_MOVE */
struct v2 mouse_delta;
}; };
struct sys_event_array { struct sys_event_array {

View File

@ -59,7 +59,6 @@ struct win32_window {
* their pre-minimized values) */ * their pre-minimized values) */
i32 x, y, width, height; i32 x, y, width, height;
struct v2 cursor_pos;
u32 cursor_set_flags; u32 cursor_set_flags;
struct v2 cursor_set_position; struct v2 cursor_set_position;
@ -788,7 +787,7 @@ INTERNAL void win32_update_window_from_settings(struct win32_window *window, str
INTERNAL void win32_window_wake(struct win32_window *window) INTERNAL void win32_window_wake(struct win32_window *window)
{ {
/* Post a blank message to the window's thread message queue to wake it. */ /* Post a blank message to the window's thread message queue to wake it. */
PostThreadMessageA(window->tid, 0, 0, 0); PostThreadMessageA(window->tid, WM_NULL, 0, 0);
} }
INTERNAL LRESULT CALLBACK win32_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) INTERNAL LRESULT CALLBACK win32_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
@ -915,8 +914,7 @@ INTERNAL LRESULT CALLBACK win32_window_proc(HWND hwnd, UINT msg, WPARAM wparam,
window, window,
(struct sys_event) { (struct sys_event) {
.kind = event_kind, .kind = event_kind,
.button = button, .button = button
.mouse_position = window->cursor_pos
} }
); );
} }
@ -938,15 +936,11 @@ INTERNAL LRESULT CALLBACK win32_window_proc(HWND hwnd, UINT msg, WPARAM wparam,
case WM_MOUSEMOVE: { case WM_MOUSEMOVE: {
i32 x = GET_X_LPARAM(lparam); i32 x = GET_X_LPARAM(lparam);
i32 y = GET_Y_LPARAM(lparam); i32 y = GET_Y_LPARAM(lparam);
struct v2 old = window->cursor_pos;
window->cursor_pos = V2(x, y);
struct v2 delta = v2_sub(window->cursor_pos, old);
win32_window_process_event( win32_window_process_event(
window, window,
(struct sys_event) { (struct sys_event) {
.kind = SYS_EVENT_KIND_MOUSE_MOVE, .kind = SYS_EVENT_KIND_CURSOR_MOVE,
.mouse_position = window->cursor_pos, .cursor_position = V2(x, y)
.mouse_delta = delta
} }
); );
} break; } break;
@ -972,8 +966,8 @@ INTERNAL LRESULT CALLBACK win32_window_proc(HWND hwnd, UINT msg, WPARAM wparam,
win32_window_process_event( win32_window_process_event(
window, window,
(struct sys_event) { (struct sys_event) {
.kind = SYS_EVENT_KIND_RAW_MOUSE_MOVE, .kind = SYS_EVENT_KIND_MOUSE_MOVE,
.raw_mouse_delta = delta .mouse_delta = delta
} }
); );
} }

View File

@ -8,7 +8,6 @@ extern "C"
#include "ttf.h" #include "ttf.h"
#include "renderer.h" #include "renderer.h"
#include "scratch.h" #include "scratch.h"
#include "math.h"
#include "util.h" #include "util.h"
/* TODO: remove this */ /* TODO: remove this */

View File

@ -64,9 +64,9 @@ GLOBAL struct {
f64 dt; f64 dt;
struct v2 screen_size; struct v2 screen_size;
struct v2 screen_center; struct v2 screen_center;
struct v2 screen_mouse; struct v2 screen_cursor;
struct v2 screen_mouse_delta; struct v2 world_cursor;
struct v2 world_mouse; struct v2 mouse_delta;
struct v2 last_focus_screen_pos; struct v2 last_focus_screen_pos;
} L = { 0 }, DEBUG_LVAR(L_user); } L = { 0 }, DEBUG_LVAR(L_user);
@ -405,13 +405,14 @@ INTERNAL void user_update(void)
e->acceleration = v2_lerp(e0->acceleration, e1->acceleration, tick_blend); e->acceleration = v2_lerp(e0->acceleration, e1->acceleration, tick_blend);
e->velocity = v2_lerp(e0->velocity, e1->velocity, tick_blend); e->velocity = v2_lerp(e0->velocity, e1->velocity, tick_blend);
e->player_acceleration = math_lerp_f32(e0->player_acceleration, e1->player_acceleration, tick_blend); e->player_acceleration = math_lerp(e0->player_acceleration, e1->player_acceleration, tick_blend);
e->player_focus_dir = v2_lerp(e0->player_focus_dir, e1->player_focus_dir, tick_blend); e->player_focus_dir = v2_lerp(e0->player_focus_dir, e1->player_focus_dir, tick_blend);
e->sprite_xform = xform_lerp(e0->sprite_xform, e1->sprite_xform, tick_blend); e->sprite_xform = xform_lerp(e0->sprite_xform, e1->sprite_xform, tick_blend);
e->animation_time_in_frame = math_lerp_f64(e0->animation_time_in_frame, e1->animation_time_in_frame, (f64)tick_blend); e->animation_time_in_frame = math_lerp_f64(e0->animation_time_in_frame, e1->animation_time_in_frame, (f64)tick_blend);
e->camera_zoom = math_lerp_f32(e0->camera_zoom, e1->camera_zoom, tick_blend); e->camera_zoom = math_lerp(e0->camera_zoom, e1->camera_zoom, tick_blend);
e->camera_target_xform = xform_lerp(e0->camera_target_xform, e1->camera_target_xform, tick_blend);
} }
} }
#else #else
@ -436,7 +437,7 @@ INTERNAL void user_update(void)
}; };
} }
L.screen_mouse_delta = V2(0, 0); L.mouse_delta = V2(0, 0);
for (u64 entity_index = 0; entity_index < events.count; ++entity_index) { for (u64 entity_index = 0; entity_index < events.count; ++entity_index) {
struct sys_event *event = &events.events[entity_index]; struct sys_event *event = &events.events[entity_index];
@ -475,13 +476,13 @@ INTERNAL void user_update(void)
#endif #endif
/* Update mouse pos */ /* Update mouse pos */
if (event->kind == SYS_EVENT_KIND_MOUSE_MOVE) { if (event->kind == SYS_EVENT_KIND_CURSOR_MOVE) {
L.screen_mouse = event->mouse_position; L.screen_cursor = event->cursor_position;
} }
/* Update mouse delta */ /* Update mouse delta */
if (event->kind == SYS_EVENT_KIND_RAW_MOUSE_MOVE) { if (event->kind == SYS_EVENT_KIND_MOUSE_MOVE) {
L.screen_mouse_delta = v2_add(L.screen_mouse_delta, event->raw_mouse_delta); L.mouse_delta = v2_add(L.mouse_delta, event->mouse_delta);
} }
/* Update bind states */ /* Update bind states */
@ -540,12 +541,12 @@ INTERNAL void user_update(void)
/* Pan view */ /* Pan view */
if (L.bind_states[USER_BIND_KIND_PAN].is_held) { if (L.bind_states[USER_BIND_KIND_PAN].is_held) {
if (!L.debug_camera_panning) { if (!L.debug_camera_panning) {
L.debug_camera_pan_start = xform_invert_mul_v2(L.world_view, L.screen_mouse); L.debug_camera_pan_start = xform_invert_mul_v2(L.world_view, L.screen_cursor);
} }
L.debug_camera_panning = true; L.debug_camera_panning = true;
struct v2 offset = v2_sub(L.debug_camera_pan_start, xform_invert_mul_v2(L.world_view, L.screen_mouse)); struct v2 offset = v2_sub(L.debug_camera_pan_start, xform_invert_mul_v2(L.world_view, L.screen_cursor));
L.world_view = xform_translate(L.world_view, v2_neg(offset)); L.world_view = xform_translate(L.world_view, v2_neg(offset));
L.debug_camera_pan_start = xform_invert_mul_v2(L.world_view, L.screen_mouse); L.debug_camera_pan_start = xform_invert_mul_v2(L.world_view, L.screen_cursor);
} else { } else {
L.debug_camera_panning = false; L.debug_camera_panning = false;
} }
@ -567,13 +568,12 @@ INTERNAL void user_update(void)
} }
} }
/* Zoom to mouse */ /* Zoom to cursor */
struct v2 world_mouse = xform_invert_mul_v2(L.world_view, L.screen_mouse); struct v2 world_cursor = xform_invert_mul_v2(L.world_view, L.screen_cursor);
L.world_view = xform_translate(L.world_view, world_mouse); L.world_view = xform_translate(L.world_view, world_cursor);
L.world_view = xform_scale(L.world_view, V2(zoom, zoom)); L.world_view = xform_scale(L.world_view, V2(zoom, zoom));
L.world_view = xform_translate(L.world_view, v2_neg(world_mouse)); L.world_view = xform_translate(L.world_view, v2_neg(world_cursor));
} }
} else { } else {
/* Keep cursor invisible and in screen */ /* Keep cursor invisible and in screen */
sys_window_cursor_hide(L.window); sys_window_cursor_hide(L.window);
@ -602,6 +602,7 @@ INTERNAL void user_update(void)
L.world_view = xform_translate(L.world_view, pivot); L.world_view = xform_translate(L.world_view, pivot);
L.world_view = xform_trs_pivot_rs(L.world_view, trs, pivot); L.world_view = xform_trs_pivot_rs(L.world_view, trs, pivot);
} }
L.world_cursor = xform_invert_mul_v2(L.world_view, L.screen_cursor);
/* ========================== * /* ========================== *
* Update listener * Update listener
@ -658,7 +659,7 @@ INTERNAL void user_update(void)
.move_dir = player_move_dir .move_dir = player_move_dir
}; };
if (!L.debug_camera) { if (!L.debug_camera) {
struct v2 focus_move_dir = xform_basis_invert_mul_v2(L.world_view, L.screen_mouse_delta); /* Make focus relative to world view direction */ struct v2 focus_move_dir = xform_basis_invert_mul_v2(L.world_view, L.mouse_delta); /* Make focus relative to world view direction */
focus_move_dir = v2_mul(focus_move_dir, MOUSE_SENSITIVITY); focus_move_dir = v2_mul(focus_move_dir, MOUSE_SENSITIVITY);
cmd.focus_move_dir = focus_move_dir; cmd.focus_move_dir = focus_move_dir;
} }
@ -887,7 +888,7 @@ INTERNAL void user_update(void)
draw_text(L.screen_canvas, font, pos, string_format(temp.arena, STR("screen_center: (%F, %F)"), FMT_FLOAT((f64)L.screen_center.x), FMT_FLOAT((f64)L.screen_center.y))); draw_text(L.screen_canvas, font, pos, string_format(temp.arena, STR("screen_center: (%F, %F)"), FMT_FLOAT((f64)L.screen_center.x), FMT_FLOAT((f64)L.screen_center.y)));
pos.y += spacing; pos.y += spacing;
draw_text(L.screen_canvas, font, pos, string_format(temp.arena, STR("screen_mouse: (%F, %F)"), FMT_FLOAT((f64)L.screen_mouse.x), FMT_FLOAT((f64)L.screen_mouse.y))); draw_text(L.screen_canvas, font, pos, string_format(temp.arena, STR("screen_cursor: (%F, %F)"), FMT_FLOAT((f64)L.screen_cursor.x), FMT_FLOAT((f64)L.screen_cursor.y)));
pos.y += spacing; pos.y += spacing;
draw_text(L.screen_canvas, font, pos, string_format(temp.arena, STR("world_view.og: (%F, %F)"), FMT_FLOAT((f64)L.world_view.og.x), FMT_FLOAT((f64)L.world_view.og.y))); draw_text(L.screen_canvas, font, pos, string_format(temp.arena, STR("world_view.og: (%F, %F)"), FMT_FLOAT((f64)L.world_view.og.x), FMT_FLOAT((f64)L.world_view.og.y)));
@ -899,7 +900,7 @@ INTERNAL void user_update(void)
draw_text(L.screen_canvas, font, pos, string_format(temp.arena, STR("world_view scale: (%F, %F)"), FMT_FLOAT((f64)xform_get_scale(L.world_view).x), FMT_FLOAT((f64)xform_get_scale(L.world_view).x))); draw_text(L.screen_canvas, font, pos, string_format(temp.arena, STR("world_view scale: (%F, %F)"), FMT_FLOAT((f64)xform_get_scale(L.world_view).x), FMT_FLOAT((f64)xform_get_scale(L.world_view).x)));
pos.y += spacing; pos.y += spacing;
draw_text(L.screen_canvas, font, pos, string_format(temp.arena, STR("world_mouse: (%F, %F)"), FMT_FLOAT((f64)L.world_mouse.x), FMT_FLOAT((f64)L.world_mouse.y))); draw_text(L.screen_canvas, font, pos, string_format(temp.arena, STR("world_cursor: (%F, %F)"), FMT_FLOAT((f64)L.world_cursor.x), FMT_FLOAT((f64)L.world_cursor.y)));
pos.y += spacing; pos.y += spacing;
draw_text(L.screen_canvas, font, pos, string_format(temp.arena, STR("debug_camera: %F"), FMT_STR(L.debug_camera ? STR("true") : STR("false")))); draw_text(L.screen_canvas, font, pos, string_format(temp.arena, STR("debug_camera: %F"), FMT_STR(L.debug_camera ? STR("true") : STR("false"))));