diff --git a/code/font/VEFontCache/LRU.odin b/code/font/VEFontCache/LRU.odin index 35ff834..0ad43cc 100644 --- a/code/font/VEFontCache/LRU.odin +++ b/code/font/VEFontCache/LRU.odin @@ -110,9 +110,6 @@ pool_list_erase :: proc( pool : ^PoolList, iter : PoolListIter ) iter_node.prev = -1 iter_node.next = -1 - // if pool.dbg_name != "" { - // logf("pool_list: erased %v, at id %v", iter_node.value, iter) - // } iter_node.value = 0 append( & free_list, iter ) @@ -179,13 +176,6 @@ LRU_hash_key :: #force_inline proc( key : u64 ) -> ( hash : u64 ) { } LRU_find :: #force_inline proc "contextless" ( cache : ^LRU_Cache, key : u64, must_find := false ) -> (LRU_Link, bool) { - // hash := LRU_hash_key( key ) - // link := get( cache.table, hash ) - // if link == nil && must_find { - // runtime.debug_trap() - // link = get( cache.table, hash ) - // } - link, success := cache.table[key] return link, success } @@ -218,7 +208,6 @@ LRU_peek :: #force_inline proc ( cache : ^LRU_Cache, key : u64, must_find := fal LRU_put :: #force_inline proc ( cache : ^LRU_Cache, key : u64, value : i32 ) -> u64 { - // hash_key := LRU_hash_key( key ) iter, success := cache.table[key] if success { LRU_refresh( cache, key ) @@ -229,20 +218,11 @@ LRU_put :: #force_inline proc ( cache : ^LRU_Cache, key : u64, value : i32 ) -> evict := key if cache.key_queue.size >= cache.capacity { evict = pool_list_pop_back( & cache.key_queue ) - - // evict_hash := LRU_hash_key( evict ) - // if cache.table.dbg_name != "" { - // logf("%v: Evicted %v with hash: %v", cache.table.dbg_name, evict, evict_hash) - // } delete_key( & cache.table, evict ) cache.num -= 1 } pool_list_push_front( & cache.key_queue, key ) - // if cache.table.dbg_name != "" { - // logf("%v: Pushed %v with hash: %v", cache.table.dbg_name, key, hash_key ) - // } - cache.table[key] = LRU_Link { value = value, ptr = cache.key_queue.front @@ -253,9 +233,6 @@ LRU_put :: #force_inline proc ( cache : ^LRU_Cache, key : u64, value : i32 ) -> LRU_refresh :: proc( cache : ^LRU_Cache, key : u64 ) { link, success := LRU_find( cache, key ) - // if cache.table.dbg_name != "" { - // logf("%v: Refreshed %v", cache.table.dbg_name, key) - // } pool_list_erase( & cache.key_queue, link.ptr ) pool_list_push_front( & cache.key_queue, key ) link.ptr = cache.key_queue.front diff --git a/code/font/VEFontCache/Readme.md b/code/font/VEFontCache/Readme.md index 44c6ea8..05f7611 100644 --- a/code/font/VEFontCache/Readme.md +++ b/code/font/VEFontCache/Readme.md @@ -4,6 +4,8 @@ This is a port of the library base on [fork](https://github.com/hypernewbie/VEFo Its original purpose was for use in game engines, however its rendeirng quality and performance is more than adequate for many other applications. +See: [docs/Readme.md](docs/Readme.md) for the library's interface + TODO (Making it a more idiomatic library): * Setup freetype, harfbuzz, depedency management within the library @@ -25,7 +27,3 @@ TODO Additional Features: * Ability to set a draw transform, viewport and projection * By default the library's position is in unsigned normalized render space * Allow curve_quality to be set on a per-font basis - -TODO Optimizations: - -* Support more granular handling of shapes by chunking any text from draw_text into visible and whitespace/formatting diff --git a/code/font/VEFontCache/VEFontCache.odin b/code/font/VEFontCache/VEFontCache.odin index b35bc32..e5682c0 100644 --- a/code/font/VEFontCache/VEFontCache.odin +++ b/code/font/VEFontCache/VEFontCache.odin @@ -21,9 +21,10 @@ Vec2 :: [2]f32 Vec2i :: [2]i32 Vec2_64 :: [2]f64 -vec2_from_scalar :: #force_inline proc "contextless" ( scalar : f32 ) -> Vec2 { return { scalar, scalar } } +vec2_from_scalar :: #force_inline proc "contextless" ( scalar : f32 ) -> Vec2 { return { scalar, scalar }} vec2_64_from_vec2 :: #force_inline proc "contextless" ( v2 : Vec2 ) -> Vec2_64 { return { f64(v2.x), f64(v2.y) }} -vec2_from_vec2i :: #force_inline proc( v2i : Vec2i ) -> Vec2 { return { f32(v2i.x), f32(v2i.y) }} +vec2_from_vec2i :: #force_inline proc "contextless" ( v2i : Vec2i ) -> Vec2 { return { f32(v2i.x), f32(v2i.y) }} +vec2i_from_vec2 :: #force_inline proc "contextless" ( v2 : Vec2 ) -> Vec2i { return { i32(v2.x), i32(v2.y) }} FontID :: distinct i64 Glyph :: distinct i32 @@ -131,7 +132,7 @@ InitGlyphDrawParams :: struct { } InitGlyphDrawParams_Default :: InitGlyphDrawParams { - over_sample = { 4, 4 }, + over_sample = { 8, 8 }, buffer_batch = 4, draw_padding = InitAtlasParams_Default.glyph_padding, } @@ -362,7 +363,6 @@ load_font :: proc( ctx : ^Context, label : string, data : []byte, size_px : f32 size_scale = size_px < 0.0 ? \ parser_scale_for_pixel_height( & parser_info, -size_px ) \ : parser_scale_for_mapping_em_to_pixels( & parser_info, size_px ) - // size_scale = 1.0 used = true @@ -429,91 +429,11 @@ draw_text :: proc( ctx : ^Context, font : FontID, text_utf8 : string, position : text_utf8_bytes := transmute([]u8) text_utf8 text_chunk : string - Text_As_Shape :: true - when Text_As_Shape - { - text_chunk = transmute(string) text_utf8_bytes[ : ] - if len(text_chunk) > 0 { - 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 ) - } + text_chunk = transmute(string) text_utf8_bytes[ : ] + if len(text_chunk) > 0 { + 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 ) } - else - { - last_byte_offset : int = 0 - byte_offset : int = 0 - for codepoint, offset in text_utf8 - { - Rune_Space :: ' ' - Rune_Tab :: '\t' - Rune_Carriage_Return :: '\r' - Rune_Line_Feed :: '\n' - // Rune_Tab_Vertical :: '\v' - - byte_offset = offset - - switch codepoint - { - case Rune_Space: fallthrough - case Rune_Tab: fallthrough - case Rune_Line_Feed: fallthrough - case Rune_Carriage_Return: - if chunk_kind == .Formatting - { - chunk_end = byte_offset - last_byte_offset = byte_offset - } - else - { - text_chunk = transmute(string) text_utf8_bytes[ chunk_start : byte_offset] - if len(text_chunk) > 0 { - 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 ) - } - - chunk_start = byte_offset - chunk_end = chunk_start - chunk_kind = .Formatting - - last_byte_offset = byte_offset - continue - } - } - - // Visible Chunk - if chunk_kind == .Visible { - chunk_end = byte_offset - last_byte_offset = byte_offset - } - else - { - text_chunk = transmute(string) text_utf8_bytes[ chunk_start : byte_offset ] - if len(text_chunk) > 0 { - 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 ) - } - - chunk_start = byte_offset - chunk_end = chunk_start - chunk_kind = .Visible - - last_byte_offset = byte_offset - } - } - - text_chunk = transmute(string) text_utf8_bytes[ chunk_start : ] - if len(text_chunk) > 0 { - 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 ) - } - - chunk_start = byte_offset - chunk_end = chunk_start - chunk_kind = .Visible - - last_byte_offset = byte_offset - } - return true } diff --git a/code/font/VEFontCache/draw.odin b/code/font/VEFontCache/draw.odin index 67e1494..0f74e03 100644 --- a/code/font/VEFontCache/draw.odin +++ b/code/font/VEFontCache/draw.odin @@ -87,8 +87,6 @@ blit_quad :: proc( draw_list : ^DrawList, p0 : Vec2 = {0, 0}, p1 : Vec2 = {1, 1} for index : i32 = 0; index < 6; index += 1 { append( & draw_list.indices, v_offset + quad_indices[ index ] ) } - // draw_list_vert_slice := array_to_slice(draw_list.vertices) - // draw_list_index_slice := array_to_slice(draw_list.indices) return } @@ -100,9 +98,6 @@ cache_glyph :: proc( ctx : ^Context, font : FontID, glyph_index : Glyph, entry : return false } - // No shpae to retrieve - // if parser_is_glyph_empty( & entry.parser_info, glyph_index ) do return true - // Retrieve the shape definition from the parser. shape, error := parser_get_glyph_shape( & entry.parser_info, glyph_index ) assert( error == .None ) @@ -228,8 +223,10 @@ cache_glyph_to_atlas :: proc( ctx : ^Context, // Get hb_font text metrics. These are unscaled! bounds_0, bounds_1 := parser_get_glyph_box( & entry.parser_info, glyph_index ) - bounds_width := f32(bounds_1.x - bounds_0.x) - bounds_height := f32(bounds_1.y - bounds_0.y) + 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 == .None || region_kind == .E do return @@ -260,13 +257,11 @@ cache_glyph_to_atlas :: proc( ctx : ^Context, assert( LRU_get( & region.state, lru_code ) != - 1 ) } - atlas := & ctx.atlas - atlas_width := f32(atlas.width) - atlas_height := f32(atlas.height) - glyph_buffer := & ctx.glyph_buffer - glyph_buffer_width := f32(glyph_buffer.width) - glyph_buffer_height := f32(glyph_buffer.height) - glyph_padding := cast(f32) atlas.glyph_padding + atlas := & ctx.atlas + glyph_buffer := & ctx.glyph_buffer + atlas_size := Vec2 { f32(atlas.width), f32(atlas.height) } + glyph_buffer_size := Vec2 { f32(glyph_buffer.width), f32(glyph_buffer.height) } + glyph_padding := cast(f32) atlas.glyph_padding if ctx.debug_print { @@ -283,36 +278,28 @@ cache_glyph_to_atlas :: proc( ctx : ^Context, glyph_draw_translate.y = cast(f32) (i32(glyph_draw_translate.y + 0.9999999)) // Allocate a glyph_update_FBO region - gwidth_scaled_px := bounds_width * glyph_draw_scale.x + 1.0 + over_sample.x * glyph_padding + gwidth_scaled_px := bounds_size.x * glyph_draw_scale.x + 1.0 + over_sample.x * glyph_padding if i32(f32(glyph_buffer.batch_x) + gwidth_scaled_px) >= i32(glyph_buffer.width) { flush_glyph_buffer_to_atlas( ctx ) } // Calculate the src and destination regions - dst_position, slot_szie := atlas_bbox( atlas, region_kind, atlas_index ) - dst_glyph_position := dst_position - dst_glyph_width := bounds_width * entry.size_scale - dst_glyph_height := bounds_height * entry.size_scale - dst_glyph_width += glyph_padding - dst_glyph_height += glyph_padding + slot_position, slot_szie := atlas_bbox( atlas, region_kind, atlas_index ) - dst_size := slot_szie - dst_glyph_size := Vec2 { dst_glyph_width, dst_glyph_height } - screenspace_x_form( & dst_glyph_position, & dst_glyph_size, atlas_width, atlas_height ) - screenspace_x_form( & dst_position, & dst_size, atlas_width, atlas_height ) + dst_glyph_position := slot_position + dst_glyph_size := bounds_size * entry.size_scale + glyph_padding + dst_size := slot_szie + screenspace_x_form( & dst_glyph_position, & dst_glyph_size, atlas_size ) + screenspace_x_form( & slot_position, & dst_size, atlas_size ) src_position := Vec2 { f32(glyph_buffer.batch_x), 0 } - src_size := Vec2 { - bounds_width * glyph_draw_scale.x, - bounds_height * glyph_draw_scale.y, - } - src_size += over_sample * glyph_padding - textspace_x_form( & src_position, & src_size, glyph_buffer_width, glyph_buffer_height ) + src_size := bounds_size * glyph_draw_scale + over_sample * glyph_padding + textspace_x_form( & src_position, & src_size, glyph_buffer_size ) // Advance glyph_update_batch_x and calculate final glyph drawing transform glyph_draw_translate.x += f32(glyph_buffer.batch_x) glyph_buffer.batch_x += i32(gwidth_scaled_px) - screenspace_x_form( & glyph_draw_translate, & glyph_draw_scale, glyph_buffer_width, glyph_buffer_height ) + screenspace_x_form( & glyph_draw_translate, & glyph_draw_scale, glyph_buffer_size ) call : DrawCall { @@ -321,14 +308,22 @@ cache_glyph_to_atlas :: proc( ctx : ^Context, pass = .Atlas region = .Ignore start_index = cast(u32) len(glyph_buffer.clear_draw_list.indices) - blit_quad( & glyph_buffer.clear_draw_list, dst_position, dst_position + dst_size, { 1.0, 1.0 }, { 1.0, 1.0 } ) + + blit_quad( & glyph_buffer.clear_draw_list, + slot_position, slot_position + dst_size, + { 1.0, 1.0 }, { 1.0, 1.0 } ) + end_index = cast(u32) len(glyph_buffer.clear_draw_list.indices) append( & glyph_buffer.clear_draw_list.calls, call ) // Queue up a blit from glyph_update_FBO to the atlas region = .None start_index = cast(u32) len(glyph_buffer.draw_list.indices) - blit_quad( & glyph_buffer.draw_list, dst_glyph_position, dst_position + dst_glyph_size, src_position, src_position + src_size ) + + blit_quad( & glyph_buffer.draw_list, + dst_glyph_position, slot_position + dst_glyph_size, + src_position, src_position + src_size ) + end_index = cast(u32) len(glyph_buffer.draw_list.indices) append( & glyph_buffer.draw_list.calls, call ) } @@ -384,52 +379,40 @@ clear_draw_list :: #force_inline proc ( draw_list : ^DrawList ) { directly_draw_massive_glyph :: proc( ctx : ^Context, entry : ^Entry, glyph : Glyph, - bounds_0, bounds_1 : Vec2, - bounds_width, bounds_height : f32, + bounds_0, bounds_1 : Vec2, + bounds_size : Vec2, over_sample, position, scale : Vec2 ) { // profile(#procedure) flush_glyph_buffer_to_atlas( ctx ) - glyph_padding := f32(ctx.atlas.glyph_padding) - glyph_buffer_width := f32(ctx.glyph_buffer.width) - glyph_buffer_height := f32(ctx.glyph_buffer.height) + glyph_padding := f32(ctx.atlas.glyph_padding) + glyph_buffer_size := Vec2 { f32(ctx.glyph_buffer.width), f32(ctx.glyph_buffer.height) } // Draw un-antialiased glyph to update FBO. glyph_draw_scale := over_sample * entry.size_scale glyph_draw_translate := -1 * bounds_0 * glyph_draw_scale + vec2_from_scalar(glyph_padding) - screenspace_x_form( & glyph_draw_translate, & glyph_draw_scale, glyph_buffer_width, glyph_buffer_height ) + screenspace_x_form( & glyph_draw_translate, & glyph_draw_scale, glyph_buffer_size ) cache_glyph( ctx, entry.id, glyph, entry, bounds_0, bounds_1, glyph_draw_scale, glyph_draw_translate ) glyph_padding_dbl := glyph_padding * 2 - bounds_scaled := Vec2 { bounds_width, bounds_height } * entry.size_scale + bounds_scaled := bounds_size * entry.size_scale // Figure out the source rect. - glyph_position := Vec2 {} - glyph_width := bounds_scaled.x * over_sample.x - glyph_height := bounds_scaled.y * over_sample.y - glyph_dst_width := bounds_scaled.x - glyph_dst_height := bounds_scaled.y - glyph_height += glyph_padding_dbl - glyph_width += glyph_padding_dbl - glyph_dst_width += glyph_padding_dbl - glyph_dst_height += glyph_padding_dbl + glyph_position := Vec2 {} + glyph_size := vec2(glyph_padding_dbl) + glyph_dst_size := glyph_size + bounds_scaled + glyph_size += bounds_scaled * over_sample // Figure out the destination rect. bounds_0_scaled := Vec2 { cast(f32) i32(bounds_0.x * entry.size_scale - 0.5), cast(f32) i32(bounds_0.y * entry.size_scale - 0.5), } - dst := position + scale * bounds_0_scaled - dst_width := scale.x * glyph_dst_width - dst_height := scale.y * glyph_dst_height - dst.x -= scale.x * glyph_padding - dst.y -= scale.y * glyph_padding - dst_size := Vec2{ dst_width, dst_height } - - glyph_size := Vec2 { glyph_width, glyph_height } - textspace_x_form( & glyph_position, & glyph_size, glyph_buffer_width, glyph_buffer_height ) + dst := position + scale * bounds_0_scaled - glyph_padding * scale + dst_size := glyph_dst_size * scale + textspace_x_form( & glyph_position, & glyph_size, glyph_buffer_size ) // Add the glyph drawcall. call : DrawCall @@ -438,8 +421,12 @@ directly_draw_massive_glyph :: proc( ctx : ^Context, pass = .Target_Uncached colour = ctx.colour start_index = u32(len(ctx.draw_list.indices)) - blit_quad( & ctx.draw_list, dst, dst + dst_size, glyph_position, glyph_position + glyph_size ) - end_index = u32(len(ctx.draw_list.indices)) + + blit_quad( & ctx.draw_list, + dst, dst + dst_size, + glyph_position, glyph_position + glyph_size ) + + end_index = u32(len(ctx.draw_list.indices)) append( & ctx.draw_list.calls, call ) } @@ -464,13 +451,15 @@ draw_cached_glyph :: proc( ctx : ^Context, ) -> b32 { // profile(#procedure) - bounds_width := f32(bounds_1.x - bounds_0.x) - bounds_height := f32(bounds_1.y - bounds_0.y) + 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_width, bounds_height, over_sample, position, scale ) + directly_draw_massive_glyph( ctx, entry, glyph_index, bounds_0, bounds_1, bounds_size, over_sample, position, scale ) return true } @@ -480,30 +469,22 @@ draw_cached_glyph :: proc( ctx : ^Context, } atlas := & ctx.atlas - atlas_width := f32(atlas.width) - atlas_height := f32(atlas.height) + 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 - glyph_atlas_position, glyph_atlas_size := atlas_bbox( atlas, region_kind, atlas_index ) + slot_position, _ := atlas_bbox( atlas, region_kind, atlas_index ) - glyph_width := bounds_width * entry.size_scale - glyph_height := bounds_height * entry.size_scale + glyph_scale := bounds_size * entry.size_scale + glyph_padding - glyph_width += glyph_padding - glyph_height += glyph_padding - glyph_scale := Vec2 { glyph_width, glyph_height } - - bounds_0_scaled := Vec2{ f32(bounds_0.x), f32(bounds_0.y) } * entry.size_scale //- { 0.5, 0.5 } + bounds_0_scaled := bounds_0 * entry.size_scale //- { 0.5, 0.5 } bounds_0_scaled = ceil(bounds_0_scaled) - dst := position + bounds_0_scaled * scale - dst -= scale * glyph_padding - dst_width := scale.x * glyph_width - dst_height := scale.y * glyph_height - dst_scale := Vec2 { dst_width, dst_height } + dst := position + bounds_0_scaled * scale + dst -= glyph_padding * scale + dst_scale := glyph_scale * scale - textspace_x_form( & glyph_atlas_position, & glyph_scale, atlas_width, atlas_height ) + textspace_x_form( & slot_position, & glyph_scale, atlas_size ) // Add the glyph drawcall call := DrawCall_Default @@ -513,7 +494,9 @@ draw_cached_glyph :: proc( ctx : ^Context, colour = ctx.colour start_index = cast(u32) len(ctx.draw_list.indices) - blit_quad( & ctx.draw_list, dst, dst + dst_scale, glyph_atlas_position, glyph_atlas_position + glyph_scale ) + 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 ) diff --git a/code/font/VEFontCache/mappings.odin b/code/font/VEFontCache/mappings.odin index 9d1afff..d81a706 100644 --- a/code/font/VEFontCache/mappings.odin +++ b/code/font/VEFontCache/mappings.odin @@ -74,6 +74,10 @@ vec2 :: proc { vec2_from_vec2i, } +vec2i :: proc { + vec2i_from_vec2, +} + vec2_64 :: proc { vec2_64_from_vec2, } diff --git a/code/font/VEFontCache/misc.odin b/code/font/VEFontCache/misc.odin index aae2ee6..5b4f409 100644 --- a/code/font/VEFontCache/misc.odin +++ b/code/font/VEFontCache/misc.odin @@ -1,18 +1,6 @@ package VEFontCache -font_glyph_lru_code :: #force_inline proc "contextless" ( font : FontID, glyph_index : Glyph ) -> (lru_code : u64) -{ - // font := font - // glyph_index := glyph_index - - // font_bytes := slice_ptr( transmute(^byte) & font, size_of(FontID) ) - // glyph_bytes := slice_ptr( transmute(^byte) & glyph_index, size_of(Glyph) ) - - // buffer : [32]byte - // copy( buffer[:], font_bytes ) - // copy( buffer[ len(font_bytes) :], glyph_bytes ) - // hash := fnv64a( transmute([]byte) buffer[: size_of(FontID) + size_of(Glyph) ] ) - // lru_code = hash +font_glyph_lru_code :: #force_inline proc "contextless" ( font : FontID, glyph_index : Glyph ) -> (lru_code : u64) { lru_code = u64(glyph_index) + ( ( 0x100000000 * u64(font) ) & 0xFFFFFFFF00000000 ) return } @@ -79,8 +67,7 @@ is_empty :: #force_inline proc ( ctx : ^Context, entry : ^Entry, glyph_index : G return false } -mark_batch_codepoint_seen :: #force_inline proc ( ctx : ^Context, lru_code : u64 ) -{ +mark_batch_codepoint_seen :: #force_inline proc ( ctx : ^Context, lru_code : u64 ) { ctx.temp_codepoint_seen[lru_code] = true ctx.temp_codepoint_seen_num += 1 } @@ -90,15 +77,13 @@ reset_batch_codepoint_state :: #force_inline proc( ctx : ^Context ) { ctx.temp_codepoint_seen_num = 0 } -screenspace_x_form :: #force_inline proc "contextless" ( position, scale : ^Vec2, width, height : f32 ) { +screenspace_x_form :: #force_inline proc "contextless" ( position, scale : ^Vec2, size : Vec2 ) { when true { pos_64 := vec2_64_from_vec2(position^) scale_64 := vec2_64_from_vec2(scale^) - width := f64(width) - height := f64(height) - quotient : Vec2_64 = 1.0 / { width, height } + quotient : Vec2_64 = 1.0 / vec2_64(size) pos_64 = pos_64 * quotient * 2.0 - 1.0 scale_64 = scale_64 * quotient * 2.0 @@ -107,21 +92,19 @@ screenspace_x_form :: #force_inline proc "contextless" ( position, scale : ^Vec2 } else { - quotient : Vec2 = 1.0 / { width, height } + quotient : Vec2 = 1.0 / size (position^) *= quotient * 2.0 - 1.0 (scale^) *= quotient * 2.0 } } -textspace_x_form :: #force_inline proc "contextless" ( position, scale : ^Vec2, width, height : f32 ) { +textspace_x_form :: #force_inline proc "contextless" ( position, scale : ^Vec2, size : Vec2 ) { when true { pos_64 := vec2_64_from_vec2(position^) scale_64 := vec2_64_from_vec2(scale^) - width := f64(width) - height := f64(height) - quotient : Vec2_64 = 1.0 / { width, height } + quotient : Vec2_64 = 1.0 / vec2_64(size) pos_64 *= quotient scale_64 *= quotient @@ -130,7 +113,7 @@ textspace_x_form :: #force_inline proc "contextless" ( position, scale : ^Vec2, } else { - quotient : Vec2 = 1.0 / { width, height } + quotient : Vec2 = 1.0 / size (position^) *= quotient (scale^) *= quotient }