cvar_t cl_csqc_generatemousemoveevents = {0, "cl_csqc_generatemousemoveevents", "1", "enables calls to CSQC_InputEvent with type 2, for compliance with EXT_CSQC spec"};
extern cvar_t v_flipped;
-extern cvar_t v_yshearing;
-
-static void IN_AddToPitch(float angle)
-{
- // In Duke3D mode, aiming up/down looks like scrolling - so let input
- // modify the pitch slope instead of the pitch angle to compensate.
- // This can be turned off by v_yshearing 2.
- if (v_yshearing.integer == 1)
- {
- float tp = tanf(cl.viewangles[PITCH] * M_PI / 180);
- tp += angle * M_PI / 180;
- cl.viewangles[PITCH] = atanf(tp) * 180 / M_PI;
- }
- else
- {
- cl.viewangles[PITCH] += angle;
- }
-}
/*
================
if (in_klook.state & 1)
{
V_StopPitchDrift ();
- IN_AddToPitch(-speed*cl_pitchspeed.value * CL_KeyState (&in_forward));
- IN_AddToPitch(speed*cl_pitchspeed.value * CL_KeyState (&in_back));
+ cl.viewangles[PITCH] -= speed*cl_pitchspeed.value * CL_KeyState (&in_forward);
+ cl.viewangles[PITCH] += speed*cl_pitchspeed.value * CL_KeyState (&in_back);
}
up = CL_KeyState (&in_lookup);
down = CL_KeyState(&in_lookdown);
- IN_AddToPitch(-speed*cl_pitchspeed.value * up);
- IN_AddToPitch(-speed*cl_pitchspeed.value * down);
+ cl.viewangles[PITCH] -= speed*cl_pitchspeed.value * up;
+ cl.viewangles[PITCH] += speed*cl_pitchspeed.value * down;
if (up || down)
V_StopPitchDrift ();
cl.cmd.sidemove += m_side.value * in_mouse_x * modulatedsensitivity;
else
cl.viewangles[YAW] -= m_yaw.value * in_mouse_x * modulatedsensitivity * cl.viewzoom;
- IN_AddToPitch(m_pitch.value * in_mouse_y * modulatedsensitivity * cl.viewzoom);
+ cl.viewangles[PITCH] += m_pitch.value * in_mouse_y * modulatedsensitivity * cl.viewzoom;
}
else
{
}
if (cl.cmd.cursor_screen[1] < -1)
{
- IN_AddToPitch(m_pitch.value * (cl.cmd.cursor_screen[1] - -1) * vid.height * sensitivity.value * cl.viewzoom);
+ cl.viewangles[PITCH] += m_pitch.value * (cl.cmd.cursor_screen[1] - -1) * vid.height * sensitivity.value * cl.viewzoom;
cl.cmd.cursor_screen[1] = -1;
}
if (cl.cmd.cursor_screen[1] > 1)
{
- IN_AddToPitch(m_pitch.value * (cl.cmd.cursor_screen[1] - 1) * vid.height * sensitivity.value * cl.viewzoom);
+ cl.viewangles[PITCH] += m_pitch.value * (cl.cmd.cursor_screen[1] - 1) * vid.height * sensitivity.value * cl.viewzoom;
cl.cmd.cursor_screen[1] = 1;
}
*/
extern matrix4x4_t viewmodelmatrix_nobob;
extern matrix4x4_t viewmodelmatrix_withbob;
Matrix4x4_CreateFromQuakeEntity(&r_refdef.view.matrix, cl.csqc_vieworigin[0], cl.csqc_vieworigin[1], cl.csqc_vieworigin[2], cl.csqc_viewangles[0], cl.csqc_viewangles[1], cl.csqc_viewangles[2], 1);
- if (v_yshearing.integer)
- Matrix4x4_QuakeToDuke3D(&r_refdef.view.matrix, &r_refdef.view.matrix);
+ if (v_yshearing.value > 0)
+ Matrix4x4_QuakeToDuke3D(&r_refdef.view.matrix, &r_refdef.view.matrix, v_yshearing.value);
Matrix4x4_Copy(&viewmodelmatrix_nobob, &r_refdef.view.matrix);
Matrix4x4_ConcatScale(&viewmodelmatrix_nobob, cl_viewmodel_scale.value);
Matrix4x4_Concat(&viewmodelmatrix_withbob, &r_refdef.view.matrix, &cl.csqc_viewmodelmatrixfromengine);
}
}
-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)
{
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
}
if (up)
{
- up[0] = 0;
- up[1] = 0;
- up[2] = sgnp;
+ up[0] = sxz*cy;
+ up[1] = sxz*sy;
+ up[2] = szz;
}
}
}
/// LordHavoc: proper matrix version of AngleVectors
void AngleVectorsFLU (const vec3_t angles, vec3_t forward, vec3_t left, vec3_t up);
/// divVerent: improper matrix version of AngleVectors
-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);
/// LordHavoc: builds a [3][4] matrix
void AngleMatrix (const vec3_t angles, const vec3_t translate, vec_t matrix[][4]);
/// LordHavoc: calculates pitch/yaw/roll angles from forward and up vectors
}
}
-void Matrix4x4_QuakeToDuke3D(const matrix4x4_t *in, matrix4x4_t *out)
+void Matrix4x4_QuakeToDuke3D(const matrix4x4_t *in, matrix4x4_t *out, double maxShearAngle)
{
// Sorry - this isn't direct at all. We can't just use an alternative to
// Matrix4x4_CreateFromQuakeEntity as in some cases the input for
scaleleft = VectorNormalizeLength(left);
scaleup = VectorNormalizeLength(up);
AnglesFromVectors(angles, forward, up, false);
- AngleVectorsDuke3DFLU(angles, forward, left, up);
+ AngleVectorsDuke3DFLU(angles, forward, left, up, maxShearAngle);
VectorScale(forward, scaleforward, forward);
VectorScale(left, scaleleft, left);
VectorScale(up, scaleup, up);
// creates a matrix for a quake entity
void Matrix4x4_CreateFromQuakeEntity(matrix4x4_t *out, double x, double y, double z, double pitch, double yaw, double roll, double scale);
// creates a duke3d view matrix for a quake view matrix ;)
-void Matrix4x4_QuakeToDuke3D(const matrix4x4_t *in, matrix4x4_t *out);
+void Matrix4x4_QuakeToDuke3D(const matrix4x4_t *in, matrix4x4_t *out, double maxShearAngle);
// converts a matrix4x4 to a set of 3D vectors for the 3 axial directions, and the translate
void Matrix4x4_ToVectors(const matrix4x4_t *in, vec_t vx[3], vec_t vy[3], vec_t vz[3], vec_t t[3]);
// Prophecy camera pitchangle by Alexander "motorsep" Zubov
cvar_t chase_pitchangle = {CVAR_SAVE, "chase_pitchangle", "55", "chase cam pitch angle"};
-cvar_t v_yshearing = {0, "v_yshearing", "0", "be all out of gum (1 = vertical slope input, 2 = vertical pitch input)"};
+cvar_t v_yshearing = {0, "v_yshearing", "0", "be all out of gum (set this to the maximum angle to allow Y shearing for - try values like 75)"};
float v_dmg_time, v_dmg_roll, v_dmg_pitch;
r_refdef.view.matrix = *entrendermatrix;
Matrix4x4_AdjustOrigin(&r_refdef.view.matrix, 0, 0, clstatsviewheight);
}
- if (v_yshearing.integer)
- Matrix4x4_QuakeToDuke3D(&r_refdef.view.matrix, &r_refdef.view.matrix);
+ if (v_yshearing.value > 0)
+ Matrix4x4_QuakeToDuke3D(&r_refdef.view.matrix, &r_refdef.view.matrix, v_yshearing.value);
Matrix4x4_Copy(&viewmodelmatrix_nobob, &r_refdef.view.matrix);
Matrix4x4_ConcatScale(&viewmodelmatrix_nobob, cl_viewmodel_scale.value);
Matrix4x4_Copy(&viewmodelmatrix_withbob, &viewmodelmatrix_nobob);
viewangles[2] += v_idlescale.value * sin(cl.time*v_iroll_cycle.value) * v_iroll_level.value;
}
Matrix4x4_CreateFromQuakeEntity(&r_refdef.view.matrix, vieworg[0], vieworg[1], vieworg[2], viewangles[0], viewangles[1], viewangles[2], 1);
- if (v_yshearing.integer)
- Matrix4x4_QuakeToDuke3D(&r_refdef.view.matrix, &r_refdef.view.matrix);
+ if (v_yshearing.value > 0)
+ Matrix4x4_QuakeToDuke3D(&r_refdef.view.matrix, &r_refdef.view.matrix, v_yshearing.value);
// calculate a viewmodel matrix for use in view-attached entities
Matrix4x4_Copy(&viewmodelmatrix_nobob, &r_refdef.view.matrix);
Matrix4x4_ConcatScale(&viewmodelmatrix_nobob, cl_viewmodel_scale.value);
Matrix4x4_CreateFromQuakeEntity(&viewmodelmatrix_withbob, gunorg[0], gunorg[1], gunorg[2], gunangles[0], gunangles[1], gunangles[2], cl_viewmodel_scale.value);
- if (v_yshearing.integer)
- Matrix4x4_QuakeToDuke3D(&viewmodelmatrix_withbob, &viewmodelmatrix_withbob);
+ if (v_yshearing.value > 0)
+ Matrix4x4_QuakeToDuke3D(&viewmodelmatrix_withbob, &viewmodelmatrix_withbob, v_yshearing.value);
VectorCopy(vieworg, cl.csqc_vieworiginfromengine);
VectorCopy(viewangles, cl.csqc_viewanglesfromengine);