// LordHavoc: like AngleVectors, but taking a forward vector instead of angles, useful!
void VectorVectors(const vec3_t forward, vec3_t right, vec3_t up)
{
- float d;
-
- right[0] = forward[2];
- right[1] = -forward[0];
- right[2] = forward[1];
-
- d = DotProduct(forward, right);
- VectorMA(right, -d, forward, right);
- VectorNormalize(right);
- CrossProduct(right, forward, up);
+ // NOTE: this is consistent to AngleVectors applied to AnglesFromVectors
+ if (forward[0] == 0 && forward[1] == 0)
+ {
+ if(forward[2] > 0)
+ {
+ VectorSet(right, 0, -1, 0);
+ VectorSet(up, -1, 0, 0);
+ }
+ else
+ {
+ VectorSet(right, 0, -1, 0);
+ VectorSet(up, 1, 0, 0);
+ }
+ }
+ else
+ {
+ right[0] = forward[1];
+ right[1] = -forward[0];
+ right[2] = 0;
+ VectorNormalize(right);
+
+ up[0] = (-forward[2]*forward[0]);
+ up[1] = (-forward[2]*forward[1]);
+ up[2] = (forward[0]*forward[0] + forward[1]*forward[1]);
+ VectorNormalize(up);
+ }
}
void VectorVectorsDouble(const double *forward, double *right, double *up)
{
- double d;
-
- right[0] = forward[2];
- right[1] = -forward[0];
- right[2] = forward[1];
-
- d = DotProduct(forward, right);
- VectorMA(right, -d, forward, right);
- VectorNormalize(right);
- CrossProduct(right, forward, up);
+ if (forward[0] == 0 && forward[1] == 0)
+ {
+ if(forward[2] > 0)
+ {
+ VectorSet(right, 0, -1, 0);
+ VectorSet(up, -1, 0, 0);
+ }
+ else
+ {
+ VectorSet(right, 0, -1, 0);
+ VectorSet(up, 1, 0, 0);
+ }
+ }
+ else
+ {
+ right[0] = forward[1];
+ right[1] = -forward[0];
+ right[2] = 0;
+ VectorNormalize(right);
+
+ up[0] = (-forward[2]*forward[0]);
+ up[1] = (-forward[2]*forward[1]);
+ up[2] = (forward[0]*forward[0] + forward[1]*forward[1]);
+ VectorNormalize(up);
+ }
}
void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point, float degrees )
}
}
+void AngleVectorsDuke3DFLU (const vec3_t angles, vec3_t forward, vec3_t left, vec3_t up, double maxShearAngle)
+{
+ 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 = 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] = sxx*cy;
+ forward[1] = sxx*sy;
+ forward[2] = szx;
+ }
+ if (left || up)
+ {
+ if (angles[ROLL])
+ {
+ angle = angles[ROLL] * (M_PI*2 / 360);
+ sr = sin(angle);
+ cr = cos(angle);
+ if (left)
+ {
+ left[0] = sr*sxz*cy+cr*-sy;
+ left[1] = sr*sxz*sy+cr*cy;
+ left[2] = sr*szz;
+ }
+ if (up)
+ {
+ up[0] = cr*sxz*cy+-sr*-sy;
+ up[1] = cr*sxz*sy+-sr*cy;
+ up[2] = cr*szz;
+ }
+ }
+ else
+ {
+ if (left)
+ {
+ left[0] = -sy;
+ left[1] = cy;
+ left[2] = 0;
+ }
+ if (up)
+ {
+ up[0] = sxz*cy;
+ up[1] = sxz*sy;
+ up[2] = szz;
+ }
+ }
+ }
+}
+
// LordHavoc: calculates pitch/yaw/roll angles from forward and up vectors
void AnglesFromVectors (vec3_t angles, const vec3_t forward, const vec3_t up, qboolean flippitch)
{
if (forward[0] == 0 && forward[1] == 0)
{
- angles[PITCH] = forward[2] > 0 ? -M_PI * 0.5 : M_PI * 0.5;
- angles[YAW] = up ? atan2(-up[1], -up[0]) : 0;
+ if(forward[2] > 0)
+ {
+ angles[PITCH] = -M_PI * 0.5;
+ angles[YAW] = up ? atan2(-up[1], -up[0]) : 0;
+ }
+ else
+ {
+ angles[PITCH] = M_PI * 0.5;
+ angles[YAW] = up ? atan2(up[1], up[0]) : 0;
+ }
angles[ROLL] = 0;
}
else
{
angles[YAW] = atan2(forward[1], forward[0]);
angles[PITCH] = -atan2(forward[2], sqrt(forward[0]*forward[0] + forward[1]*forward[1]));
+ // note: we know that angles[PITCH] is in ]-pi/2..pi/2[ due to atan2(anything, positive)
if (up)
{
vec_t cp = cos(angles[PITCH]), sp = sin(angles[PITCH]);
+ // note: we know cp > 0, due to the range angles[pitch] is in
vec_t cy = cos(angles[YAW]), sy = sin(angles[YAW]);
vec3_t tleft, tup;
tleft[0] = -sy;
tup[1] = sp*sy;
tup[2] = cp;
angles[ROLL] = -atan2(DotProduct(up, tleft), DotProduct(up, tup));
+ // for up == '0 0 1', this is
+ // angles[ROLL] = -atan2(0, cp);
+ // which is 0
}
else
angles[ROLL] = 0;
+
+ // so no up vector is equivalent to '1 0 0'!
}
// now convert radians to degrees, and make all values positive
, in->m[3][0], in->m[3][1], in->m[3][2], in->m[3][3]);
}
-int Math_atov(const char *s, vec3_t out)
+int Math_atov(const char *s, prvm_vec3_t out)
{
int i;
VectorClear(out);
}
}
+// LordHavoc: this has to be done right or you get severe precision breakdown
+int LoopingFrameNumberFromDouble(double t, int loopframes)
+{
+ if (loopframes)
+ return (int)(t - floor(t/loopframes)*loopframes);
+ else
+ return (int)t;
+}
+