#include "ClipmapRegion.h"

namespace Ogre {

	ClipmapRegion::ClipmapRegion(Vector3ix upperLeftQuad,Vector3ix lowerRightQuad, 
		Vector3ix innerUpperLeftQuad, Vector3ix innerLowerRightQuad,
		SeperateCubemappedPlanetReader* geometryReader,
		HardwareVertexBufferSharedPtr &vertexBuffer,
		ClipmapRegion* previousRegion,
		int map,
		int vertexOffset)
	{
		this->upperLeftQuad = upperLeftQuad;
		this->lowerRightQuad = lowerRightQuad;
		this->innerUpperLeftQuad = innerUpperLeftQuad;
		this->innerLowerRightQuad = innerLowerRightQuad;
		this->vertexBuffer = vertexBuffer;
		changed = true;
		mMap = map;
		setGeometryReader(geometryReader);
		initializeVertices();
		this->vertexOffset=vertexOffset;
		this->previousRegion = previousRegion;
		xmove=0;
		ymove=0;
	}


	ClipmapRegion::~ClipmapRegion()
	{
	}

	/**
	* Adds a collumn or row to the region. May overwrite a previous written one
	* on the other side of the region
	*/
	int ClipmapRegion::addExteriorRows(int amount, int direction){
		int i=0;
		if (amount > 0){
			switch (direction) {
			case LEFT : 
				while (isTooSmallOnLeft() && upperLeftQuad.x>0){
					startOffset=(startOffset-(REGIONSIZE+1)+REGIONSURF)%REGIONSURF;
					addCollumn(startOffset,upperLeftQuad.x-1,upperLeftQuad.y);
					upperLeftQuad = upperLeftQuad.getLeft();
					i++;
				}
				while (isTooBigOnRight() && lowerRightQuad.x>=0) {
					lowerRightQuad = lowerRightQuad.getLeft();
					endOffset=(endOffset+REGIONSURF-(REGIONSIZE+1))%REGIONSURF;
				}		
				break;
			case RIGHT : 
				while (isTooSmallOnRight() && lowerRightQuad.x<getLevelSize(upperLeftQuad.z)-1){
					endOffset=(endOffset+(REGIONSIZE+1))%REGIONSURF;
					addCollumn((endOffset-(lowerRightQuad.y-upperLeftQuad.y+1)+REGIONSURF)%REGIONSURF,lowerRightQuad.x+2,upperLeftQuad.y);
					lowerRightQuad = lowerRightQuad.getRight();
					i++;
				}
				while (isTooBigOnLeft() && upperLeftQuad.x<getLevelSize(upperLeftQuad.z)) {
					upperLeftQuad = upperLeftQuad.getRight();
					startOffset=(startOffset+(REGIONSIZE+1))%REGIONSURF;
				}
				break;
			case UP : 
				while (isTooSmallOnUp() && upperLeftQuad.y>0){
					startOffset=(startOffset+REGIONSURF-1)%REGIONSURF;
					addRow(startOffset,upperLeftQuad.x,upperLeftQuad.y-1);
					upperLeftQuad = upperLeftQuad.getTop();
					i++;
				}
				while (isTooBigOnDown() && lowerRightQuad.y>=0) {
					lowerRightQuad = lowerRightQuad.getTop();
					endOffset=(endOffset+REGIONSURF-1)%REGIONSURF;
				}
				break;
			case DOWN : 
				while (isTooSmallOnDown() && lowerRightQuad.y<getLevelSize(upperLeftQuad.z)-1){
					endOffset=(endOffset+1)%REGIONSURF;
					addRow((endOffset-(REGIONSIZE+1)*(lowerRightQuad.x-upperLeftQuad.x+1)+REGIONSURF)%REGIONSURF,upperLeftQuad.x,lowerRightQuad.y+2);
					lowerRightQuad = lowerRightQuad.getBottom();
					i++;
				}
				while (isTooBigOnUp() && upperLeftQuad.y<getLevelSize(upperLeftQuad.z)) {
					upperLeftQuad = upperLeftQuad.getBottom();
					startOffset=(startOffset+1)%REGIONSURF;
				}
				break;
			}
			if (i>0){
				changed = true;
			}
			return i;
		} else if (amount < 0) {
			removeExteriorRows(-amount,direction);
			return 0;
		} 
		return 0;
	}

	/**
	* Adds a collumn of vertices to the vertexBuffer
	*/
	void ClipmapRegion::addCollumn(int offset,int startx,int starty){	
		// The number of of quads to be added
		int number = lowerRightQuad.y - upperLeftQuad.y+2;
		int i, pos;
		for (i=0; i<number;i++){
			Vertex* vertex = mGeometryReader->getVertex(startx,starty+i,upperLeftQuad.z, mMap);
			Vector3 position = vertex->getVertex();
#if USE_NORMALS
			Vector3 normal = vertex->getNormal();
#endif
#if USE_TEXTURES
			Real tx,ty;
			vertex->fillTextureCoordinates(tx,ty);
#endif
			pos = ((i+offset)%REGIONSURF)*VERTEXSIZE;
			vertices[pos++] = position.x;
			vertices[pos++] = position.y;
			vertices[pos++] = position.z;
#if USE_NORMALS
			vertices[pos++] = normal.x;
			vertices[pos++] = normal.y;
			vertices[pos++] = normal.z;
#endif
#if USE_TEXTURES
			vertices[pos++] = tx;
			vertices[pos++] = ty;
#endif

		}
		changed = true;
	}

	void ClipmapRegion::blendN(int left, int right, Real* vertices, int amountOver){
		int pos;
		int i,j;
		for (j=0;j<TRANSITIONSIZE(getHeight());j++){
			Real alpha = calculateAlphaY(j+amountOver);
			for (i=left;i<right;i++){
				pos = getVertexPosition(i,j)-(vertexOffset+patchOffset);
#if USE_NORMALS					
				setVertex(pos,blendVertex(i,j, alpha), blendNormal(i,j, alpha), vertices);
#else
				setVertex(pos,blendVertex(i,j, alpha), vertices);
#endif
			}
		}
	}

	void ClipmapRegion::blendS(int left, int right, Real* vertices, int amountOver){
		int pos;
		int i,j;
		for (j=getHeight()-TRANSITIONSIZE(getHeight())+1;j<getHeight()+1;j++){
			Real alpha = calculateAlphaY(j-amountOver);
			for (i=left;i<right;i++){
				pos = getVertexPosition(i,j)-(vertexOffset+patchOffset);
#if USE_NORMALS					
				setVertex(pos,blendVertex(i,j, alpha), blendNormal(i,j, alpha), vertices);
#else
				setVertex(pos,blendVertex(i,j, alpha), vertices);
#endif
			}
		}
	}
	void ClipmapRegion::blendE(int top, int bottom, Real* vertices, int amountOver){
		int pos;
		int i,j;
		for (i=getWidth()-TRANSITIONSIZE(getWidth())+1;i<getWidth()+1;i++){
			Real alpha = calculateAlphaX(i-amountOver);
			for (j=top;j<bottom;j++){
				pos = getVertexPosition(i,j)-(vertexOffset+patchOffset);
#if USE_NORMALS					
				setVertex(pos,blendVertex(i,j, alpha), blendNormal(i,j, alpha), vertices);
#else
				setVertex(pos,blendVertex(i,j, alpha), vertices);
#endif
			}
		}
	}
	void ClipmapRegion::blendW(int top, int bottom, Real* vertices, int amountOver){
		int pos;
		int i,j;
		for (i=0;i<TRANSITIONSIZE(getWidth());i++){
			Real alpha = calculateAlphaX(i+amountOver);
			for (j=top;j<bottom;j++){
				pos = getVertexPosition(i,j)-(vertexOffset+patchOffset);
#if USE_NORMALS					
				setVertex(pos,blendVertex(i,j, alpha), blendNormal(i,j, alpha), vertices);
#else
				setVertex(pos,blendVertex(i,j, alpha), vertices);
#endif
			}
		}
	}
	void ClipmapRegion::blendNE(Real* vertices, int amountOverX, int amountOverY){
		int pos;
		int i,j;
		for (j=0;j<TRANSITIONSIZE(getHeight());j++){
			Real alphay = calculateAlphaY(j+amountOverY);
			for (i=getWidth()+1-TRANSITIONSIZE(getWidth());i<getWidth()+1;i++){
				Real alphax = calculateAlphaX(i-amountOverX);
				Real alpha = std::max(alphax,alphay);
				pos = getVertexPosition(i,j)-(vertexOffset+patchOffset);
#if USE_NORMALS					
				setVertex(pos,blendVertex(i,j, alpha), blendNormal(i,j, alpha), vertices);
#else
				setVertex(pos,blendVertex(i,j, alpha), vertices);
#endif
			}
		}
	}
	void ClipmapRegion::blendNW(Real* vertices, int amountOverX, int amountOverY){
		int pos;
		int i,j;
		for (j=0;j<TRANSITIONSIZE(getHeight());j++){
			Real alphay = calculateAlphaY(j+amountOverY);
			for (i=0;i<TRANSITIONSIZE(getWidth());i++){
				Real alphax = calculateAlphaX(i+amountOverX);
				Real alpha = std::max(alphax,alphay);
				pos = getVertexPosition(i,j)-(vertexOffset+patchOffset);
#if USE_NORMALS					
				setVertex(pos,blendVertex(i,j, alpha), blendNormal(i,j, alpha), vertices);
#else
				setVertex(pos,blendVertex(i,j, alpha), vertices);
#endif
			}
		}
	}
	void ClipmapRegion::blendSE(Real* vertices, int amountOverX, int amountOverY){
		int pos;
		int i,j;
		for (j=getHeight()+1-TRANSITIONSIZE(getHeight());j<getHeight()+1;j++){
			Real alphay = calculateAlphaY(j-amountOverY);
			for (i=getWidth()+1-TRANSITIONSIZE(getWidth());i<getWidth()+1;i++){
				Real alphax = calculateAlphaX(i-amountOverX);
				Real alpha = std::max(alphax,alphay);
				pos = getVertexPosition(i,j)-(vertexOffset+patchOffset);
#if USE_NORMALS					
				setVertex(pos,blendVertex(i,j, alpha), blendNormal(i,j, alpha), vertices);
#else
				setVertex(pos,blendVertex(i,j, alpha), vertices);
#endif
			}
		}
	}
	void ClipmapRegion::blendSW(Real* vertices, int amountOverX, int amountOverY){
		int pos;
		int i,j;
		for (j=getHeight()+1-TRANSITIONSIZE(getHeight());j<getHeight()+1;j++){
			Real alphay = calculateAlphaY(j-amountOverY);
			for (i=0;i<TRANSITIONSIZE(getWidth());i++){
				Real alphax = calculateAlphaX(i+amountOverX);
				Real alpha = std::max(alphax,alphay);
				pos = getVertexPosition(i,j)-(vertexOffset+patchOffset);
#if USE_NORMALS					
				setVertex(pos,blendVertex(i,j, alpha), blendNormal(i,j, alpha), vertices);
#else
				setVertex(pos,blendVertex(i,j, alpha), vertices);
#endif
			}
		}
	}
	void ClipmapRegion::commitBlock(int x1,int y1, int x2, int y2, Real* vertices){
		int pos;
		int i,j;
		for (j=y1;j<y2;j++){
			for (i=x1;i<x2;i++){
				pos = getVertexPosition(i,j)-(vertexOffset+patchOffset);
				commitVertex(pos, vertices);
			}
		}
	}

	void ClipmapRegion::commitVertical(int start, int end, Real* vertices){
		int swidth = 0;
		int ewidth = TRANSITIONSIZE(getHeight());
		if (hasBorderRegionOnUp()){
			int amountOverY = std::max(0,getAmountOverEdge(UP));
			blendN(start,end,vertices,amountOverY);
		} else {
			commitBlock(start,swidth,end,ewidth,vertices);
		}

		swidth=ewidth;
		ewidth=getHeight()+1-TRANSITIONSIZE(getHeight());
		commitBlock(start,swidth,end,ewidth,vertices);

		if (hasBorderRegionOnDown()){
			int amountOverY = std::max(0,getAmountOverEdge(DOWN));
			blendS(start,end,vertices,amountOverY);
		} else {
			swidth=ewidth;
			ewidth=getHeight()+1;
			commitBlock(start,swidth,end,ewidth,vertices);
		}
	}
	void ClipmapRegion::commitHorizontal(int start, int end, Real* vertices){
		int swidth = 0;
		int ewidth = TRANSITIONSIZE(getWidth());
		if (hasBorderRegionOnLeft()){
			int amountOverX = std::max(0,getAmountOverEdge(LEFT));
			blendW(start,end,vertices,amountOverX);
		} else {
			commitBlock(swidth,start,ewidth,end,vertices);
		}

		swidth=ewidth;
		ewidth=getWidth()+1-TRANSITIONSIZE(getWidth());
		commitBlock(swidth,start,ewidth,end,vertices);

		if (hasBorderRegionOnRight()){
			int amountOverX = std::max(0,getAmountOverEdge(LEFT));
			blendE(start,end,vertices,amountOverX);
		} else {
			swidth=ewidth;
			ewidth=getWidth()+1;
			commitBlock(swidth,start,ewidth,end,vertices);
		}
	}
	void ClipmapRegion::commitLeft(int amount, Real* vertices){
		int start = TRANSITIONSIZE(getWidth());
		int end = std::min(TRANSITIONSIZE(getWidth())+amount,getWidth()+1);
		commitVertical(start,end,vertices);
	}
	void ClipmapRegion::commitRight(int amount, Real* vertices){
		int start = getWidth()+1-std::min(TRANSITIONSIZE(getWidth())+amount,getWidth()+1);
		int end = getWidth()+1-TRANSITIONSIZE(getWidth());
		commitVertical(start,end,vertices);
	}
	void ClipmapRegion::commitTop(int amount, Real* vertices){
		int start = TRANSITIONSIZE(getHeight());
		int end = std::min(TRANSITIONSIZE(getHeight())+amount,getHeight()+1);
		commitHorizontal(start,end,vertices);
	}
	void ClipmapRegion::commitBottom(int amount, Real* vertices){
		int start = getHeight()+1-std::min(TRANSITIONSIZE(getHeight())+amount,getHeight()+1);
		int end = getHeight()+1-TRANSITIONSIZE(getHeight());
		commitHorizontal(start,end,vertices);
	}

	void ClipmapRegion::updateLeft(Real* vertices){

		int amountOver = std::max(0,getAmountOverEdge(LEFT));
		int swidth = 0;
		int ewidth = TRANSITIONSIZE(getHeight());
		if (hasBorderRegionOnUp()){
			int amountOverY = std::max(0,getAmountOverEdge(UP));
			blendNW(vertices,amountOver,amountOverY);
		} else {
			blendW(swidth,ewidth,vertices,amountOver);
		}

		swidth = ewidth;
		ewidth = getHeight()+1-TRANSITIONSIZE(getHeight());
		blendW(swidth,ewidth,vertices,amountOver);

		if (hasBorderRegionOnDown()){
			int amountOverY = std::max(0,getAmountOverEdge(DOWN));
			blendSW(vertices,amountOver,amountOverY);
		} else {
			swidth = ewidth;
			ewidth = getHeight()+1;
			blendW(swidth,ewidth,vertices,amountOver);
		}

	}

	void ClipmapRegion::updateRight(Real* vertices){
		int amountOver = std::max(0,getAmountOverEdge(RIGHT));
		int swidth = 0;
		int ewidth = TRANSITIONSIZE(getHeight());
		if (hasBorderRegionOnUp()){
			int amountOverY = std::max(0,getAmountOverEdge(UP));
			blendNE(vertices,amountOver,amountOverY);
		} else {
			blendE(swidth,ewidth,vertices,amountOver);
		}

		swidth = ewidth;
		ewidth = getHeight()+1-TRANSITIONSIZE(getHeight());
		blendE(swidth,ewidth,vertices,amountOver);

		if (hasBorderRegionOnDown()){
			int amountOverY = std::max(0,getAmountOverEdge(DOWN));
			blendSE(vertices,amountOver,amountOverY);
		} else {
			swidth = ewidth;
			ewidth = getHeight()+1;
			blendE(swidth,ewidth,vertices,amountOver);
		}
	}


	void ClipmapRegion::updateTop(Real* vertices){
		int amountOver = std::max(0,getAmountOverEdge(UP));
		int swidth = 0;
		int ewidth = TRANSITIONSIZE(getWidth());
		if (hasBorderRegionOnLeft()){
			int amountOverX = std::max(0,getAmountOverEdge(LEFT));
			blendNW(vertices,amountOverX,amountOver);
		} else {
			blendN(swidth,ewidth,vertices,amountOver);
		}

		swidth = ewidth;
		ewidth = getWidth()+1-TRANSITIONSIZE(getWidth());
		blendN(swidth,ewidth,vertices,amountOver);

		if (hasBorderRegionOnRight()){
			int amountOverX = std::max(0,getAmountOverEdge(RIGHT));
			blendNE(vertices,amountOverX,amountOver);
		} else {
			swidth = ewidth;
			ewidth = getWidth()+1;
			blendN(swidth,ewidth,vertices,amountOver);
		}
	}

	void ClipmapRegion::updateBottom(Real* vertices){
		int amountOver = std::max(0,getAmountOverEdge(DOWN));
		int swidth = 0;
		int ewidth = TRANSITIONSIZE(getWidth());
		if (hasBorderRegionOnLeft()){
			int amountOverX = std::max(0,getAmountOverEdge(LEFT));
			blendSW(vertices,amountOverX,amountOver);
		} else {
			blendS(swidth,ewidth,vertices,amountOver);
		}

		swidth = ewidth;
		ewidth = getWidth()+1-TRANSITIONSIZE(getWidth());
		blendS(swidth,ewidth,vertices,amountOver);

		if (hasBorderRegionOnRight()){
			int amountOverX = std::max(0,getAmountOverEdge(RIGHT));
			blendSE(vertices,amountOverX,amountOver);
		} else {
			swidth = ewidth;
			ewidth = getWidth()+1;
			blendS(swidth,ewidth,vertices,amountOver);
		}
	}
	/**
	* Updates the vertices in the transition zone.
	*/
	void ClipmapRegion::updateTransition(int amount, int direction){
		if (amount>0)
		{
			Real* vertices = (Real*)vertexBuffer->lock((vertexOffset+patchOffset)*VERTEXSIZE*sizeof(Real),REGIONSURF*VERTEXSIZE*sizeof(Real),HardwareBuffer::HBL_NO_OVERWRITE);

			switch (direction) {
		case LEFT : 
		case RIGHT : 
			// Commit the unblended vertices			
			if (hasBorderRegionOnLeft()){
				commitLeft(amount,vertices);
				updateLeft(vertices);
			} else {
				commitBlock(0,0,std::min(amount,getWidth()+1),getHeight()+1,vertices);
			}
			if (hasBorderRegionOnRight()){
				// Commit the unblended vertices
				commitRight(amount,vertices);
				// Update the blended vertices
				updateRight(vertices);
			} else {
				commitBlock(getWidth()-std::min(amount-1,getWidth()),0,getWidth()+1,getHeight()+1,vertices);
			}
			break;
		case DOWN : 
		case UP : 
			if (hasBorderRegionOnDown()){
				// Commit the unblended vertices
				commitBottom(amount,vertices);
				updateBottom(vertices);
			} else {
				commitBlock(0,getHeight()-std::min(amount-1,getHeight()),getWidth()+1,getHeight()+1,vertices);
			}
			if (hasBorderRegionOnUp()){
				// Commit the unblended vertices
				commitTop(amount,vertices);
				updateTop(vertices);
			} else {
				commitBlock(0,0,getWidth()+1,std::min(amount,getHeight()+1),vertices);
			}
			break;
			}
			vertexBuffer->unlock();
		}
	}

