1use crate::{
27 core::color::Color,
28 core::{
29 algebra::{Matrix4, Vector3},
30 math::Rect,
31 sstorage::ImmutableString,
32 },
33 renderer::{
34 cache::uniform::UniformBufferCache,
35 framework::{
36 buffer::BufferUsage,
37 error::FrameworkError,
38 framebuffer::{FrameBuffer, ResourceBindGroup, ResourceBinding},
39 geometry_buffer::{
40 AttributeDefinition, AttributeKind, GeometryBuffer, GeometryBufferDescriptor,
41 VertexBufferData, VertexBufferDescriptor,
42 },
43 gpu_program::GpuProgram,
44 server::GraphicsServer,
45 uniform::StaticUniformBuffer,
46 CompareFunc, DrawParameters, ElementRange,
47 },
48 RenderPassStatistics,
49 },
50 scene::debug::Line,
51};
52use bytemuck::{Pod, Zeroable};
53use fyrox_graphics::{framebuffer::BufferLocation, geometry_buffer::ElementsDescriptor};
54
55#[repr(C)]
56#[derive(Copy, Pod, Zeroable, Clone)]
57struct Vertex {
58 position: Vector3<f32>,
59 color: u32,
60}
61
62pub struct DebugRenderer {
64 geometry: Box<dyn GeometryBuffer>,
65 vertices: Vec<Vertex>,
66 line_indices: Vec<[u32; 2]>,
67 shader: DebugShader,
68}
69
70pub(crate) struct DebugShader {
71 program: Box<dyn GpuProgram>,
72 pub uniform_buffer_binding: usize,
73}
74
75pub fn draw_rect(rect: &Rect<f32>, lines: &mut Vec<Line>, color: Color) {
77 for (a, b) in [
78 (rect.left_top_corner(), rect.right_top_corner()),
79 (rect.right_top_corner(), rect.right_bottom_corner()),
80 (rect.right_bottom_corner(), rect.left_bottom_corner()),
81 (rect.left_bottom_corner(), rect.left_top_corner()),
82 ] {
83 lines.push(Line {
84 begin: a.to_homogeneous(),
85 end: b.to_homogeneous(),
86 color,
87 });
88 }
89}
90
91impl DebugShader {
92 fn new(server: &dyn GraphicsServer) -> Result<Self, FrameworkError> {
93 let fragment_source = include_str!("shaders/debug_fs.glsl");
94 let vertex_source = include_str!("shaders/debug_vs.glsl");
95 let program = server.create_program("DebugShader", vertex_source, fragment_source)?;
96 Ok(Self {
97 uniform_buffer_binding: program
98 .uniform_block_index(&ImmutableString::new("Uniforms"))?,
99 program,
100 })
101 }
102}
103
104impl DebugRenderer {
105 pub(crate) fn new(server: &dyn GraphicsServer) -> Result<Self, FrameworkError> {
106 let desc = GeometryBufferDescriptor {
107 elements: ElementsDescriptor::Lines(&[]),
108 buffers: &[VertexBufferDescriptor {
109 usage: BufferUsage::DynamicDraw,
110 attributes: &[
111 AttributeDefinition {
112 location: 0,
113 divisor: 0,
114 kind: AttributeKind::Float,
115 component_count: 3,
116 normalized: false,
117 },
118 AttributeDefinition {
119 location: 1,
120 kind: AttributeKind::UnsignedByte,
121 component_count: 4,
122 normalized: true,
123 divisor: 0,
124 },
125 ],
126 data: VertexBufferData::new::<Vertex>(None),
127 }],
128 usage: BufferUsage::DynamicDraw,
129 };
130
131 Ok(Self {
132 geometry: server.create_geometry_buffer(desc)?,
133 shader: DebugShader::new(server)?,
134 vertices: Default::default(),
135 line_indices: Default::default(),
136 })
137 }
138
139 pub fn set_lines(&mut self, lines: &[Line]) {
141 self.vertices.clear();
142 self.line_indices.clear();
143
144 let mut i = 0;
145 for line in lines.iter() {
146 let color = line.color.into();
147 self.vertices.push(Vertex {
148 position: line.begin,
149 color,
150 });
151 self.vertices.push(Vertex {
152 position: line.end,
153 color,
154 });
155 self.line_indices.push([i, i + 1]);
156 i += 2;
157 }
158 self.geometry.set_buffer_data_of_type(0, &self.vertices);
159 self.geometry.set_lines(&self.line_indices);
160 }
161
162 pub(crate) fn render(
163 &mut self,
164 uniform_buffer_cache: &mut UniformBufferCache,
165 viewport: Rect<i32>,
166 framebuffer: &mut dyn FrameBuffer,
167 view_projection: Matrix4<f32>,
168 ) -> Result<RenderPassStatistics, FrameworkError> {
169 let mut statistics = RenderPassStatistics::default();
170
171 let uniform_buffer =
172 uniform_buffer_cache.write(StaticUniformBuffer::<256>::new().with(&view_projection))?;
173
174 statistics += framebuffer.draw(
175 &*self.geometry,
176 viewport,
177 &*self.shader.program,
178 &DrawParameters {
179 cull_face: None,
180 color_write: Default::default(),
181 depth_write: false,
182 stencil_test: None,
183 depth_test: Some(CompareFunc::Less),
184 blend: None,
185 stencil_op: Default::default(),
186 scissor_box: None,
187 },
188 &[ResourceBindGroup {
189 bindings: &[ResourceBinding::Buffer {
190 buffer: uniform_buffer,
191 binding: BufferLocation::Auto {
192 shader_location: self.shader.uniform_buffer_binding,
193 },
194 data_usage: Default::default(),
195 }],
196 }],
197 ElementRange::Full,
198 )?;
199
200 statistics.draw_calls += 1;
201
202 Ok(statistics)
203 }
204}