unit Scenes;

interface
  uses  windows, RoadGlobal, RoadSys, RoadGraphic, RoadPhysic, SnakeUnits, opengl, RoadUnit, sysutils;
  type
    TSceneClass = class of TSceneBase;
    TSceneBase  = class(TObject)
      constructor Create;
      procedure InitScene;virtual;
      procedure FreeScene;virtual;
      procedure DrawScene;virtual;abstract;
      procedure UpdateScene;virtual;abstract;
    end;

    TSceneIntro = class(TSceneBase)
      Font : TGraphicFont;
      Timer : dword;
      gamma : Single;
      procedure DrawScene;override;
      procedure UpdateScene;override;
      procedure FreeScene;override;
    end;

    TSceneGame  = class(TSceneBase)
      Font      : TGraphicFont;
//      Snake : TRoadUnit;
      SelectMode : Boolean;
      Units : array of TRoadUnit;
      UnitCount : integer;
      EnemyTime : integer;
      EnemyTime2: integer;
      Score     : integer;
      BodyMax   : integer;
      procedure InitScene;override;
      procedure UpdateScene;override;
      procedure DrawScene;override;
      procedure FreeScene;override;
    end;

    TSceneOutro = class(TSceneBase)
      Font : TGraphicFont;
      Score : integer;
      procedure InitScene;override;
      procedure DrawScene;override;
      procedure UpdateScene;override;
      procedure FreeScene;override;
    end;

var
    Scene : TSceneBase;
implementation


{ TSceneBase }

constructor TSceneBase.Create;
begin
  InitScene;
end;

procedure TSceneBase.FreeScene;
begin
  Free;
end;

procedure TSceneBase.InitScene;
begin
  if Assigned(Scene) then
    Scene.FreeScene;
  Scene :=  Self;
  Application.SetUpdateProc(Scene.UpdateScene);
  Application.SetRenderProc(Scene.DrawScene);
end;

{ TSceneIntro }

procedure TSceneIntro.DrawScene;
var
  Font  : TGraphicFont;
begin
  inherited;
  Render.ClearBuffer;
  Font  :=  Render.CreateFont('Arial Black',24);
  glColor3f(0.4*gamma,0.4*gamma,0.9*gamma);
  Font.DrawText2D(-0.8,0.8,'W - Move Forward');
  Font.DrawText2D(-0.8,0.7,'A - Rotate Left');
  Font.DrawText2D(-0.8,0.6,'D - Rotate Right');
  Font.DrawText2D(-0.8,0.5,'Left Mouse - Fire');
  Font.DrawText2D(-0.8,-0.5,'Collect white items');
  Font.DrawText2D(-0.8,-0.6,'Eliminate enemy');
  Font.DrawText2D(-0.8,-0.8,'Press Left Mouse to Game');

  glColor3f(0,gamma,0);
  Font.DrawText2D(-0.2,0,'CRAZY SNAKE');
  Font.Free;
  Render.SwapBuffers;
end;

procedure TSceneIntro.FreeScene;
begin
  inherited;
//  Font.Free;
end;

procedure TSceneIntro.UpdateScene;
var
  gammtim : dword;
begin
  inherited;
  if timer=0 then
    timer :=  GetTickCount;
  gammtim :=  GetTickCount - Timer;
  if gammtim < 1000 then
    gamma :=  gammtim / 1000;
//      else
//        gamma :=  1-(gammtim-1000)/1000;
//  if gammtim>2000 then
//    gamma :=  0;
  if Application.Mouse.LButton then
   begin
    TSceneGame.Create;
    exit;
   end;
  if Application.Keys[vk_escape]=1 then
    FreeScene;  
end;

{ TSceneGame }
var
  an:single;
procedure TSceneGame.DrawScene;
var
  i : integer;
begin
  inherited;
  Render.ClearBuffer;
  glClearDepth(1.0);
  glDepthFunc(GL_LESS);
  glEnable(GL_DEPTH_TEST);
  glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);

  Render.ResetProjectionMatrix;
  Render.SetPerspective;
  Render.ResetModelViewMatrix;
  if not SelectMode then
   begin
   glPushMatrix;
   glColor3f(0,1,0);
    Font.DrawText3D(-0.7,0.5,-1.5,'SCORE = ' + IntToStr(Score));
    glPopMatrix;
   glPushMatrix;
   glColor3f(0,1,0);
    Font.DrawText3D(0.5,0.5,-1.5,'Body = ' + IntToStr((Units[0].Physic as TSnakePhysic).BodyCount));
    glPopMatrix;
    if (Units[0].Physic as TSnakePhysic).BomB then
      begin
         glPushMatrix;
         glColor3f(0,1,0);
          Font.DrawText3D(-0.5,-0.5,-1.5,'Press Right Mouse to BOMB!!!');
          glPopMatrix;
      end;
   end;

  WITH (units[0].Physic as TSnakePhysic) DO
    begin
      glRotatef(45,1,0,0);
      glTranslatef(0,-5,-5);
      glTranslatef(-Position.X,-Position.Y,-Position.Z);
   end;
  glEnable(GL_LIGHTING);
  glEnable(GL_LIGHT0);
  glLightModel(GL_LIGHT_MODEL_AMBIENT,0.7);
  glEnable(GL_COLOR_MATERIAL);
  for i:=0 to UnitCount-1 do
   if Units[i]<>nil then
     Units[i].Graphic.Draw;
     glColor3f(0.2,0.2,0.2);
      glBegin(GL_QUADS);
      glVertex3f(-5,0,-5);
      glVertex3f(-5,0,5);
      glVertex3f(5,0,5);
      glVertex3f(5,0,-5);
      glEnd;
      glColor3f(1,0,0);
      glLineWidth(5);
      glShadeModel(GL_SMOOTH);
      glEnable(GL_POLYGON_SMOOTH);
      glEnable(GL_LINE_SMOOTH);
      glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST);
      glHint(GL_POLYGON_SMOOTH_HINT,GL_NICEST);
      glHint(GL_LINE_SMOOTH_HINT,GL_NICEST);

      glBegin(GL_LINE_STRIP);
      glVertex3f(-5,0,-5);
      glVertex3f(-5,0,5);
      glVertex3f(5,0,5);
      glVertex3f(5,0,-5);
      glVertex3f(-5,0,-5);
      glEnd;

  glColor3f(0,1,0);
  if not SelectMode then
  begin
