Finished draft porting pass for VE Font Cache (next is hook to sokol_gfx + runtime testing)
This commit is contained in:
parent
d469fd53e8
commit
566a90001b
@ -15,6 +15,8 @@ Changes:
|
||||
*/
|
||||
package VEFontCache
|
||||
|
||||
import "core:math"
|
||||
|
||||
Advance_Snap_Smallfont_Size :: 12
|
||||
|
||||
FontID :: distinct i64
|
||||
@ -25,12 +27,13 @@ Vec2 :: [2]f32
|
||||
Vec2i :: [2]u32
|
||||
|
||||
AtlasRegionKind :: enum u8 {
|
||||
None = 0x00,
|
||||
A = 0x41,
|
||||
B = 0x42,
|
||||
C = 0x43,
|
||||
D = 0x44,
|
||||
E = 0x45,
|
||||
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
|
||||
}
|
||||
|
||||
Vertex :: struct {
|
||||
@ -571,6 +574,9 @@ cache_glyph_to_atlas :: proc( ctx : ^Context, font : FontID, glyph_index : Glyph
|
||||
assert( LRU_get( & region.state, lru_code ) != - 1 )
|
||||
}
|
||||
|
||||
atlas := & ctx.atlas
|
||||
glyph_padding := cast(f32) atlas.glyph_padding
|
||||
|
||||
if ctx.debug_print
|
||||
{
|
||||
@static debug_total_cached : i32 = 0
|
||||
@ -580,29 +586,72 @@ cache_glyph_to_atlas :: proc( ctx : ^Context, font : FontID, glyph_index : Glyph
|
||||
|
||||
// Draw oversized glyph to update FBO
|
||||
glyph_draw_scale := over_sample * entry.size_scale
|
||||
glyph_draw_translate := Vec2 { f32(bounds_0.x), f32(bounds_0.y) } * glyph_draw_scale + Vec2{ f32(ctx.atlas.glyph_padding), f32(ctx.atlas.glyph_padding) }
|
||||
glyph_draw_translate := Vec2 { f32(bounds_0.x), f32(bounds_0.y) } * glyph_draw_scale + Vec2{ glyph_padding, 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 =
|
||||
gwidth_scaled_px := i32( f32(bounds_width) * f32(glyph_draw_scale.x) + 1.0 ) + i32(2 * over_sample.x * glyph_padding)
|
||||
if i32(atlas.update_batch_x + gwidth_scaled_px) >= i32(atlas.buffer_width) {
|
||||
flush_glyph_buffer_to_atlas( ctx )
|
||||
}
|
||||
|
||||
// Calculate the src and destination regions
|
||||
dst_position, dst_width, dst_height := atlas_bbox( atlas, region_kind, u32(atlas_index) )
|
||||
dst_glyph_position := dst_position //+ { glyph_padding, glyph_padding }
|
||||
dst_glyph_width := f32(bounds_width) * entry.size_scale
|
||||
dst_glyph_height := f32(bounds_height) * entry.size_scale
|
||||
// dst_glyph_position -= { glyph_padding, glyph_padding }
|
||||
dst_glyph_width += 2 * glyph_padding
|
||||
dst_glyph_height += 2 * glyph_padding
|
||||
|
||||
dst_size := Vec2 { dst_width, dst_height }
|
||||
dst_glyph_size := Vec2 { dst_glyph_width, dst_glyph_height }
|
||||
screenspace_x_form( & dst_glyph_position, & dst_glyph_size, f32(atlas.buffer_width), f32(atlas.buffer_height) )
|
||||
screenspace_x_form( & dst_position, & dst_size, f32(atlas.buffer_width), f32(atlas.buffer_height) )
|
||||
|
||||
src_position := Vec2 { f32(atlas.update_batch_x), 0 }
|
||||
src_size := Vec2 {
|
||||
f32(bounds_width) * glyph_draw_scale.x,
|
||||
f32(bounds_height) * glyph_draw_scale.y,
|
||||
}
|
||||
src_size += Vec2{1,1} * 2 * over_sample * glyph_padding
|
||||
textspace_x_form( & src_position, & src_size, f32(atlas.buffer_width), f32(atlas.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
|
||||
screenspace_x_form( & glyph_draw_translate, & glyph_draw_scale, f32(atlas.buffer_width), f32(atlas.buffer_height))
|
||||
|
||||
// Queue up clear on target region on atlas
|
||||
call : DrawCall
|
||||
{
|
||||
// Queue up clear on target region on atlas
|
||||
using call
|
||||
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)
|
||||
append( & atlas.clear_draw_list.calls, call )
|
||||
|
||||
// Queue up a blit from glyph_update_FBO to the atlas
|
||||
region = .None
|
||||
start_index = u32(atlas.draw_list.indices.num)
|
||||
blit_quad( & atlas.draw_list, dst_glyph_position, dst_glyph_position + dst_glyph_size, src_position, src_position + src_size )
|
||||
end_index = u32(atlas.draw_list.indices.num)
|
||||
append( & atlas.draw_list.calls, call )
|
||||
}
|
||||
|
||||
// Queue up a blit from glyph_update_FBO to the atlas
|
||||
|
||||
// Render glyph to glyph_update_FBO
|
||||
// cache_glyph( )
|
||||
cache_glyph( ctx, font, glyph_index, glyph_draw_scale, glyph_draw_translate )
|
||||
}
|
||||
|
||||
directly_draw_massive_glyph :: proc( ctx : ^Context, entry : ^Entry, glyph : Glyph, bounds_0 : Vec2i, bounds_width, bounds_height : u32, over_sample, position, scale : Vec2 )
|
||||
{
|
||||
flush_glyph_buffer_to_atlas( ctx )
|
||||
|
||||
// Draw un-antialiased glyph to update FBO.
|
||||
glyph_draw_scale := over_sample * entry.size_scale
|
||||
glyph_draw_translate := - Vec2{ f32(bounds_0.x), f32(bounds_0.y)} * glyph_draw_scale + Vec2{ f32(ctx.atlas.glyph_padding), f32(ctx.atlas.glyph_padding) }
|
||||
screenspace_x_form( & glyph_draw_translate, & glyph_draw_scale, f32(ctx.atlas.buffer_width), f32(ctx.atlas.buffer_height) )
|
||||
@ -610,12 +659,46 @@ directly_draw_massive_glyph :: proc( ctx : ^Context, entry : ^Entry, glyph : Gly
|
||||
cache_glyph( ctx, entry.id, glyph, glyph_draw_scale, glyph_draw_translate )
|
||||
|
||||
// Figure out the source rect.
|
||||
glyph_position := Vec2 {}
|
||||
glyph_width := f32(bounds_width) * entry.size_scale * over_sample.x
|
||||
glyph_height := f32(bounds_height) * entry.size_scale * over_sample.y
|
||||
glyph_dst_width := f32(bounds_width) * entry.size_scale
|
||||
glyph_dst_height := f32(bounds_height) * entry.size_scale
|
||||
glyph_width += f32(2 * ctx.atlas.glyph_padding)
|
||||
glyph_height += f32(2 * ctx.atlas.glyph_padding)
|
||||
|
||||
// Figure out the destination rect.
|
||||
bounds_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),
|
||||
}
|
||||
dst := position + scale * bounds_scaled
|
||||
dst_width := scale.x * glyph_dst_width
|
||||
dst_height := scale.y * glyph_dst_height
|
||||
dst.x -= scale.x * f32(ctx.atlas.glyph_padding)
|
||||
dst.y -= scale.y * f32(ctx.atlas.glyph_padding)
|
||||
|
||||
glyph_size := Vec2 { glyph_width, glyph_height }
|
||||
textspace_x_form( & glyph_position, & glyph_size, f32(ctx.atlas.buffer_width), f32(ctx.atlas.buffer_height) )
|
||||
|
||||
// Add the glyph drawcall.
|
||||
call : DrawCall
|
||||
{
|
||||
using call
|
||||
pass = .Target_Unchanged
|
||||
colour = ctx.colour
|
||||
start_index = u32(ctx.draw_list.indices.num)
|
||||
blit_quad( & ctx.draw_list, dst, dst + { dst_width, dst_height }, glyph_position, glyph_position + glyph_size )
|
||||
end_index = u32(ctx.draw_list.indices.num)
|
||||
append( & ctx.draw_list.calls, call )
|
||||
}
|
||||
|
||||
// Clear glyph_update_FBO.
|
||||
call.pass = .Glyph
|
||||
call.start_index = 0
|
||||
call.end_index = 0
|
||||
call.clear_before_draw = true
|
||||
append( & ctx.draw_list.calls, call )
|
||||
}
|
||||
|
||||
is_empty :: proc( ctx : ^Context, entry : ^Entry, glyph_index : Glyph ) -> b32
|
||||
@ -689,13 +772,52 @@ shape_text_uncached :: proc( ctx : ^Context, font : FontID, output : ^ShapedText
|
||||
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)
|
||||
|
||||
// We use our own fallback dumbass text shaping.
|
||||
// WARNING: PLEASE USE HARFBUZZ. GOOD TEXT SHAPING IS IMPORTANT FOR INTERNATIONALISATION.
|
||||
// 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -71,9 +71,9 @@ atlas_bbox :: proc( atlas : ^Atlas, region : AtlasRegionKind, local_idx : u32 )
|
||||
position.x += f32(atlas.region_d.offset.x)
|
||||
position.y += f32(atlas.region_d.offset.y)
|
||||
|
||||
case .Ignore: fallthrough
|
||||
case .None: fallthrough
|
||||
case .E:
|
||||
assert(false, "What?")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -106,6 +106,75 @@ parser_unload_font :: proc( font : ^ParserFontInfo )
|
||||
}
|
||||
}
|
||||
|
||||
parser_find_glyph_index :: proc( font : ^ParserFontInfo, codepoint : rune ) -> (glyph_index : Glyph)
|
||||
{
|
||||
switch font.kind
|
||||
{
|
||||
case .Freetype:
|
||||
glyph_index = transmute(Glyph) freetype.get_char_index( font.freetype_info, transmute(u32) codepoint )
|
||||
|
||||
case .STB_TrueType:
|
||||
glyph_index = transmute(Glyph) stbtt.FindGlyphIndex( & font.stbtt_info, codepoint )
|
||||
}
|
||||
return Glyph(-1)
|
||||
}
|
||||
|
||||
parser_free_shape :: proc( font : ^ParserFontInfo, shape : ParserGlyphShape )
|
||||
{
|
||||
switch font.kind
|
||||
{
|
||||
case .Freetype:
|
||||
delete( array_underlying_slice(shape) )
|
||||
|
||||
case .STB_TrueType:
|
||||
stbtt.FreeShape( & font.stbtt_info, transmute( [^]stbtt.vertex) raw_data(shape) )
|
||||
}
|
||||
}
|
||||
|
||||
parser_get_codepoint_horizontal_metrics :: proc( font : ^ParserFontInfo, codepoint : rune ) -> ( advance, to_left_side_glyph : i32 )
|
||||
{
|
||||
switch font.kind
|
||||
{
|
||||
case .Freetype:
|
||||
glyph_index := transmute(Glyph) freetype.get_char_index( font.freetype_info, transmute(u32) 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
|
||||
}
|
||||
|
||||
parser_get_codepoint_kern_advance :: proc( font : ^ParserFontInfo, prev_codepoint, codepoint : rune ) -> i32
|
||||
{
|
||||
switch font.kind
|
||||
{
|
||||
case .Freetype:
|
||||
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 )
|
||||
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 :: proc( font : ^ParserFontInfo ) -> (ascent, descent, line_gap : i32 )
|
||||
{
|
||||
switch font.kind
|
||||
@ -118,115 +187,27 @@ parser_get_font_vertical_metrics :: proc( font : ^ParserFontInfo ) -> (ascent, d
|
||||
return
|
||||
}
|
||||
|
||||
parser_scale_for_pixel_height :: #force_inline proc( font : ^ParserFontInfo, size : f32 ) -> f32
|
||||
{
|
||||
switch font.kind {
|
||||
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 :: proc( font : ^ParserFontInfo, size : f32 ) -> f32
|
||||
{
|
||||
switch font.kind {
|
||||
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 := size / cast(f32) font.freetype_info.units_per_em;
|
||||
return size_scale
|
||||
|
||||
case .STB_TrueType:
|
||||
return stbtt.ScaleForMappingEmToPixels( & font.stbtt_info, size )
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
parser_is_glyph_empty :: proc( font : ^ParserFontInfo, glyph_index : Glyph ) -> b32
|
||||
parser_get_glyph_box :: proc( font : ^ParserFontInfo, glyph_index : Glyph ) -> (bounds_0, bounds_1 : Vec2i)
|
||||
{
|
||||
switch font.kind
|
||||
{
|
||||
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
|
||||
freetype.load_glyph( font.freetype_info, c.uint(glyph_index), { .No_Bitmap, .No_Hinting, .No_Scale } )
|
||||
|
||||
metrics := font.freetype_info.glyph.metrics
|
||||
|
||||
bounds_0 = {u32(metrics.hori_bearing_x), u32(metrics.hori_bearing_y - metrics.height)}
|
||||
bounds_1 = {u32(metrics.hori_bearing_x + metrics.width), u32(metrics.hori_bearing_y)}
|
||||
|
||||
case .STB_TrueType:
|
||||
return stbtt.IsGlyphEmpty( & font.stbtt_info, cast(c.int) glyph_index )
|
||||
x0, y0, x1, y1 : i32
|
||||
success := cast(bool) stbtt.GetGlyphBox( & font.stbtt_info, i32(glyph_index), & x0, & y0, & x1, & y1 )
|
||||
assert( success )
|
||||
|
||||
bounds_0 = { u32(x0), u32(y0) }
|
||||
bounds_1 = { u32(x1), u32(y1) }
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
when false {
|
||||
parser_convert_conic_to_cubic_freetype :: proc( vertices : Array(ParserGlyphVertex), p0, p1, p2 : freetype.Vector, tolerance : f32 )
|
||||
{
|
||||
scratch : [Kilobyte * 4]u8
|
||||
scratch_arena : Arena; arena_init(& scratch_arena, scratch[:])
|
||||
|
||||
points, error := make( Array(freetype.Vector), 256, allocator = arena_allocator( &scratch_arena) )
|
||||
assert(error != .None)
|
||||
|
||||
append( & points, p0)
|
||||
append( & points, p1)
|
||||
append( & points, p2)
|
||||
|
||||
to_float : f32 = 1.0 / 64.0
|
||||
control_conv :: f32(2.0 / 3.0) // Conic to cubic control point distance
|
||||
|
||||
for ; points.num > 1; {
|
||||
p0 := points.data[0]
|
||||
p1 := points.data[1]
|
||||
p2 := points.data[2]
|
||||
|
||||
fp0 := Vec2{ f32(p0.x), f32(p0.y) } * to_float
|
||||
fp1 := Vec2{ f32(p1.x), f32(p1.y) } * to_float
|
||||
fp2 := Vec2{ f32(p2.x), f32(p2.y) } * to_float
|
||||
|
||||
delta_x := fp0.x - 2 * fp1.x + fp2.x;
|
||||
delta_y := fp0.y - 2 * fp1.y + fp2.y;
|
||||
distance := math.sqrt(delta_x * delta_x + delta_y * delta_y);
|
||||
|
||||
if distance <= tolerance
|
||||
{
|
||||
control1 := {
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
control2 := {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
parser_get_glyph_shape :: proc( font : ^ParserFontInfo, glyph_index : Glyph ) -> (shape : ParserGlyphShape, error : AllocatorError)
|
||||
@ -380,37 +361,113 @@ parser_get_glyph_shape :: proc( font : ^ParserFontInfo, glyph_index : Glyph ) ->
|
||||
return
|
||||
}
|
||||
|
||||
parser_free_shape :: proc( font : ^ParserFontInfo, shape : ParserGlyphShape )
|
||||
parser_is_glyph_empty :: proc( font : ^ParserFontInfo, glyph_index : Glyph ) -> b32
|
||||
{
|
||||
switch font.kind
|
||||
{
|
||||
case .Freetype:
|
||||
delete( array_underlying_slice(shape) )
|
||||
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:
|
||||
stbtt.FreeShape( & font.stbtt_info, transmute( [^]stbtt.vertex) raw_data(shape) )
|
||||
return stbtt.IsGlyphEmpty( & font.stbtt_info, cast(c.int) glyph_index )
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
parser_get_glyph_box :: proc( font : ^ParserFontInfo, glyph_index : Glyph ) -> (bounds_0, bounds_1 : Vec2i)
|
||||
parser_scale_for_pixel_height :: #force_inline proc( font : ^ParserFontInfo, size : f32 ) -> f32
|
||||
{
|
||||
switch font.kind
|
||||
{
|
||||
switch font.kind {
|
||||
case .Freetype:
|
||||
freetype.load_glyph( font.freetype_info, c.uint(glyph_index), { .No_Bitmap, .No_Hinting, .No_Scale } )
|
||||
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
|
||||
|
||||
metrics := font.freetype_info.glyph.metrics
|
||||
case.STB_TrueType:
|
||||
return stbtt.ScaleForPixelHeight( & font.stbtt_info, size )
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
bounds_0 = {u32(metrics.hori_bearing_x), u32(metrics.hori_bearing_y - metrics.height)}
|
||||
bounds_1 = {u32(metrics.hori_bearing_x + metrics.width), u32(metrics.hori_bearing_y)}
|
||||
parser_scale_for_mapping_em_to_pixels :: proc( font : ^ParserFontInfo, size : f32 ) -> f32
|
||||
{
|
||||
switch font.kind {
|
||||
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 := size / cast(f32) font.freetype_info.units_per_em;
|
||||
return size_scale
|
||||
|
||||
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 = { u32(x0), u32(y0) }
|
||||
bounds_1 = { u32(x1), u32(y1) }
|
||||
return stbtt.ScaleForMappingEmToPixels( & font.stbtt_info, size )
|
||||
}
|
||||
return
|
||||
return 0
|
||||
}
|
||||
|
||||
when false {
|
||||
parser_convert_conic_to_cubic_freetype :: proc( vertices : Array(ParserGlyphVertex), p0, p1, p2 : freetype.Vector, tolerance : f32 )
|
||||
{
|
||||
scratch : [Kilobyte * 4]u8
|
||||
scratch_arena : Arena; arena_init(& scratch_arena, scratch[:])
|
||||
|
||||
points, error := make( Array(freetype.Vector), 256, allocator = arena_allocator( &scratch_arena) )
|
||||
assert(error != .None)
|
||||
|
||||
append( & points, p0)
|
||||
append( & points, p1)
|
||||
append( & points, p2)
|
||||
|
||||
to_float : f32 = 1.0 / 64.0
|
||||
control_conv :: f32(2.0 / 3.0) // Conic to cubic control point distance
|
||||
|
||||
for ; points.num > 1; {
|
||||
p0 := points.data[0]
|
||||
p1 := points.data[1]
|
||||
p2 := points.data[2]
|
||||
|
||||
fp0 := Vec2{ f32(p0.x), f32(p0.y) } * to_float
|
||||
fp1 := Vec2{ f32(p1.x), f32(p1.y) } * to_float
|
||||
fp2 := Vec2{ f32(p2.x), f32(p2.y) } * to_float
|
||||
|
||||
delta_x := fp0.x - 2 * fp1.x + fp2.x;
|
||||
delta_y := fp0.y - 2 * fp1.y + fp2.y;
|
||||
distance := math.sqrt(delta_x * delta_x + delta_y * delta_y);
|
||||
|
||||
if distance <= tolerance
|
||||
{
|
||||
control1 := {
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
control2 := {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user