2022-01-22 10:23:12 +00:00
|
|
|
use crate::{AlphaImage, ImageDelta};
|
|
|
|
|
|
|
|
#[derive(Clone, Copy, Eq, PartialEq)]
|
|
|
|
struct Rectu {
|
|
|
|
/// inclusive
|
|
|
|
min_x: usize,
|
|
|
|
/// inclusive
|
|
|
|
min_y: usize,
|
|
|
|
/// exclusive
|
|
|
|
max_x: usize,
|
|
|
|
/// exclusive
|
|
|
|
max_y: usize,
|
2019-01-16 23:09:12 +00:00
|
|
|
}
|
|
|
|
|
2022-01-22 10:23:12 +00:00
|
|
|
impl Rectu {
|
|
|
|
const NOTHING: Self = Self {
|
|
|
|
min_x: usize::MAX,
|
|
|
|
min_y: usize::MAX,
|
|
|
|
max_x: 0,
|
|
|
|
max_y: 0,
|
|
|
|
};
|
|
|
|
const EVERYTHING: Self = Self {
|
|
|
|
min_x: 0,
|
|
|
|
min_y: 0,
|
|
|
|
max_x: usize::MAX,
|
|
|
|
max_y: usize::MAX,
|
|
|
|
};
|
2019-01-16 23:09:12 +00:00
|
|
|
}
|
|
|
|
|
2020-07-23 12:35:12 +00:00
|
|
|
/// Contains font data in an atlas, where each character occupied a small rectangle.
|
|
|
|
///
|
|
|
|
/// More characters can be added, possibly expanding the texture.
|
2022-01-22 10:23:12 +00:00
|
|
|
#[derive(Clone)]
|
2019-01-12 23:10:53 +00:00
|
|
|
pub struct TextureAtlas {
|
2022-01-22 10:23:12 +00:00
|
|
|
image: AlphaImage,
|
|
|
|
/// What part of the image that is dirty
|
|
|
|
dirty: Rectu,
|
2019-01-12 23:10:53 +00:00
|
|
|
|
2021-01-03 17:03:11 +00:00
|
|
|
/// Used for when allocating new rectangles.
|
2019-01-12 23:10:53 +00:00
|
|
|
cursor: (usize, usize),
|
|
|
|
row_height: usize,
|
2022-01-24 13:32:36 +00:00
|
|
|
|
|
|
|
/// Set when someone requested more space than was available.
|
|
|
|
overflowed: bool,
|
2019-01-12 23:10:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl TextureAtlas {
|
2022-01-15 12:59:52 +00:00
|
|
|
pub fn new(size: [usize; 2]) -> Self {
|
2022-01-24 13:32:36 +00:00
|
|
|
assert!(size[0] >= 1024, "Tiny texture atlas");
|
2020-05-07 08:47:03 +00:00
|
|
|
Self {
|
2022-01-22 10:23:12 +00:00
|
|
|
image: AlphaImage::new(size),
|
|
|
|
dirty: Rectu::EVERYTHING,
|
|
|
|
cursor: (0, 0),
|
|
|
|
row_height: 0,
|
2022-01-24 13:32:36 +00:00
|
|
|
overflowed: false,
|
2019-01-12 23:10:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-22 10:23:12 +00:00
|
|
|
pub fn size(&self) -> [usize; 2] {
|
|
|
|
self.image.size
|
2019-01-12 23:10:53 +00:00
|
|
|
}
|
|
|
|
|
2022-01-24 13:32:36 +00:00
|
|
|
fn max_height(&self) -> usize {
|
|
|
|
// the initial width is likely the max texture side size
|
|
|
|
self.image.width()
|
|
|
|
}
|
|
|
|
|
|
|
|
/// When this get high, it might be time to clear and start over!
|
|
|
|
pub fn fill_ratio(&self) -> f32 {
|
|
|
|
if self.overflowed {
|
|
|
|
1.0
|
|
|
|
} else {
|
|
|
|
(self.cursor.1 + self.row_height) as f32 / self.max_height() as f32
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-22 10:23:12 +00:00
|
|
|
/// Call to get the change to the image since last call.
|
|
|
|
pub fn take_delta(&mut self) -> Option<ImageDelta> {
|
|
|
|
let dirty = std::mem::replace(&mut self.dirty, Rectu::NOTHING);
|
|
|
|
if dirty == Rectu::NOTHING {
|
|
|
|
None
|
|
|
|
} else if dirty == Rectu::EVERYTHING {
|
|
|
|
Some(ImageDelta::full(self.image.clone()))
|
|
|
|
} else {
|
|
|
|
let pos = [dirty.min_x, dirty.min_y];
|
|
|
|
let size = [dirty.max_x - dirty.min_x, dirty.max_y - dirty.min_y];
|
|
|
|
let region = self.image.region(pos, size);
|
|
|
|
Some(ImageDelta::partial(pos, region))
|
|
|
|
}
|
2019-01-12 23:10:53 +00:00
|
|
|
}
|
|
|
|
|
2022-01-22 10:23:12 +00:00
|
|
|
/// Returns the coordinates of where the rect ended up,
|
|
|
|
/// and invalidates the region.
|
|
|
|
pub fn allocate(&mut self, (w, h): (usize, usize)) -> ((usize, usize), &mut AlphaImage) {
|
2020-09-09 13:24:44 +00:00
|
|
|
/// On some low-precision GPUs (my old iPad) characters get muddled up
|
|
|
|
/// if we don't add some empty pixels between the characters.
|
2021-01-03 17:03:11 +00:00
|
|
|
/// On modern high-precision GPUs this is not needed.
|
2020-09-09 13:24:44 +00:00
|
|
|
const PADDING: usize = 1;
|
|
|
|
|
2021-02-23 11:03:20 +00:00
|
|
|
assert!(
|
2022-01-15 12:59:52 +00:00
|
|
|
w <= self.image.width(),
|
2021-02-23 11:03:20 +00:00
|
|
|
"Tried to allocate a {} wide glyph in a {} wide texture atlas",
|
|
|
|
w,
|
2022-01-15 12:59:52 +00:00
|
|
|
self.image.width()
|
2021-02-23 11:03:20 +00:00
|
|
|
);
|
2022-01-15 12:59:52 +00:00
|
|
|
if self.cursor.0 + w > self.image.width() {
|
2019-01-12 23:10:53 +00:00
|
|
|
// New row:
|
|
|
|
self.cursor.0 = 0;
|
2020-09-09 13:24:44 +00:00
|
|
|
self.cursor.1 += self.row_height + PADDING;
|
2019-01-12 23:10:53 +00:00
|
|
|
self.row_height = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
self.row_height = self.row_height.max(h);
|
2022-01-24 13:32:36 +00:00
|
|
|
|
|
|
|
let required_height = self.cursor.1 + self.row_height;
|
|
|
|
|
|
|
|
if required_height > self.max_height() {
|
|
|
|
// This is a bad place to be - we need to start reusing space :/
|
|
|
|
eprintln!("epaint texture atlas overflowed!");
|
|
|
|
self.cursor = (0, self.image.height() / 3); // Restart a bit down - the top of the atlas has too many important things in it
|
|
|
|
self.overflowed = true; // this will signal the user that we need to recreate the texture atlas next frame.
|
|
|
|
} else if resize_to_min_height(&mut self.image, required_height) {
|
2022-01-22 10:23:12 +00:00
|
|
|
self.dirty = Rectu::EVERYTHING;
|
|
|
|
}
|
2019-01-12 23:10:53 +00:00
|
|
|
|
|
|
|
let pos = self.cursor;
|
2020-09-09 13:24:44 +00:00
|
|
|
self.cursor.0 += w + PADDING;
|
2022-01-22 10:23:12 +00:00
|
|
|
|
|
|
|
self.dirty.min_x = self.dirty.min_x.min(pos.0);
|
|
|
|
self.dirty.min_y = self.dirty.min_y.min(pos.1);
|
|
|
|
self.dirty.max_x = self.dirty.max_x.max(pos.0 + w);
|
|
|
|
self.dirty.max_y = self.dirty.max_y.max(pos.1 + h);
|
|
|
|
|
|
|
|
(pos, &mut self.image)
|
2019-01-12 23:10:53 +00:00
|
|
|
}
|
|
|
|
}
|
2022-01-15 12:59:52 +00:00
|
|
|
|
2022-01-24 13:32:36 +00:00
|
|
|
fn resize_to_min_height(image: &mut AlphaImage, required_height: usize) -> bool {
|
|
|
|
while required_height >= image.height() {
|
2022-01-15 12:59:52 +00:00
|
|
|
image.size[1] *= 2; // double the height
|
|
|
|
}
|
|
|
|
|
|
|
|
if image.width() * image.height() > image.pixels.len() {
|
|
|
|
image.pixels.resize(image.width() * image.height(), 0);
|
2022-01-22 10:23:12 +00:00
|
|
|
true
|
|
|
|
} else {
|
|
|
|
false
|
2022-01-15 12:59:52 +00:00
|
|
|
}
|
|
|
|
}
|