DragonNest/Common/EternityEngineSrv/EtTerrain.cpp
2024-12-19 09:48:26 +08:00

187 lines
4.5 KiB
C++

#include "StdAfx.h"
#include "EtTerrain.h"
#include "EtCollisionFunc.h"
#include "EtLoader.h"
using namespace EternityEngine;
CEtTerrain::CEtTerrain(void)
{
m_BoundingBox.Reset();
m_nBlockOffsetX = 0;
m_nBlockOffsetY = 0;
}
CEtTerrain::~CEtTerrain(void)
{
}
void CEtTerrain::Initialize()
{
CalcBoundingBoxHeight();
CalcBoundingBox();
}
EtVector3 CEtTerrain::GetVertexNormal( int nIndexX, int nIndexY )
{
EtVector3 Return;
Return.x = ( GetHeight( nIndexX - 1, nIndexY ) - GetHeight( nIndexX + 1, nIndexY ) ) / ( m_TerrainInfo.fTileSize * 2 );
Return.y = 1.414f * m_TerrainInfo.fHeightMultiply;
Return.z = ( GetHeight( nIndexX, nIndexY - 1 ) - GetHeight( nIndexX, nIndexY + 1 ) ) / ( m_TerrainInfo.fTileSize * 2 );
EtVec3Normalize( &Return, &Return );
return Return;
}
void CEtTerrain::GetExtent( EtVector3 &Origin, EtVector3 &Extent )
{
Origin = ( m_BoundingBox.Max + m_BoundingBox.Min ) / 2;
Extent = ( m_BoundingBox.Max - m_BoundingBox.Min ) / 2;
}
void CEtTerrain::CalcBoundingBoxHeight()
{
int i, j;
int nSizeX, nSizeY;
nSizeX = m_TerrainInfo.nSizeX + 1;
nSizeY = m_TerrainInfo.nSizeY + 1;
float fValue;
for( i = 0; i < nSizeY; i++ )
{
for( j = 0; j < nSizeX; j++ )
{
fValue = m_TerrainInfo.pHeight[ i * m_nStride + j ] * m_TerrainInfo.fHeightMultiply;
if( fValue > m_BoundingBox.Max.y )
{
m_BoundingBox.Max.y = fValue;
}
if( fValue < m_BoundingBox.Min.y )
{
m_BoundingBox.Min.y = fValue;
}
}
}
}
void CEtTerrain::CalcBoundingBox()
{
m_BoundingBox.Max.x = m_TerrainInfo.TerrainOffset.x + m_TerrainInfo.nSizeX * m_TerrainInfo.fTileSize;
m_BoundingBox.Max.z = m_TerrainInfo.TerrainOffset.z + m_TerrainInfo.nSizeY * m_TerrainInfo.fTileSize;
m_BoundingBox.Min.x = m_TerrainInfo.TerrainOffset.x;
m_BoundingBox.Min.z = m_TerrainInfo.TerrainOffset.z;
m_BoundingBox.Max.y += 1.0f;
m_BoundingBox.Min.y -= 1.0f;
}
float CEtTerrain::Pick( EtVector3 &Origin, EtVector3 &Direction, EtVector3 &PickPos )
{
int nTileX, nTileY, nDirX, nDirY;
EtVector2 Origin2D, Direction2D;
float fTileSize, fDistX, fDistY, fRet;
fTileSize = m_TerrainInfo.fTileSize;
if( Direction.x >= 0.0f )
{
nDirX = 1;
Direction2D.x = Direction.x;
Origin2D.x = Origin.x - m_TerrainInfo.TerrainOffset.x;
}
else
{
nDirX = -1;
Direction2D.x = -Direction.x;
Origin2D.x = m_TerrainInfo.nSizeX * fTileSize - ( Origin.x - m_TerrainInfo.TerrainOffset.x );
}
if( Direction.z >= 0.0f )
{
nDirY = 1;
Direction2D.y = Direction.z;
Origin2D.y = Origin.z - m_TerrainInfo.TerrainOffset.z;
}
else
{
nDirY = -1;
Direction2D.y = -Direction.z;
Origin2D.y = m_TerrainInfo.nSizeY * fTileSize - ( Origin.z - m_TerrainInfo.TerrainOffset.z );
}
while( 1 )
{
nTileX = ( int )( Origin2D.x / fTileSize );
if( nDirX < 0 )
{
nTileX = m_TerrainInfo.nSizeX - nTileX - 1;
}
nTileY = ( int )( Origin2D.y / fTileSize );
if( nDirY < 0 )
{
nTileY = m_TerrainInfo.nSizeY - nTileY - 1;
}
if( !IsInTerrain( nTileX, nTileY ) )
{
break;
}
fRet = TestLintToTile( Origin, Direction, nTileX, nTileY );
if( ( fRet != FLT_MAX ) && ( fRet >= 0.0f ) )
{
PickPos = Origin + Direction * fRet;
return fRet;
}
fDistX = ( ( ( int )( Origin2D.x / fTileSize ) + 1 ) * fTileSize - Origin2D.x ) / Direction2D.x;
fDistY = ( ( ( int )( Origin2D.y / fTileSize ) + 1 ) * fTileSize - Origin2D.y ) / Direction2D.y;
if( fDistX >= fDistY )
{
Origin2D += fDistY * Direction2D;
}
else if( fDistX < fDistY )
{
Origin2D += fDistX * Direction2D;
}
}
return FLT_MAX;
}
bool CEtTerrain::IsInTerrain( int nX, int nY )
{
if( ( nX < 0 ) || ( nX >= m_TerrainInfo.nSizeX ) )
{
return false;
}
if( ( nY < 0 ) || ( nY >= m_TerrainInfo.nSizeY ) )
{
return false;
}
return true;
}
float CEtTerrain::TestLintToTile( EtVector3 &Origin, EtVector3 &Direction, int nTileX, int nTileY )
{
float fTileSize;
float fDist1, fDist2, fBary1, fBary2;
EtVector3 V1, V2, V3, ExtraOrigin;
fTileSize = m_TerrainInfo.fTileSize;
ExtraOrigin = Origin - m_TerrainInfo.TerrainOffset;
V1 = EtVector3( nTileX * fTileSize, GetHeight( nTileX, nTileY ), nTileY * fTileSize );
nTileY++;
V2 = EtVector3( nTileX * fTileSize, GetHeight( nTileX, nTileY ), nTileY * fTileSize );
nTileX++;
V3 = EtVector3( nTileX * fTileSize, GetHeight( nTileX, nTileY ), nTileY * fTileSize );
TestLineToTriangle( ExtraOrigin, Direction, V1, V2, V3, fDist1, fBary1, fBary2 );
nTileY--;
V2 = EtVector3( nTileX * fTileSize, GetHeight( nTileX, nTileY ), nTileY * fTileSize );
TestLineToTriangle( ExtraOrigin, Direction, V1, V3, V2, fDist2, fBary1, fBary2 );
return min( fDist1, fDist2 );
}