Merge remote-tracking branch 'offical/master'

This commit is contained in:
ed
2025-03-22 13:37:59 -04:00
90 changed files with 3814 additions and 1209 deletions
+18 -2
View File
@@ -117,9 +117,25 @@ assign_int :: proc(val: any, i: $T) -> bool {
case uint: dst = uint (i)
case uintptr: dst = uintptr(i)
case:
is_bit_set_different_endian_to_platform :: proc(ti: ^runtime.Type_Info) -> bool {
if ti == nil {
return false
}
t := runtime.type_info_base(ti)
#partial switch info in t.variant {
case runtime.Type_Info_Integer:
switch info.endianness {
case .Platform: return false
case .Little: return ODIN_ENDIAN != .Little
case .Big: return ODIN_ENDIAN != .Big
}
}
return false
}
ti := type_info_of(v.id)
if _, ok := ti.variant.(runtime.Type_Info_Bit_Set); ok {
do_byte_swap := !reflect.bit_set_is_big_endian(v)
if info, ok := ti.variant.(runtime.Type_Info_Bit_Set); ok {
do_byte_swap := is_bit_set_different_endian_to_platform(info.underlying)
switch ti.size * 8 {
case 0: // no-op.
case 8:
+14 -7
View File
@@ -116,11 +116,12 @@ register_user_formatter :: proc(id: typeid, formatter: User_Formatter) -> Regist
}
// Creates a formatted string
//
// *Allocates Using Context's Allocator*
// *Allocates Using Provided Allocator*
//
// Inputs:
// - args: A variadic list of arguments to be formatted.
// - sep: An optional separator string (default is a single space).
// - allocator: (default: context.allocator)
//
// Returns: A formatted string.
//
@@ -132,11 +133,12 @@ aprint :: proc(args: ..any, sep := " ", allocator := context.allocator) -> strin
}
// Creates a formatted string with a newline character at the end
//
// *Allocates Using Context's Allocator*
// *Allocates Using Provided Allocator*
//
// Inputs:
// - args: A variadic list of arguments to be formatted.
// - sep: An optional separator string (default is a single space).
// - allocator: (default: context.allocator)
//
// Returns: A formatted string with a newline character at the end.
//
@@ -148,11 +150,12 @@ aprintln :: proc(args: ..any, sep := " ", allocator := context.allocator) -> str
}
// Creates a formatted string using a format string and arguments
//
// *Allocates Using Context's Allocator*
// *Allocates Using Provided Allocator*
//
// Inputs:
// - fmt: A format string with placeholders for the provided arguments.
// - args: A variadic list of arguments to be formatted.
// - allocator: (default: context.allocator)
// - newline: Whether the string should end with a newline. (See `aprintfln`.)
//
// Returns: A formatted string. The returned string must be freed accordingly.
@@ -165,11 +168,12 @@ aprintf :: proc(fmt: string, args: ..any, allocator := context.allocator, newlin
}
// Creates a formatted string using a format string and arguments, followed by a newline.
//
// *Allocates Using Context's Allocator*
// *Allocates Using Provided Allocator*
//
// Inputs:
// - fmt: A format string with placeholders for the provided arguments.
// - args: A variadic list of arguments to be formatted.
// - allocator: (default: context.allocator)
//
// Returns: A formatted string. The returned string must be freed accordingly.
//
@@ -359,11 +363,12 @@ panicf :: proc(fmt: string, args: ..any, loc := #caller_location) -> ! {
// Creates a formatted C string
//
// *Allocates Using Context's Allocator*
// *Allocates Using Provided Allocator*
//
// Inputs:
// - args: A variadic list of arguments to be formatted.
// - sep: An optional separator string (default is a single space).
// - allocator: (default: context.allocator)
//
// Returns: A formatted C string.
//
@@ -379,11 +384,12 @@ caprint :: proc(args: ..any, sep := " ", allocator := context.allocator) -> cstr
// Creates a formatted C string
//
// *Allocates Using Context's Allocator*
// *Allocates Using Provided Allocator*
//
// Inputs:
// - format: A format string with placeholders for the provided arguments
// - args: A variadic list of arguments to be formatted
// - allocator: (default: context.allocator)
// - newline: Whether the string should end with a newline. (See `caprintfln`.)
//
// Returns: A formatted C string
@@ -399,11 +405,12 @@ caprintf :: proc(format: string, args: ..any, allocator := context.allocator, ne
}
// Creates a formatted C string, followed by a newline.
//
// *Allocates Using Context's Allocator*
// *Allocates Using Provided Allocator*
//
// Inputs:
// - format: A format string with placeholders for the provided arguments
// - args: A variadic list of arguments to be formatted
// - allocator: (default: context.allocator)
//
// Returns: A formatted C string
//
+20 -3
View File
@@ -953,6 +953,22 @@ make_dynamic_array_len_cap :: proc(
return runtime.make_dynamic_array_len_cap(T, len, cap, allocator, loc)
}
/*
Create a map with no initial allocation.
This procedure creates a map of type `T` with no initial allocation, which will
use the allocator specified by `allocator` as its backing allocator when it
allocates.
*/
@(require_results)
make_map :: proc(
$T: typeid/map[$K]$E,
allocator := context.allocator,
loc := #caller_location,
) -> (m: T) {
return runtime.make_map(T, allocator, loc)
}
/*
Allocate a map.
@@ -961,13 +977,13 @@ This procedure creates a map of type `T` with initial capacity specified by
allocator.
*/
@(require_results)
make_map :: proc(
make_map_cap :: proc(
$T: typeid/map[$K]$E,
#any_int cap: int = 1<<runtime.MAP_MIN_LOG2_CAPACITY,
#any_int cap: int,
allocator := context.allocator,
loc := #caller_location,
) -> (m: T, err: Allocator_Error) {
return runtime.make_map(T, cap, allocator, loc)
return runtime.make_map_cap(T, cap, allocator, loc)
}
/*
@@ -1060,6 +1076,7 @@ make :: proc{
make_dynamic_array_len,
make_dynamic_array_len_cap,
make_map,
make_map_cap,
make_multi_pointer,
make_soa_slice,
make_soa_dynamic_array,
+7 -5
View File
@@ -107,8 +107,9 @@ arena_alloc :: proc(arena: ^Arena, size: uint, alignment: uint, loc := #caller_l
switch arena.kind {
case .Growing:
needed := mem.align_forward_uint(size, alignment)
if arena.curr_block == nil || (safe_add(arena.curr_block.used, needed) or_else 0) > arena.curr_block.reserved {
prev_used := 0 if arena.curr_block == nil else arena.curr_block.used
data, err = alloc_from_memory_block(arena.curr_block, size, alignment, default_commit_size=arena.default_commit_size)
if err == .Out_Of_Memory {
if arena.minimum_block_size == 0 {
arena.minimum_block_size = DEFAULT_ARENA_GROWING_MINIMUM_BLOCK_SIZE
arena.minimum_block_size = mem.align_forward_uint(arena.minimum_block_size, DEFAULT_PAGE_SIZE)
@@ -124,6 +125,7 @@ arena_alloc :: proc(arena: ^Arena, size: uint, alignment: uint, loc := #caller_l
max(arena.default_commit_size, arena.minimum_block_size)
}
needed := mem.align_forward_uint(size, alignment)
needed = max(needed, arena.default_commit_size)
block_size := max(needed, arena.minimum_block_size)
@@ -131,10 +133,10 @@ arena_alloc :: proc(arena: ^Arena, size: uint, alignment: uint, loc := #caller_l
new_block.prev = arena.curr_block
arena.curr_block = new_block
arena.total_reserved += new_block.reserved
}
prev_used := arena.curr_block.used
data, err = alloc_from_memory_block(arena.curr_block, size, alignment, default_commit_size=arena.default_commit_size)
prev_used = 0
data, err = alloc_from_memory_block(arena.curr_block, size, alignment, default_commit_size=arena.default_commit_size)
}
arena.total_used += arena.curr_block.used - prev_used
case .Static:
if arena.curr_block == nil {
+20
View File
@@ -0,0 +1,20 @@
package mem_virtual
import "core:sys/posix"
_reserve :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) {
result := posix.mmap(nil, size, {}, {.ANONYMOUS, .PRIVATE})
if result == posix.MAP_FAILED {
assert_contextless(posix.errno() == .ENOMEM)
return nil, .Out_Of_Memory
}
return ([^]byte)(uintptr(result))[:size], nil
}
_decommit :: proc "contextless" (data: rawptr, size: uint) {
MADV_FREE :: 5
posix.mprotect(data, size, {})
posix.posix_madvise(data, size, transmute(posix.MAdvice)i32(MADV_FREE))
}
+26
View File
@@ -0,0 +1,26 @@
package mem_virtual
import "core:sys/posix"
_reserve :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) {
PROT_MAX :: proc "contextless" (flags: posix.Prot_Flags) -> posix.Prot_Flags {
_PROT_MAX_SHIFT :: 16
return transmute(posix.Prot_Flags)(transmute(i32)flags << _PROT_MAX_SHIFT)
}
result := posix.mmap(nil, size, PROT_MAX({.READ, .WRITE, .EXEC}), {.ANONYMOUS, .PRIVATE})
if result == posix.MAP_FAILED {
assert_contextless(posix.errno() == .ENOMEM)
return nil, .Out_Of_Memory
}
return ([^]byte)(uintptr(result))[:size], nil
}
_decommit :: proc "contextless" (data: rawptr, size: uint) {
MADV_FREE :: 5
posix.mprotect(data, size, {})
posix.posix_madvise(data, size, transmute(posix.MAdvice)i32(MADV_FREE))
}
+25
View File
@@ -0,0 +1,25 @@
package mem_virtual
import "core:sys/posix"
_reserve :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) {
PROT_MPROTECT :: proc "contextless" (flags: posix.Prot_Flags) -> posix.Prot_Flags {
return transmute(posix.Prot_Flags)(transmute(i32)flags << 3)
}
result := posix.mmap(nil, size, PROT_MPROTECT({.READ, .WRITE, .EXEC}), {.ANONYMOUS, .PRIVATE})
if result == posix.MAP_FAILED {
assert_contextless(posix.errno() == .ENOMEM)
return nil, .Out_Of_Memory
}
return ([^]byte)(uintptr(result))[:size], nil
}
_decommit :: proc "contextless" (data: rawptr, size: uint) {
MADV_FREE :: 6
posix.mprotect(data, size, {})
posix.posix_madvise(data, size, transmute(posix.MAdvice)i32(MADV_FREE))
}
+20
View File
@@ -0,0 +1,20 @@
package mem_virtual
import "core:sys/posix"
_reserve :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) {
result := posix.mmap(nil, size, {}, {.ANONYMOUS, .PRIVATE})
if result == posix.MAP_FAILED {
assert_contextless(posix.errno() == .ENOMEM)
return nil, .Out_Of_Memory
}
return ([^]byte)(uintptr(result))[:size], nil
}
_decommit :: proc "contextless" (data: rawptr, size: uint) {
MADV_FREE :: 6
posix.mprotect(data, size, {})
posix.posix_madvise(data, size, transmute(posix.MAdvice)i32(MADV_FREE))
}
+3 -1
View File
@@ -15,7 +15,9 @@ platform_memory_alloc :: proc "contextless" (to_commit, to_reserve: uint) -> (bl
to_commit = clamp(to_commit, size_of(Platform_Memory_Block), total_to_reserved)
data := reserve(total_to_reserved) or_return
commit(raw_data(data), to_commit)
commit_err := commit(raw_data(data), to_commit)
assert_contextless(commit_err == nil)
block = (^Platform_Memory_Block)(raw_data(data))
block.committed = to_commit
+5 -23
View File
@@ -4,36 +4,18 @@ package mem_virtual
import "core:sys/posix"
// Define non-posix needed flags:
when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD {
MADV_FREE :: 5 /* pages unneeded, discard contents */
} else when ODIN_OS == .OpenBSD || ODIN_OS == .NetBSD {
MADV_FREE :: 6
}
_reserve :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) {
flags := posix.Map_Flags{ .ANONYMOUS, .PRIVATE }
result := posix.mmap(nil, size, {}, flags)
if result == posix.MAP_FAILED {
return nil, .Out_Of_Memory
}
return ([^]byte)(uintptr(result))[:size], nil
}
_commit :: proc "contextless" (data: rawptr, size: uint) -> Allocator_Error {
if posix.mprotect(data, size, { .READ, .WRITE }) != .OK {
return .Out_Of_Memory
#partial switch posix.errno() {
case .EACCES, .EPERM: return .Invalid_Pointer
case .ENOTSUP, .EINVAL: return .Invalid_Argument
case: return .Out_Of_Memory
}
}
return nil
}
_decommit :: proc "contextless" (data: rawptr, size: uint) {
posix.mprotect(data, size, {})
posix.posix_madvise(data, size, transmute(posix.MAdvice)i32(MADV_FREE))
}
_release :: proc "contextless" (data: rawptr, size: uint) {
posix.munmap(data, size)
}
+21 -15
View File
@@ -1,5 +1,10 @@
package linux
import "base:intrinsics"
@(private)
log2 :: intrinsics.constant_log2
/*
Represents an error returned by most of syscalls
@@ -1839,22 +1844,23 @@ EPoll_Flags_Bits :: enum {
}
EPoll_Event_Kind :: enum u32 {
IN = 0x001,
PRI = 0x002,
OUT = 0x004,
RDNORM = 0x040,
RDBAND = 0x080,
WRNORM = 0x100,
WRBAND = 0x200,
MSG = 0x400,
ERR = 0x008,
HUP = 0x010,
RDHUP = 0x2000,
EXCLUSIVE = 1<<28,
WAKEUP = 1<<29,
ONESHOT = 1<<30,
ET = 1<<31,
IN = log2(0x001),
PRI = log2(0x002),
OUT = log2(0x004),
RDNORM = log2(0x040),
RDBAND = log2(0x080),
WRNORM = log2(0x100),
WRBAND = log2(0x200),
MSG = log2(0x400),
ERR = log2(0x008),
HUP = log2(0x010),
RDHUP = log2(0x2000),
EXCLUSIVE = log2(1<<28),
WAKEUP = log2(1<<29),
ONESHOT = log2(1<<30),
ET = log2(1<<31),
}
EPoll_Event_Set :: bit_set[EPoll_Event_Kind; u32]
EPoll_Ctl_Opcode :: enum i32 {
ADD = 1,
+1 -1
View File
@@ -212,7 +212,7 @@ rt_sigreturn :: proc "c" () -> ! {
/*
Alter an action taken by a process.
*/
rt_sigaction :: proc "contextless" (sig: Signal, sigaction: ^Sig_Action($T), old_sigaction: ^Sig_Action) -> Errno {
rt_sigaction :: proc "contextless" (sig: Signal, sigaction: ^Sig_Action($T), old_sigaction: ^Sig_Action($U)) -> Errno {
// NOTE(jason): It appears that the restorer is required for i386 and amd64
when ODIN_ARCH == .i386 || ODIN_ARCH == .amd64 {
sigaction.flags += {.RESTORER}
+14 -1
View File
@@ -317,5 +317,18 @@ SYS_futex_waitv :: uintptr(449)
SYS_set_mempolicy_home_node :: uintptr(450)
SYS_cachestat :: uintptr(451)
SYS_fchmodat2 :: uintptr(452)
SYS_map_shadow_stack :: uintptr(453)
SYS_futex_wake :: uintptr(454)
SYS_futex_wait :: uintptr(455)
SYS_futex_requeue :: uintptr(456)
SYS_statmount :: uintptr(457)
SYS_listmount :: uintptr(458)
SYS_lsm_get_self_attr :: uintptr(459)
SYS_lsm_set_self_attr :: uintptr(460)
SYS_lsm_list_modules :: uintptr(461)
SYS_mseal :: uintptr(462)
SYS_setxattrat :: uintptr(463)
SYS_getxattrat :: uintptr(464)
SYS_listxattrat :: uintptr(465)
SYS_removexattrat :: uintptr(466)
+1 -1
View File
@@ -1450,7 +1450,7 @@ EPoll_Data :: struct #raw_union {
}
EPoll_Event :: struct #packed {
events: EPoll_Event_Kind,
events: EPoll_Event_Set,
data: EPoll_Data,
}
+1 -1
View File
@@ -565,7 +565,7 @@ when ODIN_OS == .Darwin {
SS_ONSTACK :: 0x0001
SS_DISABLE :: 0x0004
when ODIN_ARCH == .amd64 || ODIN_ARCH == .arm32 {
when ODIN_ARCH == .arm64 || ODIN_ARCH == .arm32 {
MINSIGSTKSZ :: 1024 * 4
} else when ODIN_ARCH == .amd64 || ODIN_ARCH == .i386 {
MINSIGSTKSZ :: 512 * 4
+50 -14
View File
@@ -189,7 +189,7 @@ Key_Location :: enum u8 {
KEYBOARD_MAX_KEY_SIZE :: 32
KEYBOARD_MAX_CODE_SIZE :: 32
GAMEPAD_MAX_ID_SIZE :: 64
GAMEPAD_MAX_ID_SIZE :: 96
GAMEPAD_MAX_MAPPING_SIZE :: 64
GAMEPAD_MAX_BUTTONS :: 64
@@ -239,6 +239,12 @@ Gamepad_State :: struct {
_mapping_buf: [GAMEPAD_MAX_MAPPING_SIZE]byte `fmt:"-"`,
}
Pointer_Type :: enum u8 {
Mouse,
Pen,
Touch,
}
Event :: struct {
kind: Event_Kind,
target_kind: Event_Target_Kind,
@@ -275,6 +281,8 @@ Event :: struct {
repeat: bool,
char: rune,
_key_len: int `fmt:"-"`,
_code_len: int `fmt:"-"`,
_key_buf: [KEYBOARD_MAX_KEY_SIZE]byte `fmt:"-"`,
@@ -295,6 +303,21 @@ Event :: struct {
button: i16,
buttons: bit_set[0..<16; u16],
pointer: struct {
altitude_angle: f64,
azimuth_angle: f64,
persistent_device_id: int,
pointer_id: int,
width: int,
height: int,
pressure: f64,
tangential_pressure: f64,
tilt: [2]f64,
twist: f64,
pointer_type: Pointer_Type,
is_primary: bool,
},
},
gamepad: Gamepad_State,
@@ -323,13 +346,13 @@ add_event_listener :: proc(id: string, kind: Event_Kind, user_data: rawptr, call
return _add_event_listener(id, event_kind_string[kind], kind, user_data, callback, use_capture)
}
remove_event_listener :: proc(id: string, kind: Event_Kind, user_data: rawptr, callback: proc(e: Event)) -> bool {
remove_event_listener :: proc(id: string, kind: Event_Kind, user_data: rawptr, callback: proc(e: Event), use_capture := false) -> bool {
@(default_calling_convention="contextless")
foreign dom_lib {
@(link_name="remove_event_listener")
_remove_event_listener :: proc(id: string, name: string, user_data: rawptr, callback: proc "odin" (Event)) -> bool ---
_remove_event_listener :: proc(id: string, name: string, user_data: rawptr, callback: proc "odin" (Event), use_capture: bool) -> bool ---
}
return _remove_event_listener(id, event_kind_string[kind], user_data, callback)
return _remove_event_listener(id, event_kind_string[kind], user_data, callback, use_capture)
}
add_window_event_listener :: proc(kind: Event_Kind, user_data: rawptr, callback: proc(e: Event), use_capture := false) -> bool {
@@ -341,20 +364,26 @@ add_window_event_listener :: proc(kind: Event_Kind, user_data: rawptr, callback:
return _add_window_event_listener(event_kind_string[kind], kind, user_data, callback, use_capture)
}
remove_window_event_listener :: proc(kind: Event_Kind, user_data: rawptr, callback: proc(e: Event)) -> bool {
remove_window_event_listener :: proc(kind: Event_Kind, user_data: rawptr, callback: proc(e: Event), use_capture := false) -> bool {
@(default_calling_convention="contextless")
foreign dom_lib {
@(link_name="remove_window_event_listener")
_remove_window_event_listener :: proc(name: string, user_data: rawptr, callback: proc "odin" (Event)) -> bool ---
_remove_window_event_listener :: proc(name: string, user_data: rawptr, callback: proc "odin" (Event), use_capture: bool) -> bool ---
}
return _remove_window_event_listener(event_kind_string[kind], user_data, callback)
return _remove_window_event_listener(event_kind_string[kind], user_data, callback, use_capture)
}
remove_event_listener_from_event :: proc(e: Event) -> bool {
from_use_capture_false: bool
from_use_capture_true: bool
if e.id == "" {
return remove_window_event_listener(e.kind, e.user_data, e.callback)
from_use_capture_false = remove_window_event_listener(e.kind, e.user_data, e.callback, false)
from_use_capture_true = remove_window_event_listener(e.kind, e.user_data, e.callback, true)
} else {
from_use_capture_false = remove_event_listener(e.id, e.kind, e.user_data, e.callback, false)
from_use_capture_true = remove_event_listener(e.id, e.kind, e.user_data, e.callback, true)
}
return remove_event_listener(e.id, e.kind, e.user_data, e.callback)
return from_use_capture_false || from_use_capture_true
}
add_custom_event_listener :: proc(id: string, name: string, user_data: rawptr, callback: proc(e: Event), use_capture := false) -> bool {
@@ -365,13 +394,13 @@ add_custom_event_listener :: proc(id: string, name: string, user_data: rawptr, c
}
return _add_event_listener(id, name, .Custom, user_data, callback, use_capture)
}
remove_custom_event_listener :: proc(id: string, name: string, user_data: rawptr, callback: proc(e: Event)) -> bool {
remove_custom_event_listener :: proc(id: string, name: string, user_data: rawptr, callback: proc(e: Event), use_capture := false) -> bool {
@(default_calling_convention="contextless")
foreign dom_lib {
@(link_name="remove_event_listener")
_remove_event_listener :: proc(id: string, name: string, user_data: rawptr, callback: proc "odin" (Event)) -> bool ---
_remove_event_listener :: proc(id: string, name: string, user_data: rawptr, callback: proc "odin" (Event), use_capture: bool) -> bool ---
}
return _remove_event_listener(id, name, user_data, callback)
return _remove_event_listener(id, name, user_data, callback, use_capture)
}
get_gamepad_state :: proc "contextless" (index: int, s: ^Gamepad_State) -> bool {
@@ -384,7 +413,14 @@ get_gamepad_state :: proc "contextless" (index: int, s: ^Gamepad_State) -> bool
if s == nil {
return false
}
return _get_gamepad_state(index, s)
if !_get_gamepad_state(index, s) {
return false
}
s.id = string(s._id_buf[:s._id_len])
s.mapping = string(s._mapping_buf[:s._mapping_len])
return true
}
@@ -415,4 +451,4 @@ do_event_callback :: proc(user_data: rawptr, callback: proc(e: Event)) {
callback(event)
}
}
}
+4 -4
View File
@@ -263,7 +263,7 @@ add_event_listener :: proc(id: string, kind: Event_Kind, user_data: rawptr, call
panic("vendor:wasm/js not supported on non JS targets")
}
remove_event_listener :: proc(id: string, kind: Event_Kind, user_data: rawptr, callback: proc(e: Event)) -> bool {
remove_event_listener :: proc(id: string, kind: Event_Kind, user_data: rawptr, callback: proc(e: Event), use_capture := false) -> bool {
panic("vendor:wasm/js not supported on non JS targets")
}
@@ -271,7 +271,7 @@ add_window_event_listener :: proc(kind: Event_Kind, user_data: rawptr, callback:
panic("vendor:wasm/js not supported on non JS targets")
}
remove_window_event_listener :: proc(kind: Event_Kind, user_data: rawptr, callback: proc(e: Event)) -> bool {
remove_window_event_listener :: proc(kind: Event_Kind, user_data: rawptr, callback: proc(e: Event), use_capture := false) -> bool {
panic("vendor:wasm/js not supported on non JS targets")
}
@@ -282,6 +282,6 @@ remove_event_listener_from_event :: proc(e: Event) -> bool {
add_custom_event_listener :: proc(id: string, name: string, user_data: rawptr, callback: proc(e: Event), use_capture := false) -> bool {
panic("vendor:wasm/js not supported on non JS targets")
}
remove_custom_event_listener :: proc(id: string, name: string, user_data: rawptr, callback: proc(e: Event)) -> bool {
remove_custom_event_listener :: proc(id: string, name: string, user_data: rawptr, callback: proc(e: Event), use_capture := false) -> bool {
panic("vendor:wasm/js not supported on non JS targets")
}
}
+2 -1
View File
@@ -9,4 +9,5 @@ foreign odin_env {
abort :: proc() -> ! ---
alert :: proc(msg: string) ---
evaluate :: proc(str: string) ---
}
open :: proc(url: string, name := "", specs := "") ---
}
+108 -21
View File
@@ -17,7 +17,7 @@ class WasmMemoryInterface {
constructor() {
this.memory = null;
this.exports = null;
this.listenerMap = {};
this.listenerMap = new Map();
// Size (in bytes) of the integer type, should be 4 on `js_wasm32` and 8 on `js_wasm64p32`
this.intSize = 4;
@@ -402,6 +402,9 @@ class WebGLInterface {
BlendEquation: (mode) => {
this.ctx.blendEquation(mode);
},
BlendEquationSeparate: (modeRGB, modeAlpha) => {
this.ctx.blendEquationSeparate(modeRGB, modeAlpha);
},
BlendFunc: (sfactor, dfactor) => {
this.ctx.blendFunc(sfactor, dfactor);
},
@@ -633,6 +636,13 @@ class WebGLInterface {
GetParameter: (pname) => {
return this.ctx.getParameter(pname);
},
GetParameter4i: (pname, v0, v1, v2, v3) => {
const i4 = this.ctx.getParameter(pname);
this.mem.storeI32(v0, i4[0]);
this.mem.storeI32(v1, i4[1]);
this.mem.storeI32(v2, i4[2]);
this.mem.storeI32(v3, i4[3]);
},
GetProgramParameter: (program, pname) => {
return this.ctx.getProgramParameter(this.programs[program], pname)
},
@@ -1393,6 +1403,10 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement, memory) {
info.scrollTop = info.scrollHeight;
};
const listener_key = (id, name, data, callback, useCapture) => {
return `${id}-${name}-data:${data}-callback:${callback}-useCapture:${useCapture}`;
};
let webglContext = new WebGLInterface(wasmMemoryInterface);
const env = {};
@@ -1421,6 +1435,13 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement, memory) {
abort: () => { Module.abort() },
evaluate: (str_ptr, str_len) => { eval.call(null, wasmMemoryInterface.loadString(str_ptr, str_len)); },
open: (url_ptr, url_len, name_ptr, name_len, specs_ptr, specs_len) => {
const url = wasmMemoryInterface.loadString(url_ptr, url_len);
const name = wasmMemoryInterface.loadString(name_ptr, name_len);
const specs = wasmMemoryInterface.loadString(specs_ptr, specs_len);
window.open(url, name, specs);
},
// return a bigint to be converted to i64
time_now: () => BigInt(Date.now()),
tick_now: () => performance.now(),
@@ -1533,6 +1554,29 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement, memory) {
wmi.storeI16(off(2), e.button);
wmi.storeU16(off(2), e.buttons);
if (e instanceof PointerEvent) {
wmi.storeF64(off(8), e.altitudeAngle);
wmi.storeF64(off(8), e.azimuthAngle);
wmi.storeInt(off(W), e.persistentDeviceId);
wmi.storeInt(off(W), e.pointerId);
wmi.storeInt(off(W), e.width);
wmi.storeInt(off(W), e.height);
wmi.storeF64(off(8), e.pressure);
wmi.storeF64(off(8), e.tangentialPressure);
wmi.storeF64(off(8), e.tiltX);
wmi.storeF64(off(8), e.tiltY);
wmi.storeF64(off(8), e.twist);
if (e.pointerType == "pen") {
wmi.storeU8(off(1), 1);
} else if (e.pointerType == "touch") {
wmi.storeU8(off(1), 2);
} else {
wmi.storeU8(off(1), 0);
}
wmi.storeU8(off(1), !!e.isPrimary);
}
} else if (e instanceof KeyboardEvent) {
// Note: those strings are constructed
// on the native side from buffers that
@@ -1549,6 +1593,8 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement, memory) {
wmi.storeU8(off(1), !!e.repeat);
wmi.storeI32(off(4), e.charCode);
wmi.storeInt(off(W, W), e.key.length)
wmi.storeInt(off(W, W), e.code.length)
wmi.storeString(off(32, 1), e.key);
@@ -1588,10 +1634,24 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement, memory) {
}
}
wmi.storeInt(off(W, W), e.gamepad.id.length)
wmi.storeInt(off(W, W), e.gamepad.mapping.length)
wmi.storeString(off(64, 1), e.gamepad.id);
wmi.storeString(off(64, 1), e.gamepad.mapping);
let idLength = e.gamepad.id.length;
let id = e.gamepad.id;
if (idLength > 96) {
idLength = 96;
id = id.slice(0, 93) + '...';
}
let mappingLength = e.gamepad.mapping.length;
let mapping = e.gamepad.mapping;
if (mappingLength > 64) {
mappingLength = 61;
mapping = mapping.slice(0, 61) + '...';
}
wmi.storeInt(off(W, W), idLength);
wmi.storeInt(off(W, W), mappingLength);
wmi.storeString(off(96, 1), id);
wmi.storeString(off(64, 1), mapping);
}
},
@@ -1602,6 +1662,10 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement, memory) {
if (element == undefined) {
return false;
}
let key = listener_key(id, name, data, callback, !!use_capture);
if (wasmMemoryInterface.listenerMap.has(key)) {
return false;
}
let listener = (e) => {
let event_data = {};
@@ -1612,7 +1676,7 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement, memory) {
onEventReceived(event_data, data, callback);
};
wasmMemoryInterface.listenerMap[{data: data, callback: callback}] = listener;
wasmMemoryInterface.listenerMap.set(key, listener);
element.addEventListener(name, listener, !!use_capture);
return true;
},
@@ -1620,6 +1684,11 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement, memory) {
add_window_event_listener: (name_ptr, name_len, name_code, data, callback, use_capture) => {
let name = wasmMemoryInterface.loadString(name_ptr, name_len);
let element = window;
let key = listener_key('window', name, data, callback, !!use_capture);
if (wasmMemoryInterface.listenerMap.has(key)) {
return false;
}
let listener = (e) => {
let event_data = {};
event_data.id_ptr = 0;
@@ -1629,12 +1698,12 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement, memory) {
onEventReceived(event_data, data, callback);
};
wasmMemoryInterface.listenerMap[{data: data, callback: callback}] = listener;
wasmMemoryInterface.listenerMap.set(key, listener);
element.addEventListener(name, listener, !!use_capture);
return true;
},
remove_event_listener: (id_ptr, id_len, name_ptr, name_len, data, callback) => {
remove_event_listener: (id_ptr, id_len, name_ptr, name_len, data, callback, use_capture) => {
let id = wasmMemoryInterface.loadString(id_ptr, id_len);
let name = wasmMemoryInterface.loadString(name_ptr, name_len);
let element = getElement(id);
@@ -1642,24 +1711,28 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement, memory) {
return false;
}
let listener = wasmMemoryInterface.listenerMap[{data: data, callback: callback}];
if (listener == undefined) {
let key = listener_key(id, name, data, callback, !!use_capture);
let listener = wasmMemoryInterface.listenerMap.get(key);
if (listener === undefined) {
return false;
}
element.removeEventListener(name, listener);
wasmMemoryInterface.listenerMap.delete(key);
element.removeEventListener(name, listener, !!use_capture);
return true;
},
remove_window_event_listener: (name_ptr, name_len, data, callback) => {
remove_window_event_listener: (name_ptr, name_len, data, callback, use_capture) => {
let name = wasmMemoryInterface.loadString(name_ptr, name_len);
let element = window;
let key = {data: data, callback: callback};
let listener = wasmMemoryInterface.listenerMap[key];
if (!listener) {
let key = listener_key('window', name, data, callback, !!use_capture);
let listener = wasmMemoryInterface.listenerMap.get(key);
if (listener === undefined) {
return false;
}
wasmMemoryInterface.listenerMap[key] = undefined;
wasmMemoryInterface.listenerMap.delete(key);
element.removeEventListener(name, listener);
element.removeEventListener(name, listener, !!use_capture);
return true;
},
@@ -1756,10 +1829,24 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement, memory) {
}
}
wmi.storeInt(off(W, W), gamepad.id.length)
wmi.storeInt(off(W, W), gamepad.mapping.length)
wmi.storeString(off(64, 1), gamepad.id);
wmi.storeString(off(64, 1), gamepad.mapping);
let idLength = gamepad.id.length;
let id = gamepad.id;
if (idLength > 96) {
idLength = 96;
id = id.slice(0, 93) + '...';
}
let mappingLength = gamepad.mapping.length;
let mapping = gamepad.mapping;
if (mappingLength > 64) {
mappingLength = 61;
mapping = mapping.slice(0, 61) + '...';
}
wmi.storeInt(off(W, W), idLength);
wmi.storeInt(off(W, W), mappingLength);
wmi.storeString(off(96, 1), id);
wmi.storeString(off(64, 1), mapping);
return true;
}
+2 -4
View File
@@ -5,13 +5,11 @@ Type representing a mononotic day number corresponding to a date.
Ordinal 1 = Midnight Monday, January 1, 1 A.D. (Gregorian)
| Midnight Monday, January 3, 1 A.D. (Julian)
Every other ordinal counts days forwards, starting from the above date.
*/
Ordinal :: i64
/*
*/
EPOCH :: Ordinal(1)
/*
Minimum valid value for date.
+7 -8
View File
@@ -98,7 +98,7 @@ This procedure takes the value of an ordinal and returns the day of week for
that ordinal.
*/
day_of_week :: proc "contextless" (ordinal: Ordinal) -> (day: Weekday) {
return Weekday((ordinal - EPOCH + 1) %% 7)
return Weekday(ordinal %% 7)
}
/*
@@ -349,8 +349,7 @@ the result is unspecified.
unsafe_date_to_ordinal :: proc "contextless" (date: Date) -> (ordinal: Ordinal) {
year_minus_one := date.year - 1
// Day before epoch
ordinal = EPOCH - 1
ordinal = 0
// Add non-leap days
ordinal += 365 * year_minus_one
@@ -382,17 +381,17 @@ This procedure returns the year and the day of the year of a given ordinal.
Of the ordinal is outside of its valid range, the result is unspecified.
*/
unsafe_ordinal_to_year :: proc "contextless" (ordinal: Ordinal) -> (year: i64, day_ordinal: i64) {
// Days after epoch
d0 := ordinal - EPOCH
// Correct for leap year cycle starting at day 1.
d0 := ordinal - 1
// Number of 400-year cycles and remainder
n400, d1 := divmod(d0, 146097)
n400, d1 := divmod(d0, 365*400 + 100 - 3)
// Number of 100-year cycles and remainder
n100, d2 := divmod(d1, 36524)
n100, d2 := divmod(d1, 365*100 + 25 - 1)
// Number of 4-year cycles and remainder
n4, d3 := divmod(d2, 1461)
n4, d3 := divmod(d2, 365*4 + 1)
// Number of remaining days
n1, d4 := divmod(d3, 365)