pub struct ObjectTextRender<'font> { /* private fields */ }
Expand description

The object text renderer. Uses objects to render and layout text. It’s use is non trivial. Changes the palette to use to draw characters.

#![no_std]
#![no_main]
use agb::display::object::{ObjectTextRender, PaletteVram, TextAlignment, Size};
use agb::display::palette16::Palette16;
use agb::display::{Font, WIDTH};

use core::fmt::Write;

const EXAMPLE_FONT: Font = agb::include_font!("examples/font/yoster.ttf", 12);

#[agb::entry]
fn main(gba: &mut agb::Gba) -> ! {
    let (mut unmanaged, _) = gba.display.object.get_unmanaged();
    let vblank = agb::interrupt::VBlank::get();

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

    let mut writer = ObjectTextRender::new(&EXAMPLE_FONT, Size::S16x16, palette);

    let _ = writeln!(writer, "Hello, World!");
    writer.layout((WIDTH, 40).into(), TextAlignment::Left, 2);

    loop {
        writer.next_letter_group();
        writer.update((0, 0).into());
        vblank.wait_for_vblank();
        let oam = &mut unmanaged.iter();
        writer.commit(oam);
    }
}

Implementations§

source§

impl<'font> ObjectTextRender<'font>

source

pub fn new(font: &'font Font, sprite_size: Size, palette: PaletteVram) -> Self

Creates a new text renderer with a given font, sprite size, and palette. You must ensure that the sprite size can accomodate the letters from the font otherwise it will panic at render time.

Examples found in repository?
examples/object_text_render.rs (line 39)
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
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 timer = gba.timers.timers();
    let mut timer: agb::timer::Timer = timer.timer2;

    timer.set_enabled(true);
    timer.set_divider(agb::timer::Divider::Divider256);

    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}Hey there! 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 end = timer.value();

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

    let vblank = agb::interrupt::VBlank::get();
    let mut input = agb::input::ButtonController::new();

    let start = timer.value();

    wr.layout((WIDTH, 40).into(), 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;

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

        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).into());
        let end = timer.value();

        frame += 1;

        agb::println!(
            "Took {} cycles, line done {}",
            256 * (end.wrapping_sub(start) as u32),
            line_done
        );
    }
}
source§

impl ObjectTextRender<'_>

source

pub fn commit(&mut self, oam: &mut OamIterator<'_>)

Commits work already done to screen. You can commit to multiple places in the same frame.

Examples found in repository?
examples/object_text_render.rs (line 76)
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
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 timer = gba.timers.timers();
    let mut timer: agb::timer::Timer = timer.timer2;

    timer.set_enabled(true);
    timer.set_divider(agb::timer::Divider::Divider256);

    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}Hey there! 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 end = timer.value();

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

    let vblank = agb::interrupt::VBlank::get();
    let mut input = agb::input::ButtonController::new();

    let start = timer.value();

    wr.layout((WIDTH, 40).into(), 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;

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

        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).into());
        let end = timer.value();

        frame += 1;

        agb::println!(
            "Took {} cycles, line done {}",
            256 * (end.wrapping_sub(start) as u32),
            line_done
        );
    }
}
source

pub fn layout( &mut self, area: Vector2D<i32>, alignment: TextAlignment, paragraph_spacing: i32 )

Force a relayout, must be called after writing.

Examples found in repository?
examples/object_text_render.rs (line 61)
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
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 timer = gba.timers.timers();
    let mut timer: agb::timer::Timer = timer.timer2;

    timer.set_enabled(true);
    timer.set_divider(agb::timer::Divider::Divider256);

    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}Hey there! 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 end = timer.value();

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

    let vblank = agb::interrupt::VBlank::get();
    let mut input = agb::input::ButtonController::new();

    let start = timer.value();

    wr.layout((WIDTH, 40).into(), 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;

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

        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).into());
        let end = timer.value();

        frame += 1;

        agb::println!(
            "Took {} cycles, line done {}",
            256 * (end.wrapping_sub(start) as u32),
            line_done
        );
    }
}
source

pub fn pop_line(&mut self) -> bool

