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

📄 lightningfx.cpp

📁 Blood 2全套源码
💻 CPP
字号:
// ----------------------------------------------------------------------- //
//
// MODULE  : LightningFX.cpp
//
// PURPOSE : Special FX class for lightning-like instant particle streams
//
// CREATED : 8/1/98
//
// ----------------------------------------------------------------------- //

#include "LightningFX.h"
#include "LightningSegmentFX.h"
#include "cpp_client_de.h"
#include "ClientUtilities.h"
#include "ClientServerShared.h"
#include "BloodClientShell.h"
#include "SFXMsgIds.h"
#include "ExplosionFX.h"

// ----------------------------------------------------------------------- //
//
//	ROUTINE:	CLightningBoltFX::Init
//
//	PURPOSE:	Init the stream
//
// ----------------------------------------------------------------------- //

DBOOL CLightningBoltFX::Init(SFXCREATESTRUCT* psfxCreateStruct)
{
	if (!CSpecialFX::Init(psfxCreateStruct)) return DFALSE;

	LIGHTNINGCREATESTRUCT	*pLS = (LIGHTNINGCREATESTRUCT*)psfxCreateStruct;

	VEC_COPY(m_vSource, pLS->vSource);
	VEC_COPY(m_vDest, pLS->vDest);
	m_nShape			= pLS->nShape;
	m_nForm				= pLS->nForm;
	m_nType				= pLS->nType;

	SetupLightning();
	return DTRUE;
}

// ----------------------------------------------------------------------- //
//
//	ROUTINE:	CLightningBoltFX::SetupLightning()
//
//	PURPOSE:	Update the particles
//
// ----------------------------------------------------------------------- //

void CLightningBoltFX::SetupLightning()
{
	m_fMinRadius	= 300.0f;
	m_fMaxRadius	= 3000.0f;
	m_fDensity		= 2.5f;

	m_fDuration		= 0.25f;
	m_fFadeTime		= 0.15f;

	VEC_SET(m_vMinColor, 100.0f, 100.0f, 255.0f);
	VEC_SET(m_vMaxColor, 255.0f, 255.0f, 255.0f);
	m_fAlpha		= 0.75f;

	m_nNumLights	= 3;
	VEC_SET(m_vLightColor, 255.0f, 255.0f, 255.0f);
	m_fLightRadius	= 200.0f;

	m_nLightPos		= LIGHTNING_LIGHTS_SOURCE;

	m_fStartTime	= 0.0f;
	m_hstrTexture	= "SpriteTextures\\lightn32.dtx";
}

// ----------------------------------------------------------------------- //
//
//	ROUTINE:	CLightningBoltFX::CreateObject()
//
//	PURPOSE:	Create the particle system
//
// ----------------------------------------------------------------------- //

DBOOL CLightningBoltFX::CreateObject(CClientDE* pClientDE)
{
	if(!pClientDE)		return DFALSE;
	m_fStartTime = pClientDE->GetTime();

	return CSpecialFX::CreateObject(pClientDE);
}

// ----------------------------------------------------------------------- //
//
//	ROUTINE:	CLightningBoltFX::Update
//
//	PURPOSE:	Update the particles
//
// ----------------------------------------------------------------------- //

DBOOL CLightningBoltFX::Update()
{
	CreateLightning();
	return DFALSE;
}

// ----------------------------------------------------------------------- //
//
//	ROUTINE:	CLightningBoltFX::CreateLightning()
//
//	PURPOSE:	Make the lightning segments
//
// ----------------------------------------------------------------------- //

