diff --git a/code/font/RFont/RFont.odin b/code/font/RFont/RFont.odin new file mode 100644 index 0000000..b9eed91 --- /dev/null +++ b/code/font/RFont/RFont.odin @@ -0,0 +1,2 @@ +package RFont + diff --git a/code/font/VEFontCache/VEFontCache.odin b/code/font/VEFontCache/VEFontCache.odin new file mode 100644 index 0000000..e534dde --- /dev/null +++ b/code/font/VEFontCache/VEFontCache.odin @@ -0,0 +1,3 @@ +package VEFontCache + + diff --git a/code/font/fontstash/atlas.odin b/code/font/fontstash/atlas.odin new file mode 100644 index 0000000..9e17735 --- /dev/null +++ b/code/font/fontstash/atlas.odin @@ -0,0 +1,132 @@ +package fontstash + +atlas_add_rect :: proc( ctx : ^Context, ) +{ + +} + +atlas_add_skyline_level :: proc (ctx : ^Context, id : u64, x, y, width, height : i32 ) -> (error : AllocatorError) +{ + error = atlas_insert( ctx, id, x, y + height, width) + if error != AllocatorError.None { + ensure( false, "Failed to insert into atlas") + return + } + + // Delete skyline segments that fall under the shadow of the new segment. + for sky_id := id; sky_id < ctx.atlas.num; sky_id += 1 + { + curr := & ctx.atlas.data[sky_id ] + next := & ctx.atlas.data[sky_id + 1] + if curr.x >= next.x + next.width do break + + shrink := i16(next.x + next.width - curr.x) + curr.x += shrink + curr.width -= shrink + + if curr.width > 0 do break + + atlas_remove(ctx, sky_id) + sky_id -= 1 + } + + // Merge same height skyline segments that are next to each other. + for sky_id := id; sky_id < ctx.atlas.num - 1; + { + curr := & ctx.atlas.data[sky_id ] + next := & ctx.atlas.data[sky_id + 1] + + if curr.y == next.y { + curr.width += next.width + atlas_remove(ctx, sky_id + 1) + } + else { + sky_id += 1 + } + } + return +} + +atlas_delete :: proc ( ctx : ^Context ) { + using ctx + array_free( ctx.atlas ) +} + +atlas_expand :: proc( ctx : ^Context, width, height : i32 ) +{ + if width > ctx.width { + atlas_insert( ctx, ctx.atlas.num, ctx.width, 0, width - ctx.width ) + } + + ctx.width = width + ctx.height = height +} + +atlas_init :: proc( ctx : ^Context, width, height : i32, num_nodes : u32 = Init_Atlas_Nodes ) +{ + error : AllocatorError + ctx.atlas, error = init_reserve( AtlasNode, context.allocator, u64(num_nodes), dbg_name = "font atlas" ) + ensure(error != AllocatorError.None, "Failed to allocate font atlas") + + ctx.width = width + ctx.height = height + + array_append( & ctx.atlas, AtlasNode{ width = i16(width)} ) +} + +atlas_insert :: proc( ctx : ^Context, id : u64, x, y, width : i32 ) -> (error : AllocatorError) +{ + error = array_append_at( & ctx.atlas, AtlasNode{ i16(x), i16(y), i16(width) }, id ) + return +} + +atlas_remove :: #force_inline proc( ctx : ^Context, id : u64 ) { remove_at( ctx.atlas, id ) } + +atlas_reset :: proc( ctx : ^Context, width, height : i32 ) +{ + ctx.width = width + ctx.height = height + clear( ctx.atlas ) + + array_append( & ctx.atlas, AtlasNode{ width = i16(width)} ) +} + +atlas_rect_fits :: proc( ctx : ^Context, location, width, height : i32 ) -> (max_height : i32) +{ + // Checks if there is enough space at the location of skyline span 'i', + // and return the max height of all skyline spans under that at that location, + // (think tetris block being dropped at that position). Or -1 if no space found. + atlas := to_slice(ctx.atlas) + node := atlas[location] + + space_left : i32 + if i32(node.x) + width > ctx.width { + max_height = -1 + return + } + + space_left = width; + + y := i32(node.y) + location := location + for ; space_left > 0; + { + if u64(location) == ctx.atlas.num { + max_height = -1 + return + } + + node := atlas[location] + + y := max(y, i32(node.y)) + if y + height > ctx.height { + max_height = -1 + return + } + + space_left -= i32(node.width) + location += 1 + } + max_height = y + return +} diff --git a/code/font/fontstash/fontstash.odin b/code/font/fontstash/fontstash.odin new file mode 100644 index 0000000..91b0dc8 --- /dev/null +++ b/code/font/fontstash/fontstash.odin @@ -0,0 +1,220 @@ +/* +Yet another port of fontstash. + +I decided to use this instead of the odin port as it deviated from the original, making it difficult to sift through. +So The code was small enough that I mine as well learn it by porting for my use case. + +TODO(Ed): Add docs here and throughout +TODO(Ed): This is unfinished... + +Original author's copyright for fonstash.h: +------------------------------------------------------------------------------ + Copyright (c) 2009-2013 Mikko Mononen memon@inside.org + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +------------------------------------------------------------------------------ +*/ +package fontstash + +Range2_i16 :: struct #raw_union { + using pts : Vec2_i16, + using xy : struct { + x0, y0, x1, y1 : i16, + } +} + +Vec2 :: [2]f32 + +Vec2_i16 :: [2]i16 + +Invalid :: -1 + +Hash_Lut_Size :: 256 +Max_Fallbacks :: 20 +Max_States :: 20 +Vertex_Count :: 1024 +Init_Atlas_Nodes :: 256 + +FontLuts :: [Hash_Lut_Size]i32 +FontFallbacks :: [Max_Fallbacks]i32 + +HandleErrorProc :: #type proc( uptr : rawptr, error, val : i32 ) + +RenderCreateProc :: #type proc( uptr : rawptr, width, height : i32 ) +RenderResizeProc :: #type proc( uptr : rawptr, width, height : i32 ) +RenderUpdateProc :: #type proc( uptr : rawptr, rect : ^i32, data : ^u8 ) +RenderDrawProc :: #type proc( uptr : rawptr, verts : ^f32, tcoords : ^f32, colors : ^i32, num_verts : i32 ) +RenderDelete :: #type proc( uptr : rawptr ) + +AlignFlag :: enum u32 { + Left, + Center, + Right, + Top, + Middle, + Bottom, + Baseline, +} +AlignFlags :: bit_set[ AlignFlag; u32 ] + +// FONSflags +QuadLocation :: enum u32 { + Top_Left = 1, + Bottom_Left = 2, +} + +Atlas :: struct { + dud : i32, +} + +AtlasNode :: struct { + x, y, width : i16, +} + +ErrorCode :: enum u32 { + Atlas_Full, + Scratch_Full, + States_Overflow, + States_Underflow, +} + +Quad :: struct { + x0, y0, s0, t0 : f32, + x1, y1, s1, t1 : f32, +} + +Glyph :: struct { + codepoint : rune, + index, next : i32, + size, blur : i16, + x_advance : i16, + box : Range2_i16, + offset : Vec2_i16, +} + +Font :: struct { + parser_kind : ParserKind, + parser_data : ParserData, + name : string, + data : []byte, + free_data : bool, + + ascender : f32, + descender : f32, + line_height : f32, + + glyphs : Array(Glyph), + lut : FontLuts, + fallbacks : FontFallbacks, + num_fallbacks : i32, +} + +Params :: struct { + width, height : i32, + quad_location : QuadLocation, // (flags) + render_create : RenderCreateProc, + render_resize : RenderResizeProc, + render_update : RenderUpdateProc, + render_draw : RenderDrawProc, + render_delete : RenderDelete, +} + +State :: struct { + font : i32, + alignment : i32, + size : f32, + color : [4]u8, + blur : f32, + spacing : f32, +} + +TextIter :: struct { + x, y : f32, + next_x, next_y : f32, + scale, spacing : f32, + + isize, iblur : i16, + + font : ^Font, + prev_glyph_id : i32, + + codepoint : rune, + utf8_state : rune, + + str : string, + next : string, + end : string, +} + +Context :: struct { + params : Params, + +// Atlas + atlas : Array(AtlasNode), + texture_data : []byte, + width, height : i32, +// ---- + + normalized_size : Vec2, + + verts : [Vertex_Count * 2]f32, + tcoords : [Vertex_Count * 2]f32, + colors : [Vertex_Count ]f32, + + states : [Max_States]State, + num_states : i32, + + handle_error : HandleErrorProc, + error_uptr : rawptr, +} + +decode_utf8 :: proc( state : ^rune, codepoint : ^rune, to_decode : byte ) -> bool +{ + UTF8_Accept :: 0 + UTF8_Reject :: 1 + + @static UTF8_Decode_Table := [?]u8 { + // The first part of the table maps bytes to character classes that + // to reduce the size of the transition table and create bitmasks. + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 00..1F + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 20..3F + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 40..5F + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 60..7F + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, // 80..9F + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, // A0..BF + 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // C0..DF + 10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8, // E0..FF + + // The second part is a transition table that maps a combination + // of a state of the automaton and a character class to a state. + 0,12,24,36,60,96,84,12,12,12,48,72, 12,12,12,12,12,12,12,12,12,12,12,12, + 12, 0,12,12,12,12,12, 0,12, 0,12,12, 12,24,12,12,12,12,12,24,12,24,12,12, + 12,12,12,12,12,12,12,24,12,12,12,12, 12,24,12,12,12,12,12,12,12,24,12,12, + 12,12,12,12,12,12,12,36,12,36,12,12, 12,36,12,12,12,12,12,36,12,36,12,12, + 12,36,12,12,12,12,12,12,12,12,12,12, + } + + to_decode_rune := rune(to_decode) + type := UTF8_Decode_Table[to_decode_rune] + + // Update codepoint otherwise initialize it. + (codepoint^) = ((state^) != UTF8_Accept) ? \ + ((to_decode_rune & 0x3F) | ((codepoint^) << 6)) \ + : ((0xFF >> type) & (to_decode_rune)) + + (state^) = cast(rune)(UTF8_Decode_Table[256 + (state^) * 16 + rune(type)]) + return (state^) == UTF8_Accept +} + diff --git a/code/font/fontstash/mappings.odin b/code/font/fontstash/mappings.odin new file mode 100644 index 0000000..73c8948 --- /dev/null +++ b/code/font/fontstash/mappings.odin @@ -0,0 +1,58 @@ +package fontstash + + + +import "core:mem" + +AllocatorError :: mem.Allocator_Error + +import "codebase:grime" + +// asserts +ensure :: grime.ensure + +// container + +Array :: grime.Array + +array_init_reserve :: grime.array_init_reserve +array_append :: grime.array_append +array_append_at :: grime.array_append_at +array_clear :: grime.array_clear +array_free :: grime.array_free +array_remove_at :: grime.array_remove_at +array_to_slice :: grime.array_to_slice + +//#region("Proc overload mappings") + +append :: proc { + grime.array_append_array, + grime.array_append_slice, + grime.array_append_value, +} + +append_at :: proc { + array_append_at, +} + +clear :: proc { + array_clear, +} + +free :: proc { + array_free, +} + +init_reserve :: proc { + array_init_reserve, +} + +remove_at :: proc { + array_remove_at, +} + +to_slice :: proc { + array_to_slice, +} + +//#endregion("Proc overload mappings") diff --git a/code/font/fontstash/parser.odin b/code/font/fontstash/parser.odin new file mode 100644 index 0000000..900440c --- /dev/null +++ b/code/font/fontstash/parser.odin @@ -0,0 +1,66 @@ +package fontstash + +import stbtt "vendor:stb/truetype" +import freetype "thirdparty:freetype" + +ParserKind :: enum u32 { + stb_true_type, + freetype, +} + +ParserData :: struct #raw_union { + stbtt_info : stbtt.fontinfo, + // freetype_info : +} + +//#region("freetype") + + + +//#endregion("freetype") + +//#region("stb_truetype") + +fstash_tt_init :: proc( ctx : ^Context ) -> i32 { return 1 } + +fstash_tt_load_font :: proc( ctx : ^Context, parser_data : ^ParserData, data : []byte ) -> b32 +{ + parser_data.stbtt_info.userdata = ctx + stb_error := stbtt.InitFont( & parser_data.stbtt_info, & data[0], 0 ) + return stb_error +} + +fstash_tt_get_font_metrics :: proc( parser_data : ^ParserData, ascent, descent, line_gap : ^i32 ) { + stbtt.GetFontVMetrics( & parser_data.stbtt_info, ascent, descent, line_gap ) +} + +fstash_tt_get_pixel_height_scale :: proc( parser_data : ^ParserData, size : f32 ) -> f32 +{ + return stbtt.ScaleForPixelHeight( & parser_data.stbtt_info, size ) +} + +fstash_tt_get_glyph_index :: proc( parser_data : ^ParserData, codepoint : rune ) -> i32 +{ + return stbtt.FindGlyphIndex( & parser_data.stbtt_info, codepoint ) +} + +fstash_tt_build_glyph_bitmap :: proc( parser_data : ^ParserData, glyph_index : i32, + size, scale : f32, advance, left_side_bearing, x0, y0, x1, y1 : ^i32 ) -> i32 +{ + stbtt.GetGlyphHMetrics( & parser_data.stbtt_info, glyph_index, advance, left_side_bearing ) + stbtt.GetGlyphBitmapBox( & parser_data.stbtt_info, glyph_index, scale, scale, x0, y0, x1, y1 ) + return 1 +} + +fstash_tt_render_glyph_bitmap :: proc( parser_data : ^ParserData, output : [^]byte, + out_width, out_height, out_stride : i32, scale_x, scale_y : f32, glyph_index : i32 ) +{ + stbtt.MakeGlyphBitmap( & parser_data.stbtt_info, output, out_width, out_height, out_stride, scale_x, scale_y, glyph_index ) +} + +fstash_tt_get_glyph_kern_advance :: proc( parser_data : ^ParserData, glyph_1, glyph_2 : i32 ) -> i32 +{ + return stbtt.GetGlyphKernAdvance( & parser_data.stbtt_info, glyph_1, glyph_2 ) +} + +//#endregion("stb_truetype") diff --git a/code/grime/logger.odin b/code/grime/logger.odin index d1904ed..807cb98 100644 --- a/code/grime/logger.odin +++ b/code/grime/logger.odin @@ -113,6 +113,7 @@ logger_interface :: proc( } // 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...) Logger_Allocator_Buffer : [32 * Kilobyte]u8 log :: proc( msg : string, level := LogLevel.Info, loc := #caller_location ) { diff --git a/code/sectr/font/fontstash.odin b/code/sectr/font/fontstash.odin deleted file mode 100644 index 9a70ec6..0000000 --- a/code/sectr/font/fontstash.odin +++ /dev/null @@ -1,409 +0,0 @@ -/* -Yet another port of fontstash. - -I decided to use this instead of the odin port as it deviated from the original, making it difficult to sift through. -So The code was small enough that I mine as well learn it by porting for my use case. - -TODO(Ed): Add docs here and throughout -TODO(Ed): This is unfinished... - -Original author's copyright for fonstash.h: ------------------------------------------------------------------------------- - Copyright (c) 2009-2013 Mikko Mononen memon@inside.org - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. ------------------------------------------------------------------------------- -*/ -package sectr - -import stbtt "vendor:stb/truetype" - -FStash_Use_stb_truetype :: #config(FSTASH_USE_STB_TRUE_TYPE, true) - -Range2_i16 :: struct #raw_union { - using pts : Vec2_i16, - using xy : struct { - x0, y0, x1, y1 : i16, - } -} - -Vec2_i16 :: [2]i16 - -FStash_Invalid :: -1 - -FStash_Hash_Lut_Size :: 256 -FStash_Max_Fallbacks :: 20 -FStash_Max_States :: 20 -FStash_Vertex_Count :: 1024 -FStash_Init_Atlas_Nodes :: 256 - -FStash_FontLuts :: [FStash_Hash_Lut_Size]i32 -FStash_FontFallbacks :: [FStash_Max_Fallbacks]i32 - -FStash_HandleErrorProc :: #type proc( uptr : rawptr, error, val : i32 ) - -FStash_RenderCreateProc :: #type proc( uptr : rawptr, width, height : i32 ) -FStash_RenderResizeProc :: #type proc( uptr : rawptr, width, height : i32 ) -FStash_RenderUpdateProc :: #type proc( uptr : rawptr, rect : ^i32, data : ^u8 ) -FStash_RenderDrawProc :: #type proc( uptr : rawptr, verts : ^f32, tcoords : ^f32, colors : ^i32, num_verts : i32 ) -FStash_RenderDelete :: #type proc( uptr : rawptr ) - -FStash_AlignFlag :: enum u32 { - Left, - Center, - Right, - Top, - Middle, - Bottom, - Baseline, -} -FStash_AlignFlags :: bit_set[ FStash_AlignFlag; u32 ] - -// FONSflags -FStash_QuadLocation :: enum u32 { - Top_Left = 1, - Bottom_Left = 2, -} - -FStash_Atlas :: struct { - dud : i32, -} - -FStash_AtlasNode :: struct { - x, y, width : i16, -} - -FStash_ErrorCode :: enum u32 { - Atlas_Full, - Scratch_Full, - States_Overflow, - States_Underflow, -} - -FStash_Quad :: struct { - x0, y0, s0, t0 : f32, - x1, y1, s1, t1 : f32, -} - -when FStash_Use_stb_truetype -{ - FStash_FontParserData :: struct { - stbtt_info : stbtt.fontinfo, - } -} - -FStash_Glyph :: struct { - codepoint : rune, - index, next : i32, - size, blur : i16, - x_advance : i16, - box : Range2_i16, - offset : Vec2_i16, -} - -FStash_Font :: struct { - parser_data : FStash_FontParserData, - name : string, - data : []byte, - free_data : bool, - - ascender : f32, - descender : f32, - line_height : f32, - - glyphs : Array(FStash_Glyph), - lut : FStash_FontLuts, - fallbacks : FStash_FontFallbacks, - num_fallbacks : i32, -} - -FStash_Params :: struct { - width, height : i32, - quad_location : FStash_QuadLocation, // (flags) - render_create : FStash_RenderCreateProc, - render_resize : FStash_RenderResizeProc, - render_update : FStash_RenderUpdateProc, - render_draw : FStash_RenderDrawProc, - render_delete : FStash_RenderDelete, -} - -FStash_State :: struct { - font : i32, - alignment : i32, - size : f32, - color : [4]u8, - blur : f32, - spacing : f32, -} - -FStash_TextIter :: struct { - x, y : f32, - next_x, next_y : f32, - scale, spacing : f32, - - isize, iblur : i16, - - font : ^FStash_Font, - prev_glyph_id : i32, - - codepoint : rune, - utf8_state : rune, - - str : string, - next : string, - end : string, -} - -FStash_Context :: struct { - params : FStash_Params, - -// Atlas - atlas : Array(FStash_AtlasNode), - texture_data : []byte, - width, height : i32, -// ---- - - normalized_size : Vec2, - - verts : [FStash_Vertex_Count * 2]f32, - tcoords : [FStash_Vertex_Count * 2]f32, - colors : [FStash_Vertex_Count ]f32, - - states : [FStash_Max_States]FStash_State, - num_states : i32, - - handle_error : FStash_HandleErrorProc, - error_uptr : rawptr, -} - -when FStash_Use_stb_truetype -{ - fstash_tt_init :: proc( ctx : ^FStash_Context ) -> i32 { return 1 } - - fstash_tt_load_font :: proc( ctx : ^FStash_Context, parser_data : ^FStash_FontParserData, data : []byte ) -> b32 - { - parser_data.stbtt_info.userdata = ctx - stb_error := stbtt.InitFont( & parser_data.stbtt_info, & data[0], 0 ) - return stb_error - } - - fstash_tt_get_font_metrics :: proc( parser_data : ^FStash_FontParserData, ascent, descent, line_gap : ^i32 ) { - stbtt.GetFontVMetrics( & parser_data.stbtt_info, ascent, descent, line_gap ) - } - - fstash_tt_get_pixel_height_scale :: proc( parser_data : ^FStash_FontParserData, size : f32 ) -> f32 - { - return stbtt.ScaleForPixelHeight( & parser_data.stbtt_info, size ) - } - - fstash_tt_get_glyph_index :: proc( parser_data : ^FStash_FontParserData, codepoint : rune ) -> i32 - { - return stbtt.FindGlyphIndex( & parser_data.stbtt_info, codepoint ) - } - - fstash_tt_build_glyph_bitmap :: proc( parser_data : ^FStash_FontParserData, glyph_index : i32, - size, scale : f32, advance, left_side_bearing, x0, y0, x1, y1 : ^i32 ) -> i32 - { - stbtt.GetGlyphHMetrics( & parser_data.stbtt_info, glyph_index, advance, left_side_bearing ) - stbtt.GetGlyphBitmapBox( & parser_data.stbtt_info, glyph_index, scale, scale, x0, y0, x1, y1 ) - return 1 - } - - fstash_tt_render_glyph_bitmap :: proc( parser_data : ^FStash_FontParserData, output : [^]byte, - out_width, out_height, out_stride : i32, scale_x, scale_y : f32, glyph_index : i32 ) - { - stbtt.MakeGlyphBitmap( & parser_data.stbtt_info, output, out_width, out_height, out_stride, scale_x, scale_y, glyph_index ) - } - - fstash_tt_get_glyph_kern_advance :: proc( parser_data : ^FStash_FontParserData, glyph_1, glyph_2 : i32 ) -> i32 - { - return stbtt.GetGlyphKernAdvance( & parser_data.stbtt_info, glyph_1, glyph_2 ) - } -} // when FStash_Use_stb_true-type - -fstash_decode_utf8 :: proc( state : ^rune, codepoint : ^rune, to_decode : byte ) -> bool -{ - UTF8_Accept :: 0 - UTF8_Reject :: 1 - - @static UTF8_Decode_Table := [?]u8 { - // The first part of the table maps bytes to character classes that - // to reduce the size of the transition table and create bitmasks. - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 00..1F - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 20..3F - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 40..5F - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 60..7F - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, // 80..9F - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, // A0..BF - 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // C0..DF - 10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8, // E0..FF - - // The second part is a transition table that maps a combination - // of a state of the automaton and a character class to a state. - 0,12,24,36,60,96,84,12,12,12,48,72, 12,12,12,12,12,12,12,12,12,12,12,12, - 12, 0,12,12,12,12,12, 0,12, 0,12,12, 12,24,12,12,12,12,12,24,12,24,12,12, - 12,12,12,12,12,12,12,24,12,12,12,12, 12,24,12,12,12,12,12,12,12,24,12,12, - 12,12,12,12,12,12,12,36,12,36,12,12, 12,36,12,12,12,12,12,36,12,36,12,12, - 12,36,12,12,12,12,12,12,12,12,12,12, - } - - to_decode_rune := rune(to_decode) - type := UTF8_Decode_Table[to_decode_rune] - - // Update codepoint otherwise initialize it. - (codepoint^) = ((state^) != UTF8_Accept) ? \ - ((to_decode_rune & 0x3F) | ((codepoint^) << 6)) \ - : ((0xFF >> type) & (to_decode_rune)) - - (state^) = cast(rune)(UTF8_Decode_Table[256 + (state^) * 16 + rune(type)]) - return (state^) == UTF8_Accept -} - -fstash_atlas_delete :: proc ( ctx : ^FStash_Context ) { - using ctx - array_free( ctx.atlas ) -} - -fstash_atlas_expand :: proc( ctx : ^FStash_Context, width, height : i32 ) -{ - if width > ctx.width { - fstash_atlas_insert( ctx, ctx.atlas.num, ctx.width, 0, width - ctx.width ) - } - - ctx.width = width - ctx.height = height -} - -fstash_atlas_init :: proc( ctx : ^FStash_Context, width, height : i32, num_nodes : u32 = FStash_Init_Atlas_Nodes ) -{ - error : AllocatorError - ctx.atlas, error = array_init_reserve( FStash_AtlasNode, context.allocator, u64(num_nodes), dbg_name = "font atlas" ) - ensure(error != AllocatorError.None, "Failed to allocate font atlas") - - ctx.width = width - ctx.height = height - - array_append( & ctx.atlas, FStash_AtlasNode{ width = i16(width)} ) -} - -fstash_atlas_insert :: proc( ctx : ^FStash_Context, id : u64, x, y, width : i32 ) -> (error : AllocatorError) -{ - error = array_append_at( & ctx.atlas, FStash_AtlasNode{ i16(x), i16(y), i16(width) }, id ) - return -} - -fstash_atlas_remove :: proc( ctx : ^FStash_Context, id : u64 ) -{ - array_remove_at( ctx.atlas, id ) -} - -fstash_atlas_reset :: proc( ctx : ^FStash_Context, width, height : i32 ) -{ - ctx.width = width - ctx.height = height - array_clear( ctx.atlas ) - - array_append( & ctx.atlas, FStash_AtlasNode{ width = i16(width)} ) -} - -fstash_atlas_add_skyline_level :: proc (ctx : ^FStash_Context, id : u64, x, y, width, height : i32 ) -> (error : AllocatorError) -{ - insert :: fstash_atlas_insert - remove :: fstash_atlas_remove - - error = insert( ctx, id, x, y + height, width) - if error != AllocatorError.None { - ensure( false, "Failed to insert into atlas") - return - } - - // Delete skyline segments that fall under the shadow of the new segment. - for sky_id := id; sky_id < ctx.atlas.num; sky_id += 1 - { - curr := & ctx.atlas.data[sky_id ] - next := & ctx.atlas.data[sky_id + 1] - if curr.x >= next.x + next.width do break - - shrink := i16(next.x + next.width - curr.x) - curr.x += shrink - curr.width -= shrink - - if curr.width > 0 do break - - remove(ctx, sky_id) - sky_id -= 1 - } - - // Merge same height skyline segments that are next to each other. - for sky_id := id; sky_id < ctx.atlas.num - 1; - { - curr := & ctx.atlas.data[sky_id ] - next := & ctx.atlas.data[sky_id + 1] - - if curr.y == next.y { - curr.width += next.width - remove(ctx, sky_id + 1) - } - else { - sky_id += 1 - } - } - return -} - -fstash_atlas_rect_fits :: proc( ctx : ^FStash_Context, location, width, height : i32 ) -> (max_height : i32) -{ - // Checks if there is enough space at the location of skyline span 'i', - // and return the max height of all skyline spans under that at that location, - // (think tetris block being dropped at that position). Or -1 if no space found. - atlas := array_to_slice(ctx.atlas) - node := atlas[location] - - space_left : i32 - if i32(node.x) + width > ctx.width { - max_height = -1 - return - } - - space_left = width; - - y := i32(node.y) - location := location - for ; space_left > 0; - { - if u64(location) == ctx.atlas.num { - max_height = -1 - return - } - - node := atlas[location] - - y := max(y, i32(node.y)) - if y + height > ctx.height { - max_height = -1 - return - } - - space_left -= i32(node.width) - location += 1 - } - max_height = y - return -} - -fstash_atlas_add_rect :: proc( ctx : ^FStash_Context, ) -{ - -} diff --git a/code/sectr/font/provider_fontstash.odin b/code/sectr/font/provider_fontstash.odin index e69de29..d356527 100644 --- a/code/sectr/font/provider_fontstash.odin +++ b/code/sectr/font/provider_fontstash.odin @@ -0,0 +1,3 @@ +package sectr + +import fstash "codebase:font/fontstash" diff --git a/code/sectr/grime/mappings.odin b/code/sectr/grime/mappings.odin index 9dba11b..bbf10e8 100644 --- a/code/sectr/grime/mappings.odin +++ b/code/sectr/grime/mappings.odin @@ -127,6 +127,8 @@ import "thirdparty:backtrace" stacktrace :: backtrace.trace stacktrace_lines :: backtrace.lines +#region("codebase") + import "codebase:grime" // asserts ensure :: grime.ensure @@ -235,6 +237,8 @@ import "codebase:grime" varena_allocator :: grime.varena_allocator +#endregion("codebase") + #region("Procedure overload mappings") // This has to be done on a per-module basis.