//    Font.DrawText2D(0,0.5,'SCORE = ' + IntToStr(Score));
//  glRasterPos2f(0,0);
    glFinish;
    Render.SwapBuffers;
  end;
end;

procedure TSceneGame.FreeScene;
var
  i : integer;
begin
  for i:=0 to UnitCount-1 do
    if Units[i]<>nil then
      begin
        Units[i].Free;
        Units[i]:=nil;
      end;  
  Units :=  nil;    
  Font.Free;
  inherited;
end;

procedure TSceneGame.InitScene;
begin
  inherited;
  Render.SetRenderContext;
  Font  :=  Render.CreateFont('Arial Black',24);
  SetLength(Units,1000);
  Units[0] :=  TRoadUnit.Construct(TSnakePhysic,TSnakeGraphic);
  Units[0].Physic.Position.Z :=  2.5;
  Units[0].Physic.Position.X :=  2.5;
  (Units[0].Physic as TSnakePhysic).BodyCount  :=  3;
  SetLength((Units[0].Physic as TSnakePhysic).Body,100);
  Units[1]  :=  TRoadUnit.Construct(TFoodPhysic,TFoodGraphic);
  UnitCount :=  2;
  EnemyTime2  :=  GetTickCount;
end;


procedure TSceneGame.UpdateScene;
var
  i : integer;
begin
  inherited;
  if (Application.Keys[vk_escape]=1) or ((Units[0].Physic as TSnakePhysic).BodyCount=0) then
    begin
      TSceneOutro.Create;
      Exit;
    end;
  if (Units[0].Physic as TSnakePhysic).BodyCount>BodyMax then
   begin
    BodyMax := (Units[0].Physic as TSnakePhysic).BodyCount;
    if (BodyMax mod 10) = 0 then
      (Units[0].Physic as TSnakePhysic).Bomb := True;
   end;
  Score :=  BodyMax+(GetTickCount-EnemyTime2) div 5000;
  for i:=0 to UnitCount-1 do
   if Units[i]<>nil then
    Units[i].Physic.Update;
  EnemyTime :=  EnemyTime - dt;
  if EnemyTime>=0 then
    Exit;
  EnemyTime :=  2000-1*(GetTickCount-EnemyTime2) div 1000;
  for i:=0 to UnitCount-1 do
   if Units[i]=nil then
    begin
      Units[i]:=TRoadUnit.Construct(TEnemyPhysic,TEnemyGraphic);
      inc(UnitCount);
      exit;
    end;
  i :=  UnitCount;
      Units[i]:=TRoadUnit.Construct(TEnemyPhysic,TEnemyGraphic);
      inc(UnitCount);
  if length(Units)<=UnitCount+20 then
    begin
      SetLength(Units,length(Units)+1000);
    end;

end;

{ TSceneOutro }

procedure TSceneOutro.DrawScene;
//var
//  Font : TGraphicFont;
begin
  inherited;
  Render.ClearBuffer;
  Render.ResetProjectionMatrix;
  Render.ResetModelViewMatrix;
  Font  :=  Render.CreateFont('Arial Black',24);
  glColor3f(0,1,0);
  glDisable(GL_LIGHTING);
  Font.DrawText2D(-0.2,0,'GAME OVER');
  Font.DrawText2D(-0.3,-0.2,'YOUR SCORE = '+inttostr(Score));
  Font.DrawText2D(-0.8,-0.8,'Press Left Mouse to Game');
  Font.Free;
  Render.SwapBuffers;
end;

procedure TSceneOutro.FreeScene;
begin
  inherited;
end;

procedure TSceneOutro.InitScene;
begin
  Score :=  (Scene as TSceneGame).Score;
  Sleep(500);
  inherited;
end;

procedure TSceneOutro.UpdateScene;
begin
  inherited;
  if Application.Mouse.LButton then
    begin
      TSceneIntro.Create;
      Exit;
    end;
  if Application.Keys[vk_escape]=1 then
   begin
    Application.SetUpdateProc(nil);
    Application.SetRenderProc(nil);
    DestroyWindow(Application.Window.Handle);
    FreeScene;
   end;
end;

end.
