Descent3/fix/fix.cpp

208 lines
4.7 KiB
C++
Raw Permalink Normal View History

/*
* Descent 3
* Copyright (C) 2024 Parallax Software
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
--- HISTORICAL COMMENTS FOLLOW ---
2024-04-16 03:43:29 +00:00
* $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 $
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 6 4/22/99 8:29p Kevin
* made psrand.h come after stdlib.h
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 5 4/21/99 11:05a Kevin
* new ps_rand and ps_srand to replace rand & srand
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 4 8/26/97 10:15a Jason
* corrected the FixCeil function
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 3 8/22/97 12:34p Jason
* added FixCeil and FixFloor
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 2 8/21/97 5:57p Samir
* Added initialization of random number generator.
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 7 2/27/97 4:47 PM Jeremy
* moved inline assembly language functions processor for
* fixmul/fixdiv/fixmuldiv into fixmac.h and fixwin32.h
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 6 2/12/97 5:35p Jason
* fixed yet another dumb syntax error...will I ever learn?
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 5 2/12/97 5:34p Jason
* fixed dumb syntax error
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 4 2/12/97 5:27p Jason
* implemented asin,acos,atan2
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 3 2/10/97 1:57p Jason
* changed FloatToFix back to what it originally was
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 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 <cmath>
2024-04-16 03:43:29 +00:00
#include "fix.h"
2024-04-16 18:56:40 +00:00
// 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];
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
// 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] = std::sin(rad);
2024-04-16 18:56:40 +00:00
}
for (i = 0; i < 256; i++) {
s = std::asin((float)i / 256.0f);
c = std::acos((float)i / 256.0f);
2024-04-16 18:56:40 +00:00
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];
2024-04-16 03:43:29 +00:00
}
2024-04-16 18:56:40 +00:00
// 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;
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
i = (a >> 8) & 0xff;
f = a & 0xff;
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
s0 = sincos_table[i];
s1 = sincos_table[i + 1];
return (float)(s0 + ((s1 - s0) * (double)f / 256.0));
2024-04-16 03:43:29 +00:00
}
2024-04-16 18:56:40 +00:00
// 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;
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
i = (a >> 8) & 0xff;
f = a & 0xff;
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
c0 = sincos_table[i + 64];
c1 = sincos_table[i + 64 + 1];
return (float)(c0 + ((c1 - c0) * (double)f / 256.0));
2024-04-16 03:43:29 +00:00
}
2024-04-16 18:56:40 +00:00
// Get rid of the "no return value" warnings in the next three functions
#pragma warning(disable : 4035)
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
// compute inverse sine
angle FixAsin(float v) {
fix vv;
int i, f, aa;
2024-04-16 03:43:29 +00:00
vv = FloatToFix(std::fabs(v));
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
if (vv >= F1_0) // check for out of range
return 0x4000;
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
i = (vv >> 8) & 0xff;
f = vv & 0xff;
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
aa = asin_table[i];
aa = aa + (((asin_table[i + 1] - aa) * f) >> 8);
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
if (v < 0)
aa = F1_0 - aa;
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
return aa;
2024-04-16 03:43:29 +00:00
}
2024-04-16 18:56:40 +00:00
// compute inverse cosine
angle FixAcos(float v) {
fix vv;
int i, f, aa;
2024-04-16 03:43:29 +00:00
vv = FloatToFix(std::fabs(v));
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
if (vv >= F1_0) // check for out of range
return 0;
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
i = (vv >> 8) & 0xff;
f = vv & 0xff;
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
aa = acos_table[i];
aa = aa + (((acos_table[i + 1] - aa) * f) >> 8);
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
if (v < 0)
aa = 0x8000 - aa;
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
return aa;
2024-04-16 03:43:29 +00:00
}
2024-04-16 18:56:40 +00:00
// 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;
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
// find smaller of two
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
q = (sin * sin) + (cos * cos);
2024-04-16 03:43:29 +00:00
m = std::sqrt(q);
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
if (m == 0)
return 0;
2024-04-16 03:43:29 +00:00
if (std::fabs(sin) < std::fabs(cos)) {
2024-04-16 18:56:40 +00:00
// sin is smaller, use arcsin
t = FixAsin(sin / m);
if (cos < 0)
t = 0x8000 - t;
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
return t;
} else {
t = FixAcos(cos / m);
if (sin < 0)
t = F1_0 - t;
return t;
}
2024-04-16 03:43:29 +00:00
}