{$APPTYPE CONSOLE}

uses
  dvector2f,
  drect2f,
  dcolors,
  dstrnum,
  dvector4f,
  dfilereader,
  dswf_appendix_a,
  dflash_holder,
  dflash_player,
  dflash_scenebuffer,
  dengbase,
  deng,
  DWinAPi;

type
  PFlash = ^TFlash;
  TFlash = record
    FileName: AnsiString;
    Data: Pointer;
    DataLen: SizeUint;
    Holder: TFlashHolder;
    Player: TFlashPlayer;
    Pos: TVec2f;
    IsInside: Boolean;
  end;

var
  CurPos: TVec2f;
  CurSize: TVec2f;
  Flashes: array of PFlash;
  LastRender: LongInt;
  Scale: Single = 4;
  UseSceneBuffer: Boolean = False;
  SceneBuffer: TFlashSceneBuffer;

function LoadFlash(const FileName: AnsiString): Boolean;
label
  Failed;
begin
  SetLength(Flashes, Length(Flashes) + 1);
  New(Flashes[High(Flashes)]);
  Flashes[High(Flashes)]^.FileName := FileName;
  with Flashes[High(Flashes)]^ do begin
    if not ReadFileContent(FileName, 0, PAnsiChar(Data), DataLen) then begin
      Log('Could not open ' + FileName);
      goto Failed;
      Halt(1);
    end;
    Holder.Init;
    if not Holder.Load(FileName, Data, Data + DataLen) then begin
    //if not Holder.Load(@SWF_APPENDIX_A[0], Length(SWF_APPENDIX_A)) then begin
      Log('Failed parsing ' + FileName + ': ' + Holder.ErrorMsg);
      Holder.Done;
      goto Failed;
      Exit(False);
    end;
    Player.Init(@Holder);
    Player.SetLoop(False);
    //Player.SetFinishFrame(Player.FrameCount div 2);
    Player.Stop;
    IsInside := False;

    Log(FileName + ' size:   ' + IntToStr(Round(Holder.Size.X)) + 'x' + IntToStr(Round(Holder.Size.Y)));
    Log(FileName + ' fps:    ' + IntToStr(Round(Holder.FrameRate)));
    Log(FileName + ' frames: ' + IntToStr(Round(Holder.FrameCount)));
  end;
  Exit(True);

Failed:
  Dispose(Flashes[High(Flashes)]);
  SetLength(Flashes, Length(Flashes) - 1);
  Exit(False);
end;

procedure Init(Eng: TEngine);
var
  I: LongInt;
begin
  // LoadFlash('giflevel/giantplant_00.swf'); // <- закрашена не та область
  // LoadFlash('giflevel/giantplant_01.swf'); // <- закрашена не та область
  // LoadFlash('giflevel/giantplant_02.swf'); // <- закрашена дырка, а не тело
  // LoadFlash('giflevel/giantplanteyes_00.swf');
  // LoadFlash('giflevel/giantplantleaf_00.swf');
  // LoadFlash('giflevel/giantplantleaf_01.swf');
  {LoadFlash('giflevel/homeplant_00.swf');
  LoadFlash('giflevel/homeplant_01.swf');
  LoadFlash('giflevel/homeplant_02.swf');
  LoadFlash('giflevel/homeplant_02_hitbox.swf');
  LoadFlash('giflevel/manwithaloteyes_00.swf');
  LoadFlash('giflevel/photo_00.swf');
  LoadFlash('og/leaves0_01.swf');
  LoadFlash('og/leaves0_02.swf');
  LoadFlash('og/leaves0_03.swf');
  LoadFlash('og/plant0_01.swf');
  LoadFlash('og/plant0_02.swf');
  LoadFlash('og/plant0_03.swf');
  LoadFlash('og/stone0_01.swf');
  LoadFlash('og/stone0_02.swf');
  LoadFlash('og/tinyhuman0_00.swf');
  LoadFlash('og/tinyhuman0_01.swf');
  LoadFlash('og/worm0_01.swf');
  LoadFlash('og/leaves0_01_hitbox.swf');
  LoadFlash('og/leaves0_02_hitbox.swf');
  LoadFlash('og/plant0_01_hitbox.swf');
  LoadFlash('og/plant0_02_hitbox.swf');
  LoadFlash('og/plant0_03_hitbox.swf');
  LoadFlash('og/stone0_01_hitbox.swf');
  LoadFlash('og/stone0_02_hitbox.swf');
  LoadFlash('og/tinyhuman0_01_hitbox.swf');
  LoadFlash('og/checkboard.swf');}
  //LoadFlash('testslevel/tests_hole0.swf');
  // LoadFlash('worms/worms_hungryman0.swf'); // <- failed sub players
  LoadFlash('nekra_psaria_remake/np1_street/tex/np1_cockroachboy1.swf');

  CurPos := Vec2f(0, 0);
  CurSize := Vec2f(0, 0);
  for I := 0 to High(Flashes) do begin
    if CurPos.X + Flashes[I]^.Holder.Size.X > 700 then begin
      CurPos := Vec2f(0, CurPos.Y + CurSize.Y);
      CurSize.Y := 0;
    end;
    Flashes[I]^.Pos := CurPos;
    CurPos := CurPos + Vec2f(Flashes[I]^.Holder.Size.X, 0);
    if Flashes[I]^.Holder.Size.Y > CurSize.Y then
      CurSize.Y := Flashes[I]^.Holder.Size.Y;
  end;

  if UseSceneBuffer then begin
    SceneBuffer.Init;
    for I := 0 to High(Flashes) do begin
      Flashes[I].Player.LinkToSceneBuffer(@SceneBuffer);
    end;
    for I := 0 to High(Flashes) do begin
      Flashes[I].Player.LoadToSceneBuffer(@SceneBuffer);
    end;
  end;

  LastRender := Eng.Time;
