inline void C_ParticleSmokeGrenade::UpdateParticleDuringTrade( int iParticle, float fTimeDelta ) { SmokeParticleInfo *pInfo = &m_SmokeParticleInfos[iParticle]; SmokeParticleInfo *pOther = &m_SmokeParticleInfos[pInfo->m_TradeIndex]; Assert(pOther->m_TradeIndex == iParticle); // This makes sure the trade only gets updated once per frame. if(pInfo < pOther) { // Increment the trade clock.. pInfo->m_TradeClock = (pOther->m_TradeClock += fTimeDelta); int x, y, z; GetParticleInfoXYZ(iParticle, x, y, z); Vector myPos = GetSmokeParticlePos(x, y, z) - m_SmokeBasePos; int otherX, otherY, otherZ; GetParticleInfoXYZ(pInfo->m_TradeIndex, otherX, otherY, otherZ); Vector otherPos = GetSmokeParticlePos(otherX, otherY, otherZ) - m_SmokeBasePos; // Is the trade finished? if(pInfo->m_TradeClock >= pInfo->m_TradeDuration) { pInfo->m_TradeIndex = pOther->m_TradeIndex = -1; pInfo->m_pParticle->m_Pos = otherPos; pOther->m_pParticle->m_Pos = myPos; SmokeGrenadeParticle *temp = pInfo->m_pParticle; pInfo->m_pParticle = pOther->m_pParticle; pOther->m_pParticle = temp; } else { // Ok, move them closer. float percent = (float)cos(pInfo->m_TradeClock * 2 * 1.57079632f / pInfo->m_TradeDuration); percent = percent * 0.5 + 0.5; pInfo->m_pParticle->m_FadeAlpha = pInfo->m_FadeAlpha + (pOther->m_FadeAlpha - pInfo->m_FadeAlpha) * (1 - percent); pOther->m_pParticle->m_FadeAlpha = pInfo->m_FadeAlpha + (pOther->m_FadeAlpha - pInfo->m_FadeAlpha) * percent; InterpColor(pInfo->m_pParticle->m_Color, pInfo->m_Color, pOther->m_Color, 1-percent); InterpColor(pOther->m_pParticle->m_Color, pInfo->m_Color, pOther->m_Color, percent); pInfo->m_pParticle->m_Pos = myPos + (otherPos - myPos) * (1 - percent); pOther->m_pParticle->m_Pos = myPos + (otherPos - myPos) * percent; } } }
void C_FuncSmokeVolume::FillVolume() { Vector vPos; for(int x=0; x < m_xCount; x++) { for(int y=0; y < m_yCount; y++) { for(int z=0; z < m_zCount; z++) { vPos = GetSmokeParticlePos( x, y, z ); if(SmokeParticleInfo *pInfo = GetSmokeParticleInfo(x,y,z)) { int contents = GetWorldPointContents(vPos); if(contents & CONTENTS_SOLID) { pInfo->m_pParticle = NULL; } else { SmokeGrenadeParticle *pParticle = (SmokeGrenadeParticle*)m_ParticleEffect.AddParticle(sizeof(SmokeGrenadeParticle), m_MaterialHandle); if(pParticle) { pParticle->m_Pos = vPos; pParticle->m_ColorInterp = (unsigned char)((rand() * 255) / RAND_MAX); pParticle->m_RotationFactor = FRand( -1.0f, 1.0f ); // Rotation factor. pParticle->m_CurRotation = FRand( -m_RotationSpeed, m_RotationSpeed ); } #ifdef _DEBUG int testX, testY, testZ; int index = GetSmokeParticleIndex(x,y,z); GetParticleInfoXYZ(index, testX, testY, testZ); assert(testX == x && testY == y && testZ == z); #endif Vector vColor = EngineGetLightForPoint(vPos); pInfo->m_Color[0] = LinearToTexture( vColor.x ); pInfo->m_Color[1] = LinearToTexture( vColor.y ); pInfo->m_Color[2] = LinearToTexture( vColor.z ); // Cast some rays and if it's too close to anything, fade its alpha down. pInfo->m_FadeAlpha = 1; for(int i=0; i < NUM_FADE_PLANES; i++) { trace_t trace; WorldTraceLine(vPos, vPos + s_FadePlaneDirections[i] * 100, MASK_SOLID_BRUSHONLY, &trace); if(trace.fraction < 1.0f) { float dist = DotProduct(trace.plane.normal, vPos) - trace.plane.dist; if(dist < 0) { pInfo->m_FadeAlpha = 0; } else if(dist < m_ParticleRadius) { float alphaScale = dist / m_ParticleRadius; alphaScale *= alphaScale * alphaScale; pInfo->m_FadeAlpha *= alphaScale; } } } pInfo->m_pParticle = pParticle; pInfo->m_TradeIndex = -1; } } } } } }
void C_FuncSmokeVolume::Update( float fTimeDelta ) { // lerp m_CurrentDensity towards m_Density at a rate of m_DensityRampSpeed if( m_CurrentDensity < m_Density ) { m_CurrentDensity += m_DensityRampSpeed * fTimeDelta; if( m_CurrentDensity > m_Density ) { m_CurrentDensity = m_Density; } } else if( m_CurrentDensity > m_Density ) { m_CurrentDensity -= m_DensityRampSpeed * fTimeDelta; if( m_CurrentDensity < m_Density ) { m_CurrentDensity = m_Density; } } if( m_CurrentDensity == 0.0f ) { return; } // This is used to randomize the direction it chooses to move a particle in. int offsetLookup[3] = {-1,0,1}; float tradeDurationMax = m_ParticleSpacingDistance / m_MovementSpeed; float tradeDurationMin = tradeDurationMax * 0.5f; // Warning( "tradeDuration: [%f,%f]\n", tradeDurationMin, tradeDurationMax ); // Update all the moving traders and establish new ones. int nTotal = m_xCount * m_yCount * m_zCount; for( int i=0; i < nTotal; i++ ) { SmokeParticleInfo *pInfo = &m_pSmokeParticleInfos[i]; if(!pInfo->m_pParticle) continue; if(pInfo->m_TradeIndex == -1) { pInfo->m_pParticle->m_FadeAlpha = pInfo->m_FadeAlpha; pInfo->m_pParticle->m_Color[0] = pInfo->m_Color[0]; pInfo->m_pParticle->m_Color[1] = pInfo->m_Color[1]; pInfo->m_pParticle->m_Color[2] = pInfo->m_Color[2]; // Is there an adjacent one that's not trading? int x, y, z; GetParticleInfoXYZ(i, x, y, z); int xCountOffset = rand(); int yCountOffset = rand(); int zCountOffset = rand(); bool bFound = false; for(int xCount=0; xCount < 3 && !bFound; xCount++) { for(int yCount=0; yCount < 3 && !bFound; yCount++) { for(int zCount=0; zCount < 3; zCount++) { int testX = x + offsetLookup[(xCount+xCountOffset) % 3]; int testY = y + offsetLookup[(yCount+yCountOffset) % 3]; int testZ = z + offsetLookup[(zCount+zCountOffset) % 3]; if(testX == x && testY == y && testZ == z) continue; if(IsValidXYZCoords(testX, testY, testZ)) { SmokeParticleInfo *pOther = GetSmokeParticleInfo(testX, testY, testZ); if(pOther->m_pParticle && pOther->m_TradeIndex == -1) { // Ok, this one is looking to trade also. pInfo->m_TradeIndex = GetSmokeParticleIndex(testX, testY, testZ); pOther->m_TradeIndex = i; pInfo->m_TradeClock = pOther->m_TradeClock = 0; pOther->m_TradeDuration = pInfo->m_TradeDuration = FRand( tradeDurationMin, tradeDurationMax ); bFound = true; break; } } } } } } else { SmokeParticleInfo *pOther = &m_pSmokeParticleInfos[pInfo->m_TradeIndex]; assert(pOther->m_TradeIndex == i); // This makes sure the trade only gets updated once per frame. if(pInfo < pOther) { // Increment the trade clock.. pInfo->m_TradeClock = (pOther->m_TradeClock += fTimeDelta); int x, y, z; GetParticleInfoXYZ(i, x, y, z); Vector myPos = GetSmokeParticlePos(x, y, z); int otherX, otherY, otherZ; GetParticleInfoXYZ(pInfo->m_TradeIndex, otherX, otherY, otherZ); Vector otherPos = GetSmokeParticlePos(otherX, otherY, otherZ); // Is the trade finished? if(pInfo->m_TradeClock >= pInfo->m_TradeDuration) { pInfo->m_TradeIndex = pOther->m_TradeIndex = -1; pInfo->m_pParticle->m_Pos = otherPos; pOther->m_pParticle->m_Pos = myPos; SmokeGrenadeParticle *temp = pInfo->m_pParticle; pInfo->m_pParticle = pOther->m_pParticle; pOther->m_pParticle = temp; } else { // Ok, move them closer. float percent = (float)cos(pInfo->m_TradeClock * 2 * 1.57079632f / pInfo->m_TradeDuration); percent = percent * 0.5 + 0.5; pInfo->m_pParticle->m_FadeAlpha = pInfo->m_FadeAlpha + (pOther->m_FadeAlpha - pInfo->m_FadeAlpha) * (1 - percent); pOther->m_pParticle->m_FadeAlpha = pInfo->m_FadeAlpha + (pOther->m_FadeAlpha - pInfo->m_FadeAlpha) * percent; InterpColor(pInfo->m_pParticle->m_Color, pInfo->m_Color, pOther->m_Color, 1-percent); InterpColor(pOther->m_pParticle->m_Color, pInfo->m_Color, pOther->m_Color, percent); pInfo->m_pParticle->m_Pos = myPos + (otherPos - myPos) * (1 - percent); pOther->m_pParticle->m_Pos = myPos + (otherPos - myPos) * percent; } } } } }
inline Vector GetSmokeParticlePosIndex(int index) { int x, y, z; GetParticleInfoXYZ(index, x, y, z); return GetSmokeParticlePos(x, y, z); }
void C_FuncSmokeVolume::Update( float fTimeDelta ) { // Update our world space bbox if we've moved at all. // We do this manually because sometimes people make HUGE bboxes, and if they're constantly changing because their // particles wander outside the current bounds sometimes, it'll be linking them into all the leaves repeatedly. const Vector &curOrigin = GetAbsOrigin(); const QAngle &curAngles = GetAbsAngles(); if ( !VectorsAreEqual( curOrigin, m_vLastOrigin, 0.1 ) || fabs( curAngles.x - m_vLastAngles.x ) > 0.1 || fabs( curAngles.y - m_vLastAngles.y ) > 0.1 || fabs( curAngles.z - m_vLastAngles.z ) > 0.1 || m_bFirstUpdate ) { m_bFirstUpdate = false; m_vLastAngles = curAngles; m_vLastOrigin = curOrigin; Vector vWorldMins, vWorldMaxs; CollisionProp()->WorldSpaceAABB( &vWorldMins, &vWorldMaxs ); vWorldMins -= Vector( m_ParticleRadius, m_ParticleRadius, m_ParticleRadius ); vWorldMaxs += Vector( m_ParticleRadius, m_ParticleRadius, m_ParticleRadius ); m_ParticleEffect.SetBBox( vWorldMins, vWorldMaxs ); } // lerp m_CurrentDensity towards m_Density at a rate of m_DensityRampSpeed if( m_CurrentDensity < m_Density ) { m_CurrentDensity += m_DensityRampSpeed * fTimeDelta; if( m_CurrentDensity > m_Density ) { m_CurrentDensity = m_Density; } } else if( m_CurrentDensity > m_Density ) { m_CurrentDensity -= m_DensityRampSpeed * fTimeDelta; if( m_CurrentDensity < m_Density ) { m_CurrentDensity = m_Density; } } if( m_CurrentDensity == 0.0f ) { return; } // This is used to randomize the direction it chooses to move a particle in. int offsetLookup[3] = {-1,0,1}; float tradeDurationMax = m_ParticleSpacingDistance / ( m_MovementSpeed + 0.1f ); float tradeDurationMin = tradeDurationMax * 0.5f; if ( IS_NAN( tradeDurationMax ) || IS_NAN( tradeDurationMin ) ) return; // Warning( "tradeDuration: [%f,%f]\n", tradeDurationMin, tradeDurationMax ); // Update all the moving traders and establish new ones. int nTotal = m_xCount * m_yCount * m_zCount; for( int i=0; i < nTotal; i++ ) { SmokeParticleInfo *pInfo = &m_pSmokeParticleInfos[i]; if(!pInfo->m_pParticle) continue; if(pInfo->m_TradeIndex == -1) { pInfo->m_pParticle->m_FadeAlpha = pInfo->m_FadeAlpha; pInfo->m_pParticle->m_Color[0] = pInfo->m_Color[0]; pInfo->m_pParticle->m_Color[1] = pInfo->m_Color[1]; pInfo->m_pParticle->m_Color[2] = pInfo->m_Color[2]; // Is there an adjacent one that's not trading? int x, y, z; GetParticleInfoXYZ(i, x, y, z); int xCountOffset = rand(); int yCountOffset = rand(); int zCountOffset = rand(); bool bFound = false; for(int xCount=0; xCount < 3 && !bFound; xCount++) { for(int yCount=0; yCount < 3 && !bFound; yCount++) { for(int zCount=0; zCount < 3; zCount++) { int testX = x + offsetLookup[(xCount+xCountOffset) % 3]; int testY = y + offsetLookup[(yCount+yCountOffset) % 3]; int testZ = z + offsetLookup[(zCount+zCountOffset) % 3]; if(testX == x && testY == y && testZ == z) continue; if(IsValidXYZCoords(testX, testY, testZ)) { SmokeParticleInfo *pOther = GetSmokeParticleInfo(testX, testY, testZ); if(pOther->m_pParticle && pOther->m_TradeIndex == -1) { // Ok, this one is looking to trade also. pInfo->m_TradeIndex = GetSmokeParticleIndex(testX, testY, testZ); pOther->m_TradeIndex = i; pInfo->m_TradeClock = pOther->m_TradeClock = 0; pOther->m_TradeDuration = pInfo->m_TradeDuration = FRand( tradeDurationMin, tradeDurationMax ); bFound = true; break; } } } } } } else { SmokeParticleInfo *pOther = &m_pSmokeParticleInfos[pInfo->m_TradeIndex]; assert(pOther->m_TradeIndex == i); // This makes sure the trade only gets updated once per frame. if(pInfo < pOther) { // Increment the trade clock.. pInfo->m_TradeClock = (pOther->m_TradeClock += fTimeDelta); int x, y, z; GetParticleInfoXYZ(i, x, y, z); Vector myPos = GetSmokeParticlePos(x, y, z); int otherX, otherY, otherZ; GetParticleInfoXYZ(pInfo->m_TradeIndex, otherX, otherY, otherZ); Vector otherPos = GetSmokeParticlePos(otherX, otherY, otherZ); // Is the trade finished? if(pInfo->m_TradeClock >= pInfo->m_TradeDuration) { pInfo->m_TradeIndex = pOther->m_TradeIndex = -1; pInfo->m_pParticle->m_Pos = otherPos; pOther->m_pParticle->m_Pos = myPos; SmokeGrenadeParticle *temp = pInfo->m_pParticle; pInfo->m_pParticle = pOther->m_pParticle; pOther->m_pParticle = temp; } else { // Ok, move them closer. float percent = (float)cos(pInfo->m_TradeClock * 2 * 1.57079632f / pInfo->m_TradeDuration); percent = percent * 0.5 + 0.5; pInfo->m_pParticle->m_FadeAlpha = pInfo->m_FadeAlpha + (pOther->m_FadeAlpha - pInfo->m_FadeAlpha) * (1 - percent); pOther->m_pParticle->m_FadeAlpha = pInfo->m_FadeAlpha + (pOther->m_FadeAlpha - pInfo->m_FadeAlpha) * percent; InterpColor(pInfo->m_pParticle->m_Color, pInfo->m_Color, pOther->m_Color, 1-percent); InterpColor(pOther->m_pParticle->m_Color, pInfo->m_Color, pOther->m_Color, percent); pInfo->m_pParticle->m_Pos = myPos + (otherPos - myPos) * (1 - percent); pOther->m_pParticle->m_Pos = myPos + (otherPos - myPos) * percent; } } } } }
void C_ParticleSmokeGrenade::Update(float fTimeDelta) { m_LifetimeCounter += fTimeDelta; // Update the smoke trail. C_BaseEntity *pAimEnt = GetFollowedEntity(); if ( pAimEnt ) { Vector forward, right, up; // Update the smoke particle color. if(m_CurrentStage == 0) { m_SmokeTrail.m_StartColor = EngineGetLightForPoint(GetAbsOrigin()) * 0.5f; m_SmokeTrail.m_EndColor = m_SmokeTrail.m_StartColor; } // Spin the smoke trail. AngleVectors(pAimEnt->GetAbsAngles(), &forward, &right, &up); m_SmokeTrail.m_VelocityOffset = forward * 30 + GetAbsVelocity(); m_SmokeTrail.SetLocalOrigin( GetAbsOrigin() ); m_SmokeTrail.Update(fTimeDelta); } // Update our fade alpha. if(m_LifetimeCounter < m_FadeStartTime) { m_FadeAlpha = 1; } else if(m_LifetimeCounter < m_FadeEndTime) { float fadePercent = (m_LifetimeCounter - m_FadeStartTime) / (m_FadeEndTime - m_FadeStartTime); m_FadeAlpha = cos(fadePercent * 3.14159) * 0.5 + 0.5; } else { m_FadeAlpha = 0; } // Scale by the amount the sphere has grown. m_FadeAlpha *= m_ExpandRadius / SMOKESPHERE_MAX_RADIUS; if(m_CurrentStage == 1) { // Update the expanding sphere. m_ExpandTimeCounter += fTimeDelta; if(m_ExpandTimeCounter > SMOKESPHERE_EXPAND_TIME) m_ExpandTimeCounter = SMOKESPHERE_EXPAND_TIME; m_ExpandRadius = SMOKESPHERE_MAX_RADIUS * (float)sin(m_ExpandTimeCounter * 3.14159265358 * 0.5 / SMOKESPHERE_EXPAND_TIME); // Add our influence to the global smoke fog alpha. float testDist = (EngineGetVecRenderOrigin() - m_SmokeBasePos).Length(); float fadeEnd = m_ExpandRadius * 0.75; if(testDist < fadeEnd) { EngineGetSmokeFogOverlayAlpha() += 1 - testDist / fadeEnd; } // This is used to randomize the direction it chooses to move a particle in. int offsetLookup[3] = {-1,0,1}; // Update all the moving traders and establish new ones. int nTotal = m_xCount * m_yCount * m_zCount; for(int i=0; i < nTotal; i++) { SmokeParticleInfo *pInfo = &m_SmokeParticleInfos[i]; if(!pInfo->m_pParticle) continue; if(pInfo->m_TradeIndex == -1) { pInfo->m_pParticle->m_FadeAlpha = pInfo->m_FadeAlpha; pInfo->m_pParticle->m_Color[0] = pInfo->m_Color[0]; pInfo->m_pParticle->m_Color[1] = pInfo->m_Color[1]; pInfo->m_pParticle->m_Color[2] = pInfo->m_Color[2]; // Is there an adjacent one that's not trading? int x, y, z; GetParticleInfoXYZ(i, x, y, z); int xCountOffset = rand(); int yCountOffset = rand(); int zCountOffset = rand(); bool bFound = false; for(int xCount=0; xCount < 3 && !bFound; xCount++) { for(int yCount=0; yCount < 3 && !bFound; yCount++) { for(int zCount=0; zCount < 3; zCount++) { int testX = x + offsetLookup[(xCount+xCountOffset) % 3]; int testY = y + offsetLookup[(yCount+yCountOffset) % 3]; int testZ = z + offsetLookup[(zCount+zCountOffset) % 3]; if(testX == x && testY == y && testZ == z) continue; if(IsValidXYZCoords(testX, testY, testZ)) { SmokeParticleInfo *pOther = GetSmokeParticleInfo(testX, testY, testZ); if(pOther->m_pParticle && pOther->m_TradeIndex == -1) { // Ok, this one is looking to trade also. pInfo->m_TradeIndex = GetSmokeParticleIndex(testX, testY, testZ); pOther->m_TradeIndex = i; pInfo->m_TradeClock = pOther->m_TradeClock = 0; pInfo->m_TradeDuration = FRand(TRADE_DURATION_MIN, TRADE_DURATION_MAX); bFound = true; break; } } } } } } else { SmokeParticleInfo *pOther = &m_SmokeParticleInfos[pInfo->m_TradeIndex]; assert(pOther->m_TradeIndex == i); // This makes sure the trade only gets updated once per frame. if(pInfo < pOther) { // Increment the trade clock.. pInfo->m_TradeClock = (pOther->m_TradeClock += fTimeDelta); int x, y, z; GetParticleInfoXYZ(i, x, y, z); Vector myPos = GetSmokeParticlePos(x, y, z); int otherX, otherY, otherZ; GetParticleInfoXYZ(pInfo->m_TradeIndex, otherX, otherY, otherZ); Vector otherPos = GetSmokeParticlePos(otherX, otherY, otherZ); // Is the trade finished? if(pInfo->m_TradeClock >= pInfo->m_TradeDuration) { pInfo->m_TradeIndex = pOther->m_TradeIndex = -1; pInfo->m_pParticle->m_Pos = otherPos; pOther->m_pParticle->m_Pos = myPos; SmokeGrenadeParticle *temp = pInfo->m_pParticle; pInfo->m_pParticle = pOther->m_pParticle; pOther->m_pParticle = temp; } else { // Ok, move them closer. float percent = (float)cos(pInfo->m_TradeClock * 2 * 1.57079632f / pInfo->m_TradeDuration); percent = percent * 0.5 + 0.5; pInfo->m_pParticle->m_FadeAlpha = pInfo->m_FadeAlpha + (pOther->m_FadeAlpha - pInfo->m_FadeAlpha) * (1 - percent); pOther->m_pParticle->m_FadeAlpha = pInfo->m_FadeAlpha + (pOther->m_FadeAlpha - pInfo->m_FadeAlpha) * percent; InterpColor(pInfo->m_pParticle->m_Color, pInfo->m_Color, pOther->m_Color, 1-percent); InterpColor(pOther->m_pParticle->m_Color, pInfo->m_Color, pOther->m_Color, percent); pInfo->m_pParticle->m_Pos = myPos + (otherPos - myPos) * (1 - percent); pOther->m_pParticle->m_Pos = myPos + (otherPos - myPos) * percent; } } } } } }