Opacity compositing
This commit is contained in:
@@ -101,6 +101,7 @@ async fn run_demo() -> Result<(), Box<dyn Error>> {
|
|||||||
window.surface_target(),
|
window.surface_target(),
|
||||||
initial_size.width as u32,
|
initial_size.width as u32,
|
||||||
initial_size.height as u32,
|
initial_size.height as u32,
|
||||||
|
ruin_ui::Color::rgb(0x08, 0x0C, 0x14),
|
||||||
)
|
)
|
||||||
.expect("wgpu renderer should initialize");
|
.expect("wgpu renderer should initialize");
|
||||||
let state = Rc::new(RefCell::new(WorkerState {
|
let state = Rc::new(RefCell::new(WorkerState {
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
window.surface_target(),
|
window.surface_target(),
|
||||||
scene.logical_size.width as u32,
|
scene.logical_size.width as u32,
|
||||||
scene.logical_size.height as u32,
|
scene.logical_size.height as u32,
|
||||||
|
ruin_ui::Color::rgb(0x08, 0x0C, 0x14),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
println!("Opening RUIN Wayland / wgpu demo window...");
|
println!("Opening RUIN Wayland / wgpu demo window...");
|
||||||
|
|||||||
@@ -58,6 +58,11 @@ impl Window {
|
|||||||
self.spec = self.spec.requested_inner_size(UiSize::new(width, height));
|
self.spec = self.spec.requested_inner_size(UiSize::new(width, height));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn base_color(mut self, color: Color) -> Self {
|
||||||
|
self.spec = self.spec.base_color(color);
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Window {
|
impl Default for Window {
|
||||||
@@ -774,7 +779,7 @@ pub mod surfaces {
|
|||||||
|
|
||||||
pub fn column() -> ContainerBuilder {
|
pub fn column() -> ContainerBuilder {
|
||||||
ContainerBuilder {
|
ContainerBuilder {
|
||||||
element: Element::column().background(surfaces::canvas()),
|
element: Element::column(),
|
||||||
widget_ref: None,
|
widget_ref: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
//! Common window model types.
|
//! Common window model types.
|
||||||
|
|
||||||
use crate::scene::UiSize;
|
use crate::scene::{Color, UiSize};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
||||||
pub struct WindowId(u64);
|
pub struct WindowId(u64);
|
||||||
@@ -55,6 +55,7 @@ pub struct WindowSpec {
|
|||||||
pub maximized: bool,
|
pub maximized: bool,
|
||||||
pub fullscreen: bool,
|
pub fullscreen: bool,
|
||||||
pub resizable: bool,
|
pub resizable: bool,
|
||||||
|
pub base_color: Color,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WindowSpec {
|
impl WindowSpec {
|
||||||
@@ -72,9 +73,15 @@ impl WindowSpec {
|
|||||||
maximized: false,
|
maximized: false,
|
||||||
fullscreen: false,
|
fullscreen: false,
|
||||||
resizable: true,
|
resizable: true,
|
||||||
|
base_color: Color::rgb(0x08, 0x0C, 0x14),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn base_color(mut self, color: Color) -> Self {
|
||||||
|
self.base_color = color;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub fn key(mut self, key: impl Into<String>) -> Self {
|
pub fn key(mut self, key: impl Into<String>) -> Self {
|
||||||
self.key = Some(key.into());
|
self.key = Some(key.into());
|
||||||
self
|
self
|
||||||
|
|||||||
@@ -1096,6 +1096,7 @@ fn spawn_window_worker(
|
|||||||
spec.requested_inner_size
|
spec.requested_inner_size
|
||||||
.unwrap_or_else(|| UiSize::new(800.0, 500.0))
|
.unwrap_or_else(|| UiSize::new(800.0, 500.0))
|
||||||
.height as u32,
|
.height as u32,
|
||||||
|
spec.base_color,
|
||||||
) {
|
) {
|
||||||
Ok(renderer) => renderer,
|
Ok(renderer) => renderer,
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
|
|||||||
@@ -330,6 +330,7 @@ pub struct WgpuSceneRenderer {
|
|||||||
image_cache_order: VecDeque<u64>,
|
image_cache_order: VecDeque<u64>,
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
glyph_atlas: GlyphAtlas,
|
glyph_atlas: GlyphAtlas,
|
||||||
|
base_color: Color,
|
||||||
}
|
}
|
||||||
|
|
||||||
const MAX_TEXT_CACHE_ENTRIES: usize = 64;
|
const MAX_TEXT_CACHE_ENTRIES: usize = 64;
|
||||||
@@ -343,6 +344,7 @@ impl WgpuSceneRenderer {
|
|||||||
target: impl HasDisplayHandle + HasWindowHandle + Send + Sync + 'static,
|
target: impl HasDisplayHandle + HasWindowHandle + Send + Sync + 'static,
|
||||||
width: u32,
|
width: u32,
|
||||||
height: u32,
|
height: u32,
|
||||||
|
base_color: Color,
|
||||||
) -> Result<Self, Box<dyn Error>> {
|
) -> Result<Self, Box<dyn Error>> {
|
||||||
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor::new_without_display_handle());
|
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor::new_without_display_handle());
|
||||||
let surface = instance.create_surface(target)?;
|
let surface = instance.create_surface(target)?;
|
||||||
@@ -361,6 +363,15 @@ impl WgpuSceneRenderer {
|
|||||||
.copied()
|
.copied()
|
||||||
.find(wgpu::TextureFormat::is_srgb)
|
.find(wgpu::TextureFormat::is_srgb)
|
||||||
.unwrap_or(caps.formats[0]);
|
.unwrap_or(caps.formats[0]);
|
||||||
|
let alpha_mode = if base_color.a < 255
|
||||||
|
&& caps
|
||||||
|
.alpha_modes
|
||||||
|
.contains(&wgpu::CompositeAlphaMode::PreMultiplied)
|
||||||
|
{
|
||||||
|
wgpu::CompositeAlphaMode::PreMultiplied
|
||||||
|
} else {
|
||||||
|
caps.alpha_modes[0]
|
||||||
|
};
|
||||||
let config = wgpu::SurfaceConfiguration {
|
let config = wgpu::SurfaceConfiguration {
|
||||||
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
|
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
|
||||||
format,
|
format,
|
||||||
@@ -368,7 +379,7 @@ impl WgpuSceneRenderer {
|
|||||||
height: height.max(1),
|
height: height.max(1),
|
||||||
present_mode: wgpu::PresentMode::AutoVsync,
|
present_mode: wgpu::PresentMode::AutoVsync,
|
||||||
desired_maximum_frame_latency: 2,
|
desired_maximum_frame_latency: 2,
|
||||||
alpha_mode: caps.alpha_modes[0],
|
alpha_mode,
|
||||||
view_formats: vec![],
|
view_formats: vec![],
|
||||||
};
|
};
|
||||||
surface.configure(&device, &config);
|
surface.configure(&device, &config);
|
||||||
@@ -415,7 +426,7 @@ fn sd_round_rect(point: vec2<f32>, rect: vec4<f32>, radius: f32) -> f32 {
|
|||||||
|
|
||||||
fn rounded_rect_alpha(point: vec2<f32>, rect: vec4<f32>, radius: f32) -> f32 {
|
fn rounded_rect_alpha(point: vec2<f32>, rect: vec4<f32>, radius: f32) -> f32 {
|
||||||
let distance = sd_round_rect(point, rect, radius);
|
let distance = sd_round_rect(point, rect, radius);
|
||||||
return 1.0 - smoothstep(0.0, 1.0, distance);
|
return 1.0 - smoothstep(-0.5, 0.5, distance);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn blurred_round_rect_alpha(point: vec2<f32>, rect: vec4<f32>, radius: f32, blur: f32) -> f32 {
|
fn blurred_round_rect_alpha(point: vec2<f32>, rect: vec4<f32>, radius: f32, blur: f32) -> f32 {
|
||||||
@@ -553,7 +564,7 @@ fn sd_round_rect(point: vec2<f32>, rect: vec4<f32>, radius: f32) -> f32 {
|
|||||||
|
|
||||||
fn rounded_rect_alpha(point: vec2<f32>, rect: vec4<f32>, radius: f32) -> f32 {
|
fn rounded_rect_alpha(point: vec2<f32>, rect: vec4<f32>, radius: f32) -> f32 {
|
||||||
let distance = sd_round_rect(point, rect, radius);
|
let distance = sd_round_rect(point, rect, radius);
|
||||||
return 1.0 - smoothstep(0.0, 1.0, distance);
|
return 1.0 - smoothstep(-0.5, 0.5, distance);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_clip_alpha(point: vec2<f32>, clip_rect: vec4<f32>, rounded_clip_rect: vec4<f32>, clip_params: vec2<f32>) -> f32 {
|
fn apply_clip_alpha(point: vec2<f32>, clip_rect: vec4<f32>, rounded_clip_rect: vec4<f32>, clip_params: vec2<f32>) -> f32 {
|
||||||
@@ -710,6 +721,7 @@ fn fs_main(input: VertexOut) -> @location(0) vec4<f32> {
|
|||||||
image_cache: HashMap::new(),
|
image_cache: HashMap::new(),
|
||||||
image_cache_order: VecDeque::new(),
|
image_cache_order: VecDeque::new(),
|
||||||
glyph_atlas,
|
glyph_atlas,
|
||||||
|
base_color,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -792,11 +804,16 @@ fn fs_main(input: VertexOut) -> @location(0) vec4<f32> {
|
|||||||
depth_slice: None,
|
depth_slice: None,
|
||||||
resolve_target: None,
|
resolve_target: None,
|
||||||
ops: wgpu::Operations {
|
ops: wgpu::Operations {
|
||||||
load: wgpu::LoadOp::Clear(wgpu::Color {
|
load: wgpu::LoadOp::Clear({
|
||||||
r: 0.03,
|
let a = self.base_color.a as f64 / 255.0;
|
||||||
g: 0.04,
|
// Premultiplied: multiply RGB by alpha so the compositor
|
||||||
b: 0.08,
|
// can blend correctly when alpha_mode is PreMultiplied.
|
||||||
a: 1.0,
|
wgpu::Color {
|
||||||
|
r: (self.base_color.r as f64 / 255.0) * a,
|
||||||
|
g: (self.base_color.g as f64 / 255.0) * a,
|
||||||
|
b: (self.base_color.b as f64 / 255.0) * a,
|
||||||
|
a,
|
||||||
|
}
|
||||||
}),
|
}),
|
||||||
store: wgpu::StoreOp::Store,
|
store: wgpu::StoreOp::Store,
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user