#include "Terrain.h"
#include "ShadowApp.h"
#include "ShadowScene.h"
#include "..\Utilities\util.h"

TerrainPatch::TerrainPatch(Terrain* const terrain, int bx, int by) : SceneObject(terrain->GetScene())
{
	m_Terrain = terrain;
	m_BX = bx;
	m_BY = by;
	const int ind = m_BX + m_BY * m_Terrain->m_PatchTile;
	m_MinH = FLT_MAX;
	m_MaxH = -FLT_MAX;
	//m_MinH = m_Terrain->m_PatchMin[ind];
	//m_MaxH = m_Terrain->m_PatchMax[ind];
	const float bs = (m_Terrain->m_PatchStride-1) * m_Terrain->m_TileScale;
	
	m_VB = NULL;
	m_VB = m_Terrain->GetScene()->GetShadowApp()->GetDevice()->GetBufferManager()->CreateVB(m_Terrain->m_PatchHeightSamples * (sizeof(STPatchVertex)), 0, D3DUSAGE_WRITEONLY, POOL_MANAGED);

	InitVB();

	BuildRenderJobs();
}

TerrainPatch::~TerrainPatch(void)
{
	SAFERELEASE(m_VB);
}

void TerrainPatch::AddToRenderList(RenderList& rl)
{ 
	if (m_Terrain->GetScene()->GetShadowApp()->UseDeferred()) 
		rl.AddRJ(&m_RJDS); 
	else 
		rl.AddRJ(&m_RJ);
}

void TerrainPatch::InitVB(void)
{
	STPatchVertex* vb;

	unsigned xoff = m_BX * (m_Terrain->GetPatchStride()-1);
	unsigned yoff = m_BY * (m_Terrain->GetPatchStride()-1);

	m_VB->GetBuffer()->Lock(0, 0, (void**)&vb, 0);

	m_MinH = FLT_MAX;
	m_MaxH = -FLT_MAX;

	for(unsigned y = 0; y < m_Terrain->GetPatchStride(); y++)
		for(unsigned x = 0; x < m_Terrain->GetPatchStride(); x++)
		{
			unsigned hind = x + xoff + (y + yoff) * (m_Terrain->m_HMSize+1);
			
			vb->x = (x + xoff) * m_Terrain->GetTileScale();
			vb->y = (y + yoff) * m_Terrain->GetTileScale();
			float h = m_Terrain->m_HeightField[hind];
			vb->height = h;
			DXVector3 n = m_Terrain->CalcNormal(x + xoff, y + yoff);
			vb->nx = n.x;
			vb->ny = n.y;
			//vb->n = n;
			//vb->color = HeightToColor(m_HeightField[hind]);

			if (h < m_MinH)
				m_MinH = h;
			if (h > m_MaxH)
				m_MaxH = h;

			vb++;
		}

	DXVector3 vmin(m_BX * (m_Terrain->GetPatchStride()-1) * m_Terrain->GetTileScale(), m_BY * (m_Terrain->GetPatchStride()-1) * m_Terrain->GetTileScale(), m_MinH);
	DXVector3 vmax((m_BX + 1) * (m_Terrain->GetPatchStride()-1) * m_Terrain->GetTileScale(), (m_BY + 1) * (m_Terrain->GetPatchStride()-1) * m_Terrain->GetTileScale(), m_MaxH); //+zmaxoff

	m_AABB.SetVolume(vmin, vmax);
	m_Bound.Center = m_AABB.GetCenter();
	m_Bound.Radius = m_AABB.GetE().Length();

	m_VB->GetBuffer()->Unlock();
}

void TerrainPatch::BuildRenderJobs()
{
	float id = frand();
	m_SMID.SetValue("SM_ID", &id, sizeof(float));

	m_DC.BaseVertexIndex = 0;
	m_DC.IB = m_Terrain->m_IB ? m_Terrain->m_IB->GetBuffer() : NULL;
	m_DC.MinIndex = 0;
	m_DC.NumVertices = m_Terrain->m_PatchHeightSamples;
	m_DC.PrimitiveCount = m_Terrain->m_PatchPrimitives;
	m_DC.PrimitiveType = PT_TRIANGLELIST;
	m_DC.StartIndex = 0;
	m_DC.VB = m_VB ? m_VB->GetBuffer() : NULL;
	m_DC.VDecl = m_Terrain->m_VDecl;
	m_DC.VertexStride = sizeof(STPatchVertex);

	m_RJ.DrawCall = &m_DC;
	m_RJ.Effect = m_Terrain->m_FXTerrain;
	//m_RJ.Technique = "RenderCommon";
	m_RJ.AddParameter(m_Terrain->GetScene()->GetShadowApp()->GetShadowMapping()->GetParamSMMatrix());
	m_RJ.AddParameter(m_Terrain->GetScene()->GetShadowApp()->GetShadowMapping()->GetParamSMSize());
	m_RJ.AddTexture(m_Terrain->GetScene()->GetShadowApp()->GetShadowMapping()->GetTexParamSM());
	m_RJ.AddTexture(m_Terrain->GetScene()->GetShadowApp()->GetShadowMapping()->GetTexParamID());
	m_RJ.AddParameter(&m_SMID);
	m_RJ.UserData = NULL;
	
	m_RJDS.DrawCall = &m_DC;
	m_RJDS.Effect = m_Terrain->m_FXTerrain;
	m_RJDS.AddParameter(&m_SMID);
	//m_RJDS.Technique = "RenderDS";
	m_RJDS.UserData = NULL;
	
	m_RJShadow.DrawCall = &m_DC;
	m_RJShadow.Effect = m_Terrain->m_FXTerrain;
	//m_RJShadow.Technique = "RenderShadowDepth";
	m_RJShadow.AddParameter(m_Terrain->GetScene()->GetShadowApp()->GetShadowMapping()->GetParamSMMatrix());
	m_RJShadow.AddParameter(&m_SMID);
	m_RJShadow.UserData = &m_Bound;
	
	UpdateTechnique();
}

void TerrainPatch::UpdateTechnique(void)
{
	if (m_Terrain->GetScene()->GetShadowApp()->GetSMFiltering())
		m_RJ.Technique = "RenderCommon_Filter";
	else
		m_RJ.Technique = m_Terrain->GetScene()->GetShadowApp()->GetUseIDBuffer() ? "RenderCommon_ID" : "RenderCommon";

	if (m_Terrain->GetScene()->GetShadowApp()->GetWorldPosType() == WPT_DEPTH)
	{
		m_RJDS.Technique = m_Terrain->GetScene()->GetShadowApp()->GetUseIDBuffer() ? "RenderDS_Depth_ID" : "RenderDS_Depth";
	}
	else if (m_Terrain->GetScene()->GetShadowApp()->GetWorldPosType() == WPT_LINEARDEPTH)
	{
		m_RJDS.Technique = m_Terrain->GetScene()->GetShadowApp()->GetUseIDBuffer() ? "RenderDS_LinearDepth_ID" : "RenderDS_LinearDepth";
	}
	else if (m_Terrain->GetScene()->GetShadowApp()->GetWorldPosType() == WPT_WORLDPOS)
	{
		m_RJDS.Technique = m_Terrain->GetScene()->GetShadowApp()->GetUseIDBuffer() ? "RenderDS_World_ID" : "RenderDS_World";
	}

	if (m_pScene->GetShadowApp()->GetUseIDBuffer())
	{
		if (m_pScene->GetShadowApp()->GetUsePrimID() && m_pScene->GetShadowApp()->GetShadowMethod() != SM_COMMON)
		{
			m_RJShadow.Technique = "RenderShadowDepth_PrimID";
		}
		else
		{
			m_RJShadow.Technique = "RenderShadowDepth_ID";
		}
	}
	else
	{
		m_RJShadow.Technique = "RenderShadowDepth";
	}
}

/*
void TerrainPatch::Update(const float dt)
{
	m_bVisible = false;

	ViewFrustum viewFrustum(*m_Terrain->m_App->GetCam());
	//done by terrain
//	m_Terrain->m_App->ExpandSceneBound(m_Bound);

	//D3DXPLANE p;
	//D3DXPlaneFromPointNormal(&p, (D3DXVECTOR3*)&m_Terrain->m_App->GetCam()->GetPosition(), (D3DXVECTOR3*)&m_Terrain->m_App->GetCam()->GetViewRightVector());
	//if(!m_Bound.IsCulled(p))

	if(m_Terrain->m_QT->GetLeaf(m_Terrain->m_QT->GetLevels()-1, m_BX, m_BY)->visible != QTVT_NONE)

	//for(unsigned i=0; i < m_Terrain->m_App->GetNumAntiLightPlanes(); i++)
	//{
	//	if(m_Bound.IsCulled(m_Terrain->m_App->GetAntiLightPlanes()[i]))
	//		return;
	//}
	//for(unsigned i=0; i < 6; i++)
	//{
	//	if(m_Bound.IsCulled(viewFrustum.ClipPlanes[i]))
	//		return;
	//}

	//if(Intr_AABB_OBB(m_Bound, m_Terrain->m_App->GetShadowFrustrum()))
	{
		m_bVisible = true;

		if(m_Terrain->m_App->UseDeferred())
			m_Terrain->m_App->GetRenderList()->AddRJ(&m_RJDS);
		else
			m_Terrain->m_App->GetRenderList()->AddRJ(&m_RJ);

		m_Terrain->m_App->ExpandVisibleBound(m_Bound);
	}
	else
	{
		if (m_Terrain->m_App->GetUseDebugCam())
		{
			for(unsigned i=0; i < m_Terrain->m_App->GetNumAntiLightPlanes(); i++)
			{
				if(m_Bound.IsCulled(m_Terrain->m_App->GetAntiLightPlanes()[i]))
					return;
			}

			if(m_Terrain->m_App->UseDeferred())
				m_Terrain->m_App->GetRenderList()->AddRJ(&m_RJDS);
			else
				m_Terrain->m_App->GetRenderList()->AddRJ(&m_RJ);
		}
	}
}

void TerrainPatch::UpdateShadow()
{
	//visible objects and objects in shadow frustrum can cast shadows, so add the to the shadow renderlist
	if(m_bVisible)
	{
		m_Terrain->m_App->GetShadowRenderList()->AddRJ(&m_RJShadow);
	}
	else
	{
		D3DXPLANE* pPlanes = m_Terrain->m_App->GetAntiLightPlanes();
		for(unsigned i=0; i < m_Terrain->m_App->GetNumAntiLightPlanes(); i++)
		{
			if(m_Bound.IsCulled(pPlanes[i]))
				return;
		}
		m_Terrain->m_App->GetShadowRenderList()->AddRJ(&m_RJShadow);
	}
}*/

void TerrainPatch::OnRestoreIB(void)
{
	m_DC.IB = m_Terrain->m_IB ? m_Terrain->m_IB->GetBuffer() : NULL;
}

Terrain::Terrain(ShadowScene* const pScene, const unsigned tileshift, const float heightscale, const float tilescale, const XString& hmfile, const int hmsize) : SceneObject(pScene)
{
	m_TileShift = tileshift;
	m_HeightScale = heightscale;
	m_TileScale = tilescale;
	m_HMSize = hmsize;
	m_HMFile = hmfile;

//	m_QT = new Quadtree(1<<tileshift, 1<<tileshift);
//	m_QTShadow = new Quadtree(1<<tileshift, 1<<tileshift);

	m_PatchTile = (1<<tileshift);
	m_PatchCount = m_PatchTile * m_PatchTile;
	//m_PatchMin = new float[m_PatchCount];
	//m_PatchMax = new float[m_PatchCount];

	m_PatchTiles = (m_HMSize >> tileshift) * (m_HMSize >> tileshift);
	m_PatchStride = (m_HMSize >> tileshift) + 1;
	m_PatchPrimitives = m_PatchTiles * 2;
	m_PatchHeightSamples = m_PatchStride * m_PatchStride;

	unsigned heightsamples = (m_HMSize >> tileshift) + 1;

	D3DVERTEXELEMENT9 declTerrain[] =
    {
        /*{ 0, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },  
		{ 1, 0, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 }, 
		{ 1, 4, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0 }, 
		{ 1, 16, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0 }, */

		{ 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },  
		{ 0, 12, D3DDECLTYPE_FLOAT16_2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0 },
		//{ 0, 16, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0 },
        D3DDECL_END()
    };
	m_VDecl = new VertexDeclaration(m_pScene->GetShadowApp()->GetDevice(), declTerrain);

	m_FXTerrain = m_pScene->GetShadowApp()->GetDevice()->GetShaderManager()->CreateFX("Shaders\\Terrain.fx");
	
	m_HeightSamples = (m_HMSize+1)*(m_HMSize+1);
	m_HeightField = new float[m_HeightSamples];

	m_IB = m_pScene->GetShadowApp()->GetDevice()->GetBufferManager()->CreateIB(m_PatchPrimitives * sizeof(DWORD) * 3, D3DUSAGE_WRITEONLY, false, POOL_DEFAULT);
//	m_VB = app->GetDevice()->GetBufferManager()->CreateVB(m_HeightSamples * sizeof(STPatchVertex), D3DUSAGE_WRITEONLY, POOL_DEFAULT);

	//m_VBXY = app->GetDevice()->GetBufferManager()->CreateVB(m_PatchHeightSamples * sizeof(DXVector2), D3DUSAGE_WRITEONLY, POOL_DEFAULT);

	//m_VBPatch = new VertexBuffer*[m_PatchCount];
		
	LoadHeightField();

	m_AABB.SetVolume(DXVector3(FLT_MAX, FLT_MAX, FLT_MAX), -DXVector3(FLT_MAX, FLT_MAX, FLT_MAX));

	m_Patches = new TerrainPatch*[m_PatchCount];
	ZeroMemory(m_Patches, sizeof(TerrainPatch*) * m_PatchCount);
	for(unsigned i=0; i<m_PatchCount; i++)
	{
		int bx = i % m_PatchTile;
		int by = i / m_PatchTile;
		m_Patches[i] = new TerrainPatch(this, bx, by);

		this->m_Childs.AddTail(m_Patches[i], 0);

		m_AABB.Unify(m_Patches[i]->GetAABB());
	}

	Restore();
}

