docs/bevy/examples/2d/wireframe_2d.rs 6.4 K · 191 lines · raw · history

1 //! Showcases wireframe rendering for 2d meshes.
2 //!
3 //! Wireframes currently do not work when using webgl or webgpu.
4 //! Supported platforms:
5 //! - DX12
6 //! - Vulkan
7 //! - Metal
8 //!
9 //! This is a native only feature.
10
11 use bevy::{
12 color::palettes::basic::{GREEN, RED, WHITE},
13 feathers::{theme::UiTheme, FeathersPlugins},
14 prelude::*,
15 render::{render_resource::WgpuFeatures, settings::WgpuSettings, RenderPlugin},
16 sprite_render::{
17 NoWireframe2d, Wireframe2d, Wireframe2dColor, Wireframe2dConfig, Wireframe2dPlugin,
18 },
19 ui_widgets::{radio_self_update, ValueChange},
20 };
21
22 use radio::{feathers_option_buttons, main_ui_node_scene, RadioButtonOptionValue};
23
24 #[path = "../helpers/radio.rs"]
25 mod radio;
26
27 #[path = "../helpers/theme.rs"]
28 mod theme;
29
30 fn main() {
31 App::new()
32 .add_plugins((
33 DefaultPlugins.set(RenderPlugin {
34 render_creation: WgpuSettings {
35 // WARN this is a native only feature. It will not work with webgl or webgpu
36 features: WgpuFeatures::POLYGON_MODE_LINE,
37 ..default()
38 }
39 .into(),
40 ..default()
41 }),
42 // You need to add this plugin to enable wireframe rendering
43 Wireframe2dPlugin::default(),
44 FeathersPlugins,
45 ))
46 // Wireframes can be configured with this resource. This can be changed at runtime.
47 .insert_resource(Wireframe2dConfig {
48 // The global wireframe config enables drawing of wireframes on every mesh,
49 // except those with `NoWireframe2d`. Meshes with `Wireframe2d` will always have a wireframe,
50 // regardless of the global configuration.
51 global: true,
52 // Controls the default color of all wireframes. Used as the default color for global wireframes.
53 // Can be changed per mesh using the `Wireframe2dColor` component.
54 default_color: WHITE.into(),
55 })
56 .insert_resource(UiTheme(theme::basic_example_theme(Color::WHITE)))
57 .add_systems(Startup, setup)
58 .add_observer(update_radio_button)
59 .add_observer(radio_self_update)
60 .run();
61 }
62
63 /// Whether the global wireframe setting is on or off.
64 #[derive(Clone, Copy, Component, Default, PartialEq, Debug)]
65 enum GlobalWireframeSetting {
66 #[default]
67 On,
68 Off,
69 }
70
71 /// Whether the global color setting is red or white.
72 #[derive(Clone, Copy, Component, Default, PartialEq, Debug)]
73 enum GlobalColorSetting {
74 #[default]
75 Red,
76 White,
77 }
78
79 impl From<GlobalColorSetting> for Color {
80 fn from(value: GlobalColorSetting) -> Self {
81 match value {
82 GlobalColorSetting::Red => RED.into(),
83 GlobalColorSetting::White => WHITE.into(),
84 }
85 }
86 }
87
88 /// Whether the color of the circle wireframe is red or green.
89 #[derive(Clone, Copy, Component, Default, PartialEq, Debug)]
90 enum ColorCircleWireframeSetting {
91 #[default]
92 Red,
93 Green,
94 }
95
96 impl From<ColorCircleWireframeSetting> for Color {
97 fn from(value: ColorCircleWireframeSetting) -> Self {
98 match value {
99 ColorCircleWireframeSetting::Red => RED.into(),
100 ColorCircleWireframeSetting::Green => GREEN.into(),
101 }
102 }
103 }
104
105 /// Set up a simple 3D scene
106 fn setup(
107 mut commands: Commands,
108 mut meshes: ResMut<Assets<Mesh>>,
109 mut materials: ResMut<Assets<ColorMaterial>>,
110 ) {
111 commands.spawn_scene(bsn! {
112 @main_ui_node_scene()
113 Children [
114 @feathers_option_buttons("Toggle global",
115 &[
116 (GlobalWireframeSetting::On, "ON"),
117 (GlobalWireframeSetting::Off, "OFF"),
118 ], 0)
119 --
120 @feathers_option_buttons("Change global color",
121 &[
122 (GlobalColorSetting::Red, "RED"),
123 (GlobalColorSetting::White, "WHITE"),
124 ], 1)
125 --
126 @feathers_option_buttons("Change color of the circle wireframe",
127 &[
128 (ColorCircleWireframeSetting::Red, "RED"),
129 (ColorCircleWireframeSetting::Green, "GREEN"),
130 ], 1)
131 ]
132 });
133 // Triangle: Never renders a wireframe
134 commands.spawn((
135 Mesh2d(meshes.add(Triangle2d::new(
136 Vec2::new(0.0, 50.0),
137 Vec2::new(-50.0, -50.0),
138 Vec2::new(50.0, -50.0),
139 ))),
140 MeshMaterial2d(materials.add(Color::BLACK)),
141 Transform::from_xyz(-150.0, 0.0, 0.0),
142 NoWireframe2d,
143 ));
144 // Rectangle: Follows global wireframe setting
145 commands.spawn((
146 Mesh2d(meshes.add(Rectangle::new(100.0, 100.0))),
147 MeshMaterial2d(materials.add(Color::BLACK)),
148 Transform::from_xyz(0.0, 0.0, 0.0),
149 ));
150 // Circle: Always renders a wireframe
151 commands.spawn((
152 Mesh2d(meshes.add(Circle::new(50.0))),
153 MeshMaterial2d(materials.add(Color::BLACK)),
154 Transform::from_xyz(150.0, 0.0, 0.0),
155 Wireframe2d,
156 // This lets you configure the wireframe color of this entity.
157 // If not set, this will use the color in `WireframeConfig`
158 Wireframe2dColor {
159 color: GREEN.into(),
160 },
161 ));
162
163 commands.spawn(Camera2d);
164 }
165
166 /// This system lets you toggle various wireframe settings
167 fn update_radio_button(
168 event: On<ValueChange<Entity>>,
169 toggle_global_query: Query<&RadioButtonOptionValue<GlobalWireframeSetting>>,
170 global_color_query: Query<&RadioButtonOptionValue<GlobalColorSetting>>,
171 color_circle_query: Query<&RadioButtonOptionValue<ColorCircleWireframeSetting>>,
172 mut config: ResMut<Wireframe2dConfig>,
173 mut wireframe_colors: Query<&mut Wireframe2dColor>,
174 ) {
175 // Toggle showing a wireframe on all meshes
176 if let Ok(RadioButtonOptionValue(toggle_global)) = toggle_global_query.get(event.value) {
177 config.global = matches!(toggle_global, GlobalWireframeSetting::On);
178 }
179
180 // Toggle the global wireframe color
181 if let Ok(RadioButtonOptionValue(global_color)) = global_color_query.get(event.value) {
182 config.default_color = (*global_color).into();
183 }
184
185 // Toggle the color of a wireframe using `Wireframe2dColor` and not the global color
186 if let Ok(RadioButtonOptionValue(color_circle)) = color_circle_query.get(event.value) {
187 for mut color in &mut wireframe_colors {
188 color.color = (*color_circle).into();
189 }
190 }
191 }