///////////////////////////////////////////////////////////////////////
// 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 G2D_PRIMITIVES;

{$I DEFINES.pas}

interface
uses
  OpenGL,

  ENGINE_VAR,
  ENGINE_SCREEN,

  G2D_FX,
  ENGINE_FLAGS,

  G2D_CAMERA,

  MATH_FAST;

type
  oePoint = record
    X, Y : Single;
end;
oePPoint = ^oePoint;

type
  oePointCA = record
    X, Y  : Single;
    Color : Integer;
    Alpha : Byte;
end;
oePPointCA = ^oePointCA;

type
  oeLine = record
    x0, y0 : Single;
    x1, y1 : Single;
end;
oePLine = ^oeLine;

type
  oeRect = record
    X      : Single;
    Y      : Single;
    Width  : Single;
    Height : Single;
end;
oePRect = ^oeRect;

type
  oeTriangle = record
    X1, Y1 : Single;
    X2, Y2 : Single;
    X3, Y3 : Single;
end;
oePTriangle = ^oeTriangle;

type
  oeCircle = record
    cX, cY : Single;
    Radius : Single;
end;
oePCircle = ^oeCircle;

const
  PR_FILL   = $000001;
  PR_SMOOTH = $000002;

var
  PixelSize : Integer;
  LineWidth : Integer;


procedure Pr2D_PixelSize( Size : Integer ); stdcall;

procedure Pr2D_LineWidth( Width : Integer ); stdcall;

procedure Pr2D_Pixel(
                      X, Y  : Single;
                      Color : Integer;
                      Alpha : Byte
                    ); stdcall;

procedure Pr2D_Line(
                     X1, Y1 : Single;
                     X2, Y2 : Single;
                     Color  : Integer;
                     Alpha  : Byte;
                     Flags  : Integer
                   ); stdcall;
procedure Pr2D_TLine(
                      Line  : oePLine;
                      Color : Integer;
                      Alpha : Byte;
                      Flags : Integer
                    ); stdcall;


procedure Pr2D_Rect(
                     X, Y          : Single;
                     Width, Height : Single;
                     Color         : Integer;
                     Alpha         : Byte;
                     Flags         : Integer
                   ); stdcall;
procedure Pr2D_TRect(
                      Rectangle : oePRect;
                      Color     : Integer;
                      Alpha     : Byte;
                      Flags     : Integer
                    ); stdcall;


procedure Pr2D_Triangle(
                         X1, Y1  : Single;
                         X2, Y2  : Single;
                         X3, Y3  : Single;
                         Color   : Integer;
                         Alpha   : Byte;
                         Flags   : Integer
                       ); stdcall;
procedure Pr2D_TTriangle(
                          Triangle : oePTriangle;
                          Color    : Integer;
                          Alpha    : Byte;
                          Flags    : Integer
                        ); stdcall;

procedure Pr2D_Circle(
                       cX, cY  : Single;
                       Radius  : Single;
                       Color   : Integer;
                       Alpha   : Byte;
                       Quality : Integer;
                       Flags   : Integer
                     ); stdcall;
procedure Pr2D_TCircle(
                        Circle  : oePCircle;
                        Color   : Integer;
                        Alpha   : Byte;
                        Quality : Integer;
                        Flags   : Integer
                     ); stdcall;
procedure Pr2D_Ellipse(
                        cX, cY  : Single;
                        xRadius : Single;
                        yRadius : Single;
                        Color   : Integer;
                        Alpha   : Byte;
                        Quality : Integer;
                        Flags   : Integer
                     ); stdcall;

procedure Pr2D_Polygon(
                        Points : array of oePoint;
                        PCount : Integer;
                        Color  : Integer;
                        Alpha  : Byte;
                        Flags  : Integer
                      ); stdcall;
procedure Pr2D_PolygonCA(
                          Points : array of oePointCA;
                          PCount : Integer;
                          Flags  : Integer
                        ); stdcall;

//----------------------------------------------------------------------------//
                                 IMPLEMENTATION
//----------------------------------------------------------------------------//
uses
  COLLISION_MAIN;

procedure Pr2D_PixelSize;
Begin
PixelSize := Size;
glPointSize( Size );
End;

procedure Pr2D_LineWidth;
Begin
LineWidth := Width;
glLineWidth( Width );
End;

procedure Pr2D_Pixel;
Begin
Y := Y + 1;
if Cam2D^.Active Then
  begin
    X := X - Cam2D^.X;
    Y := Y - Cam2D^.Y;
  end;

if F_CropUnvisibleObj = 1 Then
  if not ( ( X >= CropX ) and ( X <= CropW ) and
           ( Y >= CropY ) and ( Y <= CropH ) ) Then Exit;

glPushMatrix;

if F_ResolutionCorrect = 1 Then
  glScalef( scr_ScaleX, scr_ScaleY, 1 );