	void ClipmapRegion::refreshCenter(){
		int i,j,pos;
		for (i=TRANSITIONSIZE(getWidth());i<getWidth()-TRANSITIONSIZE(getWidth())+1;i++){
			for (j=TRANSITIONSIZE(getHeight());j<getHeight()-TRANSITIONSIZE(getHeight())+1;j++){
				pos = getVertexPosition(i,j)-(vertexOffset+patchOffset);
				commitVertex(pos, vertices);
			}		
		}
	}

	void ClipmapRegion::refreshAll(){
		int i,j,pos;
		for (i=0;i<getWidth()+1;i++){
			for (j=0;j<getHeight()+1;j++){
				pos = getVertexPosition(i,j)-(vertexOffset+patchOffset);
				commitVertex(pos, vertices);
			}
		}				
	}

	/**
	* Updates the vertices in the transition zone without blending.
	*/
	void ClipmapRegion::updatePlain(int amount, int direction){
		int i,j;
		Real* vertices = (Real*)vertexBuffer->lock((vertexOffset+patchOffset)*VERTEXSIZE*sizeof(Real),REGIONSURF*VERTEXSIZE*sizeof(Real),HardwareBuffer::HBL_NO_OVERWRITE);
		int pos;
		switch (direction) {
		case LEFT : 
		case RIGHT : 
			// Commit the unblended vertices
			for (i=0;i<std::min(getWidth(),amount);i++){
				for (j=0;j<getHeight();j++){
					pos = getVertexPosition(i,j)-(vertexOffset+patchOffset);
					commitVertex(pos, vertices);
				}
			}
			// Commit the unblended vertices
			for (i=std::max(getWidth()-amount,0);i<getWidth();i++){
				for (j=0;j<getHeight();j++){
					pos = getVertexPosition(i,j)-(vertexOffset+patchOffset);
					commitVertex(pos, vertices);
				}
			}
		case UP : 
		case DOWN : 
			// Commit the unblended vertices
			for (j=std::max(getHeight()-amount,0);j<getHeight();j++){
				for (i=0;i<getWidth();i++){
					pos = getVertexPosition(i,j)-(vertexOffset+patchOffset);
					commitVertex(pos, vertices);
				}
			}
			// Commit the unblended vertices
			for (j=0;j<std::min(getHeight(),amount);j++){
				for (i=0;i<getWidth();i++){
					pos = getVertexPosition(i,j)-(vertexOffset+patchOffset);
					commitVertex(pos, vertices);
				}
			}
		}
		vertexBuffer->unlock();
	}


	inline Real ClipmapRegion::calculateAlphaX(int pos){
		pos += upperLeftQuad.x;
#if TRANSITION
		Real res = std::min(std::max((Real)(abs(pos-centerx)-(REGIONSIZE/2-TRANSITION-1))/(Real)TRANSITION,(Real)0),(Real)1);
#else
		Real res = 0;
#endif
		return res;
	}
	inline Real ClipmapRegion::calculateAlphaY(int pos){
		pos += upperLeftQuad.y;
#if TRANSITION
		Real res = std::min(std::max((Real)(abs(pos-centerz)-(REGIONSIZE/2-TRANSITION-1))/(Real)TRANSITION,(Real)0),(Real)1);
#else
		Real res = 0;
#endif
		return res;
	}

	inline void ClipmapRegion::setVertex(int pos, Vector3 vertex, Real* vertices){
		int i;
		pos*=VERTEXSIZE;
		short offset=0;
		for (i=0;i<3;i++){
			vertices[pos++]=vertex[i];
		}
#if USE_NORMALS
		for (i=0;i<3;i++){		 
			vertices[pos]=this->vertices[pos];
			pos++;
		}
#endif	
#if USE_TEXTURES
		for (i=0;i<2;i++){
			vertices[pos]=this->vertices[pos];
			pos++;
		}
#endif
#if USE_COLOURS
		vertices[pos++]=getColour(vertex[COLOURSIZE]);
#endif	
	}

	inline void ClipmapRegion::setVertex(int pos, Vector3 vertex, Vector3 normal, Real* vertices){
		int i;
		pos*=VERTEXSIZE;
		for (i=0;i<3;i++){		
			vertices[pos++]=vertex[i];
		}
#if USE_NORMALS
		for (i=0;i<3;i++){		 
			vertices[pos++]=normal[i];
		}
#endif	
#if USE_TEXTURES
		for (i=0;i<2;i++){
			vertices[pos]=this->vertices[pos];
			pos++;
		}
#endif
#if USE_COLOURS
		vertices[pos++]=getColour(vertex[COLOURSIZE]);
#endif	
	}

	/**
	* Uses the coordinates in the Local vertexBuffer for the value in the 
	* HW-vertexBuffer
	*/
	inline void ClipmapRegion::commitVertex(int pos, Real* vertices){
		int i;
		pos*=VERTEXSIZE;
		for (i=0;i<VERTEXSIZE;i++){
			vertices[pos+i]=this->vertices[pos+i];
		}
	}

	/**
	* Blends a vertex with a given amount into the next level
	*/
	Vector3 ClipmapRegion::blendVertex(int x, int y, Real alpha){
		Vector3i rcoords = getVertexCoordinates(x,y);	
		Vector3 coordinates = previousRegion->getRelativeCoordinates(rcoords.x>>1,rcoords.y>>1);	
		int pos0 = getVertexPosition(x,y)-(vertexOffset+patchOffset);
		Vector3 val1 = Vector3(vertices[pos0*VERTEXSIZE],
			vertices[pos0*VERTEXSIZE+1],
			vertices[pos0*VERTEXSIZE+2]);
		if ((x%2==0)&&(y%2==0)){
			int pos = previousRegion->getVertexPosition((int)coordinates.x, (int)coordinates.y)-previousRegion->vertexOffset-patchOffset;
			pos*=VERTEXSIZE;
			Vector3 val2 = Vector3(previousRegion->vertices[pos],
				previousRegion->vertices[pos+1],
				previousRegion->vertices[pos+2]);
			return (1-alpha)*val1+alpha*val2;
		} else if ((x%2==1)&&(y%2==0)){
			int pos1 = previousRegion->getVertexPosition((int)coordinates.x, (int)coordinates.y)-previousRegion->vertexOffset-patchOffset;
			pos1*=VERTEXSIZE;
			int pos2 = previousRegion->getVertexPosition((int)coordinates.x+1, (int)coordinates.y)-previousRegion->vertexOffset-patchOffset;
			pos2*=VERTEXSIZE;
			Vector3 val21 = Vector3(previousRegion->vertices[pos1],
				previousRegion->vertices[pos1+1],
				previousRegion->vertices[pos1+2]);
			Vector3 val22 = Vector3(previousRegion->vertices[pos2],
				previousRegion->vertices[pos2+1],
				previousRegion->vertices[pos2+2]);
			return (1-alpha)*val1+alpha*(val21+val22)/2.0;
		} else if ((x%2==0)&&(y%2==1)){
			int pos1 = previousRegion->getVertexPosition((int)coordinates.x, (int)coordinates.y)-previousRegion->vertexOffset-patchOffset;
			pos1*=VERTEXSIZE;
			int pos2 = previousRegion->getVertexPosition((int)coordinates.x, (int)coordinates.y+1)-previousRegion->vertexOffset-patchOffset;
			pos2*=VERTEXSIZE;
			Vector3 val21 = Vector3(previousRegion->vertices[pos1],
				previousRegion->vertices[pos1+1],
				previousRegion->vertices[pos1+2]);
			Vector3 val22 = Vector3(previousRegion->vertices[pos2],
				previousRegion->vertices[pos2+1],
				previousRegion->vertices[pos2+2]);
			return (1-alpha)*val1+alpha*(val21+val22)/2.0;
		} else if ((x%2==1)&&(y%2==1)){
			int pos1 = previousRegion->getVertexPosition((int)coordinates.x, (int)coordinates.y)-previousRegion->vertexOffset-patchOffset;
			pos1*=VERTEXSIZE;
			int pos2 = previousRegion->getVertexPosition((int)coordinates.x, (int)coordinates.y+1)-previousRegion->vertexOffset-patchOffset;
			pos2*=VERTEXSIZE;
			int pos3 = previousRegion->getVertexPosition((int)coordinates.x+1, (int)coordinates.y)-previousRegion->vertexOffset-patchOffset;
			pos3*=VERTEXSIZE;
			int pos4 = previousRegion->getVertexPosition((int)coordinates.x+1, (int)coordinates.y+1)-previousRegion->vertexOffset-patchOffset;
			pos4*=VERTEXSIZE;
			Vector3 val21 = Vector3(previousRegion->vertices[pos1],
				previousRegion->vertices[pos1+1],
				previousRegion->vertices[pos1+2]);
			Vector3 val22 = Vector3(previousRegion->vertices[pos2],
				previousRegion->vertices[pos2+1],
				previousRegion->vertices[pos2+2]);
			Vector3 val23 = Vector3(previousRegion->vertices[pos3],
				previousRegion->vertices[pos3+1],
				previousRegion->vertices[pos3+2]);
			Vector3 val24 = Vector3(previousRegion->vertices[pos4],
				previousRegion->vertices[pos4+1],
				previousRegion->vertices[pos4+2]);
			return (1-alpha)*val1+alpha*(val21+val22+val23+val24)/4.0;
		}
		return Vector3(0,0,0);
	}

	/**
	* Blends a vertex with a given amount into the next level
	*/
	Vector3 ClipmapRegion::blendNormal(int x, int y, Real alpha){
		Vector3i rcoords = getVertexCoordinates(x,y);	
		Vector3 coordinates = previousRegion->getRelativeCoordinates(rcoords.x>>1,rcoords.y>>1);	
		int pos0 = (getVertexPosition(x,y)-(vertexOffset+patchOffset))*VERTEXSIZE+3;
		Vector3 val1 = Vector3(vertices[pos0],
			vertices[pos0+1],
			vertices[pos0+2]);
		if ((x%2==0)&&(y%2==0)){
			int pos = previousRegion->getVertexPosition((int)coordinates.x, (int)coordinates.y)-previousRegion->vertexOffset-patchOffset;
			pos=pos*VERTEXSIZE+3;
			Vector3 val2 = Vector3(previousRegion->vertices[pos],
				previousRegion->vertices[pos+1],
				previousRegion->vertices[pos+2]);
			Vector3 res = ((1-alpha)*val1+alpha*val2);
			res.normalise();
			return res;
		} else if ((x%2==1)&&(y%2==0)){
			int pos1 = previousRegion->getVertexPosition((int)coordinates.x, (int)coordinates.y)-previousRegion->vertexOffset-patchOffset;
			pos1=pos1*VERTEXSIZE+3;
			int pos2 = previousRegion->getVertexPosition((int)coordinates.x+1, (int)coordinates.y)-previousRegion->vertexOffset-patchOffset;
			pos2=pos2*VERTEXSIZE+3;
			Vector3 val21 = Vector3(previousRegion->vertices[pos1],
				previousRegion->vertices[pos1+1],
				previousRegion->vertices[pos1+2]);
			Vector3 val22 = Vector3(previousRegion->vertices[pos2],
				previousRegion->vertices[pos2+1],
				previousRegion->vertices[pos2+2]);
			Vector3 val2 = (val21+val22)/2.0;
			Vector3 res = ((1-alpha)*val1+alpha*val2);
			return res;
		} else if ((x%2==0)&&(y%2==1)){
			int pos1 = previousRegion->getVertexPosition((int)coordinates.x, (int)coordinates.y)-previousRegion->vertexOffset-patchOffset;
			pos1=pos1*VERTEXSIZE+3;
			int pos2 = previousRegion->getVertexPosition((int)coordinates.x, (int)coordinates.y+1)-previousRegion->vertexOffset-patchOffset;
			pos2=pos2*VERTEXSIZE+3;
			Vector3 val21 = Vector3(previousRegion->vertices[pos1],
				previousRegion->vertices[pos1+1],
				previousRegion->vertices[pos1+2]);
			Vector3 val22 = Vector3(previousRegion->vertices[pos2],
				previousRegion->vertices[pos2+1],
				previousRegion->vertices[pos2+2]);
			Vector3 val2 = (val21+val22)/2.0;
			Vector3 res = ((1-alpha)*val1+alpha*val2);
			return res;
		} else if ((x%2==1)&&(y%2==1)){
			int pos1 = previousRegion->getVertexPosition((int)coordinates.x, (int)coordinates.y)-previousRegion->vertexOffset-patchOffset;
			pos1=pos1*VERTEXSIZE+3;
			int pos2 = previousRegion->getVertexPosition((int)coordinates.x, (int)coordinates.y+1)-previousRegion->vertexOffset-patchOffset;
			pos2=pos2*VERTEXSIZE+3;
			int pos3 = previousRegion->getVertexPosition((int)coordinates.x+1, (int)coordinates.y)-previousRegion->vertexOffset-patchOffset;
			pos3=pos3*VERTEXSIZE+3;
			int pos4 = previousRegion->getVertexPosition((int)coordinates.x+1, (int)coordinates.y+1)-previousRegion->vertexOffset-patchOffset;
			pos4=pos4*VERTEXSIZE+3;
			Vector3 val21 = Vector3(previousRegion->vertices[pos1],
				previousRegion->vertices[pos1+1],
				previousRegion->vertices[pos1+2]);
			Vector3 val22 = Vector3(previousRegion->vertices[pos2],
				previousRegion->vertices[pos2+1],
				previousRegion->vertices[pos2+2]);
			Vector3 val23 = Vector3(previousRegion->vertices[pos3],
				previousRegion->vertices[pos3+1],
				previousRegion->vertices[pos3+2]);
			Vector3 val24 = Vector3(previousRegion->vertices[pos4],
				previousRegion->vertices[pos4+1],
				previousRegion->vertices[pos4+2]);
			Vector3 val2 = (val21+val22+val23+val24)/4.0;
			Vector3 res = ((1-alpha)*val1+alpha*val2);
			return res;
		}
		return Vector3(0,0,0);
	}



	/**
	* Adds a row of vertices to the vertexBuffer
	*/
	void ClipmapRegion::addRow(int offset,int startx,int starty){	
		int number = lowerRightQuad.x - upperLeftQuad.x+2;
		int i, pos;
		for (i=0; i<number;i++){
			Vertex* vertex = mGeometryReader->getVertex(startx+i,starty,upperLeftQuad.z, mMap);
			Vector3 position = vertex->getVertex();
#if USE_NORMALS
			Vector3 normal = vertex->getNormal();
#endif
#if USE_TEXTURES
			Real tx,ty;
			vertex->fillTextureCoordinates(tx,ty);
#endif
			pos = ((i*(REGIONSIZE+1)+offset)%REGIONSURF)*VERTEXSIZE;
			vertices[pos++] = position.x;
			vertices[pos++] = position.y;
			vertices[pos++] = position.z;
#if USE_NORMALS
			vertices[pos++] = normal.x;
			vertices[pos++] = normal.y;
			vertices[pos++] = normal.z;
#endif
#if USE_TEXTURES
			vertices[pos++] = tx;
			vertices[pos++] = ty;
#endif
		}
		changed = true;
	}
	/**
	* adds a row to the inner side of the region. (shrinks the hole)
	*/
	void ClipmapRegion::addInteriorRows(int amount, int direction){
		int i;
		if (amount > 0){
			switch (direction) {
			case LEFT : 
				for (i=0;i<amount;i++){
					if (getQuad(innerUpperLeftQuad.getRight())==NULL) {
						break;
					}
					innerUpperLeftQuad = innerUpperLeftQuad.getRight();
				}
				break;
			case RIGHT : 
				for (i=0;i<amount;i++){
					if (getQuad(innerLowerRightQuad.getLeft())==NULL) {
						break;
					}
					innerLowerRightQuad = innerLowerRightQuad.getLeft();
				}
				break;
			case UP : 
				for (i=0;i<amount;i++){
					if (getQuad(innerUpperLeftQuad.getBottom())==NULL) {
						break;
					}
					innerUpperLeftQuad = innerUpperLeftQuad.getBottom();
				}
				break;
			case DOWN : 
				for (i=0;i<amount;i++){
					if (getQuad(innerLowerRightQuad.getTop())==NULL) {
						break;
					}
					innerLowerRightQuad = innerLowerRightQuad.getTop();
				}
				break;
			}
			changed = true;
		} else if (amount < 0) {
			removeInteriorRows(-amount,direction);
		} 
	}

	/**
	* Removes a row/collumn from the region
	*/
	void ClipmapRegion::removeExteriorRows(int amount, int direction){
		int i;
		if (amount > 0){
			switch (direction) {
			case LEFT : 
				for (i=0;i<amount;i++){
					if (getQuad(upperLeftQuad.getRight())==NULL) {
						break;
					}
					upperLeftQuad = upperLeftQuad.getRight();
					startOffset=(startOffset+(REGIONSIZE+1))%REGIONSURF;
					if (lowerRightQuad.x-upperLeftQuad.x < 0) {
						lowerRightQuad = lowerRightQuad.getRight();
						endOffset=(endOffset-(REGIONSIZE+1))%REGIONSURF;
					}
				}
				break;
			case RIGHT : 
				for (i=0;i<amount;i++){
					if (getQuad(lowerRightQuad.getLeft())==NULL) {
						break;
					}
					lowerRightQuad = lowerRightQuad.getLeft();
					endOffset=(endOffset-(REGIONSIZE+1)+REGIONSURF)%REGIONSURF;
					if (lowerRightQuad.x-upperLeftQuad.x < 0) {
						upperLeftQuad = upperLeftQuad.getLeft();
						startOffset=(startOffset-(REGIONSIZE+1)+REGIONSURF)%REGIONSURF;
					}
				}
				break;
			case UP : 
				for (i=0;i<amount;i++){
					if (getQuad(upperLeftQuad.getBottom())==NULL) {
						break;
					}
					upperLeftQuad = upperLeftQuad.getBottom();
					startOffset=(startOffset+1)%REGIONSURF;
					if (lowerRightQuad.x-upperLeftQuad.x < 0) {
						lowerRightQuad = lowerRightQuad.getBottom();
						endOffset=(endOffset+1)%REGIONSURF;
					}
				}
				break;
			case DOWN : 
				for (i=0;i<amount;i++){
					if (getQuad(lowerRightQuad.getTop())==NULL) {
						break;
					}
					lowerRightQuad = lowerRightQuad.getTop();
					endOffset=(endOffset-1+REGIONSURF)%REGIONSURF;
					if (lowerRightQuad.x-upperLeftQuad.x < 0) {
						upperLeftQuad = upperLeftQuad.getTop();
						startOffset=(startOffset-1+REGIONSURF)%REGIONSURF;
					}
				}
				break;
			}
			changed = true;
		} else if (amount < 0) {
			addExteriorRows(-amount,direction);
		} 
	}
	void ClipmapRegion::removeInteriorRows(int amount, int direction){
		int i;
		if (amount > 0){
			switch (direction) {
			case LEFT : 
				for (i=0;i<amount;i++){
					if (getQuad(innerUpperLeftQuad.getLeft())==NULL) {
						break;
					}
					innerUpperLeftQuad = innerUpperLeftQuad.getLeft();					
				}
				break;
			case RIGHT : 
				for (i=0;i<amount;i++){
					if (getQuad(innerLowerRightQuad.getRight())==NULL) {
						break;
					}
					innerLowerRightQuad = innerLowerRightQuad.getRight();
				}
				break;
			case UP : 
				for (i=0;i<amount;i++){
					if (getQuad(innerUpperLeftQuad.getTop())==NULL) {
						break;
					}
					innerUpperLeftQuad = innerUpperLeftQuad.getTop();
				}
				break;
			case DOWN : 
				for (i=0;i<amount;i++){
					if (getQuad(innerLowerRightQuad.getBottom())==NULL) {
						break;
					}
					innerLowerRightQuad = innerLowerRightQuad.getBottom();
				}
				break;
			}
			changed = true;
		} else if (amount < 0) {
			addInteriorRows(-amount,direction);
		} 
	}

	/**
	* Moves the region an amount of quads to the given direction
	* @param	amount
	* 			| The amount of quads to be moved
	* @param	direction
	* 			| The direction to move to (N,E,S,W)
	* @post	The <amount> rows will be added in the given direction
	* 				the rows that are too much will be overwritten on the other side
	* 			If <amount> is negative, the rows will be added to the opposide side
	* 				of <direction>
	* 			this->centerx and this->centerz will be moved with the given amount
	* 				and direction
	*/
	int ClipmapRegion::move(int amount, int direction){
		int moved=0;
		if (amount!=0){
			if (amount<0) {				
				return move(-amount, (direction+2)%4);
			} else {
				switch (direction) {
				case N:
					centerz-=amount;
					break;
				case E:
					centerx+=amount;
					break;
				case S:
					centerz+=amount;
					break;
				case W:
					centerx-=amount;
					break;
				}
				if (amount >= getSize()){
					moved = moveAndReset(amount,direction);
				} else {
					moved = addExteriorRows(amount, direction);
				}
				switch (direction) {
				case N:
					ymove=-amount;
					break;
				case E:
					xmove=amount;
					break;
				case S:
					ymove=amount;
					break;
				case W:
					xmove=-amount;
					break;
				}
			}
		} else {
			switch (direction) {
			case N:
			case S:
				ymove=0;
				break;
			case E:
			case W:
				xmove=0;
				break;
			}
		}
		return moved;
	}

	int ClipmapRegion::moveAndReset(int amount, int direction){
		int i=0;
		if (amount > 0){
			switch (direction) {
			case LEFT : 
				while (isTooSmallOnLeft() && upperLeftQuad.x>0){
					upperLeftQuad = upperLeftQuad.getLeft();
					i++;
				}
				while (isTooBigOnRight() && lowerRightQuad.x>=0) {
					lowerRightQuad = lowerRightQuad.getLeft();
				}		
				break;
			case RIGHT : 
				while (isTooSmallOnRight() && lowerRightQuad.x<getLevelSize(upperLeftQuad.z)-1){
					lowerRightQuad = lowerRightQuad.getRight();
					i++;
				}
				while (isTooBigOnLeft() && upperLeftQuad.x<getLevelSize(upperLeftQuad.z)) {
					upperLeftQuad = upperLeftQuad.getRight();
				}
				break;
			case UP : 
				while (isTooSmallOnUp() && upperLeftQuad.y>0){
					upperLeftQuad = upperLeftQuad.getTop();
					i++;
				}
				while (isTooBigOnDown() && lowerRightQuad.y>=0) {
					lowerRightQuad = lowerRightQuad.getTop();
				}
				break;
			case DOWN : 
				while (isTooSmallOnDown() && lowerRightQuad.y<getLevelSize(upperLeftQuad.z)-1){
					lowerRightQuad = lowerRightQuad.getBottom();
					i++;
				}
				while (isTooBigOnUp() && upperLeftQuad.y<getLevelSize(upperLeftQuad.z)) {
					upperLeftQuad = upperLeftQuad.getBottom();
				}
				break;
			}
			initializeVertices();
			if (i>0){
				changed = true;
			}
			return i;
		} 
		return 0;
	}

	void ClipmapRegion::updateVertices(){
		if (xmove < 0){
			updateVertices(-xmove, W);
		} else {
			updateVertices(xmove, E);		
		}
		if (ymove < 0){
			updateVertices(-ymove, N);
		} else {
			updateVertices(ymove, S);
		}
	}

	void ClipmapRegion::updateVertices(int amount, int direction){
		if ((getWidth() > 0)&&(getHeight()>0)){
			if (amount < 0){
				updateVertices(-amount, (direction+2)%4);
			} else {
				if (previousRegion!=0){
					updateTransition(amount, direction);
				} else {
					updatePlain(amount, direction);
				}
			}
		}
	}

	/**
	* Returns the level of the region
	*/
	int ClipmapRegion::getLevel() const {
		return upperLeftQuad.z;
	}

	/**
	* Returns the preferred width
	*/
	int ClipmapRegion::getPreferredWidth() const {
		if (getLevelSize(getLevel()) >= REGIONSIZE) {
			return REGIONSIZE;
		} else {
			return getLevelSize(getLevel());
		}
	}

	/**
	* Returns the preferred height
	*/
	int ClipmapRegion::getPreferredHeight() const {
		if (getLevelSize(getLevel()) >= REGIONSIZE) {
			return REGIONSIZE;
		} else {
			return getLevelSize(getLevel());
		}
	}

	/**
	* Returns the current width
	*/
	int ClipmapRegion::getWidth() const {
		return lowerRightQuad.x-upperLeftQuad.x+1;
	}

	/**
	* Returns the current height
	*/
	int ClipmapRegion::getHeight() const {
		return lowerRightQuad.y-upperLeftQuad.y+1;
	}


	/**
	* Returns if this region has a hole for the next level of detail
	*/
	bool ClipmapRegion::hasHole() const {
		return ((innerUpperLeftQuad.x <= innerLowerRightQuad.x) &&
			(innerUpperLeftQuad.y <= innerLowerRightQuad.y));
	}

	bool ClipmapRegion::hasBorderRegionOnLeft(){
		return ((getAmountOverEdge(LEFT)<=TRANSITION));
	}

	bool ClipmapRegion::hasBorderRegionOnRight(){
		return ((getAmountOverEdge(RIGHT)<=TRANSITION));
	}

	bool ClipmapRegion::hasBorderRegionOnUp(){
		return ((getAmountOverEdge(UP)<=TRANSITION));
	}
	bool ClipmapRegion::hasBorderRegionOnDown(){
		return ((getAmountOverEdge(DOWN)<=TRANSITION));
	}

	bool ClipmapRegion::isCompleteInLeft(){
		return (centerx - upperLeftQuad.x == REGIONSIZE>>1);
	}
	bool ClipmapRegion::isCompleteInRight(){
		return (lowerRightQuad.x - centerx + 1 == REGIONSIZE>>1);
	}
	bool ClipmapRegion::isCompleteInUp(){
		return (centerz - upperLeftQuad.y == REGIONSIZE>>1);
	}
	bool ClipmapRegion::isCompleteInDown(){
		return (lowerRightQuad.y - centerz + 1 == REGIONSIZE>>1);
	}

	bool ClipmapRegion::isTooBigOnLeft(){
		return (centerx - upperLeftQuad.x > REGIONSIZE>>1);
	}
	bool ClipmapRegion::isTooBigOnRight(){
		return (lowerRightQuad.x - centerx + 1 > REGIONSIZE>>1);
	}
	bool ClipmapRegion::isTooBigOnUp(){
		return (centerz - upperLeftQuad.y > REGIONSIZE>>1);
	}
	bool ClipmapRegion::isTooBigOnDown(){
		return (lowerRightQuad.y - centerz + 1 > REGIONSIZE>>1);
	}

	bool ClipmapRegion::isTooSmallOnLeft(){
		return (centerx - upperLeftQuad.x < REGIONSIZE>>1);
	}
	bool ClipmapRegion::isTooSmallOnRight(){
		return (lowerRightQuad.x - centerx + 1 < REGIONSIZE>>1);
	}
	bool ClipmapRegion::isTooSmallOnUp(){
		return (centerz - upperLeftQuad.y < REGIONSIZE>>1);
	}
	bool ClipmapRegion::isTooSmallOnDown(){
		return (lowerRightQuad.y - centerz + 1 < REGIONSIZE>>1);
	}

	int ClipmapRegion::getSize() const{
		return std::min(getLevelSize(getLevel()),REGIONSIZE);
	}

	void ClipmapRegion::setGeometryReader(SeperateCubemappedPlanetReader* geometryReader){
		mGeometryReader = geometryReader;
	}




	/**
	* Calculate the vertices
	* @pre	The space between the lowerRightQuad and the upperRightQuad must be
	* 		smaller then REGIONSIZE
	* 		else it will be truncated
	* 		(lowerRightQuad-upperLeftQuad).x <= REGIONSIZE
	* 		(lowerRightQuad-upperLeftQuad).y <= REGIONSIZE
	*/
	void ClipmapRegion::initializeVertices(){
		Vector3ix size = lowerRightQuad-upperLeftQuad;
		size.x+=1;
		size.y+=1;
		if (size.x > getSize()) {
			lowerRightQuad.x = upperLeftQuad.x + getSize();
			size.x = getSize();
		}
		if (size.y > getSize()) {
			lowerRightQuad.y = upperLeftQuad.y + getSize();
			size.y = getSize();
		}
		int i,j;
		startOffset=0;
		endOffset = ((size.x*(REGIONSIZE+1)+size.y) % (REGIONSURF));
		for (i=0;i<=size.x;i++){
			for (j=0;j<=size.y;j++){
				int vertexNb = getVertexPosition(i,j)-(vertexOffset+patchOffset);
				Vertex* vertex = mGeometryReader->getVertex(upperLeftQuad.x+i,upperLeftQuad.y+j,upperLeftQuad.z, mMap);
				Vector3 position = vertex->getVertex();
				short ind=0;
				this->vertices[vertexNb*VERTEXSIZE+ind++] = position.x;
				this->vertices[vertexNb*VERTEXSIZE+ind++] = position.y;
				this->vertices[vertexNb*VERTEXSIZE+ind++] = position.z;
#if USE_NORMALS
				Vector3 normal = vertex->getNormal();
				this->vertices[vertexNb*VERTEXSIZE+ind++] = normal.x;
				this->vertices[vertexNb*VERTEXSIZE+ind++] = normal.y;
				this->vertices[vertexNb*VERTEXSIZE+ind++] = normal.z;
#endif
#if USE_TEXTURES
				Real tx,ty;
				vertex->fillTextureCoordinates(tx,ty);
				this->vertices[vertexNb*VERTEXSIZE+ind++] = tx;
				this->vertices[vertexNb*VERTEXSIZE+ind++] = ty;
#endif
			}
		}
	}



	void ClipmapRegion::calculateIndices(){
		//AAABBDD
		//AAABBDD
		//AAA  DD
		//AAACCDD
		//AAACCDD
#if USE_16BIT_INDICES
		unsigned short* index = indices;
#else
		unsigned int* index = indices;
#endif

		if ((getHeight()>0) && (getWidth()>0)){

			if ((innerUpperLeftQuad.x > innerLowerRightQuad.x)||(innerUpperLeftQuad.y > innerLowerRightQuad.y)) {

				calculateAll(index);
			} else {
				calculateA(index);
				calculateB(index);
				calculateC(index);
				calculateD(index);
			}
			if (isCompleteInUp()){
				calculateN(index);
			}
			if (isCompleteInRight())	calculateE(index);
			if (isCompleteInDown())	calculateS(index);
			if (isCompleteInLeft())	calculateW(index);
		}
		indexCount = index-indices;

		changed = false;
	}

	//		.---.
	//		|\ /|	<-this line should theoreticly be 0
	//		._._.
#if USE_16BIT_INDICES
	void ClipmapRegion::calculateN(unsigned short* &index){
#else
	void ClipmapRegion::calculateN(unsigned int* &index){
#endif
		int i;
		for (i=0;i<getWidth();i+=2){
			Vector3i coor = getVertexCoordinates(i,0);
			Vector3 prev = previousRegion->getRelativeCoordinates(coor.x>>1,coor.y>>1);
			*(index++) = getVertexPosition(i,0);
			*(index++) = getVertexPosition(i+1,0);
			*(index++) = previousRegion->getVertexPosition((int)prev.x,(int)prev.y);

			*(index++) = previousRegion->getVertexPosition((int)prev.x,(int)prev.y);
			*(index++) = getVertexPosition(i+1,0);
			*(index++) = previousRegion->getVertexPosition((int)prev.x+1,(int)prev.y);

			*(index++) = getVertexPosition(i+1,0);
			*(index++) = getVertexPosition(i+2,0);
			*(index++) = previousRegion->getVertexPosition((int)prev.x+1,(int)prev.y);
		}
	}
#if USE_16BIT_INDICES
	void ClipmapRegion::calculateE(unsigned short* &index){
#else
	void ClipmapRegion::calculateE(unsigned int* &index){
#endif
		int i;
		for (i=0;i<getHeight();i+=2){
			Vector3i coor = getVertexCoordinates(getWidth(),i);
			Vector3 prev = previousRegion->getRelativeCoordinates(coor.x>>1,coor.y>>1);
			*(index++) = getVertexPosition(getWidth(),i);
			*(index++) = getVertexPosition(getWidth(),i+1);
			*(index++) = previousRegion->getVertexPosition((int)prev.x,(int)prev.y);

			*(index++) = previousRegion->getVertexPosition((int)prev.x,(int)prev.y);
			*(index++) = getVertexPosition(getWidth(),i+1);
			*(index++) = previousRegion->getVertexPosition((int)prev.x,(int)prev.y+1);

			*(index++) = getVertexPosition(getWidth(),i+1);
			*(index++) = getVertexPosition(getWidth(),i+2);
			*(index++) = previousRegion->getVertexPosition((int)prev.x,(int)prev.y+1);
		}
	}
#if USE_16BIT_INDICES
	void ClipmapRegion::calculateS(unsigned short* &index){
#else
	void ClipmapRegion::calculateS(unsigned int* &index){
#endif
		int i;
		for (i=0;i<getWidth();i+=2){
			Vector3i coor = getVertexCoordinates(i,getHeight());
			Vector3 prev = previousRegion->getRelativeCoordinates(coor.x>>1,coor.y>>1);
			*(index++) = previousRegion->getVertexPosition((int)prev.x,(int)prev.y);
			*(index++) = getVertexPosition(i+1,getHeight());
			*(index++) = getVertexPosition(i,getHeight());

			*(index++) = previousRegion->getVertexPosition((int)prev.x+1,(int)prev.y);
			*(index++) = getVertexPosition(i+1,getHeight());
			*(index++) = previousRegion->getVertexPosition((int)prev.x,(int)prev.y);

			*(index++) = previousRegion->getVertexPosition((int)prev.x+1,(int)prev.y);
			*(index++) = getVertexPosition(i+2,getHeight());
			*(index++) = getVertexPosition(i+1,getHeight());
		}
	}
#if USE_16BIT_INDICES
	void ClipmapRegion::calculateW(unsigned short* &index){
#else
	void ClipmapRegion::calculateW(unsigned int* &index){
#endif
		int i;
		for (i=0;i<getHeight();i+=2){
			Vector3i coor = getVertexCoordinates(0,i);
			Vector3 prev = previousRegion->getRelativeCoordinates(coor.x>>1,coor.y>>1);
			*(index++) = previousRegion->getVertexPosition((int)prev.x,(int)prev.y);
			*(index++) = getVertexPosition(0,i+1);
			*(index++) = getVertexPosition(0,i);

			*(index++) = previousRegion->getVertexPosition((int)prev.x,(int)prev.y+1);
			*(index++) = getVertexPosition(0,i+1);
			*(index++) = previousRegion->getVertexPosition((int)prev.x,(int)prev.y);

			*(index++) = previousRegion->getVertexPosition((int)prev.x,(int)prev.y+1);
			*(index++) = getVertexPosition(0,i+2);
			*(index++) = getVertexPosition(0,i+1);
		}
	}
	/**
	* Returns the offset of the given vertex in the vertexBuffer.
	* @param	x and y are the coordinates relative to the bufer (0,0 is the 
	* 			upperleftmost vertex in the buffer
	* @pre	the x and y coordinates should be available
	* @post	returns the vertex position, or 0 if not existing
	*/
	int ClipmapRegion::getVertexPosition(int x, int y) const {
		if ((x > getWidth())||(y > getHeight())||(x < 0)||(y < 0)){
			std::cout << "WARNING : VertexPosition out of bounds! " << x << "," << y << " in level " << upperLeftQuad.z << " map " << mMap << std::endl;		
			std::cout << "upperLeftQuad.x " << upperLeftQuad.x << " upperLeftQuad.y " << upperLeftQuad.y << std::endl;
			std::cout << "lowerRightQuad.x " << lowerRightQuad.x << " lowerRightQuad.y " << lowerRightQuad.y << std::endl;
			std::cout << "centerx " << centerx << " centerz " << centerz << std::endl;
		}
		int pos = ((startOffset+x*(REGIONSIZE+1)+y) % (REGIONSURF));
		if ((pos > endOffset) && (pos < startOffset)) {
			std::cout << "ERROR : VertexPosition out of bounds! " << x << "," << y << " gives " << pos << ">" << endOffset << " && < " << startOffset << " map " << mMap << std::endl;
			std::cout << "upperLeftQuad.x " << upperLeftQuad.x << " upperLeftQuad.y " << upperLeftQuad.y << std::endl;
			std::cout << "lowerRightQuad.x " << lowerRightQuad.x << " lowerRightQuad.y " << lowerRightQuad.y << std::endl;
			std::cout << "centerx " << centerx << " centerz " << centerz << std::endl;
			return 0;
		}
		if ((pos > endOffset) && (pos > startOffset) && (startOffset < endOffset)) {
			std::cout << "ERROR : VertexPosition out of bounds! " << x << "," << y << " gives " << pos << ">" << endOffset << " && > " << startOffset << " map " << mMap << std::endl;
			std::cout << "upperLeftQuad.x " << upperLeftQuad.x << " upperLeftQuad.y " << upperLeftQuad.y << std::endl;
			std::cout << "lowerRightQuad.x " << lowerRightQuad.x << " lowerRightQuad.y " << lowerRightQuad.y << std::endl;
			std::cout << "centerx " << centerx << " centerz " << centerz << std::endl;
			return 0;
		}
		if ((pos < endOffset) && (pos < startOffset) && (startOffset < endOffset)) {
			std::cout << "ERROR : VertexPosition out of bounds! " << x << "," << y << " gives " << pos << "<" << endOffset << " && < " << startOffset << " map " << mMap << std::endl;
			std::cout << "upperLeftQuad.x " << upperLeftQuad.x << " upperLeftQuad.y " << upperLeftQuad.y << std::endl;
			std::cout << "lowerRightQuad.x " << lowerRightQuad.x << " lowerRightQuad.y " << lowerRightQuad.y << std::endl;
			std::cout << "centerx " << centerx << " centerz " << centerz << std::endl;
			return 0;
		}
		return pos+(vertexOffset+patchOffset);
	}

	/**
	* Returns the "absolute" coordinates of the vertex in relative coordinates in
	* the region
	*/
	Vector3i ClipmapRegion::getVertexCoordinates(int x, int y) const {
		return Vector3i(upperLeftQuad.x+x,upperLeftQuad.y+y,upperLeftQuad.z);
	}

	/**
	* Returns the "relative" coordinates of the vertex in absolute coordinates in
	* the region
	*/
	Vector3 ClipmapRegion::getRelativeCoordinates(int x, int y) const {
		return Vector3((x-upperLeftQuad.x),y-upperLeftQuad.y,0);
	}

#if USE_16BIT_INDICES
	void ClipmapRegion::calculateAll(unsigned short* &index){
#else
	void ClipmapRegion::calculateAll(unsigned int* &index){
#endif
		int width = lowerRightQuad.x-upperLeftQuad.x+1;
		int height = lowerRightQuad.y-upperLeftQuad.y+1;
		if ((width>=0)&&(height>=0)&&(width<=getSize())&&(height<=getSize())){
			for (int i=0;i<width;i++){
				for (int j=0;j<height;j++){
					//02
					//13
#if DEBUG
					if (upperLeftQuad.z % 2 == 0){
#endif
						*(index++) = getVertexPosition(i,j);		//0
						*(index++) = getVertexPosition(i,j+1);		//1
						*(index++) = getVertexPosition(i+1,j+1);	//3

						*(index++) = getVertexPosition(i+1,j+1);	//3
						*(index++) = getVertexPosition(i+1,j);		//2
						*(index++) = getVertexPosition(i,j);		//0
#if DEBUG
					} else {
						*(index++) = getVertexPosition(i,j);		//0
						*(index++) = getVertexPosition(i,j+1);		//1
						*(index++) = getVertexPosition(i+1,j);		//2

						*(index++) = getVertexPosition(i+1,j+1);	//3
						*(index++) = getVertexPosition(i+1,j);		//2
						*(index++) = getVertexPosition(i,j+1);		//1
					}
#endif
				}
			}
		} else {
			std::cout << "ERROR : width = " << width << ", height = " << height << " level " << getLevel() << std::endl;
			std::cout << "innerUpperLeft " << innerUpperLeftQuad.x << "," << innerUpperLeftQuad.y << std::endl;
			std::cout << "innerLowerRight " << innerLowerRightQuad.x << "," << innerLowerRightQuad.y << std::endl;
			std::cout << "upperLeft " << upperLeftQuad.x << "," << upperLeftQuad.y << std::endl;
			std::cout << "lowerRight " << lowerRightQuad.x << "," << lowerRightQuad.y << std::endl;
			std::cout << "centerx " << centerx << " centerz " << centerz << std::endl;
		}
	}


	/**
	* Calculates the left part of the clipmap.
	* @pre	The pointer should point to the position of the first index of this
	* 		part to be written in the indexBuffer
	*/
#if USE_16BIT_INDICES
	void ClipmapRegion::calculateA(unsigned short* &index){
#else
	void ClipmapRegion::calculateA(unsigned int* &index){
#endif
		int width = innerUpperLeftQuad.x-upperLeftQuad.x;
		int height = lowerRightQuad.y-upperLeftQuad.y+1;
		if ((width>=0)&&(height>=0)&&(width<=getSize())&&(height<=getSize())){
			for (int i=0;i<width;i++){
				for (int j=0;j<height;j++){
					//02
					//13
#if DEBUG
					if (upperLeftQuad.z % 2 == 0){
#endif
						*(index++) = getVertexPosition(i,j);		//0
						*(index++) = getVertexPosition(i,j+1);		//1
						*(index++) = getVertexPosition(i+1,j+1);	//3

						*(index++) = getVertexPosition(i+1,j+1);	//3
						*(index++) = getVertexPosition(i+1,j);		//2
						*(index++) = getVertexPosition(i,j);		//0
#if DEBUG
					} else {
						*(index++) = getVertexPosition(i,j);		//0
						*(index++) = getVertexPosition(i,j+1);		//1
						*(index++) = getVertexPosition(i+1,j);		//2

						*(index++) = getVertexPosition(i+1,j+1);	//3
						*(index++) = getVertexPosition(i+1,j);		//2
						*(index++) = getVertexPosition(i,j+1);		//1
					}
#endif
				}
			}
		} else {
			std::cout << "ERROR : width = " << width << ", height = " << height << " level " << getLevel() << std::endl;
			std::cout << "innerUpperLeft " << innerUpperLeftQuad.x << "," << innerUpperLeftQuad.y << std::endl;
			std::cout << "innerLowerRight " << innerLowerRightQuad.x << "," << innerLowerRightQuad.y << std::endl;
			std::cout << "upperLeft " << upperLeftQuad.x << "," << upperLeftQuad.y << std::endl;
			std::cout << "lowerRight " << lowerRightQuad.x << "," << lowerRightQuad.y << std::endl;
			std::cout << "centerx " << centerx << " centerz " << centerz << std::endl;
		}
	}

	/**
	* Calculates the upper middle part of the clipmap.
	* @pre	The pointer should point to the position of the first index of this
	* 		part to be written in the indexBuffer
	*/
#if USE_16BIT_INDICES
	void ClipmapRegion::calculateB(unsigned short* &index){
#else
	void ClipmapRegion::calculateB(unsigned int* &index){
#endif
		int widtha = innerUpperLeftQuad.x-upperLeftQuad.x;
		int totalHeight = lowerRightQuad.y-upperLeftQuad.y+1;
		int offset = (widtha)*(totalHeight+1);

		int width = innerLowerRightQuad.x-innerUpperLeftQuad.x+1;
		int height = innerUpperLeftQuad.y-upperLeftQuad.y;
		if ((width>=0)&&(height>=0)&&(width<=getSize())&&(height<=getSize())){
			for (int i=0;i<width;i++){
				for (int j=0;j<height;j++){
					//02
					//13
#if DEBUG
					if (upperLeftQuad.z % 2 == 0){
#endif
						*(index++) = getVertexPosition(widtha+i,j);			//0
						*(index++) = getVertexPosition(widtha+i,j+1);		//1
						*(index++) = getVertexPosition(widtha+i+1,j+1);		//3

						*(index++) = getVertexPosition(widtha+i+1,j+1);		//3
						*(index++) = getVertexPosition(widtha+i+1,j);		//2
						*(index++) = getVertexPosition(widtha+i,j);			//0
#if DEBUG
					} else {
						*(index++) = getVertexPosition(widtha+i,j);			//0
						*(index++) = getVertexPosition(widtha+i,j+1);		//1
						*(index++) = getVertexPosition(widtha+i+1,j);		//2

						*(index++) = getVertexPosition(widtha+i+1,j+1);		//3
						*(index++) = getVertexPosition(widtha+i+1,j);		//2
						*(index++) = getVertexPosition(widtha+i,j+1);		//1
					}
#endif
				}
			}
		} else {
			std::cout << "ERROR : width = " << width << ", height = " << height << " level " << getLevel() << std::endl;
			std::cout << "innerUpperLeft " << innerUpperLeftQuad.x << "," << innerUpperLeftQuad.y << std::endl;
			std::cout << "innerLowerRight " << innerLowerRightQuad.x << "," << innerLowerRightQuad.y << std::endl;
			std::cout << "upperLeft " << upperLeftQuad.x << "," << upperLeftQuad.y << std::endl;
			std::cout << "lowerRight " << lowerRightQuad.x << "," << lowerRightQuad.y << std::endl;
			std::cout << "centerx " << centerx << " centerz " << centerz << std::endl;
		}
	}

	/**
	* Calculates the lower middle part of the clipmap.
	* @pre	The pointer should point to the position of the first index of this
	* 		part to be written in the indexBuffer
	*/
#if USE_16BIT_INDICES
	void ClipmapRegion::calculateC(unsigned short* &index){
#else
	void ClipmapRegion::calculateC(unsigned int* &index){
#endif
		int widtha = innerUpperLeftQuad.x-upperLeftQuad.x;
		int heighta = innerLowerRightQuad.y-upperLeftQuad.y+1;
		int totalHeight = lowerRightQuad.y-upperLeftQuad.y+1;
		int offset = (widtha)*(totalHeight+1)+innerLowerRightQuad.y-upperLeftQuad.y+1;

		int width = innerLowerRightQuad.x-innerUpperLeftQuad.x+1;
		int height = lowerRightQuad.y-innerLowerRightQuad.y;
		if ((width>=0)&&(height>=0)&&(width<=getSize())&&(height<=getSize())){
			for (int i=0;i<width;i++){
				for (int j=0;j<height;j++){
					//02
					//13
#if DEBUG
					if (upperLeftQuad.z % 2 == 0){
#endif
						*(index++) = getVertexPosition(widtha+i,heighta+j);			//0
						*(index++) = getVertexPosition(widtha+i,heighta+j+1);		//1
						*(index++) = getVertexPosition(widtha+i+1,heighta+j+1);		//3

						*(index++) = getVertexPosition(widtha+i+1,heighta+j+1);		//3
						*(index++) = getVertexPosition(widtha+i+1,heighta+j);		//2
						*(index++) = getVertexPosition(widtha+i,heighta+j);			//0
#if DEBUG
					} else {
						*(index++) = getVertexPosition(widtha+i,heighta+j);			//0
						*(index++) = getVertexPosition(widtha+i,heighta+j+1);		//1
						*(index++) = getVertexPosition(widtha+i+1,heighta+j);		//2

						*(index++) = getVertexPosition(widtha+i+1,heighta+j+1);		//3
						*(index++) = getVertexPosition(widtha+i+1,heighta+j);		//2
						*(index++) = getVertexPosition(widtha+i,heighta+j+1);		//1
					}
#endif
				}
			}
		} else {
			std::cout << "ERROR : width = " << width << ", height = " << height << " level " << getLevel() << std::endl;
			std::cout << "innerUpperLeft " << innerUpperLeftQuad.x << "," << innerUpperLeftQuad.y << std::endl;
			std::cout << "innerLowerRight " << innerLowerRightQuad.x << "," << innerLowerRightQuad.y << std::endl;
			std::cout << "upperLeft " << upperLeftQuad.x << "," << upperLeftQuad.y << std::endl;
			std::cout << "lowerRight " << lowerRightQuad.x << "," << lowerRightQuad.y << std::endl;
			std::cout << "centerx " << centerx << " centerz " << centerz << std::endl;
		}
	}

	/**
	* Calculates the right part of the clipmap.
	* @pre	The pointer should point to the position of the first index of this
	* 		part to be written in the indexBuffer
	*/
#if USE_16BIT_INDICES
	void ClipmapRegion::calculateD(unsigned short* &index){
#else
	void ClipmapRegion::calculateD(unsigned int* &index){
#endif
		int widtha = innerLowerRightQuad.x-upperLeftQuad.x+1;
		int totalHeight = lowerRightQuad.y-upperLeftQuad.y+1;
		int offset = (widtha)*(totalHeight+1);

		int width = lowerRightQuad.x-innerLowerRightQuad.x;
		int height = lowerRightQuad.y-upperLeftQuad.y+1;
		if ((width>=0)&&(height>=0)&&(width<=getSize())&&(height<=getSize())){
			for (int i=0;i<width;i++){
				for (int j=0;j<height;j++){
					//02
					//13
#if DEBUG
					if (upperLeftQuad.z % 2 == 0){
#endif
						*(index++) = getVertexPosition(widtha+i,j);			//0
						*(index++) = getVertexPosition(widtha+i,j+1);		//1
						*(index++) = getVertexPosition(widtha+i+1,j+1);		//3

						*(index++) = getVertexPosition(widtha+i+1,j+1);		//3
						*(index++) = getVertexPosition(widtha+i+1,j);		//2
						*(index++) = getVertexPosition(widtha+i,j);			//0
#if DEBUG
					} else {
						*(index++) = getVertexPosition(widtha+i,j);			//0
						*(index++) = getVertexPosition(widtha+i,j+1);		//1
						*(index++) = getVertexPosition(widtha+i+1,j);		//2

						*(index++) = getVertexPosition(widtha+i+1,j+1);		//3
						*(index++) = getVertexPosition(widtha+i+1,j);		//2
						*(index++) = getVertexPosition(widtha+i,j+1);		//1
					}
#endif
				}
			}
		} else {
			std::cout << "ERROR : width = " << width << ", height = " << height << " level " << getLevel() << std::endl;
			std::cout << "innerUpperLeft " << innerUpperLeftQuad.x << "," << innerUpperLeftQuad.y << std::endl;
			std::cout << "innerLowerRight " << innerLowerRightQuad.x << "," << innerLowerRightQuad.y << std::endl;
			std::cout << "upperLeft " << upperLeftQuad.x << "," << upperLeftQuad.y << std::endl;
			std::cout << "lowerRight " << lowerRightQuad.x << "," << lowerRightQuad.y << std::endl;
			std::cout << "centerx " << centerx << " centerz " << centerz << std::endl;
		}
	}

#if USE_16BIT_INDICES
	unsigned short* ClipmapRegion::getIndices(){
#else
	unsigned int* ClipmapRegion::getIndices(){
#endif


		if (changed) {
			calculateIndices();
		}
		return indices;
	}

	int ClipmapRegion::getIndexCount(){
		if (changed) {
			calculateIndices();
		}
		return indexCount;
	}

	void ClipmapRegion::setVertexBuffer(HardwareVertexBufferSharedPtr &vertexBuffer, int patchOffset){
		this->vertexBuffer = vertexBuffer;
		this->patchOffset=patchOffset;
	}
	void ClipmapRegion::setIndexBuffer(HardwareIndexBufferSharedPtr &indexBuffer){
		this->indexBuffer = indexBuffer;
	}
	void ClipmapRegion::updateVertexBuffer(){
		int i,j;
		Real* vertices = (Real*)vertexBuffer->lock((vertexOffset+patchOffset)*VERTEXSIZE*sizeof(Real),REGIONSURF*VERTEXSIZE*sizeof(Real),HardwareBuffer::HBL_NO_OVERWRITE);
		for (i=0;i<REGIONSURF;i++){
			for (j=0;j<VERTEXSIZE;j++){
				vertices[i*VERTEXSIZE+j] = this->vertices[i*VERTEXSIZE+j];
			}
		}
		vertexBuffer->unlock();
	}

	int ClipmapRegion::updateIndexBuffer(int offset){
		int count = getIndexCount();
#if USE_16BIT_INDICES
		unsigned short* indices = (unsigned short*)indexBuffer->lock(offset*sizeof(short),count*sizeof(short),HardwareBuffer::HBL_NO_OVERWRITE);
		unsigned short* index;
#else
		unsigned int* indices = (unsigned int*)indexBuffer->lock(offset*sizeof(int),count*sizeof(int),HardwareBuffer::HBL_NO_OVERWRITE);
		unsigned int* index;
#endif
		index = getIndices();
		int i;
		for (i=0;i<count;i++){
			indices[i] = index[i];
		}
		indexBuffer->unlock();
		return count;
	}

	void ClipmapRegion::setVertexOffset(int vertexOffset){
		this->vertexOffset = vertexOffset;
	}

	void ClipmapRegion::closeHole(){
		innerUpperLeftQuad = Vector3ix(centerx,centerz,innerUpperLeftQuad.z);
		innerLowerRightQuad = Vector3ix(centerx-1,centerz-1,innerUpperLeftQuad.z);
		changed=true;
	}

	bool ClipmapRegion::isVisible() const {
		return (!isTooBig()) && (isOnPatch());
	}

	bool ClipmapRegion::isOnPatch() const {
		return (upperLeftQuad.x <= lowerRightQuad.x)
			&& (upperLeftQuad.y <= lowerRightQuad.y);
	}

	bool ClipmapRegion::isTooBig() const {
		return (upperLeftQuad.x >= innerUpperLeftQuad.x) 
			&& (upperLeftQuad.y >= innerUpperLeftQuad.y)
			&& (lowerRightQuad.x <= innerLowerRightQuad.x)
			&& (lowerRightQuad.y <= innerLowerRightQuad.y);
	}

	void ClipmapRegion::setInnerUpperLeftQuad(Vector3ix innerUpperLeftQuad){
		this->innerUpperLeftQuad = innerUpperLeftQuad;
		changed = true;
	}

	void ClipmapRegion::setInnerLowerRightQuad(Vector3ix innerLowerRightQuad){
		this->innerLowerRightQuad = innerLowerRightQuad;
		changed = true;
	}

	const Vector3ix ClipmapRegion::getInnerUpperLeftQuad() const{
		return innerUpperLeftQuad;
	}

	const Vector3ix ClipmapRegion::getInnerLowerRightQuad() const{
		return innerLowerRightQuad;
	}

	const Vector3ix ClipmapRegion::getUpperLeftQuad() const{
		return upperLeftQuad;
	}

	const Vector3ix ClipmapRegion::getLowerRightQuad() const{
		return lowerRightQuad;
	}


	int ClipmapRegion::getLevelSize(int level) const {
		return mGeometryReader->getLevelSize(level)-1;
	}

	Vertex* ClipmapRegion::getQuad(Vector3ix quad){
		return mGeometryReader->getQuad(quad,mMap);
	}

	bool ClipmapRegion::isOverlappingEdge(int direction){
		bool overlaps;
		switch (direction){
		case N :
			overlaps = !isCompleteInUp();
			break;
		case S :
			overlaps = !isCompleteInDown();
			break;
		case E :
			overlaps = !isCompleteInRight();
			break;
		case W :
			overlaps = !isCompleteInLeft();
			break;
		}
		return isVisible()&&overlaps;
	}

	int ClipmapRegion::getRealAmountOverEdge(int direction){
		int amount;
		switch (direction) {
		case N:
			amount = (REGIONSIZE>>1) - centerz-2;
			if (amount > 0) {
				if (amount < REGIONSIZE) {
					return amount;
				} else {
					return REGIONSIZE;
				}
			}
			return 0;
		case S:
			amount = (REGIONSIZE>>1) - (getLevelSize(getLevel()) - centerz);
			if (amount > 0) {
				if (amount < REGIONSIZE) {
					return amount;
				} else {
					return REGIONSIZE;
				}
			}
			return 0;
		case W:
			amount = (REGIONSIZE>>1) - centerx-2;
			if (amount > 0) {
				if (amount < REGIONSIZE) {
					return amount;
				} else {
					return REGIONSIZE;
				}
			}
			return 0;
		case E:
			amount = (REGIONSIZE>>1) - (getLevelSize(getLevel()) - centerx);
			if (amount > 0) {
				if (amount < REGIONSIZE) {
					return amount;
				} else {
					return REGIONSIZE;
				}
			}
			return 0;
		}
		return 0;
	}

	int ClipmapRegion::getAmountOverEdge(int direction){
		if ((CUBEA!=0)||(CUBEB!=6)) return 0;
		int neighbourNb = getNeighbour(direction);
		int newdirection = getNeighbourDirection(direction);
		if ((*(otherRegions[neighbourNb])).size() > (size_t)getLevel()) {
			ClipmapRegion* neighbour = (*(otherRegions[neighbourNb]))[getLevel()];
			int size = REGIONSIZE-(neighbour->getRealAmountOverEdge((newdirection+2)%4));
			return size;
		}
		return 0;
	}

	int ClipmapRegion::getNeighbour(int direction){
		switch (mMap) {
		case 0 :
		case 1 :
		case 2 :
		case 3 :
			switch (direction) {
		case N :
			return 4;
			break;
		case S :
			return 5;
			break;
		case E :
			return (mMap+1)%4;
			break;
		case W :
			return (mMap+3)%4;
			break;
			}
			break;
		case 4 :
			switch (direction) {
		case N :
			return 3;
			break;
		case S :
			return 1;
			break;
		case E :
			return 2;
			break;
		case W :
			return 0;
			break;
			}			
			break;
		case 5 :
			switch (direction) {
		case N :
			return 3;
			break;
		case S :
			return 1;
			break;
		case E :
			return 0;
			break;
		case W :
			return 2;
			break;
			}			
			break;
		}
		return 0;
	}

	int ClipmapRegion::getNeighbourDirection(int direction){
		switch (mMap) {
		case 0 :
			switch (direction) {
		case N :
			return E;
		case S :
			return W;
			break;
		case E :
		case W :
			return direction;
			break;
			}
			break;
		case 1 :
			switch (direction) {
		case S :
			return N;
			break;
		case N :
		case E :
		case W :
			return direction;
			break;
			}
			break;
		case 2 :
			switch (direction) {
		case N :
			return W;
			break;
		case S :
			return E;
			break;
		case E :
		case W :
			return direction;
			break;
			}
			break;
		case 3 :
			switch (direction) {
		case S :
		case N :
			return S;
			break;
		case E :
		case W :
			return direction;
			break;
			}
			break;
		case 4 :
			switch (direction) {
		case N :
		case S :
		case E :
		case W :
			return S;
			break;
			}			
			break;
		case 5 :
			switch (direction) {
		case N :
		case S :
		case E :
		case W :
			return N;
			break;
			}			
			break;
		}
		return 0;
	}

	void ClipmapRegion::setOtherRegions(int index, std::vector<ClipmapRegion*> *regions){
		if ((index < CUBEA)||(index >= CUBEB)){
			std::cout << "ERROR : not a valid patch index " << index << std::endl;
		} else {
			otherRegions[index] = regions;
		}
	}

}
