⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fmaths.inc

📁 著名的游戏开发库Allegro4.2.0 for DELPHI
💻 INC
字号:
{*         ______   ___    ___
 *        /\  _  \ /\_ \  /\_ \
 *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___
 *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
 *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
 *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
 *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
 *                                           /\____/
 *                                           \_/__/
 *
 *      Fixed point math inline functions (generic C).
 *
 *      By Shawn Hargreaves.
 *
 *      See readme.txt for copyright information.
 *}
{$IFDEF ALLEGRO_INTERFACE}
const
  ERANGE = 1;
  EDOM = 2;
  
// ftofix and fixtof are used in generic C versions of fixmul and fixdiv
function ftofix(x: double): fixed;
function fixtof(x: fixed): double;
function fixadd(x, y: fixed): fixed;
function fixsub(x, y: fixed): fixed;
function fixmul(x, y: fixed): fixed;
function fixdiv(x, y: fixed): fixed;
function fixfloor(x: fixed): sint32;
function fixceil(x: fixed): sint32;
function itofix(x: sint32): fixed;
function fixtoi(x: fixed): sint32;
function fixcos(x: fixed): fixed;
function fixsin(x: fixed): fixed;
function fixtan(x: fixed): fixed;
function fixacos(x: fixed): fixed;
function fixasin(x: fixed): fixed;
{$ENDIF ALLEGRO_INTERFACE}
{$IFDEF ALLEGRO_IMPLEMENTATION}
function ftofix(x: double): fixed;
begin
  if x > 32767.0 then
  begin
    allegro_errno^[0] := ERANGE;
    Result := $7FFFFFFF;
    Exit;
  end;

  if x < -32767.0 then
  begin
    allegro_errno^[0] := ERANGE;
    Result := $7FFFFFFF;
    Exit;
  end;

  if x < 0 then
    Result := Round(x * 65536.0 + -0.5)
  else
    Result := Round(x * 65536.0 + 0.5);
end;

function fixtof(x: fixed): double;
begin
  Result := x / 65536.0;
end;

procedure _set_errno_erange;
begin
  allegro_errno^[0] := ERANGE;
end;

// use generic C versions
function fixadd(x, y: fixed): fixed; assembler;
asm
  add eax, y
  jno @Out1
  call _set_errno_erange
  mov eax, $7FFFFFFF
  cmp y, 0
  jg @Out1
  neg eax
@Out1:
end;
{
begin
  Result := x + y;

  if result >= 0 then
  begin
    if (x < 0) and (y < 0) then
    begin
      allegro_errno^[0] := ERANGE;
      Result := -$7FFFFFFF;
    end;
  end else
  begin
    if (x > 0) and (y > 0) then
    begin
      allegro_errno^[0] := ERANGE;
      Result := $7FFFFFFF;
    end
  end;
end;
}
function fixsub(x, y: fixed): fixed; assembler;
asm
  sub eax, y
  jno @Out1
  call _set_errno_erange
  mov eax, $7FFFFFFF
  cmp y, 0
  jl @Out1
  neg eax
@Out1:
end;
{
begin
  Result := x - y;

  if Result >= 0 then
  begin
    if (x < 0) and (y > 0) then
    begin
      allegro_errno^[0] := ERANGE;
      Result := -$7FFFFFFF;
    end;
  end else
  begin
    if (x > 0) and (y < 0) then
    begin
      allegro_errno^[0] := ERANGE;
      Result := $7FFFFFFF;
    end;
  end;
end;
}
{* In benchmarks conducted circa May 2005 we found that, in the main:
 * - IA32 machines performed faster with one implementation;
 * - AMD64 and G4 machines performed faster with another implementation.
 *
 * Benchmarks were mainly done with differing versions of gcc.
 * Results varied with other compilers, optimisation levels, etc.
 * so this is not optimal, though a tenable compromise.
 *
 * Note that the following implementation are NOT what were benchmarked.
 * We had forgotten to put in overflow detection in those versions.
 * If you don't need overflow detection then previous versions in the
 * CVS tree might be worth looking at.
 *
 * PS. Don't move the #ifs inside the AL_INLINE; BCC doesn't like it.
 *}
function fixmul(x, y: fixed): fixed; assembler;
begin
  Result := ftofix(fixtof(x) * fixtof(y));
end;

function fixdiv(x, y: fixed): fixed;
begin
  if y = 0 then
  begin
    allegro_errno^[0] := ERANGE;
    if x < 0 then
      Result := -$7FFFFFFF
    else
      Result := $7FFFFFFF;
  end else
    Result := ftofix(fixtof(x) / fixtof(y));
end;

function fixfloor(x: fixed): sint32; assembler;
asm
  sar eax, $10
end;
{
begin
   // (x >> 16) is not portable
  if x >= 0 then
    Result := x shr 16
  else
    Result := not((not x) shr 16);
end;
}

function fixceil(x: fixed): sint32;
begin
  if x > $7FFF0000 then
  begin
    allegro_errno^[0] := ERANGE;
    Result := $7FFF;
    Exit;
  end;

  Result := fixfloor(x + $FFFF);
end;

function itofix(x: sint32): fixed;
begin
  Result := x shl 16;
end;

function fixtoi(x: fixed): sint32;
begin
  Result := fixfloor(x) + ((x and $8000) shr 15);
end;

function fixcos(x: fixed): fixed;
begin
  Result := _cos_tbl[((x + $4000) shr 15) and $1FF];
end;

function fixsin(x: fixed): fixed;
begin
  Result := _cos_tbl[((x - $400000 + $4000) shr 15) and $1FF];
end;

function fixtan(x: fixed): fixed;
begin
  Result := _tan_tbl[((x + $4000) shr 15) and $FF];
end;

function fixacos(x: fixed): fixed;
begin
  if (x < -65536) or (x > 65536) then
  begin
      allegro_errno^[0] := EDOM;
      Result := 0;
      Exit;
  end;
  Result := _acos_tbl[(x+65536+127) shr 8];
end;

function fixasin(x: fixed): fixed;
begin
  if (x < -65536) or (x > 65536) then
  begin
      allegro_errno^[0] := EDOM;
      Result := 0;
      Exit;
  end;

  Result := $00400000 - _acos_tbl[(x+65536+127)shr 8];
end;
{$ENDIF ALLEGRO_IMPLEMENTATION}
{$IFDEF ALLEGRO_LOADVARIABLE}
{$ENDIF ALLEGRO_LOADVARIABLE}



⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -