//----------------------------------------------------------------------------- // Purpose: // Input : *pParticleMgr - // *pArgs - //----------------------------------------------------------------------------- void C_EntityParticleTrail::Start( ) { if( ParticleMgr()->AddEffect( &m_ParticleEffect, this ) == false ) return; const char *pMaterialName = GetMaterialNameFromIndex( m_iMaterialName ); if ( !pMaterialName ) return; m_hMaterial = ParticleMgr()->GetPMaterial( pMaterialName ); m_teParticleSpawn.Init( 150 ); }
//----------------------------------------------------------------------------- // Purpose: // Input : *materialName - //----------------------------------------------------------------------------- void CLitSmokeEmitter::Init( const char *materialName, Vector sortOrigin ) { m_hSmokeMaterial = GetPMaterial( materialName ); IMaterial *pMaterial = ParticleMgr()->PMaterialToIMaterial( m_hSmokeMaterial ); if ( pMaterial ) { m_Renderer.Init( ParticleMgr(), pMaterial ); } SetSortOrigin( sortOrigin ); m_bInitted = true; }
//----------------------------------------------------------------------------- // ParticleSystem iteration, query, modification //----------------------------------------------------------------------------- ParticleSystemSearchResult CClientTools::NextParticleSystem( ParticleSystemSearchResult sr ) { CNewParticleEffect *pParticleEffect = NULL; if ( sr == NULL ) { pParticleEffect = ParticleMgr()->FirstNewEffect(); } else { pParticleEffect = ParticleMgr()->NextNewEffect( reinterpret_cast< CNewParticleEffect* >( sr ) ); } return reinterpret_cast< ParticleSystemSearchResult >( pParticleEffect ); }
void CTrailParticles::RenderParticles(CParticleRenderIterator *pIterator) { const TrailParticle *pParticle = (const TrailParticle*) pIterator->GetFirst(); while (pParticle) { //Get our remaining time float lifePerc = 1.0f - (pParticle->m_flLifetime / pParticle->m_flDieTime); float scale = (pParticle->m_flLength*lifePerc); if (scale < 0.01f) scale = 0.01f; Vector start, delta; //NOTE: We need to do everything in screen space TransformParticle(ParticleMgr()->GetModelView(), pParticle->m_Pos, start); float sortKey = start.z; Vector3DMultiply(ParticleMgr()->GetModelView(), pParticle->m_vecVelocity, delta); float color[4]; float ramp = 1.0; // Fade in for the first few frames if (pParticle->m_flLifetime <= 0.3 && m_fFlags & bitsPARTICLE_TRAIL_FADE_IN) { ramp = pParticle->m_flLifetime; } else if (m_fFlags & bitsPARTICLE_TRAIL_FADE) { ramp = (1.0f - (pParticle->m_flLifetime / pParticle->m_flDieTime)); } color[0] = pParticle->m_color.r * ramp * (1.0f / 255.0f); color[1] = pParticle->m_color.g * ramp * (1.0f / 255.0f); color[2] = pParticle->m_color.b * ramp * (1.0f / 255.0f); color[3] = pParticle->m_color.a * ramp * (1.0f / 255.0f); float flLength = (pParticle->m_vecVelocity * scale).Length();//( delta - pos ).Length(); float flWidth = (flLength < pParticle->m_flWidth) ? flLength : pParticle->m_flWidth; //See if we should fade Vector vecScaledDelta = (delta*scale); Tracer_Draw(pIterator->GetParticleDraw(), start, vecScaledDelta, flWidth, color); pParticle = (const TrailParticle*) pIterator->GetNext(sortKey); } }
void CLitSmokeEmitter::RenderParticles( CParticleRenderIterator *pIterator ) { const LitSmokeParticle *pParticle = (const LitSmokeParticle*)pIterator->GetFirst(); while ( pParticle ) { float tLifetime = pParticle->m_flLifetime / pParticle->m_flDieTime; // Transform. Vector tPos; TransformParticle( ParticleMgr()->GetModelView(), pParticle->m_Pos, tPos ); float sortKey = tPos.z; float alpha255 = ( ( (float) pParticle->m_uchColor[3]/255.0f ) * sin( M_PI_F * tLifetime ) ) * 255.0f; Vector color01 = Vector( pParticle->m_uchColor[0], pParticle->m_uchColor[1], pParticle->m_uchColor[2] ) * (tLifetime / 255.0f); m_Renderer.RenderParticle_AddColor ( pIterator->GetParticleDraw(), pParticle->m_Pos, tPos, alpha255, FLerp( pParticle->m_uchStartSize, pParticle->m_uchEndSize, tLifetime ), color01 ); pParticle = (const LitSmokeParticle*)pIterator->GetNext( sortKey ); } }
void CNewParticleEffect::Construct() { m_vSortOrigin.Init(); m_bDontRemove = false; m_bRemove = false; m_bDrawn = false; m_bNeedsBBoxUpdate = false; m_bIsFirstFrame = true; m_bAutoUpdateBBox = false; m_bAllocated = true; m_bSimulate = true; m_bRecord = false; m_bShouldPerformCullCheck = false; m_bDisableAggregation = true; // will be reset when someone creates it via CreateOrAggregate m_nToolParticleEffectId = TOOLPARTICLESYSTEMID_INVALID; m_RefCount = 0; ParticleMgr()->AddEffect( this ); m_LastMax = Vector( -1.0e6, -1.0e6, -1.0e6 ); m_LastMin = Vector( 1.0e6, 1.0e6, 1.0e6 ); m_MinBounds = Vector( 1.0e6, 1.0e6, 1.0e6 ); m_MaxBounds = Vector( -1.0e6, -1.0e6, -1.0e6 ); m_pDebugName = NULL; m_nSplitScreenUser = -1; SetRenderable( this ); RecordCreation(); }
CNewParticleEffect *CParticleProperty::Create( CParticleSystemDefinition *pDef, ParticleAttachment_t iAttachType, int iAttachmentPoint, Vector vecOriginOffset, matrix3x4_t *matOffset ) { int nBatchMode = cl_particle_batch_mode.GetInt(); bool bRequestedBatch = ( nBatchMode == 2 ) || ( ( nBatchMode == 1 ) && pDef && pDef->ShouldBatch() ); if ( ( iAttachType == PATTACH_CUSTOMORIGIN ) && bRequestedBatch ) { int iIndex = FindEffect( pDef->GetName() ); if ( iIndex >= 0 ) { CNewParticleEffect *pEffect = m_ParticleEffects[iIndex].pParticleEffect.GetObject(); pEffect->Restart(); return pEffect; } } int iIndex = m_ParticleEffects.AddToTail(); ParticleEffectList_t *newEffect = &m_ParticleEffects[iIndex]; newEffect->pParticleEffect = CNewParticleEffect::Create( m_pOuter, pDef, pDef->GetName() ); if ( !newEffect->pParticleEffect->IsValid() ) { // Caused by trying to spawn an unregistered particle effect. Remove it. ParticleMgr()->RemoveEffect( newEffect->pParticleEffect.GetObject() ); return NULL; } AddControlPoint( iIndex, 0, GetOuter(), iAttachType, iAttachmentPoint, vecOriginOffset, matOffset ); if ( m_pOuter ) { m_pOuter->OnNewParticleEffect( pDef->GetName(), newEffect->pParticleEffect.GetObject() ); } return newEffect->pParticleEffect.GetObject(); }
void C_FuncSmokeVolume::OnDataChanged( DataUpdateType_t updateType ) { m_MinColor[0] = ( 1.0f / 255.0f ) * m_Color1.r; m_MinColor[1] = ( 1.0f / 255.0f ) * m_Color1.g; m_MinColor[2] = ( 1.0f / 255.0f ) * m_Color1.b; m_MaxColor[0] = ( 1.0f / 255.0f ) * m_Color2.r; m_MaxColor[1] = ( 1.0f / 255.0f ) * m_Color2.g; m_MaxColor[2] = ( 1.0f / 255.0f ) * m_Color2.b; m_ParticleRadius = m_ParticleDrawWidth * 0.5f; m_SpacingRadius = m_ParticleSpacingDistance * 0.5f; m_ParticleEffect.SetParticleCullRadius( m_ParticleRadius ); // Warning( "m_Density: %f\n", m_Density ); // Warning( "m_MovementSpeed: %f\n", m_MovementSpeed ); if(updateType == DATA_UPDATE_CREATED) { Vector size = WorldAlignMaxs() - WorldAlignMins(); m_xCount = 0.5f + ( size.x / ( m_SpacingRadius * 2.0f ) ); m_yCount = 0.5f + ( size.y / ( m_SpacingRadius * 2.0f ) ); m_zCount = 0.5f + ( size.z / ( m_SpacingRadius * 2.0f ) ); m_CurrentDensity = m_Density; delete [] m_pSmokeParticleInfos; m_pSmokeParticleInfos = new SmokeParticleInfo[m_xCount * m_yCount * m_zCount]; Start( ParticleMgr(), NULL ); } BaseClass::OnDataChanged( updateType ); }
void CLocalSpaceEmitter::RenderParticles( CParticleRenderIterator *pIterator ) { const matrix3x4_t &mLocalToWorld = GetTransformMatrix(); const VMatrix &mModelView = ParticleMgr()->GetModelView(); const SimpleParticle *pParticle = (const SimpleParticle *)pIterator->GetFirst(); while ( pParticle ) { // Transform it Vector screenPos, worldPos; VectorTransform( pParticle->m_Pos, mLocalToWorld, worldPos ); // Correct viewmodel squashing if ( m_fFlags & FLE_VIEWMODEL ) { FormatViewModelAttachment( NULL, worldPos, false ); } TransformParticle( mModelView, worldPos, screenPos ); float sortKey = (int) screenPos.z; // Render it RenderParticle_ColorSizeAngle( pIterator->GetParticleDraw(), screenPos, UpdateColor( pParticle ), UpdateAlpha( pParticle ) * GetAlphaDistanceFade( screenPos, m_flNearClipMin, m_flNearClipMax ), UpdateScale( pParticle ), pParticle->m_flRoll ); pParticle = (const SimpleParticle *)pIterator->GetNext( sortKey ); } }
//----------------------------------------------------------------------------- // Reload particle definitions //----------------------------------------------------------------------------- void CClientTools::ReloadParticleDefintions( const char *pFileName, const void *pBufData, int nLen ) { // Remove all new effects, because we are going to free internal structures they point to ParticleMgr()->RemoveAllNewEffects(); // FIXME: Use file name to determine if we care about this data CUtlBuffer buf( pBufData, nLen, CUtlBuffer::READ_ONLY ); g_pParticleSystemMgr->ReadParticleConfigFile( buf, true ); }
//----------------------------------------------------------------------------- // Purpose: First sent down from the server //----------------------------------------------------------------------------- void C_ParticleTrail::OnDataChanged(DataUpdateType_t updateType) { C_BaseEntity::OnDataChanged(updateType); if ( updateType == DATA_UPDATE_CREATED ) { Start( ParticleMgr(), NULL ); } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CBasePlasmaProjectile::Activate( void ) { BaseClass::Activate(); #if defined( CLIENT_DLL ) if ( IsClientCreated() && !m_pParticleMgr ) { Start(ParticleMgr(), NULL); SetNextClientThink( CLIENT_THINK_ALWAYS ); } #endif }
//----------------------------------------------------------------------------- // Purpose: Called after a data update has occured // Input : bnewentity - //----------------------------------------------------------------------------- void C_SmokeStack::OnDataChanged(DataUpdateType_t updateType) { C_BaseEntity::OnDataChanged(updateType); if(updateType == DATA_UPDATE_CREATED) { Start(ParticleMgr(), NULL); } // Recalulate lifetime in case length or speed changed. m_InvLifetime = m_Speed / m_JetLength; }
//----------------------------------------------------------------------------- // Creates, destroys particles attached to an attachment //----------------------------------------------------------------------------- void C_EnvParticleScript::CreateParticle( const char *pAttachmentName, const char *pSpriteName ) { // Find the attachment int nAttachment = LookupAttachment( pAttachmentName ); if ( nAttachment <= 0 ) return; // Get the sprite materials PMaterialHandle hMat = m_ParticleEffect.FindOrAddMaterial( pSpriteName ); ParticleScriptParticle_t *pParticle = (ParticleScriptParticle_t*)m_ParticleEffect.AddParticle(sizeof(ParticleScriptParticle_t), hMat); if ( pParticle == NULL ) return; // Get the sprite size from the material's materialvars bool bFound = false; IMaterialVar *pMaterialVar = NULL; IMaterial *pMaterial = ParticleMgr()->PMaterialToIMaterial( hMat ); if ( pMaterial ) { pMaterialVar = pMaterial->FindVar( "$spritesize", &bFound, false ); } if ( bFound ) { pParticle->m_flSize = pMaterialVar->GetFloatValue(); } else { pParticle->m_flSize = 100.0f; } // Make sure the particle cull size reflects our particles if ( pParticle->m_flSize > m_flMaxParticleSize ) { m_flMaxParticleSize = pParticle->m_flSize; m_ParticleEffect.SetParticleCullRadius( m_flMaxParticleSize ); } // Place the particle on the attachment specified pParticle->m_nAttachment = nAttachment; QAngle vecAngles; GetAttachment( nAttachment, pParticle->m_Pos, vecAngles ); if ( m_flSequenceScale != 1.0f ) { pParticle->m_Pos -= GetAbsOrigin(); pParticle->m_Pos *= m_flSequenceScale; pParticle->m_Pos += GetAbsOrigin(); } }
//----------------------------------------------------------------------------- // Purpose: Called after a data update has occured // Input : bnewentity - //----------------------------------------------------------------------------- void C_SteamJet::OnDataChanged(DataUpdateType_t updateType) { C_BaseEntity::OnDataChanged(updateType); if(updateType == DATA_UPDATE_CREATED) { Start(ParticleMgr(), NULL); } // Recalulate lifetime in case length or speed changed. m_Lifetime = m_JetLength / m_Speed; m_ParticleEffect.SetParticleCullRadius( max(m_StartSize, m_EndSize) ); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CBasePlasmaProjectile::OnDataChanged(DataUpdateType_t updateType) { BaseClass::OnDataChanged(updateType); if ( updateType != DATA_UPDATE_CREATED ) return; if ( !m_pParticleMgr ) { Start(ParticleMgr(), NULL); SetNextClientThink( CLIENT_THINK_ALWAYS ); } }
//----------------------------------------------------------------------------- // Purpose: Constructor //----------------------------------------------------------------------------- CParticleEffect::CParticleEffect( const char *pName ) { m_pDebugName = pName; m_vSortOrigin.Init(); m_Flags = FLAG_ALLOCATED; m_nToolParticleEffectId = TOOLPARTICLESYSTEMID_INVALID; m_RefCount = 0; m_bSimulate = true; ParticleMgr()->AddEffect( &m_ParticleEffect, this ); #if defined( _DEBUG ) g_ParticleEffects.AddToTail( this ); #endif }
void C_FuncSmokeVolume::RenderParticles( CParticleRenderIterator *pIterator ) { if ( m_CurrentDensity == 0 ) return; const SmokeGrenadeParticle *pParticle = (const SmokeGrenadeParticle*)pIterator->GetFirst(); while ( pParticle ) { Vector renderPos = pParticle->m_Pos; // Fade out globally. float alpha = m_CurrentDensity; // Apply the precalculated fade alpha from world geometry. alpha *= pParticle->m_FadeAlpha; // TODO: optimize this whole routine! Vector color = m_MinColor + (m_MaxColor - m_MinColor) * (pParticle->m_ColorInterp / 255.1f); if ( IsEmissive() ) { color.x += pParticle->m_Color[0] / 255.0f; color.y += pParticle->m_Color[1] / 255.0f; color.z += pParticle->m_Color[2] / 255.0f; color.x = clamp( color.x, 0.0f, 1.0f ); color.y = clamp( color.y, 0.0f, 1.0f ); color.z = clamp( color.z, 0.0f, 1.0f ); } else { color.x *= pParticle->m_Color[0] / 255.0f; color.y *= pParticle->m_Color[1] / 255.0f; color.z *= pParticle->m_Color[2] / 255.0f; } Vector tRenderPos; TransformParticle( ParticleMgr()->GetModelView(), renderPos, tRenderPos ); float sortKey = 1;//tRenderPos.z; RenderParticle_ColorSizeAngle( pIterator->GetParticleDraw(), tRenderPos, color, alpha * GetAlphaDistanceFade(tRenderPos, 10, 30), // Alpha m_ParticleRadius, pParticle->m_CurRotation ); pParticle = (const SmokeGrenadeParticle*)pIterator->GetNext( sortKey ); } }
//----------------------------------------------------------------------------- // Simulate the particles //----------------------------------------------------------------------------- void C_EnvParticleScript::RenderParticles( CParticleRenderIterator *pIterator ) { const ParticleScriptParticle_t* pParticle = (const ParticleScriptParticle_t*)pIterator->GetFirst(); while ( pParticle ) { Vector vecRenderPos; TransformParticle( ParticleMgr()->GetModelView(), pParticle->m_Pos, vecRenderPos ); float sortKey = vecRenderPos.z; Vector color( 1, 1, 1 ); RenderParticle_ColorSize( pIterator->GetParticleDraw(), vecRenderPos, color, 1.0f, pParticle->m_flSize ); pParticle = (const ParticleScriptParticle_t*)pIterator->GetNext( sortKey ); } }
//----------------------------------------------------------------------------- // Starts up the particle system //----------------------------------------------------------------------------- void C_EnvParticleScript::OnDataChanged( DataUpdateType_t updateType ) { BaseClass::OnDataChanged( updateType ); if( updateType == DATA_UPDATE_CREATED ) { ParticleMgr()->AddEffect( &m_ParticleEffect, this ); g_pClientLeafSystem->EnableRendering( RenderHandle(), false ); } if ( m_nOldSequence != GetSequence() ) { DestroyAllParticles(); } }
CNewParticleEffect *CParticleProperty::Create( const char *pszParticleName, ParticleAttachment_t iAttachType, int iAttachmentPoint, Vector vecOriginOffset ) { if ( GameRules() ) { pszParticleName = GameRules()->TranslateEffectForVisionFilter( "particles", pszParticleName ); } int nBatchMode = cl_particle_batch_mode.GetInt(); CParticleSystemDefinition *pDef = g_pParticleSystemMgr->FindParticleSystem( pszParticleName ); bool bRequestedBatch = ( nBatchMode == 2 ) || ( ( nBatchMode == 1 ) && pDef && pDef->ShouldBatch() ); if ( ( iAttachType == PATTACH_CUSTOMORIGIN ) && bRequestedBatch ) { int iIndex = FindEffect( pszParticleName ); if ( iIndex >= 0 ) { CNewParticleEffect *pEffect = m_ParticleEffects[iIndex].pParticleEffect.GetObject(); pEffect->Restart(); return pEffect; } } if ( !pDef ) { AssertMsg( 0, "Attempting to create unknown particle system" ); Warning( "Attempting to create unknown particle system '%s' \n", pszParticleName ); return NULL; } int iIndex = m_ParticleEffects.AddToTail(); ParticleEffectList_t *newEffect = &m_ParticleEffects[iIndex]; newEffect->pParticleEffect = CNewParticleEffect::Create( m_pOuter, pDef ); if ( !newEffect->pParticleEffect->IsValid() ) { // Caused by trying to spawn an unregistered particle effect. Remove it. ParticleMgr()->RemoveEffect( newEffect->pParticleEffect.GetObject() ); return NULL; } AddControlPoint( iIndex, 0, GetOuter(), iAttachType, iAttachmentPoint, vecOriginOffset ); if ( m_pOuter ) { m_pOuter->OnNewParticleEffect( pszParticleName, newEffect->pParticleEffect.GetObject() ); } return newEffect->pParticleEffect.GetObject(); }
void CDustEffect::RenderParticles( CParticleRenderIterator *pIterator ) { const CFuncDustParticle *pParticle = (const CFuncDustParticle*)pIterator->GetFirst(); while ( pParticle ) { // Velocity. float flAlpha; if( m_pDust->m_DustFlags & DUSTFLAGS_FROZEN ) { flAlpha = 1; } else { // Alpha. float flAngle = (pParticle->m_flLifetime / pParticle->m_flDieTime) * M_PI * 2; flAlpha = sin( flAngle - (M_PI * 0.5f) ) * 0.5f + 0.5f; } Vector tPos; TransformParticle( ParticleMgr()->GetModelView(), pParticle->m_Pos, tPos ); float sortKey = (int) tPos.z; if( -tPos.z <= m_pDust->m_DistMax ) { flAlpha *= 1 + (tPos.z / m_pDust->m_DistMax); // Draw it. float flSize = pParticle->m_flSize; if( m_pDust->m_DustFlags & DUSTFLAGS_SCALEMOTES ) flSize *= -tPos.z; RenderParticle_Color255Size( pIterator->GetParticleDraw(), tPos, Vector( m_pDust->m_Color.r, m_pDust->m_Color.g, m_pDust->m_Color.b ), flAlpha * m_pDust->m_Color.a, flSize ); } pParticle = (const CFuncDustParticle*)pIterator->GetNext( sortKey ); } }
void CTEParticleRenderer::RenderParticles( CParticleRenderIterator *pIterator ) { const StandardParticle_t *pParticle = (const StandardParticle_t*)pIterator->GetFirst(); while ( pParticle ) { // Render. Vector tPos; TransformParticle(ParticleMgr()->GetModelView(), pParticle->m_Pos, tPos); float sortKey = tPos.z; Vector vColor(pParticle->m_Color[0]/255.9f, pParticle->m_Color[1]/255.9f, pParticle->m_Color[2]/255.9f); RenderParticle_ColorSize( pIterator->GetParticleDraw(), tPos, vColor, pParticle->m_Color[3]/255.9f, m_ParticleSize); pParticle = (const StandardParticle_t*)pIterator->GetNext( sortKey ); } }
inline void C_EntityParticleTrail::RenderParticles( CParticleRenderIterator *pIterator ) { const SimpleParticle *pParticle = (const SimpleParticle*)pIterator->GetFirst(); while ( pParticle ) { float t = pParticle->m_flLifetime / pParticle->m_flDieTime; // Render Vector tPos; TransformParticle( ParticleMgr()->GetModelView(), pParticle->m_Pos, tPos ); float sortKey = tPos.z; Vector color = Vector( pParticle->m_uchColor[0] / 255.0f, pParticle->m_uchColor[1] / 255.0f, pParticle->m_uchColor[2] / 255.0f ); float alpha = Lerp( t, pParticle->m_uchStartAlpha / 255.0f, pParticle->m_uchEndAlpha / 255.0f ); float flSize = Lerp( t, pParticle->m_uchStartSize, pParticle->m_uchEndSize ); // Render it RenderParticle_ColorSize( pIterator->GetParticleDraw(), tPos, color, alpha, flSize ); pParticle = (const SimpleParticle*)pIterator->GetNext( sortKey ); } }
void CNewParticleEffect::Construct() { m_vSortOrigin.Init(); m_bDontRemove = false; m_bRemove = false; m_bDrawn = false; m_bNeedsBBoxUpdate = false; m_bIsFirstFrame = true; m_bAutoUpdateBBox = false; m_bAllocated = true; m_bSimulate = true; m_bShouldPerformCullCheck = false; m_nToolParticleEffectId = TOOLPARTICLESYSTEMID_INVALID; m_RefCount = 0; ParticleMgr()->AddEffect( this ); m_LastMax = Vector( -1.0e6, -1.0e6, -1.0e6 ); m_LastMin = Vector( 1.0e6, 1.0e6, 1.0e6 ); m_MinBounds = Vector( 1.0e6, 1.0e6, 1.0e6 ); m_MaxBounds = Vector( -1.0e6, -1.0e6, -1.0e6 ); m_pDebugName = NULL; if ( IsValid() && clienttools->IsInRecordingMode() ) { int nId = AllocateToolParticleEffectId(); static ParticleSystemCreatedState_t state; state.m_nParticleSystemId = nId; state.m_flTime = gpGlobals->curtime; state.m_pName = GetName(); state.m_nOwner = m_hOwner.Get() ? m_hOwner->entindex() : -1; KeyValues *msg = new KeyValues( "ParticleSystem_Create" ); msg->SetPtr( "state", &state ); ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg ); } }
void CSimpleEmitter::RenderParticles( CParticleRenderIterator *pIterator ) { const SimpleParticle *pParticle = (const SimpleParticle *)pIterator->GetFirst(); while ( pParticle ) { //Render Vector tPos; TransformParticle( ParticleMgr()->GetModelView(), pParticle->m_Pos, tPos ); float sortKey = (int) tPos.z; //Render it RenderParticle_ColorSizeAngle( pIterator->GetParticleDraw(), tPos, UpdateColor( pParticle ), UpdateAlpha( pParticle ) * GetAlphaDistanceFade( tPos, m_flNearClipMin, m_flNearClipMax ), UpdateScale( pParticle ), pParticle->m_flRoll ); pParticle = (const SimpleParticle *)pIterator->GetNext( sortKey ); } }
//----------------------------------------------------------------------------- // Purpose: // Input : flags - // Output : int //----------------------------------------------------------------------------- int C_EntityDissolve::DrawModel( int flags ) { // See if we should draw if ( gpGlobals->frametime == 0 || m_bReadyToDraw == false ) return 0; C_BaseAnimating *pAnimating = GetMoveParent() ? GetMoveParent()->GetBaseAnimating() : NULL; if ( pAnimating == NULL ) return 0; matrix3x4_t *hitboxbones[MAXSTUDIOBONES]; if ( pAnimating->HitboxToWorldTransforms( hitboxbones ) == false ) return 0; studiohdr_t *pStudioHdr = modelinfo->GetStudiomodel( pAnimating->GetModel() ); if ( pStudioHdr == NULL ) return false; mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( pAnimating->GetHitboxSet() ); if ( set == NULL ) return false; // Make sure the emitter is setup properly SetupEmitter(); // Get fade percentages for the effect float fadeInPerc = GetFadeInPercentage(); float fadeOutPerc = GetFadeOutPercentage(); float fadePerc = ( fadeInPerc >= 1.0f ) ? fadeOutPerc : fadeInPerc; Vector vecSkew = vec3_origin; // Do extra effects under certain circumstances if ( ( fadePerc < 0.99f ) && ( (m_nDissolveType == ENTITY_DISSOLVE_ELECTRICAL) || (m_nDissolveType == ENTITY_DISSOLVE_ELECTRICAL_LIGHT) ) ) { DoSparks( set, hitboxbones ); } // Skew the particles in front or in back of their targets vecSkew = CurrentViewForward() * ( 8.0f - ( ( 1.0f - fadePerc ) * 32.0f ) ); float spriteScale = ( ( gpGlobals->curtime - m_flStartTime ) / m_flFadeOutLength ); spriteScale = clamp( spriteScale, 0.75f, 1.0f ); // Cache off this material reference if ( g_Material_Spark == NULL ) { g_Material_Spark = ParticleMgr()->GetPMaterial( "effects/spark" ); } if ( g_Material_AR2Glow == NULL ) { g_Material_AR2Glow = ParticleMgr()->GetPMaterial( "effects/combinemuzzle2" ); } SimpleParticle *sParticle; for ( int i = 0; i < set->numhitboxes; ++i ) { Vector vecAbsOrigin, xvec, yvec; mstudiobbox_t *pBox = set->pHitbox(i); ComputeRenderInfo( pBox, *hitboxbones[pBox->bone], &vecAbsOrigin, &xvec, &yvec ); Vector offset; Vector xDir, yDir; xDir = xvec; float xScale = VectorNormalize( xDir ) * 0.75f; yDir = yvec; float yScale = VectorNormalize( yDir ) * 0.75f; int numParticles = clamp( 3.0f * fadePerc, 0.f, 3.f ); int iTempParts = 2; if ( m_nDissolveType == ENTITY_DISSOLVE_CORE ) { if ( m_bCoreExplode == true ) { numParticles = 15; iTempParts = 20; } } for ( int j = 0; j < iTempParts; j++ ) { // Skew the origin offset = xDir * Helper_RandomFloat( -xScale*0.5f, xScale*0.5f ) + yDir * Helper_RandomFloat( -yScale*0.5f, yScale*0.5f ); offset += vecSkew; if ( random->RandomInt( 0, 2 ) != 0 ) continue; sParticle = (SimpleParticle *) m_pEmitter->AddParticle( sizeof(SimpleParticle), g_Material_Spark, vecAbsOrigin + offset ); if ( sParticle == NULL ) return 1; sParticle->m_vecVelocity = Vector( Helper_RandomFloat( -4.0f, 4.0f ), Helper_RandomFloat( -4.0f, 4.0f ), Helper_RandomFloat( 16.0f, 64.0f ) ); if ( m_nDissolveType == ENTITY_DISSOLVE_CORE ) { if ( m_bCoreExplode == true ) { Vector vDirection = (vecAbsOrigin + offset) - m_vDissolverOrigin; VectorNormalize( vDirection ); sParticle->m_vecVelocity = vDirection * m_nMagnitude; } } if ( sParticle->m_vecVelocity.z > 0 ) { sParticle->m_uchStartSize = random->RandomFloat( 4, 6 ) * spriteScale; } else { sParticle->m_uchStartSize = 2 * spriteScale; } sParticle->m_flDieTime = random->RandomFloat( 0.4f, 0.5f ); // If we're the last particles, last longer if ( numParticles == 0 ) { sParticle->m_flDieTime *= 2.0f; sParticle->m_uchStartSize = 2 * spriteScale; sParticle->m_flRollDelta = Helper_RandomFloat( -4.0f, 4.0f ); if ( m_nDissolveType == ENTITY_DISSOLVE_CORE ) { if ( m_bCoreExplode == true ) { sParticle->m_flDieTime *= 2.0f; sParticle->m_flRollDelta = Helper_RandomFloat( -1.0f, 1.0f ); } } } else { sParticle->m_flRollDelta = Helper_RandomFloat( -8.0f, 8.0f ); } sParticle->m_flLifetime = 0.0f; sParticle->m_flRoll = Helper_RandomInt( 0, 360 ); float alpha = 255; sParticle->m_uchColor[0] = m_vEffectColor.x; sParticle->m_uchColor[1] = m_vEffectColor.y; sParticle->m_uchColor[2] = m_vEffectColor.z; sParticle->m_uchStartAlpha = alpha; sParticle->m_uchEndAlpha = 0; sParticle->m_uchEndSize = 0; } for ( int j = 0; j < numParticles; j++ ) { offset = xDir * Helper_RandomFloat( -xScale*0.5f, xScale*0.5f ) + yDir * Helper_RandomFloat( -yScale*0.5f, yScale*0.5f ); offset += vecSkew; sParticle = (SimpleParticle *) m_pEmitter->AddParticle( sizeof(SimpleParticle), g_Material_AR2Glow, vecAbsOrigin + offset ); if ( sParticle == NULL ) return 1; sParticle->m_vecVelocity = Vector( Helper_RandomFloat( -4.0f, 4.0f ), Helper_RandomFloat( -4.0f, 4.0f ), Helper_RandomFloat( -64.0f, 128.0f ) ); sParticle->m_uchStartSize = random->RandomFloat( 8, 12 ) * spriteScale; sParticle->m_flDieTime = 0.1f; sParticle->m_flLifetime = 0.0f; sParticle->m_flRoll = Helper_RandomInt( 0, 360 ); sParticle->m_flRollDelta = Helper_RandomFloat( -2.0f, 2.0f ); float alpha = 255; sParticle->m_uchColor[0] = m_vEffectColor.x; sParticle->m_uchColor[1] = m_vEffectColor.y; sParticle->m_uchColor[2] = m_vEffectColor.z; sParticle->m_uchStartAlpha = alpha; sParticle->m_uchEndAlpha = 0; sParticle->m_uchEndSize = 0; if ( m_nDissolveType == ENTITY_DISSOLVE_CORE ) { if ( m_bCoreExplode == true ) { Vector vDirection = (vecAbsOrigin + offset) - m_vDissolverOrigin; VectorNormalize( vDirection ); sParticle->m_vecVelocity = vDirection * m_nMagnitude; sParticle->m_flDieTime = 0.5f; } } } } return 1; }
//----------------------------------------------------------------------------- // Indicates whether the client should render particle systems //----------------------------------------------------------------------------- void CClientTools::EnableParticleSystems( bool bEnable ) { ParticleMgr()->RenderParticleSystems( bEnable ); }
//----------------------------------------------------------------------------- // Purpose: // Input : &origin - // &normal - // scale - // r - // g - // b - // flags - //----------------------------------------------------------------------------- void FX_BloodSpray( const Vector &origin, const Vector &normal, float scale, unsigned char r, unsigned char g, unsigned char b, int flags ) { if ( UTIL_IsLowViolence() ) return; //debugoverlay->AddLineOverlay( origin, origin + normal * 72, 255, 255, 255, true, 10 ); Vector offset; float spread = 0.2f; //Find area ambient light color and use it to tint smoke Vector worldLight = WorldGetLightForPoint( origin, true ); Vector color = Vector( (float)(worldLight[0] * r) / 255.0f, (float)(worldLight[1] * g) / 255.0f, (float)(worldLight[2] * b) / 255.0f ); float colorRamp; int i; Vector offDir; Vector right; Vector up; if (normal != Vector(0, 0, 1) ) { right = normal.Cross( Vector(0, 0, 1) ); up = right.Cross( normal ); } else { right = Vector(0, 0, 1); up = right.Cross( normal ); } // // Dump out drops // if (flags & FX_BLOODSPRAY_DROPS) { TrailParticle *tParticle; CSmartPtr<CTrailParticles> pTrailEmitter = CTrailParticles::Create( "blooddrops" ); if ( !pTrailEmitter ) return; pTrailEmitter->SetSortOrigin( origin ); // Partial gravity on blood drops. pTrailEmitter->SetGravity( 600.0 ); pTrailEmitter->GetBinding().SetBBox( origin - Vector( 32, 32, 32 ), origin + Vector( 32, 32, 32 ) ); pTrailEmitter->SetFlag( bitsPARTICLE_TRAIL_VELOCITY_DAMPEN ); pTrailEmitter->SetVelocityDampen( 0.2f ); PMaterialHandle hMaterial = ParticleMgr()->GetPMaterial( "effects/blood_drop" ); // // Long stringy drops of blood. // for ( i = 0; i < 14; i++ ) { // Originate from within a circle 'scale' inches in diameter. offset = origin; offset += right * random->RandomFloat( -0.5f, 0.5f ) * scale; offset += up * random->RandomFloat( -0.5f, 0.5f ) * scale; tParticle = (TrailParticle *) pTrailEmitter->AddParticle( sizeof(TrailParticle), hMaterial, offset ); if ( tParticle == NULL ) break; tParticle->m_flLifetime = 0.0f; offDir = normal + RandomVector( -0.3f, 0.3f ); tParticle->m_vecVelocity = offDir * random->RandomFloat( 4.0f * scale, 40.0f * scale ); tParticle->m_vecVelocity[2] += random->RandomFloat( 4.0f, 16.0f ) * scale; tParticle->m_flWidth = random->RandomFloat( 0.125f, 0.275f ) * scale; tParticle->m_flLength = random->RandomFloat( 0.02f, 0.03f ) * scale; tParticle->m_flDieTime = random->RandomFloat( 0.5f, 1.0f ); FloatToColor32( tParticle->m_color, color[0], color[1], color[2], 1.0f ); } // // Shorter droplets. // for ( i = 0; i < 24; i++ ) { // Originate from within a circle 'scale' inches in diameter. offset = origin; offset += right * random->RandomFloat( -0.5f, 0.5f ) * scale; offset += up * random->RandomFloat( -0.5f, 0.5f ) * scale; tParticle = (TrailParticle *) pTrailEmitter->AddParticle( sizeof(TrailParticle), hMaterial, offset ); if ( tParticle == NULL ) break; tParticle->m_flLifetime = 0.0f; offDir = normal + RandomVector( -1.0f, 1.0f ); offDir[2] += random->RandomFloat(0, 1.0f); tParticle->m_vecVelocity = offDir * random->RandomFloat( 2.0f * scale, 25.0f * scale ); tParticle->m_vecVelocity[2] += random->RandomFloat( 4.0f, 16.0f ) * scale; tParticle->m_flWidth = random->RandomFloat( 0.25f, 0.375f ) * scale; tParticle->m_flLength = random->RandomFloat( 0.0025f, 0.005f ) * scale; tParticle->m_flDieTime = random->RandomFloat( 0.5f, 1.0f ); FloatToColor32( tParticle->m_color, color[0], color[1], color[2], 1.0f ); } } if ((flags & FX_BLOODSPRAY_GORE) || (flags & FX_BLOODSPRAY_CLOUD)) { CSmartPtr<CBloodSprayEmitter> pSimple = CBloodSprayEmitter::Create( "bloodgore" ); if ( !pSimple ) return; pSimple->SetSortOrigin( origin ); pSimple->SetGravity( 0 ); PMaterialHandle hMaterial; // // Tight blossom of blood at the center. // if (flags & FX_BLOODSPRAY_GORE) { hMaterial = ParticleMgr()->GetPMaterial( "effects/blood_gore" ); SimpleParticle *pParticle; for ( i = 0; i < 6; i++ ) { // Originate from within a circle 'scale' inches in diameter. offset = origin + ( 0.5 * scale * normal ); offset += right * random->RandomFloat( -0.5f, 0.5f ) * scale; offset += up * random->RandomFloat( -0.5f, 0.5f ) * scale; pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), hMaterial, offset ); if ( pParticle != NULL ) { pParticle->m_flLifetime = 0.0f; pParticle->m_flDieTime = 0.3f; spread = 0.2f; pParticle->m_vecVelocity.Random( -spread, spread ); pParticle->m_vecVelocity += normal * random->RandomInt( 10, 100 ); //VectorNormalize( pParticle->m_vecVelocity ); colorRamp = random->RandomFloat( 0.75f, 1.25f ); pParticle->m_uchColor[0] = MIN( 1.0f, color[0] * colorRamp ) * 255.0f; pParticle->m_uchColor[1] = MIN( 1.0f, color[1] * colorRamp ) * 255.0f; pParticle->m_uchColor[2] = MIN( 1.0f, color[2] * colorRamp ) * 255.0f; pParticle->m_uchStartSize = random->RandomFloat( scale * 0.25, scale ); pParticle->m_uchEndSize = pParticle->m_uchStartSize * 2; pParticle->m_uchStartAlpha = random->RandomInt( 200, 255 ); pParticle->m_uchEndAlpha = 0; pParticle->m_flRoll = random->RandomInt( 0, 360 ); pParticle->m_flRollDelta = 0.0f; } } } // // Diffuse cloud just in front of the exit wound. // if (flags & FX_BLOODSPRAY_CLOUD) { hMaterial = ParticleMgr()->GetPMaterial( "effects/blood_puff" ); SimpleParticle *pParticle; for ( i = 0; i < 6; i++ ) { // Originate from within a circle '2 * scale' inches in diameter. offset = origin + ( scale * normal ); offset += right * random->RandomFloat( -1, 1 ) * scale; offset += up * random->RandomFloat( -1, 1 ) * scale; pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), hMaterial, offset ); if ( pParticle != NULL ) { pParticle->m_flLifetime = 0.0f; pParticle->m_flDieTime = random->RandomFloat( 0.5f, 0.8f); spread = 0.5f; pParticle->m_vecVelocity.Random( -spread, spread ); pParticle->m_vecVelocity += normal * random->RandomInt( 100, 200 ); colorRamp = random->RandomFloat( 0.75f, 1.25f ); pParticle->m_uchColor[0] = MIN( 1.0f, color[0] * colorRamp ) * 255.0f; pParticle->m_uchColor[1] = MIN( 1.0f, color[1] * colorRamp ) * 255.0f; pParticle->m_uchColor[2] = MIN( 1.0f, color[2] * colorRamp ) * 255.0f; pParticle->m_uchStartSize = random->RandomFloat( scale * 1.5f, scale * 2.0f ); pParticle->m_uchEndSize = pParticle->m_uchStartSize * 4; pParticle->m_uchStartAlpha = random->RandomInt( 80, 128 ); pParticle->m_uchEndAlpha = 0; pParticle->m_flRoll = random->RandomInt( 0, 360 ); pParticle->m_flRollDelta = 0.0f; } } } } // TODO: Play a sound? //CLocalPlayerFilter filter; //C_BaseEntity::EmitSound( filter, SOUND_FROM_WORLD, CHAN_VOICE, "Physics.WaterSplash", 1.0, ATTN_NORM, 0, 100, &origin ); }
//----------------------------------------------------------------------------- // Purpose: Used for bullets hitting bleeding surfaces // Input : origin - // normal - // scale - This parameter is not currently used //----------------------------------------------------------------------------- void FX_BloodBulletImpact( const Vector &origin, const Vector &normal, float scale /*NOTE: Unused!*/, unsigned char r, unsigned char g, unsigned char b ) { if ( UTIL_IsLowViolence() ) return; Vector offset; //Find area ambient light color and use it to tint smoke Vector worldLight = WorldGetLightForPoint( origin, true ); if ( gpGlobals->maxClients > 1 ) { worldLight = Vector( 1.0, 1.0, 1.0 ); r = 96; g = 0; b = 10; } Vector color = Vector( (float)(worldLight[0] * r) / 255.0f, (float)(worldLight[1] * g) / 255.0f, (float)(worldLight[2] * b) / 255.0f ); float colorRamp; Vector offDir; CSmartPtr<CBloodSprayEmitter> pSimple = CBloodSprayEmitter::Create( "bloodgore" ); if ( !pSimple ) return; pSimple->SetSortOrigin( origin ); pSimple->SetGravity( 200 ); // Setup a bounding box to contain the particles without (stops auto-updating) pSimple->GetBinding().SetBBox( origin - Vector( 16, 16, 16 ), origin + Vector( 16, 16, 16 ) ); // Cache the material if we haven't already if ( g_Blood_Core == NULL ) { g_Blood_Core = ParticleMgr()->GetPMaterial( "effects/blood_core" ); } SimpleParticle *pParticle; Vector dir = normal * RandomVector( -0.5f, 0.5f ); offset = origin + ( 2.0f * normal ); pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Blood_Core, offset ); if ( pParticle != NULL ) { pParticle->m_flLifetime = 0.0f; pParticle->m_flDieTime = random->RandomFloat( 0.25f, 0.5f); pParticle->m_vecVelocity = dir * random->RandomFloat( 16.0f, 32.0f ); pParticle->m_vecVelocity[2] -= random->RandomFloat( 8.0f, 16.0f ); colorRamp = random->RandomFloat( 0.75f, 2.0f ); pParticle->m_uchColor[0] = MIN( 1.0f, color[0] * colorRamp ) * 255.0f; pParticle->m_uchColor[1] = MIN( 1.0f, color[1] * colorRamp ) * 255.0f; pParticle->m_uchColor[2] = MIN( 1.0f, color[2] * colorRamp ) * 255.0f; pParticle->m_uchStartSize = random->RandomInt( 2, 4 ); pParticle->m_uchEndSize = pParticle->m_uchStartSize * 8; pParticle->m_uchStartAlpha = 255; pParticle->m_uchEndAlpha = 0; pParticle->m_flRoll = random->RandomInt( 0, 360 ); pParticle->m_flRollDelta = 0.0f; } // Cache the material if we haven't already if ( g_Blood_Gore == NULL ) { g_Blood_Gore = ParticleMgr()->GetPMaterial( "effects/blood_gore" ); } for ( int i = 0; i < 4; i++ ) { offset = origin + ( 2.0f * normal ); pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Blood_Gore, offset ); if ( pParticle != NULL ) { pParticle->m_flLifetime = 0.0f; pParticle->m_flDieTime = random->RandomFloat( 0.5f, 0.75f); pParticle->m_vecVelocity = dir * random->RandomFloat( 16.0f, 32.0f )*(i+1); pParticle->m_vecVelocity[2] -= random->RandomFloat( 32.0f, 64.0f )*(i+1); colorRamp = random->RandomFloat( 0.75f, 2.0f ); pParticle->m_uchColor[0] = MIN( 1.0f, color[0] * colorRamp ) * 255.0f; pParticle->m_uchColor[1] = MIN( 1.0f, color[1] * colorRamp ) * 255.0f; pParticle->m_uchColor[2] = MIN( 1.0f, color[2] * colorRamp ) * 255.0f; pParticle->m_uchStartSize = random->RandomInt( 2, 4 ); pParticle->m_uchEndSize = pParticle->m_uchStartSize * 4; pParticle->m_uchStartAlpha = 255; pParticle->m_uchEndAlpha = 0; pParticle->m_flRoll = random->RandomInt( 0, 360 ); pParticle->m_flRollDelta = 0.0f; } } // // Dump out drops // TrailParticle *tParticle; CSmartPtr<CTrailParticles> pTrailEmitter = CTrailParticles::Create( "blooddrops" ); if ( !pTrailEmitter ) return; pTrailEmitter->SetSortOrigin( origin ); // Partial gravity on blood drops pTrailEmitter->SetGravity( 400.0 ); // Enable simple collisions with nearby surfaces pTrailEmitter->Setup(origin, &normal, 1, 10, 100, 400, 0.2, 0 ); if ( g_Blood_Drops == NULL ) { g_Blood_Drops = ParticleMgr()->GetPMaterial( "effects/blood_drop" ); } // // Shorter droplets // for ( int i = 0; i < 8; i++ ) { // Originate from within a circle 'scale' inches in diameter offset = origin; tParticle = (TrailParticle *) pTrailEmitter->AddParticle( sizeof(TrailParticle), g_Blood_Drops, offset ); if ( tParticle == NULL ) break; tParticle->m_flLifetime = 0.0f; offDir = RandomVector( -1.0f, 1.0f ); tParticle->m_vecVelocity = offDir * random->RandomFloat( 64.0f, 128.0f ); tParticle->m_flWidth = random->RandomFloat( 0.5f, 2.0f ); tParticle->m_flLength = random->RandomFloat( 0.05f, 0.15f ); tParticle->m_flDieTime = random->RandomFloat( 0.25f, 0.5f ); FloatToColor32( tParticle->m_color, color[0], color[1], color[2], 1.0f ); } // TODO: Play a sound? //CLocalPlayerFilter filter; //C_BaseEntity::EmitSound( filter, SOUND_FROM_WORLD, CHAN_VOICE, "Physics.WaterSplash", 1.0, ATTN_NORM, 0, 100, &origin ); }