| 167 | } |
| 168 | |
| 169 | void WorldPainter::renderParticles(WorldRenderData& renderData, Particle::Layer layer) { |
| 170 | const int textParticleFontSize = m_assets->json("/rendering.config:textParticleFontSize").toInt(); |
| 171 | const RectF particleRenderWindow = RectF::withSize(Vec2F(), Vec2F(m_camera.screenSize())).padded(m_assets->json("/rendering.config:particleRenderWindowPadding").toInt()); |
| 172 | |
| 173 | if (!renderData.particles) |
| 174 | return; |
| 175 | |
| 176 | for (Particle const& particle : *renderData.particles) { |
| 177 | if (layer != particle.layer) |
| 178 | continue; |
| 179 | |
| 180 | Vec2F position = m_camera.worldToScreen(particle.position); |
| 181 | |
| 182 | if (!particleRenderWindow.contains(position)) |
| 183 | continue; |
| 184 | |
| 185 | Vec2F size = Vec2F::filled(particle.size * m_camera.pixelRatio()); |
| 186 | |
| 187 | if (particle.type == Particle::Type::Ember) { |
| 188 | m_renderer->immediatePrimitives().emplace_back(std::in_place_type_t<RenderQuad>(), |
| 189 | RectF(position - size / 2, position + size / 2), |
| 190 | particle.color.toRgba(), |
| 191 | particle.fullbright ? 0.0f : 1.0f); |
| 192 | |
| 193 | } else if (particle.type == Particle::Type::Streak) { |
| 194 | // Draw a rotated quad streaking in the direction the particle is coming from. |
| 195 | // Sadly this looks awful. |
| 196 | Vec2F dir = particle.velocity.normalized(); |
| 197 | Vec2F sideHalf = dir.rot90() * m_camera.pixelRatio() * particle.size / 2; |
| 198 | float length = particle.length * m_camera.pixelRatio(); |
| 199 | Vec4B color = particle.color.toRgba(); |
| 200 | float lightMapMultiplier = particle.fullbright ? 0.0f : 1.0f; |
| 201 | m_renderer->immediatePrimitives().emplace_back(std::in_place_type_t<RenderQuad>(), |
| 202 | position - sideHalf, |
| 203 | position + sideHalf, |
| 204 | position - dir * length + sideHalf, |
| 205 | position - dir * length - sideHalf, |
| 206 | color, lightMapMultiplier); |
| 207 | |
| 208 | } else if (particle.type == Particle::Type::Textured || particle.type == Particle::Type::Animated) { |
| 209 | Drawable drawable; |
| 210 | if (particle.type == Particle::Type::Textured) |
| 211 | drawable = Drawable::makeImage(particle.image, 1.0f / TilePixels, true, Vec2F(0, 0)); |
| 212 | else |
| 213 | drawable = particle.animation->drawable(1.0f / TilePixels); |
| 214 | |
| 215 | if (particle.flip && particle.flippable) |
| 216 | drawable.scale(Vec2F(-1, 1)); |
| 217 | if (drawable.isImage() && particle.type != Particle::Type::Animated) |
| 218 | drawable.imagePart().addDirectivesGroup(particle.directives, true); |
| 219 | drawable.fullbright = particle.fullbright; |
| 220 | drawable.color = particle.color; |
| 221 | drawable.rotate(particle.rotation); |
| 222 | drawable.scale(particle.size); |
| 223 | drawable.translate(particle.position); |
| 224 | drawDrawable(std::move(drawable)); |
| 225 | |
| 226 | } else if (particle.type == Particle::Type::Text) { |
nothing calls this directly
no test coverage detected