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

📄 ch18p2_particleemitter.cpp

📁 游戏开发特殊技巧-special.effects.game.programming
💻 CPP
📖 第 1 页 / 共 2 页
字号:
#include "Ch18p2_ParticleEmitter.h"


const int CParticleEmitter::NUMBLENDINGMODES = 11;
const BLENDINGMODE CParticleEmitter::m_BlendingModes[11] = {
  { "D3DBLEND_ZERO", D3DBLEND_ZERO },
  { "D3DBLEND_ONE", D3DBLEND_ONE },
  { "D3DBLEND_SRCCOLOR", D3DBLEND_SRCCOLOR },
  { "D3DBLEND_INVSRCCOLOR", D3DBLEND_INVSRCCOLOR },
  { "D3DBLEND_SRCALPHA", D3DBLEND_SRCALPHA },
  { "D3DBLEND_INVSRCALPHA", D3DBLEND_INVSRCALPHA },
  { "D3DBLEND_DESTALPHA", D3DBLEND_DESTALPHA },
  { "D3DBLEND_INVDESTALPHA", D3DBLEND_INVDESTALPHA },
  { "D3DBLEND_DESTCOLOR", D3DBLEND_DESTCOLOR },
  { "D3DBLEND_INVDESTCOLOR", D3DBLEND_INVDESTCOLOR },
  { "D3DBLEND_SRCALPHASAT", D3DBLEND_SRCALPHASAT }
};

CParticleEmitter::CParticleEmitter()
{
  // default particle system configuration - boring!
  SetGravity(D3DXVECTOR3(0.0f,0.0f,0.0f));
  SetPos(D3DXVECTOR3(0.0f,0.0f,0.0f));
  SetEmitRate(CMinMax<float>(1.0f, 10.0f));
  SetSize(CMinMax<float>(20.0f, 100.0f));
  
  SetStartColor1(D3DXCOLOR(1.0f,1.0f,1.0f,1.0f));
  SetStartColor2(D3DXCOLOR(1.0f,1.0f,1.0f,1.0f));
  SetEndColor1(D3DXCOLOR(1.0f,1.0f,1.0f,1.0f));
  SetEndColor2(D3DXCOLOR(1.0f,1.0f,1.0f,1.0f));
  
  SetSpawnDir1(D3DXVECTOR3(-1.0f, -1.0f, -1.0f));
  SetSpawnDir2(D3DXVECTOR3(1.0f, 1.0f, 1.0f));
  SetEmitRadius(D3DXVECTOR3(1.0f, 1.0f, 1.0f));
  
  SetSrcBlendMode(D3DBLEND_ONE);
  SetDestBlendMode(D3DBLEND_ONE);
  
  // initialize misc. other things
  m_pd3dDevice = NULL;
  m_texParticle = NULL;
  SetVBSize(NUMPARTICLES / 10);

  m_fNumNewPartsExcess = 0.0f;
  m_iMaxParticles = NUMPARTICLES;

}

CParticleEmitter::~CParticleEmitter()
{
}

HRESULT CParticleEmitter::RestoreDeviceObjects(LPDIRECT3DDEVICE8 pDev)
{
  HRESULT hr;
  m_pd3dDevice = pDev;
  m_Particles.DeleteAll();

  // load up the particle system texture
  if (FAILED(hr = D3DXCreateTextureFromFile(m_pd3dDevice, 
    m_strTexFilename.c_str(), &m_texParticle))) {
    return(hr);
  }
  
  // create vertex buffer
  if(FAILED(hr = m_pd3dDevice->CreateVertexBuffer(m_iVBSize * sizeof(VERTEX_PARTICLE), 
    D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY | D3DUSAGE_POINTS, 
    D3DFVF_PARTICLE, D3DPOOL_DEFAULT, &m_vbParticles))) {
    return(hr);
  }
  return S_OK;	
}

void CParticleEmitter::InvalidateDeviceObjects()
{
  SAFE_RELEASE(m_texParticle);
  SAFE_RELEASE(m_vbParticles);
}

