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}