end;

procedure Done(Eng: TEngine);
var
  I: LongInt;
begin
  if UseSceneBuffer then begin
    SceneBuffer.Done;
  end;
  for I := 0 to High(Flashes) do begin
    Flashes[I]^.Player.Done;
    Flashes[I]^.Holder.Done;
    FreeMem(Flashes[I]^.Data);
    Dispose(Flashes[I]);
  end;
  SetLength(Flashes, 0);
end;

procedure Render(Eng: TEngine);
var
  I: LongInt;
  Time: LongInt;
  NewIsInside: Boolean;
begin
  Time := Eng.Time;
  Eng.Draw.BeginRender;
  Eng.Draw.ClearScreen(Vec4f(0.2 * Abs(Cos(Eng.Time / 1000)), 0.2, 0.2 * Abs(Sin(Eng.Time / 1000)), 1));
  Eng.Draw.Start2D;
  Eng.Draw.BlendMode(BM_ALPHA);
  for I := 0 to High(Flashes) do begin
    Eng.Draw.PushMatrix;
    Eng.Draw.Translate(Flashes[I]^.Pos);
    Eng.Draw.Scale(Scale);
    NewIsInside := Flashes[I]^.Player.IsInside(Mul2f(Vec2f(Eng.GetMouse), 1 / Scale) - Flashes[I]^.Pos);
    if NewIsInside then begin
      Eng.Draw.RGBA(255, 255, 255, 255);
      Eng.Draw.RectFilled(Rect2f(Vec2f(0, 0), Flashes[I]^.Holder.Size));
    end;
    if NewIsInside and not Flashes[I]^.IsInside then
      Log(Flashes[I]^.FileName);
    Flashes[I]^.IsInside := NewIsInside;
    Flashes[I]^.Player.UpdateAnimation(Time - LastRender);
    if not UseSceneBuffer then
      Flashes[I]^.Player.Draw;
    Eng.Draw.PopMatrix;
  end;
  if UseSceneBuffer then begin
    SceneBuffer.Bind;
    for I := 0 to High(Flashes) do begin
      Eng.Draw.PushMatrix;
      Eng.Draw.Translate(Flashes[I]^.Pos);
      Eng.Draw.Scale(Scale);
      Flashes[I]^.Player.DrawFromSceneBuffer(@SceneBuffer);
      Eng.Draw.PopMatrix;
    end;
    SceneBuffer.Unbind;
  end;
  Eng.Draw.EndRender;
  LastRender := Time;
end;

procedure Update(Eng: TEngine);
begin
  if Eng.Control.Pressed(KEY_ESC) then
    Eng.StopLoop;
end;

begin
  WINAPI_SETTINGS.MultiSampling := False;
  Eng.InitDisplayMode(1024, 768, 32, DENG_GL);
  Eng.InitTitle('Test of TFlashPlayer');
  Eng.InitInitFunc(Init);
  Eng.InitDoneFunc(Done);
  Eng.InitRenderFunc(Render);
  Eng.InitUpdateFunc(Update, 30);
  //Eng.InitEventFunc(@OnWindowEvent);
  Eng.Run;
end.
