From 4210ff1abacae04a23a778d059658e96908b8028 Mon Sep 17 00:00:00 2001 From: Noah Metz Date: Mon, 27 Jul 2026 22:46:18 -0600 Subject: [PATCH] Fixed camera logic and simplified --- client/src/editor.c | 167 +++++++++++++++++--------------------------- client/src/engine.c | 23 ++++-- 2 files changed, 83 insertions(+), 107 deletions(-) diff --git a/client/src/editor.c b/client/src/editor.c index 8e8e320..43c19d7 100644 --- a/client/src/editor.c +++ b/client/src/editor.c @@ -28,13 +28,16 @@ const char* ModeStrings[] = { }; typedef struct EditorDataStruct EditorData; +typedef struct ModeKeyStruct ModeKey; -typedef void(*ModeKeyCallback)(EditorData* data, ClientContext* context, int action, int mods); +typedef void(*ModeKeyCallback)(EditorData* data, ClientContext* context, ModeKey* binding, int action, int mods); -typedef struct ModeKeyStruct { +struct ModeKeyStruct { int key; - ModeKeyCallback logic; -} ModeKey; + ModeKeyCallback logic; + int axis; + float amount; +}; struct EditorDataStruct { EditorMode mode; @@ -153,86 +156,59 @@ VkResult update_mode_string(ClientContext* context, EditorData* data) { return ui_lua_call(&context->ui, &context->render, container, "set_mode", ModeStrings[data->mode]); } +// Movement/spin keys are only ever seen by editor.c when no UI element has +// focus (engine.c routes key events to the focused element first). If focus +// is gained while a key is held, its release never reaches us and the +// accumulator in move_cam/spin_cam is left stuck. Zeroing here every frame a +// UI element is focused keeps the camera from drifting forever in that case. +void editor_frame_callback(ClientContext* context) { + if(context->ui.active_container != NULL) { + context->velocity[0] = 0; + context->velocity[1] = 0; + context->velocity[2] = 0; + context->spin[0] = 0; + context->spin[1] = 0; + } +} + void editor_key_callback(ClientContext* context, int key, int action, int mods) { EditorData* data = context->app_data; for(uint32_t i = 0; i < data->mode_key_counts[data->mode]; i++) { if(data->mode_keys[data->mode][i].key == key) { - data->mode_keys[data->mode][i].logic(data, context, action, mods); + data->mode_keys[data->mode][i].logic(data, context, &data->mode_keys[data->mode][i], action, mods); return; } } for(uint32_t i = 0; i < data->mode_key_counts[MODE_NONE]; i++) { if(data->mode_keys[MODE_NONE][i].key == key) { - data->mode_keys[MODE_NONE][i].logic(data, context, action, mods); + data->mode_keys[MODE_NONE][i].logic(data, context, &data->mode_keys[MODE_NONE][i], action, mods); return; } } } -void spin_cam(ClientContext* context, int action, int mods, unsigned int axis, float amount) { - (void)mods; - if(action == GLFW_PRESS) context->spin[axis] += amount; - else if(action == GLFW_RELEASE) context->spin[axis] -= amount; -} - -void spin_cam_left(EditorData* data, ClientContext* context, int action, int mods) { - (void)data; - spin_cam(context, action, mods, 0, -1); -} - -void spin_cam_right(EditorData* data, ClientContext* context, int action, int mods) { - (void)data; - spin_cam(context, action, mods, 0, 1); -} - -void spin_cam_up(EditorData* data, ClientContext* context, int action, int mods) { - (void)data; - spin_cam(context, action, mods, 1, 1); -} - -void spin_cam_down(EditorData* data, ClientContext* context, int action, int mods) { +void spin_cam_key(EditorData* data, ClientContext* context, ModeKey* binding, int action, int mods) { (void)data; - spin_cam(context, action, mods, 1, -1); -} - -void move_cam(ClientContext* context, int action, int mods, unsigned int axis, float amount) { (void)mods; - if(action == GLFW_PRESS) context->velocity[axis] += amount; - else if(action == GLFW_RELEASE) context->velocity[axis] -= amount; -} - -void move_cam_up(EditorData* data, ClientContext* context, int action, int mods) { - (void)data; - move_cam(context, action, mods, 1, 1); -} - -void move_cam_down(EditorData* data, ClientContext* context, int action, int mods) { - (void)data; - move_cam(context, action, mods, 1, -1); + if(action == GLFW_PRESS) context->spin[binding->axis] += binding->amount; + else if(action == GLFW_RELEASE) context->spin[binding->axis] -= binding->amount; } -void move_cam_left(EditorData* data, ClientContext* context, int action, int mods) { +void move_cam_key(EditorData* data, ClientContext* context, ModeKey* binding, int action, int mods) { (void)data; - move_cam(context, action, mods, 0, -1); -} - -void move_cam_right(EditorData* data, ClientContext* context, int action, int mods) { - (void)data; - move_cam(context, action, mods, 0, 1); -} - -void move_cam_forward(EditorData* data, ClientContext* context, int action, int mods) { - (void)data; - move_cam(context, action, mods, 2, 1); + (void)mods; + if(action == GLFW_PRESS) context->velocity[binding->axis] += binding->amount; + else if(action == GLFW_RELEASE) context->velocity[binding->axis] -= binding->amount; } -void move_cam_backwards(EditorData* data, ClientContext* context, int action, int mods) { - (void)data; - move_cam(context, action, mods, 2, -1); +void editor_scroll_callback(ClientContext* context, double x, double y) { + (void)x; + context->zoom = (int32_t)y; } -void clear_mode(EditorData* data, ClientContext* context, int action, int mods) { +void clear_mode(EditorData* data, ClientContext* context, ModeKey* binding, int action, int mods) { + (void)binding; (void)mods; if(action == GLFW_PRESS) { data->mode = MODE_NONE; @@ -242,7 +218,8 @@ void clear_mode(EditorData* data, ClientContext* context, int action, int mods) } } -void enter_vertex_mode(EditorData* data, ClientContext* context, int action, int mods) { +void enter_vertex_mode(EditorData* data, ClientContext* context, ModeKey* binding, int action, int mods) { + (void)binding; (void)mods; if(action == GLFW_PRESS) { data->mode = MODE_VERTEX; @@ -252,7 +229,8 @@ void enter_vertex_mode(EditorData* data, ClientContext* context, int action, int } } -void enter_neighbor_mode(EditorData* data, ClientContext* context, int action, int mods) { +void enter_neighbor_mode(EditorData* data, ClientContext* context, ModeKey* binding, int action, int mods) { + (void)binding; (void)mods; if(action == GLFW_PRESS) { data->mode = MODE_NEIGHBOR; @@ -262,7 +240,8 @@ void enter_neighbor_mode(EditorData* data, ClientContext* context, int action, i } } -void enter_hex_mode(EditorData* data, ClientContext* context, int action, int mods) { +void enter_hex_mode(EditorData* data, ClientContext* context, ModeKey* binding, int action, int mods) { + (void)binding; (void)mods; if(action == GLFW_PRESS) { data->mode = MODE_HEX; @@ -272,7 +251,8 @@ void enter_hex_mode(EditorData* data, ClientContext* context, int action, int mo } } -void enter_region_mode(EditorData* data, ClientContext* context, int action, int mods) { +void enter_region_mode(EditorData* data, ClientContext* context, ModeKey* binding, int action, int mods) { + (void)binding; (void)mods; if(action == GLFW_PRESS) { data->mode = MODE_REGION; @@ -324,41 +304,26 @@ int main() { data->mode_keys[i] = malloc(sizeof(ModeKey)*data->mode_key_counts[i]); } - // Mode Switches - data->mode_keys[MODE_NONE][0].key = GLFW_KEY_ESCAPE; - data->mode_keys[MODE_NONE][0].logic = clear_mode; - data->mode_keys[MODE_NONE][1].key = GLFW_KEY_V; - data->mode_keys[MODE_NONE][1].logic = enter_vertex_mode; - data->mode_keys[MODE_NONE][2].key = GLFW_KEY_N; - data->mode_keys[MODE_NONE][2].logic = enter_neighbor_mode; - data->mode_keys[MODE_NONE][3].key = GLFW_KEY_H; - data->mode_keys[MODE_NONE][3].logic = enter_hex_mode; - data->mode_keys[MODE_NONE][4].key = GLFW_KEY_R; - data->mode_keys[MODE_NONE][4].logic = enter_region_mode; - - // Camera Movement - data->mode_keys[MODE_NONE][5].key = GLFW_KEY_SPACE; - data->mode_keys[MODE_NONE][5].logic = move_cam_up; - data->mode_keys[MODE_NONE][6].key = GLFW_KEY_LEFT_SHIFT; - data->mode_keys[MODE_NONE][6].logic = move_cam_down; - data->mode_keys[MODE_NONE][7].key = GLFW_KEY_LEFT; - data->mode_keys[MODE_NONE][7].logic = move_cam_left; - data->mode_keys[MODE_NONE][8].key = GLFW_KEY_RIGHT; - data->mode_keys[MODE_NONE][8].logic = move_cam_right; - data->mode_keys[MODE_NONE][9].key = GLFW_KEY_UP; - data->mode_keys[MODE_NONE][9].logic = move_cam_forward; - data->mode_keys[MODE_NONE][10].key = GLFW_KEY_DOWN; - data->mode_keys[MODE_NONE][10].logic = move_cam_backwards; - - // Camera Spin - data->mode_keys[MODE_NONE][11].key = GLFW_KEY_A; - data->mode_keys[MODE_NONE][11].logic = spin_cam_left; - data->mode_keys[MODE_NONE][12].key = GLFW_KEY_D; - data->mode_keys[MODE_NONE][12].logic = spin_cam_right; - data->mode_keys[MODE_NONE][13].key = GLFW_KEY_W; - data->mode_keys[MODE_NONE][13].logic = spin_cam_up; - data->mode_keys[MODE_NONE][14].key = GLFW_KEY_S; - data->mode_keys[MODE_NONE][14].logic = spin_cam_down; - - return run_app(data, editor_startup, NULL, NULL, editor_key_callback, NULL, NULL, NULL); + // Mode Switches + data->mode_keys[MODE_NONE][0] = (ModeKey){GLFW_KEY_ESCAPE, clear_mode, 0, 0}; + data->mode_keys[MODE_NONE][1] = (ModeKey){GLFW_KEY_V, enter_vertex_mode, 0, 0}; + data->mode_keys[MODE_NONE][2] = (ModeKey){GLFW_KEY_N, enter_neighbor_mode, 0, 0}; + data->mode_keys[MODE_NONE][3] = (ModeKey){GLFW_KEY_H, enter_hex_mode, 0, 0}; + data->mode_keys[MODE_NONE][4] = (ModeKey){GLFW_KEY_R, enter_region_mode, 0, 0}; + + // Camera Movement (axis: 0 = strafe x, 1 = up/down, 2 = forward/back) + data->mode_keys[MODE_NONE][5] = (ModeKey){GLFW_KEY_SPACE, move_cam_key, 1, 1}; + data->mode_keys[MODE_NONE][6] = (ModeKey){GLFW_KEY_LEFT_SHIFT, move_cam_key, 1, -1}; + data->mode_keys[MODE_NONE][7] = (ModeKey){GLFW_KEY_LEFT, move_cam_key, 0, -1}; + data->mode_keys[MODE_NONE][8] = (ModeKey){GLFW_KEY_RIGHT, move_cam_key, 0, 1}; + data->mode_keys[MODE_NONE][9] = (ModeKey){GLFW_KEY_UP, move_cam_key, 2, 1}; + data->mode_keys[MODE_NONE][10] = (ModeKey){GLFW_KEY_DOWN, move_cam_key, 2, -1}; + + // Camera Spin (axis: 0 = yaw, 1 = pitch) + data->mode_keys[MODE_NONE][11] = (ModeKey){GLFW_KEY_A, spin_cam_key, 0, -1}; + data->mode_keys[MODE_NONE][12] = (ModeKey){GLFW_KEY_D, spin_cam_key, 0, 1}; + data->mode_keys[MODE_NONE][13] = (ModeKey){GLFW_KEY_W, spin_cam_key, 1, 1}; + data->mode_keys[MODE_NONE][14] = (ModeKey){GLFW_KEY_S, spin_cam_key, 1, -1}; + + return run_app(data, editor_startup, editor_frame_callback, NULL, editor_key_callback, NULL, editor_scroll_callback, NULL); } diff --git a/client/src/engine.c b/client/src/engine.c index 9f6df54..7af4019 100644 --- a/client/src/engine.c +++ b/client/src/engine.c @@ -216,15 +216,26 @@ int app_main(ClientContext* context) { context->rotation[1] = 0; } - context->position[0] += - context->velocity[2]*context->move_speed*cos(context->rotation[0]) - - context->velocity[0]*context->move_speed*sin(context->rotation[0]); + float move_x = context->velocity[0]; + float move_z = context->velocity[2]; + float move_mag = sqrt(move_x*move_x + move_z*move_z); + if(move_mag > 1) { + move_x /= move_mag; + move_z /= move_mag; + } + + context->position[0] += - move_z*context->move_speed*cos(context->rotation[0]) + - move_x*context->move_speed*sin(context->rotation[0]); - context->position[2] += context->velocity[0]*context->move_speed*cos(context->rotation[0]) - - context->velocity[2]*context->move_speed*sin(context->rotation[0]); + context->position[2] += move_x*context->move_speed*cos(context->rotation[0]) + - move_z*context->move_speed*sin(context->rotation[0]); context->position[1] += context->velocity[1]*context->move_speed; - context->distance += context->zoom*delta_time*context->zoom_speed; + // context->zoom is a one-frame scroll impulse (reset to 0 each frame, + // above), not a held input like spin/velocity, so it isn't scaled by + // delta_time. + context->distance += context->zoom*context->zoom_speed; if(context->distance < 1) { context->distance = 1; } @@ -272,7 +283,7 @@ int run_app( context->rotation[1] = M_PI/4; context->distance = 25; context->spin_speed = 1.0; - context->zoom_speed = 1.0; + context->zoom_speed = 0.5; context->move_speed = 0.1; memset(&context->render, 0, sizeof(RenderContext));