use std::f32::consts::{FRAC_PI_2, PI};
use bevy::{
color::palettes::css::{GREY, PINK, WHITE},
core_pipeline::core_2d::graph::{Core2d, Node2d},
prelude::*,
render::{
RenderApp,
render_graph::{RenderGraphExt, ViewNodeRunner},
},
};
use crate::{
buffers::BuffersPlugin,
change::ChangePlugin,
extract::ExtractPlugin,
lights::LightPlugin,
nodes::{ApplyLightmapNode, CreateLightmapNode, SpriteNode},
occluders::{Occluder2dShape, OccluderPlugin, translate_vertices},
pipelines::PipelinePlugin,
sprites::SpritesPlugin,
visibility::VisibilityPlugin,
*,
};
use crate::{prelude::*, prepare::PreparePlugin};
pub struct FireflyPlugin;
impl Plugin for FireflyPlugin {
fn build(&self, app: &mut App) {
app.add_plugins((
PipelinePlugin,
PreparePlugin,
ExtractPlugin,
BuffersPlugin,
VisibilityPlugin,
ChangePlugin,
));
app.add_plugins((LightPlugin, OccluderPlugin, SpritesPlugin));
let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
return;
};
render_app
.add_render_graph_node::<ViewNodeRunner<CreateLightmapNode>>(
Core2d,
CreateLightmapLabel,
)
.add_render_graph_node::<ViewNodeRunner<ApplyLightmapNode>>(Core2d, ApplyLightmapLabel)
.add_render_graph_node::<ViewNodeRunner<SpriteNode>>(Core2d, SpriteLabel);
render_app.add_render_graph_edges(
Core2d,
(
Node2d::StartMainPassPostProcessing,
SpriteLabel,
CreateLightmapLabel,
ApplyLightmapLabel,
Node2d::Tonemapping,
),
);
}
}
pub struct FireflyGizmosPlugin;
impl Plugin for FireflyGizmosPlugin {
fn build(&self, app: &mut App) {
app.init_resource::<FireflyGizmoStyle>();
app.add_systems(Update, draw_gizmos);
}
}
#[derive(Resource)]
pub struct FireflyGizmoStyle {
pub light_outer_color: Color,
pub light_inner_color: Color,
pub occluder_color: Color,
}
impl Default for FireflyGizmoStyle {
fn default() -> Self {
Self {
light_outer_color: Color::Srgba(GREY),
light_inner_color: Color::Srgba(WHITE),
occluder_color: Color::Srgba(PINK),
}
}
}
fn draw_gizmos(
mut gizmos: Gizmos,
style: Res<FireflyGizmoStyle>,
occluders: Query<(&GlobalTransform, &Occluder2d)>,
lights: Query<(&GlobalTransform, &PointLight2d)>,
) {
for (transform, light) in lights {
let isometry = Isometry2d::from_translation(transform.translation().xy());
gizmos.circle_2d(isometry, light.inner_range, style.light_inner_color);
gizmos.circle_2d(isometry, light.range, style.light_outer_color);
}
for (transform, occluder) in &occluders {
match occluder.shape().clone() {
Occluder2dShape::Polygon { vertices, .. } => {
let vertices = translate_vertices(
vertices,
transform.translation().truncate() + occluder.offset.xy(),
Rot2::radians(transform.rotation().to_euler(EulerRot::XYZ).2),
);
for line in vertices.windows(2) {
gizmos.line_2d(line[0], line[1], style.occluder_color);
}
gizmos.line_2d(
vertices[0],
vertices[vertices.len() - 1],
style.occluder_color,
);
}
Occluder2dShape::Polyline { vertices, .. } => {
let vertices = translate_vertices(
vertices,
transform.translation().truncate() + occluder.offset.xy(),
Rot2::radians(transform.rotation().to_euler(EulerRot::XYZ).2),
);
for line in vertices.windows(2) {
gizmos.line_2d(line[0], line[1], style.occluder_color);
}
}
Occluder2dShape::RoundRectangle {
width,
height,
radius,
} => {
let center = transform.translation().truncate() + occluder.offset.xy();
let width = width / 2.;
let height = height / 2.;
let rot = Rot2::radians(transform.rotation().to_euler(EulerRot::XYZ).2);
let rotate =
|v: Vec2| vec2(v.x * rot.cos - v.y * rot.sin, v.x * rot.sin + v.y * rot.cos);
gizmos.line_2d(
center + rotate(vec2(-width, height + radius)),
center + rotate(vec2(width, height + radius)),
style.occluder_color,
);
gizmos.line_2d(
center + rotate(vec2(width + radius, height)),
center + rotate(vec2(width + radius, -height)),
style.occluder_color,
);
gizmos.line_2d(
center + rotate(vec2(-width, -height - radius)),
center + rotate(vec2(width, -height - radius)),
style.occluder_color,
);
gizmos.line_2d(
center + rotate(vec2(-width - radius, height)),
center + rotate(vec2(-width - radius, -height)),
style.occluder_color,
);
gizmos.arc_2d(
Isometry2d {
translation: center + rotate(vec2(-width, height)),
rotation: Rot2::radians(transform.rotation().to_euler(EulerRot::XYZ).2),
},
FRAC_PI_2,
radius,
style.occluder_color,
);
gizmos.arc_2d(
Isometry2d {
translation: center + rotate(vec2(width, height)),
rotation: Rot2::radians(
transform.rotation().to_euler(EulerRot::XYZ).2 - FRAC_PI_2,
),
},
FRAC_PI_2,
radius,
style.occluder_color,
);
gizmos.arc_2d(
Isometry2d {
translation: center + rotate(vec2(width, -height)),
rotation: Rot2::radians(
transform.rotation().to_euler(EulerRot::XYZ).2 + PI,
),
},
FRAC_PI_2,
radius,
style.occluder_color,
);
gizmos.arc_2d(
Isometry2d {
translation: center + rotate(vec2(-width, -height)),
rotation: Rot2::radians(
transform.rotation().to_euler(EulerRot::XYZ).2 + FRAC_PI_2,
),
},
FRAC_PI_2,
radius,
style.occluder_color,
);
}
}
}
}