bottomless_pit/
material.rs

1//! Contains the Material and MaterialBuilder struct which are needed
2//! for anything to be rendered
3//! ```rust,no_run
4//! // Simple code to draw a 100x100 red rectangle to the screen
5//! let defualt_material: Material<()> = MaterialBuilder::new().build();
6//!
7//! impl Game for Struct {
8//!     fn render<'pass, 'others>(&mut Self, mut renderer: RenderInformation<'pass, 'others>) where 'others: 'pass {
9//!         self.defualt_material.add_rectangle(Vec2{x: 0.0, y: 0.0}, Vec2{x: 100.0, y: 100.0}, Colour::RED, &renderer);
10//!         self.default_material.draw(&mut renderer);
11//!     }
12//! }
13use std::f32::consts::PI;
14use std::marker::PhantomData;
15
16use encase::private::WriteInto;
17use encase::ShaderType;
18
19use crate::colour::Colour;
20use crate::context::WgpuClump;
21use crate::engine_handle::Engine;
22use crate::matrix_math::normalize_points;
23use crate::render::Renderer;
24use crate::resource::ResourceId;
25use crate::shader::{Shader, UniformData, UniformError};
26use crate::texture::{Texture, UniformTexture};
27use crate::vectors::Vec2;
28use crate::vertex::{self, LineVertex, Vertex};
29
30/// A material represents a unique combination of a Texture
31/// and Shader, while also containing all nessicary buffers.
32/// If you don't have any uniform data attached to the shader
33/// utilized by the material use the unit `()` type.
34#[derive(Debug)]
35pub struct Material<T = ()> {
36    pipeline_id: ResourceId<Shader>,
37    /// counts the bytes of vertex not the actual number
38    pub(crate) vertex_size: u64,
39    pub(crate) vertex_count: u64,
40    /// counts the bytes of the index not the actual number
41    pub(crate) index_count: u64,
42    pub(crate) index_size: u64,
43    inner: Option<InnerBuffer>,
44    texture_id: ResourceId<Texture>,
45    _marker: PhantomData<T>,
46}
47
48impl<T> Material<T> {
49    /// Takes a MaterialBuilder and turns it into a Material
50    fn from_builder(builder: MaterialBuilder<T>, engine: &mut Engine) -> Self {
51        let pipeline_id = match builder.shader_change {
52            Some(rs) => rs,
53            None => engine.defualt_pipe_id(),
54        };
55
56        let texture_id = builder
57            .texture_change
58            .unwrap_or(engine.defualt_material_bg_id());
59
60        let vertex_size = std::mem::size_of::<Vertex>() as u64;
61        let index_size = std::mem::size_of::<u16>() as u64;
62
63        Self {
64            pipeline_id,
65            vertex_count: 0,
66            vertex_size,
67            index_count: 0,
68            index_size,
69            inner: None,
70            texture_id,
71            _marker: PhantomData,
72        }
73    }
74
75    /// Swaps out the inner texture of the material
76    pub fn change_texture(&mut self, texture: ResourceId<Texture>) {
77        self.texture_id = texture
78    }
79
80    /// Will queue a Rectangle to be draw.
81    pub fn add_rectangle(
82        &mut self,
83        position: Vec2<f32>,
84        size: Vec2<f32>,
85        colour: Colour,
86        render: &Renderer,
87    ) {
88        let wgpu = render.wgpu;
89        let verts = vertex::from_pixels(position, size, colour.as_raw());
90
91        self.push_rectangle(wgpu, verts);
92    }
93
94    /// Queues a rectangle using WGSL cordinate space. (0, 0) is the center of the screen and (-1, 1) is the top left corner
95    pub fn add_screenspace_rectangle(
96        &mut self,
97        position: Vec2<f32>,
98        size: Vec2<f32>,
99        colour: Colour,
100        render: &Renderer,
101    ) {
102        let wgpu = render.wgpu;
103        let screen_size = render.size;
104
105        let verts = vertex::new(position, size, colour.as_raw(), screen_size);
106        self.push_rectangle(wgpu, verts);
107    }
108
109    /// Queues a rectagnle with UV coordniates. The position and size of the UV cordniates are the same as the pixels in the
110    /// actaul image.
111    pub fn add_rectangle_with_uv(
112        &mut self,
113        position: Vec2<f32>,
114        size: Vec2<f32>,
115        uv_position: Vec2<f32>,
116        uv_size: Vec2<f32>,
117        colour: Colour,
118        render: &Renderer,
119    ) {
120        let wgpu = render.wgpu;
121
122        let texture_size = render
123            .resources
124            .get_texture(&self.texture_id)
125            .map(|t| t.size)
126            .unwrap_or(Vec2 { x: 1.0, y: 1.0 });
127        // doesnt matter what i put here bc the texture isnt loaded regardless
128
129        let uv_size = normalize_points(uv_size, texture_size);
130        let uv_position = normalize_points(uv_position, texture_size);
131
132        let verts =
133            vertex::from_pixels_with_uv(position, size, colour.as_raw(), uv_position, uv_size);
134
135        self.push_rectangle(wgpu, verts);
136    }
137
138    /// Queues a rectangle that will be rotated around its centerpoint. Rotation is in degrees
139    pub fn add_rectangle_with_rotation(
140        &mut self,
141        position: Vec2<f32>,
142        size: Vec2<f32>,
143        colour: Colour,
144        rotation: f32,
145        render: &Renderer,
146    ) {
147        let wgpu = render.wgpu;
148
149        let verts = vertex::from_pixels_with_rotation(position, size, colour.as_raw(), rotation);
150
151        self.push_rectangle(wgpu, verts);
152    }
153
154    #[allow(clippy::too_many_arguments)]
155    /// Queues a rectangle with both UV, and Rotation,
156    pub fn add_rectangle_ex(
157        &mut self,
158        position: Vec2<f32>,
159        size: Vec2<f32>,
160        colour: Colour,
161        rotation: f32,
162        uv_position: Vec2<f32>,
163        uv_size: Vec2<f32>,
164        render: &Renderer,
165    ) {
166        let wgpu = render.wgpu;
167
168        let texture_size = render.resources.get_texture(&self.texture_id).unwrap().size;
169
170        let uv_size = normalize_points(uv_size, texture_size);
171        let uv_position = normalize_points(uv_position, texture_size);
172
173        let verts = vertex::from_pixels_ex(
174            position,
175            size,
176            colour.as_raw(),
177            rotation,
178            uv_position,
179            uv_size,
180        );
181
182        self.push_rectangle(wgpu, verts);
183    }
184
185    #[allow(clippy::too_many_arguments)]
186    /// Queues a rectangle with both UV, and Rotation, but will draw the rectangle in WGSL screenspace
187    pub fn add_screenspace_rectangle_ex(
188        &mut self,
189        position: Vec2<f32>,
190        size: Vec2<f32>,
191        colour: Colour,
192        rotation: f32,
193        uv_position: Vec2<f32>,
194        uv_size: Vec2<f32>,
195        render: &Renderer,
196    ) {
197        let wgpu = render.wgpu;
198
199        let verts = vertex::new_ex(
200            position,
201            size,
202            colour.as_raw(),
203            rotation,
204            uv_position,
205            uv_size,
206        );
207
208        self.push_rectangle(wgpu, verts);
209    }
210
211    /// Queues a 4 pointed polygon with complete control over uv coordinates and rotation. The points need to be in top left, right
212    /// bottom right and bottom left order as it will not render porperly otherwise.
213    pub fn add_custom(
214        &mut self,
215        points: [Vec2<f32>; 4],
216        uv_points: [Vec2<f32>; 4],
217        rotation: f32,
218        colour: Colour,
219        render: &Renderer,
220    ) {
221        let wgpu = render.wgpu;
222        let texture_size = render.resources.get_texture(&self.texture_id).unwrap().size;
223        let uv_points = [
224            normalize_points(uv_points[0], texture_size),
225            normalize_points(uv_points[1], texture_size),
226            normalize_points(uv_points[2], texture_size),
227            normalize_points(uv_points[3], texture_size),
228        ];
229
230        let verts = vertex::from_pixels_custom(points, uv_points, rotation, colour.as_raw());
231
232        self.push_rectangle(wgpu, verts);
233    }
234
235    /// Queues a traingle, the points must be provided in clockwise order
236    pub fn add_triangle(
237        &mut self,
238        p1: Vec2<f32>,
239        p2: Vec2<f32>,
240        p3: Vec2<f32>,
241        colour: Colour,
242        render: &Renderer,
243    ) {
244        let wgpu = render.wgpu;
245
246        let colour = colour.as_raw();
247        let tex_coords = [0.0, 0.0];
248
249        let verts = [
250            Vertex::from_2d([p1.x, p1.y], tex_coords, colour),
251            Vertex::from_2d([p2.x, p2.y], tex_coords, colour),
252            Vertex::from_2d([p3.x, p3.y], tex_coords, colour),
253        ];
254
255        self.push_triangle(wgpu, verts);
256    }
257
258    /// Queues a triangle where each vertex is given its own colour. Points must be given
259    /// in clockwise order
260    pub fn add_triangle_with_coloured_verticies(
261        &mut self,
262        points: [Vec2<f32>; 3],
263        colours: [Colour; 3],
264        render: &Renderer,
265    ) {
266        let wgpu = render.wgpu;
267
268        let tex_coords = [0.0, 0.0];
269        let verts = [
270            Vertex::from_2d([points[0].x, points[0].y], tex_coords, colours[0].as_raw()),
271            Vertex::from_2d([points[1].x, points[1].y], tex_coords, colours[1].as_raw()),
272            Vertex::from_2d([points[2].x, points[2].y], tex_coords, colours[2].as_raw()),
273        ];
274
275        self.push_triangle(wgpu, verts);
276    }
277
278    /// Queues a polygon with the specified number of sides at a position with size and colour.
279    /// This will not play nicely with texture as all the UV coords will be at [0, 0].
280    pub fn add_regular_n_gon(
281        &mut self,
282        number_of_sides: usize,
283        radius: f32,
284        center: Vec2<f32>,
285        colour: Colour,
286        render: &Renderer,
287    ) {
288        if number_of_sides < 4 {
289            return;
290        }
291
292        if self.inner.is_none() {
293            let (vert, ind) = Self::create_buffers(
294                &render.wgpu.device,
295                self.vertex_size,
296                50,
297                self.index_size,
298                50,
299            );
300
301            self.inner = Some(InnerBuffer {
302                vertex_buffer: vert,
303                index_buffer: ind,
304            });
305        }
306
307        let wgpu = render.wgpu;
308
309        let vertices = (0..number_of_sides)
310            .map(|num| Vec2 {
311                x: radius * (2.0 * PI * num as f32 / number_of_sides as f32).cos() + center.x,
312                y: radius * (2.0 * PI * num as f32 / number_of_sides as f32).sin() + center.y,
313            })
314            .map(|point| Vertex::from_2d([point.x, point.y], [0.0, 0.0], colour.as_raw()))
315            .collect::<Vec<Vertex>>();
316
317        let number_of_vertices = self.get_vertex_number() as u16;
318        let number_of_triangles = (number_of_sides - 2) as u16;
319
320        let mut indicies = (1..number_of_triangles + 1)
321            .flat_map(|i| {
322                [
323                    number_of_vertices,
324                    i + number_of_vertices,
325                    i + 1 + number_of_vertices,
326                ]
327            })
328            .collect::<Vec<u16>>();
329
330        // ensures we follow copy buffer alignment
331        let num_indicies = indicies.len();
332        let triangles_to_add = if num_indicies < 12 {
333            (12 % num_indicies) / 3
334        } else {
335            (num_indicies % 12) / 3
336        };
337
338        for _ in 0..triangles_to_add {
339            indicies.extend_from_slice(&[
340                indicies[num_indicies - 3],
341                indicies[num_indicies - 2],
342                indicies[num_indicies - 1],
343            ]);
344        }
345
346        let buffers = self.inner.as_mut().unwrap();
347
348        let max_verts = buffers.vertex_buffer.size();
349        if self.vertex_count + (vertices.len() as u64 * self.vertex_size) > max_verts {
350            grow_buffer(
351                &mut buffers.vertex_buffer,
352                wgpu,
353                self.vertex_count + (vertices.len() as u64 * self.vertex_size),
354                wgpu::BufferUsages::VERTEX,
355            );
356        }
357
358        let max_indicies = buffers.index_buffer.size();
359        if self.index_count + (indicies.len() as u64 * self.index_size) > max_indicies {
360            grow_buffer(
361                &mut buffers.index_buffer,
362                wgpu,
363                self.index_count + (indicies.len() as u64 * self.index_size),
364                wgpu::BufferUsages::INDEX,
365            );
366        }
367
368        wgpu.queue.write_buffer(
369            &buffers.vertex_buffer,
370            self.vertex_count,
371            bytemuck::cast_slice(&vertices),
372        );
373        wgpu.queue.write_buffer(
374            &buffers.index_buffer,
375            self.index_count,
376            bytemuck::cast_slice(&indicies),
377        );
378
379        self.vertex_count += vertices.len() as u64 * self.vertex_size;
380        self.index_count += indicies.len() as u64 * self.index_size;
381    }
382
383    /// This will attempt to resize the texture stored within the shader.
384    /// This will fail in the event that the shader has not loaded yet or
385    /// if the shader used to create the material never had an UniformTexture.
386    pub fn resize_uniform_texture(
387        &mut self,
388        texture: &mut UniformTexture,
389        size: Vec2<u32>,
390        engine: &mut Engine,
391    ) -> Result<(), UniformError> {
392        let context = match &engine.context {
393            Some(c) => c,
394            None => return Ok(()),
395            // the context hasnt been created yet this also means there
396            // is no reason for you to resize unless ur being silly for no
397            // reason
398        };
399
400        let texture_format = context.get_texture_format();
401
402        let options = match engine.resource_manager.get_mut_shader(&self.pipeline_id) {
403            Some(shader) => shader,
404            None => Err(UniformError::NotLoadedYet)?,
405        };
406
407        texture.resize(size, &context.wgpu, texture_format);
408
409        options.update_uniform_texture(texture, &context.wgpu, texture_format)?;
410
411        Ok(())
412    }
413
414    pub fn update_uniform_texture(
415        &mut self,
416        texture: &mut UniformTexture,
417        engine: &mut Engine,
418    ) -> Result<(), UniformError> {
419        let context = match &engine.context {
420            Some(c) => c,
421            None => return Ok(()),
422            // the context hasnt been created yet this also means there
423            // is no reason for you to resize unless ur being silly for no
424            // reason
425        };
426
427        let texture_format = context.get_texture_format();
428
429        let options = match engine.resource_manager.get_mut_shader(&self.pipeline_id) {
430            Some(shader) => shader,
431            None => Err(UniformError::NotLoadedYet)?,
432        };
433
434        options.update_uniform_texture(texture, &context.wgpu, texture_format)?;
435
436        Ok(())
437    }
438
439    /// Returns the number of verticies in the buffer
440    pub fn get_vertex_number(&self) -> u64 {
441        self.vertex_count / self.vertex_size
442    }
443
444    /// Returns the number if indincies in the buffer
445    pub fn get_index_number(&self) -> u64 {
446        self.index_count / self.index_size
447    }
448
449    /// Returns the size of the texture in pixels.
450    /// Returns None when the texture is not loaded yet
451    pub fn get_texture_size(&self, engine: &Engine) -> Option<Vec2<f32>> {
452        engine
453            .resource_manager
454            .get_texture(&self.texture_id)
455            .map(|t| t.size)
456    }
457
458    fn push_rectangle(&mut self, wgpu: &WgpuClump, verts: [Vertex; 4]) {
459        if self.inner.is_none() {
460            let (vert, ind) =
461                Self::create_buffers(&wgpu.device, self.vertex_size, 50, self.index_size, 50);
462            self.inner = Some(InnerBuffer {
463                vertex_buffer: vert,
464                index_buffer: ind,
465            });
466        }
467
468        let num_verts = self.get_vertex_number() as u16;
469        let buffers = self.inner.as_mut().unwrap();
470
471        let max_verts = buffers.vertex_buffer.size();
472        if self.vertex_count + (4 * self.vertex_size) > max_verts {
473            grow_buffer(
474                &mut buffers.vertex_buffer,
475                wgpu,
476                1,
477                wgpu::BufferUsages::VERTEX,
478            );
479        }
480
481        let indicies = [
482            num_verts,
483            1 + num_verts,
484            2 + num_verts,
485            3 + num_verts,
486            num_verts,
487            2 + num_verts,
488        ];
489
490        let max_indicies = buffers.index_buffer.size();
491        if self.index_count + (6 * self.index_size) > max_indicies {
492            grow_buffer(
493                &mut buffers.index_buffer,
494                wgpu,
495                1,
496                wgpu::BufferUsages::INDEX,
497            );
498        }
499
500        wgpu.queue.write_buffer(
501            &buffers.vertex_buffer,
502            self.vertex_count,
503            bytemuck::cast_slice(&verts),
504        );
505        wgpu.queue.write_buffer(
506            &buffers.index_buffer,
507            self.index_count,
508            bytemuck::cast_slice(&indicies),
509        );
510
511        self.vertex_count += 4 * self.vertex_size;
512        self.index_count += 6 * self.index_size;
513    }
514
515    fn push_triangle(&mut self, wgpu: &WgpuClump, verts: [Vertex; 3]) {
516        if self.inner.is_none() {
517            let (vert, ind) =
518                Self::create_buffers(&wgpu.device, self.vertex_size, 50, self.index_size, 50);
519            self.inner = Some(InnerBuffer {
520                vertex_buffer: vert,
521                index_buffer: ind,
522            });
523        }
524
525        let num_verts = self.get_vertex_number() as u16;
526        let buffers = self.inner.as_mut().unwrap();
527
528        let max_verts = buffers.vertex_buffer.size();
529        if self.vertex_count + (3 * self.vertex_size) > max_verts {
530            grow_buffer(
531                &mut buffers.vertex_buffer,
532                wgpu,
533                1,
534                wgpu::BufferUsages::VERTEX,
535            );
536        }
537
538        // yes its wastefull to do this but this is the only way to not have
539        // it mess up other drawings while also allowing triangles
540        let indicies = [
541            num_verts,
542            1 + num_verts,
543            2 + num_verts,
544            num_verts,
545            1 + num_verts,
546            2 + num_verts,
547        ];
548
549        let max_indicies = buffers.index_buffer.size();
550        if self.index_count + (6 * self.index_size) > max_indicies {
551            grow_buffer(
552                &mut buffers.index_buffer,
553                wgpu,
554                1,
555                wgpu::BufferUsages::INDEX,
556            );
557        }
558
559        wgpu.queue.write_buffer(
560            &buffers.vertex_buffer,
561            self.vertex_count,
562            bytemuck::cast_slice(&verts),
563        );
564        wgpu.queue.write_buffer(
565            &buffers.index_buffer,
566            self.index_count,
567            bytemuck::cast_slice(&indicies),
568        );
569
570        self.vertex_count += 3 * self.vertex_size;
571        self.index_count += 6 * self.index_size;
572    }
573
574    // there where 'others: 'pass notation says that 'others lives longer than 'pass
575    /// Draws all queued shapes to the screen.
576    pub fn draw<'others>(&'others mut self, information: &mut Renderer<'_, 'others>) {
577        if self.vertex_count == 0 {
578            return;
579        }
580
581        // returns early bc stuff inst loaded so we just ignore it ! :3
582        let Some(shader) = information.resources.get_pipeline(&self.pipeline_id) else {
583            return;
584        };
585
586        let Some(texture) = information
587            .resources
588            .get_texture(&self.texture_id)
589            .map(|t| &t.bind_group)
590        else {
591            return;
592        };
593        // should never panic as the vertex == 0 means that there has been
594        // some data put in which means this should be Some(T)
595        let buffers = self.inner.as_ref().unwrap();
596
597        shader.set_active(information);
598
599        information.pass.set_bind_group(0, texture, &[]);
600
601        information
602            .pass
603            .set_vertex_buffer(0, buffers.vertex_buffer.slice(0..self.vertex_count));
604        information.pass.set_index_buffer(
605            buffers.index_buffer.slice(0..self.index_count),
606            wgpu::IndexFormat::Uint16,
607        );
608
609        information
610            .pass
611            .draw_indexed(0..self.get_index_number() as u32, 0, 0..1);
612
613        self.vertex_count = 0;
614        self.index_count = 0;
615    }
616
617    pub(crate) fn create_buffers(
618        device: &wgpu::Device,
619        vertex_size: u64,
620        vert_count: u64,
621        index_size: u64,
622        index_count: u64,
623    ) -> (wgpu::Buffer, wgpu::Buffer) {
624        let vertex_buffer = device.create_buffer(&wgpu::BufferDescriptor {
625            label: Some("Vertex_Buffer"),
626            size: vertex_size * vert_count,
627            usage: wgpu::BufferUsages::VERTEX
628                | wgpu::BufferUsages::COPY_DST
629                | wgpu::BufferUsages::COPY_SRC,
630            mapped_at_creation: false,
631        });
632
633        // this is just 200 bytes pretty small
634        let index_buffer = device.create_buffer(&wgpu::BufferDescriptor {
635            label: Some("Index_Buffer"),
636            size: index_size * index_count,
637            usage: wgpu::BufferUsages::INDEX
638                | wgpu::BufferUsages::COPY_DST
639                | wgpu::BufferUsages::COPY_SRC,
640            mapped_at_creation: false,
641        });
642
643        (vertex_buffer, index_buffer)
644    }
645}
646
647impl<T: ShaderType + WriteInto> Material<T> {
648    /// Attempts to update the uniform data held within in the shader.
649    /// This will fail in the event that the shader has not loaded yet or
650    /// if the shader used to create the material never had any UniformData,
651    pub fn update_uniform_data(&self, data: &T, engine: &Engine) -> Result<(), UniformError> {
652        let options = match engine.resource_manager.get_pipeline(&self.pipeline_id) {
653            Some(shader) => shader,
654            None => return Err(UniformError::NotLoadedYet),
655        };
656
657        options.update_uniform_data(data, engine)?;
658
659        Ok(())
660    }
661}
662
663/// A builder struct used to create Materials
664pub struct MaterialBuilder<T> {
665    // using options to denote a change from the default
666    // in the case of a texture the defualt is just the White_Pixel
667    texture_change: Option<ResourceId<Texture>>,
668    shader_change: Option<ResourceId<Shader>>,
669    _marker: PhantomData<T>,
670}
671
672impl<T> MaterialBuilder<T> {
673    /// Creates a new MaterialBuilder, that contains no texture, custom shaders, or
674    /// uniforms
675    pub fn new() -> Self {
676        Self {
677            texture_change: None,
678            shader_change: None,
679            _marker: PhantomData,
680        }
681    }
682
683    /// Adds a Texture to the Material
684    pub fn add_texture(self, texture: ResourceId<Texture>) -> Self {
685        Self {
686            texture_change: Some(texture),
687            shader_change: self.shader_change,
688            _marker: PhantomData,
689        }
690    }
691
692    /// Sets the shader for the Material
693    pub fn set_shader(self, shader: ResourceId<Shader>) -> Self {
694        Self {
695            texture_change: self.texture_change,
696            shader_change: Some(shader),
697            _marker: PhantomData,
698        }
699    }
700
701    /// This is used to set the type of data used for the materials Uniform ensuring type saftey across the GPU
702    pub fn add_uniform_data<H: ShaderType + WriteInto>(
703        self,
704        _data: &UniformData<H>,
705    ) -> MaterialBuilder<H> {
706        MaterialBuilder {
707            texture_change: self.texture_change,
708            shader_change: self.shader_change,
709            _marker: PhantomData,
710        }
711    }
712
713    /// Turns the builder into a Material
714    pub fn build(self, engine_handle: &mut Engine) -> Material<T> {
715        Material::from_builder(self, engine_handle)
716    }
717}
718
719impl<T> Default for MaterialBuilder<T> {
720    fn default() -> Self {
721        Self::new()
722    }
723}
724
725/// A diffrent type of material used to draw WebGPU debug
726/// lines. These lines will allways be 1px wide and only one
727/// instance of this material should ever be made per programm.
728pub struct LineMaterial {
729    pipe_id: ResourceId<Shader>,
730    vertex_buffer: Option<wgpu::Buffer>,
731    vertex_count: u64,
732    vertex_size: u64,
733}
734
735impl LineMaterial {
736    /// Creates a new LineMaterial
737    pub fn new(engine: &Engine) -> Self {
738        let vertex_size = std::mem::size_of::<LineVertex>() as u64;
739
740        Self {
741            pipe_id: engine.line_pipe_id(),
742            vertex_buffer: None,
743            vertex_count: 0,
744            vertex_size,
745        }
746    }
747
748    /// Queues a line from the two points.
749    pub fn add_line(
750        &mut self,
751        start: Vec2<f32>,
752        end: Vec2<f32>,
753        colour: Colour,
754        renderer: &Renderer,
755    ) {
756        let wgpu = renderer.wgpu;
757        if self.vertex_buffer.is_none() {
758            self.vertex_buffer = Some(wgpu.device.create_buffer(&wgpu::BufferDescriptor {
759                label: Some("Line material vertex buffer"),
760                usage: wgpu::BufferUsages::VERTEX
761                    | wgpu::BufferUsages::COPY_DST
762                    | wgpu::BufferUsages::COPY_SRC,
763                size: self.vertex_size * 100,
764                mapped_at_creation: false,
765            }));
766        }
767
768        let verts = [
769            LineVertex::new(start.to_raw(), colour.as_raw()),
770            LineVertex::new(end.to_raw(), colour.as_raw()),
771        ];
772
773        let vertex_buffer = self.vertex_buffer.as_mut().unwrap();
774
775        let max_verts = vertex_buffer.size();
776        let vert_size = std::mem::size_of::<LineVertex>() as u64;
777        if self.vertex_count + (2 * vert_size) > max_verts {
778            grow_buffer(vertex_buffer, wgpu, 1, wgpu::BufferUsages::VERTEX);
779        }
780
781        wgpu.queue.write_buffer(
782            vertex_buffer,
783            self.vertex_count,
784            bytemuck::cast_slice(&verts),
785        );
786
787        self.vertex_count += 2 * self.vertex_size;
788    }
789
790    pub fn add_screenspace_line(
791        &mut self,
792        start: Vec2<f32>,
793        end: Vec2<f32>,
794        colour: Colour,
795        renderer: &Renderer,
796    ) {
797        let wgpu = renderer.wgpu;
798        let size = renderer.size;
799
800        if self.vertex_buffer.is_none() {
801            self.vertex_buffer = Some(wgpu.device.create_buffer(&wgpu::BufferDescriptor {
802                label: Some("Line material vertex buffer"),
803                usage: wgpu::BufferUsages::VERTEX
804                    | wgpu::BufferUsages::COPY_DST
805                    | wgpu::BufferUsages::COPY_SRC,
806                size: self.vertex_size * 100,
807                mapped_at_creation: false,
808            }));
809        }
810
811        let verts = [
812            LineVertex::new(start.to_raw(), colour.as_raw()).screenspace_to_pixels(size),
813            LineVertex::new(end.to_raw(), colour.as_raw()).screenspace_to_pixels(size),
814        ];
815
816        let vertex_buffer = self.vertex_buffer.as_mut().unwrap();
817
818        let max_verts = vertex_buffer.size();
819        let vert_size = std::mem::size_of::<LineVertex>() as u64;
820        if self.vertex_count + (2 * vert_size) > max_verts {
821            grow_buffer(vertex_buffer, wgpu, 1, wgpu::BufferUsages::VERTEX);
822        }
823
824        wgpu.queue.write_buffer(
825            vertex_buffer,
826            self.vertex_count,
827            bytemuck::cast_slice(&verts),
828        );
829
830        self.vertex_count += 2 * self.vertex_size;
831    }
832
833    /// Draws all queued lines to the screen.
834    pub fn draw<'others>(&'others mut self, information: &mut Renderer<'_, 'others>) {
835        if self.vertex_count == 0 {
836            return;
837        }
838
839        let Some(pipeline) = information
840            .resources
841            .get_pipeline(&self.pipe_id)
842            .map(|p| &p.pipeline)
843        else {
844            return;
845        };
846
847        let buffer = self.vertex_buffer.as_ref().unwrap();
848
849        information.pass.set_pipeline(pipeline);
850        information
851            .pass
852            .set_bind_group(0, information.camera_bindgroup, &[]);
853        information
854            .pass
855            .set_vertex_buffer(0, buffer.slice(0..self.vertex_count));
856
857        information
858            .pass
859            .draw(0..self.get_vertex_count() as u32, 0..1);
860
861        self.vertex_count = 0;
862    }
863
864    pub fn get_vertex_count(&self) -> u64 {
865        self.vertex_count / self.vertex_size
866    }
867}
868
869pub(crate) fn grow_buffer(
870    buffer: &mut wgpu::Buffer,
871    wgpu: &WgpuClump,
872    size_needed: u64,
873    vert_or_index: wgpu::BufferUsages,
874) {
875    let mut encoder = wgpu
876        .device
877        .create_command_encoder(&wgpu::CommandEncoderDescriptor {
878            label: Some("Material Buffer Grower"),
879        });
880
881    let size_needed = size_needed + (4 - (size_needed % wgpu::COPY_BUFFER_ALIGNMENT));
882
883    let new_size = std::cmp::max(buffer.size() * 2, size_needed);
884    let new_buffer = wgpu.device.create_buffer(&wgpu::BufferDescriptor {
885        label: Some("Vertex_Buffer"),
886        size: new_size,
887        usage: vert_or_index | wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::COPY_SRC,
888        mapped_at_creation: false,
889    });
890
891    encoder.copy_buffer_to_buffer(buffer, 0, &new_buffer, 0, buffer.size());
892
893    wgpu.queue.submit(std::iter::once(encoder.finish()));
894
895    *buffer = new_buffer;
896}
897
898#[derive(Debug)]
899struct InnerBuffer {
900    vertex_buffer: wgpu::Buffer,
901    index_buffer: wgpu::Buffer,
902}