IEffectPainter *CEffectCreator::CreatePainterFromStreamAndCreator (SLoadCtx &Ctx, CEffectCreator *pCreator)

//	CreatePainterFromStreamAndCreator
//
//	Load a painter from a stream given a creator

	{
	//	Older versions did not save UNID or class if there was no creator

	if (Ctx.dwVersion < 43 && pCreator == NULL)
		return NULL;

	//	The UNID is ignored (because it is the UNID of the creator)

	IEffectPainter::ReadUNID(Ctx);

	//	Validate the class

	if (IEffectPainter::ValidateClass(Ctx, pCreator ? pCreator->GetTag() : NULL_STR) != NOERROR)
		return NULL;

	//	Load it

	if (pCreator == NULL)
		return NULL;

	IEffectPainter *pPainter = pCreator->CreatePainter();
	pPainter->ReadFromStream(Ctx);

	//	Done

	return pPainter;
	}
ALERROR IEffectPainter::ValidateClass (SLoadCtx &Ctx, const CString &sOriginalClass)

//	ValidateClass
//
//	Reads the class string. If the class does not match the current painter,
//	we read the old data and return ERR_FAIL.

	{
	if (Ctx.dwVersion >= 40)
		{
		CString sClass;
		sClass.ReadFromStream(Ctx.pStream);

		//	If the original class doesn't match the current one, then it means
		//	that the design changed. In that case, we load the painter using the
		//	old class.

		if (!strEquals(sClass, sOriginalClass))
			{
			//	If sClass is blank, then it means that the original did not have
			//	an effect painter (but the current design does)

			if (!sClass.IsBlank())
				{
				//	Get the original creator

				CEffectCreator *pOriginalCreator;
				if (CEffectCreator::CreateFromTag(sClass, &pOriginalCreator) != NOERROR)
					{
					kernelDebugLogMessage("Unable to find original effect creator: %s", sClass.GetASCIIZPointer());
					return ERR_FAIL;
					}

				//	Load the original painter

				IEffectPainter *pOriginalPainter = pOriginalCreator->CreatePainter();
				pOriginalPainter->ReadFromStream(Ctx);

				//	Discard

				pOriginalPainter->Delete();
				delete pOriginalCreator;
				}

			//	Done

			return ERR_FAIL;
			}
		}

	return NOERROR;
	}
Exemple #3
0
IEffectPainter *COrbEffectCreator::CreatePainter (CCreatePainterCtx &Ctx)

//	CreatePainter
//
//	Creates a new painter
	
	{
	//	If we have a singleton, return that

	if (m_pSingleton)
		return m_pSingleton;

	//	Otherwise we need to create a painter with the actual
	//	parameters.

	IEffectPainter *pPainter = new COrbEffectPainter(this);

	//	Initialize the painter parameters

	pPainter->SetParam(Ctx, ANIMATE_ATTRIB, m_Animate);
	pPainter->SetParam(Ctx, RADIUS_ATTRIB, m_Radius);
	pPainter->SetParam(Ctx, STYLE_ATTRIB, m_Style);
	pPainter->SetParam(Ctx, INTENSITY_ATTRIB, m_Intensity);
	pPainter->SetParam(Ctx, PRIMARY_COLOR_ATTRIB, m_PrimaryColor);
	pPainter->SetParam(Ctx, SECONDARY_COLOR_ATTRIB, m_SecondaryColor);
	pPainter->SetParam(Ctx, LIFETIME_ATTRIB, m_Lifetime);

	//	Initialize via GetParameters, if necessary

	InitPainterParameters(Ctx, pPainter);

	//	If we are a singleton, then we only need to create this once.

	if (GetInstance() == instGame)
		{
		pPainter->SetSingleton(true);
		m_pSingleton = pPainter;
		}

	return pPainter;
	}
void CSmokeTrailPainter::OnReadFromStream (SLoadCtx &Ctx)

//	OnReadFromStream
//
//	Load from stream

	{
	m_Particles.ReadFromStream(Ctx);

	Ctx.pStream->Read((char *)&m_iLastDirection, sizeof(DWORD));
	Ctx.pStream->Read((char *)&m_iEmitLifetime, sizeof(DWORD));
	Ctx.pStream->Read((char *)&m_iTick, sizeof(DWORD));

	if (m_pParticlePainter)
		m_pParticlePainter->Delete();

	m_pParticlePainter = CEffectCreator::CreatePainterFromStreamAndCreator(Ctx, m_pCreator->GetParticleEffect());
	}
void CSmokeTrailPainter::Paint (CG16bitImage &Dest, int x, int y, SViewportPaintCtx &Ctx)

//	Paint
//
//	Paint

	{
	int iParticleLifetime = m_pCreator->GetParticleLifetimeMax();

	//	Particles move the opposite direction from the shot

	int iTrailDirection = (Ctx.iRotation + m_pCreator->GetRotation()) % 360;

	//	If we haven't created any particles yet, do it now

	if (m_iLastDirection == -1)
		{
		CreateNewParticles(m_pCreator->GetNewParticleCount(), iTrailDirection);
		}

	//	Paint with the painter

	if (m_pParticlePainter)
		{
		//	If we can get a paint descriptor, use that because it is faster

		SParticlePaintDesc Desc;
		if (m_pParticlePainter->GetParticlePaintDesc(&Desc))
			{
			Desc.iMaxLifetime = iParticleLifetime;
			m_Particles.Paint(Dest, x, y, Ctx, Desc);
			}

		//	Otherwise, we use the painter for each particle

		else
			m_Particles.Paint(Dest, x, y, Ctx, m_pParticlePainter);
		}

	//	Update

	m_iLastDirection = iTrailDirection;
	}
Exemple #6
0
void CParticleJetEffectPainter::OnUpdate (SEffectUpdateCtx &Ctx)

//	OnUpdate
//
//	Update the painter

	{
	//	Update the single-particle painter

	if (m_pParticlePainter)
		m_pParticlePainter->OnUpdate(Ctx);

	//	LATER: Support damage

#if 0
	//	If we have a wake potential or if the particles do damage
	//	then we need to hit test against all objects in the system.

	Ctx.pDamageDesc = m_pCreator->GetDamageDesc();
	Ctx.iWakePotential = m_pCreator->GetWakePotential();

	if ((Ctx.pDamageDesc || Ctx.iWakePotential > 0) && Ctx.pSystem)
		{
		//	Update

		m_Particles.Update(Ctx);
		}
#endif

	//	Create new particles

	if (!Ctx.bFade)
		CreateNewParticles(Ctx.pObj, m_EmitRate.Roll(), Ctx.vEmitPos, CalcInitialVel(Ctx.pObj));
	else if (m_bUseObjectMotion && Ctx.pObj)
		m_vLastEmitPos = Ctx.pObj->GetPos();

	//	If we're fading, reset direction (otherwise, when painting thruster 
	//	effects we'll try to interpolate between stale directions).

	if (Ctx.bFade)
		m_iCurDirection = -1;
	}
Exemple #7
0
void CParticleJetEffectPainter::OnMove (SEffectMoveCtx &Ctx, bool *retbBoundsChanged)

//	OnMove
//
//	Move the particles

	{
	//	Update the single-particle painter

	if (m_pParticlePainter)
		m_pParticlePainter->OnMove(Ctx);

	//	Update particle motion

	m_Particles.UpdateMotionLinear();

	//	If we're using the object's motion, adjust now

	if (m_bUseObjectMotion && Ctx.pObj)
		{
		CVector vToOldPos;
		if (m_bTrackingObject)
			{
			CVector vCurPos = Ctx.pObj->GetPos();
			vToOldPos = Ctx.vOldPos - vCurPos;
			}
		else
			{
			Metric rSpeed = Ctx.pObj->GetVel().Length();
			vToOldPos = ::PolarToVector(180 + m_iLastDirection, rSpeed * g_SecondsPerUpdate);
			}

		//	Move all particles by the given amount

		m_Particles.Move(vToOldPos);
		}

	//	Bounds are always changing

	if (retbBoundsChanged)
		*retbBoundsChanged = true;
	}
IEffectPainter *CEffectCreator::CreatePainterFromStream (SLoadCtx &Ctx, bool bNullCreator)

//	CreatePainterFromStream
//
//	Load a painter from a stream

	{
	CEffectCreator *pCreator;

	//	For previous versions, we only stored UNID if we had a creator

	if (Ctx.dwVersion < 43 && bNullCreator)
		return NULL;

	//	At version 15 we started saving versions as string UNIDs. We need to do this
	//	because sometimes the effect creator is inside a weapon fire desc
	//	structure (also identified by string UNIDs).

	if (Ctx.dwVersion >= 15)
		{
		CString sUNID;
		sUNID.ReadFromStream(Ctx.pStream);

		pCreator = (sUNID.IsBlank() ? NULL : CEffectCreator::FindEffectCreator(sUNID));

		//	Load the creator class that saved the painter

		if (IEffectPainter::ValidateClass(Ctx, (pCreator ? pCreator->GetTag() : NULL_STR)) != NOERROR)
			return NULL;

		//	Error

		if (pCreator == NULL)
			{
			if (!sUNID.IsBlank())
				kernelDebugLogMessage("Invalid painter creator: %s", sUNID.GetASCIIZPointer());
			return NULL;
			}
		}

	//	Old style uses DWORD UNIDs

	else
		{
		//	The first DWORD is the UNID of the creator

		DWORD dwUNID;
		Ctx.pStream->Read((char *)&dwUNID, sizeof(DWORD));
		if (dwUNID == 0)
			return NULL;

		pCreator = g_pUniverse->FindEffectType(dwUNID);

		//	Error

		if (pCreator == NULL)
			{
			kernelDebugLogMessage("Invalid painter creator: %x", dwUNID);
			return NULL;
			}
		}

	//	Let the creator create the object

	IEffectPainter *pPainter = pCreator->CreatePainter();

	//	Load it

	pPainter->ReadFromStream(Ctx);

	//	Done

	return pPainter;
	}
