e2/
sprite.rs

1use crate::*;
2use std::borrow::Cow;
3
4/// This is a version of [MeshRenderer] that is designed for rendering sprites (textured or colored rectangles).
5#[derive(Debug)]
6pub struct SpriteRenderer {
7    renderer: MeshRenderer,
8    rect: Mesh,
9    white: Texture,
10    matrix: glam::Mat4,
11}
12
13impl SpriteRenderer {
14    /// Creates a new [SpriteRenderer].
15    ///
16    /// See [MeshRenderer::new].
17    pub fn new(cx: &Context, pipeline: &MeshRenderPipeline) -> Self {
18        let renderer = MeshRenderer::new(cx, pipeline);
19
20        let rect = Mesh::new(
21            &cx,
22            &[
23                Vertex {
24                    pos: [0., 0.],
25                    uv: [0., 0.],
26                },
27                Vertex {
28                    pos: [1., 0.],
29                    uv: [1., 0.],
30                },
31                Vertex {
32                    pos: [0., 1.],
33                    uv: [0., 1.],
34                },
35                Vertex {
36                    pos: [1., 1.],
37                    uv: [1., 1.],
38                },
39            ],
40            &[0, 2, 1, 2, 3, 1],
41        );
42
43        let white = ImageTexture {
44            format: wgpu::TextureFormat::Rgba8UnormSrgb,
45            pixels: Cow::Borrowed(&[255, 255, 255, 255]),
46            width: 1,
47            height: 1,
48        }
49        .create(&cx);
50
51        SpriteRenderer {
52            renderer,
53            rect,
54            white,
55            matrix: glam::Mat4::IDENTITY,
56        }
57    }
58
59    /// Resets the previously allocated buffers, making them available for reuse.
60    ///
61    /// Call this at the start or end of every frame in order to maintain acceptable spatial performance.
62    pub fn free(&mut self) {
63        self.renderer.free();
64    }
65
66    /// Binds a sampler for use with the proceeding draw calls.
67    pub fn bind_sampler<'a>(
68        &mut self,
69        cx: &Context,
70        pass: &'a mut wgpu::RenderPass,
71        sampler: &Sampler,
72    ) {
73        self.renderer.bind_sampler(cx, pass, sampler);
74    }
75
76    /// Sets the matrix that is premultiplied against the sprite transformation matrices.
77    pub fn set_matrix(&mut self, matrix: glam::Mat4) {
78        self.matrix = matrix;
79    }
80
81    /// Draws a sprite at `rect` with a given `content` and `rotation`.
82    ///
83    /// Rotation is in radians.
84    pub fn draw<'a>(
85        &mut self,
86        cx: &Context,
87        pass: &mut ArenaRenderPass,
88        content: impl Into<SpriteContent<'a>>,
89        rect: Rect,
90        rotation: f32,
91    ) {
92        let (texture, src_rect, color) = match content.into() {
93            SpriteContent::Textured { texture, src_rect } => (texture, src_rect, Color::WHITE),
94            SpriteContent::Color(color) => (&self.white, Rect::ONE, color),
95        };
96
97        self.renderer.draw(
98            cx,
99            pass,
100            MeshDraw {
101                mesh: &self.rect,
102                texture,
103                color,
104                src_rect,
105                transform: glam::Mat4::from_scale_rotation_translation(
106                    glam::vec3(rect.size.x, rect.size.y, 1.),
107                    glam::Quat::from_rotation_z(rotation),
108                    glam::vec3(rect.origin.x, rect.origin.y, 0.),
109                ),
110            },
111        );
112    }
113}
114
115impl Slot3MeshRenderer for SpriteRenderer {
116    #[inline]
117    fn bind(&mut self, uniform: u32, texture: u32, sampler: u32) {
118        self.renderer.bind(uniform, texture, sampler);
119    }
120}
121
122/// The visual contents (texture or color) of a sprite.
123pub enum SpriteContent<'a> {
124    /// The sprite is textured.
125    Textured {
126        /// Texture to sample.
127        texture: &'a Texture,
128        /// UV sub-rectangle to use.
129        /// Using [Rect::ONE] will mean that the full UV space is available.
130        src_rect: Rect,
131    },
132    /// The sprite has a solid color.
133    Color(Color),
134}
135
136impl<'a> From<&'a Texture> for SpriteContent<'a> {
137    fn from(texture: &'a Texture) -> Self {
138        SpriteContent::Textured {
139            texture,
140            src_rect: Rect::ONE,
141        }
142    }
143}
144
145impl<'a> From<(&'a Texture, Rect)> for SpriteContent<'a> {
146    fn from((texture, src_rect): (&'a Texture, Rect)) -> Self {
147        SpriteContent::Textured { texture, src_rect }
148    }
149}
150
151impl<'a> From<Color> for SpriteContent<'a> {
152    fn from(color: Color) -> Self {
153        SpriteContent::Color(color)
154    }
155}