📄 ch11p1_simplefire.cpp
字号:
/*
#############################################################################
Ch11p1_SimpleFire.cpp: a program that demonstrates the fire algorithm,
without any annoying bells and/or whistles.
#############################################################################
*/
// include files ////////////////////////////////////////////////////////////
#define STRICT
#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 "Ch11p1_FirePalette.h"
#include "D3DHelperFuncs.h"
#include "Ch11p1_resource.h"
// A structure for our custom vertex type.
struct CUSTOMVERTEX
{
D3DXVECTOR3 position; // The position
D3DCOLOR color; // The color
FLOAT tu, tv; // The texture coordinates
};
const int TEXTURESIZE = 128; // size of the fire texture
// Our custom FVF, which describes our custom vertex structure
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1)
//-----------------------------------------------------------------------------
// Name: class CMyD3DApplication
// Desc: Application class. The base class (CD3DApplication) provides the
// generic functionality needed in all Direct3D samples. CMyD3DApplication
// adds functionality specific to this sample program.
//-----------------------------------------------------------------------------
class CMyD3DApplication : public CD3DApplication
{
// Font for drawing text
CD3DFont* m_pFont;
CD3DFont* m_pFontSmall;
// Scene
LPDIRECT3DVERTEXBUFFER8 m_pVB;
DWORD m_dwNumVertices;
// Texture
LPDIRECT3DTEXTURE8 m_pTexture;
// Texture Palette
PALETTEENTRY m_Palette[256];
char m_strTextureSurfFormat[256];
unsigned char m_cFireField[TEXTURESIZE*TEXTURESIZE]; // first fire array
unsigned char m_cFireField2[TEXTURESIZE*TEXTURESIZE]; // second fire array
unsigned char *m_pFireActive; // we use these two pointers to flip
unsigned char *m_pFireScratch; // the active fire array back and forth.
protected:
HRESULT OneTimeSceneInit();
HRESULT InitDeviceObjects();
HRESULT RestoreDeviceObjects();
HRESULT InvalidateDeviceObjects();
HRESULT DeleteDeviceObjects();
HRESULT FinalCleanup();
HRESULT Render();
HRESULT FrameMove();
HRESULT ConfirmDevice( D3DCAPS8* pCaps, DWORD dwBehavior, D3DFORMAT Format );
LRESULT MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
public:
CMyD3DApplication();
};
//-----------------------------------------------------------------------------
// Name: WinMain()
// Desc: Entry point to the program. Initializes everything, and goes into a
// message-processing loop. Idle time is used to render the scene.
//-----------------------------------------------------------------------------
INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR, INT )
{
CMyD3DApplication d3dApp;
if( FAILED( d3dApp.Create( hInst ) ) )
return 0;
return d3dApp.Run();
}
//-----------------------------------------------------------------------------
// Name: CMyD3DApplication()
// Desc: Application constructor. Sets attributes for the app.
//-----------------------------------------------------------------------------
CMyD3DApplication::CMyD3DApplication()
{
m_strWindowTitle = _T("Ch11p1_SimpleFire");
m_bUseDepthBuffer = TRUE;
m_pFont = new CD3DFont( _T("Arial"), 12, D3DFONT_BOLD );
m_pFontSmall = new CD3DFont( _T("Arial"), 9, D3DFONT_BOLD );
m_pVB = NULL;
m_dwNumVertices = 6;
m_pTexture = NULL;
}
/****************************************************************************
ProcessFire: this function processes our fire. It takes two input buffers,
the fire dimensions, and the cooling amount. It calculates the new fire
values from firefield1 and puts them into firefield2.
****************************************************************************/
void ProcessFire(unsigned char *firefield, unsigned char *firefield2, int firesizex, int firesizey, int coolamount)
{
// loop through all the fire values...
for (int y=0; y < firesizey; y++) {
for (int x=0; x < firesizex-0; x++) {
// these will store, temporarily, the fire values immediately to the
// left, right, top, and bottom of this fire value.
unsigned char firevalue_left, firevalue_right, firevalue_bottom, firevalue_top;
int finalfirevalue;
// x+-1 and y+-1 aren't always that simple; we must account for wrapping
// around the horizontal edge (not vertical, however).
// so we calculate x/y +- 1 and store them temporarily.
int xplus1, xminus1, yplus1, yminus1;
xplus1 = x+1; if (xplus1 >= firesizex) xplus1=0;
xminus1= x-1; if (xminus1 < 0) xminus1 = firesizex-1;
yplus1 = y+1; if (yplus1 >= firesizey) yplus1=firesizey-1;
yminus1= y-1; if (yminus1 < 0) yminus1 = 0;
// now we can get the fire values of the neighboring pixels
firevalue_right = firefield[(y*firesizex)+xplus1];
firevalue_left = firefield[(y*firesizex)+xminus1];
firevalue_bottom= firefield[((yplus1)*firesizex)+x];
firevalue_top = firefield[((yminus1)*firesizex)+x];
// now, the most important part- calculate the new fire value..
finalfirevalue = (firevalue_left+firevalue_right+firevalue_top+firevalue_bottom)/4;
// subtract a certain amount to simulate the fire "cooling."
// this is where you'd apply your cooling map.
finalfirevalue -= coolamount;
// make sure that the subtraction of the coolamount didn't take us
// below zero.
if (finalfirevalue < 0) finalfirevalue = 0;
// store the fire value on the scratch array, up one line from where
// it originally was. This simulates the flames rising.
firefield2[((yminus1)*firesizex)+x] = finalfirevalue;
}
}
// add fuel to the fire. This particular fueling method is one of my
// favorite; it creates little jet streams of flame.
// we work in blocks of 2x1...
for (int x=0; x < firesizex; x+=2) {
// we add fuel only to the last row.
int y=firesizey-1;
// determine whether this particular spot gets fuel added or taken
// away from it, by adding a number between (-31..31)
int fuel = firefield[(y*firesizex)+x] + (rand() % 64) - 32;
// we must be between 0-255.
if (fuel > 255) fuel = 255;
if (fuel < 0) fuel = 0;
// apply the new fuel value to two adjacent pixels. This helps reduce
// the "dithering" effect that the fire is prone to.
firefield2[(y*firesizex)+x] = (unsigned char)fuel;
firefield2[(y*firesizex)+x+1] = (unsigned char)fuel;
}
}
//-----------------------------------------------------------------------------
// Name: OneTimeSceneInit()
// Desc: Called during initial app startup, this function performs all the
// permanent initialization.
//-----------------------------------------------------------------------------
HRESULT CMyD3DApplication::OneTimeSceneInit()
{
// set up the texture palette - in this program, we just grab it directly
// from our palette header file.
for (int q=0; q < 255; q++) {
m_Palette[q].peRed = g_FireRed[q];
m_Palette[q].peGreen = g_FireGreen[q];
m_Palette[q].peBlue = g_FireBlue[q];
m_Palette[q].peFlags = 0;
}
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: FrameMove()
// Desc: Called once per frame, the call is the entry point for animating
// the scene.
//-----------------------------------------------------------------------------
HRESULT CMyD3DApplication::FrameMove()
{
FLOAT fSecsPerFrame = m_fElapsedTime;
// process the fire
ProcessFire(m_pFireActive, m_pFireScratch, TEXTURESIZE, TEXTURESIZE, 1);
// flip-flop the buffers.
unsigned char *temp = m_pFireActive;
m_pFireActive = m_pFireScratch;
m_pFireScratch = temp;
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: Render()
// Desc: Called once per frame, the call is the entry point for 3d
// rendering. This function sets up render states, clears the
// viewport, and renders the scene.
//-----------------------------------------------------------------------------
HRESULT CMyD3DApplication::Render()
{
HRESULT hr;
// Clear the backbuffer
m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,
0x000000, 1.0f, 0L );
// lock texture
D3DLOCKED_RECT lockedrect;
::ZeroMemory(&lockedrect, sizeof(lockedrect));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -