1use wgpu::*;
7
8use super::types::{BackgroundInstance, TextInstance, Vertex};
9
10const ALPHA_BLEND_RGB_REPLACE_ALPHA: BlendState = BlendState {
14 color: BlendComponent {
15 src_factor: BlendFactor::SrcAlpha,
16 dst_factor: BlendFactor::OneMinusSrcAlpha,
17 operation: BlendOperation::Add,
18 },
19 alpha: BlendComponent {
20 src_factor: BlendFactor::One,
22 dst_factor: BlendFactor::Zero,
23 operation: BlendOperation::Add,
24 },
25};
26
27pub fn create_bg_pipeline(device: &Device, surface_format: TextureFormat) -> RenderPipeline {
29 let bg_shader = device.create_shader_module(include_wgsl!("../shaders/cell_bg.wgsl"));
30
31 let bg_pipeline_layout = device.create_pipeline_layout(&PipelineLayoutDescriptor {
32 label: Some("bg pipeline layout"),
33 bind_group_layouts: &[],
34 push_constant_ranges: &[],
35 });
36
37 device.create_render_pipeline(&RenderPipelineDescriptor {
38 label: Some("bg pipeline"),
39 layout: Some(&bg_pipeline_layout),
40 vertex: VertexState {
41 module: &bg_shader,
42 entry_point: Some("vs_main"),
43 compilation_options: Default::default(),
44 buffers: &[
45 VertexBufferLayout {
46 array_stride: std::mem::size_of::<Vertex>() as BufferAddress,
47 step_mode: VertexStepMode::Vertex,
48 attributes: &vertex_attr_array![0 => Float32x2, 1 => Float32x2],
49 },
50 VertexBufferLayout {
51 array_stride: std::mem::size_of::<BackgroundInstance>() as BufferAddress,
52 step_mode: VertexStepMode::Instance,
53 attributes: &vertex_attr_array![2 => Float32x2, 3 => Float32x2, 4 => Float32x4],
54 },
55 ],
56 },
57 fragment: Some(FragmentState {
58 module: &bg_shader,
59 entry_point: Some("fs_main"),
60 compilation_options: Default::default(),
61 targets: &[Some(ColorTargetState {
62 format: surface_format,
63 blend: Some(ALPHA_BLEND_RGB_REPLACE_ALPHA),
66 write_mask: ColorWrites::ALL,
67 })],
68 }),
69 primitive: PrimitiveState {
70 topology: PrimitiveTopology::TriangleStrip,
71 ..Default::default()
72 },
73 depth_stencil: None,
74 multisample: MultisampleState::default(),
75 multiview: None,
76 cache: None,
77 })
78}
79
80pub fn create_text_bind_group_layout(device: &Device) -> BindGroupLayout {
82 device.create_bind_group_layout(&BindGroupLayoutDescriptor {
83 label: Some("text bind group layout"),
84 entries: &[
85 BindGroupLayoutEntry {
86 binding: 0,
87 visibility: ShaderStages::FRAGMENT,
88 ty: BindingType::Texture {
89 sample_type: TextureSampleType::Float { filterable: true },
90 view_dimension: TextureViewDimension::D2,
91 multisampled: false,
92 },
93 count: None,
94 },
95 BindGroupLayoutEntry {
96 binding: 1,
97 visibility: ShaderStages::FRAGMENT,
98 ty: BindingType::Sampler(SamplerBindingType::Filtering),
99 count: None,
100 },
101 ],
102 })
103}
104
105pub fn create_text_bind_group(
107 device: &Device,
108 layout: &BindGroupLayout,
109 atlas_view: &TextureView,
110 atlas_sampler: &Sampler,
111) -> BindGroup {
112 device.create_bind_group(&BindGroupDescriptor {
113 label: Some("text bind group"),
114 layout,
115 entries: &[
116 BindGroupEntry {
117 binding: 0,
118 resource: BindingResource::TextureView(atlas_view),
119 },
120 BindGroupEntry {
121 binding: 1,
122 resource: BindingResource::Sampler(atlas_sampler),
123 },
124 ],
125 })
126}
127
128pub fn create_text_pipeline(
130 device: &Device,
131 surface_format: TextureFormat,
132 text_bind_group_layout: &BindGroupLayout,
133) -> RenderPipeline {
134 let text_shader = device.create_shader_module(include_wgsl!("../shaders/cell_text.wgsl"));
135
136 let text_pipeline_layout = device.create_pipeline_layout(&PipelineLayoutDescriptor {
137 label: Some("text pipeline layout"),
138 bind_group_layouts: &[text_bind_group_layout],
139 push_constant_ranges: &[],
140 });
141
142 device.create_render_pipeline(&RenderPipelineDescriptor {
143 label: Some("text pipeline"),
144 layout: Some(&text_pipeline_layout),
145 vertex: VertexState {
146 module: &text_shader,
147 entry_point: Some("vs_main"),
148 compilation_options: Default::default(),
149 buffers: &[
150 VertexBufferLayout {
151 array_stride: std::mem::size_of::<Vertex>() as BufferAddress,
152 step_mode: VertexStepMode::Vertex,
153 attributes: &vertex_attr_array![0 => Float32x2, 1 => Float32x2],
154 },
155 VertexBufferLayout {
156 array_stride: std::mem::size_of::<TextInstance>() as BufferAddress,
157 step_mode: VertexStepMode::Instance,
158 attributes: &vertex_attr_array![
159 2 => Float32x2,
160 3 => Float32x2,
161 4 => Float32x2,
162 5 => Float32x2,
163 6 => Float32x4,
164 7 => Uint32
165 ],
166 },
167 ],
168 },
169 fragment: Some(FragmentState {
170 module: &text_shader,
171 entry_point: Some("fs_main"),
172 compilation_options: Default::default(),
173 targets: &[Some(ColorTargetState {
174 format: surface_format,
175 blend: Some(BlendState::ALPHA_BLENDING),
178 write_mask: ColorWrites::ALL,
179 })],
180 }),
181 primitive: PrimitiveState {
182 topology: PrimitiveTopology::TriangleStrip,
183 ..Default::default()
184 },
185 depth_stencil: None,
186 multisample: MultisampleState::default(),
187 multiview: None,
188 cache: None,
189 })
190}
191
192pub fn create_bg_image_bind_group_layout(device: &Device) -> BindGroupLayout {
194 device.create_bind_group_layout(&BindGroupLayoutDescriptor {
195 label: Some("bg image bind group layout"),
196 entries: &[
197 BindGroupLayoutEntry {
198 binding: 0,
199 visibility: ShaderStages::FRAGMENT,
200 ty: BindingType::Texture {
201 sample_type: TextureSampleType::Float { filterable: true },
202 view_dimension: TextureViewDimension::D2,
203 multisampled: false,
204 },
205 count: None,
206 },
207 BindGroupLayoutEntry {
208 binding: 1,
209 visibility: ShaderStages::FRAGMENT,
210 ty: BindingType::Sampler(SamplerBindingType::Filtering),
211 count: None,
212 },
213 BindGroupLayoutEntry {
214 binding: 2,
215 visibility: ShaderStages::VERTEX | ShaderStages::FRAGMENT,
216 ty: BindingType::Buffer {
217 ty: BufferBindingType::Uniform,
218 has_dynamic_offset: false,
219 min_binding_size: None,
220 },
221 count: None,
222 },
223 ],
224 })
225}
226
227pub fn create_bg_image_pipeline(
229 device: &Device,
230 surface_format: TextureFormat,
231 bg_image_bind_group_layout: &BindGroupLayout,
232) -> RenderPipeline {
233 let bg_image_shader =
234 device.create_shader_module(include_wgsl!("../shaders/background_image.wgsl"));
235
236 let bg_image_pipeline_layout = device.create_pipeline_layout(&PipelineLayoutDescriptor {
237 label: Some("bg image pipeline layout"),
238 bind_group_layouts: &[bg_image_bind_group_layout],
239 push_constant_ranges: &[],
240 });
241
242 device.create_render_pipeline(&RenderPipelineDescriptor {
243 label: Some("bg image pipeline"),
244 layout: Some(&bg_image_pipeline_layout),
245 vertex: VertexState {
246 module: &bg_image_shader,
247 entry_point: Some("vs_main"),
248 compilation_options: Default::default(),
249 buffers: &[VertexBufferLayout {
250 array_stride: std::mem::size_of::<Vertex>() as BufferAddress,
251 step_mode: VertexStepMode::Vertex,
252 attributes: &vertex_attr_array![0 => Float32x2, 1 => Float32x2],
253 }],
254 },
255 fragment: Some(FragmentState {
256 module: &bg_image_shader,
257 entry_point: Some("fs_main"),
258 compilation_options: Default::default(),
259 targets: &[Some(ColorTargetState {
260 format: surface_format,
261 blend: Some(BlendState::PREMULTIPLIED_ALPHA_BLENDING),
263 write_mask: ColorWrites::ALL,
264 })],
265 }),
266 primitive: PrimitiveState {
267 topology: PrimitiveTopology::TriangleStrip,
268 ..Default::default()
269 },
270 depth_stencil: None,
271 multisample: MultisampleState::default(),
272 multiview: None,
273 cache: None,
274 })
275}
276
277pub fn create_visual_bell_pipeline(
279 device: &Device,
280 surface_format: TextureFormat,
281) -> (RenderPipeline, BindGroup, BindGroupLayout, Buffer) {
282 let visual_bell_shader = device.create_shader_module(include_wgsl!("../shaders/cell_bg.wgsl"));
283
284 let visual_bell_bind_group_layout =
285 device.create_bind_group_layout(&BindGroupLayoutDescriptor {
286 label: Some("visual bell bind group layout"),
287 entries: &[BindGroupLayoutEntry {
288 binding: 0,
289 visibility: ShaderStages::FRAGMENT,
290 ty: BindingType::Buffer {
291 ty: BufferBindingType::Uniform,
292 has_dynamic_offset: false,
293 min_binding_size: None,
294 },
295 count: None,
296 }],
297 });
298
299 let visual_bell_pipeline_layout = device.create_pipeline_layout(&PipelineLayoutDescriptor {
300 label: Some("visual bell pipeline layout"),
301 bind_group_layouts: &[&visual_bell_bind_group_layout],
302 push_constant_ranges: &[],
303 });
304
305 let visual_bell_pipeline = device.create_render_pipeline(&RenderPipelineDescriptor {
306 label: Some("visual bell pipeline"),
307 layout: Some(&visual_bell_pipeline_layout),
308 vertex: VertexState {
309 module: &visual_bell_shader,
310 entry_point: Some("vs_main"),
311 compilation_options: Default::default(),
312 buffers: &[
313 VertexBufferLayout {
314 array_stride: std::mem::size_of::<Vertex>() as BufferAddress,
315 step_mode: VertexStepMode::Vertex,
316 attributes: &vertex_attr_array![0 => Float32x2, 1 => Float32x2],
317 },
318 VertexBufferLayout {
319 array_stride: std::mem::size_of::<BackgroundInstance>() as BufferAddress,
320 step_mode: VertexStepMode::Instance,
321 attributes: &vertex_attr_array![2 => Float32x2, 3 => Float32x2, 4 => Float32x4],
322 },
323 ],
324 },
325 fragment: Some(FragmentState {
326 module: &visual_bell_shader,
327 entry_point: Some("fs_main"),
328 compilation_options: Default::default(),
329 targets: &[Some(ColorTargetState {
330 format: surface_format,
331 blend: Some(BlendState::PREMULTIPLIED_ALPHA_BLENDING),
333 write_mask: ColorWrites::ALL,
334 })],
335 }),
336 primitive: PrimitiveState {
337 topology: PrimitiveTopology::TriangleStrip,
338 ..Default::default()
339 },
340 depth_stencil: None,
341 multisample: MultisampleState::default(),
342 multiview: None,
343 cache: None,
344 });
345
346 let visual_bell_uniform_buffer = device.create_buffer(&BufferDescriptor {
347 label: Some("visual bell uniform buffer"),
348 size: 64,
349 usage: BufferUsages::UNIFORM | BufferUsages::COPY_DST,
350 mapped_at_creation: false,
351 });
352
353 let visual_bell_bind_group = device.create_bind_group(&BindGroupDescriptor {
354 label: Some("visual bell bind group"),
355 layout: &visual_bell_bind_group_layout,
356 entries: &[BindGroupEntry {
357 binding: 0,
358 resource: visual_bell_uniform_buffer.as_entire_binding(),
359 }],
360 });
361
362 (
363 visual_bell_pipeline,
364 visual_bell_bind_group,
365 visual_bell_bind_group_layout,
366 visual_bell_uniform_buffer,
367 )
368}
369
370pub fn create_atlas(device: &Device) -> (Texture, TextureView, Sampler) {
372 let atlas_size = 2048;
373 let atlas_texture = device.create_texture(&TextureDescriptor {
374 label: Some("atlas texture"),
375 size: Extent3d {
376 width: atlas_size,
377 height: atlas_size,
378 depth_or_array_layers: 1,
379 },
380 mip_level_count: 1,
381 sample_count: 1,
382 dimension: TextureDimension::D2,
383 format: TextureFormat::Rgba8Unorm,
384 usage: TextureUsages::TEXTURE_BINDING | TextureUsages::COPY_DST,
385 view_formats: &[],
386 });
387 let atlas_view = atlas_texture.create_view(&TextureViewDescriptor::default());
388 let atlas_sampler = device.create_sampler(&SamplerDescriptor {
389 address_mode_u: AddressMode::ClampToEdge,
390 address_mode_v: AddressMode::ClampToEdge,
391 mag_filter: FilterMode::Linear,
392 min_filter: FilterMode::Linear,
393 ..Default::default()
394 });
395
396 (atlas_texture, atlas_view, atlas_sampler)
397}
398
399pub fn create_vertex_buffer(device: &Device) -> Buffer {
401 use wgpu::util::DeviceExt;
402
403 let vertices = [
404 Vertex {
405 position: [0.0, 0.0],
406 tex_coords: [0.0, 0.0],
407 },
408 Vertex {
409 position: [1.0, 0.0],
410 tex_coords: [1.0, 0.0],
411 },
412 Vertex {
413 position: [0.0, 1.0],
414 tex_coords: [0.0, 1.0],
415 },
416 Vertex {
417 position: [1.0, 1.0],
418 tex_coords: [1.0, 1.0],
419 },
420 ];
421
422 device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
423 label: Some("vertex buffer"),
424 contents: bytemuck::cast_slice(&vertices),
425 usage: BufferUsages::VERTEX,
426 })
427}
428
429pub fn create_instance_buffers(
431 device: &Device,
432 max_bg_instances: usize,
433 max_text_instances: usize,
434) -> (Buffer, Buffer) {
435 let bg_instance_buffer = device.create_buffer(&BufferDescriptor {
436 label: Some("bg instance buffer"),
437 size: (max_bg_instances * std::mem::size_of::<BackgroundInstance>()) as u64,
438 usage: BufferUsages::VERTEX | BufferUsages::COPY_DST,
439 mapped_at_creation: false,
440 });
441 let text_instance_buffer = device.create_buffer(&BufferDescriptor {
442 label: Some("text instance buffer"),
443 size: (max_text_instances * std::mem::size_of::<TextInstance>()) as u64,
444 usage: BufferUsages::VERTEX | BufferUsages::COPY_DST,
445 mapped_at_creation: false,
446 });
447
448 (bg_instance_buffer, text_instance_buffer)
449}
450
451pub fn create_bg_image_uniform_buffer(device: &Device) -> Buffer {
453 device.create_buffer(&BufferDescriptor {
454 label: Some("bg image uniform buffer"),
455 size: 64,
456 usage: BufferUsages::UNIFORM | BufferUsages::COPY_DST,
457 mapped_at_creation: false,
458 })
459}