#include "StdAfx.h"
#include "Ground.h"
//#include "Common\D3DUtil.h"
#include <math.h>

CGround::CGround(CDirect3D *d3d,CCamera *c):
 C3DObject(d3d->g_pd3dDevice), 
 tilesX(8),
 tilesY(10),
 tileSize(5),
 posZ(0),
 cubeCount(11)
{
 this->d3d = d3d;
 this->camera = c;

 D3DXCreateTextureFromFile( d3d->g_pd3dDevice, "asphalt.bmp", &g_pConcrete ); 
 if (!g_pConcrete) exit(-1);

 vertex_count = 4*(tilesX+2)*tilesY;
 faces_count = 2*(tilesX+2)*tilesY;
 
 device->CreateVertexBuffer(
 	vertex_count * sizeof(Vertex),
	D3DUSAGE_WRITEONLY,
	Vertex::FVF,
	D3DPOOL_MANAGED,
	&VB,
	0);
 device->CreateIndexBuffer(
	3*faces_count * sizeof(WORD),
	D3DUSAGE_WRITEONLY,
	D3DFMT_INDEX16,
	D3DPOOL_MANAGED,
	&IB,
	0);
 
 Vertex* vertices;
 VB->Lock(0, 0, (void**)&vertices, 0);
 for (int x=1; x<tilesX+1; x++)
  for (int y=0; y<tilesY; y++)
  {
	vertices[4*(y+tilesY*x)  ].position = D3DXVECTOR3(tileSize*(x-1)-tileSize*tilesY / 2.0,-3.5,tileSize*y+0.5);
	vertices[4*(y+tilesY*x)+1].position = D3DXVECTOR3(tileSize*(x-1)+5-tileSize*tilesY / 2.0,-3.5,tileSize*y+0.5);
	vertices[4*(y+tilesY*x)+2].position = D3DXVECTOR3(tileSize*(x-1)+5-tileSize*tilesY / 2.0,-3.5,tileSize*y+5+0.5);
	vertices[4*(y+tilesY*x)+3].position = D3DXVECTOR3(tileSize*(x-1)-tileSize*tilesY / 2.0,-3.5,tileSize*y+5+0.5);
	vertices[4*(y+tilesY*x)  ].normal   = D3DXVECTOR3(0,1,0);
	vertices[4*(y+tilesY*x)+1].normal   = D3DXVECTOR3(0,1,0);
	vertices[4*(y+tilesY*x)+2].normal   = D3DXVECTOR3(0,1,0);
	vertices[4*(y+tilesY*x)+3].normal   = D3DXVECTOR3(0,1,0);

	vertices[4*(y+tilesY*x)  ].u = 0;
	vertices[4*(y+tilesY*x)  ].v = 0;
	vertices[4*(y+tilesY*x)+1].u = 1.0;
	vertices[4*(y+tilesY*x)+1].v = 0.0;
	vertices[4*(y+tilesY*x)+2].u = 1.0;
	vertices[4*(y+tilesY*x)+2].v = 1.0;
	vertices[4*(y+tilesY*x)+3].u = 0.0;
	vertices[4*(y+tilesY*x)+3].v = 1.0;


	vertices[4*(y+tilesY*x)  ].color = D3DCOLOR_XRGB(255,255,255);
	vertices[4*(y+tilesY*x)+1].color = D3DCOLOR_XRGB(255,255,255);
	vertices[4*(y+tilesY*x)+2].color = D3DCOLOR_XRGB(255,255,255);
	vertices[4*(y+tilesY*x)+3].color = D3DCOLOR_XRGB(255,255,255);

    /*
	vertices[4*(y+tilesY*x)  ].position = D3DXVECTOR3(x,0,y);
	vertices[4*(y+tilesY*x)+1].position = D3DXVECTOR3(x+1,0,y);
	vertices[4*(y+tilesY*x)+2].position = D3DXVECTOR3(x+1,0,y+1);
	vertices[4*(y+tilesY*x)+3].position = D3DXVECTOR3(x,0,y+1);
	 */
  }

  for (int y=0; y<tilesY; y++)
  {
    int x = tilesX+1;

	vertices[4*(y+tilesY*x)  ].position = D3DXVECTOR3(tileSize*(x-1)-tileSize*tilesY / 2.0,-3.5,tileSize*y+0.5);
	vertices[4*(y+tilesY*x)+1].position = D3DXVECTOR3(tileSize*tileSize+5-tilesY,10,tileSize*y+0.5);
	vertices[4*(y+tilesY*x)+2].position = D3DXVECTOR3(tileSize*tileSize+5-tilesY,10,tileSize*y+5+0.5);
	vertices[4*(y+tilesY*x)+3].position = D3DXVECTOR3(tileSize*(x-1)-tileSize*tilesY / 2.0,-3.5,tileSize*y+5+0.5);
	vertices[4*(y+tilesY*x)  ].normal   = D3DXVECTOR3(0,1,0);
	vertices[4*(y+tilesY*x)+1].normal   = D3DXVECTOR3(0,1,0);
	vertices[4*(y+tilesY*x)+2].normal   = D3DXVECTOR3(0,1,0);
	vertices[4*(y+tilesY*x)+3].normal   = D3DXVECTOR3(0,1,0);

	vertices[4*(y+tilesY*x)  ].color = D3DCOLOR_XRGB(255,255,255);
	vertices[4*(y+tilesY*x)+1].color = D3DCOLOR_XRGB(255,255,255);
	vertices[4*(y+tilesY*x)+2].color = D3DCOLOR_XRGB(255,255,255);
	vertices[4*(y+tilesY*x)+3].color = D3DCOLOR_XRGB(255,255,255);

	vertices[4*(y+tilesY*x)  ].u = 0;
	vertices[4*(y+tilesY*x)  ].v = 0;
	vertices[4*(y+tilesY*x)+1].u = 1.0;
	vertices[4*(y+tilesY*x)+1].v = 0.0;
	vertices[4*(y+tilesY*x)+2].u = 1.0;
	vertices[4*(y+tilesY*x)+2].v = 1.0;
	vertices[4*(y+tilesY*x)+3].u = 0.0;
	vertices[4*(y+tilesY*x)+3].v = 1.0;
 }

  for (int y=0; y<tilesY; y++)
  {
    int x = 0;

	vertices[4*(y+tilesY*x)  ].position = D3DXVECTOR3(tileSize*x-tileSize*tilesY / 2.0,-3.5,tileSize*y+0.5);
	vertices[4*(y+tilesY*x)+1].position = D3DXVECTOR3(-tileSize*tileSize+5-tilesY,10,tileSize*y+0.5);
	vertices[4*(y+tilesY*x)+2].position = D3DXVECTOR3(-tileSize*tileSize+5-tilesY,10,tileSize*y+5+0.5);
	vertices[4*(y+tilesY*x)+3].position = D3DXVECTOR3(tileSize*x-tileSize*tilesY / 2.0,-3.5,tileSize*y+5+0.5);
	vertices[4*(y+tilesY*x)  ].normal   = D3DXVECTOR3(0,1,0);
	vertices[4*(y+tilesY*x)+1].normal   = D3DXVECTOR3(0,1,0);
	vertices[4*(y+tilesY*x)+2].normal   = D3DXVECTOR3(0,1,0);
	vertices[4*(y+tilesY*x)+3].normal   = D3DXVECTOR3(0,1,0);

	vertices[4*(y+tilesY*x)  ].color = D3DCOLOR_XRGB(255,255,255);
	vertices[4*(y+tilesY*x)+1].color = D3DCOLOR_XRGB(255,255,255);
	vertices[4*(y+tilesY*x)+2].color = D3DCOLOR_XRGB(255,255,255);
	vertices[4*(y+tilesY*x)+3].color = D3DCOLOR_XRGB(255,255,255);

	vertices[4*(y+tilesY*x)  ].u = 0;
	vertices[4*(y+tilesY*x)  ].v = 0;
	vertices[4*(y+tilesY*x)+1].u = 1.0;
	vertices[4*(y+tilesY*x)+1].v = 0.0;
	vertices[4*(y+tilesY*x)+2].u = 1.0;
	vertices[4*(y+tilesY*x)+2].v = 1.0;
	vertices[4*(y+tilesY*x)+3].u = 0.0;
	vertices[4*(y+tilesY*x)+3].v = 1.0;

 }

 VB->Unlock();

 maxY = tileSize*tilesY;
 diff = 0;
 // define the triangles of the cube:
 WORD* indices = 0;
 IB->Lock(0, 0, (void**)&indices, 0);
 for (int x=0; x<tilesX+2; x++)
  for (int y=0; y<tilesY; y++)
  {
	indices[6*(y+tilesY*x)]   = 4*(y+tilesY*x);
	indices[6*(y+tilesY*x)+1] = 4*(y+tilesY*x)+1;
	indices[6*(y+tilesY*x)+2] = 4*(y+tilesY*x)+2;

	indices[6*(y+tilesY*x)+3] = 4*(y+tilesY*x);
	indices[6*(y+tilesY*x)+4] = 4*(y+tilesY*x)+2;
	indices[6*(y+tilesY*x)+5] = 4*(y+tilesY*x)+3;
  } 
 IB->Unlock();

 cubes = (CCube **)malloc(sizeof(CCube *)*cubeCount);
 cubePosition = new CubePos[cubeCount];
 
 for (int i=0; i<cubeCount; i++){
	 cubes[i] = new CCube(d3d, tileSize);
	 cubePosition[i].tileX = 1+(tilesX - 2)*((float)rand() / RAND_MAX);
	 cubePosition[i].tileY = tilesY - 2;
	 cubes[i]->MoveToTile(cubePosition[i].tileX,cubePosition[i].tileY,0); 
 }
 
 skyDome = new SkyDome(d3d,c);
 skyDome->Rotate (-D3DX_PI / 2, 0 , 0);
 skyDome->Scale(700,700,700);
 skyDome->Translate (0,-400.0f,0.0f);
}

CGround::~CGround(void)
{
  SAFE_DELETE(cubes);
  SAFE_DELETE(cubePosition);
}

void CGround::Translate(float x, float y, float z)
{
 C3DObject::Translate (x,y,z);
 
 for (int i=0; i<cubeCount; i++)
	 cubes[i]->Translate (x,y,z);

 //skyDome->Translate (x,y,z);

 posZ += z;
}

void CGround::MoveGround(CCamera *c)
{	
 Vertex* vertices;
 VB->Lock(0, 0, (void**)&vertices, 0); 
 float zPosition =  c->GetPosition().z ; 
 
 for (int y=0; y<tilesY; y++) 
  if (vertices[4*(y+tilesY*0)+2].position.z+tileSize < zPosition)
  {  
   diff++;
   for (int x=0; x<tilesX+2; x++)
   {
 	vertices[4*(y+tilesY*x)  ].position.z += maxY;
	vertices[4*(y+tilesY*x)+1].position.z += maxY;
	vertices[4*(y+tilesY*x)+2].position.z += maxY;
	vertices[4*(y+tilesY*x)+3].position.z += maxY;	
   }
  } 
 VB->Unlock();

 for (int i=0; i<cubeCount; i++)
 if (cubes[i]->getBack().z < zPosition)
 {
    cubePosition[i].tileY = tilesY-2; cubePosition[i].tileX = -3+(tilesX+2)*((float)rand() / RAND_MAX);
    cubes[i]->MoveToTile(cubePosition[i].tileX,cubePosition[i].tileY,0);
 }
 
}

