33
44use agb:: {
55 display:: {
6- object:: { ChangeColour , ObjectTextRender , PaletteVram , Size , TextAlignment } ,
6+ object:: { Alignment , LetterGroup , ObjectUnmanaged , PaletteVram , Size , TextBlock } ,
77 palette16:: Palette16 ,
88 Font , HEIGHT , WIDTH ,
99 } ,
1010 include_font,
1111 input:: Button ,
1212} ;
13+ use alloc:: collections:: vec_deque:: VecDeque ;
1314
1415extern crate alloc;
1516
16- use core:: fmt :: Write ;
17+ use core:: iter :: Peekable ;
1718
1819static FONT : Font = include_font ! ( "examples/font/ark-pixel-10px-proportional-ja.ttf" , 10 ) ;
1920
@@ -22,6 +23,64 @@ fn entry(gba: agb::Gba) -> ! {
2223 main ( gba) ;
2324}
2425
26+
27+ struct MultiLineTextDisplay {
28+ block : Peekable < TextBlock < & ' static str > > ,
29+ letters : VecDeque < LetterGroup > ,
30+ max_number_of_lines : i32 ,
31+ current_line : i32 ,
32+ }
33+
34+ impl MultiLineTextDisplay {
35+ fn new ( text : TextBlock < & ' static str > , max_number_of_lines : i32 ) -> Self {
36+ Self {
37+ block : text. peekable ( ) ,
38+ letters : VecDeque :: new ( ) ,
39+ max_number_of_lines,
40+ current_line : 0 ,
41+ }
42+ }
43+
44+ fn is_done ( & mut self ) -> bool {
45+ self . block . peek ( ) . is_none ( )
46+ }
47+
48+ fn is_showing_all_available_lines ( & mut self ) -> bool {
49+ let Some ( next_letter) = self . block . peek ( ) else {
50+ return false ;
51+ } ;
52+
53+ self . current_line + self . max_number_of_lines <= next_letter. line
54+ }
55+
56+ fn increase_letters ( & mut self ) {
57+ let Some ( next_letter) = self . block . peek ( ) else {
58+
59+ return ;
60+ } ;
61+
62+ if self . current_line + self . max_number_of_lines > next_letter. line {
63+ self . letters . push_back ( self . block . next ( ) . unwrap ( ) ) ;
64+ }
65+ }
66+
67+ fn iter ( & self ) -> impl Iterator < Item = LetterGroup > + use < ' _ > {
68+ self . letters . iter ( ) . map ( |x| LetterGroup { letter : x. letter . clone ( ) , x : x. x , line : x. line - self . current_line } )
69+ }
70+
71+ fn pop_line ( & mut self ) {
72+ while let Some ( letter) = self . letters . front ( ) {
73+ if letter. line == self . current_line {
74+ self . letters . pop_front ( ) ;
75+ } else {
76+ break ;
77+ }
78+ }
79+
80+ self . current_line += 1 ;
81+ }
82+ }
83+
2584fn main ( mut gba : agb:: Gba ) -> ! {
2685 let ( mut unmanaged, _sprites) = gba. display . object . get_unmanaged ( ) ;
2786
@@ -37,16 +96,15 @@ fn main(mut gba: agb::Gba) -> ! {
3796 timer. set_enabled ( true ) ;
3897 timer. set_divider ( agb:: timer:: Divider :: Divider256 ) ;
3998
40- let mut wr = ObjectTextRender :: new ( & FONT , Size :: S16x16 , palette) ;
4199 let start = timer. value ( ) ;
100+ let wr = TextBlock :: new ( & FONT ,
101+ "Woah!{change2} {player_name}! {change1}こんにちは! I have a bunch of text I want to show you. However, you will find that the amount of text I can display is limited. Who'd have thought! Good thing that my text system supports scrolling! It only took around 20 jank versions to get here!" ,
102+ palette,
103+ Alignment :: Left ,
104+ ( WIDTH - 8 ) as u32 ,
105+ Size :: S16x16 ,
106+ ) ;
42107
43- let player_name = "You" ;
44- let _ = writeln ! (
45- wr,
46- "Woah!{change2} {player_name}! {change1}こんにちは! I have a bunch of text I want to show you. However, you will find that the amount of text I can display is limited. Who'd have thought! Good thing that my text system supports scrolling! It only took around 20 jank versions to get here!" ,
47- change2 = ChangeColour :: new( 2 ) ,
48- change1 = ChangeColour :: new( 1 ) ,
49- ) ;
50108 let end = timer. value ( ) ;
51109
52110 agb:: println!(
@@ -57,42 +115,46 @@ fn main(mut gba: agb::Gba) -> ! {
57115 let vblank = agb:: interrupt:: VBlank :: get ( ) ;
58116 let mut input = agb:: input:: ButtonController :: new ( ) ;
59117
60- let start = timer. value ( ) ;
61-
62- wr. layout ( ( WIDTH , 40 ) , TextAlignment :: Justify , 2 ) ;
63- let end = timer. value ( ) ;
64-
65- agb:: println!(
66- "Layout took {} cycles" ,
67- 256 * ( end. wrapping_sub( start) as u32 )
68- ) ;
69-
70- let mut line_done = false ;
71118 let mut frame = 0 ;
72119
120+ let mut multi_line = MultiLineTextDisplay :: new ( wr, 2 ) ;
121+
73122 loop {
74- vblank. wait_for_vblank ( ) ;
75123 input. update ( ) ;
76- let oam = & mut unmanaged. iter ( ) ;
77- wr. commit ( oam) ;
78124
79125 let start = timer. value ( ) ;
80- if frame % 4 == 0 {
81- line_done = !wr. next_letter_group ( ) ;
126+
127+ if frame % 2 == 0 {
128+ multi_line. increase_letters ( ) ;
82129 }
83- if line_done && input . is_just_pressed ( Button :: A ) {
84- line_done = false ;
85- wr . pop_line ( ) ;
130+
131+ if multi_line . is_showing_all_available_lines ( ) && input . is_just_pressed ( Button :: A ) {
132+ multi_line . pop_line ( ) ;
86133 }
87- wr . update ( ( 0 , HEIGHT - 40 ) ) ;
134+
88135 let end = timer. value ( ) ;
136+ agb:: println!(
137+ "Update took {} cycles" ,
138+ 256 * ( end. wrapping_sub( start) as u32 )
139+ ) ;
140+ let start = timer. value ( ) ;
89141
90- frame += 1 ;
91142
143+ let mut frame_oam = unmanaged. iter ( ) ;
144+
145+ for letter in multi_line. iter ( ) {
146+ let mut object = ObjectUnmanaged :: new ( letter. letter ) ;
147+ object. set_position ( ( 4 + letter. x , HEIGHT - 32 + letter. line * 16 ) . into ( ) ) . show ( ) ;
148+ frame_oam. set_next ( & object) ;
149+ }
150+
151+ let end = timer. value ( ) ;
92152 agb:: println!(
93- "Took {} cycles, line done {}" ,
94- 256 * ( end. wrapping_sub( start) as u32 ) ,
95- line_done
153+ "Draw took {} cycles" ,
154+ 256 * ( end. wrapping_sub( start) as u32 )
96155 ) ;
156+
157+ vblank. wait_for_vblank ( ) ;
158+ frame += 1 ;
97159 }
98160}
0 commit comments