Progress on getting some horrible looking glyphs on the screen

This commit is contained in:
2024-07-01 20:52:59 -04:00
parent 70b2d1fe55
commit 9db6e67155

View File

@@ -12,6 +12,7 @@ STB_Truetype has macros for its allocation unfortuantely
import "base:runtime" import "base:runtime"
import "core:c" import "core:c"
import "core:math" import "core:math"
import "core:slice"
import stbtt "vendor:stb/truetype" import stbtt "vendor:stb/truetype"
import freetype "thirdparty:freetype" import freetype "thirdparty:freetype"
@@ -198,15 +199,6 @@ parser_get_font_vertical_metrics :: #force_inline proc "contextless" ( font : ^P
descent = i32(info.descender) descent = i32(info.descender)
line_gap = i32(info.height) - (ascent - descent) line_gap = i32(info.height) - (ascent - descent)
// FreeType stores these values in font units, so we need to convert them to pixels
units_per_em := i32(info.units_per_em)
if units_per_em != 0 {
ascent = (ascent * i32(info.size.metrics.y_ppem)) / units_per_em
descent = (descent * i32(info.size.metrics.y_ppem)) / units_per_em
line_gap = (line_gap * i32(info.size.metrics.y_ppem)) / units_per_em
}
case .STB_TrueType: case .STB_TrueType:
stbtt.GetFontVMetrics( & font.stbtt_info, & ascent, & descent, & line_gap ) stbtt.GetFontVMetrics( & font.stbtt_info, & ascent, & descent, & line_gap )
} }
@@ -241,138 +233,90 @@ parser_get_glyph_shape :: proc( font : ^ParserFontInfo, glyph_index : Glyph ) ->
switch font.kind switch font.kind
{ {
case .Freetype: case .Freetype:
error := freetype.load_glyph( font.freetype_info, cast(u32) glyph_index, { .No_Bitmap, .No_Hinting, .No_Scale } ) error := freetype.load_glyph(font.freetype_info, cast(u32)glyph_index, {.No_Bitmap, .No_Hinting, .No_Scale})
if error != .Ok { if error != .Ok {
return return
} }
glyph := font.freetype_info.glyph glyph := font.freetype_info.glyph
if glyph.format != .Outline { if glyph.format != .Outline {
return return
} }
/* outline := &glyph.outline
convert freetype outline to stb_truetype shape n_points := int(outline.n_points)
n_contours := int(outline.n_contours)
freetype docs: https://freetype.org/freetype2/docs/glyphs/glyphs-6.html vertices, alloc_error := make([dynamic]ParserGlyphVertex, 0, n_points + n_contours)
if alloc_error != .None {
// Handle allocation error
return
}
stb_truetype shape info: points := slice.from_ptr(cast([^]freetype.Vector) outline.points, n_points)
The shape is a series of contours. Each one starts with tags := slice.from_ptr(cast([^]u8) outline.tags, n_points)
a STBTT_moveto, then consists of a series of mixed contours := slice.from_ptr(cast([^]i16) outline.contours, n_contours)
STBTT_lineto and STBTT_curveto segments. A lineto
draws a line from previous endpoint to its x,y; a curveto start := 0
draws a quadratic bezier from previous endpoint to for contour_index in 0 ..< n_contours
its x,y, using cx,cy as the bezier control point.
*/
{ {
FT_CURVE_TAG_CONIC :: 0x00 end := int(contours[contour_index]) + 1
FT_CURVE_TAG_ON :: 0x01
FT_CURVE_TAG_CUBIC :: 0x02
vertices, error := make( [dynamic]ParserGlyphVertex, 1024 ) first_point := points[start]
assert( error == .None ) append( & vertices, ParserGlyphVertex { type = .Move, x = i16(first_point.x), y = i16(first_point.y) })
// TODO(Ed): This makes freetype second class I guess but VEFontCache doesn't have native support for freetype originally so.... for point_index := start; point_index < end; point_index += 1
outline := & glyph.outline
contours := transmute( [^]u16) outline.contours
points := transmute( [^]freetype.Vector) outline.points
tags := transmute( [^]u8) outline.tags
// TODO(Ed): Review this, never tested before and its problably bad.
for contour : i32 = 0; contour < i32(outline.n_contours); contour += 1
{ {
start := (contour == 0) ? 0 : i32(contours[ contour - 1 ] + 1) tag := tags[point_index]
end := i32(contours[ contour ]) point := points[point_index]
next_point := points[(point_index + 1) % end]
for index := start; index < i32(outline.n_points); index += 1 if tag & 1 == 0
{
point := points[ index ]
tag := tags[ index ]
if (tag & FT_CURVE_TAG_ON) != 0
{ {
if len(vertices) > 0 && !(vertices[len(vertices) - 1].type == .Move ) // Off-curve point
{ if tags[(point_index + 1) % end] & 1 == 0
// Close the previous contour if needed {
append(& vertices, ParserGlyphVertex { type = .Line, // Next is also off-curve
x = i16(points[start].x), y = i16(points[start].y), mid_point := Vec2{
contour_x0 = i16(0), contour_y0 = i16(0), (f32(point.x) + f32(next_point.x)) / 2,
contour_x1 = i16(0), contour_y1 = i16(0), (f32(point.y) + f32(next_point.y)) / 2,
padding = 0, }
}) append(&vertices, ParserGlyphVertex {
} type = .Curve,
x = i16(mid_point.x),
append(& vertices, ParserGlyphVertex { type = .Move, y = i16(mid_point.y),
x = i16(point.x), y = i16(point.y), contour_x0 = i16(point.x),
contour_x0 = i16(0), contour_y0 = i16(0), contour_y0 = i16(point.y),
contour_x1 = i16(0), contour_y1 = i16(0), })
padding = 0, }
}) else
} {
else if (tag & FT_CURVE_TAG_CUBIC) != 0 // Next is on-curve
{ append(&vertices, ParserGlyphVertex{
point1 := points[ index + 1 ] type = .Curve,
point2 := points[ index + 2 ] x = i16(next_point.x),
append(& vertices, ParserGlyphVertex { type = .Cubic, y = i16(next_point.y),
x = i16(point2.x), y = i16(point2.y), contour_x0 = i16(point.x),
contour_x0 = i16(point.x), contour_y0 = i16(point.y), contour_y0 = i16(point.y),
contour_x1 = i16(point1.x), contour_y1 = i16(point1.y), })
padding = 0, point_index += 1
}) }
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 = i16(point1.x), y = i16(point1.y),
contour_x0 = i16(control1.x), contour_y0 = i16(control1.y),
contour_x1 = i16(control2.x), contour_y1 = i16(control2.y),
padding = 0,
})
index += 1
} }
else else
{ {
append(& vertices, ParserGlyphVertex { type = .Line, // On-curve point
append(&vertices, ParserGlyphVertex{
type = .Line,
x = i16(point.x), y = i16(point.y), x = i16(point.x), y = i16(point.y),
contour_x0 = i16(0), contour_y0 = i16(0),
contour_x1 = i16(0), contour_y1 = i16(0),
padding = 0,
}) })
} }
}
// Close contour
append(& vertices, ParserGlyphVertex { type = .Line,
x = i16(points[start].x), y = i16(points[start].y),
contour_x0 = i16(0), contour_y0 = i16(0),
contour_x1 = i16(0), contour_y1 = i16(0),
padding = 0,
})
} }
shape = vertices start = end
} }
shape = vertices
case .STB_TrueType: case .STB_TrueType:
stb_shape : [^]stbtt.vertex stb_shape : [^]stbtt.vertex
nverts := stbtt.GetGlyphShape( & font.stbtt_info, cast(i32) glyph_index, & stb_shape ) nverts := stbtt.GetGlyphShape( & font.stbtt_info, cast(i32) glyph_index, & stb_shape )