
//To be called after CreateHeightMap(). Loads the terrain vertex buffer with vertex data.(x,y,z coords, u,v coords, normal data etc.)
void Terrain::CreateVertices(DWORD or)
{
	int i;
	int j;
	float texelWidth=1.0f/(float)texWidth;
	float texelHeight=1.0f/(float)texHeight;
	float uOffset=0.5f*texelWidth;
	float vOffset=0.5f*texelHeight;
	float detailTexWidthLength=(CellLength*numOfWidthCells)/DetailTexRepeatCount;
	float detailTexHeightLength=(CellLength*numOfHeightCells)/DetailTexRepeatCount;
	TerrainVertex* vertexData;

	GraphicEngine::Device->CreateVertexBuffer(totalVertexCount*sizeof(TerrainVertex),D3DUSAGE_WRITEONLY,
											  TerrainVertexFVF,D3DPOOL_MANAGED,&VB,0);	

	VB->Lock(0,0,(void**)&vertexData,0);

	for(i=0;i<numOfHeightVertices;i++)
	{
		for(j=0;j<numOfWidthVertices;j++)
			{
				(vertexData+(numOfWidthVertices*i+j))->x=Left+j*CellLength;
				(vertexData+(numOfWidthVertices*i+j))->y=GetHeightMapValue(i,j);//0.0f;//GetHeight(i,j);
				(vertexData+(numOfWidthVertices*i+j))->z=Up-i*CellLength;
				(vertexData+(numOfWidthVertices*i+j))->u=uOffset + j*texelWidth;
				(vertexData+(numOfWidthVertices*i+j))->v=vOffset + i*texelHeight;
				(vertexData+(numOfWidthVertices*i+j))->u2=(j*CellLength)/detailTexWidthLength;
				(vertexData+(numOfWidthVertices*i+j))->v2=(i*CellLength)/detailTexHeightLength;
				//(vertexData+(numOfWidthVertices*i+j))->color=D3DCOLOR_XRGB(255,129,49);

				/*
				(vertexData+(numOfWidthVertices*i+j))->u=TextureOffsetX*j;
				(vertexData+(numOfWidthVertices*i+j))->v=TextureOffsetZ*i;
				(vertexData+(numOfWidthVertices*i+j))->u2=(j*CellLength)/DetailTexRepeatCount;
				(vertexData+(numOfWidthVertices*i+j))->v2=(i*CellLength)/DetailTexRepeatCount;
				(vertexData+(numOfWidthVertices*i+j))->encoded_GeoMorphingData=EncodeGeoMorphingData(0.0f,-1.0f,0.0f);

				(vertexData+(numOfWidthVertices*i+j))->dx=0.0f;
				(vertexData+(numOfWidthVertices*i+j))->dy=0.0f;
				(vertexData+(numOfWidthVertices*i+j))->dz=0.0f;
				*/
			}
	}

	VB->Unlock();

	//Zero all Orientations
	for(i=0;i<cellOrientationsLength;i++)
		cellOrientations[i]=0;
	//Set CellOrientations
	if(or==ALL_RIGHT_BOTTOM_TO_LEFT_TOP)
	{
		for(i=0;i<totalCellCount;i++)
			SetCellOrientation(RIGHT_BOTTOM_TO_LEFT_TOP,i);
		
	}
	else if(or==ALL_LEFT_BOTTOM_TO_RIGHT_TOP)
	{
		for(i=0;i<totalCellCount;i++)
			SetCellOrientation(LEFT_BOTTOM_TO_RIGHT_TOP,i);
	}
	else if(or==FIRST_ROW_RB_TO_LT_SECOND_ROW_LB_TO_RT)
	{
		for(i=0;i<numOfHeightVertices-1;i++)
		{
			for(j=0;j<numOfWidthVertices-1;j++)
				{
					if(i%2==0)
						SetCellOrientation(RIGHT_BOTTOM_TO_LEFT_TOP,i*(numOfWidthVertices-1)+j);
					else
						SetCellOrientation(LEFT_BOTTOM_TO_RIGHT_TOP,i*(numOfWidthVertices-1)+j);
				}
		}
	}
	else if(or==FIRST_ROW_LB_TO_RT_SECOND_ROW_RB_TO_LT)
	{
		for(i=0;i<numOfHeightVertices;i++)
		{
			for(j=0;j<numOfWidthVertices;j++)
				{
					if(i%2==0)
						SetCellOrientation(LEFT_BOTTOM_TO_RIGHT_TOP,i*(numOfWidthVertices-1)+j);
					else
						SetCellOrientation(RIGHT_BOTTOM_TO_LEFT_TOP,i*(numOfWidthVertices-1)+j);
				}
		}
	}



}*/
//To be called after CreateVertices(). Creates the indices in an unoptimized fashion for the whole terrain.
void Terrain::CreateUnOptimizedIndices()
{
	int i;
	int index=0;
	DWORD or;
	int v0,v1,v2,v3;
	int I,J;
	int* indexData;

	GraphicEngine::Device->CreateIndexBuffer(totalTriangleCount*3*sizeof(int),D3DUSAGE_WRITEONLY,D3DFMT_INDEX32,D3DPOOL_MANAGED,&IB,0);
	//Simulate Triangle Strips with regular triangles
	IB->Lock(0,0,(void**)&indexData,0);
	for(i=0;i<totalCellCount;i++)
	{
		I=i/numOfWidthCells;
		J=i%numOfWidthCells;
		
		v0= I   *numOfWidthVertices + J;
		v1= I   *numOfWidthVertices + J + 1;
		v2=(I+1)*numOfWidthVertices + J;
		v3=(I+1)*numOfWidthVertices + J + 1;
		
		or=GetCellOrientation(i);

		if(or==RIGHT_BOTTOM_TO_LEFT_TOP)
		{
		/*
		   v0    v1
			*----*
			|\   |
			| \  |
			|  \ |
			|   \|
			*----*
           v2    v3
		*/
			//Triangle 0 -> v2v0v3. CW.
			indexData[index  ]=v2;
			indexData[index+1]=v0;
			indexData[index+2]=v3;

			//Triangle 1 -> v3v0v1. CW.
			indexData[index+3]=v3;
			indexData[index+4]=v0;
			indexData[index+5]=v1;
		}
		else
		{
		/*
		   v0    v1
			*----*
			|   /|
			|  / |
			| /  |
			|/   |
			*----*
           v2    v3
		*/
			//Triangle 0 -> v0v1v2. CW.
			indexData[index  ]=v0;
			indexData[index+1]=v1;
			indexData[index+2]=v2;

			//Triangle 1 -> v2v1v3. CW.
			indexData[index+3]=v2;
			indexData[index+4]=v1;
			indexData[index+5]=v3;
		}
		index=index+6;
	}
	IB->Unlock();
	

}




