Code Search for Developers
 
 
  

TerrainBlock.cpp from NeoEngineNG at Krugle


Show TerrainBlock.cpp syntax highlighted

// Demeter Terrain Visualization Library by Clay Fowler
// Copyright (C) 2002 Clay Fowler

// $ID$

/*
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Library General Public License for more details.

You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA  02111-1307, USA.
*/

#include "Demeter/TerrainBlock.h"
#include "Demeter/Settings.h"
#include "Demeter/Terrain.h"

extern float numBlocks;
extern float numLevels;
extern float hashDelta;

using namespace Demeter;
using namespace std;

float m_Frustum[6][4];

void TerrainBlockExtractFrustum()
{
// Thanks to Mark Morley for this OpenGL frustum testing code.
// See all of it at http://www.markmorley.com/opengl/frustumculling.html.
	float proj[16];
	float modl[16];
	float clip[16];
	float t;
	/* Get the current PROJECTION matrix from OpenGL */
	glGetFloatv(GL_PROJECTION_MATRIX, proj);
	/* Get the current MODELVIEW matrix from OpenGL */
	glGetFloatv(GL_MODELVIEW_MATRIX, modl);
	/* Combine the two matrices (multiply projection by modelview) */
	clip[0] = modl[0] * proj[0] + modl[1] * proj[4] + modl[2] * proj[8] + modl[3] * proj[12];
	clip[1] = modl[0] * proj[1] + modl[1] * proj[5] + modl[2] * proj[9] + modl[3] * proj[13];
	clip[2] = modl[0] * proj[2] + modl[1] * proj[6] + modl[2] * proj[10] + modl[3] * proj[14];
	clip[3] = modl[0] * proj[3] + modl[1] * proj[7] + modl[2] * proj[11] + modl[3] * proj[15];
	clip[4] = modl[4] * proj[0] + modl[5] * proj[4] + modl[6] * proj[8] + modl[7] * proj[12];
	clip[5] = modl[4] * proj[1] + modl[5] * proj[5] + modl[6] * proj[9] + modl[7] * proj[13];
	clip[6] = modl[4] * proj[2] + modl[5] * proj[6] + modl[6] * proj[10] + modl[7] * proj[14];
	clip[7] = modl[4] * proj[3] + modl[5] * proj[7] + modl[6] * proj[11] + modl[7] * proj[15];
	clip[8] = modl[8] * proj[0] + modl[9] * proj[4] + modl[10] * proj[8] + modl[11] * proj[12];
	clip[9] = modl[8] * proj[1] + modl[9] * proj[5] + modl[10] * proj[9] + modl[11] * proj[13];
	clip[10] = modl[8] * proj[2] + modl[9] * proj[6] + modl[10] * proj[10] + modl[11] * proj[14];
	clip[11] = modl[8] * proj[3] + modl[9] * proj[7] + modl[10] * proj[11] + modl[11] * proj[15];
	clip[12] = modl[12] * proj[0] + modl[13] * proj[4] + modl[14] * proj[8] + modl[15] * proj[12];
	clip[13] = modl[12] * proj[1] + modl[13] * proj[5] + modl[14] * proj[9] + modl[15] * proj[13];
	clip[14] = modl[12] * proj[2] + modl[13] * proj[6] + modl[14] * proj[10] + modl[15] * proj[14];
	clip[15] = modl[12] * proj[3] + modl[13] * proj[7] + modl[14] * proj[11] + modl[15] * proj[15];
	/* Extract the numbers for the RIGHT plane */
	m_Frustum[0][0] = clip[3] - clip[0];
	m_Frustum[0][1] = clip[7] - clip[4];
	m_Frustum[0][2] = clip[11] - clip[8];
	m_Frustum[0][3] = clip[15] - clip[12];
	/* Normalize the result */
	t = (float)sqrtf(m_Frustum[0][0] * m_Frustum[0][0] + m_Frustum[0][1] * m_Frustum[0][1] + m_Frustum[0][2] * m_Frustum[0][2]);
	m_Frustum[0][0] /= t;
	m_Frustum[0][1] /= t;
	m_Frustum[0][2] /= t;
	m_Frustum[0][3] /= t;
	/* Extract the numbers for the LEFT plane */
	m_Frustum[1][0] = clip[3] + clip[0];
	m_Frustum[1][1] = clip[7] + clip[4];
	m_Frustum[1][2] = clip[11] + clip[8];
	m_Frustum[1][3] = clip[15] + clip[12];
	/* Normalize the result */
	t = (float)sqrtf(m_Frustum[1][0] * m_Frustum[1][0] + m_Frustum[1][1] * m_Frustum[1][1] + m_Frustum[1][2] * m_Frustum[1][2]);
	m_Frustum[1][0] /= t;
	m_Frustum[1][1] /= t;
	m_Frustum[1][2] /= t;
	m_Frustum[1][3] /= t;
	/* Extract the BOTTOM plane */
	m_Frustum[2][0] = clip[3] + clip[1];
	m_Frustum[2][1] = clip[7] + clip[5];
	m_Frustum[2][2] = clip[11] + clip[9];
	m_Frustum[2][3] = clip[15] + clip[13];
	/* Normalize the result */
	t = (float)sqrtf(m_Frustum[2][0] * m_Frustum[2][0] + m_Frustum[2][1] * m_Frustum[2][1] + m_Frustum[2][2] * m_Frustum[2][2]);
	m_Frustum[2][0] /= t;
	m_Frustum[2][1] /= t;
	m_Frustum[2][2] /= t;
	m_Frustum[2][3] /= t;
	/* Extract the TOP plane */
	m_Frustum[3][0] = clip[3] - clip[1];
	m_Frustum[3][1] = clip[7] - clip[5];
	m_Frustum[3][2] = clip[11] - clip[9];
	m_Frustum[3][3] = clip[15] - clip[13];
	/* Normalize the result */
	t = (float)sqrtf(m_Frustum[3][0] * m_Frustum[3][0] + m_Frustum[3][1] * m_Frustum[3][1] + m_Frustum[3][2] * m_Frustum[3][2]);
	m_Frustum[3][0] /= t;
	m_Frustum[3][1] /= t;
	m_Frustum[3][2] /= t;
	m_Frustum[3][3] /= t;
	/* Extract the FAR plane */
	m_Frustum[4][0] = clip[3] - clip[2];
	m_Frustum[4][1] = clip[7] - clip[6];
	m_Frustum[4][2] = clip[11] - clip[10];
	m_Frustum[4][3] = clip[15] - clip[14];
	/* Normalize the result */
	t = (float)sqrtf(m_Frustum[4][0] * m_Frustum[4][0] + m_Frustum[4][1] * m_Frustum[4][1] + m_Frustum[4][2] * m_Frustum[4][2]);
	m_Frustum[4][0] /= t;
	m_Frustum[4][1] /= t;
	m_Frustum[4][2] /= t;
	m_Frustum[4][3] /= t;
	/* Extract the NEAR plane */
	m_Frustum[5][0] = clip[3] + clip[2];
	m_Frustum[5][1] = clip[7] + clip[6];
	m_Frustum[5][2] = clip[11] + clip[10];
	m_Frustum[5][3] = clip[15] + clip[14];
	/* Normalize the result */
	t = (float)sqrtf(m_Frustum[5][0] * m_Frustum[5][0] + m_Frustum[5][1] * m_Frustum[5][1] + m_Frustum[5][2] * m_Frustum[5][2]);
	m_Frustum[5][0] /= t;
	m_Frustum[5][1] /= t;
	m_Frustum[5][2] /= t;
	m_Frustum[5][3] /= t;
}

inline bool CuboidInFrustum(const Box& cuboid)
{
	for (int p = 0; p < 6; p++)
	{
		if (m_Frustum[p][0] * cuboid.m_Min.x + m_Frustum[p][1] * cuboid.m_Min.y + m_Frustum[p][2] * cuboid.m_Min.z + m_Frustum[p][3] > 0)
			continue;
		if (m_Frustum[p][0] * cuboid.m_Max.x + m_Frustum[p][1] * cuboid.m_Min.y + m_Frustum[p][2] * cuboid.m_Min.z + m_Frustum[p][3] > 0)
			continue;
		if (m_Frustum[p][0] * cuboid.m_Min.x + m_Frustum[p][1] * cuboid.m_Max.y + m_Frustum[p][2] * cuboid.m_Min.z + m_Frustum[p][3] > 0)
			continue;
		if (m_Frustum[p][0] * cuboid.m_Max.x + m_Frustum[p][1] * cuboid.m_Max.y + m_Frustum[p][2] * cuboid.m_Min.z + m_Frustum[p][3] > 0)
			continue;
		if (m_Frustum[p][0] * cuboid.m_Min.x + m_Frustum[p][1] * cuboid.m_Min.y + m_Frustum[p][2] * cuboid.m_Max.z + m_Frustum[p][3] > 0)
			continue;
		if (m_Frustum[p][0] * cuboid.m_Max.x + m_Frustum[p][1] * cuboid.m_Min.y + m_Frustum[p][2] * cuboid.m_Max.z + m_Frustum[p][3] > 0)
			continue;
		if (m_Frustum[p][0] * cuboid.m_Min.x + m_Frustum[p][1] * cuboid.m_Max.y + m_Frustum[p][2] * cuboid.m_Max.z + m_Frustum[p][3] > 0)
			continue;
		if (m_Frustum[p][0] * cuboid.m_Max.x + m_Frustum[p][1] * cuboid.m_Max.y + m_Frustum[p][2] * cuboid.m_Max.z + m_Frustum[p][3] > 0)
			continue;
		return false;
	}
	return true;
}

inline bool PointInBox(Demeter::Vector point,Demeter::Box box)
{
	return (point.x <= box.m_Max.x && point.x >= box.m_Min.x &&
		point.y <= box.m_Max.y && point.y >= box.m_Min.y &&
		point.z <= box.m_Max.z && point.z >= box.m_Min.z);
}

int RayPlaneIntersect(const Ray * ray, const Plane * plane, Vector * point, float *distance)
{
	float vd, vo, PnDOTRo, t;

	vd = plane->a * ray->m_Direction.x + plane->b * ray->m_Direction.y + plane->c * ray->m_Direction.z;
	if (vd == 0.0)
		// The plane is parallel to the ray. I've never seen this happen but someday it will . . .
		return -1;
	if (vd > 0.0)
	{
		// The plane is facing away from the ray so no intersection occurs.
		return -2;
	}
	PnDOTRo = plane->a * ray->m_Origin.x + plane->b * ray->m_Origin.y + plane->c * ray->m_Origin.z;
	vo = -1.0f * (PnDOTRo + plane->d);
	t = vo / vd;
	if (t < 0.0f)
		// The intersection occurs behind the ray's origin.
		return -3;
	point->x = ray->m_Origin.x + ray->m_Direction.x * t;
	point->y = ray->m_Origin.y + ray->m_Direction.y * t;
	point->z = ray->m_Origin.z + ray->m_Direction.z * t;
	if (distance != NULL)
		*distance = t;
	return 1;
}

int RayBoxIntersect(const Ray * ray, const Box * box, Vector * point, float *distance)
{
	float tnear, tfar, t1, t2;

	tnear = -INFINITY;
	tfar = INFINITY;

// Find intersection with x-aligned planes of box.
	// If the ray is parallel to the box and not within the planes of the box it misses.
	if (ray->m_Direction.x == 0.0)
		if ((ray->m_Origin.x < box->m_Min.x) && (ray->m_Origin.x > box->m_Max.x))
			return 0;
	// Calculate intersection distance with the box's planes.
	t1 = (box->m_Min.x - ray->m_Origin.x) / ray->m_Direction.x;
	t2 = (box->m_Max.x - ray->m_Origin.x) / ray->m_Direction.x;
	if (t1 > t2)
	{
		float tmp = t1;
		t1 = t2;
		t2 = tmp;
	}
	if (t1 > tnear)
		tnear = t1;
	if (t2 < tfar)
		tfar = t2;
	if (tnear > tfar)
		return 0;
	if (tfar < 0.0)
		return 0;
// Find intersection with y-aligned planes of box.
	// If the ray is parallel to the box and not within the planes of the box it misses.
	if (ray->m_Direction.y == 0.0)
		if ((ray->m_Origin.y < box->m_Min.y) && (ray->m_Origin.y > box->m_Max.y))
			return 0;
	// Calculate intersection distance with the box's planes.
	t1 = (box->m_Min.y - ray->m_Origin.y) / ray->m_Direction.y;
	t2 = (box->m_Max.y - ray->m_Origin.y) / ray->m_Direction.y;
	if (t1 > t2)
	{
		float tmp = t1;
		t1 = t2;
		t2 = tmp;
	}
	if (t1 > tnear)
		tnear = t1;
	if (t2 < tfar)
		tfar = t2;
	if (tnear > tfar)
		return 0;
	if (tfar < 0.0)
		return 0;
// Find intersection with z-aligned planes of box.
	// If the ray is parallel to the box and not within the planes of the box it misses.
	if (ray->m_Direction.z == 0.0)
		if ((ray->m_Origin.z < box->m_Min.z) && (ray->m_Origin.z > box->m_Max.z))
			return 0;
	// Calculate intersection distance with the box's planes.
	t1 = (box->m_Min.z - ray->m_Origin.z) / ray->m_Direction.z;
	t2 = (box->m_Max.z - ray->m_Origin.z) / ray->m_Direction.z;
	if (t1 > t2)
	{
		float tmp = t1;
		t1 = t2;
		t2 = tmp;
	}
	if (t1 > tnear)
		tnear = t1;
	if (t2 < tfar)
		tfar = t2;
	if (tnear > tfar)
		return 0;
	if (tfar < 0.0)
		return 0;
// If we survived all of the tests, the box is hit.
	if (point != NULL)
	{
		point->x = ray->m_Origin.x + tnear * ray->m_Direction.x;
		point->y = ray->m_Origin.y + tnear * ray->m_Direction.y;
		point->z = ray->m_Origin.z + tnear * ray->m_Direction.z;
	}
	if (distance != NULL)
	{
		*distance = tnear;
	}
	return 1;
}

TerrainBlock::TerrainBlock(TerrainBlock * pParent)
{
	m_pChildren = NULL;
	m_pTriangles = NULL;
	m_pTriangleVertices = NULL;
	m_pTextureCell = NULL;
	m_pFanVertices = NULL;
	m_NumFanVerticesAllocated = m_NumFanVertices = 0;
}

TerrainBlock::TerrainBlock(int homeVertex, int stride, Terrain * pTerrain, TerrainBlock * pParent)
{
	m_pTriangles = NULL;
	m_HomeIndex = homeVertex;
	m_Stride = stride;

	static int numBlocksBuilt = 0;
	if (Settings::GetInstance()->IsVerbose())
	{
		if (hashDelta <= numBlocksBuilt++)
		{
			cout << "#" << flush;
			numBlocksBuilt = 0;
		}
	}

// Recursively build children blocks of this block.
	if (LEAF_SIZE < m_Stride)
	{
		m_pChildren = new TerrainBlock *[4];
		int childrenStride = m_Stride / 2;
		m_pChildren[0] = new TerrainBlock(homeVertex, childrenStride, pTerrain, this);
		m_pChildren[1] = new TerrainBlock(homeVertex + childrenStride, childrenStride, pTerrain, this);
		m_pChildren[2] = new TerrainBlock(homeVertex + childrenStride * pTerrain->m_WidthVertices + childrenStride, childrenStride, pTerrain, this);
		m_pChildren[3] = new TerrainBlock(homeVertex + childrenStride * pTerrain->m_WidthVertices, childrenStride, pTerrain, this);
	}
	CalculateGeometry(pTerrain);
	m_pTriangleVertices = NULL;
	m_pTextureCell = NULL;
	m_pFanVertices = NULL;
	m_NumFanVerticesAllocated = m_NumFanVertices = 0;
}

TerrainBlock::~TerrainBlock()
{
	if (m_pChildren != NULL && LEAF_SIZE < m_Stride)
	{
		for (int i = 0; i < 4; i++)
		{
			delete m_pChildren[i];
			m_pChildren[i] = NULL;
		}
		delete[]m_pChildren;
	}
	delete[] m_pTriangleVertices;
	delete[] m_pFanVertices;
	delete[] m_pTriangles;
}

bool TerrainBlock::IsActive(Terrain* pTerrain)
{
	return m_bIsActive;
}

void TerrainBlock::Tessellate(const float cameraPosX,const float cameraPosY,const double *pMatModelView, const double *pMatProjection, const int *pViewport, Terrain * pTerrain)
{
/*	Box boundingBox;
	float width = m_Stride * pTerrain->GetVertexSpacing();
	boundingBox.m_Min.x = pTerrain->m_pVertices[m_HomeIndex].x;
	boundingBox.m_Min.y = pTerrain->m_pVertices[m_HomeIndex].y;
	boundingBox.m_Min.z = m_MinElevation;
	boundingBox.m_Max.x = boundingBox.m_Min.x + width;
	boundingBox.m_Max.y = boundingBox.m_Min.y + width;
	boundingBox.m_Max.z = m_MaxElevation;*/
	m_IsUsingFans = false;

	if ((m_BoundingBox.m_Min.x < pTerrain->m_ClipMin.x && m_BoundingBox.m_Max.x < pTerrain->m_ClipMin.x) ||
	    (m_BoundingBox.m_Min.x > pTerrain->m_ClipMax.x && m_BoundingBox.m_Max.x > pTerrain->m_ClipMax.x) ||
	    (m_BoundingBox.m_Min.y < pTerrain->m_ClipMin.y && m_BoundingBox.m_Max.y < pTerrain->m_ClipMin.y) ||
	    (m_BoundingBox.m_Min.y > pTerrain->m_ClipMax.y && m_BoundingBox.m_Max.y > pTerrain->m_ClipMax.y))
	{
		m_bIsActive = false;
		m_bChildrenActive = false;
	}
	else
	{
		int widthVertices = pTerrain->m_WidthVertices;
		if (CuboidInFrustum(m_BoundingBox))
		{
			if (m_pTextureCell == NULL)
			{
				int vertexX = m_HomeIndex % pTerrain->m_WidthVertices;
				int vertexY = m_HomeIndex / pTerrain->m_HeightVertices;
				float x = vertexX * pTerrain->GetVertexSpacing() + pTerrain->GetVertexSpacing() * 0.5f; // Add some fudge for float precision
				float y = vertexY * pTerrain->GetVertexSpacing() + pTerrain->GetVertexSpacing() * 0.5f; // Add some fudge for float precision
				m_pTextureCell = pTerrain->GetTextureCellByPosition(x,y);
			}
			if (m_Stride == LEAF_SIZE)
			{
				if (m_pTriangleVertices == NULL)
				{
					m_pTriangleVertices = new GLuint[24];
					m_pTriangleVertices[0] = m_HomeIndex;
					m_pTriangleVertices[1] = m_HomeIndex + widthVertices;
					m_pTriangleVertices[2] = m_HomeIndex + 1;
					m_pTriangleVertices[3] = m_HomeIndex + 1;
					m_pTriangleVertices[4] = m_HomeIndex + widthVertices;
					m_pTriangleVertices[5] = m_HomeIndex + widthVertices + 1;
					m_pTriangleVertices[6] = m_HomeIndex + 1;
					m_pTriangleVertices[7] = m_HomeIndex + 1 + widthVertices;
					m_pTriangleVertices[8] = m_HomeIndex + 2;
					m_pTriangleVertices[9] = m_HomeIndex + 2;
					m_pTriangleVertices[10] = m_HomeIndex + 1 + widthVertices;
					m_pTriangleVertices[11] = m_HomeIndex + 2 + widthVertices;

					m_pTriangleVertices[12] = m_HomeIndex + widthVertices;
					m_pTriangleVertices[13] = m_HomeIndex + widthVertices + widthVertices;
					m_pTriangleVertices[14] = m_HomeIndex + widthVertices + 1;
					m_pTriangleVertices[15] = m_HomeIndex + widthVertices + 1;
					m_pTriangleVertices[16] = m_HomeIndex + widthVertices + widthVertices;
					m_pTriangleVertices[17] = m_HomeIndex + widthVertices + widthVertices + 1;
					m_pTriangleVertices[18] = m_HomeIndex + widthVertices + 1;
					m_pTriangleVertices[19] = m_HomeIndex + widthVertices + 1 + widthVertices;
					m_pTriangleVertices[20] = m_HomeIndex + widthVertices + 2;
					m_pTriangleVertices[21] = m_HomeIndex + widthVertices + 2;
					m_pTriangleVertices[22] = m_HomeIndex + widthVertices + 1 + widthVertices;
					m_pTriangleVertices[23] = m_HomeIndex + widthVertices + 2 + widthVertices;
				}

				pTerrain->m_pVertexStatus[m_pTriangleVertices[0]] = true;
				pTerrain->m_pVertexStatus[m_pTriangleVertices[1]] = true;
				pTerrain->m_pVertexStatus[m_pTriangleVertices[2]] = true;
				pTerrain->m_pVertexStatus[m_pTriangleVertices[3]] = true;
				pTerrain->m_pVertexStatus[m_pTriangleVertices[4]] = true;
				pTerrain->m_pVertexStatus[m_pTriangleVertices[5]] = true;
				pTerrain->m_pVertexStatus[m_pTriangleVertices[6]] = true;
				pTerrain->m_pVertexStatus[m_pTriangleVertices[7]] = true;
				pTerrain->m_pVertexStatus[m_pTriangleVertices[8]] = true;
				pTerrain->m_pVertexStatus[m_pTriangleVertices[9]] = true;
				pTerrain->m_pVertexStatus[m_pTriangleVertices[10]] = true;
				pTerrain->m_pVertexStatus[m_pTriangleVertices[11]] = true;
				pTerrain->m_pVertexStatus[m_pTriangleVertices[12]] = true;
				pTerrain->m_pVertexStatus[m_pTriangleVertices[13]] = true;
				pTerrain->m_pVertexStatus[m_pTriangleVertices[14]] = true;
				pTerrain->m_pVertexStatus[m_pTriangleVertices[15]] = true;
				pTerrain->m_pVertexStatus[m_pTriangleVertices[16]] = true;
				pTerrain->m_pVertexStatus[m_pTriangleVertices[17]] = true;
				pTerrain->m_pVertexStatus[m_pTriangleVertices[18]] = true;
				pTerrain->m_pVertexStatus[m_pTriangleVertices[19]] = true;
				pTerrain->m_pVertexStatus[m_pTriangleVertices[20]] = true;
				pTerrain->m_pVertexStatus[m_pTriangleVertices[21]] = true;
				pTerrain->m_pVertexStatus[m_pTriangleVertices[22]] = true;
				pTerrain->m_pVertexStatus[m_pTriangleVertices[23]] = true;

				m_bIsActive = true;
				m_pTextureCell->AddBlock(this);
			}
			else
			{
				if ((pTerrain->m_MaximumVisibleBlockSize < m_Stride) ||
				    (m_BoundingBox.m_Min.x < cameraPosX && m_BoundingBox.m_Max.x > cameraPosX &&
				     m_BoundingBox.m_Min.y < cameraPosY && m_BoundingBox.m_Max.y > cameraPosY))
				{
					m_pChildren[0]->Tessellate(cameraPosX,cameraPosY,pMatModelView, pMatProjection, pViewport, pTerrain);
					m_pChildren[1]->Tessellate(cameraPosX,cameraPosY,pMatModelView, pMatProjection, pViewport, pTerrain);
					m_pChildren[2]->Tessellate(cameraPosX,cameraPosY,pMatModelView, pMatProjection, pViewport, pTerrain);
					m_pChildren[3]->Tessellate(cameraPosX,cameraPosY,pMatModelView, pMatProjection, pViewport, pTerrain);
					m_bIsActive = false;
					m_bChildrenActive = true;
				}
				else
				{
					double x1,y1,z1;
					double x2,y2,z2;
					double x3,y3,z3;
					double x4,y4,z4;

					gluProject(m_BoundingBox.m_Min.x, m_BoundingBox.m_Min.y, m_BoundingBox.m_Min.z, pMatModelView, pMatProjection, (GLint*) pViewport, &x1, &y1, &z1);
					gluProject(m_BoundingBox.m_Max.x, m_BoundingBox.m_Max.y, m_BoundingBox.m_Max.z, pMatModelView, pMatProjection, (GLint*) pViewport, &x2, &y2, &z2);
					gluProject(m_BoundingBox.m_Max.x, m_BoundingBox.m_Min.y, m_BoundingBox.m_Min.z, pMatModelView, pMatProjection, (GLint*) pViewport, &x3, &y3, &z3);
					gluProject(m_BoundingBox.m_Min.x, m_BoundingBox.m_Max.y, m_BoundingBox.m_Max.z, pMatModelView, pMatProjection, (GLint*) pViewport, &x4, &y4, &z4);

					double diffx = x2 - x1;
					double diffy = y2 - y1;
					double length1 = sqrt(diffx*diffx + diffy*diffy);
					diffx = x4 - x3;
					diffy = y4 - y3;
					double length2 = sqrt(diffx*diffx + diffy*diffy);
					double length;
					if (length1 > length2)
						length = length1;
					else
						length = length2;

	/*				// Check screen coordinates of center of each face of bounding box
					double screenTopX, screenTopY, screenTopZ, screenBottomX, screenBottomY, screenBottomZ;
					float halfWidth = (m_BoundingBox.m_Max.x - m_BoundingBox.m_Min.x) / 2;
					// calculate z half way up the BoundingBox
					float CenterZ = (m_BoundingBox.m_Min.z + m_BoundingBox.m_Max.z) * 0.5f;
					float screenDist;
					int tm = Settings::GetInstance()->GetTessellateMethod();

					float faceX, faceY, faceZ;	//FIXME: use faceX/Y/Z throughout rest of method too.
					// bottom face
					faceX = m_BoundingBox.m_Min.x + halfWidth;
					faceY = m_BoundingBox.m_Min.y + halfWidth;
					if (tm == Settings::TM_NEW)
					{
						faceZ = -halfWidth * m_BPlane_A - halfWidth * m_BPlane_B - m_BPlane_Max_D;
					}
					else
					{
						faceZ = m_BoundingBox.m_Min.z;
					}
					gluProject(faceX, faceY, faceZ, pMatModelView, pMatProjection, (GLint *) pViewport, &screenBottomX, &screenBottomY, &screenBottomZ);
					// top face
					//faceZ = m_BoundingBox.m_Max.z;
					faceZ = -halfWidth * m_BPlane_A - halfWidth * m_BPlane_B - m_BPlane_Min_D;
					gluProject(faceX, faceY, faceZ, pMatModelView, pMatProjection, (GLint *) pViewport, &screenTopX, &screenTopY, &screenTopZ);
					if ((tm == Settings::TM_NEW) || (tm == Settings::TM_OLD_NEW))
					{
						float deltaX, deltaY, deltaZ;
						deltaX = (float)(screenTopX - screenBottomX);
						deltaY = (float)(screenTopY - screenBottomY);
						float zweight = Settings::GetInstance()->GetTessellateZWeight();
						deltaZ = (float)(screenTopZ - screenBottomZ) * zweight;
						screenDist = (float)sqrt(deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ);
					}
					else
					{
						float deltaX, deltaY, boxHeight;
						float screenDistHorizontal, screenDistVertical;//, screenDistNew;
						if (tm == Settings::TM_OLD_UPRIGHTONLY)
						{
							// Disregard DistHorizontal: assume we're vertical
							screenDistHorizontal = 0;
						}
						else
						{
							screenDistHorizontal = (float)fabs(screenTopX - screenBottomX);
							if (tm == Settings::TM_2D_ROLLONLY)
							{
								deltaX = (float)(screenTopX - screenBottomX);
								deltaY = (float)(screenTopY - screenBottomY);
								boxHeight = (float)sqrt(deltaX * deltaX + deltaY * deltaY);
							}
						}
						screenDistVertical = (float)fabs(screenTopY - screenBottomY);

						// Use the smaller of vertical and horizontal screen size to decide whether or not the block should be simplified.
						screenDist = screenDistHorizontal < screenDistVertical ? screenDistHorizontal : screenDistVertical;
						if (tm == Settings::TM_2D_ROLLONLY)
						{
							if (boxHeight < screenDist)
								screenDist = boxHeight;
						}
					}*/

					if (length <= pTerrain->GetDetailThreshold())
					{
						// This block is simplified, so add its triangles to the list and stop recursing.
						CreateTriangleStrip(pTerrain);
					}
					else
					{
						m_pChildren[0]->Tessellate(cameraPosX,cameraPosY,pMatModelView, pMatProjection, pViewport, pTerrain);
						m_pChildren[1]->Tessellate(cameraPosX,cameraPosY,pMatModelView, pMatProjection, pViewport, pTerrain);
						m_pChildren[2]->Tessellate(cameraPosX,cameraPosY,pMatModelView, pMatProjection, pViewport, pTerrain);
						m_pChildren[3]->Tessellate(cameraPosX,cameraPosY,pMatModelView, pMatProjection, pViewport, pTerrain);
						m_bIsActive = false;
						m_bChildrenActive = true;
					}
				}
			}
		}
		else
		{
			m_bIsActive = false;
			m_bChildrenActive = false;
		}
	}
}

