range_shift : u16;
table_map : I32Map(TTTableInfo);
+ char_maps : [..] TTCmap;
version : u32;
font_revision : u32;
ttf : TrueTypeFont;
ttf.reader = binary_reader_create(ttf_data);
i32map_init(^ttf.table_map);
+ array_init(^ttf.char_maps);
+ ttf_read_offset_table(^ttf);
return ttf;
}
return ~~read_u16(^reader);
}
+ttf_read_cmap_table :: proc (use ttf: ^TrueTypeFont) {
+ empty_table_hack := TTTableInfo.{};
+ cmap_table_info := i32map_get(^table_map, string_to_beu32("cmap"), empty_table_hack);
+ seek(^reader, cmap_table_info.offset);
+
+ version := read_u16(^reader);
+ num_subtables := read_u16(^reader);
+
+ for i: 0 .. ~~num_subtables {
+ platform_id := read_u16(^reader);
+ platform_specific_id := read_u16(^reader);
+ offset := read_u32(^reader);
+
+ // Microsoft Unicode, BMP only
+ if platform_id == ~~3 && platform_specific_id <= ~~1 {
+ ttf_read_cmap(ttf, offset + cmap_table_info.offset);
+ }
+ }
+}
+
+TTCmapFormat :: enum (u16) {
+ Simple :: 0x00;
+ Segmented :: 0x04;
+}
+
+TTCmapBase :: struct { format : TTCmapFormat; }
+TTCmap0 :: struct {
+ use base: TTCmapBase;
+
+ glyph_indicies: [] u8;
+}
+TTCmap4 :: struct {
+ use base: TTCmapBase;
+
+ seg_count : u16;
+ search_range : u16;
+ entry_selector : u16;
+ range_shift : u16;
+
+ segments : [..] TTSegment;
+ cache : I32Map(i32);
+}
+
+TTSegment :: struct {
+ start_code : u16;
+ end_code : u16;
+ id_delta : u16;
+ id_range_offset : u16;
+}
+
+TTCmap :: struct #union {
+ use base: TTCmapBase;
+ cmap0: TTCmap0;
+ cmap4: TTCmap4;
+}
+
+ttf_read_cmap :: proc (use ttf: ^TrueTypeFont, offset: u32) {
+ old := seek(^reader, offset);
+ defer seek(^reader, old);
+
+ format := read_u16(^reader);
+ length := read_u16(^reader);
+ lang := read_u16(^reader);
+
+ switch cast(i32) format {
+ case 0 do ttf_read_cmap0(ttf);
+ case 4 do ttf_read_cmap4(ttf);
+
+ case #default { print("Unsupported cmap format: "); println(cast(i32) format); }
+ }
+}
+
+ttf_read_cmap0 :: proc (use ttf: ^TrueTypeFont) {
+ cmap : TTCmap;
+ cmap.cmap0.format = TTCmapFormat.Simple;
+
+ glyphs : [..] u8;
+ array_init(^glyphs, 256);
+ for i: 0 .. 256 do array_push(^glyphs, read_u8(^reader));
+
+ cmap.cmap0.glyph_indicies = array_to_slice(^glyphs);
+
+ array_push(^char_maps, cmap);
+}
+
+ttf_read_cmap4 :: proc (use ttf: ^TrueTypeFont) {
+ cmap : TTCmap;
+ cmap.cmap4.format = TTCmapFormat.Segmented;
+ map := ^cmap.cmap4;
+
+ map.seg_count = read_u16(^reader) >> ~~1;
+ map.search_range = read_u16(^reader);
+ map.entry_selector = read_u16(^reader);
+ map.range_shift = read_u16(^reader);
+
+ array_init(^map.segments, ~~map.seg_count);
+ map.segments.count = cast(u32) map.seg_count;
+
+ for ^seg: map.segments do seg.end_code = read_u16(^reader);
+ read_u16(^reader); // Reserved and unused
+ for ^seg: map.segments do seg.start_code = read_u16(^reader);
+ for ^seg: map.segments do seg.id_delta = read_u16(^reader);
+ for ^seg: map.segments {
+ seg.id_range_offset = read_u16(^reader);
+ if seg.id_range_offset != ~~0 do seg.id_range_offset += ~~(tell(^reader) - 2);
+ }
+
+ array_push(^char_maps, cmap);
+}
+
+ttf_lookup_glyph_by_char :: proc (use ttf: ^TrueTypeFont, charcode: u32) -> u32 {
+ potential_code := 0;
+
+ for ^cmap: char_maps {
+ switch cmap.format {
+ case TTCmapFormat.Simple do potential_code = ttf_lookup_in_cmap0(ttf, ~~cmap, charcode);
+ case TTCmapFormat.Segmented do potential_code = ttf_lookup_in_cmap4(ttf, ~~cmap, charcode);
+ }
+
+ if potential_code != 0 do return potential_code;
+ }
+
+ return potential_code;
+}
+
+#private_file
+ttf_lookup_in_cmap0 :: proc (use ttf: ^TrueTypeFont, cmap: ^TTCmap0, charcode: u32) -> u32 {
+ if charcode < 0 || charcode >= 256 do return 0;
+ return ~~cmap.glyph_indicies[charcode];
+}
+
+#private_file
+ttf_lookup_in_cmap4 :: proc (use ttf: ^TrueTypeFont, cmap: ^TTCmap4, charcode: u32) -> u32 {
+ // TODO: Lookup in the cache
+
+ index := 0;
+ for ^seg: cmap.segments {
+ if ~~seg.start_code <= charcode && ~~charcode <= seg.end_code {
+ if seg.id_range_offset != ~~0 {
+ glyph_index_address := ~~seg.id_range_offset + 2 * (charcode - ~~seg.start_code);
+ seek(^reader, glyph_index_address);
+ index = cast(u32) read_u16(^reader);
+ } else {
+ index = (~~seg.id_delta + charcode) & 0xffff;
+ }
+
+ break;
+ }
+ }
+
+ return index;
+}
+
#private_file
ttf_calc_table_checksum :: proc (reader: ^BinaryReader, offset: u32, length: u32) -> u32 {
old := seek(reader, offset);
draw :: proc () {
defer render_context_flush(^renderer);
- gl.clearColor(1.0f, 1.0f, 1.0f, 1.0f);
+ gl.clearColor(0.2f, 0.2f, 0.2f, 1.0f);
gl.clear(gl.COLOR_BUFFER_BIT);
renderer.color = Color4f32.{ 1f, 0f, 0f, 1f };
- // points : [6] V2f;
- // points[0] = V2f.{ 500.0f, 700.0f };
- // points[1] = V2f.{ 600.0f, 200.0f };
- // points[2] = V2f.{ 700.0f, 400.0f };
- // points[3] = V2f.{ 1700.0f, 800.0f };
- // points[4] = V2f.{ 1800.0f, 400.0f };
- // points[5] = V2f.{ 1000.0f, 200.0f };
+ points : [6] V2f;
+ points[0] = V2f.{ 500.0f, 700.0f };
+ points[1] = V2f.{ 600.0f, 200.0f };
+ points[2] = V2f.{ 700.0f, 400.0f };
+ points[3] = V2f.{ 1700.0f, 800.0f };
+ points[4] = V2f.{ 1800.0f, 400.0f };
+ points[5] = V2f.{ 1000.0f, 200.0f };
- // for i: 0 .. 200 {
- // pos := bezier_curve(~~i / 200.0f, points[0 .. 6]);
- // draw_rect(^renderer, pos.x, pos.y, 16f, 16f);
- // }
+ for i: 0 .. 200 {
+ pos := bezier_curve(~~i / 200.0f, points[0 .. 6]);
+ draw_rect(^renderer, pos.x, pos.y, 16f, 16f);
+ }
glyph : ^TTGlyph = null;
- idx := 230;
- while glyph == null {
- glyph = ttf_read_glyph(^ttf, idx);
- idx += 1;
- }
+ glyph_index := ttf_lookup_glyph_by_char(^ttf, ~~ #char "A");
+ glyph = ttf_read_glyph(^ttf, glyph_index);
defer cfree(glyph);
+ defer array_free(^glyph.points);
+ defer array_free(^glyph.contour_ends);
rx := 100.0f / ~~ cast(i32) (glyph.x_max - glyph.x_min);
ry := 100.0f / ~~ cast(i32) (glyph.y_min - glyph.y_max);
for p: glyph.points {
+ // if p.on_curve do continue;
draw_rect(^renderer, ~~ cast(i32) p.x * rx + 100f, ~~ cast(i32) p.y * ry + 100f, 10f, 10f);
}
ttf_data := #file_contents "res/Inconsolata-Regular.ttf";
ttf = ttf_create(ttf_data);
- ttf_read_offset_table(^ttf);
ttf_read_head_table(^ttf);
+ ttf_read_cmap_table(^ttf);
// for i: 0 .. ttf_glyph_count(^ttf) {
// glyph := ttf_read_glyph(^ttf, i);
TRIANGLES /usr/share/onyx/core/js/webgl.onyx /^TRIANGLES :: 0x0004$/
TRIANGLE_FAN /usr/share/onyx/core/js/webgl.onyx /^TRIANGLE_FAN :: 0x0006$/
TRIANGLE_STRIP /usr/share/onyx/core/js/webgl.onyx /^TRIANGLE_STRIP :: 0x0005$/
+TTCmap src/font.onyx /^TTCmap :: struct #union {$/
+TTCmap0 src/font.onyx /^TTCmap0 :: struct {$/
+TTCmap4 src/font.onyx /^TTCmap4 :: struct {$/
+TTCmapBase src/font.onyx /^TTCmapBase :: struct { format : TTCmapFormat; }$/
+TTCmapFormat src/font.onyx /^TTCmapFormat :: enum (u16) {$/
TTGlyph src/font.onyx /^TTGlyph :: struct {$/
TTGlyphPoint src/font.onyx /^TTGlyphPoint :: struct {$/
TTIndexToLocFormat src/font.onyx /^TTIndexToLocFormat :: enum (i16) {$/
+TTSegment src/font.onyx /^TTSegment :: struct {$/
TTTableInfo src/font.onyx /^TTTableInfo :: struct {$/
Texture src/gfx/texture.onyx /^Texture :: struct {$/
TrueTypeFont src/font.onyx /^TrueTypeFont :: struct {$/
ttf src/main.onyx /^ttf : TrueTypeFont$/
ttf_create src/font.onyx /^ttf_create :: proc (ttf_data: [] u8) -> TrueTypeFont {$/
ttf_glyph_count src/font.onyx /^ttf_glyph_count :: proc (use ttf: ^TrueTypeFont) -> u32 {$/
+ttf_lookup_glyph_by_char src/font.onyx /^ttf_lookup_glyph_by_char :: proc (use ttf: ^TrueTypeFont, charcode: u32) -> u32 {$/
ttf_lookup_glyph_offset src/font.onyx /^ttf_lookup_glyph_offset :: proc (use ttf: ^TrueTypeFont, glyph_index: i32) -> u32 {$/
+ttf_read_cmap src/font.onyx /^ttf_read_cmap :: proc (use ttf: ^TrueTypeFont, offset: u32) {$/
+ttf_read_cmap0 src/font.onyx /^ttf_read_cmap0 :: proc (use ttf: ^TrueTypeFont) {$/
+ttf_read_cmap4 src/font.onyx /^ttf_read_cmap4 :: proc (use ttf: ^TrueTypeFont) {$/
+ttf_read_cmap_table src/font.onyx /^ttf_read_cmap_table :: proc (use ttf: ^TrueTypeFont) {$/
ttf_read_glyph src/font.onyx /^ttf_read_glyph :: proc (use ttf: ^TrueTypeFont, glyph_index: i32) -> ^TTGlyph {$/
ttf_read_head_table src/font.onyx /^ttf_read_head_table :: proc (use ttf: ^TrueTypeFont) {$/
ttf_read_offset_table src/font.onyx /^ttf_read_offset_table :: proc (use ttf: ^TrueTypeFont) {$/