⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 m2particle.cpp

📁 3D游戏展示程序
💻 CPP
字号:
//--------------------------------------------------
//  Desc: M2 Particle System
//--------------------------------------------------

#include "M2Particle.h"
#include "M2Loader.h"
#include "Common.h"

#define MAX_M2PARTICLES 1000

D3DXVECTOR4 FromARGB(uint32 color)
{
	const float a = ((color & 0xFF000000) >> 24) / 255.0f;
	const float r = ((color & 0x00FF0000) >> 16) / 255.0f;
	const float g = ((color & 0x0000FF00) >>  8) / 255.0f;
	const float b = ((color & 0x000000FF)      ) / 255.0f;
	return D3DXVECTOR4(r, g, b, a);
}

template<class T>
T lifeRamp(float life, float mid, const T &a, const T &b, const T &c)
{
	if(life<=mid) return InterpolateLinear<T>(life / mid, a, b);
	else		  return InterpolateLinear<T>((life-mid) / (1.0f-mid), b, c);
}

M2ParticleSystem::M2ParticleSystem(): 
m_Emitter(NULL), 
m_pModel(NULL), 
m_ParentBone(NULL), 
m_hTexture(0), 
m_Mid(0), 
m_fRemain(0)
{
	m_Blend = 0;
	m_Order = 0;
	m_Type = 0;
	m_AnimID = 0;
	m_AnimTime = 0;
	m_Rows = 0;
	m_Cols = 0;

	m_Slowdown = 0;
	m_Rotation = 0;
	m_Tofs = 0;
}

M2ParticleSystem::~M2ParticleSystem()
{ 
	delete m_Emitter; 
}

void M2ParticleSystem::Init(uint8* pData, ModelParticleEmitterDef &emitter, int *pGlobalSequence)
{
	m_Speed.Init(emitter.params[0], pData, pGlobalSequence);		// 发射速度
	m_Variation.Init(emitter.params[1], pData, pGlobalSequence);	// 速度变化(0-1)
	m_Spread.Init(emitter.params[2], pData, pGlobalSequence);		// 相对发射器发射方向的扩散角度(0-PI)
	m_Lat.Init(emitter.params[3], pData, pGlobalSequence);
	m_Gravity.Init(emitter.params[4], pData, pGlobalSequence);		// 重力
	m_Lifespan.Init(emitter.params[5], pData, pGlobalSequence);		// 寿命
	m_Rate.Init(emitter.params[6], pData, pGlobalSequence);			// 发射率
	m_Areal.Init(emitter.params[7], pData, pGlobalSequence);		// 发射区域的长度
	m_Areaw.Init(emitter.params[8], pData, pGlobalSequence);		// 发射区域的宽度
	m_Deacceleration.Init(emitter.params[9], pData, pGlobalSequence);// 向心力
	m_Enabled.Init(emitter.en, pData, pGlobalSequence);

	for(int i=0; i<3; i++) 
	{
		m_Colors[i] = FromARGB(emitter.p.colors[i]);
		m_Sizes[i] = emitter.p.sizes[i];
	}
	m_Mid = emitter.p.mid;
	m_Slowdown = emitter.p.slowdown;
	m_Rotation = emitter.p.rotation;
	m_Position = FixCoordSystemVector(emitter.pos);
	/*
	texture = model->textures[emitter.texture];
	*/
	m_Blend = emitter.blend;
	m_Rows = emitter.rows;
	m_Cols = emitter.cols;
	m_Type = emitter.s1;
	m_Order = emitter.s1>0 ? -1 : 0;
	m_ParentBone = m_pModel->m_pBone + emitter.bone;

	switch(emitter.type)
	{
	case 1:
		m_Emitter = new PlaneEmitter(this);
		break;
	case 2:
		m_Emitter = new SphereEmitter(this);
		break;
	}

	m_bBillboard = !(emitter.flags & 0x1000);

	// diagnosis test info
	m_Flags = emitter.flags;

	m_AnimID = m_AnimTime = 0;
	m_fRemain = 0;

	m_Tofs = rand()/(float)RAND_MAX;

	for(int i=0; i<m_Rows*m_Cols; i++)
	{
		TexCoordSet texcoord;
		InitTile(texcoord.tc, i);
		m_Tiles.push_back(texcoord);
	}
}

