# Kinda lost in Particle Engine :(

This topic is 4969 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

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 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;

};

#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);
}

{
// 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)))
{
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 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);
}

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;
}

{
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);
}



##### Share on other sites
"struct sVertex" can't have functions in it. I remember reading that somewhere, but I can't seem to find it in DirectX's help files at the moment. The only render state that I would think you wouldn't be familiar with would be D3DBLEND_ONE, which basically just takes the black out of your texture image.

You'd probably have a better chance searching GameDev.net for a better explanation of particle systems. I'm not familiar with the way this one is done. I usually do it a little different.

##### Share on other sites
Hmm, are you sure it can't? Another user was helping me initializing the array and told me to use that function. However, I see what you might be getting at. The sizeof(sVertex) won't be yielding the correct size for the vertex buffer if there is an extra function in there right?

##### Share on other sites
Yeah, that's what I was getting at. Also, since you're in 2D, did you set the appropriate render states and texture stage states at initialization? I assumed you did, but that could also be a problem.

##### Share on other sites
Which states are those? I wasn't aware of special states when working in 2D.

##### Share on other sites
These are the usual ones I set accordingly.

//this stuff is usually used in 3D//that you want to turn off(Device)->SetRenderState(D3DRS_CULLMODE,D3DCULL_NONE);(Device)->SetRenderState(D3DRS_LIGHTING,FALSE);//these are only needed if you plan on//using the alpha channel in your textures(Device)->SetRenderState(D3DRS_ALPHABLENDENABLE,TRUE);(Device)->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA);(Device)->SetRenderState(D3DRS_SRCBLEND,D3DBLEND_SRCALPHA);(Device)->SetTextureStageState(0,D3DTSS_ALPHAOP,D3DTOP_MODULATE);

##### Share on other sites
A function will be fine in the vertex structure. If it was a virtual function, it wouldn't work, but a regular function is fine.

##### Share on other sites
Why isn't anything drawing?! This is depressing. I'm using a .png texture with some transparency, and these are my currently set render states:

D3D_device->SetRenderState(D3DRS_ALPHABLENDENABLE,TRUE);
D3D_device->SetRenderState(D3DRS_SRCBLEND,D3DBLEND_SRCALPHA);
D3D_device->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA);

My main function is straight-forward, nothing special:

#define WIN32_LEAN_AND_MEAN#include "WindowsClass.h"#include <D3DX9.h>#include <ctime>#pragma comment(lib,"d3d9.lib")#pragma comment(lib,"d3dx9.lib")#pragma comment(lib,"dxguid.lib")#include "SparkSystem.h"WindowsClass* window;MSG Msg;HWND hWnd;HINSTANCE hInst;clock_t time_now;clock_t movement_timer;IDirect3D9*				D3D;IDirect3DDevice9*		D3D_device;D3DDISPLAYMODE			d3ddm;D3DPRESENT_PARAMETERS	d3dpp;bool isPlaying = true;void initD3D();void uninitD3D();int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd ){	hInst = hInstance;	window = new WindowsClass( hInstance );	hWnd = window->getHWND();	initD3D();	ParticleSystem* sparks = new SparkSystem(4, "spark.png", D3D_device, 200, 200, 0, 16, 16);	sparks->ActivateSystem();	while(Msg.message != WM_QUIT && isPlaying)	{		if(PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE))		{			TranslateMessage(&Msg);			DispatchMessage(&Msg);		}		else		{			time_now = clock();			if(time_now - movement_timer > CLK_TCK/40) 			{				movement_timer = time_now;							}						D3D_device->Clear(0,NULL,D3DCLEAR_TARGET,D3DCOLOR_RGBA(255,255,255,0),1.0f,0);			D3D_device->BeginScene();			sparks->UpdateSystem();			sparks->RenderSystem();						D3D_device->EndScene();			D3D_device->Present(NULL,NULL,NULL,NULL);		}	}	return 0;}void initD3D(){	CoInitialize(NULL);		if((D3D = Direct3DCreate9(D3D_SDK_VERSION)) == NULL)	{		MessageBox(NULL, "Creating D3D Object Failed!", "Error!",        MB_ICONEXCLAMATION | MB_OK);	}	//Set up display mode	d3ddm.Width = 640;	d3ddm.Height = 480;	d3ddm.RefreshRate = 0;	d3ddm.Format = D3DFMT_R5G6B5;	//Set up presentation paramters	d3dpp.Windowed = TRUE;	//d3dpp.SwapEffect = D3DSWAPEFFECT_FLIP;	d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;	d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;	d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;	d3dpp.BackBufferFormat = d3ddm.Format;	d3dpp.BackBufferCount = 1;	d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;    d3dpp.MultiSampleQuality = 0;    d3dpp.hDeviceWindow = hWnd;	d3dpp.Flags = 0;	d3dpp.EnableAutoDepthStencil = FALSE;	d3dpp.BackBufferWidth = 640;	d3dpp.BackBufferHeight = 480;	//Acquire device	if(FAILED(D3D->CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,hWnd,D3DCREATE_SOFTWARE_VERTEXPROCESSING,							&d3dpp,&D3D_device )))	{		MessageBox(NULL, "Creating Device Failed", "Error!",        MB_ICONEXCLAMATION | MB_OK);	}}void uinitD3D(){	CoUninitialize();	UnregisterClass("GameClass", hInst);}

##### Share on other sites
Try adding the following render states:
pDevice->SetTextureStageState(0,D3DTSS_COLOROP,D3DTOP_SELECTARG1);
pDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
pDevice->SetTextureStageState(0,D3DTSS_ALPHAOP,D3DTOP_SELECTARG1);
pDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);

pDevice->SetRenderState(D3DRS_CULLMODE,D3DCULL_NONE);
pDevice->SetRenderState(D3DRS_LIGHTING,FALSE);

Cull mode might be throwing it off, as might the color+alpha sources. Are you drawing anything else? What color is your clear color? A common mistake is to draw nothing else, and have a black clear color, then when your particles show up (incorrectly, but) black you don't see anything.

##### Share on other sites
I added those additional lines, but to no avail. What do you mean what color I am using for my clear color? My texture is opaque blue in the center, and gradually becomes transparent going towards the edges, but it is never fully transparent.

• ### What is your GameDev Story?

In 2019 we are celebrating 20 years of GameDev.net! Share your GameDev Story with us.

• 10
• 11
• 13
• 9
• 11
• ### Forum Statistics

• Total Topics
634092
• Total Posts
3015448
×