minor reorganization
This commit is contained in:
parent
894c3fee97
commit
1f4d07727e
@ -24,6 +24,7 @@ TODO Additional Features:
|
||||
* Support for harfbuzz
|
||||
* Ability to set a draw transform, viewport and projection
|
||||
* By default the library's position is in unsigned normalized render space
|
||||
* Allow curve_quality to be set on a per-font basis
|
||||
|
||||
TODO Optimizations:
|
||||
|
||||
|
@ -13,47 +13,24 @@ Changes:
|
||||
package VEFontCache
|
||||
|
||||
import "base:runtime"
|
||||
import "core:math"
|
||||
import "core:mem"
|
||||
|
||||
Advance_Snap_Smallfont_Size :: 12
|
||||
|
||||
FontID :: distinct i64
|
||||
Glyph :: distinct i32
|
||||
|
||||
Colour :: [4]f32
|
||||
Vec2 :: [2]f32
|
||||
Vec2i :: [2]i32
|
||||
|
||||
vec2_from_scalar :: proc( scalar : f32 ) -> Vec2 { return { scalar, scalar } }
|
||||
|
||||
AtlasRegionKind :: enum u8 {
|
||||
None = 0x00,
|
||||
A = 0x41,
|
||||
B = 0x42,
|
||||
C = 0x43,
|
||||
D = 0x44,
|
||||
E = 0x45,
|
||||
Ignore = 0xFF, // ve_fontcache_cache_glyph_to_atlas uses a -1 value in clear draw call
|
||||
}
|
||||
FontID :: distinct i64
|
||||
Glyph :: distinct i32
|
||||
|
||||
Vertex :: struct {
|
||||
pos : Vec2,
|
||||
u, v : f32,
|
||||
}
|
||||
|
||||
ShapedText :: struct {
|
||||
glyphs : Array(Glyph),
|
||||
positions : Array(Vec2),
|
||||
end_cursor_pos : Vec2,
|
||||
}
|
||||
|
||||
ShapedTextCache :: struct {
|
||||
storage : Array(ShapedText),
|
||||
state : LRU_Cache,
|
||||
next_cache_id : i32,
|
||||
}
|
||||
|
||||
Entry :: struct {
|
||||
parser_info : ParserFontInfo,
|
||||
shaper_info : ShaperInfo,
|
||||
@ -100,82 +77,7 @@ Context :: struct {
|
||||
debug_print_verbose : b32,
|
||||
}
|
||||
|
||||
get_cursor_pos :: proc( ctx : ^Context ) -> Vec2 { return ctx.cursor_pos }
|
||||
set_colour :: proc( ctx : ^Context, colour : Colour ) { ctx.colour = colour }
|
||||
|
||||
font_glyph_lru_code :: #force_inline proc( font : FontID, glyph_index : Glyph ) -> (lru_code : u64)
|
||||
{
|
||||
// font := font
|
||||
// glyph_index := glyph_index
|
||||
|
||||
// font_bytes := slice_ptr( transmute(^byte) & font, size_of(FontID) )
|
||||
// glyph_bytes := slice_ptr( transmute(^byte) & glyph_index, size_of(Glyph) )
|
||||
|
||||
// buffer : [32]byte
|
||||
// copy( buffer[:], font_bytes )
|
||||
// copy( buffer[ len(font_bytes) :], glyph_bytes )
|
||||
// hash := fnv64a( transmute([]byte) buffer[: size_of(FontID) + size_of(Glyph) ] )
|
||||
// lru_code = hash
|
||||
|
||||
lru_code = u64(glyph_index) + ( ( 0x100000000 * u64(font) ) & 0xFFFFFFFF00000000 )
|
||||
return
|
||||
}
|
||||
|
||||
label_hash :: #force_inline proc( label : string ) -> u64 {
|
||||
hash : u64
|
||||
for str_byte in transmute([]byte) label {
|
||||
hash = ((hash << 8) + hash) + u64(str_byte)
|
||||
}
|
||||
return hash
|
||||
}
|
||||
|
||||
// For a provided alpha value,
|
||||
// allows the function to calculate the position of a point along the curve at any given fraction of its total length
|
||||
// ve_fontcache_eval_bezier (quadratic)
|
||||
eval_point_on_bezier3 :: proc( p0, p1, p2 : Vec2, alpha : f32 ) -> Vec2
|
||||
{
|
||||
weight_start := (1 - alpha) * (1 - alpha)
|
||||
weight_control := 2.0 * (1 - alpha) * alpha
|
||||
weight_end := alpha * alpha
|
||||
|
||||
starting_point := p0 * weight_start
|
||||
control_point := p1 * weight_control
|
||||
end_point := p2 * weight_end
|
||||
|
||||
point := starting_point + control_point + end_point
|
||||
return point
|
||||
}
|
||||
|
||||
// For a provided alpha value,
|
||||
// allows the function to calculate the position of a point along the curve at any given fraction of its total length
|
||||
// ve_fontcache_eval_bezier (cubic)
|
||||
eval_point_on_bezier4 :: proc( p0, p1, p2, p3 : Vec2, alpha : f32 ) -> Vec2
|
||||
{
|
||||
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
|
||||
weight_end := alpha * alpha * alpha
|
||||
|
||||
start_point := p0 * weight_start
|
||||
control_a := p1 * weight_c_a
|
||||
control_b := p2 * weight_c_b
|
||||
end_point := p3 * weight_end
|
||||
|
||||
point := start_point + control_a + control_b + end_point
|
||||
return point
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
textspace_x_form :: proc( position, scale : ^Vec2, width, height : f32 ) {
|
||||
quotient := 1.0 / Vec2 { width, height }
|
||||
(position^) *= quotient
|
||||
(scale^) *= quotient
|
||||
}
|
||||
#region("lifetime")
|
||||
|
||||
InitAtlasRegionParams :: struct {
|
||||
width : u32,
|
||||
@ -223,7 +125,7 @@ InitGlyphDrawParams :: struct {
|
||||
}
|
||||
|
||||
InitGlyphDrawParams_Default :: InitGlyphDrawParams {
|
||||
over_sample = { 4, 4 },
|
||||
over_sample = { 8, 8 },
|
||||
buffer_batch = 4,
|
||||
draw_padding = InitAtlasParams_Default.glyph_padding,
|
||||
}
|
||||
@ -244,7 +146,7 @@ init :: 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 = 12,
|
||||
entires_reserve : u32 = Kilobyte,
|
||||
temp_path_reserve : u32 = Kilobyte,
|
||||
temp_codepoint_seen_reserve : u32 = 512,
|
||||
@ -420,6 +322,8 @@ shutdown :: proc( ctx : ^Context )
|
||||
shaper_shutdown( & shaper_ctx )
|
||||
}
|
||||
|
||||
#endregion("lifetime")
|
||||
|
||||
// ve_fontcache_configure_snap
|
||||
configure_snap :: proc( ctx : ^Context, snap_width, snap_height : u32 ) {
|
||||
assert( ctx != nil )
|
||||
@ -709,8 +613,8 @@ cache_glyph_to_atlas :: proc( ctx : ^Context, font : FontID, glyph_index : Glyph
|
||||
{
|
||||
// Queue up clear on target region on atlas
|
||||
using call
|
||||
pass = .Atlas
|
||||
region = .Ignore
|
||||
pass = .Atlas
|
||||
region = .Ignore
|
||||
start_index = u32(atlas.clear_draw_list.indices.num)
|
||||
blit_quad( & atlas.clear_draw_list, dst_position, dst_position + dst_size, { 1.0, 1.0 }, { 1.0, 1.0 } )
|
||||
end_index = u32(atlas.clear_draw_list.indices.num)
|
||||
@ -728,6 +632,9 @@ cache_glyph_to_atlas :: proc( ctx : ^Context, font : FontID, glyph_index : Glyph
|
||||
cache_glyph( ctx, font, glyph_index, glyph_draw_scale, glyph_draw_translate )
|
||||
}
|
||||
|
||||
get_cursor_pos :: proc( ctx : ^Context ) -> Vec2 { return ctx.cursor_pos }
|
||||
set_colour :: proc( ctx : ^Context, colour : Colour ) { ctx.colour = colour }
|
||||
|
||||
is_empty :: proc( ctx : ^Context, entry : ^Entry, glyph_index : Glyph ) -> b32
|
||||
{
|
||||
if glyph_index == 0 do return true
|
||||
@ -742,14 +649,11 @@ measure_text_size :: proc( ctx : ^Context, font : FontID, text_utf8 : string ) -
|
||||
|
||||
context.allocator = ctx.backing
|
||||
|
||||
atlas := ctx.atlas
|
||||
|
||||
shaped := shape_text_cached( ctx, font, text_utf8 )
|
||||
|
||||
entry := & ctx.entries.data[ font ]
|
||||
atlas := ctx.atlas
|
||||
shaped := shape_text_cached( ctx, font, text_utf8 )
|
||||
entry := & ctx.entries.data[ font ]
|
||||
padding := 2 * cast(f32) atlas.glyph_padding
|
||||
|
||||
batch_start_idx : i32 = 0
|
||||
for index : i32 = 0; index < i32(shaped.glyphs.num); index += 1
|
||||
{
|
||||
glyph_index := shaped.glyphs.data[ index ]
|
||||
@ -773,121 +677,3 @@ measure_text_size :: proc( ctx : ^Context, font : FontID, text_utf8 : string ) -
|
||||
|
||||
return measured
|
||||
}
|
||||
|
||||
reset_batch_codepoint_state :: proc( ctx : ^Context ) {
|
||||
clear( & ctx.temp_codepoint_seen )
|
||||
ctx.temp_codepoint_seen_num = 0
|
||||
}
|
||||
|
||||
shape_text_cached :: proc( ctx : ^Context, font : FontID, text_utf8 : string ) -> ^ShapedText
|
||||
{
|
||||
@static buffer : [64 * Kilobyte]byte
|
||||
|
||||
font := font
|
||||
|
||||
buffer_slice := buffer[:]
|
||||
font_bytes := slice_ptr( transmute(^byte) & font, size_of(FontID) )
|
||||
copy( buffer_slice, font_bytes )
|
||||
|
||||
text_bytes := transmute( []byte) text_utf8
|
||||
buffer_slice_post_font := buffer[size_of(FontID) : size_of(FontID) + len(text_utf8) ]
|
||||
copy( buffer_slice_post_font, text_bytes )
|
||||
|
||||
hash := label_hash( transmute(string) buffer[: size_of(FontID) + len(text_utf8)] )
|
||||
|
||||
shape_cache := & ctx.shape_cache
|
||||
state := & ctx.shape_cache.state
|
||||
|
||||
shape_cache_idx := LRU_get( state, hash )
|
||||
if shape_cache_idx == -1
|
||||
{
|
||||
if shape_cache.next_cache_id < i32(state.capacity) {
|
||||
shape_cache_idx = shape_cache.next_cache_id
|
||||
shape_cache.next_cache_id += 1
|
||||
evicted := LRU_put( state, hash, shape_cache_idx )
|
||||
assert( evicted == hash )
|
||||
}
|
||||
else
|
||||
{
|
||||
next_evict_idx := LRU_get_next_evicted( state )
|
||||
assert( next_evict_idx != 0xFFFFFFFFFFFFFFFF )
|
||||
|
||||
shape_cache_idx = LRU_peek( state, next_evict_idx, must_find = true )
|
||||
assert( shape_cache_idx != - 1 )
|
||||
|
||||
LRU_put( state, hash, shape_cache_idx )
|
||||
}
|
||||
|
||||
shape_text_uncached( ctx, font, & shape_cache.storage.data[ shape_cache_idx ], text_utf8 )
|
||||
}
|
||||
|
||||
return & shape_cache.storage.data[ shape_cache_idx ]
|
||||
}
|
||||
|
||||
shape_text_uncached :: proc( ctx : ^Context, font : FontID, output : ^ShapedText, text_utf8 : string )
|
||||
{
|
||||
assert( ctx != nil )
|
||||
assert( font >= 0 && font < FontID(ctx.entries.num) )
|
||||
|
||||
use_full_text_shape := ctx.text_shape_adv
|
||||
entry := & ctx.entries.data[ font ]
|
||||
|
||||
clear( output.glyphs )
|
||||
clear( output.positions )
|
||||
|
||||
ascent, descent, line_gap := parser_get_font_vertical_metrics( & entry.parser_info )
|
||||
|
||||
if use_full_text_shape
|
||||
{
|
||||
// assert( entry.shaper_info != nil )
|
||||
shaper_shape_from_text( & ctx.shaper_ctx, & entry.shaper_info, output, text_utf8, ascent, descent, line_gap, entry.size, entry.size_scale )
|
||||
return
|
||||
}
|
||||
else
|
||||
{
|
||||
ascent := f32(ascent)
|
||||
descent := f32(descent)
|
||||
line_gap := f32(line_gap)
|
||||
|
||||
// Note(Original Author):
|
||||
// We use our own fallback dumbass text shaping.
|
||||
// WARNING: PLEASE USE HARFBUZZ. GOOD TEXT SHAPING IS IMPORTANT FOR INTERNATIONALISATION.
|
||||
|
||||
position : Vec2
|
||||
advance : i32 = 0
|
||||
to_left_side_glyph : i32 = 0
|
||||
|
||||
prev_codepoint : rune
|
||||
for codepoint in text_utf8
|
||||
{
|
||||
if prev_codepoint > 0 {
|
||||
kern := parser_get_codepoint_kern_advance( & entry.parser_info, prev_codepoint, codepoint )
|
||||
position.x += f32(kern) * entry.size_scale
|
||||
}
|
||||
if codepoint == '\n'
|
||||
{
|
||||
position.x = 0.0
|
||||
position.y -= (ascent - descent + line_gap) * entry.size_scale
|
||||
position.y = cast(f32) i32( position.y + 0.5 )
|
||||
prev_codepoint = rune(0)
|
||||
continue
|
||||
}
|
||||
if math.abs( entry.size ) <= Advance_Snap_Smallfont_Size {
|
||||
position.x = math.ceil( position.x )
|
||||
}
|
||||
|
||||
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
|
||||
})
|
||||
|
||||
position.x += f32(advance) * entry.size_scale
|
||||
prev_codepoint = codepoint
|
||||
}
|
||||
|
||||
output.end_cursor_pos = position
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,15 @@
|
||||
package VEFontCache
|
||||
|
||||
AtlasRegionKind :: enum u8 {
|
||||
None = 0x00,
|
||||
A = 0x41,
|
||||
B = 0x42,
|
||||
C = 0x43,
|
||||
D = 0x44,
|
||||
E = 0x45,
|
||||
Ignore = 0xFF, // ve_fontcache_cache_glyph_to_atlas uses a -1 value in clear draw call
|
||||
}
|
||||
|
||||
AtlasRegion :: struct {
|
||||
state : LRU_Cache,
|
||||
|
||||
|
7
code/font/VEFontCache/docs/Readme.md
Normal file
7
code/font/VEFontCache/docs/Readme.md
Normal file
@ -0,0 +1,7 @@
|
||||
# Documentation
|
||||
|
||||
Work in progress...
|
||||
|
||||
|
||||
|
||||
|
@ -400,6 +400,20 @@ draw_text :: proc( ctx : ^Context, font : FontID, text_utf8 : string, position :
|
||||
return true
|
||||
}
|
||||
|
||||
draw_text_batch :: proc( ctx : ^Context, entry : ^Entry, shaped : ^ShapedText, batch_start_idx, batch_end_idx : i32, position, scale : Vec2 )
|
||||
{
|
||||
flush_glyph_buffer_to_atlas( ctx )
|
||||
for index := batch_start_idx; index < batch_end_idx; index += 1
|
||||
{
|
||||
glyph_index := shaped.glyphs.data[ index ]
|
||||
shaped_position := shaped.positions.data[index]
|
||||
glyph_translate := position + shaped_position * scale
|
||||
glyph_cached := draw_cached_glyph( ctx, entry, glyph_index, glyph_translate, scale)
|
||||
assert( glyph_cached == true )
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 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)
|
||||
{
|
||||
@ -429,19 +443,6 @@ draw_text_shape :: proc( ctx : ^Context, font : FontID, entry : ^Entry, shaped :
|
||||
return
|
||||
}
|
||||
|
||||
draw_text_batch :: proc( ctx : ^Context, entry : ^Entry, shaped : ^ShapedText, batch_start_idx, batch_end_idx : i32, position, scale : Vec2 )
|
||||
{
|
||||
flush_glyph_buffer_to_atlas( ctx )
|
||||
for index := batch_start_idx; index < batch_end_idx; index += 1
|
||||
{
|
||||
glyph_index := shaped.glyphs.data[ index ]
|
||||
shaped_position := shaped.positions.data[index]
|
||||
glyph_translate := position + shaped_position * scale
|
||||
glyph_cached := draw_cached_glyph( ctx, entry, glyph_index, glyph_translate, scale)
|
||||
assert( glyph_cached == true )
|
||||
}
|
||||
}
|
||||
|
||||
// ve_fontcache_flush_drawlist
|
||||
flush_draw_list :: proc( ctx : ^Context ) {
|
||||
assert( ctx != nil )
|
||||
|
@ -137,4 +137,8 @@ underlying_slice :: proc {
|
||||
array_underlying_slice,
|
||||
}
|
||||
|
||||
vec2 :: proc {
|
||||
vec2_from_scalar,
|
||||
}
|
||||
|
||||
//#endregion("Proc overload mappings")
|
||||
|
80
code/font/VEFontCache/misc.odin
Normal file
80
code/font/VEFontCache/misc.odin
Normal file
@ -0,0 +1,80 @@
|
||||
package VEFontCache
|
||||
|
||||
font_glyph_lru_code :: #force_inline proc( font : FontID, glyph_index : Glyph ) -> (lru_code : u64)
|
||||
{
|
||||
// font := font
|
||||
// glyph_index := glyph_index
|
||||
|
||||
// font_bytes := slice_ptr( transmute(^byte) & font, size_of(FontID) )
|
||||
// glyph_bytes := slice_ptr( transmute(^byte) & glyph_index, size_of(Glyph) )
|
||||
|
||||
// buffer : [32]byte
|
||||
// copy( buffer[:], font_bytes )
|
||||
// copy( buffer[ len(font_bytes) :], glyph_bytes )
|
||||
// hash := fnv64a( transmute([]byte) buffer[: size_of(FontID) + size_of(Glyph) ] )
|
||||
// lru_code = hash
|
||||
|
||||
lru_code = u64(glyph_index) + ( ( 0x100000000 * u64(font) ) & 0xFFFFFFFF00000000 )
|
||||
return
|
||||
}
|
||||
|
||||
shape_lru_hash :: #force_inline proc( label : string ) -> u64 {
|
||||
hash : u64
|
||||
for str_byte in transmute([]byte) label {
|
||||
hash = ((hash << 8) + hash) + u64(str_byte)
|
||||
}
|
||||
return hash
|
||||
}
|
||||
|
||||
// For a provided alpha value,
|
||||
// allows the function to calculate the position of a point along the curve at any given fraction of its total length
|
||||
// ve_fontcache_eval_bezier (quadratic)
|
||||
eval_point_on_bezier3 :: proc( p0, p1, p2 : Vec2, alpha : f32 ) -> Vec2
|
||||
{
|
||||
weight_start := (1 - alpha) * (1 - alpha)
|
||||
weight_control := 2.0 * (1 - alpha) * alpha
|
||||
weight_end := alpha * alpha
|
||||
|
||||
starting_point := p0 * weight_start
|
||||
control_point := p1 * weight_control
|
||||
end_point := p2 * weight_end
|
||||
|
||||
point := starting_point + control_point + end_point
|
||||
return point
|
||||
}
|
||||
|
||||
// For a provided alpha value,
|
||||
// allows the function to calculate the position of a point along the curve at any given fraction of its total length
|
||||
// ve_fontcache_eval_bezier (cubic)
|
||||
eval_point_on_bezier4 :: proc( p0, p1, p2, p3 : Vec2, alpha : f32 ) -> Vec2
|
||||
{
|
||||
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
|
||||
weight_end := alpha * alpha * alpha
|
||||
|
||||
start_point := p0 * weight_start
|
||||
control_a := p1 * weight_c_a
|
||||
control_b := p2 * weight_c_b
|
||||
end_point := p3 * weight_end
|
||||
|
||||
point := start_point + control_a + control_b + end_point
|
||||
return point
|
||||
}
|
||||
|
||||
reset_batch_codepoint_state :: proc( ctx : ^Context ) {
|
||||
clear( & ctx.temp_codepoint_seen )
|
||||
ctx.temp_codepoint_seen_num = 0
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
textspace_x_form :: proc( position, scale : ^Vec2, width, height : f32 ) {
|
||||
quotient := 1.0 / Vec2 { width, height }
|
||||
(position^) *= quotient
|
||||
(scale^) *= quotient
|
||||
}
|
127
code/font/VEFontCache/shaped_text.odin
Normal file
127
code/font/VEFontCache/shaped_text.odin
Normal file
@ -0,0 +1,127 @@
|
||||
package VEFontCache
|
||||
|
||||
import "core:math"
|
||||
|
||||
ShapedText :: struct {
|
||||
glyphs : Array(Glyph),
|
||||
positions : Array(Vec2),
|
||||
end_cursor_pos : Vec2,
|
||||
}
|
||||
|
||||
ShapedTextCache :: struct {
|
||||
storage : Array(ShapedText),
|
||||
state : LRU_Cache,
|
||||
next_cache_id : i32,
|
||||
}
|
||||
|
||||
shape_text_cached :: proc( ctx : ^Context, font : FontID, text_utf8 : string ) -> ^ShapedText
|
||||
{
|
||||
@static buffer : [64 * Kilobyte]byte
|
||||
|
||||
font := font
|
||||
|
||||
buffer_slice := buffer[:]
|
||||
font_bytes := slice_ptr( transmute(^byte) & font, size_of(FontID) )
|
||||
copy( buffer_slice, font_bytes )
|
||||
|
||||
text_bytes := transmute( []byte) text_utf8
|
||||
buffer_slice_post_font := buffer[size_of(FontID) : size_of(FontID) + len(text_utf8) ]
|
||||
copy( buffer_slice_post_font, text_bytes )
|
||||
|
||||
hash := shape_lru_hash( transmute(string) buffer[: size_of(FontID) + len(text_utf8)] )
|
||||
|
||||
shape_cache := & ctx.shape_cache
|
||||
state := & ctx.shape_cache.state
|
||||
|
||||
shape_cache_idx := LRU_get( state, hash )
|
||||
if shape_cache_idx == -1
|
||||
{
|
||||
if shape_cache.next_cache_id < i32(state.capacity) {
|
||||
shape_cache_idx = shape_cache.next_cache_id
|
||||
shape_cache.next_cache_id += 1
|
||||
evicted := LRU_put( state, hash, shape_cache_idx )
|
||||
assert( evicted == hash )
|
||||
}
|
||||
else
|
||||
{
|
||||
next_evict_idx := LRU_get_next_evicted( state )
|
||||
assert( next_evict_idx != 0xFFFFFFFFFFFFFFFF )
|
||||
|
||||
shape_cache_idx = LRU_peek( state, next_evict_idx, must_find = true )
|
||||
assert( shape_cache_idx != - 1 )
|
||||
|
||||
LRU_put( state, hash, shape_cache_idx )
|
||||
}
|
||||
|
||||
shape_text_uncached( ctx, font, & shape_cache.storage.data[ shape_cache_idx ], text_utf8 )
|
||||
}
|
||||
|
||||
return & shape_cache.storage.data[ shape_cache_idx ]
|
||||
}
|
||||
|
||||
shape_text_uncached :: proc( ctx : ^Context, font : FontID, output : ^ShapedText, text_utf8 : string )
|
||||
{
|
||||
assert( ctx != nil )
|
||||
assert( font >= 0 && font < FontID(ctx.entries.num) )
|
||||
|
||||
use_full_text_shape := ctx.text_shape_adv
|
||||
entry := & ctx.entries.data[ font ]
|
||||
|
||||
clear( output.glyphs )
|
||||
clear( output.positions )
|
||||
|
||||
ascent, descent, line_gap := parser_get_font_vertical_metrics( & entry.parser_info )
|
||||
|
||||
if use_full_text_shape
|
||||
{
|
||||
// assert( entry.shaper_info != nil )
|
||||
shaper_shape_from_text( & ctx.shaper_ctx, & entry.shaper_info, output, text_utf8, ascent, descent, line_gap, entry.size, entry.size_scale )
|
||||
return
|
||||
}
|
||||
else
|
||||
{
|
||||
// Note(Original Author):
|
||||
// We use our own fallback dumbass text shaping.
|
||||
// WARNING: PLEASE USE HARFBUZZ. GOOD TEXT SHAPING IS IMPORTANT FOR INTERNATIONALISATION.
|
||||
ascent := f32(ascent)
|
||||
descent := f32(descent)
|
||||
line_gap := f32(line_gap)
|
||||
|
||||
position : Vec2
|
||||
advance : i32 = 0
|
||||
to_left_side_glyph : i32 = 0
|
||||
|
||||
prev_codepoint : rune
|
||||
for codepoint in text_utf8
|
||||
{
|
||||
if prev_codepoint > 0 {
|
||||
kern := parser_get_codepoint_kern_advance( & entry.parser_info, prev_codepoint, codepoint )
|
||||
position.x += f32(kern) * entry.size_scale
|
||||
}
|
||||
if codepoint == '\n'
|
||||
{
|
||||
position.x = 0.0
|
||||
position.y -= (ascent - descent + line_gap) * entry.size_scale
|
||||
position.y = cast(f32) i32( position.y + 0.5 )
|
||||
prev_codepoint = rune(0)
|
||||
continue
|
||||
}
|
||||
if abs( entry.size ) <= Advance_Snap_Smallfont_Size {
|
||||
position.x = math.ceil( position.x )
|
||||
}
|
||||
|
||||
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
|
||||
})
|
||||
|
||||
position.x += f32(advance) * entry.size_scale
|
||||
prev_codepoint = codepoint
|
||||
}
|
||||
|
||||
output.end_cursor_pos = position
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user