创建Particle父类,Snow子类。
Class Particle
#include <cstdlib>
#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<IDirect3DVertexBuffer9*>(_vb);
d3d::Release<IDirect3DTexture9*>(_tex);
}
bool PSystem::init(IDirect3DDevice9* device, char* texFileName)
{
_device = device;
HRESULT hr = 0;
hr = device->CreateVertexBuffer(
_vbSize * sizeof(Particle),
D3DUSAGE_DYNAMIC | D3DUSAGE_POINTS | D3DUSAGE_WRITEONLY,
Particle::FVF,
D3DPOOL_DEFAULT,
&_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<Attribute>::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, false);
_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));
_device->SetRenderState(D3DRS_POINTSCALE_A, d3d::FtoDw(0.0f));
_device->SetRenderState(D3DRS_POINTSCALE_B, d3d::FtoDw(0.0f));
_device->SetRenderState(D3DRS_POINTSCALE_C, d3d::FtoDw(1.0f));
_device->SetTextureStageState(0, D3DTSS_ALPHAARG1, 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() )
{
preRender();
_device->SetTexture(0, _tex);
_device->SetFVF(Particle::FVF);
_device->SetStreamSource(0, _vb, 0, sizeof(Particle));
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;
std::list<Attribute>::iterator i;
for(i = _particles.begin(); i != _particles.end(); i++)
{
if( i->_isAlive )
{
v->_position = i->_position;
v->_color = (D3DCOLOR)i->_color;
v++; // next element;
numParticlesInBatch++; //increase batch counter
if(numParticlesInBatch == _vbBatchSize)
{
_vb->Unlock();
_device->DrawPrimitive(
D3DPT_POINTLIST,
_vbOffset,
_vbBatchSize);
_vbOffset += _vbBatchSize;
if(_vbOffset >= _vbSize)
_vbOffset = 0;
_vb->Lock(
_vbOffset * sizeof( Particle ),
_vbBatchSize * sizeof( Particle ),
(void**)&v,
_vbOffset ? D3DLOCK_NOOVERWRITE : D3DLOCK_DISCARD);
numParticlesInBatch = 0;
}
}
}
_vb->Unlock();
if( numParticlesInBatch )
{
_device->DrawPrimitive(
D3DPT_POINTLIST,
_vbOffset,
numParticlesInBatch);
}
_vbOffset += _vbBatchSize;
postRender();
}
}
bool PSystem::isEmpty()
{
return _particles.empty();
}
bool PSystem::isDead()
{
std::list<Attribute>::iterator i;
for(i = _particles.begin(); i != _particles.end(); i++)
{
if( i->_isAlive )
return false;
}
return true;
}
void PSystem::removeDeadParticles()
{
std::list<Attribute>::iterator i;
i = _particles.begin();
while( i != _particles.end() )
{
if( i->_isAlive == false )
{
i = _particles.erase(i);
}
else
{
i++; // next in list
}
}
}
*****************************************************************************
Class Snow
Snow::Snow(d3d::BoundingBox* boundingBox, int numParticles)
{
_boundingBox = *boundingBox;
_size = 0.25f;
_vbSize = 2048;
_vbOffset = 0;
_vbBatchSize = 512;
for(int i = 0; i < numParticles; i++)
addParticle();
}
void Snow::resetParticle(Attribute* attribute)
{
attribute->_isAlive = true;
d3d::GetRandomVector(
&attribute->_position,
&_boundingBox._min,
&_boundingBox._max);
attribute->_position.y = _boundingBox._max.y;
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;
attribute->_color = d3d::WHITE;
}
void Snow::update(float timeDelta)
{
std::list<Attribute>::iterator i;
for(i = _particles.begin(); i != _particles.end(); i++)
{
i->_position += i->_velocity * timeDelta;
// is the point outside bounds?
if( _boundingBox.isPointInside( i->_position ) == false )
{
// nope so kill it, but we want to recycle dead
// particles, so respawn it instead.
resetParticle( &(*i) );
}
}
}
}
_device->SetRenderState(D3DRS_ZWRITEENABLE, true);
}
Render Snow
#include "d3dUtility.h"
#include "psystem.h"
#include "camera.h"
#include <cstdlib>
#include <ctime>
IDirect3DDevice9* Device = 0;
const int Width = 640;
const int Height = 480;
psys::PSystem* Sno = 0;
Camera TheCamera(Camera::AIRCRAFT);
bool Setup()
{
srand((unsigned int)time(0));
d3d::BoundingBox boundingBox;
boundingBox._min = D3DXVECTOR3(-10.0f, -10.0f, -10.0f);
boundingBox._max = D3DXVECTOR3( 10.0f, 10.0f, 10.0f);
Sno = new psys::Snow(&boundingBox, 5000);
Sno->init(Device, "snowflake.dds");
d3d::DrawBasicScene(Device, 1.0f);
D3DXMATRIX proj;
D3DXMatrixPerspectiveFovLH(
&proj,
D3DX_PI / 4.0f, // 45 - degree
(float)Width / (float)Height,
1.0f,
5000.0f);
Device->SetTransform(D3DTS_PROJECTION, &proj);
return true;
}
void Cleanup()
{
d3d::Delete<psys::PSystem*>( Sno );
d3d::DrawBasicScene(0, 1.0f);
}
bool Display(float timeDelta)
{
if( Device )
{
if( ::GetAsyncKeyState(VK_UP) & 0x8000f )
TheCamera.walk(4.0f * timeDelta);
if( ::GetAsyncKeyState(VK_DOWN) & 0x8000f )
TheCamera.walk(-4.0f * timeDelta);
if( ::GetAsyncKeyState(VK_LEFT) & 0x8000f )
TheCamera.yaw(-1.0f * timeDelta);
if( ::GetAsyncKeyState(VK_RIGHT) & 0x8000f )
TheCamera.yaw(1.0f * timeDelta);
if( ::GetAsyncKeyState('A') & 0x8000f )
TheCamera.strafe(-4.0f * timeDelta);
if( ::GetAsyncKeyState('D') & 0x8000f )
TheCamera.strafe(4.0f * timeDelta);
if( ::GetAsyncKeyState('W') & 0x8000f )
TheCamera.pitch(1.0f * timeDelta);
if( ::GetAsyncKeyState('S') & 0x8000f )
TheCamera.pitch(-1.0f * timeDelta);
D3DXMATRIX V;
TheCamera.getViewMatrix(&V);
Device->SetTransform(D3DTS_VIEW, &V);
Sno->update(timeDelta);
Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x00000000, 1.0f, 0);
Device->BeginScene();
D3DXMATRIX I;
D3DXMatrixIdentity(&I);
Device->SetTransform(D3DTS_WORLD, &I);
d3d::DrawBasicScene(Device, 1.0f);
Device->SetTransform(D3DTS_WORLD, &I);
Sno->render();
Device->EndScene();
Device->Present(0, 0, 0, 0);
}
return true;
}