void CParticleEmitter::Update(float fElapsedTime, float fTimeDelta)
{
  // update existing particles
  {
    for (int q=0; q < m_Particles.GetTotalElements(); q++) {
      if (m_Particles.IsAlive(q)) {
        CParticle &part = m_Particles.GetAt(q);

        if (!part.Update(fTimeDelta)) {
          m_Particles.Delete(&part);
        }
        else {
          // apply gravity to this particle.
          part.m_vDir += fTimeDelta * m_vGravity;
        }
      } // is alive
    } // next particle
  }

  // create new particles
  {
    // determine the number of particles we need to create
    
    float fEmitRateThisFrame = m_fEmitRate.GetRandomNumInRange();
    int iNumNewParts = fEmitRateThisFrame * fTimeDelta;
    m_fNumNewPartsExcess += (float)(fEmitRateThisFrame * fTimeDelta)-iNumNewParts;
    
    if (m_fNumNewPartsExcess > 1.0f) {
      iNumNewParts += (int)m_fNumNewPartsExcess;
      m_fNumNewPartsExcess -= (int)m_fNumNewPartsExcess;
    }

    for (int q=0; q < iNumNewParts && m_Particles.GetNumUsedElements() < m_iMaxParticles; q++) {
      try {
        CParticle *part = m_Particles.New();

        part->m_fLifetime = m_fLifetime.GetRandomNumInRange();
        part->m_fSize = m_fSize.GetRandomNumInRange();
        
        // determine a random vector between dir1 and dir2
        float fRandX = RandomNumber(m_vSpawnDir1.x, m_vSpawnDir2.x);
        float fRandY = RandomNumber(m_vSpawnDir1.y, m_vSpawnDir2.y);
        float fRandZ = RandomNumber(m_vSpawnDir1.z, m_vSpawnDir2.z);

        part->m_vDir = D3DXVECTOR3(fRandX, fRandY, fRandZ);
        part->m_vPos = m_vPos;

        // pick a random vector between +/- emitradius
        fRandX = RandomNumber(-m_vEmitRadius.x, m_vEmitRadius.x);
        fRandY = RandomNumber(-m_vEmitRadius.y, m_vEmitRadius.y);
        fRandZ = RandomNumber(-m_vEmitRadius.z, m_vEmitRadius.z);
        part->m_vPos += D3DXVECTOR3(fRandX, fRandY, fRandZ);
        
        float fRandR = RandomNumber(m_StartColor1.r, m_StartColor2.r);
        float fRandG = RandomNumber(m_StartColor1.g, m_StartColor2.g);
        float fRandB = RandomNumber(m_StartColor1.b, m_StartColor2.b);
        float fRandA = RandomNumber(m_StartColor1.a, m_StartColor2.a);
        D3DXCOLOR startcolor(fRandR, fRandG, fRandB, fRandA);

        fRandR = RandomNumber(m_EndColor1.r, m_EndColor2.r);
        fRandG = RandomNumber(m_EndColor1.g, m_EndColor2.g);
        fRandB = RandomNumber(m_EndColor1.b, m_EndColor2.b);
        fRandA = RandomNumber(m_EndColor1.a, m_EndColor2.a);
        D3DXCOLOR endcolor(fRandR, fRandG, fRandB, fRandA);

        // figure out startcolor and colorstep based on start and end color.
        part->m_Color = startcolor;
        part->m_ColorStep = (endcolor-startcolor)/part->m_fLifetime;
        

      } catch(...) { q = iNumNewParts; }
    }
  }
}

