// IslandDoc.cpp : implementation of the CIslandDoc class
//

#include "stdafx.h"

#include "Helpers/Texture.h"
#include "IslandWorld.h"
#include "rock.h"
#include "Helpers/Helper.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CIslandWorld construction/destruction

CIslandWorld::CIslandWorld()
{
	// TODO: add one-time construction code here
	m_nDisplayMethod = -1;
	m_islandObjectsBoundingBoxTree = NULL;
	m_islandGroundBoundingBoxTree = NULL;

	m_guyPerson = new CIslandPerson(MAN);
	m_girlPerson = new CIslandPerson(WOMAN);
	m_godPerson = new CIslandPerson(GOD);
	//put where the top of their heads will be
	m_guyPerson->SetInitialPosition(10,40,0);
	m_girlPerson->SetInitialPosition(-10,40,0);
	m_godPerson->SetInitialPosition(0,40,0);


	m_currentPerson = m_guyPerson;
	m_bDead = false;
}

CIslandWorld::~CIslandWorld()
{
	//delete the list of faces
	int count = m_cliffsBackGlobal.GetCount();
	while (count > 0){
		CFace* obj = m_cliffsBackGlobal.RemoveHead();
		delete(obj);
		count--;
	}
	count = m_cliffsFrontGlobal.GetCount();
	while (count > 0){
		CFace* obj = m_cliffsFrontGlobal.RemoveHead();
		delete(obj);
		count--;
	}
	count = m_cliffsLeftGlobal.GetCount();
	while (count > 0){
		CFace* obj = m_cliffsLeftGlobal.RemoveHead();
		delete(obj);
		count--;
	}
	count = m_cliffsRightGlobal.GetCount();
	while (count > 0){
		CFace* obj = m_cliffsRightGlobal.RemoveHead();
		delete(obj);
		count--;
	}
	
	count = m_groundGlobal.GetCount();
	while (count > 0){
		CFace* obj = m_groundGlobal.RemoveHead();
		delete(obj);
		count--;
	}

	//delete the list of rocks
	count = m_rocks.GetCount();
	while (count > 0){
		CRock* obj = m_rocks.RemoveHead();
		delete(obj);
		count--;
	}

	count = m_rocksGlobal.GetCount();
	while (count > 0){
		CRock* obj = m_rocksGlobal.RemoveHead();
		delete(obj);
		count--;
	}
	count = m_children.GetCount();
	while (count > 0){
		CIslandPerson* obj = m_children.RemoveHead();
		delete(obj);
		count--;
	}

	if (m_islandObjectsBoundingBoxTree != NULL)
		delete (m_islandObjectsBoundingBoxTree);

	if (m_islandGroundBoundingBoxTree != NULL)
		delete (m_islandGroundBoundingBoxTree);

	delete(m_guyPerson);
	delete(m_girlPerson);
	delete(m_godPerson);
}

/////////////////////////////////////////////////////////////////////////////
// CIslandDoc serialization

void CIslandWorld::Serialize(CArchive& ar)
{
	if (ar.IsStoring())
	{
		// TODO: add storing code here
		ar << m_bDead;
		ar << m_nCurrentWeather;
		ar << m_nDisplayMethod;

		//write out the people
		m_girlPerson->Serialize(ar);
		m_godPerson->Serialize(ar);
		m_guyPerson->Serialize(ar);

		ar << m_currentPerson->GetID();
		//write out the kids
		ar << m_children.GetCount();
		POSITION pos = m_children.GetHeadPosition();
	  while (pos != NULL)
	  {
		  CIslandPerson* person = m_children.GetAt(pos);
		  person->Serialize(ar);
		  m_children.GetNext(pos);
	  }
	}
	else
	{
		// TODO: add loading code here
		ar >> m_bDead;
		ar >> m_nCurrentWeather;
		ar >> m_nDisplayMethod;

		//delete these people before reading them in
    delete(m_guyPerson);
	  delete(m_girlPerson);
	  delete(m_godPerson);
		m_guyPerson = new CIslandPerson();
	  m_girlPerson = new CIslandPerson();
	  m_godPerson = new CIslandPerson();

		m_girlPerson->Serialize(ar);
		m_godPerson->Serialize(ar);
		m_guyPerson->Serialize(ar);

		int currentPerson;
		ar >> currentPerson;
		if (currentPerson == MAN)
			m_currentPerson = m_guyPerson;
		else if (currentPerson == WOMAN)
			m_currentPerson = m_girlPerson;
		else
			m_currentPerson = m_godPerson;
		//delete the old kids list
		int count = m_children.GetCount();
	  while (count > 0){
		  CIslandPerson* obj = m_children.RemoveHead();
		  delete(obj);
		  count--;
	  }
    int nKidsCount;
		ar >> nKidsCount;
		for (int i = 0; i < nKidsCount; i++)
		{
			CIslandPerson* kid = new CIslandPerson();
			kid->Serialize(ar);
			m_children.AddHead(kid);
		}
	}
}

/////////////////////////////////////////////////////////////////////////////
// CIslandDoc commands

//load all the bitmaps we will be using.
//The ones for the sky, rocks,water, and grass.
void CIslandWorld::CreateIsland(void)
{
	// Build the scene
	// Create the display lists

	// Draw the sky
	m_skyColor[0] = 0.5f;
	m_skyColor[1] = 0.5f;
	m_skyColor[2] = 1.0f;
	m_skyColor[3] = 1.0f;
	m_skyTexture.TextureLoadBitmap("sky.bmp");
	CreateSky();

	//load up and create the water
	m_waterColor[0] = 0.0f;
	m_waterColor[1] = 0.0f;
	m_waterColor[2] = 1.0f;
	m_waterColor[3] = 1.0f;
	m_waterTexture.TextureLoadMipmap("water.bmp");
	CreateWater();

	//load up and create the land
	m_landColor[0] = 0.0f;
	m_landColor[1] = 1.0f;
	m_landColor[2] = 0.0f;
	m_landColor[3] = 1.0f;
	m_landTexture.TextureLoadMipmap("grass.bmp");
	m_rockColor[0] = 0.6f;
	m_rockColor[1] = 0.4f;
	m_rockColor[2] = 0.12f;
	m_rockColor[3] = 1.0f;
	m_rockTexture.TextureLoadMipmap("rock.bmp");
	//also sets up the member vairables for the cliffs
	CreateLand();
	CreateBoundingBoxTree();

	//do be able to set up initial height
	m_guyPerson->MoveOrTurnInDirection(VK_UP, false,
		m_islandObjectsBoundingBoxTree,m_islandGroundBoundingBoxTree, NULL);

	m_girlPerson->MoveOrTurnInDirection(VK_DOWN, false,
		m_islandObjectsBoundingBoxTree,m_islandGroundBoundingBoxTree, NULL);
	
}

//the sky will encompass the whole world
void CIslandWorld::CreateSky(void)
{
	//the top plane of the sky
	float fSkyLimit = (float)(WORLD_SIZE * 2);
	float	sky_top[4][3] =
	{			
		{ (float)(-WORLD_SIZE * WORLD_SCALE), fSkyLimit,(float)(-WORLD_SIZE * WORLD_SCALE)}, //back left
    { (float)(WORLD_SIZE * WORLD_SCALE), fSkyLimit,(float)(-WORLD_SIZE * WORLD_SCALE) },//back right
    { (float)(WORLD_SIZE * WORLD_SCALE), fSkyLimit, (float)(WORLD_SIZE* WORLD_SCALE) },//front right
    { (float)(-WORLD_SIZE * WORLD_SCALE), fSkyLimit, (float)(WORLD_SIZE* WORLD_SCALE)}//front left
  };

	//the bottom plane of the sky.
	//make this low enough so that it intersects with some but
	//not all of the grount.
	float fSkyBottom = -fSkyLimit;
  float	sky_bottom[4][3] =
  {
    { (float)(-WORLD_SIZE * WORLD_SCALE), fSkyBottom, (float)(-WORLD_SIZE * WORLD_SCALE)},//back left
    { (float)(WORLD_SIZE * WORLD_SCALE), fSkyBottom, (float)(-WORLD_SIZE* WORLD_SCALE)},//back right
    { (float)(WORLD_SIZE * WORLD_SCALE), fSkyBottom, (float) (WORLD_SIZE * WORLD_SCALE) },//front right
    { (float)(-WORLD_SIZE * WORLD_SCALE), fSkyBottom, (float) (WORLD_SIZE* WORLD_SCALE)}//front left
  };

	glNewList(SKY_LIST,GL_COMPILE);
		//where to draw it
		//load the identity because if we used the current matrix, as we turned
		//it would appear the sky gets distorted.
		glPushMatrix();
		
		//right side
		glBegin(GL_POLYGON);
			glTexCoord2d(1.0, 1.0); glVertex3fv(sky_top[2]); //front top right
			glTexCoord2d(1.0, 0.0); glVertex3fv(sky_bottom[2]); //front lower right
			glTexCoord2d(0.0, 0.0); glVertex3fv(sky_bottom[1]); //back lower left
			glTexCoord2d(0.0, 1.0); glVertex3fv(sky_top[1]); //back upper left
		glEnd();
	
		//left side
		glBegin(GL_POLYGON);
			glTexCoord2d(1.0, 0.0); glVertex3fv(sky_bottom[3]); //front lower right
			glTexCoord2d(1.0, 1.0); glVertex3fv(sky_top[3]); //front upper right
			glTexCoord2d(0.0, 1.0); glVertex3fv(sky_top[0]); //back upper left
			glTexCoord2d(0.0, 0.0); glVertex3fv(sky_bottom[0]); //back lower left
		glEnd();
	
		//front
		glBegin(GL_POLYGON);
			glTexCoord2d(1.0, 1.0); glVertex3fv(sky_top[2]); //upper right
			glTexCoord2d(0.0, 1.0); glVertex3fv(sky_top[3]); //upper left
			glTexCoord2d(0.0, 0.0); glVertex3fv(sky_bottom[3]); //lower left
			glTexCoord2d(1.0, 0.0); glVertex3fv(sky_bottom[2]); //lower right
		glEnd();

		//back
		glBegin(GL_POLYGON);
			glTexCoord2d(0.0, 1.0); glVertex3fv(sky_top[0]); //upper left
			glTexCoord2d(1.0, 1.0); glVertex3fv(sky_top[1]); //upper right
			glTexCoord2d(1.0, 0.0); glVertex3fv(sky_bottom[1]); //lower right
			glTexCoord2d(0.0, 0.0); glVertex3fv(sky_bottom[0]); //lower left
		glEnd();
		//top
		glBegin(GL_POLYGON);
			glTexCoord2d(0.0, 1.0); glVertex3fv(sky_top[0]); //upper left
			glTexCoord2d(1.0, 1.0); glVertex3fv(sky_top[1]); //upper right
			glTexCoord2d(1.0, 0.0); glVertex3fv(sky_top[2]); //lower right
			glTexCoord2d(0.0, 0.0); glVertex3fv(sky_top[3]); //lower left
		glEnd();

		
		glPopMatrix();
	
	glEndList();
}


void CIslandWorld::DrawIslandScene(void)
{
	//m_nDisplayMethod = COLORED;
	glColor4f(1.0, 1.0, 1.0, 1.0);
	glClearColor(0.5,0.5,1.0,1.0);
  glEnable(GL_DEPTH_TEST);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	//now arrang for fog if the weather is foggy
	if (m_nCurrentWeather == FOGGY)
	{
		glEnable(GL_FOG);
		glFogf(GL_FOG_DENSITY, (float)0.005);
		glFogi(GL_FOG_MODE, GL_EXP);
		float dFogColor[4] = {(float)1.0, (float)1.0, (float)1.0, (float)1.0};
		glFogfv(GL_FOG_COLOR, dFogColor);
	}
	else
	{
		glDisable(GL_FOG);
	}

	//deal with the camera positioning
	glLoadMatrixd(m_currentPerson->GetPointOfViewMatrix());

	//draw the sky
	if (m_nDisplayMethod == TEXTURED)
	{
		//enables it for all textures
		glEnable(GL_TEXTURE_2D);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
		m_skyTexture.MakeCurrent();
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	}
	else
	{
		//disables it for all textures
		glDisable(GL_TEXTURE_2D);
		glColor4fv(m_skyColor);
	}
	glCallList(SKY_LIST);
	
	
	//always replace the sky witht he water, and the water with
	//the ground.
	//draw the water
	glDepthFunc(GL_ALWAYS);
	if (m_nDisplayMethod == TEXTURED)
	{
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    m_waterTexture.MakeCurrent();
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);
  }
	else
	{
		glColor4fv(m_waterColor);
	}
	glCallList(WATER_LIST);
	
	//In the dawring of the ground we switch to glDepthFunc(GL_LESS)
	//to do the cliffs
	if (m_nDisplayMethod == TEXTURED)
	{
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    m_landTexture.MakeCurrent();
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);
	}
	else
	{
		glColor4fv(m_landColor);
	}	
	glCallList(LAND_LIST);
	

	//now draw the cliffs
	glDepthFunc(GL_LESS);
	if (m_nDisplayMethod == TEXTURED)
	{
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
		m_rockTexture.MakeCurrent();
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);
  }
	else
	{
		glColor4fv(m_rockColor);
	}	
	glCallList(CLIFFS_LIST);
	//now draw the rocks on the island
	//they use the same bitmap or color as the cliff side
	DrawRocks();
	
	if (!(m_currentPerson->GetID() == MAN))
		m_guyPerson->Draw();
	if (!(m_currentPerson->GetID() == WOMAN))
		m_girlPerson->Draw();

	//draw the kids
	POSITION pos = m_children.GetHeadPosition();
	while (pos != NULL)
	{
		CIslandPerson* person = m_children.GetAt(pos);
		person->Draw();
		m_children.GetNext(pos);
	}

	glPopMatrix();

}

//setup everything to draw the land of the island
void CIslandWorld::CreateLand()
{
	//randomly create the height of the terrain.
	//The terrain is divided into little cells this way, each
	//with its own height, to appear more realistic.
	double dTerrainHeights[TERRAIN_SIZE][TERRAIN_SIZE];
	srand(500); //because I like the terrain it generates with this
	for (int s = 0; s < TERRAIN_SIZE; s ++)
	{
    for (int x = 0; x < TERRAIN_SIZE; x ++)
    {
			//a height between 0 and -0.4
			dTerrainHeights[s][x] = -(GRASS_HEIGHT + 0.1 * (rand() % 5));
		};
	}

	SetupCliffs(dTerrainHeights);
	SetupRocks(dTerrainHeights);

	//sets up the land co-ordinates
	glNewList(LAND_LIST,GL_COMPILE);
		glPushMatrix();
		//move it up because this sits ontop of rocks
		double dYUp = 35.0;
		glTranslated(0.0, dYUp, 0.0);
		glScalef((float)TERRAIN_SCALE, (float)TERRAIN_SCALE,
				(float)TERRAIN_SCALE);
		for (int y = 0; y < (TERRAIN_SIZE - 1); y ++)
		{
			for (int x = 0; x < TERRAIN_SIZE; x ++)
			{
        glBegin(GL_QUAD_STRIP);
				//draw the back left for this cell.
				//we use the height of the cell that was before us.
				//if we are the beginning of a row use the height of
				//the cell directly above us.  If we are the very first cell
				//use the height of the last cell in our row.
				glTexCoord2i(0, 1);
				if (x == 0)
				{
					if ( y == 0)
					{
						glVertex3f((float)(x - TERRAIN_EDGE - 1),
	               (float)dTerrainHeights[y][TERRAIN_SIZE - 1],
									(float)(y - TERRAIN_EDGE));
					}
					else
					{
						glVertex3f((float)(x - TERRAIN_EDGE - 1),
	               (float)dTerrainHeights[y - 1][TERRAIN_SIZE - 1],
									(float)(y - TERRAIN_EDGE));
					}
				}
				else
				{
					glVertex3f((float)(x - TERRAIN_EDGE - 1),
	               (float)dTerrainHeights[y][x - 1],
								 (float)(y - TERRAIN_EDGE));
				}

				//draw the front left for this cell
				//use the height of the cell below us and to our left.
				//If we are the first cell, this takes the height
				//of the last cell in our row.
				glTexCoord2i(0, 0);
				glVertex3f((float)(x - TERRAIN_EDGE - 1),
	               (float)dTerrainHeights[y + 1][x - 1],
		       (float)(y - TERRAIN_EDGE + 1));

				//draw the back right for this cell.
				//Use the height we want for this cell.
				glTexCoord2i(1, 1);
				glVertex3f((float)(x - TERRAIN_EDGE),
	           (float)dTerrainHeights[y][x],
	           (float)(y - TERRAIN_EDGE));

				//draw the front right for this cell.
				//Use the height of the cell directly below us.
				glTexCoord2i(1, 0);
				glVertex3f((float)(x - TERRAIN_EDGE),
	           (float)dTerrainHeights[y + 1][x],
	           (float)(y - TERRAIN_EDGE + 1));
	 
				glEnd();
			};
    };

  glPopMatrix();
	glEndList();

	//duplicate this for the face co-ordinates
	for (y = 0; y <  (TERRAIN_SIZE - 1); y ++)
		{
			for (int x = 0; x < TERRAIN_SIZE; x ++)
			{
				CFace * face = new CFace();
				//the back left for this cell.
				double dHeight = 0;
				if (x == 0)
				{
					if ( y == 0)
					{
						dHeight = dTerrainHeights[y][TERRAIN_SIZE - 1];
					}
					else
					{
						dHeight = dTerrainHeights[y - 1][TERRAIN_SIZE - 1];
					}
				}
				else
				{
					dHeight = dTerrainHeights[y][x - 1];
				}
				C3DPoint * pointBackLeft = new C3DPoint(x - TERRAIN_EDGE - 1,
															dHeight,
															y - TERRAIN_EDGE);
				face->AddPoint(pointBackLeft);

				//draw the front left for this cell
				C3DPoint * pointFrontLeft = new C3DPoint(x - TERRAIN_EDGE - 1,
															dTerrainHeights[y + 1][x - 1],
															y - TERRAIN_EDGE + 1);
				face->AddPoint(pointFrontLeft);

				//draw the front right for this cell.
				C3DPoint * pointFrontRight = new C3DPoint(x - TERRAIN_EDGE,
															dTerrainHeights[y + 1][x],
															y - TERRAIN_EDGE + 1);
				face->AddPoint(pointFrontRight);

				//draw the back right for this cell
				C3DPoint * pointBackRight = new C3DPoint(x - TERRAIN_EDGE,
															dTerrainHeights[y][x],
															y - TERRAIN_EDGE);

				face->AddPoint(pointBackRight);

				m_groundGlobal.AddHead(ComputeGlobalLandFaceFor(face));
				delete(face);
	 
			};
    };
}

