view zooming & panning

This commit is contained in:
jacob 2024-02-29 19:01:51 -06:00
parent 8284923173
commit 7b2437889e
4 changed files with 121 additions and 162 deletions

View File

@ -139,67 +139,6 @@ INTERNAL void game_update(void)
if (!run) { if (!run) {
run = 1; run = 1;
/* Create moving ents */
{
f32 start_x = -1;
f32 start_y = -1;
struct v2 draw_size = V2(0.25f, 0.25f);
{
struct entity *e = entity_alloc();
e->active = true;
e->start_pos = V2(start_x, start_y);
entity_enable_prop(e, ENTITY_PROP_TEST);
entity_enable_prop(e, ENTITY_PROP_TEXTURED);
e->draw_size = draw_size;
e->texture_name = STR("res/graphics/timmy.ase");
}
{
struct entity *e = entity_alloc();
e->active = true;
e->start_pos = V2(start_x + 0.5f, start_y);
entity_enable_prop(e, ENTITY_PROP_TEST);
entity_enable_prop(e, ENTITY_PROP_TEXTURED);
e->draw_size = draw_size;
e->texture_name = STR("res/graphics/bla.ase");
entity_start_animation(e, STR("Test"), ANIMATION_FLAG_LOOPING);
}
{
struct entity *e = entity_alloc();
e->active = true;
e->start_pos = V2(start_x + 1.f, start_y);
entity_enable_prop(e, ENTITY_PROP_TEST);
entity_enable_prop(e, ENTITY_PROP_TEXTURED);
e->draw_size = draw_size;
e->texture_name = STR("res/graphics/floor_tiles.ase");
entity_start_animation(e, STR("Test"), ANIMATION_FLAG_LOOPING);
}
{
struct entity *e = entity_alloc();
e->active = true;
e->start_pos = V2(start_x + 1.5f, start_y);
entity_enable_prop(e, ENTITY_PROP_TEST);
entity_enable_prop(e, ENTITY_PROP_TEXTURED);
e->draw_size = draw_size;
e->texture_name = STR("res/graphics/white.ase");
entity_start_animation(e, STR("Test"), ANIMATION_FLAG_LOOPING);
}
{
struct entity *e = entity_alloc();
e->active = true;
e->start_pos = V2(start_x + 2.f, start_y);
entity_enable_prop(e, ENTITY_PROP_TEST);
entity_enable_prop(e, ENTITY_PROP_TEXTURED);
e->draw_size = draw_size;
e->texture_name = STR("res/graphics/bad.ase");
entity_start_animation(e, STR("Test"), ANIMATION_FLAG_LOOPING);
}
}
/* Player ent */ /* Player ent */
{ {
struct entity *e = entity_alloc(); struct entity *e = entity_alloc();
@ -214,38 +153,6 @@ INTERNAL void game_update(void)
f32 meters_height = sheet->image_size.y / PIXELS_PER_UNIT; f32 meters_height = sheet->image_size.y / PIXELS_PER_UNIT;
e->draw_size = V2(meters_width, meters_height); e->draw_size = V2(meters_width, meters_height);
} }
/* Screen center ent */
{
struct entity *e = entity_alloc();
e->active = true;
e->pos = V2(0, 0);
entity_enable_prop(e, ENTITY_PROP_TEST);
//entity_enable_prop(e, ENTITY_PROP_TEST_FOLLOW_MOUSE);
e->sound_name = STR("res/sounds/test2.mp3");
e->sound_desc = MIXER_DESC(
.volume = 1.0,
.flags = MIXER_FLAG_SPATIALIZE,
.looping = true,
);
entity_enable_prop(e, ENTITY_PROP_TEST_SOUND_EMITTER);
e->draw_size = V2(0.05, 0.05);
e->texture_name = STR("res/graphics/bad.ase");
entity_enable_prop(e, ENTITY_PROP_TEXTURED);
}
{
struct entity *e = entity_alloc();
e->active = true;
e->pos = V2(0, 0);
entity_enable_prop(e, ENTITY_PROP_TEXTURED);
//entity_enable_prop(e, ENTITY_PROP_TEST);
entity_enable_prop(e, ENTITY_PROP_TEST_FOLLOW_MOUSE);
e->draw_size = V2(0.5, 0.5);
e->texture_name = STR("res/graphics/bla.ase");
entity_start_animation(e, STR("Test"), ANIMATION_FLAG_LOOPING);
}
} }
/* ========================== * /* ========================== *

View File

@ -102,13 +102,13 @@ struct string string_from_float(struct arena *arena, f64 f, u32 precision)
/* Currently this function doesn't support large floats. We should /* Currently this function doesn't support large floats. We should
* rewrite this function if this needs to change. */ * rewrite this function if this needs to change. */
b32 unrepresentable = (f >= (f64)((u64)1 << 63)); f64 max_representable = (f64)((u64)1 << 62);
b32 too_large = (f >= max_representable) || (f <= -max_representable);
b32 nan = f != f; b32 nan = f != f;
if (nan) { if (nan) {
final_len += string_cpy(arena, STR("NaN")).len; final_len += string_cpy(arena, STR("NaN")).len;
} else if (unrepresentable) { } else if (too_large) {
string_from_char(arena, '?'); string_from_char(arena, '?');
++final_len; ++final_len;
} else { } else {

View File

@ -870,7 +870,17 @@ INTERNAL LRESULT CALLBACK win32_window_proc(HWND hwnd, UINT msg, WPARAM wparam,
} }
} break; } break;
/* TODO: Mouse wheel */ case WM_MOUSEWHEEL: {
int delta = GET_WHEEL_DELTA_WPARAM(wparam);
i32 dir = delta >= 0 ? 1 : -1;
enum sys_btn button = dir >= 0 ? SYS_BTN_MWHEELUP : SYS_BTN_MWHEELDOWN;
for (i32 i = 0; i < (dir * delta); i += WHEEL_DELTA) {
/* Send a button down & button up event simultaneously */
win32_window_process_event(window, (struct sys_event) { .kind = SYS_EVENT_KIND_BUTTON_DOWN, .button = button });
win32_window_process_event(window, (struct sys_event) { .kind = SYS_EVENT_KIND_BUTTON_UP, .button = button });
}
} break;
default: { default: {
result = DefWindowProcA(hwnd, msg, wparam, lparam); result = DefWindowProcA(hwnd, msg, wparam, lparam);

View File

@ -39,6 +39,9 @@ GLOBAL struct {
struct view world_view; struct view world_view;
struct tick blend_ticks[2]; struct tick blend_ticks[2];
b32 panning;
struct v2 panning_from;
/* User thread input */ /* User thread input */
struct sys_mutex sys_events_mutex; struct sys_mutex sys_events_mutex;
struct arena sys_events_arena; struct arena sys_events_arena;
@ -51,17 +54,6 @@ GLOBAL struct {
struct v2 screen_mouse; struct v2 screen_mouse;
} L = { 0 } DEBUG_LVAR(L_user); } L = { 0 } DEBUG_LVAR(L_user);
/* ========================== *
* View
* ========================== */
INTERNAL struct mat3x3 view_get_xform(struct view view)
{
f32 scale = view.zoom * view.px_per_unit;
struct mat3x3 res = mat3x3_from_trs_pivot(v2_sub(L.screen_center, view.center), view.rot, V2(scale, scale), view.center);
return res;
}
/* ========================== * /* ========================== *
* Window -> user communication * Window -> user communication
* ========================== */ * ========================== */
@ -183,6 +175,29 @@ INTERNAL void push_game_cmds(struct game_cmd_list *list)
scratch_end(scratch); scratch_end(scratch);
} }
/* ========================== *
* View
* ========================== */
INTERNAL struct mat3x3 view_get_xform(struct view view)
{
f32 scale = view.zoom * view.px_per_unit;
struct mat3x3 res = mat3x3_from_trs_pivot(v2_sub(L.screen_center, view.center), view.rot, V2(scale, scale), view.center);
return res;
}
INTERNAL struct v2 view_inverse_point(struct view view, struct v2 p)
{
struct mat3x3 mtx_inverse = mat3x3_inverse(view_get_xform(view));
struct v3 p_inverse = mat3x3_mul_v3(mtx_inverse, V3(p.x, p.y, 1));
return V2(p_inverse.x, p_inverse.y);
}
INTERNAL struct v2 view_mouse_pos(struct view view)
{
return view_inverse_point(view, L.screen_mouse);
}
/* ========================== * /* ========================== *
* Update * Update
* ========================== */ * ========================== */
@ -213,12 +228,12 @@ INTERNAL void user_update(void)
L.screen_mouse = sys_window_get_mouse_pos(L.window); L.screen_mouse = sys_window_get_mouse_pos(L.window);
struct sys_event_array events = pull_sys_events(scratch.arena); struct sys_event_array events = pull_sys_events(scratch.arena);
/* TODO: remove this (testing) */ i32 zooms_to_apply = 0;
for (u64 i = 0; i < events.count; ++i) { for (u64 i = 0; i < events.count; ++i) {
struct sys_event *event = &events.events[i]; struct sys_event *event = &events.events[i];
b32 consumed = console_process_event(*event); /* Send event to console. Skip if consumed. */
if (consumed) { if (console_process_event(*event)) {
continue; continue;
} }
@ -226,12 +241,33 @@ INTERNAL void user_update(void)
app_quit(); app_quit();
} }
/* Move camera/view */
if (event->button == SYS_BTN_M3) {
if (event->kind == SYS_EVENT_KIND_BUTTON_DOWN) {
L.panning = true;
L.panning_from = view_mouse_pos(L.world_view);
} else if (event->kind == SYS_EVENT_KIND_BUTTON_UP) {
L.panning = false;
}
}
/* Zoom camera/view */
if (event->kind == SYS_EVENT_KIND_BUTTON_DOWN) {
if (event->button == SYS_BTN_MWHEELUP) {
++zooms_to_apply;
} else if (event->button == SYS_BTN_MWHEELDOWN) {
--zooms_to_apply;
}
}
if (event->kind == SYS_EVENT_KIND_BUTTON_UP) {
#if DEVELOPER #if DEVELOPER
/* Escape quit */ /* Escape quit */
if (event->kind == SYS_EVENT_KIND_BUTTON_UP && event->button == SYS_BTN_ESC) { if (event->button == SYS_BTN_ESC) {
app_quit(); app_quit();
} }
#endif #endif
}
/* Text */ /* Text */
if (event->kind == SYS_EVENT_KIND_TEXT) { if (event->kind == SYS_EVENT_KIND_TEXT) {
@ -247,6 +283,38 @@ INTERNAL void user_update(void)
} }
} }
/* Pan view */
if (L.panning) {
struct v2 offset = v2_sub(L.panning_from, view_mouse_pos(L.world_view));
L.world_view.center = v2_add(L.world_view.center, offset);
L.panning_from = view_mouse_pos(L.world_view);
}
/* Zoom view */
if (zooms_to_apply != 0) {
i32 dir = zooms_to_apply >= 0 ? 1 : -1;
u32 zooms_abs = zooms_to_apply >= 0 ? zooms_to_apply : -zooms_to_apply;
/* Zoom camera/view */
f32 zoom_rate = 2;
f32 new_zoom = L.world_view.zoom;
for (u32 i = 0; i < zooms_abs; ++i) {
if (dir > 0) {
new_zoom *= zoom_rate;
} else {
new_zoom *= 1.0f / zoom_rate;
}
}
struct v2 old_mouse = view_mouse_pos(L.world_view);
L.world_view.zoom = new_zoom;
struct v2 new_mouse = view_mouse_pos(L.world_view);
/* Offset view to zoom in on mouse */
struct v2 offset = v2_sub(old_mouse, new_mouse);
L.world_view.center = v2_add(L.world_view.center, offset);
}
/* Pull ticks */ /* Pull ticks */
struct interp_ticks interp_ticks = pull_interp_ticks(); struct interp_ticks interp_ticks = pull_interp_ticks();
struct tick *t0 = interp_ticks.from_tick; struct tick *t0 = interp_ticks.from_tick;
@ -282,9 +350,10 @@ INTERNAL void user_update(void)
* ========================== */ * ========================== */
{ {
//f32 thickness = 1.f / PIXELS_PER_UNIT; f32 thickness = 3.f / PIXELS_PER_UNIT / L.world_view.zoom;
f32 thickness = 5.f / PIXELS_PER_UNIT;
u32 color = RGBA(0x3f, 0x3f, 0x3f, 0xFF); u32 color = RGBA(0x3f, 0x3f, 0x3f, 0xFF);
u32 x_color = RGBA(0x3f, 0, 0, 0xFF);
u32 y_color = RGBA(0, 0x3f, 0, 0xFF);
i64 startx = -5; i64 startx = -5;
i64 starty = -5; i64 starty = -5;
@ -295,18 +364,24 @@ INTERNAL void user_update(void)
/* Draw column lines */ /* Draw column lines */
struct v2 col_ray = V2(0, rows); struct v2 col_ray = V2(0, rows);
for (i64 col = starty; col <= (starty + cols); ++col) { for (i64 col = starty; col <= (starty + cols); ++col) {
u32 line_color = color;
if (col == 0) {
line_color = y_color;
}
struct v2 pos = V2(col, starty); struct v2 pos = V2(col, starty);
draw_solid_ray(L.world_canvas, pos, col_ray, thickness, color); draw_solid_ray(L.world_canvas, pos, col_ray, thickness, line_color);
} }
struct v2 row_ray = V2(cols, 0); struct v2 row_ray = V2(cols, 0);
for (i64 row = startx; row <= (startx + rows); ++row) { for (i64 row = startx; row <= (startx + rows); ++row) {
struct v2 pos = V2(startx, row); u32 line_color = color;
draw_solid_ray(L.world_canvas, pos, row_ray, thickness, color); if (row == 0) {
line_color = x_color;
}
struct v2 pos = V2(startx, row);
draw_solid_ray(L.world_canvas, pos, row_ray, thickness, line_color);
} }
/* Draw center square */
draw_solid_rect(L.world_canvas, RECT(0, 0, 1.f / 10, 1.f / 10), RGBA_F(1, 0, 0, 0.2));
} }
@ -358,42 +433,16 @@ INTERNAL void user_update(void)
} }
} }
/* ========================== *
* Testing
* ========================== */
/* Calculate view matrices */
/* World view testing */
{
//L.world_view.center.x += (1.0 / USER_FPS) * 3;
//L.world_view.center.y += (1.0 / USER_FPS) * 3;
//L.world_view.rot += -(1.0 / USER_FPS);
//L.world_view.zoom *= 1 - ((1.0 / USER_FPS) * 0.2);
/* Draw vectors */
f32 thickness = 2;
struct v2 pos = L.screen_center;
struct mat3x3 mtx = view_get_xform(L.world_view);
struct v2 right = mat3x3_right(mtx);
struct v2 down = mat3x3_down(mtx);
draw_solid_ray(L.ui_canvas, pos, right, thickness, COLOR_RED);
draw_solid_ray(L.ui_canvas, pos, down, thickness, COLOR_GREEN);
}
/* Update listener using world view */ /* Update listener using world view */
mixer_set_listener(L.world_view.center, V2(-math_sin(L.world_view.rot), -math_cos(L.world_view.rot))); mixer_set_listener(L.world_view.center, V2(-math_sin(L.world_view.rot), -math_cos(L.world_view.rot)));
/* Get world mouse pos */ /* Send world mouse pos */
struct v2 world_mouse = { 0 }; struct v2 world_mouse = view_mouse_pos(L.world_view);
{ queue_game_cmd(&cmd_list, (struct game_cmd) {
struct mat3x3 world_view_inverse = mat3x3_inverse(view_get_xform(L.world_view)); .kind = GAME_CMD_KIND_SET_PLAYER_FOCUS,
struct v3 world_mouse_v3 = mat3x3_mul_v3(world_view_inverse, V3(L.screen_mouse.x, L.screen_mouse.y, 1)); .state = true,
world_mouse = V2(world_mouse_v3.x, world_mouse_v3.y); .pos = world_mouse
} });
/* Draw debug info */ /* Draw debug info */
{ {
@ -426,13 +475,6 @@ INTERNAL void user_update(void)
pos.y += spacing; pos.y += spacing;
} }
/* Send world mouse pos */
queue_game_cmd(&cmd_list, (struct game_cmd) {
.kind = GAME_CMD_KIND_SET_PLAYER_FOCUS,
.state = true,
.pos = world_mouse
});
/* Push game cmds */ /* Push game cmds */
push_game_cmds(&cmd_list); push_game_cmds(&cmd_list);