void M2ParticleSystem::InitTile(D3DXVECTOR2 *tilecoord, int num)
{
	D3DXVECTOR2 oldtilecoord[4];
	D3DXVECTOR2 a,b;
	int x = num % m_Cols;
	int y = num / m_Cols;
	a.x = x * (1.0f / m_Cols);
	b.x = (x+1) * (1.0f / m_Cols);
	a.y = y * (1.0f / m_Rows);
	b.y = (y+1) * (1.0f / m_Rows);

	oldtilecoord[0] = a;
	oldtilecoord[2] = b;
	oldtilecoord[1].x = b.x;
	oldtilecoord[1].y = a.y;
	oldtilecoord[3].x = a.x;
	oldtilecoord[3].y = b.y;

	for(int i=0; i<4; i++)
	{
		tilecoord[(i+4-m_Order) & 3] = oldtilecoord[i];
	}
}

void M2ParticleSystem::Update(float dt)
{
	float fgrav = m_Gravity.GetValue(m_AnimID, m_AnimTime);
	float fdeaccel = m_Deacceleration.GetValue(m_AnimID, m_AnimTime);

	// spawn new particles
	if(m_Emitter)
	{
		float frate = m_Rate.GetValue(m_AnimID, m_AnimTime);
		float flife = 1.0f;
		float ftospawn = (dt * frate / flife) + m_fRemain;
		if(ftospawn < 1.0f) 
		{
			m_fRemain = ftospawn;
			if(m_fRemain<0.0f) 	m_fRemain = 0.0f;
		}
		else
		{
			int tospawn = (int)ftospawn;
			if((tospawn + m_Particles.size()) > MAX_M2PARTICLES)
				tospawn = (int)m_Particles.size() - MAX_M2PARTICLES;

			m_fRemain = ftospawn - (float)tospawn;

			float w = m_Areal.GetValue(m_AnimID, m_AnimTime) * 0.5f;
			float l = m_Areaw.GetValue(m_AnimID, m_AnimTime) * 0.5f;
			float spd = m_Speed.GetValue(m_AnimID, m_AnimTime);
			float var = m_Variation.GetValue(m_AnimID, m_AnimTime);
			float spr = m_Spread.GetValue(m_AnimID, m_AnimTime);
			float spr2 = m_Lat.GetValue(m_AnimID, m_AnimTime);
			bool en = m_Enabled.GetValue(m_AnimID, m_AnimTime) != 0;

			if(en)
			{
				for(int i=0; i<tospawn; i++)
				{
					M2Particle p = m_Emitter->NewParticle(m_AnimID, m_AnimTime, w, l, spd, var, spr, spr2);
					m_Particles.push_back(p);
				}
			}
		}
	}

	float mspeed = 1.0f;
	for(M2ParticleList::iterator it = m_Particles.begin(); it != m_Particles.end(); )
	{
		M2Particle &p = *it;
		p.m_speed += p.m_down * fgrav * dt - p.m_dir * fdeaccel * dt;

		if(m_Slowdown>0)
		{
			mspeed = expf(-1.0f * m_Slowdown * p.m_flife);
		}
		p.m_pos += p.m_speed * mspeed * dt;

		p.m_flife += dt;
		float rlife = p.m_flife / p.m_fmaxlife;
		// calculate size and color based on lifetime
		p.m_fsize = lifeRamp<float>(rlife, m_Mid, m_Sizes[0], m_Sizes[1], m_Sizes[2]);
		p.m_color = lifeRamp<D3DXVECTOR4>(rlife, m_Mid, m_Colors[0], m_Colors[1], m_Colors[2]);

		if(rlife >= 1.0f) 
			m_Particles.erase(it++);
		else 
			++it;
	}
}

void M2ParticleSystem::Render(const D3DXMATRIX &matRotate)
{
	D3DXMATRIX matTrans;
	D3DXMatrixIdentity(&matTrans);
	if(m_bBillboard)
	{			D3DXMATRIX matTemp;		g_pD3DDevice->GetTransform(D3DTS_VIEW, &matTemp);		float temp;		D3DXMatrixInverse(&matTemp, &temp, &matTemp);		if(m_Flags == 569) 		{ 			// Faith shoulders, do cylindrical billboarding			matTrans = matTemp;			matTrans._12 = 0.0f;			matTrans._14 = 0.0f;			matTrans._21 = 0.0f;			matTrans._23 = 0.0f;			matTrans._24 = 0.0f;			matTrans._32 = 0.0f;			matTrans._34 = 0.0f;			matTrans._41 = 0.0f;			matTrans._42 = 0.0f;			matTrans._43 = 0.0f;		} 		else 		{ 			// Spherical billboarding			matTrans = matTemp;			matTrans._14 = 0.0f;			matTrans._24 = 0.0f;			matTrans._34 = 0.0f;			matTrans._41 = 0.0f;			matTrans._42 = 0.0f;			matTrans._43 = 0.0f;		}		}

	D3DXVECTOR3 bv0;
	D3DXVECTOR3 bv1;
	D3DXVECTOR3 bv2;
	D3DXVECTOR3 bv3;
	float f = 0.5f;

	float ftemp;
	D3DXMATRIX matRot;
	D3DXMatrixInverse(&matRot, &ftemp, &matRotate);
	matTrans *= matRot;

	D3DXVec3TransformCoord(&bv0, &D3DXVECTOR3(+f, +f, 0), &matTrans);
	D3DXVec3TransformCoord(&bv1, &D3DXVECTOR3(-f, +f, 0), &matTrans);
	D3DXVec3TransformCoord(&bv2, &D3DXVECTOR3(-f, -f, 0), &matTrans);
	D3DXVec3TransformCoord(&bv3, &D3DXVECTOR3(+f, -f, 0), &matTrans);
	m_Index = 0;
	for(M2ParticleList::iterator it = m_Particles.begin(); it != m_Particles.end(); )
	{
		M2Particle &p = *it;
		
		m_Vertex[m_Index++].SetVertex(p.m_pos+p.m_fsize*bv0, 0xffffffff, m_Tiles[it->m_tile].tc[0]);
		m_Vertex[m_Index++].SetVertex(p.m_pos+p.m_fsize*bv1, 0xffffffff, m_Tiles[it->m_tile].tc[1]);
		m_Vertex[m_Index++].SetVertex(p.m_pos+p.m_fsize*bv2, 0xffffffff, m_Tiles[it->m_tile].tc[2]);
		m_Vertex[m_Index++].SetVertex(p.m_pos+p.m_fsize*bv2, 0xffffffff, m_Tiles[it->m_tile].tc[2]);
		m_Vertex[m_Index++].SetVertex(p.m_pos+p.m_fsize*bv3, 0xffffffff, m_Tiles[it->m_tile].tc[3]);
		m_Vertex[m_Index++].SetVertex(p.m_pos+p.m_fsize*bv0, 0xffffffff, m_Tiles[it->m_tile].tc[0]);
		++it;
	}
	g_pD3DDevice->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE);
	g_pD3DDevice->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL);
	g_pD3DDevice->SetRenderState(D3DRS_ALPHAREF, 0x2f);
	//g_pD3DDevice->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
	g_pD3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
	g_pD3DDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
	g_pD3DDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);

	g_pD3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
	g_pD3DDevice->SetFVF(M2PARTICLEFVF);
	g_pD3DDevice->DrawPrimitiveUP(D3DPT_TRIANGLELIST, m_Index/3, m_Vertex, sizeof(M2ParticleVertex));
	g_pD3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);

	g_pD3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
	g_pD3DDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
	g_pD3DDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
	//g_pD3DDevice->SetRenderState(D3DRS_ZWRITEENABLE, TRUE);
	g_pD3DDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);

}

void M2ParticleSystem::Setup(int anim, int time)
{
	m_AnimID = anim;
	m_AnimTime = time;
}

D3DXMATRIX g_matSpread;
void CalcSpreadMatrix(float Spread1,float Spread2, float w, float l)
{
	float angle[2];
	float c[2];
	float s[2];
	
	D3DXMATRIX matTemp;

	angle[0] = RandomFloat(-Spread1, Spread1)/2.0f;
	angle[1] = RandomFloat(-Spread2, Spread2)/2.0f;
	for(int i=0; i<2; i++)
	{		
		c[i]=cos(angle[i]);
		s[i]=sin(angle[i]);
	}
	D3DXMatrixIdentity(&g_matSpread);
	g_matSpread._11 *= l;
	g_matSpread._22 *= l;
	g_matSpread._33 *= w;
	
	D3DXMatrixIdentity(&matTemp);
	matTemp._22 = c[0];
	matTemp._23 = s[0];
	matTemp._32 = -s[0];
	matTemp._33 = c[0];
	// Rotate X
	g_matSpread *= matTemp;

	D3DXMatrixIdentity(&matTemp);
	matTemp._11 = c[1];
	matTemp._12 = s[1];
	matTemp._21 = -s[1];
	matTemp._22 = c[1];
	// Rotate Z
	g_matSpread *= matTemp;
}

M2Particle PlaneEmitter::NewParticle(int animID, int time, float w, float l, float spd, float var, float spr, float spr2)
{
	M2Particle particle;

	//Spread Calculation
	D3DXMATRIX matRot;
	CalcSpreadMatrix(spr, spr, 1.0f, 1.0f);
	matRot = m_PS->m_ParentBone->m_matRotate*g_matSpread;

	if(m_PS->m_Flags == 1041)
	{ 
		// Trans Halo
		D3DXVECTOR3 pos = (m_PS->m_Position + D3DXVECTOR3(RandomFloat(-l, l), 0, RandomFloat(-w, w)));
		D3DXVec3TransformCoord(&particle.m_pos, &pos, &m_PS->m_ParentBone->m_matTrans);

		float fangle = RandomFloat(0.0f, 2*AS_PI);
		particle.m_pos = D3DXVECTOR3(0.0f, m_PS->m_Position.y + 0.15f, m_PS->m_Position.y) + 
			D3DXVECTOR3(cos(fangle)/8.0f, 0.0f, sin(fangle)/8.0f);

		D3DXVECTOR3 dir(0.0f, 1.0f, 0.0f);

		particle.m_speed = dir * spd * RandomFloat(0.0f, var);
	}
	/*
	else if(m_PS->m_Flags == 25 && m_PS->m_ParentBone->m_Parent<1)
	{ 
		// Weapon Flame
		
		particle.m_pos = m_PS->m_ParentBone->m_Point + (m_PS->m_Position + 
			D3DXVECTOR3(RandomFloat(-l, l), RandomFloat(-l, l), RandomFloat(-w, w)));

		D3DXVECTOR3 dir;
		D3DXVec3TransformCoord(&dir, &D3DXVECTOR3(0.0f, 1.0f, 0.0f), &matRot);
		
	}
	*/
	else if(m_PS->m_Flags == 25 && m_PS->m_ParentBone->m_Parent>0) 
	{ 
		// Weapon with built-in Flame (Avenger lightsaber!)
	//	particle.m_pos = m_PS->m_ParentBone->m_matTrans * (m_PS->m_Position + 
	//		D3DXVECTOR3(RandomFloat(-l, l), RandomFloat(-l, l), RandomFloat(-w, w)));
	//	Vec3D dir = Vec3D(sys->parent->mat.m[1][0],sys->parent->mat.m[1][1], sys->parent->mat.m[1][2]) * Vec3D(0.0f, 1.0f, 0.0f);
	//	p.speed = dir.normalize() * spd * randfloat(0, var*2);

	}else if(m_PS->m_Flags == 17 && m_PS->m_ParentBone->m_Parent<1)
	{ 
		// Weapon Glow
	//	particle.m_pos = m_PS->m_ParentBone->m_Point * (m_PS->m_Position + 
	//		D3DXVECTOR3(RandomFloat(-l, l), RandomFloat(-l, l), RandomFloat(-w, w)));

	}
	else
	{
		particle.m_pos = m_PS->m_Position + D3DXVECTOR3(RandomFloat(-l, l), 0, RandomFloat(-w, w));
		D3DXVec3TransformCoord(&particle.m_pos, &particle.m_pos, &m_PS->m_ParentBone->m_matTrans);
		D3DXVECTOR3 dir;
		D3DXVec3TransformCoord(&dir, &D3DXVECTOR3(0.0f, 1.0f, 0.0f), &matRot);
		particle.m_down = D3DXVECTOR3(0.0f, -1.0f,0.0f);
		D3DXVec3Normalize(&dir, &dir);
		particle.m_speed = dir * spd * (1.0f + RandomFloat(-var, var));
	}

	if(!m_PS->m_bBillboard)
	{		/*		D3DXVECTOR3 look = particle.m_dir;		look.x=p.dir.y;		look.y=p.dir.z;		look.z=p.dir.x;		Vec3D up = ( look % p.dir).normalize();		Vec3D right = (up % p.dir).normalize();		up = (p.dir % right).normalize();		// calculate the billboard matrix		p.mface.m[0][1] = right.x;		p.mface.m[1][1] = right.y;		p.mface.m[2][1] = right.z;		p.mface.m[0][2] = up.x;		p.mface.m[1][2] = up.y;		p.mface.m[2][2] = up.z;		p.mface.m[0][0] = p.dir.x;		p.mface.m[1][0] = p.dir.y;		p.mface.m[2][0] = p.dir.z;
		*/
	}

	particle.m_flife = 0.0f;
	particle.m_fmaxlife = m_PS->m_Lifespan.GetValue(animID, time);

	particle.m_origin = particle.m_pos;

	particle.m_tile = RandomInt(0, m_PS->m_Rows*m_PS->m_Cols-1);
	return particle;
}

M2Particle SphereEmitter::NewParticle(int animID, int time, float w, float l, float spd, float var, float spr, float spr2)
{
	M2Particle particle;
	return particle;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -