VEFontCache: Lifted the GlyphDrawBuffer member of atlas to the context
This commit is contained in:
parent
343d558a94
commit
8e8f25ba50
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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 )
|
||||
|
@ -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")
|
||||
|
@ -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 )
|
||||
|
Loading…
Reference in New Issue
Block a user