use std::collections::BTreeMap;
use std::fmt::Write as _;
use crate::ir::*;
pub fn shader_manifest(ops: &[DrawOp]) -> String {
let mut by_shader: BTreeMap<String, Vec<&DrawOp>> = BTreeMap::new();
for op in ops {
if let Some(handle) = op.shader() {
by_shader.entry(handle.name()).or_default().push(op);
}
}
let mut s = String::new();
if by_shader.is_empty() {
s.push_str("no shaders\n");
return s;
}
for (name, group) in &by_shader {
let _ = writeln!(s, "{name} used {} times", group.len());
for op in group {
match op {
DrawOp::Quad { id, uniforms, .. } => {
let _ = write!(s, " {id}");
for (k, v) in uniforms {
let _ = write!(s, " {k}={}", v.debug_short());
}
s.push('\n');
}
DrawOp::GlyphRun {
id,
color,
text,
size,
family,
weight,
mono,
wrap,
anchor,
..
} => {
let preview: String = text.chars().take(28).collect();
let suffix = if text.chars().count() > 28 { "…" } else { "" };
let _ = write!(
s,
" {id} text=\"{preview}{suffix}\" color={} size={size:.1} family={family:?} weight={weight:?} mono={mono} wrap={wrap:?} anchor={anchor:?}",
color_label(*color),
);
s.push('\n');
}
DrawOp::AttributedText {
id,
runs,
size,
wrap,
anchor,
..
} => {
let concat: String = runs.iter().map(|(t, _)| t.as_str()).collect();
let preview: String = concat.chars().take(28).collect();
let suffix = if concat.chars().count() > 28 {
"…"
} else {
""
};
let _ = write!(
s,
" {id} attr=\"{preview}{suffix}\" runs={} size={size:.1} wrap={wrap:?} anchor={anchor:?}",
runs.len(),
);
s.push('\n');
}
DrawOp::Icon { .. } => {}
DrawOp::Image { .. } => {} DrawOp::AppTexture { .. } => {} DrawOp::Vector { .. } => {} DrawOp::BackdropSnapshot => {}
}
}
s.push('\n');
}
s
}
pub fn draw_ops_text(ops: &[DrawOp]) -> String {
let mut s = String::new();
for op in ops {
match op {
DrawOp::Quad {
id,
rect,
scissor,
shader,
uniforms,
} => {
let _ = write!(
s,
"Quad shader={:<24} rect=({:.0},{:.0},{:.0},{:.0}) id={id}",
shader.name(),
rect.x,
rect.y,
rect.w,
rect.h,
);
if let Some(sci) = scissor {
write_scissor(&mut s, *sci);
}
for (k, v) in uniforms {
let _ = write!(s, " {k}={}", v.debug_short());
}
s.push('\n');
}
DrawOp::GlyphRun {
id,
rect,
scissor,
shader,
color,
text,
size,
line_height,
family,
mono_family,
weight,
mono,
wrap,
anchor,
layout: _,
underline: _,
strikethrough: _,
link: _,
} => {
let preview: String = text.chars().take(40).collect();
let suffix = if text.chars().count() > 40 { "…" } else { "" };
let face = if *mono { *mono_family } else { *family };
let _ = write!(
s,
"Glyph shader={:<24} rect=({:.0},{:.0},{:.0},{:.0}) id={id} text=\"{preview}{suffix}\" color={} size={size:.1} line_height={line_height:.1} family={face:?} weight={weight:?} mono={mono} wrap={wrap:?} anchor={anchor:?}",
shader.name(),
rect.x,
rect.y,
rect.w,
rect.h,
color_label(*color),
);
if let Some(sci) = scissor {
write_scissor(&mut s, *sci);
}
s.push('\n');
}
DrawOp::AttributedText {
id,
rect,
scissor,
shader,
runs,
size,
line_height,
wrap,
anchor,
layout: _,
} => {
let concat: String = runs.iter().map(|(t, _)| t.as_str()).collect();
let preview: String = concat.chars().take(40).collect();
let suffix = if concat.chars().count() > 40 {
"…"
} else {
""
};
let bg_runs = runs.iter().filter(|(_, st)| st.bg.is_some()).count();
let _ = write!(
s,
"Attr shader={:<24} rect=({:.0},{:.0},{:.0},{:.0}) id={id} attr=\"{preview}{suffix}\" runs={} bg_runs={bg_runs} size={size:.1} line_height={line_height:.1} wrap={wrap:?} anchor={anchor:?}",
shader.name(),
rect.x,
rect.y,
rect.w,
rect.h,
runs.len(),
);
if let Some(sci) = scissor {
write_scissor(&mut s, *sci);
}
s.push('\n');
}
DrawOp::Icon {
id,
rect,
scissor,
source,
color,
size,
stroke_width,
} => {
let _ = write!(
s,
"Icon name={:<24} rect=({:.0},{:.0},{:.0},{:.0}) id={id} color={} size={size:.1} stroke_width={stroke_width:.1}",
source.label(),
rect.x,
rect.y,
rect.w,
rect.h,
color_label(*color),
);
if let Some(sci) = scissor {
write_scissor(&mut s, *sci);
}
s.push('\n');
}
DrawOp::Image {
id,
rect,
scissor,
image,
tint,
radius,
fit,
} => {
let tint_str = match tint {
Some(c) => color_label(*c),
None => "none".to_string(),
};
let _ = write!(
s,
"Image src={:<24} rect=({:.0},{:.0},{:.0},{:.0}) id={id} natural=({}x{}) fit={fit:?} tint={tint_str} radius=({:.1},{:.1},{:.1},{:.1})",
image.label(),
rect.x,
rect.y,
rect.w,
rect.h,
image.width(),
image.height(),
radius.tl,
radius.tr,
radius.br,
radius.bl,
);
if let Some(sci) = scissor {
write_scissor(&mut s, *sci);
}
s.push('\n');
}
DrawOp::AppTexture {
id,
rect,
scissor,
texture,
alpha,
fit,
transform,
} => {
let (tw, th) = texture.size_px();
let format = texture.format();
let _ = write!(
s,
"Surface tex_id={:<10} rect=({:.0},{:.0},{:.0},{:.0}) id={id} natural=({tw}x{th}) format={format:?} fit={fit:?} alpha={alpha:?}",
texture.id().0,
rect.x,
rect.y,
rect.w,
rect.h,
);
if !transform.is_identity() {
let _ = write!(
s,
" transform=({:.3},{:.3},{:.3},{:.3},{:.3},{:.3})",
transform.a,
transform.b,
transform.c,
transform.d,
transform.tx,
transform.ty,
);
}
if let Some(sci) = scissor {
write_scissor(&mut s, *sci);
}
s.push('\n');
}
DrawOp::Vector {
id,
rect,
scissor,
asset,
render_mode,
} => {
let [_, _, vw, vh] = asset.view_box;
let _ = write!(
s,
"Vector hash={:016x} mode={render_mode:?} rect=({:.0},{:.0},{:.0},{:.0}) id={id} view_box=({vw}x{vh}) paths={}",
asset.content_hash(),
rect.x,
rect.y,
rect.w,
rect.h,
asset.paths.len(),
);
if let Some(sci) = scissor {
write_scissor(&mut s, *sci);
}
s.push('\n');
}
DrawOp::BackdropSnapshot => {
let _ = writeln!(s, "BackdropSnapshot");
}
}
}
s
}
fn color_label(c: crate::tree::Color) -> String {
match c.token {
Some(name) => name.to_string(),
None => format!("rgba({},{},{},{})", c.r, c.g, c.b, c.a),
}
}
fn write_scissor(s: &mut String, scissor: crate::tree::Rect) {
let _ = write!(
s,
" scissor=({:.0},{:.0},{:.0},{:.0})",
scissor.x, scissor.y, scissor.w, scissor.h,
);
}