#[repr(C)]pub struct Color {
pub r: f32,
pub g: f32,
pub b: f32,
pub a: f32,
}Expand description
An RGBA color with f32 components in the 0.0..=1.0 range.
Colors are stored in linear RGBA order and can be constructed from floats,
u8 values, or hex codes:
use astrelis_render::Color;
let red = Color::rgb(1.0, 0.0, 0.0);
let semi_transparent = Color::rgba(1.0, 1.0, 1.0, 0.5);
let from_hex = Color::from_hex(0xFF8800);
let from_bytes = Color::from_rgba_u8(128, 64, 32, 255);The struct is #[repr(C)] and implements bytemuck::Pod, so it can be
used directly in GPU uniform/vertex buffers.
Fields§
§r: f32§g: f32§b: f32§a: f32Implementations§
Source§impl Color
impl Color
pub const WHITE: Color
pub const BLACK: Color
pub const RED: Color
pub const GREEN: Color
pub const BLUE: Color
pub const YELLOW: Color
pub const CYAN: Color
pub const MAGENTA: Color
pub const TRANSPARENT: Color
Sourcepub const fn rgb(r: f32, g: f32, b: f32) -> Self
pub const fn rgb(r: f32, g: f32, b: f32) -> Self
Create a color from RGB components with full opacity (alpha = 1.0).
Examples found in repository?
examples/sprite_sheet.rs (line 457)
431 fn render(
432 &mut self,
433 _ctx: &mut astrelis_winit::app::AppCtx,
434 window_id: WindowId,
435 events: &mut astrelis_winit::event::EventBatch,
436 ) {
437 let Some(window) = self.windows.get_mut(&window_id) else {
438 return;
439 };
440
441 // Handle resize
442 events.dispatch(|event| {
443 if let astrelis_winit::event::Event::WindowResized(size) = event {
444 window.resized(*size);
445 astrelis_winit::event::HandleStatus::consumed()
446 } else {
447 astrelis_winit::event::HandleStatus::ignored()
448 }
449 });
450
451 let Some(frame) = window.begin_frame() else {
452 return; // Surface not available
453 };
454 {
455 let mut pass = frame
456 .render_pass()
457 .clear_color(Color::rgb(0.1, 0.1, 0.15))
458 .label("sprite_sheet_pass")
459 .build();
460 pass.set_pipeline(&self.pipeline);
461 pass.set_bind_group(0, &self.bind_group, &[]);
462 pass.set_vertex_buffer(0, self.vertex_buffer.slice(..));
463 pass.draw(0..6, 0..1);
464 }
465 // Frame auto-submits on drop
466 }More examples
examples/image_blitting.rs (line 513)
486 fn render(
487 &mut self,
488 _ctx: &mut astrelis_winit::app::AppCtx,
489 window_id: WindowId,
490 events: &mut astrelis_winit::event::EventBatch,
491 ) {
492 let Some(window) = self.windows.get_mut(&window_id) else {
493 return;
494 };
495
496 // Handle resize
497 events.dispatch(|event| {
498 if let astrelis_winit::event::Event::WindowResized(size) = event {
499 window.resized(*size);
500 astrelis_winit::event::HandleStatus::consumed()
501 } else {
502 astrelis_winit::event::HandleStatus::ignored()
503 }
504 });
505
506 let Some(frame) = window.begin_frame() else {
507 return; // Surface not available
508 };
509
510 {
511 let mut pass = frame
512 .render_pass()
513 .clear_color(Color::rgb(0.05, 0.05, 0.08))
514 .label("image_blitting_pass")
515 .build();
516 pass.set_pipeline(&self.pipeline);
517 pass.set_bind_group(0, &self.bind_group, &[]);
518 pass.set_vertex_buffer(0, self.vertex_buffer.slice(..));
519 pass.draw(0..6, 0..1);
520 }
521 // Frame auto-submits on drop
522 }examples/textured_window.rs (line 288)
260 fn render(
261 &mut self,
262 _ctx: &mut astrelis_winit::app::AppCtx,
263 window_id: WindowId,
264 events: &mut astrelis_winit::event::EventBatch,
265 ) {
266 if window_id != self.window_id {
267 return;
268 }
269
270 // Handle window resize events
271 events.dispatch(|event| {
272 if let astrelis_winit::event::Event::WindowResized(size) = event {
273 self.window.resized(*size);
274 astrelis_winit::event::HandleStatus::consumed()
275 } else {
276 astrelis_winit::event::HandleStatus::ignored()
277 }
278 });
279
280 // --- Render Loop ---
281 let Some(frame) = self.window.begin_frame() else {
282 return; // Surface not available
283 };
284
285 {
286 let mut pass = frame
287 .render_pass()
288 .clear_color(Color::rgb(0.1, 0.2, 0.3))
289 .label("textured_window_pass")
290 .build();
291 pass.set_pipeline(&self.pipeline);
292 pass.set_bind_group(0, &self.bind_group, &[]);
293 pass.set_vertex_buffer(0, self.vertex_buffer.slice(..));
294 pass.draw(0..6, 0..1);
295 }
296 // Frame auto-submits on drop
297 }examples/window_manager_demo.rs (line 49)
38fn main() {
39 logging::init();
40
41 run_app(|ctx| {
42 let graphics_ctx =
43 GraphicsContext::new_owned_sync().expect("Failed to create graphics context");
44 let mut window_manager = WindowManager::new(graphics_ctx);
45 let mut window_colors = HashMap::new();
46
47 // Create 3 windows with different colors
48 let colors = [
49 Color::rgb(0.8, 0.2, 0.2), // Red
50 Color::rgb(0.2, 0.8, 0.2), // Green
51 Color::rgb(0.2, 0.2, 0.8), // Blue
52 ];
53
54 for (i, color) in colors.iter().enumerate() {
55 let window_id = window_manager
56 .create_window_with_descriptor(
57 ctx,
58 WindowDescriptor {
59 title: format!("Window {} - WindowManager Demo", i + 1),
60 size: Some(WinitPhysicalSize::new(400.0, 300.0)),
61 ..Default::default()
62 },
63 WindowContextDescriptor {
64 format: Some(wgpu::TextureFormat::Bgra8UnormSrgb),
65 ..Default::default()
66 },
67 )
68 .expect("Failed to create window");
69
70 window_colors.insert(window_id, *color);
71 }
72
73 Box::new(WindowManagerApp {
74 window_manager,
75 window_colors,
76 })
77 });
78}examples/profiling_demo.rs (line 162)
143 fn render(&mut self, _ctx: &mut AppCtx, window_id: WindowId, events: &mut EventBatch) {
144 new_frame();
145 profile_function!();
146
147 if window_id != self.window_id {
148 return;
149 }
150
151 events.dispatch(|event| {
152 if let astrelis_winit::event::Event::WindowResized(size) = event {
153 self.window.resized(*size);
154 astrelis_winit::event::HandleStatus::consumed()
155 } else {
156 astrelis_winit::event::HandleStatus::ignored()
157 }
158 });
159
160 // Cycle the background color to visualize frames
161 let t = (self.frame_count as f32 * 0.01).sin() * 0.5 + 0.5;
162 let clear_color = Color::rgb(0.05 + t * 0.1, 0.05, 0.15 + (1.0 - t) * 0.1);
163
164 // GPU profiling is now automatic — no special handling needed!
165 // If a profiler is attached, render passes auto-create GPU scopes,
166 // and Frame::Drop auto-resolves queries and ends the profiler frame.
167 let Some(frame) = self.window.begin_frame() else {
168 return; // Surface not available
169 };
170
171 {
172 profile_scope!("render_frame");
173 let _pass = frame
174 .render_pass()
175 .clear_color(clear_color)
176 .label("profiling_pass")
177 .build();
178 profile_scope!("draw_commands");
179 // In a real app, you would issue draw calls here.
180 }
181 // Frame auto-submits on drop
182
183 // Simulate some post-render work
184 {
185 profile_scope!("post_render");
186 let _ = &self.context;
187 }
188 }examples/renderer_api.rs (line 308)
284 fn render(&mut self, _ctx: &mut AppCtx, window_id: WindowId, events: &mut EventBatch) {
285 if window_id != self.window_id {
286 return;
287 }
288
289 // Handle window-specific resize events
290 events.dispatch(|event| {
291 if let astrelis_winit::event::Event::WindowResized(size) = event {
292 self.window.resized(*size);
293 astrelis_winit::event::HandleStatus::consumed()
294 } else {
295 astrelis_winit::event::HandleStatus::ignored()
296 }
297 });
298
299 let Some(frame) = self.window.begin_frame() else {
300 return; // Surface not available
301 };
302
303 // Pass 1: Render to offscreen framebuffer
304 {
305 let mut pass = frame
306 .render_pass()
307 .target(RenderTarget::Framebuffer(&self.offscreen_fb))
308 .clear_color(Color::rgb(0.2, 0.1, 0.3))
309 .label("offscreen_pass")
310 .build();
311 pass.set_pipeline(&self.pipeline);
312 pass.set_bind_group(0, &self.bind_group, &[]);
313 pass.set_vertex_buffer(0, self.vertex_buffer.slice(..));
314 pass.draw(0..6, 0..1);
315 }
316
317 // Pass 2: Blit framebuffer to surface
318 {
319 let mut pass = frame
320 .render_pass()
321 .clear_color(Color::rgb(0.1, 0.2, 0.3))
322 .label("blit_pass")
323 .build();
324 pass.set_pipeline(&self.blit_pipeline);
325 pass.set_bind_group(0, &self.blit_bind_group, &[]);
326 // Draw fullscreen triangle
327 pass.draw(0..3, 0..1);
328 }
329 // Frame auto-submits on drop
330 }Sourcepub const fn rgba(r: f32, g: f32, b: f32, a: f32) -> Self
pub const fn rgba(r: f32, g: f32, b: f32, a: f32) -> Self
Create a color from RGBA components.
Examples found in repository?
examples/multi_window.rs (lines 118-123)
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 }More examples
examples/batched_renderer.rs (line 436)
370 fn render(
371 &mut self,
372 _ctx: &mut astrelis_winit::app::AppCtx,
373 window_id: WindowId,
374 events: &mut astrelis_winit::event::EventBatch,
375 ) {
376 // Handle resize and get dimensions (scoped to release window borrow)
377 let (phys_width, phys_height) = {
378 let Some(window) = self.windows.get_mut(&window_id) else {
379 return;
380 };
381
382 events.dispatch(|event| {
383 if let astrelis_winit::event::Event::WindowResized(size) = event {
384 window.resized(*size);
385 astrelis_winit::event::HandleStatus::consumed()
386 } else {
387 astrelis_winit::event::HandleStatus::ignored()
388 }
389 });
390
391 let phys = window.physical_size();
392 (phys.width, phys.height)
393 };
394
395 let width = phys_width as f32;
396 let height = phys_height as f32;
397
398 if width < 1.0 || height < 1.0 {
399 return;
400 }
401
402 // Ensure depth buffer matches viewport
403 self.ensure_depth_buffer(phys_width, phys_height);
404
405 // Build instances and prepare GPU data
406 let instances = self.build_instances(width, height);
407 let batch = DrawBatch2D {
408 instances,
409 textures: vec![],
410 projection: Self::ortho_projection(width, height),
411 };
412 self.renderer.prepare(&batch);
413
414 let stats = self.renderer.stats();
415 if self.frame_count.is_multiple_of(120) {
416 tracing::info!(
417 "Frame {}: {} instances ({} opaque, {} transparent), {} draw calls",
418 self.frame_count,
419 stats.instance_count,
420 stats.opaque_count,
421 stats.transparent_count,
422 stats.draw_calls,
423 );
424 }
425
426 // Re-borrow window for rendering
427 let window = self.windows.get_mut(&window_id).unwrap();
428 let Some(frame) = window.begin_frame() else {
429 return; // Surface not available
430 };
431
432 // Create render pass with depth stencil attachment
433 {
434 let mut pass = frame
435 .render_pass()
436 .clear_color(Color::rgba(0.08, 0.08, 0.1, 1.0))
437 .depth_attachment(&self.depth_view)
438 .clear_depth(0.0) // 0.0 = far with GreaterEqual
439 .label("batched_example_pass")
440 .build();
441 self.renderer.render(pass.wgpu_pass());
442 }
443 // Frame auto-submits on drop
444 }Sourcepub fn from_rgba_u8(r: u8, g: u8, b: u8, a: u8) -> Self
pub fn from_rgba_u8(r: u8, g: u8, b: u8, a: u8) -> Self
Create a color from 8-bit RGBA values (0–255 mapped to 0.0–1.0).
Sourcepub fn from_rgb_u8(r: u8, g: u8, b: u8) -> Self
pub fn from_rgb_u8(r: u8, g: u8, b: u8) -> Self
Create a color from 8-bit RGB values with full opacity.
Examples found in repository?
examples/camera_demo.rs (line 109)
89 fn render(&mut self, _ctx: &mut AppCtx, window_id: WindowId, events: &mut EventBatch) {
90 if window_id != self.window_id {
91 return;
92 }
93
94 events.dispatch(|event| {
95 if let astrelis_winit::event::Event::WindowResized(size) = event {
96 self.window.resized(*size);
97 astrelis_winit::event::HandleStatus::consumed()
98 } else {
99 astrelis_winit::event::HandleStatus::ignored()
100 }
101 });
102
103 let Some(frame) = self.window.begin_frame() else {
104 return; // Surface not available
105 };
106 {
107 let _pass = frame
108 .render_pass()
109 .clear_color(Color::from_rgb_u8(20, 30, 40))
110 .label("camera_demo_pass")
111 .build();
112 }
113 // Frame auto-submits on drop
114 }More examples
examples/mesh_primitives.rs (line 111)
91 fn render(&mut self, _ctx: &mut AppCtx, window_id: WindowId, events: &mut EventBatch) {
92 if window_id != self.window_id {
93 return;
94 }
95
96 events.dispatch(|event| {
97 if let astrelis_winit::event::Event::WindowResized(size) = event {
98 self.window.resized(*size);
99 astrelis_winit::event::HandleStatus::consumed()
100 } else {
101 astrelis_winit::event::HandleStatus::ignored()
102 }
103 });
104
105 let Some(frame) = self.window.begin_frame() else {
106 return; // Surface not available
107 };
108 {
109 let _pass = frame
110 .render_pass()
111 .clear_color(Color::from_rgb_u8(20, 30, 40))
112 .label("mesh_primitives_pass")
113 .build();
114 }
115 // Frame auto-submits on drop
116 }examples/render_graph_demo.rs (line 109)
89 fn render(&mut self, _ctx: &mut AppCtx, window_id: WindowId, events: &mut EventBatch) {
90 if window_id != self.window_id {
91 return;
92 }
93
94 events.dispatch(|event| {
95 if let astrelis_winit::event::Event::WindowResized(size) = event {
96 self.window.resized(*size);
97 astrelis_winit::event::HandleStatus::consumed()
98 } else {
99 astrelis_winit::event::HandleStatus::ignored()
100 }
101 });
102
103 let Some(frame) = self.window.begin_frame() else {
104 return; // Surface not available
105 };
106 {
107 let _pass = frame
108 .render_pass()
109 .clear_color(Color::from_rgb_u8(20, 30, 40))
110 .label("render_graph_demo_pass")
111 .build();
112 }
113 // Frame auto-submits on drop
114 }examples/material_system.rs (line 132)
105 fn render(&mut self, _ctx: &mut AppCtx, window_id: WindowId, events: &mut EventBatch) {
106 if window_id != self.window_id {
107 return;
108 }
109
110 // Handle resize
111 events.dispatch(|event| {
112 if let astrelis_winit::event::Event::WindowResized(size) = event {
113 self.window.resized(*size);
114 astrelis_winit::event::HandleStatus::consumed()
115 } else {
116 astrelis_winit::event::HandleStatus::ignored()
117 }
118 });
119
120 // In a real application, materials would be bound during rendering:
121 // material.bind(&mut render_pass);
122 // draw_mesh(&mesh);
123
124 // Begin frame
125 let Some(frame) = self.window.begin_frame() else {
126 return; // Surface not available
127 };
128
129 {
130 let _pass = frame
131 .render_pass()
132 .clear_color(Color::from_rgb_u8(20, 30, 40))
133 .label("material_system_pass")
134 .build();
135 // Materials would be applied here in actual rendering
136 // This is a conceptual demonstration
137 }
138 // Frame auto-submits on drop
139 }examples/performance_benchmark.rs (line 157)
98 fn render(&mut self, _ctx: &mut AppCtx, window_id: WindowId, events: &mut EventBatch) {
99 if window_id != self.window_id {
100 return;
101 }
102
103 let frame_start = Instant::now();
104
105 // Handle resize
106 events.dispatch(|event| {
107 if let Event::WindowResized(size) = event {
108 self.window.resized(*size);
109 HandleStatus::consumed()
110 } else {
111 HandleStatus::ignored()
112 }
113 });
114
115 // Handle keyboard input
116 events.dispatch(|event| {
117 if let Event::KeyInput(key) = event
118 && key.state == astrelis_winit::event::ElementState::Pressed
119 {
120 match &key.logical_key {
121 Key::Named(NamedKey::Space) => {
122 self.rendering = !self.rendering;
123 println!("Rendering: {}", self.rendering);
124 return HandleStatus::consumed();
125 }
126 Key::Character(c) if c == "+" || c == "=" => {
127 self.object_count = (self.object_count + 500).min(50000);
128 println!("Object count: {}", self.object_count);
129 return HandleStatus::consumed();
130 }
131 Key::Character(c) if c == "-" => {
132 self.object_count = self.object_count.saturating_sub(500).max(100);
133 println!("Object count: {}", self.object_count);
134 return HandleStatus::consumed();
135 }
136 _ => {}
137 }
138 }
139 HandleStatus::ignored()
140 });
141
142 // Begin frame
143 let Some(frame) = self.window.begin_frame() else {
144 return; // Surface not available
145 };
146
147 if self.rendering {
148 // Simulate rendering thousands of objects
149 // In a real scenario, this would involve:
150 // - Instanced draw calls
151 // - Uniform buffer updates
152 // - Texture binding
153 // - Shader state changes
154
155 let _pass = frame
156 .render_pass()
157 .clear_color(Color::from_rgb_u8(10, 10, 15))
158 .label("benchmark_pass")
159 .build();
160 // Actual rendering would happen here
161 // For benchmark purposes, we're measuring the overhead
162 // of the render pass itself with clear operations
163 } else {
164 let _pass = frame
165 .render_pass()
166 .clear_color(Color::from_rgb_u8(10, 10, 15))
167 .label("benchmark_pass")
168 .build();
169 }
170 // Frame auto-submits on drop
171
172 let frame_end = Instant::now();
173 self.last_frame_time = frame_end.duration_since(frame_start).as_secs_f32() * 1000.0;
174 }Sourcepub fn from_hex_alpha(hex: u32) -> Self
pub fn from_hex_alpha(hex: u32) -> Self
Create a color from a 32-bit RGBA hex value (e.g. 0xFF880080).
Trait Implementations§
impl Copy for Color
impl Pod for Color
impl StructuralPartialEq for Color
Auto Trait Implementations§
impl Freeze for Color
impl RefUnwindSafe for Color
impl Send for Color
impl Sync for Color
impl Unpin for Color
impl UnsafeUnpin for Color
impl UnwindSafe for Color
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
Source§impl<T> CheckedBitPattern for Twhere
T: AnyBitPattern,
impl<T> CheckedBitPattern for Twhere
T: AnyBitPattern,
Source§type Bits = T
type Bits = T
Self must have the same layout as the specified Bits except for
the possible invalid bit patterns being checked during
is_valid_bit_pattern.Source§fn is_valid_bit_pattern(_bits: &T) -> bool
fn is_valid_bit_pattern(_bits: &T) -> bool
If this function returns true, then it must be valid to reinterpret
bits
as &Self.Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Convert
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can
then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Convert
Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be
further downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
Convert
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
Convert
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.Source§impl<T> DowncastSync for T
impl<T> DowncastSync for T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
Converts
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
Converts
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more