📄 gameoflife.cpp
字号:
/*********************************************************************NVMH2****
Path: C:\DEV\devrel\NV_SDK_4\DX8\NVEffectsBrowser\Effects\GameOfLife
File: GameOfLife.cpp
Copyright (C) 1999, 2000 NVIDIA Corporation
This file is provided without support, instruction, or implied warranty of any
kind. NVIDIA makes no guarantee of its fitness for a particular purpose and is
not liable under any circumstances for any damages or loss whatsoever arising
from the use or inability to use this file or items derived from it.
Comments:
Thanks to Matthias Wloka for his FilterBlit example, from which the texel
offsets and basic vertex and pixel shaders were derived.
The variables:
m_pTexSrc == texture source for rendering (step N)
m_pTexFinalTarg == target surface for result (step N+1)
m_pIntermediateTarg == target surface for rendering intermediate calc
(neighbor accumulation)
m_pIntermediateSrc == same surface as above, this is the texture corresponding
to it, for use as a rendering source
m_pOutputSrc == optional additional color re-map for display
m_pOutputTarg == target surface for optional color remapping
are pointers to the appropriate textures and surfaces for rendering to and
from to run the game. Since a texture cannot be used as a render source
and target at the same time, the m_pTexSrc and m_pTexFinalTarg variables
ping-pong back and forth to use the previous result in rendering the next
frame.
******************************************************************************/
#include <crtdbg.h>
#include "eb_effect.h"
#include "nvtex.h"
#include "GameOfLife.h"
#include "..\..\..\CommonSrc\NV_Error.h" // for FDebug
#include "Constants.h"
#include "PixelConstants.h"
using namespace nv_objects;
using namespace std;
#define RULE_TABLE_NAME "RuleTable.bmp";
#define OUTPUT_TABLE_NAME "OUTPUT_map_1.bmp"
#define INITIAL_FILENAME "start.bmp"
#define ASSERT_IF_FAILED( hres ) \
if( FAILED(hres) ) \
assert( false );
////////////////////////////////////////////////////////////////////
DECLARE_EFFECT_MAIN()
extern "C"
{
__declspec(dllexport) unsigned int GetNumEffects()
{
return static_cast<unsigned int>(CGameOfLife::NUM_EFFECT_OPTIONS);
}
__declspec(dllexport) EBEffect* CreateEffect(unsigned int EffectNum)
{
return new CGameOfLife(static_cast<CGameOfLife::eFilterOptions>(EffectNum));
}
}
////////////////////////////////////////////////////////////////////
CGameOfLife::CGameOfLife( eFilterOptions initDisplayOption )
{
meDisplayOption = initDisplayOption;
m_bWireframe = false;
m_pInitialStateTexture = NULL;
m_pRulesTexture = NULL ;
m_pOutputMapTexture = NULL;
m_dwVertexShader = 0;
m_dwEqualWeightCombineShader = 0;
m_dwDependentGB = 0;
m_pVertexBuffer = NULL;
mpBackbufferColor = 0 ;
mpBackbufferDepth = 0 ;
for ( int i = 0; i < kMaxNumPasses; ++i )
{
mpTextureFiltered[i] = 0;
mpFilterTarget [i] = 0;
}
m_strEffectLocation = "Pixel Shaders\\Cellular Automata";
m_strEffectVertexShader = GetFilePath("GameOfLife.nvv");
switch (meDisplayOption)
{
case GAME_OF_LIFE_EFFECT:
m_strEffectName = "Game of Life";
m_strEffectPixelShader = GetFilePath("EqualWeightCombine.nvp");
break;
default:
m_strEffectName = "Game of Life (unknown)";
m_strEffectPixelShader = GetFilePath("EqualWeightCombine.nvp");
break;
}
}
CGameOfLife::~CGameOfLife()
{
Free();
}
/////////////////////////////////////////////////////////
HRESULT CGameOfLife::ConfirmDevice(D3DCAPS8* pCaps, DWORD dwBehavior, D3DFORMAT Format)
{
// check vertex shading support
if(D3DSHADER_VERSION_MAJOR(pCaps->VertexShaderVersion) < 1)
{
m_strLastError = "Device does not support vertex shaders!";
return E_FAIL;
}
if(D3DSHADER_VERSION_MINOR(pCaps->VertexShaderVersion) < 1)
{
m_strLastError = "Device does not support 1.1 vertex shaders!";
return E_FAIL;
}
// check simultaneous texture support
if(pCaps->MaxSimultaneousTextures < 4)
{
m_strLastError = "Device does not support 4 simultaneous textures!";
return E_FAIL;
}
// check pixel shader support
if(D3DSHADER_VERSION_MAJOR(pCaps->PixelShaderVersion) < 1)
{
m_strLastError = "Device does not support pixel shaders!";
return E_FAIL;
}
if(D3DSHADER_VERSION_MINOR(pCaps->PixelShaderVersion) < 1)
{
m_strLastError = "Device does not support 1.1 pixel shaders!";
return E_FAIL;
}
if(pCaps->MaxTextureBlendStages < 8)
{
m_strLastError = "Device does not support 8 register combiners!";
return E_FAIL;
}
return S_OK;
}
void CGameOfLife::UpdateProperties()
{
EBEffect::UpdateProperties();
AddProperty(new EBProperty("W - Wireframe", OBJECT_MEMBER(m_bWireframe), EBTYPE_BOOL_PROP));
AddProperty(new EBProperty("Home - Restart", OBJECT_MEMBER( m_bReset ), EBTYPE_BOOL_PROP ));
AddProperty(new EBProperty("G - Go/Pause anim", OBJECT_MEMBER( m_bAnimate ), EBTYPE_BOOL_PROP ));
AddProperty(new EBProperty("SPC - Single step", OBJECT_MEMBER( m_bSingleStep ), EBTYPE_BOOL_PROP ));
AddProperty(new EBProperty("B - Border wrapping", OBJECT_MEMBER( m_bWrap ), EBTYPE_BOOL_PROP ));
AddProperty(new EBTriggerProperty("Hit F1 for more options"));
// Vertex shaders
m_pVertexShaderEnum->AddEnumerant(new EBEnumValue(m_pVertexShaderEnum, "Neighbor Calc Offsets",
GetFilePath("GameOfLife.nvv"), EBTYPE_STRING_PROP));
// Pixel shaders
m_pPixelShaderEnum->AddEnumerant(new EBEnumValue(m_pPixelShaderEnum, "Equal Weight",
GetFilePath("EqualWeightCombine.nvp"), EBTYPE_STRING_PROP));
m_pPixelShaderEnum->AddEnumerant(new EBEnumValue(m_pPixelShaderEnum, "Dependent GB",
GetFilePath("DependentGB.nvp"), EBTYPE_STRING_PROP));
}
void CGameOfLife::LoadRulesAndOtherMaps()
{
// Load "rules" texture which determines how the neighbor accumulation
// maps to new pixels
// Also reload output color map
// Also reload initial conditions map
EBString filename;
HRESULT hr;
if( m_pRulesTexture != NULL )
{
SAFE_DELETE( m_pRulesTexture );
m_pRulesTexture = NULL;
}
if( m_pOutputMapTexture != NULL )
{
SAFE_DELETE( m_pOutputMapTexture );
m_pOutputMapTexture = NULL;
}
if( m_pInitialStateTexture != NULL )
{
SAFE_DELETE( m_pInitialStateTexture );
m_pInitialStateTexture = NULL;
}
filename = RULE_TABLE_NAME;
m_pRulesTexture = new NVTexture();
assert( m_pRulesTexture != NULL );
hr = m_pRulesTexture->CreateFromFile(m_pD3DDev, GetFilePath( filename.c_str() ) );
if (FAILED(hr))
{
m_strLastError = "Couldn't load texture: ";
m_strLastError += filename;
assert( false );
return;
}
filename = OUTPUT_TABLE_NAME;
m_pOutputMapTexture = new NVTexture();
assert( m_pOutputMapTexture != NULL );
hr = m_pOutputMapTexture->CreateFromFile(m_pD3DDev, GetFilePath( filename.c_str() ) );
if (FAILED(hr))
{
m_strLastError = "Couldn't load texture: ";
m_strLastError += filename;
assert( false );
return;
}
filename = INITIAL_FILENAME;
m_pInitialStateTexture = new NVTexture();
assert( m_pInitialStateTexture != NULL );
hr = m_pInitialStateTexture->CreateFromFile(m_pD3DDev, GetFilePath( filename.c_str() ) );
ASSERT_IF_FAILED(hr);
if (FAILED(hr))
{
m_strLastError = "Couldn't load texture: ";
m_strLastError += filename;
assert( false );
return;
}
// Not re-creating render targets. This could be problem if
// you reload an initial texture with different resolution while
// the simulation is running. The new resolution will not be
// reflected in the render targets
}
HRESULT CGameOfLife::Initialize( LPDIRECT3DDEVICE8 pDev )
{
// Called when effect is selected from list in browser
// Free() is called when effect is de-selected
int i;
HRESULT hr;
// get the device
m_pD3DDev = pDev;
pDev->AddRef(); // released on Free()
m_bReset = true;
m_bAnimate = true;
m_bSingleStep = false;
m_bSlow = false;
m_bFarther = false;
m_bWrap = false;
m_eRenderMode = FULLSCREEN_NEIGHBOR_CALC;
m_nSkipInterval = 0;
m_nFlipState = 0;
// create the vertex and pixel shaders
vector<DWORD> Declaration;
Declaration.push_back(D3DVSD_STREAM(0));
Declaration.push_back(D3DVSD_REG(0, D3DVSDT_FLOAT3));
Declaration.push_back(D3DVSD_REG(1, D3DVSDT_FLOAT2));
Declaration.push_back(D3DVSD_END());
m_dwVertexShader = 0;
hr = LoadAndCreateShader(GetFilePath("GameOfLife.vso"), &Declaration[0], 0, SHADERTYPE_VERTEX, &m_dwVertexShader);
ASSERT_IF_FAILED(hr);
if (FAILED(hr))
return hr;
hr = LoadAndCreateShader(GetFilePath("EqualWeightCombine.pso"), NULL, 0, SHADERTYPE_PIXEL,
&(m_dwEqualWeightCombineShader));
ASSERT_IF_FAILED(hr);
if (FAILED(hr))
return hr;
// Dependent 2D lookup pixel shader for logic rules:
hr = LoadAndCreateShader(GetFilePath("DependentGB.pso"), NULL, 0, SHADERTYPE_PIXEL,
&(m_dwDependentGB ) );
ASSERT_IF_FAILED(hr);
if (FAILED(hr))
return hr;
// get a pointer to the current back-buffer (so we can restore it later)
m_pD3DDev->GetRenderTarget( &mpBackbufferColor );
m_pD3DDev->GetDepthStencilSurface( &mpBackbufferDepth );
//gjdel EBString filename;
// load the initial conditions texture map, rules map, and
// optional final color re-mapping map
// The "rules" texture determines how the neighbor accumulation
// maps to new pixels in the next generation
LoadRulesAndOtherMaps();
hr = CreateTextureRenderTarget();
ASSERT_IF_FAILED(hr);
////////////////////////////////////////////////////////////////////////////
D3DSURFACE_DESC ddsd;
m_pInitialStateTexture->GetTexture()->GetLevelDesc(0, &ddsd);
// create vertex buffer
hr = m_pD3DDev->CreateVertexBuffer( 4 * sizeof(QuadVertex), D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC, 0, D3DPOOL_DEFAULT, &m_pVertexBuffer);
ASSERT_IF_FAILED(hr);
if (FAILED(hr))
return hr;
QuadVertex *pBuff;
if (m_pVertexBuffer)
{
hr = m_pVertexBuffer->Lock(0, 4 * sizeof(QuadVertex),(BYTE**)&pBuff, 0);
ASSERT_IF_FAILED(hr);
if (FAILED(hr))
{
m_strLastError = "Couldn't lock buffer!";
return hr;
}
float uv_base;
float uv_max;
uv_base = 0.0f;
uv_max = 1.0f;
for (i = 0; i < 4; ++i)
{
pBuff->Position = D3DXVECTOR3((i==0 || i==3) ? -1.0f : 1.0f,
(i<2) ? -1.0f : 1.0f,
0.0f);
pBuff->Tex = D3DXVECTOR2((i==0 || i==3) ? uv_base : uv_max ,
(i<2) ? uv_max : uv_base );
pBuff++;
}
m_pVertexBuffer->Unlock();
}
CreateAndWriteUVOffsets(ddsd.Width, ddsd.Height);
// set up render state: disable all except texture stage 0 (see below)
for(i = 0; i < 4; i++ )
{
m_pD3DDev->SetTextureStageState(i, D3DTSS_COLOROP, D3DTOP_DISABLE);
m_pD3DDev->SetTextureStageState(i, D3DTSS_COLORARG1, D3DTA_TEXTURE);
m_pD3DDev->SetTextureStageState(i, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
m_pD3DDev->SetTextureStageState(i, D3DTSS_ADDRESSU, D3DTADDRESS_CLAMP);
m_pD3DDev->SetTextureStageState(i, D3DTSS_ADDRESSV, D3DTADDRESS_CLAMP);
m_pD3DDev->SetTextureStageState(i, D3DTSS_ADDRESSW, D3DTADDRESS_CLAMP);
m_pD3DDev->SetTextureStageState(i, D3DTSS_MAGFILTER, D3DTEXF_POINT );
m_pD3DDev->SetTextureStageState(i, D3DTSS_MINFILTER, D3DTEXF_POINT );
m_pD3DDev->SetTextureStageState(i, D3DTSS_MIPFILTER, D3DTEXF_NONE );
m_pD3DDev->SetTextureStageState(i,D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE );
m_pD3DDev->SetTextureStageState(i,D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_PASSTHRU | i );
m_pD3DDev->SetTextureStageState(i, D3DTSS_RESULTARG, D3DTA_CURRENT );
}
// Set wrap to zero - It will wrap anyway and avoid the problems of
// setting cylindrical wrapping (D3DRS_WRAP0, D3DWRAP_U == cylindrical)
// for texture coords > 1.0f
// For wrapped textures, you should use only the D3DTSS_ADDRESSU/V/W
// states, unless you are doing cube environment mapping.
m_pD3DDev->SetRenderState(D3DRS_WRAP0, 0);
m_pD3DDev->SetRenderState(D3DRS_WRAP1, 0);
m_pD3DDev->SetRenderState(D3DRS_WRAP2, 0);
m_pD3DDev->SetRenderState(D3DRS_WRAP3, 0);
m_pD3DDev->SetRenderState(D3DRS_WRAP4, 0);
m_pD3DDev->SetRenderState(D3DRS_WRAP5, 0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -