GlyphCache
This commit is contained in:
parent
d4591ddbb9
commit
9cd5aa3822
194
src/text.rs
194
src/text.rs
|
@ -3,67 +3,126 @@ use super::{DrawCommand, MeshIndex, MeshVertex};
|
|||
use allsorts::binary::read::ReadScope;
|
||||
use allsorts::cff::CFF;
|
||||
use allsorts::font::{GlyphTableFlags, MatchingPresentation};
|
||||
use allsorts::font_data::FontData;
|
||||
use allsorts::font_data::{DynamicFontTableProvider, FontData};
|
||||
use allsorts::glyph_position::{GlyphLayout, TextDirection};
|
||||
use allsorts::outline::OutlineBuilder;
|
||||
use allsorts::pathfinder_geometry::{line_segment::LineSegment2F, vector::Vector2F};
|
||||
use allsorts::tables::{glyf::GlyfTable, loca::LocaTable};
|
||||
use allsorts::tables::{FontTableProvider, SfntVersion};
|
||||
use allsorts::{tag, Font};
|
||||
use std::collections::HashMap;
|
||||
use lyon::path::Path;
|
||||
|
||||
const TEXT_SCALE: f32 = 0.0001;
|
||||
|
||||
pub struct GlyphCache {
|
||||
glyphs: HashMap<u16, CachedGlyph>,
|
||||
glyphs: Vec<CachedGlyph>,
|
||||
}
|
||||
|
||||
impl GlyphCache {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
glyphs: Default::default(),
|
||||
pub fn new(font: &mut Font<DynamicFontTableProvider>) -> Self {
|
||||
let glyph_num = font.num_glyphs();
|
||||
let mut glyphs = Vec::with_capacity(glyph_num as usize);
|
||||
|
||||
if font.glyph_table_flags.contains(GlyphTableFlags::CFF)
|
||||
&& font.font_table_provider.sfnt_version() == tag::OTTO
|
||||
{
|
||||
let cff_data = font.font_table_provider.read_table_data(tag::CFF).unwrap();
|
||||
let mut cff = ReadScope::new(&cff_data).read::<CFF<'_>>().unwrap();
|
||||
for index in 0..glyph_num {
|
||||
glyphs.push(CachedGlyph::new(&mut cff, index));
|
||||
}
|
||||
} else if font.glyph_table_flags.contains(GlyphTableFlags::GLYF) {
|
||||
let loca_data = font.font_table_provider.read_table_data(tag::LOCA).unwrap();
|
||||
let loca = ReadScope::new(&loca_data)
|
||||
.read_dep::<LocaTable<'_>>((
|
||||
usize::from(font.maxp_table.num_glyphs),
|
||||
font.head_table().unwrap().unwrap().index_to_loc_format,
|
||||
))
|
||||
.unwrap();
|
||||
let glyf_data = font.font_table_provider.read_table_data(tag::GLYF).unwrap();
|
||||
let mut glyf = ReadScope::new(&glyf_data)
|
||||
.read_dep::<GlyfTable<'_>>(&loca)
|
||||
.unwrap();
|
||||
|
||||
for index in 0..glyph_num {
|
||||
glyphs.push(CachedGlyph::new(&mut glyf, index));
|
||||
}
|
||||
} else {
|
||||
panic!("no glyf or CFF table");
|
||||
}
|
||||
|
||||
Self { glyphs }
|
||||
}
|
||||
|
||||
pub fn write_glyph(&mut self, builder: &mut impl OutlineBuilder, index: u16) {
|
||||
let mut sink = OutlineSink::new();
|
||||
builder.visit(index, &mut sink).unwrap();
|
||||
let path = sink.builder.build();
|
||||
pub fn draw(&mut self, mesh: &mut DummyText, index: u16, xpos: i32, ypos: i32) {
|
||||
let glyph = self.glyphs.get_mut(index as usize).unwrap().get_mesh();
|
||||
let voff = mesh.vertices.len() as MeshIndex;
|
||||
let xoff = (xpos as f32) * TEXT_SCALE;
|
||||
let yoff = (ypos as f32) * TEXT_SCALE;
|
||||
|
||||
use lyon::tessellation::*;
|
||||
let mut geometry: VertexBuffers<MeshVertex, MeshIndex> = VertexBuffers::new();
|
||||
let mut tessellator = FillTessellator::new();
|
||||
for v in glyph.vertices.iter() {
|
||||
let x = v.position.x + xoff - 0.9;
|
||||
let y = v.position.y + yoff + 0.5;
|
||||
mesh.vertices.push(MeshVertex {
|
||||
position: canary_types::Vec2 { x, y },
|
||||
color: v.color,
|
||||
});
|
||||
}
|
||||
|
||||
tessellator
|
||||
.tessellate_path(
|
||||
&path,
|
||||
&FillOptions::default(),
|
||||
&mut BuffersBuilder::new(&mut geometry, |vertex: FillVertex| {
|
||||
let position = vertex.position() * TEXT_SCALE;
|
||||
let position = canary_types::Vec2 {
|
||||
x: position.x,
|
||||
y: position.y,
|
||||
};
|
||||
|
||||
MeshVertex {
|
||||
position,
|
||||
color: canary_types::Color::WHITE,
|
||||
}
|
||||
}),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
self.glyphs.insert(
|
||||
index,
|
||||
CachedGlyph {
|
||||
vertices: geometry.vertices,
|
||||
indices: geometry.indices,
|
||||
},
|
||||
);
|
||||
for i in glyph.indices.iter() {
|
||||
mesh.indices.push(i + voff);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CachedGlyph {
|
||||
path: Path,
|
||||
mesh: Option<GlyphMesh>,
|
||||
}
|
||||
|
||||
impl CachedGlyph {
|
||||
pub fn new(builder: &mut impl OutlineBuilder, index: u16) -> Self {
|
||||
let mut sink = OutlineSink::new();
|
||||
builder.visit(index, &mut sink).unwrap();
|
||||
let path = sink.builder.build();
|
||||
|
||||
Self { path, mesh: None }
|
||||
}
|
||||
|
||||
pub fn get_mesh(&mut self) -> &GlyphMesh {
|
||||
self.mesh.get_or_insert_with(|| {
|
||||
use lyon::tessellation::*;
|
||||
|
||||
let mut geometry: VertexBuffers<MeshVertex, MeshIndex> = VertexBuffers::new();
|
||||
let mut tessellator = FillTessellator::new();
|
||||
tessellator
|
||||
.tessellate_path(
|
||||
&self.path.clone(),
|
||||
&FillOptions::default(),
|
||||
&mut BuffersBuilder::new(&mut geometry, |vertex: FillVertex| {
|
||||
let position = vertex.position() * TEXT_SCALE;
|
||||
let position = canary_types::Vec2 {
|
||||
x: position.x,
|
||||
y: position.y,
|
||||
};
|
||||
|
||||
MeshVertex {
|
||||
position,
|
||||
color: canary_types::Color::WHITE,
|
||||
}
|
||||
}),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
GlyphMesh {
|
||||
vertices: geometry.vertices,
|
||||
indices: geometry.indices,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct GlyphMesh {
|
||||
vertices: Vec<MeshVertex>,
|
||||
indices: Vec<MeshIndex>,
|
||||
}
|
||||
|
@ -82,43 +141,10 @@ impl Default for DummyText {
|
|||
let font_file = scope.read::<FontData<'_>>().unwrap();
|
||||
let provider = font_file.table_provider(0).unwrap();
|
||||
let mut font = Font::new(provider).unwrap().unwrap();
|
||||
|
||||
let mut cache = GlyphCache::new(&mut font);
|
||||
let text = "toki o! nimi mi li [_mun_alasa_sona]. toki+pona li pona.";
|
||||
let glyphs = font.map_glyphs(&text, script, MatchingPresentation::Required);
|
||||
|
||||
let mut cache = GlyphCache::new();
|
||||
|
||||
if font.glyph_table_flags.contains(GlyphTableFlags::CFF)
|
||||
&& font.font_table_provider.sfnt_version() == tag::OTTO
|
||||
{
|
||||
let cff_data = font.font_table_provider.read_table_data(tag::CFF).unwrap();
|
||||
let mut cff = ReadScope::new(&cff_data).read::<CFF<'_>>().unwrap();
|
||||
|
||||
println!("warming cache with {} glyphs", font.num_glyphs());
|
||||
for index in 0..font.num_glyphs() {
|
||||
cache.write_glyph(&mut cff, index);
|
||||
}
|
||||
} else if font.glyph_table_flags.contains(GlyphTableFlags::GLYF) {
|
||||
let loca_data = font.font_table_provider.read_table_data(tag::LOCA).unwrap();
|
||||
let loca = ReadScope::new(&loca_data)
|
||||
.read_dep::<LocaTable<'_>>((
|
||||
usize::from(font.maxp_table.num_glyphs),
|
||||
font.head_table().unwrap().unwrap().index_to_loc_format,
|
||||
))
|
||||
.unwrap();
|
||||
let glyf_data = font.font_table_provider.read_table_data(tag::GLYF).unwrap();
|
||||
let mut glyf = ReadScope::new(&glyf_data)
|
||||
.read_dep::<GlyfTable<'_>>(&loca)
|
||||
.unwrap();
|
||||
|
||||
println!("warming cache with {} glyphs", font.num_glyphs());
|
||||
for index in 0..font.num_glyphs() {
|
||||
cache.write_glyph(&mut glyf, index);
|
||||
}
|
||||
} else {
|
||||
panic!("no glyf or CFF table");
|
||||
}
|
||||
|
||||
let lang_tag = None;
|
||||
let features = allsorts::gsub::Features::default();
|
||||
let kerning = true;
|
||||
|
@ -143,27 +169,7 @@ impl Default for DummyText {
|
|||
let ypos = ycur + position.y_offset;
|
||||
xcur += position.hori_advance;
|
||||
ycur += position.vert_advance;
|
||||
|
||||
println!("({}, {}): {:#?}", xpos, ypos, glyph);
|
||||
|
||||
// TODO refactor
|
||||
let glyph = cache.glyphs.get(&glyph.glyph.glyph_index).unwrap();
|
||||
let voff = mesh.vertices.len() as MeshIndex;
|
||||
let xoff = (xpos as f32) * TEXT_SCALE;
|
||||
let yoff = (ypos as f32) * TEXT_SCALE;
|
||||
|
||||
for v in glyph.vertices.iter() {
|
||||
let x = v.position.x + xoff - 0.9;
|
||||
let y = v.position.y + yoff + 0.5;
|
||||
mesh.vertices.push(MeshVertex {
|
||||
position: canary_types::Vec2 { x, y },
|
||||
color: v.color,
|
||||
});
|
||||
}
|
||||
|
||||
for i in glyph.indices.iter() {
|
||||
mesh.indices.push(i + voff);
|
||||
}
|
||||
cache.draw(&mut mesh, glyph.glyph.glyph_index, xpos, ypos);
|
||||
}
|
||||
|
||||
mesh
|
||||
|
|
Loading…
Reference in New Issue