Exemple #9
0
IEffectPainter *CRayEffectCreator::CreatePainter (CCreatePainterCtx &Ctx)

//	CreatePainter
//
//	Creates a new painter
	
	{
	//	If we have a singleton, return that

	if (m_pSingleton)
		return m_pSingleton;

	//	Otherwise we need to create a painter with the actual
	//	parameters.

	IEffectPainter *pPainter = new CRayEffectPainter(this);

	//	Initialize the painter parameters

	pPainter->SetParam(Ctx, ANIMATE_OPACITY_ATTRIB, m_AnimateOpacity);
	pPainter->SetParam(Ctx, LENGTH_ATTRIB, m_Length);
	pPainter->SetParam(Ctx, WIDTH_ATTRIB, m_Width);
	pPainter->SetParam(Ctx, SHAPE_ATTRIB, m_Shape);
	pPainter->SetParam(Ctx, STYLE_ATTRIB, m_Style);
	pPainter->SetParam(Ctx, INTENSITY_ATTRIB, m_Intensity);
	pPainter->SetParam(Ctx, PRIMARY_COLOR_ATTRIB, m_PrimaryColor);
	pPainter->SetParam(Ctx, SECONDARY_COLOR_ATTRIB, m_SecondaryColor);
	pPainter->SetParam(Ctx, LIFETIME_ATTRIB, m_Lifetime);
	pPainter->SetParam(Ctx, XFORM_ROTATION_ATTRIB, m_XformRotation);

	//	Initialize via GetParameters, if necessary

	InitPainterParameters(Ctx, pPainter);

	//	If we are a singleton, then we only need to create this once.

	if (GetInstance() == instGame)
		{
		pPainter->SetSingleton(true);
		m_pSingleton = pPainter;
		}

	return pPainter;
	}
Exemple #10
0
IEffectPainter *CParticleJetEffectCreator::CreatePainter (CCreatePainterCtx &Ctx)

//	CreatePainter
//
//	Creates a new painter
	
	{
	//	If we have a singleton, return that

	if (m_pSingleton)
		return m_pSingleton;

	//	Otherwise we need to create a painter with the actual
	//	parameters.

	IEffectPainter *pPainter = new CParticleJetEffectPainter(Ctx, this);

	//	Initialize the painter parameters

	pPainter->SetParam(Ctx, EMIT_RATE_ATTRIB, m_EmitRate);

	pPainter->SetParam(Ctx, FIXED_POS_ATTRIB, m_FixedPos);
	pPainter->SetParam(Ctx, PARTICLE_LIFETIME_ATTRIB, m_ParticleLifetime);
	pPainter->SetParam(Ctx, LIFETIME_ATTRIB, m_Lifetime);
	pPainter->SetParam(Ctx, XFORM_ROTATION_ATTRIB, m_XformRotation);
	pPainter->SetParam(Ctx, XFORM_TIME_ATTRIB, m_XformTime);

	if (!m_FixedPos.EvalBool(Ctx) || m_EmitSpeed.GetType() != CEffectParamDesc::typeNull)
		pPainter->SetParam(Ctx, EMIT_SPEED_ATTRIB, m_EmitSpeed);

	if (m_SpreadAngle.GetType() != CEffectParamDesc::typeNull)
		pPainter->SetParam(Ctx, SPREAD_ANGLE_ATTRIB, m_SpreadAngle);
	else
		pPainter->SetParam(Ctx, TANGENT_SPEED_ATTRIB, m_TangentSpeed);

	//	Initialize via GetParameters, if necessary

	InitPainterParameters(Ctx, pPainter);

	//	If we are a singleton, then we only need to create this once.

	if (GetInstance() == instGame)
		{
		pPainter->SetSingleton(true);
		m_pSingleton = pPainter;
		}

	return pPainter;
	}
