unit Capsule;

interface

uses
  _Geometry,   
  Frost.Forms, 
  Frost.Renderers,
  Frost.Engine,
  Frost.GL,
  Frost.Utils,
  Planetoid,
  OpenGL;

const
 // ENEMY_SPEED = 50;
  MAX_CAPSULES = 120;

type
TCreationMethod =  procedure(Rotation: TMatrix3; Tag: Integer) of Object;

TCapsule = class(TComponent)
  private
    class var FMesh: TMesh;
  protected
    FMeshRenderer: TMeshRenderer;
    FCapsule: TGameObject;
    FLife: Single;        
    FUsed: Boolean;
    FAction: TCreationMethod;
    FTag: Integer;
  public
    class procedure Init;
    class procedure Add(Rotate: TMatrix3; Action: TCreationMethod; Tag: Integer; Life: Single = 6);
  public
    procedure OnStart(); override;
    procedure OnUpdate(const Delta: Double); override;
    procedure OnDestroy(); override;
  end;

var
  Capsules: Array [0..MAX_CAPSULES] of TCapsule;

implementation

uses
  WorldScene,
  Frost.Particles;

{$REGION 'Capsule'}
function CreateCylinderMesh(Radius: Single = 0.2; Length: Single = 1; Edges: Word = 16): TMesh;
var
  Vertex:   TVertexes;
  Normals:  TNormals;
  Textures: TTextures;
  Faces: TFaces;
  i: Integer;
begin
  SetLength(Vertex, Edges * 2 + 2);
  SetLength(Textures, Edges * 2 + 2);
  SetLength(Normals, Edges * 2 + 2);
  SetLength(Faces, (Edges - 1) * 2 + (Edges - 1) * 2); //2 triangles on each side panel, and 2 circle
  for i := 0 to Edges - 1 do
  begin
    Vertex[i        ] := Vector3(GetVector(i * 360 / (Edges - 1), Radius).X,  Length * 0.5, -GetVector(i * 360 / (Edges - 1), Radius).Y);
    Vertex[i + Edges] := Vector3(GetVector(i * 360 / (Edges - 1), Radius).X, -Length * 0.5, -GetVector(i * 360 / (Edges - 1), Radius).Y);
    Normals[i        ] := Vector3(GetVector(i * 360 / (Edges - 1), Radius).X,  0, -GetVector(i * 360 / (Edges - 1), Radius).Y);
    Normals[i + Edges] := Vector3(GetVector(i * 360 / (Edges - 1), Radius).X,  0, -GetVector(i * 360 / (Edges - 1), Radius).Y);
    Textures[i        ] := Vector2(1 / (Edges - 1) * i, 0);
    Textures[i + Edges] := Vector2(1 / (Edges - 1) * i, 1);
  end;
  Vertex[Edges + Edges + 0] := Vector3(0,  Length * 0.5, 0);
  Vertex[Edges + Edges + 1] := Vector3(0, -Length * 0.5, 0);
  Normals[Edges + Edges + 0] := Vector3(0, 0,  1);
  Normals[Edges + Edges + 1] := Vector3(0, 0, -1);
  Textures[Edges + Edges + 0] := Vector2(0, 0);
  Textures[Edges + Edges + 1] := Vector2(0, 1);

  for i := 0 to Edges - 2 do
  begin
    Faces[i * 2 + 0] := Face( i + 1, i, i + Edges);
    Faces[i * 2 + 1] := Face( i + Edges + 1, i + 1, i + Edges);
    Faces[(i + Edges - 1) * 2 + 0] := Face( i, i + 1, Edges + Edges + 0);
    Faces[(i + Edges - 1) * 2 + 1] := Face( i + Edges, Edges + Edges + 1, i + Edges + 1);
  end;

  Result := TMesh.Create(Faces, Vertex, Textures, Normals);
  SetLength(Vertex, 0);
  SetLength(Textures, 0);
  SetLength(Normals, 0);
  SetLength(Faces, 0);
end;

{$ENDREGION}

{$REGION 'BaseEnemy'}
class procedure TCapsule.Init;
var
  i: Word;
begin
  for i:= 0 to MAX_CAPSULES - 1 do
    Capsules[i] := TCapsule.Create(TGameObject.Create());
end;

class procedure TCapsule.Add(Rotate: TMatrix3; Action: TCreationMethod; Tag: Integer; Life: Single = 6);
var
  i: Word;
begin
  for i:= 0 to MAX_CAPSULES - 1 do
    if (not Capsules[i].Enable) then
    begin
      Capsules[i].Enable := True;    
      Capsules[i].FUsed := False;
      Capsules[i].GameObject.LocalRotation := Rotate;
      Capsules[i].FLife := Life;
      Capsules[i].FAction := Action;
      Capsules[i].FTag := Tag;
      Capsules[i].FMeshRenderer.Enable := True;
      break;
    end;
end;

procedure TCapsule.OnStart;
begin
  if (FMesh = nil) then
    FMesh := CreateCylinderMesh;
  FCapsule := TGameObject.Create(GameObject);
  FCapsule.LocalPosition := Vector3(0, 0, 0);
  FMeshRenderer := TMeshRenderer.CreateMeshRenderer(FMesh, TDummyMaterial.Create);
  FCapsule.AddComponent(FMeshRenderer);
  Enable := False;                      
  FMeshRenderer.Enable := False;
end;

procedure TCapsule.OnUpdate(const Delta: Double);
var
  i: Byte;
  Rotation : TMatrix3;
  Position : TVector3;
begin
  FLife := FLife - Delta;              
  if (not FUsed) then
    FCapsule.LocalPosition := Vector3(0, TPlanetoid.Instance.Radius + FLife * 10, 0)
  else
    FCapsule.LocalPosition := Vector3(0, TPlanetoid.Instance.Radius + FLife * 0.1, 0);
  FCapsule.LocalRotation := Rotate(Delta * 180, Vector3(0,1,0)) * FCapsule.LocalRotation;
  if not (FUsed) and (FLife <= 0) then
  begin
    FUsed := true;
    FAction(GameObject.LocalRotation, FTag);
    Rotation := GameObject.LocalRotation.Transpose;
    Position := GameObject.LocalRotation.Transpose * Vector3(0, TPlanetoid.Instance.Radius, 0);
    for i := 0 to 40 - 1 do
      TParticleRendererLayer.Emit(
        Position,
        Rotation * Vector3(Random(100) - 50, Random(20) - 10, Random(100) - 50) * 0.008,
            8, 0.3, 0.1);
    World.Stress();
  end;
  if (FLife < - 10) then
  begin
    Enable := False;
    FMeshRenderer.Enable := False;
  end;
end;

procedure TCapsule.OnDestroy;
begin

end;
{$ENDREGION}

end.
