DragonNest/Common/EternityEngine/EtDecal.cpp

566 lines
16 KiB
C++
Raw Normal View History

2024-12-19 09:48:26 +08:00
#include "StdAfx.h"
#include "EtDecal.h"
#include "EtConvexVolume.h"
#include "EtBackBufferMng.h"
#include "EtOptionController.h"
#ifdef _DEBUG
#define new new(_NORMAL_BLOCK,__FILE__,__LINE__)
#endif
DECL_SMART_PTR_STATIC( CEtDecal, 100 )
CEtDecal::CEtDecal(void)
{
m_nTechniqueIndex = 0;
m_nSrcBlend = 0;
m_nDestBlend = 0;
m_bInitialize = true;
m_bUseAddressUVWrap = false;
m_bUseFixedUV = false;
m_fAppearTime = 0.0f;
m_fLifeTime = 0.0f;
m_fProgressTime = 0.0f;
m_nFrustumMask = 0;
}
CEtDecal::~CEtDecal(void)
{
m_DecalStream.Clear();
SAFE_RELEASE_SPTR( m_hMaterial );
}
void CEtDecal::Initialize( EtTextureHandle hTexture, float fX, float fZ, float fRadius, float fLifeTime, float fAppearTime, float fRotate,
EtColor &DecalColor, int nSrcBlend, int nDestBlend, CalcHeightFn *pHeightFunc, float fYHint )
{
if( !m_hMaterial )
{
m_hMaterial = LoadResource( "Decal.fx", RT_SHADER );
}
#ifdef PRE_FIX_MATERIAL_DUMP
if( !m_hMaterial ) return;
#endif
m_nTechniqueIndex = 0;
m_fLifeTime = fLifeTime;
m_fAppearTime = fAppearTime;
m_fProgressTime = 0.f;
int nTexIndex;
nTexIndex = ( hTexture ) ? hTexture->GetMyIndex() : -1;
AddCustomParam( m_vecCustomParam, EPT_TEX, m_hMaterial, "g_DiffuseTex", &nTexIndex );
m_hDecalTexture = hTexture;
m_nSrcBlend = nSrcBlend;
m_nDestBlend = nDestBlend;
Update( fX, fZ, fRadius, fRotate, DecalColor, pHeightFunc, fYHint );
}
void CEtDecal::Update( float fX, float fZ, float fRadius, float fRotate, EtColor &DecalColor, CalcHeightFn *pHeightFunc, float fYHint , float fHintThreshold )
{
int nTileScale = 1;
SGraphicOption Option;
GetEtOptionController()->GetGraphicOption( Option );
if( !Option.bUseSplatting ) {
nTileScale = 2;
}
EtTerrainHandle hTerrainArea;
int nTileX, nTileZ, nSizeX, nSizeZ;
hTerrainArea = CEtTerrainArea::GetTerrainArea( fX, fZ );
float fTileSize = 50.f;
if( hTerrainArea )
{
fTileSize = hTerrainArea->GetTerrainInfo()->fTileSize;
}
m_DecalColor = DecalColor;
AddCustomParam( m_vecCustomParam, EPT_VECTOR_PTR, m_hMaterial, "g_DecalColor", &m_DecalColor );
float fTileX = ( fX - fRadius ) / fTileSize;
float fTileZ = ( fZ - fRadius ) / fTileSize;
if( fTileX < 0.0f ) fTileX -= 1.0f;
if( fTileZ < 0.0f ) fTileZ -= 1.0f;
nTileX = (int)fTileX;
nTileZ = (int)fTileZ;
nSizeX = (int)(fRadius * 2.0f / fTileSize + 1.0f);
nSizeZ = (int)(fRadius * 2.0f / fTileSize + 1.0f);
EtMatrix TransMat;
EtVector3 vTransU, vTransV;
EtMatrix FixedUVMat;
EtMatrixIdentity( &FixedUVMat );
EtMatrixIdentity( &TransMat );
TransMat._11 = 1.0f / ( fRadius * 2.0f );
TransMat._22 = TransMat._11;
TransMat._33 = 0.0f;
TransMat._41 = ( fRadius - fX ) / ( fRadius * 2.0f );
TransMat._42 = ( fRadius - fZ ) / ( fRadius * 2.0f );
TransMat._43 = 0.0f;
if( fRotate != 0.0f )
{
EtMatrix RotateMat, MoveMat;
EtMatrixTranslation( &MoveMat, -0.5f, -0.5f, 0.0f );
EtMatrixRotationZ( &RotateMat, EtToRadian( fRotate ) );
EtMatrixMultiply( &RotateMat, &MoveMat, &RotateMat );
EtMatrixTranslation( &MoveMat, 0.5f, 0.5f, 0.0f );
EtMatrixMultiply( &RotateMat, &RotateMat, &MoveMat );
EtMatrixMultiply( &TransMat, &TransMat, &RotateMat );
FixedUVMat = RotateMat;
}
vTransU.x = TransMat._11;
vTransU.y = TransMat._21;
vTransU.z = TransMat._41;
vTransV.x = TransMat._12;
vTransV.y = TransMat._22;
vTransV.z = TransMat._42;
int i, j;
int nVertexCount, nIndexCount;
EtVector3 *pVertex;
EtVector2 *pTexCoord;
float *pAlpha;
WORD *pIndexBuf;
CMemoryStream Stream;
nVertexCount = ( nSizeX + 1 ) * ( nSizeZ + 1 );
nIndexCount = nSizeX * nSizeZ * 6;
pVertex = new EtVector3[ nVertexCount ];
pTexCoord = new EtVector2[ nVertexCount ];
pAlpha = new float[ nVertexCount ];
pIndexBuf = ( WORD * )pVertex;
m_BoundingBox.Reset();
bool bFixedY = false;
float fFixedY = 0.f;
if( pHeightFunc ) {
float fMinY = FLT_MAX;
float fMaxY = -FLT_MAX;
for( i = 0; i <= nSizeZ; i++ ) {
for( j = 0; j <= nSizeX; j++ ) {
float fPointX, fPointZ;
fPointX = ( nTileX + j ) * fTileSize;
fPointZ = ( nTileZ + i ) * fTileSize;
float fY = pHeightFunc->GetHeight( fPointX, fYHint, fPointZ, nTileScale );
if( fY > fMaxY ) fMaxY = fY;
if( fY < fMinY ) fMinY = fY;
}
}
if( fMaxY-fMinY > fHintThreshold ) { // <20><><EFBFBD>̰<EFBFBD> <20>ʹ<EFBFBD> ũ<><C5A9> <20><>ƮY <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>Ѵ<EFBFBD>.
bFixedY = true;
if( fabsf( fMaxY - fYHint ) < fabsf( fMinY - fYHint ) ) {
fFixedY = fMaxY;
}
else {
fFixedY = fMinY;
}
}
}
for( i = 0; i <= nSizeZ; i++ )
{
for( j = 0; j <= nSizeX; j++ )
{
int nIndex;
float fPointX, fPointZ;
static float fBiasY = 1.0f;
nIndex = ( nSizeX + 1 ) * i + j;
fPointX = ( nTileX + j ) * fTileSize;
fPointZ = ( nTileZ + i ) * fTileSize;
if( hTerrainArea ) {
if( bFixedY ) {
pVertex[ nIndex ] = EtVector3( fPointX, fFixedY + fBiasY, fPointZ );
}
else if( pHeightFunc ) {
pVertex[ nIndex ] = EtVector3( fPointX, pHeightFunc->GetHeight( fPointX, fYHint, fPointZ, nTileScale ) + fBiasY, fPointZ );
}
else {
pVertex[ nIndex ] = EtVector3( fPointX, hTerrainArea->GetLandHeight( fPointX, fPointZ, NULL, nTileScale ) + fBiasY, fPointZ );
}
}
else {
pVertex[ nIndex ] = EtVector3( fPointX, fBiasY, fPointZ );
}
if( !m_bUseFixedUV ) {
pTexCoord[ nIndex ].x = pVertex[ nIndex ].x * vTransU.x + pVertex[ nIndex ].z * vTransU.y + vTransU.z;
pTexCoord[ nIndex ].y = 1.f - (pVertex[ nIndex ].x * vTransV.x + pVertex[ nIndex ].z * vTransV.y + vTransV.z);
}
else {
float fBaseU = (float)j / nSizeX;
float fBaseV = (float)i / nSizeZ;
pTexCoord[ nIndex ].x = fBaseU * FixedUVMat._11 + fBaseV * FixedUVMat._21 + FixedUVMat._41;
pTexCoord[ nIndex ].y = 1.0f - (fBaseU * FixedUVMat._12 + fBaseV * FixedUVMat._22 + FixedUVMat._42);
}
EtVec3Maximize( &m_BoundingBox.Max, &m_BoundingBox.Max, pVertex + nIndex );
EtVec3Minimize( &m_BoundingBox.Min, &m_BoundingBox.Min, pVertex + nIndex );
}
}
const float fDiffThreshold = 350.f;
for( i = 0; i <= nSizeZ; i++ )
{
for( j = 0; j <= nSizeX; j++ )
{
int nIndex;
nIndex = ( nSizeX + 1 ) * i + j;
pAlpha[ nIndex ] = 1.0f;
if( i == 0 || i == nSizeZ || j == 0 || j == nSizeX )
continue;
// <20><><EFBFBD><EFBFBD>, <20>¿<EFBFBD>, <20><EFBFBD><EBB0A2> <20><><EFBFBD><EFBFBD> üũ<C3BC>ؾ<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>˻<EFBFBD> <20><> <20>ϴ°Ŵ<C2B0>.
if( abs( pVertex[nIndex-nSizeX-1].y - pVertex[nIndex].y ) > fDiffThreshold ||
abs( pVertex[nIndex+nSizeX+1].y - pVertex[nIndex].y ) > fDiffThreshold ||
abs( pVertex[nIndex-1].y - pVertex[nIndex].y ) > fDiffThreshold ||
abs( pVertex[nIndex+1].y - pVertex[nIndex].y ) > fDiffThreshold ||
abs( pVertex[nIndex-nSizeX-1-1].y - pVertex[nIndex].y ) > fDiffThreshold ||
abs( pVertex[nIndex-nSizeX-1+1].y - pVertex[nIndex].y ) > fDiffThreshold ||
abs( pVertex[nIndex+nSizeX+1-1].y - pVertex[nIndex].y ) > fDiffThreshold ||
abs( pVertex[nIndex+nSizeX+1+1].y - pVertex[nIndex].y ) > fDiffThreshold )
pAlpha[ nIndex ] = 0.0f;
}
}
if( m_DecalStream.GetVertexCount() < nVertexCount ) {
m_DecalStream.Clear();
}
Stream.Initialize( pVertex, sizeof( EtVector3 ) * nVertexCount );
m_DecalStream.LoadVertexStream( &Stream, MST_POSITION, 0, nVertexCount );
Stream.Initialize( pTexCoord, sizeof( EtVector2 ) * nVertexCount );
m_DecalStream.LoadVertexStream( &Stream, MST_TEXCOORD, 0, nVertexCount );
Stream.Initialize( pAlpha, sizeof( float ) * nVertexCount );
m_DecalStream.LoadVertexStream( &Stream, MST_DEPTH, 0, nVertexCount );
for( i = 0; i < nSizeZ; i++ )
{
for( j = 0; j < nSizeX; j++ )
{
int nIndex, nBaseVertex;
nIndex = ( nSizeX * i + j ) * 6;
nBaseVertex = i * ( nSizeX + 1 ) + j;
pIndexBuf[ nIndex ] = nBaseVertex;
pIndexBuf[ nIndex + 1 ] = nBaseVertex + nSizeX + 1;
pIndexBuf[ nIndex + 2 ] = nBaseVertex + nSizeX + 2;
pIndexBuf[ nIndex + 3 ] = nBaseVertex;
pIndexBuf[ nIndex + 4 ] = nBaseVertex + nSizeX + 2;
pIndexBuf[ nIndex + 5 ] = nBaseVertex + 1;
}
}
Stream.Initialize( pIndexBuf, sizeof( WORD ) * nIndexCount );
m_DecalStream.LoadIndexStream( &Stream, false, nIndexCount );
delete [] pVertex;
delete [] pTexCoord;
delete [] pAlpha;
}
void CEtDecal::GetExtent( EtVector3 &Origin, EtVector3 &Extent )
{
Origin = ( m_BoundingBox.Max + m_BoundingBox.Min ) / 2;
Extent = ( m_BoundingBox.Max - m_BoundingBox.Min ) / 2;
}
bool CEtDecal::Process( float fElapsedTime )
{
if( !m_bInitialize ) {
m_fLifeTime -= fElapsedTime;
}
if( m_fProgressTime < m_fAppearTime ) {
float fAlpha = m_fProgressTime / m_fAppearTime;
m_DecalColor.a = fAlpha;
}
m_fProgressTime += fElapsedTime;
if( m_fLifeTime < 0.0f )
{
return true;
}
if( !m_bInitialize && m_fLifeTime <= 0.5f ) {
float fAlpha = (m_fLifeTime / 0.5f);
m_DecalColor.a = fAlpha;
}
m_bInitialize = false;
return false;
}
void CEtDecal::Render()
{
if( m_DecalStream.GetIndexCount() == 0 )
{
return;
}
SRenderStackElement RenderElement;
EtMatrix WorldMat;
EtMatrixIdentity( &WorldMat );
RenderElement.hMaterial = m_hMaterial;
RenderElement.nTechniqueIndex = m_nTechniqueIndex;
RenderElement.WorldMat = WorldMat;
RenderElement.nSaveMatIndex = -1;
RenderElement.pvecCustomParam = &m_vecCustomParam;
RenderElement.pRenderMeshStream = &m_DecalStream;
RenderElement.renderPriority = IsPointLight() ? RP_HIGH : RP_ABOVE_NORMAL;
RenderElement.nBakeDepthIndex = DT_NONE;
int nDiffuseSamplerIndex = 0;
int nParamIndex = m_hMaterial->GetParameterByName( "g_DiffuseTex" );
for( int i = 0; i < m_hMaterial->GetParameterCount(); ++i ) {
if( i == nParamIndex )
break;
if( m_hMaterial->GetParameterType( i ) == D3DXPT_TEXTURE2D ) {
++nDiffuseSamplerIndex;
}
}
SStateBlock RenderStateBlock;
RenderStateBlock.AddSamplerState( D3DSAMP_ADDRESSU, m_bUseAddressUVWrap ? TADDRESS_WRAP : TADDRESS_CLAMP, nDiffuseSamplerIndex );
RenderStateBlock.AddSamplerState( D3DSAMP_ADDRESSV, m_bUseAddressUVWrap ? TADDRESS_WRAP : TADDRESS_CLAMP, nDiffuseSamplerIndex );
RenderStateBlock.AddSamplerState( D3DSAMP_BORDERCOLOR, 0 );
if( m_nSrcBlend != 0 ) RenderStateBlock.AddRenderState( D3DRS_SRCBLEND, m_nSrcBlend);
if( m_nDestBlend != 0 ) RenderStateBlock.AddRenderState( D3DRS_DESTBLEND, m_nDestBlend);
RenderElement.nStateBlockIndex = CEtStateBlockManager::GetInstance().CreateStateBlock( &RenderStateBlock );
if( IsPointLight() ) {
GetCurRenderStack()->AddUseBackBufferRenderElement( RenderElement );
}
else {
GetCurRenderStack()->AddAlphaRenderElement( RenderElement );
}
}
void CEtDecal::RenderDecalList( int nMask, float fElapsedTime )
{
ScopeLock<CSyncLock> Lock( s_SmartPtrLock );
int i, nCount;
EtDecalHandle hHandle;
std::vector< EtDecalHandle > vecDeleteList;
nCount = GetItemCount();
for( i = 0; i < nCount; i++ )
{
hHandle = GetItem( i );
if( !hHandle )
{
continue;
}
if( hHandle->Process( fElapsedTime ) )
{
vecDeleteList.push_back( hHandle );
continue;
}
if( hHandle->GetFrustumMask() & nMask )
{
hHandle->Render();
}
}
nCount = ( int )vecDeleteList.size();
for( i = 0; i < nCount; i++ )
{
SAFE_RELEASE_SPTR( vecDeleteList[ i ] );
}
}
void CEtDecal::ProcessDeleteDecalList( float fElapsedTime )
{
ScopeLock<CSyncLock> Lock( s_SmartPtrLock );
int i, nCount;
EtDecalHandle hHandle;
std::vector< EtDecalHandle > vecDeleteList;
nCount = GetItemCount();
for( i = 0; i < nCount; i++ )
{
hHandle = GetItem( i );
if( !hHandle )
{
continue;
}
if( hHandle->Process( fElapsedTime ) )
{
vecDeleteList.push_back( hHandle );
continue;
}
}
nCount = ( int )vecDeleteList.size();
for( i = 0; i < nCount; i++ )
{
SAFE_RELEASE_SPTR( vecDeleteList[ i ] );
}
}
void CEtDecal::ClearFrustumMask()
{
ScopeLock<CSyncLock> Lock( s_SmartPtrLock );
int i, nCount;
nCount = GetItemCount();
for( i = 0; i < nCount; i++ )
{
GetItem( i )->SetFrustumMask( 0 );
}
}
void CEtDecal::MaskFrustumDecalList( CEtConvexVolume *pFrustum, int nFrustumMask )
{
ScopeLock<CSyncLock> Lock( s_SmartPtrLock );
int i, nCount;
nCount = GetItemCount();
for( i = 0; i < nCount; i++ )
{
EtVector3 Origin, Extent;
EtDecalHandle hHandle;
hHandle = GetItem( i );
hHandle->GetExtent( Origin, Extent );
if( pFrustum->TesToBox( Origin, Extent ) )
{
hHandle->AddFrustumMask( nFrustumMask );
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////////
// CEtPointLightDecal
///////////////////////////////////////////////////////////////////////////////////////////////
CEtPointLightDecal::CEtPointLightDecal(void)
{
}
CEtPointLightDecal::~CEtPointLightDecal(void)
{
}
void CEtPointLightDecal::Initialize( SLightInfo &LightInfo, float fRadius, float fLifeTime )
{
if( !m_hMaterial )
{
m_hMaterial = LoadResource( "Decal.fx", RT_SHADER );
}
#ifdef PRE_FIX_MATERIAL_DUMP
if( !m_hMaterial ) return;
#endif
m_fLifeTime = fLifeTime;
m_nTechniqueIndex = 1;
int nTexIndex;
nTexIndex = GetEtBackBufferMng()->GetBackBufferIndex();
AddCustomParam( m_vecCustomParam, EPT_TEX, m_hMaterial, "g_DiffuseTex", &nTexIndex );
EtMatrixIdentity(&m_MatBias);
m_MatBias._11 = 0.5f;
m_MatBias._22 = -0.5f;
m_MatBias._41 = 0.5f + 0.5f / GetEtDevice()->Width();
m_MatBias._42 = 0.5f + 0.5f / GetEtDevice()->Height();
AddCustomParam( m_vecCustomParam, EPT_MATRIX_PTR, m_hMaterial, "g_BiasMat", &m_MatBias );
Update( LightInfo, fRadius );
}
void CEtPointLightDecal::Update( SLightInfo &LightInfo, float fRadius )
{
EtTerrainHandle hTerrainArea;
STerrainInfo *pTerrainInfo;
int nTileX, nTileZ, nSizeX, nSizeZ;
float fX, fZ;
fX = LightInfo.Position.x;
fZ = LightInfo.Position.z;
hTerrainArea = CEtTerrainArea::GetTerrainArea( fX, fZ );
if( !hTerrainArea )
{
return;
}
pTerrainInfo = hTerrainArea->GetTerrainInfo();
nTileX = ( int )( ( fX - fRadius ) / pTerrainInfo->fTileSize ) - 1;
nTileZ = ( int )( ( fZ - fRadius ) / pTerrainInfo->fTileSize ) - 1;
nSizeX = ( int )( ( fX + fRadius) / pTerrainInfo->fTileSize ) - nTileX;
nSizeZ = ( int )( ( fZ + fRadius) / pTerrainInfo->fTileSize ) - nTileZ;
int i, j;
int nVertexCount, nIndexCount;
EtVector3 *pVertex;
EtColor *pColor;
WORD *pIndexBuf;
CMemoryStream Stream;
nVertexCount = ( nSizeX + 1 ) * ( nSizeZ + 1 );
nIndexCount = nSizeX * nSizeZ * 6;
pVertex = new EtVector3[ nVertexCount ];
pColor = new EtColor[ nVertexCount ];
pIndexBuf = ( WORD * )pVertex;
m_BoundingBox.Reset();
for( i = 0; i <= nSizeZ; i++ )
{
for( j = 0; j <= nSizeX; j++ )
{
int nIndex;
float fPointX, fPointZ;
EtVector3 vNormal;
nIndex = ( nSizeX + 1 ) * i + j;
fPointX = ( nTileX + j ) * pTerrainInfo->fTileSize;
fPointZ = ( nTileZ + i ) * pTerrainInfo->fTileSize;
pVertex[ nIndex ] = EtVector3( fPointX, hTerrainArea->GetLandHeight( fPointX, fPointZ, &vNormal ) + 1.0f, fPointZ );
CalcPointLight( pColor[ nIndex ], LightInfo, pVertex[ nIndex ], vNormal );
EtVec3Maximize( &m_BoundingBox.Max, &m_BoundingBox.Max, pVertex + nIndex );
EtVec3Minimize( &m_BoundingBox.Min, &m_BoundingBox.Min, pVertex + nIndex );
}
}
Stream.Initialize( pVertex, sizeof( EtVector3 ) * nVertexCount );
m_DecalStream.LoadVertexStream( &Stream, MST_POSITION, 0, nVertexCount );
Stream.Initialize( pColor, sizeof( EtColor ) * nVertexCount );
m_DecalStream.LoadVertexStream( &Stream, MST_BONEWEIGHT, 0, nVertexCount );
for( i = 0; i < nSizeZ; i++ )
{
for( j = 0; j < nSizeX; j++ )
{
int nIndex, nBaseVertex;
nIndex = ( nSizeX * i + j ) * 6;
nBaseVertex = i * ( nSizeX + 1 ) + j;
pIndexBuf[ nIndex ] = nBaseVertex;
pIndexBuf[ nIndex + 1 ] = nBaseVertex + nSizeX + 1;
pIndexBuf[ nIndex + 2 ] = nBaseVertex + nSizeX + 2;
pIndexBuf[ nIndex + 3 ] = nBaseVertex;
pIndexBuf[ nIndex + 4 ] = nBaseVertex + nSizeX + 2;
pIndexBuf[ nIndex + 5 ] = nBaseVertex + 1;
}
}
Stream.Initialize( pIndexBuf, sizeof( WORD ) * nIndexCount );
m_DecalStream.LoadIndexStream( &Stream, false, nIndexCount );
delete [] pVertex;
delete [] pColor;
}
void CEtPointLightDecal::CalcPointLight( EtColor &OutColor, SLightInfo &LightInfo, EtVector3 &vPosition, EtVector3 &vNormal )
{
float fLength, fAttenuation;
EtVector3 vLightDir;
vLightDir = LightInfo.Position - vPosition;
fLength = EtVec3Length( &vLightDir );
vLightDir /= fLength;
fAttenuation = max( 0.0f, 1.0f - ( fLength / LightInfo.fRange ) );
OutColor = LightInfo.Diffuse * max( 0.0f , EtVec3Dot( &vNormal, &vLightDir ) ) * fAttenuation;
OutColor.r += 1.0f;
OutColor.g += 1.0f;
OutColor.b += 1.0f;
}