added kerning to TTF
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Sun, 18 Apr 2021 18:21:53 +0000 (13:21 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Sun, 18 Apr 2021 18:21:53 +0000 (13:21 -0500)
data/Inconsolata-Regular.ttf [new file with mode: 0644]
lib/ttf/types.onyx
lib/ttf_font.onyx [deleted file]
test/basic.onyx

diff --git a/data/Inconsolata-Regular.ttf b/data/Inconsolata-Regular.ttf
new file mode 100644 (file)
index 0000000..e329bbc
Binary files /dev/null and b/data/Inconsolata-Regular.ttf differ
index caa8252752ae668565c8f2ac73e28f9df45ce1ed..340973bb358f8c70f8bd8731898dfba774febe43 100644 (file)
@@ -226,10 +226,10 @@ ttf_glyph_destroy :: (glyph: ^TTGlyph) {
 
 #private_file
 TTGlyphFlags :: enum #flags {
-    On_Curve :: 0x01;
-    X_Is_Byte :: 0x2;
-    Y_Is_Byte :: 0x4;
-    Repeat    :: 0x8;
+    On_Curve  :: 0x01;
+    X_Is_Byte :: 0x02;
+    Y_Is_Byte :: 0x04;
+    Repeat    :: 0x08;
     X_Delta   :: 0x10;
     Y_Delta   :: 0x20;
 }
@@ -513,8 +513,84 @@ TTKern0Table :: struct {
     n_pairs   : i32;
     kmap      : map.Map(u32, i16);
     old_index : i32 = -1;
+
+    reset :: (use kern: ^TTKern0Table) {
+        old_index = -1;
+    }
+
+    get :: (use kern: ^TTKern0Table, glyph_index: i32) -> (i32, i32) {
+        x := 0
+
+        if old_index >= 0 {
+            ch := ((cast(u32) old_index & 0xFFFF) << 16) | (cast(u32) glyph_index & 0xFFFF);
+            if map.has(^kmap, ch) {
+                x = cast(i32) map.get(^kmap, ch);
+            }
+        }
+        
+        old_index = glyph_index;
+        if swap do return 0, x;
+        else    do return x, 0;
+    }
 }
 
+ttf_read_kern_table :: (use ttf: ^TrueTypeFont) {
+    use package core.io.binary
+    if !map.has(^table_map, "kern") do return;
+
+    kern_table_info := map.get(^table_map, "kern");
+    seek(^reader, kern_table_info.offset);
+
+    version := read_u16(^reader);
+    assert(version == 0, "Expected kern table version to be 0.");
+    n_tables := cast(u32) read_u16(^reader);
+
+    for _: n_tables {
+        sub_table_version := cast(u32) read_u16(^reader);
+        length            := cast(u32) read_u16(^reader);
+        coverage          := cast(u32) read_u16(^reader);
+        format            := coverage >> 8;
+        cross             := coverage & 4;
+        vertical          := (coverage & 1) == 0;
+
+        if format == 0 {
+            kern_table := ttf_read_kern0(ttf, vertical, cross != 0);
+            array.push(^kern, kern_table);
+
+        } else {
+            // Unknown format
+            seek(^reader, tell(^reader) + length);
+        }
+    }
+}
+
+ttf_read_kern0 :: (use ttf: ^TrueTypeFont, vertical: bool, cross: bool) -> TTKern0Table {
+    use package core.io.binary
+    use package core.intrinsics.onyx { __zero_value }
+
+    offset := tell(^reader);
+    n_pairs := cast(i32) read_u16(^reader);
+    search_range := cast(i32) read_u16(^reader);
+    entry_selector := cast(i32) read_u16(^reader);
+    range_shift := cast(i32) read_u16(^reader);
+
+    kt := TTKern0Table.{
+        swap    = (vertical && !cross) || (!vertical && cross),
+        offset  = offset,
+        n_pairs = n_pairs,
+        kmap    = __zero_value(#type map.Map(u32, i16))
+    };
+
+    for _: n_pairs {
+        left  := cast(i32) read_u16(^reader);
+        right := cast(i32) read_u16(^reader);
+        value := read_fword(^reader);
+        tmp_index := (left << 16) | right;
+        map.put(^kt.kmap, tmp_index, value);
+    }
+
+    return kt;
+}
 
 TTHorizontalMetrics :: struct {
     advance_width     : u16;
diff --git a/lib/ttf_font.onyx b/lib/ttf_font.onyx
deleted file mode 100644 (file)
index 5c736fa..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-package imgui.font
-
-use package core
-#private_file gl :: package gl
-
-
-TrueTypeFont :: struct {
-    reader: io.Reader;
-
-    // NOTE: I don't know how useful these are, but they're at
-    // the beginning of the ttf file.
-    scalar_type    : u32;
-    search_range   : u16;
-    entry_selector : u16;
-    range_shift    : u16;
-
-    table_map : map.Map(i32, TTTableInfo);
-    char_maps : [..] TTCmap;
-
-    version : u32;
-    font_revision : u32;
-    checksum_adjustment : u32;
-    magic_number : u32;
-    flags : u16;
-    units_per_em : u16;
-    // created : u64;
-    // modified : u64;
-    x_min : i16;
-    x_max : i16;
-    y_min : i16;
-    y_max : i16;
-    mac_style : u16;
-    lowest_rec_ppem : u16;
-    font_direction_hint : i16;
-    index_to_loc_format : TTIndexToLocFormat;
-    glyph_data_format : i16;
-
-    hhea : struct {
-        version : u32;
-        ascent  : i16;
-        descent : i16;
-        line_gap : i16;
-        advance_width_max : u16;
-        min_left_side_bearing : i16;
-        min_right_side_bearing : i16;
-        x_max_extent : i16;
-        caret_slope_rise : i16;
-        caret_slope_run : i16;
-        caret_offset : i16;
-        metric_data_format : i16;
-        num_of_long_hor_metrics : u16;
-    };
-}
-
-TTTableInfo :: struct {
-    checksum : u32 = 0;
-    offset   : u32 = 0;
-    length   : u32 = 0;
-}
-
-TTIndexToLocFormat :: enum (i16) {
-    Short :: 0x00;
-    Long  :: 0x01;
-}
-
-TTGlyph :: struct {
-    contour_count : i16;
-    x_min : i16;
-    x_max : i16;
-    y_min : i16;
-    y_max : i16;
-
-    points : [..] TTGlyphPoint;
-    contour_ends : [..] u16;
-}
-
-TTGlyphPoint :: struct {
-    on_curve : bool;
-    x : i16 = ~~0;
-    y : i16 = ~~0;
-}
-
-ttf_create :: (ttf_data: [] u8) -> TrueTypeFont {
-    ttf : TrueTypeFont;
-    ttf.reader = binary_reader_create(ttf_data);
-    map.init(^ttf.table_map, .{});
-    array.init(^ttf.char_maps);
-    ttf_read_offset_table(^ttf);
-    ttf_read_head_table(^ttf);
-    ttf_read_cmap_table(^ttf);
-    ttf_read_hhea_table(^ttf);
-
-    return ttf;
-}
-
index b1e51bd7540bc46a60559ac4caf5e533ed37a41c..6b87b5d72aaaeb0f1fc91b9f2085d1d3a839159d 100644 (file)
@@ -99,7 +99,8 @@ loop :: () -> void #export {
 
 
 main :: (args: [] cstr) {
-    println("Hey! We got here!");
+    font_data := #file_contents "data/Inconsolata-Regular.ttf";
+    font := imgui.ttf.ttf_create(font_data);
 
     init();