From efdaf519284d458f8bb5944ce6b6e767f080ce3d Mon Sep 17 00:00:00 2001 From: Andrei Alexeyev Date: Sat, 3 Jul 2021 16:29:24 +0300 Subject: [PATCH] stage3d: add free camera control tool for debugging --- src/camcontrol.c | 139 +++++++++++++++++++++++++++++++++++++++++++++++ src/camcontrol.h | 31 +++++++++++ src/meson.build | 6 ++ src/video.c | 4 ++ src/video.h | 1 + 5 files changed, 181 insertions(+) create mode 100644 src/camcontrol.c create mode 100644 src/camcontrol.h diff --git a/src/camcontrol.c b/src/camcontrol.c new file mode 100644 index 00000000..9a82878e --- /dev/null +++ b/src/camcontrol.c @@ -0,0 +1,139 @@ +/* + * This software is licensed under the terms of the MIT License. + * See COPYING for further information. + * --- + * Copyright (c) 2011-2019, Lukas Weber . + * Copyright (c) 2012-2019, Andrei Alexeyev . +*/ + +#include "taisei.h" + +#include "camcontrol.h" + +#include "stagetext.h" +#include "coroutine.h" +#include "util/glm.h" +#include "video.h" + +#define CAMCTRL_MOVE_SPEED 0.1 +// for scroll wheel move speed adjustment +#define CAMCTRL_MOVE_SPEED_STEP (CAMCTRL_MOVE_SPEED * 0.25) + +#define CAMCTROL_MOUSE_SENS 0.1 + +#define CAMCTRL_PITCH_SPEED -CAMCTROL_MOUSE_SENS +#define CAMCTRL_YAW_SPEED -CAMCTROL_MOUSE_SENS +#define CAMCTRL_ROLL_SPEED 1.0 + +#define CAMCTRL_PITCH_AXIS 0 +#define CAMCTRL_YAW_AXIS 2 +#define CAMCTRL_ROLL_AXIS 1 + +#define CAMCTRL_KEY_FORWARD SDL_SCANCODE_W +#define CAMCTRL_KEY_BACK SDL_SCANCODE_S +#define CAMCTRL_KEY_LEFT SDL_SCANCODE_A +#define CAMCTRL_KEY_RIGHT SDL_SCANCODE_D +#define CAMCTRL_KEY_UP SDL_SCANCODE_R +#define CAMCTRL_KEY_DOWN SDL_SCANCODE_F + +// FIXME doesn't work that well with mouse-look… +#define CAMCTRL_KEY_ROLL_LEFT SDL_SCANCODE_Q +#define CAMCTRL_KEY_ROLL_RIGHT SDL_SCANCODE_E + +INLINE float normangle(float a) { + return a - 360.0f * floorf((a + 180.0f) / 360.0f); +} + +INLINE void addangle(float *a, float d) { + *a = normangle(*a + d); +} + +static bool mouse_event(SDL_Event *e, void *a) { + Camera3D *cam = a; + + float *pitch = cam->rot.v + CAMCTRL_PITCH_AXIS; + float *yaw = cam->rot.v + CAMCTRL_YAW_AXIS; + + addangle(pitch, CAMCTRL_PITCH_SPEED * e->motion.yrel); + addangle(yaw, CAMCTRL_YAW_SPEED * e->motion.xrel); + + return false; +} + +static bool wheel_event(SDL_Event *e, void *a) { + float delta = CAMCTRL_MOVE_SPEED_STEP; + float *move_speed = a; + *move_speed += e->wheel.y * delta; + return false; +} + +TASK(camera_control, { Camera3D *cam; }) { + Camera3D *cam = ARGS.cam; + + SDL_Window *w = NOT_NULL(video_get_window()); + SDL_SetWindowGrab(w, true); + SDL_CaptureMouse(true); + SDL_SetRelativeMouseMode(true); + SDL_EventState(SDL_MOUSEMOTION, SDL_ENABLE); + SDL_EventState(SDL_MOUSEWHEEL, SDL_ENABLE); + + float move_speed = CAMCTRL_MOVE_SPEED; + + events_register_handler( + &(EventHandler) { .proc = mouse_event, .arg = cam, .event_type = SDL_MOUSEMOTION } + ); + + events_register_handler( + &(EventHandler) { .proc = wheel_event, .arg = &move_speed, .event_type = SDL_MOUSEWHEEL } + ); + + Font *fnt = res_font("monotiny"); + StageText *txt = stagetext_add( + NULL, I*font_get_lineskip(fnt)/2, ALIGN_LEFT, fnt, RGB(1,1,1), 0, 9000000, 0, 0 + ); + + for(;;YIELD) { + int numkeys = 0; + const uint8_t *keys = SDL_GetKeyboardState(&numkeys); + + if(numkeys < 1) { + continue; + } + + float m = move_speed; + + vec3 forward = { 0, 0, -m }; + vec3 right = { m, 0, 0 }; + vec3 up = { 0, m, 0 }; + + mat4 camera_trans; + glm_mat4_identity(camera_trans); + camera3d_apply_transforms(cam, camera_trans); + glm_mat4_inv_precise(camera_trans, camera_trans); + + glm_vec3_rotate_m4(camera_trans, forward, forward); + glm_vec3_rotate_m4(camera_trans, right, right); + glm_vec3_rotate_m4(camera_trans, up, up); + + if(keys[CAMCTRL_KEY_FORWARD]) glm_vec3_add(cam->pos, forward, cam->pos); + if(keys[CAMCTRL_KEY_BACK]) glm_vec3_sub(cam->pos, forward, cam->pos); + if(keys[CAMCTRL_KEY_RIGHT]) glm_vec3_add(cam->pos, right, cam->pos); + if(keys[CAMCTRL_KEY_LEFT]) glm_vec3_sub(cam->pos, right, cam->pos); + if(keys[CAMCTRL_KEY_UP]) glm_vec3_add(cam->pos, up, cam->pos); + if(keys[CAMCTRL_KEY_DOWN]) glm_vec3_sub(cam->pos, up, cam->pos); + + float *roll = cam->rot.v + CAMCTRL_ROLL_AXIS; + if(keys[CAMCTRL_KEY_ROLL_LEFT]) addangle(roll, -CAMCTRL_ROLL_SPEED); + if(keys[CAMCTRL_KEY_ROLL_RIGHT]) addangle(roll, CAMCTRL_ROLL_SPEED); + + snprintf(txt->text, sizeof(txt->text), + "% 9.03f % 9.03f % 9.03f\n% 9.03f % 9.03f % 9.03f", + cam->pos[0], cam->pos[1], cam->pos[2], + cam->rot.v[0], cam->rot.v[1], cam->rot.v[2] + ); + } +} + +void camcontrol_init(Camera3D *cam) { + INVOKE_TASK(camera_control, cam); +} diff --git a/src/camcontrol.h b/src/camcontrol.h new file mode 100644 index 00000000..aafcdb3a --- /dev/null +++ b/src/camcontrol.h @@ -0,0 +1,31 @@ +/* + * This software is licensed under the terms of the MIT License. + * See COPYING for further information. + * --- + * Copyright (c) 2011-2019, Lukas Weber . + * Copyright (c) 2012-2019, Andrei Alexeyev . +*/ + +#ifndef IGUARD_camcontrol_h +#define IGUARD_camcontrol_h + +#include "taisei.h" + +#include "stageutils.h" + +/* + * NOTE: This is a stage background debugging facility that provides FPS-like keyboard-and-mouse + * fly-mode camera control. This code is not linked into non-developer builds, and usually is not + * referenced anywhere — it is expected to be used transiently while working on backgrounds. Which + * is why it doesn't bother with cleaning up after itself, by the way. + * + * To use it, simply call `camcontrol_init` in your background animation setup code instead of + * invoking normal animation code. For best results, disable anything that can alter the camera + * state directly. Or you can allocate a secondary camera for this purpose. + * + * See camcontrol.c for controls and adjustable parameters. + */ + +void camcontrol_init(Camera3D *cam); + +#endif // IGUARD_camcontrol_h diff --git a/src/meson.build b/src/meson.build index 08a7836f..3e18588f 100644 --- a/src/meson.build +++ b/src/meson.build @@ -102,6 +102,12 @@ taisei_src = files( 'video_postprocess.c', ) +if is_developer_build + taisei_src += files( + 'camcontrol.c' + ) +endif + if get_option('objpools') taisei_src += files( 'objectpool.c', diff --git a/src/video.c b/src/video.c index 5db06b96..51c682d1 100644 --- a/src/video.c +++ b/src/video.c @@ -525,6 +525,10 @@ void video_set_mode(uint display, uint w, uint h, bool fs, bool resizable) { } } +SDL_Window *video_get_window(void) { + return video.window; +} + void video_set_fullscreen(bool fullscreen) { video_set_mode( SDL_GetWindowDisplayIndex(video.window), diff --git a/src/video.h b/src/video.h index 4410c6a1..778b7ae5 100644 --- a/src/video.h +++ b/src/video.h @@ -86,5 +86,6 @@ VideoMode video_get_mode(uint idx, bool fullscreen); uint video_get_num_modes(bool fullscreen); VideoMode video_get_current_mode(void); double video_get_scaling_factor(void); +SDL_Window *video_get_window(void); #endif // IGUARD_video_h