333 lines
9.6 KiB
C++
333 lines
9.6 KiB
C++
#include "StdAfx.h"
|
||
#include "EtInstancingMng.h"
|
||
#include "EtOptionController.h"
|
||
#include "EtMRTMng.h"
|
||
|
||
#ifdef _DEBUG
|
||
#define new new(_NORMAL_BLOCK,__FILE__,__LINE__)
|
||
#endif
|
||
|
||
#define MAX_INSTANCING_COUNT 1024
|
||
|
||
bool NormalRenderInstancingSort( SRenderStackElement *Element1, SRenderStackElement *Element2 )
|
||
{
|
||
if( Element1->renderPriority != Element2->renderPriority )
|
||
{
|
||
if( Element1->renderPriority < Element2->renderPriority )
|
||
return true;
|
||
else
|
||
return false;
|
||
}
|
||
#ifdef PRE_FIX_MATERIAL_DUMP
|
||
else if( Element1->hMaterial && Element2->hMaterial && Element1->hMaterial != Element2->hMaterial )
|
||
#else
|
||
else if( Element1->hMaterial != Element2->hMaterial )
|
||
#endif
|
||
{
|
||
int nRef1, nRef2;
|
||
|
||
nRef1 = Element1->hMaterial->GetRefCount();
|
||
nRef2 = Element2->hMaterial->GetRefCount();
|
||
if( nRef1 > nRef2 )
|
||
{
|
||
return true;
|
||
}
|
||
else if (nRef1 < nRef2 )
|
||
{
|
||
return false;
|
||
}
|
||
else
|
||
{
|
||
return Element1->hMaterial.GetIndex() > Element2->hMaterial.GetIndex();
|
||
}
|
||
}
|
||
else if( Element1->nTechniqueIndex != Element2->nTechniqueIndex )
|
||
{
|
||
if( Element1->nTechniqueIndex < Element2->nTechniqueIndex )
|
||
{
|
||
return true;
|
||
}
|
||
else
|
||
{
|
||
return false;
|
||
}
|
||
}
|
||
else if( Element1->pRenderSubMesh != Element2->pRenderSubMesh )
|
||
{
|
||
if( Element1->pRenderSubMesh < Element2->pRenderSubMesh )
|
||
{
|
||
return true;
|
||
}
|
||
else
|
||
{
|
||
return false;
|
||
}
|
||
}
|
||
else if( Element1->fDirLightAttenuation != Element2->fDirLightAttenuation )
|
||
{
|
||
if( Element1->fDirLightAttenuation < Element2->fDirLightAttenuation )
|
||
{
|
||
return true;
|
||
}
|
||
else
|
||
{
|
||
return false;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if( Element1->fDist < Element2->fDist )
|
||
{
|
||
return true;
|
||
}
|
||
else
|
||
{
|
||
return false;
|
||
}
|
||
}
|
||
}
|
||
|
||
CEtInstancingMng::CEtInstancingMng()
|
||
{
|
||
m_bInit = false;
|
||
m_bEnable = false;
|
||
m_pWorldViewMatVB = NULL;
|
||
memset(m_nVertexDecl, 0, sizeof(m_nVertexDecl));
|
||
}
|
||
|
||
CEtInstancingMng::~CEtInstancingMng()
|
||
{
|
||
SAFE_RELEASE( m_pWorldViewMatVB );
|
||
SAFE_RELEASE_SPTR( m_hMaterial );
|
||
SAFE_RELEASE_SPTR( m_hSourceMaterial );
|
||
}
|
||
|
||
void CEtInstancingMng::Enable( bool bEnable )
|
||
{
|
||
if( bEnable ) {
|
||
int nVSVersion = ( GetEtDevice()->GetVSVersion() & 0xffff ) >> 8;
|
||
int nPSVersion = ( GetEtDevice()->GetPSVersion() & 0xffff ) >> 8;
|
||
|
||
if( ( nVSVersion < 3 ) || ( nPSVersion < 3 ) ) { // <20><><EFBFBD>̴<EFBFBD> 3.0 <20>̻<CCBB><F3BFA1BC><EFBFBD> <20>ν<EFBFBD><CEBD>Ͻ<EFBFBD><CFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>ȴ<EFBFBD>..
|
||
m_bEnable = false;
|
||
OutputDebug("Gpu does not support instancing.\n");
|
||
}
|
||
else {
|
||
m_bEnable = true;
|
||
/*OutputDebug("Instancing Enable\n");*/
|
||
}
|
||
}
|
||
else {
|
||
m_bEnable = false;
|
||
/*OutputDebug("Instancing Disable\n");*/
|
||
}
|
||
}
|
||
|
||
void CEtInstancingMng::Initialize()
|
||
{
|
||
if( m_bInit ) {
|
||
return;
|
||
}
|
||
m_pWorldViewMatVB = GetEtDevice()->CreateVertexBuffer( sizeof(EtMatrix) * MAX_INSTANCING_COUNT, 0 );
|
||
|
||
D3DVERTEXELEMENT9 VertexElement0[] = { {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
|
||
{1, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0 },
|
||
{2, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },
|
||
{3, 0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1 },
|
||
{3, 16, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 2 },
|
||
{3, 32, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 3 },
|
||
{3, 48, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 4 },
|
||
D3DDECL_END() };
|
||
|
||
D3DVERTEXELEMENT9 VertexElement1[] = { {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
|
||
{1, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },
|
||
{2, 0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1 },
|
||
{2, 16, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 2 },
|
||
{2, 32, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 3 },
|
||
{2, 48, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 4 },
|
||
D3DDECL_END() };
|
||
|
||
D3DVERTEXELEMENT9 VertexElement2[] = { {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
|
||
{1, 0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1 },
|
||
{1, 16, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 2 },
|
||
{1, 32, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 3 },
|
||
{1, 48, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 4 },
|
||
D3DDECL_END() };
|
||
|
||
m_nVertexDecl[ 0 ] = GetEtDevice()->CreateVertexDeclaration( VertexElement0 );
|
||
m_nVertexDecl[ 1 ] = GetEtDevice()->CreateVertexDeclaration( VertexElement1 );
|
||
m_nVertexDecl[ 2 ] = GetEtDevice()->CreateVertexDeclaration( VertexElement2 );
|
||
|
||
m_hMaterial = LoadResource( "DiffuseInstancing.fx", RT_SHADER );
|
||
m_hSourceMaterial = LoadResource( "Diffuse.fx", RT_SHADER);
|
||
m_bInit = true;
|
||
}
|
||
|
||
void CEtInstancingMng::ClassifyBlock( std::vector< SRenderStackElement* > &vecBlock, std::vector< SRenderStackElement* > &vecInstancingBlock )
|
||
{
|
||
if( !m_bEnable || vecBlock.empty() || !CEtCamera::GetActiveCamera() ) {
|
||
return;
|
||
}
|
||
|
||
Initialize();
|
||
|
||
std::sort( vecBlock.begin(), vecBlock.end(), NormalRenderInstancingSort );
|
||
|
||
int i ;
|
||
ASSERT( vecInstancingBlock.empty() );
|
||
int nDup = 0;
|
||
for( i = 0; i< ( int )vecBlock.size()-1; i++)
|
||
{
|
||
SRenderStackElement *pBlock = vecBlock[ i ];
|
||
SRenderStackElement *pNextBlock = vecBlock[ i + 1 ];
|
||
int nLight = 0;
|
||
for( nLight = 0; nLight < MAX_POINT_LIGHT_COUNT + MAX_SPOT_LIGHT_COUNT; nLight++) {
|
||
if( pBlock->pInfluenceLight[ nLight ] == NULL && pNextBlock->pInfluenceLight[ nLight ] == NULL ) {
|
||
nLight = MAX_POINT_LIGHT_COUNT + MAX_SPOT_LIGHT_COUNT;
|
||
break;
|
||
}
|
||
if( pBlock->pInfluenceLight[ nLight ] != pNextBlock->pInfluenceLight[ nLight ] ) {
|
||
break;
|
||
}
|
||
}
|
||
bool bSameLight = ( nLight == MAX_POINT_LIGHT_COUNT + MAX_SPOT_LIGHT_COUNT );
|
||
|
||
if( bSameLight &&
|
||
pBlock->hMaterial == m_hSourceMaterial &&
|
||
pBlock->nSaveMatIndex == -1 &&
|
||
pBlock->pRenderMeshStream == NULL &&
|
||
pBlock->pRenderSubMesh == pNextBlock->pRenderSubMesh &&
|
||
pBlock->fDirLightAttenuation == pNextBlock->fDirLightAttenuation &&
|
||
pBlock->nTechniqueIndex == pNextBlock->nTechniqueIndex ) {
|
||
nDup++;
|
||
vecInstancingBlock.push_back( pBlock );
|
||
|
||
bool bLastElement = (i == vecBlock.size() - 2);
|
||
if( bLastElement ) {
|
||
pNextBlock->bLastElement = true;
|
||
vecInstancingBlock.push_back( pNextBlock );
|
||
vecBlock.erase( vecBlock.begin() + i );
|
||
}
|
||
vecBlock.erase( vecBlock.begin() + i );
|
||
i--;
|
||
}
|
||
else {
|
||
if( nDup != 0 ) {
|
||
|
||
vecBlock[i]->bLastElement = true;
|
||
vecInstancingBlock.push_back( vecBlock[i] );
|
||
vecBlock.erase( vecBlock.begin() + i );
|
||
i--;
|
||
}
|
||
nDup = 0;
|
||
}
|
||
}
|
||
|
||
if( vecInstancingBlock.empty() ) {
|
||
return;
|
||
}
|
||
|
||
ASSERT( vecInstancingBlock.size() <= MAX_INSTANCING_COUNT );
|
||
|
||
EtMatrix *pLockedPtr = NULL;
|
||
m_pWorldViewMatVB->Lock( 0, sizeof(EtMatrix)*(int)vecInstancingBlock.size(), (void**)&pLockedPtr, 0);
|
||
int nSize = (int)vecInstancingBlock.size();
|
||
for( i = 0; i < nSize; i++) {
|
||
EtMatrixMultiply( &pLockedPtr[ i ], &vecInstancingBlock[ i ]->WorldMat, CEtCamera::GetActiveCamera()->GetViewMat() );
|
||
}
|
||
m_pWorldViewMatVB->Unlock();
|
||
}
|
||
|
||
void CEtInstancingMng::RenderDepth( std::vector< SRenderStackElement* > &vecBlock )
|
||
{
|
||
if( !m_bEnable || vecBlock.empty() ) {
|
||
return;
|
||
}
|
||
if( !CEtRenderStack::IsDepthRender() ) {
|
||
return;
|
||
}
|
||
|
||
Initialize();
|
||
|
||
int i, nPasses;
|
||
int nDup = 0;
|
||
int nStartIndex = 0;
|
||
|
||
EtMatrix IdentMat;
|
||
EtMatrixIdentity( &IdentMat );
|
||
|
||
CEtMRTMng::GetInstance().BeginDepthTarget();
|
||
for( i = 0; i < ( int )vecBlock.size(); i++ )
|
||
{
|
||
nDup++;
|
||
SRenderStackElement *pCurBlock = vecBlock[ i ];
|
||
if( !pCurBlock->bLastElement ) {
|
||
continue;
|
||
}
|
||
ASSERT( pCurBlock->nBakeDepthIndex == DT_NORMAL || pCurBlock->nBakeDepthIndex == DT_OPAQUE || pCurBlock->nBakeDepthIndex == DT_VOLUME );
|
||
int nTechnique = (pCurBlock->nBakeDepthIndex == DT_OPAQUE ) ? 2 : 1;
|
||
|
||
m_hMaterial->SetTechnique( nTechnique );
|
||
m_hMaterial->BeginEffect( nPasses );
|
||
m_hMaterial->BeginPass( 0 );
|
||
m_hMaterial->SetGlobalParams();
|
||
|
||
m_hMaterial->SetWorldMatParams( &IdentMat, &IdentMat );
|
||
if( pCurBlock->pvecCustomParam ) {
|
||
m_hMaterial->SetCustomParamList( *pCurBlock->pvecCustomParam );
|
||
}
|
||
m_hMaterial->CommitChanges();
|
||
|
||
pCurBlock->pRenderSubMesh->GetMeshStream()->DrawInstancing( m_nVertexDecl[ nTechnique ] , m_pWorldViewMatVB, nStartIndex, nDup );
|
||
nStartIndex += nDup;
|
||
nDup = 0;
|
||
|
||
m_hMaterial->EndPass();
|
||
m_hMaterial->EndEffect();
|
||
}
|
||
CEtMRTMng::GetInstance().EndDepthTarget();
|
||
}
|
||
|
||
void CEtInstancingMng::Render( std::vector< SRenderStackElement* > &vecBlock )
|
||
{
|
||
if( !m_bEnable || vecBlock.empty() ) {
|
||
return;
|
||
}
|
||
|
||
Initialize();
|
||
|
||
int i, nPasses;
|
||
|
||
EtMatrix IdentMat;
|
||
EtMatrixIdentity( &IdentMat );
|
||
|
||
m_hMaterial->SetTechnique( 0 );
|
||
m_hMaterial->BeginEffect( nPasses );
|
||
m_hMaterial->BeginPass( 0 );
|
||
m_hMaterial->SetGlobalParams();
|
||
|
||
int nDup = 0;
|
||
int nStartIndex = 0;
|
||
for( i = 0; i< ( int )vecBlock.size(); i++) {
|
||
nDup++;
|
||
SRenderStackElement *pCurBlock = vecBlock[ i ];
|
||
if( !pCurBlock->bLastElement ) {
|
||
continue;
|
||
}
|
||
CEtLight::SetInfluenceLight( pCurBlock->pInfluenceLight );
|
||
CEtLight::SetDirLightAttenuation( pCurBlock->fDirLightAttenuation );
|
||
|
||
m_hMaterial->SetWorldMatParams( &IdentMat, &IdentMat );
|
||
if( pCurBlock->pvecCustomParam ) {
|
||
m_hMaterial->SetCustomParamList( *pCurBlock->pvecCustomParam );
|
||
}
|
||
m_hMaterial->CommitChanges();
|
||
pCurBlock->pRenderSubMesh->GetMeshStream()->DrawInstancing( m_nVertexDecl[ 0 ], m_pWorldViewMatVB, nStartIndex, nDup );
|
||
nStartIndex += nDup;
|
||
nDup = 0;
|
||
}
|
||
m_hMaterial->EndPass();
|
||
m_hMaterial->EndEffect();
|
||
|
||
vecBlock.clear();
|
||
}
|