program TetMan;

uses
  Windows,
  Forms,
  SysUtils,
  Messages,
  classes,
  DGLE in 'DGLE\DGLE.pas',
  DGLE_Types in 'DGLE\DGLE_Types.pas',
  DGLE_Base in 'DGLE\DGLE_Base.pas',
  DGLE_CoreRenderer in 'DGLE\DGLE_CoreRenderer.pas';

const
  APP_CAPTION = 'TetMan';
  FNT_MAIN = 'FntMain';
  FNT_MENU = 'FntMenu';
  //Figure types
  SQUARE = 0;
  LINE = 1;
  LSTAIR = 2;
  RSTAIR = 3;
  LGTYPE = 4;
  RGTYPE = 5;
  TTYPE = 6;
  ONE = 7;

  //COLORS
  RED:TColor4 = (r:0.96; g:0; b:0; a:255);
  GREEN:TColor4 = (r:0; g:0.86; b:0; a:255);
  BLUE:TColor4 = (r:0; g:0; b:0.70; a:255);
  YELLOW:TColor4 = (r:0.86; g:0.90; b:0; a:255);
  PURPLE:TColor4 = (r:0.86; g:0.58; b:0.86; a:255);
  AQUA:TColor4 = (r:0; g:0.58; b:1; a:255);
  PON:TColor4 = (r:0.58; g:0.39; b:0; a:255);
  NONE:TColor4 = (r:0; g:0; b:0; a:0);

type
  TCoordArray = array[1..4] of ShortInt;
  TSqr = record
    rec:TRectf;
    color:TColor4;
    bonus:byte;
  end;
  TFigure = record
    XA,YA:TCoordArray;
    Clrs:array[1..4] of TColor4;
    Typ:byte;
    Pos:byte;
  end;
  TFieldSize = record
    width:byte;
    height:byte;
  end;
var
  pInput:IInput=nil;
  pEngineCore:IEngineCore=nil;
  pResMan:IResourceManager=nil;
  pRender:IRender=nil;
  pRender2D:IRender2D=nil;

  pFrame:ITexture=nil;
  pCentre:ITexture=nil;
  pGar:IBitmapFont=nil;
  pGarBold:IBitmapFont=nil;
  gLvl:byte=1;
  gSpeed:byte=15;
  gLvlSpeed:byte=15;
  gSize:byte=25;
  gMode:byte=1;
  gMenu:byte=1;
  mTime:TTime;
  gScore:LongInt=0;
  gFieldSize:TFieldSize;
  gKeysPause:cardinal=0;
  gFile:TFileStream;
  gHScore:LongInt;
  gIsHScore:boolean=false;
  fgr:TFigure;
  Field:array of array of TSqr;
  moves:boolean=false;
  counter:integer=0;
  gTime:TTime;
  menu:boolean=true;

function ColorEqlt(col1,col2:TColor4):boolean;
begin
  if (col1.r=col2.r) and
     (col1.g=col2.g) and
     (col1.b=col2.b) and
     (col1.a=col2.a) then
    result:=true
  else
    result:=false;
end;

function MoveLeft(out X,Y:TCoordArray):boolean;
var
  i:byte;
  move:boolean;
begin
  move:=true;
  for i := 1 to 4 do
    if (X[i]-1)<0 then
    begin
      move:=false;
      break;
    end;
  if move then
  begin
    for i := 1 to 4 do
    begin
      if Field[X[i]-1,Y[i]].color.a<>0then
      begin
        move:=false;
        break;
      end;
    end;
  end;
  if move then
  begin
    for i := 1 to 4 do
    begin
      X[i]:=X[i]-1;
    end;
    result:=true;
  end else
    result:=false;
end;

function MoveRight(out X,Y:TCoordArray):boolean;
var
  i:byte;
  move:boolean;
begin
  move:=true;
  for i := 1 to 4 do
    if (X[i]+1)>gFieldSize.width-1 then
    begin
      move:=false;
      break;
    end;
  if move then
  begin
    for i := 1 to 4 do
    begin
      if Field[X[i]+1,Y[i]].color.a<>0then
      begin
        move:=false;
        break;
      end;
    end;
  end;
  if move then
  begin
    for i := 1 to 4 do
    begin
      X[i]:=X[i]+1;
    end;
    result:=true;
  end else
    result:=false;
end;

procedure RotateFigure;
var
  i,j,pos:byte;
  x,y:TCoordArray;
  rot:boolean;
  MinX,MaxY,MaxX:ShortInt;
