From 68ba3c0f45faa71b989b0a05fd974405a21cfd7b Mon Sep 17 00:00:00 2001 From: 3gg <3gg@shellblade.net> Date: Mon, 16 Sep 2024 19:56:58 -0700 Subject: Add camera control. --- game/src/plugins/viewer.c | 113 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 100 insertions(+), 13 deletions(-) diff --git a/game/src/plugins/viewer.c b/game/src/plugins/viewer.c index f621b00..5fc4be7 100644 --- a/game/src/plugins/viewer.c +++ b/game/src/plugins/viewer.c @@ -1,5 +1,6 @@ #include "plugin.h" +#include #include #include #include @@ -27,11 +28,33 @@ static const char* BOXES = #define DEFAULT_SCENE_FILE GIRL -struct State { - Scene* scene; - Model* model; - SceneCamera* camera; -}; +static const bool RenderBoundingBoxes = false; +static const R DefaultCameraSpeed = (R)6.0; +static const R DefaultMouseSensitivity = (R)(10 * TO_RAD); +static const vec3 DefaultCameraPosition = (vec3){0, 2, 5}; + +typedef struct CameraCommand { + bool CameraMoveLeft : 1; + bool CameraMoveRight : 1; + bool CameraMoveForward : 1; + bool CameraMoveBackward : 1; +} CameraCommand; + +typedef struct CameraController { + R camera_speed; // Camera movement speed. + R mouse_sensitivity; // Controls the degree with which mouse movements + // rotate the camera. + vec2 prev_mouse_position; // Mouse position in the previous frame. + bool rotating; // When true, subsequent mouse movements cause the + // camera to rotate. +} CameraController; + +typedef struct State { + Scene* scene; + Model* model; + SceneCamera* camera; + CameraController camera_controller; +} State; /// Load the skyquad texture. static const Texture* load_environment_map(Gfx* gfx) { @@ -131,8 +154,21 @@ bool init(Game* game, State** pp_state) { if (anima) { gfx_play_animation( anima, &(AnimationPlaySettings){.name = "Walk", .loop = true}); + // TODO: Interpolate animations. + /*gfx_play_animation( + anima, + &(AnimationPlaySettings){.name = "Jumping-jack-lower", .loop = true}); + gfx_play_animation( + anima, &(AnimationPlaySettings){ + .name = "Jumping-jack-arms-mid", .loop = true});*/ } + spatial3_set_position( + &gfx_get_camera_camera(state->camera)->spatial, DefaultCameraPosition); + + state->camera_controller.camera_speed = DefaultCameraSpeed; + state->camera_controller.mouse_sensitivity = DefaultMouseSensitivity; + *pp_state = state; return true; @@ -153,19 +189,68 @@ void shutdown(Game* game, State* state) { } } +static void update_camera( + CameraController* controller, R dt, vec2 mouse_position, + CameraCommand command, Spatial3* camera) { + assert(controller); + assert(camera); + + // Translation. + const R move_x = (R)(command.CameraMoveLeft ? -1 : 0) + + (R)(command.CameraMoveRight ? 1 : 0); + const R move_y = (R)(command.CameraMoveForward ? 1 : 0) + + (R)(command.CameraMoveBackward ? -1 : 0); + const vec2 translation = + vec2_scale(vec2_make(move_x, move_y), controller->camera_speed * dt); + spatial3_move_right(camera, translation.x); + spatial3_move_forwards(camera, translation.y); + + // Rotation. + if (controller->rotating) { + const vec2 mouse_delta = + vec2_sub(mouse_position, controller->prev_mouse_position); + + const vec2 rotation = + vec2_scale(mouse_delta, controller->mouse_sensitivity * dt); + + spatial3_global_yaw(camera, -rotation.x); + spatial3_pitch(camera, -rotation.y); + } + + // Update controller state. + controller->prev_mouse_position = mouse_position; +} + void update(Game* game, State* state, double t, double dt) { assert(game); assert(state); assert(state->scene); assert(state->camera); - const vec3 orbit_point = vec3_make(0, 2, 0); - Camera* camera = gfx_get_camera_camera(state->camera); - spatial3_orbit( - &camera->spatial, orbit_point, - /*radius=*/5, - /*azimuth=*/(R)(t * 0.5), /*zenith=*/0); - spatial3_lookat(&camera->spatial, orbit_point); + double mouse_x, mouse_y; + gfx_app_get_mouse_position(&mouse_x, &mouse_y); + const vec2 mouse_position = {(R)mouse_x, (R)mouse_y}; + + const CameraCommand camera_command = (CameraCommand){ + .CameraMoveLeft = gfx_app_is_key_pressed(KeyA), + .CameraMoveRight = gfx_app_is_key_pressed(KeyD), + .CameraMoveForward = gfx_app_is_key_pressed(KeyW), + .CameraMoveBackward = gfx_app_is_key_pressed(KeyS), + }; + + state->camera_controller.rotating = gfx_app_is_mouse_button_pressed(LMB); + + update_camera( + &state->camera_controller, (R)dt, mouse_position, camera_command, + &gfx_get_camera_camera(state->camera)->spatial); + + // const vec3 orbit_point = vec3_make(0, 2, 0); + // Camera* camera = gfx_get_camera_camera(state->camera); + // spatial3_orbit( + // &camera->spatial, orbit_point, + // /*radius=*/5, + // /*azimuth=*/(R)(t * 0.5), /*zenith=*/0); + // spatial3_lookat(&camera->spatial, orbit_point); gfx_update(state->scene, state->camera, (R)t); } @@ -261,7 +346,9 @@ void render(const Game* game, const State* state) { .scene = state->scene, .camera = state->camera}); - render_bounding_boxes(game, state); + if (RenderBoundingBoxes) { + render_bounding_boxes(game, state); + } } void resize(Game* game, State* state, int width, int height) { -- cgit v1.2.3