view zooming & panning
This commit is contained in:
parent
8284923173
commit
7b2437889e
93
src/game.c
93
src/game.c
@ -139,67 +139,6 @@ INTERNAL void game_update(void)
|
||||
if (!run) {
|
||||
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 */
|
||||
{
|
||||
struct entity *e = entity_alloc();
|
||||
@ -214,38 +153,6 @@ INTERNAL void game_update(void)
|
||||
f32 meters_height = sheet->image_size.y / PIXELS_PER_UNIT;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
|
||||
@ -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
|
||||
* 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;
|
||||
|
||||
|
||||
if (nan) {
|
||||
final_len += string_cpy(arena, STR("NaN")).len;
|
||||
} else if (unrepresentable) {
|
||||
} else if (too_large) {
|
||||
string_from_char(arena, '?');
|
||||
++final_len;
|
||||
} else {
|
||||
|
||||
@ -870,7 +870,17 @@ INTERNAL LRESULT CALLBACK win32_window_proc(HWND hwnd, UINT msg, WPARAM wparam,
|
||||
}
|
||||
} 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: {
|
||||
result = DefWindowProcA(hwnd, msg, wparam, lparam);
|
||||
|
||||
172
src/user.c
172
src/user.c
@ -39,6 +39,9 @@ GLOBAL struct {
|
||||
struct view world_view;
|
||||
struct tick blend_ticks[2];
|
||||
|
||||
b32 panning;
|
||||
struct v2 panning_from;
|
||||
|
||||
/* User thread input */
|
||||
struct sys_mutex sys_events_mutex;
|
||||
struct arena sys_events_arena;
|
||||
@ -51,17 +54,6 @@ GLOBAL struct {
|
||||
struct v2 screen_mouse;
|
||||
} 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
|
||||
* ========================== */
|
||||
@ -183,6 +175,29 @@ INTERNAL void push_game_cmds(struct game_cmd_list *list)
|
||||
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
|
||||
* ========================== */
|
||||
@ -213,12 +228,12 @@ INTERNAL void user_update(void)
|
||||
L.screen_mouse = sys_window_get_mouse_pos(L.window);
|
||||
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) {
|
||||
struct sys_event *event = &events.events[i];
|
||||
|
||||
b32 consumed = console_process_event(*event);
|
||||
if (consumed) {
|
||||
/* Send event to console. Skip if consumed. */
|
||||
if (console_process_event(*event)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -226,12 +241,33 @@ INTERNAL void user_update(void)
|
||||
app_quit();
|
||||
}
|
||||
|
||||
#if DEVELOPER
|
||||
/* Escape quit */
|
||||
if (event->kind == SYS_EVENT_KIND_BUTTON_UP && event->button == SYS_BTN_ESC) {
|
||||
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
|
||||
/* Escape quit */
|
||||
if (event->button == SYS_BTN_ESC) {
|
||||
app_quit();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
struct interp_ticks interp_ticks = pull_interp_ticks();
|
||||
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 = 5.f / PIXELS_PER_UNIT;
|
||||
f32 thickness = 3.f / PIXELS_PER_UNIT / L.world_view.zoom;
|
||||
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 starty = -5;
|
||||
@ -295,18 +364,24 @@ INTERNAL void user_update(void)
|
||||
/* Draw column lines */
|
||||
struct v2 col_ray = V2(0, rows);
|
||||
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);
|
||||
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);
|
||||
for (i64 row = startx; row <= (startx + rows); ++row) {
|
||||
u32 line_color = color;
|
||||
if (row == 0) {
|
||||
line_color = x_color;
|
||||
}
|
||||
struct v2 pos = V2(startx, row);
|
||||
draw_solid_ray(L.world_canvas, pos, row_ray, thickness, color);
|
||||
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 */
|
||||
mixer_set_listener(L.world_view.center, V2(-math_sin(L.world_view.rot), -math_cos(L.world_view.rot)));
|
||||
|
||||
/* Get world mouse pos */
|
||||
struct v2 world_mouse = { 0 };
|
||||
{
|
||||
struct mat3x3 world_view_inverse = mat3x3_inverse(view_get_xform(L.world_view));
|
||||
struct v3 world_mouse_v3 = mat3x3_mul_v3(world_view_inverse, V3(L.screen_mouse.x, L.screen_mouse.y, 1));
|
||||
world_mouse = V2(world_mouse_v3.x, world_mouse_v3.y);
|
||||
}
|
||||
/* Send world mouse pos */
|
||||
struct v2 world_mouse = view_mouse_pos(L.world_view);
|
||||
queue_game_cmd(&cmd_list, (struct game_cmd) {
|
||||
.kind = GAME_CMD_KIND_SET_PLAYER_FOCUS,
|
||||
.state = true,
|
||||
.pos = world_mouse
|
||||
});
|
||||
|
||||
/* Draw debug info */
|
||||
{
|
||||
@ -426,13 +475,6 @@ INTERNAL void user_update(void)
|
||||
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(&cmd_list);
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user