push orca target and old bindings

This commit is contained in:
skytrias
2024-03-18 22:09:17 +01:00
parent 6cb74b63ec
commit bca4c37f02
20 changed files with 2312 additions and 8 deletions

View File

@@ -1,4 +1,4 @@
//+build js, wasi, freestanding, essence
//+build js, wasi, freestanding, essence, orca
//+private
package runtime

View File

@@ -0,0 +1,14 @@
//+build orca
//+private
package runtime
// TODO
// foreign import
// fd_write :: proc "contextless" ()
import "core:sys/wasm/wasi"
_stderr_write :: proc "contextless" (data: []byte) -> (int, _OS_Errno) {
data := (wasi.ciovec_t)(data)
n, err := wasi.fd_write(1, {data})
return int(n), _OS_Errno(err)
}

View File

@@ -2,6 +2,7 @@
//+private
package runtime
// TODO reimplement fd_write
import "core:sys/wasm/wasi"
_stderr_write :: proc "contextless" (data: []byte) -> (int, _OS_Errno) {

View File

@@ -25,6 +25,17 @@ when ODIN_NO_CRT && ODIN_OS == .Windows {
RtlMoveMemory(dst, src, len)
return dst
}
} else when ODIN_OS == .Orca {
memset :: proc "c" (ptr: rawptr, val: i32, len: int) -> rawptr {
if ptr != nil && len != 0 {
b := byte(val)
p := ([^]byte)(ptr)
for i := 0; i < len; i += 1 {
p[i] = b
}
}
return ptr
}
} else when ODIN_NO_CRT || (ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32) {
@(link_name="memset", linkage="strong", require)
memset :: proc "c" (ptr: rawptr, val: i32, len: int) -> rawptr {

109
core/os/os_orca.odin Normal file
View File

@@ -0,0 +1,109 @@
package os
import "core:sys/wasm/wasi"
import "base:runtime"
Handle :: distinct i32
Errno :: distinct i32
ERROR_NONE :: Errno(wasi.errno_t.SUCCESS)
O_RDONLY :: 0x00000
O_WRONLY :: 0x00001
O_RDWR :: 0x00002
O_CREATE :: 0x00040
O_EXCL :: 0x00080
O_NOCTTY :: 0x00100
O_TRUNC :: 0x00200
O_NONBLOCK :: 0x00800
O_APPEND :: 0x00400
O_SYNC :: 0x01000
O_ASYNC :: 0x02000
O_CLOEXEC :: 0x80000
stdin: Handle = 0
stdout: Handle = 1
stderr: Handle = 2
current_dir: Handle = 3
write :: proc(fd: Handle, data: []byte) -> (int, Errno) {
iovs := wasi.ciovec_t(data)
n, err := wasi.fd_write(wasi.fd_t(fd), {iovs})
return int(n), Errno(err)
}
read :: proc(fd: Handle, data: []byte) -> (int, Errno) {
iovs := wasi.iovec_t(data)
n, err := wasi.fd_read(wasi.fd_t(fd), {iovs})
return int(n), Errno(err)
}
write_at :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) {
iovs := wasi.ciovec_t(data)
n, err := wasi.fd_pwrite(wasi.fd_t(fd), {iovs}, wasi.filesize_t(offset))
return int(n), Errno(err)
}
read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) {
iovs := wasi.iovec_t(data)
n, err := wasi.fd_pread(wasi.fd_t(fd), {iovs}, wasi.filesize_t(offset))
return int(n), Errno(err)
}
open :: proc(path: string, mode: int = O_RDONLY, perm: int = 0) -> (Handle, Errno) {
oflags: wasi.oflags_t
if mode & O_CREATE == O_CREATE {
oflags += {.CREATE}
}
if mode & O_EXCL == O_EXCL {
oflags += {.EXCL}
}
if mode & O_TRUNC == O_TRUNC {
oflags += {.TRUNC}
}
rights: wasi.rights_t = {.FD_SEEK, .FD_FILESTAT_GET}
switch mode & (O_RDONLY|O_WRONLY|O_RDWR) {
case O_RDONLY: rights += {.FD_READ}
case O_WRONLY: rights += {.FD_WRITE}
case O_RDWR: rights += {.FD_READ, .FD_WRITE}
}
fdflags: wasi.fdflags_t
if mode & O_APPEND == O_APPEND {
fdflags += {.APPEND}
}
if mode & O_NONBLOCK == O_NONBLOCK {
fdflags += {.NONBLOCK}
}
if mode & O_SYNC == O_SYNC {
fdflags += {.SYNC}
}
fd, err := wasi.path_open(wasi.fd_t(current_dir),{.SYMLINK_FOLLOW},path,oflags,rights,{},fdflags)
return Handle(fd), Errno(err)
}
close :: proc(fd: Handle) -> Errno {
err := wasi.fd_close(wasi.fd_t(fd))
return Errno(err)
}
seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
n, err := wasi.fd_seek(wasi.fd_t(fd), wasi.filedelta_t(offset), wasi.whence_t(whence))
return i64(n), Errno(err)
}
current_thread_id :: proc "contextless" () -> int {
return 0
}
@(private)
_processor_core_count :: proc() -> int {
return 1
}
file_size :: proc(fd: Handle) -> (i64, Errno) {
stat, err := wasi.fd_filestat_get(wasi.fd_t(fd))
if err != nil {
return 0, Errno(err)
}
return i64(stat.size), 0
}
exit :: proc "contextless" (code: int) -> ! {
runtime._cleanup_runtime_contextless()
wasi.proc_exit(wasi.exitcode_t(code))
}

View File

@@ -0,0 +1,58 @@
package orca
import "core:math"
// TODO use orcas or native?
@(default_calling_convention="c", link_prefix="oc_")
foreign {
mat2x3_mul_m :: proc(lhs, rhs: mat2x3) -> mat2x3 ---
mat2x3_inv :: proc(x: mat2x3) -> mat2x3 ---
mat2x3_mul :: proc(m: mat2x3, p: vec2) -> vec2 ---
mat2x3_rotate :: proc(radians: f32) -> mat2x3 ---
mat2x3_translate :: proc(x, y: f32) -> mat2x3 ---
}
// mat2x3_mul_m :: proc "contextless" (lhs, rhs: mat2x3) -> (res: mat2x3) {
// res[0] = lhs[0] * rhs[0] + lhs[1] * rhs[3]
// res[1] = lhs[0] * rhs[1] + lhs[1] * rhs[4]
// res[2] = lhs[0] * rhs[2] + lhs[1] * rhs[5] + lhs[2]
// res[3] = lhs[3] * rhs[0] + lhs[4] * rhs[3]
// res[4] = lhs[3] * rhs[1] + lhs[4] * rhs[4]
// res[5] = lhs[3] * rhs[2] + lhs[4] * rhs[5] + lhs[5]
// return
// }
// mat2x3_inv :: proc "contextless" (x: mat2x3) -> (res: mat2x3) {
// res[0] = x[4] / (x[0] * x[4] - x[1] * x[3])
// res[1] = x[1] / (x[1] * x[3] - x[0] * x[4])
// res[3] = x[3] / (x[1] * x[3] - x[0] * x[4])
// res[4] = x[0] / (x[0] * x[4] - x[1] * x[3])
// res[2] = -(x[2] * res[0] + x[5] * res[1])
// res[5] = -(x[2] * res[3] + x[5] * res[4])
// return
// }
// mat2x3_mul :: proc "contextless" (m: mat2x3, p: vec2) -> vec2 {
// return {
// p.x * m[0] + p.y * m[1] + m[2],
// p.x * m[3] + p.y * m[4] + m[5],
// }
// }
// mat2x3_rotate :: proc "contextless" (radians: f32) -> mat2x3 {
// sinRot := math.sin(radians)
// cosRot := math.cos(radians)
// rot := mat2x3 {
// cosRot, -sinRot, 0,
// sinRot, cosRot, 0,
// }
// return rot
// }
// mat2x3_translate :: proc "contextless" (x, y: f32) -> mat2x3 {
// return {
// 1, 0, x,
// 0, 1, y,
// }
// }