HRESULT CParticleEmitter::Render()
{
  HRESULT hr;

  // Set the render states for using point sprites
  m_pd3dDevice->SetRenderState(D3DRS_POINTSPRITEENABLE, true);
  m_pd3dDevice->SetRenderState(D3DRS_POINTSCALEENABLE,  true);
  m_pd3dDevice->SetRenderState(D3DRS_POINTSIZE,     FtoDW(0.08f));
  m_pd3dDevice->SetRenderState(D3DRS_POINTSIZE_MIN, FtoDW(m_fSize.m_Min));
  m_pd3dDevice->SetRenderState(D3DRS_POINTSIZE_MAX, FtoDW(m_fSize.m_Max));
  m_pd3dDevice->SetRenderState(D3DRS_POINTSCALE_A,  FtoDW(0.00f));
  m_pd3dDevice->SetRenderState(D3DRS_POINTSCALE_B,  FtoDW(0.00f));
  m_pd3dDevice->SetRenderState(D3DRS_POINTSCALE_C,  FtoDW(1.00f));
  
  m_pd3dDevice->SetRenderState(D3DRS_SRCBLEND, GetSrcBlendMode());
  m_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, GetDestBlendMode());

  // Set up the vertex buffer to be rendered
  m_pd3dDevice->SetStreamSource( 0, m_vbParticles, sizeof(VERTEX_PARTICLE) );
  m_pd3dDevice->SetVertexShader( D3DFVF_PARTICLE );

  m_pd3dDevice->SetTexture(0, m_texParticle);
  
  VERTEX_PARTICLE *pVertices;
  DWORD dwNumParticlesToRender = 0;

  // Lock the vertex buffer.  We fill the vertex buffer in small
  // chunks, using D3DLOCK_NOOVERWRITE.  When we are done filling
  // each chunk, we call DrawPrim, and lock the next chunk.  When
  // we run out of space in the vertex buffer, we start over at
  // the beginning, using D3DLOCK_DISCARD.

  int iCurStart = 0;

  if(FAILED(hr = m_vbParticles->Lock(iCurStart * sizeof(VERTEX_PARTICLE), m_iVBSize * sizeof(VERTEX_PARTICLE),
    (BYTE **) &pVertices, iCurStart ? D3DLOCK_NOOVERWRITE : D3DLOCK_DISCARD)))
  {
	  return hr;
  }

  // Render each particle
  for (int q=0; q < NUMPARTICLES; q++) {
    
    // Render each particle a bunch of times to get a blurring effect
    if (m_Particles.IsAlive(q)) {
      CParticle &part = m_Particles.GetAt(q);
    
      pVertices->position = part.m_vPos;
      pVertices->pointsize = part.m_fSize;
      pVertices->color = (DWORD)part.m_Color;
      pVertices++;

      if( ++dwNumParticlesToRender == m_iVBSize ) {
        // Done filling this chunk of the vertex buffer.  Lets unlock and
        // draw this portion so we can begin filling the next chunk.

        m_vbParticles->Unlock();

        if(FAILED(hr = m_pd3dDevice->DrawPrimitive( 
          D3DPT_POINTLIST, iCurStart, dwNumParticlesToRender)))
	        return hr;

        // Lock the next chunk of the vertex buffer.  If we are at the 
        // end of the vertex buffer, DISCARD the vertex buffer and start
        // at the beginning.  Otherwise, specify NOOVERWRITE, so we can
        // continue filling the VB while the previous chunk is drawing.
        iCurStart = 0;

        if(FAILED(hr = m_vbParticles->Lock(0, m_iVBSize * sizeof(VERTEX_PARTICLE),
		      (BYTE **) &pVertices, D3DLOCK_DISCARD)))
          return hr;

        dwNumParticlesToRender = 0;
      }
    }
  }

  // Unlock the vertex buffer
  m_vbParticles->Unlock();

  // Render any remaining particles
  if( dwNumParticlesToRender )
  {
    if(FAILED(hr = m_pd3dDevice->DrawPrimitive( D3DPT_POINTLIST, iCurStart, dwNumParticlesToRender )))
		return hr;
  }

  // Reset render states
  m_pd3dDevice->SetRenderState( D3DRS_POINTSPRITEENABLE, FALSE );
  m_pd3dDevice->SetRenderState( D3DRS_POINTSCALEENABLE,  FALSE );

  return S_OK;


}

void CParticleEmitter::SetTexture(const char *strTexFilename)
{
  m_strTexFilename = strTexFilename;
  if (m_pd3dDevice) {
    SAFE_RELEASE(m_texParticle);
    if (FAILED(D3DXCreateTextureFromFile(m_pd3dDevice, 
    m_strTexFilename.c_str(), &m_texParticle))) {
    m_texParticle = NULL;
    }
  }
}

⌨️ 快捷键说明

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