unit Landscape;

interface      

uses
  _Geometry,
  Frost.Renderers,
  Frost.Engine,
  Frost.GL,
  _PNG;

const
  Map_X = 60;
  Map_Y = 60;

type
TCellType = (
  CTNone,
  CTDesert,
  CTForest,   
  CTPatrol,    
  CTTower,
  CTFactory,
  CTRadar,  
  CTLaboratory,
  CTControlCenter,
  CTMonorail,
  CTBase
  );

TMapCell = record
  CellType: TCellType;
  ObjectsOnCell: TGameObject;
  UnitOnCell: array [0..3] of TGameObject;  
  end;

TLandscape = class(TComponent)
  private
    FMap: Array [0..Map_X, 0..Map_Y] of TMapCell;
    FMesh: TMesh;
    procedure GenerateMap;
    function GenerateMapMesh: TMesh;
  public                 
    procedure GenerateMapObjects;
    procedure OnStart; override;
    procedure OnUpdate(const Delta: Double); override;
    procedure OnDestroy; override;
  end;

implementation

uses
  LandZone, 
  Forest,
  Factory,
  Laboratory,   
  Radar,
  ControlCenter,
  Monorail,
  AATower,   
  BaseEnemy,
  Hero;

const
  TILE_SIZE = 4.0;
{$REGION 'Landscape'}
{$REGION 'Generator'}
procedure TLandscape.GenerateMap;
var
  i, j: Integer;
begin
  for i := 0 to Map_X do
    for j := 0 to Map_Y do
    begin
      FMap[i, j].CellType := TCellType(Random(8) * Random(2) + (1 - Random(2) * Random(2) * Random(2) * Random(2) * Random(2)));
      if (FMap[i, j].CellType = CTFactory) and(Random(7) = 0) then
        FMap[i, j].CellType := CTPatrol;
      if (FMap[i, j].CellType = CTRadar) and(Random(7) = 0) then
        FMap[i, j].CellType := CTPatrol;
      if (FMap[i, j].CellType = CTControlCenter) and(Random(7) = 0) then
        FMap[i, j].CellType := CTTower;
      if (FMap[i, j].CellType = CTLaboratory) and(Random(7) = 0) then
        FMap[i, j].CellType := CTTower;
    end;
  // Landing      
  for i := 8 to 12 do
    for j := 8 to 12 do
      FMap[i, j].CellType := CTDesert;
  FMap[10,10].CellType := CTBase;

  for j := 0 to Map_Y do
    FMap[16, j].CellType := CTMonorail;
end;

function TLandscape.GenerateMapMesh: TMesh;
var
  i, j,
  Count: Integer;
  Vertex:   TVertexes;
  Normals:  TNormals;
  Textures: TTextures;
  Faces: TFaces;
begin
  Count := 0;
  for i := 0 to Map_X do
    for j := 0 to Map_Y do
    begin
      if (FMap[i,j].CellType <> CTForest) then
        Inc(Count);
    end;
//      case FMap[i, j].CellType of
//        None: ;
//        Desert:;
//        Forest:;
//        Base:;
//      end;
  SetLength(Vertex,   Count * 4);
  SetLength(Textures, Count * 4);
  SetLength(Normals,  Count * 4);
  SetLength(Faces,    Count * 2);
  Count := 0;
  for i := 0 to Map_X do
    for j := 0 to Map_Y do
    begin             
      if (FMap[i,j].CellType <> CTForest) then
      begin
        Vertex[Count * 4 + 0] := Vector3( TILE_SIZE * 0.5 + TILE_SIZE * i, -TILE_SIZE * 0.5 + TILE_SIZE * j,  0); //up
        Vertex[Count * 4 + 1] := Vector3( TILE_SIZE * 0.5 + TILE_SIZE * i,  TILE_SIZE * 0.5 + TILE_SIZE * j,  0);
        Vertex[Count * 4 + 2] := Vector3(-TILE_SIZE * 0.5 + TILE_SIZE * i,  TILE_SIZE * 0.5 + TILE_SIZE * j,  0);
        Vertex[Count * 4 + 3] := Vector3(-TILE_SIZE * 0.5 + TILE_SIZE * i, -TILE_SIZE * 0.5 + TILE_SIZE * j,  0);
        Normals[Count * 4 + 0] := Vector3( 0,  0,  1); //up
        Normals[Count * 4 + 1] := Vector3( 0,  0,  1);
        Normals[Count * 4 + 2] := Vector3( 0,  0,  1);
        Normals[Count * 4 + 3] := Vector3( 0,  0,  1);  
        Textures[Count * 4 + 0] := Vector2(0, 1);
        Textures[Count * 4 + 1] := Vector2(0, 0); //up
        Textures[Count * 4 + 2] := Vector2(1, 0);
        Textures[Count * 4 + 3] := Vector2(1, 1);
        Faces[Count * 2 + 0] := Face( 0 + Count * 4, 1 + Count * 4, 2 + Count * 4);
        Faces[Count * 2 + 1] := Face( 0 + Count * 4, 2 + Count * 4, 3 + Count * 4);
        Inc(Count);
      end;
    end;
  Result := TMesh.Create(Faces, Vertex, Textures, Normals);
  SetLength(Vertex, 0);
  SetLength(Textures, 0);
  SetLength(Normals, 0);
  SetLength(Faces, 0);
end;
{$ENDREGION}
procedure TLandscape.GenerateMapObjects;
var
  i, j, z: Integer;
  AddObject: TGameObject;
begin
  for i := 0 to Map_X do
    for j := 0 to Map_Y do
      case FMap[i, j].CellType of
        CTNone: ;
        CTDesert:;
        CTPatrol:begin
            FMap[i, j].UnitOnCell[0] := TGameObject.Create(nil,  Vector3( TILE_SIZE * i, TILE_SIZE * j,  0) + Vector3( (Random(20) - 10) * 0.1, (Random(20) - 10) * 0.1,  0));
            TBaseEnemy.Create(FMap[i, j].UnitOnCell[0]);
            FMap[i, j].UnitOnCell[1] := TGameObject.Create(nil,  Vector3( TILE_SIZE * i, TILE_SIZE * j,  0) + Vector3( (Random(20) - 10) * 0.1, (Random(20) - 10) * 0.1,  0));
            TBaseEnemy.Create(FMap[i, j].UnitOnCell[1]);
          end;
        CTTower:begin
            FMap[i, j].UnitOnCell[0] := TGameObject.Create(nil,  Vector3( TILE_SIZE * i, TILE_SIZE * j,  0));
            TAATower.Create(FMap[i, j].UnitOnCell[0]);
          end;
        CTForest: begin
            FMap[i, j].ObjectsOnCell := TGameObject.Create(nil,  Vector3( TILE_SIZE * i, TILE_SIZE * j,  0));
            FMap[i, j].ObjectsOnCell.LocalRotation := Rotate(Random(4) * 90, Vector3(0,0,1));
            TForest.Create(FMap[i, j].ObjectsOnCell);
          end;
        CTFactory: begin
            FMap[i, j].ObjectsOnCell := TGameObject.Create(nil,  Vector3( TILE_SIZE * i, TILE_SIZE * j,  0));
            TFactory.Create(FMap[i, j].ObjectsOnCell);
//            TLaboratory.Create(FMap[i, j].ObjectsOnCell);
//            TRadar.Create(FMap[i, j].ObjectsOnCell);
          end;                   
        CTLaboratory: begin
            FMap[i, j].ObjectsOnCell := TGameObject.Create(nil,  Vector3( TILE_SIZE * i, TILE_SIZE * j,  0));
            TLaboratory.Create(FMap[i, j].ObjectsOnCell);
          end;                  
        CTRadar: begin
            FMap[i, j].ObjectsOnCell := TGameObject.Create(nil,  Vector3( TILE_SIZE * i, TILE_SIZE * j,  0));
            TRadar.Create(FMap[i, j].ObjectsOnCell);
          end;
        CTControlCenter:begin
            FMap[i, j].ObjectsOnCell := TGameObject.Create(nil,  Vector3( TILE_SIZE * i, TILE_SIZE * j,  0));
            TControlCenter.Create(FMap[i, j].ObjectsOnCell);
          end;            
        CTMonorail: begin
            FMap[i, j].ObjectsOnCell := TGameObject.Create(nil,  Vector3( TILE_SIZE * i, TILE_SIZE * j,  0));
            TMonorail.Create(FMap[i, j].ObjectsOnCell);
          end;
        CTBase: begin
            FMap[i, j].ObjectsOnCell := TGameObject.Create(nil,  Vector3( TILE_SIZE * i, TILE_SIZE * j,  0));
            TLandZone.Create(FMap[i, j].ObjectsOnCell);
          end;
      end;
end;


procedure TLandscape.OnStart;
var
   MeshRenderer: TMeshRenderer;
begin
//  Instance := Self;
  GenerateMap;
  THero.FInstance.GameObject.LocalPosition := Vector3(10 * TILE_SIZE, 10 * TILE_SIZE, 0);
  FMesh := GenerateMapMesh;
//  FMesh := TMesh.CreateCube(5);
//  FMesh.Translate(Vector3(5,0,-5)).AttachMesh(TMesh.CreateCube(4).Translate(Vector3(-5,0,-5)));
  MeshRenderer := TMeshRenderer.Create(GameObject);
  MeshRenderer.Mesh := FMesh;
  MeshRenderer.Material := TTexturedMaterial.Create(LoadPNGTexture('data/textures/ground.png'));   
  GenerateMapObjects;
end;

procedure TLandscape.OnUpdate(const Delta: Double);
var
  i, j, z: Integer;
  Sx, Sy, Ex, Ey: Integer;
begin
  Sx := Round(THero.FInstance.GameObject.Position.X / TILE_SIZE) - 6;
  Sy := Round(THero.FInstance.GameObject.Position.Y / TILE_SIZE) - 6;
  Ex := Round(THero.FInstance.GameObject.Position.X / TILE_SIZE) + 6;
  Ey := Round(THero.FInstance.GameObject.Position.Y / TILE_SIZE) + 6;
  if (Sx < 0) then Sx := 0;
  if (Sy < 0) then Sy := 0;
  if (Ex > Map_X) then Ex := Map_X;
  if (Ey > Map_Y) then Ey := Map_Y;

  for i := 0 to Map_X do
    for j := 0 to Map_Y do
    begin
      if
        (i >= Sx) and (i <= Ex) and
        (j >= Sy) and (j <= Ey) then
        begin
          if (FMap[i, j].ObjectsOnCell <> nil) then
            FMap[i, j].ObjectsOnCell.Enabled := true;
          for z := 0 to 3 do
            if (FMap[i, j].UnitOnCell[z] <> nil) then
              FMap[i, j].UnitOnCell[z].Enabled := true;
        end else
        begin
          if (FMap[i, j].ObjectsOnCell <> nil) then
            FMap[i, j].ObjectsOnCell.Enabled := false;
          for z := 0 to 3 do
            if (FMap[i, j].UnitOnCell[z] <> nil) then
              FMap[i, j].UnitOnCell[z].Enabled := false;
        end;
    end;
    
  THero.FInstance.GameObject.Position
end;

procedure TLandscape.OnDestroy;
begin

end;

{$ENDREGION}

end.
