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) {
|
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
|
|||||||
@ -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 {
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
172
src/user.c
172
src/user.c
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
#if DEVELOPER
|
/* Move camera/view */
|
||||||
/* Escape quit */
|
if (event->button == SYS_BTN_M3) {
|
||||||
if (event->kind == SYS_EVENT_KIND_BUTTON_UP && event->button == SYS_BTN_ESC) {
|
if (event->kind == SYS_EVENT_KIND_BUTTON_DOWN) {
|
||||||
app_quit();
|
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
|
#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) {
|
||||||
|
u32 line_color = color;
|
||||||
|
if (row == 0) {
|
||||||
|
line_color = x_color;
|
||||||
|
}
|
||||||
struct v2 pos = V2(startx, row);
|
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 */
|
/* 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);
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user