//---------------------------------------------------------------------------

#include <vcl.h>
#include <Keyboard.hpp>
#include <stdlib.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "GLLensFlare"
#pragma link "VectorGeometry"
#pragma link "GLSMBASS"
#pragma link "GLSound"
#pragma link "GLWin32Viewer"
#pragma link "GLSkydome"
#pragma link "GLBitmapFont"
#pragma link "GLHUDObjects"
#pragma link "GLTexture"
#pragma link "GLCadencer"
#pragma link "GLHeightData"
#pragma link "jpeg"
#pragma link "GLMisc"
#pragma link "GLObjects"
#pragma link "GLTerrainRenderer"
#pragma link "GLScene"
#pragma link "Keyboard"
#pragma resource "*.dfm"
TForm1 *Form1;

float random(void)
{
  return (float)(rand() & 0x1FFF) / (float)0x1FFF;
}

//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent * Owner):TForm(Owner)
{
  SetCurrentDir(ExtractFilePath(Application->ExeName) + "..\\..\\media");
  // 8 MB height data cache
  // Note this is the data size in terms of elevation samples, it does not
  // take into account all the data required/allocated by the renderer
  GLBitmapHDS1->MaxPoolSize = 8 * 1024 * 1024;
  // specify height map data
  GLBitmapHDS1->Picture->LoadFromFile("terrain.bmp");
  // load the texture maps
  GLMaterialLibrary1->Materials->Items[0]->Material->Texture->Image->
    LoadFromFile("snow512.jpg");
  GLMaterialLibrary1->Materials->Items[1]->Material->Texture->Image->
    LoadFromFile("detailmap.jpg");
  SPMoon->Material->Texture->Image->LoadFromFile("moon.bmp");
  SPSun->Material->Texture->Image->LoadFromFile("flare1.bmp");
  // apply texture map scale (our heightmap size is 256)
  TerrainRenderer1->TilesPerTexture = 256.0 / TerrainRenderer1->TileSize;
  // load Bitmap Font
  BitmapFont1->Glyphs->LoadFromFile("darkgold_font.bmp");
  // load and setup sound samples
  GLSoundLibrary->Samples->Add()->LoadFromFile("ChillyWind.mp3");
  GLSoundLibrary->Samples->Add()->LoadFromFile("howl.mp3");
  // Could've been done at design time, but then it hurts the eyes ;)
  GLSceneViewer1->Buffer->BackgroundColor = clWhite;
  // Move camera starting point to an interesting hand-picked location
  DummyCube1->Position->X = 570;
  DummyCube1->Position->Z = -385;
  DummyCube1->Turn(90);
  // Initial camera height offset (controled with pageUp/pageDown)
  FCamHeight = 10;

  randomize();
}

//---------------------------------------------------------------------------

void __fastcall TForm1::GLCadencer1Progress(TObject * Sender,
                                            const double deltaTime,
                                            const double newTime)
{
  float speed;

  // handle keypresses
  if(IsKeyDown(VK_SHIFT))
    speed = 5 * deltaTime;
  else
    speed = deltaTime;
  TGLCoordinates *c = GLCamera1->Position;
  if(IsKeyDown(VK_UP))
    DummyCube1->Translate(c->Z * speed, 0, -c->X * speed);
  if(IsKeyDown(VK_DOWN))
    DummyCube1->Translate(-c->Z * speed, 0, c->X * speed);
  if(IsKeyDown(VK_LEFT))
    DummyCube1->Translate(-c->X * speed, 0, -c->Z * speed);
  if(IsKeyDown(VK_RIGHT))
    DummyCube1->Translate(c->X * speed, 0, c->Z * speed);
  if(IsKeyDown(VK_PRIOR))
    FCamHeight = FCamHeight + 10 * speed;
  if(IsKeyDown(VK_NEXT))
    FCamHeight = FCamHeight - 10 * speed;
  if(IsKeyDown(VK_ESCAPE))
    Close();

  // don't drop through terrain!
  DummyCube1->Position->Y =
    TerrainRenderer1->InterpolatedHeight(DummyCube1->Position->AsVector) +
    FCamHeight;
}

