]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - mathlib.c
v_yshearing: Make the cvar take the max angle to apply the effect to; remove the...
[xonotic/darkplaces.git] / mathlib.c
index 8f8e7b50dfa7e712209a88ad91443eb1e27e558a..a58d76e8cdfd97e4f9fd5f612bc5a03aa431bf50 100644 (file)
--- a/mathlib.c
+++ b/mathlib.c
@@ -549,35 +549,64 @@ void AngleVectorsFLU (const vec3_t angles, vec3_t forward, vec3_t left, vec3_t u
        }
 }
 
-void AngleVectorsDuke3DFLU (const vec3_t angles, vec3_t forward, vec3_t left, vec3_t up)
+void AngleVectorsDuke3DFLU (const vec3_t angles, vec3_t forward, vec3_t left, vec3_t up, double maxShearAngle)
 {
-       double angle, sr, tp, sy, cr, sgnp, cy;
+       double angle, sr, sy, cr, cy;
+       double sxx, sxz, szx, szz;
+       double cosMaxShearAngle = cos(maxShearAngle * (M_PI*2 / 360));
+       double tanMaxShearAngle = tan(maxShearAngle * (M_PI*2 / 360));
 
        angle = angles[YAW] * (M_PI*2 / 360);
        sy = sin(angle);
        cy = cos(angle);
-       angle = ANGLEMOD(angles[PITCH]);
-       // Avoid hitting tan(M_PI/2 * (2n+1))...
-       // TODO shouldn't this be a cvar?
-       // |pitch| <= 90 degrees.
-       if (angle <= 90 && angle > 80)
-               angle = 80;
-       if (angle >= 270 && angle < 280)
-               angle = 280;
-       // |pitch| > 90 degrees.
-       if (angle > 90 && angle < 100)
-               angle = 100;
-       if (angle < 270 && angle > 260)
-               angle = 260;
-       // Flip the view when "turning over".
-       sgnp = (angle > 90) && (angle < 270) ? -1.0 : 1.0;
-       angle *= (M_PI*2 / 360);
-       tp = tan(angle);
+       angle = angles[PITCH] * (M_PI*2 / 360);
+
+       // We will calculate a shear matrix pitch = [[sxx sxz][szx szz]].
+
+       if (fabs(cos(angle)) > cosMaxShearAngle)
+       {
+               // Pure shear. Keep the original sign of the coefficients.
+               sxx = 1;
+               sxz = 0;
+               szx = -tan(angle);
+               szz = 1;
+               // Covering angle per screen coordinate:
+               // d/dt arctan((sxz + t*szz) / (sxx + t*szx)) @ t=0
+               // d_angle = det(S) / (sxx*sxx + szx*szx)
+               //         = 1 / (1 + tan^2 angle)
+               //         = cos^2 angle.
+       }
+       else
+       {
+               // A mix of shear and rotation. Implementation-wise, we're
+               // looking at a capsule, and making the screen surface
+               // tangential to it... and if we get here, we're looking at the
+               // two half-spheres of the capsule (and the cylinder part is
+               // handled above).
+               double x, y, h, t, d, f;
+               h = tanMaxShearAngle;
+               x = cos(angle);
+               y = sin(angle);
+               t = h * fabs(y) + sqrt(1 - (h * x) * (h * x));
+               sxx =  x * t;
+               sxz =  y * t - h * (y > 0 ? 1.0 : -1.0);
+               szx = -y * t;
+               szz =  x * t;
+               // BUT: keep the amount of a sphere we see in pitch direction
+               // invariant.
+               // Covering angle per screen coordinate:
+               // d_angle = det(S) / (sxx*sxx + szx*szx)
+               d = (sxx * szz - sxz * szx) / (sxx * sxx + szx * szx);
+               f = cosMaxShearAngle * cosMaxShearAngle / d;
+               sxz *= f;
+               szz *= f;
+       }
+
        if (forward)
        {
-               forward[0] = cy*sgnp;
-               forward[1] = sy*sgnp;
-               forward[2] = -tp;
+               forward[0] = sxx*cy;
+               forward[1] = sxx*sy;
+               forward[2] = szx;
        }
        if (left || up)
        {
@@ -588,15 +617,15 @@ void AngleVectorsDuke3DFLU (const vec3_t angles, vec3_t forward, vec3_t left, ve
                        cr = cos(angle);
                        if (left)
                        {
-                               left[0] = cr*-sy;
-                               left[1] = cr*cy;
-                               left[2] = sr*sgnp;
+                               left[0] = sr*sxz*cy+cr*-sy;
+                               left[1] = sr*sxz*sy+cr*cy;
+                               left[2] = sr*szz;
                        }
                        if (up)
                        {
-                               up[0] = -sr*-sy;
-                               up[1] = -sr*cy;
-                               up[2] = cr*sgnp;
+                               up[0] = cr*sxz*cy+-sr*-sy;
+                               up[1] = cr*sxz*sy+-sr*cy;
+                               up[2] = cr*szz;
                        }
                }
                else
@@ -609,9 +638,9 @@ void AngleVectorsDuke3DFLU (const vec3_t angles, vec3_t forward, vec3_t left, ve
                        }
                        if (up)
                        {
-                               up[0] = 0;
-                               up[1] = 0;
-                               up[2] = sgnp;
+                               up[0] = sxz*cy;
+                               up[1] = sxz*sy;
+                               up[2] = szz;
                        }
                }
        }