//To be called after CreateVertices(). Calls D3DX functions to optimize the face and vertex ordering in order to benefit from vertex caches.
void Terrain::CreateOptimizedIndices()
{
	int i;
	int index=0;
	DWORD or;
	int v0,v1,v2,v3;
	int I,J;
	int* unOptIndexList;
	int* indexData;
	int indexCount;

	indexCount=totalTriangleCount*3;
	App::mem.AllocateMemory((void**)&unOptIndexList,indexCount*sizeof(int));

	for(i=0;i<totalCellCount;i++)
	{
		I=i/numOfWidthCells;
		J=i%numOfWidthCells;
		
		v0= I   *numOfWidthVertices + J;
		v1= I   *numOfWidthVertices + J + 1;
		v2=(I+1)*numOfWidthVertices + J;
		v3=(I+1)*numOfWidthVertices + J + 1;
		
		or=GetCellOrientation(i);

		if(or==RIGHT_BOTTOM_TO_LEFT_TOP)
		{
		/*
		   v0    v1
			*----*
			|\   |
			| \  |
			|  \ |
			|   \|
			*----*
           v2    v3
		*/
			//Triangle 0 -> v2v0v3. CW.
			unOptIndexList[index  ]=v2;
			unOptIndexList[index+1]=v0;
			unOptIndexList[index+2]=v3;

			//Triangle 1 -> v3v0v1. CW.
			unOptIndexList[index+3]=v3;
			unOptIndexList[index+4]=v0;
			unOptIndexList[index+5]=v1;
		}
		else
		{
		/*
		   v0    v1
			*----*
			|   /|
			|  / |
			| /  |
			|/   |
			*----*
           v2    v3
		*/
			//Triangle 0 -> v0v1v2. CW.
			unOptIndexList[index  ]=v0;
			unOptIndexList[index+1]=v1;
			unOptIndexList[index+2]=v2;

			//Triangle 1 -> v2v1v3. CW.
			unOptIndexList[index+3]=v2;
			unOptIndexList[index+4]=v1;
			unOptIndexList[index+5]=v3;
		}
		index=index+6;
	}

	App::mem.FreeMemory(unOptIndexList);
}


	
	{
	/*
	for(i=0;i<triangleCount;i++)
	{
		optIndexList[3*faceRemapBuffer[i]  ]=unOptIndexList[3*i  ];
		optIndexList[3*faceRemapBuffer[i]+1]=unOptIndexList[3*i+1];
		optIndexList[3*faceRemapBuffer[i]+2]=unOptIndexList[3*i+2];
	}
	*/
	
    /*
	for(i=0;i<triangleCount;i++)
	{
		optIndexList[3*i  ]=unOptIndexList[3*i  ];
		optIndexList[3*i+1]=unOptIndexList[3*i+1];
		optIndexList[3*i+2]=unOptIndexList[3*i+2];
	}
	*/
	/*
	for(i=0;i<triangleCount;i++)
	{
		vertexOptIndexList[3*i  ]=optIndexList[3*i  ];
		vertexOptIndexList[3*i+1]=optIndexList[3*i+1];
		vertexOptIndexList[3*i+2]=optIndexList[3*i+2];
	}
	*/
	}
	
	
