unit uParticles;

interface

uses
  dfHRenderer, dfMath,
  uAccum;

const
  FADE_TIME_BASE = 0.5;

type
  TpdParticle = class (TpdAccumItem)
  public
    spr: IdfSprite;
    timeRemain, timeAll: Single;
    moveDir: TdfVec2f;
    speed: Single;
    procedure OnCreate(); override;
    procedure OnGet(); override;
    procedure OnFree(); override;
  end;

  TpdParticles = class (TpdAccum)
  public
    class function Initialize(aScene: Idf2DScene): TpdParticles;
    function NewAccumItem(): TpdAccumItem; override;
    function GetItem(): TpdParticle; reintroduce;

    procedure Update(const dt: Single);

    procedure AddBlock(aPos: TdfVec2f);
    procedure AddPunch(aPos: TdfVec2f);
  end;

implementation

uses
  uGlobal;

var
  internalZ: Integer = 0;
  scene: Idf2DScene;

{ TpdParticle }

procedure TpdParticle.OnCreate;
begin
  inherited;
  spr := dfCreateHUDSprite();
  spr.Material.Texture := texParticle;
  spr.PivotPoint := ppCenter;
  spr.UpdateTexCoords();
  spr.SetSizeToTextureSize();
  spr.Z := Z_HUD + internalZ;
  Inc(internalZ);
  scene.RegisterElement(spr);

  OnFree();
end;

procedure TpdParticle.OnFree;
begin
  inherited;
  spr.Visible := False;
  speed := 0;
end;

procedure TpdParticle.OnGet;
begin
  inherited;
  spr.Visible := True;
  timeAll := FADE_TIME_BASE + 1.5 * Random();
  timeRemain := timeAll;
  spr.Material.MaterialOptions.Diffuse := colorGreen;
  spr.SetSizeToTextureSize();
end;

{ TpdParticles }

procedure TpdParticles.AddBlock(aPos: TdfVec2f);
var
  i, count: Integer;
  color: TdfVec4f;
begin
  count := 5 + Random(5);
  color := dfVec4f(Random(), Random(), Random(), 1.0);
  for i := 0 to count - 1 do
    with GetItem() do
    begin
      spr.Position := aPos;
      spr.Rotation := Random(360);
      spr.Width := spr.Width * (0.3 + Random());
      spr.Height := spr.Width;
      moveDir := dfVec2f(0 + Random(360)).Normal;
      speed := 60 + Random(30);
      spr.Material.MaterialOptions.Diffuse := color;
    end;
end;

procedure TpdParticles.AddPunch(aPos: TdfVec2f);
var
  i, count: Integer;
  color: TdfVec4f;
begin
  count := 10 + Random(10);
  color := dfVec4f(1.0, 0.2, 0.1, 1.0);
  for i := 0 to count - 1 do
    with GetItem() do
    begin
      spr.Position := aPos;
      spr.Rotation := Random(360);
      spr.Width := spr.Width * (0.3 + Random());
      spr.Height := spr.Width;
      moveDir := dfVec2f(0 + Random(360)).Normal;
      speed := 60 + Random(30);
      spr.Material.MaterialOptions.Diffuse := color;
    end;
end;

function TpdParticles.GetItem: TpdParticle;
begin
  Result := inherited GetItem() as TpdParticle;
end;

class function TpdParticles.Initialize(aScene: Idf2DScene): TpdParticles;
begin
  scene := aScene;
  Result := TpdParticles.Create(128);
end;

function TpdParticles.NewAccumItem: TpdAccumItem;
begin
  Result := TpdParticle.Create();
end;

procedure TpdParticles.Update(const dt: Single);
var
  i: Integer;
begin
  for i := 0 to High(Items) do
    if Items[i].Used then
      with Items[i] as TpdParticle do
      begin
        if timeRemain > 0 then
        begin
          timeRemain := timeRemain - dt;
          spr.Material.MaterialOptions.PDiffuse.w := timeRemain / timeAll;
          //spr.Width := spr.Material.Texture.Width * (timeRemain / FADE_TIME);
          //spr.Height := spr.Material.Texture.Height * (timeRemain / FADE_TIME);
          spr.Position := spr.Position + moveDir * speed * dt;
          moveDir := (moveDir + dfVec2f(0, 2 * dt));
          //spr.Rotation := spr.Rotation + (speed * 2) * dt;
        end
        else
          FreeItem(Items[i]);
      end;
end;

end.
