Descent3/fix/fix.cpp
2024-04-16 12:56:40 -06:00

259 lines
5.4 KiB
C++

/*
* $Logfile: /DescentIII/Main/fix/fix.cpp $
* $Revision: 6 $
* $Date: 4/22/99 8:29p $
* $Author: Kevin $
*
* Fixed-point math functions, including trig & float conversions
*
* $Log: /DescentIII/Main/fix/fix.cpp $
*
* 6 4/22/99 8:29p Kevin
* made psrand.h come after stdlib.h
*
* 5 4/21/99 11:05a Kevin
* new ps_rand and ps_srand to replace rand & srand
*
* 4 8/26/97 10:15a Jason
* corrected the FixCeil function
*
* 3 8/22/97 12:34p Jason
* added FixCeil and FixFloor
*
* 2 8/21/97 5:57p Samir
* Added initialization of random number generator.
*
* 7 2/27/97 4:47 PM Jeremy
* moved inline assembly language functions processor for
* fixmul/fixdiv/fixmuldiv into fixmac.h and fixwin32.h
*
* 6 2/12/97 5:35p Jason
* fixed yet another dumb syntax error...will I ever learn?
*
* 5 2/12/97 5:34p Jason
* fixed dumb syntax error
*
* 4 2/12/97 5:27p Jason
* implemented asin,acos,atan2
*
* 3 2/10/97 1:57p Jason
* changed FloatToFix back to what it originally was
*
* 2 2/07/97 5:44p Matt
* Moved fixed-point math funcs from vecmat to fix
* Changed trig functions to use small table like D2
*
* $NoKeywords: $
*/
#include "fix.h"
#include <time.h>
#include <stdlib.h>
#include "psrand.h"
// Tables for trig functions
float sincos_table[321]; // 256 entries + 64 sin-only + 1 for interpolation
angle asin_table[257]; // 1 quadrants worth, +1 for interpolation
angle acos_table[257];
#define PI 3.141592654
// Generate the data for the trig tables
void InitMathTables() {
int i;
float rad, s, c;
for (i = 0; i < 321; i++) {
rad = (float)((double)i / 256.0 * 2 * PI);
sincos_table[i] = (float)sin(rad);
}
for (i = 0; i < 256; i++) {
s = asin((float)i / 256.0);
c = acos((float)i / 256.0);
s = (s / (PI * 2));
c = (c / (PI * 2));
asin_table[i] = FloatToFix(s);
acos_table[i] = FloatToFix(c);
}
asin_table[256] = asin_table[255];
acos_table[256] = acos_table[255];
// Initialize a random seed.
ps_srand(time(NULL));
}
// Returns the sine of the given angle. Linearly interpolates between two entries in a 256-entry table
float FixSin(angle a) {
int i, f;
float s0, s1;
i = (a >> 8) & 0xff;
f = a & 0xff;
s0 = sincos_table[i];
s1 = sincos_table[i + 1];
return (float)(s0 + ((s1 - s0) * (double)f / 256.0));
}
// Returns the cosine of the given angle. Linearly interpolates between two entries in a 256-entry table
float FixCos(angle a) {
int i, f;
float c0, c1;
i = (a >> 8) & 0xff;
f = a & 0xff;
c0 = sincos_table[i + 64];
c1 = sincos_table[i + 64 + 1];
return (float)(c0 + ((c1 - c0) * (double)f / 256.0));
}
// Returns the sine of the given angle, but does no interpolation
float FixSinFast(angle a) {
int i;
i = ((a + 0x80) >> 8) & 0xff;
return sincos_table[i];
}
// Returns the cosine of the given angle, but does no interpolation
float FixCosFast(angle a) {
int i;
i = ((a + 0x80) >> 8) & 0xff;
return sincos_table[i + 64];
}
// use this instead of:
// for: (int)floor(x+0.5f) use FloatRound(x)
// (int)ceil(x-0.5f) use FloatRound(x)
// (int)floor(x-0.5f) use FloatRound(x-1.0f)
// (int)floor(x) use FloatRound(x-0.5f)
// for values in the range -2048 to 2048
// Set a vector to {0,0,0}
int FloatRound(float x) {
float nf;
nf = x + 8390656.0f;
return ((*((int *)&nf)) & 0x7FFFFF) - 2048;
}
// A fast way to convert floats to fix
fix FloatToFixFast(float x) {
float nf;
nf = x * 65536.0f + 8390656.0f;
return ((*((int *)&nf)) & 0x7FFFFF) - 2048;
}
// Get rid of the "no return value" warnings in the next three functions
#pragma warning(disable : 4035)
// compute inverse sine
angle FixAsin(float v) {
fix vv;
int i, f, aa;
vv = FloatToFix(fabs(v));
if (vv >= F1_0) // check for out of range
return 0x4000;
i = (vv >> 8) & 0xff;
f = vv & 0xff;
aa = asin_table[i];
aa = aa + (((asin_table[i + 1] - aa) * f) >> 8);
if (v < 0)
aa = F1_0 - aa;
return aa;
}
// compute inverse cosine
angle FixAcos(float v) {
fix vv;
int i, f, aa;
vv = FloatToFix(fabs(v));
if (vv >= F1_0) // check for out of range
return 0;
i = (vv >> 8) & 0xff;
f = vv & 0xff;
aa = acos_table[i];
aa = aa + (((acos_table[i + 1] - aa) * f) >> 8);
if (v < 0)
aa = 0x8000 - aa;
return aa;
}
// given cos & sin of an angle, return that angle.
// parms need not be normalized, that is, the ratio of the parms cos/sin must
// equal the ratio of the actual cos & sin for the result angle, but the parms
// need not be the actual cos & sin.
// NOTE: this is different from the standard C atan2, since it is left-handed.
angle FixAtan2(float cos, float sin) {
float q, m;
angle t;
// find smaller of two
q = (sin * sin) + (cos * cos);
m = sqrt(q);
if (m == 0)
return 0;
if (fabs(sin) < fabs(cos)) {
// sin is smaller, use arcsin
t = FixAsin(sin / m);
if (cos < 0)
t = 0x8000 - t;
return t;
} else {
t = FixAcos(cos / m);
if (sin < 0)
t = F1_0 - t;
return t;
}
}
// Does a ceiling operation on a fixed number
fix FixCeil(fix num) {
int int_num;
fix new_num;
int_num = FixToInt(num);
if (num & 0xFFFF) {
new_num = IntToFix(int_num + 1);
return new_num;
}
new_num = IntToFix(int_num);
return (new_num);
}
// Floors a fixed number
fix FixFloor(fix num) {
int int_num = FixToInt(num);
return (IntToFix(int_num));
}