begin
  case fgr.Typ of
    SQUARE:begin
      case fgr.Pos of
        1:begin
          x[1]:=fgr.XA[1]+1;
          y[1]:=fgr.YA[1];
          x[2]:=fgr.XA[2];
          y[2]:=fgr.YA[2]+1;
          x[3]:=fgr.XA[3];
          y[3]:=fgr.YA[3]-1;
          x[4]:=fgr.XA[4]-1;
          y[4]:=fgr.YA[4];
          pos:=2;
        end;
        2:begin
          x[1]:=fgr.XA[1];
          y[1]:=fgr.YA[1]+1;
          x[2]:=fgr.XA[2]-1;
          y[2]:=fgr.YA[2];
          x[3]:=fgr.XA[3]+1;
          y[3]:=fgr.YA[3];
          x[4]:=fgr.XA[4];
          y[4]:=fgr.YA[4]-1;
          pos:=3;
        end;
        3:begin
          x[1]:=fgr.XA[1]-1;
          y[1]:=fgr.YA[1];
          x[2]:=fgr.XA[2];
          y[2]:=fgr.YA[2]-1;
          x[3]:=fgr.XA[3];
          y[3]:=fgr.YA[3]+1;
          x[4]:=fgr.XA[4]+1;
          y[4]:=fgr.YA[4];
          pos:=4;
        end;
        4:begin
          x[1]:=fgr.XA[1];
          y[1]:=fgr.YA[1]-1;
          x[2]:=fgr.XA[2]+1;
          y[2]:=fgr.YA[2];
          x[3]:=fgr.XA[3]-1;
          y[3]:=fgr.YA[3];
          x[4]:=fgr.XA[4];
          y[4]:=fgr.YA[4]+1;
          pos:=1;
        end;
      end;
    end;
    LINE:begin
      case fgr.Pos of
        1:begin
          x[1]:=fgr.XA[1]+1;
          y[1]:=fgr.YA[1]-1;
          x[2]:=fgr.XA[2];
          y[2]:=fgr.YA[2];
          x[3]:=fgr.XA[3]-1;
          y[3]:=fgr.YA[3]+1;
          x[4]:=fgr.XA[4]-2;
          y[4]:=fgr.YA[4]+2;
          pos:=2;
        end;
        2:begin
          x[1]:=fgr.XA[1]+2;
          y[1]:=fgr.YA[1]+2;
          x[2]:=fgr.XA[2]+1;
          y[2]:=fgr.YA[2]+1;
          x[3]:=fgr.XA[3];
          y[3]:=fgr.YA[3];
          x[4]:=fgr.XA[4]-1;
          y[4]:=fgr.YA[4]-1;
          pos:=3;
        end;
        3:begin
          x[1]:=fgr.XA[1]-1;
          y[1]:=fgr.YA[1]+1;
          x[2]:=fgr.XA[2];
          y[2]:=fgr.YA[2];
          x[3]:=fgr.XA[3]+1;
          y[3]:=fgr.YA[3]-1;
          x[4]:=fgr.XA[4]+2;
          y[4]:=fgr.YA[4]-2;
          pos:=4;
        end;
        4:begin
          x[1]:=fgr.XA[1]-2;
          y[1]:=fgr.YA[1]-2;
          x[2]:=fgr.XA[2]-1;
          y[2]:=fgr.YA[2]-1;
          x[3]:=fgr.XA[3];
          y[3]:=fgr.YA[3];
          x[4]:=fgr.XA[4]+1;
          y[4]:=fgr.YA[4]+1;
          pos:=1;
        end;
      end;
    end;
    LSTAIR:begin
      case fgr.Pos of
        1:begin
          x[1]:=fgr.XA[1];
          y[1]:=fgr.YA[1]-2;
          x[2]:=fgr.XA[2]-1;
          y[2]:=fgr.YA[2]-1;
          x[3]:=fgr.XA[3];
          y[3]:=fgr.YA[3];
          x[4]:=fgr.XA[4]-1;
          y[4]:=fgr.YA[4]+1;
          pos:=2;
        end;
        2:begin
          x[1]:=fgr.XA[1]+2;
          y[1]:=fgr.YA[1];
          x[2]:=fgr.XA[2]+1;
          y[2]:=fgr.YA[2]-1;
          x[3]:=fgr.XA[3];
          y[3]:=fgr.YA[3];
          x[4]:=fgr.XA[4]-1;
          y[4]:=fgr.YA[4]-1;
          pos:=3;
        end;
        3:begin
          x[1]:=fgr.XA[1];
          y[1]:=fgr.YA[1]+2;
          x[2]:=fgr.XA[2]+1;
          y[2]:=fgr.YA[2]+1;
          x[3]:=fgr.XA[3];
          y[3]:=fgr.YA[3];
          x[4]:=fgr.XA[4]+1;
          y[4]:=fgr.YA[4]-1;
          pos:=4;
        end;
        4:begin
          x[1]:=fgr.XA[1]-2;
          y[1]:=fgr.YA[1];
          x[2]:=fgr.XA[2]-1;
          y[2]:=fgr.YA[2]+1;
          x[3]:=fgr.XA[3];
          y[3]:=fgr.YA[3];
          x[4]:=fgr.XA[4]+1;
          y[4]:=fgr.YA[4]+1;
          pos:=1;
        end;
      end;
    end;
    RSTAIR:begin
      case fgr.Pos of
        1:begin
          x[1]:=fgr.XA[1]+1;
          y[1]:=fgr.YA[1]-1;
          x[2]:=fgr.XA[2];
          y[2]:=fgr.YA[2];
          x[3]:=fgr.XA[3]-1;
          y[3]:=fgr.YA[3]-1;
          x[4]:=fgr.XA[4]-2;
          y[4]:=fgr.YA[4];
          pos:=2;
        end;
        2:begin
          x[1]:=fgr.XA[1]+1;
          y[1]:=fgr.YA[1]+1;
          x[2]:=fgr.XA[2];
          y[2]:=fgr.YA[2];
          x[3]:=fgr.XA[3]+1;
          y[3]:=fgr.YA[3]-1;
          x[4]:=fgr.XA[4];
          y[4]:=fgr.YA[4]-2;
          pos:=3;
        end;
        3:begin
          x[1]:=fgr.XA[1]-1;
          y[1]:=fgr.YA[1]+1;
          x[2]:=fgr.XA[2];
          y[2]:=fgr.YA[2];
          x[3]:=fgr.XA[3]+1;
          y[3]:=fgr.YA[3]+1;
          x[4]:=fgr.XA[4]+2;
          y[4]:=fgr.YA[4];
          pos:=4;
        end;
        4:begin
          x[1]:=fgr.XA[1]-1;
          y[1]:=fgr.YA[1]-1;
          x[2]:=fgr.XA[2];
          y[2]:=fgr.YA[2];
          x[3]:=fgr.XA[3]-1;
          y[3]:=fgr.YA[3]+1;
          x[4]:=fgr.XA[4];
          y[4]:=fgr.YA[4]+2;
          pos:=1;
        end;
      end;
    end;
    LGTYPE:begin
      case fgr.Pos of
        1:begin
          x[1]:=fgr.XA[1]+1;
          y[1]:=fgr.YA[1]-1;
          x[2]:=fgr.XA[2];
          y[2]:=fgr.YA[2];
          x[3]:=fgr.XA[3]-1;
          y[3]:=fgr.YA[3]+1;
          x[4]:=fgr.XA[4];
          y[4]:=fgr.YA[4]+2;
          pos:=2;
        end;
        2:begin
          x[1]:=fgr.XA[1]+1;
          y[1]:=fgr.YA[1]+1;
          x[2]:=fgr.XA[2];
          y[2]:=fgr.YA[2];
          x[3]:=fgr.XA[3]-1;
          y[3]:=fgr.YA[3]-1;
          x[4]:=fgr.XA[4]-2;
          y[4]:=fgr.YA[4];
          pos:=3;
        end;
        3:begin
          x[1]:=fgr.XA[1]-1;
          y[1]:=fgr.YA[1]+1;
          x[2]:=fgr.XA[2];
          y[2]:=fgr.YA[2];
          x[3]:=fgr.XA[3]+1;
          y[3]:=fgr.YA[3]-1;
          x[4]:=fgr.XA[4];
          y[4]:=fgr.YA[4]-2;
          pos:=4;
        end;
        4:begin
          x[1]:=fgr.XA[1]-1;
          y[1]:=fgr.YA[1]-1;
          x[2]:=fgr.XA[2];
          y[2]:=fgr.YA[2];
          x[3]:=fgr.XA[3]+1;
          y[3]:=fgr.YA[3]+1;
          x[4]:=fgr.XA[4]+2;
          y[4]:=fgr.YA[4];
          pos:=1;
        end;
      end;
    end;
    RGTYPE:begin
      case fgr.Pos of
        1:begin
          x[1]:=fgr.XA[1]+2;
          y[1]:=fgr.YA[1];
          x[2]:=fgr.XA[2]+1;
          y[2]:=fgr.YA[2]-1;
          x[3]:=fgr.XA[3];
          y[3]:=fgr.YA[3];
          x[4]:=fgr.XA[4]-1;
          y[4]:=fgr.YA[4]+1;
          pos:=2;
        end;
        2:begin
          x[1]:=fgr.XA[1];
          y[1]:=fgr.YA[1]+2;
          x[2]:=fgr.XA[2]+1;
          y[2]:=fgr.YA[2]+1;
          x[3]:=fgr.XA[3];
          y[3]:=fgr.YA[3];
          x[4]:=fgr.XA[4]-1;
          y[4]:=fgr.YA[4]-1;
          pos:=3;
        end;
        3:begin
          x[1]:=fgr.XA[1]-2;
          y[1]:=fgr.YA[1];
          x[2]:=fgr.XA[2]-1;
          y[2]:=fgr.YA[2]+1;
          x[3]:=fgr.XA[3];
          y[3]:=fgr.YA[3];
          x[4]:=fgr.XA[4]+1;
          y[4]:=fgr.YA[4]-1;
          pos:=4;
        end;
        4:begin
          x[1]:=fgr.XA[1];
          y[1]:=fgr.YA[1]-2;
          x[2]:=fgr.XA[2]-1;
          y[2]:=fgr.YA[2]-1;
          x[3]:=fgr.XA[3];
          y[3]:=fgr.YA[3];
          x[4]:=fgr.XA[4]+1;
          y[4]:=fgr.YA[4]+1;
          pos:=1;
        end;
      end;
    end;
    TTYPE:begin
      case fgr.Pos of
        1:begin
          x[1]:=fgr.XA[1]+1;
          y[1]:=fgr.YA[1]-1;
          x[2]:=fgr.XA[2];
          y[2]:=fgr.YA[2];
          x[3]:=fgr.XA[3]-1;
          y[3]:=fgr.YA[3]+1;
          x[4]:=fgr.XA[4]+1;
          y[4]:=fgr.YA[4]+1;
          pos:=2;
        end;
        2:begin
          x[1]:=fgr.XA[1]+1;
          y[1]:=fgr.YA[1]+1;
          x[2]:=fgr.XA[2];
          y[2]:=fgr.YA[2];
          x[3]:=fgr.XA[3]-1;
          y[3]:=fgr.YA[3]-1;
          x[4]:=fgr.XA[4]-1;
          y[4]:=fgr.YA[4]+1;
          pos:=3;
        end;
        3:begin
          x[1]:=fgr.XA[1]-1;
          y[1]:=fgr.YA[1]+1;
          x[2]:=fgr.XA[2];
          y[2]:=fgr.YA[2];
          x[3]:=fgr.XA[3]+1;
          y[3]:=fgr.YA[3]-1;
          x[4]:=fgr.XA[4]-1;
          y[4]:=fgr.YA[4]-1;
          pos:=4;
        end;
        4:begin
          x[1]:=fgr.XA[1]-1;
          y[1]:=fgr.YA[1]-1;
          x[2]:=fgr.XA[2];
          y[2]:=fgr.YA[2];
          x[3]:=fgr.XA[3]+1;
          y[3]:=fgr.YA[3]+1;
          x[4]:=fgr.XA[4]+1;
          y[4]:=fgr.YA[4]-1;
          pos:=1;
        end;
      end;
    end;
    ONE:begin

    end;
  end;
  MinX:=X[1];
  MaxX:=X[1];
  MaxY:=Y[1];
  for i := 2 to 4 do
  begin
    if X[i]<MinX then
      MinX:=X[i];
    if X[i]>MaxX then
      MaxX:=X[i];
    if Y[i]>MaxY then
      MaxY:=Y[i];
  end;
  if MinX<0 then
  begin
    if MinX=-2 then
      for i := 1 to 4 do
        Inc(x[i]);
    if MoveRight(X,Y) then
      rot:=true
    else
      rot:=false;
  end else
  begin
    if MaxX>gFieldSize.width-1 then
    begin
      if MaxX=gFieldSize.width+1 then
        for i := 1 to 4 do
          Dec(x[i]);
      if MoveLeft(X,Y) then
        rot:=true
      else
        rot:=false;
    end else
    begin
      if MaxY>gFieldSize.height-1 then
        rot:=false
      else
      begin
        rot:=true;
        for i := 1 to 4 do
          if Field[x[i],y[i]].color.a<>0 then
          begin
            rot:=false;
            break;
          end;
      end;
    end;
  end;
  if rot then
  begin
    fgr.XA:=X;
    fgr.YA:=Y;
    fgr.Pos:=pos;
  end;