//move a predefine amount in the direction nChar.
void CIslandWorld::KeyPressedInDirection(int nChar)
{
	//ignore key presses if we are dead
	//unless we are god
	if (m_bDead && m_currentPerson->GetID() != GOD)
		return;
	//need to pass ina list of the other people on the island
	//to do collision detection with them
	CList<CIslandPerson*, CIslandPerson*> otherPeople;
	if (m_currentPerson->GetID() == MAN)
	{
		otherPeople.AddHead(m_girlPerson);
	}
	else if (m_currentPerson->GetID() == WOMAN)
	{
		otherPeople.AddHead(m_guyPerson);
	}
	POSITION pos = m_children.GetHeadPosition();
	while (pos != NULL)
	{
		CIslandPerson* person = m_children.GetAt(pos);
		otherPeople.AddHead(person);
		m_children.GetNext(pos);
	}

	//this sets up the persons next camera translations
	CIslandPerson* kid = m_currentPerson->MoveOrTurnInDirection(nChar, false,
		m_islandObjectsBoundingBoxTree,m_islandGroundBoundingBoxTree, &otherPeople);
	if (kid)
	{
		if (m_children.GetCount() == MAX_CHILDREN
			&& !(kid->GetID() == GIRL || kid->GetID() == BOY))
		{
			CString message = "You have created another child.\n";
			message += "You have too many now.\n";
			message += "You have used up the limited resources on this island.\n";
			message += "You all starve to death!";
			::MessageBox(NULL,message, "Procreation=Death", MB_OK);
			m_bDead = true;
		}
		else if (kid->GetID() == GIRL || kid->GetID() == BOY)
		{
			::MessageBox(NULL,"Please don't step on your kids", "Be More Careful", MB_OK);
		}
		else
		{
			::MessageBox(NULL,"You have created another child.\nYou might want to look around for him/her.", "Procreation", MB_OK);
		//create a child
			CIslandPerson * child;
			int nNumKids = m_children.GetCount();
			switch (nNumKids)
			{
				case 0:
					child = new CIslandPerson(GIRL);
					child->SetInitialPosition(15,40,0);
					break;
				case 1:
					child = new CIslandPerson(BOY);
					child->SetInitialPosition(30,40,-10);
					break;
				case 2:
					child = new CIslandPerson(BOY);
					child->SetInitialPosition(55,40,-25);
					break;
				case 3:
					child = new CIslandPerson(GIRL);
					child->SetInitialPosition(40,40,50);
					break;
				case 4:
					child = new CIslandPerson(GIRL);
					child->SetInitialPosition(60,40,75);
					break;
			}
			m_children.AddHead(child);
		}
	}
}

void CIslandWorld::KeyUpInDirection(int nChar)
{
	//ignore key presses if we are dead
	//unless we are god
	if (m_bDead && m_currentPerson->GetID() != GOD)
		return;
	//this sets up the persons next camera translations
	m_currentPerson->MoveOrTurnInDirection(nChar, true,
		m_islandObjectsBoundingBoxTree,m_islandGroundBoundingBoxTree, NULL);
}

//create the wate that goes around the island
void CIslandWorld::CreateWater()
{
	//randomly create the height of the water.
	//The water is divided into little cells this way, each
	//with its own height, to appear more realistic.
	double dWaterHeights[WORLD_SIZE][WORLD_SIZE];
	srand(500); //because I like the terrain it generates with this
	for (int y = 0; y < WORLD_SIZE; y ++)
	{
    for (int x = 0; x < WORLD_SIZE; x ++)
    {
			//a height between 0 and -0.2
			dWaterHeights[y][x] = -(WATER_HEIGHT + 0.1 * (rand() % 2));
		};
	}

	glNewList(WATER_LIST,GL_COMPILE);
		glPushMatrix();
		glTranslatef(0,-35, 0);
		glScalef((float)WATER_SCALE, (float)WATER_SCALE,
				(float)WATER_SCALE);
		
		//cover bottom of world with water
		for (y = 0; y < (WORLD_SIZE - 1); y ++)
    {

      for (int x = 0; x < WORLD_SIZE; x ++)
      {
        glBegin(GL_QUAD_STRIP);

				//draw the back left for this cell.
				//we use the height of the cell that was before us.
				//if we are the beginning of a row use the height of
				//the cell directly above us.  If we are the very first cell
				//use the height of the last cell in our row.
				glTexCoord2i(0, 1);
				if (x == 0)
				{
					if ( y == 0)
					{
						glVertex3f((float)(x - WORLD_EDGE - 1),
	               (float)dWaterHeights[y][WORLD_SIZE - 1],
									(float)(y - WORLD_EDGE));
					}
					else
					{
						glVertex3f((float)(x - WORLD_EDGE - 1),
	               (float)dWaterHeights[y - 1][WORLD_SIZE - 1],
									(float)(y - WORLD_EDGE));
					}
				}
				else
				{
					glVertex3f((float)(x - WORLD_EDGE - 1),
	               (float)dWaterHeights[y][x - 1],
								 (float)(y - WORLD_EDGE));
				}

				//draw the front left for this cell
				//use the height of the cell below us and to our left.
				//If we are the first cell, this takes the height
				//of the last cell in our row.
				glTexCoord2i(0, 0);
				glVertex3f((float)(x - WORLD_EDGE - 1),
	               (float)dWaterHeights[y + 1][x - 1],
		       (float)(y - WORLD_EDGE + 1));


				//draw the back right for this cell.
				//Use the height we want for this cell.
				glTexCoord2i(1, 1);
				glVertex3f((float)(x - WORLD_EDGE),
	           (float)dWaterHeights[y][x],
	           (float)(y - WORLD_EDGE));

				//draw the front right for this cell.
				//Use the height of the cell directly below us.
				glTexCoord2i(1, 0);
				glVertex3f((float)(x - WORLD_EDGE),
	           (float)dWaterHeights[y + 1][x],
	           (float)(y - WORLD_EDGE + 1));

				glEnd();
     };
	
  };
  glPopMatrix();
	glEndList();
}


//draws the Plygon defined by the points in dRocksCoords
//This forms the "cliffs" going down from the grass to the water
void CIslandWorld::DrawCliffSide(double  dRockCoords[TERRAIN_SIZE][2][3],  double dHeight, int numCells)
{
	for (int x = 0; x < numCells; x++)
	{
		glBegin(GL_POLYGON);
		
		//top left
		glTexCoord2i(0, 1);
		glVertex3dv(dRockCoords[x][0]);
		
		//top right
		glTexCoord2i(0, 0);
		glVertex3dv(dRockCoords[x][1]);
		
		//bottom right
		double *dBottomRight = dRockCoords[x][1];
		glTexCoord2i(1, 0);
		glVertex3d(dBottomRight[0],
							-dHeight,
							dBottomRight[2]);

		//bottom left
		double *dBottomLeft = dRockCoords[x][0];
		glTexCoord2i(1, 1);
		glVertex3d(dBottomLeft[0],
							-dHeight,
							dBottomLeft[2]);
		
		glEnd();
	}
}

//return the code describing the current weather conditions
int CIslandWorld::GetWeather()
{
	return m_nCurrentWeather;
}

void CIslandWorld::SetWeather(int nWeather)
{
	m_nCurrentWeather = nWeather;
}

int CIslandWorld::GetDisplayMethod(void)
{
	return m_nDisplayMethod;
}

void CIslandWorld::ToggleCurrentDisplayMethod(void)
{
	if (m_nDisplayMethod == TEXTURED)
	{
		m_nDisplayMethod = COLORED;
	}
	else 
	{
		m_nDisplayMethod = TEXTURED;
	}
}

//create the clifs that run along the sides
void CIslandWorld::SetupCliffs(double dTerrainHeights[TERRAIN_SIZE][TERRAIN_SIZE])
{
	double dRockFrontCoords[TERRAIN_SIZE][2][3];
	double dRockBackCoords[TERRAIN_SIZE][2][3];
	double dRockLeftCoords[TERRAIN_SIZE - 1][2][3];
	double dRockRightCoords[TERRAIN_SIZE - 1][2][3];

	//setup the cliff side array: This only needs to be done once
	//we also care about colliding with these so keep them
	//for the faces
	double dHeight = 2;
	for (int y = 0; y < (TERRAIN_SIZE - 1); y ++)
  {
		for (int x = 0; x < TERRAIN_SIZE; x ++)
     {
				double dBackLeftHeight = 0.0;
				if (x == 0)
				{
					if ( y == 0)
					{
						dBackLeftHeight = dTerrainHeights[y][TERRAIN_SIZE - 1];
					}
					else
					{
						dBackLeftHeight = dTerrainHeights[y - 1][TERRAIN_SIZE - 1];
					}
				}
				else
				{
					dBackLeftHeight = dTerrainHeights[y][x - 1];
				}
				//I record to co-ordinates for the sides
				//so the side rock terrain can be drawn later
				if (y == 0)
				{
					CFace * face = new CFace();
					//remeber the front coordinates
					dRockFrontCoords[x][0][0] = x - TERRAIN_EDGE - 1;
					dRockFrontCoords[x][0][1] = dBackLeftHeight;
					dRockFrontCoords[x][0][2] = (float)(y - TERRAIN_EDGE);
					
					//take care of the left side of the face
					C3DPoint * pointTopLeft = new C3DPoint(dRockFrontCoords[x][0][0],
															dRockFrontCoords[x][0][1],
															dRockFrontCoords[x][0][2]);
					face->AddPoint(pointTopLeft);
					C3DPoint* pointBotLeft = new C3DPoint(dRockFrontCoords[x][0][0],
															-dHeight,
															dRockFrontCoords[x][0][2]);
					face->AddPoint(pointBotLeft);

					dRockFrontCoords[x][1][0] = x - TERRAIN_EDGE;
					dRockFrontCoords[x][1][1] = (float)dTerrainHeights[y][x];
					dRockFrontCoords[x][1][2] = (float)(y - TERRAIN_EDGE);
				
					//the right side of the face
					C3DPoint* pointBotRight = new C3DPoint(dRockFrontCoords[x][1][0],
															-dHeight,
															dRockFrontCoords[x][1][2]);
					face->AddPoint(pointBotRight);
					C3DPoint* pointTopRight = new C3DPoint(dRockFrontCoords[x][1][0],
															dRockFrontCoords[x][1][1],
															dRockFrontCoords[x][1][2]);
					face->AddPoint(pointTopRight);
					m_cliffsFrontGlobal.AddHead(ComputeGlobalCliffFaceFor(face));
					delete(face);
				}
				//remomber the back coordinates
				if (y == TERRAIN_SIZE - 2)
				{
					CFace * face = new CFace();
					dRockBackCoords[x][0][0] = x - TERRAIN_EDGE - 1;
					dRockBackCoords[x][0][1] = dTerrainHeights[y + 1][x - 1];
					dRockBackCoords[x][0][2] = (float)(y - TERRAIN_EDGE + 1);
					
					//take care of the left side of the face
					C3DPoint * pointTopLeft = new C3DPoint(dRockBackCoords[x][0][0],
															dRockBackCoords[x][0][1],
															dRockBackCoords[x][0][2]);
					face->AddPoint(pointTopLeft);
					C3DPoint* pointBotLeft = new C3DPoint(dRockBackCoords[x][0][0],
															-dHeight,
															dRockBackCoords[x][0][2]);
					face->AddPoint(pointBotLeft);


					dRockBackCoords[x][1][0] = x - TERRAIN_EDGE;
					dRockBackCoords[x][1][1] = (float)dTerrainHeights[y + 1][x];
					dRockBackCoords[x][1][2] = (float)(y - TERRAIN_EDGE + 1);
				
					//the right side of the face
					C3DPoint* pointBotRight = new C3DPoint(dRockBackCoords[x][1][0],
															-dHeight,
															dRockBackCoords[x][1][2]);
					face->AddPoint(pointBotRight);
					C3DPoint* pointTopRight = new C3DPoint(dRockBackCoords[x][1][0],
															dRockBackCoords[x][1][1],
															dRockBackCoords[x][1][2]);
					face->AddPoint(pointTopRight);
					m_cliffsBackGlobal.AddHead(ComputeGlobalCliffFaceFor(face));
					delete(face);
				}
				//remember the left
				if (x == 0)
				{
					CFace * face = new CFace();
					//used back left and front left
					dRockLeftCoords[y][0][0] = x - TERRAIN_EDGE - 1;
					dRockLeftCoords[y][0][1] = dBackLeftHeight;
					dRockLeftCoords[y][0][2] = (float)(y - TERRAIN_EDGE);
					//take care of the left side of the face
					C3DPoint * pointTopLeft = new C3DPoint(dRockLeftCoords[y][0][0],
															dRockLeftCoords[y][0][1],
															dRockLeftCoords[y][0][2]);
					face->AddPoint(pointTopLeft);
					C3DPoint* pointBotLeft = new C3DPoint(dRockLeftCoords[y][0][0],
															-dHeight,
															dRockLeftCoords[y][0][2]);
					face->AddPoint(pointBotLeft);

					dRockLeftCoords[y][1][0] = x - TERRAIN_EDGE - 1;
					dRockLeftCoords[y][1][1] = (float)dTerrainHeights[y + 1][x - 1];
					dRockLeftCoords[y][1][2] = (float)(y - TERRAIN_EDGE + 1);
					//take care of the right side of the face
					C3DPoint* pointBotRight = new C3DPoint(dRockLeftCoords[y][1][0],
															-dHeight,
															dRockLeftCoords[y][1][2]);
					face->AddPoint(pointBotRight);
					C3DPoint * pointTopRight = new C3DPoint(dRockLeftCoords[y][1][0],
															dRockLeftCoords[y][1][1],
															dRockLeftCoords[y][1][2]);
					face->AddPoint(pointTopRight);
					m_cliffsLeftGlobal.AddHead(ComputeGlobalCliffFaceFor(face));
					delete(face);
				}
				//remember the right
				if (x == TERRAIN_SIZE - 1)
				{
					CFace * face = new CFace();
					//use back right and front right
					dRockRightCoords[y][0][0] = x - TERRAIN_EDGE;
					dRockRightCoords[y][0][1] = (float)dTerrainHeights[y][x];
					dRockRightCoords[y][0][2] = (float)(y - TERRAIN_EDGE);
					//take care of the left side of the face
					C3DPoint * pointTopLeft = new C3DPoint(dRockRightCoords[y][0][0],
															dRockRightCoords[y][0][1],
															dRockRightCoords[y][0][2]);
					face->AddPoint(pointTopLeft);
					C3DPoint* pointBotLeft = new C3DPoint(dRockRightCoords[y][0][0],
															-dHeight,
															dRockRightCoords[y][0][2]);
					face->AddPoint(pointBotLeft);

					dRockRightCoords[y][1][0] = x - TERRAIN_EDGE;
					dRockRightCoords[y][1][1] = (float)dTerrainHeights[y + 1][x];
					dRockRightCoords[y][1][2] = (float)(y - TERRAIN_EDGE + 1);
				
					//take care of the right side of the face
					C3DPoint* pointBotRight = new C3DPoint(dRockRightCoords[y][1][0],
															-dHeight,
															dRockRightCoords[y][1][2]);
					face->AddPoint(pointBotRight);
					C3DPoint * pointTopRight = new C3DPoint(dRockRightCoords[y][1][0],
															dRockRightCoords[y][1][1],
															dRockRightCoords[y][1][2]);
					face->AddPoint(pointTopRight);
					m_cliffsRightGlobal.AddHead(ComputeGlobalCliffFaceFor(face));
					delete(face);
				}
	 
			};
    };
	glNewList(CLIFFS_LIST,GL_COMPILE);
		glPushMatrix();
		//move it up because this sits ontop of rocks
		double dYUp = 35.0;
		glTranslated(0.0, dYUp, 0.0);
		glScalef((float)TERRAIN_SCALE, (float)TERRAIN_SCALE,
				(float)TERRAIN_SCALE);

		DrawCliffSide(dRockFrontCoords, dHeight, TERRAIN_SIZE);
		DrawCliffSide(dRockBackCoords, dHeight, TERRAIN_SIZE);
		DrawCliffSide(dRockLeftCoords, dHeight, TERRAIN_SIZE - 1);
		DrawCliffSide(dRockRightCoords, dHeight, TERRAIN_SIZE - 1);
		glPopMatrix();
	glEndList();
}

//create the rocks that sit on top
void CIslandWorld::SetupRocks(double dTerrainHeights[TERRAIN_SIZE][TERRAIN_SIZE])
{
	//give cell co-ordinates of where rocks should start
	const int numRocks = 3;
	//don't put any on the edges
	int rockPos[numRocks][2] = {
		{5,5},
		{10, 13},
		{7, 10},
	};
	//how many cells this rock should cover
	const int rockWidth = 3; 
	int rockHeights[rockWidth];
	//generate random hieght between 1 and 2 for the rocks
	srand(100);
	for (int a = 0; a < rockWidth; a++)
		rockHeights[a] = 1 + 0.1 * (rand() % 5);
	
	for (int i = 0; i < numRocks; i++)
	{
		int xCellStart = rockPos[i][0];
		int yCellStart = rockPos[i][1];
		CRock * rock = new CRock();
		CRock * rockGlobal = new CRock();
		for (int j = 0; j < rockWidth; j++)
		{
			int yCell = yCellStart + j;
			for (int k = 0; k < rockWidth; k++)
			{
				int xCell = xCellStart + k;
				double dLeftHeight = 0;
				double dRightHeight = 0;
				if (k == rockWidth / 2)
				{
					dLeftHeight = rockHeights[k];
					dRightHeight = rockHeights[k];
				}
				else
				{
					//left hand side
					if (k < rockWidth / 2)
					{
						dLeftHeight = 0.25 * abs((rockWidth / 2) - k) * rockHeights[k];
						if ((k + 1) == rockWidth / 2)
							dRightHeight = rockHeights[k];
						else
							dRightHeight = 0.25 * abs((rockWidth / 2) - (k + 1)) * rockHeights[k];
					}
					else
					{
						//right side
						dRightHeight = 0.25 * abs((rockWidth / 2) - k) * rockHeights[k];
						if ((k - 1) == rockWidth / 2)
							dLeftHeight = rockHeights[k];
						else
							dLeftHeight = 0.25 * abs((rockWidth / 2) - (k - 1)) * rockHeights[k];
					
					}
					
				}
				//get all the important points
				//make it level on the bottom
				double dMinBottom = dTerrainHeights[yCell][xCell - 1];
				if (dTerrainHeights[yCell][xCell] < dMinBottom)
					dMinBottom = dTerrainHeights[yCell][xCell];

				if (dTerrainHeights[yCell + 1][xCell] < dMinBottom)
					dMinBottom = dTerrainHeights[yCell + 1][xCell];

				if (dTerrainHeights[yCell + 1][xCell - 1] < dMinBottom)
					dMinBottom = dTerrainHeights[yCell + 1][xCell - 1];

				//point back left
				C3DPoint * pointBackLeft = new C3DPoint(xCell - TERRAIN_EDGE - 1,
															dMinBottom,
															yCell - TERRAIN_EDGE); 
				//back right
				C3DPoint * pointBackRight = new C3DPoint(xCell - TERRAIN_EDGE,
															dMinBottom,
															yCell - TERRAIN_EDGE); 

				//front left
				C3DPoint * pointFrontLeft = new C3DPoint(xCell - TERRAIN_EDGE - 1,
															dMinBottom,
															yCell - TERRAIN_EDGE + 1);

				//front right
				C3DPoint * pointFrontRight = new C3DPoint(xCell - TERRAIN_EDGE,
															dMinBottom,
															yCell - TERRAIN_EDGE + 1);

				//point top back left
				C3DPoint * pointTopBackLeft = new C3DPoint(pointBackLeft->m_x,
															pointBackLeft->m_y + dLeftHeight,
															pointBackLeft->m_z); 
				//back top back right
				C3DPoint * pointTopBackRight = new C3DPoint(pointBackRight->m_x,
															pointBackRight->m_y + dRightHeight,
															pointBackRight->m_z);
 
				//top front right
				C3DPoint * pointTopFrontRight = new C3DPoint(pointFrontRight->m_x,
															pointFrontRight->m_y + dRightHeight,
															pointFrontRight->m_z);
		
				//top front left
				C3DPoint * pointTopFrontLeft = new C3DPoint(pointFrontLeft->m_x,
															pointFrontLeft->m_y + dLeftHeight,
															pointFrontLeft->m_z);
				//now compute the faces
				CFace* backFace = new CFace();
				CFace* rightFace = new CFace();
				CFace* frontFace = new CFace();
				CFace* leftFace = new CFace();
				CFace* topFace = new CFace();

				//Because in the desctrutuor for the face I delete
				//all the points, I must allocate new memory for them all.
				//do the back face.
				//Must make this concave
				backFace->AddPoint(new C3DPoint(pointTopBackRight));
				backFace->AddPoint(new C3DPoint(pointTopBackLeft));
				backFace->AddPoint(new C3DPoint(pointBackLeft));
				backFace->AddPoint(new C3DPoint(pointBackRight));
				backFace->CalculateNormalAndCenter();
				rock->AddFace(backFace);
				rockGlobal->AddFace(ComputeGlobalRockFaceFor(backFace));
			
				//do the right face	
				rightFace->AddPoint(new C3DPoint(pointFrontRight));
				rightFace->AddPoint(new C3DPoint(pointTopFrontRight));
				rightFace->AddPoint(new C3DPoint(pointTopBackRight));
				rightFace->AddPoint(new C3DPoint(pointBackRight));
				rightFace->CalculateNormalAndCenter();
				rock->AddFace(rightFace);
				rockGlobal->AddFace(ComputeGlobalRockFaceFor(rightFace));
			
				//do the left face
				leftFace->AddPoint(new C3DPoint(pointTopFrontLeft));
				leftFace->AddPoint(new C3DPoint(pointTopBackLeft));
				leftFace->AddPoint(new C3DPoint(pointBackLeft));
				leftFace->AddPoint(new C3DPoint(pointFrontLeft));
				leftFace->CalculateNormalAndCenter();
				rock->AddFace(leftFace);
				rockGlobal->AddFace(ComputeGlobalRockFaceFor(leftFace));
				
				
				//do the front face
				frontFace->AddPoint(new C3DPoint(pointTopFrontLeft));
				frontFace->AddPoint(new C3DPoint(pointFrontLeft));
				frontFace->AddPoint(new C3DPoint(pointFrontRight));
				frontFace->AddPoint(new C3DPoint(pointTopFrontRight));
				frontFace->CalculateNormalAndCenter();
				rock->AddFace(frontFace);
				rockGlobal->AddFace(ComputeGlobalRockFaceFor(frontFace));

				//do the top face
				topFace->AddPoint(new C3DPoint(pointTopFrontRight));
				topFace->AddPoint(new C3DPoint(pointTopBackRight));
				topFace->AddPoint(new C3DPoint(pointTopBackLeft));
				topFace->AddPoint(new C3DPoint(pointTopFrontLeft));
				
				topFace->CalculateNormalAndCenter();
				rock->AddFace(topFace);
				rockGlobal->AddFace(ComputeGlobalRockFaceFor(topFace));
				
				//now delete the points
				delete(pointBackLeft); 
				delete(pointBackRight); 
				delete(pointTopBackLeft); 
				delete(pointTopBackRight);
				delete(pointFrontRight); 
				delete(pointTopFrontRight);
				delete(pointFrontLeft);
				delete(pointTopFrontLeft);
			}
		}
		m_rocks.AddHead(rock);
		m_rocksGlobal.AddHead(rockGlobal);
	}
}

//this has to be done in a function because the call lists
//seem to not work with this sort of design
void CIslandWorld::DrawRocks(void)
{
	glPushMatrix();
		//move it up because this sits ontop of rocks
		double dYUp = 35.0;
		glTranslated(0.0, dYUp, 0.0);
		glScalef((float)TERRAIN_SCALE, (float)TERRAIN_SCALE,
				(float)TERRAIN_SCALE);
		double matrixTrans[16];
		glGetDoublev(GL_MODELVIEW_MATRIX, matrixTrans);

		POSITION pos = m_rocks.GetHeadPosition();
		while (pos != NULL)
		{
			CRock* obj = m_rocks.GetAt(pos);
			obj->Draw();
			m_rocks.GetNext(pos);
		}
		glPopMatrix();
}

//create the bounding box tree
void CIslandWorld::CreateBoundingBoxTree(void)
{

	//first create a list that for each
	//leaf object in the bouding box tree
	CList<CBoundingBoxTree*, CBoundingBoxTree*> list;

	CBoundingBoxTree* tree;
	//give it the rocks
	CList<CFace*, CFace*> * faces;
	POSITION pos = m_rocksGlobal.GetHeadPosition();
	while (pos != NULL)
	{
		CRock* obj = m_rocksGlobal.GetAt(pos);
		faces = obj->GetFaces();
		tree = new CBoundingBoxTree();

		tree->CreateFrom(faces);

		list.AddHead(tree);
		m_rocksGlobal.GetNext(pos);
	}
	
	//give it the cliffs
	tree = new CBoundingBoxTree();
	tree->CreateFrom(&m_cliffsBackGlobal);
	list.AddHead(tree);
	tree = new CBoundingBoxTree();
	tree->CreateFrom(&m_cliffsFrontGlobal);
	list.AddHead(tree);
	tree = new CBoundingBoxTree();
	tree->CreateFrom(&m_cliffsLeftGlobal);
	list.AddHead(tree);
	tree = new CBoundingBoxTree();
	tree->CreateFrom(&m_cliffsRightGlobal);
	list.AddHead(tree);


	//sequence through list, remove the element with
	//the minimum volume, and then union it with
	//something else.
	//At the end list should just contain one element
	while (list.GetCount() != 1)
	{
		//find tree with minimal volume
		POSITION minPos = list.GetHeadPosition();
		double dMinVolume;
		CBoundingBoxTree* pMinVolTree;
		POSITION minVolPos;
		int count = 1;
		while (minPos != NULL)
		{
			CBoundingBoxTree* obj = list.GetAt(minPos);
			if ((obj->GetVolume() < dMinVolume) || count == 1)
			{
				dMinVolume = obj->GetVolume();
				pMinVolTree = obj;
				minVolPos = minPos;
				count++;
			}
			list.GetNext(minPos);
		}
		//remove this item from list
		list.RemoveAt(minVolPos);
		//find another tree
		dMinVolume = 0;
		minPos = list.GetHeadPosition();
		CBoundingBoxTree* pMinVolUnionTree;
		count = 1;
		while (minPos != NULL)
		{
			CBoundingBoxTree* obj = list.GetAt(minPos);
			if ((obj->GetUnionVolumeWith(pMinVolTree) < dMinVolume) || count == 1)
			{
				dMinVolume = obj->GetVolume();
				pMinVolUnionTree = obj;
				minVolPos = minPos;
				count++;
			}
			list.GetNext(minPos);
		}

		//remove this from the list
		list.RemoveAt(minVolPos);

		//add to the list a tree consisting of the union
		//of pMinVolUnionTree and pMinVolTree
		CBoundingBoxTree* newTree = new CBoundingBoxTree;
		newTree->CreateFromUnionOf(pMinVolTree,pMinVolUnionTree);
		list.AddHead(newTree);
	}

	pos = list.GetHeadPosition();
	m_islandObjectsBoundingBoxTree = (list.GetAt(pos));

	//now setup the bounding box for the ground
	m_islandGroundBoundingBoxTree = new CBoundingBoxTree();
	m_islandGroundBoundingBoxTree->CreateFrom(&m_groundGlobal);
	int x = 5;
}

//compute the points in global coordinate
CFace* CIslandWorld::ComputeGlobalRockFaceFor(CFace * backFace)
{
	glPushMatrix();
	double dYUp = 35.0;
	glTranslated(0.0, dYUp, 0.0);
	glScalef((float)TERRAIN_SCALE, (float)TERRAIN_SCALE,
				(float)TERRAIN_SCALE);
	
	double matrixTrans[16];
	glGetDoublev(GL_MODELVIEW_MATRIX, matrixTrans);
	glPopMatrix();
	
	//sequence through our points and make them global
	POSITION pos = backFace->m_points.GetHeadPosition();
	CFace* newFace = new CFace();
	while (pos != NULL)
	{
		C3DPoint* obj = backFace->m_points.GetAt(pos);
		double dPoint[4];
		dPoint[0] = obj->m_x;
		dPoint[1] = obj->m_y;
		dPoint[2] = obj->m_z;
		dPoint[3] = 1;

		double dResult[4];
		CHelper::MultiplyPointByMatrix(dPoint, matrixTrans, dResult);
		C3DPoint * point = new C3DPoint();
		point->m_x = dResult[0];
		point->m_y = dResult[1];
		point->m_z = dResult[2];
		newFace->AddPoint(point);
		backFace->m_points.GetNext(pos);
	}
	newFace->CalculateNormalAndCenter();
	return newFace;
}

//compute the points in global coordinate
CFace* CIslandWorld::ComputeGlobalLandFaceFor(CFace * backFace)
{
	glPushMatrix();
	double dYUp = 35.0;
	glTranslated(0.0, dYUp, 0.0);
	glScalef((float)TERRAIN_SCALE, (float)TERRAIN_SCALE,
				(float)TERRAIN_SCALE);
	
	double matrixTrans[16];
	glGetDoublev(GL_MODELVIEW_MATRIX, matrixTrans);
	glPopMatrix();
	
	//sequence through our points and make them global
	POSITION pos = backFace->m_points.GetHeadPosition();
	CFace* newFace = new CFace();
	while (pos != NULL)
	{
		C3DPoint* obj = backFace->m_points.GetAt(pos);
		double dPoint[4];
		dPoint[0] = obj->m_x;
		dPoint[1] = obj->m_y;
		dPoint[2] = obj->m_z;
		dPoint[3] = 1;

		double dResult[4];
		CHelper::MultiplyPointByMatrix(dPoint, matrixTrans, dResult);
		C3DPoint * point = new C3DPoint();
		point->m_x = dResult[0];
		point->m_y = dResult[1];
		point->m_z = dResult[2];
		newFace->AddPoint(point);
		backFace->m_points.GetNext(pos);
	}
	newFace->CalculateNormalAndCenter();
	return newFace;
}

//compute the points in global coordinate
CFace* CIslandWorld::ComputeGlobalCliffFaceFor(CFace * backFace)
{
	glPushMatrix();
	double dYUp = 35.0;
	glTranslated(0.0, dYUp, 0.0);
	glScalef((float)TERRAIN_SCALE, (float)TERRAIN_SCALE,
				(float)TERRAIN_SCALE);
	
	double matrixTrans[16];
	glGetDoublev(GL_MODELVIEW_MATRIX, matrixTrans);
	glPopMatrix();
	
	//sequence through our points and make them global
	POSITION pos = backFace->m_points.GetHeadPosition();
	CFace* newFace = new CFace();
	while (pos != NULL)
	{
		C3DPoint* obj = backFace->m_points.GetAt(pos);
		double dPoint[4];
		dPoint[0] = obj->m_x;
		dPoint[1] = obj->m_y;
		dPoint[2] = obj->m_z;
		dPoint[3] = 1;

		double dResult[4];
		CHelper::MultiplyPointByMatrix(dPoint, matrixTrans, dResult);
		C3DPoint * point = new C3DPoint();
		point->m_x = dResult[0];
		point->m_y = dResult[1];
		point->m_z = dResult[2];
		newFace->AddPoint(point);
		backFace->m_points.GetNext(pos);
	}
	newFace->CalculateNormalAndCenter();
	return newFace;
}

//change the current island character
void CIslandWorld::ChangeCharacter(int code)
{
	switch (code)
	{
		case GOD:
			m_currentPerson = m_godPerson;
			break;
		case WOMAN:
			m_currentPerson = m_girlPerson;
			break;
		case MAN:
			m_currentPerson = m_guyPerson;
			break;
	}
}

int CIslandWorld::GetCurrentCharacter()
{
	return m_currentPerson->GetID();
}