//---------------------------------------------------------------------------

void __fastcall TForm1::GLSceneViewer1MouseDown(TObject * Sender,
                                                TMouseButton Button,
                                                TShiftState Shift, int X, int Y)
{
  my = Y;
  mx = X;
}

//---------------------------------------------------------------------------

void __fastcall TForm1::GLSceneViewer1MouseMove(TObject * Sender,
                                                TShiftState Shift, int X, int Y)
{
  if(Shift.Contains(ssLeft))
  {
    GLCamera1->MoveAroundTarget((my - Y) * 0.5, (mx - X) * 0.5);
    mx = X;
    my = Y;
  }
}

//---------------------------------------------------------------------------

void __fastcall TForm1::Timer1Timer(TObject * Sender)
{
  String s;
  s.printf("%.1f FPS - %d", GLSceneViewer1->FramesPerSecond(),
           TerrainRenderer1->LastTriangleCount);
  HUDText1->Text = s;
  GLSceneViewer1->ResetPerformanceMonitor();
}

//---------------------------------------------------------------------------

void __fastcall TForm1::FormKeyPress(TObject * Sender, char &Key)
{
  TGLFaceProperties *fp;
  TGLFogEnvironment *fe;
  switch (Key)
  {
  case 'w':
  case 'W':
    fp = GLMaterialLibrary1->Materials->Items[0]->Material->FrontProperties;
    if(fp->PolygonMode == pmLines)
      fp->PolygonMode = pmFill;
    else
      fp->PolygonMode = pmLines;
    break;
  case '+':
    if(GLCamera1->DepthOfView < 2000)
    {
      GLCamera1->DepthOfView = GLCamera1->DepthOfView * 1.2;
      fe = GLSceneViewer1->Buffer->FogEnvironment;
      fe->FogEnd = fe->FogEnd * 1.2;
      fe->FogStart = fe->FogStart * 1.2;
    }
    break;
  case '-':
    if(GLCamera1->DepthOfView > 300)
    {
      GLCamera1->DepthOfView = GLCamera1->DepthOfView / 1.2;
      fe = GLSceneViewer1->Buffer->FogEnvironment;
      fe->FogEnd = fe->FogEnd / 1.2;
      fe->FogStart = fe->FogStart / 1.2;
    }
    break;
  case '*':
    if(TerrainRenderer1->CLODPrecision > 20)
      TerrainRenderer1->CLODPrecision =
        Round(TerrainRenderer1->CLODPrecision * 0.8);
    break;
  case '/':
    if(TerrainRenderer1->CLODPrecision < 1000)
      TerrainRenderer1->CLODPrecision =
        Round(TerrainRenderer1->CLODPrecision * 1.2);
    break;
  case '8':
    if(TerrainRenderer1->QualityDistance > 40)
      TerrainRenderer1->QualityDistance =
        Round(TerrainRenderer1->QualityDistance * 0.8);
    break;
  case '9':
    if(TerrainRenderer1->QualityDistance < 1000)
      TerrainRenderer1->QualityDistance =
        Round(TerrainRenderer1->QualityDistance * 1.2);
    break;
  case 'n':
  case 'N':
    if(SkyDome1->Stars->Count == 0)
    {
      // turn on 'night' mode
      SkyDome1->Bands->Items[1]->StopColor->AsWinColor =
        (Graphics::TColor) RGB(0, 0, 16);
      SkyDome1->Bands->Items[1]->StartColor->AsWinColor =
        (Graphics::TColor) RGB(0, 0, 8);
      SkyDome1->Bands->Items[0]->StopColor->AsWinColor =
        (Graphics::TColor) RGB(0, 0, 8);
      SkyDome1->Bands->Items[0]->StartColor->AsWinColor =
        (Graphics::TColor) RGB(0, 0, 0);

      SkyDome1->Stars->AddRandomStars(700, clWhite, True);      // many white stars
      SkyDome1->Stars->AddRandomStars(100, (Graphics::TColor) RGB(255, 200, 200), True);        // some redish ones
      SkyDome1->Stars->AddRandomStars(100, (Graphics::TColor) RGB(200, 200, 255), True);        // some blueish ones
      SkyDome1->Stars->AddRandomStars(100, (Graphics::TColor) RGB(255, 255, 200), True);        // some yellowish ones

      GLSceneViewer1->Buffer->BackgroundColor = Graphics::clBlack;
      fe = GLSceneViewer1->Buffer->FogEnvironment;
      fe->FogColor->AsWinColor = Graphics::clBlack;
      fe->FogStart = -fe->FogStart;     // Fog is used to make things darker

      SPMoon->Visible = True;
      SPSun->Visible = False;
      GLLensFlare->Visible = False;
    }
    break;
  case 'd':
  case 'D':
    if(SkyDome1->Stars->Count > 0)
    {
      // turn on 'day' mode
      SkyDome1->Bands->Items[1]->StopColor->Color = clrNavy;
      SkyDome1->Bands->Items[1]->StartColor->Color = clrBlue;
      SkyDome1->Bands->Items[0]->StopColor->Color = clrBlue;
      SkyDome1->Bands->Items[0]->StartColor->Color = clrWhite;
      SkyDome1->Stars->Clear();
      GLSceneViewer1->Buffer->BackgroundColor = clWhite;
      fe = GLSceneViewer1->Buffer->FogEnvironment;
      fe->FogColor->AsWinColor = clWhite;
      fe->FogStart = -fe->FogStart;

      GLSceneViewer1->Buffer->FogEnvironment->FogStart = 0;
      SPMoon->Visible = False;
      SPSun->Visible = True;
    }
    break;
  case 't':
    if(SkyDome1->Options.Contains(sdoTwinkle))
      SkyDome1->Options = SkyDome1->Options << sdoTwinkle;
    else
      SkyDome1->Options = SkyDome1->Options >> sdoTwinkle;
    break;
  case 'l':
    GLLensFlare->Visible = (!GLLensFlare->Visible) && SPSun->Visible;
  }
  Key = '\0';
}

