fyrox_impl/renderer/
debug_renderer.rs

1// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and associated documentation files (the "Software"), to deal
5// in the Software without restriction, including without limitation the rights
6// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7// copies of the Software, and to permit persons to whom the Software is
8// furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in all
11// copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19// SOFTWARE.
20
21//! Debug renderer allows you to create debug geometry (wireframe) on the fly. As it said
22//! in its name its purpose - output debug information. It can be used to render collision
23//! shapes, contact information (normals, positions, etc.), paths build by navmesh and so
24//! on. It contains implementations to draw most common shapes (line, box, oob, frustum, etc).
25
26use 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
62/// See module docs.
63pub 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
75/// "Draws" a rectangle into a list of lines.
76pub 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    /// Uploads the new set of lines to GPU.
140    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}