end;

function RandomColor():TColor4;
begin
  case random(3) of
    3:result:=RED;
    4:result:=GREEN;
    6:result:=BLUE;
    0:result:=YELLOW;
    1:result:=PURPLE;
    2:result:=AQUA;
  end;
end;

function MoveDown():boolean;
var
  i:byte;
  move:boolean;
begin
  move:=true;
  for i := 1 to 4 do
    if (fgr.YA[i]+1)>(gFieldSize.height-1) then
      move:=false;
  if move then
  begin
    for i := 1 to 4 do
    begin
      if Field[fgr.XA[i],fgr.YA[i]+1].color.a<>0then
      begin
        move:=false;
      end;
    end;
  end;
  if move then
  begin
    for i := 1 to 4 do
    begin
      fgr.YA[i]:=fgr.YA[i]+1;
    end;
    result:=true;
  end else
  begin
    for i := 1 to 4 do
      Field[fgr.XA[i],fgr.YA[i]].color:=fgr.Clrs[i];
    result:=false;
  end;
end;

procedure CreateFigure(nX:shortInt; out Figure:TFigure);
var
  i:integer;
begin
  case Random(7) of
    SQUARE:begin
      Figure.Typ:=SQUARE;
      Figure.Pos:=1;
      Figure.XA[1]:=nX;
      Figure.XA[2]:=nX + 1;
      Figure.XA[3]:=nX;
      Figure.XA[4]:=nX + 1;
      Figure.YA[1]:=0;
      Figure.YA[2]:=0;
      Figure.YA[3]:=1;
      Figure.YA[4]:=1;
      for i := 1 to 4 do
      begin
        Figure.Clrs[i]:=RandomColor;
      end;
    end;
    LINE:begin
      Figure.Typ:=LINE;
      Figure.Pos:=1;
      Figure.XA[1]:=nX - 1;
      Figure.XA[2]:=nX;
      Figure.XA[3]:=nX + 1;
      Figure.XA[4]:=nX + 2;
      Figure.YA[1]:=0;
      Figure.YA[2]:=0;
      Figure.YA[3]:=0;
      Figure.YA[4]:=0;
      for i := 1 to 4 do
      begin
        Figure.Clrs[i]:=RandomColor;
      end;
    end;
    LSTAIR:begin
      Figure.Typ:=LSTAIR;
      Figure.Pos:=1;
      Figure.XA[1]:=nX - 1;
      Figure.XA[2]:=nX;
      Figure.XA[3]:=nX;
      Figure.XA[4]:=nX + 1;
      Figure.YA[1]:=1;
      Figure.YA[2]:=1;
      Figure.YA[3]:=0;
      Figure.YA[4]:=0;
      for i := 1 to 4 do
      begin
        Figure.Clrs[i]:=RandomColor;
      end;
    end;
    RSTAIR:begin
      Figure.Typ:=RSTAIR;
      Figure.Pos:=1;
      Figure.XA[1]:=nX - 1;
      Figure.XA[2]:=nX;
      Figure.XA[3]:=nX;
      Figure.XA[4]:=nX + 1;
      Figure.YA[1]:=0;
      Figure.YA[2]:=0;
      Figure.YA[3]:=1;
      Figure.YA[4]:=1;
      for i := 1 to 4 do
      begin
        Figure.Clrs[i]:=RandomColor;
      end;
    end;
    LGTYPE:begin
      Figure.Typ:=LGTYPE;
      Figure.Pos:=1;
      Figure.XA[1]:=nX - 1;
      Figure.XA[2]:=nX;
      Figure.XA[3]:=nX + 1;
      Figure.XA[4]:=nX + 1;
      Figure.YA[1]:=1;
      Figure.YA[2]:=1;
      Figure.YA[3]:=1;
      Figure.YA[4]:=0;
      for i := 1 to 4 do
      begin
        Figure.Clrs[i]:=RandomColor;
      end;
    end;
    RGTYPE:begin
      Figure.Typ:=RGTYPE;
      Figure.Pos:=1;
      Figure.XA[1]:=nX - 1;
      Figure.XA[2]:=nX - 1;
      Figure.XA[3]:=nX;
      Figure.XA[4]:=nX + 1;
      Figure.YA[1]:=0;
      Figure.YA[2]:=1;
      Figure.YA[3]:=1;
      Figure.YA[4]:=1;
      for i := 1 to 4 do
      begin
        Figure.Clrs[i]:=RandomColor;
      end;
    end;
    TTYPE:begin
      Figure.Typ:=TTYPE;
      Figure.Pos:=1;
      Figure.XA[1]:=nX - 1;
      Figure.XA[2]:=nX;
      Figure.XA[3]:=nX + 1;
      Figure.XA[4]:=nX;
      Figure.YA[1]:=1;
      Figure.YA[2]:=1;
      Figure.YA[3]:=1;
      Figure.YA[4]:=0;
      for i := 1 to 4 do
      begin
        Figure.Clrs[i]:=RandomColor;
      end;
    end;
    ONE:begin

    end;
  end;
