program Project1;

{$APPTYPE CONSOLE}

uses
  FastMM4,
  SysUtils,
  Classes,
  Contnrs,
  AnimationrigMisc in '..\lib\AnimationrigMisc.pas',
  Animationrig in '..\lib\Animationrig.pas',
  AnimationrigState in '..\lib\AnimationrigState.pas',
  AnimationrigValuePreset in '..\lib\AnimationrigValuePreset.pas',
  AnimationrigLogger in '..\lib\AnimationrigLogger.pas',
  AnimationrigNull in '..\lib\AnimationrigNull.pas',
  AnimationrigPhysicsSpring in '..\lib\AnimationrigPhysicsSpring.pas',
  AnimationrigWiggle in '..\lib\AnimationrigWiggle.pas';

type
  TMain = class
    protected
      procedure LogCallback(const s:string);
      procedure EventCallback(state:TAnimrigState; const data:TAnimrigStateEventData);

      procedure TrackLogOut(o : TAnimrigStateTrack; index:integer; const name:string);
      procedure ObjectLogOut(o : TAnimrigObject);
      procedure Update(state:TAnimrigState);
    public
      constructor Create;
      procedure Main;
  end;


{ TMain }

constructor TMain.Create;
begin

end;

procedure TMain.EventCallback(state: TAnimrigState; const data: TAnimrigStateEventData);
begin
  TAnimrigLogger.Log('event');
  TAnimrigLogger.Log('  name : ' + data.ID);
  TAnimrigLogger.Log('  strings : ' + '"'+data.Strings[0]+'"' + ' , ' + '"'+data.Strings[1]+'"');
  TAnimrigLogger.Log('  floats : ' + TAnimrigLogger.FloatToStr(data.Floats[0]) + ' , ' + TAnimrigLogger.FloatToStr(data.Floats[1]));
end;

procedure TMain.LogCallback(const s: string);
begin
  Writeln(s);
end;

procedure TMain.Main;
var
  data : TAnimrig;
  state : TAnimrigState;
  preset : TAnimrigPreset;
  logger : TAnimrigStateLogRenderer;
  ms : TMemoryStream;
  i : integer;
  s : string;
  interval : integer;
begin
  // log callback attach
  TAnimrigLogger.OnLog := LogCallback;

  // load
  data := TAnimrig.Create;
  ms := TMemorySTream.Create;
  ms.LoadFromFile('data\sample.animrig');
  ms.Position := 0;
  if not data.LoadFromBinary(ms) then
    raise Exception.Create('can not load animrig file : ' + data.LastError);
  ms.free;

  // state
  state := TAnimrigState.Create(data);
  state.OnEvent := EventCallback;

  // preset
  preset := TAnimrigPreset.Create();
  ms := TMemorySTream.Create;
  ms.LoadFromFile('data\sample.animrig.preset.txt');
  ms.Position := 0;
  if not preset.LoadFromStream(ms) then
    raise Exception.Create('can not load preset file.');
  ms.free;

  // setup
  logger := TAnimrigStateLogRenderer.Create(anoSpine);
  logger.name := 'logger';
  state.Inputs[0].Renderer := logger;

  // object
  ObjectLogOut(data.Objects[0]);

  // update
  interval := 60;
  for i:=0 to interval-1 do Update(state);

  state.EntryTrack(0 , 'setup');
  state.EntryTrack(1 , 'pose_test');
  state.EntryTrack(3 , 'physics_wind');
  preset.SetDefault(state.Inputs[0]);
  for i:=0 to interval-1 do Update(state);

  preset.SetPreset(state.Inputs[0], 'lookdown', 1.0);
  for i:=0 to interval-1 do Update(state);

  state.EntryTrackFade(2 , 'facial_lol',1.0);
  for i:=0 to interval-1 do Update(state);

  state.EntryTrackFade(2 , 'facial_boo',1.0);
  // state save
  ms := TmemoryStream.Create;
  state.SaveToBinary(ms);
  writeln('state save to binary : ' + IntToStr(ms.Size)+'KB');
  for i:=0 to interval-1 do Update(state);

  state.ClearTrackFade(2 , 1.0);
  preset.SetClear(state.Inputs[0], 1.0);
  for i:=0 to interval-1 do Update(state);

  state.ClearTrackFade(0 , 1.0);
  state.ClearTrackFade(1 , 1.0);
  state.ClearTrackFade(2 , 1.0);
  for i:=0 to interval-1 do Update(state);

  // state load
  ms.Position := 0;
  if state.LoadFromBinary(ms) then
  begin
    for i:=0 to interval-1 do Update(state);
  end
  else
  begin
    Writeln('state load error.');
  end;

  state.ClearTracks;
  ms.Position := 0;
  if state.LoadFromBinary(ms) then
  begin
    for i:=0 to interval-1 do Update(state);
  end
  else
  begin
    Writeln('state load error.');
  end;


  // free
  ms.free;
  logger.free;
  state.free;
  data.free;
  preset.free;

  // wait
  Writeln('push any key');
  Readln(s);
end;

procedure TMain.ObjectLogOut(o: TAnimrigObject);
begin
  TAnimrigLogger.Log('object.state');
  TAnimrigLogger.Log('  name : ' + o.Name);
  TAnimrigLogger.Log('  enable : ' + TAnimrigLogger.BoolToStr(o.Enable));
  TAnimrigLogger.Log('  visible : ' + TAnimrigLogger.BoolToStr(o.Visible));
  TAnimrigLogger.Log('  offset : ' + TAnimrigLogger.VectorToStr(o.Offset));
  TAnimrigLogger.Log('  scale : ' + TAnimrigLogger.VectorToStr(o.Scale));
  TAnimrigLogger.Log('  parent object index : ' + inttostr(o.ParentObjectIndex));
  TAnimrigLogger.Log('  draw priority : ' + TAnimrigLogger.FloatToStr(o.DrawPriority));
end;

procedure TMain.TrackLogOut(o: TAnimrigStateTrack; index:integer; const name: string);
begin
  TAnimrigLogger.Log(name+'.statetrack[' + IntToStr(index) + ']');
  if o = nil then
  begin
    TAnimrigLogger.Log('  null');
    exit;
  end;

  TAnimrigLogger.Log('  enable : ' + TAnimrigLogger.BoolToStr(o.Enable));
  TAnimrigLogger.Log('  play frame : ' + TAnimrigLogger.FloatToStr(o.PlayFrame));
  TAnimrigLogger.Log('  track alpha : ' + TAnimrigLogger.FloatToStr(o.TrackAlphaEase.Value));
  TAnimrigLogger.Log('  mix alpha : ' + TAnimrigLogger.FloatToStr(o.MixAlphaEase.Value));
end;

procedure TMain.Update(state: TAnimrigState);
begin
  state.Update(0.1,true);
  TrackLogOut(state.Tracks[0],0,'track[0]');
  TrackLogOut(state.Tracks[1],1,'track[1]');
  TrackLogOut(state.Tracks[2],2,'track[2]');
  TrackLogOut(state.Tracks[3],3,'track[3]');
end;

var
  main : TMain;
begin
  ReportMemoryLeaksOnShutdown := true;

  try
    { TODO -oUser -cConsole Main }
    main := TMain.Create;
    main.Main;
    main.free;
  except
    on E: Exception do
    begin
      Writeln('***error***');
      Writeln(E.ClassName, ': ', E.Message);
    end;
  end;
end.
