Created
March 7, 2018 03:15
-
-
Save thebirk/a8e4de3db557a20ac590f2193b6589e5 to your computer and use it in GitHub Desktop.
Basic texture atlas using freetype in odin
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Store the glyph index in the font for faster kerning lookup? | |
Glyph :: struct { | |
bearingX, bearingY: int, | |
width, height: int, | |
advanceX: int, | |
} | |
Font :: struct { | |
face: FT_Face, | |
contex: stbrp_context, | |
nodes: []stbrp_node, | |
atlas_w, atlas_h: int, | |
pixels: []u8, | |
glyphs: map[rune]Glyph, | |
} | |
the_library: FT_Library; | |
load_font :: proc(path: string, pixel_size: int, atlas_width, atlas_height: int) -> ^Font { | |
font := new(Font); | |
font.atlas_w = atlas_width; | |
font.atlas_h = atlas_height; | |
using font; | |
cpath := strings.new_c_string(path); | |
defer free(cpath); | |
if FT_New_Face(the_library, cpath, 0, &face) != 0 { | |
return nil; | |
} | |
FT_Set_Pixel_Sizes(face, 0, auto_cast pixel_size); | |
pixels = make([]u8, atlas_w*atlas_h); | |
nodes = make([]stbrp_node, atlas_w); | |
stbrp_init_target(&contex, i32(atlas_w-1), i32(atlas_h-1), &nodes[0], auto_cast len(nodes)); | |
pack_range(font, ' ', '~'); | |
return font; | |
} | |
pack_range :: proc(using font: ^Font, first, last: rune) -> (packed_all: bool = true) { | |
glyph_count := int(last-first+1); | |
reserve(&glyphs, glyph_count); | |
rects := make([]stbrp_rect, glyph_count); | |
defer free(rects); | |
fmt.printf("glyph_count %v\n", glyph_count); | |
// Get glyph data and setup packing | |
for cp in first...last { | |
if FT_Load_Char(face, auto_cast cp, FT_LOAD_RENDER) != 0 { | |
assert(false, "Invalid font cp!"); | |
} | |
glyph := face.glyph; | |
g: Glyph; | |
g.width = auto_cast glyph.metrics.width; | |
g.height = auto_cast glyph.metrics.height; | |
g.bearingX = auto_cast glyph.metrics.horiBearingX; | |
g.bearingY = auto_cast glyph.metrics.horiBearingY; | |
g.advanceX = auto_cast glyph.metrics.horiAdvance; | |
glyphs[cp] = g; | |
rects[cp-first].w = auto_cast (glyph.bitmap.width+1); | |
rects[cp-first].h = auto_cast (glyph.bitmap.rows+1); | |
} | |
stbrp_pack_rects(&contex, &rects[0], i32(len(rects))); | |
copy_to_atlas :: proc(using font: ^Font, r: ^stbrp_rect, bitmap: []u8) { | |
for y in 0..r.h { | |
yy := int(r.y+y); | |
for x in 0..r.w { | |
xx := int(r.x+x); | |
font.pixels[xx+yy*font.atlas_w] = bitmap[x+y*r.w]; | |
} | |
} | |
} | |
// Do packing and writing to atlas | |
for cp in first...last { | |
if FT_Load_Char(face, auto_cast cp, FT_LOAD_RENDER) != 0 { | |
assert(false, "Invalid font cp!!??!?!"); | |
} | |
r := &rects[cp-first]; | |
if r.was_packed == 0 { | |
packed_all = false; | |
continue; | |
} | |
r.x += 1; | |
r.y += 1; | |
r.w -= 1; | |
r.h -= 1; | |
pixels := mem.slice_ptr(face.glyph.bitmap.buffer, int(face.glyph.bitmap.width*face.glyph.bitmap.rows)); | |
copy_to_atlas(font, r, pixels); | |
} | |
return; | |
} | |
import stbiw "shared:odin-stb/stb_image_write.odin" | |
main :: proc() { | |
FT_Init_FreeType(&the_library); | |
defer FT_Done_FreeType(the_library); | |
font := load_font("fonts/arial.ttf", 48, 1024, 1024); | |
if font == nil { | |
assert(false, "failed to init font!"); | |
} | |
pack_range(font, 0xA0, 0xFF); | |
pack_range(font, 0x400, 0x4FF); | |
stbiw.write_png("test.png\x00", font.atlas_w, font.atlas_h, 1, font.pixels, 0); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment