1use bytemuck::{Pod, Zeroable};
7use wgpu::*;
8
9fn align_size(size: usize, alignment: usize) -> usize {
12 (size + alignment - 1) & !(alignment - 1)
13}
14
15#[repr(C)]
20#[derive(Debug, Copy, Clone, Pod, Zeroable)]
21pub struct Uniforms {
22 pub mvp: [[f32; 4]; 4],
24 pub gamma: f32,
26 pub _padding: [f32; 3],
28}
29
30impl Uniforms {
31 pub fn new() -> Self {
33 Self {
34 mvp: [
35 [1.0, 0.0, 0.0, 0.0],
36 [0.0, 1.0, 0.0, 0.0],
37 [0.0, 0.0, 1.0, 0.0],
38 [0.0, 0.0, 0.0, 1.0],
39 ],
40 gamma: 1.0,
41 _padding: [0.0; 3],
42 }
43 }
44
45 pub fn create_orthographic_matrix(
49 display_pos: [f32; 2],
50 display_size: [f32; 2],
51 ) -> [[f32; 4]; 4] {
52 let l = display_pos[0];
53 let r = display_pos[0] + display_size[0];
54 let t = display_pos[1];
55 let b = display_pos[1] + display_size[1];
56
57 [
58 [2.0 / (r - l), 0.0, 0.0, 0.0],
59 [0.0, 2.0 / (t - b), 0.0, 0.0],
60 [0.0, 0.0, 0.5, 0.0],
61 [(r + l) / (l - r), (t + b) / (b - t), 0.5, 1.0],
62 ]
63 }
64
65 pub fn gamma_for_format(format: TextureFormat) -> f32 {
70 match format {
71 TextureFormat::Astc {
76 block: AstcBlock::B4x4,
77 channel: AstcChannel::UnormSrgb,
78 }
79 | TextureFormat::Astc {
80 block: AstcBlock::B5x4,
81 channel: AstcChannel::UnormSrgb,
82 }
83 | TextureFormat::Astc {
84 block: AstcBlock::B5x5,
85 channel: AstcChannel::UnormSrgb,
86 }
87 | TextureFormat::Astc {
88 block: AstcBlock::B6x5,
89 channel: AstcChannel::UnormSrgb,
90 }
91 | TextureFormat::Astc {
92 block: AstcBlock::B6x6,
93 channel: AstcChannel::UnormSrgb,
94 }
95 | TextureFormat::Astc {
96 block: AstcBlock::B8x5,
97 channel: AstcChannel::UnormSrgb,
98 }
99 | TextureFormat::Astc {
100 block: AstcBlock::B8x6,
101 channel: AstcChannel::UnormSrgb,
102 }
103 | TextureFormat::Astc {
104 block: AstcBlock::B8x8,
105 channel: AstcChannel::UnormSrgb,
106 }
107 | TextureFormat::Astc {
108 block: AstcBlock::B10x5,
109 channel: AstcChannel::UnormSrgb,
110 }
111 | TextureFormat::Astc {
112 block: AstcBlock::B10x6,
113 channel: AstcChannel::UnormSrgb,
114 }
115 | TextureFormat::Astc {
116 block: AstcBlock::B10x8,
117 channel: AstcChannel::UnormSrgb,
118 }
119 | TextureFormat::Astc {
120 block: AstcBlock::B10x10,
121 channel: AstcChannel::UnormSrgb,
122 }
123 | TextureFormat::Astc {
124 block: AstcBlock::B12x10,
125 channel: AstcChannel::UnormSrgb,
126 }
127 | TextureFormat::Astc {
128 block: AstcBlock::B12x12,
129 channel: AstcChannel::UnormSrgb,
130 }
131 | TextureFormat::Bc1RgbaUnormSrgb
133 | TextureFormat::Bc2RgbaUnormSrgb
134 | TextureFormat::Bc3RgbaUnormSrgb
135 | TextureFormat::Bc7RgbaUnormSrgb
136 | TextureFormat::Rgba8UnormSrgb
138 | TextureFormat::Bgra8UnormSrgb
139 | TextureFormat::Etc2Rgb8UnormSrgb
141 | TextureFormat::Etc2Rgb8A1UnormSrgb
142 | TextureFormat::Etc2Rgba8UnormSrgb => 2.2,
143 _ => 1.0,
145 }
146 }
147
148 pub fn set_mvp(&mut self, mvp: [[f32; 4]; 4]) {
150 self.mvp = mvp;
151 }
152
153 pub fn set_gamma(&mut self, gamma: f32) {
155 self.gamma = gamma;
156 }
157
158 pub fn update(&mut self, mvp: [[f32; 4]; 4], gamma: f32) {
160 self.mvp = mvp;
161 self.gamma = gamma;
162 }
163}
164
165impl Default for Uniforms {
166 fn default() -> Self {
167 Self::new()
168 }
169}
170
171pub struct UniformBuffer {
173 buffer: Buffer,
174 bind_group: BindGroup,
175 bind_group_layout: BindGroupLayout,
176}
177
178impl UniformBuffer {
179 pub fn new(device: &Device, sampler: &Sampler) -> Self {
181 let buffer_size = align_size(std::mem::size_of::<Uniforms>(), 16);
183 let buffer = device.create_buffer(&BufferDescriptor {
184 label: Some("Dear ImGui Uniform Buffer"),
185 size: buffer_size as u64,
186 usage: BufferUsages::UNIFORM | BufferUsages::COPY_DST,
187 mapped_at_creation: false,
188 });
189
190 let bind_group_layout = device.create_bind_group_layout(&BindGroupLayoutDescriptor {
192 label: Some("Dear ImGui Common Bind Group Layout"),
193 entries: &[
194 BindGroupLayoutEntry {
195 binding: 0,
196 visibility: ShaderStages::VERTEX | ShaderStages::FRAGMENT,
197 ty: BindingType::Buffer {
198 ty: BufferBindingType::Uniform,
199 has_dynamic_offset: false,
200 min_binding_size: None,
201 },
202 count: None,
203 },
204 BindGroupLayoutEntry {
205 binding: 1,
206 visibility: ShaderStages::FRAGMENT,
207 ty: BindingType::Sampler(SamplerBindingType::Filtering),
208 count: None,
209 },
210 ],
211 });
212
213 let bind_group = device.create_bind_group(&BindGroupDescriptor {
215 label: Some("Dear ImGui Common Bind Group"),
216 layout: &bind_group_layout,
217 entries: &[
218 BindGroupEntry {
219 binding: 0,
220 resource: buffer.as_entire_binding(),
221 },
222 BindGroupEntry {
223 binding: 1,
224 resource: BindingResource::Sampler(sampler),
225 },
226 ],
227 });
228
229 Self {
230 buffer,
231 bind_group,
232 bind_group_layout,
233 }
234 }
235
236 pub fn update(&self, queue: &Queue, uniforms: &Uniforms) {
238 queue.write_buffer(&self.buffer, 0, bytemuck::bytes_of(uniforms));
239 }
240
241 pub fn bind_group(&self) -> &BindGroup {
243 &self.bind_group
244 }
245
246 pub fn bind_group_layout(&self) -> &BindGroupLayout {
248 &self.bind_group_layout
249 }
250
251 pub fn buffer(&self) -> &Buffer {
253 &self.buffer
254 }
255}