Terrain::~Terrain(void)
{
//	delete m_QT;
//	delete m_QTShadow;
	//delete [] m_PatchMin;
	//delete [] m_PatchMax;
	delete [] m_HeightField;

	m_IB->Release();
//	m_VBXY->Release();
//	m_VB->Release();

/*	for(unsigned i=0; i< m_PatchCount; i++)
	{
		SAFERELEASE(m_VBPatch[i]);
	}
	delete [] m_VBPatch;*/

	for(unsigned i=0; i< m_PatchCount; i++)
	{
		delete m_Patches[i];
	}
	delete [] m_Patches;

	delete m_VDecl;

	m_FXTerrain->Release();
}

void Terrain::DoRestore(void)
{
	if (m_IB)
	{
		WORD* ib;
		m_IB->GetBuffer()->Lock(0, 0, (void**)&ib, 0);

		unsigned stride = m_PatchStride;
		//unsigned stride = m_HMSize + 1;

		for(unsigned y = 0; y<m_PatchStride-1; y++)
			for(unsigned x = 0; x<m_PatchStride-1; x++)
			{
				if(x%2 && y%2 || !(x%2) && !(y%2))
				{
					*ib++ = x + y * stride;
					*ib++ = x + 1 + y * stride;
					*ib++ = x + 1 + (y + 1) * stride;

					*ib++ = x + y * stride;
					*ib++ = x + 1 + (y + 1) * stride;
					*ib++ = x + (y + 1) * stride;
				}
				else
				{
					*ib++ = x + y * stride;
					*ib++ = x + 1 + y * stride;
					*ib++ = x + (y + 1) * stride;

					*ib++ = x + 1 + y * stride;
					*ib++ = x + 1 + (y + 1) * stride;
					*ib++ = x + (y + 1) * stride;
				}
			}

		m_IB->GetBuffer()->Unlock();

		for(unsigned i=0; i< m_PatchCount; i++)
		{
			if (m_Patches[i])
				m_Patches[i]->OnRestoreIB();
		}
	}

	/*DXVector2* vb;
	m_VBXY->GetBuffer()->Lock(0, 0, (void**)&vb, 0);

	for(unsigned y = 0; y<m_PatchStride; y++)
		for(unsigned x = 0; x<m_PatchStride; x++)
		{
			*vb++ = DXVector2(x, y) * m_TileScale;
		}

	m_VBXY->GetBuffer()->Unlock();*/

	/*STPatchVertex* vb;
	m_VB->GetBuffer()->Lock(0, 0, (void**)&vb, 0);
	for(int y = 0; y <= m_HMSize; y++)
		for(int x = 0; x <= m_HMSize; x++)
		{
			vb->x = x * m_TileScale;
			vb->y = y * m_TileScale;
			vb->height = m_HeightField[x + y * (m_HMSize + 1)];
			DXVector3 n = CalcNormal(x, y);
			vb->nx = n.x;
			vb->ny = n.y;
			vb++;
		}

	m_VB->GetBuffer()->Unlock();*/
}

