Having finished my first 2D game, I'm trying to make the leap into particle engines. I've been trying to write my own engine, pulling in ideas from 2 different sources. My engine compiles right now, but nothing is drawing to the screen in my little test application. I'm basically using Jim Adam's Roleplaying book for rendering help, and another online tutorial for the design ideas.
What I don't like about this book is that he gives you an overview of C++ and all this other bullcrap about writing a story for games, and attempts to teach you about particles in 2 pages. WTF?
Anyways, I don't fully understand what the D3DMATERIAL9 object does in his example, and all these SetRenderState calls. Basically I'm just lost at the moment, but I really don't want to throw away what I have, I've worked hard looking at both sources and putting this together. I really think I'm on the right track though. Any suggestions/pointers/advice and clue as to why this is not working as it is would be appreciated. Here's what I have:
Particle Two structs and my particle system class
#ifndef ParticleSystem_H_
#define ParticleSystem_H_
#include <d3d9.h>
#include <D3DX9.h>
#define D3D_OVERLOADS
#define VERTEX_FVF (D3DFVF_XYZ | D3DFVF_TEX1)
struct sVertex
{
void Set( float fX, float fY, float fZ, float fU, float fV )
{
x = fX; y = fY; z = fZ;
u = fU; v = fV;
}
float x, y, z;
float u, v;
};
struct Particle
{
D3DXVECTOR3 Position; // Position of particle in world-space
D3DXVECTOR3 OldPos; // Position in last frame
D3DXVECTOR3 Velocity; // Velocity along the three axes
D3DXVECTOR3 Acceleration; // Acceleration along the three axes
int Age; // Age of particle (sum of TimePassed passed to UpdateSystem)
float Size; // Size of particle
bool Alive; // Does this particle need to be updated?
sVertex Verts[4];
};
class ParticleSystem
{
protected:
IDirect3DDevice9* D3D_device;
Particle *Particles;
int NumParts;
D3DXVECTOR3 SystemOrigin; // origin of system in world-space (origin param of constructor)
public:
ParticleSystem(int numparts, float xOrig, float yOrig, float zOrig, int width, int height, IDirect3DDevice9* device);
virtual ~ParticleSystem(); // destructor
virtual void UpdateOrigin(float x, float y, float z){SystemOrigin.x = x; SystemOrigin.y = y; SystemOrigin.z = z;}
virtual void ActivateSystem();
virtual void ResetSystem(float xOrig, float yOrig, float zOrig); // Initializes system, don't have to overwrite
virtual void SetParticleDefaults(int i) = 0; // resets particle; must overwrite
virtual void UpdateSystem() = 0; // must overwrite
virtual void RenderSystem() = 0; // must overwrite
IDirect3DTexture9* srcTexture;
IDirect3DTexture9* loadTexture(char* filename, D3DCOLOR key);
};
#endif
ParticleSystem function definitions
#include "ParticleSystem.h"
ParticleSystem::ParticleSystem(int numparts, float xOrig, float yOrig, float zOrig, int width, int height, IDirect3DDevice9* device)
{
D3D_device = device;
NumParts = numparts; // store number of particles
Particles = new Particle[NumParts]; // allocate particles array
for(int i = 0; i < NumParts; i++)
{
Particles.Verts[0].Set( 0.0f, (float)height, 0.0f, 0.0f, 0.0f );
Particles.Verts[1].Set( (float)width, (float)height, 0.0f, 1.0f, 0.0f );
Particles.Verts[2].Set( 0.0f, 0.0f, 0.0f, 0.0f, 1.0f );
Particles.Verts[3].Set( (float)width, 0.0f, 0.0f, 1.0f, 1.0f );
}
SystemOrigin.x = xOrig;// store system origin
SystemOrigin.y = yOrig;
SystemOrigin.z = zOrig;
}
ParticleSystem::~ParticleSystem()
{
if (Particles) { delete[] Particles; Particles = NULL; }
}
void ParticleSystem::ActivateSystem()
{
for(int i = 0; i < NumParts; i++)
{
Particles.Alive = true;
}
}
void ParticleSystem::ResetSystem(float xOrig, float yOrig, float zOrig)
{
SystemOrigin.x = xOrig;
SystemOrigin.y = yOrig;
SystemOrigin.z = zOrig;
for (int i=0; i < NumParts; i++)
SetParticleDefaults(i);
}
IDirect3DTexture9* ParticleSystem::loadTexture(char* filename,D3DCOLOR key)
{
// Second parameter is the color key. Use 0xFFFF00FF for magenta. 0xFF000000 for black.
// Use 0x00000000 for no 'color key' substitution
IDirect3DTexture9* texture;
D3DXIMAGE_INFO SrcInfo; // Optional
if(FAILED(D3DXCreateTextureFromFileEx( D3D_device, filename, 0, 0, 1, 0,
D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, D3DX_FILTER_NONE, D3DX_DEFAULT,
key, &SrcInfo , NULL, &texture)))
{
MessageBox(NULL, "Failed to load paddle texture", "Error!",
MB_ICONEXCLAMATION | MB_OK);
}
return texture;
}
I create a SparkSystem class to attempt to use my ParticleSystem class, but nothing is drawing.
#ifndef SparkSystem_H_
#define SparkSystem_H_
#include "ParticleSystem.h"
class SparkSystem : public ParticleSystem
{
public:
SparkSystem(int numparts, char* filename, IDirect3DDevice9* device, float xOrig, float yOrig, float zOrig, int width, int height);
virtual ~SparkSystem();
//float Width, Depth, Ground; // size of system. Can be freely changed after initialization.
virtual void SetParticleDefaults(int i);
virtual void UpdateSystem();
virtual void RenderSystem();
private:
IDirect3DTexture9* ParticleTexture;
};
#endif
And the definitions for the SparkSystem class.
#include "SparkSystem.h"
SparkSystem::SparkSystem(int numparts, char* filename, IDirect3DDevice9* device, float xOrig, float yOrig, float zOrig, int width, int height) : ParticleSystem(numparts, xOrig, yOrig, zOrig, width, height, device)
{
ResetSystem(xOrig, yOrig, zOrig);
srcTexture = loadTexture(filename, 0x00000000);
}
SparkSystem::~SparkSystem()
{
if(Particles)
{
delete[] Particles;
Particles = NULL;
}
srcTexture->Release();
}
void SparkSystem::SetParticleDefaults(int i)
{
// position the particles somewhere near the system origin (same height, within
// rectangle specified by Width and Depth). Give them random speed downwards:
Particles.Position = D3DXVECTOR3(
SystemOrigin.x, SystemOrigin.y, SystemOrigin.z);
Particles.Velocity = D3DXVECTOR3(
1, 2, 0);
Particles.Acceleration = D3DXVECTOR3(0, 0, 0);
Particles.Size = 1.0f;
Particles.Age = 0;
Particles.Alive = false;
}
void SparkSystem::UpdateSystem()
{
for (int i=0; i < NumParts; i++)
{
Particles.Age += 1;
Particles.Position += Particles.Velocity * 1;
Particles.Velocity += Particles.Acceleration;
if (Particles.Age >= 500)
SetParticleDefaults(i);
}
}
void SparkSystem::RenderSystem()
{
D3DXMATRIX matWorld, matView, matTransposed;
D3DXMATRIX matTrans, matScale;
D3DMATERIAL9 d3dm;
IDirect3DVertexBuffer9* vertBuffer;
BYTE* Ptr;
D3D_device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
D3D_device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
D3D_device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
D3D_device->SetRenderState(D3DRS_AMBIENT, 0xffffffff);
for(int i = 0; i < NumParts; i++)
{
if(Particles.Alive)
{
D3D_device->CreateVertexBuffer(sizeof(sVertex)*4, 0, VERTEX_FVF, D3DPOOL_DEFAULT, &vertBuffer,NULL);
vertBuffer->Lock(0, 0, (void**)&Ptr,0);
for(int j = 0; j < 4; j++)
memcpy(Ptr, (void*)&Particles.Verts[j], sizeof(sVertex));
vertBuffer->Unlock();
D3D_device->SetStreamSource(0, vertBuffer, 0, sizeof(sVertex));
D3D_device->SetTexture(0, srcTexture);
ZeroMemory(&d3dm, sizeof(D3DMATERIAL9));
d3dm.Diffuse.r = d3dm.Ambient.r = 1.0f;
d3dm.Diffuse.g = d3dm.Ambient.g = 1.0f;
d3dm.Diffuse.b = d3dm.Ambient.b = 1.0f;
d3dm.Diffuse.a = d3dm.Ambient.a = 1.0f;
D3D_device->SetMaterial(&d3dm);
D3DXMatrixScaling(&matScale, Particles.Size, Particles.Size, Particles.Size);
D3DXMatrixTranslation(&matTrans,Particles.Position.x,Particles.Position.y,Particles.Position.z);
D3D_device->GetTransform(D3DTS_VIEW, &matView);
D3DXMatrixTranspose(&matTransposed, &matView);
D3DXMatrixMultiply(&matWorld, &matScale, &matTransposed);
D3DXMatrixMultiply(&matWorld, &matWorld, &matTrans);
D3D_device->SetTransform(D3DTS_WORLD, &matWorld);
D3D_device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
}
}
D3D_device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
}
There are some things so stupid that only an intellect could believe them.