Files
2026-06-01 12:46:52 +02:00

583 lines
15 KiB
C++

#include "stdafx.h"
#include "SWaterViewPort.h"
#include "KPrimitive.h"
#include "KRenderDeviceDX.h"
#include <dump/XException.h>
#include <kfile/KFileManager.h>
namespace {
K3DTexture* CreateWaterBumpMap(K3DRenderDevice* dev, DWORD dwWidth, DWORD dwHeight)
{
if(dev == NULL) return NULL;
K3DTexture* psBumpMap;
// Create the bump map texture
if( FAILED( psBumpMap = dev->CreateTexture( dwWidth, dwHeight, K3DFMT_V8U8 ) ) )
return NULL;
// Lock the surface and write in some bumps for the waves
//D3DLOCKED_RECT d3dlr;
CHAR* pDst;
int nStride;
CHAR iDu, iDv;
psBumpMap->LockRect( NULL, (void **)&pDst, nStride );
if(!pDst)
{
// assert(0 && "psBumpMap->LockRect( NULL, (void **)&pDst, nStride );");
return NULL;
}
//pDst = (CHAR*)d3dlr.pBits;
for( DWORD y=0; y<dwHeight; y++ )
{
CHAR* pPixel = pDst;
for( DWORD x=0; x<dwWidth; x++ )
{
FLOAT fx = x/(FLOAT)dwWidth + 5.f;
FLOAT fy = y/(FLOAT)dwHeight + 5.f;
FLOAT r = sqrtf( fx*fx + fy*fy );
iDu = (CHAR)( 32 * cosf( 900.0f * r ) * expf( -r * 5.0f ) );
iDu += (CHAR)( 16 * cosf( 450.0f * ( fx + fy ) ) );
iDu += (CHAR)( 8 * cosf( 420.0f * ( fx * 0.85f - fy ) ) );
iDv = (CHAR)( 32 * sinf( 900.0f * r ) * expf( -r * 5.0f ) );
iDv += (CHAR)( 16 * sinf( 450.0f * ( fx + fy ) ) );
iDv += (CHAR)( 8 * sinf( 420.0f * ( fx * 0.85f - fy ) ) );
*pPixel++ = iDu;
*pPixel++ = iDv;
}
pDst += nStride;//d3dlr.Pitch;
}
psBumpMap->Unlock();
return psBumpMap;
}
K3DTexture* CreateBumpMap(K3DRenderDevice* dev, const char* src, int width, int height)
{
if(dev == NULL) return NULL;
if(src == NULL) return NULL;
LPDIRECT3DTEXTURE9 psBumpSrc = NULL;
HRESULT res;
D3DXIMAGE_INFO infoImg;
int strlength = (int)strlen(src);
res = D3DXGetImageInfoFromFile( src, &infoImg );
res = D3DXCreateTextureFromFileEx( ((K3DRenderDeviceDX*)dev)->GetD3DDevice(),
src, infoImg.Width, infoImg.Height,
0, 0, D3DFMT_UNKNOWN, D3DPOOL_SYSTEMMEM, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, &psBumpSrc );
if( !psBumpSrc ) return NULL;
K3DTexture* psBumpDst;
int texWidth = infoImg.Width;
int texHeight = infoImg.Height;
// Create the bumpmap's surface and texture objects
// 2010.06.03 - prodongi
if( !( psBumpDst = dev->CreateTexture( texWidth, texHeight, K3DFMT_V8U8 )))
//if( FAILED( psBumpDst = dev->CreateTexture( texWidth, texHeight, K3DFMT_V8U8 ) ) )
{
return NULL;
}
// Fill the bits of the new texture surface with bits from
// a private format.
D3DLOCKED_RECT dxrc;
BYTE* pSrcTopRow;
int dwSrcPitch;
res = psBumpSrc->LockRect( 0, &dxrc, NULL, D3DLOCK_READONLY );
if(res != D3D_OK)
{
//assert(res == D3D_OK && "res = psBumpSrc->LockRect( 0, &dxrc, NULL, D3DLOCK_READONLY );");
return NULL;
}
pSrcTopRow = (BYTE *)dxrc.pBits;
dwSrcPitch = dxrc.Pitch;
BYTE* pSrcCurRow = pSrcTopRow;
BYTE* pSrcBotRow = pSrcTopRow + (dwSrcPitch * (texHeight - 1) );
BYTE* pDstTopRow;
int dwDstPitch;
psBumpDst->LockRect( NULL, (void **)&pDstTopRow, dwDstPitch );
if(!pDstTopRow)
{
//assert(pDstTopRow && "psBumpDst->LockRect( NULL, (void **)&pDstTopRow, dwDstPitch );");
return NULL;
}
BYTE* pDstCurRow = pDstTopRow;
BYTE* pDstBotRow = pDstTopRow + (dwDstPitch * (texHeight - 1) );
for( int y=0; y<texHeight; y++ )
{
BYTE* pSrcB0; // addr of current pixel
BYTE* pSrcB1; // addr of pixel below current pixel, wrapping to top if necessary
BYTE* pSrcB2; // addr of pixel above current pixel, wrapping to bottom if necessary
BYTE* pDstT; // addr of dest pixel;
pSrcB0 = pSrcCurRow;
if( y == texHeight - 1)
pSrcB1 = pSrcTopRow;
else
pSrcB1 = pSrcCurRow + dwSrcPitch;
if( y == 0 )
pSrcB2 = pSrcBotRow;
else
pSrcB2 = pSrcCurRow - dwSrcPitch;
pDstT = pDstCurRow;
for( int x=0; x<texWidth; x++ )
{
LONG v00; // Current pixel
LONG v01; // Pixel to the right of current pixel, wrapping to left edge if necessary
LONG vM1; // Pixel to the left of current pixel, wrapping to right edge if necessary
LONG v10; // Pixel one line below.
LONG v1M; // Pixel one line above.
v00 = *(pSrcB0+0);
if( x == texWidth - 1 )
v01 = *(pSrcCurRow);
else
v01 = *(pSrcB0+4);
if( x == 0 )
vM1 = *(pSrcCurRow + (4 * (texWidth - 1)));
else
vM1 = *(pSrcB0-4);
v10 = *(pSrcB1+0);
v1M = *(pSrcB2+0);
LONG iDu = (vM1-v01); // The delta-u bump value
LONG iDv = (v1M-v10); // The delta-v bump value
// The luminance bump value (land masses are less shiny)
WORD uL = ( v00>1 ) ? 63 : 127;
*pDstT++ = (BYTE)iDu;
*pDstT++ = (BYTE)iDv;
// Move one pixel to the right (src is 32-bpp)
pSrcB0+=4;
pSrcB1+=4;
pSrcB2+=4;
}
// Move to the next line
pSrcCurRow += dwSrcPitch;
pDstCurRow += dwDstPitch;
}
psBumpDst->Unlock();
psBumpSrc->UnlockRect(0);
psBumpSrc->Release();
return psBumpDst;
}
};
SWaterViewPort::SWaterViewPort( bool bClearColorBuffer, bool bClearDepthBuffer)
: SViewPort( VIEWPORT_WATER, bClearColorBuffer, bClearDepthBuffer )
{
ClearRegisteredList();
int n = 0xffffffff;
m_nRenderFlag.CopyFrom( &n );
#ifndef NDEBUG
m_bDebugMode = false;
#endif
m_nWaterQuality = 3;
//m_pGameViewport = NULL;
m_fHQWaterHeight = 0.f;
}
SWaterViewPort::~SWaterViewPort()
{
}
void SWaterViewPort::SetWaterQuality(int nQuality)
{
if(m_spWaterBumpTexture && m_spWaterReflectionTexture && m_nWaterQuality == nQuality) return;
if(nQuality < 0 || nQuality > 3) return;
std::string src = KFileManager::Instance().CreateTemporaryFileFromResource( "waterbump.bmp" );
switch(nQuality)
{
case 3:
m_spWaterBumpTexture = CreateBumpMap(m_dev, src.c_str(), 512, 512);
if(m_spWaterBumpTexture) break;
else nQuality = 2;
case 2:
m_spWaterBumpTexture = CreateBumpMap(m_dev, src.c_str(), 256, 256);
if(m_spWaterBumpTexture) break;
else nQuality = 1;
case 1:
m_spWaterBumpTexture = CreateBumpMap(m_dev, src.c_str(), 128, 128);
if(m_spWaterBumpTexture) break;
else nQuality = 0;
}
switch(nQuality)
{
case 3:
//m_spWaterReflectionTexture = m_dev->CreateRenderTarget( 512, 512, 1, K3DFMT_X1R5G5B5, K3DRenderTarget::DEPTH_ENABLE );
//if(m_spWaterReflectionTexture == NULL)
// m_spWaterReflectionTexture = m_dev->CreateRenderTarget(512, 512, 1, K3DFMT_R5G6B5, K3DRenderTarget::DEPTH_ENABLE );
m_spWaterReflectionTexture = m_dev->CreateRenderTarget( 512, 512, 1, K3DFMT_X8R8G8B8, K3DRenderTarget::DEPTH_ENABLE );
if(m_spWaterReflectionTexture == NULL)
m_spWaterReflectionTexture = m_dev->CreateRenderTarget(512, 512, 1, K3DFMT_A8R8G8B8, K3DRenderTarget::DEPTH_ENABLE );
if(m_spWaterReflectionTexture) break;
else nQuality = 2;
case 2:
m_spWaterReflectionTexture = m_dev->CreateRenderTarget( 256, 256, 1, K3DFMT_X1R5G5B5, K3DRenderTarget::DEPTH_ENABLE );
if(m_spWaterReflectionTexture == NULL)
m_spWaterReflectionTexture = m_dev->CreateRenderTarget(256, 256, 1, K3DFMT_R5G6B5, K3DRenderTarget::DEPTH_ENABLE );
if(m_spWaterReflectionTexture) break;
else nQuality = 1;
case 1:
m_spWaterReflectionTexture = m_dev->CreateRenderTarget( 128, 128, 1, K3DFMT_X1R5G5B5, K3DRenderTarget::DEPTH_ENABLE );
if(m_spWaterReflectionTexture == NULL)
m_spWaterReflectionTexture = m_dev->CreateRenderTarget(128, 128, 1, K3DFMT_R5G6B5, K3DRenderTarget::DEPTH_ENABLE );
if(m_spWaterReflectionTexture) break;
else nQuality = 0;
}
if(nQuality != 0)
{
assert(m_spWaterReflectionTexture != NULL && "Water Reflection Texture 생성실패");
assert(m_spWaterBumpTexture != NULL && "Water Bump Texture 생성실패");
}
m_nWaterQuality = nQuality;
}
void SWaterViewPort::Initilaize( K3DRenderDevice *dev, const KViewportStruct &viewarea, float nearClip, float farClip )
{
SViewPort::Initilaize( dev, viewarea, nearClip, farClip );
m_fVertexAspectForWater = dev->GetScreenVertexAspect();
SetWaterQuality(m_nWaterQuality);
}
void SWaterViewPort::SetCamera( const K3DCamera *cam )
{
/*// Reset camera & it's matrix
m_vCamPos = GetCameraPos();
m_vTarPos = GetCameraTargetPos();
float val = (m_fHQWaterHeight - m_vCamPos.z)/(m_vTarPos.z - m_vCamPos.z);
m_vTarPos = val*m_vTarPos + (1 - val)*m_vCamPos;
m_vCamPos.z -= (m_vCamPos.z - m_fHQWaterHeight)*2;
//SetSceneState(m_fFieldofView, m_fScrWidth/m_fScrHeight, m_fDepthNear, m_fDepthFar, true, false, D3DXVECTOR3(0, 0, -1));
K3DMatrixPerspectiveFovLH( &m_matProjection,
m_pViewCamera->GetFOV(),
GetVertexAspect(),
GetNearClip(),
GetFarClip() );
K3DMatrixLookAtLH(&m_matView, &m_vCamPos, &m_vTarPos, &(-m_pViewCamera->GetUpVector()));*/
// 반사에 맞게 변형
K3DCamera t_cam = *cam;
K3DVector campos = cam->GetCamPos();
K3DVector tarpos = cam->GetTargetPos();
K3DVector upvector = cam->GetUpVector();
float val = (m_fHQWaterHeight - campos.z)/(tarpos.z - campos.z);
tarpos = val*tarpos + (1 - val)*campos;
campos.z -= (campos.z - m_fHQWaterHeight)*2;
//t_cam.SetCoordinateToLeftHand();
t_cam.SetCamPos(campos.x, campos.y, campos.z);
t_cam.SetTargetPos(tarpos.x, tarpos.y, tarpos.z);
t_cam.SetUpVector(-upvector.x, -upvector.y, -upvector.z);
SViewPort::SetCamera(&t_cam);
//SViewPort::SetCamera(cam);
}
void SWaterViewPort::ClearRegisteredList()
{
SViewPort::ClearRegisteredList();
}
void SWaterViewPort::Register( K3DPrimitive *pr, DWORD flag )
{
if( m_bUseViewPort == false ) return;
// flag 참조하여 필요없는 것은 패스 시킨다.
SViewPort::Register(pr, flag);
}
void SWaterViewPort::Render( bool bClearRegister /*= true*/, bool bSetRenderTarget /*= true*/ )
{
START_RENDER_VIEWPORT("Water Viweport");
m_bLocalCoord = false;
if( m_bUseViewPort == false ) return;
if(m_nWaterQuality < 1) return;
KViewportStruct backview = m_viewport;
//뷰포트 설정
m_viewport.X = 0;
m_viewport.Y = 0;
m_viewport.Width = m_spWaterReflectionTexture->GetWidth() -1;
m_viewport.Height = m_spWaterReflectionTexture->GetHeight()-1;
m_viewport.MinZ = 0;
m_viewport.MaxZ = 1;
// Render Target 변경
m_dev->SetRenderTarget(m_spWaterReflectionTexture);
/*{
// Reset camera & it's matrix
m_vCamPos = GetCameraPos();
m_vTarPos = GetCameraTargetPos();
float val = (m_fHQWaterHeight - m_vCamPos.z)/(m_vTarPos.z - m_vCamPos.z);
m_vTarPos = val*m_vTarPos + (1 - val)*m_vCamPos;
m_vCamPos.z -= (m_vCamPos.z - m_fHQWaterHeight)*2;
//SetSceneState(m_fFieldofView, m_fScrWidth/m_fScrHeight, m_fDepthNear, m_fDepthFar, true, false, D3DXVECTOR3(0, 0, -1));
K3DMatrixPerspectiveFovRH( &m_matProjection,
m_ViewCamera.GetFOV(),
GetVertexAspect(),
GetNearClip(),
GetFarClip() );
K3DMatrixLookAtRH(&m_matView, &m_vCamPos, &m_vTarPos, &(-m_ViewCamera.GetUpVector()));
}*/
{
static float s_fWaterHeightOffset = 0.0f;
K3DMatrix mattemp = m_matView*m_matProjection;
K3DVector a(m_vCamPos.x, m_vCamPos.y, m_fHQWaterHeight - s_fWaterHeightOffset), b(m_vCamPos.x+1000, m_vCamPos.y+1000, m_fHQWaterHeight - s_fWaterHeightOffset),
c(m_vCamPos.x, m_vCamPos.y+1000, m_fHQWaterHeight - s_fWaterHeightOffset);
K3DVectorTransform(a, a, mattemp);
K3DVectorTransform(b, b, mattemp);
K3DVectorTransform(c, c, mattemp);
K3DPlane clip_plane;
K3DPlaneFromPoints( clip_plane, a, c, b );
if(clip_plane.d > 0)
K3DPlaneFromPoints( clip_plane, a, b, c );
m_dev->SetClipPlane(0, clip_plane);
m_dev->SetClipPlaneMode(K3DRenderDevice::CPM_USER1);
}
m_dev->SetCullMode(K3DRenderDevice::KCM_CCW);
//TODO : 물 높이의 하늘 색과 같은 칼라 구하기 추가 해야 함.
SetFillColor(
KColor( (unsigned char)(m_SkyColorEnd.r*255.f),
(unsigned char)(m_SkyColorEnd.g*255.f),
(unsigned char)(m_SkyColorEnd.b*255.f),
(unsigned char)(1.0f) // 255가 아닐까? ;;
)
// KColor(215,222,255,255)
);
BeginRender();
//float fOldClipOffsetRatio = GetClipOffsetRatio();
static float s_fClipOffsetRatio = -0.2f;
SetClipOffsetRatio( s_fClipOffsetRatio );
float fOldMipBias = m_dev->GetMipBias();
m_dev->SetMipBias( fOldMipBias + ( fOldMipBias + 1.0f ) * 0.5f );
// fog off
// m_dev->SetFogMode( K3DRenderDevice::FOGM_NONE, 0, 0, 0 );
m_dev->SetCullMode( K3DRenderDevice::KCM_CCW );
RenderSky();
m_dev->SetCullMode( K3DRenderDevice::KCM_NONE );
RenderCloud();
if ( m_fogMode != K3DRenderDevice::FOGM_NONE )
{
m_dev->SetFogMode( m_fogMode, m_fogColor, m_fogFactor1, m_fogFactor2, m_fogFactor3, m_fogFactor4 );
}
m_dev->SetCullMode( K3DRenderDevice::KCM_CCW );
{
RenderTerrain( true );
}
{
//float scale = 1/SShadowViewPort::SHADOW_RATIO;
//m_dev->SetVertexShaderConstant(CONSTANT_TERRAIN1STTEXTURESCALE, &scale, 1);
//m_dev->SetVertexShaderConstant(CONSTANT_TERRAIN2NDTEXTURESCALE, &scale, 1);
//m_dev->SetVertexShaderConstant(CONSTANT_TERRAIN3THTEXTURESCALE, &scale, 1);
//m_dev->SetVertexShaderConstant(CONSTANT_TERRAIN4THTEXTURESCALE, &scale, 1);
//float center[4] = { +GetCameraTargetPos().x-SHADOW_RATIO/2, +GetCameraTargetPos().y-SHADOW_RATIO/2, GetCameraTargetPos().z, 0 };
//m_dev->SetVertexShaderConstant(CONSTANT_TERRAINTEXTURECENTER, center, 4);
}
//RenderTerrainShadow();
m_dev->SetRenderState( K3DRenderDevice::RS_DEFAULT );
/*RenderBuilding(NULL, NULL);
RenderAlphaBuilding(NULL, NULL);
*/
m_dev->SetDepthBufferWriteEnable( true );
m_dev->SetDepthBufferCompareMode( K3DRenderDevice::DCM_LESSEQUAL );
m_dev->SetCullMode(K3DRenderDevice::KCM_CW);
{
RenderBranch();
m_dev->SetCullMode(K3DRenderDevice::KCM_NONE);
RenderFrond();
RenderLeaf();
RenderTreeBillboard();
}
{
//RenderPathEffect();
RenderQuadPrimitive();
RenderLinePrimitive();
RenderPolyLinePrimitive();
m_dev->SetVertexShaderDefault();
m_dev->SetCullMode( K3DRenderDevice::KCM_CCW );
m_dev->SetDepthBufferWriteEnable( true );
m_dev->SetDepthBufferCompareMode( K3DRenderDevice::DCM_LESSEQUAL );
/*RenderProp(NULL, NULL);
RenderAlphaProp(NULL, NULL);
RenderPrNoLightList();
*/
if ( m_fogMode != K3DRenderDevice::FOGM_NONE )
{
m_dev->SetFogMode( m_fogMode, m_fogColor, m_fogFactor1, m_fogFactor2, m_fogFactor3, m_fogFactor4 );
}
/*RenderPrVSList();
RenderPrVSListSpecularList();
RenderPrList();
RenderPrListSpecularList();
*/
RenderPrList(m_prMesh, NULL, NULL);
// fog off
m_dev->SetFogMode( K3DRenderDevice::FOGM_NONE, 0, 0, 0, 0, 0 );
/*RenderPrNoFogList();
if ( m_fogMode != K3DRenderDevice::FOGM_NONE )
{
m_dev->SetFogMode( m_fogMode, m_fogColor, m_fogFactor1, m_fogFactor2, m_fogFactor3, m_fogFactor4 );
}
/*RenderPrVSAlphaList();
RenderPrAlphaList();
RenderPrVSAlphaSpecularList();
*/
RenderPrAlphaList(m_prTransMesh, NULL, NULL);
m_dev->SetFogMode( K3DRenderDevice::FOGM_NONE, m_fogColor, m_fogFactor1, m_fogFactor2, m_fogFactor3, m_fogFactor4 );
m_dev->SetCullMode(K3DRenderDevice::KCM_NONE);
RenderBliiboardList();
m_dev->SetCullMode(K3DRenderDevice::KCM_CCW);
/*RenderPrNoFogAlphaList();
RenderAdditiveBuilding(NULL, NULL);
RenderAdditiveProp(NULL, NULL);
*/
}
//버그땜시 잠시제거
{
RenderAdditiveBliiboard();
}
{
RenderSpeedGrass();
}
//if( NULL != m_pChildViewportObj )
// m_pChildViewportObj->Render( bClearRegister );
m_dev->SetCullMode(K3DRenderDevice::KCM_CCW);
// Render Target 복구
m_dev->SetRenderTarget(NULL);
m_dev->SetClipPlaneMode(0);
m_viewport = backview;
m_dev->SetViewport( m_viewport );
//D3DXSaveTextureToFile("c:\\water_reflection.bmp", D3DXIFF_BMP, ((K3DRenderTargetDX*)m_spWaterReflectionTexture)->GetD3DTexture(), NULL);
if( 0 != HIBYTE(GetAsyncKeyState(VK_RSHIFT)) )
{
_oprint( "ViewPort Water - DP Count : %d\n", ((K3DRenderDeviceDX*)m_dev)->GetDPCount() );
}
EndRender(bClearRegister);
m_dev->SetMipBias( fOldMipBias );
//SetClipOffsetRatio( fOldClipOffsetRatio );
}