use wgpu_glyph::{ab_glyph, Extra, SectionGlyph};
use super::{CustomWindow, DrawWindow};
use kas::draw::{Colour, Draw, DrawText, Pass};
use kas::geom::{Quad, Vec2};
use kas::text::fonts::{fonts, FontId};
use kas::text::{Effect, Glyph, TextDisplay};
fn to_point(Vec2(x, y): Vec2) -> ab_glyph::Point {
ab_glyph::Point { x, y }
}
fn ktv_to_point(kas::text::Vec2(x, y): kas::text::Vec2) -> ab_glyph::Point {
ab_glyph::Point { x, y }
}
impl<CW: CustomWindow + 'static> DrawText for DrawWindow<CW> {
fn prepare_fonts(&mut self) {
let fonts = fonts();
let n1 = self.glyph_brush.fonts().len();
let n2 = fonts.num_fonts();
if n2 > n1 {
let font_data = kas::text::fonts::fonts().font_data();
for i in n1..n2 {
let (data, index) = font_data.get_data(i);
let font = ab_glyph::FontRef::try_from_slice_and_index(data, index).unwrap();
let id = self.glyph_brush.add_font(font);
assert_eq!(id.0, i);
}
}
}
fn text(
&mut self,
pass: Pass,
pos: Vec2,
bounds: Vec2,
offset: Vec2,
text: &TextDisplay,
col: Colour,
) {
let time = std::time::Instant::now();
let ab_pos = to_point(pos);
let ab_offset = ab_pos - to_point(offset);
let mut glyphs = Vec::with_capacity(text.num_glyphs());
let for_glyph = |font_id: FontId, _, height: f32, glyph: Glyph| {
glyphs.push(SectionGlyph {
section_index: 0,
byte_index: 0, glyph: ab_glyph::Glyph {
id: ab_glyph::GlyphId(glyph.id.0),
scale: height.into(),
position: ab_offset + ktv_to_point(glyph.position),
},
font_id: wgpu_glyph::FontId(font_id.get()),
});
};
text.glyphs(for_glyph);
let min = ab_pos;
let max = ab_pos + to_point(bounds);
let bounds = ab_glyph::Rect { min, max };
let extra = vec![Extra {
color: col.into(),
z: pass.depth(),
}];
self.glyph_brush.queue_pre_positioned(glyphs, extra, bounds);
self.dur_text += time.elapsed();
}
fn text_col_effects(
&mut self,
pass: Pass,
pos: Vec2,
bounds: Vec2,
offset: Vec2,
text: &TextDisplay,
col: Colour,
effects: &[Effect<()>],
) {
if effects.len() <= 1
&& effects
.get(0)
.map(|e| e.flags == Default::default())
.unwrap_or(true)
{
return self.text(pass, pos, bounds, offset, text, col);
}
let time = std::time::Instant::now();
let ab_pos = to_point(pos);
let ab_offset = ab_pos - to_point(offset);
let mut glyphs = Vec::with_capacity(text.num_glyphs());
if effects.len() > 1
|| effects
.get(0)
.map(|e| *e != Default::default())
.unwrap_or(false)
{
let for_glyph = |font_id: FontId, _, height: f32, glyph: Glyph, _, _| {
glyphs.push(SectionGlyph {
section_index: 0,
byte_index: 0, glyph: ab_glyph::Glyph {
id: ab_glyph::GlyphId(glyph.id.0),
scale: height.into(),
position: ab_offset + ktv_to_point(glyph.position),
},
font_id: wgpu_glyph::FontId(font_id.get()),
});
};
let for_rect = |x1, x2, mut y, h: f32, _, _| {
let y2 = y + h;
if h < 1.0 {
y = y2 - 1.0;
}
let quad = Quad::with_coords(pos + Vec2(x1, y), pos + Vec2(x2, y2));
self.rect(pass, quad, col);
};
text.glyphs_with_effects(effects, for_glyph, for_rect);
} else {
let for_glyph = |font_id: FontId, _, height: f32, glyph: Glyph| {
glyphs.push(SectionGlyph {
section_index: 0,
byte_index: 0, glyph: ab_glyph::Glyph {
id: ab_glyph::GlyphId(glyph.id.0),
scale: height.into(),
position: ab_offset + ktv_to_point(glyph.position),
},
font_id: wgpu_glyph::FontId(font_id.get()),
});
};
text.glyphs(for_glyph);
}
let min = ab_pos;
let max = ab_pos + to_point(bounds);
let bounds = ab_glyph::Rect { min, max };
let extra = vec![Extra {
color: col.into(),
z: pass.depth(),
}];
self.glyph_brush.queue_pre_positioned(glyphs, extra, bounds);
self.dur_text += time.elapsed();
}
fn text_effects(
&mut self,
pass: Pass,
pos: Vec2,
bounds: Vec2,
offset: Vec2,
text: &TextDisplay,
effects: &[Effect<Colour>],
) {
if effects.len() <= 1
&& effects
.get(0)
.map(|e| e.flags == Default::default())
.unwrap_or(true)
{
let col = effects.get(0).map(|e| e.aux).unwrap_or(Colour::default());
return self.text(pass, pos, bounds, offset, text, col);
}
let time = std::time::Instant::now();
let ab_pos = to_point(pos);
let ab_offset = ab_pos - to_point(offset);
let mut glyphs = Vec::with_capacity(text.num_glyphs());
let mut extra = Vec::with_capacity(effects.len() + 1);
{
let mut index_incr = 0;
if effects.get(1).map(|e| e.start > 0).unwrap_or(true) {
index_incr = 1;
extra.push(Extra {
color: Colour::default().into(),
z: pass.depth(),
});
}
for e in effects {
extra.push(Extra {
color: e.aux.into(),
z: pass.depth(),
});
}
let for_glyph = |font_id: FontId, _, height: f32, glyph: Glyph, i: usize, _| {
glyphs.push(SectionGlyph {
section_index: i.wrapping_add(index_incr),
byte_index: 0, glyph: ab_glyph::Glyph {
id: ab_glyph::GlyphId(glyph.id.0),
scale: height.into(),
position: ab_offset + ktv_to_point(glyph.position),
},
font_id: wgpu_glyph::FontId(font_id.get()),
});
};
let for_rect = |x1, x2, mut y, h: f32, i: usize, _| {
let y2 = y + h;
if h < 1.0 {
y = y2 - 1.0;
}
let quad = Quad::with_coords(pos + Vec2(x1, y), pos + Vec2(x2, y2));
self.rect(pass, quad, effects[i].aux);
};
text.glyphs_with_effects(effects, for_glyph, for_rect);
}
let min = ab_pos;
let max = ab_pos + to_point(bounds);
let bounds = ab_glyph::Rect { min, max };
self.glyph_brush.queue_pre_positioned(glyphs, extra, bounds);
self.dur_text += time.elapsed();
}
}