///////////////////////////////////////////////////////////////////////
// Copyright (C) Andru 2007                                          //
// mail: dr.andru@gmail.com                                          //
// site: http://andru.2x4.ru                                         //
//                                                                   //
// OMEGA Engine is free software.                                    //
//                                                                   //
// You may redistribute it and/or modify it under the terms of the   //
// GNU General Public License, as published by the Free Software     //
// Foundation; either version 2 of the License, or (at your option)  //
// any later version.                                                //
//                                                                   //
// this module 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 module.  If not, write to:                        //
// 	The Free Software Foundation, Inc.,                              //
// 	51 Franklin Street, Fifth Floor                                  //
// 	Boston, MA  02110-1301, USA.                                     //
///////////////////////////////////////////////////////////////////////
unit MATH_FAST;

{$I DEFINES.pas}

interface

function M_Cos( Angle : Integer ) : Single; stdcall;
function M_Sin( Angle : Integer ) : Single; stdcall;
function M_CosF( Angle : Integer ) : Single; stdcall;
function M_SinF( Angle : Integer ) : Single; stdcall;

function M_Round( Value : Single )  : Integer; stdcall;
function M_Trunc( Value : Single )  : Integer; stdcall;

function M_Distance( X1, Y1, X2, Y2 : Single ) : Single; stdcall;
function M_FindAngle( X1, Y1, X2, Y2 : Integer ) : Integer; stdcall;

procedure InitCosSinTables;

var
  CosTable : array[ 0..360 ] of Single;
  SinTable : array[ 0..360 ] of Single;

  cwChop   : Word = $1F3F;

//----------------------------------------------------------------------------//
                                 IMPLEMENTATION
//----------------------------------------------------------------------------//

procedure InitCosSinTables;
  var
    i         : Integer;
    rad_angle : Single;
Begin

for i := 0 to 360 do
  begin
    rad_angle := i * ( 3.1415926 / 180 );
    CosTable[ i ] := Cos( rad_angle );
    SinTable[ i ] := Sin( rad_angle );
  end;

End;

function M_Cos;
Begin

while Angle < 0 do
  Angle := Angle + 360;
while Angle > 360 do
  Angle := Angle - 360;
Result := CosTable[ Angle ];

End;

function M_Sin;
Begin

while Angle < 0 do
  Angle := Angle + 360;
while Angle > 360 do
  Angle := Angle - 360;
Result := SinTable[ Angle ];

End;

function M_CosF;
Begin

Result := CosTable[ Angle ];

End;

function M_SinF;
Begin

Result := SinTable[ Angle ];

End;

{$IFNDEF FPC}
{$O -}
{$ENDIF}
function M_Round;
asm
  FLD   Value
  FISTP DWORD PTR [ Value ]
  MOV   EAX,      [ Value ]
end;

function M_Trunc;
asm
  SUB     ESP, 8
  FSTCW   [ ESP ]
  FLDCW   cwChop
  FLD     Value
  FISTP   dword ptr [ ESP + 4 ]
  FLDCW   [ ESP ]

  POP     ECX
  POP     EAX
end;
{$IFNDEF FPC}
{$O +}
{$ENDIF}

function ArcTangens( dx, dy : Single ) : Integer;
Begin
Result := Abs( M_Round( ArcTan( dy / dx ) * ( 180 / 3.14159 ) ) );
End;

function M_Distance;
Begin
Result := Sqrt( ( X1 - X2 ) * ( X1 - X2 ) + ( Y1 - Y2 ) * ( Y1 - Y2 ) );
End;

function M_FindAngle;
  var
    dx, dy : Single;
Begin

dx := ( X1 - X2 );
dy := ( Y1 - Y2 );

if dx = 0 Then
  begin
    if dy > 0 Then
      Result := 90
    else
      Result := 270;
    exit;
  end;

if dy = 0 Then
  begin
    if dx > 0 Then
      Result := 0
    else
      Result := 180;
    exit;
  end;

if ( dx < 0 ) and ( dy > 0 ) Then { 2nd quad }
  Result := 180 - ArcTangens( dx, dy )
else
  if ( dx < 0 ) and ( dy < 0 ) Then { 3rd quad }
    Result := 180 + ArcTangens( dx, dy )
  else
    if ( dx > 0 ) and ( dy < 0 ) Then { 4th quad }
      Result := 360 - ArcTangens( dx, dy )
    else                                { 1st quad }
      Result := ArcTangens( dx, dy )
End;

initialization
  InitCosSinTables;

end.
