1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 
5 use api::{ColorU, ImageFormat, ImageBufferKind};
6 use api::units::*;
7 use crate::debug_font_data;
8 use crate::device::{Device, Program, Texture, TextureSlot, VertexDescriptor, ShaderError, VAO};
9 use crate::device::{TextureFilter, VertexAttribute, VertexAttributeKind, VertexUsageHint};
10 use euclid::{Point2D, Rect, Size2D, Transform3D, default};
11 use crate::internal_types::Swizzle;
12 use std::f32;
13 
14 #[derive(Debug, Copy, Clone)]
15 enum DebugSampler {
16     Font,
17 }
18 
19 impl Into<TextureSlot> for DebugSampler {
into(self) -> TextureSlot20     fn into(self) -> TextureSlot {
21         match self {
22             DebugSampler::Font => TextureSlot(0),
23         }
24     }
25 }
26 
27 const DESC_FONT: VertexDescriptor = VertexDescriptor {
28     vertex_attributes: &[
29         VertexAttribute {
30             name: "aPosition",
31             count: 2,
32             kind: VertexAttributeKind::F32,
33         },
34         VertexAttribute {
35             name: "aColor",
36             count: 4,
37             kind: VertexAttributeKind::U8Norm,
38         },
39         VertexAttribute {
40             name: "aColorTexCoord",
41             count: 2,
42             kind: VertexAttributeKind::F32,
43         },
44     ],
45     instance_attributes: &[],
46 };
47 
48 const DESC_COLOR: VertexDescriptor = VertexDescriptor {
49     vertex_attributes: &[
50         VertexAttribute {
51             name: "aPosition",
52             count: 2,
53             kind: VertexAttributeKind::F32,
54         },
55         VertexAttribute {
56             name: "aColor",
57             count: 4,
58             kind: VertexAttributeKind::U8Norm,
59         },
60     ],
61     instance_attributes: &[],
62 };
63 
64 #[repr(C)]
65 pub struct DebugFontVertex {
66     pub x: f32,
67     pub y: f32,
68     pub color: ColorU,
69     pub u: f32,
70     pub v: f32,
71 }
72 
73 impl DebugFontVertex {
new(x: f32, y: f32, u: f32, v: f32, color: ColorU) -> DebugFontVertex74     pub fn new(x: f32, y: f32, u: f32, v: f32, color: ColorU) -> DebugFontVertex {
75         DebugFontVertex { x, y, color, u, v }
76     }
77 }
78 
79 #[repr(C)]
80 pub struct DebugColorVertex {
81     pub x: f32,
82     pub y: f32,
83     pub color: ColorU,
84 }
85 
86 impl DebugColorVertex {
new(x: f32, y: f32, color: ColorU) -> DebugColorVertex87     pub fn new(x: f32, y: f32, color: ColorU) -> DebugColorVertex {
88         DebugColorVertex { x, y, color }
89     }
90 }
91 
92 pub struct DebugRenderer {
93     font_vertices: Vec<DebugFontVertex>,
94     font_indices: Vec<u32>,
95     font_program: Program,
96     font_vao: VAO,
97     font_texture: Texture,
98 
99     tri_vertices: Vec<DebugColorVertex>,
100     tri_indices: Vec<u32>,
101     tri_vao: VAO,
102     line_vertices: Vec<DebugColorVertex>,
103     line_vao: VAO,
104     color_program: Program,
105 }
106 
107 impl DebugRenderer {
new(device: &mut Device) -> Result<Self, ShaderError>108     pub fn new(device: &mut Device) -> Result<Self, ShaderError> {
109         let font_program = device.create_program_linked(
110             "debug_font",
111             &[],
112             &DESC_FONT,
113         )?;
114         device.bind_program(&font_program);
115         device.bind_shader_samplers(&font_program, &[("sColor0", DebugSampler::Font)]);
116 
117         let color_program = device.create_program_linked(
118             "debug_color",
119             &[],
120             &DESC_COLOR,
121         )?;
122 
123         let font_vao = device.create_vao(&DESC_FONT, 1);
124         let line_vao = device.create_vao(&DESC_COLOR, 1);
125         let tri_vao = device.create_vao(&DESC_COLOR, 1);
126 
127         let font_texture = device.create_texture(
128             ImageBufferKind::Texture2D,
129             ImageFormat::R8,
130             debug_font_data::BMP_WIDTH,
131             debug_font_data::BMP_HEIGHT,
132             TextureFilter::Linear,
133             None,
134         );
135         device.upload_texture_immediate(
136             &font_texture,
137             &debug_font_data::FONT_BITMAP
138         );
139 
140         Ok(DebugRenderer {
141             font_vertices: Vec::new(),
142             font_indices: Vec::new(),
143             line_vertices: Vec::new(),
144             tri_vao,
145             tri_vertices: Vec::new(),
146             tri_indices: Vec::new(),
147             font_program,
148             color_program,
149             font_vao,
150             line_vao,
151             font_texture,
152         })
153     }
154 
deinit(self, device: &mut Device)155     pub fn deinit(self, device: &mut Device) {
156         device.delete_texture(self.font_texture);
157         device.delete_program(self.font_program);
158         device.delete_program(self.color_program);
159         device.delete_vao(self.tri_vao);
160         device.delete_vao(self.line_vao);
161         device.delete_vao(self.font_vao);
162     }
163 
line_height(&self) -> f32164     pub fn line_height(&self) -> f32 {
165         debug_font_data::FONT_SIZE as f32 * 1.1
166     }
167 
168     /// Draws a line of text at the provided starting coordinates.
169     ///
170     /// If |bounds| is specified, glyphs outside the bounds are discarded.
171     ///
172     /// Y-coordinates is relative to screen top, along with everything else in
173     /// this file.
add_text( &mut self, x: f32, y: f32, text: &str, color: ColorU, bounds: Option<DeviceRect>, ) -> default::Rect<f32>174     pub fn add_text(
175         &mut self,
176         x: f32,
177         y: f32,
178         text: &str,
179         color: ColorU,
180         bounds: Option<DeviceRect>,
181     ) -> default::Rect<f32> {
182         let mut x_start = x;
183         let ipw = 1.0 / debug_font_data::BMP_WIDTH as f32;
184         let iph = 1.0 / debug_font_data::BMP_HEIGHT as f32;
185 
186         let mut min_x = f32::MAX;
187         let mut max_x = -f32::MAX;
188         let mut min_y = f32::MAX;
189         let mut max_y = -f32::MAX;
190 
191         for c in text.chars() {
192             let c = c as usize - debug_font_data::FIRST_GLYPH_INDEX as usize;
193             if c < debug_font_data::GLYPHS.len() {
194                 let glyph = &debug_font_data::GLYPHS[c];
195 
196                 let x0 = (x_start + glyph.xo + 0.5).floor();
197                 let y0 = (y + glyph.yo + 0.5).floor();
198 
199                 let x1 = x0 + glyph.x1 as f32 - glyph.x0 as f32;
200                 let y1 = y0 + glyph.y1 as f32 - glyph.y0 as f32;
201 
202                 // If either corner of the glyph will end up out of bounds, drop it.
203                 if let Some(b) = bounds {
204                     let rect = DeviceRect {
205                         min: DevicePoint::new(x0, y0),
206                         max: DevicePoint::new(x1, y1),
207                     };
208                     if !b.contains_box(&rect) {
209                         continue;
210                     }
211                 }
212 
213                 let s0 = glyph.x0 as f32 * ipw;
214                 let t0 = glyph.y0 as f32 * iph;
215                 let s1 = glyph.x1 as f32 * ipw;
216                 let t1 = glyph.y1 as f32 * iph;
217 
218                 x_start += glyph.xa;
219 
220                 let vertex_count = self.font_vertices.len() as u32;
221 
222                 self.font_vertices
223                     .push(DebugFontVertex::new(x0, y0, s0, t0, color));
224                 self.font_vertices
225                     .push(DebugFontVertex::new(x1, y0, s1, t0, color));
226                 self.font_vertices
227                     .push(DebugFontVertex::new(x0, y1, s0, t1, color));
228                 self.font_vertices
229                     .push(DebugFontVertex::new(x1, y1, s1, t1, color));
230 
231                 self.font_indices.push(vertex_count + 0);
232                 self.font_indices.push(vertex_count + 1);
233                 self.font_indices.push(vertex_count + 2);
234                 self.font_indices.push(vertex_count + 2);
235                 self.font_indices.push(vertex_count + 1);
236                 self.font_indices.push(vertex_count + 3);
237 
238                 min_x = min_x.min(x0);
239                 max_x = max_x.max(x1);
240                 min_y = min_y.min(y0);
241                 max_y = max_y.max(y1);
242             }
243         }
244 
245         Rect::new(
246             Point2D::new(min_x, min_y),
247             Size2D::new(max_x - min_x, max_y - min_y),
248         )
249     }
250 
add_quad( &mut self, x0: f32, y0: f32, x1: f32, y1: f32, color_top: ColorU, color_bottom: ColorU, )251     pub fn add_quad(
252         &mut self,
253         x0: f32,
254         y0: f32,
255         x1: f32,
256         y1: f32,
257         color_top: ColorU,
258         color_bottom: ColorU,
259     ) {
260         let vertex_count = self.tri_vertices.len() as u32;
261 
262         self.tri_vertices
263             .push(DebugColorVertex::new(x0, y0, color_top));
264         self.tri_vertices
265             .push(DebugColorVertex::new(x1, y0, color_top));
266         self.tri_vertices
267             .push(DebugColorVertex::new(x0, y1, color_bottom));
268         self.tri_vertices
269             .push(DebugColorVertex::new(x1, y1, color_bottom));
270 
271         self.tri_indices.push(vertex_count + 0);
272         self.tri_indices.push(vertex_count + 1);
273         self.tri_indices.push(vertex_count + 2);
274         self.tri_indices.push(vertex_count + 2);
275         self.tri_indices.push(vertex_count + 1);
276         self.tri_indices.push(vertex_count + 3);
277     }
278 
279     #[allow(dead_code)]
add_line(&mut self, x0: i32, y0: i32, color0: ColorU, x1: i32, y1: i32, color1: ColorU)280     pub fn add_line(&mut self, x0: i32, y0: i32, color0: ColorU, x1: i32, y1: i32, color1: ColorU) {
281         self.line_vertices
282             .push(DebugColorVertex::new(x0 as f32, y0 as f32, color0));
283         self.line_vertices
284             .push(DebugColorVertex::new(x1 as f32, y1 as f32, color1));
285     }
286 
287 
add_rect(&mut self, rect: &DeviceIntRect, color: ColorU)288     pub fn add_rect(&mut self, rect: &DeviceIntRect, color: ColorU) {
289         let p0 = rect.min;
290         let p1 = rect.max;
291         self.add_line(p0.x, p0.y, color, p1.x, p0.y, color);
292         self.add_line(p1.x, p0.y, color, p1.x, p1.y, color);
293         self.add_line(p1.x, p1.y, color, p0.x, p1.y, color);
294         self.add_line(p0.x, p1.y, color, p0.x, p0.y, color);
295     }
296 
render( &mut self, device: &mut Device, viewport_size: Option<DeviceIntSize>, scale: f32, surface_origin_is_top_left: bool, )297     pub fn render(
298         &mut self,
299         device: &mut Device,
300         viewport_size: Option<DeviceIntSize>,
301         scale: f32,
302         surface_origin_is_top_left: bool,
303     ) {
304         if let Some(viewport_size) = viewport_size {
305             device.disable_depth();
306             device.set_blend(true);
307             device.set_blend_mode_premultiplied_alpha();
308 
309             let (bottom, top) = if surface_origin_is_top_left {
310                 (0.0, viewport_size.height as f32 * scale)
311             } else {
312                 (viewport_size.height as f32 * scale, 0.0)
313             };
314 
315             let projection = Transform3D::ortho(
316                 0.0,
317                 viewport_size.width as f32 * scale,
318                 bottom,
319                 top,
320                 device.ortho_near_plane(),
321                 device.ortho_far_plane(),
322             );
323 
324             // Triangles
325             if !self.tri_vertices.is_empty() {
326                 device.bind_program(&self.color_program);
327                 device.set_uniforms(&self.color_program, &projection);
328                 device.bind_vao(&self.tri_vao);
329                 device.update_vao_indices(&self.tri_vao, &self.tri_indices, VertexUsageHint::Dynamic);
330                 device.update_vao_main_vertices(
331                     &self.tri_vao,
332                     &self.tri_vertices,
333                     VertexUsageHint::Dynamic,
334                 );
335                 device.draw_triangles_u32(0, self.tri_indices.len() as i32);
336             }
337 
338             // Lines
339             if !self.line_vertices.is_empty() {
340                 device.bind_program(&self.color_program);
341                 device.set_uniforms(&self.color_program, &projection);
342                 device.bind_vao(&self.line_vao);
343                 device.update_vao_main_vertices(
344                     &self.line_vao,
345                     &self.line_vertices,
346                     VertexUsageHint::Dynamic,
347                 );
348                 device.draw_nonindexed_lines(0, self.line_vertices.len() as i32);
349             }
350 
351             // Glyph
352             if !self.font_indices.is_empty() {
353                 device.bind_program(&self.font_program);
354                 device.set_uniforms(&self.font_program, &projection);
355                 device.bind_texture(DebugSampler::Font, &self.font_texture, Swizzle::default());
356                 device.bind_vao(&self.font_vao);
357                 device.update_vao_indices(&self.font_vao, &self.font_indices, VertexUsageHint::Dynamic);
358                 device.update_vao_main_vertices(
359                     &self.font_vao,
360                     &self.font_vertices,
361                     VertexUsageHint::Dynamic,
362                 );
363                 device.draw_triangles_u32(0, self.font_indices.len() as i32);
364             }
365         }
366 
367         self.font_indices.clear();
368         self.font_vertices.clear();
369         self.line_vertices.clear();
370         self.tri_vertices.clear();
371         self.tri_indices.clear();
372     }
373 }
374 
375 pub struct LazyInitializedDebugRenderer {
376     debug_renderer: Option<DebugRenderer>,
377     failed: bool,
378 }
379 
380 impl LazyInitializedDebugRenderer {
new() -> Self381     pub fn new() -> Self {
382         Self {
383             debug_renderer: None,
384             failed: false,
385         }
386     }
387 
get_mut<'a>(&'a mut self, device: &mut Device) -> Option<&'a mut DebugRenderer>388     pub fn get_mut<'a>(&'a mut self, device: &mut Device) -> Option<&'a mut DebugRenderer> {
389         if self.failed {
390             return None;
391         }
392         if self.debug_renderer.is_none() {
393             match DebugRenderer::new(device) {
394                 Ok(renderer) => { self.debug_renderer = Some(renderer); }
395                 Err(_) => {
396                     // The shader compilation code already logs errors.
397                     self.failed = true;
398                 }
399             }
400         }
401 
402         self.debug_renderer.as_mut()
403     }
404 
405     /// Returns mut ref to `debug::DebugRenderer` if one already exists, otherwise returns `None`.
try_get_mut<'a>(&'a mut self) -> Option<&'a mut DebugRenderer>406     pub fn try_get_mut<'a>(&'a mut self) -> Option<&'a mut DebugRenderer> {
407         self.debug_renderer.as_mut()
408     }
409 
deinit(self, device: &mut Device)410     pub fn deinit(self, device: &mut Device) {
411         if let Some(debug_renderer) = self.debug_renderer {
412             debug_renderer.deinit(device);
413         }
414     }
415 }
416