Skip to content

Commit fa77241

Browse files
committed
a new text render system
1 parent 16c1fad commit fa77241

File tree

9 files changed

+509
-889
lines changed

9 files changed

+509
-889
lines changed

agb/examples/object_text_render.rs

Lines changed: 96 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,18 @@
33

44
use 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

1415
extern crate alloc;
1516

16-
use core::fmt::Write;
17+
use core::iter::Peekable;
1718

1819
static 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+
2584
fn 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
}

agb/src/display/object.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ pub use unmanaged::{
2525
AffineMode, GraphicsMode, OamIterator, OamSlot, OamUnmanaged, ObjectUnmanaged,
2626
};
2727

28-
pub use font::{ChangeColour, ObjectTextRender, TextAlignment};
28+
pub use font::{Alignment, LetterGroup, TextBlock};
2929

3030
use super::DISPLAY_CONTROL;
3131

0 commit comments

Comments
 (0)