📄 ca_gameoflife.cpp
字号:
m_pD3DDev->SetTexture(0, mpTextureFiltered[m_nTargetCellField] );
hr = m_pD3DDev->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 2);
break;
case FULLSCREEN_NEIGHBOR_CALC:
// Draw quad over full display
D3DXMatrixScaling(&matWorld, 2.0f, 2.0f, 1.0f);
D3DXMatrixMultiply(&matWorldViewProj, &matWorld, &matViewProj);
D3DXMatrixTranspose(&matWorldViewProj, &matWorldViewProj);
m_pD3DDev->SetVertexShaderConstant(CV_WORLDVIEWPROJ_0, &matWorldViewProj(0, 0), 4);
// reset offsets to 0 (ie no offsets)
offset.x = 0.0f;
m_pD3DDev->SetVertexShaderConstant(CV_UV_OFFSET_TO_USE, &offset, 1);
m_pD3DDev->SetTexture(0, mpTextureFiltered[ m_nTargetIntermediate ] );
hr = m_pD3DDev->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 2);
break;
case ALL_TOGETHER :
// draw quad in upper left corner: original texture
D3DXMatrixTranslation(&matWorld, -1.0f, 1.0f, 0.0f);
D3DXMatrixMultiply(&matWorldViewProj, &matWorld, &matViewProj);
D3DXMatrixTranspose(&matWorldViewProj, &matWorldViewProj);
m_pD3DDev->SetVertexShaderConstant(CV_WORLDVIEWPROJ_0, &matWorldViewProj(0, 0), 4);
// reset offsets to 0 (ie no offsets)
offset.x = 0.0f;
m_pD3DDev->SetVertexShaderConstant(CV_UV_OFFSET_TO_USE, &offset, 1);
m_pD3DDev->SetTexture(0, m_pInitialStateTexture );
hr = m_pD3DDev->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 2);
// draw quads in the other corners, use generated textures
for (int j = 0; j < 3; ++j)
{
D3DXMatrixTranslation(&matWorld, (j == 2) ? -1.0f : 1.0f,
(j == 0) ? 1.0f : -1.0,
0.0f);
D3DXMatrixMultiply(&matWorldViewProj, &matWorld, &matViewProj);
D3DXMatrixTranspose(&matWorldViewProj, &matWorldViewProj);
m_pD3DDev->SetVertexShaderConstant(CV_WORLDVIEWPROJ_0, &matWorldViewProj(0, 0), 4);
pSrcTex = mpTextureFiltered[m_nTargetIntermediate]; // upper right corner
if( j==1 )
pSrcTex = mpTextureFiltered[m_nTargetCellField]; // lower right
else if( j==2 )
pSrcTex = mpTextureFiltered[m_nTargetCellField]; // lower left
if( pSrcTex != 0 )
{
m_pD3DDev->SetTexture(0, pSrcTex );
hr = m_pD3DDev->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 2);
}
}
break;
}; // switch for display config
}
else
{
// skip rendering this frame
// Set normal render target in case the app is doing more rendering
// to the window
hr = m_pD3DDev->SetRenderTarget(mpBackbufferColor, mpBackbufferDepth);
nSkip++;
}
return( hr );
}
HRESULT CA_GameOfLife::DoSingleTimeStep_3Pass()
{
HRESULT hr;
int i;
float pix_mult[4];
// variable for writing to constant memory which uv-offsets to use
D3DXVECTOR4 offset(0.0f, 1.0f, 0.0f, 0.0f);
m_pD3DDev->SetVertexShaderConstant( CV_ONOFF_1, &offset, 1);
// even if wireframe mode, render to texture as solid
m_pD3DDev->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID );
/////////////////////////////////////////////////////////////////
DWORD wrapval = m_bWrap ? D3DTADDRESS_WRAP : D3DTADDRESS_CLAMP;
for( i=0; i < 4 ; i++ )
{
m_pD3DDev->SetTextureStageState(i, D3DTSS_ADDRESSU, wrapval);
m_pD3DDev->SetTextureStageState(i, D3DTSS_ADDRESSV, wrapval);
}
/////////////////////////////////////////////////////////
// First, write the source texture into the blue channel
// I do this in preparation for a 2D dependent green-blue lookup
// into a "rules" texture which governs how old pixels spawn
// or die into new pixels.
// The logic for the game of life depends on 9 pixels: the source
// pixel and it's 8 neightbors. These are accumulated in three
// passes.
hr = m_pD3DDev->SetRenderTarget( mpFilterTarget[m_nTargetIntermediate], NULL);
// Set simple pixel shader to multiply input texture by RGB = 0,0,1
// to select only blue, and add a small component of green + blue to
// that in order to properly offset the dependent green-blue lookup
// to be done in a later stage
SetPixelShader( m_SHI_TexelsToBlueWithBias );
m_pD3DDev->SetTexture(0, m_pTexSrc );
m_pD3DDev->SetRenderState( D3DRS_ALPHABLENDENABLE, false );
// Render using offsets of zero
offset.x = 0.0f;
m_pD3DDev->SetVertexShaderConstant(CV_UV_OFFSET_TO_USE, &offset, 1);
// draw the fan with normal texture coords
hr = m_pD3DDev->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 2);
////////////////////////////////////////////////////
// Excitation of Game Of Life simulation
// Every 400 steps draw the cell field into itself
// at offset coordinates to spawn new activity.
static int count = 0;
if( m_bOccasionalExcitation )
{
count++;
if( count > 400 )
{
// Additive blending
m_pD3DDev->SetRenderState( D3DRS_ALPHABLENDENABLE, true );
m_pD3DDev->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_ONE );
m_pD3DDev->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ONE );
// Render using scrolling offsets of a few texels
offset.x = 4.0f;
m_pD3DDev->SetVertexShaderConstant(CV_UV_OFFSET_TO_USE, &offset, 1);
// draw the fan with normal texture coords
hr = m_pD3DDev->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 2);
count = 0;
}
}
/////////////////////////////////////////////////////////////////
// Render 1st set of neighbors
// Add in nearest neighbors
hr = SetPixelShader( m_SHI_EqualWeightCombineShader );
hr = m_pD3DDev->SetRenderTarget( mpFilterTarget[m_nTargetIntermediate], NULL);
ASSERT_IF_FAILED(hr);
// Add result of pixel operations into the dest texture:
// This adds the new green component from neighbor sampling
// into the previous blue on/off result from above
m_pD3DDev->SetRenderState( D3DRS_ALPHABLENDENABLE, true );
m_pD3DDev->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_ONE );
m_pD3DDev->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ONE );
// Render set of neighbors using bilinear filtering to sample
// equal weight of all 8 neighbors in just 4 texture samples
offset.x = 3.0f;
m_pD3DDev->SetVertexShaderConstant(CV_UV_OFFSET_TO_USE, &offset, 1);
pix_mult[0] = 0.0f; // red
pix_mult[1] = 0.25f; // green
pix_mult[2] = 0.0f; // blue
pix_mult[3] = 0.0f; // alpha
hr = m_pD3DDev->SetPixelShaderConstant( PCN_MULTFACTOR_1, &pix_mult, 1 );
ASSERT_IF_FAILED(hr);
hr = m_pD3DDev->SetPixelShaderConstant( PCN_MULTFACTOR_2, &pix_mult, 1 );
ASSERT_IF_FAILED(hr);
m_pD3DDev->SetTexture(0, m_pTexSrc );
m_pD3DDev->SetTexture(1, m_pTexSrc );
m_pD3DDev->SetTexture(2, m_pTexSrc );
m_pD3DDev->SetTexture(3, m_pTexSrc );
// Enable bilinear to count 8 neighbors with 4 samples
for( i=0; i < 4; i++ )
{
m_pD3DDev->SetTextureStageState(i, D3DTSS_MAGFILTER, D3DTEXF_LINEAR );
m_pD3DDev->SetTextureStageState(i, D3DTSS_MINFILTER, D3DTEXF_LINEAR );
}
// draw the fan with displaced texture coordinates
hr = m_pD3DDev->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 2);
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
// Now do dependent 2D lookup into rules texture to set new
// source pixels;
// Write white colors to final target
m_pD3DDev->SetRenderState( D3DRS_ALPHABLENDENABLE, false );
hr = SetPixelShader( m_SHI_DependentGB );
ASSERT_IF_FAILED( hr );
hr = m_pD3DDev->SetRenderTarget( mpFilterTarget[m_nTargetCellField], NULL);
ASSERT_IF_FAILED(hr);
// Render using offsets of zero
offset.x = 0.0f;
m_pD3DDev->SetVertexShaderConstant(CV_UV_OFFSET_TO_USE, &offset, 1);
m_pD3DDev->SetTexture(0, mpTextureFiltered[ m_nTargetIntermediate ] );
m_pD3DDev->SetTexture(1, m_pRulesTexture );
m_pD3DDev->SetTextureStageState(0, D3DTSS_MAGFILTER, D3DTEXF_POINT );
m_pD3DDev->SetTextureStageState(0, D3DTSS_MINFILTER, D3DTEXF_POINT );
m_pD3DDev->SetTextureStageState(0, D3DTSS_ADDRESSU, D3DTADDRESS_CLAMP);
m_pD3DDev->SetTextureStageState(0, D3DTSS_ADDRESSV, D3DTADDRESS_CLAMP);
m_pD3DDev->SetTextureStageState(1, D3DTSS_MAGFILTER, D3DTEXF_POINT );
m_pD3DDev->SetTextureStageState(1, D3DTSS_MINFILTER, D3DTEXF_POINT );
m_pD3DDev->SetTextureStageState(1, D3DTSS_ADDRESSU, D3DTADDRESS_CLAMP);
m_pD3DDev->SetTextureStageState(1, D3DTSS_ADDRESSV, D3DTADDRESS_CLAMP);
// Draw the quad to render in all new cells
hr = m_pD3DDev->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 2);
ASSERT_IF_FAILED(hr);
////////////////////////////////////////////////////////////
// Flip the state variable for the next round of rendering
switch( m_nFlipState )
{
case 0:
m_nFlipState = 1;
break;
case 1:
m_nFlipState = 2;
break;
case 2:
m_nFlipState = 1;
break;
}
return hr;
}
void CA_GameOfLife::CreateAndWriteUVOffsets(int width, int height)
{
// This sets vertex shader constants used to displace the
// source texture over several additive samples. This is
// used to accumulate neighboring texel information that we
// need to run the game - the 8 surrounding texels, and the
// single source texel which will either spawn or die in the
// next generation.
// Label the texels as follows, for a source texel "e" that
// we want to compute for the next generation:
//
// abc
// def
// ghi:
// first the easy one: no offsets for sampling center
// occupied or unoccupied
// Use index offset value 0.0 to access these in the
// vertex shader.
m_fPerTexelWidth = 1.0f/static_cast<float>(width);
m_fPerTexelHeight = 1.0f/static_cast<float>(height);
HRESULT hr;
// Change the multiplier to 2 or 3 to spread the texel sampling. This
// has the effect of running several independent "games" in neighboring
// texels, which do not affect eachother.
m_fPerTexelWidth *= 1; // 1 = no change - run standard game of life
m_fPerTexelHeight *= 1;
float woff, hoff;
woff = m_fPerTexelWidth/2.0f;
hoff = m_fPerTexelHeight/2.0f;
// Ofset set 0 : center texel sampling
float noOffsetX[4] = { woff,woff,woff,woff };
float noOffsetY[4] = { hoff,hoff,hoff,hoff };
// Offset set 1: Nearest neighbors - b,d,f,h texels
// Use index offset 1.0 to access these
float type1OffsetX[4] = { - m_fPerTexelWidth + woff,
m_fPerTexelWidth + woff,
0.0f + woff,
0.0f + woff };
float type1OffsetY[4] = { 0.0f + hoff,
0.0f + hoff,
m_fPerTexelHeight + hoff,
- m_fPerTexelHeight + hoff };
// These are a,c,g,i texels == diagonal neightbors
// Use index offset 2.0 to use these
float type2OffsetX[4] = { - m_fPerTexelWidth,
- m_fPerTexelWidth,
m_fPerTexelWidth,
m_fPerTexelWidth };
float type2OffsetY[4] = { - m_fPerTexelHeight,
m_fPerTexelHeight,
m_fPerTexelHeight,
- m_fPerTexelHeight };
// These offsets are for use with bilinear filtering
// of the neighbors, to sample all 8 neighbors in
// one pass instead of two. Bilinear averages the
// two bordering texels, but the coordinate must be
// exactly on the texel border to make this work.
// [0] = on the border of the ab texels
// [1] = between cf texels
// [2] = between ih texels
// [3] = between gd texels
float type3OffsetX[4] = { - m_fPerTexelWidth/2.0f + woff,
m_fPerTexelWidth + woff,
m_fPerTexelWidth/2.0f + woff,
- m_fPerTexelWidth + woff };
float type3OffsetY[4] = { - m_fPerTexelHeight + hoff,
- m_fPerTexelHeight/2.0f + hoff,
m_fPerTexelHeight + hoff,
m_fPerTexelHeight/2.0f + hoff };
// drifing uppder
// hoff += -m_fPerTexelHeight;
/*
float type4OffsetX[4] = { - m_fPerTexelWidth + woff,
m_fPerTexelWidth + woff,
0.0f + woff,
0.0f + woff };
float type4OffsetY[4] = { 0.0f + hoff,
0.0f + hoff,
m_fPerTexelHeight + hoff,
- m_fPerTexelHeight + hoff };
*/
hoff += -3.5f * m_fPerTexelHeight;
float type4OffsetX[4] = { - m_fPerTexelWidth + woff,
m_fPerTexelWidth + woff,
0.0f + woff,
0.0f + woff };
float type4OffsetY[4] = { 0.0f + hoff,
0.0f + hoff,
m_fPerTexelHeight + hoff,
- m_fPerTexelHeight + hoff };
// write all these offsets to constant memory
for (int i = 0; i < 4; ++i)
{
D3DXVECTOR4 noOffset( noOffsetX[i], noOffsetY[i], 0.0f, 0.0f);
D3DXVECTOR4 type1Offset(type1OffsetX[i], type1OffsetY[i], 0.0f, 0.0f);
D3DXVECTOR4 type2Offset(type2OffsetX[i], type2OffsetY[i], 0.0f, 0.0f);
D3DXVECTOR4 type3Offset(type3OffsetX[i], type3OffsetY[i], 0.0f, 0.0f);
D3DXVECTOR4 type4Offset(type4OffsetX[i], type4OffsetY[i], 0.0f, 0.0f);
m_pD3DDev->SetVertexShaderConstant(CV_UV_T0_NO_OFFSET + 5*i, &noOffset, 1);
m_pD3DDev->SetVertexShaderConstant(CV_UV_T0_TYPE1 + 5*i, &type1Offset, 1);
m_pD3DDev->SetVertexShaderConstant(CV_UV_T0_TYPE2 + 5*i, &type2Offset, 1);
m_pD3DDev->SetVertexShaderConstant(CV_UV_T0_TYPE3 + 5*i, &type3Offset, 1);
m_pD3DDev->SetVertexShaderConstant(CV_UV_T0_TYPE4 + 5*i, &type4Offset, 1);
}
// Set pixel shader consts:
// This constant is a color mask - It is used to only keep the
// green component for the accumulation of neighbor texel info.
// Mult the source green by 1/8 to get the average of the 8 samples,
// with a max of 1.0f
/// R,G,B,A
float pix_mult[4] = { 0.0f, 0.125f, 0.0f, 0.0f };
hr = m_pD3DDev->SetPixelShaderConstant( PCN_MULTFACTOR_1, &pix_mult, 1 );
ASSERT_IF_FAILED(hr);
hr = m_pD3DDev->SetPixelShaderConstant( PCN_MULTFACTOR_2, &pix_mult, 1 );
ASSERT_IF_FAILED(hr);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -