unit ant_main;

//
//  The unit implements global and game logic.
//  For the rendering see ant_renderer.
//

{$MODE FPC}
{$MODESWITCH AUTODEREF}
{$MODESWITCH DEFAULTPARAMETERS}
{$MODESWITCH OUT}
{$MODESWITCH RESULT}

interface

uses
  {$I deng_app_units.inc},
  dstrnum,
  dvector2f,
  dvector2i,
  drect2i,
  dvector4f,
  dstream,
  dstreamfile,
  ant_config,
  ant_resources,
  ant_world,
  ant_camera,
  ant_hud,
  ant_renderer,
  ant_text;

procedure AntMain;

implementation

const
  BASE_TITLE = 'ant';

type
  TTime = Int32;

var
  World: TWorld;
  Renderer: TRenderer;
  Camera: TCamera;
  Global: record
    State: PtrInt; // 0 - main menu, 1 - game, 2 - in game menu
    Paused: Boolean; // controls updating the world
    FrameFactor: Single;
    LastRenderTime: TTime;
    HUD: THUD;
  end;

procedure ShowExitConfirmation;
begin
  // TODO
  Eng.StopLoop;
end;

procedure SwitchToInGameMenu;
begin
  // TODO
  Eng.StopLoop;
end;

function OnExitPressed: Boolean;
begin
  case Global.State of
  0: ShowExitConfirmation;
  1: SwitchToInGameMenu;
  2: ;
  else
    // Ignore
  end;
  Exit(True);
end;

function OnTheButtonPressed: Boolean;
begin
  World.Player^.Switch;
  Exit(True);
end;

procedure PlayMusic;
begin
  if (not Eng.Music.IsPlaying) and (Config.GameMusic <> '') then begin
    Eng.Music.SetVolume(Config.MasterVolume);
    Eng.Music.Play(Config.GameMusic);
  end;
end;

procedure AntInit(Eng: TEngine);
begin
  LoadAllResources;

  World.Init;
  World.Generate;

  Camera.Init;
  Renderer.Init(@World);
  Global.State := 0;
  Global.Paused := True;
  Global.FrameFactor := 0;
  Global.LastRenderTime := 0;
  Global.HUD.Init;

  InitText;

  PlayMusic;
end;

procedure AntDone(Eng: TEngine);
begin
  Global.HUD.Done;
  Camera.Done;
  Renderer.Done;
  World.Done;
end;

procedure AntUpdate(Eng: TEngine);
begin
  World.Update;
end;

procedure AntRender(Eng: TEngine);
var
  T: TTime;
begin
  T := Eng.Time;
  Global.FrameFactor := (T - Eng.LastUpdateTime) / Eng.Delta;

  Eng.Draw.BeginRender;
  Eng.Draw.BlendMode(BM_ALPHA);
  Eng.Draw.ClearScreen(Vec4f(24/255, 63/255, 19/255, 1));

  // Renderer.Render(@Camera, Global.FrameFactor);

  Eng.Draw.Start2D;
  World.Render;
  Eng.Draw.PushMatrix;
  Eng.Draw.Translate(Vec2f(300, 100));
  Global.HUD.Draw(@(World.Player^.AntHillState), World.Player^.DamagedRecently, World.Player^.IsLastStanding and (Eng.Time - WonTime < 20000));
  Eng.Draw.PopMatrix;
  Eng.Draw.End2D;

  Eng.Draw.EndRender;

  Global.LastRenderTime := T;
end;

function AntOnWindowEvent(Event: PWindowEvent): Boolean;
begin
  if Event^.IsKeyDown(KEY_ESC) then begin
    Exit(OnExitPressed);
  end else if Event.IsAltPressed and Event.IsKeyDown(KEY_ENTER) then begin
    Eng.WinApi.ToggleFullScreen;
    // TODO send reshape event to all subsystems
    Exit(True);
  //end else if Event^.IsKeyDown then begin // all other keys are the button
  end else if Event^.IsKeyDown(KEY_SPACE) or Event^.IsKeyDown(KEY_ENTER) or Event^.IsLeftClickDown then begin
    Exit(OnTheButtonPressed);
  end else if Event^.IsKeyDown(Ord('R'))  then begin
    World.Generate;
    Exit(True);
  end;
  Exit(False);
end;

procedure AntMain;
var
  Flags: Int32;
begin
  Flags := DENG_GL;
  if Config.GetFullScreen then
    Flags := Flags or DENG_FULLSCREEN;
  Eng.InitDisplayMode(Config.GetWidth, Config.GetHeight, 32, Flags);
  Eng.InitTitle(BASE_TITLE);
  Eng.InitEventFunc(@AntOnWindowEvent);
  Eng.Run(@AntRender, @AntUpdate, 30, @AntInit, @AntDone);
end;

end.
