aboutsummaryrefslogtreecommitdiff
path: root/core/sys
diff options
context:
space:
mode:
authorColin Davidson <colrdavidson@gmail.com>2024-09-24 02:32:06 -0700
committerColin Davidson <colrdavidson@gmail.com>2024-09-24 02:32:06 -0700
commitf3ab14b8ccb45d0fef8a96937635bdf0943ce7d6 (patch)
tree1309d7c797117463996a84522ef3d1c9713a286c /core/sys
parent99938c7d4fb26d43a07dd4b8f4f00ab87e67e73f (diff)
parentf7d74ff3a8596efef67d151ffb758ed085e94be0 (diff)
Merge branch 'master' into macharena
Diffstat (limited to 'core/sys')
-rw-r--r--core/sys/darwin/CoreFoundation/CFString.odin299
-rw-r--r--core/sys/darwin/Foundation/NSApplication.odin5
-rw-r--r--core/sys/darwin/Foundation/NSEvent.odin4
-rw-r--r--core/sys/darwin/Foundation/NSString.odin5
-rw-r--r--core/sys/darwin/Foundation/objc.odin113
-rw-r--r--core/sys/darwin/darwin.odin2
-rw-r--r--core/sys/darwin/sync.odin11
-rw-r--r--core/sys/darwin/xnu_system_call_helpers.odin6
-rw-r--r--core/sys/darwin/xnu_system_call_wrappers.odin58
-rw-r--r--core/sys/freebsd/syscalls.odin108
-rw-r--r--core/sys/freebsd/types.odin12
-rw-r--r--core/sys/haiku/errors.odin2
-rw-r--r--core/sys/haiku/find_directory.odin2
-rw-r--r--core/sys/haiku/os.odin2
-rw-r--r--core/sys/haiku/types.odin2
-rw-r--r--core/sys/info/cpu_arm.odin2
-rw-r--r--core/sys/info/cpu_intel.odin2
-rw-r--r--core/sys/info/cpu_linux_arm.odin4
-rw-r--r--core/sys/info/cpu_linux_riscv64.odin125
-rw-r--r--core/sys/info/cpu_riscv64.odin98
-rw-r--r--core/sys/info/doc.odin9
-rw-r--r--core/sys/info/platform_bsd.odin2
-rw-r--r--core/sys/info/platform_darwin.odin4
-rw-r--r--core/sys/kqueue/kqueue.odin2
-rw-r--r--core/sys/linux/bits.odin84
-rw-r--r--core/sys/linux/helpers.odin4
-rw-r--r--core/sys/linux/sys.odin46
-rw-r--r--core/sys/linux/syscall_amd64.odin2
-rw-r--r--core/sys/linux/syscall_arm32.odin2
-rw-r--r--core/sys/linux/syscall_arm64.odin2
-rw-r--r--core/sys/linux/syscall_i386.odin2
-rw-r--r--core/sys/linux/syscall_riscv64.odin3
-rw-r--r--core/sys/linux/types.odin17
-rw-r--r--core/sys/linux/wrappers.odin2
-rw-r--r--core/sys/llvm/bit_manipulation.odin1
-rw-r--r--core/sys/llvm/code_generator.odin1
-rw-r--r--core/sys/llvm/standard_c_library.odin1
-rw-r--r--core/sys/posix/time.odin2
-rw-r--r--core/sys/posix/unistd.odin2
-rw-r--r--core/sys/unix/pthread_darwin.odin2
-rw-r--r--core/sys/unix/pthread_freebsd.odin2
-rw-r--r--core/sys/unix/pthread_linux.odin2
-rw-r--r--core/sys/unix/pthread_openbsd.odin2
-rw-r--r--core/sys/unix/pthread_unix.odin4
-rw-r--r--core/sys/unix/sysctl_darwin.odin2
-rw-r--r--core/sys/unix/sysctl_freebsd.odin2
-rw-r--r--core/sys/unix/sysctl_openbsd.odin2
-rw-r--r--core/sys/valgrind/callgrind.odin2
-rw-r--r--core/sys/valgrind/helgrind.odin2
-rw-r--r--core/sys/valgrind/memcheck.odin2
-rw-r--r--core/sys/valgrind/valgrind.odin2
-rw-r--r--core/sys/wasm/README.md15
-rw-r--r--core/sys/wasm/js/dom.odin93
-rw-r--r--core/sys/wasm/js/dom_all_targets.odin36
-rw-r--r--core/sys/wasm/js/events.odin418
-rw-r--r--core/sys/wasm/js/events_all_targets.odin287
-rw-r--r--core/sys/wasm/js/general.odin12
-rw-r--r--core/sys/wasm/js/memory_all_targets.odin14
-rw-r--r--core/sys/wasm/js/memory_js.odin44
-rw-r--r--core/sys/wasm/js/odin.js1983
-rw-r--r--core/sys/wasm/wasi/wasi_api.odin2
-rw-r--r--core/sys/windows/advapi32.odin2
-rw-r--r--core/sys/windows/bcrypt.odin2
-rw-r--r--core/sys/windows/bluetooth.odin2
-rw-r--r--core/sys/windows/codepage.odin2
-rw-r--r--core/sys/windows/comctl32.odin2
-rw-r--r--core/sys/windows/comdlg32.odin2
-rw-r--r--core/sys/windows/dbghelp.odin2
-rw-r--r--core/sys/windows/dnsapi.odin2
-rw-r--r--core/sys/windows/dwmapi.odin6
-rw-r--r--core/sys/windows/gdi32.odin2
-rw-r--r--core/sys/windows/hidpi.odin2
-rw-r--r--core/sys/windows/hidusage.odin2
-rw-r--r--core/sys/windows/ip_helper.odin2
-rw-r--r--core/sys/windows/kernel32.odin21
-rw-r--r--core/sys/windows/key_codes.odin2
-rw-r--r--core/sys/windows/known_folders.odin2
-rw-r--r--core/sys/windows/netapi32.odin2
-rw-r--r--core/sys/windows/ntdll.odin2
-rw-r--r--core/sys/windows/shcore.odin2
-rw-r--r--core/sys/windows/shell32.odin2
-rw-r--r--core/sys/windows/shlwapi.odin2
-rw-r--r--core/sys/windows/synchronization.odin2
-rw-r--r--core/sys/windows/system_params.odin2
-rw-r--r--core/sys/windows/tlhelp.odin2
-rw-r--r--core/sys/windows/types.odin52
-rw-r--r--core/sys/windows/user32.odin41
-rw-r--r--core/sys/windows/userenv.odin2
-rw-r--r--core/sys/windows/util.odin2
-rw-r--r--core/sys/windows/ux_theme.odin2
-rw-r--r--core/sys/windows/wgl.odin2
-rw-r--r--core/sys/windows/wglext.odin2
-rw-r--r--core/sys/windows/window_messages.odin2
-rw-r--r--core/sys/windows/winerror.odin3
-rw-r--r--core/sys/windows/winmm.odin2
-rw-r--r--core/sys/windows/winnls.odin2
-rw-r--r--core/sys/windows/winver.odin2
-rw-r--r--core/sys/windows/wow64_apiset.odin2
-rw-r--r--core/sys/windows/ws2_32.odin2
99 files changed, 3795 insertions, 374 deletions
diff --git a/core/sys/darwin/CoreFoundation/CFString.odin b/core/sys/darwin/CoreFoundation/CFString.odin
index 6ad3c5bfc..24485a494 100644
--- a/core/sys/darwin/CoreFoundation/CFString.odin
+++ b/core/sys/darwin/CoreFoundation/CFString.odin
@@ -1,7 +1,5 @@
package CoreFoundation
-import "base:runtime"
-
foreign import CoreFoundation "system:CoreFoundation.framework"
String :: distinct TypeRef // same as CFStringRef
@@ -9,157 +7,157 @@ String :: distinct TypeRef // same as CFStringRef
StringEncoding :: distinct u32
StringBuiltInEncodings :: enum StringEncoding {
- MacRoman = 0,
+ MacRoman = 0,
WindowsLatin1 = 0x0500,
- ISOLatin1 = 0x0201,
+ ISOLatin1 = 0x0201,
NextStepLatin = 0x0B01,
- ASCII = 0x0600,
- Unicode = 0x0100,
- UTF8 = 0x08000100,
+ ASCII = 0x0600,
+ Unicode = 0x0100,
+ UTF8 = 0x08000100,
NonLossyASCII = 0x0BFF,
- UTF16 = 0x0100,
+ UTF16 = 0x0100,
UTF16BE = 0x10000100,
UTF16LE = 0x14000100,
- UTF32 = 0x0c000100,
- UTF32BE = 0x18000100,
- UTF32LE = 0x1c000100,
+ UTF32 = 0x0c000100,
+ UTF32BE = 0x18000100,
+ UTF32LE = 0x1c000100,
}
StringEncodings :: enum Index {
- MacJapanese = 1,
- MacChineseTrad = 2,
- MacKorean = 3,
- MacArabic = 4,
- MacHebrew = 5,
- MacGreek = 6,
- MacCyrillic = 7,
- MacDevanagari = 9,
- MacGurmukhi = 10,
- MacGujarati = 11,
- MacOriya = 12,
- MacBengali = 13,
- MacTamil = 14,
- MacTelugu = 15,
- MacKannada = 16,
- MacMalayalam = 17,
- MacSinhalese = 18,
- MacBurmese = 19,
- MacKhmer = 20,
- MacThai = 21,
- MacLaotian = 22,
- MacGeorgian = 23,
- MacArmenian = 24,
- MacChineseSimp = 25,
- MacTibetan = 26,
- MacMongolian = 27,
- MacEthiopic = 28,
- MacCentralEurRoman = 29,
- MacVietnamese = 30,
- MacExtArabic = 31,
- MacSymbol = 33,
- MacDingbats = 34,
- MacTurkish = 35,
- MacCroatian = 36,
- MacIcelandic = 37,
- MacRomanian = 38,
- MacCeltic = 39,
- MacGaelic = 40,
- MacFarsi = 0x8C,
- MacUkrainian = 0x98,
- MacInuit = 0xEC,
- MacVT100 = 0xFC,
- MacHFS = 0xFF,
- ISOLatin2 = 0x0202,
- ISOLatin3 = 0x0203,
- ISOLatin4 = 0x0204,
- ISOLatinCyrillic = 0x0205,
- ISOLatinArabic = 0x0206,
- ISOLatinGreek = 0x0207,
- ISOLatinHebrew = 0x0208,
- ISOLatin5 = 0x0209,
- ISOLatin6 = 0x020A,
- ISOLatinThai = 0x020B,
- ISOLatin7 = 0x020D,
- ISOLatin8 = 0x020E,
- ISOLatin9 = 0x020F,
- ISOLatin10 = 0x0210,
- DOSLatinUS = 0x0400,
- DOSGreek = 0x0405,
- DOSBalticRim = 0x0406,
- DOSLatin1 = 0x0410,
- DOSGreek1 = 0x0411,
- DOSLatin2 = 0x0412,
- DOSCyrillic = 0x0413,
- DOSTurkish = 0x0414,
- DOSPortuguese = 0x0415,
- DOSIcelandic = 0x0416,
- DOSHebrew = 0x0417,
- DOSCanadianFrench = 0x0418,
- DOSArabic = 0x0419,
- DOSNordic = 0x041A,
- DOSRussian = 0x041B,
- DOSGreek2 = 0x041C,
- DOSThai = 0x041D,
- DOSJapanese = 0x0420,
- DOSChineseSimplif = 0x0421,
- DOSKorean = 0x0422,
- DOSChineseTrad = 0x0423,
- WindowsLatin2 = 0x0501,
- WindowsCyrillic = 0x0502,
- WindowsGreek = 0x0503,
- WindowsLatin5 = 0x0504,
- WindowsHebrew = 0x0505,
- WindowsArabic = 0x0506,
- WindowsBalticRim = 0x0507,
- WindowsVietnamese = 0x0508,
- WindowsKoreanJohab = 0x0510,
- ANSEL = 0x0601,
- JIS_X0201_76 = 0x0620,
- JIS_X0208_83 = 0x0621,
- JIS_X0208_90 = 0x0622,
- JIS_X0212_90 = 0x0623,
- JIS_C6226_78 = 0x0624,
- ShiftJIS_X0213 = 0x0628,
- ShiftJIS_X0213_MenKuTen = 0x0629,
- GB_2312_80 = 0x0630,
- GBK_95 = 0x0631,
- GB_18030_2000 = 0x0632,
- KSC_5601_87 = 0x0640,
- KSC_5601_92_Johab = 0x0641,
- CNS_11643_92_P1 = 0x0651,
- CNS_11643_92_P2 = 0x0652,
- CNS_11643_92_P3 = 0x0653,
- ISO_2022_JP = 0x0820,
- ISO_2022_JP_2 = 0x0821,
- ISO_2022_JP_1 = 0x0822,
- ISO_2022_JP_3 = 0x0823,
- ISO_2022_CN = 0x0830,
- ISO_2022_CN_EXT = 0x0831,
- ISO_2022_KR = 0x0840,
- EUC_JP = 0x0920,
- EUC_CN = 0x0930,
- EUC_TW = 0x0931,
- EUC_KR = 0x0940,
- ShiftJIS = 0x0A01,
- KOI8_R = 0x0A02,
- Big5 = 0x0A03,
- MacRomanLatin1 = 0x0A04,
- HZ_GB_2312 = 0x0A05,
- Big5_HKSCS_1999 = 0x0A06,
- VISCII = 0x0A07,
- KOI8_U = 0x0A08,
- Big5_E = 0x0A09,
- NextStepJapanese = 0x0B02,
- EBCDIC_US = 0x0C01,
- EBCDIC_CP037 = 0x0C02,
- UTF7 = 0x04000100,
- UTF7_IMAP = 0x0A10,
- ShiftJIS_X0213_00 = 0x0628, // Deprecated. Use `ShiftJIS_X0213` instead.
+ MacJapanese = 1,
+ MacChineseTrad = 2,
+ MacKorean = 3,
+ MacArabic = 4,
+ MacHebrew = 5,
+ MacGreek = 6,
+ MacCyrillic = 7,
+ MacDevanagari = 9,
+ MacGurmukhi = 10,
+ MacGujarati = 11,
+ MacOriya = 12,
+ MacBengali = 13,
+ MacTamil = 14,
+ MacTelugu = 15,
+ MacKannada = 16,
+ MacMalayalam = 17,
+ MacSinhalese = 18,
+ MacBurmese = 19,
+ MacKhmer = 20,
+ MacThai = 21,
+ MacLaotian = 22,
+ MacGeorgian = 23,
+ MacArmenian = 24,
+ MacChineseSimp = 25,
+ MacTibetan = 26,
+ MacMongolian = 27,
+ MacEthiopic = 28,
+ MacCentralEurRoman = 29,
+ MacVietnamese = 30,
+ MacExtArabic = 31,
+ MacSymbol = 33,
+ MacDingbats = 34,
+ MacTurkish = 35,
+ MacCroatian = 36,
+ MacIcelandic = 37,
+ MacRomanian = 38,
+ MacCeltic = 39,
+ MacGaelic = 40,
+ MacFarsi = 0x8C,
+ MacUkrainian = 0x98,
+ MacInuit = 0xEC,
+ MacVT100 = 0xFC,
+ MacHFS = 0xFF,
+ ISOLatin2 = 0x0202,
+ ISOLatin3 = 0x0203,
+ ISOLatin4 = 0x0204,
+ ISOLatinCyrillic = 0x0205,
+ ISOLatinArabic = 0x0206,
+ ISOLatinGreek = 0x0207,
+ ISOLatinHebrew = 0x0208,
+ ISOLatin5 = 0x0209,
+ ISOLatin6 = 0x020A,
+ ISOLatinThai = 0x020B,
+ ISOLatin7 = 0x020D,
+ ISOLatin8 = 0x020E,
+ ISOLatin9 = 0x020F,
+ ISOLatin10 = 0x0210,
+ DOSLatinUS = 0x0400,
+ DOSGreek = 0x0405,
+ DOSBalticRim = 0x0406,
+ DOSLatin1 = 0x0410,
+ DOSGreek1 = 0x0411,
+ DOSLatin2 = 0x0412,
+ DOSCyrillic = 0x0413,
+ DOSTurkish = 0x0414,
+ DOSPortuguese = 0x0415,
+ DOSIcelandic = 0x0416,
+ DOSHebrew = 0x0417,
+ DOSCanadianFrench = 0x0418,
+ DOSArabic = 0x0419,
+ DOSNordic = 0x041A,
+ DOSRussian = 0x041B,
+ DOSGreek2 = 0x041C,
+ DOSThai = 0x041D,
+ DOSJapanese = 0x0420,
+ DOSChineseSimplif = 0x0421,
+ DOSKorean = 0x0422,
+ DOSChineseTrad = 0x0423,
+ WindowsLatin2 = 0x0501,
+ WindowsCyrillic = 0x0502,
+ WindowsGreek = 0x0503,
+ WindowsLatin5 = 0x0504,
+ WindowsHebrew = 0x0505,
+ WindowsArabic = 0x0506,
+ WindowsBalticRim = 0x0507,
+ WindowsVietnamese = 0x0508,
+ WindowsKoreanJohab = 0x0510,
+ ANSEL = 0x0601,
+ JIS_X0201_76 = 0x0620,
+ JIS_X0208_83 = 0x0621,
+ JIS_X0208_90 = 0x0622,
+ JIS_X0212_90 = 0x0623,
+ JIS_C6226_78 = 0x0624,
+ ShiftJIS_X0213 = 0x0628,
+ ShiftJIS_X0213_MenKuTen = 0x0629,
+ GB_2312_80 = 0x0630,
+ GBK_95 = 0x0631,
+ GB_18030_2000 = 0x0632,
+ KSC_5601_87 = 0x0640,
+ KSC_5601_92_Johab = 0x0641,
+ CNS_11643_92_P1 = 0x0651,
+ CNS_11643_92_P2 = 0x0652,
+ CNS_11643_92_P3 = 0x0653,
+ ISO_2022_JP = 0x0820,
+ ISO_2022_JP_2 = 0x0821,
+ ISO_2022_JP_1 = 0x0822,
+ ISO_2022_JP_3 = 0x0823,
+ ISO_2022_CN = 0x0830,
+ ISO_2022_CN_EXT = 0x0831,
+ ISO_2022_KR = 0x0840,
+ EUC_JP = 0x0920,
+ EUC_CN = 0x0930,
+ EUC_TW = 0x0931,
+ EUC_KR = 0x0940,
+ ShiftJIS = 0x0A01,
+ KOI8_R = 0x0A02,
+ Big5 = 0x0A03,
+ MacRomanLatin1 = 0x0A04,
+ HZ_GB_2312 = 0x0A05,
+ Big5_HKSCS_1999 = 0x0A06,
+ VISCII = 0x0A07,
+ KOI8_U = 0x0A08,
+ Big5_E = 0x0A09,
+ NextStepJapanese = 0x0B02,
+ EBCDIC_US = 0x0C01,
+ EBCDIC_CP037 = 0x0C02,
+ UTF7 = 0x04000100,
+ UTF7_IMAP = 0x0A10,
+ ShiftJIS_X0213_00 = 0x0628, // Deprecated. Use `ShiftJIS_X0213` instead.
}
-@(link_prefix = "CF", default_calling_convention = "c")
+@(link_prefix="CF", default_calling_convention="c")
foreign CoreFoundation {
// Copies the character contents of a string to a local C string buffer after converting the characters to a given encoding.
StringGetCString :: proc(theString: String, buffer: [^]byte, bufferSize: Index, encoding: StringEncoding) -> b8 ---
@@ -181,23 +179,16 @@ foreign CoreFoundation {
STR :: StringMakeConstantString
-StringCopyToOdinString :: proc(
- theString: String,
- allocator := context.allocator,
-) -> (
- str: string,
- ok: bool,
-) #optional_ok {
+StringCopyToOdinString :: proc(theString: String, allocator := context.allocator) -> (str: string, ok: bool) #optional_ok {
length := StringGetLength(theString)
max := StringGetMaximumSizeForEncoding(length, StringEncoding(StringBuiltInEncodings.UTF8))
buf, err := make([]byte, max, allocator)
- if err != nil { return }
-
- raw_str := runtime.Raw_String {
- data = raw_data(buf),
+ if err != nil {
+ return
}
- StringGetBytes(theString, {0, length}, StringEncoding(StringBuiltInEncodings.UTF8), 0, false, raw_data(buf), max, (^Index)(&raw_str.len))
- return transmute(string)raw_str, true
+ n: Index
+ StringGetBytes(theString, {0, length}, StringEncoding(StringBuiltInEncodings.UTF8), 0, false, raw_data(buf), Index(len(buf)), &n)
+ return string(buf[:n]), true
}
diff --git a/core/sys/darwin/Foundation/NSApplication.odin b/core/sys/darwin/Foundation/NSApplication.odin
index 482221cdf..7191f6d07 100644
--- a/core/sys/darwin/Foundation/NSApplication.odin
+++ b/core/sys/darwin/Foundation/NSApplication.odin
@@ -79,7 +79,10 @@ Application_setActivationPolicy :: proc "c" (self: ^Application, activationPolic
return msgSend(BOOL, self, "setActivationPolicy:", activationPolicy)
}
-@(deprecated="Use NSApplication method activate instead.")
+// NOTE: this is technically deprecated but still actively used (Sokol, glfw, SDL, etc.)
+// and has no clear alternative although `activate` is what Apple tells you to use,
+// that does not work the same way.
+// @(deprecated="Use NSApplication method activate instead.")
@(objc_type=Application, objc_name="activateIgnoringOtherApps")
Application_activateIgnoringOtherApps :: proc "c" (self: ^Application, ignoreOtherApps: BOOL) {
msgSend(nil, self, "activateIgnoringOtherApps:", ignoreOtherApps)
diff --git a/core/sys/darwin/Foundation/NSEvent.odin b/core/sys/darwin/Foundation/NSEvent.odin
index f20afd3ab..548c5c172 100644
--- a/core/sys/darwin/Foundation/NSEvent.odin
+++ b/core/sys/darwin/Foundation/NSEvent.odin
@@ -5,8 +5,8 @@ Event :: struct {using _: Object}
-EventMask :: distinct bit_set[EventType; UInteger]
-EventMaskAny :: ~EventMask{}
+EventMask :: distinct bit_set[EventType; UInteger]
+EventMaskAny :: transmute(EventMask)(max(UInteger))
when size_of(UInteger) == 4 {
// We don't support a 32-bit darwin system but this is mostly to shut up the type checker for the time being
diff --git a/core/sys/darwin/Foundation/NSString.odin b/core/sys/darwin/Foundation/NSString.odin
index b4918b3fb..a10b33fc0 100644
--- a/core/sys/darwin/Foundation/NSString.odin
+++ b/core/sys/darwin/Foundation/NSString.odin
@@ -58,7 +58,10 @@ MakeConstantString :: proc "c" (#const c: cstring) -> ^String {
@(link_prefix="NS", default_calling_convention="c")
foreign Foundation {
- StringFromClass :: proc(cls: Class) -> ^String ---
+ StringFromClass :: proc(cls: Class) -> ^String ---
+ ClassFromString :: proc(str: ^String) -> Class ---
+ StringFromSelector :: proc(selector: SEL) -> ^String ---
+ SelectorFromString :: proc(str: ^String) -> SEL ---
}
@(objc_type=String, objc_name="alloc", objc_is_class_method=true)
diff --git a/core/sys/darwin/Foundation/objc.odin b/core/sys/darwin/Foundation/objc.odin
index 51cfee444..82d6199ce 100644
--- a/core/sys/darwin/Foundation/objc.odin
+++ b/core/sys/darwin/Foundation/objc.odin
@@ -9,24 +9,85 @@ import "core:c"
IMP :: proc "c" (object: id, sel: SEL, #c_vararg args: ..any) -> id
+@(default_calling_convention="c")
foreign Foundation {
- objc_getMetaClass :: proc "c" (name: cstring) -> id ---
- objc_lookUpClass :: proc "c" (name: cstring) -> Class ---
- objc_allocateClassPair :: proc "c" (superclass : Class, name : cstring, extraBytes : c.size_t) -> Class ---
- objc_registerClassPair :: proc "c" (cls : Class) ---
-
- sel_registerName :: proc "c" (name: cstring) -> SEL ---
-
- class_addMethod :: proc "c" (cls: Class, name: SEL, imp: IMP, types: cstring) -> BOOL ---
- class_getInstanceMethod :: proc "c" (cls: Class, name: SEL) -> Method ---
- class_createInstance :: proc "c" (cls: Class, extraBytes: c.size_t) -> id ---
-
- method_setImplementation :: proc "c" (method: Method, imp: IMP) ---
-
- object_getClass :: proc "c" (obj: id) -> Class ---
- object_setClass :: proc "c" (obj: id, cls: Class) -> Class ---
- object_getClassName :: proc "c" (obj: id) -> cstring ---
- object_getIndexedIvars :: proc "c" (obj: id) -> rawptr ---
+ objc_getMetaClass :: proc(name: cstring) -> id ---
+ objc_lookUpClass :: proc(name: cstring) -> Class ---
+ objc_allocateClassPair :: proc(superclass: Class, name: cstring, extraBytes: c.size_t) -> Class ---
+ objc_registerClassPair :: proc(cls: Class) ---
+ objc_disposeClassPair :: proc(cls: Class) ---
+ objc_duplicateClass :: proc(original: Class, name: cstring, extraBytes: c.size_t) -> Class ---
+ objc_getProtocol :: proc(name: cstring) -> ^Protocol ---
+ objc_copyProtocolList :: proc(outCount: ^uint) -> [^]^Protocol ---
+ objc_constructInstance :: proc(cls: Class, bytes: rawptr) -> id ---
+ objc_destructInstance :: proc(obj: id) -> rawptr ---
+ objc_getClassList :: proc(buffer: [^]Class, bufferCount: int) -> int ---
+ objc_copyClassList :: proc(outCount: ^uint) -> [^]Class ---
+ objc_getRequiredClass :: proc(name: cstring) -> Class ---
+ objc_setAssociatedObject :: proc(object: id, key: rawptr, value: id, policy: objc_AssociationPolicy) ---
+ objc_getAssociatedObject :: proc(object: id, key: rawptr) -> id ---
+ objc_removeAssociatedObjects :: proc(object: id) ---
+
+ sel_registerName :: proc(name: cstring) -> SEL ---
+ sel_getName :: proc(sel: SEL) -> cstring ---
+ sel_isEqual :: proc(lhs, rhs: SEL) -> BOOL ---
+
+ class_addMethod :: proc(cls: Class, name: SEL, imp: IMP, types: cstring) -> BOOL ---
+ class_getInstanceMethod :: proc(cls: Class, name: SEL) -> Method ---
+ class_getClassMethod :: proc(cls: Class, name: SEL) -> Method ---
+ class_copyMethodList :: proc(cls: Class, outCount: ^uint) -> [^]Method ---
+ class_createInstance :: proc(cls: Class, extraBytes: c.size_t) -> id ---
+ class_replaceMethod :: proc(cls: Class, name: SEL, imp: IMP, types: cstring) -> IMP ---
+ class_getMethodImplementation :: proc(cls: Class, name: SEL) -> IMP ---
+ class_getSuperclass :: proc(cls: Class) -> Class ---
+ class_getName :: proc(cls: Class) -> cstring ---
+ class_isMetaClass :: proc(cls: Class) -> BOOL ---
+ class_addProtocol :: proc(cls: Class, protocol: ^Protocol) -> BOOL ---
+ class_getVersion :: proc(cls: Class) -> c.int ---
+ class_setVersion :: proc(cls: Class, version: c.int) ---
+ class_getProperty :: proc(cls: Class, name: cstring) -> objc_property_t ---
+ class_addProperty :: proc(cls: Class, name: cstring, attributes: [^]objc_property_attribute_t, attributeCount: uint) -> BOOL ---
+ class_replaceProperty :: proc(cls: Class, name: cstring, attributes: [^]objc_property_attribute_t, attributeCount: uint) ---
+ class_copyPropertyList :: proc(cls: Class, outCount: ^uint) -> [^]objc_property_t ---
+ class_conformsToProtocol :: proc(cls: Class, protocol: ^Protocol) -> BOOL ---
+ class_copyProtocolList :: proc(cls: Class, outCount: ^uint) -> [^]^Protocol ---
+ class_respondsToSelector :: proc(cls: Class, sel: SEL) -> BOOL ---
+ class_getClassVariable :: proc(cls: Class, name: cstring) -> Ivar ---
+ class_getInstanceVariable :: proc(cls: Class, name: cstring) -> Ivar ---
+ class_addIvar :: proc(cls: Class, name: cstring, size: c.size_t, alignment: u8, types: cstring) -> BOOL ---
+ class_copyIvarList :: proc(cls: Class, outCount: ^uint) -> [^]Ivar ---
+ class_getInstanceSize :: proc(cls: Class) -> c.size_t ---
+
+ property_getName :: proc(property: objc_property_t) -> cstring ---
+ property_getAttributes :: proc(property: objc_property_t) -> cstring ---
+ property_copyAttributeList :: proc(property: objc_property_t, outCount: ^uint) -> [^]objc_property_attribute_t ---
+ property_copyAttributeValue :: proc(property: objc_property_t, attributeName: cstring) -> cstring ---
+
+ protocol_conformsToProtocol :: proc(proto: ^Protocol, other: ^Protocol) -> BOOL ---
+ protocol_isEqual :: proc(proto: ^Protocol, other: ^Protocol) -> BOOL ---
+ protocol_getName :: proc(proto: ^Protocol) -> cstring ---
+
+ method_getImplementation :: proc(m: Method) -> IMP ---
+ method_setImplementation :: proc(m: Method, imp: IMP) ---
+ method_copyArgumentType :: proc(m: Method, index: uint) -> cstring ---
+ method_getReturnType :: proc(m: Method, dst: cstring, dst_len: c.size_t) ---
+ method_getNumberOfArguments :: proc(m: Method) -> uint ---
+ method_getArgumentType :: proc(m: Method, index: uint, dst: cstring, dst_len: c.size_t) ---
+
+ object_getClass :: proc(obj: id) -> Class ---
+ object_setClass :: proc(obj: id, cls: Class) -> Class ---
+ object_copy :: proc(obj: id, size: c.size_t) -> id ---
+ object_dispose :: proc(obj: id) -> id ---
+ object_getClassName :: proc(obj: id) -> cstring ---
+ object_getIndexedIvars :: proc(obj: id) -> rawptr ---
+ object_getInstanceVariable :: proc(obj: id, name: cstring, outValue: rawptr) -> Ivar ---
+ object_setInstanceVariable :: proc(obj: id, name: cstring, value: rawptr) -> Ivar ---
+ object_getIvar :: proc(obj: id, ivar: Ivar) -> id ---
+ object_setIvar :: proc(obj: id, ivar: Ivar, value: id) ---
+
+ ivar_getName :: proc(v: Ivar) -> cstring ---
+ ivar_getTypeEncoding :: proc(v: Ivar) -> cstring ---
+ ivar_getOffset :: proc(v: Ivar) -> c.ptrdiff_t ---
}
@@ -47,7 +108,17 @@ objc_method :: struct {
}
objc_method_list :: struct {}
+objc_property :: struct{}
+objc_property_t :: ^objc_property
+
+objc_property_attribute_t :: struct {
+ name: cstring,
+ value: cstring,
+}
+
objc_ivar :: struct {}
+Ivar :: ^objc_ivar
+
objc_ivar_list :: struct {}
objc_cache :: struct {
@@ -85,3 +156,11 @@ objc_class_internals :: struct {
protocols: rawptr,
}
+
+objc_AssociationPolicy :: enum c.uintptr_t {
+ Assign = 0,
+ Retain_Nonatomic = 1,
+ Copy_Nonatomic = 3,
+ Retain = 01401,
+ Copy = 01403,
+}
diff --git a/core/sys/darwin/darwin.odin b/core/sys/darwin/darwin.odin
index ddd25a76c..d109f5544 100644
--- a/core/sys/darwin/darwin.odin
+++ b/core/sys/darwin/darwin.odin
@@ -1,4 +1,4 @@
-//+build darwin
+#+build darwin
package darwin
import "core:c"
diff --git a/core/sys/darwin/sync.odin b/core/sys/darwin/sync.odin
index 121d3edef..58fc7c9e4 100644
--- a/core/sys/darwin/sync.odin
+++ b/core/sys/darwin/sync.odin
@@ -5,6 +5,7 @@ foreign import system "system:System.framework"
// #define OS_WAIT_ON_ADDR_AVAILABILITY \
// __API_AVAILABLE(macos(14.4), ios(17.4), tvos(17.4), watchos(10.4))
when ODIN_OS == .Darwin {
+
when ODIN_PLATFORM_SUBTARGET == .iOS && ODIN_MINIMUM_OS_VERSION >= 17_04_00 {
WAIT_ON_ADDRESS_AVAILABLE :: true
} else when ODIN_MINIMUM_OS_VERSION >= 14_04_00 {
@@ -12,8 +13,18 @@ when ODIN_OS == .Darwin {
} else {
WAIT_ON_ADDRESS_AVAILABLE :: false
}
+
+ when ODIN_PLATFORM_SUBTARGET == .iOS && ODIN_MINIMUM_OS_VERSION >= 14_00_00 {
+ ULOCK_WAIT_2_AVAILABLE :: true
+ } else when ODIN_MINIMUM_OS_VERSION >= 11_00_00 {
+ ULOCK_WAIT_2_AVAILABLE :: true
+ } else {
+ ULOCK_WAIT_2_AVAILABLE :: false
+ }
+
} else {
WAIT_ON_ADDRESS_AVAILABLE :: false
+ ULOCK_WAIT_2_AVAILABLE :: false
}
os_sync_wait_on_address_flag :: enum u32 {
diff --git a/core/sys/darwin/xnu_system_call_helpers.odin b/core/sys/darwin/xnu_system_call_helpers.odin
index a641a4be9..ae8373f99 100644
--- a/core/sys/darwin/xnu_system_call_helpers.odin
+++ b/core/sys/darwin/xnu_system_call_helpers.odin
@@ -15,9 +15,9 @@ sys_write_string :: proc (fd: c.int, message: string) -> bool {
Offset_From :: enum c.int {
SEEK_SET = 0, // the offset is set to offset bytes.
SEEK_CUR = 1, // the offset is set to its current location plus offset bytes.
- SEEK_END = 2, // the offset is set to the size of the file plus offset bytes.
- SEEK_HOLE = 3, // the offset is set to the start of the next hole greater than or equal to the supplied offset.
- SEEK_DATA = 4, // the offset is set to the start of the next non-hole file region greater than or equal to the supplied offset.
+ SEEK_END = 2, // the offset is set to the size of the file plus offset bytes.
+ SEEK_HOLE = 3, // the offset is set to the start of the next hole greater than or equal to the supplied offset.
+ SEEK_DATA = 4, // the offset is set to the start of the next non-hole file region greater than or equal to the supplied offset.
}
Open_Flags_Enum :: enum u8 {
diff --git a/core/sys/darwin/xnu_system_call_wrappers.odin b/core/sys/darwin/xnu_system_call_wrappers.odin
index 30faf86be..1188091a9 100644
--- a/core/sys/darwin/xnu_system_call_wrappers.odin
+++ b/core/sys/darwin/xnu_system_call_wrappers.odin
@@ -192,43 +192,43 @@ _STRUCT_TIMEVAL :: struct {
/* pwd.h */
_Password_Entry :: struct {
- pw_name: cstring, /* username */
- pw_passwd: cstring, /* user password */
- pw_uid: i32, /* user ID */
- pw_gid: i32, /* group ID */
+ pw_name: cstring, /* username */
+ pw_passwd: cstring, /* user password */
+ pw_uid: i32, /* user ID */
+ pw_gid: i32, /* group ID */
pw_change: u64, /* password change time */
pw_class: cstring, /* user access class */
- pw_gecos: cstring, /* full user name */
- pw_dir: cstring, /* home directory */
- pw_shell: cstring, /* shell program */
+ pw_gecos: cstring, /* full user name */
+ pw_dir: cstring, /* home directory */
+ pw_shell: cstring, /* shell program */
pw_expire: u64, /* account expiration */
pw_fields: i32, /* filled fields */
}
/* processinfo.h */
_Proc_Bsdinfo :: struct {
- pbi_flags: u32, /* if is 64bit; emulated etc */
- pbi_status: u32,
- pbi_xstatus: u32,
- pbi_pid: u32,
- pbi_ppid: u32,
- pbi_uid: u32,
- pbi_gid: u32,
- pbi_ruid: u32,
- pbi_rgid: u32,
- pbi_svuid: u32,
- pbi_svgid: u32,
- res: u32,
- pbi_comm: [DARWIN_MAXCOMLEN]u8,
- pbi_name: [2 * DARWIN_MAXCOMLEN]u8, /* empty if no name is registered */
- pbi_nfiles: u32,
- pbi_pgid: u32,
- pbi_pjobc: u32,
- e_tdev: u32, /* controlling tty dev */
- e_tpgid: u32, /* tty process group id */
- pbi_nice: i32,
- pbi_start_tvsec: u64,
- pbi_start_tvusec: u64,
+ pbi_flags: u32, /* if is 64bit; emulated etc */
+ pbi_status: u32,
+ pbi_xstatus: u32,
+ pbi_pid: u32,
+ pbi_ppid: u32,
+ pbi_uid: u32,
+ pbi_gid: u32,
+ pbi_ruid: u32,
+ pbi_rgid: u32,
+ pbi_svuid: u32,
+ pbi_svgid: u32,
+ res: u32,
+ pbi_comm: [DARWIN_MAXCOMLEN]u8,
+ pbi_name: [2 * DARWIN_MAXCOMLEN]u8, /* empty if no name is registered */
+ pbi_nfiles: u32,
+ pbi_pgid: u32,
+ pbi_pjobc: u32,
+ e_tdev: u32, /* controlling tty dev */
+ e_tpgid: u32, /* tty process group id */
+ pbi_nice: i32,
+ pbi_start_tvsec: u64,
+ pbi_start_tvusec: u64,
}
/*--==========================================================================--*/
diff --git a/core/sys/freebsd/syscalls.odin b/core/sys/freebsd/syscalls.odin
index 4a79bd56c..83b51138a 100644
--- a/core/sys/freebsd/syscalls.odin
+++ b/core/sys/freebsd/syscalls.odin
@@ -14,12 +14,16 @@ import "core:c"
// FreeBSD 15 syscall numbers
// See: https://alfonsosiciliano.gitlab.io/posts/2023-08-28-freebsd-15-system-calls.html
+SYS_read : uintptr : 3
+SYS_write : uintptr : 4
SYS_open : uintptr : 5
SYS_close : uintptr : 6
SYS_getpid : uintptr : 20
SYS_recvfrom : uintptr : 29
SYS_accept : uintptr : 30
+SYS_getsockname: uintptr : 32
SYS_fcntl : uintptr : 92
+SYS_fsync : uintptr : 95
SYS_socket : uintptr : 97
SYS_connect : uintptr : 98
SYS_bind : uintptr : 104
@@ -29,12 +33,46 @@ SYS_shutdown : uintptr : 134
SYS_setsockopt : uintptr : 105
SYS_sysctl : uintptr : 202
SYS__umtx_op : uintptr : 454
+SYS_pread : uintptr : 475
+SYS_pwrite : uintptr : 476
SYS_accept4 : uintptr : 541
//
// Odin syscall wrappers
//
+// Read input.
+//
+// The read() function appeared in Version 1 AT&T UNIX.
+read :: proc "contextless" (fd: Fd, buf: []u8) -> (int, Errno) {
+ result, ok := intrinsics.syscall_bsd(SYS_read,
+ cast(uintptr)fd,
+ cast(uintptr)raw_data(buf),
+ cast(uintptr)len(buf))
+
+ if !ok {
+ return 0, cast(Errno)result
+ }
+
+ return cast(int)result, nil
+}
+
+// Write output.
+//
+// The write() function appeared in Version 1 AT&T UNIX.
+write :: proc "contextless" (fd: Fd, buf: []u8) -> (int, Errno) {
+ result, ok := intrinsics.syscall_bsd(SYS_pwrite,
+ cast(uintptr)fd,
+ cast(uintptr)raw_data(buf),
+ cast(uintptr)len(buf))
+
+ if !ok {
+ return 0, cast(Errno)result
+ }
+
+ return cast(int)result, nil
+}
+
// Open or create a file for reading, writing or executing.
//
// The open() function appeared in Version 1 AT&T UNIX.
@@ -164,6 +202,36 @@ accept_nil :: proc "contextless" (s: Fd) -> (Fd, Errno) {
accept :: proc { accept_T, accept_nil }
+// Get socket name.
+//
+// The getsockname() system call appeared in 4.2BSD.
+getsockname :: proc "contextless" (s: Fd, sockaddr: ^$T) -> Errno {
+ // sockaddr must contain a valid pointer, or this will segfault because
+ // we're telling the syscall that there's memory available to write to.
+ addrlen: socklen_t = size_of(T)
+
+ result, ok := intrinsics.syscall_bsd(SYS_getsockname,
+ cast(uintptr)s,
+ cast(uintptr)sockaddr,
+ cast(uintptr)&addrlen)
+
+ if !ok {
+ return cast(Errno)result
+ }
+
+ return nil
+}
+
+// Synchronize changes to a file.
+//
+// The fsync() system call appeared in 4.2BSD.
+fsync :: proc "contextless" (fd: Fd) -> Errno {
+ result, _ := intrinsics.syscall_bsd(SYS_fsync,
+ cast(uintptr)fd)
+
+ return cast(Errno)result
+}
+
// File control.
//
// The fcntl() system call appeared in 4.2BSD.
@@ -469,6 +537,46 @@ _umtx_op :: proc "contextless" (obj: rawptr, op: Userland_Mutex_Operation, val:
return cast(Errno)result
}
+// Read input without modifying the file pointer.
+//
+// The pread() function appeared in AT&T System V Release 4 UNIX.
+pread :: proc "contextless" (fd: Fd, buf: []u8, offset: off_t) -> (int, Errno) {
+ result, ok := intrinsics.syscall_bsd(SYS_pread,
+ cast(uintptr)fd,
+ cast(uintptr)raw_data(buf),
+ cast(uintptr)len(buf),
+ cast(uintptr)offset)
+
+ if !ok {
+ return 0, cast(Errno)result
+ }
+
+ return cast(int)result, nil
+}
+
+// Write output without modifying the file pointer.
+//
+// The pwrite() function appeared in AT&T System V Release 4 UNIX.
+//
+// BUGS
+//
+// The pwrite() system call appends the file without changing the file
+// offset if O_APPEND is set, contrary to IEEE Std 1003.1-2008 (“POSIX.1”)
+// where pwrite() writes into offset regardless of whether O_APPEND is set.
+pwrite :: proc "contextless" (fd: Fd, buf: []u8, offset: off_t) -> (int, Errno) {
+ result, ok := intrinsics.syscall_bsd(SYS_pwrite,
+ cast(uintptr)fd,
+ cast(uintptr)raw_data(buf),
+ cast(uintptr)len(buf),
+ cast(uintptr)offset)
+
+ if !ok {
+ return 0, cast(Errno)result
+ }
+
+ return cast(int)result, nil
+}
+
// Accept a connection on a socket.
//
// The accept4() system call appeared in FreeBSD 10.0.
diff --git a/core/sys/freebsd/types.odin b/core/sys/freebsd/types.odin
index a13961a47..37e8abf68 100644
--- a/core/sys/freebsd/types.odin
+++ b/core/sys/freebsd/types.odin
@@ -695,12 +695,12 @@ Record_Lock_Flag :: enum c.int {
// struct flock
File_Lock :: struct {
- start: off_t, /* starting offset */
- len: off_t, /* len = 0 means until end of file */
- pid: pid_t, /* lock owner */
- type: Record_Lock_Flag, /* lock type: read/write, etc. */
- whence: c.short, /* type of l_start */
- sysid: c.int, /* remote system id or zero for local */
+ start: off_t, /* starting offset */
+ len: off_t, /* len = 0 means until end of file */
+ pid: pid_t, /* lock owner */
+ type: Record_Lock_Flag, /* lock type: read/write, etc. */
+ whence: c.short, /* type of l_start */
+ sysid: c.int, /* remote system id or zero for local */
}
/*
diff --git a/core/sys/haiku/errors.odin b/core/sys/haiku/errors.odin
index 023045001..febe647ea 100644
--- a/core/sys/haiku/errors.odin
+++ b/core/sys/haiku/errors.odin
@@ -1,4 +1,4 @@
-//+build haiku
+#+build haiku
package sys_haiku
import "core:c"
diff --git a/core/sys/haiku/find_directory.odin b/core/sys/haiku/find_directory.odin
index 103e677d7..758c4dff4 100644
--- a/core/sys/haiku/find_directory.odin
+++ b/core/sys/haiku/find_directory.odin
@@ -1,4 +1,4 @@
-//+build haiku
+#+build haiku
package sys_haiku
import "core:c"
diff --git a/core/sys/haiku/os.odin b/core/sys/haiku/os.odin
index 883072c2d..6ab3ef573 100644
--- a/core/sys/haiku/os.odin
+++ b/core/sys/haiku/os.odin
@@ -1,4 +1,4 @@
-//+build haiku
+#+build haiku
package sys_haiku
import "core:c"
diff --git a/core/sys/haiku/types.odin b/core/sys/haiku/types.odin
index 0440d5a98..47755b0b7 100644
--- a/core/sys/haiku/types.odin
+++ b/core/sys/haiku/types.odin
@@ -1,4 +1,4 @@
-//+build haiku
+#+build haiku
package sys_haiku
import "core:c"
diff --git a/core/sys/info/cpu_arm.odin b/core/sys/info/cpu_arm.odin
index aa4bb368a..960e55a56 100644
--- a/core/sys/info/cpu_arm.odin
+++ b/core/sys/info/cpu_arm.odin
@@ -1,4 +1,4 @@
-//+build arm32, arm64
+#+build arm32, arm64
package sysinfo
import "core:sys/unix"
diff --git a/core/sys/info/cpu_intel.odin b/core/sys/info/cpu_intel.odin
index 73d4c15e7..d6fa98507 100644
--- a/core/sys/info/cpu_intel.odin
+++ b/core/sys/info/cpu_intel.odin
@@ -1,4 +1,4 @@
-//+build i386, amd64
+#+build i386, amd64
package sysinfo
import "base:intrinsics"
diff --git a/core/sys/info/cpu_linux_arm.odin b/core/sys/info/cpu_linux_arm.odin
index dcc252971..6408decb7 100644
--- a/core/sys/info/cpu_linux_arm.odin
+++ b/core/sys/info/cpu_linux_arm.odin
@@ -1,5 +1,5 @@
-//+build arm32, arm64
-//+build linux
+#+build arm32, arm64
+#+build linux
package sysinfo
import "core:sys/linux"
diff --git a/core/sys/info/cpu_linux_riscv64.odin b/core/sys/info/cpu_linux_riscv64.odin
index 0f109e7ba..84f6134d4 100644
--- a/core/sys/info/cpu_linux_riscv64.odin
+++ b/core/sys/info/cpu_linux_riscv64.odin
@@ -1,5 +1,5 @@
-//+build riscv64
-//+build linux
+#+build riscv64
+#+build linux
package sysinfo
import "base:intrinsics"
@@ -8,35 +8,102 @@ import "core:sys/linux"
@(init, private)
init_cpu_features :: proc() {
- fd, err := linux.open("/proc/self/auxv", {})
- if err != .NONE { return }
- defer linux.close(fd)
-
- // This is probably enough right?
- buf: [4096]byte
- n, rerr := linux.read(fd, buf[:])
- if rerr != .NONE || n == 0 { return }
-
- ulong :: u64
- AT_HWCAP :: 16
-
- // TODO: using these we could get more information than just the basics.
- // AT_HWCAP2 :: 26
- // AT_HWCAP3 :: 29
- // AT_HWCAP4 :: 30
-
- auxv := buf[:n]
- for len(auxv) >= size_of(ulong)*2 {
- key := intrinsics.unaligned_load((^ulong)(&auxv[0]))
- val := intrinsics.unaligned_load((^ulong)(&auxv[size_of(ulong)]))
- auxv = auxv[2*size_of(ulong):]
-
- if key != AT_HWCAP {
- continue
+ _features: CPU_Features
+ defer cpu_features = _features
+
+ HWCAP_Bits :: enum u64 {
+ I = 'I' - 'A',
+ M = 'M' - 'A',
+ A = 'A' - 'A',
+ F = 'F' - 'A',
+ D = 'D' - 'A',
+ C = 'C' - 'A',
+ V = 'V' - 'A',
+ }
+ HWCAP :: bit_set[HWCAP_Bits; u64]
+
+ // Read HWCAP for base extensions, we can get this info through hwprobe too but that is Linux 6.4+ only.
+ {
+ fd, err := linux.open("/proc/self/auxv", {})
+ if err != .NONE { return }
+ defer linux.close(fd)
+
+ // This is probably enough right?
+ buf: [4096]byte
+ n, rerr := linux.read(fd, buf[:])
+ if rerr != .NONE || n == 0 { return }
+
+ ulong :: u64
+ AT_HWCAP :: 16
+
+ auxv := buf[:n]
+ for len(auxv) >= size_of(ulong)*2 {
+ key := intrinsics.unaligned_load((^ulong)(&auxv[0]))
+ val := intrinsics.unaligned_load((^ulong)(&auxv[size_of(ulong)]))
+ auxv = auxv[2*size_of(ulong):]
+
+ if key != AT_HWCAP {
+ continue
+ }
+
+ cap := transmute(HWCAP)(val)
+ if .I in cap {
+ _features += { .I }
+ }
+ if .M in cap {
+ _features += { .M }
+ }
+ if .A in cap {
+ _features += { .A }
+ }
+ if .F in cap {
+ _features += { .F }
+ }
+ if .D in cap {
+ _features += { .D }
+ }
+ if .C in cap {
+ _features += { .C }
+ }
+ if .V in cap {
+ _features += { .V }
+ }
+ break
}
+ }
- cpu_features = transmute(CPU_Features)(val)
- break
+ // hwprobe for other features.
+ {
+ pairs := []linux.RISCV_HWProbe{
+ { key = .IMA_EXT_0 },
+ { key = .CPUPERF_0 },
+ { key = .MISALIGNED_SCALAR_PERF },
+ }
+ err := linux.riscv_hwprobe(raw_data(pairs), len(pairs), 0, nil, {})
+ if err != nil {
+ assert(err == .ENOSYS, "unexpected error from riscv_hwprobe()")
+ return
+ }
+
+ assert(pairs[0].key == .IMA_EXT_0)
+ exts := pairs[0].value.ima_ext_0
+ exts -= { .FD, .C, .V }
+ _features += transmute(CPU_Features)exts
+
+ if pairs[2].key == .MISALIGNED_SCALAR_PERF {
+ if pairs[2].value.misaligned_scalar_perf == .FAST {
+ _features += { .Misaligned_Supported, .Misaligned_Fast }
+ } else if pairs[2].value.misaligned_scalar_perf != .UNSUPPORTED {
+ _features += { .Misaligned_Supported }
+ }
+ } else {
+ assert(pairs[1].key == .CPUPERF_0)
+ if .FAST in pairs[1].value.cpu_perf_0 {
+ _features += { .Misaligned_Supported, .Misaligned_Fast }
+ } else if .UNSUPPORTED not_in pairs[1].value.cpu_perf_0 {
+ _features += { .Misaligned_Supported }
+ }
+ }
}
}
diff --git a/core/sys/info/cpu_riscv64.odin b/core/sys/info/cpu_riscv64.odin
index 754110911..c3319c48c 100644
--- a/core/sys/info/cpu_riscv64.odin
+++ b/core/sys/info/cpu_riscv64.odin
@@ -1,13 +1,97 @@
package sysinfo
CPU_Feature :: enum u64 {
- I = 'I' - 'A', // Base features, don't think this is ever not here.
- M = 'M' - 'A', // Integer multiplication and division, currently required by Odin.
- A = 'A' - 'A', // Atomics.
- F = 'F' - 'A', // Single precision floating point, currently required by Odin.
- D = 'D' - 'A', // Double precision floating point, currently required by Odin.
- C = 'C' - 'A', // Compressed instructions.
- V = 'V' - 'A', // Vector operations.
+ // Bit-Manipulation ISA Extensions v1.
+ Zba = 3,
+ Zbb,
+ Zbs,
+
+ // CMOs (ratified).
+ Zicboz,
+
+ // Bit-Manipulation ISA Extensions v1.
+ Zbc,
+
+ // Scalar Crypto ISA extensions v1.
+ Zbkb,
+ Zbkc,
+ Zbkx,
+ Zknd,
+ Zkne,
+ Zknh,
+ Zksed,
+ Zksh,
+ Zkt,
+
+ // Cryptography Extensions Volume II v1.
+ Zvbb,
+ Zvbc,
+ Zvkb,
+ Zvkg,
+ Zvkned,
+ Zvknha,
+ Zvknhb,
+ Zvksed,
+ Zvksh,
+ Zvkt,
+
+ // ISA Manual v1.
+ Zfh,
+ Zfhmin,
+ Zihintntl,
+
+ // ISA manual (ratified).
+ Zvfh,
+ Zvfhmin,
+ Zfa,
+ Ztso,
+
+ // Atomic Compare-and-Swap Instructions Manual (ratified).
+ Zacas,
+ Zicond,
+
+ // ISA manual (ratified).
+ Zihintpause,
+
+ // Vector Extensions Manual v1.
+ Zve32x,
+ Zve32f,
+ Zve64x,
+ Zve64f,
+ Zve64d,
+
+ // ISA manual (ratified).
+ Zimop,
+
+ // Code Size Reduction (ratified).
+ Zca,
+ Zcb,
+ Zcd,
+ Zcf,
+
+ // ISA manual (ratified).
+ Zcmop,
+ Zawrs,
+
+ // Base features, don't think this is ever not here.
+ I,
+ // Integer multiplication and division, currently required by Odin.
+ M,
+ // Atomics.
+ A,
+ // Single precision floating point, currently required by Odin.
+ F,
+ // Double precision floating point, currently required by Odin.
+ D,
+ // Compressed instructions.
+ C,
+ // Vector operations.
+ V,
+
+ // Indicates Misaligned Scalar Loads will not trap the program.
+ Misaligned_Supported,
+ // Indicates Hardware Support for Misaligned Scalar Loads.
+ Misaligned_Fast,
}
CPU_Features :: distinct bit_set[CPU_Feature; u64]
diff --git a/core/sys/info/doc.odin b/core/sys/info/doc.odin
index 802cd9c60..b5cd62d81 100644
--- a/core/sys/info/doc.odin
+++ b/core/sys/info/doc.odin
@@ -2,6 +2,12 @@
Copyright 2022 Jeroen van Rijn <nom@duclavier.com>.
Made available under Odin's BSD-3 license.
+List of contributors:
+ Jeroen van Rijn: Initial implementation.
+ Laytan: ARM and RISC-V CPU feature detection.
+*/
+
+/*
Package `core:sys/info` gathers system information on:
Windows, Linux, macOS, FreeBSD & OpenBSD.
@@ -11,9 +17,10 @@ and CPU information.
On Windows, GPUs will also be enumerated using the registry.
CPU feature flags can be tested against `cpu_features`, where applicable, e.g.
-`if .aes in si.aes { ... }`
+`if .aes in info.cpu_features.? { ... }`
Example:
+ package main
import "core:fmt"
import si "core:sys/info"
diff --git a/core/sys/info/platform_bsd.odin b/core/sys/info/platform_bsd.odin
index e2273d253..6bb32cd3d 100644
--- a/core/sys/info/platform_bsd.odin
+++ b/core/sys/info/platform_bsd.odin
@@ -1,4 +1,4 @@
-//+build openbsd, netbsd
+#+build openbsd, netbsd
package sysinfo
import sys "core:sys/unix"
diff --git a/core/sys/info/platform_darwin.odin b/core/sys/info/platform_darwin.odin
index 3fd857bfe..493f038f0 100644
--- a/core/sys/info/platform_darwin.odin
+++ b/core/sys/info/platform_darwin.odin
@@ -530,6 +530,10 @@ macos_release_map: map[string]Darwin_To_Release = {
"23F79" = {{23, 5, 0}, "macOS", {"Sonoma", {14, 5, 0}}},
"23G80" = {{23, 6, 0}, "macOS", {"Sonoma", {14, 6, 0}}},
"23G93" = {{23, 6, 0}, "macOS", {"Sonoma", {14, 6, 1}}},
+ "23H124" = {{23, 6, 0}, "macOS", {"Sonoma", {14, 7, 0}}},
+
+ // MacOS Sequoia
+ "24A335" = {{24, 0, 0}, "macOS", {"Sequoia", {15, 0, 0}}},
}
@(private)
diff --git a/core/sys/kqueue/kqueue.odin b/core/sys/kqueue/kqueue.odin
index 27d1ecaae..56be1cf7a 100644
--- a/core/sys/kqueue/kqueue.odin
+++ b/core/sys/kqueue/kqueue.odin
@@ -1,4 +1,4 @@
-//+build darwin, netbsd, openbsd, freebsd
+#+build darwin, netbsd, openbsd, freebsd
package kqueue
when ODIN_OS == .Darwin {
diff --git a/core/sys/linux/bits.odin b/core/sys/linux/bits.odin
index f78891bc8..8a4a6dd7a 100644
--- a/core/sys/linux/bits.odin
+++ b/core/sys/linux/bits.odin
@@ -1839,3 +1839,87 @@ Execveat_Flags_Bits :: enum {
AT_SYMLINK_NOFOLLOW = 8,
AT_EMPTY_PATH = 12,
}
+
+RISCV_HWProbe_Key :: enum i64 {
+ UNSUPPORTED = -1,
+ MVENDORID = 0,
+ MARCHID = 1,
+ MIMPID = 2,
+ BASE_BEHAVIOR = 3,
+ IMA_EXT_0 = 4,
+ // Deprecated, try `.MISALIGNED_SCALAR_PERF` first, if that is `.UNSUPPORTED`, use this.
+ CPUPERF_0 = 5,
+ ZICBOZ_BLOCK_SIZE = 6,
+ HIGHEST_VIRT_ADDRESS = 7,
+ TIME_CSR_FREQ = 8,
+ MISALIGNED_SCALAR_PERF = 9,
+}
+
+RISCV_HWProbe_Flags_Bits :: enum {
+ WHICH_CPUS,
+}
+
+RISCV_HWProbe_Base_Behavior_Bits :: enum {
+ IMA,
+}
+
+RISCV_HWProbe_IMA_Ext_0_Bits :: enum {
+ FD,
+ C,
+ V,
+ EXT_ZBA,
+ EXT_ZBB,
+ EXT_ZBS,
+ EXT_ZICBOZ,
+ EXT_ZBC,
+ EXT_ZBKB,
+ EXT_ZBKC,
+ EXT_ZBKX,
+ EXT_ZKND,
+ EXT_ZKNE,
+ EXT_ZKNH,
+ EXT_ZKSED,
+ EXT_ZKSH,
+ EXT_ZKT,
+ EXT_ZVBB,
+ EXT_ZVBC,
+ EXT_ZVKB,
+ EXT_ZVKG,
+ EXT_ZVKNED,
+ EXT_ZVKNHA,
+ EXT_ZVKNHB,
+ EXT_ZVKSED,
+ EXT_ZVKSH,
+ EXT_ZVKT,
+ EXT_ZFH,
+ EXT_ZFHMIN,
+ EXT_ZIHINTNTL,
+ EXT_ZVFH,
+ EXT_ZVFHMIN,
+ EXT_ZFA,
+ EXT_ZTSO,
+ EXT_ZACAS,
+ EXT_ZICOND,
+ EXT_ZIHINTPAUSE,
+ EXT_ZVE32X,
+ EXT_ZVE32F,
+ EXT_ZVE64X,
+ EXT_ZVE64F,
+ EXT_ZVE64D,
+ EXT_ZIMOP,
+ EXT_ZCA,
+ EXT_ZCB,
+ EXT_ZCD,
+ EXT_ZCF,
+ EXT_ZCMOP,
+ EXT_ZAWRS,
+}
+
+RISCV_HWProbe_Misaligned_Scalar_Perf :: enum {
+ UNKNOWN,
+ EMULATED,
+ SLOW,
+ FAST,
+ UNSUPPORTED,
+}
+
diff --git a/core/sys/linux/helpers.odin b/core/sys/linux/helpers.odin
index f1abbbf61..aefc1179e 100644
--- a/core/sys/linux/helpers.odin
+++ b/core/sys/linux/helpers.odin
@@ -1,5 +1,5 @@
-//+build linux
-//+no-instrumentation
+#+build linux
+#+no-instrumentation
package linux
import "base:intrinsics"
diff --git a/core/sys/linux/sys.odin b/core/sys/linux/sys.odin
index 6e4194be7..c5894d78b 100644
--- a/core/sys/linux/sys.odin
+++ b/core/sys/linux/sys.odin
@@ -1,4 +1,4 @@
-//+no-instrumentation
+#+no-instrumentation
package linux
import "base:intrinsics"
@@ -1443,8 +1443,9 @@ ptrace_traceme :: proc "contextless" (rq: PTrace_Traceme_Type) -> (Errno) {
}
ptrace_peek :: proc "contextless" (rq: PTrace_Peek_Type, pid: Pid, addr: uintptr) -> (uint, Errno) {
- ret := syscall(SYS_ptrace, rq, pid, addr)
- return errno_unwrap(ret, uint)
+ res: uint = ---
+ ret := syscall(SYS_ptrace, rq, pid, addr, &res)
+ return res, Errno(-ret)
}
ptrace_poke :: proc "contextless" (rq: PTrace_Poke_Type, pid: Pid, addr: uintptr, data: uint) -> (Errno) {
@@ -1493,12 +1494,12 @@ ptrace_setregset :: proc "contextless" (rq: PTrace_Setregset_Type, pid: Pid, not
}
ptrace_getsiginfo :: proc "contextless" (rq: PTrace_Getsiginfo_Type, pid: Pid, si: ^Sig_Info) -> (Errno) {
- ret := syscall(SYS_ptrace, rq, pid, si)
+ ret := syscall(SYS_ptrace, rq, pid, si, rawptr(nil))
return Errno(-ret)
}
ptrace_peeksiginfo :: proc "contextless" (rq: PTrace_Peeksiginfo_Type, pid: Pid, si: ^Sig_Info) -> (Errno) {
- ret := syscall(SYS_ptrace, rq, pid, si)
+ ret := syscall(SYS_ptrace, rq, pid, si, rawptr(nil))
return Errno(-ret)
}
@@ -1518,52 +1519,52 @@ ptrace_setoptions :: proc "contextless" (rq: PTrace_Setoptions_Type, pid: Pid, o
}
ptrace_geteventmsg :: proc "contextless" (rq: PTrace_Geteventmsg_Type, pid: Pid, msg: ^uint) -> (Errno) {
- ret := syscall(SYS_ptrace, rq, pid, msg)
+ ret := syscall(SYS_ptrace, rq, pid, msg, rawptr(nil))
return Errno(-ret)
}
ptrace_cont :: proc "contextless" (rq: PTrace_Cont_Type, pid: Pid, sig: Signal) -> (Errno) {
- ret := syscall(SYS_ptrace, rq, pid, sig)
+ ret := syscall(SYS_ptrace, rq, pid, rawptr(nil), sig)
return Errno(-ret)
}
ptrace_singlestep :: proc "contextless" (rq: PTrace_Singlestep_Type, pid: Pid, sig: Signal) -> (Errno) {
- ret := syscall(SYS_ptrace, rq, pid, sig)
+ ret := syscall(SYS_ptrace, rq, pid, rawptr(nil), sig)
return Errno(-ret)
}
ptrace_syscall :: proc "contextless" (rq: PTrace_Syscall_Type, pid: Pid, sig: Signal) -> (Errno) {
- ret := syscall(SYS_ptrace, rq, pid, sig)
+ ret := syscall(SYS_ptrace, rq, pid, rawptr(nil), sig)
return Errno(-ret)
}
ptrace_sysemu :: proc "contextless" (rq: PTrace_Sysemu_Type, pid: Pid, sig: Signal) -> (Errno) {
- ret := syscall(SYS_ptrace, rq, pid, sig)
+ ret := syscall(SYS_ptrace, rq, pid, rawptr(nil), sig)
return Errno(-ret)
}
ptrace_sysemu_singlestep :: proc "contextless" (rq: PTrace_Sysemu_Singlestep_Type, pid: Pid, sig: Signal) -> (Errno) {
- ret := syscall(SYS_ptrace, rq, pid, sig)
+ ret := syscall(SYS_ptrace, rq, pid, rawptr(nil), sig)
return Errno(-ret)
}
ptrace_listen :: proc "contextless" (rq: PTrace_Listen_Type, pid: Pid) -> (Errno) {
- ret := syscall(SYS_ptrace, rq, pid)
+ ret := syscall(SYS_ptrace, rq, pid, 0, rawptr(nil))
return Errno(-ret)
}
ptrace_interrupt :: proc "contextless" (rq: PTrace_Interrupt_Type, pid: Pid) -> (Errno) {
- ret := syscall(SYS_ptrace, rq, pid)
+ ret := syscall(SYS_ptrace, rq, pid, 0, rawptr(nil))
return Errno(-ret)
}
ptrace_attach :: proc "contextless" (rq: PTrace_Attach_Type, pid: Pid) -> (Errno) {
- ret := syscall(SYS_ptrace, rq, pid)
+ ret := syscall(SYS_ptrace, rq, pid, 0, rawptr(nil))
return Errno(-ret)
}
ptrace_seize :: proc "contextless" (rq: PTrace_Seize_Type, pid: Pid, opt: PTrace_Options) -> (Errno) {
- ret := syscall(SYS_ptrace, rq, pid, 0, transmute(u32) opt)
+ ret := syscall(SYS_ptrace, rq, pid, 0, transmute(u32) opt, rawptr(nil))
return Errno(-ret)
}
@@ -2993,3 +2994,18 @@ epoll_pwait2 :: proc(epfd: Fd, events: [^]EPoll_Event, count: i32, timeout: ^Tim
// TODO(flysand): fchmodat2
// TODO(flysand): map_shadow_stack
+
+when ODIN_ARCH == .riscv64 {
+ /*
+ Probe for RISC-V Hardware Support.
+ Available since Linux 6.4.
+
+ TODO: cpu_set_t
+
+ See: https://docs.kernel.org/arch/riscv/hwprobe.html
+ */
+ riscv_hwprobe :: proc "contextless" (pairs: [^]RISCV_HWProbe, pair_count: uint, cpu_count: uint, cpus: rawptr /* cpu_set_t */, flags: RISCV_HWProbe_Flags) -> Errno {
+ ret := syscall(SYS_riscv_hwprobe, pairs, pair_count, cpu_count, cpus, transmute(u32)flags)
+ return Errno(-ret)
+ }
+}
diff --git a/core/sys/linux/syscall_amd64.odin b/core/sys/linux/syscall_amd64.odin
index ee4e16280..31c8ed61c 100644
--- a/core/sys/linux/syscall_amd64.odin
+++ b/core/sys/linux/syscall_amd64.odin
@@ -1,4 +1,4 @@
-//+build amd64
+#+build amd64
package linux
// AMD64 uses the new way to define syscalls, i.e. one that
diff --git a/core/sys/linux/syscall_arm32.odin b/core/sys/linux/syscall_arm32.odin
index 74640a1a3..731ce36a5 100644
--- a/core/sys/linux/syscall_arm32.odin
+++ b/core/sys/linux/syscall_arm32.odin
@@ -1,4 +1,4 @@
-//+build arm32
+#+build arm32
package linux
// This file was taken and transformed from
diff --git a/core/sys/linux/syscall_arm64.odin b/core/sys/linux/syscall_arm64.odin
index 61b5a31b7..da8eb45da 100644
--- a/core/sys/linux/syscall_arm64.odin
+++ b/core/sys/linux/syscall_arm64.odin
@@ -1,4 +1,4 @@
-//+build arm64
+#+build arm64
package linux
// Syscalls for arm64 are defined using the new way, i.e. differently from
diff --git a/core/sys/linux/syscall_i386.odin b/core/sys/linux/syscall_i386.odin
index 4609fc99c..affdff02c 100644
--- a/core/sys/linux/syscall_i386.odin
+++ b/core/sys/linux/syscall_i386.odin
@@ -1,4 +1,4 @@
-//+build i386
+#+build i386
package linux
// The numbers are taken from
diff --git a/core/sys/linux/syscall_riscv64.odin b/core/sys/linux/syscall_riscv64.odin
index ce374312e..17845c5ed 100644
--- a/core/sys/linux/syscall_riscv64.odin
+++ b/core/sys/linux/syscall_riscv64.odin
@@ -1,4 +1,4 @@
-//+build riscv64
+#+build riscv64
package linux
// https://github.com/riscv-collab/riscv-gnu-toolchain/blob/master/linux-headers/include/asm-generic/unistd.h
@@ -248,6 +248,7 @@ SYS_rt_tgsigqueueinfo :: uintptr(240)
SYS_perf_event_open :: uintptr(241)
SYS_accept4 :: uintptr(242)
SYS_recvmmsg :: uintptr(243)
+SYS_riscv_hwprobe :: uintptr(258)
SYS_wait4 :: uintptr(260)
SYS_prlimit64 :: uintptr(261)
SYS_fanotify_init :: uintptr(262)
diff --git a/core/sys/linux/types.odin b/core/sys/linux/types.odin
index 3f873f96c..0e5b8218b 100644
--- a/core/sys/linux/types.odin
+++ b/core/sys/linux/types.odin
@@ -1335,3 +1335,20 @@ EPoll_Event :: struct #packed {
Flags for execveat(2) syscall.
*/
Execveat_Flags :: bit_set[Execveat_Flags_Bits; i32]
+
+RISCV_HWProbe_Flags :: bit_set[RISCV_HWProbe_Flags_Bits; u32]
+RISCV_HWProbe_CPU_Perf_0 :: bit_set[RISCV_HWProbe_Misaligned_Scalar_Perf; u64]
+RISCV_HWProbe_Base_Behavior :: bit_set[RISCV_HWProbe_Base_Behavior_Bits; u64]
+RISCV_HWProbe_IMA_Ext_0 :: bit_set[RISCV_HWProbe_IMA_Ext_0_Bits; u64]
+
+RISCV_HWProbe :: struct {
+ // set to `.UNSUPPORTED` by the kernel if that is the case.
+ key: RISCV_HWProbe_Key,
+ value: struct #raw_union {
+ base_behavior: RISCV_HWProbe_Base_Behavior,
+ ima_ext_0: RISCV_HWProbe_IMA_Ext_0,
+ cpu_perf_0: RISCV_HWProbe_CPU_Perf_0,
+ misaligned_scalar_perf: RISCV_HWProbe_Misaligned_Scalar_Perf,
+ raw: u64,
+ },
+}
diff --git a/core/sys/linux/wrappers.odin b/core/sys/linux/wrappers.odin
index 7a30c3bde..4f6118c80 100644
--- a/core/sys/linux/wrappers.odin
+++ b/core/sys/linux/wrappers.odin
@@ -1,4 +1,4 @@
-//+build linux
+#+build linux
package linux
/// Low 8 bits of the exit code
diff --git a/core/sys/llvm/bit_manipulation.odin b/core/sys/llvm/bit_manipulation.odin
index 39464773d..2e237dd32 100644
--- a/core/sys/llvm/bit_manipulation.odin
+++ b/core/sys/llvm/bit_manipulation.odin
@@ -1,4 +1,5 @@
// Bit Manipulation Intrinsics
+
package sys_llvm
/*
diff --git a/core/sys/llvm/code_generator.odin b/core/sys/llvm/code_generator.odin
index 7d41ed67b..6422976c5 100644
--- a/core/sys/llvm/code_generator.odin
+++ b/core/sys/llvm/code_generator.odin
@@ -1,4 +1,5 @@
// Code Generator Intrinsics
+
package sys_llvm
@(default_calling_convention="none")
diff --git a/core/sys/llvm/standard_c_library.odin b/core/sys/llvm/standard_c_library.odin
index 108d1268e..1818e8462 100644
--- a/core/sys/llvm/standard_c_library.odin
+++ b/core/sys/llvm/standard_c_library.odin
@@ -1,4 +1,5 @@
// Standard C Library Intrinsics
+
package sys_llvm
@(default_calling_convention="none")
diff --git a/core/sys/posix/time.odin b/core/sys/posix/time.odin
index 9b91c9558..5c6ebcf2f 100644
--- a/core/sys/posix/time.odin
+++ b/core/sys/posix/time.odin
@@ -13,7 +13,7 @@ when ODIN_OS == .Darwin {
foreign lib {
/*
- Convert the broken down time in the structure to a string form: Sun Sep 16 01:03:52 1973\n\0
+ Convert the broken down time in the structure to a string form: Sun Sep 16 01:03:52 1973.
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/asctime_r.html ]]
*/
diff --git a/core/sys/posix/unistd.odin b/core/sys/posix/unistd.odin
index 6ed9e5d11..15dbb576f 100644
--- a/core/sys/posix/unistd.odin
+++ b/core/sys/posix/unistd.odin
@@ -112,7 +112,7 @@ foreign lib {
Return configuration-defined string values.
Its use and purpose are similar to sysconf(), but it is used where string values rather than numeric values are returned.
- Returns: 0 (setting errno) if `name` is invalid, need `buf` `len` if buf is `nil`, amount of bytes added to buf otherwise
+ Returns: 0 (setting errno) if `name` is invalid, need `buf` of `len` bytes if `buf` is `nil`, amount of bytes added to buf otherwise
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/confstr.html ]]
*/
diff --git a/core/sys/unix/pthread_darwin.odin b/core/sys/unix/pthread_darwin.odin
index 378fa9309..eb2cc4c9f 100644
--- a/core/sys/unix/pthread_darwin.odin
+++ b/core/sys/unix/pthread_darwin.odin
@@ -1,4 +1,4 @@
-//+build darwin
+#+build darwin
package unix
import "core:c"
diff --git a/core/sys/unix/pthread_freebsd.odin b/core/sys/unix/pthread_freebsd.odin
index 5f4dac289..38fe7db55 100644
--- a/core/sys/unix/pthread_freebsd.odin
+++ b/core/sys/unix/pthread_freebsd.odin
@@ -1,4 +1,4 @@
-//+build freebsd
+#+build freebsd
package unix
import "core:c"
diff --git a/core/sys/unix/pthread_linux.odin b/core/sys/unix/pthread_linux.odin
index f4ded7464..d67add24b 100644
--- a/core/sys/unix/pthread_linux.odin
+++ b/core/sys/unix/pthread_linux.odin
@@ -1,4 +1,4 @@
-//+build linux
+#+build linux
package unix
import "core:c"
diff --git a/core/sys/unix/pthread_openbsd.odin b/core/sys/unix/pthread_openbsd.odin
index 855e7d99c..2c6d9e598 100644
--- a/core/sys/unix/pthread_openbsd.odin
+++ b/core/sys/unix/pthread_openbsd.odin
@@ -1,4 +1,4 @@
-//+build openbsd
+#+build openbsd
package unix
import "core:c"
diff --git a/core/sys/unix/pthread_unix.odin b/core/sys/unix/pthread_unix.odin
index 68a0859b4..43c4866ed 100644
--- a/core/sys/unix/pthread_unix.odin
+++ b/core/sys/unix/pthread_unix.odin
@@ -1,4 +1,4 @@
-//+build linux, darwin, freebsd, openbsd, netbsd, haiku
+#+build linux, darwin, freebsd, openbsd, netbsd, haiku
package unix
foreign import "system:pthread"
@@ -27,6 +27,8 @@ foreign pthread {
pthread_equal :: proc(a, b: pthread_t) -> b32 ---
+ pthread_detach :: proc(t: pthread_t) -> c.int ---
+
sched_get_priority_min :: proc(policy: c.int) -> c.int ---
sched_get_priority_max :: proc(policy: c.int) -> c.int ---
diff --git a/core/sys/unix/sysctl_darwin.odin b/core/sys/unix/sysctl_darwin.odin
index 92222bdfe..32dd720b0 100644
--- a/core/sys/unix/sysctl_darwin.odin
+++ b/core/sys/unix/sysctl_darwin.odin
@@ -1,4 +1,4 @@
-//+build darwin
+#+build darwin
package unix
import "base:intrinsics"
diff --git a/core/sys/unix/sysctl_freebsd.odin b/core/sys/unix/sysctl_freebsd.odin
index 8ca40ef1b..f5fee6c6c 100644
--- a/core/sys/unix/sysctl_freebsd.odin
+++ b/core/sys/unix/sysctl_freebsd.odin
@@ -1,4 +1,4 @@
-//+build freebsd
+#+build freebsd
package unix
import "base:intrinsics"
diff --git a/core/sys/unix/sysctl_openbsd.odin b/core/sys/unix/sysctl_openbsd.odin
index b93e8f9bd..49c9b6336 100644
--- a/core/sys/unix/sysctl_openbsd.odin
+++ b/core/sys/unix/sysctl_openbsd.odin
@@ -1,4 +1,4 @@
-//+build openbsd
+#+build openbsd
package unix
import "core:c"
diff --git a/core/sys/valgrind/callgrind.odin b/core/sys/valgrind/callgrind.odin
index b1ba8c6e9..5cd58753a 100644
--- a/core/sys/valgrind/callgrind.odin
+++ b/core/sys/valgrind/callgrind.odin
@@ -1,4 +1,4 @@
-//+build amd64
+#+build amd64
package sys_valgrind
import "base:intrinsics"
diff --git a/core/sys/valgrind/helgrind.odin b/core/sys/valgrind/helgrind.odin
index 2f0114522..3f5e7a531 100644
--- a/core/sys/valgrind/helgrind.odin
+++ b/core/sys/valgrind/helgrind.odin
@@ -1,4 +1,4 @@
-//+build amd64
+#+build amd64
package sys_valgrind
import "base:intrinsics"
diff --git a/core/sys/valgrind/memcheck.odin b/core/sys/valgrind/memcheck.odin
index dfbe4c3be..bc77444be 100644
--- a/core/sys/valgrind/memcheck.odin
+++ b/core/sys/valgrind/memcheck.odin
@@ -1,4 +1,4 @@
-//+build amd64
+#+build amd64
package sys_valgrind
import "base:intrinsics"
diff --git a/core/sys/valgrind/valgrind.odin b/core/sys/valgrind/valgrind.odin
index d0c46af53..b5c71664f 100644
--- a/core/sys/valgrind/valgrind.odin
+++ b/core/sys/valgrind/valgrind.odin
@@ -1,4 +1,4 @@
-//+build amd64
+#+build amd64
package sys_valgrind
import "base:intrinsics"
diff --git a/core/sys/wasm/README.md b/core/sys/wasm/README.md
new file mode 100644
index 000000000..1aaeaa429
--- /dev/null
+++ b/core/sys/wasm/README.md
@@ -0,0 +1,15 @@
+# WASM on the Web
+
+This directory is for use when targeting the `js_wasm32` target and the packages that rely on it.
+
+The `js_wasm32` target assumes that the WASM output will be ran within a web browser rather than a standalone VM. In the VM cases, either `wasi_wasm32` or `freestanding_wasm32` should be used accordingly.
+
+## Example for `js_wasm32`
+
+```html
+<!-- Copy `core:sys/wasm/js/odin.js` into your web server -->
+<script type="text/javascript" src="odin.js"></script>
+<script type="text/javascript">
+ odin.runWasm(pathToWasm, consolePreElement);
+</script>
+```
diff --git a/core/sys/wasm/js/dom.odin b/core/sys/wasm/js/dom.odin
new file mode 100644
index 000000000..ffc58a9a3
--- /dev/null
+++ b/core/sys/wasm/js/dom.odin
@@ -0,0 +1,93 @@
+#+build js wasm32, js wasm64p32
+package wasm_js_interface
+
+foreign import dom_lib "odin_dom"
+
+@(default_calling_convention="contextless")
+foreign dom_lib {
+ get_element_value_f64 :: proc(id: string) -> f64 ---
+ set_element_value_f64 :: proc(id: string, value: f64) ---
+
+ get_element_key_f64 :: proc(id: string, key: string) -> f64 ---
+ set_element_key_f64 :: proc(id: string, key: string, value: f64) ---
+
+ set_element_value_string :: proc(id: string, value: string) ---
+ get_element_value_string_length :: proc(id: string) -> int ---
+
+ set_element_key_string :: proc(id: string, key: string, value: string) ---
+ get_element_key_string_length :: proc(id: string, key: string, ) -> int ---
+
+ device_pixel_ratio :: proc() -> f64 ---
+
+ window_set_scroll :: proc(x, y: f64) ---
+}
+
+get_element_value_string :: proc "contextless" (id: string, buf: []byte) -> string {
+ @(default_calling_convention="contextless")
+ foreign dom_lib {
+ @(link_name="get_element_value_string")
+ _get_element_value_string :: proc(id: string, buf: []byte) -> int ---
+ }
+ n := _get_element_value_string(id, buf)
+ return string(buf[:n])
+}
+
+get_element_key_string :: proc "contextless" (id: string, key: string, buf: []byte) -> string {
+ @(default_calling_convention="contextless")
+ foreign dom_lib {
+ @(link_name="get_element_key_string")
+ _get_element_key_string :: proc(id: string, key: string, buf: []byte) -> int ---
+ }
+ n := _get_element_key_string(id, key, buf)
+ return string(buf[:n])
+
+}
+
+
+
+get_element_min_max :: proc "contextless" (id: string) -> (min, max: f64) {
+ @(default_calling_convention="contextless")
+ foreign dom_lib {
+ @(link_name="get_element_min_max")
+ _get_element_min_max :: proc(min_max: ^[2]f64, id: string) ---
+ }
+ min_max: [2]f64
+ _get_element_min_max(&min_max, id)
+ return min_max[0], min_max[1]
+}
+
+
+Rect :: struct {
+ x, y, width, height: f64,
+}
+
+get_bounding_client_rect :: proc "contextless" (id: string) -> (rect: Rect) {
+ @(default_calling_convention="contextless")
+ foreign dom_lib {
+ @(link_name="get_bounding_client_rect")
+ _get_bounding_client_rect :: proc(rect: ^Rect, id: string) ---
+ }
+ _get_bounding_client_rect(&rect, id)
+ return
+}
+
+window_get_rect :: proc "contextless" () -> (rect: Rect) {
+ @(default_calling_convention="contextless")
+ foreign dom_lib {
+ @(link_name="window_get_rect")
+ _window_get_rect :: proc(rect: ^Rect) ---
+ }
+ _window_get_rect(&rect)
+ return
+}
+
+window_get_scroll :: proc "contextless" () -> (x, y: f64) {
+ @(default_calling_convention="contextless")
+ foreign dom_lib {
+ @(link_name="window_get_scroll")
+ _window_get_scroll :: proc(scroll: ^[2]f64) ---
+ }
+ scroll: [2]f64
+ _window_get_scroll(&scroll)
+ return scroll.x, scroll.y
+} \ No newline at end of file
diff --git a/core/sys/wasm/js/dom_all_targets.odin b/core/sys/wasm/js/dom_all_targets.odin
new file mode 100644
index 000000000..171deed2f
--- /dev/null
+++ b/core/sys/wasm/js/dom_all_targets.odin
@@ -0,0 +1,36 @@
+#+build !js
+package wasm_js_interface
+
+import "base:runtime"
+
+
+get_element_value_string :: proc "contextless" (id: string, buf: []byte) -> string {
+ context = runtime.default_context()
+ panic("vendor:wasm/js not supported on non JS targets")
+}
+
+
+get_element_min_max :: proc "contextless" (id: string) -> (min, max: f64) {
+ context = runtime.default_context()
+ panic("vendor:wasm/js not supported on non JS targets")
+}
+
+
+Rect :: struct {
+ x, y, width, height: f64,
+}
+
+get_bounding_client_rect :: proc "contextless" (id: string) -> (rect: Rect) {
+ context = runtime.default_context()
+ panic("vendor:wasm/js not supported on non JS targets")
+}
+
+window_get_rect :: proc "contextless" () -> (rect: Rect) {
+ context = runtime.default_context()
+ panic("vendor:wasm/js not supported on non JS targets")
+}
+
+window_get_scroll :: proc "contextless" () -> (x, y: f64) {
+ context = runtime.default_context()
+ panic("vendor:wasm/js not supported on non JS targets")
+}
diff --git a/core/sys/wasm/js/events.odin b/core/sys/wasm/js/events.odin
new file mode 100644
index 000000000..905b3eba9
--- /dev/null
+++ b/core/sys/wasm/js/events.odin
@@ -0,0 +1,418 @@
+#+build js wasm32, js wasm64p32
+package wasm_js_interface
+
+foreign import dom_lib "odin_dom"
+
+Event_Kind :: enum u32 {
+ Invalid,
+
+ Load,
+ Unload,
+ Error,
+ Resize,
+ Visibility_Change,
+ Fullscreen_Change,
+ Fullscreen_Error,
+
+ Click,
+ Double_Click,
+ Mouse_Move,
+ Mouse_Over,
+ Mouse_Out,
+ Mouse_Up,
+ Mouse_Down,
+
+ Key_Up,
+ Key_Down,
+ Key_Press,
+
+ Scroll,
+ Wheel,
+
+ Focus,
+ Focus_In,
+ Focus_Out,
+ Submit,
+ Blur,
+ Change,
+ Hash_Change,
+ Select,
+
+ Animation_Start,
+ Animation_End,
+ Animation_Iteration,
+ Animation_Cancel,
+
+ Copy,
+ Cut,
+ Paste,
+
+ // Drag,
+ // Drag_Start,
+ // Drag_End,
+ // Drag_Enter,
+ // Drag_Leave,
+ // Drag_Over,
+ // Drop,
+
+ Pointer_Cancel,
+ Pointer_Down,
+ Pointer_Enter,
+ Pointer_Leave,
+ Pointer_Move,
+ Pointer_Over,
+ Pointer_Up,
+ Got_Pointer_Capture,
+ Lost_Pointer_Capture,
+ Pointer_Lock_Change,
+ Pointer_Lock_Error,
+
+ Selection_Change,
+ Selection_Start,
+
+ Touch_Cancel,
+ Touch_End,
+ Touch_Move,
+ Touch_Start,
+
+ Transition_Start,
+ Transition_End,
+ Transition_Run,
+ Transition_Cancel,
+
+ Context_Menu,
+
+ Gamepad_Connected,
+ Gamepad_Disconnected,
+
+ Custom,
+
+}
+event_kind_string := [Event_Kind]string{
+ .Invalid = "",
+
+ .Load = "load",
+ .Unload = "unload",
+ .Error = "error",
+ .Resize = "resize",
+ .Visibility_Change = "visibilitychange",
+ .Fullscreen_Change = "fullscreenchange",
+ .Fullscreen_Error = "fullscreenerror",
+
+ .Click = "click",
+ .Double_Click = "dblclick",
+ .Mouse_Move = "mousemove",
+ .Mouse_Over = "mouseover",
+ .Mouse_Out = "mouseout",
+ .Mouse_Up = "mouseup",
+ .Mouse_Down = "mousedown",
+
+ .Key_Up = "keyup",
+ .Key_Down = "keydown",
+ .Key_Press = "keypress",
+
+ .Scroll = "scroll",
+ .Wheel = "wheel",
+
+ .Focus = "focus",
+ .Focus_In = "focusin",
+ .Focus_Out = "focusout",
+ .Submit = "submit",
+ .Blur = "blur",
+ .Change = "change",
+ .Hash_Change = "hashchange",
+ .Select = "select",
+
+ .Animation_Start = "animationstart",
+ .Animation_End = "animationend",
+ .Animation_Iteration = "animationiteration",
+ .Animation_Cancel = "animationcancel",
+
+ .Copy = "copy",
+ .Cut = "cut",
+ .Paste = "paste",
+
+ // .Drag, = "drag",
+ // .Drag_Start, = "dragstart",
+ // .Drag_End, = "dragend",
+ // .Drag_Enter, = "dragenter",
+ // .Drag_Leave, = "dragleave",
+ // .Drag_Over, = "dragover",
+ // .Drop, = "drop",
+
+ .Pointer_Cancel = "pointercancel",
+ .Pointer_Down = "pointerdown",
+ .Pointer_Enter = "pointerenter",
+ .Pointer_Leave = "pointerleave",
+ .Pointer_Move = "pointermove",
+ .Pointer_Over = "pointerover",
+ .Pointer_Up = "pointerup",
+ .Got_Pointer_Capture = "gotpointercapture",
+ .Lost_Pointer_Capture = "lostpointercapture",
+ .Pointer_Lock_Change = "pointerlockchange",
+ .Pointer_Lock_Error = "pointerlockerror",
+
+ .Selection_Change = "selectionchange",
+ .Selection_Start = "selectionstart",
+
+ .Transition_Start = "transitionstart",
+ .Transition_End = "transitionend",
+ .Transition_Run = "transitionrun",
+ .Transition_Cancel = "transitioncancel",
+
+ .Touch_Cancel = "touchcancel",
+ .Touch_End = "touchend",
+ .Touch_Move = "touchmove",
+ .Touch_Start = "touchstart",
+
+ .Context_Menu = "contextmenu",
+
+ .Gamepad_Connected = "gamepadconnected",
+ .Gamepad_Disconnected = "gamepaddisconnected",
+
+ .Custom = "?custom?",
+}
+
+Delta_Mode :: enum u32 {
+ Pixel = 0,
+ Line = 1,
+ Page = 2,
+}
+
+Key_Location :: enum u8 {
+ Standard = 0,
+ Left = 1,
+ Right = 2,
+ Numpad = 3,
+}
+
+KEYBOARD_MAX_KEY_SIZE :: 16
+KEYBOARD_MAX_CODE_SIZE :: 16
+
+GAMEPAD_MAX_ID_SIZE :: 64
+GAMEPAD_MAX_MAPPING_SIZE :: 64
+
+GAMEPAD_MAX_BUTTONS :: 64
+GAMEPAD_MAX_AXES :: 16
+
+Event_Target_Kind :: enum u32 {
+ Element = 0,
+ Document = 1,
+ Window = 2,
+}
+
+Event_Phase :: enum u8 {
+ None = 0,
+ Capturing_Phase = 1,
+ At_Target = 2,
+ Bubbling_Phase = 3,
+}
+
+Event_Option :: enum u8 {
+ Bubbles = 0,
+ Cancelable = 1,
+ Composed = 2,
+}
+Event_Options :: distinct bit_set[Event_Option; u8]
+
+Gamepad_Button :: struct {
+ value: f64,
+ pressed: bool,
+ touched: bool,
+}
+
+Gamepad_State :: struct {
+ id: string,
+ mapping: string,
+ index: int,
+ connected: bool,
+ timestamp: f64,
+
+ button_count: int,
+ axis_count: int,
+ buttons: [GAMEPAD_MAX_BUTTONS]Gamepad_Button `fmt:"v,button_count"`,
+ axes: [GAMEPAD_MAX_AXES]f64 `fmt:"v,axes_count"`,
+
+ _id_len: int `fmt:"-"`,
+ _mapping_len: int `fmt:"-"`,
+ _id_buf: [GAMEPAD_MAX_ID_SIZE]byte `fmt:"-"`,
+ _mapping_buf: [GAMEPAD_MAX_MAPPING_SIZE]byte `fmt:"-"`,
+}
+
+Event :: struct {
+ kind: Event_Kind,
+ target_kind: Event_Target_Kind,
+ current_target_kind: Event_Target_Kind,
+ id: string,
+ timestamp: f64,
+
+ phase: Event_Phase,
+ options: Event_Options,
+ is_composing: bool,
+ is_trusted: bool,
+
+ using data: struct #raw_union #align(8) {
+ scroll: struct {
+ delta: [2]f64,
+ },
+ visibility_change: struct {
+ is_visible: bool,
+ },
+ wheel: struct {
+ delta: [3]f64,
+ delta_mode: Delta_Mode,
+ },
+
+ key: struct {
+ key: string,
+ code: string,
+ location: Key_Location,
+
+ ctrl: bool,
+ shift: bool,
+ alt: bool,
+ meta: bool,
+
+ repeat: bool,
+
+ _key_len: int `fmt:"-"`,
+ _code_len: int `fmt:"-"`,
+ _key_buf: [KEYBOARD_MAX_KEY_SIZE]byte `fmt:"-"`,
+ _code_buf: [KEYBOARD_MAX_KEY_SIZE]byte `fmt:"-"`,
+ },
+
+ mouse: struct {
+ screen: [2]i64,
+ client: [2]i64,
+ offset: [2]i64,
+ page: [2]i64,
+ movement: [2]i64,
+
+ ctrl: bool,
+ shift: bool,
+ alt: bool,
+ meta: bool,
+
+ button: i16,
+ buttons: bit_set[0..<16; u16],
+ },
+
+ gamepad: Gamepad_State,
+ },
+
+
+ user_data: rawptr,
+ callback: proc(e: Event),
+}
+
+@(default_calling_convention="contextless")
+foreign dom_lib {
+ event_stop_propagation :: proc() ---
+ event_stop_immediate_propagation :: proc() ---
+ event_prevent_default :: proc() ---
+ dispatch_custom_event :: proc(id: string, name: string, options := Event_Options{}) -> bool ---
+}
+
+add_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="add_event_listener")
+ _add_event_listener :: proc(id: string, name: string, name_code: Event_Kind, user_data: rawptr, callback: proc "odin" (Event), use_capture: bool) -> bool ---
+ }
+ // TODO: Pointer_Lock_Change etc related stuff for all different browsers
+ 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 {
+ @(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 ---
+ }
+ return _remove_event_listener(id, event_kind_string[kind], user_data, callback)
+}
+
+add_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="add_window_event_listener")
+ _add_window_event_listener :: proc(name: string, name_code: Event_Kind, user_data: rawptr, callback: proc "odin" (Event), use_capture: bool) -> bool ---
+ }
+ 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 {
+ @(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 ---
+ }
+ return _remove_window_event_listener(event_kind_string[kind], user_data, callback)
+}
+
+remove_event_listener_from_event :: proc(e: Event) -> bool {
+ if e.id == "" {
+ return remove_window_event_listener(e.kind, e.user_data, e.callback)
+ }
+ return remove_event_listener(e.id, e.kind, e.user_data, e.callback)
+}
+
+add_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="add_event_listener")
+ _add_event_listener :: proc(id: string, name: string, name_code: Event_Kind, user_data: rawptr, callback: proc "odin" (Event), use_capture: bool) -> bool ---
+ }
+ 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 {
+ @(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 ---
+ }
+ return _remove_event_listener(id, name, user_data, callback)
+}
+
+get_gamepad_state :: proc "contextless" (index: int, s: ^Gamepad_State) -> bool {
+ @(default_calling_convention="contextless")
+ foreign dom_lib {
+ @(link_name="get_gamepad_state")
+ _get_gamepad_state :: proc(index: int, s: ^Gamepad_State) -> bool ---
+ }
+
+ if s == nil {
+ return false
+ }
+ return _get_gamepad_state(index, s)
+}
+
+
+@(export, link_name="odin_dom_do_event_callback")
+do_event_callback :: proc(user_data: rawptr, callback: proc(e: Event)) {
+ @(default_calling_convention="contextless")
+ foreign dom_lib {
+ init_event_raw :: proc(e: ^Event) ---
+ }
+
+ if callback != nil {
+ event := Event{
+ user_data = user_data,
+ callback = callback,
+ }
+
+
+ init_event_raw(&event)
+
+ #partial switch event.kind {
+ case .Key_Up, .Key_Down, .Key_Press:
+ event.key.key = string(event.key._key_buf[:event.key._key_len])
+ event.key.code = string(event.key._code_buf[:event.key._code_len])
+ case .Gamepad_Connected, .Gamepad_Disconnected:
+ event.gamepad.id = string(event.gamepad._id_buf[:event.gamepad._id_len])
+ event.gamepad.mapping = string(event.gamepad._mapping_buf[:event.gamepad._mapping_len])
+ }
+
+ callback(event)
+ }
+} \ No newline at end of file
diff --git a/core/sys/wasm/js/events_all_targets.odin b/core/sys/wasm/js/events_all_targets.odin
new file mode 100644
index 000000000..b7e01ca10
--- /dev/null
+++ b/core/sys/wasm/js/events_all_targets.odin
@@ -0,0 +1,287 @@
+#+build !js
+package wasm_js_interface
+
+
+Event_Kind :: enum u32 {
+ Invalid,
+
+ Load,
+ Unload,
+ Error,
+ Resize,
+ Visibility_Change,
+ Fullscreen_Change,
+ Fullscreen_Error,
+
+ Click,
+ Double_Click,
+ Mouse_Move,
+ Mouse_Over,
+ Mouse_Out,
+ Mouse_Up,
+ Mouse_Down,
+
+ Key_Up,
+ Key_Down,
+ Key_Press,
+
+ Scroll,
+ Wheel,
+
+ Focus,
+ Submit,
+ Blur,
+ Change,
+ Select,
+
+ Animation_Start,
+ Animation_End,
+ Animation_Iteration,
+ Animation_Cancel,
+
+ Copy,
+ Cut,
+ Paste,
+
+ // Drag,
+ // Drag_Start,
+ // Drag_End,
+ // Drag_Enter,
+ // Drag_Leave,
+ // Drag_Over,
+ // Drop,
+
+ Pointer_Cancel,
+ Pointer_Down,
+ Pointer_Enter,
+ Pointer_Leave,
+ Pointer_Move,
+ Pointer_Over,
+ Pointer_Up,
+ Got_Pointer_Capture,
+ Lost_Pointer_Capture,
+ Pointer_Lock_Change,
+ Pointer_Lock_Error,
+
+ Selection_Change,
+ Selection_Start,
+
+ Touch_Cancel,
+ Touch_End,
+ Touch_Move,
+ Touch_Start,
+
+ Transition_Start,
+ Transition_End,
+ Transition_Run,
+ Transition_Cancel,
+
+ Context_Menu,
+
+ Custom,
+
+}
+event_kind_string := [Event_Kind]string{
+ .Invalid = "",
+
+ .Load = "load",
+ .Unload = "unload",
+ .Error = "error",
+ .Resize = "resize",
+ .Visibility_Change = "visibilitychange",
+ .Fullscreen_Change = "fullscreenchange",
+ .Fullscreen_Error = "fullscreenerror",
+
+ .Click = "click",
+ .Double_Click = "dblclick",
+ .Mouse_Move = "mousemove",
+ .Mouse_Over = "mouseover",
+ .Mouse_Out = "mouseout",
+ .Mouse_Up = "mouseup",
+ .Mouse_Down = "mousedown",
+
+ .Key_Up = "keyup",
+ .Key_Down = "keydown",
+ .Key_Press = "keypress",
+
+ .Scroll = "scroll",
+ .Wheel = "wheel",
+
+ .Focus = "focus",
+ .Submit = "submit",
+ .Blur = "blur",
+ .Change = "change",
+ .Select = "select",
+
+ .Animation_Start = "animationstart",
+ .Animation_End = "animationend",
+ .Animation_Iteration = "animationiteration",
+ .Animation_Cancel = "animationcancel",
+
+ .Copy = "copy",
+ .Cut = "cut",
+ .Paste = "paste",
+
+ // .Drag, = "drag",
+ // .Drag_Start, = "dragstart",
+ // .Drag_End, = "dragend",
+ // .Drag_Enter, = "dragenter",
+ // .Drag_Leave, = "dragleave",
+ // .Drag_Over, = "dragover",
+ // .Drop, = "drop",
+
+ .Pointer_Cancel = "pointercancel",
+ .Pointer_Down = "pointerdown",
+ .Pointer_Enter = "pointerenter",
+ .Pointer_Leave = "pointerleave",
+ .Pointer_Move = "pointermove",
+ .Pointer_Over = "pointerover",
+ .Pointer_Up = "pointerup",
+ .Got_Pointer_Capture = "gotpointercapture",
+ .Lost_Pointer_Capture = "lostpointercapture",
+ .Pointer_Lock_Change = "pointerlockchange",
+ .Pointer_Lock_Error = "pointerlockerror",
+
+ .Selection_Change = "selectionchange",
+ .Selection_Start = "selectionstart",
+
+ .Transition_Start = "transitionstart",
+ .Transition_End = "transitionend",
+ .Transition_Run = "transitionrun",
+ .Transition_Cancel = "transitioncancel",
+
+ .Touch_Cancel = "touchcancel",
+ .Touch_End = "touchend",
+ .Touch_Move = "touchmove",
+ .Touch_Start = "touchstart",
+
+ .Context_Menu = "contextmenu",
+
+ .Custom = "?custom?",
+}
+
+Delta_Mode :: enum u32 {
+ Pixel = 0,
+ Line = 1,
+ Page = 2,
+}
+
+Key_Location :: enum u8 {
+ Standard = 0,
+ Left = 1,
+ Right = 2,
+ Numpad = 3,
+}
+
+KEYBOARD_MAX_KEY_SIZE :: 16
+KEYBOARD_MAX_CODE_SIZE :: 16
+
+Event_Target_Kind :: enum u32 {
+ Element = 0,
+ Document = 1,
+ Window = 2,
+}
+
+Event_Phase :: enum u8 {
+ None = 0,
+ Capturing_Phase = 1,
+ At_Target = 2,
+ Bubbling_Phase = 3,
+}
+
+Event_Option :: enum u8 {
+ Bubbles = 0,
+ Cancelable = 1,
+ Composed = 2,
+}
+Event_Options :: distinct bit_set[Event_Option; u8]
+
+Event :: struct {
+ kind: Event_Kind,
+ target_kind: Event_Target_Kind,
+ current_target_kind: Event_Target_Kind,
+ id: string,
+ timestamp: f64,
+
+ phase: Event_Phase,
+ options: Event_Options,
+ is_composing: bool,
+ is_trusted: bool,
+
+ using data: struct #raw_union #align(8) {
+ scroll: struct {
+ delta: [2]f64,
+ },
+ visibility_change: struct {
+ is_visible: bool,
+ },
+ wheel: struct {
+ delta: [3]f64,
+ delta_mode: Delta_Mode,
+ },
+
+ key: struct {
+ key: string,
+ code: string,
+ location: Key_Location,
+
+ ctrl: bool,
+ shift: bool,
+ alt: bool,
+ meta: bool,
+
+ repeat: bool,
+
+ _key_buf: [KEYBOARD_MAX_KEY_SIZE]byte,
+ _code_buf: [KEYBOARD_MAX_KEY_SIZE]byte,
+ },
+
+ mouse: struct {
+ screen: [2]i64,
+ client: [2]i64,
+ offset: [2]i64,
+ page: [2]i64,
+ movement: [2]i64,
+
+ ctrl: bool,
+ shift: bool,
+ alt: bool,
+ meta: bool,
+
+ button: i16,
+ buttons: bit_set[0..<16; u16],
+ },
+ },
+
+
+ user_data: rawptr,
+ callback: proc(e: Event),
+}
+
+
+add_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")
+}
+
+remove_event_listener :: proc(id: string, kind: Event_Kind, user_data: rawptr, callback: proc(e: Event)) -> bool {
+ panic("vendor:wasm/js not supported on non JS targets")
+}
+
+add_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")
+}
+
+remove_window_event_listener :: proc(kind: Event_Kind, user_data: rawptr, callback: proc(e: Event)) -> bool {
+ panic("vendor:wasm/js not supported on non JS targets")
+}
+
+remove_event_listener_from_event :: proc(e: Event) -> bool {
+ panic("vendor:wasm/js not supported on non JS targets")
+}
+
+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 {
+ panic("vendor:wasm/js not supported on non JS targets")
+} \ No newline at end of file
diff --git a/core/sys/wasm/js/general.odin b/core/sys/wasm/js/general.odin
new file mode 100644
index 000000000..4ed2ae298
--- /dev/null
+++ b/core/sys/wasm/js/general.odin
@@ -0,0 +1,12 @@
+#+build js wasm32, js wasm64p32
+package wasm_js_interface
+
+foreign import "odin_env"
+
+@(default_calling_convention="contextless")
+foreign odin_env {
+ trap :: proc() -> ! ---
+ abort :: proc() -> ! ---
+ alert :: proc(msg: string) ---
+ evaluate :: proc(str: string) ---
+} \ No newline at end of file
diff --git a/core/sys/wasm/js/memory_all_targets.odin b/core/sys/wasm/js/memory_all_targets.odin
new file mode 100644
index 000000000..e80d13c0b
--- /dev/null
+++ b/core/sys/wasm/js/memory_all_targets.odin
@@ -0,0 +1,14 @@
+#+build !js
+package wasm_js_interface
+
+import "core:mem"
+
+PAGE_SIZE :: 64 * 1024
+page_alloc :: proc(page_count: int) -> (data: []byte, err: mem.Allocator_Error) {
+ panic("vendor:wasm/js not supported on non-js targets")
+}
+
+page_allocator :: proc() -> mem.Allocator {
+ panic("vendor:wasm/js not supported on non-js targets")
+}
+
diff --git a/core/sys/wasm/js/memory_js.odin b/core/sys/wasm/js/memory_js.odin
new file mode 100644
index 000000000..8232cd0c9
--- /dev/null
+++ b/core/sys/wasm/js/memory_js.odin
@@ -0,0 +1,44 @@
+#+build js wasm32, js wasm64p32
+package wasm_js_interface
+
+import "core:mem"
+import "base:intrinsics"
+
+PAGE_SIZE :: 64 * 1024
+page_alloc :: proc(page_count: int) -> (data: []byte, err: mem.Allocator_Error) {
+ prev_page_count := intrinsics.wasm_memory_grow(0, uintptr(page_count))
+ if prev_page_count < 0 {
+ return nil, .Out_Of_Memory
+ }
+
+ ptr := ([^]u8)(uintptr(prev_page_count) * PAGE_SIZE)
+ return ptr[:page_count * PAGE_SIZE], nil
+}
+
+page_allocator :: proc() -> mem.Allocator {
+ procedure :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
+ size, alignment: int,
+ old_memory: rawptr, old_size: int,
+ location := #caller_location) -> ([]byte, mem.Allocator_Error) {
+ switch mode {
+ case .Alloc, .Alloc_Non_Zeroed:
+ assert(size % PAGE_SIZE == 0)
+ return page_alloc(size/PAGE_SIZE)
+ case .Resize, .Free, .Free_All, .Query_Info, .Resize_Non_Zeroed:
+ return nil, .Mode_Not_Implemented
+ case .Query_Features:
+ set := (^mem.Allocator_Mode_Set)(old_memory)
+ if set != nil {
+ set^ = {.Alloc, .Query_Features}
+ }
+ }
+
+ return nil, nil
+ }
+
+ return {
+ procedure = procedure,
+ data = nil,
+ }
+}
+
diff --git a/core/sys/wasm/js/odin.js b/core/sys/wasm/js/odin.js
new file mode 100644
index 000000000..bf002da74
--- /dev/null
+++ b/core/sys/wasm/js/odin.js
@@ -0,0 +1,1983 @@
+"use strict";
+
+(function() {
+
+function getElement(name) {
+ if (name) {
+ return document.getElementById(name);
+ }
+ return undefined;
+}
+
+function stripNewline(str) {
+ return str.replace(/\n/, ' ')
+}
+
+class WasmMemoryInterface {
+ constructor() {
+ this.memory = null;
+ this.exports = null;
+ this.listenerMap = {};
+
+ // Size (in bytes) of the integer type, should be 4 on `js_wasm32` and 8 on `js_wasm64p32`
+ this.intSize = 4;
+ }
+
+ setIntSize(size) {
+ this.intSize = size;
+ }
+
+ setMemory(memory) {
+ this.memory = memory;
+ }
+
+ setExports(exports) {
+ this.exports = exports;
+ }
+
+ get mem() {
+ return new DataView(this.memory.buffer);
+ }
+
+
+ loadF32Array(addr, len) {
+ let array = new Float32Array(this.memory.buffer, addr, len);
+ return array;
+ }
+ loadF64Array(addr, len) {
+ let array = new Float64Array(this.memory.buffer, addr, len);
+ return array;
+ }
+ loadU32Array(addr, len) {
+ let array = new Uint32Array(this.memory.buffer, addr, len);
+ return array;
+ }
+ loadI32Array(addr, len) {
+ let array = new Int32Array(this.memory.buffer, addr, len);
+ return array;
+ }
+
+
+ loadU8(addr) { return this.mem.getUint8 (addr); }
+ loadI8(addr) { return this.mem.getInt8 (addr); }
+ loadU16(addr) { return this.mem.getUint16 (addr, true); }
+ loadI16(addr) { return this.mem.getInt16 (addr, true); }
+ loadU32(addr) { return this.mem.getUint32 (addr, true); }
+ loadI32(addr) { return this.mem.getInt32 (addr, true); }
+ loadU64(addr) {
+ const lo = this.mem.getUint32(addr + 0, true);
+ const hi = this.mem.getUint32(addr + 4, true);
+ return lo + hi*4294967296;
+ };
+ loadI64(addr) {
+ const lo = this.mem.getUint32(addr + 0, true);
+ const hi = this.mem.getInt32 (addr + 4, true);
+ return lo + hi*4294967296;
+ };
+ loadF32(addr) { return this.mem.getFloat32(addr, true); }
+ loadF64(addr) { return this.mem.getFloat64(addr, true); }
+ loadInt(addr) {
+ if (this.intSize == 8) {
+ return this.loadI64(addr);
+ } else if (this.intSize == 4) {
+ return this.loadI32(addr);
+ } else {
+ throw new Error('Unhandled `intSize`, expected `4` or `8`');
+ }
+ };
+ loadUint(addr) {
+ if (this.intSize == 8) {
+ return this.loadU64(addr);
+ } else if (this.intSize == 4) {
+ return this.loadU32(addr);
+ } else {
+ throw new Error('Unhandled `intSize`, expected `4` or `8`');
+ }
+ };
+ loadPtr(addr) { return this.loadU32(addr); }
+
+ loadB32(addr) {
+ return this.loadU32(addr) != 0;
+ }
+
+ loadBytes(ptr, len) {
+ return new Uint8Array(this.memory.buffer, ptr, Number(len));
+ }
+
+ loadString(ptr, len) {
+ const bytes = this.loadBytes(ptr, Number(len));
+ return new TextDecoder().decode(bytes);
+ }
+
+ loadCstring(ptr) {
+ const start = this.loadPtr(ptr);
+ if (start == 0) {
+ return null;
+ }
+ let len = 0;
+ for (; this.mem.getUint8(start+len) != 0; len += 1) {}
+ return this.loadString(start, len);
+ }
+
+ storeU8(addr, value) { this.mem.setUint8 (addr, value); }
+ storeI8(addr, value) { this.mem.setInt8 (addr, value); }
+ storeU16(addr, value) { this.mem.setUint16 (addr, value, true); }
+ storeI16(addr, value) { this.mem.setInt16 (addr, value, true); }
+ storeU32(addr, value) { this.mem.setUint32 (addr, value, true); }
+ storeI32(addr, value) { this.mem.setInt32 (addr, value, true); }
+ storeU64(addr, value) {
+ this.mem.setUint32(addr + 0, Number(value), true);
+
+ let div = 4294967296;
+ if (typeof value == 'bigint') {
+ div = BigInt(div);
+ }
+
+ this.mem.setUint32(addr + 4, Math.floor(Number(value / div)), true);
+ }
+ storeI64(addr, value) {
+ this.mem.setUint32(addr + 0, Number(value), true);
+
+ let div = 4294967296;
+ if (typeof value == 'bigint') {
+ div = BigInt(div);
+ }
+
+ this.mem.setInt32(addr + 4, Math.floor(Number(value / div)), true);
+ }
+ storeF32(addr, value) { this.mem.setFloat32(addr, value, true); }
+ storeF64(addr, value) { this.mem.setFloat64(addr, value, true); }
+ storeInt(addr, value) {
+ if (this.intSize == 8) {
+ this.storeI64(addr, value);
+ } else if (this.intSize == 4) {
+ this.storeI32(addr, value);
+ } else {
+ throw new Error('Unhandled `intSize`, expected `4` or `8`');
+ }
+ }
+ storeUint(addr, value) {
+ if (this.intSize == 8) {
+ this.storeU64(addr, value);
+ } else if (this.intSize == 4) {
+ this.storeU32(addr, value);
+ } else {
+ throw new Error('Unhandled `intSize`, expected `4` or `8`');
+ }
+ }
+
+ // Returned length might not be the same as `value.length` if non-ascii strings are given.
+ storeString(addr, value) {
+ const src = new TextEncoder().encode(value);
+ const dst = new Uint8Array(this.memory.buffer, addr, src.length);
+ dst.set(src);
+ return src.length;
+ }
+};
+
+class WebGLInterface {
+ constructor(wasmMemoryInterface) {
+ this.wasmMemoryInterface = wasmMemoryInterface;
+ this.ctxElement = null;
+ this.ctx = null;
+ this.ctxVersion = 1.0;
+ this.counter = 1;
+ this.lastError = 0;
+ this.buffers = [];
+ this.mappedBuffers = {};
+ this.programs = [];
+ this.framebuffers = [];
+ this.renderbuffers = [];
+ this.textures = [];
+ this.uniforms = [];
+ this.shaders = [];
+ this.vaos = [];
+ this.contexts = [];
+ this.currentContext = null;
+ this.offscreenCanvases = {};
+ this.timerQueriesEXT = [];
+ this.queries = [];
+ this.samplers = [];
+ this.transformFeedbacks = [];
+ this.syncs = [];
+ this.programInfos = {};
+ }
+
+ get mem() {
+ return this.wasmMemoryInterface
+ }
+
+ setCurrentContext(element, contextSettings) {
+ if (!element) {
+ return false;
+ }
+ if (this.ctxElement == element) {
+ return true;
+ }
+
+ contextSettings = contextSettings ?? {};
+ this.ctx = element.getContext("webgl2", contextSettings) || element.getContext("webgl", contextSettings);
+ if (!this.ctx) {
+ return false;
+ }
+ this.ctxElement = element;
+ if (this.ctx.getParameter(0x1F02).indexOf("WebGL 2.0") !== -1) {
+ this.ctxVersion = 2.0;
+ } else {
+ this.ctxVersion = 1.0;
+ }
+ return true;
+ }
+
+ assertWebGL2() {
+ if (this.ctxVersion < 2) {
+ throw new Error("WebGL2 procedure called in a canvas without a WebGL2 context");
+ }
+ }
+ getNewId(table) {
+ for (var ret = this.counter++, i = table.length; i < ret; i++) {
+ table[i] = null;
+ }
+ return ret;
+ }
+ recordError(errorCode) {
+ this.lastError || (this.lastError = errorCode);
+ }
+ populateUniformTable(program) {
+ let p = this.programs[program];
+ this.programInfos[program] = {
+ uniforms: {},
+ maxUniformLength: 0,
+ maxAttributeLength: -1,
+ maxUniformBlockNameLength: -1,
+ };
+ for (let ptable = this.programInfos[program], utable = ptable.uniforms, numUniforms = this.ctx.getProgramParameter(p, this.ctx.ACTIVE_UNIFORMS), i = 0; i < numUniforms; ++i) {
+ let u = this.ctx.getActiveUniform(p, i);
+ let name = u.name;
+ if (ptable.maxUniformLength = Math.max(ptable.maxUniformLength, name.length + 1), name.indexOf("]", name.length - 1) !== -1) {
+ name = name.slice(0, name.lastIndexOf("["));
+ }
+ let loc = this.ctx.getUniformLocation(p, name);
+ if (loc !== null) {
+ let id = this.getNewId(this.uniforms);
+ utable[name] = [u.size, id], this.uniforms[id] = loc;
+ for (let j = 1; j < u.size; ++j) {
+ let n = name + "[" + j + "]";
+ let loc = this.ctx.getUniformLocation(p, n);
+ let id = this.getNewId(this.uniforms);
+ this.uniforms[id] = loc;
+ }
+ }
+ }
+ }
+ getSource(shader, strings_ptr, strings_length) {
+ const stringSize = this.mem.intSize*2;
+ let source = "";
+ for (let i = 0; i < strings_length; i++) {
+ let ptr = this.mem.loadPtr(strings_ptr + i*stringSize);
+ let len = this.mem.loadPtr(strings_ptr + i*stringSize + 4);
+ let str = this.mem.loadString(ptr, len);
+ source += str;
+ }
+ return source;
+ }
+
+ getWebGL1Interface() {
+ return {
+ SetCurrentContextById: (name_ptr, name_len) => {
+ let name = this.mem.loadString(name_ptr, name_len);
+ let element = getElement(name);
+ return this.setCurrentContext(element, {alpha: true, antialias: true, depth: true, premultipliedAlpha: true});
+ },
+ CreateCurrentContextById: (name_ptr, name_len, attributes) => {
+ let name = this.mem.loadString(name_ptr, name_len);
+ let element = getElement(name);
+
+ let contextSettings = {
+ alpha: !(attributes & (1<<0)),
+ antialias: !(attributes & (1<<1)),
+ depth: !(attributes & (1<<2)),
+ failIfMajorPerformanceCaveat: !!(attributes & (1<<3)),
+ premultipliedAlpha: !(attributes & (1<<4)),
+ preserveDrawingBuffer: !!(attributes & (1<<5)),
+ stencil: !!(attributes & (1<<6)),
+ desynchronized: !!(attributes & (1<<7)),
+ };
+
+ return this.setCurrentContext(element, contextSettings);
+ },
+ GetCurrentContextAttributes: () => {
+ if (!this.ctx) {
+ return 0;
+ }
+ let attrs = this.ctx.getContextAttributes();
+ let res = 0;
+ if (!attrs.alpha) res |= 1<<0;
+ if (!attrs.antialias) res |= 1<<1;
+ if (!attrs.depth) res |= 1<<2;
+ if (attrs.failIfMajorPerformanceCaveat) res |= 1<<3;
+ if (!attrs.premultipliedAlpha) res |= 1<<4;
+ if (attrs.preserveDrawingBuffer) res |= 1<<5;
+ if (attrs.stencil) res |= 1<<6;
+ if (attrs.desynchronized) res |= 1<<7;
+ return res;
+ },
+
+ DrawingBufferWidth: () => this.ctx.drawingBufferWidth,
+ DrawingBufferHeight: () => this.ctx.drawingBufferHeight,
+
+ IsExtensionSupported: (name_ptr, name_len) => {
+ let name = this.mem.loadString(name_ptr, name_len);
+ let extensions = this.ctx.getSupportedExtensions();
+ return extensions.indexOf(name) !== -1
+ },
+
+
+ GetError: () => {
+ let err = this.lastError;
+ this.recordError(0);
+ if (err) {
+ return err;
+ }
+ return this.ctx.getError();
+ },
+
+ GetWebGLVersion: (major_ptr, minor_ptr) => {
+ let version = this.ctx.getParameter(0x1F02);
+ if (version.indexOf("WebGL 2.0") !== -1) {
+ this.mem.storeI32(major_ptr, 2);
+ this.mem.storeI32(minor_ptr, 0);
+ return;
+ }
+
+ this.mem.storeI32(major_ptr, 1);
+ this.mem.storeI32(minor_ptr, 0);
+ },
+ GetESVersion: (major_ptr, minor_ptr) => {
+ let version = this.ctx.getParameter(0x1F02);
+ if (version.indexOf("OpenGL ES 3.0") !== -1) {
+ this.mem.storeI32(major_ptr, 3);
+ this.mem.storeI32(minor_ptr, 0);
+ return;
+ }
+
+ this.mem.storeI32(major_ptr, 2);
+ this.mem.storeI32(minor_ptr, 0);
+ },
+
+
+ ActiveTexture: (x) => {
+ this.ctx.activeTexture(x);
+ },
+ AttachShader: (program, shader) => {
+ this.ctx.attachShader(this.programs[program], this.shaders[shader]);
+ },
+ BindAttribLocation: (program, index, name_ptr, name_len) => {
+ let name = this.mem.loadString(name_ptr, name_len);
+ this.ctx.bindAttribLocation(this.programs[program], index, name)
+ },
+ BindBuffer: (target, buffer) => {
+ let bufferObj = buffer ? this.buffers[buffer] : null;
+ if (target == 35051) {
+ this.ctx.currentPixelPackBufferBinding = buffer;
+ } else {
+ if (target == 35052) {
+ this.ctx.currentPixelUnpackBufferBinding = buffer;
+ }
+ this.ctx.bindBuffer(target, bufferObj)
+ }
+ },
+ BindFramebuffer: (target, framebuffer) => {
+ this.ctx.bindFramebuffer(target, framebuffer ? this.framebuffers[framebuffer] : null)
+ },
+ BindTexture: (target, texture) => {
+ this.ctx.bindTexture(target, texture ? this.textures[texture] : null)
+ },
+ BlendColor: (red, green, blue, alpha) => {
+ this.ctx.blendColor(red, green, blue, alpha);
+ },
+ BlendEquation: (mode) => {
+ this.ctx.blendEquation(mode);
+ },
+ BlendFunc: (sfactor, dfactor) => {
+ this.ctx.blendFunc(sfactor, dfactor);
+ },
+ BlendFuncSeparate: (srcRGB, dstRGB, srcAlpha, dstAlpha) => {
+ this.ctx.blendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
+ },
+
+
+ BufferData: (target, size, data, usage) => {
+ if (data) {
+ this.ctx.bufferData(target, this.mem.loadBytes(data, size), usage);
+ } else {
+ this.ctx.bufferData(target, size, usage);
+ }
+ },
+ BufferSubData: (target, offset, size, data) => {
+ if (data) {
+ this.ctx.bufferSubData(target, offset, this.mem.loadBytes(data, size));
+ } else {
+ this.ctx.bufferSubData(target, offset, null);
+ }
+ },
+
+
+ Clear: (x) => {
+ this.ctx.clear(x);
+ },
+ ClearColor: (r, g, b, a) => {
+ this.ctx.clearColor(r, g, b, a);
+ },
+ ClearDepth: (x) => {
+ this.ctx.clearDepth(x);
+ },
+ ClearStencil: (x) => {
+ this.ctx.clearStencil(x);
+ },
+ ColorMask: (r, g, b, a) => {
+ this.ctx.colorMask(!!r, !!g, !!b, !!a);
+ },
+ CompileShader: (shader) => {
+ this.ctx.compileShader(this.shaders[shader]);
+ },
+
+
+ CompressedTexImage2D: (target, level, internalformat, width, height, border, imageSize, data) => {
+ if (data) {
+ this.ctx.compressedTexImage2D(target, level, internalformat, width, height, border, this.mem.loadBytes(data, imageSize));
+ } else {
+ this.ctx.compressedTexImage2D(target, level, internalformat, width, height, border, null);
+ }
+ },
+ CompressedTexSubImage2D: (target, level, xoffset, yoffset, width, height, format, imageSize, data) => {
+ if (data) {
+ this.ctx.compressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, this.mem.loadBytes(data, imageSize));
+ } else {
+ this.ctx.compressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, null);
+ }
+ },
+
+ CopyTexImage2D: (target, level, internalformat, x, y, width, height, border) => {
+ this.ctx.copyTexImage2D(target, level, internalformat, x, y, width, height, border);
+ },
+ CopyTexSubImage2D: (target, level, xoffset, yoffset, x, y, width, height) => {
+ this.ctx.copyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
+ },
+
+
+ CreateBuffer: () => {
+ let buffer = this.ctx.createBuffer();
+ if (!buffer) {
+ this.recordError(1282);
+ return 0;
+ }
+ let id = this.getNewId(this.buffers);
+ buffer.name = id
+ this.buffers[id] = buffer;
+ return id;
+ },
+ CreateFramebuffer: () => {
+ let buffer = this.ctx.createFramebuffer();
+ let id = this.getNewId(this.framebuffers);
+ buffer.name = id
+ this.framebuffers[id] = buffer;
+ return id;
+ },
+ CreateProgram: () => {
+ let program = this.ctx.createProgram();
+ let id = this.getNewId(this.programs);
+ program.name = id;
+ this.programs[id] = program;
+ return id;
+ },
+ CreateRenderbuffer: () => {
+ let buffer = this.ctx.createRenderbuffer();
+ let id = this.getNewId(this.renderbuffers);
+ buffer.name = id;
+ this.renderbuffers[id] = buffer;
+ return id;
+ },
+ CreateShader: (shaderType) => {
+ let shader = this.ctx.createShader(shaderType);
+ let id = this.getNewId(this.shaders);
+ shader.name = id;
+ this.shaders[id] = shader;
+ return id;
+ },
+ CreateTexture: () => {
+ let texture = this.ctx.createTexture();
+ if (!texture) {
+ this.recordError(1282)
+ return 0;
+ }
+ let id = this.getNewId(this.textures);
+ texture.name = id;
+ this.textures[id] = texture;
+ return id;
+ },
+
+
+ CullFace: (mode) => {
+ this.ctx.cullFace(mode);
+ },
+
+
+ DeleteBuffer: (id) => {
+ let obj = this.buffers[id];
+ if (obj && id != 0) {
+ this.ctx.deleteBuffer(obj);
+ this.buffers[id] = null;
+ }
+ },
+ DeleteFramebuffer: (id) => {
+ let obj = this.framebuffers[id];
+ if (obj && id != 0) {
+ this.ctx.deleteFramebuffer(obj);
+ this.framebuffers[id] = null;
+ }
+ },
+ DeleteProgram: (id) => {
+ let obj = this.programs[id];
+ if (obj && id != 0) {
+ this.ctx.deleteProgram(obj);
+ this.programs[id] = null;
+ }
+ },
+ DeleteRenderbuffer: (id) => {
+ let obj = this.renderbuffers[id];
+ if (obj && id != 0) {
+ this.ctx.deleteRenderbuffer(obj);
+ this.renderbuffers[id] = null;
+ }
+ },
+ DeleteShader: (id) => {
+ let obj = this.shaders[id];
+ if (obj && id != 0) {
+ this.ctx.deleteShader(obj);
+ this.shaders[id] = null;
+ }
+ },
+ DeleteTexture: (id) => {
+ let obj = this.textures[id];
+ if (obj && id != 0) {
+ this.ctx.deleteTexture(obj);
+ this.textures[id] = null;
+ }
+ },
+
+
+ DepthFunc: (func) => {
+ this.ctx.depthFunc(func);
+ },
+ DepthMask: (flag) => {
+ this.ctx.depthMask(!!flag);
+ },
+ DepthRange: (zNear, zFar) => {
+ this.ctx.depthRange(zNear, zFar);
+ },
+ DetachShader: (program, shader) => {
+ this.ctx.detachShader(this.programs[program], this.shaders[shader]);
+ },
+ Disable: (cap) => {
+ this.ctx.disable(cap);
+ },
+ DisableVertexAttribArray: (index) => {
+ this.ctx.disableVertexAttribArray(index);
+ },
+ DrawArrays: (mode, first, count) => {
+ this.ctx.drawArrays(mode, first, count);
+ },
+ DrawElements: (mode, count, type, indices) => {
+ this.ctx.drawElements(mode, count, type, indices);
+ },
+
+
+ Enable: (cap) => {
+ this.ctx.enable(cap);
+ },
+ EnableVertexAttribArray: (index) => {
+ this.ctx.enableVertexAttribArray(index);
+ },
+ Finish: () => {
+ this.ctx.finish();
+ },
+ Flush: () => {
+ this.ctx.flush();
+ },
+ FramebufferRenderbuffer: (target, attachment, renderbuffertarget, renderbuffer) => {
+ this.ctx.framebufferRenderbuffer(target, attachment, renderbuffertarget, this.renderbuffers[renderbuffer]);
+ },
+ FramebufferTexture2D: (target, attachment, textarget, texture, level) => {
+ this.ctx.framebufferTexture2D(target, attachment, textarget, this.textures[texture], level);
+ },
+ FrontFace: (mode) => {
+ this.ctx.frontFace(mode);
+ },
+
+
+ GenerateMipmap: (target) => {
+ this.ctx.generateMipmap(target);
+ },
+
+
+ GetAttribLocation: (program, name_ptr, name_len) => {
+ let name = this.mem.loadString(name_ptr, name_len);
+ return this.ctx.getAttribLocation(this.programs[program], name);
+ },
+
+
+ GetParameter: (pname) => {
+ return this.ctx.getParameter(pname);
+ },
+ GetProgramParameter: (program, pname) => {
+ return this.ctx.getProgramParameter(this.programs[program], pname)
+ },
+ GetProgramInfoLog: (program, buf_ptr, buf_len, length_ptr) => {
+ let log = this.ctx.getProgramInfoLog(this.programs[program]);
+ if (log === null) {
+ log = "(unknown error)";
+ }
+ if (buf_len > 0 && buf_ptr) {
+ let n = Math.min(buf_len, log.length);
+ log = log.substring(0, n);
+ this.mem.loadBytes(buf_ptr, buf_len).set(new TextEncoder().encode(log))
+
+ this.mem.storeInt(length_ptr, n);
+ }
+ },
+ GetShaderInfoLog: (shader, buf_ptr, buf_len, length_ptr) => {
+ let log = this.ctx.getShaderInfoLog(this.shaders[shader]);
+ if (log === null) {
+ log = "(unknown error)";
+ }
+ if (buf_len > 0 && buf_ptr) {
+ let n = Math.min(buf_len, log.length);
+ log = log.substring(0, n);
+ this.mem.loadBytes(buf_ptr, buf_len).set(new TextEncoder().encode(log))
+
+ this.mem.storeInt(length_ptr, n);
+ }
+ },
+ GetShaderiv: (shader, pname, p) => {
+ if (p) {
+ if (pname == 35716) {
+ let log = this.ctx.getShaderInfoLog(this.shaders[shader]);
+ if (log === null) {
+ log = "(unknown error)";
+ }
+ this.mem.storeInt(p, log.length+1);
+ } else if (pname == 35720) {
+ let source = this.ctx.getShaderSource(this.shaders[shader]);
+ let sourceLength = (source === null || source.length == 0) ? 0 : source.length+1;
+ this.mem.storeInt(p, sourceLength);
+ } else {
+ let param = this.ctx.getShaderParameter(this.shaders[shader], pname);
+ this.mem.storeI32(p, param);
+ }
+ } else {
+ this.recordError(1281);
+ }
+ },
+
+
+ GetUniformLocation: (program, name_ptr, name_len) => {
+ let name = this.mem.loadString(name_ptr, name_len);
+ let arrayOffset = 0;
+ if (name.indexOf("]", name.length - 1) !== -1) {
+ let ls = name.lastIndexOf("["),
+ arrayIndex = name.slice(ls + 1, -1);
+ if (arrayIndex.length > 0 && (arrayOffset = parseInt(arrayIndex)) < 0) {
+ return -1;
+ }
+ name = name.slice(0, ls)
+ }
+ var ptable = this.programInfos[program];
+ if (!ptable) {
+ return -1;
+ }
+ var uniformInfo = ptable.uniforms[name];
+ return (uniformInfo && arrayOffset < uniformInfo[0]) ? uniformInfo[1] + arrayOffset : -1
+ },
+
+
+ GetVertexAttribOffset: (index, pname) => {
+ return this.ctx.getVertexAttribOffset(index, pname);
+ },
+
+
+ Hint: (target, mode) => {
+ this.ctx.hint(target, mode);
+ },
+
+
+ IsBuffer: (buffer) => this.ctx.isBuffer(this.buffers[buffer]),
+ IsEnabled: (cap) => this.ctx.isEnabled(cap),
+ IsFramebuffer: (framebuffer) => this.ctx.isFramebuffer(this.framebuffers[framebuffer]),
+ IsProgram: (program) => this.ctx.isProgram(this.programs[program]),
+ IsRenderbuffer: (renderbuffer) => this.ctx.isRenderbuffer(this.renderbuffers[renderbuffer]),
+ IsShader: (shader) => this.ctx.isShader(this.shaders[shader]),
+ IsTexture: (texture) => this.ctx.isTexture(this.textures[texture]),
+
+ LineWidth: (width) => {
+ this.ctx.lineWidth(width);
+ },
+ LinkProgram: (program) => {
+ this.ctx.linkProgram(this.programs[program]);
+ this.programInfos[program] = null;
+ this.populateUniformTable(program);
+ },
+ PixelStorei: (pname, param) => {
+ this.ctx.pixelStorei(pname, param);
+ },
+ PolygonOffset: (factor, units) => {
+ this.ctx.polygonOffset(factor, units);
+ },
+
+
+ ReadnPixels: (x, y, width, height, format, type, bufSize, data) => {
+ this.ctx.readPixels(x, y, width, height, format, type, this.mem.loadBytes(data, bufSize));
+ },
+ RenderbufferStorage: (target, internalformat, width, height) => {
+ this.ctx.renderbufferStorage(target, internalformat, width, height);
+ },
+ SampleCoverage: (value, invert) => {
+ this.ctx.sampleCoverage(value, !!invert);
+ },
+ Scissor: (x, y, width, height) => {
+ this.ctx.scissor(x, y, width, height);
+ },
+ ShaderSource: (shader, strings_ptr, strings_length) => {
+ let source = this.getSource(shader, strings_ptr, strings_length);
+ this.ctx.shaderSource(this.shaders[shader], source);
+ },
+
+ StencilFunc: (func, ref, mask) => {
+ this.ctx.stencilFunc(func, ref, mask);
+ },
+ StencilFuncSeparate: (face, func, ref, mask) => {
+ this.ctx.stencilFuncSeparate(face, func, ref, mask);
+ },
+ StencilMask: (mask) => {
+ this.ctx.stencilMask(mask);
+ },
+ StencilMaskSeparate: (face, mask) => {
+ this.ctx.stencilMaskSeparate(face, mask);
+ },
+ StencilOp: (fail, zfail, zpass) => {
+ this.ctx.stencilOp(fail, zfail, zpass);
+ },
+ StencilOpSeparate: (face, fail, zfail, zpass) => {
+ this.ctx.stencilOpSeparate(face, fail, zfail, zpass);
+ },
+
+
+ TexImage2D: (target, level, internalformat, width, height, border, format, type, size, data) => {
+ if (data) {
+ this.ctx.texImage2D(target, level, internalformat, width, height, border, format, type, this.mem.loadBytes(data, size));
+ } else {
+ this.ctx.texImage2D(target, level, internalformat, width, height, border, format, type, null);
+ }
+ },
+ TexParameterf: (target, pname, param) => {
+ this.ctx.texParameterf(target, pname, param);
+ },
+ TexParameteri: (target, pname, param) => {
+ this.ctx.texParameteri(target, pname, param);
+ },
+ TexSubImage2D: (target, level, xoffset, yoffset, width, height, format, type, size, data) => {
+ this.ctx.texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, this.mem.loadBytes(data, size));
+ },
+
+
+ Uniform1f: (location, v0) => { this.ctx.uniform1f(this.uniforms[location], v0); },
+ Uniform2f: (location, v0, v1) => { this.ctx.uniform2f(this.uniforms[location], v0, v1); },
+ Uniform3f: (location, v0, v1, v2) => { this.ctx.uniform3f(this.uniforms[location], v0, v1, v2); },
+ Uniform4f: (location, v0, v1, v2, v3) => { this.ctx.uniform4f(this.uniforms[location], v0, v1, v2, v3); },
+
+ Uniform1i: (location, v0) => { this.ctx.uniform1i(this.uniforms[location], v0); },
+ Uniform2i: (location, v0, v1) => { this.ctx.uniform2i(this.uniforms[location], v0, v1); },
+ Uniform3i: (location, v0, v1, v2) => { this.ctx.uniform3i(this.uniforms[location], v0, v1, v2); },
+ Uniform4i: (location, v0, v1, v2, v3) => { this.ctx.uniform4i(this.uniforms[location], v0, v1, v2, v3); },
+
+ UniformMatrix2fv: (location, addr) => {
+ let array = this.mem.loadF32Array(addr, 2*2);
+ this.ctx.uniformMatrix2fv(this.uniforms[location], false, array);
+ },
+ UniformMatrix3fv: (location, addr) => {
+ let array = this.mem.loadF32Array(addr, 3*3);
+ this.ctx.uniformMatrix3fv(this.uniforms[location], false, array);
+ },
+ UniformMatrix4fv: (location, addr) => {
+ let array = this.mem.loadF32Array(addr, 4*4);
+ this.ctx.uniformMatrix4fv(this.uniforms[location], false, array);
+ },
+
+ UseProgram: (program) => {
+ if (program) this.ctx.useProgram(this.programs[program]);
+ },
+ ValidateProgram: (program) => {
+ if (program) this.ctx.validateProgram(this.programs[program]);
+ },
+
+
+ VertexAttrib1f: (index, x) => {
+ this.ctx.vertexAttrib1f(index, x);
+ },
+ VertexAttrib2f: (index, x, y) => {
+ this.ctx.vertexAttrib2f(index, x, y);
+ },
+ VertexAttrib3f: (index, x, y, z) => {
+ this.ctx.vertexAttrib3f(index, x, y, z);
+ },
+ VertexAttrib4f: (index, x, y, z, w) => {
+ this.ctx.vertexAttrib4f(index, x, y, z, w);
+ },
+ VertexAttribPointer: (index, size, type, normalized, stride, ptr) => {
+ this.ctx.vertexAttribPointer(index, size, type, !!normalized, stride, ptr);
+ },
+
+ Viewport: (x, y, w, h) => {
+ this.ctx.viewport(x, y, w, h);
+ },
+ };
+ }
+
+ getWebGL2Interface() {
+ return {
+ /* Buffer objects */
+ CopyBufferSubData: (readTarget, writeTarget, readOffset, writeOffset, size) => {
+ this.assertWebGL2();
+ this.ctx.copyBufferSubData(readTarget, writeTarget, readOffset, writeOffset, size);
+ },
+ GetBufferSubData: (target, srcByteOffset, dst_buffer_ptr, dst_buffer_len, dstOffset, length) => {
+ this.assertWebGL2();
+ this.ctx.getBufferSubData(target, srcByteOffset, this.mem.loadBytes(dst_buffer_ptr, dst_buffer_len), dstOffset, length);
+ },
+
+ /* Framebuffer objects */
+ BlitFramebuffer: (srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter) => {
+ this.assertWebGL2();
+ this.ctx.blitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
+ },
+ FramebufferTextureLayer: (target, attachment, texture, level, layer) => {
+ this.assertWebGL2();
+ this.ctx.framebufferTextureLayer(target, attachment, this.textures[texture], level, layer);
+ },
+ InvalidateFramebuffer: (target, attachments_ptr, attachments_len) => {
+ this.assertWebGL2();
+ let attachments = this.mem.loadU32Array(attachments_ptr, attachments_len);
+ this.ctx.invalidateFramebuffer(target, attachments);
+ },
+ InvalidateSubFramebuffer: (target, attachments_ptr, attachments_len, x, y, width, height) => {
+ this.assertWebGL2();
+ let attachments = this.mem.loadU32Array(attachments_ptr, attachments_len);
+ this.ctx.invalidateSubFramebuffer(target, attachments, x, y, width, height);
+ },
+ ReadBuffer: (src) => {
+ this.assertWebGL2();
+ this.ctx.readBuffer(src);
+ },
+
+ /* Renderbuffer objects */
+ RenderbufferStorageMultisample: (target, samples, internalformat, width, height) => {
+ this.assertWebGL2();
+ this.ctx.renderbufferStorageMultisample(target, samples, internalformat, width, height);
+ },
+
+ /* Texture objects */
+
+ TexStorage3D: (target, levels, internalformat, width, height, depth) => {
+ this.assertWebGL2();
+ this.ctx.texStorage3D(target, levels, internalformat, width, height, depth);
+ },
+ TexImage3D: (target, level, internalformat, width, height, depth, border, format, type, size, data) => {
+ this.assertWebGL2();
+ if (data) {
+ this.ctx.texImage3D(target, level, internalformat, width, height, depth, border, format, type, this.mem.loadBytes(data, size));
+ } else {
+ this.ctx.texImage3D(target, level, internalformat, width, height, depth, border, format, type, null);
+ }
+ },
+ TexSubImage3D: (target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, size, data) => {
+ this.assertWebGL2();
+ this.ctx.texSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, this.mem.loadBytes(data, size));
+ },
+ CompressedTexImage3D: (target, level, internalformat, width, height, depth, border, imageSize, data) => {
+ this.assertWebGL2();
+ if (data) {
+ this.ctx.compressedTexImage3D(target, level, internalformat, width, height, depth, border, this.mem.loadBytes(data, imageSize));
+ } else {
+ this.ctx.compressedTexImage3D(target, level, internalformat, width, height, depth, border, null);
+ }
+ },
+ CompressedTexSubImage3D: (target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data) => {
+ this.assertWebGL2();
+ if (data) {
+ this.ctx.compressedTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, this.mem.loadBytes(data, imageSize));
+ } else {
+ this.ctx.compressedTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, null);
+ }
+ },
+
+ CopyTexSubImage3D: (target, level, xoffset, yoffset, zoffset, x, y, width, height) => {
+ this.assertWebGL2();
+ this.ctx.copyTexSubImage3D(target, level, xoffset, yoffset, zoffset, x, y, width, height);
+ },
+
+ /* Programs and shaders */
+ GetFragDataLocation: (program, name_ptr, name_len) => {
+ this.assertWebGL2();
+ return this.ctx.getFragDataLocation(this.programs[program], this.mem.loadString(name_ptr, name_len));
+ },
+
+ /* Uniforms */
+ Uniform1ui: (location, v0) => {
+ this.assertWebGL2();
+ this.ctx.uniform1ui(this.uniforms[location], v0);
+ },
+ Uniform2ui: (location, v0, v1) => {
+ this.assertWebGL2();
+ this.ctx.uniform2ui(this.uniforms[location], v0, v1);
+ },
+ Uniform3ui: (location, v0, v1, v2) => {
+ this.assertWebGL2();
+ this.ctx.uniform3ui(this.uniforms[location], v0, v1, v2);
+ },
+ Uniform4ui: (location, v0, v1, v2, v3) => {
+ this.assertWebGL2();
+ this.ctx.uniform4ui(this.uniforms[location], v0, v1, v2, v3);
+ },
+
+ UniformMatrix3x2fv: (location, addr) => {
+ this.assertWebGL2();
+ let array = this.mem.loadF32Array(addr, 3*2);
+ this.ctx.uniformMatrix3x2fv(this.uniforms[location], false, array);
+ },
+ UniformMatrix4x2fv: (location, addr) => {
+ this.assertWebGL2();
+ let array = this.mem.loadF32Array(addr, 4*2);
+ this.ctx.uniformMatrix4x2fv(this.uniforms[location], false, array);
+ },
+ UniformMatrix2x3fv: (location, addr) => {
+ this.assertWebGL2();
+ let array = this.mem.loadF32Array(addr, 2*3);
+ this.ctx.uniformMatrix2x3fv(this.uniforms[location], false, array);
+ },
+ UniformMatrix4x3fv: (location, addr) => {
+ this.assertWebGL2();
+ let array = this.mem.loadF32Array(addr, 4*3);
+ this.ctx.uniformMatrix4x3fv(this.uniforms[location], false, array);
+ },
+ UniformMatrix2x4fv: (location, addr) => {
+ this.assertWebGL2();
+ let array = this.mem.loadF32Array(addr, 2*4);
+ this.ctx.uniformMatrix2x4fv(this.uniforms[location], false, array);
+ },
+ UniformMatrix3x4fv: (location, addr) => {
+ this.assertWebGL2();
+ let array = this.mem.loadF32Array(addr, 3*4);
+ this.ctx.uniformMatrix3x4fv(this.uniforms[location], false, array);
+ },
+
+ /* Vertex attribs */
+ VertexAttribI4i: (index, x, y, z, w) => {
+ this.assertWebGL2();
+ this.ctx.vertexAttribI4i(index, x, y, z, w);
+ },
+ VertexAttribI4ui: (index, x, y, z, w) => {
+ this.assertWebGL2();
+ this.ctx.vertexAttribI4ui(index, x, y, z, w);
+ },
+ VertexAttribIPointer: (index, size, type, stride, offset) => {
+ this.assertWebGL2();
+ this.ctx.vertexAttribIPointer(index, size, type, stride, offset);
+ },
+
+ /* Writing to the drawing buffer */
+ VertexAttribDivisor: (index, divisor) => {
+ this.assertWebGL2();
+ this.ctx.vertexAttribDivisor(index, divisor);
+ },
+ DrawArraysInstanced: (mode, first, count, instanceCount) => {
+ this.assertWebGL2();
+ this.ctx.drawArraysInstanced(mode, first, count, instanceCount);
+ },
+ DrawElementsInstanced: (mode, count, type, offset, instanceCount) => {
+ this.assertWebGL2();
+ this.ctx.drawElementsInstanced(mode, count, type, offset, instanceCount);
+ },
+ DrawRangeElements: (mode, start, end, count, type, offset) => {
+ this.assertWebGL2();
+ this.ctx.drawRangeElements(mode, start, end, count, type, offset);
+ },
+
+ /* Multiple Render Targets */
+ DrawBuffers: (buffers_ptr, buffers_len) => {
+ this.assertWebGL2();
+ let array = this.mem.loadU32Array(buffers_ptr, buffers_len);
+ this.ctx.drawBuffers(array);
+ },
+ ClearBufferfv: (buffer, drawbuffer, values_ptr, values_len) => {
+ this.assertWebGL2();
+ let array = this.mem.loadF32Array(values_ptr, values_len);
+ this.ctx.clearBufferfv(buffer, drawbuffer, array);
+ },
+ ClearBufferiv: (buffer, drawbuffer, values_ptr, values_len) => {
+ this.assertWebGL2();
+ let array = this.mem.loadI32Array(values_ptr, values_len);
+ this.ctx.clearBufferiv(buffer, drawbuffer, array);
+ },
+ ClearBufferuiv: (buffer, drawbuffer, values_ptr, values_len) => {
+ this.assertWebGL2();
+ let array = this.mem.loadU32Array(values_ptr, values_len);
+ this.ctx.clearBufferuiv(buffer, drawbuffer, array);
+ },
+ ClearBufferfi: (buffer, drawbuffer, depth, stencil) => {
+ this.assertWebGL2();
+ this.ctx.clearBufferfi(buffer, drawbuffer, depth, stencil);
+ },
+
+ /* Query Objects */
+ CreateQuery: () => {
+ this.assertWebGL2();
+ let query = this.ctx.createQuery();
+ let id = this.getNewId(this.queries);
+ query.name = id;
+ this.queries[id] = query;
+ return id;
+ },
+ DeleteQuery: (id) => {
+ this.assertWebGL2();
+ let obj = this.queries[id];
+ if (obj && id != 0) {
+ this.ctx.deleteQuery(obj);
+ this.queries[id] = null;
+ }
+ },
+ IsQuery: (query) => {
+ this.assertWebGL2();
+ return this.ctx.isQuery(this.queries[query]);
+ },
+ BeginQuery: (target, query) => {
+ this.assertWebGL2();
+ this.ctx.beginQuery(target, this.queries[query])
+ },
+ EndQuery: (target) => {
+ this.assertWebGL2();
+ this.ctx.endQuery(target);
+ },
+ GetQuery: (target, pname) => {
+ this.assertWebGL2();
+ let query = this.ctx.getQuery(target, pname);
+ if (!query) {
+ return 0;
+ }
+ if (this.queries.indexOf(query) !== -1) {
+ return query.name;
+ }
+ let id = this.getNewId(this.queries);
+ query.name = id;
+ this.queries[id] = query;
+ return id;
+ },
+
+ /* Sampler Objects */
+ CreateSampler: () => {
+ this.assertWebGL2();
+ let sampler = this.ctx.createSampler();
+ let id = this.getNewId(this.samplers);
+ sampler.name = id;
+ this.samplers[id] = sampler;
+ return id;
+ },
+ DeleteSampler: (id) => {
+ this.assertWebGL2();
+ let obj = this.samplers[id];
+ if (obj && id != 0) {
+ this.ctx.deleteSampler(obj);
+ this.samplers[id] = null;
+ }
+ },
+ IsSampler: (sampler) => {
+ this.assertWebGL2();
+ return this.ctx.isSampler(this.samplers[sampler]);
+ },
+ BindSampler: (unit, sampler) => {
+ this.assertWebGL2();
+ this.ctx.bindSampler(unit, this.samplers[sampler]);
+ },
+ SamplerParameteri: (sampler, pname, param) => {
+ this.assertWebGL2();
+ this.ctx.samplerParameteri(this.samplers[sampler], pname, param);
+ },
+ SamplerParameterf: (sampler, pname, param) => {
+ this.assertWebGL2();
+ this.ctx.samplerParameterf(this.samplers[sampler], pname, param);
+ },
+
+ /* Sync objects */
+ FenceSync: (condition, flags) => {
+ this.assertWebGL2();
+ let sync = this.ctx.fenceSync(condition, flags);
+ let id = this.getNewId(this.syncs);
+ sync.name = id;
+ this.syncs[id] = sync;
+ return id;
+ },
+ IsSync: (sync) => {
+ this.assertWebGL2();
+ return this.ctx.isSync(this.syncs[sync]);
+ },
+ DeleteSync: (id) => {
+ this.assertWebGL2();
+ let obj = this.syncs[id];
+ if (obj && id != 0) {
+ this.ctx.deleteSampler(obj);
+ this.syncs[id] = null;
+ }
+ },
+ ClientWaitSync: (sync, flags, timeout) => {
+ this.assertWebGL2();
+ return this.ctx.clientWaitSync(this.syncs[sync], flags, timeout);
+ },
+ WaitSync: (sync, flags, timeout) => {
+ this.assertWebGL2();
+ this.ctx.waitSync(this.syncs[sync], flags, timeout) ;
+ },
+
+
+ /* Transform Feedback */
+ CreateTransformFeedback: () => {
+ this.assertWebGL2();
+ let transformFeedback = this.ctx.createTransformFeedback();
+ let id = this.getNewId(this.transformFeedbacks);
+ transformFeedback.name = id;
+ this.transformFeedbacks[id] = transformFeedback;
+ return id;
+ },
+ DeleteTransformFeedback: (id) => {
+ this.assertWebGL2();
+ let obj = this.transformFeedbacks[id];
+ if (obj && id != 0) {
+ this.ctx.deleteTransformFeedback(obj);
+ this.transformFeedbacks[id] = null;
+ }
+ },
+ IsTransformFeedback: (tf) => {
+ this.assertWebGL2();
+ return this.ctx.isTransformFeedback(this.transformFeedbacks[tf]);
+ },
+ BindTransformFeedback: (target, tf) => {
+ this.assertWebGL2();
+ this.ctx.bindTransformFeedback(target, this.transformFeedbacks[tf]);
+ },
+ BeginTransformFeedback: (primitiveMode) => {
+ this.assertWebGL2();
+ this.ctx.beginTransformFeedback(primitiveMode);
+ },
+ EndTransformFeedback: () => {
+ this.assertWebGL2();
+ this.ctx.endTransformFeedback();
+ },
+ TransformFeedbackVaryings: (program, varyings_ptr, varyings_len, bufferMode) => {
+ this.assertWebGL2();
+ const stringSize = this.mem.intSize*2;
+ let varyings = [];
+ for (let i = 0; i < varyings_len; i++) {
+ let ptr = this.mem.loadPtr(varyings_ptr + i*stringSize + 0*4);
+ let len = this.mem.loadPtr(varyings_ptr + i*stringSize + 1*4);
+ varyings.push(this.mem.loadString(ptr, len));
+ }
+ this.ctx.transformFeedbackVaryings(this.programs[program], varyings, bufferMode);
+ },
+ PauseTransformFeedback: () => {
+ this.assertWebGL2();
+ this.ctx.pauseTransformFeedback();
+ },
+ ResumeTransformFeedback: () => {
+ this.assertWebGL2();
+ this.ctx.resumeTransformFeedback();
+ },
+
+
+ /* Uniform Buffer Objects and Transform Feedback Buffers */
+ BindBufferBase: (target, index, buffer) => {
+ this.assertWebGL2();
+ this.ctx.bindBufferBase(target, index, this.buffers[buffer]);
+ },
+ BindBufferRange: (target, index, buffer, offset, size) => {
+ this.assertWebGL2();
+ this.ctx.bindBufferRange(target, index, this.buffers[buffer], offset, size);
+ },
+ GetUniformBlockIndex: (program, uniformBlockName_ptr, uniformBlockName_len) => {
+ this.assertWebGL2();
+ return this.ctx.getUniformBlockIndex(this.programs[program], this.mem.loadString(uniformBlockName_ptr, uniformBlockName_len));
+ },
+ // any getActiveUniformBlockParameter(WebGLProgram program, GLuint uniformBlockIndex, GLenum pname);
+ GetActiveUniformBlockName: (program, uniformBlockIndex, buf_ptr, buf_len, length_ptr) => {
+ this.assertWebGL2();
+ let name = this.ctx.getActiveUniformBlockName(this.programs[program], uniformBlockIndex);
+
+ let n = Math.min(buf_len, name.length);
+ name = name.substring(0, n);
+ this.mem.loadBytes(buf_ptr, buf_len).set(new TextEncoder().encode(name))
+ this.mem.storeInt(length_ptr, n);
+ },
+ UniformBlockBinding: (program, uniformBlockIndex, uniformBlockBinding) => {
+ this.assertWebGL2();
+ this.ctx.uniformBlockBinding(this.programs[program], uniformBlockIndex, uniformBlockBinding);
+ },
+
+ /* Vertex Array Objects */
+ CreateVertexArray: () => {
+ this.assertWebGL2();
+ let vao = this.ctx.createVertexArray();
+ let id = this.getNewId(this.vaos);
+ vao.name = id;
+ this.vaos[id] = vao;
+ return id;
+ },
+ DeleteVertexArray: (id) => {
+ this.assertWebGL2();
+ let obj = this.vaos[id];
+ if (obj && id != 0) {
+ this.ctx.deleteVertexArray(obj);
+ this.vaos[id] = null;
+ }
+ },
+ IsVertexArray: (vertexArray) => {
+ this.assertWebGL2();
+ return this.ctx.isVertexArray(this.vaos[vertexArray]);
+ },
+ BindVertexArray: (vertexArray) => {
+ this.assertWebGL2();
+ this.ctx.bindVertexArray(this.vaos[vertexArray]);
+ },
+ };
+ }
+};
+
+
+function odinSetupDefaultImports(wasmMemoryInterface, consoleElement, memory, eventQueue, event_temp) {
+ const MAX_INFO_CONSOLE_LINES = 512;
+ let infoConsoleLines = new Array();
+ let currentLine = {};
+ currentLine[false] = "";
+ currentLine[true] = "";
+ let prevIsError = false;
+
+ const writeToConsole = (line, isError) => {
+ if (!line) {
+ return;
+ }
+
+ const println = (text, forceIsError) => {
+ let style = [
+ "color: #eee",
+ "background-color: #d20",
+ "padding: 2px 4px",
+ "border-radius: 2px",
+ ].join(";");
+ let doIsError = isError;
+ if (forceIsError !== undefined) {
+ doIsError = forceIsError;
+ }
+
+ if (doIsError) {
+ console.log("%c"+text, style);
+ } else {
+ console.log(text);
+ }
+
+ };
+
+ // Print to console
+ if (line == "\n") {
+ println(currentLine[isError]);
+ currentLine[isError] = "";
+ } else if (!line.includes("\n")) {
+ currentLine[isError] = currentLine[isError].concat(line);
+ } else {
+ let lines = line.split("\n");
+ let printLast = lines.length > 1 && line.endsWith("\n");
+ println(currentLine[isError].concat(lines[0]));
+ currentLine[isError] = "";
+ for (let i = 1; i < lines.length-1; i++) {
+ println(lines[i]);
+ }
+ let last = lines[lines.length-1];
+ if (printLast) {
+ println(last);
+ } else {
+ currentLine[isError] = last;
+ }
+ }
+
+ if (prevIsError != isError) {
+ if (prevIsError) {
+ println(currentLine[prevIsError], prevIsError);
+ currentLine[prevIsError] = "";
+ }
+ }
+ prevIsError = isError;
+
+
+ // HTML based console
+ if (!consoleElement) {
+ return;
+ }
+ const wrap = (x) => {
+ if (isError) {
+ return '<span style="color:#f21">'+x+'</span>';
+ }
+ return x;
+ };
+
+ if (line == "\n") {
+ infoConsoleLines.push(line);
+ } else if (!line.includes("\n")) {
+ let prevLine = "";
+ if (infoConsoleLines.length > 0) {
+ prevLine = infoConsoleLines.pop();
+ }
+ infoConsoleLines.push(prevLine.concat(wrap(line)));
+ } else {
+ let lines = line.split("\n");
+ let lastHasNewline = lines.length > 1 && line.endsWith("\n");
+
+ let prevLine = "";
+ if (infoConsoleLines.length > 0) {
+ prevLine = infoConsoleLines.pop();
+ }
+ infoConsoleLines.push(prevLine.concat(wrap(lines[0]).concat("\n")));
+
+ for (let i = 1; i < lines.length-1; i++) {
+ infoConsoleLines.push(wrap(lines[i]).concat("\n"));
+ }
+ let last = lines[lines.length-1];
+ if (lastHasNewline) {
+ infoConsoleLines.push(last.concat("\n"));
+ } else {
+ infoConsoleLines.push(last);
+ }
+ }
+
+ if (infoConsoleLines.length > MAX_INFO_CONSOLE_LINES) {
+ infoConsoleLines.shift(MAX_INFO_CONSOLE_LINES);
+ }
+
+ let data = "";
+ for (let i = 0; i < infoConsoleLines.length; i++) {
+ data = data.concat(infoConsoleLines[i]);
+ }
+
+ let info = consoleElement;
+ info.innerHTML = data;
+ info.scrollTop = info.scrollHeight;
+ };
+
+ let webglContext = new WebGLInterface(wasmMemoryInterface);
+
+ const env = {};
+
+ if (memory) {
+ env.memory = memory;
+ }
+
+ return {
+ env,
+ "odin_env": {
+ write: (fd, ptr, len) => {
+ const str = wasmMemoryInterface.loadString(ptr, len);
+ if (fd == 1) {
+ writeToConsole(str, false);
+ return;
+ } else if (fd == 2) {
+ writeToConsole(str, true);
+ return;
+ } else {
+ throw new Error("Invalid fd to 'write'" + stripNewline(str));
+ }
+ },
+ trap: () => { throw new Error() },
+ alert: (ptr, len) => { alert(wasmMemoryInterface.loadString(ptr, len)) },
+ abort: () => { Module.abort() },
+ evaluate: (str_ptr, str_len) => { eval.call(null, wasmMemoryInterface.loadString(str_ptr, str_len)); },
+
+ // return a bigint to be converted to i64
+ time_now: () => BigInt(Date.now()),
+ tick_now: () => performance.now(),
+ time_sleep: (duration_ms) => {
+ if (duration_ms > 0) {
+ // TODO(bill): Does this even make any sense?
+ }
+ },
+
+ sqrt: Math.sqrt,
+ sin: Math.sin,
+ cos: Math.cos,
+ pow: Math.pow,
+ fmuladd: (x, y, z) => x*y + z,
+ ln: Math.log,
+ exp: Math.exp,
+ ldexp: (x, exp) => x * Math.pow(2, exp),
+
+ rand_bytes: (ptr, len) => {
+ const view = new Uint8Array(wasmMemoryInterface.memory.buffer, ptr, len)
+ crypto.getRandomValues(view)
+ },
+ },
+ "odin_dom": {
+ init_event_raw: (ep) => {
+ const W = wasmMemoryInterface.intSize;
+ let offset = ep;
+ let off = (amount, alignment) => {
+ if (alignment === undefined) {
+ alignment = Math.min(amount, W);
+ }
+ if (offset % alignment != 0) {
+ offset += alignment - (offset%alignment);
+ }
+ let x = offset;
+ offset += amount;
+ return x;
+ };
+
+ let align = (alignment) => {
+ const modulo = offset & (alignment-1);
+ if (modulo != 0) {
+ offset += alignment - modulo
+ }
+ };
+
+ let wmi = wasmMemoryInterface;
+
+ if (!event_temp.data) {
+ return;
+ }
+
+ let e = event_temp.data.event;
+
+ wmi.storeU32(off(4), event_temp.data.name_code);
+ if (e.target == document) {
+ wmi.storeU32(off(4), 1);
+ } else if (e.target == window) {
+ wmi.storeU32(off(4), 2);
+ } else {
+ wmi.storeU32(off(4), 0);
+ }
+ if (e.currentTarget == document) {
+ wmi.storeU32(off(4), 1);
+ } else if (e.currentTarget == window) {
+ wmi.storeU32(off(4), 2);
+ } else {
+ wmi.storeU32(off(4), 0);
+ }
+
+ align(W);
+
+ wmi.storeI32(off(W), event_temp.data.id_ptr);
+ wmi.storeUint(off(W), event_temp.data.id_len);
+
+ align(8);
+ wmi.storeF64(off(8), e.timeStamp*1e-3);
+
+ wmi.storeU8(off(1), e.eventPhase);
+ let options = 0;
+ if (!!e.bubbles) { options |= 1<<0; }
+ if (!!e.cancelable) { options |= 1<<1; }
+ if (!!e.composed) { options |= 1<<2; }
+ wmi.storeU8(off(1), options);
+ wmi.storeU8(off(1), !!e.isComposing);
+ wmi.storeU8(off(1), !!e.isTrusted);
+
+ align(8);
+ if (e instanceof WheelEvent) {
+ wmi.storeF64(off(8), e.deltaX);
+ wmi.storeF64(off(8), e.deltaY);
+ wmi.storeF64(off(8), e.deltaZ);
+ wmi.storeU32(off(4), e.deltaMode);
+ } else if (e instanceof MouseEvent) {
+ wmi.storeI64(off(8), e.screenX);
+ wmi.storeI64(off(8), e.screenY);
+ wmi.storeI64(off(8), e.clientX);
+ wmi.storeI64(off(8), e.clientY);
+ wmi.storeI64(off(8), e.offsetX);
+ wmi.storeI64(off(8), e.offsetY);
+ wmi.storeI64(off(8), e.pageX);
+ wmi.storeI64(off(8), e.pageY);
+ wmi.storeI64(off(8), e.movementX);
+ wmi.storeI64(off(8), e.movementY);
+
+ wmi.storeU8(off(1), !!e.ctrlKey);
+ wmi.storeU8(off(1), !!e.shiftKey);
+ wmi.storeU8(off(1), !!e.altKey);
+ wmi.storeU8(off(1), !!e.metaKey);
+
+ wmi.storeI16(off(2), e.button);
+ wmi.storeU16(off(2), e.buttons);
+ } else if (e instanceof KeyboardEvent) {
+ // Note: those strings are constructed
+ // on the native side from buffers that
+ // are filled later, so skip them
+ const keyPtr = off(W*2, W);
+ const codePtr = off(W*2, W);
+
+ wmi.storeU8(off(1), e.location);
+
+ wmi.storeU8(off(1), !!e.ctrlKey);
+ wmi.storeU8(off(1), !!e.shiftKey);
+ wmi.storeU8(off(1), !!e.altKey);
+ wmi.storeU8(off(1), !!e.metaKey);
+
+ wmi.storeU8(off(1), !!e.repeat);
+
+ wmi.storeInt(off(W, W), e.key.length)
+ wmi.storeInt(off(W, W), e.code.length)
+ wmi.storeString(off(16, 1), e.key);
+ wmi.storeString(off(16, 1), e.code);
+ } else if (e.type === 'scroll') {
+ wmi.storeF64(off(8, 8), window.scrollX);
+ wmi.storeF64(off(8, 8), window.scrollY);
+ } else if (e.type === 'visibilitychange') {
+ wmi.storeU8(off(1), !document.hidden);
+ } else if (e instanceof GamepadEvent) {
+ const idPtr = off(W*2, W);
+ const mappingPtr = off(W*2, W);
+
+ wmi.storeI32(off(W, W), e.gamepad.index);
+ wmi.storeU8(off(1), !!e.gamepad.connected);
+ wmi.storeF64(off(8, 8), e.gamepad.timestamp);
+
+ wmi.storeInt(off(W, W), e.gamepad.buttons.length);
+ wmi.storeInt(off(W, W), e.gamepad.axes.length);
+
+ for (let i = 0; i < 64; i++) {
+ if (i < e.gamepad.buttons.length) {
+ let b = e.gamepad.buttons[i];
+ wmi.storeF64(off(8, 8), b.value);
+ wmi.storeU8(off(1), !!b.pressed);
+ wmi.storeU8(off(1), !!b.touched);
+ } else {
+ off(16, 8);
+ }
+ }
+ for (let i = 0; i < 16; i++) {
+ if (i < e.gamepad.axes.length) {
+ let a = e.gamepad.axes[i];
+ wmi.storeF64(off(8, 8), a);
+ } else {
+ off(8, 8);
+ }
+ }
+
+ 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);
+ }
+ },
+
+ add_event_listener: (id_ptr, id_len, name_ptr, name_len, name_code, data, callback, use_capture) => {
+ let id = wasmMemoryInterface.loadString(id_ptr, id_len);
+ let name = wasmMemoryInterface.loadString(name_ptr, name_len);
+ let element = getElement(id);
+ if (element == undefined) {
+ return false;
+ }
+
+ let listener = (e) => {
+ let event_data = {};
+ event_data.id_ptr = id_ptr;
+ event_data.id_len = id_len;
+ event_data.event = e;
+ event_data.name_code = name_code;
+
+ eventQueue.push({event_data: event_data, data: data, callback: callback});
+ };
+ wasmMemoryInterface.listenerMap[{data: data, callback: callback}] = listener;
+ element.addEventListener(name, listener, !!use_capture);
+ return true;
+ },
+
+ 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 listener = (e) => {
+ let event_data = {};
+ event_data.id_ptr = 0;
+ event_data.id_len = 0;
+ event_data.event = e;
+ event_data.name_code = name_code;
+
+ eventQueue.push({event_data: event_data, data: data, callback: callback});
+ };
+ wasmMemoryInterface.listenerMap[{data: data, callback: callback}] = listener;
+ element.addEventListener(name, listener, !!use_capture);
+ return true;
+ },
+
+ remove_event_listener: (id_ptr, id_len, name_ptr, name_len, data, callback) => {
+ let id = wasmMemoryInterface.loadString(id_ptr, id_len);
+ let name = wasmMemoryInterface.loadString(name_ptr, name_len);
+ let element = getElement(id);
+ if (element == undefined) {
+ return false;
+ }
+
+ let listener = wasmMemoryInterface.listenerMap[{data: data, callback: callback}];
+ if (listener == undefined) {
+ return false;
+ }
+ element.removeEventListener(name, listener);
+ return true;
+ },
+ remove_window_event_listener: (name_ptr, name_len, data, callback) => {
+ let name = wasmMemoryInterface.loadString(name_ptr, name_len);
+ let element = window;
+ let key = {data: data, callback: callback};
+ let listener = wasmMemoryInterface.listenerMap[key];
+ if (!listener) {
+ return false;
+ }
+ wasmMemoryInterface.listenerMap[key] = undefined;
+
+ element.removeEventListener(name, listener);
+ return true;
+ },
+
+ event_stop_propagation: () => {
+ if (event_temp.data && event_temp.data.event) {
+ event_temp.data.event.stopPropagation();
+ }
+ },
+ event_stop_immediate_propagation: () => {
+ if (event_temp.data && event_temp.data.event) {
+ event_temp.data.event.stopImmediatePropagation();
+ }
+ },
+ event_prevent_default: () => {
+ if (event_temp.data && event_temp.data.event) {
+ event_temp.data.event.preventDefault();
+ }
+ },
+
+ dispatch_custom_event: (id_ptr, id_len, name_ptr, name_len, options_bits) => {
+ let id = wasmMemoryInterface.loadString(id_ptr, id_len);
+ let name = wasmMemoryInterface.loadString(name_ptr, name_len);
+ let options = {
+ bubbles: (options_bits & (1<<0)) !== 0,
+ cancelable: (options_bits & (1<<1)) !== 0,
+ composed: (options_bits & (1<<2)) !== 0,
+ };
+
+ let element = getElement(id);
+ if (element) {
+ element.dispatchEvent(new Event(name, options));
+ return true;
+ }
+ return false;
+ },
+
+ get_gamepad_state: (gamepad_id, ep) => {
+ let index = gamepad_id;
+ let gps = navigator.getGamepads();
+ if (0 <= index && index < gps.length) {
+ let gamepad = gps[index];
+ if (!gamepad) {
+ return false;
+ }
+
+ const W = wasmMemoryInterface.intSize;
+ let offset = ep;
+ let off = (amount, alignment) => {
+ if (alignment === undefined) {
+ alignment = Math.min(amount, W);
+ }
+ if (offset % alignment != 0) {
+ offset += alignment - (offset%alignment);
+ }
+ let x = offset;
+ offset += amount;
+ return x;
+ };
+
+ let align = (alignment) => {
+ const modulo = offset & (alignment-1);
+ if (modulo != 0) {
+ offset += alignment - modulo
+ }
+ };
+
+ let wmi = wasmMemoryInterface;
+
+ const idPtr = off(W*2, W);
+ const mappingPtr = off(W*2, W);
+
+ wmi.storeI32(off(W), gamepad.index);
+ wmi.storeU8(off(1), !!gamepad.connected);
+ wmi.storeF64(off(8), gamepad.timestamp);
+
+ wmi.storeInt(off(W), gamepad.buttons.length);
+ wmi.storeInt(off(W), gamepad.axes.length);
+
+ for (let i = 0; i < 64; i++) {
+ if (i < gamepad.buttons.length) {
+ let b = gamepad.buttons[i];
+ wmi.storeF64(off(8, 8), b.value);
+ wmi.storeU8(off(1), !!b.pressed);
+ wmi.storeU8(off(1), !!b.touched);
+ } else {
+ off(16, 8);
+ }
+ }
+ for (let i = 0; i < 16; i++) {
+ if (i < gamepad.axes.length) {
+ wmi.storeF64(off(8, 8), gamepad.axes[i]);
+ } else {
+ off(8, 8);
+ }
+ }
+
+ 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);
+
+ return true;
+ }
+ return false;
+ },
+
+ get_element_value_f64: (id_ptr, id_len) => {
+ let id = wasmMemoryInterface.loadString(id_ptr, id_len);
+ let element = getElement(id);
+ return element ? element.value : 0;
+ },
+ get_element_value_string: (id_ptr, id_len, buf_ptr, buf_len) => {
+ let id = wasmMemoryInterface.loadString(id_ptr, id_len);
+ let element = getElement(id);
+ if (element) {
+ let str = element.value;
+ if (buf_len > 0 && buf_ptr) {
+ let n = Math.min(buf_len, str.length);
+ str = str.substring(0, n);
+ this.mem.loadBytes(buf_ptr, buf_len).set(new TextEncoder().encode(str))
+ return n;
+ }
+ }
+ return 0;
+ },
+ get_element_value_string_length: (id_ptr, id_len) => {
+ let id = wasmMemoryInterface.loadString(id_ptr, id_len);
+ let element = getElement(id);
+ if (element) {
+ return element.value.length;
+ }
+ return 0;
+ },
+ get_element_min_max: (ptr_array2_f64, id_ptr, id_len) => {
+ let id = wasmMemoryInterface.loadString(id_ptr, id_len);
+ let element = getElement(id);
+ if (element) {
+ let values = wasmMemoryInterface.loadF64Array(ptr_array2_f64, 2);
+ values[0] = element.min;
+ values[1] = element.max;
+ }
+ },
+ set_element_value_f64: (id_ptr, id_len, value) => {
+ let id = wasmMemoryInterface.loadString(id_ptr, id_len);
+ let element = getElement(id);
+ if (element) {
+ element.value = value;
+ }
+ },
+ set_element_value_string: (id_ptr, id_len, value_ptr, value_len) => {
+ let id = wasmMemoryInterface.loadString(id_ptr, id_len);
+ let value = wasmMemoryInterface.loadString(value_ptr, value_len);
+ let element = getElement(id);
+ if (element) {
+ element.value = value;
+ }
+ },
+
+ get_element_key_f64: (id_ptr, id_len, key_ptr, key_len) => {
+ let id = wasmMemoryInterface.loadString(id_ptr, id_len);
+ let key = wasmMemoryInterface.loadString(key_ptr, key_len);
+ let element = getElement(id);
+ return element ? element[key] : 0;
+ },
+ get_element_key_string: (id_ptr, id_len, key_ptr, key_len, buf_ptr, buf_len) => {
+ let id = wasmMemoryInterface.loadString(id_ptr, id_len);
+ let key = wasmMemoryInterface.loadString(key_ptr, key_len);
+ let element = getElement(id);
+ if (element) {
+ let str = element[key];
+ if (buf_len > 0 && buf_ptr) {
+ let n = Math.min(buf_len, str.length);
+ str = str.substring(0, n);
+ this.mem.loadBytes(buf_ptr, buf_len).set(new TextEncoder().encode(str))
+ return n;
+ }
+ }
+ return 0;
+ },
+ get_element_key_string_length: (id_ptr, id_len, key_ptr, key_len) => {
+ let id = wasmMemoryInterface.loadString(id_ptr, id_len);
+ let key = wasmMemoryInterface.loadString(key_ptr, key_len);
+ let element = getElement(id);
+ if (element && element[key]) {
+ return element[key].length;
+ }
+ return 0;
+ },
+
+ set_element_key_f64: (id_ptr, id_len, key_ptr, key_len, value) => {
+ let id = wasmMemoryInterface.loadString(id_ptr, id_len);
+ let key = wasmMemoryInterface.loadString(key_ptr, key_len);
+ let element = getElement(id);
+ if (element) {
+ element[key] = value;
+ }
+ },
+ set_element_key_string: (id_ptr, id_len, key_ptr, key_len, value_ptr, value_len) => {
+ let id = wasmMemoryInterface.loadString(id_ptr, id_len);
+ let key = wasmMemoryInterface.loadString(key_ptr, key_len);
+ let value = wasmMemoryInterface.loadString(value_ptr, value_len);
+ let element = getElement(id);
+ if (element) {
+ element[key] = value;
+ }
+ },
+
+
+ get_bounding_client_rect: (rect_ptr, id_ptr, id_len) => {
+ let id = wasmMemoryInterface.loadString(id_ptr, id_len);
+ let element = getElement(id);
+ if (element) {
+ let values = wasmMemoryInterface.loadF64Array(rect_ptr, 4);
+ let rect = element.getBoundingClientRect();
+ values[0] = rect.left;
+ values[1] = rect.top;
+ values[2] = rect.right - rect.left;
+ values[3] = rect.bottom - rect.top;
+ }
+ },
+ window_get_rect: (rect_ptr) => {
+ let values = wasmMemoryInterface.loadF64Array(rect_ptr, 4);
+ values[0] = window.screenX;
+ values[1] = window.screenY;
+ values[2] = window.screen.width;
+ values[3] = window.screen.height;
+ },
+
+ window_get_scroll: (pos_ptr) => {
+ let values = wasmMemoryInterface.loadF64Array(pos_ptr, 2);
+ values[0] = window.scrollX;
+ values[1] = window.scrollY;
+ },
+ window_set_scroll: (x, y) => {
+ window.scroll(x, y);
+ },
+
+ device_pixel_ratio: () => {
+ return window.devicePixelRatio;
+ },
+
+ },
+
+ "webgl": webglContext.getWebGL1Interface(),
+ "webgl2": webglContext.getWebGL2Interface(),
+ };
+};
+
+/**
+ * @param {string} wasmPath - Path to the WASM module to run
+ * @param {?HTMLPreElement} consoleElement - Optional console/pre element to append output to, in addition to the console
+ * @param {any} extraForeignImports - Imports, in addition to the default runtime to provide the module
+ * @param {?WasmMemoryInterface} wasmMemoryInterface - Optional memory to use instead of the defaults
+ * @param {?int} intSize - Size (in bytes) of the integer type, should be 4 on `js_wasm32` and 8 on `js_wasm64p32`
+ */
+async function runWasm(wasmPath, consoleElement, extraForeignImports, wasmMemoryInterface, intSize = 4) {
+ if (!wasmMemoryInterface) {
+ wasmMemoryInterface = new WasmMemoryInterface();
+ }
+ wasmMemoryInterface.setIntSize(intSize);
+
+ let eventQueue = new Array();
+ let event_temp = {};
+
+ let imports = odinSetupDefaultImports(wasmMemoryInterface, consoleElement, wasmMemoryInterface.memory, eventQueue, event_temp);
+ let exports = {};
+
+ if (extraForeignImports !== undefined) {
+ imports = {
+ ...imports,
+ ...extraForeignImports,
+ };
+ }
+
+ const response = await fetch(wasmPath);
+ const file = await response.arrayBuffer();
+ const wasm = await WebAssembly.instantiate(file, imports);
+ exports = wasm.instance.exports;
+ wasmMemoryInterface.setExports(exports);
+
+ if (exports.memory) {
+ if (wasmMemoryInterface.memory) {
+ console.warn("WASM module exports memory, but `runWasm` was given an interface with existing memory too");
+ }
+ wasmMemoryInterface.setMemory(exports.memory);
+ }
+
+ exports._start();
+
+ // Define a `@export step :: proc(current_type: f64) -> (keep_going: bool) {`
+ // in your app and it will get called every frame.
+ // return `false` to stop the execution of the module.
+ if (exports.step) {
+ const odin_ctx = exports.default_context_ptr();
+
+ let prevTimeStamp = undefined;
+ function step(currTimeStamp) {
+ if (prevTimeStamp == undefined) {
+ prevTimeStamp = currTimeStamp;
+ }
+
+ const dt = (currTimeStamp - prevTimeStamp)*0.001;
+ prevTimeStamp = currTimeStamp;
+
+ while (eventQueue.length > 0) {
+ let e = eventQueue.shift()
+ event_temp.data = e.event_data;
+ exports.odin_dom_do_event_callback(e.data, e.callback, odin_ctx);
+ }
+ event_temp.data = null;
+
+ if (!exports.step(currTimeStamp*0.001, odin_ctx)) {
+ exports._end();
+ return;
+ }
+
+ window.requestAnimationFrame(step);
+ }
+
+ window.requestAnimationFrame(step);
+ } else {
+ exports._end();
+ }
+
+ return;
+};
+
+window.odin = {
+ // Interface Types
+ WasmMemoryInterface: WasmMemoryInterface,
+ WebGLInterface: WebGLInterface,
+
+ // Functions
+ setupDefaultImports: odinSetupDefaultImports,
+ runWasm: runWasm,
+};
+})();
diff --git a/core/sys/wasm/wasi/wasi_api.odin b/core/sys/wasm/wasi/wasi_api.odin
index 38d95e754..8d50f1690 100644
--- a/core/sys/wasm/wasi/wasi_api.odin
+++ b/core/sys/wasm/wasi/wasi_api.odin
@@ -1,4 +1,4 @@
-//+build wasm32
+#+build wasm32
package sys_wasi
foreign import wasi "wasi_snapshot_preview1"
diff --git a/core/sys/windows/advapi32.odin b/core/sys/windows/advapi32.odin
index 1e34f1fd6..f834511d4 100644
--- a/core/sys/windows/advapi32.odin
+++ b/core/sys/windows/advapi32.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
foreign import advapi32 "system:Advapi32.lib"
diff --git a/core/sys/windows/bcrypt.odin b/core/sys/windows/bcrypt.odin
index d891aa92b..f15f1e305 100644
--- a/core/sys/windows/bcrypt.odin
+++ b/core/sys/windows/bcrypt.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
foreign import bcrypt "system:Bcrypt.lib"
diff --git a/core/sys/windows/bluetooth.odin b/core/sys/windows/bluetooth.odin
index 7bfb7ea96..86c66b9a1 100644
--- a/core/sys/windows/bluetooth.odin
+++ b/core/sys/windows/bluetooth.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
foreign import "system:bthprops.lib"
diff --git a/core/sys/windows/codepage.odin b/core/sys/windows/codepage.odin
index 90040f1ee..527289f03 100644
--- a/core/sys/windows/codepage.odin
+++ b/core/sys/windows/codepage.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
// https://learn.microsoft.com/en-us/windows/win32/intl/code-page-identifiers
diff --git a/core/sys/windows/comctl32.odin b/core/sys/windows/comctl32.odin
index 9c4404a9d..477800413 100644
--- a/core/sys/windows/comctl32.odin
+++ b/core/sys/windows/comctl32.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
foreign import "system:Comctl32.lib"
diff --git a/core/sys/windows/comdlg32.odin b/core/sys/windows/comdlg32.odin
index 30d9b169c..a9800b47a 100644
--- a/core/sys/windows/comdlg32.odin
+++ b/core/sys/windows/comdlg32.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
foreign import "system:Comdlg32.lib"
diff --git a/core/sys/windows/dbghelp.odin b/core/sys/windows/dbghelp.odin
index cb5458248..336992b4a 100644
--- a/core/sys/windows/dbghelp.odin
+++ b/core/sys/windows/dbghelp.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
foreign import "system:Dbghelp.lib"
diff --git a/core/sys/windows/dnsapi.odin b/core/sys/windows/dnsapi.odin
index dd2d1acee..4fd9f7a19 100644
--- a/core/sys/windows/dnsapi.odin
+++ b/core/sys/windows/dnsapi.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
foreign import "system:Dnsapi.lib"
diff --git a/core/sys/windows/dwmapi.odin b/core/sys/windows/dwmapi.odin
index 91911baae..11a46f53a 100644
--- a/core/sys/windows/dwmapi.odin
+++ b/core/sys/windows/dwmapi.odin
@@ -1,10 +1,10 @@
-// +build windows
+#+build windows
package sys_windows
foreign import dwmapi "system:Dwmapi.lib"
DWMWINDOWATTRIBUTE :: enum {
- DWMWA_NCRENDERING_ENABLED,
+ DWMWA_NCRENDERING_ENABLED = 1,
DWMWA_NCRENDERING_POLICY,
DWMWA_TRANSITIONS_FORCEDISABLED,
DWMWA_ALLOW_NCPAINT,
@@ -28,7 +28,7 @@ DWMWINDOWATTRIBUTE :: enum {
DWMWA_TEXT_COLOR,
DWMWA_VISIBLE_FRAME_BORDER_THICKNESS,
DWMWA_SYSTEMBACKDROP_TYPE,
- DWMWA_LAST,
+ DWMWA_LAST,
}
DWMNCRENDERINGPOLICY :: enum {
diff --git a/core/sys/windows/gdi32.odin b/core/sys/windows/gdi32.odin
index 5cbafddba..1d7a93d85 100644
--- a/core/sys/windows/gdi32.odin
+++ b/core/sys/windows/gdi32.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
import "core:math/fixed"
diff --git a/core/sys/windows/hidpi.odin b/core/sys/windows/hidpi.odin
index bea03694e..5e9787527 100644
--- a/core/sys/windows/hidpi.odin
+++ b/core/sys/windows/hidpi.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
import "core:c"
diff --git a/core/sys/windows/hidusage.odin b/core/sys/windows/hidusage.odin
index a32aa7b9f..eb2a85f2e 100644
--- a/core/sys/windows/hidusage.odin
+++ b/core/sys/windows/hidusage.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
USAGE :: distinct USHORT
diff --git a/core/sys/windows/ip_helper.odin b/core/sys/windows/ip_helper.odin
index 4c2534c10..7a6e545ac 100644
--- a/core/sys/windows/ip_helper.odin
+++ b/core/sys/windows/ip_helper.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
foreign import "system:iphlpapi.lib"
diff --git a/core/sys/windows/kernel32.odin b/core/sys/windows/kernel32.odin
index 54dc11389..2771581e6 100644
--- a/core/sys/windows/kernel32.odin
+++ b/core/sys/windows/kernel32.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
foreign import kernel32 "system:Kernel32.lib"
@@ -400,6 +400,9 @@ foreign kernel32 {
GlobalAlloc :: proc(flags: UINT, bytes: SIZE_T) -> LPVOID ---
GlobalReAlloc :: proc(mem: LPVOID, bytes: SIZE_T, flags: UINT) -> LPVOID ---
GlobalFree :: proc(mem: LPVOID) -> LPVOID ---
+
+ GlobalLock :: proc(hMem: HGLOBAL) -> LPVOID ---
+ GlobalUnlock :: proc(hMem: HGLOBAL) -> BOOL ---
ReadDirectoryChangesW :: proc(
hDirectory: HANDLE,
@@ -1175,17 +1178,17 @@ SYSTEM_POWER_STATUS :: struct {
}
AC_Line_Status :: enum BYTE {
- Offline = 0,
- Online = 1,
- Unknown = 255,
+ Offline = 0,
+ Online = 1,
+ Unknown = 255,
}
Battery_Flag :: enum BYTE {
- High = 0,
- Low = 1,
- Critical = 2,
- Charging = 3,
- No_Battery = 7,
+ High = 0,
+ Low = 1,
+ Critical = 2,
+ Charging = 3,
+ No_Battery = 7,
}
Battery_Flags :: bit_set[Battery_Flag; BYTE]
diff --git a/core/sys/windows/key_codes.odin b/core/sys/windows/key_codes.odin
index 284b0e437..0991ca4b3 100644
--- a/core/sys/windows/key_codes.odin
+++ b/core/sys/windows/key_codes.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
// https://docs.microsoft.com/en-us/windows/win32/inputdev/about-keyboard-input
diff --git a/core/sys/windows/known_folders.odin b/core/sys/windows/known_folders.odin
index 439d65faf..cbaf5eeeb 100644
--- a/core/sys/windows/known_folders.odin
+++ b/core/sys/windows/known_folders.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
FOLDERID_NetworkFolder :: GUID {0xD20BEEC4, 0x5CA8, 0x4905, {0xAE, 0x3B, 0xBF, 0x25, 0x1E, 0xA0, 0x9B, 0x53}}
diff --git a/core/sys/windows/netapi32.odin b/core/sys/windows/netapi32.odin
index d9f75c623..9442193ca 100644
--- a/core/sys/windows/netapi32.odin
+++ b/core/sys/windows/netapi32.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
foreign import netapi32 "system:Netapi32.lib"
diff --git a/core/sys/windows/ntdll.odin b/core/sys/windows/ntdll.odin
index 23444ff34..747130749 100644
--- a/core/sys/windows/ntdll.odin
+++ b/core/sys/windows/ntdll.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
foreign import ntdll_lib "system:ntdll.lib"
diff --git a/core/sys/windows/shcore.odin b/core/sys/windows/shcore.odin
index 54f67989e..08a76ebe6 100644
--- a/core/sys/windows/shcore.odin
+++ b/core/sys/windows/shcore.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
diff --git a/core/sys/windows/shell32.odin b/core/sys/windows/shell32.odin
index 7340ae4d4..54cee718c 100644
--- a/core/sys/windows/shell32.odin
+++ b/core/sys/windows/shell32.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
foreign import shell32 "system:Shell32.lib"
diff --git a/core/sys/windows/shlwapi.odin b/core/sys/windows/shlwapi.odin
index bf9d2d1e8..095fff304 100644
--- a/core/sys/windows/shlwapi.odin
+++ b/core/sys/windows/shlwapi.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
foreign import shlwapi "system:shlwapi.lib"
diff --git a/core/sys/windows/synchronization.odin b/core/sys/windows/synchronization.odin
index 79efaab34..bcaeb3f5f 100644
--- a/core/sys/windows/synchronization.odin
+++ b/core/sys/windows/synchronization.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
foreign import Synchronization "system:Synchronization.lib"
diff --git a/core/sys/windows/system_params.odin b/core/sys/windows/system_params.odin
index e94d777bf..e463feb7e 100644
--- a/core/sys/windows/system_params.odin
+++ b/core/sys/windows/system_params.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
// Parameter for SystemParametersInfo.
diff --git a/core/sys/windows/tlhelp.odin b/core/sys/windows/tlhelp.odin
index 45d5a3ff9..006c9c330 100644
--- a/core/sys/windows/tlhelp.odin
+++ b/core/sys/windows/tlhelp.odin
@@ -1,4 +1,4 @@
-//+build windows
+#+build windows
package sys_windows
foreign import kernel32 "system:Kernel32.lib"
diff --git a/core/sys/windows/types.odin b/core/sys/windows/types.odin
index d9a6bd1fd..934d103e5 100644
--- a/core/sys/windows/types.odin
+++ b/core/sys/windows/types.odin
@@ -3546,11 +3546,11 @@ SIGDN :: enum c_int {
}
SIATTRIBFLAGS :: enum c_int {
- AND = 0x1,
- OR = 0x2,
- APPCOMPAT = 0x3,
- MASK = 0x3,
- ALLITEMS = 0x4000,
+ AND = 0x1,
+ OR = 0x2,
+ APPCOMPAT = 0x3,
+ MASK = 0x3,
+ ALLITEMS = 0x4000,
}
FDAP :: enum c_int {
@@ -4503,35 +4503,35 @@ DNS_INFO_NO_RECORDS :: 9501
DNS_QUERY_NO_RECURSION :: 0x00000004
DNS_RECORD :: struct { // aka DNS_RECORDA
- pNext: ^DNS_RECORD,
- pName: cstring,
- wType: WORD,
- wDataLength: USHORT,
- Flags: DWORD,
- dwTtl: DWORD,
- _: DWORD,
- Data: struct #raw_union {
- CNAME: DNS_PTR_DATAA,
- A: u32be, // Ipv4 Address
- AAAA: u128be, // Ipv6 Address
- TXT: DNS_TXT_DATAA,
- NS: DNS_PTR_DATAA,
- MX: DNS_MX_DATAA,
- SRV: DNS_SRV_DATAA,
- },
+ pNext: ^DNS_RECORD,
+ pName: cstring,
+ wType: WORD,
+ wDataLength: USHORT,
+ Flags: DWORD,
+ dwTtl: DWORD,
+ _: DWORD,
+ Data: struct #raw_union {
+ CNAME: DNS_PTR_DATAA,
+ A: u32be, // Ipv4 Address
+ AAAA: u128be, // Ipv6 Address
+ TXT: DNS_TXT_DATAA,
+ NS: DNS_PTR_DATAA,
+ MX: DNS_MX_DATAA,
+ SRV: DNS_SRV_DATAA,
+ },
}
DNS_TXT_DATAA :: struct {
- dwStringCount: DWORD,
- pStringArray: cstring,
+ dwStringCount: DWORD,
+ pStringArray: cstring,
}
DNS_PTR_DATAA :: cstring
DNS_MX_DATAA :: struct {
- pNameExchange: cstring, // the hostname
- wPreference: WORD, // lower values preferred
- _: WORD, // padding.
+ pNameExchange: cstring, // the hostname
+ wPreference: WORD, // lower values preferred
+ _: WORD, // padding.
}
DNS_SRV_DATAA :: struct {
pNameTarget: cstring,
diff --git a/core/sys/windows/user32.odin b/core/sys/windows/user32.odin
index f1232c680..514592e7b 100644
--- a/core/sys/windows/user32.odin
+++ b/core/sys/windows/user32.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
import "base:intrinsics"
@@ -66,7 +66,7 @@ foreign user32 {
RemovePropW :: proc(hWnd: HWND, lpString: LPCWSTR) -> HANDLE ---
EnumPropsW :: proc(hWnd: HWND, lpEnumFunc: PROPENUMPROCW) -> INT ---
EnumPropsExW :: proc(hWnd: HWND, lpEnumFunc: PROPENUMPROCW, lParam: LPARAM) -> INT ---
- GetMessageW :: proc(lpMsg: ^MSG, hWnd: HWND, wMsgFilterMin: UINT, wMsgFilterMax: UINT) -> BOOL ---
+ GetMessageW :: proc(lpMsg: ^MSG, hWnd: HWND, wMsgFilterMin: UINT, wMsgFilterMax: UINT) -> INT ---
TranslateMessage :: proc(lpMsg: ^MSG) -> BOOL ---
DispatchMessageW :: proc(lpMsg: ^MSG) -> LRESULT ---
@@ -142,7 +142,7 @@ foreign user32 {
AppendMenuW :: proc(hMenu: HMENU, uFlags: UINT, uIDNewItem: UINT_PTR, lpNewItem: LPCWSTR) -> BOOL ---
GetMenu :: proc(hWnd: HWND) -> HMENU ---
SetMenu :: proc(hWnd: HWND, hMenu: HMENU) -> BOOL ---
- TrackPopupMenu :: proc(hMenu: HMENU, uFlags: UINT, x, y: INT, nReserved: INT, hWnd: HWND, prcRect: ^RECT) -> BOOL ---
+ TrackPopupMenu :: proc(hMenu: HMENU, uFlags: UINT, x, y: INT, nReserved: INT, hWnd: HWND, prcRect: ^RECT) -> INT ---
RegisterWindowMessageW :: proc(lpString: LPCWSTR) -> UINT ---
CreateAcceleratorTableW :: proc(paccel: LPACCEL, cAccel: INT) -> HACCEL ---
@@ -305,6 +305,13 @@ foreign user32 {
GetProcessWindowStation :: proc() -> HWINSTA ---
GetUserObjectInformationW :: proc(hObj: HANDLE, nIndex: GetUserObjectInformationFlags, pvInfo: PVOID, nLength: DWORD, lpnLengthNeeded: LPDWORD) -> BOOL ---
+
+ OpenClipboard :: proc(hWndNewOwner: HWND) -> BOOL ---
+ CloseClipboard :: proc() -> BOOL ---
+ GetClipboardData :: proc(uFormat: UINT) -> HANDLE ---
+ SetClipboardData :: proc(uFormat: UINT, hMem: HANDLE) -> HANDLE ---
+ IsClipboardFormatAvailable :: proc(format: UINT) -> BOOL ---
+ EmptyClipboard :: proc() -> BOOL ---
}
CreateWindowW :: #force_inline proc "system" (
@@ -746,3 +753,31 @@ WinEventFlag :: enum DWORD {
SKIPOWNPROCESS = 1,
INCONTEXT = 2,
}
+
+// Standard Clipboard Formats
+CF_TEXT :: 1
+CF_BITMAP :: 2
+CF_METAFILEPICT :: 3
+CF_SYLK :: 4
+CF_DIF :: 5
+CF_TIFF :: 6
+CF_OEMTEXT :: 7
+CF_DIB :: 8
+CF_PALETTE :: 9
+CF_PENDATA :: 10
+CF_RIFF :: 11
+CF_WAVE :: 12
+CF_UNICODETEXT :: 13
+CF_ENHMETAFILE :: 14
+CF_HDROP :: 15
+CF_LOCALE :: 16
+CF_DIBV5 :: 17
+CF_DSPBITMAP :: 0x0082
+CF_DSPENHMETAFILE :: 0x008E
+CF_DSPMETAFILEPICT :: 0x0083
+CF_DSPTEXT :: 0x0081
+CF_GDIOBJFIRST :: 0x0300
+CF_GDIOBJLAST :: 0x03FF
+CF_OWNERDISPLAY :: 0x0080
+CF_PRIVATEFIRST :: 0x0200
+CF_PRIVATELAST :: 0x02FF
diff --git a/core/sys/windows/userenv.odin b/core/sys/windows/userenv.odin
index a31e363e1..2a2209d2c 100644
--- a/core/sys/windows/userenv.odin
+++ b/core/sys/windows/userenv.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
foreign import userenv "system:Userenv.lib"
diff --git a/core/sys/windows/util.odin b/core/sys/windows/util.odin
index 929df1765..b3eb800bc 100644
--- a/core/sys/windows/util.odin
+++ b/core/sys/windows/util.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
import "base:runtime"
diff --git a/core/sys/windows/ux_theme.odin b/core/sys/windows/ux_theme.odin
index 7af399361..527abd62f 100644
--- a/core/sys/windows/ux_theme.odin
+++ b/core/sys/windows/ux_theme.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
foreign import uxtheme "system:UxTheme.lib"
diff --git a/core/sys/windows/wgl.odin b/core/sys/windows/wgl.odin
index d0d96d90b..8fea55c3d 100644
--- a/core/sys/windows/wgl.odin
+++ b/core/sys/windows/wgl.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
import "core:c"
diff --git a/core/sys/windows/wglext.odin b/core/sys/windows/wglext.odin
index 0c4b51d65..4c76b39ec 100644
--- a/core/sys/windows/wglext.odin
+++ b/core/sys/windows/wglext.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
// WGL_ARB_buffer_region
diff --git a/core/sys/windows/window_messages.odin b/core/sys/windows/window_messages.odin
index 888c5ccf9..d69771bdf 100644
--- a/core/sys/windows/window_messages.odin
+++ b/core/sys/windows/window_messages.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
WM_NULL :: 0x0000
diff --git a/core/sys/windows/winerror.odin b/core/sys/windows/winerror.odin
index 8882dad71..b3b470619 100644
--- a/core/sys/windows/winerror.odin
+++ b/core/sys/windows/winerror.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
// https://learn.microsoft.com/en-us/windows/win32/api/winerror/
@@ -213,6 +213,7 @@ ERROR_BROKEN_PIPE : DWORD : 109
ERROR_CALL_NOT_IMPLEMENTED : DWORD : 120
ERROR_INSUFFICIENT_BUFFER : DWORD : 122
ERROR_INVALID_NAME : DWORD : 123
+ERROR_NEGATIVE_SEEK : DWORD : 131
ERROR_BAD_ARGUMENTS : DWORD : 160
ERROR_LOCK_FAILED : DWORD : 167
ERROR_ALREADY_EXISTS : DWORD : 183
diff --git a/core/sys/windows/winmm.odin b/core/sys/windows/winmm.odin
index a1786c27a..3c7ec80e7 100644
--- a/core/sys/windows/winmm.odin
+++ b/core/sys/windows/winmm.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
foreign import winmm "system:Winmm.lib"
diff --git a/core/sys/windows/winnls.odin b/core/sys/windows/winnls.odin
index 292d2fad2..ffb2638d5 100644
--- a/core/sys/windows/winnls.odin
+++ b/core/sys/windows/winnls.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
LCTYPE :: distinct DWORD
diff --git a/core/sys/windows/winver.odin b/core/sys/windows/winver.odin
index 091d53d3a..47751dab7 100644
--- a/core/sys/windows/winver.odin
+++ b/core/sys/windows/winver.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
foreign import version "system:version.lib"
diff --git a/core/sys/windows/wow64_apiset.odin b/core/sys/windows/wow64_apiset.odin
index 28558e9ca..3d29b786e 100644
--- a/core/sys/windows/wow64_apiset.odin
+++ b/core/sys/windows/wow64_apiset.odin
@@ -1,4 +1,4 @@
-//+build windows
+#+build windows
package sys_windows
foreign import kernel32 "system:Kernel32.lib"
diff --git a/core/sys/windows/ws2_32.odin b/core/sys/windows/ws2_32.odin
index e9bf8abc9..5b2952495 100644
--- a/core/sys/windows/ws2_32.odin
+++ b/core/sys/windows/ws2_32.odin
@@ -1,4 +1,4 @@
-// +build windows
+#+build windows
package sys_windows
// Define flags to be used with the WSAAsyncSelect() call.