end;

procedure ProcessMenu;
var
  prsd:boolean;
  i,j,l:integer;
begin
  pInput.GetKey(KEY_RETURN,prsd);
  if prsd then
  begin
    case gMode of
      1:begin
        case gMenu of
          1:begin
            for i := 0 to gFieldSize.width-1 do
              for j := 0 to gFieldSize.height-1 do
                Field[i,j].color:=NONE;
            moves:=false;
            menu:=false;
            gMode:=2;
            gScore:=0;
            gTime:=Time;
            gIsHScore:=false;
          end;
          2:pEngineCore.QuitEngine();
        end;
      end;
      2:begin
        case gMenu of
          1:begin
            for i := 0 to gFieldSize.width-1 do
              for j := 0 to gFieldSize.height-1 do
                Field[i,j].color:=NONE;
            moves:=false;
            menu:=false;
            gScore:=0;
            gTime:=Time;
            gIsHScore:=false;
          end;
          2:begin
            menu:=false;
            gTime:=gTime+(Time-mTime);
          end;
          3:pEngineCore.QuitEngine();
        end;
      end;
    end;
  end;

  pInput.GetKey(KEY_DOWN,prsd);
  if prsd and (gKeysPause>5) then
  begin
    case gMode of
      1:begin
        if gMenu=2 then
          gMenu:=1
        else
          Inc(gMenu);
      end;
      2:begin
        if gMenu=3 then
          gMenu:=1
        else
          Inc(gMenu);
      end;
    end;
    gKeysPause:=0;
  end else
    Inc(gKeysPause);

  pInput.GetKey(KEY_UP,prsd);
  if prsd and (gKeysPause>5) then
  begin
    case gMode of
      1:begin
        if gMenu=1 then
          gMenu:=2
        else
          Dec(gMenu);
      end;
      2:begin
        if gMenu=1 then
          gMenu:=3
        else
          Dec(gMenu);
      end;
    end;
    gKeysPause:=0;
  end else
    Inc(gKeysPause);
