diff options
| -rw-r--r-- | core/sys/orca/macros.odin | 293 | ||||
| -rw-r--r-- | core/sys/orca/orca.odin | 2178 | ||||
| -rw-r--r-- | examples/all/all_main.odin | 2 |
3 files changed, 2473 insertions, 0 deletions
diff --git a/core/sys/orca/macros.odin b/core/sys/orca/macros.odin new file mode 100644 index 000000000..9e7dbed85 --- /dev/null +++ b/core/sys/orca/macros.odin @@ -0,0 +1,293 @@ +// File contains implementations of the Orca API that are defined as macros in Orca. + +package orca + +import "core:fmt" + +//////////////////////////////////////////////////////////////////////////////// +// Helpers for logging, asserting and aborting. +//////////////////////////////////////////////////////////////////////////////// + +log_error :: proc "contextless" (msg: cstring, loc := #caller_location) { + log_ext( + .ERROR, + cstring(raw_data(loc.procedure)), + cstring(raw_data(loc.file_path)), + loc.line, + msg, + ) +} + +log_errorf :: proc(format: string, args: ..any, loc := #caller_location) { + log_ext( + .ERROR, + cstring(raw_data(loc.procedure)), + cstring(raw_data(loc.file_path)), + loc.line, + fmt.ctprintf(format, ..args), + ) +} + +log_warning :: proc "contextless" (msg: cstring, loc := #caller_location) { + log_ext( + .WARNING, + cstring(raw_data(loc.procedure)), + cstring(raw_data(loc.file_path)), + loc.line, + msg, + ) +} + +log_warningf :: proc(format: string, args: ..any, loc := #caller_location) { + log_ext( + .WARNING, + cstring(raw_data(loc.procedure)), + cstring(raw_data(loc.file_path)), + loc.line, + fmt.ctprintf(format, ..args), + ) +} + +log_info :: proc "contextless" (msg: cstring, loc := #caller_location) { + log_ext( + .INFO, + cstring(raw_data(loc.procedure)), + cstring(raw_data(loc.file_path)), + loc.line, + msg, + ) +} + +log_infof :: proc(format: string, args: ..any, loc := #caller_location) { + log_ext( + .INFO, + cstring(raw_data(loc.procedure)), + cstring(raw_data(loc.file_path)), + loc.line, + fmt.ctprintf(format, ..args), + ) +} + +abort :: proc "contextless" (msg: cstring, loc := #caller_location) { + abort_ext( + cstring(raw_data(loc.procedure)), + cstring(raw_data(loc.file_path)), + loc.line, + msg, + ) +} + +abortf :: proc(format: string, args: ..any, loc := #caller_location) { + abort_ext( + cstring(raw_data(loc.procedure)), + cstring(raw_data(loc.file_path)), + loc.line, + fmt.ctprintf(format, ..args), + ) +} + +//////////////////////////////////////////////////////////////////////////////// +// Types and helpers for doubly-linked lists. +//////////////////////////////////////////////////////////////////////////////// + +// Get the entry for a given list element. +list_entry :: proc "contextless" (elt: ^list_elt, $T: typeid, $member: string) -> ^T { + return container_of(elt, T, member) +} + +// Get the next entry in a list. +list_next_entry :: proc "contextless" (list: ^list, elt: ^list_elt, $T: typeid, $member: string) -> ^T { + if elt.next != list.last { + return list_entry(elt.next, T, member) + } + + return nil +} + +// Get the previous entry in a list. +list_prev_entry :: proc "contextless" (list: ^list, elt: ^list_elt, $T: typeid, $member: string) -> ^T { + if elt.prev != list.last { + return list_entry(elt.prev, T, member) + } + + return nil +} + +// Same as `list_entry` but `elt` might be `nil`. +list_checked_entry :: proc "contextless" (elt: ^list_elt, $T: typeid, $member: string) -> ^T { + if elt != nil { + return list_entry(elt, T, member) + } + + return nil +} + +list_first_entry :: proc "contextless" (list: ^list, $T: typeid, $member: string) -> ^T { + return list_checked_entry(list.first, T, member) +} + +list_last_entry :: proc "contextless" (list: ^list, $T: typeid, $member: string) -> ^T { + return list_checked_entry(list.last, T, member) +} + +// Example: +// +// _elt: ^list_elt +// for elt in oc.list_for(list, &_elt, int, "elt") { +// } +list_for :: proc "contextless" (list: ^list, elt: ^^list_elt, $T: typeid, $member: string) -> (^T, bool) { + if elt == nil { + assert_fail(#file, #procedure, #line, "elt != nil", "misuse of `list_for`, expected `elt` to not be nil") + } + + if elt^ == nil { + elt^ = list.first + entry := list_checked_entry(elt^, T, member) + return entry, entry != nil + } + + elt^ = elt^.next + entry := list_checked_entry(elt^, T, member) + return entry, entry != nil +} + +list_iter :: list_for + +list_for_reverse :: proc "contextless" (list: ^list, elt: ^^list_elt, $T: typeid, $member: string) -> (^T, bool) { + if elt^ == nil { + elt^ = list.last + entry := list_checked_entry(elt^, T, member) + return entry, entry != nil + } + + elt^ = elt^.prev + entry := list_checked_entry(elt^, T, member) + return entry, entry != nil +} + +list_iter_reverse :: list_for_reverse + +list_pop_front_entry :: proc "contextless" (list: ^list, $T: typeid, $member: string) -> ^T { + if list_empty(list^) { + return nil + } + + return list_entry(list_pop_front(list), T, member) +} + +list_pop_back_entry :: proc "contextless" (list: ^list, $T: typeid, $member: string) -> ^T { + if list_empty(list^) { + return nil + } + + return list_entry(list_pop_back(list), T, member) +} + +//////////////////////////////////////////////////////////////////////////////// +// Base allocator and memory arenas. +//////////////////////////////////////////////////////////////////////////////// + +arena_push_type :: proc "contextless" (arena: ^arena, $T: typeid) -> ^T { + return (^T)(arena_push_aligned(arena, size_of(T), align_of(T))) +} + +arena_push_array :: proc "contextless" (arena: ^arena, $T: typeid, count: u64) -> []T { + return ([^]T)(arena_push_aligned(arena, size_of(T) * count, align_of(T)))[:count] +} + +scratch_end :: arena_scope_end + +//////////////////////////////////////////////////////////////////////////////// +// String slices and string lists. +//////////////////////////////////////////////////////////////////////////////// + +str8_list_first :: proc "contextless" (sl: ^str8_list) -> str8 { + if list_empty(sl.list) { + return "" + } + + return list_first_entry(&sl.list, str8_elt, "listElt").string +} + +str8_list_last :: proc "contextless" (sl: ^str8_list) -> str8 { + if list_empty(sl.list) { + return "" + } + + return list_last_entry(&sl.list, str8_elt, "listElt").string +} + +str8_list_for :: proc "contextless" (list: ^str8_list, elt: ^^list_elt) -> (^str8_elt, bool) { + return list_for(&list.list, elt, str8_elt, "listElt") +} + +str8_list_iter :: str8_list_for + +str8_list_empty :: proc "contextless" (list: str8_list) -> bool { + return list_empty(list.list) +} + +str16_list_first :: proc "contextless" (sl: ^str16_list) -> str16 { + if list_empty(sl.list) { + return {} + } + + return list_first_entry(&sl.list, str16_elt, "listElt").string +} + +str16_list_last :: proc "contextless" (sl: ^str16_list) -> str16 { + if list_empty(sl.list) { + return {} + } + + return list_last_entry(&sl.list, str16_elt, "listElt").string +} + +str16_list_for :: proc "contextless" (list: ^str16_list, elt: ^^list_elt) -> (^str16_elt, bool) { + return list_for(&list.list, elt, str16_elt, "listElt") +} + +str32_list_first :: proc "contextless" (sl: ^str32_list) -> str32 { + if list_empty(sl.list) { + return {} + } + + return list_first_entry(&sl.list, str32_elt, "listElt").string +} + +str32_list_last :: proc "contextless" (sl: ^str32_list) -> str32 { + if list_empty(sl.list) { + return {} + } + + return list_last_entry(&sl.list, str32_elt, "listElt").string +} + +str32_list_for :: proc "contextless" (list: ^str32_list, elt: ^^list_elt) -> (^str32_elt, bool) { + return list_for(&list.list, elt, str32_elt, "listElt") +} + +@(deferred_none=ui_box_end) +ui_container :: proc "contextless" (name: string, flags: ui_flags = {}) -> ^ui_box { + return ui_box_begin_str8(name, flags) +} + +@(deferred_none=ui_end_frame) +ui_frame :: proc "contextless" (frame_size: [2]f32, style: ui_style, mask: ui_style_mask) { + ui_begin_frame(frame_size, style, mask) +} + +@(deferred_none=ui_panel_end) +ui_panel :: proc "contextless" (name: cstring, flags: ui_flags) { + ui_panel_begin(name, flags) +} + +@(deferred_none=ui_menu_end) +ui_menu :: proc "contextless" (name: cstring) { + ui_menu_begin(name) +} + +@(deferred_none=ui_menu_bar_end) +ui_menu_bar :: proc "contextless" (name: cstring) { + ui_menu_bar_begin(name) +} diff --git a/core/sys/orca/orca.odin b/core/sys/orca/orca.odin new file mode 100644 index 000000000..d1e7dbf66 --- /dev/null +++ b/core/sys/orca/orca.odin @@ -0,0 +1,2178 @@ +package orca + +import "core:c" + +char :: c.char + +// currently missing in the api.json +window :: distinct u64 + +// currently missing in the api.json +pool :: struct { + arena: arena, + freeList: list, + blockSize: u64, +} + +@(link_prefix="OC_") +foreign { + UI_DARK_THEME: ui_theme + UI_LIGHT_THEME: ui_theme + + UI_DARK_PALETTE: ui_palette + UI_LIGHT_PALETTE: ui_palette +} + + +SYS_MAX_ERROR :: 1024 + +sys_err_def :: struct { + msg: [SYS_MAX_ERROR]u8 `fmt:"s,0"`, + code: i32, +} + +@(link_prefix="oc_") +foreign { + sys_error: sys_err_def +} +UNICODE_BASIC_LATIN :: unicode_range { 0x0000, 127 } +UNICODE_C1_CONTROLS_AND_LATIN_1_SUPPLEMENT :: unicode_range { 0x0080, 127 } +UNICODE_LATIN_EXTENDED_A :: unicode_range { 0x0100, 127 } +UNICODE_LATIN_EXTENDED_B :: unicode_range { 0x0180, 207 } +UNICODE_IPA_EXTENSIONS :: unicode_range { 0x0250, 95 } +UNICODE_SPACING_MODIFIER_LETTERS :: unicode_range { 0x02b0, 79 } +UNICODE_COMBINING_DIACRITICAL_MARKS :: unicode_range { 0x0300, 111 } +UNICODE_GREEK_COPTIC :: unicode_range { 0x0370, 143 } +UNICODE_CYRILLIC :: unicode_range { 0x0400, 255 } +UNICODE_CYRILLIC_SUPPLEMENT :: unicode_range { 0x0500, 47 } +UNICODE_ARMENIAN :: unicode_range { 0x0530, 95 } +UNICODE_HEBREW :: unicode_range { 0x0590, 111 } +UNICODE_ARABIC :: unicode_range { 0x0600, 255 } +UNICODE_SYRIAC :: unicode_range { 0x0700, 79 } +UNICODE_THAANA :: unicode_range { 0x0780, 63 } +UNICODE_DEVANAGARI :: unicode_range { 0x0900, 127 } +UNICODE_BENGALI_ASSAMESE :: unicode_range { 0x0980, 127 } +UNICODE_GURMUKHI :: unicode_range { 0x0a00, 127 } +UNICODE_GUJARATI :: unicode_range { 0x0a80, 127 } +UNICODE_ORIYA :: unicode_range { 0x0b00, 127 } +UNICODE_TAMIL :: unicode_range { 0x0b80, 127 } +UNICODE_TELUGU :: unicode_range { 0x0c00, 127 } +UNICODE_KANNADA :: unicode_range { 0x0c80, 127 } +UNICODE_MALAYALAM :: unicode_range { 0x0d00, 255 } +UNICODE_SINHALA :: unicode_range { 0x0d80, 127 } +UNICODE_THAI :: unicode_range { 0x0e00, 127 } +UNICODE_LAO :: unicode_range { 0x0e80, 127 } +UNICODE_TIBETAN :: unicode_range { 0x0f00, 255 } +UNICODE_MYANMAR :: unicode_range { 0x1000, 159 } +UNICODE_GEORGIAN :: unicode_range { 0x10a0, 95 } +UNICODE_HANGUL_JAMO :: unicode_range { 0x1100, 255 } +UNICODE_ETHIOPIC :: unicode_range { 0x1200, 383 } +UNICODE_CHEROKEE :: unicode_range { 0x13a0, 95 } +UNICODE_UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS :: unicode_range { 0x1400, 639 } +UNICODE_OGHAM :: unicode_range { 0x1680, 31 } +UNICODE_RUNIC :: unicode_range { 0x16a0, 95 } +UNICODE_TAGALOG :: unicode_range { 0x1700, 31 } +UNICODE_HANUNOO :: unicode_range { 0x1720, 31 } +UNICODE_BUHID :: unicode_range { 0x1740, 31 } +UNICODE_TAGBANWA :: unicode_range { 0x1760, 31 } +UNICODE_KHMER :: unicode_range { 0x1780, 127 } +UNICODE_MONGOLIAN :: unicode_range { 0x1800, 175 } +UNICODE_LIMBU :: unicode_range { 0x1900, 79 } +UNICODE_TAI_LE :: unicode_range { 0x1950, 47 } +UNICODE_KHMER_SYMBOLS :: unicode_range { 0x19e0, 31 } +UNICODE_PHONETIC_EXTENSIONS :: unicode_range { 0x1d00, 127 } +UNICODE_LATIN_EXTENDED_ADDITIONAL :: unicode_range { 0x1e00, 255 } +UNICODE_GREEK_EXTENDED :: unicode_range { 0x1f00, 255 } +UNICODE_GENERAL_PUNCTUATION :: unicode_range { 0x2000, 111 } +UNICODE_SUPERSCRIPTS_AND_SUBSCRIPTS :: unicode_range { 0x2070, 47 } +UNICODE_CURRENCY_SYMBOLS :: unicode_range { 0x20a0, 47 } +UNICODE_COMBINING_DIACRITICAL_MARKS_FOR_SYMBOLS :: unicode_range { 0x20d0, 47 } +UNICODE_LETTERLIKE_SYMBOLS :: unicode_range { 0x2100, 79 } +UNICODE_NUMBER_FORMS :: unicode_range { 0x2150, 63 } +UNICODE_ARROWS :: unicode_range { 0x2190, 111 } +UNICODE_MATHEMATICAL_OPERATORS :: unicode_range { 0x2200, 255 } +UNICODE_MISCELLANEOUS_TECHNICAL :: unicode_range { 0x2300, 255 } +UNICODE_CONTROL_PICTURES :: unicode_range { 0x2400, 63 } +UNICODE_OPTICAL_CHARACTER_RECOGNITION :: unicode_range { 0x2440, 31 } +UNICODE_ENCLOSED_ALPHANUMERICS :: unicode_range { 0x2460, 159 } +UNICODE_BOX_DRAWING :: unicode_range { 0x2500, 127 } +UNICODE_BLOCK_ELEMENTS :: unicode_range { 0x2580, 31 } +UNICODE_GEOMETRIC_SHAPES :: unicode_range { 0x25a0, 95 } +UNICODE_MISCELLANEOUS_SYMBOLS :: unicode_range { 0x2600, 255 } +UNICODE_DINGBATS :: unicode_range { 0x2700, 191 } +UNICODE_MISCELLANEOUS_MATHEMATICAL_SYMBOLS_A :: unicode_range { 0x27c0, 47 } +UNICODE_SUPPLEMENTAL_ARROWS_A :: unicode_range { 0x27f0, 15 } +UNICODE_BRAILLE_PATTERNS :: unicode_range { 0x2800, 255 } +UNICODE_SUPPLEMENTAL_ARROWS_B :: unicode_range { 0x2900, 127 } +UNICODE_MISCELLANEOUS_MATHEMATICAL_SYMBOLS_B :: unicode_range { 0x2980, 127 } +UNICODE_SUPPLEMENTAL_MATHEMATICAL_OPERATORS :: unicode_range { 0x2a00, 255 } +UNICODE_MISCELLANEOUS_SYMBOLS_AND_ARROWS :: unicode_range { 0x2b00, 255 } +UNICODE_CJK_RADICALS_SUPPLEMENT :: unicode_range { 0x2e80, 127 } +UNICODE_KANGXI_RADICALS :: unicode_range { 0x2f00, 223 } +UNICODE_IDEOGRAPHIC_DESCRIPTION_CHARACTERS :: unicode_range { 0x2ff0, 15 } +UNICODE_CJK_SYMBOLS_AND_PUNCTUATION :: unicode_range { 0x3000, 63 } +UNICODE_HIRAGANA :: unicode_range { 0x3040, 95 } +UNICODE_KATAKANA :: unicode_range { 0x30a0, 95 } +UNICODE_BOPOMOFO :: unicode_range { 0x3100, 47 } +UNICODE_HANGUL_COMPATIBILITY_JAMO :: unicode_range { 0x3130, 95 } +UNICODE_KANBUN_KUNTEN :: unicode_range { 0x3190, 15 } +UNICODE_BOPOMOFO_EXTENDED :: unicode_range { 0x31a0, 31 } +UNICODE_KATAKANA_PHONETIC_EXTENSIONS :: unicode_range { 0x31f0, 15 } +UNICODE_ENCLOSED_CJK_LETTERS_AND_MONTHS :: unicode_range { 0x3200, 255 } +UNICODE_CJK_COMPATIBILITY :: unicode_range { 0x3300, 255 } +UNICODE_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A :: unicode_range { 0x3400, 6591 } +UNICODE_YIJING_HEXAGRAM_SYMBOLS :: unicode_range { 0x4dc0, 63 } +UNICODE_CJK_UNIFIED_IDEOGRAPHS :: unicode_range { 0x4e00, 20911 } +UNICODE_YI_SYLLABLES :: unicode_range { 0xa000, 1167 } +UNICODE_YI_RADICALS :: unicode_range { 0xa490, 63 } +UNICODE_HANGUL_SYLLABLES :: unicode_range { 0xac00, 11183 } +UNICODE_HIGH_SURROGATE_AREA :: unicode_range { 0xd800, 1023 } +UNICODE_LOW_SURROGATE_AREA :: unicode_range { 0xdc00, 1023 } +UNICODE_PRIVATE_USE_AREA :: unicode_range { 0xe000, 6399 } +UNICODE_CJK_COMPATIBILITY_IDEOGRAPHS :: unicode_range { 0xf900, 511 } +UNICODE_ALPHABETIC_PRESENTATION_FORMS :: unicode_range { 0xfb00, 79 } +UNICODE_ARABIC_PRESENTATION_FORMS_A :: unicode_range { 0xfb50, 687 } +UNICODE_VARIATION_SELECTORS :: unicode_range { 0xfe00, 15 } +UNICODE_COMBINING_HALF_MARKS :: unicode_range { 0xfe20, 15 } +UNICODE_CJK_COMPATIBILITY_FORMS :: unicode_range { 0xfe30, 31 } +UNICODE_SMALL_FORM_VARIANTS :: unicode_range { 0xfe50, 31 } +UNICODE_ARABIC_PRESENTATION_FORMS_B :: unicode_range { 0xfe70, 143 } +UNICODE_HALFWIDTH_AND_FULLWIDTH_FORMS :: unicode_range { 0xff00, 239 } +UNICODE_SPECIALS :: unicode_range { 0xfff0, 15 } +UNICODE_LINEAR_B_SYLLABARY :: unicode_range { 0x10000, 127 } +UNICODE_LINEAR_B_IDEOGRAMS :: unicode_range { 0x10080, 127 } +UNICODE_AEGEAN_NUMBERS :: unicode_range { 0x10100, 63 } +UNICODE_OLD_ITALIC :: unicode_range { 0x10300, 47 } +UNICODE_GOTHIC :: unicode_range { 0x10330, 31 } +UNICODE_UGARITIC :: unicode_range { 0x10380, 31 } +UNICODE_DESERET :: unicode_range { 0x10400, 79 } +UNICODE_SHAVIAN :: unicode_range { 0x10450, 47 } +UNICODE_OSMANYA :: unicode_range { 0x10480, 47 } +UNICODE_CYPRIOT_SYLLABARY :: unicode_range { 0x10800, 63 } +UNICODE_BYZANTINE_MUSICAL_SYMBOLS :: unicode_range { 0x1d000, 255 } +UNICODE_MUSICAL_SYMBOLS :: unicode_range { 0x1d100, 255 } +UNICODE_TAI_XUAN_JING_SYMBOLS :: unicode_range { 0x1d300, 95 } +UNICODE_MATHEMATICAL_ALPHANUMERIC_SYMBOLS :: unicode_range { 0x1d400, 1023 } +UNICODE_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B :: unicode_range { 0x20000, 42719 } +UNICODE_CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT :: unicode_range { 0x2f800, 543 } +UNICODE_TAGS :: unicode_range { 0xe0000, 127 } +UNICODE_VARIATION_SELECTORS_SUPPLEMENT :: unicode_range { 0xe0100, 239 } +UNICODE_SUPPLEMENTARY_PRIVATE_USE_AREA_A :: unicode_range { 0xf0000, 65533 } +UNICODE_SUPPLEMENTARY_PRIVATE_USE_AREA_B :: unicode_range { 0x100000, 65533 } + +clock_kind :: enum c.int { + MONOTONIC, + UPTIME, + DATE, +} + +@(default_calling_convention="c", link_prefix="oc_") +foreign { + clock_time :: proc(clock: clock_kind) -> f64 --- +} + +file_write_slice :: proc(file: file, slice: []char) -> u64 { + return file_write(file, u64(len(slice)), raw_data(slice)) +} + +file_read_slice :: proc(file: file, slice: []char) -> u64 { + return file_read(file, u64(len(slice)), raw_data(slice)) +} + +style_enum :: enum { + SIZE_WIDTH = 1, + SIZE_HEIGHT, + + LAYOUT_AXIS, + LAYOUT_ALIGN_X, + LAYOUT_ALIGN_Y, + LAYOUT_SPACING, + LAYOUT_MARGIN_X, + LAYOUT_MARGIN_Y, + + FLOAT_X, + FLOAT_Y, + + COLOR, + BG_COLOR, + BORDER_COLOR, + BORDER_SIZE, + ROUNDNESS, + + FONT, + FONT_SIZE, + + ANIMATION_TIME, + ANIMATION_MASK, +} + +ui_style_mask :: bit_set[style_enum; u64] + +// Masks like the C version that can be used as common combinations +SIZE :: ui_style_mask { .SIZE_WIDTH, .SIZE_HEIGHT } +LAYOUT_MARGINS :: ui_style_mask { .LAYOUT_MARGIN_X, .LAYOUT_MARGIN_Y } +LAYOUT :: ui_style_mask { .LAYOUT_AXIS, .LAYOUT_ALIGN_X, .LAYOUT_ALIGN_Y, .LAYOUT_SPACING, .LAYOUT_MARGIN_X, .LAYOUT_MARGIN_Y } +FLOAT :: ui_style_mask { .FLOAT_X, .FLOAT_Y } +MASK_INHERITED :: ui_style_mask { .COLOR, .FONT, .FONT_SIZE, .ANIMATION_TIME, .ANIMATION_MASK } + +//////////////////////////////////////////////////////////////////////////////// +// Utility data structures and helpers used throughout the Orca API. +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +// Types and helpers for vectors and matrices. +//////////////////////////////////////////////////////////////////////////////// + +// A 2D vector type. +vec2 :: [2]f32 + +// A 3D vector type. +vec3 :: [3]f32 + +// A 2D integer vector type. +vec2i :: [2]i32 + +// A 4D vector type. +vec4 :: [4]f32 + +// A 2-by-3 matrix. +mat2x3 :: [6]f32 + +// An axis-aligned rectangle. +rect :: struct { x, y, w, h: f32 } + +@(default_calling_convention="c", link_prefix="oc_") +foreign { + // Check if two 2D vectors are equal. + vec2_equal :: proc(v0: vec2, v1: vec2) -> bool --- + // Multiply a 2D vector by a scalar. + vec2_mul :: proc(f: f32, v: vec2) -> vec2 --- + // Add two 2D vectors + vec2_add :: proc(v0: vec2, v1: vec2) -> vec2 --- + // Transforms a vector by an affine transformation represented as a 2x3 matrix. + mat2x3_mul :: proc(m: mat2x3, p: vec2) -> vec2 --- + // Multiply two affine transformations represented as 2x3 matrices. Both matrices are treated as 3x3 matrices with an implicit `(0, 0, 1)` bottom row + mat2x3_mul_m :: proc(lhs: mat2x3, rhs: mat2x3) -> mat2x3 --- + // Invert an affine transform represented as a 2x3 matrix. + mat2x3_inv :: proc(x: mat2x3) -> mat2x3 --- + // Return a 2x3 matrix representing a rotation. + mat2x3_rotate :: proc(radians: f32) -> mat2x3 --- + // Return a 2x3 matrix representing a translation. + mat2x3_translate :: proc(x: f32, y: f32) -> mat2x3 --- +} + +//////////////////////////////////////////////////////////////////////////////// +// Helpers for logging, asserting and aborting. +//////////////////////////////////////////////////////////////////////////////// + +// Constants allowing to specify the level of logging verbosity. +log_level :: enum u32 { + // Only errors are logged. + ERROR = 0, + // Only warnings and errors are logged. + WARNING = 1, + // All messages are logged. + INFO = 2, + COUNT = 3, +} + +@(default_calling_convention="c", link_prefix="oc_") +foreign { + /* + Abort the application, showing an error message. + + This function should not be called directly by user code, which should use the `OC_ABORT` macro instead, as the macro takes care of filling in the source location parameters of the function. + */ + abort_ext :: proc(file: cstring, function: cstring, line: i32, fmt: cstring, #c_vararg args: ..any) -> ! --- + /* + Tigger a failed assertion. This aborts the application, showing the failed assertion and an error message. + + This function should not be called directly by user code, which should use the `OC_ASSERT` macro instead. The macro checks the assert condition and calls the function if it is false. It also takes care of filling in the source location parameters of the function. + */ + assert_fail :: proc(file: cstring, function: cstring, line: i32, src: cstring, fmt: cstring, #c_vararg args: ..any) -> ! --- + // Set the logging verbosity. + log_set_level :: proc(level: log_level) --- + /* + Log a message to the console. + + This function should not be called directly by user code, which should use the `oc_log_XXX` family of macros instead. The macros take care of filling in the message level and source location parameters of the function. + */ + log_ext :: proc(level: log_level, function: cstring, file: cstring, line: i32, fmt: cstring, #c_vararg args: ..any) --- +} + +//////////////////////////////////////////////////////////////////////////////// +// Types and helpers for doubly-linked lists. +//////////////////////////////////////////////////////////////////////////////// + +// An element of an intrusive doubly-linked list. +list_elt :: struct { + // Points to the previous element in the list. + prev: ^list_elt, + // Points to the next element in the list. + next: ^list_elt, +} + +// A doubly-linked list. +list :: struct { + // Points to the first element in the list. + first: ^list_elt, + // Points to the last element in the list. + last: ^list_elt, +} + +@(default_calling_convention="c", link_prefix="oc_") +foreign { + // Check if a list is empty. + list_empty :: proc(list: list) -> bool --- + // Zero-initializes a linked list. + list_init :: proc(list: ^list) --- + // Insert an element in a list after a given element. + list_insert :: proc(list: ^list, afterElt: ^list_elt, elt: ^list_elt) --- + // Insert an element in a list before a given element. + list_insert_before :: proc(list: ^list, beforeElt: ^list_elt, elt: ^list_elt) --- + // Remove an element from a list. + list_remove :: proc(list: ^list, elt: ^list_elt) --- + // Add an element at the end of a list. + list_push_back :: proc(list: ^list, elt: ^list_elt) --- + // Remove the last element from a list. + list_pop_back :: proc(list: ^list) -> ^list_elt --- + // Add an element at the beginning of a list. + list_push_front :: proc(list: ^list, elt: ^list_elt) --- + // Remove the first element from a list. + list_pop_front :: proc(list: ^list) -> ^list_elt --- +} + +//////////////////////////////////////////////////////////////////////////////// +// Base allocator and memory arenas. +//////////////////////////////////////////////////////////////////////////////// + +// The prototype of a procedure to reserve memory from the system. +mem_reserve_proc :: proc "c" (_context: ^base_allocator, size: u64) -> rawptr + +// The prototype of a procedure to modify a memory reservation. +mem_modify_proc :: proc "c" (_context: ^base_allocator, ptr: rawptr, size: u64) + +// A structure that defines how to allocate memory from the system. +base_allocator :: struct { + // A procedure to reserve memory from the system. + reserve: mem_reserve_proc, + // A procedure to commit memory from the system. + commit: mem_modify_proc, + // A procedure to decommit memory from the system. + decommit: mem_modify_proc, + // A procedure to release memory previously reserved from the system. + release: mem_modify_proc, +} + +// A contiguous chunk of memory managed by a memory arena. +arena_chunk :: struct { + listElt: list_elt, + ptr: cstring, + offset: u64, + committed: u64, + cap: u64, +} + +// A memory arena, allowing to allocate memory in a linear or stack-like fashion. +arena :: struct { + // An allocator providing memory pages from the system + base: ^base_allocator, + // A list of `oc_arena_chunk` chunks. + chunks: list, + // The chunk new memory allocations are pulled from. + currentChunk: ^arena_chunk, +} + +// This struct provides a way to store the current offset in a given arena, in order to reset the arena to that offset later. This allows using arenas in a stack-like fashion, e.g. to create temporary "scratch" allocations +arena_scope :: struct { + // The arena which offset is stored. + arena: ^arena, + // The arena chunk to which the offset belongs. + chunk: ^arena_chunk, + // The offset to rewind the arena to. + offset: u64, +} + +// Options for arena creation. +arena_options :: struct { + // The base allocator to use with this arena + base: ^base_allocator, + // The amount of memory to reserve up-front when creating the arena. + reserve: u64, +} + +@(default_calling_convention="c", link_prefix="oc_") +foreign { + // Initialize a memory arena. + arena_init :: proc(arena: ^arena) --- + // Initialize a memory arena with additional options. + arena_init_with_options :: proc(arena: ^arena, options: ^arena_options) --- + // Release all resources allocated to a memory arena. + arena_cleanup :: proc(arena: ^arena) --- + // Allocate a block of memory from an arena. + arena_push :: proc(arena: ^arena, size: u64) -> rawptr --- + // Allocate an aligned block of memory from an arena. + arena_push_aligned :: proc(arena: ^arena, size: u64, alignment: u32) -> rawptr --- + // Reset an arena. All memory that was previously allocated from this arena is released to the arena, and can be reallocated by later calls to `oc_arena_push` and similar functions. No memory is actually released _to the system_. + arena_clear :: proc(arena: ^arena) --- + // Begin a memory scope. This creates an `oc_arena_scope` object that stores the current offset of the arena. The arena can later be reset to that offset by calling `oc_arena_scope_end`, releasing all memory that was allocated within the scope to the arena. + arena_scope_begin :: proc(arena: ^arena) -> arena_scope --- + // End a memory scope. This resets an arena to the offset it had when the scope was created. All memory allocated within the scope is released back to the arena. + arena_scope_end :: proc(scope: arena_scope) --- + /* + Begin a scratch scope. This creates a memory scope on a per-thread, global "scratch" arena. This allows easily creating temporary memory for scratch computations or intermediate results, in a stack-like fashion. + + If you must return results in an arena passed by the caller, and you also use a scratch arena to do intermediate computations, beware that the results arena could itself be a scatch arena. In this case, you have to be careful not to intermingle your scratch computations with the final result, or clear your result entirely. You can either: + + - Allocate memory for the result upfront and call `oc_scratch_begin` afterwards, if possible. + - Use `oc_scratch_begin_next()` and pass it the result arena, to get a scratch arena that does not conflict with it. + */ + scratch_begin :: proc() -> arena_scope --- + // Begin a scratch scope that does not conflict with a given arena. See `oc_scratch_begin()` for more details about when to use this function. + scratch_begin_next :: proc(used: ^arena) -> arena_scope --- +} + +//////////////////////////////////////////////////////////////////////////////// +// String slices and string lists. +//////////////////////////////////////////////////////////////////////////////// + +// A type representing a string of bytes. +str8 :: string + +// A type representing an element of a string list. +str8_elt :: struct { + // The string element is linked into its parent string list through this field. + listElt: list_elt, + // The string for this element. + string: str8, +} + +// A type representing a string list. +str8_list :: struct { + // A linked-list of `oc_str8_elt`. + list: list, + // The number of elements in `list`. + eltCount: u64, + // The total length of the string list, which is the sum of the lengths over all elements. + len: u64, +} + +// A type describing a string of 16-bits characters (typically used for UTF-16). +str16 :: distinct []u16 + +// A type representing an element of an `oc_str16` list. +str16_elt :: struct { + // The string element is linked into its parent string list through this field. + listElt: list_elt, + // The string for this element. + string: str16, +} + +str16_list :: struct { + // A linked-list of `oc_str16_elt`. + list: list, + // The number of elements in `list`. + eltCount: u64, + // The total length of the string list, which is the sum of the lengths over all elements. + len: u64, +} + +// A type describing a string of 32-bits characters (typically used for UTF-32 codepoints). +str32 :: distinct []rune + +// A type representing an element of an `oc_str32` list. +str32_elt :: struct { + // The string element is linked into its parent string list through this field. + listElt: list_elt, + // The string for this element. + string: str32, +} + +str32_list :: struct { + // A linked-list of `oc_str32_elt`. + list: list, + // The number of elements in `list`. + eltCount: u64, + // The total length of the string list, which is the sum of the lengths over all elements. + len: u64, +} + +@(default_calling_convention="c", link_prefix="oc_") +foreign { + // Make a string from a bytes buffer and a length. + str8_from_buffer :: proc(len: u64, buffer: [^]char) -> str8 --- + // Make a string from a slice of another string. The resulting string designates some subsequence of the input string. + str8_slice :: proc(s: str8, start: u64, end: u64) -> str8 --- + // Pushes a copy of a buffer to an arena, and makes a string refering to that copy. + str8_push_buffer :: proc(arena: ^arena, len: u64, buffer: [^]char) -> str8 --- + // Pushes a copy of a C null-terminated string to an arena, and makes a string referring to that copy. + str8_push_cstring :: proc(arena: ^arena, str: cstring) -> str8 --- + // Copy the contents of a string on an arena and make a new string referring to the copied bytes. + str8_push_copy :: proc(arena: ^arena, s: str8) -> str8 --- + // Make a copy of a string slice. This function copies a subsequence of the input string onto an arena, and returns a new string referring to the copied content. + str8_push_slice :: proc(arena: ^arena, s: str8, start: u64, end: u64) -> str8 --- + // Lexicographically compare the contents of two strings. + str8_cmp :: proc(s1: str8, s2: str8) -> i32 --- + // Create a null-terminated C-string from an `oc_str8` string. + str8_to_cstring :: proc(arena: ^arena, string: str8) -> cstring --- + // Push a string element to the back of a string list. This creates a `oc_str8_elt` element referring to the contents of the input string, and links that element at the end of the string list. + str8_list_push :: proc(arena: ^arena, list: ^str8_list, str: str8) --- + // Build a string from a null-terminated format string an variadic arguments, and append it to a string list. + str8_list_pushf :: proc(arena: ^arena, list: ^str8_list, format: cstring, #c_vararg args: ..any) --- + // Build a string by combining the elements of a string list with a prefix, a suffix, and separators. + str8_list_collate :: proc(arena: ^arena, list: str8_list, prefix: str8, separator: str8, suffix: str8) -> str8 --- + // Build a string by joining the elements of a string list. + str8_list_join :: proc(arena: ^arena, list: str8_list) -> str8 --- + /* + Split a list into a string list according to separators. + + No string copies are made. The elements of the resulting string list refer to subsequences of the input string. + */ + str8_split :: proc(arena: ^arena, str: str8, separators: str8_list) -> str8_list --- + // Make an `oc_str16` string from a buffer of 16-bit characters. + str16_from_buffer :: proc(len: u64, buffer: [^]u16) -> str16 --- + // Make an `oc_str16` string from a slice of another `oc_str16` string. + str16_slice :: proc(s: str16, start: u64, end: u64) -> str16 --- + // Copy the content of a 16-bit character buffer on an arena and make a new `oc_str16` referencing the copied contents. + str16_push_buffer :: proc(arena: ^arena, len: u64, buffer: [^]u16) -> str16 --- + // Copy the contents of an `oc_str16` string and make a new string referencing the copied contents. + str16_push_copy :: proc(arena: ^arena, s: str16) -> str16 --- + // Copy a slice of an `oc_str16` string an make a new string referencing the copies contents. + str16_push_slice :: proc(arena: ^arena, s: str16, start: u64, end: u64) -> str16 --- + // Push a string element to the back of a string list. This creates a `oc_str16_elt` element referring to the contents of the input string, and links that element at the end of the string list. + str16_list_push :: proc(arena: ^arena, list: ^str16_list, str: str16) --- + // Build a string by joining the elements of a string list. + str16_list_join :: proc(arena: ^arena, list: str16_list) -> str16 --- + /* + Split a list into a string list according to separators. + + No string copies are made. The elements of the resulting string list refer to subsequences of the input string. + */ + str16_split :: proc(arena: ^arena, str: str16, separators: str16_list) -> str16_list --- + // Make an `oc_str32` string from a buffer of 32-bit characters. + str32_from_buffer :: proc(len: u64, buffer: [^]u32) -> str32 --- + // Make an `oc_str32` string from a slice of another `oc_str32` string. + str32_slice :: proc(s: str32, start: u64, end: u64) -> str32 --- + // Copy the content of a 32-bit character buffer on an arena and make a new `oc_str32` referencing the copied contents. + str32_push_buffer :: proc(arena: ^arena, len: u64, buffer: [^]u32) -> str32 --- + // Copy the contents of an `oc_str32` string and make a new string referencing the copied contents. + str32_push_copy :: proc(arena: ^arena, s: str32) -> str32 --- + // Copy a slice of an `oc_str32` string an make a new string referencing the copies contents. + str32_push_slice :: proc(arena: ^arena, s: str32, start: u64, end: u64) -> str32 --- + // Push a string element to the back of a string list. This creates a `oc_str32_elt` element referring to the contents of the input string, and links that element at the end of the string list. + str32_list_push :: proc(arena: ^arena, list: ^str32_list, str: str32) --- + // Build a string by joining the elements of a string list. + str32_list_join :: proc(arena: ^arena, list: str32_list) -> str32 --- + /* + Split a list into a string list according to separators. + + No string copies are made. The elements of the resulting string list refer to subsequences of the input string. + */ + str32_split :: proc(arena: ^arena, str: str32, separators: str32_list) -> str32_list --- +} + +//////////////////////////////////////////////////////////////////////////////// +// UTF8 encoding/decoding. +//////////////////////////////////////////////////////////////////////////////// + +// A unicode codepoint. +utf32 :: rune + +// A type representing the result of decoding of utf8-encoded codepoint. +utf8_dec :: struct { + // The decoded codepoint. + codepoint: utf32, + // The size of the utf8 sequence encoding that codepoint. + size: u32, +} + +// A type representing a contiguous range of unicode codepoints. +unicode_range :: struct { + // The first codepoint of the range. + firstCodePoint: utf32, + // The number of codepoints in the range. + count: u32, +} + +@(default_calling_convention="c", link_prefix="oc_") +foreign { + // Get the size of a utf8-encoded codepoint for the first byte of the encoded sequence. + utf8_size_from_leading_char :: proc(leadingChar: char) -> u32 --- + // Get the size of the utf8 encoding of a codepoint. + utf8_codepoint_size :: proc(codePoint: utf32) -> u32 --- + utf8_codepoint_count_for_string :: proc(string: str8) -> u64 --- + // Get the length of the utf8 encoding of a sequence of unicode codepoints. + utf8_byte_count_for_codepoints :: proc(codePoints: str32) -> u64 --- + // Get the offset of the next codepoint after a given offset, in a utf8 encoded string. + utf8_next_offset :: proc(string: str8, byteOffset: u64) -> u64 --- + // Get the offset of the previous codepoint before a given offset, in a utf8 encoded string. + utf8_prev_offset :: proc(string: str8, byteOffset: u64) -> u64 --- + // Decode a utf8 encoded codepoint. + utf8_decode :: proc(string: str8) -> utf8_dec --- + // Decode a codepoint at a given offset in a utf8 encoded string. + utf8_decode_at :: proc(string: str8, offset: u64) -> utf8_dec --- + // Encode a unicode codepoint into a utf8 sequence. + utf8_encode :: proc(dst: cstring, codePoint: utf32) -> str8 --- + // Decode a utf8 string to a string of unicode codepoints using memory passed by the caller. + utf8_to_codepoints :: proc(maxCount: u64, backing: ^utf32, string: str8) -> str32 --- + // Encode a string of unicode codepoints into a utf8 string using memory passed by the caller. + utf8_from_codepoints :: proc(maxBytes: u64, backing: cstring, codePoints: str32) -> str8 --- + // Decode a utf8 encoded string to a string of unicode codepoints using an arena. + utf8_push_to_codepoints :: proc(arena: ^arena, string: str8) -> str32 --- + // Encode a string of unicode codepoints into a utf8 string using an arena. + utf8_push_from_codepoints :: proc(arena: ^arena, codePoints: str32) -> str8 --- +} + +//////////////////////////////////////////////////////////////////////////////// +// Input, windowing, dialogs. +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +// Application events. +//////////////////////////////////////////////////////////////////////////////// + +// This enum defines the type events that can be sent to the application by the runtime. This determines which member of the `oc_event` union field is active. +event_type :: enum u32 { + // No event. That could be used simply to wake up the application. + NONE = 0, + // A modifier key event. This event is sent when a key such as <kbd>Alt</kbd>, <kbd>Control</kbd>, <kbd>Command</kbd> or <kbd>Shift</kbd> are pressed, released, or repeated. The `key` field contains the event's details. + KEYBOARD_MODS = 1, + // A key event. This event is sent when a normal key is pressed, released, or repeated. The `key` field contains the event's details. + KEYBOARD_KEY = 2, + // A character input event. This event is sent when an input character is produced by the keyboard. The `character` field contains the event's details. + KEYBOARD_CHAR = 3, + // A mouse button event. This is event sent when one of the mouse buttons is pressed, released, or clicked. The `key` field contains the event's details. + MOUSE_BUTTON = 4, + // A mouse move event. This is event sent when the mouse is moved. The `mouse` field contains the event's details. + MOUSE_MOVE = 5, + // A mouse wheel event. This is event sent when the mouse wheel is moved (or when a trackpad is scrolled). The `mouse` field contains the event's details. + MOUSE_WHEEL = 6, + // A mouse enter event. This event is sent when the mouse enters the application's window. The `mouse` field contains the event's details. + MOUSE_ENTER = 7, + // A mouse leave event. This event is sent when the mouse leaves the application's window. + MOUSE_LEAVE = 8, + // A clipboard paste event. This event is sent when the user uses the paste shortcut while the application window has focus. + CLIPBOARD_PASTE = 9, + // A resize event. This event is sent when the application's window is resized. The `move` field contains the event's details. + WINDOW_RESIZE = 10, + // A move event. This event is sent when the window is moved. The `move` field contains the event's details. + WINDOW_MOVE = 11, + // A focus event. This event is sent when the application gains focus. + WINDOW_FOCUS = 12, + // An unfocus event. This event is sent when the application looses focus. + WINDOW_UNFOCUS = 13, + // A hide event. This event is sent when the application's window is hidden or minimized. + WINDOW_HIDE = 14, + // A show event. This event is sent when the application's window is shown or de-minimized. + WINDOW_SHOW = 15, + // A close event. This event is sent when the window is about to be closed. + WINDOW_CLOSE = 16, + // A path drop event. This event is sent when the user drops files onto the application's window. The `paths` field contains the event's details. + PATHDROP = 17, + // A frame event. This event is sent when the application should render a frame. + FRAME = 18, + // A quit event. This event is sent when the application has been requested to quit. + QUIT = 19, +} + +// This enum describes the actions that can happen to a key. +key_action :: enum u32 { + // No action happened on that key. + NO_ACTION = 0, + // The key was pressed. + PRESS = 1, + // The key was released. + RELEASE = 2, + // The key was maintained pressed at least for the system's key repeat period. + REPEAT = 3, +} + +// A code representing a key's physical location. This is independent of the system's keyboard layout. +scan_code :: enum u32 { + UNKNOWN = 0, + SPACE = 32, + APOSTROPHE = 39, + COMMA = 44, + MINUS = 45, + PERIOD = 46, + SLASH = 47, + _0 = 48, + _1 = 49, + _2 = 50, + _3 = 51, + _4 = 52, + _5 = 53, + _6 = 54, + _7 = 55, + _8 = 56, + _9 = 57, + SEMICOLON = 59, + EQUAL = 61, + LEFT_BRACKET = 91, + BACKSLASH = 92, + RIGHT_BRACKET = 93, + GRAVE_ACCENT = 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, + WORLD_1 = 161, + WORLD_2 = 162, + ESCAPE = 256, + ENTER = 257, + TAB = 258, + BACKSPACE = 259, + INSERT = 260, + DELETE = 261, + RIGHT = 262, + LEFT = 263, + DOWN = 264, + UP = 265, + PAGE_UP = 266, + PAGE_DOWN = 267, + HOME = 268, + END = 269, + CAPS_LOCK = 280, + SCROLL_LOCK = 281, + NUM_LOCK = 282, + PRINT_SCREEN = 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, + KP_0 = 320, + KP_1 = 321, + KP_2 = 322, + KP_3 = 323, + KP_4 = 324, + KP_5 = 325, + KP_6 = 326, + KP_7 = 327, + KP_8 = 328, + KP_9 = 329, + KP_DECIMAL = 330, + KP_DIVIDE = 331, + KP_MULTIPLY = 332, + KP_SUBTRACT = 333, + KP_ADD = 334, + KP_ENTER = 335, + KP_EQUAL = 336, + LEFT_SHIFT = 340, + LEFT_CONTROL = 341, + LEFT_ALT = 342, + LEFT_SUPER = 343, + RIGHT_SHIFT = 344, + RIGHT_CONTROL = 345, + RIGHT_ALT = 346, + RIGHT_SUPER = 347, + MENU = 348, + COUNT = 349, +} + +// A code identifying a key. The physical location of the key corresponding to a given key code depends on the system's keyboard layout. +key_code :: enum u32 { + UNKNOWN = 0, + SPACE = 32, + APOSTROPHE = 39, + COMMA = 44, + MINUS = 45, + PERIOD = 46, + SLASH = 47, + _0 = 48, + _1 = 49, + _2 = 50, + _3 = 51, + _4 = 52, + _5 = 53, + _6 = 54, + _7 = 55, + _8 = 56, + _9 = 57, + SEMICOLON = 59, + EQUAL = 61, + LEFT_BRACKET = 91, + BACKSLASH = 92, + RIGHT_BRACKET = 93, + GRAVE_ACCENT = 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, + WORLD_1 = 161, + WORLD_2 = 162, + ESCAPE = 256, + ENTER = 257, + TAB = 258, + BACKSPACE = 259, + INSERT = 260, + DELETE = 261, + RIGHT = 262, + LEFT = 263, + DOWN = 264, + UP = 265, + PAGE_UP = 266, + PAGE_DOWN = 267, + HOME = 268, + END = 269, + CAPS_LOCK = 280, + SCROLL_LOCK = 281, + NUM_LOCK = 282, + PRINT_SCREEN = 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, + KP_0 = 320, + KP_1 = 321, + KP_2 = 322, + KP_3 = 323, + KP_4 = 324, + KP_5 = 325, + KP_6 = 326, + KP_7 = 327, + KP_8 = 328, + KP_9 = 329, + KP_DECIMAL = 330, + KP_DIVIDE = 331, + KP_MULTIPLY = 332, + KP_SUBTRACT = 333, + KP_ADD = 334, + KP_ENTER = 335, + KP_EQUAL = 336, + LEFT_SHIFT = 340, + LEFT_CONTROL = 341, + LEFT_ALT = 342, + LEFT_SUPER = 343, + RIGHT_SHIFT = 344, + RIGHT_CONTROL = 345, + RIGHT_ALT = 346, + RIGHT_SUPER = 347, + MENU = 348, + COUNT = 349, +} + +keymod_flag :: enum u32 { + ALT = 0, + SHIFT, + CTRL, + CMD, + MAIN_MODIFIER, +} +keymod_flags :: bit_set[keymod_flag; u32] + +// A code identifying a mouse button. +mouse_button :: enum u32 { + LEFT = 0, + RIGHT = 1, + MIDDLE = 2, + EXT1 = 3, + EXT2 = 4, + BUTTON_COUNT = 5, +} + +// A structure describing a key event or a mouse button event. +key_event :: struct { + // The action that was done on the key. + action: key_action, + // The scan code of the key. Only valid for key events. + scanCode: scan_code, + // The key code of the key. Only valid for key events. + keyCode: key_code, + // The button of the mouse. Only valid for mouse button events. + button: mouse_button, + // Modifier flags indicating which modifier keys where pressed at the time of the event. + mods: keymod_flags, + // The number of clicks that where detected for the button. Only valid for mouse button events. + clickCount: u8, +} + +// A structure describing a character input event. +char_event :: struct { + // The unicode codepoint of the character. + codepoint: utf32, + // The utf8 sequence of the character. + sequence: [8]char, + // The utf8 sequence length. + seqLen: u8, +} + +// A structure describing a mouse move or a mouse wheel event. Mouse coordinates have their origin at the top-left corner of the window, with the y axis going down. +mouse_event :: struct { + // The x coordinate of the mouse. + x: f32, + // The y coordinate of the mouse. + y: f32, + // The delta from the last x coordinate of the mouse, or the scroll value along the x coordinate. + deltaX: f32, + // The delta from the last y coordinate of the mouse, or the scoll value along the y coordinate. + deltaY: f32, + // Modifier flags indicating which modifier keys where pressed at the time of the event. + mods: keymod_flags, +} + +// A structure describing a window move or resize event. +move_event :: struct { + // The position and dimension of the frame rectangle, i.e. including the window title bar and border. + frame: rect, + // The position and dimension of the content rectangle, relative to the frame rectangle. + content: rect, +} + +// A structure describing an event sent to the application. +event :: struct { + // The window in which this event happened. + window: window, + // The type of the event. This determines which member of the event union is active. + type: event_type, + using _: struct #raw_union { + key: key_event, + character: char_event, + mouse: mouse_event, + move: move_event, + paths: str8_list, + }, +} + +// This enum describes the kinds of possible file dialogs. +file_dialog_kind :: enum u32 { + // The file dialog is a save dialog. + SAVE = 0, + // The file dialog is an open dialog. + OPEN = 1, +} + +// A type for flags describing various file dialog options. +// File dialog flags. +file_dialog_flag :: enum u32 { + // This dialog allows selecting files. + FILES = 1, + // This dialog allows selecting directories. + DIRECTORIES, + // This dialog allows selecting multiple items. + MULTIPLE, + // This dialog allows creating directories. + CREATE_DIRECTORIES, +} +file_dialog_flags :: bit_set[file_dialog_flag; u32] + +// A structure describing a file dialog. +file_dialog_desc :: struct { + // The kind of file dialog, see `oc_file_dialog_kind`. + kind: file_dialog_kind, + // A combination of file dialog flags used to enable file dialog options. + flags: file_dialog_flags, + // The title of the dialog, displayed in the dialog title bar. + title: str8, + // Optional. The label of the OK button, e.g. "Save" or "Open". + okLabel: str8, + // Optional. A file handle to the root directory for the dialog. If set to zero, the root directory is the application's default data directory. + startAt: file, + // Optional. The path of the starting directory of the dialog, relative to its root directory. If set to nil, the dialog starts at its root directory. + startPath: str8, + // A list of file extensions used to restrict which files can be selected in this dialog. An empty list allows all files to be selected. Extensions should be provided without a leading dot. + filters: str8_list, +} + +// An enum identifying the button clicked by the user when a file dialog returns. +file_dialog_button :: enum u32 { + // The user clicked the "Cancel" button, or closed the dialog box. + CANCEL = 0, + // The user clicked the "OK" button. + OK = 1, +} + +// A structure describing the result of a file dialog. +file_dialog_result :: struct { + // The button clicked by the user. + button: file_dialog_button, + // The path that was selected when the user clicked the OK button. If the dialog box had the `OC_FILE_DIALOG_MULTIPLE` flag set, this is the first file of the list of selected paths. + path: str8, + // If the dialog box had the `OC_FILE_DIALOG_MULTIPLE` flag set and the user clicked the OK button, this list contains the selected paths. + selection: str8_list, +} + +@(default_calling_convention="c", link_prefix="oc_") +foreign { + // Set the title of the application's window. + window_set_title :: proc(title: str8) --- + // Set the size of the application's window. + window_set_size :: proc(size: vec2) --- + // Request the system to quit the application. + request_quit :: proc() --- + // Convert a scancode to a keycode, according to current keyboard layout. + scancode_to_keycode :: proc(scanCode: scan_code) -> key_code --- + // Put a string in the clipboard. + clipboard_set_string :: proc(string: str8) --- +} + +//////////////////////////////////////////////////////////////////////////////// +// File input/output. +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +// API for opening, reading and writing files. +//////////////////////////////////////////////////////////////////////////////// + +// An opaque handle identifying an opened file. +file :: distinct u64 + +// The type of file open flags describing file open options. +// Flags for the `oc_file_open()` function. +file_open_flag :: enum u16 { + // Open the file in 'append' mode. All writes append data at the end of the file. + APPEND = 1, + // Truncate the file to 0 bytes when opening. + TRUNCATE, + // Create the file if it does not exist. + CREATE, + // If the file is a symlink, open the symlink itself instead of following it. + SYMLINK, + // If the file is a symlink, the call to open will fail. + NO_FOLLOW, + // Reserved. + RESTRICT, +} +file_open_flags :: bit_set[file_open_flag; u16] + +// This enum describes the access permissions of a file handle. +file_access_flag :: enum u16 { + // The file handle can be used for reading from the file. + READ = 1, + // The file handle can be used for writing to the file. + WRITE, +} +file_access :: bit_set[file_access_flag; u16] + +// This enum is used in `oc_file_seek()` to specify the starting point of the seek operation. +file_whence :: enum u32 { + // Set the file position relative to the beginning of the file. + SET = 0, + // Set the file position relative to the end of the file. + END = 1, + // Set the file position relative to the current position. + CURRENT = 2, +} + +// A type used to identify I/O requests. +io_req_id :: u64 + +// A type used to identify I/O operations. +// This enum declares all I/O operations. +io_op :: enum u32 { + // ['Open a file at a path relative to a given root directory.', '', " - `handle` is the handle to the root directory. If it is nil, the application's default directory is used.", ' - `size` is the size of the path, in bytes.', ' - `buffer` points to an array containing the path of the file to open, relative to the directory identified by `handle`.', ' - `open` contains the permissions and flags for the open operation.'] + OPEN_AT = 0, + // ['Close a file handle.', '', ' - `handle` is the handle to close.'] + CLOSE = 1, + // ['Get status information for a file handle.', '', ' - `handle` is the handle to stat.', ' - `size` is the size of the result buffer. It should be at least `sizeof(oc_file_status)`.', ' - `buffer` is the result buffer.'] + FSTAT = 2, + // ['Move the file position in a file.', '', ' - `handle` is the handle of the file.', ' - `offset` specifies the offset of the new position, relative to the base position specified by `whence`.', ' - `whence` determines the base position for the seek operation.'] + SEEK = 3, + // ['Read data from a file.', '', ' - `handle` is the handle of the file.', ' - `size` is the number of bytes to read.', ' - `buffer` is the result buffer. It should be big enough to hold `size` bytes.'] + READ = 4, + // ['Write data to a file.', '', ' - `handle` is the handle of the file.', ' - `size` is the number of bytes to write.', ' - `buffer` contains the data to write to the file.'] + WRITE = 5, + // ['Get the error attached to a file handle.', '', ' - `handle` is the handle of the file.'] + OC_OC_IO_ERROR = 6, +} + +// A structure describing an I/O request. +io_req :: struct { + // An identifier for the request. You can set this to any value you want. It is passed back in the `oc_io_cmp` completion and can be used to match requests and completions. + id: io_req_id, + // The requested operation. + op: io_op, + // A file handle used by some operations. + handle: file, + // An offset used by some operations. + offset: i64, + // A size indicating the capacity of the buffer pointed to by `buffer`, in bytes. + size: u64, + using _: struct #raw_union { + buffer: [^]char, + unused: u64, + }, + using _: struct #raw_union { + open: struct { + // The access permissions requested on the file to open. + rights: file_access, + // The options to use when opening the file. + flags: file_open_flags, + }, + whence: file_whence, + }, +} + +// A type identifying an I/O error. +// This enum declares all I/O error values. +io_error :: enum u32 { + // No error. + OK = 0, + // An unexpected error happened. + UNKNOWN = 1, + // The request had an invalid operation. + OP = 2, + // The request had an invalid handle. + HANDLE = 3, + // The operation was not carried out because the file handle has previous errors. + PREV = 4, + // The request contained wrong arguments. + ARG = 5, + // The operation requires permissions that the file handle doesn't have. + PERM = 6, + // The operation couldn't complete due to a lack of space in the result buffer. + SPACE = 7, + // One of the directory in the path does not exist or couldn't be traversed. + NO_ENTRY = 8, + // The file already exists. + EXISTS = 9, + // The file is not a directory. + NOT_DIR = 10, + // The file is a directory. + DIR = 11, + // There are too many opened files. + MAX_FILES = 12, + // The path contains too many symbolic links (this may be indicative of a symlink loop). + MAX_LINKS = 13, + // The path is too long. + PATH_LENGTH = 14, + // The file is too large. + FILE_SIZE = 15, + // The file is too large to be opened. + OVERFLOW = 16, + // The file is locked or the device on which it is stored is not ready. + NOT_READY = 17, + // The system is out of memory. + MEM = 18, + // The operation was interrupted by a signal. + INTERRUPT = 19, + // A physical error happened. + PHYSICAL = 20, + // The device on which the file is stored was not found. + NO_DEVICE = 21, + // One element along the path is outside the root directory subtree. + WALKOUT = 22, +} + +// A structure describing the completion of an I/O operation. +io_cmp :: struct { + // The request ID as passed in the `oc_io_req` request that generated this completion. + id: io_req_id, + // The error value for the operation. + error: io_error, + using _: struct #raw_union { + result: i64, + size: u64, + offset: i64, + handle: file, + }, +} + +// An enum identifying the type of a file. +file_type :: enum u32 { + // The file is of unknown type. + UNKNOWN = 0, + // The file is a regular file. + REGULAR = 1, + // The file is a directory. + DIRECTORY = 2, + // The file is a symbolic link. + SYMLINK = 3, + // The file is a block device. + BLOCK = 4, + // The file is a character device. + CHARACTER = 5, + // The file is a FIFO pipe. + FIFO = 6, + // The file is a socket. + SOCKET = 7, +} + +// A type describing file permissions. +file_perm_flag :: enum u16 { + OTHER_EXEC = 1, + OTHER_WRITE, + OTHER_READ, + GROUP_EXEC, + GROUP_WRITE, + GROUP_READ, + OWNER_EXEC, + OWNER_WRITE, + OWNER_READ, + STICKY_BIT, + SET_GID, + SET_UID, +} +file_perm :: bit_set[file_perm_flag; u16] + +datestamp :: struct { + seconds: i64, + fraction: u64, +} + +file_status :: struct { + uid: u64, + type: file_type, + perm: file_perm, + size: u64, + creationDate: datestamp, + accessDate: datestamp, + modificationDate: datestamp, +} + +@(default_calling_convention="c", link_prefix="oc_") +foreign { + // Send a single I/O request and wait for its completion. + io_wait_single_req :: proc(req: ^io_req) -> io_cmp --- + // Returns a `nil` file handle + file_nil :: proc() -> file --- + // Test if a file handle is `nil`. + file_is_nil :: proc(handle: file) -> bool --- + // Open a file in the applications' default directory subtree. + file_open :: proc(path: str8, rights: file_access, flags: file_open_flags) -> file --- + // Open a file in a given directory's subtree. + file_open_at :: proc(dir: file, path: str8, rights: file_access, flags: file_open_flags) -> file --- + // Close a file. + file_close :: proc(file: file) --- + // Get the current position in a file. + file_pos :: proc(file: file) -> i64 --- + // Set the current position in a file. + file_seek :: proc(file: file, offset: i64, whence: file_whence) -> i64 --- + // Write data to a file. + file_write :: proc(file: file, size: u64, buffer: [^]char) -> u64 --- + // Read from a file. + file_read :: proc(file: file, size: u64, buffer: [^]char) -> u64 --- + // Get the last error on a file handle. + file_last_error :: proc(handle: file) -> io_error --- + file_get_status :: proc(file: file) -> file_status --- + file_size :: proc(file: file) -> u64 --- + file_open_with_request :: proc(path: str8, rights: file_access, flags: file_open_flags) -> file --- +} + +//////////////////////////////////////////////////////////////////////////////// +// API for obtaining file capabilities through open/save dialogs. +//////////////////////////////////////////////////////////////////////////////// + +// An element of a list of file handles acquired through a file dialog. +file_open_with_dialog_elt :: struct { + listElt: list_elt, + file: file, +} + +// A structure describing the result of a call to `oc_file_open_with_dialog()`. +file_open_with_dialog_result :: struct { + // The button of the file dialog clicked by the user. + button: file_dialog_button, + // The file that was opened through the dialog. If the dialog had the `OC_FILE_DIALOG_MULTIPLE` flag set, this is equal to the first handle in the `selection` list. + file: file, + // If the dialog had the `OC_FILE_DIALOG_MULTIPLE` flag set, this list of `oc_file_open_with_dialog_elt` contains the handles of the opened files. + selection: list, +} + +@(default_calling_convention="c", link_prefix="oc_") +foreign { + // Open files through a file dialog. This allows the user to select files outside the root directories currently accessible to the applications, giving them a way to provide new file capabilities to the application. + file_open_with_dialog :: proc(arena: ^arena, rights: file_access, flags: file_open_flags, desc: ^file_dialog_desc) -> file_open_with_dialog_result --- +} + +//////////////////////////////////////////////////////////////////////////////// +// API for handling filesystem paths. +//////////////////////////////////////////////////////////////////////////////// + +@(default_calling_convention="c", link_prefix="oc_") +foreign { + // Get a string slice of the directory part of a path. + path_slice_directory :: proc(path: str8) -> str8 --- + // Get a string slice of the file name part of a path. + path_slice_filename :: proc(path: str8) -> str8 --- + // Split a path into path elements. + path_split :: proc(arena: ^arena, path: str8) -> str8_list --- + // Join path elements to form a path. + path_join :: proc(arena: ^arena, elements: str8_list) -> str8 --- + // Append a path to another path. + path_append :: proc(arena: ^arena, parent: str8, relPath: str8) -> str8 --- + // Test wether a path is an absolute path. + path_is_absolute :: proc(path: str8) -> bool --- +} + +//////////////////////////////////////////////////////////////////////////////// +// 2D/3D rendering APIs. +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +// A 2D Vector Graphics API. +//////////////////////////////////////////////////////////////////////////////// + +surface :: distinct u64 + +canvas_renderer :: distinct u64 + +canvas_context :: distinct u64 + +font :: distinct u64 + +image :: distinct u64 + +gradient_blend_space :: enum u32 { + LINEAR = 0, + SRGB = 1, +} + +color_space :: enum u32 { + RGB = 0, + SRGB = 1, +} + +color :: struct { using c: [4]f32, colorSpace: color_space } + +joint_type :: enum u32 { + MITER = 0, + BEVEL = 1, + NONE = 2, +} + +cap_type :: enum u32 { + NONE = 0, + SQUARE = 1, +} + +font_metrics :: struct { + ascent: f32, + descent: f32, + lineGap: f32, + xHeight: f32, + capHeight: f32, + width: f32, +} + +glyph_metrics :: struct { + ink: rect, + advance: vec2, +} + +text_metrics :: struct { + ink: rect, + logical: rect, + advance: vec2, +} + +rect_atlas :: struct {} + +image_region :: struct { + image: image, + rect: rect, +} + +@(default_calling_convention="c", link_prefix="oc_") +foreign { + surface_nil :: proc() -> surface --- + surface_is_nil :: proc(surface: surface) -> bool --- + surface_destroy :: proc(surface: surface) --- + surface_get_size :: proc(surface: surface) -> vec2 --- + surface_contents_scaling :: proc(surface: surface) -> vec2 --- + surface_bring_to_front :: proc(surface: surface) --- + surface_send_to_back :: proc(surface: surface) --- + surface_get_hidden :: proc(surface: surface) -> bool --- + surface_set_hidden :: proc(surface: surface, hidden: bool) --- + color_rgba :: proc(r: f32, g: f32, b: f32, a: f32) -> color --- + color_srgba :: proc(r: f32, g: f32, b: f32, a: f32) -> color --- + color_convert :: proc(_color: color, colorSpace: color_space) -> color --- + canvas_renderer_nil :: proc() -> canvas_renderer --- + canvas_renderer_is_nil :: proc(renderer: canvas_renderer) -> bool --- + canvas_renderer_create :: proc() -> canvas_renderer --- + canvas_renderer_destroy :: proc(renderer: canvas_renderer) --- + canvas_render :: proc(renderer: canvas_renderer, _context: canvas_context, surface: surface) --- + canvas_present :: proc(renderer: canvas_renderer, surface: surface) --- + canvas_surface_create :: proc(renderer: canvas_renderer) -> surface --- + canvas_surface_swap_interval :: proc(surface: surface, swap: i32) --- + canvas_context_nil :: proc() -> canvas_context --- + canvas_context_is_nil :: proc(_context: canvas_context) -> bool --- + canvas_context_create :: proc() -> canvas_context --- + canvas_context_destroy :: proc(_context: canvas_context) --- + canvas_context_select :: proc(_context: canvas_context) -> canvas_context --- + canvas_context_set_msaa_sample_count :: proc(_context: canvas_context, sampleCount: u32) --- + font_nil :: proc() -> font --- + font_is_nil :: proc(font: font) -> bool --- + font_create_from_memory :: proc(mem: str8, rangeCount: u32, ranges: ^unicode_range) -> font --- + font_create_from_file :: proc(file: file, rangeCount: u32, ranges: ^unicode_range) -> font --- + font_create_from_path :: proc(path: str8, rangeCount: u32, ranges: ^unicode_range) -> font --- + font_destroy :: proc(font: font) --- + font_get_glyph_indices :: proc(font: font, codePoints: str32, backing: str32) -> str32 --- + font_push_glyph_indices :: proc(arena: ^arena, font: font, codePoints: str32) -> str32 --- + font_get_glyph_index :: proc(font: font, codePoint: utf32) -> u32 --- + font_get_metrics :: proc(font: font, emSize: f32) -> font_metrics --- + font_get_metrics_unscaled :: proc(font: font) -> font_metrics --- + font_get_scale_for_em_pixels :: proc(font: font, emSize: f32) -> f32 --- + font_text_metrics_utf32 :: proc(font: font, fontSize: f32, codepoints: str32) -> text_metrics --- + font_text_metrics :: proc(font: font, fontSize: f32, text: str8) -> text_metrics --- + image_nil :: proc() -> image --- + image_is_nil :: proc(a: image) -> bool --- + image_create :: proc(renderer: canvas_renderer, width: u32, height: u32) -> image --- + image_create_from_rgba8 :: proc(renderer: canvas_renderer, width: u32, height: u32, pixels: [^]u8) -> image --- + image_create_from_memory :: proc(renderer: canvas_renderer, mem: str8, flip: bool) -> image --- + image_create_from_file :: proc(renderer: canvas_renderer, file: file, flip: bool) -> image --- + image_create_from_path :: proc(renderer: canvas_renderer, path: str8, flip: bool) -> image --- + image_destroy :: proc(image: image) --- + image_upload_region_rgba8 :: proc(image: image, region: rect, pixels: [^]u8) --- + image_size :: proc(image: image) -> vec2 --- + rect_atlas_create :: proc(arena: ^arena, width: i32, height: i32) -> ^rect_atlas --- + rect_atlas_alloc :: proc(atlas: ^rect_atlas, width: i32, height: i32) -> rect --- + rect_atlas_recycle :: proc(atlas: ^rect_atlas, rect: rect) --- + image_atlas_alloc_from_rgba8 :: proc(atlas: ^rect_atlas, backingImage: image, width: u32, height: u32, pixels: [^]u8) -> image_region --- + image_atlas_alloc_from_memory :: proc(atlas: ^rect_atlas, backingImage: image, mem: str8, flip: bool) -> image_region --- + image_atlas_alloc_from_file :: proc(atlas: ^rect_atlas, backingImage: image, file: file, flip: bool) -> image_region --- + image_atlas_alloc_from_path :: proc(atlas: ^rect_atlas, backingImage: image, path: str8, flip: bool) -> image_region --- + image_atlas_recycle :: proc(atlas: ^rect_atlas, imageRgn: image_region) --- + matrix_push :: proc(_matrix: mat2x3) --- + matrix_multiply_push :: proc(_matrix: mat2x3) --- + matrix_pop :: proc() --- + matrix_top :: proc() -> mat2x3 --- + clip_push :: proc(x: f32, y: f32, w: f32, h: f32) --- + clip_pop :: proc() --- + clip_top :: proc() -> rect --- + set_color :: proc(_color: color) --- + set_color_rgba :: proc(r: f32, g: f32, b: f32, a: f32) --- + set_color_srgba :: proc(r: f32, g: f32, b: f32, a: f32) --- + set_gradient :: proc(blendSpace: gradient_blend_space, bottomLeft: color, bottomRight: color, topRight: color, topLeft: color) --- + set_width :: proc(width: f32) --- + set_tolerance :: proc(tolerance: f32) --- + set_joint :: proc(joint: joint_type) --- + set_max_joint_excursion :: proc(maxJointExcursion: f32) --- + set_cap :: proc(cap: cap_type) --- + set_font :: proc(font: font) --- + set_font_size :: proc(size: f32) --- + set_text_flip :: proc(flip: bool) --- + set_image :: proc(image: image) --- + set_image_source_region :: proc(region: rect) --- + get_color :: proc() -> color --- + get_width :: proc() -> f32 --- + get_tolerance :: proc() -> f32 --- + get_joint :: proc() -> joint_type --- + get_max_joint_excursion :: proc() -> f32 --- + get_cap :: proc() -> cap_type --- + get_font :: proc() -> font --- + get_font_size :: proc() -> f32 --- + get_text_flip :: proc() -> bool --- + get_image :: proc() -> image --- + get_image_source_region :: proc() -> rect --- + get_position :: proc() -> vec2 --- + move_to :: proc(x: f32, y: f32) --- + line_to :: proc(x: f32, y: f32) --- + quadratic_to :: proc(x1: f32, y1: f32, x2: f32, y2: f32) --- + cubic_to :: proc(x1: f32, y1: f32, x2: f32, y2: f32, x3: f32, y3: f32) --- + close_path :: proc() --- + glyph_outlines :: proc(glyphIndices: str32) -> rect --- + codepoints_outlines :: proc(string: str32) --- + text_outlines :: proc(string: str8) --- + clear :: proc() --- + fill :: proc() --- + stroke :: proc() --- + rectangle_fill :: proc(x: f32, y: f32, w: f32, h: f32) --- + rectangle_stroke :: proc(x: f32, y: f32, w: f32, h: f32) --- + rounded_rectangle_fill :: proc(x: f32, y: f32, w: f32, h: f32, r: f32) --- + rounded_rectangle_stroke :: proc(x: f32, y: f32, w: f32, h: f32, r: f32) --- + ellipse_fill :: proc(x: f32, y: f32, rx: f32, ry: f32) --- + ellipse_stroke :: proc(x: f32, y: f32, rx: f32, ry: f32) --- + circle_fill :: proc(x: f32, y: f32, r: f32) --- + circle_stroke :: proc(x: f32, y: f32, r: f32) --- + arc :: proc(x: f32, y: f32, r: f32, arcAngle: f32, startAngle: f32) --- + text_fill :: proc(x: f32, y: f32, text: str8) --- + image_draw :: proc(image: image, rect: rect) --- + image_draw_region :: proc(image: image, srcRegion: rect, dstRegion: rect) --- +} + +//////////////////////////////////////////////////////////////////////////////// +// A surface for rendering using the GLES API. +//////////////////////////////////////////////////////////////////////////////// + +@(default_calling_convention="c", link_prefix="oc_") +foreign { + gles_surface_create :: proc() -> surface --- + gles_surface_make_current :: proc(surface: surface) --- + gles_surface_swap_interval :: proc(surface: surface, interval: i32) --- + gles_surface_swap_buffers :: proc(surface: surface) --- +} + +//////////////////////////////////////////////////////////////////////////////// +// Graphical User Interface API. +//////////////////////////////////////////////////////////////////////////////// + +key_state :: struct { + lastUpdate: u64, + transitionCount: u32, + repeatCount: u32, + down: bool, + sysClicked: bool, + sysDoubleClicked: bool, + sysTripleClicked: bool, +} + +keyboard_state :: struct { + keys: [349]key_state, + mods: keymod_flags, +} + +mouse_state :: struct { + lastUpdate: u64, + posValid: bool, + pos: vec2, + delta: vec2, + wheel: vec2, + using _: struct #raw_union { + buttons: [5]key_state, + using _: struct { + left: key_state, + right: key_state, + middle: key_state, + ext1: key_state, + ext2: key_state, + }, + }, +} + +BACKING_SIZE :: 64 + +text_state :: struct { + lastUpdate: u64, + backing: [64]utf32, + codePoints: str32, +} + +clipboard_state :: struct { + lastUpdate: u64, + pastedText: str8, +} + +input_state :: struct { + frameCounter: u64, + keyboard: keyboard_state, + mouse: mouse_state, + text: text_state, + clipboard: clipboard_state, +} + +ui_key :: struct { + hash: u64, +} + +ui_axis :: enum u32 { + X = 0, + Y = 1, + COUNT = 2, +} + +ui_align :: enum u32 { + START = 0, + END = 1, + CENTER = 2, +} + +ui_layout_align :: [2]ui_align + +ui_layout :: struct { + axis: ui_axis, + spacing: f32, + margin: [2]f32, + align: ui_layout_align, +} + +ui_size_kind :: enum u32 { + TEXT = 0, + PIXELS = 1, + CHILDREN = 2, + PARENT = 3, + PARENT_MINUS_PIXELS = 4, +} + +ui_size :: struct { + kind: ui_size_kind, + value: f32, + relax: f32, + minSize: f32, +} + +ui_box_size :: [2]ui_size + +ui_box_floating :: [2]bool + +ui_style :: struct { + size: ui_box_size, + layout: ui_layout, + floating: ui_box_floating, + floatTarget: vec2, + _color: color, + bgColor: color, + borderColor: color, + font: font, + fontSize: f32, + borderSize: f32, + roundness: f32, + animationTime: f32, + animationMask: ui_style_mask, +} + +ui_palette :: struct { + red0: color, + red1: color, + red2: color, + red3: color, + red4: color, + red5: color, + red6: color, + red7: color, + red8: color, + red9: color, + orange0: color, + orange1: color, + orange2: color, + orange3: color, + orange4: color, + orange5: color, + orange6: color, + orange7: color, + orange8: color, + orange9: color, + amber0: color, + amber1: color, + amber2: color, + amber3: color, + amber4: color, + amber5: color, + amber6: color, + amber7: color, + amber8: color, + amber9: color, + yellow0: color, + yellow1: color, + yellow2: color, + yellow3: color, + yellow4: color, + yellow5: color, + yellow6: color, + yellow7: color, + yellow8: color, + yellow9: color, + lime0: color, + lime1: color, + lime2: color, + lime3: color, + lime4: color, + lime5: color, + lime6: color, + lime7: color, + lime8: color, + lime9: color, + lightGreen0: color, + lightGreen1: color, + lightGreen2: color, + lightGreen3: color, + lightGreen4: color, + lightGreen5: color, + lightGreen6: color, + lightGreen7: color, + lightGreen8: color, + lightGreen9: color, + green0: color, + green1: color, + green2: color, + green3: color, + green4: color, + green5: color, + green6: color, + green7: color, + green8: color, + green9: color, + teal0: color, + teal1: color, + teal2: color, + teal3: color, + teal4: color, + teal5: color, + teal6: color, + teal7: color, + teal8: color, + teal9: color, + cyan0: color, + cyan1: color, + cyan2: color, + cyan3: color, + cyan4: color, + cyan5: color, + cyan6: color, + cyan7: color, + cyan8: color, + cyan9: color, + lightBlue0: color, + lightBlue1: color, + lightBlue2: color, + lightBlue3: color, + lightBlue4: color, + lightBlue5: color, + lightBlue6: color, + lightBlue7: color, + lightBlue8: color, + lightBlue9: color, + blue0: color, + blue1: color, + blue2: color, + blue3: color, + blue4: color, + blue5: color, + blue6: color, + blue7: color, + blue8: color, + blue9: color, + indigo0: color, + indigo1: color, + indigo2: color, + indigo3: color, + indigo4: color, + indigo5: color, + indigo6: color, + indigo7: color, + indigo8: color, + indigo9: color, + violet0: color, + violet1: color, + violet2: color, + violet3: color, + violet4: color, + violet5: color, + violet6: color, + violet7: color, + violet8: color, + violet9: color, + purple0: color, + purple1: color, + purple2: color, + purple3: color, + purple4: color, + purple5: color, + purple6: color, + purple7: color, + purple8: color, + purple9: color, + pink0: color, + pink1: color, + pink2: color, + pink3: color, + pink4: color, + pink5: color, + pink6: color, + pink7: color, + pink8: color, + pink9: color, + grey0: color, + grey1: color, + grey2: color, + grey3: color, + grey4: color, + grey5: color, + grey6: color, + grey7: color, + grey8: color, + grey9: color, + black: color, + white: color, +} + +ui_theme :: struct { + white: color, + primary: color, + primaryHover: color, + primaryActive: color, + border: color, + fill0: color, + fill1: color, + fill2: color, + bg0: color, + bg1: color, + bg2: color, + bg3: color, + bg4: color, + text0: color, + text1: color, + text2: color, + text3: color, + sliderThumbBorder: color, + elevatedBorder: color, + roundnessSmall: f32, + roundnessMedium: f32, + roundnessLarge: f32, + palette: ^ui_palette, +} + +ui_tag :: struct { + hash: u64, +} + +ui_selector_kind :: enum u32 { + ANY = 0, + OWNER = 1, + TEXT = 2, + TAG = 3, + STATUS = 4, + KEY = 5, +} + +ui_status_flag :: enum u8 { + HOVER = 1, + HOT, + ACTIVE, + DRAGGING, +} +ui_status :: bit_set[ui_status_flag; u8] + +ui_selector_op :: enum u32 { + DESCENDANT = 0, + AND = 1, +} + +ui_selector :: struct { + listElt: list_elt, + kind: ui_selector_kind, + op: ui_selector_op, + using _: struct #raw_union { + text: str8, + key: ui_key, + tag: ui_tag, + status: ui_status, + }, +} + +ui_pattern :: struct { + l: list, +} + +ui_box :: struct { + listElt: list_elt, + children: list, + parent: ^ui_box, + overlayElt: list_elt, + bucketElt: list_elt, + key: ui_key, + frameCounter: u64, + flags: ui_flags, + string: str8, + tags: list, + drawProc: ui_box_draw_proc, + drawData: rawptr, + beforeRules: list, + afterRules: list, + targetStyle: ^ui_style, + style: ui_style, + z: u32, + floatPos: vec2, + childrenSum: [2]f32, + spacing: [2]f32, + minSize: [2]f32, + rect: rect, + sig: ^ui_sig, + fresh: bool, + closed: bool, + parentClosed: bool, + dragging: bool, + hot: bool, + active: bool, + scroll: vec2, + pressedMouse: vec2, + hotTransition: f32, + activeTransition: f32, +} + +ui_style_rule :: struct { + boxElt: list_elt, + buildElt: list_elt, + tmpElt: list_elt, + owner: ^ui_box, + pattern: ui_pattern, + mask: ui_style_mask, + style: ^ui_style, +} + +ui_sig :: struct { + box: ^ui_box, + mouse: vec2, + delta: vec2, + wheel: vec2, + pressed: bool, + released: bool, + clicked: bool, + doubleClicked: bool, + tripleClicked: bool, + rightPressed: bool, + dragging: bool, + hovering: bool, + pasted: bool, +} + +ui_box_draw_proc :: proc "c" (arg0: ^ui_box, arg1: rawptr) + +ui_flag :: enum u32 { + CLICKABLE = 0, + SCROLL_WHEEL_X, + SCROLL_WHEEL_Y, + BLOCK_MOUSE, + HOT_ANIMATION, + ACTIVE_ANIMATION, + OVERFLOW_ALLOW_X, + OVERFLOW_ALLOW_Y, + CLIP, + DRAW_BACKGROUND, + DRAW_FOREGROUND, + DRAW_BORDER, + DRAW_TEXT, + DRAW_PROC, + OVERLAY, +} +ui_flags :: bit_set[ui_flag; u32] + +MAX_INPUT_CHAR_PER_FRAME :: 64 + +ui_input_text :: struct { + count: u8 `fmt:"-"`, + codePoints: [64]utf32 `fmt:"s,count"`, +} + +ui_stack_elt :: struct { + parent: ^ui_stack_elt, + using _: struct #raw_union { + box: ^ui_box, + size: ui_size, + clip: rect, + }, +} + +ui_tag_elt :: struct { + listElt: list_elt, + tag: ui_tag, +} + +BOX_MAP_BUCKET_COUNT :: 1024 + +ui_edit_move :: enum u32 { + NONE = 0, + CHAR = 1, + WORD = 2, + LINE = 3, +} + +ui_context :: struct { + init: bool, + input: input_state, + frameCounter: u64, + frameTime: f64, + lastFrameDuration: f64, + frameArena: arena, + boxPool: pool, + boxMap: [1024]list, + root: ^ui_box, + overlay: ^ui_box, + overlayList: list, + boxStack: ^ui_stack_elt, + clipStack: ^ui_stack_elt, + nextBoxBeforeRules: list, + nextBoxAfterRules: list, + nextBoxTags: list, + z: u32, + hovered: ^ui_box, + focus: ^ui_box, + editCursor: i32, + editMark: i32, + editFirstDisplayedChar: i32, + editCursorBlinkStart: f64, + editSelectionMode: ui_edit_move, + editWordSelectionInitialCursor: i32, + editWordSelectionInitialMark: i32, + theme: ^ui_theme, +} + +ui_text_box_result :: struct { + changed: bool, + accepted: bool, + text: str8, +} + +ui_select_popup_info :: struct { + changed: bool, + selectedIndex: i32, + optionCount: i32 `fmt:"-"`, + options: [^]str8 `fmt:"s,optionCount"`, + placeholder: str8, +} + +ui_radio_group_info :: struct { + changed: bool, + selectedIndex: i32, + optionCount: i32 `fmt:"-"`, + options: [^]str8 `fmt:"s,optionCount"`, +} + +@(default_calling_convention="c", link_prefix="oc_") +foreign { + input_process_event :: proc(arena: ^arena, state: ^input_state, event: ^event) --- + input_next_frame :: proc(state: ^input_state) --- + key_down :: proc(state: ^input_state, key: key_code) -> bool --- + key_press_count :: proc(state: ^input_state, key: key_code) -> u8 --- + key_release_count :: proc(state: ^input_state, key: key_code) -> u8 --- + key_repeat_count :: proc(state: ^input_state, key: key_code) -> u8 --- + key_down_scancode :: proc(state: ^input_state, key: scan_code) -> bool --- + key_press_count_scancode :: proc(state: ^input_state, key: scan_code) -> u8 --- + key_release_count_scancode :: proc(state: ^input_state, key: scan_code) -> u8 --- + key_repeat_count_scancode :: proc(state: ^input_state, key: scan_code) -> u8 --- + mouse_down :: proc(state: ^input_state, button: mouse_button) -> bool --- + mouse_pressed :: proc(state: ^input_state, button: mouse_button) -> u8 --- + mouse_released :: proc(state: ^input_state, button: mouse_button) -> u8 --- + mouse_clicked :: proc(state: ^input_state, button: mouse_button) -> bool --- + mouse_double_clicked :: proc(state: ^input_state, button: mouse_button) -> bool --- + mouse_position :: proc(state: ^input_state) -> vec2 --- + mouse_delta :: proc(state: ^input_state) -> vec2 --- + mouse_wheel :: proc(state: ^input_state) -> vec2 --- + input_text_utf32 :: proc(arena: ^arena, state: ^input_state) -> str32 --- + input_text_utf8 :: proc(arena: ^arena, state: ^input_state) -> str8 --- + clipboard_pasted :: proc(state: ^input_state) -> bool --- + clipboard_pasted_text :: proc(state: ^input_state) -> str8 --- + key_mods :: proc(state: ^input_state) -> keymod_flags --- + ui_init :: proc(_context: ^ui_context) --- + ui_get_context :: proc() -> ^ui_context --- + ui_set_context :: proc(_context: ^ui_context) --- + ui_process_event :: proc(event: ^event) --- + ui_begin_frame :: proc(size: vec2, #by_ptr defaultStyle: ui_style, mask: ui_style_mask) --- + ui_end_frame :: proc() --- + ui_draw :: proc() --- + ui_set_theme :: proc(theme: ^ui_theme) --- + ui_key_make_str8 :: proc(string: str8) -> ui_key --- + ui_key_make_path :: proc(path: str8_list) -> ui_key --- + ui_box_make_str8 :: proc(string: str8, flags: ui_flags) -> ^ui_box --- + ui_box_begin_str8 :: proc(string: str8, flags: ui_flags) -> ^ui_box --- + ui_box_end :: proc() -> ^ui_box --- + ui_box_push :: proc(box: ^ui_box) --- + ui_box_pop :: proc() --- + ui_box_top :: proc() -> ^ui_box --- + ui_box_lookup_key :: proc(key: ui_key) -> ^ui_box --- + ui_box_lookup_str8 :: proc(string: str8) -> ^ui_box --- + ui_box_set_draw_proc :: proc(box: ^ui_box, _proc: ui_box_draw_proc, data: rawptr) --- + ui_box_closed :: proc(box: ^ui_box) -> bool --- + ui_box_set_closed :: proc(box: ^ui_box, closed: bool) --- + ui_box_active :: proc(box: ^ui_box) -> bool --- + ui_box_activate :: proc(box: ^ui_box) --- + ui_box_deactivate :: proc(box: ^ui_box) --- + ui_box_hot :: proc(box: ^ui_box) -> bool --- + ui_box_set_hot :: proc(box: ^ui_box, hot: bool) --- + ui_box_sig :: proc(box: ^ui_box) -> ui_sig --- + ui_tag_make_str8 :: proc(string: str8) -> ui_tag --- + ui_tag_box_str8 :: proc(box: ^ui_box, string: str8) --- + ui_tag_next_str8 :: proc(string: str8) --- + ui_apply_style_with_mask :: proc(dst: ^ui_style, src: ^ui_style, mask: ui_style_mask) --- + ui_pattern_push :: proc(arena: ^arena, pattern: ^ui_pattern, selector: ui_selector) --- + ui_pattern_all :: proc() -> ui_pattern --- + ui_pattern_owner :: proc() -> ui_pattern --- + ui_style_next :: proc(#by_ptr style: ui_style, mask: ui_style_mask) --- + ui_style_match_before :: proc(pattern: ui_pattern, #by_ptr style: ui_style, mask: ui_style_mask) --- + ui_style_match_after :: proc(pattern: ui_pattern, #by_ptr style: ui_style, mask: ui_style_mask) --- + ui_label :: proc(label: cstring) -> ui_sig --- + ui_label_str8 :: proc(label: str8) -> ui_sig --- + ui_button :: proc(label: cstring) -> ui_sig --- + ui_checkbox :: proc(name: cstring, checked: ^bool) -> ui_sig --- + ui_slider :: proc(name: cstring, value: ^f32) -> ^ui_box --- + ui_scrollbar :: proc(name: cstring, thumbRatio: f32, scrollValue: ^f32) -> ^ui_box --- + ui_tooltip :: proc(label: cstring) --- + ui_panel_begin :: proc(name: cstring, flags: ui_flags) --- + ui_panel_end :: proc() --- + ui_menu_bar_begin :: proc(name: cstring) --- + ui_menu_bar_end :: proc() --- + ui_menu_begin :: proc(label: cstring) --- + ui_menu_end :: proc() --- + ui_menu_button :: proc(label: cstring) -> ui_sig --- + ui_text_box :: proc(name: cstring, arena: ^arena, text: str8) -> ui_text_box_result --- + ui_select_popup :: proc(name: cstring, info: ^ui_select_popup_info) -> ui_select_popup_info --- + ui_radio_group :: proc(name: cstring, info: ^ui_radio_group_info) -> ui_radio_group_info --- +} + diff --git a/examples/all/all_main.odin b/examples/all/all_main.odin index 62b891352..63bd386f8 100644 --- a/examples/all/all_main.odin +++ b/examples/all/all_main.odin @@ -136,6 +136,7 @@ import time "core:time" import datetime "core:time/datetime" import flags "core:flags" +import orca "core:sys/orca" import sysinfo "core:sys/info" import unicode "core:unicode" @@ -256,6 +257,7 @@ _ :: thread _ :: time _ :: datetime _ :: flags +_ :: orca _ :: sysinfo _ :: unicode _ :: uuid |