Set glyph_padding to 4 (when using 8x8 over_sample we need more padding)

This commit is contained in:
Edward R. Gonzalez 2024-06-26 17:02:15 -04:00
parent e6ccdd90d1
commit 86d6adc931
7 changed files with 42 additions and 46 deletions

View File

@ -6,8 +6,6 @@ Its original purpose was for use in game engines, however its rendeirng quality
TODO (Making it a more idiomatic library):
* Use Odin's builtin dynamic arrays
* Use Odin's builtin map type
* Setup freetype, harfbuzz, depedency management within the library
TODO Documentation:

View File

@ -21,8 +21,8 @@ Vec2 :: [2]f32
Vec2i :: [2]i32
Vec2_64 :: [2]f64
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) }}
vec2_from_scalar :: #force_inline proc "contextless" ( scalar : f32 ) -> Vec2 { return { scalar, scalar } }
vec2_64_from_vec2 :: #force_inline proc "contextless" ( v2 : Vec2 ) -> Vec2_64 { return { f64(v2.x), f64(v2.y) }}
vec2_from_vec2i :: #force_inline proc( v2i : Vec2i ) -> Vec2 { return { f32(v2i.x), f32(v2i.y) }}
FontID :: distinct i64
@ -104,7 +104,7 @@ InitAtlasParams :: struct {
InitAtlasParams_Default :: InitAtlasParams {
width = 4096,
height = 2048,
glyph_padding = 1,
glyph_padding = 4,
region_a = {
width = 32,

View File

@ -41,7 +41,7 @@ atlas_bbox :: proc( atlas : ^Atlas, region : AtlasRegionKind, local_idx : i32 )
{
case .A:
width = f32(atlas.region_a.width)
height = f32(atlas.region_b.height)
height = f32(atlas.region_a.height)
position.x = cast(f32) (( local_idx % atlas.region_a.capacity.x ) * i32(atlas.region_a.width))
position.y = cast(f32) (( local_idx / atlas.region_a.capacity.x ) * i32(atlas.region_a.height))
@ -123,7 +123,7 @@ can_batch_glyph :: #force_inline proc( ctx : ^Context, font : FontID, entry : ^E
return true
}
decide_codepoint_region :: #force_inline proc( ctx : ^Context, entry : ^Entry, glyph_index : Glyph
decide_codepoint_region :: proc( ctx : ^Context, entry : ^Entry, glyph_index : Glyph
) -> (region_kind : AtlasRegionKind, region : ^AtlasRegion, over_sample : Vec2)
{
if parser_is_glyph_empty( & entry.parser_info, glyph_index ) {
@ -131,14 +131,16 @@ decide_codepoint_region :: #force_inline proc( ctx : ^Context, entry : ^Entry, g
}
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)
atlas := & ctx.atlas
glyph_buffer := & ctx.glyph_buffer
bounds_width_scaled := cast(u32) (f32(bounds_width) * entry.size_scale + 2.0 * f32(atlas.glyph_padding))
bounds_height_scaled := cast(u32) (f32(bounds_height) * entry.size_scale + 2.0 * f32(atlas.glyph_padding))
glyph_padding := f32(atlas.glyph_padding) * 2
bounds_width_scaled := cast(u32) (bounds_width * entry.size_scale + glyph_padding)
bounds_height_scaled := cast(u32) (bounds_height * entry.size_scale + glyph_padding)
if bounds_width_scaled <= atlas.region_a.width && bounds_height_scaled <= atlas.region_a.height
{

View File

@ -70,4 +70,6 @@ Will update the draw list layer with the latest offset based on the current leng
Provides a Vec2 the width and height occupied by the provided text string. The y is measured to be the the largest glyph box bounds height of the text. The width is derived from the `end_cursor_pos` field from a `ShapedText` entry.
## get_font_vertical_metrics
A wrapper for `parser_get_font_vertical_metrics`. Will provide the ascent, descent, and line_gap for a font entry.

View File

@ -224,7 +224,7 @@ cache_glyph_to_atlas :: proc( ctx : ^Context,
region : ^AtlasRegion,
over_sample : Vec2 )
{
// profile(#procedure)
profile(#procedure)
// Get hb_font text metrics. These are unscaled!
bounds_0, bounds_1 := parser_get_glyph_box( & entry.parser_info, glyph_index )
@ -283,8 +283,8 @@ cache_glyph_to_atlas :: proc( ctx : ^Context,
glyph_draw_translate.y = cast(f32) (i32(glyph_draw_translate.y + 0.9999999))
// Allocate a glyph_update_FBO region
gwidth_scaled_px := i32( bounds_width * glyph_draw_scale.x + 1.0 ) + i32(over_sample.x * glyph_padding)
if i32(glyph_buffer.batch_x + gwidth_scaled_px) >= i32(glyph_buffer.width) {
gwidth_scaled_px := bounds_width * glyph_draw_scale.x + 1.0 + over_sample.x * glyph_padding
if i32(f32(glyph_buffer.batch_x) + gwidth_scaled_px) >= i32(glyph_buffer.width) {
flush_glyph_buffer_to_atlas( ctx )
}
@ -311,7 +311,7 @@ cache_glyph_to_atlas :: proc( ctx : ^Context,
// Advance glyph_update_batch_x and calculate final glyph drawing transform
glyph_draw_translate.x += f32(glyph_buffer.batch_x)
glyph_buffer.batch_x += gwidth_scaled_px
glyph_buffer.batch_x += i32(gwidth_scaled_px)
screenspace_x_form( & glyph_draw_translate, & glyph_draw_scale, glyph_buffer_width, glyph_buffer_height )
call : DrawCall
@ -524,7 +524,7 @@ draw_filled_path :: proc( draw_list : ^DrawList, outside_point : Vec2, path : []
append( & draw_list.vertices, vertex )
}
for index : u32 = 1; index < u32(len(path)); index += 1 {
for index : u32 = 1; index < cast(u32) len(path); index += 1 {
indices := & draw_list.indices
append( indices, outside_vertex )
append( indices, v_offset + index - 1 )
@ -577,7 +577,7 @@ draw_text_shape :: proc( ctx : ^Context,
// position := position //+ ctx.cursor_pos * scale
// profile(#procedure)
batch_start_idx : i32 = 0
for index : i32 = 0; index < i32(len(shaped.glyphs)); index += 1
for index : i32 = 0; index < cast(i32) len(shaped.glyphs); index += 1
{
glyph_index := shaped.glyphs[ index ]
if is_empty( ctx, entry, glyph_index ) do continue
@ -602,7 +602,7 @@ draw_text_shape :: proc( ctx : ^Context,
}
// flush_glyph_buffer_to_atlas(ctx)
draw_text_batch( ctx, entry, shaped, batch_start_idx, i32(len(shaped.glyphs)), position, scale, snap_width , snap_height )
draw_text_batch( ctx, entry, shaped, batch_start_idx, cast(i32) len(shaped.glyphs), position, scale, snap_width , snap_height )
reset_batch_codepoint_state( ctx )
cursor_pos = shaped.end_cursor_pos
return

View File

@ -30,10 +30,10 @@ shape_lru_hash :: #force_inline proc "contextless" ( label : string ) -> u64 {
// ve_fontcache_eval_bezier (quadratic)
eval_point_on_bezier3 :: #force_inline proc "contextless" ( 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)
p0 := vec2_64(p0)
p1 := vec2_64(p1)
p2 := vec2_64(p2)
alpha := f64(alpha)
weight_start := (1 - alpha) * (1 - alpha)
weight_control := 2.0 * (1 - alpha) * alpha
@ -52,11 +52,11 @@ eval_point_on_bezier3 :: #force_inline proc "contextless" ( p0, p1, p2 : Vec2, a
// ve_fontcache_eval_bezier (cubic)
eval_point_on_bezier4 :: #force_inline proc "contextless" ( 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)
p0 := vec2_64(p0)
p1 := vec2_64(p1)
p2 := vec2_64(p2)
p3 := vec2_64(p3)
alpha := f64(alpha)
weight_start := (1 - alpha) * (1 - alpha) * (1 - alpha)
weight_c_a := 3 * (1 - alpha) * (1 - alpha) * alpha
@ -91,7 +91,7 @@ reset_batch_codepoint_state :: #force_inline proc( ctx : ^Context ) {
}
screenspace_x_form :: #force_inline proc "contextless" ( position, scale : ^Vec2, width, height : f32 ) {
when false
when true
{
pos_64 := vec2_64_from_vec2(position^)
scale_64 := vec2_64_from_vec2(scale^)
@ -108,15 +108,13 @@ screenspace_x_form :: #force_inline proc "contextless" ( position, scale : ^Vec2
else
{
quotient : Vec2 = 1.0 / { width, height }
pos := position^ * quotient * 2.0 - 1.0
s := scale^ * quotient * 2.0
(position^) = { f32(pos.x), f32(pos.y) }
(scale^) = { f32(s.x), f32(s.y) }
(position^) *= quotient * 2.0 - 1.0
(scale^) *= quotient * 2.0
}
}
textspace_x_form :: #force_inline proc "contextless" ( position, scale : ^Vec2, width, height : f32 ) {
when false
when true
{
pos_64 := vec2_64_from_vec2(position^)
scale_64 := vec2_64_from_vec2(scale^)
@ -132,13 +130,8 @@ textspace_x_form :: #force_inline proc "contextless" ( position, scale : ^Vec2,
}
else
{
pos := position^
s := scale^
quotient : Vec2 = 1.0 / { width, height }
pos *= quotient
s *= quotient
(position^) = { f32(pos.x), f32(pos.y) }
(scale^) = { f32(s.x), f32(s.y) }
(position^) *= quotient
(scale^) *= quotient
}
}

View File

@ -62,6 +62,7 @@ shape_text_cached :: proc( ctx : ^Context, font : FontID, text_utf8 : string, en
return & shape_cache.storage[ shape_cache_idx ]
}
// TODO(Ed): Make position rounding an option
shape_text_uncached :: proc( ctx : ^Context, font : FontID, text_utf8 : string, entry : ^Entry, output : ^ShapedText )
{
// profile(#procedure)
@ -105,7 +106,7 @@ shape_text_uncached :: proc( ctx : ^Context, font : FontID, text_utf8 : string,
{
position.x = 0.0
position.y -= (ascent - descent + line_gap) * entry.size_scale
position.y = cast(f32) i32( position.y + 0.5 )
position.y = ceil(position.y)
prev_codepoint = rune(0)
continue
}
@ -116,11 +117,11 @@ shape_text_uncached :: proc( ctx : ^Context, font : FontID, text_utf8 : string,
append( & output.glyphs, parser_find_glyph_index( & entry.parser_info, codepoint ))
advance, to_left_side_glyph = parser_get_codepoint_horizontal_metrics( & entry.parser_info, codepoint )
// append( & output.positions, Vec2 {
// cast(f32) i32(position.x + 0.5),
// position.y
// })
append( & output.positions, position )
append( & output.positions, Vec2 {
ceil(position.x),
position.y
})
// append( & output.positions, position )
position.x += f32(advance) * entry.size_scale
prev_codepoint = codepoint