#![allow(dead_code)]
use super::types::{GradientData, GradientKind};
#[repr(C)]
#[derive(Debug, Clone, Copy, bytemuck::Pod, bytemuck::Zeroable)]
#[allow(dead_code)]
pub(crate) struct GpuGradientColorParams {
pub gradient_type: u32,
pub spread_mode: u32,
pub units: u32,
pub is_constant: u32,
pub constant_color: [f32; 4],
pub linear_start: [f32; 2],
pub linear_end: [f32; 2],
pub radial_center: [f32; 2],
pub radial_radius: [f32; 2],
pub conic_center: [f32; 2],
pub conic_start_angle: f32,
pub period_start: f32,
pub period_len: f32,
pub ramp_start: f32,
pub ramp_end: f32,
pub _padding: f32,
}
impl GpuGradientColorParams {
pub fn from_gradient_data(data: &GradientData) -> Self {
let gradient_type = match data.kind {
GradientKind::Linear => 1u32,
GradientKind::Radial => 2u32,
GradientKind::Conic => 3u32,
};
let spread_mode = match data.spread {
super::types::SpreadMode::Pad => 0u32,
super::types::SpreadMode::Repeat => 1u32,
};
let units = match data.units {
super::types::GradientUnits::Local => 0u32,
super::types::GradientUnits::Canvas => 1u32,
};
let linear_start = data.linear_line.map(|l| l.start).unwrap_or([0.0, 0.0]);
let linear_end = data.linear_line.map(|l| l.end).unwrap_or([0.0, 0.0]);
let radial_center = data.radial_center.unwrap_or([0.0, 0.0]);
let radial_radius = data.radial_radius.unwrap_or([0.0, 0.0]);
let conic_center = data.conic_center.unwrap_or([0.0, 0.0]);
let conic_start_angle = data.conic_start_angle.unwrap_or(0.0);
let is_conic = data.kind == GradientKind::Conic;
let (period_start, period_len) = if is_conic {
let tau = std::f32::consts::TAU;
(data.period_start / tau, data.period_len / tau)
} else {
(data.period_start, data.period_len)
};
GpuGradientColorParams {
gradient_type,
spread_mode,
units,
is_constant: data.is_constant as u32,
constant_color: data.constant_color,
linear_start,
linear_end,
radial_center,
radial_radius,
conic_center,
conic_start_angle,
period_start,
period_len,
ramp_start: period_start,
ramp_end: period_start + period_len,
_padding: 0.0,
}
}
pub fn none() -> Self {
Self {
gradient_type: 0,
spread_mode: 0,
units: 0,
is_constant: 0,
constant_color: [0.0; 4],
linear_start: [0.0; 2],
linear_end: [0.0; 2],
radial_center: [0.0; 2],
radial_radius: [0.0; 2],
conic_center: [0.0; 2],
conic_start_angle: 0.0,
period_start: 0.0,
period_len: 0.0,
ramp_start: 0.0,
ramp_end: 1.0,
_padding: 0.0,
}
}
}
#[repr(C)]
#[derive(Debug, Clone, Copy, bytemuck::Pod, bytemuck::Zeroable)]
pub(crate) struct GpuBackdropSamplingParams {
pub capture_origin: [f32; 2],
pub inverse_capture_size: [f32; 2],
}
impl Default for GpuBackdropSamplingParams {
fn default() -> Self {
Self {
capture_origin: [0.0, 0.0],
inverse_capture_size: [1.0, 1.0],
}
}
}
impl GpuBackdropSamplingParams {
pub fn from_sampling_uniform(
sampling_uniform: crate::pipeline::BackdropSamplingUniform,
) -> Self {
Self {
capture_origin: sampling_uniform.capture_origin,
inverse_capture_size: sampling_uniform.inverse_capture_size,
}
}
}
#[repr(C)]
#[derive(Debug, Clone, Copy, bytemuck::Pod, bytemuck::Zeroable)]
pub(crate) struct GpuMaterialParams {
pub gradient: GpuGradientColorParams,
pub backdrop_sampling: GpuBackdropSamplingParams,
}
impl Default for GpuMaterialParams {
fn default() -> Self {
Self {
gradient: GpuGradientColorParams::none(),
backdrop_sampling: GpuBackdropSamplingParams::default(),
}
}
}
impl GpuMaterialParams {
pub fn from_gradient_data(data: &GradientData) -> Self {
Self {
gradient: GpuGradientColorParams::from_gradient_data(data),
backdrop_sampling: GpuBackdropSamplingParams::default(),
}
}
pub fn with_backdrop_sampling(
mut self,
sampling_uniform: crate::pipeline::BackdropSamplingUniform,
) -> Self {
self.backdrop_sampling = GpuBackdropSamplingParams::from_sampling_uniform(sampling_uniform);
self
}
pub fn for_backdrop_sampling(
sampling_uniform: crate::pipeline::BackdropSamplingUniform,
) -> Self {
Self::default().with_backdrop_sampling(sampling_uniform)
}
}
pub(crate) fn create_ramp_texture(
device: &wgpu::Device,
queue: &wgpu::Queue,
ramp: &[[f32; 4]],
) -> (wgpu::Texture, wgpu::TextureView) {
let fallback = [[0.0_f32; 4]];
let ramp = if ramp.is_empty() { &fallback[..] } else { ramp };
let width = ramp.len() as u32;
let texture = device.create_texture(&wgpu::TextureDescriptor {
label: Some("gradient_ramp_texture"),
size: wgpu::Extent3d {
width,
height: 1,
depth_or_array_layers: 1,
},
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D1,
format: wgpu::TextureFormat::Rgba32Float,
usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
view_formats: &[],
});
queue.write_texture(
wgpu::TexelCopyTextureInfo {
texture: &texture,
mip_level: 0,
origin: wgpu::Origin3d::ZERO,
aspect: wgpu::TextureAspect::All,
},
bytemuck::cast_slice(ramp),
wgpu::TexelCopyBufferLayout {
offset: 0,
bytes_per_row: Some(width * 16), rows_per_image: None,
},
wgpu::Extent3d {
width,
height: 1,
depth_or_array_layers: 1,
},
);
let view = texture.create_view(&wgpu::TextureViewDescriptor {
dimension: Some(wgpu::TextureViewDimension::D1),
..Default::default()
});
(texture, view)
}
pub(crate) fn create_default_ramp_texture(
device: &wgpu::Device,
queue: &wgpu::Queue,
) -> (wgpu::Texture, wgpu::TextureView) {
create_ramp_texture(device, queue, &[[0.0, 0.0, 0.0, 0.0]])
}