{$MODE delphi}
{$I deng_defines.inc}
unit DDraw;

interface

uses
  {$IFDEF DENG_USE_DRAW_OPENGL}{$IFDEF ANDROID}GLES,{$ELSE}GL,glext,{$ENDIF}{$ENDIF}
  {$IFDEF DENG_USE_DRAW_VULKAN}vulkan,{$ENDIF}
  {$IFDEF MSWINDOWS}windows,{$ENDIF}
  DEngBase,
  DWinApi,
  dtypes,
  dcolors,
  dmath,
  dintersect,
  dvector2i,
  drect2i,
  drect2f,
  dvector2f,
  dvector3f,
  dvector4f,
  dquat4f,
  dmatrix4f;

{$IFDEF DENG_USE_DRAW_OPENGL}
const
  DENG_USE_DRAW_OPENGL = True;
{$ENDIF}
{$IFDEF DENG_USE_DRAW_VULKAN}
const
  DENG_USE_DRAW_VULKAN = True;
{$ENDIF}

type
PDraw = ^TDraw;
TGraph = PDraw;
TDraw = object
private
  FWinApi: PWinApi;
  FCursor: TVec2i;
  FWidth: Float;
  {$IFDEF ANDROID}
  FColor: Cardinal;
  //FShader: TShader;
  FProjection: TMat4f;
  procedure glOrtho(Left, Right, Bottom, Top, NearVal, FarVal: Double);
  {$ENDIF}
  function GetCircleSegments(R: Single): Integer; static;
public type
  TBlendMode = DEngBase.TBlendMode;
public
  //
  constructor Init(WinApi: PWinApi);
  destructor Done; virtual;
  //
  procedure OnInit;
  //
  function IsOpenGL: Boolean; inline;
  function IsVulkan: Boolean; inline;
  //
  procedure BeginRender;
  procedure EndRender;
  procedure Start2D; overload;
  procedure Start2D(const Pos, Size: TVec2i); overload;
  procedure Start2D(const Pos: TVec2i; Coeff: Single); overload;
  procedure End2D;
  procedure Start3D(FOVYInDegrees: Single = 90;
                    Aspect: Single = 0;
                    ZNear: Single = 0.1;
                    ZFar: Single = 1000.0); overload;
  procedure End3D;
  // color
  class procedure SetColor(const Color: TVec4f);
  // old prototypes, must be removed
  procedure DrawPixel(const P: TVec2i; const Color: TVec4f); deprecated 'use Pixel instead';
  procedure DrawLine(const P1, P2: TVec2i; const Color: TVec4f); deprecated 'use Line instead';
  procedure DrawRect(const P1, P2: TVec2i; const Color: TVec4f); deprecated 'use Rect instead';
  procedure DrawCircle(const P: TVec2f; R: Single; const Color: TVec4f); deprecated 'use Circle instead';
  procedure DrawBuffer(X, Y, W, H: Integer; Data: Pointer); deprecated 'use Buffer instead';
  procedure SetBlendMode(Mode: TBlendMode); deprecated 'use BlendMode instead';
  // low level
  procedure Pixel(const P: TVec2i; const Color: TVec4f); overload;
  procedure Pixel(X, Y: LongInt; const Color: Cardinal); overload;
  // primitives status
  function Color(const Value: TVec4f): TDraw; inline overload;
  function Color(const Value: Cardinal): TDraw; inline overload;
  function RGBA(R, G, B, A: Byte): TDraw; inline;
  function Width(W: Float): TDraw;
  function From(const Cursor: TVec2i): TDraw;
  function BlendMode(Mode: TBlendMode): TDraw;
  procedure BlendModeMax;
  procedure BlendModeMaxOff;
  procedure EnableWireframe; inline;
  procedure DisableWireframe; inline;
  procedure EnableCull(Front: Boolean = True); inline;
  procedure DisableCull; inline;
  // primitives
  function Line(const A, B: TVec2i): TDraw; overload;
  function Line(const A, B: TVec2f): TDraw; overload;
  function LineTo(const Cursor: TVec2i): TDraw;
  function Rect(const R: TRect2i): TDraw; overload;
  function Rect(const R: TRect2f): TDraw; overload;
  function Circle(const P: TVec2f; R: Single): TDraw;
  function RectFilled(const R: TRect2i): TDraw; overload;
  function RectFilled(const R: TRect2f): TDraw; overload;
  function CircleFilled(const P: TVec2f; R: Single): TDraw;
  function Triangle(const X1, Y1, X2, Y2, X3, Y3: Single): TDraw; overload;
  function Triangle(const V1, V2, V3: TVec2f): TDraw; overload;
  function Polygon(P: PPolygon2f): TDraw; overload;
  function FilledPolygon(P: PPolygon2f): TDraw; overload;
  // primitives in 3d
  function Line(const A, B: TVec3f): TDraw; overload;
  function Triangles(var V: array of TVec2f): TDraw; overload;
  function Triangles(V: PVec2f; Count: SizeUInt): TDraw; overload;
  function Triangles(var V: array of TVec3f): TDraw; overload;
  function Triangle(const V1, V2, V3: TVec3f): TDraw; overload;
  function AxisLines(const P: TVec3f; Size: Single = 1): TDraw;
  function AxisAlignedBox(const A, B: TVec3f): TDraw;
  // matrix
  function ResetMatrix: TDraw;
  function PushMatrix: TDraw;
  function PopMatrix: TDraw;
  function MultMatrix(const M: TMat4f): TDraw; overload;
  function Translate(const V: TVec2f): TDraw; overload;
  function Translate(const V: TVec3f): TDraw; overload;
  function Rotate(Angle: Single): TDraw; overload;
  function Rotate(const V: TVec3f; Angle: Single): TDraw; overload;
  function Rotate(const Q: TQuat4f): TDraw; overload;
  function Scale(S: Single): TDraw; overload; inline;
  function Scale(const V: TVec2f): TDraw; overload; inline;
  procedure LookAt(const Eye, Center, Up: TVec3f);
  procedure GetModelViewMatrix(out M: TMat4f);
  procedure GetProjectionMatrix(out M: TMat4f);
  // buffer
  procedure Buffer(Data: Pointer; const P, S: TVec2i);
  // clearing screen
  procedure ClearScreen(const Color: TVec4f); overload; inline;
  procedure ClearScreen(R, G, B, A: Byte); overload; inline;
  procedure ClearDepth;
  // read data from screen
  procedure ReadScreen(Buf: PByte; W, H: LongInt); inline;
  // backend errors
  procedure LogErrors(Name: PAnsiChar);
end;

type
  TBlendMode = TDraw.TBlendMode deprecated 'use TDraw.TBlendMode instead';

implementation

uses
  dstrnum, DEng, DDrawVertexBuffer;

function TDraw.GetCircleSegments(R: Single): Integer;
begin
  Result := Trunc(10 * Sqrt(Abs(R)));
  if Result <= 2 then
    Result := 3;
end;

destructor TDraw.Done;
begin
end;

{$IFDEF DENG_USE_NODRAW}
{$I DDraw_no.inc}
{$ENDIF}

{$IFDEF DENG_USE_DRAW_OPENGL}
{$I DDraw_opengl.inc}
{$ENDIF}

{$IFDEF DENG_USE_DRAW_VULKAN}
{$I DDraw_vulkan.inc}
{$ENDIF}

function TDraw.Rotate(const Q: TQuat4f): TDraw;
begin
  MultMatrix(Matrix4f(Q));
  Result := Self;
end;

end.
