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; }
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; }
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; }
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; }
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; }
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; }
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; }
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(); }