mirror of
https://github.com/thug1src/thug.git
synced 2025-01-22 05:43:47 +00:00
1411 lines
54 KiB
C++
1411 lines
54 KiB
C++
#include <core/defines.h>
|
|
#include <core/debug.h>
|
|
#include <xgraphics.h>
|
|
#include "nx_init.h"
|
|
#include "render.h"
|
|
#include "screenfx.h"
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// A filter sample holds a subpixel offset and a filter value
|
|
// to be multiplied by a source texture to compute an arbitrary
|
|
// filter. See filter_copy for more details.
|
|
//-----------------------------------------------------------------------------
|
|
struct FilterSample
|
|
{
|
|
FLOAT fValue; // Coefficient
|
|
FLOAT fOffsetX, fOffsetY; // Subpixel offsets of supersamples in destination coordinates
|
|
};
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// The depth-mapping pixel shader attempts to do higher precision
|
|
// math with eight-bit color registers. The _x4 instruction modifier
|
|
// is used twice to get a 16x range of values.
|
|
//-----------------------------------------------------------------------------
|
|
FLOAT g_fPixelShaderScale = 16.0f; // to get into the right range, we scale up the value in the pixel shader
|
|
FLOAT m_fDepth0 = 0.900f;
|
|
FLOAT m_fDepth1 = 0.997f;
|
|
D3DTexture* m_pTextureFocusRange = NULL; // Lookup table for range of z values to use
|
|
|
|
// Enumeration of blur filters available in this sample to compare the speed and quality of different types of blur filters for
|
|
// the out-of-focus parts of the scene.
|
|
enum FILTERMODE
|
|
{
|
|
FM_BOX,
|
|
FM_VERT,
|
|
FM_HORIZ,
|
|
FM_BOX2,
|
|
FM_VERT2,
|
|
FM_HORIZ2,
|
|
FM_BOX2_BOX2,
|
|
FM_VERT2_HORIZ2,
|
|
FM_HORIZ2_VERT2,
|
|
FM_VERT2_HORIZ,
|
|
FM_HORIZ2_VERT,
|
|
FM_VERT2_HORIZ2_BOX2,
|
|
FM_BOX2_BOX2_BOX2,
|
|
FM_VERT2_HORIZ2_VERT2,
|
|
FM_HORIZ2_VERT2_HORIZ2,
|
|
FM_VERT2_HORIZ2_VERT2_HORIZ2,
|
|
FM_HORIZ2_VERT2_HORIZ2_VERT2,
|
|
FM_BOX2_BOX2_BOX2_BOX2,
|
|
_FM_MAX
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
namespace NxXbox
|
|
{
|
|
|
|
|
|
void draw_rain( void )
|
|
{
|
|
static float table_x[512];
|
|
static float table_y[512];
|
|
static bool table_set = false;
|
|
static int table_index = 0;
|
|
if( !table_set )
|
|
{
|
|
table_set = true;
|
|
for( int i = 0; i < 512; ++i )
|
|
{
|
|
table_x[i] = ((float)( rand() - ( RAND_MAX / 2 )) * 32.0f ) / (float)RAND_MAX;
|
|
table_y[i] = ((float)rand() * 12.0f ) / (float)RAND_MAX;
|
|
}
|
|
}
|
|
|
|
static float radius = 24.0f;
|
|
|
|
// Distance of the drip from the camera.
|
|
static float distance = 10.0f * 12.0f;
|
|
|
|
// Drip vector.
|
|
static Mth::Vector offset( 0.0f, -1.0f * radius, 0.0f );
|
|
static Mth::Vector offset_target( 0.0f, -1.0f * radius, 0.0f );
|
|
|
|
static int num_drops = 1000;
|
|
|
|
if(( rand() & 63 ) == 1 )
|
|
{
|
|
offset_target[X] = ( radius * 0.25f * ( rand() - ( RAND_MAX / 2 ))) / RAND_MAX;
|
|
offset_target[Y] = ( radius * -1.0f * rand() ) / RAND_MAX;
|
|
offset_target[Z] = ( radius * 0.25f * ( rand() - ( RAND_MAX / 2 ))) / RAND_MAX;
|
|
|
|
offset_target.Normalize( radius );
|
|
}
|
|
|
|
offset += ( offset_target - offset ) * 0.2f;
|
|
offset.Normalize( radius );
|
|
|
|
D3DXVECTOR4 or( EngineGlobals.cam_position.x + ( distance * EngineGlobals.cam_at.x ),
|
|
EngineGlobals.cam_position.y + ( distance * EngineGlobals.cam_at.y ),
|
|
EngineGlobals.cam_position.z + ( distance * EngineGlobals.cam_at.z ),
|
|
1.0f );
|
|
D3DXVECTOR4 of( or.x + offset[X], or.y + offset[Y], or.z + offset[Z], 1.0f );
|
|
|
|
D3DXVec4Transform( &or, &or, (D3DXMATRIX*)&EngineGlobals.view_matrix );
|
|
D3DXVec4Transform( &of, &of, (D3DXMATRIX*)&EngineGlobals.view_matrix );
|
|
|
|
D3DXVec4Transform( &or, &or, (D3DXMATRIX*)&EngineGlobals.projection_matrix );
|
|
D3DXVec4Transform( &of, &of, (D3DXMATRIX*)&EngineGlobals.projection_matrix );
|
|
|
|
or.x /= or.w;
|
|
or.y /= or.w;
|
|
|
|
of.x /= of.w;
|
|
of.y /= of.w;
|
|
|
|
of.y = -of.y;
|
|
|
|
// printf( "(%.2f %.2f) (%.2f %.2f)\n", or.x, or.y, of.x, of.y );
|
|
|
|
// Obtain push buffer lock.
|
|
DWORD *p_push;
|
|
DWORD dwords_per_particle = 10;
|
|
DWORD dword_count = dwords_per_particle * num_drops;
|
|
|
|
// Submit particle material.
|
|
// mp_engine_particle->mp_material->Submit();
|
|
NxXbox::set_blend_mode( vBLEND_MODE_BLEND );
|
|
|
|
// Set up correct vertex and pixel shader.
|
|
NxXbox::set_vertex_shader( D3DFVF_XYZRHW | D3DFVF_DIFFUSE );
|
|
NxXbox::set_pixel_shader( PixelShader5 );
|
|
|
|
// The additional number (+5 is minimum) is to reserve enough overhead for the encoding parameters. It can safely be more, but no less.
|
|
p_push = D3DDevice_BeginPush( dword_count + 32 );
|
|
|
|
// Note that p_push is returned as a pointer to write-combined memory. Writes to write-combined memory should be
|
|
// consecutive and in increasing order. Reads should be avoided. Additionally, any CPU reads from memory or the
|
|
// L2 cache can force expensive partial flushes of the 32-byte write-combine cache.
|
|
p_push[0] = D3DPUSH_ENCODE( D3DPUSH_SET_BEGIN_END, 1 );
|
|
p_push[1] = D3DPT_LINELIST;
|
|
p_push += 2;
|
|
|
|
// Set up loop variables here, since we be potentially entering the loop more than once.
|
|
int lp = 0;
|
|
|
|
while( dword_count > 0 )
|
|
{
|
|
int dwords_written = 0;
|
|
|
|
// NOTE: A maximum of 2047 DWORDs can be specified to D3DPUSH_ENCODE. If there is more than 2047 DWORDs of vertex
|
|
// data, simply split the data into multiple D3DPUSH_ENCODE( D3DPUSH_INLINE_ARRAY ) sections.
|
|
p_push[0] = D3DPUSH_ENCODE( D3DPUSH_NOINCREMENT_FLAG | D3DPUSH_INLINE_ARRAY, ( dword_count > 2047 ) ? ((int)( 2047 / dwords_per_particle )) * dwords_per_particle: dword_count );
|
|
++p_push;
|
|
|
|
for( ; lp < num_drops; lp++ )
|
|
{
|
|
// Check to see if writing another particle will take us over the edge.
|
|
if(( dwords_written + dwords_per_particle ) > 2047 )
|
|
{
|
|
break;
|
|
}
|
|
|
|
float screen_x0 = (float)(( NxXbox::EngineGlobals.backbuffer_width * rand() ) / RAND_MAX );
|
|
float screen_y0 = (float)(( NxXbox::EngineGlobals.backbuffer_height * rand() ) / RAND_MAX );
|
|
|
|
int random_length = rand();
|
|
|
|
float screen_x1 = (float)( screen_x0 + (( of.x * ( EngineGlobals.backbuffer_width / 2 ) * random_length ) / RAND_MAX ));
|
|
float screen_y1 = (float)( screen_y0 + (( of.y * ( EngineGlobals.backbuffer_height / 2 ) * random_length ) / RAND_MAX ));
|
|
|
|
screen_x1 += table_x[table_index];
|
|
screen_y1 += table_y[table_index];
|
|
table_index = ( table_index >= 512 ) ? 0 : ( table_index + 1 );
|
|
|
|
p_push[0] = *((DWORD*)&screen_x0 );
|
|
p_push[1] = *((DWORD*)&screen_y0 );
|
|
p_push[2] = 0x00000000UL;
|
|
p_push[3] = 0x00000000UL;
|
|
p_push[4] = 0xA0808080UL;
|
|
p_push += 5;
|
|
|
|
p_push[0] = *((DWORD*)&screen_x1 );
|
|
p_push[1] = *((DWORD*)&screen_y1 );
|
|
p_push[2] = 0x00000000UL;
|
|
p_push[3] = 0x00000000UL;
|
|
p_push[4] = 0x20808080UL;
|
|
p_push += 5;
|
|
|
|
dwords_written += dwords_per_particle;
|
|
dword_count -= dwords_per_particle;
|
|
}
|
|
}
|
|
p_push[0] = D3DPUSH_ENCODE( D3DPUSH_SET_BEGIN_END, 1 );
|
|
p_push[1] = 0;
|
|
p_push += 2;
|
|
D3DDevice_EndPush( p_push );
|
|
}
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// For mapping from the depth buffer to blend values using
|
|
// a texture map lookup. See media\shaders\depthlookup.psh
|
|
//
|
|
// This is more general than computing the range as in
|
|
// media\shaders\depth.psh, since the ramp can be filled in
|
|
// arbitrarily, but may be more expensive due to the extra texture
|
|
// lookup.
|
|
//
|
|
float FUnitMap(float fAlpha, float fBlue, float fAlphaOffset, float fAlphaSlope, float fBlueOffset, float fBlueSlope)
|
|
{
|
|
//return g_fPixelShaderScale * fAlphaSlope * (fAlpha - fAlphaOffset) + fBlueSlope * fBlue + fBlueOffset - 0.5f;
|
|
return g_fPixelShaderScale * fAlphaSlope * (fAlpha - fAlphaOffset) + fBlueSlope * (fBlue - fBlueOffset);
|
|
}
|
|
|
|
float FQuantizedDepth(float fDepth, float *pfAlpha, float *pfBlue)
|
|
{
|
|
float fDepth16 = fDepth * (float)(1 << 16);
|
|
DWORD dwDepth16 = (DWORD)(fDepth16 /*+ 0.5f*/);
|
|
*pfAlpha = (dwDepth16 >> 8) * (1.0f / 255.0f);
|
|
*pfBlue = (dwDepth16 & 0xff) * (1.0f / 255.0f);
|
|
return (float)dwDepth16 / (float)(1 << 16);
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: CalculateDepthMapping()
|
|
// Desc: Calculate offsets and slope to map given z range to 0,1 in
|
|
// the depth and focus pixel shaders.
|
|
//-----------------------------------------------------------------------------
|
|
static HRESULT calculate_depth_mapping( float fDepth0, float fDepth1, float* pfAlphaOffset, float* pfAlphaSlope, float* pfBlueOffset, float* pfBlueSlope )
|
|
{
|
|
// Check range of args
|
|
if( fDepth0 < 0.0f ) fDepth0 = 0.0f;
|
|
if( fDepth0 > 1.0f ) fDepth0 = 1.0f;
|
|
if( fDepth1 < 0.0f ) fDepth1 = 0.0f;
|
|
if( fDepth1 > 1.0f ) fDepth1 = 1.0f;
|
|
|
|
if( fDepth1 < fDepth0 )
|
|
{
|
|
// Swap depth to make fDepth0 <= fDepth1
|
|
float t = fDepth1;
|
|
fDepth1 = fDepth0;
|
|
fDepth0 = t;
|
|
}
|
|
|
|
// Calculate quantized values
|
|
float fAlpha0, fBlue0;
|
|
float fQuantizedDepth0 = FQuantizedDepth(fDepth0, &fAlpha0, &fBlue0);
|
|
float fAlpha1, fBlue1;
|
|
float fQuantizedDepth1 = FQuantizedDepth(fDepth1, &fAlpha1, &fBlue1);
|
|
|
|
// Calculate offset and slopes
|
|
float fScale = 1.0f / (fQuantizedDepth1 - fQuantizedDepth0);
|
|
if( fScale > g_fPixelShaderScale )
|
|
{
|
|
fScale = g_fPixelShaderScale; // This is the steepest slope we can handle
|
|
fDepth0 = 0.5f * (fDepth0 + fDepth1) - 0.5f / fScale; // Move start so that peak is in middle of fDepth0 and fDepth1
|
|
fDepth1 = fDepth0 + 1.0f / fScale;
|
|
fQuantizedDepth0 = FQuantizedDepth(fDepth0, &fAlpha0, &fBlue0);
|
|
fQuantizedDepth1 = FQuantizedDepth(fDepth1, &fAlpha1, &fBlue1);
|
|
}
|
|
|
|
(*pfAlphaOffset) = fAlpha0;
|
|
(*pfAlphaSlope) = fScale / g_fPixelShaderScale;
|
|
(*pfBlueSlope) = fScale * (1.0f/255.0f); // blue ramp adds more levels to the ramp
|
|
|
|
// Align peak of map to center by calculating the quantized alpha value
|
|
// *pfBlueOffset = 0.5f; // zero biased up by 0.5f
|
|
// float fZeroDesired = (fQuantizedDepth0 - fDepth0) / (fDepth1 - fDepth0);
|
|
// float fZero = FUnitMap(fAlpha0, fBlue0, *pfAlphaOffset, *pfAlphaSlope, *pfBlueOffset, *pfBlueSlope);
|
|
// float fOneDesired = (fQuantizedDepth1 - fDepth0) / (fDepth1 - fDepth0);
|
|
// float fOne = FUnitMap(fAlpha1, fBlue1, *pfAlphaOffset, *pfAlphaSlope, *pfBlueOffset, *pfBlueSlope);
|
|
// *pfBlueOffset = 0.5f * (fZeroDesired-fZero + fOneDesired-fOne) + 0.5f; // biased up by 0.5f
|
|
(*pfBlueOffset) = fBlue0;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static HRESULT fill_focus_range_texture( bool bRamp )
|
|
{
|
|
HRESULT hr;
|
|
|
|
static const DWORD Width = 256;
|
|
static const DWORD Height = 256;
|
|
|
|
// Create the focus range texture
|
|
if( m_pTextureFocusRange )
|
|
m_pTextureFocusRange->Release();
|
|
EngineGlobals.p_Device->CreateTexture( Width, Height, 1, 0, D3DFMT_A8, 0, &m_pTextureFocusRange );
|
|
|
|
// Fill the focus range texture
|
|
D3DLOCKED_RECT lockedRect;
|
|
hr = m_pTextureFocusRange->LockRect( 0, &lockedRect, NULL, 0L );
|
|
if( FAILED(hr) )
|
|
return hr;
|
|
|
|
DWORD dwPixelStride = 1;
|
|
Swizzler s(Width, Height, 0);
|
|
s.SetV(s.SwizzleV(0));
|
|
s.SetU(s.SwizzleU(0));
|
|
if( bRamp )
|
|
{
|
|
for( DWORD j = 0; j < Height; j++ )
|
|
{
|
|
for( DWORD i = 0; i < Width; i++ )
|
|
{
|
|
BYTE *p = (BYTE *)lockedRect.pBits + dwPixelStride * s.Get2D();
|
|
*p = (BYTE)i;
|
|
s.IncU();
|
|
}
|
|
s.IncV();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// float fAlphaOffset, fAlphaSlope, fBlueOffset, fBlueSlope;
|
|
// calculate_depth_mapping( m_fDepth0, m_fDepth1, &fAlphaOffset, &fAlphaSlope, &fBlueOffset, &fBlueSlope );
|
|
for( DWORD i = 0; i < Width; i++ )
|
|
{
|
|
float z_high = (float)i / ( Width - 1 );
|
|
|
|
for( DWORD j = 0; j < Height; j++ )
|
|
{
|
|
BYTE *p = (BYTE *)lockedRect.pBits + dwPixelStride * s.Get2D();
|
|
// float fAlpha = (float)i / (Width - 1);
|
|
// float fBlue = (float)j / (Height - 1);
|
|
// float fUnit = 2.0f * (FUnitMap(fAlpha, fBlue, fAlphaOffset, fAlphaSlope, fBlueOffset, fBlueSlope) - 0.5f);
|
|
// float fMap = 1.0f - fUnit * fUnit;
|
|
// if( fMap < 0.0f ) fMap = 0.0f;
|
|
// if( fMap > 1.0f ) fMap = 1.0f;
|
|
// *p = (BYTE)(255 * fMap + 0.5f);
|
|
|
|
float z_low = (float)j / ( Height - 1 );
|
|
float quantized_z = ((( z_high * 256.0f ) + z_low ) * 256.0f ) / 65536.0f;
|
|
|
|
if( quantized_z < m_fDepth0 )
|
|
{
|
|
*p = 0;
|
|
}
|
|
else if( quantized_z > m_fDepth1 )
|
|
{
|
|
*p = 0;
|
|
}
|
|
else
|
|
{
|
|
*p = 255;
|
|
}
|
|
s.IncV();
|
|
}
|
|
s.IncU();
|
|
}
|
|
}
|
|
|
|
m_pTextureFocusRange->UnlockRect( 0 );
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: filter_copy()
|
|
// Desc: Filter the source texture by rendering into the destination texture
|
|
// with subpixel offsets. Does 4 filter coefficients at a time, using all
|
|
// the stages of the pixel shader.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
D3DTexture* m_pBlur;
|
|
|
|
static HRESULT filter_copy( LPDIRECT3DTEXTURE8 pTextureDst,
|
|
LPDIRECT3DTEXTURE8 pTextureSrc,
|
|
DWORD dwNumSamples,
|
|
FilterSample rSample[],
|
|
DWORD dwSuperSampleX,
|
|
DWORD dwSuperSampleY )
|
|
{
|
|
// Set destination as render target, with no-depth buffer
|
|
LPDIRECT3DSURFACE8 pSurface;
|
|
pTextureDst->GetSurfaceLevel( 0, &pSurface );
|
|
EngineGlobals.p_Device->SetRenderTarget( pSurface, NULL );
|
|
pSurface->Release();
|
|
|
|
// Get descriptions of source and destination
|
|
D3DSURFACE_DESC descSrc;
|
|
pTextureSrc->GetLevelDesc( 0, &descSrc );
|
|
|
|
if( descSrc.MultiSampleType == D3DMULTISAMPLE_2_SAMPLES_MULTISAMPLE_LINEAR )
|
|
{
|
|
descSrc.Width *= 2;
|
|
}
|
|
|
|
// Set render state for filtering
|
|
EngineGlobals.p_Device->SetRenderState( D3DRS_LIGHTING, FALSE );
|
|
set_render_state( RS_ZWRITEENABLE, 0 );
|
|
set_render_state( RS_ZTESTENABLE, 0 );
|
|
set_render_state( RS_ALPHATESTENABLE, 0 );
|
|
set_render_state( RS_ALPHABLENDENABLE, 0 );
|
|
EngineGlobals.p_Device->SetRenderState( D3DRS_BLENDOP, D3DBLENDOP_ADD ); // Setup subsequent renderings to add to previous value
|
|
EngineGlobals.p_Device->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_ONE );
|
|
EngineGlobals.p_Device->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ONE );
|
|
|
|
// Set texture state
|
|
DWORD xx;
|
|
for( xx = 0; xx < 4; xx++ )
|
|
{
|
|
set_texture( xx, pTextureSrc ); // use our source texture for all four stages
|
|
|
|
EngineGlobals.p_Device->SetTextureStageState( xx, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE ); // pass texture coords without transformation
|
|
EngineGlobals.p_Device->SetTextureStageState( xx, D3DTSS_TEXCOORDINDEX, xx ); // each texture has different tex coords
|
|
set_render_state( RS_UVADDRESSMODE0 + xx, 0x00010001UL );
|
|
EngineGlobals.p_Device->SetTextureStageState( xx, D3DTSS_ALPHAKILL, D3DTALPHAKILL_DISABLE );
|
|
}
|
|
|
|
// Use blur pixel shader.
|
|
set_pixel_shader( PixelShaderFocusBlur );
|
|
set_vertex_shader( D3DFVF_XYZRHW | D3DFVF_TEX4 );
|
|
|
|
// Prepare quadrilateral vertices
|
|
float x0 = -0.5f;
|
|
float y0 = -0.5f;
|
|
float x1 = (float)( descSrc.Width / dwSuperSampleX ) - 0.5f;
|
|
float y1 = (float)( descSrc.Height / dwSuperSampleY ) - 0.5f;
|
|
struct QUAD
|
|
{
|
|
float x, y, z, w1;
|
|
struct uv
|
|
{
|
|
float u, v;
|
|
} tex[4]; // each texture has different offset
|
|
};
|
|
|
|
QUAD aQuad[4] =
|
|
{
|
|
{ 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, }
|
|
};
|
|
|
|
// Draw a quad for each block of 4 filter coefficients
|
|
xx = 0; // current texture stage
|
|
FLOAT fOffsetScaleX, fOffsetScaleY; // convert destination coords to source texture coords
|
|
FLOAT u0, v0, u1, v1; // base source rectangle.
|
|
if( XGIsSwizzledFormat( descSrc.Format ))
|
|
{
|
|
FLOAT fWidthScale = 1.0f / (FLOAT)descSrc.Width;
|
|
FLOAT fHeightScale = 1.0f / (FLOAT)descSrc.Height;
|
|
fOffsetScaleX = (FLOAT)dwSuperSampleX * fWidthScale;
|
|
fOffsetScaleY = (FLOAT)dwSuperSampleY * fHeightScale;
|
|
u0 = 0.0f;
|
|
v0 = 0.0f;
|
|
u1 = (FLOAT)descSrc.Width * fWidthScale;
|
|
v1 = (FLOAT)descSrc.Height * fHeightScale;
|
|
}
|
|
else
|
|
{
|
|
fOffsetScaleX = (FLOAT)dwSuperSampleX;
|
|
fOffsetScaleY = (FLOAT)dwSuperSampleY;
|
|
u0 = 0.0f;
|
|
v0 = 0.0f;
|
|
u1 = (FLOAT)descSrc.Width;
|
|
v1 = (FLOAT)descSrc.Height;
|
|
}
|
|
D3DCOLOR rColor[4];
|
|
DWORD rPSInput[4];
|
|
for( DWORD dwSample = 0; dwSample < dwNumSamples; dwSample++ )
|
|
{
|
|
// Set filter coefficients
|
|
FLOAT fValue = rSample[dwSample].fValue;
|
|
// float rf[4] = {fValue, fValue, fValue, fValue};
|
|
// EngineGlobals.p_Device->SetPixelShaderConstant(xx, rf, 1); // positive coeff
|
|
|
|
if( fValue < 0.0f )
|
|
{
|
|
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[dwSample].fOffsetX * fOffsetScaleX;
|
|
FLOAT fOffsetY = rSample[dwSample].fOffsetY * fOffsetScaleY;
|
|
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 || dwSample == dwNumSamples - 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++ )
|
|
{
|
|
set_texture( xx, NULL );
|
|
rColor[xx] = 0;
|
|
rPSInput[xx] = PS_INPUTMAPPING_UNSIGNED_IDENTITY | PS_REGISTER_ZERO;
|
|
}
|
|
|
|
// Set coefficients
|
|
EngineGlobals.p_Device->SetRenderState( D3DRS_PSCONSTANT0_0, rColor[0] );
|
|
EngineGlobals.p_Device->SetRenderState( D3DRS_PSCONSTANT1_0, rColor[1] );
|
|
EngineGlobals.p_Device->SetRenderState( D3DRS_PSCONSTANT0_1, rColor[2] );
|
|
EngineGlobals.p_Device->SetRenderState( D3DRS_PSCONSTANT1_1, rColor[3] );
|
|
|
|
// Remap coefficients to proper sign
|
|
EngineGlobals.p_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 ) );
|
|
EngineGlobals.p_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 ) );
|
|
EngineGlobals.p_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 ) );
|
|
EngineGlobals.p_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
|
|
EngineGlobals.p_Device->DrawPrimitiveUP( D3DPT_TRIANGLESTRIP, 2, aQuad, sizeof( QUAD )); // one quad blends 4 textures
|
|
|
|
// On subsequent renderings, add to what's in the render target.
|
|
set_render_state( RS_ALPHABLENDENABLE, 1 );
|
|
xx = 0;
|
|
}
|
|
}
|
|
|
|
// Clear texture stages
|
|
for( xx=0; xx<4; xx++ )
|
|
{
|
|
set_texture( xx, NULL );
|
|
}
|
|
|
|
// Restore render target, zbuffer, and state.
|
|
set_pixel_shader( NULL );
|
|
EngineGlobals.p_Device->SetRenderTarget( EngineGlobals.p_RenderSurface, EngineGlobals.p_ZStencilSurface );
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: Blur()
|
|
// Desc: Blur backbuffer and set m_pBlur to the current blur texture. Calls
|
|
// filter_copy() with different filter coefficients and offsets, based on
|
|
// the current FILTERMODE setting.
|
|
//-----------------------------------------------------------------------------
|
|
static HRESULT focus_blur( void )
|
|
{
|
|
D3DTexture m_BackBufferTexture;
|
|
D3DTexture m_BlurTexture[5];
|
|
|
|
FILTERMODE filter_mode = FM_BOX2_BOX2;
|
|
|
|
int multisample_adjusted_width = EngineGlobals.backbuffer_width * 2;
|
|
|
|
XGSetTextureHeader( multisample_adjusted_width, EngineGlobals.backbuffer_height, 1, 0,
|
|
EngineGlobals.backbuffer_format, 0, &m_BackBufferTexture,
|
|
EngineGlobals.p_RenderSurface->Data,
|
|
multisample_adjusted_width * XGBytesPerPixelFromFormat( EngineGlobals.backbuffer_format ));
|
|
|
|
XGSetTextureHeader( EngineGlobals.backbuffer_width, EngineGlobals.backbuffer_height, 1, 0,
|
|
EngineGlobals.blurbuffer_format, 0, &m_BlurTexture[0],
|
|
EngineGlobals.p_BlurSurface[0]->Data,
|
|
EngineGlobals.backbuffer_width * XGBytesPerPixelFromFormat( EngineGlobals.blurbuffer_format ));
|
|
|
|
XGSetTextureHeader( EngineGlobals.backbuffer_width / 2, EngineGlobals.backbuffer_height / 2, 1, 0,
|
|
EngineGlobals.blurbuffer_format, 0, &m_BlurTexture[1],
|
|
EngineGlobals.p_BlurSurface[1]->Data,
|
|
EngineGlobals.backbuffer_width / 2 * XGBytesPerPixelFromFormat( EngineGlobals.blurbuffer_format ));
|
|
|
|
XGSetTextureHeader( EngineGlobals.backbuffer_width / 4, EngineGlobals.backbuffer_height / 4, 1, 0,
|
|
EngineGlobals.blurbuffer_format, 0, &m_BlurTexture[2],
|
|
EngineGlobals.p_BlurSurface[2]->Data,
|
|
EngineGlobals.backbuffer_width / 4 * XGBytesPerPixelFromFormat( EngineGlobals.blurbuffer_format ));
|
|
|
|
XGSetTextureHeader( EngineGlobals.backbuffer_width / 8, EngineGlobals.backbuffer_height / 8, 1, 0,
|
|
EngineGlobals.blurbuffer_format, 0, &m_BlurTexture[3],
|
|
EngineGlobals.p_BlurSurface[3]->Data,
|
|
EngineGlobals.backbuffer_width / 8 * XGBytesPerPixelFromFormat( EngineGlobals.blurbuffer_format ));
|
|
|
|
// Filters align to blurriest point in supersamples, on the 0.5 boundaries.
|
|
// This takes advantage of the bilinear filtering in the texture map lookup.
|
|
static FilterSample BoxFilter[] = // for 2x2 downsampling
|
|
{
|
|
{ 0.25f, -0.5f, -0.5f },
|
|
{ 0.25f, 0.5f, -0.5f },
|
|
{ 0.25f, -0.5f, 0.5f },
|
|
{ 0.25f, 0.5f, 0.5f },
|
|
};
|
|
static FilterSample YFilter[] = // 1221 4-tap filter in Y
|
|
{
|
|
{ 1.0f/6.0f, 0.0f, -1.5f },
|
|
{ 2.0f/6.0f, 0.0f, -0.5f },
|
|
{ 2.0f/6.0f, 0.0f, 0.5f },
|
|
{ 1.0f/6.0f, 0.0f, 1.5f },
|
|
};
|
|
static FilterSample XFilter[] = // 1221 4-tap filter in X
|
|
{
|
|
{ 1.0f/6.0f, -1.5f, 0.0f },
|
|
{ 2.0f/6.0f, -0.5f, 0.0f },
|
|
{ 2.0f/6.0f, 0.5f, 0.0f },
|
|
{ 1.0f/6.0f, 1.5f, 0.0f },
|
|
};
|
|
static FilterSample Y141Filter[] = // 141 3-tap filter in Y
|
|
{
|
|
{ 1.0f/6.0f, 0.0f, -1.0f },
|
|
{ 4.0f/6.0f, 0.0f, 0.0f },
|
|
{ 1.0f/6.0f, 0.0f, 1.0f },
|
|
};
|
|
static FilterSample X141Filter[] = // 141 3-tap filter in X
|
|
{
|
|
{ 1.0f/6.0f, -1.0f, 0.0f },
|
|
{ 4.0f/6.0f, 0.0f, 0.0f },
|
|
{ 1.0f/6.0f, 1.0f, 0.0f },
|
|
};
|
|
static FilterSample IdentityFilter[] = // No filtering
|
|
{
|
|
{ 1.0f, 0.0f, 0.0f },
|
|
};
|
|
|
|
switch( filter_mode )
|
|
{
|
|
case FM_BOX:
|
|
{
|
|
// Blur from the backbuffer to the blur texture
|
|
D3DTexture* pTextureSrc = &m_BackBufferTexture;
|
|
D3DTexture* pTextureDst = &m_BlurTexture[0];
|
|
filter_copy( pTextureDst, pTextureSrc, 4, BoxFilter, 1, 1 );
|
|
|
|
m_pBlur = (IDirect3DTexture8*)NxXbox::EngineGlobals.p_BlurSurface[0];
|
|
break;
|
|
}
|
|
|
|
case FM_VERT:
|
|
{
|
|
// Blur from the backbuffer to the blur texture
|
|
D3DTexture* pTextureSrc = &m_BackBufferTexture;
|
|
D3DTexture* pTextureDst = &m_BlurTexture[0];
|
|
filter_copy( pTextureDst, pTextureSrc, 4, YFilter, 1, 1 );
|
|
|
|
m_pBlur = (IDirect3DTexture8*)NxXbox::EngineGlobals.p_BlurSurface[0];
|
|
break;
|
|
}
|
|
|
|
case FM_HORIZ:
|
|
{
|
|
// Blur from the backbuffer to the blur texture
|
|
D3DTexture* pTextureSrc = &m_BackBufferTexture;
|
|
D3DTexture* pTextureDst = &m_BlurTexture[0];
|
|
filter_copy( pTextureDst, pTextureSrc, 4, XFilter, 1, 1 );
|
|
|
|
m_pBlur = (IDirect3DTexture8*)NxXbox::EngineGlobals.p_BlurSurface[0];
|
|
break;
|
|
}
|
|
|
|
case FM_BOX2:
|
|
{
|
|
// Blur from the backbuffer to the 1/2 sized blur texture
|
|
D3DTexture* pTextureSrc = &m_BackBufferTexture;
|
|
D3DTexture *pTextureDst = &m_BlurTexture[1];
|
|
filter_copy( pTextureDst, pTextureSrc, 4, BoxFilter, 2, 2 );
|
|
|
|
m_pBlur = (IDirect3DTexture8*)NxXbox::EngineGlobals.p_BlurSurface[1];
|
|
break;
|
|
}
|
|
|
|
case FM_VERT2:
|
|
{
|
|
// Blur from the backbuffer to the 1/2 sized blur texture
|
|
D3DTexture* pTextureSrc = &m_BackBufferTexture;
|
|
D3DTexture* pTextureDst = &m_BlurTexture[1];
|
|
filter_copy( pTextureDst, pTextureSrc, 4, YFilter, 2, 2 );
|
|
|
|
m_pBlur = (IDirect3DTexture8*)NxXbox::EngineGlobals.p_BlurSurface[1];
|
|
break;
|
|
}
|
|
|
|
case FM_HORIZ2:
|
|
{
|
|
// Blur from the backbuffer to the 1/2 sized blur texture
|
|
D3DTexture* pTextureSrc = &m_BackBufferTexture;
|
|
D3DTexture *pTextureDst = &m_BlurTexture[1];
|
|
filter_copy( pTextureDst, pTextureSrc, 4, XFilter, 2, 2 );
|
|
|
|
m_pBlur = (IDirect3DTexture8*)NxXbox::EngineGlobals.p_BlurSurface[1];
|
|
break;
|
|
}
|
|
|
|
case FM_VERT2_HORIZ2:
|
|
{
|
|
// Blur from the backbuffer to the 1/2 sized blur texture
|
|
D3DTexture* pTextureSrc = &m_BackBufferTexture;
|
|
D3DTexture* pTextureDst = &m_BlurTexture[1];
|
|
filter_copy( pTextureDst, pTextureSrc, 4, YFilter, 2, 2 );
|
|
|
|
// Blur from the previous blur texture to the next blur texture
|
|
pTextureSrc = &m_BlurTexture[1];
|
|
pTextureDst = &m_BlurTexture[2];
|
|
filter_copy( pTextureDst, pTextureSrc, 4, XFilter, 2, 2 );
|
|
|
|
m_pBlur = (IDirect3DTexture8*)NxXbox::EngineGlobals.p_BlurSurface[2];
|
|
break;
|
|
}
|
|
|
|
case FM_HORIZ2_VERT2:
|
|
{
|
|
// Blur from the backbuffer to the 1/2 sized blur texture
|
|
D3DTexture* pTextureSrc = &m_BackBufferTexture;
|
|
D3DTexture* pTextureDst = &m_BlurTexture[1];
|
|
filter_copy( pTextureDst, pTextureSrc, 4, XFilter, 2, 2 );
|
|
|
|
// Blur from the previous blur texture to the next blur texture
|
|
pTextureSrc = &m_BlurTexture[1];
|
|
pTextureDst = &m_BlurTexture[2];
|
|
filter_copy( pTextureDst, pTextureSrc, 4, YFilter, 2, 2 );
|
|
|
|
m_pBlur = (IDirect3DTexture8*)NxXbox::EngineGlobals.p_BlurSurface[2];
|
|
break;
|
|
}
|
|
|
|
case FM_VERT2_HORIZ:
|
|
{
|
|
// Blur from the backbuffer to the 1/2 sized blur texture
|
|
D3DTexture* pTextureSrc = &m_BackBufferTexture;
|
|
D3DTexture* pTextureDst = &m_BlurTexture[1];
|
|
filter_copy( pTextureDst, pTextureSrc, 4, YFilter, 2, 2 );
|
|
|
|
// Blur from the previous blur texture to the next blur texture
|
|
pTextureSrc = &m_BlurTexture[1];
|
|
pTextureDst = &m_BlurTexture[2];
|
|
filter_copy( pTextureDst, pTextureSrc, 3, X141Filter, 2, 2 );
|
|
|
|
m_pBlur = (IDirect3DTexture8*)NxXbox::EngineGlobals.p_BlurSurface[2];
|
|
break;
|
|
}
|
|
|
|
case FM_HORIZ2_VERT:
|
|
{
|
|
// Blur from the backbuffer to the 1/2 sized blur texture
|
|
D3DTexture* pTextureSrc = &m_BackBufferTexture;
|
|
D3DTexture* pTextureDst = &m_BlurTexture[1];
|
|
filter_copy( pTextureDst, pTextureSrc, 4, XFilter, 2, 2 );
|
|
|
|
// Blur from the previous blur texture to the next blur texture
|
|
pTextureSrc = &m_BlurTexture[1];
|
|
pTextureDst = &m_BlurTexture[2]; // destination is next blur texture
|
|
filter_copy( pTextureDst, pTextureSrc, 3, Y141Filter, 2, 2 );
|
|
|
|
m_pBlur = (IDirect3DTexture8*)NxXbox::EngineGlobals.p_BlurSurface[2];
|
|
break;
|
|
}
|
|
|
|
case FM_BOX2_BOX2:
|
|
{
|
|
// Blur from the backbuffer to the 1/2 sized blur texture
|
|
D3DTexture* pTextureSrc = &m_BackBufferTexture;
|
|
D3DTexture* pTextureDst = &m_BlurTexture[0];
|
|
filter_copy( pTextureDst, pTextureSrc, 4, BoxFilter, 2, 1 );
|
|
|
|
// Blur from the previous blur texture to the next blur texture
|
|
pTextureSrc = &m_BlurTexture[0];
|
|
pTextureDst = &m_BlurTexture[1];
|
|
filter_copy( pTextureDst, pTextureSrc, 4, BoxFilter, 2, 2 );
|
|
|
|
m_pBlur = (IDirect3DTexture8*)NxXbox::EngineGlobals.p_BlurSurface[1];
|
|
break;
|
|
}
|
|
|
|
|
|
case FM_VERT2_HORIZ2_BOX2:
|
|
{
|
|
// Blur from the backbuffer to the 1/2 sized blur texture
|
|
D3DTexture* pTextureSrc = &m_BackBufferTexture;
|
|
D3DTexture* pTextureDst = &m_BlurTexture[1];
|
|
filter_copy( pTextureDst, pTextureSrc, 4, YFilter, 2, 2 );
|
|
|
|
// Blur from the previous blur texture to the next blur texture
|
|
pTextureSrc = &m_BlurTexture[1];
|
|
pTextureDst = &m_BlurTexture[2];
|
|
filter_copy( pTextureDst, pTextureSrc, 4, XFilter, 2, 2 );
|
|
|
|
// Blur from the previous blur texture to the next blur texture
|
|
pTextureSrc = &m_BlurTexture[2];
|
|
pTextureDst = &m_BlurTexture[3];
|
|
filter_copy( pTextureDst, pTextureSrc, 4, BoxFilter, 2, 2 );
|
|
|
|
m_pBlur = (IDirect3DTexture8*)NxXbox::EngineGlobals.p_BlurSurface[3];
|
|
break;
|
|
}
|
|
|
|
case FM_BOX2_BOX2_BOX2:
|
|
{
|
|
// Blur from the backbuffer to the 1/2 sized blur texture
|
|
D3DTexture* pTextureSrc = &m_BackBufferTexture;
|
|
D3DTexture* pTextureDst = &m_BlurTexture[1];
|
|
filter_copy( pTextureDst, pTextureSrc, 4, BoxFilter, 2, 2 );
|
|
|
|
// Blur from the previous blur texture to the next blur texture
|
|
pTextureSrc = &m_BlurTexture[1];
|
|
pTextureDst = &m_BlurTexture[2];
|
|
filter_copy( pTextureDst, pTextureSrc, 4, BoxFilter, 2, 2 );
|
|
|
|
// Blur from the previous blur texture to the next blur texture
|
|
pTextureSrc = &m_BlurTexture[2];
|
|
pTextureDst = &m_BlurTexture[3];
|
|
filter_copy( pTextureDst, pTextureSrc, 4, BoxFilter, 2, 2 );
|
|
|
|
m_pBlur = (IDirect3DTexture8*)NxXbox::EngineGlobals.p_BlurSurface[3];
|
|
break;
|
|
}
|
|
|
|
case FM_VERT2_HORIZ2_VERT2:
|
|
{
|
|
// Blur from the backbuffer to the 1/2 sized blur texture
|
|
D3DTexture* pTextureSrc = &m_BackBufferTexture;
|
|
D3DTexture* pTextureDst = &m_BlurTexture[1];
|
|
filter_copy( pTextureDst, pTextureSrc, 4, YFilter, 2, 2 );
|
|
|
|
// Blur from the previous blur texture to the next blur texture
|
|
pTextureSrc = &m_BlurTexture[1];
|
|
pTextureDst = &m_BlurTexture[2];
|
|
filter_copy( pTextureDst, pTextureSrc, 4, XFilter, 2, 2 );
|
|
|
|
// Blur from the previous blur texture to the next blur texture
|
|
pTextureSrc = &m_BlurTexture[2];
|
|
pTextureDst = &m_BlurTexture[3];
|
|
filter_copy( pTextureDst, pTextureSrc, 4, YFilter, 2, 2 );
|
|
|
|
m_pBlur = (IDirect3DTexture8*)NxXbox::EngineGlobals.p_BlurSurface[3];
|
|
break;
|
|
}
|
|
|
|
case FM_HORIZ2_VERT2_HORIZ2:
|
|
{
|
|
// Blur from the backbuffer to the 1/2 sized blur texture
|
|
D3DTexture* pTextureSrc = &m_BackBufferTexture;
|
|
D3DTexture* pTextureDst = &m_BlurTexture[1];
|
|
filter_copy( pTextureDst, pTextureSrc, 4, XFilter, 2, 2 );
|
|
|
|
// Blur from the previous blur texture to the next blur texture
|
|
pTextureSrc = &m_BlurTexture[1];
|
|
pTextureDst = &m_BlurTexture[2];
|
|
filter_copy( pTextureDst, pTextureSrc, 4, YFilter, 2, 2 );
|
|
|
|
// Blur from the previous blur texture to the next blur texture
|
|
pTextureSrc = &m_BlurTexture[2];
|
|
pTextureDst = &m_BlurTexture[3];
|
|
filter_copy( pTextureDst, pTextureSrc, 4, XFilter, 2, 2 );
|
|
|
|
m_pBlur = (IDirect3DTexture8*)NxXbox::EngineGlobals.p_BlurSurface[3];
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
m_pBlur = NULL;
|
|
break;
|
|
}
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
static HRESULT draw_focus_effect_using_planes( void )
|
|
{
|
|
// Make a D3DTexture wrapper around the depth buffer surface
|
|
// D3DTexture ZBufferTexture;
|
|
// XGSetTextureHeader( EngineGlobals.backbuffer_width, EngineGlobals.backbuffer_height, 1, 0,
|
|
// D3DFMT_LIN_A8B8G8R8, 0, &ZBufferTexture,
|
|
// EngineGlobals.p_ZStencilSurface->Data, EngineGlobals.backbuffer_width * 4 );
|
|
|
|
// Get size of blur texture for setting texture coords of final blur
|
|
D3DSURFACE_DESC descBlur;
|
|
m_pBlur->GetLevelDesc( 0, &descBlur );
|
|
float fOffsetX = 0.0f;
|
|
float fOffsetY = 0.5f / (float)descBlur.Height; // vertical blur
|
|
struct VERTEX
|
|
{
|
|
D3DXVECTOR4 p;
|
|
FLOAT tu0, tv0;
|
|
|
|
} v[4];
|
|
v[0].p = D3DXVECTOR4( -0.5f, -0.5f, 1.0f, 1.0f );
|
|
v[1].p = D3DXVECTOR4( EngineGlobals.backbuffer_width - 0.5f, -0.5f, 1.0f, 1.0f );
|
|
v[2].p = D3DXVECTOR4( -0.5f, EngineGlobals.backbuffer_height - 0.5f, 1.0f, 1.0f );
|
|
v[3].p = D3DXVECTOR4( EngineGlobals.backbuffer_width - 0.5f, EngineGlobals.backbuffer_height - 0.5f, 1.0f, 1.0f );
|
|
v[0].tu0 = fOffsetX; v[0].tv0 = fOffsetY;
|
|
v[1].tu0 = fOffsetX + (float)descBlur.Width; v[1].tv0 = fOffsetY;
|
|
v[2].tu0 = fOffsetX; v[2].tv0 = fOffsetY + (float)descBlur.Height;
|
|
v[3].tu0 = fOffsetX + (float)descBlur.Width; v[3].tv0 = fOffsetY + (float)descBlur.Height;
|
|
|
|
// Set pixel shader state
|
|
// float fAlphaOffset, fAlphaSlope, fBlueOffset, fBlueSlope;
|
|
// calculate_depth_mapping( m_fDepth0, m_fDepth1, &fAlphaOffset, &fAlphaSlope, &fBlueOffset, &fBlueSlope );
|
|
// float Constants[] =
|
|
// {
|
|
// 0.0f, 0.0f, fBlueOffset, fAlphaOffset, // offset
|
|
// 0.0f, 0.0f, fBlueSlope, 0.0f, // 1x
|
|
// 0.0f, 0.0f, 0.0f, 0.0f, // 4x
|
|
// 0.0f, 0.0f, 0.0f, fAlphaSlope, // 16x
|
|
// };
|
|
|
|
set_pixel_shader( 0 );
|
|
// EngineGlobals.p_Device->SetPixelShaderConstant( 0, Constants, 4 );
|
|
|
|
// Set render state
|
|
set_render_state( RS_ZWRITEENABLE, 0 );
|
|
set_render_state( RS_ZTESTENABLE, 1 );
|
|
set_render_state( RS_ALPHATESTENABLE, 0 );
|
|
set_render_state( RS_ALPHABLENDENABLE, 0 );
|
|
set_render_state( RS_ALPHACUTOFF, 0 );
|
|
// EngineGlobals.p_Device->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_ONE );
|
|
// EngineGlobals.p_Device->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
|
|
EngineGlobals.p_Device->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_ONE );
|
|
EngineGlobals.p_Device->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ZERO );
|
|
|
|
// Set texture state.
|
|
set_texture( 0, m_pBlur );
|
|
set_texture( 1, NULL );
|
|
set_texture( 2, NULL );
|
|
set_texture( 3, NULL );
|
|
|
|
set_render_state( RS_UVADDRESSMODE0, 0x00010001UL );
|
|
|
|
set_vertex_shader( D3DFVF_XYZRHW | D3DFVF_TEX1 );
|
|
|
|
// Render the screen-aligned quadrilateral
|
|
for( int vx = 0; vx < 4; ++vx )
|
|
{
|
|
v[vx].p.z = m_fDepth1;
|
|
}
|
|
EngineGlobals.p_Device->SetRenderState( D3DRS_ZFUNC, D3DCMP_LESSEQUAL );
|
|
EngineGlobals.p_Device->DrawPrimitiveUP( D3DPT_QUADSTRIP, 1, v, sizeof( VERTEX ));
|
|
|
|
// Render the screen-aligned quadrilateral
|
|
for( int vx = 0; vx < 4; ++vx )
|
|
{
|
|
v[vx].p.z = m_fDepth0;
|
|
}
|
|
EngineGlobals.p_Device->SetRenderState( D3DRS_ZFUNC, D3DCMP_GREATEREQUAL );
|
|
EngineGlobals.p_Device->DrawPrimitiveUP( D3DPT_QUADSTRIP, 1, v, sizeof( VERTEX ));
|
|
|
|
// Reset render states
|
|
EngineGlobals.p_Device->SetRenderState( D3DRS_ZFUNC, D3DCMP_LESSEQUAL );
|
|
|
|
set_render_state( RS_ALPHATESTENABLE, 1 );
|
|
set_render_state( RS_ALPHABLENDENABLE, 1 );
|
|
set_render_state( RS_ZWRITEENABLE, 1 );
|
|
set_render_state( RS_ZTESTENABLE, 1 );
|
|
|
|
set_pixel_shader( 0 );
|
|
|
|
set_texture( 0, NULL );
|
|
set_texture( 1, NULL );
|
|
set_texture( 2, NULL );
|
|
set_texture( 3, NULL );
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: DrawFocusRange()
|
|
// Desc: Choose the focus range by mapping z to a focus value using pixel
|
|
// shader arithmetic. See media/shaders/focus.psh for more details.
|
|
//
|
|
// High focus values leave the back-buffer unchanged.
|
|
// Low focus values blend in the blurred texture computed by Blur().
|
|
//-----------------------------------------------------------------------------
|
|
static HRESULT draw_focus_effect_using_range( void )
|
|
{
|
|
// Make a D3DTexture wrapper around the depth buffer surface
|
|
D3DTexture ZBufferTexture;
|
|
XGSetTextureHeader( EngineGlobals.backbuffer_width, EngineGlobals.backbuffer_height, 1, 0,
|
|
D3DFMT_LIN_A8B8G8R8, 0, &ZBufferTexture,
|
|
EngineGlobals.p_ZStencilSurface->Data, EngineGlobals.backbuffer_width * 4 );
|
|
|
|
// Get size of blur texture for setting texture coords of final blur
|
|
D3DSURFACE_DESC descBlur;
|
|
m_pBlur->GetLevelDesc( 0, &descBlur );
|
|
float fOffsetX = 0.0f;
|
|
float fOffsetY = 0.5f / (float)descBlur.Height; // vertical blur
|
|
struct VERTEX
|
|
{
|
|
D3DXVECTOR4 p;
|
|
FLOAT tu0, tv0;
|
|
FLOAT tu1, tv1;
|
|
} v[4];
|
|
v[0].p = D3DXVECTOR4( -0.5f, -0.5f, 1.0f, 1.0f );
|
|
v[1].p = D3DXVECTOR4( EngineGlobals.backbuffer_width - 0.5f, -0.5f, 1.0f, 1.0f );
|
|
v[2].p = D3DXVECTOR4( -0.5f, EngineGlobals.backbuffer_height - 0.5f, 1.0f, 1.0f );
|
|
v[3].p = D3DXVECTOR4( EngineGlobals.backbuffer_width - 0.5f, EngineGlobals.backbuffer_height - 0.5f, 1.0f, 1.0f );
|
|
v[0].tu0 = 0.0f; v[0].tv0 = 0.0f;
|
|
v[1].tu0 = (float)EngineGlobals.backbuffer_width; v[1].tv0 = 0.0f;
|
|
v[2].tu0 = 0.0f; v[2].tv0 = (float)EngineGlobals.backbuffer_height;
|
|
v[3].tu0 = (float)EngineGlobals.backbuffer_width; v[3].tv0 = (float)EngineGlobals.backbuffer_height;
|
|
v[0].tu1 = fOffsetX; v[0].tv1 = fOffsetY;
|
|
v[1].tu1 = fOffsetX + (float)descBlur.Width; v[1].tv1 = fOffsetY;
|
|
v[2].tu1 = fOffsetX; v[2].tv1 = fOffsetY + (float)descBlur.Height;
|
|
v[3].tu1 = fOffsetX + (float)descBlur.Width; v[3].tv1 = fOffsetY + (float)descBlur.Height;
|
|
|
|
// Set pixel shader state
|
|
float fAlphaOffset, fAlphaSlope, fBlueOffset, fBlueSlope;
|
|
calculate_depth_mapping( m_fDepth0, m_fDepth1, &fAlphaOffset, &fAlphaSlope, &fBlueOffset, &fBlueSlope );
|
|
float Constants[] =
|
|
{
|
|
0.0f, 0.0f, fBlueOffset, fAlphaOffset, // offset
|
|
0.0f, 0.0f, fBlueSlope, 0.0f, // 1x
|
|
0.0f, 0.0f, 0.0f, 0.0f, // 4x
|
|
0.0f, 0.0f, 0.0f, fAlphaSlope, // 16x
|
|
};
|
|
|
|
set_pixel_shader( PixelShaderFocusIntegrate );
|
|
EngineGlobals.p_Device->SetPixelShaderConstant( 0, Constants, 4 );
|
|
|
|
// Set render state
|
|
set_render_state( RS_ZWRITEENABLE, 0 );
|
|
set_render_state( RS_ZTESTENABLE, 0 );
|
|
set_render_state( RS_ALPHATESTENABLE, 1 );
|
|
set_render_state( RS_ALPHABLENDENABLE, 1 );
|
|
set_render_state( RS_ALPHACUTOFF, 1 );
|
|
EngineGlobals.p_Device->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_ONE );
|
|
EngineGlobals.p_Device->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
|
|
|
|
// Set texture state.
|
|
set_texture( 0, &ZBufferTexture );
|
|
set_texture( 1, m_pBlur );
|
|
set_texture( 2, NULL );
|
|
set_texture( 3, NULL );
|
|
|
|
set_render_state( RS_UVADDRESSMODE0, 0x00010001UL );
|
|
set_render_state( RS_UVADDRESSMODE1, 0x00010001UL );
|
|
set_render_state( RS_UVADDRESSMODE2, 0x00010001UL );
|
|
set_render_state( RS_UVADDRESSMODE3, 0x00010001UL );
|
|
|
|
// Render the screen-aligned quadrilateral
|
|
set_vertex_shader( D3DFVF_XYZRHW | D3DFVF_TEX4 );
|
|
EngineGlobals.p_Device->DrawPrimitiveUP( D3DPT_QUADSTRIP, 1, v, sizeof( VERTEX ));
|
|
|
|
// Reset render states
|
|
set_render_state( RS_ALPHATESTENABLE, 1 );
|
|
set_render_state( RS_ALPHABLENDENABLE, 1 );
|
|
set_render_state( RS_ZWRITEENABLE, 1 );
|
|
set_render_state( RS_ZTESTENABLE, 1 );
|
|
|
|
set_pixel_shader( 0 );
|
|
|
|
set_texture( 0, NULL );
|
|
set_texture( 1, NULL );
|
|
set_texture( 2, NULL );
|
|
set_texture( 3, NULL );
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: DrawFocusLookup()
|
|
// Desc: Choose the focus range by mapping z through a lookup texture.
|
|
//
|
|
// See media/shaders/focuslookup.psh for more detail.
|
|
//
|
|
// This technique has lower performance than using DrawFocus(),
|
|
// but the focus values can be arbitrary, rather than the
|
|
// limited types of z-to-focus value mappings available with
|
|
// pixel shader arithmetic.
|
|
//
|
|
// High focus values leave the back-buffer unchanged.
|
|
// Low focus values blend in the blurred texture computed by Blur().
|
|
//-----------------------------------------------------------------------------
|
|
static HRESULT draw_focus_effect_using_lookup( void )
|
|
{
|
|
// Make a D3DTexture wrapper around the depth buffer surface
|
|
D3DTexture ZBufferTexture;
|
|
XGSetTextureHeader( EngineGlobals.backbuffer_width, EngineGlobals.backbuffer_height, 1, 0,
|
|
D3DFMT_LIN_A8B8G8R8, 0, &ZBufferTexture,
|
|
EngineGlobals.p_ZStencilSurface->Data, EngineGlobals.backbuffer_width * 4 );
|
|
|
|
// Get size of blur texture for setting texture coords of final blur
|
|
D3DSURFACE_DESC descBlur;
|
|
m_pBlur->GetLevelDesc( 0, &descBlur );
|
|
FLOAT fOffsetX = 0.0f;
|
|
FLOAT fOffsetY = 0.5f / (FLOAT)descBlur.Height; // vertical blur
|
|
|
|
// Define a set of vertices to draw a quad in screenspace
|
|
struct VERTEX
|
|
{
|
|
D3DXVECTOR4 p;
|
|
FLOAT tu0, tv0;
|
|
FLOAT tu1, tv1;
|
|
FLOAT tu2, tv2;
|
|
FLOAT tu3, tv3;
|
|
} v[4];
|
|
v[0].p = D3DXVECTOR4( -0.5f, -0.5f, 1.0f, 1.0f );
|
|
v[1].p = D3DXVECTOR4( EngineGlobals.backbuffer_width - 0.5f, -0.5f, 1.0f, 1.0f );
|
|
v[2].p = D3DXVECTOR4( -0.5f, EngineGlobals.backbuffer_height - 0.5f, 1.0f, 1.0f );
|
|
v[3].p = D3DXVECTOR4( EngineGlobals.backbuffer_width - 0.5f, EngineGlobals.backbuffer_height - 0.5f, 1.0f, 1.0f );
|
|
v[0].tu0 = 0.0f; v[0].tv0 = 0.0f;
|
|
v[1].tu0 = (float)EngineGlobals.backbuffer_width; v[1].tv0 = 0.0f;
|
|
v[2].tu0 = 0.0f; v[2].tv0 = (float)EngineGlobals.backbuffer_height;
|
|
v[3].tu0 = (float)EngineGlobals.backbuffer_width; v[3].tv0 = (float)EngineGlobals.backbuffer_height;
|
|
|
|
// tu1 and tv1 are ignored
|
|
// offset final set of texture coords to apply an additional blur
|
|
v[0].tu2 = -fOffsetX; v[0].tv2 = -fOffsetY;
|
|
v[1].tu2 = -fOffsetX + (FLOAT)descBlur.Width; v[1].tv2 = -fOffsetY;
|
|
v[2].tu2 = -fOffsetX; v[2].tv2 = -fOffsetY + (FLOAT)descBlur.Height;
|
|
v[3].tu2 = -fOffsetX + (FLOAT)descBlur.Width; v[3].tv2 = -fOffsetY + (FLOAT)descBlur.Height;
|
|
v[0].tu3 = fOffsetX; v[0].tv3 = fOffsetY;
|
|
v[1].tu3 = fOffsetX + (FLOAT)descBlur.Width; v[1].tv3 = fOffsetY;
|
|
v[2].tu3 = fOffsetX; v[2].tv3 = fOffsetY + (FLOAT)descBlur.Height;
|
|
v[3].tu3 = fOffsetX + (FLOAT)descBlur.Width; v[3].tv3 = fOffsetY + (FLOAT)descBlur.Height;
|
|
|
|
// Set pixel shader
|
|
set_pixel_shader( PixelShaderFocusLookupIntegrate );
|
|
|
|
// Set texture state
|
|
set_texture( 0, &ZBufferTexture );
|
|
set_texture( 1, m_pTextureFocusRange );
|
|
set_texture( 2, m_pBlur );
|
|
set_texture( 3, m_pBlur );
|
|
|
|
set_render_state( RS_UVADDRESSMODE0, 0x00010001UL );
|
|
set_render_state( RS_UVADDRESSMODE1, 0x00010001UL );
|
|
set_render_state( RS_UVADDRESSMODE2, 0x00010001UL );
|
|
set_render_state( RS_UVADDRESSMODE3, 0x00010001UL );
|
|
|
|
// Set render state
|
|
set_render_state( RS_ZWRITEENABLE, 0 );
|
|
set_render_state( RS_ZTESTENABLE, 0 );
|
|
set_render_state( RS_ALPHATESTENABLE, 1 );
|
|
set_render_state( RS_ALPHABLENDENABLE, 1 );
|
|
set_render_state( RS_ALPHACUTOFF, 1 );
|
|
EngineGlobals.p_Device->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_ONE );
|
|
EngineGlobals.p_Device->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
|
|
|
|
// Render the screen-aligned quadrilateral
|
|
set_vertex_shader( D3DFVF_XYZRHW | D3DFVF_TEX4 );
|
|
EngineGlobals.p_Device->DrawPrimitiveUP( D3DPT_QUADSTRIP, 1, v, sizeof( VERTEX ));
|
|
|
|
// Reset render states
|
|
set_render_state( RS_ALPHATESTENABLE, 1 );
|
|
set_render_state( RS_ALPHABLENDENABLE, 1 );
|
|
set_render_state( RS_ZWRITEENABLE, 1 );
|
|
set_render_state( RS_ZTESTENABLE, 1 );
|
|
|
|
set_pixel_shader( 0 );
|
|
|
|
set_texture( 0, NULL );
|
|
set_texture( 1, NULL );
|
|
set_texture( 2, NULL );
|
|
set_texture( 3, NULL );
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
void set_focus_blur_focus( Mth::Vector & focal_point, float offset, float near_depth, float far_depth )
|
|
{
|
|
Mth::Vector diff = focal_point - Mth::Vector( EngineGlobals.cam_position[0], EngineGlobals.cam_position[1], EngineGlobals.cam_position[2] );
|
|
Mth::Vector unit_diff = diff.Normalize();
|
|
|
|
Mth::Vector p0 = focal_point + (( offset - near_depth ) * unit_diff );
|
|
Mth::Vector p1 = focal_point + (( offset + far_depth ) * unit_diff );
|
|
|
|
D3DXVECTOR4 v0( p0[X], p0[Y], p0[Z], 1.0f );
|
|
D3DXVECTOR4 v1( p1[X], p1[Y], p1[Z], 1.0f );
|
|
|
|
D3DXVec4Transform( &v0, &v0, (D3DXMATRIX*)&EngineGlobals.view_matrix );
|
|
D3DXVec4Transform( &v0, &v0, (D3DXMATRIX*)&EngineGlobals.projection_matrix );
|
|
|
|
D3DXVec4Transform( &v1, &v1, (D3DXMATRIX*)&EngineGlobals.view_matrix );
|
|
D3DXVec4Transform( &v1, &v1, (D3DXMATRIX*)&EngineGlobals.projection_matrix );
|
|
|
|
m_fDepth0 = v0.z / v0.w;
|
|
m_fDepth1 = v1.z / v1.w;
|
|
|
|
// If a z value ends up > 1.0, it is likely from intersecting the near plane, in which case just set it to 0.
|
|
if( m_fDepth0 > 1.0f )
|
|
m_fDepth0 = 0.0f;
|
|
|
|
// printf( "%.4f %.4f\n", m_fDepth0, m_fDepth1 );
|
|
|
|
// If the two values are sufficiently close, it will cause problems since they have
|
|
// to get quantized down. We have to ensure that ( 1 / ( d1 - d0 )) < 16, that is ( d1 - d0 ) > ( 1 / 16 ).
|
|
// m_fDepth0 = m_fDepth1 - 0.0625f;
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
void start_focus_blur( void )
|
|
{
|
|
D3DDevice_SetRenderTarget( NxXbox::EngineGlobals.p_RenderSurface, NxXbox::EngineGlobals.p_ZStencilSurface );
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
void finish_focus_blur( void )
|
|
{
|
|
// If the focus blur is active, we want to render into a the blur buffer, otherwise into the regular frame buffer.
|
|
if(( EngineGlobals.focus_blur > 0 ) && ( EngineGlobals.focus_blur_duration > 1 ))
|
|
{
|
|
EngineGlobals.p_Device->BlockUntilIdle();
|
|
|
|
// Store and reset the min filter for each stage.
|
|
DWORD min_filter[4];
|
|
for( int s = 0; s < 4; ++s )
|
|
{
|
|
D3DDevice_GetTextureStageState( s, D3DTSS_MINFILTER, &min_filter[s] );
|
|
D3DDevice_SetTextureStageState( s, D3DTSS_MINFILTER, D3DTEXF_LINEAR );
|
|
}
|
|
|
|
// First step is to render the back buffer into the blur texture.
|
|
// fill_focus_range_texture( false );
|
|
|
|
focus_blur();
|
|
|
|
// draw_focus_effect_using_range();
|
|
// draw_focus_effect_using_lookup();
|
|
draw_focus_effect_using_planes();
|
|
|
|
// Restore the min filter for each stage.
|
|
for( int s = 0; s < 4; ++s )
|
|
{
|
|
D3DDevice_SetTextureStageState( s, D3DTSS_MINFILTER, min_filter[s] );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
void start_screen_blur( void )
|
|
{
|
|
// If the screen blur is active, we want to render into a the blur buffer, otherwise into the regular frame buffer.
|
|
if(( EngineGlobals.screen_blur > 0 ) && ( EngineGlobals.screen_blur_duration > 1 ))
|
|
{
|
|
D3DDevice_SetRenderTarget( NxXbox::EngineGlobals.p_BlurSurface[0], NxXbox::EngineGlobals.p_ZStencilSurface );
|
|
}
|
|
else
|
|
{
|
|
D3DDevice_SetRenderTarget( NxXbox::EngineGlobals.p_RenderSurface, NxXbox::EngineGlobals.p_ZStencilSurface );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
void finish_screen_blur( void )
|
|
{
|
|
// If the screen blur is active, we want to render into a the blur buffer, otherwise into the regular frame buffer.
|
|
if(( EngineGlobals.screen_blur > 0 ) && ( EngineGlobals.screen_blur_duration > 1 ))
|
|
{
|
|
EngineGlobals.p_Device->BlockUntilIdle();
|
|
|
|
// Now that everything has been drawn, set the backbuffer as the rendertarget, and draw the poly on top of it.
|
|
D3DDevice_SetRenderTarget( NxXbox::EngineGlobals.p_RenderSurface, NxXbox::EngineGlobals.p_ZStencilSurface );
|
|
|
|
NxXbox::set_blend_mode( NxXbox::vBLEND_MODE_BLEND );
|
|
|
|
// Turn on clamping so that the linear textures work
|
|
NxXbox::set_render_state( RS_UVADDRESSMODE0, 0x00010001UL );
|
|
|
|
// Use a default vertex and pixel shader
|
|
NxXbox::set_vertex_shader( D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1 );
|
|
NxXbox::set_pixel_shader( PixelShader4 );
|
|
|
|
// Select the texture (flush first, since the blur texture is linear).
|
|
NxXbox::set_texture( 0, NULL );
|
|
NxXbox::set_texture( 0, (IDirect3DTexture8*)NxXbox::EngineGlobals.p_BlurSurface[0] );
|
|
|
|
// Setup up the vertices.
|
|
struct sBlurVert
|
|
{
|
|
float sx,sy,sz;
|
|
float rhw;
|
|
uint32 color;
|
|
float tu,tv;
|
|
};
|
|
|
|
sBlurVert vertices[4];
|
|
|
|
uint32 alpha = ( 0xFF - EngineGlobals.screen_blur ) / 2;
|
|
alpha = ( alpha < 0x20 ) ? 0x20 : alpha;
|
|
|
|
vertices[0].sx = 0;
|
|
vertices[0].sy = 0;
|
|
vertices[0].sz = 0.0f;
|
|
vertices[0].rhw = 1.0f;
|
|
vertices[0].color = ( alpha << 24 ) | 0x808080;
|
|
vertices[0].tu = 0.0f;
|
|
vertices[0].tv = 0.0f;
|
|
|
|
vertices[1] = vertices[0];
|
|
vertices[1].sx = 640;
|
|
vertices[1].tu = 640.0f;
|
|
|
|
vertices[2] = vertices[0];
|
|
vertices[2].sy = 480;
|
|
vertices[2].tv = 480.0f;
|
|
|
|
vertices[3] = vertices[1];
|
|
vertices[3].sy = vertices[2].sy;
|
|
vertices[3].tv = vertices[2].tv;
|
|
|
|
// Adjust if we are in letterbox mode.
|
|
if( NxXbox::EngineGlobals.letterbox_active )
|
|
{
|
|
vertices[0].sy += NxXbox::EngineGlobals.backbuffer_height / 8;
|
|
vertices[1].sy += NxXbox::EngineGlobals.backbuffer_height / 8;
|
|
vertices[0].tv += (float)( NxXbox::EngineGlobals.backbuffer_height / 8 );
|
|
vertices[1].tv += (float)( NxXbox::EngineGlobals.backbuffer_height / 8 );
|
|
|
|
vertices[2].sy -= NxXbox::EngineGlobals.backbuffer_height / 8;
|
|
vertices[3].sy -= NxXbox::EngineGlobals.backbuffer_height / 8;
|
|
vertices[2].tv -= (float)( NxXbox::EngineGlobals.backbuffer_height / 8 );
|
|
vertices[3].tv -= (float)( NxXbox::EngineGlobals.backbuffer_height / 8 );
|
|
}
|
|
|
|
// Draw the vertices.
|
|
set_render_state( RS_CULLMODE, D3DCULL_NONE );
|
|
set_render_state( RS_ZWRITEENABLE, 0 );
|
|
set_render_state( RS_ZTESTENABLE, 0 );
|
|
|
|
D3DDevice_DrawVerticesUP( D3DPT_TRIANGLESTRIP, 4, vertices, sizeof( sBlurVert ));
|
|
|
|
// Reflush linear texture.
|
|
NxXbox::set_texture( 0, NULL );
|
|
}
|
|
}
|
|
|
|
|
|
} // namespace NxXbox
|