Skip to content

Commit

Permalink
Fps overlay (#12382)
Browse files Browse the repository at this point in the history
# Objective

- Part of #12351
- Add fps overlay

## Solution

- Create `FpsOverlayPlugin`
- Allow for configuration through resource `FpsOverlayConfig`
- Allow for configuration during runtime

### Preview on default settings

![20240308_22h23m25s_grim](https://github.com/bevyengine/bevy/assets/62356462/33d3d7a9-435e-4e0b-9814-d3274e779a69)

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
  • Loading branch information
matiqo15 and alice-i-cecile committed Mar 11, 2024
1 parent 27215b7 commit 2d29954
Show file tree
Hide file tree
Showing 6 changed files with 190 additions and 0 deletions.
12 changes: 12 additions & 0 deletions Cargo.toml
Expand Up @@ -2763,6 +2763,18 @@ description = "A scene showcasing light gizmos"
category = "Gizmos"
wasm = true

[[example]]
name = "fps_overlay"
path = "examples/dev_tools/fps_overlay.rs"
doc-scrape-examples = true
required-features = ["bevy_dev_tools"]

[package.metadata.example.fps_overlay]
name = "FPS overlay"
description = "Demonstrates FPS overlay"
category = "Dev tools"
wasm = true

[profile.wasm-release]
inherits = "release"
opt-level = "z"
Expand Down
6 changes: 6 additions & 0 deletions crates/bevy_dev_tools/Cargo.toml
Expand Up @@ -19,6 +19,12 @@ bevy_ecs = { path = "../bevy_ecs", version = "0.14.0-dev" }
bevy_render = { path = "../bevy_render", version = "0.14.0-dev" }
bevy_time = { path = "../bevy_time", version = "0.14.0-dev" }
bevy_window = { path = "../bevy_window", version = "0.14.0-dev" }
bevy_asset = { path = "../bevy_asset", version = "0.14.0-dev" }
bevy_ui = { path = "../bevy_ui", version = "0.14.0-dev" }
bevy_text = { path = "../bevy_text", version = "0.14.0-dev" }
bevy_diagnostic = { path = "../bevy_diagnostic", version = "0.14.0-dev" }
bevy_color = { path = "../bevy_color", version = "0.14.0-dev" }
bevy_input = { path = "../bevy_input", version = "0.14.0-dev" }

# other
serde = { version = "1.0", features = ["derive"], optional = true }
Expand Down
98 changes: 98 additions & 0 deletions crates/bevy_dev_tools/src/fps_overlay.rs
@@ -0,0 +1,98 @@
//! Module containing logic for FPS overlay.

use bevy_app::{Plugin, Startup, Update};
use bevy_asset::Handle;
use bevy_color::Color;
use bevy_diagnostic::{DiagnosticsStore, FrameTimeDiagnosticsPlugin};
use bevy_ecs::{
component::Component,
query::With,
schedule::{common_conditions::resource_changed, IntoSystemConfigs},
system::{Commands, Query, Res, Resource},
};
use bevy_text::{Font, Text, TextSection, TextStyle};
use bevy_ui::node_bundles::TextBundle;

/// A plugin that adds an FPS overlay to the Bevy application.
///
/// This plugin will add the [`FrameTimeDiagnosticsPlugin`] if it wasn't added before.
///
/// Note: It is recommended to use native overlay of rendering statistics when possible for lower overhead and more accurate results.
/// The correct way to do this will vary by platform:
/// - **Metal**: setting env variable `MTL_HUD_ENABLED=1`
#[derive(Default)]
pub struct FpsOverlayPlugin {
/// Starting configuration of overlay, this can be later be changed through [`FpsOverlayConfig`] resource.
pub config: FpsOverlayConfig,
}

impl Plugin for FpsOverlayPlugin {
fn build(&self, app: &mut bevy_app::App) {
// TODO: Use plugin dependencies, see https://github.com/bevyengine/bevy/issues/69
if !app.is_plugin_added::<FrameTimeDiagnosticsPlugin>() {
app.add_plugins(FrameTimeDiagnosticsPlugin);
}
app.insert_resource(self.config.clone())
.add_systems(Startup, setup)
.add_systems(
Update,
(
customize_text.run_if(resource_changed::<FpsOverlayConfig>),
update_text,
),
);
}
}

/// Configuration options for the FPS overlay.
#[derive(Resource, Clone)]
pub struct FpsOverlayConfig {
/// Configuration of text in the overlay.
pub text_config: TextStyle,
}

impl Default for FpsOverlayConfig {
fn default() -> Self {
FpsOverlayConfig {
text_config: TextStyle {
font: Handle::<Font>::default(),
font_size: 32.0,
color: Color::WHITE,
},
}
}
}

#[derive(Component)]
struct FpsText;

fn setup(mut commands: Commands, overlay_config: Res<FpsOverlayConfig>) {
commands.spawn((
TextBundle::from_sections([
TextSection::new("FPS: ", overlay_config.text_config.clone()),
TextSection::from_style(overlay_config.text_config.clone()),
]),
FpsText,
));
}

fn update_text(diagnostic: Res<DiagnosticsStore>, mut query: Query<&mut Text, With<FpsText>>) {
for mut text in &mut query {
if let Some(fps) = diagnostic.get(&FrameTimeDiagnosticsPlugin::FPS) {
if let Some(value) = fps.smoothed() {
text.sections[1].value = format!("{value:.2}");
}
}
}
}

fn customize_text(
overlay_config: Res<FpsOverlayConfig>,
mut query: Query<&mut Text, With<FpsText>>,
) {
for mut text in &mut query {
for section in text.sections.iter_mut() {
section.style = overlay_config.text_config.clone();
}
}
}
2 changes: 2 additions & 0 deletions crates/bevy_dev_tools/src/lib.rs
Expand Up @@ -3,8 +3,10 @@
#![cfg_attr(docsrs, feature(doc_auto_cfg))]

use bevy_app::prelude::*;

#[cfg(feature = "bevy_ci_testing")]
pub mod ci_testing;
pub mod fps_overlay;

/// Enables developer tools in an [`App`]. This plugin is added automatically with `bevy_dev_tools`
/// feature.
Expand Down
7 changes: 7 additions & 0 deletions examples/README.md
Expand Up @@ -45,6 +45,7 @@ git checkout v0.4.0
- [Assets](#assets)
- [Async Tasks](#async-tasks)
- [Audio](#audio)
- [Dev tools](#dev-tools)
- [Diagnostics](#diagnostics)
- [ECS (Entity Component System)](#ecs-entity-component-system)
- [Games](#games)
Expand Down Expand Up @@ -219,6 +220,12 @@ Example | Description
[Spatial Audio 2D](../examples/audio/spatial_audio_2d.rs) | Shows how to play spatial audio, and moving the emitter in 2D
[Spatial Audio 3D](../examples/audio/spatial_audio_3d.rs) | Shows how to play spatial audio, and moving the emitter in 3D

## Dev tools

Example | Description
--- | ---
[FPS overlay](../examples/dev_tools/fps_overlay.rs) | Demonstrates FPS overlay

## Diagnostics

Example | Description
Expand Down
65 changes: 65 additions & 0 deletions examples/dev_tools/fps_overlay.rs
@@ -0,0 +1,65 @@
//! Showcase how to use and configure FPS overlay.

use bevy::{
dev_tools::fps_overlay::{FpsOverlayConfig, FpsOverlayPlugin},
prelude::*,
};

fn main() {
App::new()
.add_plugins((
DefaultPlugins,
FpsOverlayPlugin {
config: FpsOverlayConfig {
text_config: TextStyle {
// Here we define size of our overlay
font_size: 50.0,
// We can also change color of the overlay
color: Color::srgb(0.0, 1.0, 0.0),
// If we want, we can use a custom font
font: default(),
},
},
},
))
.add_systems(Startup, setup)
.add_systems(Update, customize_config)
.run();
}

fn setup(mut commands: Commands) {
// We need to spawn camera to see overlay
commands.spawn(Camera2dBundle::default());
commands.spawn(
TextBundle::from_sections([
TextSection::new(
"Press 1 to change color of the overlay.",
TextStyle {
font_size: 25.0,
..default()
},
),
TextSection::new(
"\nPress 2 to change size of the overlay",
TextStyle {
font_size: 25.0,
..default()
},
),
])
.with_style(Style {
justify_self: JustifySelf::Center,
..default()
}),
);
}

fn customize_config(input: Res<ButtonInput<KeyCode>>, mut overlay: ResMut<FpsOverlayConfig>) {
if input.just_pressed(KeyCode::Digit1) {
// Changing resource will affect overlay
overlay.text_config.color = Color::srgb(1.0, 0.0, 0.0);
}
if input.just_pressed(KeyCode::Digit2) {
overlay.text_config.font_size -= 2.0;
}
}

0 comments on commit 2d29954

Please sign in to comment.