Files
FC1/RenderDll/XRenderD3D9/D3DHDRRender.cpp
romkazvo 34d6c5d489 123
2023-08-07 19:29:24 +08:00

2872 lines
91 KiB
C++

/*=============================================================================
D3DHDRRender.cpp : Direct3D specific high dynamic range post-processing
Copyright (c) 2001 Crytek Studios. All Rights Reserved.
Revision history:
* Created by Honitch Andrey
=============================================================================*/
#include "RenderPCH.h"
#include "DriverD3D9.h"
#include "D3DCGPShader.h"
#include "D3DCGVProgram.h"
//=============================================================================
//----------------------------------------------------------------------------------------
// Render Target Management functions
// Allocation order affects performance. These functions try to find an optimal allocation
// order for an arbitrary number of render targets.
//-----------------------------------------------------------------------------------------
static DWORD FormatSize( D3DFORMAT Format )
{
switch ( Format )
{
case D3DFMT_R16F:
return 2;
case D3DFMT_A8R8G8B8:
case D3DFMT_X8R8G8B8:
case D3DFMT_G16R16:
case D3DFMT_G16R16F:
case D3DFMT_R32F:
return 4;
case D3DFMT_A16B16G16R16:
case D3DFMT_A16B16G16R16F:
return 8;
default:
assert(0);
}
return 4;
}
// defer allocation of render targets until we have a list of all required targets...
// then, sort the list to make "optimal" use of GPU memory
struct DeferredRenderTarget
{
DWORD dwWidth;
DWORD dwHeight;
D3DFORMAT Format;
STexPic **lplpStorage;
char szName[64];
DWORD dwPitch;
float fPriority;
};
std::vector< DeferredRenderTarget* > g_vAllRenderTargets;
#define SORT_RENDERTARGETS TRUE
struct DescendingRenderTargetSort
{
bool operator()( DeferredRenderTarget* drtStart, DeferredRenderTarget *drtEnd ) { return (drtStart->dwPitch*drtStart->fPriority) > (drtEnd->dwPitch*drtEnd->fPriority); }
};
// This function just clears the vector
void StartRenderTargetList( )
{
std::vector< DeferredRenderTarget* >::iterator _it = g_vAllRenderTargets.begin();
while ( _it != g_vAllRenderTargets.end() )
{
DeferredRenderTarget *drt = (DeferredRenderTarget*)*_it++;
delete drt;
}
g_vAllRenderTargets.clear();
}
// Add a render target to the list
void AllocateDeferredRenderTarget( DWORD dwWidth, DWORD dwHeight, D3DFORMAT Format, float fPriority, const char *szName, STexPic **pStorage )
{
DeferredRenderTarget *drt = new DeferredRenderTarget;
drt->dwWidth = dwWidth;
drt->dwHeight = dwHeight;
drt->Format = Format;
drt->fPriority = fPriority;
drt->lplpStorage = pStorage;
strcpy(drt->szName, szName);
drt->dwPitch = dwWidth * FormatSize( Format );
g_vAllRenderTargets.push_back( drt );
}
// Now, sort and allocate all render targets
bool EndRenderTargetList( )
{
if ( SORT_RENDERTARGETS )
std::sort( g_vAllRenderTargets.begin(), g_vAllRenderTargets.end(), DescendingRenderTargetSort() );
std::vector< DeferredRenderTarget* >::iterator _it = g_vAllRenderTargets.begin();
bool bRes = true;
while ( _it != g_vAllRenderTargets.end() )
{
DeferredRenderTarget *drt = (DeferredRenderTarget*)*_it++;
CD3D9TexMan *tm = (CD3D9TexMan *)gcpRendD3D->m_TexMan;
STexPic *tp = tm->CreateTexture(drt->dwWidth, drt->dwHeight, drt->Format, D3DUSAGE_RENDERTARGET, false, drt->szName);
if (tp)
*drt->lplpStorage = tp;
else
bRes = false;
}
StartRenderTargetList( );
return S_OK;
}
STexPic *CD3D9TexMan::CreateTexture(int nWidth, int nHeight, D3DFORMAT d3dFMT, int d3dUsage, bool bMips, const char *szName)
{
LPDIRECT3DTEXTURE9 pTexture;
STexPic *tp;
if(FAILED(D3DXCreateTexture(gcpRendD3D->mfGetD3DDevice(), nWidth, nHeight, bMips ? D3DX_DEFAULT : 1, d3dUsage, d3dFMT, D3DPOOL_DEFAULT, &pTexture)))
return NULL;
int nFlags = FT_NOREMOVE | FT_NOSTREAM;
if (!bMips)
nFlags |= FT_NOMIPS;
tp = LoadTexture(szName, nFlags, FT2_NODXT | FT2_RENDERTARGET, eTT_Base, -1.0f, -1.0f);
STexPicD3D *ti = (STexPicD3D *)tp;
ti->m_RefTex.m_VidTex = (void *)pTexture;
ti->m_RefTex.m_MipFilter = bMips ? GetMipFilter() : D3DTEXF_NONE;
ti->m_RefTex.m_MinFilter = GetMinFilter();
ti->m_RefTex.m_MagFilter = GetMagFilter();
ti->m_RefTex.m_AnisLevel = 1;
ti->m_RefTex.m_Type = TEXTGT_2D;
ti->m_DstFormat = d3dFMT;
ti->m_Width = nWidth;
ti->m_Height = nHeight;
CD3D9TexMan::CalcMipsAndSize(ti);
AddToHash(ti->m_Bind, ti);
ti->Unlink();
ti->Link(&STexPic::m_Root);
gRenDev->m_TexMan->m_StatsCurTexMem += ti->m_Size;
HRESULT hr = S_OK;
PDIRECT3DSURFACE9 pSurface = NULL;
hr = pTexture->GetSurfaceLevel(0, &pSurface);
if (SUCCEEDED(hr))
gcpRendD3D->m_pd3dDevice->ColorFill(pSurface, NULL, D3DCOLOR_ARGB(0, 0, 0, 0));
SAFE_RELEASE( pSurface );
return ti;
}
void CD3D9TexMan::DestroyHDRMaps()
{
CD3D9Renderer *r = gcpRendD3D;
int i;
SAFE_RELEASE( m_HDR_RT_FSAA );
if (m_Text_HDRTarget)
m_Text_HDRTarget->Release(true);
m_Text_HDRTarget = NULL;
if (m_Text_HDRTarget_Temp)
m_Text_HDRTarget_Temp->Release(true);
m_Text_HDRTarget_Temp = NULL;
//if (m_Text_HDRTarget_K)
// m_Text_HDRTarget_K->Release(true);
//m_Text_HDRTarget_K = NULL;
if (m_Text_ScreenMap_HDR)
m_Text_ScreenMap_HDR->Release(true);
m_Text_ScreenMap_HDR = NULL;
if (r->m_TexMan->m_Text_HDRTargetScaled[0])
r->m_TexMan->m_Text_HDRTargetScaled[0]->Release(true);
r->m_TexMan->m_Text_HDRTargetScaled[0] = NULL;
if (r->m_TexMan->m_Text_HDRTargetScaled[1])
r->m_TexMan->m_Text_HDRTargetScaled[1]->Release(true);
r->m_TexMan->m_Text_HDRTargetScaled[1] = NULL;
if (r->m_TexMan->m_Text_HDRBrightPass)
r->m_TexMan->m_Text_HDRBrightPass->Release(true);
r->m_TexMan->m_Text_HDRBrightPass = NULL;
if (r->m_TexMan->m_Text_HDRStarSource)
r->m_TexMan->m_Text_HDRStarSource->Release(true);
r->m_TexMan->m_Text_HDRStarSource = NULL;
if (r->m_TexMan->m_Text_HDRBloomSource)
r->m_TexMan->m_Text_HDRBloomSource->Release(true);
r->m_TexMan->m_Text_HDRBloomSource = NULL;
if (r->m_TexMan->m_Text_HDRAdaptedLuminanceCur)
r->m_TexMan->m_Text_HDRAdaptedLuminanceCur->Release(true);
r->m_TexMan->m_Text_HDRAdaptedLuminanceCur = NULL;
if (r->m_TexMan->m_Text_HDRAdaptedLuminanceLast)
r->m_TexMan->m_Text_HDRAdaptedLuminanceLast->Release(true);
r->m_TexMan->m_Text_HDRAdaptedLuminanceLast = NULL;
for(i=0; i<NUM_HDR_TONEMAP_TEXTURES; i++)
{
if (m_Text_HDRToneMaps[i])
m_Text_HDRToneMaps[i]->Release(true);
m_Text_HDRToneMaps[i] = NULL;
}
for(i=0; i<NUM_HDR_BLOOM_TEXTURES; i++)
{
if (m_Text_HDRBloomMaps[i])
m_Text_HDRBloomMaps[i]->Release(true);
m_Text_HDRBloomMaps[i] = NULL;
}
for(i=0; i<NUM_HDR_STAR_TEXTURES; i++)
{
if (m_Text_HDRStarMaps[i][0])
m_Text_HDRStarMaps[i][0]->Release(true);
m_Text_HDRStarMaps[i][0] = NULL;
if (m_Text_HDRStarMaps[i][1])
m_Text_HDRStarMaps[i][1]->Release(true);
m_Text_HDRStarMaps[i][1] = NULL;
}
}
void CD3D9TexMan::GenerateHDRMaps()
{
int i;
char szName[256];
CD3D9Renderer *r = gcpRendD3D;
r->m_dwHDRCropWidth = r->m_width - r->m_width % 8;
r->m_dwHDRCropHeight = r->m_height - r->m_height % 8;
DestroyHDRMaps();
StartRenderTargetList();
if (r->m_nHDRType == 2)
{
AllocateDeferredRenderTarget(r->m_width, r->m_height, D3DFMT_A8R8G8B8, 1.0f, "$HDRTarget", &m_Text_HDRTarget);
//AllocateDeferredRenderTarget(r->m_width, r->m_height, D3DFMT_A8R8G8B8, 1.0f, "$HDRTarget_K", &m_Text_HDRTarget_K);
AllocateDeferredRenderTarget(r->m_width, r->m_height, D3DFMT_A16B16G16R16F, 1.0f, "$HDRTarget_Temp", &m_Text_HDRTarget_Temp);
AllocateDeferredRenderTarget(r->m_width, r->m_height, D3DFMT_A8R8G8B8, 0.8f, "$HDRScreenMap", &m_Text_ScreenMap_HDR);
}
else
{
if( r->CV_r_fsaa == 2 )
{
HRESULT hr = r->m_pd3dDevice->CreateRenderTarget( r->m_width, r->m_height, D3DFMT_A16B16G16R16F, ConvertFSAASamplesToType( r->m_FSAA_samples ), r->m_FSAA_quality, FALSE, &m_HDR_RT_FSAA, 0 );
//if( SUCCEEDED( hr ) )
// iLog->Log( "HDR-FSAA: Created multi-sampled HDR render target for current FSAA settings (samples = %d / quality = %d).", r->m_FSAA_samples, r->m_FSAA_quality );
//else
// iLog->Log( "HDR-FSAA: Multi-sampled HDR render target creation failed!" );
}
AllocateDeferredRenderTarget(r->m_width, r->m_height, D3DFMT_A16B16G16R16F, 1.0f, "$HDRTarget", &m_Text_HDRTarget);
AllocateDeferredRenderTarget(r->m_width, r->m_height, D3DFMT_A16B16G16R16F, 0.8f, "$HDRScreenMap", &m_Text_ScreenMap_HDR);
}
// Scaled version of the HDR scene texture
if (r->m_bDeviceSupportsMRT)
{
AllocateDeferredRenderTarget(r->m_dwHDRCropWidth/4, r->m_dwHDRCropHeight/4, D3DFMT_G16R16F, 1.f, "$HDRTargetScaled0", &m_Text_HDRTargetScaled[0]);
AllocateDeferredRenderTarget(r->m_dwHDRCropWidth/4, r->m_dwHDRCropHeight/4, D3DFMT_G16R16F, 1.f, "$HDRTargetScaled1", &m_Text_HDRTargetScaled[1]);
}
else
{
AllocateDeferredRenderTarget(r->m_dwHDRCropWidth/4, r->m_dwHDRCropHeight/4, D3DFMT_A16B16G16R16F, 1.f, "$HDRTargetScaled", &m_Text_HDRTargetScaled[0] );
m_Text_HDRTargetScaled[1] = NULL;
}
AllocateDeferredRenderTarget(r->m_dwHDRCropWidth/4+2, r->m_dwHDRCropHeight/4+2, D3DFMT_A8R8G8B8, 0.5f, "$HDRBrightPass", &m_Text_HDRBrightPass);
AllocateDeferredRenderTarget(r->m_dwHDRCropWidth/4+2, r->m_dwHDRCropHeight/4+2, D3DFMT_A8R8G8B8, 0.5f, "$HDRStarSource", &m_Text_HDRStarSource);
AllocateDeferredRenderTarget(r->m_dwHDRCropWidth/8+2, r->m_dwHDRCropHeight/8+2, D3DFMT_A8R8G8B8, 0.8f, "$HDRBloomSource", &m_Text_HDRBloomSource);
AllocateDeferredRenderTarget(1, 1, r->m_HDR_FloatFormat_Scalar, 0.1f, "$HDRAdaptedLuminanceCur", &m_Text_HDRAdaptedLuminanceCur);
AllocateDeferredRenderTarget(1, 1, r->m_HDR_FloatFormat_Scalar, 0.1f, "$HDRAdaptedLuminanceLast", &m_Text_HDRAdaptedLuminanceLast);
// For each scale stage, create a texture to hold the intermediate results
// of the luminance calculation
for(i=0; i<NUM_HDR_TONEMAP_TEXTURES; i++)
{
int iSampleLen = 1 << (2*i);
sprintf(szName, "$HDRToneMap_%d", i);
AllocateDeferredRenderTarget(iSampleLen, iSampleLen, r->m_HDR_FloatFormat_Scalar, 0.7f, szName, &m_Text_HDRToneMaps[i]);
}
// Create the temporary blooming effect textures
// Texture has a black border of single texel thickness to fake border
// addressing using clamp addressing
for(i=1; i<NUM_HDR_BLOOM_TEXTURES; i++)
{
sprintf(szName, "$HDRBloomMap_%d", i);
AllocateDeferredRenderTarget(r->m_dwHDRCropWidth/8+2, r->m_dwHDRCropHeight/8+2, D3DFMT_A8R8G8B8, 0.8f, szName, &m_Text_HDRBloomMaps[i]);
}
AllocateDeferredRenderTarget(r->m_dwHDRCropWidth/8, r->m_dwHDRCropHeight/8, D3DFMT_A8R8G8B8, 0.5f, "$HDRBloomMap_0", &m_Text_HDRBloomMaps[0]);
// Create the star effect textures
for(i=0; i<NUM_HDR_STAR_TEXTURES; i++)
{
if (r->m_bDeviceSupportsMRT )
{
sprintf(szName, "$HDRStarMap_%d(0)", i);
AllocateDeferredRenderTarget(r->m_dwHDRCropWidth/4, r->m_dwHDRCropHeight/4, D3DFMT_G16R16F, 0.8f, szName, &m_Text_HDRStarMaps[i][0]);
sprintf(szName, "$HDRStarMap_%d(1)", i);
AllocateDeferredRenderTarget(r->m_dwHDRCropWidth/4, r->m_dwHDRCropHeight/4, D3DFMT_G16R16F, 0.8f, szName, &m_Text_HDRStarMaps[i][1]);
}
else
{
sprintf(szName, "$HDRStarMap_%d", i);
AllocateDeferredRenderTarget(r->m_dwHDRCropWidth/4, r->m_dwHDRCropHeight/4, D3DFMT_A16B16G16R16F, 0.8f, szName, &m_Text_HDRStarMaps[i][0]);
m_Text_HDRStarMaps[i][1] = NULL;
}
}
EndRenderTargetList();
}
//=============================================================================
//----------------------------------------------------------
// Star generation
// Define each line of the star.
typedef struct STARLINE
{
int nPasses ;
float fSampleLength ;
float fAttenuation ;
float fInclination ;
} *LPSTARLINE ;
// Simple definition of the star.
typedef struct STARDEF
{
TCHAR *szStarName ;
int nStarLines ;
int nPasses ;
float fSampleLength ;
float fAttenuation ;
float fInclination ;
bool bRotation ;
} *LPSTARDEF ;
// Simple definition of the sunny cross filter
typedef struct STARDEF_SUNNYCROSS
{
TCHAR *szStarName ;
float fSampleLength ;
float fAttenuation ;
float fInclination ;
} *LPSTARDEF_SUNNYCROSS ;
// Star form library
enum ESTARLIBTYPE
{
STLT_DISABLE = 0,
STLT_CROSS,
STLT_CROSSFILTER,
STLT_SNOWCROSS,
STLT_VERTICAL,
NUM_BASESTARLIBTYPES,
STLT_SUNNYCROSS = NUM_BASESTARLIBTYPES,
NUM_STARLIBTYPES,
} ;
//----------------------------------------------------------
// Star generation object
class CStarDef
{
public:
TCHAR m_strStarName[256] ;
int m_nStarLines ;
LPSTARLINE m_pStarLine ; // [m_nStarLines]
float m_fInclination ;
bool m_bRotation ; // Rotation is available from outside ?
// Static library
public:
static CStarDef *ms_pStarLib ;
static D3DXCOLOR ms_avChromaticAberrationColor[8] ;
// Public method
public:
CStarDef() ;
CStarDef(const CStarDef& src) ;
~CStarDef() ;
CStarDef& operator =(const CStarDef& src) {
Initialize(src) ;
return *this ;
}
HRESULT Construct() ;
void Destruct() ;
void Release() ;
HRESULT Initialize(const CStarDef& src) ;
HRESULT Initialize(ESTARLIBTYPE eType) {
return Initialize(ms_pStarLib[eType]) ;
}
/// Generic simple star generation
HRESULT Initialize(const TCHAR *szStarName,
int nStarLines,
int nPasses,
float fSampleLength,
float fAttenuation,
float fInclination,
bool bRotation) ;
HRESULT Initialize(const STARDEF& starDef)
{
return Initialize(starDef.szStarName,
starDef.nStarLines,
starDef.nPasses,
starDef.fSampleLength,
starDef.fAttenuation,
starDef.fInclination,
starDef.bRotation) ;
}
/// Specific star generation
// Sunny cross filter
HRESULT Initialize_SunnyCrossFilter(const TCHAR *szStarName = TEXT("SunnyCross"),
float fSampleLength = 1.0f,
float fAttenuation = 0.88f,
float fLongAttenuation = 0.95f,
float fInclination = D3DXToRadian(0.0f)) ;
// Public static method
public:
/// Create star library
static HRESULT InitializeStaticStarLibs() ;
static HRESULT DeleteStaticStarLibs() ;
/// Access to the star library
static const CStarDef& GetLib(DWORD dwType) {
return ms_pStarLib[dwType] ;
}
static const D3DXCOLOR& GetChromaticAberrationColor(DWORD dwID) {
return ms_avChromaticAberrationColor[dwID] ;
}
} ;
//============================================================================
// Glare form library
enum EGLARELIBTYPE
{
GLT_DISABLE = 0,
GLT_CAMERA,
GLT_NATURAL,
GLT_CHEAPLENS,
//GLT_AFTERIMAGE,
GLT_FILTER_CROSSSCREEN,
GLT_FILTER_CROSSSCREEN_SPECTRAL,
GLT_FILTER_SNOWCROSS,
GLT_FILTER_SNOWCROSS_SPECTRAL,
GLT_FILTER_SUNNYCROSS,
GLT_FILTER_SUNNYCROSS_SPECTRAL,
GLT_CINECAM_VERTICALSLITS,
GLT_CINECAM_HORIZONTALSLITS,
NUM_GLARELIBTYPES,
GLT_USERDEF = -1,
GLT_DEFAULT = GLT_FILTER_CROSSSCREEN,
} ;
// Simple glare definition
typedef struct GLAREDEF
{
TCHAR *szGlareName ;
float fGlareLuminance ;
float fBloomLuminance ;
float fGhostLuminance ;
float fGhostDistortion ;
float fStarLuminance ;
ESTARLIBTYPE eStarType ;
float fStarInclination ;
float fChromaticAberration ;
float fAfterimageSensitivity ; // Current weight
float fAfterimageRatio ; // Afterimage weight
float fAfterimageLuminance ;
} *LPGLAREDEF ;
class CGlareDef
{
public:
TCHAR m_strGlareName[256] ;
float m_fGlareLuminance ; // Total glare intensity (not effect to "after image")
float m_fBloomLuminance ;
float m_fGhostLuminance ;
float m_fGhostDistortion ;
float m_fStarLuminance ;
float m_fStarInclination ;
float m_fChromaticAberration ;
float m_fAfterimageSensitivity ; // Current weight
float m_fAfterimageRatio ; // Afterimage weight
float m_fAfterimageLuminance ;
CStarDef m_starDef ;
// Static library
public:
static CGlareDef *ms_pGlareLib ;
// Public method
public:
CGlareDef() ;
CGlareDef(const CGlareDef& src) ;
~CGlareDef() ;
CGlareDef& operator =(const CGlareDef& src) {
Initialize(src) ;
return *this ;
}
HRESULT Construct() ;
void Destruct() ;
void Release() ;
HRESULT Initialize(const CGlareDef& src) ;
HRESULT Initialize(const TCHAR *szStarName,
float fGlareLuminance,
float fBloomLuminance,
float fGhostLuminance,
float fGhostDistortion,
float fStarLuminance,
ESTARLIBTYPE eStarType,
float fStarInclination,
float fChromaticAberration,
float fAfterimageSensitivity, // Current weight
float fAfterimageRatio, // After Image weight
float fAfterimageLuminance) ;
HRESULT Initialize(const GLAREDEF& glareDef)
{
return Initialize(glareDef.szGlareName,
glareDef.fGlareLuminance,
glareDef.fBloomLuminance,
glareDef.fGhostLuminance,
glareDef.fGhostDistortion,
glareDef.fStarLuminance,
glareDef.eStarType,
glareDef.fStarInclination,
glareDef.fChromaticAberration,
glareDef.fAfterimageSensitivity,
glareDef.fAfterimageRatio,
glareDef.fAfterimageLuminance) ;
}
HRESULT Initialize(EGLARELIBTYPE eType) {
return Initialize(ms_pGlareLib[eType]) ;
}
// Public static method
public:
/// Create glare library
static HRESULT InitializeStaticGlareLibs() ;
static HRESULT DeleteStaticGlareLibs() ;
/// Access to the glare library
static const CGlareDef& GetLib(DWORD dwType) {
return ms_pGlareLib[dwType] ;
}
} ;
//----------------------------------------------------------
// Dummy to generate static object of glare
class __CGlare_GenerateStaticObjects
{
public:
__CGlare_GenerateStaticObjects() {
CStarDef::InitializeStaticStarLibs() ;
CGlareDef::InitializeStaticGlareLibs() ;
}
~__CGlare_GenerateStaticObjects() {
CGlareDef::DeleteStaticGlareLibs() ;
CStarDef::DeleteStaticStarLibs() ;
}
static __CGlare_GenerateStaticObjects ms_staticObject ;
} ;
__CGlare_GenerateStaticObjects __CGlare_GenerateStaticObjects::ms_staticObject ;
CGlareDef g_GlareDef;
#define _Rad D3DXToRadian
// Static star library information
static STARDEF s_aLibStarDef[NUM_BASESTARLIBTYPES] =
{
// star name lines passes length attn rotate bRotate
{ TEXT("Disable"), 0, 0, 0.0f, 0.0f, _Rad(00.0f), false, }, // STLT_DISABLE
{ TEXT("Cross"), 4, 3, 1.0f, 0.85f, _Rad(0.0f), true, }, // STLT_CROSS
{ TEXT("CrossFilter"), 4, 3, 1.0f, 0.95f, _Rad(0.0f), true, }, // STLT_CROSS
{ TEXT("snowCross"), 6, 3, 1.0f, 0.96f, _Rad(20.0f), true, }, // STLT_SNOWCROSS
{ TEXT("Vertical"), 2, 3, 1.0f, 0.96f, _Rad(00.0f), false, }, // STLT_VERTICAL
} ;
static int s_nLibStarDefs = sizeof(s_aLibStarDef) / sizeof(STARDEF) ;
// Static glare library information
static GLAREDEF s_aLibGlareDef[NUM_GLARELIBTYPES] =
{
// glare name glare bloom ghost distort star star type
// rotate C.A current after ai lum
{ TEXT("Disable"), 0.0f, 0.0f, 0.0f, 0.01f, 0.0f, STLT_DISABLE,
_Rad(0.0f), 0.5f, 0.00f, 0.00f, 0.0f, }, // GLT_DISABLE
{ TEXT("Camera"), 1.5f, 1.2f, 1.0f, 0.00f, 1.0f, STLT_CROSS,
_Rad(00.0f), 0.5f, 0.25f, 0.90f, 1.0f, }, // GLT_CAMERA
{ TEXT("Natural Bloom"), 1.5f, 1.2f, 0.0f, 0.00f, 0.0f, STLT_DISABLE,
_Rad(00.0f), 0.0f, 0.40f, 0.85f, 0.5f, }, // GLT_NATURAL
{ TEXT("Cheap Lens Camera"), 1.25f, 2.0f, 1.5f, 0.05f, 2.0f, STLT_CROSS,
_Rad(00.0f), 0.5f, 0.18f, 0.95f, 1.0f, }, // GLT_CHEAPLENS
/*
{ TEXT("Afterimage"), 1.5f, 1.2f, 0.5f, 0.00f, 0.7f, STLT_CROSS,
_Rad(00.0f), 0.5f, 0.1f, 0.98f, 2.0f, }, // GLT_AFTERIMAGE
*/
{ TEXT("Cross Screen Filter"), 1.0f, 2.0f, 1.7f, 0.00f, 1.5f, STLT_CROSSFILTER,
_Rad(25.0f), 0.5f, 0.20f, 0.93f, 1.0f, }, // GLT_FILTER_CROSSSCREEN
{ TEXT("Spectral Cross Filter"), 1.0f, 2.0f, 1.7f, 0.00f, 1.8f, STLT_CROSSFILTER,
_Rad(70.0f), 1.5f, 0.20f, 0.93f, 1.0f, }, // GLT_FILTER_CROSSSCREEN_SPECTRAL
{ TEXT("Snow Cross Filter"), 1.0f, 2.0f, 1.7f, 0.00f, 1.5f, STLT_SNOWCROSS,
_Rad(10.0f), 0.5f, 0.20f, 0.93f, 1.0f, }, // GLT_FILTER_SNOWCROSS
{ TEXT("Spectral Snow Cross"), 1.0f, 2.0f, 1.7f, 0.00f, 1.8f, STLT_SNOWCROSS,
_Rad(40.0f), 1.5f, 0.20f, 0.93f, 1.0f, }, // GLT_FILTER_SNOWCROSS_SPECTRAL
{ TEXT("Sunny Cross Filter"), 1.0f, 2.0f, 1.7f, 0.00f, 1.5f, STLT_SUNNYCROSS,
_Rad(00.0f), 0.5f, 0.20f, 0.93f, 1.0f, }, // GLT_FILTER_SUNNYCROSS
{ TEXT("Spectral Sunny Cross"), 1.0f, 2.0f, 1.7f, 0.00f, 1.8f, STLT_SUNNYCROSS,
_Rad(45.0f), 1.5f, 0.20f, 0.93f, 1.0f, }, // GLT_FILTER_SUNNYCROSS_SPECTRAL
{ TEXT("Cine Camera Vertical Slits"), 1.0f, 2.0f, 1.5f, 0.00f, 1.0f, STLT_VERTICAL,
_Rad(90.0f), 0.5f, 0.20f, 0.93f, 1.0f, }, // GLT_CINECAM_VERTICALSLIT
{ TEXT("Cine Camera Horizontal Slits"), 1.0f, 2.0f, 1.5f, 0.00f, 1.0f, STLT_VERTICAL,
_Rad(00.0f), 0.5f, 0.20f, 0.93f, 1.0f, }, // GLT_CINECAM_HORIZONTALSLIT
} ;
static int s_nLibGlareDefs = sizeof(s_aLibGlareDef) / sizeof(GLAREDEF) ;
//----------------------------------------------------------
// Information object for star generation
CStarDef *CStarDef::ms_pStarLib = NULL ;
D3DXCOLOR CStarDef::ms_avChromaticAberrationColor[] ;
CStarDef::CStarDef()
{
Construct() ;
}
CStarDef::CStarDef(const CStarDef& src)
{
Construct() ;
Initialize(src) ;
}
CStarDef::~CStarDef()
{
Destruct() ;
}
HRESULT CStarDef::Construct()
{
ZeroMemory( m_strStarName, sizeof(m_strStarName) );
m_nStarLines = 0 ;
m_pStarLine = NULL ;
m_fInclination = 0.0f ;
m_bRotation = false ;
return S_OK ;
}
void CStarDef::Destruct()
{
Release() ;
}
void CStarDef::Release()
{
SAFE_DELETE_ARRAY(m_pStarLine) ;
m_nStarLines = 0 ;
}
HRESULT CStarDef::Initialize(const CStarDef& src)
{
if (&src == this) {
return S_OK ;
}
// Release the data
Release() ;
// Copy the data from source
lstrcpyn( m_strStarName, src.m_strStarName, 255 );
m_nStarLines = src.m_nStarLines ;
m_fInclination = src.m_fInclination ;
m_bRotation = src.m_bRotation ;
m_pStarLine = new STARLINE[m_nStarLines] ;
for (int i = 0 ; i < m_nStarLines ; i ++) {
m_pStarLine[i] = src.m_pStarLine[i] ;
}
return S_OK ;
}
/// generic simple star generation
HRESULT CStarDef::Initialize(const TCHAR *szStarName,
int nStarLines,
int nPasses,
float fSampleLength,
float fAttenuation,
float fInclination,
bool bRotation)
{
// Release the data
Release() ;
// Copy from parameters
lstrcpyn( m_strStarName, szStarName, 255 );
m_nStarLines = nStarLines ;
m_fInclination = fInclination ;
m_bRotation = bRotation ;
m_pStarLine = new STARLINE[m_nStarLines] ;
float fInc = D3DXToRadian(360.0f / (float)m_nStarLines) ;
for (int i = 0 ; i < m_nStarLines ; i ++)
{
m_pStarLine[i].nPasses = nPasses ;
m_pStarLine[i].fSampleLength = fSampleLength ;
m_pStarLine[i].fAttenuation = fAttenuation ;
m_pStarLine[i].fInclination = fInc * (float)i ;
}
return S_OK ;
}
/// Specific start generation
// Sunny cross filter
HRESULT CStarDef::Initialize_SunnyCrossFilter(const TCHAR *szStarName,
float fSampleLength,
float fAttenuation,
float fLongAttenuation,
float fInclination)
{
// Release the data
Release() ;
// Create parameters
lstrcpyn( m_strStarName, szStarName, 255 );
m_nStarLines = 8 ;
m_fInclination = fInclination ;
// m_bRotation = true ;
m_bRotation = false ;
m_pStarLine = new STARLINE[m_nStarLines] ;
float fInc = D3DXToRadian(360.0f / (float)m_nStarLines) ;
for (int i = 0 ; i < m_nStarLines ; i ++)
{
m_pStarLine[i].fSampleLength = fSampleLength ;
m_pStarLine[i].fInclination = fInc * (float)i + D3DXToRadian(0.0f) ;
if ( 0 == (i % 2) ) {
m_pStarLine[i].nPasses = 3 ;
m_pStarLine[i].fAttenuation = fLongAttenuation ; // long
}
else {
m_pStarLine[i].nPasses = 3 ;
m_pStarLine[i].fAttenuation = fAttenuation ;
}
}
return S_OK ;
}
HRESULT CStarDef::InitializeStaticStarLibs()
{
if (ms_pStarLib) {
return S_OK ;
}
ms_pStarLib = new CStarDef[NUM_STARLIBTYPES] ;
// Create basic form
for (int i = 0 ; i < NUM_BASESTARLIBTYPES ; i ++) {
ms_pStarLib[i].Initialize(s_aLibStarDef[i]) ;
}
// Create special form
// Sunny cross filter
ms_pStarLib[STLT_SUNNYCROSS].Initialize_SunnyCrossFilter() ;
// Initialize color aberration table
/*
{
D3DXCOLOR(0.5f, 0.5f, 0.5f, 0.0f),
D3DXCOLOR(1.0f, 0.2f, 0.2f, 0.0f),
D3DXCOLOR(0.2f, 0.6f, 0.2f, 0.0f),
D3DXCOLOR(0.2f, 0.2f, 1.0f, 0.0f),
} ;
*/
D3DXCOLOR avColor[8] =
{
/*
D3DXCOLOR(0.5f, 0.5f, 0.5f, 0.0f),
D3DXCOLOR(0.3f, 0.3f, 0.8f, 0.0f),
D3DXCOLOR(0.2f, 0.2f, 1.0f, 0.0f),
D3DXCOLOR(0.2f, 0.4f, 0.5f, 0.0f),
D3DXCOLOR(0.2f, 0.6f, 0.2f, 0.0f),
D3DXCOLOR(0.5f, 0.4f, 0.2f, 0.0f),
D3DXCOLOR(0.7f, 0.3f, 0.2f, 0.0f),
D3DXCOLOR(1.0f, 0.2f, 0.2f, 0.0f),
*/
D3DXCOLOR(0.5f, 0.5f, 0.5f, 0.0f), // w
D3DXCOLOR(0.8f, 0.3f, 0.3f, 0.0f),
D3DXCOLOR(1.0f, 0.2f, 0.2f, 0.0f), // r
D3DXCOLOR(0.5f, 0.2f, 0.6f, 0.0f),
D3DXCOLOR(0.2f, 0.2f, 1.0f, 0.0f), // b
D3DXCOLOR(0.2f, 0.3f, 0.7f, 0.0f),
D3DXCOLOR(0.2f, 0.6f, 0.2f, 0.0f), // g
D3DXCOLOR(0.3f, 0.5f, 0.3f, 0.0f),
} ;
memcpy( ms_avChromaticAberrationColor, avColor, sizeof(D3DXCOLOR) * 8 ) ;
/*
ms_avChromaticAberrationColor[0] = D3DXCOLOR(0.5f, 0.5f, 0.5f, 0.0f) ;
ms_avChromaticAberrationColor[1] = D3DXCOLOR(0.7f, 0.3f, 0.3f, 0.0f) ;
ms_avChromaticAberrationColor[2] = D3DXCOLOR(1.0f, 0.2f, 0.2f, 0.0f) ;
ms_avChromaticAberrationColor[3] = D3DXCOLOR(0.5f, 0.5f, 0.5f, 0.0f) ;
ms_avChromaticAberrationColor[4] = D3DXCOLOR(0.2f, 0.6f, 0.2f, 0.0f) ;
ms_avChromaticAberrationColor[5] = D3DXCOLOR(0.2f, 0.4f, 0.5f, 0.0f) ;
ms_avChromaticAberrationColor[6] = D3DXCOLOR(0.2f, 0.3f, 0.8f, 0.0f) ;
ms_avChromaticAberrationColor[7] = D3DXCOLOR(0.2f, 0.2f, 1.0f, 0.0f) ;
*/
return S_OK ;
}
HRESULT CStarDef::DeleteStaticStarLibs()
{
// Delete all libraries
SAFE_DELETE_ARRAY( ms_pStarLib ) ;
return S_OK ;
}
//----------------------------------------------------------
// Glare definition
CGlareDef *CGlareDef::ms_pGlareLib = NULL ;
CGlareDef::CGlareDef()
{
Construct() ;
}
CGlareDef::CGlareDef(const CGlareDef& src)
{
Construct() ;
Initialize(src) ;
}
CGlareDef::~CGlareDef()
{
Destruct() ;
}
HRESULT CGlareDef::Construct()
{
ZeroMemory( m_strGlareName, sizeof(m_strGlareName) );
m_fGlareLuminance = 0.0f ;
m_fBloomLuminance = 0.0f ;
m_fGhostLuminance = 0.0f ;
m_fStarLuminance = 0.0f ;
m_fStarInclination = 0.0f ;
m_fChromaticAberration = 0.0f ;
m_fAfterimageSensitivity = 0.0f ;
m_fAfterimageRatio = 0.0f ;
m_fAfterimageLuminance = 0.0f ;
return S_OK ;
}
void CGlareDef::Destruct()
{
m_starDef.Release() ;
}
void CGlareDef::Release()
{
}
HRESULT CGlareDef::Initialize(const CGlareDef& src)
{
if (&src == this) {
return S_OK ;
}
// Release the data
Release() ;
// Copy data from source
lstrcpyn( m_strGlareName, src.m_strGlareName, 255 );
m_fGlareLuminance = src.m_fGlareLuminance ;
m_fBloomLuminance = src.m_fBloomLuminance ;
m_fGhostLuminance = src.m_fGhostLuminance ;
m_fGhostDistortion = src.m_fGhostDistortion ;
m_fStarLuminance = src.m_fStarLuminance ;
m_fStarLuminance = src.m_fStarLuminance ;
m_fStarInclination = src.m_fStarInclination ;
m_fChromaticAberration = src.m_fChromaticAberration ;
m_fAfterimageSensitivity = src.m_fStarLuminance ;
m_fAfterimageRatio = src.m_fStarLuminance ;
m_fAfterimageLuminance = src.m_fStarLuminance ;
m_starDef = src.m_starDef ;
return S_OK ;
}
HRESULT CGlareDef::Initialize(const TCHAR *szStarName,
float fGlareLuminance,
float fBloomLuminance,
float fGhostLuminance,
float fGhostDistortion,
float fStarLuminance,
ESTARLIBTYPE eStarType,
float fStarInclination,
float fChromaticAberration,
float fAfterimageSensitivity, // Current weight
float fAfterimageRatio, // Afterimage weight
float fAfterimageLuminance)
{
// Release the data
Release() ;
// Create parameters
lstrcpyn( m_strGlareName, szStarName, 255 );
m_fGlareLuminance = fGlareLuminance ;
m_fBloomLuminance = fBloomLuminance ;
m_fGhostLuminance = fGhostLuminance ;
m_fGhostDistortion = fGhostDistortion ;
m_fStarLuminance = fStarLuminance ;
m_fStarInclination = fStarInclination ;
m_fChromaticAberration = fChromaticAberration ;
m_fAfterimageSensitivity = fAfterimageSensitivity ;
m_fAfterimageRatio = fAfterimageRatio ;
m_fAfterimageLuminance = fAfterimageLuminance ;
// Create star form data
m_starDef = CStarDef::GetLib(eStarType) ;
return S_OK ;
}
HRESULT CGlareDef::InitializeStaticGlareLibs()
{
if (ms_pGlareLib) {
return S_OK ;
}
CStarDef::InitializeStaticStarLibs() ;
ms_pGlareLib = new CGlareDef[NUM_GLARELIBTYPES] ;
// Create glare form
for (int i = 0 ; i < NUM_GLARELIBTYPES ; i ++) {
ms_pGlareLib[i].Initialize(s_aLibGlareDef[i]) ;
}
return S_OK ;
}
HRESULT CGlareDef::DeleteStaticGlareLibs()
{
// Delete all libraries
SAFE_DELETE_ARRAY( ms_pGlareLib ) ;
return S_OK ;
}
//=============================================================================
// Texture coordinate rectangle
struct CoordRect
{
float fLeftU, fTopV;
float fRightU, fBottomV;
};
// Screen quad vertex format
struct ScreenVertex
{
D3DXVECTOR4 p; // position
D3DCOLOR color;
D3DXVECTOR2 t; // texture coordinate
};
// log helper
#define LOG_EFFECT(msg)\
if (gRenDev->m_LogFile)\
{\
gRenDev->Logv(SRendItem::m_RecurseLevel, msg);\
}\
// ===============================================================
// SetTexture - sets texture stage
inline void SetTexture(CD3D9Renderer *pRenderer, STexPic *pTex, int iStage, int iMinFilter, int iMagFilter, bool bClamp)
{
pRenderer->EF_SelectTMU(iStage);
if(pTex)
{
pTex->m_RefTex.m_MinFilter=iMinFilter;
pTex->m_RefTex.m_MagFilter=iMagFilter;
pTex->m_RefTex.bRepeats=(!bClamp);
pTex->Set();
}
else
{
pRenderer->SetTexture(0);
}
}
PDIRECT3DSURFACE9 GetSurfaceTP(STexPic *tp)
{
PDIRECT3DSURFACE9 pSurf = NULL;
if (tp)
{
LPDIRECT3DTEXTURE9 pTexture = (LPDIRECT3DTEXTURE9)tp->m_RefTex.m_VidTex;
assert(pTexture);
HRESULT hr = pTexture->GetSurfaceLevel(0, &pSurf);
}
return pSurf;
}
#define NV_CACHE_OPTS_ENABLED TRUE
//-----------------------------------------------------------------------------
// Name: DrawFullScreenQuad
// Desc: Draw a properly aligned quad covering the entire render target
//-----------------------------------------------------------------------------
void DrawFullScreenQuad(float fLeftU, float fTopV, float fRightU, float fBottomV)
{
D3DSURFACE_DESC dtdsdRT;
PDIRECT3DSURFACE9 pSurfRT;
CD3D9Renderer *rd = gcpRendD3D;
LPDIRECT3DDEVICE9 dv = rd->m_pd3dDevice;
// Acquire render target width and height
dv->GetRenderTarget(0, &pSurfRT);
pSurfRT->GetDesc(&dtdsdRT);
pSurfRT->Release();
// Ensure that we're directly mapping texels to pixels by offset by 0.5
// For more info see the doc page titled "Directly Mapping Texels to Pixels"
int nWidth = min((int)dtdsdRT.Width, rd->GetWidth());
int nHeight = min((int)dtdsdRT.Height, rd->GetHeight());
float fWidth5 = (float)nWidth;
float fHeight5 = (float)nHeight;
fWidth5 = (NV_CACHE_OPTS_ENABLED) ? (2.f*fWidth5) - 0.5f : fWidth5 - 0.5f;
fHeight5 = (NV_CACHE_OPTS_ENABLED) ? (2.f*fHeight5)- 0.5f : fHeight5 - 0.5f;
// Draw the quad
ScreenVertex svQuad[4];
svQuad[0].p = D3DXVECTOR4(-0.5f, -0.5f, 0.5f, 1.0f);
svQuad[0].color = -1;
svQuad[0].t = D3DXVECTOR2(fLeftU, fTopV);
if (NV_CACHE_OPTS_ENABLED)
{
float tWidth = fRightU - fLeftU;
float tHeight = fBottomV - fTopV;
svQuad[1].p = D3DXVECTOR4(fWidth5, -0.5f, 0.5f, 1.f);
svQuad[1].t = D3DXVECTOR2(fLeftU + (tWidth*2.f), fTopV);
svQuad[2].p = D3DXVECTOR4(-0.5f, fHeight5, 0.5f, 1.f);
svQuad[2].t = D3DXVECTOR2(fLeftU, fTopV + (tHeight*2.f));
}
else
{
svQuad[1].p = D3DXVECTOR4(fWidth5, -0.5f, 0.5f, 1.0f);
svQuad[1].color = -1;
svQuad[1].t = D3DXVECTOR2(fRightU, fTopV);
svQuad[2].p = D3DXVECTOR4(-0.5f, fHeight5, 0.5f, 1.0f);
svQuad[2].color = -1;
svQuad[2].t = D3DXVECTOR2(fLeftU, fBottomV);
svQuad[3].p = D3DXVECTOR4(fWidth5, fHeight5, 0.5f, 1.0f);
svQuad[3].color = -1;
svQuad[3].t = D3DXVECTOR2(fRightU, fBottomV);
}
rd->EF_SetState(GS_NODEPTHTEST);
rd->EF_SetVertexDeclaration(0, VERTEX_FORMAT_TRP3F_COL4UB_TEX2F);
dv->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, (NV_CACHE_OPTS_ENABLED)?1:2, svQuad, sizeof(ScreenVertex));
}
void DrawFullScreenQuad(CoordRect c)
{
DrawFullScreenQuad( c.fLeftU, c.fTopV, c.fRightU, c.fBottomV );
}
//-----------------------------------------------------------------------------
// Name: GetTextureRect()
// Desc: Get the dimensions of the texture
//-----------------------------------------------------------------------------
HRESULT GetTextureRect(STexPic *pTexture, RECT* pRect)
{
pRect->left = 0;
pRect->top = 0;
pRect->right = pTexture->m_Width;
pRect->bottom = pTexture->m_Height;
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: GetTextureCoords()
// Desc: Get the texture coordinates to use when rendering into the destination
// texture, given the source and destination rectangles
//-----------------------------------------------------------------------------
HRESULT GetTextureCoords( STexPic *pTexSrc, RECT* pRectSrc, STexPic *pTexDest, RECT* pRectDest, CoordRect* pCoords)
{
float tU, tV;
// Validate arguments
if( pTexSrc == NULL || pTexDest == NULL || pCoords == NULL )
return E_INVALIDARG;
// Start with a default mapping of the complete source surface to complete
// destination surface
pCoords->fLeftU = 0.0f;
pCoords->fTopV = 0.0f;
pCoords->fRightU = 1.0f;
pCoords->fBottomV = 1.0f;
// If not using the complete source surface, adjust the coordinates
if(pRectSrc != NULL)
{
// These delta values are the distance between source texel centers in
// texture address space
tU = 1.0f / pTexSrc->m_Width;
tV = 1.0f / pTexSrc->m_Height;
pCoords->fLeftU += pRectSrc->left * tU;
pCoords->fTopV += pRectSrc->top * tV;
pCoords->fRightU -= (pTexSrc->m_Width - pRectSrc->right) * tU;
pCoords->fBottomV -= (pTexSrc->m_Height - pRectSrc->bottom) * tV;
}
// If not drawing to the complete destination surface, adjust the coordinates
if(pRectDest != NULL)
{
// These delta values are the distance between source texel centers in
// texture address space
tU = 1.0f / pTexDest->m_Width;
tV = 1.0f / pTexDest->m_Height;
pCoords->fLeftU -= pRectDest->left * tU;
pCoords->fTopV -= pRectDest->top * tV;
pCoords->fRightU += (pTexDest->m_Width - pRectDest->right) * tU;
pCoords->fBottomV += (pTexDest->m_Height - pRectDest->bottom) * tV;
}
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: GaussianDistribution
// Desc: Helper function for GetSampleOffsets function to compute the
// 2 parameter Gaussian distrubution using the given standard deviation
// rho
//-----------------------------------------------------------------------------
float GaussianDistribution( float x, float y, float rho )
{
float g = 1.0f / sqrtf(2.0f * D3DX_PI * rho * rho);
g *= expf( -(x*x + y*y)/(2*rho*rho) );
return g;
}
//-----------------------------------------------------------------------------
// Name: GetSampleOffsets_GaussBlur5x5
// Desc: Get the texture coordinate offsets to be used inside the GaussBlur5x5
// pixel shader.
//-----------------------------------------------------------------------------
HRESULT GetSampleOffsets_GaussBlur5x5(DWORD dwD3DTexWidth, DWORD dwD3DTexHeight, D3DXVECTOR4* avTexCoordOffset, D3DXVECTOR4* avSampleWeight, FLOAT fMultiplier)
{
float tu = 1.0f / (float)dwD3DTexWidth ;
float tv = 1.0f / (float)dwD3DTexHeight ;
D3DXVECTOR4 vWhite( 1.0f, 1.0f, 1.0f, 1.0f );
float totalWeight = 0.0f;
int index=0;
for(int x=-2; x<=2; x++)
{
for(int y=-2; y<=2; y++)
{
// Exclude pixels with a block distance greater than 2. This will
// create a kernel which approximates a 5x5 kernel using only 13
// sample points instead of 25; this is necessary since 2.0 shaders
// only support 16 texture grabs.
if( abs(x) + abs(y) > 2 )
continue;
// Get the unscaled Gaussian intensity for this offset
avTexCoordOffset[index] = D3DXVECTOR4(x*tu, y*tv, 0, 1);
avSampleWeight[index] = vWhite * GaussianDistribution( (float)x, (float)y, 1.0f);
totalWeight += avSampleWeight[index].x;
index++;
}
}
// Divide the current weight by the total weight of all the samples; Gaussian
// blur kernels add to 1.0f to ensure that the intensity of the image isn't
// changed when the blur occurs. An optional multiplier variable is used to
// add or remove image intensity during the blur.
for(int i=0; i<index; i++)
{
avSampleWeight[i] /= totalWeight;
avSampleWeight[i] *= fMultiplier;
}
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: GetSampleOffsets_GaussBlur5x5Bilinear
// Desc: Get the texture coordinate offsets to be used inside the GaussBlur5x5
// pixel shader.
//-----------------------------------------------------------------------------
HRESULT GetSampleOffsets_GaussBlur5x5Bilinear(DWORD dwD3DTexWidth, DWORD dwD3DTexHeight, D3DXVECTOR4* avTexCoordOffset, D3DXVECTOR4* avSampleWeight, FLOAT fMultiplier)
{
float tu = 1.0f / (float)dwD3DTexWidth ;
float tv = 1.0f / (float)dwD3DTexHeight ;
float totalWeight = 0.0f;
D3DXVECTOR4 vWhite( 1.f, 1.f, 1.f, 1.f );
float fWeights[5];
int index = 0;
for (int x=-2; x<=2; x++, index++)
{
fWeights[index] = GaussianDistribution( (float)x, 0.f, 1.f );
}
// compute weights for the 2x2 taps. only 9 bilinear taps are required to sample the entire area.
index = 0;
for (int y=-2; y<=2; y+=2)
{
float tScale = (y==2)?fWeights[4] : (fWeights[y+2] + fWeights[y+3]);
float tFrac = fWeights[y+2] / tScale;
float tOfs = ((float)y + (1.f-tFrac)) * tv;
for (int x=-2; x<=2; x+=2, index++)
{
float sScale = (x==2)?fWeights[4] : (fWeights[x+2] + fWeights[x+3]);
float sFrac = fWeights[x+2] / sScale;
float sOfs = ((float)x + (1.f-sFrac)) * tu;
avTexCoordOffset[index] = D3DXVECTOR4(sOfs, tOfs, 0, 1);
avSampleWeight[index] = vWhite * sScale * tScale;
totalWeight += sScale * tScale;
}
}
for ( int i=0; i<index; i++)
{
avSampleWeight[i] *= (fMultiplier / totalWeight);
}
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: GetSampleOffsets_Bloom
// Desc: Get the texture coordinate offsets to be used inside the Bloom
// pixel shader.
//-----------------------------------------------------------------------------
HRESULT GetSampleOffsets_Bloom(DWORD dwD3DTexSize, float afTexCoordOffset[15], D3DXVECTOR4* avColorWeight, float fDeviation, float fMultiplier)
{
int i=0;
float tu = 1.0f / (float)dwD3DTexSize;
// Fill the center texel
float weight = fMultiplier * GaussianDistribution( 0, 0, fDeviation );
avColorWeight[0] = D3DXVECTOR4( weight, weight, weight, 1.0f );
afTexCoordOffset[0] = 0.0f;
// Fill the first half
for(i=1; i<8; i++)
{
// Get the Gaussian intensity for this offset
weight = fMultiplier * GaussianDistribution( (float)i, 0, fDeviation );
afTexCoordOffset[i] = i * tu;
avColorWeight[i] = D3DXVECTOR4( weight, weight, weight, 1.0f );
}
// Mirror to the second half
for(i=8; i<15; i++)
{
avColorWeight[i] = avColorWeight[i-7];
afTexCoordOffset[i] = -afTexCoordOffset[i-7];
}
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: GetSampleOffsets_BloomBilinear
// Desc: Get the texture coordinate offsets to be used inside the Bloom
// pixel shader.
//-----------------------------------------------------------------------------
HRESULT GetSampleOffsets_BloomBilinear(DWORD dwD3DTexSize, float afTexCoordOffset[15], D3DXVECTOR4* avColorWeight, float fDeviation, float fMultiplier)
{
int i=0;
float tu = 1.0f / (float)dwD3DTexSize;
// store all the intermediate offsets & weights, then compute the bilinear
// taps in a second pass
// NOTE: always go left-to-right.
float tmpWeightArray[15];
float tmpOffsetArray[15];
// Fill the center texel
tmpWeightArray[7] = fMultiplier * GaussianDistribution( 0, 0, fDeviation );
tmpOffsetArray[7] = 0.0f;
// Fill the first half
for(i=0; i<7; i++)
{
// Get the Gaussian intensity for this offset
tmpWeightArray[i] = fMultiplier * GaussianDistribution( (float)(7-i), 0, fDeviation );
tmpOffsetArray[i] = -(float)(7-i) * tu;
}
// Mirror to the second half
for(i=8; i<15; i++)
{
tmpWeightArray[i] = tmpWeightArray[14-i];
tmpOffsetArray[i] =-tmpOffsetArray[14-i];
}
// now, munge these into bilinear weights
for(i=0; i<7; i++)
{
float sScale = tmpWeightArray[i*2] + tmpWeightArray[i*2+1];
float sFrac = tmpWeightArray[i*2] / sScale;
afTexCoordOffset[i] = tmpOffsetArray[i*2] + (1.f-sFrac)*tu;
avColorWeight[i] = D3DXVECTOR4(sScale, sScale, sScale, 2.f);
}
afTexCoordOffset[7] = tmpOffsetArray[14];
avColorWeight[7] = D3DXVECTOR4( tmpWeightArray[14], tmpWeightArray[14], tmpWeightArray[14], 1.f );
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: GetSampleOffsets_DownScale4x4
// Desc: Get the texture coordinate offsets to be used inside the DownScale4x4
// pixel shader.
//-----------------------------------------------------------------------------
HRESULT GetSampleOffsets_DownScale4x4( DWORD dwWidth, DWORD dwHeight, D3DXVECTOR4 avSampleOffsets[])
{
if(NULL == avSampleOffsets)
return E_INVALIDARG;
float tU = 1.0f / dwWidth;
float tV = 1.0f / dwHeight;
// Sample from the 16 surrounding points. Since the center point will be in
// the exact center of 16 texels, a 0.5f offset is needed to specify a texel
// center.
int index=0;
for(int y=0; y<4; y++)
{
for(int x=0; x<4; x++)
{
avSampleOffsets[index].x = (x - 1.5f) * tU;
avSampleOffsets[index].y = (y - 1.5f) * tV;
avSampleOffsets[index].z = 0;
avSampleOffsets[index].w = 1;
index++;
}
}
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: GetSampleOffsets_DownScale4x4Bilinear
// Desc: Get the texture coordinate offsets to be used inside the DownScale4x4
// pixel shader.
//-----------------------------------------------------------------------------
HRESULT GetSampleOffsets_DownScale4x4Bilinear( DWORD dwWidth, DWORD dwHeight, D3DXVECTOR4 avSampleOffsets[])
{
if ( NULL == avSampleOffsets )
return E_INVALIDARG;
float tU = 1.0f / dwWidth;
float tV = 1.0f / dwHeight;
// Sample from the 16 surrounding points. Since bilinear filtering is being used, specific the coordinate
// exactly halfway between the current texel center (k-1.5) and the neighboring texel center (k-0.5)
int index=0;
for(int y=0; y<4; y+=2)
{
for(int x=0; x<4; x+=2, index++)
{
avSampleOffsets[index].x = (x - 1.f) * tU;
avSampleOffsets[index].y = (y - 1.f) * tV;
avSampleOffsets[index].z = 0;
avSampleOffsets[index].w = 1;
}
}
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: GetSampleOffsets_DownScale2x2
// Desc: Get the texture coordinate offsets to be used inside the DownScale2x2
// pixel shader.
//-----------------------------------------------------------------------------
HRESULT GetSampleOffsets_DownScale2x2( DWORD dwWidth, DWORD dwHeight, D3DXVECTOR4 avSampleOffsets[] )
{
if( NULL == avSampleOffsets )
return E_INVALIDARG;
float tU = 1.0f / dwWidth;
float tV = 1.0f / dwHeight;
// Sample from the 4 surrounding points. Since the center point will be in
// the exact center of 4 texels, a 0.5f offset is needed to specify a texel
// center.
int index=0;
for( int y=0; y < 2; y++ )
{
for( int x=0; x < 2; x++ )
{
avSampleOffsets[index].x = (x - 0.5f) * tU;
avSampleOffsets[index].y = (y - 0.5f) * tV;
avSampleOffsets[index].z = 0;
avSampleOffsets[index].w = 1;
index++;
}
}
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: GetSampleOffsets_DownScale2x2Bilinear
// Desc: Get the texture coordinate offsets to be used inside the DownScale2x2
// pixel shader.
//-----------------------------------------------------------------------------
HRESULT GetSampleOffsets_DownScale2x2Bilinear( DWORD dwWidth, DWORD dwHeight, D3DXVECTOR4 avSampleOffsets[] )
{
if( NULL == avSampleOffsets )
return E_INVALIDARG;
float tU = 1.0f / dwWidth;
float tV = 1.0f / dwHeight;
// Sample from the 4 surrounding points. Since the center point will be in
// the exact center of 4 texels, a 0.5f offset is needed to specify a texel
// center.
int index=0;
for(int y=0; y<2; y+=2 )
{
for(int x=0; x<2; x+=2)
{
avSampleOffsets[index].x = x * tU;
avSampleOffsets[index].y = y * tV;
avSampleOffsets[index].z = 0;
avSampleOffsets[index].w = 1;
index++;
}
}
return S_OK;
}
bool HDR_SceneToSceneScaled()
{
HRESULT hr = S_OK;
D3DXVECTOR4 avSampleOffsets[16];
CD3D9Renderer *rd = gcpRendD3D;
LPDIRECT3DDEVICE9 dv = rd->m_pd3dDevice;
// Get the new render target surface
PDIRECT3DSURFACE9 pSurfScaledScene[2];
PDIRECT3DSURFACE9 pSurfTempScene;
pSurfScaledScene[0] = GetSurfaceTP(rd->m_TexMan->m_Text_HDRTargetScaled[0]);
pSurfScaledScene[1] = GetSurfaceTP(rd->m_TexMan->m_Text_HDRTargetScaled[1]);
pSurfTempScene = GetSurfaceTP(rd->m_TexMan->m_Text_HDRTarget_Temp);
// Create a 1/4 x 1/4 scale copy of the HDR texture. Since bloom textures
// are 1/8 x 1/8 scale, border texels of the HDR texture will be discarded
// to keep the dimensions evenly divisible by 8; this allows for precise
// control over sampling inside pixel shaders.
CCGPShader_D3D *fpDownScale;
CCGPShader_D3D *fpTemp;
// Place the rectangle in the center of the back buffer surface
RECT rectSrc;
rectSrc.left = (rd->GetWidth() - rd->m_dwHDRCropWidth) / 2;
rectSrc.top = (rd->GetHeight() - rd->m_dwHDRCropHeight) / 2;
rectSrc.right = rectSrc.left + rd->m_dwHDRCropWidth;
rectSrc.bottom = rectSrc.top + rd->m_dwHDRCropHeight;
if (rd->m_nHDRType == 2)
{
SetTexture(rd, rd->m_TexMan->m_Text_HDRTarget, 0, D3DTEXF_POINT, D3DTEXF_POINT, true);
//SetTexture(rd, rd->m_TexMan->m_Text_HDRTarget_K, 1, D3DTEXF_POINT, D3DTEXF_POINT, true);
SetTexture(rd, rd->m_TexMan->m_Text_White, 1, D3DTEXF_POINT, D3DTEXF_POINT, true);
dv->SetRenderTarget(0, pSurfTempScene);
fpTemp = (CCGPShader_D3D *)PShaderForName(rd->m_RP.m_PS_HDRTemp, "CGRC_HDR_MRTK_2_FP16_PS20");
assert(fpTemp);
if (fpTemp)
{
fpTemp->mfSet(true);
DrawFullScreenQuad(0, 0, 1, 1);
fpTemp->mfSet(false);
}
SetTexture(rd, NULL, 1, D3DTEXF_POINT, D3DTEXF_POINT, true);
rd->EF_SelectTMU(0);
}
// Get the texture coordinates for the render target
CoordRect coords;
GetTextureCoords(rd->m_TexMan->m_Text_HDRTarget, &rectSrc, rd->m_TexMan->m_Text_HDRTargetScaled[0], NULL, &coords);
int nBitPlanes = rd->m_bDeviceSupportsMRT ? 2 : 1;
for (int i=0; i<nBitPlanes; i++)
{
dv->SetRenderTarget(0, pSurfScaledScene[i]);
if (!rd->m_bDeviceSupportsMRT)
{
if (rd->m_bDeviceSupportsFP16Filter)
fpDownScale = (CCGPShader_D3D *)PShaderForName(rd->m_RP.m_PS_HDRDownScale4x4, "CGRC_HDR_DownScale4x4_Bilinear_PS20");
else
fpDownScale = (CCGPShader_D3D *)PShaderForName(rd->m_RP.m_PS_HDRDownScale4x4, "CGRC_HDR_DownScale4x4_PS20");
}
else
{
if (rd->m_bDeviceSupportsFP16Filter)
{
if (!i)
fpDownScale = (CCGPShader_D3D *)PShaderForName(rd->m_RP.m_PS_HDRDownScale4x4_RG, "CGRC_HDR_DownScale4x4_Bilinear_RG_PS20");
else
fpDownScale = (CCGPShader_D3D *)PShaderForName(rd->m_RP.m_PS_HDRDownScale4x4_BA, "CGRC_HDR_DownScale4x4_Bilinear_BA_PS20");
}
else
{
if (!i)
fpDownScale = (CCGPShader_D3D *)PShaderForName(rd->m_RP.m_PS_HDRDownScale4x4_RG, "CGRC_HDR_DownScale4x4_RG_PS20");
else
fpDownScale = (CCGPShader_D3D *)PShaderForName(rd->m_RP.m_PS_HDRDownScale4x4_BA, "CGRC_HDR_DownScale4x4_BA_PS20");
}
}
if (!fpDownScale)
return false;
fpDownScale->mfSet(true, 0);
if (!i)
{
// Get the sample offsets used within the pixel shader
SCGBind *bind = fpDownScale->mfGetParameterBind("vSampleOffsets");
assert(bind);
if (rd->m_bDeviceSupportsFP16Filter)
{
GetSampleOffsets_DownScale4x4Bilinear(rd->GetWidth(), rd->GetHeight(), avSampleOffsets);
fpDownScale->mfParameter(bind, &avSampleOffsets[0].x, 4);
SetTexture(rd, rd->m_TexMan->m_Text_HDRTarget, 0, D3DTEXF_LINEAR, D3DTEXF_LINEAR, true);
}
else
{
GetSampleOffsets_DownScale4x4(rd->GetWidth(), rd->GetHeight(), avSampleOffsets);
fpDownScale->mfParameter(bind, &avSampleOffsets[0].x, 16);
if (rd->m_nHDRType == 2)
SetTexture(rd, rd->m_TexMan->m_Text_HDRTarget_Temp, 0, D3DTEXF_POINT, D3DTEXF_POINT, true);
else
SetTexture(rd, rd->m_TexMan->m_Text_HDRTarget, 0, D3DTEXF_POINT, D3DTEXF_POINT, true);
}
}
// Draw a fullscreen quad
DrawFullScreenQuad(coords);
}
fpDownScale->mfSet(false, 0);
SAFE_RELEASE(pSurfScaledScene[0]);
SAFE_RELEASE(pSurfScaledScene[1]);
SAFE_RELEASE(pSurfTempScene);
if (rd->m_bDeviceSupportsMRT)
dv->SetRenderTarget(1, NULL);
return true;
}
bool HDR_MeasureLuminance()
{
HRESULT hr = S_OK;
int i, x, y, index;
D3DXVECTOR4 avSampleOffsets[16];
CD3D9Renderer *rd = gcpRendD3D;
LPDIRECT3DDEVICE9 dv = rd->m_pd3dDevice;
CCGPShader_D3D *fpSampleAvgLum = NULL;
CCGPShader_D3D *fpResampleAvgLum = NULL;
CCGPShader_D3D *fpResampleAvgLumExp = NULL;
SCGBind *bind;
bool bResult = false;
DWORD dwCurTexture = NUM_HDR_TONEMAP_TEXTURES-1;
// Sample log average luminance
PDIRECT3DSURFACE9 apSurfToneMap[NUM_HDR_TONEMAP_TEXTURES] = {0};
// Retrieve the tonemap surfaces
for(i=0; i<NUM_HDR_TONEMAP_TEXTURES; i++)
{
apSurfToneMap[i] = GetSurfaceTP(rd->m_TexMan->m_Text_HDRToneMaps[i]);
if (!apSurfToneMap[i])
goto LCleanReturn;
}
// Initialize the sample offsets for the initial luminance pass.
float tU, tV;
tU = 1.0f / (3.0f * rd->m_TexMan->m_Text_HDRToneMaps[dwCurTexture]->m_Width);
tV = 1.0f / (3.0f * rd->m_TexMan->m_Text_HDRToneMaps[dwCurTexture]->m_Height);
index=0;
for(x=-1; x<=1; x++)
{
for(y=-1; y<=1; y++)
{
avSampleOffsets[index].x = x * tU;
avSampleOffsets[index].y = y * tV;
avSampleOffsets[index].z = 0;
avSampleOffsets[index].w = 1;
index++;
}
}
// After this pass, the CTexMan::m_Text_HDRToneMaps[NUM_TONEMAP_TEXTURES-1] texture will contain
// a scaled, grayscale copy of the HDR scene. Individual texels contain the log
// of average luminance values for points sampled on the HDR texture.
if (rd->m_bDeviceSupportsMRT)
fpSampleAvgLum = (CCGPShader_D3D *)PShaderForName(rd->m_RP.m_PS_HDRSampleAvgLum, "CGRC_HDR_SampleAvgLum_FromMRT_PS20");
else
fpSampleAvgLum = (CCGPShader_D3D *)PShaderForName(rd->m_RP.m_PS_HDRSampleAvgLum, "CGRC_HDR_SampleAvgLum_PS20");
if (!fpSampleAvgLum)
goto LCleanReturn;
fpSampleAvgLum->mfSet(true, 0);
bind = fpSampleAvgLum->mfGetParameterBind("vSampleOffsets");
assert(bind);
fpSampleAvgLum->mfParameter(bind, &avSampleOffsets[0].x, 9);
if (rd->m_bDeviceSupportsMRT)
{
SetTexture(rd, rd->m_TexMan->m_Text_HDRTargetScaled[0], 0, D3DTEXF_POINT, D3DTEXF_POINT, true);
SetTexture(rd, rd->m_TexMan->m_Text_HDRTargetScaled[1], 1, D3DTEXF_POINT, D3DTEXF_POINT, true);
}
else
SetTexture(rd, rd->m_TexMan->m_Text_HDRTargetScaled[0], 0, D3DTEXF_POINT, D3DTEXF_POINT, true);
dv->SetRenderTarget(0, apSurfToneMap[dwCurTexture]);
// Draw a fullscreen quad to sample the RT
DrawFullScreenQuad(0.0f, 0.0f, 1.0f, 1.0f);
if (rd->m_bDeviceSupportsMRT )
dv->SetTexture(1, NULL);
dwCurTexture--;
// Initialize the sample offsets for the iterative luminance passes
while(dwCurTexture > 0)
{
dv->SetRenderTarget(0, apSurfToneMap[dwCurTexture]);
if (rd->m_bDeviceSupportsFP16Filter)
{
GetSampleOffsets_DownScale4x4Bilinear(rd->m_TexMan->m_Text_HDRToneMaps[dwCurTexture+1]->m_Width, rd->m_TexMan->m_Text_HDRToneMaps[dwCurTexture+1]->m_Height, avSampleOffsets);
// Each of these passes continue to scale down the log of average
// luminance texture created above, storing intermediate results in
// HDRToneMaps[1] through HDRToneMaps[NUM_HDR_TONEMAP_TEXTURES-1].
fpResampleAvgLum = (CCGPShader_D3D *)PShaderForName(rd->m_RP.m_PS_HDRResampleAvgLum, "CGRC_HDR_ResampleAvgLum_Bilinear_PS20");
if (!fpResampleAvgLum)
goto LCleanReturn;
fpResampleAvgLum->mfSet(true, 0);
bind = fpResampleAvgLum->mfGetParameterBind("vSampleOffsets");
assert(bind);
fpResampleAvgLum->mfParameter(bind, &avSampleOffsets[0].x, 4);
dv->SetRenderTarget(0, apSurfToneMap[dwCurTexture]);
SetTexture(rd, rd->m_TexMan->m_Text_HDRToneMaps[dwCurTexture+1], 0, D3DTEXF_LINEAR, D3DTEXF_LINEAR, true);
}
else
{
GetSampleOffsets_DownScale4x4(rd->m_TexMan->m_Text_HDRToneMaps[dwCurTexture+1]->m_Width, rd->m_TexMan->m_Text_HDRToneMaps[dwCurTexture+1]->m_Height, avSampleOffsets);
// Each of these passes continue to scale down the log of average
// luminance texture created above, storing intermediate results in
// HDRToneMaps[1] through HDRToneMaps[NUM_HDR_TONEMAP_TEXTURES-1].
fpResampleAvgLum = (CCGPShader_D3D *)PShaderForName(rd->m_RP.m_PS_HDRResampleAvgLum, "CGRC_HDR_ResampleAvgLum_PS20");
if (!fpResampleAvgLum)
goto LCleanReturn;
fpResampleAvgLum->mfSet(true, 0);
bind = fpResampleAvgLum->mfGetParameterBind("vSampleOffsets");
assert(bind);
fpResampleAvgLum->mfParameter(bind, &avSampleOffsets[0].x, 16);
SetTexture(rd, rd->m_TexMan->m_Text_HDRToneMaps[dwCurTexture+1], 0, D3DTEXF_POINT, D3DTEXF_POINT, true);
}
// Draw a fullscreen quad to sample the RT
DrawFullScreenQuad(0.0f, 0.0f, 1.0f, 1.0f);
dwCurTexture--;
}
if (rd->m_bDeviceSupportsFP16Filter)
{
GetSampleOffsets_DownScale4x4Bilinear(rd->m_TexMan->m_Text_HDRToneMaps[1]->m_Width, rd->m_TexMan->m_Text_HDRToneMaps[1]->m_Height, avSampleOffsets);
// Perform the final pass of the average luminance calculation. This pass
// scales the 4x4 log of average luminance texture from above and performs
// an exp() operation to return a single texel cooresponding to the average
// luminance of the scene in CTexMan::m_Text_HDRToneMaps[0].
fpResampleAvgLumExp = (CCGPShader_D3D *)PShaderForName(rd->m_RP.m_PS_HDRResampleAvgLumExp, "CGRC_HDR_ResampleAvgLumExp_Bilinear_PS20");
if (!fpResampleAvgLumExp)
goto LCleanReturn;
fpResampleAvgLumExp->mfSet(true, 0);
bind = fpResampleAvgLumExp->mfGetParameterBind("vSampleOffsets");
assert(bind);
fpResampleAvgLumExp->mfParameter(bind, &avSampleOffsets[0].x, 4);
SetTexture(rd, rd->m_TexMan->m_Text_HDRToneMaps[1], 0, D3DTEXF_LINEAR, D3DTEXF_LINEAR, true);
}
else
{
GetSampleOffsets_DownScale4x4(rd->m_TexMan->m_Text_HDRToneMaps[1]->m_Width, rd->m_TexMan->m_Text_HDRToneMaps[1]->m_Height, avSampleOffsets);
// Each of these passes continue to scale down the log of average
// luminance texture created above, storing intermediate results in
// HDRToneMaps[1] through HDRToneMaps[NUM_HDR_TONEMAP_TEXTURES-1].
fpResampleAvgLumExp = (CCGPShader_D3D *)PShaderForName(rd->m_RP.m_PS_HDRResampleAvgLumExp, "CGRC_HDR_ResampleAvgLumExp_PS20");
if (!fpResampleAvgLumExp)
goto LCleanReturn;
fpResampleAvgLumExp->mfSet(true, 0);
bind = fpResampleAvgLumExp->mfGetParameterBind("vSampleOffsets");
assert(bind);
fpResampleAvgLumExp->mfParameter(bind, &avSampleOffsets[0].x, 16);
SetTexture(rd, rd->m_TexMan->m_Text_HDRToneMaps[1], 0, D3DTEXF_POINT, D3DTEXF_POINT, true);
}
dv->SetRenderTarget(0, apSurfToneMap[0]);
// Draw a fullscreen quad to sample the RT
DrawFullScreenQuad(0.0f, 0.0f, 1.0f, 1.0f);
bResult = true;
LCleanReturn:
for(i=0; i<NUM_HDR_TONEMAP_TEXTURES; i++)
{
SAFE_RELEASE(apSurfToneMap[i]);
}
if (fpSampleAvgLum)
fpSampleAvgLum->mfSet(false, 0);
if (fpResampleAvgLum)
fpResampleAvgLum->mfSet(false, 0);
if (fpResampleAvgLumExp)
fpResampleAvgLumExp->mfSet(false, 0);
return bResult;
}
//-----------------------------------------------------------------------------
// Name: HDR_CalculateAdaptation()
// Desc: Increment the user's adapted luminance
//-----------------------------------------------------------------------------
bool HDR_CalculateAdaptation()
{
HRESULT hr = S_OK;
CD3D9Renderer *rd = gcpRendD3D;
LPDIRECT3DDEVICE9 dv = rd->m_pd3dDevice;
CD3D9TexMan *tm = (CD3D9TexMan *)rd->m_TexMan;
CCGPShader_D3D *fpCalcAdaptedLum = NULL;
bool bResult = false;
// Swap current & last luminance
STexPic *pTexSwap = tm->m_Text_HDRAdaptedLuminanceLast;
tm->m_Text_HDRAdaptedLuminanceLast = tm->m_Text_HDRAdaptedLuminanceCur;
tm->m_Text_HDRAdaptedLuminanceCur = pTexSwap;
PDIRECT3DSURFACE9 pSurfAdaptedLum = GetSurfaceTP(tm->m_Text_HDRAdaptedLuminanceCur);
if(!pSurfAdaptedLum)
return false;
// This simulates the light adaptation that occurs when moving from a
// dark area to a bright area, or vice versa. The g_pTexAdaptedLuminance
// texture stores a single texel cooresponding to the user's adapted
// level.
fpCalcAdaptedLum = (CCGPShader_D3D *)PShaderForName(rd->m_RP.m_PS_HDRCalcAdaptedLum, "CGRC_HDR_CalculateAdaptedLum_PS20");
if (!fpCalcAdaptedLum)
goto LCleanReturn;
fpCalcAdaptedLum->mfSet(true, 0);
float v[4];
v[0] = iTimer->GetFrameTime();
v[1] = v[2] = v[3] = 0;
fpCalcAdaptedLum->mfParameter4f("fElapsedTime", v);
dv->SetRenderTarget(0, pSurfAdaptedLum);
SetTexture(rd, tm->m_Text_HDRAdaptedLuminanceLast, 0, D3DTEXF_POINT, D3DTEXF_POINT, true);
SetTexture(rd, tm->m_Text_HDRToneMaps[0], 1, D3DTEXF_POINT, D3DTEXF_POINT, true);
// Draw a fullscreen quad to sample the RT
DrawFullScreenQuad(0.0f, 0.0f, 1.0f, 1.0f);
bResult = true;
LCleanReturn:
if (fpCalcAdaptedLum)
fpCalcAdaptedLum->mfSet(false, 0);
rd->EF_SelectTMU(0);
SAFE_RELEASE(pSurfAdaptedLum);
return bResult;
}
//-----------------------------------------------------------------------------
// Name: SceneScaled_To_BrightPass
// Desc: Run the bright-pass filter on CTexman::m_Text_HDRTargetScaled and place the result
// in CTexMan::m_Text_HDRBrightPass
//-----------------------------------------------------------------------------
bool HDR_SceneScaledToBrightPass()
{
HRESULT hr = S_OK;
CD3D9Renderer *rd = gcpRendD3D;
LPDIRECT3DDEVICE9 dv = rd->m_pd3dDevice;
CD3D9TexMan *tm = (CD3D9TexMan *)rd->m_TexMan;
CCGPShader_D3D *fpBrightPassFilter = NULL;
bool bResult = false;
// Get the new render target surface
PDIRECT3DSURFACE9 pSurfBrightPass = GetSurfaceTP(tm->m_Text_HDRBrightPass);
if(!pSurfBrightPass)
return false;
// clear destination surface
dv->ColorFill(pSurfBrightPass, NULL, D3DCOLOR_ARGB(0, 0, 0, 0));
// Get the rectangle describing the sampled portion of the source texture.
// Decrease the rectangle to adjust for the single pixel black border.
RECT rectSrc;
GetTextureRect(tm->m_Text_HDRTargetScaled[0], &rectSrc);
InflateRect(&rectSrc, -1, -1);
// Get the destination rectangle.
// Decrease the rectangle to adjust for the single pixel black border.
RECT rectDest;
GetTextureRect(tm->m_Text_HDRBrightPass, &rectDest);
InflateRect(&rectDest, -1, -1);
// Get the correct texture coordinates to apply to the rendered quad in order
// to sample from the source rectangle and render into the destination rectangle
CoordRect coords;
GetTextureCoords(tm->m_Text_HDRTargetScaled[0], &rectSrc, tm->m_Text_HDRBrightPass, &rectDest, &coords);
// The bright-pass filter removes everything from the scene except lights and
// bright reflections
if (rd->m_bDeviceSupportsMRT)
fpBrightPassFilter = (CCGPShader_D3D *)PShaderForName(rd->m_RP.m_PS_HDRBrightPassFilter, "CGRC_HDR_BrightPassFilter_FromMRT_PS20");
else
fpBrightPassFilter = (CCGPShader_D3D *)PShaderForName(rd->m_RP.m_PS_HDRBrightPassFilter, "CGRC_HDR_BrightPassFilter_PS20");
if (!fpBrightPassFilter)
goto LCleanReturn;
fpBrightPassFilter->mfSet(true, 0);
float v[4];
v[0] = CRenderer::CV_r_hdrlevel;
v[1] = CRenderer::CV_r_hdrbrightoffset;
v[2] = CRenderer::CV_r_hdrbrightthreshold;
v[3] = 0;
fpBrightPassFilter->mfParameter4f("Params", v);
dv->SetRenderTarget(0, pSurfBrightPass);
if (rd->m_bDeviceSupportsMRT)
{
SetTexture(rd, tm->m_Text_HDRTargetScaled[0], 0, D3DTEXF_POINT, D3DTEXF_POINT, true);
SetTexture(rd, tm->m_Text_HDRTargetScaled[1], 1, D3DTEXF_POINT, D3DTEXF_POINT, true);
SetTexture(rd, tm->m_Text_HDRAdaptedLuminanceCur, 2, D3DTEXF_POINT, D3DTEXF_POINT, true);
}
else
{
SetTexture(rd, tm->m_Text_HDRTargetScaled[0], 0, D3DTEXF_POINT, D3DTEXF_POINT, true);
SetTexture(rd, tm->m_Text_HDRAdaptedLuminanceCur, 1, D3DTEXF_POINT, D3DTEXF_POINT, true);
}
dv->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE);
dv->SetScissorRect(&rectDest);
// Draw a fullscreen quad to sample the RT
DrawFullScreenQuad(coords);
dv->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
bResult = true;
LCleanReturn:
SAFE_RELEASE(pSurfBrightPass);
rd->EF_SelectTMU(0);
if (fpBrightPassFilter)
fpBrightPassFilter->mfSet(false, 0);
return bResult;
}
//-----------------------------------------------------------------------------
// Name: HDR_BrightPass_To_StarSource
// Desc: Perform a 5x5 gaussian blur on g_pTexBrightPass and place the result
// in g_pTexStarSource. The bright-pass filtered image is blurred before
// being used for star operations to avoid aliasing artifacts.
//-----------------------------------------------------------------------------
bool HDR_BrightPassToStarSource()
{
HRESULT hr = S_OK;
CD3D9Renderer *rd = gcpRendD3D;
LPDIRECT3DDEVICE9 dv = rd->m_pd3dDevice;
CD3D9TexMan *tm = (CD3D9TexMan *)rd->m_TexMan;
CCGPShader_D3D *fpGaussBlur5x5 = NULL;
bool bResult = false;
SCGBind *bind = NULL;
D3DXVECTOR4 avSampleOffsets[16];
D3DXVECTOR4 avSampleWeights[16];
// Get the new render target surface
PDIRECT3DSURFACE9 pSurfStarSource = GetSurfaceTP(tm->m_Text_HDRStarSource);
if(!pSurfStarSource)
return false;
// clear destination surface
dv->ColorFill(pSurfStarSource, NULL, D3DCOLOR_ARGB(0, 0, 0, 0));
// Get the destination rectangle.
// Decrease the rectangle to adjust for the single pixel black border.
RECT rectDest;
GetTextureRect(tm->m_Text_HDRStarSource, &rectDest);
InflateRect(&rectDest, -1, -1);
// Get the correct texture coordinates to apply to the rendered quad in order
// to sample from the source rectangle and render into the destination rectangle
CoordRect coords;
GetTextureCoords(tm->m_Text_HDRBrightPass, NULL, tm->m_Text_HDRStarSource, &rectDest, &coords);
// The gaussian blur smooths out rough edges to avoid aliasing effects
// when the star effect is run
if (rd->m_bDeviceSupportsFP16Filter)
{
GetSampleOffsets_GaussBlur5x5Bilinear(tm->m_Text_HDRBrightPass->m_Width, tm->m_Text_HDRBrightPass->m_Height, avSampleOffsets, avSampleWeights, 1.0f);
fpGaussBlur5x5 = (CCGPShader_D3D *)PShaderForName(rd->m_RP.m_PS_HDRGaussBlur5x5_Bilinear, "CGRC_HDR_GaussBlur5x5_Bilinear_PS20");
}
else
{
GetSampleOffsets_GaussBlur5x5(tm->m_Text_HDRBrightPass->m_Width, tm->m_Text_HDRBrightPass->m_Height, avSampleOffsets, avSampleWeights, 1.0f);
fpGaussBlur5x5 = (CCGPShader_D3D *)PShaderForName(rd->m_RP.m_PS_HDRGaussBlur5x5, "CGRC_HDR_GaussBlur5x5_PS20");
}
if (!fpGaussBlur5x5)
goto LCleanReturn;
fpGaussBlur5x5->mfSet(true, 0);
bind = fpGaussBlur5x5->mfGetParameterBind("vSampleOffsets");
assert(bind);
if (rd->m_bDeviceSupportsFP16Filter)
fpGaussBlur5x5->mfParameter(bind, &avSampleOffsets[0].x, 9);
else
fpGaussBlur5x5->mfParameter(bind, &avSampleOffsets[0].x, 13);
bind = fpGaussBlur5x5->mfGetParameterBind("vSampleWeights");
assert(bind);
if (rd->m_bDeviceSupportsFP16Filter)
fpGaussBlur5x5->mfParameter(bind, &avSampleWeights[0].x, 9);
else
fpGaussBlur5x5->mfParameter(bind, &avSampleWeights[0].x, 13);
dv->SetRenderTarget(0, pSurfStarSource);
if (rd->m_bDeviceSupportsFP16Filter)
SetTexture(rd, tm->m_Text_HDRBrightPass, 0, D3DTEXF_LINEAR, D3DTEXF_LINEAR, true);
else
SetTexture(rd, tm->m_Text_HDRBrightPass, 0, D3DTEXF_POINT, D3DTEXF_POINT, true);
dv->SetScissorRect(&rectDest);
dv->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE);
// Draw a fullscreen quad
DrawFullScreenQuad(coords);
dv->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
bResult = true;
LCleanReturn:
SAFE_RELEASE(pSurfStarSource);
rd->EF_SelectTMU(0);
if (fpGaussBlur5x5)
fpGaussBlur5x5->mfSet(false, 0);
return bResult;
}
//-----------------------------------------------------------------------------
// Name: HDR_StarSource_To_BloomSource
// Desc: Scale down g_pTexStarSource by 1/2 x 1/2 and place the result in
// CTexMan::m_Text_HDRBloomSource
//-----------------------------------------------------------------------------
bool HDR_StarSourceToBloomSource()
{
HRESULT hr = S_OK;
CD3D9Renderer *rd = gcpRendD3D;
LPDIRECT3DDEVICE9 dv = rd->m_pd3dDevice;
CD3D9TexMan *tm = (CD3D9TexMan *)rd->m_TexMan;
CCGPShader_D3D *fpDownScale2x2 = NULL;
bool bResult = false;
SCGBind *bind = NULL;
D3DXVECTOR4 avSampleOffsets[4];
// Get the new render target surface
PDIRECT3DSURFACE9 pSurfBloomSource = GetSurfaceTP(tm->m_Text_HDRBloomSource);
if(!pSurfBloomSource)
return false;
// clear destination surface
dv->ColorFill(pSurfBloomSource, NULL, D3DCOLOR_ARGB(0, 0, 0, 0));
// Get the rectangle describing the sampled portion of the source texture.
// Decrease the rectangle to adjust for the single pixel black border.
RECT rectSrc;
GetTextureRect(tm->m_Text_HDRStarSource, &rectSrc);
InflateRect(&rectSrc, -1, -1);
// Get the destination rectangle.
// Decrease the rectangle to adjust for the single pixel black border.
RECT rectDest;
GetTextureRect(tm->m_Text_HDRBloomSource, &rectDest);
InflateRect(&rectDest, -1, -1);
// Get the correct texture coordinates to apply to the rendered quad in order
// to sample from the source rectangle and render into the destination rectangle
CoordRect coords;
GetTextureCoords(tm->m_Text_HDRStarSource, &rectSrc, tm->m_Text_HDRBloomSource, &rectDest, &coords);
if (rd->m_bDeviceSupportsFP16Filter)
{
GetSampleOffsets_DownScale2x2Bilinear(tm->m_Text_HDRBrightPass->m_Width, tm->m_Text_HDRBrightPass->m_Height, avSampleOffsets);
fpDownScale2x2 = (CCGPShader_D3D *)PShaderForName(rd->m_RP.m_PS_HDRDownScale2x2, "CGRC_HDR_DownScale2x2_Bilinear_PS20");
}
else
{
GetSampleOffsets_DownScale2x2(tm->m_Text_HDRBrightPass->m_Width, tm->m_Text_HDRBrightPass->m_Height, avSampleOffsets);
fpDownScale2x2 = (CCGPShader_D3D *)PShaderForName(rd->m_RP.m_PS_HDRDownScale2x2, "CGRC_HDR_DownScale2x2_PS20");
}
// Create an exact 1/2 x 1/2 copy of the source texture
if (!fpDownScale2x2)
goto LCleanReturn;
fpDownScale2x2->mfSet(true, 0);
bind = fpDownScale2x2->mfGetParameterBind("vSampleOffsets");
assert(bind);
if (rd->m_bDeviceSupportsFP16Filter)
fpDownScale2x2->mfParameter(bind, &avSampleOffsets[0].x, 1);
else
fpDownScale2x2->mfParameter(bind, &avSampleOffsets[0].x, 4);
dv->SetRenderTarget(0, pSurfBloomSource);
if (rd->m_bDeviceSupportsFP16Filter)
SetTexture(rd, tm->m_Text_HDRStarSource, 0, D3DTEXF_LINEAR, D3DTEXF_LINEAR, true);
else
SetTexture(rd, tm->m_Text_HDRStarSource, 0, D3DTEXF_POINT, D3DTEXF_POINT, true);
dv->SetScissorRect(&rectDest);
dv->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE);
// Draw a fullscreen quad
DrawFullScreenQuad(coords);
dv->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
bResult = true;
LCleanReturn:
SAFE_RELEASE(pSurfBloomSource);
if (fpDownScale2x2)
fpDownScale2x2->mfSet(false, 0);
return bResult;
}
//-----------------------------------------------------------------------------
// Name: HDR_RenderBloom()
// Desc: Render the blooming effect
//-----------------------------------------------------------------------------
bool HDR_RenderBloom()
{
HRESULT hr = S_OK;
CD3D9Renderer *rd = gcpRendD3D;
LPDIRECT3DDEVICE9 dv = rd->m_pd3dDevice;
CD3D9TexMan *tm = (CD3D9TexMan *)rd->m_TexMan;
CCGPShader_D3D *fpGaussBlur5x5 = NULL;
CCGPShader_D3D *fpBloom = NULL;
bool bResult = false;
SCGBind *bind = NULL;
int i;
D3DXVECTOR4 avSampleOffsets[16];
FLOAT afSampleOffsets[16];
D3DXVECTOR4 avSampleWeights[16];
PDIRECT3DSURFACE9 pSurfScaledHDR0 = GetSurfaceTP(tm->m_Text_HDRTargetScaled[0]);
PDIRECT3DSURFACE9 pSurfBloom = GetSurfaceTP(tm->m_Text_HDRBloomMaps[0]);
PDIRECT3DSURFACE9 pSurfHDR = GetSurfaceTP(tm->m_Text_HDRTarget);
PDIRECT3DSURFACE9 pSurfTempBloom = GetSurfaceTP(tm->m_Text_HDRBloomMaps[1]);
PDIRECT3DSURFACE9 pSurfBloomSource = GetSurfaceTP(tm->m_Text_HDRBloomMaps[2]);
// Clear the bloom texture
dv->ColorFill(pSurfBloom, NULL, D3DCOLOR_ARGB(0, 0, 0, 0));
if (g_GlareDef.m_fGlareLuminance <= 0.0f || g_GlareDef.m_fBloomLuminance <= 0.0f)
{
hr = S_OK;
goto LCleanReturn;
}
RECT rectSrc;
GetTextureRect(tm->m_Text_HDRBloomSource, &rectSrc);
InflateRect(&rectSrc, -1, -1);
RECT rectDest;
GetTextureRect(tm->m_Text_HDRBloomMaps[2], &rectDest);
InflateRect(&rectDest, -1, -1);
CoordRect coords;
GetTextureCoords(tm->m_Text_HDRBloomSource, &rectSrc, tm->m_Text_HDRBloomMaps[2], &rectDest, &coords);
if (rd->m_bDeviceSupportsFP16Filter)
{
hr = GetSampleOffsets_GaussBlur5x5Bilinear(tm->m_Text_HDRBloomSource->m_Width, tm->m_Text_HDRBloomSource->m_Height, avSampleOffsets, avSampleWeights, 1.0f);
fpGaussBlur5x5 = (CCGPShader_D3D *)PShaderForName(rd->m_RP.m_PS_HDRGaussBlur5x5_Bilinear, "CGRC_HDR_GaussBlur5x5_Bilinear_PS20");
}
else
{
hr = GetSampleOffsets_GaussBlur5x5(tm->m_Text_HDRBloomSource->m_Width, tm->m_Text_HDRBloomSource->m_Height, avSampleOffsets, avSampleWeights, 1.0f);
fpGaussBlur5x5 = (CCGPShader_D3D *)PShaderForName(rd->m_RP.m_PS_HDRGaussBlur5x5, "CGRC_HDR_GaussBlur5x5_PS20");
}
if (!fpGaussBlur5x5)
goto LCleanReturn;
fpGaussBlur5x5->mfSet(true, 0);
bind = fpGaussBlur5x5->mfGetParameterBind("vSampleOffsets");
assert(bind);
if (rd->m_bDeviceSupportsFP16Filter)
fpGaussBlur5x5->mfParameter(bind, &avSampleOffsets[0].x, 9);
else
fpGaussBlur5x5->mfParameter(bind, &avSampleOffsets[0].x, 13);
bind = fpGaussBlur5x5->mfGetParameterBind("vSampleWeights");
assert(bind);
if (rd->m_bDeviceSupportsFP16Filter)
fpGaussBlur5x5->mfParameter(bind, &avSampleWeights[0].x, 9);
else
fpGaussBlur5x5->mfParameter(bind, &avSampleWeights[0].x, 13);
dv->SetRenderTarget(0, pSurfBloomSource);
if (rd->m_bDeviceSupportsFP16Filter)
SetTexture(rd, tm->m_Text_HDRBloomSource, 0, D3DTEXF_LINEAR, D3DTEXF_LINEAR, true);
else
SetTexture(rd, tm->m_Text_HDRBloomSource, 0, D3DTEXF_POINT, D3DTEXF_POINT, true);
dv->SetScissorRect(&rectDest);
dv->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE);
// Draw a fullscreen quad to sample the RT
DrawFullScreenQuad(coords);
dv->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
int n;
if (rd->m_bDeviceSupportsFP16Filter)
{
hr = GetSampleOffsets_BloomBilinear(tm->m_Text_HDRBloomMaps[2]->m_Width, afSampleOffsets, avSampleWeights, 3.0f, 2.0f);
n = 8;
fpBloom = (CCGPShader_D3D *)PShaderForName(rd->m_RP.m_PS_HDRBloom, "CGRC_HDR_Bloom_Bilinear_PS20");
}
else
{
hr = GetSampleOffsets_Bloom(tm->m_Text_HDRBloomMaps[2]->m_Width, afSampleOffsets, avSampleWeights, 3.0f, 2.0f);
n = 16;
fpBloom = (CCGPShader_D3D *)PShaderForName(rd->m_RP.m_PS_HDRBloom, "CGRC_HDR_Bloom_PS20");
}
for(i=0; i<n; i++ )
{
avSampleOffsets[i] = D3DXVECTOR4(afSampleOffsets[i], 0.0f, 0, 1);
}
if (!fpBloom)
goto LCleanReturn;
fpBloom->mfSet(true, 0);
bind = fpBloom->mfGetParameterBind("vSampleOffsets");
assert(bind);
fpBloom->mfParameter(bind, &avSampleOffsets[0].x, n);
bind = fpBloom->mfGetParameterBind("vSampleWeights");
assert(bind);
fpBloom->mfParameter(bind, &avSampleWeights[0].x, n);
dv->SetRenderTarget(0, pSurfTempBloom);
if (rd->m_bDeviceSupportsFP16Filter)
SetTexture(rd, tm->m_Text_HDRBloomMaps[2], 0, D3DTEXF_LINEAR, D3DTEXF_LINEAR, true);
else
SetTexture(rd, tm->m_Text_HDRBloomMaps[2], 0, D3DTEXF_POINT, D3DTEXF_POINT, true);
dv->SetScissorRect(&rectDest);
dv->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE);
// Draw a fullscreen quad to sample the RT
DrawFullScreenQuad( coords );
dv->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
if (rd->m_bDeviceSupportsFP16Filter)
{
hr = GetSampleOffsets_BloomBilinear(tm->m_Text_HDRBloomMaps[1]->m_Width, afSampleOffsets, avSampleWeights, 3.0f, 2.0f);
n = 8;
}
else
{
hr = GetSampleOffsets_Bloom(tm->m_Text_HDRBloomMaps[1]->m_Width, afSampleOffsets, avSampleWeights, 3.0f, 2.0f);
n = 16;
}
for(i=0; i<n; i++ )
{
avSampleOffsets[i] = D3DXVECTOR4(afSampleOffsets[i], 0.0f, 0, 1);
}
GetTextureRect(tm->m_Text_HDRBloomMaps[1], &rectSrc);
InflateRect(&rectSrc, -1, -1);
GetTextureCoords(tm->m_Text_HDRBloomMaps[1], &rectSrc, tm->m_Text_HDRBloomMaps[0], NULL, &coords);
bind = fpBloom->mfGetParameterBind("vSampleOffsets");
assert(bind);
fpBloom->mfParameter(bind, &avSampleOffsets[0].x, n);
bind = fpBloom->mfGetParameterBind("vSampleWeights");
assert(bind);
fpBloom->mfParameter(bind, &avSampleWeights[0].x, n);
dv->SetRenderTarget(0, pSurfBloom);
if (rd->m_bDeviceSupportsFP16Filter)
SetTexture(rd, tm->m_Text_HDRBloomMaps[1], 0, D3DTEXF_LINEAR, D3DTEXF_LINEAR, true);
else
SetTexture(rd, tm->m_Text_HDRBloomMaps[1], 0, D3DTEXF_POINT, D3DTEXF_POINT, true);
// Draw a fullscreen quad to sample the RT
DrawFullScreenQuad(coords);
bResult = true;
LCleanReturn:
SAFE_RELEASE(pSurfBloomSource);
SAFE_RELEASE(pSurfTempBloom);
SAFE_RELEASE(pSurfBloom);
SAFE_RELEASE(pSurfHDR);
SAFE_RELEASE(pSurfScaledHDR0);
return bResult;
}
//-----------------------------------------------------------------------------
// Name: HDR_RenderStar()
// Desc: Render the blooming effect
//-----------------------------------------------------------------------------
bool HDR_RenderStar()
{
HRESULT hr = S_OK;
CD3D9Renderer *rd = gcpRendD3D;
LPDIRECT3DDEVICE9 dv = rd->m_pd3dDevice;
CD3D9TexMan *tm = (CD3D9TexMan *)rd->m_TexMan;
CCGPShader_D3D *fpStar = NULL;
CCGPShader_D3D *fpMergeTextures = NULL;
bool bResult = false;
SCGBind *bind = NULL;
D3DXVECTOR4 avSampleOffsets[16];
D3DXVECTOR4 avSampleWeights[16];
int i, d, p, s; // Loop variables
LPDIRECT3DSURFACE9 pSurfStar0 = GetSurfaceTP(tm->m_Text_HDRStarMaps[0][0]);
if(!pSurfStar0)
return false;
LPDIRECT3DSURFACE9 pSurfStar1 = GetSurfaceTP(tm->m_Text_HDRStarMaps[0][1]);
// Clear the star texture
dv->ColorFill(pSurfStar0, NULL, D3DCOLOR_ARGB(0, 0, 0, 0));
SAFE_RELEASE(pSurfStar0);
if (pSurfStar1)
{
dv->ColorFill(pSurfStar1, NULL, D3DCOLOR_ARGB(0, 0, 0, 0));
SAFE_RELEASE(pSurfStar1);
}
// Avoid rendering the star if it's not being used in the current glare
if(g_GlareDef.m_fGlareLuminance <= 0.0f || g_GlareDef.m_fStarLuminance <= 0.0f)
return true;
// Initialize the constants used during the effect
const CStarDef& starDef = g_GlareDef.m_starDef;
const float fTanFoV = atanf(D3DX_PI/8) ;
const D3DXVECTOR4 vWhite( 1.0f, 1.0f, 1.0f, 1.0f );
static const s_maxPasses = 3 ;
static const int nSamples = 8 ;
static D3DXVECTOR4 s_aaColor[s_maxPasses][8] ;
static const D3DXCOLOR s_colorWhite(0.63f, 0.63f, 0.63f, 0.0f) ;
rd->EF_SetState(GS_NODEPTHTEST);
PDIRECT3DSURFACE9 pSurfDest[2] = {NULL, NULL};
// Set aside all the star texture surfaces as a convenience
PDIRECT3DSURFACE9 apSurfStar[NUM_HDR_STAR_TEXTURES][2] = {0};
for(i=0; i<NUM_HDR_STAR_TEXTURES; i++)
{
apSurfStar[i][0] = GetSurfaceTP(tm->m_Text_HDRStarMaps[i][0]);
if(!apSurfStar[i][0])
goto LCleanReturn;
if (rd->m_bDeviceSupportsMRT)
{
apSurfStar[i][1] = GetSurfaceTP(tm->m_Text_HDRStarMaps[i][1]);
if(!apSurfStar[i][1])
goto LCleanReturn;
}
}
float srcW;
srcW = (FLOAT)tm->m_Text_HDRStarSource->m_Width;
float srcH;
srcH= (FLOAT)tm->m_Text_HDRStarSource->m_Height;
for (p=0; p<s_maxPasses; p++)
{
float ratio;
ratio = (float)(p + 1) / (float)s_maxPasses;
for (s=0; s<nSamples; s++)
{
D3DXCOLOR chromaticAberrColor ;
D3DXColorLerp(&chromaticAberrColor, &( CStarDef::GetChromaticAberrationColor(s) ), &s_colorWhite, ratio);
D3DXColorLerp( (D3DXCOLOR*)&(s_aaColor[p][s]), &s_colorWhite, &chromaticAberrColor, g_GlareDef.m_fChromaticAberration);
}
}
float radOffset;
radOffset = g_GlareDef.m_fStarInclination + starDef.m_fInclination ;
STexPic *pTexSource[2];
// Direction loop
for (d=0; d<starDef.m_nStarLines; d++)
{
CONST STARLINE& starLine = starDef.m_pStarLine[d];
pTexSource[0] = tm->m_Text_HDRStarSource;
pTexSource[1] = NULL;
float rad;
rad = radOffset + starLine.fInclination;
float sn, cs;
sn = sinf(rad), cs = cosf(rad);
D3DXVECTOR2 vtStepUV;
vtStepUV.x = sn / srcW * starLine.fSampleLength;
vtStepUV.y = cs / srcH * starLine.fSampleLength;
float attnPowScale;
attnPowScale = (fTanFoV + 0.1f) * 1.0f * (160.0f + 120.0f) / (srcW + srcH) * 1.2f;
// 1 direction expansion loop
rd->EF_SetState(GS_NODEPTHTEST);
int iWorkTexture;
iWorkTexture = 1 ;
for (p=0; p<starLine.nPasses; p++)
{
if (p == starLine.nPasses-1)
{
// Last pass move to other work buffer
pSurfDest[0] = apSurfStar[d+4][0];
pSurfDest[1] = apSurfStar[d+4][1];
}
else
{
pSurfDest[0] = apSurfStar[iWorkTexture][0];
pSurfDest[1] = apSurfStar[iWorkTexture][1];
}
// Sampling configration for each stage
for (i=0; i<nSamples; i++)
{
float lum;
lum = powf(starLine.fAttenuation, attnPowScale * i);
avSampleWeights[i] = s_aaColor[starLine.nPasses - 1 - p][i] * lum * (p+1.0f) * 0.5f;
// Offset of sampling coordinate
avSampleOffsets[i].x = vtStepUV.x * i;
avSampleOffsets[i].y = vtStepUV.y * i;
avSampleOffsets[i].z = 0;
avSampleOffsets[i].w = 1;
if (fabs(avSampleOffsets[i].x) >= 0.9f || fabs(avSampleOffsets[i].y) >= 0.9f)
{
avSampleOffsets[i].x = 0.0f;
avSampleOffsets[i].y = 0.0f;
avSampleWeights[i] *= 0.0f;
}
}
D3DSURFACE_DESC srcDesc;
LPDIRECT3DTEXTURE9 pTex = (LPDIRECT3DTEXTURE9)pTexSource[0]->m_RefTex.m_VidTex;
pTex->GetLevelDesc(0, &srcDesc);
int nBitPlanes = 1;
BOOL bSplitOutput = FALSE;
if (rd->m_bDeviceSupportsMRT && srcDesc.Format==D3DFMT_G16R16F)
{
fpStar = (CCGPShader_D3D *)PShaderForName(rd->m_RP.m_PS_HDRStar, "CGRC_HDR_Star_PS20");
nBitPlanes = 2;
bSplitOutput = FALSE;
}
else
if (rd->m_bDeviceSupportsMRT && (srcDesc.Format==D3DFMT_A8R8G8B8))
{
fpStar = (CCGPShader_D3D *)PShaderForName(rd->m_RP.m_PS_HDRStar_MRT, "CGRC_HDR_Star_MRT_PS20");
nBitPlanes = 1;
bSplitOutput = TRUE;
}
else
{
fpStar = (CCGPShader_D3D *)PShaderForName(rd->m_RP.m_PS_HDRStar, "CGRC_HDR_Star_PS20");
nBitPlanes = 1;
bSplitOutput = FALSE;
}
if (!fpStar)
goto LCleanReturn;
fpStar->mfSet(true, 0);
bind = fpStar->mfGetParameterBind("vSampleOffsets");
assert(bind);
fpStar->mfParameter(bind, &avSampleOffsets[0].x, nSamples);
for (int iBitPlane=0; iBitPlane<nBitPlanes; iBitPlane++)
{
// mux weights for multi-planar outputs
for ( int s=0; s<nSamples; s++)
{
D3DXVECTOR4 weight = avSampleWeights[s];
if ( iBitPlane&1 )
{
avSampleWeights[s].x = weight.z;
avSampleWeights[s].y = weight.w;
avSampleWeights[s].z = weight.x;
avSampleWeights[s].w = weight.y;
}
}
bind = fpStar->mfGetParameterBind("vSampleWeights");
assert(bind);
fpStar->mfParameter(bind, &avSampleWeights[0].x, nSamples);
dv->SetRenderTarget( 0, pSurfDest[iBitPlane] );
SetTexture(rd, pTexSource[iBitPlane], 0, D3DTEXF_LINEAR, D3DTEXF_LINEAR, true);
if (bSplitOutput)
dv->SetRenderTarget(1, pSurfDest[1]);
// Draw a fullscreen quad to sample the RT
DrawFullScreenQuad(0.0f, 0.0f, 1.0f, 1.0f);
}
if (bSplitOutput)
dv->SetRenderTarget(1, NULL);
// Setup next expansion
vtStepUV *= nSamples ;
attnPowScale *= nSamples ;
// Set the work drawn just before to next texture source.
pTexSource[0] = tm->m_Text_HDRStarMaps[iWorkTexture][0];
pTexSource[1] = tm->m_Text_HDRStarMaps[iWorkTexture][1];
iWorkTexture += 1;
if (iWorkTexture > 2)
iWorkTexture = 1;
}
}
pSurfDest[0] = apSurfStar[0][0];
pSurfDest[1] = apSurfStar[0][1];
int nBitPlanes = (rd->m_bDeviceSupportsMRT) ? 2 : 1;
for (int iBitPlane=0; iBitPlane<nBitPlanes; iBitPlane++)
{
for(i=0; i<starDef.m_nStarLines; i++)
{
SetTexture(rd, tm->m_Text_HDRStarMaps[i+4][iBitPlane], i, D3DTEXF_LINEAR, D3DTEXF_LINEAR, true);
avSampleWeights[i] = vWhite * 1.0f / (FLOAT) starDef.m_nStarLines;
}
CHAR strTechnique[256];
_snprintf(strTechnique, 256, "CGRC_HDR_MergeTextures_%d_PS20", starDef.m_nStarLines);
strTechnique[255] = 0;
fpMergeTextures = (CCGPShader_D3D *)PShaderForName(rd->m_RP.m_PS_HDRMergeTextures[starDef.m_nStarLines], strTechnique);
if (!fpMergeTextures)
goto LCleanReturn;
fpMergeTextures->mfSet(true, 0);
bind = fpMergeTextures->mfGetParameterBind("vSampleWeights");
assert(bind);
fpMergeTextures->mfParameter(bind, &avSampleWeights[0].x, starDef.m_nStarLines);
dv->SetRenderTarget(0, pSurfDest[iBitPlane]);
// Draw a fullscreen quad to sample the RT
DrawFullScreenQuad(0.0f, 0.0f, 1.0f, 1.0f);
}
bResult = true;
LCleanReturn:
for (int iPlane=0; iPlane<2; iPlane++)
{
for(i=0; i<NUM_HDR_STAR_TEXTURES; i++)
{
SAFE_RELEASE(apSurfStar[i][iPlane]);
}
}
rd->EF_SelectTMU(0);
if (fpMergeTextures)
fpMergeTextures->mfSet(false, 0);
return bResult;
}
bool HDR_RenderFinalScene()
{
HRESULT hr = S_OK;
CD3D9Renderer *rd = gcpRendD3D;
LPDIRECT3DDEVICE9 dv = rd->m_pd3dDevice;
CD3D9TexMan *tm = (CD3D9TexMan *)rd->m_TexMan;
CCGPShader_D3D *fpFinalScene = NULL;
bool bResult = false;
// Draw the high dynamic range scene texture to the low dynamic range
// back buffer. As part of this final pass, the scene will be tone-mapped
// using the user's current adapted luminance, blue shift will occur
// if the scene is determined to be very dark, and the post-process lighting
// effect textures will be added to the scene.
if (rd->m_bDeviceSupportsMRT)
fpFinalScene = (CCGPShader_D3D *)PShaderForName(rd->m_RP.m_PS_HDRFinalScene, "CGRC_HDR_FinalScene_BlueShift_ToneMap_FromMRT_PS20");
else
fpFinalScene = (CCGPShader_D3D *)PShaderForName(rd->m_RP.m_PS_HDRFinalScene, "CGRC_HDR_FinalScene_BlueShift_ToneMap_PS20");
if (!fpFinalScene)
return false;
fpFinalScene->mfSet(true, 0);
float fKeyValue = CRenderer::CV_r_hdrlevel;
float fBloomScale = 1.0f;
float fStarScale = 0.5f;
float v[4];
v[0] = fStarScale;
v[1] = fBloomScale;
v[2] = 0;
v[3] = fKeyValue;
fpFinalScene->mfParameter4f("Params", v);
dv->SetRenderTarget(0, rd->mfGetBackSurface());
if (rd->m_bDeviceSupportsMRT)
{
SetTexture(rd, tm->m_Text_HDRTarget, 0, D3DTEXF_POINT, D3DTEXF_POINT, true);
SetTexture(rd, tm->m_Text_HDRBloomMaps[0], 1, D3DTEXF_LINEAR, D3DTEXF_LINEAR, true);
SetTexture(rd, tm->m_Text_HDRStarMaps[0][0], 2, D3DTEXF_LINEAR, D3DTEXF_LINEAR, true);
SetTexture(rd, tm->m_Text_HDRStarMaps[0][1], 3, D3DTEXF_LINEAR, D3DTEXF_LINEAR, true);
SetTexture(rd, tm->m_Text_HDRAdaptedLuminanceCur, 4, D3DTEXF_POINT, D3DTEXF_POINT, true);
}
else
{
if (rd->m_nHDRType == 2)
SetTexture(rd, tm->m_Text_HDRTarget_Temp, 0, D3DTEXF_POINT, D3DTEXF_POINT, true);
else
SetTexture(rd, tm->m_Text_HDRTarget, 0, D3DTEXF_POINT, D3DTEXF_POINT, true);
SetTexture(rd, tm->m_Text_HDRBloomMaps[0], 1, D3DTEXF_LINEAR, D3DTEXF_LINEAR, true);
SetTexture(rd, tm->m_Text_HDRStarMaps[0][0], 2, D3DTEXF_LINEAR, D3DTEXF_LINEAR, true);
SetTexture(rd, tm->m_Text_HDRAdaptedLuminanceCur, 3, D3DTEXF_POINT, D3DTEXF_POINT, true);
}
DrawFullScreenQuad( 0.0f, 0.0f, 1.0f, 1.0f );
fpFinalScene->mfSet(false, 0);
rd->EF_SelectTMU(0);
return true;
}
void HDR_DrawDebug()
{
#ifdef USE_HDR
if (!CRenderer::CV_r_hdrrendering)
return;
#endif
CD3D9Renderer *rd = gcpRendD3D;
rd->EF_SetState(GS_NODEPTHTEST);
int iTmpX, iTmpY, iTempWidth, iTempHeight;
rd->GetViewport(&iTmpX, &iTmpY, &iTempWidth, &iTempHeight);
rd->EF_SetColorOp(eCO_MODULATE, eCO_MODULATE, DEF_TEXARG0, DEF_TEXARG0);
rd->Set2DMode(true, 1, 1);
rd->m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_POINT );
rd->m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_POINT );
CCGPShader_D3D *fpShowR = NULL;
CCGPShader_D3D *fpShowMRT = NULL;
fpShowR = (CCGPShader_D3D *)PShaderForName(rd->m_RP.m_PS_HDR_ShowR, "CGRC_HDR_ShowR_PS20");
fpShowMRT = (CCGPShader_D3D *)PShaderForName(rd->m_RP.m_PS_HDR_ShowRG_MRT, "CGRC_HDR_ShowRG_MRT_PS20");
rd->SetViewport(10, 400, 100, 100);
if (rd->m_nHDRType == 2)
rd->DrawImage(0, 0, 1, 1, rd->m_TexMan->m_Text_HDRTarget_Temp->m_Bind, 0, 1, 1, 0, 1,1,1,1);
else
rd->DrawImage(0, 0, 1, 1, rd->m_TexMan->m_Text_HDRTarget->m_Bind, 0, 1, 1, 0, 1,1,1,1);
rd->SetViewport(120, 400, 100, 100);
if (rd->m_bDeviceSupportsMRT && fpShowMRT)
{
fpShowMRT->mfSet(true, 0);
rd->EF_SelectTMU(1);
rd->m_TexMan->m_Text_HDRTargetScaled[1]->Set();
rd->EF_SelectTMU(0);
rd->DrawImage(0, 0, 1, 1, rd->m_TexMan->m_Text_HDRTargetScaled[0]->m_Bind, 0, 1, 1, 0, 1,1,1,1);
rd->EF_SelectTMU(1);
rd->SetTexture(0);
rd->EF_SelectTMU(0);
fpShowMRT->mfSet(false, 0);
}
else
rd->DrawImage(0, 0, 1, 1, rd->m_TexMan->m_Text_HDRTargetScaled[0]->m_Bind, 0, 1, 1, 0, 1,1,1,1);
if (fpShowR)
{
fpShowR->mfSet(true, 0);
rd->SetViewport(10, 510, 100, 100);
rd->DrawImage(0, 0, 1, 1, rd->m_TexMan->m_Text_HDRToneMaps[0]->m_Bind, 0, 1, 1, 0, 1,1,1,1);
rd->SetViewport(120, 510, 100, 100);
rd->DrawImage(0, 0, 1, 1, rd->m_TexMan->m_Text_HDRAdaptedLuminanceCur->m_Bind, 0, 1, 1, 0, 1,1,1,1);
fpShowR->mfSet(false, 0);
}
rd->SetViewport(230, 400, 100, 100);
rd->DrawImage(0, 0, 1, 1, rd->m_TexMan->m_Text_HDRBrightPass->m_Bind, 0, 1, 1, 0, 1,1,1,1);
rd->SetViewport(340, 400, 100, 100);
rd->DrawImage(0, 0, 1, 1, rd->m_TexMan->m_Text_HDRStarSource->m_Bind, 0, 1, 1, 0, 1,1,1,1);
rd->SetViewport(450, 400, 100, 100);
rd->DrawImage(0, 0, 1, 1, rd->m_TexMan->m_Text_HDRBloomSource->m_Bind, 0, 1, 1, 0, 1,1,1,1);
rd->SetViewport(560, 400, 100, 100);
rd->DrawImage(0, 0, 1, 1, rd->m_TexMan->m_Text_HDRBloomMaps[0]->m_Bind, 0, 1, 1, 0, 1,1,1,1);
rd->SetViewport(670, 400, 100, 100);
if (rd->m_bDeviceSupportsMRT && fpShowMRT)
{
fpShowMRT->mfSet(true, 0);
rd->EF_SelectTMU(1);
rd->m_TexMan->m_Text_HDRStarMaps[0][1]->Set();
rd->EF_SelectTMU(0);
rd->DrawImage(0, 0, 1, 1, rd->m_TexMan->m_Text_HDRStarMaps[0][0]->m_Bind, 0, 1, 1, 0, 1,1,1,1);
rd->EF_SelectTMU(1);
rd->SetTexture(0);
rd->EF_SelectTMU(0);
fpShowMRT->mfSet(false, 0);
}
else
rd->DrawImage(0, 0, 1, 1, rd->m_TexMan->m_Text_HDRStarMaps[0][0]->m_Bind, 0, 1, 1, 0, 1,1,1,1);
//rd->SetViewport(300, 210, 100, 100);
//rd->DrawImage(0, 0, 1, 1, rd->m_TexMan->m_Text_ScreenMap_HDR->m_Bind, 0, 1, 1, 0, 1,1,1,1);
rd->Set2DMode(false, 1, 1);
rd->SetViewport(iTmpX, iTmpY, iTempWidth, iTempHeight);
}
void CD3D9Renderer::EF_HDRPostProcessing()
{
static EGLARELIBTYPE seGlareType = (EGLARELIBTYPE)-1;
PROFILE_FRAME(Draw_HDR_PostProcessing);
#ifdef USE_HDR
if ((int)seGlareType != CV_r_hdrrendering)
{
if (CV_r_hdrrendering >= NUM_GLARELIBTYPES)
{
ICVar *var = iConsole->GetCVar("r_HDRRendering");
if (var)
var->Set(NUM_GLARELIBTYPES-1);
}
else
if (CV_r_hdrrendering < 0)
{
ICVar *var = iConsole->GetCVar("r_HDRRendering");
if (var)
var->Set(1);
}
seGlareType = (EGLARELIBTYPE)CV_r_hdrrendering;
g_GlareDef.Initialize(seGlareType);
}
#endif
CD3D9TexMan *tm = (CD3D9TexMan *)m_TexMan;
if (!tm->m_Text_HDRTarget)
return;
if (tm->m_Text_HDRTarget->m_Width != m_width || tm->m_Text_HDRTarget->m_Height != m_height)
tm->GenerateHDRMaps();
if( tm->m_HDR_RT_FSAA )
{
STexPic *tp = tm->m_Text_HDRTarget;
LPDIRECT3DTEXTURE9 pTexture = (LPDIRECT3DTEXTURE9)tp->m_RefTex.m_VidTex;
assert(pTexture);
LPDIRECT3DSURFACE9 pSurf;
pTexture->GetSurfaceLevel(0, &pSurf);
assert(pSurf);
HRESULT hr = m_pd3dDevice->StretchRect( tm->m_HDR_RT_FSAA, 0, pSurf, 0, D3DTEXF_NONE );
pSurf->Release();
}
bool bMeasureLuminance = true;
EF_SetState(GS_NODEPTHTEST);
D3DSetCull(eCULL_None);
CD3D9TexMan::BindNULL(1);
EF_SelectTMU(0);
m_RP.m_PersFlags &= ~(RBPF_VSNEEDSET | RBPF_PS1NEEDSET);
m_RP.m_FlagsModificators = 0;
m_RP.m_CurrentVLights = 0;
m_RP.m_FlagsPerFlush = 0;
EF_CommitShadersState();
EF_CommitVLightsState();
m_pd3dDevice->SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE);
if (m_RP.m_TexStages[0].TCIndex != 0)
{
m_RP.m_TexStages[0].TCIndex = 0;
m_pd3dDevice->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_PASSTHRU | 0);
}
EF_Scissor(false, 0, 0, 0, 0);
m_RP.m_pShader = NULL;
if (m_nHDRType == 2)
m_pd3dDevice->SetRenderTarget(1, NULL);
m_pCurBackBuffer = m_pBackBuffer;
// Create a scaled copy of the scene
HDR_SceneToSceneScaled();
// Setup tone mapping technique
if (bMeasureLuminance)
HDR_MeasureLuminance();
// Calculate the current luminance adaptation level
HDR_CalculateAdaptation();
// Now that luminance information has been gathered, the scene can be bright-pass filtered
// to remove everything except bright lights and reflections.
HDR_SceneScaledToBrightPass();
// Blur the bright-pass filtered image to create the source texture for the star effect
HDR_BrightPassToStarSource();
// Scale-down the source texture for the star effect to create the source texture
// for the bloom effect
HDR_StarSourceToBloomSource();
// Render post-process lighting effects
HDR_RenderBloom();
HDR_RenderStar();
// Render final scene to the back buffer
HDR_RenderFinalScene();
SAFE_RELEASE(m_pHDRTargetSurf);
SAFE_RELEASE(m_pHDRTargetSurf_K);
m_RP.m_PersFlags &= ~RBPF_HDR;
ResetToDefault();
}