end;

procedure RenderMenu;
var TXT:PAnsiChar;
    w,h:Cardinal;
    i,j:integer;
begin
  TXT:='IGDC #100 Back to the Future';
  pGar.GetTextDimensions(TXT, w, h);
  pGar.Draw2D(Screen.Width div 2 - w div 2,100,TXT,Color4(255,255,0,255));
  case gMode of
    1:begin
      if gMenu=1 then
        pGarBold.Draw2D(Screen.Width-200,300,'Новая игра',Color4(255,255,0,255))
      else
        pGar.Draw2D(Screen.Width-200,300,'Новая игра',Color4(255,255,0,255));
      if gMenu=2 then
        pGarBold.Draw2D(Screen.Width-200,350,'Выход',Color4(255,255,0,255))
      else
        pGar.Draw2D(Screen.Width-200,350,'Выход',Color4(255,255,0,255));
    end;
    2:begin
      if gMenu=1 then
        pGarBold.Draw2D(Screen.Width-200,250,'Новая игра',Color4(255,255,0,255))
      else
        pGar.Draw2D(Screen.Width-200,250,'Новая игра',Color4(255,255,0,255));
      if gMenu=2 then
        pGarBold.Draw2D(Screen.Width-200,300,'Продолжить',Color4(255,255,0,255))
      else
        pGar.Draw2D(Screen.Width-200,300,'Продолжить',Color4(255,255,0,255));
      if gMenu=3 then
        pGarBold.Draw2D(Screen.Width-200,350,'Выход',Color4(255,255,0,255))
      else
        pGar.Draw2D(Screen.Width-200,350,'Выход',Color4(255,255,0,255));
    end;
  end;
  TXT:=PAnsiChar('Лучший счёт: '+AnsiString(IntToStr(gHScore)));
  pGar.GetTextDimensions(TXT, w, h);
  pGar.Draw2D((Screen.Width-w) div 2,Screen.Height-40,TXT,Color4(255,255,0,255));

  pGar.SetScale(2);
  pGar.GetTextDimensions(APP_CAPTION,w,h);
  pGar.Draw2D((Screen.Width-w) div 2,(Screen.Height-h) div 2,APP_CAPTION,Color4(255,255,0,255));
  pGar.SetScale(1);
