mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-24 09:46:59 -06:00
Symbols: thumbnails work out the document's resource key once per panel frame, not per tile
Review follow-up (CodeRabbit): each thumbnail hashed every symbol's and pattern's art before its texture cache lookup, so a panel frame cost visible tiles × (symbols + patterns) even when every thumbnail was cached. The Symbols panel works the key out once per frame, a symbol library panel once per library it shows, and the dragged chip once; thumbnails take it as given.
This commit is contained in:
committed by
bflatastic
parent
f6715487c0
commit
5c8e440ab5
@@ -609,11 +609,11 @@ pub(crate) fn drag_preview(app: &VectorcraftApp, ctx: &egui::Context) {
|
||||
},
|
||||
PanelDrag::GraphicStyle(name) => return pointer_chip(ctx, |ui, r| super::graphic_styles::paint_style(app, ui, r, name)),
|
||||
PanelDrag::Symbol(name) => match app.session.active() {
|
||||
Some(st) => return pointer_chip(ctx, |ui, r| super::symbols::chip(ui, &st.doc, r, name)),
|
||||
Some(st) => return pointer_chip(ctx, |ui, r| super::symbols::chip(ui, &st.doc, super::symbols::resources_key(&st.doc), r, name)),
|
||||
None => return,
|
||||
},
|
||||
PanelDrag::LibrarySymbol { library, name } => match vectorcraft_engine::cmd::symbollib::library(&app.session, library) {
|
||||
Some((_, lib)) => return pointer_chip(ctx, |ui, r| super::symbols::chip(ui, &lib.doc, r, name)),
|
||||
Some((_, lib)) => return pointer_chip(ctx, |ui, r| super::symbols::chip(ui, &lib.doc, super::symbols::resources_key(&lib.doc), r, name)),
|
||||
None => return,
|
||||
},
|
||||
PanelDrag::Brush { def, .. } => return pointer_chip(ctx, |ui, r| super::brushes::chip(ui, r, def)),
|
||||
|
||||
@@ -20,15 +20,15 @@ use crate::theme::Tokens;
|
||||
use crate::widgets::{self, PanelDrag, menu_item};
|
||||
|
||||
/// A thumbnail of symbol `name` (an instance at its natural size), cached by the identity of the
|
||||
/// art it shows: its own and that of the symbols and patterns it may use.
|
||||
fn thumb(ui: &Ui, doc: &Document, name: &str, size: f32) -> Option<egui::TextureHandle> {
|
||||
/// art it shows: its own and `resources`, [`resources_key`] of `doc`.
|
||||
fn thumb(ui: &Ui, doc: &Document, resources: u64, name: &str, size: f32) -> Option<egui::TextureHandle> {
|
||||
thread_local! {
|
||||
static RENDERER: RefCell<vectorcraft_render::Renderer> = RefCell::new(vectorcraft_render::Renderer::new());
|
||||
static CACHE: crate::graphics::TexCache<HashMap<(usize, u64, String, u32), egui::TextureHandle>> = crate::graphics::TexCache::default();
|
||||
}
|
||||
let sym = doc.symbols.iter().find(|s| s.name == name)?;
|
||||
let px = (size * ui.ctx().pixels_per_point()).round().max(8.0) as u32;
|
||||
let key = (Arc::as_ptr(&sym.art) as usize, resources_key(doc), name.to_string(), px);
|
||||
let key = (Arc::as_ptr(&sym.art) as usize, resources, name.to_string(), px);
|
||||
if let Some(t) = CACHE.with(|c| c.borrow().get(&key).cloned()) {
|
||||
return Some(t);
|
||||
}
|
||||
@@ -45,8 +45,9 @@ fn thumb(ui: &Ui, doc: &Document, name: &str, size: f32) -> Option<egui::Texture
|
||||
Some(tex)
|
||||
}
|
||||
|
||||
/// The identity of `doc`'s symbol and pattern art, which a symbol's thumbnail may show.
|
||||
fn resources_key(doc: &Document) -> u64 {
|
||||
/// The identity of `doc`'s symbol and pattern art, which a symbol's thumbnail may show. It takes a
|
||||
/// pass over them: work it out once per panel frame, not per thumbnail.
|
||||
pub(crate) fn resources_key(doc: &Document) -> u64 {
|
||||
use std::hash::{Hash, Hasher};
|
||||
let mut h = std::collections::hash_map::DefaultHasher::new();
|
||||
for s in &doc.symbols {
|
||||
@@ -73,10 +74,10 @@ fn render_thumb(r: &mut vectorcraft_render::Renderer, doc: &Document, name: &str
|
||||
}
|
||||
|
||||
/// Symbol `name`'s thumbnail on white in `r` (the panel's tiles and the chip a dragged symbol
|
||||
/// shows at the pointer).
|
||||
pub(crate) fn chip(ui: &Ui, doc: &Document, r: egui::Rect, name: &str) {
|
||||
/// shows at the pointer); `resources` is [`resources_key`] of `doc`.
|
||||
pub(crate) fn chip(ui: &Ui, doc: &Document, resources: u64, r: egui::Rect, name: &str) {
|
||||
ui.painter().rect_filled(r, 0.0, egui::Color32::WHITE);
|
||||
if let Some(tex) = thumb(ui, doc, name, r.width()) {
|
||||
if let Some(tex) = thumb(ui, doc, resources, name, r.width()) {
|
||||
ui.painter().image(tex.id(), r, egui::Rect::from_min_max(egui::pos2(0.0, 0.0), egui::pos2(1.0, 1.0)), egui::Color32::WHITE);
|
||||
}
|
||||
}
|
||||
@@ -101,6 +102,7 @@ pub fn show(app: &mut VectorcraftApp, ui: &mut Ui) {
|
||||
let t = Tokens::get(ui.ctx());
|
||||
let Some(doc) = app.session.active().map(|d| d.doc.clone()) else { return };
|
||||
let names: Vec<String> = doc.symbols.iter().map(|s| s.name.clone()).collect();
|
||||
let resources = resources_key(&doc);
|
||||
let list: bool = pstate(ui.ctx(), "sym-list");
|
||||
let sel = current(app);
|
||||
let mut clicked: Option<(String, bool)> = None;
|
||||
@@ -121,7 +123,7 @@ pub fn show(app: &mut VectorcraftApp, ui: &mut Ui) {
|
||||
} else if resp.hovered() {
|
||||
ui.painter().rect_filled(r, 0.0, t.hover);
|
||||
}
|
||||
chip(ui, &doc, egui::Rect::from_center_size(r.left_center() + vec2(14.0, 0.0), vec2(22.0, 22.0)), n);
|
||||
chip(ui, &doc, resources, egui::Rect::from_center_size(r.left_center() + vec2(14.0, 0.0), vec2(22.0, 22.0)), n);
|
||||
ui.painter().text(r.left_center() + vec2(32.0, 0.0), egui::Align2::LEFT_CENTER, n, egui::FontId::proportional(12.5), t.text);
|
||||
if resp.double_clicked() {
|
||||
clicked = Some((n.clone(), true));
|
||||
@@ -134,7 +136,7 @@ pub fn show(app: &mut VectorcraftApp, ui: &mut Ui) {
|
||||
for n in &names {
|
||||
let (r, resp) = ui.allocate_exact_size(vec2(44.0, 44.0), Sense::click_and_drag());
|
||||
widgets::drag_source(ui, &resp, || PanelDrag::Symbol(n.clone()));
|
||||
chip(ui, &doc, r.shrink(2.0), n);
|
||||
chip(ui, &doc, resources, r.shrink(2.0), n);
|
||||
let on = sel.as_deref() == Some(n.as_str());
|
||||
ui.painter().rect_stroke(
|
||||
r,
|
||||
@@ -245,6 +247,8 @@ fn save_library(app: &mut VectorcraftApp, names: Vec<String>) {
|
||||
pub(crate) struct LibSymbol {
|
||||
lib: Arc<SymbolLibrary>,
|
||||
index: usize,
|
||||
/// [`resources_key`] of the library's document.
|
||||
resources: u64,
|
||||
}
|
||||
|
||||
impl LibSymbol {
|
||||
@@ -274,7 +278,8 @@ impl LibraryKind for SymbolLibraries {
|
||||
}
|
||||
fn get(app: &VectorcraftApp, id: &str) -> Option<(String, Self::Lib)> {
|
||||
let (info, lib) = symbollib::library(&app.session, id)?;
|
||||
let shown = (0..lib.len()).map(|index| LibSymbol { lib: lib.clone(), index }).collect();
|
||||
let resources = resources_key(&lib.doc);
|
||||
let shown = (0..lib.len()).map(|index| LibSymbol { lib: lib.clone(), index, resources }).collect();
|
||||
Some((info.name, Arc::new(shown)))
|
||||
}
|
||||
fn find(app: &VectorcraftApp, key: &str) -> library_panel::Found {
|
||||
@@ -289,7 +294,7 @@ impl LibraryKind for SymbolLibraries {
|
||||
}
|
||||
/// The symbol's art on white, as the Symbols panel shows it.
|
||||
fn draw(_: &VectorcraftApp, ui: &Ui, r: egui::Rect, s: &LibSymbol, selected: bool, hovered: bool) {
|
||||
chip(ui, &s.lib.doc, r, s.name());
|
||||
chip(ui, &s.lib.doc, s.resources, r, s.name());
|
||||
super::graphic_styles::outline(ui, r, selected, hovered);
|
||||
}
|
||||
fn row_icons(_: &Ui, _: egui::Rect, _: &LibSymbol) {}
|
||||
|
||||
Reference in New Issue
Block a user