diff --git a/src/game.c b/src/game.c index 81764c9d..496552f5 100644 --- a/src/game.c +++ b/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); - } } /* ========================== * diff --git a/src/string.c b/src/string.c index 51396670..7dfc4100 100644 --- a/src/string.c +++ b/src/string.c @@ -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 { diff --git a/src/sys_win32.c b/src/sys_win32.c index bfe58f5b..ef09a88b 100644 --- a/src/sys_win32.c +++ b/src/sys_win32.c @@ -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); diff --git a/src/user.c b/src/user.c index 463ffe76..ccdceaaf 100644 --- a/src/user.c +++ b/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);