//---------------------------------------------------------------------------

void __fastcall TForm1::TISoundTimer(TObject * Sender)
{
  TVector wolfPos;
  float c, s;
  TGLBSoundEmitter *be;

  if(!GLSMBASS1->Active)
    return;
  if(SkyDome1->Stars->Count == 0)
  {
    // wind blows around camera
    be = GetOrCreateSoundEmitter(GLCamera1);
    be->Source->SoundLibrary = GLSoundLibrary;
    be->Source->SoundName = GLSoundLibrary->Samples->Items[0]->Name;
    be->Source->Volume = random() * 0.5 + 0.5;
    be->Playing = True;
  }
  else
  {
    // wolf howl at some distance, at ground level
    wolfPos = GLCamera1->AbsolutePosition;
    SinCos(random() * c2PI, 100 + random(1000), s, c);
    wolfPos.Coord[0] = wolfPos.Coord[0] + c;
    wolfPos.Coord[2] = wolfPos.Coord[2] + s;
    wolfPos.Coord[1] = TerrainRenderer1->InterpolatedHeight(wolfPos);
    DCSound->Position->AsVector = wolfPos;
    be = GetOrCreateSoundEmitter(DCSound);
    be->Source->SoundLibrary = GLSoundLibrary;
    be->Source->SoundName = GLSoundLibrary->Samples->Items[1]->Name;
    be->Source->MinDistance = 100;
    be->Source->MaxDistance = 4000;
    be->Playing = True;
  }
  TISound->Enabled = False;
  TISound->Interval = 10000 + random(10000);
  TISound->Enabled = True;
}

//---------------------------------------------------------------------------

