mirror of
https://github.com/Ed94/VEFontCache-Odin.git
synced 2025-08-06 06:52:44 -07:00
Changes based on latest from Sectr Prototype
This commit is contained in:
33
LRU.odin
33
LRU.odin
@@ -20,12 +20,12 @@ PoolList :: struct {
|
|||||||
free_list : [dynamic]PoolListIter,
|
free_list : [dynamic]PoolListIter,
|
||||||
front : PoolListIter,
|
front : PoolListIter,
|
||||||
back : PoolListIter,
|
back : PoolListIter,
|
||||||
size : u32,
|
size : i32,
|
||||||
capacity : u32,
|
capacity : i32,
|
||||||
dbg_name : string,
|
dbg_name : string,
|
||||||
}
|
}
|
||||||
|
|
||||||
pool_list_init :: proc( pool : ^PoolList, capacity : u32, dbg_name : string = "" )
|
pool_list_init :: proc( pool : ^PoolList, capacity : i32, dbg_name : string = "" )
|
||||||
{
|
{
|
||||||
error : AllocatorError
|
error : AllocatorError
|
||||||
pool.items, error = make( [dynamic]PoolListItem, int(capacity) )
|
pool.items, error = make( [dynamic]PoolListItem, int(capacity) )
|
||||||
@@ -53,13 +53,11 @@ pool_list_init :: proc( pool : ^PoolList, capacity : u32, dbg_name : string = ""
|
|||||||
back = -1
|
back = -1
|
||||||
}
|
}
|
||||||
|
|
||||||
pool_list_free :: proc( pool : ^PoolList )
|
pool_list_free :: proc( pool : ^PoolList ) {
|
||||||
{
|
|
||||||
// TODO(Ed): Implement
|
// TODO(Ed): Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
pool_list_reload :: proc( pool : ^PoolList, allocator : Allocator )
|
pool_list_reload :: proc( pool : ^PoolList, allocator : Allocator ) {
|
||||||
{
|
|
||||||
reload_array( & pool.items, allocator )
|
reload_array( & pool.items, allocator )
|
||||||
reload_array( & pool.free_list, allocator )
|
reload_array( & pool.free_list, allocator )
|
||||||
}
|
}
|
||||||
@@ -160,13 +158,13 @@ LRU_Link :: struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
LRU_Cache :: struct {
|
LRU_Cache :: struct {
|
||||||
capacity : u32,
|
capacity : i32,
|
||||||
num : u32,
|
num : i32,
|
||||||
table : map[u64]LRU_Link,
|
table : map[u64]LRU_Link,
|
||||||
key_queue : PoolList,
|
key_queue : PoolList,
|
||||||
}
|
}
|
||||||
|
|
||||||
LRU_init :: proc( cache : ^LRU_Cache, capacity : u32, dbg_name : string = "" ) {
|
LRU_init :: proc( cache : ^LRU_Cache, capacity : i32, dbg_name : string = "" ) {
|
||||||
error : AllocatorError
|
error : AllocatorError
|
||||||
cache.capacity = capacity
|
cache.capacity = capacity
|
||||||
cache.table, error = make( map[u64]LRU_Link, uint(capacity) )
|
cache.table, error = make( map[u64]LRU_Link, uint(capacity) )
|
||||||
@@ -175,23 +173,15 @@ LRU_init :: proc( cache : ^LRU_Cache, capacity : u32, dbg_name : string = "" ) {
|
|||||||
pool_list_init( & cache.key_queue, capacity, dbg_name = dbg_name )
|
pool_list_init( & cache.key_queue, capacity, dbg_name = dbg_name )
|
||||||
}
|
}
|
||||||
|
|
||||||
LRU_free :: proc( cache : ^LRU_Cache )
|
LRU_free :: proc( cache : ^LRU_Cache ) {
|
||||||
{
|
|
||||||
// TODO(Ed): Implement
|
// TODO(Ed): Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
LRU_reload :: #force_inline proc( cache : ^LRU_Cache, allocator : Allocator )
|
LRU_reload :: #force_inline proc( cache : ^LRU_Cache, allocator : Allocator ) {
|
||||||
{
|
|
||||||
reload_map( & cache.table, allocator )
|
reload_map( & cache.table, allocator )
|
||||||
pool_list_reload( & cache.key_queue, allocator )
|
pool_list_reload( & cache.key_queue, allocator )
|
||||||
}
|
}
|
||||||
|
|
||||||
LRU_hash_key :: #force_inline proc( key : u64 ) -> ( hash : u64 ) {
|
|
||||||
bytes := transmute( [8]byte ) key
|
|
||||||
hash = fnv64a( bytes[:] )
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
LRU_find :: #force_inline proc "contextless" ( cache : ^LRU_Cache, key : u64, must_find := false ) -> (LRU_Link, bool) {
|
LRU_find :: #force_inline proc "contextless" ( cache : ^LRU_Cache, key : u64, must_find := false ) -> (LRU_Link, bool) {
|
||||||
link, success := cache.table[key]
|
link, success := cache.table[key]
|
||||||
return link, success
|
return link, success
|
||||||
@@ -205,8 +195,7 @@ LRU_get :: #force_inline proc( cache: ^LRU_Cache, key : u64 ) -> i32 {
|
|||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
LRU_get_next_evicted :: #force_inline proc ( cache : ^LRU_Cache ) -> u64
|
LRU_get_next_evicted :: #force_inline proc ( cache : ^LRU_Cache ) -> u64 {
|
||||||
{
|
|
||||||
if cache.key_queue.size >= cache.capacity {
|
if cache.key_queue.size >= cache.capacity {
|
||||||
evict := pool_list_peek_back( & cache.key_queue )
|
evict := pool_list_peek_back( & cache.key_queue )
|
||||||
return evict
|
return evict
|
||||||
|
14
Readme.md
14
Readme.md
@@ -6,9 +6,17 @@ Its original purpose was for use in game engines, however its rendeirng quality
|
|||||||
|
|
||||||
See: [docs/Readme.md](docs/Readme.md) for the library's interface
|
See: [docs/Readme.md](docs/Readme.md) for the library's interface
|
||||||
|
|
||||||
|
## Changes from orignal
|
||||||
|
|
||||||
|
* Font Parser & Glyph shaper are abstracted to their own interface
|
||||||
|
* Font face parser info encapsulated in parser_info struct.
|
||||||
|
* ve_fontcache_loadfile not ported (ust use core:os or os2, then call load_font)
|
||||||
|
* Macro defines have been coverted (mostly) to runtime parameters
|
||||||
|
* Support for hot_reloading
|
||||||
|
|
||||||
## TODOs
|
## TODOs
|
||||||
|
|
||||||
### (Making it a more idiomatic library):
|
### Thirdparty support:
|
||||||
|
|
||||||
* Setup freetype, harfbuzz, depedency management within the library
|
* Setup freetype, harfbuzz, depedency management within the library
|
||||||
|
|
||||||
@@ -28,6 +36,7 @@ See: [docs/Readme.md](docs/Readme.md) for the library's interface
|
|||||||
* Support for harfbuzz
|
* Support for harfbuzz
|
||||||
* Ability to set a draw transform, viewport and projection
|
* Ability to set a draw transform, viewport and projection
|
||||||
* By default the library's position is in unsigned normalized render space
|
* By default the library's position is in unsigned normalized render space
|
||||||
|
* Could implement a similar design to sokol_gp's interface
|
||||||
* Allow curve_quality to be set on a per-font basis
|
* Allow curve_quality to be set on a per-font basis
|
||||||
|
|
||||||
### Optimization:
|
### Optimization:
|
||||||
@@ -43,9 +52,10 @@ See: [docs/Readme.md](docs/Readme.md) for the library's interface
|
|||||||
* glyph_draw_buffer
|
* glyph_draw_buffer
|
||||||
* shape_cache
|
* shape_cache
|
||||||
* This would need to converge to the singlar draw_list on a per layer basis (then user reqeusts a draw_list layer there could a yield to wait for the jobs to finish); if the interface expects the user to issue the commands single-threaded unless, we just assume the user is going to feed the gpu the commands & data through separate threads as well (not ideal ux).
|
* This would need to converge to the singlar draw_list on a per layer basis (then user reqeusts a draw_list layer there could a yield to wait for the jobs to finish); if the interface expects the user to issue the commands single-threaded unless, we just assume the user is going to feed the gpu the commands & data through separate threads as well (not ideal ux).
|
||||||
|
* How the contexts are given jobs should be left up to the user (can recommend a screen quadrant based approach in demo examples)
|
||||||
|
|
||||||
Failed Attempts:
|
Failed Attempts:
|
||||||
|
|
||||||
* Attempted to chunk the text to more granular 'shapes' from `draw_list` before doing the actual call to `draw_text_shape`. This lead to a larger performance cost due to the additional iteration across the text string.
|
* Attempted to chunk the text to more granular 'shapes' from `draw_list` before doing the actual call to `draw_text_shape`. This lead to a larger performance cost due to the additional iteration across the text string.
|
||||||
* Attempted to cache the shape draw_list for future calls. Led to larger performance cost due to additional iteration in the `merge_draw_list`.
|
* Attempted to cache the shape draw_list for future calls. Led to larger performance cost due to additional iteration in the `merge_draw_list`.
|
||||||
* The shapes glyphs must still be traversed to identify if the glyph is cached. This arguably could be handled in `shape_text_uncached`, however that would require a significan't amount of refactoring to identify... (and would be more unergonomic when shapers libs are processing the text)
|
* The shapes glyphs must still be traversed to identify if the glyph is cached. This arguably could be handled in `shape_text_uncached`, however that would require a significan't amount of refactoring to identify... (and would be more unergonomic when shapers libs are processing the text)
|
||||||
|
106
VEFontCache.odin
106
VEFontCache.odin
@@ -1,14 +1,11 @@
|
|||||||
/*
|
/*
|
||||||
A port of (https://github.com/hypernewbie/VEFontCache) to Odin.
|
A port of (https://github.com/hypernewbie/VEFontCache) to Odin.
|
||||||
|
|
||||||
Status:
|
|
||||||
This port is heavily tied to the grime package in SectrPrototype.
|
|
||||||
|
|
||||||
Changes:
|
Changes:
|
||||||
- Font Parser & Glyph Shaper are abstracted to their own interface
|
- Font Parser & Glyph Shaper are abstracted to their own interface
|
||||||
- Font Face parser info stored separately from entries
|
- 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
|
- 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
|
- Macro defines have been made (mostly) into runtime parameters
|
||||||
*/
|
*/
|
||||||
package VEFontCache
|
package VEFontCache
|
||||||
|
|
||||||
@@ -20,12 +17,13 @@ FontID :: distinct i64
|
|||||||
Glyph :: distinct i32
|
Glyph :: distinct i32
|
||||||
|
|
||||||
Entry :: struct {
|
Entry :: struct {
|
||||||
parser_info : ParserFontInfo,
|
parser_info : ParserFontInfo,
|
||||||
shaper_info : ShaperInfo,
|
shaper_info : ShaperInfo,
|
||||||
id : FontID,
|
id : FontID,
|
||||||
used : b32,
|
used : b32,
|
||||||
size : f32,
|
curve_quality : f32,
|
||||||
size_scale : f32,
|
size : f32,
|
||||||
|
size_scale : f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
Entry_Default :: Entry {
|
Entry_Default :: Entry {
|
||||||
@@ -46,16 +44,14 @@ Context :: struct {
|
|||||||
|
|
||||||
temp_path : [dynamic]Vertex,
|
temp_path : [dynamic]Vertex,
|
||||||
temp_codepoint_seen : map[u64]bool,
|
temp_codepoint_seen : map[u64]bool,
|
||||||
temp_codepoint_seen_num : u32,
|
temp_codepoint_seen_num : int,
|
||||||
|
|
||||||
snap_width : u32,
|
snap_width : f32,
|
||||||
snap_height : u32,
|
snap_height : f32,
|
||||||
|
|
||||||
colour : Colour,
|
colour : Colour,
|
||||||
cursor_pos : Vec2,
|
cursor_pos : Vec2,
|
||||||
|
|
||||||
// draw_cursor_pos : Vec2,
|
|
||||||
|
|
||||||
draw_layer : struct {
|
draw_layer : struct {
|
||||||
vertices_offset : int,
|
vertices_offset : int,
|
||||||
indices_offset : int,
|
indices_offset : int,
|
||||||
@@ -67,8 +63,8 @@ Context :: struct {
|
|||||||
glyph_buffer : GlyphDrawBuffer,
|
glyph_buffer : GlyphDrawBuffer,
|
||||||
shape_cache : ShapedTextCache,
|
shape_cache : ShapedTextCache,
|
||||||
|
|
||||||
curve_quality : u32,
|
default_curve_quality : i32,
|
||||||
text_shape_adv : b32,
|
text_shape_adv : b32,
|
||||||
|
|
||||||
debug_print : b32,
|
debug_print : b32,
|
||||||
debug_print_verbose : b32,
|
debug_print_verbose : b32,
|
||||||
@@ -116,7 +112,7 @@ InitAtlasParams_Default :: InitAtlasParams {
|
|||||||
}
|
}
|
||||||
|
|
||||||
InitGlyphDrawParams :: struct {
|
InitGlyphDrawParams :: struct {
|
||||||
over_sample : Vec2,
|
over_sample : Vec2i,
|
||||||
buffer_batch : u32,
|
buffer_batch : u32,
|
||||||
draw_padding : u32,
|
draw_padding : u32,
|
||||||
}
|
}
|
||||||
@@ -133,8 +129,8 @@ InitShapeCacheParams :: struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
InitShapeCacheParams_Default :: InitShapeCacheParams {
|
InitShapeCacheParams_Default :: InitShapeCacheParams {
|
||||||
capacity = 2048,
|
capacity = 8 * 1024,
|
||||||
reserve_length = 2048,
|
reserve_length = 1 * 1024,
|
||||||
}
|
}
|
||||||
|
|
||||||
// ve_fontcache_init
|
// ve_fontcache_init
|
||||||
@@ -143,7 +139,7 @@ startup :: proc( ctx : ^Context, parser_kind : ParserKind,
|
|||||||
atlas_params := InitAtlasParams_Default,
|
atlas_params := InitAtlasParams_Default,
|
||||||
glyph_draw_params := InitGlyphDrawParams_Default,
|
glyph_draw_params := InitGlyphDrawParams_Default,
|
||||||
shape_cache_params := InitShapeCacheParams_Default,
|
shape_cache_params := InitShapeCacheParams_Default,
|
||||||
curve_quality : u32 = 3,
|
default_curve_quality : u32 = 3,
|
||||||
entires_reserve : u32 = 512,
|
entires_reserve : u32 = 512,
|
||||||
temp_path_reserve : u32 = 1024,
|
temp_path_reserve : u32 = 1024,
|
||||||
temp_codepoint_seen_reserve : u32 = 2048,
|
temp_codepoint_seen_reserve : u32 = 2048,
|
||||||
@@ -155,10 +151,10 @@ startup :: proc( ctx : ^Context, parser_kind : ParserKind,
|
|||||||
ctx.backing = allocator
|
ctx.backing = allocator
|
||||||
context.allocator = ctx.backing
|
context.allocator = ctx.backing
|
||||||
|
|
||||||
if curve_quality == 0 {
|
if default_curve_quality == 0 {
|
||||||
curve_quality = 3
|
default_curve_quality = 3
|
||||||
}
|
}
|
||||||
ctx.curve_quality = curve_quality
|
ctx.default_curve_quality = default_curve_quality
|
||||||
|
|
||||||
error : AllocatorError
|
error : AllocatorError
|
||||||
entries, error = make( [dynamic]Entry, len = 0, cap = entires_reserve )
|
entries, error = make( [dynamic]Entry, len = 0, cap = entires_reserve )
|
||||||
@@ -184,8 +180,8 @@ startup :: proc( ctx : ^Context, parser_kind : ParserKind,
|
|||||||
using region
|
using region
|
||||||
|
|
||||||
next_idx = 0;
|
next_idx = 0;
|
||||||
width = region_params.width
|
width = i32(region_params.width)
|
||||||
height = region_params.height
|
height = i32(region_params.height)
|
||||||
size = {
|
size = {
|
||||||
i32(params.width) / factor.x,
|
i32(params.width) / factor.x,
|
||||||
i32(params.height) / factor.y,
|
i32(params.height) / factor.y,
|
||||||
@@ -197,28 +193,26 @@ startup :: proc( ctx : ^Context, parser_kind : ParserKind,
|
|||||||
assert( capacity.x * capacity.y == expected_cap )
|
assert( capacity.x * capacity.y == expected_cap )
|
||||||
|
|
||||||
error : AllocatorError
|
error : AllocatorError
|
||||||
// state.cache, error = make( HMapChained(LRU_Link), uint(capacity.x * capacity.y) )
|
LRU_init( & state, capacity.x * capacity.y )
|
||||||
// assert( error == .None, "VEFontCache.init_atlas_region : Failed to allocate state.cache")
|
|
||||||
LRU_init( & state, u32(capacity.x * capacity.y) )
|
|
||||||
}
|
}
|
||||||
init_atlas_region( & atlas.region_a, atlas_params, atlas_params.region_a, { 4, 2}, 1024 )
|
init_atlas_region( & atlas.region_a, atlas_params, atlas_params.region_a, { 4, 2}, 1024 )
|
||||||
init_atlas_region( & atlas.region_b, atlas_params, atlas_params.region_b, { 4, 2}, 512 )
|
init_atlas_region( & atlas.region_b, atlas_params, atlas_params.region_b, { 4, 2}, 512 )
|
||||||
init_atlas_region( & atlas.region_c, atlas_params, atlas_params.region_c, { 4, 1}, 512 )
|
init_atlas_region( & atlas.region_c, atlas_params, atlas_params.region_c, { 4, 1}, 512 )
|
||||||
init_atlas_region( & atlas.region_d, atlas_params, atlas_params.region_d, { 2, 1}, 256 )
|
init_atlas_region( & atlas.region_d, atlas_params, atlas_params.region_d, { 2, 1}, 256 )
|
||||||
|
|
||||||
atlas.width = atlas_params.width
|
atlas.width = i32(atlas_params.width)
|
||||||
atlas.height = atlas_params.height
|
atlas.height = i32(atlas_params.height)
|
||||||
atlas.glyph_padding = atlas_params.glyph_padding
|
atlas.glyph_padding = i32(atlas_params.glyph_padding)
|
||||||
|
|
||||||
atlas.region_a.offset = {0, 0}
|
atlas.region_a.offset = {0, 0}
|
||||||
atlas.region_b.offset.x = 0
|
atlas.region_b.offset.x = 0
|
||||||
atlas.region_b.offset.y = atlas.region_a.size.y
|
atlas.region_b.offset.y = atlas.region_a.size.y
|
||||||
atlas.region_c.offset.x = atlas.region_a.size.x
|
atlas.region_c.offset.x = atlas.region_a.size.x
|
||||||
atlas.region_c.offset.y = 0
|
atlas.region_c.offset.y = 0
|
||||||
atlas.region_d.offset.x = i32(atlas.width) / 2
|
atlas.region_d.offset.x = atlas.width / 2
|
||||||
atlas.region_d.offset.y = 0
|
atlas.region_d.offset.y = 0
|
||||||
|
|
||||||
LRU_init( & shape_cache.state, shape_cache_params.capacity )
|
LRU_init( & shape_cache.state, i32(shape_cache_params.capacity) )
|
||||||
|
|
||||||
shape_cache.storage, error = make( [dynamic]ShapedText, shape_cache_params.capacity )
|
shape_cache.storage, error = make( [dynamic]ShapedText, shape_cache_params.capacity )
|
||||||
assert(error == .None, "VEFontCache.init : Failed to allocate shape_cache.storage")
|
assert(error == .None, "VEFontCache.init : Failed to allocate shape_cache.storage")
|
||||||
@@ -245,11 +239,11 @@ startup :: proc( ctx : ^Context, parser_kind : ParserKind,
|
|||||||
// Note(From original author): We can actually go over VE_FONTCACHE_GLYPHDRAW_BUFFER_BATCH batches due to smart packing!
|
// Note(From original author): We can actually go over VE_FONTCACHE_GLYPHDRAW_BUFFER_BATCH batches due to smart packing!
|
||||||
{
|
{
|
||||||
using glyph_buffer
|
using glyph_buffer
|
||||||
over_sample = glyph_draw_params.over_sample
|
over_sample = vec2(glyph_draw_params.over_sample)
|
||||||
batch = glyph_draw_params.buffer_batch
|
batch = cast(i32) glyph_draw_params.buffer_batch
|
||||||
width = atlas.region_d.width * u32(over_sample.x) * batch
|
width = atlas.region_d.width * i32(over_sample.x) * batch
|
||||||
height = atlas.region_d.height * u32(over_sample.y)
|
height = atlas.region_d.height * i32(over_sample.y)
|
||||||
draw_padding = glyph_draw_params.draw_padding
|
draw_padding = cast(i32) glyph_draw_params.draw_padding
|
||||||
|
|
||||||
draw_list.calls, error = make( [dynamic]DrawCall, len = 0, cap = glyph_draw_params.buffer_batch * 2 )
|
draw_list.calls, error = make( [dynamic]DrawCall, len = 0, cap = glyph_draw_params.buffer_batch * 2 )
|
||||||
assert( error == .None, "VEFontCache.init : Failed to allocate calls for draw_list" )
|
assert( error == .None, "VEFontCache.init : Failed to allocate calls for draw_list" )
|
||||||
@@ -295,7 +289,7 @@ hot_reload :: proc( ctx : ^Context, allocator : Allocator )
|
|||||||
LRU_reload( & atlas.region_d.state, allocator)
|
LRU_reload( & atlas.region_d.state, allocator)
|
||||||
|
|
||||||
LRU_reload( & shape_cache.state, allocator )
|
LRU_reload( & shape_cache.state, allocator )
|
||||||
for idx : u32 = 0; idx < u32(len(shape_cache.storage)); idx += 1 {
|
for idx : i32 = 0; idx < i32(len(shape_cache.storage)); idx += 1 {
|
||||||
stroage_entry := & shape_cache.storage[idx]
|
stroage_entry := & shape_cache.storage[idx]
|
||||||
using stroage_entry
|
using stroage_entry
|
||||||
|
|
||||||
@@ -332,7 +326,7 @@ shutdown :: proc( ctx : ^Context )
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ve_fontcache_load
|
// ve_fontcache_load
|
||||||
load_font :: proc( ctx : ^Context, label : string, data : []byte, size_px : f32 ) -> (font_id : FontID)
|
load_font :: proc( ctx : ^Context, label : string, data : []byte, size_px : f32, glyph_curve_quality : u32 = 0 ) -> (font_id : FontID)
|
||||||
{
|
{
|
||||||
assert( ctx != nil )
|
assert( ctx != nil )
|
||||||
assert( len(data) > 0 )
|
assert( len(data) > 0 )
|
||||||
@@ -355,19 +349,25 @@ load_font :: proc( ctx : ^Context, label : string, data : []byte, size_px : f32
|
|||||||
entry := & entries[ id ]
|
entry := & entries[ id ]
|
||||||
{
|
{
|
||||||
using entry
|
using entry
|
||||||
|
used = true
|
||||||
|
|
||||||
parser_info = parser_load_font( & parser_ctx, label, data )
|
parser_info = parser_load_font( & parser_ctx, label, data )
|
||||||
// assert( parser_info != nil, "VEFontCache.load_font: Failed to load font info from parser" )
|
// assert( parser_info != nil, "VEFontCache.load_font: Failed to load font info from parser" )
|
||||||
|
|
||||||
|
shaper_info = shaper_load_font( & shaper_ctx, label, data, transmute(rawptr) id )
|
||||||
|
// assert( shaper_info != nil, "VEFontCache.load_font: Failed to load font from shaper")
|
||||||
|
|
||||||
size = size_px
|
size = size_px
|
||||||
size_scale = size_px < 0.0 ? \
|
size_scale = size_px < 0.0 ? \
|
||||||
parser_scale_for_pixel_height( & parser_info, -size_px ) \
|
parser_scale_for_pixel_height( & parser_info, -size_px ) \
|
||||||
: parser_scale_for_mapping_em_to_pixels( & parser_info, size_px )
|
: parser_scale_for_mapping_em_to_pixels( & parser_info, size_px )
|
||||||
|
|
||||||
used = true
|
if glyph_curve_quality == 0 {
|
||||||
|
curve_quality = f32(ctx.default_curve_quality)
|
||||||
shaper_info = shaper_load_font( & shaper_ctx, label, data, transmute(rawptr) id )
|
}
|
||||||
// assert( shaper_info != nil, "VEFontCache.load_font: Failed to load font from shaper")
|
else {
|
||||||
|
curve_quality = f32(glyph_curve_quality)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
entry.id = FontID(id)
|
entry.id = FontID(id)
|
||||||
ctx.entries[ id ].id = FontID(id)
|
ctx.entries[ id ].id = FontID(id)
|
||||||
@@ -398,8 +398,8 @@ unload_font :: proc( ctx : ^Context, font : FontID )
|
|||||||
// ve_fontcache_configure_snap
|
// ve_fontcache_configure_snap
|
||||||
configure_snap :: #force_inline proc( ctx : ^Context, snap_width, snap_height : u32 ) {
|
configure_snap :: #force_inline proc( ctx : ^Context, snap_width, snap_height : u32 ) {
|
||||||
assert( ctx != nil )
|
assert( ctx != nil )
|
||||||
ctx.snap_width = snap_width
|
ctx.snap_width = f32(snap_width)
|
||||||
ctx.snap_height = snap_height
|
ctx.snap_height = f32(snap_height)
|
||||||
}
|
}
|
||||||
|
|
||||||
get_cursor_pos :: #force_inline proc "contextless" ( ctx : ^Context ) -> Vec2 { return ctx.cursor_pos }
|
get_cursor_pos :: #force_inline proc "contextless" ( ctx : ^Context ) -> Vec2 { return ctx.cursor_pos }
|
||||||
@@ -413,13 +413,11 @@ draw_text :: proc( ctx : ^Context, font : FontID, text_utf8 : string, position,
|
|||||||
|
|
||||||
ctx.cursor_pos = {}
|
ctx.cursor_pos = {}
|
||||||
|
|
||||||
position := position
|
position := position
|
||||||
snap_width := f32(ctx.snap_width)
|
if ctx.snap_width > 0 do position.x = cast(f32) cast(u32) (position.x * ctx.snap_width + 0.5) / ctx.snap_width
|
||||||
snap_height := f32(ctx.snap_height)
|
if ctx.snap_height > 0 do position.y = cast(f32) cast(u32) (position.y * ctx.snap_height + 0.5) / ctx.snap_height
|
||||||
if ctx.snap_width > 0 do position.x = cast(f32) cast(u32) (position.x * snap_width + 0.5) / snap_width
|
|
||||||
if ctx.snap_height > 0 do position.y = cast(f32) cast(u32) (position.y * snap_height + 0.5) / snap_height
|
|
||||||
|
|
||||||
entry := & ctx.entries[ font ]
|
entry := & ctx.entries[ font ]
|
||||||
|
|
||||||
ChunkType :: enum u32 { Visible, Formatting }
|
ChunkType :: enum u32 { Visible, Formatting }
|
||||||
chunk_kind : ChunkType
|
chunk_kind : ChunkType
|
||||||
@@ -432,7 +430,7 @@ draw_text :: proc( ctx : ^Context, font : FontID, text_utf8 : string, position,
|
|||||||
text_chunk = transmute(string) text_utf8_bytes[ : ]
|
text_chunk = transmute(string) text_utf8_bytes[ : ]
|
||||||
if len(text_chunk) > 0 {
|
if len(text_chunk) > 0 {
|
||||||
shaped := shape_text_cached( ctx, font, text_chunk, entry )
|
shaped := shape_text_cached( ctx, font, text_chunk, entry )
|
||||||
ctx.cursor_pos = draw_text_shape( ctx, font, entry, shaped, position, scale, snap_width, snap_height )
|
ctx.cursor_pos = draw_text_shape( ctx, font, entry, shaped, position, scale, ctx.snap_width, ctx.snap_height )
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
32
atlas.odin
32
atlas.odin
@@ -13,21 +13,21 @@ AtlasRegionKind :: enum u8 {
|
|||||||
AtlasRegion :: struct {
|
AtlasRegion :: struct {
|
||||||
state : LRU_Cache,
|
state : LRU_Cache,
|
||||||
|
|
||||||
width : u32,
|
width : i32,
|
||||||
height : u32,
|
height : i32,
|
||||||
|
|
||||||
size : Vec2i,
|
size : Vec2i,
|
||||||
capacity : Vec2i,
|
capacity : Vec2i,
|
||||||
offset : Vec2i,
|
offset : Vec2i,
|
||||||
|
|
||||||
next_idx : u32,
|
next_idx : i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
Atlas :: struct {
|
Atlas :: struct {
|
||||||
width : u32,
|
width : i32,
|
||||||
height : u32,
|
height : i32,
|
||||||
|
|
||||||
glyph_padding : u32,
|
glyph_padding : i32,
|
||||||
|
|
||||||
region_a : AtlasRegion,
|
region_a : AtlasRegion,
|
||||||
region_b : AtlasRegion,
|
region_b : AtlasRegion,
|
||||||
@@ -43,8 +43,8 @@ atlas_bbox :: proc( atlas : ^Atlas, region : AtlasRegionKind, local_idx : i32 )
|
|||||||
size.x = f32(atlas.region_a.width)
|
size.x = f32(atlas.region_a.width)
|
||||||
size.y = f32(atlas.region_a.height)
|
size.y = f32(atlas.region_a.height)
|
||||||
|
|
||||||
position.x = cast(f32) (( local_idx % atlas.region_a.capacity.x ) * i32(atlas.region_a.width))
|
position.x = cast(f32) (( local_idx % atlas.region_a.capacity.x ) * atlas.region_a.width)
|
||||||
position.y = cast(f32) (( local_idx / atlas.region_a.capacity.x ) * i32(atlas.region_a.height))
|
position.y = cast(f32) (( local_idx / atlas.region_a.capacity.x ) * atlas.region_a.height)
|
||||||
|
|
||||||
position.x += f32(atlas.region_a.offset.x)
|
position.x += f32(atlas.region_a.offset.x)
|
||||||
position.y += f32(atlas.region_a.offset.y)
|
position.y += f32(atlas.region_a.offset.y)
|
||||||
@@ -53,8 +53,8 @@ atlas_bbox :: proc( atlas : ^Atlas, region : AtlasRegionKind, local_idx : i32 )
|
|||||||
size.x = f32(atlas.region_b.width)
|
size.x = f32(atlas.region_b.width)
|
||||||
size.y = f32(atlas.region_b.height)
|
size.y = f32(atlas.region_b.height)
|
||||||
|
|
||||||
position.x = cast(f32) (( local_idx % atlas.region_b.capacity.x ) * i32(atlas.region_b.width))
|
position.x = cast(f32) (( local_idx % atlas.region_b.capacity.x ) * atlas.region_b.width)
|
||||||
position.y = cast(f32) (( local_idx / atlas.region_b.capacity.x ) * i32(atlas.region_b.height))
|
position.y = cast(f32) (( local_idx / atlas.region_b.capacity.x ) * atlas.region_b.height)
|
||||||
|
|
||||||
position.x += f32(atlas.region_b.offset.x)
|
position.x += f32(atlas.region_b.offset.x)
|
||||||
position.y += f32(atlas.region_b.offset.y)
|
position.y += f32(atlas.region_b.offset.y)
|
||||||
@@ -63,8 +63,8 @@ atlas_bbox :: proc( atlas : ^Atlas, region : AtlasRegionKind, local_idx : i32 )
|
|||||||
size.x = f32(atlas.region_c.width)
|
size.x = f32(atlas.region_c.width)
|
||||||
size.y = f32(atlas.region_c.height)
|
size.y = f32(atlas.region_c.height)
|
||||||
|
|
||||||
position.x = cast(f32) (( local_idx % atlas.region_c.capacity.x ) * i32(atlas.region_c.width))
|
position.x = cast(f32) (( local_idx % atlas.region_c.capacity.x ) * atlas.region_c.width)
|
||||||
position.y = cast(f32) (( local_idx / atlas.region_c.capacity.x ) * i32(atlas.region_c.height))
|
position.y = cast(f32) (( local_idx / atlas.region_c.capacity.x ) * atlas.region_c.height)
|
||||||
|
|
||||||
position.x += f32(atlas.region_c.offset.x)
|
position.x += f32(atlas.region_c.offset.x)
|
||||||
position.y += f32(atlas.region_c.offset.y)
|
position.y += f32(atlas.region_c.offset.y)
|
||||||
@@ -73,8 +73,8 @@ atlas_bbox :: proc( atlas : ^Atlas, region : AtlasRegionKind, local_idx : i32 )
|
|||||||
size.x = f32(atlas.region_d.width)
|
size.x = f32(atlas.region_d.width)
|
||||||
size.y = f32(atlas.region_d.height)
|
size.y = f32(atlas.region_d.height)
|
||||||
|
|
||||||
position.x = cast(f32) (( local_idx % atlas.region_d.capacity.x ) * i32(atlas.region_d.width))
|
position.x = cast(f32) (( local_idx % atlas.region_d.capacity.x ) * atlas.region_d.width)
|
||||||
position.y = cast(f32) (( local_idx / atlas.region_d.capacity.x ) * i32(atlas.region_d.height))
|
position.y = cast(f32) (( local_idx / atlas.region_d.capacity.x ) * atlas.region_d.height)
|
||||||
|
|
||||||
position.x += f32(atlas.region_d.offset.x)
|
position.x += f32(atlas.region_d.offset.x)
|
||||||
position.y += f32(atlas.region_d.offset.y)
|
position.y += f32(atlas.region_d.offset.y)
|
||||||
@@ -101,8 +101,8 @@ decide_codepoint_region :: proc(ctx : ^Context, entry : ^Entry, glyph_index : Gl
|
|||||||
glyph_buffer := & ctx.glyph_buffer
|
glyph_buffer := & ctx.glyph_buffer
|
||||||
glyph_padding := f32( atlas.glyph_padding ) * 2
|
glyph_padding := f32( atlas.glyph_padding ) * 2
|
||||||
|
|
||||||
bounds_width_scaled := u32(bounds_width * entry.size_scale + glyph_padding)
|
bounds_width_scaled := i32(bounds_width * entry.size_scale + glyph_padding)
|
||||||
bounds_height_scaled := u32(bounds_height * entry.size_scale + glyph_padding)
|
bounds_height_scaled := i32(bounds_height * entry.size_scale + glyph_padding)
|
||||||
|
|
||||||
// Use a lookup table for faster region selection
|
// Use a lookup table for faster region selection
|
||||||
region_lookup := [4]struct { kind: AtlasRegionKind, region: ^AtlasRegion } {
|
region_lookup := [4]struct { kind: AtlasRegionKind, region: ^AtlasRegion } {
|
||||||
|
200
draw.odin
200
draw.odin
@@ -39,10 +39,10 @@ FrameBufferPass :: enum u32 {
|
|||||||
|
|
||||||
GlyphDrawBuffer :: struct {
|
GlyphDrawBuffer :: struct {
|
||||||
over_sample : Vec2,
|
over_sample : Vec2,
|
||||||
batch : u32,
|
batch : i32,
|
||||||
width : u32,
|
width : i32,
|
||||||
height : u32,
|
height : i32,
|
||||||
draw_padding : u32,
|
draw_padding : i32,
|
||||||
|
|
||||||
batch_x : i32,
|
batch_x : i32,
|
||||||
clear_draw_list : DrawList,
|
clear_draw_list : DrawList,
|
||||||
@@ -106,23 +106,8 @@ cache_glyph :: proc(ctx : ^Context, font : FontID, glyph_index : Glyph, entry :
|
|||||||
path := &ctx.temp_path
|
path := &ctx.temp_path
|
||||||
clear(path)
|
clear(path)
|
||||||
|
|
||||||
append_bezier_curve :: #force_inline proc(path: ^[dynamic]Vertex, p0, p1, p2: Vec2, quality: u32) {
|
for edge in shape do #partial switch edge.type
|
||||||
step := 1.0 / f32(quality)
|
{
|
||||||
for index := u32(1); index <= quality; index += 1 {
|
|
||||||
alpha := f32(index) * step
|
|
||||||
append( path, Vertex { pos = eval_point_on_bezier3(p0, p1, p2, alpha) } )
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
append_bezier_curve_cubic :: #force_inline proc(path: ^[dynamic]Vertex, p0, p1, p2, p3: Vec2, quality: u32) {
|
|
||||||
step := 1.0 / f32(quality)
|
|
||||||
for index := u32(1); index <= quality; index += 1 {
|
|
||||||
alpha := f32(index) * step
|
|
||||||
append( path, Vertex { pos = eval_point_on_bezier4(p0, p1, p2, p3, alpha) } )
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for edge in shape do #partial switch edge.type {
|
|
||||||
case .Move:
|
case .Move:
|
||||||
if len(path) > 0 {
|
if len(path) > 0 {
|
||||||
draw_filled_path(&ctx.draw_list, outside, path[:], scale, translate, ctx.debug_print_verbose)
|
draw_filled_path(&ctx.draw_list, outside, path[:], scale, translate, ctx.debug_print_verbose)
|
||||||
@@ -138,7 +123,12 @@ cache_glyph :: proc(ctx : ^Context, font : FontID, glyph_index : Glyph, entry :
|
|||||||
p0 := path[ len(path) - 1].pos
|
p0 := path[ len(path) - 1].pos
|
||||||
p1 := Vec2{ f32(edge.contour_x0), f32(edge.contour_y0) }
|
p1 := Vec2{ f32(edge.contour_x0), f32(edge.contour_y0) }
|
||||||
p2 := Vec2{ f32(edge.x), f32(edge.y) }
|
p2 := Vec2{ f32(edge.x), f32(edge.y) }
|
||||||
append_bezier_curve( path, p0, p1, p2, ctx.curve_quality )
|
|
||||||
|
step := 1.0 / entry.curve_quality
|
||||||
|
for index : f32 = 1; index <= entry.curve_quality; index += 1 {
|
||||||
|
alpha := index * step
|
||||||
|
append( path, Vertex { pos = eval_point_on_bezier3(p0, p1, p2, alpha) } )
|
||||||
|
}
|
||||||
|
|
||||||
case .Cubic:
|
case .Cubic:
|
||||||
assert( len(path) > 0)
|
assert( len(path) > 0)
|
||||||
@@ -146,7 +136,12 @@ cache_glyph :: proc(ctx : ^Context, font : FontID, glyph_index : Glyph, entry :
|
|||||||
p1 := Vec2{ f32(edge.contour_x0), f32(edge.contour_y0) }
|
p1 := Vec2{ f32(edge.contour_x0), f32(edge.contour_y0) }
|
||||||
p2 := Vec2{ f32(edge.contour_x1), f32(edge.contour_y1) }
|
p2 := Vec2{ f32(edge.contour_x1), f32(edge.contour_y1) }
|
||||||
p3 := Vec2{ f32(edge.x), f32(edge.y) }
|
p3 := Vec2{ f32(edge.x), f32(edge.y) }
|
||||||
append_bezier_curve_cubic( path, p0, p1, p2, p3, ctx.curve_quality )
|
|
||||||
|
step := 1.0 / entry.curve_quality
|
||||||
|
for index : f32 = 1; index <= entry.curve_quality; index += 1 {
|
||||||
|
alpha := index * step
|
||||||
|
append( path, Vertex { pos = eval_point_on_bezier4(p0, p1, p2, p3, alpha) } )
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(path) > 0 {
|
if len(path) > 0 {
|
||||||
@@ -313,7 +308,7 @@ check_glyph_in_atlas :: #force_inline proc( ctx : ^Context, font : FontID, entry
|
|||||||
|
|
||||||
if atlas_index == - 1
|
if atlas_index == - 1
|
||||||
{
|
{
|
||||||
if region.next_idx > u32( region.state.capacity) {
|
if region.next_idx > region.state.capacity {
|
||||||
// We will evict LRU. We must predict which LRU will get evicted, and if it's something we've seen then we need to take slowpath and flush batch.
|
// We will evict LRU. We must predict which LRU will get evicted, and if it's something we've seen then we need to take slowpath and flush batch.
|
||||||
next_evict_codepoint := LRU_get_next_evicted( & region.state )
|
next_evict_codepoint := LRU_get_next_evicted( & region.state )
|
||||||
seen, success := ctx.temp_codepoint_seen[next_evict_codepoint]
|
seen, success := ctx.temp_codepoint_seen[next_evict_codepoint]
|
||||||
@@ -405,90 +400,6 @@ directly_draw_massive_glyph :: proc( ctx : ^Context,
|
|||||||
append( & ctx.draw_list.calls, ..calls[:] )
|
append( & ctx.draw_list.calls, ..calls[:] )
|
||||||
}
|
}
|
||||||
|
|
||||||
draw_cached_glyph :: proc( ctx : ^Context, shaped : ^ShapedText,
|
|
||||||
entry : ^Entry,
|
|
||||||
glyph_index : Glyph,
|
|
||||||
lru_code : u64,
|
|
||||||
atlas_index : i32,
|
|
||||||
bounds_0, bounds_1 : Vec2,
|
|
||||||
region_kind : AtlasRegionKind,
|
|
||||||
region : ^AtlasRegion,
|
|
||||||
over_sample : Vec2,
|
|
||||||
position, scale : Vec2
|
|
||||||
) -> b32
|
|
||||||
{
|
|
||||||
// profile(#procedure)
|
|
||||||
bounds_size := Vec2 {
|
|
||||||
f32(bounds_1.x - bounds_0.x),
|
|
||||||
f32(bounds_1.y - bounds_0.y),
|
|
||||||
}
|
|
||||||
|
|
||||||
// E region is special case and not cached to atlas
|
|
||||||
if region_kind == .E
|
|
||||||
{
|
|
||||||
directly_draw_massive_glyph( ctx, entry, glyph_index, bounds_0, bounds_1, bounds_size, over_sample, position, scale )
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Is this codepoint cached?
|
|
||||||
if atlas_index == - 1 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
atlas := & ctx.atlas
|
|
||||||
atlas_size := Vec2 { f32(atlas.width), f32(atlas.height) }
|
|
||||||
glyph_padding := f32(atlas.glyph_padding)
|
|
||||||
|
|
||||||
// Figure out the source bounding box in the atlas texture
|
|
||||||
slot_position, _ := atlas_bbox( atlas, region_kind, atlas_index )
|
|
||||||
|
|
||||||
glyph_scale := bounds_size * entry.size_scale + glyph_padding
|
|
||||||
|
|
||||||
bounds_0_scaled := bounds_0 * entry.size_scale //- { 0.5, 0.5 }
|
|
||||||
bounds_0_scaled = ceil(bounds_0_scaled)
|
|
||||||
|
|
||||||
dst := position + (bounds_0_scaled - glyph_padding) * scale
|
|
||||||
dst_scale := glyph_scale * scale
|
|
||||||
|
|
||||||
textspace_x_form( & slot_position, & glyph_scale, atlas_size )
|
|
||||||
|
|
||||||
// Shape call setup
|
|
||||||
when false
|
|
||||||
{
|
|
||||||
call := DrawCall_Default
|
|
||||||
{
|
|
||||||
using call
|
|
||||||
pass = .Target
|
|
||||||
colour = ctx.colour
|
|
||||||
start_index = cast(u32) len(shaped.draw_list.indices)
|
|
||||||
|
|
||||||
blit_quad( & shaped.draw_list,
|
|
||||||
dst, dst + dst_scale,
|
|
||||||
slot_position, slot_position + glyph_scale )
|
|
||||||
end_index = cast(u32) len(shaped.draw_list.indices)
|
|
||||||
}
|
|
||||||
append( & shaped.draw_list.calls, call )
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Add the glyph drawcall
|
|
||||||
call := DrawCall_Default
|
|
||||||
{
|
|
||||||
using call
|
|
||||||
pass = .Target
|
|
||||||
colour = ctx.colour
|
|
||||||
start_index = cast(u32) len(ctx.draw_list.indices)
|
|
||||||
|
|
||||||
blit_quad( & ctx.draw_list,
|
|
||||||
dst, dst + dst_scale,
|
|
||||||
slot_position, slot_position + glyph_scale )
|
|
||||||
end_index = cast(u32) len(ctx.draw_list.indices)
|
|
||||||
}
|
|
||||||
append( & ctx.draw_list.calls, call )
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Constructs a triangle fan to fill a shape using the provided path
|
// Constructs a triangle fan to fill a shape using the provided path
|
||||||
// outside_point represents the center point of the fan.
|
// outside_point represents the center point of the fan.
|
||||||
//
|
//
|
||||||
@@ -551,49 +462,50 @@ draw_text_batch :: proc(ctx: ^Context, entry: ^Entry, shaped: ^ShapedText,
|
|||||||
|
|
||||||
for index := batch_start_idx; index < batch_end_idx; index += 1
|
for index := batch_start_idx; index < batch_end_idx; index += 1
|
||||||
{
|
{
|
||||||
glyph_index := shaped.glyphs[index]
|
glyph_index := shaped.glyphs[index]
|
||||||
|
|
||||||
if glyph_index == 0 || parser_is_glyph_empty( & entry.parser_info, glyph_index) do continue
|
if glyph_index == 0 || parser_is_glyph_empty( & entry.parser_info, glyph_index) do continue
|
||||||
|
|
||||||
region_kind, region, over_sample := decide_codepoint_region( ctx, entry, glyph_index )
|
region_kind, region, over_sample := decide_codepoint_region( ctx, entry, glyph_index )
|
||||||
lru_code := font_glyph_lru_code( entry.id, glyph_index )
|
lru_code := font_glyph_lru_code( entry.id, glyph_index )
|
||||||
atlas_index := region_kind != .E ? LRU_get( & region.state, lru_code ) : -1
|
atlas_index := region_kind != .E ? LRU_get( & region.state, lru_code ) : -1
|
||||||
bounds_0, bounds_1 := parser_get_glyph_box( & entry.parser_info, glyph_index )
|
bounds_0, bounds_1 := parser_get_glyph_box( & entry.parser_info, glyph_index )
|
||||||
vbounds_0 := vec2(bounds_0)
|
vbounds_0 := vec2(bounds_0)
|
||||||
vbounds_1 := vec2(bounds_1)
|
vbounds_1 := vec2(bounds_1)
|
||||||
bounds_size := Vec2 { vbounds_1.x - vbounds_0.x, vbounds_1.y - vbounds_0.y }
|
bounds_size := Vec2 { vbounds_1.x - vbounds_0.x, vbounds_1.y - vbounds_0.y }
|
||||||
|
|
||||||
shaped_position := shaped.positions[index]
|
shaped_position := shaped.positions[index]
|
||||||
glyph_translate := position + shaped_position * scale
|
glyph_translate := position + shaped_position * scale
|
||||||
|
|
||||||
if region_kind == .E
|
if region_kind == .E
|
||||||
{
|
{
|
||||||
directly_draw_massive_glyph(ctx, entry, glyph_index,
|
directly_draw_massive_glyph(ctx, entry, glyph_index,
|
||||||
vbounds_0, vbounds_1,
|
vbounds_0, vbounds_1,
|
||||||
bounds_size,
|
bounds_size,
|
||||||
over_sample, glyph_translate, scale )
|
over_sample, glyph_translate, scale )
|
||||||
}
|
}
|
||||||
else if atlas_index != -1
|
else if atlas_index != -1
|
||||||
{
|
{
|
||||||
slot_position, _ := atlas_bbox( atlas, region_kind, atlas_index )
|
// Draw cacxhed glyph
|
||||||
glyph_scale := bounds_size * entry.size_scale + glyph_padding
|
slot_position, _ := atlas_bbox( atlas, region_kind, atlas_index )
|
||||||
bounds_0_scaled := ceil( vbounds_0 * entry.size_scale )
|
glyph_scale := bounds_size * entry.size_scale + glyph_padding
|
||||||
dst := glyph_translate + (bounds_0_scaled - glyph_padding) * scale
|
bounds_0_scaled := ceil( vbounds_0 * entry.size_scale )
|
||||||
dst_scale := glyph_scale * scale
|
dst := glyph_translate + (bounds_0_scaled - glyph_padding) * scale
|
||||||
textspace_x_form( & slot_position, & glyph_scale, atlas_size )
|
dst_scale := glyph_scale * scale
|
||||||
|
textspace_x_form( & slot_position, & glyph_scale, atlas_size )
|
||||||
|
|
||||||
call := DrawCall_Default
|
call := DrawCall_Default
|
||||||
call.pass = .Target
|
call.pass = .Target
|
||||||
call.colour = ctx.colour
|
call.colour = ctx.colour
|
||||||
call.start_index = u32(len(ctx.draw_list.indices))
|
call.start_index = u32(len(ctx.draw_list.indices))
|
||||||
|
|
||||||
blit_quad(&ctx.draw_list,
|
blit_quad(&ctx.draw_list,
|
||||||
dst, dst + dst_scale,
|
dst, dst + dst_scale,
|
||||||
slot_position, slot_position + glyph_scale )
|
slot_position, slot_position + glyph_scale )
|
||||||
|
|
||||||
call.end_index = u32(len(ctx.draw_list.indices))
|
call.end_index = u32(len(ctx.draw_list.indices))
|
||||||
append(&ctx.draw_list.calls, call)
|
append(&ctx.draw_list.calls, call)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -23,10 +23,10 @@ import "core:mem"
|
|||||||
Arena :: mem.Arena
|
Arena :: mem.Arena
|
||||||
arena_allocator :: mem.arena_allocator
|
arena_allocator :: mem.arena_allocator
|
||||||
arena_init :: mem.arena_init
|
arena_init :: mem.arena_init
|
||||||
import "codebase:grime"
|
// import "codebase:grime"
|
||||||
log :: grime.log
|
// log :: grime.log
|
||||||
logf :: grime.logf
|
// logf :: grime.logf
|
||||||
profile :: grime.profile
|
// profile :: grime.profile
|
||||||
|
|
||||||
//#region("Proc overload mappings")
|
//#region("Proc overload mappings")
|
||||||
|
|
||||||
|
28
misc.odin
28
misc.odin
@@ -19,24 +19,24 @@ vec2i_from_vec2 :: #force_inline proc "contextless" ( v2 : Vec2 ) -> Vec2
|
|||||||
@(require_results) ceil_vec2 :: proc "contextless" ( v : Vec2 ) -> Vec2 { return { ceil_f32(v.x), ceil_f32(v.y) } }
|
@(require_results) ceil_vec2 :: proc "contextless" ( v : Vec2 ) -> Vec2 { return { ceil_f32(v.x), ceil_f32(v.y) } }
|
||||||
|
|
||||||
// This buffer is used below excluisvely to prevent any allocator recusion when verbose logging from allocators.
|
// This buffer is used below excluisvely to prevent any allocator recusion when verbose logging from allocators.
|
||||||
// This means a single line is limited to 32k buffer (increase naturally if this SOMEHOW becomes a bottleneck...)
|
// This means a single line is limited to 4k buffer
|
||||||
// Logger_Allocator_Buffer : [32 * Kilobyte]u8
|
Logger_Allocator_Buffer : [4 * Kilobyte]u8
|
||||||
|
|
||||||
// log :: proc( msg : string, level := core_log.Level.Info, loc := #caller_location ) {
|
log :: proc( msg : string, level := core_log.Level.Info, loc := #caller_location ) {
|
||||||
// temp_arena : Arena; arena_init(& temp_arena, Logger_Allocator_Buffer[:])
|
temp_arena : Arena; arena_init(& temp_arena, Logger_Allocator_Buffer[:])
|
||||||
// context.allocator = arena_allocator(& temp_arena)
|
context.allocator = arena_allocator(& temp_arena)
|
||||||
// context.temp_allocator = arena_allocator(& temp_arena)
|
context.temp_allocator = arena_allocator(& temp_arena)
|
||||||
|
|
||||||
// core_log.log( level, msg, location = loc )
|
core_log.log( level, msg, location = loc )
|
||||||
// }
|
}
|
||||||
|
|
||||||
// logf :: proc( fmt : string, args : ..any, level := core_log.Level.Info, loc := #caller_location ) {
|
logf :: proc( fmt : string, args : ..any, level := core_log.Level.Info, loc := #caller_location ) {
|
||||||
// temp_arena : Arena; arena_init(& temp_arena, Logger_Allocator_Buffer[:])
|
temp_arena : Arena; arena_init(& temp_arena, Logger_Allocator_Buffer[:])
|
||||||
// context.allocator = arena_allocator(& temp_arena)
|
context.allocator = arena_allocator(& temp_arena)
|
||||||
// context.temp_allocator = arena_allocator(& temp_arena)
|
context.temp_allocator = arena_allocator(& temp_arena)
|
||||||
|
|
||||||
// core_log.logf( level, fmt, ..args, location = loc )
|
core_log.logf( level, fmt, ..args, location = loc )
|
||||||
// }
|
}
|
||||||
|
|
||||||
reload_array :: proc( self : ^[dynamic]$Type, allocator : Allocator ) {
|
reload_array :: proc( self : ^[dynamic]$Type, allocator : Allocator ) {
|
||||||
raw := transmute( ^runtime.Raw_Dynamic_Array) self
|
raw := transmute( ^runtime.Raw_Dynamic_Array) self
|
||||||
|
@@ -73,8 +73,7 @@ parser_init :: proc( ctx : ^ParserContext )
|
|||||||
// assert( error == .None, "VEFontCache.parser_init: Failed to allocate fonts array" )
|
// assert( error == .None, "VEFontCache.parser_init: Failed to allocate fonts array" )
|
||||||
}
|
}
|
||||||
|
|
||||||
parser_shutdown :: proc( ctx : ^ParserContext )
|
parser_shutdown :: proc( ctx : ^ParserContext ) {
|
||||||
{
|
|
||||||
// TODO(Ed): Implement
|
// TODO(Ed): Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user