VEFontCache: Lifted the GlyphDrawBuffer member of atlas to the context

This commit is contained in:
Edward R. Gonzalez 2024-06-26 15:15:03 -04:00
parent 343d558a94
commit 8e8f25ba50
6 changed files with 240 additions and 212 deletions

View File

@ -175,7 +175,6 @@ LRU_reload :: #force_inline proc( cache : ^LRU_Cache, allocator : Allocator )
LRU_hash_key :: #force_inline proc( key : u64 ) -> ( hash : u64 ) {
bytes := transmute( [8]byte ) key
hash = fnv64a( bytes[:] )
// hash = cast(u64) crc64( bytes[:] )
return
}

View File

@ -13,7 +13,6 @@ Changes:
package VEFontCache
import "base:runtime"
import "core:mem"
Advance_Snap_Smallfont_Size :: 12
@ -22,8 +21,9 @@ 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( 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_vec2i :: #force_inline proc( v2i : Vec2i ) -> Vec2 { return { f32(v2i.x), f32(v2i.y) }}
FontID :: distinct i64
Glyph :: distinct i32
@ -71,9 +71,10 @@ Context :: struct {
calls_offset : int,
},
draw_list : DrawList,
atlas : Atlas,
shape_cache : ShapedTextCache,
draw_list : DrawList,
atlas : Atlas,
glyph_buffer : GlyphDrawBuffer,
shape_cache : ShapedTextCache,
curve_quality : u32,
text_shape_adv : b32,
@ -103,7 +104,7 @@ InitAtlasParams :: struct {
InitAtlasParams_Default :: InitAtlasParams {
width = 4096,
height = 2048,
glyph_padding = 2,
glyph_padding = 1,
region_a = {
width = 32,
@ -151,7 +152,7 @@ startup :: proc( ctx : ^Context, parser_kind : ParserKind,
atlas_params := InitAtlasParams_Default,
glyph_draw_params := InitGlyphDrawParams_Default,
shape_cache_params := InitShapeCacheParams_Default,
curve_quality : u32 = 6,
curve_quality : u32 = 3,
entires_reserve : u32 = 512,
temp_path_reserve : u32 = 512,
temp_codepoint_seen_reserve : u32 = 512,
@ -164,7 +165,7 @@ startup :: proc( ctx : ^Context, parser_kind : ParserKind,
context.allocator = ctx.backing
if curve_quality == 0 {
curve_quality = 6
curve_quality = 3
}
ctx.curve_quality = curve_quality
@ -242,11 +243,11 @@ startup :: proc( ctx : ^Context, parser_kind : ParserKind,
// Note(From original author): We can actually go over VE_FONTCACHE_GLYPHDRAW_BUFFER_BATCH batches due to smart packing!
{
using atlas
using glyph_buffer
over_sample = glyph_draw_params.over_sample
buffer_batch = glyph_draw_params.buffer_batch
buffer_width = region_d.width * u32(over_sample.x) * buffer_batch
buffer_height = region_d.height * u32(over_sample.y)
batch = glyph_draw_params.buffer_batch
width = atlas.region_d.width * u32(over_sample.x) * batch
height = atlas.region_d.height * u32(over_sample.y)
draw_padding = glyph_draw_params.draw_padding
draw_list.calls, error = make( [dynamic]DrawCall, cast(u64) glyph_draw_params.buffer_batch * 2 )
@ -301,13 +302,13 @@ hot_reload :: proc( ctx : ^Context, allocator : Allocator )
reload_array( & positions, allocator )
}
reload_array( & atlas.draw_list.calls, allocator )
reload_array( & atlas.draw_list.indices, allocator )
reload_array( & atlas.draw_list.vertices, allocator )
reload_array( & glyph_buffer.draw_list.calls, allocator )
reload_array( & glyph_buffer.draw_list.indices, allocator )
reload_array( & glyph_buffer.draw_list.vertices, allocator )
reload_array( & atlas.clear_draw_list.calls, allocator )
reload_array( & atlas.clear_draw_list.indices, allocator )
reload_array( & atlas.clear_draw_list.vertices, allocator )
reload_array( & glyph_buffer.clear_draw_list.calls, allocator )
reload_array( & glyph_buffer.clear_draw_list.indices, allocator )
reload_array( & glyph_buffer.clear_draw_list.vertices, allocator )
reload_array( & shape_cache.storage, allocator )
LRU_reload( & shape_cache.state, allocator )
@ -358,7 +359,7 @@ load_font :: proc( ctx : ^Context, label : string, data : []byte, size_px : f32
// assert( parser_info != nil, "VEFontCache.load_font: Failed to load font info from parser" )
size = size_px
size_scale = size_px < 0.0 ? \
size_scale = size_px < 0.0 ? \
parser_scale_for_pixel_height( & parser_info, -size_px ) \
: parser_scale_for_mapping_em_to_pixels( & parser_info, size_px )
// size_scale = 1.0
@ -404,10 +405,6 @@ configure_snap :: #force_inline proc( ctx : ^Context, snap_width, snap_height :
get_cursor_pos :: #force_inline proc "contextless" ( ctx : ^Context ) -> Vec2 { return ctx.cursor_pos }
set_colour :: #force_inline proc "contextless" ( ctx : ^Context, colour : Colour ) { ctx.colour = colour }
// TODO(Ed): Change this to be whitespace aware so that we can optimize the caching of shpaes properly.
// Right now the entire text provided to this call is considered a "shape" this is really bad as basically it invalidates caching for large chunks of text
// Instead we should be aware of whitespace tokens and the chunks between them (the whitespace lexer could be abused for this).
// From there we should maek a 'draw text shape' that breaks up the batch text draws for each of the shapes.
draw_text :: proc( ctx : ^Context, font : FontID, text_utf8 : string, position : Vec2, scale : Vec2 ) -> b32
{
// profile(#procedure)
@ -424,8 +421,6 @@ draw_text :: proc( ctx : ^Context, font : FontID, text_utf8 : string, position :
entry := & ctx.entries[ font ]
last_shaped : ^ShapedText
ChunkType :: enum u32 { Visible, Formatting }
chunk_kind : ChunkType
chunk_start : int = 0
@ -434,91 +429,91 @@ draw_text :: proc( ctx : ^Context, font : FontID, text_utf8 : string, position :
text_utf8_bytes := transmute([]u8) text_utf8
text_chunk : string
when true {
text_chunk = transmute(string) text_utf8_bytes[ : ]
if len(text_chunk) > 0 {
shaped := shape_text_cached( ctx, font, text_chunk, entry )
ctx.cursor_pos = draw_text_shape( ctx, font, entry, shaped, position, scale, snap_width, snap_height )
last_shaped = shaped
}
}
else {
last_byte_offset : int = 0
byte_offset : int = 0
for codepoint, offset in text_utf8
Text_As_Shape :: true
when Text_As_Shape
{
Rune_Space :: ' '
Rune_Tab :: '\t'
Rune_Carriage_Return :: '\r'
Rune_Line_Feed :: '\n'
// Rune_Tab_Vertical :: '\v'
byte_offset = offset
switch codepoint
text_chunk = transmute(string) text_utf8_bytes[ : ]
if len(text_chunk) > 0 {
shaped := shape_text_cached( ctx, font, text_chunk, entry )
ctx.cursor_pos = draw_text_shape( ctx, font, entry, shaped, position, scale, snap_width, snap_height )
}
}
else
{
last_byte_offset : int = 0
byte_offset : int = 0
for codepoint, offset in text_utf8
{
case Rune_Space: fallthrough
case Rune_Tab: fallthrough
case Rune_Line_Feed: fallthrough
case Rune_Carriage_Return:
if chunk_kind == .Formatting {
chunk_end = byte_offset
last_byte_offset = byte_offset
}
else
{
text_chunk = transmute(string) text_utf8_bytes[ chunk_start : byte_offset]
if len(text_chunk) > 0 {
shaped := shape_text_cached( ctx, font, text_chunk, entry )
ctx.cursor_pos += draw_text_shape( ctx, font, entry, shaped, position, scale, snap_width, snap_height )
last_shaped = shaped
Rune_Space :: ' '
Rune_Tab :: '\t'
Rune_Carriage_Return :: '\r'
Rune_Line_Feed :: '\n'
// Rune_Tab_Vertical :: '\v'
byte_offset = offset
switch codepoint
{
case Rune_Space: fallthrough
case Rune_Tab: fallthrough
case Rune_Line_Feed: fallthrough
case Rune_Carriage_Return:
if chunk_kind == .Formatting
{
chunk_end = byte_offset
last_byte_offset = byte_offset
}
else
{
text_chunk = transmute(string) text_utf8_bytes[ chunk_start : byte_offset]
if len(text_chunk) > 0 {
shaped := shape_text_cached( ctx, font, text_chunk, entry )
ctx.cursor_pos += draw_text_shape( ctx, font, entry, shaped, position, scale, snap_width, snap_height )
}
chunk_start = byte_offset
chunk_end = chunk_start
chunk_kind = .Formatting
chunk_start = byte_offset
chunk_end = chunk_start
chunk_kind = .Formatting
last_byte_offset = byte_offset
continue
}
}
// Visible Chunk
if chunk_kind == .Visible {
chunk_end = byte_offset
last_byte_offset = byte_offset
}
else
{
text_chunk = transmute(string) text_utf8_bytes[ chunk_start : byte_offset ]
if len(text_chunk) > 0 {
shaped := shape_text_cached( ctx, font, text_chunk, entry )
ctx.cursor_pos += draw_text_shape( ctx, font, entry, shaped, position, scale, snap_width, snap_height )
last_shaped = shaped
last_byte_offset = byte_offset
continue
}
}
chunk_start = byte_offset
chunk_end = chunk_start
chunk_kind = .Visible
// Visible Chunk
if chunk_kind == .Visible {
chunk_end = byte_offset
last_byte_offset = byte_offset
}
else
{
text_chunk = transmute(string) text_utf8_bytes[ chunk_start : byte_offset ]
if len(text_chunk) > 0 {
shaped := shape_text_cached( ctx, font, text_chunk, entry )
ctx.cursor_pos += draw_text_shape( ctx, font, entry, shaped, position, scale, snap_width, snap_height )
}
last_byte_offset = byte_offset
chunk_start = byte_offset
chunk_end = chunk_start
chunk_kind = .Visible
last_byte_offset = byte_offset
}
}
text_chunk = transmute(string) text_utf8_bytes[ chunk_start : ]
if len(text_chunk) > 0 {
shaped := shape_text_cached( ctx, font, text_chunk, entry )
ctx.cursor_pos += draw_text_shape( ctx, font, entry, shaped, position, scale, snap_width, snap_height )
}
chunk_start = byte_offset
chunk_end = chunk_start
chunk_kind = .Visible
last_byte_offset = byte_offset
}
text_chunk = transmute(string) text_utf8_bytes[ chunk_start : byte_offset ]
if len(text_chunk) > 0 {
shaped := shape_text_cached( ctx, font, text_chunk, entry )
ctx.cursor_pos += draw_text_shape( ctx, font, entry, shaped, position, scale, snap_width, snap_height )
last_shaped = shaped
}
chunk_start = byte_offset
chunk_end = chunk_start
chunk_kind = .Visible
last_byte_offset = byte_offset
}
return true
}
@ -526,7 +521,6 @@ draw_text :: proc( ctx : ^Context, font : FontID, text_utf8 : string, position :
get_draw_list :: proc( ctx : ^Context, optimize_before_returning := true ) -> ^DrawList {
assert( ctx != nil )
if optimize_before_returning do optimize_draw_list( & ctx.draw_list, 0 )
return & ctx.draw_list
}

View File

@ -33,8 +33,6 @@ Atlas :: struct {
region_b : AtlasRegion,
region_c : AtlasRegion,
region_d : AtlasRegion,
using glyph_update_batch : GlyphDrawBuffer,
}
atlas_bbox :: proc( atlas : ^Atlas, region : AtlasRegionKind, local_idx : i32 ) -> (position : Vec2, width, height : f32)
@ -136,7 +134,8 @@ decide_codepoint_region :: #force_inline proc( ctx : ^Context, entry : ^Entry, g
bounds_width := bounds_1.x - bounds_0.x
bounds_height := bounds_1.y - bounds_0.y
atlas := & ctx.atlas
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))
@ -165,12 +164,12 @@ decide_codepoint_region :: #force_inline proc( ctx : ^Context, entry : ^Entry, g
region_kind = .D
region = & atlas.region_d
}
else if bounds_width_scaled <= atlas.buffer_width && bounds_height_scaled <= atlas.buffer_height
else if bounds_width_scaled <= glyph_buffer.width && bounds_height_scaled <= glyph_buffer.height
{
// Region 'E' for massive glyphs. These are rendered uncached and un-oversampled.
region_kind = .E
region = nil
if bounds_width_scaled <= atlas.buffer_width / 2 && bounds_height_scaled <= atlas.buffer_height / 2 {
if bounds_width_scaled <= glyph_buffer.width / 2 && bounds_height_scaled <= glyph_buffer.height / 2 {
over_sample = { 2.0, 2.0 }
}
else {
@ -183,7 +182,7 @@ decide_codepoint_region :: #force_inline proc( ctx : ^Context, entry : ^Entry, g
return
}
over_sample = ctx.atlas.over_sample
over_sample = glyph_buffer.over_sample
assert(region != nil)
return
}

View File

@ -1,7 +1,5 @@
package VEFontCache
import "core:math"
Vertex :: struct {
pos : Vec2,
u, v : f32,
@ -41,12 +39,12 @@ FrameBufferPass :: enum u32 {
GlyphDrawBuffer :: struct {
over_sample : Vec2,
buffer_batch : u32,
buffer_width : u32,
buffer_height : u32,
batch : u32,
width : u32,
height : u32,
draw_padding : u32,
update_batch_x : i32,
batch_x : i32,
clear_draw_list : DrawList,
draw_list : DrawList,
}
@ -94,7 +92,7 @@ blit_quad :: proc( draw_list : ^DrawList, p0 : Vec2 = {0, 0}, p1 : Vec2 = {1, 1}
return
}
cache_glyph :: proc( ctx : ^Context, font : FontID, glyph_index : Glyph, entry : ^Entry, bounds_0, bounds_1 : Vec2i, scale, translate : Vec2 ) -> b32
cache_glyph :: proc( ctx : ^Context, font : FontID, glyph_index : Glyph, entry : ^Entry, bounds_0, bounds_1 : Vec2, scale, translate : Vec2 ) -> b32
{
// profile(#procedure)
if glyph_index == Glyph(0) {
@ -141,8 +139,8 @@ cache_glyph :: proc( ctx : ^Context, font : FontID, glyph_index : Glyph, entry :
Note that this outside point is scaled alongside the glyph in ve_fontcache_draw_filled_path, so we don't need to handle that here.
*/
outside := Vec2 {
f32(bounds_0.x) - 21,
f32(bounds_0.y) - 33,
bounds_0.x - 21,
bounds_0.y - 33,
}
// Note(Original Author): Figure out scaling so it fits within our box.
@ -165,7 +163,7 @@ cache_glyph :: proc( ctx : ^Context, font : FontID, glyph_index : Glyph, entry :
fallthrough
case .Line:
append_elem( & path, Vec2{ f32(edge.x), f32(edge.y) })
append( & path, Vec2{ f32(edge.x), f32(edge.y) })
case .Curve:
assert( len(path) > 0 )
@ -176,7 +174,7 @@ cache_glyph :: proc( ctx : ^Context, font : FontID, glyph_index : Glyph, entry :
step := 1.0 / f32(ctx.curve_quality)
alpha := step
for index := i32(0); index < i32(ctx.curve_quality); index += 1 {
append_elem( & path, eval_point_on_bezier3( p0, p1, p2, alpha ))
append( & path, eval_point_on_bezier3( p0, p1, p2, alpha ))
alpha += step
}
@ -190,7 +188,7 @@ cache_glyph :: proc( ctx : ^Context, font : FontID, glyph_index : Glyph, entry :
step := 1.0 / f32(ctx.curve_quality)
alpha := step
for index := i32(0); index < i32(ctx.curve_quality); index += 1 {
append_elem( & path, eval_point_on_bezier4( p0, p1, p2, p3, alpha ))
append( & path, eval_point_on_bezier4( p0, p1, p2, p3, alpha ))
alpha += step
}
@ -214,9 +212,17 @@ cache_glyph :: proc( ctx : ^Context, font : FontID, glyph_index : Glyph, entry :
/*
Called by:
* can_batch_glyph : If it determines that the glyph was not detected and we haven't reached capacity in the atlas
* draw_text_shape : Glyph
* draw_text_shape : Glyph
*/
cache_glyph_to_atlas :: proc( ctx : ^Context, font : FontID, glyph_index : Glyph, lru_code : u64, atlas_index : i32, entry : ^Entry, region_kind : AtlasRegionKind, region : ^AtlasRegion, over_sample : Vec2 )
cache_glyph_to_atlas :: proc( ctx : ^Context,
font : FontID,
glyph_index : Glyph,
lru_code : u64,
atlas_index : i32,
entry : ^Entry,
region_kind : AtlasRegionKind,
region : ^AtlasRegion,
over_sample : Vec2 )
{
// profile(#procedure)
@ -257,26 +263,28 @@ cache_glyph_to_atlas :: proc( ctx : ^Context, font : FontID, glyph_index : Glyph
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_buffer := & ctx.glyph_buffer
glyph_buffer_width := f32(glyph_buffer.width)
glyph_buffer_height := f32(glyph_buffer.height)
glyph_padding := cast(f32) atlas.glyph_padding
if ctx.debug_print
{
@static debug_total_cached : i32 = 0
logf("glyph %v%v( %v ) caching to atlas region %v at idx %d. %d total glyphs cached.\n", i32(glyph_index), rune(glyph_index), cast(rune) region_kind, atlas_index, debug_total_cached)
logf("glyph %v%v( %v ) caching to atlas region %v at idx %d. %d total glyphs cached.\n",
i32(glyph_index), rune(glyph_index), cast(rune) region_kind, atlas_index, debug_total_cached)
debug_total_cached += 1
}
// Draw oversized glyph to update FBO
glyph_draw_scale := over_sample * entry.size_scale
glyph_draw_translate := -1 * Vec2 { f32(bounds_0.x), f32(bounds_0.y) } * glyph_draw_scale + vec2( glyph_padding )
glyph_draw_translate := -1 * vec2(bounds_0) * 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( 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) {
if i32(glyph_buffer.batch_x + gwidth_scaled_px) >= i32(glyph_buffer.width) {
flush_glyph_buffer_to_atlas( ctx )
}
@ -293,7 +301,7 @@ cache_glyph_to_atlas :: proc( ctx : ^Context, font : FontID, glyph_index : Glyph
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_position := Vec2 { f32(glyph_buffer.batch_x), 0 }
src_size := Vec2 {
bounds_width * glyph_draw_scale.x,
bounds_height * glyph_draw_scale.y,
@ -302,8 +310,8 @@ cache_glyph_to_atlas :: proc( ctx : ^Context, font : FontID, glyph_index : Glyph
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
glyph_draw_translate.x += f32(glyph_buffer.batch_x)
glyph_buffer.batch_x += gwidth_scaled_px
screenspace_x_form( & glyph_draw_translate, & glyph_draw_scale, glyph_buffer_width, glyph_buffer_height )
call : DrawCall
@ -312,21 +320,21 @@ cache_glyph_to_atlas :: proc( ctx : ^Context, font : FontID, glyph_index : Glyph
using call
pass = .Atlas
region = .Ignore
start_index = cast(u32) len(atlas.clear_draw_list.indices)
blit_quad( & atlas.clear_draw_list, dst_position, dst_position + dst_size, { 1.0, 1.0 }, { 1.0, 1.0 } )
end_index = cast(u32) len(atlas.clear_draw_list.indices)
append( & atlas.clear_draw_list.calls, call )
start_index = cast(u32) len(glyph_buffer.clear_draw_list.indices)
blit_quad( & glyph_buffer.clear_draw_list, dst_position, dst_position + dst_size, { 1.0, 1.0 }, { 1.0, 1.0 } )
end_index = cast(u32) len(glyph_buffer.clear_draw_list.indices)
append( & glyph_buffer.clear_draw_list.calls, call )
// Queue up a blit from glyph_update_FBO to the atlas
region = .None
start_index = cast(u32) len(atlas.draw_list.indices)
blit_quad( & atlas.draw_list, dst_glyph_position, dst_position + dst_glyph_size, src_position, src_position + src_size )
end_index = cast(u32) len(atlas.draw_list.indices)
append( & atlas.draw_list.calls, call )
start_index = cast(u32) len(glyph_buffer.draw_list.indices)
blit_quad( & glyph_buffer.draw_list, dst_glyph_position, dst_position + dst_glyph_size, src_position, src_position + src_size )
end_index = cast(u32) len(glyph_buffer.draw_list.indices)
append( & glyph_buffer.draw_list.calls, call )
}
// Render glyph to glyph_update_FBO
cache_glyph( ctx, font, glyph_index, entry, bounds_0, bounds_1, glyph_draw_scale, glyph_draw_translate )
cache_glyph( ctx, font, glyph_index, entry, vec2(bounds_0), vec2(bounds_1), glyph_draw_scale, glyph_draw_translate )
}
// ve_fontcache_clear_drawlist
@ -336,18 +344,23 @@ clear_draw_list :: #force_inline proc ( draw_list : ^DrawList ) {
clear( & draw_list.vertices )
}
directly_draw_massive_glyph :: proc( ctx : ^Context, entry : ^Entry, glyph : Glyph, bounds_0, bounds_1 : Vec2i, bounds_width, bounds_height : f32, over_sample, position, scale : Vec2 )
directly_draw_massive_glyph :: proc( ctx : ^Context,
entry : ^Entry,
glyph : Glyph,
bounds_0, bounds_1 : Vec2,
bounds_width, bounds_height : f32,
over_sample, position, scale : Vec2 )
{
// profile(#procedure)
flush_glyph_buffer_to_atlas( ctx )
glyph_padding := f32(ctx.atlas.glyph_padding)
glyph_buffer_width := f32(ctx.atlas.buffer_width)
glyph_buffer_height := f32(ctx.atlas.buffer_height)
glyph_buffer_width := f32(ctx.glyph_buffer.width)
glyph_buffer_height := f32(ctx.glyph_buffer.height)
// Draw un-antialiased glyph to update FBO.
glyph_draw_scale := over_sample * entry.size_scale
glyph_draw_translate := -1 * Vec2{ f32(bounds_0.x), f32(bounds_0.y) } * glyph_draw_scale + vec2_from_scalar(glyph_padding)
glyph_draw_translate := -1 * bounds_0 * glyph_draw_scale + vec2_from_scalar(glyph_padding)
screenspace_x_form( & glyph_draw_translate, & glyph_draw_scale, glyph_buffer_width, glyph_buffer_height )
cache_glyph( ctx, entry.id, glyph, entry, bounds_0, bounds_1, glyph_draw_scale, glyph_draw_translate )
@ -368,14 +381,14 @@ directly_draw_massive_glyph :: proc( ctx : ^Context, entry : ^Entry, glyph : Gly
// Figure out the destination rect.
bounds_0_scaled := Vec2 {
cast(f32) i32(f32(bounds_0.x) * entry.size_scale - 0.5),
cast(f32) i32(f32(bounds_0.y) * entry.size_scale - 0.5),
cast(f32) i32(bounds_0.x * entry.size_scale - 0.5),
cast(f32) i32(bounds_0.y * entry.size_scale - 0.5),
}
dst := position + scale * bounds_0_scaled
dst_width := scale.x * glyph_dst_width
dst_height := scale.y * glyph_dst_height
dst.x -= scale.x * f32(ctx.atlas.draw_padding)
dst.y -= scale.y * f32(ctx.atlas.draw_padding)
dst.x -= scale.x * glyph_padding
dst.y -= scale.y * glyph_padding
dst_size := Vec2{ dst_width, dst_height }
glyph_size := Vec2 { glyph_width, glyph_height }
@ -401,11 +414,16 @@ directly_draw_massive_glyph :: proc( ctx : ^Context, entry : ^Entry, glyph : Gly
append( & ctx.draw_list.calls, call )
}
draw_cached_glyph :: proc( ctx : ^Context, entry : ^Entry, glyph_index : Glyph,
lru_code : u64, atlas_index : i32,
bounds_0, bounds_1 : Vec2i,
region_kind : AtlasRegionKind, region : ^AtlasRegion, over_sample : Vec2,
position, scale : Vec2
draw_cached_glyph :: proc( ctx : ^Context,
entry : ^Entry,
glyph_index : Glyph,
lru_code : u64,
atlas_index : i32,
bounds_0, bounds_1 : Vec2,
region_kind : AtlasRegionKind,
region : ^AtlasRegion,
over_sample : Vec2,
position, scale : Vec2
) -> b32
{
// profile(#procedure)
@ -440,10 +458,8 @@ draw_cached_glyph :: proc( ctx : ^Context, entry : ^Entry, glyph_index : Glyph,
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 = {
math.ceil(bounds_0_scaled.x),
math.ceil(bounds_0_scaled.y),
}
bounds_0_scaled = ceil(bounds_0_scaled)
dst := position + bounds_0_scaled * scale
dst -= scale * glyph_padding
dst_width := scale.x * glyph_width
@ -516,12 +532,14 @@ draw_filled_path :: proc( draw_list : ^DrawList, outside_point : Vec2, path : []
}
}
draw_text_batch :: proc( ctx : ^Context, entry : ^Entry, shaped : ^ShapedText, batch_start_idx, batch_end_idx : i32, position, scale : Vec2, snap_width, snap_height : f32 )
draw_text_batch :: proc( ctx : ^Context, entry : ^Entry, shaped : ^ShapedText,
batch_start_idx, batch_end_idx : i32,
position, scale : Vec2,
snap_width, snap_height : f32 )
{
// flush_glyph_buffer_to_atlas( ctx )
flush_glyph_buffer_to_atlas( ctx )
for index := batch_start_idx; index < batch_end_idx; index += 1
{
// profile(#procedure)
glyph_index := shaped.glyphs[ index ]
if glyph_index == 0 do continue
@ -537,10 +555,10 @@ draw_text_batch :: proc( ctx : ^Context, entry : ^Entry, shaped : ^ShapedText, b
shaped_position := shaped.positions[index]
glyph_translate := position + shaped_position * scale
glyph_cached := draw_cached_glyph( ctx,
entry, glyph_index,
lru_code, atlas_index,
bounds_0, bounds_1,
glyph_cached := draw_cached_glyph( ctx,
entry, glyph_index,
lru_code, atlas_index,
vec2(bounds_0), vec2(bounds_1),
region_kind, region, over_sample,
glyph_translate, scale)
assert( glyph_cached == true )
@ -548,7 +566,13 @@ draw_text_batch :: proc( ctx : ^Context, entry : ^Entry, shaped : ^ShapedText, b
}
// Helper for draw_text, all raw text content should be confirmed to be either formatting or visible shapes before getting cached.
draw_text_shape :: proc( ctx : ^Context, font : FontID, entry : ^Entry, shaped : ^ShapedText, position, scale : Vec2, snap_width, snap_height : f32 ) -> (cursor_pos : Vec2)
draw_text_shape :: proc( ctx : ^Context,
font : FontID,
entry : ^Entry,
shaped : ^ShapedText,
position, scale : Vec2,
snap_width, snap_height : f32
) -> (cursor_pos : Vec2)
{
// position := position //+ ctx.cursor_pos * scale
// profile(#procedure)
@ -568,7 +592,7 @@ draw_text_shape :: proc( ctx : ^Context, font : FontID, entry : ^Entry, shaped :
// Glyph has not been catched, needs to be directly drawn.
// First batch the other cached glyphs
flush_glyph_buffer_to_atlas(ctx)
// flush_glyph_buffer_to_atlas(ctx)
draw_text_batch( ctx, entry, shaped, batch_start_idx, index, position, scale, snap_width, snap_height )
reset_batch_codepoint_state( ctx )
@ -577,7 +601,7 @@ draw_text_shape :: proc( ctx : ^Context, font : FontID, entry : ^Entry, shaped :
batch_start_idx = index
}
flush_glyph_buffer_to_atlas(ctx)
// 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 )
reset_batch_codepoint_state( ctx )
cursor_pos = shaped.end_cursor_pos
@ -588,22 +612,21 @@ flush_glyph_buffer_to_atlas :: proc( ctx : ^Context )
{
// profile(#procedure)
// Flush drawcalls to draw list
merge_draw_list( & ctx.draw_list, & ctx.atlas.clear_draw_list )
merge_draw_list( & ctx.draw_list, & ctx.atlas.draw_list)
clear_draw_list( & ctx.atlas.draw_list )
clear_draw_list( & ctx.atlas.clear_draw_list )
merge_draw_list( & ctx.draw_list, & ctx.glyph_buffer.clear_draw_list )
merge_draw_list( & ctx.draw_list, & ctx.glyph_buffer.draw_list)
clear_draw_list( & ctx.glyph_buffer.draw_list )
clear_draw_list( & ctx.glyph_buffer.clear_draw_list )
// Clear glyph_update_FBO
if ctx.atlas.update_batch_x != 0
if ctx.glyph_buffer.batch_x != 0
{
call := DrawCall_Default
call.pass = .Glyph
call.start_index = 0
call.end_index = 0
call.pass = .Glyph
call.start_index = 0
call.end_index = 0
call.clear_before_draw = true
append( & ctx.draw_list.calls, call )
ctx.atlas.update_batch_x = 0
ctx.glyph_buffer.batch_x = 0
}
}
@ -614,23 +637,19 @@ merge_draw_list :: proc( dst, src : ^DrawList )
error : AllocatorError
v_offset := cast(u32) len( dst.vertices )
// for index : u32 = 0; index < cast(u32) src.vertices.num; index += 1 {
// error = append( & dst.vertices, src.vertices.data[index] )
// assert( error == .None )
// }
num_appended : int
num_appended, error = append_elems( & dst.vertices, ..src.vertices[:] )
num_appended, error = append( & dst.vertices, ..src.vertices[:] )
assert( error == .None )
i_offset := cast(u32) len(dst.indices)
for index : u32 = 0; index < cast(u32) len(src.indices); index += 1 {
for index : int = 0; index < len(src.indices); index += 1 {
ignored : int
ignored, error = append( & dst.indices, src.indices[index] + v_offset )
assert( error == .None )
}
for index : u32 = 0; index < cast(u32) len(src.calls); index += 1 {
src_call := src.calls[ index ]
for index : int = 0; index < len(src.calls); index += 1 {
src_call := src.calls[ index ]
src_call.start_index += i_offset
src_call.end_index += i_offset
append( & dst.calls, src_call )

View File

@ -1,36 +1,36 @@
package VEFontCache
import "core:hash"
crc64 :: hash.crc64_xz
crc32 :: hash.crc32
fnv64a :: hash.fnv64a
import "core:math"
ceil_f16 :: math.ceil_f16
ceil_f16le :: math.ceil_f16le
ceil_f16be :: math.ceil_f16be
ceil_f32 :: math.ceil_f32
ceil_f32le :: math.ceil_f32le
ceil_f32be :: math.ceil_f32be
ceil_f64 :: math.ceil_f64
ceil_f64le :: math.ceil_f64le
ceil_f64be :: math.ceil_f64be
import "core:math/linalg"
import "core:mem"
Kilobyte :: mem.Kilobyte
slice_ptr :: mem.slice_ptr
Kilobyte :: mem.Kilobyte
slice_ptr :: mem.slice_ptr
Arena :: mem.Arena
arena_allocator :: mem.arena_allocator
arena_init :: mem.arena_init
Allocator :: mem.Allocator
AllocatorError :: mem.Allocator_Error
Allocator :: mem.Allocator
AllocatorError :: mem.Allocator_Error
Arena :: mem.Arena
arena_allocator :: mem.arena_allocator
arena_init :: mem.arena_init
import "codebase:grime"
hmap_closest_prime :: grime.hmap_closest_prime
// logging
log :: grime.log
logf :: grime.logf
profile :: grime.profile
reload_array :: grime.reload_array
reload_map :: grime.reload_map
hmap_closest_prime :: grime.hmap_closest_prime
log :: grime.log
logf :: grime.logf
profile :: grime.profile
reload_array :: grime.reload_array
reload_map :: grime.reload_map
//#region("Proc overload mappings")
@ -40,6 +40,20 @@ append :: proc {
append_elem_string,
}
ceil :: proc {
math.ceil_f16,
math.ceil_f16le,
math.ceil_f16be,
math.ceil_f32,
math.ceil_f32le,
math.ceil_f32be,
math.ceil_f64,
math.ceil_f64le,
math.ceil_f64be,
grime.ceil_vec2,
}
clear :: proc {
clear_dynamic_array,
}
@ -51,13 +65,17 @@ make :: proc {
make_map,
}
resize :: proc {
resize_dynamic_array,
}
vec2 :: proc {
vec2_from_scalar,
vec2_from_vec2i,
}
vec2_64 :: proc {
vec2_64_from_vec2,
}
//#endregion("Proc overload mappings")

View File

@ -4,7 +4,6 @@ Note(Ed): The only reason I didn't directly use harfbuzz is because hamza exists
*/
import "core:c"
import "core:math"
import "thirdparty:harfbuzz"
ShaperKind :: enum {
@ -112,9 +111,9 @@ shaper_shape_from_text :: proc( ctx : ^ShaperContext, info : ^ShaperInfo, output
(vertical_position^) = cast(f32) i32(vertical_position^ + 0.5)
continue
}
if math.abs( size ) <= Advance_Snap_Smallfont_Size
if abs( size ) <= Advance_Snap_Smallfont_Size
{
(position^) = math.ceil( position^ )
(position^) = ceil( position^ )
}
append( & output.glyphs, glyph_id )