Source code

Revision control

Other Tools

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