⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ch11p2_texturefire.cpp

📁 游戏开发特殊技巧-special.effects.game.programming
💻 CPP
字号:
// Ch11p2_TextureFire.cpp: implementation of the CTextureFire class.
//
//////////////////////////////////////////////////////////////////////

#include "CommonFuncs.h"
#include "Ch11p2_TextureFire.h"

// Our hard-coded color palette for our fire.
// Nuthin' but a string of bytes.

unsigned char g_FireRed[256] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,4,4,4,4,4,4,4,8,8,8,8,8,12,12,12,12,16,16,16,16,20,20,20,24,24,
  24,28,28,32,32,32,36,36,40,40,44,44,48,48,52,52,56,56,60,60,64,68,68,72,72,
  76,80,80,84,88,88,92,92,96,100,100,104,108,108,112,116,120,120,124,128,128,
  132,136,136,140,144,144,148,152,152,156,160,160,164,164,172,172,172,176,176,
  180,184,184,188,188,192,192,196,196,200,200,204,204,208,208,208,212,212,216,
  216,220,220,220,220,224,224,224,228,228,228,228,232,232,232,232,236,236,236,
  236,236,240,240,240,240,240,240,240,244,244,244,244,244,244,244,244,244,244,
  248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,
  248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,
  248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,
  248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,
  248,248,248,248,248};

unsigned char g_FireGreen[256]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,4,4,4,4,4,4,4,4,4,8,8,8,8,
  8,8,8,8,8,12,12,12,12,12,12,16,16,16,16,16,16,20,20,20,20,20,24,24,24,24,28,
  28,28,28,32,32,32,32,36,36,36,36,40,40,40,44,44,44,48,48,48,52,52,52,56,56,
  56,60,60,60,64,64,64,68,68,72,72,72,76,76,80,80,80,84,84,84,88,88,92,92,92,
  96,96,100,100,104,104,104,108,108,112,112,116,116,116,120,120,124,124,128,
  128,128,132,132,136,136,140,140,140,144,144,148,148,148,152,152,156,156,160,
  160,163,164,164,168,168,168,172,172,172,176,176,180,180,180,184,184,184,188,
  188,188,192,192,192,196,196,200,200,200,200,200,204,204,204,208,208,208,208,
  212,212,212,212,216,216,216,216,220,220,220,220,220,224,224,224,224,224,228,
  228,228,228,228,228,232,232,232,232,232,232,236,236,236,236,236,236,236,236,
  240,240,240,240,240,240};

unsigned char g_FireBlue[256]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
  4,4,8,8,8,2,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,12,12,12,12,12,12,12,12,12,12,
  12,12,12,12,12,12,12,16,16,16,16,16,16,16,16,16,16,16,16,16,16,20,20,20,20,
  20,20,20,20,20,20,20,20,24,24,24,24,24,24,24,24,24,24,24,24,28,28,28,28,28,
  28,28,28,28,28,32,32,32,32,32,32,32,32,32,32,36,36,36,36,36,36,36,36,36,40,
  40,40,40,40,40,40,40,44,44,44,44,44};


//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

void CTextureFire::InitDeviceObjects(LPDIRECT3DDEVICE8 pDevice, int iTextureSize,
                                     int iCoolAmount)
{
  if (!pDevice) { throw("CTextureFire::InitDeviceObjects: invalid pDevice."); }
  if (iTextureSize < 2 || iTextureSize > 512 || !IsPowerOf2(iTextureSize)) {
    throw("CTextureFire::InitDeviceObjects: invalid texture size.");
  }

  m_iCoolAmount = iCoolAmount;
  m_pd3dDevice = pDevice;
  m_iTextureSize = iTextureSize;

  // allocate fire buffers
  m_FireBuffer1 = new unsigned char[iTextureSize*iTextureSize];
  m_FireBuffer2 = new unsigned char[iTextureSize*iTextureSize];

  // set the first fire buffer active, 2nd one as scratch surface
  m_pActiveBuffer = m_FireBuffer1;
  m_pScratchBuffer = m_FireBuffer2;

  // clear the buffers
  memset(m_FireBuffer1, 0, iTextureSize*iTextureSize);
  memset(m_FireBuffer2, 0, iTextureSize*iTextureSize);

  // set up a default palette
  for (int q=0; q < 256; q++) {
    m_Palette[q].peBlue  = g_FireBlue[q];
    m_Palette[q].peGreen = g_FireGreen[q];
    m_Palette[q].peRed   = g_FireRed[q];
    m_Palette[q].peFlags = 0;
  }
}

void CTextureFire::RestoreDeviceObjects(void)
{
  HRESULT hr;
  // create fire texture
  if (FAILED(hr = D3DXCreateTexture(m_pd3dDevice, m_iTextureSize, m_iTextureSize, 1, 0, 
    D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &m_pTexture))) {
    throw("CTextureFire::RestoreDeviceObjects: can't create texture!");
  }
}

