1- use core:: fmt;
1+ use core:: fmt:: { self , Write } ;
2+ use core:: ops:: Range ;
23#[ cfg( feature = "std" ) ]
34use 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+ } ;
711use 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 }
0 commit comments