1use std::f32::consts::{FRAC_PI_2, PI};
4
5use bevy::{
6 color::palettes::css::{DARK_CYAN, GOLD, GRAY, PURPLE},
7 prelude::*,
8};
9
10fn main() {
11 App::new()
12 .add_plugins(DefaultPlugins)
13 .add_systems(Startup, setup)
14 .add_systems(Update, rotate_camera)
15 .add_systems(Update, update_config)
16 .run();
17}
18
19#[derive(Component)]
20struct GizmoColorText;
21
22fn gizmo_color_text(config: &LightGizmoConfigGroup) -> String {
23 match config.color {
24 LightGizmoColor::Manual(color) => format!("Manual {}", Srgba::from(color).to_hex()),
25 LightGizmoColor::Varied => "Random from entity".to_owned(),
26 LightGizmoColor::MatchLightColor => "Match light color".to_owned(),
27 LightGizmoColor::ByLightType => {
28 format!(
29 "Point {}, Spot {}, Directional {}",
30 Srgba::from(config.point_light_color).to_hex(),
31 Srgba::from(config.spot_light_color).to_hex(),
32 Srgba::from(config.directional_light_color).to_hex()
33 )
34 }
35 }
36}
37
38fn setup(
39 mut commands: Commands,
40 mut meshes: ResMut<Assets<Mesh>>,
41 mut materials: ResMut<Assets<StandardMaterial>>,
42 mut config_store: ResMut<GizmoConfigStore>,
43) {
44 commands.spawn((
46 Mesh3d(meshes.add(Circle::new(4.0))),
47 MeshMaterial3d(materials.add(Color::WHITE)),
48 Transform::from_rotation(Quat::from_rotation_x(-FRAC_PI_2)),
49 ));
50
51 {
53 let mesh = meshes.add(Cuboid::new(1.0, 1.0, 1.0));
54 let material = materials.add(Color::srgb_u8(124, 144, 255));
55 for x in [-2.0, 0.0, 2.0] {
56 commands.spawn((
57 Mesh3d(mesh.clone()),
58 MeshMaterial3d(material.clone()),
59 Transform::from_xyz(x, 0.5, 0.0),
60 ));
61 }
62 }
63
64 {
66 commands.spawn((
67 PointLight {
68 shadows_enabled: true,
69 range: 2.0,
70 color: DARK_CYAN.into(),
71 ..default()
72 },
73 Transform::from_xyz(0.0, 1.5, 0.0),
74 ));
75 commands.spawn((
76 SpotLight {
77 shadows_enabled: true,
78 range: 3.5,
79 color: PURPLE.into(),
80 outer_angle: PI / 4.0,
81 inner_angle: PI / 4.0 * 0.8,
82 ..default()
83 },
84 Transform::from_xyz(4.0, 2.0, 0.0).looking_at(Vec3::X * 1.5, Vec3::Y),
85 ));
86 commands.spawn((
87 DirectionalLight {
88 color: GOLD.into(),
89 illuminance: DirectionalLight::default().illuminance * 0.05,
90 shadows_enabled: true,
91 ..default()
92 },
93 Transform::from_xyz(-4.0, 2.0, 0.0).looking_at(Vec3::NEG_X * 1.5, Vec3::Y),
94 ));
95 }
96
97 commands.spawn((
99 Camera3d::default(),
100 Transform::from_xyz(-2.5, 4.5, 9.0).looking_at(Vec3::ZERO, Vec3::Y),
101 ));
102
103 {
105 commands.spawn((
106 Text::new(
107 "Press 'D' to toggle drawing gizmos on top of everything else in the scene\n\
108 Hold 'Left' or 'Right' to change the line width of the gizmos\n\
109 Press 'A' to toggle drawing of the light gizmos\n\
110 Press 'C' to cycle between the light gizmos coloring modes",
111 ),
112 Node {
113 position_type: PositionType::Absolute,
114 top: px(12),
115 left: px(12),
116 ..default()
117 },
118 ));
119
120 let (_, light_config) = config_store.config_mut::<LightGizmoConfigGroup>();
121 light_config.draw_all = true;
122 light_config.color = LightGizmoColor::MatchLightColor;
123
124 commands
125 .spawn((
126 Text::new("Gizmo color mode: "),
127 GizmoColorText,
128 Node {
129 position_type: PositionType::Absolute,
130 bottom: px(12),
131 left: px(12),
132 ..default()
133 },
134 ))
135 .with_child(TextSpan(gizmo_color_text(light_config)));
136 }
137}
138
139fn rotate_camera(mut transform: Single<&mut Transform, With<Camera>>, time: Res<Time>) {
140 transform.rotate_around(Vec3::ZERO, Quat::from_rotation_y(time.delta_secs() / 2.));
141}
142
143fn update_config(
144 mut config_store: ResMut<GizmoConfigStore>,
145 keyboard: Res<ButtonInput<KeyCode>>,
146 time: Res<Time>,
147 color_text_query: Single<Entity, With<GizmoColorText>>,
148 mut writer: TextUiWriter,
149) {
150 if keyboard.just_pressed(KeyCode::KeyD) {
151 for (_, config, _) in config_store.iter_mut() {
152 config.depth_bias = if config.depth_bias == 0. { -1. } else { 0. };
153 }
154 }
155
156 let (config, light_config) = config_store.config_mut::<LightGizmoConfigGroup>();
157 if keyboard.pressed(KeyCode::ArrowRight) {
158 config.line.width += 5. * time.delta_secs();
159 config.line.width = config.line.width.clamp(0., 50.);
160 }
161 if keyboard.pressed(KeyCode::ArrowLeft) {
162 config.line.width -= 5. * time.delta_secs();
163 config.line.width = config.line.width.clamp(0., 50.);
164 }
165 if keyboard.just_pressed(KeyCode::KeyA) {
166 config.enabled ^= true;
167 }
168 if keyboard.just_pressed(KeyCode::KeyC) {
169 light_config.color = match light_config.color {
170 LightGizmoColor::Manual(_) => LightGizmoColor::Varied,
171 LightGizmoColor::Varied => LightGizmoColor::MatchLightColor,
172 LightGizmoColor::MatchLightColor => LightGizmoColor::ByLightType,
173 LightGizmoColor::ByLightType => LightGizmoColor::Manual(GRAY.into()),
174 };
175 *writer.text(*color_text_query, 1) = gizmo_color_text(light_config);
176 }
177}