Files
Leviathan/Client/Game/game/Env/SGameLowQualityWater.cpp
2026-06-01 12:46:52 +02:00

1205 lines
36 KiB
C++

#include "stdafx.h"
#include "SGameLowQualityWater.h"
#include "SGame.h"
#include "KRenderObject.h"
#include "SGameViewPort.h"
#include "K3DTypes.h"
#include "KResourceManager.h"
#include "K3DCamera.h"
#include "EnvironmentInfo.h"
#include "k3dpccp.h"
#include "GameRule.h"
#include "SLowQualityWaterDB.h"
#include "SDebug_Util.h"
namespace
{
//거리 체크
bool CheckDistance( K3DVector* pTargetPos, K3DVector* pMinVertex, K3DVector* pMaxVertex )
{
K3DVector vTargetPos = K3DVector(pTargetPos->x, pTargetPos->y, 0.0f );
K3DVector vLeftTop = K3DVector(pMinVertex->x, pMinVertex->y, 0.0f );
K3DVector vRightBottonm = K3DVector(pMaxVertex->x, pMaxVertex->y, 0.0f );
K3DVector vLeftBotton = K3DVector(pMinVertex->x, pMaxVertex->y, 0.0f );
K3DVector vRightTop = K3DVector(pMaxVertex->x, pMinVertex->y, 0.0f );
float fD1 = K3DVectorLength( vTargetPos - vLeftTop );
float fD2 = K3DVectorLength( vTargetPos - vRightBottonm );
float fD3 = K3DVectorLength( vTargetPos - vLeftBotton );
float fD4 = K3DVectorLength( vTargetPos - vRightTop );
if( fD1 > cTerrainVisibleDistance && fD2 > cTerrainVisibleDistance &&
fD3 > cTerrainVisibleDistance && fD4 > cTerrainVisibleDistance )
return false;
return true;
}
//경계구 충돌 체크
bool CheckSphere( const K3DVector* pPosition, const K3DVector* pCenter, float fRadius1, float fRadius2 )
{
float fXDiff = (float)fabs( pPosition->x - pCenter->x );
float fYDiff = (float)fabs( pPosition->y - pCenter->y );
float fDistance = (float)sqrt( (fXDiff*fXDiff)+(fYDiff*fYDiff) );
if( fDistance <= (fRadius1 + fRadius2) ) //내 경계구와 물의 경계구가 충돌이 됐다면
return true;
return false;
}
bool CheckCameraInWater( K3DVector* vMin, K3DVector* vMax, K3DCamera* pCamera )
{
K3DVector vCampos = pCamera->GetCamPos();
// 카메라 포스와 타겟이 물 사각 안에 있는지 검사
if( (int)vMin->x <= (int)vCampos.x && (int)vMin->y >= (int)vCampos.y &&
(int)vMax->x >= (int)vCampos.x && (int)vMax->y <= (int)vCampos.y )
{
return true;
}
return false;
}
bool CheckPlayerInWater( K3DVector* vMin, K3DVector* vMax, K3DCamera* pCamera, K3DVector & vPlayerPos )
{
// 카메라 포스와 타겟이 물 사각 안에 있는지 검사
if( (int)vMin->x <= (int)vPlayerPos.x && (int)vMin->y >= (int)vPlayerPos.y &&
(int)vMax->x >= (int)vPlayerPos.x && (int)vMax->y <= (int)vPlayerPos.y )
{
//if( fabs( vPlayerPos.z - vMin->z ) <= 1.0f || vPlayerPos.z <= vMin->z ) return true;
//물 높이가 플레이어 보다 높다면
if( ( vPlayerPos.z - vMin->z ) <= 1.5f || vPlayerPos.z <= vMin->z ) return true;
}
return false;
}
bool CheckCameraWaterHeight( K3DVector* vMin, K3DVector* vMax, K3DCamera* pCamera )
{
K3DVector vCampos = pCamera->GetCamPos();
//물이더 높게 있다면
if( vMin->z > vCampos.z )
return true;
return false;
}
}
void WATER_TEXTURE_SET::CreateTextureSet( int nWaterType, LowQualityWater* pLowQualityWaterData )
{
m_nWaterType = nWaterType;
if( pLowQualityWaterData == NULL ) return;
NX3LoadPack loadpack;
loadpack.Init();
char** ppTextureSetName = pLowQualityWaterData->GetTextureFileName();
for( int x = 0; x < cMaxWaterTexture; ++x )
{
std::string strTextureName = ppTextureSetName[x];
strTextureName += ".dds";
m_spTextureArray[x] = KTextureManager::GetManager()->GetTexture( strTextureName.c_str(), &loadpack, true, KTextureManager::GetManager()->GetMipMapBiasLevel() );
}
}
K3DTextureSPtr* WATER_TEXTURE_SET::GetTextureSet()
{
// ++m_nRef;
InterlockedIncrement( (volatile LONG *)&m_nRef ); //m_nRef++;
return m_spTextureArray;
}
bool WATER_TEXTURE_SET::Release()
{
InterlockedDecrement( (volatile LONG *)&m_nRef ); ////m_nRef--;
//이 텍스처 세트를 참조하는 곳이 없다면 0
return ( m_nRef <= 0 ) ? true : false;
}
//디테일 세그먼트 만들기
bool WATER_DETAIL_SEGMENT::CreateDetailSegment( K3DVector* vMin, K3DVector* vMax, KColor sColor, K3DVector* vCenter, int nWidth, int nHeight, class SGame* pGame, bool bIsHigh )
{
///가로 세로 거리를 세그먼트로 나눈다
float fWidthLength = (vMax->x - vMin->x) / (float)(env_fx::c_WaterDetailSegment-1);
float fHeightLength = (vMin->y - vMax->y) / (float)(env_fx::c_WaterDetailSegment-1);
bool bCheck = false;
if( bIsHigh )
{
m_pVertex = new K3DVERTEX_H_WATER[env_fx::c_WaterDetailSegment*env_fx::c_WaterDetailSegment];
K3DVERTEX_H_WATER* pVertex = m_pVertex;
for( int h = 0; h < env_fx::c_WaterDetailSegment; ++h )
{
for( int w = 0; w < env_fx::c_WaterDetailSegment; ++w )
{
pVertex->p = K3DVector4( (float)(vMin->x + (w*fWidthLength) ), (float)( vMin->y - (h*fHeightLength) ), vMin->z, 1.0f );
if( bCheck == false )
{
float fHeight = 0.f;
WORD wTile=0;
bool bSucFindTerrain = pGame->GetHeight( pVertex->p.x+vCenter->x, pVertex->p.y+vCenter->y, fHeight,wTile );
if( bSucFindTerrain && fHeight <= vCenter->z )
{
//몰보다 높은게 존재 한다면 더이상 검사 할 필요가 없음
bCheck = true;
m_bCheckReservation = false;
}
}
++pVertex;
}
}
if( bCheck == false )
{
//지형을 못찾았다면 보류 대상
if( m_bCheckReservation == false )
m_bCheckReservation = true;
}
}
else
{
//이 세그먼트의 가로 세로의 거리를 구한후 미터로 환산한다
//환산한후 c_WaterDetailSegment( 세그먼트 개수 ) 로 나눠 주면 이 세그먼트에
//물을 몇장을 발라야 하는지 알수있음
float fTileCountX = ( (vMax->x - vMin->x) / (float)(GameRule::DEFAULT_UNIT_SIZE*6) ) / env_fx::c_WaterDetailSegment;
float fTileCountY = ( (vMin->y - vMax->y) / (float)(GameRule::DEFAULT_UNIT_SIZE*6) ) / env_fx::c_WaterDetailSegment;
//이전 Segment의 UV값을 유지해야한다
float fUVX = (fTileCountX * (env_fx::c_WaterDetailSegment-1)) * nWidth;
float fUVY = (fTileCountY * (env_fx::c_WaterDetailSegment-1)) * nHeight;
if( m_pVertex )
{
assert(false);
}
m_pVertex = new K3DVERTEX_H_WATER[env_fx::c_WaterDetailSegment*env_fx::c_WaterDetailSegment];
K3DVERTEX_H_WATER* pVertex = m_pVertex;
for( int h = 0; h < env_fx::c_WaterDetailSegment; ++h )
{
for( int w = 0; w < env_fx::c_WaterDetailSegment; ++w )
{
pVertex->p = K3DVector4( (float)(vMin->x + (w*fWidthLength) ), (float)( vMin->y - (h*fHeightLength) ), vMin->z, 1.0f );
// pVertex->normal = K3DVector( 0.f, 0.f, 1.f);
pVertex->color = sColor;
pVertex->tu2 = pVertex->tu = (float)( w * fTileCountX ) + fUVX;
pVertex->tv2 = pVertex->tv = (float)( h * fTileCountY ) + fUVY;
if( bCheck == false )
{
float fHeight = 0.f;
WORD wTile=0;
bool bSucFindTerrain = pGame->GetHeight( pVertex->p.x+vCenter->x, pVertex->p.y+vCenter->y, fHeight,wTile );
if( bSucFindTerrain && fHeight <= vCenter->z )
{
//몰보다 높은게 존재 한다면 더이상 검사 할 필요가 없음
bCheck = true;
m_bCheckReservation = false;
}
}
++pVertex;
}
}
if( bCheck == false )
{
//지형을 못찾았다면 보류 대상
if( m_bCheckReservation == false )
m_bCheckReservation = true;
}
}
return true;
}
void WATER_DETAIL_SEGMENT::SetPrimitiveData( K3DINDEXED_WATER* pIndexed, K3DMatrix* pMatrix )
{
if( m_pPrimitive )
{
assert(false);
}
m_pPrimitive = new SLowQualityWaterPrimitive;
m_pPrimitive->SetCommonVertex( m_pVertex );
m_pPrimitive->SetCommonIndexed( pIndexed );
m_pPrimitive->SetTransform( pMatrix, pMatrix );
K3DVector vCenterPos;
vCenterPos.x = m_vMinVertex.x + ( ( m_vMaxVertex.x - m_vMinVertex.x ) / 2.0f );
vCenterPos.y = m_vMinVertex.y - ( ( m_vMinVertex.y - m_vMaxVertex.y ) / 2.0f );
vCenterPos.z = m_vMinVertex.z;
m_pPrimitive->SetTransparent( true );
m_pPrimitive->SetCenterPosition( vCenterPos );
m_pPrimitive->SetBlendMode( K3DMaterial::MBM_LQ_WATER );
}
void WATER_DETAIL_SEGMENT::SetVertexMinMax(K3DVector* vMin, K3DVector* vMax )
{
m_BoundCube = K3DBoundRotCube( vMax->x, vMin->x, vMax->y, vMin->y, (vMax->z+1.f), (vMin->z-1.f) );
m_vMinVertex = *vMin;
m_vMaxVertex = *vMax;
}
void WATER_DETAIL_SEGMENT::SetChangeColor( KColor Color )
{
K3DVERTEX_H_WATER* pVertex = m_pVertex;
for( int h = 0; h < env_fx::c_WaterDetailSegment; ++h )
{
for( int w = 0; w < env_fx::c_WaterDetailSegment; ++w )
{
pVertex->color = Color;
++pVertex;
}
}
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////
SWater::SWater( class SGame* pGame ) : m_pGame(pGame)
{
m_pHWaterPrimitive = NULL;
m_pIndexed = NULL;
m_spTextureArray = NULL;
m_pCamera = NULL;
m_dwStartTime = 0;
m_nMapX = 0;
m_nMapY = 0;
m_nSegMentCount = 0;
m_nWaterType = 0;
m_Color = KColor( 255, 255, 255, 255 );
m_bIsHighQualityWater = false;
m_vMinVertex = K3DVector( 0.0f, 0.0f, 0.0f );
m_vMaxVertex = K3DVector( 0.0f, 0.0f, 0.0f );
m_vCenterPoint = K3DVector( 0.0f, 0.0f, 0.0f );
m_fRadius = 0.f; //고사양용 스피어 반지름 값
m_fAniCount = 0.0f;
m_dwChangeTime = 50;
m_bTextureAnimation = true;
m_bUVAnimation = false;
m_dwUAniTime = 30;
m_dwVAniTime = 0;
m_dwStartUTime = 0;
m_dwStartVTime = 0;
m_fUCoord = 0.0f;
m_fVCoord = 0.0f;
}
SWater::~SWater()
{
m_spTextureArray = NULL;
m_pCamera = NULL;
SAFE_DELETE( m_pPrimitive );
SAFE_DELETE_ARRAY(m_pIndexed);
SAFE_DELETE_ARRAY(m_pHWaterPrimitive);
std::vector< WATER_DETAIL_SEGMENT* >::iterator iter = m_vWaterSegment.begin();
for( ; iter != m_vWaterSegment.end(); )
{
SAFE_DELETE( (*iter) );
iter = m_vWaterSegment.erase( iter );
}
}
void SWater::Init( K3DRenderDevice *pDevice, K3DIndexBuffer * pIndexBuf )
{
}
//고사양 물
void SWater::CreateSegment( K3DVector* vLeftTop, K3DVector* vRightBottom, K3DVector* vCenter )
{
//컬링용 바운드 큐브 만들기
m_vMinVertex = K3DVector( vLeftTop->x - 0.5f, vLeftTop->y + 0.5f, vLeftTop->z );
m_vMaxVertex = K3DVector( vRightBottom->x + 0.5f, vRightBottom->y - 0.5f, vRightBottom->z );
m_BoundCube = K3DBoundRotCube( m_vMaxVertex.x, m_vMinVertex.x, m_vMaxVertex.y, m_vMinVertex.y, (m_vMaxVertex.z + 1.f), (m_vMinVertex.z - 1.f) );
m_vCenterPoint.x = m_vMinVertex.x + ( ( m_vMaxVertex.x - m_vMinVertex.x ) / 2.0f );
m_vCenterPoint.y = m_vMinVertex.y - ( ( m_vMinVertex.y - m_vMaxVertex.y ) / 2.0f );
m_vCenterPoint.z = m_vMinVertex.z;
m_fRadius = K3DVectorLength( m_vCenterPoint - m_vMinVertex );
m_bIsHighQualityWater = true;
if( m_pHWaterPrimitive == NULL )
{
m_pHWaterPrimitive = new K3DVERTEX_H_WATER[ SHighQualityWaterPrimitive::NUM_SEGMENTS * 2 ];
m_pPrimitive = new SHighQualityWaterPrimitive;
m_pPrimitive->SetCommonVertex(m_pHWaterPrimitive);
m_pPrimitive->SetHQWaterHeight(vCenter->z);
m_pPrimitive->SetTransparent( true );
m_pPrimitive->SetCenterPosition( m_vCenterPoint );
m_pPrimitive->SetBlendMode( K3DMaterial::MBM_HQ_WATER );
}
int nNumSegment = SHighQualityWaterPrimitive::NUM_SEGMENTS;
float fStartU1 = 1.0f;
float fIncU1 = -1.0f / ( float ) ( nNumSegment - 1 );
float fV1[ 2 ] = { 0.0f, 1.0f };
float fU2[ 2 ] = { 1.0f, 0.0f };
float fStartV2 = 1.0f;
float fIncV2 = -1.0f / ( float ) ( nNumSegment - 1 );
K3DVector normal( 0.0f, 0.0f, 1.0f );
for( int i = 0; i < SHighQualityWaterPrimitive::NUM_SEGMENTS * 2; i ++ )
{
// m_pHWaterPrimitive[ i ].normal = normal;
m_pHWaterPrimitive[ i ].color = m_Color;//( DWORD ) D3DCOLOR_ARGB( m_Color.a, m_Color.r, m_Color.g, m_Color.b );
m_pHWaterPrimitive[ i ].tu = fStartU1 + fIncU1 * ( float ) ( i / 2 );
m_pHWaterPrimitive[ i ].tv = fV1[ i % 2 ];
m_pHWaterPrimitive[ i ].tu2 = fU2[ i % 2 ];
m_pHWaterPrimitive[ i ].tv2 = fStartV2 + fIncV2 * ( float ) ( i / 2 );
}
int iWidth = 32; // 물 반사 맵 은 가로 32개 정도 쪼개자
int iHeight = 32; // 물 반사 맵 은 세로 32개 정도 쪼개자
//느슨하게 만들자
float flooseX = (vRightBottom->x - vLeftTop->x) / pow((double)2,5);
float flooseY = (vLeftTop->y - vRightBottom->y) / pow((double)2,5);
//세크먼트 개수
m_nSegMentCount = iWidth*iHeight;
//간격 구하기
float fWidthLength = (vRightBottom->x - vLeftTop->x) / iWidth;
float fHeightLength = (vLeftTop->y - vRightBottom->y) / iHeight;
float fWidthCenter = (vRightBottom->x - vLeftTop->x) / 2.f;
float fHeightCenter = (vLeftTop->y - vRightBottom->y) / 2.f;
for( int h = 0; h < iHeight; ++h )
{
for( int w = 0; w < iWidth; ++w )
{
WATER_DETAIL_SEGMENT* pWaterSegment = new WATER_DETAIL_SEGMENT;
K3DVector vMin = K3DVector( (float)(-fWidthCenter) + (w*fWidthLength), (float)( fHeightCenter - (h*fHeightLength) ), 0.f);
K3DVector vMax = K3DVector( (float)(-fWidthCenter) + ((w+1)*fWidthLength), (float)( fHeightCenter - ((h+1)*fHeightLength) ), 0.f);
bool bSuc = pWaterSegment->CreateDetailSegment( &vMin, &vMax, m_Color, &m_vCenterPoint, w, h, m_pGame, true );
pWaterSegment->SetVertexMinMax( &K3DVector( (vMin.x + m_vCenterPoint.x)-flooseX, (vMin.y + m_vCenterPoint.y)+flooseY, m_vCenterPoint.z ),
&K3DVector( (vMax.x + m_vCenterPoint.x)+flooseX, (vMax.y + m_vCenterPoint.y)-flooseY, m_vCenterPoint.z ) );
if( bSuc ) m_vWaterSegment.push_back( pWaterSegment );
else SAFE_DELETE( pWaterSegment );
}
}
}
//저사양 물
void SWater::CreateSegment( K3DVector* vLeftTop, K3DVector* vRightBottom, K3DVector* vCenter, float fTileLength )
{
//가로 세로 크기를 구한다
int iWidth = (int)((vRightBottom->x - vLeftTop->x)/fTileLength);
int iHeight = (int)((vLeftTop->y - vRightBottom->y)/fTileLength);
float fDepth = 1;
if( iWidth >= 32 && iHeight >= 32 )
{
iWidth = 32;
iHeight = 32;
fDepth = 5;
}
else if( iWidth >= 16 && iHeight >= 16 )
{
iWidth = 16;
iHeight = 16;
fDepth = 4;
}
else if( iWidth >= 8 && iHeight >= 8 )
{
iWidth = 8;
iHeight = 8;
fDepth = 3;
}
else
{
iWidth = 4;
iHeight = 4;
fDepth = 2;
}
//느슨하게 만들자
float flooseX = (vRightBottom->x - vLeftTop->x) / pow((double)2,(double)fDepth);
float flooseY = (vLeftTop->y - vRightBottom->y) / pow((double)2,(double)fDepth);
iWidth -= 1;
iHeight -= 1;
//컬링용 바운드 큐브 만들기
m_vMinVertex = K3DVector( vLeftTop->x - 0.5f, vLeftTop->y + 0.5f, vLeftTop->z );
m_vMaxVertex = K3DVector( vRightBottom->x + 0.5f, vRightBottom->y - 0.5f, vRightBottom->z );
m_BoundCube = K3DBoundRotCube( m_vMaxVertex.x, m_vMinVertex.x, m_vMaxVertex.y, m_vMinVertex.y, (m_vMaxVertex.z + 1.f), (m_vMinVertex.z - 1.f) );
m_vCenterPoint = *vCenter;
//세크먼트 개수
m_nSegMentCount = iWidth*iHeight;
//간격 구하기
float fWidthLength = (vRightBottom->x - vLeftTop->x) / iWidth;
float fHeightLength = (vLeftTop->y - vRightBottom->y) / iHeight;
float fWidthCenter = (vRightBottom->x - vLeftTop->x) / 2.f;
float fHeightCenter = (vLeftTop->y - vRightBottom->y) / 2.f;
int h;
for( h = 0; h < iHeight; ++h )
{
for( int w = 0; w < iWidth; ++w )
{
WATER_DETAIL_SEGMENT* pWaterSegment = new WATER_DETAIL_SEGMENT;
K3DVector vMin = K3DVector( (float)(-fWidthCenter) + (w*fWidthLength), (float)( fHeightCenter - (h*fHeightLength) ), 0.f);
K3DVector vMax = K3DVector( (float)(-fWidthCenter) + ((w+1)*fWidthLength), (float)( fHeightCenter - ((h+1)*fHeightLength) ), 0.f);
bool bSuc = pWaterSegment->CreateDetailSegment( &vMin, &vMax, m_Color, &m_vCenterPoint, w, h, m_pGame );
pWaterSegment->SetVertexMinMax( &K3DVector( vMin.x + m_vCenterPoint.x-flooseX, vMin.y + m_vCenterPoint.y+flooseY, m_vCenterPoint.z ),
&K3DVector( vMax.x + m_vCenterPoint.x+flooseX, vMax.y + m_vCenterPoint.y-flooseY, m_vCenterPoint.z ) );
if( bSuc ) m_vWaterSegment.push_back( pWaterSegment );
else SAFE_DELETE( pWaterSegment );
}
}
//공용으로 사용될 인덱스
m_pIndexed = new K3DINDEXED_WATER[env_fx::c_WaterDetailSegmentIndexedCount];
K3DINDEXED_WATER* pIndexed = m_pIndexed;
for( h = 0; h < (env_fx::c_WaterDetailSegment-1); ++h )
{
for( int w = 0; w < (env_fx::c_WaterDetailSegment-1); ++w )
{
pIndexed->a = (WORD)((env_fx::c_WaterDetailSegment*h)+w);
pIndexed->b = (WORD)((env_fx::c_WaterDetailSegment*h)+w+1);
pIndexed->c = (WORD)((env_fx::c_WaterDetailSegment*(h+1))+w);
++pIndexed;
pIndexed->a = (WORD)((env_fx::c_WaterDetailSegment*h)+w+1);
pIndexed->b = (WORD)((env_fx::c_WaterDetailSegment*(h+1))+w+1);
pIndexed->c = (WORD)((env_fx::c_WaterDetailSegment*(h+1))+w);
++pIndexed;
}
}
K3DMatrixIdentity( m_matWorld );
K3DMatrixTranslation( m_matWorld, m_vCenterPoint.x, m_vCenterPoint.y, m_vCenterPoint.z );
std::vector< WATER_DETAIL_SEGMENT* >::iterator iter = m_vWaterSegment.begin();
for( ; iter != m_vWaterSegment.end(); ++iter )
(*iter)->SetPrimitiveData( m_pIndexed, &m_matWorld );
}
//사용될 텍스처 세트 및 심리스 월드 좌표
void SWater::SetWaterInfoData( int nWaterType, int nMapX, int nMapY, K3DCamera* pCamera, WATER_TEXTURE_SET* pTextureSet )
{
m_nWaterType = nWaterType;
m_nMapX = nMapX;
m_nMapY = nMapY;
m_pCamera = pCamera;
if( pTextureSet )
m_spTextureArray = pTextureSet->GetTextureSet();
}
void SWater::Process( DWORD dwTime )
{
if(m_pHWaterPrimitive) { return; }
if( m_bTextureAnimation )
{
if( m_dwChangeTime > 0 )
{
if( m_dwStartTime == 0 ) m_dwStartTime = dwTime;
m_fAniCount = (float)( (dwTime - m_dwStartTime) / m_dwChangeTime );
if( (int)m_fAniCount >= cMaxWaterTexture )
{
m_fAniCount = 0.0f;
m_dwStartTime = dwTime;
}
}
}
else
{
m_dwStartTime = 0;
}
if( m_bUVAnimation )
{
float fTime = 0.0f;
if( m_dwUAniTime > 0 )
{
if( m_dwStartUTime == 0 ) m_dwStartUTime = dwTime;
m_fUCoord = (float)((dwTime - m_dwStartUTime) / m_dwUAniTime) * 0.01f;
if( m_fUCoord > 1.0f )
{
m_fUCoord = 0.0f;
m_dwStartUTime = dwTime;
}
}
if( m_dwVAniTime > 0 )
{
if( m_dwStartVTime == 0 ) m_dwStartVTime = dwTime;
m_fVCoord = (float)((dwTime - m_dwStartVTime) / m_dwVAniTime) * 0.01f;
if( m_fVCoord > 1.0f )
{
m_fVCoord = 0.0f;
m_dwStartVTime = dwTime;
}
}
}
else
{
m_dwStartUTime = 0;
m_dwStartVTime = 0;
m_fUCoord = 0.0f;
m_fVCoord = 0.0f;
}
}
void SWater::Render( KViewportObject *viewport )
{
bool bCheckCameraInWater = false;
float fHeight = 0.f;
std::vector< WATER_DETAIL_SEGMENT* >::iterator iter = m_vWaterSegment.begin();
if(m_pHWaterPrimitive)
{
bool bRenderHQWater = false;
for( ; iter != m_vWaterSegment.end(); )
{
//세부 세그먼트 컬링
bool bVisible = KPCCP::nonuniformcube_collide_nonuniformcube(viewport->GetFrustum(), (*iter)->GetBoundCube() );
if( !bVisible ) { ++iter; continue; }
if( CheckDistance( &m_pCamera->GetTargetPos(), (*iter)->GetMinVertex(), (*iter)->GetMaxVertex() ) )//거리 체크
{
bRenderHQWater = true;
if( !bCheckCameraInWater )
{
if( CheckCameraInWater( (*iter)->GetMinVertex(), (*iter)->GetMaxVertex(), m_pCamera ) )
{
bCheckCameraInWater = true;
if( viewport->GetWaterHeight() < (*iter)->GetMinVertex()->z )
{
viewport->SetWaterHeight( true, (*iter)->GetMinVertex()->z );
if( CheckCameraWaterHeight( (*iter)->GetMinVertex(), (*iter)->GetMaxVertex(), m_pCamera ) )
viewport->SetInsideWater( true );
}
break;
}
}
//if( m_spTextureArray[ m_cAniCount ] ) m_pPrimitive->SetTexture( 2, m_spTextureArray[ m_cAniCount ] );
//else m_pPrimitive->SetTexture( 2, NULL );
if( !CheckReservation( (*iter) ) )
{
SAFE_DELETE( (*iter) );
iter = m_vWaterSegment.erase( iter );
continue;
}
}
++iter;
}
if( bRenderHQWater )
{
// sonador 7.0.14 카메라 위치에 따른 물효과 컬링 문제 수정
viewport->Register( m_pPrimitive , KRenderObject::RENDEREFX_WATER );
viewport->SetRenderWater(true);
}
else
viewport->SetRenderWater(false);
return;
}
for( ; iter != m_vWaterSegment.end(); )
{
//세부 세그먼트 컬링
bool bVisible = KPCCP::nonuniformcube_collide_nonuniformcube( viewport->GetFrustum(), (*iter)->GetBoundCube() );
if( !bVisible ) { ++iter; continue; }
if( CheckDistance( &m_pCamera->GetTargetPos(), (*iter)->GetMinVertex(), (*iter)->GetMaxVertex() ) )//거리 체크
{
if( !bCheckCameraInWater )
{
//카메라가 물영역 안에 있는지 검사
if( CheckCameraInWater( (*iter)->GetMinVertex(), (*iter)->GetMaxVertex(), m_pCamera ) )
{
bCheckCameraInWater = true;
if( viewport->GetWaterHeight() < (*iter)->GetMinVertex()->z )
{
viewport->SetWaterHeight( true, (*iter)->GetMinVertex()->z );
//수면 밑으로 카메라가 들어갔다면
if( CheckCameraWaterHeight( (*iter)->GetMinVertex(), (*iter)->GetMaxVertex(), m_pCamera ) )
viewport->SetInsideWater( true );
}
}
}
if( CheckReservation( (*iter) ) )
{
SEnvPrimitive* pPrimitive = (*iter)->GetPrimitive();
assert( pPrimitive );
if( pPrimitive )
{
if(m_spTextureArray[(int)m_fAniCount] != NULL) pPrimitive->SetTexture(0, m_spTextureArray[(int)m_fAniCount]);
else pPrimitive->SetTexture(0, NULL );
/* pPrimitive->SetTextureStage(0, m_spTextureArray[0] );
pPrimitive->SetTextureStage(1, m_spTextureArray[1] );*/
pPrimitive->SetTextureUVAnimation( m_fUCoord, m_fVCoord );
// sonador 7.0.14 카메라 위치에 따른 물효과 컬링 문제 수정
viewport->Register( pPrimitive , KRenderObject::RENDEREFX_WATER );
}
}
else
{
SAFE_DELETE( (*iter) );
iter = m_vWaterSegment.erase( iter );
continue;
}
}
++iter;
}
}
bool SWater::CheckReservation( WATER_DETAIL_SEGMENT* pDetail )
{
if( !pDetail->IsCheckReservation() ) return true;
const K3DVERTEX_H_WATER* pVertex = pDetail->GetVertex();
for( int h = 0; h < env_fx::c_WaterDetailSegment; ++h )
{
for( int w = 0; w < env_fx::c_WaterDetailSegment; ++w )
{
float fHeight = 0.f;
WORD wTile=0;
bool bSucFindTerrain = m_pGame->GetHeight( pVertex->p.x + m_vCenterPoint.x, pVertex->p.y + m_vCenterPoint.y, fHeight,wTile );
if( bSucFindTerrain )
{
//지형보다 높다면
if( fHeight <= m_vCenterPoint.z )
{
pDetail->SetCheckReservation(false);
return true;
}
}
else
return true; //여전히 찾기 실패 했다면 기냥 그리자
++pVertex;
}
}
//지형 보다 높은 폴리곤이 없다면 삭제한다
return false;
}
void SWater::SetChangeColor( KColor Color, bool bNewColor )
{
if(m_pHWaterPrimitive) return;
std::vector< WATER_DETAIL_SEGMENT* >::iterator iter = m_vWaterSegment.begin();
for( ; iter != m_vWaterSegment.end(); ++iter )
{
if( bNewColor ) (*iter)->SetChangeColor( Color );
else (*iter)->SetChangeColor( m_Color );
}
}
void SWater::SetChangeTextureTime( DWORD dwTime )
{
m_dwChangeTime = dwTime;
}
K3DVector* SWater::GetBoundCube()
{
return (K3DVector*)m_BoundCube.GetVertices();
}
void SWater::SetHqWaterColor( BYTE r, BYTE g, BYTE b, BYTE a )
{
DWORD dwColor = ( DWORD ) b | ( DWORD ) g << 8 | ( DWORD ) r << 16 | ( DWORD ) a << 24;
if( m_pHWaterPrimitive )
{
for ( int i = 0; i < SHighQualityWaterPrimitive::NUM_SEGMENTS * 2; i++ )
m_pHWaterPrimitive[ i ].color = dwColor;
}
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////
SGameLowQualityWater::SGameLowQualityWater()
{
m_pGame = NULL;
m_pCamera = NULL;
}
SGameLowQualityWater::~SGameLowQualityWater()
{
std::vector< SWater* >::iterator vWaterPrimitive = m_vWaterPrimitive.begin();
for( ; vWaterPrimitive != m_vWaterPrimitive.end(); )
{
SAFE_DELETE( (*vWaterPrimitive) );
vWaterPrimitive = m_vWaterPrimitive.erase(vWaterPrimitive);
}
m_vWaterPrimitive.clear();
std::vector< WATER_TEXTURE_SET* >::iterator vTextureSet = m_vTextureSet.begin();
for( ; vTextureSet != m_vTextureSet.end(); )
{
SAFE_DELETE( (*vTextureSet) );
vTextureSet = m_vTextureSet.erase(vTextureSet);
}
m_vTextureSet.clear();
m_pGame = NULL;
m_pCamera = NULL;
}
bool SGameLowQualityWater::Init()
{
return true;
}
void SGameLowQualityWater::AddLowQualityWater( int nMapX, int nMapY, WATERAREA_HEADER* pWaterInfo, float fTileLength )
{
LowQualityWater* pLowQualityWaterData = GetLowQualityWaterDB().GetLowQualityWaterData( pWaterInfo->nWaterType );
if( pLowQualityWaterData == NULL )
{
assert( false && "물정보가 없습니다." );
_oprint( "물정보가 없습니다. %d\n", pWaterInfo->nWaterType );
}
WATER_TEXTURE_SET* pTextureSet = GetTextureSetData( pWaterInfo->nWaterType );
//텍스처 세트가 없다면
if( pTextureSet == NULL )
{
pTextureSet = new WATER_TEXTURE_SET;
pTextureSet->CreateTextureSet( pWaterInfo->nWaterType, pLowQualityWaterData ); //텍스처 이름 DB에서 읽어오자
m_vTextureSet.push_back(pTextureSet);
}
SWater* pWater = new SWater( m_pGame );
if( pLowQualityWaterData )
{
pWater->SetColor( KColor(pLowQualityWaterData->r, pLowQualityWaterData->g, pLowQualityWaterData->b, pLowQualityWaterData->a) );
pWater->SetChangeTimeTexture( pLowQualityWaterData->texture_change_time );
}
pWater->CreateSegment(&pWaterInfo->vLeftTop, &pWaterInfo->vRightBottom, &pWaterInfo->vCenter, fTileLength);
pWater->SetWaterInfoData( pWaterInfo->nWaterType, nMapX, nMapY, m_pCamera, pTextureSet );
m_vWaterPrimitive.push_back(pWater);
}
void SGameLowQualityWater::AddHighQualityWater( int nMapX, int nMapY, struct WATERAREA_HEADER* pWaterInfo )
{
LowQualityWater* pLowQualityWaterData = GetLowQualityWaterDB().GetLowQualityWaterData( pWaterInfo->nWaterType );
if( pLowQualityWaterData == NULL )
{
assert( false && "물정보가 없습니다." );
_oprint( "물정보가 없습니다. %d\n", pWaterInfo->nWaterType );
}
//// 임시코드 by blackfish ->
//WATER_TEXTURE_SET* pTextureSet = GetTextureSetData( pWaterInfo->nWaterType );
////텍스처 세트가 없다면
//if( pTextureSet == NULL )
//{
// pTextureSet = new WATER_TEXTURE_SET;
// pTextureSet->CreateTextureSet( pWaterInfo->nWaterType, pLowQualityWaterData ); //텍스처 이름 DB에서 읽어오자
// m_vTextureSet.push_back(pTextureSet);
//}
//// <- 임시코드 by blackfish
SWater* pWater = new SWater( m_pGame );
if( pLowQualityWaterData )
pWater->SetColor( KColor(pLowQualityWaterData->r, pLowQualityWaterData->g, pLowQualityWaterData->b, pLowQualityWaterData->a) );
else
pWater->SetColor( KColor(255, 255, 255, 255) ); //컬러값 DB에서 읽어 오자
pWater->CreateSegment(&pWaterInfo->vLeftTop, &pWaterInfo->vRightBottom, &pWaterInfo->vCenter);
//pWater->SetWaterInfoData( 0, nMapX, nMapY, m_pCamera, pTextureSet );
pWater->SetWaterInfoData( 0, nMapX, nMapY, m_pCamera );
pWater->SetHighQualityWater(true);
m_vWaterPrimitive.push_back(pWater);
}
void SGameLowQualityWater::SetGame( SGame* pGame )
{
m_pGame = pGame;
}
void SGameLowQualityWater::SetCamera( K3DCamera* pCamera )
{
m_pCamera = pCamera;
}
//높낮이 체크해서 렌더 할지 결정한다
bool SGameLowQualityWater::CheckHeight( K3DVector* vMin, K3DVector* vMax, K3DVector* vCenter )
{
K3DVector vCampos = m_pCamera->GetCamPos();
K3DVector vTarPos = m_pCamera->GetTargetPos();
bool bInsideCam = false;
bool bInsideTar = false;
// 카메라 포스와 타겟이 물 사각 안에 있는지 검사
if( vMin->x <= vCampos.x && vMin->y >= vCampos.y &&
vMax->x >= vCampos.x && vMax->y <= vCampos.y )
{
bInsideCam = true;
}
if( vMin->x <= vTarPos.x && vMin->y >= vTarPos.y &&
vMax->x >= vTarPos.x && vMax->y <= vTarPos.y )
{
bInsideTar = true;
}
//카메라 포스나 타겟의 위치가 물 사각안에 있다면 리턴 true
if( bInsideCam || bInsideTar ) return true;
//카메라 포스나 타겟 둘중 하나가 물의 높이보다 높다면 리턴 true
if( vCenter->z < vCampos.z || vCenter->z < vTarPos.z )
return true;
//둘다 물 높이 보다 작다면 리턴 false
return false;
}
void SGameLowQualityWater::Process( DWORD dwTime, float fTerrainVisibleDistance )
{
std::vector< SWater* >::iterator iter = m_vWaterPrimitive.begin();
for( ; iter != m_vWaterPrimitive.end(); ++iter )
{
(*iter)->Process( dwTime );
}
cTerrainVisibleDistance = m_fTerrainVisibleDistance = fTerrainVisibleDistance;
}
void SGameLowQualityWater::Render( KViewportObject *viewport )
{
viewport->SetWaterHeight( false );
viewport->SetInsideWater( false );
bool bSetRenderHqWater = false;
std::vector< SWater* >::iterator iter = m_vWaterPrimitive.begin();
for( ; iter != m_vWaterPrimitive.end(); ++iter )
{
SWater* pWater = (*iter);
bool bVisible = KPCCP::nonuniformcube_collide_nonuniformcube(viewport->GetFrustum(), pWater->GetBoundCube() );
if(bVisible)
{
if( CheckHeight( pWater->GetMinVertex(), pWater->GetMaxVertex(), pWater->GetCenterPoint() ) )
{
pWater->Render( viewport );
if( pWater->IsHighQualityWater() ) //고사양 물일경우 렌더 여부 체크
bSetRenderHqWater = true;
}
else if( pWater->IsHighQualityWater() )
{
viewport->SetRenderWater( bSetRenderHqWater );
}
}
else if( pWater->IsHighQualityWater() )
{
viewport->SetRenderWater( bSetRenderHqWater );
}
}
}
void SGameLowQualityWater::RemoveWater( int nMapX, int nMapY )
{
std::vector< SWater* >::iterator iter = m_vWaterPrimitive.begin();
for( ; iter != m_vWaterPrimitive.end(); )
{
// _oprint( "RemoveWater : %d\n", (*iter)->GetWaterType() );
if( (*iter)->CheckMap(nMapX, nMapY) )
{
//저사양 물만 텍스쳐셋을 갖고 있음.
if( !(*iter)->IsHighQualityWater() )
RemoveTextureSet( (*iter)->GetWaterType() );
SAFE_DELETE( (*iter) );
iter = m_vWaterPrimitive.erase(iter);
}
else
++iter;
}
}
WATER_TEXTURE_SET* SGameLowQualityWater::GetTextureSetData( int nWaterType )
{
std::vector< WATER_TEXTURE_SET* >::iterator iter = m_vTextureSet.begin();
for(; iter != m_vTextureSet.end(); ++iter )
{
if( (*iter)->GetWaterType() == nWaterType )
return (*iter);
}
return NULL;
}
void SGameLowQualityWater::RemoveTextureSet( int nWaterType )
{
std::vector< WATER_TEXTURE_SET* >::iterator iter = m_vTextureSet.begin();
for(; iter != m_vTextureSet.end(); )
{
// _oprint( "WaterType() : %d\n", nWaterType );
if( (*iter)->GetWaterType() == nWaterType )
{
if( (*iter)->Release() )
{
SAFE_DELETE((*iter));
iter = m_vTextureSet.erase(iter);
continue;
}
}
++iter;
}
}
void SGameLowQualityWater::SetLowQualityWaterColor( KColor Color, bool bNewColor )
{
std::vector< SWater* >::iterator iter = m_vWaterPrimitive.begin();
for( ; iter != m_vWaterPrimitive.end(); ++iter )
{
(*iter)->SetChangeColor( Color, bNewColor );
}
}
void SGameLowQualityWater::SetLowQualityWaterChangeTextureTime( DWORD dwTime )
{
std::vector< SWater* >::iterator iter = m_vWaterPrimitive.begin();
for( ; iter != m_vWaterPrimitive.end(); ++iter )
{
(*iter)->SetChangeTextureTime( dwTime );
}
}
SWater* SGameLowQualityWater::GetHightQualityWater()
{
std::vector< SWater* >::iterator iter = m_vWaterPrimitive.begin();
for( ; iter != m_vWaterPrimitive.end(); ++iter )
{
if( (*iter)->IsHighQualityWater() )
return (*iter);
}
return NULL;
}
bool SGameLowQualityWater::PlayerInsideWaterExistence( K3DVector & vPlayerPos )
{
std::vector< SWater* >::iterator iter = m_vWaterPrimitive.begin();
for( ; iter != m_vWaterPrimitive.end(); ++iter )
{
SWater* pWater = (*iter);
if( CheckPlayerInWater( pWater->GetMinVertex(), pWater->GetMaxVertex(), m_pCamera, vPlayerPos ) )
{
return true;
}
}
return false;
}
bool SGameLowQualityWater::GetWaterHeight( K3DVector & vPlayerPos, float & fHeight )
{
std::vector< SWater* >::iterator iter = m_vWaterPrimitive.begin();
for( ; iter != m_vWaterPrimitive.end(); ++iter )
{
SWater* pWater = (*iter);
if( CheckPlayerInWater( pWater->GetMinVertex(), pWater->GetMaxVertex(), m_pCamera, vPlayerPos ) )
{
fHeight = pWater->GetMinVertex()->z;
return true;
}
}
return false;
}
// { [sonador][COLLIDABLE_CAMERA]
bool SGameLowQualityWater::GetLineCrossedPoint( const K3DVector& vNear, const K3DVector& vFar, const float fRadius, float& fNearestT, K3DVector& p )
{
// infinite
if( vNear.z == vFar.z ) return false;
K3DVector intersection, candidate, min, max;
std::vector< SWater* >::iterator itEnd = m_vWaterPrimitive.end();
for( std::vector< SWater* >::iterator it = m_vWaterPrimitive.begin();
it != itEnd; ++it )
{
SWater* pWater = (*it);
min = *pWater->GetMinVertex();
max = *pWater->GetMaxVertex();
if( min.x > max.x ) std::swap( min.x, max.x );
if( min.y > max.y ) std::swap( min.y, max.y );
min.z += fRadius;
max.z += fRadius;
// fast culling
// xxxx|xxxxxxxxx|xxxx
// xxxx|xxxxxxxxx|xxxx
// ----+---------+----
// xxxx| |xxxx
// xxxx| |xxxx
// xxxx| |xxxx
// xxxx| |xxxx
// ----+---------+----
// xxxx|xxxxxxxxx|xxxx
// xxxx|xxxxxxxxx|xxxx
if( ( vNear.z < min.z && vFar.z < min.z ) || ( vNear.z > min.z && vFar.z > min.z ) ||
( vNear.x < min.x && vFar.x < min.x ) || ( vNear.x > max.x && vFar.x > max.x ) ||
( vNear.y < min.y && vFar.y < min.y ) || ( vNear.y > max.y && vFar.y > max.y ) )
continue;
// min 0 +---------+ 1
// | left / |
// | / |
// | / |
// | / right |
// 2 +---------+ 3 max
K3DVertex polygon[ 4 ];
polygon[ 0 ].Set( min.x, min.y, min.z ); // 0
polygon[ 1 ].Set( max.x, min.y, min.z ); // 1
polygon[ 2 ].Set( min.x, max.y, min.z ); // 2
polygon[ 3 ].Set( max.x, max.y, min.z ); // 3
float fT = 1.0f;
// check left plane
fT = KPCCP::triangle_collide_edge_twosides( polygon[ 2 ], polygon[ 1 ], polygon[ 0 ], vNear, vFar, p );
if( fNearestT > fT )
{
fNearestT = fT;
return true;
}
// check right plane
fT = KPCCP::triangle_collide_edge_twosides( polygon[ 2 ], polygon[ 3 ], polygon[ 1 ], vNear, vFar, p );
if( fNearestT > fT )
{
fNearestT = fT;
return true;
}
}
return false;
}
// }
// { [sonador][7.1.7]충돌 처리 개선(Swept Shpere Collision Detection)
bool SGameLowQualityWater::GetEllipsoidCrossedPoint
( const K3DVector& vBase
, const K3DVector& vVelocity
, const K3DVector& vRadius
, float& fNearestT
, K3DVector& vPickedPoint
#ifdef _DEBUG
, K3DVector* pCollidedPolygon
#endif
) const
{
bool bFound = false;
float fT = 1.0f;
K3DVector vIntersection, vMin, vMax, vFar( vBase + vVelocity );
K3DVector vBaseInESpace ( vBase.x / vRadius.x, vBase.y / vRadius.y, vBase.z / vRadius.z );
K3DVector vVelocityInESpace ( vVelocity.x / vRadius.x, vVelocity.y / vRadius.y, vVelocity.z / vRadius.z );
std::vector< SWater* >::const_iterator itEnd = m_vWaterPrimitive.end( );
for( std::vector< SWater* >::const_iterator it = m_vWaterPrimitive.begin( ); it != itEnd; ++it )
{
SWater* pWater = (*it);
vMin = *pWater->GetMinVertex( );
vMax = *pWater->GetMaxVertex( );
if( vMin.x > vMax.x ) std::swap( vMin.x, vMax.x );
if( vMin.y > vMax.y ) std::swap( vMin.y, vMax.y );
// fast culling
// xxxx|xxxxxxxxx|xxxx
// xxxx|xxxxxxxxx|xxxx
// ----+---------+----
// xxxx| |xxxx
// xxxx| |xxxx
// xxxx| |xxxx
// xxxx| |xxxx
// ----+---------+----
// xxxx|xxxxxxxxx|xxxx
// xxxx|xxxxxxxxx|xxxx
if( ( ( vBase.z + vRadius.z ) < vMin.z && ( vFar.z + vRadius.z ) < vMin.z ) || ( ( vBase.z - vRadius.z ) > vMin.z && ( vFar.z - vRadius.z ) > vMin.z ) ||
( ( vBase.x + vRadius.x ) < vMin.x && ( vFar.x + vRadius.x ) < vMin.x ) || ( ( vBase.x - vRadius.x ) > vMax.x && ( vFar.x - vRadius.x ) > vMax.x ) ||
( ( vBase.y + vRadius.y ) < vMin.y && ( vFar.y + vRadius.y ) < vMin.y ) || ( ( vBase.y - vRadius.y ) > vMax.y && ( vFar.y - vRadius.y ) > vMax.y ) )
continue;
// vMin 0 +---------+ 1
// | left / |
// | / |
// | / |
// | / right |
// 2 +---------+ 3 vMax
K3DVertex vPolygon[ 4 ];
vPolygon[ 0 ].Set( vMin.x / vRadius.x, vMin.y / vRadius.y, vMin.z / vRadius.z ); // 0
vPolygon[ 1 ].Set( vMax.x / vRadius.x, vMin.y / vRadius.y, vMin.z / vRadius.z ); // 1
vPolygon[ 2 ].Set( vMin.x / vRadius.x, vMax.y / vRadius.y, vMin.z / vRadius.z ); // 2
vPolygon[ 3 ].Set( vMax.x / vRadius.x, vMax.y / vRadius.y, vMin.z / vRadius.z ); // 3
// check left plane
if( KPCCP::triangle_collide_swept_unit_sphere( vPolygon[ 0 ], vPolygon[ 1 ], vPolygon[ 2 ], vBaseInESpace, vVelocityInESpace, vIntersection, fT ) && ( fNearestT > fT ) )
{
bFound = true;
fNearestT = fT;
vPickedPoint = vIntersection;
#ifdef _DEBUG
pCollidedPolygon[ 0 ] = vPolygon[ 0 ];
pCollidedPolygon[ 1 ] = vPolygon[ 1 ];
pCollidedPolygon[ 2 ] = vPolygon[ 2 ];
#endif
}
// check right plane
if( KPCCP::triangle_collide_swept_unit_sphere( vPolygon[ 1 ], vPolygon[ 3 ], vPolygon[ 2 ], vBaseInESpace, vVelocityInESpace, vIntersection, fT ) && ( fNearestT > fT ) )
{
bFound = true;
fNearestT = fT;
vPickedPoint = vIntersection;
#ifdef _DEBUG
pCollidedPolygon[ 0 ] = vPolygon[ 1 ];
pCollidedPolygon[ 1 ] = vPolygon[ 3 ];
pCollidedPolygon[ 2 ] = vPolygon[ 2 ];
#endif
}
}
return bFound;
}
// }