/*
* This file is part of the DXX-Rebirth project .
* It is copyright by its individual contributors, as recorded in the
* project's Git history. See COPYING.txt at the top level for license
* terms and a link to the Git history.
*/
/*
*
* C version of fixed point library
*
*/
#include
#include
#include
#include "dxxerror.h"
#include "maths.h"
#define EPSILON (F1_0/100)
fix fixmul(fix a, fix b)
{
return (fix)((((fix64) a) * b) / 65536);
}
fix64 fixmul64(fix a, fix b)
{
return (fix64)((((fix64) a) * b) / 65536);
}
fix fixdiv(fix a, fix b)
{
return b ? (fix)((((fix64)a) *65536)/b) : 1;
}
fix fixmuldiv(fix a, fix b, fix c)
{
return c ? (fix)((((fix64)a)*b)/c) : 1;
}
//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.
fixang fix_atan2(fix cos,fix sin)
{
double d, dsin, dcos;
fixang t;
//Assert(!(cos==0 && sin==0));
//find smaller of two
dsin = (double)sin;
dcos = (double)cos;
d = sqrt((dsin * dsin) + (dcos * dcos));
if (d==0.0)
return 0;
if (labs(sin) < labs(cos)) { //sin is smaller, use arcsin
t = fix_asin((fix)((dsin / d) * 65536.0));
if (cos<0)
t = 0x8000 - t;
return t;
}
else {
t = fix_acos((fix)((dcos / d) * 65536.0));
if (sin<0)
t = -t;
return t;
}
}
static unsigned int fixdivquadlongu(quadint n, uint64_t d)
{
return n.q / d;
}
u_int32_t quad_sqrt(const quadint iq)
{
const u_int32_t low = iq.low;
const int32_t high = iq.high;
int i, cnt;
u_int32_t r,old_r,t;
if (high<0)
return 0;
if (high==0 && (int32_t)low>=0)
return long_sqrt((int32_t)low);
if (high & 0xff000000) {
cnt=12+16; i = high >> 24;
} else if (high & 0xff0000) {
cnt=8+16; i = high >> 16;
} else if (high & 0xff00) {
cnt=4+16; i = high >> 8;
} else {
cnt=0+16; i = high;
}
r = guess_table[i]<>cnt)&0xff]<>8)&0xff;
f = a&0xff;
if (s)
{
fix ss = sincos_table[i];
*s = (ss + (((sincos_table[i+1] - ss) * f)>>8))<<2;
}
if (c)
{
fix cc = sincos_table[i+64];
*c = (cc + (((sincos_table[i+64+1] - cc) * f)>>8))<<2;
}
}
//compute sine and cosine of an angle, filling in the variables
//either of the pointers can be NULL
//no interpolation
void fix_fastsincos(fix a,fix *s,fix *c)
{
int i;
i = (a>>8)&0xff;
if (s) *s = sincos_table[i] << 2;
if (c) *c = sincos_table[i+64] << 2;
}
//compute inverse sine
fixang fix_asin(fix v)
{
fix vv;
int i,f,aa;
vv = labs(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 = -aa;
return aa;
}
//compute inverse cosine
fixang fix_acos(fix v)
{
fix vv;
int i,f,aa;
vv = labs(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;
}