use bytemuck::{Pod, Zeroable};
use wgpu::*;
fn align_size(size: usize, alignment: usize) -> usize {
(size + alignment - 1) & !(alignment - 1)
}
#[repr(C)]
#[derive(Debug, Copy, Clone, Pod, Zeroable)]
pub struct Uniforms {
pub mvp: [[f32; 4]; 4],
pub gamma: f32,
pub _padding: [f32; 3],
}
impl Uniforms {
pub fn new() -> Self {
Self {
mvp: [
[1.0, 0.0, 0.0, 0.0],
[0.0, 1.0, 0.0, 0.0],
[0.0, 0.0, 1.0, 0.0],
[0.0, 0.0, 0.0, 1.0],
],
gamma: 1.0,
_padding: [0.0; 3],
}
}
pub fn create_orthographic_matrix(
display_pos: [f32; 2],
display_size: [f32; 2],
) -> [[f32; 4]; 4] {
let l = display_pos[0];
let r = display_pos[0] + display_size[0];
let t = display_pos[1];
let b = display_pos[1] + display_size[1];
[
[2.0 / (r - l), 0.0, 0.0, 0.0],
[0.0, 2.0 / (t - b), 0.0, 0.0],
[0.0, 0.0, 0.5, 0.0],
[(r + l) / (l - r), (t + b) / (b - t), 0.5, 1.0],
]
}
pub fn gamma_for_format(format: TextureFormat) -> f32 {
match format {
TextureFormat::Astc {
block: AstcBlock::B4x4,
channel: AstcChannel::UnormSrgb,
}
| TextureFormat::Astc {
block: AstcBlock::B5x4,
channel: AstcChannel::UnormSrgb,
}
| TextureFormat::Astc {
block: AstcBlock::B5x5,
channel: AstcChannel::UnormSrgb,
}
| TextureFormat::Astc {
block: AstcBlock::B6x5,
channel: AstcChannel::UnormSrgb,
}
| TextureFormat::Astc {
block: AstcBlock::B6x6,
channel: AstcChannel::UnormSrgb,
}
| TextureFormat::Astc {
block: AstcBlock::B8x5,
channel: AstcChannel::UnormSrgb,
}
| TextureFormat::Astc {
block: AstcBlock::B8x6,
channel: AstcChannel::UnormSrgb,
}
| TextureFormat::Astc {
block: AstcBlock::B8x8,
channel: AstcChannel::UnormSrgb,
}
| TextureFormat::Astc {
block: AstcBlock::B10x5,
channel: AstcChannel::UnormSrgb,
}
| TextureFormat::Astc {
block: AstcBlock::B10x6,
channel: AstcChannel::UnormSrgb,
}
| TextureFormat::Astc {
block: AstcBlock::B10x8,
channel: AstcChannel::UnormSrgb,
}
| TextureFormat::Astc {
block: AstcBlock::B10x10,
channel: AstcChannel::UnormSrgb,
}
| TextureFormat::Astc {
block: AstcBlock::B12x10,
channel: AstcChannel::UnormSrgb,
}
| TextureFormat::Astc {
block: AstcBlock::B12x12,
channel: AstcChannel::UnormSrgb,
}
| TextureFormat::Bc1RgbaUnormSrgb
| TextureFormat::Bc2RgbaUnormSrgb
| TextureFormat::Bc3RgbaUnormSrgb
| TextureFormat::Bc7RgbaUnormSrgb
| TextureFormat::Rgba8UnormSrgb
| TextureFormat::Bgra8UnormSrgb
| TextureFormat::Etc2Rgb8UnormSrgb
| TextureFormat::Etc2Rgb8A1UnormSrgb
| TextureFormat::Etc2Rgba8UnormSrgb => 2.2,
_ => 1.0,
}
}
pub fn set_mvp(&mut self, mvp: [[f32; 4]; 4]) {
self.mvp = mvp;
}
pub fn set_gamma(&mut self, gamma: f32) {
self.gamma = gamma;
}
pub fn update(&mut self, mvp: [[f32; 4]; 4], gamma: f32) {
self.mvp = mvp;
self.gamma = gamma;
}
}
impl Default for Uniforms {
fn default() -> Self {
Self::new()
}
}
pub struct UniformBuffer {
buffer: Buffer,
bind_group: BindGroup,
bind_group_layout: BindGroupLayout,
}
impl UniformBuffer {
pub fn new(device: &Device, sampler: &Sampler) -> Self {
let buffer_size = align_size(std::mem::size_of::<Uniforms>(), 16);
let buffer = device.create_buffer(&BufferDescriptor {
label: Some("Dear ImGui Uniform Buffer"),
size: buffer_size as u64,
usage: BufferUsages::UNIFORM | BufferUsages::COPY_DST,
mapped_at_creation: false,
});
let bind_group_layout = device.create_bind_group_layout(&BindGroupLayoutDescriptor {
label: Some("Dear ImGui Common Bind Group Layout"),
entries: &[
BindGroupLayoutEntry {
binding: 0,
visibility: ShaderStages::VERTEX | ShaderStages::FRAGMENT,
ty: BindingType::Buffer {
ty: BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
BindGroupLayoutEntry {
binding: 1,
visibility: ShaderStages::FRAGMENT,
ty: BindingType::Sampler(SamplerBindingType::Filtering),
count: None,
},
],
});
let bind_group = device.create_bind_group(&BindGroupDescriptor {
label: Some("Dear ImGui Common Bind Group"),
layout: &bind_group_layout,
entries: &[
BindGroupEntry {
binding: 0,
resource: buffer.as_entire_binding(),
},
BindGroupEntry {
binding: 1,
resource: BindingResource::Sampler(sampler),
},
],
});
Self {
buffer,
bind_group,
bind_group_layout,
}
}
pub fn update(&self, queue: &Queue, uniforms: &Uniforms) {
queue.write_buffer(&self.buffer, 0, bytemuck::bytes_of(uniforms));
}
pub fn bind_group(&self) -> &BindGroup {
&self.bind_group
}
pub fn bind_group_layout(&self) -> &BindGroupLayout {
&self.bind_group_layout
}
pub fn buffer(&self) -> &Buffer {
&self.buffer
}
}