making initial code2 codebase diretory
This commit is contained in:
196
code2/vefontcache/parser.odin
Normal file
196
code2/vefontcache/parser.odin
Normal file
@@ -0,0 +1,196 @@
|
||||
package vefontcache
|
||||
|
||||
/*
|
||||
Notes:
|
||||
This is a minimal wrapper I originally did incase a font parser other than stb_truetype is introduced in the future.
|
||||
Otherwise, its essentially 1:1 with it.
|
||||
|
||||
Freetype isn't really supported and its not a high priority.
|
||||
~~Freetype will do memory allocations and has an interface the user can implement.~~
|
||||
~~That interface is not exposed from this parser but could be added to parser_init.~~
|
||||
|
||||
STB_Truetype:
|
||||
* Added ability to set the stb_truetype allocator for STBTT_MALLOC and STBTT_FREE.
|
||||
* Changed procedure signatures to pass the font_info struct by immutable ptr (#by_ptr)
|
||||
when the C equivalent has their parameter as `const*`.
|
||||
*/
|
||||
|
||||
import "core:c"
|
||||
import stbtt "thirdparty:stb/truetype"
|
||||
// import freetype "thirdparty:freetype"
|
||||
|
||||
Parser_Kind :: enum u32 {
|
||||
STB_TrueType,
|
||||
Freetype, // Currently not implemented.
|
||||
}
|
||||
|
||||
Parser_Font_Info :: struct {
|
||||
label : string,
|
||||
kind : Parser_Kind,
|
||||
stbtt_info : stbtt.fontinfo,
|
||||
// freetype_info : freetype.Face
|
||||
data : []byte,
|
||||
}
|
||||
|
||||
Glyph_Vert_Type :: enum u8 {
|
||||
None,
|
||||
Move = 1,
|
||||
Line,
|
||||
Curve,
|
||||
Cubic,
|
||||
}
|
||||
|
||||
// Based directly off of stb_truetype's vertex
|
||||
Parser_Glyph_Vertex :: struct {
|
||||
x, y : i16,
|
||||
contour_x0, contour_y0 : i16,
|
||||
contour_x1, contour_y1 : i16,
|
||||
type : Glyph_Vert_Type,
|
||||
padding : u8,
|
||||
}
|
||||
// A shape can be a dynamic array free_type or an opaque set of data handled by stb_truetype
|
||||
Parser_Glyph_Shape :: [dynamic]Parser_Glyph_Vertex
|
||||
|
||||
Parser_Context :: struct {
|
||||
lib_backing : Allocator,
|
||||
kind : Parser_Kind,
|
||||
// ft_library : freetype.Library,
|
||||
}
|
||||
|
||||
parser_stbtt_allocator_proc :: proc(
|
||||
allocator_data : rawptr,
|
||||
type : stbtt.zpl_allocator_type,
|
||||
size : c.ssize_t,
|
||||
alignment : c.ssize_t,
|
||||
old_memory : rawptr,
|
||||
old_size : c.ssize_t,
|
||||
flags : c.ulonglong
|
||||
) -> rawptr
|
||||
{
|
||||
allocator := transmute(^Allocator) allocator_data
|
||||
result, error := allocator.procedure( allocator.data, cast(Allocator_Mode) type, cast(int) size, cast(int) alignment, old_memory, cast(int) old_size )
|
||||
assert(error == .None)
|
||||
|
||||
if type == .Alloc || type == .Resize {
|
||||
raw := transmute(Raw_Slice) result
|
||||
// assert(raw.len > 0, "Allocation is 0 bytes?")
|
||||
return transmute(rawptr) raw.data
|
||||
}
|
||||
else do return nil
|
||||
}
|
||||
|
||||
parser_init :: proc( ctx : ^Parser_Context, kind : Parser_Kind, allocator := context.allocator )
|
||||
{
|
||||
ctx.kind = kind
|
||||
ctx.lib_backing = allocator
|
||||
|
||||
stbtt_allocator := stbtt.zpl_allocator { parser_stbtt_allocator_proc, & ctx.lib_backing }
|
||||
stbtt.SetAllocator( stbtt_allocator )
|
||||
}
|
||||
|
||||
parser_reload :: proc( ctx : ^Parser_Context, allocator := context.allocator) {
|
||||
ctx.lib_backing = allocator
|
||||
stbtt_allocator := stbtt.zpl_allocator { parser_stbtt_allocator_proc, & ctx.lib_backing }
|
||||
stbtt.SetAllocator( stbtt_allocator )
|
||||
}
|
||||
|
||||
parser_shutdown :: proc( ctx : ^Parser_Context ) {
|
||||
// Note: Not necesssary for stb_truetype
|
||||
}
|
||||
|
||||
parser_load_font :: proc( ctx : ^Parser_Context, label : string, data : []byte ) -> (font : Parser_Font_Info, error : b32)
|
||||
{
|
||||
error = ! stbtt.InitFont( & font.stbtt_info, raw_data(data), 0 )
|
||||
|
||||
font.label = label
|
||||
font.data = data
|
||||
font.kind = ctx.kind
|
||||
return
|
||||
}
|
||||
|
||||
parser_unload_font :: proc( font : ^Parser_Font_Info )
|
||||
{
|
||||
// case .STB_TrueType:
|
||||
// Do Nothing
|
||||
}
|
||||
|
||||
parser_find_glyph_index :: #force_inline proc "contextless" ( font : Parser_Font_Info, codepoint : rune ) -> (glyph_index : Glyph)
|
||||
{
|
||||
glyph_index = transmute(Glyph) stbtt.FindGlyphIndex( font.stbtt_info, codepoint )
|
||||
return
|
||||
}
|
||||
|
||||
parser_free_shape :: #force_inline proc( font : Parser_Font_Info, shape : Parser_Glyph_Shape )
|
||||
{
|
||||
shape := shape
|
||||
shape_raw := transmute( ^Raw_Dynamic_Array) & shape
|
||||
stbtt.FreeShape( font.stbtt_info, transmute( [^]stbtt.vertex) shape_raw.data )
|
||||
}
|
||||
|
||||
parser_get_codepoint_horizontal_metrics :: #force_inline proc "contextless" ( font : Parser_Font_Info, codepoint : rune ) -> ( advance, to_left_side_glyph : i32 )
|
||||
{
|
||||
stbtt.GetCodepointHMetrics( font.stbtt_info, codepoint, & advance, & to_left_side_glyph )
|
||||
return
|
||||
}
|
||||
|
||||
parser_get_codepoint_kern_advance :: #force_inline proc "contextless" ( font : Parser_Font_Info, prev_codepoint, codepoint : rune ) -> i32
|
||||
{
|
||||
kern := stbtt.GetCodepointKernAdvance( font.stbtt_info, prev_codepoint, codepoint )
|
||||
return kern
|
||||
}
|
||||
|
||||
parser_get_font_vertical_metrics :: #force_inline proc "contextless" ( font : Parser_Font_Info ) -> (ascent, descent, line_gap : i32 )
|
||||
{
|
||||
stbtt.GetFontVMetrics( font.stbtt_info, & ascent, & descent, & line_gap )
|
||||
return
|
||||
}
|
||||
|
||||
parser_get_bounds :: #force_inline proc "contextless" ( font : Parser_Font_Info, glyph_index : Glyph ) -> (bounds : Range2)
|
||||
{
|
||||
// profile(#procedure)
|
||||
bounds_0, bounds_1 : Vec2i
|
||||
|
||||
x0, y0, x1, y1 : i32
|
||||
success := cast(bool) stbtt.GetGlyphBox( font.stbtt_info, i32(glyph_index), & x0, & y0, & x1, & y1 )
|
||||
|
||||
bounds_0 = { x0, y0 }
|
||||
bounds_1 = { x1, y1 }
|
||||
bounds = { vec2(bounds_0), vec2(bounds_1) }
|
||||
return
|
||||
}
|
||||
|
||||
parser_get_glyph_shape :: #force_inline proc ( font : Parser_Font_Info, glyph_index : Glyph ) -> (shape : Parser_Glyph_Shape, error : Allocator_Error)
|
||||
{
|
||||
stb_shape : [^]stbtt.vertex
|
||||
nverts := stbtt.GetGlyphShape( font.stbtt_info, cast(i32) glyph_index, & stb_shape )
|
||||
|
||||
shape_raw := transmute( ^Raw_Dynamic_Array) & shape
|
||||
shape_raw.data = stb_shape
|
||||
shape_raw.len = int(nverts)
|
||||
shape_raw.cap = int(nverts)
|
||||
shape_raw.allocator = nil_allocator()
|
||||
error = Allocator_Error.None
|
||||
return
|
||||
}
|
||||
|
||||
parser_is_glyph_empty :: #force_inline proc "contextless" ( font : Parser_Font_Info, glyph_index : Glyph ) -> b32
|
||||
{
|
||||
return stbtt.IsGlyphEmpty( font.stbtt_info, cast(c.int) glyph_index )
|
||||
}
|
||||
|
||||
parser_scale :: #force_inline proc "contextless" ( font : Parser_Font_Info, size : f32 ) -> f32
|
||||
{
|
||||
// profile(#procedure)
|
||||
size_scale := size > 0.0 ? parser_scale_for_mapping_em_to_pixels( font, size ) : parser_scale_for_pixel_height( font, -size )
|
||||
return size_scale
|
||||
}
|
||||
|
||||
parser_scale_for_pixel_height :: #force_inline proc "contextless" ( font : Parser_Font_Info, size : f32 ) -> f32
|
||||
{
|
||||
return stbtt.ScaleForPixelHeight( font.stbtt_info, size )
|
||||
}
|
||||
|
||||
parser_scale_for_mapping_em_to_pixels :: #force_inline proc "contextless" ( font : Parser_Font_Info, size : f32 ) -> f32
|
||||
{
|
||||
return stbtt.ScaleForMappingEmToPixels( font.stbtt_info, size )
|
||||
}
|
Reference in New Issue
Block a user