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