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 ); } }
//----------------------------------------------------------------------------- // Purpose: Simulate motion and render all child particles // Input : *pInParticle - // *pDraw - // &sortKey - // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool CSimpleEmitter::SimulateAndRender( Particle *pInParticle, ParticleDraw *pDraw, float &sortKey) { SimpleParticle *pParticle = (SimpleParticle *) pInParticle; float timeDelta = pDraw->GetTimeDelta(); //Render Vector tPos; TransformParticle( g_ParticleMgr.GetModelView(), pParticle->m_Pos, tPos ); sortKey = (int) tPos.z; //Render it RenderParticle_ColorSizeAngle( pDraw, tPos, UpdateColor( pParticle, timeDelta ), UpdateAlpha( pParticle, timeDelta ) * GetAlphaDistanceFade( tPos, m_flNearClipMin, m_flNearClipMax ), UpdateScale( pParticle, timeDelta ), UpdateRoll( pParticle, timeDelta ) ); //Update velocity UpdateVelocity( pParticle, timeDelta ); pParticle->m_Pos += pParticle->m_vecVelocity * timeDelta; //Should this particle die? pParticle->m_flLifetime += timeDelta; if ( pParticle->m_flLifetime >= pParticle->m_flDieTime ) return false; return true; }
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 ); } }
void C_AR2Explosion::RenderParticles( CParticleRenderIterator *pIterator ) { const AR2ExplosionParticle *pParticle = (const AR2ExplosionParticle *)pIterator->GetFirst(); while ( pParticle ) { float sortKey = 0; if ( pParticle->m_Lifetime >= 0.0f ) { // Draw. float lifetimePercent = ( pParticle->m_Lifetime - AR2_DUST_FADE_IN_TIME ) / pParticle->m_Dwell; // FIXME: base color should be a dirty version of the material color Vector color = g_AR2DustColor1 * (1.0 - lifetimePercent) + g_AR2DustColor2 * lifetimePercent; Vector tPos; TransformParticle(m_pParticleMgr->GetModelView(), pParticle->m_Pos, tPos); sortKey = tPos.z; float alpha; if ( pParticle->m_Lifetime < AR2_DUST_FADE_IN_TIME ) { alpha = AR2_DUST_ALPHA * ( pParticle->m_Lifetime / AR2_DUST_FADE_IN_TIME ); } else { alpha = AR2_DUST_ALPHA * ( 1.0f - lifetimePercent ); } alpha *= GetAlphaDistanceFade( tPos, IsXbox() ? 100 : 50, IsXbox() ? 200 : 150 ); RenderParticle_ColorSizeAngle( pIterator->GetParticleDraw(), tPos, color, alpha, pParticle->m_Dist, // size based on how far it's traveled pParticle->m_Roll); } pParticle = (const AR2ExplosionParticle *)pIterator->GetNext( sortKey ); } }
bool C_FuncSmokeVolume::SimulateAndRender( Particle *pBaseParticle, ParticleDraw *pDraw, float &sortKey ) { if( m_CurrentDensity == 0.0f ) { return true; } SmokeGrenadeParticle* pParticle = (SmokeGrenadeParticle*)pBaseParticle; Vector renderPos = pParticle->m_Pos; // Fade out globally. float alpha = m_CurrentDensity; pParticle->m_CurRotation += pParticle->m_RotationFactor * ( M_PI / 180.0f ) * m_RotationSpeed * pDraw->GetTimeDelta(); // 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); 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( g_ParticleMgr.GetModelView(), renderPos, tRenderPos ); sortKey = tRenderPos.z; RenderParticle_ColorSizeAngle( pDraw, tRenderPos, color, alpha * GetAlphaDistanceFade(tRenderPos, 10, 30), // Alpha m_ParticleRadius, pParticle->m_CurRotation ); return true; }
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 ); } }
bool C_AR2Explosion::SimulateAndRender(Particle *pBaseParticle, ParticleDraw *pDraw, float &sortKey) { AR2ExplosionParticle* pParticle = (AR2ExplosionParticle*)pBaseParticle; float dt = pDraw->GetTimeDelta(); if (dt > 0.05) dt = 0.05; // yuck, air resistance function craps out at less then 20fps // Update its lifetime. pParticle->m_Lifetime += dt; // pDraw->GetTimeDelta(); if(pParticle->m_Lifetime > pParticle->m_Dwell) { // faded to nothing.... return false; } // Spin the thing pParticle->m_Roll += pParticle->m_RollSpeed * pDraw->GetTimeDelta(); // delayed? if(pParticle->m_Lifetime < 0.0f) { // not alive yet return true; } // Draw. float lifetimePercent = ( pParticle->m_Lifetime - AR2_DUST_FADE_IN_TIME ) / pParticle->m_Dwell; // FIXME: base color should be a dirty version of the material color Vector color = g_AR2DustColor1 * (1.0 - lifetimePercent) + g_AR2DustColor2 * lifetimePercent; Vector tPos; TransformParticle(m_pParticleMgr->GetModelView(), pParticle->m_Pos, tPos); // sortKey = tPos.z; float alpha; if ( pParticle->m_Lifetime < AR2_DUST_FADE_IN_TIME ) { alpha = AR2_DUST_ALPHA * ( pParticle->m_Lifetime / AR2_DUST_FADE_IN_TIME ); } else { alpha = AR2_DUST_ALPHA * ( 1.0f - lifetimePercent ); } alpha *= GetAlphaDistanceFade( tPos, 50, 150 ); RenderParticle_ColorSizeAngle( pDraw, tPos, color, alpha, pParticle->m_Dist, // size based on how far it's traveled pParticle->m_Roll); // Move it (this comes after rendering to make it clear that moving the particle here won't change // its rendering for this frame since m_TransformedPos has already been set). pParticle->m_Pos = pParticle->m_Pos + pParticle->m_Velocity * dt; // keep track of distance traveled pParticle->m_Dist = pParticle->m_Dist + pParticle->m_Velocity.Length() * dt; // Dampen velocity. float dist = pParticle->m_Velocity.Length() * dt; float r = dist * dist; // FIXME: this is a really screwy air-resistance function.... pParticle->m_Velocity = pParticle->m_Velocity * (100 / (100 + r )); // dampen roll static float dtime; static float decay; if (dtime != dt) { dtime = dt; decay = ExponentialDecay( 0.3, 1.0, dtime ); } if (fabs(pParticle->m_RollSpeed) > 0.2) pParticle->m_RollSpeed = pParticle->m_RollSpeed * decay; return true; }
//----------------------------------------------------------------------------- // Purpose: Update state + render //----------------------------------------------------------------------------- bool CBasePlasmaProjectile::SimulateAndRender(Particle *pInParticle, ParticleDraw *pDraw, float &sortKey) { if ( IsDormantPredictable() ) return true; if ( GetMoveType() == MOVETYPE_NONE ) return true; // Update the particle position pInParticle->m_Pos = GetAbsOrigin(); // Add our blended offset if ( gpGlobals->curtime < m_Shared.GetSpawnTime() + REMAP_BLEND_TIME ) { float frac = ( gpGlobals->curtime - m_Shared.GetSpawnTime() ) / REMAP_BLEND_TIME; frac = 1.0f - clamp( frac, 0.0f, 1.0f ); Vector scaledOffset; VectorScale( m_vecGunOriginOffset, frac, scaledOffset ); pInParticle->m_Pos += scaledOffset; } float timeDelta = pDraw->GetTimeDelta(); // Render the head particle if ( pInParticle == m_pHeadParticle ) { SimpleParticle *pParticle = (SimpleParticle *) pInParticle; pParticle->m_flLifetime += timeDelta; // Render Vector tPos, vecOrigin; RemapPosition( m_pPreviousPositions[MAX_HISTORY-1].m_Position, m_pPreviousPositions[MAX_HISTORY-1].m_Time, vecOrigin ); TransformParticle( ParticleMgr()->GetModelView(), vecOrigin, tPos ); sortKey = (int) tPos.z; //Render it RenderParticle_ColorSizeAngle( pDraw, tPos, UpdateColor( pParticle, timeDelta ), UpdateAlpha( pParticle, timeDelta ) * GetAlphaDistanceFade( tPos, 16, 64 ), UpdateScale( pParticle, timeDelta ), UpdateRoll( pParticle, timeDelta ) ); /* if ( m_flNextSparkEffect < gpGlobals->curtime ) { // Drop sparks? if ( GetTeamNumber() == TEAM_HUMANS ) { g_pEffects->Sparks( pInParticle->m_Pos, 1, 3 ); } else { g_pEffects->EnergySplash( pInParticle->m_Pos, vec3_origin ); } m_flNextSparkEffect = gpGlobals->curtime + RandomFloat( 0.5, 2 ); } */ return true; } // Render the trail TrailParticle *pParticle = (TrailParticle *) pInParticle; pParticle->m_flLifetime += timeDelta; Vector vecScreenStart, vecScreenDelta; sortKey = pParticle->m_Pos.z; // NOTE: We need to do everything in screen space float flFragmentLength = (MAX_HISTORY > 1) ? 1.0 / (float)(MAX_HISTORY-1) : 1.0; for ( int i = 0; i < (MAX_HISTORY-1); i++ ) { Vector vecWorldStart, vecWorldEnd, vecScreenEnd; float flStartV, flEndV; // Did we just appear? if ( m_pPreviousPositions[i].m_Time == 0 ) continue; RemapPosition( m_pPreviousPositions[i+1].m_Position, m_pPreviousPositions[i+1].m_Time, vecWorldStart ); RemapPosition( m_pPreviousPositions[i].m_Position, m_pPreviousPositions[i].m_Time, vecWorldEnd ); // Texture wrapping flStartV = (flFragmentLength * (i+1)); flEndV = (flFragmentLength * i); TransformParticle( ParticleMgr()->GetModelView(), vecWorldStart, vecScreenStart ); TransformParticle( ParticleMgr()->GetModelView(), vecWorldEnd, vecScreenEnd ); Vector vecScreenDelta = (vecScreenEnd - vecScreenStart); if ( vecScreenDelta == vec3_origin ) continue; /* Vector vecForward, vecRight; AngleVectors( MainViewAngles(), &vecForward, &vecRight, NULL ); Vector vecWorldDelta = ( vecWorldEnd - vecWorldStart ); VectorNormalize( vecWorldDelta ); float flDot = fabs(DotProduct( vecWorldDelta, vecForward )); if ( flDot > 0.99 ) { // Remap alpha pParticle->m_flColor[3] = 1.0 - min( 1.0, RemapVal( flDot, 0.99, 1.0, 0, 1 ) ); } */ // See if we should fade float color[4]; Color32ToFloat4( color, pParticle->m_color ); Tracer_Draw( pDraw, vecScreenStart, vecScreenDelta, pParticle->m_flWidth, color, flStartV, flEndV ); } return true; }
void C_ParticleSmokeGrenade::RenderParticles( CParticleRenderIterator *pIterator ) { const SmokeGrenadeParticle *pParticle = (const SmokeGrenadeParticle*)pIterator->GetFirst(); while ( pParticle ) { Vector vWorldSpacePos = m_SmokeBasePos + pParticle->m_Pos; float sortKey; // Draw. float len = pParticle->m_Pos.Length(); if ( len > m_ExpandRadius ) { Vector vTemp; TransformParticle(ParticleMgr()->GetModelView(), vWorldSpacePos, vTemp); sortKey = vTemp.z; } else { // This smooths out the growing sphere. Rather than having particles appear in one spot as the sphere // expands, they stay at the borders. Vector renderPos; if(len > m_ExpandRadius * 0.5f) { renderPos = m_SmokeBasePos + (pParticle->m_Pos * (m_ExpandRadius * 0.5f)) / len; } else { renderPos = vWorldSpacePos; } // Figure out the alpha based on where it is in the sphere. float alpha = 1 - len / m_ExpandRadius; // This changes the ramp to be very solid in the core, then taper off. static float testCutoff=0.7; if(alpha > testCutoff) { alpha = 1; } else { // at testCutoff it's 1, at 0, it's 0 alpha = alpha / testCutoff; } // Fade out globally. alpha *= m_FadeAlpha; // 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); color.x *= pParticle->m_Color[0] / 255.0f; color.y *= pParticle->m_Color[1] / 255.0f; color.z *= pParticle->m_Color[2] / 255.0f; // Lighting. ApplyDynamicLight( renderPos, color ); Vector tRenderPos; TransformParticle(ParticleMgr()->GetModelView(), renderPos, tRenderPos); sortKey = tRenderPos.z; RenderParticle_ColorSizeAngle( pIterator->GetParticleDraw(), tRenderPos, color, alpha * GetAlphaDistanceFade(tRenderPos, 100, 200), // Alpha SMOKEPARTICLE_SIZE, pParticle->m_CurRotation ); } pParticle = (SmokeGrenadeParticle*)pIterator->GetNext( sortKey ); } }
bool C_ParticleSmokeGrenade::SimulateAndRender(Particle *pBaseParticle, ParticleDraw *pDraw, float &sortKey) { SmokeGrenadeParticle* pParticle = (SmokeGrenadeParticle*)pBaseParticle; // Draw. float len = (pParticle->m_Pos - m_SmokeBasePos).Length(); if(len > m_ExpandRadius) { Vector vTemp; TransformParticle(g_ParticleMgr.GetModelView(), pParticle->m_Pos, vTemp); sortKey = vTemp.z; return true; } // This smooths out the growing sphere. Rather than having particles appear in one spot as the sphere // expands, they stay at the borders. Vector renderPos; if(len > m_ExpandRadius * 0.5f) { renderPos = m_SmokeBasePos + ((pParticle->m_Pos - m_SmokeBasePos) * (m_ExpandRadius * 0.5f)) / len; } else { renderPos = pParticle->m_Pos; } // Figure out the alpha based on where it is in the sphere. float alpha = 1 - len / m_ExpandRadius; // This changes the ramp to be very solid in the core, then taper off. static float testCutoff=0.7; if(alpha > testCutoff) { alpha = 1; } else { // at testCutoff it's 1, at 0, it's 0 alpha = alpha / testCutoff; } // Fade out globally. alpha *= m_FadeAlpha; pParticle->m_CurRotation += pParticle->m_RotationSpeed * pDraw->GetTimeDelta(); // 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); 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(g_ParticleMgr.GetModelView(), renderPos, tRenderPos); sortKey = tRenderPos.z; RenderParticle_ColorSizeAngle( pDraw, tRenderPos, color, alpha * GetAlphaDistanceFade(tRenderPos, 10, 30), // Alpha SMOKEPARTICLE_SIZE, pParticle->m_CurRotation ); return true; }