Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Let user deal with font sprites #580

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 68 additions & 37 deletions agb/examples/object_text_render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,21 @@

use agb::{
display::{
object::{ChangeColour, ObjectTextRender, PaletteVram, Size, TextAlignment},
object::{
ChangeColour, LeftAlignLayout, ObjectUnmanaged, PaletteVram, SimpleTextRender, Size,
},
palette16::Palette16,
Font, HEIGHT, WIDTH,
},
include_font,
input::Button,
};
use agb_fixnum::Vector2D;

extern crate alloc;
use alloc::borrow::Cow;
use core::num::NonZeroU32;

use core::fmt::Write;
extern crate alloc;

static FONT: Font = include_font!("examples/font/ark-pixel-10px-proportional-ja.ttf", 10);

Expand All @@ -36,17 +40,22 @@ fn main(mut gba: agb::Gba) -> ! {

timer.set_enabled(true);
timer.set_divider(agb::timer::Divider::Divider256);
let player_name = "You";
let text = alloc::format!(
"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!\n",
change2 = ChangeColour::new(2),
change1 = ChangeColour::new(1),
);

let mut wr = ObjectTextRender::new(&FONT, Size::S16x16, palette);
let start = timer.value();

let player_name = "You";
let _ = writeln!(
wr,
"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!",
change2 = ChangeColour::new(2),
change1 = ChangeColour::new(1),
);
let simple = SimpleTextRender::new(
Cow::Owned(text),
&FONT,
palette,
Size::S16x16,
Some(|c| c == '.'),
);
let mut wr = LeftAlignLayout::new(simple, NonZeroU32::new(WIDTH as u32));
let end = timer.value();

agb::println!(
Expand All @@ -57,42 +66,64 @@ fn main(mut gba: agb::Gba) -> ! {
let vblank = agb::interrupt::VBlank::get();
let mut input = agb::input::ButtonController::new();

let start = timer.value();

wr.layout((WIDTH, 40), TextAlignment::Justify, 2);
let end = timer.value();

agb::println!(
"Layout took {} cycles",
256 * (end.wrapping_sub(start) as u32)
);

let mut line_done = false;
let mut frame = 0;
let mut groups_to_show = 0;

loop {
vblank.wait_for_vblank();
input.update();
let oam = &mut unmanaged.iter();
wr.commit(oam);

wr.at_least_n_letter_groups(groups_to_show + 2);
let start = timer.value();
if frame % 4 == 0 {
line_done = !wr.next_letter_group();
}
if line_done && input.is_just_pressed(Button::A) {
line_done = false;
wr.pop_line();
}
wr.update((0, HEIGHT - 40));
let end = timer.value();

frame += 1;
let can_pop_line = {
let mut letters = wr.layout();
let displayed_letters = letters.by_ref().take(groups_to_show);

for (letter, slot) in displayed_letters.zip(oam) {
let mut obj = ObjectUnmanaged::new(letter.sprite().clone());
obj.show();
let y = HEIGHT - 40 + letter.line() as i32 * FONT.line_height();
obj.set_position(Vector2D::new(letter.x(), y));

slot.set(&obj);
}

let speed_up = if input.is_pressed(Button::A | Button::B) {
4
} else {
1
};

if let Some(next_letter) = letters.next() {
if next_letter.line() < 2 {
if next_letter.string() == "." {
if frame % (16 / speed_up) == 0 {
groups_to_show += 1;
}
} else if frame % (4 / speed_up) == 0 {
groups_to_show += 1;
}
false
} else {
true
}
} else {
false
}
};

let end = timer.value();
agb::println!(
"Took {} cycles, line done {}",
256 * (end.wrapping_sub(start) as u32),
line_done
"Layout took {} cycles",
256 * (end.wrapping_sub(start) as u32)
);

if can_pop_line && input.is_just_pressed(Button::A) {
groups_to_show -= wr.pop_line();
}

frame += 1;
}
}
107 changes: 107 additions & 0 deletions agb/examples/rotating_text.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
#![no_std]
#![no_main]

use agb::{
display::{
affine::AffineMatrix,
object::{
AffineMatrixInstance, AffineMode, ObjectTextRender, ObjectUnmanaged, PaletteVram, Size,
SpriteVram, TextAlignment,
},
palette16::Palette16,
Font, HEIGHT, WIDTH,
},
include_font,
};
use agb_fixnum::{num, Num, Vector2D};
use alloc::vec::Vec;

extern crate alloc;

const FONT: Font = include_font!("examples/font/yoster.ttf", 12);
#[agb::entry]
fn entry(gba: agb::Gba) -> ! {
main(gba);
}

fn text_objects(
font: &Font,
sprite_size: Size,
palette: PaletteVram,
text_alignment: TextAlignment,
width: i32,
paragraph_spacing: i32,
arguments: core::fmt::Arguments,
) -> Vec<(SpriteVram, Vector2D<i32>)> {
let text = alloc::format!("{}\n", arguments);
let mut wr = ObjectTextRender::new(text, font, sprite_size, palette, None);

wr.layout(width, text_alignment, paragraph_spacing);
wr.render_all();

wr.letter_groups()
.map(|x| (x.sprite().clone(), x.relative_position()))
.collect()
}

fn main(mut gba: agb::Gba) -> ! {
let (mut unmanaged, _sprites) = gba.display.object.get_unmanaged();

let mut palette = [0x0; 16];
palette[1] = 0xFF_FF;
palette[2] = 0x00_FF;
let palette = Palette16::new(palette);
let palette = PaletteVram::new(&palette).unwrap();

let groups: Vec<_> = text_objects(
&FONT,
Size::S16x16,
palette,
TextAlignment::Center,
WIDTH,
0,
format_args!("Woah, ROTATION!"),
)
.into_iter()
.map(|x| (x.0, x.1 - (WIDTH / 2, 0).into() + (8, 4).into()))
.collect();

let vblank = agb::interrupt::VBlank::get();
let mut angle: Num<i32, 8> = num!(0.);

loop {
angle += num!(0.01);
if angle >= num!(1.) {
angle -= num!(1.);
}

let rotation_matrix = AffineMatrix::from_rotation(angle);

let letter_group_rotation_matrix_instance =
AffineMatrixInstance::new(AffineMatrix::from_rotation(-angle).to_object_wrapping());

let frame_positions: Vec<_> = groups
.iter()
.map(|x| {
let mat = AffineMatrix::from_translation(x.1.change_base());

let mat = rotation_matrix * mat;

let position = mat.position() + (WIDTH / 2, HEIGHT / 2).into() - (16, 16).into();

let mut object = ObjectUnmanaged::new(x.0.clone());
object.set_affine_matrix(letter_group_rotation_matrix_instance.clone());
object.show_affine(AffineMode::AffineDouble);
object.set_position(position.floor());

object
})
.collect();

vblank.wait_for_vblank();
let mut oam = unmanaged.iter();
for (object, oam_slot) in frame_positions.into_iter().zip(&mut oam) {
oam_slot.set(&object);
}
}
}
3 changes: 2 additions & 1 deletion agb/src/display/font.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,8 @@ impl Font {
self.ascent
}

pub(crate) fn line_height(&self) -> i32 {
#[must_use]
pub fn line_height(&self) -> i32 {
self.line_height
}
}
Expand Down
2 changes: 1 addition & 1 deletion agb/src/display/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ pub use affine::AffineMatrixInstance;
pub use managed::{OamManaged, Object};
pub use unmanaged::{AffineMode, OamIterator, OamSlot, OamUnmanaged, ObjectUnmanaged};

pub use font::{ChangeColour, ObjectTextRender, TextAlignment};
pub use font::{ChangeColour, LeftAlignLayout, SimpleTextRender};

use super::DISPLAY_CONTROL;

Expand Down
Loading
Loading