]> git.rm.cloudns.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Implement zoom scrolling
authork9er <k9wolf@pm.me>
Sun, 19 Jan 2025 18:54:07 +0000 (18:54 +0000)
committerterencehill <piuntn@gmail.com>
Sun, 19 Jan 2025 18:54:07 +0000 (18:54 +0000)
qcsrc/client/main.qc
qcsrc/client/view.qc
qcsrc/client/view.qh
qcsrc/menu/xonotic/dialog_settings_game_view.qc
xonotic-client.cfg

index 568f0f5a0a0b30739b0399c6e7c70d95bc1dd961..54299e524568286c4a32f4e5147cb5788b0125b9 100644 (file)
@@ -493,6 +493,10 @@ float CSQC_InputEvent(int bInputType, float nPrimary, float nSecondary)
        if (override)
                return true;
 
+       override |= View_InputEvent(bInputType, nPrimary, nSecondary);
+       if (override)
+               return true;
+
        override |= HUD_Panel_Chat_InputEvent(bInputType, nPrimary, nSecondary);
 
        override |= QuickMenu_InputEvent(bInputType, nPrimary, nSecondary);
index 583f167dc7569f8fbb62cd628d478f1f3ae395d9..4911dc4168fbdbfd6603fbbf4599fbc8fcb64ccc 100644 (file)
@@ -421,22 +421,9 @@ STATIC_INIT(fpscounter_init)
        showfps_prevfps_time = currentTime; // we must initialize it to avoid an instant low frame sending
 }
 
-float avgspeed;
-vector GetCurrentFov(float fov)
+bool IsZooming()
 {
-       float zoomsensitivity, zoomspeed, zoomfactor, zoomdir;
-       float velocityzoom, curspeed;
-       vector v;
-
-       zoomsensitivity = autocvar_cl_zoomsensitivity;
-       zoomfactor = autocvar_cl_zoomfactor;
-       if(zoomfactor < 1 || zoomfactor > 30)
-               zoomfactor = 2.5;
-       zoomspeed = autocvar_cl_zoomspeed;
-       if (zoomspeed >= 0 && (zoomspeed < 0.5 || zoomspeed > 16))
-               zoomspeed = 3.5;
-
-       zoomdir = button_zoom;
+       bool zoomdir = button_zoom;
 
        if(hud == HUD_NORMAL && !spectatee_status)
        {
@@ -453,38 +440,109 @@ vector GetCurrentFov(float fov)
                        }
                }
        }
-       if(spectatee_status > 0 || isdemo())
+
+       if(spectatorbutton_zoom && (spectatee_status > 0 || isdemo()))
+               zoomdir = !zoomdir;
+
+       return zoomdir;
+}
+
+const float MAX_ZOOMFACTOR = 30;
+float zoomscroll_factor;
+float zoomscroll_factor_target;
+void ZoomScroll(float nPrimary)
+{
+       bool zoomin = (nPrimary == K_MWHEELUP);
+       if (autocvar_cl_zoomscroll_scale < 0)
+               zoomin = !zoomin;
+
+       // allow negatives so that players can scroll the other way, biggest change allowed is +100%
+       float zoomscroll_scale = 1 + min(fabs(autocvar_cl_zoomscroll_scale), 1);
+
+       if (zoomin)
+               zoomscroll_factor_target = min(MAX_ZOOMFACTOR, zoomscroll_factor_target * zoomscroll_scale);
+       else
+               zoomscroll_factor_target = max(1, zoomscroll_factor_target / zoomscroll_scale);
+}
+
+bool View_InputEvent(int bInputType, float nPrimary, float nSecondary)
+{
+       if (bInputType == 2 || bInputType == 3)
+               return false;
+
+       // at this point bInputType can only be 0 or 1 (key pressed or released)
+       bool key_pressed = (bInputType == 0);
+
+       if (nPrimary == K_MWHEELUP || nPrimary == K_MWHEELDOWN)
        {
-               if(spectatorbutton_zoom)
-               {
-                       if(zoomdir)
-                               zoomdir = 0;
-                       else
-                               zoomdir = 1;
-               }
-               // fteqcc failed twice here already, don't optimize this
+               if (!autocvar_cl_zoomscroll || autocvar_cl_zoomscroll_scale == 0)
+                       return false; // zoom scroll disabled
+               if (!IsZooming())
+                       return false;
+               if (key_pressed)
+                       ZoomScroll(nPrimary);
+               return true;
        }
 
-       if(zoomdir) { zoomin_effect = 0; }
+       return false;
+}
+
+float avgspeed;
+vector GetCurrentFov(float fov)
+{
+       float zoomsensitivity, zoomspeed, zoomfactor, zoomdir;
+       float velocityzoom, curspeed;
+       vector v;
+
+       zoomdir = IsZooming();
+
+       zoomspeed = autocvar_cl_zoomspeed;
+       if(zoomspeed >= 0 && (zoomspeed < 0.5 || zoomspeed > 16))
+               zoomspeed = 3.5;
+       zoomsensitivity = autocvar_cl_zoomsensitivity;
+
+       zoomfactor = autocvar_cl_zoomfactor;
+       if(zoomfactor < 1 || zoomfactor > MAX_ZOOMFACTOR)
+               zoomfactor = 2.5;
+
+       if(zoomdir)
+               zoomin_effect = 0;
 
        if (spectatee_status > 0 && STAT(CAMERA_SPECTATOR) == 2)
-       {
                current_viewzoom = 1;
-       }
        else if (camera_active)
-       {
                current_viewzoom = min(1, current_viewzoom + drawframetime);
-       }
        else if(autocvar_cl_spawnzoom && zoomin_effect)
        {
-               float spawnzoomfactor = bound(1, autocvar_cl_spawnzoom_factor, 30);
+               float spawnzoomfactor = bound(1, autocvar_cl_spawnzoom_factor, MAX_ZOOMFACTOR);
 
                current_viewzoom += (autocvar_cl_spawnzoom_speed * (spawnzoomfactor - current_viewzoom) * drawframetime);
                current_viewzoom = bound(1 / spawnzoomfactor, current_viewzoom, 1);
-               if(current_viewzoom == 1) { zoomin_effect = 0; }
+               if(current_viewzoom == 1)
+                       zoomin_effect = 0;
        }
        else
        {
+               // initialize zoom scroll in the first frame / reset zoom scroll when fully zoomed out
+               if (!zoomscroll_factor || (current_viewzoom == 1 && !zoomdir))
+               {
+                       zoomscroll_factor_target = zoomfactor;
+                       zoomscroll_factor = zoomfactor;
+               }
+               if (zoomscroll_factor != zoomscroll_factor_target)
+               {
+                       if (fabs(zoomscroll_factor - zoomscroll_factor_target) < 0.001 || autocvar_cl_zoomscroll_speed < 0) // snap
+                               zoomscroll_factor = zoomscroll_factor_target;
+                       else if (autocvar_cl_zoomscroll_speed != 0)
+                       {
+                               // NOTE: this averaging formula is frametime independent
+                               float avg_time = 1 / autocvar_cl_zoomscroll_speed;
+                               float frac = 1 - exp(-drawframetime / max(0.001, avg_time));
+                               zoomscroll_factor = frac * zoomscroll_factor_target + (1 - frac) * zoomscroll_factor;
+                       }
+               }
+               zoomfactor = zoomscroll_factor;
+
                if(zoomspeed < 0) // instant zoom
                {
                        if(zoomdir)
index cd33ebfb6a1201e41f9caa706209c1cc2fcb3d92..6e370da737a0dd3742ed7f8c3e09f6a4dc9db522 100644 (file)
@@ -32,6 +32,9 @@ float autocvar_cl_velocityzoom_time;
 float autocvar_cl_zoomfactor;
 float autocvar_cl_zoomsensitivity;
 float autocvar_cl_zoomspeed;
+bool autocvar_cl_zoomscroll = 1;
+float autocvar_cl_zoomscroll_scale = 0.2;
+float autocvar_cl_zoomscroll_speed = 16;
 float autocvar_fov;
 float autocvar_hud_colorflash_alpha;
 bool autocvar_hud_contents;
@@ -127,3 +130,5 @@ float blurtest_time0, blurtest_time1, blurtest_radius, blurtest_power;
 
 float intermission_time;
 float game_stopped_time;
+
+bool View_InputEvent(int bInputType, float nPrimary, float nSecondary);
index b4c170280c652febf3435542d8bd57073f81601f..5e667aa1cad8b3dc842b7b2b9e9566c3527ca2a5 100644 (file)
@@ -95,6 +95,30 @@ void XonoticGameViewSettingsTab_fill(entity me)
                me.TD(me, 1, 1, e = makeXonoticTextLabel(0, ZCTX(_("ZOOM^Zoom sensitivity:"))));
                me.TD(me, 1, 2, e = makeXonoticSlider_T(0, 1, 0.1, "cl_zoomsensitivity",
                        _("How zoom changes sensitivity, from 0 (lower sensitivity) to 1 (no sensitivity change)")));
+       me.TR(me);
+               me.TD(me, 1, 1, e = makeXonoticCheckBox(0, "cl_zoomscroll", _("Zoom scrolling")));
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Scale:")));
+                       setDependent(e, "cl_zoomscroll", 1, 1);
+               me.TD(me, 1, 2, e = makeXonoticSlider(-1, 1, 0.1, "cl_zoomscroll_scale")); // would be better if this could skip 0
+                       setDependent(e, "cl_zoomscroll", 1, 1);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Speed:")));
+                       setDependent(e, "cl_zoomscroll", 1, 1);
+               me.TD(me, 1, 2, e = makeXonoticTextSlider("cl_zoomscroll_speed"));
+                       e.addValue(e, "2", "2"); // Samual: for() loop doesn't work here, even though it would make sense.
+                       e.addValue(e, "4", "4");
+                       e.addValue(e, "6", "6");
+                       e.addValue(e, "8", "8");
+                       e.addValue(e, "10", "10");
+                       e.addValue(e, "12", "12");
+                       e.addValue(e, "14", "14");
+                       e.addValue(e, "16", "16");
+                       e.addValue(e, ZCTX(_("ZOOM^Instant")), "-1");
+                       e.configureXonoticTextSliderValues(e);
+                       setDependent(e, "cl_zoomscroll", 1, 1);
        me.TR(me);
        me.TR(me);
                me.TD(me, 1, 1, e = makeXonoticCheckBox(0, "cl_velocityzoom_enabled", _("Velocity zoom")));
index 5b620f00702179549211129f7e47e565eeff64eb..e85cecc61398ca8f9d6f2e60bd8b26b96fd65e73 100644 (file)
@@ -61,6 +61,9 @@ seta cl_spawnzoom_factor 2 "factor of zoom while spawning"
 seta cl_zoomfactor 5   "how much +zoom will zoom (1-30)"
 seta cl_zoomspeed 8    "how fast +zoom will zoom (0.5-16), negative values mean instant zoom"
 seta cl_zoomsensitivity 0      "how zoom changes sensitivity; \"0\" = weakest, \"1\" = strongest"
+seta cl_zoomscroll 1 "allow scrolling to zoom in or out further while holding +zoom"
+seta cl_zoomscroll_scale 0.2 "percentage of zoom change on scroll (maximum 1, negative values change the scroll direction)"
+seta cl_zoomscroll_speed 16 "zoom scroll speed, negative values mean instant change when scrolling"
 
 seta cl_unpress_zoom_on_spawn 1 "automatically unpress zoom when you spawn"
 seta cl_unpress_zoom_on_death 1 "automatically unpress zoom when you die (and don't allow zoom again while dead)"