void Terrain::CreateNodeVertices(QuadTreeNode* node)
{
	int i;
	int j;
	float texelWidth=1.0f/(float)texWidth;
	float texelHeight=1.0f/(float)texHeight;
	float uOffset=0.5f*texelWidth;
	float vOffset=0.5f*texelHeight;
	float detailTexWidthLength=(CellLength*numOfWidthCells)/DetailTexRepeatCount;
	float detailTexHeightLength=(CellLength*numOfHeightCells)/DetailTexRepeatCount;
	float nodeLeft=Left + node->LeftTopJ*CellLength;
	float nodeUp=Up - node->LeftTopI*CellLength;
	TerrainVertex* vertexData;

	node->WidthVertexCount=node->WidthSpaceCount+1;
	node->HeightVertexCount=node->HeightSpaceCount+1;
	node->VertexCount=(node->HeightVertexCount)*(node->WidthVertexCount);
	node->TriangleCount=node->HeightSpaceCount*node->WidthSpaceCount*2;

	GraphicEngine::Device->CreateVertexBuffer(node->VertexCount*sizeof(TerrainVertex),D3DUSAGE_WRITEONLY,
											  TerrainVertexFVF,D3DPOOL_MANAGED,&node->VB,0);	
	node->VB->Lock(0,0,(void**)&vertexData,0);
	
	for(i=0;i<node->HeightVertexCount;i++)
	{
		for(j=0;j<node->WidthVertexCount;j++)
		{
				(vertexData+(node->WidthVertexCount*i+j))->x=nodeLeft + j*CellLength;
				(vertexData+(node->WidthVertexCount*i+j))->y=GetHeightMapValue(node->LeftTopI + i,node->LeftTopJ + j);
				(vertexData+(node->WidthVertexCount*i+j))->z=nodeUp - i*CellLength;
				(vertexData+(node->WidthVertexCount*i+j))->u=uOffset + (node->LeftTopJ + j)*texelWidth;
				(vertexData+(node->WidthVertexCount*i+j))->v=vOffset + (node->LeftTopI + i)*texelHeight;
				(vertexData+(node->WidthVertexCount*i+j))->u2=((node->LeftTopJ + j)*CellLength)/detailTexWidthLength;
				(vertexData+(node->WidthVertexCount*i+j))->v2=((node->LeftTopI + i)*CellLength)/detailTexHeightLength;
		}
	}

	node->VB->Unlock();

}

//Create the shared index buffer for all leaf nodes.
void Terrain::CreateNodeIndices()
{
	int i,j;
	int index=0;
	DWORD or;
	int v0,v1,v2,v3;
	int I,J;
	int* unOptIndexList;
	int* optIndexList;
	int* vertexOptIndexList;
	int* indexData;
	int cellIndex=0;
	int nodeNumOfWidthCells=(numOfWidthCells/(int)pow((double)2,(int)quadTreeDivisionCount));
	int nodeNumOfHeightCells=(numOfHeightCells/(int)pow((double)2,(int)quadTreeDivisionCount));
	int triangleCount=nodeNumOfWidthCells*nodeNumOfHeightCells*2;
	int vertexCount=(nodeNumOfWidthCells+1)*(nodeNumOfHeightCells+1);
	int indexCount=nodeNumOfWidthCells*nodeNumOfHeightCells*6;
	DWORD* faceRemapBuffer;
	DWORD* reverseVertexRemapBuffer;

	App::mem.AllocateMemory((void**)&unOptIndexList,indexCount*sizeof(int));
	App::mem.AllocateMemory((void**)&optIndexList,indexCount*sizeof(int));
	App::mem.AllocateMemory((void**)&vertexOptIndexList,indexCount*sizeof(int));
	App::mem.AllocateMemory((void**)&faceRemapBuffer,triangleCount*sizeof(DWORD));
	App::mem.AllocateMemory((void**)&vertexRemapBuffer,vertexCount*sizeof(DWORD));
	App::mem.AllocateMemory((void**)&reverseVertexRemapBuffer,vertexCount*sizeof(DWORD));

	GraphicEngine::Device->CreateIndexBuffer(indexCount*sizeof(int),D3DUSAGE_WRITEONLY,D3DFMT_INDEX32,D3DPOOL_MANAGED,&IB,0);

	for(i=0;i<nodeNumOfHeightCells;i++)
	{
		for(j=0;j<nodeNumOfWidthCells;j++)
		{
			v0= i   *(nodeNumOfWidthCells+1) + j;
			v1= i   *(nodeNumOfWidthCells+1) + j + 1;
			v2=(i+1)*(nodeNumOfWidthCells+1) + j;
			v3=(i+1)*(nodeNumOfWidthCells+1) + j + 1;

			or=GetCellOrientation(i*nodeNumOfWidthCells + j);

			if(or==RIGHT_BOTTOM_TO_LEFT_TOP)
			{
			/*
			   v0    v1
				*----*
				|\   |
				| \  |
				|  \ |
				|   \|
				*----*
			   v2    v3
			*/
				//Triangle 0 -> v2v0v3. CW.
				unOptIndexList[index  ]=v2;
				unOptIndexList[index+1]=v0;
				unOptIndexList[index+2]=v3;

				//Triangle 1 -> v3v0v1. CW.
				unOptIndexList[index+3]=v3;
				unOptIndexList[index+4]=v0;
				unOptIndexList[index+5]=v1;
			}
			else
			{
			/*
			   v0    v1
				*----*
				|   /|
				|  / |
				| /  |
				|/   |
				*----*
			   v2    v3
			*/
				//Triangle 0 -> v0v1v2. CW.
				unOptIndexList[index  ]=v0;
				unOptIndexList[index+1]=v1;
				unOptIndexList[index+2]=v2;

				//Triangle 1 -> v2v1v3. CW.
				unOptIndexList[index+3]=v2;
				unOptIndexList[index+4]=v1;
				unOptIndexList[index+5]=v3;
			}
			index=index+6;

		}
	}

	//Optimize Triangle ordering for better vertex cache utilization.
	D3DXOptimizeFaces(unOptIndexList,triangleCount,vertexCount,true,faceRemapBuffer);
	//Reorder the faces in the index buffer according to the faceRemapBuffer.
	for(i=0;i<triangleCount;i++)
	{
		optIndexList[3*i  ]=unOptIndexList[3*faceRemapBuffer[i]  ];
		optIndexList[3*i+1]=unOptIndexList[3*faceRemapBuffer[i]+1];
		optIndexList[3*i+2]=unOptIndexList[3*faceRemapBuffer[i]+2];
	}
	//Optimize vertex ordering for better vertex cache utilization.
	D3DXOptimizeVertices(optIndexList,triangleCount,vertexCount,true,reverseVertexRemapBuffer);
	//Reorder the vertices in the face optimized index buffer according to the vertexRemapBuffer.
	//reverseVertexRemapBuffer^-1 = vertexRemapBuffer
	for(i=0;i<vertexCount;i++)
	{
		for(j=0;j<vertexCount;j++)
		{
			if(reverseVertexRemapBuffer[j]==i)
			{
				vertexRemapBuffer[i]=j;
				break;
			}
		}
	}

	for(i=0;i<indexCount;i++)
		vertexOptIndexList[i]=(int)vertexRemapBuffer[optIndexList[i]];
	

	IB->Lock(0,0,(void**)&indexData,0);
	for(i=0;i<indexCount;i++)
		indexData[i]=vertexOptIndexList[i];
	IB->Unlock();

	App::mem.FreeMemory(unOptIndexList);
	App::mem.FreeMemory(optIndexList);
	App::mem.FreeMemory(vertexOptIndexList);
	App::mem.FreeMemory(faceRemapBuffer);
	App::mem.FreeMemory(reverseVertexRemapBuffer);
	//App::mem.FreeMemory(vertexRemapBuffer);
}

/*
	terInput->cellLength=25.0f;
	terInput->heightMax=250.0f;
	terInput->detailTexRepeatCount=30.0f;
	terInput->detailTexMixtureRatio=0.4f;
	terInput->SeedCoeff=1.0f;
	terInput->RoughnessConst=0.5f;
	terInput->RandomRangeCoeff=0.5f;
	terInput->initFreq=0.004f;
	terInput->initAmpl=1.0f;
	terInput->initOcta=8;
	terInput->initPers=0.5f;
	terInput->doDrawLeafBBs=false;
	terInput->doSaveHeightMap=false;
	terInput->doLoadHeightMap=true;
	terInput->MaxGMMLevels=MAX_GEOMIPMAP_LEVELS;
	terInput->thetaValue=3.0f;
	strlength=strlen("heightmap.map");
	App::mem.AllocateMemory((void**)&terInput->hmSaveFile,strlength*sizeof(char));
	strcpy(terInput->hmSaveFile,"heightmap.map");
	strlength=strlen("heightmap.map");
	App::mem.AllocateMemory((void**)&terInput->hmLoadFile,strlength*sizeof(char));
	strcpy(terInput->hmLoadFile,"heightmap.map");

	App::mem.AllocateMemory((void**)&terInput->textures,textureCount*sizeof(ProceduralTextureInfo));
	terInput->texCount=textureCount;

	strlength=strlen("textures/dirt512.bmp");
	App::mem.AllocateMemory((void**)&terInput->textures[0].filePath,strlength*sizeof(char));
	strcpy(terInput->textures[0].filePath,"textures/dirt512.bmp");
	terInput->textures[0].weight=10;

	strlength=strlen("textures/grass512.bmp");
	App::mem.AllocateMemory((void**)&terInput->textures[1].filePath,strlength*sizeof(char));
	strcpy(terInput->textures[1].filePath,"textures/grass512.bmp");
	terInput->textures[1].weight=10;

	strlength=strlen("textures/rock512.bmp");
	App::mem.AllocateMemory((void**)&terInput->textures[2].filePath,strlength*sizeof(char));
	strcpy(terInput->textures[2].filePath,"textures/rock512.bmp");
	terInput->textures[2].weight=10;

	strlength=strlen("textures/snow512.bmp");
	App::mem.AllocateMemory((void**)&terInput->textures[3].filePath,strlength*sizeof(char));
	strcpy(terInput->textures[3].filePath,"textures/snow512.bmp");
	terInput->textures[3].weight=4;

	terInput->texWidth=1024;
	terInput->texHeight=1024;
	terInput->texMethod=Terrain::DETAIL_TEXTURING;
	terInput->numWidthVertices=TERRAIN_SIZE;
	terInput->numHeightVertices=TERRAIN_SIZE;
	terInput->QTDivisionCount=(int)( log((double)(TERRAIN_SIZE-1)/(double)QUADTREE_NODE_CELL_SIZE) / log(2.0) );

	camInput->speed=1.0f;
	camInput->CPosx=0.0;
	camInput->CPosy=300.0f;
	camInput->CPosz=0.0f;
	camInput->Lookx=0.0f;
	camInput->Looky=0.0f;
	camInput->Lookz=1.0;
	camInput->minHFromGround=4.0f;
	camInput->isFarDistConst=false;
	camInput->farDistance=7.0f;
	camInput->speedFactor=1.0f;
	camInput->rotationSpeed=1.0f;
	camInput->screenWidth=ScreenWidth;
	camInput->screenHeight=ScreenHeight;
	camInput->TerrainSizeX=(float)(terInput->numWidthVertices-1)*terInput->cellLength;
	camInput->TerrainSizeZ=(float)(terInput->numHeightVertices-1)*terInput->cellLength;
*/