turbine_scene3d_wgpu/
lib.rs

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/// A render pipeline configuration.
47#[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
186/// Stores the state of the WGPU backend.
187pub struct State {
188    /// The surface texture used for rendering.
189    ///
190    /// This is set to `None` when not rendering.
191    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    /// Whether to enable culling of faces.
215    pub cull_face: bool,
216    /// Whether to cull front faces.
217    pub cull_face_front: bool,
218    /// Whether to cull back faces.
219    pub cull_face_back: bool,
220    /// Whether blend is enabled.
221    pub enable_blend: bool,
222    /// The blend operation, if active.
223    pub blend_op: wgpu::BlendState,
224}
225
226impl State {
227    /// Creates a new state.
228    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    /// Start rendering.
267    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    /// End rendering.
273    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        // This is not supported in the WGPU backend.
407    }
408    fn disable_framebuffer_srgb(&mut self) {
409        // This is not supported in the WGPU backend.
410    }
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    /// Start a new render pass.
856    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    /// End current render pass.
898    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}