void TerrainBlock::CreateTriangleStrip(Terrain * pTerrain)
{
	if (m_pTriangleVertices == NULL)
	{
		m_pTriangleVertices = new GLuint[6];
		m_pTriangleVertices[0] = m_HomeIndex;
		m_pTriangleVertices[1] = m_HomeIndex + pTerrain->m_WidthVertices * m_Stride;
		m_pTriangleVertices[2] = m_HomeIndex + m_Stride;
		m_pTriangleVertices[3] = m_HomeIndex + m_Stride;
		m_pTriangleVertices[4] = m_HomeIndex + pTerrain->m_WidthVertices * m_Stride;
		m_pTriangleVertices[5] = m_HomeIndex + pTerrain->m_WidthVertices * m_Stride + m_Stride;
	}
	pTerrain->m_pVertexStatus[m_pTriangleVertices[0]] = true;
	pTerrain->m_pVertexStatus[m_pTriangleVertices[1]] = true;
	pTerrain->m_pVertexStatus[m_pTriangleVertices[2]] = true;
	pTerrain->m_pVertexStatus[m_pTriangleVertices[3]] = true;
	pTerrain->m_pVertexStatus[m_pTriangleVertices[4]] = true;
	pTerrain->m_pVertexStatus[m_pTriangleVertices[5]] = true;
	m_bIsActive = true;
	m_pTextureCell->AddBlock(this);
	m_bChildrenActive = false;
}

void TerrainBlock::EnableStrip(bool bEnabled)
{
	m_IsUsingFans = !bEnabled;
	m_NumFanVertices = 0;
}

int TerrainBlock::GetStride()
{
	return m_Stride;
}

int TerrainBlock::GetHomeIndex()
{
	return m_HomeIndex;
}

