VEFC: Added bad edge case to handle parsing conic curves, progess on cache_glyph

This commit is contained in:
Edward R. Gonzalez 2024-06-03 21:08:12 -04:00
parent c182ab7173
commit 38ebed8874
4 changed files with 118 additions and 14 deletions

View File

@ -530,7 +530,8 @@ cache_glyph :: proc( ctx : ^Context, font : FontID, glyph_index : Glyph, scale,
if ctx.debug_print_verbose
{
log( "shape: \n")
// for
}
/*
@ -538,8 +539,26 @@ cache_glyph :: proc( ctx : ^Context, font : FontID, glyph_index : Glyph, scale,
We need a random point that is outside our shape. We simply pick something diagonally across from top-left bound corner.
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.
*/
bounds_0, bounds_1 : Vec2i
// success := parser_get_glyph_box()
bounds_0, bounds_1 := parser_get_glyph_box( entry.parser_info, glyph_index )
outside := Vec2 {
f32(bounds_0.x - 21),
f32(bounds_0.y - 33),
}
// Note(Original Author): Figure out scaling so it fits within our box.
draw : DrawCall
draw.pass = FrameBufferPass.Glyph
draw.start_index = u32(ctx.draw_list.indices.num)
// Note(Original Author);
// Draw the path using simplified version of https://medium.com/@evanwallace/easy-scalable-text-rendering-on-the-gpu-c3f4d782c5ac.
// Instead of involving fragment shader code we simply make use of modern GPU ability to crunch triangles and brute force curve definitions.
path := ctx.temp_path
clear(path)
for vertex in shape {
}
return false
}

View File

@ -1,6 +1,7 @@
package VEFontCache
FrameBufferPass :: enum {
FrameBufferPass :: enum u32 {
None = 0,
Glyph = 1,
Atlas = 2,
Target = 3,
@ -8,7 +9,7 @@ FrameBufferPass :: enum {
}
DrawCall :: struct {
pass : u32,
pass : FrameBufferPass,
start_index : u32,
end_index : u32,
clear_before_draw : b32,
@ -17,7 +18,7 @@ DrawCall :: struct {
}
DrawCall_Default :: DrawCall {
pass = 0,
pass = .None,
start_index = 0,
end_index = 0,
clear_before_draw = false,

View File

@ -7,6 +7,11 @@ import "core:mem"
Kilobyte :: mem.Kilobyte
Arena :: mem.Arena
arena_allocator :: mem.arena_allocator
arena_init :: mem.arena_init
Allocator :: mem.Allocator
AllocatorError :: mem.Allocator_Error

View File

@ -8,6 +8,7 @@ That interface is not exposed from this parser but could be added to parser_init
*/
import "core:c"
import "core:math"
import stbtt "vendor:stb/truetype"
import freetype "thirdparty:freetype"
@ -169,11 +170,50 @@ parser_is_glyph_empty :: proc( font : ^ParserFontInfo, glyph_index : Glyph ) ->
return false
}
// TODO(Ed): This makes freetype second class I guess but VEFontCache doesn't have native support for freetype originally so....
// parser_convert_freetype_outline_to_stb_truetype_shape :: proc( outline : freetype.Outline ) -> (shape : ParserGlyphShape, error : AllocatorError)
// {
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 := {
}
}
}
}
}
parser_get_glyph_shape :: proc( font : ^ParserFontInfo, glyph_index : Glyph ) -> (shape : ParserGlyphShape, error : AllocatorError)
{
@ -261,6 +301,34 @@ parser_get_glyph_shape :: proc( font : ^ParserFontInfo, glyph_index : Glyph ) ->
})
index += 2
}
else if (tag & FT_CURVE_TAG_CONIC) != 0
{
// TODO(Ed): This is using a very dead simple algo to convert the conic to a cubic curve
// not sure if we need something more sophisticaated
point1 := points[ index + 1 ]
control_conv :: f32(0.5) // Conic to cubic control point distance
to_float := f32(1.0 / 64.0)
fp := Vec2 { f32(point.x), f32(point.y) } * to_float
fp1 := Vec2 { f32(point1.x), f32(point1.y) } * to_float
control1 := freetype.Vector {
point.x + freetype.Pos( (fp1.x - fp.x) * control_conv * 64.0 ),
point.y + freetype.Pos( (fp1.y - fp.y) * control_conv * 64.0 ),
}
control2 := freetype.Vector {
point1.x + freetype.Pos( (fp.x - fp1.x) * control_conv * 64.0 ),
point1.y + freetype.Pos( (fp.y - fp1.y) * control_conv * 64.0 ),
}
append(& vertices, ParserGlyphVertex { type = .Cubic,
x = u16(point1.x), y = u16(point1.y),
contour_x0 = u16(control1.x), contour_y0 = u16(control1.y),
contour_x1 = u16(control2.x), contour_y1 = u16(control2.y),
padding = 0,
})
index += 1
}
else
{
append(& vertices, ParserGlyphVertex { type = .Line,
@ -280,6 +348,8 @@ parser_get_glyph_shape :: proc( font : ^ParserFontInfo, glyph_index : Glyph ) ->
padding = 0,
})
}
shape = array_to_slice(vertices)
}
case .STB_TrueType:
@ -298,8 +368,17 @@ parser_get_glyph_shape :: proc( font : ^ParserFontInfo, glyph_index : Glyph ) ->
parser_free_shape :: proc( font : ^ParserFontInfo, shape : ParserGlyphShape )
{
// switch font.kind
// {
// case .Freetype
// }
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_glyph_box :: proc( font : ^ParserFontInfo, glyph_index : Glyph ) -> (bounds_0, bounds_1 : Vec2i)
{
return
}