ParticleSystem.cpp
上传用户:sycq158
上传日期:2008-10-22
资源大小:15361k
文件大小:13k
源码类别:

游戏

开发平台:

Visual C++

  1. //-----------------------------------------------------------------------------
  2. // File: ParticleSystem.cpp
  3. //
  4. // Copyright (C) Microsoft Corporation. All Rights Reserved.
  5. //-----------------------------------------------------------------------------
  6. #include "stdafx.h"
  7. //-----------------------------------------------------------------------------
  8. // Name:
  9. // Desc:
  10. //-----------------------------------------------------------------------------
  11. CParticleSystem::CParticleSystem( DWORD dwFlush, DWORD dwDiscard, float fRadius )
  12. {
  13.     m_fRadius        = fRadius;
  14.     m_dwBase         = dwDiscard;
  15.     m_dwFlush        = dwFlush;
  16. m_dwDiscard      = dwDiscard;
  17.     m_dwParticles    = 0;
  18.     m_dwParticlesLim = 2048;
  19.     m_pParticles     = NULL;
  20.     m_pParticlesFree = NULL;
  21. m_pVB            = NULL;
  22.     m_fTime          = 0.0f;
  23. }
  24. //-----------------------------------------------------------------------------
  25. // Name:
  26. // Desc:
  27. //-----------------------------------------------------------------------------
  28. CParticleSystem::~CParticleSystem()
  29. {
  30. InvalidateDeviceObjects();
  31.     while( m_pParticles )
  32.     {
  33.         PARTICLE* pSpark = m_pParticles;
  34.         m_pParticles = pSpark->m_pNext;
  35.         delete pSpark;
  36.     }
  37.     while( m_pParticlesFree )
  38.     {
  39.         PARTICLE *pSpark = m_pParticlesFree;
  40.         m_pParticlesFree = pSpark->m_pNext;
  41.         delete pSpark;
  42.     }
  43. }
  44. //-----------------------------------------------------------------------------
  45. // Name:
  46. // Desc:
  47. //-----------------------------------------------------------------------------
  48. HRESULT CParticleSystem::RestoreDeviceObjects()
  49. {
  50.     HRESULT hr;
  51.     // Create a vertex buffer for the particle system.  The size of this buffer
  52.     // does not relate to the number of particles that exist.  Rather, the
  53.     // buffer is used as a communication channel with the device.. we fill in 
  54.     // a bit, and tell the device to draw.  While the device is drawing, we
  55.     // fill in the next bit using NOOVERWRITE.  We continue doing this until 
  56.     // we run out of vertex buffer space, and are forced to DISCARD the buffer
  57.     // and start over at the beginning.
  58.     if(FAILED(hr = g_pd3dDevice->CreateVertexBuffer( m_dwDiscard * 
  59. sizeof(POINTVERTEX), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY | D3DUSAGE_POINTS, 
  60. D3DFVF_POINTVERTEX, D3DPOOL_DEFAULT, &m_pVB, NULL )))
  61. {
  62.         return E_FAIL;
  63. }
  64.     return S_OK;
  65. }
  66. //-----------------------------------------------------------------------------
  67. // Name:
  68. // Desc:
  69. //-----------------------------------------------------------------------------
  70. HRESULT CParticleSystem::InvalidateDeviceObjects()
  71. {
  72.     SAFE_RELEASE( m_pVB );
  73.     return S_OK;
  74. }
  75. //-----------------------------------------------------------------------------
  76. // Name:
  77. // Desc:
  78. //-----------------------------------------------------------------------------
  79. HRESULT CParticleSystem::Update( FLOAT fSecsPerFrame, DWORD dwNumParticlesToEmit,
  80.                                  const D3DXCOLOR &clrEmitColor,
  81.                                  const D3DXCOLOR &clrFadeColor, float fEmitVel,
  82.                                  D3DXVECTOR3 vPosition, BOOL bEmitNewParticles )
  83. {
  84. //dwNumParticlesToEmit = 1;
  85.     PARTICLE *pParticle, **ppParticle;
  86.     m_fTime += fSecsPerFrame;
  87.     ppParticle = &m_pParticles;
  88.     while( *ppParticle )
  89.     {
  90.         pParticle = *ppParticle;
  91.         // Calculate new position
  92.         float fT = m_fTime - pParticle->m_fTime0;
  93.         float fGravity;
  94.         if( pParticle->m_bSpark )
  95.         {
  96.             fGravity = -5.0f;
  97.             pParticle->m_fFade -= fSecsPerFrame * 2.25f;
  98.         }
  99.         else
  100.         {
  101.             fGravity = -9.8f;
  102.             pParticle->m_fFade -= fSecsPerFrame * 0.25f;
  103.         }
  104.         pParticle->m_vPos    = pParticle->m_vVel0 * fT + pParticle->m_vPos0;
  105.         pParticle->m_vPos.y += (0.5f * fGravity) * (fT * fT);
  106.         pParticle->m_vVel.y  = pParticle->m_vVel0.y + fGravity * fT;
  107.         if( pParticle->m_fFade < 0.0f )
  108.             pParticle->m_fFade = 0.0f;
  109.         // Kill old particles
  110.         if( pParticle->m_vPos.y < m_fRadius ||
  111.             pParticle->m_bSpark && pParticle->m_fFade <= 0.0f )
  112.         {
  113.             // Emit sparks
  114.             if( !pParticle->m_bSpark )
  115.             {
  116.                 for( int i=0; i<4; i++ )
  117.                 {
  118.                     PARTICLE *pSpark;
  119.                     if( m_pParticlesFree )
  120.                     {
  121.                         pSpark = m_pParticlesFree;
  122.                         m_pParticlesFree = pSpark->m_pNext;
  123.                     }
  124.                     else
  125.                     {
  126.                         if( NULL == ( pSpark = new PARTICLE ) )
  127.                             return E_OUTOFMEMORY;
  128.                     }
  129.                     pSpark->m_pNext = pParticle->m_pNext;
  130.                     pParticle->m_pNext = pSpark;
  131.                     pSpark->m_bSpark  = TRUE;
  132.                     pSpark->m_vPos0   = pParticle->m_vPos;
  133.                     pSpark->m_vPos0.y = m_fRadius;
  134.                     FLOAT fRand1 = ((FLOAT)rand()/(FLOAT)RAND_MAX) * D3DX_PI * 2.00f;
  135.                     FLOAT fRand2 = ((FLOAT)rand()/(FLOAT)RAND_MAX) * D3DX_PI * 0.25f;
  136.                     pSpark->m_vVel0.x  = pParticle->m_vVel.x * 0.25f + cosf(fRand1) * sinf(fRand2);
  137.                     pSpark->m_vVel0.z  = pParticle->m_vVel.z * 0.25f + sinf(fRand1) * sinf(fRand2);
  138.                     pSpark->m_vVel0.y  = cosf(fRand2);
  139.                     pSpark->m_vVel0.y *= ((FLOAT)rand()/(FLOAT)RAND_MAX) * 1.5f;
  140.                     pSpark->m_vPos = pSpark->m_vPos0;
  141.                     pSpark->m_vVel = pSpark->m_vVel0;
  142.                     D3DXColorLerp( &pSpark->m_clrDiffuse, &pParticle->m_clrFade,
  143.                                    &pParticle->m_clrDiffuse, pParticle->m_fFade );
  144.                     pSpark->m_clrFade = D3DXCOLOR(0.0f, 0.0f, 0.0f, 1.0f);
  145.                     pSpark->m_fFade   = 1.0f;
  146.                     pSpark->m_fTime0  = m_fTime;
  147.                 }
  148.             }
  149.             // Kill particle
  150.             *ppParticle = pParticle->m_pNext;
  151.             pParticle->m_pNext = m_pParticlesFree;
  152.             m_pParticlesFree = pParticle;
  153.             if(!pParticle->m_bSpark)
  154.                 m_dwParticles--;
  155.         }
  156.         else
  157.         {
  158.             ppParticle = &pParticle->m_pNext;
  159.         }
  160.     }
  161.     if( bEmitNewParticles )
  162.     {
  163.         // Emit new particles
  164.         DWORD dwParticlesEmit = m_dwParticles + dwNumParticlesToEmit;
  165.         while( m_dwParticles < m_dwParticlesLim && m_dwParticles < dwParticlesEmit )
  166.         {
  167.             if( m_pParticlesFree )
  168.             {
  169.                 pParticle = m_pParticlesFree;
  170.                 m_pParticlesFree = pParticle->m_pNext;
  171.             }
  172.             else
  173.             {
  174.                 if( NULL == ( pParticle = new PARTICLE ) )
  175.                     return E_OUTOFMEMORY;
  176.             }
  177.             pParticle->m_pNext = m_pParticles;
  178.             m_pParticles = pParticle;
  179.             m_dwParticles++;
  180.             // Emit new particle
  181.             FLOAT fRand1 = ((FLOAT)rand()/(FLOAT)RAND_MAX) * D3DX_PI * 2.0f;
  182.             FLOAT fRand2 = ((FLOAT)rand()/(FLOAT)RAND_MAX) * D3DX_PI * 0.25f;
  183.             pParticle->m_bSpark = FALSE;
  184.             pParticle->m_vPos0 = vPosition + D3DXVECTOR3( 0.0f, m_fRadius, 0.0f );
  185.             pParticle->m_vVel0.x  = cosf(fRand1) * sinf(fRand2) * 2.5f;
  186.             pParticle->m_vVel0.z  = sinf(fRand1) * sinf(fRand2) * 2.5f;
  187.             pParticle->m_vVel0.y  = cosf(fRand2);
  188.             pParticle->m_vVel0.y *= ((FLOAT)rand()/(FLOAT)RAND_MAX) * fEmitVel;
  189.             pParticle->m_vPos = pParticle->m_vPos0;
  190.             pParticle->m_vVel = pParticle->m_vVel0;
  191.             pParticle->m_clrDiffuse = clrEmitColor;
  192.             pParticle->m_clrFade    = clrFadeColor;
  193.             pParticle->m_fFade      = 1.0f;
  194.             pParticle->m_fTime0     = m_fTime;
  195.         }
  196.     }
  197.     return S_OK;
  198. }
  199. //-----------------------------------------------------------------------------
  200. // Name: Render()
  201. // Desc: Renders the particle system using either pointsprites (if supported)
  202. //       or using 4 vertices per particle
  203. //-----------------------------------------------------------------------------
  204. HRESULT CParticleSystem::Render( const float fWrapOffsetX, const float fWrapOffsetZ )
  205. {
  206.     HRESULT hr;
  207.     // TODO: remove particle blur
  208.     // Set the render states for using point sprites
  209.     g_pd3dDevice->SetRenderState( D3DRS_POINTSPRITEENABLE, TRUE );
  210.     g_pd3dDevice->SetRenderState( D3DRS_POINTSCALEENABLE,  TRUE );
  211.     g_pd3dDevice->SetRenderState( D3DRS_POINTSIZE,     FtoDW(0.08f) );
  212.     g_pd3dDevice->SetRenderState( D3DRS_POINTSIZE_MIN, FtoDW(0.00f) );
  213.     g_pd3dDevice->SetRenderState( D3DRS_POINTSCALE_A,  FtoDW(0.00f) );
  214.     g_pd3dDevice->SetRenderState( D3DRS_POINTSCALE_B,  FtoDW(0.00f) );
  215.     g_pd3dDevice->SetRenderState( D3DRS_POINTSCALE_C,  FtoDW(1.00f) );
  216.     // Set up the vertex buffer to be rendered
  217.     g_pd3dDevice->SetStreamSource( 0, m_pVB, 0, sizeof(POINTVERTEX) );
  218.     g_pd3dDevice->SetFVF( D3DFVF_POINTVERTEX );
  219.     PARTICLE*    pParticle = m_pParticles;
  220.     POINTVERTEX* pVertices;
  221.     DWORD        dwNumParticlesToRender = 0;
  222. // Lock the vertex buffer.  We fill the vertex buffer in small
  223. // chunks, using D3DLOCK_NOOVERWRITE.  When we are done filling
  224. // each chunk, we call DrawPrim, and lock the next chunk.  When
  225. // we run out of space in the vertex buffer, we start over at
  226. // the beginning, using D3DLOCK_DISCARD.
  227. m_dwBase += m_dwFlush;
  228. if(m_dwBase >= m_dwDiscard)
  229. m_dwBase = 0;
  230. if(FAILED(hr = m_pVB->Lock( m_dwBase * sizeof(POINTVERTEX), m_dwFlush * sizeof(POINTVERTEX),
  231.                         (void**) &pVertices, m_dwBase ? D3DLOCK_NOOVERWRITE : D3DLOCK_DISCARD)))
  232. return hr;
  233. //    pParticle->m_vVel = D3DXVECTOR3(0,0,0);
  234. //    pParticle->m_vPos = D3DXVECTOR3(0,0,0);
  235.     // Render each particle
  236.     while( pParticle )
  237.     {
  238.         D3DXVECTOR3 vPos(pParticle->m_vPos);
  239.         D3DXVECTOR3 vVel(pParticle->m_vVel);
  240.         FLOAT       fLengthSq = D3DXVec3LengthSq(&vVel);
  241.         UINT        dwSteps;
  242.         vPos.x += fWrapOffsetX;
  243.         vPos.z += fWrapOffsetZ;
  244. //vVel = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
  245.         if( fLengthSq < 1.0f )        dwSteps = 2;
  246.         else if( fLengthSq <  4.00f ) dwSteps = 3;
  247.         else if( fLengthSq <  9.00f ) dwSteps = 4;
  248.         else if( fLengthSq < 12.25f ) dwSteps = 5;
  249.         else if( fLengthSq < 16.00f ) dwSteps = 6;
  250.         else if( fLengthSq < 20.25f ) dwSteps = 7;
  251.         else                          dwSteps = 8;
  252. //dwSteps = 1;
  253.         vVel *= -0.04f / (FLOAT)dwSteps;
  254.         D3DXCOLOR clrDiffuse;
  255.         D3DXColorLerp(&clrDiffuse, &pParticle->m_clrFade, &pParticle->m_clrDiffuse, pParticle->m_fFade);
  256.         DWORD dwDiffuse = (DWORD) clrDiffuse;
  257.         // Render each particle a bunch of times to get a blurring effect
  258.         for( DWORD i = 0; i < dwSteps; i++ )
  259.         {
  260.             pVertices->v     = vPos;
  261. /*            pVertices->v     = D3DXVECTOR3( (float)((rand() % 100)/100.0f)*100,
  262.                                              20.0f+(float)((rand() % 100)/100.0f)*5,
  263.                                             (float)((rand() % 100)/100.0f)*100 );
  264. */
  265.             pVertices->color = dwDiffuse;
  266.             pVertices++;
  267.             if( ++dwNumParticlesToRender == m_dwFlush )
  268.             {
  269.                 // Done filling this chunk of the vertex buffer.  Lets unlock and
  270.                 // draw this portion so we can begin filling the next chunk.
  271.                 m_pVB->Unlock();
  272.                 if(FAILED(hr = g_pd3dDevice->DrawPrimitive( D3DPT_POINTLIST, m_dwBase, dwNumParticlesToRender)))
  273. return hr;
  274.                 // Lock the next chunk of the vertex buffer.  If we are at the 
  275.                 // end of the vertex buffer, DISCARD the vertex buffer and start
  276.                 // at the beginning.  Otherwise, specify NOOVERWRITE, so we can
  277.                 // continue filling the VB while the previous chunk is drawing.
  278. m_dwBase += m_dwFlush;
  279. if(m_dwBase >= m_dwDiscard)
  280. m_dwBase = 0;
  281. if(FAILED(hr = m_pVB->Lock(m_dwBase * sizeof(POINTVERTEX), m_dwFlush * sizeof(POINTVERTEX),
  282.             (void**) &pVertices, m_dwBase ? D3DLOCK_NOOVERWRITE : D3DLOCK_DISCARD)))
  283.                 {
  284. return hr;
  285.                 }
  286.                 dwNumParticlesToRender = 0;
  287.             }
  288.             vPos += vVel;
  289.         }
  290.         pParticle = pParticle->m_pNext;
  291.     }
  292.     // Unlock the vertex buffer
  293.     m_pVB->Unlock();
  294.     // Render any remaining particles
  295.     if( dwNumParticlesToRender )
  296.     {
  297.         if(FAILED(hr = g_pd3dDevice->DrawPrimitive( D3DPT_POINTLIST, m_dwBase, dwNumParticlesToRender )))
  298. return hr;
  299.     }
  300.     // Reset render states
  301.     g_pd3dDevice->SetRenderState( D3DRS_POINTSPRITEENABLE, FALSE );
  302.     g_pd3dDevice->SetRenderState( D3DRS_POINTSCALEENABLE,  FALSE );
  303.     return S_OK;
  304. }