void TerrainBlock::RepairCracks(Terrain * pTerrain)
{
	if (LEAF_SIZE < m_Stride)
	{
		if (m_bIsActive)
		{
			int halfStride = m_Stride / 2;
			int bottomLeft = m_HomeIndex + m_Stride * pTerrain->m_WidthVertices;
			int bottomRight = bottomLeft + m_Stride;
			int i, previousVertex;
			int v0;
			//int numVertices = 0;
			previousVertex = -1;

			bool bNeedToFix = false;
			for (i = m_HomeIndex + m_Stride - 1; m_HomeIndex < i && !bNeedToFix; i--)
				bNeedToFix = (pTerrain->m_pVertexStatus[i]);
			if (!bNeedToFix)
			{
				for (i = m_HomeIndex + pTerrain->m_WidthVertices; i < m_HomeIndex + m_Stride * pTerrain->m_WidthVertices && !bNeedToFix; i += pTerrain->m_WidthVertices)
					bNeedToFix = (pTerrain->m_pVertexStatus[i]);
				if (!bNeedToFix)
				{
					for (i = bottomLeft + 1; i < bottomRight && !bNeedToFix; i++)
						bNeedToFix = (pTerrain->m_pVertexStatus[i]);
					if (!bNeedToFix)
					{
						for (i = bottomRight - pTerrain->m_WidthVertices; m_HomeIndex + m_Stride < i && !bNeedToFix; i -= pTerrain->m_WidthVertices)
							bNeedToFix = (pTerrain->m_pVertexStatus[i]);
					}
				}
			}

			if (bNeedToFix)
			{
				EnableStrip(false);
				v0 = m_HomeIndex + halfStride + halfStride * pTerrain->m_WidthVertices;
				assert(0 <= v0);
				assert(v0 < pTerrain->m_NumberOfVertices);
				if (m_pFanVertices == NULL)
				{
					m_NumFanVerticesAllocated = 8;
					m_pFanVertices = new GLuint[m_NumFanVerticesAllocated];
				}
				for (i = m_HomeIndex + m_Stride; m_HomeIndex <= i; i--)
				{
					assert(0 <= i);
					assert(i < pTerrain->m_NumberOfVertices);
					if (pTerrain->m_pVertexStatus[i])
					{
						if (m_NumFanVertices + 3 >= m_NumFanVerticesAllocated)
						{
							int newSize = m_NumFanVerticesAllocated * 2;
							GLuint* pTemp = new GLuint[newSize];
							memcpy((void*)pTemp,(void*)m_pFanVertices,m_NumFanVertices * sizeof(GLuint));
							delete[] m_pFanVertices;
							m_pFanVertices = pTemp;
							m_NumFanVerticesAllocated = newSize;
						}
						if (previousVertex != -1)
						{
							m_pFanVertices[m_NumFanVertices++] = v0;
							m_pFanVertices[m_NumFanVertices++] = previousVertex;
							m_pFanVertices[m_NumFanVertices++] = i;
						}
						previousVertex = i;
					}
				}
				for (i = m_HomeIndex + pTerrain->m_WidthVertices; i <= m_HomeIndex + m_Stride * pTerrain->m_WidthVertices; i += pTerrain->m_WidthVertices)
				{
					assert(0 <= i);
					assert(i < pTerrain->m_NumberOfVertices);
					if (pTerrain->m_pVertexStatus[i])
					{
						if (m_NumFanVertices + 3 >= m_NumFanVerticesAllocated)
						{
							int newSize = m_NumFanVerticesAllocated * 2;
							GLuint* pTemp = new GLuint[newSize];
							memcpy((void*)pTemp,(void*)m_pFanVertices,m_NumFanVertices * sizeof(GLuint));
							delete[] m_pFanVertices;
							m_pFanVertices = pTemp;
							m_NumFanVerticesAllocated = newSize;
						}
						if (previousVertex != -1)
						{
							m_pFanVertices[m_NumFanVertices++] = v0;
							m_pFanVertices[m_NumFanVertices++] = previousVertex;
							m_pFanVertices[m_NumFanVertices++] = i;
						}
						previousVertex = i;
					}
				}
				for (i = bottomLeft; i <= bottomRight; i++)
				{
					assert(0 <= i);
					assert(i < pTerrain->m_NumberOfVertices);
					if (pTerrain->m_pVertexStatus[i])
					{
						if (m_NumFanVertices + 3 >= m_NumFanVerticesAllocated)
						{
							int newSize = m_NumFanVerticesAllocated * 2;
							GLuint* pTemp = new GLuint[newSize];
							memcpy((void*)pTemp,(void*)m_pFanVertices,m_NumFanVertices * sizeof(GLuint));
							delete[] m_pFanVertices;
							m_pFanVertices = pTemp;
							m_NumFanVerticesAllocated = newSize;
						}
						if (previousVertex != -1)
						{
							m_pFanVertices[m_NumFanVertices++] = v0;
							m_pFanVertices[m_NumFanVertices++] = previousVertex;
							m_pFanVertices[m_NumFanVertices++] = i;
						}
						previousVertex = i;
					}
				}
				for (i = bottomRight - pTerrain->m_WidthVertices; m_HomeIndex + m_Stride <= i; i -= pTerrain->m_WidthVertices)
				{
					assert(0 <= i);
					assert(i < pTerrain->m_NumberOfVertices);
					if (pTerrain->m_pVertexStatus[i])
					{
						if (m_NumFanVertices + 3 >= m_NumFanVerticesAllocated)
						{
							int newSize = m_NumFanVerticesAllocated * 2;
							GLuint* pTemp = new GLuint[newSize];
							memcpy((void*)pTemp,(void*)m_pFanVertices,m_NumFanVertices * sizeof(GLuint));
							delete[] m_pFanVertices;
							m_pFanVertices = pTemp;
							m_NumFanVerticesAllocated = newSize;
						}
						if (previousVertex != -1)
						{
							m_pFanVertices[m_NumFanVertices++] = v0;
							m_pFanVertices[m_NumFanVertices++] = previousVertex;
							m_pFanVertices[m_NumFanVertices++] = i;
						}
						previousVertex = i;
					}
				}
			}
		}
		else if (m_bChildrenActive)
		{
			m_pChildren[0]->RepairCracks(pTerrain);
			m_pChildren[1]->RepairCracks(pTerrain);
			m_pChildren[2]->RepairCracks(pTerrain);
			m_pChildren[3]->RepairCracks(pTerrain);
		}
	}
}

void TerrainBlock::VertexChanged(Terrain * pTerrain)
{
	CalculateGeometry(pTerrain);
	if (LEAF_SIZE < m_Stride)
	{
		m_pChildren[0]->VertexChanged(pTerrain);
		m_pChildren[1]->VertexChanged(pTerrain);
		m_pChildren[2]->VertexChanged(pTerrain);
		m_pChildren[3]->VertexChanged(pTerrain);
	}
}

// speed up variant of VertexChanged by detecting blocks 
// where vertex changed
void TerrainBlock::VertexChanged(Terrain * pTerrain, int index)
{
	int y1 = m_HomeIndex / pTerrain->m_WidthVertices;
	int x1 = m_HomeIndex - y1 * pTerrain->m_WidthVertices;
	int last_index = m_HomeIndex + m_Stride * (pTerrain->m_WidthVertices + 1);
	int y2 = last_index / pTerrain->m_WidthVertices;
	int x2 = last_index - y2 * pTerrain->m_WidthVertices;
	int y = index / pTerrain->m_WidthVertices;
	int x = index - y * pTerrain->m_WidthVertices;
	if (x >= x1 && x <= x2 && y >= y1 && y <= y2)
	{
		CalculateGeometry(pTerrain);
		if (LEAF_SIZE < m_Stride)
		{
			m_pChildren[0]->VertexChanged(pTerrain, index);
			m_pChildren[1]->VertexChanged(pTerrain, index);
			m_pChildren[2]->VertexChanged(pTerrain, index);
			m_pChildren[3]->VertexChanged(pTerrain, index);
		}
	}
}

void TerrainBlock::VertexChanged(Terrain * pTerrain, int index1, int index2)
{
	// block coords
	int last_index = m_HomeIndex + m_Stride * (pTerrain->m_WidthVertices + 1);

	// top left
	int block_y11 = m_HomeIndex / pTerrain->m_WidthVertices;
	int block_x11 = m_HomeIndex - block_y11 * pTerrain->m_WidthVertices;

	// bottom right
	int block_y22 = last_index / pTerrain->m_WidthVertices;
	int block_x22 = last_index - block_y22 * pTerrain->m_WidthVertices;

	// top right
	int block_x12 = block_x22;
	int block_y12 = block_y11;

	// bottom left
	int block_x21 = block_x11;
	int block_y21 = block_y22;

	// changed rectangle coords
	// top left
	int changed_y11 = index1 / pTerrain->m_WidthVertices;
	int changed_x11 = index1 - changed_y11 * pTerrain->m_WidthVertices;

	// bottom right
	int changed_y22 = index2 / pTerrain->m_WidthVertices;
	int changed_x22 = index2 - changed_y22 * pTerrain->m_WidthVertices;

	// top right
	int changed_x12 = changed_x22;
	int changed_y12 = changed_y11;

	// bottom left
	int changed_x21 = changed_x11;
	int changed_y21 = changed_y22;

	// detect of intersection of two boxes ((block_x11, block_y11) - (block_x22, block_y22))
	// and ((changed_x11, changed_y11) - (changed_x22, changed_y22))
	if ((changed_x11 >= block_x11 && changed_x11 <= block_x22 && changed_y11 >= block_y11 && changed_y11 <= block_y22) || (changed_x12 >= block_x11 && changed_x12 <= block_x22 && changed_y12 >= block_y11 && changed_y12 <= block_y22) || (changed_x21 >= block_x11 && changed_x21 <= block_x22 && changed_y21 >= block_y11 && changed_y21 <= block_y22) || (changed_x22 >= block_x11 && changed_x22 <= block_x22 && changed_y22 >= block_y11 && changed_y22 <= block_y22) || (block_x11 >= changed_x11 && block_x11 <= changed_x22 && block_y11 >= changed_y11 && block_y11 <= changed_y22) || (block_x12 >= changed_x11 && block_x12 <= changed_x22 && block_y12 >= changed_y11 && block_y12 <= changed_y22) || (block_x21 >= changed_x11 && block_x21 <= changed_x22 && block_y21 >= changed_y11 && block_y21 <= changed_y22) || (block_x22 >= changed_x11 && block_x22 <= changed_x22 && block_y22 >= changed_y11 && block_y22 <= changed_y22))
	{
		CalculateGeometry(pTerrain);
		if (LEAF_SIZE < m_Stride)
		{
			m_pChildren[0]->VertexChanged(pTerrain, index1, index2);
			m_pChildren[1]->VertexChanged(pTerrain, index1, index2);
			m_pChildren[2]->VertexChanged(pTerrain, index1, index2);
			m_pChildren[3]->VertexChanged(pTerrain, index1, index2);
		}
	}
}


void TerrainBlock::CalculateGeometry(Terrain * pTerrain)
{
	// Calculate slope of best plane approximation of TerrainBlock
	//FIXME: (later, don't optimize too early) - decrease multiplies by adding first.
	//       or include e.g. the 0.5 in the scaling factor below.
/*	m_BPlane_A = 0.5f * pTerrain->GetElevation(m_HomeIndex) - 0.5f * pTerrain->GetElevation(m_HomeIndex + m_Stride) - 0.5f * pTerrain->GetElevation(m_HomeIndex + m_Stride + pTerrain->m_WidthVertices * m_Stride) + 0.5f * pTerrain->GetElevation(m_HomeIndex + pTerrain->m_WidthVertices);
	m_BPlane_B = 0.5f * pTerrain->GetElevation(m_HomeIndex) + 0.5f * pTerrain->GetElevation(m_HomeIndex + m_Stride) - 0.5f * pTerrain->GetElevation(m_HomeIndex + m_Stride + pTerrain->m_WidthVertices * m_Stride) - 0.5f * pTerrain->GetElevation(m_HomeIndex + pTerrain->m_WidthVertices);
	float VertexSpacing = pTerrain->GetVertexSpacing();
	float scalefactor = m_Stride * VertexSpacing;
	m_BPlane_A /= scalefactor;
	m_BPlane_B /= scalefactor;*/

	// Find this block's bounding box.
	float minElevation = pTerrain->GetElevation(m_HomeIndex);
	float maxElevation = pTerrain->GetElevation(m_HomeIndex);
	int WidthVertices = pTerrain->m_WidthVertices;
	for (int i = 0; i <= m_Stride; i++)
	{
		for (int j = 0; j <= m_Stride; j++)
		{
			float elevation = pTerrain->GetElevation(m_HomeIndex + i * WidthVertices + j);
//			float planeD = -m_BPlane_A * (j * VertexSpacing) - m_BPlane_B * (i * VertexSpacing) - elevation;
//			if (planeD < m_BPlane_Min_D)
//				m_BPlane_Min_D = planeD;
//			if (m_BPlane_Max_D < planeD)
//				m_BPlane_Max_D = planeD;
			if (elevation < minElevation)
				minElevation = elevation;
			if (maxElevation < elevation)
				maxElevation = elevation;
		}
	}

	if (pTerrain->UsesRaytracing())
	{
		// Build triangles for ray intersection and collision detection.
		if (m_Stride == LEAF_SIZE)
		{
			m_pTriangles = new Triangle[8];
			m_pTriangles[0].DefineFromPoints(pTerrain->m_pVertices[m_HomeIndex], pTerrain->m_pVertices[m_HomeIndex + pTerrain->m_WidthVertices], pTerrain->m_pVertices[m_HomeIndex + 1]);
			m_pTriangles[1].DefineFromPoints(pTerrain->m_pVertices[m_HomeIndex + 1], pTerrain->m_pVertices[m_HomeIndex + pTerrain->m_WidthVertices], pTerrain->m_pVertices[m_HomeIndex + pTerrain->m_WidthVertices + 1]);
			m_pTriangles[2].DefineFromPoints(pTerrain->m_pVertices[m_HomeIndex + 1], pTerrain->m_pVertices[m_HomeIndex + 1 + pTerrain->m_WidthVertices], pTerrain->m_pVertices[m_HomeIndex + 2]);
			m_pTriangles[3].DefineFromPoints(pTerrain->m_pVertices[m_HomeIndex + 2], pTerrain->m_pVertices[m_HomeIndex + 1 + pTerrain->m_WidthVertices], pTerrain->m_pVertices[m_HomeIndex + 2 + pTerrain->m_WidthVertices]);
			m_pTriangles[4].DefineFromPoints(pTerrain->m_pVertices[m_HomeIndex + pTerrain->m_WidthVertices], pTerrain->m_pVertices[m_HomeIndex + pTerrain->m_WidthVertices + pTerrain->m_WidthVertices], pTerrain->m_pVertices[m_HomeIndex + pTerrain->m_WidthVertices + 1]);
			m_pTriangles[5].DefineFromPoints(pTerrain->m_pVertices[m_HomeIndex + pTerrain->m_WidthVertices + 1], pTerrain->m_pVertices[m_HomeIndex + pTerrain->m_WidthVertices + pTerrain->m_WidthVertices], pTerrain->m_pVertices[m_HomeIndex + pTerrain->m_WidthVertices + pTerrain->m_WidthVertices + 1]);
			m_pTriangles[6].DefineFromPoints(pTerrain->m_pVertices[m_HomeIndex + pTerrain->m_WidthVertices + 1], pTerrain->m_pVertices[m_HomeIndex + pTerrain->m_WidthVertices + 1 + pTerrain->m_WidthVertices], pTerrain->m_pVertices[m_HomeIndex + pTerrain->m_WidthVertices + 2]);
			m_pTriangles[7].DefineFromPoints(pTerrain->m_pVertices[m_HomeIndex + pTerrain->m_WidthVertices + 2], pTerrain->m_pVertices[m_HomeIndex + pTerrain->m_WidthVertices + 1 + pTerrain->m_WidthVertices], pTerrain->m_pVertices[m_HomeIndex + pTerrain->m_WidthVertices + 2 + pTerrain->m_WidthVertices]);

			pTerrain->m_pTrianglePairs[m_HomeIndex].m_pTriangle1 = &m_pTriangles[0];
			pTerrain->m_pTrianglePairs[m_HomeIndex].m_pTriangle2 = &m_pTriangles[1];
			pTerrain->m_pTrianglePairs[m_HomeIndex + 1].m_pTriangle1 = &m_pTriangles[2];
			pTerrain->m_pTrianglePairs[m_HomeIndex + 1].m_pTriangle2 = &m_pTriangles[3];
			pTerrain->m_pTrianglePairs[m_HomeIndex + pTerrain->m_WidthVertices].m_pTriangle1 = &m_pTriangles[4];
			pTerrain->m_pTrianglePairs[m_HomeIndex + pTerrain->m_WidthVertices].m_pTriangle2 = &m_pTriangles[5];
			pTerrain->m_pTrianglePairs[m_HomeIndex + pTerrain->m_WidthVertices + 1].m_pTriangle1 = &m_pTriangles[6];
			pTerrain->m_pTrianglePairs[m_HomeIndex + pTerrain->m_WidthVertices + 1].m_pTriangle2 = &m_pTriangles[7];
		}
	}

	float width = m_Stride * pTerrain->GetVertexSpacing();
	m_BoundingBox.m_Min.x = pTerrain->m_pVertices[m_HomeIndex].x;
	m_BoundingBox.m_Min.y = pTerrain->m_pVertices[m_HomeIndex].y;
	m_BoundingBox.m_Min.z = minElevation;
	m_BoundingBox.m_Max.x = m_BoundingBox.m_Min.x + width;
	m_BoundingBox.m_Max.y = m_BoundingBox.m_Min.y + width;
	m_BoundingBox.m_Max.z = maxElevation;
}

