{******************************************************************************}
{* Иллюстрация к книге "DirectX. Графика в проектах Delphi".                  *}
{* Издательство BHV. www.bhv.ru                                               *}
{* Краснов М.В. softgl@chat.ru                                                *}
{******************************************************************************}
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  AppEvnts, ExtCtrls,
  DirectDraw, DDUtil,
  CDXScreenX, CDXTileX, CDXMapX, CDXInputX, DirectInput;

type
  TfrmDD = class(TForm)
    ApplicationEvents1: TApplicationEvents;
    procedure FormCreate(Sender: TObject);
    procedure ApplicationEvents1Deactivate(Sender: TObject);
    procedure ApplicationEvents1Restore(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure ApplicationEvents1Idle(Sender: TObject; var Done: Boolean);
    procedure FormActivate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
    FActive : BOOL;
    function UpdateFrame : HRESULT;
  public
    { Public declarations }
  protected
    procedure FormSetCursor(var aMsg : TMessage); message WM_SETCURSOR;
  end;

const
  ScreenWidth    = 640;
  ScreenHeight   = 480;
  ScreenBitDepth = 8;
  MapSizeX       = 32;
  MapSizeY       = 32;

var
  frmDD : TfrmDD;
  GameInput : CDXInput;
  GameScreen : CDXScreen;
  LandScape : CDXTile;
  GameCursor : CDXSurface;
  GameMap : CDXMap;
  CurX, CurY : Integer;
  MapScrollSpeed : Integer = 4;

implementation

{$R *.DFM}

procedure TfrmDD.FormCreate(Sender: TObject);
begin
  CurX := 0;
  CurY := 0;

  GameInput := CDXInput.CreateCDXInput;
  GameInput.Create(HInstance, Handle);

  GameScreen := CDXScreen.CreateCDXScreenCustomBPP(Handle, ScreenWidth,
                      ScreenHeight, ScreenBitDepth);
  GameScreen.LoadPalette('Tiles.bmp');

  LandScape := CDXTile.CDXTileCustom(GameScreen,'Tiles.bmp', 64, 64, 1);

  GameCursor := CDXSurface.Create;
  GameCursor.CreateCDXSurfaceFromFile(GameScreen,'Cur.bmp');
  GameCursor.ColorKey(0);

  GameMap := CDXMap.CDXMap(LandScape, GameScreen);
  GameMap.CreateMap(MapSizeX, MapSizeY, 1);
  GameMap.MoveTo(0, 0);

  GameScreen.GetAppBackBuffer.ChangeFont('Times', 16, 20, FW_BOLD);
end;

procedure TfrmDD.ApplicationEvents1Deactivate(Sender: TObject);
begin
  FActive := False;
  Application.Minimize;
end;

procedure TfrmDD.FormSetCursor(var aMsg : TMessage);
begin
  SetCursor(0);
end;

procedure TfrmDD.ApplicationEvents1Restore(Sender: TObject);
begin
  WindowState := wsMaximized;
  FActive := True;
end;

function KeyDown (Key : Byte): BOOL;
begin
  Result := GameInput.Keys[Key] = 128;
end;

procedure UpdateKeys;
begin
  if KeyDown(DIK_RIGHT) then GameMap.WrapScrollRight(MapScrollSpeed);
  if KeyDown(DIK_LEFT) then GameMap.WrapScrollLeft(MapScrollSpeed);
  if KeyDown(DIK_UP) then GameMap.WrapScrollUp(MapScrollSpeed);
  if KeyDown(DIK_DOWN) then GameMap.WrapScrollDown(MapScrollSpeed);
  if KeyDown(DIK_ESCAPE) then frmDD.Close;
end;

procedure UpDateMouse;
var
  TempX, TempY : Integer;
begin
  TempX := GameInput.Mouse.X;
  TempY := GameInput.Mouse.Y;
  CurX := CurX + 3 * TempX;
  CurY := CurY + 3 * TempY;
  if CurX < 0 then CurX := 0 else
  if CurX > ScreenWidth - MapSizeX then CurX := ScreenWidth - MapSizeX;

  if CurY < 0 then CurY := 0 else
  if CurY > ScreenHeight - MapSizeY then CurY := ScreenHeight - MapSizeY;

  if CurX = 0 then begin
     if TempX < 0 then GameMap.WrapScrollLeft(-TempX);
  end else
  if CurX = ScreenWidth - MapSizeX then
     if TempX > 0 then GameMap.WrapScrollRight(TempX);

  if CurY = 0 then begin
     if TempY < 0 then GameMap.WrapScrollUp(-TempY);
  end else
  if CurY = ScreenHeight - MapSizeY then
     if TempY > 0 then GameMap.WrapScrollDown(TempY);
end;

function TfrmDD.UpdateFrame : HRESULT;
var
  wrk : TRECT;
begin
  GameInput.Update;
  UpdateKeys;
  UpdateMouse;
  SetRect (wrk, 0, 0, ScreenWidth, ScreenHeight);
  GameMap.DrawClipped (GameScreen.GetAppBackBuffer, wrk);
  GameCursor.DrawFast(CurX, CurY, GameScreen.GetAppBackBuffer);
  GameScreen.GetAppBackBuffer.TextXY(10, 10, 255,'CDX Example for Delphi');
  GameScreen.GetAppBackBuffer.TextXY(10, 30, 255, PChar('X = ' + IntToStr(CurX)));
  GameScreen.GetAppBackBuffer.TextXY(10, 50, 255, PChar('Y = ' + IntToStr(CurY)));
  Result := GameScreen.Flip;
end;

procedure TfrmDD.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Hide
end;

procedure TfrmDD.ApplicationEvents1Idle(Sender: TObject;
  var Done: Boolean);
begin
  if FActive then if Failed (UpdateFrame) then begin
     GameScreen.Restore;
     GameScreen.LoadPalette('Tiles.bmp');
     LandScape.Restore;
  end;
  Done := False;
end;

procedure TfrmDD.FormActivate(Sender: TObject);
begin
  FActive := True;
end;

procedure TfrmDD.FormDestroy(Sender: TObject);
begin
  if Assigned (GameInput) then GameInput.Destroy;
  if Assigned (LandScape) then LandScape.Destroy;
  if Assigned (GameCursor) then GameCursor.Destroy;
  if Assigned (GameMap) then GameMap.Destroy;
  if Assigned (GameScreen) then GameScreen.Destroy;
end;

end.