DBOOL CLightningBoltFX::CreateLightning()
{
	CBloodClientShell *pShell = (CBloodClientShell*)g_pClientDE->GetClientShell();
	CSFXMgr* psfxMgr = pShell->GetSFXMgr();

	if(!psfxMgr || !m_pClientDE)		return DFALSE;

	LSEGMENTCREATESTRUCT	lscs;
	DVector		vTemp;
	DVector		vU, vR, vF;
	DRotation	rRot;
	DFLOAT		fMag, fSegMag, fDirMag;
	DDWORD		m_nNumSegments;

	// Set all the consistant variables for each segment
	lscs.fAlpha = m_fAlpha;
	lscs.fDuration = m_fDuration;
	lscs.fFadeTime = m_fFadeTime;
	lscs.hstrTexture = m_pClientDE->CreateString(m_hstrTexture);

	// Calculate the magnitude
	VEC_SUB(vTemp, m_vDest, m_vSource);
	fMag = VEC_MAG(vTemp);

	// Calculate the min and max offset based on the length
	m_fMaxOffset = fMag / LIGHTNING_OFFSET_RATIO;
	m_fMinOffset = m_fMaxOffset / LIGHTNING_OFFSET_RATIO;

	// Get a rotation to follow the path of
	VEC_SET(vU, 0.0f, 1.0f, 0.0f);
	m_pClientDE->AlignRotation(&rRot, &vTemp, &vU);

	switch(m_nType)
	{
		case LIGHTNING_TYPE_LOWSEG:
			m_nNumSegments = (DDWORD)(fMag / LIGHTNING_SEGMAG_LOW);
			break;
		case LIGHTNING_TYPE_MEDSEG:
			m_nNumSegments = (DDWORD)(fMag / LIGHTNING_SEGMAG_MED);
			break;
		case LIGHTNING_TYPE_HIGHSEG:
			m_nNumSegments = (DDWORD)(fMag / LIGHTNING_SEGMAG_HIGH);
			break;
	}

	if(m_nNumSegments < 5)		m_nNumSegments = 5;
	if(m_nNumSegments > 25)		m_nNumSegments = 25;
	fSegMag = fMag / (float)m_nNumSegments;

	m_fMaxRadius = m_fMaxRadius * (m_nNumSegments / 5);

	//****************************************************************************//
	// Calculate the other variables that will be different for each segment
	DFLOAT		fOffset;
	DFLOAT		radiusRatio = (m_fMaxRadius - m_fMinRadius) / (float)m_nNumSegments;
	DFLOAT		offsetRatio = (m_fMaxOffset - m_fMinOffset) / (float)m_nNumSegments;
	DFLOAT		colorXRatio = (m_vMaxColor.x - m_vMinColor.x) / (float)m_nNumSegments;
	DFLOAT		colorYRatio = (m_vMaxColor.y - m_vMinColor.y) / (float)m_nNumSegments;
	DFLOAT		colorZRatio = (m_vMaxColor.z - m_vMinColor.z) / (float)m_nNumSegments;
	DVector		vDir;

	VEC_COPY(lscs.vOffset, m_vSource);
	VEC_COPY(lscs.vNextOffset, m_vSource);

	if(m_nShape == LIGHTNING_SHAPE_RANDOM)	m_nShape = GetRandom(LIGHTNING_SHAPE_MIN, LIGHTNING_SHAPE_MAX);
	if(m_nForm == LIGHTNING_FORM_RANDOM)	m_nType = GetRandom(LIGHTNING_FORM_MIN, LIGHTNING_FORM_MAX);

	for(DDWORD i = 0; i < m_nNumSegments; i++)
	{
		// Set the variables values for the type of lightning to use
		switch(m_nForm)
		{
			case	LIGHTNING_FORM_WIDE2THIN:
				lscs.fRadius = m_fMaxRadius - ((float)i * radiusRatio);
				fOffset = m_fMaxOffset - ((float)i * offsetRatio);

				lscs.vColor.x = m_vMaxColor.x - ((float)i * colorXRatio);
				lscs.vColor.y = m_vMaxColor.y - ((float)i * colorYRatio);
				lscs.vColor.z = m_vMaxColor.z - ((float)i * colorZRatio);
				break;

			case	LIGHTNING_FORM_THIN2WIDE:
				lscs.fRadius = m_fMinRadius + ((float)i * radiusRatio);
				fOffset = m_fMinOffset + ((float)i * offsetRatio);

				lscs.vColor.x = m_vMinColor.x + ((float)i * colorXRatio);
				lscs.vColor.y = m_vMinColor.y + ((float)i * colorYRatio);
				lscs.vColor.z = m_vMinColor.z + ((float)i * colorZRatio);
				break;

			case	LIGHTNING_FORM_THIN2THIN:
			{
				float	j;
				if(i < (m_nNumSegments >> 1))	j = (float)(i << 1);
					else						j = (float)((m_nNumSegments - 1 - i) << 1);

				lscs.fRadius = m_fMinRadius + (j * radiusRatio);
				fOffset = m_fMinOffset + (j * offsetRatio);

				lscs.vColor.x = m_vMinColor.x + (j * colorXRatio);
				lscs.vColor.y = m_vMinColor.y + (j * colorYRatio);
				lscs.vColor.z = m_vMinColor.z + (j * colorZRatio);
				break;
			}

			case	LIGHTNING_FORM_WIDE2WIDE:
			{
				float	j;
				if(i < (m_nNumSegments >> 1))	j = (float)(i << 1);
					else						j = (float)((m_nNumSegments - 1 - i) << 1);

				lscs.fRadius = m_fMaxRadius - (j * radiusRatio);
				fOffset = m_fMaxOffset - (j * offsetRatio);

				lscs.vColor.x = m_vMaxColor.x - (j * colorXRatio);
				lscs.vColor.y = m_vMaxColor.y - (j * colorYRatio);
				lscs.vColor.z = m_vMaxColor.z - (j * colorZRatio);
				break;
			}

			default:
				lscs.fRadius = m_fMaxRadius - ((float)i * radiusRatio);
				fOffset = m_fMaxOffset - ((float)i * offsetRatio);

				lscs.vColor.x = m_vMaxColor.x - ((float)i * colorXRatio);
				lscs.vColor.y = m_vMaxColor.y - ((float)i * colorYRatio);
				lscs.vColor.z = m_vMaxColor.z - ((float)i * colorZRatio);
				break;
		}

		// Set the variables values for the shape of lightning to use
		switch(m_nShape)
		{
			case	LIGHTNING_SHAPE_FLAT:
				m_pClientDE->GetRotationVectors(&rRot, &vU, &vR, &vF);
				VEC_MULSCALAR(vR, vR, GetRandom(-fOffset, fOffset));
				VEC_MULSCALAR(vF, vF, fSegMag * (float)(i + 1));
				VEC_ADD(lscs.vNextOffset, m_vSource, vF);
				VEC_ADD(lscs.vNextOffset, lscs.vNextOffset, vR);
				break;

			case	LIGHTNING_SHAPE_BOXED:
				m_pClientDE->GetRotationVectors(&rRot, &vU, &vR, &vF);
				VEC_MULSCALAR(vU, vU, GetRandom(-fOffset, fOffset));
				VEC_MULSCALAR(vR, vR, GetRandom(-fOffset, fOffset));
				VEC_MULSCALAR(vF, vF, fSegMag * (float)(i + 1));
				VEC_ADD(lscs.vNextOffset, m_vSource, vF);
				VEC_ADD(lscs.vNextOffset, lscs.vNextOffset, vR);
				VEC_ADD(lscs.vNextOffset, lscs.vNextOffset, vU);
				break;

			case	LIGHTNING_SHAPE_SPIRAL:
			{
				m_pClientDE->GetRotationVectors(&rRot, &vU, &vR, &vF);
				m_pClientDE->RotateAroundAxis(&rRot, &vF, i * (4.0f * MATH_PI / (float)(m_nNumSegments - 1)));
				m_pClientDE->GetRotationVectors(&rRot, &vU, &vR, &vF);
				VEC_MULSCALAR(vR, vR, fOffset);
				VEC_MULSCALAR(vF, vF, fSegMag * (float)(i + 1));
				VEC_ADD(lscs.vNextOffset, m_vSource, vF);
				VEC_ADD(lscs.vNextOffset, lscs.vNextOffset, vR);
				break;
			}

			case	LIGHTNING_SHAPE_STAR:
			{
				m_pClientDE->GetRotationVectors(&rRot, &vU, &vR, &vF);
				m_pClientDE->RotateAroundAxis(&rRot, &vF, (i % 5) * 4.0f * (MATH_PI / 5));
				m_pClientDE->GetRotationVectors(&rRot, &vU, &vR, &vF);
				VEC_MULSCALAR(vR, vR, fOffset);
				VEC_MULSCALAR(vF, vF, fSegMag * (float)(i + 1));
				VEC_ADD(lscs.vNextOffset, m_vSource, vF);
				VEC_ADD(lscs.vNextOffset, lscs.vNextOffset, vR);
				break;
			}

			default:
				m_pClientDE->GetRotationVectors(&rRot, &vU, &vR, &vF);
				VEC_MULSCALAR(vU, vU, GetRandom(-fOffset, fOffset));
				VEC_MULSCALAR(vR, vR, GetRandom(-fOffset, fOffset));
				VEC_MULSCALAR(vF, vF, fSegMag * (float)(i + 1));
				VEC_ADD(lscs.vNextOffset, m_vSource, vF);
				VEC_ADD(lscs.vNextOffset, lscs.vNextOffset, vR);
				VEC_ADD(lscs.vNextOffset, lscs.vNextOffset, vU);
				break;
		}

		if(i == m_nNumSegments - 1)
			{ VEC_COPY(lscs.vNextOffset, m_vDest); }

		// Calculate the direction the particles need to travel from source to dest offsets
		VEC_SUB(vDir, lscs.vNextOffset, lscs.vOffset);
		fDirMag = VEC_MAG(vDir);

		// Determine how many particles need to be drawn to fill the gap
		lscs.nNumParticles = (DDWORD)(fDirMag / (m_fDensity * lscs.fRadius / 1000.0f));

		// Scale the direction offset based on the magnitude and particle count
		lscs.fIncrement = (fDirMag / (float)lscs.nNumParticles);

		// Create the particle segment
 		CSpecialFX* pFX = psfxMgr->CreateSFX(SFX_LIGHTNINGSEG_ID, &lscs, DFALSE, this);

		// Place the offset at the previously calculated next offset
		VEC_COPY(lscs.vOffset, lscs.vNextOffset);
	}

	//****************************************************************************//
	// Variables to create the lights
	EXPLOSIONLIGHTCS	el;
	VEC_MULSCALAR(el.vColor1, m_vLightColor, 1.0f/255.0f);
	VEC_MULSCALAR(el.vColor2, m_vLightColor, 1.0f/255.0f);
	el.fDelay		= 0.0f;
	el.fDuration	= m_fDuration * 2.0f;
	el.fRadius1		= m_fLightRadius;
	el.fRadius2		= m_fLightRadius / 2.0f;

	// Create the lights of the lightning bolt
	for(i = 0; i < m_nNumLights; i++)
	{
		DVector		lightVec;
		DVector		vLightPos;

		switch(m_nLightPos)
		{
			case	LIGHTNING_LIGHTS_SOURCE:
				if(m_nNumLights == 1)
					{ VEC_COPY(el.vPos, m_vSource); }
				else
				{
					VEC_SUB(lightVec, m_vDest, m_vSource);
					VEC_MULSCALAR(vLightPos, lightVec, (float)i / (float)(m_nNumLights - 1));
					VEC_ADD(el.vPos, m_vSource, vLightPos);
				}
				break;

			case	LIGHTNING_LIGHTS_CENTER:
				VEC_SUB(lightVec, m_vDest, m_vSource);
				VEC_MULSCALAR(vLightPos, lightVec, (float)(i + 1) / (float)(m_nNumLights + 1));
				VEC_ADD(el.vPos, m_vSource, vLightPos);
				break;

			case	LIGHTNING_LIGHTS_DEST:
				if(m_nNumLights == 1)
					{ VEC_COPY(el.vPos, m_vDest); }
				else
				{
					VEC_SUB(lightVec, m_vSource, m_vDest);
					VEC_MULSCALAR(vLightPos, lightVec, (float)i / (float)(m_nNumLights - 1));
					VEC_ADD(el.vPos, m_vDest, vLightPos);
				}
				break;
		}

		// Create the particle segment
 		CSpecialFX* pFX = psfxMgr->CreateSFX(SFX_EXPLOSIONLIGHT_ID, &el, DFALSE, this);
	}

	return DTRUE;
}

⌨️ 快捷键说明

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