diff --git a/code/font/vefontcache/LRU.odin b/code/font/vefontcache/LRU.odin index b3f6223..20e18a3 100644 --- a/code/font/vefontcache/LRU.odin +++ b/code/font/vefontcache/LRU.odin @@ -1,4 +1,4 @@ -package vetext +package vefontcache /* Note(Ed): Original implementation has been changed moderately. diff --git a/code/font/vefontcache/Readme.md b/code/font/vefontcache/Readme.md index 9c97613..2fc0e0e 100644 --- a/code/font/vefontcache/Readme.md +++ b/code/font/vefontcache/Readme.md @@ -19,7 +19,7 @@ Features: * Robust quality of life features: * Tracks text layers! * Push and pop stack for font, font_size, colour, view, position, scale and zoom! - * Enforce even only font-sizing [TODO] + * Enforce even only font-sizing (useful for linear-zoom) [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/atlas.odin b/code/font/vefontcache/atlas.odin index ad987f4..ddb95ac 100644 --- a/code/font/vefontcache/atlas.odin +++ b/code/font/vefontcache/atlas.odin @@ -1,4 +1,4 @@ -package vetext +package vefontcache // There are only 4 actual regions of the atlas. E represents the atlas_decide_region detecting an oversized glyph. // Note(Ed): None should never really occur anymore. So its safe to most likely add an assert when its detected. diff --git a/code/font/vefontcache/draw.odin b/code/font/vefontcache/draw.odin index d170d6b..69a1888 100644 --- a/code/font/vefontcache/draw.odin +++ b/code/font/vefontcache/draw.odin @@ -1,4 +1,4 @@ -package vetext +package vefontcache /* Note(Ed): This may be seperated in the future into another file dedending on how much is involved with supportin ear-clipping triangulation. diff --git a/code/font/vefontcache/freetype_wip.odin b/code/font/vefontcache/freetype_wip.odin index fa6abf0..d6306a4 100644 --- a/code/font/vefontcache/freetype_wip.odin +++ b/code/font/vefontcache/freetype_wip.odin @@ -1,9 +1,9 @@ -package vetext +package vefontcache when false { // TODO(Ed): Freetype support -// TODO(Ed): glyph caching cannot be handled in a 'font parser' abstraction. Just going to have explicit procedures to grab info neatly... +// TODO(Ed): glyph triangulation cannot be handled in a 'font parser' abstraction. Just going to have explicit procedures to grab info neatly... cache_glyph_freetype :: proc(ctx: ^Context, font: Font_ID, glyph_index: Glyph, entry: ^Entry, bounds_0, bounds_1: Vec2, scale, translate: Vec2) -> b32 { draw_filled_path_freetype :: proc( draw_list : ^Draw_List, outside_point : Vec2, path : []Vertex, diff --git a/code/font/vefontcache/misc.odin b/code/font/vefontcache/misc.odin index 60843a0..7826400 100644 --- a/code/font/vefontcache/misc.odin +++ b/code/font/vefontcache/misc.odin @@ -1,4 +1,4 @@ -package vetext +package vefontcache /* Didn't want to splinter this into more files.. diff --git a/code/font/vefontcache/parser.odin b/code/font/vefontcache/parser.odin index 61a8d33..cef2502 100644 --- a/code/font/vefontcache/parser.odin +++ b/code/font/vefontcache/parser.odin @@ -1,4 +1,4 @@ -package vetext +package vefontcache /* Notes: @@ -24,7 +24,7 @@ import stbtt "vendor:stb/truetype" Parser_Kind :: enum u32 { STB_TrueType, - Freetype, + Freetype, // Currently not implemented. } Parser_Font_Info :: struct { @@ -63,40 +63,16 @@ Parser_Context :: struct { parser_init :: proc( ctx : ^Parser_Context, kind : Parser_Kind ) { - // switch kind - // { - // case .Freetype: - // result := freetype.init_free_type( & ctx.ft_library ) - // assert( result == freetype.Error.Ok, "VEFontCache.parser_init: Failed to initialize freetype" ) - - // case .STB_TrueType: - // Do nothing intentional - // } - ctx.kind = kind } parser_shutdown :: proc( ctx : ^Parser_Context ) { - // TODO(Ed): Implement + // Note: Not necesssary for stb_truetype } parser_load_font :: proc( ctx : ^Parser_Context, label : string, data : []byte ) -> (font : Parser_Font_Info, error : b32) { - // switch ctx.kind - // { - // case .Freetype: - // when ODIN_OS == .Windows { - // error_status := freetype.new_memory_face( ctx.ft_library, raw_data(data), cast(i32) len(data), 0, & font.freetype_info ) - // if error != .Ok do error = true - // } - // else when ODIN_OS == .Linux { - // error := freetype.new_memory_face( ctx.ft_library, raw_data(data), cast(i64) len(data), 0, & font.freetype_info ) - // if error_status != .Ok do error = true - // } - - // case .STB_TrueType: error = ! stbtt.InitFont( & font.stbtt_info, raw_data(data), 0 ) - // } font.label = label font.data = data @@ -106,122 +82,36 @@ parser_load_font :: proc( ctx : ^Parser_Context, label : string, data : []byte ) parser_unload_font :: proc( font : ^Parser_Font_Info ) { - // switch font.kind { - // case .Freetype: - // error := freetype.done_face( font.freetype_info ) - // assert( error == .Ok, "VEFontCache.parser_unload_font: Failed to unload freetype face" ) - - // case .STB_TrueType: - // Do Nothing - // } + // case .STB_TrueType: + // Do Nothing } parser_find_glyph_index :: #force_inline proc "contextless" ( font : Parser_Font_Info, codepoint : rune ) -> (glyph_index : Glyph) { - // profile(#procedure) - // switch font.kind - // { - // case .Freetype: - // when ODIN_OS == .Windows { - // glyph_index = transmute(Glyph) freetype.get_char_index( font.freetype_info, transmute(u32) codepoint ) - // } - // else when ODIN_OS == .Linux { - // glyph_index = transmute(Glyph) freetype.get_char_index( font.freetype_info, cast(u64) codepoint ) - // } - // return - - // case .STB_TrueType: - glyph_index = transmute(Glyph) stbtt.FindGlyphIndex( font.stbtt_info, codepoint ) - return - // } - // return Glyph(-1) + glyph_index = transmute(Glyph) stbtt.FindGlyphIndex( font.stbtt_info, codepoint ) + return } parser_free_shape :: #force_inline proc( font : Parser_Font_Info, shape : Parser_Glyph_Shape ) { - // switch font.kind - // { - // case .Freetype: - // delete(shape) - - // case .STB_TrueType: - stbtt.FreeShape( font.stbtt_info, transmute( [^]stbtt.vertex) raw_data(shape) ) - // } + stbtt.FreeShape( font.stbtt_info, transmute( [^]stbtt.vertex) raw_data(shape) ) } parser_get_codepoint_horizontal_metrics :: #force_inline proc "contextless" ( font : Parser_Font_Info, codepoint : rune ) -> ( advance, to_left_side_glyph : i32 ) { - // switch font.kind - // { - // case .Freetype: - // glyph_index : Glyph - // when ODIN_OS == .Windows { - // glyph_index = transmute(Glyph) freetype.get_char_index( font.freetype_info, transmute(u32) codepoint ) - // } - // else when ODIN_OS == .Linux { - // glyph_index = transmute(Glyph) freetype.get_char_index( font.freetype_info, cast(u64) codepoint ) - // } - - // if glyph_index != 0 - // { - // freetype.load_glyph( font.freetype_info, c.uint(codepoint), { .No_Bitmap, .No_Hinting, .No_Scale } ) - // advance = i32(font.freetype_info.glyph.advance.x) >> 6 - // to_left_side_glyph = i32(font.freetype_info.glyph.metrics.hori_bearing_x) >> 6 - // } - // else - // { - // advance = 0 - // to_left_side_glyph = 0 - // } - - // case .STB_TrueType: - stbtt.GetCodepointHMetrics( font.stbtt_info, codepoint, & advance, & to_left_side_glyph ) - // } + stbtt.GetCodepointHMetrics( font.stbtt_info, codepoint, & advance, & to_left_side_glyph ) return } parser_get_codepoint_kern_advance :: #force_inline proc "contextless" ( font : Parser_Font_Info, prev_codepoint, codepoint : rune ) -> i32 { - // switch font.kind - // { - // case .Freetype: - // prev_glyph_index : Glyph - // glyph_index : Glyph - // when ODIN_OS == .Windows { - // prev_glyph_index = transmute(Glyph) freetype.get_char_index( font.freetype_info, transmute(u32) prev_codepoint ) - // glyph_index = transmute(Glyph) freetype.get_char_index( font.freetype_info, transmute(u32) codepoint ) - // } - // else when ODIN_OS == .Linux { - // prev_glyph_index = transmute(Glyph) freetype.get_char_index( font.freetype_info, cast(u64) prev_codepoint ) - // glyph_index = transmute(Glyph) freetype.get_char_index( font.freetype_info, cast(u64) codepoint ) - // } - - // if prev_glyph_index != 0 && glyph_index != 0 - // { - // kerning : freetype.Vector - // font.freetype_info.driver.clazz.get_kerning( font.freetype_info, transmute(u32) prev_codepoint, transmute(u32) codepoint, & kerning ) - // } - - // case .STB_TrueType: - kern := stbtt.GetCodepointKernAdvance( font.stbtt_info, prev_codepoint, codepoint ) - return kern - // } - // return -1 + kern := stbtt.GetCodepointKernAdvance( font.stbtt_info, prev_codepoint, codepoint ) + return kern } parser_get_font_vertical_metrics :: #force_inline proc "contextless" ( font : Parser_Font_Info ) -> (ascent, descent, line_gap : i32 ) { - // switch font.kind - // { - // case .Freetype: - // info := font.freetype_info - // ascent = i32(info.ascender) - // descent = i32(info.descender) - // line_gap = i32(info.height) - (ascent - descent) - - // case .STB_TrueType: - stbtt.GetFontVMetrics( font.stbtt_info, & ascent, & descent, & line_gap ) - // } + stbtt.GetFontVMetrics( font.stbtt_info, & ascent, & descent, & line_gap ) return } @@ -230,122 +120,47 @@ parser_get_bounds :: #force_inline proc "contextless" ( font : Parser_Font_Info, // profile(#procedure) bounds_0, bounds_1 : Vec2i - // switch font.kind - // { - // case .Freetype: - // freetype.load_glyph( font.freetype_info, c.uint(glyph_index), { .No_Bitmap, .No_Hinting, .No_Scale } ) + x0, y0, x1, y1 : i32 + success := cast(bool) stbtt.GetGlyphBox( font.stbtt_info, i32(glyph_index), & x0, & y0, & x1, & y1 ) - // metrics := font.freetype_info.glyph.metrics - - // bounds_0 = {i32(metrics.hori_bearing_x), i32(metrics.hori_bearing_y - metrics.height)} - // bounds_1 = {i32(metrics.hori_bearing_x + metrics.width), i32(metrics.hori_bearing_y)} - - // case .STB_TrueType: - x0, y0, x1, y1 : i32 - success := cast(bool) stbtt.GetGlyphBox( font.stbtt_info, i32(glyph_index), & x0, & y0, & x1, & y1 ) - // assert( success ) - - bounds_0 = { x0, y0 } - bounds_1 = { x1, y1 } - // } + bounds_0 = { x0, y0 } + bounds_1 = { x1, y1 } bounds = { vec2(bounds_0), vec2(bounds_1) } return } parser_get_glyph_shape :: #force_inline proc ( font : Parser_Font_Info, glyph_index : Glyph ) -> (shape : Parser_Glyph_Shape, error : Allocator_Error) { - // switch font.kind - // { - // case .Freetype: - // // TODO(Ed): Don't do this, going a completely different route for handling shapes. - // // This abstraction fails to be time-saving or performant. - - // case .STB_TrueType: - stb_shape : [^]stbtt.vertex - nverts := stbtt.GetGlyphShape( font.stbtt_info, cast(i32) glyph_index, & stb_shape ) - - shape_raw := transmute( ^runtime.Raw_Dynamic_Array) & shape - shape_raw.data = stb_shape - shape_raw.len = int(nverts) - shape_raw.cap = int(nverts) - shape_raw.allocator = runtime.nil_allocator() - error = Allocator_Error.None - // return - // } + stb_shape : [^]stbtt.vertex + nverts := stbtt.GetGlyphShape( font.stbtt_info, cast(i32) glyph_index, & stb_shape ) + shape_raw := transmute( ^runtime.Raw_Dynamic_Array) & shape + shape_raw.data = stb_shape + shape_raw.len = int(nverts) + shape_raw.cap = int(nverts) + shape_raw.allocator = runtime.nil_allocator() + error = Allocator_Error.None return } parser_is_glyph_empty :: #force_inline proc "contextless" ( font : Parser_Font_Info, glyph_index : Glyph ) -> b32 { - // switch font.kind - // { - // case .Freetype: - // error := freetype.load_glyph( font.freetype_info, cast(u32) glyph_index, { .No_Bitmap, .No_Hinting, .No_Scale } ) - // if error == .Ok - // { - // if font.freetype_info.glyph.format == .Outline { - // return font.freetype_info.glyph.outline.n_points == 0 - // } - // else if font.freetype_info.glyph.format == .Bitmap { - // return font.freetype_info.glyph.bitmap.width == 0 && font.freetype_info.glyph.bitmap.rows == 0; - // } - // } - // return false - - // case .STB_TrueType: - return stbtt.IsGlyphEmpty( font.stbtt_info, cast(c.int) glyph_index ) - // } - // return false + return stbtt.IsGlyphEmpty( font.stbtt_info, cast(c.int) glyph_index ) } parser_scale :: #force_inline proc "contextless" ( font : Parser_Font_Info, size : f32 ) -> f32 { // profile(#procedure) - // size_scale := size < 0.0 ? parser_scale_for_pixel_height( font, -size ) : parser_scale_for_mapping_em_to_pixels( font, size ) size_scale := size > 0.0 ? parser_scale_for_pixel_height( font, size ) : parser_scale_for_mapping_em_to_pixels( font, -size ) return size_scale } parser_scale_for_pixel_height :: #force_inline proc "contextless" ( font : Parser_Font_Info, size : f32 ) -> f32 { - // switch font.kind { - // case .Freetype: - // freetype.set_pixel_sizes( font.freetype_info, 0, cast(u32) size ) - // size_scale := size / cast(f32)font.freetype_info.units_per_em - // return size_scale - - // case.STB_TrueType: - return stbtt.ScaleForPixelHeight( font.stbtt_info, size ) - // } - // return 0 + return stbtt.ScaleForPixelHeight( font.stbtt_info, size ) } parser_scale_for_mapping_em_to_pixels :: #force_inline proc "contextless" ( font : Parser_Font_Info, size : f32 ) -> f32 { - // switch font.kind { - // case .Freetype: - // Inches_To_CM :: cast(f32) 2.54 - // Points_Per_CM :: cast(f32) 28.3465 - // CM_Per_Point :: cast(f32) 1.0 / DPT_DPCM - // CM_Per_Pixel :: cast(f32) 1.0 / DPT_PPCM - // DPT_DPCM :: cast(f32) 72.0 * Inches_To_CM // 182.88 points/dots per cm - // DPT_PPCM :: cast(f32) 96.0 * Inches_To_CM // 243.84 pixels per cm - // DPT_DPI :: cast(f32) 72.0 - - // // TODO(Ed): Don't assume the dots or pixels per inch. - // system_dpi :: DPT_DPI - - // FT_Font_Size_Point_Unit :: 1.0 / 64.0 - // FT_Point_10 :: 64.0 - - // points_per_em := (size / system_dpi ) * DPT_DPI - // freetype.set_char_size( font.freetype_info, 0, cast(freetype.F26Dot6) f32(points_per_em * FT_Point_10), cast(u32) DPT_DPI, cast(u32) DPT_DPI ) - // size_scale := f32(f64(size) / cast(f64) font.freetype_info.units_per_em) - // return size_scale - - // case .STB_TrueType: - return stbtt.ScaleForMappingEmToPixels( font.stbtt_info, size ) - // } - // return 0 + return stbtt.ScaleForMappingEmToPixels( font.stbtt_info, size ) } diff --git a/code/font/vefontcache/pkg_mapping.odin b/code/font/vefontcache/pkg_mapping.odin index 69a5b32..9e39d0f 100644 --- a/code/font/vefontcache/pkg_mapping.odin +++ b/code/font/vefontcache/pkg_mapping.odin @@ -1,4 +1,4 @@ -package vetext +package vefontcache import "base:builtin" resize_soa_non_zero :: non_zero_resize_soa diff --git a/code/font/vefontcache/shaper.odin b/code/font/vefontcache/shaper.odin index bf5715e..d7150f5 100644 --- a/code/font/vefontcache/shaper.odin +++ b/code/font/vefontcache/shaper.odin @@ -1,4 +1,4 @@ -package vetext +package vefontcache /* Note(Ed): The only reason I didn't directly use harfbuzz is because hamza exists and seems to be under active development as an alternative. */ @@ -190,8 +190,8 @@ shaper_shape_harfbuzz :: proc( ctx : ^Shaper_Context, text_utf8 : string, entry f32(hb_gposition.x_advance) * font_scale, f32(hb_gposition.y_advance) * font_scale } - (position^) += advance - (max_line_width^) = max(max_line_width^, position.x) + (position^) += advance + (max_line_width^) = max(max_line_width^, position.x) is_empty := parser_is_glyph_empty(entry.parser_info, glyph) if ! is_empty { diff --git a/code/font/vefontcache/vefontcache.odin b/code/font/vefontcache/vefontcache.odin index 572b879..6a3dc82 100644 --- a/code/font/vefontcache/vefontcache.odin +++ b/code/font/vefontcache/vefontcache.odin @@ -1,7 +1,7 @@ /* See: https://github.com/Ed94/VEFontCache-Odin */ -package vetext +package vefontcache import "base:runtime" @@ -761,6 +761,7 @@ draw_text_normalized_space :: proc( ctx : ^Context, ) } +// TODO(Ed): Use this in sectr over normalized space // 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, @@ -803,6 +804,7 @@ draw_text_shape_view_space :: #force_inline proc( ctx : ^Context, ) } +// TODO(Ed): Use this in sectr over normalized space // 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, diff --git a/code/grime/mappings.odin b/code/grime/pkg_mappings.odin similarity index 100% rename from code/grime/mappings.odin rename to code/grime/pkg_mappings.odin diff --git a/code/sectr/app/state.odin b/code/sectr/app/state.odin index 8e20fa4..235ca69 100644 --- a/code/sectr/app/state.odin +++ b/code/sectr/app/state.odin @@ -281,12 +281,13 @@ frametime_delta32 :: #force_inline proc "contextless" () -> f32 { return cast(f32) get_state().frametime.delta_ms } -app_config :: #force_inline proc "contextless" () -> AppConfig { return get_state().config } -app_color_theme :: #force_inline proc "contextless" () -> AppColorTheme { return get_state().config.color_theme } -debug_data :: #force_inline proc "contextless" () -> ScratchData { return get_state().debug } -get_frametime :: #force_inline proc "contextless" () -> FrameTime { return get_state().frametime } -get_default_font :: #force_inline proc "contextless" () -> FontID { return get_state().default_font } -get_input_state :: #force_inline proc "contextless" () -> InputState { return (get_state().input ^) } +app_config :: #force_inline proc "contextless" () -> AppConfig { return get_state().config } +app_color_theme :: #force_inline proc "contextless" () -> AppColorTheme { return get_state().config.color_theme } +debug_data :: #force_inline proc "contextless" () -> ScratchData { return get_state().debug } +get_frametime :: #force_inline proc "contextless" () -> FrameTime { return get_state().frametime } +get_default_font :: #force_inline proc "contextless" () -> FontID { return get_state().default_font } +get_input_state :: #force_inline proc "contextless" () -> InputState { return (get_state().input ^) } +get_screen_extent :: #force_inline proc "contextless" () -> Extents2 { return get_state().app_window.extent } get_ui_context_mut :: #force_inline proc "contextless" () -> ^UI_State { return get_state().ui_context } set_ui_context :: #force_inline proc "contextless" ( ui : ^UI_State ) { get_state().ui_context = ui } diff --git a/code/sectr/engine/client_api.odin b/code/sectr/engine/client_api.odin index ba456d8..6644769 100644 --- a/code/sectr/engine/client_api.odin +++ b/code/sectr/engine/client_api.odin @@ -272,20 +272,21 @@ startup :: proc( prof : ^SpallProfiler, persistent_mem, frame_mem, transient_mem // Load default font - path_roboto_regular := strings.concatenate( { Path_Assets, "Roboto-Regular.ttf"} ) - font_roboto_regular = font_load( path_roboto_regular, "Roboto Regular", 32.0 ) + path_firacode := strings.concatenate( { Path_Assets, "FiraCode-Regular.ttf" } ) + font_firacode = font_load( path_firacode, "FiraCode", 16.0 ) + + // path_roboto_regular := strings.concatenate( { Path_Assets, "Roboto-Regular.ttf"} ) + // font_roboto_regular = font_load( path_roboto_regular, "Roboto Regular", 32.0 ) // path_fira_cousine := strings.concatenate( { Path_Assets, "FiraCousine-Regular.ttf" } ) // font_fira_cousine = font_load( path_fira_cousine, "Fira Cousine", 16.0 ) - default_font = font_roboto_regular + default_font = font_firacode // Aysnc load the others // path_arial_unicode_ms := strings.concatenate( { Path_Assets, "Arial Unicode MS.ttf" } ) // font_arial_unicode_ms = font_load( path_arial_unicode_ms, "Arial_Unicode_MS", 16.0 ) - // path_firacode := strings.concatenate( { Path_Assets, "FiraCode-Regular.ttf" } ) - // font_firacode = font_load( path_firacode, "FiraCode", 16.0 ) // path_neodgm_code := strings.concatenate( { Path_Assets, "neodgm_code.ttf"} ) // font_neodgm_code = font_load( path_neodgm_code, "NeoDunggeunmo Code", 32.0 ) @@ -299,7 +300,6 @@ startup :: proc( prof : ^SpallProfiler, persistent_mem, frame_mem, transient_mem // path_rec_mono_linear := strings.concatenate( { Path_Assets, "RecMonoLinear-Regular-1.084.ttf" }) // font_rec_mono_linear = font_load( path_rec_mono_linear, "RecMonoLinear Regular", 32.0 ) - // path_roboto_mono_regular := strings.concatenate( { Path_Assets, "RobotoMono-Regular.ttf"} ) // font_roboto_mono_regular = font_load( path_roboto_mono_regular, "Roboto Mono Regular", 32.0 ) diff --git a/code/sectr/grime/mappings.odin b/code/sectr/grime/pkg_mappings.odin similarity index 100% rename from code/sectr/grime/mappings.odin rename to code/sectr/grime/pkg_mappings.odin diff --git a/code/sectr/math/space.odin b/code/sectr/math/space.odin index f89e876..ae5a453 100644 --- a/code/sectr/math/space.odin +++ b/code/sectr/math/space.odin @@ -212,8 +212,8 @@ screen_to_ws_view_pos :: #force_inline proc "contextless" (pos: Vec2) -> Vec2 { // Centered screen space to conventional screen space used for rendering screen_to_render_pos :: #force_inline proc "contextless" (pos : Vec2) -> Vec2 { - screen_extent := transmute(Vec2) get_state().app_window.extent - return pos * {1, 1} + { screen_extent.x, screen_extent.y } + screen_extent := transmute(Vec2) get_screen_extent() + return pos + screen_extent } // TODO(Ed): These should assume a cam_context or have the ability to provide it in params