Skip to main content

multi_window/
multi_window.rs

1//! Multi-window example demonstrating multiple RenderableWindows.
2//!
3//! This example creates 3 windows, each with a different clear color:
4//! - Red window
5//! - Green window
6//! - Blue window
7//!
8//! Each window shares the same GraphicsContext and renders independently
9//! using the RenderPassBuilder API.
10
11use astrelis_core::logging;
12use astrelis_render::{Color, GraphicsContext, RenderWindow, RenderWindowBuilder};
13use astrelis_winit::{
14    WindowId,
15    app::run_app,
16    window::{WindowDescriptor, WinitPhysicalSize},
17};
18use std::collections::HashMap;
19
20struct App {
21    // Each window gets its own RenderWindow (owns a wgpu::Surface) plus a clear color.
22    windows: HashMap<WindowId, (RenderWindow, wgpu::Color)>,
23}
24
25fn main() {
26    logging::init();
27
28    run_app(|ctx| {
29        let graphics_ctx =
30            GraphicsContext::new_owned_sync().expect("Failed to create graphics context");
31
32        let mut windows = HashMap::new();
33
34        // Create 3 windows with different colors
35        let colors = [
36            wgpu::Color {
37                r: 0.8,
38                g: 0.2,
39                b: 0.2,
40                a: 1.0,
41            },
42            wgpu::Color {
43                r: 0.2,
44                g: 0.8,
45                b: 0.2,
46                a: 1.0,
47            },
48            wgpu::Color {
49                r: 0.2,
50                g: 0.2,
51                b: 0.8,
52                a: 1.0,
53            },
54        ];
55
56        for (i, color) in colors.iter().enumerate() {
57            let window = ctx
58                .create_window(WindowDescriptor {
59                    title: format!("Window {} - Multi-Window Example", i + 1),
60                    size: Some(WinitPhysicalSize::new(400.0, 300.0)),
61                    ..Default::default()
62                })
63                .expect("Failed to create window");
64
65            let renderable_window = RenderWindowBuilder::new()
66                .color_format(wgpu::TextureFormat::Bgra8UnormSrgb)
67                .with_depth_default()
68                .build(window, graphics_ctx.clone())
69                .expect("Failed to create render window");
70
71            let window_id = renderable_window.id();
72            windows.insert(window_id, (renderable_window, *color));
73        }
74
75        Box::new(App { windows })
76    });
77}
78
79impl astrelis_winit::app::App for App {
80    fn update(
81        &mut self,
82        _ctx: &mut astrelis_winit::app::AppCtx,
83        _time: &astrelis_winit::FrameTime,
84    ) {
85        // Global logic - called once per frame
86        // (none needed for this example)
87    }
88
89    fn render(
90        &mut self,
91        _ctx: &mut astrelis_winit::app::AppCtx,
92        window_id: WindowId,
93        events: &mut astrelis_winit::event::EventBatch,
94    ) {
95        // Get the window and color for this specific window
96        let Some((window, color)) = self.windows.get_mut(&window_id) else {
97            return;
98        };
99
100        // Handle resize: each window dispatches events independently.
101        events.dispatch(|event| {
102            if let astrelis_winit::event::Event::WindowResized(size) = event {
103                window.resized(*size);
104                astrelis_winit::event::HandleStatus::consumed()
105            } else {
106                astrelis_winit::event::HandleStatus::ignored()
107            }
108        });
109
110        // Render this specific window
111        let Some(frame) = window.begin_frame() else {
112            return; // Surface not available
113        };
114
115        {
116            let _pass = frame
117                .render_pass()
118                .clear_color(Color::rgba(
119                    color.r as f32,
120                    color.g as f32,
121                    color.b as f32,
122                    color.a as f32,
123                ))
124                .label("multi_window_pass")
125                .build();
126            // Just clearing - no rendering commands needed
127        }
128        // Frame auto-submits on drop
129    }
130}