Subversion Repositories Games.Descent

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * This file is part of the DXX-Rebirth project <https://www.dxx-rebirth.com/>.
  3.  * It is copyright by its individual contributors, as recorded in the
  4.  * project's Git history.  See COPYING.txt at the top level for license
  5.  * terms and a link to the Git history.
  6.  */
  7.  
  8. /*
  9.  *
  10.  * C version of fixed point library
  11.  *
  12.  */
  13.  
  14. #include <cstdint>
  15. #include <stdlib.h>
  16. #include <math.h>
  17.  
  18. #include "dxxerror.h"
  19. #include "maths.h"
  20.  
  21. namespace dcx {
  22.  
  23. #define EPSILON (F1_0/100)
  24.  
  25. namespace {
  26.  
  27. class fix_sincos_input
  28. {
  29. public:
  30.         const uint8_t m_idx;
  31.         const signed m_mul;
  32.         fix_sincos_input(fix a) :
  33.                 m_idx(static_cast<uint8_t>(a >> 8)),
  34.                 m_mul(static_cast<uint8_t>(a))
  35.         {
  36.         }
  37. };
  38.  
  39. }
  40.  
  41. fix64 fixmul64(fix a, fix b)
  42. {
  43.         const fix64 a64 = a;
  44.         const fix64 b64 = b;
  45.         return (a64 * b64) / 65536;
  46. }
  47.  
  48. fix fixdiv(fix a, fix b)
  49. {
  50.         if (!b)
  51.                 return 1;
  52.         const fix64 a64 = a;
  53.         return static_cast<fix>((a64 * 65536) / b);
  54. }
  55.  
  56. fix fixmuldiv(fix a, fix b, fix c)
  57. {
  58.         if (!c)
  59.                 return 1;
  60.         const fix64 a64 = a;
  61.         return static_cast<fix>((a64 * b) / c);
  62. }
  63.  
  64. //given cos & sin of an angle, return that angle.
  65. //parms need not be normalized, that is, the ratio of the parms cos/sin must
  66. //equal the ratio of the actual cos & sin for the result angle, but the parms
  67. //need not be the actual cos & sin.  
  68. //NOTE: this is different from the standard C atan2, since it is left-handed.
  69.  
  70. fixang fix_atan2(fix cos,fix sin)
  71. {
  72.         fixang t;
  73.  
  74.         //Assert(!(cos==0 && sin==0));
  75.  
  76.         //find smaller of two
  77.  
  78.         const auto dsin = static_cast<double>(sin);
  79.         const auto dcos = static_cast<double>(cos);
  80.         double d;
  81.         d = sqrt((dsin * dsin) + (dcos * dcos));
  82.  
  83.         if (d==0.0)
  84.                 return 0;
  85.  
  86.         if (labs(sin) < labs(cos)) {                            //sin is smaller, use arcsin
  87.                 t = fix_asin(static_cast<fix>((dsin / d) * 65536.0));
  88.                 if (cos<0)
  89.                         t = 0x8000 - t;
  90.                 return t;
  91.         }
  92.         else {
  93.                 t = fix_acos(static_cast<fix>((dcos / d) * 65536.0));
  94.                 if (sin<0)
  95.                         t = -t;
  96.                 return t;
  97.         }
  98. }
  99.  
  100. static unsigned int fixdivquadlongu(quadint n, uint64_t d)
  101. {
  102.         return n.q / d;
  103. }
  104.  
  105. uint32_t quad_sqrt(const quadint iq)
  106. {
  107.         const uint32_t low = iq.low;
  108.         const int32_t high = iq.high;
  109.         int i, cnt;
  110.         uint32_t r,old_r,t;
  111.  
  112.         if (high<0)
  113.                 return 0;
  114.  
  115.         if (high==0 && static_cast<int32_t>(low)>=0)
  116.                 return long_sqrt(static_cast<int32_t>(low));
  117.  
  118.         if ((i = high >> 24)) {
  119.                 cnt=12+16;
  120.         }
  121.         else if ((i = high >> 16))
  122.         {
  123.                 cnt=8+16;
  124.         }
  125.         else if ((i = high >> 8))
  126.         {
  127.                 cnt=4+16;
  128.         } else {
  129.                 cnt=0+16; i = high;
  130.         }
  131.        
  132.         r = guess_table[i]<<cnt;
  133.  
  134.         //quad loop usually executed 4 times
  135.  
  136.         r = fixdivquadlongu(iq,r)/2 + r/2;
  137.         r = fixdivquadlongu(iq,r)/2 + r/2;
  138.         r = fixdivquadlongu(iq,r)/2 + r/2;
  139.  
  140.         do {
  141.  
  142.                 old_r = r;
  143.                 t = fixdivquadlongu(iq,r);
  144.  
  145.                 if (t==r)       //got it!
  146.                         return r;
  147.  
  148.                 r = t/2 + r/2;
  149.  
  150.         } while (!(r==t || r==old_r));
  151.  
  152.         t = fixdivquadlongu(iq,r);
  153.         quadint tq;
  154.         //edited 05/17/99 Matt Mueller - tq.high is undefined here.. so set them to = 0
  155.         tq.q = 0;
  156.         //end edit -MM
  157.         fixmulaccum(&tq,r,t);
  158.         if (tq.q != iq.q)
  159.                 r++;
  160.  
  161.         return r;
  162. }
  163.  
  164. //computes the square root of a long, returning a short
  165. ushort long_sqrt(int32_t a)
  166. {
  167.         int cnt,r,old_r,t;
  168.  
  169.         if (a<=0)
  170.                 return 0;
  171.  
  172.         if (a & 0xff000000)
  173.                 cnt=12;
  174.         else if (a & 0xff0000)
  175.                 cnt=8;
  176.         else if (a & 0xff00)
  177.                 cnt=4;
  178.         else
  179.                 cnt=0;
  180.        
  181.         r = guess_table[(a>>cnt)&0xff]<<cnt;
  182.  
  183.         //the loop nearly always executes 3 times, so we'll unroll it 2 times and
  184.         //not do any checking until after the third time.  By my calcutations, the
  185.         //loop is executed 2 times in 99.97% of cases, 3 times in 93.65% of cases,
  186.         //four times in 16.18% of cases, and five times in 0.44% of cases.  It never
  187.         //executes more than five times.  By timing, I determined that is is faster
  188.         //to always execute three times and not check for termination the first two
  189.         //times through.  This means that in 93.65% of cases, we save 6 cmp/jcc pairs,
  190.         //and in 6.35% of cases we do an extra divide.  In real life, these numbers
  191.         //might not be the same.
  192.  
  193.         r = ((a/r)+r)/2;
  194.         r = ((a/r)+r)/2;
  195.  
  196.         do {
  197.  
  198.                 old_r = r;
  199.                 t = a/r;
  200.  
  201.                 if (t==r)       //got it!
  202.                         return r;
  203.  
  204.                 r = (t+r)/2;
  205.  
  206.         } while (!(r==t || r==old_r));
  207.  
  208.         if (a % r)
  209.                 r++;
  210.  
  211.         return r;
  212. }
  213.  
  214. //computes the square root of a fix, returning a fix
  215. fix fix_sqrt(fix a)
  216. {
  217.         return static_cast<fix>(long_sqrt(a)) << 8;
  218. }
  219.  
  220. static fix fix_sincos(const uint8_t idx0, const signed mul)
  221. {
  222.         const fix t0 = sincos_table[idx0];
  223.         const uint8_t idx1 = idx0 + 1;
  224.         const fix t1 = sincos_table[idx1];
  225.         return (t0 + (((t1 - t0) * mul) >> 8)) << 2;
  226. }
  227.  
  228. static fix fix_sin(const fix_sincos_input sci)
  229. {
  230.         return fix_sincos(sci.m_idx, sci.m_mul);
  231. }
  232.  
  233. __attribute_warn_unused_result
  234. static fix fix_cos(const fix_sincos_input sci)
  235. {
  236.         return fix_sincos(static_cast<uint8_t>(sci.m_idx + 64), sci.m_mul);
  237. }
  238.  
  239. //compute sine and cosine of an angle, filling in the variables
  240. //either of the pointers can be NULL
  241. //with interpolation
  242. fix_sincos_result fix_sincos(fix a)
  243. {
  244.         fix_sincos_input i(a);
  245.         return {fix_sin(i), fix_cos(i)};
  246. }
  247.  
  248. fix fix_sin(fix a)
  249. {
  250.         return fix_sin(fix_sincos_input{a});
  251. }
  252.  
  253. fix fix_cos(fix a)
  254. {
  255.         return fix_cos(fix_sincos_input{a});
  256. }
  257.  
  258. //compute sine and cosine of an angle, filling in the variables
  259. //either of the pointers can be NULL
  260. //no interpolation
  261. fix fix_fastsin(fix a)
  262. {
  263.         const uint8_t i = static_cast<uint8_t>(a >> 8);
  264.         return sincos_table[i] << 2;
  265. }
  266.  
  267. //compute inverse sine
  268. fixang fix_asin(fix v)
  269. {
  270.         fix vv;
  271.         int i,f,aa;
  272.  
  273.         vv = labs(v);
  274.  
  275.         if (vv >= f1_0)         //check for out of range
  276.                 return 0x4000;
  277.  
  278.         i = (vv>>8)&0xff;
  279.         f = vv&0xff;
  280.  
  281.         aa = asin_table[i];
  282.         aa = aa + (((asin_table[i+1] - aa) * f)>>8);
  283.  
  284.         if (v < 0)
  285.                 aa = -aa;
  286.  
  287.         return aa;
  288. }
  289.  
  290. //compute inverse cosine
  291. fixang fix_acos(fix v)
  292. {
  293.         fix vv;
  294.         int i,f,aa;
  295.  
  296.         vv = labs(v);
  297.  
  298.         if (vv >= f1_0)         //check for out of range
  299.                 return 0;
  300.  
  301.         i = (vv>>8)&0xff;
  302.         f = vv&0xff;
  303.  
  304.         aa = acos_table[i];
  305.         aa = aa + (((acos_table[i+1] - aa) * f)>>8);
  306.  
  307.         if (v < 0)
  308.                 aa = 0x8000 - aa;
  309.  
  310.         return aa;
  311. }
  312.  
  313. }
  314.