/*****************************************************************************

	File: NaturePatch.cpp
	Desc: This class provides basic functionality of a terrain patch
	Date: 2003/02/27

	Author: Martin Persson

*****************************************************************************/

#include "ClipmapPatch.h"

#include <cmath>

//#define SINGLELEVEL 7
//#define MINLEVEL 9
//#define MAXLEVEL 10
#define MAXQUADS 512*256
// 256*256 is certainly not too much
namespace Ogre
{

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

unsigned int ClipmapPatch::mGenNameCount = 0;

bool ClipmapPatch::setMaterial(String materialName, SceneNode* mSceneRoot) {
#if USE_TEXTURES
		// get material
		mMaterial = mSceneRoot->getCreator()->getMaterial("ClipmapPatchMaterial");
		if (mMaterial != 0) MaterialManager::getSingleton().unload(mMaterial);

		mMaterial = mSceneRoot->getCreator()->createMaterial("ClipmapPatchMaterial");
	    
		TextureUnitState *layer;
		layer = mMaterial->getTechnique(0)->getPass(0)->createTextureUnitState(materialName, 0);

//	    layer = mMaterial->addTextureLayer(materialName, 0);
//    	layer->setColourOperation(LBO_REPLACE);

//		String detail_texture = config.getSetting("DetailTexture");
//		if (detail_texture != "")
//		{
//			layer = mMaterial->getTechnique(0)->getPass(0)->createTextureUnitState(detail_texture, 0);
//			layer->setTextureScale(0.2, 0.2);
//		}
//    }
#endif

	#if USE_NORMALS
		std::cout << "enabling light" << std::endl;
		mMaterial->setLightingEnabled(true);
	#endif

    mMaterial->load();
	
	return true;
}
            
bool ClipmapPatch::initialise(SceneNode *sceneRoot, HeightmapLoader* mapLoader) {
	std::cout << "Initializing masterpatch" << std::endl;
	mMapLoader = mapLoader;
	mSceneRoot  = sceneRoot;
	mScale = mapLoader->mScale;
	mWorld = mapLoader->mWorld;
	mQuadIndex = mapLoader->quadIndex;
	clipRegion = mapLoader->clipRegion;
	std::cout << "ClipRegion : " << clipRegion << std::endl;
	std::cout << "VertexSize : " << VERTEXSIZE << std::endl;
//	clipSize = mapLoader->clipSize;
	
	nbOfLevels = mQuadIndex->getDepth();
	
	if (clipRegions!=NULL){
		delete [] clipRegions;
	}
	clipRegions = new ClipmapRegion*[nbOfLevels];
	// Gets done somewhere else
	for (int i=0;i<nbOfLevels;i++){
		clipRegions[i]= NULL;
	}

	currentHighest=nbOfLevels-1;
	vertexsize = 3;
#if USE_NORMALS
	vertexsize += 3;
#endif
	
	std::cout << "generating rendering queue and landscape" << std::endl;
	createLandscape();
	generateRenderQueue();
	
    mMaterial = reinterpret_cast<Material*>
	(MaterialManager::getSingleton().getByName("BaseWhite"));
    
   	heightMapWidth = mapLoader->getMapSize();
	heightMapHeight = mapLoader->getMapSize();
    mBounds.setExtents(mWorld.x,
		       mWorld.y,
		       mWorld.z,
		       mWorld.x + heightMapWidth * mScale.x,
		       mWorld.y + 255 * mScale.y,	    // wrong
		       mWorld.z + heightMapHeight * mScale.z);
//	std::cout << "Width : " << heightMapWidth << ", height: " << heightMapHeight << std::endl;
//	std::cout << "Scale : " << mScale.x << "," << mScale.y << "," << mScale.z << std::endl;
//	std::cout << "Boundingbox : " << mBounds.getMinimum().x << "," << mBounds.getMinimum().y << "," << mBounds.getMinimum().z << "-" << mBounds.getMaximum().x << "," << mBounds.getMaximum().y << "," << mBounds.getMaximum().z << std::endl;
		  

//	std::cout << "Setting mInit" << std::endl;
	mInit = true;
//	std::cout << " mInit : " << mInit << std::endl;

	return true;
}

void ClipmapPatch::_notifyCurrentCamera(Camera *cam) {
	pcampos = campos;
	campos = cam->getPosition();
//	std::cout << "Camera at : " << campos.x << "," << campos.y << "," << campos.z << std::endl;
//	std::cout << "Camera at : " << campos.x << "," << campos.y << "," << campos.z << std::endl;
//	std::cout << "  vcount : " << "<->" << vertexoffset << std::endl;
//	std::cout << "  icount : " << "<->" << indexoffset << std::endl;
	
}


// I think this is PRETTY IMPORTANT!!!
void ClipmapPatch::getRenderOperation(RenderOperation& op)
{
//	std::cout << "Render operation" << std::endl;
//	std::cout << "#vertices : " << numVertices << std::endl;
//	std::cout << "#indices : " << mIndexCount << std::endl;
//	std::cout << "vertices : " << mVertexData << std::endl;
//	std::cout << "indices : " << mIndexData << std::endl;
	
	assert( mInit && "Uninitialized" );
	
    op.useIndexes = true;
    op.operationType = RenderOperation::OT_TRIANGLE_LIST;

    op.vertexData = mVertexData;
//    op.vertexData->vertexStart = 0;
 //   op.vertexData->vertexCount = vertexoffset/vertexsize;

    op.indexData = mIndexData;
//	std::cout << "indexbuffer at : " << &(mIndexData->indexBuffer) << std::endl;
//    op.indexData->indexStart = 0;
 //   op.indexData->indexCount = indexoffset;
//	std::cout << "vcount : " << op.vertexData->vertexCount << "<->" << vertexoffset;
//	std::cout << "icount : " << op.indexData->indexCount << "<->" << indexoffset;


	
//	std::cout << "Render operation end" << std::endl;
    //std::cerr << "index count = " << mIndexCount << std::endl;
    
    
}

void ClipmapPatch::clearData() {
//	std::cout << "Clearing data" << std::endl;
	if (vertices!=NULL){
		delete [] vertices;
	}
	if (indices!=NULL){
		delete [] indices;
	}
	if (mVertexData!=NULL){
		delete mVertexData;
	}
	if (mIndexData!=NULL){
		delete mIndexData;
	}
//	std::cout << "cleared" << std::endl;
}

void ClipmapPatch::createLandscape(){
	std::cout << "Creating landscape" << std::endl;
//	std::cout << "Clearing data" << std::endl;
//	clearData();

//	std::cout << "Initing vertices" << std::endl;
//	initVertices();
	numVertices=mQuadIndex->getDepth()*REGIONSURF;

	int i,j,k,l,x,y,z,b;

	Real* vertex = vertices;
	

	mVertexData = new VertexData();

	mVertexData->vertexStart = 0;
	mVertexData->vertexCount = numVertices;
	
	VertexDeclaration* vdecl = mVertexData->vertexDeclaration; 
	VertexBufferBinding* vbind = mVertexData->vertexBufferBinding;
	
    size_t offset = 0;
	vdecl->addElement(0, offset, VET_FLOAT3, VES_POSITION);
    offset += VertexElement::getTypeSize(VET_FLOAT3);
//	std::cout << "vet_float3size : " << VertexElement::getTypeSize(VET_FLOAT3) << std::endl;    
	
#if USE_NORMALS
    // normals
    vdecl->addElement(0, offset, VET_FLOAT3, VES_NORMAL);
    offset += VertexElement::getTypeSize(VET_FLOAT3);
#endif

#if USE_TEXTURES
    // texture coord sets
    vdecl->addElement(0, offset, VET_FLOAT2, VES_TEXTURE_COORDINATES, 0);
    offset += VertexElement::getTypeSize(VET_FLOAT2);
#endif


//	std::cout << "Getting data" << std::endl;

//	std::cout << "Preparing buffer for positions" << std::endl;
	// Prepare buffer for positions - todo: first attempt, slow
	posVertexBuffer = 
         HardwareBufferManager::getSingleton().createVertexBuffer( 
            offset, 
			numVertices, 
			HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY);
	vbind->setBinding(0, posVertexBuffer);


/*	
	posVertexBuffer->writeData(0, 
		posVertexBuffer->getSizeInBytes(), // size 
		vertices // source
		); // discard?
*/		

//	std::cout << "Writing data to index buffer" << std::endl;
//	std::cout << "Size : " << mIndexData->indexBuffer->getSizeInBytes() << std::endl;
//	std::cout << "Indices : ";
//	std::cout << std::endl;	
/*
    mIndexData->indexBuffer->writeData(0, 
        mIndexData->indexBuffer->getSizeInBytes(), indices);
*/
//	std::cout << "Creating landscape done" << std::endl;
}

void ClipmapPatch::getNormal(int x, int z, Vector3 *normal)
{   
    Vector3 here, left, down;
                
    here.x = x;
    here.y = pHeightMap[z * heightMapWidth + x]
        * mScale.y + mWorld.y;
    here.z = z;
    
    left.x = x - 1;
    if (x > 0)
        left.y = pHeightMap[z * heightMapWidth + (x - 1)]
            * mScale.y + mWorld.y;
    else
        left.y = here.y;

    left.z = z;

    down.x = x;
    if (z < heightMapWidth)
        down.y = pHeightMap[(z + 1) * heightMapWidth + x]
            * mScale.y + mWorld.y;
    else
        down.y = here.y;

    down.z = z + 1;

    left = left - here;
    down = down - here;

    left.normalise();
    down.normalise();

    *normal = left.crossProduct(down);
    normal->normalise();
}

void ClipmapPatch::initVertices(){
	int i;
	numVertices = 0;
	mIndexCount = 0;

#ifdef MINLEVEL
	for (i = MINLEVEL;i<MAXLEVEL;i++){
#else
	for (i = 0;i<nbOfLevels;i++){
#endif
		numVertices += clipRegions[i]->getVertexCount();
		mIndexCount += clipRegions[i]->getIndexCount();
	}
	
//	std::cout << "Reserving memory for " << numVertices << " vertices and " << mIndexCount << " indices" << std::endl;
	vertices = new Real[numVertices*vertexsize];

#if USE_16BIT_INDICES
	indices = new unsigned short[mIndexCount];
#else
	indices = new unsigned int[mIndexCount];
#endif

}

void ClipmapPatch::generateRenderQueue(){
//	std::cout << "Generating rendering queue" << std::endl;
	int i;
	if (mInit){		
//		std::cout << "Inited" << std::endl;
		Vector3 rpiq = getRelativePointInQuad(mQuadIndex->getQuad(0,0,0),&campos);
		Real t = rpiq.x;
		Real sqdist = sqrt(rpiq.y);
		Real s = rpiq.z;

//		minlevel=0;
		i=minlevel-1;
		if (i<0) i=0;
		int start = i;
//		nbOfLevels=8;
//		i=7;
		
//		std::cout << "nbOfLevels : " << nbOfLevels << std::endl;
		while(i < nbOfLevels){
//			std::cout << "updating region " << i << std::endl;
			int reallevel = i;
//			std::cout << "minlevel = " << minlevel << ", maxlevel = " << maxlevel << std::endl;
			int nbX = mQuadIndex->getLevelSize(reallevel);
			int nbZ = mQuadIndex->getLevelSize(reallevel);
			int sizeX = mQuadIndex->getLevelQuadSize(reallevel);
			int sizeZ = mQuadIndex->getLevelQuadSize(reallevel);
//			int centerx = ((int)(nbX * t));
//			int centerz = ((int)(nbZ * s));
			int centerx = (((int)(nbX * t+1))>>1)<<1;
			int centerz = (((int)(nbZ * s+1))>>1)<<1;
//			cout << "nbX " << nbX << " nbZ " << nbZ << std::endl;
//			cout << "t " << t << " s " << s << std::endl;
//			cout << "centerx " << centerx << " centerz " << centerz << std::endl;

//			int ncenterx = ((((int)(2*nbX * t+1))>>1));
//			int ncenterz = ((((int)(2*nbZ * s+1))>>1));

			// Is it too big, so we will have to use a higher detail region
//			std::cout << "TOOBIG " << (double)mQuadIndex->getLevelQuadSize(reallevel)*(double)REGIONSIZE / sqdist
//					 << " clipRegion " << clipRegion << " : " << i << std::endl;

			//Calculate the translation of the camera in number of squares
			int movex = (int)(centerx-clipRegions[i]->centerx);
			int movez = (int)(centerz-clipRegions[i]->centerz);
//			std::cout << "movex : " << movex << " movez : " << movez << std::endl;

#define TOOBIG ((double)mQuadIndex->getLevelQuadSize(reallevel)*(double)REGIONSIZE / sqdist > clipRegion)&&(i!=nbOfLevels-1)

			
			if (TOOBIG)
			{
//				std::cout << "Region " << i << " with hole" << std::endl;
				//Yes, we will have to leave a hole for the higher detail region

				if (i>=minlevel) {
					if ((i==0)||(clipRegions[i-1]->isTooBig())){
//						std::cout << "Region " << i-1 << " became invisible" << std::endl;
						minlevel = i;
					} else {
						if (i>0){
							if (i-1==start){
								minlevel = i-1;
								i-=2;
								if (i<0) i=0;
								start--;
							}
						}
					}
				}
			} else {
				//No, this is the highest needed lod.
//				std::cout << "Region " << i << " without hole" << std::endl;
				
				//Is this the same maximum level region as previous frame?
//				if(i < maxlevel) {
					//No, it is of coarser detail, we have to close the hole
//					std::cout << "Closing hole" << std::endl;
					clipRegions[i]->closeHole();
//					std::cout << "minlevel " << minlevel << " maxelevel " << maxlevel << std::endl;
//				} else {
//					std::cout << "minlevel " << minlevel << " maxelevel " << maxlevel << std::endl;
//				}
				maxlevel = i;
			}

			//Translate the region
			clipRegions[i]->move(movex,E);
			clipRegions[i]->move(movez,S);
			clipRegions[i]->updateVertices(movex,E);
			clipRegions[i]->updateVertices(movez,S);

			if (i>0){
//				if (clipRegions[i-1]->hasHole()){
//					//We have a hole, so we can just move it
//					clipRegions[i-1]->moveHole(movex>>1,E);
//					clipRegions[i-1]->moveHole(movez>>1,S);
//				} else {
					// We don't have a hole in the previous level. We 
					// need to create it.
//					std::cout << "setting hole of " << i-1 << std::endl;
//					std::cout << "innerUpperLeftQuad " << (clipRegions[i]->getUpperLeftQuad().x>>1) << "," << (clipRegions[i]->getUpperLeftQuad().y>>1) << "," << i-1 << std::endl;
//					std::cout << "innerLowerRightQuad " << (clipRegions[i]->getLowerRightQuad().x>>1) << "," << (clipRegions[i]->getLowerRightQuad().y>>1) << "," << i-1 << std::endl;
					clipRegions[i-1]->setInnerUpperLeftQuad(Vector3ix(clipRegions[i]->getUpperLeftQuad().x>>1,clipRegions[i]->getUpperLeftQuad().y>>1,i-1));
					clipRegions[i-1]->setInnerLowerRightQuad(Vector3ix(clipRegions[i]->getLowerRightQuad().x>>1,clipRegions[i]->getLowerRightQuad().y>>1,i-1));
//				}
			}
			
//			if (i>0){
//				std::cout << "reformed(i-1) innerUpperLeftQuad " << clipRegions[i-1]->getInnerUpperLeftQuad().x*2 << "," << clipRegions[i-1]->getInnerUpperLeftQuad().y*2 << std::endl;
//				std::cout << "reformed(i-1) innerLowerRightQuad " << clipRegions[i-1]->getInnerLowerRightQuad().x*2+1 << "," << clipRegions[i-1]->getInnerLowerRightQuad().y*2+1 << std::endl;
//			}
//			if (i<nbOfLevels){
//				std::cout << "i " << i << " clipRegions[i] " << clipRegions[i] << std::endl;
//				std::cout << "upperLeftQuad " << clipRegions[i]->getUpperLeftQuad().x << "," << clipRegions[i]->getUpperLeftQuad().y << std::endl;
//				std::cout << "lowerRightQuad " << clipRegions[i]->getLowerRightQuad().x << "," << clipRegions[i]->getLowerRightQuad().y << std::endl;
//				std::cout << "innerUpperLeftQuad " << clipRegions[i]->getInnerUpperLeftQuad().x << "," << clipRegions[i]->getInnerUpperLeftQuad().y << std::endl;
//				std::cout << "innerLowerRightQuad " << clipRegions[i]->getInnerLowerRightQuad().x << "," << clipRegions[i]->getInnerLowerRightQuad().y << std::endl;
//			}

			if (!TOOBIG)					
			{
				i=nbOfLevels;
			}
			
			i++;
//			std::cout << "Region update done: minlevel = " << minlevel << ", maxlevel = " << maxlevel << std::endl;			
		}

	} else {
		//Not yet initialized

		Vector3 rpiq = getRelativePointInQuad(mQuadIndex->getQuad(0,0,0),&campos);
		Real t = rpiq.x;
		Real sqdist = sqrt(rpiq.y);
		Real s = rpiq.z;
		
		i=0;
		// check for every level
		minlevel=i;
		maxlevel=-1;
		while((i<nbOfLevels)&&(maxlevel==-1)){
			std::cout << "Creating level " << i << std::endl;
			int reallevel = i;
			// Get the number of quads in this level
			int nbX = mQuadIndex->getLevelSize(reallevel);
			int nbZ = mQuadIndex->getLevelSize(reallevel);

			// Clean up the region if necessary
			if (clipRegions[i] != NULL) {
				delete clipRegions[i];
			}
			
			int centerx = (((int)(nbX * t+1))>>1)<<1;
			int centerz = (((int)(nbZ * s+1))>>1)<<1;

			// The corners of the patch
			int leftx = centerx-(REGIONSIZE/2);
			int topz = centerz-(REGIONSIZE/2);
			int rightx = centerx+(REGIONSIZE/2)-1;
			int bottomz = centerz+(REGIONSIZE/2)-1;

			if (leftx<0) leftx=0;
			if (leftx>=mQuadIndex->getLevelSize(reallevel)) leftx=mQuadIndex->getLevelSize(reallevel)-1;
			if (rightx<0) rightx=0;
			if (rightx>=mQuadIndex->getLevelSize(reallevel)) rightx=mQuadIndex->getLevelSize(reallevel)-1;
			if (topz<0) topz=0;
			if (topz>=mQuadIndex->getLevelSize(reallevel)) topz=mQuadIndex->getLevelSize(reallevel)-1;
			if (bottomz<0) bottomz=0;
			if (bottomz>=mQuadIndex->getLevelSize(reallevel)) bottomz=mQuadIndex->getLevelSize(reallevel)-1;

			int pleftx = leftx>>1;
			int ptopz = topz>>1;
			int prightx = rightx>>1;
			int pbottomz = bottomz>>1;

			if ((i>0)){
//				std::cout << "Creating hole in previous level" << std::endl;
				clipRegions[i-1]->setInnerUpperLeftQuad(Vector3ix(pleftx,ptopz,reallevel-1));
				clipRegions[i-1]->setInnerLowerRightQuad(Vector3ix(prightx,pbottomz,reallevel-1));
//				std::cout << "reformed(i-1) innerUpperLeftQuad " << clipRegions[i-1]->getInnerUpperLeftQuad().x*2 << "," << clipRegions[i-1]->getInnerUpperLeftQuad().y*2 << std::endl;
//				std::cout << "reformed(i-1) innerLowerRightQuad " << clipRegions[i-1]->getInnerLowerRightQuad().x*2+1 << "," << clipRegions[i-1]->getInnerLowerRightQuad().y*2+1 << std::endl;
			}


			// Is it too big, so we will have to use a higher detail region and
			// is this not the maximum detail we have available?
				if (TOOBIG)
				{
//					std::cout << "level " << i << " is visible" << std::endl;
					
					if ((i>0)&&(clipRegions[i-1]->isTooBig())){
//						std::cout << "level " << i-1 << " became invisible" << std::endl;
						minlevel=i;
					}
					
				} else {
					//No, this is as fine as we need
//					std::cout << "level " << i << " is without hole visible" << std::endl;
	
					maxlevel = i;
				}
//			std::cout << "centerx " << centerx << ", centerz " << centerz << std::endl;
//			std::cout << "leftx " << leftx << ", topz " << topz << ", rightx " << rightx << ", bottomz " << bottomz << std::endl;
//			std::cout << "pleftx " << pleftx << ", ptopz " << ptopz << ", prightx " << prightx << ", pbottomz " << pbottomz << std::endl;

			ClipmapRegion* region;
			if (i>0){
				region = clipRegions[i-1];
			} else {
				region = 0;
			}
			clipRegions[i] = new ClipmapRegion(Vector3ix(leftx,topz,reallevel),
												Vector3ix(rightx,bottomz,reallevel),
												Vector3ix(centerx,centerz,reallevel),
												Vector3ix(centerx-1,centerz-1,reallevel),
												mQuadIndex,
												posVertexBuffer,
												indexBuffer,
												clipRegions[i-1],
												reallevel*REGIONSURF);
			clipRegions[i]->centerx = centerx;
			clipRegions[i]->centerz = centerz;
//			std::cout << "minlevel " << minlevel << " maxlevel " << maxlevel << std::endl;

			i++;			
		}
		//Initialize the other levels to some default value
		while (i<nbOfLevels){
//			std::cout << "Precreating level " << i << std::endl;

			int reallevel = i;
			// Get the number of quads in this level
			int nbX = mQuadIndex->getLevelSize(reallevel);
			int nbZ = mQuadIndex->getLevelSize(reallevel);

			// Clean up the region if necessary
			if (clipRegions[i] != NULL) {
				delete clipRegions[i];
			}
			
			int centerx = (((int)(nbX * t+1))>>1)<<1;
			int centerz = (((int)(nbZ * s+1))>>1)<<1;

			int ncenterx = ((((int)(2*nbX * t+1))>>1));
			int ncenterz = ((((int)(2*nbZ * s+1))>>1));
			
			// The corners of the patch
			int leftx = centerx-(REGIONSIZE/2);
			int topz = centerz-(REGIONSIZE/2);
			int rightx = centerx+(REGIONSIZE/2)-1;
			int bottomz = centerz+(REGIONSIZE/2)-1;

			if (leftx<0) leftx=0;
			if (leftx>=mQuadIndex->getLevelSize(reallevel)) leftx=mQuadIndex->getLevelSize(reallevel)-1;
			if (rightx<0) rightx=0;
			if (rightx>=mQuadIndex->getLevelSize(reallevel)) rightx=mQuadIndex->getLevelSize(reallevel)-1;
			if (topz<0) topz=0;
			if (topz>=mQuadIndex->getLevelSize(reallevel)) topz=mQuadIndex->getLevelSize(reallevel)-1;
			if (bottomz<0) bottomz=0;
			if (bottomz>=mQuadIndex->getLevelSize(reallevel)) bottomz=mQuadIndex->getLevelSize(reallevel)-1;

			int pleftx = leftx>>1;
			int ptopz = topz>>1;
			int prightx = rightx>>1;
			int pbottomz = bottomz>>1;

//			std::cout << "centerx " << centerx << ", centerz " << centerz << std::endl;
//			std::cout << "ncenterx " << ncenterx << ", ncenterz " << ncenterz << std::endl;
//			std::cout << "leftx " << leftx << ", topz " << topz << ", rightx " << rightx << ", bottomz " << bottomz << std::endl;
//			std::cout << "pleftx " << pleftx << ", ptopz " << ptopz << ", prightx " << prightx << ", pbottomz " << pbottomz << std::endl;
			ClipmapRegion* region;
			if (i>0){
				region = clipRegions[i-1];
			} else {
				region = 0;
			}
			clipRegions[i] = new ClipmapRegion(Vector3ix(leftx,topz,reallevel),
												Vector3ix(rightx,bottomz,reallevel),
												Vector3ix(centerx,centerz,reallevel),
												Vector3ix(centerx-1,centerz-1,reallevel),
												mQuadIndex,
												posVertexBuffer,
												indexBuffer,
												clipRegions[i-1],
												reallevel*REGIONSURF);
			clipRegions[i]->centerx = centerx;
			clipRegions[i]->centerz = centerz;

			i++;			



		}
	}
	
	int mIndexCount=0, tot=0;
//	maxlevel=11;
//	minlevel=;
//	std::cout << "minlevel " << minlevel << " maxlevel " << maxlevel << std::endl;
	for (i=maxlevel;i>=minlevel;i--){
//		std::cout << "Get count from level " << i << std::endl;
		mIndexCount+=clipRegions[i]->getIndexCount();
	}
//	std::cout << "Got " << mIndexCount << " indices" << std::endl;

	if (mIndexData!=0){
		delete mIndexData;
	}
    mIndexData = new IndexData();
    mIndexData->indexStart = 0;
    mIndexData->indexCount = mIndexCount;    

	indexBuffer = 
		HardwareBufferManager::getSingleton().createIndexBuffer(
#if USE_16BIT_INDICES
			HardwareIndexBuffer::IT_16BIT, 
#else
			HardwareIndexBuffer::IT_32BIT, 
#endif
			mIndexCount, 
			HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY);			
	mIndexData->indexBuffer = indexBuffer;
	
	

	for (i=maxlevel;i>=minlevel;i--){
//		std::cout << "Getting data from level " << i << std::endl;
		clipRegions[i]->setIndexBuffer(indexBuffer);
		if (!mInit){
			clipRegions[i]->updateVertexBuffer();
		}
		tot+=clipRegions[i]->updateIndexBuffer(tot);
	}
//	for (i=maxlevel;i>=minlevel;i--){
//		clipRegions[i]->updateVertices();
//	}
//	std::cout << "Done" << std::endl;
	mInit = true;
}

Vector3 ClipmapPatch::getPointInQuad(Quad* quad, Vector3* point){
		Vector3* coor = new Vector3();
//		std::cout << "Getting coordinate of big quad" << std::endl;
		quad->getVertexCoordinates(0, coor);
		Vector3 relative;
		// This would be good enough (even overkill) for a planar version
		// but, we want to be able to build a 3D version of it
		relative = *(coor)-*(point);
		
		// Get the corners of our landscape to do some calculations
		// Maybe we should make this landscape flat before working with it?
//		std::cout << "Getting the corners of our landscape" << std::endl;
		Vector3* p0 = new Vector3();
		quad->getVertexCoordinates(0, p0);
//		std::cout << "Coord 0 done = c " << p0->x << "," << p0->y << "," << p0->z << std::endl;
		Vector3* p1 = new Vector3();
		quad->getVertexCoordinates(2, p1);
//		std::cout << "Coord 1 done " << p1->x << "," << p1->y << "," << p1->z << std::endl;
		Vector3* p2 = new Vector3();
		quad->getVertexCoordinates(1, p2);
//		std::cout << "Coord 2 done " << p2->x << "," << p2->y << "," << p2->z << std::endl;

		// Calculate the projection of the camera in the plane
//		std::cout << "Calculating the projection of the camera in the plane" << std::endl;
		Vector3 a = (*p0 - *p1).crossProduct(*p0 - *p2);
		a.normalise();
//		std::cout << "a = n " << a.x << "," << a.y << "," << a.z << std::endl;
		Vector3 b = *(point);
//		std::cout << "campos = b " << b.x << "," << b.y << "," << b.z << std::endl;
		Vector3 n = a;
		Vector3 c = *p0;
//				Real tt = ((c-a).dotProduct(n))/((b-a).dotProduct(n));
		Real tt = ((b.dotProduct(n)/a.dotProduct(n)));
//		std::cout << "tt " << tt << std::endl;
		delete p0, p1, p2, coor;
		return b - (a)*tt;	
}

Vector3 ClipmapPatch::getRelativePointInQuad(Quad* quad, Vector3* point){
		Vector3 r = getPointInQuad(quad, point);
//		std::cout << "Getting the corners of our landscape" << std::endl;
		Vector3* p0 = new Vector3();
		quad->getVertexCoordinates(0, p0);
//		std::cout << "Coord 0 done = c " << p0->x << "," << p0->y << "," << p0->z << std::endl;
		Vector3* p1 = new Vector3();
		quad->getVertexCoordinates(2, p1);
//		std::cout << "Coord 1 done " << p1->x << "," << p1->y << "," << p1->z << std::endl;
		Vector3* p2 = new Vector3();
		quad->getVertexCoordinates(1, p2);
//		std::cout << "Coord 2 done " << p2->x << "," << p2->y << "," << p2->z << std::endl;

		Vector3 u = *p1 - *p0;
//		std::cout << "u " << u.x << "," << u.y << "," << u.z << std::endl;
		Vector3 v = *p2 - *p0;
//		std::cout << "v " << v.x << "," << v.y << "," << v.z << std::endl;
		Vector3 w = r - *p0;
//		std::cout << "w " << w.x << "," << w.y << "," << w.z << std::endl;
	
		Real sqdist = (r - *(point)).squaredLength();
//		std::cout << "sqdist " << sqdist << std::endl;
		
		Real s = ((u.dotProduct(v)*w.dotProduct(v))-(v.dotProduct(v)*w.dotProduct(u))) 
				/ ((u.dotProduct(v)*u.dotProduct(v))-(u.dotProduct(u)*v.dotProduct(v)));
//		std::cout << "s " << s << std::endl;
		Real t = ((u.dotProduct(v)*w.dotProduct(u))-(u.dotProduct(u)*w.dotProduct(v))) 
				/ ((u.dotProduct(v)*u.dotProduct(v))-(u.dotProduct(u)*v.dotProduct(v)));
//		std::cout << "t " << t << std::endl;
		
		Vector3 rel;
		rel.x = t;
		rel.y = sqdist;
		rel.z = s;
		delete p0, p1, p2;
		return rel;
}
//----------------------------------------------------------------------------

}
