diff options
| author | gingerBill <bill@gingerbill.org> | 2023-06-28 11:36:27 +0100 |
|---|---|---|
| committer | gingerBill <bill@gingerbill.org> | 2023-06-28 11:36:27 +0100 |
| commit | 9e9f3c485bfd283cda92c788a921e521e9c0a66b (patch) | |
| tree | 086d75c6b746bada39a7ebb4e5cf734072b680c8 | |
| parent | d50a8447209ef4e79a03a2a006c70987448d7d65 (diff) | |
General code style clean up for `vendor:fontstash`
| -rw-r--r-- | vendor/fontstash/fontstash.odin | 469 |
1 files changed, 217 insertions, 252 deletions
diff --git a/vendor/fontstash/fontstash.odin b/vendor/fontstash/fontstash.odin index 67b2c781c..93a48bc0d 100644 --- a/vendor/fontstash/fontstash.odin +++ b/vendor/fontstash/fontstash.odin @@ -7,6 +7,7 @@ import "core:os" import "core:mem" import "core:math" import "core:strings" +import "core:slice" import stbtt "vendor:stb/truetype" // This is a port from Fontstash into odin - specialized for nanovg @@ -23,13 +24,13 @@ import stbtt "vendor:stb/truetype" // leaves GPU vertex creation & texture management up to the user // texture atlas expands by default -INVALID :: -1 -MAX_STATES :: 20 -HASH_LUT_SIZE :: 256 -INIT_GLYPHS :: 256 +INVALID :: -1 +MAX_STATES :: 20 +HASH_LUT_SIZE :: 256 +INIT_GLYPHS :: 256 INIT_ATLAS_NODES :: 256 -MAX_FALLBACKS :: 20 -Glyph_Index :: i32 // in case you want to change the handle for glyph indices +MAX_FALLBACKS :: 20 +Glyph_Index :: i32 // in case you want to change the handle for glyph indices AlignHorizontal :: enum { LEFT, @@ -47,30 +48,30 @@ AlignVertical :: enum { Font :: struct { name: string, // allocated - info: stbtt.fontinfo, - loadedData: []byte, + info: stbtt.fontinfo, + loadedData: []byte, freeLoadedData: bool, // in case you dont want loadedData to be removed - ascender: f32, - descender: f32, + ascender: f32, + descender: f32, lineHeight: f32, glyphs: [dynamic]Glyph, - lut: [HASH_LUT_SIZE]int, + lut: [HASH_LUT_SIZE]int, - fallbacks: [MAX_FALLBACKS]int, + fallbacks: [MAX_FALLBACKS]int, nfallbacks: int, } Glyph :: struct { - codepoint: rune, - index: Glyph_Index, - next: int, - isize: i16, - blurSize: i16, + codepoint: rune, + index: Glyph_Index, + next: int, + isize: i16, + blurSize: i16, x0, y0, x1, y1: i16, - xoff, yoff: i16, - xadvance: i16, + xoff, yoff: i16, + xadvance: i16, } AtlasNode :: struct { @@ -78,8 +79,8 @@ AtlasNode :: struct { } Vertex :: struct #packed { - x, y: f32, - u, v: f32, + x, y: f32, + u, v: f32, color: [4]u8, } @@ -95,13 +96,13 @@ FontContext :: struct { nodes: [dynamic]AtlasNode, // actual pixels - textureData: []byte, // allocated using context.allocator + textureData: []byte, // allocated using context.allocator width, height: int, // 1 / texture_atlas_width, 1 / texture_atlas_height itw, ith: f32, // state - states: []State, + states: []State, state_count: int, // used states location: QuadLocation, @@ -118,24 +119,24 @@ FontContext :: struct { callbackUpdate: proc(data: rawptr, dirtyRect: [4]f32, textureData: rawptr), } -Init :: proc(using ctx: ^FontContext, w, h: int, loc: QuadLocation) { - userData = ctx - location = loc - fonts = make([dynamic]Font, 0, 8) +Init :: proc(ctx: ^FontContext, w, h: int, loc: QuadLocation) { + ctx.userData = ctx + ctx.location = loc + ctx.fonts = make([dynamic]Font, 0, 8) + + ctx.itw, ctx.ith = 1.0 / f32(w), 1.0 / f32(h) - itw = f32(1) / f32(w) - ith = f32(1) / f32(h) - textureData = make([]byte, w * h) + ctx.textureData = make([]byte, w * h) - width = w - height = h - nodes = make([dynamic]AtlasNode, 0, INIT_ATLAS_NODES) + ctx.width = w + ctx.height = h + ctx.nodes = make([dynamic]AtlasNode, 0, INIT_ATLAS_NODES) __dirtyRectReset(ctx) - states = make([]State, MAX_STATES) + ctx.states = make([]State, MAX_STATES) // NOTE NECESSARY - append(&nodes, AtlasNode { + append(&ctx.nodes, AtlasNode{ width = i16(w), }) @@ -145,8 +146,8 @@ Init :: proc(using ctx: ^FontContext, w, h: int, loc: QuadLocation) { ClearState(ctx) } -Destroy :: proc(using ctx: ^FontContext) { - for font in fonts { +Destroy :: proc(ctx: ^FontContext) { + for font in ctx.fonts { if font.freeLoadedData { delete(font.loadedData) } @@ -155,18 +156,18 @@ Destroy :: proc(using ctx: ^FontContext) { delete(font.glyphs) } - delete(states) - delete(textureData) - delete(fonts) - delete(nodes) + delete(ctx.states) + delete(ctx.textureData) + delete(ctx.fonts) + delete(ctx.nodes) } -Reset :: proc(using ctx: ^FontContext) { - __atlasReset(ctx, width, height) +Reset :: proc(ctx: ^FontContext) { + __atlasReset(ctx, ctx.width, ctx.height) __dirtyRectReset(ctx) - mem.zero_slice(textureData) + slice.zero(ctx.textureData) - for &font in fonts { + for &font in ctx.fonts { __lutReset(&font) } @@ -175,84 +176,67 @@ Reset :: proc(using ctx: ^FontContext) { ClearState(ctx) } -__atlasInsertNode :: proc(using ctx: ^FontContext, idx, x, y, w: int) { - // resize is alright here - resize(&nodes, len(nodes) + 1) - - // shift nodes up once to leave space at idx - for i := len(nodes) - 1; i > idx; i -= 1 { - nodes[i] = nodes[i - 1] - } - - // set new inserted one to properties - nodes[idx].x = i16(x) - nodes[idx].y = i16(y) - nodes[idx].width = i16(w) +__atlasInsertNode :: proc(ctx: ^FontContext, idx: int, x, y, w: int) { + inject_at(&ctx.nodes, idx, AtlasNode{ + x = i16(x), + y = i16(y), + width = i16(w), + }) } -__atlasRemoveNode :: proc(using ctx: ^FontContext, idx: int) { - if len(nodes) == 0 { +__atlasRemoveNode :: proc(ctx: ^FontContext, idx: int) { + if len(ctx.nodes) == 0 { return } - // remove node at index, shift elements down - for i in idx..<len(nodes) - 1 { - nodes[i] = nodes[i + 1] - } - - // reduce size of array - raw := transmute(^mem.Raw_Dynamic_Array) &nodes - raw.len -= 1 + ordered_remove(&ctx.nodes, idx) } -__atlasExpand :: proc(using ctx: ^FontContext, w, h: int) { - if w > width { - __atlasInsertNode(ctx, len(nodes), width, 0, w - width) +__atlasExpand :: proc(ctx: ^FontContext, w, h: int) { + if w > ctx.width { + __atlasInsertNode(ctx, len(ctx.nodes), ctx.width, 0, w - ctx.width) } - width = w - height = h + ctx.width, ctx.height = w, h } -__atlasReset :: proc(using ctx: ^FontContext, w, h: int) { - width = w - height = h - clear(&nodes) +__atlasReset :: proc(ctx: ^FontContext, w, h: int) { + ctx.width, ctx.height = w, h + clear(&ctx.nodes) // init root node - append(&nodes, AtlasNode { + append(&ctx.nodes, AtlasNode{ width = i16(w), }) } -__AtlasAddSkylineLevel :: proc(using ctx: ^FontContext, idx, x, y, w, h: int) { +__AtlasAddSkylineLevel :: proc(using ctx: ^FontContext, idx: int, x, y, w, h: int) { // insert new node __atlasInsertNode(ctx, idx, x, y + h, w) // Delete skyline segments that fall under the shadow of the new segment. for i := idx + 1; i < len(nodes); i += 1 { - if nodes[i].x < nodes[i - 1].x + nodes[i - 1].width { - shrink := nodes[i-1].x + nodes[i-1].width - nodes[i].x - nodes[i].x += i16(shrink) - nodes[i].width -= i16(shrink) - - if nodes[i].width <= 0 { - __atlasRemoveNode(ctx, i) - i -= 1 - } else { - break - } - } else { + if nodes[i].x >= nodes[i-1].x + nodes[i-1].width { + break + } + shrink := nodes[i-1].x + nodes[i-1].width - nodes[i].x + nodes[i].x += i16(shrink) + nodes[i].width -= i16(shrink) + + if nodes[i].width > 0 { break } + __atlasRemoveNode(ctx, i) + i -= 1 } // Merge same height skyline segments that are next to each other. - for i := 0; i < len(nodes) - 1; i += 1 { - if nodes[i].y == nodes[i + 1].y { - nodes[i].width += nodes[i + 1].width - __atlasRemoveNode(ctx, i + 1) - i -= 1 + for i := 0; i < len(nodes) - 1; /**/ { + if nodes[i].y == nodes[i+1].y { + nodes[i].width += nodes[i+1].width + __atlasRemoveNode(ctx, i+1) + } else { + i += 1 } } } @@ -261,14 +245,14 @@ __AtlasRectFits :: proc(using ctx: ^FontContext, i, w, h: int) -> int { // 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. - x := int(nodes[i].x) - y := int(nodes[i].y) - + + i := i + x, y := int(nodes[i].x), int(nodes[i].y) + if x + w > width { return -1 } - i := i space_left := w for space_left > 0 { if i == len(nodes) { @@ -288,8 +272,7 @@ __AtlasRectFits :: proc(using ctx: ^FontContext, i, w, h: int) -> int { } __AtlasAddRect :: proc(using ctx: ^FontContext, rw, rh: int) -> (rx, ry: int, ok: bool) { - besth := height - bestw := width + bestw, besth := width, height besti, bestx, besty := -1, -1, -1 // Bottom left fit heuristic. @@ -313,18 +296,11 @@ __AtlasAddRect :: proc(using ctx: ^FontContext, rw, rh: int) -> (rx, ry: int, ok // Perform the actual packing. __AtlasAddSkylineLevel(ctx, besti, bestx, besty, rw, rh) - ok = true - rx = bestx - ry = besty - return + return bestx, besty, true } -__AtlasAddWhiteRect :: proc(ctx: ^FontContext, w, h: int) { - gx, gy, ok := __AtlasAddRect(ctx, w, h) - - if !ok { - return - } +__AtlasAddWhiteRect :: proc(ctx: ^FontContext, w, h: int) -> bool { + gx, gy := __AtlasAddRect(ctx, w, h) or_return // Rasterize dst := ctx.textureData[gx + gy * ctx.width:] @@ -336,10 +312,12 @@ __AtlasAddWhiteRect :: proc(ctx: ^FontContext, w, h: int) { dst = dst[ctx.width:] } - ctx.dirtyRect[0] = cast(f32) min(int(ctx.dirtyRect[0]), gx) - ctx.dirtyRect[1] = cast(f32) min(int(ctx.dirtyRect[1]), gy) - ctx.dirtyRect[2] = cast(f32) max(int(ctx.dirtyRect[2]), gx + w) - ctx.dirtyRect[3] = cast(f32) max(int(ctx.dirtyRect[3]), gy + h) + ctx.dirtyRect[0] = f32(min(int(ctx.dirtyRect[0]), gx)) + ctx.dirtyRect[1] = f32(min(int(ctx.dirtyRect[1]), gy)) + ctx.dirtyRect[2] = f32(max(int(ctx.dirtyRect[2]), gx + w)) + ctx.dirtyRect[3] = f32(max(int(ctx.dirtyRect[3]), gy + h)) + + return true } AddFontPath :: proc( @@ -359,25 +337,26 @@ AddFontPath :: proc( // push a font to the font stack // optionally init with ascii characters at a wanted size AddFontMem :: proc( - ctx: ^FontContext, - name: string, - data: []u8, + ctx: ^FontContext, + name: string, + data: []u8, freeLoadedData: bool, ) -> int { - append(&ctx.fonts, Font {}) + append(&ctx.fonts, Font{}) res := &ctx.fonts[len(ctx.fonts) - 1] - res.loadedData = data + res.loadedData = data res.freeLoadedData = freeLoadedData - res.name = strings.clone(name) + res.name = strings.clone(name) stbtt.InitFont(&res.info, &res.loadedData[0], 0) ascent, descent, line_gap: i32 + stbtt.GetFontVMetrics(&res.info, &ascent, &descent, &line_gap) fh := f32(ascent - descent) - res.ascender = f32(ascent) / fh - res.descender = f32(descent) / fh + res.ascender = f32(ascent) / fh + res.descender = f32(descent) / fh res.lineHeight = (fh + f32(line_gap)) / fh - res.glyphs = make([dynamic]Glyph, 0, INIT_GLYPHS) + res.glyphs = make([dynamic]Glyph, 0, INIT_GLYPHS) __lutReset(res) return len(ctx.fonts) - 1 @@ -417,9 +396,7 @@ GetFontByName :: proc(ctx: ^FontContext, name: string) -> int { __lutReset :: proc(font: ^Font) { // set lookup table - for i in 0..<HASH_LUT_SIZE { - font.lut[i] = -1 - } + slice.fill(font.lut[:], -1) } __hashint :: proc(a: u32) -> u32 { @@ -434,23 +411,23 @@ __hashint :: proc(a: u32) -> u32 { } __renderGlyphBitmap :: proc( - font: ^Font, - output: []u8, - outWidth: i32, - outHeight: i32, - outStride: i32, - scaleX: f32, - scaleY: f32, + font: ^Font, + output: []u8, + outWidth: i32, + outHeight: i32, + outStride: i32, + scaleX: f32, + scaleY: f32, glyphIndex: Glyph_Index, ) { stbtt.MakeGlyphBitmap(&font.info, raw_data(output), outWidth, outHeight, outStride, scaleX, scaleY, glyphIndex) } __buildGlyphBitmap :: proc( - font: ^Font, + font: ^Font, glyphIndex: Glyph_Index, - pixelSize: f32, - scale: f32, + pixelSize: f32, + scale: f32, ) -> (advance, lsb, x0, y0, x1, y1: i32) { stbtt.GetGlyphHMetrics(&font.info, glyphIndex, &advance, &lsb) stbtt.GetGlyphBitmapBox(&font.info, glyphIndex, scale, scale, &x0, &y0, &x1, &y1) @@ -459,28 +436,26 @@ __buildGlyphBitmap :: proc( // get glyph and push to atlas if not exists __getGlyph :: proc( - ctx: ^FontContext, - font: ^Font, + ctx: ^FontContext, + font: ^Font, codepoint: rune, - isize: i16, - blur: i16 = 0, -) -> (res: ^Glyph) #no_bounds_check { + isize: i16, + blur: i16 = 0, +) -> (res: ^Glyph, ok: bool) #no_bounds_check { if isize < 2 { return } // find code point and size h := __hashint(u32(codepoint)) & (HASH_LUT_SIZE - 1) - i := font.lut[h] - for i != -1 { + for i := font.lut[h]; i != -1; /**/ { glyph := &font.glyphs[i] - if - glyph.codepoint == codepoint && - glyph.isize == isize && - glyph.blurSize == blur - { + if glyph.codepoint == codepoint && + glyph.isize == isize && + glyph.blurSize == blur { res = glyph + ok = true return } @@ -505,39 +480,34 @@ __getGlyph :: proc( } pixel_size := f32(isize) / 10 - blurSize := min(blur, 20) - padding := i16(blurSize + 2) // 2 minimum padding - scale := __getPixelHeightScale(render_font, pixel_size) + blurSize := min(blur, 20) + padding := i16(blurSize + 2) // 2 minimum padding + scale := __getPixelHeightScale(render_font, pixel_size) advance, _, x0, y0, x1, y1 := __buildGlyphBitmap(render_font, glyph_index, pixel_size, scale) gw := (x1 - x0) + i32(padding) * 2 gh := (y1 - y0) + i32(padding) * 2 // Find free spot for the rect in the atlas - gx, gy, ok := __AtlasAddRect(ctx, int(gw), int(gh)) - if !ok { + gx, gy, rect_ok := __AtlasAddRect(ctx, int(gw), int(gh)) + if !rect_ok { // try again with expanded ExpandAtlas(ctx, ctx.width * 2, ctx.height * 2) - gx, gy, ok = __AtlasAddRect(ctx, int(gw), int(gh)) - } - - // still not ok? - if !ok { - return + gx, gy = __AtlasAddRect(ctx, int(gw), int(gh)) or_return } // Init glyph. - append(&font.glyphs, Glyph { + append(&font.glyphs, Glyph{ codepoint = codepoint, - isize = isize, - blurSize = blurSize, - index = glyph_index, - x0 = i16(gx), - y0 = i16(gy), - x1 = i16(i32(gx) + gw), - y1 = i16(i32(gy) + gh), - xadvance = i16(scale * f32(advance) * 10), - xoff = i16(x0 - i32(padding)), - yoff = i16(y0 - i32(padding)), + isize = isize, + blurSize = blurSize, + index = glyph_index, + x0 = i16(gx), + y0 = i16(gy), + x1 = i16(i32(gx) + gw), + y1 = i16(i32(gy) + gh), + xadvance = i16(scale * f32(advance) * 10), + xoff = i16(x0 - i32(padding)), + yoff = i16(y0 - i32(padding)), // insert char to hash lookup. next = font.lut[h], @@ -575,11 +545,12 @@ __getGlyph :: proc( __blur(dst, int(gw), int(gh), ctx.width, blurSize) } - ctx.dirtyRect[0] = cast(f32) min(int(ctx.dirtyRect[0]), int(res.x0)) - ctx.dirtyRect[1] = cast(f32) min(int(ctx.dirtyRect[1]), int(res.y0)) - ctx.dirtyRect[2] = cast(f32) max(int(ctx.dirtyRect[2]), int(res.x1)) - ctx.dirtyRect[3] = cast(f32) max(int(ctx.dirtyRect[3]), int(res.y1)) + ctx.dirtyRect[0] = f32(min(int(ctx.dirtyRect[0]), int(res.x0))) + ctx.dirtyRect[1] = f32(min(int(ctx.dirtyRect[1]), int(res.y0))) + ctx.dirtyRect[2] = f32(max(int(ctx.dirtyRect[2]), int(res.x1))) + ctx.dirtyRect[3] = f32(max(int(ctx.dirtyRect[3]), int(res.y1))) + ok = true return } @@ -640,7 +611,7 @@ __blurRows :: proc(dst: []u8, w, h, dstStride, alpha: int) { } __blur :: proc(dst: []u8, w, h, dstStride: int, blurSize: i16) { - assert(blurSize != 0) + assert(blurSize > 0) // Calculate the alpha such that 90% of the kernel is within the radius. (Kernel extends to infinity) sigma := f32(blurSize) * 0.57735 // 1 / sqrt(3) @@ -710,9 +681,10 @@ ExpandAtlas :: proc(ctx: ^FontContext, width, height: int, allocator := context. ResetAtlas :: proc(ctx: ^FontContext, width, height: int, allocator := context.allocator) -> bool { if width == ctx.width && height == ctx.height { // just clear - mem.zero_slice(ctx.textureData) + slice.zero(ctx.textureData) } else { // realloc + delete(ctx.textureData, allocator) ctx.textureData = make([]byte, width * height, allocator) } @@ -732,7 +704,7 @@ ResetAtlas :: proc(ctx: ^FontContext, width, height: int, allocator := context.a ctx.itw = 1.0 / f32(width) ctx.ith = 1.0 / f32(height) - __AtlasAddWhiteRect(ctx, 2, 2) + _ = __AtlasAddWhiteRect(ctx, 2, 2) return true } @@ -769,16 +741,16 @@ CodepointWidth :: proc( // get top and bottom line boundary LineBounds :: proc(ctx: ^FontContext, y: f32) -> (miny, maxy: f32) { state := __getState(ctx) - font := __getFont(ctx, state.font) + font := __getFont(ctx, state.font) isize := i16(state.size * 10.0) y := y y += __getVerticalAlign(ctx, font, state.av, isize) if ctx.location == .TOPLEFT { - miny = y - font.ascender * f32(isize) / 10 + miny = y - font.ascender * f32(isize) / 10 maxy = miny + font.lineHeight * f32(isize / 10) } else if ctx.location == .BOTTOMLEFT { - miny = y + font.ascender * f32(isize) / 10 + miny = y + font.ascender * f32(isize) / 10 maxy = miny - font.lineHeight * f32(isize / 10) } @@ -809,9 +781,9 @@ ValidateTexture :: proc(using ctx: ^FontContext, dirty: ^[4]f32) -> bool { // get alignment based on font __getVerticalAlign :: proc( - ctx: ^FontContext, - font: ^Font, - av: AlignVertical, + ctx: ^FontContext, + font: ^Font, + av: AlignVertical, pixelSize: i16, ) -> (res: f32) { switch ctx.location { @@ -842,7 +814,7 @@ UTF8_ACCEPT :: 0 UTF8_REJECT :: 1 @(private) -utf8d := [400]u8 { +utf8d := [400]u8{ 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 @@ -871,11 +843,11 @@ __decutf8 :: #force_inline proc(state: ^rune, codep: ^rune, b: byte) -> bool { // state used to share font options State :: struct { - font: int, - size: f32, - color: [4]u8, + font: int, + size: f32, + color: [4]u8, spacing: f32, - blur: f32, + blur: f32, ah: AlignHorizontal, av: AlignVertical, @@ -890,21 +862,21 @@ Quad :: struct { // text iteration with custom settings TextIter :: struct { x, y, nextx, nexty, scale, spacing: f32, - isize, iblur: i16, + isize, iblur: i16, - font: ^Font, + font: ^Font, previousGlyphIndex: Glyph_Index, // unicode iteration - utf8state: rune, // utf8 - codepoint: rune, - text: string, + utf8state: rune, // utf8 + codepoint: rune, + text: string, codepointCount: int, // byte indices - str: int, + str: int, next: int, - end: int, + end: int, } // push a state, copies the current one over to the next one @@ -930,13 +902,13 @@ PopState :: proc(using ctx: ^FontContext) { // clear current state ClearState :: proc(ctx: ^FontContext) { state := __getState(ctx) - state.size = 12 - state.color = 255 - state.blur = 0 + state.size = 12 + state.color = 255 + state.blur = 0 state.spacing = 0 - state.font = 0 - state.ah = .LEFT - state.av = .BASELINE + state.font = 0 + state.ah = .LEFT + state.av = .BASELINE } __getState :: #force_inline proc(ctx: ^FontContext) -> ^State #no_bounds_check { @@ -975,13 +947,13 @@ SetAlignVertical :: proc(ctx: ^FontContext, av: AlignVertical) { } __getQuad :: proc( - ctx: ^FontContext, + ctx: ^FontContext, font: ^Font, previousGlyphIndex: i32, - glyph: ^Glyph, + glyph: ^Glyph, - scale: f32, + scale: f32, spacing: f32, x, y: ^f32, @@ -1036,27 +1008,27 @@ __getQuad :: proc( // init text iter struct with settings TextIterInit :: proc( - ctx: ^FontContext, - x: f32, - y: f32, + ctx: ^FontContext, + x: f32, + y: f32, text: string, ) -> (res: TextIter) { + + x, y := x, y + state := __getState(ctx) - res.font = __getFont(ctx, state.font) + res.font = __getFont(ctx, state.font) res.isize = i16(f32(state.size) * 10) res.iblur = i16(state.blur) res.scale = __getPixelHeightScale(res.font, f32(res.isize) / 10) // align horizontally - x := x - y := y switch state.ah { - case .LEFT: {} - + case .LEFT: + /**/ case .CENTER: width := TextBounds(ctx, text, x, y, nil) x = math.round(x - width * 0.5) - case .RIGHT: width := TextBounds(ctx, text, x, y, nil) x -= width @@ -1066,24 +1038,22 @@ TextIterInit :: proc( y = math.round(y + __getVerticalAlign(ctx, res.font, state.av, res.isize)) // set positions - res.x = x - res.nextx = x - res.y = y - res.nexty = y + res.x, res.nextx = x, x + res.y, res.nexty = y, y res.previousGlyphIndex = -1 res.spacing = state.spacing - res.text = text + res.text = text - res.str = 0 + res.str = 0 res.next = 0 - res.end = len(text) + res.end = len(text) return } // step through each codepoint TextIterNext :: proc( - ctx: ^FontContext, + ctx: ^FontContext, iter: ^TextIter, quad: ^Quad, ) -> (ok: bool) { @@ -1097,13 +1067,12 @@ TextIterNext :: proc( iter.x = iter.nextx iter.y = iter.nexty iter.codepointCount += 1 - glyph := __getGlyph(ctx, iter.font, iter.codepoint, iter.isize, iter.iblur) - - if glyph != nil { + if glyph, ok := __getGlyph(ctx, iter.font, iter.codepoint, iter.isize, iter.iblur); ok { __getQuad(ctx, iter.font, iter.previousGlyphIndex, glyph, iter.scale, iter.spacing, &iter.nextx, &iter.nexty, quad) + iter.previousGlyphIndex = glyph.index + } else { + iter.previousGlyphIndex = -1 } - - iter.previousGlyphIndex = glyph == nil ? -1 : glyph.index ok = true break } @@ -1115,24 +1084,21 @@ TextIterNext :: proc( // width of a text line, optionally the full rect TextBounds :: proc( - ctx: ^FontContext, - text: string, - x: f32 = 0, - y: f32 = 0, + ctx: ^FontContext, + text: string, + x: f32 = 0, + y: f32 = 0, bounds: ^[4]f32 = nil, ) -> f32 { state := __getState(ctx) isize := i16(state.size * 10) iblur := i16(state.blur) - font := __getFont(ctx, state.font) + font := __getFont(ctx, state.font) // bunch of state - x := x - y := y - minx := x - maxx := x - miny := y - maxy := y + x, y := x, y + minx, maxx := x, x + miny, maxy := y, y start_x := x // iterate @@ -1143,9 +1109,7 @@ TextBounds :: proc( codepoint: rune for byte_offset in 0..<len(text) { if __decutf8(&utf8state, &codepoint, text[byte_offset]) { - glyph := __getGlyph(ctx, font, codepoint, isize, iblur) - - if glyph != nil { + if glyph, ok := __getGlyph(ctx, font, codepoint, isize, iblur); ok { __getQuad(ctx, font, previousGlyphIndex, glyph, scale, state.spacing, &x, &y, &quad) if quad.x0 < minx { @@ -1170,21 +1134,23 @@ TextBounds :: proc( maxy = quad.y0 } } + + previousGlyphIndex = glyph.index + } else { + previousGlyphIndex = -1 } - previousGlyphIndex = glyph == nil ? -1 : glyph.index } } // horizontal alignment advance := x - start_x switch state.ah { - case .LEFT: {} - + case .LEFT: + /**/ case .CENTER: minx -= advance * 0.5 maxx -= advance * 0.5 - case .RIGHT: minx -= advance maxx -= advance @@ -1202,16 +1168,16 @@ VerticalMetrics :: proc( ) -> (ascender, descender, lineHeight: f32) { state := __getState(ctx) isize := i16(state.size * 10.0) - font := __getFont(ctx, state.font) - ascender = font.ascender * f32(isize / 10) - descender = font.descender * f32(isize / 10) + font := __getFont(ctx, state.font) + ascender = font.ascender * f32(isize / 10) + descender = font.descender * f32(isize / 10) lineHeight = font.lineHeight * f32(isize / 10) return } // reset to single state -BeginState :: proc(using ctx: ^FontContext) { - state_count = 0 +BeginState :: proc(ctx: ^FontContext) { + ctx.state_count = 0 PushState(ctx) ClearState(ctx) } @@ -1223,7 +1189,6 @@ EndState :: proc(using ctx: ^FontContext) { if callbackUpdate != nil { callbackUpdate(userData, dirtyRect, raw_data(textureData)) } - __dirtyRectReset(ctx) } }
\ No newline at end of file |