Removes one complete line. Returns whether a line could be removed. You must call update after this

Examples found in repository?
examples/object_text_render.rs (line 84)
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
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 timer = gba.timers.timers();
    let mut timer: agb::timer::Timer = timer.timer2;

    timer.set_enabled(true);
    timer.set_divider(agb::timer::Divider::Divider256);

    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}Hey there! 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 end = timer.value();

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

    let vblank = agb::interrupt::VBlank::get();
    let mut input = agb::input::ButtonController::new();

    let start = timer.value();

    wr.layout((WIDTH, 40).into(), 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;

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

        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).into());
        let end = timer.value();

        frame += 1;

        agb::println!(
            "Took {} cycles, line done {}",
            256 * (end.wrapping_sub(start) as u32),
            line_done
        );
    }
}
source

pub fn update(&mut self, position: Vector2D<i32>)

Updates the internal state of the number of letters to write and popped line. Should be called in the same frame as and after next_letter_group, next_line, and pop_line.

Examples found in repository?
examples/object_text_render.rs (line 86)
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
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 timer = gba.timers.timers();
    let mut timer: agb::timer::Timer = timer.timer2;

    timer.set_enabled(true);
    timer.set_divider(agb::timer::Divider::Divider256);

    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}Hey there! 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 end = timer.value();

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

    let vblank = agb::interrupt::VBlank::get();
    let mut input = agb::input::ButtonController::new();

    let start = timer.value();

    wr.layout((WIDTH, 40).into(), 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;

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

        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).into());
        let end = timer.value();

        frame += 1;

        agb::println!(
            "Took {} cycles, line done {}",
            256 * (end.wrapping_sub(start) as u32),
            line_done
        );
    }
}
source

pub fn next_letter_group(&mut self) -> bool

Causes the next letter group to be shown on the next update. Returns whether another letter could be added in the space given.

Examples found in repository?
examples/object_text_render.rs (line 80)
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
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 timer = gba.timers.timers();
    let mut timer: agb::timer::Timer = timer.timer2;

    timer.set_enabled(true);
    timer.set_divider(agb::timer::Divider::Divider256);

    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}Hey there! 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 end = timer.value();

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

    let vblank = agb::interrupt::VBlank::get();
    let mut input = agb::input::ButtonController::new();

    let start = timer.value();

    wr.layout((WIDTH, 40).into(), 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;

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

        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).into());
        let end = timer.value();

        frame += 1;

        agb::println!(
            "Took {} cycles, line done {}",
            256 * (end.wrapping_sub(start) as u32),
            line_done
        );
    }
}
source

pub fn next_line(&mut self) -> bool

Causes the next line to be shown on the next update. Returns whether another line could be added in the space given.

Trait Implementations§

source§

impl Write for ObjectTextRender<'_>

source§

fn write_str(&mut self, s: &str) -> Result

Writes a string slice into this writer, returning whether the write succeeded. Read more
1.1.0§

fn write_char(&mut self, c: char) -> Result<(), Error>

Writes a [char] into this writer, returning whether the write succeeded. Read more
1.0.0§

fn write_fmt(&mut self, args: Arguments<'_>) -> Result<(), Error>

Glue for usage of the [write!] macro with implementors of this trait. Read more

Auto Trait Implementations§

§

impl<'font> !RefUnwindSafe for ObjectTextRender<'font>

§

impl<'font> !Send for ObjectTextRender<'font>

§

impl<'font> !Sync for ObjectTextRender<'font>

§

impl<'font> Unpin for ObjectTextRender<'font>

§

impl<'font> !UnwindSafe for ObjectTextRender<'font>

Blanket Implementations§

§

impl<T> Any for Twhere T: 'static + ?Sized,

§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
§

impl<T> Borrow<T> for Twhere T: ?Sized,

§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
§

impl<T> BorrowMut<T> for Twhere T: ?Sized,

§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
§

impl<T> From<T> for T

§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T, U> Into<U> for Twhere U: From<T>,

§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of [From]<T> for U chooses to do.

§

impl<T, U> TryFrom<U> for Twhere U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
§

impl<T, U> TryInto<U> for Twhere U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.