Sign in to follow this  
POLSKASH

Kinda lost in Particle Engine :(

Recommended Posts

POLSKASH    100
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[i].Verts[0].Set( 0.0f, (float)height, 0.0f, 0.0f, 0.0f );
		Particles[i].Verts[1].Set( (float)width, (float)height, 0.0f, 1.0f, 0.0f );
		Particles[i].Verts[2].Set( 0.0f, 0.0f, 0.0f, 0.0f, 1.0f );
		Particles[i].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[i].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[i].Position = D3DXVECTOR3(
        SystemOrigin.x, SystemOrigin.y, SystemOrigin.z);
    Particles[i].Velocity = D3DXVECTOR3(
        1, 2, 0);
    Particles[i].Acceleration = D3DXVECTOR3(0, 0, 0);
    Particles[i].Size = 1.0f;
	Particles[i].Age = 0;
	Particles[i].Alive = false;
}

void SparkSystem::UpdateSystem()
{
	for (int i=0; i < NumParts; i++)
    {
		Particles[i].Age += 1;
        Particles[i].Position += Particles[i].Velocity * 1;
        Particles[i].Velocity += Particles[i].Acceleration;
        if (Particles[i].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[i].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[i].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[i].Size, Particles[i].Size, Particles[i].Size);
			D3DXMatrixTranslation(&matTrans,Particles[i].Position.x,Particles[i].Position.y,Particles[i].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 this post


Link to post
Share on other sites
Idej    122
"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 this post


Link to post
Share on other sites
POLSKASH    100
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 this post


Link to post
Share on other sites
Idej    122
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 this post


Link to post
Share on other sites
Idej    122
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 this post


Link to post
Share on other sites
Kibble    504
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 this post


Link to post
Share on other sites
POLSKASH    100
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 this post


Link to post
Share on other sites
ms291052    223
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 this post


Link to post
Share on other sites
POLSKASH    100
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.

Share this post


Link to post
Share on other sites
POLSKASH    100
I'm starting to have the feeling that maybe it's all that matrix math that's causing nothing to draw. Does the math look alright? It's basically straight from Jim Adam's book.

Share this post


Link to post
Share on other sites
nilkn    960
Quote:
Original post by POLSKASH
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?


Yes, it will, because a function is not stored as part of the class. For example:


// Consider the following class:
class Person
{

public:
void Render(...) { /* ... */ }

private:
// ...
};

// The function Person::Render is translated to something like this by the compiler:

void Person_Render(Person* Class, ...);

// So this code:

Person nick = Person();
nick.Render(...);

// Would be translated to something along these lines:

Person nick = Person();
Person_Render(&nick, ...);




The exception is overriden virtual functions, in which case memory must be allocated for the v-table. Otherwise, functions won't take up space for a class.

[Edited by - nilkn on June 15, 2005 9:28:07 AM]

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this