// // // Win_HighDynamicRange.cpp // // High dynamic range effect // // #include "../server/exe_headers.h" #include "../renderer/tr_local.h" #include "glw_win_dx8.h" #include "win_local.h" #include "win_highdynamicrange.h" #include #include VVHighDynamicRange HDREffect; VVHighDynamicRange::VVHighDynamicRange() { m_bInitialized = false; m_dwHotBlurPixelShader = 0; m_dwExtractHotPixelShader = 0; } void VVHighDynamicRange::Initialize() { // Create pixel shader if(!(CreatePixelShader("D:\\base\\media\\hotblur.xpu", &m_dwHotBlurPixelShader))) return; if(!(CreatePixelShader("D:\\base\\media\\extracthot.xpu", &m_dwExtractHotPixelShader))) return; // Get size of render target LPDIRECT3DSURFACE8 pRenderTarget; glw_state->device->GetRenderTarget( &pRenderTarget ); D3DSURFACE_DESC descRenderTarget; pRenderTarget->GetDesc( &descRenderTarget ); UINT Width = descRenderTarget.Width; UINT Height = descRenderTarget.Height; D3DFORMAT Format = descRenderTarget.Format; pRenderTarget->Release(); // Create extract hot text glw_state->device->CreateTexture( Width >> 1, Height >> 1, 1, D3DUSAGE_RENDERTARGET, Format, 0, &m_rpHotImage); // Make the size a factor of 2 smaller on each axis glw_state->device->CreateTexture( Width >> 1, Height >> 2, 1, D3DUSAGE_RENDERTARGET, Format, 0, &m_rpBlur[0]); glw_state->device->CreateTexture( Width >> 2, Height >> 2, 1, D3DUSAGE_RENDERTARGET, Format, 0, &m_rpBlur[1]); // Set bloom scale m_fBloomScale = 1.00f; m_bInitialized = true; } void VVHighDynamicRange::Render() { if(!m_bInitialized) return; DWORD lighting, fog, srcblend, destblend, alphablend, zwrite, zenable; glw_state->device->GetRenderState( D3DRS_LIGHTING, &lighting ); glw_state->device->GetRenderState( D3DRS_FOGENABLE, &fog ); glw_state->device->GetRenderState( D3DRS_SRCBLEND, &srcblend ); glw_state->device->GetRenderState( D3DRS_DESTBLEND, &destblend ); glw_state->device->GetRenderState( D3DRS_ALPHABLENDENABLE, &alphablend ); glw_state->device->GetRenderState( D3DRS_ZWRITEENABLE, &zwrite ); glw_state->device->GetRenderState( D3DRS_ZENABLE, &zenable ); HotBlur(); // Blur the hot values in the backbuffer DrawHotBlur(); // Draw blurred hot values, add to scene glw_state->device->SetRenderState( D3DRS_LIGHTING, lighting ); glw_state->device->SetRenderState( D3DRS_FOGENABLE, fog ); glw_state->device->SetRenderState( D3DRS_SRCBLEND, srcblend ); glw_state->device->SetRenderState( D3DRS_DESTBLEND, destblend ); glw_state->device->SetRenderState( D3DRS_ALPHABLENDENABLE, alphablend ); glw_state->device->SetRenderState( D3DRS_ZWRITEENABLE, zwrite ); glw_state->device->SetRenderState( D3DRS_ZENABLE, zenable ); } void VVHighDynamicRange::DrawHotBlur() { if( !m_pBlur ) return; LPDIRECT3DTEXTURE8 pTexture = m_pBlur; // Get size of backbuffer LPDIRECT3DSURFACE8 pRenderTarget; glw_state->device->GetRenderTarget( &pRenderTarget ); D3DSURFACE_DESC descRenderTarget; pRenderTarget->GetDesc( &descRenderTarget ); UINT Width = descRenderTarget.Width; UINT Height = descRenderTarget.Height; pRenderTarget->Release(); // Texture coordinates in linear format textures go from 0 to n-1 rather // than the 0 to 1 that is used for swizzled textures. D3DSURFACE_DESC desc; pTexture->GetLevelDesc( 0, &desc ); struct BACKGROUNDVERTEX { D3DXVECTOR4 p; FLOAT tu, tv; } v[4]; v[0].p = D3DXVECTOR4( -0.5f, -0.5f, 1.0f, 1.0f ); v[0].tu = 0.0f; v[0].tv = 0.0f; v[1].p = D3DXVECTOR4( Width - 0.5f, -0.5f, 1.0f, 1.0f ); v[1].tu = (float)desc.Width; v[1].tv = 0.0f; v[2].p = D3DXVECTOR4( -0.5f, Height - 0.5f, 1.0f, 1.0f ); v[2].tu = 0.0f; v[2].tv = (float)desc.Height; v[3].p = D3DXVECTOR4( Width - 0.5f, Height - 0.5f, 1.0f, 1.0f ); v[3].tu = (float)desc.Width; v[3].tv = (float)desc.Height; // Set states glw_state->device->SetPixelShader( 0 ); glw_state->device->SetTexture( 0, pTexture ); glw_state->device->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE2X ); glw_state->device->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE ); glw_state->device->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_TFACTOR ); glw_state->device->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_DISABLE ); glw_state->device->SetTextureStageState( 0, D3DTSS_ADDRESSU, D3DTADDRESS_CLAMP ); glw_state->device->SetTextureStageState( 0, D3DTSS_ADDRESSV, D3DTADDRESS_CLAMP ); glw_state->device->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR ); glw_state->device->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR ); glw_state->device->SetTextureStageState( 0, D3DTSS_MAXMIPLEVEL, 0 ); glw_state->device->SetTextureStageState( 0, D3DTSS_MIPFILTER, D3DTEXF_NONE ); glw_state->device->SetRenderState( D3DRS_ZENABLE, FALSE ); glw_state->device->SetRenderState( D3DRS_ALPHATESTENABLE, FALSE ); XGCOLOR Blend(1.0f, 1.0f, 1.0f, 1.0f); Blend*= r_hdrbloom->value;//m_fBloomScale; // adjust blend amount glw_state->device->SetRenderState( D3DRS_TEXTUREFACTOR, Blend ); // add if requested glw_state->device->SetRenderState( D3DRS_ALPHABLENDENABLE, true ); glw_state->device->SetRenderState( D3DRS_BLENDOP, D3DBLENDOP_ADD ); glw_state->device->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_ONE ); glw_state->device->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ONE ); // Render the screen-aligned quadrilateral glw_state->device->SetVertexShader( D3DFVF_XYZRHW|D3DFVF_TEX1 ); glw_state->device->DrawVerticesUP( D3DPT_QUADSTRIP, 4, v, sizeof(BACKGROUNDVERTEX) ); glw_state->device->SetRenderState( D3DRS_ZENABLE, TRUE ); } void VVHighDynamicRange::FilterCopy( LPDIRECT3DTEXTURE8 pTextureDst, LPDIRECT3DTEXTURE8 pTextureSrc, UINT nSample, FilterSample rSample[], UINT nSuperSampleX, UINT nSuperSampleY, bool bCrap, RECT* pRectDst, RECT* pRectSrc ) { // Texture space pixel center == screen space pixel center glw_state->device->SetScreenSpaceOffset( -0.5f, -0.5f ); // Save current render target and depth buffer LPDIRECT3DSURFACE8 pRenderTarget, pZBuffer; glw_state->device->GetRenderTarget( &pRenderTarget ); glw_state->device->GetDepthStencilSurface( &pZBuffer ); // Set destination as render target LPDIRECT3DSURFACE8 pSurface = NULL; pTextureDst->GetSurfaceLevel( 0, &pSurface ); glw_state->device->SetRenderTarget( pSurface, NULL ); // no depth-buffering pSurface->Release(); // Get descriptions of source and destination D3DSURFACE_DESC descSrc; pTextureSrc->GetLevelDesc( 0, &descSrc ); D3DSURFACE_DESC descDst; pTextureDst->GetLevelDesc( 0, &descDst ); // Setup rectangles if not specified on input RECT rectSrc = { 0, 0, descSrc.Width, descSrc.Height }; if( pRectSrc == NULL ) pRectSrc = &rectSrc; RECT rectDst = { 0, 0, descDst.Width, descDst.Height }; if( pRectDst == NULL ) { // If the destination rectangle is not specified, // we change it to match the source rectangle rectDst.right = (pRectSrc->right - pRectSrc->left) / nSuperSampleX; rectDst.bottom = (pRectSrc->bottom - pRectSrc->top) / nSuperSampleY; pRectDst = &rectDst; } assert( (pRectDst->right - pRectDst->left) == (pRectSrc->right - pRectDst->left) / (INT)nSuperSampleX ); assert( (pRectDst->bottom - pRectDst->top) == (pRectSrc->bottom - pRectDst->top) / (INT)nSuperSampleY ); //Set render state for filtering glw_state->device->SetRenderState( D3DRS_LIGHTING, FALSE ); glw_state->device->SetRenderState( D3DRS_FILLMODE, D3DFILL_SOLID ); glw_state->device->SetRenderState( D3DRS_ALPHATESTENABLE, FALSE ); glw_state->device->SetRenderState( D3DRS_ZENABLE, D3DZB_FALSE ); glw_state->device->SetRenderState( D3DRS_STENCILENABLE, FALSE ); glw_state->device->SetRenderState( D3DRS_FOGENABLE, FALSE ); // On first rendering, copy new value over current render target contents glw_state->device->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE ); // Setup subsequent renderings to add to previous value glw_state->device->SetRenderState( D3DRS_BLENDOP, D3DBLENDOP_ADD ); glw_state->device->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_ONE ); glw_state->device->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ONE ); // Set texture state for( UINT xx = 0; xx < 4; xx++) { // Use our source texture for all four stages glw_state->device->SetTexture( xx, pTextureSrc); glw_state->device->SetTextureStageState( xx, D3DTSS_COLOROP, D3DTOP_DISABLE ); glw_state->device->SetTextureStageState( xx, D3DTSS_ALPHAOP, D3DTOP_DISABLE ); // Pass texture coords without transformation glw_state->device->SetTextureStageState( xx, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE ); // Each texture has different tex coords glw_state->device->SetTextureStageState( xx, D3DTSS_TEXCOORDINDEX, xx ); glw_state->device->SetTextureStageState( xx, D3DTSS_ADDRESSU, D3DTADDRESS_CLAMP ); glw_state->device->SetTextureStageState( xx, D3DTSS_ADDRESSV, D3DTADDRESS_CLAMP ); glw_state->device->SetTextureStageState( xx, D3DTSS_MAXMIPLEVEL, 0 ); glw_state->device->SetTextureStageState( xx, D3DTSS_MIPFILTER, D3DTEXF_NONE ); glw_state->device->SetTextureStageState( xx, D3DTSS_MINFILTER, D3DTEXF_LINEAR ); glw_state->device->SetTextureStageState( xx, D3DTSS_MAGFILTER, D3DTEXF_LINEAR ); glw_state->device->SetTextureStageState( xx, D3DTSS_COLORKEYOP, D3DTCOLORKEYOP_DISABLE ); glw_state->device->SetTextureStageState( xx, D3DTSS_COLORSIGN, 0 ); glw_state->device->SetTextureStageState( xx, D3DTSS_ALPHAKILL, D3DTALPHAKILL_DISABLE ); } // Use hot blur pixel shader if(bCrap) glw_state->device->SetPixelShader( m_dwExtractHotPixelShader ); else glw_state->device->SetPixelShader( m_dwHotBlurPixelShader ); // For screen-space texture-mapped quadrilateral glw_state->device->SetVertexShader( D3DFVF_XYZRHW|D3DFVF_TEX4 ); // Prepare quadrilateral vertices float x0 = (float)pRectDst->left; float y0 = (float)pRectDst->top; float x1 = (float)pRectDst->right; float y1 = (float)pRectDst->bottom; struct Quad { float x, y, z, w1; struct uv { float u, v; } tex[4]; // each texture has different offset } aQuad[4] = { // X Y Z 1/W u0 v0 u1 v1 u2 v2 u3 v3 {x0, y0, 1.0f, 1.0f, }, // texture coords are set below {x1, y0, 1.0f, 1.0f, }, {x0, y1, 1.0f, 1.0f, }, {x1, y1, 1.0f, 1.0f, } }; // Set rendering to just the destination rect glw_state->device->SetScissors( 1, FALSE, (D3DRECT *)pRectDst ); // Draw a quad for each block of 4 filter coefficients float fOffsetScaleU = (float)nSuperSampleX; // offset for supersample float fOffsetScaleV = (float)nSuperSampleY; float u0 = (float)pRectSrc->left; float v0 = (float)pRectSrc->top; float u1 = (float)pRectSrc->right; float v1 = (float)pRectSrc->bottom; if( XGIsSwizzledFormat( descSrc.Format ) ) { float fWidthScale = 1.f / (float)descSrc.Width; float fHeightScale = 1.f / (float)descSrc.Height; fOffsetScaleU *= fWidthScale; fOffsetScaleV *= fHeightScale; u0 *= fWidthScale; v0 *= fHeightScale; u1 *= fWidthScale; v1 *= fHeightScale; } xx = 0; // current texture stage D3DCOLOR rColor[4]; DWORD rPSInput[4]; for( UINT iSample = 0; iSample < nSample; iSample++ ) { // Set filter coefficients float fValue = rSample[iSample].fValue; if( fValue < 0.f ) { rColor[xx] = D3DXCOLOR( -fValue, -fValue, -fValue, -fValue ); rPSInput[xx] = PS_INPUTMAPPING_SIGNED_NEGATE | ((xx % 2) ? PS_REGISTER_C1 : PS_REGISTER_C0); } else { rColor[xx] = D3DXCOLOR( fValue, fValue, fValue, fValue ); rPSInput[xx] = PS_INPUTMAPPING_SIGNED_IDENTITY | ((xx % 2) ? PS_REGISTER_C1 : PS_REGISTER_C0); } // Align supersamples with center of destination pixels float fOffsetX = rSample[iSample].fOffsetX;// * fOffsetScaleU; float fOffsetY = rSample[iSample].fOffsetY;// * fOffsetScaleV; aQuad[0].tex[xx].u = u0 + fOffsetX; aQuad[0].tex[xx].v = v0 + fOffsetY; aQuad[1].tex[xx].u = u1 + fOffsetX; aQuad[1].tex[xx].v = v0 + fOffsetY; aQuad[2].tex[xx].u = u0 + fOffsetX; aQuad[2].tex[xx].v = v1 + fOffsetY; aQuad[3].tex[xx].u = u1 + fOffsetX; aQuad[3].tex[xx].v = v1 + fOffsetY; xx++; // Go to next stage if( xx == 4 || iSample == nSample - 1 ) // max texture stages or last sample { // Zero out unused texture stage coefficients // (Only for last filter sample, when number of samples is not divisible by 4) for( ; xx < 4; xx++) { glw_state->device->SetTexture( xx, NULL ); rColor[xx] = 0; rPSInput[xx] = PS_INPUTMAPPING_UNSIGNED_IDENTITY | PS_REGISTER_ZERO; } // Set coefficients glw_state->device->SetRenderState( D3DRS_PSCONSTANT0_0, rColor[0] ); glw_state->device->SetRenderState( D3DRS_PSCONSTANT1_0, rColor[1] ); glw_state->device->SetRenderState( D3DRS_PSCONSTANT0_1, rColor[2] ); glw_state->device->SetRenderState( D3DRS_PSCONSTANT1_1, rColor[3] ); if(bCrap) { } else { // Remap coefficients to proper sign glw_state->device->SetRenderState( D3DRS_PSRGBINPUTS0, PS_COMBINERINPUTS( rPSInput[0] | PS_CHANNEL_RGB, PS_REGISTER_T0 | PS_CHANNEL_RGB | PS_INPUTMAPPING_SIGNED_IDENTITY, rPSInput[1] | PS_CHANNEL_RGB, PS_REGISTER_T1 | PS_CHANNEL_RGB | PS_INPUTMAPPING_SIGNED_IDENTITY ) ); glw_state->device->SetRenderState( D3DRS_PSALPHAINPUTS0, PS_COMBINERINPUTS( rPSInput[0] | PS_CHANNEL_ALPHA, PS_REGISTER_T0 | PS_CHANNEL_ALPHA | PS_INPUTMAPPING_SIGNED_IDENTITY, rPSInput[1] | PS_CHANNEL_ALPHA, PS_REGISTER_T1 | PS_CHANNEL_ALPHA | PS_INPUTMAPPING_SIGNED_IDENTITY ) ); glw_state->device->SetRenderState( D3DRS_PSRGBINPUTS1, PS_COMBINERINPUTS( rPSInput[2] | PS_CHANNEL_RGB, PS_REGISTER_T2 | PS_CHANNEL_RGB | PS_INPUTMAPPING_SIGNED_IDENTITY, rPSInput[3] | PS_CHANNEL_RGB, PS_REGISTER_T3 | PS_CHANNEL_RGB | PS_INPUTMAPPING_SIGNED_IDENTITY ) ); glw_state->device->SetRenderState( D3DRS_PSALPHAINPUTS1, PS_COMBINERINPUTS( rPSInput[2] | PS_CHANNEL_ALPHA, PS_REGISTER_T2 | PS_CHANNEL_ALPHA | PS_INPUTMAPPING_SIGNED_IDENTITY, rPSInput[3] | PS_CHANNEL_ALPHA, PS_REGISTER_T3 | PS_CHANNEL_ALPHA | PS_INPUTMAPPING_SIGNED_IDENTITY ) ); } // Draw the quad to filter the coefficients so far // One quad blends 4 textures glw_state->device->DrawPrimitiveUP( D3DPT_TRIANGLESTRIP, 2, aQuad, sizeof(Quad) ); // On subsequent renderings, add to what's in the render target glw_state->device->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE ); xx = 0; } } // Clear texture stages for( xx=0; xx<4; xx++ ) { glw_state->device->SetTexture( xx, NULL ); glw_state->device->SetTextureStageState( xx, D3DTSS_COLOROP, D3DTOP_DISABLE ); glw_state->device->SetTextureStageState( xx, D3DTSS_ALPHAOP, D3DTOP_DISABLE ); glw_state->device->SetTextureStageState( xx, D3DTSS_MIPMAPLODBIAS, 0 ); } // Restore render target and zbuffer glw_state->device->SetRenderTarget( pRenderTarget, pZBuffer ); if( pRenderTarget ) pRenderTarget->Release(); if( pZBuffer ) pZBuffer->Release(); glw_state->device->SetScreenSpaceOffset( 0.0f, 0.0f ); } void VVHighDynamicRange::ExtractHot( LPDIRECT3DTEXTURE8 pTextureDst, LPDIRECT3DTEXTURE8 pTextureSrc, UINT nSuperSampleX, UINT nSuperSampleY, RECT* pRectDst, RECT* pRectSrc ) { // Texture space pixel center == screen space pixel center glw_state->device->SetScreenSpaceOffset( -0.5f, -0.5f ); // Save current render target and depth buffer LPDIRECT3DSURFACE8 pRenderTarget, pZBuffer; glw_state->device->GetRenderTarget( &pRenderTarget ); glw_state->device->GetDepthStencilSurface( &pZBuffer ); // Set destination as render target LPDIRECT3DSURFACE8 pSurface = NULL; pTextureDst->GetSurfaceLevel( 0, &pSurface ); glw_state->device->SetRenderTarget( pSurface, NULL ); // no depth-buffering pSurface->Release(); // Get descriptions of source and destination D3DSURFACE_DESC descSrc; pTextureSrc->GetLevelDesc( 0, &descSrc ); D3DSURFACE_DESC descDst; pTextureDst->GetLevelDesc( 0, &descDst ); // Setup rectangles if not specified on input RECT rectSrc = { 0, 0, descSrc.Width, descSrc.Height }; if( pRectSrc == NULL ) pRectSrc = &rectSrc; RECT rectDst = { 0, 0, descDst.Width, descDst.Height }; if( pRectDst == NULL ) { // If the destination rectangle is not specified, // we change it to match the source rectangle rectDst.right = (pRectSrc->right - pRectSrc->left) / nSuperSampleX; rectDst.bottom = (pRectSrc->bottom - pRectSrc->top) / nSuperSampleY; pRectDst = &rectDst; } assert( (pRectDst->right - pRectDst->left) == (pRectSrc->right - pRectDst->left) / (INT)nSuperSampleX ); assert( (pRectDst->bottom - pRectDst->top) == (pRectSrc->bottom - pRectDst->top) / (INT)nSuperSampleY ); //Set render state for filtering glw_state->device->SetRenderState( D3DRS_LIGHTING, FALSE ); glw_state->device->SetRenderState( D3DRS_FILLMODE, D3DFILL_SOLID ); glw_state->device->SetRenderState( D3DRS_ALPHATESTENABLE, FALSE ); glw_state->device->SetRenderState( D3DRS_ZENABLE, D3DZB_FALSE ); glw_state->device->SetRenderState( D3DRS_STENCILENABLE, FALSE ); glw_state->device->SetRenderState( D3DRS_FOGENABLE, FALSE ); glw_state->device->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE ); glw_state->device->SetRenderState( D3DRS_BLENDOP, D3DBLENDOP_ADD ); glw_state->device->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_ONE ); glw_state->device->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ONE ); glw_state->device->SetTexture( 0, pTextureSrc); glw_state->device->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_DISABLE ); glw_state->device->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_DISABLE ); // Pass texture coords without transformation glw_state->device->SetTextureStageState( 0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE ); // Each texture has different tex coords glw_state->device->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, 0 ); glw_state->device->SetTextureStageState( 0, D3DTSS_ADDRESSU, D3DTADDRESS_CLAMP ); glw_state->device->SetTextureStageState( 0, D3DTSS_ADDRESSV, D3DTADDRESS_CLAMP ); glw_state->device->SetTextureStageState( 0, D3DTSS_MAXMIPLEVEL, 0 ); glw_state->device->SetTextureStageState( 0, D3DTSS_MIPFILTER, D3DTEXF_NONE ); glw_state->device->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_GAUSSIANCUBIC ); glw_state->device->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_GAUSSIANCUBIC ); glw_state->device->SetTextureStageState( 0, D3DTSS_COLORKEYOP, D3DTCOLORKEYOP_DISABLE ); glw_state->device->SetTextureStageState( 0, D3DTSS_COLORSIGN, 0 ); glw_state->device->SetTextureStageState( 0, D3DTSS_ALPHAKILL, D3DTALPHAKILL_DISABLE ); // Use extract hot pixel shader glw_state->device->SetPixelShader( m_dwExtractHotPixelShader ); // For screen-space texture-mapped quadrilateral glw_state->device->SetVertexShader( D3DFVF_XYZRHW|D3DFVF_TEX1 ); // Prepare quadrilateral vertices float x0 = (float)pRectDst->left; float y0 = (float)pRectDst->top; float x1 = (float)pRectDst->right; float y1 = (float)pRectDst->bottom; struct Quad { float x, y, z, w1; struct uv { float u, v; } tex; } aQuad[4] = { // X Y Z 1/W u0 v0 u1 v1 u2 v2 u3 v3 {x0, y0, 1.0f, 1.0f, }, // texture coords are set below {x1, y0, 1.0f, 1.0f, }, {x0, y1, 1.0f, 1.0f, }, {x1, y1, 1.0f, 1.0f, } }; // Set rendering to just the destination rect glw_state->device->SetScissors( 1, FALSE, (D3DRECT *)pRectDst ); // Draw a quad for each block of 4 filter coefficients float u0 = (float)pRectSrc->left; float v0 = (float)pRectSrc->top; float u1 = (float)pRectSrc->right; float v1 = (float)pRectSrc->bottom; if( XGIsSwizzledFormat( descSrc.Format ) ) { float fWidthScale = 1.f / (float)descSrc.Width; float fHeightScale = 1.f / (float)descSrc.Height; u0 *= fWidthScale; v0 *= fHeightScale; u1 *= fWidthScale; v1 *= fHeightScale; } aQuad[0].tex.u = u0; aQuad[0].tex.v = v0; aQuad[1].tex.u = u1; aQuad[1].tex.v = v0; aQuad[2].tex.u = u0; aQuad[2].tex.v = v1; aQuad[3].tex.u = u1; aQuad[3].tex.v = v1; // Draw the quad glw_state->device->DrawPrimitiveUP( D3DPT_TRIANGLESTRIP, 2, aQuad, sizeof(Quad) ); glw_state->device->SetTexture( 0, NULL ); // Restore render target and zbuffer glw_state->device->SetRenderTarget( pRenderTarget, pZBuffer ); if( pRenderTarget ) pRenderTarget->Release(); if( pZBuffer ) pZBuffer->Release(); glw_state->device->SetScreenSpaceOffset( 0.0f, 0.0f ); } void VVHighDynamicRange::HotBlur() { // Make D3DTexture wrapper around current render target LPDIRECT3DSURFACE8 pRenderTarget; glw_state->device->GetRenderTarget( &pRenderTarget ); D3DSURFACE_DESC descRenderTarget; pRenderTarget->GetDesc( &descRenderTarget ); D3DTexture RenderTargetTexture; ZeroMemory( &RenderTargetTexture, sizeof(RenderTargetTexture) ); XGSetTextureHeader( descRenderTarget.Width, descRenderTarget.Height, 1, 0, descRenderTarget.Format, 0, &RenderTargetTexture, pRenderTarget->Data, descRenderTarget.Width * 4 ); pRenderTarget->Release(); // Filters align to blurriest point in supersamples, on the pixel centers // This takes advantage of the bilinear filtering in the texture map lookup. FilterSample YFilter[] = // 1221 4-tap filter in Y { { 2.0f/6.f, 0.0f, 1.0f }, { 1.0f/6.f, 0.0f, 3.0f }, { 2.0f/6.f, 0.0f, -1.0f }, { 1.0f/6.f, 0.0f, -3.0f }, }; FilterSample XFilter[] = // 1221 4-tap filter in X { { 2.0f/6.f, 1.0f, 0.0f }, { 1.0f/6.f, 3.0f, 0.0f }, { 2.0f/6.f, -1.0f, 0.0f }, { 1.0f/6.f, -3.0f, 0.0f }, }; D3DTexture *pTextureSrc; D3DTexture *pTextureDst; pTextureDst = &RenderTargetTexture; // source is backbuffer // extract "hot" portion of hte image with downsampling pTextureSrc = pTextureDst; pTextureDst = m_rpHotImage; // destination is blur texture ExtractHot( pTextureDst, pTextureSrc, 2, 2 ); // 2 passes: Vertical gaussian (1221) followed by // horizontal gaussian (1221), with 2x2 downsampling pTextureSrc = pTextureDst; // destination is next blur texture pTextureDst = m_rpBlur[0]; // destination is blur texture FilterCopy(pTextureDst, pTextureSrc, 4, YFilter, 1, 2, false); pTextureSrc = pTextureDst; // source is previous blur texture pTextureDst = m_rpBlur[1]; // destination is next blur texture FilterCopy(pTextureDst, pTextureSrc, 4, XFilter, 2, 1, false); m_pBlur = pTextureDst; }