float CGround::GetDifference()
{
	return diff*tileSize;
}

void CGround::ZeroDifference()
{
	diff = 0;
}

void CGround::Render()
{ 
 if( d3d->g_pd3dDevice)
 {
   d3d->g_pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
   
   d3d->g_pd3dDevice->SetTexture( 0, g_pConcrete );
   d3d->g_pd3dDevice->SetStreamSource(0, VB, 0, sizeof(Vertex));
   d3d->g_pd3dDevice->SetIndices(IB);
   d3d->g_pd3dDevice->SetFVF(Vertex::FVF);
   d3d->g_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,0, 0, vertex_count, 0, faces_count);
   d3d->g_pd3dDevice->SetTexture(0, NULL);

   for (int i=0; i<cubeCount; i++)
	   cubes[i]->Render();
   skyDome->Render();
 }
}

bool CGround::ColisionDetection(C3DObject *obj)
{
	//optimize 
	//линейные ограничения по бокам
    float ax1 = tileSize*tilesX-tileSize*tilesY / 2.0;
	float ax2 = tileSize*tileSize+5-2.5-tilesY;
	float ay1 = -3.5;
	float ay2 = 10;

    float bx1 = -tileSize*tilesY / 2.0;
	float bx2 = -tileSize*tileSize+5+2.5-tilesY;
	float by1 = -3.5;
	float by2 = 10;
   
	Vertex* vertices;
    obj->VB->Lock(0, 0, (void**)&vertices, 0);

	//проверка столкновения с кубами
	for (int i=0; i<cubeCount; i++){
		 D3DXVECTOR3 front = cubes[i]->getFront ();
		 D3DXVECTOR3 back  = cubes[i]->getBack  ();

		 for (int j = 0; j< obj->vertex_count; j++)
		 {
			 if (vertices[j].position.y <  -3.5)
				 return TRUE;

			 if (front.z < vertices[j].position.z &&
				 back.z > vertices[j].position.z)
			 {
				 if (front.x < vertices[j].position.x &&
					 back.x  > vertices[j].position.x &&
					 front.y < vertices[j].position.y &&
					 back.y  > vertices[j].position.y)
				 {
					 return TRUE;
				 }
			 }
		 }
	}	 

	//проверка линейных ограничений по бокам
	for (int j = 0; j< obj->vertex_count; j++)
    {
	 float da = (vertices[j].position.x - ax1) / (ax2-ax1) - (vertices[j].position.y - ay1) / (ay2-ay1);
	 float db = (vertices[j].position.x - bx1) / (bx2-bx1) - (vertices[j].position.y - by1) / (by2-by1);
     if (da*db < 0) return true;
	}
	obj->VB->Unlock();

	return FALSE;
}

