📄 ch15p1_simpleclouds.cpp
字号:
/*
#############################################################################
Ch15p1_SimpleClouds.cpp: a program that demonstrates the water algorithm,
without any annoying bells and/or whistles.
#############################################################################
*/
// include files ////////////////////////////////////////////////////////////
#define STRICT
#include <vector>
#include <stdio.h>
#include <math.h>
#include <D3DX8.h>
#include "D3DApp.h"
#include "D3DFile.h"
#include "D3DFont.h"
#include "D3DUtil.h"
#include "DXUtil.h"
#include "D3DHelperFuncs.h"
#include "Ch15p1_resource.h"
#include "CommonFuncs.h"
using namespace std;
const int NUMOCTAVES = 4;
//===========================================================================
//
// class: CCloudOctave. Represents a single octave of Perlin noise for our
// cloud.
//
//===========================================================================
class CCloudOctave
{
public:
CCloudOctave(int iOctaveSize, LPDIRECT3DDEVICE8 pDev,
LPDIRECT3DVERTEXBUFFER8 pvbQuad);
virtual ~CCloudOctave();
LPDIRECT3DTEXTURE8 m_ptexOctave; // each octave of noise
LPDIRECT3DTEXTURE8 m_ptexSmoothOctave; // smoothed octave
HRESULT GenerateRegularNoise();
HRESULT SmoothLayer();
int m_iOctaveSize;
private:
LPDIRECT3DDEVICE8 m_pd3dDevice;
LPDIRECT3DVERTEXBUFFER8 m_pvbQuad;
};
typedef vector<CCloudOctave *> CloudOctaveVector;
CCloudOctave::CCloudOctave(int iOctaveSize, LPDIRECT3DDEVICE8 pDev,
LPDIRECT3DVERTEXBUFFER8 pvbQuad)
{
HRESULT hr;
// squirrel away the device and vertex buffer pointers for later
m_pd3dDevice = pDev;
m_pvbQuad = pvbQuad;
m_iOctaveSize = iOctaveSize;
OutputDebugString("\nCCloudOctave::CCloudOctave: Allocating Cloud Octave Textures...");
if (FAILED(hr = D3DXCreateTexture(pDev, iOctaveSize, iOctaveSize,
1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT,
&m_ptexSmoothOctave))) throw(hr);
if (FAILED(hr = D3DXCreateTexture(pDev, iOctaveSize, iOctaveSize,
1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &m_ptexOctave))) throw(hr);
}
CCloudOctave::~CCloudOctave()
{
OutputDebugString("\nCCloudOctave::CCloudOctave: Freeing Cloud Octave Textures...");
// the device and vertex buffers do not belong to us, so we don't
// delete them.
SAFE_RELEASE(m_ptexSmoothOctave);
SAFE_RELEASE(m_ptexOctave);
}
HRESULT CCloudOctave::SmoothLayer()
{
return(SmoothRenderCopy(m_ptexOctave, m_ptexSmoothOctave,
m_iOctaveSize, m_iOctaveSize, m_pd3dDevice, m_pvbQuad));
}
/****************************************************************************
GenerateRegularNoise: Creates what Kim Pallister refers to as "Salt and
Pepper" noise. Each texel is assigned a random shade of gray.
****************************************************************************/
HRESULT CCloudOctave::GenerateRegularNoise()
{
HRESULT hr;
// lock the textures
D3DLOCKED_RECT lockedrect;
::ZeroMemory(&lockedrect, sizeof(lockedrect));
if (FAILED(hr = m_ptexOctave->LockRect(0, &lockedrect, NULL, 0))) return(hr);
// our texture surface is now locked, and we can use the pitch to traverse it.
unsigned char *pSurfBits = static_cast<unsigned char *>(lockedrect.pBits);
int index=0;
for (int y=0; y < m_iOctaveSize; y++) {
for (int x=0; x < m_iOctaveSize; x++) {
/*
// Unremark this (and remark out the section below this) to generate
// color clouds instead of normal clouds.
char cIntensityR = (char)((1.0f+Noise3D(x,y,0)) * 128);
char cIntensityG = (char)((1.0f+Noise3D(x,y,1)) * 128);
char cIntensityB = (char)((1.0f+Noise3D(x,y,2)) * 128);
// the intensity determines the color of this texel
pSurfBits[index++] = cIntensityB; // blue
pSurfBits[index++] = cIntensityG; // green
pSurfBits[index++] = cIntensityR; // red
pSurfBits[index++] = 0xff; // alpha
*/
// this chunk of code generates normal clouds
char cIntensity = (char)((1.0f+Noise2D(x,y)) * 128);
// the intensity determines the color of this texel
pSurfBits[index++] = cIntensity; // blue
pSurfBits[index++] = cIntensity; // green
pSurfBits[index++] = cIntensity; // red
pSurfBits[index++] = 0xff; // alpha
}
// next line
index += lockedrect.Pitch - (m_iOctaveSize*4);
}
// unlock texture surface
if (FAILED(hr = m_ptexOctave->UnlockRect(0))) return(hr);
return S_OK;
}
//===========================================================================
//
// class: CCloud. This class represents a cloud texture.
//
//===========================================================================
class CCloud
{
public:
// pointers must be set to NULL so that SAFE_RELEASE doesn't try
// to release something that isn't there.
CCloud() : m_ptexFinal(NULL), m_ptexComposite(NULL), m_pvbAlphaBlendingQuad(NULL),
m_iTextureSize(0) { }
virtual ~CCloud() { InvalidateDeviceObjects(); }
HRESULT RestoreDeviceObjects(LPDIRECT3DDEVICE8 pDev,
LPDIRECT3DVERTEXBUFFER8 pvbQuad, int iNumOctaves, int iTextureSize);
HRESULT InvalidateDeviceObjects();
void RenderToFinalTexture();
// you can change this to m_ptexComposite to see what it looks like
// without squaring.
LPDIRECT3DTEXTURE8 GetFinalTexture() { return(m_ptexComposite); }
CloudOctaveVector m_vOctaves; // individual cloud layers
private:
LPDIRECT3DTEXTURE8 m_ptexComposite; // the composite noise texture
LPDIRECT3DTEXTURE8 m_ptexFinal; // the final cloud texture (composite squared)
void CompositeLayers();
void SquareCompositeLayer();
LPDIRECT3DVERTEXBUFFER8 m_pvbAlphaBlendingQuad; // 0.5 alpha quad
int m_iTextureSize;
LPDIRECT3DDEVICE8 m_pd3dDevice;
LPDIRECT3DVERTEXBUFFER8 m_pvbQuad; // normal (opaque) quad for rendering textures
};
void CCloud::CompositeLayers()
{
// get surface interfaces
LPDIRECT3DSURFACE8 psurfComposite;
m_ptexComposite->GetSurfaceLevel(0, &psurfComposite);
// set new rendering target & clear
m_pd3dDevice->SetRenderTarget(psurfComposite, NULL);
m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_TARGET, 0x000000, 1.0f, 0L );
// set up orthogonal projection matrix
SetupOrthoProjForRenderCopy(m_pd3dDevice, m_iTextureSize, m_iTextureSize);
// begin rendering the scene
if (FAILED(m_pd3dDevice->BeginScene())) return;
m_pd3dDevice->SetStreamSource(0, m_pvbAlphaBlendingQuad, sizeof(VERTEX_XYZ_DIFFUSE_TEX1));
m_pd3dDevice->SetVertexShader(D3DFVF_XYZ_DIFFUSE_TEX1);
// now alpha blend (using a factor of 0.5) all other octaves onto the final dest.
// D3D gets the alpha value from our vertices' alpha components.
// set up texture stages for simple texture stage copy
m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
m_pd3dDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
m_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
m_pd3dDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
m_pd3dDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
m_pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);
m_pd3dDevice->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_SRCCOLOR);
for (CloudOctaveVector::iterator i = m_vOctaves.begin(); i != m_vOctaves.end(); ++i) {
CCloudOctave *octave = (*i);
// set the source texture active
m_pd3dDevice->SetTexture(0, octave->m_ptexSmoothOctave);
// this "blits" the texture
m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, 2 );
}
// end scene
m_pd3dDevice->EndScene();
// release the dest surface
psurfComposite->Release();
}
void CCloud::SquareCompositeLayer()
{
// get surface interfaces
LPDIRECT3DSURFACE8 psurfFinal;
m_ptexFinal->GetSurfaceLevel(0, &psurfFinal);
// set new rendering target & clear
m_pd3dDevice->SetRenderTarget(psurfFinal, NULL);
m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_TARGET, 0x000000, 1.0f, 0L );
// set up orthogonal projection matrix
SetupOrthoProjForRenderCopy(m_pd3dDevice, m_iTextureSize, m_iTextureSize);
// begin rendering the scene
if (FAILED(m_pd3dDevice->BeginScene())) return;
m_pd3dDevice->SetStreamSource(0, m_pvbQuad, sizeof(VERTEX_XYZ_DIFFUSE_TEX1));
m_pd3dDevice->SetVertexShader(D3DFVF_XYZ_DIFFUSE_TEX1);
m_pd3dDevice->SetTexture(0,m_ptexComposite);
m_pd3dDevice->SetTextureStageState(0,D3DTSS_COLOROP, D3DTOP_SELECTARG1);
m_pd3dDevice->SetTextureStageState(0,D3DTSS_COLORARG1, D3DTA_TEXTURE);
m_pd3dDevice->SetTextureStageState(0,D3DTSS_COLORARG2, D3DTA_DIFFUSE);
m_pd3dDevice->SetTexture(1,m_ptexComposite);
m_pd3dDevice->SetTextureStageState(1,D3DTSS_COLOROP, D3DTOP_SELECTARG1);
m_pd3dDevice->SetTextureStageState(1,D3DTSS_COLORARG1, D3DTA_TEXTURE);
m_pd3dDevice->SetTextureStageState(1,D3DTSS_COLORARG2, D3DTA_CURRENT);
m_pd3dDevice->SetTexture(2,NULL);
m_pd3dDevice->SetTextureStageState(2,D3DTSS_COLOROP, D3DTOP_DISABLE);
m_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
// this "blits" the texture
m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, 2 );
// end scene
m_pd3dDevice->EndScene();
// release the dest surface
psurfFinal->Release();
}
void CCloud::RenderToFinalTexture()
{
// get the current depth buffer (we have to pass this into SetRenderTarget
// so we don't inadvertently drop our depth buffer.)
LPDIRECT3DSURFACE8 pDepthSurf;
m_pd3dDevice->GetDepthStencilSurface(&pDepthSurf);
// get the current rendering target (we'll set it back later)
LPDIRECT3DSURFACE8 pOldRenderTarget;
m_pd3dDevice->GetRenderTarget(&pOldRenderTarget);
// combine all the noise layers together onto m_ptexComposite
CompositeLayers();
// now square the composite texture and put it on the final texture.
//SquareCompositeLayer();
// set the rendering target back to the old target.
m_pd3dDevice->SetRenderTarget(pOldRenderTarget, pDepthSurf);
m_pd3dDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
pOldRenderTarget->Release();
// release the depth surface interface.
pDepthSurf->Release();
}
HRESULT CCloud::RestoreDeviceObjects(LPDIRECT3DDEVICE8 pDev,
LPDIRECT3DVERTEXBUFFER8 pvbQuad,
int iNumOctaves, int iTextureSize)
{
HRESULT hr;
InvalidateDeviceObjects(); // just in case something's left over
// squirrel away the device and vertex buffer pointers for later
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -