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)
{
}
}
}
- 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)
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")));