Skip to content

Commit 88b70ff

Browse files
committed
WIP Add console window for debugging
1 parent 909b06a commit 88b70ff

File tree

4 files changed

+116
-28
lines changed

4 files changed

+116
-28
lines changed

core/src/render/text.rs

Lines changed: 104 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
1-
use core::fmt;
1+
use core::fmt::{self, Write};
2+
use core::ops::Range;
23
#[cfg(feature = "std")]
34
use std::io;
45

5-
use crate::geom::{Mesh, tri, vertex};
6-
use crate::math::{Color3, Point2, Vec2, pt2, vec2, vec3};
6+
use crate::geom::{Mesh, Tri, Vertex, Vertex3, tri, vertex};
7+
use crate::math::{
8+
Color3, Color4, Point2, Point2u, ProjMat3, ProjVec3, Vec2, color::gray,
9+
orthographic, pt2, pt3, vec2, vec3, viewport,
10+
};
711
use crate::util::buf::Buf2;
812

9-
use super::tex::{Atlas, Layout, SamplerClamp, TexCoord};
13+
use super::{
14+
Batch, Context, Frag, FragmentShader, Model, Target, VertexShader,
15+
tex::{Atlas, Layout, SamplerClamp, TexCoord},
16+
};
1017

1118
/// Text represented as texture-mapped geometry, one quad per glyph.
1219
#[derive(Clone)]
@@ -18,6 +25,42 @@ pub struct Text {
1825
cursor: Point2,
1926
}
2027

28+
pub struct Console {
29+
text: Text,
30+
left_top: Point2u,
31+
right_bot: Point2u,
32+
}
33+
34+
pub struct TextShader<'a>(&'a Text);
35+
36+
impl VertexShader<Vertex3<TexCoord>, ProjMat3<Model>> for TextShader<'_> {
37+
type Output = Vertex<ProjVec3, TexCoord>;
38+
39+
fn shade_vertex(
40+
&self,
41+
v: Vertex3<TexCoord>,
42+
tf: ProjMat3<Model>,
43+
) -> Self::Output {
44+
vertex(tf.apply(&v.pos), v.attrib)
45+
}
46+
}
47+
48+
impl FragmentShader<TexCoord> for TextShader<'_> {
49+
fn shade_fragment(&self, f: Frag<TexCoord>) -> Option<Color4> {
50+
let c = self.0.sample(f.var);
51+
(c != gray(0)).then_some(c.to_rgba())
52+
}
53+
}
54+
55+
pub type TextBatch<'a> = Batch<
56+
Tri<usize>,
57+
Vertex3<TexCoord>,
58+
ProjMat3<Model>,
59+
TextShader<'a>,
60+
(),
61+
Context,
62+
>;
63+
2164
//
2265
// Inherent impls
2366
//
@@ -64,7 +107,7 @@ impl Text {
64107
fn write_char(&mut self, idx: u32) {
65108
let Self { font, geom, cursor, .. } = self;
66109

67-
let Layout::Grid { sub_dims: (gw, gh) } = font.layout;
110+
let (gw, gh) = font.dims(idx);
68111
let (glyph_w, glyph_h) = (gw as f32, gh as f32);
69112

70113
let [tl, tr, bl, br] = font.coords(idx);
@@ -90,6 +133,60 @@ impl Text {
90133

91134
*cursor += vec2(glyph_w, 0.0);
92135
}
136+
137+
fn newline(&mut self) {
138+
let Layout::Grid { sub_dims } = self.font.layout;
139+
// TODO variable line height support
140+
self.cursor = pt2(0.0, self.cursor.y() + sub_dims.1 as f32)
141+
}
142+
}
143+
144+
impl Console {
145+
pub fn new(font: Atlas<Color3>, bounds: Range<Point2u>) -> Self {
146+
Self {
147+
text: Text::new(font),
148+
left_top: bounds.start,
149+
right_bot: bounds.end,
150+
}
151+
}
152+
153+
pub fn print(&mut self, s: &str) {
154+
_ = self.text.write_str(s);
155+
}
156+
pub fn println(&mut self, s: &str) {
157+
self.print(s);
158+
self.print("\n");
159+
}
160+
161+
pub fn write_fmt(&mut self, args: fmt::Arguments) {
162+
_ = self.text.write_fmt(args)
163+
}
164+
165+
pub fn clear(&mut self) {
166+
self.text.clear();
167+
}
168+
169+
pub fn batch(&self) -> TextBatch<'_> {
170+
let Self {
171+
left_top: lt, right_bot: rb, ..
172+
} = self;
173+
174+
let [w, h] = (*rb - *lt).0;
175+
let projection =
176+
orthographic(pt3(0.0, 0.0, 0.0), pt3(w as f32, h as f32, 0.0));
177+
178+
let viewport = viewport(*lt..*rb);
179+
180+
Batch::new()
181+
.mesh(&self.text.geom)
182+
.uniform(projection.to())
183+
.shader(TextShader(&self.text))
184+
.viewport(viewport)
185+
}
186+
187+
pub fn render(&self, target: impl Target, ctx: &Context) {
188+
self.batch().target(target).context(ctx).render();
189+
}
93190
}
94191

95192
//
@@ -110,18 +207,9 @@ impl io::Write for Text {
110207
///
111208
/// [1]: https://en.wikipedia.org/wiki/Mojibake
112209
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
113-
/*let (rows, cols) = buf
114-
.split(|&b| b == b'\n')
115-
.fold((0, 0), |(rs, cs), row| (rs + 1, cs.max(row.len() as u32)));
116-
if rows == 0 || cols == 0 {
117-
return Ok(0);
118-
}*/
119-
let Layout::Grid { sub_dims } = self.font.layout;
120-
let glyph_h = sub_dims.1 as f32;
121-
122210
for &b in buf {
123211
match b {
124-
b'\n' => self.cursor = pt2(0.0, self.cursor.y() + glyph_h),
212+
b'\n' => self.newline(),
125213
_ => self.write_char(b.into()),
126214
}
127215
}
@@ -140,20 +228,9 @@ impl fmt::Write for Text {
140228
/// of each `char` as an index into the font. As such, the font should have
141229
/// enough glyphs to cover all the characters used.
142230
fn write_str(&mut self, s: &str) -> fmt::Result {
143-
/*let (rows, cols) = s
144-
.split(|c| c == '\n')
145-
.fold((0, 0), |(rs, cs), row| {
146-
(rs + 1, cs.max(row.chars().count() as u32))
147-
});
148-
if rows == 0 || cols == 0 {
149-
return Ok(());
150-
}*/
151-
let Layout::Grid { sub_dims } = self.font.layout;
152-
let glyph_h = sub_dims.1 as f32;
153-
154231
for c in s.chars() {
155232
match c {
156-
'\n' => self.cursor = pt2(0.0, self.cursor.y() + glyph_h),
233+
'\n' => self.newline(),
157234
_ => self.write_char(c.into()),
158235
}
159236
}

demos/assets/font_6x10.pbm

1.88 KB
Binary file not shown.

demos/assets/font_8x12.pbm

3.01 KB
Binary file not shown.

demos/src/bin/crates.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ use re::core::render::{
88
clip::Status::*,
99
scene::Obj,
1010
shader,
11-
tex::SamplerClamp,
11+
tex::{Atlas, SamplerClamp},
12+
text::Console,
1213
};
1314
// Try also Rgb565 or Rgba4444
1415
use re::core::util::{pixfmt::Rgba8888, pnm::read_pnm};
@@ -20,6 +21,7 @@ fn main() {
2021
let mut win = Window::builder()
2122
.title("retrofire//crates")
2223
.pixel_fmt(Rgba8888)
24+
.vsync(false)
2325
.build()
2426
.expect("should create window");
2527

@@ -56,6 +58,11 @@ fn main() {
5658
let floor = floor();
5759
let crates = crates();
5860

61+
static FONT: &[u8] = include_bytes!("../../assets/font_6x10.pbm");
62+
let font = Atlas::grid((6, 10), read_pnm(FONT).expect("font exists").into());
63+
64+
let mut con = Console::new(font, pt2(20, 20)..pt2(400, 200));
65+
5966
win.run(|frame| {
6067
//
6168
// Camera
@@ -132,6 +139,10 @@ fn main() {
132139
frame.ctx.stats.borrow_mut().objs.o += 1;
133140
}
134141

142+
con.clear();
143+
write!(con, "{}", frame.ctx.stats.borrow());
144+
con.render(frame.buf, frame.ctx);
145+
135146
Continue(())
136147
})
137148
.expect("should run");

0 commit comments

Comments
 (0)