#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; } // }