| 324 | } |
| 325 | |
| 326 | void ClientWeather::spawnWeatherParticles(RectF newClientRegion, float dt) { |
| 327 | if (!m_currentWeatherType) |
| 328 | return; |
| 329 | |
| 330 | for (auto const& particleConfig : m_currentWeatherType->particles) { |
| 331 | // Move client region to same wrap region as newClientRegion |
| 332 | RectF visibleRegion(m_worldGeometry.nearestTo(newClientRegion.min(), m_lastParticleVisibleRegion.min()), |
| 333 | m_worldGeometry.nearestTo(newClientRegion.min(), m_lastParticleVisibleRegion.max())); |
| 334 | |
| 335 | Vec2F targetVelocity = particleConfig.particle.velocity + Vec2F(wind(), 0); |
| 336 | float angleChange = Vec2F::angleBetween2(Vec2F(0, 1), targetVelocity); |
| 337 | visibleRegion.translate(targetVelocity * dt); |
| 338 | |
| 339 | for (auto const& renderZone : newClientRegion.subtract(visibleRegion)) { |
| 340 | float count = particleConfig.density * renderZone.width() * renderZone.height() * m_currentWeatherIntensity; |
| 341 | if (Random::randf() > fpart(count)) |
| 342 | count = std::floor(count); |
| 343 | else |
| 344 | count = std::ceil(count); |
| 345 | |
| 346 | for (int i = 0; i < count; ++i) { |
| 347 | auto newParticle = particleConfig.particle; |
| 348 | float x = Random::randf() * renderZone.width() + renderZone.xMin(); |
| 349 | float y = Random::randf() * renderZone.height() + renderZone.yMin(); |
| 350 | newParticle.position += m_worldGeometry.xwrap(Vec2F(x, y)); |
| 351 | newParticle.velocity = targetVelocity; |
| 352 | if (y > m_undergroundLevel && (!m_weatherEffectsActiveQuery || m_weatherEffectsActiveQuery(Vec2I::floor(newParticle.position)))) { |
| 353 | if (particleConfig.autoRotate) |
| 354 | newParticle.rotation += angleChange; |
| 355 | m_particles.append(std::move(newParticle)); |
| 356 | } |
| 357 | } |
| 358 | } |
| 359 | } |
| 360 | |
| 361 | m_lastParticleVisibleRegion = newClientRegion; |
| 362 | } |
| 363 | |
| 364 | } |
nothing calls this directly
no test coverage detected