366
core/sys/orca/app.odin Normal file
View File

@@ -0,0 +1,366 @@
package orca
import "core:c"
window :: u64
mouse_cursor :: enum c.int {
ARROW,
RESIZE_0,
RESIZE_90,
RESIZE_45,
RESIZE_135,
TEXT,
}
window_style :: enum u32 {
NO_TITLE = 0x01 << 0,
FIXED_SIZE = 0x01 << 1,
NO_CLOSE = 0x01 << 2,
NO_MINIFY = 0x01 << 3,
NO_FOCUS = 0x01 << 4,
FLOAT = 0x01 << 5,
POPUPMENU = 0x01 << 6,
NO_BUTTONS = 0x01 << 7
}
event_type :: enum c.int {
NONE,
KEYBOARD_MODS, //TODO: remove, keep only key?
KEYBOARD_KEY,
KEYBOARD_CHAR,
MOUSE_BUTTON,
MOUSE_MOVE,
MOUSE_WHEEL,
MOUSE_ENTER,
MOUSE_LEAVE,
CLIPBOARD_PASTE,
WINDOW_RESIZE,
WINDOW_MOVE,
WINDOW_FOCUS,
WINDOW_UNFOCUS,
WINDOW_HIDE, // rename to minimize?
WINDOW_SHOW, // rename to restore?
WINDOW_CLOSE,
PATHDROP,
FRAME,
QUIT
}
key_action :: enum c.int {
NO_ACTION,
PRESS,
RELEASE,
REPEAT
}
key_code :: enum c.int {
KEY_UNKNOWN = '\x00',
KEY_SPACE = ' ',
KEY_APOSTROPHE = '\'',
KEY_COMMA = ',',
KEY_MINUS = '-',
KEY_PERIOD = '.',
KEY_SLASH = '/',
KEY_0 = '0',
KEY_1 = '1',
KEY_2 = '2',
KEY_3 = '3',
KEY_4 = '4',
KEY_5 = '5',
KEY_6 = '6',
KEY_7 = '7',
KEY_8 = '8',
KEY_9 = '9',
KEY_SEMICOLON = ';',
KEY_EQUAL = '=',
KEY_LEFT_BRACKET = '[',
KEY_BACKSLASH = '\\',
KEY_RIGHT_BRACKET = ']',
KEY_GRAVE_ACCENT = '`',
KEY_A = 'a',
KEY_B = 'b',
KEY_C = 'c',
KEY_D = 'd',
KEY_E = 'e',
KEY_F = 'f',
KEY_G = 'g',
KEY_H = 'h',
KEY_I = 'i',
KEY_J = 'j',
KEY_K = 'k',
KEY_L = 'l',
KEY_M = 'm',
KEY_N = 'n',
KEY_O = 'o',
KEY_P = 'p',
KEY_Q = 'q',
KEY_R = 'r',
KEY_S = 's',
KEY_T = 't',
KEY_U = 'u',
KEY_V = 'v',
KEY_W = 'w',
KEY_X = 'x',
KEY_Y = 'y',
KEY_Z = 'z',
KEY_WORLD_1 = 161,
KEY_WORLD_2 = 162,
KEY_ESCAPE = 256,
KEY_ENTER = 257,
KEY_TAB = 258,
KEY_BACKSPACE = 259,
KEY_INSERT = 260,
KEY_DELETE = 261,
KEY_RIGHT = 262,
KEY_LEFT = 263,
KEY_DOWN = 264,
KEY_UP = 265,
KEY_PAGE_UP = 266,
KEY_PAGE_DOWN = 267,
KEY_HOME = 268,
KEY_END = 269,
KEY_CAPS_LOCK = 280,
KEY_SCROLL_LOCK = 281,
KEY_NUM_LOCK = 282,
KEY_PRINT_SCREEN = 283,
KEY_PAUSE = 284,
KEY_F1 = 290,
KEY_F2 = 291,
KEY_F3 = 292,
KEY_F4 = 293,
KEY_F5 = 294,
KEY_F6 = 295,
KEY_F7 = 296,
KEY_F8 = 297,
KEY_F9 = 298,
KEY_F10 = 299,
KEY_F11 = 300,
KEY_F12 = 301,
KEY_F13 = 302,
KEY_F14 = 303,
KEY_F15 = 304,
KEY_F16 = 305,
KEY_F17 = 306,
KEY_F18 = 307,
KEY_F19 = 308,
KEY_F20 = 309,
KEY_F21 = 310,
KEY_F22 = 311,
KEY_F23 = 312,
KEY_F24 = 313,
KEY_F25 = 314,
KEY_KP_0 = 320,
KEY_KP_1 = 321,
KEY_KP_2 = 322,
KEY_KP_3 = 323,
KEY_KP_4 = 324,
KEY_KP_5 = 325,
KEY_KP_6 = 326,
KEY_KP_7 = 327,
KEY_KP_8 = 328,
KEY_KP_9 = 329,
KEY_KP_DECIMAL = 330,
KEY_KP_DIVIDE = 331,
KEY_KP_MULTIPLY = 332,
KEY_KP_SUBTRACT = 333,
KEY_KP_ADD = 334,
KEY_KP_ENTER = 335,
KEY_KP_EQUAL = 336,
KEY_LEFT_SHIFT = 340,
KEY_LEFT_CONTROL = 341,
KEY_LEFT_ALT = 342,
KEY_LEFT_SUPER = 343,
KEY_RIGHT_SHIFT = 344,
KEY_RIGHT_CONTROL = 345,
KEY_RIGHT_ALT = 346,
KEY_RIGHT_SUPER = 347,
KEY_MENU = 348,
}
scan_code :: enum c.int {
SCANCODE_UNKNOWN = 0,
SCANCODE_SPACE = 32,
SCANCODE_APOSTROPHE = 39,
SCANCODE_COMMA = 44,
SCANCODE_MINUS = 45,
SCANCODE_PERIOD = 46,
SCANCODE_SLASH = 47,
SCANCODE_0 = 48,
SCANCODE_1 = 49,
SCANCODE_2 = 50,
SCANCODE_3 = 51,
SCANCODE_4 = 52,
SCANCODE_5 = 53,
SCANCODE_6 = 54,
SCANCODE_7 = 55,
SCANCODE_8 = 56,
SCANCODE_9 = 57,
SCANCODE_SEMICOLON = 59,
SCANCODE_EQUAL = 61,
SCANCODE_LEFT_BRACKET = 91,
SCANCODE_BACKSLASH = 92,
SCANCODE_RIGHT_BRACKET = 93,
SCANCODE_GRAVE_ACCENT = 96,
SCANCODE_A = 97,
SCANCODE_B = 98,
SCANCODE_C = 99,
SCANCODE_D = 100,
SCANCODE_E = 101,
SCANCODE_F = 102,
SCANCODE_G = 103,
SCANCODE_H = 104,
SCANCODE_I = 105,
SCANCODE_J = 106,
SCANCODE_K = 107,
SCANCODE_L = 108,
SCANCODE_M = 109,
SCANCODE_N = 110,
SCANCODE_O = 111,
SCANCODE_P = 112,
SCANCODE_Q = 113,
SCANCODE_R = 114,
SCANCODE_S = 115,
SCANCODE_T = 116,
SCANCODE_U = 117,
SCANCODE_V = 118,
SCANCODE_W = 119,
SCANCODE_X = 120,
SCANCODE_Y = 121,
SCANCODE_Z = 122,
SCANCODE_WORLD_1 = 161,
SCANCODE_WORLD_2 = 162,
SCANCODE_ESCAPE = 256,
SCANCODE_ENTER = 257,
SCANCODE_TAB = 258,
SCANCODE_BACKSPACE = 259,
SCANCODE_INSERT = 260,
SCANCODE_DELETE = 261,
SCANCODE_RIGHT = 262,
SCANCODE_LEFT = 263,
SCANCODE_DOWN = 264,
SCANCODE_UP = 265,
SCANCODE_PAGE_UP = 266,
SCANCODE_PAGE_DOWN = 267,
SCANCODE_HOME = 268,
SCANCODE_END = 269,
SCANCODE_CAPS_LOCK = 280,
SCANCODE_SCROLL_LOCK = 281,
SCANCODE_NUM_LOCK = 282,
SCANCODE_PRINT_SCREEN = 283,
SCANCODE_PAUSE = 284,
SCANCODE_F1 = 290,
SCANCODE_F2 = 291,
SCANCODE_F3 = 292,
SCANCODE_F4 = 293,
SCANCODE_F5 = 294,
SCANCODE_F6 = 295,
SCANCODE_F7 = 296,
SCANCODE_F8 = 297,
SCANCODE_F9 = 298,
SCANCODE_F10 = 299,
SCANCODE_F11 = 300,
SCANCODE_F12 = 301,
SCANCODE_F13 = 302,
SCANCODE_F14 = 303,
SCANCODE_F15 = 304,
SCANCODE_F16 = 305,
SCANCODE_F17 = 306,
SCANCODE_F18 = 307,
SCANCODE_F19 = 308,
SCANCODE_F20 = 309,
SCANCODE_F21 = 310,
SCANCODE_F22 = 311,
SCANCODE_F23 = 312,
SCANCODE_F24 = 313,
SCANCODE_F25 = 314,
SCANCODE_KP_0 = 320,
SCANCODE_KP_1 = 321,
SCANCODE_KP_2 = 322,
SCANCODE_KP_3 = 323,
SCANCODE_KP_4 = 324,
SCANCODE_KP_5 = 325,
SCANCODE_KP_6 = 326,
SCANCODE_KP_7 = 327,
SCANCODE_KP_8 = 328,
SCANCODE_KP_9 = 329,
SCANCODE_KP_DECIMAL = 330,
SCANCODE_KP_DIVIDE = 331,
SCANCODE_KP_MULTIPLY = 332,
SCANCODE_KP_SUBTRACT = 333,
SCANCODE_KP_ADD = 334,
SCANCODE_KP_ENTER = 335,
SCANCODE_KP_EQUAL = 336,
SCANCODE_LEFT_SHIFT = 340,
SCANCODE_LEFT_CONTROL = 341,
SCANCODE_LEFT_ALT = 342,
SCANCODE_LEFT_SUPER = 343,
SCANCODE_RIGHT_SHIFT = 344,
SCANCODE_RIGHT_CONTROL = 345,
SCANCODE_RIGHT_ALT = 346,
SCANCODE_RIGHT_SUPER = 347,
SCANCODE_MENU = 348,
}
keymod_flags :: enum c.int {
NONE = 0x00,
ALT = 0x01,
SHIFT = 0x02,
CTRL = 0x04,
CMD = 0x08,
MAIN_MODIFIER = 0x10 /* CMD on Mac, CTRL on Win32 */
}
mouse_button :: enum c.int {
LEFT = 0x00,
RIGHT = 0x01,
MIDDLE = 0x02,
EXT1 = 0x03,
EXT2 = 0x04,
}
// keyboard and mouse buttons input
key_event :: struct {
action: key_action,
scanCode: scan_code,
keyCode: key_code,
button: mouse_button,
mods: keymod_flags,
clickCount: u8,
}
// character input
char_event :: struct {
codepoint: utf32,
sequence: [8]c.char,
seqLen: u8,
}
// mouse move/scroll
mouse_event :: struct {
x: f32,
y: f32,
deltaX: f32,
deltaY: f32,
mods: keymod_flags,
}
// window resize / move
move_event :: struct {
frame: rect,
content: rect,
}
event :: struct {
//TODO clipboard and path drop
window: window,
type: event_type,
_: struct #raw_union {
key: key_event,
character: char_event,
mouse: mouse_event,
move: move_event,
paths: str8_list,
}
}

246
core/sys/orca/graphics.odin Normal file
View File

@@ -0,0 +1,246 @@
package orca
import "core:c"
// types
color :: [4]f32
utf32 :: u32
// handles
surface :: u64
font :: u64
image :: u64
canvas :: u64
joint_type :: enum c.int {
MITER,
BEVEL,
NONE,
}
cap_type :: enum c.int {
NONE,
SQUARE,
}
font_metrics :: 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)
lineGap: f32, // spacing between one row's descent and the next row's ascent
xHeight: f32, // height of the lower case letter 'x'
capHeight: f32, // height of the upper case letter 'M'
width: f32, // maximum width of the font
}
glyph_metrics :: struct {
ink: rect,
advance: vec2,
}
text_metrics :: struct {
ink: rect,
logical: rect,
advance: vec2,
}
rect_atlas :: struct {
arena: ^arena,
size: vec2i,
pos: vec2i,
lineHeight: u32,
}
image_region :: struct {
image: image,
rect: rect,
}
//------------------------------------------------------------------------------------------
// graphics surface
//------------------------------------------------------------------------------------------
@(default_calling_convention="c", link_prefix="oc_")
foreign {
surface_nil :: proc() -> surface ---
surface_is_nil :: proc() -> c.bool ---
surface_canvas :: proc() -> surface ---
surface_gles :: proc() -> surface ---
surface_destroy :: proc(surface: surface) ---
surface_select :: proc(surface: surface) ---
surface_deselect :: proc() ---
surface_present :: 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) ---
}
//------------------------------------------------------------------------------------------
// 2D canvas command buffer
//------------------------------------------------------------------------------------------
@(default_calling_convention="c", link_prefix="oc_")
foreign {
canvas_nil :: proc() -> canvas ---
canvas_is_nil :: proc(canvas: canvas) -> c.bool ---
canvas_create :: proc() -> canvas ---
canvas_destroy :: proc(canvas: canvas) ---
canvas_set_current :: proc(_canvas: canvas) -> canvas ---
canvas_select :: proc(_canvas: canvas) -> canvas ---
render :: proc(canvas: canvas) ---
}
//------------------------------------------------------------------------------------------
// transform and clipping
//------------------------------------------------------------------------------------------
@(default_calling_convention="c", link_prefix="oc_")
foreign {
matrix_push :: proc(mat: mat2x3) ---
matrix_multiply_push :: proc(mat: mat2x3) ---
matrix_pop :: proc() ---
matrix_top :: proc() -> mat2x3 ---
clip_push :: proc(x, y, w, h: f32) ---
clip_pop :: proc() ---
clip_top :: proc() -> rect ---
}
//------------------------------------------------------------------------------------------
// graphics attributes setting/getting
//------------------------------------------------------------------------------------------
@(default_calling_convention="c", link_prefix="oc_")
foreign {
set_color :: proc(color: color) ---
set_color_rgba :: proc(r, g, b, a: f32) ---
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: c.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 ---
}
//------------------------------------------------------------------------------------------
// path construction
//------------------------------------------------------------------------------------------
@(default_calling_convention="c", link_prefix="oc_")
foreign {
get_position :: proc() -> vec2 ---
move_to :: proc(x, y: f32) ---
line_to :: proc(x, y: f32) ---
quadratic_to :: proc(x1, y1, x2, y2: f32) ---
cubic_to :: proc(x1, y1, x2, y2, x3, y3: f32) ---
close_path :: proc() ---
glyph_outlines :: proc(glyphIndices: str32) -> rect ---
codepoints_outlines :: proc(str: str32) ---
text_outlines :: proc(str: str8) ---
}
//------------------------------------------------------------------------------------------
// clear/fill/stroke
//------------------------------------------------------------------------------------------
@(default_calling_convention="c", link_prefix="oc_")
foreign {
clear :: proc() ---
fill :: proc() ---
stroke :: proc() ---
}
//------------------------------------------------------------------------------------------
// shapes helpers
//------------------------------------------------------------------------------------------
@(default_calling_convention="c", link_prefix="oc_")
foreign {
rectangle_fill :: proc(x, y, w, h: f32) ---
rectangle_stroke :: proc(x, y, w, h: f32) ---
rounded_rectangle_fill :: proc(x, y, w, h, r: f32) ---
rounded_rectangle_stroke :: proc(x, y, w, h, r: f32) ---
ellipse_fill :: proc(x, y, rx, ry: f32) ---
ellipse_stroke :: proc(x, y, rx, ry: f32) ---
circle_fill :: proc(x, y, r: f32) ---
circle_stroke :: proc(x, y, r: f32) ---
arc :: proc(x, y, r, arcAngle, startAngle: f32) ---
image_draw :: proc(image: image, rect: rect) ---
image_draw_region :: proc(image: image, srcRegion, dstRegion: rect) ---
text_fill :: proc(x, y: f32, text: str8) ---
}
//------------------------------------------------------------------------------------------
// fonts
//------------------------------------------------------------------------------------------
@(default_calling_convention="c", link_prefix="oc_")
foreign {
font_nil :: proc() -> font ---
font_is_nil :: proc(font: font) -> c.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 ---
}
//------------------------------------------------------------------------------------------
// images
//------------------------------------------------------------------------------------------
@(default_calling_convention="c", link_prefix="oc_")
foreign {
image_nil :: proc() -> image ---
image_is_nil :: proc(a: image) -> c.bool ---
image_create :: proc(surface: surface, width, height: u32) -> image ---
image_create_from_rgba8 :: proc(surface: surface, width, height: u32, pixels: [^]u8) -> image ---
image_create_from_memory :: proc(surface: surface, mem: str8, flip: c.bool) -> image ---
image_create_from_file :: proc(surface: surface, file: file, flip: c.bool) -> image ---
image_create_from_path :: proc(surface: surface, path: str8, flip: c.bool) -> image ---
image_destroy :: proc(image: image) ---
image_upload_region_rgba8 :: proc(image: image, region: rect, pixels: [^]u8) ---
image_size :: proc(image: image) -> vec2 ---
}
//------------------------------------------------------------------------------------------
// image atlas
//------------------------------------------------------------------------------------------
@(default_calling_convention="c", link_prefix="oc_")
foreign {
rect_atlas_create :: proc(arena: ^arena, width, height: i32) -> ^rect_atlas ---
rect_atlas_alloc :: proc(atlas: ^rect_atlas, width, height: i32) -> rect ---
rect_atlas_recycle :: proc(atlas: ^rect_atlas, rect: rect) ---
image_atlas_allfrom_rgba8 :: proc(atlas: ^rect_atlas, backingImage: image, width, height: u32, pixels: [^]u8) -> image_region ---
image_atlas_allfrom_memory :: proc(atlas: ^rect_atlas, backingImage: image, mem: str8, flip: c.bool) -> image_region ---
image_atlas_allfrom_file :: proc(atlas: ^rect_atlas, backingImage: image, file: file, flip: c.bool) -> image_region ---
image_atlas_allfrom_path :: proc(atlas: ^rect_atlas, backingImage: image, path: str8, flip: c.bool) -> image_region ---
image_atlas_recycle :: proc(atlas: ^rect_atlas, imageRgn: image_region) ---
}

View File

@@ -0,0 +1,59 @@
package orca
import "core:c"
key_state :: struct {
lastUpdate: u64,
transitionCount: u32,
repeatCount: u32,
down: c.bool,
sysClicked: c.bool,
sysDoubleClicked: c.bool,
sysTripleClicked: c.bool,
}
keyboard_state :: struct {
keys: [len(key_code)]key_state,
mods: keymod_flags,
}
mouse_state :: struct {
lastUpdate: u64,
posValid: c.bool,
pos: vec2,
delta: vec2,
wheel: vec2,
_: struct #raw_union {
buttons: [len(mouse_button)]key_state,
_: struct {
left: key_state,
right: key_state,
middle: key_state,
ext1: key_state,
ext2: key_state,
}
}
}
INPUT_TEXT_BACKING_SIZE :: 64
text_state :: struct {
lastUpdate: u64,
backing: [INPUT_TEXT_BACKING_SIZE]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,
}

159
core/sys/orca/io.odin Normal file
View File

@@ -0,0 +1,159 @@
package orca
import "core:c"
file :: distinct u64 // handle
file_access :: enum u16 {
NONE = 0,
READ = 1 << 1,
WRITE = 1 << 2,
}
file_open_flags :: enum u16 {
NONE = 0,
APPEND = 1 << 1,
TRUNCATE = 1 << 2,
CREATE = 1 << 3,
SYMLINK = 1 << 4,
NO_FOLLOW = 1 << 5,
RESTRICT = 1 << 6,
}
file_whence :: enum c.int {
SEEK_SET,
SEEK_END,
SEEK_CURRENT,
}
io_error :: enum i32 {
OK = 0,
ERR_UNKNOWN,
ERR_OP, // unsupported operation
ERR_HANDLE, // invalid handle
ERR_PREV, // previously had a fatal error (last error stored on handle)
ERR_ARG, // invalid argument or argument combination
ERR_PERM, // access denied
ERR_SPACE, // no space left
ERR_NO_ENTRY, // file or directory does not exist
ERR_EXISTS, // file already exists
ERR_NOT_DIR, // path element is not a directory
ERR_DIR, // attempted to write directory
ERR_MAX_FILES, // max open files reached
ERR_MAX_LINKS, // too many symbolic links in path
ERR_PATH_LENGTH, // path too long
ERR_FILE_SIZE, // file too big
ERR_OVERFLOW, // offset too big
ERR_NOT_READY, // no data ready to be read/written
ERR_MEM, // failed to allocate memory
ERR_INTERRUPT, // operation interrupted by a signal
ERR_PHYSICAL, // physical IO error
ERR_NO_DEVICE, // device not found
ERR_WALKOUT, // attempted to walk out of root directory
}
//----------------------------------------------------------------
// File System wrapper API
//----------------------------------------------------------------
file_type :: enum c.int {
UNKNOWN,
REGULAR,
DIRECTORY,
SYMLINK,
BLOCK,
CHARACTER,
FIFO,
SOCKET,
}
file_perm :: enum u16 {
OTHER_EXEC = 1 << 0,
OTHER_WRITE = 1 << 1,
OTHER_READ = 1 << 2,
GROUP_EXEC = 1 << 3,
GROUP_WRITE = 1 << 4,
GROUP_READ = 1 << 5,
OWNER_EXEC = 1 << 6,
OWNER_WRITE = 1 << 7,
OWNER_READ = 1 << 8,
STICKY_BIT = 1 << 9,
SET_GID = 1 << 10,
SET_UID = 1 << 11,
}
datestamp :: struct {
seconds: i64, // seconds relative to NTP epoch.
fraction: u64, // fraction of seconds elapsed since the time specified by seconds.
}
file_status :: struct {
uid: u64,
type: file_type,
perm: file_perm,
size: u64,
creationDate: datestamp,
accessDate: datestamp,
modificationDate: datestamp,
}
// TODO file dialogs
// typedef struct oc_file_open_with_dialog_elt
// {
// oc_list_elt listElt;
// oc_file file;
// } oc_file_open_with_dialog_elt;
// typedef struct oc_file_open_with_dialog_result
// {
// oc_file_dialog_button button;
// oc_file file;
// oc_list selection;
// } oc_file_open_with_dialog_result;
// file_open_with_dialog_result :: u64 // TODO
// file_dialog_desc :: u64 // TODO
//----------------------------------------------------------------
// Low-level File IO API
//----------------------------------------------------------------
// @(default_calling_convention="c", link_prefix="oc_")
// foreign {
// oc_io_cmp oc_io_wait_single_req(oc_io_req* req);
// }
//----------------------------------------------------------------
// High-level File IO API
//----------------------------------------------------------------
@(default_calling_convention="c", link_prefix="oc_")
foreign {
file_nil :: proc() -> file ---
file_is_nil :: proc(handle: file) -> c.bool ---
file_open :: proc(path: str8, rights: file_access, flags: file_open_flags) -> file ---
file_open_at :: proc(dir: file, path: str8, rights: file_access, flags: file_open_flags) -> file ---
file_close :: proc(file: file) ---
file_last_error :: proc(handle: file) -> io_error ---
file_pos :: proc(file: file) -> i64 ---
file_seek :: proc(file: file, offset: i64, whence: file_whence) -> i64 ---
file_write :: proc(file: file, size: u64, buffer: [^]byte) -> u64 ---
file_read :: proc(file: file, size: u64, buffer: [^]byte) -> u64 ---
file_get_status :: proc(file: file) -> file_status ---
file_size :: proc(file: file) -> u64 ---
}
//----------------------------------------------------------------
// Asking users for file capabilities
//----------------------------------------------------------------
// @(default_calling_convention="c", link_prefix="oc_")
// foreign {
// file_open_with_request :: proc(path: str8, rights: file_access, flags: file_open_flags) -> file ---
// file_open_with_dialog :: proc(arena: ^arena, rights: file_access, flags: file_open_flags, desc: ^file_dialog_desc) -> file_open_with_dialog_result ---
// }

117
core/sys/orca/lists.odin Normal file
View File

@@ -0,0 +1,117 @@
package orca
// TODO could check if container/intrusive/list/intrusive_list.odin can be used
//----------------------------------------------------------------
// Lists
//----------------------------------------------------------------
list_elt :: struct {
prev: ^list_elt,
next: ^list_elt,
}
list :: struct {
first: ^list_elt,
last: ^list_elt,
}
list_init :: proc "c" (list: ^list) {
list.first = nil
list.last = nil
}
list_insert :: proc "c" (list: ^list, afterElt, elt: ^list_elt) {
elt.prev = afterElt
elt.next = afterElt.next
if afterElt.next != nil {
afterElt.next.prev = elt
} else {
list.last = elt
}
afterElt.next = elt
// OC_DEBUG_ASSERT(elt.next != elt, "list_insert(): can't insert an element into itself")
}
list_insert_before :: proc "c" (list: ^list, beforeElt, elt: ^list_elt) {
elt.next = beforeElt
elt.prev = beforeElt.prev
if beforeElt.prev != nil {
beforeElt.prev.next = elt
} else {
list.first = elt
}
beforeElt.prev = elt
// OC_DEBUG_ASSERT(elt.next != elt, "list_insert_before(): can't insert an element into itself")
}
list_remove :: proc "c" (list: ^list, elt: ^list_elt) {
if elt.prev != nil {
elt.prev.next = elt.next
} else {
// OC_DEBUG_ASSERT(list.first == elt)
list.first = elt.next
}
if elt.next != nil {
elt.next.prev = elt.prev
} else {
// OC_DEBUG_ASSERT(list.last == elt)
list.last = elt.prev
}
elt.prev = nil
elt.next = nil
}
list_push :: proc "c" (list: ^list, elt: ^list_elt) {
elt.next = list.first
elt.prev = nil
if list.first != nil {
list.first.prev = elt
} else {
list.last = elt
}
list.first = elt
}
list_pop :: proc "c" (list: ^list) -> ^list_elt {
elt := list.first
if elt != list.last {
list_remove(list, elt)
return elt
} else {
return nil
}
}
list_push_back :: proc "c" (list: ^list, elt: ^list_elt) {
elt.prev = list.last
elt.next = nil
if list.last != nil {
list.last.next = elt
} else {
list.first = elt
}
list.last = elt
}
list_append :: list_push_back
list_pop_back :: proc "c" (list: ^list) -> ^list_elt {
elt := list.last
if elt != nil {
list_remove(list, elt)
return elt
} else {
return nil
}
}
list_empty :: proc "c" (list: ^list) -> bool {
return list.first == nil || list.last == nil
}

32
core/sys/orca/orca.odin Normal file
View File

@@ -0,0 +1,32 @@
package orca
import "core:c"
vec2 :: [2]f32
vec3 :: [3]f32
vec4 :: [4]f32
vec2i :: [2]i32
// mat2x3 :: [6]f32
mat2x3 :: matrix[2, 3]f32
rect :: [4]f32
//------------------------------------------------------------------------------------------
// window
//------------------------------------------------------------------------------------------
@(default_calling_convention="c", link_prefix="oc_")
foreign {
window_set_title :: proc(title: str8) ---
window_set_size :: proc(size: vec2) ---
request_quit :: proc() ---
}
clock_kind :: enum c.int {
MONOTONIC,
UPTIME,
DATE,
}
@(default_calling_convention="c", link_prefix="oc_")
foreign {
clock_time :: proc(clock: clock_kind) -> f64 ---
}

685
core/sys/orca/ui.odin Normal file
View File

@@ -0,0 +1,685 @@
package orca
import "core:c"
ui_key :: struct {
hash: u64
}
ui_axis :: enum c.int {
X,
Y,
}
ui_align :: enum c.int {
START,
END,
CENTER,
}
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 c.int {
TEXT,
PIXELS,
CHILDREN,
PARENT,
PARENT_MINUS_PIXELS,
}
ui_size :: struct {
kind: ui_size_kind,
value: f32,
relax: f32,
minSize: f32,
}
ui_box_size :: [2]ui_size
ui_box_floating :: [2]c.bool
//NOTE: flags for axis-dependent properties (e.g. UI_STYLE_FLOAT_X/Y) need to be consecutive bits
// in order to play well with axis agnostic functions
ui_style_mask :: enum u64 {
NONE = 0,
SIZE_WIDTH = 1 << 1,
SIZE_HEIGHT = 1 << 2,
LAYOUT_AXIS = 1 << 3,
LAYOUT_ALIGN_X = 1 << 4,
LAYOUT_ALIGN_Y = 1 << 5,
LAYOUT_SPACING = 1 << 6,
LAYOUT_MARGIN_X = 1 << 7,
LAYOUT_MARGIN_Y = 1 << 8,
FLOAT_X = 1 << 9,
FLOAT_Y = 1 << 10,
COLOR = 1 << 11,
BG_COLOR = 1 << 12,
BORDER_COLOR = 1 << 13,
BORDER_SIZE = 1 << 14,
ROUNDNESS = 1 << 15,
FONT = 1 << 16,
FONT_SIZE = 1 << 17,
ANIMATION_TIME = 1 << 18,
ANIMATION_MASK = 1 << 19,
//masks
SIZE = SIZE_WIDTH | SIZE_HEIGHT,
LAYOUT_MARGINS = LAYOUT_MARGIN_X | LAYOUT_MARGIN_Y,
LAYOUT = LAYOUT_AXIS | LAYOUT_ALIGN_X | LAYOUT_ALIGN_Y | LAYOUT_SPACING | LAYOUT_MARGIN_X | LAYOUT_MARGIN_Y,
FLOAT = FLOAT_X | FLOAT_Y,
MASK_INHERITED = COLOR | FONT | FONT_SIZE | ANIMATION_TIME | ANIMATION_MASK,
}
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,
}
// TODO exteern
// ui_palette: UI_DARK_PALETTE
// ui_palette: UI_LIGHT_PALETTE
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,
}
@export UI_DARK_THEME: ui_theme
@export UI_LIGHT_THEME: ui_theme
ui_tag :: struct {
hash: u64,
}
ui_selector_kind :: enum c.int {
ANY,
OWNER,
TEXT,
TAG,
STATUS,
KEY,
}
ui_status :: enum u8 {
NONE = 0,
HOVER = 1 << 1,
HOT = 1 << 2,
ACTIVE = 1 << 3,
DRAGGING = 1 << 4,
}
ui_selector_op :: enum c.int {
DESCENDANT = 0,
AND = 1,
}
ui_selector :: struct {
listElt: list_elt,
kind: ui_selector_kind,
op: ui_selector_op,
type: struct #raw_union {
text: str8,
key: ui_key,
tag: ui_tag,
status: ui_status,
}
}
ui_pattern :: struct {
l: list,
}
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: c.bool,
released: c.bool,
clicked: c.bool,
doubleClicked: c.bool,
tripleClicked: c.bool,
rightPressed: c.bool,
dragging: c.bool,
hovering: c.bool,
pasted: c.bool,
}
ui_box_draw_proc :: proc "c" (box: ^ui_box, data: rawptr)
ui_flags :: enum c.int {
NONE = 0,
CLICKABLE = (1 << 0),
SCROLL_WHEEL_X = (1 << 1),
SCROLL_WHEEL_Y = (1 << 2),
BLOCK_MOUSE = (1 << 3),
HOT_ANIMATION = (1 << 4),
ACTIVE_ANIMATION = (1 << 5),
//WARN: these two following flags need to be kept as consecutive bits to
// play well with axis-agnostic functions
OVERFLOW_ALLOW_X = (1 << 6),
OVERFLOW_ALLOW_Y = (1 << 7),
CLIP = (1 << 8),
DRAW_BACKGROUND = (1 << 9),
DRAW_FOREGROUND = (1 << 10),
DRAW_BORDER = (1 << 11),
DRAW_TEXT = (1 << 12),
DRAW_PROC = (1 << 13),
OVERLAY = (1 << 16),
}
ui_box :: struct {
// hierarchy
listElt: list_elt,
children: list,
parent: ^ui_box,
overlayElt: list_elt,
// keying and caching
bucketElt: list_elt,
key: ui_key,
frameCounter: u64,
// builder-provided info
flags: ui_flags,
string: str8,
tags: list,
drawProc: ui_box_draw_proc,
drawData: rawptr,
// styling
beforeRules: list,
afterRules: list,
//ui_style_tag tag
targetStyle: ^ui_style,
style: ui_style,
z: u32,
floatPos: vec2,
childrenSum: [2]f32,
spacing: [2]f32,
minSize: [2]f32,
rect: rect,
// signals
sig: ^ui_sig,
// stateful behaviour
fresh: c.bool,
closed: c.bool,
parentClosed: c.bool,
dragging: c.bool,
hot: c.bool,
active: c.bool,
scroll: vec2,
pressedMouse: vec2,
// animation data
hotTransition: f32,
activeTransition: f32,
}
UI_MAX_INPUT_CHAR_PER_FRAME :: 64
ui_input_text :: struct {
count: u8,
codePoints: [UI_MAX_INPUT_CHAR_PER_FRAME]utf32,
}
ui_stack_elt :: struct {
parent: ^ui_stack_elt,
_: struct #raw_union {
box: ^ui_box,
size: ui_size,
clip: rect,
}
}
ui_tag_elt :: struct {
listElt: list_elt,
tag: ui_tag,
}
UI_BOX_MAP_BUCKET_COUNT :: 1024
ui_edit_move :: enum c.int {
NONE,
CHAR,
WORD,
LINE,
}
ui_context :: struct {
init: c.bool,
input: input_state,
frameCounter: u64,
frameTime: f64,
lastFrameDuration: f64,
frameArena: arena,
boxPool: pool,
boxMap: [UI_BOX_MAP_BUCKET_COUNT]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,
clipboardRegistered: c.bool,
theme: ^ui_theme,
}
ui_text_box_result :: struct {
changed: c.bool,
accepted: c.bool,
text: str8,
}
ui_select_popup_info :: struct {
changed: bool,
selectedIndex: int, // -1 if nothing is selected
optionCount: int,
options: [^]str8,
placeholder: str8,
}
ui_radio_group_info :: struct {
changed: bool,
selectedIndex: int, // -1 if nothing is selected
optionCount: int,
options: [^]str8,
}
//----------------------------------------------------------------
// Context and frame lifecycle
//----------------------------------------------------------------
@(default_calling_convention="c", link_prefix="oc_")
foreign {
ui_init :: proc(ctx: ^ui_context) ---
ui_get_context :: proc() -> ^ui_context ---
ui_set_context :: proc(ctx: ^ui_context) ---
ui_process_event :: proc(event: ^event) ---
ui_begin_frame :: proc(size: vec2, defaultStyle: ^ui_style, mask: ui_style_mask) ---
ui_end_frame :: proc() ---
ui_draw :: proc() ---
}
@(deferred_none=ui_end_frame)
ui_frame :: proc "c" (size: vec2, defaultStyle: ^ui_style, mask: ui_style_mask) {
ui_begin_frame(size, defaultStyle, mask)
}
ui_frame_scoped :: ui_frame
//----------------------------------------------------------------
// Common widget helpers
//----------------------------------------------------------------
@(default_calling_convention="c", link_prefix="oc_")
foreign {
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: ^c.bool) -> ui_sig ---
ui_slider :: proc(label: cstring, value: ^f32) -> ^ui_box ---
ui_scrollbar :: proc(label: cstring, thumbRatio: f32, scrollValue: ^f32) -> ^ui_box ---
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 ---
ui_panel_begin :: proc(name: cstring, flags: ui_flags) ---
ui_panel_end :: proc() ---
ui_menu_bar_begin :: proc(label: cstring) ---
ui_menu_bar_end :: proc() ---
ui_menu_begin :: proc(label: cstring) ---
ui_menu_end :: proc() ---
ui_menu_button :: proc(name: cstring) -> ui_sig ---
ui_tooltip_begin :: proc(name: cstring) -> ui_sig ---
ui_tooltip_end :: proc() ---
}
@(deferred_none=ui_panel_end)
ui_panel :: proc "c" (name: cstring, flags: ui_flags) {
ui_panel_begin(name, flags)
}
ui_panel_scoped :: ui_panel
@(deferred_none=ui_menu_bar_end)
ui_menu_bar :: proc "c" (label: cstring) {
ui_menu_bar_begin(label)
}
ui_menu_bar_scoped :: ui_menu_bar
@(deferred_none=ui_menu_end)
ui_menu :: proc "c" (label: cstring) {
ui_menu_begin(label)
}
ui_menu_scoped :: ui_menu
@(deferred_none=ui_tooltip_end)
ui_tooltip :: proc "c" (label: cstring) -> ui_sig {
return ui_tooltip_begin(label)
}
ui_tooltip_scoped :: ui_menu
//-------------------------------------------------------------------------------------
// Styling
//-------------------------------------------------------------------------------------
@(default_calling_convention="c", link_prefix="oc_")
foreign {
ui_style_next :: proc(style: ^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_match_before :: proc(pattern: ui_pattern, style: ^ui_style, mask: ui_style_mask) ---
ui_style_match_after :: proc(pattern: ui_pattern, style: ^ui_style, mask: ui_style_mask) ---
}
//-------------------------------------------------------------------------------------
// BOX
//-------------------------------------------------------------------------------------
@(default_calling_convention="c", link_prefix="oc_")
foreign {
ui_box_make_str8 :: proc(str: str8, flags: ui_flags) -> ^ui_box ---
ui_box_begin_str8 :: proc(str: str8, flags: ui_flags) -> ^ui_box ---
ui_box_end :: proc() -> ^ui_box ---
}
@(deferred_none=ui_box_end)
ui_container :: proc "c" (str: string, flags: ui_flags) -> ^ui_box {
return ui_box_begin_str8(str, flags)
}
@(deferred_none=ui_box_end)
ui_container_str8 :: proc "c" (str: str8, flags: ui_flags) -> ^ui_box {
return ui_box_begin_str8(str, flags)
}
ui_box_make :: proc "c" (str: string, flags: ui_flags) -> ^ui_box {
return ui_box_make_str8(str, flags)
}
ui_box_begin :: proc "c" (str: string, flags: ui_flags) -> ^ui_box {
return ui_box_begin_str8(str, flags)
}
//-------------------------------------------------------------------------------------
// BOX
//-------------------------------------------------------------------------------------
@(default_calling_convention="c", link_prefix="oc_")
foreign {
ui_tag_make_str8 :: proc(str: str8) -> ui_tag ---
ui_tag_box_str8 :: proc(box: ^ui_box, str: str8) ---
ui_tag_next_str8 :: proc(str: str8) ---
}
ui_tag_make :: proc "c" (s: string) -> ui_tag {
return ui_tag_make_str8(s)
}
ui_tag_box :: proc "c" (b: ^ui_box, s: string) {
ui_tag_box_str8(b, s)
}
ui_tag_next :: proc "c" (s: string) {
ui_tag_next_str8(s)
}

131
core/sys/orca/utf8.odin Normal file
View File

@@ -0,0 +1,131 @@
package orca
unicode_range :: struct {
firstCodePoint: utf32,
count: u32,
}
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 }

266
core/sys/orca/util.odin Normal file
View File

@@ -0,0 +1,266 @@
package orca
import "core:c"
import "core:fmt"
import "core:runtime"
import "core:intrinsics"
//----------------------------------------------------------------
// Arenas
//----------------------------------------------------------------
mem_reserve_proc :: proc "c" (ctx: ^base_allocator, size: u64)
mem_modify_proc :: proc "c" (ctx: ^base_allocator, ptr: rawptr, size: u64)
base_allocator :: struct {
reserve: mem_reserve_proc,
commit: mem_modify_proc,
decommit: mem_modify_proc,
release: mem_modify_proc,
}
arena_chunk :: struct {
listElt: list_elt,
ptr: ^c.char,
offset: u64,
committed: u64,
cap: u64,
}
arena :: struct {
base: ^base_allocator,
chunks: list,
currentChunk: ^arena_chunk,
}
arena_scope :: struct {
arena: ^arena,
chunk: ^arena_chunk,
offset: u64,
}
arena_options :: struct {
base: ^base_allocator,
reserve: u64,
}
@(default_calling_convention="c", link_prefix="oc_")
foreign {
arena_init :: proc(arena: ^arena) ---
arena_init_with_options :: proc(arena: ^arena, options: ^arena_options) ---
arena_cleanup :: proc(arena: ^arena) ---
arena_push :: proc(arena: ^arena, size: u64) -> rawptr ---
arena_clear :: proc(arena: ^arena) ---
arena_scope_begin :: proc(arena: ^arena) -> arena_scope ---
arena_scope_end :: proc(scope: arena_scope) ---
scratch_begin :: proc() -> arena_scope ---
scratch_begin_next :: proc(used: ^arena) -> arena_scope ---
}
arena_push_type :: proc "c" (arena: ^arena, $T: typeid) -> ^T {
return cast(^T) arena_push(arena, size_of(T))
}
arena_push_array :: proc "c" (arena: ^arena, $T: typeid, count: int) -> []T {
return ([^]T)(arena_push(arena, size_of(T)))[:count]
}
scratch_end :: arena_scope_end
//----------------------------------------------------------------
// Pool
//----------------------------------------------------------------
pool :: struct {
arena: arena,
freeList: list,
blockSize: u64,
}
pool_options :: struct {
base: ^base_allocator,
reserve: u64,
}
@(default_calling_convention="c", link_prefix="oc_")
foreign {
pool_init :: proc(pool: ^pool, blockSize: u64) ---
pool_init_with_options :: proc(pool: ^pool, blockSize: u64, options: ^pool_options) ---
pool_cleanup :: proc(pool: ^pool) ---
pool_alloc :: proc(pool: ^pool) -> rawptr ---
pool_recycle :: proc(pool: ^pool, ptr: rawptr) ---
pool_clear :: proc(pool: ^pool) ---
}
pool_alloc_type :: proc "c" (arena: ^arena, $T: typeid) -> ^T {
return cast(^T) pool_alloc(arena)
}
// TODO support list macros?
// #define list_entry :: proc(ptr, type, member)
// #define list_next_entry :: proc(list, elt, type, member)
// #define list_prev_entry :: proc(list, elt, type, member)
// #define list_first_entry :: proc(list, type, member)
// #define list_last_entry :: proc(list, type, member)
// #define list_pop_entry :: proc(list, type, member)
// @(default_calling_convention="c", link_prefix="oc_")
// foreign {
// list_init :: proc(list: ^list) ---
// list_empty :: proc(list: ^list) -> c.bool ---
// list_begin :: proc(list: ^list) -> ^list_elt ---
// list_end :: proc(list: ^list) -> ^list_elt ---
// list_last :: proc(list: ^list) -> ^list_elt ---
// list_insert :: proc(list: ^list, afterElt: ^list_elt, elt: ^list_elt) ---
// list_insert_before :: proc(list: ^list, beforeElt: ^list_elt, elt: ^list_elt) ---
// list_remove :: proc(list: ^list, elt: ^list_elt) ---
// list_push :: proc(list: ^list, elt: ^list_elt) ---
// list_pop :: proc(list: ^list) -> ^list_elt ---
// list_push_back :: proc(list: ^list, elt: ^list_elt) ---
// list_pop_back :: proc(list: ^list) -> ^list_elt ---
// }
//------------------------------------------------------------------------------------------
// for iterators
//------------------------------------------------------------------------------------------
List_Iterator :: struct($T: typeid) {
iterate: ^list,
curr: ^list_elt,
index: int,
offset: uintptr,
}
// NOTE(Skytrias): intrusive list iterator
list_iter_init :: proc "c" (iterate: ^list, $T: typeid, $field_name: string) -> (res: List_Iterator(T))
where intrinsics.type_has_field(T, field_name),
intrinsics.type_field_type(T, field_name) == list_elt {
res.iterate = iterate
res.curr = list_begin(iterate)
res.offset = offset_of_by_string(T, field_name)
return
}
list_iterate :: proc "c" (iter: ^List_Iterator($T)) -> (ptr: ^T, ok: bool) {
node := iter.curr
if node == nil {
return nil, false
}
iter.index += 1
iter.curr = node.next
return (^T)(uintptr(node) - iter.offset), true
}
//----------------------------------------------------------------
// Strings / string lists / path strings
//----------------------------------------------------------------
// TODO use odin cstring when ^c.char is used?
str8 :: string
str32 :: []rune
str8_list :: struct {
list: list,
eltCount: u64,
len: u64,
}
str8_elt :: struct {
str: str8,
listElt: list_elt,
}
@(default_calling_convention="c", link_prefix="oc_")
foreign {
str8_push_buffer :: proc(arena: ^arena, len: u64, buffer: ^c.char) -> str8 ---
str8_push_cstring :: proc(arena: ^arena, str: ^c.char) -> str8 ---
str8_push_copy :: proc(arena: ^arena, s: str8) -> str8 ---
str8_push_slice :: proc(arena: ^arena, s: str8, start: u64, end: u64) -> str8 ---
// TODO get rid of these or wrap them
str8_pushfv :: proc(arena: ^arena, format: cstring, args: c.va_list) -> str8 ---
str8_pushf :: proc(arena: ^arena, format: cstring, #c_vararg args: ..any) -> str8 ---
str8_to_cstring :: proc(arena: ^arena, string: str8) -> ^c.char ---
str8_list_push :: proc(arena: ^arena, list: ^str8_list, str: str8) ---
str8_list_pushf :: proc(arena: ^arena, list: ^str8_list, format: cstring, #c_vararg args: ..any) ---
str8_list_collate :: proc(arena: ^arena, list: str8_list, prefix: str8, separator: str8, postfix: str8) -> str8 ---
str8_list_join :: proc(arena: ^arena, list: str8_list) -> str8 ---
str8_split :: proc(arena: ^arena, str: str8, separators: str8_list) -> str8_list ---
path_slice_directory :: proc(path: str8) -> str8 ---
path_slice_filename :: proc(path: str8) -> str8 ---
path_split :: proc(arena: ^arena, path: str8) -> str8_list ---
path_join :: proc(arena: ^arena, elements: str8_list) -> str8 ---
path_append :: proc(arena: ^arena, parent: str8, relPath: str8) -> str8 ---
path_is_absolute :: proc(path: str8) -> bool ---
}
//----------------------------------------------------------------
// Logging
//----------------------------------------------------------------
// TODO proper odin formatted strings
log_level :: enum c.int {
ERROR,
WARNING,
INFO,
}
@(default_calling_convention="c", link_prefix="oc_")
foreign {
log_ext :: proc(
level: log_level,
function: cstring,
file: cstring,
line: c.int,
fmt: cstring,
#c_vararg args: ..any,
) ---
}
log_proc: [1028]u8
log_file: [1028]u8
log_temp :: proc "c" (loc: runtime.Source_Code_Location) -> (function, file: cstring) {
copy(log_proc[:], loc.procedure)
log_proc[len(loc.procedure)] = 0
function = cstring(&log_proc[0])
copy(log_file[:], loc.file_path)
log_file[len(loc.file_path)] = 0
file = cstring(&log_file[0])
return
}
log_info :: proc "c" (format: cstring, args: ..any, loc := #caller_location) {
function, file := log_temp(loc)
// final := fmt.ctprintf(format, ..args)
// log_ext(.INFO, function, file, loc.line, final, {})
log_ext(.INFO, function, file, loc.line, format, {})
}
log_warning :: proc "c" (format: cstring, args: ..any, loc := #caller_location) {
function, file := log_temp(loc)
// final := fmt.ctprintf(format, ..args)
// log_ext(.WARNING, function, file, loc.line, final, {})
log_ext(.WARNING, function, file, loc.line, format, {})
}
log_error :: proc "c" (format: cstring, args: ..any, loc := #caller_location) {
function, file := log_temp(loc)
// final := fmt.ctprintf(format, ..args)
// log_ext(.ERROR, function, file, loc.line, final, {})
log_ext(.ERROR, function, file, loc.line, format, {})
}

View File

@@ -1,7 +1,11 @@
//+build wasm32
package sys_wasi
foreign import wasi "wasi_snapshot_preview1"
when ODIN_OS == .Orca {
foreign import wasi "wasi"
} else {
foreign import wasi "wasi_snapshot_preview1"
}
DIRCOOKIE_START :: u64(0)
size_t :: uint

26
core/time/time_orca.odin Normal file
View File

@@ -0,0 +1,26 @@
//+private
//+build orca
package time
import wasi "core:sys/wasm/wasi"
_IS_SUPPORTED :: false
_now :: proc "contextless" () -> Time {
return {}
}
_sleep :: proc "contextless" (d: Duration) {
}
_tick_now :: proc "contextless" () -> Tick {
// mul_div_u64 :: proc "contextless" (val, num, den: i64) -> i64 {
// q := val / den
// r := val % den
// return q * num + r * num / den
// }
return {}
}
_yield :: proc "contextless" () {
}

View File

@@ -22,6 +22,7 @@ enum TargetOsKind : u16 {
TargetOs_wasi,
TargetOs_js,
TargetOs_orca,
TargetOs_freestanding,
@@ -83,6 +84,7 @@ gb_global String target_os_names[TargetOs_COUNT] = {
str_lit("wasi"),
str_lit("js"),
str_lit("orca"),
str_lit("freestanding"),
};
@@ -583,6 +585,14 @@ gb_global TargetMetrics target_wasi_wasm32 = {
str_lit("e-m:e-p:32:32-i64:64-n32:64-S128"),
};
gb_global TargetMetrics target_orca_wasm32 = {
TargetOs_orca,
TargetArch_wasm32,
4, 4, 8, 16,
str_lit("wasm32-wasi-js"),
str_lit("e-m:e-p:32:32-i64:64-n32:64-S128"),
};
gb_global TargetMetrics target_freestanding_wasm64p32 = {
TargetOs_freestanding,
@@ -655,6 +665,7 @@ gb_global NamedTargetMetrics named_targets[] = {
{ str_lit("freestanding_wasm32"), &target_freestanding_wasm32 },
{ str_lit("wasi_wasm32"), &target_wasi_wasm32 },
{ str_lit("js_wasm32"), &target_js_wasm32 },
{ str_lit("orca_wasm32"), &target_orca_wasm32 },
{ str_lit("freestanding_wasm64p32"), &target_freestanding_wasm64p32 },
{ str_lit("js_wasm64p32"), &target_js_wasm64p32 },
@@ -1513,9 +1524,12 @@ gb_internal void init_build_context(TargetMetrics *cross_target, Subtarget subta
// if (bc->metrics.arch == TargetArch_wasm64) {
// link_flags = gb_string_appendc(link_flags, "-mwasm64 ");
// }
if (bc->no_entry_point) {
if (bc->no_entry_point || bc->metrics.os == TargetOs_orca) {
link_flags = gb_string_appendc(link_flags, "--no-entry ");
}
// in case orca target was
bc->no_entry_point = true;
}
bc->link_flags = make_string_c(link_flags);

View File

@@ -1015,6 +1015,7 @@ gb_internal void init_universal(void) {
{"WASI", TargetOs_wasi},
{"JS", TargetOs_js},
{"Freestanding", TargetOs_freestanding},
{"Orca", TargetOs_orca},
};
auto fields = add_global_enum_type(str_lit("Odin_OS_Type"), values, gb_count_of(values));

View File

@@ -69,15 +69,20 @@ gb_internal i32 linker_stage(LinkerData *gen) {
if (is_arch_wasm()) {
timings_start_section(timings, str_lit("wasm-ld"));
String extra_orca_flags = {};
if (build_context.metrics.os == TargetOs_orca) {
extra_orca_flags = str_lit(" -L . -lorca --export-dynamic");
}
#if defined(GB_SYSTEM_WINDOWS)
result = system_exec_command_line_app("wasm-ld",
"\"%.*s\\bin\\wasm-ld\" \"%.*s.o\" -o \"%.*s\" %.*s %.*s",
"\"%.*s\\bin\\wasm-ld\" \"%.*s.o\" -o \"%.*s\" %.*s %.*s %.*s",
LIT(build_context.ODIN_ROOT),
LIT(output_filename), LIT(output_filename), LIT(build_context.link_flags), LIT(build_context.extra_linker_flags));
LIT(output_filename), LIT(output_filename), LIT(build_context.link_flags), LIT(build_context.extra_linker_flags), LIT(extra_orca_flags));
#else
result = system_exec_command_line_app("wasm-ld",
"wasm-ld \"%.*s.o\" -o \"%.*s\" %.*s %.*s",
LIT(output_filename), LIT(output_filename), LIT(build_context.link_flags), LIT(build_context.extra_linker_flags));
"wasm-ld \"%.*s.o\" -o \"%.*s\" %.*s %.*s %.*s",
LIT(output_filename), LIT(output_filename), LIT(build_context.link_flags), LIT(build_context.extra_linker_flags), LIT(extra_orca_flags));
#endif
return result;
}