X-Git-Url: https://de.git.xonotic.org/?a=blobdiff_plain;ds=sidebyside;f=mathlib.c;h=a58d76e8cdfd97e4f9fd5f612bc5a03aa431bf50;hb=81804fa83299b491dc24dd5f058527165faa38da;hp=d6170d28977c27645f71b9987887854670d34916;hpb=fde75b49095458f8c405fef8c5550675f7e65761;p=xonotic%2Fdarkplaces.git diff --git a/mathlib.c b/mathlib.c index d6170d28..a58d76e8 100644 --- a/mathlib.c +++ b/mathlib.c @@ -198,30 +198,61 @@ 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); - 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 ) @@ -518,6 +549,103 @@ 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, 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) { @@ -539,9 +667,11 @@ void AnglesFromVectors (vec3_t angles, const vec3_t forward, const vec3_t up, qb { 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; @@ -551,9 +681,14 @@ void AnglesFromVectors (vec3_t angles, const vec3_t forward, const vec3_t up, qb 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 @@ -722,7 +857,7 @@ void Matrix4x4_Print(const matrix4x4_t *in) , 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); @@ -756,3 +891,12 @@ void BoxFromPoints(vec3_t mins, vec3_t maxs, int numpoints, vec_t *point3f) } } +// 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; +} +