mirror of
https://github.com/DrBeef/Doom3Quest.git
synced 2024-12-11 12:40:52 +00:00
526 lines
9.9 KiB
C
526 lines
9.9 KiB
C
|
/*
|
||
|
mathlib.c - internal mathlib
|
||
|
Copyright (C) 2010 Uncle Mike
|
||
|
|
||
|
This program is free software: you can redistribute it and/or modify
|
||
|
it under the terms of the GNU General Public License as published by
|
||
|
the Free Software Foundation, either version 3 of the License, or
|
||
|
(at your option) any later version.
|
||
|
|
||
|
This program is distributed in the hope that it will be useful,
|
||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
GNU General Public License for more details.
|
||
|
*/
|
||
|
|
||
|
#include "mathlib.h"
|
||
|
|
||
|
unsigned short FloatToHalf( float v )
|
||
|
{
|
||
|
unsigned int i = *((unsigned int *)&v);
|
||
|
unsigned int e = (i >> 23) & 0x00ff;
|
||
|
unsigned int m = i & 0x007fffff;
|
||
|
unsigned short h;
|
||
|
|
||
|
if( e <= 127 - 15 )
|
||
|
h = ((m | 0x00800000) >> (127 - 14 - e)) >> 13;
|
||
|
else h = (i >> 13) & 0x3fff;
|
||
|
|
||
|
h |= (i >> 16) & 0xc000;
|
||
|
|
||
|
return h;
|
||
|
}
|
||
|
|
||
|
float HalfToFloat( unsigned short h )
|
||
|
{
|
||
|
unsigned int f = (h << 16) & 0x80000000;
|
||
|
unsigned int em = h & 0x7fff;
|
||
|
|
||
|
if( em > 0x03ff )
|
||
|
{
|
||
|
f |= (em << 13) + ((127 - 15) << 23);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
unsigned int m = em & 0x03ff;
|
||
|
|
||
|
if( m != 0 )
|
||
|
{
|
||
|
unsigned int e = (em >> 10) & 0x1f;
|
||
|
|
||
|
while(( m & 0x0400 ) == 0 )
|
||
|
{
|
||
|
m <<= 1;
|
||
|
e--;
|
||
|
}
|
||
|
|
||
|
m &= 0x3ff;
|
||
|
f |= ((e + (127 - 14)) << 23) | (m << 13);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return *((float *)&f);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
=================
|
||
|
NearestPOW
|
||
|
=================
|
||
|
*/
|
||
|
int NearestPOW( int value, bool roundDown )
|
||
|
{
|
||
|
int n = 1;
|
||
|
|
||
|
if( value <= 0 ) return 1;
|
||
|
while( n < value ) n <<= 1;
|
||
|
|
||
|
if( roundDown )
|
||
|
{
|
||
|
if( n > value ) n >>= 1;
|
||
|
}
|
||
|
return n;
|
||
|
}
|
||
|
|
||
|
// remap a value in the range [A,B] to [C,D].
|
||
|
float RemapVal( float val, float A, float B, float C, float D )
|
||
|
{
|
||
|
return C + (D - C) * (val - A) / (B - A);
|
||
|
}
|
||
|
|
||
|
float ApproachVal( float target, float value, float speed )
|
||
|
{
|
||
|
float delta = target - value;
|
||
|
|
||
|
if( delta > speed )
|
||
|
value += speed;
|
||
|
else if( delta < -speed )
|
||
|
value -= speed;
|
||
|
else value = target;
|
||
|
|
||
|
return value;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
=================
|
||
|
rsqrt
|
||
|
=================
|
||
|
*/
|
||
|
float rsqrt( float number )
|
||
|
{
|
||
|
int i;
|
||
|
float x, y;
|
||
|
|
||
|
if( number == 0.0f )
|
||
|
return 0.0f;
|
||
|
|
||
|
x = number * 0.5f;
|
||
|
i = *(int *)&number; // evil floating point bit level hacking
|
||
|
i = 0x5f3759df - (i >> 1); // what the fuck?
|
||
|
y = *(float *)&i;
|
||
|
y = y * (1.5f - (x * y * y)); // first iteration
|
||
|
|
||
|
return y;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
=================
|
||
|
SinCos
|
||
|
=================
|
||
|
*/
|
||
|
void SinCos( float radians, float *sine, float *cosine )
|
||
|
{
|
||
|
#if _MSC_VER == 1200
|
||
|
_asm
|
||
|
{
|
||
|
fld dword ptr [radians]
|
||
|
fsincos
|
||
|
|
||
|
mov edx, dword ptr [cosine]
|
||
|
mov eax, dword ptr [sine]
|
||
|
|
||
|
fstp dword ptr [edx]
|
||
|
fstp dword ptr [eax]
|
||
|
}
|
||
|
#else
|
||
|
// I think, better use math.h function, instead of ^
|
||
|
#if defined (__linux__) && !defined (__ANDROID__)
|
||
|
sincosf(radians, sine, cosine);
|
||
|
#else
|
||
|
*sine = sinf(radians);
|
||
|
*cosine = cosf(radians);
|
||
|
#endif
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
#ifdef XASH_VECTORIZE_SINCOS
|
||
|
void SinCosFastVector4(float r1, float r2, float r3, float r4,
|
||
|
float *s0, float *s1, float *s2, float *s3,
|
||
|
float *c0, float *c1, float *c2, float *c3)
|
||
|
{
|
||
|
v4sf rad_vector = {r1, r2, r3, r4};
|
||
|
v4sf sin_vector, cos_vector;
|
||
|
|
||
|
sincos_ps(rad_vector, &sin_vector, &cos_vector);
|
||
|
|
||
|
*s0 = s4f_x(sin_vector);
|
||
|
*s1 = s4f_y(sin_vector);
|
||
|
*s2 = s4f_z(sin_vector);
|
||
|
*s3 = s4f_w(sin_vector);
|
||
|
|
||
|
*c0 = s4f_x(cos_vector);
|
||
|
*c1 = s4f_y(cos_vector);
|
||
|
*c2 = s4f_z(cos_vector);
|
||
|
*c3 = s4f_w(cos_vector);
|
||
|
}
|
||
|
|
||
|
void SinCosFastVector3(float r1, float r2, float r3,
|
||
|
float *s0, float *s1, float *s2,
|
||
|
float *c0, float *c1, float *c2)
|
||
|
{
|
||
|
v4sf rad_vector = {r1, r2, r3, 0};
|
||
|
v4sf sin_vector, cos_vector;
|
||
|
|
||
|
sincos_ps(rad_vector, &sin_vector, &cos_vector);
|
||
|
|
||
|
*s0 = s4f_x(sin_vector);
|
||
|
*s1 = s4f_y(sin_vector);
|
||
|
*s2 = s4f_z(sin_vector);
|
||
|
|
||
|
*c0 = s4f_x(cos_vector);
|
||
|
*c1 = s4f_y(cos_vector);
|
||
|
*c2 = s4f_z(cos_vector);
|
||
|
}
|
||
|
|
||
|
void SinCosFastVector2(float r1, float r2,
|
||
|
float *s0, float *s1,
|
||
|
float *c0, float *c1)
|
||
|
{
|
||
|
v4sf rad_vector = {r1, r2, 0, 0};
|
||
|
v4sf sin_vector, cos_vector;
|
||
|
|
||
|
sincos_ps(rad_vector, &sin_vector, &cos_vector);
|
||
|
|
||
|
*s0 = s4f_x(sin_vector);
|
||
|
*s1 = s4f_y(sin_vector);
|
||
|
|
||
|
*c0 = s4f_x(cos_vector);
|
||
|
*c1 = s4f_y(cos_vector);
|
||
|
}
|
||
|
|
||
|
void SinFastVector3(float r1, float r2, float r3,
|
||
|
float *s0, float *s1, float *s2)
|
||
|
{
|
||
|
v4sf rad_vector = {r1, r2, r3, 0};
|
||
|
v4sf sin_vector;
|
||
|
|
||
|
sin_vector = sin_ps(rad_vector);
|
||
|
|
||
|
*s0 = s4f_x(sin_vector);
|
||
|
*s1 = s4f_y(sin_vector);
|
||
|
*s2 = s4f_z(sin_vector);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
float VectorNormalizeLength2( const vec3_t v, vec3_t out )
|
||
|
{
|
||
|
float length, ilength;
|
||
|
|
||
|
length = v[0] * v[0] + v[1] * v[1] + v[2] * v[2];
|
||
|
length = sqrt( length );
|
||
|
|
||
|
if( length )
|
||
|
{
|
||
|
ilength = 1.0f / length;
|
||
|
out[0] = v[0] * ilength;
|
||
|
out[1] = v[1] * ilength;
|
||
|
out[2] = v[2] * ilength;
|
||
|
}
|
||
|
|
||
|
return length;
|
||
|
}
|
||
|
|
||
|
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 );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
=================
|
||
|
AngleVectors
|
||
|
|
||
|
=================
|
||
|
*/
|
||
|
void AngleVectors( const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up )
|
||
|
{
|
||
|
static float sr, sp, sy, cr, cp, cy;
|
||
|
|
||
|
#ifdef XASH_VECTORIZE_SINCOS
|
||
|
SinCosFastVector3( DEG2RAD(angles[YAW]), DEG2RAD(angles[PITCH]), DEG2RAD(angles[ROLL]),
|
||
|
&sy, &sp, &sr,
|
||
|
&cy, &cp, &cr);
|
||
|
#else
|
||
|
SinCos( DEG2RAD( angles[YAW] ), &sy, &cy );
|
||
|
SinCos( DEG2RAD( angles[PITCH] ), &sp, &cp );
|
||
|
SinCos( DEG2RAD( angles[ROLL] ), &sr, &cr );
|
||
|
#endif
|
||
|
|
||
|
if( forward )
|
||
|
{
|
||
|
forward[0] = cp * cy;
|
||
|
forward[1] = cp * sy;
|
||
|
forward[2] = -sp;
|
||
|
}
|
||
|
|
||
|
if( right )
|
||
|
{
|
||
|
right[0] = (-1.0f * sr * sp * cy + -1.0f * cr * -sy );
|
||
|
right[1] = (-1.0f * sr * sp * sy + -1.0f * cr * cy );
|
||
|
right[2] = (-1.0f * sr * cp);
|
||
|
}
|
||
|
|
||
|
if( up )
|
||
|
{
|
||
|
up[0] = (cr * sp * cy + -sr * -sy );
|
||
|
up[1] = (cr * sp * sy + -sr * cy );
|
||
|
up[2] = (cr * cp);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
=================
|
||
|
VectorAngles
|
||
|
|
||
|
=================
|
||
|
*/
|
||
|
void VectorAngles( const float *forward, float *angles )
|
||
|
{
|
||
|
float tmp, yaw, pitch;
|
||
|
|
||
|
if( !forward || !angles )
|
||
|
{
|
||
|
if( angles ) VectorClear( angles );
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if( forward[1] == 0 && forward[0] == 0 )
|
||
|
{
|
||
|
// fast case
|
||
|
yaw = 0;
|
||
|
if( forward[2] > 0 )
|
||
|
pitch = 90.0f;
|
||
|
else pitch = 270.0f;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
yaw = ( atan2( forward[1], forward[0] ) * 180 / M_PI );
|
||
|
if( yaw < 0 ) yaw += 360;
|
||
|
|
||
|
tmp = sqrt( forward[0] * forward[0] + forward[1] * forward[1] );
|
||
|
pitch = ( atan2( forward[2], tmp ) * 180 / M_PI );
|
||
|
if( pitch < 0 ) pitch += 360;
|
||
|
}
|
||
|
|
||
|
VectorSet( angles, pitch, yaw, 0 );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
=================
|
||
|
VectorsAngles
|
||
|
|
||
|
=================
|
||
|
*/
|
||
|
void VectorsAngles( const vec3_t forward, const vec3_t right, const vec3_t up, vec3_t angles )
|
||
|
{
|
||
|
float pitch, cpitch, yaw, roll;
|
||
|
|
||
|
pitch = -asin( forward[2] );
|
||
|
cpitch = cos( pitch );
|
||
|
|
||
|
if( fabs( cpitch ) > EQUAL_EPSILON ) // gimball lock?
|
||
|
{
|
||
|
cpitch = 1.0f / cpitch;
|
||
|
pitch = RAD2DEG( pitch );
|
||
|
yaw = RAD2DEG( atan2( forward[1] * cpitch, forward[0] * cpitch ));
|
||
|
roll = RAD2DEG( atan2( -right[2] * cpitch, up[2] * cpitch ));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pitch = forward[2] > 0 ? -90.0f : 90.0f;
|
||
|
yaw = RAD2DEG( atan2( right[0], -right[1] ));
|
||
|
roll = 180.0f;
|
||
|
}
|
||
|
|
||
|
angles[PITCH] = pitch;
|
||
|
angles[YAW] = yaw;
|
||
|
angles[ROLL] = roll;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
=================
|
||
|
InterpolateAngles
|
||
|
=================
|
||
|
*/
|
||
|
void InterpolateAngles( vec3_t start, vec3_t end, vec3_t out, float frac )
|
||
|
{
|
||
|
float d, ang1, ang2;
|
||
|
int i;
|
||
|
for( i = 0; i < 3; i++ )
|
||
|
{
|
||
|
ang1 = start[i];
|
||
|
ang2 = end[i];
|
||
|
d = ang1 - ang2;
|
||
|
|
||
|
if( d > 180.0f ) d -= 360.0f;
|
||
|
else if( d < -180.0f ) d += 360.0f;
|
||
|
|
||
|
out[i] = ang2 + d * frac;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
=================
|
||
|
BoundsIntersect
|
||
|
=================
|
||
|
*/
|
||
|
bool BoundsIntersect( const vec3_t mins1, const vec3_t maxs1, const vec3_t mins2, const vec3_t maxs2 )
|
||
|
{
|
||
|
if( mins1[0] > maxs2[0] || mins1[1] > maxs2[1] || mins1[2] > maxs2[2] )
|
||
|
return false;
|
||
|
if( maxs1[0] < mins2[0] || maxs1[1] < mins2[1] || maxs1[2] < mins2[2] )
|
||
|
return false;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
=================
|
||
|
BoundsAndSphereIntersect
|
||
|
=================
|
||
|
*/
|
||
|
bool BoundsAndSphereIntersect( const vec3_t mins, const vec3_t maxs, const vec3_t origin, float radius )
|
||
|
{
|
||
|
if( mins[0] > origin[0] + radius || mins[1] > origin[1] + radius || mins[2] > origin[2] + radius )
|
||
|
return false;
|
||
|
if( maxs[0] < origin[0] - radius || maxs[1] < origin[1] - radius || maxs[2] < origin[2] - radius )
|
||
|
return false;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//
|
||
|
// studio utils
|
||
|
//
|
||
|
/*
|
||
|
====================
|
||
|
AngleQuaternion
|
||
|
|
||
|
====================
|
||
|
*/
|
||
|
void AngleQuaternion( const vec3_t angles, vec4_t q )
|
||
|
{
|
||
|
float sr, sp, sy, cr, cp, cy;
|
||
|
|
||
|
#ifdef XASH_VECTORIZE_SINCOS
|
||
|
SinCosFastVector3( angles[2] * 0.5f, angles[1] * 0.5f, angles[0] * 0.5f,
|
||
|
&sy, &sp, &sr,
|
||
|
&cy, &cp, &cr);
|
||
|
#else
|
||
|
float angle;
|
||
|
|
||
|
angle = angles[2] * 0.5f;
|
||
|
SinCos( angle, &sy, &cy );
|
||
|
angle = angles[1] * 0.5f;
|
||
|
SinCos( angle, &sp, &cp );
|
||
|
angle = angles[0] * 0.5f;
|
||
|
SinCos( angle, &sr, &cr );
|
||
|
#endif
|
||
|
|
||
|
q[0] = sr * cp * cy - cr * sp * sy; // X
|
||
|
q[1] = cr * sp * cy + sr * cp * sy; // Y
|
||
|
q[2] = cr * cp * sy - sr * sp * cy; // Z
|
||
|
q[3] = cr * cp * cy + sr * sp * sy; // W
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
====================
|
||
|
QuaternionSlerp
|
||
|
|
||
|
====================
|
||
|
*/
|
||
|
void QuaternionSlerp( const vec4_t p, vec4_t q, float t, vec4_t qt )
|
||
|
{
|
||
|
float omega, sclp, sclq;
|
||
|
float cosom, sinom;
|
||
|
float a = 0.0f;
|
||
|
float b = 0.0f;
|
||
|
int i;
|
||
|
|
||
|
// decide if one of the quaternions is backwards
|
||
|
for( i = 0; i < 4; i++ )
|
||
|
{
|
||
|
a += (p[i] - q[i]) * (p[i] - q[i]);
|
||
|
b += (p[i] + q[i]) * (p[i] + q[i]);
|
||
|
}
|
||
|
|
||
|
if( a > b )
|
||
|
{
|
||
|
for( i = 0; i < 4; i++ )
|
||
|
{
|
||
|
q[i] = -q[i];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
cosom = p[0] * q[0] + p[1] * q[1] + p[2] * q[2] + p[3] * q[3];
|
||
|
|
||
|
if(( 1.0 + cosom ) > 0.000001f )
|
||
|
{
|
||
|
if(( 1.0f - cosom ) > 0.000001f )
|
||
|
{
|
||
|
omega = acos( cosom );
|
||
|
|
||
|
#ifdef XASH_VECTORIZE_SINCOS
|
||
|
SinFastVector3( omega, ( 1.0f - t ) * omega, t * omega,
|
||
|
&sinom, &sclp, &sclq );
|
||
|
sclp /= sinom;
|
||
|
sclq /= sinom;
|
||
|
#else
|
||
|
sinom = sin( omega );
|
||
|
sclp = sin(( 1.0f - t ) * omega ) / sinom;
|
||
|
sclq = sin( t * omega ) / sinom;
|
||
|
#endif
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
sclp = 1.0f - t;
|
||
|
sclq = t;
|
||
|
}
|
||
|
|
||
|
for( i = 0; i < 4; i++ )
|
||
|
qt[i] = sclp * p[i] + sclq * q[i];
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
qt[0] = -q[1];
|
||
|
qt[1] = q[0];
|
||
|
qt[2] = -q[3];
|
||
|
qt[3] = q[2];
|
||
|
sclp = sin(( 1.0f - t ) * ( 0.5f * M_PI ));
|
||
|
sclq = sin( t * ( 0.5f * M_PI ));
|
||
|
|
||
|
for( i = 0; i < 3; i++ )
|
||
|
qt[i] = sclp * p[i] + sclq * qt[i];
|
||
|
}
|
||
|
}
|