Parcourir la source

Merge branch 'master' into windows-llvm-13.0.0

gingerBill il y a 2 ans
Parent
commit
2fa0c99080
53 fichiers modifiés avec 1227 ajouts et 708 suppressions
  1. 8 0
      .github/workflows/ci.yml
  2. 8 0
      build_odin.sh
  3. 15 2
      core/c/libc/errno.odin
  4. 3 3
      core/fmt/fmt_os.odin
  5. 9 0
      core/math/rand/rand.odin
  6. 331 0
      core/mem/virtual/arena.odin
  7. 0 41
      core/mem/virtual/arena_util.odin
  8. 0 170
      core/mem/virtual/growing_arena.odin
  9. 0 153
      core/mem/virtual/static_arena.odin
  10. 18 15
      core/mem/virtual/virtual.odin
  11. 0 26
      core/mem/virtual/virtual_platform.odin
  12. 1 4
      core/os/dir_windows.odin
  13. 1 1
      core/os/os2/file_windows.odin
  14. 10 10
      core/os/stat_windows.odin
  15. 1 1
      core/runtime/procs_darwin.odin
  16. 3 2
      core/slice/sort_private.odin
  17. 8 1
      core/strconv/strconv.odin
  18. 30 0
      core/sys/windows/advapi32.odin
  19. 9 0
      core/sys/windows/comctl32.odin
  20. 1 0
      core/sys/windows/gdi32.odin
  21. 18 0
      core/sys/windows/kernel32.odin
  22. 6 0
      core/sys/windows/shell32.odin
  23. 1 0
      core/sys/windows/shlwapi.odin
  24. 279 4
      core/sys/windows/types.odin
  25. 1 0
      core/sys/windows/user32.odin
  26. 4 4
      core/sys/windows/util.odin
  27. 3 0
      core/sys/windows/window_messages.odin
  28. 34 32
      core/time/time.odin
  29. 10 3
      core/time/time_windows.odin
  30. 1 1
      src/big_int.cpp
  31. 2 2
      src/check_builtin.cpp
  32. 5 0
      src/check_decl.cpp
  33. 64 16
      src/check_expr.cpp
  34. 5 1
      src/check_stmt.cpp
  35. 18 18
      src/llvm_abi.cpp
  36. 1 0
      src/llvm_backend_debug.cpp
  37. 14 0
      src/llvm_backend_proc.cpp
  38. 12 4
      tests/issues/run.bat
  39. 8 5
      tests/issues/run.sh
  40. 5 1
      tests/issues/test_issue_2087.odin
  41. 13 0
      tests/issues/test_issue_2113.odin
  42. 3 3
      vendor/darwin/Foundation/NSApplication.odin
  43. 16 0
      vendor/darwin/Foundation/NSWindow.odin
  44. 5 1
      vendor/darwin/Foundation/objc.odin
  45. 183 141
      vendor/directx/d3d11/d3d11.odin
  46. 1 0
      vendor/glfw/bindings/bindings.odin
  47. 3 0
      vendor/glfw/constants.odin
  48. 0 33
      vendor/glfw/native.odin
  49. 16 0
      vendor/glfw/native_darwin.odin
  50. 15 0
      vendor/glfw/native_linux.odin
  51. 15 0
      vendor/glfw/native_windows.odin
  52. 7 7
      vendor/vulkan/_gen/create_vulkan_odin_wrapper.py
  53. 3 3
      vendor/vulkan/procedures.odin

+ 8 - 0
.github/workflows/ci.yml

@@ -38,6 +38,10 @@ jobs:
           cd tests/vendor
           make
         timeout-minutes: 10
+      - name: Odin issues tests
+        run: |
+          cd tests/issues
+          ./run.sh
       - name: Odin check examples/all for Linux i386
         run: ./odin check examples/all -vet -strict-style -target:linux_i386
         timeout-minutes: 10
@@ -151,6 +155,10 @@ jobs:
           cd tests\vendor
           call build.bat
         timeout-minutes: 10
+      - name: Odin issues tests
+        run: |
+          cd tests/issues
+          ./run.bat
       - name: core:math/big tests
         shell: cmd
         run: |

+ 8 - 0
build_odin.sh

@@ -134,6 +134,14 @@ run_demo() {
 	./odin run examples/demo/demo.odin -file
 }
 
+have_which() {
+	if ! which which > /dev/null 2>&1; then
+		panic "Could not find \`which\`"
+	fi
+}
+
+have_which
+
 case $OS in
 Linux)
 	config_linux

+ 15 - 2
core/c/libc/errno.odin

@@ -14,11 +14,24 @@ when ODIN_OS == .Windows {
 //	EDOM,
 //	EILSEQ
 //	ERANGE
-when ODIN_OS == .Linux || ODIN_OS == .FreeBSD {
+when ODIN_OS == .Linux {
 	@(private="file")
 	@(default_calling_convention="c")
 	foreign libc {
-		@(link_name="__libc_errno_location")
+		@(link_name="__errno_location")
+		_get_errno :: proc() -> ^int ---
+	}
+
+	EDOM   :: 33
+	EILSEQ :: 84
+	ERANGE :: 34
+}
+
+when ODIN_OS == .FreeBSD {
+	@(private="file")
+	@(default_calling_convention="c")
+	foreign libc {
+		@(link_name="__error")
 		_get_errno :: proc() -> ^int ---
 	}
 

+ 3 - 3
core/fmt/fmt_os.odin

@@ -16,7 +16,7 @@ fprintln :: proc(fd: os.Handle, args: ..any, sep := " ") -> int {
 	w := io.to_writer(os.stream_from_handle(fd))
 	return wprintln(w=w, args=args, sep=sep)
 }
-// fprintf formats according to the specififed format string and writes to fd
+// fprintf formats according to the specified format string and writes to fd
 fprintf :: proc(fd: os.Handle, fmt: string, args: ..any) -> int {
 	w := io.to_writer(os.stream_from_handle(fd))
 	return wprintf(w, fmt, ..args)
@@ -34,12 +34,12 @@ fprint_typeid :: proc(fd: os.Handle, id: typeid) -> (n: int, err: io.Error) {
 print   :: proc(args: ..any, sep := " ") -> int { return fprint(fd=os.stdout, args=args, sep=sep) }
 // println formats using the default print settings and writes to os.stdout
 println :: proc(args: ..any, sep := " ") -> int { return fprintln(fd=os.stdout, args=args, sep=sep) }
-// printf formats according to the specififed format string and writes to os.stdout
+// printf formats according to the specified format string and writes to os.stdout
 printf  :: proc(fmt: string, args: ..any) -> int { return fprintf(os.stdout, fmt, ..args) }
 
 // eprint formats using the default print settings and writes to os.stderr
 eprint   :: proc(args: ..any, sep := " ") -> int { return fprint(fd=os.stderr, args=args, sep=sep) }
 // eprintln formats using the default print settings and writes to os.stderr
 eprintln :: proc(args: ..any, sep := " ") -> int { return fprintln(fd=os.stderr, args=args, sep=sep) }
-// eprintf formats according to the specififed format string and writes to os.stderr
+// eprintf formats according to the specified format string and writes to os.stderr
 eprintf  :: proc(fmt: string, args: ..any) -> int { return fprintf(os.stderr, fmt, ..args) }

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

@@ -182,3 +182,12 @@ shuffle :: proc(array: $T/[]$E, r: ^Rand = nil) {
 		array[i], array[j] = array[j], array[i]
 	}
 }
+
+// Returns a random element from the given slice
+choice :: proc(array: $T/[]$E, r: ^Rand = nil) -> (res: E) {
+	n := i64(len(array))
+	if n < 1 {
+		return E{}
+	}
+	return array[int63_max(n, r)]
+}

+ 331 - 0
core/mem/virtual/arena.odin

@@ -0,0 +1,331 @@
+package mem_virtual
+
+import "core:mem"
+
+Arena_Kind :: enum uint {
+	Growing = 0, // Chained memory blocks (singly linked list).
+	Static  = 1, // Fixed reservation sized.
+	Buffer  = 2, // Uses a fixed sized buffer.
+}
+
+Arena :: struct {
+	kind:               Arena_Kind,
+	curr_block:         ^Memory_Block,
+	total_used:         uint,
+	total_reserved:     uint,
+	minimum_block_size: uint,
+	temp_count:         uint,
+}
+
+
+// 1 MiB should be enough to start with
+DEFAULT_ARENA_STATIC_COMMIT_SIZE         :: 1<<20
+DEFAULT_ARENA_GROWING_MINIMUM_BLOCK_SIZE :: DEFAULT_ARENA_STATIC_COMMIT_SIZE
+
+// 1 GiB on 64-bit systems, 128 MiB on 32-bit systems by default
+DEFAULT_ARENA_STATIC_RESERVE_SIZE :: 1<<30 when size_of(uintptr) == 8 else 1<<27
+
+
+
+@(require_results)
+arena_init_growing :: proc(arena: ^Arena, reserved: uint = DEFAULT_ARENA_GROWING_MINIMUM_BLOCK_SIZE) -> (err: Allocator_Error) {
+	arena.kind           = .Growing
+	arena.curr_block     = memory_block_alloc(0, reserved, {}) or_return
+	arena.total_used     = 0
+	arena.total_reserved = arena.curr_block.reserved
+	return
+}
+
+
+@(require_results)
+arena_init_static :: proc(arena: ^Arena, reserved: uint, commit_size: uint = DEFAULT_ARENA_STATIC_COMMIT_SIZE) -> (err: Allocator_Error) {
+	arena.kind           = .Static
+	arena.curr_block     = memory_block_alloc(commit_size, reserved, {}) or_return
+	arena.total_used     = 0
+	arena.total_reserved = arena.curr_block.reserved
+	return
+}
+
+@(require_results)
+arena_init_buffer :: proc(arena: ^Arena, buffer: []byte) -> (err: Allocator_Error) {
+	if len(buffer) < size_of(Memory_Block) {
+		return .Out_Of_Memory
+	}
+
+	arena.kind = .Buffer
+
+	mem.zero_slice(buffer)
+
+	block_base := raw_data(buffer)
+	block := (^Memory_Block)(block_base)
+	block.base      = block_base[size_of(Memory_Block):]
+	block.reserved  = len(buffer) - size_of(Memory_Block)
+	block.committed = block.reserved
+	block.used      = 0
+
+	arena.curr_block = block
+	arena.total_used = 0
+	arena.total_reserved = arena.curr_block.reserved
+	return
+}
+
+@(require_results)
+arena_alloc :: proc(arena: ^Arena, size: uint, alignment: uint, loc := #caller_location) -> (data: []byte, err: Allocator_Error) {
+	assert(alignment & (alignment-1) == 0, "non-power of two alignment", loc)
+
+	size := size
+	if size == 0 {
+		return nil, nil
+	}
+
+	switch arena.kind {
+	case .Growing:
+		if arena.curr_block == nil || (safe_add(arena.curr_block.used, size) or_else 0) > arena.curr_block.reserved {
+			size = mem.align_forward_uint(size, alignment)
+			if arena.minimum_block_size == 0 {
+				arena.minimum_block_size = DEFAULT_ARENA_GROWING_MINIMUM_BLOCK_SIZE
+			}
+
+			block_size := max(size, arena.minimum_block_size)
+
+			new_block := memory_block_alloc(size, block_size, {}) or_return
+			new_block.prev = arena.curr_block
+			arena.curr_block = new_block
+			arena.total_reserved += new_block.reserved
+		}
+
+		prev_used := arena.curr_block.used
+		data, err = alloc_from_memory_block(arena.curr_block, size, alignment)
+		arena.total_used += arena.curr_block.used - prev_used
+	case .Static:
+		if arena.curr_block == nil {
+			if arena.minimum_block_size == 0 {
+				arena.minimum_block_size = DEFAULT_ARENA_STATIC_RESERVE_SIZE
+			}
+			arena_init_static(arena=arena, reserved=arena.minimum_block_size, commit_size=DEFAULT_ARENA_STATIC_COMMIT_SIZE) or_return
+		}
+		fallthrough
+	case .Buffer:
+		if arena.curr_block == nil {
+			return nil, .Out_Of_Memory
+		}
+		data, err = alloc_from_memory_block(arena.curr_block, size, alignment)
+		arena.total_used = arena.curr_block.used
+	}
+	return
+}
+
+arena_static_reset_to :: proc(arena: ^Arena, pos: uint, loc := #caller_location) -> bool {
+	if arena.curr_block != nil {
+		assert(arena.kind != .Growing, "expected a non .Growing arena", loc)
+
+		prev_pos := arena.curr_block.used
+		arena.curr_block.used = clamp(pos, 0, arena.curr_block.reserved)
+
+		if prev_pos < pos {
+			mem.zero_slice(arena.curr_block.base[arena.curr_block.used:][:pos-prev_pos])
+		}
+		arena.total_used = arena.curr_block.used
+		return true
+	} else if pos == 0 {
+		arena.total_used = 0
+		return true
+	}
+	return false
+}
+
+arena_growing_free_last_memory_block :: proc(arena: ^Arena, loc := #caller_location) {
+	if free_block := arena.curr_block; free_block != nil {
+		assert(arena.kind == .Growing, "expected a .Growing arena", loc)
+		arena.curr_block = free_block.prev
+		memory_block_dealloc(free_block)
+	}
+}
+
+arena_free_all :: proc(arena: ^Arena) {
+	switch arena.kind {
+	case .Growing:
+		for arena.curr_block != nil {
+			arena_growing_free_last_memory_block(arena)
+		}
+		arena.total_reserved = 0
+	case .Static, .Buffer:
+		arena_static_reset_to(arena, 0)
+	}
+	arena.total_used = 0
+}
+
+arena_destroy :: proc(arena: ^Arena) {
+	arena_free_all(arena)
+	if arena.kind != .Buffer {
+		memory_block_dealloc(arena.curr_block)
+	}
+	arena.curr_block = nil
+	arena.total_used     = 0
+	arena.total_reserved = 0
+	arena.temp_count     = 0
+}
+
+arena_growing_bootstrap_new :: proc{
+	arena_growing_bootstrap_new_by_offset,
+	arena_growing_bootstrap_new_by_name,
+}
+
+arena_static_bootstrap_new :: proc{
+	arena_static_bootstrap_new_by_offset,
+	arena_static_bootstrap_new_by_name,
+}
+
+@(require_results)
+arena_growing_bootstrap_new_by_offset :: proc($T: typeid, offset_to_arena: uintptr, minimum_block_size: uint = DEFAULT_ARENA_GROWING_MINIMUM_BLOCK_SIZE) -> (ptr: ^T, err: Allocator_Error) {
+	bootstrap: Arena
+	bootstrap.kind = .Growing
+	bootstrap.minimum_block_size = minimum_block_size
+
+	data := arena_alloc(&bootstrap, size_of(T), align_of(T)) or_return
+
+	ptr = (^T)(raw_data(data))
+
+	(^Arena)(uintptr(ptr) + offset_to_arena)^ = bootstrap
+
+	return
+}
+
+@(require_results)
+arena_growing_bootstrap_new_by_name :: proc($T: typeid, $field_name: string, minimum_block_size: uint = DEFAULT_ARENA_GROWING_MINIMUM_BLOCK_SIZE) -> (ptr: ^T, err: Allocator_Error) {
+	return arena_growing_bootstrap_new_by_offset(T, offset_of_by_string(T, field_name), minimum_block_size)
+}
+
+@(require_results)
+arena_static_bootstrap_new_by_offset :: proc($T: typeid, offset_to_arena: uintptr, reserved: uint) -> (ptr: ^T, err: Allocator_Error) {
+	bootstrap: Arena
+	bootstrap.kind = .Static
+	bootstrap.minimum_block_size = reserved
+
+	data := arena_alloc(&bootstrap, size_of(T), align_of(T)) or_return
+
+	ptr = (^T)(raw_data(data))
+
+	(^Arena)(uintptr(ptr) + offset_to_arena)^ = bootstrap
+
+	return
+}
+
+@(require_results)
+arena_static_bootstrap_new_by_name :: proc($T: typeid, $field_name: string, reserved: uint) -> (ptr: ^T, err: Allocator_Error) {
+	return arena_static_bootstrap_new_by_offset(T, offset_of_by_string(T, field_name), reserved)
+}
+
+
+@(require_results)
+arena_allocator :: proc(arena: ^Arena) -> mem.Allocator {
+	return mem.Allocator{arena_allocator_proc, arena}
+}
+
+arena_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
+                             size, alignment: int,
+                             old_memory: rawptr, old_size: int,
+                             location := #caller_location) -> (data: []byte, err: Allocator_Error) {
+	arena := (^Arena)(allocator_data)
+
+	size, alignment := uint(size), uint(alignment)
+	old_size := uint(old_size)
+
+	switch mode {
+	case .Alloc:
+		return arena_alloc(arena, size, alignment)
+	case .Free:
+		err = .Mode_Not_Implemented
+	case .Free_All:
+		arena_free_all(arena)
+	case .Resize:
+		old_data := ([^]byte)(old_memory)
+
+		switch {
+		case old_data == nil:
+			return arena_alloc(arena, size, alignment)
+		case size == old_size:
+			// return old memory
+			data = old_data[:size]
+			return
+		case size == 0:
+			err = .Mode_Not_Implemented
+			return
+		case (uintptr(old_data) & uintptr(alignment-1) == 0) && size < old_size:
+			// shrink data in-place
+			data = old_data[:size]
+			return
+		}
+
+		new_memory := arena_alloc(arena, size, alignment) or_return
+		if new_memory == nil {
+			return
+		}
+		copy(new_memory, old_data[:old_size])
+		return new_memory, nil
+	case .Query_Features:
+		set := (^mem.Allocator_Mode_Set)(old_memory)
+		if set != nil {
+			set^ = {.Alloc, .Free_All, .Resize, .Query_Features}
+		}
+	case .Query_Info:
+		err = .Mode_Not_Implemented
+	}
+
+	return
+}
+
+
+
+
+Arena_Temp :: struct {
+	arena: ^Arena,
+	block: ^Memory_Block,
+	used:  uint,
+}
+
+@(require_results)
+arena_temp_begin :: proc(arena: ^Arena, loc := #caller_location) -> (temp: Arena_Temp) {
+	assert(arena != nil, "nil arena", loc)
+	temp.arena = arena
+	temp.block = arena.curr_block
+	if arena.curr_block != nil {
+		temp.used = arena.curr_block.used
+	}
+	arena.temp_count += 1
+	return
+}
+
+arena_temp_end :: proc(temp: Arena_Temp, loc := #caller_location) {
+	assert(temp.arena != nil, "nil arena", loc)
+	arena := temp.arena
+
+	memory_block_found := false
+	for block := arena.curr_block; block != nil; block = block.prev {
+		if block == temp.block {
+			memory_block_found = true
+			break
+		}
+	}
+	if !memory_block_found {
+		assert(arena.curr_block == temp.block, "memory block stored within Arena_Temp not owned by Arena", loc)
+	}
+
+	for arena.curr_block != temp.block {
+		arena_growing_free_last_memory_block(arena)
+	}
+
+	if block := arena.curr_block; block != nil {
+		assert(block.used >= temp.used, "out of order use of arena_temp_end", loc)
+		amount_to_zero := min(block.used-temp.used, block.reserved-block.used)
+		mem.zero_slice(block.base[temp.used:][:amount_to_zero])
+		block.used = temp.used
+	}
+
+	assert(arena.temp_count > 0, "double-use of arena_temp_end", loc)
+	arena.temp_count -= 1
+}
+
+arena_check_temp :: proc(arena: ^Arena, loc := #caller_location) {
+	assert(arena.temp_count == 0, "Arena_Temp not been ended", loc)
+}

+ 0 - 41
core/mem/virtual/arena_util.odin

@@ -1,41 +0,0 @@
-package mem_virtual
-
-arena_init :: proc{
-	static_arena_init,
-	growing_arena_init,
-}
-
-arena_temp_begin :: proc{
-	static_arena_temp_begin,
-	growing_arena_temp_begin,
-}
-
-arena_temp_end :: proc{
-	static_arena_temp_end,
-	growing_arena_temp_end,
-}
-
-arena_check_temp :: proc{
-	static_arena_check_temp,
-	growing_arena_check_temp,
-}
-
-arena_allocator :: proc{
-	static_arena_allocator,
-	growing_arena_allocator,
-}
-
-arena_alloc :: proc{
-	static_arena_alloc,
-	growing_arena_alloc,
-}
-
-arena_free_all :: proc{
-	static_arena_free_all,
-	growing_arena_free_all,
-}
-
-arena_destroy :: proc{
-	static_arena_destroy,
-	growing_arena_destroy,
-}

+ 0 - 170
core/mem/virtual/growing_arena.odin

@@ -1,170 +0,0 @@
-package mem_virtual
-
-import "core:mem"
-
-Growing_Arena :: struct {
-	curr_block:     ^Memory_Block,
-	total_used:     uint,
-	total_reserved: uint,
-	
-	minimum_block_size: uint,
-	temp_count: int,
-}
-
-DEFAULT_MINIMUM_BLOCK_SIZE :: 1<<20 // 1 MiB should be enough
-
-growing_arena_init :: proc(arena: ^Growing_Arena, reserved: uint = DEFAULT_MINIMUM_BLOCK_SIZE) -> (err: Allocator_Error) {
-	arena.curr_block = memory_block_alloc(0, reserved, {}) or_return
-	arena.total_used = 0
-	arena.total_reserved = arena.curr_block.reserved
-	return
-}
-
-growing_arena_alloc :: proc(arena: ^Growing_Arena, min_size: int, alignment: int) -> (data: []byte, err: Allocator_Error) {
-	align_forward_offset :: proc "contextless" (arena: ^Growing_Arena, alignment: int) -> uint #no_bounds_check {
-		alignment_offset := uint(0)
-		ptr := uintptr(arena.curr_block.base[arena.curr_block.used:])
-		mask := uintptr(alignment-1)
-		if ptr & mask != 0 {
-			alignment_offset = uint(alignment) - uint(ptr & mask)
-		}
-		return alignment_offset
-	}
-	
-	assert(mem.is_power_of_two(uintptr(alignment)))
-
-	size := uint(0)
-	if arena.curr_block != nil {
-		size = uint(min_size) + align_forward_offset(arena, alignment)
-	}
-	
-	if arena.curr_block == nil || arena.curr_block.used + size > arena.curr_block.reserved {
-		size = uint(mem.align_forward_int(min_size, alignment))
-		arena.minimum_block_size = max(DEFAULT_MINIMUM_BLOCK_SIZE, arena.minimum_block_size)
-		
-		block_size := max(size, arena.minimum_block_size)
-		
-		new_block := memory_block_alloc(size, block_size, {}) or_return
-		new_block.prev = arena.curr_block
-		arena.curr_block = new_block
-		arena.total_reserved += new_block.reserved	
-	}	
-	
-	
-	data, err = alloc_from_memory_block(arena.curr_block, int(size), alignment)
-	if err == nil {
-		arena.total_used += size
-	}
-	return
-}
-
-growing_arena_free_last_memory_block :: proc(arena: ^Growing_Arena) {
-	free_block := arena.curr_block
-	arena.curr_block = free_block.prev
-	memory_block_dealloc(free_block)
-}
-
-growing_arena_free_all :: proc(arena: ^Growing_Arena) {
-	for arena.curr_block != nil {
-		growing_arena_free_last_memory_block(arena)
-	}
-	arena.total_used = 0
-	arena.total_reserved = 0
-}
-
-growing_arena_destroy :: proc(arena: ^Growing_Arena) {
-	growing_arena_free_all(arena)
-}
-
-growing_arena_bootstrap_new_by_offset :: proc($T: typeid, offset_to_arena: uintptr, minimum_block_size: uint = DEFAULT_MINIMUM_BLOCK_SIZE) -> (ptr: ^T, err: Allocator_Error) {	bootstrap: Growing_Arena
-	bootstrap.minimum_block_size = minimum_block_size
-	
-	data := growing_arena_alloc(&bootstrap, size_of(T), align_of(T)) or_return
-	
-	ptr = (^T)(raw_data(data))
-	
-	(^Growing_Arena)(uintptr(ptr) + offset_to_arena)^ = bootstrap
-	
-	return
-}
-
-growing_arena_bootstrap_new_by_name :: proc($T: typeid, $field_name: string, minimum_block_size: uint = DEFAULT_MINIMUM_BLOCK_SIZE) -> (ptr: ^T, err: Allocator_Error) {
-	return growing_arena_bootstrap_new_by_offset(T, offset_of_by_string(T, field_name), minimum_block_size)
-}
-growing_arena_bootstrap_new :: proc{
-	growing_arena_bootstrap_new_by_offset, 
-	growing_arena_bootstrap_new_by_name,
-}
-
-growing_arena_allocator :: proc(arena: ^Growing_Arena) -> mem.Allocator {
-	return mem.Allocator{growing_arena_allocator_proc, arena}
-}
-
-growing_arena_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
-                                     size, alignment: int,
-                                     old_memory: rawptr, old_size: int,
-                                     location := #caller_location) -> (data: []byte, err: Allocator_Error) {
-	arena := (^Growing_Arena)(allocator_data)
-		
-	switch mode {
-	case .Alloc:
-		return growing_arena_alloc(arena, size, alignment)
-	case .Free:
-		err = .Mode_Not_Implemented
-		return
-	case .Free_All:
-		growing_arena_free_all(arena)
-		return
-	case .Resize:
-		return mem.default_resize_bytes_align(mem.byte_slice(old_memory, old_size), size, alignment, growing_arena_allocator(arena), location)
-		
-	case .Query_Features, .Query_Info:
-		err = .Mode_Not_Implemented
-		return	
-	}	
-	
-	err = .Mode_Not_Implemented
-	return 
-}
-
-Growing_Arena_Temp :: struct {
-	arena: ^Growing_Arena,
-	block: ^Memory_Block,
-	used:  uint,
-}
-
-growing_arena_temp_begin :: proc(arena: ^Growing_Arena) -> (temp: Growing_Arena_Temp) {
-	temp.arena = arena
-	temp.block = arena.curr_block
-	if arena.curr_block != nil {
-		temp.used = arena.curr_block.used
-	}
-	arena.temp_count += 1
-	return
-}
-
-growing_arena_temp_end :: proc(temp: Growing_Arena_Temp, loc := #caller_location) {
-	assert(temp.arena != nil, "nil arena", loc)
-	arena := temp.arena
-	
-	for arena.curr_block != temp.block {
-		growing_arena_free_last_memory_block(arena)
-	}
-	
-	if block := arena.curr_block; block != nil {
-		assert(block.used >= temp.used, "out of order use of growing_arena_temp_end", loc)
-		amount_to_zero := min(block.used-temp.used, block.reserved-block.used)
-		mem.zero_slice(block.base[temp.used:][:amount_to_zero])
-		block.used = temp.used
-	}
-	
-	assert(arena.temp_count > 0, "double-use of growing_arena_temp_end", loc)
-	arena.temp_count -= 1
-}
-
-growing_arena_check_temp :: proc(arena: ^Growing_Arena, loc := #caller_location) {
-	assert(arena.temp_count == 0, "Growing_Arena_Temp not been ended", loc)
-}
-
-
-

+ 0 - 153
core/mem/virtual/static_arena.odin

@@ -1,153 +0,0 @@
-package mem_virtual
-
-import "core:mem"
-
-Static_Arena :: struct {
-	block: ^Memory_Block,
-	total_used:     uint,
-	total_reserved: uint,
-	
-	minimum_block_size: uint,
-	temp_count: int,
-}
-
-STATIC_ARENA_DEFAULT_COMMIT_SIZE  :: 1<<20 // 1 MiB should be enough to start with
-
-// 1 GiB on 64-bit systems, 128 MiB on 32-bit systems by default
-STATIC_ARENA_DEFAULT_RESERVE_SIZE :: 1<<30 when size_of(uintptr) == 8 else 1<<27
-
-static_arena_init :: proc(arena: ^Static_Arena, reserved: uint, commit_size: uint = STATIC_ARENA_DEFAULT_COMMIT_SIZE) -> (err: Allocator_Error) {	
-	arena.block = memory_block_alloc(commit_size, reserved, {}) or_return
-	arena.total_used = 0
-	arena.total_reserved = arena.block.reserved
-	return
-} 
-
-static_arena_destroy :: proc(arena: ^Static_Arena) {
-	memory_block_dealloc(arena.block)
-	arena^ = {}
-} 
-
-
-static_arena_alloc :: proc(arena: ^Static_Arena, size: int, alignment: int) -> (data: []byte, err: Allocator_Error) {
-	align_forward :: #force_inline proc "contextless" (ptr: uint, align: uint) -> uint {
-		mask := align-1
-		return (ptr + mask) &~ mask
-	}
-	
-	if arena.block == nil {
-		reserve_size := max(arena.minimum_block_size, STATIC_ARENA_DEFAULT_RESERVE_SIZE)
-		static_arena_init(arena, reserve_size, STATIC_ARENA_DEFAULT_COMMIT_SIZE) or_return
-	}
-	
-	MINIMUM_ALIGN :: 2*align_of(uintptr)
-	
-	defer arena.total_used = arena.block.used
-	return alloc_from_memory_block(arena.block, size, max(MINIMUM_ALIGN, alignment))
-}
-
-static_arena_reset_to :: proc(arena: ^Static_Arena, pos: uint) -> bool {
-	if arena.block != nil {
-		prev_pos := arena.block.used
-		arena.block.used = clamp(pos, 0, arena.block.reserved)
-		
-		if prev_pos < pos {
-			mem.zero_slice(arena.block.base[arena.block.used:][:pos-prev_pos])
-		}
-		return true
-	} else if pos == 0 {
-		return true
-	}
-	return false
-}
-
-static_arena_free_all :: proc(arena: ^Static_Arena) {
-	static_arena_reset_to(arena, 0)
-}
-
-
-static_arena_bootstrap_new_by_offset :: proc($T: typeid, offset_to_arena: uintptr, reserved: uint) -> (ptr: ^T, err: Allocator_Error) {
-	bootstrap: Static_Arena
-	bootstrap.minimum_block_size = reserved
-	
-	data := static_arena_alloc(&bootstrap, size_of(T), align_of(T)) or_return
-	
-	ptr = (^T)(raw_data(data))
-	
-	(^Static_Arena)(uintptr(ptr) + offset_to_arena)^ = bootstrap
-	
-	return
-}
-
-static_arena_bootstrap_new_by_name :: proc($T: typeid, $field_name: string, reserved: uint) -> (ptr: ^T, err: Allocator_Error) { 
-	return static_arena_bootstrap_new_by_offset(T, offset_of_by_string(T, field_name), reserved)
-}
-static_arena_bootstrap_new :: proc{
-	static_arena_bootstrap_new_by_offset, 
-	static_arena_bootstrap_new_by_name,
-}
-
-
-static_arena_allocator :: proc(arena: ^Static_Arena) -> mem.Allocator {
-	return mem.Allocator{static_arena_allocator_proc, arena}
-}
-
-static_arena_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
-                             size, alignment: int,
-                             old_memory: rawptr, old_size: int,
-                             location := #caller_location) -> (data: []byte, err: Allocator_Error) {
-	arena := (^Static_Arena)(allocator_data)
-	
-	switch mode {
-	case .Alloc:
-		return static_arena_alloc(arena, size, alignment)
-	case .Free:
-		err = .Mode_Not_Implemented
-		return
-	case .Free_All:
-		static_arena_free_all(arena)
-		return
-	case .Resize:
-		return mem.default_resize_bytes_align(mem.byte_slice(old_memory, old_size), size, alignment, static_arena_allocator(arena), location)
-		
-	case .Query_Features, .Query_Info:
-		err = .Mode_Not_Implemented
-		return	
-	}	
-	
-	err = .Mode_Not_Implemented
-	return 
-}
-
-
-Static_Arena_Temp :: struct {
-	arena: ^Static_Arena,
-	used:  uint,
-}
-
-
-static_arena_temp_begin :: proc(arena: ^Static_Arena) -> (temp: Static_Arena_Temp) {
-	temp.arena = arena
-	temp.used = arena.block.used if arena.block != nil else 0
-	arena.temp_count += 1
-	return
-}
-
-static_arena_temp_end :: proc(temp: Static_Arena_Temp, loc := #caller_location) {
-	assert(temp.arena != nil, "nil arena", loc)
-	arena := temp.arena
-	
-	used := arena.block.used if arena.block != nil else 0
-	
-	assert(temp.used >= used, "invalid Static_Arena_Temp", loc)
-	
-	static_arena_reset_to(arena, temp.used)
-	
-	assert(arena.temp_count > 0, "double-use of static_arena_temp_end", loc)
-	arena.temp_count -= 1
-}
-
-
-static_arena_check_temp :: proc(arena: ^Static_Arena, loc := #caller_location) {
-	assert(arena.temp_count == 0, "Static_Arena_Temp not been ended", loc)
-}

+ 18 - 15
core/mem/virtual/virtual.odin

@@ -1,6 +1,7 @@
 package mem_virtual
 
 import "core:mem"
+import "core:intrinsics"
 
 DEFAULT_PAGE_SIZE := uint(4096)
 
@@ -95,18 +96,11 @@ memory_block_alloc :: proc(committed, reserved: uint, flags: Memory_Block_Flags)
 	pmblock.block.committed = committed
 	pmblock.block.reserved  = reserved
 
-	sentinel := &global_platform_memory_block_sentinel
-	platform_mutex_lock()
-	pmblock.next = sentinel
-	pmblock.prev = sentinel.prev
-	pmblock.prev.next = pmblock
-	pmblock.next.prev = pmblock
-	platform_mutex_unlock()
 	
 	return &pmblock.block, nil
 }
 
-alloc_from_memory_block :: proc(block: ^Memory_Block, min_size, alignment: int) -> (data: []byte, err: Allocator_Error) {
+alloc_from_memory_block :: proc(block: ^Memory_Block, min_size, alignment: uint) -> (data: []byte, err: Allocator_Error) {
 	calc_alignment_offset :: proc "contextless" (block: ^Memory_Block, alignment: uintptr) -> uint {
 		alignment_offset := uint(0)
 		ptr := uintptr(block.base[block.used:])
@@ -134,11 +128,18 @@ alloc_from_memory_block :: proc(block: ^Memory_Block, min_size, alignment: int)
 		return nil
 	}
 
+	if block == nil {
+		return nil, .Out_Of_Memory
+	}
 
 	alignment_offset := calc_alignment_offset(block, uintptr(alignment))
-	size := uint(min_size) + alignment_offset
+	size, size_ok := safe_add(min_size, alignment_offset)
+	if !size_ok {
+		err = .Out_Of_Memory
+		return
+	}
 
-	if block.used + size > block.reserved {
+	if to_be_used, ok := safe_add(block.used, size); !ok || to_be_used > block.reserved {
 		err = .Out_Of_Memory
 		return
 	}
@@ -153,12 +154,14 @@ alloc_from_memory_block :: proc(block: ^Memory_Block, min_size, alignment: int)
 
 memory_block_dealloc :: proc(block_to_free: ^Memory_Block) {
 	if block := (^Platform_Memory_Block)(block_to_free); block != nil {
-		platform_mutex_lock()
-		block.prev.next = block.next
-		block.next.prev = block.prev
-		platform_mutex_unlock()
-		
 		platform_memory_free(block)
 	}
 }
 
+
+
+@(private)
+safe_add :: #force_inline proc "contextless" (x, y: uint) -> (uint, bool) {
+	z, did_overflow := intrinsics.overflow_add(x, y)
+	return z, !did_overflow
+}

+ 0 - 26
core/mem/virtual/virtual_platform.odin

@@ -1,13 +1,10 @@
 //+private
 package mem_virtual
 
-import "core:sync"
-
 Platform_Memory_Block :: struct {
 	block:      Memory_Block,
 	committed:  uint,
 	reserved:   uint,
-	prev, next: ^Platform_Memory_Block,
 } 
 
 platform_memory_alloc :: proc "contextless" (to_commit, to_reserve: uint) -> (block: ^Platform_Memory_Block, err: Allocator_Error) {
@@ -33,28 +30,6 @@ platform_memory_free :: proc "contextless" (block: ^Platform_Memory_Block) {
 	}
 }
 
-platform_mutex_lock :: proc() {
-	sync.mutex_lock(&global_memory_block_mutex)
-}
-
-platform_mutex_unlock :: proc() {
-	sync.mutex_unlock(&global_memory_block_mutex)
-}
-
-global_memory_block_mutex: sync.Mutex
-global_platform_memory_block_sentinel: Platform_Memory_Block
-global_platform_memory_block_sentinel_set: bool
-
-@(init)
-platform_memory_init :: proc() {
-	if !global_platform_memory_block_sentinel_set {
-		_platform_memory_init()
-		global_platform_memory_block_sentinel.prev = &global_platform_memory_block_sentinel
-		global_platform_memory_block_sentinel.next = &global_platform_memory_block_sentinel
-		global_platform_memory_block_sentinel_set = true
-	}
-}
-
 platform_memory_commit :: proc "contextless" (block: ^Platform_Memory_Block, to_commit: uint) -> (err: Allocator_Error) {
 	if to_commit < block.committed {
 		return nil
@@ -63,7 +38,6 @@ platform_memory_commit :: proc "contextless" (block: ^Platform_Memory_Block, to_
 		return .Out_Of_Memory
 	}
 
-
 	commit(block, to_commit) or_return
 	block.committed = to_commit
 	return nil

+ 1 - 4
core/os/dir_windows.odin

@@ -2,7 +2,6 @@ package os
 
 import win32 "core:sys/windows"
 import "core:strings"
-import "core:time"
 
 read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []File_Info, err: Errno) {
 	find_data_to_file_info :: proc(base_path: string, d: ^win32.WIN32_FIND_DATAW) -> (fi: File_Info) {
@@ -41,9 +40,7 @@ read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []F
 			// fi.mode |= file_type_mode(h);
 		}
 
-		fi.creation_time     = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftCreationTime))
-		fi.modification_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastWriteTime))
-		fi.access_time       = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastAccessTime))
+		windows_set_file_info_times(&fi, d)
 
 		fi.is_dir = fi.mode & File_Mode_Dir != 0
 		return

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

@@ -130,7 +130,7 @@ _new_file :: proc(handle: uintptr, name: string) -> ^File {
 	f := new(File, _file_allocator())
 
 	f.impl.allocator = _file_allocator()
-	f.impl.fd = rawptr(fd)
+	f.impl.fd = rawptr(handle)
 	f.impl.name = strings.clone(name, f.impl.allocator)
 	f.impl.wname = win32.utf8_to_wstring(name, f.impl.allocator)
 

+ 10 - 10
core/os/stat_windows.odin

@@ -228,6 +228,13 @@ file_mode_from_file_attributes :: proc(FileAttributes: win32.DWORD, h: win32.HAN
 	return
 }
 
+@(private)
+windows_set_file_info_times :: proc(fi: ^File_Info, d: ^$T) {
+	fi.creation_time     = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftCreationTime))
+	fi.modification_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastWriteTime))
+	fi.access_time       = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastAccessTime))
+}
+
 @(private)
 file_info_from_win32_file_attribute_data :: proc(d: ^win32.WIN32_FILE_ATTRIBUTE_DATA, name: string) -> (fi: File_Info, e: Errno) {
 	fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow)
@@ -235,9 +242,7 @@ file_info_from_win32_file_attribute_data :: proc(d: ^win32.WIN32_FILE_ATTRIBUTE_
 	fi.mode |= file_mode_from_file_attributes(d.dwFileAttributes, nil, 0)
 	fi.is_dir = fi.mode & File_Mode_Dir != 0
 
-	fi.creation_time     = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftCreationTime))
-	fi.modification_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastWriteTime))
-	fi.access_time       = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastAccessTime))
+	windows_set_file_info_times(&fi, d)
 
 	fi.fullpath, e = full_path_from_name(name)
 	fi.name = basename(fi.fullpath)
@@ -252,9 +257,7 @@ file_info_from_win32_find_data :: proc(d: ^win32.WIN32_FIND_DATAW, name: string)
 	fi.mode |= file_mode_from_file_attributes(d.dwFileAttributes, nil, 0)
 	fi.is_dir = fi.mode & File_Mode_Dir != 0
 
-	fi.creation_time     = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftCreationTime))
-	fi.modification_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastWriteTime))
-	fi.access_time       = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastAccessTime))
+	windows_set_file_info_times(&fi, d)
 
 	fi.fullpath, e = full_path_from_name(name)
 	fi.name = basename(fi.fullpath)
@@ -290,10 +293,7 @@ file_info_from_get_file_information_by_handle :: proc(path: string, h: win32.HAN
 	fi.mode |= file_mode_from_file_attributes(ti.FileAttributes, h, ti.ReparseTag)
 	fi.is_dir = fi.mode & File_Mode_Dir != 0
 
-	fi.creation_time     = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftCreationTime))
-	fi.modification_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastWriteTime))
-	fi.access_time       = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastAccessTime))
-
+	windows_set_file_info_times(&fi, &d)
 
 	return fi, ERROR_NONE
 }

+ 1 - 1
core/runtime/procs_darwin.odin