bool CGround::LaserShot(CLaser *obj)
{
	//optimize 
	//линейные ограничения по бокам
    float ax1 = tileSize*tilesX-tileSize*tilesY / 2.0;
	float ax2 = tileSize*tileSize+5-2.5-tilesY;
	float ay1 = -3.5;
	float ay2 = 10;

    float bx1 = -tileSize*tilesY / 2.0;
	float bx2 = -tileSize*tileSize+5+2.5-tilesY;
	float by1 = -3.5;
	float by2 = 10;

    
	Vertex* vertices;
    obj->VB->Lock(0, 0, (void**)&vertices, 0);

	//проверка столкновения с кубами
	for (int i=0; i<cubeCount; i++){
		 D3DXVECTOR3 front = cubes[i]->getFront ();
		 D3DXVECTOR3 back  = cubes[i]->getBack  ();

		 for (int j = 0; j< obj->vertex_count; j++)
		 {
			 if (vertices[j].position.y <  -3.5)
				 return TRUE;

			 if (front.z < vertices[j].position.z &&
				 back.z > vertices[j].position.z)
			 {
				 if (front.x < vertices[j].position.x &&
					 back.x  > vertices[j].position.x &&
					 front.y < vertices[j].position.y &&
					 back.y  > vertices[j].position.y)
				 {
                     cubePosition[i].tileY = tilesY-1; 
					 cubePosition[i].tileX = -3+(tilesX+2)*((float)rand() / RAND_MAX);
                     cubes[i]->MoveToTile(cubePosition[i].tileX,cubePosition[i].tileY,0);					 
					 return TRUE;
				 }
			 }
		 }
	}	 

	//проверка линейных ограничений по бокам
	for (int j = 0; j< obj->vertex_count; j++)
    {
	 float da = (vertices[j].position.x - ax1) / (ax2-ax1) - (vertices[j].position.y - ay1) / (ay2-ay1);
	 float db = (vertices[j].position.x - bx1) / (bx2-bx1) - (vertices[j].position.y - by1) / (by2-by1);
     if (da*db < 0) return true;
	}
	obj->VB->Unlock();

	return FALSE;
}