void CTextureFire::InvalidateDeviceObjects(void)
{
  SAFE_RELEASE( m_pTexture );
}

void CTextureFire::DeleteDeviceObjects(void)
{
  // delete fire buffers
  delete[] m_FireBuffer1; m_FireBuffer1 = NULL;
  delete[] m_FireBuffer2; m_FireBuffer2 = NULL;
}


void CTextureFire::SetupTextureStages(void)
{
  // set the fire stage active...
  m_pd3dDevice->SetTexture( 0, m_pTexture );

  // set up our texture stages for a simple texture copy...
  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->SetTextureStageState( 0, D3DTSS_ALPHAOP,   D3DTOP_SELECTARG1 );

  // turning on linear filtering for our fire texture really helps out with
  // the image quality.
  m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR);
  m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR);
  m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MIPFILTER, D3DTEXF_LINEAR);
}

/****************************************************************************

 Process: 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 CTextureFire::Process(void)
{
  // loop through all the fire values...
  for (int y=0; y < m_iTextureSize; y++) {
    for (int x=0; x < m_iTextureSize-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 >= m_iTextureSize) xplus1=0;
      xminus1= x-1; if (xminus1 < 0) xminus1 = m_iTextureSize-1;
      yplus1 = y+1; if (yplus1 >= m_iTextureSize) yplus1=m_iTextureSize-1;
      yminus1= y-1; if (yminus1 < 0) yminus1 = 0;
      
      // now we can get the fire values of the neighboring pixels
      firevalue_right = m_pActiveBuffer[(y*m_iTextureSize)+xplus1];
      firevalue_left  = m_pActiveBuffer[(y*m_iTextureSize)+xminus1];
      firevalue_bottom= m_pActiveBuffer[((yplus1)*m_iTextureSize)+x];
      firevalue_top   = m_pActiveBuffer[((yminus1)*m_iTextureSize)+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 -= m_iCoolAmount;

      // 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.
      m_pScratchBuffer[((yminus1)*m_iTextureSize)+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 < m_iTextureSize; x+=2) {
    // we add fuel only to the last row.
    int y=m_iTextureSize-1;
    
    // determine whether this particular spot gets fuel added or taken
    // away from it, by adding a number between (-31..31)
    int fuel = m_pActiveBuffer[(y*m_iTextureSize)+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.
    m_pScratchBuffer[(y*m_iTextureSize)+x] = (unsigned char)fuel;
    m_pScratchBuffer[(y*m_iTextureSize)+x+1] = (unsigned char)fuel;
  }
}

void CTextureFire::FrameMove(void)
{
  Process();
  CopyToTexture();

  // flip-flop the buffers.
  unsigned char *temp = m_pActiveBuffer;
  m_pActiveBuffer = m_pScratchBuffer;
  m_pScratchBuffer = temp;
}

bool CTextureFire::CopyToTexture(void)
{
  HRESULT hr;
  // lock texture
  D3DLOCKED_RECT lockedrect;
  ::ZeroMemory(&lockedrect, sizeof(lockedrect));
  
  if (FAILED(hr = m_pTexture->LockRect(0, &lockedrect, NULL, 0))) return(false);
  
  // 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_iTextureSize; y++) {
    for (int x=0; x < m_iTextureSize; x++) {
      // the fire value at this position determines the color of this texel
      pSurfBits[index++] = m_Palette[m_pActiveBuffer[(y*m_iTextureSize)+x]].peBlue; // blue
      pSurfBits[index++] = m_Palette[m_pActiveBuffer[(y*m_iTextureSize)+x]].peGreen; // green
      pSurfBits[index++] = m_Palette[m_pActiveBuffer[(y*m_iTextureSize)+x]].peRed; // red
      pSurfBits[index++] = m_Palette[m_pActiveBuffer[(y*m_iTextureSize)+x]].peFlags; // alpha
    }
    // next line
    index += lockedrect.Pitch - (m_iTextureSize*4);
  }

  // unlock texture surface
  if (FAILED(hr = m_pTexture->UnlockRect(0))) return(false);
  return(true);
}


bool CTextureFire::LoadPaletteFromBMP(const char *strBMPfile)
{
  LPDIRECT3DTEXTURE8 pTexture;
  
  if (FAILED(D3DXCreateTextureFromFileExA(m_pd3dDevice,
    strBMPfile,
    0,
    0,
    1,
    0,
    D3DFMT_UNKNOWN,
    D3DPOOL_MANAGED,
    0,
    0,
    0,
    NULL,
    m_Palette,
    &pTexture))) { return(false); }

  SAFE_RELEASE(pTexture);
  return(true);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -