unit MainFm; 

{$mode objfpc}{$H+}

//---------------------------------------------------------------------------
interface

//---------------------------------------------------------------------------
uses
  Variants, Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs,
  StdCtrls;

//---------------------------------------------------------------------------
type
 TMainForm = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { private declarations }
    GameTicks: Integer;

    procedure OnDeviceCreate(Sender: TObject; Param: Pointer;
     var Handled: Boolean);
    procedure TimerEvent(Sender: TObject);
    procedure ProcessEvent(Sender: TObject);
    procedure RenderEvent(Sender: TObject);
  public
    { public declarations }
  end; 

//---------------------------------------------------------------------------
var
  MainForm: TMainForm;

//---------------------------------------------------------------------------
implementation

//---------------------------------------------------------------------------
uses
 Windows, Vectors2px, Vectors2, AsphyreTypes, AsphyreFactory, DX7Providers,
 AsphyreImages, AsphyreFonts, AsphyreDb, AbstractDevices, AsphyreTimer,
 GameTypes;

//---------------------------------------------------------------------------
procedure TMainForm.FormCreate(Sender: TObject);
begin
 // Set the display size
 DisplaySize:= Point2px(800, 600);

 // Indicate that we're using DirectX 7.0
 Factory.UseProvider(idDirectX7);

 // Create Asphyre components in run-time.
 GameDevice:= Factory.CreateDevice();
 GameCanvas:= Factory.CreateCanvas();
 GameImages:= TAsphyreImages.Create();

 GameFonts:= TAsphyreFonts.Create();
 GameFonts.Images:= GameImages;
 GameFonts.Canvas:= GameCanvas;

 MediaASDb:= TASDb.Create();
 MediaASDb.FileName:= ExtractFilePath(ParamStr(0)) + 'media.asdb';
 MediaASDb.OpenMode:= opReadOnly;

 GameDevice.WindowHandle:= Self.Handle;
 GameDevice.Size    := DisplaySize;
 GameDevice.Windowed:= True;
 GameDevice.VSync   := False;
 GameDevice.Multisamples:= 8;

 EventDeviceCreate.Subscribe(@OnDeviceCreate, 0);

 // Attempt to initialize Asphyre device.
 if (not GameDevice.Initialize()) then
  begin
   MessageBox(Self.Handle, PChar('Failed to initialize Asphyre device.'),
    PChar('Error'), MB_OK or MB_ICONERROR);
   Exit;
  end;

 // Create rendering timer.
 Timer.OnTimer  := @TimerEvent;
 Timer.OnProcess:= @ProcessEvent;
 Timer.Speed    := 60.0;
 Timer.MaxFPS   := 4000;
 Timer.Enabled  := True;

 GameTicks:= 0;
end;

//---------------------------------------------------------------------------
procedure TMainForm.FormDestroy(Sender: TObject);
begin
 Timer.Enabled:= False;

 // Release all Asphyre components.
 FreeAndNil(GameFonts);
 FreeAndNil(GameImages);
 FreeAndNil(MediaASDb);
 FreeAndNil(GameCanvas);
 FreeAndNil(GameDevice);
end;

//---------------------------------------------------------------------------
procedure TMainForm.OnDeviceCreate(Sender: TObject; Param: Pointer;
 var Handled: Boolean);
var
 Success: Boolean;
begin
 // This variable returns "Success" to Device initialization, so if you
 // set it to False, device creation will fail.
 Success:= Boolean(Param^);

 GameImages.RemoveAll();
 GameFonts.RemoveAll();

 // This image is used by our bitmap font.
 GameImages.AddFromASDb('/tahoma9b.image', MediaASDb);

 fontTahoma9b:= GameFonts.Insert('/media.asdb | /tahoma9b.xml', 'tahoma9b.image');
 imageLena   := GameImages.AddFromASDb('/lena.image', MediaASDb);

 Success:=
  Success and
  (imageLena <> -1)and
  (fontTahoma9b <> -1);

 Boolean(Param^):= Success;
end;

//---------------------------------------------------------------------------
procedure TMainForm.TimerEvent(Sender: TObject);
begin
 GameDevice.Render(@RenderEvent, $000000);
 Timer.Process();
end;

//---------------------------------------------------------------------------
procedure TMainForm.ProcessEvent(Sender: TObject);
begin
 Inc(GameTicks);
end;

//---------------------------------------------------------------------------
procedure TMainForm.RenderEvent(Sender: TObject);
var
 j, i: Integer;
 Omega, Kappa: Single;
begin
 for j:= 0 to (DisplaySize.y div 40) - 1 do
  for i:= 0 to (DisplaySize.x div 40) - 1 do
   GameCanvas.FillQuad(
    pBounds4(i * 40, j * 40, 40, 40),
    cColor4($FF585858, $FF505050, $FF484848, $FF404040));

 for i:= 0 to (DisplaySize.x div 40) - 1 do
  GameCanvas.Line(
   Point2(i * 40.0, 0.0),
   Point2(i * 40.0, DisplaySize.y),
   $FF505050, $FF505050);

 for j:= 0 to (DisplaySize.y div 40) - 1 do
  GameCanvas.Line(
   Point2(0.0, j * 40.0),
   Point2(DisplaySize.x, j * 40.0),
   $FF505050, $FF505050);

 // Draw an animated hole.
 GameCanvas.QuadHole(
  Point2(0.0, 0.0),
  Point2(DisplaySize.x, DisplaySize.y),
  Point2(
   DisplaySize.x * 0.5 + Cos(GameTicks * 0.0073) * DisplaySize.x * 0.25,
   DisplaySize.y * 0.5 + Sin(GameTicks * 0.00312) * DisplaySize.y * 0.25),
  Point2(80.0, 100.0),
  $20FFFFFF, $80955BFF, 16);

 GameCanvas.UseImagePx(GameImages[imageLena], pxBounds4(0, 0, 512, 512));
 GameCanvas.TexMap(pRotate4c(
  Point2(400.0, 300.0),
  Point2(300.0, 300.0),
  GameTicks * 0.01),
  cAlpha4(128));

 // Draw an animated Arc.
 Omega:= GameTicks * 0.0274;
 Kappa:= 1.25 * Pi + Sin(GameTicks * 0.01854) * 0.5 * Pi;

 GameCanvas.FillArc(Point2(DisplaySize.x * 0.1, DisplaySize.y * 0.9),
  Point2(75.0, 50.0), Omega, Omega + Kappa, 32,
  cColor4($FFFF0000, $FF00FF00, $FF0000FF, $FFFFFFFF));

 // Draw an animated Ribbon.
 Omega:= GameTicks * 0.02231;
 Kappa:= 1.25 * Pi + Sin(GameTicks * 0.024751) * 0.5 * Pi;

 GameCanvas.FillRibbon(Point2(DisplaySize.x * 0.9, DisplaySize.y * 0.85),
  Point2(25.0, 20.0), Point2(70.0, 80.0), Omega, Omega + Kappa, 32,
  cColor4($FFFF0000, $FF00FF00, $FF0000FF, $FFFFFFFF));

 GameFonts[fontTahoma9b].TextOut(
  Point2(4.0, 4.0),
  'FPS: ' + IntToStr(Timer.FrameRate),
  cColor2($FFFFE887, $FFFF0000), 1.0);
end;

//---------------------------------------------------------------------------
initialization
  {$I MainFm.lrs}

//---------------------------------------------------------------------------
end.

