1#![deny(missing_docs)]
2#![doc = include_str!("../README.md")]
3
4use texture::TextureSettings;
5use turbine_scene3d::*;
6use vecmath::{
7 Matrix4,
8 Vector3,
9 Vector2,
10};
11use wgpu::util::DeviceExt;
12
13use std::path::Path;
14use std::collections::HashMap;
15use std::sync::Arc;
16
17pub mod utils;
18
19struct Va {
20 pub bufs: Vec<(u32, Vert)>,
21}
22
23impl Va {
24 fn new() -> Va {
25 Va {
26 bufs: vec![]
27 }
28 }
29}
30
31enum Vert {
32 Buf2(VertexBuffer2),
33 Buf3(VertexBuffer3),
34 Col(ColorBuffer),
35 UV(UVBuffer),
36 Nor(NormalBuffer),
37}
38
39enum Uni {
40 F32(F32Uniform),
41 Matrix4(Matrix4Uniform),
42 Vector3(Vector3Uniform),
43 Vector2(Vector2Uniform),
44}
45
46#[derive(PartialEq, Eq)]
48struct RpConf {
49 topology: wgpu::PrimitiveTopology,
50 polygon_mode: wgpu::PolygonMode,
51 cull_mode: Option<wgpu::Face>,
52 blend: Option<wgpu::BlendState>,
53}
54
55impl RpConf {
56 fn new(
57 topology: wgpu::PrimitiveTopology,
58 polygon_mode: wgpu::PolygonMode,
59 state: &State,
60 ) -> Option<RpConf> {
61 Some(RpConf {
62 topology,
63 polygon_mode,
64 cull_mode: if state.cull_face {
65 match (state.cull_face_front, state.cull_face_back) {
66 (false, false) => None,
67 (false, true) => Some(wgpu::Face::Back),
68 (true, false) => Some(wgpu::Face::Front),
69 (true, true) => return None,
70 }
71 } else {None},
72 blend: if state.enable_blend {
73 Some(state.blend_op)
74 } else {None},
75 })
76 }
77}
78
79struct Prog {
80 pub render_pipelines: Vec<(RpConf, wgpu::RenderPipeline)>,
81 pub uniforms: Vec<Uni>,
82 pub uniform_bind_group_layout_entries: Vec<wgpu::BindGroupLayoutEntry>,
83 pub uniform_bind_group: Option<wgpu::BindGroup>,
84 pub vs: VertexShader,
85 pub fs: FragmentShader,
86}
87
88impl Prog {
89 fn new(vs: VertexShader, fs: FragmentShader) -> Prog {
90 Prog {
91 render_pipelines: vec![],
92 uniforms: vec![],
93 uniform_bind_group_layout_entries: vec![],
94 uniform_bind_group: None,
95 vs, fs,
96 }
97 }
98
99 fn create_render_pipeline(
100 &mut self,
101 vs: &wgpu::ShaderModule,
102 fs: &wgpu::ShaderModule,
103 surface_config: &wgpu::SurfaceConfiguration,
104 va: &Va,
105 texture_layout: Option<&wgpu::BindGroupLayout>,
106 topology: wgpu::PrimitiveTopology,
107 polygon_mode: wgpu::PolygonMode,
108 cull_mode: Option<wgpu::Face>,
109 blend: Option<wgpu::BlendState>,
110 device: &wgpu::Device,
111 ) -> wgpu::RenderPipeline {
112 use std::mem::size_of;
113 use wgpu::VertexFormat::*;
114
115 let mut vertex_attributes = vec![];
116 for (attr, n) in &va.bufs {
117 vertex_attributes.push(match n {
118 Vert::Buf2(_) | Vert::UV(_) => wgpu::VertexAttribute {
119 offset: 0,
120 shader_location: *attr,
121 format: Float32x2,
122 },
123 Vert::Buf3(_) | Vert::Nor(_) => wgpu::VertexAttribute {
124 offset: 0,
125 shader_location: *attr,
126 format: Float32x3,
127 },
128 Vert::Col(_) => wgpu::VertexAttribute {
129 offset: 0,
130 shader_location: *attr,
131 format: Float32x4,
132 },
133 });
134 }
135 let mut vertex_buffer_layouts: Vec<wgpu::VertexBufferLayout> = vec![];
136 for (id, (_, n)) in va.bufs.iter().enumerate() {
137 vertex_buffer_layouts.push(match n {
138 Vert::Buf2(_) | Vert::UV(_) => wgpu::VertexBufferLayout {
139 array_stride: size_of::<[f32; 2]>() as wgpu::BufferAddress,
140 step_mode: wgpu::VertexStepMode::Vertex,
141 attributes: &vertex_attributes[id..id + 1],
142 },
143 Vert::Buf3(_) | Vert::Nor(_) => wgpu::VertexBufferLayout {
144 array_stride: size_of::<[f32; 3]>() as wgpu::BufferAddress,
145 step_mode: wgpu::VertexStepMode::Vertex,
146 attributes: &vertex_attributes[id..id + 1],
147 },
148 Vert::Col(_) => wgpu::VertexBufferLayout {
149 array_stride: size_of::<[f32; 4]>() as wgpu::BufferAddress,
150 step_mode: wgpu::VertexStepMode::Vertex,
151 attributes: &vertex_attributes[id..id + 1],
152 },
153 });
154 }
155
156 let uniform_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
157 label: Some("uniform_bind_group_layout"),
158 entries: &self.uniform_bind_group_layout_entries,
159 });
160
161 let layouts = if let Some(texture_layout) = texture_layout {
162 vec![&uniform_layout, texture_layout]
163 } else {vec![&uniform_layout]};
164
165 let pipeline_layout = device.create_pipeline_layout(
166 &wgpu::PipelineLayoutDescriptor {
167 label: Some("Pipeline Layout"),
168 bind_group_layouts: &layouts,
169 push_constant_ranges: &[],
170 }
171 );
172
173 utils::render_pipeline(
174 &pipeline_layout,
175 vs, fs,
176 &vertex_buffer_layouts,
177 &[Some(utils::color_target_state_replace(&surface_config, blend))],
178 topology,
179 polygon_mode,
180 cull_mode,
181 &device,
182 )
183 }
184}
185
186pub struct State {
188 pub surface_texture: Option<wgpu::SurfaceTexture>,
192 surface_config: wgpu::SurfaceConfiguration,
193 device: Arc<wgpu::Device>,
194 queue: Arc<wgpu::Queue>,
195 shader_modules: Vec<wgpu::ShaderModule>,
196 shader_cache: HashMap<String, usize>,
197 programs: Vec<Prog>,
198 f32_uniforms: Vec<f32>,
199 f32_uniform_buffers: Vec<wgpu::Buffer>,
200 matrix4_uniforms: Vec<Matrix4<f32>>,
201 matrix4_uniform_buffers: Vec<wgpu::Buffer>,
202 vector3_uniforms: Vec<Vector3<f32>>,
203 vector3_uniform_buffers: Vec<wgpu::Buffer>,
204 vector2_uniforms: Vec<Vector2<f32>>,
205 vector2_uniform_buffers: Vec<wgpu::Buffer>,
206 vas: Vec<Va>,
207 vertex_buffers: Vec<wgpu::Buffer>,
208 textures: Vec<(wgpu::Texture, wgpu::BindGroupLayout, wgpu::BindGroup, u32, u32)>,
209 depth_texture_view: wgpu::TextureView,
210 encoder: Option<wgpu::CommandEncoder>,
211 render_pass: Option<wgpu::RenderPass<'static>>,
212 current_program: Option<Program>,
213 current_texture: Option<Texture>,
214 pub cull_face: bool,
216 pub cull_face_front: bool,
218 pub cull_face_back: bool,
220 pub enable_blend: bool,
222 pub blend_op: wgpu::BlendState,
224}
225
226impl State {
227 pub fn new(
229 device: Arc<wgpu::Device>,
230 queue: Arc<wgpu::Queue>,
231 surface_config: wgpu::SurfaceConfiguration,
232 depth_texture_view: wgpu::TextureView,
233 ) -> State {
234 State {
235 surface_config,
236 device,
237 queue,
238 shader_modules: vec![],
239 shader_cache: HashMap::new(),
240 programs: vec![],
241 f32_uniforms: vec![],
242 f32_uniform_buffers: vec![],
243 matrix4_uniforms: vec![],
244 matrix4_uniform_buffers: vec![],
245 vector3_uniforms: vec![],
246 vector3_uniform_buffers: vec![],
247 vector2_uniforms: vec![],
248 vector2_uniform_buffers: vec![],
249 vas: vec![],
250 vertex_buffers: vec![],
251 textures: vec![],
252 depth_texture_view,
253 cull_face: false,
254 cull_face_back: false,
255 cull_face_front: false,
256 encoder: None,
257 render_pass: None,
258 surface_texture: None,
259 current_program: None,
260 current_texture: None,
261 enable_blend: true,
262 blend_op: wgpu::BlendState::REPLACE,
263 }
264 }
265
266 pub fn start_render(&mut self, surface: &wgpu::Surface) {
268 let surface_texture = surface.get_current_texture().unwrap();
269 self.surface_texture = Some(surface_texture);
270 }
271
272 pub fn end_render(&mut self) {
274 self.end_render_pass();
275 if let Some(surface_texture) = std::mem::replace(
276 &mut self.surface_texture, None
277 ) {
278 surface_texture.present();
279 }
280 }
281
282 fn draw(
283 &mut self,
284 va: VertexArray,
285 n: usize,
286 rp_conf: RpConf,
287 ) {
288 if let (Some(program), Some(render_pass)) =
289 (self.current_program, self.render_pass.as_mut())
290 {
291 let prog = &mut self.programs[program.0];
292 let mut ind: Option<usize> = prog.render_pipelines.iter().position(|n| n.0 == rp_conf);
293 if ind.is_none() {
294 ind = Some(prog.render_pipelines.len());
295 let pipeline = prog.create_render_pipeline(
296 &self.shader_modules[prog.vs.0],
297 &self.shader_modules[prog.fs.0],
298 &self.surface_config,
299 &self.vas[va.0],
300 self.current_texture.map(|n| &self.textures[n.0].1),
301 rp_conf.topology,
302 rp_conf.polygon_mode,
303 rp_conf.cull_mode,
304 rp_conf.blend,
305 &self.device,
306 );
307 prog.render_pipelines.push((rp_conf, pipeline));
308 }
309 if prog.uniform_bind_group.is_none() {
310 let mut entries: Vec<wgpu::BindGroupEntry> = vec![];
311 for (binding, uni) in prog.uniforms.iter().enumerate() {
312 entries.push(match uni {
313 Uni::F32(s) => wgpu::BindGroupEntry {
314 binding: binding as u32,
315 resource: self.f32_uniform_buffers[s.0].as_entire_binding(),
316 },
317 Uni::Matrix4(m) => wgpu::BindGroupEntry {
318 binding: binding as u32,
319 resource: self.matrix4_uniform_buffers[m.0].as_entire_binding(),
320 },
321 Uni::Vector3(v) => wgpu::BindGroupEntry {
322 binding: binding as u32,
323 resource: self.vector3_uniform_buffers[v.0].as_entire_binding(),
324 },
325 Uni::Vector2(v) => wgpu::BindGroupEntry {
326 binding: binding as u32,
327 resource: self.vector2_uniform_buffers[v.0].as_entire_binding(),
328 },
329 });
330 }
331 let layout = self.device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
332 label: Some("uniform_bind_group_layout"),
333 entries: &prog.uniform_bind_group_layout_entries,
334 });
335 prog.uniform_bind_group = Some(utils::uniform_bind_group(
336 &layout, &entries, &self.device));
337 }
338 if let (Some((_, render_pipeline)), Some(uniform_bind_group)) =
339 (prog.render_pipelines.get(ind.unwrap()), prog.uniform_bind_group.as_ref())
340 {
341 render_pass.set_pipeline(render_pipeline);
342 render_pass.set_bind_group(0, uniform_bind_group, &[]);
343 if let Some(tex) = self.current_texture {
344 render_pass.set_bind_group(1, &self.textures[tex.0].2, &[]);
345 }
346 for (attr, buf) in &self.vas[va.0].bufs {
347 let ind = match buf {
348 Vert::Buf2(VertexBuffer2(x, _)) |
349 Vert::Buf3(VertexBuffer3(x, _)) |
350 Vert::Col(ColorBuffer(x, _)) |
351 Vert::UV(UVBuffer(x, _)) |
352 Vert::Nor(NormalBuffer(x, _)) => *x,
353 };
354 render_pass.set_vertex_buffer(*attr, self.vertex_buffers[ind].slice(..));
355 }
356 render_pass.draw(0..n as u32, 0..1);
357 }
358 self.queue.submit([]);
359 }
360 }
361}
362
363impl Backend for State {
364 type ImageError = image::ImageError;
365
366 fn set_texture(&mut self, tex: turbine_scene3d::Texture) {
367 self.current_texture = Some(tex);
368 }
369 fn draw_points(&mut self, va: turbine_scene3d::VertexArray, n: usize) {
370 if let Some(rp_conf) = RpConf::new(
371 wgpu::PrimitiveTopology::TriangleList,
372 wgpu::PolygonMode::Point,
373 self,
374 ) {
375 self.draw(va, n, rp_conf);
376 }
377 }
378 fn draw_lines(&mut self, va: turbine_scene3d::VertexArray, n: usize) {
379 if let Some(rp_conf) = RpConf::new(
380 wgpu::PrimitiveTopology::TriangleList,
381 wgpu::PolygonMode::Line,
382 self,
383 ) {
384 self.draw(va, n, rp_conf);
385 }
386 }
387 fn draw_triangle_strip(&mut self, va: VertexArray, n: usize) {
388 if let Some(rp_conf) = RpConf::new(
389 wgpu::PrimitiveTopology::TriangleStrip,
390 wgpu::PolygonMode::Fill,
391 self,
392 ) {
393 self.draw(va, n, rp_conf);
394 }
395 }
396 fn draw_triangles(&mut self, va: VertexArray, n: usize) {
397 if let Some(rp_conf) = RpConf::new(
398 wgpu::PrimitiveTopology::TriangleList,
399 wgpu::PolygonMode::Fill,
400 self,
401 ) {
402 self.draw(va, n, rp_conf);
403 }
404 }
405 fn enable_framebuffer_srgb(&mut self) {
406 }
408 fn disable_framebuffer_srgb(&mut self) {
409 }
411 fn enable_blend(&mut self) {self.enable_blend = true}
412 fn disable_blend(&mut self) {self.enable_blend = false}
413 fn enable_cull_face(&mut self) {self.cull_face = true}
414 fn disable_cull_face(&mut self) {self.cull_face = false}
415 fn cull_face_front(&mut self) {self.cull_face_front = true}
416 fn cull_face_back(&mut self) {self.cull_face_back = true}
417 fn cull_face_front_and_back(&mut self) {
418 self.cull_face_front = true;
419 self.cull_face_back = true;
420 }
421 fn clear(&mut self, color: [f32; 4], _settings: &turbine_scene3d::SceneSettings) {
422 let surface_texture = self.surface_texture.as_ref().unwrap();
423 let surface_view = surface_texture
424 .texture
425 .create_view(&wgpu::TextureViewDescriptor::default());
426 let depth_texture_view = &self.depth_texture_view;
427
428 let clear_color = wgpu::Color {
429 r: color[0] as f64,
430 g: color[1] as f64,
431 b: color[2] as f64,
432 a: color[3] as f64,
433 };
434 let mut encoder = self.device
435 .create_command_encoder(&wgpu::CommandEncoderDescriptor {
436 label: Some("Render Encoder"),
437 });
438 let rpass_color_attachment = wgpu::RenderPassColorAttachment {
439 view: &surface_view,
440 resolve_target: None,
441 ops: wgpu::Operations {
442 load: wgpu::LoadOp::Clear(clear_color),
443 store: wgpu::StoreOp::Store,
444 },
445 depth_slice: None,
446 };
447 let render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
448 label: Some("Render Pass"),
449 color_attachments: &[Some(rpass_color_attachment)],
450 depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
451 view: &depth_texture_view,
452 depth_ops: Some(wgpu::Operations {
453 load: wgpu::LoadOp::Clear(1.0),
454 store: wgpu::StoreOp::Store,
455 }),
456 stencil_ops: None,
457 }),
458 occlusion_query_set: None,
459 timestamp_writes: None,
460 });
461 drop(render_pass);
462
463 self.queue.submit(Some(encoder.finish()));
464 }
465 fn set_f32(&mut self, uni: F32Uniform, s: f32) {
466 let rendering = self.surface_texture.is_some();
467 self.end_render_pass();
468
469 self.f32_uniforms[uni.0] = s;
470 self.queue.write_buffer(
471 &self.f32_uniform_buffers[uni.0],
472 0,
473 bytemuck::cast_slice(&[s]),
474 );
475 self.queue.submit([]);
476
477 if rendering {self.begin_render_pass()};
478 }
479 fn set_vector2(&mut self, uni: Vector2Uniform, v: [f32; 2]) {
480 let rendering = self.surface_texture.is_some();
481 self.end_render_pass();
482
483 self.vector2_uniforms[uni.0] = v;
484 self.queue.write_buffer(
485 &self.vector2_uniform_buffers[uni.0],
486 0,
487 bytemuck::cast_slice(&[v]),
488 );
489 self.queue.submit([]);
490
491 if rendering {self.begin_render_pass()};
492 }
493 fn set_vector3(&mut self, uni: Vector3Uniform, v: [f32; 3]) {
494 let rendering = self.surface_texture.is_some();
495 self.end_render_pass();
496
497 self.vector3_uniforms[uni.0] = v;
498 self.queue.write_buffer(
499 &self.vector3_uniform_buffers[uni.0],
500 0,
501 bytemuck::cast_slice(&[v]),
502 );
503 self.queue.submit([]);
504
505 if rendering {self.begin_render_pass()};
506 }
507 fn set_matrix4(&mut self, uni: turbine_scene3d::Matrix4Uniform, mat: [[f32; 4]; 4]) {
508 let rendering = self.surface_texture.is_some();
509 self.end_render_pass();
510
511 self.matrix4_uniforms[uni.0] = mat;
512 self.queue.write_buffer(
513 &self.matrix4_uniform_buffers[uni.0],
514 0,
515 bytemuck::cast_slice(&[mat]),
516 );
517 self.queue.submit([]);
518
519 if rendering {self.begin_render_pass()};
520 }
521 fn use_program(&mut self, program: turbine_scene3d::Program) {
522 self.current_program = Some(program);
523 }
524 fn vertex_shader(&mut self, src: &str) -> std::result::Result<turbine_scene3d::VertexShader, String> {
525 if let Some(id) = self.shader_cache.get(src) {
526 Ok(VertexShader(*id))
527 } else {
528 let id = self.shader_modules.len();
529 self.shader_modules.push({
530 use std::borrow::Cow;
531 use wgpu::{Label, ShaderModuleDescriptor, ShaderSource};
532 self.device.create_shader_module(
533 ShaderModuleDescriptor {
534 label: Label::None,
535 source: ShaderSource::Wgsl(Cow::Borrowed(src))
536 }
537 )
538 });
539 self.shader_cache.insert(src.to_string(), id);
540 Ok(VertexShader(id))
541 }
542 }
543 fn fragment_shader(&mut self, src: &str) -> std::result::Result<turbine_scene3d::FragmentShader, String> {
544 if let Some(id) = self.shader_cache.get(src) {
545 Ok(FragmentShader(*id))
546 } else {
547 let id = self.shader_modules.len();
548 self.shader_modules.push({
549 use std::borrow::Cow;
550 use wgpu::{Label, ShaderModuleDescriptor, ShaderSource};
551 self.device.create_shader_module(
552 ShaderModuleDescriptor {
553 label: Label::None,
554 source: ShaderSource::Wgsl(Cow::Borrowed(src))
555 }
556 )
557 });
558 self.shader_cache.insert(src.to_string(), id);
559 Ok(FragmentShader(id))
560 }
561 }
562 fn vertex_buffer2(&mut self, va: turbine_scene3d::VertexArray, attr: u32, data: &[f32]) -> VertexBuffer2 {
563 let id = VertexBuffer2(0, data.len() / 2);
564 let va = &mut self.vas[va.0];
565 va.bufs.push((attr, Vert::Buf2(id)));
566 id
567 }
568 fn vertex_buffer3(&mut self, va: turbine_scene3d::VertexArray, attr: u32, data: &[f32]) -> VertexBuffer3 {
569 let id = VertexBuffer3(self.vertex_buffers.len(), data.len() / 3);
570 self.vertex_buffers.push(self.device.create_buffer_init(
571 &wgpu::util::BufferInitDescriptor {
572 label: Some("VertexBuffer3"),
573 contents: bytemuck::cast_slice(data),
574 usage: wgpu::BufferUsages::VERTEX,
575 }
576 ));
577 let va = &mut self.vas[va.0];
578 va.bufs.push((attr, Vert::Buf3(id)));
579 id
580 }
581 fn color_buffer(&mut self, va: turbine_scene3d::VertexArray, attr: u32, data: &[f32]) -> ColorBuffer {
582 let id = ColorBuffer(self.vertex_buffers.len(), data.len() / 4);
583 self.vertex_buffers.push(self.device.create_buffer_init(
584 &wgpu::util::BufferInitDescriptor {
585 label: Some("ColorBuffer"),
586 contents: bytemuck::cast_slice(data),
587 usage: wgpu::BufferUsages::VERTEX,
588 }
589 ));
590 let va = &mut self.vas[va.0];
591 va.bufs.push((attr, Vert::Col(id)));
592 id
593 }
594 fn vertex_array(&mut self) -> turbine_scene3d::VertexArray {
595 let id = self.vas.len();
596 self.vas.push(Va::new());
597 VertexArray(id)
598 }
599 fn matrix4_uniform(&mut self, program: Program, _: &str) -> Result<Matrix4Uniform, String> {
600 let id = Matrix4Uniform(self.matrix4_uniforms.len());
601
602 let binding = self.programs[program.0].uniforms.len();
603
604 let uniform = vecmath::mat4_id();
605 let uniform_buffer = utils::matrix4_uniform_buffer(uniform, &self.device);
606 self.programs[program.0].uniform_bind_group_layout_entries.push(
607 wgpu::BindGroupLayoutEntry {
608 binding: binding as u32,
609 count: None,
610 visibility: wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT,
611 ty: wgpu::BindingType::Buffer {
612 ty: wgpu::BufferBindingType::Uniform,
613 has_dynamic_offset: false,
614 min_binding_size: None,
615 },
616 }
617 );
618
619 self.matrix4_uniforms.push(uniform);
620 self.matrix4_uniform_buffers.push(uniform_buffer);
621
622 self.programs[program.0].uniforms.push(Uni::Matrix4(id));
623 Ok(id)
624 }
625 fn program_from_vertex_fragment(&mut self, vs: VertexShader, fs: FragmentShader) -> turbine_scene3d::Program {
626 let id = self.programs.len();
627 self.programs.push(Prog::new(vs, fs));
628 Program(id)
629 }
630 fn f32_uniform(&mut self, program: Program, _: &str) -> Result<F32Uniform, String> {
631 let id = F32Uniform(self.f32_uniforms.len());
632
633 let binding = self.programs[program.0].uniforms.len();
634
635 let uniform = 0.0;
636 let uniform_buffer = utils::f32_uniform_buffer(uniform, &self.device);
637 self.programs[program.0].uniform_bind_group_layout_entries.push(
638 wgpu::BindGroupLayoutEntry {
639 binding: binding as u32,
640 count: None,
641 visibility: wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT,
642 ty: wgpu::BindingType::Buffer {
643 ty: wgpu::BufferBindingType::Uniform,
644 has_dynamic_offset: false,
645 min_binding_size: None,
646 },
647 }
648 );
649
650 self.f32_uniforms.push(uniform);
651 self.f32_uniform_buffers.push(uniform_buffer);
652
653 self.programs[program.0].uniforms.push(Uni::F32(id));
654 Ok(id)
655 }
656 fn vector2_uniform(&mut self, program: Program, _: &str) -> Result<Vector2Uniform, String> {
657 let id = Vector2Uniform(self.vector2_uniforms.len());
658
659 let binding = self.programs[program.0].uniforms.len();
660
661 let uniform = [0.0; 2];
662 let uniform_buffer = utils::vector2_uniform_buffer(uniform, &self.device);
663 self.programs[program.0].uniform_bind_group_layout_entries.push(
664 wgpu::BindGroupLayoutEntry {
665 binding: binding as u32,
666 count: None,
667 visibility: wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT,
668 ty: wgpu::BindingType::Buffer {
669 ty: wgpu::BufferBindingType::Uniform,
670 has_dynamic_offset: false,
671 min_binding_size: None,
672 },
673 }
674 );
675
676 self.vector2_uniforms.push(uniform);
677 self.vector2_uniform_buffers.push(uniform_buffer);
678
679 self.programs[program.0].uniforms.push(Uni::Vector2(id));
680 Ok(id)
681 }
682 fn vector3_uniform(&mut self, program: Program, _: &str) -> Result<Vector3Uniform, String> {
683 let id = Vector3Uniform(self.vector3_uniforms.len());
684
685 let binding = self.programs[program.0].uniforms.len();
686
687 let uniform = [0.0; 3];
688 let uniform_buffer = utils::vector3_uniform_buffer(uniform, &self.device);
689 self.programs[program.0].uniform_bind_group_layout_entries.push(
690 wgpu::BindGroupLayoutEntry {
691 binding: binding as u32,
692 count: None,
693 visibility: wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT,
694 ty: wgpu::BindingType::Buffer {
695 ty: wgpu::BufferBindingType::Uniform,
696 has_dynamic_offset: false,
697 min_binding_size: None,
698 },
699 }
700 );
701
702 self.vector3_uniforms.push(uniform);
703 self.vector3_uniform_buffers.push(uniform_buffer);
704
705 self.programs[program.0].uniforms.push(Uni::Vector3(id));
706 Ok(id)
707 }
708 fn load_texture<P>(
709 &mut self,
710 path: P,
711 settings: &TextureSettings,
712 ) -> Result<Texture, <Self as Backend>::ImageError>
713 where P: AsRef<Path>
714 {
715 use texture::{Filter, Wrap};
716
717 let image = match image::open(path)? {
718 image::DynamicImage::ImageRgba8(img) => img,
719 x => x.to_rgba8()
720 };
721 let (width, height) = image.dimensions();
722
723 let texture_size = wgpu::Extent3d {
724 width,
725 height,
726 depth_or_array_layers: 1,
727 };
728
729 let texture = self.device.create_texture(&wgpu::TextureDescriptor {
730 label: Some("Diffuse Texture"),
731 size: texture_size,
732 mip_level_count: 1,
733 sample_count: 1,
734 dimension: wgpu::TextureDimension::D2,
735 format: wgpu::TextureFormat::Rgba8UnormSrgb,
736 usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
737 view_formats: &[wgpu::TextureFormat::Rgba8UnormSrgb],
738 });
739
740 self.queue.write_texture(
741 wgpu::TexelCopyTextureInfoBase {
742 texture: &texture,
743 mip_level: 0,
744 origin: wgpu::Origin3d::ZERO,
745 aspect: wgpu::TextureAspect::All,
746 },
747 &image,
748 wgpu::TexelCopyBufferLayout {
749 offset: 0,
750 bytes_per_row: Some(4 * width),
751 rows_per_image: Some(height),
752 },
753 texture_size,
754 );
755
756 let texture_view = texture.create_view(&wgpu::TextureViewDescriptor {
757 label: Some("Texture View"),
758 ..Default::default()
759 });
760
761 let sampler = self.device.create_sampler(&wgpu::SamplerDescriptor {
762 address_mode_u: match settings.get_wrap_u() {
763 Wrap::ClampToEdge => wgpu::AddressMode::ClampToEdge,
764 Wrap::Repeat => wgpu::AddressMode::Repeat,
765 Wrap::MirroredRepeat => wgpu::AddressMode::MirrorRepeat,
766 Wrap::ClampToBorder => wgpu::AddressMode::ClampToBorder,
767 },
768 address_mode_v: match settings.get_wrap_v() {
769 Wrap::ClampToEdge => wgpu::AddressMode::ClampToEdge,
770 Wrap::Repeat => wgpu::AddressMode::Repeat,
771 Wrap::MirroredRepeat => wgpu::AddressMode::MirrorRepeat,
772 Wrap::ClampToBorder => wgpu::AddressMode::ClampToBorder,
773 },
774 address_mode_w: wgpu::AddressMode::ClampToEdge,
775 mag_filter: match settings.get_mag() {
776 Filter::Linear => wgpu::FilterMode::Linear,
777 Filter::Nearest => wgpu::FilterMode::Nearest,
778 },
779 min_filter: match settings.get_min() {
780 Filter::Linear => wgpu::FilterMode::Linear,
781 Filter::Nearest => wgpu::FilterMode::Nearest,
782 },
783 mipmap_filter: match settings.get_mipmap() {
784 Filter::Linear => wgpu::FilterMode::Linear,
785 Filter::Nearest => wgpu::FilterMode::Nearest,
786 },
787 border_color: if settings.get_border_color() == [0.0; 4] {
788 Some(wgpu::SamplerBorderColor::TransparentBlack)
789 } else if settings.get_border_color() == [0.0, 0.0, 0.0, 1.0] {
790 Some(wgpu::SamplerBorderColor::OpaqueBlack)
791 } else if settings.get_border_color() == [1.0; 4] {
792 Some(wgpu::SamplerBorderColor::OpaqueWhite)
793 } else {
794 None
795 },
796 ..Default::default()
797 });
798
799 let bind_group_layout = utils::texture_bind_group_layout(&self.device);
800
801 let bind_group = self.device.create_bind_group(&wgpu::BindGroupDescriptor {
802 label: Some("Texture Bind Group"),
803 layout: &bind_group_layout,
804 entries: &[
805 wgpu::BindGroupEntry {
806 binding: 0,
807 resource: wgpu::BindingResource::TextureView(&texture_view),
808 },
809 wgpu::BindGroupEntry {
810 binding: 1,
811 resource: wgpu::BindingResource::Sampler(&sampler),
812 },
813 ],
814 });
815
816 let id = self.textures.len();
817 self.textures.push((
818 texture,
819 bind_group_layout,
820 bind_group,
821 width,
822 height,
823 ));
824 Ok(Texture(id))
825 }
826 fn normal_buffer(&mut self, va: VertexArray, attr: u32, data: &[f32]) -> NormalBuffer {
827 let id = NormalBuffer(self.vertex_buffers.len(), data.len() / 4);
828 self.vertex_buffers.push(self.device.create_buffer_init(
829 &wgpu::util::BufferInitDescriptor {
830 label: Some("NormalBuffer"),
831 contents: bytemuck::cast_slice(data),
832 usage: wgpu::BufferUsages::VERTEX,
833 }
834 ));
835 let va = &mut self.vas[va.0];
836 va.bufs.push((attr, Vert::Nor(id)));
837 id
838 }
839 fn uv_buffer(&mut self, va: VertexArray, attr: u32, data: &[f32]) -> UVBuffer {
840 let id = UVBuffer(self.vertex_buffers.len(), data.len() / 4);
841 self.vertex_buffers.push(self.device.create_buffer_init(
842 &wgpu::util::BufferInitDescriptor {
843 label: Some("UVBuffer"),
844 contents: bytemuck::cast_slice(data),
845 usage: wgpu::BufferUsages::VERTEX,
846 }
847 ));
848 let va = &mut self.vas[va.0];
849 va.bufs.push((attr, Vert::UV(id)));
850 id
851 }
852}
853
854impl State {
855 pub fn begin_render_pass(&mut self) {
857 let surface_texture = self.surface_texture.as_ref().unwrap();
858 let surface_view = surface_texture
859 .texture
860 .create_view(&wgpu::TextureViewDescriptor::default());
861 let depth_texture_view = &self.depth_texture_view;
862
863 let mut encoder = self.device.create_command_encoder(
864 &wgpu::CommandEncoderDescriptor {
865 label: None,
866 }
867 );
868
869 let rpass_color_attachment = wgpu::RenderPassColorAttachment {
870 view: &surface_view,
871 resolve_target: None,
872 ops: wgpu::Operations {
873 load: wgpu::LoadOp::Load,
874 store: wgpu::StoreOp::Store,
875 },
876 depth_slice: None,
877 };
878 let render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
879 label: Some("Render Pass"),
880 color_attachments: &[Some(rpass_color_attachment)],
881 depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
882 view: &depth_texture_view,
883 depth_ops: Some(wgpu::Operations {
884 load: wgpu::LoadOp::Load,
885 store: wgpu::StoreOp::Store,
886 }),
887 stencil_ops: None,
888 }),
889 occlusion_query_set: None,
890 timestamp_writes: None,
891 }).forget_lifetime();
892
893 self.encoder = Some(encoder);
894 self.render_pass = Some(render_pass);
895 }
896
897 pub fn end_render_pass(&mut self) {
899 self.render_pass = None;
900 if let Some(encoder) = std::mem::replace(&mut self.encoder, None) {
901 self.queue.submit(Some(encoder.finish()));
902 }
903 }
904}