📄 ca_water.cpp
字号:
/*********************************************************************NVMH2****
Path: C:\Dev\devrel\Nv_sdk_4\Dx8\NVEffectsBrowser\Effects\CA_RGB_Plasmas
File: CA_Water.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:
3/17/01 - Greg James - This is fun stuff!
The class is getting a bit bloated & could use a good parent class.
******************************************************************************/
#include <crtdbg.h>
#include "eb_file.h" // for GetFilePath() and Load..Shader()
#include "CA_Water.h"
#include "nvtex.h"
#include "..\..\..\CommonSrc\NV_Error.h" // for FDebug
#include "Constants.h"
#include "PixelConstants.h"
using namespace nv_objects;
using namespace std;
// Resolution of the calculations is that of the initial file
// loaded. This can be any power of 2 in width and height.
#define INITIAL_FILENAME "start.tga"
////////////////////////////////////////////////////////////////////
#ifndef ASSERT_IF_FAILED
#define ASSERT_IF_FAILED( hres ) \
{ \
if( FAILED(hres) ) \
assert( false ); \
}
#endif
////////////////////////////////////////////////////////////////////
CA_Water::CA_Water()
{
m_bWireframe = false;
m_pInitialStateTexture = NULL;
m_pDropletTexture = NULL;
m_dwVertexShader = 0;
m_dwEqualWeight_PostMultShader = 0;
m_dwNeighborForceCalc_1 = 0;
m_dwNeighborForceCalc_2 = 0;
m_dwApplyForceShader = 0;
m_dwApplyVelocityShader = 0;
m_dwPSH_NormalMapCreate2_Scale = 0;
m_pVertexBuffer = NULL;
mpBackbufferColor = 0 ;
mpBackbufferDepth = 0 ;
m_bDrawOutput = true;
for ( int i = 0; i < kMaxNumTargets; ++i )
{
mpTextureFiltered[i] = 0;
mpFilterTarget [i] = 0;
}
}
CA_Water::~CA_Water()
{
Free();
}
/////////////////////////////////////////////////////////
HRESULT CA_Water::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 CA_Water::ReleaseNVTextures( nv_objects::NVTexture *** pTex, int num )
{
for( int i=0; i < num; i++ )
{
if( *pTex[i] != NULL )
{
SAFE_DELETE( *pTex[i] );
*pTex[i] = NULL;
}
}
}
void CA_Water::ReleaseNVTextures()
{
const int NUM = 2;
nv_objects::NVTexture ** pTex[NUM];
pTex[0] = &m_pInitialStateTexture;
pTex[1] = &m_pDropletTexture;
ReleaseNVTextures( pTex, NUM );
}
HRESULT CA_Water::LoadNVTexture( LPDIRECT3DDEVICE8 pD3DDev, nv_objects::NVTexture * pTex, EBString filename )
{
HRESULT hr = S_OK;
hr = pTex->CreateFromFile( pD3DDev, GetFilePath( filename.c_str() ) );
if (FAILED(hr))
{
m_strLastError = "Couldn't load texture: ";
m_strLastError += filename;
assert( false );
}
return( hr );
}
void CA_Water::LoadRulesAndOtherMaps()
{
// This one does not re-create the render targets
// if new maps of different resolution are loaded
// while running. Only Initialize() creates
// the render targets.
ReleaseNVTextures();
////////////////////////////////////////////////
m_pInitialStateTexture = new nv_objects::NVTexture();
assert( m_pInitialStateTexture != NULL );
LoadNVTexture( m_pD3DDev, m_pInitialStateTexture, INITIAL_FILENAME );
////////////////////////////////////////////////
m_pDropletTexture = new nv_objects::NVTexture();
assert( m_pInitialStateTexture != NULL );
LoadNVTexture( m_pD3DDev, m_pDropletTexture, "Droplet1.bmp" );
}
std::string CA_Water::GetFilePath( const std::string& strFileName )
{
return( effect_api::GetFilePath( strFileName ) );
}
HRESULT CA_Water::LoadAndCreateShader(const std::string& strFilePath,
const DWORD* pDeclaration,
DWORD Usage,
EBSHADERTYPE ShaderType,
DWORD* pHandle)
{
return( effect_api::LoadAndCreateShader( m_pD3DDev, strFilePath, pDeclaration, Usage, ShaderType, pHandle ));
}
HRESULT CA_Water::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
assert( pDev != NULL );
m_pD3DDev = pDev;
m_pD3DDev->AddRef(); // released on Free()
m_Droplets.clear();
// See class header for what each variable represents!
m_bReset = true;
m_bAnimate = true;
m_bSingleStep = false;
m_bSlow = true;
m_bWrap = true;
m_bCreateNormalMap = true;
m_bDrawOutput = true;
m_bMulticolor = false;
m_bUseNormalMapMethod2 = true;
m_bApplyInteriorBoundaries = true;
m_eRenderMode = FULLSCREEN_FINALOUT;
m_nSkipInterval = 0;
m_nFlipState = 0;
m_fNrmlSTScale = 0.8f;
m_dwSleepDelay = 20;
m_fEqRestore_factor = 0.5f;
/////////////////////
m_fBlend = 0.25f;
m_fVelFactor = 0.50f;
m_fBlurDist = 0.5f;
m_fEqRestore_factor = 0.5f;
m_fDropletFreq = 0.175f;
/////////////////////////////////
m_dwCurrentVertexShader = NULL;
m_pCurrentRulesTex = NULL;
/////////////////////////////////
// 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("TexCoord_4_Offset.vso"), &Declaration[0], 0, SHADERTYPE_VERTEX, &m_dwVertexShader);
ASSERT_IF_FAILED(hr);
if (FAILED(hr))
return hr;
hr = LoadAndCreateShader(GetFilePath("EqualWeightCombine_PostMult.pso"), NULL, 0, SHADERTYPE_PIXEL,
&(m_dwEqualWeight_PostMultShader));
ASSERT_IF_FAILED(hr);
if (FAILED(hr))
return hr;
// Load pixel shaders for neighbor force calc
// 1st pass = 3 samples & center
hr = LoadAndCreateShader(GetFilePath("NeighborForceCalc.pso"), NULL, 0, SHADERTYPE_PIXEL,
&(m_dwNeighborForceCalc_1 ) );
ASSERT_IF_FAILED(hr);
if (FAILED(hr))
return hr;
// 2nd pass of force calc = 1 sample & center
hr = LoadAndCreateShader(GetFilePath("NeighborForceCalc2.pso"), NULL, 0, SHADERTYPE_PIXEL,
&(m_dwNeighborForceCalc_2 ) );
ASSERT_IF_FAILED(hr);
if (FAILED(hr))
return hr;
// pixel shader for applying force to height field
hr = LoadAndCreateShader(GetFilePath("ApplyForceShader.pso"), NULL, 0, SHADERTYPE_PIXEL,
&(m_dwApplyForceShader ) );
ASSERT_IF_FAILED(hr);
if (FAILED(hr))
return hr;
// pixel shader for applying force to height field
hr = LoadAndCreateShader(GetFilePath("ApplyVelocityShader.pso"), NULL, 0, SHADERTYPE_PIXEL,
&(m_dwApplyVelocityShader ) );
ASSERT_IF_FAILED(hr);
if (FAILED(hr))
return hr;
// pixel shader for creating normal maps with scalable red & green
// components for the s and t axis
hr = LoadAndCreateShader(GetFilePath("NormalMapCreate2_Scale.pso"), NULL, 0, SHADERTYPE_PIXEL,
&(m_dwPSH_NormalMapCreate2_Scale ) );
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 );
D3DXVECTOR4 commonconst( 0.0f, 0.5f, 1.0f, 2.0f );
m_pD3DDev->SetVertexShaderConstant( CV_CONSTS_1, &commonconst, 1);
/////////////////////////////////
// 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);
SetInitialRenderStates();
return hr;
}
HRESULT CA_Water::Free()
{
SAFE_RELEASE( m_pVertexBuffer ); // sets pointers to null after delete
ReleaseNVTextures();
m_Droplets.clear();
if (m_pD3DDev)
{
m_pD3DDev->DeleteVertexShader(m_dwVertexShader);
m_pD3DDev->DeletePixelShader(m_dwEqualWeight_PostMultShader);
m_pD3DDev->DeletePixelShader(m_dwNeighborForceCalc_1);
m_pD3DDev->DeletePixelShader(m_dwNeighborForceCalc_2);
m_pD3DDev->DeletePixelShader(m_dwApplyForceShader);
m_pD3DDev->DeletePixelShader(m_dwApplyVelocityShader);
m_pD3DDev->DeletePixelShader(m_dwPSH_NormalMapCreate2_Scale);
m_dwVertexShader = 0;
m_dwEqualWeight_PostMultShader = 0;
m_dwNeighborForceCalc_1 = 0;
m_dwNeighborForceCalc_2 = 0;
m_dwApplyForceShader = 0;
m_dwApplyVelocityShader = 0;
m_dwPSH_NormalMapCreate2_Scale = 0;
for (int i = 0; i < kMaxNumTargets; ++i)
{
SAFE_RELEASE(mpFilterTarget[i]);
SAFE_RELEASE(mpTextureFiltered[i]);
}
SAFE_RELEASE(mpBackbufferColor);
SAFE_RELEASE(mpBackbufferDepth);
SAFE_RELEASE(m_pD3DDev); // we AddRef()'d in Initialize
}
m_pD3DDev = NULL;
return S_OK;
}
HRESULT CA_Water::Start()
{
return S_OK;
}
HRESULT CA_Water::CreateTextureRenderTarget()
{
HRESULT hr;
_ASSERT( mpBackbufferColor != NULL );
_ASSERT( mpBackbufferDepth != NULL );
// get the description for the texture we want to filter
D3DSURFACE_DESC ddsd;
m_pInitialStateTexture->GetTexture()->GetLevelDesc(0, &ddsd);
int i;
for( i=0; i < kMaxNumTargets; i++ )
{
if( mpFilterTarget[i] != NULL )
{
SAFE_RELEASE(mpFilterTarget[i]);
mpFilterTarget[i] = NULL;
}
if( mpTextureFiltered[i] != NULL )
{
SAFE_RELEASE(mpTextureFiltered[i]);
mpTextureFiltered[i] = NULL;
}
}
// create new textures just like the current texture
for( i = 0; i < kMaxNumTargets; i++ )
{
hr = m_pD3DDev->CreateTexture(ddsd.Width, ddsd.Height, 1,
D3DUSAGE_RENDERTARGET, D3DFMT_X8R8G8B8,
D3DPOOL_DEFAULT, &mpTextureFiltered[i]);
if (FAILED(hr))
{
m_strLastError = "Can't CreateTexture!\n";
assert(false);
return E_FAIL;
}
hr = mpTextureFiltered[i]->GetSurfaceLevel(0, &mpFilterTarget[i]);
if (FAILED(hr))
{
m_strLastError = "Can't Get to top-level texture!\n";
assert(false);
return E_FAIL;
}
// set our render target to the new and shiny textures without depth
hr = m_pD3DDev->SetRenderTarget(mpFilterTarget[i], NULL);
if (FAILED(hr))
{
m_strLastError = "Can't SetRenderTarget to new surface!\n";
assert(false);
return E_FAIL;
}
}
// switch back to conventional back-buffer
hr = m_pD3DDev->SetRenderTarget(mpBackbufferColor, mpBackbufferDepth);
if (FAILED(hr))
{
m_strLastError = "Can't SetRenderTarget to original back-buffer surfaces!\n";
assert(false);
return E_FAIL;
}
return S_OK;
}
bool CA_Water::Keyboard(DWORD dwKey, UINT nFlags, bool bDown)
{
// Return true if keyboard key handled.
char charcode;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -