Text rendering offset + scale + color

This commit is contained in:
marceline-cramer 2022-07-18 20:51:54 -06:00
parent bf6228f277
commit d617eaaf64
4 changed files with 79 additions and 43 deletions

View File

@ -35,18 +35,22 @@ impl PanelImpl for DummyPanel {
let ctx = draw::DrawContext::new(self.panel);
self.menu.draw(&ctx);
let layout = TextLayout::new("Hello, world!");
let bounds = layout.get_bounds();
let text = "Hello, world!";
let bg = Color::MAGENTA;
let fg = Color::BLACK;
let scale = 0.1;
let pos = Vec2::ZERO;
let bounds = draw::Rect {
bl: bounds.bl.into(),
tr: bounds.tr.into(),
let layout = TextLayout::new(text);
let bounds = layout.get_bounds();
let bounds = draw::Rect {
bl: Vec2::from(bounds.bl) * scale,
tr: Vec2::from(bounds.tr) * scale,
};
ctx.draw_rect(bounds, Color::MAGENTA);
ctx.draw_rect(bounds.offset(pos), bg);
let glyphs = layout.get_glyphs();
self.panel.draw_glyphs(glyphs.as_slice());
self.panel.draw_glyphs(&glyphs, pos.into(), scale, fg);
}
fn on_cursor_event(&mut self, kind: CursorEventKind, at: canary_script::Vec2) {

View File

@ -95,8 +95,20 @@ impl Panel {
}
}
pub fn draw_glyphs(&self, glyphs: &[GlyphPosition]) {
unsafe { draw_glyphs(glyphs.as_ptr() as u32, glyphs.len() as u32) }
pub fn draw_glyphs(&self, glyphs: &[GlyphPosition], offset: Vec2, scale: f32, color: Color) {
unsafe {
draw_glyphs(
glyphs.as_ptr() as u32,
glyphs.len() as u32,
offset.x,
offset.y,
scale,
color.r,
color.g,
color.b,
color.a,
)
}
}
pub fn draw_triangle(&self, v1: Vec2, v2: Vec2, v3: Vec2, color: Color) {
@ -157,7 +169,18 @@ impl Drop for TextLayout {
extern "C" {
fn draw_indexed(vertices_ptr: u32, vertices_num: u32, indices_ptr: u32, indices_num: u32);
fn draw_glyphs(glyphs_ptr: u32, glyphs_len: u32);
fn draw_glyphs(
glyphs_ptr: u32,
glyphs_len: u32,
xoff: f32,
yoff: f32,
scale: f32,
r: f32,
g: f32,
b: f32,
a: f32,
);
fn text_layout_new(text_ptr: u32, text_len: u32) -> u32;
fn text_layout_delete(id: u32);

View File

@ -11,7 +11,7 @@ pub mod text;
pub trait ScriptAbi {
fn start_draw(&self);
fn draw_indexed(&self, vertices: &[MeshVertex], indices: &[MeshIndex]);
fn draw_glyphs(&self, glyphs: &[GlyphPosition]);
fn draw_glyphs(&self, glyphs: &[GlyphPosition], offset: Vec2, scale: f32, color: Color);
fn with_draw_commands(&self, f: impl FnOnce(&[DrawCommand]));
fn text_layout_new(&self, text: &str) -> u32;
@ -105,9 +105,20 @@ impl<T: ScriptAbi> WasmtimeScript<T> {
linker.func_wrap(
module,
"draw_glyphs",
|mut caller: wasmtime::Caller<'_, T>, glyphs_ptr: u32, glyphs_num: u32| {
|mut caller: wasmtime::Caller<'_, T>,
glyphs_ptr: u32,
glyphs_num: u32,
xoff: f32,
yoff: f32,
scale: f32,
r: f32,
g: f32,
b: f32,
a: f32| {
let glyphs = Self::get_memory_slice(&mut caller, glyphs_ptr, glyphs_num);
caller.data().draw_glyphs(glyphs);
let offset = Vec2 { x: xoff, y: yoff };
let color = Color { r, g, b, a };
caller.data().draw_glyphs(glyphs, offset, scale, color);
},
)?;
@ -240,9 +251,9 @@ impl ScriptAbi for ScriptAbiImpl {
})
}
fn draw_glyphs(&self, glyphs: &[GlyphPosition]) {
fn draw_glyphs(&self, glyphs: &[GlyphPosition], offset: Vec2, scale: f32, color: Color) {
let font = self.font_store.load_font("Liberation Sans");
let cmds = font.draw(glyphs, 0.9);
let cmds = font.draw(glyphs, offset, scale, color);
self.draw_cmds.lock().extend(cmds.into_iter());
}

View File

@ -10,15 +10,13 @@ use allsorts::pathfinder_geometry::{line_segment::LineSegment2F, vector::Vector2
use allsorts::tables::{glyf::GlyfTable, loca::LocaTable};
use allsorts::tables::{FontTableProvider, SfntVersion};
use allsorts::{tag, Font as AllsortsFont};
use canary_types::{GlyphPosition, Rect};
use canary_types::{Color, GlyphPosition, Rect, Vec2};
use lyon::path::Path;
use ouroboros::self_referencing;
use parking_lot::{Mutex, RwLock};
use std::collections::HashMap;
use std::sync::Arc;
const TEXT_SCALE: f32 = 0.075;
pub struct GlyphCache {
units_per_em: f32,
glyphs: RwLock<Vec<CachedGlyph>>,
@ -89,7 +87,7 @@ impl CachedGlyph {
self.mesh.get_or_insert_with(|| {
use lyon::tessellation::*;
let mut geometry: VertexBuffers<MeshVertex, MeshIndex> = VertexBuffers::new();
let mut geometry: VertexBuffers<Vec2, u32> = VertexBuffers::new();
let fill_options = FillOptions::default().with_tolerance(0.0005);
let mut tessellator = FillTessellator::new();
tessellator
@ -97,15 +95,10 @@ impl CachedGlyph {
&self.path.clone(),
&fill_options,
&mut BuffersBuilder::new(&mut geometry, |vertex: FillVertex| {
let position = vertex.position() * TEXT_SCALE;
let position = canary_types::Vec2 {
let position = vertex.position();
Vec2 {
x: position.x,
y: position.y,
};
MeshVertex {
position,
color: canary_types::Color::WHITE,
}
}),
)
@ -199,8 +192,8 @@ impl allsorts::outline::OutlineSink for OutlineSink {
}
pub struct GlyphMesh {
vertices: Vec<MeshVertex>,
indices: Vec<MeshIndex>,
vertices: Vec<Vec2>,
indices: Vec<u32>,
}
pub struct TextLayout {
@ -241,15 +234,14 @@ impl Font {
xcur += position.hori_advance;
ycur += position.vert_advance;
let scale = TEXT_SCALE / units_per_em;
let xpos = xpos as f32 * scale - 0.9;
let ypos = ypos as f32 * scale + 0.9;
let xpos = xpos as f32 / units_per_em;
let ypos = ypos as f32 / units_per_em;
let mut bb = glyphs.get(position.index as usize).unwrap().bounding_box;
bb.bl.x = bb.bl.x * TEXT_SCALE + xpos;
bb.bl.y = bb.bl.y * TEXT_SCALE + ypos;
bb.tr.x = bb.tr.x * TEXT_SCALE + xpos;
bb.tr.y = bb.tr.y * TEXT_SCALE + ypos;
bb.bl.x = bb.bl.x + xpos;
bb.bl.y = bb.bl.y + ypos;
bb.tr.x = bb.tr.x + xpos;
bb.tr.y = bb.tr.y + ypos;
// TODO use euclid instead
if bounds.bl.x > bb.bl.x {
@ -275,13 +267,20 @@ impl Font {
}
}
pub fn draw(&self, positions: &[GlyphPosition], yoff: f32) -> Vec<DrawCommand> {
pub fn draw(
&self,
positions: &[GlyphPosition],
offset: Vec2,
scale: f32,
color: Color,
) -> Vec<DrawCommand> {
let mut vertices = Vec::new();
let mut indices = Vec::new();
// TODO defer tessellation of missed glyph cache entries
let mut glyphs = self.glyph_cache.glyphs.write();
let units_per_em = self.glyph_cache.units_per_em;
let pos_scale = scale / units_per_em;
let mut xcur = 0;
let mut ycur = 0;
for position in positions.iter() {
@ -293,16 +292,15 @@ impl Font {
ycur += position.vert_advance;
let voff = vertices.len() as MeshIndex;
let scale = TEXT_SCALE / units_per_em;
let xpos = xpos as f32 * scale;
let ypos = ypos as f32 * scale;
let xpos = xpos as f32 * pos_scale + offset.x;
let ypos = ypos as f32 * pos_scale + offset.y;
for v in glyph.vertices.iter() {
let x = v.position.x + xpos - 0.9;
let y = v.position.y + ypos + yoff;
let x = v.x * scale + xpos;
let y = v.y * scale + ypos;
vertices.push(MeshVertex {
position: canary_types::Vec2 { x, y },
color: v.color,
color,
});
}