void Terrain::LoadHeightField(void)
{
	FILE* f;
	XString fn = "Terrain\\";
	fn.appand(m_HMFile);
	fopen_s(&f, fn.getbuffer(), "rb");

	WORD* heightfield = new WORD[m_HeightSamples];
	fread(heightfield, sizeof(WORD), m_HeightSamples, f);

	fclose(f);

	for (int i = 0; i < m_HeightSamples; i++)
		m_HeightField[i] = heightfield[i] * m_HeightScale;

	//m_AABB.SetVolume(DXVector3(FLT_MAX, FLT_MAX, FLT_MAX), -DXVector3(FLT_MAX, FLT_MAX, FLT_MAX));

	//fill heightfield
	/*for(unsigned by = 0; by < m_PatchTile; by++)
		for(unsigned bx = 0; bx < m_PatchTile; bx++)
		{
			unsigned ind = bx + by * m_PatchTile;

			//m_PatchMin[ind] = 1e30f;
			//m_PatchMax[ind] = -1e30f;

			unsigned xoff = bx * (m_PatchStride-1);
			unsigned yoff = by * (m_PatchStride-1);

			for(unsigned y = 0; y < m_PatchStride; y++)
				for(unsigned x = 0; x < m_PatchStride; x++)
				{
					unsigned hind = x + xoff + (y + yoff) * (m_HMSize+1);
					float h = heightfield[hind] * m_HeightScale;

					//if(h < m_PatchMin[ind])
					//	m_PatchMin[ind] = h;
					//else if(h > m_PatchMax[ind])
					//	m_PatchMax[ind] = h;

					m_HeightField[hind] = h;
				}

			//const float zmaxoff = 8;
			//DXVector3 vmin(bx * (m_PatchStride-1) * m_TileScale, by * (m_PatchStride-1) * m_TileScale, m_PatchMin[ind]);
			//DXVector3 vmax((bx + 1) * (m_PatchStride-1) * m_TileScale, (by + 1) * (m_PatchStride-1) * m_TileScale, m_PatchMax[ind] + zmaxoff);
			//m_AABB.Unify(AABB(vmin,vmax));
			//m_QT->GetLeaf(m_QT->GetLevels() - 1, bx, by)->SetPoints(vmin, vmax);
			//m_QTShadow->GetLeaf(m_QTShadow->GetLevels() - 1, bx, by)->SetPoints(vmin, vmax);
		}*/

	delete [] heightfield;

//	m_QT->UpdatePoints();
//	m_QTShadow->UpdatePoints();

	/*STPatchVertex* vb;

	//write vertexbuffers
	for(unsigned by = 0; by < m_PatchTile; by++)
		for(unsigned bx = 0; bx < m_PatchTile; bx++)
		{
			unsigned ind = bx + by * m_PatchTile;

			unsigned xoff = bx * (m_PatchStride-1);
			unsigned yoff = by * (m_PatchStride-1);

			m_VBPatch[ind]->GetBuffer()->Lock(0, 0, (void**)&vb, 0);

			for(unsigned y = 0; y < m_PatchStride; y++)
				for(unsigned x = 0; x < m_PatchStride; x++)
				{
					unsigned hind = x + xoff + (y + yoff) * (m_HMSize+1);
					
					vb->x = (x + xoff) * m_TileScale;
					vb->y = (y + yoff) * m_TileScale;
					vb->height = m_HeightField[hind];
					DXVector3 n = CalcNormal(x + xoff, y + yoff);
					vb->nx = n.x;
					vb->ny = n.y;
					//vb->n = n;
					//vb->color = HeightToColor(m_HeightField[hind]);

					vb++;
				}

			m_VBPatch[ind]->GetBuffer()->Unlock();
		}*/
}
/*
void Terrain::Update(void)
{
	m_QT->CalcVisible(*m_App->GetCam());

	for(unsigned i=0; i< m_PatchCount; i++)
	{
		if (m_Patches[i])
			m_Patches[i]->Update(0);
	}

	m_App->ExpandSceneBound(m_AABB);
}

void Terrain::UpdateShadow(void)
{
	for(unsigned i=0; i< m_PatchCount; i++)
	{
		if (m_Patches[i])
			m_Patches[i]->UpdateShadow();
	}
	//Camera camShadow;
	//camShadow.SetViewMatrix(m_App->GetShadowMapping()->GetLightView());
	//camShadow.SetProjMatrix(m_App->GetShadowMapping()->GetLightProj());
	
	//m_QTShadow->CalcVisible(camShadow);

	//if(m_QTShadow->GetRoot()->visible != QTVT_NONE)
	//	m_App->AddToShadowRenderList(this);
}*/

//void Terrain::Render(const bool depthmap)
//{
//	if(m_FXTerrain->IsCompiled())
//	{
//		if(depthmap)
//		{
//			m_FXTerrain->SetMatrix("SM_matSM", m_App->GetShadowMapping()->GetSMMatrix());
//
//			m_FXTerrain->SetTechnique("RenderShadowDepth");
//		}
//		else
//		{
//			m_FXTerrain->SetMatrix(m_hMatViewProj, m_App->GetActiveCam()->GetViewProjMatrix());
//
//			if(m_App->UseDeferred())
//			{
//				m_FXTerrain->SetTechnique("RenderDS");
//			}
//			else
//			{
//				m_FXTerrain->SetTechnique("Render");
//				m_FXTerrain->SetVector(m_hSunColor, static_cast<DXVector4>(m_App->GetSunColor()));
//				m_FXTerrain->SetVector(m_hAmbientColor, static_cast<DXVector4>(m_App->GetAmbientColor()));
//				m_FXTerrain->SetFloatArray(m_hLightDir, (float*)&m_App->GetSunDir(), 3);
//
//				m_FXTerrain->SetMatrix("SM_matSMTex", m_App->GetShadowMapping()->GetSMTexMatrix());  
//				m_FXTerrain->SetMatrix("SM_matSM", m_App->GetShadowMapping()->GetSMMatrix()); 
//				m_FXTerrain->SetTexture("SM_ShadowMap",m_App->GetShadowMapping()->GetShadowMap()->GetSurface());  
//				//m_FXTerrain->SetFloat("SM_rcpShadowMapSize", 1.f/m_App->GetShadowMapping()->GetShadowMapSize());  
//				m_FXTerrain->SetFloat("SM_ShadowMapSize", m_App->GetShadowMapping()->GetShadowMapSize());  
//				
//				m_FXTerrain->SetMatrix("SM_matWorld", DXMatrix::IDENTITY());
//			}
//		}
//		
//		m_App->GetDevice()->SetVertexDeclaration(m_VDecl->GetVDecl());
//		//m_App->GetDevice()->SetStreamSource(0, m_VBXY->GetBuffer(), 0, sizeof(DXVector2));
//		m_App->GetDevice()->SetIndices(m_IB->GetBuffer());
//		//m_App->GetDevice()->SetStreamSource(0, m_VB->GetBuffer(), 0, sizeof(STPatchVertex));
//
//		RENDERFX(m_FXTerrain,
//			for(unsigned by = 0; by < m_PatchTile; by++)
//				for(unsigned bx = 0; bx < m_PatchTile; bx++)
//				{
//					//if(!depthmap && m_QT->GetLeaf(m_QT->GetLevels()-1, bx, by)->visible != QTVT_NONE || depthmap && m_QTShadow->GetLeaf(m_QTShadow->GetLevels()-1, bx, by)->visible != QTVT_NONE)
//					if(m_QT->GetLeaf(m_QT->GetLevels()-1, bx, by)->visible != QTVT_NONE)
//					{
//						/*DXMatrix matWorld;
//						D3DXMatrixTranslation((D3DXMATRIX*)&matWorld, bx * (m_PatchStride-1) * m_TileScale, by* (m_PatchStride-1) * m_TileScale, 0);
//
//						if(depthmap)
//						{
//							m_FXTerrain->SetMatrix("SM_matWorld", matWorld);
//						}
//						else
//						{
//							m_FXTerrain->SetMatrix(m_hMatWorld, matWorld);
//						}
//
//						m_FXTerrain->GetShader()->CommitChanges();
//
//						unsigned ind = bx + by * m_PatchTile;
//						m_App->GetDevice()->SetStreamSource(1, m_VBPatch[ind]->GetBuffer(), 0, sizeof(STPatchVertex));
//
//						m_App->GetDevice()->DrawIndexedPrimitive(PT_TRIANGLELIST, 0, 0, m_PatchHeightSamples, 0, m_PatchPrimitives);*/
//
//						unsigned ind = bx + by * m_PatchTile;
//						m_App->GetDevice()->SetStreamSource(0, m_VBPatch[ind]->GetBuffer(), 0, sizeof(STPatchVertex));
//						m_App->GetDevice()->DrawIndexedPrimitive(PT_TRIANGLELIST, 0, 0, m_PatchHeightSamples, 0, m_PatchPrimitives);
//
//						/*int bsize = (m_HMSize >> m_TileShift);
//						int baseIndex = bx * bsize + by * bsize * (m_HMSize + 1);
//						int numVertices = (m_HMSize + 2) * m_PatchTiles + 1;
// 
//						m_App->GetDevice()->DrawIndexedPrimitive(PT_TRIANGLELIST, baseIndex, 0, numVertices, 0, m_PatchPrimitives);*/
//					}
//				}
//		);
//	}
//}