void TerrainBlock::IntersectRay(const Ray & ray, Vector & intersectionPoint, float &lowestDistance, const Terrain * pTerrain)
{
// First test ray against this block's bounding box.
/*	Box boundingBox;
	float width = m_Stride * pTerrain->GetVertexSpacing();
	boundingBox.m_Min.x = pTerrain->m_pVertices[m_HomeIndex].x;
	boundingBox.m_Min.y = pTerrain->m_pVertices[m_HomeIndex].y;
	boundingBox.m_Min.z = m_MinElevation;
	boundingBox.m_Max.x = boundingBox.m_Min.x + width;
	boundingBox.m_Max.y = boundingBox.m_Min.y + width;
	boundingBox.m_Max.z = m_MaxElevation;*/
	float boxDistance;
	if (RayBoxIntersect(&ray, &m_BoundingBox, NULL, &boxDistance))
	{
		if (PointInBox(ray.m_Origin,m_BoundingBox) || boxDistance <= ray.m_Length)
		{
			if (LEAF_SIZE < m_Stride)
			{
				m_pChildren[0]->IntersectRay(ray, intersectionPoint, lowestDistance, pTerrain);
				m_pChildren[1]->IntersectRay(ray, intersectionPoint, lowestDistance, pTerrain);
				m_pChildren[2]->IntersectRay(ray, intersectionPoint, lowestDistance, pTerrain);
				m_pChildren[3]->IntersectRay(ray, intersectionPoint, lowestDistance, pTerrain);
			}
			else
			{
				float distance;
				Vector point;
				const float ERROR_PAD = 0.1f;
				for (int i = 0; i < 8; i++)
				{
					if (RayPlaneIntersect(&ray, m_pTriangles[i].GetPlane(), &point, &distance) == 1)
					{
						if (i == 0 || i == 2 || i == 4 || i == 6)
						{
							if (m_pTriangles[i].GetVertex(0)->x - ERROR_PAD <= point.x && m_pTriangles[i].GetVertex(0)->y - ERROR_PAD <= point.y && point.x - ERROR_PAD <= m_pTriangles[i].GetVertex(2)->x && point.y - ERROR_PAD <= m_pTriangles[i].GetVertex(1)->y && ((fmod(point.y, pTerrain->m_VertexSpacing) + fmod(point.x, pTerrain->m_VertexSpacing)) - ERROR_PAD <= pTerrain->m_VertexSpacing))
							{
								if (distance < lowestDistance)
								{
									lowestDistance = distance;
									intersectionPoint.x = point.x;
									intersectionPoint.y = point.y;
									intersectionPoint.z = point.z;
								}
							}
						}
						else
						{
							if (m_pTriangles[i].GetVertex(1)->x - ERROR_PAD <= point.x && m_pTriangles[i].GetVertex(0)->y - ERROR_PAD <= point.y && point.x - ERROR_PAD <= m_pTriangles[i].GetVertex(2)->x && point.y - ERROR_PAD <= m_pTriangles[i].GetVertex(1)->y && ((fmod(point.y, pTerrain->m_VertexSpacing) + fmod(point.x, pTerrain->m_VertexSpacing)) + ERROR_PAD >= pTerrain->m_VertexSpacing))
							{
								if (distance < lowestDistance)
								{
									lowestDistance = distance;
									intersectionPoint.x = point.x;
									intersectionPoint.y = point.y;
									intersectionPoint.z = point.z;
								}
							}
						}
					}
				}
			}
		}
	}
}




See more files for this project here

NeoEngineNG

NeoenEngine NG (Next Generation) is the evolution of neoengine one,it\'s a different development from NeoEngine2, it\'s a direct inherits from NeoEngine one.\n

Project homepage: http://sourceforge.net/projects/neoengineng
Programming language(s): C,C++
License: other

  Brush.cpp
  DemeterDrawable.cpp
  DemeterEntryPoint.cpp
  DetailTexture.cpp
  GDALElevationLoader.cpp
  Globals.cpp
  Loader.cpp
  MersenneTwister.c
  OGLSL.cpp
  Plane.cpp
  SConscript
  SDLTextureLoader.cpp
  Settings.cpp
  Shader.cpp
  SkyBox.cpp
  StdAfx.cpp
  Terrain.cpp
  TerrainBlock.cpp
  TerrainLattice.cpp
  TerrainVertex.cpp
  Texture.cpp
  TextureCell.cpp
  TextureSet.cpp
  Triangle.cpp
  Vector.cpp