mirror of
https://github.com/Ed94/VEFontCache-Odin.git
synced 2025-08-06 06:52:44 -07:00
Progress on cleanup
This commit is contained in:
@@ -35,8 +35,8 @@ Upcoming:
|
|||||||
* Support for which triangulation method used on a by font basis?
|
* Support for which triangulation method used on a by font basis?
|
||||||
* Multi-threading supported job queue.
|
* Multi-threading supported job queue.
|
||||||
* Lift heavy-lifting portion of the library's context into a thread context.
|
* Lift heavy-lifting portion of the library's context into a thread context.
|
||||||
* Synchronize threads by merging their generated layered drawlist into a file draw-list for processing on the user's render thread.
|
* Synchronize threads by merging their generated layered draw list into a finished draw-list for processing on the user's render thread.
|
||||||
* User defines how context's are distributed for drawing (a basic quandrant basic selector procedure will be provided.)
|
* User defines how thread context's are distributed for drawing (a basic quandrant based selector procedure will be provided.)
|
||||||
|
|
||||||
See: [docs/Readme.md](docs/Readme.md) for the library's interface.
|
See: [docs/Readme.md](docs/Readme.md) for the library's interface.
|
||||||
|
|
||||||
|
@@ -12,7 +12,6 @@ Atlas_Region_Kind :: enum u8 {
|
|||||||
Ignore = 0xFF, // ve_fontcache_cache_glyph_to_atlas uses a -1 value in clear draw call
|
Ignore = 0xFF, // ve_fontcache_cache_glyph_to_atlas uses a -1 value in clear draw call
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note(Ed): Using 16 bit hash had collision failures and no observable performance improvement (tried several 16-bit hashers)
|
|
||||||
Atlas_Key :: u32
|
Atlas_Key :: u32
|
||||||
|
|
||||||
// TODO(Ed) It might perform better with a tailored made hashtable implementation for the LRU_Cache or dedicated array struct/procs for the Atlas.
|
// TODO(Ed) It might perform better with a tailored made hashtable implementation for the LRU_Cache or dedicated array struct/procs for the Atlas.
|
||||||
|
@@ -3,7 +3,7 @@ package vefontcache
|
|||||||
when false {
|
when false {
|
||||||
// TODO(Ed): Freetype support
|
// TODO(Ed): Freetype support
|
||||||
|
|
||||||
// TODO(Ed): glyph caching cannot be handled in a 'font parser' abstraction. Just going to have explicit procedures to grab info neatly...
|
// TODO(Ed): glyph triangulation cannot be handled in a 'font parser' abstraction. Just going to have explicit procedures to grab info neatly...
|
||||||
cache_glyph_freetype :: proc(ctx: ^Context, font: Font_ID, glyph_index: Glyph, entry: ^Entry, bounds_0, bounds_1: Vec2, scale, translate: Vec2) -> b32
|
cache_glyph_freetype :: proc(ctx: ^Context, font: Font_ID, glyph_index: Glyph, entry: ^Entry, bounds_0, bounds_1: Vec2, scale, translate: Vec2) -> b32
|
||||||
{
|
{
|
||||||
draw_filled_path_freetype :: proc( draw_list : ^Draw_List, outside_point : Vec2, path : []Vertex,
|
draw_filled_path_freetype :: proc( draw_list : ^Draw_List, outside_point : Vec2, path : []Vertex,
|
||||||
|
@@ -12,7 +12,7 @@ Freetype isn't really supported and its not a high priority (pretty sure its too
|
|||||||
STB_Truetype:
|
STB_Truetype:
|
||||||
* Has macros for its allocation unfortuantely.
|
* Has macros for its allocation unfortuantely.
|
||||||
TODO(Ed): Just keep a local version of stb_truetype and modify it to support a sokol/odin compatible allocator.
|
TODO(Ed): Just keep a local version of stb_truetype and modify it to support a sokol/odin compatible allocator.
|
||||||
Already wanted to do so anyway to evaluate the glyph point shape implementation on its side.
|
Already wanted to do so anyway to evaluate the shape generation implementation.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import "base:runtime"
|
import "base:runtime"
|
||||||
@@ -24,7 +24,7 @@ import stbtt "vendor:stb/truetype"
|
|||||||
|
|
||||||
Parser_Kind :: enum u32 {
|
Parser_Kind :: enum u32 {
|
||||||
STB_TrueType,
|
STB_TrueType,
|
||||||
Freetype,
|
Freetype, // Currently not implemented.
|
||||||
}
|
}
|
||||||
|
|
||||||
Parser_Font_Info :: struct {
|
Parser_Font_Info :: struct {
|
||||||
@@ -63,40 +63,16 @@ Parser_Context :: struct {
|
|||||||
|
|
||||||
parser_init :: proc( ctx : ^Parser_Context, kind : Parser_Kind )
|
parser_init :: proc( ctx : ^Parser_Context, kind : Parser_Kind )
|
||||||
{
|
{
|
||||||
// switch kind
|
|
||||||
// {
|
|
||||||
// case .Freetype:
|
|
||||||
// result := freetype.init_free_type( & ctx.ft_library )
|
|
||||||
// assert( result == freetype.Error.Ok, "VEFontCache.parser_init: Failed to initialize freetype" )
|
|
||||||
|
|
||||||
// case .STB_TrueType:
|
|
||||||
// Do nothing intentional
|
|
||||||
// }
|
|
||||||
|
|
||||||
ctx.kind = kind
|
ctx.kind = kind
|
||||||
}
|
}
|
||||||
|
|
||||||
parser_shutdown :: proc( ctx : ^Parser_Context ) {
|
parser_shutdown :: proc( ctx : ^Parser_Context ) {
|
||||||
// TODO(Ed): Implement
|
// Note: Not necesssary for stb_truetype
|
||||||
}
|
}
|
||||||
|
|
||||||
parser_load_font :: proc( ctx : ^Parser_Context, label : string, data : []byte ) -> (font : Parser_Font_Info, error : b32)
|
parser_load_font :: proc( ctx : ^Parser_Context, label : string, data : []byte ) -> (font : Parser_Font_Info, error : b32)
|
||||||
{
|
{
|
||||||
// switch ctx.kind
|
|
||||||
// {
|
|
||||||
// case .Freetype:
|
|
||||||
// when ODIN_OS == .Windows {
|
|
||||||
// error_status := freetype.new_memory_face( ctx.ft_library, raw_data(data), cast(i32) len(data), 0, & font.freetype_info )
|
|
||||||
// if error != .Ok do error = true
|
|
||||||
// }
|
|
||||||
// else when ODIN_OS == .Linux {
|
|
||||||
// error := freetype.new_memory_face( ctx.ft_library, raw_data(data), cast(i64) len(data), 0, & font.freetype_info )
|
|
||||||
// if error_status != .Ok do error = true
|
|
||||||
// }
|
|
||||||
|
|
||||||
// case .STB_TrueType:
|
|
||||||
error = ! stbtt.InitFont( & font.stbtt_info, raw_data(data), 0 )
|
error = ! stbtt.InitFont( & font.stbtt_info, raw_data(data), 0 )
|
||||||
// }
|
|
||||||
|
|
||||||
font.label = label
|
font.label = label
|
||||||
font.data = data
|
font.data = data
|
||||||
@@ -106,122 +82,36 @@ parser_load_font :: proc( ctx : ^Parser_Context, label : string, data : []byte )
|
|||||||
|
|
||||||
parser_unload_font :: proc( font : ^Parser_Font_Info )
|
parser_unload_font :: proc( font : ^Parser_Font_Info )
|
||||||
{
|
{
|
||||||
// switch font.kind {
|
// case .STB_TrueType:
|
||||||
// case .Freetype:
|
// Do Nothing
|
||||||
// error := freetype.done_face( font.freetype_info )
|
|
||||||
// assert( error == .Ok, "VEFontCache.parser_unload_font: Failed to unload freetype face" )
|
|
||||||
|
|
||||||
// case .STB_TrueType:
|
|
||||||
// Do Nothing
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
parser_find_glyph_index :: #force_inline proc "contextless" ( font : Parser_Font_Info, codepoint : rune ) -> (glyph_index : Glyph)
|
parser_find_glyph_index :: #force_inline proc "contextless" ( font : Parser_Font_Info, codepoint : rune ) -> (glyph_index : Glyph)
|
||||||
{
|
{
|
||||||
// profile(#procedure)
|
glyph_index = transmute(Glyph) stbtt.FindGlyphIndex( font.stbtt_info, codepoint )
|
||||||
// switch font.kind
|
return
|
||||||
// {
|
|
||||||
// case .Freetype:
|
|
||||||
// when ODIN_OS == .Windows {
|
|
||||||
// glyph_index = transmute(Glyph) freetype.get_char_index( font.freetype_info, transmute(u32) codepoint )
|
|
||||||
// }
|
|
||||||
// else when ODIN_OS == .Linux {
|
|
||||||
// glyph_index = transmute(Glyph) freetype.get_char_index( font.freetype_info, cast(u64) codepoint )
|
|
||||||
// }
|
|
||||||
// return
|
|
||||||
|
|
||||||
// case .STB_TrueType:
|
|
||||||
glyph_index = transmute(Glyph) stbtt.FindGlyphIndex( font.stbtt_info, codepoint )
|
|
||||||
return
|
|
||||||
// }
|
|
||||||
// return Glyph(-1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
parser_free_shape :: #force_inline proc( font : Parser_Font_Info, shape : Parser_Glyph_Shape )
|
parser_free_shape :: #force_inline proc( font : Parser_Font_Info, shape : Parser_Glyph_Shape )
|
||||||
{
|
{
|
||||||
// switch font.kind
|
stbtt.FreeShape( font.stbtt_info, transmute( [^]stbtt.vertex) raw_data(shape) )
|
||||||
// {
|
|
||||||
// case .Freetype:
|
|
||||||
// delete(shape)
|
|
||||||
|
|
||||||
// case .STB_TrueType:
|
|
||||||
stbtt.FreeShape( font.stbtt_info, transmute( [^]stbtt.vertex) raw_data(shape) )
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
parser_get_codepoint_horizontal_metrics :: #force_inline proc "contextless" ( font : Parser_Font_Info, codepoint : rune ) -> ( advance, to_left_side_glyph : i32 )
|
parser_get_codepoint_horizontal_metrics :: #force_inline proc "contextless" ( font : Parser_Font_Info, codepoint : rune ) -> ( advance, to_left_side_glyph : i32 )
|
||||||
{
|
{
|
||||||
// switch font.kind
|
stbtt.GetCodepointHMetrics( font.stbtt_info, codepoint, & advance, & to_left_side_glyph )
|
||||||
// {
|
|
||||||
// case .Freetype:
|
|
||||||
// glyph_index : Glyph
|
|
||||||
// when ODIN_OS == .Windows {
|
|
||||||
// glyph_index = transmute(Glyph) freetype.get_char_index( font.freetype_info, transmute(u32) codepoint )
|
|
||||||
// }
|
|
||||||
// else when ODIN_OS == .Linux {
|
|
||||||
// glyph_index = transmute(Glyph) freetype.get_char_index( font.freetype_info, cast(u64) codepoint )
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if glyph_index != 0
|
|
||||||
// {
|
|
||||||
// freetype.load_glyph( font.freetype_info, c.uint(codepoint), { .No_Bitmap, .No_Hinting, .No_Scale } )
|
|
||||||
// advance = i32(font.freetype_info.glyph.advance.x) >> 6
|
|
||||||
// to_left_side_glyph = i32(font.freetype_info.glyph.metrics.hori_bearing_x) >> 6
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// advance = 0
|
|
||||||
// to_left_side_glyph = 0
|
|
||||||
// }
|
|
||||||
|
|
||||||
// case .STB_TrueType:
|
|
||||||
stbtt.GetCodepointHMetrics( font.stbtt_info, codepoint, & advance, & to_left_side_glyph )
|
|
||||||
// }
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
parser_get_codepoint_kern_advance :: #force_inline proc "contextless" ( font : Parser_Font_Info, prev_codepoint, codepoint : rune ) -> i32
|
parser_get_codepoint_kern_advance :: #force_inline proc "contextless" ( font : Parser_Font_Info, prev_codepoint, codepoint : rune ) -> i32
|
||||||
{
|
{
|
||||||
// switch font.kind
|
kern := stbtt.GetCodepointKernAdvance( font.stbtt_info, prev_codepoint, codepoint )
|
||||||
// {
|
return kern
|
||||||
// case .Freetype:
|
|
||||||
// prev_glyph_index : Glyph
|
|
||||||
// glyph_index : Glyph
|
|
||||||
// when ODIN_OS == .Windows {
|
|
||||||
// prev_glyph_index = transmute(Glyph) freetype.get_char_index( font.freetype_info, transmute(u32) prev_codepoint )
|
|
||||||
// glyph_index = transmute(Glyph) freetype.get_char_index( font.freetype_info, transmute(u32) codepoint )
|
|
||||||
// }
|
|
||||||
// else when ODIN_OS == .Linux {
|
|
||||||
// prev_glyph_index = transmute(Glyph) freetype.get_char_index( font.freetype_info, cast(u64) prev_codepoint )
|
|
||||||
// glyph_index = transmute(Glyph) freetype.get_char_index( font.freetype_info, cast(u64) codepoint )
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if prev_glyph_index != 0 && glyph_index != 0
|
|
||||||
// {
|
|
||||||
// kerning : freetype.Vector
|
|
||||||
// font.freetype_info.driver.clazz.get_kerning( font.freetype_info, transmute(u32) prev_codepoint, transmute(u32) codepoint, & kerning )
|
|
||||||
// }
|
|
||||||
|
|
||||||
// case .STB_TrueType:
|
|
||||||
kern := stbtt.GetCodepointKernAdvance( font.stbtt_info, prev_codepoint, codepoint )
|
|
||||||
return kern
|
|
||||||
// }
|
|
||||||
// return -1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
parser_get_font_vertical_metrics :: #force_inline proc "contextless" ( font : Parser_Font_Info ) -> (ascent, descent, line_gap : i32 )
|
parser_get_font_vertical_metrics :: #force_inline proc "contextless" ( font : Parser_Font_Info ) -> (ascent, descent, line_gap : i32 )
|
||||||
{
|
{
|
||||||
// switch font.kind
|
stbtt.GetFontVMetrics( font.stbtt_info, & ascent, & descent, & line_gap )
|
||||||
// {
|
|
||||||
// case .Freetype:
|
|
||||||
// info := font.freetype_info
|
|
||||||
// ascent = i32(info.ascender)
|
|
||||||
// descent = i32(info.descender)
|
|
||||||
// line_gap = i32(info.height) - (ascent - descent)
|
|
||||||
|
|
||||||
// case .STB_TrueType:
|
|
||||||
stbtt.GetFontVMetrics( font.stbtt_info, & ascent, & descent, & line_gap )
|
|
||||||
// }
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -230,122 +120,47 @@ parser_get_bounds :: #force_inline proc "contextless" ( font : Parser_Font_Info,
|
|||||||
// profile(#procedure)
|
// profile(#procedure)
|
||||||
bounds_0, bounds_1 : Vec2i
|
bounds_0, bounds_1 : Vec2i
|
||||||
|
|
||||||
// switch font.kind
|
x0, y0, x1, y1 : i32
|
||||||
// {
|
success := cast(bool) stbtt.GetGlyphBox( font.stbtt_info, i32(glyph_index), & x0, & y0, & x1, & y1 )
|
||||||
// case .Freetype:
|
|
||||||
// freetype.load_glyph( font.freetype_info, c.uint(glyph_index), { .No_Bitmap, .No_Hinting, .No_Scale } )
|
|
||||||
|
|
||||||
// metrics := font.freetype_info.glyph.metrics
|
bounds_0 = { x0, y0 }
|
||||||
|
bounds_1 = { x1, y1 }
|
||||||
// bounds_0 = {i32(metrics.hori_bearing_x), i32(metrics.hori_bearing_y - metrics.height)}
|
|
||||||
// bounds_1 = {i32(metrics.hori_bearing_x + metrics.width), i32(metrics.hori_bearing_y)}
|
|
||||||
|
|
||||||
// case .STB_TrueType:
|
|
||||||
x0, y0, x1, y1 : i32
|
|
||||||
success := cast(bool) stbtt.GetGlyphBox( font.stbtt_info, i32(glyph_index), & x0, & y0, & x1, & y1 )
|
|
||||||
// assert( success )
|
|
||||||
|
|
||||||
bounds_0 = { x0, y0 }
|
|
||||||
bounds_1 = { x1, y1 }
|
|
||||||
// }
|
|
||||||
bounds = { vec2(bounds_0), vec2(bounds_1) }
|
bounds = { vec2(bounds_0), vec2(bounds_1) }
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
parser_get_glyph_shape :: #force_inline proc ( font : Parser_Font_Info, glyph_index : Glyph ) -> (shape : Parser_Glyph_Shape, error : Allocator_Error)
|
parser_get_glyph_shape :: #force_inline proc ( font : Parser_Font_Info, glyph_index : Glyph ) -> (shape : Parser_Glyph_Shape, error : Allocator_Error)
|
||||||
{
|
{
|
||||||
// switch font.kind
|
stb_shape : [^]stbtt.vertex
|
||||||
// {
|
nverts := stbtt.GetGlyphShape( font.stbtt_info, cast(i32) glyph_index, & stb_shape )
|
||||||
// case .Freetype:
|
|
||||||
// // TODO(Ed): Don't do this, going a completely different route for handling shapes.
|
|
||||||
// // This abstraction fails to be time-saving or performant.
|
|
||||||
|
|
||||||
// case .STB_TrueType:
|
|
||||||
stb_shape : [^]stbtt.vertex
|
|
||||||
nverts := stbtt.GetGlyphShape( font.stbtt_info, cast(i32) glyph_index, & stb_shape )
|
|
||||||
|
|
||||||
shape_raw := transmute( ^runtime.Raw_Dynamic_Array) & shape
|
|
||||||
shape_raw.data = stb_shape
|
|
||||||
shape_raw.len = int(nverts)
|
|
||||||
shape_raw.cap = int(nverts)
|
|
||||||
shape_raw.allocator = runtime.nil_allocator()
|
|
||||||
error = Allocator_Error.None
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
shape_raw := transmute( ^runtime.Raw_Dynamic_Array) & shape
|
||||||
|
shape_raw.data = stb_shape
|
||||||
|
shape_raw.len = int(nverts)
|
||||||
|
shape_raw.cap = int(nverts)
|
||||||
|
shape_raw.allocator = runtime.nil_allocator()
|
||||||
|
error = Allocator_Error.None
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
parser_is_glyph_empty :: #force_inline proc "contextless" ( font : Parser_Font_Info, glyph_index : Glyph ) -> b32
|
parser_is_glyph_empty :: #force_inline proc "contextless" ( font : Parser_Font_Info, glyph_index : Glyph ) -> b32
|
||||||
{
|
{
|
||||||
// switch font.kind
|
return stbtt.IsGlyphEmpty( font.stbtt_info, cast(c.int) glyph_index )
|
||||||
// {
|
|
||||||
// case .Freetype:
|
|
||||||
// error := freetype.load_glyph( font.freetype_info, cast(u32) glyph_index, { .No_Bitmap, .No_Hinting, .No_Scale } )
|
|
||||||
// if error == .Ok
|
|
||||||
// {
|
|
||||||
// if font.freetype_info.glyph.format == .Outline {
|
|
||||||
// return font.freetype_info.glyph.outline.n_points == 0
|
|
||||||
// }
|
|
||||||
// else if font.freetype_info.glyph.format == .Bitmap {
|
|
||||||
// return font.freetype_info.glyph.bitmap.width == 0 && font.freetype_info.glyph.bitmap.rows == 0;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// return false
|
|
||||||
|
|
||||||
// case .STB_TrueType:
|
|
||||||
return stbtt.IsGlyphEmpty( font.stbtt_info, cast(c.int) glyph_index )
|
|
||||||
// }
|
|
||||||
// return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
parser_scale :: #force_inline proc "contextless" ( font : Parser_Font_Info, size : f32 ) -> f32
|
parser_scale :: #force_inline proc "contextless" ( font : Parser_Font_Info, size : f32 ) -> f32
|
||||||
{
|
{
|
||||||
// profile(#procedure)
|
// profile(#procedure)
|
||||||
// size_scale := size < 0.0 ? parser_scale_for_pixel_height( font, -size ) : parser_scale_for_mapping_em_to_pixels( font, size )
|
|
||||||
size_scale := size > 0.0 ? parser_scale_for_pixel_height( font, size ) : parser_scale_for_mapping_em_to_pixels( font, -size )
|
size_scale := size > 0.0 ? parser_scale_for_pixel_height( font, size ) : parser_scale_for_mapping_em_to_pixels( font, -size )
|
||||||
return size_scale
|
return size_scale
|
||||||
}
|
}
|
||||||
|
|
||||||
parser_scale_for_pixel_height :: #force_inline proc "contextless" ( font : Parser_Font_Info, size : f32 ) -> f32
|
parser_scale_for_pixel_height :: #force_inline proc "contextless" ( font : Parser_Font_Info, size : f32 ) -> f32
|
||||||
{
|
{
|
||||||
// switch font.kind {
|
return stbtt.ScaleForPixelHeight( font.stbtt_info, size )
|
||||||
// case .Freetype:
|
|
||||||
// freetype.set_pixel_sizes( font.freetype_info, 0, cast(u32) size )
|
|
||||||
// size_scale := size / cast(f32)font.freetype_info.units_per_em
|
|
||||||
// return size_scale
|
|
||||||
|
|
||||||
// case.STB_TrueType:
|
|
||||||
return stbtt.ScaleForPixelHeight( font.stbtt_info, size )
|
|
||||||
// }
|
|
||||||
// return 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
parser_scale_for_mapping_em_to_pixels :: #force_inline proc "contextless" ( font : Parser_Font_Info, size : f32 ) -> f32
|
parser_scale_for_mapping_em_to_pixels :: #force_inline proc "contextless" ( font : Parser_Font_Info, size : f32 ) -> f32
|
||||||
{
|
{
|
||||||
// switch font.kind {
|
return stbtt.ScaleForMappingEmToPixels( font.stbtt_info, size )
|
||||||
// case .Freetype:
|
|
||||||
// Inches_To_CM :: cast(f32) 2.54
|
|
||||||
// Points_Per_CM :: cast(f32) 28.3465
|
|
||||||
// CM_Per_Point :: cast(f32) 1.0 / DPT_DPCM
|
|
||||||
// CM_Per_Pixel :: cast(f32) 1.0 / DPT_PPCM
|
|
||||||
// DPT_DPCM :: cast(f32) 72.0 * Inches_To_CM // 182.88 points/dots per cm
|
|
||||||
// DPT_PPCM :: cast(f32) 96.0 * Inches_To_CM // 243.84 pixels per cm
|
|
||||||
// DPT_DPI :: cast(f32) 72.0
|
|
||||||
|
|
||||||
// // TODO(Ed): Don't assume the dots or pixels per inch.
|
|
||||||
// system_dpi :: DPT_DPI
|
|
||||||
|
|
||||||
// FT_Font_Size_Point_Unit :: 1.0 / 64.0
|
|
||||||
// FT_Point_10 :: 64.0
|
|
||||||
|
|
||||||
// points_per_em := (size / system_dpi ) * DPT_DPI
|
|
||||||
// freetype.set_char_size( font.freetype_info, 0, cast(freetype.F26Dot6) f32(points_per_em * FT_Point_10), cast(u32) DPT_DPI, cast(u32) DPT_DPI )
|
|
||||||
// size_scale := f32(f64(size) / cast(f64) font.freetype_info.units_per_em)
|
|
||||||
// return size_scale
|
|
||||||
|
|
||||||
// case .STB_TrueType:
|
|
||||||
return stbtt.ScaleForMappingEmToPixels( font.stbtt_info, size )
|
|
||||||
// }
|
|
||||||
// return 0
|
|
||||||
}
|
}
|
||||||
|
@@ -136,22 +136,4 @@ vec2_64 :: proc {
|
|||||||
vec2_64_from_vec2,
|
vec2_64_from_vec2,
|
||||||
}
|
}
|
||||||
|
|
||||||
import "../../grime"
|
|
||||||
|
|
||||||
@(deferred_none = profile_end, disabled = DISABLE_PROFILING)
|
|
||||||
profile :: #force_inline proc "contextless" ( name : string, loc := #caller_location ) {
|
|
||||||
grime.profile_begin(name, loc)
|
|
||||||
}
|
|
||||||
|
|
||||||
@(disabled = DISABLE_PROFILING)
|
|
||||||
profile_begin :: #force_inline proc "contextless" ( name : string, loc := #caller_location ) {
|
|
||||||
grime.profile_begin(name, loc)
|
|
||||||
}
|
|
||||||
|
|
||||||
@(disabled = DISABLE_PROFILING)
|
|
||||||
profile_end :: #force_inline proc "contextless" () {
|
|
||||||
grime.profile_end()
|
|
||||||
}
|
|
||||||
|
|
||||||
//#endregion("Proc overload mappings")
|
//#endregion("Proc overload mappings")
|
||||||
|
|
||||||
|
17
vefontcache/profiling.odin
Normal file
17
vefontcache/profiling.odin
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package vefontcache
|
||||||
|
|
||||||
|
// Add profiling hookup here
|
||||||
|
|
||||||
|
// import ""
|
||||||
|
|
||||||
|
@(deferred_none = profile_end, disabled = DISABLE_PROFILING)
|
||||||
|
profile :: #force_inline proc "contextless" ( name : string, loc := #caller_location ) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@(disabled = DISABLE_PROFILING)
|
||||||
|
profile_begin :: #force_inline proc "contextless" ( name : string, loc := #caller_location ) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@(disabled = DISABLE_PROFILING)
|
||||||
|
profile_end :: #force_inline proc "contextless" () {
|
||||||
|
}
|
@@ -13,15 +13,14 @@ Shape_Key :: u32
|
|||||||
Traditionally a shape only refers to resolving which glyph and
|
Traditionally a shape only refers to resolving which glyph and
|
||||||
its position should be used for rendering.
|
its position should be used for rendering.
|
||||||
|
|
||||||
For this library's case it also involes keeping any content
|
For this library's case it also resolves any content that does not have to be done
|
||||||
that does not have to be resolved once again in the later stage of processing:
|
on a per-frame basis for draw list generation.
|
||||||
* Resolve atlas lru codes
|
* Resolve atlas lru codes
|
||||||
* Resolve glyph bounds and scale
|
* Resolve glyph bounds and scale
|
||||||
* Resolve atlas region the glyph is associated with.
|
* Resolve atlas region the glyph is associated with.
|
||||||
|
|
||||||
Ideally the user should resolve this shape once and cache/store it on their side.
|
Ideally the user should resolve this shape once and cache/store it on their side.
|
||||||
They have the best ability to avoid costly lookups to streamline
|
They have the best ability to avoid costly lookups.
|
||||||
a hot path to only focusing on draw list generation that must be computed every frame.
|
|
||||||
*/
|
*/
|
||||||
Shaped_Text :: struct #packed {
|
Shaped_Text :: struct #packed {
|
||||||
glyph : [dynamic]Glyph,
|
glyph : [dynamic]Glyph,
|
||||||
@@ -190,8 +189,8 @@ shaper_shape_harfbuzz :: proc( ctx : ^Shaper_Context, text_utf8 : string, entry
|
|||||||
f32(hb_gposition.x_advance) * font_scale,
|
f32(hb_gposition.x_advance) * font_scale,
|
||||||
f32(hb_gposition.y_advance) * font_scale
|
f32(hb_gposition.y_advance) * font_scale
|
||||||
}
|
}
|
||||||
(position^) += advance
|
(position^) += advance
|
||||||
(max_line_width^) = max(max_line_width^, position.x)
|
(max_line_width^) = max(max_line_width^, position.x)
|
||||||
|
|
||||||
is_empty := parser_is_glyph_empty(entry.parser_info, glyph)
|
is_empty := parser_is_glyph_empty(entry.parser_info, glyph)
|
||||||
if ! is_empty {
|
if ! is_empty {
|
||||||
|
@@ -94,7 +94,8 @@ Context :: struct {
|
|||||||
|
|
||||||
stack : Scope_Stack,
|
stack : Scope_Stack,
|
||||||
|
|
||||||
cursor_pos : Vec2, // TODO(Ed): Review this (most likely not being used properly right now)
|
colour : RGBAN, // Color used in draw interface TODO(Ed): use the stack
|
||||||
|
cursor_pos : Vec2, // TODO(Ed): Review this, no longer used much at all... (still useful I guess)
|
||||||
// Will apply a boost scalar (1.0 + alpha sharpen) to the colour's alpha which provides some sharpening of the edges.
|
// Will apply a boost scalar (1.0 + alpha sharpen) to the colour's alpha which provides some sharpening of the edges.
|
||||||
// Has a boldening side-effect. If overblown will look smeared.
|
// Has a boldening side-effect. If overblown will look smeared.
|
||||||
alpha_sharpen : f32,
|
alpha_sharpen : f32,
|
||||||
@@ -647,11 +648,9 @@ get_cursor_pos :: #force_inline proc "contextless" ( ctx : Context ) -> Vec2 { r
|
|||||||
get_snapped_position :: #force_inline proc "contextless" ( position : Vec2, view : Vec2 ) -> (snapped_position : Vec2) {
|
get_snapped_position :: #force_inline proc "contextless" ( position : Vec2, view : Vec2 ) -> (snapped_position : Vec2) {
|
||||||
snap_quotient := 1 / Vec2 { max(view.x, 1), max(view.y, 1) }
|
snap_quotient := 1 / Vec2 { max(view.x, 1), max(view.y, 1) }
|
||||||
should_snap := view * snap_quotient
|
should_snap := view * snap_quotient
|
||||||
|
|
||||||
snapped_position = position
|
snapped_position = position
|
||||||
snapped_position.x = ceil(position.x * view.x) * snap_quotient.x
|
snapped_position.x = ceil(position.x * view.x) * snap_quotient.x
|
||||||
snapped_position.y = ceil(position.y * view.y) * snap_quotient.y
|
snapped_position.y = ceil(position.y * view.y) * snap_quotient.y
|
||||||
|
|
||||||
snapped_position *= should_snap
|
snapped_position *= should_snap
|
||||||
snapped_position.x = max(snapped_position.x, position.x)
|
snapped_position.x = max(snapped_position.x, position.x)
|
||||||
snapped_position.y = max(snapped_position.y, position.y)
|
snapped_position.y = max(snapped_position.y, position.y)
|
||||||
@@ -763,7 +762,7 @@ draw_text_normalized_space :: proc( ctx : ^Context,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Equivalent to draw_text_shape_normalized_space, however position's units is scaled to view and must be normalized.
|
// Equivalent to draw_text_shape_normalized_space, however position's units is scaled to view and must be normalized.
|
||||||
@(optimization_mode="favor_size")
|
// @(optimization_mode="favor_size")
|
||||||
draw_text_shape_view_space :: #force_inline proc( ctx : ^Context,
|
draw_text_shape_view_space :: #force_inline proc( ctx : ^Context,
|
||||||
font : Font_ID,
|
font : Font_ID,
|
||||||
px_size : f32,
|
px_size : f32,
|
||||||
@@ -805,16 +804,16 @@ draw_text_shape_view_space :: #force_inline proc( ctx : ^Context,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Equivalent to draw_text_normalized_space, however position's units is scaled to view and must be normalized.
|
// Equivalent to draw_text_normalized_space, however position's units is scaled to view and must be normalized.
|
||||||
@(optimization_mode = "favor_size")
|
// @(optimization_mode = "favor_size")
|
||||||
draw_text_view_space :: proc(ctx : ^Context,
|
draw_text_view_space :: proc(ctx : ^Context,
|
||||||
font : Font_ID,
|
font : Font_ID,
|
||||||
px_size : f32,
|
px_size : f32,
|
||||||
colour : RGBAN,
|
colour : RGBAN,
|
||||||
view : Vec2,
|
view : Vec2,
|
||||||
view_position : Vec2,
|
position : Vec2,
|
||||||
scale : Vec2,
|
scale : Vec2,
|
||||||
zoom : f32, // TODO(Ed): Implement Zoom support
|
zoom : f32, // TODO(Ed): Implement Zoom support
|
||||||
text_utf8 : string
|
text_utf8 : string
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
profile(#procedure)
|
profile(#procedure)
|
||||||
@@ -855,7 +854,7 @@ draw_text_view_space :: proc(ctx : ^Context,
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@(optimization_mode = "favor_size")
|
// @(optimization_mode = "favor_size")
|
||||||
draw_shape :: proc( ctx : ^Context, position, scale : Vec2, shape : Shaped_Text )
|
draw_shape :: proc( ctx : ^Context, position, scale : Vec2, shape : Shaped_Text )
|
||||||
{
|
{
|
||||||
profile(#procedure)
|
profile(#procedure)
|
||||||
@@ -908,7 +907,7 @@ draw_shape :: proc( ctx : ^Context, position, scale : Vec2, shape : Shaped_Text
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@(optimization_mode = "favor_size")
|
// @(optimization_mode = "favor_size")
|
||||||
draw_text :: proc( ctx : ^Context, position, scale : Vec2, text_utf8 : string )
|
draw_text :: proc( ctx : ^Context, position, scale : Vec2, text_utf8 : string )
|
||||||
{
|
{
|
||||||
profile(#procedure)
|
profile(#procedure)
|
||||||
@@ -1020,7 +1019,7 @@ measure_text_size :: #force_inline proc( ctx : ^Context, font : Font_ID, px_size
|
|||||||
|
|
||||||
entry := ctx.entries[font]
|
entry := ctx.entries[font]
|
||||||
|
|
||||||
downscale := 1 / ctx.px_scalar
|
target_scale := 1 / ctx.px_scalar
|
||||||
target_px_size := px_size * ctx.px_scalar
|
target_px_size := px_size * ctx.px_scalar
|
||||||
target_font_scale := parser_scale( entry.parser_info, target_px_size )
|
target_font_scale := parser_scale( entry.parser_info, target_px_size )
|
||||||
|
|
||||||
@@ -1035,7 +1034,7 @@ measure_text_size :: #force_inline proc( ctx : ^Context, font : Font_ID, px_size
|
|||||||
target_font_scale,
|
target_font_scale,
|
||||||
shaper_shape_text_uncached_advanced
|
shaper_shape_text_uncached_advanced
|
||||||
)
|
)
|
||||||
return shaped.size * downscale
|
return shaped.size * target_scale
|
||||||
}
|
}
|
||||||
|
|
||||||
get_font_vertical_metrics :: #force_inline proc ( ctx : ^Context, font : Font_ID, px_size : f32 ) -> ( ascent, descent, line_gap : f32 )
|
get_font_vertical_metrics :: #force_inline proc ( ctx : ^Context, font : Font_ID, px_size : f32 ) -> ( ascent, descent, line_gap : f32 )
|
||||||
@@ -1102,7 +1101,6 @@ shape_text_advanced :: #force_inline proc( ctx : ^Context, font : Font_ID, px_si
|
|||||||
}
|
}
|
||||||
|
|
||||||
// User handled shaped text. Will not be cached
|
// User handled shaped text. Will not be cached
|
||||||
// @(disabled = true)
|
|
||||||
shape_text_latin_uncached :: #force_inline proc( ctx : ^Context, font : Font_ID, px_size: f32, text_utf8 : string, shape : ^Shaped_Text )
|
shape_text_latin_uncached :: #force_inline proc( ctx : ^Context, font : Font_ID, px_size: f32, text_utf8 : string, shape : ^Shaped_Text )
|
||||||
{
|
{
|
||||||
profile(#procedure)
|
profile(#procedure)
|
||||||
@@ -1125,7 +1123,6 @@ shape_text_latin_uncached :: #force_inline proc( ctx : ^Context, font : Font_ID,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// User handled shaped text. Will not be cached
|
// User handled shaped text. Will not be cached
|
||||||
// @(disabled = true)
|
|
||||||
shape_text_advanced_uncached :: #force_inline proc( ctx : ^Context, font : Font_ID, px_size: f32, text_utf8 : string, shape : ^Shaped_Text )
|
shape_text_advanced_uncached :: #force_inline proc( ctx : ^Context, font : Font_ID, px_size: f32, text_utf8 : string, shape : ^Shaped_Text )
|
||||||
{
|
{
|
||||||
profile(#procedure)
|
profile(#procedure)
|
||||||
|
Reference in New Issue
Block a user