*/
// mathlib.c -- math primitives
-#include <math.h>
#include "quakedef.h"
+#include <math.h>
+
vec3_t vec3_origin = {0,0,0};
float ixtable[4096];
};
#if 0
-qbyte NormalToByte(const vec3_t n)
+unsigned char NormalToByte(const vec3_t n)
{
int i, best;
float bestdistance, distance;
}
// note: uses byte partly to force unsigned for the validity check
-void ByteToNormal(qbyte num, vec3_t n)
+void ByteToNormal(unsigned char num, vec3_t n)
{
if (num < NUMVERTEXNORMALS)
VectorCopy(m_bytenormals[num], n);
VectorClear(n); // FIXME: complain?
}
-float Q_RSqrt(float number)
-{
- float y;
-
- if (number == 0.0f)
- return 0.0f;
-
- *((int *)&y) = 0x5f3759df - ((* (int *) &number) >> 1);
- return y * (1.5f - (number * 0.5f * y * y));
-}
-
// assumes "src" is normalized
void PerpendicularVector( vec3_t dst, const vec3_t src )
{
// 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);
- VectorNormalizeFast(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 )
+ (t0 * vr[2] + t1 * vu[2] + vf[2] * vf[2]) * point[2];
}
+/*-----------------------------------------------------------------*/
+
+// returns the smallest integer greater than or equal to "value", or 0 if "value" is too big
+unsigned int CeilPowerOf2(unsigned int value)
+{
+ unsigned int ceilvalue;
+
+ if (value > (1U << (sizeof(int) * 8 - 1)))
+ return 0;
+
+ ceilvalue = 1;
+ while (ceilvalue < value)
+ ceilvalue <<= 1;
+
+ return ceilvalue;
+}
+
+
/*-----------------------------------------------------------------*/
}
}
+#if 0
int BoxOnPlaneSide_Separate(const vec3_t emins, const vec3_t emaxs, const vec3_t normal, const vec_t dist)
{
switch((normal[0] < 0) | ((normal[1] < 0) << 1) | ((normal[2] < 0) << 2))
case 7: return (((normal[0] * emins[0] + normal[1] * emins[1] + normal[2] * emins[2]) >= dist) | (((normal[0] * emaxs[0] + normal[1] * emaxs[1] + normal[2] * emaxs[2]) < dist) << 1));
}
}
+#endif
void BoxPlaneCorners(const vec3_t emins, const vec3_t emaxs, const mplane_t *p, vec3_t outnear, vec3_t outfar)
{
}
}
+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)
+ {
+ 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;
+ tleft[1] = cy;
+ tleft[2] = 0;
+ tup[0] = sp*cy;
+ 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
+ VectorScale(angles, 180.0 / M_PI, angles);
+ if (flippitch)
+ angles[PITCH] *= -1;
+ if (angles[PITCH] < 0) angles[PITCH] += 360;
+ if (angles[YAW] < 0) angles[YAW] += 360;
+ if (angles[ROLL] < 0) angles[ROLL] += 360;
+
+#if 0
+{
+ // debugging code
+ vec3_t tforward, tleft, tup, nforward, nup;
+ VectorCopy(forward, nforward);
+ VectorNormalize(nforward);
+ if (up)
+ {
+ VectorCopy(up, nup);
+ VectorNormalize(nup);
+ AngleVectors(angles, tforward, tleft, tup);
+ if (VectorDistance(tforward, nforward) > 0.01 || VectorDistance(tup, nup) > 0.01)
+ {
+ Con_Printf("vectoangles('%f %f %f', '%f %f %f') = %f %f %f\n", nforward[0], nforward[1], nforward[2], nup[0], nup[1], nup[2], angles[0], angles[1], angles[2]);
+ Con_Printf("^3But that is '%f %f %f', '%f %f %f'\n", tforward[0], tforward[1], tforward[2], tup[0], tup[1], tup[2]);
+ }
+ }
+ else
+ {
+ AngleVectors(angles, tforward, tleft, tup);
+ if (VectorDistance(tforward, nforward) > 0.01)
+ {
+ Con_Printf("vectoangles('%f %f %f') = %f %f %f\n", nforward[0], nforward[1], nforward[2], angles[0], angles[1], angles[2]);
+ Con_Printf("^3But that is '%f %f %f'\n", tforward[0], tforward[1], tforward[2]);
+ }
+ }
+}
+#endif
+}
+
#if 0
void AngleMatrix (const vec3_t angles, const vec3_t translate, vec_t matrix[][4])
{
, 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;
+}
+