const std = @import("std"); const AllocError = std.mem.Allocator.Error; //------------------------------------------------------------------------------------------ // [PLATFORM] //------------------------------------------------------------------------------------------ pub const Platform = enum(c_uint) { MacOS, Windows, }; extern fn oc_get_host_platform() Platform; pub const getHostPlatform = oc_get_host_platform; //------------------------------------------------------------------------------------------ // [DEBUG] Logging //------------------------------------------------------------------------------------------ pub const log = struct { pub const Level = enum(c_uint) { Error, Warning, Info, }; pub const Output = opaque { extern var OC_LOG_DEFAULT_OUTPUT: ?*Output; extern fn oc_log_set_output(output: *Output) void; pub inline fn default() ?*Output { return OC_LOG_DEFAULT_OUTPUT; } const set = oc_log_set_output; }; extern fn oc_log_set_level(level: Level) void; extern fn oc_log_ext(level: Level, function: [*]const u8, file: [*]const u8, line: c_int, fmt: [*]const u8, ...) void; const setLevel = oc_log_set_level; pub fn info(comptime fmt: []const u8, args: anytype, source: std.builtin.SourceLocation) void { ext(Level.Info, fmt, args, source); } pub fn warn(comptime fmt: []const u8, args: anytype, source: std.builtin.SourceLocation) void { ext(Level.Warning, fmt, args, source); } pub fn err(comptime fmt: []const u8, args: anytype, source: std.builtin.SourceLocation) void { ext(Level.Error, fmt, args, source); } pub fn ext(comptime level: Level, comptime fmt: []const u8, args: anytype, source: std.builtin.SourceLocation) void { var format_buf: [512:0]u8 = undefined; _ = std.fmt.bufPrintZ(&format_buf, fmt, args) catch 0; // just discard NoSpaceLeft error for now var line: c_int = @intCast(source.line); oc_log_ext(level, source.fn_name.ptr, source.file.ptr, line, format_buf[0..].ptr); } }; //------------------------------------------------------------------------------------------ // [DEBUG] Assert/Abort //------------------------------------------------------------------------------------------ extern fn oc_abort_ext(file: [*]const u8, function: [*]const u8, line: c_int, fmt: [*]const u8, ...) void; extern fn oc_assert_fail(file: [*]const u8, function: [*]const u8, line: c_int, src: [*]const u8, fmt: [*]const u8, ...) void; pub fn assert(condition: bool, comptime fmt: []const u8, args: anytype, source: std.builtin.SourceLocation) void { if (condition == false) { var format_buf: [512:0]u8 = undefined; _ = std.fmt.bufPrintZ(&format_buf, fmt, args) catch 0; var line: c_int = @intCast(source.line); oc_assert_fail(source.file.ptr, source.fn_name.ptr, line, "assertion failed", format_buf[0..].ptr); } } pub fn abort(comptime fmt: []const u8, args: anytype, source: std.builtin.SourceLocation) void { var format_buf: [512:0]u8 = undefined; _ = std.fmt.bufPrintZ(&format_buf, fmt, args) catch 0; var line: c_int = @intCast(source.line); oc_abort_ext(source.file.ptr, source.fn_name.ptr, line, format_buf[0..].ptr); } //------------------------------------------------------------------------------------------ // [INTRUSIVE LIST] //------------------------------------------------------------------------------------------ pub const ListElt = extern struct { prev: ?*ListElt, next: ?*ListElt, pub fn entry(self: *ListElt, comptime ParentType: type, comptime field_name_in_parent: []const u8) *ParentType { return @fieldParentPtr(ParentType, field_name_in_parent, self); } pub fn nextEntry(comptime ParentType: type, comptime field_name_in_parent: []const u8, elt_parent: *ParentType) ?*ParentType { const elt: ?*ListElt = @field(elt_parent, field_name_in_parent); if (elt.next) |next| { return next.entry(ParentType, field_name_in_parent); } return null; } pub fn prevEntry(comptime ParentType: type, comptime field_name_in_parent: []const u8, elt_parent: *ParentType) ?*ParentType { const elt: ?*ListElt = @field(elt_parent, field_name_in_parent); if (elt.prev) |prev| { return prev.entry(ParentType, field_name_in_parent); } return null; } }; pub const List = extern struct { first: ?*ListElt, last: ?*ListElt, pub fn init() List { return .{ .first = null, .last = null, }; } pub fn firstEntry(self: *List, comptime EltParentType: type, comptime field_name_in_parent: []const u8) ?*EltParentType { if (self.first) |elt| { return elt.entry(EltParentType, field_name_in_parent); } return null; } pub fn lastEntry(self: *List, comptime EltParentType: type, comptime field_name_in_parent: []const u8) ?*EltParentType { if (self.last) |elt| { return elt.entry(EltParentType, field_name_in_parent); } return null; } const IterDirection = enum { Forward, Backward, }; pub fn makeIter(comptime direction: IterDirection, comptime EltParentType: type, comptime field_name_in_parent: []const u8) type { return struct { const Self = @This(); item: ?*ListElt, pub fn next(self: *Self) ?*EltParentType { if (self.item) |elt| { var entry: *EltParentType = elt.entry(EltParentType, field_name_in_parent); self.item = if (direction == .Forward) elt.next else elt.prev; return entry; } return null; } }; } pub fn iter(self: *const List, comptime EltParentType: type, comptime field_name_in_parent: []const u8) makeIter(.Forward, EltParentType, field_name_in_parent) { const Iter = makeIter(.Forward, EltParentType, field_name_in_parent); return Iter{ .item = self.first, }; } pub fn iterReverse(self: *const List, comptime EltParentType: type, comptime field_name_in_parent: []const u8) makeIter(.Backward, EltParentType, field_name_in_parent) { const Iter = makeIter(.Backward, EltParentType, field_name_in_parent); return Iter{ .item = self.last, }; } pub fn insert(self: *List, after_elt: ?*ListElt, elt: *ListElt) void { elt.prev = after_elt; elt.next = after_elt.next; if (after_elt.next) |elt_next| { after_elt.next.prev = elt_next; } else { self.last = elt; } after_elt.next = elt; } pub fn insertBefore(self: *List, before_elt: ?*ListElt, elt: *ListElt) void { elt.next = before_elt; elt.prev = before_elt.prev; if (before_elt.prev) |elt_prev| { before_elt.prev.next = elt_prev; } else { self.first = elt; } before_elt.prev = elt; } pub fn remove(self: *List, elt: *ListElt) void { if (elt.prev != null) { elt.prev.next = elt.next; } else { self.first = elt.next; } if (elt.next != null) { elt.next.prev = elt.prev; } else { self.last = elt.prev; } elt.prev = blk: { const tmp = null; elt.next = tmp; break :blk tmp; }; } pub fn push(self: *List, elt: *ListElt) void { elt.next = self.first; elt.prev = null; if (self.first) |elt_first| { elt_first.prev = elt; } else { self.last = elt; } self.first = elt; } pub fn pop(self: *List) ?*ListElt { if (self.first) |elt_begin| { remove(self, elt_begin); return elt_begin; } return null; } pub fn popEntry(self: *List, comptime EltParentType: type, comptime field_name_in_parent: []const u8) ?*EltParentType { if (self.pop()) |elt| { return elt.entry(EltParentType, field_name_in_parent); } return null; } pub fn pushBack(self: *List, elt: *ListElt) void { elt.prev = self.last; elt.next = null; if (self.last) |last_elt| { last_elt.next = elt; } else { self.first = elt; } self.last = elt; } pub fn popBack(self: *List) ?*ListElt { if (self.last) |last_elt| { remove(self, last_elt); return last_elt; } return null; } pub fn empty(self: *const List) bool { return (self.first == null) or (self.last == null); } }; //------------------------------------------------------------------------------------------ // [MEMORY] //------------------------------------------------------------------------------------------ pub const BaseAllocator = extern struct { const MemReserveFunction = *const fn (context: *BaseAllocator, size: u64) ?[*]u8; const MemModifyFunction = *const fn (context: *BaseAllocator, ptr: ?[*]u8, size: u64) ?[*]u8; func_reserve: MemReserveFunction, func_commit: MemModifyFunction, func_decommit: MemModifyFunction, func_release: MemModifyFunction, extern fn oc_base_allocator_default() *BaseAllocator; pub const default = oc_base_allocator_default; }; pub const ArenaChunk = extern struct { list_elt: ListElt, ptr: ?[*]u8, offset: u64, committed: u64, cap: u64, }; pub const ArenaScope = extern struct { arena: *Arena, chunk: *ArenaChunk, offset: u64, extern fn oc_arena_scope_end(scope: ArenaScope) void; pub const end = oc_arena_scope_end; }; pub const ArenaOptions = extern struct { base: ?*BaseAllocator, reserve: u64, }; pub const Arena = extern struct { base: ?*BaseAllocator, chunks: List, current_chunk: ?*ArenaChunk, extern fn oc_arena_init(arena: *Arena) void; extern fn oc_arena_init_with_options(arena: *Arena, options: *ArenaOptions) void; extern fn oc_arena_cleanup(arena: *Arena) void; extern fn oc_arena_push(arena: *Arena, size: u64) ?[*]u8; extern fn oc_arena_push_aligned(arena: *Arena, size: u64, alignment: u32) ?[*]u8; extern fn oc_arena_clear(arena: *Arena) void; extern fn oc_arena_scope_begin(arena: *Arena) ArenaScope; extern fn oc_scratch_next(used: *Arena) *Arena; extern fn oc_scratch_begin() ArenaScope; extern fn oc_scratch_begin_next(used: *Arena) ArenaScope; pub fn init() Arena { var arena: Arena = undefined; oc_arena_init(&arena); return arena; } pub fn initWithOptions(opts: ArenaOptions) Arena { var arena: Arena = undefined; oc_arena_init(&arena, &opts); return arena; } pub const deinit = oc_arena_cleanup; pub const clear = oc_arena_clear; pub const scopeBegin = oc_arena_scope_begin; pub fn push(arena: *Arena, size: usize) AllocError![]u8 { return arena.pushAligned(size, 1); } pub fn pushAligned(arena: *Arena, size: usize, alignment: u32) AllocError![]u8 { if (oc_arena_push_aligned(arena, size, alignment)) |mem| { return mem[0..size]; } return AllocError.OutOfMemory; } pub fn pushType(arena: *Arena, comptime T: type) AllocError!*T { var mem: []u8 = try arena.pushAligned(@sizeOf(T), @alignOf(T)); assert(mem.len >= @sizeOf(T), "need at least {} bytes, but got {}", .{ mem.len, @sizeOf(T) }, @src()); var p: *T = @alignCast(@ptrCast(mem.ptr)); return p; } pub fn pushArray(arena: *Arena, comptime T: type, count: usize) AllocError![]T { var mem: []u8 = try arena.pushAligned(@sizeOf(T) * count, @alignOf(T)); std.debug.assert(mem.len >= @sizeOf(T) * count); var items: [*]T = @alignCast(@ptrCast(mem.ptr)); return items[0..count]; } pub const scratchNext = oc_scratch_next; pub const scratchBegin = oc_scratch_begin; pub const scratchBeginNext = oc_scratch_begin_next; }; //------------------------------------------------------------------------------------------ // [STRINGS] u8 strings //------------------------------------------------------------------------------------------ fn stringType(comptime CharType: type) type { return extern struct { pub const StrListElt = extern struct { list_elt: ListElt, string: Str, }; pub const StrList = extern struct { list: List, elt_count: u64, len: u64, pub fn init() StrList { return .{ .list = List.init(), .elt_count = 0, .len = 0, }; } pub fn push(list: *StrList, arena: *Arena, str: Str) AllocError!void { var elt: *StrListElt = try arena.pushType(StrListElt); elt.string = str; list.list.pushBack(&elt.list_elt); list.elt_count += 1; list.len += str.len; } pub fn pushSlice(list: *StrList, arena: *Arena, str: []const CharType) AllocError!void { try list.push(arena, Str.fromSlice(str)); } pub fn pushf(list: *StrList, arena: *Arena, comptime format: []const u8, args: anytype) AllocError!void { var str = try Str.pushf(arena, format, args); try list.push(arena, str); } pub fn iter(list: *const StrList) List.makeIter(.Forward, StrListElt, "list_elt") { return list.list.iter(StrListElt, "list_elt"); } pub fn iterReverse(list: *const StrList) List.makeIter(.Backward, StrListElt, "list_elt") { return list.list.iterReverse(StrListElt, "list_elt"); } pub fn find(list: *const StrList, needle: *const Str) ?*StrListElt { return list.findSlice(needle.slice()); } pub fn findSlice(list: *const StrList, needle: []const CharType) ?*StrListElt { var iterator = list.iter(); while (iterator.next()) |elt_string| { if (std.mem.eql(CharType, elt_string.string.slice(), needle)) { return elt_string; } } return null; } pub fn contains(list: *const StrList, needle: *const Str) bool { return list.findSlice(needle.slice()) != null; } pub fn containsSlice(list: *const StrList, needle: []const CharType) bool { return list.findSlice(needle) != null; } pub fn join(list: *const StrList, arena: *Arena) AllocError!Str { const empty = Str{ .ptr = null, .len = 0 }; return try list.collate(arena, empty, empty, empty); } pub fn collate(list: *const StrList, arena: *Arena, prefix: Str, separator: Str, postfix: Str) AllocError!Str { var str: Str = undefined; str.len = @intCast(prefix.len + list.len + (list.elt_count - 1) * separator.len + postfix.len); str.ptr = (try arena.pushArray(CharType, str.len + 1)).ptr; @memcpy(str.ptr.?[0..prefix.len], prefix.slice()); var offset = prefix.len; var iterator = list.iter(); var index: usize = 0; while (iterator.next()) |list_str| { if (index > 0) { @memcpy(str.ptr.?[offset .. offset + separator.len], separator.slice()); offset += separator.len; } @memcpy(str.ptr.?[offset .. offset + list_str.string.len], list_str.string.slice()); offset += list_str.string.len; index += 1; } @memcpy(str.ptr.?[offset .. offset + postfix.len], postfix.slice()); str.ptr.?[str.len] = 0; return str; } }; const Str = @This(); ptr: ?[*]CharType, len: usize, extern fn strncmp(a: ?[*]u8, b: ?[*]u8, len: usize) c_int; pub fn fromSlice(str: []const CharType) Str { return .{ .ptr = @constCast(str.ptr), .len = str.len, }; } pub fn slice(str: *const Str) []CharType { if (str.ptr) |p| { return p[0..str.len]; } return &[_]CharType{}; } pub fn sliceInner(str: *const Str, start: u64, end: u64) []CharType { if (str.ptr) |p| { assert(start <= end, "{}.sliceLen: start <= end", .{typename()}, @src()); assert(end <= str.len, "{}.sliceLen: end <= str.len", .{typename()}, @src()); return p[start..end]; } return &[_]CharType{}; } pub fn fromBuffer(len: u64, buffer: ?[]CharType) Str { return .{ .ptr = buffer, .len = @intCast(len), }; } pub fn pushBuffer(arena: *Arena, buffer: []u8) Str { var str: Str = undefined; str.len = buffer.len; str.ptr = arena.pushArray(CharType, buffer.len + 1); @memcpy(str.ptr[0..buffer.len], buffer); str.ptr[buffer.len] = 0; return str; } pub fn pushCopy(str: *const Str, arena: *Arena) Str { return pushBuffer(arena, str.ptr[0..str.len]); } pub fn pushSlice(str: *const Str, arena: *Arena, start: usize, end: usize) Str { return pushBuffer(arena, str.ptr[start..end]); } pub fn pushf(arena: *Arena, comptime format: []const u8, args: anytype) AllocError!Str { if (CharType != u8) { @compileError("pushf() is only supported for Str8"); } var str: Str = undefined; str.len = @intCast(std.fmt.count(format, args)); str.ptr = (try arena.pushArray(CharType, str.len + 1)).ptr; _ = std.fmt.bufPrintZ(str.ptr.?[0 .. str.len + 1], format, args) catch unreachable; return str; } pub fn join(arena: *Arena, strings: []const []const CharType) AllocError!Str { const empty = &[_]CharType{}; return collate(arena, strings, empty, empty, empty); } pub fn collate( arena: *Arena, strings: []const []const CharType, prefix: []const CharType, separator: []const CharType, postfix: []const CharType, ) AllocError!Str { var strings_total_len: usize = 0; for (strings) |s| { strings_total_len += s.len; } var str: Str = undefined; str.len = prefix.len + strings_total_len + (strings.len - 1) * separator.len + postfix.len; str.ptr = (try arena.pushArray(CharType, str.len + 1)).ptr; @memcpy(str.ptr.?[0..prefix.len], prefix); var offset = prefix.len; for (strings, 0..) |list_str, index| { if (index > 0) { @memcpy(str.ptr.?[offset .. offset + separator.len], separator); offset += separator.len; } @memcpy(str.ptr.?[offset .. offset + list_str.len], list_str); offset += list_str.len; } @memcpy(str.ptr.?[offset .. offset + postfix.len], postfix); offset += postfix.len; str.ptr.?[str.len] = 0; return str; } pub fn split(str: *const Str, arena: *Arena, separators: StrList) AllocError!StrList { var list = StrList.init(); if (str.ptr == null) { return list; } const ptr = str.ptr.?; var offset: usize = 0; var offset_substring: usize = 0; while (offset < str.len) { const haystack = ptr[offset..str.len]; var separator_iter = separators.iter(); while (separator_iter.next()) |list_sep| { if (std.mem.startsWith(CharType, haystack, list_sep.string.slice()) and list_sep.string.len > 0) { var substr = ptr[offset_substring..offset]; if (separators.containsSlice(substr)) { substr = ptr[offset..offset]; } try list.pushSlice(arena, substr); // -1 / +1 to account for offset += 1 at the end of the loop offset += list_sep.string.len - 1; offset_substring = offset + 1; break; } } offset += 1; } if (offset_substring != offset) { var substr = ptr[offset_substring..offset]; try list.pushSlice(arena, substr); } return list; } pub fn cmp(a: *const Str, b: *const Str) std.math.Order { if (CharType != u8) { @compileError("cmp() is only supported for Str8"); } const value = strncmp(a.ptr, b.ptr, std.math.min(a.len, b.len)); if (value < 0) { return .lt; } else if (value == 0) { return .eq; } else { return .gt; } } fn typename() []const u8 { return switch (CharType) { u8 => "Str8", u16 => "Str16", u32 => "Str32", else => unreachable, }; } }; } pub const Str8 = stringType(u8); pub const Str16 = stringType(u16); pub const Str32 = stringType(u32); pub const Str8ListElt = Str8.StrListElt; pub const Str16ListElt = Str16.StrListElt; pub const Str32ListElt = Str32.StrListElt; pub const Str8List = Str8.StrList; pub const Str16List = Str16.StrList; pub const Str32List = Str32.StrList; //------------------------------------------------------------------------------------------ // [UTF8] //------------------------------------------------------------------------------------------ pub const Utf32 = u32; pub const Utf8Dec = extern struct { code_point: Utf32, // decoded codepoint size: u32, // size of corresponding oc_utf8 sequence }; pub const Utf8 = struct { // getting sizes / offsets / indices extern fn oc_utf8_size_from_leading_char(leadingChar: c_char) u32; extern fn oc_utf8_codepoint_size(code_point: Utf32) u32; extern fn oc_utf8_codepoint_count_for_string(string: Str8) u64; extern fn oc_utf8_byte_count_for_codepoints(code_points: Str32) u64; extern fn oc_utf8_next_offset(string: Str8, byteOffset: u64) u64; extern fn oc_utf8_prev_offset(string: Str8, byteOffset: u64) u64; pub const sizeFromLeadingChar = oc_utf8_size_from_leading_char; pub const codepointSize = oc_utf8_codepoint_size; pub const codepointCountForString = oc_utf8_codepoint_count_for_string; pub const byteCountForCodepoints = oc_utf8_byte_count_for_codepoints; pub const nextOffset = oc_utf8_next_offset; pub const prevOffset = oc_utf8_prev_offset; // encoding / decoding extern fn oc_utf8_decode(string: Str8) Utf8Dec; //NOTE: decode a single oc_utf8 sequence at start of string extern fn oc_utf8_decode_at(string: Str8, offset: u64) Utf8Dec; //NOTE: decode a single oc_utf8 sequence starting at byte offset extern fn oc_utf8_encode(dst: [*]u8, code_point: Utf32) Str8; //NOTE: encode codepoint into backing buffer dst extern fn oc_utf8_to_codepoints(maxCount: u64, backing: [*]Utf32, string: Str8) Str32; extern fn oc_utf8_from_codepoints(maxBytes: u64, backing: [*]c_char, code_points: Str32) Str8; extern fn oc_utf8_push_to_codepoints(arena: *Arena, string: Str8) Str32; extern fn oc_utf8_push_from_codepoints(arena: *Arena, code_points: Str32) Str8; pub const decode = oc_utf8_decode; pub const decodeAt = oc_utf8_decode_at; pub const encode = oc_utf8_encode; pub const toCodepoints = oc_utf8_to_codepoints; pub const fromCodepoints = oc_utf8_from_codepoints; pub const pushToCodepoints = oc_utf8_push_to_codepoints; pub const pushFromCodepoints = oc_utf8_push_from_codepoints; }; //------------------------------------------------------------------------------------------ // [UTF8] Unicode //------------------------------------------------------------------------------------------ pub const UnicodeRange = extern struct { first_code_point: Utf32, count: u32, extern const OC_UNICODE_BASIC_LATIN: UnicodeRange; extern const OC_UNICODE_C1_CONTROLS_AND_LATIN_1_SUPPLEMENT: UnicodeRange; extern const OC_UNICODE_LATIN_EXTENDED_A: UnicodeRange; extern const OC_UNICODE_LATIN_EXTENDED_B: UnicodeRange; extern const OC_UNICODE_IPA_EXTENSIONS: UnicodeRange; extern const OC_UNICODE_SPACING_MODIFIER_LETTERS: UnicodeRange; extern const OC_UNICODE_COMBINING_DIACRITICAL_MARKS: UnicodeRange; extern const OC_UNICODE_GREEK_COPTIC: UnicodeRange; extern const OC_UNICODE_CYRILLIC: UnicodeRange; extern const OC_UNICODE_CYRILLIC_SUPPLEMENT: UnicodeRange; extern const OC_UNICODE_ARMENIAN: UnicodeRange; extern const OC_UNICODE_HEBREW: UnicodeRange; extern const OC_UNICODE_ARABIC: UnicodeRange; extern const OC_UNICODE_SYRIAC: UnicodeRange; extern const OC_UNICODE_THAANA: UnicodeRange; extern const OC_UNICODE_DEVANAGARI: UnicodeRange; extern const OC_UNICODE_BENGALI_ASSAMESE: UnicodeRange; extern const OC_UNICODE_GURMUKHI: UnicodeRange; extern const OC_UNICODE_GUJARATI: UnicodeRange; extern const OC_UNICODE_ORIYA: UnicodeRange; extern const OC_UNICODE_TAMIL: UnicodeRange; extern const OC_UNICODE_TELUGU: UnicodeRange; extern const OC_UNICODE_KANNADA: UnicodeRange; extern const OC_UNICODE_MALAYALAM: UnicodeRange; extern const OC_UNICODE_SINHALA: UnicodeRange; extern const OC_UNICODE_THAI: UnicodeRange; extern const OC_UNICODE_LAO: UnicodeRange; extern const OC_UNICODE_TIBETAN: UnicodeRange; extern const OC_UNICODE_MYANMAR: UnicodeRange; extern const OC_UNICODE_GEORGIAN: UnicodeRange; extern const OC_UNICODE_HANGUL_JAMO: UnicodeRange; extern const OC_UNICODE_ETHIOPIC: UnicodeRange; extern const OC_UNICODE_CHEROKEE: UnicodeRange; extern const OC_UNICODE_UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS: UnicodeRange; extern const OC_UNICODE_OGHAM: UnicodeRange; extern const OC_UNICODE_RUNIC: UnicodeRange; extern const OC_UNICODE_TAGALOG: UnicodeRange; extern const OC_UNICODE_HANUNOO: UnicodeRange; extern const OC_UNICODE_BUHID: UnicodeRange; extern const OC_UNICODE_TAGBANWA: UnicodeRange; extern const OC_UNICODE_KHMER: UnicodeRange; extern const OC_UNICODE_MONGOLIAN: UnicodeRange; extern const OC_UNICODE_LIMBU: UnicodeRange; extern const OC_UNICODE_TAI_LE: UnicodeRange; extern const OC_UNICODE_KHMER_SYMBOLS: UnicodeRange; extern const OC_UNICODE_PHONETIC_EXTENSIONS: UnicodeRange; extern const OC_UNICODE_LATIN_EXTENDED_ADDITIONAL: UnicodeRange; extern const OC_UNICODE_GREEK_EXTENDED: UnicodeRange; extern const OC_UNICODE_GENERAL_PUNCTUATION: UnicodeRange; extern const OC_UNICODE_SUPERSCRIPTS_AND_SUBSCRIPTS: UnicodeRange; extern const OC_UNICODE_CURRENCY_SYMBOLS: UnicodeRange; extern const OC_UNICODE_COMBINING_DIACRITICAL_MARKS_FOR_SYMBOLS: UnicodeRange; extern const OC_UNICODE_LETTERLIKE_SYMBOLS: UnicodeRange; extern const OC_UNICODE_NUMBER_FORMS: UnicodeRange; extern const OC_UNICODE_ARROWS: UnicodeRange; extern const OC_UNICODE_MATHEMATICAL_OPERATORS: UnicodeRange; extern const OC_UNICODE_MISCELLANEOUS_TECHNICAL: UnicodeRange; extern const OC_UNICODE_CONTROL_PICTURES: UnicodeRange; extern const OC_UNICODE_OPTICAL_CHARACTER_RECOGNITION: UnicodeRange; extern const OC_UNICODE_ENCLOSED_ALPHANUMERICS: UnicodeRange; extern const OC_UNICODE_BOX_DRAWING: UnicodeRange; extern const OC_UNICODE_BLOCK_ELEMENTS: UnicodeRange; extern const OC_UNICODE_GEOMETRIC_SHAPES: UnicodeRange; extern const OC_UNICODE_MISCELLANEOUS_SYMBOLS: UnicodeRange; extern const OC_UNICODE_DINGBATS: UnicodeRange; extern const OC_UNICODE_MISCELLANEOUS_MATHEMATICAL_SYMBOLS_A: UnicodeRange; extern const OC_UNICODE_SUPPLEMENTAL_ARROWS_A: UnicodeRange; extern const OC_UNICODE_BRAILLE_PATTERNS: UnicodeRange; extern const OC_UNICODE_SUPPLEMENTAL_ARROWS_B: UnicodeRange; extern const OC_UNICODE_MISCELLANEOUS_MATHEMATICAL_SYMBOLS_B: UnicodeRange; extern const OC_UNICODE_SUPPLEMENTAL_MATHEMATICAL_OPERATORS: UnicodeRange; extern const OC_UNICODE_MISCELLANEOUS_SYMBOLS_AND_ARROWS: UnicodeRange; extern const OC_UNICODE_CJK_RADICALS_SUPPLEMENT: UnicodeRange; extern const OC_UNICODE_KANGXI_RADICALS: UnicodeRange; extern const OC_UNICODE_IDEOGRAPHIC_DESCRIPTION_CHARACTERS: UnicodeRange; extern const OC_UNICODE_CJK_SYMBOLS_AND_PUNCTUATION: UnicodeRange; extern const OC_UNICODE_HIRAGANA: UnicodeRange; extern const OC_UNICODE_KATAKANA: UnicodeRange; extern const OC_UNICODE_BOPOMOFO: UnicodeRange; extern const OC_UNICODE_HANGUL_COMPATIBILITY_JAMO: UnicodeRange; extern const OC_UNICODE_KANBUN_KUNTEN: UnicodeRange; extern const OC_UNICODE_BOPOMOFO_EXTENDED: UnicodeRange; extern const OC_UNICODE_KATAKANA_PHONETIC_EXTENSIONS: UnicodeRange; extern const OC_UNICODE_ENCLOSED_CJK_LETTERS_AND_MONTHS: UnicodeRange; extern const OC_UNICODE_CJK_COMPATIBILITY: UnicodeRange; extern const OC_UNICODE_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A: UnicodeRange; extern const OC_UNICODE_YIJING_HEXAGRAM_SYMBOLS: UnicodeRange; extern const OC_UNICODE_CJK_UNIFIED_IDEOGRAPHS: UnicodeRange; extern const OC_UNICODE_YI_SYLLABLES: UnicodeRange; extern const OC_UNICODE_YI_RADICALS: UnicodeRange; extern const OC_UNICODE_HANGUL_SYLLABLES: UnicodeRange; extern const OC_UNICODE_HIGH_SURROGATE_AREA: UnicodeRange; extern const OC_UNICODE_LOW_SURROGATE_AREA: UnicodeRange; extern const OC_UNICODE_PRIVATE_USE_AREA: UnicodeRange; extern const OC_UNICODE_CJK_COMPATIBILITY_IDEOGRAPHS: UnicodeRange; extern const OC_UNICODE_ALPHABETIC_PRESENTATION_FORMS: UnicodeRange; extern const OC_UNICODE_ARABIC_PRESENTATION_FORMS_A: UnicodeRange; extern const OC_UNICODE_VARIATION_SELECTORS: UnicodeRange; extern const OC_UNICODE_COMBINING_HALF_MARKS: UnicodeRange; extern const OC_UNICODE_CJK_COMPATIBILITY_FORMS: UnicodeRange; extern const OC_UNICODE_SMALL_FORM_VARIANTS: UnicodeRange; extern const OC_UNICODE_ARABIC_PRESENTATION_FORMS_B: UnicodeRange; extern const OC_UNICODE_HALFWIDTH_AND_FULLWIDTH_FORMS: UnicodeRange; extern const OC_UNICODE_SPECIALS: UnicodeRange; extern const OC_UNICODE_LINEAR_B_SYLLABARY: UnicodeRange; extern const OC_UNICODE_LINEAR_B_IDEOGRAMS: UnicodeRange; extern const OC_UNICODE_AEGEAN_NUMBERS: UnicodeRange; extern const OC_UNICODE_OLD_ITALIC: UnicodeRange; extern const OC_UNICODE_GOTHIC: UnicodeRange; extern const OC_UNICODE_UGARITIC: UnicodeRange; extern const OC_UNICODE_DESERET: UnicodeRange; extern const OC_UNICODE_SHAVIAN: UnicodeRange; extern const OC_UNICODE_OSMANYA: UnicodeRange; extern const OC_UNICODE_CYPRIOT_SYLLABARY: UnicodeRange; extern const OC_UNICODE_BYZANTINE_MUSICAL_SYMBOLS: UnicodeRange; extern const OC_UNICODE_MUSICAL_SYMBOLS: UnicodeRange; extern const OC_UNICODE_TAI_XUAN_JING_SYMBOLS: UnicodeRange; extern const OC_UNICODE_MATHEMATICAL_ALPHANUMERIC_SYMBOLS: UnicodeRange; extern const OC_UNICODE_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B: UnicodeRange; extern const OC_UNICODE_CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT: UnicodeRange; extern const OC_UNICODE_TAGS: UnicodeRange; extern const OC_UNICODE_VARIATION_SELECTORS_SUPPLEMENT: UnicodeRange; extern const OC_UNICODE_SUPPLEMENTARY_PRIVATE_USE_AREA_A: UnicodeRange; extern const OC_UNICODE_SUPPLEMENTARY_PRIVATE_USE_AREA_B: UnicodeRange; pub const Enum = enum { BasicLatin, C1ControlsAndLatin1Supplement, LatinExtendedA, LatinExtendedB, IpaExtensions, SpacingModifierLetters, CombiningDiacriticalMarks, GreekCoptic, Cyrillic, CyrillicSupplement, Armenian, Hebrew, Arabic, Syriac, Thaana, Devanagari, BengaliAssamese, Gurmukhi, Gujarati, Oriya, Tamil, Telugu, Kannada, Malayalam, Sinhala, Thai, Lao, Tibetan, Myanmar, Georgian, HangulJamo, Ethiopic, Cherokee, UnifiedCanadianAboriginalSyllabics, Ogham, Runic, Tagalog, Hanunoo, Buhid, Tagbanwa, Khmer, Mongolian, Limbu, TaiLe, KhmerSymbols, PhoneticExtensions, LatinExtendedAdditional, GreekExtended, GeneralPunctuation, SuperscriptsAndSubscripts, CurrencySymbols, CombiningDiacriticalMarksForSymbols, LetterlikeSymbols, NumberForms, Arrows, MathematicalOperators, MiscellaneousTechnical, ControlPictures, OpticalCharacterRecognition, EnclosedAlphanumerics, BoxDrawing, BlockElements, GeometricShapes, MiscellaneousSymbols, Dingbats, MiscellaneousMathematicalSymbolsA, SupplementalArrowsA, BraillePatterns, SupplementalArrowsB, MiscellaneousMathematicalSymbolsB, SupplementalMathematicalOperators, MiscellaneousSymbolsAndArrows, CjkRadicalsSupplement, KangxiRadicals, IdeographicDescriptionCharacters, CjkSymbolsAndPunctuation, Hiragana, Katakana, Bopomofo, HangulCompatibilityJamo, KanbunKunten, BopomofoExtended, KatakanaPhoneticExtensions, EnclosedCjkLettersAndMonths, CjkCompatibility, CjkUnifiedIdeographsExtensionA, YijingHexagramSymbols, CjkUnifiedIdeographs, YiSyllables, YiRadicals, HangulSyllables, HighSurrogateArea, LowSurrogateArea, PrivateUseArea, CjkCompatibilityIdeographs, AlphabeticPresentationForms, ArabicPresentationFormsA, VariationSelectors, CombiningHalfMarks, CjkCompatibilityForms, SmallFormVariants, ArabicPresentationFormsB, HalfwidthAndFullwidthForms, Specials, LinearBSyllabary, LinearBIdeograms, AegeanNumbers, OldItalic, Gothic, Ugaritic, Deseret, Shavian, Osmanya, CypriotSyllabary, ByzantineMusicalSymbols, MusicalSymbols, TaiXuanJingSymbols, MathematicalAlphanumericSymbols, CjkUnifiedIdeographsExtensionB, CjkCompatibilityIdeographsSupplement, Tags, VariationSelectorsSupplement, SupplementaryPrivateUseAreaA, SupplementaryPrivateUseAreaB, }; pub fn range(comptime enums: []const Enum) [enums.len]UnicodeRange { var r: [enums.len]UnicodeRange = undefined; for (enums, 0..r.len) |e, i| { r[i] = switch (e) { .BasicLatin => OC_UNICODE_BASIC_LATIN, .C1ControlsAndLatin1Supplement => OC_UNICODE_C1_CONTROLS_AND_LATIN_1_SUPPLEMENT, .LatinExtendedA => OC_UNICODE_LATIN_EXTENDED_A, .LatinExtendedB => OC_UNICODE_LATIN_EXTENDED_B, .IpaExtensions => OC_UNICODE_IPA_EXTENSIONS, .SpacingModifierLetters => OC_UNICODE_SPACING_MODIFIER_LETTERS, .CombiningDiacriticalMarks => OC_UNICODE_COMBINING_DIACRITICAL_MARKS, .GreekCoptic => OC_UNICODE_GREEK_COPTIC, .Cyrillic => OC_UNICODE_CYRILLIC, .CyrillicSupplement => OC_UNICODE_CYRILLIC_SUPPLEMENT, .Armenian => OC_UNICODE_ARMENIAN, .Hebrew => OC_UNICODE_HEBREW, .Arabic => OC_UNICODE_ARABIC, .Syriac => OC_UNICODE_SYRIAC, .Thaana => OC_UNICODE_THAANA, .Devanagari => OC_UNICODE_DEVANAGARI, .BengaliAssamese => OC_UNICODE_BENGALI_ASSAMESE, .Gurmukhi => OC_UNICODE_GURMUKHI, .Gujarati => OC_UNICODE_GUJARATI, .Oriya => OC_UNICODE_ORIYA, .Tamil => OC_UNICODE_TAMIL, .Telugu => OC_UNICODE_TELUGU, .Kannada => OC_UNICODE_KANNADA, .Malayalam => OC_UNICODE_MALAYALAM, .Sinhala => OC_UNICODE_SINHALA, .Thai => OC_UNICODE_THAI, .Lao => OC_UNICODE_LAO, .Tibetan => OC_UNICODE_TIBETAN, .Myanmar => OC_UNICODE_MYANMAR, .Georgian => OC_UNICODE_GEORGIAN, .HangulJamo => OC_UNICODE_HANGUL_JAMO, .Ethiopic => OC_UNICODE_ETHIOPIC, .Cherokee => OC_UNICODE_CHEROKEE, .UnifiedCanadianAboriginalSyllabics => OC_UNICODE_UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS, .Ogham => OC_UNICODE_OGHAM, .Runic => OC_UNICODE_RUNIC, .Tagalog => OC_UNICODE_TAGALOG, .Hanunoo => OC_UNICODE_HANUNOO, .Buhid => OC_UNICODE_BUHID, .Tagbanwa => OC_UNICODE_TAGBANWA, .Khmer => OC_UNICODE_KHMER, .Mongolian => OC_UNICODE_MONGOLIAN, .Limbu => OC_UNICODE_LIMBU, .TaiLe => OC_UNICODE_TAI_LE, .KhmerSymbols => OC_UNICODE_KHMER_SYMBOLS, .PhoneticExtensions => OC_UNICODE_PHONETIC_EXTENSIONS, .LatinExtendedAdditional => OC_UNICODE_LATIN_EXTENDED_ADDITIONAL, .GreekExtended => OC_UNICODE_GREEK_EXTENDED, .GeneralPunctuation => OC_UNICODE_GENERAL_PUNCTUATION, .SuperscriptsAndSubscripts => OC_UNICODE_SUPERSCRIPTS_AND_SUBSCRIPTS, .CurrencySymbols => OC_UNICODE_CURRENCY_SYMBOLS, .CombiningDiacriticalMarksForSymbols => OC_UNICODE_COMBINING_DIACRITICAL_MARKS_FOR_SYMBOLS, .LetterlikeSymbols => OC_UNICODE_LETTERLIKE_SYMBOLS, .NumberForms => OC_UNICODE_NUMBER_FORMS, .Arrows => OC_UNICODE_ARROWS, .MathematicalOperators => OC_UNICODE_MATHEMATICAL_OPERATORS, .MiscellaneousTechnical => OC_UNICODE_MISCELLANEOUS_TECHNICAL, .ControlPictures => OC_UNICODE_CONTROL_PICTURES, .OpticalCharacterRecognition => OC_UNICODE_OPTICAL_CHARACTER_RECOGNITION, .EnclosedAlphanumerics => OC_UNICODE_ENCLOSED_ALPHANUMERICS, .BoxDrawing => OC_UNICODE_BOX_DRAWING, .BlockElements => OC_UNICODE_BLOCK_ELEMENTS, .GeometricShapes => OC_UNICODE_GEOMETRIC_SHAPES, .MiscellaneousSymbols => OC_UNICODE_MISCELLANEOUS_SYMBOLS, .Dingbats => OC_UNICODE_DINGBATS, .MiscellaneousMathematicalSymbolsA => OC_UNICODE_MISCELLANEOUS_MATHEMATICAL_SYMBOLS_A, .SupplementalArrowsA => OC_UNICODE_SUPPLEMENTAL_ARROWS_A, .BraillePatterns => OC_UNICODE_BRAILLE_PATTERNS, .SupplementalArrowsB => OC_UNICODE_SUPPLEMENTAL_ARROWS_B, .MiscellaneousMathematicalSymbolsB => OC_UNICODE_MISCELLANEOUS_MATHEMATICAL_SYMBOLS_B, .SupplementalMathematicalOperators => OC_UNICODE_SUPPLEMENTAL_MATHEMATICAL_OPERATORS, .MiscellaneousSymbolsAndArrows => OC_UNICODE_MISCELLANEOUS_SYMBOLS_AND_ARROWS, .CjkRadicalsSupplement => OC_UNICODE_CJK_RADICALS_SUPPLEMENT, .KangxiRadicals => OC_UNICODE_KANGXI_RADICALS, .IdeographicDescriptionCharacters => OC_UNICODE_IDEOGRAPHIC_DESCRIPTION_CHARACTERS, .CjkSymbolsAndPunctuation => OC_UNICODE_CJK_SYMBOLS_AND_PUNCTUATION, .Hiragana => OC_UNICODE_HIRAGANA, .Katakana => OC_UNICODE_KATAKANA, .Bopomofo => OC_UNICODE_BOPOMOFO, .HangulCompatibilityJamo => OC_UNICODE_HANGUL_COMPATIBILITY_JAMO, .KanbunKunten => OC_UNICODE_KANBUN_KUNTEN, .BopomofoExtended => OC_UNICODE_BOPOMOFO_EXTENDED, .KatakanaPhoneticExtensions => OC_UNICODE_KATAKANA_PHONETIC_EXTENSIONS, .EnclosedCjkLettersAndMonths => OC_UNICODE_ENCLOSED_CJK_LETTERS_AND_MONTHS, .CjkCompatibility => OC_UNICODE_CJK_COMPATIBILITY, .CjkUnifiedIdeographsExtensionA => OC_UNICODE_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A, .YijingHexagramSymbols => OC_UNICODE_YIJING_HEXAGRAM_SYMBOLS, .CjkUnifiedIdeographs => OC_UNICODE_CJK_UNIFIED_IDEOGRAPHS, .YiSyllables => OC_UNICODE_YI_SYLLABLES, .YiRadicals => OC_UNICODE_YI_RADICALS, .HangulSyllables => OC_UNICODE_HANGUL_SYLLABLES, .HighSurrogateArea => OC_UNICODE_HIGH_SURROGATE_AREA, .LowSurrogateArea => OC_UNICODE_LOW_SURROGATE_AREA, .PrivateUseArea => OC_UNICODE_PRIVATE_USE_AREA, .CjkCompatibilityIdeographs => OC_UNICODE_CJK_COMPATIBILITY_IDEOGRAPHS, .AlphabeticPresentationForms => OC_UNICODE_ALPHABETIC_PRESENTATION_FORMS, .ArabicPresentationFormsA => OC_UNICODE_ARABIC_PRESENTATION_FORMS_A, .VariationSelectors => OC_UNICODE_VARIATION_SELECTORS, .CombiningHalfMarks => OC_UNICODE_COMBINING_HALF_MARKS, .CjkCompatibilityForms => OC_UNICODE_CJK_COMPATIBILITY_FORMS, .SmallFormVariants => OC_UNICODE_SMALL_FORM_VARIANTS, .ArabicPresentationFormsB => OC_UNICODE_ARABIC_PRESENTATION_FORMS_B, .HalfwidthAndFullwidthForms => OC_UNICODE_HALFWIDTH_AND_FULLWIDTH_FORMS, .Specials => OC_UNICODE_SPECIALS, .LinearBSyllabary => OC_UNICODE_LINEAR_B_SYLLABARY, .LinearBIdeograms => OC_UNICODE_LINEAR_B_IDEOGRAMS, .AegeanNumbers => OC_UNICODE_AEGEAN_NUMBERS, .OldItalic => OC_UNICODE_OLD_ITALIC, .Gothic => OC_UNICODE_GOTHIC, .Ugaritic => OC_UNICODE_UGARITIC, .Deseret => OC_UNICODE_DESERET, .Shavian => OC_UNICODE_SHAVIAN, .Osmanya => OC_UNICODE_OSMANYA, .CypriotSyllabary => OC_UNICODE_CYPRIOT_SYLLABARY, .ByzantineMusicalSymbols => OC_UNICODE_BYZANTINE_MUSICAL_SYMBOLS, .MusicalSymbols => OC_UNICODE_MUSICAL_SYMBOLS, .TaiXuanJingSymbols => OC_UNICODE_TAI_XUAN_JING_SYMBOLS, .MathematicalAlphanumericSymbols => OC_UNICODE_MATHEMATICAL_ALPHANUMERIC_SYMBOLS, .CjkUnifiedIdeographsExtensionB => OC_UNICODE_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B, .CjkCompatibilityIdeographsSupplement => OC_UNICODE_CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT, .Tags => OC_UNICODE_TAGS, .VariationSelectorsSupplement => OC_UNICODE_VARIATION_SELECTORS_SUPPLEMENT, .SupplementaryPrivateUseAreaA => OC_UNICODE_SUPPLEMENTARY_PRIVATE_USE_AREA_A, .SupplementaryPrivateUseAreaB => OC_UNICODE_SUPPLEMENTARY_PRIVATE_USE_AREA_B, }; } return r; } }; //------------------------------------------------------------------------------------------ // [FONT]: fonts //------------------------------------------------------------------------------------------ pub const Font = extern struct { h: u64, extern fn oc_font_nil() Font; extern fn oc_font_is_nil(font: Font) bool; extern fn oc_font_create_from_memory(mem: Str8, range_count: u32, ranges: [*]const UnicodeRange) Font; extern fn oc_font_create_from_file(file: File, range_count: u32, ranges: [*]const UnicodeRange) Font; extern fn oc_font_create_from_path(path: Str8, range_count: u32, ranges: [*]const UnicodeRange) Font; extern fn oc_font_get_glyph_indices(font: Font, code_points: Str32, backing: Str32) Str32; extern fn oc_font_push_glyph_indices(font: Font, arena: *Arena, code_points: Str32) Str32; extern fn oc_font_get_glyph_index(font: Font, code_point: Utf32) u32; extern fn oc_font_destroy(font: Font) void; extern fn oc_font_get_metrics(font: Font) FontMetrics; extern fn oc_font_get_metrics_unscaled(font: Font, em_size: f32) FontMetrics; extern fn oc_font_get_scale_for_em_pixels(font: Font, em_size: f32) f32; extern fn oc_font_text_metrics_utf32(font: Font, font_size: f32, code_points: Str32) TextMetrics; extern fn oc_font_text_metrics(font: Font, font_size: f32, text: Str8) TextMetrics; pub const nil = oc_font_nil; pub const isNil = oc_font_is_nil; pub fn createFromMemory(mem: []const u8, ranges: []const UnicodeRange) Font { return oc_font_create_from_memory(Str8.fromSlice(mem), @intCast(ranges.len), ranges.ptr); } pub fn createFromFile(file: File, ranges: []const UnicodeRange) Font { return oc_font_create_from_file(file, @intCast(ranges.len), ranges.ptr); } pub fn createFromPath(path: []const u8, ranges: []const UnicodeRange) Font { return oc_font_create_from_path(Str8.fromSlice(path), @intCast(ranges.len), ranges.ptr); } pub const getGlyphIndices = oc_font_get_glyph_indices; pub const pushGlyphIndices = oc_font_push_glyph_indices; pub const getGlyphIndex = oc_font_get_glyph_index; pub const destroy = oc_font_destroy; pub const getMetrics = oc_font_get_metrics; pub const getMetricsUnscaled = oc_font_get_metrics_unscaled; pub const getScaleForEmPixels = oc_font_get_scale_for_em_pixels; pub const textMetricsUtf32 = oc_font_text_metrics_utf32; pub const textMetrics = oc_font_text_metrics; }; pub const JointType = enum(c_uint) { Miter, Bevel, None, }; pub const CapType = enum(c_uint) { None, Square, }; pub const FontMetrics = extern struct { ascent: f32, // the extent above the baseline (by convention a positive value extends above the baseline) descent: f32, // the extent below the baseline (by convention, positive value extends below the baseline) line_gap: f32, // spacing between one row's descent and the next row's ascent x_height: f32, // height of the lower case letter 'x' cap_height: f32, // height of the upper case letter 'M' width: f32, // maximum width of the font }; pub const GlyphMetrics = extern struct { ink: Rect, advance: Vec2, }; pub const TextMetrics = extern struct { ink: Rect, logical: Rect, advance: Vec2, }; //------------------------------------------------------------------------------------------ // [APP] //------------------------------------------------------------------------------------------ extern fn oc_request_quit() void; pub const requestQuit = oc_request_quit; //------------------------------------------------------------------------------------------ // [APP] input //------------------------------------------------------------------------------------------ const MouseCursor = enum(c_uint) { Arrow, Resize0, Resize90, Resize45, Resize135, Text, }; extern fn oc_set_cursor(cursor: MouseCursor) void; pub const setCursor = oc_set_cursor; pub const ScanCode = enum(c_uint) { Unknown = 0, Space = 32, Apostrophe = 39, Comma = 44, Minus = 45, Period = 46, Slash = 47, Num0 = 48, Num1 = 49, Num2 = 50, Num3 = 51, Num4 = 52, Num5 = 53, Num6 = 54, Num7 = 55, Num8 = 56, Num9 = 57, Semicolon = 59, Equal = 61, LeftBracket = 91, Backslash = 92, RightBracket = 93, GraveAccent = 96, A = 97, B = 98, C = 99, D = 100, E = 101, F = 102, G = 103, H = 104, I = 105, J = 106, K = 107, L = 108, M = 109, N = 110, O = 111, P = 112, Q = 113, R = 114, S = 115, T = 116, U = 117, V = 118, W = 119, X = 120, Y = 121, Z = 122, World1 = 161, World2 = 162, Escape = 256, Enter = 257, Tab = 258, Backspace = 259, Insert = 260, Delete = 261, Right = 262, Left = 263, Down = 264, Up = 265, PageUp = 266, PageDown = 267, Home = 268, End = 269, CapsLock = 280, ScrollLock = 281, NumLock = 282, PrintScreen = 283, Pause = 284, F1 = 290, F2 = 291, F3 = 292, F4 = 293, F5 = 294, F6 = 295, F7 = 296, F8 = 297, F9 = 298, F10 = 299, F11 = 300, F12 = 301, F13 = 302, F14 = 303, F15 = 304, F16 = 305, F17 = 306, F18 = 307, F19 = 308, F20 = 309, F21 = 310, F22 = 311, F23 = 312, F24 = 313, F25 = 314, Kp0 = 320, Kp1 = 321, Kp2 = 322, Kp3 = 323, Kp4 = 324, Kp5 = 325, Kp6 = 326, Kp7 = 327, Kp8 = 328, Kp9 = 329, KpDecimal = 330, KpDivide = 331, KpMultiply = 332, KpSubtract = 333, KpAdd = 334, KpEnter = 335, KpEqual = 336, LeftShift = 340, LeftControl = 341, LeftAlt = 342, LeftSuper = 343, RightShift = 344, RightControl = 345, RightAlt = 346, RightSuper = 347, Menu = 348, }; pub const KeyCode = enum(c_uint) { Unknown = 0, Space = ' ', Apostrophe = '\'', Comma = ',', Minus = '-', Period = '.', Slash = '/', Num0 = '0', Num1 = '1', Num2 = '2', Num3 = '3', Num4 = '4', Num5 = '5', Num6 = '6', Num7 = '7', Num8 = '8', Num9 = '9', Semicolon = ';', Equal = '=', LeftBracket = '[', Backslash = '\\', RightBracket = ']', GraveAccent = '`', A = 'a', B = 'b', C = 'c', D = 'd', E = 'e', F = 'f', G = 'g', H = 'h', I = 'i', J = 'j', K = 'k', L = 'l', M = 'm', N = 'n', O = 'o', P = 'p', Q = 'q', R = 'r', S = 's', T = 't', U = 'u', V = 'v', W = 'w', X = 'x', Y = 'y', Z = 'z', World1 = 161, World2 = 162, Escape = 256, Enter = 257, Tab = 258, Backspace = 259, Insert = 260, Delete = 261, Right = 262, Left = 263, Down = 264, Up = 265, PageUp = 266, PageDown = 267, Home = 268, End = 269, CapsLock = 280, ScrollLock = 281, NumLock = 282, PrintScreen = 283, Pause = 284, F1 = 290, F2 = 291, F3 = 292, F4 = 293, F5 = 294, F6 = 295, F7 = 296, F8 = 297, F9 = 298, F10 = 299, F11 = 300, F12 = 301, F13 = 302, F14 = 303, F15 = 304, F16 = 305, F17 = 306, F18 = 307, F19 = 308, F20 = 309, F21 = 310, F22 = 311, F23 = 312, F24 = 313, F25 = 314, Kp0 = 320, Kp1 = 321, Kp2 = 322, Kp3 = 323, Kp4 = 324, Kp5 = 325, Kp6 = 326, Kp7 = 327, Kp8 = 328, Kp9 = 329, KpDecimal = 330, KpDivide = 331, KpMultiply = 332, KpSubtract = 333, KpAdd = 334, KpEnter = 335, KpEqual = 336, LeftShift = 340, LeftControl = 341, LeftAlt = 342, LeftSuper = 343, RightShift = 344, RightControl = 345, RightAlt = 346, RightSuper = 347, Menu = 348, Count = 349, }; pub const MouseButton = enum(c_uint) { Left = 0x00, Right = 0x01, Middle = 0x02, Ext1 = 0x03, Ext2 = 0x04, }; //------------------------------------------------------------------------------------------ // [APP] windows //------------------------------------------------------------------------------------------ extern fn oc_window_set_title(title: Str8) void; extern fn oc_window_set_size(size: Vec2) void; pub fn windowSetTitle(title: []const u8) void { oc_window_set_title(Str8.fromSlice(title)); } pub const windowSetSize = oc_window_set_size; //------------------------------------------------------------------------------------------ // [CLOCK] //------------------------------------------------------------------------------------------ pub const clock = struct { pub const Kind = enum(c_uint) { Monotonic, Uptime, Date, }; extern fn oc_clock_time(clock: Kind) f64; pub const time = oc_clock_time; }; //------------------------------------------------------------------------------------------ // [MATH] Vec2 //------------------------------------------------------------------------------------------ pub const Vec2 = extern struct { x: f32, y: f32, pub fn mul(self: Vec2, scalar: f32) Vec2 { return .{ .x = self.x * scalar, .y = self.y * scalar, }; } pub fn add(a: Vec2, b: Vec2) Vec2 { return .{ .x = a.x + b.x, .y = a.y + b.y, }; } }; //------------------------------------------------------------------------------------------ // [MATH] Matrix stack //------------------------------------------------------------------------------------------ pub const Mat2x3 = extern struct { m: [6]f32, extern fn oc_mat2x3_mul(m: Mat2x3, p: Vec2) Vec2; extern fn oc_mat2x3_mul_m(lhs: Mat2x3, rhs: Mat2x3) Mat2x3; extern fn oc_mat2x3_inv(x: Mat2x3) Mat2x3; extern fn oc_mat2x3_rotate(radians: f32) Mat2x3; extern fn oc_mat2x3_translate(x: f32, y: f32) Mat2x3; extern fn oc_matrix_push(matrix: Mat2x3) void; extern fn oc_matrix_pop() void; extern fn oc_matrix_top() Mat2x3; pub const mul = oc_mat2x3_mul; pub const mul_m = oc_mat2x3_mul_m; pub const inv = oc_mat2x3_inv; pub const rotate = oc_mat2x3_rotate; pub const translate = oc_mat2x3_translate; pub fn scale(x: f32, y: f32) Mat2x3 { return .{ .m = .{ x, 0, 0, 0, y, 0 } }; } pub fn scaleUniform(s: f32) Mat2x3 { return .{ .m = .{ s, 0, 0, 0, s, 0 } }; } pub const push = oc_matrix_push; pub const pop = oc_matrix_pop; pub const top = oc_matrix_top; }; //------------------------------------------------------------------------------------------ // [GRAPHICS] Clip stack //------------------------------------------------------------------------------------------ pub const clip = struct { extern fn oc_clip_push(x: f32, y: f32, w: f32, h: f32) void; extern fn oc_clip_pop() void; extern fn oc_clip_top() Rect; pub const push = oc_clip_push; pub const pop = oc_clip_pop; pub const top = oc_clip_top; }; //------------------------------------------------------------------------------------------ // [GRAPHICS]: resources //------------------------------------------------------------------------------------------ pub const Surface = extern struct { h: u64, extern fn oc_surface_nil(void) Surface; extern fn oc_surface_is_nil(surface: Surface) bool; extern fn oc_surface_canvas() Surface; extern fn oc_surface_gles() Surface; extern fn oc_surface_select(surface: Surface) void; extern fn oc_surface_present(surface: Surface) void; extern fn oc_surface_get_size(surface: Surface) Vec2; extern fn oc_surface_contents_scaling(surface: Surface) Vec2; extern fn oc_surface_bring_to_front(surface: Surface) void; extern fn oc_surface_send_to_back(surface: Surface) void; // TODO // extern fn oc_surface_render_commands( // surface: Surface, // color: Color, // primitive_count: u32, // primitives: [*]Primitive, // elt_count: u32, // elements: [*]PathElt, // ) void; pub const nil = oc_surface_nil; pub const isNil = oc_surface_is_nil; pub const canvas = oc_surface_canvas; pub const gles = oc_surface_gles; pub const select = oc_surface_select; pub const present = oc_surface_present; pub const getSize = oc_surface_get_size; pub const contentsScaling = oc_surface_contents_scaling; pub const bringToFront = oc_surface_bring_to_front; pub const sendToBack = oc_surface_send_to_back; // pub const renderCommands = oc_surface_render_commands; }; pub const Image = extern struct { h: u64, extern fn oc_image_nil() Image; extern fn oc_image_is_nil(image: Image) bool; extern fn oc_image_create(surface: Surface, width: u32, height: u32) Image; extern fn oc_image_create_from_rgba8(surface: Surface, width: u32, height: u32, pixels: [*]u8) Image; extern fn oc_image_create_from_memory(surface: Surface, mem: Str8, flip: bool) Image; extern fn oc_image_create_from_file(surface: Surface, file: File, flip: bool) Image; extern fn oc_image_create_from_path(surface: Surface, path: Str8, flip: bool) Image; extern fn oc_image_destroy(image: Image) void; extern fn oc_image_upload_region_rgba8(image: Image, region: Rect, pixels: [*]u8) void; extern fn oc_image_size(image: Image) Vec2; extern fn oc_image_draw(image: Image, rect: Rect) void; extern fn oc_image_draw_region(image: Image, srcRegion: Rect, dstRegion: Rect) void; pub const nil = oc_image_nil; pub const isNil = oc_image_is_nil; pub const create = oc_image_create; pub const createFromRgba8 = oc_image_create_from_rgba8; pub const createFromMemory = oc_image_create_from_memory; pub const createFromFile = oc_image_create_from_file; pub const createFromPath = oc_image_create_from_path; pub const destroy = oc_image_destroy; pub const uploadRegionRgba8 = oc_image_upload_region_rgba8; pub const size = oc_image_size; pub const draw = oc_image_draw; pub const drawRegion = oc_image_draw_region; }; pub const Rect = extern union { Flat: extern struct { x: f32, y: f32, w: f32, h: f32, }, Pairs: extern struct { xy: Vec2, wh: Vec2, }, Array: [4]f32, pub fn xywh(x: f32, y: f32, w: f32, h: f32) Rect { return .{ .Flat = .{ .x = x, .y = y, .w = w, .h = h } }; } }; pub const Color = extern union { Flat: extern struct { r: f32, g: f32, b: f32, a: f32, }, Array: [4]f32, }; //------------------------------------------------------------------------------------------ // [GRAPHICS]: Canvas //------------------------------------------------------------------------------------------ pub const Canvas = extern struct { h: u64, extern fn oc_canvas_nil() Canvas; extern fn oc_canvas_is_nil(canvas: Canvas) bool; extern fn oc_canvas_create() Canvas; extern fn oc_canvas_destroy(canvas: Canvas) void; extern fn oc_canvas_select(canvas: Canvas) Canvas; extern fn oc_render(canvas: Canvas) void; pub const nil = oc_canvas_nil; pub const isNil = oc_canvas_is_nil; pub const create = oc_canvas_create; pub const destroy = oc_canvas_destroy; pub const select = oc_canvas_select; pub const render = oc_render; // vector graphics extern fn oc_clear() void; extern fn oc_fill() void; extern fn oc_stroke() void; pub const clear = oc_clear; pub const fill = oc_fill; pub const stroke = oc_stroke; // attributes setting/getting extern fn oc_set_color(color: Color) void; extern fn oc_set_color_rgba(r: f32, g: f32, b: f32, a: f32) void; extern fn oc_set_width(width: f32) void; extern fn oc_set_tolerance(tolerance: f32) void; extern fn oc_set_joint(joint: JointType) void; extern fn oc_set_max_joint_excursion(max_joint_excursion: f32) void; extern fn oc_set_cap(cap: CapType) void; extern fn oc_set_font(font: Font) void; extern fn oc_set_font_size(size: f32) void; extern fn oc_set_text_flip(flip: bool) void; extern fn oc_set_image(image: Image) void; extern fn oc_set_image_source_region(region: Rect) void; extern fn oc_get_color() Color; extern fn oc_get_width() f32; extern fn oc_get_tolerance() f32; extern fn oc_get_joint() JointType; extern fn oc_get_max_joint_excursion() f32; extern fn oc_get_cap() CapType; extern fn oc_get_font() Font; extern fn oc_get_font_size() f32; extern fn oc_get_text_flip() bool; extern fn oc_get_image() Image; extern fn oc_get_image_source_region() Rect; pub const setColor = oc_set_color; pub const setColorRgba = oc_set_color_rgba; pub const setWidth = oc_set_width; pub const setTolerance = oc_set_tolerance; pub const setJoint = oc_set_joint; pub const setMaxJointExcursion = oc_set_max_joint_excursion; pub const setCap = oc_set_cap; pub const setFont = oc_set_font; pub const setFontSize = oc_set_font_size; pub const setTextFlip = oc_set_text_flip; pub const setImage = oc_set_image; pub const setImageSourceRegion = oc_set_image_source_region; pub const getColor = oc_get_color; pub const getWidth = oc_get_width; pub const getTolerance = oc_get_tolerance; pub const getJoint = oc_get_joint; pub const getMaxJointExcursion = oc_get_max_joint_excursion; pub const getCap = oc_get_cap; pub const getFont = oc_get_font; pub const getFontSize = oc_get_font_size; pub const getTextFlip = oc_get_text_flip; pub const getImage = oc_get_image; pub const getImageSourceRegion = oc_get_image_source_region; // path construction extern fn oc_get_position() Vec2; extern fn oc_move_to(x: f32, y: f32) void; extern fn oc_line_to(x: f32, y: f32) void; extern fn oc_quadratic_to(x1: f32, y1: f32, x2: f32, y2: f32) void; extern fn oc_cubic_to(x1: f32, y1: f32, x2: f32, y2: f32, x3: f32, y3: f32) void; extern fn oc_close_path() void; extern fn oc_glyph_outlines(glyph_indices: Str32) Rect; extern fn oc_codepoints_outlines(string: Str32) void; extern fn oc_text_outlines(string: Str8) void; pub const getPosition = oc_get_position; pub const moveTo = oc_move_to; pub const lineTo = oc_line_to; pub const quadraticTo = oc_quadratic_to; pub const cubicTo = oc_cubic_to; pub const closePath = oc_close_path; pub const glyphOutlines = oc_glyph_outlines; pub const codepointsOutlines = oc_codepoints_outlines; pub const textOutlines = oc_text_outlines; // shape helpers extern fn oc_rectangle_fill(x: f32, y: f32, w: f32, h: f32) void; extern fn oc_rectangle_stroke(x: f32, y: f32, w: f32, h: f32) void; extern fn oc_rounded_rectangle_fill(x: f32, y: f32, w: f32, h: f32, r: f32) void; extern fn oc_rounded_rectangle_stroke(x: f32, y: f32, w: f32, h: f32, r: f32) void; extern fn oc_ellipse_fill(x: f32, y: f32, rx: f32, ry: f32) void; extern fn oc_ellipse_stroke(x: f32, y: f32, rx: f32, ry: f32) void; extern fn oc_circle_fill(x: f32, y: f32, r: f32) void; extern fn oc_circle_stroke(x: f32, y: f32, r: f32) void; extern fn oc_arc(x: f32, y: f32, r: f32, arc_angle: f32, start_angle: f32) void; pub const rectangleFill = oc_rectangle_fill; pub const rectangleStroke = oc_rectangle_stroke; pub const roundedRectangleFill = oc_rounded_rectangle_fill; pub const roundedRectangleStroke = oc_rounded_rectangle_stroke; pub const ellipseFill = oc_ellipse_fill; pub const ellipseStroke = oc_ellipse_stroke; pub const circleFill = oc_circle_fill; pub const circleStroke = oc_circle_stroke; pub const arc = oc_arc; }; //------------------------------------------------------------------------------------------ // [GRAPHICS]: GLES //------------------------------------------------------------------------------------------ // TODO //------------------------------------------------------------------------------------------ // [UI] //------------------------------------------------------------------------------------------ // TODO //------------------------------------------------------------------------------------------ // [FILE IO] basic API //------------------------------------------------------------------------------------------ const File = extern struct { h: u64, extern fn oc_file_nil() File; extern fn oc_file_is_nil(file: File) bool; extern fn oc_file_open(path: Str8, rights: FileAccessFlags, flags: FileOpenFlags) File; extern fn oc_file_open_at(dir: File, path: Str8, rights: FileAccessFlags, flags: FileOpenFlags) File; extern fn oc_file_close(file: File) void; extern fn oc_file_last_error(file: File) IoError; extern fn oc_file_pos(file: File) i64; extern fn oc_file_seek(file: File, offset: i64, whence: FileWhence) i64; extern fn oc_file_write(file: File, size: u64, buffer: ?[*]u8) u64; extern fn oc_file_read(file: File, size: u64, buffer: ?[*]u8) u64; extern fn oc_file_get_status(file: File) FileStatus; extern fn oc_file_size(file: File) u64; extern fn oc_file_open_with_request(path: Str8, rights: FileAccessFlags, flags: FileOpenFlags) File; extern fn oc_file_open_with_dialog(arena: *Arena, rights: FileAccessFlags, flags: FileOpenFlags, desc: *FileDialogDesc) FileOpenWithDialogResult; pub const nil = oc_file_nil; pub const isNil = oc_file_is_nil; pub const open = oc_file_open; pub const openAt = oc_file_open_at; pub const close = oc_file_close; pub const lastError = oc_file_last_error; pub const pos = oc_file_pos; pub const seek = oc_file_seek; pub const write = oc_file_write; pub const read = oc_file_read; pub const getStatus = oc_file_get_status; pub const size = oc_file_size; pub const openWithRequest = oc_file_open_with_request; pub const openWithDialog = oc_file_open_with_dialog; }; const FileOpenFlags = packed struct(u16) { none: bool, append: bool, truncate: bool, create: bool, symlink: bool, no_follow: bool, restrict: bool, }; const FileAccessFlags = packed struct(u16) { none: bool, read: bool, write: bool, }; const FileWhence = enum(c_uint) { Set, End, Current, }; const IoReqId = u16; const IoOp = u32; const IoOpEnum = enum(c_uint) { OpenAt = 0, Close, FStat, Seek, Read, Write, Error, }; const IoReq = extern struct { id: IoReqId, op: IoOp, handle: File, offset: i64, size: u64, buffer: extern union { data: ?[*]u8, unused: u64, // This is a horrible hack to get the same layout on wasm and on host }, type: extern union { open: extern struct { rights: FileAccessFlags, flags: FileOpenFlags, }, whence: FileWhence, }, }; const IoError = enum(i32) { Ok = 0, Unknown, Op, // unsupported operation Handle, // invalid handle Prev, // previously had a fatal error (last error stored on handle) Arg, // invalid argument or argument combination Perm, // access denied Space, // no space left NoEntry, // file or directory does not exist Exists, // file already exists NotDir, // path element is not a directory Dir, // attempted to write directory MaxFiles, // max open files reached MaxLinks, // too many symbolic links in path PathLength, // path too long FileSize, // file too big Overflow, // offset too big NotReady, // no data ready to be read/written Mem, // failed to allocate memory Interrupt, // operation interrupted by a signal Physical, // physical IO error NoDevice, // device not found Walkout, // attempted to walk out of root directory }; const IoCmp = extern struct { id: IoReqId, err: IoError, data: extern union { result: i64, size: u64, offset: i64, handle: File, }, }; const FileType = enum(c_uint) { Unknown, Regular, Directory, Symlink, Block, Character, Fifo, Socket, }; const FilePerm = packed struct(u16) { other_exec: bool, other_write: bool, other_read: bool, group_exec: bool, group_write: bool, group_read: bool, owner_exec: bool, owner_write: bool, owner_read: bool, sticky_bit: bool, set_gid: bool, set_uid: bool, }; const DateStamp = extern struct { seconds: i64, // seconds relative to NTP epoch. fraction: u64, // fraction of seconds elapsed since the time specified by seconds. }; const FileStatus = extern struct { uid: u64, type: FileType, perm: FilePerm, size: u64, creation_date: DateStamp, access_date: DateStamp, modification_date: DateStamp, }; const FileDialogKind = enum(c_uint) { Save, Open, }; const FileDialogFlags = packed struct(u32) { files: bool, directories: bool, multiple: bool, create_directories: bool, }; const FileDialogDesc = extern struct { kind: FileDialogKind, flags: FileDialogFlags, title: Str8, ok_label: Str8, start_at: File, start_path: Str8, filters: Str8List, }; const FileDialogButton = enum(c_uint) { Cancel, Ok, }; const FileOpenWithDialogElt = extern struct { list_elt: ListElt, file: File, }; const FileOpenWithDialogResult = extern struct { button: FileDialogButton, file: File, selection: List, }; //------------------------------------------------------------------------------------------ // [FILE IO] complete io queue api //------------------------------------------------------------------------------------------ extern fn oc_io_wait_single_req(req: *IoReq) IoCmp; pub const ioWaitSingleReq = oc_io_wait_single_req;