Exemple #11
0
void CParticleJetEffectPainter::Paint (CG32bitImage &Dest, int x, int y, SViewportPaintCtx &Ctx)

//	Paint
//
//	Paint the effect

	{
	int iParticleLifetime = m_ParticleLifetime.GetMaxValue();

	//	Particles move the opposite direction from the shot

	int iTrailDirection = Ctx.iRotation;

	//	If we're using the object center then we paint at the object center.
	//	Otherwise we paint at the given position.

	int xPaint;
	int yPaint;
	if (m_bUseObjectCenter)
		{
		if (Ctx.pObj)
			Ctx.XForm.Transform(Ctx.pObj->GetPos(), &xPaint, &yPaint);
		else
			{
			//	If we don't have an object then we use the viewport center. This
			//	handles the case where we paint in TransData (where there is
			//	no object).

			xPaint = Ctx.xCenter;
			yPaint = Ctx.yCenter;
			}
		}
	else
		{
		xPaint = x;
		yPaint = y;
		}

	//	If we haven't created any particles yet, do it now

	if (m_iCurDirection == -1
			&& !Ctx.bFade)
		{
		m_iLastDirection = iTrailDirection;
		m_iCurDirection = iTrailDirection;

		//	Figure out the position where we create particles

		CVector vPos;

		//	If we're using the object center then it means that x,y is where
		//	we emit particles from. We need to convert from screen coordinates
		//	to object-relative coordinates.

		if (m_bUseObjectCenter)
			vPos = CVector((x - xPaint) * g_KlicksPerPixel, (yPaint - y) * g_KlicksPerPixel);

		//	Initialize last emit position

		m_vLastEmitPos = (m_bUseObjectMotion && Ctx.pObj ? Ctx.pObj->GetPos() + vPos : vPos);

		//	Create particles

		CreateNewParticles(Ctx.pObj, m_EmitRate.Roll(), vPos, CalcInitialVel(Ctx.pObj));
		}

	//	Paint with the painter

	if (m_pParticlePainter)
		{
		//	If we can get a paint descriptor, use that because it is faster

		SParticlePaintDesc Desc;
		if (m_pParticlePainter->GetParticlePaintDesc(&Desc))
			{
			Desc.iMaxLifetime = iParticleLifetime;
			m_Particles.Paint(Dest, xPaint, yPaint, Ctx, Desc);
			}

		//	Otherwise, we use the painter for each particle

		else
			m_Particles.Paint(Dest, xPaint, yPaint, Ctx, m_pParticlePainter);
		}

	//	Update

	m_iCurDirection = iTrailDirection;
	}
Exemple #12
0
void CEffectEntry::GetImage (const CCompositeImageSelector &Selector, CObjectImageArray *retImage)

//	GetImage
//
//	Fills in the image

	{
	//	Short circuit

	if (m_pEffect.IsEmpty())
		{
		*retImage = EMPTY_IMAGE;
		return;
		}

	//	Create a painter

	CCreatePainterCtx Ctx;
	IEffectPainter *pPainter = m_pEffect->CreatePainter(Ctx);
	if (pPainter == NULL)
		{
		*retImage = EMPTY_IMAGE;
		return;
		}

	//	Get the painter bounds

	RECT rcBounds;
	pPainter->GetBounds(&rcBounds);
	int cxWidth = RectWidth(rcBounds);
	int cyHeight = RectHeight(rcBounds);

	//	Manual compositing

	bool bCanComposite = pPainter->CanPaintComposite();

	//	Create a resulting image

	CG32bitImage *pDest = new CG32bitImage;
	pDest->Create(cxWidth, cyHeight, CG32bitImage::alpha8, (bCanComposite ? CG32bitPixel::Null() : CG32bitPixel(0)));

	//	Set up paint context

	SViewportPaintCtx PaintCtx;

	//	Since we don't have an object, we use the viewport center to indicate
	//	the center of the object.

	PaintCtx.xCenter = -rcBounds.left;
	PaintCtx.yCenter = -rcBounds.top;

	//	Paint

	pPainter->PaintComposite(*pDest, (cxWidth / 2), (cyHeight / 2), PaintCtx);

	//	Initialize an image

	RECT rcFinalRect;
	rcFinalRect.left = 0;
	rcFinalRect.top = 0;
	rcFinalRect.right = cxWidth;
	rcFinalRect.bottom = cyHeight;

	CObjectImageArray Comp;
	Comp.Init(pDest, rcFinalRect, 0, 0, true);

	//	Done

	retImage->TakeHandoff(Comp);
	pPainter->Delete();
	}