Browse Source

Merge branch 'odin-lang:master' into master

avanspector 7 months ago
parent
commit
be7799459b
92 changed files with 2711 additions and 1190 deletions
  1. 2 0
      base/builtin/builtin.odin
  2. 4 2
      base/intrinsics/intrinsics.odin
  3. 60 3
      base/runtime/core_builtin.odin
  4. 34 11
      base/runtime/dynamic_map_internal.odin
  5. 2 2
      build_odin.sh
  6. 230 148
      core/encoding/base32/base32.odin
  7. 227 0
      core/encoding/base32/base32_test.odin
  8. 2 2
      core/encoding/json/unmarshal.odin
  9. 1 1
      core/image/general.odin
  10. 1 129
      core/image/png/helpers.odin
  11. 7 3
      core/io/util.odin
  12. 66 18
      core/math/linalg/general.odin
  13. 66 18
      core/math/linalg/glsl/linalg_glsl.odin
  14. 66 18
      core/math/linalg/hlsl/linalg_hlsl.odin
  15. 0 24
      core/math/rand/rand.odin
  16. 0 23
      core/mem/allocators.odin
  17. 1 8
      core/mem/mem.odin
  18. 2 1
      core/mem/virtual/arena.odin
  19. 1 1
      core/os/os2/file.odin
  20. 27 54
      core/os/os2/file_linux.odin
  21. 29 20
      core/os/os2/file_posix.odin
  22. 37 16
      core/os/os2/file_windows.odin
  23. 1 1
      core/os/os2/heap_linux.odin
  24. 0 2
      core/os/os2/path_linux.odin
  25. 2 2
      core/os/os2/pipe_linux.odin
  26. 2 2
      core/os/os2/pipe_posix.odin
  27. 10 1
      core/os/os2/process.odin
  28. 11 36
      core/os/os2/process_linux.odin
  29. 2 0
      core/prof/spall/doc.odin
  30. 59 37
      core/sys/linux/bits.odin
  31. 2 2
      core/sys/linux/helpers.odin
  32. 25 15
      core/sys/linux/sys.odin
  33. 166 66
      core/sys/linux/types.odin
  34. 21 1
      core/sys/windows/kernel32.odin
  35. 26 2
      core/sys/windows/types.odin
  36. 1 0
      core/sys/windows/user32.odin
  37. 153 141
      core/time/timezone/tz_windows.odin
  38. 1 0
      examples/demo/demo.odin
  39. 12 6
      src/build_settings.cpp
  40. 48 50
      src/check_decl.cpp
  41. 53 10
      src/check_expr.cpp
  42. 8 1
      src/check_type.cpp
  43. 51 1
      src/checker.cpp
  44. 2 0
      src/checker.hpp
  45. 1 0
      src/entity.cpp
  46. 0 2
      src/llvm_backend.cpp
  47. 8 1
      src/llvm_backend.hpp
  48. 11 5
      src/llvm_backend_expr.cpp
  49. 17 1
      src/llvm_backend_general.cpp
  50. 5 1
      src/llvm_backend_proc.cpp
  51. 52 29
      src/llvm_backend_stmt.cpp
  52. 20 7
      src/llvm_backend_utility.cpp
  53. 3 3
      src/main.cpp
  54. 67 3
      src/parser.cpp
  55. 2 0
      src/parser.hpp
  56. 1 0
      tests/core/encoding/cbor/test_core_cbor.odin
  57. 1 0
      tests/core/fmt/test_core_fmt.odin
  58. 1 0
      tests/core/hash/test_core_hash.odin
  59. 1 0
      tests/core/hash/test_vectors_xxhash.odin
  60. 1 0
      tests/core/image/test_core_image.odin
  61. 1 0
      tests/core/net/test_core_net.odin
  62. 99 1
      tests/core/runtime/test_core_runtime.odin
  63. 1 0
      tests/core/slice/test_core_slice.odin
  64. 1 0
      tests/issues/run.bat
  65. 1 0
      tests/issues/run.sh
  66. 198 0
      tests/issues/test_issue_4584.odin
  67. 1 0
      tests/issues/test_issue_829.odin
  68. 3 11
      vendor/box2d/box2d.odin
  69. 5 0
      vendor/box2d/build_box2d.sh
  70. 3 1
      vendor/box2d/wasm.Makefile
  71. 58 13
      vendor/cgltf/cgltf.odin
  72. BIN
      vendor/cgltf/lib/cgltf.lib
  73. BIN
      vendor/cgltf/lib/cgltf_wasm.o
  74. 338 200
      vendor/cgltf/src/cgltf.h
  75. 55 12
      vendor/cgltf/src/cgltf_write.h
  76. 2 2
      vendor/libc/include/math.h
  77. 2 2
      vendor/libc/math.odin
  78. 1 0
      vendor/libc/stdio.odin
  79. 5 0
      vendor/raylib/raygui.odin
  80. 5 0
      vendor/raylib/raylib.odin
  81. 1 1
      vendor/raylib/raymath.odin
  82. 6 1
      vendor/raylib/rlgl/rlgl.odin
  83. BIN
      vendor/raylib/wasm/libraygui.a
  84. BIN
      vendor/raylib/wasm/libraylib.a
  85. 34 12
      vendor/vulkan/_gen/create_vulkan_odin_wrapper.py
  86. 56 0
      vendor/vulkan/_gen/vulkan_xcb.h
  87. 56 0
      vendor/vulkan/_gen/vulkan_xlib.h
  88. 6 0
      vendor/vulkan/core.odin
  89. 4 0
      vendor/vulkan/enums.odin
  90. 16 0
      vendor/vulkan/procedures.odin
  91. 37 4
      vendor/vulkan/structs.odin
  92. 4 0
      vendor/x11/xlib/xlib.odin

+ 2 - 0
base/builtin/builtin.odin

@@ -1,6 +1,8 @@
 // This is purely for documentation
 // This is purely for documentation
 package builtin
 package builtin
 
 
+import "base:runtime"
+
 nil   :: nil
 nil   :: nil
 false :: 0!=0
 false :: 0!=0
 true  :: 0==0
 true  :: 0==0

+ 4 - 2
base/intrinsics/intrinsics.odin

@@ -2,6 +2,8 @@
 #+build ignore
 #+build ignore
 package intrinsics
 package intrinsics
 
 
+import "base:runtime"
+
 // Package-Related
 // Package-Related
 is_package_imported :: proc(package_name: string) -> bool ---
 is_package_imported :: proc(package_name: string) -> bool ---
 
 
@@ -72,7 +74,7 @@ prefetch_write_instruction :: proc(address: rawptr, #const locality: i32 /* 0..=
 prefetch_write_data        :: proc(address: rawptr, #const locality: i32 /* 0..=3 */) ---
 prefetch_write_data        :: proc(address: rawptr, #const locality: i32 /* 0..=3 */) ---
 
 
 // Compiler Hints
 // Compiler Hints
-expect :: proc(val, expected_val: T) -> T ---
+expect :: proc(val, expected_val: $T) -> T ---
 
 
 // Linux and Darwin Only
 // Linux and Darwin Only
 syscall :: proc(id: uintptr, args: ..uintptr) -> uintptr ---
 syscall :: proc(id: uintptr, args: ..uintptr) -> uintptr ---
@@ -219,7 +221,7 @@ type_map_cell_info :: proc($T: typeid)           -> ^runtime.Map_Cell_Info ---
 type_convert_variants_to_pointers :: proc($T: typeid) -> typeid where type_is_union(T) ---
 type_convert_variants_to_pointers :: proc($T: typeid) -> typeid where type_is_union(T) ---
 type_merge :: proc($U, $V: typeid) -> typeid where type_is_union(U), type_is_union(V) ---
 type_merge :: proc($U, $V: typeid) -> typeid where type_is_union(U), type_is_union(V) ---
 
 
-type_has_shared_fields :: proc($U, $V: typeid) -> bool typeid where type_is_struct(U), type_is_struct(V) ---
+type_has_shared_fields :: proc($U, $V: typeid) -> bool where type_is_struct(U), type_is_struct(V) ---
 
 
 constant_utf16_cstring :: proc($literal: string) -> [^]u16 ---
 constant_utf16_cstring :: proc($literal: string) -> [^]u16 ---
 
 

+ 60 - 3
base/runtime/core_builtin.odin

@@ -826,10 +826,12 @@ _resize_dynamic_array :: #force_inline proc(a: ^Raw_Dynamic_Array, size_of_elem,
 		return nil
 		return nil
 	}
 	}
 
 
+	if should_zero && a.len < length {
+		num_reused := min(a.cap, length) - a.len
+		intrinsics.mem_zero(([^]byte)(a.data)[a.len*size_of_elem:], num_reused*size_of_elem)
+	}
+
 	if length <= a.cap {
 	if length <= a.cap {
-		if should_zero && a.len < length {
-			intrinsics.mem_zero(([^]byte)(a.data)[a.len*size_of_elem:], (length-a.len)*size_of_elem)
-		}
 		a.len = max(length, 0)
 		a.len = max(length, 0)
 		return nil
 		return nil
 	}
 	}
@@ -936,6 +938,32 @@ map_upsert :: proc(m: ^$T/map[$K]$V, key: K, value: V, loc := #caller_location)
 	return
 	return
 }
 }
 
 
+/*
+Retrieves a pointer to the key and value for a possibly just inserted entry into the map.
+
+If the `key` was not in the map `m`, an entry is inserted with the zero value and `just_inserted` will be `true`.
+Otherwise the existing entry is left untouched and pointers to its key and value are returned.
+
+If the map has to grow in order to insert the entry and the allocation fails, `err` is set and returned.
+
+If `err` is `nil`, `key_ptr` and `value_ptr` are valid pointers and will not be `nil`.
+
+WARN: User modification of the key pointed at by `key_ptr` should only be done if the new key is equal to (in hash) the old key.
+If that is not the case you will corrupt the map.
+*/
+@(builtin, require_results)
+map_entry :: proc(m: ^$T/map[$K]$V, key: K, loc := #caller_location) -> (key_ptr: ^K, value_ptr: ^V, just_inserted: bool, err: Allocator_Error) {
+	key := key
+	zero: V
+
+	_key_ptr, _value_ptr: rawptr
+	_key_ptr, _value_ptr, just_inserted, err = __dynamic_map_entry((^Raw_Map)(m), map_info(T), &key, &zero, loc)
+
+	key_ptr   = (^K)(_key_ptr)
+	value_ptr = (^V)(_value_ptr)
+	return
+}
+
 
 
 @builtin
 @builtin
 card :: proc "contextless" (s: $S/bit_set[$E; $U]) -> int {
 card :: proc "contextless" (s: $S/bit_set[$E; $U]) -> int {
@@ -964,6 +992,24 @@ assert :: proc(condition: bool, message := #caller_expression(condition), loc :=
 	}
 	}
 }
 }
 
 
+// Evaluates the condition and aborts the program iff the condition is
+// false.  This routine ignores `ODIN_DISABLE_ASSERT`, and will always
+// execute.
+@builtin
+ensure :: proc(condition: bool, message := #caller_expression(condition), loc := #caller_location) {
+	if !condition {
+		@(cold)
+		internal :: proc(message: string, loc: Source_Code_Location) {
+			p := context.assertion_failure_proc
+			if p == nil {
+				p = default_assertion_failure_proc
+			}
+			p("unsatisfied ensure", message, loc)
+		}
+		internal(message, loc)
+	}
+}
+
 @builtin
 @builtin
 panic :: proc(message: string, loc := #caller_location) -> ! {
 panic :: proc(message: string, loc := #caller_location) -> ! {
 	p := context.assertion_failure_proc
 	p := context.assertion_failure_proc
@@ -999,6 +1045,17 @@ assert_contextless :: proc "contextless" (condition: bool, message := #caller_ex
 	}
 	}
 }
 }
 
 
+@builtin
+ensure_contextless :: proc "contextless" (condition: bool, message := #caller_expression(condition), loc := #caller_location) {
+	if !condition {
+		@(cold)
+		internal :: proc "contextless" (message: string, loc: Source_Code_Location) {
+			default_assertion_contextless_failure_proc("unsatisfied ensure", message, loc)
+		}
+		internal(message, loc)
+	}
+}
+
 @builtin
 @builtin
 panic_contextless :: proc "contextless" (message: string, loc := #caller_location) -> ! {
 panic_contextless :: proc "contextless" (message: string, loc := #caller_location) -> ! {
 	default_assertion_contextless_failure_proc("panic", message, loc)
 	default_assertion_contextless_failure_proc("panic", message, loc)

+ 34 - 11
base/runtime/dynamic_map_internal.odin

@@ -158,21 +158,21 @@ map_cell_index_static :: #force_inline proc "contextless" (cells: [^]Map_Cell($T
 	} else when (N & (N - 1)) == 0 && N <= 8*size_of(uintptr) {
 	} else when (N & (N - 1)) == 0 && N <= 8*size_of(uintptr) {
 		// Likely case, N is a power of two because T is a power of two.
 		// Likely case, N is a power of two because T is a power of two.
 
 
+		// Unique case, no need to index data here since only one element.
+		when N == 1 {
+			return &cells[index].data[0]
+		}
+
 		// Compute the integer log 2 of N, this is the shift amount to index the
 		// Compute the integer log 2 of N, this is the shift amount to index the
 		// correct cell. Odin's intrinsics.count_leading_zeros does not produce a
 		// correct cell. Odin's intrinsics.count_leading_zeros does not produce a
 		// constant, hence this approach. We only need to check up to N = 64.
 		// constant, hence this approach. We only need to check up to N = 64.
-		SHIFT :: 1 when N < 2  else
-		         2 when N < 4  else
-		         3 when N < 8  else
-		         4 when N < 16 else
-		         5 when N < 32 else 6
+		SHIFT :: 1 when N == 2  else
+		         2 when N == 4  else
+		         3 when N == 8  else
+		         4 when N == 16 else
+		         5 when N == 32 else 6
 		#assert(SHIFT <= MAP_CACHE_LINE_LOG2)
 		#assert(SHIFT <= MAP_CACHE_LINE_LOG2)
-		// Unique case, no need to index data here since only one element.
-		when N == 1 {
-			return &cells[index >> SHIFT].data[0]
-		} else {
-			return &cells[index >> SHIFT].data[index & (N - 1)]
-		}
+		return &cells[index >> SHIFT].data[index & (N - 1)]
 	} else {
 	} else {
 		// Least likely (and worst case), we pay for a division operation but we
 		// Least likely (and worst case), we pay for a division operation but we
 		// assume the compiler does not actually generate a division. N will be in the
 		// assume the compiler does not actually generate a division. N will be in the
@@ -941,6 +941,29 @@ __dynamic_map_set_extra :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^
 	return nil, rawptr(result)
 	return nil, rawptr(result)
 }
 }
 
 
+__dynamic_map_entry :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_Info, key: rawptr, zero: rawptr, loc := #caller_location) -> (key_ptr: rawptr, value_ptr: rawptr, just_inserted: bool, err: Allocator_Error) {
+	hash := info.key_hasher(key, map_seed(m^))
+
+	if key_ptr, value_ptr = __dynamic_map_get_key_and_value(m, info, hash, key); value_ptr != nil {
+		return
+	}
+
+	has_grown: bool
+	if err, has_grown = __dynamic_map_check_grow(m, info, loc); err != nil {
+		return
+	} else if has_grown {
+		hash = info.key_hasher(key, map_seed(m^))
+	}
+
+	value_ptr = rawptr(map_insert_hash_dynamic(m, info, hash, uintptr(key), uintptr(zero)))
+	assert(value_ptr != nil)
+	key_ptr = rawptr(map_cell_index_dynamic(map_data(m^), info.ks, map_desired_position(m^, hash)))
+
+	m.len += 1
+	just_inserted = true
+	return
+}
+
 
 
 // IMPORTANT: USED WITHIN THE COMPILER
 // IMPORTANT: USED WITHIN THE COMPILER
 @(private)
 @(private)

+ 2 - 2
build_odin.sh

@@ -110,8 +110,8 @@ Linux)
 	LDFLAGS="$LDFLAGS -Wl,-rpath=\$ORIGIN"
 	LDFLAGS="$LDFLAGS -Wl,-rpath=\$ORIGIN"
 	;;
 	;;
 OpenBSD)
 OpenBSD)
-	CXXFLAGS="$CXXFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
-	LDFLAGS="$LDFLAGS -liconv"
+	CXXFLAGS="$CXXFLAGS -I/usr/local/include $($LLVM_CONFIG --cxxflags --ldflags)"
+	LDFLAGS="$LDFLAGS -L/usr/local/lib -liconv"
 	LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs)"
 	LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs)"
 	;;
 	;;
 Haiku)
 Haiku)

+ 230 - 148
core/encoding/base32/base32.odin

@@ -1,148 +1,230 @@
-package encoding_base32
-
-// @note(zh): Encoding utility for Base32
-// A secondary param can be used to supply a custom alphabet to
-// @link(encode) and a matching decoding table to @link(decode).
-// If none is supplied it just uses the standard Base32 alphabet.
-// Incase your specific version does not use padding, you may
-// truncate it from the encoded output.
-
-ENC_TABLE := [32]byte {
-	'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
-	'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
-	'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
-	'Y', 'Z', '2', '3', '4', '5', '6', '7',
-}
-
-PADDING :: '='
-
-DEC_TABLE := [?]u8 {
-	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-	 0,  0, 26, 27, 28, 29, 30, 31,  0,  0,  0,  0,  0,  0,  0,  0,
-	 0,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
-	15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,  0,  0,  0,  0,  0,
-	 0,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
-	15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,  0,  0,  0,  0,  0,
-	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-}
-
-encode :: proc(data: []byte, ENC_TBL := ENC_TABLE, allocator := context.allocator) -> string {
-	out_length := (len(data) + 4) / 5 * 8
-	out := make([]byte, out_length)
-	_encode(out, data)
-	return string(out)
-}
-
-@private
-_encode :: proc(out, data: []byte, ENC_TBL := ENC_TABLE, allocator := context.allocator) {
-	out := out
-	data := data
-
-	for len(data) > 0 {
-		carry: byte
-		switch len(data) {
-		case:
-			out[7] = ENC_TABLE[data[4] & 0x1f]
-			carry = data[4] >> 5
-			fallthrough
-		case 4:
-			out[6] = ENC_TABLE[carry | (data[3] << 3) & 0x1f]
-			out[5] = ENC_TABLE[(data[3] >> 2) & 0x1f]
-			carry = data[3] >> 7
-			fallthrough
-		case 3:
-			out[4] = ENC_TABLE[carry | (data[2] << 1) & 0x1f]
-			carry = (data[2] >> 4) & 0x1f
-			fallthrough
-		case 2:
-			out[3] = ENC_TABLE[carry | (data[1] << 4) & 0x1f]
-			out[2] = ENC_TABLE[(data[1] >> 1) & 0x1f]
-			carry = (data[1] >> 6) & 0x1f
-			fallthrough
-		case 1:
-			out[1] = ENC_TABLE[carry | (data[0] << 2) & 0x1f]
-			out[0] = ENC_TABLE[data[0] >> 3]
-		}
-
-		if len(data) < 5 {
-			out[7] = byte(PADDING)
-			if len(data) < 4 {
-				out[6] = byte(PADDING)
-				out[5] = byte(PADDING)
-				if len(data) < 3 {
-					out[4] = byte(PADDING)
-					if len(data) < 2 {
-						out[3] = byte(PADDING)
-						out[2] = byte(PADDING)
-					}
-				}
-			}
-			break
-		}
-		data = data[5:]
-		out = out[8:]
-	}
-}
-
-decode :: proc(data: string, DEC_TBL := DEC_TABLE, allocator := context.allocator) -> []byte #no_bounds_check{
-	if len(data) == 0 {
-		return nil
-	}
-
-	outi := 0
-	data := data
-
-	out := make([]byte, len(data) / 8 * 5, allocator)
-	end := false
-	for len(data) > 0 && !end {
-		dbuf : [8]byte
-		dlen := 8
-
-		for j := 0; j < 8; {
-			if len(data) == 0 {
-				dlen, end = j, true
-				break
-			}
-			input := data[0]
-			data = data[1:]
-			if input == byte(PADDING) && j >= 2 && len(data) < 8 {
-				assert(!(len(data) + j < 8 - 1), "Corrupted input")
-				for k := 0; k < 8-1-j; k +=1 {
-					assert(len(data) < k || data[k] == byte(PADDING), "Corrupted input")
-				}
-				dlen, end = j, true
-				assert(dlen != 1 && dlen != 3 && dlen != 6, "Corrupted input")
-				break
-			}
-			dbuf[j] = DEC_TABLE[input]
-			assert(dbuf[j] != 0xff, "Corrupted input")
-			j += 1
-		}
-
-		switch dlen {
-		case 8:
-			out[outi + 4] = dbuf[6] << 5 | dbuf[7]
-			fallthrough
-		case 7:
-			out[outi + 3] = dbuf[4] << 7 | dbuf[5] << 2 | dbuf[6] >> 3
-			fallthrough
-		case 5:
-			out[outi + 2] = dbuf[3] << 4 | dbuf[4] >> 1
-			fallthrough
-		case 4:
-			out[outi + 1] = dbuf[1] << 6 | dbuf[2] << 1 | dbuf[3] >> 4
-			fallthrough
-		case 2:
-			out[outi + 0] = dbuf[0] << 3 | dbuf[1] >> 2
-		}
-		outi += 5
-	}
-	return out
-}
+// Base32 encoding/decoding implementation as specified in RFC 4648.
+// [[ More; https://www.rfc-editor.org/rfc/rfc4648.html ]]
+package encoding_base32
+
+// @note(zh): Encoding utility for Base32
+// A secondary param can be used to supply a custom alphabet to
+// @link(encode) and a matching decoding table to @link(decode).
+// If none is supplied it just uses the standard Base32 alphabet.
+// In case your specific version does not use padding, you may
+// truncate it from the encoded output.
+
+// Error represents errors that can occur during base32 decoding operations.
+// As per RFC 4648:
+// - Section 3.3: Invalid character handling
+// - Section 3.2: Padding requirements
+// - Section 6: Base32 encoding specifics (including block size requirements)
+Error :: enum {
+	None,
+	Invalid_Character, // Input contains characters outside the specified alphabet
+	Invalid_Length,    // Input length is not valid for base32 (must be a multiple of 8 with proper padding)
+	Malformed_Input,   // Input has improper structure (wrong padding position or incomplete groups)
+}
+
+Validate_Proc :: #type proc(c: byte) -> bool
+
+@private
+_validate_default :: proc(c: byte) -> bool {
+	return (c >= 'A' && c <= 'Z') || (c >= '2' && c <= '7')
+}
+
+@(rodata)
+ENC_TABLE := [32]byte {
+	'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
+	'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
+	'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
+	'Y', 'Z', '2', '3', '4', '5', '6', '7',
+}
+
+PADDING :: '='
+
+@(rodata)
+DEC_TABLE := [256]u8 {
+	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	 0,  0, 26, 27, 28, 29, 30, 31,  0,  0,  0,  0,  0,  0,  0,  0,
+	 0,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
+	15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,  0,  0,  0,  0,  0,
+	 0,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
+	15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,  0,  0,  0,  0,  0,
+	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+}
+
+encode :: proc(data: []byte, ENC_TBL := ENC_TABLE, allocator := context.allocator) -> string {
+	out_length := (len(data) + 4) / 5 * 8
+	out := make([]byte, out_length, allocator)
+	_encode(out, data, ENC_TBL)
+	return string(out[:])
+}
+
+@private
+_encode :: proc(out, data: []byte, ENC_TBL := ENC_TABLE, allocator := context.allocator) {
+	out := out
+	data := data
+
+	for len(data) > 0 {
+		carry: byte
+		switch len(data) {
+		case:
+			out[7] = ENC_TBL[data[4] & 0x1f]
+			carry = data[4] >> 5
+			fallthrough
+		case 4:
+			out[6] = ENC_TBL[carry | (data[3] << 3) & 0x1f]
+			out[5] = ENC_TBL[(data[3] >> 2) & 0x1f]
+			carry = data[3] >> 7
+			fallthrough
+		case 3:
+			out[4] = ENC_TBL[carry | (data[2] << 1) & 0x1f]
+			carry = (data[2] >> 4) & 0x1f
+			fallthrough
+		case 2:
+			out[3] = ENC_TBL[carry | (data[1] << 4) & 0x1f]
+			out[2] = ENC_TBL[(data[1] >> 1) & 0x1f]
+			carry = (data[1] >> 6) & 0x1f
+			fallthrough
+		case 1:
+			out[1] = ENC_TBL[carry | (data[0] << 2) & 0x1f]
+			out[0] = ENC_TBL[data[0] >> 3]
+		}
+
+		if len(data) < 5 {
+			out[7] = byte(PADDING)
+			if len(data) < 4 {
+				out[6] = byte(PADDING)
+				out[5] = byte(PADDING)
+				if len(data) < 3 {
+					out[4] = byte(PADDING)
+					if len(data) < 2 {
+						out[3] = byte(PADDING)
+						out[2] = byte(PADDING)
+					}
+				}
+			}
+			break
+		}
+		data = data[5:]
+		out = out[8:]
+	}
+}
+
+@(optimization_mode="favor_size")
+decode :: proc(
+  data: string,
+  DEC_TBL := DEC_TABLE,
+  validate: Validate_Proc = _validate_default,
+  allocator := context.allocator) -> (out: []byte, err: Error) {
+	if len(data) == 0 {
+		return nil, .None
+	}
+
+	// Check minimum length requirement first
+	if len(data) < 2 {
+		return nil, .Invalid_Length
+	}
+
+	// Validate characters using provided validation function
+	for i := 0; i < len(data); i += 1 {
+		c := data[i]
+		if c == byte(PADDING) {
+			break
+		}
+		if !validate(c) {
+			return nil, .Invalid_Character
+		}
+	}
+
+	// Validate padding and length
+	data_len := len(data)
+	padding_count := 0
+	for i := data_len - 1; i >= 0; i -= 1 {
+		if data[i] != byte(PADDING) {
+			break
+		}
+		padding_count += 1
+	}
+
+	// Check for proper padding and length combinations
+	if padding_count > 0 {
+		// Verify no padding in the middle
+		for i := 0; i < data_len - padding_count; i += 1 {
+			if data[i] == byte(PADDING) {
+				return nil, .Malformed_Input
+			}
+		}
+
+		content_len := data_len - padding_count
+		mod8 := content_len % 8
+		required_padding: int
+		switch mod8 {
+		case 2: required_padding = 6 // 2 chars need 6 padding chars
+		case 4: required_padding = 4 // 4 chars need 4 padding chars
+		case 5: required_padding = 3 // 5 chars need 3 padding chars
+		case 7: required_padding = 1 // 7 chars need 1 padding char
+		case: required_padding = 0
+		}
+
+		if required_padding > 0 {
+			if padding_count != required_padding {
+				return nil, .Malformed_Input
+			}
+		} else if mod8 != 0 {
+			return nil, .Malformed_Input
+		}
+	} else {
+		// No padding - must be multiple of 8
+		if data_len % 8 != 0 {
+			return nil, .Malformed_Input
+		}
+	}
+
+	// Calculate decoded length: 5 bytes for every 8 input chars
+	input_chars := data_len - padding_count
+	out_len := input_chars * 5 / 8
+	out = make([]byte, out_len, allocator)
+	defer if err != .None {
+		delete(out)
+	}
+
+	// Process input in 8-byte blocks
+	outi := 0
+	for i := 0; i < input_chars; i += 8 {
+		buf: [8]byte
+		block_size := min(8, input_chars - i)
+
+		// Decode block
+		for j := 0; j < block_size; j += 1 {
+			buf[j] = DEC_TBL[data[i + j]]
+		}
+
+		// Convert to output bytes based on block size
+		bytes_to_write := block_size * 5 / 8
+		switch block_size {
+		case 8:
+			out[outi + 4] = (buf[6] << 5) | buf[7]
+			fallthrough
+		case 7:
+			out[outi + 3] = (buf[4] << 7) | (buf[5] << 2) | (buf[6] >> 3)
+			fallthrough
+		case 5:
+			out[outi + 2] = (buf[3] << 4) | (buf[4] >> 1)
+			fallthrough
+		case 4:
+			out[outi + 1] = (buf[1] << 6) | (buf[2] << 1) | (buf[3] >> 4)
+			fallthrough
+		case 2:
+			out[outi] = (buf[0] << 3) | (buf[1] >> 2)
+		}
+		outi += bytes_to_write
+	}
+
+	return
+}

+ 227 - 0
core/encoding/base32/base32_test.odin

@@ -0,0 +1,227 @@
+package encoding_base32
+
+import "core:testing"
+import "core:bytes"
+
+@(test)
+test_base32_decode_valid :: proc(t: ^testing.T) {
+	// RFC 4648 Section 10 - Test vectors
+	cases := [?]struct {
+		input, expected: string,
+	}{
+		{"", ""},
+		{"MY======", "f"},
+		{"MZXQ====", "fo"},
+		{"MZXW6===", "foo"},
+		{"MZXW6YQ=", "foob"},
+		{"MZXW6YTB", "fooba"},
+		{"MZXW6YTBOI======", "foobar"},
+	}
+
+	for c in cases {
+		output, err := decode(c.input)
+		if output != nil {
+			defer delete(output)
+		}
+		testing.expect_value(t, err, Error.None)
+		expected := transmute([]u8)c.expected
+		if output != nil {
+			testing.expect(t, bytes.equal(output, expected))
+		} else {
+			testing.expect(t, len(c.expected) == 0)
+		}
+	}
+}
+
+@(test)
+test_base32_encode :: proc(t: ^testing.T) {
+	// RFC 4648 Section 10 - Test vectors
+	cases := [?]struct {
+		input, expected: string,
+	}{
+		{"", ""},
+		{"f", "MY======"},
+		{"fo", "MZXQ===="},
+		{"foo", "MZXW6==="},
+		{"foob", "MZXW6YQ="},
+		{"fooba", "MZXW6YTB"},
+		{"foobar", "MZXW6YTBOI======"},
+	}
+
+	for c in cases {
+		output := encode(transmute([]byte)c.input)
+		defer delete(output)
+		testing.expect(t, output == c.expected)
+	}
+}
+
+@(test)
+test_base32_decode_invalid :: proc(t: ^testing.T) {
+	// Section 3.3 - Non-alphabet characters
+	{
+		// Characters outside alphabet
+		input := "MZ1W6YTB" // '1' not in alphabet (A-Z, 2-7)
+		output, err := decode(input)
+		if output != nil {
+			defer delete(output)
+		}
+		testing.expect_value(t, err, Error.Invalid_Character)
+	}
+	{
+		// Lowercase not allowed
+		input := "mzxq===="
+		output, err := decode(input)
+		if output != nil {
+			defer delete(output)
+		}
+		testing.expect_value(t, err, Error.Invalid_Character)
+	}
+
+	// Section 3.2 - Padding requirements
+	{
+		// Padding must only be at end
+		input := "MZ=Q===="
+		output, err := decode(input)
+		if output != nil {
+			defer delete(output)
+		}
+		testing.expect_value(t, err, Error.Malformed_Input)
+	}
+	{
+		// Missing padding
+		input := "MZXQ" // Should be MZXQ====
+		output, err := decode(input)
+		if output != nil {
+			defer delete(output)
+		}
+		testing.expect_value(t, err, Error.Malformed_Input)
+	}
+	{
+		// Incorrect padding length
+		input := "MZXQ=" // Needs 4 padding chars
+		output, err := decode(input)
+		if output != nil {
+			defer delete(output)
+		}
+		testing.expect_value(t, err, Error.Malformed_Input)
+	}
+	{
+		// Too much padding
+		input := "MY=========" // Extra padding chars
+		output, err := decode(input)
+		if output != nil {
+			defer delete(output)
+		}
+		testing.expect_value(t, err, Error.Malformed_Input)
+	}
+
+	// Section 6 - Base32 block size requirements
+	{
+		// Single character (invalid block)
+		input := "M"
+		output, err := decode(input)
+		if output != nil {
+			defer delete(output)
+		}
+		testing.expect_value(t, err, Error.Invalid_Length)
+	}
+}
+
+@(test)
+test_base32_roundtrip :: proc(t: ^testing.T) {
+	cases := [?]string{
+		"",
+		"f",
+		"fo",
+		"foo",
+		"foob",
+		"fooba",
+		"foobar",
+	}
+
+	for input in cases {
+		encoded := encode(transmute([]byte)input)
+		defer delete(encoded)
+		decoded, err := decode(encoded)
+		if decoded != nil {
+			defer delete(decoded)
+		}
+		testing.expect_value(t, err, Error.None)
+		testing.expect(t, bytes.equal(decoded, transmute([]byte)input))
+	}
+}
+
+@(test)
+test_base32_custom_alphabet :: proc(t: ^testing.T) {
+	custom_enc_table := [32]byte{
+		'0', '1', '2', '3', '4', '5', '6', '7',
+		'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
+		'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
+		'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
+	}
+
+	custom_dec_table: [256]u8
+	for i := 0; i < len(custom_enc_table); i += 1 {
+		custom_dec_table[custom_enc_table[i]] = u8(i)
+	}
+
+	/*
+	custom_dec_table := [256]u8{
+		0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, // 0x00-0x0f
+		0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, // 0x10-0x1f
+		0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, // 0x20-0x2f
+		0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  0,  0,  0,  0,  0,  0, // 0x30-0x3f ('0'-'9')
+		0, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, // 0x40-0x4f ('A'-'O')
+	 25, 26, 27, 28, 29, 30, 31,  0,  0,  0,  0,  0,  0,  0,  0,  0, // 0x50-0x5f ('P'-'V')
+		0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, // 0x60-0x6f
+		0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, // 0x70-0x7f
+		0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, // 0x80-0x8f
+		0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, // 0x90-0x9f
+		0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, // 0xa0-0xaf
+		0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, // 0xb0-0xbf
+		0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, // 0xc0-0xcf
+		0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, // 0xd0-0xdf
+		0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, // 0xe0-0xef
+		0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, // 0xf0-0xff
+	}
+	*/
+
+	custom_validate :: proc(c: byte) -> bool {
+		return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'V') || c == byte(PADDING)
+	}
+
+	cases := [?]struct {
+		input: string,
+		enc_expected: string,
+	}{
+		{"f", "CO======"},
+		{"fo", "CPNG===="},
+		{"foo", "CPNMU==="},
+	}
+
+	for c in cases {
+		// Test encoding
+		encoded := encode(transmute([]byte)c.input, custom_enc_table)
+		defer delete(encoded)
+		testing.expect(t, encoded == c.enc_expected)
+
+		// Test decoding
+		decoded, err := decode(encoded, custom_dec_table, custom_validate)
+		defer if decoded != nil {
+			delete(decoded)
+		}
+
+		testing.expect_value(t, err, Error.None)
+		testing.expect(t, bytes.equal(decoded, transmute([]byte)c.input))
+	}
+
+	// Test invalid character detection
+	{
+		input := "WXY=====" // Contains chars not in our alphabet
+		output, err := decode(input, custom_dec_table, custom_validate)
+		if output != nil {
+			delete(output)
+		}
+		testing.expect_value(t, err, Error.Invalid_Character)
+	}
+}

+ 2 - 2
core/encoding/json/unmarshal.odin

@@ -439,7 +439,7 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm
 			use_field_idx := -1
 			use_field_idx := -1
 			
 			
 			for field, field_idx in fields {
 			for field, field_idx in fields {
-				tag_value := string(reflect.struct_tag_get(field.tag, "json"))
+				tag_value := reflect.struct_tag_get(field.tag, "json")
 				json_name, _ := json_name_from_tag_value(tag_value)
 				json_name, _ := json_name_from_tag_value(tag_value)
 				if key == json_name {
 				if key == json_name {
 					use_field_idx = field_idx
 					use_field_idx = field_idx
@@ -470,7 +470,7 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm
 						}
 						}
 					}
 					}
 
 
-					if field.name == key {
+					if field.name == key || (field.tag != "" && reflect.struct_tag_get(field.tag, "json") == key) {
 						offset = field.offset
 						offset = field.offset
 						type = field.type
 						type = field.type
 						found = true
 						found = true

+ 1 - 1
core/image/general.odin

@@ -146,7 +146,7 @@ which_bytes :: proc(data: []byte) -> Which_File_Type {
 	case s[6:10] == "JFIF", s[6:10] == "Exif":
 	case s[6:10] == "JFIF", s[6:10] == "Exif":
 		return .JPEG
 		return .JPEG
 	case s[:3] == "\xff\xd8\xff":
 	case s[:3] == "\xff\xd8\xff":
-		switch s[4] {
+		switch s[3] {
 		case 0xdb, 0xee, 0xe1, 0xe0:
 		case 0xdb, 0xee, 0xe1, 0xe0:
 			return .JPEG
 			return .JPEG
 		}
 		}

+ 1 - 129
core/image/png/helpers.odin

@@ -396,132 +396,4 @@ exif :: proc(c: image.PNG_Chunk) -> (res: Exif, ok: bool) {
 	General helper functions
 	General helper functions
 */
 */
 
 
-compute_buffer_size :: image.compute_buffer_size
-
-/*
-	PNG save helpers
-*/
-
-when false {
-
-	make_chunk :: proc(c: any, t: Chunk_Type) -> (res: Chunk) {
-
-		data: []u8
-		if v, ok := c.([]u8); ok {
-			data = v
-		} else {
-			data = mem.any_to_bytes(c)
-		}
-
-		res.header.length = u32be(len(data))
-		res.header.type   = t
-		res.data   = data
-
-		// CRC the type
-		crc    := hash.crc32(mem.any_to_bytes(res.header.type))
-		// Extend the CRC with the data
-		res.crc = u32be(hash.crc32(data, crc))
-		return
-	}
-
-	write_chunk :: proc(fd: os.Handle, chunk: Chunk) {
-		c := chunk
-		// Write length + type
-		os.write_ptr(fd, &c.header, 8)
-		// Write data
-		os.write_ptr(fd, mem.raw_data(c.data), int(c.header.length))
-		// Write CRC32
-		os.write_ptr(fd, &c.crc, 4)
-	}
-
-	write_image_as_png :: proc(filename: string, image: Image) -> (err: Error) {
-		profiler.timed_proc()
-		using image
-		using os
-		flags: int = O_WRONLY|O_CREATE|O_TRUNC
-
-		if len(image.pixels) == 0 || len(image.pixels) < image.width * image.height * int(image.channels) {
-			return .Invalid_Image_Dimensions
-		}
-
-		mode: int = 0
-		when ODIN_OS == .Linux || ODIN_OS == .Darwin {
-			// NOTE(justasd): 644 (owner read, write; group read; others read)
-			mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
-		}
-
-		fd, fderr := open(filename, flags, mode)
-		if fderr != nil {
-			return .Cannot_Open_File
-		}
-		defer close(fd)
-
-		magic := Signature
-
-		write_ptr(fd, &magic, 8)
-
-		ihdr := IHDR{
-			width              = u32be(width),
-			height             = u32be(height),
-			bit_depth          = depth,
-			compression_method = 0,
-			filter_method      = 0,
-			interlace_method   = .None,
-		}
-
-		switch channels {
-		case 1: ihdr.color_type = Color_Type{}
-		case 2: ihdr.color_type = Color_Type{.Alpha}
-		case 3: ihdr.color_type = Color_Type{.Color}
-		case 4: ihdr.color_type = Color_Type{.Color, .Alpha}
-		case:// Unhandled
-			return .Unknown_Color_Type
-		}
-		h := make_chunk(ihdr, .IHDR)
-		write_chunk(fd, h)
-
-		bytes_needed := width * height * int(channels) + height
-		filter_bytes := mem.make_dynamic_array_len_cap([dynamic]u8, bytes_needed, bytes_needed, context.allocator)
-		defer delete(filter_bytes)
-
-		i := 0; j := 0
-		// Add a filter byte 0 per pixel row
-		for y := 0; y < height; y += 1 {
-			filter_bytes[j] = 0; j += 1
-			for x := 0; x < width; x += 1 {
-				for z := 0; z < channels; z += 1 {
-					filter_bytes[j+z] = image.pixels[i+z]
-				}
-				i += channels; j += channels
-			}
-		}
-		assert(j == bytes_needed)
-
-		a: []u8 = filter_bytes[:]
-
-		out_buf: ^[dynamic]u8
-		defer free(out_buf)
-
-		ctx := zlib.ZLIB_Context{
-			in_buf  = &a,
-			out_buf = out_buf,
-		}
-		err = zlib.write_zlib_stream_from_memory(&ctx)
-
-		b: []u8
-		if err == nil {
-			b = ctx.out_buf[:]
-		} else {
-			return err
-		}
-
-		idat := make_chunk(b, .IDAT)
-
-		write_chunk(fd, idat)
-
-		iend := make_chunk([]u8{}, .IEND)
-		write_chunk(fd, iend)
-
-		return nil
-	}
-}
+compute_buffer_size :: image.compute_buffer_size

+ 7 - 3
core/io/util.odin

@@ -132,9 +132,13 @@ write_encoded_rune :: proc(w: Writer, r: rune, write_quote := true, n_written: ^
 			buf: [2]byte
 			buf: [2]byte
 			s := strconv.append_bits(buf[:], u64(r), 16, true, 64, strconv.digits, nil)
 			s := strconv.append_bits(buf[:], u64(r), 16, true, 64, strconv.digits, nil)
 			switch len(s) {
 			switch len(s) {
-			case 0: write_string(w, "00", &n) or_return
-			case 1: write_byte(w, '0',    &n) or_return
-			case 2: write_string(w, s,    &n) or_return
+			case 0: 
+				write_string(w, "00", &n) or_return
+			case 1: 
+				write_byte(w, '0',    &n) or_return
+				fallthrough
+			case 2: 
+				write_string(w, s,    &n) or_return
 			}
 			}
 		} else {
 		} else {
 			write_rune(w, r, &n) or_return
 			write_rune(w, r, &n) or_return

+ 66 - 18
core/math/linalg/general.odin

@@ -417,6 +417,13 @@ adjugate :: proc{
 	matrix4x4_adjugate,
 	matrix4x4_adjugate,
 }
 }
 
 
+cofactor :: proc{
+	matrix1x1_cofactor,
+	matrix2x2_cofactor,
+	matrix3x3_cofactor,
+	matrix4x4_cofactor,
+}
+
 inverse_transpose :: proc{
 inverse_transpose :: proc{
 	matrix1x1_inverse_transpose,
 	matrix1x1_inverse_transpose,
 	matrix2x2_inverse_transpose,
 	matrix2x2_inverse_transpose,
@@ -479,9 +486,9 @@ matrix3x3_determinant :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (det: T) #
 }
 }
 @(require_results)
 @(require_results)
 matrix4x4_determinant :: proc "contextless" (m: $M/matrix[4, 4]$T) -> (det: T) #no_bounds_check {
 matrix4x4_determinant :: proc "contextless" (m: $M/matrix[4, 4]$T) -> (det: T) #no_bounds_check {
-	a := adjugate(m)
+	c := cofactor(m)
 	for i in 0..<4 {
 	for i in 0..<4 {
-		det += m[0, i] * a[0, i]
+		det += m[0, i] * c[0, i]
 	}
 	}
 	return
 	return
 }
 }
@@ -497,6 +504,47 @@ matrix1x1_adjugate :: proc "contextless" (x: $M/matrix[1, 1]$T) -> (y: M) #no_bo
 
 
 @(require_results)
 @(require_results)
 matrix2x2_adjugate :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) #no_bounds_check {
 matrix2x2_adjugate :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) #no_bounds_check {
+	y[0, 0] = +x[1, 1]
+	y[0, 1] = -x[0, 1]
+	y[1, 0] = -x[1, 0]
+	y[1, 1] = +x[0, 0]
+	return
+}
+
+@(require_results)
+matrix3x3_adjugate :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (y: M) #no_bounds_check {
+	y[0, 0] = +(m[1, 1] * m[2, 2] - m[2, 1] * m[1, 2])
+	y[1, 0] = -(m[1, 0] * m[2, 2] - m[2, 0] * m[1, 2])
+	y[2, 0] = +(m[1, 0] * m[2, 1] - m[2, 0] * m[1, 1])
+	y[0, 1] = -(m[0, 1] * m[2, 2] - m[2, 1] * m[0, 2])
+	y[1, 1] = +(m[0, 0] * m[2, 2] - m[2, 0] * m[0, 2])
+	y[2, 1] = -(m[0, 0] * m[2, 1] - m[2, 0] * m[0, 1])
+	y[0, 2] = +(m[0, 1] * m[1, 2] - m[1, 1] * m[0, 2])
+	y[1, 2] = -(m[0, 0] * m[1, 2] - m[1, 0] * m[0, 2])
+	y[2, 2] = +(m[0, 0] * m[1, 1] - m[1, 0] * m[0, 1])
+	return
+}
+
+@(require_results)
+matrix4x4_adjugate :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) #no_bounds_check {
+	for i in 0..<4 {
+		for j in 0..<4 {
+			sign: T = 1 if (i + j) % 2 == 0 else -1
+			y[i, j] = sign * matrix_minor(x, j, i)
+		}
+	}
+	return
+}
+
+
+@(require_results)
+matrix1x1_cofactor :: proc "contextless" (x: $M/matrix[1, 1]$T) -> (y: M) #no_bounds_check {
+	y = x
+	return
+}
+
+@(require_results)
+matrix2x2_cofactor :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) #no_bounds_check {
 	y[0, 0] = +x[1, 1]
 	y[0, 0] = +x[1, 1]
 	y[0, 1] = -x[1, 0]
 	y[0, 1] = -x[1, 0]
 	y[1, 0] = -x[0, 1]
 	y[1, 0] = -x[0, 1]
@@ -505,7 +553,7 @@ matrix2x2_adjugate :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) #no_bo
 }
 }
 
 
 @(require_results)
 @(require_results)
-matrix3x3_adjugate :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (y: M) #no_bounds_check {
+matrix3x3_cofactor :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (y: M) #no_bounds_check {
 	y[0, 0] = +(m[1, 1] * m[2, 2] - m[2, 1] * m[1, 2])
 	y[0, 0] = +(m[1, 1] * m[2, 2] - m[2, 1] * m[1, 2])
 	y[0, 1] = -(m[1, 0] * m[2, 2] - m[2, 0] * m[1, 2])
 	y[0, 1] = -(m[1, 0] * m[2, 2] - m[2, 0] * m[1, 2])
 	y[0, 2] = +(m[1, 0] * m[2, 1] - m[2, 0] * m[1, 1])
 	y[0, 2] = +(m[1, 0] * m[2, 1] - m[2, 0] * m[1, 1])
@@ -520,7 +568,7 @@ matrix3x3_adjugate :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (y: M) #no_bo
 
 
 
 
 @(require_results)
 @(require_results)
-matrix4x4_adjugate :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) #no_bounds_check {
+matrix4x4_cofactor :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) #no_bounds_check {
 	for i in 0..<4 {
 	for i in 0..<4 {
 		for j in 0..<4 {
 		for j in 0..<4 {
 			sign: T = 1 if (i + j) % 2 == 0 else -1
 			sign: T = 1 if (i + j) % 2 == 0 else -1
@@ -556,19 +604,19 @@ matrix2x2_inverse_transpose :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y:
 
 
 @(require_results)
 @(require_results)
 matrix3x3_inverse_transpose :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y: M) #no_bounds_check {
 matrix3x3_inverse_transpose :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y: M) #no_bounds_check {
-	a := adjugate(x)
+	c := cofactor(x)
 	d := determinant(x)
 	d := determinant(x)
 	when intrinsics.type_is_integer(T) {
 	when intrinsics.type_is_integer(T) {
 		for i in 0..<3 {
 		for i in 0..<3 {
 			for j in 0..<3 {
 			for j in 0..<3 {
-				y[i, j] = a[i, j] / d
+				y[i, j] = c[i, j] / d
 			}
 			}
 		}
 		}
 	} else {
 	} else {
 		id := 1/d
 		id := 1/d
 		for i in 0..<3 {
 		for i in 0..<3 {
 			for j in 0..<3 {
 			for j in 0..<3 {
-				y[i, j] = a[i, j] * id
+				y[i, j] = c[i, j] * id
 			}
 			}
 		}
 		}
 	}
 	}
@@ -577,22 +625,22 @@ matrix3x3_inverse_transpose :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y:
 
 
 @(require_results)
 @(require_results)
 matrix4x4_inverse_transpose :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) #no_bounds_check {
 matrix4x4_inverse_transpose :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) #no_bounds_check {
-	a := adjugate(x)
+	c := cofactor(x)
 	d: T
 	d: T
 	for i in 0..<4 {
 	for i in 0..<4 {
-		d += x[0, i] * a[0, i]
+		d += x[0, i] * c[0, i]
 	}
 	}
 	when intrinsics.type_is_integer(T) {
 	when intrinsics.type_is_integer(T) {
 		for i in 0..<4 {
 		for i in 0..<4 {
 			for j in 0..<4 {
 			for j in 0..<4 {
-				y[i, j] = a[i, j] / d
+				y[i, j] = c[i, j] / d
 			}
 			}
 		}
 		}
 	} else {
 	} else {
 		id := 1/d
 		id := 1/d
 		for i in 0..<4 {
 		for i in 0..<4 {
 			for j in 0..<4 {
 			for j in 0..<4 {
-				y[i, j] = a[i, j] * id
+				y[i, j] = c[i, j] * id
 			}
 			}
 		}
 		}
 	}
 	}
@@ -625,19 +673,19 @@ matrix2x2_inverse :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) #no_bou
 
 
 @(require_results)
 @(require_results)
 matrix3x3_inverse :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y: M) #no_bounds_check {
 matrix3x3_inverse :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y: M) #no_bounds_check {
-	a := adjugate(x)
+	c := cofactor(x)
 	d := determinant(x)
 	d := determinant(x)
 	when intrinsics.type_is_integer(T) {
 	when intrinsics.type_is_integer(T) {
 		for i in 0..<3 {
 		for i in 0..<3 {
 			for j in 0..<3 {
 			for j in 0..<3 {
-				y[i, j] = a[j, i] / d
+				y[i, j] = c[j, i] / d
 			}
 			}
 		}
 		}
 	} else {
 	} else {
 		id := 1/d
 		id := 1/d
 		for i in 0..<3 {
 		for i in 0..<3 {
 			for j in 0..<3 {
 			for j in 0..<3 {
-				y[i, j] = a[j, i] * id
+				y[i, j] = c[j, i] * id
 			}
 			}
 		}
 		}
 	}
 	}
@@ -646,22 +694,22 @@ matrix3x3_inverse :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y: M) #no_bou
 
 
 @(require_results)
 @(require_results)
 matrix4x4_inverse :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) #no_bounds_check {
 matrix4x4_inverse :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) #no_bounds_check {
-	a := adjugate(x)
+	c := cofactor(x)
 	d: T
 	d: T
 	for i in 0..<4 {
 	for i in 0..<4 {
-		d += x[0, i] * a[0, i]
+		d += x[0, i] * c[0, i]
 	}
 	}
 	when intrinsics.type_is_integer(T) {
 	when intrinsics.type_is_integer(T) {
 		for i in 0..<4 {
 		for i in 0..<4 {
 			for j in 0..<4 {
 			for j in 0..<4 {
-				y[i, j] = a[j, i] / d
+				y[i, j] = c[j, i] / d
 			}
 			}
 		}
 		}
 	} else {
 	} else {
 		id := 1/d
 		id := 1/d
 		for i in 0..<4 {
 		for i in 0..<4 {
 			for j in 0..<4 {
 			for j in 0..<4 {
-				y[i, j] = a[j, i] * id
+				y[i, j] = c[j, i] * id
 			}
 			}
 		}
 		}
 	}
 	}

+ 66 - 18
core/math/linalg/glsl/linalg_glsl.odin

@@ -1882,6 +1882,13 @@ adjugate :: proc{
 	adjugate_matrix4x4,
 	adjugate_matrix4x4,
 }
 }
 
 
+cofactor :: proc{
+	cofactor_matrix1x1,
+	cofactor_matrix2x2,
+	cofactor_matrix3x3,
+	cofactor_matrix4x4,
+}
+
 inverse_transpose :: proc{
 inverse_transpose :: proc{
 	inverse_transpose_matrix1x1,
 	inverse_transpose_matrix1x1,
 	inverse_transpose_matrix2x2,
 	inverse_transpose_matrix2x2,
@@ -1944,9 +1951,9 @@ determinant_matrix3x3 :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (det: T) {
 }
 }
 @(require_results)
 @(require_results)
 determinant_matrix4x4 :: proc "contextless" (m: $M/matrix[4, 4]$T) -> (det: T) {
 determinant_matrix4x4 :: proc "contextless" (m: $M/matrix[4, 4]$T) -> (det: T) {
-	a := adjugate(m)
+	c := cofactor(m)
 	#no_bounds_check for i in 0..<4 {
 	#no_bounds_check for i in 0..<4 {
-		det += m[0, i] * a[0, i]
+		det += m[0, i] * c[0, i]
 	}
 	}
 	return
 	return
 }
 }
@@ -1962,6 +1969,47 @@ adjugate_matrix1x1 :: proc "contextless" (x: $M/matrix[1, 1]$T) -> (y: M) {
 
 
 @(require_results)
 @(require_results)
 adjugate_matrix2x2 :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) {
 adjugate_matrix2x2 :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) {
+	y[0, 0] = +x[1, 1]
+	y[0, 1] = -x[0, 1]
+	y[1, 0] = -x[1, 0]
+	y[1, 1] = +x[0, 0]
+	return
+}
+
+@(require_results)
+adjugate_matrix3x3 :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (y: M) {
+	y[0, 0] = +(m[1, 1] * m[2, 2] - m[2, 1] * m[1, 2])
+	y[1, 0] = -(m[1, 0] * m[2, 2] - m[2, 0] * m[1, 2])
+	y[2, 0] = +(m[1, 0] * m[2, 1] - m[2, 0] * m[1, 1])
+	y[0, 1] = -(m[0, 1] * m[2, 2] - m[2, 1] * m[0, 2])
+	y[1, 1] = +(m[0, 0] * m[2, 2] - m[2, 0] * m[0, 2])
+	y[2, 1] = -(m[0, 0] * m[2, 1] - m[2, 0] * m[0, 1])
+	y[0, 2] = +(m[0, 1] * m[1, 2] - m[1, 1] * m[0, 2])
+	y[1, 2] = -(m[0, 0] * m[1, 2] - m[1, 0] * m[0, 2])
+	y[2, 2] = +(m[0, 0] * m[1, 1] - m[1, 0] * m[0, 1])
+	return
+}
+
+@(require_results)
+adjugate_matrix4x4 :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) {
+	for i in 0..<4 {
+		for j in 0..<4 {
+			sign: T = 1 if (i + j) % 2 == 0 else -1
+			y[i, j] = sign * matrix_minor(x, j, i)
+		}
+	}
+	return
+}
+
+
+@(require_results)
+cofactor_matrix1x1 :: proc "contextless" (x: $M/matrix[1, 1]$T) -> (y: M) {
+	y = x
+	return
+}
+
+@(require_results)
+cofactor_matrix2x2 :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) {
 	y[0, 0] = +x[1, 1]
 	y[0, 0] = +x[1, 1]
 	y[0, 1] = -x[1, 0]
 	y[0, 1] = -x[1, 0]
 	y[1, 0] = -x[0, 1]
 	y[1, 0] = -x[0, 1]
@@ -1970,7 +2018,7 @@ adjugate_matrix2x2 :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) {
 }
 }
 
 
 @(require_results)
 @(require_results)
-adjugate_matrix3x3 :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (y: M) {
+cofactor_matrix3x3 :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (y: M) {
 	y[0, 0] = +(m[1, 1] * m[2, 2] - m[2, 1] * m[1, 2])
 	y[0, 0] = +(m[1, 1] * m[2, 2] - m[2, 1] * m[1, 2])
 	y[0, 1] = -(m[1, 0] * m[2, 2] - m[2, 0] * m[1, 2])
 	y[0, 1] = -(m[1, 0] * m[2, 2] - m[2, 0] * m[1, 2])
 	y[0, 2] = +(m[1, 0] * m[2, 1] - m[2, 0] * m[1, 1])
 	y[0, 2] = +(m[1, 0] * m[2, 1] - m[2, 0] * m[1, 1])
@@ -1985,7 +2033,7 @@ adjugate_matrix3x3 :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (y: M) {
 
 
 
 
 @(require_results)
 @(require_results)
-adjugate_matrix4x4 :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) {
+cofactor_matrix4x4 :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) {
 	for i in 0..<4 {
 	for i in 0..<4 {
 		for j in 0..<4 {
 		for j in 0..<4 {
 			sign: T = 1 if (i + j) % 2 == 0 else -1
 			sign: T = 1 if (i + j) % 2 == 0 else -1
@@ -2021,19 +2069,19 @@ inverse_transpose_matrix2x2 :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y:
 
 
 @(require_results)
 @(require_results)
 inverse_transpose_matrix3x3 :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y: M) #no_bounds_check {
 inverse_transpose_matrix3x3 :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y: M) #no_bounds_check {
-	a := adjugate(x)
+	c := cofactor(x)
 	d := determinant(x)
 	d := determinant(x)
 	when intrinsics.type_is_integer(T) {
 	when intrinsics.type_is_integer(T) {
 		for i in 0..<3 {
 		for i in 0..<3 {
 			for j in 0..<3 {
 			for j in 0..<3 {
-				y[i, j] = a[i, j] / d
+				y[i, j] = c[i, j] / d
 			}
 			}
 		}
 		}
 	} else {
 	} else {
 		id := 1/d
 		id := 1/d
 		for i in 0..<3 {
 		for i in 0..<3 {
 			for j in 0..<3 {
 			for j in 0..<3 {
-				y[i, j] = a[i, j] * id
+				y[i, j] = c[i, j] * id
 			}
 			}
 		}
 		}
 	}
 	}
@@ -2042,22 +2090,22 @@ inverse_transpose_matrix3x3 :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y:
 
 
 @(require_results)
 @(require_results)
 inverse_transpose_matrix4x4 :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) #no_bounds_check {
 inverse_transpose_matrix4x4 :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) #no_bounds_check {
-	a := adjugate(x)
+	c := cofactor(x)
 	d: T
 	d: T
 	for i in 0..<4 {
 	for i in 0..<4 {
-		d += x[0, i] * a[0, i]
+		d += x[0, i] * c[0, i]
 	}
 	}
 	when intrinsics.type_is_integer(T) {
 	when intrinsics.type_is_integer(T) {
 		for i in 0..<4 {
 		for i in 0..<4 {
 			for j in 0..<4 {
 			for j in 0..<4 {
-				y[i, j] = a[i, j] / d
+				y[i, j] = c[i, j] / d
 			}
 			}
 		}
 		}
 	} else {
 	} else {
 		id := 1/d
 		id := 1/d
 		for i in 0..<4 {
 		for i in 0..<4 {
 			for j in 0..<4 {
 			for j in 0..<4 {
-				y[i, j] = a[i, j] * id
+				y[i, j] = c[i, j] * id
 			}
 			}
 		}
 		}
 	}
 	}
@@ -2090,19 +2138,19 @@ inverse_matrix2x2 :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) {
 
 
 @(require_results)
 @(require_results)
 inverse_matrix3x3 :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y: M) #no_bounds_check {
 inverse_matrix3x3 :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y: M) #no_bounds_check {
-	a := adjugate(x)
+	c := cofactor(x)
 	d := determinant(x)
 	d := determinant(x)
 	when intrinsics.type_is_integer(T) {
 	when intrinsics.type_is_integer(T) {
 		for i in 0..<3 {
 		for i in 0..<3 {
 			for j in 0..<3 {
 			for j in 0..<3 {
-				y[i, j] = a[j, i] / d
+				y[i, j] = c[j, i] / d
 			}
 			}
 		}
 		}
 	} else {
 	} else {
 		id := 1/d
 		id := 1/d
 		for i in 0..<3 {
 		for i in 0..<3 {
 			for j in 0..<3 {
 			for j in 0..<3 {
-				y[i, j] = a[j, i] * id
+				y[i, j] = c[j, i] * id
 			}
 			}
 		}
 		}
 	}
 	}
@@ -2111,22 +2159,22 @@ inverse_matrix3x3 :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y: M) #no_bou
 
 
 @(require_results)
 @(require_results)
 inverse_matrix4x4 :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) #no_bounds_check {
 inverse_matrix4x4 :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) #no_bounds_check {
-	a := adjugate(x)
+	c := cofactor(x)
 	d: T
 	d: T
 	for i in 0..<4 {
 	for i in 0..<4 {
-		d += x[0, i] * a[0, i]
+		d += x[0, i] * c[0, i]
 	}
 	}
 	when intrinsics.type_is_integer(T) {
 	when intrinsics.type_is_integer(T) {
 		for i in 0..<4 {
 		for i in 0..<4 {
 			for j in 0..<4 {
 			for j in 0..<4 {
-				y[i, j] = a[j, i] / d
+				y[i, j] = c[j, i] / d
 			}
 			}
 		}
 		}
 	} else {
 	} else {
 		id := 1/d
 		id := 1/d
 		for i in 0..<4 {
 		for i in 0..<4 {
 			for j in 0..<4 {
 			for j in 0..<4 {
-				y[i, j] = a[j, i] * id
+				y[i, j] = c[j, i] * id
 			}
 			}
 		}
 		}
 	}
 	}

+ 66 - 18
core/math/linalg/hlsl/linalg_hlsl.odin

@@ -1514,6 +1514,13 @@ adjugate :: proc{
 	adjugate_matrix4x4,
 	adjugate_matrix4x4,
 }
 }
 
 
+cofactor :: proc{
+	cofactor_matrix1x1,
+	cofactor_matrix2x2,
+	cofactor_matrix3x3,
+	cofactor_matrix4x4,
+}
+
 inverse_transpose :: proc{
 inverse_transpose :: proc{
 	inverse_transpose_matrix1x1,
 	inverse_transpose_matrix1x1,
 	inverse_transpose_matrix2x2,
 	inverse_transpose_matrix2x2,
@@ -1568,9 +1575,9 @@ determinant_matrix3x3 :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (det: T) {
 }
 }
 @(require_results)
 @(require_results)
 determinant_matrix4x4 :: proc "contextless" (m: $M/matrix[4, 4]$T) -> (det: T) {
 determinant_matrix4x4 :: proc "contextless" (m: $M/matrix[4, 4]$T) -> (det: T) {
-	a := adjugate(m)
+	c := cofactor(m)
 	#no_bounds_check for i in 0..<4 {
 	#no_bounds_check for i in 0..<4 {
-		det += m[0, i] * a[0, i]
+		det += m[0, i] * c[0, i]
 	}
 	}
 	return
 	return
 }
 }
@@ -1586,6 +1593,47 @@ adjugate_matrix1x1 :: proc "contextless" (x: $M/matrix[1, 1]$T) -> (y: M) {
 
 
 @(require_results)
 @(require_results)
 adjugate_matrix2x2 :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) {
 adjugate_matrix2x2 :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) {
+	y[0, 0] = +x[1, 1]
+	y[0, 1] = -x[0, 1]
+	y[1, 0] = -x[1, 0]
+	y[1, 1] = +x[0, 0]
+	return
+}
+
+@(require_results)
+adjugate_matrix3x3 :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (y: M) {
+	y[0, 0] = +(m[1, 1] * m[2, 2] - m[2, 1] * m[1, 2])
+	y[1, 0] = -(m[1, 0] * m[2, 2] - m[2, 0] * m[1, 2])
+	y[2, 0] = +(m[1, 0] * m[2, 1] - m[2, 0] * m[1, 1])
+	y[0, 1] = -(m[0, 1] * m[2, 2] - m[2, 1] * m[0, 2])
+	y[1, 1] = +(m[0, 0] * m[2, 2] - m[2, 0] * m[0, 2])
+	y[2, 1] = -(m[0, 0] * m[2, 1] - m[2, 0] * m[0, 1])
+	y[0, 2] = +(m[0, 1] * m[1, 2] - m[1, 1] * m[0, 2])
+	y[1, 2] = -(m[0, 0] * m[1, 2] - m[1, 0] * m[0, 2])
+	y[2, 2] = +(m[0, 0] * m[1, 1] - m[1, 0] * m[0, 1])
+	return
+}
+
+@(require_results)
+adjugate_matrix4x4 :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) {
+	for i in 0..<4 {
+		for j in 0..<4 {
+			sign: T = 1 if (i + j) % 2 == 0 else -1
+			y[i, j] = sign * matrix_minor(x, j, i)
+		}
+	}
+	return
+}
+
+
+@(require_results)
+cofactor_matrix1x1 :: proc "contextless" (x: $M/matrix[1, 1]$T) -> (y: M) {
+	y = x
+	return
+}
+
+@(require_results)
+cofactor_matrix2x2 :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) {
 	y[0, 0] = +x[1, 1]
 	y[0, 0] = +x[1, 1]
 	y[0, 1] = -x[1, 0]
 	y[0, 1] = -x[1, 0]
 	y[1, 0] = -x[0, 1]
 	y[1, 0] = -x[0, 1]
@@ -1594,7 +1642,7 @@ adjugate_matrix2x2 :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) {
 }
 }
 
 
 @(require_results)
 @(require_results)
-adjugate_matrix3x3 :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (y: M) {
+cofactor_matrix3x3 :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (y: M) {
 	y[0, 0] = +(m[1, 1] * m[2, 2] - m[2, 1] * m[1, 2])
 	y[0, 0] = +(m[1, 1] * m[2, 2] - m[2, 1] * m[1, 2])
 	y[0, 1] = -(m[1, 0] * m[2, 2] - m[2, 0] * m[1, 2])
 	y[0, 1] = -(m[1, 0] * m[2, 2] - m[2, 0] * m[1, 2])
 	y[0, 2] = +(m[1, 0] * m[2, 1] - m[2, 0] * m[1, 1])
 	y[0, 2] = +(m[1, 0] * m[2, 1] - m[2, 0] * m[1, 1])
@@ -1609,7 +1657,7 @@ adjugate_matrix3x3 :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (y: M) {
 
 
 
 
 @(require_results)
 @(require_results)
-adjugate_matrix4x4 :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) {
+cofactor_matrix4x4 :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) {
 	for i in 0..<4 {
 	for i in 0..<4 {
 		for j in 0..<4 {
 		for j in 0..<4 {
 			sign: T = 1 if (i + j) % 2 == 0 else -1
 			sign: T = 1 if (i + j) % 2 == 0 else -1
@@ -1645,19 +1693,19 @@ inverse_transpose_matrix2x2 :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y:
 
 
 @(require_results)
 @(require_results)
 inverse_transpose_matrix3x3 :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y: M) #no_bounds_check {
 inverse_transpose_matrix3x3 :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y: M) #no_bounds_check {
-	a := adjugate(x)
+	c := cofactor(x)
 	d := determinant(x)
 	d := determinant(x)
 	when intrinsics.type_is_integer(T) {
 	when intrinsics.type_is_integer(T) {
 		for i in 0..<3 {
 		for i in 0..<3 {
 			for j in 0..<3 {
 			for j in 0..<3 {
-				y[i, j] = a[i, j] / d
+				y[i, j] = c[i, j] / d
 			}
 			}
 		}
 		}
 	} else {
 	} else {
 		id := 1/d
 		id := 1/d
 		for i in 0..<3 {
 		for i in 0..<3 {
 			for j in 0..<3 {
 			for j in 0..<3 {
-				y[i, j] = a[i, j] * id
+				y[i, j] = c[i, j] * id
 			}
 			}
 		}
 		}
 	}
 	}
@@ -1666,22 +1714,22 @@ inverse_transpose_matrix3x3 :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y:
 
 
 @(require_results)
 @(require_results)
 inverse_transpose_matrix4x4 :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) #no_bounds_check {
 inverse_transpose_matrix4x4 :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) #no_bounds_check {
-	a := adjugate(x)
+	c := cofactor(x)
 	d: T
 	d: T
 	for i in 0..<4 {
 	for i in 0..<4 {
-		d += x[0, i] * a[0, i]
+		d += x[0, i] * c[0, i]
 	}
 	}
 	when intrinsics.type_is_integer(T) {
 	when intrinsics.type_is_integer(T) {
 		for i in 0..<4 {
 		for i in 0..<4 {
 			for j in 0..<4 {
 			for j in 0..<4 {
-				y[i, j] = a[i, j] / d
+				y[i, j] = c[i, j] / d
 			}
 			}
 		}
 		}
 	} else {
 	} else {
 		id := 1/d
 		id := 1/d
 		for i in 0..<4 {
 		for i in 0..<4 {
 			for j in 0..<4 {
 			for j in 0..<4 {
-				y[i, j] = a[i, j] * id
+				y[i, j] = c[i, j] * id
 			}
 			}
 		}
 		}
 	}
 	}
@@ -1714,19 +1762,19 @@ inverse_matrix2x2 :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) {
 
 
 @(require_results)
 @(require_results)
 inverse_matrix3x3 :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y: M) #no_bounds_check {
 inverse_matrix3x3 :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y: M) #no_bounds_check {
-	a := adjugate(x)
+	c := cofactor(x)
 	d := determinant(x)
 	d := determinant(x)
 	when intrinsics.type_is_integer(T) {
 	when intrinsics.type_is_integer(T) {
 		for i in 0..<3 {
 		for i in 0..<3 {
 			for j in 0..<3 {
 			for j in 0..<3 {
-				y[i, j] = a[j, i] / d
+				y[i, j] = c[j, i] / d
 			}
 			}
 		}
 		}
 	} else {
 	} else {
 		id := 1/d
 		id := 1/d
 		for i in 0..<3 {
 		for i in 0..<3 {
 			for j in 0..<3 {
 			for j in 0..<3 {
-				y[i, j] = a[j, i] * id
+				y[i, j] = c[j, i] * id
 			}
 			}
 		}
 		}
 	}
 	}
@@ -1735,22 +1783,22 @@ inverse_matrix3x3 :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y: M) #no_bou
 
 
 @(require_results)
 @(require_results)
 inverse_matrix4x4 :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) #no_bounds_check {
 inverse_matrix4x4 :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) #no_bounds_check {
-	a := adjugate(x)
+	c := cofactor(x)
 	d: T
 	d: T
 	for i in 0..<4 {
 	for i in 0..<4 {
-		d += x[0, i] * a[0, i]
+		d += x[0, i] * c[0, i]
 	}
 	}
 	when intrinsics.type_is_integer(T) {
 	when intrinsics.type_is_integer(T) {
 		for i in 0..<4 {
 		for i in 0..<4 {
 			for j in 0..<4 {
 			for j in 0..<4 {
-				y[i, j] = a[j, i] / d
+				y[i, j] = c[j, i] / d
 			}
 			}
 		}
 		}
 	} else {
 	} else {
 		id := 1/d
 		id := 1/d
 		for i in 0..<4 {
 		for i in 0..<4 {
 			for j in 0..<4 {
 			for j in 0..<4 {
-				y[i, j] = a[j, i] * id
+				y[i, j] = c[j, i] * id
 			}
 			}
 		}
 		}
 	}
 	}

+ 0 - 24
core/math/rand/rand.odin

@@ -29,30 +29,6 @@ Reset the seed used by the context.random_generator.
 Inputs:
 Inputs:
 - seed: The seed value
 - seed: The seed value
 
 
-Example:
-	import "core:math/rand"
-	import "core:fmt"
-
-	set_global_seed_example :: proc() {
-		rand.set_global_seed(1)
-		fmt.println(rand.uint64())
-	}
-
-Possible Output:
-
-	10
-*/
-@(deprecated="Prefer `rand.reset`")
-set_global_seed :: proc(seed: u64) {
-	runtime.random_generator_reset_u64(context.random_generator, seed)
-}
-
-/*
-Reset the seed used by the context.random_generator.
-
-Inputs:
-- seed: The seed value
-
 Example:
 Example:
 	import "core:math/rand"
 	import "core:math/rand"
 	import "core:fmt"
 	import "core:fmt"

+ 0 - 23
core/mem/allocators.odin

@@ -140,14 +140,6 @@ arena_init :: proc(a: ^Arena, data: []byte) {
 	a.temp_count = 0
 	a.temp_count = 0
 }
 }
 
 
-@(deprecated="prefer 'mem.arena_init'")
-init_arena :: proc(a: ^Arena, data: []byte) {
-	a.data       = data
-	a.offset     = 0
-	a.peak_used  = 0
-	a.temp_count = 0
-}
-
 /*
 /*
 Allocate memory from an arena.
 Allocate memory from an arena.
 
 
@@ -786,14 +778,6 @@ stack_init :: proc(s: ^Stack, data: []byte) {
 	s.peak_used   = 0
 	s.peak_used   = 0
 }
 }
 
 
-@(deprecated="prefer 'mem.stack_init'")
-init_stack :: proc(s: ^Stack, data: []byte) {
-	s.data        = data
-	s.prev_offset = 0
-	s.curr_offset = 0
-	s.peak_used   = 0
-}
-
 /*
 /*
 Allocate memory from stack.
 Allocate memory from stack.
 
 
@@ -1162,13 +1146,6 @@ small_stack_init :: proc(s: ^Small_Stack, data: []byte) {
 	s.peak_used = 0
 	s.peak_used = 0
 }
 }
 
 
-@(deprecated="prefer 'small_stack_init'")
-init_small_stack :: proc(s: ^Small_Stack, data: []byte) {
-	s.data      = data
-	s.offset    = 0
-	s.peak_used = 0
-}
-
 /*
 /*
 Small stack allocator.
 Small stack allocator.
 
 

+ 1 - 8
core/mem/mem.odin

@@ -685,11 +685,4 @@ calc_padding_with_header :: proc "contextless" (ptr: uintptr, align: uintptr, he
 		}
 		}
 	}
 	}
 	return int(padding)
 	return int(padding)
-}
-
-@(require_results, deprecated="prefer 'slice.clone'")
-clone_slice :: proc(slice: $T/[]$E, allocator := context.allocator, loc := #caller_location) -> (new_slice: T) {
-	new_slice, _ = make(T, len(slice), allocator, loc)
-	runtime.copy(new_slice, slice)
-	return new_slice
-}
+}

+ 2 - 1
core/mem/virtual/arena.odin

@@ -204,8 +204,9 @@ arena_free_all :: proc(arena: ^Arena, loc := #caller_location) {
 		}
 		}
 		// Zero the first block's memory
 		// Zero the first block's memory
 		if arena.curr_block != nil {
 		if arena.curr_block != nil {
-			mem.zero(arena.curr_block.base, int(arena.curr_block.used))
+			curr_block_used := int(arena.curr_block.used)
 			arena.curr_block.used = 0
 			arena.curr_block.used = 0
+			mem.zero(arena.curr_block.base, curr_block_used)
 		}
 		}
 		arena.total_used = 0
 		arena.total_used = 0
 	case .Static, .Buffer:
 	case .Static, .Buffer:

+ 1 - 1
core/os/os2/file.odin

@@ -115,7 +115,7 @@ open :: proc(name: string, flags := File_Flags{.Read}, perm := 0o777) -> (^File,
 
 
 @(require_results)
 @(require_results)
 new_file :: proc(handle: uintptr, name: string) -> ^File {
 new_file :: proc(handle: uintptr, name: string) -> ^File {
-	file, err := _new_file(handle, name)
+	file, err := _new_file(handle, name, file_allocator())
 	if err != nil {
 	if err != nil {
 		panic(error_string(err))
 		panic(error_string(err))
 	}
 	}

+ 27 - 54
core/os/os2/file_linux.odin

@@ -39,37 +39,23 @@ _stderr := File{
 
 
 @init
 @init
 _standard_stream_init :: proc() {
 _standard_stream_init :: proc() {
-	@static stdin_impl := File_Impl {
-		name = "/proc/self/fd/0",
-		fd = 0,
-	}
-
-	@static stdout_impl := File_Impl {
-		name = "/proc/self/fd/1",
-		fd = 1,
-	}
-
-	@static stderr_impl := File_Impl {
-		name = "/proc/self/fd/2",
-		fd = 2,
+	new_std :: proc(impl: ^File_Impl, fd: linux.Fd, name: string) -> ^File {
+		impl.file.impl = impl
+		impl.fd = linux.Fd(fd)
+		impl.allocator = runtime.nil_allocator()
+		impl.name = name
+		impl.file.stream = {
+			data = impl,
+			procedure = _file_stream_proc,
+		}
+		impl.file.fstat = _fstat
+		return &impl.file
 	}
 	}
 
 
-	stdin_impl.allocator  = file_allocator()
-	stdout_impl.allocator = file_allocator()
-	stderr_impl.allocator = file_allocator()
-
-	_stdin.impl  = &stdin_impl
-	_stdout.impl = &stdout_impl
-	_stderr.impl = &stderr_impl
-
-	// cannot define these initially because cyclic reference
-	_stdin.stream.data  = &stdin_impl
-	_stdout.stream.data = &stdout_impl
-	_stderr.stream.data = &stderr_impl
-
-	stdin  = &_stdin
-	stdout = &_stdout
-	stderr = &_stderr
+	@(static) files: [3]File_Impl
+	stdin  = new_std(&files[0], 0, "/proc/self/fd/0")
+	stdout = new_std(&files[1], 1, "/proc/self/fd/1")
+	stderr = new_std(&files[2], 2, "/proc/self/fd/2")
 }
 }
 
 
 _open :: proc(name: string, flags: File_Flags, perm: int) -> (f: ^File, err: Error) {
 _open :: proc(name: string, flags: File_Flags, perm: int) -> (f: ^File, err: Error) {
@@ -80,6 +66,9 @@ _open :: proc(name: string, flags: File_Flags, perm: int) -> (f: ^File, err: Err
 	// terminal would be incredibly rare. This has no effect on files while
 	// terminal would be incredibly rare. This has no effect on files while
 	// allowing us to open serial devices.
 	// allowing us to open serial devices.
 	sys_flags: linux.Open_Flags = {.NOCTTY, .CLOEXEC}
 	sys_flags: linux.Open_Flags = {.NOCTTY, .CLOEXEC}
+	when size_of(rawptr) == 4 {
+		sys_flags += {.LARGEFILE}
+	}
 	switch flags & (O_RDONLY|O_WRONLY|O_RDWR) {
 	switch flags & (O_RDONLY|O_WRONLY|O_RDWR) {
 	case O_RDONLY:
 	case O_RDONLY:
 	case O_WRONLY: sys_flags += {.WRONLY}
 	case O_WRONLY: sys_flags += {.WRONLY}
@@ -97,18 +86,18 @@ _open :: proc(name: string, flags: File_Flags, perm: int) -> (f: ^File, err: Err
 		return nil, _get_platform_error(errno)
 		return nil, _get_platform_error(errno)
 	}
 	}
 
 
-	return _new_file(uintptr(fd), name)
+	return _new_file(uintptr(fd), name, file_allocator())
 }
 }
 
 
-_new_file :: proc(fd: uintptr, _: string = "") -> (f: ^File, err: Error) {
-	impl := new(File_Impl, file_allocator()) or_return
+_new_file :: proc(fd: uintptr, _: string, allocator: runtime.Allocator) -> (f: ^File, err: Error) {
+	impl := new(File_Impl, allocator) or_return
 	defer if err != nil {
 	defer if err != nil {
-		free(impl, file_allocator())
+		free(impl, allocator)
 	}
 	}
 	impl.file.impl = impl
 	impl.file.impl = impl
 	impl.fd = linux.Fd(fd)
 	impl.fd = linux.Fd(fd)
-	impl.allocator = file_allocator()
-	impl.name = _get_full_path(impl.fd, file_allocator()) or_return
+	impl.allocator = allocator
+	impl.name = _get_full_path(impl.fd, impl.allocator) or_return
 	impl.file.stream = {
 	impl.file.stream = {
 		data = impl,
 		data = impl,
 		procedure = _file_stream_proc,
 		procedure = _file_stream_proc,
@@ -272,28 +261,12 @@ _truncate :: proc(f: ^File, size: i64) -> Error {
 }
 }
 
 
 _remove :: proc(name: string) -> Error {
 _remove :: proc(name: string) -> Error {
-	is_dir_fd :: proc(fd: linux.Fd) -> bool {
-		s: linux.Stat
-		if linux.fstat(fd, &s) != .NONE {
-			return false
-		}
-		return linux.S_ISDIR(s.mode)
-	}
-
 	TEMP_ALLOCATOR_GUARD()
 	TEMP_ALLOCATOR_GUARD()
 	name_cstr := temp_cstring(name) or_return
 	name_cstr := temp_cstring(name) or_return
 
 
-	fd, errno := linux.open(name_cstr, {.NOFOLLOW})
-	#partial switch (errno) {
-	case .ELOOP:
-		/* symlink */
-	case .NONE:
-		defer linux.close(fd)
-		if is_dir_fd(fd) {
-			return _get_platform_error(linux.rmdir(name_cstr))
-		}
-	case:
-		return _get_platform_error(errno)
+	if fd, errno := linux.open(name_cstr, _OPENDIR_FLAGS + {.NOFOLLOW}); errno == .NONE {
+		linux.close(fd)
+		return _get_platform_error(linux.rmdir(name_cstr))
 	}
 	}
 
 
 	return _get_platform_error(linux.unlink(name_cstr))
 	return _get_platform_error(linux.unlink(name_cstr))

+ 29 - 20
core/os/os2/file_posix.odin

@@ -21,23 +21,29 @@ File_Impl :: struct {
 	name:  string,
 	name:  string,
 	cname: cstring,
 	cname: cstring,
 	fd:    posix.FD,
 	fd:    posix.FD,
+	allocator: runtime.Allocator,
 }
 }
 
 
 @(init)
 @(init)
 init_std_files :: proc() {
 init_std_files :: proc() {
-	// NOTE: is this (paths) also the case on non darwin?
-
-	stdin = __new_file(posix.STDIN_FILENO)
-	(^File_Impl)(stdin.impl).name  = "/dev/stdin"
-	(^File_Impl)(stdin.impl).cname = "/dev/stdin"
-
-	stdout = __new_file(posix.STDIN_FILENO)
-	(^File_Impl)(stdout.impl).name  = "/dev/stdout"
-	(^File_Impl)(stdout.impl).cname = "/dev/stdout"
+	new_std :: proc(impl: ^File_Impl, fd: posix.FD, name: cstring) -> ^File {
+		impl.file.impl = impl
+		impl.fd = fd
+		impl.allocator = runtime.nil_allocator()
+		impl.cname = name
+		impl.name  = string(name)
+		impl.file.stream = {
+			data = impl,
+			procedure = _file_stream_proc,
+		}
+		impl.file.fstat = _fstat
+		return &impl.file
+	}
 
 
-	stderr = __new_file(posix.STDIN_FILENO)
-	(^File_Impl)(stderr.impl).name  = "/dev/stderr"
-	(^File_Impl)(stderr.impl).cname = "/dev/stderr"
+	@(static) files: [3]File_Impl
+	stdin  = new_std(&files[0], posix.STDIN_FILENO,  "/dev/stdin")
+	stdout = new_std(&files[1], posix.STDOUT_FILENO, "/dev/stdout")
+	stderr = new_std(&files[2], posix.STDERR_FILENO, "/dev/stderr")
 }
 }
 
 
 _open :: proc(name: string, flags: File_Flags, perm: int) -> (f: ^File, err: Error) {
 _open :: proc(name: string, flags: File_Flags, perm: int) -> (f: ^File, err: Error) {
@@ -72,10 +78,10 @@ _open :: proc(name: string, flags: File_Flags, perm: int) -> (f: ^File, err: Err
 		return
 		return
 	}
 	}
 
 
-	return _new_file(uintptr(fd), name)
+	return _new_file(uintptr(fd), name, file_allocator())
 }
 }
 
 
-_new_file :: proc(handle: uintptr, name: string) -> (f: ^File, err: Error) {
+_new_file :: proc(handle: uintptr, name: string, allocator: runtime.Allocator) -> (f: ^File, err: Error) {
 	if name == "" {
 	if name == "" {
 		err = .Invalid_Path
 		err = .Invalid_Path
 		return
 		return
@@ -84,10 +90,10 @@ _new_file :: proc(handle: uintptr, name: string) -> (f: ^File, err: Error) {
 		return
 		return
 	}
 	}
 
 
-	crname := _posix_absolute_path(posix.FD(handle), name, file_allocator()) or_return
+	crname := _posix_absolute_path(posix.FD(handle), name, allocator) or_return
 	rname  := string(crname)
 	rname  := string(crname)
 
 
-	f = __new_file(posix.FD(handle))
+	f = __new_file(posix.FD(handle), allocator)
 	impl := (^File_Impl)(f.impl)
 	impl := (^File_Impl)(f.impl)
 	impl.name  = rname
 	impl.name  = rname
 	impl.cname = crname
 	impl.cname = crname
@@ -95,10 +101,11 @@ _new_file :: proc(handle: uintptr, name: string) -> (f: ^File, err: Error) {
 	return f, nil
 	return f, nil
 }
 }
 
 
-__new_file :: proc(handle: posix.FD) -> ^File {
-	impl := new(File_Impl, file_allocator())
+__new_file :: proc(handle: posix.FD, allocator: runtime.Allocator) -> ^File {
+	impl := new(File_Impl, allocator)
 	impl.file.impl = impl
 	impl.file.impl = impl
 	impl.fd = posix.FD(handle)
 	impl.fd = posix.FD(handle)
+	impl.allocator = allocator
 	impl.file.stream = {
 	impl.file.stream = {
 		data = impl,
 		data = impl,
 		procedure = _file_stream_proc,
 		procedure = _file_stream_proc,
@@ -114,8 +121,10 @@ _close :: proc(f: ^File_Impl) -> (err: Error) {
 		err = _get_platform_error()
 		err = _get_platform_error()
 	}
 	}
 
 
-	delete(f.cname, file_allocator())
-	free(f, file_allocator())
+	allocator := f.allocator
+
+	delete(f.cname, allocator)
+	free(f, allocator)
 	return
 	return
 }
 }
 
 

+ 37 - 16
core/os/os2/file_windows.odin

@@ -44,17 +44,38 @@ File_Impl :: struct {
 
 
 @(init)
 @(init)
 init_std_files :: proc() {
 init_std_files :: proc() {
-	stdin  = new_file(uintptr(win32.GetStdHandle(win32.STD_INPUT_HANDLE)),  "<stdin>")
-	stdout = new_file(uintptr(win32.GetStdHandle(win32.STD_OUTPUT_HANDLE)), "<stdout>")
-	stderr = new_file(uintptr(win32.GetStdHandle(win32.STD_ERROR_HANDLE)),  "<stderr>")
-}
-@(fini)
-fini_std_files :: proc() {
-	_destroy((^File_Impl)(stdin.impl))
-	_destroy((^File_Impl)(stdout.impl))
-	_destroy((^File_Impl)(stderr.impl))
-}
+	new_std :: proc(impl: ^File_Impl, code: u32, name: string) -> ^File {
+		impl.file.impl = impl
+
+		impl.allocator = runtime.nil_allocator()
+		impl.fd = win32.GetStdHandle(code)
+		impl.name = name
+		impl.wname = nil
+
+		handle := _handle(&impl.file)
+		kind := File_Impl_Kind.File
+		if m: u32; win32.GetConsoleMode(handle, &m) {
+			kind = .Console
+		}
+		if win32.GetFileType(handle) == win32.FILE_TYPE_PIPE {
+			kind = .Pipe
+		}
+		impl.kind = kind
 
 
+		impl.file.stream = {
+			data = impl,
+			procedure = _file_stream_proc,
+		}
+		impl.file.fstat = _fstat
+
+		return &impl.file
+	}
+
+	@(static) files: [3]File_Impl
+	stdin  = new_std(&files[0], win32.STD_INPUT_HANDLE,  "<stdin>")
+	stdout = new_std(&files[1], win32.STD_OUTPUT_HANDLE, "<stdout>")
+	stderr = new_std(&files[2], win32.STD_ERROR_HANDLE,  "<stderr>")
+}
 
 
 _handle :: proc(f: ^File) -> win32.HANDLE {
 _handle :: proc(f: ^File) -> win32.HANDLE {
 	return win32.HANDLE(_fd(f))
 	return win32.HANDLE(_fd(f))
@@ -132,21 +153,21 @@ _open_internal :: proc(name: string, flags: File_Flags, perm: int) -> (handle: u
 _open :: proc(name: string, flags: File_Flags, perm: int) -> (f: ^File, err: Error) {
 _open :: proc(name: string, flags: File_Flags, perm: int) -> (f: ^File, err: Error) {
 	flags := flags if flags != nil else {.Read}
 	flags := flags if flags != nil else {.Read}
 	handle := _open_internal(name, flags, perm) or_return
 	handle := _open_internal(name, flags, perm) or_return
-	return _new_file(handle, name)
+	return _new_file(handle, name, file_allocator())
 }
 }
 
 
-_new_file :: proc(handle: uintptr, name: string) -> (f: ^File, err: Error) {
+_new_file :: proc(handle: uintptr, name: string, allocator: runtime.Allocator) -> (f: ^File, err: Error) {
 	if handle == INVALID_HANDLE {
 	if handle == INVALID_HANDLE {
 		return
 		return
 	}
 	}
-	impl := new(File_Impl, file_allocator()) or_return
+	impl := new(File_Impl, allocator) or_return
 	defer if err != nil {
 	defer if err != nil {
-		free(impl, file_allocator())
+		free(impl, allocator)
 	}
 	}
 
 
 	impl.file.impl = impl
 	impl.file.impl = impl
 
 
-	impl.allocator = file_allocator()
+	impl.allocator = allocator
 	impl.fd = rawptr(handle)
 	impl.fd = rawptr(handle)
 	impl.name = clone_string(name, impl.allocator) or_return
 	impl.name = clone_string(name, impl.allocator) or_return
 	impl.wname = win32_utf8_to_wstring(name, impl.allocator) or_return
 	impl.wname = win32_utf8_to_wstring(name, impl.allocator) or_return
@@ -180,7 +201,7 @@ _open_buffered :: proc(name: string, buffer_size: uint, flags := File_Flags{.Rea
 }
 }
 
 
 _new_file_buffered :: proc(handle: uintptr, name: string, buffer_size: uint) -> (f: ^File, err: Error) {
 _new_file_buffered :: proc(handle: uintptr, name: string, buffer_size: uint) -> (f: ^File, err: Error) {
-	f, err = _new_file(handle, name)
+	f, err = _new_file(handle, name, file_allocator())
 	if f != nil && err == nil {
 	if f != nil && err == nil {
 		impl := (^File_Impl)(f.impl)
 		impl := (^File_Impl)(f.impl)
 		impl.r_buf = make([]byte, buffer_size, file_allocator())
 		impl.r_buf = make([]byte, buffer_size, file_allocator())

+ 1 - 1
core/os/os2/heap_linux.odin

@@ -415,7 +415,7 @@ _region_resize :: proc(alloc: ^Allocation_Header, new_size: int, alloc_is_free_l
 	back_idx := -1
 	back_idx := -1
 	idx: u16
 	idx: u16
 	infinite: for {
 	infinite: for {
-		for i := 0; i < len(region_iter.hdr.free_list); i += 1 {
+		for i := 0; i < int(region_iter.hdr.free_list_len); i += 1 {
 			idx = region_iter.hdr.free_list[i]
 			idx = region_iter.hdr.free_list[i]
 			if _get_block_count(region_iter.memory[idx]) >= new_block_count {
 			if _get_block_count(region_iter.memory[idx]) >= new_block_count {
 				break infinite
 				break infinite

+ 0 - 2
core/os/os2/path_linux.odin

@@ -77,8 +77,6 @@ _mkdir_all :: proc(path: string, perm: int) -> Error {
 }
 }
 
 
 _remove_all :: proc(path: string) -> Error {
 _remove_all :: proc(path: string) -> Error {
-	DT_DIR :: 4
-
 	remove_all_dir :: proc(dfd: linux.Fd) -> Error {
 	remove_all_dir :: proc(dfd: linux.Fd) -> Error {
 		n := 64
 		n := 64
 		buf := make([]u8, n)
 		buf := make([]u8, n)

+ 2 - 2
core/os/os2/pipe_linux.odin

@@ -10,8 +10,8 @@ _pipe :: proc() -> (r, w: ^File, err: Error) {
 		return nil, nil,_get_platform_error(errno)
 		return nil, nil,_get_platform_error(errno)
 	}
 	}
 
 
-	r = _new_file(uintptr(fds[0])) or_return
-	w = _new_file(uintptr(fds[1])) or_return
+	r = _new_file(uintptr(fds[0]), "", file_allocator()) or_return
+	w = _new_file(uintptr(fds[1]), "", file_allocator()) or_return
 
 
 	return
 	return
 }
 }

+ 2 - 2
core/os/os2/pipe_posix.odin

@@ -21,7 +21,7 @@ _pipe :: proc() -> (r, w: ^File, err: Error) {
 		return
 		return
 	}
 	}
 
 
-	r = __new_file(fds[0])
+	r = __new_file(fds[0], file_allocator())
 	ri := (^File_Impl)(r.impl)
 	ri := (^File_Impl)(r.impl)
 
 
 	rname := strings.builder_make(file_allocator())
 	rname := strings.builder_make(file_allocator())
@@ -31,7 +31,7 @@ _pipe :: proc() -> (r, w: ^File, err: Error) {
 	ri.name  = strings.to_string(rname)
 	ri.name  = strings.to_string(rname)
 	ri.cname = strings.to_cstring(&rname)
 	ri.cname = strings.to_cstring(&rname)
 
 
-	w = __new_file(fds[1])
+	w = __new_file(fds[1], file_allocator())
 	wi := (^File_Impl)(w.impl)
 	wi := (^File_Impl)(w.impl)
 	
 	
 	wname := strings.builder_make(file_allocator())
 	wname := strings.builder_make(file_allocator())

+ 10 - 1
core/os/os2/process.odin

@@ -290,12 +290,21 @@ process_open :: proc(pid: int, flags := Process_Open_Flags {}) -> (Process, Erro
 	return _process_open(pid, flags)
 	return _process_open(pid, flags)
 }
 }
 
 
+
+/*
+OS-specific process attributes.
+*/
+Process_Attributes :: struct {
+	sys_attr: _Sys_Process_Attributes,
+}
+
 /*
 /*
 	The description of how a process should be created.
 	The description of how a process should be created.
 */
 */
 Process_Desc :: struct {
 Process_Desc :: struct {
 	// OS-specific attributes.
 	// OS-specific attributes.
-	sys_attr: _Sys_Process_Attributes,
+	sys_attr: Process_Attributes,
+
 	// The working directory of the process. If the string has length 0, the
 	// The working directory of the process. If the string has length 0, the
 	// working directory is assumed to be the current working directory of the
 	// working directory is assumed to be the current working directory of the
 	// current process.
 	// current process.

+ 11 - 36
core/os/os2/process_linux.odin

@@ -384,14 +384,6 @@ _Sys_Process_Attributes :: struct {}
 
 
 @(private="package")
 @(private="package")
 _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
 _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
-	has_executable_permissions :: proc(fd: linux.Fd) -> bool {
-		backing: [48]u8
-		b := strings.builder_from_bytes(backing[:])
-		strings.write_string(&b, "/proc/self/fd/")
-		strings.write_int(&b, int(fd))
-		return linux.access(strings.to_cstring(&b), linux.X_OK) == .NONE
-	}
-
 	TEMP_ALLOCATOR_GUARD()
 	TEMP_ALLOCATOR_GUARD()
 
 
 	if len(desc.command) == 0 {
 	if len(desc.command) == 0 {
@@ -411,7 +403,7 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
 	}
 	}
 
 
 	// search PATH if just a plain name is provided
 	// search PATH if just a plain name is provided
-	exe_fd: linux.Fd
+	exe_path: cstring
 	executable_name := desc.command[0]
 	executable_name := desc.command[0]
 	if strings.index_byte(executable_name, '/') < 0 {
 	if strings.index_byte(executable_name, '/') < 0 {
 		path_env := get_env("PATH", temp_allocator())
 		path_env := get_env("PATH", temp_allocator())
@@ -426,16 +418,11 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
 			strings.write_byte(&exe_builder, '/')
 			strings.write_byte(&exe_builder, '/')
 			strings.write_string(&exe_builder, executable_name)
 			strings.write_string(&exe_builder, executable_name)
 
 
-			exe_path := strings.to_cstring(&exe_builder)
-			if exe_fd, errno = linux.openat(dir_fd, exe_path, {.PATH, .CLOEXEC}); errno != .NONE {
-				continue
-			}
-			if !has_executable_permissions(exe_fd) {
-				linux.close(exe_fd)
-				continue
+			exe_path = strings.to_cstring(&exe_builder)
+			if linux.access(exe_path, linux.X_OK) == .NONE {
+				found = true
+				break
 			}
 			}
-			found = true
-			break
 		}
 		}
 		if !found {
 		if !found {
 			// check in cwd to match windows behavior
 			// check in cwd to match windows behavior
@@ -443,29 +430,18 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
 			strings.write_string(&exe_builder, "./")
 			strings.write_string(&exe_builder, "./")
 			strings.write_string(&exe_builder, executable_name)
 			strings.write_string(&exe_builder, executable_name)
 
 
-			exe_path := strings.to_cstring(&exe_builder)
-			if exe_fd, errno = linux.openat(dir_fd, exe_path, {.PATH, .CLOEXEC}); errno != .NONE {
+			exe_path = strings.to_cstring(&exe_builder)
+			if linux.access(exe_path, linux.X_OK) != .NONE {
 				return process, .Not_Exist
 				return process, .Not_Exist
 			}
 			}
-			if !has_executable_permissions(exe_fd) {
-				linux.close(exe_fd)
-				return process, .Permission_Denied
-			}
 		}
 		}
 	} else {
 	} else {
-		exe_path := temp_cstring(executable_name) or_return
-		if exe_fd, errno = linux.openat(dir_fd, exe_path, {.PATH, .CLOEXEC}); errno != .NONE {
-			return process, _get_platform_error(errno)
-		}
-		if !has_executable_permissions(exe_fd) {
-			linux.close(exe_fd)
-			return process, .Permission_Denied
+		exe_path = temp_cstring(executable_name) or_return
+		if linux.access(exe_path, linux.X_OK) != .NONE {
+			return process, .Not_Exist
 		}
 		}
 	}
 	}
 
 
-	// At this point, we have an executable.
-	defer linux.close(exe_fd)
-
 	// args and environment need to be a list of cstrings
 	// args and environment need to be a list of cstrings
 	// that are terminated by a nil pointer.
 	// that are terminated by a nil pointer.
 	cargs := make([]cstring, len(desc.command) + 1, temp_allocator()) or_return
 	cargs := make([]cstring, len(desc.command) + 1, temp_allocator()) or_return
@@ -492,7 +468,6 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
 	}
 	}
 	defer linux.close(child_pipe_fds[READ])
 	defer linux.close(child_pipe_fds[READ])
 
 
-
 	// TODO: This is the traditional textbook implementation with fork.
 	// TODO: This is the traditional textbook implementation with fork.
 	//       A more efficient implementation with vfork:
 	//       A more efficient implementation with vfork:
 	//
 	//
@@ -573,7 +548,7 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
 			write_errno_to_parent_and_abort(child_pipe_fds[WRITE], errno)
 			write_errno_to_parent_and_abort(child_pipe_fds[WRITE], errno)
 		}
 		}
 
 
-		errno = linux.execveat(exe_fd, "", &cargs[0], env, {.AT_EMPTY_PATH})
+		errno = linux.execveat(dir_fd, exe_path, &cargs[0], env)
 		assert(errno != nil)
 		assert(errno != nil)
 		write_errno_to_parent_and_abort(child_pipe_fds[WRITE], errno)
 		write_errno_to_parent_and_abort(child_pipe_fds[WRITE], errno)
 	}
 	}

+ 2 - 0
core/prof/spall/doc.odin

@@ -18,6 +18,8 @@ Example:
 		defer spall.context_destroy(&spall_ctx)
 		defer spall.context_destroy(&spall_ctx)
 
 
 		buffer_backing := make([]u8, spall.BUFFER_DEFAULT_SIZE)
 		buffer_backing := make([]u8, spall.BUFFER_DEFAULT_SIZE)
+		defer delete(buffer_backing)
+
 		spall_buffer = spall.buffer_create(buffer_backing, u32(sync.current_thread_id()))
 		spall_buffer = spall.buffer_create(buffer_backing, u32(sync.current_thread_id()))
 		defer spall.buffer_destroy(&spall_ctx, &spall_buffer)
 		defer spall.buffer_destroy(&spall_ctx, &spall_buffer)
 
 

+ 59 - 37
core/sys/linux/bits.odin

@@ -152,43 +152,65 @@ Errno :: enum i32 {
 	RDONLY flag is not present, because it has the value of 0, i.e. it is the
 	RDONLY flag is not present, because it has the value of 0, i.e. it is the
 	default, unless WRONLY or RDWR is specified.
 	default, unless WRONLY or RDWR is specified.
 */
 */
-Open_Flags_Bits :: enum {
-	WRONLY    = 0,
-	RDWR      = 1,
-	CREAT     = 6,
-	EXCL      = 7,
-	NOCTTY    = 8,
-	TRUNC     = 9,
-	APPEND    = 10,
-	NONBLOCK  = 11,
-	DSYNC     = 12,
-	ASYNC     = 13,
-	DIRECT    = 14,
-	LARGEFILE = 15,
-	DIRECTORY = 16,
-	NOFOLLOW  = 17,
-	NOATIME   = 18,
-	CLOEXEC   = 19,
-	PATH      = 21,
-}
-// https://github.com/torvalds/linux/blob/7367539ad4b0f8f9b396baf02110962333719a48/include/uapi/asm-generic/fcntl.h#L19
-#assert(1 << uint(Open_Flags_Bits.WRONLY)    == 0o0000000_1)
-#assert(1 << uint(Open_Flags_Bits.RDWR)      == 0o0000000_2)
-#assert(1 << uint(Open_Flags_Bits.CREAT)     == 0o00000_100)
-#assert(1 << uint(Open_Flags_Bits.EXCL)      == 0o00000_200)
-#assert(1 << uint(Open_Flags_Bits.NOCTTY)    == 0o00000_400)
-#assert(1 << uint(Open_Flags_Bits.TRUNC)     == 0o0000_1000)
-#assert(1 << uint(Open_Flags_Bits.APPEND)    == 0o0000_2000)
-#assert(1 << uint(Open_Flags_Bits.NONBLOCK)  == 0o0000_4000)
-#assert(1 << uint(Open_Flags_Bits.DSYNC)     == 0o000_10000)
-#assert(1 << uint(Open_Flags_Bits.ASYNC)     == 0o000_20000)
-#assert(1 << uint(Open_Flags_Bits.DIRECT)    == 0o000_40000)
-#assert(1 << uint(Open_Flags_Bits.LARGEFILE) == 0o00_100000)
-#assert(1 << uint(Open_Flags_Bits.DIRECTORY) == 0o00_200000)
-#assert(1 << uint(Open_Flags_Bits.NOFOLLOW)  == 0o00_400000)
-#assert(1 << uint(Open_Flags_Bits.NOATIME)   == 0o0_1000000)
-#assert(1 << uint(Open_Flags_Bits.CLOEXEC)   == 0o0_2000000)
-#assert(1 << uint(Open_Flags_Bits.PATH)      == 0o_10000000)
+when ODIN_ARCH != .arm64 && ODIN_ARCH != .arm32 {
+	Open_Flags_Bits :: enum {
+		WRONLY    = 0,
+		RDWR      = 1,
+		CREAT     = 6,
+		EXCL      = 7,
+		NOCTTY    = 8,
+		TRUNC     = 9,
+		APPEND    = 10,
+		NONBLOCK  = 11,
+		DSYNC     = 12,
+		ASYNC     = 13,
+		DIRECT    = 14,
+		LARGEFILE = 15,
+		DIRECTORY = 16,
+		NOFOLLOW  = 17,
+		NOATIME   = 18,
+		CLOEXEC   = 19,
+		PATH      = 21,
+	}
+	// https://github.com/torvalds/linux/blob/7367539ad4b0f8f9b396baf02110962333719a48/include/uapi/asm-generic/fcntl.h#L19
+	#assert(1 << uint(Open_Flags_Bits.WRONLY)    == 0o0000000_1)
+	#assert(1 << uint(Open_Flags_Bits.RDWR)      == 0o0000000_2)
+	#assert(1 << uint(Open_Flags_Bits.CREAT)     == 0o00000_100)
+	#assert(1 << uint(Open_Flags_Bits.EXCL)      == 0o00000_200)
+	#assert(1 << uint(Open_Flags_Bits.NOCTTY)    == 0o00000_400)
+	#assert(1 << uint(Open_Flags_Bits.TRUNC)     == 0o0000_1000)
+	#assert(1 << uint(Open_Flags_Bits.APPEND)    == 0o0000_2000)
+	#assert(1 << uint(Open_Flags_Bits.NONBLOCK)  == 0o0000_4000)
+	#assert(1 << uint(Open_Flags_Bits.DSYNC)     == 0o000_10000)
+	#assert(1 << uint(Open_Flags_Bits.ASYNC)     == 0o000_20000)
+	#assert(1 << uint(Open_Flags_Bits.DIRECT)    == 0o000_40000)
+	#assert(1 << uint(Open_Flags_Bits.LARGEFILE) == 0o00_100000)
+	#assert(1 << uint(Open_Flags_Bits.DIRECTORY) == 0o00_200000)
+	#assert(1 << uint(Open_Flags_Bits.NOFOLLOW)  == 0o00_400000)
+	#assert(1 << uint(Open_Flags_Bits.NOATIME)   == 0o0_1000000)
+	#assert(1 << uint(Open_Flags_Bits.CLOEXEC)   == 0o0_2000000)
+	#assert(1 << uint(Open_Flags_Bits.PATH)      == 0o_10000000)
+} else {
+	Open_Flags_Bits :: enum {
+		WRONLY    = 0,
+		RDWR      = 1,
+		CREAT     = 6,
+		EXCL      = 7,
+		NOCTTY    = 8,
+		TRUNC     = 9,
+		APPEND    = 10,
+		NONBLOCK  = 11,
+		DSYNC     = 12,
+		ASYNC     = 13,
+		DIRECTORY = 14,
+		NOFOLLOW  = 15,
+		DIRECT    = 16,
+		LARGEFILE = 17,
+		NOATIME   = 18,
+		CLOEXEC   = 19,
+		PATH      = 21,
+	}
+}
 
 
 /*
 /*
 	Bits for FD_Flags bitset
 	Bits for FD_Flags bitset

+ 2 - 2
core/sys/linux/helpers.odin

@@ -138,8 +138,8 @@ errno_unwrap :: proc {errno_unwrap2, errno_unwrap3}
 when size_of(int) == 4 {
 when size_of(int) == 4 {
 	// xxx64 system calls take some parameters as pairs of ulongs rather than a single pointer
 	// xxx64 system calls take some parameters as pairs of ulongs rather than a single pointer
 	@(private)
 	@(private)
-	compat64_arg_pair :: #force_inline proc "contextless" (a: i64) -> (hi: uint, lo: uint) {
-		no_sign := uint(a)
+	compat64_arg_pair :: #force_inline proc "contextless" (a: i64) -> (lo: uint, hi: uint) {
+		no_sign := u64(a)
 		hi = uint(no_sign >> 32)
 		hi = uint(no_sign >> 32)
 		lo = uint(no_sign & 0xffff_ffff)
 		lo = uint(no_sign & 0xffff_ffff)
 		return
 		return

+ 25 - 15
core/sys/linux/sys.odin

@@ -151,7 +151,8 @@ lseek :: proc "contextless" (fd: Fd, off: i64, whence: Seek_Whence) -> (i64, Err
 		return errno_unwrap(ret, i64)
 		return errno_unwrap(ret, i64)
 	} else {
 	} else {
 		result: i64 = ---
 		result: i64 = ---
-		ret := syscall(SYS__llseek, fd, compat64_arg_pair(off), &result, whence)
+		lo, hi := compat64_arg_pair(off)
+		ret := syscall(SYS__llseek, fd, hi, lo, &result, whence)
 		return result, Errno(-ret)
 		return result, Errno(-ret)
 	}
 	}
 }
 }
@@ -251,7 +252,11 @@ ioctl :: proc "contextless" (fd: Fd, request: u32, arg: uintptr) -> (uintptr) {
 	Available since Linux 2.2.
 	Available since Linux 2.2.
 */
 */
 pread :: proc "contextless" (fd: Fd, buf: []u8, offset: i64) -> (int, Errno) {
 pread :: proc "contextless" (fd: Fd, buf: []u8, offset: i64) -> (int, Errno) {
-	ret := syscall(SYS_pread64, fd, raw_data(buf), len(buf), compat64_arg_pair(offset))
+	when ODIN_ARCH == .arm32 {
+		ret := syscall(SYS_pread64, fd, raw_data(buf), len(buf), 0, compat64_arg_pair(offset))
+	} else {
+		ret := syscall(SYS_pread64, fd, raw_data(buf), len(buf), compat64_arg_pair(offset))
+	}
 	return errno_unwrap(ret, int)
 	return errno_unwrap(ret, int)
 }
 }
 
 
@@ -261,7 +266,11 @@ pread :: proc "contextless" (fd: Fd, buf: []u8, offset: i64) -> (int, Errno) {
 	Available since Linux 2.2.
 	Available since Linux 2.2.
 */
 */
 pwrite :: proc "contextless" (fd: Fd, buf: []u8, offset: i64) -> (int, Errno) {
 pwrite :: proc "contextless" (fd: Fd, buf: []u8, offset: i64) -> (int, Errno) {
-	ret := syscall(SYS_pwrite64, fd, raw_data(buf), len(buf), compat64_arg_pair(offset))
+	when ODIN_ARCH == .arm32 {
+		ret := syscall(SYS_pwrite64, fd, raw_data(buf), len(buf), 0, compat64_arg_pair(offset))
+	} else {
+		ret := syscall(SYS_pwrite64, fd, raw_data(buf), len(buf), compat64_arg_pair(offset))
+	}
 	return errno_unwrap(ret, int)
 	return errno_unwrap(ret, int)
 }
 }
 
 
@@ -1127,7 +1136,10 @@ fdatasync :: proc "contextless" (fd: Fd) -> (Errno) {
 	On 32-bit architectures available since Linux 2.4.
 	On 32-bit architectures available since Linux 2.4.
 */
 */
 truncate :: proc "contextless" (name: cstring, length: i64) -> (Errno) {
 truncate :: proc "contextless" (name: cstring, length: i64) -> (Errno) {
-	when size_of(int) == 4 {
+	when ODIN_ARCH == .arm32 {
+		ret := syscall(SYS_truncate64, cast(rawptr) name, 0, compat64_arg_pair(length))
+		return Errno(-ret)
+	} else when size_of(int) == 4 {
 		ret := syscall(SYS_truncate64, cast(rawptr) name, compat64_arg_pair(length))
 		ret := syscall(SYS_truncate64, cast(rawptr) name, compat64_arg_pair(length))
 		return Errno(-ret)
 		return Errno(-ret)
 	} else {
 	} else {
@@ -1141,7 +1153,10 @@ truncate :: proc "contextless" (name: cstring, length: i64) -> (Errno) {
 	On 32-bit architectures available since 2.4.
 	On 32-bit architectures available since 2.4.
 */
 */
 ftruncate :: proc "contextless" (fd: Fd, length: i64) -> (Errno) {
 ftruncate :: proc "contextless" (fd: Fd, length: i64) -> (Errno) {
-	when size_of(int) == 4 {
+	when ODIN_ARCH == .arm32 {
+		ret := syscall(SYS_ftruncate64, fd, 0, compat64_arg_pair(length))
+		return Errno(-ret)
+	} else when size_of(int) == 4 {
 		ret := syscall(SYS_ftruncate64, fd, compat64_arg_pair(length))
 		ret := syscall(SYS_ftruncate64, fd, compat64_arg_pair(length))
 		return Errno(-ret)
 		return Errno(-ret)
 	} else {
 	} else {
@@ -1952,10 +1967,10 @@ sigaltstack :: proc "contextless" (stack: ^Sig_Stack, old_stack: ^Sig_Stack) ->
 */
 */
 mknod :: proc "contextless" (name: cstring, mode: Mode, dev: Dev) -> (Errno) {
 mknod :: proc "contextless" (name: cstring, mode: Mode, dev: Dev) -> (Errno) {
 	when ODIN_ARCH == .arm64 || ODIN_ARCH == .riscv64 {
 	when ODIN_ARCH == .arm64 || ODIN_ARCH == .riscv64 {
-		ret := syscall(SYS_mknodat, AT_FDCWD, cast(rawptr) name, transmute(u32) mode, dev)
+		ret := syscall(SYS_mknodat, AT_FDCWD, cast(rawptr) name, transmute(u32) mode, cast(uint) dev)
 		return Errno(-ret)
 		return Errno(-ret)
 	} else {
 	} else {
-		ret := syscall(SYS_mknod, cast(rawptr) name, transmute(u32) mode, dev)
+		ret := syscall(SYS_mknod, cast(rawptr) name, transmute(u32) mode, cast(uint) dev)
 		return Errno(-ret)
 		return Errno(-ret)
 	}
 	}
 }
 }
@@ -2586,7 +2601,7 @@ mkdirat :: proc "contextless" (dirfd: Fd, name: cstring, mode: Mode) -> (Errno)
 	Available since Linux 2.6.16.
 	Available since Linux 2.6.16.
 */
 */
 mknodat :: proc "contextless" (dirfd: Fd, name: cstring, mode: Mode, dev: Dev) -> (Errno) {
 mknodat :: proc "contextless" (dirfd: Fd, name: cstring, mode: Mode, dev: Dev) -> (Errno) {
-	ret := syscall(SYS_mknodat, dirfd, cast(rawptr) name, transmute(u32) mode, dev)
+	ret := syscall(SYS_mknodat, dirfd, cast(rawptr) name, transmute(u32) mode, cast(uint) dev)
 	return Errno(-ret)
 	return Errno(-ret)
 }
 }
 
 
@@ -2684,13 +2699,8 @@ faccessat :: proc "contextless" (dirfd: Fd, name: cstring, mode: Mode = F_OK) ->
 	Available since Linux 2.6.16.
 	Available since Linux 2.6.16.
 */
 */
 ppoll :: proc "contextless" (fds: []Poll_Fd, timeout: ^Time_Spec, sigmask: ^Sig_Set) -> (i32, Errno) {
 ppoll :: proc "contextless" (fds: []Poll_Fd, timeout: ^Time_Spec, sigmask: ^Sig_Set) -> (i32, Errno) {
-	when size_of(int) == 8 {
-		ret := syscall(SYS_ppoll, raw_data(fds), len(fds), timeout, sigmask, size_of(Sig_Set))
-		return errno_unwrap(ret, i32)
-	} else {
-		ret := syscall(SYS_ppoll_time64, raw_data(fds), len(fds), timeout, sigmask, size_of(Sig_Set))
-		return errno_unwrap(ret, i32)
-	}
+	ret := syscall(SYS_ppoll, raw_data(fds), len(fds), timeout, sigmask, size_of(Sig_Set))
+	return errno_unwrap(ret, i32)
 }
 }
 
 
 // TODO(flysand): unshare
 // TODO(flysand): unshare

+ 166 - 66
core/sys/linux/types.odin

@@ -3,7 +3,7 @@ package linux
 /*
 /*
 	Type for storage device handle.
 	Type for storage device handle.
 */
 */
-Dev :: distinct int
+Dev :: distinct u64
 
 
 /*
 /*
 	Type for 32-bit User IDs.
 	Type for 32-bit User IDs.
@@ -153,6 +153,7 @@ when ODIN_ARCH == .amd64 {
 		uid:        Uid,
 		uid:        Uid,
 		gid:        Gid,
 		gid:        Gid,
 		rdev:       Dev,
 		rdev:       Dev,
+		_:          [4]u8,
 		size:       i64,
 		size:       i64,
 		blksize:    uint,
 		blksize:    uint,
 		blocks:     u64,
 		blocks:     u64,
@@ -516,79 +517,79 @@ Pid_FD_Flags :: bit_set[Pid_FD_Flags_Bits; i32]
 Sig_Set :: [_SIGSET_NWORDS]uint
 Sig_Set :: [_SIGSET_NWORDS]uint
 
 
 @private SI_MAX_SIZE       :: 128
 @private SI_MAX_SIZE       :: 128
-@private SI_ARCH_PREAMBLE  :: 4 * size_of(i32)
+@private SI_ARCH_PREAMBLE  :: 4 * size_of(i32) when size_of(rawptr) == 8 else 3 * size_of(i32)
 @private SI_PAD_SIZE       :: SI_MAX_SIZE - SI_ARCH_PREAMBLE
 @private SI_PAD_SIZE       :: SI_MAX_SIZE - SI_ARCH_PREAMBLE
 
 
 Sig_Handler_Fn :: #type proc "c" (sig: Signal)
 Sig_Handler_Fn :: #type proc "c" (sig: Signal)
 Sig_Restore_Fn :: #type proc "c" () -> !
 Sig_Restore_Fn :: #type proc "c" () -> !
 
 
-Sig_Info :: struct #packed {
-	signo: Signal,
-	errno: Errno,
-	code: i32,
-	_pad0: i32,
-	using _union: struct #raw_union {
-		_pad1: [SI_PAD_SIZE]u8,
-		using _kill: struct {
-			pid: Pid, /* sender's pid */
-			uid: Uid, /* sender's uid */
-		},
-		using _timer: struct {
-			timerid: i32,   /* timer id */
-			overrun: i32,   /* overrun count */
-			value: Sig_Val, /* timer value */
-		},
-		/* POSIX.1b signals */
-		using _rt: struct {
-			_pid0: Pid, /* sender's pid */
-			_uid0: Uid, /* sender's uid */
-		},
-		/* SIGCHLD */
-		using _sigchld: struct {
-			_pid1: Pid,  /* which child */
-			_uid1: Uid,  /* sender's uid */
-			status: i32, /* exit code */
-			utime: uint,
-			stime: uint, //clock_t
-		},
-		/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
-		using _sigfault: struct {
-			addr: rawptr, /* faulting insn/memory ref. */
-			using _: struct #raw_union {
-				trapno: i32,   /* Trap number that caused signal */
-				addr_lsb: i16, /* LSB of the reported address */
-				using _addr_bnd: struct {
-					_pad2: u64,
-					lower: rawptr, /* lower bound during fault */
-					upper: rawptr, /* upper bound during fault */
-				},
-				using _addr_pkey: struct {
-					_pad3: u64,
-					pkey: u32, /* protection key on PTE that faulted */
-				},
-				using _perf: struct {
-					perf_data: u64,
-					perf_type: u32,
-					perf_flags: u32,
+when size_of(rawptr) == 8 {
+	Sig_Info :: struct #packed {
+		signo: Signal,
+		errno: Errno,
+		code: i32,
+		_pad0: i32,
+		using _union: struct #raw_union {
+			_pad1: [SI_PAD_SIZE]u8,
+			using _kill: struct {
+				pid: Pid, /* sender's pid */
+				uid: Uid, /* sender's uid */
+			},
+			using _timer: struct {
+				timerid: i32,   /* timer id */
+				overrun: i32,   /* overrun count */
+				value: Sig_Val, /* timer value */
+			},
+			/* POSIX.1b signals */
+			using _rt: struct {
+				_pid0: Pid, /* sender's pid */
+				_uid0: Uid, /* sender's uid */
+			},
+			/* SIGCHLD */
+			using _sigchld: struct {
+				_pid1: Pid,  /* which child */
+				_uid1: Uid,  /* sender's uid */
+				status: i32, /* exit code */
+				utime: uint,
+				stime: uint, //clock_t
+			},
+			/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
+			using _sigfault: struct {
+				addr: rawptr, /* faulting insn/memory ref. */
+				using _: struct #raw_union {
+					trapno: i32,   /* Trap number that caused signal */
+					addr_lsb: i16, /* LSB of the reported address */
+					using _addr_bnd: struct {
+						_pad2: u64,
+						lower: rawptr, /* lower bound during fault */
+						upper: rawptr, /* upper bound during fault */
+					},
+					using _addr_pkey: struct {
+						_pad3: u64,
+						pkey: u32, /* protection key on PTE that faulted */
+					},
+					using _perf: struct {
+						perf_data: u64,
+						perf_type: u32,
+						perf_flags: u32,
+					},
 				},
 				},
 			},
 			},
+			/* SIGPOLL */
+			using _sigpoll: struct {
+				band: int, /* POLL_IN, POLL_OUT, POLL_MSG */
+				fd: Fd,
+			},
+			/* SIGSYS */
+			using _sigsys: struct {
+				call_addr: rawptr, /* calling user insn */
+				syscall: i32,      /* triggering system call number */
+				arch: u32,         /* AUDIT_ARCH_* of syscall */
+			},
 		},
 		},
-		/* SIGPOLL */
-		using _sigpoll: struct {
-			band: int, /* POLL_IN, POLL_OUT, POLL_MSG */
-			fd: Fd,
-		},
-		/* SIGSYS */
-		using _sigsys: struct {
-			call_addr: rawptr, /* calling user insn */
-			syscall: i32,      /* triggering system call number */
-			arch: u32,         /* AUDIT_ARCH_* of syscall */
-		},
-	},
-}
+	}
 
 
-#assert(size_of(Sig_Info) == 128)
-when ODIN_ARCH == .amd64 || ODIN_ARCH == .arm64 {
+	#assert(size_of(Sig_Info) == 128)
 	#assert(offset_of(Sig_Info, signo)      == 0x00)
 	#assert(offset_of(Sig_Info, signo)      == 0x00)
 	#assert(offset_of(Sig_Info, errno)      == 0x04)
 	#assert(offset_of(Sig_Info, errno)      == 0x04)
 	#assert(offset_of(Sig_Info, code)       == 0x08)
 	#assert(offset_of(Sig_Info, code)       == 0x08)
@@ -615,7 +616,96 @@ when ODIN_ARCH == .amd64 || ODIN_ARCH == .arm64 {
 	#assert(offset_of(Sig_Info, syscall)    == 0x18)
 	#assert(offset_of(Sig_Info, syscall)    == 0x18)
 	#assert(offset_of(Sig_Info, arch)       == 0x1C)
 	#assert(offset_of(Sig_Info, arch)       == 0x1C)
 } else {
 } else {
-	// TODO
+	Sig_Info :: struct {
+		signo: Signal,
+		errno: Errno,
+		code: i32,
+		using _union: struct #raw_union {
+			_pad1: [SI_PAD_SIZE]u8,
+			using _kill: struct {
+				pid: Pid, /* sender's pid */
+				uid: Uid, /* sender's uid */
+			},
+			using _timer: struct {
+				timerid: i32,   /* timer id */
+				overrun: i32,   /* overrun count */
+				value: Sig_Val, /* timer value */
+			},
+			/* POSIX.1b signals */
+			using _rt: struct {
+				_pid0: Pid, /* sender's pid */
+				_uid0: Uid, /* sender's uid */
+			},
+			/* SIGCHLD */
+			using _sigchld: struct {
+				_pid1: Pid,  /* which child */
+				_uid1: Uid,  /* sender's uid */
+				status: i32, /* exit code */
+				utime: uint,
+				stime: uint, //clock_t
+			},
+			/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
+			using _sigfault: struct {
+				addr: rawptr, /* faulting insn/memory ref. */
+				using _: struct #raw_union {
+					trapno: i32,   /* Trap number that caused signal */
+					addr_lsb: i16, /* LSB of the reported address */
+					using _addr_bnd: struct {
+						_pad2: u32,
+						lower: rawptr, /* lower bound during fault */
+						upper: rawptr, /* upper bound during fault */
+					},
+					using _addr_pkey: struct {
+						_pad3: u32,
+						pkey: u32, /* protection key on PTE that faulted */
+					},
+					using _perf: struct {
+						perf_data: u32,
+						perf_type: u32,
+						perf_flags: u32,
+					},
+				},
+			},
+			/* SIGPOLL */
+			using _sigpoll: struct {
+				band: int, /* POLL_IN, POLL_OUT, POLL_MSG */
+				fd: Fd,
+			},
+			/* SIGSYS */
+			using _sigsys: struct {
+				call_addr: rawptr, /* calling user insn */
+				syscall: i32,      /* triggering system call number */
+				arch: u32,         /* AUDIT_ARCH_* of syscall */
+			},
+		},
+	}
+
+	#assert(size_of(Sig_Info) == 128)
+	#assert(offset_of(Sig_Info, signo)      == 0x00)
+	#assert(offset_of(Sig_Info, errno)      == 0x04)
+	#assert(offset_of(Sig_Info, code)       == 0x08)
+	#assert(offset_of(Sig_Info, pid)        == 0x0c)
+	#assert(offset_of(Sig_Info, uid)        == 0x10)
+	#assert(offset_of(Sig_Info, timerid)    == 0x0c)
+	#assert(offset_of(Sig_Info, overrun)    == 0x10)
+	#assert(offset_of(Sig_Info, value)      == 0x14)
+	#assert(offset_of(Sig_Info, status)     == 0x14)
+	#assert(offset_of(Sig_Info, utime)      == 0x18)
+	#assert(offset_of(Sig_Info, stime)      == 0x1c)
+	#assert(offset_of(Sig_Info, addr)       == 0x0c)
+	#assert(offset_of(Sig_Info, addr_lsb)   == 0x10)
+	#assert(offset_of(Sig_Info, trapno)     == 0x10)
+	#assert(offset_of(Sig_Info, lower)      == 0x14)
+	#assert(offset_of(Sig_Info, upper)      == 0x18)
+	#assert(offset_of(Sig_Info, pkey)       == 0x14)
+	#assert(offset_of(Sig_Info, perf_data)  == 0x10)
+	#assert(offset_of(Sig_Info, perf_type)  == 0x14)
+	#assert(offset_of(Sig_Info, perf_flags) == 0x18)
+	#assert(offset_of(Sig_Info, band)       == 0x0c)
+	#assert(offset_of(Sig_Info, fd)         == 0x10)
+	#assert(offset_of(Sig_Info, call_addr)  == 0x0c)
+	#assert(offset_of(Sig_Info, syscall)    == 0x10)
+	#assert(offset_of(Sig_Info, arch)       == 0x14)
 }
 }
 
 
 SIGEV_MAX_SIZE :: 64
 SIGEV_MAX_SIZE :: 64
@@ -684,6 +774,14 @@ Address_Family :: distinct Protocol_Family
 */
 */
 Socket_Msg :: bit_set[Socket_Msg_Bits; i32]
 Socket_Msg :: bit_set[Socket_Msg_Bits; i32]
 
 
+/*
+	Struct representing a generic socket address.
+*/
+Sock_Addr :: struct #packed {
+	sa_family: Address_Family,
+	sa_data:   [14]u8,
+}
+
 /*
 /*
 	Struct representing IPv4 socket address.
 	Struct representing IPv4 socket address.
 */
 */
@@ -691,6 +789,7 @@ Sock_Addr_In :: struct #packed {
 	sin_family: Address_Family,
 	sin_family: Address_Family,
 	sin_port:   u16be,
 	sin_port:   u16be,
 	sin_addr:   [4]u8,
 	sin_addr:   [4]u8,
+	sin_zero:   [size_of(Sock_Addr) - size_of(Address_Family) - size_of(u16be) - size_of([4]u8)]u8,
 }
 }
 
 
 /*
 /*
@@ -720,6 +819,7 @@ Sock_Addr_Any :: struct #raw_union {
 		family: Address_Family,
 		family: Address_Family,
 		port:   u16be,
 		port:   u16be,
 	},
 	},
+	using generic: Sock_Addr,
 	using ipv4: Sock_Addr_In,
 	using ipv4: Sock_Addr_In,
 	using ipv6: Sock_Addr_In6,
 	using ipv6: Sock_Addr_In6,
 	using uds: Sock_Addr_Un,
 	using uds: Sock_Addr_Un,

+ 21 - 1
core/sys/windows/kernel32.odin

@@ -20,6 +20,15 @@ COMMON_LVB_GRID_RVERTICAL  :: WORD(0x1000)
 COMMON_LVB_REVERSE_VIDEO   :: WORD(0x4000)
 COMMON_LVB_REVERSE_VIDEO   :: WORD(0x4000)
 COMMON_LVB_UNDERSCORE      :: WORD(0x8000)
 COMMON_LVB_UNDERSCORE      :: WORD(0x8000)
 COMMON_LVB_SBCSDBCS        :: WORD(0x0300)
 COMMON_LVB_SBCSDBCS        :: WORD(0x0300)
+EV_BREAK                   :: DWORD(0x0040)
+EV_CTS                     :: DWORD(0x0008)
+EV_DSR                     :: DWORD(0x0010)
+EV_ERR                     :: DWORD(0x0080)
+EV_RING                    :: DWORD(0x0100)
+EV_RLSD                    :: DWORD(0x0020)
+EV_RXCHAR                  :: DWORD(0x0001)
+EV_RXFLAG                  :: DWORD(0x0002)
+EV_TXEMPTY                 :: DWORD(0x0004)
 
 
 @(default_calling_convention="system")
 @(default_calling_convention="system")
 foreign kernel32 {
 foreign kernel32 {
@@ -109,7 +118,9 @@ foreign kernel32 {
 	ClearCommError :: proc(hFile: HANDLE, lpErrors: ^Com_Error, lpStat: ^COMSTAT) -> BOOL ---
 	ClearCommError :: proc(hFile: HANDLE, lpErrors: ^Com_Error, lpStat: ^COMSTAT) -> BOOL ---
 	GetCommState :: proc(handle: HANDLE, dcb: ^DCB) -> BOOL ---
 	GetCommState :: proc(handle: HANDLE, dcb: ^DCB) -> BOOL ---
 	SetCommState :: proc(handle: HANDLE, dcb: ^DCB) -> BOOL ---
 	SetCommState :: proc(handle: HANDLE, dcb: ^DCB) -> BOOL ---
-	GetCommPorts :: proc(lpPortNumbers: PULONG, uPortNumbersCount: ULONG, puPortNumbersFound: PULONG) -> ULONG ---
+	SetCommMask :: proc(handle: HANDLE, dwEvtMap: DWORD) -> BOOL ---
+	GetCommMask :: proc(handle: HANDLE, lpEvtMask: LPDWORD) -> BOOL ---
+	WaitCommEvent :: proc(handle: HANDLE, lpEvtMask: LPDWORD, lpOverlapped: LPOVERLAPPED) -> BOOL ---
 	GetCommandLineW :: proc() -> LPCWSTR ---
 	GetCommandLineW :: proc() -> LPCWSTR ---
 	GetTempPathW :: proc(nBufferLength: DWORD, lpBuffer: LPCWSTR) -> DWORD ---
 	GetTempPathW :: proc(nBufferLength: DWORD, lpBuffer: LPCWSTR) -> DWORD ---
 	GetCurrentProcess :: proc() -> HANDLE ---
 	GetCurrentProcess :: proc() -> HANDLE ---
@@ -239,6 +250,10 @@ foreign kernel32 {
 		hThread: HANDLE,
 		hThread: HANDLE,
 		lpContext: LPCONTEXT,
 		lpContext: LPCONTEXT,
 	) -> BOOL ---
 	) -> BOOL ---
+	SetThreadContext :: proc(
+		hThread: HANDLE,
+		lpContext: LPCONTEXT,
+	) -> BOOL ---
 	CreateProcessW :: proc(
 	CreateProcessW :: proc(
 		lpApplicationName: LPCWSTR,
 		lpApplicationName: LPCWSTR,
 		lpCommandLine: LPWSTR,
 		lpCommandLine: LPWSTR,
@@ -1068,6 +1083,11 @@ foreign one_core {
 		PageProtection: ULONG,
 		PageProtection: ULONG,
 		PreferredNode: ULONG,
 		PreferredNode: ULONG,
 	) -> PVOID ---
 	) -> PVOID ---
+	GetCommPorts :: proc(
+		lpPortNumbers: PULONG,
+		uPortNumbersCount: ULONG,
+		puPortNumbersFound: PULONG,
+	) -> ULONG ---
 }
 }
 
 
 
 

+ 26 - 2
core/sys/windows/types.odin

@@ -143,6 +143,7 @@ LPWSAPROTOCOL_INFO :: ^WSAPROTOCOL_INFO
 LPSTR :: ^CHAR
 LPSTR :: ^CHAR
 LPWSTR :: ^WCHAR
 LPWSTR :: ^WCHAR
 OLECHAR :: WCHAR
 OLECHAR :: WCHAR
+BSTR :: ^OLECHAR
 LPOLESTR :: ^OLECHAR
 LPOLESTR :: ^OLECHAR
 LPCOLESTR :: LPCSTR
 LPCOLESTR :: LPCSTR
 LPFILETIME :: ^FILETIME
 LPFILETIME :: ^FILETIME
@@ -2694,11 +2695,23 @@ EXCEPTION_MAXIMUM_PARAMETERS :: 15
 
 
 EXCEPTION_DATATYPE_MISALIGNMENT     :: 0x80000002
 EXCEPTION_DATATYPE_MISALIGNMENT     :: 0x80000002
 EXCEPTION_BREAKPOINT                :: 0x80000003
 EXCEPTION_BREAKPOINT                :: 0x80000003
+EXCEPTION_SINGLE_STEP               :: 0x80000004
 EXCEPTION_ACCESS_VIOLATION          :: 0xC0000005
 EXCEPTION_ACCESS_VIOLATION          :: 0xC0000005
+EXCEPTION_IN_PAGE_ERROR             :: 0xC0000006
 EXCEPTION_ILLEGAL_INSTRUCTION       :: 0xC000001D
 EXCEPTION_ILLEGAL_INSTRUCTION       :: 0xC000001D
+EXCEPTION_NONCONTINUABLE_EXCEPTION  :: 0xC0000025
+EXCEPTION_INVALID_DISPOSITION       :: 0xC0000026
 EXCEPTION_ARRAY_BOUNDS_EXCEEDED     :: 0xC000008C
 EXCEPTION_ARRAY_BOUNDS_EXCEEDED     :: 0xC000008C
+EXCEPTION_FLT_DENORMAL_OPERAND      :: 0xC000008D
+EXCEPTION_FLT_DIVIDE_BY_ZERO        :: 0xC000008E
+EXCEPTION_FLT_INEXACT_RESULT        :: 0xC000008F
+EXCEPTION_FLT_INVALID_OPERATION     :: 0xC0000090
+EXCEPTION_FLT_OVERFLOW              :: 0xC0000091
+EXCEPTION_FLT_STACK_CHECK           :: 0xC0000092
+EXCEPTION_FLT_UNDERFLOW             :: 0xC0000093
 EXCEPTION_INT_DIVIDE_BY_ZERO        :: 0xC0000094
 EXCEPTION_INT_DIVIDE_BY_ZERO        :: 0xC0000094
 EXCEPTION_INT_OVERFLOW              :: 0xC0000095
 EXCEPTION_INT_OVERFLOW              :: 0xC0000095
+EXCEPTION_PRIV_INSTRUCTION          :: 0xC0000096
 EXCEPTION_STACK_OVERFLOW            :: 0xC00000FD
 EXCEPTION_STACK_OVERFLOW            :: 0xC00000FD
 STATUS_PRIVILEGED_INSTRUCTION       :: 0xC0000096
 STATUS_PRIVILEGED_INSTRUCTION       :: 0xC0000096
 
 
@@ -3415,8 +3428,6 @@ TIME_ZONE_INFORMATION :: struct {
 	DaylightBias: LONG,
 	DaylightBias: LONG,
 }
 }
 
 
-
-@(private="file")
 IMAGE_DOS_HEADER :: struct {
 IMAGE_DOS_HEADER :: struct {
 	e_magic:    WORD,
 	e_magic:    WORD,
 	e_cblp:     WORD,
 	e_cblp:     WORD,
@@ -3534,6 +3545,19 @@ IMAGE_EXPORT_DIRECTORY :: struct {
 	AddressOfNameOrdinals: DWORD, // RVA from base of image
 	AddressOfNameOrdinals: DWORD, // RVA from base of image
 }
 }
 
 
+IMAGE_DEBUG_DIRECTORY :: struct {
+	Characteristics:  DWORD,
+	TimeDateStamp:    DWORD,
+	MajorVersion:     WORD,
+	MinorVersion:     WORD,
+	Type:             DWORD,
+	SizeOfData:       DWORD,
+	AddressOfRawData: DWORD,
+	PointerToRawData: DWORD,
+}
+
+IMAGE_DEBUG_TYPE_CODEVIEW :: 2
+
 SICHINTF :: DWORD
 SICHINTF :: DWORD
 SHCONTF :: DWORD
 SHCONTF :: DWORD
 SFGAOF :: ULONG
 SFGAOF :: ULONG

+ 1 - 0
core/sys/windows/user32.odin

@@ -51,6 +51,7 @@ foreign user32 {
 	IsWindowVisible :: proc(hwnd: HWND) -> BOOL ---
 	IsWindowVisible :: proc(hwnd: HWND) -> BOOL ---
 	IsWindowEnabled :: proc(hwnd: HWND) -> BOOL ---
 	IsWindowEnabled :: proc(hwnd: HWND) -> BOOL ---
 	IsIconic :: proc(hwnd: HWND) -> BOOL ---
 	IsIconic :: proc(hwnd: HWND) -> BOOL ---
+	IsZoomed :: proc(hwnd: HWND) -> BOOL ---
 	BringWindowToTop :: proc(hWnd: HWND) -> BOOL ---
 	BringWindowToTop :: proc(hWnd: HWND) -> BOOL ---
 	GetTopWindow :: proc(hWnd: HWND) -> HWND ---
 	GetTopWindow :: proc(hWnd: HWND) -> HWND ---
 	SetForegroundWindow :: proc(hWnd: HWND) -> BOOL ---
 	SetForegroundWindow :: proc(hWnd: HWND) -> BOOL ---

+ 153 - 141
core/time/timezone/tz_windows.odin

@@ -11,146 +11,147 @@ TZ_Abbrev :: struct {
 	dst: string,
 	dst: string,
 }
 }
 
 
-tz_abbrevs := map[string]TZ_Abbrev {
-	"Egypt Standard Time"             = {"EET", "EEST"},    // Africa/Cairo
-	"Morocco Standard Time"           = {"+00", "+01"},     // Africa/Casablanca
-	"South Africa Standard Time"      = {"SAST", "SAST"},   // Africa/Johannesburg
-	"South Sudan Standard Time"       = {"CAT", "CAT"},     // Africa/Juba
-	"Sudan Standard Time"             = {"CAT", "CAT"},     // Africa/Khartoum
-	"W. Central Africa Standard Time" = {"WAT", "WAT"},     // Africa/Lagos
-	"E. Africa Standard Time"         = {"EAT", "EAT"},     // Africa/Nairobi
-	"Sao Tome Standard Time"          = {"GMT", "GMT"},     // Africa/Sao_Tome
-	"Libya Standard Time"             = {"EET", "EET"},     // Africa/Tripoli
-	"Namibia Standard Time"           = {"CAT", "CAT"},     // Africa/Windhoek
-	"Aleutian Standard Time"          = {"HST", "HDT"},     // America/Adak
-	"Alaskan Standard Time"           = {"AKST", "AKDT"},   // America/Anchorage
-	"Tocantins Standard Time"         = {"-03", "-03"},     // America/Araguaina
-	"Paraguay Standard Time"          = {"-04", "-03"},     // America/Asuncion
-	"Bahia Standard Time"             = {"-03", "-03"},     // America/Bahia
-	"SA Pacific Standard Time"        = {"-05", "-05"},     // America/Bogota
-	"Argentina Standard Time"         = {"-03", "-03"},     // America/Buenos_Aires
-	"Eastern Standard Time (Mexico)"  = {"EST", "EST"},     // America/Cancun
-	"Venezuela Standard Time"         = {"-04", "-04"},     // America/Caracas
-	"SA Eastern Standard Time"        = {"-03", "-03"},     // America/Cayenne
-	"Central Standard Time"           = {"CST", "CDT"},     // America/Chicago
-	"Central Brazilian Standard Time" = {"-04", "-04"},     // America/Cuiaba
-	"Mountain Standard Time"          = {"MST", "MDT"},     // America/Denver
-	"Greenland Standard Time"         = {"-03", "-02"},     // America/Godthab
-	"Turks And Caicos Standard Time"  = {"EST", "EDT"},     // America/Grand_Turk
-	"Central America Standard Time"   = {"CST", "CST"},     // America/Guatemala
-	"Atlantic Standard Time"          = {"AST", "ADT"},     // America/Halifax
-	"Cuba Standard Time"              = {"CST", "CDT"},     // America/Havana
-	"US Eastern Standard Time"        = {"EST", "EDT"},     // America/Indianapolis
-	"SA Western Standard Time"        = {"-04", "-04"},     // America/La_Paz
-	"Pacific Standard Time"           = {"PST", "PDT"},     // America/Los_Angeles
-	"Mountain Standard Time (Mexico)" = {"MST", "MST"},     // America/Mazatlan
-	"Central Standard Time (Mexico)"  = {"CST", "CST"},     // America/Mexico_City
-	"Saint Pierre Standard Time"      = {"-03", "-02"},     // America/Miquelon
-	"Montevideo Standard Time"        = {"-03", "-03"},     // America/Montevideo
-	"Eastern Standard Time"           = {"EST", "EDT"},     // America/New_York
-	"US Mountain Standard Time"       = {"MST", "MST"},     // America/Phoenix
-	"Haiti Standard Time"             = {"EST", "EDT"},     // America/Port-au-Prince
-	"Magallanes Standard Time"        = {"-03", "-03"},     // America/Punta_Arenas
-	"Canada Central Standard Time"    = {"CST", "CST"},     // America/Regina
-	"Pacific SA Standard Time"        = {"-04", "-03"},     // America/Santiago
-	"E. South America Standard Time"  = {"-03", "-03"},     // America/Sao_Paulo
-	"Newfoundland Standard Time"      = {"NST", "NDT"},     // America/St_Johns
-	"Pacific Standard Time (Mexico)"  = {"PST", "PDT"},     // America/Tijuana
-	"Yukon Standard Time"             = {"MST", "MST"},     // America/Whitehorse
-	"Central Asia Standard Time"      = {"+06", "+06"},     // Asia/Almaty
-	"Jordan Standard Time"            = {"+03", "+03"},     // Asia/Amman
-	"Arabic Standard Time"            = {"+03", "+03"},     // Asia/Baghdad
-	"Azerbaijan Standard Time"        = {"+04", "+04"},     // Asia/Baku
-	"SE Asia Standard Time"           = {"+07", "+07"},     // Asia/Bangkok
-	"Altai Standard Time"             = {"+07", "+07"},     // Asia/Barnaul
-	"Middle East Standard Time"       = {"EET", "EEST"},    // Asia/Beirut
-	"India Standard Time"             = {"IST", "IST"},     // Asia/Calcutta
-	"Transbaikal Standard Time"       = {"+09", "+09"},     // Asia/Chita
-	"Sri Lanka Standard Time"         = {"+0530", "+0530"}, // Asia/Colombo
-	"Syria Standard Time"             = {"+03", "+03"},     // Asia/Damascus
-	"Bangladesh Standard Time"        = {"+06", "+06"},     // Asia/Dhaka
-	"Arabian Standard Time"           = {"+04", "+04"},     // Asia/Dubai
-	"West Bank Standard Time"         = {"EET", "EEST"},    // Asia/Hebron
-	"W. Mongolia Standard Time"       = {"+07", "+07"},     // Asia/Hovd
-	"North Asia East Standard Time"   = {"+08", "+08"},     // Asia/Irkutsk
-	"Israel Standard Time"            = {"IST", "IDT"},     // Asia/Jerusalem
-	"Afghanistan Standard Time"       = {"+0430", "+0430"}, // Asia/Kabul
-	"Russia Time Zone 11"             = {"+12", "+12"},     // Asia/Kamchatka
-	"Pakistan Standard Time"          = {"PKT", "PKT"},     // Asia/Karachi
-	"Nepal Standard Time"             = {"+0545", "+0545"}, // Asia/Katmandu
-	"North Asia Standard Time"        = {"+07", "+07"},     // Asia/Krasnoyarsk
-	"Magadan Standard Time"           = {"+11", "+11"},     // Asia/Magadan
-	"N. Central Asia Standard Time"   = {"+07", "+07"},     // Asia/Novosibirsk
-	"Omsk Standard Time"              = {"+06", "+06"},     // Asia/Omsk
-	"North Korea Standard Time"       = {"KST", "KST"},     // Asia/Pyongyang
-	"Qyzylorda Standard Time"         = {"+05", "+05"},     // Asia/Qyzylorda
-	"Myanmar Standard Time"           = {"+0630", "+0630"}, // Asia/Rangoon
-	"Arab Standard Time"              = {"+03", "+03"},     // Asia/Riyadh
-	"Sakhalin Standard Time"          = {"+11", "+11"},     // Asia/Sakhalin
-	"Korea Standard Time"             = {"KST", "KST"},     // Asia/Seoul
-	"China Standard Time"             = {"CST", "CST"},     // Asia/Shanghai
-	"Singapore Standard Time"         = {"+08", "+08"},     // Asia/Singapore
-	"Russia Time Zone 10"             = {"+11", "+11"},     // Asia/Srednekolymsk
-	"Taipei Standard Time"            = {"CST", "CST"},     // Asia/Taipei
-	"West Asia Standard Time"         = {"+05", "+05"},     // Asia/Tashkent
-	"Georgian Standard Time"          = {"+04", "+04"},     // Asia/Tbilisi
-	"Iran Standard Time"              = {"+0330", "+0330"}, // Asia/Tehran
-	"Tokyo Standard Time"             = {"JST", "JST"},     // Asia/Tokyo
-	"Tomsk Standard Time"             = {"+07", "+07"},     // Asia/Tomsk
-	"Ulaanbaatar Standard Time"       = {"+08", "+08"},     // Asia/Ulaanbaatar
-	"Vladivostok Standard Time"       = {"+10", "+10"},     // Asia/Vladivostok
-	"Yakutsk Standard Time"           = {"+09", "+09"},     // Asia/Yakutsk
-	"Ekaterinburg Standard Time"      = {"+05", "+05"},     // Asia/Yekaterinburg
-	"Caucasus Standard Time"          = {"+04", "+04"},     // Asia/Yerevan
-	"Azores Standard Time"            = {"-01", "+00"},     // Atlantic/Azores
-	"Cape Verde Standard Time"        = {"-01", "-01"},     // Atlantic/Cape_Verde
-	"Greenwich Standard Time"         = {"GMT", "GMT"},     // Atlantic/Reykjavik
-	"Cen. Australia Standard Time"    = {"ACST", "ACDT"},   // Australia/Adelaide
-	"E. Australia Standard Time"      = {"AEST", "AEST"},   // Australia/Brisbane
-	"AUS Central Standard Time"       = {"ACST", "ACST"},   // Australia/Darwin
-	"Aus Central W. Standard Time"    = {"+0845", "+0845"}, // Australia/Eucla
-	"Tasmania Standard Time"          = {"AEST", "AEDT"},   // Australia/Hobart
-	"Lord Howe Standard Time"         = {"+1030", "+11"},   // Australia/Lord_Howe
-	"W. Australia Standard Time"      = {"AWST", "AWST"},   // Australia/Perth
-	"AUS Eastern Standard Time"       = {"AEST", "AEDT"},   // Australia/Sydney
-	"UTC-11"                          = {"-11", "-11"},     // Etc/GMT+11
-	"Dateline Standard Time"          = {"-12", "-12"},     // Etc/GMT+12
-	"UTC-02"                          = {"-02", "-02"},     // Etc/GMT+2
-	"UTC-08"                          = {"-08", "-08"},     // Etc/GMT+8
-	"UTC-09"                          = {"-09", "-09"},     // Etc/GMT+9
-	"UTC+12"                          = {"+12", "+12"},     // Etc/GMT-12
-	"UTC+13"                          = {"+13", "+13"},     // Etc/GMT-13
-	"UTC"                             = {"UTC", "UTC"},     // Etc/UTC
-	"Astrakhan Standard Time"         = {"+04", "+04"},     // Europe/Astrakhan
-	"W. Europe Standard Time"         = {"CET", "CEST"},    // Europe/Berlin
-	"GTB Standard Time"               = {"EET", "EEST"},    // Europe/Bucharest
-	"Central Europe Standard Time"    = {"CET", "CEST"},    // Europe/Budapest
-	"E. Europe Standard Time"         = {"EET", "EEST"},    // Europe/Chisinau
-	"Turkey Standard Time"            = {"+03", "+03"},     // Europe/Istanbul
-	"Kaliningrad Standard Time"       = {"EET", "EET"},     // Europe/Kaliningrad
-	"FLE Standard Time"               = {"EET", "EEST"},    // Europe/Kiev
-	"GMT Standard Time"               = {"GMT", "BST"},     // Europe/London
-	"Belarus Standard Time"           = {"+03", "+03"},     // Europe/Minsk
-	"Russian Standard Time"           = {"MSK", "MSK"},     // Europe/Moscow
-	"Romance Standard Time"           = {"CET", "CEST"},    // Europe/Paris
-	"Russia Time Zone 3"              = {"+04", "+04"},     // Europe/Samara
-	"Saratov Standard Time"           = {"+04", "+04"},     // Europe/Saratov
-	"Volgograd Standard Time"         = {"MSK", "MSK"},     // Europe/Volgograd
-	"Central European Standard Time"  = {"CET", "CEST"},    // Europe/Warsaw
-	"Mauritius Standard Time"         = {"+04", "+04"},     // Indian/Mauritius
-	"Samoa Standard Time"             = {"+13", "+13"},     // Pacific/Apia
-	"New Zealand Standard Time"       = {"NZST", "NZDT"},   // Pacific/Auckland
-	"Bougainville Standard Time"      = {"+11", "+11"},     // Pacific/Bougainville
-	"Chatham Islands Standard Time"   = {"+1245", "+1345"}, // Pacific/Chatham
-	"Easter Island Standard Time"     = {"-06", "-05"},     // Pacific/Easter
-	"Fiji Standard Time"              = {"+12", "+12"},     // Pacific/Fiji
-	"Central Pacific Standard Time"   = {"+11", "+11"},     // Pacific/Guadalcanal
-	"Hawaiian Standard Time"          = {"HST", "HST"},     // Pacific/Honolulu
-	"Line Islands Standard Time"      = {"+14", "+14"},     // Pacific/Kiritimati
-	"Marquesas Standard Time"         = {"-0930", "-0930"}, // Pacific/Marquesas
-	"Norfolk Standard Time"           = {"+11", "+12"},     // Pacific/Norfolk
-	"West Pacific Standard Time"      = {"+10", "+10"},     // Pacific/Port_Moresby
-	"Tonga Standard Time"             = {"+13", "+13"},     // Pacific/Tongatapu
+@(rodata)
+tz_abbrevs := [?]struct{key: string, value: TZ_Abbrev}{
+	{"Egypt Standard Time",             {"EET", "EEST"}},    // Africa/Cairo
+	{"Morocco Standard Time",           {"+00", "+01"}},     // Africa/Casablanca
+	{"South Africa Standard Time",      {"SAST", "SAST"}},   // Africa/Johannesburg
+	{"South Sudan Standard Time",       {"CAT", "CAT"}},     // Africa/Juba
+	{"Sudan Standard Time",             {"CAT", "CAT"}},     // Africa/Khartoum
+	{"W. Central Africa Standard Time", {"WAT", "WAT"}},     // Africa/Lagos
+	{"E. Africa Standard Time",         {"EAT", "EAT"}},     // Africa/Nairobi
+	{"Sao Tome Standard Time",          {"GMT", "GMT"}},     // Africa/Sao_Tome
+	{"Libya Standard Time",             {"EET", "EET"}},     // Africa/Tripoli
+	{"Namibia Standard Time",           {"CAT", "CAT"}},     // Africa/Windhoek
+	{"Aleutian Standard Time",          {"HST", "HDT"}},     // America/Adak
+	{"Alaskan Standard Time",           {"AKST", "AKDT"}},   // America/Anchorage
+	{"Tocantins Standard Time",         {"-03", "-03"}},     // America/Araguaina
+	{"Paraguay Standard Time",          {"-04", "-03"}},     // America/Asuncion
+	{"Bahia Standard Time",             {"-03", "-03"}},     // America/Bahia
+	{"SA Pacific Standard Time",        {"-05", "-05"}},     // America/Bogota
+	{"Argentina Standard Time",         {"-03", "-03"}},     // America/Buenos_Aires
+	{"Eastern Standard Time (Mexico)",  {"EST", "EST"}},     // America/Cancun
+	{"Venezuela Standard Time",         {"-04", "-04"}},     // America/Caracas
+	{"SA Eastern Standard Time",        {"-03", "-03"}},     // America/Cayenne
+	{"Central Standard Time",           {"CST", "CDT"}},     // America/Chicago
+	{"Central Brazilian Standard Time", {"-04", "-04"}},     // America/Cuiaba
+	{"Mountain Standard Time",          {"MST", "MDT"}},     // America/Denver
+	{"Greenland Standard Time",         {"-03", "-02"}},     // America/Godthab
+	{"Turks And Caicos Standard Time",  {"EST", "EDT"}},     // America/Grand_Turk
+	{"Central America Standard Time",   {"CST", "CST"}},     // America/Guatemala
+	{"Atlantic Standard Time",          {"AST", "ADT"}},     // America/Halifax
+	{"Cuba Standard Time",              {"CST", "CDT"}},     // America/Havana
+	{"US Eastern Standard Time",        {"EST", "EDT"}},     // America/Indianapolis
+	{"SA Western Standard Time",        {"-04", "-04"}},     // America/La_Paz
+	{"Pacific Standard Time",           {"PST", "PDT"}},     // America/Los_Angeles
+	{"Mountain Standard Time (Mexico)", {"MST", "MST"}},     // America/Mazatlan
+	{"Central Standard Time (Mexico)",  {"CST", "CST"}},     // America/Mexico_City
+	{"Saint Pierre Standard Time",      {"-03", "-02"}},     // America/Miquelon
+	{"Montevideo Standard Time",        {"-03", "-03"}},     // America/Montevideo
+	{"Eastern Standard Time",           {"EST", "EDT"}},     // America/New_York
+	{"US Mountain Standard Time",       {"MST", "MST"}},     // America/Phoenix
+	{"Haiti Standard Time",             {"EST", "EDT"}},     // America/Port-au-Prince
+	{"Magallanes Standard Time",        {"-03", "-03"}},     // America/Punta_Arenas
+	{"Canada Central Standard Time",    {"CST", "CST"}},     // America/Regina
+	{"Pacific SA Standard Time",        {"-04", "-03"}},     // America/Santiago
+	{"E. South America Standard Time",  {"-03", "-03"}},     // America/Sao_Paulo
+	{"Newfoundland Standard Time",      {"NST", "NDT"}},     // America/St_Johns
+	{"Pacific Standard Time (Mexico)",  {"PST", "PDT"}},     // America/Tijuana
+	{"Yukon Standard Time",             {"MST", "MST"}},     // America/Whitehorse
+	{"Central Asia Standard Time",      {"+06", "+06"}},     // Asia/Almaty
+	{"Jordan Standard Time",            {"+03", "+03"}},     // Asia/Amman
+	{"Arabic Standard Time",            {"+03", "+03"}},     // Asia/Baghdad
+	{"Azerbaijan Standard Time",        {"+04", "+04"}},     // Asia/Baku
+	{"SE Asia Standard Time",           {"+07", "+07"}},     // Asia/Bangkok
+	{"Altai Standard Time",             {"+07", "+07"}},     // Asia/Barnaul
+	{"Middle East Standard Time",       {"EET", "EEST"}},    // Asia/Beirut
+	{"India Standard Time",             {"IST", "IST"}},     // Asia/Calcutta
+	{"Transbaikal Standard Time",       {"+09", "+09"}},     // Asia/Chita
+	{"Sri Lanka Standard Time",         {"+0530", "+0530"}}, // Asia/Colombo
+	{"Syria Standard Time",             {"+03", "+03"}},     // Asia/Damascus
+	{"Bangladesh Standard Time",        {"+06", "+06"}},     // Asia/Dhaka
+	{"Arabian Standard Time",           {"+04", "+04"}},     // Asia/Dubai
+	{"West Bank Standard Time",         {"EET", "EEST"}},    // Asia/Hebron
+	{"W. Mongolia Standard Time",       {"+07", "+07"}},     // Asia/Hovd
+	{"North Asia East Standard Time",   {"+08", "+08"}},     // Asia/Irkutsk
+	{"Israel Standard Time",            {"IST", "IDT"}},     // Asia/Jerusalem
+	{"Afghanistan Standard Time",       {"+0430", "+0430"}}, // Asia/Kabul
+	{"Russia Time Zone 11",             {"+12", "+12"}},     // Asia/Kamchatka
+	{"Pakistan Standard Time",          {"PKT", "PKT"}},     // Asia/Karachi
+	{"Nepal Standard Time",             {"+0545", "+0545"}}, // Asia/Katmandu
+	{"North Asia Standard Time",        {"+07", "+07"}},     // Asia/Krasnoyarsk
+	{"Magadan Standard Time",           {"+11", "+11"}},     // Asia/Magadan
+	{"N. Central Asia Standard Time",   {"+07", "+07"}},     // Asia/Novosibirsk
+	{"Omsk Standard Time",              {"+06", "+06"}},     // Asia/Omsk
+	{"North Korea Standard Time",       {"KST", "KST"}},     // Asia/Pyongyang
+	{"Qyzylorda Standard Time",         {"+05", "+05"}},     // Asia/Qyzylorda
+	{"Myanmar Standard Time",           {"+0630", "+0630"}}, // Asia/Rangoon
+	{"Arab Standard Time",              {"+03", "+03"}},     // Asia/Riyadh
+	{"Sakhalin Standard Time",          {"+11", "+11"}},     // Asia/Sakhalin
+	{"Korea Standard Time",             {"KST", "KST"}},     // Asia/Seoul
+	{"China Standard Time",             {"CST", "CST"}},     // Asia/Shanghai
+	{"Singapore Standard Time",         {"+08", "+08"}},     // Asia/Singapore
+	{"Russia Time Zone 10",             {"+11", "+11"}},     // Asia/Srednekolymsk
+	{"Taipei Standard Time",            {"CST", "CST"}},     // Asia/Taipei
+	{"West Asia Standard Time",         {"+05", "+05"}},     // Asia/Tashkent
+	{"Georgian Standard Time",          {"+04", "+04"}},     // Asia/Tbilisi
+	{"Iran Standard Time",              {"+0330", "+0330"}}, // Asia/Tehran
+	{"Tokyo Standard Time",             {"JST", "JST"}},     // Asia/Tokyo
+	{"Tomsk Standard Time",             {"+07", "+07"}},     // Asia/Tomsk
+	{"Ulaanbaatar Standard Time",       {"+08", "+08"}},     // Asia/Ulaanbaatar
+	{"Vladivostok Standard Time",       {"+10", "+10"}},     // Asia/Vladivostok
+	{"Yakutsk Standard Time",           {"+09", "+09"}},     // Asia/Yakutsk
+	{"Ekaterinburg Standard Time",      {"+05", "+05"}},     // Asia/Yekaterinburg
+	{"Caucasus Standard Time",          {"+04", "+04"}},     // Asia/Yerevan
+	{"Azores Standard Time",            {"-01", "+00"}},     // Atlantic/Azores
+	{"Cape Verde Standard Time",        {"-01", "-01"}},     // Atlantic/Cape_Verde
+	{"Greenwich Standard Time",         {"GMT", "GMT"}},     // Atlantic/Reykjavik
+	{"Cen. Australia Standard Time",    {"ACST", "ACDT"}},   // Australia/Adelaide
+	{"E. Australia Standard Time",      {"AEST", "AEST"}},   // Australia/Brisbane
+	{"AUS Central Standard Time",       {"ACST", "ACST"}},   // Australia/Darwin
+	{"Aus Central W. Standard Time",    {"+0845", "+0845"}}, // Australia/Eucla
+	{"Tasmania Standard Time",          {"AEST", "AEDT"}},   // Australia/Hobart
+	{"Lord Howe Standard Time",         {"+1030", "+11"}},   // Australia/Lord_Howe
+	{"W. Australia Standard Time",      {"AWST", "AWST"}},   // Australia/Perth
+	{"AUS Eastern Standard Time",       {"AEST", "AEDT"}},   // Australia/Sydney
+	{"UTC-11",                          {"-11", "-11"}},     // Etc/GMT+11
+	{"Dateline Standard Time",          {"-12", "-12"}},     // Etc/GMT+12
+	{"UTC-02",                          {"-02", "-02"}},     // Etc/GMT+2
+	{"UTC-08",                          {"-08", "-08"}},     // Etc/GMT+8
+	{"UTC-09",                          {"-09", "-09"}},     // Etc/GMT+9
+	{"UTC+12",                          {"+12", "+12"}},     // Etc/GMT-12
+	{"UTC+13",                          {"+13", "+13"}},     // Etc/GMT-13
+	{"UTC",                             {"UTC", "UTC"}},     // Etc/UTC
+	{"Astrakhan Standard Time",         {"+04", "+04"}},     // Europe/Astrakhan
+	{"W. Europe Standard Time",         {"CET", "CEST"}},    // Europe/Berlin
+	{"GTB Standard Time",               {"EET", "EEST"}},    // Europe/Bucharest
+	{"Central Europe Standard Time",    {"CET", "CEST"}},    // Europe/Budapest
+	{"E. Europe Standard Time",         {"EET", "EEST"}},    // Europe/Chisinau
+	{"Turkey Standard Time",            {"+03", "+03"}},     // Europe/Istanbul
+	{"Kaliningrad Standard Time",       {"EET", "EET"}},     // Europe/Kaliningrad
+	{"FLE Standard Time",               {"EET", "EEST"}},    // Europe/Kiev
+	{"GMT Standard Time",               {"GMT", "BST"}},     // Europe/London
+	{"Belarus Standard Time",           {"+03", "+03"}},     // Europe/Minsk
+	{"Russian Standard Time",           {"MSK", "MSK"}},     // Europe/Moscow
+	{"Romance Standard Time",           {"CET", "CEST"}},    // Europe/Paris
+	{"Russia Time Zone 3",              {"+04", "+04"}},     // Europe/Samara
+	{"Saratov Standard Time",           {"+04", "+04"}},     // Europe/Saratov
+	{"Volgograd Standard Time",         {"MSK", "MSK"}},     // Europe/Volgograd
+	{"Central European Standard Time",  {"CET", "CEST"}},    // Europe/Warsaw
+	{"Mauritius Standard Time",         {"+04", "+04"}},     // Indian/Mauritius
+	{"Samoa Standard Time",             {"+13", "+13"}},     // Pacific/Apia
+	{"New Zealand Standard Time",       {"NZST", "NZDT"}},   // Pacific/Auckland
+	{"Bougainville Standard Time",      {"+11", "+11"}},     // Pacific/Bougainville
+	{"Chatham Islands Standard Time",   {"+1245", "+1345"}}, // Pacific/Chatham
+	{"Easter Island Standard Time",     {"-06", "-05"}},     // Pacific/Easter
+	{"Fiji Standard Time",              {"+12", "+12"}},     // Pacific/Fiji
+	{"Central Pacific Standard Time",   {"+11", "+11"}},     // Pacific/Guadalcanal
+	{"Hawaiian Standard Time",          {"HST", "HST"}},     // Pacific/Honolulu
+	{"Line Islands Standard Time",      {"+14", "+14"}},     // Pacific/Kiritimati
+	{"Marquesas Standard Time",         {"-0930", "-0930"}}, // Pacific/Marquesas
+	{"Norfolk Standard Time",           {"+11", "+12"}},     // Pacific/Norfolk
+	{"West Pacific Standard Time",      {"+10", "+10"}},     // Pacific/Port_Moresby
+	{"Tonga Standard Time",             {"+13", "+13"}},     // Pacific/Tongatapu
 }
 }
 
 
 iana_to_windows_tz :: proc(iana_name: string, allocator := context.allocator) -> (name: string, success: bool) {
 iana_to_windows_tz :: proc(iana_name: string, allocator := context.allocator) -> (name: string, success: bool) {
@@ -269,7 +270,18 @@ _region_load :: proc(reg_str: string, allocator := context.allocator) -> (out_re
 	defer delete(wintz_name, allocator)
 	defer delete(wintz_name, allocator)
 	defer delete(iana_name, allocator)
 	defer delete(iana_name, allocator)
 
 
-	abbrevs := tz_abbrevs[wintz_name] or_return
+	abbrevs: TZ_Abbrev
+	abbrevs_ok: bool
+	for pair in tz_abbrevs {
+		if pair.key == wintz_name {
+			abbrevs = pair.value
+			abbrevs_ok = true
+			break
+		}
+	}
+	if !abbrevs_ok {
+		return
+	}
 	if abbrevs.std == "UTC" && abbrevs.dst == abbrevs.std {
 	if abbrevs.std == "UTC" && abbrevs.dst == abbrevs.std {
 		return nil, true
 		return nil, true
 	}
 	}

+ 1 - 0
examples/demo/demo.odin

@@ -1,4 +1,5 @@
 #+vet !using-stmt !using-param
 #+vet !using-stmt !using-param
+#+feature dynamic-literals
 package main
 package main
 
 
 import "core:fmt"
 import "core:fmt"

+ 12 - 6
src/build_settings.cpp

@@ -324,6 +324,18 @@ u64 get_vet_flag_from_name(String const &name) {
 	return VetFlag_NONE;
 	return VetFlag_NONE;
 }
 }
 
 
+enum OptInFeatureFlags : u64 {
+	OptInFeatureFlag_NONE            = 0,
+	OptInFeatureFlag_DynamicLiterals = 1u<<0,
+};
+
+u64 get_feature_flag_from_name(String const &name) {
+	if (name == "dynamic-literals") {
+		return OptInFeatureFlag_DynamicLiterals;
+	}
+	return OptInFeatureFlag_NONE;
+}
+
 
 
 enum SanitizerFlags : u32 {
 enum SanitizerFlags : u32 {
 	SanitizerFlag_NONE = 0,
 	SanitizerFlag_NONE = 0,
@@ -429,7 +441,6 @@ struct BuildContext {
 	bool   ignore_unknown_attributes;
 	bool   ignore_unknown_attributes;
 	bool   no_bounds_check;
 	bool   no_bounds_check;
 	bool   no_type_assert;
 	bool   no_type_assert;
-	bool   no_dynamic_literals;
 	bool   no_output_files;
 	bool   no_output_files;
 	bool   no_crt;
 	bool   no_crt;
 	bool   no_rpath;
 	bool   no_rpath;
@@ -1855,11 +1866,6 @@ gb_internal bool init_build_paths(String init_filename) {
 		produces_output_file = true;
 		produces_output_file = true;
 	}
 	}
 
 
-	if (build_context.ODIN_DEFAULT_TO_NIL_ALLOCATOR ||
-	    build_context.ODIN_DEFAULT_TO_PANIC_ALLOCATOR) {
-		bc->no_dynamic_literals = true;
-	}
-
 	if (!produces_output_file) {
 	if (!produces_output_file) {
 		// Command doesn't produce output files. We're done.
 		// Command doesn't produce output files. We're done.
 		return true;
 		return true;

+ 48 - 50
src/check_decl.cpp

@@ -94,12 +94,14 @@ gb_internal Type *check_init_variable(CheckerContext *ctx, Entity *e, Operand *o
 				return nullptr;
 				return nullptr;
 			}
 			}
 			if (e2->state.load() != EntityState_Resolved) {
 			if (e2->state.load() != EntityState_Resolved) {
-				gbString str = type_to_string(t);
-				defer (gb_string_free(str));
-				error(e->token, "Invalid use of a polymorphic type '%s' in %.*s", str, LIT(context_name));
-				e->type = t_invalid;
+				e->type = t;
 				return nullptr;
 				return nullptr;
 			}
 			}
+			gbString str = type_to_string(t);
+			defer (gb_string_free(str));
+			error(operand->expr, "Invalid use of a non-specialized polymorphic type '%s' in %.*s", str, LIT(context_name));
+			e->type = t_invalid;
+			return nullptr;
 		} else if (is_type_empty_union(t)) {
 		} else if (is_type_empty_union(t)) {
 			gbString str = type_to_string(t);
 			gbString str = type_to_string(t);
 			defer (gb_string_free(str));
 			defer (gb_string_free(str));
@@ -971,6 +973,43 @@ gb_internal void check_objc_methods(CheckerContext *ctx, Entity *e, AttributeCon
 	}
 	}
 }
 }
 
 
+gb_internal void check_foreign_procedure(CheckerContext *ctx, Entity *e, DeclInfo *d) {
+	GB_ASSERT(e != nullptr);
+	GB_ASSERT(e->kind == Entity_Procedure);
+	String name = e->Procedure.link_name;
+
+	mutex_lock(&ctx->info->foreign_mutex);
+
+	auto *fp = &ctx->info->foreigns;
+	StringHashKey key = string_hash_string(name);
+	Entity **found = string_map_get(fp, key);
+	if (found && e != *found) {
+		Entity *f = *found;
+		TokenPos pos = f->token.pos;
+		Type *this_type = base_type(e->type);
+		Type *other_type = base_type(f->type);
+		if (is_type_proc(this_type) && is_type_proc(other_type)) {
+			if (!are_signatures_similar_enough(this_type, other_type)) {
+				error(d->proc_lit,
+				      "Redeclaration of foreign procedure '%.*s' with different type signatures\n"
+				      "\tat %s",
+				      LIT(name), token_pos_to_string(pos));
+			}
+		} else if (!signature_parameter_similar_enough(this_type, other_type)) {
+			error(d->proc_lit,
+			      "Foreign entity '%.*s' previously declared elsewhere with a different type\n"
+			      "\tat %s",
+			      LIT(name), token_pos_to_string(pos));
+		}
+	} else if (name == "main") {
+		error(d->proc_lit, "The link name 'main' is reserved for internal use");
+	} else {
+		string_map_set(fp, key, e);
+	}
+
+	mutex_unlock(&ctx->info->foreign_mutex);
+}
+
 gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
 gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
 	GB_ASSERT(e->type == nullptr);
 	GB_ASSERT(e->type == nullptr);
 	if (d->proc_lit->kind != Ast_ProcLit) {
 	if (d->proc_lit->kind != Ast_ProcLit) {
@@ -1307,57 +1346,16 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
 			name = e->Procedure.link_name;
 			name = e->Procedure.link_name;
 		}
 		}
 		Entity *foreign_library = init_entity_foreign_library(ctx, e);
 		Entity *foreign_library = init_entity_foreign_library(ctx, e);
-		
-		if (is_arch_wasm() && foreign_library != nullptr) {
-			String module_name = str_lit("env");
-			GB_ASSERT (foreign_library->kind == Entity_LibraryName);
-			if (foreign_library->LibraryName.paths.count != 1) {
-				error(foreign_library->token, "'foreign import' for '%.*s' architecture may only have one path, got %td",
-				      LIT(target_arch_names[build_context.metrics.arch]), foreign_library->LibraryName.paths.count);
-			}
-
-			if (foreign_library->LibraryName.paths.count >= 1) {
-				module_name = foreign_library->LibraryName.paths[0];
-			}
-
-			if (!string_ends_with(module_name, str_lit(".o"))) {
-				name = concatenate3_strings(permanent_allocator(), module_name, WASM_MODULE_NAME_SEPARATOR, name);
-			}
-		}
-
 		e->Procedure.is_foreign = true;
 		e->Procedure.is_foreign = true;
 		e->Procedure.link_name = name;
 		e->Procedure.link_name = name;
+		e->Procedure.foreign_library = foreign_library;
 
 
-		mutex_lock(&ctx->info->foreign_mutex);
-
-		auto *fp = &ctx->info->foreigns;
-		StringHashKey key = string_hash_string(name);
-		Entity **found = string_map_get(fp, key);
-		if (found && e != *found) {
-			Entity *f = *found;
-			TokenPos pos = f->token.pos;
-			Type *this_type = base_type(e->type);
-			Type *other_type = base_type(f->type);
-			if (is_type_proc(this_type) && is_type_proc(other_type)) {
-				if (!are_signatures_similar_enough(this_type, other_type)) {
-					error(d->proc_lit,
-					      "Redeclaration of foreign procedure '%.*s' with different type signatures\n"
-					      "\tat %s",
-					      LIT(name), token_pos_to_string(pos));
-				}
-			} else if (!signature_parameter_similar_enough(this_type, other_type)) {
-				error(d->proc_lit,
-				      "Foreign entity '%.*s' previously declared elsewhere with a different type\n"
-				      "\tat %s",
-				      LIT(name), token_pos_to_string(pos));
-			}
-		} else if (name == "main") {
-			error(d->proc_lit, "The link name 'main' is reserved for internal use");
+		if (is_arch_wasm() && foreign_library != nullptr) {
+			// NOTE(bill): this must be delayed because the foreign import paths might not be evaluated yet until much later
+			mpsc_enqueue(&ctx->info->foreign_decls_to_check, e);
 		} else {
 		} else {
-			string_map_set(fp, key, e);
+			check_foreign_procedure(ctx, e, d);
 		}
 		}
-
-		mutex_unlock(&ctx->info->foreign_mutex);
 	} else {
 	} else {
 		String name = e->token.string;
 		String name = e->token.string;
 		if (e->Procedure.link_name.len > 0) {
 		if (e->Procedure.link_name.len > 0) {

+ 53 - 10
src/check_expr.cpp

@@ -3672,6 +3672,13 @@ gb_internal bool check_binary_array_expr(CheckerContext *c, Token op, Operand *x
 			}
 			}
 		}
 		}
 	}
 	}
+	if (is_type_simd_vector(x->type) && !is_type_simd_vector(y->type)) {
+		if (check_is_assignable_to(c, y, x->type)) {
+			if (check_binary_op(c, x, op)) {
+				return true;
+			}
+		}
+	}
 	return false;
 	return false;
 }
 }
 
 
@@ -4556,6 +4563,19 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar
 		break;
 		break;
 	}
 	}
 	
 	
+	case Type_SimdVector: {
+		Type *elem = base_array_type(t);
+		if (check_is_assignable_to(c, operand, elem)) {
+			operand->mode = Addressing_Value;
+		} else {
+			operand->mode = Addressing_Invalid;
+			convert_untyped_error(c, operand, target_type);
+			return;
+		}
+
+		break;
+	}
+	
 	case Type_Matrix: {
 	case Type_Matrix: {
 		Type *elem = base_array_type(t);
 		Type *elem = base_array_type(t);
 		if (check_is_assignable_to(c, operand, elem)) {
 		if (check_is_assignable_to(c, operand, elem)) {
@@ -8725,6 +8745,18 @@ gb_internal ExprKind check_basic_directive_expr(CheckerContext *c, Operand *o, A
 		error(node, "#caller_expression may only be used as a default argument parameter");
 		error(node, "#caller_expression may only be used as a default argument parameter");
 		o->type = t_string;
 		o->type = t_string;
 		o->mode = Addressing_Value;
 		o->mode = Addressing_Value;
+	} else if (name == "branch_location") {
+		if (!c->in_defer) {
+			error(node, "#branch_location may only be used within a 'defer' statement");
+		} else if (c->curr_proc_decl) {
+			Entity *e = c->curr_proc_decl->entity;
+			if (e != nullptr) {
+				GB_ASSERT(e->kind == Entity_Procedure);
+				e->Procedure.uses_branch_location = true;
+			}
+		}
+		o->type = t_source_code_location;
+		o->mode = Addressing_Value;
 	} else {
 	} else {
 		if (name == "location") {
 		if (name == "location") {
 			init_core_source_code_location(c->checker);
 			init_core_source_code_location(c->checker);
@@ -9339,6 +9371,23 @@ gb_internal bool is_expr_inferred_fixed_array(Ast *type_expr) {
 	return false;
 	return false;
 }
 }
 
 
+gb_internal bool check_for_dynamic_literals(CheckerContext *c, Ast *node, AstCompoundLit *cl) {
+	if (cl->elems.count > 0 && (check_feature_flags(c, node) & OptInFeatureFlag_DynamicLiterals) == 0) {
+		ERROR_BLOCK();
+		error(node, "Compound literals of dynamic types are disabled by default");
+		error_line("\tSuggestion: If you want to enable them for this specific file, add '#+feature dynamic-literals' at the top of the file\n");
+		error_line("\tWarning: Please understand that dynamic literals will implicitly allocate using the current 'context.allocator' in that scope\n");
+		if (build_context.ODIN_DEFAULT_TO_NIL_ALLOCATOR) {
+			error_line("\tWarning: As '-default-to-panic-allocator' has been set, the dynamic compound literal may not be initialized as expected\n");
+		} else if (build_context.ODIN_DEFAULT_TO_PANIC_ALLOCATOR) {
+			error_line("\tWarning: As '-default-to-panic-allocator' has been set, the dynamic compound literal may not be initialized as expected\n");
+		}
+		return false;
+	}
+
+	return cl->elems.count > 0;
+}
+
 gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) {
 gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) {
 	ExprKind kind = Expr_Expr;
 	ExprKind kind = Expr_Expr;
 	ast_node(cl, CompoundLit, node);
 	ast_node(cl, CompoundLit, node);
@@ -9539,11 +9588,6 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
 			elem_type = t->DynamicArray.elem;
 			elem_type = t->DynamicArray.elem;
 			context_name = str_lit("dynamic array literal");
 			context_name = str_lit("dynamic array literal");
 			is_constant = false;
 			is_constant = false;
-
-			if (!build_context.no_dynamic_literals) {
-				add_package_dependency(c, "runtime", "__dynamic_array_reserve");
-				add_package_dependency(c, "runtime", "__dynamic_array_append");
-			}
 		} else if (t->kind == Type_SimdVector) {
 		} else if (t->kind == Type_SimdVector) {
 			elem_type = t->SimdVector.elem;
 			elem_type = t->SimdVector.elem;
 			context_name = str_lit("simd vector literal");
 			context_name = str_lit("simd vector literal");
@@ -9718,8 +9762,9 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
 
 
 
 
 		if (t->kind == Type_DynamicArray) {
 		if (t->kind == Type_DynamicArray) {
-			if (build_context.no_dynamic_literals && cl->elems.count) {
-				error(node, "Compound literals of dynamic types have been disabled");
+			if (check_for_dynamic_literals(c, node, cl)) {
+				add_package_dependency(c, "runtime", "__dynamic_array_reserve");
+				add_package_dependency(c, "runtime", "__dynamic_array_append");
 			}
 			}
 		}
 		}
 
 
@@ -10108,9 +10153,7 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
 			}
 			}
 		}
 		}
 
 
-		if (build_context.no_dynamic_literals && cl->elems.count) {
-			error(node, "Compound literals of dynamic types have been disabled");
-		} else {
+		if (check_for_dynamic_literals(c, node, cl)) {
 			add_map_reserve_dependencies(c);
 			add_map_reserve_dependencies(c);
 			add_map_set_dependencies(c);
 			add_map_set_dependencies(c);
 		}
 		}

+ 8 - 1
src/check_type.cpp

@@ -2440,8 +2440,12 @@ gb_internal bool check_procedure_type(CheckerContext *ctx, Type *type, Ast *proc
 	bool success = true;
 	bool success = true;
 	isize specialization_count = 0;
 	isize specialization_count = 0;
 	Type *params  = check_get_params(c, c->scope, pt->params, &variadic, &variadic_index, &success, &specialization_count, operands);
 	Type *params  = check_get_params(c, c->scope, pt->params, &variadic, &variadic_index, &success, &specialization_count, operands);
-	Type *results = check_get_results(c, c->scope, pt->results);
 
 
+	bool no_poly_return = c->disallow_polymorphic_return_types;
+	c->disallow_polymorphic_return_types = c->scope == c->polymorphic_scope;
+	// NOTE(zen3ger): if the parapoly scope is the current proc's scope, then the return types shall not declare new poly vars
+	Type *results = check_get_results(c, c->scope, pt->results);
+	c->disallow_polymorphic_return_types = no_poly_return;
 
 
 	isize param_count = 0;
 	isize param_count = 0;
 	isize result_count = 0;
 	isize result_count = 0;
@@ -3383,6 +3387,9 @@ gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, T
 		}
 		}
 		Type *t = alloc_type_generic(ctx->scope, 0, token.string, specific);
 		Type *t = alloc_type_generic(ctx->scope, 0, token.string, specific);
 		if (ctx->allow_polymorphic_types) {
 		if (ctx->allow_polymorphic_types) {
+			if (ctx->disallow_polymorphic_return_types) {
+				error(ident, "Undeclared polymorphic parameter '%.*s' in return type", LIT(token.string));
+			}
 			Scope *ps = ctx->polymorphic_scope;
 			Scope *ps = ctx->polymorphic_scope;
 			Scope *s = ctx->scope;
 			Scope *s = ctx->scope;
 			Scope *entity_scope = s;
 			Scope *entity_scope = s;

+ 51 - 1
src/checker.cpp

@@ -542,6 +542,23 @@ gb_internal u64 check_vet_flags(Ast *node) {
 	return ast_file_vet_flags(file);
 	return ast_file_vet_flags(file);
 }
 }
 
 
+gb_internal u64 check_feature_flags(CheckerContext *c, Ast *node) {
+	AstFile *file = c->file;
+	if (file == nullptr &&
+	    c->curr_proc_decl &&
+	    c->curr_proc_decl->proc_lit) {
+		file = c->curr_proc_decl->proc_lit->file();
+	}
+	if (file == nullptr) {
+		file = node->file();
+	}
+	if (file != nullptr && file->feature_flags_set) {
+		return file->feature_flags;
+	}
+	return 0;
+}
+
+
 enum VettedEntityKind {
 enum VettedEntityKind {
 	VettedEntity_Invalid,
 	VettedEntity_Invalid,
 
 
@@ -1164,7 +1181,6 @@ gb_internal void init_universal(void) {
 	add_global_bool_constant("ODIN_NO_BOUNDS_CHECK",            build_context.no_bounds_check);
 	add_global_bool_constant("ODIN_NO_BOUNDS_CHECK",            build_context.no_bounds_check);
 	add_global_bool_constant("ODIN_NO_TYPE_ASSERT",             build_context.no_type_assert);
 	add_global_bool_constant("ODIN_NO_TYPE_ASSERT",             build_context.no_type_assert);
 	add_global_bool_constant("ODIN_DEFAULT_TO_PANIC_ALLOCATOR", bc->ODIN_DEFAULT_TO_PANIC_ALLOCATOR);
 	add_global_bool_constant("ODIN_DEFAULT_TO_PANIC_ALLOCATOR", bc->ODIN_DEFAULT_TO_PANIC_ALLOCATOR);
-	add_global_bool_constant("ODIN_NO_DYNAMIC_LITERALS",        bc->no_dynamic_literals);
 	add_global_bool_constant("ODIN_NO_CRT",                     bc->no_crt);
 	add_global_bool_constant("ODIN_NO_CRT",                     bc->no_crt);
 	add_global_bool_constant("ODIN_USE_SEPARATE_MODULES",       bc->use_separate_modules);
 	add_global_bool_constant("ODIN_USE_SEPARATE_MODULES",       bc->use_separate_modules);
 	add_global_bool_constant("ODIN_TEST",                       bc->command_kind == Command_test);
 	add_global_bool_constant("ODIN_TEST",                       bc->command_kind == Command_test);
@@ -1356,6 +1372,7 @@ gb_internal void init_checker_info(CheckerInfo *i) {
 	mpsc_init(&i->required_global_variable_queue, a); // 1<<10);
 	mpsc_init(&i->required_global_variable_queue, a); // 1<<10);
 	mpsc_init(&i->required_foreign_imports_through_force_queue, a); // 1<<10);
 	mpsc_init(&i->required_foreign_imports_through_force_queue, a); // 1<<10);
 	mpsc_init(&i->foreign_imports_to_check_fullpaths, a); // 1<<10);
 	mpsc_init(&i->foreign_imports_to_check_fullpaths, a); // 1<<10);
+	mpsc_init(&i->foreign_decls_to_check, a); // 1<<10);
 	mpsc_init(&i->intrinsics_entry_point_usage, a); // 1<<10); // just waste some memory here, even if it probably never used
 	mpsc_init(&i->intrinsics_entry_point_usage, a); // 1<<10); // just waste some memory here, even if it probably never used
 
 
 	string_map_init(&i->load_directory_cache);
 	string_map_init(&i->load_directory_cache);
@@ -1382,6 +1399,7 @@ gb_internal void destroy_checker_info(CheckerInfo *i) {
 	mpsc_destroy(&i->required_global_variable_queue);
 	mpsc_destroy(&i->required_global_variable_queue);
 	mpsc_destroy(&i->required_foreign_imports_through_force_queue);
 	mpsc_destroy(&i->required_foreign_imports_through_force_queue);
 	mpsc_destroy(&i->foreign_imports_to_check_fullpaths);
 	mpsc_destroy(&i->foreign_imports_to_check_fullpaths);
+	mpsc_destroy(&i->foreign_decls_to_check);
 
 
 	map_destroy(&i->objc_msgSend_types);
 	map_destroy(&i->objc_msgSend_types);
 	string_map_destroy(&i->load_file_cache);
 	string_map_destroy(&i->load_file_cache);
@@ -5094,6 +5112,38 @@ gb_internal void check_foreign_import_fullpaths(Checker *c) {
 
 
 		e->LibraryName.paths = fl->fullpaths;
 		e->LibraryName.paths = fl->fullpaths;
 	}
 	}
+
+	for (Entity *e = nullptr; mpsc_dequeue(&c->info.foreign_decls_to_check, &e); /**/) {
+		GB_ASSERT(e != nullptr);
+		if (e->kind != Entity_Procedure) {
+			continue;
+		}
+		if (!is_arch_wasm()) {
+			continue;
+		}
+		Entity *foreign_library = e->Procedure.foreign_library;
+		GB_ASSERT(foreign_library != nullptr);
+
+		String name = e->Procedure.link_name;
+
+		String module_name = str_lit("env");
+		GB_ASSERT (foreign_library->kind == Entity_LibraryName);
+		if (foreign_library->LibraryName.paths.count != 1) {
+			error(foreign_library->token, "'foreign import' for '%.*s' architecture may only have one path, got %td",
+			      LIT(target_arch_names[build_context.metrics.arch]), foreign_library->LibraryName.paths.count);
+		}
+
+		if (foreign_library->LibraryName.paths.count >= 1) {
+			module_name = foreign_library->LibraryName.paths[0];
+		}
+
+		if (!string_ends_with(module_name, str_lit(".o"))) {
+			name = concatenate3_strings(permanent_allocator(), module_name, WASM_MODULE_NAME_SEPARATOR, name);
+		}
+		e->Procedure.link_name = name;
+
+		check_foreign_procedure(&ctx, e, e->decl_info);
+	}
 }
 }
 
 
 gb_internal void check_add_foreign_import_decl(CheckerContext *ctx, Ast *decl) {
 gb_internal void check_add_foreign_import_decl(CheckerContext *ctx, Ast *decl) {

+ 2 - 0
src/checker.hpp

@@ -461,6 +461,7 @@ struct CheckerInfo {
 	MPSCQueue<Entity *> required_global_variable_queue;
 	MPSCQueue<Entity *> required_global_variable_queue;
 	MPSCQueue<Entity *> required_foreign_imports_through_force_queue;
 	MPSCQueue<Entity *> required_foreign_imports_through_force_queue;
 	MPSCQueue<Entity *> foreign_imports_to_check_fullpaths;
 	MPSCQueue<Entity *> foreign_imports_to_check_fullpaths;
+	MPSCQueue<Entity *> foreign_decls_to_check;
 
 
 	MPSCQueue<Ast *> intrinsics_entry_point_usage;
 	MPSCQueue<Ast *> intrinsics_entry_point_usage;
 
 
@@ -521,6 +522,7 @@ struct CheckerContext {
 	bool       in_enum_type;
 	bool       in_enum_type;
 	bool       collect_delayed_decls;
 	bool       collect_delayed_decls;
 	bool       allow_polymorphic_types;
 	bool       allow_polymorphic_types;
+	bool       disallow_polymorphic_return_types; // NOTE(zen3ger): no poly type decl in return types
 	bool       no_polymorphic_errors;
 	bool       no_polymorphic_errors;
 	bool       hide_polymorphic_errors;
 	bool       hide_polymorphic_errors;
 	bool       in_polymorphic_specialization;
 	bool       in_polymorphic_specialization;

+ 1 - 0
src/entity.cpp

@@ -256,6 +256,7 @@ struct Entity {
 			bool    entry_point_only           : 1;
 			bool    entry_point_only           : 1;
 			bool    has_instrumentation        : 1;
 			bool    has_instrumentation        : 1;
 			bool    is_memcpy_like             : 1;
 			bool    is_memcpy_like             : 1;
+			bool    uses_branch_location       : 1;
 		} Procedure;
 		} Procedure;
 		struct {
 		struct {
 			Array<Entity *> entities;
 			Array<Entity *> entities;

+ 0 - 2
src/llvm_backend.cpp

@@ -1096,8 +1096,6 @@ gb_internal void lb_internal_dynamic_map_set(lbProcedure *p, lbValue const &map_
 }
 }
 
 
 gb_internal lbValue lb_dynamic_map_reserve(lbProcedure *p, lbValue const &map_ptr, isize const capacity, TokenPos const &pos) {
 gb_internal lbValue lb_dynamic_map_reserve(lbProcedure *p, lbValue const &map_ptr, isize const capacity, TokenPos const &pos) {
-	GB_ASSERT(!build_context.no_dynamic_literals);
-
 	TEMPORARY_ALLOCATOR_GUARD();
 	TEMPORARY_ALLOCATOR_GUARD();
 
 
 	String proc_name = {};
 	String proc_name = {};

+ 8 - 1
src/llvm_backend.hpp

@@ -359,6 +359,10 @@ struct lbProcedure {
 	bool             in_multi_assignment;
 	bool             in_multi_assignment;
 	Array<LLVMValueRef> raw_input_parameters;
 	Array<LLVMValueRef> raw_input_parameters;
 
 
+	bool             uses_branch_location;
+	TokenPos         branch_location_pos;
+	TokenPos         curr_token_pos;
+
 	Array<lbVariadicReuseSlices> variadic_reuses;
 	Array<lbVariadicReuseSlices> variadic_reuses;
 	lbAddr variadic_reuse_base_array_ptr;
 	lbAddr variadic_reuse_base_array_ptr;
 
 
@@ -444,7 +448,8 @@ gb_internal lbValue lb_emit_matrix_ev(lbProcedure *p, lbValue s, isize row, isiz
 
 
 gb_internal lbValue lb_emit_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type);
 gb_internal lbValue lb_emit_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type);
 gb_internal lbValue lb_emit_byte_swap(lbProcedure *p, lbValue value, Type *end_type);
 gb_internal lbValue lb_emit_byte_swap(lbProcedure *p, lbValue value, Type *end_type);
-gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block);
+gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block, TokenPos pos);
+gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block, Ast *node);
 gb_internal lbValue lb_emit_transmute(lbProcedure *p, lbValue value, Type *t);
 gb_internal lbValue lb_emit_transmute(lbProcedure *p, lbValue value, Type *t);
 gb_internal lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue right);
 gb_internal lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue right);
 gb_internal lbValue lb_emit_call(lbProcedure *p, lbValue value, Array<lbValue> const &args, ProcInlining inlining = ProcInlining_none);
 gb_internal lbValue lb_emit_call(lbProcedure *p, lbValue value, Array<lbValue> const &args, ProcInlining inlining = ProcInlining_none);
@@ -742,3 +747,5 @@ gb_global char const *llvm_linkage_strings[] = {
 };
 };
 
 
 #define ODIN_METADATA_IS_PACKED str_lit("odin-is-packed")
 #define ODIN_METADATA_IS_PACKED str_lit("odin-is-packed")
+#define ODIN_METADATA_MIN_ALIGN str_lit("odin-min-align")
+#define ODIN_METADATA_MAX_ALIGN str_lit("odin-max-align")

+ 11 - 5
src/llvm_backend_expr.cpp

@@ -3502,7 +3502,13 @@ gb_internal lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) {
 
 
 	case_ast_node(bd, BasicDirective, expr);
 	case_ast_node(bd, BasicDirective, expr);
 		TokenPos pos = bd->token.pos;
 		TokenPos pos = bd->token.pos;
-		GB_PANIC("Non-constant basic literal %s - %.*s", token_pos_to_string(pos), LIT(bd->name.string));
+		String name = bd->name.string;
+		if (name == "branch_location") {
+			GB_ASSERT(p->uses_branch_location);
+			String proc_name = p->entity->token.string;
+			return lb_emit_source_code_location_as_global(p, proc_name, p->branch_location_pos);
+		}
+		GB_PANIC("Non-constant basic literal %s - %.*s", token_pos_to_string(pos), LIT(name));
 	case_end;
 	case_end;
 
 
 	case_ast_node(i, Implicit, expr);
 	case_ast_node(i, Implicit, expr);
@@ -3668,7 +3674,7 @@ gb_internal lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) {
 
 
 		lb_emit_if(p, lb_emit_try_has_value(p, rhs), then, else_);
 		lb_emit_if(p, lb_emit_try_has_value(p, rhs), then, else_);
 		lb_start_block(p, else_);
 		lb_start_block(p, else_);
-		lb_emit_defer_stmts(p, lbDeferExit_Branch, block);
+		lb_emit_defer_stmts(p, lbDeferExit_Branch, block, expr);
 		lb_emit_jump(p, block);
 		lb_emit_jump(p, block);
 		lb_start_block(p, then);
 		lb_start_block(p, then);
 
 
@@ -4807,7 +4813,7 @@ gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) {
 		if (cl->elems.count == 0) {
 		if (cl->elems.count == 0) {
 			break;
 			break;
 		}
 		}
-		GB_ASSERT(!build_context.no_dynamic_literals);
+		GB_ASSERT(expr->file()->feature_flags & OptInFeatureFlag_DynamicLiterals);
 
 
 		lbValue err = lb_dynamic_map_reserve(p, v.addr, 2*cl->elems.count, pos);
 		lbValue err = lb_dynamic_map_reserve(p, v.addr, 2*cl->elems.count, pos);
 		gb_unused(err);
 		gb_unused(err);
@@ -4896,7 +4902,7 @@ gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) {
 		if (cl->elems.count == 0) {
 		if (cl->elems.count == 0) {
 			break;
 			break;
 		}
 		}
-		GB_ASSERT(!build_context.no_dynamic_literals);
+		GB_ASSERT(expr->file()->feature_flags & OptInFeatureFlag_DynamicLiterals);
 
 
 		Type *et = bt->DynamicArray.elem;
 		Type *et = bt->DynamicArray.elem;
 		lbValue size  = lb_const_int(p->module, t_int, type_size_of(et));
 		lbValue size  = lb_const_int(p->module, t_int, type_size_of(et));
@@ -5493,7 +5499,7 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) {
 
 
 		lb_emit_if(p, lb_emit_try_has_value(p, rhs), then, else_);
 		lb_emit_if(p, lb_emit_try_has_value(p, rhs), then, else_);
 		lb_start_block(p, else_);
 		lb_start_block(p, else_);
-		lb_emit_defer_stmts(p, lbDeferExit_Branch, block);
+		lb_emit_defer_stmts(p, lbDeferExit_Branch, block, expr);
 		lb_emit_jump(p, block);
 		lb_emit_jump(p, block);
 		lb_start_block(p, then);
 		lb_start_block(p, then);
 
 

+ 17 - 1
src/llvm_backend_general.cpp

@@ -734,6 +734,17 @@ gb_internal LLVMValueRef OdinLLVMBuildLoad(lbProcedure *p, LLVMTypeRef type, LLV
 		if (is_packed != 0) {
 		if (is_packed != 0) {
 			LLVMSetAlignment(result, 1);
 			LLVMSetAlignment(result, 1);
 		}
 		}
+		u64 align = LLVMGetAlignment(result);
+		u64 align_min = lb_get_metadata_custom_u64(p->module, value, ODIN_METADATA_MIN_ALIGN);
+		u64 align_max = lb_get_metadata_custom_u64(p->module, value, ODIN_METADATA_MAX_ALIGN);
+		if (align_min != 0 && align < align_min) {
+			align = align_min;
+		}
+		if (align_max != 0 && align > align_max) {
+			align = align_max;
+		}
+		GB_ASSERT(align <= UINT_MAX);
+		LLVMSetAlignment(result, (unsigned int)align);
 	}
 	}
 
 
 	return result;
 	return result;
@@ -2121,6 +2132,7 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
 			}
 			}
 			
 			
 			i64 prev_offset = 0;
 			i64 prev_offset = 0;
+			bool requires_packing = type->Struct.is_packed;
 			for (i32 field_index : struct_fields_index_by_increasing_offset(temporary_allocator(), type)) {
 			for (i32 field_index : struct_fields_index_by_increasing_offset(temporary_allocator(), type)) {
 				Entity *field = type->Struct.fields[field_index];
 				Entity *field = type->Struct.fields[field_index];
 				i64 offset = type->Struct.offsets[field_index];
 				i64 offset = type->Struct.offsets[field_index];
@@ -2141,6 +2153,10 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
 					field_type = t_rawptr;
 					field_type = t_rawptr;
 				}
 				}
 
 
+				// max_field_align might misalign items in a way that requires packing
+				// so check the alignment of all fields to see if packing is required.
+				requires_packing = requires_packing || ((offset % type_align_of(field_type)) != 0);
+
 				array_add(&fields, lb_type(m, field_type));
 				array_add(&fields, lb_type(m, field_type));
 
 
 				prev_offset = offset + type_size_of(field->type);
 				prev_offset = offset + type_size_of(field->type);
@@ -2155,7 +2171,7 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
 				GB_ASSERT(fields[i] != nullptr);
 				GB_ASSERT(fields[i] != nullptr);
 			}
 			}
 			
 			
-			LLVMTypeRef struct_type = LLVMStructTypeInContext(ctx, fields.data, cast(unsigned)fields.count, type->Struct.is_packed);
+			LLVMTypeRef struct_type = LLVMStructTypeInContext(ctx, fields.data, cast(unsigned)fields.count, requires_packing);
 			map_set(&m->struct_field_remapping, cast(void *)struct_type, field_remapping);
 			map_set(&m->struct_field_remapping, cast(void *)struct_type, field_remapping);
 			map_set(&m->struct_field_remapping, cast(void *)type, field_remapping);			
 			map_set(&m->struct_field_remapping, cast(void *)type, field_remapping);			
 			#if 0
 			#if 0

+ 5 - 1
src/llvm_backend_proc.cpp

@@ -125,6 +125,10 @@ gb_internal lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool i
 	// map_init(&p->selector_addr,    0);
 	// map_init(&p->selector_addr,    0);
 	// map_init(&p->tuple_fix_map,    0);
 	// map_init(&p->tuple_fix_map,    0);
 
 
+	if (p->entity != nullptr && p->entity->Procedure.uses_branch_location) {
+		p->uses_branch_location = true;
+	}
+
 	if (p->is_foreign) {
 	if (p->is_foreign) {
 		lb_add_foreign_library_path(p->module, entity->Procedure.foreign_library);
 		lb_add_foreign_library_path(p->module, entity->Procedure.foreign_library);
 	}
 	}
@@ -757,7 +761,7 @@ gb_internal void lb_end_procedure_body(lbProcedure *p) {
 	if (p->type->Proc.result_count == 0) {
 	if (p->type->Proc.result_count == 0) {
 		instr = LLVMGetLastInstruction(p->curr_block->block);
 		instr = LLVMGetLastInstruction(p->curr_block->block);
 		if (!lb_is_instr_terminating(instr)) {
 		if (!lb_is_instr_terminating(instr)) {
-			lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr);
+			lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr, p->body);
 			lb_set_debug_position_to_procedure_end(p);
 			lb_set_debug_position_to_procedure_end(p);
 			LLVMBuildRetVoid(p->builder);
 			LLVMBuildRetVoid(p->builder);
 		}
 		}

+ 52 - 29
src/llvm_backend_stmt.cpp

@@ -208,8 +208,8 @@ gb_internal void lb_open_scope(lbProcedure *p, Scope *s) {
 
 
 }
 }
 
 
-gb_internal void lb_close_scope(lbProcedure *p, lbDeferExitKind kind, lbBlock *block, bool pop_stack=true) {
-	lb_emit_defer_stmts(p, kind, block);
+gb_internal void lb_close_scope(lbProcedure *p, lbDeferExitKind kind, lbBlock *block, Ast *node, bool pop_stack=true) {
+	lb_emit_defer_stmts(p, kind, block, node);
 	GB_ASSERT(p->scope_index > 0);
 	GB_ASSERT(p->scope_index > 0);
 
 
 	// NOTE(bill): Remove `context`s made in that scope
 	// NOTE(bill): Remove `context`s made in that scope
@@ -721,7 +721,7 @@ gb_internal void lb_build_range_interval(lbProcedure *p, AstBinaryExpr *node,
 
 
 		lb_build_stmt(p, rs->body);
 		lb_build_stmt(p, rs->body);
 
 
-		lb_close_scope(p, lbDeferExit_Default, nullptr);
+		lb_close_scope(p, lbDeferExit_Default, nullptr, node->left);
 		lb_pop_target_list(p);
 		lb_pop_target_list(p);
 
 
 		if (check != nullptr) {
 		if (check != nullptr) {
@@ -854,7 +854,7 @@ gb_internal void lb_build_range_tuple(lbProcedure *p, AstRangeStmt *rs, Scope *s
 
 
 	lb_build_stmt(p, rs->body);
 	lb_build_stmt(p, rs->body);
 
 
-	lb_close_scope(p, lbDeferExit_Default, nullptr);
+	lb_close_scope(p, lbDeferExit_Default, nullptr, rs->body);
 	lb_pop_target_list(p);
 	lb_pop_target_list(p);
 	lb_emit_jump(p, loop);
 	lb_emit_jump(p, loop);
 	lb_start_block(p, done);
 	lb_start_block(p, done);
@@ -976,7 +976,7 @@ gb_internal void lb_build_range_stmt_struct_soa(lbProcedure *p, AstRangeStmt *rs
 
 
 	lb_build_stmt(p, rs->body);
 	lb_build_stmt(p, rs->body);
 
 
-	lb_close_scope(p, lbDeferExit_Default, nullptr);
+	lb_close_scope(p, lbDeferExit_Default, nullptr, rs->body);
 	lb_pop_target_list(p);
 	lb_pop_target_list(p);
 	lb_emit_jump(p, loop);
 	lb_emit_jump(p, loop);
 	lb_start_block(p, done);
 	lb_start_block(p, done);
@@ -1192,7 +1192,7 @@ gb_internal void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *sc
 
 
 	lb_build_stmt(p, rs->body);
 	lb_build_stmt(p, rs->body);
 
 
-	lb_close_scope(p, lbDeferExit_Default, nullptr);
+	lb_close_scope(p, lbDeferExit_Default, nullptr, rs->body);
 	lb_pop_target_list(p);
 	lb_pop_target_list(p);
 	lb_emit_jump(p, loop);
 	lb_emit_jump(p, loop);
 	lb_start_block(p, done);
 	lb_start_block(p, done);
@@ -1363,7 +1363,7 @@ gb_internal void lb_build_unroll_range_stmt(lbProcedure *p, AstUnrollRangeStmt *
 	}
 	}
 
 
 
 
-	lb_close_scope(p, lbDeferExit_Default, nullptr);
+	lb_close_scope(p, lbDeferExit_Default, nullptr, rs->body);
 }
 }
 
 
 gb_internal bool lb_switch_stmt_can_be_trivial_jump_table(AstSwitchStmt *ss, bool *default_found_) {
 gb_internal bool lb_switch_stmt_can_be_trivial_jump_table(AstSwitchStmt *ss, bool *default_found_) {
@@ -1433,6 +1433,7 @@ gb_internal void lb_build_switch_stmt(lbProcedure *p, AstSwitchStmt *ss, Scope *
 	ast_node(body, BlockStmt, ss->body);
 	ast_node(body, BlockStmt, ss->body);
 
 
 	isize case_count = body->stmts.count;
 	isize case_count = body->stmts.count;
+	Ast *default_clause = nullptr;
 	Slice<Ast *> default_stmts = {};
 	Slice<Ast *> default_stmts = {};
 	lbBlock *default_fall = nullptr;
 	lbBlock *default_fall = nullptr;
 	lbBlock *default_block = nullptr;
 	lbBlock *default_block = nullptr;
@@ -1482,6 +1483,7 @@ gb_internal void lb_build_switch_stmt(lbProcedure *p, AstSwitchStmt *ss, Scope *
 
 
 		if (cc->list.count == 0) {
 		if (cc->list.count == 0) {
 			// default case
 			// default case
+			default_clause = clause;
 			default_stmts = cc->stmts;
 			default_stmts = cc->stmts;
 			default_fall  = fall;
 			default_fall  = fall;
 			if (switch_instr == nullptr) {
 			if (switch_instr == nullptr) {
@@ -1552,7 +1554,7 @@ gb_internal void lb_build_switch_stmt(lbProcedure *p, AstSwitchStmt *ss, Scope *
 		lb_push_target_list(p, ss->label, done, nullptr, fall);
 		lb_push_target_list(p, ss->label, done, nullptr, fall);
 		lb_open_scope(p, body->scope);
 		lb_open_scope(p, body->scope);
 		lb_build_stmt_list(p, cc->stmts);
 		lb_build_stmt_list(p, cc->stmts);
-		lb_close_scope(p, lbDeferExit_Default, body);
+		lb_close_scope(p, lbDeferExit_Default, body, clause);
 		lb_pop_target_list(p);
 		lb_pop_target_list(p);
 
 
 		lb_emit_jump(p, done);
 		lb_emit_jump(p, done);
@@ -1570,13 +1572,13 @@ gb_internal void lb_build_switch_stmt(lbProcedure *p, AstSwitchStmt *ss, Scope *
 		lb_push_target_list(p, ss->label, done, nullptr, default_fall);
 		lb_push_target_list(p, ss->label, done, nullptr, default_fall);
 		lb_open_scope(p, default_block->scope);
 		lb_open_scope(p, default_block->scope);
 		lb_build_stmt_list(p, default_stmts);
 		lb_build_stmt_list(p, default_stmts);
-		lb_close_scope(p, lbDeferExit_Default, default_block);
+		lb_close_scope(p, lbDeferExit_Default, default_block, default_clause);
 		lb_pop_target_list(p);
 		lb_pop_target_list(p);
 	}
 	}
 
 
 	lb_emit_jump(p, done);
 	lb_emit_jump(p, done);
 	lb_start_block(p, done);
 	lb_start_block(p, done);
-	lb_close_scope(p, lbDeferExit_Default, done);
+	lb_close_scope(p, lbDeferExit_Default, done, ss->body);
 }
 }
 
 
 gb_internal void lb_store_type_case_implicit(lbProcedure *p, Ast *clause, lbValue value, bool is_default_case) {
 gb_internal void lb_store_type_case_implicit(lbProcedure *p, Ast *clause, lbValue value, bool is_default_case) {
@@ -1627,7 +1629,7 @@ gb_internal void lb_type_case_body(lbProcedure *p, Ast *label, Ast *clause, lbBl
 
 
 	lb_push_target_list(p, label, done, nullptr, nullptr);
 	lb_push_target_list(p, label, done, nullptr, nullptr);
 	lb_build_stmt_list(p, cc->stmts);
 	lb_build_stmt_list(p, cc->stmts);
-	lb_close_scope(p, lbDeferExit_Default, body);
+	lb_close_scope(p, lbDeferExit_Default, body, clause);
 	lb_pop_target_list(p);
 	lb_pop_target_list(p);
 
 
 	lb_emit_jump(p, done);
 	lb_emit_jump(p, done);
@@ -1835,7 +1837,7 @@ gb_internal void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss
 
 
 	lb_emit_jump(p, done);
 	lb_emit_jump(p, done);
 	lb_start_block(p, done);
 	lb_start_block(p, done);
-	lb_close_scope(p, lbDeferExit_Default, done);
+	lb_close_scope(p, lbDeferExit_Default, done, ss->body);
 }
 }
 
 
 
 
@@ -1959,7 +1961,7 @@ gb_internal void lb_build_assignment(lbProcedure *p, Array<lbAddr> &lvals, Slice
 	p->in_multi_assignment = prev_in_assignment;
 	p->in_multi_assignment = prev_in_assignment;
 }
 }
 
 
-gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res) {
+gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res, TokenPos pos) {
 	lbFunctionType *ft = lb_get_function_type(p->module, p->type);
 	lbFunctionType *ft = lb_get_function_type(p->module, p->type);
 	bool return_by_pointer = ft->ret.kind == lbArg_Indirect;
 	bool return_by_pointer = ft->ret.kind == lbArg_Indirect;
 	bool split_returns = ft->multiple_return_original_type != nullptr;
 	bool split_returns = ft->multiple_return_original_type != nullptr;
@@ -1982,7 +1984,7 @@ gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res) {
 			LLVMBuildStore(p->builder, LLVMConstNull(p->abi_function_type->ret.type), p->return_ptr.addr.value);
 			LLVMBuildStore(p->builder, LLVMConstNull(p->abi_function_type->ret.type), p->return_ptr.addr.value);
 		}
 		}
 
 
-		lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr);
+		lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr, pos);
 
 
 		// Check for terminator in the defer stmts
 		// Check for terminator in the defer stmts
 		LLVMValueRef instr = LLVMGetLastInstruction(p->curr_block->block);
 		LLVMValueRef instr = LLVMGetLastInstruction(p->curr_block->block);
@@ -2012,7 +2014,7 @@ gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res) {
 			ret_val = OdinLLVMBuildTransmute(p, ret_val, ret_type);
 			ret_val = OdinLLVMBuildTransmute(p, ret_val, ret_type);
 		}
 		}
 
 
-		lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr);
+		lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr, pos);
 
 
 		// Check for terminator in the defer stmts
 		// Check for terminator in the defer stmts
 		LLVMValueRef instr = LLVMGetLastInstruction(p->curr_block->block);
 		LLVMValueRef instr = LLVMGetLastInstruction(p->curr_block->block);
@@ -2021,7 +2023,7 @@ gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res) {
 		}
 		}
 	}
 	}
 }
 }
-gb_internal void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return_results) {
+gb_internal void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return_results, TokenPos pos) {
 	lb_ensure_abi_function_type(p->module, p);
 	lb_ensure_abi_function_type(p->module, p);
 
 
 	isize return_count = p->type->Proc.result_count;
 	isize return_count = p->type->Proc.result_count;
@@ -2029,7 +2031,7 @@ gb_internal void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return
 	if (return_count == 0) {
 	if (return_count == 0) {
 		// No return values
 		// No return values
 
 
-		lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr);
+		lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr, pos);
 		
 		
 		// Check for terminator in the defer stmts
 		// Check for terminator in the defer stmts
 		LLVMValueRef instr = LLVMGetLastInstruction(p->curr_block->block);
 		LLVMValueRef instr = LLVMGetLastInstruction(p->curr_block->block);
@@ -2138,11 +2140,11 @@ gb_internal void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return
 				GB_ASSERT(result_values.count-1 == result_eps.count);
 				GB_ASSERT(result_values.count-1 == result_eps.count);
 				lb_addr_store(p, p->return_ptr, result_values[result_values.count-1]);
 				lb_addr_store(p, p->return_ptr, result_values[result_values.count-1]);
 
 
-				lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr);
+				lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr, pos);
 				LLVMBuildRetVoid(p->builder);
 				LLVMBuildRetVoid(p->builder);
 				return;
 				return;
 			} else {
 			} else {
-				return lb_build_return_stmt_internal(p, result_values[result_values.count-1]);
+				return lb_build_return_stmt_internal(p, result_values[result_values.count-1], pos);
 			}
 			}
 
 
 		} else {
 		} else {
@@ -2169,7 +2171,7 @@ gb_internal void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return
 			}
 			}
 
 
 			if (return_by_pointer) {
 			if (return_by_pointer) {
-				lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr);
+				lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr, pos);
 				LLVMBuildRetVoid(p->builder);
 				LLVMBuildRetVoid(p->builder);
 				return;
 				return;
 			}
 			}
@@ -2177,13 +2179,13 @@ gb_internal void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return
 			res = lb_emit_load(p, res);
 			res = lb_emit_load(p, res);
 		}
 		}
 	}
 	}
-	lb_build_return_stmt_internal(p, res);
+	lb_build_return_stmt_internal(p, res, pos);
 }
 }
 
 
 gb_internal void lb_build_if_stmt(lbProcedure *p, Ast *node) {
 gb_internal void lb_build_if_stmt(lbProcedure *p, Ast *node) {
 	ast_node(is, IfStmt, node);
 	ast_node(is, IfStmt, node);
 	lb_open_scope(p, is->scope); // Scope #1
 	lb_open_scope(p, is->scope); // Scope #1
-	defer (lb_close_scope(p, lbDeferExit_Default, nullptr));
+	defer (lb_close_scope(p, lbDeferExit_Default, nullptr, node));
 
 
 	lbBlock *then = lb_create_block(p, "if.then");
 	lbBlock *then = lb_create_block(p, "if.then");
 	lbBlock *done = lb_create_block(p, "if.done");
 	lbBlock *done = lb_create_block(p, "if.done");
@@ -2234,7 +2236,7 @@ gb_internal void lb_build_if_stmt(lbProcedure *p, Ast *node) {
 
 
 				lb_open_scope(p, scope_of_node(is->else_stmt));
 				lb_open_scope(p, scope_of_node(is->else_stmt));
 				lb_build_stmt(p, is->else_stmt);
 				lb_build_stmt(p, is->else_stmt);
-				lb_close_scope(p, lbDeferExit_Default, nullptr);
+				lb_close_scope(p, lbDeferExit_Default, nullptr, is->else_stmt);
 			}
 			}
 			lb_emit_jump(p, done);
 			lb_emit_jump(p, done);
 
 
@@ -2251,7 +2253,7 @@ gb_internal void lb_build_if_stmt(lbProcedure *p, Ast *node) {
 
 
 			lb_open_scope(p, scope_of_node(is->else_stmt));
 			lb_open_scope(p, scope_of_node(is->else_stmt));
 			lb_build_stmt(p, is->else_stmt);
 			lb_build_stmt(p, is->else_stmt);
-			lb_close_scope(p, lbDeferExit_Default, nullptr);
+			lb_close_scope(p, lbDeferExit_Default, nullptr, is->else_stmt);
 
 
 			lb_emit_jump(p, done);
 			lb_emit_jump(p, done);
 		}
 		}
@@ -2322,7 +2324,7 @@ gb_internal void lb_build_for_stmt(lbProcedure *p, Ast *node) {
 	}
 	}
 
 
 	lb_start_block(p, done);
 	lb_start_block(p, done);
-	lb_close_scope(p, lbDeferExit_Default, nullptr);
+	lb_close_scope(p, lbDeferExit_Default, nullptr, node);
 }
 }
 
 
 gb_internal void lb_build_assign_stmt_array(lbProcedure *p, TokenKind op, lbAddr const &lhs, lbValue const &value) {
 gb_internal void lb_build_assign_stmt_array(lbProcedure *p, TokenKind op, lbAddr const &lhs, lbValue const &value) {
@@ -2588,7 +2590,7 @@ gb_internal void lb_build_stmt(lbProcedure *p, Ast *node) {
 
 
 		lb_open_scope(p, bs->scope);
 		lb_open_scope(p, bs->scope);
 		lb_build_stmt_list(p, bs->stmts);
 		lb_build_stmt_list(p, bs->stmts);
-		lb_close_scope(p, lbDeferExit_Default, nullptr);
+		lb_close_scope(p, lbDeferExit_Default, nullptr, node);
 
 
 		if (done != nullptr) {
 		if (done != nullptr) {
 			lb_emit_jump(p, done);
 			lb_emit_jump(p, done);
@@ -2702,7 +2704,7 @@ gb_internal void lb_build_stmt(lbProcedure *p, Ast *node) {
 	case_end;
 	case_end;
 
 
 	case_ast_node(rs, ReturnStmt, node);
 	case_ast_node(rs, ReturnStmt, node);
-		lb_build_return_stmt(p, rs->results);
+		lb_build_return_stmt(p, rs->results, ast_token(node).pos);
 	case_end;
 	case_end;
 
 
 	case_ast_node(is, IfStmt, node);
 	case_ast_node(is, IfStmt, node);
@@ -2755,7 +2757,7 @@ gb_internal void lb_build_stmt(lbProcedure *p, Ast *node) {
 			}
 			}
 		}
 		}
 		if (block != nullptr) {
 		if (block != nullptr) {
-			lb_emit_defer_stmts(p, lbDeferExit_Branch, block);
+			lb_emit_defer_stmts(p, lbDeferExit_Branch, block, node);
 		}
 		}
 		lb_emit_jump(p, block);
 		lb_emit_jump(p, block);
 		lb_start_block(p, lb_create_block(p, "unreachable"));
 		lb_start_block(p, lb_create_block(p, "unreachable"));
@@ -2795,7 +2797,13 @@ gb_internal void lb_build_defer_stmt(lbProcedure *p, lbDefer const &d) {
 	}
 	}
 }
 }
 
 
-gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block) {
+gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block, TokenPos pos) {
+	TokenPos prev_token_pos = p->branch_location_pos;
+	if (p->uses_branch_location) {
+		p->branch_location_pos = pos;
+	}
+	defer (p->branch_location_pos = prev_token_pos);
+
 	isize count = p->defer_stmts.count;
 	isize count = p->defer_stmts.count;
 	isize i = count;
 	isize i = count;
 	while (i --> 0) {
 	while (i --> 0) {
@@ -2822,6 +2830,21 @@ gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlo
 	}
 	}
 }
 }
 
 
+gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block, Ast *node) {
+	TokenPos pos = {};
+	if (node) {
+		if (node->kind == Ast_BlockStmt) {
+			pos = ast_end_token(node).pos;
+		} else if (node->kind == Ast_CaseClause) {
+			pos = ast_end_token(node).pos;
+		} else {
+			pos = ast_token(node).pos;
+		}
+	}
+	return lb_emit_defer_stmts(p, kind, block, pos);
+}
+
+
 gb_internal void lb_add_defer_node(lbProcedure *p, isize scope_index, Ast *stmt) {
 gb_internal void lb_add_defer_node(lbProcedure *p, isize scope_index, Ast *stmt) {
 	Type *pt = base_type(p->type);
 	Type *pt = base_type(p->type);
 	GB_ASSERT(pt->kind == Type_Proc);
 	GB_ASSERT(pt->kind == Type_Proc);

+ 20 - 7
src/llvm_backend_utility.cpp

@@ -476,8 +476,8 @@ gb_internal lbValue lb_emit_or_else(lbProcedure *p, Ast *arg, Ast *else_expr, Ty
 	}
 	}
 }
 }
 
 
-gb_internal void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return_results);
-gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res);
+gb_internal void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return_results, TokenPos pos);
+gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res, TokenPos pos);
 
 
 gb_internal lbValue lb_emit_or_return(lbProcedure *p, Ast *arg, TypeAndValue const &tv) {
 gb_internal lbValue lb_emit_or_return(lbProcedure *p, Ast *arg, TypeAndValue const &tv) {
 	lbValue lhs = {};
 	lbValue lhs = {};
@@ -506,10 +506,10 @@ gb_internal lbValue lb_emit_or_return(lbProcedure *p, Ast *arg, TypeAndValue con
 			lbValue found = map_must_get(&p->module->values, end_entity);
 			lbValue found = map_must_get(&p->module->values, end_entity);
 			lb_emit_store(p, found, rhs);
 			lb_emit_store(p, found, rhs);
 
 
-			lb_build_return_stmt(p, {});
+			lb_build_return_stmt(p, {}, ast_token(arg).pos);
 		} else {
 		} else {
 			GB_ASSERT(tuple->variables.count == 1);
 			GB_ASSERT(tuple->variables.count == 1);
-			lb_build_return_stmt_internal(p, rhs);
+			lb_build_return_stmt_internal(p, rhs, ast_token(arg).pos);
 		}
 		}
 	}
 	}
 	lb_start_block(p, continue_block);
 	lb_start_block(p, continue_block);
@@ -1200,9 +1200,22 @@ gb_internal lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index) {
 	lbValue gep = lb_emit_struct_ep_internal(p, s, index, result_type);
 	lbValue gep = lb_emit_struct_ep_internal(p, s, index, result_type);
 
 
 	Type *bt = base_type(t);
 	Type *bt = base_type(t);
-	if (bt->kind == Type_Struct && bt->Struct.is_packed) {
-		lb_set_metadata_custom_u64(p->module, gep.value, ODIN_METADATA_IS_PACKED, 1);
-		GB_ASSERT(lb_get_metadata_custom_u64(p->module, gep.value, ODIN_METADATA_IS_PACKED) == 1);
+	if (bt->kind == Type_Struct) {
+		if (bt->Struct.is_packed) {
+			lb_set_metadata_custom_u64(p->module, gep.value, ODIN_METADATA_IS_PACKED, 1);
+			GB_ASSERT(lb_get_metadata_custom_u64(p->module, gep.value, ODIN_METADATA_IS_PACKED) == 1);
+		}
+		u64 align_max = bt->Struct.custom_max_field_align;
+		u64 align_min = bt->Struct.custom_min_field_align;
+		GB_ASSERT(align_min == 0 || align_max == 0 || align_min <= align_max);
+		if (align_max) {
+			lb_set_metadata_custom_u64(p->module, gep.value, ODIN_METADATA_MAX_ALIGN, align_max);
+			GB_ASSERT(lb_get_metadata_custom_u64(p->module, gep.value, ODIN_METADATA_MAX_ALIGN) == align_max);
+		}
+		if (align_min) {
+			lb_set_metadata_custom_u64(p->module, gep.value, ODIN_METADATA_MIN_ALIGN, align_min);
+			GB_ASSERT(lb_get_metadata_custom_u64(p->module, gep.value, ODIN_METADATA_MIN_ALIGN) == align_min);
+		}
 	}
 	}
 
 
 	return gep;
 	return gep;

+ 3 - 3
src/main.cpp

@@ -1192,7 +1192,7 @@ gb_internal bool parse_build_flags(Array<String> args) {
 							build_context.no_type_assert = true;
 							build_context.no_type_assert = true;
 							break;
 							break;
 						case BuildFlag_NoDynamicLiterals:
 						case BuildFlag_NoDynamicLiterals:
-							build_context.no_dynamic_literals = true;
+							gb_printf_err("Warning: Use of -no-dynamic-literals is now redundant\n");
 							break;
 							break;
 						case BuildFlag_NoCRT:
 						case BuildFlag_NoCRT:
 							build_context.no_crt = true;
 							build_context.no_crt = true;
@@ -2120,7 +2120,7 @@ gb_internal void export_dependencies(Checker *c) {
 		for_array(i, files) {
 		for_array(i, files) {
 			AstFile *file = files[i];
 			AstFile *file = files[i];
 			gb_fprintf(&f, "\t\t\"%.*s\"", LIT(file->fullpath));
 			gb_fprintf(&f, "\t\t\"%.*s\"", LIT(file->fullpath));
-			if (i+1 == files.count) {
+			if (i+1 < files.count) {
 				gb_fprintf(&f, ",");
 				gb_fprintf(&f, ",");
 			}
 			}
 			gb_fprintf(&f, "\n");
 			gb_fprintf(&f, "\n");
@@ -2133,7 +2133,7 @@ gb_internal void export_dependencies(Checker *c) {
 		for_array(i, load_files) {
 		for_array(i, load_files) {
 			LoadFileCache *cache = load_files[i];
 			LoadFileCache *cache = load_files[i];
 			gb_fprintf(&f, "\t\t\"%.*s\"", LIT(cache->path));
 			gb_fprintf(&f, "\t\t\"%.*s\"", LIT(cache->path));
-			if (i+1 == load_files.count) {
+			if (i+1 < load_files.count) {
 				gb_fprintf(&f, ",");
 				gb_fprintf(&f, ",");
 			}
 			}
 			gb_fprintf(&f, "\n");
 			gb_fprintf(&f, "\n");

+ 67 - 3
src/parser.cpp

@@ -6265,10 +6265,16 @@ gb_internal u64 parse_vet_tag(Token token_for_pos, String s) {
 			syntax_error(token_for_pos, "Invalid vet flag name: %.*s", LIT(p));
 			syntax_error(token_for_pos, "Invalid vet flag name: %.*s", LIT(p));
 			error_line("\tExpected one of the following\n");
 			error_line("\tExpected one of the following\n");
 			error_line("\tunused\n");
 			error_line("\tunused\n");
+			error_line("\tunused-variables\n");
+			error_line("\tunused-imports\n");
+			error_line("\tunused-procedures\n");
 			error_line("\tshadowing\n");
 			error_line("\tshadowing\n");
 			error_line("\tusing-stmt\n");
 			error_line("\tusing-stmt\n");
 			error_line("\tusing-param\n");
 			error_line("\tusing-param\n");
+			error_line("\tstyle\n");
 			error_line("\textra\n");
 			error_line("\textra\n");
+			error_line("\tcast\n");
+			error_line("\ttabs\n");
 			return build_context.vet_flags;
 			return build_context.vet_flags;
 		}
 		}
 	}
 	}
@@ -6286,6 +6292,63 @@ gb_internal u64 parse_vet_tag(Token token_for_pos, String s) {
 	return vet_flags &~ vet_not_flags;
 	return vet_flags &~ vet_not_flags;
 }
 }
 
 
+gb_internal u64 parse_feature_tag(Token token_for_pos, String s) {
+	String const prefix = str_lit("feature");
+	GB_ASSERT(string_starts_with(s, prefix));
+	s = string_trim_whitespace(substring(s, prefix.len, s.len));
+
+	if (s.len == 0) {
+		return OptInFeatureFlag_NONE;
+	}
+
+	u64 feature_flags = 0;
+	u64 feature_not_flags = 0;
+
+	while (s.len > 0) {
+		String p = string_trim_whitespace(vet_tag_get_token(s, &s));
+		if (p.len == 0) {
+			break;
+		}
+
+		bool is_notted = false;
+		if (p[0] == '!') {
+			is_notted = true;
+			p = substring(p, 1, p.len);
+			if (p.len == 0) {
+				syntax_error(token_for_pos, "Expected a feature flag name after '!'");
+				return OptInFeatureFlag_NONE;
+			}
+		}
+
+		u64 flag = get_feature_flag_from_name(p);
+		if (flag != OptInFeatureFlag_NONE) {
+			if (is_notted) {
+				feature_not_flags |= flag;
+			} else {
+				feature_flags     |= flag;
+			}
+		} else {
+			ERROR_BLOCK();
+			syntax_error(token_for_pos, "Invalid feature flag name: %.*s", LIT(p));
+			error_line("\tExpected one of the following\n");
+			error_line("\tdynamic-literals\n");
+			return OptInFeatureFlag_NONE;
+		}
+	}
+
+	if (feature_flags == 0 && feature_not_flags == 0) {
+		return OptInFeatureFlag_NONE;
+	}
+	if (feature_flags == 0 && feature_not_flags != 0) {
+		return OptInFeatureFlag_NONE &~ feature_not_flags;
+	}
+	if (feature_flags != 0 && feature_not_flags == 0) {
+		return feature_flags;
+	}
+	GB_ASSERT(feature_flags != 0 && feature_not_flags != 0);
+	return feature_flags &~ feature_not_flags;
+}
+
 gb_internal String dir_from_path(String path) {
 gb_internal String dir_from_path(String path) {
 	String base_dir = path;
 	String base_dir = path;
 	for (isize i = path.len-1; i >= 0; i--) {
 	for (isize i = path.len-1; i >= 0; i--) {
@@ -6399,6 +6462,9 @@ gb_internal bool parse_file_tag(const String &lc, const Token &tok, AstFile *f)
 		} else if (command == "file") {
 		} else if (command == "file") {
 			f->flags |= AstFile_IsPrivateFile;
 			f->flags |= AstFile_IsPrivateFile;
 		}
 		}
+	} else if (string_starts_with(lc, str_lit("feature"))) {
+		f->feature_flags |= parse_feature_tag(tok, lc);
+		f->feature_flags_set = true;
 	} else if (lc == "lazy") {
 	} else if (lc == "lazy") {
 		if (build_context.ignore_lazy) {
 		if (build_context.ignore_lazy) {
 			// Ignore
 			// Ignore
@@ -6493,9 +6559,7 @@ gb_internal bool parse_file(Parser *p, AstFile *f) {
 	}
 	}
 	f->package_name = package_name.string;
 	f->package_name = package_name.string;
 
 
-	// TODO: Shouldn't single file only matter for build tags? no-instrumentation for example
-	// should be respected even when in single file mode.
-	if (!f->pkg->is_single_file) {
+	{
 		if (docs != nullptr && docs->list.count > 0) {
 		if (docs != nullptr && docs->list.count > 0) {
 			for (Token const &tok : docs->list) {
 			for (Token const &tok : docs->list) {
 				GB_ASSERT(tok.kind == Token_Comment);
 				GB_ASSERT(tok.kind == Token_Comment);

+ 2 - 0
src/parser.hpp

@@ -108,7 +108,9 @@ struct AstFile {
 	String       package_name;
 	String       package_name;
 
 
 	u64          vet_flags;
 	u64          vet_flags;
+	u64          feature_flags;
 	bool         vet_flags_set;
 	bool         vet_flags_set;
+	bool         feature_flags_set;
 
 
 	// >= 0: In Expression
 	// >= 0: In Expression
 	// <  0: In Control Clause
 	// <  0: In Control Clause

+ 1 - 0
tests/core/encoding/cbor/test_core_cbor.odin

@@ -1,3 +1,4 @@
+#+feature dynamic-literals
 package test_encoding_cbor
 package test_encoding_cbor
 
 
 import "base:intrinsics"
 import "base:intrinsics"

+ 1 - 0
tests/core/fmt/test_core_fmt.odin

@@ -1,3 +1,4 @@
+#+feature dynamic-literals
 package test_core_fmt
 package test_core_fmt
 
 
 import "base:runtime"
 import "base:runtime"

+ 1 - 0
tests/core/hash/test_core_hash.odin

@@ -1,3 +1,4 @@
+#+feature dynamic-literals
 package test_core_hash
 package test_core_hash
 
 
 import "core:hash/xxhash"
 import "core:hash/xxhash"

+ 1 - 0
tests/core/hash/test_vectors_xxhash.odin

@@ -1,4 +1,5 @@
 // Hash Test Vectors
 // Hash Test Vectors
+#+feature dynamic-literals
 package test_core_hash
 package test_core_hash
 
 
 XXHASH_Test_Vectors :: struct #packed {
 XXHASH_Test_Vectors :: struct #packed {

+ 1 - 0
tests/core/image/test_core_image.odin

@@ -7,6 +7,7 @@
 
 
 	A test suite for PNG, TGA, NetPBM, QOI and BMP.
 	A test suite for PNG, TGA, NetPBM, QOI and BMP.
 */
 */
+#+feature dynamic-literals
 package test_core_image
 package test_core_image
 
 
 import "core:testing"
 import "core:testing"

+ 1 - 0
tests/core/net/test_core_net.odin

@@ -12,6 +12,7 @@
 */
 */
 #+build !netbsd
 #+build !netbsd
 #+build !openbsd
 #+build !openbsd
+#+feature dynamic-literals
 package test_core_net
 package test_core_net
 
 
 import "core:testing"
 import "core:testing"

+ 99 - 1
tests/core/runtime/test_core_runtime.odin

@@ -1,3 +1,4 @@
+#+feature dynamic-literals
 package test_core_runtime
 package test_core_runtime
 
 
 import "base:intrinsics"
 import "base:intrinsics"
@@ -63,4 +64,101 @@ test_init_cap_map_dynarray :: proc(t: ^testing.T) {
         defer delete(d2)
         defer delete(d2)
         testing.expect(t, cap(d2) == 0)
         testing.expect(t, cap(d2) == 0)
         testing.expect(t, d2.allocator.procedure == ally.procedure)
         testing.expect(t, d2.allocator.procedure == ally.procedure)
-}
+}
+
+@(test)
+test_map_get :: proc(t: ^testing.T) {
+	check :: proc(t: ^testing.T, m: map[$K]$V, loc := #caller_location) {
+		for k, v in m {
+			got_key, got_val, ok := runtime.map_get(m, k)
+			testing.expect_value(t, got_key, k, loc = loc)
+			testing.expect_value(t, got_val, v, loc = loc)
+			testing.expect(t, ok, loc = loc)
+		}
+	}
+
+	// small keys & values
+	{
+		m := map[int]int{
+			1 = 10,
+			2 = 20,
+			3 = 30,
+		}
+		defer delete(m)
+		check(t, m)
+	}
+
+	// small keys; 2 values per cell
+	{
+		m := map[int][3]int{
+			1 = [3]int{10, 100, 1000},
+			2 = [3]int{20, 200, 2000},
+			3 = [3]int{30, 300, 3000},
+		}
+		defer delete(m)
+		check(t, m)
+	}
+
+	// 2 keys per cell; small values
+	{
+		m := map[[3]int]int{
+			[3]int{10, 100, 1000} = 1,
+			[3]int{20, 200, 2000} = 2,
+			[3]int{30, 300, 3000} = 3,
+		}
+		defer delete(m)
+		check(t, m)
+	}
+
+
+	// small keys; 3 values per cell
+	{
+		val :: struct #packed {
+			a, b: int,
+			c:    i32,
+		}
+		m := map[int]val{
+			1 = val{10, 100, 1000},
+			2 = val{20, 200, 2000},
+			3 = val{30, 300, 3000},
+		}
+		defer delete(m)
+		check(t, m)
+	}
+
+	// 3 keys per cell; small values
+	{
+		key :: struct #packed {
+			a, b: int,
+			c:    i32,
+		}
+		m := map[key]int{
+			key{10, 100, 1000} = 1,
+			key{20, 200, 2000} = 2,
+			key{30, 300, 3000} = 3,
+		}
+		defer delete(m)
+		check(t, m)
+	}
+
+	// small keys; value bigger than a chacheline
+	{
+		m := map[int][9]int{
+			1 = [9]int{10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000},
+			2 = [9]int{20, 200, 2000, 20000, 200000, 2000000, 20000000, 200000000, 2000000000},
+			3 = [9]int{30, 300, 3000, 30000, 300000, 3000000, 30000000, 300000000, 3000000000},
+		}
+		defer delete(m)
+		check(t, m)
+	}
+	// keys bigger than a chacheline; small values
+	{
+		m := map[[9]int]int{
+			[9]int{10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000} = 1,
+			[9]int{20, 200, 2000, 20000, 200000, 2000000, 20000000, 200000000, 2000000000} = 2,
+			[9]int{30, 300, 3000, 30000, 300000, 3000000, 30000000, 300000000, 3000000000} = 3,
+		}
+		defer delete(m)
+		check(t, m)
+	}
+}

+ 1 - 0
tests/core/slice/test_core_slice.odin

@@ -1,3 +1,4 @@
+#+feature dynamic-literals
 package test_core_slice
 package test_core_slice
 
 
 import "core:slice"
 import "core:slice"

+ 1 - 0
tests/issues/run.bat

@@ -16,6 +16,7 @@ set COMMON=-define:ODIN_TEST_FANCY=false -file -vet -strict-style
 ..\..\..\odin test ..\test_issue_2637.odin %COMMON%  || exit /b
 ..\..\..\odin test ..\test_issue_2637.odin %COMMON%  || exit /b
 ..\..\..\odin test ..\test_issue_2666.odin %COMMON%  || exit /b
 ..\..\..\odin test ..\test_issue_2666.odin %COMMON%  || exit /b
 ..\..\..\odin test ..\test_issue_4210.odin %COMMON%  || exit /b
 ..\..\..\odin test ..\test_issue_4210.odin %COMMON%  || exit /b
+..\..\..\odin test ..\test_issue_4584.odin %COMMON%  || exit /b
 
 
 @echo off
 @echo off
 
 

+ 1 - 0
tests/issues/run.sh

@@ -17,6 +17,7 @@ $ODIN test ../test_issue_2615.odin $COMMON
 $ODIN test ../test_issue_2637.odin $COMMON
 $ODIN test ../test_issue_2637.odin $COMMON
 $ODIN test ../test_issue_2666.odin $COMMON
 $ODIN test ../test_issue_2666.odin $COMMON
 $ODIN test ../test_issue_4210.odin $COMMON
 $ODIN test ../test_issue_4210.odin $COMMON
+$ODIN test ../test_issue_4584.odin $COMMON
 if [[ $($ODIN build ../test_issue_2395.odin $COMMON 2>&1 >/dev/null | grep -c "Error:") -eq 2 ]] ; then
 if [[ $($ODIN build ../test_issue_2395.odin $COMMON 2>&1 >/dev/null | grep -c "Error:") -eq 2 ]] ; then
 	echo "SUCCESSFUL 1/1"
 	echo "SUCCESSFUL 1/1"
 else
 else

+ 198 - 0
tests/issues/test_issue_4584.odin

@@ -0,0 +1,198 @@
+// Tests issue #4584 https://github.com/odin-lang/Odin/issues/4584
+package test_issues
+
+import "core:testing"
+import "core:log"
+import "core:math/linalg"
+import glm "core:math/linalg/glsl"
+import hlm "core:math/linalg/hlsl"
+
+@test
+test_adjugate_2x2 :: proc(t: ^testing.T) {
+	I := linalg.identity(matrix[2,2]int)
+	m := matrix[2,2]int {
+		-3, 2,
+		-1, 0,
+	}
+	expected := matrix[2,2]int {
+		 0, -2,
+		 1, -3,
+	}
+	testing.expect_value(t, linalg.adjugate(m), expected)
+	testing.expect_value(t, linalg.determinant(m), 2)
+	testing.expect_value(t, linalg.adjugate(m) * m, 2 * I)
+	testing.expect_value(t, m * linalg.adjugate(m), 2 * I)
+
+	testing.expect_value(t, glm.adjugate(m), expected)
+	testing.expect_value(t, glm.determinant(m), 2)
+	testing.expect_value(t, glm.adjugate(m) * m, 2 * I)
+	testing.expect_value(t, m * glm.adjugate(m), 2 * I)
+
+	testing.expect_value(t, hlm.adjugate(m), expected)
+	testing.expect_value(t, hlm.determinant(m), 2)
+	testing.expect_value(t, hlm.adjugate(m) * m, 2 * I)
+	testing.expect_value(t, m * hlm.adjugate(m), 2 * I)
+}
+
+@test
+test_adjugate_3x3 :: proc(t: ^testing.T) {
+	I := linalg.identity(matrix[3,3]int)
+	m := matrix[3,3]int {
+		-3,  2, -5,
+		-1,  0, -2,
+		 3, -4,  1,
+	}
+	expected := matrix[3,3]int {
+		-8, 18, -4,
+		-5, 12, -1,
+		 4, -6,  2,
+	}
+	testing.expect_value(t, linalg.adjugate(m), expected)
+	testing.expect_value(t, linalg.determinant(m), -6)
+	testing.expect_value(t, linalg.adjugate(m) * m, -6 * I)
+	testing.expect_value(t, m * linalg.adjugate(m), -6 * I)
+
+	testing.expect_value(t, glm.adjugate(m), expected)
+	testing.expect_value(t, glm.determinant(m), -6)
+	testing.expect_value(t, glm.adjugate(m) * m, -6 * I)
+	testing.expect_value(t, m * glm.adjugate(m), -6 * I)
+
+	testing.expect_value(t, hlm.adjugate(m), expected)
+	testing.expect_value(t, hlm.determinant(m), -6)
+	testing.expect_value(t, hlm.adjugate(m) * m, -6 * I)
+	testing.expect_value(t, m * hlm.adjugate(m), -6 * I)
+}
+
+@test
+test_adjugate_4x4 :: proc(t: ^testing.T) {
+	I := linalg.identity(matrix[4,4]int)
+	m := matrix[4,4]int {
+		-3,  2, -5, 1,
+		-1,  0, -2, 2,
+		 3, -4,  1, 3,
+		 4,  5,  6, 7,
+	}
+	expected := matrix[4,4]int {
+		-144,  266, -92, -16,
+		 -57,   92,  -5, -16,
+		 105, -142,  55,   2,
+		  33,  -96,   9,  -6,
+	}
+	testing.expect_value(t, linalg.adjugate(m), expected)
+	testing.expect_value(t, linalg.determinant(m), -174)
+	testing.expect_value(t, linalg.adjugate(m) * m, -174 * I)
+	testing.expect_value(t, m * linalg.adjugate(m), -174 * I)
+
+	testing.expect_value(t, glm.adjugate(m), expected)
+	testing.expect_value(t, glm.determinant(m), -174)
+	testing.expect_value(t, glm.adjugate(m) * m, -174 * I)
+	testing.expect_value(t, m * glm.adjugate(m), -174 * I)
+
+	testing.expect_value(t, hlm.adjugate(m), expected)
+	testing.expect_value(t, hlm.determinant(m), -174)
+	testing.expect_value(t, hlm.adjugate(m) * m, -174 * I)
+	testing.expect_value(t, m * hlm.adjugate(m), -174 * I)
+}
+
+@test
+test_inverse_regression_2x2 :: proc(t: ^testing.T) {
+	I := linalg.identity(matrix[2,2]f32)
+	m := matrix[2,2]f32 {
+		-3, 2,
+		-1, 0,
+	}
+	expected := matrix[2,2]f32 {
+		    0.0,     -1.0,
+		1.0/2.0, -3.0/2.0,
+	}
+	expect_float_matrix_value(t, linalg.inverse(m), expected)
+	expect_float_matrix_value(t, linalg.inverse_transpose(m), linalg.transpose(expected))
+	expect_float_matrix_value(t, linalg.inverse(m) * m, I)
+	expect_float_matrix_value(t, m * linalg.inverse(m), I)
+
+	expect_float_matrix_value(t, glm.inverse(m), expected)
+	expect_float_matrix_value(t, glm.inverse_transpose(m), glm.transpose(expected))
+	expect_float_matrix_value(t, glm.inverse(m) * m, I)
+	expect_float_matrix_value(t, m * glm.inverse(m), I)
+
+	expect_float_matrix_value(t, hlm.inverse(m), expected)
+	expect_float_matrix_value(t, hlm.inverse_transpose(m), hlm.transpose(expected))
+	expect_float_matrix_value(t, hlm.inverse(m) * m, I)
+	expect_float_matrix_value(t, m * hlm.inverse(m), I)
+}
+
+@test
+test_inverse_regression_3x3 :: proc(t: ^testing.T) {
+	I := linalg.identity(matrix[3,3]f32)
+	m := matrix[3,3]f32 {
+		-3,  2, -5,
+		-1,  0, -2,
+		 3, -4,  1,
+	}
+	expected := matrix[3,3]f32 {
+		 4.0/3.0, -3.0,  2.0/3.0,
+		 5.0/6.0, -2.0,  1.0/6.0,
+		-2.0/3.0,  1.0, -1.0/3.0,
+	}
+	expect_float_matrix_value(t, linalg.inverse(m), expected)
+	expect_float_matrix_value(t, linalg.inverse_transpose(m), linalg.transpose(expected))
+	expect_float_matrix_value(t, linalg.inverse(m) * m, I)
+	expect_float_matrix_value(t, m * linalg.inverse(m), I)
+
+	expect_float_matrix_value(t, glm.inverse(m), expected)
+	expect_float_matrix_value(t, glm.inverse_transpose(m), glm.transpose(expected))
+	expect_float_matrix_value(t, glm.inverse(m) * m, I)
+	expect_float_matrix_value(t, m * glm.inverse(m), I)
+
+	expect_float_matrix_value(t, hlm.inverse(m), expected)
+	expect_float_matrix_value(t, hlm.inverse_transpose(m), hlm.transpose(expected))
+	expect_float_matrix_value(t, hlm.inverse(m) * m, I)
+	expect_float_matrix_value(t, m * hlm.inverse(m), I)
+}
+
+@test
+test_inverse_regression_4x4 :: proc(t: ^testing.T) {
+	I := linalg.identity(matrix[4,4]f32)
+	m := matrix[4,4]f32 {
+		-3,  2, -5, 1,
+		-1,  0, -2, 2,
+		 3, -4,  1, 3,
+		 4,  5,  6, 7,
+	}
+	expected := matrix[4,4]f32 {
+		 24.0/29.0, -133.0/87.0,   46.0/87.0,  8.0/87.0,
+		 19.0/58.0,  -46.0/87.0,   5.0/174.0,  8.0/87.0,
+		-35.0/58.0,   71.0/87.0, -55.0/174.0, -1.0/87.0,
+		-11.0/58.0,   16.0/29.0,   -3.0/58.0,  1.0/29.0,
+	}
+	expect_float_matrix_value(t, linalg.inverse(m), expected)
+	expect_float_matrix_value(t, linalg.inverse_transpose(m), linalg.transpose(expected))
+	expect_float_matrix_value(t, linalg.inverse(m) * m, I)
+	expect_float_matrix_value(t, m * linalg.inverse(m), I)
+
+	expect_float_matrix_value(t, glm.inverse(m), expected)
+	expect_float_matrix_value(t, glm.inverse_transpose(m), glm.transpose(expected))
+	expect_float_matrix_value(t, glm.inverse(m) * m, I)
+	expect_float_matrix_value(t, m * glm.inverse(m), I)
+
+	expect_float_matrix_value(t, hlm.inverse(m), expected)
+	expect_float_matrix_value(t, hlm.inverse_transpose(m), hlm.transpose(expected))
+	expect_float_matrix_value(t, hlm.inverse(m) * m, I)
+	expect_float_matrix_value(t, m * hlm.inverse(m), I)
+}
+
+@(private="file")
+expect_float_matrix_value :: proc(t: ^testing.T, value, expected: $M/matrix[$N, N]f32, loc := #caller_location, value_expr := #caller_expression(value)) -> bool {
+	ok := true
+	outer: for i in 0..<N {
+		for j in 0..<N {
+			diff := abs(value[i, j] - expected[i, j])
+			if diff > 1e-6 {
+				ok = false
+				break outer
+			}
+		}
+	}
+	if !ok do log.errorf("expected %v to be %v, got %v", value_expr, expected, value, location=loc)
+	return ok
+}

+ 1 - 0
tests/issues/test_issue_829.odin

@@ -1,4 +1,5 @@
 // Tests issue #829 https://github.com/odin-lang/Odin/issues/829
 // Tests issue #829 https://github.com/odin-lang/Odin/issues/829
+#+feature dynamic-literals
 package test_issues
 package test_issues
 
 
 import "core:testing"
 import "core:testing"

+ 3 - 11
vendor/box2d/box2d.odin

@@ -24,19 +24,11 @@ when ODIN_OS == .Windows {
 }
 }
 
 
 when !#exists(LIB_PATH) {
 when !#exists(LIB_PATH) {
-	#panic("Could not find the compiled box2d libraries at \"" + LIB_PATH + "\", they can be compiled by running the `build.sh` script at `" + ODIN_ROOT + "vendor/box2d/build_box2d.sh\"`")
+	#panic("Could not find the compiled box2d libraries at \"" + LIB_PATH + "\", they can be compiled by running the `build_box2d.sh` script at `" + ODIN_ROOT + "vendor/box2d/build_box2d.sh\"`")
 }
 }
 
 
-when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 {
-	when VECTOR_EXT == "_simd" {
-		foreign import lib "lib/box2d_wasm_simd.o"
-	} else {
-		foreign import lib "lib/box2d_wasm.o"
-	}
-} else {
-	foreign import lib {
-		LIB_PATH,
-	}
+foreign import lib {
+	LIB_PATH,
 }
 }
 
 
 
 

+ 5 - 0
vendor/box2d/build_box2d.sh

@@ -68,7 +68,12 @@ esac
 
 
 cd ..
 cd ..
 
 
+set +e
 make -f wasm.Makefile
 make -f wasm.Makefile
+if [[ $? -ne 0 ]]; then
+	printf "\e[30;43mwarning:\e[0m Native Box2D libraries were built successfully, the WASM build failed, likely because your default C compiler and/or linker doesn't support WASM, you can set the CC and LD environment variables to point to a compiler and linker that support it\n"
+fi
+set -e
 
 
 rm -rf v3.0.0.tar.gz
 rm -rf v3.0.0.tar.gz
 rm -rf box2d-3.0.0
 rm -rf box2d-3.0.0

+ 3 - 1
vendor/box2d/wasm.Makefile

@@ -2,6 +2,8 @@
 # I tried to make a cmake toolchain file for this / use cmake but this is far easier.
 # I tried to make a cmake toolchain file for this / use cmake but this is far easier.
 # NOTE: We are pretending to be emscripten to box2d so it takes WASM code paths, but we don't actually use emscripten.
 # NOTE: We are pretending to be emscripten to box2d so it takes WASM code paths, but we don't actually use emscripten.
 
 
+# WARN: wasm is probably not supported by your default C compiler and linker, overwrite the CC and LD environment variables accordingly.
+# Example for MacOS:
 # CC = $(shell brew --prefix llvm)/bin/clang
 # CC = $(shell brew --prefix llvm)/bin/clang
 # LD = $(shell brew --prefix llvm)/bin/wasm-ld
 # LD = $(shell brew --prefix llvm)/bin/wasm-ld
 
 
@@ -10,7 +12,7 @@ SRCS      = $(wildcard box2d-$(VERSION)/src/*.c)
 OBJS_SIMD = $(SRCS:.c=_simd.o)
 OBJS_SIMD = $(SRCS:.c=_simd.o)
 OBJS      = $(SRCS:.c=.o)
 OBJS      = $(SRCS:.c=.o)
 SYSROOT   = $(shell odin root)/vendor/libc
 SYSROOT   = $(shell odin root)/vendor/libc
-CFLAGS    = -Ibox2d-$(VERSION)/include -Ibox2d-$(VERSION)/Extern/simde --target=wasm32 -D__EMSCRIPTEN__ -DNDEBUG -O3 --sysroot=$(SYSROOT)
+CFLAGS    = -Ibox2d-$(VERSION)/include -Ibox2d-$(VERSION)/extern/simde --target=wasm32 -D__EMSCRIPTEN__ -DNDEBUG -O3 --sysroot=$(SYSROOT)
 
 
 all: lib/box2d_wasm.o lib/box2d_wasm_simd.o clean
 all: lib/box2d_wasm.o lib/box2d_wasm_simd.o clean
 
 

+ 58 - 13
vendor/cgltf/cgltf.odin

@@ -105,6 +105,7 @@ type :: enum c.int {
 }
 }
 
 
 primitive_type :: enum c.int {
 primitive_type :: enum c.int {
+	invalid,
 	points,
 	points,
 	lines,
 	lines,
 	line_loop,
 	line_loop,
@@ -222,15 +223,6 @@ accessor_sparse :: struct {
 	indices_component_type:   component_type,
 	indices_component_type:   component_type,
 	values_buffer_view:       ^buffer_view,
 	values_buffer_view:       ^buffer_view,
 	values_byte_offset:       uint,
 	values_byte_offset:       uint,
-	extras:                   extras_t,
-	indices_extras:           extras_t,
-	values_extras:            extras_t,
-	extensions_count:         uint,
-	extensions:               [^]extension `fmt:"v,extensions_count"`,
-	indices_extensions_count: uint,
-	indices_extensions:       [^]extension `fmt:"v,indices_extensions_count"`,
-	values_extensions_count:  uint,
-	values_extensions:        [^]extension `fmt:"v,values_extensions_count"`,
 }
 }
 
 
 accessor :: struct {
 accessor :: struct {
@@ -306,9 +298,6 @@ texture_view :: struct {
 	scale:            f32, /* equivalent to strength for occlusion_texture */
 	scale:            f32, /* equivalent to strength for occlusion_texture */
 	has_transform:    b32,
 	has_transform:    b32,
 	transform:        texture_transform,
 	transform:        texture_transform,
-	extras:           extras_t,
-	extensions_count: uint,
-	extensions:       [^]extension `fmt:"v,extensions_count"`,
 }
 }
 
 
 pbr_metallic_roughness :: struct {
 pbr_metallic_roughness :: struct {
@@ -381,6 +370,16 @@ iridescence :: struct {
 	iridescence_thickness_texture: texture_view,
 	iridescence_thickness_texture: texture_view,
 }
 }
 
 
+anisotropy :: struct {
+	anisotropy_strength: f32,
+	anisotropy_rotation: f32,
+	anisotropy_texture:  texture_view,
+}
+
+dispersion :: struct {
+	dispersion: f32,
+}
+
 material :: struct {
 material :: struct {
 	name: cstring,
 	name: cstring,
 	has_pbr_metallic_roughness:  b32,
 	has_pbr_metallic_roughness:  b32,
@@ -393,6 +392,8 @@ material :: struct {
 	has_sheen:                   b32,
 	has_sheen:                   b32,
 	has_emissive_strength:       b32,
 	has_emissive_strength:       b32,
 	has_iridescence:             b32,
 	has_iridescence:             b32,
+	has_anisotropy:              b32,
+	has_dispersion:              b32,
 	pbr_metallic_roughness:      pbr_metallic_roughness,
 	pbr_metallic_roughness:      pbr_metallic_roughness,
 	pbr_specular_glossiness:     pbr_specular_glossiness,
 	pbr_specular_glossiness:     pbr_specular_glossiness,
 	clearcoat:                   clearcoat,
 	clearcoat:                   clearcoat,
@@ -403,6 +404,8 @@ material :: struct {
 	volume:                      volume,
 	volume:                      volume,
 	emissive_strength:           emissive_strength,
 	emissive_strength:           emissive_strength,
 	iridescence:                 iridescence,
 	iridescence:                 iridescence,
+	anisotropy:                  anisotropy,
+	dispersion:                  dispersion,
 	normal_texture:              texture_view,
 	normal_texture:              texture_view,
 	occlusion_texture:           texture_view,
 	occlusion_texture:           texture_view,
 	emissive_texture:            texture_view,
 	emissive_texture:            texture_view,
@@ -432,7 +435,6 @@ draco_mesh_compression :: struct {
 }
 }
 
 
 mesh_gpu_instancing :: struct {
 mesh_gpu_instancing :: struct {
-	buffer_view: ^buffer_view,
 	attributes:  []attribute,
 	attributes:  []attribute,
 }
 }
 
 
@@ -683,6 +685,9 @@ foreign lib {
 	node_transform_local :: proc(node: ^node, out_matrix: [^]f32) ---
 	node_transform_local :: proc(node: ^node, out_matrix: [^]f32) ---
 	node_transform_world :: proc(node: ^node, out_matrix: [^]f32) ---
 	node_transform_world :: proc(node: ^node, out_matrix: [^]f32) ---
 
 
+	@(require_results)
+	buffer_view_data :: proc(view: ^/*const*/buffer_view) -> [^]byte ---
+
 	@(require_results)
 	@(require_results)
 	accessor_read_float :: proc(accessor: ^/*const*/accessor, index: uint, out: [^]f32,    element_size: uint) -> b32 ---
 	accessor_read_float :: proc(accessor: ^/*const*/accessor, index: uint, out: [^]f32,    element_size: uint) -> b32 ---
 	@(require_results)
 	@(require_results)
@@ -693,13 +698,53 @@ foreign lib {
 	@(require_results)
 	@(require_results)
 	num_components :: proc(type: type) -> uint ---
 	num_components :: proc(type: type) -> uint ---
 
 
+	@(require_results)
+	component_size :: proc(component_type: component_type) -> uint ---
+	@(require_results)
+	calc_size :: proc(type: type, component_type: component_type) -> uint ---
+
 	@(require_results)
 	@(require_results)
 	accessor_unpack_floats :: proc(accessor: ^/*const*/accessor, out: [^]f32, float_count: uint) -> uint ---
 	accessor_unpack_floats :: proc(accessor: ^/*const*/accessor, out: [^]f32, float_count: uint) -> uint ---
+	@(require_results)
+	accessor_unpack_indices :: proc(accessor: ^/*const*/accessor , out: rawptr, out_component_size: uint, index_count: uint) -> uint ---
 
 
 	/* this function is deprecated and will be removed in the future; use cgltf_extras::data instead */
 	/* this function is deprecated and will be removed in the future; use cgltf_extras::data instead */
 	@(require_results)
 	@(require_results)
 	copy_extras_json :: proc(data: ^data, extras: ^extras_t, dest: [^]byte, dest_size: ^uint) -> result ---
 	copy_extras_json :: proc(data: ^data, extras: ^extras_t, dest: [^]byte, dest_size: ^uint) -> result ---
 
 
+	@(require_results)
+	mesh_index        :: proc(data: ^/*const*/data, object: ^/*const*/mesh) -> uint ---
+	@(require_results)
+	material_index    :: proc(data: ^/*const*/data, object: ^/*const*/material) -> uint ---
+	@(require_results)
+	accessor_index    :: proc(data: ^/*const*/data, object: ^/*const*/accessor) -> uint ---
+	@(require_results)
+	buffer_view_index :: proc(data: ^/*const*/data, object: ^/*const*/buffer_view) -> uint ---
+	@(require_results)
+	buffer_index      :: proc(data: ^/*const*/data, object: ^/*const*/buffer) -> uint ---
+	@(require_results)
+	image_index       :: proc(data: ^/*const*/data, object: ^/*const*/image) -> uint ---
+	@(require_results)
+	texture_index     :: proc(data: ^/*const*/data, object: ^/*const*/texture) -> uint ---
+	@(require_results)
+	sampler_index     :: proc(data: ^/*const*/data, object: ^/*const*/sampler) -> uint ---
+	@(require_results)
+	skin_index        :: proc(data: ^/*const*/data, object: ^/*const*/skin) -> uint ---
+	@(require_results)
+	camera_index      :: proc(data: ^/*const*/data, object: ^/*const*/camera) -> uint ---
+	@(require_results)
+	light_index       :: proc(data: ^/*const*/data, object: ^/*const*/light) -> uint ---
+	@(require_results)
+	node_index        :: proc(data: ^/*const*/data, object: ^/*const*/node) -> uint ---
+	@(require_results)
+	scene_index       :: proc(data: ^/*const*/data, object: ^/*const*/scene) -> uint ---
+	@(require_results)
+	animation_index   :: proc(data: ^/*const*/data, object: ^/*const*/animation) -> uint ---
+	@(require_results)
+	animation_sampler_index :: proc(animation: ^/*const*/animation, object: ^/*const*/animation_sampler) -> uint ---
+	@(require_results)
+	animation_channel_index :: proc(animation: ^/*const*/animation, object: ^/*const*/animation_channel) -> uint ---
+	
 	@(require_results)
 	@(require_results)
 	write_file :: proc(#by_ptr options: options, path:   cstring,             data: ^data) -> result ---
 	write_file :: proc(#by_ptr options: options, path:   cstring,             data: ^data) -> result ---
 	@(require_results)
 	@(require_results)

BIN
vendor/cgltf/lib/cgltf.lib


BIN
vendor/cgltf/lib/cgltf_wasm.o


File diff suppressed because it is too large
+ 338 - 200
vendor/cgltf/src/cgltf.h


+ 55 - 12
vendor/cgltf/src/cgltf_write.h

@@ -1,7 +1,7 @@
 /**
 /**
  * cgltf_write - a single-file glTF 2.0 writer written in C99.
  * cgltf_write - a single-file glTF 2.0 writer written in C99.
  *
  *
- * Version: 1.13
+ * Version: 1.14
  *
  *
  * Website: https://github.com/jkuhlmann/cgltf
  * Website: https://github.com/jkuhlmann/cgltf
  *
  *
@@ -85,6 +85,8 @@ cgltf_size cgltf_write(const cgltf_options* options, char* buffer, cgltf_size si
 #define CGLTF_EXTENSION_FLAG_MATERIALS_EMISSIVE_STRENGTH (1 << 13)
 #define CGLTF_EXTENSION_FLAG_MATERIALS_EMISSIVE_STRENGTH (1 << 13)
 #define CGLTF_EXTENSION_FLAG_MESH_GPU_INSTANCING (1 << 14)
 #define CGLTF_EXTENSION_FLAG_MESH_GPU_INSTANCING (1 << 14)
 #define CGLTF_EXTENSION_FLAG_MATERIALS_IRIDESCENCE (1 << 15)
 #define CGLTF_EXTENSION_FLAG_MATERIALS_IRIDESCENCE (1 << 15)
+#define CGLTF_EXTENSION_FLAG_MATERIALS_ANISOTROPY (1 << 16)
+#define CGLTF_EXTENSION_FLAG_MATERIALS_DISPERSION (1 << 17)
 
 
 typedef struct {
 typedef struct {
 	char* buffer;
 	char* buffer;
@@ -152,7 +154,6 @@ typedef struct {
 			context->extension_flags |= CGLTF_EXTENSION_FLAG_TEXTURE_TRANSFORM; \
 			context->extension_flags |= CGLTF_EXTENSION_FLAG_TEXTURE_TRANSFORM; \
 			cgltf_write_texture_transform(context, &info.transform); \
 			cgltf_write_texture_transform(context, &info.transform); \
 		} \
 		} \
-		cgltf_write_extras(context, &info.extras); \
 		cgltf_write_line(context, "}"); }
 		cgltf_write_line(context, "}"); }
 
 
 #define CGLTF_WRITE_NORMAL_TEXTURE_INFO(label, info) if (info.texture) { \
 #define CGLTF_WRITE_NORMAL_TEXTURE_INFO(label, info) if (info.texture) { \
@@ -164,7 +165,6 @@ typedef struct {
 			context->extension_flags |= CGLTF_EXTENSION_FLAG_TEXTURE_TRANSFORM; \
 			context->extension_flags |= CGLTF_EXTENSION_FLAG_TEXTURE_TRANSFORM; \
 			cgltf_write_texture_transform(context, &info.transform); \
 			cgltf_write_texture_transform(context, &info.transform); \
 		} \
 		} \
-		cgltf_write_extras(context, &info.extras); \
 		cgltf_write_line(context, "}"); }
 		cgltf_write_line(context, "}"); }
 
 
 #define CGLTF_WRITE_OCCLUSION_TEXTURE_INFO(label, info) if (info.texture) { \
 #define CGLTF_WRITE_OCCLUSION_TEXTURE_INFO(label, info) if (info.texture) { \
@@ -176,12 +176,11 @@ typedef struct {
 			context->extension_flags |= CGLTF_EXTENSION_FLAG_TEXTURE_TRANSFORM; \
 			context->extension_flags |= CGLTF_EXTENSION_FLAG_TEXTURE_TRANSFORM; \
 			cgltf_write_texture_transform(context, &info.transform); \
 			cgltf_write_texture_transform(context, &info.transform); \
 		} \
 		} \
-		cgltf_write_extras(context, &info.extras); \
 		cgltf_write_line(context, "}"); }
 		cgltf_write_line(context, "}"); }
 
 
 #ifndef CGLTF_CONSTS
 #ifndef CGLTF_CONSTS
-static const cgltf_size GlbHeaderSize = 12;
-static const cgltf_size GlbChunkHeaderSize = 8;
+#define GlbHeaderSize 12
+#define GlbChunkHeaderSize 8
 static const uint32_t GlbVersion = 2;
 static const uint32_t GlbVersion = 2;
 static const uint32_t GlbMagic = 0x46546C67;
 static const uint32_t GlbMagic = 0x46546C67;
 static const uint32_t GlbMagicJsonChunk = 0x4E4F534A;
 static const uint32_t GlbMagicJsonChunk = 0x4E4F534A;
@@ -360,6 +359,21 @@ static int cgltf_int_from_component_type(cgltf_component_type ctype)
 	}
 	}
 }
 }
 
 
+static int cgltf_int_from_primitive_type(cgltf_primitive_type ctype)
+{
+	switch (ctype)
+	{
+		case cgltf_primitive_type_points: return 0;
+		case cgltf_primitive_type_lines: return 1;
+		case cgltf_primitive_type_line_loop: return 2;
+		case cgltf_primitive_type_line_strip: return 3;
+		case cgltf_primitive_type_triangles: return 4;
+		case cgltf_primitive_type_triangle_strip: return 5;
+		case cgltf_primitive_type_triangle_fan: return 6;
+		default: return -1;
+	}
+}
+
 static const char* cgltf_str_from_alpha_mode(cgltf_alpha_mode alpha_mode)
 static const char* cgltf_str_from_alpha_mode(cgltf_alpha_mode alpha_mode)
 {
 {
 	switch (alpha_mode)
 	switch (alpha_mode)
@@ -455,7 +469,7 @@ static void cgltf_write_asset(cgltf_write_context* context, const cgltf_asset* a
 
 
 static void cgltf_write_primitive(cgltf_write_context* context, const cgltf_primitive* prim)
 static void cgltf_write_primitive(cgltf_write_context* context, const cgltf_primitive* prim)
 {
 {
-	cgltf_write_intprop(context, "mode", (int) prim->type, 4);
+	cgltf_write_intprop(context, "mode", cgltf_int_from_primitive_type(prim->type), 4);
 	CGLTF_WRITE_IDXPROP("indices", prim->indices, context->data->accessors);
 	CGLTF_WRITE_IDXPROP("indices", prim->indices, context->data->accessors);
 	CGLTF_WRITE_IDXPROP("material", prim->material, context->data->materials);
 	CGLTF_WRITE_IDXPROP("material", prim->material, context->data->materials);
 	cgltf_write_line(context, "\"attributes\": {");
 	cgltf_write_line(context, "\"attributes\": {");
@@ -641,6 +655,16 @@ static void cgltf_write_material(cgltf_write_context* context, const cgltf_mater
 		context->extension_flags |= CGLTF_EXTENSION_FLAG_MATERIALS_IRIDESCENCE;
 		context->extension_flags |= CGLTF_EXTENSION_FLAG_MATERIALS_IRIDESCENCE;
 	}
 	}
 
 
+	if (material->has_anisotropy)
+	{
+		context->extension_flags |= CGLTF_EXTENSION_FLAG_MATERIALS_ANISOTROPY;
+	}
+
+	if (material->has_dispersion)
+	{
+		context->extension_flags |= CGLTF_EXTENSION_FLAG_MATERIALS_DISPERSION;
+	}
+
 	if (material->has_pbr_metallic_roughness)
 	if (material->has_pbr_metallic_roughness)
 	{
 	{
 		const cgltf_pbr_metallic_roughness* params = &material->pbr_metallic_roughness;
 		const cgltf_pbr_metallic_roughness* params = &material->pbr_metallic_roughness;
@@ -656,7 +680,7 @@ static void cgltf_write_material(cgltf_write_context* context, const cgltf_mater
 		cgltf_write_line(context, "}");
 		cgltf_write_line(context, "}");
 	}
 	}
 
 
-	if (material->unlit || material->has_pbr_specular_glossiness || material->has_clearcoat || material->has_ior || material->has_specular || material->has_transmission || material->has_sheen || material->has_volume || material->has_emissive_strength || material->has_iridescence)
+	if (material->unlit || material->has_pbr_specular_glossiness || material->has_clearcoat || material->has_ior || material->has_specular || material->has_transmission || material->has_sheen || material->has_volume || material->has_emissive_strength || material->has_iridescence || material->has_anisotropy || material->has_dispersion)
 	{
 	{
 		cgltf_write_line(context, "\"extensions\": {");
 		cgltf_write_line(context, "\"extensions\": {");
 		if (material->has_clearcoat)
 		if (material->has_clearcoat)
@@ -767,6 +791,22 @@ static void cgltf_write_material(cgltf_write_context* context, const cgltf_mater
 			CGLTF_WRITE_TEXTURE_INFO("iridescenceThicknessTexture", params->iridescence_thickness_texture);
 			CGLTF_WRITE_TEXTURE_INFO("iridescenceThicknessTexture", params->iridescence_thickness_texture);
 			cgltf_write_line(context, "}");
 			cgltf_write_line(context, "}");
 		}
 		}
+		if (material->has_anisotropy)
+		{
+			cgltf_write_line(context, "\"KHR_materials_anisotropy\": {");
+			const cgltf_anisotropy* params = &material->anisotropy;
+			cgltf_write_floatprop(context, "anisotropyFactor", params->anisotropy_strength, 0.f);
+			cgltf_write_floatprop(context, "anisotropyRotation", params->anisotropy_rotation, 0.f);
+			CGLTF_WRITE_TEXTURE_INFO("anisotropyTexture", params->anisotropy_texture);
+			cgltf_write_line(context, "}");
+		}
+		if (material->has_dispersion)
+		{
+			cgltf_write_line(context, "\"KHR_materials_dispersion\": {");
+			const cgltf_dispersion* params = &material->dispersion;
+			cgltf_write_floatprop(context, "dispersion", params->dispersion, 0.f);
+			cgltf_write_line(context, "}");
+		}
 		cgltf_write_line(context, "}");
 		cgltf_write_line(context, "}");
 	}
 	}
 
 
@@ -977,7 +1017,6 @@ static void cgltf_write_node(cgltf_write_context* context, const cgltf_node* nod
 
 
 		cgltf_write_line(context, "\"EXT_mesh_gpu_instancing\": {");
 		cgltf_write_line(context, "\"EXT_mesh_gpu_instancing\": {");
 		{
 		{
-			CGLTF_WRITE_IDXPROP("bufferView", node->mesh_gpu_instancing.buffer_view, context->data->buffer_views);
 			cgltf_write_line(context, "\"attributes\": {");
 			cgltf_write_line(context, "\"attributes\": {");
 			{
 			{
 				for (cgltf_size i = 0; i < node->mesh_gpu_instancing.attributes_count; ++i)
 				for (cgltf_size i = 0; i < node->mesh_gpu_instancing.attributes_count; ++i)
@@ -1044,14 +1083,11 @@ static void cgltf_write_accessor(cgltf_write_context* context, const cgltf_acces
 		cgltf_write_sizeprop(context, "byteOffset", (int)accessor->sparse.indices_byte_offset, 0);
 		cgltf_write_sizeprop(context, "byteOffset", (int)accessor->sparse.indices_byte_offset, 0);
 		CGLTF_WRITE_IDXPROP("bufferView", accessor->sparse.indices_buffer_view, context->data->buffer_views);
 		CGLTF_WRITE_IDXPROP("bufferView", accessor->sparse.indices_buffer_view, context->data->buffer_views);
 		cgltf_write_intprop(context, "componentType", cgltf_int_from_component_type(accessor->sparse.indices_component_type), 0);
 		cgltf_write_intprop(context, "componentType", cgltf_int_from_component_type(accessor->sparse.indices_component_type), 0);
-		cgltf_write_extras(context, &accessor->sparse.indices_extras);
 		cgltf_write_line(context, "}");
 		cgltf_write_line(context, "}");
 		cgltf_write_line(context, "\"values\": {");
 		cgltf_write_line(context, "\"values\": {");
 		cgltf_write_sizeprop(context, "byteOffset", (int)accessor->sparse.values_byte_offset, 0);
 		cgltf_write_sizeprop(context, "byteOffset", (int)accessor->sparse.values_byte_offset, 0);
 		CGLTF_WRITE_IDXPROP("bufferView", accessor->sparse.values_buffer_view, context->data->buffer_views);
 		CGLTF_WRITE_IDXPROP("bufferView", accessor->sparse.values_buffer_view, context->data->buffer_views);
-		cgltf_write_extras(context, &accessor->sparse.values_extras);
 		cgltf_write_line(context, "}");
 		cgltf_write_line(context, "}");
-		cgltf_write_extras(context, &accessor->sparse.extras);
 		cgltf_write_line(context, "}");
 		cgltf_write_line(context, "}");
 	}
 	}
 	cgltf_write_extras(context, &accessor->extras);
 	cgltf_write_extras(context, &accessor->extras);
@@ -1123,6 +1159,7 @@ static void cgltf_write_light(cgltf_write_context* context, const cgltf_light* l
 		cgltf_write_floatprop(context, "outerConeAngle", light->spot_outer_cone_angle, 3.14159265358979323846f/4.0f);
 		cgltf_write_floatprop(context, "outerConeAngle", light->spot_outer_cone_angle, 3.14159265358979323846f/4.0f);
 		cgltf_write_line(context, "}");
 		cgltf_write_line(context, "}");
 	}
 	}
+	cgltf_write_extras( context, &light->extras );
 	cgltf_write_line(context, "}");
 	cgltf_write_line(context, "}");
 }
 }
 
 
@@ -1249,9 +1286,15 @@ static void cgltf_write_extensions(cgltf_write_context* context, uint32_t extens
 	if (extension_flags & CGLTF_EXTENSION_FLAG_MATERIALS_IRIDESCENCE) {
 	if (extension_flags & CGLTF_EXTENSION_FLAG_MATERIALS_IRIDESCENCE) {
 		cgltf_write_stritem(context, "KHR_materials_iridescence");
 		cgltf_write_stritem(context, "KHR_materials_iridescence");
 	}
 	}
+	if (extension_flags & CGLTF_EXTENSION_FLAG_MATERIALS_ANISOTROPY) {
+		cgltf_write_stritem(context, "KHR_materials_anisotropy");
+	}
 	if (extension_flags & CGLTF_EXTENSION_FLAG_MESH_GPU_INSTANCING) {
 	if (extension_flags & CGLTF_EXTENSION_FLAG_MESH_GPU_INSTANCING) {
 		cgltf_write_stritem(context, "EXT_mesh_gpu_instancing");
 		cgltf_write_stritem(context, "EXT_mesh_gpu_instancing");
 	}
 	}
+	if (extension_flags & CGLTF_EXTENSION_FLAG_MATERIALS_DISPERSION) {
+		cgltf_write_stritem(context, "KHR_materials_dispersion");
+	}
 }
 }
 
 
 cgltf_size cgltf_write(const cgltf_options* options, char* buffer, cgltf_size size, const cgltf_data* data)
 cgltf_size cgltf_write(const cgltf_options* options, char* buffer, cgltf_size size, const cgltf_data* data)

+ 2 - 2
vendor/libc/include/math.h

@@ -17,5 +17,5 @@ double fabs(double x);
 int abs(int);
 int abs(int);
 double ldexp(double, int);
 double ldexp(double, int);
 double exp(double);
 double exp(double);
-float log(float);
-float sin(float);
+double log(double);
+double sin(double);

+ 2 - 2
vendor/libc/math.odin

@@ -90,11 +90,11 @@ exp :: proc "c" (x: f64) -> f64 {
 }
 }
 
 
 @(require, linkage="strong", link_name="log")
 @(require, linkage="strong", link_name="log")
-log :: proc "c" (x: f32) -> f32 {
+log :: proc "c" (x: f64) -> f64 {
 	return math.ln(x)
 	return math.ln(x)
 }
 }
 
 
 @(require, linkage="strong", link_name="sin")
 @(require, linkage="strong", link_name="sin")
-sin :: proc "c" (x: f32) -> f32 {
+sin :: proc "c" (x: f64) -> f64 {
 	return math.sin(x)
 	return math.sin(x)
 }
 }

+ 1 - 0
vendor/libc/stdio.odin

@@ -1,3 +1,4 @@
+#+build !freestanding
 package odin_libc
 package odin_libc
 
 
 import "core:c"
 import "core:c"

+ 5 - 0
vendor/raylib/raygui.odin

@@ -3,6 +3,7 @@ package raylib
 import "core:c"
 import "core:c"
 
 
 RAYGUI_SHARED :: #config(RAYGUI_SHARED, false)
 RAYGUI_SHARED :: #config(RAYGUI_SHARED, false)
+RAYGUI_WASM_LIB :: #config(RAYGUI_WASM_LIB, "wasm/libraygui.a")
 
 
 when ODIN_OS == .Windows {
 when ODIN_OS == .Windows {
 	foreign import lib {
 	foreign import lib {
@@ -22,6 +23,10 @@ when ODIN_OS == .Windows {
 			"macos/libraygui.dylib" when RAYGUI_SHARED else "macos/libraygui.a",
 			"macos/libraygui.dylib" when RAYGUI_SHARED else "macos/libraygui.a",
 		}
 		}
 	}
 	}
+} else when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 {
+	foreign import lib {
+		RAYGUI_WASM_LIB,
+	}
 } else {
 } else {
 	foreign import lib "system:raygui"
 	foreign import lib "system:raygui"
 }
 }

+ 5 - 0
vendor/raylib/raylib.odin

@@ -100,6 +100,7 @@ MAX_TEXT_BUFFER_LENGTH :: #config(RAYLIB_MAX_TEXT_BUFFER_LENGTH, 1024)
 #assert(size_of(rune) == size_of(c.int))
 #assert(size_of(rune) == size_of(c.int))
 
 
 RAYLIB_SHARED :: #config(RAYLIB_SHARED, false)
 RAYLIB_SHARED :: #config(RAYLIB_SHARED, false)
+RAYLIB_WASM_LIB :: #config(RAYLIB_WASM_LIB, "wasm/libraylib.a")
 
 
 when ODIN_OS == .Windows {
 when ODIN_OS == .Windows {
 	@(extra_linker_flags="/NODEFAULTLIB:" + ("msvcrt" when RAYLIB_SHARED else "libcmt"))
 	@(extra_linker_flags="/NODEFAULTLIB:" + ("msvcrt" when RAYLIB_SHARED else "libcmt"))
@@ -127,6 +128,10 @@ when ODIN_OS == .Windows {
 		"system:OpenGL.framework",
 		"system:OpenGL.framework",
 		"system:IOKit.framework",
 		"system:IOKit.framework",
 	} 
 	} 
+} else when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 {
+	foreign import lib {
+		RAYLIB_WASM_LIB,
+	}
 } else {
 } else {
 	foreign import lib "system:raylib"
 	foreign import lib "system:raylib"
 }
 }

+ 1 - 1
vendor/raylib/raymath.odin

@@ -523,7 +523,7 @@ Vector3Unproject :: proc "c" (source: Vector3, projection: Matrix, view: Matrix)
 
 
 	quat: Quaternion
 	quat: Quaternion
 	quat.x = source.x
 	quat.x = source.x
-	quat.y = source.z
+	quat.y = source.y
 	quat.z = source.z
 	quat.z = source.z
 	quat.w = 1
 	quat.w = 1
 
 

+ 6 - 1
vendor/raylib/rlgl/rlgl.odin

@@ -113,6 +113,7 @@ import rl "../."
 VERSION :: "5.0"
 VERSION :: "5.0"
 
 
 RAYLIB_SHARED :: #config(RAYLIB_SHARED, false)
 RAYLIB_SHARED :: #config(RAYLIB_SHARED, false)
+RAYLIB_WASM_LIB :: #config(RAYLIB_WASM_LIB, "../wasm/libraylib.a")
 
 
 // Note: We pull in the full raylib library. If you want a truly stand-alone rlgl, then:
 // Note: We pull in the full raylib library. If you want a truly stand-alone rlgl, then:
 // - Compile a separate rlgl library and use that in the foreign import blocks below.
 // - Compile a separate rlgl library and use that in the foreign import blocks below.
@@ -145,6 +146,10 @@ when ODIN_OS == .Windows {
 		"system:OpenGL.framework",
 		"system:OpenGL.framework",
 		"system:IOKit.framework",
 		"system:IOKit.framework",
 	} 
 	} 
+} else when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 {
+	foreign import lib {
+		RAYLIB_WASM_LIB,
+	}
 } else {
 } else {
 	foreign import lib "system:raylib"
 	foreign import lib "system:raylib"
 }
 }
@@ -509,7 +514,7 @@ foreign lib {
 	UpdateVertexBufferElements       :: proc(id: c.uint, data: rawptr, dataSize: c.int, offset: c.int) ---        // Update vertex buffer elements with new data
 	UpdateVertexBufferElements       :: proc(id: c.uint, data: rawptr, dataSize: c.int, offset: c.int) ---        // Update vertex buffer elements with new data
 	UnloadVertexArray                :: proc(vaoId: c.uint) ---
 	UnloadVertexArray                :: proc(vaoId: c.uint) ---
 	UnloadVertexBuffer               :: proc(vboId: c.uint) ---
 	UnloadVertexBuffer               :: proc(vboId: c.uint) ---
-	SetVertexAttribute               :: proc(index: c.uint, compSize: c.int, type: c.int, normalized: bool, stride: c.int, pointer: rawptr) ---
+	SetVertexAttribute               :: proc(index: c.uint, compSize: c.int, type: c.int, normalized: bool, stride: c.int, offset: c.int) ---
 	SetVertexAttributeDivisor        :: proc(index: c.uint, divisor: c.int) ---
 	SetVertexAttributeDivisor        :: proc(index: c.uint, divisor: c.int) ---
 	SetVertexAttributeDefault        :: proc(locIndex: c.int, value: rawptr, attribType: c.int, count: c.int) --- // Set vertex attribute default value
 	SetVertexAttributeDefault        :: proc(locIndex: c.int, value: rawptr, attribType: c.int, count: c.int) --- // Set vertex attribute default value
 	DrawVertexArray                  :: proc(offset: c.int, count: c.int) ---
 	DrawVertexArray                  :: proc(offset: c.int, count: c.int) ---

BIN
vendor/raylib/wasm/libraygui.a


BIN
vendor/raylib/wasm/libraylib.a


+ 34 - 12
vendor/vulkan/_gen/create_vulkan_odin_wrapper.py

@@ -16,6 +16,8 @@ file_and_urls = [
     ("vulkan_macos.h",   'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vulkan/vulkan_macos.h',   False),
     ("vulkan_macos.h",   'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vulkan/vulkan_macos.h',   False),
     ("vulkan_ios.h",     'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vulkan/vulkan_ios.h',     False),
     ("vulkan_ios.h",     'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vulkan/vulkan_ios.h',     False),
     ("vulkan_wayland.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vulkan/vulkan_wayland.h', False),
     ("vulkan_wayland.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vulkan/vulkan_wayland.h', False),
+    ("vulkan_xlib.h",    'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vulkan/vulkan_xlib.h',    False),
+    ("vulkan_xcb.h",     'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vulkan/vulkan_xcb.h',     False),
     # Vulkan Video
     # Vulkan Video
     ("vulkan_video_codec_av1std.h",         'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vk_video/vulkan_video_codec_av1std.h', False),
     ("vulkan_video_codec_av1std.h",         'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vk_video/vulkan_video_codec_av1std.h', False),
     ("vulkan_video_codec_av1std_decode.h",  'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vk_video/vulkan_video_codec_av1std_decode.h', False),
     ("vulkan_video_codec_av1std_decode.h",  'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vk_video/vulkan_video_codec_av1std_decode.h', False),
@@ -46,17 +48,18 @@ def no_vk(t):
     t = t.replace('PFN_', 'Proc')
     t = t.replace('PFN_', 'Proc')
     t = t.replace('PFN_', 'Proc')
     t = t.replace('PFN_', 'Proc')
 
 
-    t = re.sub('(?:Vk|VK_)?(\w+)', '\\1', t)
+    t = re.sub('(?:Vk|VK_)?(\\w+)', '\\1', t)
 
 
     # Vulkan Video
     # Vulkan Video
-    t = re.sub('(?:Std|STD_|VK_STD)?(\w+)', '\\1', t)
+    t = re.sub('(?:Std|STD_|VK_STD)?(\\w+)', '\\1', t)
     return t
     return t
 
 
 OPAQUE_STRUCTS = """
 OPAQUE_STRUCTS = """
-wl_surface   :: struct {} // Opaque struct defined by Wayland
-wl_display   :: struct {} // Opaque struct defined by Wayland
-IOSurfaceRef :: struct {} // Opaque struct defined by Apple’s CoreGraphics framework
-""" 
+wl_surface       :: struct {} // Opaque struct defined by Wayland
+wl_display       :: struct {} // Opaque struct defined by Wayland
+xcb_connection_t :: struct {} // Opaque struct defined by xcb
+IOSurfaceRef     :: struct {} // Opaque struct defined by Apple’s CoreGraphics framework
+"""
 
 
 def convert_type(t, prev_name, curr_name):
 def convert_type(t, prev_name, curr_name):
     table = {
     table = {
@@ -91,6 +94,9 @@ def convert_type(t, prev_name, curr_name):
         "struct BaseInStructure":  "BaseInStructure",
         "struct BaseInStructure":  "BaseInStructure",
         "struct wl_display": "wl_display",
         "struct wl_display": "wl_display",
         "struct wl_surface": "wl_surface",
         "struct wl_surface": "wl_surface",
+        "Display": "XlibDisplay",
+        "Window": "XlibWindow",
+        "VisualID": "XlibVisualID",
         'v': '',
         'v': '',
     }
     }
 
 
@@ -106,7 +112,7 @@ def convert_type(t, prev_name, curr_name):
     elif t.endswith("*"):
     elif t.endswith("*"):
         pointer = "^"
         pointer = "^"
         ttype = t[:len(t)-1]
         ttype = t[:len(t)-1]
-        elem = convert_type(ttype, prev_name, curr_name)    
+        elem = convert_type(ttype, prev_name, curr_name)
 
 
         if curr_name.endswith("s") or curr_name.endswith("Table"):
         if curr_name.endswith("s") or curr_name.endswith("Table"):
             if prev_name.endswith("Count") or prev_name.endswith("Counts"):
             if prev_name.endswith("Count") or prev_name.endswith("Counts"):
@@ -445,7 +451,7 @@ def parse_enums(f):
 
 
 def parse_fake_enums(f):
 def parse_fake_enums(f):
     data = re.findall(r"static const Vk(\w+FlagBits2) VK_(\w+?) = (\w+);", src, re.S)
     data = re.findall(r"static const Vk(\w+FlagBits2) VK_(\w+?) = (\w+);", src, re.S)
-    
+
     data.sort(key=lambda x: x[0])
     data.sort(key=lambda x: x[0])
 
 
     fake_enums = {}
     fake_enums = {}
@@ -507,7 +513,7 @@ def parse_fake_enums(f):
                 continue
                 continue
 
 
             ff.append((n, v))
             ff.append((n, v))
-        
+
         max_flag_value = max([int(v) for n, v in ff if is_int(v)] + [0])
         max_flag_value = max([int(v) for n, v in ff if is_int(v)] + [0])
         max_group_value = max([int(v) for n, v in groups if is_int(v)] + [0])
         max_group_value = max([int(v) for n, v in groups if is_int(v)] + [0])
         if max_flag_value < max_group_value:
         if max_flag_value < max_group_value:
@@ -575,13 +581,13 @@ def parse_structs(f):
                     ffields.append(tuple([bit_field_name, bit_field_type, comment]))
                     ffields.append(tuple([bit_field_name, bit_field_type, comment]))
                     prev_name = ""
                     prev_name = ""
                     continue
                     continue
-                
+
                 # The second way has many fields that are each 1 bit
                 # The second way has many fields that are each 1 bit
                 elif int(fname) == 1:
                 elif int(fname) == 1:
                     bit_field_type = do_type(bit_field[0], prev_name, fname)
                     bit_field_type = do_type(bit_field[0], prev_name, fname)
                     ffields.append(tuple(["bitfield", bit_field_type, comment]))
                     ffields.append(tuple(["bitfield", bit_field_type, comment]))
                     break
                     break
-                    
+
 
 
 
 
             if '[' in fname:
             if '[' in fname:
@@ -894,6 +900,10 @@ import "core:c"
 
 
 import win32 "core:sys/windows"
 import win32 "core:sys/windows"
 _ :: win32
 _ :: win32
+
+import "vendor:x11/xlib"
+_ :: xlib
+
 when ODIN_OS == .Windows {
 when ODIN_OS == .Windows {
 \tHINSTANCE           :: win32.HINSTANCE
 \tHINSTANCE           :: win32.HINSTANCE
 \tHWND                :: win32.HWND
 \tHWND                :: win32.HWND
@@ -919,7 +929,19 @@ when ODIN_OS == .Windows {
 \t}
 \t}
 }
 }
 
 
-CAMetalLayer :: struct {}
+when xlib.IS_SUPPORTED {
+\tXlibDisplay  :: xlib.Display
+\tXlibWindow   :: xlib.Window
+\tXlibVisualID :: xlib.VisualID
+} else {
+\tXlibDisplay  :: struct {} // Opaque struct defined by Xlib
+\tXlibWindow   :: c.ulong
+\tXlibVisualID :: c.ulong
+}
+
+xcb_visualid_t :: u32
+xcb_window_t   :: u32
+CAMetalLayer   :: struct {}
 
 
 MTLBuffer_id       :: rawptr
 MTLBuffer_id       :: rawptr
 MTLTexture_id      :: rawptr
 MTLTexture_id      :: rawptr

+ 56 - 0
vendor/vulkan/_gen/vulkan_xcb.h

@@ -0,0 +1,56 @@
+#ifndef VULKAN_XCB_H_
+#define VULKAN_XCB_H_ 1
+
+/*
+** Copyright 2015-2024 The Khronos Group Inc.
+**
+** SPDX-License-Identifier: Apache-2.0
+*/
+
+/*
+** This header is generated from the Khronos Vulkan XML API Registry.
+**
+*/
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+// VK_KHR_xcb_surface is a preprocessor guard. Do not pass it to API calls.
+#define VK_KHR_xcb_surface 1
+#define VK_KHR_XCB_SURFACE_SPEC_VERSION   6
+#define VK_KHR_XCB_SURFACE_EXTENSION_NAME "VK_KHR_xcb_surface"
+typedef VkFlags VkXcbSurfaceCreateFlagsKHR;
+typedef struct VkXcbSurfaceCreateInfoKHR {
+    VkStructureType               sType;
+    const void*                   pNext;
+    VkXcbSurfaceCreateFlagsKHR    flags;
+    xcb_connection_t*             connection;
+    xcb_window_t                  window;
+} VkXcbSurfaceCreateInfoKHR;
+
+typedef VkResult (VKAPI_PTR *PFN_vkCreateXcbSurfaceKHR)(VkInstance instance, const VkXcbSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);
+typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, xcb_connection_t* connection, xcb_visualid_t visual_id);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateXcbSurfaceKHR(
+    VkInstance                                  instance,
+    const VkXcbSurfaceCreateInfoKHR*            pCreateInfo,
+    const VkAllocationCallbacks*                pAllocator,
+    VkSurfaceKHR*                               pSurface);
+
+VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceXcbPresentationSupportKHR(
+    VkPhysicalDevice                            physicalDevice,
+    uint32_t                                    queueFamilyIndex,
+    xcb_connection_t*                           connection,
+    xcb_visualid_t                              visual_id);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 56 - 0
vendor/vulkan/_gen/vulkan_xlib.h

@@ -0,0 +1,56 @@
+#ifndef VULKAN_XLIB_H_
+#define VULKAN_XLIB_H_ 1
+
+/*
+** Copyright 2015-2024 The Khronos Group Inc.
+**
+** SPDX-License-Identifier: Apache-2.0
+*/
+
+/*
+** This header is generated from the Khronos Vulkan XML API Registry.
+**
+*/
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+// VK_KHR_xlib_surface is a preprocessor guard. Do not pass it to API calls.
+#define VK_KHR_xlib_surface 1
+#define VK_KHR_XLIB_SURFACE_SPEC_VERSION  6
+#define VK_KHR_XLIB_SURFACE_EXTENSION_NAME "VK_KHR_xlib_surface"
+typedef VkFlags VkXlibSurfaceCreateFlagsKHR;
+typedef struct VkXlibSurfaceCreateInfoKHR {
+    VkStructureType                sType;
+    const void*                    pNext;
+    VkXlibSurfaceCreateFlagsKHR    flags;
+    Display*                       dpy;
+    Window                         window;
+} VkXlibSurfaceCreateInfoKHR;
+
+typedef VkResult (VKAPI_PTR *PFN_vkCreateXlibSurfaceKHR)(VkInstance instance, const VkXlibSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);
+typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, Display* dpy, VisualID visualID);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateXlibSurfaceKHR(
+    VkInstance                                  instance,
+    const VkXlibSurfaceCreateInfoKHR*           pCreateInfo,
+    const VkAllocationCallbacks*                pAllocator,
+    VkSurfaceKHR*                               pSurface);
+
+VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceXlibPresentationSupportKHR(
+    VkPhysicalDevice                            physicalDevice,
+    uint32_t                                    queueFamilyIndex,
+    Display*                                    dpy,
+    VisualID                                    visualID);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 6 - 0
vendor/vulkan/core.odin

@@ -1161,6 +1161,12 @@ EXT_METAL_OBJECTS_EXTENSION_NAME                          :: "VK_EXT_metal_objec
 KHR_wayland_surface                                       :: 1
 KHR_wayland_surface                                       :: 1
 KHR_WAYLAND_SURFACE_SPEC_VERSION                          :: 6
 KHR_WAYLAND_SURFACE_SPEC_VERSION                          :: 6
 KHR_WAYLAND_SURFACE_EXTENSION_NAME                        :: "VK_KHR_wayland_surface"
 KHR_WAYLAND_SURFACE_EXTENSION_NAME                        :: "VK_KHR_wayland_surface"
+KHR_xlib_surface                                          :: 1
+KHR_XLIB_SURFACE_SPEC_VERSION                             :: 6
+KHR_XLIB_SURFACE_EXTENSION_NAME                           :: "VK_KHR_xlib_surface"
+KHR_xcb_surface                                           :: 1
+KHR_XCB_SURFACE_SPEC_VERSION                              :: 6
+KHR_XCB_SURFACE_EXTENSION_NAME                            :: "VK_KHR_xcb_surface"
 
 
 // Handles types
 // Handles types
 Instance       :: distinct Handle
 Instance       :: distinct Handle

+ 4 - 0
vendor/vulkan/enums.odin

@@ -4585,6 +4585,10 @@ WaylandSurfaceCreateFlagsKHR                         :: distinct bit_set[Wayland
 WaylandSurfaceCreateFlagKHR                          :: enum u32 {}
 WaylandSurfaceCreateFlagKHR                          :: enum u32 {}
 Win32SurfaceCreateFlagsKHR                           :: distinct bit_set[Win32SurfaceCreateFlagKHR; Flags]
 Win32SurfaceCreateFlagsKHR                           :: distinct bit_set[Win32SurfaceCreateFlagKHR; Flags]
 Win32SurfaceCreateFlagKHR                            :: enum u32 {}
 Win32SurfaceCreateFlagKHR                            :: enum u32 {}
+XcbSurfaceCreateFlagsKHR                             :: distinct bit_set[XcbSurfaceCreateFlagKHR; Flags]
+XcbSurfaceCreateFlagKHR                              :: enum u32 {}
+XlibSurfaceCreateFlagsKHR                            :: distinct bit_set[XlibSurfaceCreateFlagKHR; Flags]
+XlibSurfaceCreateFlagKHR                             :: enum u32 {}
 AccessFlags2 :: distinct bit_set[AccessFlag2; Flags64]
 AccessFlags2 :: distinct bit_set[AccessFlag2; Flags64]
 AccessFlag2 :: enum Flags64 {
 AccessFlag2 :: enum Flags64 {
 	INDIRECT_COMMAND_READ                     = 0,
 	INDIRECT_COMMAND_READ                     = 0,

+ 16 - 0
vendor/vulkan/procedures.odin

@@ -36,6 +36,8 @@ ProcCreateMacOSSurfaceMVK                                            :: #type pr
 ProcCreateMetalSurfaceEXT                                            :: #type proc "system" (instance: Instance, pCreateInfo: ^MetalSurfaceCreateInfoEXT, pAllocator: ^AllocationCallbacks, pSurface: ^SurfaceKHR) -> Result
 ProcCreateMetalSurfaceEXT                                            :: #type proc "system" (instance: Instance, pCreateInfo: ^MetalSurfaceCreateInfoEXT, pAllocator: ^AllocationCallbacks, pSurface: ^SurfaceKHR) -> Result
 ProcCreateWaylandSurfaceKHR                                          :: #type proc "system" (instance: Instance, pCreateInfo: ^WaylandSurfaceCreateInfoKHR, pAllocator: ^AllocationCallbacks, pSurface: ^SurfaceKHR) -> Result
 ProcCreateWaylandSurfaceKHR                                          :: #type proc "system" (instance: Instance, pCreateInfo: ^WaylandSurfaceCreateInfoKHR, pAllocator: ^AllocationCallbacks, pSurface: ^SurfaceKHR) -> Result
 ProcCreateWin32SurfaceKHR                                            :: #type proc "system" (instance: Instance, pCreateInfo: ^Win32SurfaceCreateInfoKHR, pAllocator: ^AllocationCallbacks, pSurface: ^SurfaceKHR) -> Result
 ProcCreateWin32SurfaceKHR                                            :: #type proc "system" (instance: Instance, pCreateInfo: ^Win32SurfaceCreateInfoKHR, pAllocator: ^AllocationCallbacks, pSurface: ^SurfaceKHR) -> Result
+ProcCreateXcbSurfaceKHR                                              :: #type proc "system" (instance: Instance, pCreateInfo: ^XcbSurfaceCreateInfoKHR, pAllocator: ^AllocationCallbacks, pSurface: ^SurfaceKHR) -> Result
+ProcCreateXlibSurfaceKHR                                             :: #type proc "system" (instance: Instance, pCreateInfo: ^XlibSurfaceCreateInfoKHR, pAllocator: ^AllocationCallbacks, pSurface: ^SurfaceKHR) -> Result
 ProcDebugReportMessageEXT                                            :: #type proc "system" (instance: Instance, flags: DebugReportFlagsEXT, objectType: DebugReportObjectTypeEXT, object: u64, location: int, messageCode: i32, pLayerPrefix: cstring, pMessage: cstring)
 ProcDebugReportMessageEXT                                            :: #type proc "system" (instance: Instance, flags: DebugReportFlagsEXT, objectType: DebugReportObjectTypeEXT, object: u64, location: int, messageCode: i32, pLayerPrefix: cstring, pMessage: cstring)
 ProcDestroyDebugReportCallbackEXT                                    :: #type proc "system" (instance: Instance, callback: DebugReportCallbackEXT, pAllocator: ^AllocationCallbacks)
 ProcDestroyDebugReportCallbackEXT                                    :: #type proc "system" (instance: Instance, callback: DebugReportCallbackEXT, pAllocator: ^AllocationCallbacks)
 ProcDestroyDebugUtilsMessengerEXT                                    :: #type proc "system" (instance: Instance, messenger: DebugUtilsMessengerEXT, pAllocator: ^AllocationCallbacks)
 ProcDestroyDebugUtilsMessengerEXT                                    :: #type proc "system" (instance: Instance, messenger: DebugUtilsMessengerEXT, pAllocator: ^AllocationCallbacks)
@@ -113,6 +115,8 @@ ProcGetPhysicalDeviceVideoEncodeQualityLevelPropertiesKHR            :: #type pr
 ProcGetPhysicalDeviceVideoFormatPropertiesKHR                        :: #type proc "system" (physicalDevice: PhysicalDevice, pVideoFormatInfo: ^PhysicalDeviceVideoFormatInfoKHR, pVideoFormatPropertyCount: ^u32, pVideoFormatProperties: [^]VideoFormatPropertiesKHR) -> Result
 ProcGetPhysicalDeviceVideoFormatPropertiesKHR                        :: #type proc "system" (physicalDevice: PhysicalDevice, pVideoFormatInfo: ^PhysicalDeviceVideoFormatInfoKHR, pVideoFormatPropertyCount: ^u32, pVideoFormatProperties: [^]VideoFormatPropertiesKHR) -> Result
 ProcGetPhysicalDeviceWaylandPresentationSupportKHR                   :: #type proc "system" (physicalDevice: PhysicalDevice, queueFamilyIndex: u32, display: ^wl_display) -> b32
 ProcGetPhysicalDeviceWaylandPresentationSupportKHR                   :: #type proc "system" (physicalDevice: PhysicalDevice, queueFamilyIndex: u32, display: ^wl_display) -> b32
 ProcGetPhysicalDeviceWin32PresentationSupportKHR                     :: #type proc "system" (physicalDevice: PhysicalDevice, queueFamilyIndex: u32) -> b32
 ProcGetPhysicalDeviceWin32PresentationSupportKHR                     :: #type proc "system" (physicalDevice: PhysicalDevice, queueFamilyIndex: u32) -> b32
+ProcGetPhysicalDeviceXcbPresentationSupportKHR                       :: #type proc "system" (physicalDevice: PhysicalDevice, queueFamilyIndex: u32, connection: ^xcb_connection_t, visual_id: xcb_visualid_t) -> b32
+ProcGetPhysicalDeviceXlibPresentationSupportKHR                      :: #type proc "system" (physicalDevice: PhysicalDevice, queueFamilyIndex: u32, dpy: ^XlibDisplay, visualID: XlibVisualID) -> b32
 ProcGetWinrtDisplayNV                                                :: #type proc "system" (physicalDevice: PhysicalDevice, deviceRelativeId: u32, pDisplay: ^DisplayKHR) -> Result
 ProcGetWinrtDisplayNV                                                :: #type proc "system" (physicalDevice: PhysicalDevice, deviceRelativeId: u32, pDisplay: ^DisplayKHR) -> Result
 ProcReleaseDisplayEXT                                                :: #type proc "system" (physicalDevice: PhysicalDevice, display: DisplayKHR) -> Result
 ProcReleaseDisplayEXT                                                :: #type proc "system" (physicalDevice: PhysicalDevice, display: DisplayKHR) -> Result
 ProcSubmitDebugUtilsMessageEXT                                       :: #type proc "system" (instance: Instance, messageSeverity: DebugUtilsMessageSeverityFlagsEXT, messageTypes: DebugUtilsMessageTypeFlagsEXT, pCallbackData: ^DebugUtilsMessengerCallbackDataEXT)
 ProcSubmitDebugUtilsMessageEXT                                       :: #type proc "system" (instance: Instance, messageSeverity: DebugUtilsMessageSeverityFlagsEXT, messageTypes: DebugUtilsMessageTypeFlagsEXT, pCallbackData: ^DebugUtilsMessengerCallbackDataEXT)
@@ -730,6 +734,8 @@ CreateMacOSSurfaceMVK:                                            ProcCreateMacO
 CreateMetalSurfaceEXT:                                            ProcCreateMetalSurfaceEXT
 CreateMetalSurfaceEXT:                                            ProcCreateMetalSurfaceEXT
 CreateWaylandSurfaceKHR:                                          ProcCreateWaylandSurfaceKHR
 CreateWaylandSurfaceKHR:                                          ProcCreateWaylandSurfaceKHR
 CreateWin32SurfaceKHR:                                            ProcCreateWin32SurfaceKHR
 CreateWin32SurfaceKHR:                                            ProcCreateWin32SurfaceKHR
+CreateXcbSurfaceKHR:                                              ProcCreateXcbSurfaceKHR
+CreateXlibSurfaceKHR:                                             ProcCreateXlibSurfaceKHR
 DebugReportMessageEXT:                                            ProcDebugReportMessageEXT
 DebugReportMessageEXT:                                            ProcDebugReportMessageEXT
 DestroyDebugReportCallbackEXT:                                    ProcDestroyDebugReportCallbackEXT
 DestroyDebugReportCallbackEXT:                                    ProcDestroyDebugReportCallbackEXT
 DestroyDebugUtilsMessengerEXT:                                    ProcDestroyDebugUtilsMessengerEXT
 DestroyDebugUtilsMessengerEXT:                                    ProcDestroyDebugUtilsMessengerEXT
@@ -806,6 +812,8 @@ GetPhysicalDeviceVideoEncodeQualityLevelPropertiesKHR:            ProcGetPhysica
 GetPhysicalDeviceVideoFormatPropertiesKHR:                        ProcGetPhysicalDeviceVideoFormatPropertiesKHR
 GetPhysicalDeviceVideoFormatPropertiesKHR:                        ProcGetPhysicalDeviceVideoFormatPropertiesKHR
 GetPhysicalDeviceWaylandPresentationSupportKHR:                   ProcGetPhysicalDeviceWaylandPresentationSupportKHR
 GetPhysicalDeviceWaylandPresentationSupportKHR:                   ProcGetPhysicalDeviceWaylandPresentationSupportKHR
 GetPhysicalDeviceWin32PresentationSupportKHR:                     ProcGetPhysicalDeviceWin32PresentationSupportKHR
 GetPhysicalDeviceWin32PresentationSupportKHR:                     ProcGetPhysicalDeviceWin32PresentationSupportKHR
+GetPhysicalDeviceXcbPresentationSupportKHR:                       ProcGetPhysicalDeviceXcbPresentationSupportKHR
+GetPhysicalDeviceXlibPresentationSupportKHR:                      ProcGetPhysicalDeviceXlibPresentationSupportKHR
 GetWinrtDisplayNV:                                                ProcGetWinrtDisplayNV
 GetWinrtDisplayNV:                                                ProcGetWinrtDisplayNV
 ReleaseDisplayEXT:                                                ProcReleaseDisplayEXT
 ReleaseDisplayEXT:                                                ProcReleaseDisplayEXT
 SubmitDebugUtilsMessageEXT:                                       ProcSubmitDebugUtilsMessageEXT
 SubmitDebugUtilsMessageEXT:                                       ProcSubmitDebugUtilsMessageEXT
@@ -1423,6 +1431,8 @@ load_proc_addresses_custom :: proc(set_proc_address: SetProcAddressType) {
 	set_proc_address(&CreateMetalSurfaceEXT,                                            "vkCreateMetalSurfaceEXT")
 	set_proc_address(&CreateMetalSurfaceEXT,                                            "vkCreateMetalSurfaceEXT")
 	set_proc_address(&CreateWaylandSurfaceKHR,                                          "vkCreateWaylandSurfaceKHR")
 	set_proc_address(&CreateWaylandSurfaceKHR,                                          "vkCreateWaylandSurfaceKHR")
 	set_proc_address(&CreateWin32SurfaceKHR,                                            "vkCreateWin32SurfaceKHR")
 	set_proc_address(&CreateWin32SurfaceKHR,                                            "vkCreateWin32SurfaceKHR")
+	set_proc_address(&CreateXcbSurfaceKHR,                                              "vkCreateXcbSurfaceKHR")
+	set_proc_address(&CreateXlibSurfaceKHR,                                             "vkCreateXlibSurfaceKHR")
 	set_proc_address(&DebugReportMessageEXT,                                            "vkDebugReportMessageEXT")
 	set_proc_address(&DebugReportMessageEXT,                                            "vkDebugReportMessageEXT")
 	set_proc_address(&DestroyDebugReportCallbackEXT,                                    "vkDestroyDebugReportCallbackEXT")
 	set_proc_address(&DestroyDebugReportCallbackEXT,                                    "vkDestroyDebugReportCallbackEXT")
 	set_proc_address(&DestroyDebugUtilsMessengerEXT,                                    "vkDestroyDebugUtilsMessengerEXT")
 	set_proc_address(&DestroyDebugUtilsMessengerEXT,                                    "vkDestroyDebugUtilsMessengerEXT")
@@ -1499,6 +1509,8 @@ load_proc_addresses_custom :: proc(set_proc_address: SetProcAddressType) {
 	set_proc_address(&GetPhysicalDeviceVideoFormatPropertiesKHR,                        "vkGetPhysicalDeviceVideoFormatPropertiesKHR")
 	set_proc_address(&GetPhysicalDeviceVideoFormatPropertiesKHR,                        "vkGetPhysicalDeviceVideoFormatPropertiesKHR")
 	set_proc_address(&GetPhysicalDeviceWaylandPresentationSupportKHR,                   "vkGetPhysicalDeviceWaylandPresentationSupportKHR")
 	set_proc_address(&GetPhysicalDeviceWaylandPresentationSupportKHR,                   "vkGetPhysicalDeviceWaylandPresentationSupportKHR")
 	set_proc_address(&GetPhysicalDeviceWin32PresentationSupportKHR,                     "vkGetPhysicalDeviceWin32PresentationSupportKHR")
 	set_proc_address(&GetPhysicalDeviceWin32PresentationSupportKHR,                     "vkGetPhysicalDeviceWin32PresentationSupportKHR")
+	set_proc_address(&GetPhysicalDeviceXcbPresentationSupportKHR,                       "vkGetPhysicalDeviceXcbPresentationSupportKHR")
+	set_proc_address(&GetPhysicalDeviceXlibPresentationSupportKHR,                      "vkGetPhysicalDeviceXlibPresentationSupportKHR")
 	set_proc_address(&GetWinrtDisplayNV,                                                "vkGetWinrtDisplayNV")
 	set_proc_address(&GetWinrtDisplayNV,                                                "vkGetWinrtDisplayNV")
 	set_proc_address(&ReleaseDisplayEXT,                                                "vkReleaseDisplayEXT")
 	set_proc_address(&ReleaseDisplayEXT,                                                "vkReleaseDisplayEXT")
 	set_proc_address(&SubmitDebugUtilsMessageEXT,                                       "vkSubmitDebugUtilsMessageEXT")
 	set_proc_address(&SubmitDebugUtilsMessageEXT,                                       "vkSubmitDebugUtilsMessageEXT")
@@ -3879,6 +3891,8 @@ load_proc_addresses_instance :: proc(instance: Instance) {
 	CreateMetalSurfaceEXT                                            = auto_cast GetInstanceProcAddr(instance, "vkCreateMetalSurfaceEXT")
 	CreateMetalSurfaceEXT                                            = auto_cast GetInstanceProcAddr(instance, "vkCreateMetalSurfaceEXT")
 	CreateWaylandSurfaceKHR                                          = auto_cast GetInstanceProcAddr(instance, "vkCreateWaylandSurfaceKHR")
 	CreateWaylandSurfaceKHR                                          = auto_cast GetInstanceProcAddr(instance, "vkCreateWaylandSurfaceKHR")
 	CreateWin32SurfaceKHR                                            = auto_cast GetInstanceProcAddr(instance, "vkCreateWin32SurfaceKHR")
 	CreateWin32SurfaceKHR                                            = auto_cast GetInstanceProcAddr(instance, "vkCreateWin32SurfaceKHR")
+	CreateXcbSurfaceKHR                                              = auto_cast GetInstanceProcAddr(instance, "vkCreateXcbSurfaceKHR")
+	CreateXlibSurfaceKHR                                             = auto_cast GetInstanceProcAddr(instance, "vkCreateXlibSurfaceKHR")
 	DebugReportMessageEXT                                            = auto_cast GetInstanceProcAddr(instance, "vkDebugReportMessageEXT")
 	DebugReportMessageEXT                                            = auto_cast GetInstanceProcAddr(instance, "vkDebugReportMessageEXT")
 	DestroyDebugReportCallbackEXT                                    = auto_cast GetInstanceProcAddr(instance, "vkDestroyDebugReportCallbackEXT")
 	DestroyDebugReportCallbackEXT                                    = auto_cast GetInstanceProcAddr(instance, "vkDestroyDebugReportCallbackEXT")
 	DestroyDebugUtilsMessengerEXT                                    = auto_cast GetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT")
 	DestroyDebugUtilsMessengerEXT                                    = auto_cast GetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT")
@@ -3955,6 +3969,8 @@ load_proc_addresses_instance :: proc(instance: Instance) {
 	GetPhysicalDeviceVideoFormatPropertiesKHR                        = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceVideoFormatPropertiesKHR")
 	GetPhysicalDeviceVideoFormatPropertiesKHR                        = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceVideoFormatPropertiesKHR")
 	GetPhysicalDeviceWaylandPresentationSupportKHR                   = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceWaylandPresentationSupportKHR")
 	GetPhysicalDeviceWaylandPresentationSupportKHR                   = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceWaylandPresentationSupportKHR")
 	GetPhysicalDeviceWin32PresentationSupportKHR                     = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceWin32PresentationSupportKHR")
 	GetPhysicalDeviceWin32PresentationSupportKHR                     = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceWin32PresentationSupportKHR")
+	GetPhysicalDeviceXcbPresentationSupportKHR                       = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceXcbPresentationSupportKHR")
+	GetPhysicalDeviceXlibPresentationSupportKHR                      = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceXlibPresentationSupportKHR")
 	GetWinrtDisplayNV                                                = auto_cast GetInstanceProcAddr(instance, "vkGetWinrtDisplayNV")
 	GetWinrtDisplayNV                                                = auto_cast GetInstanceProcAddr(instance, "vkGetWinrtDisplayNV")
 	ReleaseDisplayEXT                                                = auto_cast GetInstanceProcAddr(instance, "vkReleaseDisplayEXT")
 	ReleaseDisplayEXT                                                = auto_cast GetInstanceProcAddr(instance, "vkReleaseDisplayEXT")
 	SubmitDebugUtilsMessageEXT                                       = auto_cast GetInstanceProcAddr(instance, "vkSubmitDebugUtilsMessageEXT")
 	SubmitDebugUtilsMessageEXT                                       = auto_cast GetInstanceProcAddr(instance, "vkSubmitDebugUtilsMessageEXT")

+ 37 - 4
vendor/vulkan/structs.odin

@@ -7,6 +7,10 @@ import "core:c"
 
 
 import win32 "core:sys/windows"
 import win32 "core:sys/windows"
 _ :: win32
 _ :: win32
+
+import "vendor:x11/xlib"
+_ :: xlib
+
 when ODIN_OS == .Windows {
 when ODIN_OS == .Windows {
 	HINSTANCE           :: win32.HINSTANCE
 	HINSTANCE           :: win32.HINSTANCE
 	HWND                :: win32.HWND
 	HWND                :: win32.HWND
@@ -32,7 +36,19 @@ when ODIN_OS == .Windows {
 	}
 	}
 }
 }
 
 
-CAMetalLayer :: struct {}
+when xlib.IS_SUPPORTED {
+	XlibDisplay  :: xlib.Display
+	XlibWindow   :: xlib.Window
+	XlibVisualID :: xlib.VisualID
+} else {
+	XlibDisplay  :: struct {} // Opaque struct defined by Xlib
+	XlibWindow   :: c.ulong
+	XlibVisualID :: c.ulong
+}
+
+xcb_visualid_t :: u32
+xcb_window_t   :: u32
+CAMetalLayer   :: struct {}
 
 
 MTLBuffer_id       :: rawptr
 MTLBuffer_id       :: rawptr
 MTLTexture_id      :: rawptr
 MTLTexture_id      :: rawptr
@@ -8910,6 +8926,22 @@ WaylandSurfaceCreateInfoKHR :: struct {
 	surface: ^wl_surface,
 	surface: ^wl_surface,
 }
 }
 
 
+XlibSurfaceCreateInfoKHR :: struct {
+	sType:  StructureType,
+	pNext:  rawptr,
+	flags:  XlibSurfaceCreateFlagsKHR,
+	dpy:    ^XlibDisplay,
+	window: XlibWindow,
+}
+
+XcbSurfaceCreateInfoKHR :: struct {
+	sType:      StructureType,
+	pNext:      rawptr,
+	flags:      XcbSurfaceCreateFlagsKHR,
+	connection: ^xcb_connection_t,
+	window:     xcb_window_t,
+}
+
 VideoAV1ColorConfigFlags :: struct {
 VideoAV1ColorConfigFlags :: struct {
 	bitfield: u32,
 	bitfield: u32,
 }
 }
@@ -9753,9 +9785,10 @@ VideoEncodeH265ReferenceInfo :: struct {
 
 
 // Opaque structs
 // Opaque structs
 
 
-wl_surface   :: struct {} // Opaque struct defined by Wayland
-wl_display   :: struct {} // Opaque struct defined by Wayland
-IOSurfaceRef :: struct {} // Opaque struct defined by Apple’s CoreGraphics framework
+wl_surface       :: struct {} // Opaque struct defined by Wayland
+wl_display       :: struct {} // Opaque struct defined by Wayland
+xcb_connection_t :: struct {} // Opaque struct defined by xcb
+IOSurfaceRef     :: struct {} // Opaque struct defined by Apple’s CoreGraphics framework
 // Aliases
 // Aliases
 PhysicalDeviceVariablePointerFeatures                       :: PhysicalDeviceVariablePointersFeatures
 PhysicalDeviceVariablePointerFeatures                       :: PhysicalDeviceVariablePointersFeatures
 PhysicalDeviceShaderDrawParameterFeatures                   :: PhysicalDeviceShaderDrawParametersFeatures
 PhysicalDeviceShaderDrawParameterFeatures                   :: PhysicalDeviceShaderDrawParametersFeatures

+ 4 - 0
vendor/x11/xlib/xlib.odin

@@ -0,0 +1,4 @@
+package xlib
+
+// Value, specifying whether `vendor:x11/xlib` is available on the current platform.
+IS_SUPPORTED :: ODIN_OS == .Linux || ODIN_OS == .FreeBSD || ODIN_OS == .OpenBSD

Some files were not shown because too many files changed in this diff