Browse Source

General code style clean up for `vendor:fontstash`

gingerBill 2 years ago
parent
commit
9e9f3c485b
1 changed files with 217 additions and 252 deletions
  1. 217 252
      vendor/fontstash/fontstash.odin

+ 217 - 252
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)
 	}
 }