www.pudn.com > snow.rar > pSystem.cpp
#include#include "pSystem.h" using namespace psys; const DWORD Particle::FVF = D3DFVF_XYZ | D3DFVF_DIFFUSE; PSystem::PSystem() { _device = 0; _vb = 0; _tex = 0; } PSystem::~PSystem() { d3d::Release (_vb); d3d::Release (_tex); } bool PSystem::init(IDirect3DDevice9* device, char* texFileName) { _device = device; // save a ptr to the device HRESULT hr = 0; hr = device->CreateVertexBuffer( _vbSize * sizeof(Particle), D3DUSAGE_DYNAMIC | D3DUSAGE_POINTS | D3DUSAGE_WRITEONLY, Particle::FVF, D3DPOOL_DEFAULT, // D3DPOOL_MANAGED can't be used with D3DUSAGE_DYNAMIC &_vb, 0); if(FAILED(hr)) { ::MessageBox(0, "CreateVertexBuffer() - FAILED", "PSystem", 0); return false; } hr = D3DXCreateTextureFromFile( device, texFileName, &_tex); if(FAILED(hr)) { ::MessageBox(0, "D3DXCreateTextureFromFile() - FAILED", "PSystem", 0); return false; } return true; } void PSystem::reset() { std::list ::iterator i; for(i = _particles.begin(); i != _particles.end(); i++) { resetParticle( &(*i) ); } } void PSystem::addParticle() { Attribute attribute; resetParticle(&attribute); _particles.push_back(attribute); } void PSystem::preRender() { _device->SetRenderState(D3DRS_LIGHTING, true); _device->SetRenderState(D3DRS_POINTSPRITEENABLE, true); _device->SetRenderState(D3DRS_POINTSCALEENABLE, true); _device->SetRenderState(D3DRS_POINTSIZE, d3d::FtoDw(_size)); _device->SetRenderState(D3DRS_POINTSIZE_MIN, d3d::FtoDw(0.0f)); // control the size of the particle relative to distance _device->SetRenderState(D3DRS_POINTSCALE_A, d3d::FtoDw(0.0f)); _device->SetRenderState(D3DRS_POINTSCALE_B, d3d::FtoDw(5.0f)); _device->SetRenderState(D3DRS_POINTSCALE_C, d3d::FtoDw(10.0f)); // use alpha from texture _device->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE ); _device->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE ); _device->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE ); _device->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTA_TEXTURE); _device->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); _device->SetRenderState(D3DRS_ALPHABLENDENABLE, true); _device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); _device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); } void PSystem::postRender() { _device->SetRenderState(D3DRS_LIGHTING, true); _device->SetRenderState(D3DRS_POINTSPRITEENABLE, false); _device->SetRenderState(D3DRS_POINTSCALEENABLE, false); _device->SetRenderState(D3DRS_ALPHABLENDENABLE, false); } void PSystem::render() { if( !_particles.empty() ) { // // set render states // preRender(); _device->SetTexture(0, _tex); _device->SetFVF(Particle::FVF); _device->SetStreamSource(0, _vb, 0, sizeof(Particle)); // // render batches one by one // if(_vbOffset >= _vbSize) _vbOffset = 0; Particle* v = 0; _vb->Lock( _vbOffset * sizeof( Particle ), _vbBatchSize * sizeof( Particle ), (void**)&v, _vbOffset ? D3DLOCK_NOOVERWRITE : D3DLOCK_DISCARD); DWORD numParticlesInBatch = 0; // // Until all particles have been rendered. // std::list ::iterator i; for(i = _particles.begin(); i != _particles.end(); i++) { if( i->_isAlive ) { // // Copy a batch of the living particles to the // next vertex buffer segment // v->_position = i->_position; v->_color = (D3DCOLOR)i->_color; v++; // next element; numParticlesInBatch++; //increase batch counter // if this batch full? if(numParticlesInBatch == _vbBatchSize) { // // Draw the last batch of particles that was // copied to the vertex buffer. // _vb->Unlock(); _device->DrawPrimitive( D3DPT_POINTLIST, _vbOffset, _vbBatchSize); // move the offset to the start of the next batch _vbOffset += _vbBatchSize; if(_vbOffset >= _vbSize) _vbOffset = 0; _vb->Lock( _vbOffset * sizeof( Particle ), _vbBatchSize * sizeof( Particle ), (void**)&v, _vbOffset ? D3DLOCK_NOOVERWRITE : D3DLOCK_DISCARD); numParticlesInBatch = 0; // reset for new batch } } } _vb->Unlock(); if( numParticlesInBatch ) { _device->DrawPrimitive( D3DPT_POINTLIST, _vbOffset, numParticlesInBatch); } // next block _vbOffset += _vbBatchSize; // // reset render states // postRender(); } } bool PSystem::isEmpty() { return _particles.empty(); } bool PSystem::isDead() { std::list ::iterator i; for(i = _particles.begin(); i != _particles.end(); i++) { if( i->_isAlive ) return false; } return true; } void PSystem::removeDeadParticles() { std::list ::iterator i; i = _particles.begin(); while( i != _particles.end() ) { if( i->_isAlive == false ) { i = _particles.erase(i); } else { i++; // next in list } } } //***************************************************************************** // Snow System //*************** Snow::Snow(d3d::BoundingBox* boundingBox, int numParticles) { _boundingBox = *boundingBox; _size = 0.23f; _vbSize = 2048; _vbOffset = 0; _vbBatchSize = 512; for(int i = 0; i < numParticles; i++) addParticle(); } void Snow::resetParticle(Attribute* attribute) { attribute->_isAlive = true; // get random x, z coordinate for the position of the snow flake. d3d::GetRandomVector( &attribute->_position, &_boundingBox._min, &_boundingBox._max); attribute->_position.y = _boundingBox._max.y; // snow flakes fall downwards and slightly to the left attribute->_velocity.x = d3d::GetRandomFloat(0.0f, 1.0f) * -3.0f; attribute->_velocity.y = d3d::GetRandomFloat(0.0f, 1.0f) * -10.0f; attribute->_velocity.z = 0.0f; // white snow flake attribute->_color = d3d::WHITE; } void Snow::update(float timeDelta) { std::list ::iterator i; for(i = _particles.begin(); i != _particles.end(); i++) { i->_position += i->_velocity * timeDelta; if( _boundingBox.isPointInside( i->_position ) == false ) { resetParticle( &(*i) ); } } }