Nimbin[12]?SDL & Graphics / sdl_runtime_compiler / commits / 8933a91

sdl_runtime_compiler git · main

SDL3 game for running and compiling code at runtime

sdl3 c++ compiler dlopen cmake · first commit 2026-04-19 · last commit 2026-07-03 (3 months ago) · synced 3 days ago · upstream: git.ide3.de/hsnr/sdl-runtime-compiler

C++ 72.3% C 26.2%
git clone https://git.christianimmanuel.de/sdl-graphics/sdl_runtime_compiler.gitwget https://git.christianimmanuel.de/sdl-graphics/sdl_runtime_compiler/archive/sdl_runtime_compiler.tar.gz

Add move cam while in focus With Claude

Christian Immanuel · 2026-06-12 07:10 · 8933a91f0a1a7aa0ad054546a6ae5fcefd4656cf

 info.txt                     |  7 ++++
 src/states/game_state.cpp    | 90 +++++++++++++++++++++++++++++++-------------
 src/states/game_state.hpp    |  7 ++--
 src/systems/input_system.cpp |  9 ++++-
 src/systems/input_system.hpp |  8 ++--
 5 files changed, 86 insertions(+), 35 deletions(-)

diff --git a/info.txt b/info.txt
index 69e2615..657432d 100644
--- a/info.txt
+++ b/info.txt
@@ -1,4 +1,11 @@
+wall size should be monitor size
+text size match somehow
+---------------------------------
 
+zoom to wall on key press down. if other key pressed move to wall.
+    if zoom on editor "i" to start and jump?
+add jetpack?
+--------------------------------
 i need to store the big info text meshes so displaying them is not that expensive.
 
 ---------------------------------
diff --git a/src/states/game_state.cpp b/src/states/game_state.cpp
index a39e0f5..2ec1aa0 100644
--- a/src/states/game_state.cpp
+++ b/src/states/game_state.cpp
@@ -387,8 +387,8 @@ void
 GameState::on_Jump()
 {
     if (_focus_active) {
-        _ctx.player->pos       = _focus_pos;
-        _ctx.player->prev_pos  = _focus_pos;
+        _ctx.player->pos       = _ctx.camera->pos;
+        _ctx.player->prev_pos  = _ctx.camera->pos;
         _ctx.player->vel       = Vec3{0, 0, 0};
         _ctx.player->on_ground = false;
         return;
@@ -630,6 +630,8 @@ GameState::update(double dt, const GlRenderer* gl)
 
     input.look_x = 0;
     input.look_y = 0;
+    input.scroll_x = 0;
+    input.scroll_y = 0;
     input.commands.clear();
 }
 
@@ -704,16 +706,24 @@ GameState::update_Input(FrameInput& input, double dt)
     if (input.shoot && _shoot_cooldown <= 0.0)
         { FP_ZONE("handle_input.onShootO"); if (on_ShootOne()) _shoot_cooldown = 0.15; }
 
-    if (!_freelook_sys->state.active && !input.focus_wall)
+    const bool focus = input.focus_wall;
+
+    if (!_freelook_sys->state.active && !focus)
         _ctx.player->add_Look(input.look_x, input.look_y);
 
-    if (input.focus_wall)
+    _freelook_sys->update(dt);
+
+    if (focus) {
+        const bool f = input.forward, b = input.backward,
+                   l = input.left,    r = input.right;
         input.forward = input.backward = input.left = input.right = false;
+        _ctx.player->compute_Movement(input);
+        input.forward = f; input.backward = b; input.left = l; input.right = r;
+    } else {
+        _ctx.player->compute_Movement(input);
+    }
 
-    _freelook_sys->update(dt);
-    _ctx.player->compute_Movement(input);
     _ctx.camera->sync_FromPlayer(*_ctx.player);
-
     update_WallFocus(input, dt);
 }
 
@@ -1268,13 +1278,13 @@ GameState::handler_For(Wall::Role r)
 }
 
 
+
 bool
 GameState::compute_FocusTarget()
 {
     const Camera& cam = *_ctx.camera;
     const float  ws  = World::get_BoxScale<float>();
 
-    // Pick the wall plane the camera faces (nearest forward intersection).
     const Wall::Role roles[4] = { Wall::Role::Editor, Wall::Role::Program,
                                   Wall::Role::Info,   Wall::Role::Compiler };
     Wall::Role best_role = Wall::Role::Editor;
@@ -1284,7 +1294,7 @@ GameState::compute_FocusTarget()
         const Vec3 n = Wall::inward_Normal(Wall::position_Of(role));
         const Vec3 p = Wall::get_Position(role, ws);
         const double denom = cam.fwd.x*n.x + cam.fwd.y*n.y + cam.fwd.z*n.z;
-        if (denom < -1e-4) {                                   // fwd opposes inward → facing it
+        if (denom < -1e-4) {
             const double t = ((p.x-cam.pos.x)*n.x + (p.y-cam.pos.y)*n.y + (p.z-cam.pos.z)*n.z) / denom;
             if (t > 0.1 && t < best_t) { best_t = t; best_role = role; found = true; }
         }
@@ -1296,7 +1306,6 @@ GameState::compute_FocusTarget()
     const bool horiz_is_z = (tf.wall_position == Wall::Position::PosX ||
                              tf.wall_position == Wall::Position::NegX);
 
-    // Text bounding box (skip whitespace ghosts).
     double y_min=1e30, y_max=-1e30, h_min=1e30, h_max=-1e30; bool any=false;
     if (Text::Handler* hw = handler_For(best_role))
         for (const Text::Line& line : hw->get_Lines())
@@ -1314,22 +1323,21 @@ GameState::compute_FocusTarget()
     if (any) { cy=(y_min+y_max)*0.5; ch=(h_min+h_max)*0.5; text_w=h_max-h_min; text_h=y_max-y_min; }
     else     { cy=tf.position.y;     ch=0.0;               text_w=2.0;          text_h=2.0; }
 
-    // Fit distance so the text fills ~85% of the view (whichever axis binds).
-    const double fov      = (_fov_y  > 0.01f) ? static_cast<double>(_fov_y ) : (SDL_PI_D / 3.0);
-    const double asp      = (_aspect > 0.01f) ? static_cast<double>(_aspect) : 1.7;
+    const double fov      = (_fov_y  > 0.01f) ? (double)_fov_y  : (SDL_PI_D / 3.0);
+    const double asp      = (_aspect > 0.01f) ? (double)_aspect : 1.7;
     const double half_tan = SDL_tan(fov * 0.5);
     constexpr double FIT  = 0.85;
     const double d_v = (text_h * 0.5) / (FIT * half_tan);
     const double d_h = (text_w * 0.5) / (FIT * half_tan * asp);
-    const double d   = SDL_max(SDL_max(d_v, d_h), 2.0);
 
-    Vec3 centroid = tf.position;            // wall-coordinate on the normal axis
-    centroid.y = cy;
-    if (horiz_is_z) centroid.z = ch; else centroid.x = ch;
+    Vec3 center = tf.position;
+    center.y = cy;
+    if (horiz_is_z) center.z = ch; else center.x = ch;
 
-    _focus_pos     = { centroid.x + n.x*d, centroid.y + n.y*d, centroid.z + n.z*d };
-    _focus_yaw_r   = tf.yaw;                // facing the wall
-    _focus_pitch_r = 0.0;
+    _focus_center = center;
+    _focus_normal = n;
+    _focus_dist   = SDL_max(SDL_max(d_v, d_h), 2.0);
+    _focus_yaw_r  = tf.yaw;
     return true;
 }
 
@@ -1342,24 +1350,52 @@ GameState::update_WallFocus(FrameInput& input, double dt)
     if (input.focus_wall) {
         if (!_focus_active) { if (!compute_FocusTarget()) return; _focus_active = true; }
         _focus_t = SDL_min(1.0, _focus_t + dt / DUR);
+
+        const double ws = World::get_BoxScale();
+
+        // dolly (scroll wheel): wheel up = toward the wall, down = away. Clamped
+        // inside the room. Scale by distance so each notch feels proportional.
+        constexpr double DOLLY = 1.2, MIN_D = 0.6;
+        const double MAX_D = 2.0 * ws - 0.6;
+        _focus_dist -= input.scroll_y * DOLLY * (_focus_dist * 0.15 + 1.0);
+        _focus_dist  = SDL_clamp(_focus_dist, MIN_D, MAX_D);
+
+        // pan via mouse motion — smooth, any direction (look is suppressed while
+        // focused, so the mouse deltas are ours). Scale by distance so the pan
+        // feels the same in screen space whether zoomed in or out.
+        constexpr double PAN_SENS = 0.0016;
+        const double k    = PAN_SENS * _focus_dist;
+        const double rx   = SDL_cos(_focus_yaw_r);     // focus camera right axis (y = 0)
+        const double rz   = -SDL_sin(_focus_yaw_r);
+        const double pan_h = (double)input.look_x * k;
+        const double pan_v = (double)input.look_y * k;
+        const double lim   = ws - 0.5;
+
+        _focus_center.x = SDL_clamp(_focus_center.x + rx * pan_h, -lim, lim);
+        _focus_center.z = SDL_clamp(_focus_center.z + rz * pan_h, -lim, lim);
+        _focus_center.y = SDL_clamp(_focus_center.y - pan_v,      -lim, lim);
     } else {
         if (!_focus_active) return;
         _focus_t -= dt / DUR;
         if (_focus_t <= 0.0) { _focus_t = 0.0; _focus_active = false; return; }
     }
 
-    Camera& cam = *_ctx.camera;             // cam currently holds the fresh player view
-    const double s = _focus_t * _focus_t * (3.0 - 2.0 * _focus_t);   // smoothstep
+    const Vec3 focus_pos = { _focus_center.x + _focus_normal.x * _focus_dist,
+                             _focus_center.y + _focus_normal.y * _focus_dist,
+                             _focus_center.z + _focus_normal.z * _focus_dist };
+
+    Camera& cam = *_ctx.camera;
+    const double s = _focus_t * _focus_t * (3.0 - 2.0 * _focus_t);
 
-    double dyaw = _focus_yaw_r - cam.yaw_r;                  // shortest angular path
+    double dyaw = _focus_yaw_r - cam.yaw_r;
     while (dyaw >  SDL_PI_D) dyaw -= 2.0 * SDL_PI_D;
     while (dyaw < -SDL_PI_D) dyaw += 2.0 * SDL_PI_D;
 
     const double yaw_r   = cam.yaw_r   + dyaw * s;
-    const double pitch_r = cam.pitch_r + (_focus_pitch_r - cam.pitch_r) * s;
-    const Vec3   pos     = { cam.pos.x + (_focus_pos.x - cam.pos.x) * s,
-                             cam.pos.y + (_focus_pos.y - cam.pos.y) * s,
-                             cam.pos.z + (_focus_pos.z - cam.pos.z) * s };
+    const double pitch_r = cam.pitch_r + (0.0 - cam.pitch_r) * s;
+    const Vec3   pos     = { cam.pos.x + (focus_pos.x - cam.pos.x) * s,
+                             cam.pos.y + (focus_pos.y - cam.pos.y) * s,
+                             cam.pos.z + (focus_pos.z - cam.pos.z) * s };
 
     const double binrad = ConfigPhysics::binrad;
     cam.pos     = pos;
diff --git a/src/states/game_state.hpp b/src/states/game_state.hpp
index 042d05b..5ce9931 100644
--- a/src/states/game_state.hpp
+++ b/src/states/game_state.hpp
@@ -61,10 +61,11 @@ class GameState : public IState
 
     // focus wall jump START
     bool   _focus_active  { false };
-    double _focus_t       { 0.0 };       // 0 = player view, 1 = wall view
-    Vec3   _focus_pos     {};
+    double _focus_t       { 0.0 };
+    Vec3   _focus_center  {};        // look-at point on the wall plane (panned by scroll)
+    Vec3   _focus_normal  {};        // inward normal of the focused wall
+    double _focus_dist    { 4.0 };   // camera distance from the wall plane (dolly via W/S)
     double _focus_yaw_r   { 0.0 };
-    double _focus_pitch_r { 0.0 };
     float  _fov_y         { 0.0f };
     float  _aspect        { 0.0f };
     // focus wall jump END
diff --git a/src/systems/input_system.cpp b/src/systems/input_system.cpp
index 29b7857..640319a 100644
--- a/src/systems/input_system.cpp
+++ b/src/systems/input_system.cpp
@@ -11,8 +11,13 @@ InputSystem::handle_Event(Game& game, const SDL_Event& e, FrameInput& input)
 {
     switch (e.type) {
         case SDL_EVENT_MOUSE_MOTION:
-            input.look_x += (int)e.motion.xrel;
-            input.look_y += (int)e.motion.yrel;
+            input.look_x += static_cast<int>(e.motion.xrel);
+            input.look_y += static_cast<int>(e.motion.yrel);
+            break;
+
+        case SDL_EVENT_MOUSE_WHEEL:
+            input.scroll_x += static_cast<double>(e.wheel.x);
+            input.scroll_y += static_cast<double>(e.wheel.y);
             break;
 
         case SDL_EVENT_MOUSE_BUTTON_DOWN: {
diff --git a/src/systems/input_system.hpp b/src/systems/input_system.hpp
index dc23808..228c72b 100644
--- a/src/systems/input_system.hpp
+++ b/src/systems/input_system.hpp
@@ -35,7 +35,7 @@ struct FrameInput
     bool right    = false;
     bool pick     = false;
     bool shoot    = false;
-    bool focus_wall = false;     
+    bool focus_wall = false;
 
     bool normal_keys    = false;
 
@@ -46,8 +46,10 @@ struct FrameInput
     bool typing_commit = false;
     bool typing_cancel = false;
 
-    int look_x   = 0;
-    int look_y   = 0;
+    int    look_x   = 0;
+    int    look_y   = 0;
+    double scroll_x = 0.0;
+    double scroll_y = 0.0;
 
     std::string            typing_buffer;
     DynArray<int>          vim_keys;