unit uSMath;
//основа взята тут:
// http://code.google.com/p/dforth/
//ну и своё тоже самое было написано, но только Vec2f.
//
// date 07.08.2011

//а оно надо??
{.$DEGINE SMATH_USE_DOUBLE_PRECISION}
//параметры-вектора?
{.$DEFINE SMATH_ZENGL_SUPPORT}
//приведение типов
{.$DEFINE SMATH_ZGL_CHIPMUNK_SUPPORT}

interface

uses
{$IFDEF SMATH_ZENGL_SUPPORT}
  zglHeader,
{$ENDIF}
{$IFDEF SMATH_ZGL_CHIPMUNK_SUPPORT}
  zglChipmunk,
{$ENDIF}
  Math;

const
//pi
  PI          =  3.1415926536;
  PISqr       =  9.8696044011;
  PISqrt      =  1.7724538509;
  PI2         =  6.2831853072;
  PI2Sqr      = 39.4784176044;
  PI2Sqrt     =  2.5066282746;
  PIHalf      =  1.5707963268;
  PIHalfSqr   =  2.4674011003;
  PIHalfSqrt  =  1.2533141373;
//natural log base
  NBase       =  2.7182818285;
  NBaseSqr    =  7.3890560989;
  NBaseSqrt   =  1.6487212707;
//conversion of angles
  DegToRad    = PI / 180;
  RadToDeg    = 180 / PI;

//assembler command extensions
function CheckSupportMMX(): Boolean;
function CheckSupportSSE(): Boolean;
function CheckSupportSSE2(): Boolean;
function CheckSupportSSE3(): Boolean;

//min/max for integer
function Min( A, B: Integer ): Integer; overload; inline;
function Max( A, B: Integer ): Integer; overload; inline;
//min/max for single
function Min( A, B: Single  ): Single;  overload; inline;
function Max( A, B: Single  ): Single;  overload; inline;
//min/max for double
function Min( A, B: Double ): Double;   overload; inline;
function Max( A, B: Double ): Double;   overload; inline;

type
  pVec2f = ^rVec2f;
  rVec2f = packed record
    {$IFDEF SMATH_ZGL_CHIPMUNK_SUPPORT}
      class operator Implicit( A: rVec2f ): cpVect;
    {$ENDIF}
    {$IFDEF SMATH_ZENGL_SUPPORT}
      class operator Implicit( A: rVec2f ): zglTPoint2D;
    {$ENDIF}
    class operator Add     ( A, B: rVec2f ): rVec2f;                    inline;
    class operator Subtract( A, B: rVec2f ): rVec2f;                    inline;
    class operator Multiply( A: rVec2f; S: Single ): rVec2f;  overload; inline;
    class operator Multiply( S: Single; A: rVec2f ): rVec2f;  overload; inline;
    class operator Multiply( A, B: rVec2f ): rVec2f;          overload; inline;
    class operator Divide  ( A, B: rVec2f ): rVec2f;          overload; inline;
    class operator Divide  ( A: rVec2f; S: Single ): rVec2f;  overload; inline;
    class operator Negative( A: rVec2f ): rVec2f;                       inline;
    class operator Positive( A: rVec2f ): rVec2f;                       inline;
    class operator Equal   ( A, B: rVec2f ): Boolean;                   inline;
    class operator NotEqual( A, B: rVec2f ): Boolean;                   inline;

    procedure SetValue  ( _X, _Y: Single );                   overload; inline;
    procedure SetValue  ( _X, _Y: Integer );                  overload; inline;
    function  Length    (): Single;                                     inline;
    function  LengthSqr (): Single;                                     inline;
    procedure Normalize ();                                             inline;
    function  Normalized(): rVec2f;                                     inline;
    function  Dot       ( V: rVec2f ): Single;                          inline;  
    function  Cross     ( V: rVec2f ): Single;                          inline;
    function  Angle     ( V: rVec2f ): Single;                          inline;
    function  Perp      (): rVec2f;                                     inline;
    function  RPerp     (): rVec2f;                                     inline;
    function  Rotate    ( Angle: Single ): rVec2f;                      inline;
    function  UnRotate  ( Angle: Single ): rVec2f;                      inline;
    function  Lerp      ( toV: rVec2f; t: Single ): rVec2f;             inline;
    //distance
    //reflect?
    //project
    //cmplx rotate
    //cmplx unrotate
    //cmplx rotate s
    //cmplx unrotate s
    //clamp
    //spherical linearly interpolate
    //spherical linearly interpolate by distance   
    //const??? 
    
    case integer of
      0: (X, Y: Single);
      1: (Arr: array [ 0 .. 1 ] of Single);
  end;

  pArrayOfVec2f = ^aArrayOfVec2f;
  aArrayOfVec2f = array of rVec2f;

  pVec2i = ^rVec2i;
  rVec2i = packed record
    class operator Implicit( A: rVec2i ): rVec2f;                       inline;
    class operator Add     ( A, B: rVec2i ): rVec2i;                    inline;
    class operator Subtract( A, B: rVec2i ): rVec2i;                    inline;
    class operator Multiply( A: rVec2i; I: integer ): rVec2i; overload; inline;
    class operator Multiply( A: rVec2i; S: single  ): rVec2f; overload; inline;
    class operator Multiply( A, B: rVec2i ): rVec2i;          overload; inline;
    class operator Divide  ( A, B: rVec2i ): rVec2i;          overload; inline;
    class operator Divide  ( A: rVec2i; I: Integer ): rVec2i; overload; inline;
    class operator Negative( A: rVec2i ): rVec2i;                       inline;
    class operator Positive( A: rVec2i ): rVec2i;                       inline;
    class operator Equal   ( A, B: rVec2i ): Boolean;                   inline;
    class operator NotEqual( A, B: rVec2i ): Boolean;                   inline;

    case integer of
      0: (X, Y: integer);
      1: (Arr: array [ 0 .. 1 ] of integer);
  end;

  pVec3f = ^rVec3f;
  rVec3f = packed record
    class operator Add     ( A, B: rVec3f ): rVec3f;            inline;
    class operator Subtract( A, B: rVec3f ): rVec3f;            inline;
    class operator Multiply( Vec: rVec3f; S: Single ): rVec3f;  inline;

    case integer of
      0: (X, Y, Z: Single);
      1: (Arr: array [ 0 .. 2 ] of Single);
  end;

  pVec4f = ^rVec4f;
  rVec4f = packed record
    class operator Add     ( A, B: rVec4f ): rVec4f;                    inline;
    class operator Subtract( A, B: rVec4f ): rVec4f;                    inline;
    class operator Multiply( A: rVec4f; S: Single ): rVec4f;  overload; inline;
    class operator Multiply( S: Single; A: rVec4f ): rVec4f;  overload; inline;
    class operator Multiply( A, B: rVec4f ): rVec4f;          overload; inline;

    case integer of
      0: (X, Y, Z, W: Single);
      1: (Arr: array[ 0 .. 3 ] of Single);
  end;

  pRectf = ^rRectf;
  rRectf = record     /////неправильно работают проперти
      A, B: rVec2f;
    private
      function  GetX      (): Single;
      function  GetY      (): Single;
      procedure SetX      ( _x: Single );
      procedure SetY      ( _y: Single );
      function  GetWidth  (): Single;
      function  GetHeight (): Single;
      procedure SetWidth  ( w: Single );
      procedure SetHeight ( h: Single );
      function  GetCenter (): rVec2f;
      procedure SetCenter ( _c: rVec2f );
    public
      property X      : Single read GetX      write SetX;
      property Y      : Single read GetY      write SetY;
      property Width  : Single read GetWidth  write SetWidth;
      property Height : Single read GetHeight write SetHeight;
      property Center : rVec2f read GetCenter write SetCenter;
  end;

  pRect = ^rRect;
  rRect = rRectf;

  pCirclef = ^rCirclef;
  rCirclef = packed record
    Pos   : rVec2f;
    Radius: Single;
  end;

  pCircle = ^rCircle;
  rCircle = rCirclef;

  pLine2f = ^rLine2f;
  rLine2f = record
    N: rVec2f;
    D: Single;
  end;

  rMatrix4f = ^aMatrix4f;
  aMatrix4f = array [ 0 .. 3 ] of array [ 0 .. 3 ] of Single;

  TPoly2f = class
    private
      FPoints: array of rVec2f;
      function  GetCount: Integer;
      procedure SetCount( Count: Integer );
      function  GetPoint( Index: Integer ): rVec2f;
      procedure SetPoint( Index: Integer; const Point: rVec2f );
    public
      constructor Create;
      destructor  Destroy; override;

      procedure Add( const Point: rVec2f );
      function  AsArray: aArrayOfVec2f;
      property  Count: Integer read GetCount write SetCount;
      property  Points[ Index: Integer ]: rVec2f read GetPoint write SetPoint; default;
  end;

const
  Vec2fZero : rVec2f = ( X: 0; Y: 0; );
  Vec2iZero : rVec2i = ( X: 0; Y: 0; );
  Vec3fZero : rVec3f = ( X: 0; Y: 0; Z: 0; );
  Vec4fZero : rVec4f = ( X: 0; Y: 0; Z: 0; W: 0 );
  
  function Vec2i( A, B: Integer ): rVec2i;
  function Len2i( A: rVec2i ): Single;
  function Dot2i( A, B: rVec2i ): Integer;
  function Round2f( V: rVec2f ): rVec2i;
  
  function Vec2f( A, B: Single ): rVec2f; overload;
  function Vec2f( V: rVec2i ): rVec2f;    overload;
  function Len2f( A: rVec2f ): Single;
  function Dot2f( A, B: rVec2f ): Single;
  function Norm2f( V: rVec2f ): rVec2f;
  function Rotate2f( const V: rVec2f; Angle: Single ): rVec2f;
  function GetNormal2f( const A, B: rVec2f ): rVec2f;

  function Vec3f( A, B, C: Single ): rVec3f;

  function Vec4f( A, B, C, D: Single ): rVec4f;

  function Rect( A, B: rVec2f ): rRect;

  function Line2f( Vec: rVec2f; S: Single ): rLine2f;   overload;
  function Line2f( A, B: rVec2f ): rLine2f;             overload;
  function Dist2f( Line: rLine2f; P: rVec2f ): Single;  overload;

  function Circle( const Pos: rVec2f; Radius: Single ): rCirclef;

  //utils
  procedure SMathSinCos( const Angle : Single; var s, c : Single ); assembler;
  
implementation

{$REGION 'Assembler Command Extensions'}
function CheckSupportMMX(): Boolean;
asm
    mov   [Result], 0;
    push  ebx;
    mov   eax,      1;
    cpuid;
    test  ecx,      00800000h
    jz    @Done;
    mov   [Result], 1;
  @Done:
    pop   ebx;
end;

function CheckSupportSSE(): Boolean;
asm
    mov   [Result], 0;
    push  ebx;
    mov   eax,      1;
    cpuid;
    test  ecx,      02000000h
    jz    @Done;
    mov   [Result], 1;
  @Done:
    pop   ebx;
end;

function CheckSupportSSE2(): Boolean;
asm
    mov   [Result], 0;
    push  ebx;
    mov   eax,      1;
    cpuid;
    test  ecx,      04000000h
    jz    @Done;
    mov   [Result], 1;
  @Done:
    pop   ebx;
end;

function CheckSupportSSE3(): Boolean;
asm
    mov   [Result], 0;
    push  ebx;
    mov   eax,      1;
    cpuid;
    test  ecx,      00000001h
    jz    @Done;
    mov   [Result], 1;
  @Done:
    pop   ebx;
end;
{$ENDREGION}

{$Region 'MinMax'}
function Min( A, B: Integer ): Integer;
begin
  if A < B then begin
    Result := A
  end else begin
    Result := B;
  end;
end;

function Max( A, B: Integer ): Integer;
begin
  if A > B then begin
    Result := A
  end else begin
    Result := B;
  end;
end;

function Min( A, B: Single ): Single;
begin
  if A < B then begin
    Result := A
  end else begin
    Result := B;
  end;
end;

function Max( A, B: Single ): Single;
begin
  if A > B then begin
    Result := A
  end else begin
    Result := B;
  end;
end;

function Min( A, B: Double ): Double;
begin
  if A < B then begin
    Result := A;
  end else begin
    Result := B;
  end;
end;

function Max( A, B: Double ): Double;
begin
  if A > B then begin
    Result := A;
  end else begin
    Result := B;
  end;
end;

{$Endregion}

{$Region 'rVec2i'}
function Vec2i( A, B: Integer ): rVec2i;
begin
  with Result do begin
    X := A;
    Y := B;
  end;
end;

class operator rVec2i.Implicit( A: rVec2i ): rVec2f;
begin
  with Result do begin
    X := A.X;
    Y := A.Y;
  end;
end;

class operator rVec2i.Add( A, B: rVec2i ): rVec2i;
begin
  with Result do begin
    X := A.X + B.X;
    Y := A.Y + B.Y;
  end;
end;

class operator rVec2i.Subtract( A, B: rVec2i ): rVec2i;
begin
  with Result do begin
    X := A.X - B.X;
    Y := A.Y - B.Y;
  end;
end;

class operator rVec2i.Multiply( A: rVec2i; I: integer ): rVec2i;
begin
  with Result do begin
    X := I * A.X;
    Y := I * A.Y;
  end;
end;

class operator rVec2i.Multiply( A: rVec2i; S: single ): rVec2f;
begin
  with Result do begin
    X := S * A.X;
    Y := S * A.Y;
  end;
end;

class operator rVec2i.Multiply( A, B: rVec2i ): rVec2i;
begin
  with Result do begin
    X := A.X * B.X;
    Y := A.Y * B.Y;
  end;
end;

class operator rVec2i.Divide( A: rVec2i; B: rVec2i ): rVec2i;
begin
  with Result do begin
    X := A.X div B.X;
    Y := A.Y div B.Y;
  end;
end;

class operator rVec2i.Divide( A: rVec2i; I: Integer ): rVec2i;
begin
  with Result do begin
    X := A.X div I;
    Y := A.Y div I;
  end;
end;

class operator rVec2i.Negative( A: rVec2i ): rVec2i;
begin
  with Result do begin
    X := -A.X;
    Y := -A.Y;
  end;
end;

class operator rVec2i.Positive( A: rVec2i ): rVec2i;
begin
  Result := A;
end;

class operator rVec2i.Equal( A, B: rVec2i ): Boolean;
begin
  Result := ( A.X = B.X ) and ( A.Y = B.Y );
end;

class operator rVec2i.NotEqual( A, B: rVec2i ): Boolean;
begin
  Result := ( A.X <> B.X ) and ( A.Y <> B.Y );
end;

function Round2f( V: rVec2f ): rVec2i;
begin
  with Result do begin
    X := Round( V.X );
    Y := Round( V.Y );
  end;
end;

function Len2i( A: rVec2i ): Single;
begin
  Result := Sqrt( Sqr( A.X ) + Sqr( A.Y ) );
end;

function Dot2i( A, B: rVec2i ): Integer;
begin
  Result := A.X * B.X + A.Y * B.Y;
end;
{$Endregion}

{$Region 'rVec2f'}
function Vec2f( A, B: Single ): rVec2f;
begin
  with Result do begin
    X := A;
    Y := B;
  end;
end;

function Vec2f( V: rVec2i ): rVec2f;
begin
  with Result do Vec2f( X, Y );
end;

{$IFDEF SMATH_ZGL_CHIPMUNK_SUPPORT}
  class operator rVec2f.Implicit( A: rVec2f ): cpVect;
  begin
    Result.x := A.X;
    Result.y := A.Y;
  end;
{$ENDIF}

{$IFDEF SMATH_ZENGL_SUPPORT}
  class operator rVec2f.Implicit( A: rVec2f ): zglTPoint2D;
  begin
    Result.X := A.X;
    Result.Y := A.Y;
  end;
{$ENDIF}

class operator rVec2f.Add( A, B: rVec2f ): rVec2f;
begin
  with Result do begin
    X := A.X + B.X;
    Y := A.Y + B.Y;
  end;
end;

class operator rVec2f.Subtract( A, B: rVec2f ): rVec2f;
begin
  with Result do begin
    X := A.X - B.X;
    Y := A.Y - B.Y;
  end;
end;

class operator rVec2f.Multiply( A: rVec2f; S: single ): rVec2f;
begin
  with Result do begin
    X := S * A.X;
    Y := S * A.Y;
  end;
end;

class operator rVec2f.Multiply( S: single; A: rVec2f ): rVec2f;
begin
  with Result do begin
    X := S * A.X;
    Y := S * A.Y;
  end;
end;

class operator rVec2f.Multiply( A, B: rVec2f ): rVec2f;
begin
  with Result do begin
    X := A.X * B.X;
    Y := A.Y * B.Y;
  end;
end;

class operator rVec2f.Divide( A: rVec2f; B: rVec2f ): rVec2f;
begin
  with Result do begin
    X := A.X / B.X;
    Y := A.Y / B.Y;
  end;
end;

class operator rVec2f.Divide( A: rVec2f; S: Single ): rVec2f;
begin
  with Result do begin
    X := A.X / S;
    Y := A.Y / S;
  end;
end;

class operator rVec2f.Negative( A: rVec2f ): rVec2f;
begin
  with Result do begin
    X := -A.X;
    Y := -A.Y;
  end;
end;

class operator rVec2f.Positive( A: rVec2f ): rVec2f;
begin
  Result := A;
end;

class operator rVec2f.Equal( A, B: rVec2f ): Boolean;
begin
  Result := ( A.X = B.X ) and ( A.Y = B.Y );
end;

class operator rVec2f.NotEqual( A, B: rVec2f ): Boolean;
begin
  Result := ( A.X <> B.X ) and ( A.Y <> B.Y );
end;

procedure rVec2f.SetValue( _X, _Y : Single );
begin
  X := _X;
  Y := _Y;
end;

procedure rVec2f.SetValue( _X, _Y: Integer );
begin
  X := _X;
  Y := _Y;
end;

function rVec2f.Length(): Single;
begin
  Result := Sqrt( Sqr( X ) + Sqr( Y ) );
end;

function rVec2f.LengthSqr(): Single;
begin
  Result := Sqr( X ) + Sqr( Y );
end;

procedure rVec2f.Normalize();
var l : Single;
begin
  l := Length;
  if l <> 0 then begin  
    x := x / l;
    y := y / l;
    //Self := Self / l; ???
  end else begin
    x := 0;
    y := 0;
  end;
end;

function rVec2f.Normalized(): rVec2f;
var l : Single;
begin
  l := Length;
  if l <> 0 then begin
    Result.X := x / l;
    Result.Y := y / l;  
  end else begin
    Result.X := 0;
    Result.Y := 0;
  end;         
  //Result := Self / Length; ???
end;

function  rVec2f.Dot( V: rVec2f ): Single;
begin
  Result := X * V.X + Y * V.Y;
end;

function  rVec2f.Cross( V: rVec2f ): Single;
begin
  Result := X * V.Y + Y * V.X;
end;

function  rVec2f.Angle( V: rVec2f ): Single;
var jlen : Single;
begin
  jlen := Length * V.Length;
  if jlen > 0 then begin
    Result := ArcCos( Dot( V ) / jlen );
  end else begin
    Result := 0;
  end;
end;

function  rVec2f.Perp(): rVec2f;
begin
  Result.X := -Y;
  Result.Y := X;
end;

function  rVec2f.RPerp(): rVec2f; 
begin
  Result.X := Y;
  Result.Y := X;
end;

function rVec2f.Rotate(Angle: Single): rVec2f;
var s, c : Single;
begin
  SMathSinCos( Angle, s, c );
  Result.X := X * c - Y * s;
  Result.Y := Y * c - X * s;
end;

function rVec2f.UnRotate(Angle: Single): rVec2f;
var s, c : Single;
begin
  SMathSinCos( -Angle, s, c );
  Result.X := X * c - Y * s;
  Result.Y := Y * c - X * s;
end;

function rVec2f.Lerp(toV: rVec2f; t: Single): rVec2f;
begin
  Result := Self + ( toV - Self ) * t;
end;

function Len2f( A: rVec2f ): Single;
begin
  Result := Sqrt( Sqr( A.X ) + Sqr( A.Y ) );
end;

function Dot2f( A, B: rVec2f ): Single;
begin
  Result := A.X * B.X  +  A.Y * B.Y;
end;

function Norm2f( V: rVec2f ): rVec2f;
begin
  Result := V / Len2f( V );
end;

function Rotate2f( const V: rVec2f; Angle: Single ): rVec2f;
var C, S: Single;
begin
  C := Cos( Angle );
  S := Sin( Angle );
  Rotate2f.X := C * V.X  -  S * V.Y;
  Rotate2f.Y := C * V.Y  +  S * V.X;
end;

function GetNormal2f( const A, B: rVec2f ): rVec2f;
begin
  Result := B - A;
  Result := Vec2f( -Result.Y, Result.X );
end;
{$Endregion}

{$Region 'rVec3f'}
function Vec3f( A, B, C: Single ): rVec3f;
begin
  with Result do begin
    X := A;
    Y := B;
    Z := C;
  end;
end;

class operator rVec3f.Add( A: rVec3f; B: rVec3f ): rVec3f;
begin
  with Result do begin
    X := A.X + B.X;
    Y := A.Y + B.Y;
    Z := A.Z + B.Z;
  end;
end;

class operator rVec3f.Subtract( A: rVec3f; B: rVec3f ): rVec3f;
begin
  with Result do begin
    X := A.X - B.X;
    Y := A.Y - B.Y;
    Z := A.Z - B.Z;
  end;
end;

class operator rVec3f.Multiply( Vec: rVec3f; S: Single ): rVec3f;
begin
  with Result do begin
    X := Vec.X * S;
    Y := Vec.Y * S;
    Z := Vec.Z * S;
  end;
end;
{$Endregion}

{$Region 'rVec4f'}
function Vec4f( A, B, C, D: Single ): rVec4f;
begin
  with Result do begin
    X := A;
    Y := B;
    Z := C;
    W := D;
  end;
end;

class operator rVec4f.Add( A, B: rVec4f ): rVec4f;
begin
  with Result do begin
    X := A.X + B.X;
    Y := A.Y + B.Y;
    Z := A.Z + B.Z;
    W := A.W + B.W;
  end;
end;

class operator rVec4f.Subtract( A, B: rVec4f ): rVec4f;
begin
  with Result do begin
    X := A.X - B.X;
    Y := A.Y - B.Y;
    Z := A.Z - B.Z;
    W := A.W - B.W;
  end;
end;

class operator rVec4f.Multiply( A: rVec4f; S: Single ): rVec4f;
begin
  with Result do begin
    X := A.X * S;
    Y := A.Y * S;
    Z := A.Z * S;
    W := A.W * S;
  end;
end;

class operator rVec4f.Multiply( S: Single; A: rVec4f ): rVec4f;
begin
  with Result do begin
    X := A.X * S;
    Y := A.Y * S;
    Z := A.Z * S;
    W := A.W * S;
  end;
end;

class operator rVec4f.Multiply( A, B: rVec4f ): rVec4f;
begin
  with Result do begin
    X := A.X * B.X;
    Y := A.Y * B.Y;
    Z := A.Z * B.Z;
    W := A.W * B.W;
  end;
end;
{$Endregion}

{$Region 'rRect'}
function rRectf.GetX(): Single;
begin
  //Result := Min( A.X, B.X );
  if A.X < B.X then Result := A.X else Result := B.X;  
end;

function rRectf.GetY(): Single;
begin
  //Result := Min( A.Y, B.Y );
  if A.Y < B.Y then Result := A.Y else Result := B.Y;
end;

procedure rRectf.SetX(_x: Single);
begin
  if A.X < B.X then A.X := _x else B.X := _x;
end;

procedure rRectf.SetY(_y: Single);
begin
  if A.Y < B.Y then A.Y := _y else B.Y := _y;
end;

function rRectf.GetWidth(): Single;
begin
  Result := Abs( B.X - A.X );
end;

function rRectf.GetHeight(): Single;
begin
  Result := Abs( B.Y - A.Y );
end;

procedure rRectf.SetWidth(w: Single);
begin
  if A.X < B.X then B.X := A.X + w else A.X := B.X + w;
end;

procedure rRectf.SetHeight(h: Single);
begin
  if A.Y < B.Y then B.Y := A.Y + h else A.Y := B.Y + h;
end;

function rRectf.GetCenter(): rVec2f;
begin
  Result := Vec2f( X, Y ) + Vec2f( Width, Height ) * 0.5;
end;

procedure rRectf.SetCenter(_c: rVec2f);
begin
  X := _c.X - Width  * 0.5;
  Y := _c.Y - Height * 0.5;
end;

function Rect( A, B: rVec2f ): rRect;
begin
  Rect.A := A;
  Rect.B := B;
end;
{$Endregion}

{$Region 'rLine2f'}
function Line2f( Vec: rVec2f; S: Single ): rLine2f;
begin
  with Result do begin
    N := Vec;
    D := S;
  end;
end;

function Line2f( A, B: rVec2f ): rLine2f;
begin
  with Result do begin
    N := ( B - A ) / Len2f( B - A );
    N := Vec2f( -Result.N.Y, Result.N.X );
    D := - Dot2f( A, Result.N );
  end;
end;

function Dist2f( Line: rLine2f; P: rVec2f ): Single; overload;
begin
  Result := Dot2f( Line.N, P ) + Line.D;
end;
{$Endregion}

{$REGION 'TPoly2f'}
function TPoly2f.GetCount: Integer;
begin
  GetCount := Length( FPoints );
end;

procedure TPoly2f.SetCount( Count: Integer );
begin
  SetLength( FPoints, Count );
end;

function TPoly2f.GetPoint( Index: Integer ): rVec2f;
begin
  if Count > 0 then
    GetPoint := FPoints[ Index mod Count ]
  else
    GetPoint := Vec2f( 0, 0 );
end;

procedure TPoly2f.SetPoint( Index: Integer; const Point: rVec2f );
begin
  if Count > 0 then
    FPoints[ Index mod Count ] := Point;
end;

constructor TPoly2f.Create;
begin
  SetLength( FPoints, 0 );
end;

destructor TPoly2f.Destroy;
begin
end;

procedure TPoly2f.Add( const Point: rVec2f );
begin
  Count := Count + 1;
  FPoints[ Count - 1 ] := Point;
end;

function TPoly2f.AsArray: aArrayOfVec2f;
var I: Integer;
begin
  SetLength( Result, Count );
  for I := 0 to Count - 1 do Result[ I ] := FPoints[ I ];
end;
{$ENDREGION}

function Circle( const Pos: rVec2f; Radius: Single ): rCirclef;
begin
  Circle.Pos    := Pos;
  Circle.Radius := Radius;
end;

//utils
procedure SMathSinCos( const Angle : Single; var s, c : Single );
asm
  fld Angle
  fsincos
  fstp [edx]
  fstp [eax]
  fwait
end;

initialization

end.
