diff --git a/res/graphics/sound.ase b/res/graphics/sound.ase new file mode 100644 index 00000000..20b42cb3 --- /dev/null +++ b/res/graphics/sound.ase @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:47f0ff498681bd8e240fb2187823dfd5b1726a4bde3328455379138871471c7f +size 614 diff --git a/res/sounds/test.mp3 b/res/sounds/test.mp3 new file mode 100644 index 00000000..58ecaffd --- /dev/null +++ b/res/sounds/test.mp3 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0640de834464d484a20878ccbf635d02e8a8e11b7bf1e38e5a8a6c66e7fe93b5 +size 2547394 diff --git a/src/game.c b/src/game.c index 8da41076..8ed8bda4 100644 --- a/src/game.c +++ b/src/game.c @@ -120,7 +120,7 @@ INTERNAL void game_update(void) entity_enable_prop(e, ENTITY_PROP_PLAYER_CONTROLLED); e->player_max_speed = 5.f; - e->player_acceleration = 15.0f; + e->player_acceleration = 20.0f; e->player_focus_dir = V2(0, -1); entity_enable_prop(e, ENTITY_PROP_ANIMATING); @@ -201,7 +201,30 @@ INTERNAL void game_update(void) entity_enable_prop(e, ENTITY_PROP_CAMERA_ACTIVE); e->camera_follow = player_ent->handle; e->camera_zoom = 1; + } + /* Sound ent */ + { + struct entity *e = entity_alloc(&L.world.entity_store); + e->valid = true; + e->rel_xform = XFORM_POS(V2(-3, -3)); + + struct string sprite_name = STR("res/graphics/sound.ase"); + struct sheet *sheet = sheet_load(sprite_name); + f32 meters_width = sheet->frame_size.x / PIXELS_PER_UNIT; + f32 meters_height = sheet->frame_size.y / PIXELS_PER_UNIT; + + struct v2 sprite_size = V2(meters_width, meters_height); + e->sprite_xform = xform_with_scale(XFORM_IDENT, sprite_size); + + e->sprite_name = sprite_name; + e->sprite_tint = RGBA_F(1, 1, 0, 1); + + entity_enable_prop(e, ENTITY_PROP_TEST_SOUND_EMITTER); + e->sound_name = STR("res/sounds/test.mp3"); + e->sound_desc = MIXER_DESC(.flags = MIXER_FLAG_SPATIALIZE); + + entity_enable_prop(e, ENTITY_PROP_TEST); } } @@ -306,16 +329,21 @@ INTERNAL void game_update(void) /* ENTITY_PROP_TEST */ if (entity_has_prop(ent, ENTITY_PROP_TEST)) { f32 t = ((f32)L.world.time); - struct v2 og = V2(math_cos(t), math_sin(t)); - f32 r = t * 2.f; - f32 s = 1 + (math_fabs(math_sin(t * 5)) * 3); + struct v2 og = v2_mul(V2(math_cos(t), math_sin(t)), 3); + f32 r = t + PI / 2; + struct v2 s = V2(1 + (math_fabs(math_sin(t * 5)) * 3), 1); (UNUSED)og; (UNUSED)r; (UNUSED)s; + og = v2_add(og, ent->test_start_rel_xform.og); + r += xform_get_rotation(ent->test_start_rel_xform); + s = v2_add(s, xform_get_scale(ent->test_start_rel_xform)); + + ent->rel_xform.og = og; ent->rel_xform = xform_with_rotation(ent->rel_xform, r); - ent->rel_xform = xform_with_scale(ent->rel_xform, V2(s, 1)); + ent->rel_xform = xform_with_scale(ent->rel_xform, s); } } @@ -426,7 +454,6 @@ INTERNAL void game_update(void) if (entity_has_prop(ent, ENTITY_PROP_CAMERA)) { struct entity *follow = entity_from_handle(&L.world.entity_store, ent->camera_follow); - ent->world_xform = follow->world_xform; ent->world_xform = xform_with_rotation(ent->world_xform, 0); ent->world_xform = xform_with_scale(ent->world_xform, V2(1, 1)); @@ -439,6 +466,7 @@ INTERNAL void game_update(void) if (entity_has_prop(ent, ENTITY_PROP_TEST_SOUND_EMITTER)) { struct mixer_desc desc = ent->sound_desc; desc.speed = L.world.timescale; + desc.pos = ent->world_xform.og; struct sound *sound = sound_load_async(ent->sound_name, 0); b32 played = ent->sound_handle.gen != 0; diff --git a/src/mixer.c b/src/mixer.c index 89195956..03e70e28 100644 --- a/src/mixer.c +++ b/src/mixer.c @@ -240,7 +240,7 @@ void mixer_set_listener(struct v2 pos, struct v2 dir) sys_mutex_lock(&L.mutex); { L.listener_pos = pos; - L.listener_dir = dir; + L.listener_dir = v2_norm(dir); } sys_mutex_unlock(&L.mutex); } diff --git a/src/user.c b/src/user.c index fd55d1e7..ee7ce7b2 100644 --- a/src/user.c +++ b/src/user.c @@ -19,14 +19,6 @@ #include "sound.h" #include "mixer.h" -struct view { - f32 px_per_unit; - - struct v2 center; - f32 zoom; - f32 rot; -}; - struct bind_state { b32 is_held; /* Is this bind held down this frame */ u32 num_presses; /* How many times was this bind pressed since last frame */ @@ -48,7 +40,7 @@ GLOBAL struct { struct sys_window *window; struct renderer_canvas *world_canvas; struct renderer_canvas *screen_canvas; - struct view world_view; + struct xform world_view; struct blend_tick *head_free_blend_tick; struct blend_tick *head_blend_tick; @@ -93,7 +85,7 @@ GLOBAL READONLY enum user_bind_kind g_binds[SYS_BTN_COUNT] = { [SYS_BTN_C] = USER_BIND_KIND_DEBUG_CLEAR, [SYS_BTN_F6] = USER_BIND_KIND_DEBUG_DRAW, - [SYS_BTN_F7] = USER_BIND_KIND_DEBUG_CAMERA, + [SYS_BTN_F7] = USER_BIND_KIND_DEBUG_CAMERA, [SYS_BTN_MWHEELUP] = USER_BIND_KIND_ZOOM_IN, [SYS_BTN_MWHEELDOWN] = USER_BIND_KIND_ZOOM_OUT, [SYS_BTN_M3] = USER_BIND_KIND_PAN @@ -298,49 +290,6 @@ INTERNAL void pubilsh_game_cmds(struct game_cmd_list *list) scratch_end(scratch); } -/* ========================== * - * View - * ========================== */ - -INTERNAL struct xform view_get_xform(struct view view) -{ - f32 scale = view.zoom * view.px_per_unit; - struct trs trs = TRS( - .t = v2_sub(L.screen_center, view.center), - .r = view.rot, - .s = V2(scale, scale) - ); - - struct v2 pivot = view.center; - struct xform res = XFORM_IDENT; - res = xform_translate(res, pivot); - res = xform_trs_pivot_rs(res, trs, pivot); - - return res; -} - -INTERNAL struct v2 view_xform_v2(struct view view, struct v2 p) -{ - struct xform mtx = view_get_xform(view); - return xform_mul_v2(mtx, p); -} - -INTERNAL struct v2 view_xform_basis_v2(struct view view, struct v2 p) -{ - struct xform mtx = view_get_xform(view); - return xform_basis_mul_v2(mtx, p); -} - -INTERNAL struct v2 view_inverse_xform_v2(struct view view, struct v2 p) -{ - return xform_invert_mul_v2(view_get_xform(view), p); -} - -INTERNAL struct v2 view_inverse_xform_basis_v2(struct view view, struct v2 p) -{ - return xform_basis_invert_mul_v2(view_get_xform(view), p); -} - /* ========================== * * Update * ========================== */ @@ -354,9 +303,9 @@ INTERNAL void debug_draw_xform(struct xform xf) u32 color_x = RGBA_F(1, 0, 0, 0.3); u32 color_y = RGBA_F(0, 1, 0, 0.3); - struct v2 pos = view_xform_v2(L.world_view, xf.og); - struct v2 x_ray = view_xform_basis_v2(L.world_view, xform_get_right(xf)); - struct v2 y_ray = view_xform_basis_v2(L.world_view, xform_get_up(xf)); + struct v2 pos = xform_mul_v2(L.world_view, xf.og); + struct v2 x_ray = xform_basis_mul_v2(L.world_view, xform_get_right(xf)); + struct v2 y_ray = xform_basis_mul_v2(L.world_view, xform_get_up(xf)); struct quad quad = quad_from_rect(RECT(0, 0, 1, -1)); quad = quad_mul_xform(quad_scale(quad, 0.075), xf); @@ -375,9 +324,9 @@ INTERNAL void debug_draw_movement(struct entity *ent) u32 color_vel = RGBA_F(1, 0.5, 0, 1); u32 color_acc = RGBA_F(1, 1, 0.5, 1); - struct v2 pos = view_xform_v2(L.world_view, ent->world_xform.og); - struct v2 vel_ray = view_xform_basis_v2(L.world_view, ent->velocity); - struct v2 acc_ray = view_xform_basis_v2(L.world_view, ent->acceleration); + struct v2 pos = xform_mul_v2(L.world_view, ent->world_xform.og); + struct v2 vel_ray = xform_basis_mul_v2(L.world_view, ent->velocity); + struct v2 acc_ray = xform_basis_mul_v2(L.world_view, ent->acceleration); draw_solid_arrow_ray(L.screen_canvas, pos, vel_ray, thickness, arrow_len, color_vel); draw_solid_arrow_ray(L.screen_canvas, pos, acc_ray, thickness, arrow_len, color_acc); @@ -506,6 +455,7 @@ INTERNAL void user_update(void) #endif } +#if 0 /* Text */ if (event->kind == SYS_EVENT_KIND_TEXT) { /* TODO: remove this (sound test) */ @@ -518,6 +468,7 @@ INTERNAL void user_update(void) } } } +#endif /* Update mouse pos */ if (event->kind == SYS_EVENT_KIND_MOUSE_MOVE) { @@ -577,18 +528,18 @@ INTERNAL void user_update(void) } if (L.debug_camera) { - sys_window_cursor_show(L.window); sys_window_cursor_disable_keep_in_window(L.window); + sys_window_cursor_show(L.window); /* Pan view */ if (L.bind_states[USER_BIND_KIND_PAN].is_held) { if (!L.debug_camera_panning) { - L.debug_camera_pan_start = view_inverse_xform_v2(L.world_view, L.screen_mouse); + L.debug_camera_pan_start = xform_invert_mul_v2(L.world_view, L.screen_mouse); } L.debug_camera_panning = true; - struct v2 offset = v2_sub(L.debug_camera_pan_start, view_inverse_xform_v2(L.world_view, L.screen_mouse)); - L.world_view.center = v2_add(L.world_view.center, offset); - L.debug_camera_pan_start = view_inverse_xform_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_mouse)); + 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); } else { L.debug_camera_panning = false; } @@ -599,28 +550,24 @@ INTERNAL void user_update(void) i32 dir = input_zooms >= 0 ? 1 : -1; u32 zooms_abs = input_zooms >= 0 ? input_zooms : -input_zooms; - /* Zoom camera/view */ + /* Determine zoom */ f32 zoom_rate = 2; - f32 zoom_min = 1.f / 128.f; - f32 zoom_max = 1.f * 128.f; - f32 new_zoom = L.world_view.zoom; + f32 zoom = 1; for (u32 i = 0; i < zooms_abs; ++i) { if (dir > 0) { - new_zoom *= zoom_rate; + zoom *= zoom_rate; } else { - new_zoom *= 1.0f / zoom_rate; + zoom *= 1.0f / zoom_rate; } - new_zoom = clamp_f32(new_zoom, zoom_min, zoom_max); } - struct v2 old_mouse = view_inverse_xform_v2(L.world_view, L.screen_mouse); - L.world_view.zoom = new_zoom; - struct v2 new_mouse = view_inverse_xform_v2(L.world_view, L.screen_mouse); - - /* 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); + /* Zoom to mouse */ + struct v2 world_mouse = xform_invert_mul_v2(L.world_view, L.screen_mouse); + L.world_view = xform_translate(L.world_view, world_mouse); + L.world_view = xform_scale(L.world_view, V2(zoom, zoom)); + L.world_view = xform_translate(L.world_view, v2_neg(world_mouse)); } + } else { /* Keep cursor invisible and in screen */ sys_window_cursor_hide(L.window); @@ -637,10 +584,28 @@ INTERNAL void user_update(void) f32 rot = xform_get_rotation(ent->world_xform); f32 zoom = ent->camera_zoom; zoom = zoom > 0 ? zoom : 1; - L.world_view.center = center; - L.world_view.rot = rot; - L.world_view.zoom = zoom; - L.world_mouse = view_inverse_xform_v2(L.world_view, L.screen_mouse); + + struct trs trs = TRS( + .t = v2_sub(L.screen_center, center), + .r = rot, + .s = v2_mul(V2(PIXELS_PER_UNIT, PIXELS_PER_UNIT), zoom) + ); + + struct v2 pivot = center; + L.world_view = XFORM_IDENT; + L.world_view = xform_translate(L.world_view, pivot); + L.world_view = xform_trs_pivot_rs(L.world_view, trs, pivot); + } + + /* ========================== * + * Update listener + * ========================== */ + + { + struct v2 up = V2(0, -1); + struct v2 listener_pos = xform_invert_mul_v2(L.world_view, L.screen_center); + struct v2 listener_dir = v2_norm(xform_basis_invert_mul_v2(L.world_view, up)); + mixer_set_listener(listener_pos, listener_dir); } /* ========================== * @@ -679,7 +644,7 @@ INTERNAL void user_update(void) } } - player_move_dir = view_inverse_xform_basis_v2(L.world_view, player_move_dir); /* Make move dir relative to world view */ + player_move_dir = xform_basis_invert_mul_v2(L.world_view, player_move_dir); /* Make move dir relative to world view */ player_move_dir = v2_norm(player_move_dir); struct game_cmd cmd = (struct game_cmd) { @@ -687,7 +652,7 @@ INTERNAL void user_update(void) .move_dir = player_move_dir }; if (!L.debug_camera) { - struct v2 focus_move_dir = view_inverse_xform_basis_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.screen_mouse_delta); /* Make focus relative to world view direction */ focus_move_dir = v2_mul(focus_move_dir, MOUSE_SENSITIVITY); cmd.focus_move_dir = focus_move_dir; } @@ -699,7 +664,7 @@ INTERNAL void user_update(void) * ========================== */ { - f32 thickness = 3.f / PIXELS_PER_UNIT / L.world_view.zoom; + f32 thickness = 3.f / xform_get_scale(L.world_view).x; u32 color = RGBA(0x3f, 0x3f, 0x3f, 0xFF); u32 x_color = RGBA(0x3f, 0, 0, 0xFF); u32 y_color = RGBA(0, 0x3f, 0, 0xFF); @@ -813,7 +778,7 @@ INTERNAL void user_update(void) /* Draw crosshair */ if (!L.debug_camera && entity_has_prop(ent, ENTITY_PROP_PLAYER_CONTROLLED)) { struct v2 focus_pos = v2_add(ent->world_xform.og, ent->player_focus_dir); - struct v2 focus_pos_screen = view_xform_v2(L.world_view, focus_pos); + struct v2 focus_pos_screen = xform_mul_v2(L.world_view, focus_pos); u32 tint = RGBA_F(1, 1, 1, 0.5); struct texture *t = texture_load_async(STR("res/graphics/crosshair.ase")); @@ -840,7 +805,7 @@ INTERNAL void user_update(void) f32 offset = 1; struct v2 pos = v2_add(xf.og, v2_mul(V2(0, -1), offset)); - pos = view_xform_v2(L.world_view, pos); + pos = xform_mul_v2(L.world_view, pos); pos = v2_round(pos); struct string disp_name = ent->sprite_name; @@ -877,8 +842,8 @@ INTERNAL void user_update(void) f32 thickness = 5; f32 arrow_height = 15; - struct v2 start = view_xform_v2(L.world_view, ent->world_xform.og); - struct v2 end = view_xform_v2(L.world_view, parent->world_xform.og); + struct v2 start = xform_mul_v2(L.world_view, ent->world_xform.og); + struct v2 end = xform_mul_v2(L.world_view, parent->world_xform.og); draw_solid_arrow_line(L.screen_canvas, start, end, thickness, arrow_height, color); } @@ -887,8 +852,8 @@ INTERNAL void user_update(void) u32 color = RGBA_F(0.75, 0, 0.75, 0.5); f32 thickness = 3; f32 arrow_height = 10; - struct v2 pos = view_xform_v2(L.world_view, ent->world_xform.og); - struct v2 focus_ray = view_xform_basis_v2(L.world_view, ent->player_focus_dir); + struct v2 pos = xform_mul_v2(L.world_view, ent->world_xform.og); + struct v2 focus_ray = xform_basis_mul_v2(L.world_view, ent->player_focus_dir); draw_solid_arrow_ray(L.screen_canvas, pos, focus_ray, thickness, arrow_height, color); } @@ -899,9 +864,6 @@ INTERNAL void user_update(void) /* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */ - /* 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))); - /* Debug draw info */ if (L.debug_draw) { struct temp_arena temp = arena_temp_begin(scratch.arena); @@ -922,13 +884,13 @@ INTERNAL void user_update(void) 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))); pos.y += spacing; - draw_text(L.screen_canvas, font, pos, string_format(temp.arena, STR("world_view.center: (%F, %F)"), FMT_FLOAT((f64)L.world_view.center.x), FMT_FLOAT((f64)L.world_view.center.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))); pos.y += spacing; - draw_text(L.screen_canvas, font, pos, string_format(temp.arena, STR("world_view.rot: %F"), FMT_FLOAT((f64)L.world_view.rot))); + draw_text(L.screen_canvas, font, pos, string_format(temp.arena, STR("world_view rotation: %F"), FMT_FLOAT((f64)xform_get_rotation(L.world_view)))); pos.y += spacing; - draw_text(L.screen_canvas, font, pos, string_format(temp.arena, STR("world_view.zoom: %F"), FMT_FLOAT((f64)L.world_view.zoom))); + 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; 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))); @@ -952,8 +914,8 @@ INTERNAL void user_update(void) renderer_canvas_send_to_gpu(L.screen_canvas); /* Set canvas views before presenting */ - renderer_canvas_set_view(L.world_canvas, view_get_xform(L.world_view)); - renderer_canvas_set_view(L.screen_canvas, view_get_xform((struct view) {.px_per_unit = 1, .center = L.screen_center, .rot = 0, .zoom = 1})); + renderer_canvas_set_view(L.world_canvas, L.world_view); + renderer_canvas_set_view(L.screen_canvas, XFORM_IDENT); /* Present */ i32 vsync = VSYNC_ENABLED; @@ -1005,13 +967,7 @@ void user_startup(struct sys_window *window) world_alloc(&L.world); L.world_canvas = renderer_canvas_alloc(); - L.world_view = (struct view) { - .px_per_unit = PIXELS_PER_UNIT, - - .center = V2(0, 0), - .rot = 0, - .zoom = 1 - }; + L.world_view = XFORM_TRS(.t = V2(0, 0), .r = 0, .s = V2(PIXELS_PER_UNIT, PIXELS_PER_UNIT)); L.screen_canvas = renderer_canvas_alloc();