Various improvements to VEFontCache's font rendering
This commit is contained in:
parent
1fe741034d
commit
b5f9687927
@ -17,11 +17,13 @@ import "core:mem"
|
||||
|
||||
Advance_Snap_Smallfont_Size :: 12
|
||||
|
||||
Colour :: [4]f32
|
||||
Vec2 :: [2]f32
|
||||
Vec2i :: [2]i32
|
||||
Colour :: [4]f32
|
||||
Vec2 :: [2]f32
|
||||
Vec2i :: [2]i32
|
||||
Vec2_64 :: [2]f64
|
||||
|
||||
vec2_from_scalar :: proc( scalar : f32 ) -> Vec2 { return { scalar, scalar } }
|
||||
vec2_from_scalar :: #force_inline proc( scalar : f32 ) -> Vec2 { return { scalar, scalar } }
|
||||
vec2_64_from_vec2 :: #force_inline proc( v2 : Vec2 ) -> Vec2_64 { return { f64(v2.x), f64(v2.y) }}
|
||||
|
||||
FontID :: distinct i64
|
||||
Glyph :: distinct i32
|
||||
@ -98,7 +100,7 @@ InitAtlasParams :: struct {
|
||||
InitAtlasParams_Default :: InitAtlasParams {
|
||||
width = 4096,
|
||||
height = 2048,
|
||||
glyph_padding = 1,
|
||||
glyph_padding = 2,
|
||||
|
||||
region_a = {
|
||||
width = 32,
|
||||
@ -125,9 +127,10 @@ InitGlyphDrawParams :: struct {
|
||||
}
|
||||
|
||||
InitGlyphDrawParams_Default :: InitGlyphDrawParams {
|
||||
over_sample = { 8, 8 },
|
||||
over_sample = { 4, 4 },
|
||||
buffer_batch = 4,
|
||||
draw_padding = InitAtlasParams_Default.glyph_padding,
|
||||
// draw_padding = InitAtlasParams_Default.glyph_padding,
|
||||
}
|
||||
|
||||
InitShapeCacheParams :: struct {
|
||||
@ -159,7 +162,7 @@ init :: proc( ctx : ^Context, parser_kind : ParserKind,
|
||||
context.allocator = ctx.backing
|
||||
|
||||
if curve_quality == 0 {
|
||||
curve_quality = 6
|
||||
curve_quality = 12
|
||||
}
|
||||
ctx.curve_quality = curve_quality
|
||||
|
||||
@ -525,8 +528,8 @@ cache_glyph_to_atlas :: proc( ctx : ^Context, font : FontID, glyph_index : Glyph
|
||||
|
||||
// Get hb_font text metrics. These are unscaled!
|
||||
bounds_0, bounds_1 := parser_get_glyph_box( & entry.parser_info, glyph_index )
|
||||
bounds_width := bounds_1.x - bounds_0.x
|
||||
bounds_height := bounds_1.y - bounds_0.y
|
||||
bounds_width := f32(bounds_1.x - bounds_0.x)
|
||||
bounds_height := f32(bounds_1.y - bounds_0.y)
|
||||
|
||||
region_kind, region, over_sample := decide_codepoint_region( ctx, entry, glyph_index )
|
||||
|
||||
@ -560,8 +563,12 @@ cache_glyph_to_atlas :: proc( ctx : ^Context, font : FontID, glyph_index : Glyph
|
||||
assert( LRU_get( & region.state, lru_code ) != - 1 )
|
||||
}
|
||||
|
||||
atlas := & ctx.atlas
|
||||
glyph_padding := cast(f32) atlas.glyph_padding
|
||||
atlas := & ctx.atlas
|
||||
atlas_width := f32(atlas.width)
|
||||
atlas_height := f32(atlas.height)
|
||||
glyph_buffer_width := f32(atlas.buffer_width)
|
||||
glyph_buffer_height := f32(atlas.buffer_height)
|
||||
glyph_padding := cast(f32) atlas.glyph_padding
|
||||
|
||||
if ctx.debug_print
|
||||
{
|
||||
@ -572,42 +579,41 @@ cache_glyph_to_atlas :: proc( ctx : ^Context, font : FontID, glyph_index : Glyph
|
||||
|
||||
// Draw oversized glyph to update FBO
|
||||
glyph_draw_scale := over_sample * entry.size_scale
|
||||
glyph_draw_translate := Vec2 { -f32(bounds_0.x), -f32(bounds_0.y) } * glyph_draw_scale + Vec2{ glyph_padding, glyph_padding }
|
||||
glyph_draw_translate := -1 * Vec2 { f32(bounds_0.x), f32(bounds_0.y) } * glyph_draw_scale + vec2( glyph_padding )
|
||||
glyph_draw_translate.x = cast(f32) (i32(glyph_draw_translate.x + 0.9999999))
|
||||
glyph_draw_translate.y = cast(f32) (i32(glyph_draw_translate.y + 0.9999999))
|
||||
|
||||
// Allocate a glyph_update_FBO region
|
||||
gwidth_scaled_px := i32( f32(bounds_width) * f32(glyph_draw_scale.x) + 1.0 ) + i32(2 * over_sample.x * glyph_padding)
|
||||
gwidth_scaled_px := i32( bounds_width * glyph_draw_scale.x + 1.0 ) + i32(over_sample.x * glyph_padding)
|
||||
if i32(atlas.update_batch_x + gwidth_scaled_px) >= i32(atlas.buffer_width) {
|
||||
flush_glyph_buffer_to_atlas( ctx )
|
||||
}
|
||||
|
||||
// Calculate the src and destination regions
|
||||
dst_position, dst_width, dst_height := atlas_bbox( atlas, region_kind, atlas_index )
|
||||
dst_glyph_position := dst_position + { glyph_padding, glyph_padding }
|
||||
dst_glyph_width := f32(bounds_width) * entry.size_scale
|
||||
dst_glyph_height := f32(bounds_height) * entry.size_scale
|
||||
dst_glyph_position -= { glyph_padding, glyph_padding }
|
||||
dst_glyph_width += 2 * glyph_padding
|
||||
dst_glyph_height += 2 * glyph_padding
|
||||
dst_glyph_position := dst_position
|
||||
dst_glyph_width := bounds_width * entry.size_scale
|
||||
dst_glyph_height := bounds_height * entry.size_scale
|
||||
dst_glyph_width += glyph_padding
|
||||
dst_glyph_height += glyph_padding
|
||||
|
||||
dst_size := Vec2 { dst_width, dst_height }
|
||||
dst_glyph_size := Vec2 { dst_glyph_width, dst_glyph_height }
|
||||
screenspace_x_form( & dst_glyph_position, & dst_glyph_size, f32(atlas.width), f32(atlas.height) )
|
||||
screenspace_x_form( & dst_position, & dst_size, f32(atlas.width), f32(atlas.height) )
|
||||
screenspace_x_form( & dst_glyph_position, & dst_glyph_size, atlas_width, atlas_height )
|
||||
screenspace_x_form( & dst_position, & dst_size, atlas_width, atlas_height )
|
||||
|
||||
src_position := Vec2 { f32(atlas.update_batch_x), 0 }
|
||||
src_size := Vec2 {
|
||||
f32(bounds_width) * glyph_draw_scale.x,
|
||||
f32(bounds_height) * glyph_draw_scale.y,
|
||||
bounds_width * glyph_draw_scale.x,
|
||||
bounds_height * glyph_draw_scale.y,
|
||||
}
|
||||
src_size += 2 * over_sample * glyph_padding
|
||||
textspace_x_form( & src_position, & src_size, f32(atlas.buffer_width), f32(atlas.buffer_height) )
|
||||
src_size += over_sample * glyph_padding
|
||||
textspace_x_form( & src_position, & src_size, glyph_buffer_width, glyph_buffer_height )
|
||||
|
||||
// Advance glyph_update_batch_x and calculate final glyph drawing transform
|
||||
glyph_draw_translate.x += f32(atlas.update_batch_x)
|
||||
atlas.update_batch_x += gwidth_scaled_px
|
||||
screenspace_x_form( & glyph_draw_translate, & glyph_draw_scale, f32(atlas.buffer_width), f32(atlas.buffer_height))
|
||||
screenspace_x_form( & glyph_draw_translate, & glyph_draw_scale, glyph_buffer_width, glyph_buffer_height )
|
||||
|
||||
call : DrawCall
|
||||
{
|
||||
@ -652,7 +658,7 @@ measure_text_size :: proc( ctx : ^Context, font : FontID, text_utf8 : string ) -
|
||||
atlas := ctx.atlas
|
||||
shaped := shape_text_cached( ctx, font, text_utf8 )
|
||||
entry := & ctx.entries.data[ font ]
|
||||
padding := 2 * cast(f32) atlas.glyph_padding
|
||||
padding := cast(f32) atlas.glyph_padding
|
||||
|
||||
for index : i32 = 0; index < i32(shaped.glyphs.num); index += 1
|
||||
{
|
||||
@ -666,14 +672,14 @@ measure_text_size :: proc( ctx : ^Context, font : FontID, text_utf8 : string ) -
|
||||
// region_kind, region, over_sample := decide_codepoint_region( ctx, entry, glyph_index )
|
||||
|
||||
glyph_size := Vec2 {
|
||||
f32(bounds_width) * entry.size_scale + padding,
|
||||
f32(bounds_height) * entry.size_scale + padding,
|
||||
f32(bounds_width) * entry.size_scale, //+ padding,
|
||||
f32(bounds_height) * entry.size_scale, //+ padding,
|
||||
}
|
||||
|
||||
dummy_position : Vec2
|
||||
measured.y = max(measured.y, glyph_size.y)
|
||||
}
|
||||
measured.x = shaped.end_cursor_pos.x - padding
|
||||
measured.x = shaped.end_cursor_pos.x
|
||||
|
||||
return measured
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
package VEFontCache
|
||||
|
||||
import "core:math"
|
||||
|
||||
DrawCall :: struct {
|
||||
pass : FrameBufferPass,
|
||||
start_index : u32,
|
||||
@ -123,8 +125,8 @@ directly_draw_massive_glyph :: proc( ctx : ^Context, entry : ^Entry, glyph : Gly
|
||||
dst := position + scale * bounds_scaled
|
||||
dst_width := scale.x * glyph_dst_width
|
||||
dst_height := scale.y * glyph_dst_height
|
||||
dst.x -= scale.x * f32(ctx.atlas.glyph_padding)
|
||||
dst.y -= scale.y * f32(ctx.atlas.glyph_padding)
|
||||
dst.x -= scale.x * f32(ctx.atlas.draw_padding)
|
||||
dst.y -= scale.y * f32(ctx.atlas.draw_padding)
|
||||
dst_size := Vec2{ dst_width, dst_height }
|
||||
|
||||
glyph_size := Vec2 { glyph_width, glyph_height }
|
||||
@ -158,8 +160,8 @@ draw_cached_glyph :: proc( ctx : ^Context, entry : ^Entry, glyph_index : Glyph,
|
||||
|
||||
bounds_0, bounds_1 := parser_get_glyph_box( & entry.parser_info, glyph_index )
|
||||
|
||||
bounds_width := bounds_1.x - bounds_0.x
|
||||
bounds_height := bounds_1.y - bounds_0.y
|
||||
bounds_width := f32(bounds_1.x - bounds_0.x)
|
||||
bounds_height := f32(bounds_1.y - bounds_0.y)
|
||||
|
||||
// Decide which atlas to target
|
||||
region_kind, region, over_sample := decide_codepoint_region( ctx, entry, glyph_index )
|
||||
@ -167,7 +169,7 @@ draw_cached_glyph :: proc( ctx : ^Context, entry : ^Entry, glyph_index : Glyph,
|
||||
// E region is special case and not cached to atlas
|
||||
if region_kind == .E
|
||||
{
|
||||
directly_draw_massive_glyph( ctx, entry, glyph_index, bounds_0, bounds_width, bounds_height, over_sample, position, scale )
|
||||
directly_draw_massive_glyph( ctx, entry, glyph_index, bounds_0, cast(i32) bounds_width, cast(i32) bounds_height, over_sample, position, scale )
|
||||
return true
|
||||
}
|
||||
|
||||
@ -180,32 +182,36 @@ draw_cached_glyph :: proc( ctx : ^Context, entry : ^Entry, glyph_index : Glyph,
|
||||
}
|
||||
|
||||
atlas := & ctx.atlas
|
||||
atlas_width := f32(atlas.width)
|
||||
atlas_height := f32(atlas.height)
|
||||
glyph_padding := f32(atlas.glyph_padding)
|
||||
|
||||
// Figure out the source bounding box in the atlas texture
|
||||
atlas_position, atlas_width, atlas_height := atlas_bbox( atlas, region_kind, atlas_index )
|
||||
glyph_atlas_position, glyph_atlas_width, glyph_atlas_height := atlas_bbox( atlas, region_kind, atlas_index )
|
||||
|
||||
glyph_position := atlas_position //* {1, 2}
|
||||
glyph_width := f32(bounds_width) * entry.size_scale
|
||||
glyph_height := f32(bounds_height) * entry.size_scale
|
||||
glyph_width := bounds_width * entry.size_scale
|
||||
glyph_height := bounds_height * entry.size_scale
|
||||
|
||||
glyph_width += 2 * f32(atlas.glyph_padding)
|
||||
glyph_height += 2 * f32(atlas.glyph_padding)
|
||||
glyph_width += glyph_padding
|
||||
glyph_height += glyph_padding
|
||||
glyph_scale := Vec2 { glyph_width, glyph_height }
|
||||
|
||||
bounds_0_scaled := Vec2{ f32(bounds_0.x), f32(bounds_0.y) } * entry.size_scale - { 0.5, 0.5 }
|
||||
bounds_0_scaled := Vec2{ f32(bounds_0.x), f32(bounds_0.y) } * entry.size_scale //- { 0.5, 0.5 }
|
||||
bounds_0_scaled = {
|
||||
cast(f32) cast(i32) bounds_0_scaled.x,
|
||||
cast(f32) cast(i32) bounds_0_scaled.y,
|
||||
math.ceil(bounds_0_scaled.x),
|
||||
math.ceil(bounds_0_scaled.y),
|
||||
}
|
||||
// dst := position * scale * bounds_0_scaled
|
||||
dst := Vec2 {
|
||||
position.x + scale.x * bounds_0_scaled.x,
|
||||
position.y + scale.y * bounds_0_scaled.y,
|
||||
position.x + bounds_0_scaled.x * scale.x,
|
||||
position.y + bounds_0_scaled.y * scale.y,
|
||||
}
|
||||
dst_width := scale.x * glyph_width
|
||||
dst_height := scale.y * glyph_height
|
||||
dst -= scale * { f32(atlas.glyph_padding), f32(atlas.glyph_padding) }
|
||||
dst -= scale * glyph_padding
|
||||
dst_scale := Vec2 { dst_width, dst_height }
|
||||
textspace_x_form( & glyph_position, & glyph_scale, f32(atlas.width), f32(atlas.height) )
|
||||
|
||||
textspace_x_form( & glyph_atlas_position, & glyph_scale, atlas_width, atlas_height )
|
||||
|
||||
// Add the glyph drawcall
|
||||
call := DrawCall_Default
|
||||
@ -215,7 +221,7 @@ draw_cached_glyph :: proc( ctx : ^Context, entry : ^Entry, glyph_index : Glyph,
|
||||
colour = ctx.colour
|
||||
start_index = cast(u32) ctx.draw_list.indices.num
|
||||
|
||||
blit_quad( & ctx.draw_list, dst, dst + dst_scale, glyph_position, glyph_position + glyph_scale )
|
||||
blit_quad( & ctx.draw_list, dst, dst + dst_scale, glyph_atlas_position, glyph_atlas_position + glyph_scale )
|
||||
end_index = cast(u32) ctx.draw_list.indices.num
|
||||
}
|
||||
append( & ctx.draw_list.calls, call )
|
||||
|
@ -31,6 +31,11 @@ shape_lru_hash :: #force_inline proc( label : string ) -> u64 {
|
||||
// ve_fontcache_eval_bezier (quadratic)
|
||||
eval_point_on_bezier3 :: proc( p0, p1, p2 : Vec2, alpha : f32 ) -> Vec2
|
||||
{
|
||||
p0 := vec2_64_from_vec2(p0)
|
||||
p1 := vec2_64_from_vec2(p1)
|
||||
p2 := vec2_64_from_vec2(p2)
|
||||
alpha := f64(alpha)
|
||||
|
||||
weight_start := (1 - alpha) * (1 - alpha)
|
||||
weight_control := 2.0 * (1 - alpha) * alpha
|
||||
weight_end := alpha * alpha
|
||||
@ -40,7 +45,7 @@ eval_point_on_bezier3 :: proc( p0, p1, p2 : Vec2, alpha : f32 ) -> Vec2
|
||||
end_point := p2 * weight_end
|
||||
|
||||
point := starting_point + control_point + end_point
|
||||
return point
|
||||
return { f32(point.x), f32(point.y) }
|
||||
}
|
||||
|
||||
// For a provided alpha value,
|
||||
@ -48,6 +53,12 @@ eval_point_on_bezier3 :: proc( p0, p1, p2 : Vec2, alpha : f32 ) -> Vec2
|
||||
// ve_fontcache_eval_bezier (cubic)
|
||||
eval_point_on_bezier4 :: proc( p0, p1, p2, p3 : Vec2, alpha : f32 ) -> Vec2
|
||||
{
|
||||
p0 := vec2_64_from_vec2(p0)
|
||||
p1 := vec2_64_from_vec2(p1)
|
||||
p2 := vec2_64_from_vec2(p2)
|
||||
p3 := vec2_64_from_vec2(p3)
|
||||
alpha := f64(alpha)
|
||||
|
||||
weight_start := (1 - alpha) * (1 - alpha) * (1 - alpha)
|
||||
weight_c_a := 3 * (1 - alpha) * (1 - alpha) * alpha
|
||||
weight_c_b := 3 * (1 - alpha) * alpha * alpha
|
||||
@ -59,7 +70,7 @@ eval_point_on_bezier4 :: proc( p0, p1, p2, p3 : Vec2, alpha : f32 ) -> Vec2
|
||||
end_point := p3 * weight_end
|
||||
|
||||
point := start_point + control_a + control_b + end_point
|
||||
return point
|
||||
return { f32(point.x), f32(point.y) }
|
||||
}
|
||||
|
||||
reset_batch_codepoint_state :: proc( ctx : ^Context ) {
|
||||
@ -68,13 +79,31 @@ reset_batch_codepoint_state :: proc( ctx : ^Context ) {
|
||||
}
|
||||
|
||||
screenspace_x_form :: proc( position, scale : ^Vec2, width, height : f32 ) {
|
||||
quotient := 1.0 / Vec2 { width, height }
|
||||
(position^) = (position^) * quotient * 2.0 - 1.0
|
||||
(scale^) = (scale^) * quotient * 2.0
|
||||
pos_64 := vec2_64_from_vec2(position^)
|
||||
scale_64 := vec2_64_from_vec2(scale^)
|
||||
width := f64(width)
|
||||
height := f64(height)
|
||||
|
||||
quotient : Vec2_64 = 1.0 / { width, height }
|
||||
// quotient : Vec2 = 1.0 / { width, height }
|
||||
pos_64 = pos_64 * quotient * 2.0 - 1.0
|
||||
scale_64 = scale_64 * quotient * 2.0
|
||||
|
||||
(position^) = { f32(pos_64.x), f32(pos_64.y) }
|
||||
(scale^) = { f32(scale_64.x), f32(scale_64.y) }
|
||||
}
|
||||
|
||||
textspace_x_form :: proc( position, scale : ^Vec2, width, height : f32 ) {
|
||||
quotient := 1.0 / Vec2 { width, height }
|
||||
(position^) *= quotient
|
||||
(scale^) *= quotient
|
||||
pos_64 := vec2_64_from_vec2(position^)
|
||||
scale_64 := vec2_64_from_vec2(scale^)
|
||||
width := f64(width)
|
||||
height := f64(height)
|
||||
|
||||
quotient : Vec2_64 = 1.0 / { width, height }
|
||||
// quotient : Vec2 = 1.0 / { width, height }
|
||||
pos_64 *= quotient
|
||||
scale_64 *= quotient
|
||||
|
||||
(position^) = { f32(pos_64.x), f32(pos_64.y) }
|
||||
(scale^) = { f32(scale_64.x), f32(scale_64.y) }
|
||||
}
|
||||
|
@ -438,8 +438,8 @@ parser_scale_for_mapping_em_to_pixels :: proc( font : ^ParserFontInfo, size : f3
|
||||
FT_Point_10 :: 64.0
|
||||
|
||||
points_per_em := (size / system_dpi ) * DPT_DPI
|
||||
freetype.set_char_size( font.freetype_info, 0, cast(freetype.F26Dot6) (f32(points_per_em) * FT_Point_10), cast(u32) DPT_DPI, cast(u32) DPT_DPI )
|
||||
size_scale := size / cast(f32) font.freetype_info.units_per_em;
|
||||
freetype.set_char_size( font.freetype_info, 0, cast(freetype.F26Dot6) f32(points_per_em * FT_Point_10), cast(u32) DPT_DPI, cast(u32) DPT_DPI )
|
||||
size_scale := f32(f64(size) / cast(f64) font.freetype_info.units_per_em)
|
||||
return size_scale
|
||||
|
||||
case .STB_TrueType:
|
||||
|
Loading…
Reference in New Issue
Block a user