DragonNest/Common/EternityEngine/EtDecal.cpp
Cussrro 47f7895977 Revert "修复编码问题"
This reverts commit 9e69c01767.
2024-12-21 10:04:04 +08:00

565 lines
16 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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