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