SkyDome::SkyDome(CDirect3D *d3d, CCamera *c):
  C3DObject(d3d->g_pd3dDevice)
{
	 this->d3d = d3d;
	 camera = c;

	 D3DXCreateTextureFromFile( d3d->g_pd3dDevice, "Env_Sky.jpg", &g_pSky ); 
	 if (!g_pSky) exit(-1);

	 //Расчет и генерация полусферы
	 //22 сентябрь 2006

	 //Параметры
	 // h - кол-во делений высоты
	 // n - кол-во делений каждого круга
	 
	 int h = 15, n = 20;

	 vertex_count = h*n + 1;
	 faces_count  = 2*n*(h-1)+n;
	 
	 device->CreateVertexBuffer(
 		vertex_count * sizeof(Vertex),
		D3DUSAGE_WRITEONLY,
		Vertex::FVF,
		D3DPOOL_MANAGED,
		&VB,
		0);
	 device->CreateIndexBuffer(
		3*faces_count * sizeof(WORD),
		D3DUSAGE_WRITEONLY,
		D3DFMT_INDEX16,
		D3DPOOL_MANAGED,
		&IB,
		0);
	 
	 Vertex* vertices;
	 VB->Lock(0, 0, (void**)&vertices, 0);
	  
	  float x,y,z,r;  
	  for (int k=0; k<h; k++)
	  {
		  z = (float) k / h;
		  r = sqrt(1 - z*z);
		  for (int j=0; j<n; j++)
		  {
			  float fi = 2 * j * D3DX_PI / n;
			  x = (float)r*cos(fi);
			  y = (float)r*sin(fi);

			  vertices[j+k*n].position = D3DXVECTOR3(x,y,z);
			  vertices[j+k*n].normal   = D3DXVECTOR3(x,y,z);
			  vertices[j+k*n].color    = D3DCOLOR_XRGB(255,255,255);
			  vertices[j+k*n].u        = (float)j / (n-1);
			  vertices[j+k*n].v        = r;

		  }
	  }
			  vertices[h*n].position = D3DXVECTOR3(0,0,1);
			  vertices[h*n].normal   = D3DXVECTOR3(0,0,1);
			  vertices[h*n].color    = D3DCOLOR_XRGB(255,255,255);
			  vertices[h*n].u        = 0.5;
			  vertices[h*n].v        = 1;

     VB->Unlock();
	 
	 // define the triangles of the cube:
	 WORD* indices = 0;
	 IB->Lock(0, 0, (void**)&indices, 0);
	 int index = 0;
	  for (int k=0; k<h-1; k++)
	  {
		  for (int j=0; j<n; j++)
		  {	  
			  indices[index  ] = j+k*n;
			  indices[index+1] = j+k*n+1;
			  if (j == n-1) indices[index+1] = k*n;
		      indices[index+2] = j+(k+1)*n+1;
			  if (j == n-1) indices[index+2] = (k+1)*n;
		      
			  indices[index+3] = j+(k+1)*n;
			  indices[index+4] = j+(k+1)*n+1;
			  if (j == n-1) indices[index+4] = (k+1)*n;
			  indices[index+5] = j+k*n;

			  index += 6;
		  }
	  }

     for (int j=0; j<n; j++)
	 {
		 indices[index  ] = j+(h-1)*n;
		 indices[index+1] = h*n;
		 indices[index+2] = j+(h-1)*n+1;
		 if (j == n-1) indices[index+2] = (h-1)*n;
		 
		 index += 3;
	 }

	 IB->Unlock();

}

void SkyDome::Render()
{
if( d3d->g_pd3dDevice)
 {
   d3d->g_pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
   d3d->g_pd3dDevice->SetTexture( 0, g_pSky );
   
   d3d->g_pd3dDevice->SetStreamSource(0, VB, 0, sizeof(Vertex));
   d3d->g_pd3dDevice->SetIndices(IB);
   d3d->g_pd3dDevice->SetFVF(Vertex::FVF);
   d3d->g_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,0, 0, vertex_count, 0, faces_count);

   d3d->g_pd3dDevice->SetTexture(0, NULL);
 }

}