@@ -12,7 +12,7 @@ objc_SEL :: ^intrinsics.objc_selector
 foreign Foundation {
 	objc_lookUpClass :: proc "c" (name: cstring) -> objc_Class ---
 	sel_registerName :: proc "c" (name: cstring) -> objc_SEL ---
-	objc_allocateClassPair :: proc "c" (superclass: objc_Class, name: cstring, extraBytes: uint) ---
+	objc_allocateClassPair :: proc "c" (superclass: objc_Class, name: cstring, extraBytes: uint) -> objc_Class ---
 
 	objc_msgSend        :: proc "c" (self: objc_id, op: objc_SEL, #c_vararg args: ..any) ---
 	objc_msgSend_fpret  :: proc "c" (self: objc_id, op: objc_SEL, #c_vararg args: ..any) -> f64 ---

+ 3 - 2
core/slice/sort_private.odin

@@ -177,7 +177,6 @@ _quick_sort_general :: proc(data: $T/[]$E, a, b, max_depth: int, call: $P, $KIND
 }
 
 
-// merge sort
 _stable_sort_general :: proc(data: $T/[]$E, call: $P, $KIND: Sort_Kind) where (ORD(E) && KIND == .Ordered) || (KIND != .Ordered) #no_bounds_check {
 	less :: #force_inline proc(a, b: E, call: P) -> bool {
 		when KIND == .Ordered {
@@ -190,7 +189,9 @@ _stable_sort_general :: proc(data: $T/[]$E, call: $P, $KIND: Sort_Kind) where (O
 			#panic("unhandled Sort_Kind")
 		}
 	}
-
+	
+	// insertion sort
+	// TODO(bill): use a different algorithm as insertion sort is O(n^2)
 	n := len(data)
 	for i in 1..<n {
 		for j := i; j > 0 && less(data[j], data[j-1], call); j -= 1 {

+ 8 - 1
core/strconv/strconv.odin

@@ -575,9 +575,11 @@ parse_f64 :: proc(str: string, n: ^int = nil) -> (value: f64, ok: bool) {
 	i := 0
 
 	sign: f64 = 1
+	seen_sign := true
 	switch s[i] {
 	case '-': i += 1; sign = -1
 	case '+': i += 1
+	case: seen_sign = false
 	}
 
 	for ; i < len(s); i += 1 {
@@ -677,8 +679,13 @@ parse_f64 :: proc(str: string, n: ^int = nil) -> (value: f64, ok: bool) {
 			for exp >   0 { scale *=   10; exp -=  1 }
 		}
 	}
-	s = s[i:]
 
+	// If we only consumed a sign, return false
+	if i == 1 && seen_sign {
+		return 0, false
+	}
+
+	s = s[i:]
 	if frac {
 		value = sign * (value/scale)
 	} else {

+ 30 - 0
core/sys/windows/advapi32.odin

@@ -128,4 +128,34 @@ foreign advapi32 {
 		lpData: LPCVOID,
 		cbData: DWORD,
 	) -> LSTATUS ---
+
+	GetFileSecurityW :: proc(
+		lpFileName: LPCWSTR,
+		RequestedInformation: SECURITY_INFORMATION,
+		pSecurityDescriptor: PSECURITY_DESCRIPTOR,
+		nLength: DWORD,
+		lpnLengthNeeded: LPDWORD,
+	) -> BOOL ---
+
+	DuplicateToken :: proc(
+		ExistingTokenHandle: HANDLE,
+		ImpersonationLevel: SECURITY_IMPERSONATION_LEVEL,
+		DuplicateTokenHandle: PHANDLE,
+	) -> BOOL ---
+
+	MapGenericMask :: proc(
+		AccessMask: PDWORD,
+		GenericMapping: PGENERIC_MAPPING,
+	) ---
+
+	AccessCheck :: proc(
+		pSecurityDescriptor: PSECURITY_DESCRIPTOR,
+		ClientToken: HANDLE,
+		DesiredAccess: DWORD,
+		GenericMapping: PGENERIC_MAPPING,
+		PrivilegeSet: PPRIVILEGE_SET,
+		PrivilegeSetLength: LPDWORD,
+		GrantedAccess: LPDWORD,
+		AccessStatus: LPBOOL,
+	) -> BOOL ---
 }

+ 9 - 0
core/sys/windows/comctl32.odin

@@ -0,0 +1,9 @@
+// +build windows
+package sys_windows
+
+foreign import "system:Comctl32.lib"
+
+@(default_calling_convention="stdcall")
+foreign Comctl32 {
+	LoadIconWithScaleDown :: proc(hinst: HINSTANCE, pszName: PCWSTR, cx: c_int, cy: c_int, phico: ^HICON) -> HRESULT ---
+}

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

@@ -77,6 +77,7 @@ foreign gdi32 {
 	) -> HFONT ---
 	TextOutW :: proc(hdc: HDC, x, y: c_int, lpString: LPCWSTR, c: c_int) -> BOOL ---
 	GetTextExtentPoint32W :: proc(hdc: HDC, lpString: LPCWSTR, c: c_int, psizl: LPSIZE) -> BOOL ---
+	GetTextMetricsW :: proc(hdc: HDC, lptm: LPTEXTMETRICW) -> BOOL ---
 }
 
 RGB :: #force_inline proc "contextless" (r, g, b: u8) -> COLORREF {

+ 18 - 0
core/sys/windows/kernel32.odin

@@ -248,6 +248,17 @@ foreign kernel32 {
 	GetModuleHandleW :: proc(lpModuleName: LPCWSTR) -> HMODULE ---
 	GetModuleHandleA :: proc(lpModuleName: LPCSTR) -> HMODULE ---
 	GetSystemTimeAsFileTime :: proc(lpSystemTimeAsFileTime: LPFILETIME) ---
+	GetSystemTimePreciseAsFileTime :: proc(lpSystemTimeAsFileTime: LPFILETIME) ---
+	FileTimeToSystemTime :: proc(lpFileTime: ^FILETIME, lpSystemTime: ^SYSTEMTIME) -> BOOL ---
+	SystemTimeToTzSpecificLocalTime :: proc(
+		lpTimeZoneInformation: ^TIME_ZONE_INFORMATION,
+		lpUniversalTime: ^SYSTEMTIME,
+		lpLocalTime: ^SYSTEMTIME,
+	) -> BOOL ---
+	SystemTimeToFileTime :: proc(
+		lpSystemTime: ^SYSTEMTIME,
+		lpFileTime: LPFILETIME,
+	) -> BOOL ---
 	CreateEventW :: proc(
 		lpEventAttributes: LPSECURITY_ATTRIBUTES,
 		bManualReset: BOOL,
@@ -346,6 +357,13 @@ foreign kernel32 {
 	GenerateConsoleCtrlEvent :: proc(dwCtrlEvent: DWORD, dwProcessGroupId: DWORD) -> BOOL ---
 	FreeConsole :: proc() -> BOOL ---
 	GetConsoleWindow :: proc() -> HWND ---
+
+	GetDiskFreeSpaceExW :: proc(
+		lpDirectoryName: LPCWSTR,
+		lpFreeBytesAvailableToCaller: PULARGE_INTEGER,
+		lpTotalNumberOfBytes: PULARGE_INTEGER,
+		lpTotalNumberOfFreeBytes: PULARGE_INTEGER,
+	) -> BOOL ---
 }
 
 

+ 6 - 0
core/sys/windows/shell32.odin

@@ -14,4 +14,10 @@ foreign shell32 {
 		lpDirectory: LPCWSTR,
 		nShowCmd: INT,
 	) -> HINSTANCE ---
+	SHCreateDirectoryExW :: proc(
+		hwnd: HWND,
+		pszPath: LPCWSTR,
+		psa: ^SECURITY_ATTRIBUTES,
+	) -> c_int ---
+	SHFileOperationW :: proc(lpFileOp: LPSHFILEOPSTRUCTW) -> c_int ---
 }

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

@@ -8,4 +8,5 @@ foreign shlwapi {
 	PathFileExistsW    :: proc(pszPath: wstring) -> BOOL ---
 	PathFindExtensionW :: proc(pszPath: wstring) -> wstring ---
 	PathFindFileNameW  :: proc(pszPath: wstring) -> wstring ---
+	SHAutoComplete     :: proc(hwndEdit: HWND, dwFlags: DWORD) -> LWSTDAPI ---
 }

+ 279 - 4
core/sys/windows/types.odin

@@ -20,6 +20,7 @@ DWORD :: c_ulong
 DWORDLONG :: c.ulonglong
 QWORD :: c.ulonglong
 HANDLE :: distinct LPVOID
+PHANDLE :: ^HANDLE
 HINSTANCE :: HANDLE
 HMODULE :: distinct HINSTANCE
 HRESULT :: distinct LONG
@@ -43,6 +44,7 @@ BOOLEAN :: distinct b8
 GROUP :: distinct c_uint
 LARGE_INTEGER :: distinct c_longlong
 ULARGE_INTEGER :: distinct c_ulonglong
+PULARGE_INTEGER :: ^ULARGE_INTEGER
 LONG :: c_long
 UINT :: c_uint
 INT  :: c_int
@@ -133,6 +135,11 @@ LPWSAOVERLAPPED :: distinct rawptr
 LPWSAOVERLAPPED_COMPLETION_ROUTINE :: distinct rawptr
 LPCVOID :: rawptr
 
+PACCESS_TOKEN :: PVOID
+PSECURITY_DESCRIPTOR :: PVOID
+PSID :: PVOID
+PCLAIMS_BLOB :: PVOID
+
 PCONDITION_VARIABLE :: ^CONDITION_VARIABLE
 PLARGE_INTEGER :: ^LARGE_INTEGER
 PSRWLOCK :: ^SRWLOCK
@@ -175,6 +182,7 @@ FILE_SHARE_DELETE: DWORD : 0x00000004
 FILE_GENERIC_ALL: DWORD : 0x10000000
 FILE_GENERIC_EXECUTE: DWORD : 0x20000000
 FILE_GENERIC_READ: DWORD : 0x80000000
+FILE_ALL_ACCESS :: STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1FF
 
 FILE_ACTION_ADDED            :: 0x00000001
 FILE_ACTION_REMOVED          :: 0x00000002
@@ -230,6 +238,20 @@ SECURITY_SQOS_PRESENT: DWORD : 0x00100000
 
 FIONBIO: c_ulong : 0x8004667e
 
+OWNER_SECURITY_INFORMATION               :: 0x00000001
+GROUP_SECURITY_INFORMATION               :: 0x00000002
+DACL_SECURITY_INFORMATION                :: 0x00000004
+SACL_SECURITY_INFORMATION                :: 0x00000008
+LABEL_SECURITY_INFORMATION               :: 0x00000010
+ATTRIBUTE_SECURITY_INFORMATION           :: 0x00000020
+SCOPE_SECURITY_INFORMATION               :: 0x00000040
+PROCESS_TRUST_LABEL_SECURITY_INFORMATION :: 0x00000080
+ACCESS_FILTER_SECURITY_INFORMATION       :: 0x00000100
+BACKUP_SECURITY_INFORMATION              :: 0x00010000
+PROTECTED_DACL_SECURITY_INFORMATION      :: 0x80000000
+PROTECTED_SACL_SECURITY_INFORMATION      :: 0x40000000
+UNPROTECTED_DACL_SECURITY_INFORMATION    :: 0x20000000
+UNPROTECTED_SACL_SECURITY_INFORMATION    :: 0x10000000
 
 GET_FILEEX_INFO_LEVELS :: distinct i32
 GetFileExInfoStandard: GET_FILEEX_INFO_LEVELS : 0
@@ -773,6 +795,30 @@ MSG :: struct {
 
 LPMSG :: ^MSG
 
+TEXTMETRICW :: struct {
+	tmHeight: LONG,
+	tmAscent: LONG,
+	tmDescent: LONG,
+	tmInternalLeading: LONG,
+	tmExternalLeading: LONG,
+	tmAveCharWidth: LONG,
+	tmMaxCharWidth: LONG,
+	tmWeight: LONG,
+	tmOverhang: LONG,
+	tmDigitizedAspectX: LONG,
+	tmDigitizedAspectY: LONG,
+	tmFirstChar: WCHAR,
+	tmLastChar: WCHAR,
+	tmDefaultChar: WCHAR,
+	tmBreakChar: WCHAR,
+	tmItalic: BYTE,
+	tmUnderlined: BYTE,
+	tmStruckOut: BYTE,
+	tmPitchAndFamily: BYTE,
+	tmCharSet: BYTE,
+}
+LPTEXTMETRICW :: ^TEXTMETRICW
+
 PAINTSTRUCT :: struct {
 	hdc: HDC,
 	fErase: BOOL,
@@ -879,6 +925,48 @@ NM_FONTCHANGED          :: NM_OUTOFMEMORY-22
 NM_CUSTOMTEXT           :: NM_OUTOFMEMORY-23 // uses NMCUSTOMTEXT struct
 NM_TVSTATEIMAGECHANGING :: NM_OUTOFMEMORY-23 // uses NMTVSTATEIMAGECHANGING struct, defined after HTREEITEM
 
+PCZZWSTR :: ^WCHAR
+
+SHFILEOPSTRUCTW :: struct {
+	hwnd: HWND,
+	wFunc: UINT,
+	pFrom: PCZZWSTR,
+	pTo: PCZZWSTR,
+	fFlags: FILEOP_FLAGS,
+	fAnyOperationsAborted: BOOL,
+	hNameMappings: LPVOID,
+	lpszProgressTitle: PCWSTR, // only used if FOF_SIMPLEPROGRESS
+}
+LPSHFILEOPSTRUCTW :: ^SHFILEOPSTRUCTW
+
+// Shell File Operations
+FO_MOVE   :: 0x0001
+FO_COPY   :: 0x0002
+FO_DELETE :: 0x0003
+FO_RENAME :: 0x0004
+
+// SHFILEOPSTRUCT.fFlags and IFileOperation::SetOperationFlags() flag values
+FOF_MULTIDESTFILES        :: 0x0001
+FOF_CONFIRMMOUSE          :: 0x0002
+FOF_SILENT                :: 0x0004  // don't display progress UI (confirm prompts may be displayed still)
+FOF_RENAMEONCOLLISION     :: 0x0008  // automatically rename the source files to avoid the collisions
+FOF_NOCONFIRMATION        :: 0x0010  // don't display confirmation UI, assume "yes" for cases that can be bypassed, "no" for those that can not
+FOF_WANTMAPPINGHANDLE     :: 0x0020  // Fill in SHFILEOPSTRUCT.hNameMappings
+                                     // Must be freed using SHFreeNameMappings
+FOF_ALLOWUNDO             :: 0x0040  // enable undo including Recycle behavior for IFileOperation::Delete()
+FOF_FILESONLY             :: 0x0080  // only operate on the files (non folders), both files and folders are assumed without this
+FOF_SIMPLEPROGRESS        :: 0x0100  // means don't show names of files
+FOF_NOCONFIRMMKDIR        :: 0x0200  // don't dispplay confirmatino UI before making any needed directories, assume "Yes" in these cases
+FOF_NOERRORUI             :: 0x0400  // don't put up error UI, other UI may be displayed, progress, confirmations
+FOF_NOCOPYSECURITYATTRIBS :: 0x0800  // dont copy file security attributes (ACLs)
+FOF_NORECURSION           :: 0x1000  // don't recurse into directories for operations that would recurse
+FOF_NO_CONNECTED_ELEMENTS :: 0x2000  // don't operate on connected elements ("xxx_files" folders that go with .htm files)
+FOF_WANTNUKEWARNING       :: 0x4000  // during delete operation, warn if object is being permanently destroyed instead of recycling (partially overrides FOF_NOCONFIRMATION)
+FOF_NORECURSEREPARSE      :: 0x8000  // deprecated; the operations engine always does the right thing on FolderLink objects (symlinks, reparse points, folder shortcuts)
+FOF_NO_UI                 :: (FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_NOCONFIRMMKDIR) // don't display any UI at all
+
+FILEOP_FLAGS :: WORD
+
 DEVMODEW :: struct {
 	dmDeviceName:   [32]wchar_t,
 	dmSpecVersion:   WORD,
@@ -1066,8 +1154,14 @@ WS_EX_TOPMOST               : UINT : 0x0000_0008
 WS_EX_TRANSPARENT           : UINT : 0x0000_0020
 WS_EX_WINDOWEDGE            : UINT : 0x0000_0100
 
-PBS_SMOOTH   :: 0x01
-PBS_VERTICAL :: 0x04
+PBS_SMOOTH        :: 0x01
+PBS_VERTICAL      :: 0x04
+PBS_MARQUEE       :: 0x08
+PBS_SMOOTHREVERSE :: 0x10
+
+PBST_NORMAL :: 0x0001
+PBST_ERROR  :: 0x0002
+PBST_PAUSED :: 0x0003
 
 QS_ALLEVENTS      : UINT : QS_INPUT | QS_POSTMESSAGE | QS_TIMER | QS_PAINT | QS_HOTKEY
 QS_ALLINPUT       : UINT : QS_INPUT | QS_POSTMESSAGE | QS_TIMER | QS_PAINT | QS_HOTKEY | QS_SENDMESSAGE
@@ -1462,6 +1556,24 @@ IDI_WARNING      := IDI_EXCLAMATION
 IDI_ERROR        := IDI_HAND
 IDI_INFORMATION  := IDI_ASTERISK
 
+IMAGE_BITMAP      :: 0
+IMAGE_ICON        :: 1
+IMAGE_CURSOR      :: 2
+IMAGE_ENHMETAFILE :: 3
+
+LR_DEFAULTCOLOR     :: 0x00000000
+LR_MONOCHROME       :: 0x00000001
+LR_COLOR            :: 0x00000002
+LR_COPYRETURNORG    :: 0x00000004
+LR_COPYDELETEORG    :: 0x00000008
+LR_LOADFROMFILE     :: 0x00000010
+LR_LOADTRANSPARENT  :: 0x00000020
+LR_DEFAULTSIZE      :: 0x00000040
+LR_VGACOLOR         :: 0x00000080
+LR_LOADMAP3DCOLORS  :: 0x00001000
+LR_CREATEDIBSECTION :: 0x00002000
+LR_COPYFROMRESOURCE :: 0x00004000
+LR_SHARED           :: 0x00008000
 
 // DIB color table identifiers
 DIB_RGB_COLORS :: 0
@@ -1774,12 +1886,15 @@ WAIT_FAILED: DWORD : 0xFFFFFFFF
 
 PIPE_ACCESS_INBOUND: DWORD : 0x00000001
 PIPE_ACCESS_OUTBOUND: DWORD : 0x00000002
+PIPE_ACCESS_DUPLEX: DWORD : 0x00000003
 FILE_FLAG_FIRST_PIPE_INSTANCE: DWORD : 0x00080000
 FILE_FLAG_OVERLAPPED: DWORD : 0x40000000
 PIPE_WAIT: DWORD : 0x00000000
 PIPE_TYPE_BYTE: DWORD : 0x00000000
+PIPE_TYPE_MESSAGE: DWORD : 0x00000004
 PIPE_REJECT_REMOTE_CLIENTS: DWORD : 0x00000008
 PIPE_READMODE_BYTE: DWORD : 0x00000000
+PIPE_READMODE_MESSAGE: DWORD : 0x00000002
 PIPE_ACCEPT_REMOTE_CLIENTS: DWORD : 0x00000000
 
 FD_SETSIZE :: 64
@@ -1793,7 +1908,58 @@ HEAP_ZERO_MEMORY: DWORD : 0x00000008
 HANDLE_FLAG_INHERIT: DWORD : 0x00000001
 HANDLE_FLAG_PROTECT_FROM_CLOSE :: 0x00000002
 
-TOKEN_READ: DWORD : 0x20008
+GENERIC_MAPPING :: struct {
+	GenericRead: ACCESS_MASK,
+	GenericWrite: ACCESS_MASK,
+	GenericExecute: ACCESS_MASK,
+	GenericAll: ACCESS_MASK,
+}
+PGENERIC_MAPPING :: ^GENERIC_MAPPING
+
+SECURITY_IMPERSONATION_LEVEL :: enum {
+	SecurityAnonymous,
+	SecurityIdentification,
+	SecurityImpersonation,
+	SecurityDelegation,
+}
+
+SECURITY_INFORMATION :: DWORD
+ANYSIZE_ARRAY :: 1
+
+LUID_AND_ATTRIBUTES :: struct {
+	Luid: LUID,
+	Attributes: DWORD,
+}
+
+PRIVILEGE_SET :: struct {
+	PrivilegeCount: DWORD,
+	Control: DWORD,
+	Privilege: [ANYSIZE_ARRAY]LUID_AND_ATTRIBUTES,
+}
+PPRIVILEGE_SET :: ^PRIVILEGE_SET
+
+// Token Specific Access Rights.
+TOKEN_ASSIGN_PRIMARY    :: 0x0001
+TOKEN_DUPLICATE         :: 0x0002
+TOKEN_IMPERSONATE       :: 0x0004
+TOKEN_QUERY             :: 0x0008
+TOKEN_QUERY_SOURCE      :: 0x0010
+TOKEN_ADJUST_PRIVILEGES :: 0x0020
+TOKEN_ADJUST_GROUPS     :: 0x0040
+TOKEN_ADJUST_DEFAULT    :: 0x0080
+TOKEN_ADJUST_SESSIONID  :: 0x0100
+
+TOKEN_ALL_ACCESS_P :: STANDARD_RIGHTS_REQUIRED | TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_QUERY |\
+	TOKEN_QUERY_SOURCE | TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_DEFAULT
+
+TOKEN_ALL_ACCESS                :: TOKEN_ALL_ACCESS_P | TOKEN_ADJUST_SESSIONID
+TOKEN_READ                      :: STANDARD_RIGHTS_READ | TOKEN_QUERY
+TOKEN_WRITE                     :: STANDARD_RIGHTS_WRITE | TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_DEFAULT
+TOKEN_EXECUTE                   :: STANDARD_RIGHTS_EXECUTE
+TOKEN_TRUST_CONSTRAINT_MASK     :: STANDARD_RIGHTS_READ | TOKEN_QUERY | TOKEN_QUERY_SOURCE
+TOKEN_ACCESS_PSEUDO_HANDLE_WIN8 :: TOKEN_QUERY | TOKEN_QUERY_SOURCE
+TOKEN_ACCESS_PSEUDO_HANDLE      :: TOKEN_ACCESS_PSEUDO_HANDLE_WIN8
+
 
 CP_ACP        :: 0     // default to ANSI code page
 CP_OEMCP      :: 1     // default to OEM  code page
@@ -2101,9 +2267,10 @@ FILETIME :: struct {
 
 FILETIME_as_unix_nanoseconds :: proc "contextless" (ft: FILETIME) -> i64 {
 	t := i64(u64(ft.dwLowDateTime) | u64(ft.dwHighDateTime) << 32)
-	return (t - 0x019db1ded53e8000) * 100
+	return (t - 116444736000000000) * 100
 }
 
+
 OVERLAPPED :: struct {
 	Internal: ^c_ulong,
 	InternalHigh: ^c_ulong,
@@ -2777,6 +2944,16 @@ SYSTEMTIME :: struct {
 	milliseconds: WORD,
 }
 
+TIME_ZONE_INFORMATION :: struct {
+	Bias:         LONG,
+	StandardName: [32]WCHAR,
+	StandardDate: SYSTEMTIME,
+	StandardBias: LONG,
+	DaylightName: [32]WCHAR,
+	DaylightDate: SYSTEMTIME,
+	DaylightBias: LONG,
+}
+
 
 @(private="file")
 IMAGE_DOS_HEADER :: struct {
@@ -3048,12 +3225,32 @@ SHCONTF_FLATLIST              :: 0x4000
 SHCONTF_ENABLE_ASYNC          :: 0x8000
 SHCONTF_INCLUDESUPERHIDDEN    :: 0x10000
 
+SHACF_DEFAULT               :: 0x00000000  // Currently (SHACF_FILESYSTEM | SHACF_URLALL)
+SHACF_FILESYSTEM            :: 0x00000001  // This includes the File System as well as the rest of the shell (Desktop\My Computer\Control Panel\)
+SHACF_URLALL                :: (SHACF_URLHISTORY | SHACF_URLMRU)
+SHACF_URLHISTORY            :: 0x00000002  // URLs in the User's History
+SHACF_URLMRU                :: 0x00000004  // URLs in the User's Recently Used list.
+SHACF_USETAB                :: 0x00000008  // Use the tab to move thru the autocomplete possibilities instead of to the next dialog/window control.
+SHACF_FILESYS_ONLY          :: 0x00000010  // This includes the File System
+SHACF_FILESYS_DIRS          :: 0x00000020  // Same as SHACF_FILESYS_ONLY except it only includes directories, UNC servers, and UNC server shares.
+SHACF_VIRTUAL_NAMESPACE     :: 0x00000040  // Also include the virtual namespace
+SHACF_AUTOSUGGEST_FORCE_ON  :: 0x10000000  // Ignore the registry default and force the feature on.
+SHACF_AUTOSUGGEST_FORCE_OFF :: 0x20000000  // Ignore the registry default and force the feature off.
+SHACF_AUTOAPPEND_FORCE_ON   :: 0x40000000  // Ignore the registry default and force the feature on. (Also know as AutoComplete)
+SHACF_AUTOAPPEND_FORCE_OFF  :: 0x80000000  // Ignore the registry default and force the feature off. (Also know as AutoComplete)
+
+LWSTDAPI :: HRESULT
+
 CLSID_FileOpenDialog := &GUID{0xDC1C5A9C, 0xE88A, 0x4DDE, {0xA5, 0xA1, 0x60, 0xF8, 0x2A, 0x20, 0xAE, 0xF7}}
 CLSID_FileSaveDialog := &GUID{0xC0B4E2F3, 0xBA21, 0x4773, {0x8D, 0xBA, 0x33, 0x5E, 0xC9, 0x46, 0xEB, 0x8B}}
+CLSID_TaskbarList := &GUID{0x56FDF344, 0xFD6D, 0x11d0, {0x95, 0x8A, 0x00, 0x60, 0x97, 0xC9, 0xA0, 0x90}}
 
 IID_IFileDialog := &GUID{0x42F85136, 0xDB7E, 0x439C, {0x85, 0xF1, 0xE4, 0x07, 0x5D, 0x13, 0x5F, 0xC8}}
 IID_IFileSaveDialog := &GUID{0x84BCCD23, 0x5FDE, 0x4CDB, {0xAE, 0xA4, 0xAF, 0x64, 0xB8, 0x3D, 0x78, 0xAB}}
 IID_IFileOpenDialog := &GUID{0xD57C7288, 0xD4AD, 0x4768, {0xBE, 0x02, 0x9D, 0x96, 0x95, 0x32, 0xD9, 0x60}}
+IID_ITaskbarList := &GUID{0x56FDF342, 0xFD6D, 0x11d0, {0x95, 0x8A, 0x00, 0x60, 0x97, 0xC9, 0xA0, 0x90}}
+IID_ITaskbarList2 := &GUID{0x602D4995, 0xB13A, 0x429b, {0xA6, 0x6E, 0x19, 0x35, 0xE4, 0x4F, 0x43, 0x17}}
+IID_ITaskbarList3 := &GUID{0xea1afb91, 0x9e28, 0x4b86, {0x90, 0xe9, 0x9e, 0x9f, 0x8a, 0x5e, 0xef, 0xaf}}
 
 IModalWindow :: struct #raw_union {
 	#subtype IUnknown: IUnknown,
@@ -3358,6 +3555,84 @@ IFileSaveDialogVtbl :: struct {
 	ApplyProperties:        proc "stdcall" (this: ^IFileSaveDialog, psi: ^IShellItem, pStore: ^IPropertyStore, hwnd: HWND, pSink: ^IFileOperationProgressSink) -> HRESULT,
 }
 
+ITaskbarList :: struct #raw_union {
+	#subtype IUnknown: IUnknown,
+	using Vtbl: ^ITaskbarListVtbl,
+}
+ITaskbarListVtbl :: struct {
+	using IUnknownVtbl: IUnknownVtbl,
+	HrInit: proc "stdcall" (this: ^ITaskbarList) -> HRESULT,
+	AddTab: proc "stdcall" (this: ^ITaskbarList, hwnd: HWND) -> HRESULT,
+	DeleteTab: proc "stdcall" (this: ^ITaskbarList, hwnd: HWND) -> HRESULT,
+	ActivateTab: proc "stdcall" (this: ^ITaskbarList, hwnd: HWND) -> HRESULT,
+	SetActiveAlt: proc "stdcall" (this: ^ITaskbarList, hwnd: HWND) -> HRESULT,
+}
+
+ITaskbarList2 :: struct #raw_union {
+	#subtype ITaskbarList: ITaskbarList,
+	using Vtbl: ^ITaskbarList2Vtbl,
+}
+ITaskbarList2Vtbl :: struct {
+	using ITaskbarListVtbl: ITaskbarListVtbl,
+	MarkFullscreenWindow: proc "stdcall" (this: ^ITaskbarList2, hwnd: HWND, fFullscreen: BOOL) -> HRESULT,
+}
+
+TBPFLAG :: enum c_int {
+	NOPROGRESS    = 0,
+	INDETERMINATE = 0x1,
+	NORMAL        = 0x2,
+	ERROR         = 0x4,
+	PAUSED        = 0x8,
+}
+
+THUMBBUTTONFLAGS :: enum c_int {
+	ENABLED        = 0,
+	DISABLED       = 0x1,
+	DISMISSONCLICK = 0x2,
+	NOBACKGROUND   = 0x4,
+	HIDDEN         = 0x8,
+	NONINTERACTIVE = 0x10,
+}
+
+THUMBBUTTONMASK :: enum c_int {
+	BITMAP  = 0x1,
+	ICON    = 0x2,
+	TOOLTIP = 0x4,
+	FLAGS   = 0x8,
+}
+
+THUMBBUTTON :: struct {
+	dwMask: THUMBBUTTONMASK,
+	iId: UINT,
+	iBitmap: UINT,
+	hIcon: HICON,
+	szTip: [260]WCHAR,
+	dwFlags: THUMBBUTTONFLAGS,
+}
+LPTHUMBBUTTON :: ^THUMBBUTTON
+
+HIMAGELIST :: ^IUnknown
+
+ITaskbarList3 :: struct #raw_union {
+	#subtype ITaskbarList2: ITaskbarList2,
+	using Vtbl: ^ITaskbarList3Vtbl,
+}
+ITaskbarList3Vtbl :: struct {
+	using ITaskbarList2Vtbl: ITaskbarList2Vtbl,
+	SetProgressValue: proc "stdcall" (this: ^ITaskbarList3, hwnd: HWND, ullCompleted: ULONGLONG, ullTotal: ULONGLONG) -> HRESULT,
+	SetProgressState: proc "stdcall" (this: ^ITaskbarList3, hwnd: HWND, tbpFlags: TBPFLAG) -> HRESULT,
+	RegisterTab: proc "stdcall" (this: ^ITaskbarList3, hwndTab: HWND, hwndMDI: HWND) -> HRESULT,
+	UnregisterTab: proc "stdcall" (this: ^ITaskbarList3, hwndTab: HWND) -> HRESULT,
+	SetTabOrder: proc "stdcall" (this: ^ITaskbarList3, hwndTab: HWND, hwndInsertBefore: HWND) -> HRESULT,
+	SetTabActive: proc "stdcall" (this: ^ITaskbarList3, hwndTab: HWND, hwndMDI: HWND, dwReserved: DWORD) -> HRESULT,
+	ThumbBarAddButtons: proc "stdcall" (this: ^ITaskbarList3, hwnd: HWND, cButtons: UINT, pButton: LPTHUMBBUTTON) -> HRESULT,
+	ThumbBarUpdateButtons: proc "stdcall" (this: ^ITaskbarList3, hwnd: HWND, cButtons: UINT, pButton: LPTHUMBBUTTON) -> HRESULT,
+	ThumbBarSetImageList: proc "stdcall" (this: ^ITaskbarList3, hwnd: HWND, himl: HIMAGELIST) -> HRESULT,
+	SetOverlayIcon: proc "stdcall" (this: ^ITaskbarList3, hwnd: HWND, hIcon: HICON, pszDescription: LPCWSTR) -> HRESULT,
+	SetThumbnailTooltip: proc "stdcall" (this: ^ITaskbarList3, hwnd: HWND, pszTip: LPCWSTR) -> HRESULT,
+	SetThumbnailClip: proc "stdcall" (this: ^ITaskbarList3, hwnd: HWND, prcClip: ^RECT) -> HRESULT,
+}
+
 MEMORYSTATUSEX :: struct {
 	dwLength:                DWORD,
 	dwMemoryLoad:            DWORD,

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

@@ -78,6 +78,7 @@ foreign user32 {
 	LoadIconW :: proc(hInstance: HINSTANCE, lpIconName: LPCWSTR) -> HICON ---
 	LoadCursorA :: proc(hInstance: HINSTANCE, lpCursorName: LPCSTR) -> HCURSOR ---
 	LoadCursorW :: proc(hInstance: HINSTANCE, lpCursorName: LPCWSTR) -> HCURSOR ---
+	LoadImageW :: proc(hInst: HINSTANCE, name: LPCWSTR, type: UINT, cx: c_int, cy: c_int, fuLoad: UINT) -> HANDLE ---
 
 	GetWindowRect :: proc(hWnd: HWND, lpRect: LPRECT) -> BOOL ---
 	GetClientRect :: proc(hWnd: HWND, lpRect: LPRECT) -> BOOL ---

+ 4 - 4
core/sys/windows/util.odin

@@ -62,19 +62,19 @@ utf8_to_wstring :: proc(s: string, allocator := context.temp_allocator) -> wstri
 wstring_to_utf8 :: proc(s: wstring, N: int, allocator := context.temp_allocator) -> (res: string, err: runtime.Allocator_Error) {
 	context.allocator = allocator
 
-	if N <= 0 {
+	if N == 0 {
 		return
 	}
 
-	n := WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, s, i32(N), nil, 0, nil, nil)
+	n := WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, s, i32(N) if N > 0 else -1, nil, 0, nil, nil)
 	if n == 0 {
 		return
 	}
 
-	// If N == -1 the call to WideCharToMultiByte assume the wide string is null terminated
+	// If N < 0 the call to WideCharToMultiByte assume the wide string is null terminated
 	// and will scan it to find the first null terminated character. The resulting string will
 	// also be null terminated.
-	// If N != -1 it assumes the wide string is not null terminated and the resulting string
+	// If N > 0 it assumes the wide string is not null terminated and the resulting string
 	// will not be null terminated.
 	text := make([]byte, n) or_return
 

+ 3 - 0
core/sys/windows/window_messages.odin

@@ -454,6 +454,7 @@ TB_ISBUTTONENABLED                :: 0x0409
 TBM_CLEARTICS                     :: 0x0409
 TTM_SETTOOLINFOA                  :: 0x0409
 CBEM_HASEDITCHANGED               :: 0x040a
+PBM_SETMARQUEE                    :: 0x040a
 RB_INSERTBANDW                    :: 0x040a
 SB_GETRECT                        :: 0x040a
 TB_ISBUTTONCHECKED                :: 0x040a
@@ -488,10 +489,12 @@ TTM_ENUMTOOLSA                    :: 0x040e
 SB_SETICON                        :: 0x040f
 TBM_GETTICPOS                     :: 0x040f
 TTM_GETCURRENTTOOLA               :: 0x040f
+PBM_SETSTATE                      :: 0x0410
 RB_IDTOINDEX                      :: 0x0410
 SB_SETTIPTEXTA                    :: 0x0410
 TBM_GETNUMTICS                    :: 0x0410
 TTM_WINDOWFROMPOINT               :: 0x0410
+PBM_GETSTATE                      :: 0x0411
 RB_GETTOOLTIPS                    :: 0x0411
 SB_SETTIPTEXTW                    :: 0x0411
 TBM_GETSELSTART                   :: 0x0411

+ 34 - 32
core/time/time.odin

@@ -17,7 +17,7 @@ MAX_DURATION :: Duration(1<<63 - 1)
 IS_SUPPORTED :: _IS_SUPPORTED
 
 Time :: struct {
-	_nsec: i64, // zero is 1970-01-01 00:00:00
+	_nsec: i64, // Measured in UNIX nanonseconds
 }
 
 Month :: enum int {
@@ -59,36 +59,36 @@ sleep :: proc "contextless" (d: Duration) {
 	_sleep(d)
 }
 
-stopwatch_start :: proc(using stopwatch: ^Stopwatch) {
+stopwatch_start :: proc "contextless" (using stopwatch: ^Stopwatch) {
 	if !running {
 		_start_time = tick_now()
 		running = true
 	}
 }
 
-stopwatch_stop :: proc(using stopwatch: ^Stopwatch) {
+stopwatch_stop :: proc "contextless" (using stopwatch: ^Stopwatch) {
 	if running {
 		_accumulation += tick_diff(_start_time, tick_now())
 		running = false
 	}
 }
 
-stopwatch_reset :: proc(using stopwatch: ^Stopwatch) {
+stopwatch_reset :: proc "contextless" (using stopwatch: ^Stopwatch) {
 	_accumulation = {}
 	running = false
 }
 
-stopwatch_duration :: proc(using stopwatch: Stopwatch) -> Duration {
+stopwatch_duration :: proc "contextless" (using stopwatch: Stopwatch) -> Duration {
 	if !running { return _accumulation }
 	return _accumulation + tick_diff(_start_time, tick_now())
 }
 
-diff :: proc(start, end: Time) -> Duration {
+diff :: proc "contextless" (start, end: Time) -> Duration {
 	d := end._nsec - start._nsec
 	return Duration(d)
 }
 
-since :: proc(start: Time) -> Duration {
+since :: proc "contextless" (start: Time) -> Duration {
 	return diff(start, now())
 }
 
@@ -117,8 +117,8 @@ duration_hours :: proc "contextless" (d: Duration) -> f64 {
 	return f64(hour) + f64(nsec)/(60*60*1e9)
 }
 
-duration_round :: proc(d, m: Duration) -> Duration {
-	_less_than_half :: #force_inline proc(x, y: Duration) -> bool {
+duration_round :: proc "contextless" (d, m: Duration) -> Duration {
+	_less_than_half :: #force_inline proc "contextless" (x, y: Duration) -> bool {
 		return u64(x)+u64(x) < u64(y)
 	}
 
@@ -146,45 +146,45 @@ duration_round :: proc(d, m: Duration) -> Duration {
 	return MAX_DURATION
 }
 
-duration_truncate :: proc(d, m: Duration) -> Duration {
+duration_truncate :: proc "contextless" (d, m: Duration) -> Duration {
 	return d if m <= 0 else d - d%m
 }
 
-date :: proc(t: Time) -> (year: int, month: Month, day: int) {
+date :: proc "contextless" (t: Time) -> (year: int, month: Month, day: int) {
 	year, month, day, _ = _abs_date(_time_abs(t), true)
 	return
 }
 
-year :: proc(t: Time) -> (year: int) {
+year :: proc "contextless" (t: Time) -> (year: int) {
 	year, _, _, _ = _date(t, true)
 	return
 }
 
-month :: proc(t: Time) -> (month: Month) {
+month :: proc "contextless" (t: Time) -> (month: Month) {
 	_, month, _, _ = _date(t, true)
 	return
 }
 
-day :: proc(t: Time) -> (day: int) {
+day :: proc "contextless" (t: Time) -> (day: int) {
 	_, _, day, _ = _date(t, true)
 	return
 }
 
 clock :: proc { clock_from_time, clock_from_duration, clock_from_stopwatch }
 
-clock_from_time :: proc(t: Time) -> (hour, min, sec: int) {
+clock_from_time :: proc "contextless" (t: Time) -> (hour, min, sec: int) {
 	return clock_from_seconds(_time_abs(t))
 }
 
-clock_from_duration :: proc(d: Duration) -> (hour, min, sec: int) {
+clock_from_duration :: proc "contextless" (d: Duration) -> (hour, min, sec: int) {
 	return clock_from_seconds(u64(d/1e9))
 }
 
-clock_from_stopwatch :: proc(s: Stopwatch) -> (hour, min, sec: int) {
+clock_from_stopwatch :: proc "contextless" (s: Stopwatch) -> (hour, min, sec: int) {
 	return clock_from_duration(stopwatch_duration(s))
 }
 
-clock_from_seconds :: proc(nsec: u64) -> (hour, min, sec: int) {
+clock_from_seconds :: proc "contextless" (nsec: u64) -> (hour, min, sec: int) {
 	sec = int(nsec % SECONDS_PER_DAY)
 	hour = sec / SECONDS_PER_HOUR
 	sec -= hour * SECONDS_PER_HOUR
@@ -193,11 +193,11 @@ clock_from_seconds :: proc(nsec: u64) -> (hour, min, sec: int) {
 	return
 }
 
-read_cycle_counter :: proc() -> u64 {
+read_cycle_counter :: proc "contextless" () -> u64 {
 	return u64(intrinsics.read_cycle_counter())
 }
 
-unix :: proc(sec: i64, nsec: i64) -> Time {
+unix :: proc "contextless" (sec: i64, nsec: i64) -> Time {
 	sec, nsec := sec, nsec
 	if nsec < 0 || nsec >= 1e9 {
 		n := nsec / 1e9
@@ -208,20 +208,20 @@ unix :: proc(sec: i64, nsec: i64) -> Time {
 			sec -= 1
 		}
 	}
-	return Time{(sec*1e9 + nsec) + UNIX_TO_INTERNAL}
+	return Time{(sec*1e9 + nsec)}
 }
 
 to_unix_seconds :: time_to_unix
-time_to_unix :: proc(t: Time) -> i64 {
+time_to_unix :: proc "contextless" (t: Time) -> i64 {
 	return t._nsec/1e9
 }
 
 to_unix_nanoseconds :: time_to_unix_nano
-time_to_unix_nano :: proc(t: Time) -> i64 {
+time_to_unix_nano :: proc "contextless" (t: Time) -> i64 {
 	return t._nsec
 }
 
-time_add :: proc(t: Time, d: Duration) -> Time {
+time_add :: proc "contextless" (t: Time, d: Duration) -> Time {
 	return Time{t._nsec + i64(d)}
 }
 
@@ -231,7 +231,7 @@ time_add :: proc(t: Time, d: Duration) -> Time {
 // On Windows it depends but is comparable with regular sleep in the worst case.
 // To get the same kind of accuracy as on Linux, have your program call `win32.time_begin_period(1)` to
 // tell Windows to use a more accurate timer for your process.
-accurate_sleep :: proc(d: Duration) {
+accurate_sleep :: proc "contextless" (d: Duration) {
 	to_sleep, estimate, mean, m2, count: Duration
 
 	to_sleep = d
@@ -279,19 +279,19 @@ ABSOLUTE_TO_UNIX :: -UNIX_TO_ABSOLUTE
 
 
 @(private)
-_date :: proc(t: Time, full: bool) -> (year: int, month: Month, day: int, yday: int) {
+_date :: proc "contextless" (t: Time, full: bool) -> (year: int, month: Month, day: int, yday: int) {
 	year, month, day, yday = _abs_date(_time_abs(t), full)
 	return
 }
 
 @(private)
-_time_abs :: proc(t: Time) -> u64 {
+_time_abs :: proc "contextless" (t: Time) -> u64 {
 	return u64(t._nsec/1e9 + UNIX_TO_ABSOLUTE)
 }
 
 @(private)
-_abs_date :: proc(abs: u64, full: bool) -> (year: int, month: Month, day: int, yday: int) {
-	_is_leap_year :: proc(year: int) -> bool {
+_abs_date :: proc "contextless" (abs: u64, full: bool) -> (year: int, month: Month, day: int, yday: int) {
+	_is_leap_year :: proc "contextless" (year: int) -> bool {
 		return year%4 == 0 && (year%100 != 0 || year%400 == 0)
 	}
 
@@ -352,9 +352,11 @@ _abs_date :: proc(abs: u64, full: bool) -> (year: int, month: Month, day: int, y
 	return
 }
 
-datetime_to_time :: proc(year, month, day, hour, minute, second: int, nsec := int(0)) -> (t: Time, ok: bool) {
-	divmod :: proc(year: int, divisor: int) -> (div: int, mod: int) {
-		assert(divisor > 0)
+datetime_to_time :: proc "contextless" (year, month, day, hour, minute, second: int, nsec := int(0)) -> (t: Time, ok: bool) {
+	divmod :: proc "contextless" (year: int, divisor: int) -> (div: int, mod: int) {
+		if divisor <= 0 {
+			intrinsics.debug_trap()
+		}
 		div = int(year / divisor)
 		mod = year % divisor
 		return

+ 10 - 3
core/time/time_windows.odin

@@ -7,9 +7,16 @@ _IS_SUPPORTED :: true
 
 _now :: proc "contextless" () -> Time {
 	file_time: win32.FILETIME
-	win32.GetSystemTimeAsFileTime(&file_time)
-	ns := win32.FILETIME_as_unix_nanoseconds(file_time)
-	return Time{_nsec=ns}
+
+	ns: i64
+
+	// monotonic
+	win32.GetSystemTimePreciseAsFileTime(&file_time)
+
+	dt := u64(transmute(u64le)file_time) // in 100ns units
+	ns = i64((dt - 116444736000000000) * 100) // convert to ns
+
+	return unix(0, ns)
 }
 
 _sleep :: proc "contextless" (d: Duration) {

+ 1 - 1
src/big_int.cpp

@@ -71,7 +71,7 @@ void big_int_and    (BigInt *dst, BigInt const *x, BigInt const *y);
 void big_int_and_not(BigInt *dst, BigInt const *x, BigInt const *y);
 void big_int_xor    (BigInt *dst, BigInt const *x, BigInt const *y);
 void big_int_or     (BigInt *dst, BigInt const *x, BigInt const *y);
-void big_int_not    (BigInt *dst, BigInt const *x, u64 bit_count, bool is_signed);
+void big_int_not    (BigInt *dst, BigInt const *x, i32 bit_count, bool is_signed);
 
 
 void big_int_add_eq(BigInt *dst, BigInt const *x);

+ 2 - 2
src/check_builtin.cpp

@@ -1533,10 +1533,10 @@ bool check_builtin_procedure_directive(CheckerContext *c, Operand *operand, Ast
 		}
 
 		bool is_defined = check_identifier_exists(c->scope, arg);
-		gb_unused(is_defined);
+		// gb_unused(is_defined);
 		operand->type = t_untyped_bool;
 		operand->mode = Addressing_Constant;
-		operand->value = exact_value_bool(false);
+		operand->value = exact_value_bool(is_defined);
 
 	} else if (name == "config") {
 		if (ce->args.count != 2) {

+ 5 - 0
src/check_decl.cpp

@@ -1488,6 +1488,11 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty
 				if (!(e->flags & EntityFlag_Using)) {
 					continue;
 				}
+				if (is_blank_ident(e->token)) {
+                    error(e->token, "'using' a procedure parameter requires a non blank identifier");
+					break;
+				}
+
 				bool is_value = (e->flags & EntityFlag_Value) != 0 && !is_type_pointer(e->type);
 				String name = e->token.string;
 				Type *t = base_type(type_deref(e->type));

+ 64 - 16
src/check_expr.cpp

@@ -821,11 +821,12 @@ i64 check_distance_between_types(CheckerContext *c, Operand *operand, Type *type
 		if (are_types_identical(src, dst)) {
 			return 5;
 		}
-
-		Type *dst_elem = base_array_type(dst);
-		i64 distance = check_distance_between_types(c, operand, dst_elem);
-		if (distance >= 0) {
-			return distance + 7;
+		if (dst->Matrix.row_count == dst->Matrix.column_count) {
+			Type *dst_elem = base_array_type(dst);
+			i64 distance = check_distance_between_types(c, operand, dst_elem);
+			if (distance >= 0) {
+				return distance + 7;
+			}
 		}
 	}
 
@@ -2916,7 +2917,12 @@ bool check_transmute(CheckerContext *c, Ast *node, Operand *o, Type *t) {
 	// 	return false;
 	// }
 
-	if (is_type_untyped(o->type)) {
+	Type *src_t = o->type;
+	Type *dst_t = t;
+	Type *src_bt = base_type(src_t);
+	Type *dst_bt = base_type(dst_t);
+
+	if (is_type_untyped(src_t)) {
 		gbString expr_str = expr_to_string(o->expr);
 		error(o->expr, "Cannot transmute untyped expression: '%s'", expr_str);
 		gb_string_free(expr_str);
@@ -2925,7 +2931,6 @@ bool check_transmute(CheckerContext *c, Ast *node, Operand *o, Type *t) {
 		return false;
 	}
 
-	Type *dst_bt = base_type(t);
 	if (dst_bt == nullptr || dst_bt == t_invalid) {
 		GB_ASSERT(global_error_collector.count != 0);
 
@@ -2934,21 +2939,21 @@ bool check_transmute(CheckerContext *c, Ast *node, Operand *o, Type *t) {
 		return false;
 	}
 
-	Type *src_bt = base_type(o->type);
 	if (src_bt == nullptr || src_bt == t_invalid) {
 		// NOTE(bill): this should be an error
 		GB_ASSERT(global_error_collector.count != 0);
 		o->mode = Addressing_Value;
 		o->expr = node;
-		o->type = t;
+		o->type = dst_t;
 		return true;
 	}
 
-	i64 srcz = type_size_of(o->type);
-	i64 dstz = type_size_of(t);
+
+	i64 srcz = type_size_of(src_t);
+	i64 dstz = type_size_of(dst_t);
 	if (srcz != dstz) {
 		gbString expr_str = expr_to_string(o->expr);
-		gbString type_str = type_to_string(t);
+		gbString type_str = type_to_string(dst_t);
 		error(o->expr, "Cannot transmute '%s' to '%s', %lld vs %lld bytes", expr_str, type_str, srcz, dstz);
 		gb_string_free(type_str);
 		gb_string_free(expr_str);
@@ -2958,16 +2963,53 @@ bool check_transmute(CheckerContext *c, Ast *node, Operand *o, Type *t) {
 	}
 
 	if (build_context.vet_extra) {
-		if (are_types_identical(o->type, t)) {
-			gbString str = type_to_string(t);
+		if (are_types_identical(o->type, dst_t)) {
+			gbString str = type_to_string(dst_t);
 			warning(o->expr, "Unneeded transmute to the same type '%s'", str);
 			gb_string_free(str);
 		}
 	}
 
 	o->expr = node;
+	o->type = dst_t;
+	if (o->mode == Addressing_Constant) {
+		if (are_types_identical(src_bt, dst_bt)) {
+			return true;
+		}
+		if (is_type_integer(src_t) && is_type_integer(dst_t)) {
+			if (types_have_same_internal_endian(src_t, dst_t)) {
+				ExactValue src_v = exact_value_to_integer(o->value);
+				GB_ASSERT(src_v.kind == ExactValue_Integer);
+				BigInt v = src_v.value_integer;
+
+				BigInt smax = {};
+				BigInt umax = {};
+
+				big_int_from_u64(&smax, 0);
+				big_int_not(&smax, &smax, cast(i32)(srcz*8 - 1), false);
+
+				big_int_from_u64(&umax, 1);
+				BigInt sz_in_bits = big_int_make_i64(srcz*8);
+				big_int_shl_eq(&umax, &sz_in_bits);
+
+				if (is_type_unsigned(src_t) && !is_type_unsigned(dst_t)) {
+					if (big_int_cmp(&v, &smax) >= 0) {
+						big_int_sub_eq(&v, &umax);
+					}
+				} else if (!is_type_unsigned(src_t) && is_type_unsigned(dst_t)) {
+					if (big_int_is_neg(&v)) {
+						big_int_add_eq(&v, &umax);
+					}
+				}
+
+				o->value.kind = ExactValue_Integer;
+				o->value.value_integer = v;
+				return true;
+			}
+		}
+	}
+
 	o->mode = Addressing_Value;
-	o->type = t;
 	o->value = {};
 	return true;
 }
@@ -6413,7 +6455,9 @@ CallArgumentError check_polymorphic_record_type(CheckerContext *c, Operand *oper
 		if (e->kind == Entity_TypeName) {
 			if (o->mode != Addressing_Type) {
 				if (show_error) {
-					error(o->expr, "Expected a type for the argument '%.*s'", LIT(e->token.string));
+					gbString expr = expr_to_string(o->expr);
+					error(o->expr, "Expected a type for the argument '%.*s', got %s", LIT(e->token.string), expr);
+					gb_string_free(expr);
 				}
 				err = CallArgumentError_WrongTypes;
 			}
@@ -6456,6 +6500,10 @@ CallArgumentError check_polymorphic_record_type(CheckerContext *c, Operand *oper
 		// add_type_info_type(c, o->type);
 	}
 
+	if (show_error && err) {
+		return err;
+	}
+
 	{
 		bool failure = false;
 		Entity *found_entity = find_polymorphic_record_entity(c, original_type, param_count, ordered_operands, &failure);

+ 5 - 1
src/check_stmt.cpp

@@ -584,7 +584,11 @@ void check_label(CheckerContext *ctx, Ast *label, Ast *parent) {
 // Returns 'true' for 'continue', 'false' for 'return'
 bool check_using_stmt_entity(CheckerContext *ctx, AstUsingStmt *us, Ast *expr, bool is_selector, Entity *e) {
 	if (e == nullptr) {
-		error(us->token, "'using' applied to an unknown entity");
+		if (is_blank_ident(expr)) {
+			error(us->token, "'using' in a statement is not allowed with the blank identifier '_'");
+		} else {
+			error(us->token, "'using' applied to an unknown entity");
+		}
 		return true;
 	}
 

+ 18 - 18
src/llvm_abi.cpp

@@ -550,10 +550,10 @@ namespace lbAbiAmd64SysV {
 		if (is_mem_cls(cls, attribute_kind)) {
 			LLVMAttributeRef attribute = nullptr;
 			if (attribute_kind == Amd64TypeAttribute_ByVal) {
-				if (!is_calling_convention_odin(calling_convention)) {
+				// if (!is_calling_convention_odin(calling_convention)) {
 					return lb_arg_type_indirect_byval(c, type);
-				}
-				attribute = nullptr;
+				// }
+				// attribute = nullptr;
 			} else if (attribute_kind == Amd64TypeAttribute_StructRect) {
 				attribute = lb_create_enum_attribute_with_type(c, "sret", type);
 			}
@@ -982,13 +982,13 @@ namespace lbAbiArm64 {
 		}
 		return false;
 	}
-    
-    unsigned is_homogenous_aggregate_small_enough(LLVMTypeRef *base_type_, unsigned member_count_) {
-        return (member_count_ <= 4);
-    }
+
+	unsigned is_homogenous_aggregate_small_enough(LLVMTypeRef base_type, unsigned member_count) {
+		return (member_count <= 4);
+	}
 
 	lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef type, bool return_is_defined) {
-		LLVMTypeRef homo_base_type = {};
+		LLVMTypeRef homo_base_type = nullptr;
 		unsigned homo_member_count = 0;
 
 		if (!return_is_defined) {
@@ -996,16 +996,16 @@ namespace lbAbiArm64 {
 		} else if (is_register(type)) {
 			return non_struct(c, type);
 		} else if (is_homogenous_aggregate(c, type, &homo_base_type, &homo_member_count)) {
-            if(is_homogenous_aggregate_small_enough(&homo_base_type, homo_member_count)) {
-                return lb_arg_type_direct(type, LLVMArrayType(homo_base_type, homo_member_count), nullptr, nullptr);
-            } else {
-                //TODO(Platin): do i need to create stuff that can handle the diffrent return type?
-                //              else this needs a fix in llvm_backend_proc as we would need to cast it to the correct array type
-                
-                //LLVMTypeRef array_type = LLVMArrayType(homo_base_type, homo_member_count);
-                LLVMAttributeRef attr = lb_create_enum_attribute_with_type(c, "sret", type);
-                return lb_arg_type_indirect(type, attr);
-            }
+			if (is_homogenous_aggregate_small_enough(homo_base_type, homo_member_count)) {
+				return lb_arg_type_direct(type, LLVMArrayType(homo_base_type, homo_member_count), nullptr, nullptr);
+			} else {
+				//TODO(Platin): do i need to create stuff that can handle the diffrent return type?
+				//              else this needs a fix in llvm_backend_proc as we would need to cast it to the correct array type
+
+				//LLVMTypeRef array_type = LLVMArrayType(homo_base_type, homo_member_count);
+				LLVMAttributeRef attr = lb_create_enum_attribute_with_type(c, "sret", type);
+				return lb_arg_type_indirect(type, attr);
+			}
 		} else {
 			i64 size = lb_sizeof(type);
 			if (size <= 16) {

+ 1 - 0
src/llvm_backend_debug.cpp

@@ -293,6 +293,7 @@ LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) {
 	case Type_Named:
 		GB_PANIC("Type_Named should be handled in lb_debug_type separately");
 
+	case Type_SoaPointer:
 	case Type_Pointer:
 		return LLVMDIBuilderCreatePointerType(m->debug_builder, lb_debug_type(m, type->Pointer.elem), word_bits, word_bits, 0, nullptr, 0);
 	case Type_MultiPointer:

+ 14 - 0
src/llvm_backend_proc.cpp

@@ -753,12 +753,16 @@ lbValue lb_emit_call_internal(lbProcedure *p, lbValue value, lbValue return_ptr,
 		}
 		GB_ASSERT_MSG(lb_is_type_kind(fnp, LLVMFunctionTypeKind), "%s", LLVMPrintTypeToString(fnp));
 
+		lbFunctionType *ft = map_must_get(&p->module->function_type_map, base_type(value.type));
+
 		{
 			unsigned param_count = LLVMCountParamTypes(fnp);
 			GB_ASSERT(arg_count >= param_count);
 
 			LLVMTypeRef *param_types = gb_alloc_array(temporary_allocator(), LLVMTypeRef, param_count);
 			LLVMGetParamTypes(fnp, param_types);
+
+
 			for (unsigned i = 0; i < param_count; i++) {
 				LLVMTypeRef param_type = param_types[i];
 				LLVMTypeRef arg_type = LLVMTypeOf(args[i]);
@@ -776,10 +780,20 @@ lbValue lb_emit_call_internal(lbProcedure *p, lbValue value, lbValue return_ptr,
 
 		LLVMValueRef ret = LLVMBuildCall2(p->builder, fnp, fn, args, arg_count, "");
 
+		LLVMAttributeIndex param_offset = LLVMAttributeIndex_FirstArgIndex;
 		if (return_ptr.value != nullptr) {
+			param_offset += 1;
+
 			LLVMAddCallSiteAttribute(ret, 1, lb_create_enum_attribute_with_type(p->module->ctx, "sret", LLVMTypeOf(args[0])));
 		}
 
+		for_array(i, ft->args) {
+			LLVMAttributeRef attribute = ft->args[i].attribute;
+			if (attribute != nullptr) {
+				LLVMAddCallSiteAttribute(ret, param_offset + cast(LLVMAttributeIndex)i, attribute);
+			}
+		}
+
 		switch (inlining) {
 		case ProcInlining_none:
 			break;

+ 12 - 4
tests/issues/run.bat

@@ -1,15 +1,23 @@
 @echo off
 
 if not exist "build\" mkdir build
+pushd build
 
-set COMMON=-collection:tests=..
+set COMMON=-collection:tests=..\..
+
+set ERROR_DID_OCCUR=0
 
 @echo on
 
-..\..\odin test test_issue_829.odin %COMMON% -file
-..\..\odin test test_issue_1592.odin %COMMON% -file
-..\..\odin test test_issue_2087.odin %COMMON% -file
+..\..\..\odin test ..\test_issue_829.odin %COMMON% -file
+..\..\..\odin test ..\test_issue_1592.odin %COMMON% -file
+..\..\..\odin test ..\test_issue_2087.odin %COMMON% -file
+..\..\..\odin build ..\test_issue_2113.odin %COMMON% -file -debug
 
 @echo off
 
+if %ERRORLEVEL% NEQ 0 set ERROR_DID_OCCUR=1
+
+popd
 rmdir /S /Q build
+if %ERROR_DID_OCCUR% NEQ 0 EXIT /B 1

+ 8 - 5
tests/issues/run.sh

@@ -2,15 +2,18 @@
 set -eu
 
 mkdir -p build
-ODIN=../../odin
-COMMON="-collection:tests=.."
+pushd build
+ODIN=../../../odin
+COMMON="-collection:tests=../.."
 
 set -x
 
-$ODIN test test_issue_829.odin  $COMMON -file
-$ODIN test test_issue_1592.odin $COMMON -file
-$ODIN test test_issue_2087.odin $COMMON -file
+$ODIN test ../test_issue_829.odin  $COMMON -file
+$ODIN test ../test_issue_1592.odin $COMMON -file
+$ODIN test ../test_issue_2087.odin $COMMON -file
+$ODIN build ../test_issue_2113.odin $COMMON -file -debug
 
 set +x
 
+popd
 rm -rf build

+ 5 - 1
tests/issues/test_issue_2087.odin

@@ -10,9 +10,13 @@ test_parse_float :: proc(t: ^testing.T) {
 	{
 		f, ok := strconv.parse_f64("1.2")
 		testing.expect(t, ok && f == 1.2, "expected f64(1.2), fully consumed")
-
 		f, ok = strconv.parse_f64("1.2a")
 		testing.expect(t, !ok && f == 1.2, "expected f64(1.2), partially consumed")
+		f, ok = strconv.parse_f64("+")
+		testing.expect(t, !ok && f == 0.0, "expected f64(0.0), with ok=false")
+		f, ok = strconv.parse_f64("-")
+		testing.expect(t, !ok && f == 0.0, "expected f64(0.0), with ok=false")
+
 
 		f, ok = strconv.parse_f64("inf")
 		testing.expect(t, ok && math.classify(f) == math.Float_Class.Inf, "expected f64(+inf), fully consumed")

+ 13 - 0
tests/issues/test_issue_2113.odin

@@ -0,0 +1,13 @@
+// Tests issue #2113 https://github.com/odin-lang/Odin/issues/2113
+// Causes a panic on compilation
+package test_issues
+
+T :: struct {
+    a: int,
+}
+
+main :: proc() {
+    array: #soa[1]T
+    a := &array[0]
+    _ = a
+}

+ 3 - 3
vendor/darwin/Foundation/NSApplication.odin

@@ -11,7 +11,7 @@ ActivationPolicy :: enum UInteger {
 ApplicationDelegate :: struct {
 	willFinishLaunching:                  proc "c" (self: ^ApplicationDelegate, notification: ^Notification),
 	didFinishLaunching:                   proc "c" (self: ^ApplicationDelegate, notification: ^Notification),
-	shouldTerminateAfterLastWindowClosed: proc "c" (self: ^ApplicationDelegate, sender: ^Application),
+	shouldTerminateAfterLastWindowClosed: proc "c" (self: ^ApplicationDelegate, sender: ^Application) -> BOOL,
 
 	user_data: rawptr,
 }
@@ -34,9 +34,9 @@ Application_setDelegate :: proc(self: ^Application, delegate: ^ApplicationDelega
 		del := (^ApplicationDelegate)(self->pointerValue())
 		del->didFinishLaunching(notification)
 	}
-	shouldTerminateAfterLastWindowClosed :: proc "c" (self: ^Value, _: SEL, application: ^Application) {
+	shouldTerminateAfterLastWindowClosed :: proc "c" (self: ^Value, _: SEL, application: ^Application) -> BOOL {
 		del := (^ApplicationDelegate)(self->pointerValue())
-		del->shouldTerminateAfterLastWindowClosed(application)
+		return del->shouldTerminateAfterLastWindowClosed(application)
 	}
 
 	wrapper := Value.valueWithPointer(delegate)

+ 16 - 0
vendor/darwin/Foundation/NSWindow.odin

@@ -156,6 +156,22 @@ Window_makeKeyAndOrderFront :: proc(self: ^Window, key: ^NS.Object) {
 Window_setTitle :: proc(self: ^Window, title: ^NS.String) {
 	msgSend(nil, self, "setTitle:", title)
 }
+@(objc_type=Window, objc_name="setTitlebarAppearsTransparent")
+Window_setTitlebarAppearsTransparent :: proc(self: ^Window, ok: NS.BOOL) {
+	msgSend(nil, self, "setTitlebarAppearsTransparent:", ok)
+}
+@(objc_type=Window, objc_name="setMovable")
+Window_setMovable :: proc(self: ^Window, ok: NS.BOOL) {
+	msgSend(nil, self, "setMovable:", ok)
+}
+@(objc_type=Window, objc_name="setMovableByWindowBackground")
+Window_setMovableByWindowBackground :: proc(self: ^Window, ok: NS.BOOL) {
+	msgSend(nil, self, "setMovableByWindowBackground:", ok)
+}
+@(objc_type=Window, objc_name="setStyleMask")
+Window_setStyleMask :: proc(self: ^Window, style_mask: WindowStyleMask) {
+	msgSend(nil, self, "setStyleMask:", style_mask)
+}
 @(objc_type=Window, objc_name="close")
 Window_close :: proc(self: ^Window) {
 	msgSend(nil, self, "close")

+ 5 - 1
vendor/darwin/Foundation/objc.odin

@@ -10,9 +10,13 @@ IMP :: proc "c" (object: id, sel: SEL, #c_vararg args: ..any) -> id
 foreign Foundation {
 	objc_lookUpClass       :: proc "c" (name: cstring) -> Class ---
 	sel_registerName       :: proc "c" (name: cstring) -> SEL ---
-	objc_allocateClassPair :: proc "c" (superclass: Class, name: cstring, extraBytes: uint) ---
+	objc_allocateClassPair :: proc "c" (superclass : Class, name : cstring, extraBytes : c.size_t) -> Class ---
+	objc_registerClassPair :: proc "c" (cls : Class) ---
 
 	class_addMethod :: proc "c" (cls: Class, name: SEL, imp: IMP, types: cstring) -> BOOL ---
+	class_getInstanceMethod :: proc "c" (cls: Class, name: SEL) -> Method ---
+
+	method_setImplementation :: proc "c" (method: Method, imp: IMP) ---
 }
 
 

+ 183 - 141
vendor/directx/d3d11/d3d11.odin

@@ -30,7 +30,7 @@ foreign d3d11 {
 		DriverType:         DRIVER_TYPE,
 		Software:           HMODULE,
 		Flags:              CREATE_DEVICE_FLAGS,
-		pFeatureLevels:     ^FEATURE_LEVEL,
+		pFeatureLevels:     [^]FEATURE_LEVEL,
 		FeatureLevels:      u32,
 		SDKVersion:         u32,
 		ppDevice:           ^^IDevice,
@@ -41,8 +41,8 @@ foreign d3d11 {
 		pAdapter:           ^dxgi.IAdapter,
 		DriverType:         DRIVER_TYPE,
 		Software:           HMODULE,
-		Flags:              u32,
-		pFeatureLevels:     ^FEATURE_LEVEL,
+		Flags:              CREATE_DEVICE_FLAGS,
+		pFeatureLevels:     [^]FEATURE_LEVEL,
 		FeatureLevels:      u32,
 		SDKVersion:         u32,
 		pSwapChainDesc:     ^dxgi.SWAP_CHAIN_DESC,
@@ -539,24 +539,36 @@ ANISOTROPIC_FILTERING_BIT :: 0x40
 SDK_VERSION :: 7
 RETURN_PARAMETER_INDEX :: -1
 
-COMPONENT_MASK :: enum u32 { // TODO: make bit_set
+COMPONENT_MASK :: distinct bit_set[COMPONENT_MASK_ELEMENT; u32]
+COMPONENT_MASK_ELEMENT :: enum u32 {
 	X = 1,
 	Y = 2,
 	Z = 4,
 	W = 8,
 }
 
-SHADER_REQUIRES :: enum u32 { // TODO: make bit_set
-	DOUBLES                      = 0x00000001,
-	EARLY_DEPTH_STENCIL          = 0x00000002,
-	UAVS_AT_EVERY_STAGE          = 0x00000004,
-	_64_UAVS                     = 0x00000008,
-	MINIMUM_PRECISION            = 0x00000010,
-	_11_1_DOUBLE_EXTENSIONS      = 0x00000020,
-	_11_1_SHADER_EXTENSIONS      = 0x00000040,
-	LEVEL_9_COMPARISON_FILTERING = 0x00000080,
-	TILED_RESOURCES              = 0x00000100,
-}
+SHADER_REQUIRES_FLAGS :: distinct bit_set[SHADER_REQUIRES_FLAG; u64]
+SHADER_REQUIRES_FLAG :: enum u64 {
+	DOUBLES                      = 0,
+	EARLY_DEPTH_STENCIL          = 1,
+	UAVS_AT_EVERY_STAGE          = 2,
+	_64_UAVS                     = 3,
+	MINIMUM_PRECISION            = 4,
+	_11_1_DOUBLE_EXTENSIONS      = 5,
+	_11_1_SHADER_EXTENSIONS      = 6,
+	LEVEL_9_COMPARISON_FILTERING = 7,
+	TILED_RESOURCES              = 8,
+}
+
+SHADER_REQUIRES_DOUBLES                      :: SHADER_REQUIRES_FLAGS{.DOUBLES}
+SHADER_REQUIRES_EARLY_DEPTH_STENCIL          :: SHADER_REQUIRES_FLAGS{.EARLY_DEPTH_STENCIL}
+SHADER_REQUIRES_UAVS_AT_EVERY_STAGE          :: SHADER_REQUIRES_FLAGS{.UAVS_AT_EVERY_STAGE}
+SHADER_REQUIRES_64_UAVS                      :: SHADER_REQUIRES_FLAGS{._64_UAVS}
+SHADER_REQUIRES_MINIMUM_PRECISION            :: SHADER_REQUIRES_FLAGS{.MINIMUM_PRECISION}
+SHADER_REQUIRES_11_1_DOUBLE_EXTENSIONS       :: SHADER_REQUIRES_FLAGS{._11_1_DOUBLE_EXTENSIONS}
+SHADER_REQUIRES_11_1_SHADER_EXTENSIONS       :: SHADER_REQUIRES_FLAGS{._11_1_SHADER_EXTENSIONS}
+SHADER_REQUIRES_LEVEL_9_COMPARISON_FILTERING :: SHADER_REQUIRES_FLAGS{.LEVEL_9_COMPARISON_FILTERING}
+SHADER_REQUIRES_TILED_RESOURCES              :: SHADER_REQUIRES_FLAGS{.TILED_RESOURCES}
 
 DRIVER_TYPE :: enum i32 {
 	UNKNOWN   = 0,
@@ -708,11 +720,12 @@ SHADER_VARIABLE_CLASS :: enum i32 {
 	INTERFACE_POINTER     = 7,
 }
 
-SHADER_VARIABLE_FLAGS :: enum u32 { // TODO: make bit_set
-	USERPACKED              = 0x1,
-	USED                    = 0x2,
-	INTERFACE_POINTER       = 0x4,
-	INTERFACE_PARAMETER     = 0x8,
+SHADER_VARIABLE_FLAGS :: distinct bit_set[SHADER_VARIABLE_FLAG; u32]
+SHADER_VARIABLE_FLAG :: enum u32 {
+	USERPACKED              = 0,
+	USED                    = 1,
+	INTERFACE_POINTER       = 2,
+	INTERFACE_PARAMETER     = 3,
 }
 
 SHADER_VARIABLE_TYPE :: enum i32 {
@@ -776,14 +789,21 @@ SHADER_VARIABLE_TYPE :: enum i32 {
 	MIN16UINT                     = 57,
 }
 
-SHADER_INPUT_FLAGS :: enum u32 { // TODO: make bit_set
-	USERPACKED          = 0x1,
-	COMPARISON_SAMPLER  = 0x2,
-	TEXTURE_COMPONENT_0 = 0x4,
-	TEXTURE_COMPONENT_1 = 0x8,
+SHADER_INPUT_FLAGS :: distinct bit_set[SHADER_INPUT_FLAG; u32]
+SHADER_INPUT_FLAG :: enum u32 {
+	USERPACKED          = 0,
+	COMPARISON_SAMPLER  = 1,
+	TEXTURE_COMPONENT_0 = 2,
+	TEXTURE_COMPONENT_1 = 3,
 	TEXTURE_COMPONENTS  = 0xc,
-	UNUSED              = 0x10,
+	UNUSED              = 4,
 }
+SHADER_INPUT_FLAG_USERPACKED          :: SHADER_INPUT_FLAGS{.USERPACKED}
+SHADER_INPUT_FLAG_COMPARISON_SAMPLER  :: SHADER_INPUT_FLAGS{.COMPARISON_SAMPLER}
+SHADER_INPUT_FLAG_TEXTURE_COMPONENT_0 :: SHADER_INPUT_FLAGS{.TEXTURE_COMPONENT_0}
+SHADER_INPUT_FLAG_TEXTURE_COMPONENT_1 :: SHADER_INPUT_FLAGS{.TEXTURE_COMPONENT_1}
+SHADER_INPUT_FLAG_TEXTURE_COMPONENTS  :: SHADER_INPUT_FLAGS{.TEXTURE_COMPONENT_0, .TEXTURE_COMPONENT_1}
+SHADER_INPUT_FLAG_UNUSED              :: SHADER_INPUT_FLAGS{.UNUSED}
 
 SHADER_INPUT_TYPE :: enum i32 {
 	CBUFFER                       = 0,
@@ -802,8 +822,9 @@ SHADER_INPUT_TYPE :: enum i32 {
 	UAV_FEEDBACKTEXTURE           = 13,
 }
 
-SHADER_CBUFFER_FLAGS :: enum u32 { // TODO: make bit_set
-	USERPACKED = 0x1,
+SHADER_CBUFFER_FLAGS :: distinct bit_set[SHADER_CBUFFER_FLAG; u32]
+SHADER_CBUFFER_FLAG :: enum u32 {
+	USERPACKED = 0,
 }
 
 CBUFFER_TYPE :: enum i32 {
@@ -906,10 +927,10 @@ INTERPOLATION_MODE :: enum i32 {
 	LINEAR_NOPERSPECTIVE_SAMPLE   = 7,
 }
 
-PARAMETER_FLAGS :: enum u32 { // TODO: make bit_set
-	NONE = 0x0,
-	IN   = 0x1,
-	OUT  = 0x2,
+PARAMETER_FLAGS :: distinct bit_set[PARAMETER_FLAG; u32]
+PARAMETER_FLAG :: enum u32 {
+	IN   = 0,
+	OUT  = 1,
 }
 
 CDEFAULT :: struct {
@@ -1022,43 +1043,46 @@ USAGE :: enum i32 {
 	STAGING   = 3,
 }
 
-BIND_FLAG :: enum u32 { // TODO: make bit_set
-	VERTEX_BUFFER    = 0x1,
-	INDEX_BUFFER     = 0x2,
-	CONSTANT_BUFFER  = 0x4,
-	SHADER_RESOURCE  = 0x8,
-	STREAM_OUTPUT    = 0x10,
-	RENDER_TARGET    = 0x20,
-	DEPTH_STENCIL    = 0x40,
-	UNORDERED_ACCESS = 0x80,
-	DECODER          = 0x200,
-	VIDEO_ENCODER    = 0x400,
-}
-
-CPU_ACCESS_FLAG :: enum u32 { // TODO: make bit_set
-	WRITE = 0x10000,
-	READ  = 0x20000,
-
-}
-
-RESOURCE_MISC_FLAG :: enum u32 { // TODO: make bit_set
-	GENERATE_MIPS                   = 0x1,
-	SHARED                          = 0x2,
-	TEXTURECUBE                     = 0x4,
-	DRAWINDIRECT_ARGS               = 0x10,
-	BUFFER_ALLOW_RAW_VIEWS          = 0x20,
-	BUFFER_STRUCTURED               = 0x40,
-	RESOURCE_CLAMP                  = 0x80,
-	SHARED_KEYEDMUTEX               = 0x100,
-	GDI_COMPATIBLE                  = 0x200,
-	SHARED_NTHANDLE                 = 0x800,
-	RESTRICTED_CONTENT              = 0x1000,
-	RESTRICT_SHARED_RESOURCE        = 0x2000,
-	RESTRICT_SHARED_RESOURCE_DRIVER = 0x4000,
-	GUARDED                         = 0x8000,
-	TILE_POOL                       = 0x20000,
-	TILED                           = 0x40000,
-	HW_PROTECTED                    = 0x80000,
+BIND_FLAGS :: distinct bit_set[BIND_FLAG; u32]
+BIND_FLAG :: enum u32 {
+	VERTEX_BUFFER    = 0,
+	INDEX_BUFFER     = 1,
+	CONSTANT_BUFFER  = 2,
+	SHADER_RESOURCE  = 3,
+	STREAM_OUTPUT    = 4,
+	RENDER_TARGET    = 5,
+	DEPTH_STENCIL    = 6,
+	UNORDERED_ACCESS = 7,
+	DECODER          = 9,
+	VIDEO_ENCODER    = 10,
+}
+
+CPU_ACCESS_FLAGS :: distinct bit_set[CPU_ACCESS_FLAG; u32]
+CPU_ACCESS_FLAG :: enum u32 {
+	WRITE = 16,
+	READ  = 17,
+
+}
+
+RESOURCE_MISC_FLAGS :: distinct bit_set[RESOURCE_MISC_FLAG; u32]
+RESOURCE_MISC_FLAG :: enum u32 {
+	GENERATE_MIPS                   = 0,
+	SHARED                          = 1,
+	TEXTURECUBE                     = 2,
+	DRAWINDIRECT_ARGS               = 4,
+	BUFFER_ALLOW_RAW_VIEWS          = 5,
+	BUFFER_STRUCTURED               = 6,
+	RESOURCE_CLAMP                  = 7,
+	SHARED_KEYEDMUTEX               = 8,
+	GDI_COMPATIBLE                  = 9,
+	SHARED_NTHANDLE                 = 11,
+	RESTRICTED_CONTENT              = 12,
+	RESTRICT_SHARED_RESOURCE        = 13,
+	RESTRICT_SHARED_RESOURCE_DRIVER = 14,
+	GUARDED                         = 15,
+	TILE_POOL                       = 17,
+	TILED                           = 18,
+	HW_PROTECTED                    = 19,
 }
 
 MAP :: enum i32 {
@@ -1069,17 +1093,20 @@ MAP :: enum i32 {
 	WRITE_NO_OVERWRITE = 5,
 }
 
-MAP_FLAG :: enum u32 { // TODO: make bit_set
-	DO_NOT_WAIT = 0x100000,
+MAP_FLAGS :: distinct bit_set[MAP_FLAG; u32]
+MAP_FLAG :: enum u32 {
+	DO_NOT_WAIT = 20,
 }
 
-RAISE_FLAG :: enum u32 { // TODO: make bit_set
-	DRIVER_INTERNAL_ERROR = 0x1,
+RAISE_FLAGS :: distinct bit_set[RAISE_FLAG; u32]
+RAISE_FLAG :: enum u32 {
+	DRIVER_INTERNAL_ERROR = 0,
 }
 
-CLEAR_FLAG :: enum u32 { // TODO: make bit_set
-	DEPTH   = 0x1,
-	STENCIL = 0x2,
+CLEAR_FLAGS :: distinct bit_set[CLEAR_FLAG; u32]
+CLEAR_FLAG :: enum u32 {
+	DEPTH   = 0,
+	STENCIL = 1,
 }
 
 
@@ -1206,7 +1233,15 @@ BLEND_OP :: enum i32 {
 	MAX          = 5,
 }
 
-COLOR_WRITE_ENABLE :: enum i32 { // TODO: make bit_set
+COLOR_WRITE_ENABLE_MASK   :: distinct bit_set[COLOR_WRITE_ENABLE; u32]
+
+COLOR_WRITE_ENABLE_RED   :: COLOR_WRITE_ENABLE_MASK{.RED}
+COLOR_WRITE_ENABLE_GREEN :: COLOR_WRITE_ENABLE_MASK{.GREEN}
+COLOR_WRITE_ENABLE_BLUE  :: COLOR_WRITE_ENABLE_MASK{.BLUE}
+COLOR_WRITE_ENABLE_ALPHA :: COLOR_WRITE_ENABLE_MASK{.ALPHA}
+COLOR_WRITE_ENABLE_ALL   :: COLOR_WRITE_ENABLE_MASK{.RED, .GREEN, .BLUE, .ALPHA}
+
+COLOR_WRITE_ENABLE :: enum i32 {
 	RED   = 1,
 	GREEN = 2,
 	BLUE  = 4,
@@ -1308,9 +1343,9 @@ IResource_VTable :: struct {
 BUFFER_DESC :: struct {
 	ByteWidth:           u32,
 	Usage:               USAGE,
-	BindFlags:           BIND_FLAG,
-	CPUAccessFlags:      CPU_ACCESS_FLAG,
-	MiscFlags:           RESOURCE_MISC_FLAG,
+	BindFlags:           BIND_FLAGS,
+	CPUAccessFlags:      CPU_ACCESS_FLAGS,
+	MiscFlags:           RESOURCE_MISC_FLAGS,
 	StructureByteStride: u32,
 }
 
@@ -1337,9 +1372,9 @@ TEXTURE1D_DESC :: struct {
 	ArraySize:      u32,
 	Format:         dxgi.FORMAT,
 	Usage:          USAGE,
-	BindFlags:      BIND_FLAG,
-	CPUAccessFlags: CPU_ACCESS_FLAG,
-	MiscFlags:      RESOURCE_MISC_FLAG,
+	BindFlags:      BIND_FLAGS,
+	CPUAccessFlags: CPU_ACCESS_FLAGS,
+	MiscFlags:      RESOURCE_MISC_FLAGS,
 }
 
 CTEXTURE1D_DESC :: struct {
@@ -1367,9 +1402,9 @@ TEXTURE2D_DESC :: struct {
 	Format:         dxgi.FORMAT,
 	SampleDesc:     dxgi.SAMPLE_DESC,
 	Usage:          USAGE,
-	BindFlags:      BIND_FLAG,
-	CPUAccessFlags: CPU_ACCESS_FLAG,
-	MiscFlags:      RESOURCE_MISC_FLAG,
+	BindFlags:      BIND_FLAGS,
+	CPUAccessFlags: CPU_ACCESS_FLAGS,
+	MiscFlags:      RESOURCE_MISC_FLAGS,
 }
 
 CTEXTURE2D_DESC :: struct {
@@ -1396,9 +1431,9 @@ TEXTURE3D_DESC :: struct {
 	MipLevels:      u32,
 	Format:         dxgi.FORMAT,
 	Usage:          USAGE,
-	BindFlags:      BIND_FLAG,
-	CPUAccessFlags: CPU_ACCESS_FLAG,
-	MiscFlags:      RESOURCE_MISC_FLAG,
+	BindFlags:      BIND_FLAGS,
+	CPUAccessFlags: CPU_ACCESS_FLAGS,
+	MiscFlags:      RESOURCE_MISC_FLAGS,
 }
 
 CTEXTURE3D_DESC :: struct {
@@ -1451,14 +1486,15 @@ BUFFER_SRV :: struct {
 	},
 }
 
-BUFFEREX_SRV_FLAG :: enum u32 { // TODO: make bit_set
-	RAW = 0x1,
+BUFFEREX_SRV_FLAGS :: distinct bit_set[BUFFEREX_SRV_FLAG; u32]
+BUFFEREX_SRV_FLAG :: enum u32 {
+	RAW = 0,
 }
 
 BUFFEREX_SRV :: struct {
 	FirstElement: u32,
 	NumElements:  u32,
-	Flags:        u32,
+	Flags:        BUFFEREX_SRV_FLAGS,
 }
 
 TEX1D_SRV :: struct {
@@ -1657,15 +1693,16 @@ TEX2DMS_ARRAY_DSV :: struct {
 	ArraySize:       u32,
 }
 
-DSV_FLAG :: enum u32 { // TODO: make bit_set
-	DEPTH   = 0x1,
-	STENCIL = 0x2,
+DSV_FLAGS :: distinct bit_set[DSV_FLAG; u32]
+DSV_FLAG :: enum u32 {
+	DEPTH   = 0,
+	STENCIL = 1,
 }
 
 DEPTH_STENCIL_VIEW_DESC :: struct {
 	Format:        dxgi.FORMAT,
 	ViewDimension: DSV_DIMENSION,
-	Flags:         u32,
+	Flags:         DSV_FLAGS,
 	using _: struct #raw_union {
 		Texture1D:        TEX1D_DSV,
 		Texture1DArray:   TEX1D_ARRAY_DSV,
@@ -1693,16 +1730,17 @@ IDepthStencilView_VTable :: struct {
 }
 
 
-BUFFER_UAV_FLAG :: enum u32 { // TODO: make bit_set
-	RAW     = 0x1,
-	APPEND  = 0x2,
-	COUNTER = 0x4,
+BUFFER_UAV_FLAGS :: distinct bit_set[BUFFER_UAV_FLAG; u32]
+BUFFER_UAV_FLAG :: enum u32 {
+	RAW     = 0,
+	APPEND  = 1,
+	COUNTER = 2,
 }
 
 BUFFER_UAV :: struct {
 	FirstElement: u32,
 	NumElements:  u32,
-	Flags:        u32,
+	Flags:        BUFFER_UAV_FLAGS,
 }
 
 TEX1D_UAV :: struct {
@@ -1961,8 +1999,9 @@ IAsynchronous_VTable :: struct {
 }
 
 
-ASYNC_GETDATA_FLAG :: enum u32 { // TODO: make bit_set
-	DONOTFLUSH = 0x1,
+ASYNC_GETDATA_FLAGS :: distinct bit_set[ASYNC_GETDATA_FLAG; u32]
+ASYNC_GETDATA_FLAG :: enum u32 {
+	DONOTFLUSH = 0,
 }
 
 QUERY :: enum i32 {
@@ -1984,13 +2023,14 @@ QUERY :: enum i32 {
 	SO_OVERFLOW_PREDICATE_STREAM3 = 15,
 }
 
-QUERY_MISC_FLAG :: enum u32 { // TODO: make bit_set
-	QUERY_MISC_PREDICATEHINT = 0x1,
+QUERY_MISC_FLAGS :: distinct bit_set[QUERY_MISC_FLAG; u32]
+QUERY_MISC_FLAG :: enum u32 {
+	PREDICATEHINT = 0,
 }
 
 QUERY_DESC :: struct {
 	Query:     QUERY,
-	MiscFlags: RESOURCE_MISC_FLAG,
+	MiscFlags: QUERY_MISC_FLAGS,
 }
 
 CQUERY_DESC :: struct {
@@ -2054,7 +2094,7 @@ COUNTER_TYPE :: enum i32 {
 
 COUNTER_DESC :: struct {
 	Counter:   COUNTER,
-	MiscFlags: RESOURCE_MISC_FLAG,
+	MiscFlags: RESOURCE_MISC_FLAGS,
 }
 
 CCOUNTER_DESC :: struct {
@@ -2150,21 +2190,21 @@ FEATURE :: enum i32 {
 	FORMAT_SUPPORT                 = 2,
 	FORMAT_SUPPORT2                = 3,
 	D3D10_X_HARDWARE_OPTIONS       = 4,
-	OPTIONS                  = 5,
+	OPTIONS                        = 5,
 	ARCHITECTURE_INFO              = 6,
 	D3D9_OPTIONS                   = 7,
 	SHADER_MIN_PRECISION_SUPPORT   = 8,
 	D3D9_SHADOW_SUPPORT            = 9,
-	OPTIONS1                 = 10,
+	OPTIONS1                       = 10,
 	D3D9_SIMPLE_INSTANCING_SUPPORT = 11,
 	MARKER_SUPPORT                 = 12,
 	D3D9_OPTIONS1                  = 13,
-	OPTIONS2                 = 14,
-	OPTIONS3                 = 15,
+	OPTIONS2                       = 14,
+	OPTIONS3                       = 15,
 	GPU_VIRTUAL_ADDRESS_SUPPORT    = 16,
-	OPTIONS4                 = 17,
+	OPTIONS4                       = 17,
 	SHADER_CACHE                   = 18,
-	OPTIONS5                 = 19,
+	OPTIONS5                       = 19,
 }
 
 FEATURE_DATA_THREADING :: struct {
@@ -2285,14 +2325,14 @@ FEATURE_DATA_GPU_VIRTUAL_ADDRESS_SUPPORT :: struct {
 	MaxGPUVirtualAddressBitsPerProcess:  u32,
 }
 
-SHADER_CACHE_SUPPORT_FLAGS :: enum u32 { // TODO: make bit_set
-	NONE                   = 0x0,
-	AUTOMATIC_INPROC_CACHE = 0x1,
-	AUTOMATIC_DISK_CACHE   = 0x2,
+SHADER_CACHE_SUPPORT_FLAGS :: distinct bit_set[SHADER_CACHE_SUPPORT_FLAG; u32]
+SHADER_CACHE_SUPPORT_FLAG :: enum u32 {
+	AUTOMATIC_INPROC_CACHE = 0,
+	AUTOMATIC_DISK_CACHE   = 1,
 }
 
 FEATURE_DATA_SHADER_CACHE :: struct {
-	SupportFlags: u32,
+	SupportFlags: SHADER_CACHE_SUPPORT_FLAGS,
 }
 
 SHARED_RESOURCE_TIER :: enum i32 {
@@ -2322,7 +2362,7 @@ IDeviceContext_VTable :: struct {
 	VSSetShader:                               proc "stdcall" (this: ^IDeviceContext, pVertexShader: ^IVertexShader, ppClassInstances: ^^IClassInstance, NumClassInstances: u32),
 	DrawIndexed:                               proc "stdcall" (this: ^IDeviceContext, IndexCount: u32, StartIndexLocation: u32, BaseVertexLocation: i32),
 	Draw:                                      proc "stdcall" (this: ^IDeviceContext, VertexCount: u32, StartVertexLocation: u32),
-	Map:                                       proc "stdcall" (this: ^IDeviceContext, pResource: ^IResource, Subresource: u32, MapType: MAP, MapFlags: u32, pMappedResource: ^MAPPED_SUBRESOURCE) -> HRESULT,
+	Map:                                       proc "stdcall" (this: ^IDeviceContext, pResource: ^IResource, Subresource: u32, MapType: MAP, MapFlags: MAP_FLAGS, pMappedResource: ^MAPPED_SUBRESOURCE) -> HRESULT,
 	Unmap:                                     proc "stdcall" (this: ^IDeviceContext, pResource: ^IResource, Subresource: u32),
 	PSSetConstantBuffers:                      proc "stdcall" (this: ^IDeviceContext, StartSlot: u32, NumBuffers: u32, ppConstantBuffers: ^^IBuffer),
 	IASetInputLayout:                          proc "stdcall" (this: ^IDeviceContext, pInputLayout: ^IInputLayout),
@@ -2343,7 +2383,7 @@ IDeviceContext_VTable :: struct {
 	GSSetSamplers:                             proc "stdcall" (this: ^IDeviceContext, StartSlot: u32, NumSamplers: u32, ppSamplers: ^^ISamplerState),
 	OMSetRenderTargets:                        proc "stdcall" (this: ^IDeviceContext, NumViews: u32, ppRenderTargetViews: ^^IRenderTargetView, pDepthStencilView: ^IDepthStencilView),
 	OMSetRenderTargetsAndUnorderedAccessViews: proc "stdcall" (this: ^IDeviceContext, NumRTVs: u32, ppRenderTargetViews: ^^IRenderTargetView, pDepthStencilView: ^IDepthStencilView, UAVStartSlot: u32, NumUAVs: u32, ppUnorderedAccessViews: ^^IUnorderedAccessView, pUAVInitialCounts: ^u32),
-	OMSetBlendState:                           proc "stdcall" (this: ^IDeviceContext, pBlendState: ^IBlendState, BlendFactor: ^[4]f32, SampleMask: u32),
+	OMSetBlendState:                           proc "stdcall" (this: ^IDeviceContext, pBlendState: ^IBlendState, BlendFactor: ^[4]f32, SampleMask: COLOR_WRITE_ENABLE_MASK),
 	OMSetDepthStencilState:                    proc "stdcall" (this: ^IDeviceContext, pDepthStencilState: ^IDepthStencilState, StencilRef: u32),
 	SOSetTargets:                              proc "stdcall" (this: ^IDeviceContext, NumBuffers: u32, ppSOTargets: ^^IBuffer, pOffsets: ^u32),
 	DrawAuto:                                  proc "stdcall" (this: ^IDeviceContext),
@@ -2399,7 +2439,7 @@ IDeviceContext_VTable :: struct {
 	GSGetSamplers:                             proc "stdcall" (this: ^IDeviceContext, StartSlot: u32, NumSamplers: u32, ppSamplers: ^^ISamplerState),
 	OMGetRenderTargets:                        proc "stdcall" (this: ^IDeviceContext, NumViews: u32, ppRenderTargetViews: ^^IRenderTargetView, ppDepthStencilView: ^^IDepthStencilView),
 	OMGetRenderTargetsAndUnorderedAccessViews: proc "stdcall" (this: ^IDeviceContext, NumRTVs: u32, ppRenderTargetViews: ^^IRenderTargetView, ppDepthStencilView: ^^IDepthStencilView, UAVStartSlot: u32, NumUAVs: u32, ppUnorderedAccessViews: ^^IUnorderedAccessView),
-	OMGetBlendState:                           proc "stdcall" (this: ^IDeviceContext, ppBlendState: ^^IBlendState, BlendFactor: ^[4]f32, pSampleMask: ^u32),
+	OMGetBlendState:                           proc "stdcall" (this: ^IDeviceContext, ppBlendState: ^^IBlendState, BlendFactor: ^[4]f32, pSampleMask: ^COLOR_WRITE_ENABLE_MASK),
 	OMGetDepthStencilState:                    proc "stdcall" (this: ^IDeviceContext, ppDepthStencilState: ^^IDepthStencilState, pStencilRef: ^u32),
 	SOGetTargets:                              proc "stdcall" (this: ^IDeviceContext, NumBuffers: u32, ppSOTargets: ^^IBuffer),
 	RSGetState:                                proc "stdcall" (this: ^IDeviceContext, ppRasterizerState: ^^IRasterizerState),
@@ -3315,13 +3355,13 @@ IDevice_VTable :: struct {
 	GetCreationFlags:                     proc "stdcall" (this: ^IDevice) -> u32,
 	GetDeviceRemovedReason:               proc "stdcall" (this: ^IDevice) -> HRESULT,
 	GetImmediateContext:                  proc "stdcall" (this: ^IDevice, ppImmediateContext: ^^IDeviceContext),
-	SetExceptionMode:                     proc "stdcall" (this: ^IDevice, RaiseFlags: u32) -> HRESULT,
+	SetExceptionMode:                     proc "stdcall" (this: ^IDevice, RaiseFlags: RAISE_FLAGS) -> HRESULT,
 	GetExceptionMode:                     proc "stdcall" (this: ^IDevice) -> u32,
 }
 
 
 CREATE_DEVICE_FLAGS :: distinct bit_set[CREATE_DEVICE_FLAG; u32]
-CREATE_DEVICE_FLAG :: enum u32 { // TODO: make bit_set
+CREATE_DEVICE_FLAG :: enum u32 {
 	SINGLETHREADED                                = 0,
 	DEBUG                                         = 1,
 	SWITCH_TO_REF                                 = 2,
@@ -3367,14 +3407,14 @@ SHADER_BUFFER_DESC :: struct {
 	Type:      CBUFFER_TYPE,
 	Variables: u32,
 	Size:      u32,
-	uFlags:    u32,
+	uFlags:    SHADER_CBUFFER_FLAGS,
 }
 
 SHADER_VARIABLE_DESC :: struct {
 	Name:         cstring,
 	StartOffset:  u32,
 	Size:         u32,
-	uFlags:       u32,
+	uFlags:       SHADER_VARIABLE_FLAGS,
 	DefaultValue: rawptr,
 	StartTexture: u32,
 	TextureSize:  u32,
@@ -3443,7 +3483,7 @@ SHADER_INPUT_BIND_DESC :: struct {
 	BindPoint:  u32,
 	BindCount:  u32,
 
-	uFlags:     u32,
+	uFlags:     SHADER_INPUT_FLAGS,
 	ReturnType: RESOURCE_RETURN_TYPE,
 	Dimension:  SRV_DIMENSION,
 	NumSamples: u32,
@@ -3485,7 +3525,7 @@ FUNCTION_DESC :: struct {
 	ConversionInstructionCount:  u32,
 	BitwiseInstructionCount:     u32,
 	MinFeatureLevel:             FEATURE_LEVEL,
-	RequiredFeatureFlags:        u64,
+	RequiredFeatureFlags:        SHADER_REQUIRES_FLAGS,
 
 	Name:                        cstring,
 	FunctionParameterCount:      i32,
@@ -3571,7 +3611,7 @@ IShaderReflection_VTable :: struct {
 	GetNumInterfaceSlots:          proc "stdcall" (this: ^IShaderReflection) -> u32,
 	GetMinFeatureLevel:            proc "stdcall" (this: ^IShaderReflection, pLevel: ^FEATURE_LEVEL) -> HRESULT,
 	GetThreadGroupSize:            proc "stdcall" (this: ^IShaderReflection, pSizeX: ^u32, pSizeY: ^u32, pSizeZ: ^u32) -> u32,
-	GetRequiresFlags:              proc "stdcall" (this: ^IShaderReflection) -> u64,
+	GetRequiresFlags:              proc "stdcall" (this: ^IShaderReflection) -> SHADER_REQUIRES_FLAGS,
 }
 
 
@@ -3634,22 +3674,24 @@ IDebug :: struct #raw_union {
 	using id3d11debug_vtable: ^IDebug_VTable,
 }
 
-RLDO_FLAGS :: enum u32 { // TODO: make bit_set
-	SUMMARY = 0x1,
-	DETAIL = 0x2,
-	IGNORE_INTERNAL = 0x4,
+RLDO_FLAGS :: distinct bit_set[RLDO_FLAG; u32]
+RLDO_FLAG :: enum u32 {
+	SUMMARY = 0,
+	DETAIL = 1,
+	IGNORE_INTERNAL = 2,
 }
 
-DEBUG_FEATURE :: enum u32 { // TODO: make bit_set
-	FLUSH_PER_RENDER_OP = 0x1,
-	FINISH_PER_RENDER_OP = 0x2,
-	FEATURE_PRESENT_PER_RENDER_OP = 0x4,
+DEBUG_FEATURES :: distinct bit_set[DEBUG_FEATURE; u32]
+DEBUG_FEATURE :: enum u32 {
+	FLUSH_PER_RENDER_OP = 0,
+	FINISH_PER_RENDER_OP = 1,
+	FEATURE_PRESENT_PER_RENDER_OP = 2,
 }
 
 IDebug_VTable :: struct {
 	using iunkown_vtable: IUnknown_VTable,
-	SetFeatureMask:             proc "stdcall" (this: ^IDebug, mask: DEBUG_FEATURE) -> HRESULT,
-	GetFeatureMask:             proc "stdcall" (this: ^IDebug) -> DEBUG_FEATURE,
+	SetFeatureMask:             proc "stdcall" (this: ^IDebug, mask: DEBUG_FEATURES) -> HRESULT,
+	GetFeatureMask:             proc "stdcall" (this: ^IDebug) -> DEBUG_FEATURES,
 	SetPresentPerRenderOpDelay: proc "stdcall" (this: ^IDebug, Milliseconds: u32) -> HRESULT,
 	GetPresentPerRenderOpDelay: proc "stdcall" (this: ^IDebug) -> u32,
 	SetSwapChain:               proc "stdcall" (this: ^IDebug, pSwapChain: ^dxgi.ISwapChain) -> HRESULT,
@@ -3667,7 +3709,7 @@ IInfoQueue :: struct #raw_union {
 	using id3d11infoqueue_vtable: ^IInfoQueue_VTable,
 }
 
-MESSAGE_SEVERITY :: enum u32 { // TODO: make bit_set
+MESSAGE_SEVERITY :: enum u32 {
 	CORRUPTION = 0,
 	ERROR,
 	WARNING,
@@ -3675,7 +3717,7 @@ MESSAGE_SEVERITY :: enum u32 { // TODO: make bit_set
 	MESSAGE, // Not supported until D3D 11.1
 }
 
-MESSAGE_CATEGORY :: enum u32 { // TODO: make bit_set
+MESSAGE_CATEGORY :: enum u32 {
 	APPLICATION_DEFINED = 0,
 	MISCELLANEOUS,
 	INITIALIZATION,
@@ -3750,7 +3792,7 @@ IInfoQueue_VTable :: struct {
 	SetMuteDebugOutput:                           proc "stdcall" (this: ^IInfoQueue, bMute: BOOL),
 }
 
-MESSAGE_ID :: enum u32 { // TODO: make bit_set
+MESSAGE_ID :: enum u32 {
 	UNKNOWN = 0,
 	DEVICE_IASETVERTEXBUFFERS_HAZARD,
 	DEVICE_IASETINDEXBUFFER_HAZARD,

+ 1 - 0
vendor/glfw/bindings/bindings.odin

@@ -110,6 +110,7 @@ foreign glfw {
 	WaitEventsTimeout :: proc(timeout: f64) ---
 	PostEmptyEvent    :: proc() ---
 
+	RawMouseMotionSupported :: proc() -> b32 ---
 	GetInputMode :: proc(window: WindowHandle, mode: c.int) -> c.int ---
 	SetInputMode :: proc(window: WindowHandle, mode, value: c.int) ---
 

+ 3 - 0
vendor/glfw/constants.odin

@@ -339,6 +339,9 @@ CURSOR_NORMAL   :: 0x00034001
 CURSOR_HIDDEN   :: 0x00034002
 CURSOR_DISABLED :: 0x00034003
 
+/* Mouse motion */
+RAW_MOUSE_MOTION :: 0x00033005
+
 /* Behavior? */
 ANY_RELEASE_BEHAVIOR   :: 0
 RELEASE_BEHAVIOR_FLUSH :: 0x00035001

+ 0 - 33
vendor/glfw/native.odin

@@ -1,33 +0,0 @@
-package glfw
-
-when ODIN_OS == .Windows {
-	import win32 "core:sys/windows"
-	
-	foreign import glfw { "lib/glfw3_mt.lib", "system:user32.lib", "system:gdi32.lib", "system:shell32.lib" }
-	
-	@(default_calling_convention="c", link_prefix="glfw")
-	foreign glfw {
-		GetWin32Adapter :: proc(monitor: MonitorHandle) -> cstring ---
-		GetWin32Monitor :: proc(monitor: MonitorHandle) -> cstring ---
-		GetWin32Window  :: proc(window: WindowHandle) -> win32.HWND ---
-		GetWGLContext   :: proc(window: WindowHandle) -> rawptr ---
-	}
-} else when ODIN_OS == .Linux {
-	// TODO: Native Linux
-	// Display* glfwGetX11Display(void);
-	// RRCrtc glfwGetX11Adapter(GLFWmonitor* monitor);
-	// RROutput glfwGetX11Monitor(GLFWmonitor* monitor);
-	// Window glfwGetX11Window(GLFWwindow* window);
-	// void glfwSetX11SelectionString(const char* string);
-	// const char* glfwGetX11SelectionString(void);
-	
-	// struct wl_display* glfwGetWaylandDisplay(void);
-	// struct wl_output* glfwGetWaylandMonitor(GLFWmonitor* monitor);
-	// struct wl_surface* glfwGetWaylandWindow(GLFWwindow* window);
-} else when ODIN_OS == .Darwin {
-	// TODO: Native Darwin
-	// CGDirectDisplayID glfwGetCocoaMonitor(GLFWmonitor* monitor);
-	// id glfwGetCocoaWindow(GLFWwindow* window);
-	// id glfwGetNSGLContext(GLFWwindow* window);
-}
-

+ 16 - 0
vendor/glfw/native_darwin.odin

@@ -0,0 +1,16 @@
+//+build darwin
+
+package glfw
+
+import NS "vendor:darwin/foundation"
+
+foreign import glfw { "lib/darwin/libglfw3.a" }
+
+@(default_calling_convention="c", link_prefix="glfw")
+foreign glfw {
+    GetCocoaWindow :: proc(window: WindowHandle) -> ^NS.Window ---
+}
+
+// TODO:
+// CGDirectDisplayID glfwGetCocoaMonitor(GLFWmonitor* monitor);
+// id glfwGetNSGLContext(GLFWwindow* window);

+ 15 - 0
vendor/glfw/native_linux.odin

@@ -0,0 +1,15 @@
+//+build linux
+
+package glfw
+
+// TODO: Native Linux
+// Display* glfwGetX11Display(void);
+// RRCrtc glfwGetX11Adapter(GLFWmonitor* monitor);
+// RROutput glfwGetX11Monitor(GLFWmonitor* monitor);
+// Window glfwGetX11Window(GLFWwindow* window);
+// void glfwSetX11SelectionString(const char* string);
+// const char* glfwGetX11SelectionString(void);
+
+// struct wl_display* glfwGetWaylandDisplay(void);
+// struct wl_output* glfwGetWaylandMonitor(GLFWmonitor* monitor);
+// struct wl_surface* glfwGetWaylandWindow(GLFWwindow* window);

+ 15 - 0
vendor/glfw/native_windows.odin

@@ -0,0 +1,15 @@
+//+build windows
+
+package glfw
+
+import win32 "core:sys/windows"
+
+foreign import glfw { "lib/glfw3_mt.lib", "system:user32.lib", "system:gdi32.lib", "system:shell32.lib" }
+
+@(default_calling_convention="c", link_prefix="glfw")
+foreign glfw {
+    GetWin32Adapter :: proc(monitor: MonitorHandle) -> cstring ---
+    GetWin32Monitor :: proc(monitor: MonitorHandle) -> cstring ---
+    GetWin32Window  :: proc(window: WindowHandle) -> win32.HWND ---
+    GetWGLContext   :: proc(window: WindowHandle) -> rawptr ---
+}

+ 7 - 7
vendor/vulkan/_gen/create_vulkan_odin_wrapper.py

@@ -84,7 +84,7 @@ def convert_type(t, prev_name, curr_name):
         else:
             ttype = t[:len(t)-1]
             elem = convert_type(ttype, prev_name, curr_name)
-            
+
         if curr_name.endswith("s") or curr_name.endswith("Table"):
             if prev_name.endswith("Count") or prev_name.endswith("Counts"):
                 pointer = "[^]"
@@ -95,10 +95,10 @@ def convert_type(t, prev_name, curr_name):
                     pointer = "[^]"
             elif curr_name.startswith("p"):
                 pointer = "[^]"
-                
+
         if curr_name and elem.endswith("Flags"):
             pointer = "[^]"
-                    
+
         return "{}{}".format(pointer, elem)
     elif t[0].isupper():
         return t
@@ -276,7 +276,7 @@ def parse_enums(f):
     f.write("// Enums\n")
 
     data = re.findall(r"typedef enum Vk(\w+) {(.+?)} \w+;", src, re.S)
-    
+
     data.sort(key=lambda x: x[0])
 
     generated_flags = set()
@@ -458,14 +458,14 @@ def parse_procedures(f):
 
     for rt, name, fields in data:
         proc_name = no_vk(name)
-        
+
         pf = []
         prev_name = ""
         for type_, fname in re.findall(r"(?:\s*|)(.+?)\s*(\w+)(?:,|$)", fields):
             curr_name = fix_arg(fname)
             pf.append((do_type(type_, prev_name, curr_name), curr_name))
             prev_name = curr_name
-            
+
         data_fields = ', '.join(["{}: {}".format(n, t) for t, n in pf if t != ""])
 
         ts = "proc \"c\" ({})".format(data_fields)
@@ -510,7 +510,7 @@ def group_functions(f):
 
         if table_name in ('Device', 'Queue', 'CommandBuffer') and name != 'GetDeviceProcAddr':
             group_map["Device"].append(nn)
-        elif table_name in ('Instance', 'PhysicalDevice') or name == 'GetDeviceProcAddr':
+        elif table_name in ('Instance', 'PhysicalDevice') and name != 'ProcGetInstanceProcAddr' or name == 'GetDeviceProcAddr':
             group_map["Instance"].append(nn)
         elif table_name in ('rawptr', '', 'DebugReportFlagsEXT') or name == 'GetInstanceProcAddr':
             # Skip the allocation function and the dll entry point

+ 3 - 3
vendor/vulkan/procedures.odin

@@ -533,6 +533,7 @@ DeviceMemoryReportCallbackEXT:        ProcDeviceMemoryReportCallbackEXT
 EnumerateInstanceExtensionProperties: ProcEnumerateInstanceExtensionProperties
 EnumerateInstanceLayerProperties:     ProcEnumerateInstanceLayerProperties
 EnumerateInstanceVersion:             ProcEnumerateInstanceVersion
+GetInstanceProcAddr:                  ProcGetInstanceProcAddr
 
 // Instance Procedures
 AcquireDrmDisplayEXT:                                            ProcAcquireDrmDisplayEXT
@@ -564,7 +565,6 @@ GetDisplayPlaneCapabilities2KHR:                                 ProcGetDisplayP
 GetDisplayPlaneCapabilitiesKHR:                                  ProcGetDisplayPlaneCapabilitiesKHR
 GetDisplayPlaneSupportedDisplaysKHR:                             ProcGetDisplayPlaneSupportedDisplaysKHR
 GetDrmDisplayEXT:                                                ProcGetDrmDisplayEXT
-GetInstanceProcAddr:                                             ProcGetInstanceProcAddr
 GetPhysicalDeviceCalibrateableTimeDomainsEXT:                    ProcGetPhysicalDeviceCalibrateableTimeDomainsEXT
 GetPhysicalDeviceCooperativeMatrixPropertiesNV:                  ProcGetPhysicalDeviceCooperativeMatrixPropertiesNV
 GetPhysicalDeviceDisplayPlaneProperties2KHR:                     ProcGetPhysicalDeviceDisplayPlaneProperties2KHR
@@ -1045,6 +1045,7 @@ load_proc_addresses_custom :: proc(set_proc_address: SetProcAddressType) {
 	set_proc_address(&EnumerateInstanceExtensionProperties, "vkEnumerateInstanceExtensionProperties")
 	set_proc_address(&EnumerateInstanceLayerProperties,     "vkEnumerateInstanceLayerProperties")
 	set_proc_address(&EnumerateInstanceVersion,             "vkEnumerateInstanceVersion")
+	set_proc_address(&GetInstanceProcAddr,                  "vkGetInstanceProcAddr")
 
 	// Instance Procedures
 	set_proc_address(&AcquireDrmDisplayEXT,                                            "vkAcquireDrmDisplayEXT")
@@ -1076,7 +1077,6 @@ load_proc_addresses_custom :: proc(set_proc_address: SetProcAddressType) {
 	set_proc_address(&GetDisplayPlaneCapabilitiesKHR,                                  "vkGetDisplayPlaneCapabilitiesKHR")
 	set_proc_address(&GetDisplayPlaneSupportedDisplaysKHR,                             "vkGetDisplayPlaneSupportedDisplaysKHR")
 	set_proc_address(&GetDrmDisplayEXT,                                                "vkGetDrmDisplayEXT")
-	set_proc_address(&GetInstanceProcAddr,                                             "vkGetInstanceProcAddr")
 	set_proc_address(&GetPhysicalDeviceCalibrateableTimeDomainsEXT,                    "vkGetPhysicalDeviceCalibrateableTimeDomainsEXT")
 	set_proc_address(&GetPhysicalDeviceCooperativeMatrixPropertiesNV,                  "vkGetPhysicalDeviceCooperativeMatrixPropertiesNV")
 	set_proc_address(&GetPhysicalDeviceDisplayPlaneProperties2KHR,                     "vkGetPhysicalDeviceDisplayPlaneProperties2KHR")
@@ -2839,7 +2839,6 @@ load_proc_addresses_instance :: proc(instance: Instance) {
 	GetDisplayPlaneCapabilitiesKHR                                  = auto_cast GetInstanceProcAddr(instance, "vkGetDisplayPlaneCapabilitiesKHR")
 	GetDisplayPlaneSupportedDisplaysKHR                             = auto_cast GetInstanceProcAddr(instance, "vkGetDisplayPlaneSupportedDisplaysKHR")
 	GetDrmDisplayEXT                                                = auto_cast GetInstanceProcAddr(instance, "vkGetDrmDisplayEXT")
-	GetInstanceProcAddr                                             = auto_cast GetInstanceProcAddr(instance, "vkGetInstanceProcAddr")
 	GetPhysicalDeviceCalibrateableTimeDomainsEXT                    = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceCalibrateableTimeDomainsEXT")
 	GetPhysicalDeviceCooperativeMatrixPropertiesNV                  = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceCooperativeMatrixPropertiesNV")
 	GetPhysicalDeviceDisplayPlaneProperties2KHR                     = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceDisplayPlaneProperties2KHR")
@@ -3322,6 +3321,7 @@ load_proc_addresses_global :: proc(vk_get_instance_proc_addr: rawptr) {
 	EnumerateInstanceExtensionProperties = auto_cast GetInstanceProcAddr(nil, "vkEnumerateInstanceExtensionProperties")
 	EnumerateInstanceLayerProperties     = auto_cast GetInstanceProcAddr(nil, "vkEnumerateInstanceLayerProperties")
 	EnumerateInstanceVersion             = auto_cast GetInstanceProcAddr(nil, "vkEnumerateInstanceVersion")
+	GetInstanceProcAddr                  = auto_cast GetInstanceProcAddr(nil, "vkGetInstanceProcAddr")
 }
 
 load_proc_addresses :: proc{