ParticleSystem.cpp
上传用户:sycq158
上传日期:2008-10-22
资源大小:15361k
文件大小:13k
- //-----------------------------------------------------------------------------
- // File: ParticleSystem.cpp
- //
- // Copyright (C) Microsoft Corporation. All Rights Reserved.
- //-----------------------------------------------------------------------------
- #include "stdafx.h"
- //-----------------------------------------------------------------------------
- // Name:
- // Desc:
- //-----------------------------------------------------------------------------
- CParticleSystem::CParticleSystem( DWORD dwFlush, DWORD dwDiscard, float fRadius )
- {
- m_fRadius = fRadius;
- m_dwBase = dwDiscard;
- m_dwFlush = dwFlush;
- m_dwDiscard = dwDiscard;
- m_dwParticles = 0;
- m_dwParticlesLim = 2048;
- m_pParticles = NULL;
- m_pParticlesFree = NULL;
- m_pVB = NULL;
- m_fTime = 0.0f;
- }
- //-----------------------------------------------------------------------------
- // Name:
- // Desc:
- //-----------------------------------------------------------------------------
- CParticleSystem::~CParticleSystem()
- {
- InvalidateDeviceObjects();
- while( m_pParticles )
- {
- PARTICLE* pSpark = m_pParticles;
- m_pParticles = pSpark->m_pNext;
- delete pSpark;
- }
- while( m_pParticlesFree )
- {
- PARTICLE *pSpark = m_pParticlesFree;
- m_pParticlesFree = pSpark->m_pNext;
- delete pSpark;
- }
- }
- //-----------------------------------------------------------------------------
- // Name:
- // Desc:
- //-----------------------------------------------------------------------------
- HRESULT CParticleSystem::RestoreDeviceObjects()
- {
- HRESULT hr;
- // Create a vertex buffer for the particle system. The size of this buffer
- // does not relate to the number of particles that exist. Rather, the
- // buffer is used as a communication channel with the device.. we fill in
- // a bit, and tell the device to draw. While the device is drawing, we
- // fill in the next bit using NOOVERWRITE. We continue doing this until
- // we run out of vertex buffer space, and are forced to DISCARD the buffer
- // and start over at the beginning.
- if(FAILED(hr = g_pd3dDevice->CreateVertexBuffer( m_dwDiscard *
- sizeof(POINTVERTEX), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY | D3DUSAGE_POINTS,
- D3DFVF_POINTVERTEX, D3DPOOL_DEFAULT, &m_pVB, NULL )))
- {
- return E_FAIL;
- }
- return S_OK;
- }
- //-----------------------------------------------------------------------------
- // Name:
- // Desc:
- //-----------------------------------------------------------------------------
- HRESULT CParticleSystem::InvalidateDeviceObjects()
- {
- SAFE_RELEASE( m_pVB );
- return S_OK;
- }
- //-----------------------------------------------------------------------------
- // Name:
- // Desc:
- //-----------------------------------------------------------------------------
- HRESULT CParticleSystem::Update( FLOAT fSecsPerFrame, DWORD dwNumParticlesToEmit,
- const D3DXCOLOR &clrEmitColor,
- const D3DXCOLOR &clrFadeColor, float fEmitVel,
- D3DXVECTOR3 vPosition, BOOL bEmitNewParticles )
- {
- //dwNumParticlesToEmit = 1;
- PARTICLE *pParticle, **ppParticle;
- m_fTime += fSecsPerFrame;
- ppParticle = &m_pParticles;
- while( *ppParticle )
- {
- pParticle = *ppParticle;
- // Calculate new position
- float fT = m_fTime - pParticle->m_fTime0;
- float fGravity;
- if( pParticle->m_bSpark )
- {
- fGravity = -5.0f;
- pParticle->m_fFade -= fSecsPerFrame * 2.25f;
- }
- else
- {
- fGravity = -9.8f;
- pParticle->m_fFade -= fSecsPerFrame * 0.25f;
- }
- pParticle->m_vPos = pParticle->m_vVel0 * fT + pParticle->m_vPos0;
- pParticle->m_vPos.y += (0.5f * fGravity) * (fT * fT);
- pParticle->m_vVel.y = pParticle->m_vVel0.y + fGravity * fT;
- if( pParticle->m_fFade < 0.0f )
- pParticle->m_fFade = 0.0f;
- // Kill old particles
- if( pParticle->m_vPos.y < m_fRadius ||
- pParticle->m_bSpark && pParticle->m_fFade <= 0.0f )
- {
- // Emit sparks
- if( !pParticle->m_bSpark )
- {
- for( int i=0; i<4; i++ )
- {
- PARTICLE *pSpark;
- if( m_pParticlesFree )
- {
- pSpark = m_pParticlesFree;
- m_pParticlesFree = pSpark->m_pNext;
- }
- else
- {
- if( NULL == ( pSpark = new PARTICLE ) )
- return E_OUTOFMEMORY;
- }
- pSpark->m_pNext = pParticle->m_pNext;
- pParticle->m_pNext = pSpark;
- pSpark->m_bSpark = TRUE;
- pSpark->m_vPos0 = pParticle->m_vPos;
- pSpark->m_vPos0.y = m_fRadius;
- FLOAT fRand1 = ((FLOAT)rand()/(FLOAT)RAND_MAX) * D3DX_PI * 2.00f;
- FLOAT fRand2 = ((FLOAT)rand()/(FLOAT)RAND_MAX) * D3DX_PI * 0.25f;
- pSpark->m_vVel0.x = pParticle->m_vVel.x * 0.25f + cosf(fRand1) * sinf(fRand2);
- pSpark->m_vVel0.z = pParticle->m_vVel.z * 0.25f + sinf(fRand1) * sinf(fRand2);
- pSpark->m_vVel0.y = cosf(fRand2);
- pSpark->m_vVel0.y *= ((FLOAT)rand()/(FLOAT)RAND_MAX) * 1.5f;
- pSpark->m_vPos = pSpark->m_vPos0;
- pSpark->m_vVel = pSpark->m_vVel0;
- D3DXColorLerp( &pSpark->m_clrDiffuse, &pParticle->m_clrFade,
- &pParticle->m_clrDiffuse, pParticle->m_fFade );
- pSpark->m_clrFade = D3DXCOLOR(0.0f, 0.0f, 0.0f, 1.0f);
- pSpark->m_fFade = 1.0f;
- pSpark->m_fTime0 = m_fTime;
- }
- }
- // Kill particle
- *ppParticle = pParticle->m_pNext;
- pParticle->m_pNext = m_pParticlesFree;
- m_pParticlesFree = pParticle;
- if(!pParticle->m_bSpark)
- m_dwParticles--;
- }
- else
- {
- ppParticle = &pParticle->m_pNext;
- }
- }
- if( bEmitNewParticles )
- {
- // Emit new particles
- DWORD dwParticlesEmit = m_dwParticles + dwNumParticlesToEmit;
- while( m_dwParticles < m_dwParticlesLim && m_dwParticles < dwParticlesEmit )
- {
- if( m_pParticlesFree )
- {
- pParticle = m_pParticlesFree;
- m_pParticlesFree = pParticle->m_pNext;
- }
- else
- {
- if( NULL == ( pParticle = new PARTICLE ) )
- return E_OUTOFMEMORY;
- }
- pParticle->m_pNext = m_pParticles;
- m_pParticles = pParticle;
- m_dwParticles++;
- // Emit new particle
- FLOAT fRand1 = ((FLOAT)rand()/(FLOAT)RAND_MAX) * D3DX_PI * 2.0f;
- FLOAT fRand2 = ((FLOAT)rand()/(FLOAT)RAND_MAX) * D3DX_PI * 0.25f;
- pParticle->m_bSpark = FALSE;
- pParticle->m_vPos0 = vPosition + D3DXVECTOR3( 0.0f, m_fRadius, 0.0f );
- pParticle->m_vVel0.x = cosf(fRand1) * sinf(fRand2) * 2.5f;
- pParticle->m_vVel0.z = sinf(fRand1) * sinf(fRand2) * 2.5f;
- pParticle->m_vVel0.y = cosf(fRand2);
- pParticle->m_vVel0.y *= ((FLOAT)rand()/(FLOAT)RAND_MAX) * fEmitVel;
- pParticle->m_vPos = pParticle->m_vPos0;
- pParticle->m_vVel = pParticle->m_vVel0;
- pParticle->m_clrDiffuse = clrEmitColor;
- pParticle->m_clrFade = clrFadeColor;
- pParticle->m_fFade = 1.0f;
- pParticle->m_fTime0 = m_fTime;
- }
- }
- return S_OK;
- }
- //-----------------------------------------------------------------------------
- // Name: Render()
- // Desc: Renders the particle system using either pointsprites (if supported)
- // or using 4 vertices per particle
- //-----------------------------------------------------------------------------
- HRESULT CParticleSystem::Render( const float fWrapOffsetX, const float fWrapOffsetZ )
- {
- HRESULT hr;
- // TODO: remove particle blur
- // Set the render states for using point sprites
- g_pd3dDevice->SetRenderState( D3DRS_POINTSPRITEENABLE, TRUE );
- g_pd3dDevice->SetRenderState( D3DRS_POINTSCALEENABLE, TRUE );
- g_pd3dDevice->SetRenderState( D3DRS_POINTSIZE, FtoDW(0.08f) );
- g_pd3dDevice->SetRenderState( D3DRS_POINTSIZE_MIN, FtoDW(0.00f) );
- g_pd3dDevice->SetRenderState( D3DRS_POINTSCALE_A, FtoDW(0.00f) );
- g_pd3dDevice->SetRenderState( D3DRS_POINTSCALE_B, FtoDW(0.00f) );
- g_pd3dDevice->SetRenderState( D3DRS_POINTSCALE_C, FtoDW(1.00f) );
- // Set up the vertex buffer to be rendered
- g_pd3dDevice->SetStreamSource( 0, m_pVB, 0, sizeof(POINTVERTEX) );
- g_pd3dDevice->SetFVF( D3DFVF_POINTVERTEX );
- PARTICLE* pParticle = m_pParticles;
- POINTVERTEX* 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.
- m_dwBase += m_dwFlush;
- if(m_dwBase >= m_dwDiscard)
- m_dwBase = 0;
- if(FAILED(hr = m_pVB->Lock( m_dwBase * sizeof(POINTVERTEX), m_dwFlush * sizeof(POINTVERTEX),
- (void**) &pVertices, m_dwBase ? D3DLOCK_NOOVERWRITE : D3DLOCK_DISCARD)))
- return hr;
- // pParticle->m_vVel = D3DXVECTOR3(0,0,0);
- // pParticle->m_vPos = D3DXVECTOR3(0,0,0);
- // Render each particle
- while( pParticle )
- {
- D3DXVECTOR3 vPos(pParticle->m_vPos);
- D3DXVECTOR3 vVel(pParticle->m_vVel);
- FLOAT fLengthSq = D3DXVec3LengthSq(&vVel);
- UINT dwSteps;
- vPos.x += fWrapOffsetX;
- vPos.z += fWrapOffsetZ;
- //vVel = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
- if( fLengthSq < 1.0f ) dwSteps = 2;
- else if( fLengthSq < 4.00f ) dwSteps = 3;
- else if( fLengthSq < 9.00f ) dwSteps = 4;
- else if( fLengthSq < 12.25f ) dwSteps = 5;
- else if( fLengthSq < 16.00f ) dwSteps = 6;
- else if( fLengthSq < 20.25f ) dwSteps = 7;
- else dwSteps = 8;
- //dwSteps = 1;
- vVel *= -0.04f / (FLOAT)dwSteps;
- D3DXCOLOR clrDiffuse;
- D3DXColorLerp(&clrDiffuse, &pParticle->m_clrFade, &pParticle->m_clrDiffuse, pParticle->m_fFade);
- DWORD dwDiffuse = (DWORD) clrDiffuse;
- // Render each particle a bunch of times to get a blurring effect
- for( DWORD i = 0; i < dwSteps; i++ )
- {
- pVertices->v = vPos;
- /* pVertices->v = D3DXVECTOR3( (float)((rand() % 100)/100.0f)*100,
- 20.0f+(float)((rand() % 100)/100.0f)*5,
- (float)((rand() % 100)/100.0f)*100 );
- */
- pVertices->color = dwDiffuse;
- pVertices++;
- if( ++dwNumParticlesToRender == m_dwFlush )
- {
- // Done filling this chunk of the vertex buffer. Lets unlock and
- // draw this portion so we can begin filling the next chunk.
- m_pVB->Unlock();
- if(FAILED(hr = g_pd3dDevice->DrawPrimitive( D3DPT_POINTLIST, m_dwBase, 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.
- m_dwBase += m_dwFlush;
- if(m_dwBase >= m_dwDiscard)
- m_dwBase = 0;
- if(FAILED(hr = m_pVB->Lock(m_dwBase * sizeof(POINTVERTEX), m_dwFlush * sizeof(POINTVERTEX),
- (void**) &pVertices, m_dwBase ? D3DLOCK_NOOVERWRITE : D3DLOCK_DISCARD)))
- {
- return hr;
- }
- dwNumParticlesToRender = 0;
- }
- vPos += vVel;
- }
- pParticle = pParticle->m_pNext;
- }
- // Unlock the vertex buffer
- m_pVB->Unlock();
- // Render any remaining particles
- if( dwNumParticlesToRender )
- {
- if(FAILED(hr = g_pd3dDevice->DrawPrimitive( D3DPT_POINTLIST, m_dwBase, dwNumParticlesToRender )))
- return hr;
- }
- // Reset render states
- g_pd3dDevice->SetRenderState( D3DRS_POINTSPRITEENABLE, FALSE );
- g_pd3dDevice->SetRenderState( D3DRS_POINTSCALEENABLE, FALSE );
- return S_OK;
- }