end;

procedure ProcessGame;
var
  prsd:boolean;
  i,j,k,x:integer;
  count,LineCount:integer;
  TempColor:TColor4;
  mins,all:word;
begin
  if gMode<>1 then
  begin
  //Move left
    pInput.GetKey(KEY_LEFT,prsd);
    if prsd and (gKeysPause>10) then
    begin
      MoveLeft(fgr.XA,fgr.YA);
      gKeysPause:=0;
    end else
      Inc(gKeysPause);

  //Move right
    pInput.GetKey(KEY_RIGHT,prsd);
    if prsd and (gKeysPause>10) then
    begin
      MoveRight(fgr.XA,fgr.YA);
      gKeysPause:=0;
    end else
      Inc(gKeysPause);

    //Color burn
    k:=gFieldSize.height-1;
    while k>-1 do
    begin
      count:=0;
      TempColor:=NONE;
      for i:=0 to gFieldSize.width-1 do
      begin
        if Not(ColorEqlt(Field[i,k].color,NONE)) and
           ColorEqlt(Field[i,k].color,TempColor) and
           Not(ColorEqlt(Field[i,k].color,PON)) then
          Inc(count)
        else
        begin
          if count>2 then
          begin
            for j := i-count to i-1 do
            begin
              Field[j,k].color:=PON;
            end;
            gScore:=gScore+count*10*(16-gLvlSpeed);
          end;
          count:=1;
          TempColor:=Field[i,k].color;
        end;
      end;
      if count>2 then
      begin
        for j:=gFieldSize.width-count to gFieldSize.width-1 do
        begin
          Field[j,k].color:=PON;
        end;
        gScore:=gScore+count*10*(16-gLvlSpeed);
      end;
      Dec(k);
    end;

    //Line burn
    LineCount:=0;
    k:=gFieldSize.height-1;
    while k>-1 do
    begin
      count:=0;
      for i:=0 to gFieldSize.width-1 do
      begin
        if Field[i,k].color.a=0 then
          break
        else
          Inc(count);
      end;
      if count=gFieldSize.width then
      begin
        Inc(LineCount);
        for j:=k downto 1 do
          for i:=0 to gFieldSize.width-1 do
             Field[i,j].color:=Field[i,j-1].color;
        for i:=0 to gFieldSize.width-1 do
          Field[i,0].color:=NONE;
        Inc(k);
      end;
      Dec(k);
    end;
    if LineCount<>0 then
      gScore:=gScore+(10*LineCount*(16-gLvlSpeed))*LineCount;

  //Move down and create new figure
    if moves then
    begin
      if Counter mod gSpeed = 0 then
        moves:=MoveDown();
    end else
    begin
      CreateFigure(gFieldSize.width div 2,fgr);
      moves:=true;
    end;

  //GAMEOVER
    for i := 0 to gFieldSize.width-1 do
      if not(ColorEqlt(Field[i,0].color,NONE)) then
      begin
        if gScore>gHScore then
        begin
          gIsHScore:=true;
          gHScore:=gScore;
          gFile:=TFileStream.Create('res\hs.bin', fmOpenReadWrite);
          gFile.WriteBuffer(gHScore,SizeOf(LongInt));
          gFile.Free;
        end;
        gMode:=1;
      end;

  //Colore change
    pInput.GetKey(KEY_DOWN,prsd);
    if prsd and (gKeysPause>15) then
    begin
      TempColor:=fgr.Clrs[4];
      for i := 4 downto 2 do
        fgr.Clrs[i]:=fgr.Clrs[i-1];
      fgr.Clrs[1]:=TempColor;
      gKeysPause:=0;
    end else
      Inc(gKeysPause);

  //Rotation figure
    pInput.GetKey(KEY_UP,prsd);
    if prsd and (gKeysPause>15) then
    begin
      RotateFigure;
      gKeysPause:=0;
    end else
      Inc(gKeysPause);

  //Increas lvl
    DecodeTime((Time-gTime),all,mins,all,all);
    case mins div 1 of
      1:gLvlSpeed:=14;
      2:gLvlSpeed:=13;
      3:gLvlSpeed:=12;
      4:gLvlSpeed:=11;
      5:gLvlSpeed:=10;
      6:gLvlSpeed:=9;
      7:gLvlSpeed:=8;
      8:gLvlSpeed:=7;
      9:gLvlSpeed:=6;
      10:gLvlSpeed:=5;
      11:gLvlSpeed:=4;
      12:gLvlSpeed:=3;
      13:gLvlSpeed:=2;
      14:gLvlSpeed:=1;
    end;
    gSpeed:=gLvlSpeed;

  //Increas speed
    pInput.GetKey(KEY_SPACE,prsd);
    if prsd then
    begin
      if gLvlSpeed>2 then
        gSpeed:=2;
    end else
      gSpeed:=gLvlSpeed;
  end;

//Show menu
  pInput.GetKey(KEY_ESCAPE,prsd);
  if prsd then
  begin
    counter:=0;
    menu:=true;
    mTime:=time;
  end;
end;

procedure RenderGame;
var
  i,j:integer;
  w,h:Cardinal;
  TXT:PAnsiChar;
begin
//Render Score
  TXT:=PAnsiChar(pansichar('Очки: '+AnsiString(IntToStr(gScore))));
  pGar.GetTextDimensions(TXT, w, h);
  pGar.Draw2D(Screen.Width-w-10,10,TXT,Color4(255,255,0,255));

//Render Speed
  TXT:=PAnsiChar(pansichar('Скорость: '+AnsiString(IntToStr(16-gLvlSpeed))));
  pGar.GetTextDimensions(TXT, w, h);
  pGar.Draw2D(Screen.Width-w-10,50,TXT,Color4(255,255,0,255));

//Render Field Line
  pRender2D.SetLineWidth(2);
  pRender2D.DrawRectangle(Rectf((Screen.Width-gFieldSize.width*gSize) div 2+10,10,gSize * gFieldSize.width+2, gSize * gFieldSize.height+2),AQUA);

//Render Field
  for i := 0 to gFieldSize.width-1 do
    for j := 0 to gFieldSize.height-1 do
    begin
      pRender2D.DrawRectangle(Field[i,j].rec,Field[i,j].color,PF_FILL);
      if Field[i,j].color.a<>0 then
        pRender2D.DrawTexture(pFrame,Point2(Field[i,j].rec.x,Field[i,j].rec.y),Point2(gSize,gSize));
      if ColorEqlt(Field[i,j].color,PON) then
        pRender2D.DrawTexture(pCentre,Point2(Field[i,j].rec.x+5,Field[i,j].rec.y+5),Point2(gSize-10,gSize-10));
    end;

//Render Figure
  for i := 1 to 4 do
  begin
    pRender2D.DrawRectangle(Field[fgr.XA[i],fgr.YA[i]].rec,fgr.Clrs[i],PF_FILL);
    pRender2D.DrawTexture(pFrame,Point2(Field[fgr.XA[i],fgr.YA[i]].rec.x,Field[fgr.XA[i],fgr.YA[i]].rec.y),Point2(gSize,gSize));
  end;
