text update for more code reuse + much better caching

This commit is contained in:
2025-09-29 13:45:48 -04:00
parent c98a43f94d
commit 628840d5cd
9 changed files with 319 additions and 273 deletions

View File

@@ -1,6 +1,6 @@
use crate::{
layout::{
Layers, Modules, TextAttrs, TextBuffer, TextData, TextOffset, TextureHandle, Textures,
Layers, Modules, TextAttrs, TextBuffer, TextData, TextTexture, TextureHandle, Textures,
UiRegion, UiVec2, Vec2, WidgetId, Widgets,
},
render::{Primitive, PrimitiveHandle},
@@ -29,7 +29,7 @@ pub struct PainterCtx<'a> {
pub screen_size: Vec2,
pub modules: &'a mut Modules,
pub px_dependent: &'a mut HashSet<Id>,
drawing: HashSet<Id>,
draw_started: HashSet<Id>,
}
pub struct WidgetInstance {
@@ -80,12 +80,14 @@ impl<'a> PainterCtx<'a> {
screen_size: data.output_size,
modules: &mut data.modules,
px_dependent: &mut data.px_dependent,
drawing: HashSet::default(),
draw_started: HashSet::default(),
}
}
pub fn redraw(&mut self, id: Id) {
self.drawing.clear();
if self.draw_started.contains(&id) {
return;
}
let Some(active) = self.active.get(&id) else {
return;
};
@@ -99,11 +101,13 @@ impl<'a> PainterCtx<'a> {
widgets: self.widgets,
region: UiRegion::full(),
screen_size: self.screen_size,
px_dependent: self.px_dependent,
id,
};
let desired = ctx.size_inner(id, active.region);
if size != desired {
self.redraw(rid);
if self.drawing.contains(&id) {
if self.draw_started.contains(&id) {
return;
}
}
@@ -124,7 +128,7 @@ impl<'a> PainterCtx<'a> {
}
pub fn draw(&mut self, id: Id) {
self.drawing.clear();
self.draw_started.clear();
self.layers.clear();
self.draw_inner(0, id, UiRegion::full(), None, None);
}
@@ -143,7 +147,7 @@ impl<'a> PainterCtx<'a> {
// but this has a very weird issue where you can't move widgets unless u remove first
// so swapping is impossible rn I think?
// there's definitely better solutions like a counter (>1 = panic) but don't care rn
if self.drawing.contains(&id) {
if self.draw_started.contains(&id) {
panic!("Cannot draw the same widget twice (1)");
}
let mut old_children = old_children.unwrap_or_default();
@@ -165,7 +169,7 @@ impl<'a> PainterCtx<'a> {
resize = active.resize;
}
self.drawing.insert(id);
self.draw_started.insert(id);
let mut painter = Painter {
region,
@@ -308,11 +312,7 @@ impl<'a, 'c> Painter<'a, 'c> {
}
/// returns (handle, offset from top left)
pub fn render_text(
&mut self,
buffer: &mut TextBuffer,
attrs: &TextAttrs,
) -> (TextureHandle, TextOffset) {
pub fn render_text(&mut self, buffer: &mut TextBuffer, attrs: &TextAttrs) -> TextTexture {
self.ctx.text.draw(buffer, attrs, self.ctx.textures)
}
@@ -331,6 +331,8 @@ impl<'a, 'c> Painter<'a, 'c> {
widgets: self.ctx.widgets,
checked: &mut self.sized_children,
screen_size: self.ctx.screen_size,
px_dependent: self.ctx.px_dependent,
id: self.id,
region: self.region,
}
}
@@ -357,9 +359,11 @@ pub struct SizeCtx<'a> {
pub text: &'a mut TextData,
pub textures: &'a mut Textures,
widgets: &'a Widgets,
px_dependent: &'a mut HashSet<Id>,
checked: &'a mut HashMap<Id, UiVec2>,
region: UiRegion,
screen_size: Vec2,
id: Id,
}
impl SizeCtx<'_> {
@@ -381,14 +385,11 @@ impl SizeCtx<'_> {
pub fn size_within<W>(&mut self, id: &WidgetId<W>, region: UiRegion) -> UiVec2 {
self.size_inner(id.id, region.within(&self.region))
}
pub fn px_size(&self) -> Vec2 {
pub fn px_size(&mut self) -> Vec2 {
self.px_dependent.insert(self.id);
self.region.in_size(self.screen_size)
}
pub fn draw_text(
&mut self,
buffer: &mut TextBuffer,
attrs: &TextAttrs,
) -> (TextureHandle, TextOffset) {
pub fn draw_text(&mut self, buffer: &mut TextBuffer, attrs: &TextAttrs) -> TextTexture {
self.text.draw(buffer, attrs, self.textures)
}
}

View File

@@ -2,7 +2,7 @@ use cosmic_text::{Attrs, AttrsList, Buffer, Family, FontSystem, Metrics, SwashCa
use image::{Rgba, RgbaImage};
use crate::{
layout::{TextureHandle, Textures, UiColor, Vec2},
layout::{Align, TextureHandle, Textures, UiColor, Vec2},
util::HashMap,
};
@@ -27,6 +27,8 @@ pub struct TextAttrs {
pub line_height: f32,
pub family: Family<'static>,
pub wrap: bool,
/// inner alignment of text region (within where its drawn)
pub align: Align,
}
impl TextAttrs {
@@ -56,6 +58,7 @@ impl Default for TextAttrs {
line_height: size * 1.2,
family: Family::SansSerif,
wrap: false,
align: Align::Center,
}
}
}
@@ -66,7 +69,11 @@ impl TextData {
buffer: &mut TextBuffer,
attrs: &TextAttrs,
textures: &mut Textures,
) -> (TextureHandle, TextOffset) {
) -> TextTexture {
// TODO: either this or the layout stuff (or both) is super slow,
// should probably do texture packing and things if possible.
// very visible if you add just a couple of wrapping texts and resize window
// should also be timed to figure out exactly what points need to be sped up
let mut pixels = HashMap::default();
let mut min_x = 0;
let mut min_y = 0;
@@ -113,22 +120,23 @@ impl TextData {
let y = (y - min_y) as u32;
image.put_pixel(x, y, color);
}
let offset = TextOffset {
TextTexture {
handle: textures.add(image),
top_left: Vec2::new(min_x as f32, min_y as f32),
bot_right: Vec2::new(max_width - max_x as f32, height - max_y as f32),
};
(textures.add(image), offset)
}
}
}
#[derive(Clone, Copy)]
pub struct TextOffset {
#[derive(Clone)]
pub struct TextTexture {
pub handle: TextureHandle,
pub top_left: Vec2,
pub bot_right: Vec2,
}
impl TextOffset {
pub fn size(&self, handle: &TextureHandle) -> Vec2 {
handle.size() - self.top_left + self.bot_right
impl TextTexture {
pub fn size(&self) -> Vec2 {
self.handle.size() - self.top_left + self.bot_right
}
}

View File

@@ -14,6 +14,7 @@ use std::{
};
pub struct Ui {
// TODO: make this at least pub(super)
pub(crate) data: PainterData,
root: Option<WidgetId>,
updates: Vec<Id>,