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