3dcam-headers/src/math.c

192 lines
6.5 KiB
C

#include <math.h>
// Stolen from grumpycoder
// this is from here : https://github.com/grumpycoders/Balau/blob/master/tests/test-Handles.cc#L20-L102
// precalc costable
static int m_cosTable[512];
static const unsigned int DC_2PI = 2048;
static const unsigned int DC_PI = 1024;
static const unsigned int DC_PI2 = 512;
// f(n) = cos(n * 2pi / 2048) <- 2048 is == DC_2PI value
// f(n) = 2 * f(1) * f(n - 1) - f(n - 2)
void generateTable(void){
m_cosTable[0] = 16777216; // 2^24 * cos(0 * 2pi / 2048) => 2^24 * 1 = 2^24 : here, 2^24 defines the precision we want after the decimal point
static const long long C = 16777137; // 2^24 * cos(1 * 2pi / 2048) = C = f(1);
m_cosTable[1] = C;
for (int i = 2; i < 511; i++){
m_cosTable[i] = ((C * m_cosTable[i - 1]) >> 23) - m_cosTable[i - 2];
}
for (int i = 0; i < 512; i++){
m_cosTable[i] >>= 12;
}
};
int ncos(unsigned int t) {
t %= DC_2PI;
int r;
if (t < DC_PI2) {
r = m_cosTable[t];
} else if (t < DC_PI) {
r = -m_cosTable[DC_PI - 1 - t];
} else if (t < (DC_PI + DC_PI2)) {
r = -m_cosTable[t - DC_PI];
} else {
r = m_cosTable[DC_2PI - 1 - t];
};
return r;
};
// sin(x) = cos(x - pi / 2)
int nsin(unsigned int t) {
t %= DC_2PI;
if (t < DC_PI2){
return ncos(t + DC_2PI - DC_PI2);
};
return ncos(t - DC_PI2);
};
// https://github.com/Arsunt/TR2Main/blob/411cacb35914c616cb7960c0e677e00c71c7ee88/3dsystem/phd_math.cpp#L432
long long patan(long x, long y){
long long result;
int swapBuf;
int flags = 0;
// if either x or y are 0, return 0
if( x == 0 && y == 0){
return 0;
}
if( x < 0 ) {
flags |= 4;
x = -x;
}
if ( y < 0 ) {
flags |= 2;
y = -y;
}
if ( y > x ) {
flags |= 1;
SWAP(x, y ,swapBuf);
}
result = AtanBaseTable[flags] + AtanAngleTable[0x800 * y / x];
if ( result < 0 ){
result = -result;
return result;
}
};
u_int psqrt(u_int n){
u_int result = 0;
u_int base = 0x40000000;
u_int basedResult;
for( ; base != 0; base >>= 2 ) {
for( ; base != 0; base >>= 2 ) {
basedResult = base + result;
result >>= 1;
if( basedResult > n ) {
break;
}
n -= basedResult;
result |= base;
}
}
return result;
};
// From : https://github.com/grumpycoders/pcsx-redux/blob/7438e9995833db5bc1e14da735bbf9dc78300f0b/src/mips/shell/math.h
int32_t dMul(int32_t a, int32_t b) {
long long r = a;
r *= b;
return r >> 24;
};
// standard lerp function
// s = source, an arbitrary number up to 2^24
// d = destination, an arbitrary number up to 2^24
// p = position, a number between 0 and 256, inclusive
// p = 0 means output = s
// p = 256 means output = d
uint32_t lerpU(uint32_t start, uint32_t dest, unsigned pos) {
return (start * (256 - pos) + dest * pos) >> 8;
};
int32_t lerpS(int32_t start, int32_t dest, unsigned pos) {
return (start * (256 - pos) + dest * pos) >> 8;
};
// start, dest and pos have to be << x, then the result has to be >> x where x defines precision:
// precision = 2^24 - 2^x
// << x : 0 < pos < precision
// https://discord.com/channels/642647820683444236/646765703143227394/811318550978494505
// my angles are between 0 and 2048 (full circle), so 2^11 for the range of angles; with numbers on a 8.24 representation,
// a 1.0 angle (or 2pi) means it's 2^24, so to "convert" my angles from 8.24 to my internal discrete cos, I only have to shift by 13
int32_t lerpD(int32_t start, int32_t dest, int32_t pos) {
return dMul(start, 16777216 - pos) + dMul(dest, pos);
};
long long lerpL(long long start, long long dest, long long pos) {
return dMul( (start << 12), 16777216 - (pos << 12) ) + dMul((dest << 12), (pos << 12) ) >> 12;
};
int lerp(int start, int end, int factor){
// lerp interpolated cam movement
// InBetween = Value 1 + ( ( Value2 - Value1 ) * lerpValue ) ;
// lerpValue should be a int between 17 and 256.
return ( ( start ) + ( ( end - start ) * factor ) ) >> 12;
};
long long easeIn(long long i){
return ((i << 7) * (i << 7) * (i << 7) / 32 ) >> 19;
};
int easeOut(int i){
return (4096 >> 7) - ((4096 - (i << 7)) * (4096 - (i << 7))) >> 12;
};
//~ int easeInOut(int i, int div){
//~ return lerp(easeIn(i, div), easeOut(i) , i);
//~ };
SVECTOR SVlerp(SVECTOR start, SVECTOR end, int factor){
SVECTOR output = {0,0,0,0};
output.vx = lerp(start.vx, end.vx, factor);
output.vy = lerp(start.vy, end.vy, factor);
output.vz = lerp(start.vz, end.vz, factor);
return output;
};
VECTOR getVectorTo( VECTOR actor, VECTOR target ) {
// Returns a normalized vector that points from actor to target
VECTOR direction = { subVector(target, actor) };
VECTOR Ndirection = {0,0,0,0};
u_int distSq = (direction.vx * direction.vx) + (direction.vz * direction.vz);
direction.pad = psqrt(distSq);
VectorNormal(&direction, &Ndirection);
return Ndirection ;
};
// 20.12 fixed point to 20.12 fixed point rounding
int32_t round(int32_t n) {
return (n + 2048) & 0xfffff000;
};
// 20.12 fixed point to int, rounding first
static inline int32_t toint(int32_t n) {
return (n + 2048) >> 12;
};
//~ int32_t round( int32_t n){
//~ // GRS - Action
//~ // 0xx - round down = do nothing (x means any bit value, 0 or 1)
//~ // 100 - this is a tie: round up if the mantissa's bit just before G is 1, else round down=do nothing
//~ // 101 - round up
//~ // 110 - round up
//~ // 111 - round up
//~ // source : https://stackoverflow.com/a/8984135
//~ // e.g : n == 106 150 == 0000 0000 0000 0001 1001 1110 1010 0110
//~ // Get GRS bits
//~ // 0xe00 == 0000 1110 0000 0000
//~ int8_t grs = ( n & 0xe00) >> 8 ; // 1110 0000 0000 >> 8
//~ // GRS == 111(0)
//~ // Get G value - 0x8 == 1000
//~ if (grs & 0x8){
//~ // GRS = 1xx
//~ if ( // Get R value - 0x4 == 0100
//~ // GRS == 11x ; round up
//~ grs & 0x4 ||
//~ // Get S value - 0x2 == 0010
//~ // GRS == 101 ; round up
//~ ( !(grs & 0x4) && grs & 0x2)
//~ ) {
//~ n += 0x800;
//~ } else if ( !(n & 0x1000) ) {
//~ // Get mantissa lsb - 0x1000 == 0001 0000 0000
//~ // GRS == 100 ; tie, round up if mantissa lsb is 1
//~ n += 0x800;
//~ }
//~ }
//~ return n;
//~ };