//Render GAMEOVER text
  if gMode=1 then
  begin
    TXT:=PAnsiChar('Игра окончена! Ваш счёт: '+AnsiString(IntToStr(gScore)));
    pGarBold.GetTextDimensions(TXT, w, h);
    pGarBold.Draw2D((Screen.Width-w) div 2,(Screen.Height-h) div 2,TXT,RED);
  end;
//Render NEW HiScore
  if gIsHScore then
  begin
    TXT:=PAnsiChar('Поздравляем! Это новый рекорд!!!');
    pGarBold.GetTextDimensions(TXT, w, h);
    pGarBold.Draw2D((Screen.Width-w) div 2,(Screen.Height-h) div 2 + 40,TXT,RED);
  end;
end;

procedure Init(pParametr:Pointer); stdcall;
var
  i,j:integer;
  x,y:single;
begin
  pEngineCore.GetSubsystem(ESS_RESOURCE_MANAGER,IEngineSubSystem(pResMan));
  pEngineCore.GetSubsystem(ESS_RENDER,IEngineSubSystem(pRender));
  pEngineCore.GetSubsystem(ESS_INPUT,IEngineSubSystem(pInput));
  pRender.GetRender2D(pRender2D);
	pRender.SetClearColor(Color4(0, 0, 0, 255));
  pRender2D.SetResolutionCorrection(Screen.Width,Screen.Height);
  pInput.Configure(ICF_HIDE_CURSOR);

  pResMan.Load('res\textures\frame.png',IEngineBaseObject(pFrame),TEXTURE_LOAD_DEFAULT_2D);
  pResMan.Load('res\textures\centre.png',IEngineBaseObject(pCentre),TEXTURE_LOAD_DEFAULT_2D);
  pResMan.Load('res\fonts\garamond.dft',IEngineBaseObject(pGar),RES_LOAD_DEFAULT, FNT_MAIN);
  pResMan.Load('res\fonts\garamondB.dft',IEngineBaseObject(pGarBold),RES_LOAD_DEFAULT, FNT_MENU);  randomize;

//Initialize game field
  gSize:=(Screen.Height - 20) div 20;
  gFieldSize.width:=12;
  gFieldSize.height:=20;
  SetLength(Field,gFieldSize.width,gFieldSize.height);
  x:=(Screen.Width-gFieldSize.width*gSize) div 2+11;
  y:=11;
  for i := 0 to gFieldSize.width-1 do
  begin
    Field[i,0].rec:=Rectf(x,y,gSize,gSize);
    Field[i,0].color:=NONE;
    for j := 1 to gFieldSize.height-1 do
    begin
      Field[i,j].rec:=RectF(Field[i,0].rec.x,Field[i,j-1].rec.y+gSize,gSize,gSize);
      Field[i,j].color:=NONE;
    end;
    x:=x+gSize;
  end;

//Load HiScore
  try
    gFile:=TFileStream.Create('res\hs.bin', fmOpenReadWrite);
    gFile.ReadBuffer(gHScore,SizeOf(LongInt));
    gFile.Free;
  except
    gFile:=TFileStream.Create('res\hs.bin', fmCreate);
    gHScore:=0;
    gFile.WriteBuffer(gHScore,SizeOf(LongInt));
    gFile.Free;
  end;
end;

procedure Update(pParametr:Pointer); stdcall;
var t:TTime;
begin
  if menu then
    ProcessMenu
  else
    ProcessGame;
  if Counter>2000000000 then
    Counter:=30
  else
    Inc(Counter);
end;

procedure Render(pParametr:Pointer); stdcall;
begin
  pRender2D.Begin2D;
  if menu then
    RenderMenu
  else
    RenderGame;
  pRender2D.End2D;
end;

procedure Free(pParametr:Pointer); stdcall;
begin
  pInput:=nil;
  pEngineCore:=nil;
  pResMan:=nil;
  pRender:=nil;
  pRender2D:=nil;

  Field:=nil;
  pCentre:=nil;
  pFrame:=nil;
  pGar:=nil;
  pGarBold:=nil;
end;

begin
  if (GetEngine('DGLE.dll',pEngineCore)) then
  begin
    if (SUCCEEDED(pEngineCore.InitializeEngine(0,APP_CAPTION,EngWindow(Screen.Width,Screen.Height,true,false,MM_NONE,EWF_DEFAULT)))) then
    begin
      pEngineCore.AddProcedure(EPT_INIT,@Init);
      pEngineCore.AddProcedure(EPT_UPDATE,@Update);
      pEngineCore.AddProcedure(EPT_RENDER,@Render);
      pEngineCore.AddProcedure(EPT_FREE,@Free);
      pEngineCore.StartEngine();
    end;
    FreeEngine();
  end
  else
    MessageBox(0,'Не загружается DGLE.dll!',APP_CAPTION,MB_OK or MB_ICONERROR or MB_SETFOREGROUND);
end.
