Original Post
This may be a DirectX problem, but I have a thread over there also. I thought you guys might be able to check out my algorithms for me. I have a 2d user interface which is mainly composed of textured quads. I have just implemented a particle system which uses point sprites but I don't seem to be having much luck. Sometimes I can see the particles and sometimes I can't, and when I can see them they are flashing on and off with a frequency of about 0.5 seconds. The code for the particle system class is shown below. ScreenEntityParticleSystem.cpp ScreenEntityParticleSystem.h Thanks for any help guys, I can't figure out what the problem could be?! Kind regards. Mark Coleman
#include "ScreenEntityParticleSystem.h"
// TODO -- Add the gravity vector as a member of this class
// Also make render call update if the system is not paused
// GetRandomNumber needs to be able to return negative values
// Correct the clearing of stack objects
// Need to take into account the VELOCITY VAR
// Try using an object, the render states will definately be wrong.
// Make sure the states are changed before and after the render method
// Default constructor
ScreenEntityParticleSystem::ScreenEntityParticleSystem()
:ScreenEntityBase()
{
RECT TempRect;
TempRect.bottom = 0;
TempRect.top = 0;
TempRect.left = 0;
TempRect.right = 0;
ReleaseArea = TempRect;
ParticleTextureLocation = "";
Gravity = false;
ReleaseInterval = 1.0f;
MaxParticles = 1;
VBOffset = 0;
Flush = 128;
Discard = 512;
Size = 1.0f;
VelocityVar = 1.0f;
Paused = true;
SupportsPSIZE = false;
LastTime = timeGetTime();
LastEmit = 0.0f;
//TODO -- Is this necessary
//DeadList.clear();
ParticleList.clear();
}
// Copy constructor
ScreenEntityParticleSystem::ScreenEntityParticleSystem(ScreenEntityParticleSystem & rhs)
:ScreenEntityBase(rhs)
{
// Copy all the simple types
ParticleTextureLocation = rhs.GetParticleTextureLocation();
Gravity = rhs.GetGravity();
ReleaseArea = rhs.GetReleaseArea();
ReleaseInterval = rhs.GetReleaseInterval();
MaxParticles = rhs.GetMaxParticles();
VBOffset = rhs.GetVBOffset();
Flush = rhs.GetFlush();
Discard = rhs.GetDiscard();
MaxPointSize = rhs.GetMaxPointSize();
Size = rhs.GetSize();
VelocityVar = rhs.GetVelocityVar();
Paused = rhs.GetPaused();
SupportsPSIZE = rhs.GetSupportsPSIZE();
LastTime = rhs.GetLastTime();
LastEmit = rhs.GetLastEmit();
for(int i = 0;i < DeadList.size();i++)
DeadList.pop();
for(i = 0;i < rhs.GetDeadList().size();i++)
{
DeadList.push(rhs.GetDeadList().top());
rhs.GetDeadList().pop();
}
ParticleList.clear();
for(vector<Particle>::iterator walker = rhs.GetParticleList().begin();walker != rhs.GetParticleList().end();walker++)
{
ParticleList.push_back(*walker);
}
}
// Constructor
ScreenEntityParticleSystem::ScreenEntityParticleSystem(RECT cScreenRectangle,
DWORD cFlags,
int cDepthLevel,
string cBehaviourModifier,
string cParticleTexture)
:ScreenEntityBase(cScreenRectangle,
cFlags,
cDepthLevel,
cBehaviourModifier),
ParticleTextureLocation(cParticleTexture)
{
LastTime = timeGetTime();
LastEmit = 0.0f;
}
// Deconstructor
ScreenEntityParticleSystem::~ScreenEntityParticleSystem()
{
// This may also need to be filled in at a later date
}
// Assignment operator
ScreenEntityParticleSystem& ScreenEntityParticleSystem::operator =(ScreenEntityParticleSystem & rhs)
{
if(this == &rhs)
return *this;
// Call the base class operator so that the full assignment in carried out
ScreenEntityBase::operator=(rhs);
// Copy all the simple types
ParticleTextureLocation = rhs.GetParticleTextureLocation();
Gravity = rhs.GetGravity();
ReleaseArea = rhs.GetReleaseArea();
ReleaseInterval = rhs.GetReleaseInterval();
MaxParticles = rhs.GetMaxParticles();
VBOffset = rhs.GetVBOffset();
Flush = rhs.GetFlush();
Discard = rhs.GetDiscard();
MaxPointSize = rhs.GetMaxPointSize();
Size = rhs.GetSize();
VelocityVar = rhs.GetVelocityVar();
Paused = rhs.GetPaused();
SupportsPSIZE = rhs.GetSupportsPSIZE();
LastTime = rhs.GetLastTime();
LastEmit = rhs.GetLastEmit();
for(int i = 0;i < DeadList.size();i++)
DeadList.pop();
for(i = 0;i < rhs.GetDeadList().size();i++)
{
DeadList.push(rhs.GetDeadList().top());
rhs.GetDeadList().pop();
}
ParticleList.clear();
for(vector<Particle>::iterator walker = rhs.GetParticleList().begin();walker != rhs.GetParticleList().end();walker++)
{
ParticleList.push_back(*walker);
}
return *this;
}
// Initialise the screen entity
HRESULT ScreenEntityParticleSystem::Initialise()
{
// Create a vertex buffer for the particle system
if(FAILED(GlobalDirect3D9Device->CreateVertexBuffer(Discard*sizeof(PointVertex),
D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY | D3DUSAGE_POINTS,
D3DFVF_TLVERTEXPOINT,
D3DPOOL_DEFAULT,
&VertexBuffer,
NULL)))
{
return E_FAIL;
DXTRACE_MSG("Could not create vertex buffer in particle system");
}
// Get the max point size
D3DCAPS9 d3dcaps;
GlobalDirect3D9Device->GetDeviceCaps(&d3dcaps);
MaxPointSize = d3dcaps.MaxPointSize;
// Check to see if we can change the size of the point sprites
if(d3dcaps.FVFCaps & D3DFVFCAPS_PSIZE)
SupportsPSIZE = true;
else
SupportsPSIZE = false;
// Create the texture object
if(FAILED(D3DXCreateTextureFromFile(GlobalDirect3D9Device,
ParticleTextureLocation.c_str(),
&ParticleTexture)))
{
return E_FAIL;
DXTRACE_MSG("Could not create texture file in particle system");
}
// Initialise the GlobalGravityVector
GlobalGravityVector.x = 0;
GlobalGravityVector.y = 0.5;
// The initialisation has been successful so we set the valid flag to true
Flags = Flags | SCREENENTITY_VALID;
return S_OK;
}
HRESULT ScreenEntityParticleSystem::HandleMessage(UINT MessageType, WPARAM wParam, LPARAM lParam)
{
// The particle system is not effected by user input or render calls so just return S_OK
return S_OK;
}
HRESULT ScreenEntityParticleSystem::Update()
{
DXTRACE_MSG("********************************************************");
DXTRACE_MSG("Beginning of update");
OutputInformation();
float CurrentTime = timeGetTime();
float ElapsedTime = (float)((CurrentTime - LastTime) * 0.001);
for(int i = 0;i < ParticleList.size();i++)
{
// If the particle is not dead then we process it
if(!(ParticleList.Dead))
{
// If the particle is dead, put it on the dead list
if(((CurrentTime - ParticleList.StartTime) * 0.001) >= ParticleList.LifeTime)
{
// Tell the Particle that it is dead and put a reference to it on the deadlist
ParticleList.Dead = true;
DeadList.push(i);
}
else
{
// The particle is still in it's active lifetime so we updated the position and velocity
// If gravity is switched on then we apply this here
if(Gravity)
{
ParticleList.CurrentVelocity += GlobalGravityVector * ElapsedTime;
}
// Update the position with respect to the velocity
ParticleList.CurrentPosition += ParticleList.CurrentVelocity * ElapsedTime;
// Update the alpha value
// TODO -- Finsh this
}
}
else
{
// This particle is dead so it does not need to be updated
}
}
// Now we need to emit new particles
if(((CurrentTime - LastEmit) * 0.001f) > ReleaseInterval)
{
// It is time to release a new particle, first check if there are any on the dead list
if(!(DeadList.empty()))
{
// Restart the dead particle
InitialiseParticle(&ParticleList[DeadList.top()]);
// Remove the reference from the deadlist
DeadList.pop();
}
else
{
// There are no dead particles to reactivate so we will make
// another one if there is enough space on the ParticleList
if(ParticleList.size() <= MaxParticles)
{
Particle newParticle;
InitialiseParticle(&newParticle);
ParticleList.push_back(newParticle);
}
else
{
// There is no space for any more particles so we don't do anything
}
}
LastEmit = CurrentTime;
}
// Last update the LastTime float
LastTime = CurrentTime;
DXTRACE_MSG("End of update");
OutputInformation();
DXTRACE_MSG("********************************************************");
return S_OK;
}
HRESULT ScreenEntityParticleSystem::RenderScreenEntity()
{
// If the system is not paused, then update the particles before they are rendered
if(!(Paused))
Update();
// Set the render states for using point sprites
GlobalDirect3D9Device->SetRenderState(D3DRS_POINTSPRITEENABLE, TRUE);
//GlobalDirect3D9Device->SetRenderState(D3DRS_POINTSCALEENABLE, TRUE);
GlobalDirect3D9Device->SetRenderState(D3DRS_POINTSIZE, FtoDW(Size));
GlobalDirect3D9Device->SetRenderState(D3DRS_POINTSIZE_MIN, FtoDW(1.0f));
//GlobalDirect3D9Device->SetRenderState(D3DRS_POINTSCALE_A, FtoDW(0.0f));
//GlobalDirect3D9Device->SetRenderState(D3DRS_POINTSCALE_B, FtoDW(0.0f));
//GlobalDirect3D9Device->SetRenderState(D3DRS_POINTSCALE_C, FtoDW(1.0f));
GlobalDirect3D9Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
// Used as a reference to the vertex buffer
PointVertex* Vertices;
DWORD NumParticlesToRender= 0;
// Lock the vertex buffer. Fill the vertex buffer in small chunks, using D3DLOCK_NOOVERWRITE.
// When done filling each chunk, call DrawPrimitive and lock the next chunk. When space runs
// out in the vertex buffer, start over at the beginning using D3DLOCK_DISCARD.
// Move the offset to fill the next chunk of the vertex buffer
VBOffset += Flush;
// If about to overflow the buffer, set it back to 0
if(VBOffset >= Discard)
VBOffset = 0;
// Lock the vertex buffer
HRESULT hr;
if(FAILED(hr = VertexBuffer->Lock(VBOffset*sizeof(PointVertex), // Offset to lock
Flush*sizeof(PointVertex), // Size to lock
(VOID **) &Vertices,
VBOffset ? D3DLOCK_NOOVERWRITE : D3DLOCK_DISCARD)))
{
DXTRACE_ERR("Failed to lock the vertex buffer in the render method of the particle system", hr);
return hr;
}
GlobalDirect3D9Device->SetStreamSource(0, VertexBuffer, 0, sizeof(PointVertex));
// Render each particle
for(vector<Particle>::iterator walker = ParticleList.begin(); walker != ParticleList.end();walker++)
{
if(!(walker->Dead))
{
D3DXVECTOR2 vVel(walker->CurrentVelocity);
Vertices->posit = walker->CurrentPosition;
Vertices->color = walker->Colour;
Vertices++;
if(++NumParticlesToRender == Flush)
{
// Done filling this chunk of the vertex buffer so unlock and draw so that the
// next chunk can start being filled
VertexBuffer->Unlock();
GlobalDirect3D9Device->SetFVF(D3DFVF_TLVERTEXPOINT);
if(FAILED(hr = GlobalDirect3D9Device->DrawPrimitive(D3DPT_POINTLIST,
VBOffset,
NumParticlesToRender)))
{
DXTRACE_ERR("Draw primitive failed inside the Flush-if in the render method", hr);
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.
VBOffset += Flush;
// If about to overflow reset the offset to 0
if(VBOffset >= Discard)
VBOffset = 0;
if(FAILED(hr = VertexBuffer->Lock(VBOffset*sizeof(PointVertex),
Flush*sizeof(PointVertex),
(VOID **) &Vertices,
VBOffset ? D3DLOCK_NOOVERWRITE : D3DLOCK_DISCARD)))
{
DXTRACE_ERR("Failed to lock the vertex buffer in the latter part of the render method", hr);
return hr;
}
NumParticlesToRender = 0;
}
}
else
{
// Do nothing as this particle is dead
}
}
// Unlock the vertex buffer
VertexBuffer->Unlock();
// Render any remaining particles
if(NumParticlesToRender)
{
GlobalDirect3D9Device->SetFVF(D3DFVF_TLVERTEXPOINT);
if(FAILED(hr = GlobalDirect3D9Device->DrawPrimitive(D3DPT_POINTLIST,
VBOffset,
NumParticlesToRender)))
{
DXTRACE_ERR("Draw primitive failed inside the final part of the render method", hr);
return hr;
}
}
// Reset render states
GlobalDirect3D9Device->SetRenderState(D3DRS_POINTSPRITEENABLE, FALSE);
GlobalDirect3D9Device->SetRenderState(D3DRS_POINTSCALEENABLE, FALSE);
GlobalDirect3D9Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
GlobalDirect3D9Device->SetFVF(D3DFVF_TLVERTEX);
// Re-set the stream source
GlobalDirect3D9Device->SetStreamSource(0, GlobalDirect3D9VertexBuffer, 0, sizeof(TLVERTEX));
return S_OK;
}
void ScreenEntityParticleSystem::OutputInformation()
{
char output[500];
// Walk through the particle list and for each particle output the colour, position,
// velocity, starttime, lifetime and alpha decay
for(vector<Particle>::iterator walker = ParticleList.begin();walker != ParticleList.end();walker++)
{
sprintf(output, "Position x: %f, Position y: %f, Velocity x: %f, Velocity y: %f, Starttime: %f, LifeTime: %f, AlphaDecay: %f",
walker->CurrentPosition.x,
walker->CurrentPosition.y,
walker->CurrentVelocity.x,
walker->CurrentVelocity.y,
walker->StartTime,
walker->LifeTime,
walker->AlphaDecay);
DXTRACE_MSG(output);
}
}
void ScreenEntityParticleSystem::Release()
{
SAFE_RELEASE(VertexBuffer);
SAFE_RELEASE(ParticleTexture);
//TODO -- Is this necessary
//DeadList.clear();
ParticleList.clear();
}
void ScreenEntityParticleSystem::ControlEntity(bool start)
{
if(start)
Paused = false;
else
Paused = true;
}
void ScreenEntityParticleSystem::InitialiseParticle(Particle* DeadParticle)
{
// Tell the particle that it is alive!
DeadParticle->Dead = false;
// Place the particle somewhere within the release area
DeadParticle->CurrentPosition.x = GetRandomNumber(ReleaseArea.left, ReleaseArea.right);
DeadParticle->CurrentPosition.y = GetRandomNumber(ReleaseArea.top, ReleaseArea.bottom);
// Set the intial velocity, colour, lifetime and alpha decay in accordance with the type of effect being created
if((Flags & PARTICLE_FIRE) > 0)
{
// ************** VELOCITY ****
// If this is fire then all the particles need to be sent more or less upwards so we
// set the y value to -2 (-y is up) and then add a Random between -10 and 10 divided
// 10 leading to +/-1
DeadParticle->CurrentVelocity.y = -2.0f;
DeadParticle->CurrentVelocity.y += (float)(GetRandomNumber(-10, 10)/10);
// The x is set straight up the middle (0) but we vary it with a random number between
// 10 and -10 which is then divide by 20 giving a maximum of 0.5 either way. That equates
// to a maximum angle of 22.5 degrees which may have to be reduced
DeadParticle->CurrentVelocity.x = 0.0f;
DeadParticle->CurrentVelocity.x += (float)(GetRandomNumber(-10,10)/20);
// ************** COLOUR ****
// Define each colour element (plus the alpha)
float r, g, b, a, random;
// Calculate the random to be 0.2 either way. So get a random number between -10 and
// 10 and then divide it by fifty.
//random = (float)(GetRandomNumber(-10,10)/50); // Random
r = 0.5f;// + random; // Red
g = 0.5f;// + random; // Green
b = 0.5f;// + random; // Blue
a = 0.5f; // Start the alpha at full
// Set the colour
DeadParticle->Colour = D3DXCOLOR(r, g, b, a);
// ************** LIFETIME ****
// Alter the life time by 0.5 either way
DeadParticle->LifeTime = 10.5f;// + (float)((GetRandomNumber(-10,10)/20));
// ************** ALPHA DECAY ****
// Alter the alpha decay by 0.1 either way
DeadParticle->AlphaDecay = 0.1;// + (float)((GetRandomNumber(-10, 10)/100));
}
else if((Flags & PARTICLE_DUST) > 0)
{
DXTRACE_MSG("Particle dust not defined yet!!");
}
else
{
DXTRACE_MSG("Particle system is of an invalid type or flag not set");
PostQuitMessage(0);
}
// Set the start time of the particle
DeadParticle->StartTime = timeGetTime();
}
// Get and set methods
string ScreenEntityParticleSystem::GetParticleTextureLocation()
{
return ParticleTextureLocation;
}
void ScreenEntityParticleSystem::SetParticleTextureLocation(string newParticleTextureLocation)
{
ParticleTextureLocation = newParticleTextureLocation;
}
bool ScreenEntityParticleSystem::GetGravity()
{
return Gravity;
}
void ScreenEntityParticleSystem::SetGravity(bool newGravity)
{
Gravity = newGravity;
}
DWORD ScreenEntityParticleSystem::GetVBOffset()
{
return VBOffset;
}
void ScreenEntityParticleSystem::SetVBOffset(DWORD newVBOffset)
{
VBOffset = newVBOffset;
}
RECT ScreenEntityParticleSystem::GetReleaseArea()
{
return ReleaseArea;
}
bool ScreenEntityParticleSystem::GetSupportsPSIZE()
{
return SupportsPSIZE;
}
void ScreenEntityParticleSystem::SetReleaseArea(RECT newReleaseArea)
{
ReleaseArea = newReleaseArea;
}
float ScreenEntityParticleSystem::GetReleaseInterval()
{
return ReleaseInterval;
}
void ScreenEntityParticleSystem::SetReleaseInterval(float newReleaseInterval)
{
ReleaseInterval = newReleaseInterval;
}
int ScreenEntityParticleSystem::GetMaxParticles()
{
return MaxParticles;
}
void ScreenEntityParticleSystem::SetMaxParticles(int newMaxParticles)
{
MaxParticles = newMaxParticles;
}
DWORD ScreenEntityParticleSystem::GetFlush()
{
return Flush;
}
void ScreenEntityParticleSystem::SetFlush(DWORD newFlush)
{
Flush = newFlush;
}
DWORD ScreenEntityParticleSystem::GetDiscard()
{
return Discard;
}
void ScreenEntityParticleSystem::SetDicard(DWORD newDiscard)
{
Discard = newDiscard;
}
float ScreenEntityParticleSystem::GetMaxPointSize()
{
return MaxPointSize;
}
void ScreenEntityParticleSystem::SetMaxPointSize(float newMaxPointSize)
{
MaxPointSize = newMaxPointSize;
}
float ScreenEntityParticleSystem::GetSize()
{
return Size;
}
void ScreenEntityParticleSystem::SetSize(float newSize)
{
Size = newSize;
}
float ScreenEntityParticleSystem::GetVelocityVar()
{
return VelocityVar;
}
void ScreenEntityParticleSystem::SetVelocityVar(float newVelocityVar)
{
VelocityVar = newVelocityVar;
}
bool ScreenEntityParticleSystem::GetPaused()
{
return Paused;
}
void ScreenEntityParticleSystem::SetPaused(bool newPaused)
{
Paused = newPaused;
}
float ScreenEntityParticleSystem::GetLastTime()
{
return LastTime;
}
void ScreenEntityParticleSystem::SetLastTime(float newLastTime)
{
LastTime = newLastTime;
}
float ScreenEntityParticleSystem::GetLastEmit()
{
return LastEmit;
}
void ScreenEntityParticleSystem::SetLastEmit(float newLastEmit)
{
LastEmit = newLastEmit;
}
stack<int> ScreenEntityParticleSystem::GetDeadList()
{
return DeadList;
}
void ScreenEntityParticleSystem::SetDeadList(stack<int> newDeadList)
{
for(int i = 0;i < DeadList.size();i++)
DeadList.pop();
for(i = 0;i < newDeadList.size();i++)
{
DeadList.push(newDeadList.top());
newDeadList.pop();
}
}
vector<Particle> ScreenEntityParticleSystem::GetParticleList()
{
return ParticleList;
}
void ScreenEntityParticleSystem::SetParticleList(vector<Particle> newParticleList)
{
ParticleList.clear();
for(vector<Particle>::iterator walker = newParticleList.begin();walker != newParticleList.end();walker++)
{
ParticleList.push_back(*walker);
}
}
#ifndef SCREENENTITYPARTICLESYSTEM
#define SCREENENTITYPARTICLESYSTEM
#include "ScreenEntityBase.h"
struct Particle
{
D3DXVECTOR2 CurrentPosition; // The current position of the particle
D3DXVECTOR2 CurrentVelocity; // The current velocity of the particle
D3DCOLOR Colour; // The colour of the particle (RGBA)
float StartTime; // The time the particle started
float LifeTime; // The amount of time the particle has to live
float AlphaDecay; // The amount of alpha which decays each second
bool Dead;
};
class ScreenEntityParticleSystem : public ScreenEntityBase
{
public:
// (De)Constructors
ScreenEntityParticleSystem(); // Default constructor
ScreenEntityParticleSystem(ScreenEntityParticleSystem & rhs); // Copy constructor
ScreenEntityParticleSystem(RECT cScreenRectangle,
DWORD cFlags,
int cDepthLevel,
string cBehaviourModifier,
string cParticleTexture); // Constrcutor
~ScreenEntityParticleSystem(); // Deconstructor
// Assignment operator
ScreenEntityParticleSystem& ScreenEntityParticleSystem::operator =(ScreenEntityParticleSystem & rhs);
// Public methods
HRESULT Initialise();
HRESULT HandleMessage(UINT MessageType, WPARAM wParam, LPARAM lParam);
HRESULT RenderScreenEntity();
void OutputInformation();
virtual void Release();
virtual void ControlEntity(bool start);
// Get and set methods
string GetParticleTextureLocation();
void SetParticleTextureLocation(string newParticleTextureLocation);
bool GetGravity();
void SetGravity(bool newGravity);
RECT GetReleaseArea();
void SetReleaseArea(RECT newReleaseArea);
float GetReleaseInterval();
void SetReleaseInterval(float newReleaseInterval);
int GetMaxParticles();
void SetMaxParticles(int newMaxParticles);
DWORD GetFlush();
void SetFlush(DWORD newFlush);
DWORD GetDiscard();
void SetDicard(DWORD newDiscard);
float GetMaxPointSize();
void SetMaxPointSize(float newMaxPointSize);
float GetSize();
void SetSize(float newSize);
float GetVelocityVar();
void SetVelocityVar(float newVelocityVar);
DWORD GetVBOffset();
void SetVBOffset(DWORD newVBOffset);
bool GetPaused();
void SetPaused(bool newPaused);
bool GetSupportsPSIZE();
void SetSupportsPSIZE(bool newSupportsPSIZE);
float GetLastTime();
void SetLastTime(float newLastTime);
float GetLastEmit();
void SetLastEmit(float newLastEmit);
stack<int> GetDeadList();
void SetDeadList(stack<int> newDeadList);
vector<Particle> GetParticleList();
void SetParticleList(vector<Particle> newParticleList);
private:
// Private methods
HRESULT Update();
void InitialiseParticle(Particle* DeadParticle);
// Private Data Members
string ParticleTextureLocation; // The location of the particle file
bool Gravity; // true if gravity is to be taken into account
RECT ReleaseArea; // A rect from within which the particles are emitted
float ReleaseInterval; // The interval at which new particles should be released
int MaxParticles; // The maximum number of particles which may exist in the system
DWORD VBOffset; // The offset of the VB to write to
DWORD Flush; // The number of sprites to send to the hardware at once
DWORD Discard; // The maximum number of point sprites that the vertex buffer can load before we have to discard and start again
float MaxPointSize; // The maximum point size
float Size; // The size of the sprite to be drawn
float VelocityVar; // A scaling factor for the velocity
bool Paused; // Updates on particles are not carried out if this is true
bool SupportsPSIZE; // Hardware allows us to change the size of the point sprites
float LastTime; // Holds the time when the last updated occured
float LastEmit; // The last time new particles were emitted
LPDIRECT3DVERTEXBUFFER9 VertexBuffer; // Holds the vertices to be rendered
LPDIRECT3DTEXTURE9 ParticleTexture;// Stores the particle texture
stack<int> DeadList; // Holds the dead particles
vector<Particle> ParticleList; // Holds all the particles
};
#endif