VEFC: ported decide_codepoint_region
This commit is contained in:
parent
38ebed8874
commit
26e53bf327
@ -11,6 +11,7 @@ Changes:
|
||||
- Font Parser & Glyph Shaper are abstracted to their own interface
|
||||
- Font Face parser info stored separately from entries
|
||||
- ve_fontcache_loadfile not ported (just use odin's core:os or os2), then call load_font
|
||||
- Macro defines have been made into runtime parameters
|
||||
*/
|
||||
package VEFontCache
|
||||
|
||||
@ -21,12 +22,13 @@ Colour :: [4]f32
|
||||
Vec2 :: [2]f32
|
||||
Vec2i :: [2]u32
|
||||
|
||||
AtlasRegionKind :: enum {
|
||||
A = 0,
|
||||
B = 1,
|
||||
C = 2,
|
||||
D = 3,
|
||||
E = 4,
|
||||
AtlasRegionKind :: enum u8 {
|
||||
None = 0x00,
|
||||
A = 0x41,
|
||||
B = 0x42,
|
||||
C = 0x43,
|
||||
D = 0x44,
|
||||
E = 0x45,
|
||||
}
|
||||
|
||||
Vertex :: struct {
|
||||
@ -34,15 +36,6 @@ Vertex :: struct {
|
||||
u, v : f32,
|
||||
}
|
||||
|
||||
// GlyphDrawBuffer :: struct {
|
||||
// over_sample : Vec2,
|
||||
|
||||
// batch : i32,
|
||||
// width : i32,
|
||||
// height : i32,
|
||||
// padding : i32,
|
||||
// }
|
||||
|
||||
ShapedText :: struct {
|
||||
glyphs : Array(Glyph),
|
||||
positions : Array(Vec2),
|
||||
@ -97,6 +90,7 @@ Context :: struct {
|
||||
atlas : Atlas,
|
||||
shape_cache : ShapedTextCache,
|
||||
|
||||
curve_quality : u32,
|
||||
text_shape_adv : b32,
|
||||
|
||||
debug_print_verbose : b32
|
||||
@ -150,15 +144,15 @@ InitAtlasParams_Default :: InitAtlasParams {
|
||||
}
|
||||
|
||||
InitGlyphDrawParams :: struct {
|
||||
over_sample : Vec2i,
|
||||
buffer_batch : u32,
|
||||
padding : u32,
|
||||
over_sample : Vec2,
|
||||
buffer_batch : u32,
|
||||
draw_padding : u32,
|
||||
}
|
||||
|
||||
InitGlyphDrawParams_Default :: InitGlyphDrawParams {
|
||||
over_sample = { 4, 4 },
|
||||
buffer_batch = 4,
|
||||
padding = InitAtlasParams_Default.glyph_padding,
|
||||
over_sample = { 4, 4 },
|
||||
buffer_batch = 4,
|
||||
draw_padding = InitAtlasParams_Default.glyph_padding,
|
||||
}
|
||||
|
||||
InitShapeCacheParams :: struct {
|
||||
@ -177,6 +171,7 @@ init :: proc( ctx : ^Context,
|
||||
atlas_params := InitAtlasParams_Default,
|
||||
glyph_draw_params := InitGlyphDrawParams_Default,
|
||||
shape_cache_params := InitShapeCacheParams_Default,
|
||||
curve_quality : u32 = 6,
|
||||
advance_snap_smallfont_size : u32 = 12,
|
||||
entires_reserve : u32 = Kilobyte,
|
||||
temp_path_reserve : u32 = Kilobyte,
|
||||
@ -189,6 +184,8 @@ init :: proc( ctx : ^Context,
|
||||
ctx.backing = allocator
|
||||
context.allocator = ctx.backing
|
||||
|
||||
ctx.curve_quality = curve_quality
|
||||
|
||||
error : AllocatorError
|
||||
entries, error = make( Array(Entry), u64(entires_reserve) )
|
||||
assert(error == .None, "VEFontCache.init : Failed to allocate entries")
|
||||
@ -233,6 +230,10 @@ init :: proc( ctx : ^Context,
|
||||
init_atlas_region( & atlas.region_c, atlas_params, atlas_params.region_c )
|
||||
init_atlas_region( & atlas.region_d, atlas_params, atlas_params.region_d )
|
||||
|
||||
atlas.width = atlas_params.width
|
||||
atlas.height = atlas_params.height
|
||||
atlas.glyph_padding = atlas_params.glyph_padding
|
||||
|
||||
atlas.region_b.offset.y = atlas.region_a.size.y
|
||||
atlas.region_c.offset.x = atlas.region_a.size.x
|
||||
atlas.region_d.offset.x = atlas.width / 2
|
||||
@ -251,6 +252,12 @@ init :: proc( ctx : ^Context,
|
||||
// Note(From original author): We can actually go over VE_FONTCACHE_GLYPHDRAW_BUFFER_BATCH batches due to smart packing!
|
||||
{
|
||||
using atlas
|
||||
over_sample = glyph_draw_params.over_sample
|
||||
buffer_batch = glyph_draw_params.buffer_batch
|
||||
buffer_width = region_d.width * u32(over_sample.x) * buffer_batch
|
||||
buffer_height = region_d.height * u32(over_sample.y)
|
||||
draw_padding = glyph_draw_params.draw_padding
|
||||
|
||||
draw_list.calls, error = make( Array(DrawCall), cast(u64) glyph_draw_params.buffer_batch * 2 )
|
||||
assert( error != .None, "VEFontCache.init : Failed to allocate calls for draw_list" )
|
||||
|
||||
@ -348,53 +355,6 @@ configure_snap :: proc( ctx : ^Context, snap_width, snap_height : u32 ) {
|
||||
ctx.snap_height = snap_height
|
||||
}
|
||||
|
||||
// ve_fontcache_drawlist
|
||||
get_draw_list :: proc( ctx : ^Context ) -> ^DrawList {
|
||||
assert( ctx != nil )
|
||||
return & ctx.draw_list
|
||||
}
|
||||
|
||||
// ve_fontcache_clear_drawlist
|
||||
clear_draw_list :: proc( draw_list : ^DrawList ) {
|
||||
clear( draw_list.calls )
|
||||
clear( draw_list.indices )
|
||||
clear( draw_list.vertices )
|
||||
}
|
||||
|
||||
// ve_fontcache_merge_drawlist
|
||||
merge_draw_list :: proc( dst, src : ^DrawList )
|
||||
{
|
||||
error : AllocatorError
|
||||
|
||||
v_offset := cast(u32) dst.vertices.num
|
||||
// for index : u32 = 0; index < cast(u32) src.vertices.num; index += 1 {
|
||||
// error = append( & dst.vertices, src.vertices.data[index] )
|
||||
// assert( error == .None )
|
||||
// }
|
||||
error = append( & dst.vertices, src.vertices )
|
||||
assert( error == .None )
|
||||
|
||||
i_offset := cast(u32) dst.indices.num
|
||||
for index : u32 = 0; index < cast(u32) src.indices.num; index += 1 {
|
||||
error = append( & dst.indices, src.indices.data[index] + v_offset )
|
||||
assert( error == .None )
|
||||
}
|
||||
|
||||
for index : u32 = 0; index < cast(u32) src.calls.num; index += 1 {
|
||||
src_call := src.calls.data[ index ]
|
||||
src_call.start_index += i_offset
|
||||
src_call.end_index += i_offset
|
||||
append( & dst.calls, src_call )
|
||||
assert( error == .None )
|
||||
}
|
||||
}
|
||||
|
||||
// ve_fontcache_flush_drawlist
|
||||
flush_draw_list :: proc( ctx : ^Context ) {
|
||||
assert( ctx != nil )
|
||||
clear_draw_list( & ctx.draw_list )
|
||||
}
|
||||
|
||||
// For a provided alpha value,
|
||||
// allows the function to calculate the position of a point along the curve at any given fraction of its total length
|
||||
// ve_fontcache_eval_bezier (quadratic)
|
||||
@ -422,92 +382,6 @@ eval_point_on_bezier4 :: proc( p0, p1, p2, p3 : Vec2, alpha : f32 ) -> Vec2
|
||||
return point
|
||||
}
|
||||
|
||||
// Constructs a triangle fan to fill a shape using the provided path
|
||||
// outside_point represents the center point of the fan.
|
||||
//
|
||||
// Note(Original Author):
|
||||
// WARNING: doesn't actually append drawcall; caller is responsible for actually appending the drawcall.
|
||||
// ve_fontcache_draw_filled_path
|
||||
draw_filled_path :: proc( draw_list : ^DrawList, outside_point : Vec2, path : []Vec2,
|
||||
scale := Vec2 { 1, 1 },
|
||||
translate := Vec2 { 0, 0 },
|
||||
debug_print_verbose : b32 = false
|
||||
)
|
||||
{
|
||||
if debug_print_verbose
|
||||
{
|
||||
log("outline_path: \n")
|
||||
for point in path {
|
||||
logf(" %.2f %.2f\n", point.x * scale )
|
||||
}
|
||||
}
|
||||
|
||||
v_offset := cast(u32) draw_list.vertices.num
|
||||
for point in path {
|
||||
vertex := Vertex {
|
||||
pos = point * scale + translate,
|
||||
u = 0,
|
||||
v = 0,
|
||||
}
|
||||
append( & draw_list.vertices, vertex )
|
||||
}
|
||||
|
||||
outside_vertex := cast(u32) draw_list.vertices.num
|
||||
{
|
||||
vertex := Vertex {
|
||||
pos = outside_point * scale + translate,
|
||||
u = 0,
|
||||
v = 0,
|
||||
}
|
||||
append( & draw_list.vertices, vertex )
|
||||
}
|
||||
|
||||
for index : u32 = 1; index < u32(len(path)); index += 1 {
|
||||
indices := & draw_list.indices
|
||||
append( indices, outside_vertex )
|
||||
append( indices, v_offset + index - 1 )
|
||||
append( indices, v_offset + index )
|
||||
}
|
||||
}
|
||||
|
||||
blit_quad :: proc( draw_list : ^DrawList, p0, p1 : Vec2, uv0, uv1 : Vec2 )
|
||||
{
|
||||
v_offset := cast(u32) draw_list.vertices.num
|
||||
|
||||
vertex := Vertex {
|
||||
{p0.x, p0.y},
|
||||
uv0.x,
|
||||
uv0.y
|
||||
}
|
||||
append( & draw_list.vertices, vertex )
|
||||
vertex = Vertex {
|
||||
{p0.x, p1.y},
|
||||
uv0.x,
|
||||
uv1.y
|
||||
}
|
||||
append( & draw_list.vertices, vertex )
|
||||
vertex = Vertex {
|
||||
{p1.x, p0.y},
|
||||
uv1.x,
|
||||
uv0.y
|
||||
}
|
||||
append( & draw_list.vertices, vertex )
|
||||
vertex = Vertex {
|
||||
{p1.x, p1.y},
|
||||
uv1.x,
|
||||
uv1.y
|
||||
}
|
||||
append( & draw_list.vertices, vertex )
|
||||
|
||||
quad_indices : []u32 = {
|
||||
0, 1, 2,
|
||||
2, 1, 3
|
||||
}
|
||||
for index : i32 = 0; index < 6; index += 1 {
|
||||
append( & draw_list.indices, v_offset + quad_indices[ index ] )
|
||||
}
|
||||
}
|
||||
|
||||
cache_glyph :: proc( ctx : ^Context, font : FontID, glyph_index : Glyph, scale, translate : Vec2 ) -> b32
|
||||
{
|
||||
assert( ctx != nil )
|
||||
@ -531,7 +405,24 @@ cache_glyph :: proc( ctx : ^Context, font : FontID, glyph_index : Glyph, scale,
|
||||
if ctx.debug_print_verbose
|
||||
{
|
||||
log( "shape: \n")
|
||||
// for
|
||||
for vertex in shape
|
||||
{
|
||||
if vertex.type == .Move {
|
||||
logf("move_to %d %d\n", vertex.x, vertex.y )
|
||||
}
|
||||
else if vertex.type == .Line {
|
||||
logf("line_to %d %d\n", vertex.x, vertex.y )
|
||||
}
|
||||
else if vertex.type == .Curve {
|
||||
logf("curve_to %d %d through %d %d\n", vertex.x, vertex.y, vertex.contour_x0, vertex.contour_y0 )
|
||||
}
|
||||
else if vertex.type == .Cubic {
|
||||
logf("cubic_to %d %d through %d %d and %d %d\n",
|
||||
vertex.x, vertex.y,
|
||||
vertex.contour_x0, vertex.contour_y0,
|
||||
vertex.contour_x1, vertex.contour_y1 )
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -556,16 +447,130 @@ cache_glyph :: proc( ctx : ^Context, font : FontID, glyph_index : Glyph, scale,
|
||||
// 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 {
|
||||
|
||||
for edge in shape do switch edge.type
|
||||
{
|
||||
case .Move:
|
||||
if path.num > 0 {
|
||||
draw_filled_path( & ctx.draw_list, outside, array_to_slice(path), scale, translate )
|
||||
}
|
||||
clear(path)
|
||||
fallthrough
|
||||
|
||||
case .Line:
|
||||
append( & path, Vec2{ f32(edge.x), f32(edge.y) })
|
||||
|
||||
case .Curve:
|
||||
assert( path.num > 0 )
|
||||
p0 := path.data[ path.num - 1 ]
|
||||
p1 := Vec2{ f32(edge.contour_x0), f32(edge.contour_y0) }
|
||||
p2 := Vec2{ f32(edge.x), f32(edge.y) }
|
||||
|
||||
step := 1.0 / f32(ctx.curve_quality)
|
||||
alpha := step
|
||||
for index := i32(0); index < i32(ctx.curve_quality); index += 1 {
|
||||
append( & path, eval_point_on_bezier3( p0, p1, p2, alpha ))
|
||||
alpha += step
|
||||
}
|
||||
|
||||
case .Cubic:
|
||||
assert( path.num > 0 )
|
||||
p0 := path.data[ path.num - 1]
|
||||
p1 := Vec2{ f32(edge.contour_x0), f32(edge.contour_y0) }
|
||||
p2 := Vec2{ f32(edge.contour_x1), f32(edge.contour_y1) }
|
||||
p3 := Vec2{ f32(edge.x), f32(edge.y) }
|
||||
|
||||
step := 1.0 / f32(ctx.curve_quality)
|
||||
alpha := step
|
||||
for index := i32(0); index < i32(ctx.curve_quality); index += 1 {
|
||||
append( & path, eval_point_on_bezier4( p0, p1, p2, p3, alpha ))
|
||||
alpha += step
|
||||
}
|
||||
|
||||
case .None:
|
||||
assert(false, "Unknown edge type or invalid")
|
||||
}
|
||||
if path.num > 0 {
|
||||
draw_filled_path( & ctx.draw_list, outside, array_to_slice(path), scale, translate )
|
||||
}
|
||||
|
||||
// Note(Original Author): Apend the draw call
|
||||
draw.end_index = cast(u32) ctx.draw_list.indices.num
|
||||
if draw.end_index > draw.start_index {
|
||||
append(& ctx.draw_list.calls, draw)
|
||||
}
|
||||
|
||||
parser_free_shape( entry.parser_info, shape )
|
||||
return false
|
||||
}
|
||||
|
||||
decide_codepoint_region :: proc() -> AtlasRegionKind
|
||||
decide_codepoint_region :: proc( ctx : ^Context, entry : ^Entry, glyph_index : Glyph
|
||||
) -> (region : AtlasRegionKind, state : ^LRU_Cache, next_idx : ^u32, over_sample : ^Vec2)
|
||||
{
|
||||
return {}
|
||||
if parser_is_glyph_empty( entry.parser_info, glyph_index ) {
|
||||
region = .None
|
||||
}
|
||||
|
||||
bounds_0, bounds_1 := parser_get_glyph_box( entry.parser_info, glyph_index )
|
||||
bounds_width := bounds_1.x - bounds_0.x
|
||||
bounds_height := bounds_1.y - bounds_0.y
|
||||
|
||||
atlas := & ctx.atlas
|
||||
|
||||
bounds_width_scaled := cast(u32) (f32(bounds_width) * entry.size_scale + 2.0 * f32(atlas.glyph_padding))
|
||||
bounds_height_scaled := cast(u32) (f32(bounds_height) * entry.size_scale + 2.0 * f32(atlas.glyph_padding))
|
||||
|
||||
if bounds_width_scaled <= atlas.region_a.width && bounds_height_scaled <= atlas.region_a.height
|
||||
{
|
||||
// Region A for small glyphs. These are good for things such as punctuation.
|
||||
region = .A
|
||||
state = & atlas.region_a.state
|
||||
next_idx = & atlas.region_a.next_idx
|
||||
}
|
||||
else if bounds_width_scaled <= atlas.region_b.width && bounds_height_scaled <= atlas.region_b.height
|
||||
{
|
||||
// Region B for tall glyphs. These are good for things such as european alphabets.
|
||||
region = .B
|
||||
state = & atlas.region_b.state
|
||||
next_idx = & atlas.region_b.next_idx
|
||||
}
|
||||
else if bounds_width_scaled <= atlas.region_c.width && bounds_height_scaled <= atlas.region_c.height
|
||||
{
|
||||
// Region C for big glyphs. These are good for things such as asian typography.
|
||||
region = .C
|
||||
state = & atlas.region_c.state
|
||||
next_idx = & atlas.region_c.next_idx
|
||||
}
|
||||
else if bounds_width_scaled <= atlas.region_d.width && bounds_height_scaled <= atlas.region_d.height
|
||||
{
|
||||
// Region D for huge glyphs. These are good for things such as titles and 4k.
|
||||
region = .D
|
||||
state = & atlas.region_d.state
|
||||
next_idx = & atlas.region_d.next_idx
|
||||
}
|
||||
else if bounds_width_scaled <= atlas.buffer_width && bounds_height_scaled <= atlas.buffer_height
|
||||
{
|
||||
// Region 'E' for massive glyphs. These are rendered uncached and un-oversampled.
|
||||
region = .E
|
||||
state = nil
|
||||
next_idx = nil
|
||||
if bounds_width_scaled <= atlas.buffer_width / 2 && bounds_height_scaled <= atlas.buffer_height / 2
|
||||
{
|
||||
(over_sample^) = { 2.0, 2.0 }
|
||||
}
|
||||
else
|
||||
{
|
||||
(over_sample^) = { 1.0, 1.0 }
|
||||
}
|
||||
return
|
||||
}
|
||||
else {
|
||||
region = .None
|
||||
return
|
||||
}
|
||||
|
||||
assert(state != nil)
|
||||
assert(next_idx != nil)
|
||||
return
|
||||
}
|
||||
|
||||
flush_glyph_buffer_to_atlas :: proc()
|
||||
|
@ -1,6 +1,12 @@
|
||||
package VEFontCache
|
||||
|
||||
GlyphUpdateBatch :: struct {
|
||||
GlyphDrawBuffer :: struct {
|
||||
over_sample : Vec2,
|
||||
buffer_batch : u32,
|
||||
buffer_width : u32,
|
||||
buffer_height : u32,
|
||||
draw_padding : u32,
|
||||
|
||||
update_batch_x : i32,
|
||||
clear_draw_list : DrawList,
|
||||
draw_list : DrawList,
|
||||
@ -23,12 +29,12 @@ Atlas :: struct {
|
||||
width : u32,
|
||||
height : u32,
|
||||
|
||||
glyph_pad : u16,
|
||||
glyph_padding : u32,
|
||||
|
||||
region_a : AtlasRegion,
|
||||
region_b : AtlasRegion,
|
||||
region_c : AtlasRegion,
|
||||
region_d : AtlasRegion,
|
||||
|
||||
using glyph_update_batch : GlyphUpdateBatch,
|
||||
using glyph_update_batch : GlyphDrawBuffer,
|
||||
}
|
||||
|
@ -31,3 +31,136 @@ DrawList :: struct {
|
||||
indices : Array(u32),
|
||||
calls : Array(DrawCall),
|
||||
}
|
||||
|
||||
blit_quad :: proc( draw_list : ^DrawList, p0, p1 : Vec2, uv0, uv1 : Vec2 )
|
||||
{
|
||||
v_offset := cast(u32) draw_list.vertices.num
|
||||
|
||||
vertex := Vertex {
|
||||
{p0.x, p0.y},
|
||||
uv0.x,
|
||||
uv0.y
|
||||
}
|
||||
append( & draw_list.vertices, vertex )
|
||||
vertex = Vertex {
|
||||
{p0.x, p1.y},
|
||||
uv0.x,
|
||||
uv1.y
|
||||
}
|
||||
append( & draw_list.vertices, vertex )
|
||||
vertex = Vertex {
|
||||
{p1.x, p0.y},
|
||||
uv1.x,
|
||||
uv0.y
|
||||
}
|
||||
append( & draw_list.vertices, vertex )
|
||||
vertex = Vertex {
|
||||
{p1.x, p1.y},
|
||||
uv1.x,
|
||||
uv1.y
|
||||
}
|
||||
append( & draw_list.vertices, vertex )
|
||||
|
||||
quad_indices : []u32 = {
|
||||
0, 1, 2,
|
||||
2, 1, 3
|
||||
}
|
||||
for index : i32 = 0; index < 6; index += 1 {
|
||||
append( & draw_list.indices, v_offset + quad_indices[ index ] )
|
||||
}
|
||||
}
|
||||
|
||||
// ve_fontcache_clear_drawlist
|
||||
clear_draw_list :: proc( draw_list : ^DrawList ) {
|
||||
clear( draw_list.calls )
|
||||
clear( draw_list.indices )
|
||||
clear( draw_list.vertices )
|
||||
}
|
||||
|
||||
// Constructs a triangle fan to fill a shape using the provided path
|
||||
// outside_point represents the center point of the fan.
|
||||
//
|
||||
// Note(Original Author):
|
||||
// WARNING: doesn't actually append drawcall; caller is responsible for actually appending the drawcall.
|
||||
// ve_fontcache_draw_filled_path
|
||||
draw_filled_path :: proc( draw_list : ^DrawList, outside_point : Vec2, path : []Vec2,
|
||||
scale := Vec2 { 1, 1 },
|
||||
translate := Vec2 { 0, 0 },
|
||||
debug_print_verbose : b32 = false
|
||||
)
|
||||
{
|
||||
if debug_print_verbose
|
||||
{
|
||||
log("outline_path: \n")
|
||||
for point in path {
|
||||
logf(" %.2f %.2f\n", point.x * scale )
|
||||
}
|
||||
}
|
||||
|
||||
v_offset := cast(u32) draw_list.vertices.num
|
||||
for point in path {
|
||||
vertex := Vertex {
|
||||
pos = point * scale + translate,
|
||||
u = 0,
|
||||
v = 0,
|
||||
}
|
||||
append( & draw_list.vertices, vertex )
|
||||
}
|
||||
|
||||
outside_vertex := cast(u32) draw_list.vertices.num
|
||||
{
|
||||
vertex := Vertex {
|
||||
pos = outside_point * scale + translate,
|
||||
u = 0,
|
||||
v = 0,
|
||||
}
|
||||
append( & draw_list.vertices, vertex )
|
||||
}
|
||||
|
||||
for index : u32 = 1; index < u32(len(path)); index += 1 {
|
||||
indices := & draw_list.indices
|
||||
append( indices, outside_vertex )
|
||||
append( indices, v_offset + index - 1 )
|
||||
append( indices, v_offset + index )
|
||||
}
|
||||
}
|
||||
|
||||
// ve_fontcache_flush_drawlist
|
||||
flush_draw_list :: proc( ctx : ^Context ) {
|
||||
assert( ctx != nil )
|
||||
clear_draw_list( & ctx.draw_list )
|
||||
}
|
||||
|
||||
// ve_fontcache_drawlist
|
||||
get_draw_list :: proc( ctx : ^Context ) -> ^DrawList {
|
||||
assert( ctx != nil )
|
||||
return & ctx.draw_list
|
||||
}
|
||||
|
||||
// ve_fontcache_merge_drawlist
|
||||
merge_draw_list :: proc( dst, src : ^DrawList )
|
||||
{
|
||||
error : AllocatorError
|
||||
|
||||
v_offset := cast(u32) dst.vertices.num
|
||||
// for index : u32 = 0; index < cast(u32) src.vertices.num; index += 1 {
|
||||
// error = append( & dst.vertices, src.vertices.data[index] )
|
||||
// assert( error == .None )
|
||||
// }
|
||||
error = append( & dst.vertices, src.vertices )
|
||||
assert( error == .None )
|
||||
|
||||
i_offset := cast(u32) dst.indices.num
|
||||
for index : u32 = 0; index < cast(u32) src.indices.num; index += 1 {
|
||||
error = append( & dst.indices, src.indices.data[index] + v_offset )
|
||||
assert( error == .None )
|
||||
}
|
||||
|
||||
for index : u32 = 0; index < cast(u32) src.calls.num; index += 1 {
|
||||
src_call := src.calls.data[ index ]
|
||||
src_call.start_index += i_offset
|
||||
src_call.end_index += i_offset
|
||||
append( & dst.calls, src_call )
|
||||
assert( error == .None )
|
||||
}
|
||||
}
|
||||
|
@ -380,5 +380,18 @@ parser_free_shape :: proc( font : ^ParserFontInfo, shape : ParserGlyphShape )
|
||||
|
||||
parser_get_glyph_box :: proc( font : ^ParserFontInfo, glyph_index : Glyph ) -> (bounds_0, bounds_1 : Vec2i)
|
||||
{
|
||||
switch font.kind
|
||||
{
|
||||
case .Freetype:
|
||||
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user