desktop_request_redraw/
desktop_request_redraw.rs

1//! Desktop request redraw
2use bevy::{
3    dev_tools::fps_overlay::{FpsOverlayConfig, FpsOverlayPlugin},
4    prelude::*,
5    window::RequestRedraw,
6    winit::WinitSettings,
7};
8
9fn main() {
10    App::new()
11        .add_plugins(DefaultPlugins)
12        .add_plugins(MeshPickingPlugin)
13        // Enable the FPS overlay with a high resolution refresh interval. This makes it
14        // easier to validate that UpdateMode is behaving correctly when desktop_app is used.
15        // The FPS counter should essentially pause when the cube is not rotating and should
16        // update rapidly when the cube is rotating or there is input (e.g. moving the mouse).
17        //
18        // Left and Right clicking the cube should roggle rotation on/off.
19        .add_plugins(FpsOverlayPlugin {
20            config: FpsOverlayConfig {
21                text_config: TextFont {
22                    font_size: 12.0,
23                    ..default()
24                },
25                text_color: Color::srgb(0.0, 1.0, 0.0),
26                refresh_interval: core::time::Duration::from_millis(16),
27                ..default()
28            },
29        })
30        .insert_resource(WinitSettings::desktop_app())
31        .add_systems(Startup, setup)
32        .add_systems(Update, (update, redraw.after(update)))
33        .run();
34}
35
36#[derive(Component)]
37struct AnimationActive;
38
39fn setup(
40    mut commands: Commands,
41    mut meshes: ResMut<Assets<Mesh>>,
42    mut materials: ResMut<Assets<StandardMaterial>>,
43) {
44    commands.spawn((
45        Camera3d::default(),
46        Transform::from_xyz(0.0, 5.0, 0.0).looking_at(Vec3::ZERO, Vec3::Y),
47    ));
48
49    commands.spawn((
50        PointLight {
51            intensity: 1e6,
52            ..Default::default()
53        },
54        Transform::from_xyz(-1.0, 5.0, 1.0),
55    ));
56
57    let node = Node {
58        display: Display::Block,
59        padding: UiRect::all(Val::Px(10.0)),
60        row_gap: Val::Px(10.0),
61        ..Default::default()
62    };
63
64    commands.spawn((
65        node.clone(),
66        children![
67            (
68                node.clone(),
69                children![Text::new("Right click cube to pause animation")]
70            ),
71            (
72                node.clone(),
73                children![Text::new("Left click cube to start animation")]
74            )
75        ],
76    ));
77
78    commands
79        .spawn((
80            Mesh3d(meshes.add(Cuboid::from_length(1.0))),
81            MeshMaterial3d(materials.add(Color::WHITE)),
82            AnimationActive,
83        ))
84        .observe(
85            |click: On<Pointer<Click>>, mut commands: Commands| match click.button {
86                PointerButton::Primary => {
87                    commands.entity(click.entity).insert(AnimationActive);
88                }
89                PointerButton::Secondary => {
90                    commands.entity(click.entity).remove::<AnimationActive>();
91                }
92                _ => {}
93            },
94        );
95}
96
97fn update(time: Res<Time>, mut query: Query<&mut Transform, With<AnimationActive>>) {
98    if let Ok(mut transform) = query.single_mut() {
99        transform.rotate_x(time.delta_secs().min(1.0 / 60.0));
100    }
101}
102
103fn redraw(mut commands: Commands, query: Query<Entity, With<AnimationActive>>) {
104    if query.iter().next().is_some() {
105        commands.write_message(RequestRedraw);
106    }
107}