diff --git a/code/font/vefontcache/Readme.md b/code/font/vefontcache/Readme.md index b765e2e..9c97613 100644 --- a/code/font/vefontcache/Readme.md +++ b/code/font/vefontcache/Readme.md @@ -18,8 +18,8 @@ Features: * Clear the caches at any-time! * Robust quality of life features: * Tracks text layers! - * Push and pop stack for font, font_size, view, position, scale and zoom! - * Enforce even only font-sizing + * Push and pop stack for font, font_size, colour, view, position, scale and zoom! + * Enforce even only font-sizing [TODO] * Snap-positining to view for better hinting * Basic or advanced text shaping via Harfbuzz * All rendering is real-time, triangulation done on the CPU, vertex rendering and texture blitting on the gpu. diff --git a/code/font/vefontcache/draw.odin b/code/font/vefontcache/draw.odin index d5d3e64..d170d6b 100644 --- a/code/font/vefontcache/draw.odin +++ b/code/font/vefontcache/draw.odin @@ -2,8 +2,6 @@ package vetext /* Note(Ed): This may be seperated in the future into another file dedending on how much is involved with supportin ear-clipping triangulation. - - */ import "base:runtime" @@ -113,7 +111,12 @@ Glyph_Draw_Buffer :: struct{ // Contructs a quad mesh for bliting a texture from one render target (src uv0 & 1) to the destination rendertarget (p0, p1) @(optimization_mode="favor_size") -blit_quad :: #force_inline proc ( draw_list : ^Draw_List, p0 : Vec2 = {0, 0}, p1 : Vec2 = {1, 1}, uv0 : Vec2 = {0, 0}, uv1 : Vec2 = {1, 1} ) +blit_quad :: #force_inline proc ( draw_list : ^Draw_List, + p0 : Vec2 = {0, 0}, + p1 : Vec2 = {1, 1}, + uv0 : Vec2 = {0, 0}, + uv1 : Vec2 = {1, 1} +) { // profile(#procedure) v_offset := cast(u32) len(draw_list.vertices) @@ -250,7 +253,16 @@ generate_glyph_pass_draw_list :: proc(draw_list : ^Draw_List, path : ^[dynamic]V } // Just a warpper of generate_shape_draw_list for handling an array of shapes -generate_shapes_draw_list :: #force_inline proc ( ctx : ^Context, font : Font_ID, colour : RGBAN, entry : Entry, px_size, font_scale : f32, position, scale : Vec2, shapes : []Shaped_Text ) +generate_shapes_draw_list :: #force_inline proc ( ctx : ^Context, + font : Font_ID, + colour : RGBAN, + entry : Entry, + px_size : f32, + font_scale : f32, + position : Vec2, + scale : Vec2, + shapes : []Shaped_Text +) { assert(len(shapes) > 0) for shape in shapes { diff --git a/code/font/vefontcache/pkg_mapping.odin b/code/font/vefontcache/pkg_mapping.odin index aa73ce4..69a5b32 100644 --- a/code/font/vefontcache/pkg_mapping.odin +++ b/code/font/vefontcache/pkg_mapping.odin @@ -88,6 +88,11 @@ fill :: proc { slice.fill, } +max :: proc { + linalg.max_single, + linalg.max_double, +} + make :: proc { builtin.make_dynamic_array, builtin.make_dynamic_array_len, diff --git a/code/font/vefontcache/shaper.odin b/code/font/vefontcache/shaper.odin index fae97b5..bf5715e 100644 --- a/code/font/vefontcache/shaper.odin +++ b/code/font/vefontcache/shaper.odin @@ -22,11 +22,6 @@ Shape_Key :: u32 Ideally the user should resolve this shape once and cache/store it on their side. They have the best ability to avoid costly lookups to streamline a hot path to only focusing on draw list generation that must be computed every frame. - - For ease of use the cache does a relatively good job and only adds a - few hundred nano-seconds to resolve a shape's lookup from its source specification. - If your doing something very heavy though (tens-of thousands +) your not - going to be satisfied with keeping that in the iteration). */ Shaped_Text :: struct #packed { glyph : [dynamic]Glyph, @@ -36,6 +31,8 @@ Shaped_Text :: struct #packed { bounds : [dynamic]Range2, end_cursor_pos : Vec2, size : Vec2, + font_id : Font_ID, + // TODO(Ed): We need to track the font here for usage in user interface when directly drawing the shape. } // Ease of use cache, can handle thousands of lookups per frame with ease. diff --git a/code/font/vefontcache/vefontcache.odin b/code/font/vefontcache/vefontcache.odin index e495c58..572b879 100644 --- a/code/font/vefontcache/vefontcache.odin +++ b/code/font/vefontcache/vefontcache.odin @@ -104,7 +104,7 @@ Context :: struct { // the draw_list result by the same amount. px_scalar : f32, // Improves hinting, positioning, etc. Can make zoomed out text too jagged. - default_curve_quality : i32, + default_curve_quality : i32, } Init_Atlas_Params :: struct { @@ -336,6 +336,15 @@ startup :: proc( ctx : ^Context, parser_kind : Parser_Kind = .STB_TrueType, // N parser_init( & ctx.parser_ctx, parser_kind ) shaper_init( & ctx.shaper_ctx ) + + // Set the default stack values + // Will be popped on shutdown + // push_colour(ctx, {1, 1, 1, 1}) + // push_font_size(ctx, 36) + // push_view(ctx, { 0, 0 }) + // push_position(ctx, {0, 0}) + // push_scale(ctx, 1.0) + // push_zoom(ctx, 1.0) } hot_reload :: proc( ctx : ^Context, allocator : Allocator ) @@ -399,6 +408,13 @@ shutdown :: proc( ctx : ^Context ) shape_cache := & ctx.shape_cache draw_list := & ctx.draw_list + // pop_colour(ctx) + // pop_font_size(ctx) + // pop_view(ctx) + // pop_position(ctx) + // pop_scale(ctx) + // pop_zoom(ctx) + for & entry in ctx.entries { unload_font( ctx, entry.id ) } @@ -544,12 +560,6 @@ unload_font :: proc( ctx : ^Context, font : Font_ID ) //#region("scoping") -configure_snap :: #force_inline proc( ctx : ^Context, snap_width, snap_height : u32 ) { - assert( ctx != nil ) - ctx.snap_width = f32(snap_width) - ctx.snap_height = f32(snap_height) -} - /* Scope stacking ease of use interface. View: Extents in 2D for the relative space the the text is being drawn within. @@ -593,7 +603,7 @@ auto_pop_position :: #force_inline proc( ctx : ^Context, view : Vec2 ) @(deferred_in = auto_pop_scale) scope_scale :: #force_inline proc( ctx : ^Context, scale : Vec2 ) { assert(ctx != nil); append(& ctx.stack.scale, scale ) } push_scale :: #force_inline proc( ctx : ^Context, scale : Vec2 ) { assert(ctx != nil); append(& ctx.stack.scale, scale ) } -pop_scale :: #force_inline proc( ctx : ^Context, scale : Vec2 ) { assert(ctx != nil); pop(& ctx.stack.scale) } +pop_scale :: #force_inline proc( ctx : ^Context, ) { assert(ctx != nil); pop(& ctx.stack.scale) } auto_pop_scale :: #force_inline proc( ctx : ^Context, scale : Vec2 ) { assert(ctx != nil); pop(& ctx.stack.scale) } @(deferred_in = auto_pop_zoom ) @@ -635,19 +645,21 @@ auto_pop_vpz :: #force_inline proc( ctx : ^Context, camera : VPZ_Transform ) { get_cursor_pos :: #force_inline proc "contextless" ( ctx : Context ) -> Vec2 { return ctx.cursor_pos } // Does nothing when view is 1 or 0. -get_snapped_position :: #force_inline proc "contextless" ( ctx : Context, position : Vec2 ) -> (snapped_position : Vec2) { - snap_width := max(ctx.snap_width, 1) - snap_height := max(ctx.snap_height, 1) - snap_quotient := 1 / Vec2 { snap_width, snap_height } +get_snapped_position :: #force_inline proc "contextless" ( position : Vec2, view : Vec2 ) -> (snapped_position : Vec2) { + snap_quotient := 1 / Vec2 { max(view.x, 1), max(view.y, 1) } + should_snap := view * snap_quotient snapped_position = position - snapped_position.x = ceil(position.x * snap_width ) * snap_quotient.x - snapped_position.y = ceil(position.y * snap_height) * snap_quotient.y - return + snapped_position.x = ceil(position.x * view.x) * snap_quotient.x + snapped_position.y = ceil(position.y * view.y) * snap_quotient.y + snapped_position *= should_snap + snapped_position.x = max(snapped_position.x, position.x) + snapped_position.y = max(snapped_position.y, position.y) + return snapped_position } -set_alpha_scalar :: #force_inline proc( ctx : ^Context, scalar : f32 ) { assert(ctx != nil); ctx.alpha_sharpen = scalar } -set_colour :: #force_inline proc( ctx : ^Context, colour : RGBAN ) { assert(ctx != nil); ctx.colour = colour } -set_px_scalar :: #force_inline proc( ctx : ^Context, scalar : f32 ) { assert(ctx != nil); ctx.px_scalar = scalar } +set_alpha_scalar :: #force_inline proc( ctx : ^Context, scalar : f32 ) { assert(ctx != nil); ctx.alpha_sharpen = scalar } +set_colour :: #force_inline proc( ctx : ^Context, colour : RGBAN ) { assert(ctx != nil); ctx.colour = colour } +set_px_scalar :: #force_inline proc( ctx : ^Context, scalar : f32 ) { assert(ctx != nil); ctx.px_scalar = scalar } set_snap_glyph_shape_position :: #force_inline proc( ctx : ^Context, should_snap : b32 ) { assert(ctx != nil) @@ -661,7 +673,6 @@ set_snap_glyph_render_height :: #force_inline proc( ctx : ^Context, should_snap // Non-scoping context. The most fundamental interface-level draw shape procedure. // (everything else is either batching/pipelining or quality of life warppers) -// Note: Prefer over draw_text_normalized_space if possible to resolve shape once persistently or at least once per frame or non-dirty state. @(optimization_mode="favor_size") draw_text_shape_normalized_space :: #force_inline proc( ctx : ^Context, font : Font_ID, @@ -670,7 +681,7 @@ draw_text_shape_normalized_space :: #force_inline proc( ctx : ^Context, view : Vec2, position : Vec2, scale : Vec2, - zoom : f32, + zoom : f32, // TODO(Ed): Implement zoom support shape : Shaped_Text ) { @@ -678,15 +689,13 @@ draw_text_shape_normalized_space :: #force_inline proc( ctx : ^Context, assert( ctx != nil ) assert( font >= 0 && int(font) < len(ctx.entries) ) - adjusted_position := get_snapped_position( ctx^, position ) + adjusted_position := get_snapped_position( position, view ) entry := ctx.entries[ font ] adjusted_colour := colour adjusted_colour.a = 1.0 + ctx.alpha_sharpen - font_scale := parser_scale( entry.parser_info, px_size ) - target_px_size := px_size * ctx.px_scalar target_scale := scale * (1 / ctx.px_scalar) target_font_scale := parser_scale( entry.parser_info, target_px_size ) @@ -704,15 +713,15 @@ draw_text_shape_normalized_space :: #force_inline proc( ctx : ^Context, // Non-scoping context. The most fundamental interface-level draw text procedure. // (everything else is either batching/pipelining or quality of life warppers) -// Note: shape lookup can be expensive on high call usage. -draw_text_normalized_space :: #force_inline proc( ctx : ^Context, +@(optimization_mode = "favor_size") +draw_text_normalized_space :: proc( ctx : ^Context, font : Font_ID, px_size : f32, colour : RGBAN, view : Vec2, position : Vec2, scale : Vec2, - zoom : f32, + zoom : f32, // TODO(Ed): Implement Zoom support text_utf8 : string ) { @@ -720,15 +729,14 @@ draw_text_normalized_space :: #force_inline proc( ctx : ^Context, assert( ctx != nil ) assert( font >= 0 && int(font) < len(ctx.entries) ) assert( len(text_utf8) > 0 ) - assert( ctx.snap_width > 0 && ctx.snap_height > 0 ) ctx.cursor_pos = {} entry := ctx.entries[ font ] - adjusted_position := get_snapped_position( ctx^, position ) + adjusted_position := get_snapped_position( position, view ) - colour := ctx.colour - colour.a = 1.0 + ctx.alpha_sharpen + adjusted_colour := colour + adjusted_colour.a = 1.0 + ctx.alpha_sharpen // Does nothing when px_scalar is 1.0 target_px_size := px_size * ctx.px_scalar @@ -744,7 +752,7 @@ draw_text_normalized_space :: #force_inline proc( ctx : ^Context, ) ctx.cursor_pos = generate_shape_draw_list( & ctx.draw_list, shape, & ctx.atlas, & ctx.glyph_buffer, ctx.px_scalar, - colour, + adjusted_colour, entry, target_px_size, target_font_scale, @@ -753,88 +761,210 @@ draw_text_normalized_space :: #force_inline proc( ctx : ^Context, ) } -draw_shape :: #force_inline proc( ctx : ^Context, position, scale : Vec2, shape : Shaped_Text ) { - // peek_position -} - -draw_text :: #force_inline proc( ctx : ^Context, text_utf8 : string, position, scale : Vec2 ) { - -} - -Text_Layer_Elem :: struct { - text : string, +// Equivalent to draw_text_shape_normalized_space, however position's units is scaled to view and must be normalized. +@(optimization_mode="favor_size") +draw_text_shape_view_space :: #force_inline proc( ctx : ^Context, + font : Font_ID, + px_size : f32, + colour : RGBAN, view : Vec2, position : Vec2, - scale : Vec2, - font : Font_ID, - px_size : f32, - zoom : f32, - colour : RGBAN, -} - -// Batch a layer of text. Use get_draw_list_layer to process the layer immediately after. -draw_text_layer :: #force_inline proc( ctx : ^Context, layer : []Text_Layer_Elem ) + scale : Vec2, + zoom : f32, // TODO(Ed): Implement zoom support + shape : Shaped_Text +) { profile(#procedure) assert( ctx != nil ) - assert( len(layer) > 0 ) + assert( font >= 0 && int(font) < len(ctx.entries) ) - shapes := make( []Shaped_Text, len(layer) ) - for elem in layer - { - assert( elem.font >= 0 && int(elem.font) < len(ctx.entries) ) + norm_position := position * (1 / view) - for elem, id in layer - { - entry := ctx.entries[ elem.font ] + view := view; view.x = max(view.x, 1); view.y = max(view.y, 1) + adjusted_position := get_snapped_position( norm_position, view ) - ctx.cursor_pos = {} + entry := ctx.entries[ font ] - // colour := ctx.colour - // colour.a = 1.0 + ctx.alpha_sharpen + adjusted_colour := colour + adjusted_colour.a = 1.0 + ctx.alpha_sharpen - // adjusted_position := get_snapped_position( ctx^, elem.position ) + target_px_size := px_size * ctx.px_scalar + target_scale := scale * (1 / ctx.px_scalar) + target_font_scale := parser_scale( entry.parser_info, target_px_size ) - // font_scale := parser_scale( entry.parser_info, elem.px_size ) + ctx.cursor_pos = generate_shape_draw_list( & ctx.draw_list, shape, & ctx.atlas, & ctx.glyph_buffer, + ctx.px_scalar, + adjusted_colour, + entry, + target_px_size, + target_font_scale, + position, + target_scale, + ) +} - target_px_size := elem.px_size * ctx.px_scalar - // target_scale := elem.scale * (1 / ctx.px_scalar) - target_font_scale := parser_scale( entry.parser_info, target_px_size ) +// Equivalent to draw_text_normalized_space, however position's units is scaled to view and must be normalized. +@(optimization_mode = "favor_size") +draw_text_view_space :: proc(ctx : ^Context, + font : Font_ID, + px_size : f32, + colour : RGBAN, + view : Vec2, + view_position : Vec2, + scale : Vec2, + zoom : f32, // TODO(Ed): Implement Zoom support + text_utf8 : string +) +{ + profile(#procedure) + assert( ctx != nil ) + assert( font >= 0 && int(font) < len(ctx.entries) ) + assert( len(text_utf8) > 0 ) - assert( len(elem.text) > 0 ) - shape := shaper_shape_text_cached( elem.text, - & ctx.shaper_ctx, - & ctx.shape_cache, - ctx.atlas, - vec2(ctx.glyph_buffer.size), - elem.font, - entry, - target_px_size, - target_font_scale, - shaper_shape_text_uncached_advanced - ) - shapes[id] = shape - } - } + ctx.cursor_pos = {} + entry := ctx.entries[ font ] - for elem, id in layer { - entry := ctx.entries[ elem.font ] + norm_position := view_position * (1 / view) - ctx.cursor_pos = {} + adjusted_position := get_snapped_position( norm_position, view ) - colour := ctx.colour - colour.a = 1.0 + ctx.alpha_sharpen + adjusted_colour := colour + adjusted_colour.a = 1.0 + ctx.alpha_sharpen - adjusted_position := get_snapped_position( ctx^, elem.position ) + // Does nothing when px_scalar is 1.0 + target_px_size := px_size * ctx.px_scalar + target_scale := scale * (1 / ctx.px_scalar) + target_font_scale := parser_scale( entry.parser_info, target_px_size ) - // font_scale := parser_scale( entry.parser_info, elem.px_size ) + shape := shaper_shape_text_cached( text_utf8, & ctx.shaper_ctx, & ctx.shape_cache, ctx.atlas, vec2(ctx.glyph_buffer.size), + font, + entry, + target_px_size, + target_font_scale, + shaper_shape_text_uncached_advanced + ) + ctx.cursor_pos = generate_shape_draw_list( & ctx.draw_list, shape, & ctx.atlas, & ctx.glyph_buffer, + ctx.px_scalar, + adjusted_colour, + entry, + target_px_size, + target_font_scale, + adjusted_position, + target_scale, + ) +} - target_px_size := elem.px_size * ctx.px_scalar - target_scale := elem.scale * (1 / ctx.px_scalar) - target_font_scale := parser_scale( entry.parser_info, target_px_size ) +@(optimization_mode = "favor_size") +draw_shape :: proc( ctx : ^Context, position, scale : Vec2, shape : Shaped_Text ) +{ + profile(#procedure) + assert( ctx != nil ) - generate_shapes_draw_list(ctx, elem.font, elem.colour, entry, target_px_size, target_font_scale, adjusted_position, target_scale, shapes ) - } + stack := & ctx.stack + assert(len(stack.font) > 0) + assert(len(stack.view) > 0) + assert(len(stack.colour) > 0) + assert(len(stack.position) > 0) + assert(len(stack.scale) > 0) + assert(len(stack.font_size) > 0) + assert(len(stack.zoom) > 0) + + // TODO(Ed): This should be taken from the shape instead (you cannot use a different font with a shape) + font := peek(stack.font) + assert( font >= 0 &&int(font) < len(ctx.entries) ) + + view := peek(stack.view); + + ctx.cursor_pos = {} + entry := ctx.entries[ font ] + + adjusted_colour := peek(stack.colour) + adjusted_colour.a = 1.0 + ctx.alpha_sharpen + + // TODO(Ed): Implement zoom for draw_text + zoom := peek(stack.zoom) + + absolute_position := peek(stack.position) + position + absolute_scale := peek(stack.scale) * scale + + adjusted_position := get_snapped_position( absolute_position, view ) + + px_size := peek(stack.font_size) + + // Does nothing when px_scalar is 1.0 + target_px_size := px_size * ctx.px_scalar + target_scale := absolute_scale * (1 / ctx.px_scalar) + target_font_scale := parser_scale( entry.parser_info, target_px_size ) + + ctx.cursor_pos = generate_shape_draw_list( & ctx.draw_list, shape, & ctx.atlas, & ctx.glyph_buffer, + ctx.px_scalar, + adjusted_colour, + entry, + target_px_size, + target_font_scale, + adjusted_position, + target_scale, + ) +} + +@(optimization_mode = "favor_size") +draw_text :: proc( ctx : ^Context, position, scale : Vec2, text_utf8 : string ) +{ + profile(#procedure) + assert( ctx != nil ) + assert( len(text_utf8) > 0 ) + + stack := & ctx.stack + assert(len(stack.font) > 0) + assert(len(stack.view) > 0) + assert(len(stack.colour) > 0) + assert(len(stack.position) > 0) + assert(len(stack.scale) > 0) + assert(len(stack.font_size) > 0) + assert(len(stack.zoom) > 0) + + font := peek(stack.font) + assert( font >= 0 &&int(font) < len(ctx.entries) ) + + view := peek(stack.view); + + ctx.cursor_pos = {} + entry := ctx.entries[ font ] + + adjusted_colour := peek(stack.colour) + adjusted_colour.a = 1.0 + ctx.alpha_sharpen + + // TODO(Ed): Implement zoom for draw_text + zoom := peek(stack.zoom) + + absolute_position := peek(stack.position) + position + absolute_scale := peek(stack.scale) * scale + + adjusted_position := get_snapped_position( absolute_position, view ) + + px_size := peek(stack.font_size) + + // Does nothing when px_scalar is 1.0 + target_px_size := px_size * ctx.px_scalar + target_scale := absolute_scale * (1 / ctx.px_scalar) + target_font_scale := parser_scale( entry.parser_info, target_px_size ) + + shape := shaper_shape_text_cached( text_utf8, & ctx.shaper_ctx, & ctx.shape_cache, ctx.atlas, vec2(ctx.glyph_buffer.size), + font, + entry, + target_px_size, + target_font_scale, + shaper_shape_text_uncached_advanced + ) + ctx.cursor_pos = generate_shape_draw_list( & ctx.draw_list, shape, & ctx.atlas, & ctx.glyph_buffer, + ctx.px_scalar, + adjusted_colour, + entry, + target_px_size, + target_font_scale, + adjusted_position, + target_scale, + ) } get_draw_list :: #force_inline proc( ctx : ^Context, optimize_before_returning := true ) -> ^Draw_List { @@ -889,11 +1019,9 @@ measure_text_size :: #force_inline proc( ctx : ^Context, font : Font_ID, px_size entry := ctx.entries[font] - font_scale := parser_scale( entry.parser_info, px_size ) - - downscale := 1 / ctx.px_scalar - px_size_upscaled := px_size * ctx.px_scalar - font_scale_upscaled := parser_scale( entry.parser_info, px_size_upscaled ) + downscale := 1 / ctx.px_scalar + target_px_size := px_size * ctx.px_scalar + target_font_scale := parser_scale( entry.parser_info, target_px_size ) shaped := shaper_shape_text_cached( text_utf8, & ctx.shaper_ctx, @@ -902,8 +1030,8 @@ measure_text_size :: #force_inline proc( ctx : ^Context, font : Font_ID, px_size vec2(ctx.glyph_buffer.size), font, entry, - px_size_upscaled, - font_scale_upscaled, + target_px_size, + target_font_scale, shaper_shape_text_uncached_advanced ) return shaped.size * downscale @@ -934,10 +1062,8 @@ shape_text_latin :: #force_inline proc( ctx : ^Context, font : Font_ID, px_size assert( len(text_utf8) > 0 ) entry := ctx.entries[ font ] - font_scale := parser_scale( entry.parser_info, px_size ) - - px_size_upscaled := px_size * ctx.px_scalar - font_scale_upscaled := parser_scale( entry.parser_info, px_size_upscaled ) + target_px_size := px_size * ctx.px_scalar + target_font_scale := parser_scale( entry.parser_info, target_px_size ) return shaper_shape_text_cached( text_utf8, & ctx.shaper_ctx, @@ -946,8 +1072,8 @@ shape_text_latin :: #force_inline proc( ctx : ^Context, font : Font_ID, px_size vec2(ctx.glyph_buffer.size), font, entry, - px_size_upscaled, - font_scale_upscaled, + target_px_size, + target_font_scale, shaper_shape_text_latin ) } @@ -958,10 +1084,8 @@ shape_text_advanced :: #force_inline proc( ctx : ^Context, font : Font_ID, px_si assert( len(text_utf8) > 0 ) entry := ctx.entries[ font ] - font_scale := parser_scale( entry.parser_info, px_size ) - - px_size_upscaled := px_size * ctx.px_scalar - font_scale_upscaled := parser_scale( entry.parser_info, px_size_upscaled ) + target_px_size := px_size * ctx.px_scalar + target_font_scale := parser_scale( entry.parser_info, target_px_size ) return shaper_shape_text_cached( text_utf8, & ctx.shaper_ctx, @@ -970,25 +1094,55 @@ shape_text_advanced :: #force_inline proc( ctx : ^Context, font : Font_ID, px_si vec2(ctx.glyph_buffer.size), font, entry, - px_size_upscaled, - font_scale_upscaled, + target_px_size, + target_font_scale, shaper_shape_text_uncached_advanced ) } // User handled shaped text. Will not be cached // @(disabled = true) -shape_text_latin_uncached :: #force_inline proc( ctx : ^Context, font : Font_ID, text_utf8 : string, entry : ^Entry, shape : ^Shaped_Text ) +shape_text_latin_uncached :: #force_inline proc( ctx : ^Context, font : Font_ID, px_size: f32, text_utf8 : string, shape : ^Shaped_Text ) { - assert(false) + profile(#procedure) + assert( len(text_utf8) > 0 ) + entry := ctx.entries[ font ] + + target_px_size := px_size * ctx.px_scalar + target_font_scale := parser_scale( entry.parser_info, target_px_size ) + + shaper_shape_text_latin(& ctx.shaper_ctx, + ctx.atlas, + vec2(ctx.glyph_buffer.size), + entry, + target_px_size, + target_font_scale, + text_utf8, + shape + ) return } // User handled shaped text. Will not be cached // @(disabled = true) -shape_text_advanced_uncahed :: #force_inline proc( ctx : ^Context, font : Font_ID, text_utf8 : string, entry : ^Entry, shape : ^Shaped_Text ) +shape_text_advanced_uncached :: #force_inline proc( ctx : ^Context, font : Font_ID, px_size: f32, text_utf8 : string, shape : ^Shaped_Text ) { - assert(false) + profile(#procedure) + assert( len(text_utf8) > 0 ) + entry := ctx.entries[ font ] + + target_px_size := px_size * ctx.px_scalar + target_font_scale := parser_scale( entry.parser_info, target_px_size ) + + shaper_shape_text_uncached_advanced(& ctx.shaper_ctx, + ctx.atlas, + vec2(ctx.glyph_buffer.size), + entry, + target_px_size, + target_font_scale, + text_utf8, + shape + ) return } diff --git a/code/sectr/engine/client_api.odin b/code/sectr/engine/client_api.odin index 2fe47cf..ba456d8 100644 --- a/code/sectr/engine/client_api.odin +++ b/code/sectr/engine/client_api.odin @@ -156,7 +156,7 @@ startup :: proc( prof : ^SpallProfiler, persistent_mem, frame_mem, transient_mem text_snap_glyph_shape_position = false text_snap_glyph_render_height = false text_size_screen_scalar = 2 - text_size_canvas_scalar = 0.2 + text_size_canvas_scalar = 2 text_alpha_sharpen = 0.1 } diff --git a/code/sectr/engine/render.odin b/code/sectr/engine/render.odin index b181ac5..b1bf85d 100644 --- a/code/sectr/engine/render.odin +++ b/code/sectr/engine/render.odin @@ -56,9 +56,10 @@ render_mode_2d_workspace :: proc( screen_extent : Vec2, cam : Camera, input : In cam_zoom_ratio := 1.0 / cam.zoom screen_size := screen_extent * 2 - // TODO(Ed): Eventually will be the viewport extents font_provider_set_px_scalar( app_config().text_size_canvas_scalar ) - ve.configure_snap( ve_ctx, u32(screen_size.x), u32(screen_size.y) ) + + // TODO(Ed): Eventually will be the viewport extents + // ve.configure_snap( ve_ctx, u32(screen_size.x), u32(screen_size.y) ) // ve.configure_snap( ve_ctx, 0, 0 ) Render_Debug: @@ -124,7 +125,7 @@ render_mode_screenspace :: proc( screen_extent : Extents2, screen_ui : ^UI_State screen_ratio := screen_size.x * ( 1.0 / screen_size.y ) font_provider_set_px_scalar( app_config().text_size_screen_scalar ) - ve.configure_snap( ve_ctx, u32(screen_size.x), u32(screen_size.y) ) + // ve.configure_snap( ve_ctx, u32(screen_size.x), u32(screen_size.y) ) render_screen_ui( screen_extent, screen_ui, ve_ctx, ve_render ) @@ -908,26 +909,29 @@ draw_rect_rounded_border :: proc(rect: Range2, radii: [4]f32, border_width: f32, // Draw text using a string and normalized render coordinates draw_text_string_pos_norm :: #force_inline proc( text : string, id : FontID, font_size : f32, pos : Vec2, color := Color_White, scale : f32 = 1.0 ) { - state := get_state(); using state - width := app_window.extent.x * 2 - height := app_window.extent.y * 2 - - // over_sample : f32 = f32(config.font_size_screen_scalar) + screen_extent := get_state().app_window.extent // TODO(Ed): Pass this in instead.. + screen_size := screen_extent * 2 target_size := font_size - // target_size *= over_sample ve_id, resolved_size := font_provider_resolve_draw_id( id, target_size ) color_norm := normalize_rgba8(color) - screen_size_norm := 1 / Vec2 { width, height } + screen_size_norm := 1 / screen_size + draw_scale := screen_size_norm * scale - draw_scale := screen_size_norm * scale - // draw_scale /= over_sample - - // ve.set_px_scalar( & font_provider_ctx.ve_ctx, config.font_size_screen_scalar ) - ve.set_colour( & font_provider_ctx.ve_ctx, color_norm ) - ve.draw_text_normalized_space( & font_provider_ctx.ve_ctx, ve_id, f32(resolved_size), color_norm, {}, pos, draw_scale, 1.0, text ) + ve_ctx := & get_state().font_provider_ctx.ve_ctx + ve.set_colour(ve_ctx, color_norm ) + ve.draw_text_normalized_space(ve_ctx, + ve_id, + f32(resolved_size), + color_norm, + screen_size, + pos, + draw_scale, + 1.0, + text + ) return } @@ -935,8 +939,8 @@ draw_text_string_pos_norm :: #force_inline proc( text : string, id : FontID, fon draw_text_string_pos_extent :: #force_inline proc( text : string, id : FontID, font_size : f32, pos : Vec2, color := Color_White ) { profile(#procedure) - state := get_state(); using state - screen_size := app_window.extent * 2 + screen_extent := get_state().app_window.extent // TODO(Ed): Pass this in instead.. + screen_size := screen_extent * 2 render_pos := screen_to_render_pos(pos) normalized_pos := render_pos * (1.0 / screen_size) @@ -1002,7 +1006,7 @@ draw_text_string_pos_extent_zoomed :: #force_inline proc( text : string, id : Fo ve_id, f32(resolved_size), color_norm, - {}, + screen_size, normalized_pos, text_scale, 1.0, @@ -1043,7 +1047,16 @@ draw_text_shape_pos_extent_zoomed :: #force_inline proc( shape : ShapedText, id color_norm := normalize_rgba8(color) // ve.set_px_scalar( & get_state().font_provider_ctx.ve_ctx, config.font_size_canvas_scalar ) ve.set_colour( & font_provider_ctx.ve_ctx, color_norm ) - ve.draw_text_shape_normalized_space( & font_provider_ctx.ve_ctx, ve_id, f32_resolved_size, color_norm, {}, normalized_pos, text_scale, 1.0, shape ) + ve.draw_text_shape_normalized_space( & font_provider_ctx.ve_ctx, + ve_id, + f32_resolved_size, + color_norm, + screen_size, + normalized_pos, + text_scale, + 1.0, + shape + ) } // TODO(Ed): Eventually the workspace will need a viewport for drawing text