rg3d/renderer/
sprite_renderer.rs

1use crate::{
2    core::{
3        math::{Matrix4Ext, Rect},
4        scope_profile,
5        sstorage::ImmutableString,
6    },
7    renderer::{
8        framework::{
9            error::FrameworkError,
10            framebuffer::{CullFace, DrawParameters, FrameBuffer},
11            geometry_buffer::{GeometryBuffer, GeometryBufferKind},
12            gpu_program::{GpuProgram, UniformLocation},
13            gpu_texture::GpuTexture,
14            state::{BlendFactor, BlendFunc, PipelineState},
15        },
16        RenderPassStatistics, TextureCache,
17    },
18    scene::{camera::Camera, graph::Graph, mesh::surface::SurfaceData, node::Node},
19};
20use std::{cell::RefCell, rc::Rc};
21
22struct SpriteShader {
23    program: GpuProgram,
24    view_projection_matrix: UniformLocation,
25    world_matrix: UniformLocation,
26    camera_side_vector: UniformLocation,
27    camera_up_vector: UniformLocation,
28    color: UniformLocation,
29    diffuse_texture: UniformLocation,
30    size: UniformLocation,
31    rotation: UniformLocation,
32}
33
34impl SpriteShader {
35    pub fn new(state: &mut PipelineState) -> Result<Self, FrameworkError> {
36        let fragment_source = include_str!("shaders/sprite_fs.glsl");
37        let vertex_source = include_str!("shaders/sprite_vs.glsl");
38        let program =
39            GpuProgram::from_source(state, "SpriteShader", vertex_source, fragment_source)?;
40        Ok(Self {
41            view_projection_matrix: program
42                .uniform_location(state, &ImmutableString::new("viewProjectionMatrix"))?,
43            world_matrix: program.uniform_location(state, &ImmutableString::new("worldMatrix"))?,
44            camera_side_vector: program
45                .uniform_location(state, &ImmutableString::new("cameraSideVector"))?,
46            camera_up_vector: program
47                .uniform_location(state, &ImmutableString::new("cameraUpVector"))?,
48            size: program.uniform_location(state, &ImmutableString::new("size"))?,
49            diffuse_texture: program
50                .uniform_location(state, &ImmutableString::new("diffuseTexture"))?,
51            color: program.uniform_location(state, &ImmutableString::new("color"))?,
52            rotation: program.uniform_location(state, &ImmutableString::new("rotation"))?,
53            program,
54        })
55    }
56}
57
58pub struct SpriteRenderer {
59    shader: SpriteShader,
60    collapsed_quad: GeometryBuffer,
61}
62
63pub(in crate) struct SpriteRenderContext<'a, 'b, 'c> {
64    pub state: &'a mut PipelineState,
65    pub framebuffer: &'b mut FrameBuffer,
66    pub graph: &'c Graph,
67    pub camera: &'c Camera,
68    pub white_dummy: Rc<RefCell<GpuTexture>>,
69    pub viewport: Rect<i32>,
70    pub textures: &'a mut TextureCache,
71}
72
73impl SpriteRenderer {
74    pub fn new(state: &mut PipelineState) -> Result<Self, FrameworkError> {
75        let surface = GeometryBuffer::from_surface_data(
76            &SurfaceData::make_collapsed_xy_quad(),
77            GeometryBufferKind::StaticDraw,
78            state,
79        );
80
81        Ok(Self {
82            shader: SpriteShader::new(state)?,
83            collapsed_quad: surface,
84        })
85    }
86
87    #[must_use]
88    pub(in crate) fn render(&mut self, args: SpriteRenderContext) -> RenderPassStatistics {
89        scope_profile!();
90
91        let mut statistics = RenderPassStatistics::default();
92
93        let SpriteRenderContext {
94            state,
95            framebuffer,
96            graph,
97            camera,
98            white_dummy,
99            viewport,
100            textures,
101        } = args;
102
103        let initial_view_projection = camera.view_projection_matrix();
104
105        let inv_view = camera.inv_view_matrix().unwrap();
106
107        let camera_up = inv_view.up();
108        let camera_side = inv_view.side();
109
110        for sprite in graph.linear_iter().filter_map(|node| {
111            if !node.global_visibility() {
112                return None;
113            }
114
115            if let Node::Sprite(sprite) = node {
116                Some(sprite)
117            } else {
118                None
119            }
120        }) {
121            let view_projection = if sprite.depth_offset_factor() != 0.0 {
122                let mut projection = camera.projection_matrix();
123                projection[14] -= sprite.depth_offset_factor();
124                projection * camera.view_matrix()
125            } else {
126                initial_view_projection
127            };
128
129            let diffuse_texture = if let Some(texture) = sprite.texture_ref() {
130                if let Some(texture) = textures.get(state, texture) {
131                    texture
132                } else {
133                    white_dummy.clone()
134                }
135            } else {
136                white_dummy.clone()
137            };
138
139            statistics += framebuffer.draw(
140                &self.collapsed_quad,
141                state,
142                viewport,
143                &self.shader.program,
144                &DrawParameters {
145                    cull_face: Some(CullFace::Back),
146                    color_write: Default::default(),
147                    depth_write: false,
148                    stencil_test: None,
149                    depth_test: true,
150                    blend: Some(BlendFunc {
151                        sfactor: BlendFactor::SrcAlpha,
152                        dfactor: BlendFactor::OneMinusSrcAlpha,
153                    }),
154                    stencil_op: Default::default(),
155                },
156                |mut program_binding| {
157                    program_binding
158                        .set_texture(&self.shader.diffuse_texture, &diffuse_texture)
159                        .set_matrix4(&self.shader.view_projection_matrix, &view_projection)
160                        .set_matrix4(&self.shader.world_matrix, &sprite.global_transform())
161                        .set_vector3(&self.shader.camera_up_vector, &camera_up)
162                        .set_vector3(&self.shader.camera_side_vector, &camera_side)
163                        .set_f32(&self.shader.size, sprite.size())
164                        .set_linear_color(&self.shader.color, &sprite.color())
165                        .set_f32(&self.shader.rotation, sprite.rotation());
166                },
167            );
168        }
169
170        statistics
171    }
172}