DXVector3 Terrain::CalcNormal(int x, int y)
{
	float h1; //oben
	float h2; //links
	float h3; //rechst
	float h4; //unten

	int ind = x + y * (m_HMSize+1);

	if(y > 0)
		h1 = m_HeightField[ind-m_HMSize-1];
	else
		h1 = m_HeightField[ind];

	if(x > 0)
		h2 = m_HeightField[ind-1];
	else
		h2 = m_HeightField[ind];

	if(x < m_HMSize)
		h3 = m_HeightField[ind+1];
	else
		h3 = m_HeightField[ind];

	if(y < m_HMSize)
		h4 = m_HeightField[ind+m_HMSize+1];
	else
		h4 = m_HeightField[ind];

	DXVector3 n;
	D3DXVec3Cross(n, &D3DXVECTOR3(2.f * m_TileScale, 0.f, h3 - h2), &D3DXVECTOR3(0.f, 2.f * m_TileScale, h4 - h1));
	D3DXVec3Normalize(n, n); 
	return n; 
}

DXColor Terrain::HeightToColor(const float z) const
{
	static const DXColor hc[6] = {	
		DXColor(148/255.f,142/255.f,50/255.f,1),
		DXColor(148/255.f,142/255.f,50/255.f,1),
		DXColor(48/255.f,142/255.f,50/255.f,1),
		DXColor(127/255.f,177/255.f,112/255.f,1),
		DXColor(151/255.f,146/255.f,145/255.f,1),
		DXColor(230/255.f,238/255.f,254/255.f,1)};

	DXColor c1, c2;
	float s;

	float step = 40;

	if(z < step)
		return hc[0];

	int i=0;
	for(; i < 5; i++)
	{
		if(z < (i+2) * step)
		{
			c1 = hc[i];
			c2 = hc[i+1];
			s = 1 - ((i+2)*step - z)/step;
			break;
		}
	}

	if(i >= 5)
		return hc[5];

	DXColor out;
	D3DXColorLerp((D3DXCOLOR*)&out, (D3DXCOLOR*)&c1, (D3DXCOLOR*)&c2, s);

	return out;
}

float Terrain::GetHeight(const float x, const float y)
{	
	float xb = x / m_TileScale;
	float yb = y / m_TileScale;

	float sx = xb - (int)xb;
	float sy = yb - (int)yb;

	int ix = (int)xb;
	int iy = (int)yb;

	if(ix < 0)
	{
		ix = 0;
		sx = 0;
	}
	else if(ix > m_HMSize)
	{
		ix = m_HMSize;
		sx = 0;
	}
	if(iy < 0)
	{
		iy = 0;
		sy = 0;
	}
	else if(iy > m_HMSize)
	{
		iy = m_HMSize;
		sy = 0;
	}

	int ix2 = ix+1;
	int iy2 = iy+1;

	if(ix2 > m_HMSize)
		ix2 = m_HMSize;
	if(iy2 > m_HMSize)
		iy2 = m_HMSize;

	float h0 = m_HeightField[ix + iy * (m_HMSize+1)];
	float h1 = m_HeightField[ix2 + iy * (m_HMSize+1)];
	float hx0 = Linear_Interpolate(h0, h1, sx);
	float h2 = m_HeightField[ix + iy2 * (m_HMSize+1)];
	float h3 = m_HeightField[ix2 + iy2 * (m_HMSize+1)];
	float hx1 = Linear_Interpolate(h2, h3, sx);

	return Linear_Interpolate(hx0, hx1, sy);
}