cearn_atan.pas 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. (*
  2. coranac.com's awesome atan2 implementation
  3. Very fast and very small.
  4. *)
  5. unit cearn_atan;
  6. {$mode objfpc}
  7. {$H+}
  8. interface
  9. uses
  10. ctypes, nds9;
  11. const
  12. __qran_seed: cint = 42;
  13. function atan2Lookup(x, y: cint): cuint32;
  14. function atan2Lerp(x, y: cint): cuint32;
  15. function sqran(seed: cint): cint;
  16. function qran(): cint; inline;
  17. function qran_range(min, max: cint): cint; inline;
  18. const
  19. BRAD_PI_SHIFT = 14;
  20. BRAD_PI = 1 shl BRAD_PI_SHIFT;
  21. BRAD_HPI = BRAD_PI div 2;
  22. BRAD_2PI = BRAD_PI * 2;
  23. ATAN_ONE = $1000;
  24. ATAN_FP = 12;
  25. // Some constants for dealing with atanLUT.
  26. ATANLUT_STRIDE = ATAN_ONE div $80;
  27. ATANLUT_STRIDE_SHIFT = 5;
  28. // Arctangents LUT. Interval: [0, 1] (one=128); PI=0x20000
  29. atanLUT: array [0..130-1] of cushort = (
  30. $0000, $0146, $028C, $03D2, $0517, $065D, $07A2, $08E7,
  31. $0A2C, $0B71, $0CB5, $0DF9, $0F3C, $107F, $11C1, $1303,
  32. $1444, $1585, $16C5, $1804, $1943, $1A80, $1BBD, $1CFA,
  33. $1E35, $1F6F, $20A9, $21E1, $2319, $2450, $2585, $26BA,
  34. $27ED, $291F, $2A50, $2B80, $2CAF, $2DDC, $2F08, $3033,
  35. $315D, $3285, $33AC, $34D2, $35F6, $3719, $383A, $395A,
  36. $3A78, $3B95, $3CB1, $3DCB, $3EE4, $3FFB, $4110, $4224,
  37. $4336, $4447, $4556, $4664, $4770, $487A, $4983, $4A8B,
  38. // 64
  39. $4B90, $4C94, $4D96, $4E97, $4F96, $5093, $518F, $5289,
  40. $5382, $5478, $556E, $5661, $5753, $5843, $5932, $5A1E,
  41. $5B0A, $5BF3, $5CDB, $5DC1, $5EA6, $5F89, $606A, $614A,
  42. $6228, $6305, $63E0, $64B9, $6591, $6667, $673B, $680E,
  43. $68E0, $69B0, $6A7E, $6B4B, $6C16, $6CDF, $6DA8, $6E6E,
  44. $6F33, $6FF7, $70B9, $717A, $7239, $72F6, $73B3, $746D,
  45. $7527, $75DF, $7695, $774A, $77FE, $78B0, $7961, $7A10,
  46. $7ABF, $7B6B, $7C17, $7CC1, $7D6A, $7E11, $7EB7, $7F5C,
  47. // 128
  48. $8000, $80A2);
  49. implementation
  50. // Quick (and very dirty) pseudo-random number generator
  51. // return random in range [0,8000h>
  52. function qran(): cint; inline;
  53. begin
  54. __qran_seed := 1664525 * __qran_seed + 1013904223;
  55. result := (__qran_seed shr 16) and $7FFF;
  56. end;
  57. function qran_range(min, max: cint): cint; inline;
  58. begin
  59. result := (qran() * (max - min) shr 15) + min;
  60. end;
  61. // Get the octant a coordinate pair is in.
  62. procedure OCTANTIFY(var _x, _y, _o: cint); inline;
  63. var
  64. _t: cint;
  65. begin
  66. repeat
  67. _o := 0;
  68. if (_y < 0) then
  69. begin
  70. _x := -_x;
  71. _y := -_y;
  72. _o := _o + 4;
  73. end;
  74. if (_x <= 0) then
  75. begin
  76. _t := _x;
  77. _x := _y;
  78. _y := -_t;
  79. _o := _o + 2;
  80. end;
  81. if (_x <= _y) then
  82. begin
  83. _t := _y - _x;
  84. _x := _x + _y;
  85. _y := _t;
  86. _o := _o + 1;
  87. end;
  88. until true;
  89. end;
  90. function QDIV(num, den: cint; const bits: cint): cint; inline;
  91. begin
  92. while (REG_DIVCNT^ and DIV_BUSY) <> 0 do;
  93. REG_DIVCNT^ := DIV_64_32;
  94. REG_DIV_NUMER^ := cint64(num) shl bits;
  95. REG_DIV_DENOM_L^ := den;
  96. while (REG_DIVCNT^ and DIV_BUSY) <> 0 do;
  97. result := REG_DIV_RESULT_L^;
  98. end;
  99. function atan2Lerp(x, y: cint): cuint32;
  100. var
  101. phi: cint;
  102. t, fa, fb, h: cuint32;
  103. begin
  104. if (y =0) then
  105. begin
  106. if x >= 0 then
  107. result := 0
  108. else
  109. result := BRAD_PI;
  110. exit;
  111. end;
  112. OCTANTIFY(x, y, phi);
  113. phi := phi * BRAD_PI div 4;
  114. t := QDIV(y, x, ATAN_FP);
  115. h := t mod ATANLUT_STRIDE;
  116. fa := atanLUT[t div ATANLUT_STRIDE];
  117. fb := atanLUT[t div ATANLUT_STRIDE + 1];
  118. result := phi + (fa + SarLongint((fb - fa) * h, ATANLUT_STRIDE_SHIFT)) div 8;
  119. end;
  120. function atan2Lookup(x, y: cint): cuint32;
  121. var
  122. phi: cint;
  123. t: cuint32;
  124. begin
  125. if (y = 0) then
  126. begin
  127. if x >= 0 then
  128. result := 0
  129. else
  130. result := BRAD_PI;
  131. exit;
  132. end;
  133. OCTANTIFY(x, y, phi);
  134. phi := phi * BRAD_PI div 4;
  135. t := QDIV(y, x, ATAN_FP);
  136. result := phi + atanLUT[t div ATANLUT_STRIDE] div 8;
  137. end;
  138. function sqran(seed: cint): cint;
  139. var
  140. old: cint;
  141. begin
  142. old := __qran_seed;
  143. __qran_seed := seed;
  144. result := old;
  145. end;
  146. end.