glColor4ub(
            (   Color and $FF              ),
            ( ( Color and $FF00   ) shr 8  ),
            ( ( Color and $FF0000 ) shr 16 ),
                Alpha
         );
glEnable( GL_BLEND );
glBegin( GL_POINTS );
  glVertex2f( X, Y );
glEnd;
glDisable( GL_BLEND );

glPopMatrix;

End;

procedure Pr2D_Line;
Begin
Y1 := Y1 + 1;
Y2 := Y2 + 1;
if Cam2D^.Active Then
  begin
    X1 := X1 - Cam2D^.X;
    Y1 := Y1 - Cam2D^.Y;
    X2 := X2 - Cam2D^.X;
    Y2 := Y2 - Cam2D^.Y;
  end;

if F_CropUnvisibleObj = 1 Then
  if ( ( ( X1 < CropX ) and ( X2 < CropX ) ) or ( ( X1 > CropW ) and ( X2 > CropW ) ) ) or
     ( ( ( Y1 < CropY ) and ( Y2 < CropY ) ) or ( ( Y1 > CropH ) and ( Y2 > CropH ) ) ) Then Exit;

glPushMatrix;

if F_ResolutionCorrect = 1 Then
  glScalef( scr_ScaleX, scr_ScaleY, 1 );

glColor4ub(
            (   Color and $FF              ),
            ( ( Color and $FF00   ) shr 8  ),
            ( ( Color and $FF0000 ) shr 16 ),
                Alpha
         );

if Flags and PR_SMOOTH > 0 Then
  glEnable( GL_LINE_SMOOTH );

glEnable( GL_BLEND );
glBegin( GL_LINES );
  if Flags and FX_VCA > 0 Then glColor4ub( FX_VR1, FX_VG1, FX_VB1, FX_VA1 );
  glVertex2f( X1, Y1 );
  if Flags and FX_VCA > 0 Then glColor4ub( FX_VR2, FX_VG2, FX_VB2, FX_VA2 );
  glVertex2f( X2, Y2 );
glEnd;
glDisable( GL_BLEND );

if Flags and PR_SMOOTH > 0 Then
  glDisable( GL_LINE_SMOOTH );

glPopMatrix;

End;

procedure Pr2D_TLine;
Begin
Pr2D_Line( Line^.x0, Line^.y0, Line^.x1, Line^.y1, Color, Alpha, Flags );
End;

procedure Pr2D_Rect;
Begin
Y := Y + 1;
if Flags and PR_FILL > 0 Then
  begin
    Y := Y - 1;
    Width := Width + 1;
    Height := Height + 1;
  end;

if Cam2D^.Active Then                                   
  begin
    X := X - Cam2D^.X;
    Y := Y - Cam2D^.Y;
  end;

if F_CropUnvisibleObj = 1 Then
  if not ( ( X + Width  >= CropX ) and ( X <= CropW ) and
           ( Y + Height >= CropY ) and ( Y <= CropH ) ) Then Exit;

glPushMatrix;

if F_ResolutionCorrect = 1 Then
  glScalef( scr_ScaleX, scr_ScaleY, 1 );

glColor4ub(
            (   Color and $FF              ),
            ( ( Color and $FF00   ) shr 8  ),
            ( ( Color and $FF0000 ) shr 16 ),
                Alpha
         );

if Flags and PR_FILL = 0 Then
  glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );

glEnable( GL_BLEND );
glBegin( GL_QUADS );
  if Flags and FX_VCA > 0 Then glColor4ub( FX_VR1, FX_VG1, FX_VB1, FX_VA1 );
  glVertex2f( X,         Y          );
  if Flags and FX_VCA > 0 Then glColor4ub( FX_VR2, FX_VG2, FX_VB2, FX_VA2 );
  glVertex2f( X + Width, Y          );
  if Flags and FX_VCA > 0 Then glColor4ub( FX_VR3, FX_VG3, FX_VB3, FX_VA3 );
  glVertex2f( X + Width, Y + Height );
  if Flags and FX_VCA > 0 Then glColor4ub( FX_VR4, FX_VG4, FX_VB4, FX_VA4 );
  glVertex2f( X,         Y + Height );
glEnd;
glDisable( GL_BLEND );

if Flags and PR_FILL = 0 Then
  glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );

glPopMatrix;

End;

procedure Pr2D_TRect;
Begin
Pr2D_Rect( Rectangle^.X, Rectangle^.Y, Rectangle^.Width, Rectangle^.Height, Color, Alpha, Flags );
End;

procedure Pr2D_Triangle;
Begin
Y1 := Y1 + 1;
Y2 := Y2 + 1;
Y3 := Y3 + 1;
if Cam2D^.Active Then
  begin
    X1 := X1 - Cam2D^.X;
    Y1 := Y1 - Cam2D^.Y;
    X2 := X2 - Cam2D^.X;
    Y2 := Y2 - Cam2D^.Y;
    X3 := X3 - Cam2D^.X;
    Y3 := Y3 - Cam2D^.Y;
  end;

if F_CropUnvisibleObj = 1 Then
  if ( ( ( X1 < CropX ) and ( X2 < CropX ) and ( X3 < CropX ) ) or
       ( ( X1 > CropW ) and ( X2 > CropW ) and ( X3 > CropW ) ) ) or
     ( ( ( Y1 < CropY ) and ( Y2 < CropY ) and ( Y3 < CropY ) ) or
       ( ( Y1 > CropH ) and ( Y2 > CropH ) and ( Y3 > CropH ) ) ) Then Exit;

glPushMatrix;

if F_ResolutionCorrect = 1 Then
  glScalef( scr_ScaleX, scr_ScaleY, 1 );

glColor4ub(
            (   Color and $FF              ),
            ( ( Color and $FF00   ) shr 8  ),
            ( ( Color and $FF0000 ) shr 16 ),
                Alpha
         );

if Flags and PR_FILL = 0 Then
  glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
if Flags and PR_SMOOTH > 0 Then
  begin
    glEnable( GL_LINE_SMOOTH    );
    glEnable( GL_POLYGON_SMOOTH );
  end;

glEnable( GL_BLEND );
glBegin( GL_TRIANGLES );
  if Flags and FX_VCA > 0 Then glColor4ub( FX_VR1, FX_VG1, FX_VB1, FX_VA1 );
  glVertex2f( X1, Y1 );
  if Flags and FX_VCA > 0 Then glColor4ub( FX_VR2, FX_VG2, FX_VB2, FX_VA2 );
  glVertex2f( X2, Y2 );
  if Flags and FX_VCA > 0 Then glColor4ub( FX_VR3, FX_VG3, FX_VB3, FX_VA3 );
  glVertex2f( X3, Y3 );
glEnd;
glDisable( GL_BLEND );

if Flags and PR_FILL = 0 Then
  glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
if Flags and PR_SMOOTH > 0 Then
  begin
    glDisable( GL_LINE_SMOOTH    );
    glDisable( GL_POLYGON_SMOOTH );
  end;

glPopMatrix;

End;

procedure Pr2D_TTriangle;
Begin
Pr2D_Triangle( Triangle^.X1, Triangle^.Y1,
               Triangle^.X2, Triangle^.Y2,
               Triangle^.X3, Triangle^.Y3,
               Color, Alpha, Flags );
End;

procedure Pr2D_Circle;
  var
    i : Integer;
    k : Single;
Begin
cY := cY + 1;
if Cam2D^.Active Then
  begin
    cX := cX - Cam2D^.X;
    cY := cY - Cam2D^.Y;
  end;

if F_CropUnvisibleObj = 1 Then
  if ( cX + Radius < CropX ) or ( cX - Radius > CropW ) or
     ( cY + Radius < CropY ) or ( cY - Radius > CropH ) Then Exit;

glPushMatrix;

if F_ResolutionCorrect = 1 Then
  glScalef( scr_ScaleX, scr_ScaleY, 1 );

glColor4ub(
            (   Color and $FF              ),
            ( ( Color and $FF00   ) shr 8  ),
            ( ( Color and $FF0000 ) shr 16 ),
                Alpha
         );

if Flags and PR_FILL = 0 Then
  glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
if Flags and PR_SMOOTH > 0 Then
  begin
    glEnable( GL_LINE_SMOOTH    );
    glEnable( GL_POLYGON_SMOOTH );
  end;

if Quality > 360 Then Quality := 360;
k := 360 / Quality;
glEnable( GL_BLEND );
glBegin( GL_POLYGON );

  glVertex2f( cX + Radius, cY );
  for i := 0 to Quality do
    glVertex2f(
                cX + Radius * CosTable[ M_Round( i * k ) ],
                cY + Radius * SinTable[ M_Round( i * k ) ]
              );
glEnd;

if Flags and PR_FILL = 0 Then
  glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
if Flags and PR_SMOOTH > 0 Then
  begin
    glDisable( GL_LINE_SMOOTH    );
    glDisable( GL_POLYGON_SMOOTH );
  end;

glPopMatrix;

End;

procedure Pr2D_TCircle;
Begin
Pr2D_Circle( Circle^.cX, Circle^.cY, Circle^.Radius, Color, Alpha, Quality, Flags );
End;

procedure Pr2D_Ellipse;
  var
    i : Integer;
    k : Single;
Begin
cY := cY + 1;
if Cam2D^.Active Then
  begin
    cX := cX - Cam2D^.X;
    cY := cY - Cam2D^.Y;
  end;

