#include "dxstdafx.h" #include ".\particlesystem.h" #include #include #define D3DFVF_PARTICLEVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX2|D3DFVF_TEXCOORDSIZE4(0)|D3DFVF_TEXCOORDSIZE3(1)) D3DXVECTOR3 cameraPosition; float time = 0; bool particleSortAscend(Particle* p1, Particle* p2) { D3DXVECTOR3 t; float dist1 = D3DXVec3Length(D3DXVec3Subtract(&t, &p1->position, &cameraPosition)); float dist2 = D3DXVec3Length(D3DXVec3Subtract(&t, &p2->position, &cameraPosition)); if (dist1 > dist2) return true; return false; } bool particleSortDescend(Particle* p1, Particle* p2) { return particleSortAscend(p1, p2); } double UnitRandom () { return ((double)rand()) / RAND_MAX; } double RangeRandom (double fLow, double fHigh) { return (fHigh-fLow)*UnitRandom() + fLow; } double SymmetricRandom () { return 2.0f * UnitRandom() - 1.0f; } ParticleSystem::ParticleSystem(void) { int frameCount = 0; int maxParticleCount = 0; int currentframe = -1; allVertices = 0; fireTemperature = 0.5; } ParticleSystem::~ParticleSystem(void) { for(int i = 0; i < animFrames.size(); i++) { delete[] allVertices[i]; Frame* f = animFrames.at(i); vector::iterator it; for(it = f->begin(); it != f->end(); it++) { Particle* p = *it; delete p; } f->clear(); delete f; } animFrames.clear(); delete[] allVertices; } void ParticleSystem::setCameraPosition(const D3DXVECTOR3& pos) { cameraPosition = pos; } void ParticleSystem::addSystem(char* filename, bool fire, D3DCOLOR particleColor, float minSize, float maxSize) { ifstream f; f.open(filename, ios_base::in | ios_base::binary); int frameCount; f.read((char*) &frameCount, sizeof(int)); this->frameCount = frameCount; for(int frame = 0; frame < frameCount; frame++) { int particleCount; f.read((char*) &particleCount, sizeof(int)); if(animFrames.size() < frame + 1) animFrames.push_back(new Frame()); Frame* thisFrame = animFrames.at(frame); maxParticleCount += particleCount; for(int p = 0; p < particleCount; p++) { float* positions = new float[3]; f.read((char*) positions, 3 * sizeof(float)); float size=RangeRandom(minSize, maxSize) ; Particle* particle = new Particle(); particle->color = particleColor; particle->position = D3DXVECTOR3(positions[0], positions[1], positions[2]); particle->size = maxSize; particle->fire = fire; delete positions; thisFrame->push_back(particle); } } } void ParticleSystem::initBuffers() { if(allVertices == 0) { allVertices = new vertexFormat*[frameCount]; for(int i = 0; i < frameCount; i++) allVertices[i] = 0; } //sort particles Frame* f = animFrames.at(currentframe); sort(f->begin(), f->end(), particleSortDescend); //create buffer float blockSize = 0.35; int c = 0; int i = currentframe; int particleCount = f->size(); if(allVertices[currentframe] == 0) allVertices[currentframe] = new vertexFormat[particleCount * 6]; for(int j = 0; j < particleCount; j++) { Particle* p = f->at(j); //TexCoords u1, v1 allVertices[i][6 * j].u1 = -1; allVertices[i][6 * j].v1 = -1; allVertices[i][6 * j + 1].u1 = 1; allVertices[i][6 * j + 1].v1 = 1; allVertices[i][6 * j + 2].u1 = -1; allVertices[i][6 * j + 2].v1 = 1; allVertices[i][6 * j + 3].u1 = -1; allVertices[i][6 * j + 3].v1 = -1; allVertices[i][6 * j + 4].u1 = 1; allVertices[i][6 * j + 4].v1 = -1; allVertices[i][6 * j + 5].u1 = 1; allVertices[i][6 * j + 5].v1 = 1; float randD = UnitRandom(); //vertex positions, radius and fire for(int v = 0; v < 6; v++) { allVertices[i][6 * j + v].color = p->color; allVertices[i][6 * j + v].x = p->position.x; allVertices[i][6 * j + v].y = p->position.y; allVertices[i][6 * j + v].z = -p->position.z; allVertices[i][6 * j + v].s1 = p->size; allVertices[i][6 * j + v].t1 = p->fire; allVertices[i][6 * j + v].s2 = randD; } float randX, randY; randX = RangeRandom(blockSize, 1 - blockSize); randY = RangeRandom(blockSize, 1 - blockSize); //TexCoords u2, v2 : random block coordinate allVertices[i][6 * j].u2 = randX - blockSize; allVertices[i][6 * j].v2 = randY - blockSize; allVertices[i][6 * j + 1].u2 = randX + blockSize; allVertices[i][6 * j + 1].v2 = randY + blockSize; allVertices[i][6 * j + 2].u2 = randX - blockSize; allVertices[i][6 * j + 2].v2 = randY + blockSize; allVertices[i][6 * j + 3].u2 = randX - blockSize; allVertices[i][6 * j + 3].v2 = randY - blockSize; allVertices[i][6 * j + 4].u2 = randX + blockSize; allVertices[i][6 * j + 4].v2 = randY - blockSize; allVertices[i][6 * j + 5].u2 = randX + blockSize; allVertices[i][6 * j + 5].v2 = randY + blockSize; c += 6; } } void ParticleSystem::OnCreateDevice( IDirect3DDevice9* pd3dDevice) { this->pd3dDevice = pd3dDevice; ID3DXBuffer* errBuff = NULL; if( FAILED(D3DXCreateEffectFromFile( pd3dDevice, L"Media//Shaders/Explosion.fx", NULL, NULL, NULL, NULL, &sbbEffect, &errBuff ))) { int BufSize = errBuff->GetBufferSize(); // displaying error message of arbitrary length wchar_t* wbuf = new wchar_t[BufSize]; mbstowcs( wbuf, (const char*)errBuff->GetBufferPointer(), BufSize ); MessageBox(NULL, wbuf, L".fx Compilation Error", MB_ICONERROR); // show error message delete wbuf; exit(-1); } } void ParticleSystem::OnDestroyDevice() { SAFE_RELEASE( sbbEffect ); } void ParticleSystem::OnResetDevice() { if( sbbEffect ) sbbEffect->OnResetDevice(); D3DXCreateTextureFromFile( pd3dDevice, FIRE_ALPHA_PATH, &fireAlpha ); D3DXCreateTextureFromFile( pd3dDevice, SMOKE_ALPHA_PATH, &smokeAlpha ); D3DXCreateTextureFromFile( pd3dDevice, PLANCK_COLOR_PATH, &planckColors ); D3DXCreateTextureFromFile( pd3dDevice, NOISE_TEXTURE_PATH, &perlinNoise ); D3DXCreateTextureFromFile( pd3dDevice, GRAD_TEXTURE_PATH, &gradTex ); } void ParticleSystem::OnLostDevice() { if( sbbEffect ) sbbEffect->OnLostDevice(); SAFE_RELEASE(fireAlpha); SAFE_RELEASE(smokeAlpha); SAFE_RELEASE(planckColors); SAFE_RELEASE(perlinNoise); SAFE_RELEASE(gradTex); } void ParticleSystem::draw(IDirect3DTexture9* sceneTexture, IDirect3DTexture9* phaseTexture) { initBuffers(); time += 0.001; if(time > frameCount) time = 0; V( sbbEffect->SetTexture( "FireAlpha", fireAlpha ) ); V( sbbEffect->SetTexture( "SmokeAlpha", smokeAlpha ) ); V( sbbEffect->SetTexture( "PlanckColors", planckColors ) ); V( sbbEffect->SetTexture( "NoiseTexture", perlinNoise ) ); V( sbbEffect->SetTexture( "SceneDepth", sceneTexture ) ); V( sbbEffect->SetTexture( "gradTexture", gradTex ) ); V( sbbEffect->SetTexture( "phaseTexture", phaseTexture ) ); fireTemperature = (params->Get(fFireColor) * 0.8); V( sbbEffect->SetFloat( "fireTemperature", fireTemperature ) ); float densities[3]; densities[0] = params->Get(fFireIntensity) * 3; densities[1] = params->Get(fSmokeIntensity) * 3; densities[2] = params->Get(fDustIntensity) * 3; V( sbbEffect->SetFloatArray("densityFactor", densities, 3) ); float lPos[] = {0,0,0}; V( sbbEffect->SetFloatArray("mLightPos", lPos, 3) ); V( sbbEffect->SetFloat( "time", time / (float)frameCount ) ); float halfPixel[] = { 1.0 / screenWidth * 0.5, 1.0 / screenHeight * 0.5}; V( sbbEffect->SetFloatArray("halfPixel", halfPixel, 2) ); V( sbbEffect->CommitChanges() ); UINT p; sbbEffect->SetTechnique("SBB"); sbbEffect->Begin(&p, 0 ); sbbEffect->BeginPass( 0 ); V(pd3dDevice->SetFVF(D3DFVF_PARTICLEVERTEX)); Frame* f = animFrames.at(currentframe); int particlecount = f->size(); pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); //pd3dDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE); //pd3dDevice->SetRenderState(D3DRS_SRCBLENDALPHA, D3DBLEND_ONE); //pd3dDevice->SetRenderState(D3DRS_DESTBLENDALPHA, D3DBLEND_ONE); pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); pd3dDevice->SetRenderState(D3DRS_ZENABLE, FALSE); V(pd3dDevice->DrawPrimitiveUP(D3DPT_TRIANGLELIST, particlecount * 2, allVertices[currentframe], sizeof(vertexFormat))); pd3dDevice->SetRenderState(D3DRS_ZENABLE, TRUE); pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW); sbbEffect->EndPass(); sbbEffect->End(); } void ParticleSystem::SetWorldViewProj(D3DXMATRIXA16& mWorld, D3DXMATRIXA16& mView, D3DXMATRIXA16& mProj ) { D3DXMATRIXA16 mWorldView = mWorld * mView; D3DXMATRIXA16 mWorldViewProjection = mWorldView * mProj; D3DXMATRIXA16 mWorldViewI, mWorldViewIT; D3DXMatrixInverse(&mWorldViewI, NULL, &mWorldView); D3DXMatrixTranspose(&mWorldViewIT, &mWorldViewI); V( sbbEffect->SetMatrix( "WorldView", &mWorldView ) ); V( sbbEffect->SetMatrix( "WorldViewIT", &mWorldViewIT ) ); V( sbbEffect->SetMatrix( "WorldViewProj", &mWorldViewProjection ) ); V( sbbEffect->SetMatrix( "Proj", &mProj ) ); V( sbbEffect->CommitChanges() ); } void ParticleSystem::stepFrame() { //currentframe = 2; return; currentframe++; if(currentframe == animFrames.size()) currentframe = 0; }