#include "TerrainScene.h"
#include "QuadTree.h"
#include "DynOctTree.h"

static const int g_iMeshTypes = 8;
static const char* g_strMeshes[] = {"tiger.x", "car.x", "oster.x", "arrow.x", "eifel.x", "airplane 2.x", "bigship1.x", "heli.x"};
//static const int g_iMeshCount[] = {0, 0, 0, 0, 0, 30, 30, 30};
//static const int g_iMeshCount[] = {300, 150, 200, 200, 20, 30, 30, 30};
static const int g_StaticObjCount = 1500;
static const int g_DynamicObjCount = 200;
static const float g_ObjRatio[] = {0.3f, 0.19f, 0.2f, 0.2f, 0.01f, 0.333f, 0.333f, 0.334f};
static const float g_fMeshScale[] = {5, 2, 1, 30, 0.5f, 1, 1, 1};
static const float g_fAirPlaneSpeed[] = {0, 0, 0, 0, 0, 30, 80, 10};
static const float g_fMeshZOff[] = {3, 5, 9, 30, -1, 40, 70, 30};
static const bool g_bAirPlane[] = {false, false, false, false, false, true, true, true};
static const float g_fMeshRot[] = {D3DX_PI/2, D3DX_PI/2, 0, D3DX_PI, 0, 0, 0, 0};
static CMesh* g_pMeshes[] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};


TerrainScene::TerrainScene(ShadowApp* const pApp) : ShadowScene(pApp)
{
	m_pTerrain = NULL;

	srand(114);

	m_pSPT = new DynOctTree(32, 0.2f);
	
	m_pTerrain = new Terrain(this, 5, 0.0042f, 4, "heightfield513.raw", 512);

	for(int y = 0; y < (1 << 5); y++)
	{
		for(int x = 0; x < (1 << 5); x++)
		{
			TerrainPatch* p = m_pTerrain->GetPatch(x, y);
			m_pSPT->AddObject(p);
		}
	}

	m_pSG->SetRoot(new SceneObject(this));

	for (int i=0; i < g_iMeshTypes; i++)
	{
		g_pMeshes[i] = new CMesh(m_pApp->GetDevice(), XString(g_strMeshes[i]), XString("Meshes\\"));
		g_pMeshes[i]->BuildDrawCalls();
		for(unsigned j= 0; j<g_pMeshes[i]->GetMaterialCount(); j++)
			g_pMeshes[i]->GetMaterials()[j].SetAmbient(D3DXCOLOR(0.2f, 0.2f, 0.2f, 1));

		int cnt = (g_bAirPlane[i] ? g_DynamicObjCount : g_StaticObjCount) * g_ObjRatio[i];
		for (int j = 0; j < cnt;j++)
		{
			SceneObject* obj;

			if (g_bAirPlane[i])
			{
				obj = new AirPlane(this, g_pMeshes[i], g_fMeshScale[i], g_fAirPlaneSpeed[i]);

				float height = g_fMeshZOff[i] + frand() * g_fMeshZOff[i] + (frand()-0.5) * 20;

				DXVector3 p1(-1,0,0);
				//DXVector3 dir(-1,0,0);

				//add 10 wapoints
				for (int j = 0; j < 10; j++)
				{
					float x = frand() * 2046 + 1;
					float y = frand() * 2046 + 1;
					float z = (m_pTerrain ? m_pTerrain->GetHeight(x, y) : 0) + height;

					DXVector3 p2 = DXVector3(x, y, z);
					
					if(p1.x != -1)
					{
						float d = D3DXVec3Length(p2 - p1);
						if(d < 50 || d > 200)
						{
							j--;
							continue;
						}
					}

					((AirPlane*)obj)->AddPoint(p2, 0);

					p1 = p2;
				}
				
				m_pSG->GetRoot()->m_Childs.AddTail(obj, 0);
			}
			else
			{
				DXMatrix matScale;
				D3DXMatrixScaling((D3DXMATRIX*)&matScale, g_fMeshScale[i], g_fMeshScale[i], g_fMeshScale[i]);

				DXMatrix matRotate;
				D3DXMatrixRotationX((D3DXMATRIX*)&matRotate, g_fMeshRot[i]);
			
				float x = frand() * 2046 + 1;
				float y = frand() * 2046 + 1 ;
				float z = m_pTerrain ? m_pTerrain->GetHeight(x, y) : 0;

				DXMatrix matTrans;
				D3DXMatrixTranslation((D3DXMATRIX*)&matTrans, x, y, z + g_fMeshZOff[i]);

				obj = new MeshObject(this, g_pMeshes[i], matScale * matRotate * matTrans);
			}
			
			m_Objects.AddTail(obj, 0);

			m_pSPT->AddObject(obj);
		}
	}

	//update bounds from all childs and objects in tree
	m_pSPT->GetRoot()->UpdateBound();

	ResetCam();

	InitCamPositions();

	//m_pSkyTexture = m_pApp->GetDevice()->GetTextureManager()->CreateCubeTexture("SkyBox\\skybox.dds", FMT_A8R8G8B8, POOL_MANAGED);

	m_pSkyTexture = m_pApp->GetDevice()->GetTextureManager()->CreateCubeTexture(2048, 1, 0, FMT_A8R8G8B8, POOL_MANAGED);
	LPDIRECT3DSURFACE9 s;

	m_pSkyTexture->GetCubeTexture()->GetCubeMapSurface(D3DCUBEMAP_FACE_POSITIVE_X, 0, &s);
	D3DXLoadSurfaceFromFile(s, NULL, NULL, "SkyBox\\SkyBox0001.png", NULL, D3DX_DEFAULT, 0, NULL);
	s->Release();

	m_pSkyTexture->GetCubeTexture()->GetCubeMapSurface(D3DCUBEMAP_FACE_NEGATIVE_X, 0, &s);
	D3DXLoadSurfaceFromFile(s, NULL, NULL, "SkyBox\\SkyBox0002.png", NULL, D3DX_DEFAULT, 0, NULL);
	s->Release();

	m_pSkyTexture->GetCubeTexture()->GetCubeMapSurface(D3DCUBEMAP_FACE_POSITIVE_Y, 0, &s);
	D3DXLoadSurfaceFromFile(s, NULL, NULL, "SkyBox\\SkyBox0003.png", NULL, D3DX_DEFAULT, 0, NULL);
	s->Release();

	m_pSkyTexture->GetCubeTexture()->GetCubeMapSurface(D3DCUBEMAP_FACE_NEGATIVE_Y, 0, &s);
	D3DXLoadSurfaceFromFile(s, NULL, NULL, "SkyBox\\SkyBox0004.png", NULL, D3DX_DEFAULT, 0, NULL);
	s->Release();

	m_pSkyTexture->GetCubeTexture()->GetCubeMapSurface(D3DCUBEMAP_FACE_POSITIVE_Z, 0, &s);
	D3DXLoadSurfaceFromFile(s, NULL, NULL, "SkyBox\\SkyBox0005.png", NULL, D3DX_DEFAULT, 0, NULL);
	s->Release();

	m_pSkyTexture->GetCubeTexture()->GetCubeMapSurface(D3DCUBEMAP_FACE_NEGATIVE_Z, 0, &s);
	D3DXLoadSurfaceFromFile(s, NULL, NULL, "SkyBox\\SkyBox0006.png", NULL, D3DX_DEFAULT, 0, NULL);
	s->Release();
}

TerrainScene::~TerrainScene(void)
{
	delete m_pTerrain;
	delete m_pSG->GetRoot();

	for (int i = 0; i < g_iMeshTypes; i++)
	{
		delete g_pMeshes[i];
		g_pMeshes[i] = NULL;
	}
}

void TerrainScene::DoInvalidate(void)
{
	if (m_pTerrain)
		m_pTerrain->Invalidate();
}

void TerrainScene::DoRestore(void)
{
	if (m_pTerrain)
		m_pTerrain->Restore();
}

void TerrainScene::ResetCam(void)
{
	m_Cam.SetPosition(DXVector3(1024, 1024, 300));
	m_Cam.SetPerspectiveProj(m_pApp->GetCurrentMode().Width, m_pApp->GetCurrentMode().Height, 1, 2000);
	m_Cam.SetLookAt(DXVector3(1024, 768, 0), DXVector3(0, 0, 1));

	m_DebugCam = m_Cam;
	m_DebugCam.SetPerspectiveProj(m_pApp->GetCurrentMode().Width, m_pApp->GetCurrentMode().Height, 1, 4000);
}

void TerrainScene::InitCamPositions(void)
{
	m_CamPos[0] = DXVector3(1937.4579f, 154.25737f, 106.18068f);
	m_CamDir[0] = DXVector3(-0.96903992f, 0.20067826f, -0.14387560f);
	m_CamUp[0] = DXVector3(-0.14088205f, 0.029169858f, 0.98960102f);
	m_CamLightAngX[0] = 0.43204838f; m_CamLightAngZ[0] = 0;

	m_CamPos[1] = DXVector3(576.573181f, 424.377930f, 256.113831f);
	m_CamDir[1] = DXVector3(0.305432f, 0.854176f, -0.420844f);
	m_CamUp[1] = DXVector3(0.141696f, 0.396262f, 0.907141f);
	m_CamLightAngX[1] = 0.318296f; m_CamLightAngZ[1] = 0;

	m_CamPos[2] = DXVector3(85.702980f, 894.873047f, 215.861694f);
	m_CamDir[2] = DXVector3(0.949439f, 0.002271f, -0.313977f);
	m_CamUp[2] = DXVector3(0.313968f, 0.000736f, 0.949441f);
	m_CamLightAngX[2] = 0.295423f; m_CamLightAngZ[2] = 0;

	m_CamPos[3] = DXVector3(208.453995f, 1516.988770f, 181.697083f);
	m_CamDir[3] = DXVector3(0.818656f, -0.516234f, -0.251646f);
	m_CamUp[3] = DXVector3(0.212845f, -0.134241f, 0.967831f);
	m_CamLightAngX[3] = 0.644571f; m_CamLightAngZ[3] = 0;

	m_CamPos[4] = DXVector3(340.873138f, 1494.112793f, 450.509613f);
	m_CamDir[4] = DXVector3(0.492476f, -0.714938f, -0.496351f);
	m_CamUp[4] = DXVector3(0.281548f, -0.408770f, 0.868141f);
	m_CamLightAngX[4] = 0.659811f; m_CamLightAngZ[4] = 0;

	m_CamPos[5] = DXVector3(700.123535f, 616.446960f, 191.116272f);
	m_CamDir[5] = DXVector3(-0.361574f, 0.896390f, -0.256493f);
	m_CamUp[5] = DXVector3(-0.095941f, 0.237841f, 0.966567f);
	m_CamLightAngX[5] = 0.670558f; m_CamLightAngZ[5] = 0;

	m_CamPos[6] = DXVector3(2049.973877f, 1980.262695f, 459.401306f);
	m_CamDir[6] = DXVector3(-0.682487f, -0.610016f, -0.402674f);
	m_CamUp[6] = DXVector3(-0.300138f, -0.268436f, 0.915373f);
	m_CamLightAngX[6] = 0.322578f; m_CamLightAngZ[6] = 0;

	m_CamPos[7] = DXVector3(960.017822f, 1391.885498f, 164.222977f);
	m_CamDir[7] = DXVector3(0.451880f, 0.817842f, -0.356472f);
	m_CamUp[7] = DXVector3(0.172346f, 0.311934f, 0.934378f);
	m_CamLightAngX[7] = 0.347406f; m_CamLightAngZ[7] = 0;

	m_CamPos[8] = DXVector3(1905.679199f, 958.261902f, 95.568993f);
	m_CamDir[8] = DXVector3(-0.930177f, -0.309385f, -0.198345f);
	m_CamUp[8] = DXVector3(-0.187858f, -0.063387f, 0.980280f);
	m_CamLightAngX[8] = 0.647445f; m_CamLightAngZ[8] = 0;

	m_CamPos[9] = DXVector3(1213.800537f, 1123.877686f, 171.902130f);
	m_CamDir[9] = DXVector3(0.886222f, -0.134756f, -0.443853f);
	m_CamUp[9] = DXVector3(0.438808f, -0.065643f, 0.896408f);
	m_CamLightAngX[9] = 0.442477f; m_CamLightAngZ[9] = 0;
}