if F_CropUnvisibleObj = 1 Then
  if ( cX + xRadius < CropX ) or ( cX - xRadius > CropW ) or
     ( cY + yRadius < CropY ) or ( cY - yRadius > CropH ) Then Exit;

glPushMatrix;

if F_ResolutionCorrect = 1 Then
  glScalef( scr_ScaleX, scr_ScaleY, 1 );

glColor4ub(
            (   Color and $FF              ),
            ( ( Color and $FF00   ) shr 8  ),
            ( ( Color and $FF0000 ) shr 16 ),
                Alpha
         );

if Flags and PR_FILL = 0 Then
  glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
if Flags and PR_SMOOTH > 0 Then
  begin
    glEnable( GL_LINE_SMOOTH    );
    glEnable( GL_POLYGON_SMOOTH );
  end;

if Quality > 360 Then Quality := 360;
k := 360 / Quality;
glEnable( GL_BLEND );
glBegin( GL_POLYGON );

  glVertex2f( cX + xRadius, cY );
  for i := 0 to Quality do
    glVertex2f(
                cX + xRadius * CosTable[ M_Round( i * k ) ],
                cY + yRadius * SinTable[ M_Round( i * k ) ]
              );
glEnd;

if Flags and PR_FILL = 0 Then
  glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
if Flags and PR_SMOOTH > 0 Then
  begin
    glDisable( GL_LINE_SMOOTH    );
    glDisable( GL_POLYGON_SMOOTH );
  end;

glPopMatrix;

End;

procedure Pr2D_Polygon;
  var
    i : Integer;
Begin
if F_ResolutionCorrect = 1 Then
  for i := 0 to PCount do
    begin
      Points[ i ].X := Points[ i ].X * scr_ScaleX;
      Points[ i ].Y := Points[ i ].Y * scr_ScaleY;
    end;

glColor4ub(
            (   Color and $FF              ),
            ( ( Color and $FF00   ) shr 8  ),
            ( ( Color and $FF0000 ) shr 16 ),
                Alpha
         );

if Flags and PR_FILL = 0 Then
  glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
if Flags and PR_SMOOTH > 0 Then
  begin
    glEnable( GL_LINE_SMOOTH    );
    glEnable( GL_POLYGON_SMOOTH );
  end;

glEnable( GL_BLEND );

glBegin( GL_POLYGON );
if Cam2D^.Active Then
  for i := 0 to PCount do
    glVertex2f( Points[ i ].X - Cam2D^.X, Points[ i ].Y + 1 - Cam2D^.Y )
else
  for i := 0 to PCount do
    glVertex2f( Points[ i ].X, Points[ i ].Y + 1 );
glEnd;

glDisable( GL_BLEND );

if Flags and PR_FILL = 0 Then
  glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
if Flags and PR_SMOOTH > 0 Then
  begin
    glDisable( GL_LINE_SMOOTH    );
    glDisable( GL_POLYGON_SMOOTH );
  end;

End;

procedure Pr2D_PolygonCA;
  var
    i : Integer;
Begin
if F_ResolutionCorrect = 1 Then
  for i := 0 to PCount do
    begin
      Points[ i ].X := Points[ i ].X * scr_ScaleX;
      Points[ i ].Y := Points[ i ].Y * scr_ScaleY;
    end;

if Flags and PR_FILL = 0 Then
  glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
if Flags and PR_SMOOTH > 0 Then
  begin
    glEnable( GL_LINE_SMOOTH    );
    glEnable( GL_POLYGON_SMOOTH );
  end;

glEnable( GL_BLEND );

glBegin( GL_POLYGON );
if Cam2D^.Active Then
  for i := 0 to PCount do
    begin
      glColor4ub(
                  (   Points[ i ].Color and $FF              ),
                  ( ( Points[ i ].Color and $FF00   ) shr 8  ),
                  ( ( Points[ i ].Color and $FF0000 ) shr 16 ),
                      Points[ i ].Alpha
                );
      glVertex2f( Points[ i ].X - Cam2D^.X, Points[ i ].Y + 1 - Cam2D^.Y );
    end
else
  for i := 0 to PCount do
    begin
      glColor4ub(
                  (   Points[ i ].Color and $FF              ),
                  ( ( Points[ i ].Color and $FF00   ) shr 8  ),
                  ( ( Points[ i ].Color and $FF0000 ) shr 16 ),
                      Points[ i ].Alpha
                );
      glVertex2f( Points[ i ].X, Points[ i ].Y + 1 );
    end;
glEnd;

glDisable( GL_BLEND );

if Flags and PR_FILL = 0 Then
  glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
if Flags and PR_SMOOTH > 0 Then
  begin
    glDisable( GL_LINE_SMOOTH    );
    glDisable( GL_POLYGON_SMOOTH );
  end;

End;

end.
