multi_window_text/multi_window_text.rs
1//! Renders text to multiple windows with different scale factors using both Text and Text2d.
2use bevy::{
3 camera::{visibility::RenderLayers, RenderTarget},
4 color::palettes::css::{LIGHT_CYAN, YELLOW},
5 prelude::*,
6 sprite::Text2dShadow,
7 window::{WindowRef, WindowResolution},
8};
9
10fn main() {
11 App::new()
12 // By default, a primary window is spawned by `WindowPlugin`, contained in `DefaultPlugins`.
13 // The primary window is given the `PrimaryWindow` marker component.
14 .add_plugins(DefaultPlugins.set(WindowPlugin {
15 primary_window: Some(Window {
16 title: "Primary window".to_owned(),
17 // Override the primary window's scale factor and use `1.` (no scaling).
18 resolution: WindowResolution::default().with_scale_factor_override(1.),
19 ..default()
20 }),
21 ..Default::default()
22 }))
23 .add_systems(Startup, setup_scene)
24 .run();
25}
26
27fn setup_scene(mut commands: Commands) {
28 // The first camera; no render target is specified, its render target will be set to the primary window automatically.
29 // This camera has no `RenderLayers` component, so it only renders entities belonging to render layer `0`.
30 commands.spawn(Camera2d);
31
32 // Spawn a second window
33 let secondary_window = commands
34 .spawn(Window {
35 title: "Secondary Window".to_owned(),
36 // Override the secondary window's scale factor and set it to double that of the primary window.
37 // This means the second window's text will use glyphs drawn at twice the resolution of the primary window's text,
38 // and they will be twice as big on screen.
39 resolution: WindowResolution::default().with_scale_factor_override(2.),
40 ..default()
41 })
42 .id();
43
44 // Spawn a second camera
45 let secondary_window_camera = commands
46 .spawn((
47 Camera2d,
48 // This camera will only render entities belonging to render layer `1`.
49 RenderLayers::layer(1),
50 // Without an explicit render target, this camera would also target the primary window.
51 RenderTarget::Window(WindowRef::Entity(secondary_window)),
52 ))
53 .id();
54
55 let node = Node {
56 position_type: PositionType::Absolute,
57 top: px(12.0),
58 left: px(12.0),
59 ..default()
60 };
61
62 let text_font = TextFont::from_font_size(30.);
63
64 // UI nodes can only be rendered by one camera at a time and ignore `RenderLayers`.
65 // This root UI node has no `UiTargetCamera` so `bevy_ui` will try to find a
66 // camera with the `IsDefaultUiCamera` marker component. When that fails (neither
67 // camera spawned here has an `IsDefaultUiCamera`), it queries for the
68 // first camera targeting the primary window and uses that.
69 commands.spawn(node.clone()).with_child((
70 Text::new("UI Text Primary Window"),
71 text_font.clone(),
72 TextShadow::default(),
73 ));
74
75 commands
76 .spawn((node, UiTargetCamera(secondary_window_camera)))
77 .with_child((
78 Text::new("UI Text Secondary Window"),
79 text_font.clone(),
80 TextShadow::default(),
81 ));
82
83 // `Text2d` belonging to render layer `0`.
84 commands.spawn((
85 Text2d::new("Text2d Primary Window"),
86 TextColor(YELLOW.into()),
87 text_font.clone(),
88 Text2dShadow::default(),
89 ));
90
91 // `Text2d` belonging to render layer `1`.
92 commands.spawn((
93 Text2d::new("Text2d Secondary Window"),
94 TextColor(YELLOW.into()),
95 text_font.clone(),
96 Text2dShadow::default(),
97 RenderLayers::layer(1),
98 ));
99
100 // This `Text2d` entity belongs to both render layers `0` and `1`, so it will be rendered by both
101 // cameras. A single text layout is generated per `Text2d` entity, targeting a specific scale
102 // factor. Since the two camera's render targets have different scale factors, the text layout
103 // will be generated using the higher scale factor (the secondary window's), and then downscaled when it is
104 // drawn by the camera targeting the primary window.
105 commands.spawn((
106 Text2d::new("Text2d Both Windows"),
107 TextColor(LIGHT_CYAN.into()),
108 text_font,
109 Text2dShadow::default(),
110 RenderLayers::from_layers(&[0, 1]),
111 Transform::from_xyz(0., -50., 0.),
112 ));
113}