mirror of
https://github.com/italicsjenga/agb.git
synced 2024-12-23 08:11:33 +11:00
caching layout
This commit is contained in:
parent
f947d82049
commit
cf400029f5
|
@ -4,7 +4,7 @@
|
||||||
use agb::{
|
use agb::{
|
||||||
display::{
|
display::{
|
||||||
object::{
|
object::{
|
||||||
font::{BufferedRender, TextAlignment},
|
font::{BufferedRender, LayoutCache, TextAlignment},
|
||||||
PaletteVram, Size,
|
PaletteVram, Size,
|
||||||
},
|
},
|
||||||
palette16::Palette16,
|
palette16::Palette16,
|
||||||
|
@ -53,27 +53,25 @@ fn main(mut gba: agb::Gba) -> ! {
|
||||||
timer.set_divider(agb::timer::Divider::Divider256);
|
timer.set_divider(agb::timer::Divider::Divider256);
|
||||||
|
|
||||||
let mut num_letters = 0;
|
let mut num_letters = 0;
|
||||||
let mut frame = 0;
|
|
||||||
|
|
||||||
let mut alignment = TextAlignment::Left;
|
let mut alignment = TextAlignment::Left;
|
||||||
|
|
||||||
let mut text = Vec::new();
|
let mut cache = LayoutCache::new();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
vblank.wait_for_vblank();
|
vblank.wait_for_vblank();
|
||||||
input.update();
|
input.update();
|
||||||
let oam = &mut unmanaged.iter();
|
let oam = &mut unmanaged.iter();
|
||||||
for (letter, slot) in text.iter().zip(oam) {
|
cache.commit(oam);
|
||||||
slot.set(letter);
|
|
||||||
}
|
|
||||||
|
|
||||||
let start = timer.value();
|
let start = timer.value();
|
||||||
wr.process();
|
wr.process();
|
||||||
text = wr.layout(
|
cache.update(
|
||||||
Rect::new((WIDTH / 8, 0).into(), (80, 100).into()),
|
&mut wr,
|
||||||
|
Rect::new((WIDTH / 3, 0).into(), (WIDTH / 3, 100).into()),
|
||||||
alignment,
|
alignment,
|
||||||
num_letters,
|
|
||||||
2,
|
2,
|
||||||
|
num_letters,
|
||||||
);
|
);
|
||||||
let end = timer.value();
|
let end = timer.value();
|
||||||
|
|
||||||
|
@ -89,11 +87,7 @@ fn main(mut gba: agb::Gba) -> ! {
|
||||||
alignment = TextAlignment::Center;
|
alignment = TextAlignment::Center;
|
||||||
}
|
}
|
||||||
|
|
||||||
frame += 1;
|
|
||||||
|
|
||||||
// if frame % 2 == 0 {
|
|
||||||
num_letters += 1;
|
num_letters += 1;
|
||||||
// }
|
|
||||||
|
|
||||||
if input.is_just_pressed(Button::A) {
|
if input.is_just_pressed(Button::A) {
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -69,6 +69,10 @@ impl Font {
|
||||||
pub(crate) fn ascent(&self) -> i32 {
|
pub(crate) fn ascent(&self) -> i32 {
|
||||||
self.ascent
|
self.ascent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn line_height(&self) -> i32 {
|
||||||
|
self.line_height
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Font {
|
impl Font {
|
||||||
|
|
|
@ -10,7 +10,7 @@ use self::{
|
||||||
renderer::{Configuration, WordRender},
|
renderer::{Configuration, WordRender},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{DynamicSprite, ObjectUnmanaged, PaletteVram, Size, SpriteVram};
|
use super::{DynamicSprite, OamIterator, ObjectUnmanaged, PaletteVram, Size, SpriteVram};
|
||||||
|
|
||||||
mod preprocess;
|
mod preprocess;
|
||||||
mod renderer;
|
mod renderer;
|
||||||
|
@ -48,11 +48,15 @@ pub struct BufferedRender<'font> {
|
||||||
font: &'font Font,
|
font: &'font Font,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Word {
|
||||||
|
index: usize,
|
||||||
|
length: usize,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
struct Letters {
|
struct Letters {
|
||||||
letters: Vec<LetterGroup>,
|
letters: Vec<LetterGroup>,
|
||||||
word_lengths: Vec<u8>,
|
|
||||||
current_word_length: usize,
|
|
||||||
number_of_groups: usize,
|
number_of_groups: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,7 +123,8 @@ impl<'font> BufferedRender<'font> {
|
||||||
|
|
||||||
impl BufferedRender<'_> {
|
impl BufferedRender<'_> {
|
||||||
fn input_character(&mut self, character: char) {
|
fn input_character(&mut self, character: char) {
|
||||||
self.preprocessor.add_character(self.font, character);
|
self.preprocessor
|
||||||
|
.add_character(self.font, character, self.char_render.sprite_width());
|
||||||
self.buffered_chars.push_back(character);
|
self.buffered_chars.push_back(character);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,102 +134,164 @@ impl BufferedRender<'_> {
|
||||||
' ' | '\n' => {
|
' ' | '\n' => {
|
||||||
if let Some(group) = self.char_render.finalise_letter() {
|
if let Some(group) = self.char_render.finalise_letter() {
|
||||||
self.letters.letters.push(group);
|
self.letters.letters.push(group);
|
||||||
self.letters.current_word_length += 1;
|
|
||||||
self.letters.number_of_groups += 1;
|
self.letters.number_of_groups += 1;
|
||||||
}
|
}
|
||||||
if self.letters.current_word_length != 0 {
|
|
||||||
self.letters.word_lengths.push(
|
|
||||||
self.letters
|
|
||||||
.current_word_length
|
|
||||||
.try_into()
|
|
||||||
.expect("word is too big"),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
self.letters.current_word_length = 0;
|
|
||||||
self.letters.number_of_groups += 1;
|
self.letters.number_of_groups += 1;
|
||||||
}
|
}
|
||||||
letter => {
|
letter => {
|
||||||
if let Some(group) = self.char_render.render_char(self.font, letter) {
|
if let Some(group) = self.char_render.render_char(self.font, letter) {
|
||||||
self.letters.letters.push(group);
|
self.letters.letters.push(group);
|
||||||
self.letters.current_word_length += 1;
|
|
||||||
self.letters.number_of_groups += 1;
|
self.letters.number_of_groups += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[must_use]
|
pub struct LayoutCache {
|
||||||
pub fn layout(
|
objects: Vec<ObjectUnmanaged>,
|
||||||
&mut self,
|
state: LayoutCacheState,
|
||||||
area: Rect<i32>,
|
settings: LayoutSettings,
|
||||||
alignment: TextAlignment,
|
}
|
||||||
number_of_groups: usize,
|
|
||||||
paragraph_spacing: i32,
|
|
||||||
) -> Vec<ObjectUnmanaged> {
|
|
||||||
let mut objects = Vec::new();
|
|
||||||
|
|
||||||
while !self.buffered_chars.is_empty() && self.letters.number_of_groups <= number_of_groups {
|
impl LayoutCache {
|
||||||
self.process();
|
fn update_cache(&mut self, number_of_groups: usize, render: &BufferedRender) {
|
||||||
|
let minimum_space_width = render.font.letter(' ').advance_width as i32;
|
||||||
|
|
||||||
|
let lines = render
|
||||||
|
.preprocessor
|
||||||
|
.lines_element(self.settings.area.size.x, minimum_space_width);
|
||||||
|
|
||||||
|
'outer: for (line, line_elements) in lines.skip(self.state.line_depth) {
|
||||||
|
let settings = self.settings.alignment.settings(
|
||||||
|
&line,
|
||||||
|
minimum_space_width,
|
||||||
|
self.settings.area.size,
|
||||||
|
);
|
||||||
|
|
||||||
|
if self.state.line_element_depth == 0 {
|
||||||
|
self.state.head_position.x += settings.start_x;
|
||||||
}
|
}
|
||||||
|
|
||||||
let minimum_space_width = self.font.letter(' ').advance_width as i32;
|
for element in line_elements.iter().skip(self.state.line_element_depth) {
|
||||||
|
|
||||||
let lines = self.preprocessor.lines(area.size.x, minimum_space_width);
|
|
||||||
let mut head_position = area.position;
|
|
||||||
|
|
||||||
let mut processed_depth = 0;
|
|
||||||
let mut group_depth = 0;
|
|
||||||
let mut word_depth = 0;
|
|
||||||
let mut rendered_groups = 0;
|
|
||||||
|
|
||||||
'outer: for line in lines {
|
|
||||||
let settings = alignment.settings(&line, minimum_space_width, area.size);
|
|
||||||
head_position.x += settings.start_x;
|
|
||||||
|
|
||||||
for idx in 0..line.number_of_text_elements() {
|
|
||||||
let element = self.preprocessor.get(processed_depth + idx);
|
|
||||||
match element {
|
match element {
|
||||||
PreprocessedElement::Word(_) => {
|
PreprocessedElement::Word(word) => {
|
||||||
for _ in 0..self
|
for letter in (word.sprite_index()
|
||||||
.letters
|
..(word.sprite_index() + word.number_of_sprites()))
|
||||||
.word_lengths
|
.skip(self.state.word_depth)
|
||||||
.get(word_depth)
|
.map(|x| &render.letters.letters[x])
|
||||||
.copied()
|
|
||||||
.unwrap_or(u8::MAX)
|
|
||||||
{
|
{
|
||||||
let letter_group = &self.letters.letters[group_depth];
|
let mut object = ObjectUnmanaged::new(letter.sprite.clone());
|
||||||
let mut object = ObjectUnmanaged::new(letter_group.sprite.clone());
|
self.state.head_position.x += letter.left as i32;
|
||||||
head_position.x += letter_group.left as i32;
|
object.set_position(self.state.head_position);
|
||||||
object.set_position(head_position);
|
self.state.head_position.x += letter.width as i32;
|
||||||
head_position.x += letter_group.width as i32;
|
|
||||||
object.show();
|
object.show();
|
||||||
objects.push(object);
|
self.objects.push(object);
|
||||||
group_depth += 1;
|
self.state.rendered_groups += 1;
|
||||||
rendered_groups += 1;
|
self.state.word_depth += 1;
|
||||||
if rendered_groups >= number_of_groups {
|
if self.state.rendered_groups >= number_of_groups {
|
||||||
break 'outer;
|
break 'outer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
word_depth += 1;
|
|
||||||
|
self.state.word_depth = 0;
|
||||||
|
self.state.line_element_depth += 1;
|
||||||
}
|
}
|
||||||
PreprocessedElement::WhiteSpace(space_type) => {
|
PreprocessedElement::WhiteSpace(space_type) => {
|
||||||
if space_type == WhiteSpace::NewLine {
|
if *space_type == WhiteSpace::NewLine {
|
||||||
head_position.y += paragraph_spacing;
|
self.state.head_position.y += self.settings.paragraph_spacing;
|
||||||
}
|
}
|
||||||
head_position.x += settings.space_width;
|
self.state.head_position.x += settings.space_width;
|
||||||
rendered_groups += 1;
|
self.state.rendered_groups += 1;
|
||||||
if rendered_groups >= number_of_groups {
|
self.state.line_element_depth += 1;
|
||||||
|
if self.state.rendered_groups >= number_of_groups {
|
||||||
break 'outer;
|
break 'outer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
processed_depth += line.number_of_text_elements();
|
self.state.head_position.y += render.font.line_height();
|
||||||
head_position.x = area.position.x;
|
self.state.head_position.x = self.settings.area.position.x;
|
||||||
head_position.y += 9;
|
|
||||||
|
self.state.line_element_depth = 0;
|
||||||
|
self.state.line_depth += 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
objects
|
pub fn update(
|
||||||
|
&mut self,
|
||||||
|
r: &mut BufferedRender<'_>,
|
||||||
|
area: Rect<i32>,
|
||||||
|
alignment: TextAlignment,
|
||||||
|
paragraph_spacing: i32,
|
||||||
|
number_of_groups: usize,
|
||||||
|
) {
|
||||||
|
while !r.buffered_chars.is_empty() && r.letters.number_of_groups <= number_of_groups {
|
||||||
|
r.process();
|
||||||
|
}
|
||||||
|
|
||||||
|
let settings = LayoutSettings {
|
||||||
|
area,
|
||||||
|
alignment,
|
||||||
|
paragraph_spacing,
|
||||||
|
};
|
||||||
|
if settings != self.settings {
|
||||||
|
self.reset(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.update_cache(number_of_groups, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn commit(&self, oam: &mut OamIterator) {
|
||||||
|
for (object, slot) in self.objects.iter().zip(oam) {
|
||||||
|
slot.set(object);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
objects: Vec::new(),
|
||||||
|
state: Default::default(),
|
||||||
|
settings: LayoutSettings {
|
||||||
|
area: Rect::new((0, 0).into(), (0, 0).into()),
|
||||||
|
alignment: TextAlignment::Right,
|
||||||
|
paragraph_spacing: -100,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reset(&mut self, settings: LayoutSettings) {
|
||||||
|
self.objects.clear();
|
||||||
|
self.state = LayoutCacheState {
|
||||||
|
head_position: settings.area.position,
|
||||||
|
processed_depth: 0,
|
||||||
|
group_depth: 0,
|
||||||
|
word_depth: 0,
|
||||||
|
rendered_groups: 0,
|
||||||
|
line_depth: 0,
|
||||||
|
line_element_depth: 0,
|
||||||
|
};
|
||||||
|
self.settings = settings;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq)]
|
||||||
|
struct LayoutSettings {
|
||||||
|
area: Rect<i32>,
|
||||||
|
alignment: TextAlignment,
|
||||||
|
paragraph_spacing: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct LayoutCacheState {
|
||||||
|
head_position: Vector2D<i32>,
|
||||||
|
processed_depth: usize,
|
||||||
|
group_depth: usize,
|
||||||
|
word_depth: usize,
|
||||||
|
rendered_groups: usize,
|
||||||
|
line_depth: usize,
|
||||||
|
line_element_depth: usize,
|
||||||
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use core::num::NonZeroU8;
|
||||||
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
use crate::display::Font;
|
use crate::display::Font;
|
||||||
|
@ -6,50 +8,53 @@ use super::WhiteSpace;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub(crate) enum PreprocessedElement {
|
pub(crate) enum PreprocessedElement {
|
||||||
Word(u8),
|
Word(Word),
|
||||||
WhiteSpace(WhiteSpace),
|
WhiteSpace(WhiteSpace),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test_case]
|
||||||
|
fn check_size_of_preprocessed_element_is_correct(_: &mut crate::Gba) {
|
||||||
|
assert_eq!(
|
||||||
|
core::mem::size_of::<PreprocessedElement>(),
|
||||||
|
core::mem::size_of::<Word>()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||||
|
#[repr(align(4))]
|
||||||
|
pub(crate) struct Word {
|
||||||
|
pixels: u8,
|
||||||
|
number_of_sprites: NonZeroU8,
|
||||||
|
index: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Word {
|
||||||
|
pub fn pixels(self) -> i32 {
|
||||||
|
self.pixels.into()
|
||||||
|
}
|
||||||
|
pub fn number_of_sprites(self) -> usize {
|
||||||
|
self.number_of_sprites.get().into()
|
||||||
|
}
|
||||||
|
pub fn sprite_index(self) -> usize {
|
||||||
|
self.index.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||||
struct PreprocessedElementStored(u8);
|
pub(crate) struct PreprocessedElementStored(u8);
|
||||||
|
|
||||||
impl core::fmt::Debug for PreprocessedElementStored {
|
|
||||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
|
||||||
f.debug_tuple("PreprocessedElementStored")
|
|
||||||
.field(&self.parse())
|
|
||||||
.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PreprocessedElementStored {
|
|
||||||
fn parse(self) -> PreprocessedElement {
|
|
||||||
match self.0 {
|
|
||||||
255 => PreprocessedElement::WhiteSpace(WhiteSpace::NewLine),
|
|
||||||
254 => PreprocessedElement::WhiteSpace(WhiteSpace::Space),
|
|
||||||
length => PreprocessedElement::Word(length),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_element(x: PreprocessedElement) -> Self {
|
|
||||||
match x {
|
|
||||||
PreprocessedElement::Word(length) => PreprocessedElementStored(length),
|
|
||||||
PreprocessedElement::WhiteSpace(space) => PreprocessedElementStored(match space {
|
|
||||||
WhiteSpace::NewLine => 255,
|
|
||||||
WhiteSpace::Space => 254,
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
pub(crate) struct Preprocessed {
|
pub(crate) struct Preprocessed {
|
||||||
widths: Vec<PreprocessedElementStored>,
|
widths: Vec<PreprocessedElement>,
|
||||||
preprocessor: Preprocessor,
|
preprocessor: Preprocessor,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
struct Preprocessor {
|
struct Preprocessor {
|
||||||
current_word_width: i32,
|
current_word_width: i32,
|
||||||
|
number_of_sprites: usize,
|
||||||
|
width_in_sprite: i32,
|
||||||
|
total_number_of_sprites: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Preprocessor {
|
impl Preprocessor {
|
||||||
|
@ -57,27 +62,44 @@ impl Preprocessor {
|
||||||
&mut self,
|
&mut self,
|
||||||
font: &Font,
|
font: &Font,
|
||||||
character: char,
|
character: char,
|
||||||
widths: &mut Vec<PreprocessedElementStored>,
|
sprite_width: i32,
|
||||||
|
widths: &mut Vec<PreprocessedElement>,
|
||||||
) {
|
) {
|
||||||
match character {
|
match character {
|
||||||
space @ (' ' | '\n') => {
|
space @ (' ' | '\n') => {
|
||||||
if self.current_word_width != 0 {
|
if self.current_word_width != 0 {
|
||||||
widths.push(PreprocessedElementStored::from_element(
|
self.number_of_sprites += 1;
|
||||||
PreprocessedElement::Word(
|
self.total_number_of_sprites += 1;
|
||||||
self.current_word_width
|
widths.push(PreprocessedElement::Word(Word {
|
||||||
|
pixels: self.current_word_width.try_into().expect("word too wide"),
|
||||||
|
number_of_sprites: NonZeroU8::new(
|
||||||
|
self.number_of_sprites.try_into().expect("word too wide"),
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
index: (self.total_number_of_sprites - self.number_of_sprites)
|
||||||
.try_into()
|
.try_into()
|
||||||
.expect("word should be small and positive"),
|
.expect("out of range"),
|
||||||
),
|
}));
|
||||||
));
|
|
||||||
self.current_word_width = 0;
|
self.current_word_width = 0;
|
||||||
|
self.number_of_sprites = 0;
|
||||||
|
self.width_in_sprite = 0;
|
||||||
}
|
}
|
||||||
widths.push(PreprocessedElementStored::from_element(
|
widths.push(PreprocessedElement::WhiteSpace(WhiteSpace::from_char(
|
||||||
PreprocessedElement::WhiteSpace(WhiteSpace::from_char(space)),
|
space,
|
||||||
));
|
)));
|
||||||
}
|
}
|
||||||
letter => {
|
letter => {
|
||||||
let letter = font.letter(letter);
|
let letter = font.letter(letter);
|
||||||
self.current_word_width += letter.advance_width as i32 + letter.xmin as i32;
|
self.current_word_width += letter.advance_width as i32 + letter.xmin as i32;
|
||||||
|
if self.width_in_sprite + letter.width as i32 > sprite_width {
|
||||||
|
self.number_of_sprites += 1;
|
||||||
|
self.total_number_of_sprites += 1;
|
||||||
|
self.width_in_sprite = 0;
|
||||||
|
}
|
||||||
|
if self.width_in_sprite != 0 {
|
||||||
|
self.width_in_sprite += letter.xmin as i32;
|
||||||
|
}
|
||||||
|
self.width_in_sprite += letter.advance_width as i32;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,7 +108,7 @@ impl Preprocessor {
|
||||||
pub(crate) struct Lines<'preprocess> {
|
pub(crate) struct Lines<'preprocess> {
|
||||||
minimum_space_width: i32,
|
minimum_space_width: i32,
|
||||||
layout_width: i32,
|
layout_width: i32,
|
||||||
data: &'preprocess [PreprocessedElementStored],
|
data: &'preprocess [PreprocessedElement],
|
||||||
current_start_idx: usize,
|
current_start_idx: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,11 +153,11 @@ impl<'pre> Iterator for Lines<'pre> {
|
||||||
let mut number_of_words = 0;
|
let mut number_of_words = 0;
|
||||||
|
|
||||||
while let Some(next) = self.data.get(self.current_start_idx + line_idx_length) {
|
while let Some(next) = self.data.get(self.current_start_idx + line_idx_length) {
|
||||||
match next.parse() {
|
match next {
|
||||||
PreprocessedElement::Word(pixels) => {
|
PreprocessedElement::Word(word) => {
|
||||||
let additional_space_width =
|
let additional_space_width =
|
||||||
additional_space_count as i32 * self.minimum_space_width;
|
additional_space_count as i32 * self.minimum_space_width;
|
||||||
let width = pixels as i32;
|
let width = word.pixels();
|
||||||
if width + current_line_width + additional_space_width > self.layout_width {
|
if width + current_line_width + additional_space_width > self.layout_width {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -173,12 +195,9 @@ impl Preprocessed {
|
||||||
Default::default()
|
Default::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get(&self, idx: usize) -> PreprocessedElement {
|
pub(crate) fn add_character(&mut self, font: &Font, c: char, sprite_width: i32) {
|
||||||
self.widths[idx].parse()
|
self.preprocessor
|
||||||
}
|
.add_character(font, c, sprite_width, &mut self.widths);
|
||||||
|
|
||||||
pub(crate) fn add_character(&mut self, font: &Font, c: char) {
|
|
||||||
self.preprocessor.add_character(font, c, &mut self.widths);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn lines(&self, layout_width: i32, minimum_space_width: i32) -> Lines<'_> {
|
pub(crate) fn lines(&self, layout_width: i32, minimum_space_width: i32) -> Lines<'_> {
|
||||||
|
@ -190,17 +209,17 @@ impl Preprocessed {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lines_element(
|
pub(crate) fn lines_element(
|
||||||
&self,
|
&self,
|
||||||
layout_width: i32,
|
layout_width: i32,
|
||||||
minimum_space_width: i32,
|
minimum_space_width: i32,
|
||||||
) -> impl Iterator<Item = &[PreprocessedElementStored]> {
|
) -> impl Iterator<Item = (Line, &[PreprocessedElement])> {
|
||||||
let mut idx = 0;
|
let mut idx = 0;
|
||||||
self.lines(layout_width, minimum_space_width).map(move |x| {
|
self.lines(layout_width, minimum_space_width).map(move |x| {
|
||||||
let length = x.number_of_text_elements;
|
let length = x.number_of_text_elements;
|
||||||
let d = &self.widths[idx..(idx + length)];
|
let d = &self.widths[idx..(idx + length)];
|
||||||
idx += length;
|
idx += length;
|
||||||
d
|
(x, d)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,6 +50,10 @@ pub(crate) struct WordRender {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WordRender {
|
impl WordRender {
|
||||||
|
pub(crate) fn sprite_width(&self) -> i32 {
|
||||||
|
self.config.sprite_size.to_width_height().0 as i32
|
||||||
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub(crate) fn new(config: Configuration) -> Self {
|
pub(crate) fn new(config: Configuration) -> Self {
|
||||||
WordRender {
|
WordRender {
|
||||||
|
|
Loading…
Reference in a new issue