BVB Source Codes

CRYENGINE Show ParticleSubEmitter.cpp Source code

Return Download CRYENGINE: download ParticleSubEmitter.cpp Source code - Download CRYENGINE Source code - Type:.cpp
  1. // Copyright 2001-2016 Crytek GmbH / Crytek Group. All rights reserved.
  2.  
  3. // -------------------------------------------------------------------------
  4. //  File name:   ParticleSubEmitter.cpp
  5. //  Created:     20/04/2010 by Corey
  6. //  Description: Split out from ParticleEmitter.cpp
  7. // -------------------------------------------------------------------------
  8. //  History:
  9. //
  10. ////////////////////////////////////////////////////////////////////////////
  11.  
  12. #include "StdAfx.h"
  13. #include "ParticleSubEmitter.h"
  14. #include "ParticleEmitter.h"
  15. #include <CryAudio/IAudioSystem.h>
  16.  
  17. static const float fMIN_PULSE_PERIOD = 0.1f;
  18.  
  19. //////////////////////////////////////////////////////////////////////////
  20. // CParticleSubEmitter implementation.
  21. //////////////////////////////////////////////////////////////////////////
  22.  
  23. CParticleSubEmitter::CParticleSubEmitter(CParticleSource* pSource, CParticleContainer* pCont)
  24.         : m_ChaosKey(0U)
  25.         , m_nEmitIndex(0)
  26.         , m_nSequenceIndex(0)
  27.         , m_pContainer(pCont)
  28.         , m_pSource(pSource)
  29.         , m_startAudioTriggerId(INVALID_AUDIO_CONTROL_ID)
  30.         , m_stopAudioTriggerId(INVALID_AUDIO_CONTROL_ID)
  31.         , m_audioRtpcId(INVALID_AUDIO_CONTROL_ID)
  32.         , m_pIAudioProxy(NULL)
  33.         , m_currentAudioOcclusionType(eAudioOcclusionType_Ignore)
  34.         , m_bExecuteAudioTrigger(false)
  35. {
  36.         assert(pCont);
  37.         assert(pSource);
  38.         SetLastLoc();
  39.         m_fActivateAge = m_fLastEmitAge = -fHUGE;
  40.         m_fStartAge = m_fStopAge = m_fRepeatAge = fHUGE;
  41.         m_pForce = NULL;
  42. }
  43.  
  44. CParticleSubEmitter::~CParticleSubEmitter()
  45. {
  46.         Deactivate();
  47. }
  48.  
  49. //////////////////////////////////////////////////////////////////////////
  50. void CParticleSubEmitter::Initialize(float fAge)
  51. {
  52.         const ResourceParticleParams& params = GetParams();
  53.  
  54.         m_nEmitIndex = 0;
  55.         m_nSequenceIndex = m_pContainer->GetNextEmitterSequence();
  56.         SetLastLoc();
  57.  
  58.         // Reseed randomness.
  59.         m_ChaosKey = CChaosKey(cry_random_uint32());
  60.         m_fActivateAge = fAge;
  61.  
  62.         // Compute lifetime params.
  63.         m_fStartAge = m_fStopAge = m_fActivateAge + params.fSpawnDelay(VRANDOM);
  64.         m_fLastEmitAge = -fHUGE;
  65.         if (params.bContinuous || !params.fParticleLifeTime)
  66.         {
  67.                 if (params.fEmitterLifeTime)
  68.                         m_fStopAge += params.fEmitterLifeTime(VRANDOM);
  69.                 else
  70.                         m_fStopAge = fHUGE;
  71.         }
  72.  
  73.         // Compute next repeat age.
  74.         if (params.fPulsePeriod)
  75.         {
  76.                 float fRepeat = params.fPulsePeriod(VRANDOM);
  77.                 fRepeat = max(fRepeat, fMIN_PULSE_PERIOD);
  78.                 m_fRepeatAge = m_fActivateAge + fRepeat;
  79.                 m_fStopAge = min(m_fStopAge, m_fRepeatAge);
  80.         }
  81.         else
  82.                 m_fRepeatAge = fHUGE;
  83.  
  84.         m_bExecuteAudioTrigger = true;
  85. }
  86.  
  87. //////////////////////////////////////////////////////////////////////////
  88. void CParticleSubEmitter::Deactivate()
  89. {
  90.         DeactivateAudio();
  91.  
  92.         if (m_pForce)
  93.         {
  94.                 assert(!JobManager::IsWorkerThread());
  95.                 GetPhysicalWorld()->DestroyPhysicalEntity(m_pForce);
  96.                 m_pForce = 0;
  97.         }
  98. }
  99.  
  100. void CParticleSubEmitter::UpdateState(float fAgeAdjust)
  101. {
  102.         // Evolve emitter state.
  103.         m_fActivateAge += fAgeAdjust;
  104.         m_fLastEmitAge += fAgeAdjust;
  105.  
  106.         float fAge = GetAge();
  107.  
  108.         ParticleParams::ESpawn eSpawn = GetParams().eSpawnIndirection;
  109.         float fActivateAge = eSpawn == eSpawn.ParentCollide ? GetSource().GetCollideAge()
  110.                              : eSpawn == eSpawn.ParentDeath ? GetSource().GetStopAge()
  111.                              : 0.f;
  112.         if (fActivateAge > m_fActivateAge && fAge >= fActivateAge)
  113.                 Initialize(fActivateAge);
  114.  
  115.         m_fStopAge = min(m_fStopAge, GetSource().GetStopAge());
  116. }
  117.  
  118. float CParticleSubEmitter::GetStopAge(ParticleParams::ESoundControlTime eControl) const
  119. {
  120.         switch (eControl)
  121.         {
  122.         default:
  123.         case ParticleParams::ESoundControlTime::EmitterLifeTime:
  124.                 return GetStopAge();
  125.         case ParticleParams::ESoundControlTime::EmitterExtendedLifeTime:
  126.                 return GetParticleStopAge();
  127.         case ParticleParams::ESoundControlTime::EmitterPulsePeriod:
  128.                 return m_fRepeatAge;
  129.         }
  130. }
  131.  
  132. float CParticleSubEmitter::GetAgeRelativeTo(float fStopAge, float fAgeAdjust) const
  133. {
  134.         float fAge = GetAge() + fAgeAdjust;
  135.         if (min(fAge, fStopAge) <= m_fStartAge)
  136.                 return 0.f;
  137.  
  138.         return div_min(fAge - m_fStartAge, fStopAge - m_fStartAge, 1.f);
  139. }
  140.  
  141. float CParticleSubEmitter::GetStrength(float fAgeAdjust /* = 0.f */, ParticleParams::ESoundControlTime const eControl /* = EmitterLifeTime */) const
  142. {
  143.         float fStrength = GetMain().GetSpawnParams().fStrength;
  144.         if (fStrength < 0.f)
  145.         {
  146.                 if (GetParams().bContinuous)
  147.                         return GetRelativeAge(eControl, fAgeAdjust);
  148.                 else
  149.                         return div_min((float)m_nEmitIndex, GetParams().fCount.GetMaxValue(), 1.f);
  150.         }
  151.         else
  152.                 return min(fStrength, 1.f);
  153. }
  154.  
  155. void CParticleSubEmitter::EmitParticles(SParticleUpdateContext& context)
  156. {
  157.         const ResourceParticleParams& params = GetParams();
  158.  
  159.         context.fDensityAdjust = 1.f;
  160.  
  161.         float fAge = GetAge();
  162.         const float fFullLife = GetContainer().GetMaxParticleFullLife() + GetParticleTimer()->GetFrameTime() * 2;
  163.  
  164.         // Iterate through one or more pulse periods
  165.         // Compute max possible pulses as an extra check to avoid infinite looping
  166.         int nMaxPulses = 1;
  167.         if (params.fPulsePeriod)
  168.         {
  169.                 const float fMinPulsePeriod = max(params.fPulsePeriod(VMIN), fMIN_PULSE_PERIOD);
  170.                 nMaxPulses += int_ceil(context.fUpdateTime / fMinPulsePeriod);
  171.         }
  172.  
  173.         while (nMaxPulses-- > 0)
  174.         {
  175.                 // Determine time window to update.
  176.                 float fAge0 = max(m_fLastEmitAge, m_fStartAge);
  177.                 float fAge1 = min(fAge, m_fStopAge);
  178.  
  179.                 // Skip time before emitted particles would still be alive.
  180.                 fAge0 = max(fAge0, fAge - fFullLife);
  181.  
  182.                 if (fAge1 > m_fLastEmitAge && fAge0 <= fAge1)
  183.                 {
  184.                         const float fStrength = GetStrength((fAge0 + fAge1) * 0.5f - fAge);
  185.                         float fCount = params.fCount(VRANDOM, fStrength);
  186.                         if (!GetContainer().GetParent())
  187.                                 fCount *= GetMain().GetEmitCountScale();
  188.                         if (fCount > 0.f)
  189.                         {
  190.                                 const float fEmitterLife = m_fStopAge - m_fStartAge;
  191.                                 float fParticleLife = params.fParticleLifeTime(VMAX, fStrength);
  192.                                 if (fParticleLife == 0.f)
  193.                                         fParticleLife = fEmitterLife;
  194.  
  195.                                 if (fParticleLife > 0.f)
  196.                                 {
  197.                                         EmitParticleData data;
  198.                                         data.Location = GetSource().GetLocation();
  199.  
  200.                                         if (params.bContinuous && fEmitterLife > 0.f)
  201.                                         {
  202.                                                 // Continuous emission rate which maintains fCount particles
  203.                                                 float fAgeIncrement = min(fParticleLife, fEmitterLife) / fCount;
  204.  
  205.                                                 // Set up location interpolation.
  206.                                                 const QuatTS& locA = GetSource().GetLocation();
  207.                                                 const QuatTS& locB = m_LastLoc;
  208.  
  209.                                                 struct
  210.                                                 {
  211.                                                         bool  bInterp;
  212.                                                         bool  bSlerp;
  213.                                                         float fInterp;
  214.                                                         float fInterpInc;
  215.                                                         Vec3  vArc;
  216.                                                         float fA;
  217.                                                         float fCosA;
  218.                                                         float fInvSinA;
  219.                                                 } Interp;
  220.  
  221.                                                 Interp.bInterp = context.fUpdateTime > 0.f && !params.bMoveRelativeEmitter
  222.                                                                         && m_LastLoc.s >= 0.f && !IsEquivalent(locA, locB, 0.0045f, 1e-5f);
  223.  
  224.                                                 if (params.fMaintainDensity && (Interp.bInterp || params.nEnvFlags & ENV_PHYS_AREA))
  225.                                                 {
  226.                                                         float fAdjust = ComputeDensityIncrease(fStrength, fParticleLife, locA, Interp.bInterp ? &locB : 0);
  227.                                                         if (fAdjust > 1.f)
  228.                                                         {
  229.                                                                 fAdjust = Lerp(1.f, fAdjust, params.fMaintainDensity);
  230.                                                                 float fInvAdjust = 1.f / fAdjust;
  231.                                                                 fAgeIncrement *= fInvAdjust;
  232.                                                                 context.fDensityAdjust = Lerp(1.f, fInvAdjust, params.fMaintainDensity.fReduceAlpha);
  233.                                                         }
  234.                                                 }
  235.  
  236.                                                 if (Interp.bInterp)
  237.                                                 {
  238.                                                         Interp.bSlerp = false;
  239.                                                         Interp.fInterp = div_min(fAge - fAge0, context.fUpdateTime, 1.f);
  240.                                                         Interp.fInterpInc = -div_min(fAgeIncrement, context.fUpdateTime, 1.f);
  241.  
  242.                                                         if (!(GetCVars()->e_ParticlesDebug & AlphaBit('q')))
  243.                                                         {
  244.                                                                 /*
  245.                                                                           Spherically interpolate based on rotation changes and velocity.
  246.                                                                           Instead of interpolating linearly along path (P0,P1,t);
  247.                                                                           Interpolate along an arc:
  248.  
  249.                                                                           (P0,P1,y) + C x, where
  250.                                                                           a = half angle of arc segment = angle(R0,R1) / 2 = acos (R1 ~R0).w
  251.                                                                           C = max arc extension, perpendicular to (P0,P1)
  252.                                                                           = (P0,P1)/2 ^ (R1 ~R0).xyz.norm (1 - cos a)
  253.                                                                           y = (sin (a (2t-1)) / sin(a) + 1)/2
  254.                                                                           x = cos (a (2t-1)) - cos a
  255.                                                                         */
  256.  
  257.                                                                 Vec3 vVelB = GetSource().GetVelocity().vLin;
  258.                                                                 Vec3 vDeltaAdjusted = locB.t - locA.t - vVelB * context.fUpdateTime;
  259.                                                                 if (!vDeltaAdjusted.IsZero())
  260.                                                                 {
  261.                                                                         Quat qDelta = locB.q * locA.q.GetInverted();
  262.                                                                         float fSinA = qDelta.v.GetLength();
  263.                                                                         if (fSinA > 0.001f)
  264.                                                                         {
  265.                                                                                 Interp.bSlerp = true;
  266.                                                                                 if (qDelta.w < 0.f)
  267.                                                                                         qDelta = -qDelta;
  268.                                                                                 Interp.fA = asin_tpl(fSinA);
  269.                                                                                 Interp.fInvSinA = 1.f / fSinA;
  270.                                                                                 Interp.fCosA = qDelta.w;
  271.                                                                                 Interp.vArc = vDeltaAdjusted ^ qDelta.v;
  272.                                                                                 Interp.vArc *= Interp.fInvSinA * Interp.fInvSinA * 0.5f;
  273.                                                                         }
  274.                                                                 }
  275.                                                         }
  276.                                                 }
  277.  
  278.                                                 if (params.Connection.bConnectToOrigin)
  279.                                                         fAge -= fAgeIncrement;
  280.  
  281.                                                 float fPast = fAge - fAge0, fMinPast = fAge - fAge1;
  282.                                                 for (; fPast > fMinPast; fPast -= fAgeIncrement)
  283.                                                 {
  284.                                                         if (Interp.bInterp)
  285.                                                         {
  286.                                                                 // Interpolate the location linearly.
  287.                                                                 data.Location.q.SetNlerp(locA.q, locB.q, Interp.fInterp);
  288.                                                                 data.Location.s = locA.s + (locB.s - locA.s) * Interp.fInterp;
  289.  
  290.                                                                 if (Interp.bSlerp)
  291.                                                                 {
  292.                                                                         float fX, fY;
  293.                                                                         sincos_tpl(Interp.fA * (2.f * Interp.fInterp - 1.f), &fY, &fX);
  294.                                                                         fY = (fY * Interp.fInvSinA + 1.f) * 0.5f;
  295.                                                                         fX -= Interp.fCosA;
  296.  
  297.                                                                         data.Location.t.SetLerp(locA.t, locB.t, fY);
  298.                                                                         data.Location.t += Interp.vArc * fX;
  299.                                                                 }
  300.                                                                 else
  301.                                                                 {
  302.                                                                         data.Location.t.SetLerp(locA.t, locB.t, Interp.fInterp);
  303.                                                                 }
  304.                                                                 Interp.fInterp += Interp.fInterpInc;
  305.                                                         }
  306.  
  307.                                                         if (!EmitParticle(context, data, fPast))
  308.                                                         {
  309.                                                                 GetContainer().GetCounts().ParticlesReject += (fPast - fMinPast) / fAgeIncrement;
  310.                                                                 break;
  311.                                                         }
  312.                                                 }
  313.                                                 m_fLastEmitAge = fAge - fPast;
  314.                                         }
  315.                                         else
  316.                                         {
  317.                                                 // Instant emission of fCount particles
  318.                                                 for (int nEmit = int_round(fCount); nEmit > 0; nEmit--)
  319.                                                 {
  320.                                                         if (!EmitParticle(context, data, fAge - m_fStartAge))
  321.                                                         {
  322.                                                                 GetContainer().GetCounts().ParticlesReject += nEmit;
  323.                                                                 break;
  324.                                                         }
  325.                                                 }
  326.                                                 m_fLastEmitAge = fAge;
  327.                                         }
  328.                                 }
  329.                         }
  330.                 }
  331.  
  332.                 // Check if next pulse also occurs in this update
  333.                 if (fAge >= m_fRepeatAge && GetSource().GetStopAge() > m_fRepeatAge)
  334.                         Initialize(m_fRepeatAge);
  335.                 else
  336.                         break;
  337.         }
  338.  
  339.         SetLastLoc();
  340. }
  341.  
  342. float CParticleSubEmitter::GetParticleScale() const
  343. {
  344.         return GetParams().bMoveRelativeEmitter.ScaleWithSize() ?
  345.                GetSource().GetLocation().s :
  346.                GetMain().GetParticleScale();
  347. }
  348.  
  349. static inline float AdjustedScale(const QuatTS& loc)
  350. {
  351.         float fMinScale = max(loc.t.GetLengthFast(), 1.f) * 1e-5f;
  352.         return loc.s + fMinScale;
  353. }
  354.  
  355. bool CParticleSubEmitter::GetMoveRelative(Vec3& vPreTrans, QuatTS& qtsMove) const
  356. {
  357.         if (m_LastLoc.s < 0.f)
  358.                 return false;
  359.  
  360.         ParticleParams const& params = GetParams();
  361.  
  362.         vPreTrans = -m_LastLoc.t;
  363.         const QuatTS& locCur = GetSource().GetLocation();
  364.  
  365.         if (!params.bMoveRelativeEmitter.bIgnoreRotation)
  366.                 qtsMove.q = locCur.q * m_LastLoc.q.GetInverted();
  367.         else
  368.                 qtsMove.q.SetIdentity();
  369.  
  370.         if (!params.bMoveRelativeEmitter.bIgnoreSize)
  371.                 qtsMove.s = AdjustedScale(locCur) / AdjustedScale(m_LastLoc);
  372.         else
  373.                 qtsMove.s = 1.f;
  374.  
  375.         qtsMove.t = locCur.t;
  376.         return true;
  377. }
  378.  
  379. void CParticleSubEmitter::UpdateForce()
  380. {
  381.         FUNCTION_PROFILER(GetISystem(), PROFILE_PARTICLE);
  382.  
  383.         // Set or clear physical force.
  384.  
  385.         float fAge = GetAge();
  386.         if (fAge >= m_fStartAge && fAge <= GetParticleStopAge())
  387.         {
  388.                 struct SForceGeom
  389.                 {
  390.                         QuatTS qpLoc;               // world placement of force
  391.                         AABB   bbOuter, bbInner;    // local boundaries of force.
  392.                         Vec3   vForce3;
  393.                         float  fForceW;
  394.                 } force;
  395.  
  396.                 //
  397.                 // Compute force geom.
  398.                 //
  399.  
  400.                 const ResourceParticleParams& params = GetParams();
  401.  
  402.                 float fStrength = GetStrength();
  403.                 SPhysEnviron const& PhysEnv = GetMain().GetPhysEnviron();
  404.  
  405.                 // Location.
  406.                 force.qpLoc = GetSource().GetLocation();
  407.                 force.qpLoc.s = GetParticleScale();
  408.                 force.qpLoc.t = force.qpLoc * params.vPositionOffset;
  409.  
  410.                 // Direction.
  411.                 GetEmitFocusDir(force.qpLoc, fStrength, &force.qpLoc.q);
  412.  
  413.                 force.qpLoc.t = force.qpLoc * params.vPositionOffset;
  414.  
  415.                 // Set inner box from spawn geometry.
  416.                 Quat qToLocal = force.qpLoc.q.GetInverted() * m_pSource->GetLocation().q;
  417.                 Vec3 vOffset = qToLocal * Vec3(params.vRandomOffset);
  418.                 force.bbInner = AABB(-vOffset, vOffset);
  419.  
  420.                 // Emission directions.
  421.                 float fPhiMax = DEG2RAD(params.fEmitAngle(VMAX, fStrength)),
  422.                       fPhiMin = DEG2RAD(params.fEmitAngle(VMIN, fStrength));
  423.  
  424.                 AABB bbTrav;
  425.                 bbTrav.max.y = cosf(fPhiMin);
  426.                 bbTrav.min.y = cosf(fPhiMax);
  427.                 float fCosAvg = (bbTrav.max.y + bbTrav.min.y) * 0.5f;
  428.                 bbTrav.max.x = bbTrav.max.z = (bbTrav.min.y * bbTrav.max.y < 0.f ? 1.f : sin(fPhiMax));
  429.                 bbTrav.min.x = bbTrav.min.z = -bbTrav.max.x;
  430.                 bbTrav.Add(Vec3(ZERO));
  431.  
  432.                 // Force magnitude: speed times relative particle density.
  433.                 float fPLife = params.fParticleLifeTime(0.5f, fStrength);
  434.                 float fTime = fAge - m_fStartAge;
  435.  
  436.                 float fSpeed = params.fSpeed(0.5f, fStrength) * GetMain().GetSpawnParams().fSpeedScale;
  437.                 float fDist = Travel::TravelDistance(abs(fSpeed), params.fAirResistance(0.5f, fStrength, 0.5f), min(fTime, fPLife));
  438.                 fSpeed = Travel::TravelSpeed(abs(fSpeed), params.fAirResistance(0.5f, fStrength, 0.5f), min(fTime, fPLife));
  439.                 float fForce = fSpeed * params.fAlpha(0.5f, fStrength, 0.5f) * force.qpLoc.s;
  440.  
  441.                 if (params.bContinuous && fPLife > 0.f)
  442.                 {
  443.                         // Ramp up/down over particle life.
  444.                         float fStopAge = GetStopAge();
  445.                         if (fTime < fPLife)
  446.                                 fForce *= fTime / fPLife;
  447.                         else if (fTime > fStopAge)
  448.                                 fForce *= 1.f - (fTime - fStopAge) / fPLife;
  449.                 }
  450.  
  451.                 // Force direction.
  452.                 force.vForce3.zero();
  453.                 force.vForce3.y = fCosAvg * fForce;
  454.                 force.fForceW = sqrtf(1.f - square(fCosAvg)) * fForce;
  455.  
  456.                 // Travel distance.
  457.                 bbTrav.min *= fDist;
  458.                 bbTrav.max *= fDist;
  459.  
  460.                 // Set outer box.
  461.                 force.bbOuter = force.bbInner;
  462.                 force.bbOuter.Augment(bbTrav);
  463.  
  464.                 // Expand by size.
  465.                 float fSize = params.fSize(0.5f, fStrength, VMAX);
  466.                 force.bbOuter.Expand(Vec3(fSize));
  467.  
  468.                 // Scale: Normalise box size, so we can handle some geom changes through scaling.
  469.                 Vec3 vSize = force.bbOuter.GetSize() * 0.5f;
  470.                 float fRadius = max(max(vSize.x, vSize.y), vSize.z);
  471.  
  472.                 force.qpLoc.s *= fRadius;
  473.  
  474.                 if (fForce * force.qpLoc.s == 0.f)
  475.                 {
  476.                         // No force.
  477.                         if (m_pForce)
  478.                         {
  479.                                 GetPhysicalWorld()->DestroyPhysicalEntity(m_pForce);
  480.                                 m_pForce = NULL;
  481.                         }
  482.                         return;
  483.                 }
  484.  
  485.                 float fIRadius = 1.f / fRadius;
  486.                 force.bbOuter.min *= fIRadius;
  487.                 force.bbOuter.max *= fIRadius;
  488.                 force.bbInner.min *= fIRadius;
  489.                 force.bbInner.max *= fIRadius;
  490.  
  491.                 //
  492.                 // Create physical area for force.
  493.                 //
  494.  
  495.                 primitives::box geomBox;
  496.                 geomBox.Basis.SetIdentity();
  497.                 geomBox.bOriented = 0;
  498.                 geomBox.center = force.bbOuter.GetCenter();
  499.                 geomBox.size = force.bbOuter.GetSize() * 0.5f;
  500.  
  501.                 pe_status_pos spos;
  502.                 if (m_pForce)
  503.                 {
  504.                         // Check whether shape changed.
  505.                         m_pForce->GetStatus(&spos);
  506.                         if (spos.pGeom)
  507.                         {
  508.                                 primitives::box curBox;
  509.                                 spos.pGeom->GetBBox(&curBox);
  510.                                 if (!IsEquivalent(curBox.center, geomBox.center, 0.001f)
  511.                                     || !IsEquivalent(curBox.size, geomBox.size, 0.001f))
  512.                                         spos.pGeom = NULL;
  513.                         }
  514.                         if (!spos.pGeom)
  515.                         {
  516.                                 GetPhysicalWorld()->DestroyPhysicalEntity(m_pForce);
  517.                                 m_pForce = NULL;
  518.                         }
  519.                 }
  520.  
  521.                 if (!m_pForce)
  522.                 {
  523.                         IGeometry* pGeom = m_pPhysicalWorld->GetGeomManager()->CreatePrimitive(primitives::box::type, &geomBox);
  524.                         m_pForce = m_pPhysicalWorld->AddArea(pGeom, force.qpLoc.t, force.qpLoc.q, force.qpLoc.s);
  525.                         if (!m_pForce)
  526.                                 return;
  527.  
  528.                         // Tag area with this emitter, so we can ignore it in the emitter family.
  529.                         pe_params_foreign_data fd;
  530.                         fd.pForeignData = (void*)&GetMain();
  531.                         fd.iForeignData = fd.iForeignFlags = 0;
  532.                         m_pForce->SetParams(&fd);
  533.                 }
  534.                 else
  535.                 {
  536.                         // Update position & box size as needed.
  537.                         if (!IsEquivalent(spos.pos, force.qpLoc.t, 0.01f)
  538.                             || !IsEquivalent(spos.q, force.qpLoc.q)
  539.                             || spos.scale != force.qpLoc.s)
  540.                         {
  541.                                 pe_params_pos pos;
  542.                                 pos.pos = force.qpLoc.t;
  543.                                 pos.q = force.qpLoc.q;
  544.                                 pos.scale = force.qpLoc.s;
  545.                                 m_pForce->SetParams(&pos);
  546.                         }
  547.                 }
  548.  
  549.                 // To do: 4D flow
  550.                 pe_params_area area;
  551.                 float fVMagSqr = force.vForce3.GetLengthSquared(),
  552.                       fWMagSqr = square(force.fForceW);
  553.                 float fMag = sqrtf(fVMagSqr + fWMagSqr);
  554.                 area.bUniform = (fVMagSqr > fWMagSqr) * 2;
  555.                 if (area.bUniform)
  556.                 {
  557.                         force.vForce3 *= fMag * isqrt_tpl(fVMagSqr);
  558.                 }
  559.                 else
  560.                 {
  561.                         force.vForce3.z = fMag * (force.fForceW < 0.f ? -1.f : 1.f);
  562.                         force.vForce3.x = force.vForce3.y = 0.f;
  563.                 }
  564.                 area.falloff0 = force.bbInner.GetRadius();
  565.  
  566.                 if (params.eForceGeneration == params.eForceGeneration.Gravity)
  567.                         area.gravity = force.vForce3;
  568.                 m_pForce->SetParams(&area);
  569.  
  570.                 if (params.eForceGeneration == params.eForceGeneration.Wind)
  571.                 {
  572.                         pe_params_buoyancy buoy;
  573.                         buoy.iMedium = 1;
  574.                         buoy.waterDensity = buoy.waterResistance = 1;
  575.                         buoy.waterFlow = force.vForce3;
  576.                         buoy.waterPlane.n = -PhysEnv.m_UniformForces.plWater.n;
  577.                         buoy.waterPlane.origin = PhysEnv.m_UniformForces.plWater.n * PhysEnv.m_UniformForces.plWater.d;
  578.                         m_pForce->SetParams(&buoy);
  579.                 }
  580.         }
  581.         else
  582.         {
  583.                 if (m_pForce)
  584.                 {
  585.                         GetPhysicalWorld()->DestroyPhysicalEntity(m_pForce);
  586.                         m_pForce = NULL;
  587.                 }
  588.         }
  589. }
  590.  
  591. void CParticleSubEmitter::UpdateAudio()
  592. {
  593.         FUNCTION_PROFILER(GetISystem(), PROFILE_PARTICLE);
  594.         SpawnParams const& spawnParams = GetMain().GetSpawnParams();
  595.  
  596.         if (spawnParams.bEnableAudio && GetCVars()->e_ParticlesAudio > 0)
  597.         {
  598.                 ResourceParticleParams const& params = GetParams();
  599.  
  600.                 if (m_pIAudioProxy != nullptr)
  601.                 {
  602.                         if (m_audioRtpcId != INVALID_AUDIO_CONTROL_ID && params.fSoundFXParam(VMAX, VMIN) < 1.0f)
  603.                         {
  604.                                 float const value = params.fSoundFXParam(m_ChaosKey, GetStrength(0.0f, params.eSoundControlTime));
  605.                                 m_pIAudioProxy->SetRtpcValue(m_audioRtpcId, value);
  606.                         }
  607.  
  608.                         m_pIAudioProxy->SetTransformation(GetEmitTM());
  609.  
  610.                         if (m_currentAudioOcclusionType != spawnParams.occlusionType)
  611.                         {
  612.                                 m_pIAudioProxy->SetOcclusionType(spawnParams.occlusionType);
  613.                                 m_currentAudioOcclusionType = spawnParams.occlusionType;
  614.                         }
  615.  
  616.                         if (m_bExecuteAudioTrigger)
  617.                         {
  618.                                 m_pIAudioProxy->SetCurrentEnvironments();
  619.                                 m_pIAudioProxy->ExecuteTrigger(m_startAudioTriggerId);
  620.                         }
  621.                 }
  622.                 else
  623.                 {
  624.                         if (!params.sStartTrigger.empty())
  625.                         {
  626.                                 gEnv->pAudioSystem->GetAudioTriggerId(params.sStartTrigger.c_str(), m_startAudioTriggerId);
  627.                         }
  628.  
  629.                         if (!params.sStopTrigger.empty())
  630.                         {
  631.                                 gEnv->pAudioSystem->GetAudioTriggerId(params.sStopTrigger.c_str(), m_stopAudioTriggerId);
  632.                         }
  633.  
  634.                         if (m_startAudioTriggerId != INVALID_AUDIO_CONTROL_ID || m_stopAudioTriggerId != INVALID_AUDIO_CONTROL_ID)
  635.                         {
  636.                                 assert(m_pIAudioProxy == nullptr);
  637.                                 m_pIAudioProxy = gEnv->pAudioSystem->GetFreeAudioProxy();
  638.  
  639.                                 if (m_pIAudioProxy != nullptr)
  640.                                 {
  641.                                         m_pIAudioProxy->Initialize("ParticleSubEmitter");
  642.                                         m_pIAudioProxy->SetOcclusionType(spawnParams.occlusionType);
  643.                                         m_currentAudioOcclusionType = spawnParams.occlusionType;
  644.  
  645.                                         if (!spawnParams.audioRtpc.empty())
  646.                                         {
  647.                                                 gEnv->pAudioSystem->GetAudioRtpcId(spawnParams.audioRtpc.c_str(), m_audioRtpcId);
  648.  
  649.                                                 if (m_audioRtpcId != INVALID_AUDIO_CONTROL_ID)
  650.                                                 {
  651.                                                         float const value = params.fSoundFXParam(m_ChaosKey, GetStrength(0.0f, params.eSoundControlTime));
  652.                                                         m_pIAudioProxy->SetRtpcValue(m_audioRtpcId, value);
  653.                                                 }
  654.                                         }
  655.  
  656.                                         // Execute start trigger immediately.
  657.                                         if (m_startAudioTriggerId != INVALID_AUDIO_CONTROL_ID)
  658.                                         {
  659.                                                 m_pIAudioProxy->SetTransformation(GetEmitTM());
  660.                                                 m_pIAudioProxy->SetCurrentEnvironments();
  661.                                                 m_pIAudioProxy->ExecuteTrigger(m_startAudioTriggerId);
  662.                                         }
  663.                                 }
  664.                         }
  665.                 }
  666.         }
  667.         else if (m_pIAudioProxy != nullptr)
  668.         {
  669.                 DeactivateAudio();
  670.         }
  671.  
  672.         m_bExecuteAudioTrigger = false;
  673. }
  674.  
  675. int CParticleSubEmitter::EmitParticle(SParticleUpdateContext& context, const EmitParticleData& data_in, float fAge, QuatTS* plocPreTransform)
  676. {
  677.         const ResourceParticleParams& params = GetParams();
  678.  
  679.         EmitParticleData data = data_in;
  680.  
  681.         // Determine geometry
  682.         if (!data.pStatObj)
  683.                 data.pStatObj = params.pStatObj;
  684.  
  685.         if (data.pStatObj && !data.pPhysEnt && params.eGeometryPieces != params.eGeometryPieces.Whole)
  686.         {
  687.                 // Emit sub-meshes rather than parent mesh.
  688.                 IStatObj* pParentObj = data.pStatObj;
  689.                 QuatTS* plocMainPreTransform = plocPreTransform;
  690.  
  691.                 int nPieces = 0;
  692.                 for (int i = pParentObj->GetSubObjectCount() - 1; i >= 0; i--)
  693.                 {
  694.                         if (IStatObj::SSubObject* pSub = GetSubGeometry(pParentObj, i))
  695.                         {
  696.                                 if (params.eGeometryPieces == params.eGeometryPieces.AllPieces || (nPieces++ == 0 || cry_random(0, nPieces - 1) == 0))
  697.                                 {
  698.                                         // Emit this piece
  699.                                         data.pStatObj = pSub->pStatObj;
  700.  
  701.                                         QuatTS locPreTransform;
  702.                                         if (params.bNoOffset)
  703.                                         {
  704.                                                 // Use piece's sub-location
  705.                                                 locPreTransform = QuatTS(pSub->localTM);
  706.                                                 if (plocMainPreTransform)
  707.                                                         locPreTransform = *plocMainPreTransform * locPreTransform;
  708.                                                 plocPreTransform = &locPreTransform;
  709.                                         }
  710.                                         if (params.eGeometryPieces == params.eGeometryPieces.AllPieces)
  711.                                                 // Emit each piece as a separate particle
  712.                                                 nPieces += EmitParticle(context, data, fAge, plocPreTransform);
  713.                                 }
  714.                         }
  715.                 }
  716.                 if (params.eGeometryPieces == params.eGeometryPieces.AllPieces && nPieces > 0)
  717.                         return nPieces;
  718.         }
  719.  
  720.         m_nEmitIndex++;
  721.  
  722.         // Init local particle, copy to container. Use raw data buffer, to avoid extra destructor.
  723.         CRY_ALIGN(128) char buffer[sizeof(CParticle)];
  724.         CParticle* pPart = new(buffer) CParticle;
  725.  
  726.         pPart->Init(context, fAge, this, data);
  727.  
  728.         if (plocPreTransform)
  729.                 pPart->PreTransform(*plocPreTransform);
  730.  
  731.         CParticle* pNewPart = GetContainer().AddParticle(context, *pPart);
  732.         if (!pNewPart)
  733.         {
  734.                 pPart->~CParticle();
  735.                 return 0;
  736.         }
  737.  
  738.         if (GetContainer().GetChildFlags())
  739.         {
  740.                 // Create child emitters (on actual particle address, not pPart)
  741.                 GetMain().CreateIndirectEmitters(pNewPart, &GetContainer());
  742.         }
  743.  
  744.         return 1;
  745. }
  746.  
  747. Vec3 CParticleSubEmitter::GetEmitFocusDir(const QuatTS& loc, float fStrength, Quat* pRot) const
  748. {
  749.         const ParticleParams& params = GetParams();
  750.  
  751.         Quat q = loc.q;
  752.         Vec3 vFocus = loc.q.GetColumn1();
  753.  
  754.         if (params.bFocusGravityDir)
  755.         {
  756.                 float fLenSq = GetMain().GetPhysEnviron().m_UniformForces.vAccel.GetLengthSquared();
  757.                 if (fLenSq > FLT_MIN)
  758.                 {
  759.                         vFocus = GetMain().GetPhysEnviron().m_UniformForces.vAccel * -isqrt_tpl(fLenSq);
  760.                         if (params.fFocusAngle || pRot)
  761.                                 RotateTo(q, vFocus);
  762.                 }
  763.         }
  764.  
  765.         if (params.fFocusCameraDir)
  766.         {
  767.                 float fBias = params.fFocusCameraDir(m_ChaosKey, fStrength);
  768.                 Vec3 vCamDir = (gEnv->p3DEngine->GetRenderingCamera().GetPosition() - loc.t).GetNormalized();
  769.                 vFocus.SetSlerp(vFocus, vCamDir, fBias);
  770.                 if (params.fFocusAngle || pRot)
  771.                         RotateTo(q, vFocus);
  772.         }
  773.  
  774.         if (params.fFocusAngle)
  775.         {
  776.                 float fAngle = DEG2RAD(params.fFocusAngle(m_ChaosKey, fStrength));
  777.                 float fAzimuth = DEG2RAD(params.fFocusAzimuth(m_ChaosKey, fStrength));
  778.                 q = q * Quat::CreateRotationXYZ(Ang3(fAngle, fAzimuth, 0));
  779.                 vFocus = q.GetColumn1();
  780.         }
  781.  
  782.         if (pRot)
  783.                 *pRot = q;
  784.  
  785.         return vFocus;
  786. }
  787.  
  788. void CParticleSubEmitter::DeactivateAudio()
  789. {
  790.         if (m_pIAudioProxy != nullptr)
  791.         {
  792.                 m_pIAudioProxy->SetTransformation(GetEmitTM());
  793.  
  794.                 if (m_audioRtpcId != INVALID_AUDIO_CONTROL_ID)
  795.                 {
  796.                         ResourceParticleParams const& params = GetParams();
  797.                         float const value = params.fSoundFXParam(m_ChaosKey, GetStrength(0.0f, params.eSoundControlTime));
  798.                         m_pIAudioProxy->SetRtpcValue(m_audioRtpcId, value);
  799.                 }
  800.  
  801.                 if (m_stopAudioTriggerId != INVALID_AUDIO_CONTROL_ID)
  802.                 {
  803.                         m_pIAudioProxy->ExecuteTrigger(m_stopAudioTriggerId);
  804.                 }
  805.                 else
  806.                 {
  807.                         assert(m_startAudioTriggerId != INVALID_AUDIO_CONTROL_ID);
  808.                         m_pIAudioProxy->StopTrigger(m_startAudioTriggerId);
  809.                 }
  810.  
  811.                 m_pIAudioProxy->Release();
  812.                 m_startAudioTriggerId = INVALID_AUDIO_CONTROL_ID;
  813.                 m_stopAudioTriggerId = INVALID_AUDIO_CONTROL_ID;
  814.                 m_audioRtpcId = INVALID_AUDIO_CONTROL_ID;
  815.                 m_pIAudioProxy = nullptr;
  816.         }
  817. }
  818.  
  819. float CParticleSubEmitter::ComputeDensityIncrease(float fStrength, float fParticleLife, const QuatTS& locA, const QuatTS* plocB) const
  820. {
  821.         // Increase emission rate to compensate for moving emitter and non-uniform forces.
  822.         const ResourceParticleParams& params = GetParams();
  823.         SPhysEnviron const& PhysEnv = GetMain().GetPhysEnviron();
  824.  
  825.         AABB bbSource = params.GetEmitOffsetBounds();
  826.  
  827.         FStaticBounds opts;
  828.         opts.fSpeedScale = GetMain().GetSpawnParams().fSpeedScale;
  829.         opts.fMaxLife = fParticleLife;
  830.  
  831.         FEmitterFixed fixed = { m_ChaosKey, fStrength };
  832.         float fSize = params.fSize(0.5f, fStrength, VMAX) * 2.f;
  833.         float fGravityScale = params.fGravityScale(0.5f, fStrength, 0.5f);
  834.  
  835.         // Get emission volume for default orientation and forces
  836.         SForceParams forces;
  837.         static_cast<SPhysForces&>(forces) = PhysEnv.m_UniformForces;
  838.         forces.vAccel = forces.vAccel * fGravityScale + params.vAcceleration;
  839.         forces.vWind.zero();
  840.         forces.fDrag = params.fAirResistance(0.5f, fStrength, 0.5f);
  841.         forces.fStretch = 0.f;
  842.  
  843.         AABB bbTravel(AABB::RESET);
  844.         float fDist = params.GetTravelBounds(bbTravel, IParticleEffect::ParticleLoc(Vec3(ZERO)), forces, opts, fixed);
  845.         float fStandardVolume = Travel::TravelVolume(bbSource, bbTravel, fDist, fSize);
  846.  
  847.         // Get emission volume for current forces, in local space
  848.         Quat qToA = locA.q.GetInverted();
  849.  
  850.         PhysEnv.GetForces(forces, GetSource().GetLocation().t, GetContainer().GetEnvironmentFlags());
  851.         forces.vAccel = qToA * forces.vAccel * fGravityScale + params.vAcceleration;
  852.         forces.vWind = qToA * forces.vWind * params.fAirResistance.fWindScale;
  853.  
  854.         fDist = params.GetTravelBounds(bbTravel, QuatTS(IDENTITY), forces, opts, fixed);
  855.         if (plocB)
  856.         {
  857.                 // Add previous emission from previous location, in local space
  858.                 QuatTS locToA = locA.GetInverted() * *plocB;
  859.                 bbSource.Add(AABB::CreateTransformedAABB(QuatT(locToA), bbSource));
  860.                 AABB bbTravelB;
  861.                 float fDistB = params.GetTravelBounds(bbTravelB, locToA, forces, opts, fixed);
  862.                 fDist = max(fDist, fDistB);
  863.                 bbTravel.Add(bbTravelB);
  864.         }
  865.         float fVolume = Travel::TravelVolume(bbSource, bbTravel, fDist, fSize);
  866.  
  867.         return div_min(fVolume, fStandardVolume, fMAX_DENSITY_ADJUST);
  868. }
  869.  
  870. Matrix34 CParticleSubEmitter::GetEmitTM() const
  871. {
  872.         QuatTS const& loc = GetSource().GetLocation();
  873.         Matrix34 emitTM(loc);
  874.         emitTM.SetColumn(3, loc * GetParams().vPositionOffset);
  875.         return emitTM;
  876. }
  877.  
downloadParticleSubEmitter.cpp Source code - Download CRYENGINE Source code
Related Source Codes/Software:
postal - 2017-06-11
reactide - Reactide is the first dedicated IDE for React web ... 2017-06-11
rkt - rkt is a pod-native container engine for Linux. It... 2017-06-11
uWebSockets - Tiny WebSockets https://for... 2017-06-11
realworld - TodoMVC for the RealWorld - Exemplary fullstack Me... 2017-06-11
CRYENGINE - CRYENGINE is a powerful real-time game development... 2017-06-11
goreplay - GoReplay is an open-source tool for capturing and ... 2017-06-10
pyenv - Simple Python version management 2017-06-10
redux-saga - An alternative side effect model for Redux apps ... 2017-06-10
angular-starter - 2017-06-10

 Back to top