368 lines
9 KiB
C++
368 lines
9 KiB
C++
#include "StdAfx.h"
|
|
#include "EtConvexVolume.h"
|
|
#include "EtCollisionFunc.h"
|
|
#include "EtLoader.h"
|
|
#include "EtTerrainArea.h"
|
|
|
|
using namespace EternityEngine;
|
|
|
|
DECL_MULTISMART_PTR_STATIC( CEtTerrainArea, MAX_SESSION_COUNT, 20 )
|
|
|
|
CEtTerrainArea::CEtTerrainArea( CMultiRoom *pRoom )
|
|
: CMultiSmartPtrBase< CEtTerrainArea, MAX_SESSION_COUNT >(pRoom)
|
|
{
|
|
m_BoundingBox.Reset();
|
|
m_nBlockCountX = 0;
|
|
m_nBlockCountY = 0;
|
|
m_nBlockSizeX = 0;
|
|
m_nBlockSizeY = 0;
|
|
}
|
|
|
|
CEtTerrainArea::~CEtTerrainArea(void)
|
|
{
|
|
Clear();
|
|
}
|
|
|
|
void CEtTerrainArea::Clear()
|
|
{
|
|
SAFE_DELETE_PVEC( m_vecTerrain );
|
|
}
|
|
|
|
void CEtTerrainArea::CalcSelectCount( int nBlockIndex, int &nStart, int &nEnd )
|
|
{
|
|
if( nBlockIndex == -1 )
|
|
{
|
|
nStart = 0;
|
|
nEnd = ( int )m_vecTerrain.size();
|
|
}
|
|
else
|
|
{
|
|
nStart = nBlockIndex;
|
|
nEnd = nStart + 1;
|
|
}
|
|
}
|
|
|
|
void CEtTerrainArea::Initialize( STerrainInfo *pInfo )
|
|
{
|
|
CEtTerrain *pTerrain;
|
|
int i, j;
|
|
|
|
Clear();
|
|
|
|
m_TerrainInfo = *pInfo;
|
|
|
|
m_nBlockCountX = pInfo->nSizeX / DEFAULT_TERRAIN_SIZE;
|
|
if( pInfo->nSizeX % DEFAULT_TERRAIN_SIZE )
|
|
{
|
|
m_nBlockCountX++;
|
|
}
|
|
m_nBlockSizeX = DEFAULT_TERRAIN_SIZE;
|
|
|
|
m_nBlockCountY = pInfo->nSizeY / DEFAULT_TERRAIN_SIZE;
|
|
if( pInfo->nSizeY % DEFAULT_TERRAIN_SIZE )
|
|
{
|
|
m_nBlockCountY++;
|
|
}
|
|
m_nBlockSizeY = DEFAULT_TERRAIN_SIZE;
|
|
|
|
STerrainInfo TerrainInfo;
|
|
|
|
memcpy( &TerrainInfo, pInfo, sizeof( STerrainInfo ) );
|
|
TerrainInfo.nSizeX = m_nBlockSizeX;
|
|
TerrainInfo.nSizeY = m_nBlockSizeY;
|
|
for( i = 0; i < m_nBlockCountY; i++ )
|
|
{
|
|
for( j = 0; j < m_nBlockCountX; j++ )
|
|
{
|
|
TerrainInfo.pHeight = pInfo->pHeight + ( i * m_nBlockSizeY ) * ( pInfo->nSizeX + 1 ) + j * m_nBlockSizeX;
|
|
TerrainInfo.pLayerDensity = pInfo->pLayerDensity + ( i * m_nBlockSizeY ) * ( pInfo->nSizeX + 1 ) + j * m_nBlockSizeX;
|
|
|
|
TerrainInfo.TerrainOffset = pInfo->TerrainOffset
|
|
+ EtVector3( pInfo->fTileSize * j * m_nBlockSizeX, 0.0f, pInfo->fTileSize * i * m_nBlockSizeY );
|
|
pTerrain = new CEtTerrain();
|
|
pTerrain->SetTerrainInfo( &TerrainInfo );
|
|
pTerrain->SetBlockOffset( j * m_nBlockSizeX, i * m_nBlockSizeY );
|
|
pTerrain->SetStride( pInfo->nSizeX + 1, pInfo->nSizeY + 1 );
|
|
m_vecTerrain.push_back( pTerrain );
|
|
}
|
|
}
|
|
|
|
float fWorldSizeX, fWorldSizeY, fWorldSizeZ;
|
|
fWorldSizeX = m_TerrainInfo.nSizeX * m_TerrainInfo.fTileSize;
|
|
fWorldSizeY = m_TerrainInfo.nSizeY * m_TerrainInfo.fTileSize;
|
|
fWorldSizeZ = pInfo->fHeightMultiply * 65535.f;
|
|
CEtObject::SetWorldSize( GetRoom(), EtVector3( fWorldSizeX * 0.5f, 0.0f, fWorldSizeY * 0.5f ), max( max( fWorldSizeX, fWorldSizeY ), fWorldSizeZ ) );
|
|
|
|
CalcBoundingBox();
|
|
}
|
|
|
|
void CEtTerrainArea::InitializeBlock( int nBlockIndex )
|
|
{
|
|
int i, nStart, nEnd;
|
|
|
|
CalcSelectCount( nBlockIndex, nStart, nEnd );
|
|
for( i = nStart; i < nEnd; i++ )
|
|
{
|
|
m_vecTerrain[ i ]->Initialize();
|
|
}
|
|
CalcBoundingBox();
|
|
}
|
|
|
|
void CEtTerrainArea::ChangeBlockType( TerrainType Type, int nBlockIndex )
|
|
{
|
|
}
|
|
|
|
TerrainType CEtTerrainArea::GetBlockType( int nBlockIndex )
|
|
{
|
|
return TT_NORMAL;
|
|
}
|
|
|
|
void CEtTerrainArea::GetExtent( EtVector3 &Origin, EtVector3 &Extent )
|
|
{
|
|
Origin = ( m_BoundingBox.Max + m_BoundingBox.Min ) / 2;
|
|
Extent = ( m_BoundingBox.Max - m_BoundingBox.Min ) / 2;
|
|
}
|
|
|
|
void CEtTerrainArea::CalcBoundingBox()
|
|
{
|
|
int i;
|
|
SAABox *pBoundingBox;
|
|
|
|
for( i = 0; i < ( int )m_vecTerrain.size(); i++ )
|
|
{
|
|
pBoundingBox = m_vecTerrain[ i ]->GetBoundingBox();
|
|
if( m_BoundingBox.Min.y > pBoundingBox->Min.y )
|
|
{
|
|
m_BoundingBox.Min.y = pBoundingBox->Min.y;
|
|
}
|
|
if( m_BoundingBox.Max.y < pBoundingBox->Max.y )
|
|
{
|
|
m_BoundingBox.Max.y = pBoundingBox->Max.y;
|
|
}
|
|
}
|
|
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;
|
|
}
|
|
|
|
bool CEtTerrainArea::Pick( EtVector3 &Origin, EtVector3 &Direction, EtVector3 &PickPos )
|
|
{
|
|
int i;
|
|
float fMinDist, fFindDist, fDistToBox;
|
|
EtVector3 FindPos, ModifyOrigin;
|
|
|
|
fMinDist = FLT_MAX;
|
|
for( i = 0; i < ( int )m_vecTerrain.size(); i++ )
|
|
{
|
|
SAABox *pBoundingBox;
|
|
|
|
pBoundingBox = m_vecTerrain[ i ]->GetBoundingBox();
|
|
if( !TestLineToBox( Origin, Direction, *pBoundingBox, fDistToBox ) )
|
|
{
|
|
continue;
|
|
}
|
|
if( fDistToBox == 0.0f )
|
|
{
|
|
ModifyOrigin = Origin;
|
|
}
|
|
else
|
|
{
|
|
ModifyOrigin = Origin + Direction * fDistToBox;
|
|
}
|
|
fFindDist = m_vecTerrain[ i ]->Pick( ModifyOrigin, Direction, FindPos ) + fDistToBox;
|
|
if(fFindDist < fMinDist )
|
|
{
|
|
fMinDist = fFindDist;
|
|
PickPos = FindPos;
|
|
}
|
|
}
|
|
|
|
if( fMinDist != FLT_MAX )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool CEtTerrainArea::IsInside( float fX, float fZ )
|
|
{
|
|
if( fX < m_TerrainInfo.TerrainOffset.x )
|
|
{
|
|
return false;
|
|
}
|
|
if( fX > m_TerrainInfo.TerrainOffset.x + m_TerrainInfo.nSizeX * m_TerrainInfo.fTileSize )
|
|
{
|
|
return false;
|
|
}
|
|
if( fZ < m_TerrainInfo.TerrainOffset.z )
|
|
{
|
|
return false;
|
|
}
|
|
if( fZ > m_TerrainInfo.TerrainOffset.z + m_TerrainInfo.nSizeY * m_TerrainInfo.fTileSize )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void CEtTerrainArea::CalcCellPosition( float fX, float fZ, int &nCellX, int &nCellZ, float *pWeight )
|
|
{
|
|
float fModX, fModZ;
|
|
|
|
fX -= m_TerrainInfo.TerrainOffset.x;
|
|
fZ -= m_TerrainInfo.TerrainOffset.z;
|
|
if( fX < 0.0f )
|
|
{
|
|
fX = 0.f;
|
|
}
|
|
else if( fX >= m_TerrainInfo.nSizeX * m_TerrainInfo.fTileSize )
|
|
{
|
|
fX = m_TerrainInfo.nSizeX * m_TerrainInfo.fTileSize - 0.1f;
|
|
}
|
|
|
|
if( fZ < 0.f )
|
|
{
|
|
fZ = 0.f;
|
|
}
|
|
else if( fZ >= m_TerrainInfo.nSizeY * m_TerrainInfo.fTileSize )
|
|
{
|
|
fZ = m_TerrainInfo.nSizeY * m_TerrainInfo.fTileSize - 0.1f;
|
|
}
|
|
|
|
nCellX = ( int )( fX / m_TerrainInfo.fTileSize );
|
|
nCellZ = ( int )( fZ / m_TerrainInfo.fTileSize );
|
|
fModX = fX / m_TerrainInfo.fTileSize - nCellX;
|
|
fModZ = fZ / m_TerrainInfo.fTileSize - nCellZ;
|
|
|
|
if( fModX > fModZ )
|
|
{
|
|
pWeight[ 0 ] = 1.0f - fModX;
|
|
pWeight[ 1 ] = fModX - fModZ;
|
|
pWeight[ 2 ] = 0.0f;
|
|
pWeight[ 3 ] = fModZ;
|
|
}
|
|
else if( fModX < fModZ )
|
|
{
|
|
pWeight[ 0 ] = 1.0f - fModZ;
|
|
pWeight[ 1 ] = 0.0f;
|
|
pWeight[ 2 ] = fModZ - fModX;
|
|
pWeight[ 3 ] = fModX;
|
|
}
|
|
else
|
|
{
|
|
pWeight[ 0 ] = 1.0f - fModZ;
|
|
pWeight[ 1 ] = 0.0f;
|
|
pWeight[ 2 ] = 0.0f;
|
|
pWeight[ 3 ] = fModZ;
|
|
}
|
|
}
|
|
|
|
float CEtTerrainArea::GetLandHeight( float fX, float fZ, EtVector3 *pNormal )
|
|
{
|
|
int i;
|
|
float fRet;
|
|
int nCellX, nCellZ;
|
|
float fHeight[ 4 ], fWeight[ 4 ];
|
|
DWORD dwSectorWidth = m_TerrainInfo.nSizeX + 1;
|
|
|
|
CalcCellPosition( fX, fZ, nCellX, nCellZ, fWeight );
|
|
fHeight[ 0 ] = m_TerrainInfo.pHeight[ nCellZ * dwSectorWidth + nCellX ];
|
|
fHeight[ 1 ] = m_TerrainInfo.pHeight[ nCellZ * dwSectorWidth + nCellX + 1 ];
|
|
fHeight[ 2 ] = m_TerrainInfo.pHeight[ ( nCellZ + 1 ) * dwSectorWidth + nCellX ];
|
|
fHeight[ 3 ] = m_TerrainInfo.pHeight[ ( nCellZ + 1 ) * dwSectorWidth + nCellX + 1 ];
|
|
fRet = 0.0f;
|
|
for( i = 0; i < 4; i++ )
|
|
{
|
|
fRet += fHeight[ i ] * fWeight[ i ];
|
|
}
|
|
|
|
if( pNormal )
|
|
{
|
|
GetVertexNormal( *pNormal, nCellX, nCellZ );
|
|
}
|
|
|
|
return fRet * m_TerrainInfo.fHeightMultiply;
|
|
}
|
|
|
|
void CEtTerrainArea::GetLandNormal( EtVector3 &Normal, float fX, float fZ )
|
|
{
|
|
int i;
|
|
EtVector3 ReturnVec, VertexNormal[ 4 ];
|
|
int nCellX, nCellZ;
|
|
float fWeight[ 4 ];
|
|
|
|
CalcCellPosition( fX, fZ, nCellX, nCellZ, fWeight );
|
|
GetVertexNormal( VertexNormal[ 0 ], nCellX, nCellZ );
|
|
GetVertexNormal( VertexNormal[ 1 ], nCellX + 1, nCellZ );
|
|
GetVertexNormal( VertexNormal[ 2 ], nCellX, nCellZ + 1 );
|
|
GetVertexNormal( VertexNormal[ 3 ], nCellX + 1, nCellZ + 1 );
|
|
ReturnVec = EtVector3( 0.0f, 0.0f, 0.0f );;
|
|
for( i = 0; i < 4; i++ )
|
|
{
|
|
ReturnVec += VertexNormal[ i ] * fWeight[ i ];
|
|
}
|
|
EtVec3Normalize( &Normal, &ReturnVec );
|
|
}
|
|
|
|
void CEtTerrainArea::GetVertexNormal( EtVector3 &Normal, int nCellX, int nCellZ )
|
|
{
|
|
int nHeightIndex;
|
|
float fDX, fDZ;
|
|
EtVector3 Return;
|
|
|
|
DWORD dwTileWidth = m_TerrainInfo.nSizeX + 1;
|
|
DWORD dwTileHeight = m_TerrainInfo.nSizeY + 1;
|
|
nHeightIndex = dwTileWidth * nCellZ + nCellX;
|
|
if( nCellX == 0 )
|
|
{
|
|
fDX = ( m_TerrainInfo.pHeight[ nHeightIndex ] - m_TerrainInfo.pHeight[ nHeightIndex + 1 ] ) / m_TerrainInfo.fTileSize;
|
|
}
|
|
else if( nCellX == dwTileWidth - 1 )
|
|
{
|
|
fDX = ( m_TerrainInfo.pHeight[ nHeightIndex - 1 ] - m_TerrainInfo.pHeight[ nHeightIndex ] ) / m_TerrainInfo.fTileSize;
|
|
}
|
|
else
|
|
{
|
|
fDX = ( m_TerrainInfo.pHeight[ nHeightIndex - 1 ] - m_TerrainInfo.pHeight[ nHeightIndex + 1 ] ) / ( m_TerrainInfo.fTileSize * 2 );
|
|
}
|
|
|
|
if( nCellZ == 0 )
|
|
{
|
|
fDZ = ( m_TerrainInfo.pHeight[ nHeightIndex ] - m_TerrainInfo.pHeight[ nHeightIndex + dwTileWidth ] ) / m_TerrainInfo.fTileSize;
|
|
}
|
|
else if( nCellZ == dwTileHeight - 1 )
|
|
{
|
|
fDZ = ( m_TerrainInfo.pHeight[ nHeightIndex - dwTileWidth ] - m_TerrainInfo.pHeight[ nHeightIndex ] ) / m_TerrainInfo.fTileSize;
|
|
}
|
|
else
|
|
{
|
|
fDZ = ( m_TerrainInfo.pHeight[ nHeightIndex - dwTileWidth ] - m_TerrainInfo.pHeight[ nHeightIndex + dwTileWidth ] ) / ( m_TerrainInfo.fTileSize * 2 );
|
|
}
|
|
|
|
Return.x = fDX;
|
|
Return.y = 1.414f;
|
|
Return.z = fDZ;
|
|
EtVec3Normalize( &Normal, &Return );
|
|
}
|
|
|
|
EtTerrainHandle CEtTerrainArea::GetTerrainArea( CMultiRoom *pRoom, float fX, float fZ )
|
|
{
|
|
int i;
|
|
|
|
for( i = 0; i < GetItemCount(pRoom); i++ )
|
|
{
|
|
EtTerrainHandle hTerrainArea;
|
|
|
|
hTerrainArea = GetItem( pRoom, i );
|
|
if( hTerrainArea->IsInside( fX, fZ ) )
|
|
{
|
|
return hTerrainArea;
|
|
}
|
|
}
|
|
|
|
return CEtTerrainArea::Identity();
|
|
}
|