Browse Source

Merge branch 'master' of https://github.com/FrancisTheCat/Odin

Franz Höltermann 1 year ago
parent
commit
c3302615a3

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

@@ -39,6 +39,35 @@ jobs:
           ./odin test tests/vendor -all-packages -define:ODIN_TEST_FANCY=false
           ./odin test tests/vendor -all-packages -define:ODIN_TEST_FANCY=false
           ./odin test tests/benchmark -all-packages -define:ODIN_TEST_FANCY=false
           ./odin test tests/benchmark -all-packages -define:ODIN_TEST_FANCY=false
           (cd tests/issues; ./run.sh)
           (cd tests/issues; ./run.sh)
+  build_freebsd:
+    name: FreeBSD Build, Check, and Test
+    runs-on: ubuntu-latest
+    steps:
+    - uses: actions/checkout@v4
+    - name: Build, Check, and Test
+      timeout-minutes: 15
+      uses: vmactions/freebsd-vm@v1
+      with:
+        usesh: true
+        copyback: false
+        prepare: |
+          pkg install -y gmake git bash python3 libxml2 llvm17
+        run: |
+          # `set -e` is needed for test failures to register. https://github.com/vmactions/freebsd-vm/issues/72
+          set -e -x
+          git config --global --add safe.directory $(pwd)
+          gmake release
+          ./odin version
+          ./odin report
+          gmake -C vendor/stb/src
+          gmake -C vendor/cgltf/src
+          gmake -C vendor/miniaudio/src
+          ./odin check examples/all -vet -strict-style -target:freebsd_amd64
+          ./odin test tests/core/normal.odin -file -all-packages -define:ODIN_TEST_FANCY=false
+          ./odin test tests/core/speed.odin -file -all-packages -o:speed -define:ODIN_TEST_FANCY=false
+          ./odin test tests/vendor -all-packages -define:ODIN_TEST_FANCY=false
+          ./odin test tests/benchmark -all-packages -define:ODIN_TEST_FANCY=false
+          (cd tests/issues; ./run.sh)
   ci:
   ci:
     strategy:
     strategy:
       fail-fast: false
       fail-fast: false

+ 5 - 5
base/runtime/core_builtin.odin

@@ -383,7 +383,7 @@ clear_map :: proc "contextless" (m: ^$T/map[$K]$V) {
 //
 //
 // Note: Prefer the procedure group `reserve`
 // Note: Prefer the procedure group `reserve`
 @builtin
 @builtin
-reserve_map :: proc(m: ^$T/map[$K]$V, capacity: int, loc := #caller_location) -> Allocator_Error {
+reserve_map :: proc(m: ^$T/map[$K]$V, #any_int capacity: int, loc := #caller_location) -> Allocator_Error {
 	return __dynamic_map_reserve((^Raw_Map)(m), map_info(T), uint(capacity), loc) if m != nil else nil
 	return __dynamic_map_reserve((^Raw_Map)(m), map_info(T), uint(capacity), loc) if m != nil else nil
 }
 }
 
 
@@ -721,12 +721,12 @@ _reserve_dynamic_array :: #force_inline proc(array: ^$T/[dynamic]$E, capacity: i
 }
 }
 
 
 @builtin
 @builtin
-reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #caller_location) -> Allocator_Error {
+reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, #any_int capacity: int, loc := #caller_location) -> Allocator_Error {
 	return _reserve_dynamic_array(array, capacity, true, loc)
 	return _reserve_dynamic_array(array, capacity, true, loc)
 }
 }
 
 
 @builtin
 @builtin
-non_zero_reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #caller_location) -> Allocator_Error {
+non_zero_reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, #any_int capacity: int, loc := #caller_location) -> Allocator_Error {
 	return _reserve_dynamic_array(array, capacity, false, loc)
 	return _reserve_dynamic_array(array, capacity, false, loc)
 }
 }
 
 
@@ -773,12 +773,12 @@ _resize_dynamic_array :: #force_inline proc(array: ^$T/[dynamic]$E, length: int,
 }
 }
 
 
 @builtin
 @builtin
-resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, length: int, loc := #caller_location) -> Allocator_Error {
+resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, #any_int length: int, loc := #caller_location) -> Allocator_Error {
 	return _resize_dynamic_array(array, length, true, loc=loc)
 	return _resize_dynamic_array(array, length, true, loc=loc)
 }
 }
 
 
 @builtin
 @builtin
-non_zero_resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, length: int, loc := #caller_location) -> Allocator_Error {
+non_zero_resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, #any_int length: int, loc := #caller_location) -> Allocator_Error {
 	return _resize_dynamic_array(array, length, false, loc=loc)
 	return _resize_dynamic_array(array, length, false, loc=loc)
 }
 }
 
 

+ 2 - 2
core/crypto/rand_darwin.odin

@@ -11,7 +11,7 @@ HAS_RAND_BYTES :: true
 _rand_bytes :: proc(dst: []byte) {
 _rand_bytes :: proc(dst: []byte) {
 	err := Sec.RandomCopyBytes(count=len(dst), bytes=raw_data(dst))
 	err := Sec.RandomCopyBytes(count=len(dst), bytes=raw_data(dst))
 	if err != .Success {
 	if err != .Success {
-        msg := CF.StringCopyToOdinString(Sec.CopyErrorMessageString(err))
-        panic(fmt.tprintf("crypto/rand_bytes: SecRandomCopyBytes returned non-zero result: %v %s", err, msg))
+	        msg := CF.StringCopyToOdinString(Sec.CopyErrorMessageString(err))
+	        fmt.panicf("crypto/rand_bytes: SecRandomCopyBytes returned non-zero result: %v %s", err, msg)
 	}
 	}
 }
 }

+ 1 - 1
core/crypto/rand_linux.odin

@@ -32,7 +32,7 @@ _rand_bytes :: proc (dst: []byte) {
 			// All other failures are things that should NEVER happen
 			// All other failures are things that should NEVER happen
 			// unless the kernel interface changes (ie: the Linux
 			// unless the kernel interface changes (ie: the Linux
 			// developers break userland).
 			// developers break userland).
-			panic(fmt.tprintf("crypto: getrandom failed: %v", errno))
+			fmt.panicf("crypto: getrandom failed: %v", errno)
 		}
 		}
 		l -= n_read
 		l -= n_read
 		dst = dst[n_read:]
 		dst = dst[n_read:]

+ 10 - 10
core/crypto/rand_windows.odin

@@ -11,16 +11,16 @@ _rand_bytes :: proc(dst: []byte) {
 	ret := (os.Errno)(win32.BCryptGenRandom(nil, raw_data(dst), u32(len(dst)), win32.BCRYPT_USE_SYSTEM_PREFERRED_RNG))
 	ret := (os.Errno)(win32.BCryptGenRandom(nil, raw_data(dst), u32(len(dst)), win32.BCRYPT_USE_SYSTEM_PREFERRED_RNG))
 	if ret != os.ERROR_NONE {
 	if ret != os.ERROR_NONE {
 		switch ret {
 		switch ret {
-			case os.ERROR_INVALID_HANDLE:
-				// The handle to the first parameter is invalid.
-				// This should not happen here, since we explicitly pass nil to it
-				panic("crypto: BCryptGenRandom Invalid handle for hAlgorithm")
-			case os.ERROR_INVALID_PARAMETER:
-				// One of the parameters was invalid
-				panic("crypto: BCryptGenRandom Invalid parameter")
-			case:
-				// Unknown error
-				panic(fmt.tprintf("crypto: BCryptGenRandom failed: %d\n", ret))
+		case os.ERROR_INVALID_HANDLE:
+			// The handle to the first parameter is invalid.
+			// This should not happen here, since we explicitly pass nil to it
+			panic("crypto: BCryptGenRandom Invalid handle for hAlgorithm")
+		case os.ERROR_INVALID_PARAMETER:
+			// One of the parameters was invalid
+			panic("crypto: BCryptGenRandom Invalid parameter")
+		case:
+			// Unknown error
+			fmt.panicf("crypto: BCryptGenRandom failed: %d\n", ret)
 		}
 		}
 	}
 	}
 }
 }

+ 54 - 69
core/encoding/entity/entity.odin

@@ -56,38 +56,27 @@ CDATA_END     :: "]]>"
 COMMENT_START :: "<!--"
 COMMENT_START :: "<!--"
 COMMENT_END   :: "-->"
 COMMENT_END   :: "-->"
 
 
-/*
-	Default: CDATA and comments are passed through unchanged.
-*/
+// Default: CDATA and comments are passed through unchanged.
 XML_Decode_Option :: enum u8 {
 XML_Decode_Option :: enum u8 {
-	/*
-		Do not decode & entities. It decodes by default.
-		If given, overrides `Decode_CDATA`.
-	*/
+	// Do not decode & entities. It decodes by default. If given, overrides `Decode_CDATA`.
 	No_Entity_Decode,
 	No_Entity_Decode,
 
 
-	/*
-		CDATA is unboxed.
-	*/
+	// CDATA is unboxed.
 	Unbox_CDATA,
 	Unbox_CDATA,
 
 
-	/*
-		Unboxed CDATA is decoded as well.
-		Ignored if `.Unbox_CDATA` is not given.
-	*/
+	// Unboxed CDATA is decoded as well. Ignored if `.Unbox_CDATA` is not given.
 	Decode_CDATA,
 	Decode_CDATA,
 
 
-	/*
-		Comments are stripped.
-	*/
+	// Comments are stripped.
 	Comment_Strip,
 	Comment_Strip,
+
+	// Normalize whitespace
+	Normalize_Whitespace,
 }
 }
 XML_Decode_Options :: bit_set[XML_Decode_Option; u8]
 XML_Decode_Options :: bit_set[XML_Decode_Option; u8]
 
 
-/*
-	Decode a string that may include SGML/XML/HTML entities.
-	The caller has to free the result.
-*/
+// Decode a string that may include SGML/XML/HTML entities.
+// The caller has to free the result.
 decode_xml :: proc(input: string, options := XML_Decode_Options{}, allocator := context.allocator) -> (decoded: string, err: Error) {
 decode_xml :: proc(input: string, options := XML_Decode_Options{}, allocator := context.allocator) -> (decoded: string, err: Error) {
 	context.allocator = allocator
 	context.allocator = allocator
 
 
@@ -100,14 +89,14 @@ decode_xml :: proc(input: string, options := XML_Decode_Options{}, allocator :=
 	t := Tokenizer{src=input}
 	t := Tokenizer{src=input}
 	in_data := false
 	in_data := false
 
 
+	prev: rune = ' '
+
 	loop: for {
 	loop: for {
 		advance(&t) or_return
 		advance(&t) or_return
 		if t.r < 0 { break loop }
 		if t.r < 0 { break loop }
 
 
-		/*
-			Below here we're never inside a CDATA tag.
-			At most we'll see the start of one, but that doesn't affect the logic.
-		*/
+		// Below here we're never inside a CDATA tag. At most we'll see the start of one,
+		// but that doesn't affect the logic.
 		switch t.r {
 		switch t.r {
 		case '<':
 		case '<':
 			/*
 			/*
@@ -126,9 +115,7 @@ decode_xml :: proc(input: string, options := XML_Decode_Options{}, allocator :=
 			in_data = _handle_xml_special(&t, &builder, options) or_return
 			in_data = _handle_xml_special(&t, &builder, options) or_return
 
 
 		case ']':
 		case ']':
-			/*
-				If we're unboxing _and_ decoding CDATA, we'll have to check for the end tag.
-			*/
+			// If we're unboxing _and_ decoding CDATA, we'll have to check for the end tag.
 			if in_data {
 			if in_data {
 				if t.read_offset + len(CDATA_END) < len(t.src) {
 				if t.read_offset + len(CDATA_END) < len(t.src) {
 					if string(t.src[t.offset:][:len(CDATA_END)]) == CDATA_END {
 					if string(t.src[t.offset:][:len(CDATA_END)]) == CDATA_END {
@@ -143,22 +130,16 @@ decode_xml :: proc(input: string, options := XML_Decode_Options{}, allocator :=
 
 
 		case:
 		case:
 			if in_data && .Decode_CDATA not_in options {
 			if in_data && .Decode_CDATA not_in options {
-				/*
-					Unboxed, but undecoded.
-				*/
+				// Unboxed, but undecoded.
 				write_rune(&builder, t.r)
 				write_rune(&builder, t.r)
 				continue
 				continue
 			}
 			}
 
 
 			if t.r == '&' {
 			if t.r == '&' {
 				if entity, entity_err := _extract_xml_entity(&t); entity_err != .None {
 				if entity, entity_err := _extract_xml_entity(&t); entity_err != .None {
-					/*
-						We read to the end of the string without closing the entity.
-						Pass through as-is.
-					*/
+					// We read to the end of the string without closing the entity. Pass through as-is.
 					write_string(&builder, entity)
 					write_string(&builder, entity)
 				} else {
 				} else {
-
 					if .No_Entity_Decode not_in options {
 					if .No_Entity_Decode not_in options {
 						if decoded, ok := xml_decode_entity(entity); ok {
 						if decoded, ok := xml_decode_entity(entity); ok {
 							write_rune(&builder, decoded)
 							write_rune(&builder, decoded)
@@ -166,19 +147,41 @@ decode_xml :: proc(input: string, options := XML_Decode_Options{}, allocator :=
 						}
 						}
 					}
 					}
 
 
-					/*
-						Literal passthrough because the decode failed or we want entities not decoded.
-					*/
+					// Literal passthrough because the decode failed or we want entities not decoded.
 					write_string(&builder, "&")
 					write_string(&builder, "&")
 					write_string(&builder, entity)
 					write_string(&builder, entity)
 					write_string(&builder, ";")
 					write_string(&builder, ";")
 				}
 				}
 			} else {
 			} else {
-				write_rune(&builder, t.r)
+				// Handle AV Normalization: https://www.w3.org/TR/2006/REC-xml11-20060816/#AVNormalize
+				if .Normalize_Whitespace in options {
+					switch t.r {
+					case ' ', '\r', '\n', '\t':
+						if prev != ' ' {
+							write_rune(&builder, ' ')
+							prev = ' '
+						}
+					case:
+						write_rune(&builder, t.r)
+						prev = t.r
+					}
+				} else {
+					// https://www.w3.org/TR/2006/REC-xml11-20060816/#sec-line-ends
+					switch t.r {
+					case '\n', 0x85, 0x2028:
+						write_rune(&builder, '\n')
+					case '\r': // Do nothing until next character
+					case:
+						if prev == '\r' { // Turn a single carriage return into a \n
+							write_rune(&builder, '\n')
+						}
+						write_rune(&builder, t.r)
+					}
+					prev = t.r
+				}
 			}
 			}
 		}
 		}
 	}
 	}
-
 	return strings.clone(strings.to_string(builder), allocator), err
 	return strings.clone(strings.to_string(builder), allocator), err
 }
 }
 
 
@@ -253,24 +256,18 @@ xml_decode_entity :: proc(entity: string) -> (decoded: rune, ok: bool) {
 		return rune(val), true
 		return rune(val), true
 
 
 	case:
 	case:
-		/*
-			Named entity.
-		*/
+		// Named entity.
 		return named_xml_entity_to_rune(entity)
 		return named_xml_entity_to_rune(entity)
 	}
 	}
 }
 }
 
 
-/*
-	Private XML helper to extract `&<stuff>;` entity.
-*/
+// Private XML helper to extract `&<stuff>;` entity.
 @(private="file")
 @(private="file")
 _extract_xml_entity :: proc(t: ^Tokenizer) -> (entity: string, err: Error) {
 _extract_xml_entity :: proc(t: ^Tokenizer) -> (entity: string, err: Error) {
 	assert(t != nil && t.r == '&')
 	assert(t != nil && t.r == '&')
 
 
-	/*
-		All of these would be in the ASCII range.
-		Even if one is not, it doesn't matter. All characters we need to compare to extract are.
-	*/
+	// All of these would be in the ASCII range.
+	// Even if one is not, it doesn't matter. All characters we need to compare to extract are.
 
 
 	length := len(t.src)
 	length := len(t.src)
 	found  := false
 	found  := false
@@ -292,9 +289,7 @@ _extract_xml_entity :: proc(t: ^Tokenizer) -> (entity: string, err: Error) {
 	return string(t.src[t.offset : t.read_offset]), .Invalid_Entity_Encoding
 	return string(t.src[t.offset : t.read_offset]), .Invalid_Entity_Encoding
 }
 }
 
 
-/*
-	Private XML helper for CDATA and comments.
-*/
+// Private XML helper for CDATA and comments.
 @(private="file")
 @(private="file")
 _handle_xml_special :: proc(t: ^Tokenizer, builder: ^strings.Builder, options: XML_Decode_Options) -> (in_data: bool, err: Error) {
 _handle_xml_special :: proc(t: ^Tokenizer, builder: ^strings.Builder, options: XML_Decode_Options) -> (in_data: bool, err: Error) {
 	assert(t != nil && t.r == '<')
 	assert(t != nil && t.r == '<')
@@ -304,20 +299,14 @@ _handle_xml_special :: proc(t: ^Tokenizer, builder: ^strings.Builder, options: X
 		t.read_offset += len(CDATA_START) - 1
 		t.read_offset += len(CDATA_START) - 1
 
 
 		if .Unbox_CDATA in options && .Decode_CDATA in options {
 		if .Unbox_CDATA in options && .Decode_CDATA in options {
-			/*
-				We're unboxing _and_ decoding CDATA
-			*/
+			// We're unboxing _and_ decoding CDATA
 			return true, .None
 			return true, .None
 		}
 		}
 
 
-		/*
-			CDATA is passed through.
-		*/
+		// CDATA is passed through.
 		offset := t.offset
 		offset := t.offset
 
 
-		/*
-			Scan until end of CDATA.
-		*/
+		// Scan until end of CDATA.
 		for {
 		for {
 			advance(t) or_return
 			advance(t) or_return
 			if t.r < 0 { return true, .CDATA_Not_Terminated }
 			if t.r < 0 { return true, .CDATA_Not_Terminated }
@@ -341,14 +330,10 @@ _handle_xml_special :: proc(t: ^Tokenizer, builder: ^strings.Builder, options: X
 
 
 	} else if string(t.src[t.offset:][:len(COMMENT_START)]) == COMMENT_START {
 	} else if string(t.src[t.offset:][:len(COMMENT_START)]) == COMMENT_START {
 		t.read_offset += len(COMMENT_START)
 		t.read_offset += len(COMMENT_START)
-		/*
-			Comment is passed through by default.
-		*/
+		// Comment is passed through by default.
 		offset := t.offset
 		offset := t.offset
 
 
-		/*
-			Scan until end of Comment.
-		*/
+		// Scan until end of Comment.
 		for {
 		for {
 			advance(t) or_return
 			advance(t) or_return
 			if t.r < 0 { return true, .Comment_Not_Terminated }
 			if t.r < 0 { return true, .Comment_Not_Terminated }

+ 11 - 32
core/encoding/xml/tokenizer.odin

@@ -218,9 +218,7 @@ scan_identifier :: proc(t: ^Tokenizer) -> string {
 	for is_valid_identifier_rune(t.ch) {
 	for is_valid_identifier_rune(t.ch) {
 		advance_rune(t)
 		advance_rune(t)
 		if t.ch == ':' {
 		if t.ch == ':' {
-			/*
-				A namespaced attr can have at most two parts, `namespace:ident`.
-			*/
+			// A namespaced attr can have at most two parts, `namespace:ident`.
 			if namespaced {
 			if namespaced {
 				break	
 				break	
 			}
 			}
@@ -268,14 +266,10 @@ scan_comment :: proc(t: ^Tokenizer) -> (comment: string, err: Error) {
 	return string(t.src[offset : t.offset - 1]), .None
 	return string(t.src[offset : t.offset - 1]), .None
 }
 }
 
 
-/*
-	Skip CDATA
-*/
+// Skip CDATA
 skip_cdata :: proc(t: ^Tokenizer) -> (err: Error) {
 skip_cdata :: proc(t: ^Tokenizer) -> (err: Error) {
 	if t.read_offset + len(CDATA_START) >= len(t.src) {
 	if t.read_offset + len(CDATA_START) >= len(t.src) {
-		/*
-			Can't be the start of a CDATA tag.
-		*/
+		// Can't be the start of a CDATA tag.
 		return .None
 		return .None
 	}
 	}
 
 
@@ -290,9 +284,7 @@ skip_cdata :: proc(t: ^Tokenizer) -> (err: Error) {
 				return .Premature_EOF
 				return .Premature_EOF
 			}
 			}
 
 
-			/*
-				Scan until the end of a CDATA tag.
-			*/
+			// Scan until the end of a CDATA tag.
 			if t.read_offset + len(CDATA_END) < len(t.src) {
 			if t.read_offset + len(CDATA_END) < len(t.src) {
 				if string(t.src[t.offset:][:len(CDATA_END)]) == CDATA_END {
 				if string(t.src[t.offset:][:len(CDATA_END)]) == CDATA_END {
 					t.read_offset += len(CDATA_END)
 					t.read_offset += len(CDATA_END)
@@ -319,14 +311,10 @@ scan_string :: proc(t: ^Tokenizer, offset: int, close: rune = '<', consume_close
 		case '<':
 		case '<':
 			if peek_byte(t) == '!' {
 			if peek_byte(t) == '!' {
 				if peek_byte(t, 1) == '[' {
 				if peek_byte(t, 1) == '[' {
-					/*
-						Might be the start of a CDATA tag.
-					*/
+					// Might be the start of a CDATA tag.
 					skip_cdata(t) or_return
 					skip_cdata(t) or_return
 				} else if peek_byte(t, 1) == '-' && peek_byte(t, 2) == '-' {
 				} else if peek_byte(t, 1) == '-' && peek_byte(t, 2) == '-' {
-					/*
-						Comment start. Eat comment.
-					*/
+					// Comment start. Eat comment.
 					t.read_offset += 3
 					t.read_offset += 3
 					_ = scan_comment(t) or_return
 					_ = scan_comment(t) or_return
 				}
 				}
@@ -342,17 +330,13 @@ scan_string :: proc(t: ^Tokenizer, offset: int, close: rune = '<', consume_close
 		}
 		}
 
 
 		if t.ch == close {
 		if t.ch == close {
-			/*
-				If it's not a CDATA or comment, it's the end of this body.
-			*/
+			// If it's not a CDATA or comment, it's the end of this body.
 			break loop
 			break loop
 		}
 		}
 		advance_rune(t)
 		advance_rune(t)
 	}
 	}
 
 
-	/*
-		Strip trailing whitespace.
-	*/
+	// Strip trailing whitespace.
 	lit := string(t.src[offset : t.offset])
 	lit := string(t.src[offset : t.offset])
 
 
 	end := len(lit)
 	end := len(lit)
@@ -369,11 +353,6 @@ scan_string :: proc(t: ^Tokenizer, offset: int, close: rune = '<', consume_close
 	if consume_close {
 	if consume_close {
 		advance_rune(t)
 		advance_rune(t)
 	}
 	}
-
-	/*
-		TODO: Handle decoding escape characters and unboxing CDATA.
-	*/
-
 	return lit, err
 	return lit, err
 }
 }
 
 
@@ -384,7 +363,7 @@ peek :: proc(t: ^Tokenizer) -> (token: Token) {
 	return token
 	return token
 }
 }
 
 
-scan :: proc(t: ^Tokenizer) -> Token {
+scan :: proc(t: ^Tokenizer, multiline_string := false) -> Token {
 	skip_whitespace(t)
 	skip_whitespace(t)
 
 
 	offset := t.offset
 	offset := t.offset
@@ -418,7 +397,7 @@ scan :: proc(t: ^Tokenizer) -> Token {
 		case '"', '\'':
 		case '"', '\'':
 			kind = .Invalid
 			kind = .Invalid
 
 
-			lit, err = scan_string(t, t.offset, ch, true, false)
+			lit, err = scan_string(t, t.offset, ch, true, multiline_string)
 			if err == .None {
 			if err == .None {
 				kind = .String
 				kind = .String
 			}
 			}
@@ -435,4 +414,4 @@ scan :: proc(t: ^Tokenizer) -> Token {
 		lit = string(t.src[offset : t.offset])
 		lit = string(t.src[offset : t.offset])
 	}
 	}
 	return Token{kind, lit, pos}
 	return Token{kind, lit, pos}
-}
+}

+ 14 - 10
core/encoding/xml/xml_reader.odin

@@ -203,9 +203,7 @@ parse_bytes :: proc(data: []u8, options := DEFAULT_OPTIONS, path := "", error_ha
 
 
 	doc.elements = make([dynamic]Element, 1024, 1024, allocator)
 	doc.elements = make([dynamic]Element, 1024, 1024, allocator)
 
 
-	// strings.intern_init(&doc.intern, allocator, allocator)
-
-	err =            .Unexpected_Token
+	err = .Unexpected_Token
 	element, parent: Element_ID
 	element, parent: Element_ID
 	open: Token
 	open: Token
 
 
@@ -259,8 +257,8 @@ parse_bytes :: proc(data: []u8, options := DEFAULT_OPTIONS, path := "", error_ha
 				case .Slash:
 				case .Slash:
 					// Empty tag. Close it.
 					// Empty tag. Close it.
 					expect(t, .Gt) or_return
 					expect(t, .Gt) or_return
-					parent      = doc.elements[element].parent
-					element     = parent
+					parent  = doc.elements[element].parent
+					element = parent
 
 
 				case:
 				case:
 					error(t, t.offset, "Expected close tag, got: %#v\n", end_token)
 					error(t, t.offset, "Expected close tag, got: %#v\n", end_token)
@@ -276,8 +274,8 @@ parse_bytes :: proc(data: []u8, options := DEFAULT_OPTIONS, path := "", error_ha
 					error(t, t.offset, "Mismatched Closing Tag. Expected %v, got %v\n", doc.elements[element].ident, ident.text)
 					error(t, t.offset, "Mismatched Closing Tag. Expected %v, got %v\n", doc.elements[element].ident, ident.text)
 					return doc, .Mismatched_Closing_Tag
 					return doc, .Mismatched_Closing_Tag
 				}
 				}
-				parent      = doc.elements[element].parent
-				element     = parent
+				parent  = doc.elements[element].parent
+				element = parent
 
 
 			} else if open.kind == .Exclaim {
 			} else if open.kind == .Exclaim {
 				// <!
 				// <!
@@ -463,8 +461,8 @@ validate_options :: proc(options: Options) -> (validated: Options, err: Error) {
 	return validated, .None
 	return validated, .None
 }
 }
 
 
-expect :: proc(t: ^Tokenizer, kind: Token_Kind) -> (tok: Token, err: Error) {
-	tok = scan(t)
+expect :: proc(t: ^Tokenizer, kind: Token_Kind, multiline_string := false) -> (tok: Token, err: Error) {
+	tok = scan(t, multiline_string=multiline_string)
 	if tok.kind == kind { return tok, .None }
 	if tok.kind == kind { return tok, .None }
 
 
 	error(t, t.offset, "Expected \"%v\", got \"%v\".", kind, tok.kind)
 	error(t, t.offset, "Expected \"%v\", got \"%v\".", kind, tok.kind)
@@ -480,7 +478,13 @@ parse_attribute :: proc(doc: ^Document) -> (attr: Attribute, offset: int, err: E
 	offset  = t.offset - len(key.text)
 	offset  = t.offset - len(key.text)
 
 
 	_       = expect(t, .Eq)     or_return
 	_       = expect(t, .Eq)     or_return
-	value  := expect(t, .String) or_return
+	value  := expect(t, .String, multiline_string=true) or_return
+
+	normalized, normalize_err := entity.decode_xml(value.text, {.Normalize_Whitespace}, doc.allocator)
+	if normalize_err == .None {
+		append(&doc.strings_to_free, normalized)
+		value.text = normalized
+	}
 
 
 	attr.key = key.text
 	attr.key = key.text
 	attr.val = value.text
 	attr.val = value.text

+ 1 - 0
core/fmt/doc.odin

@@ -9,6 +9,7 @@ The verbs:
 General:
 General:
 	%v     the value in a default format
 	%v     the value in a default format
 	%#v    an expanded format of %v with newlines and indentation
 	%#v    an expanded format of %v with newlines and indentation
+	%w     an Odin-syntax representation of the value
 	%T     an Odin-syntax representation of the type of the value
 	%T     an Odin-syntax representation of the type of the value
 	%%     a literal percent sign; consumes no value
 	%%     a literal percent sign; consumes no value
 	{{     a literal open brace; consumes no value
 	{{     a literal open brace; consumes no value

+ 57 - 0
core/fmt/example.odin

@@ -0,0 +1,57 @@
+//+build ignore
+package custom_formatter_example
+import "core:fmt"
+import "core:io"
+
+SomeType :: struct {
+	value: int,
+}
+
+My_Custom_Base_Type :: distinct u32
+
+main :: proc() {
+ 	// Ensure the fmt._user_formatters map is initialized
+	fmt.set_user_formatters(new(map[typeid]fmt.User_Formatter))
+
+	// Register custom formatters for my favorite types
+	err := fmt.register_user_formatter(type_info_of(SomeType).id, SomeType_Formatter)
+ 	assert(err == .None)
+	err  = fmt.register_user_formatter(type_info_of(My_Custom_Base_Type).id, My_Custom_Base_Formatter)
+ 	assert(err == .None)
+
+	// Use the custom formatters.
+	fmt.printfln("SomeType{{42}}: '%v'", SomeType{42})
+	fmt.printfln("My_Custom_Base_Type(0xdeadbeef): '%v'", My_Custom_Base_Type(0xdeadbeef))
+}
+
+SomeType_Formatter :: proc(fi: ^fmt.Info, arg: any, verb: rune) -> bool {
+	m := cast(^SomeType)arg.data
+	switch verb {
+	case 'v', 'd': // We handle `%v` and `%d`
+		fmt.fmt_int(fi, u64(m.value), true, 8 * size_of(SomeType), verb)
+	case:
+		return false
+	}
+	return true
+}
+
+My_Custom_Base_Formatter :: proc(fi: ^fmt.Info, arg: any, verb: rune) -> bool {
+	m := cast(^My_Custom_Base_Type)arg.data
+	switch verb {
+	case 'v', 'b':
+		value := u64(m^)
+		for value > 0 {
+			if value & 1 == 1 {
+				io.write_string(fi.writer, "Hellope!", &fi.n)
+			} else {
+				io.write_string(fi.writer, "Hellope?", &fi.n)
+			}
+			value >>= 1
+		}
+
+	case:
+		return false
+	}
+	return true
+}
+

+ 16 - 6
core/fmt/fmt.odin

@@ -1726,10 +1726,12 @@ fmt_bit_set :: proc(fi: ^Info, v: any, name: string = "", verb: rune = 'v') {
 
 
 		et := runtime.type_info_base(info.elem)
 		et := runtime.type_info_base(info.elem)
 
 
-		if name != "" {
-			io.write_string(fi.writer, name, &fi.n)
-		} else {
-			reflect.write_type(fi.writer, type_info, &fi.n)
+		if verb != 'w' {
+			if name != "" {
+				io.write_string(fi.writer, name, &fi.n)
+			} else {
+				reflect.write_type(fi.writer, type_info, &fi.n)
+			}
 		}
 		}
 		io.write_byte(fi.writer, '{', &fi.n)
 		io.write_byte(fi.writer, '{', &fi.n)
 		defer io.write_byte(fi.writer, '}', &fi.n)
 		defer io.write_byte(fi.writer, '}', &fi.n)
@@ -1746,9 +1748,17 @@ fmt_bit_set :: proc(fi: ^Info, v: any, name: string = "", verb: rune = 'v') {
 			}
 			}
 
 
 			if is_enum {
 			if is_enum {
+				enum_name: string
+			 	if ti_named, is_named := info.elem.variant.(runtime.Type_Info_Named); is_named {
+					enum_name = ti_named.name
+				}
 				for ev, evi in e.values {
 				for ev, evi in e.values {
 					v := u64(ev)
 					v := u64(ev)
 					if v == u64(i) {
 					if v == u64(i) {
+						if verb == 'w' {
+							io.write_string(fi.writer, enum_name, &fi.n)
+							io.write_byte(fi.writer, '.', &fi.n)
+						}
 						io.write_string(fi.writer, e.names[evi], &fi.n)
 						io.write_string(fi.writer, e.names[evi], &fi.n)
 						commas += 1
 						commas += 1
 						continue loop
 						continue loop
@@ -2391,7 +2401,6 @@ fmt_named :: proc(fi: ^Info, v: any, verb: rune, info: runtime.Type_Info_Named)
 			     runtime.Type_Info_Dynamic_Array,
 			     runtime.Type_Info_Dynamic_Array,
 			     runtime.Type_Info_Slice,
 			     runtime.Type_Info_Slice,
 			     runtime.Type_Info_Struct,
 			     runtime.Type_Info_Struct,
-			     runtime.Type_Info_Union,
 			     runtime.Type_Info_Enum,
 			     runtime.Type_Info_Enum,
 			     runtime.Type_Info_Map,
 			     runtime.Type_Info_Map,
 			     runtime.Type_Info_Bit_Set,
 			     runtime.Type_Info_Bit_Set,
@@ -2498,8 +2507,9 @@ fmt_matrix :: proc(fi: ^Info, v: any, verb: rune, info: runtime.Type_Info_Matrix
 		}
 		}
 	} else {
 	} else {
 		// Printed in Row-Major layout to match text layout
 		// Printed in Row-Major layout to match text layout
+		row_separator := ", " if verb == 'w' else "; "
 		for row in 0..<info.row_count {
 		for row in 0..<info.row_count {
-			if row > 0 { io.write_string(fi.writer, "; ", &fi.n) }
+			if row > 0 { io.write_string(fi.writer, row_separator, &fi.n) }
 			for col in 0..<info.column_count {
 			for col in 0..<info.column_count {
 				if col > 0 { io.write_string(fi.writer, ", ", &fi.n) }
 				if col > 0 { io.write_string(fi.writer, ", ", &fi.n) }
 
 

+ 49 - 12
core/os/os_freebsd.odin

@@ -112,15 +112,15 @@ EOWNERDEAD:      Errno : 96
 O_RDONLY   :: 0x00000
 O_RDONLY   :: 0x00000
 O_WRONLY   :: 0x00001
 O_WRONLY   :: 0x00001
 O_RDWR     :: 0x00002
 O_RDWR     :: 0x00002
-O_CREATE   :: 0x00040
-O_EXCL     :: 0x00080
-O_NOCTTY   :: 0x00100
-O_TRUNC    :: 0x00200
-O_NONBLOCK :: 0x00800
-O_APPEND   :: 0x00400
-O_SYNC     :: 0x01000
-O_ASYNC    :: 0x02000
-O_CLOEXEC  :: 0x80000
+O_NONBLOCK :: 0x00004
+O_APPEND   :: 0x00008
+O_ASYNC    :: 0x00040
+O_SYNC     :: 0x00080
+O_CREATE   :: 0x00200
+O_TRUNC    :: 0x00400
+O_EXCL     :: 0x00800
+O_NOCTTY   :: 0x08000
+O_CLOEXEC  :: 0100000
 
 
 
 
 SEEK_DATA  :: 3
 SEEK_DATA  :: 3
@@ -140,6 +140,8 @@ RTLD_NOLOAD       :: 0x02000
 
 
 MAX_PATH :: 1024
 MAX_PATH :: 1024
 
 
+KINFO_FILE_SIZE :: 1392
+
 args := _alloc_command_line_arguments()
 args := _alloc_command_line_arguments()
 
 
 Unix_File_Time :: struct {
 Unix_File_Time :: struct {
@@ -191,6 +193,21 @@ OS_Stat :: struct {
 	lspare: [10]u64,
 	lspare: [10]u64,
 }
 }
 
 
+KInfo_File :: struct {
+	structsize: c.int,
+	type:       c.int,
+	fd:         c.int,
+	ref_count:  c.int,
+	flags:      c.int,
+	pad0:       c.int,
+	offset:     i64,
+
+	// NOTE(Feoramund): This field represents a complicated union that I am
+	// avoiding implementing for now. I only need the path data below.
+	_union: [336]byte,
+
+	path: [MAX_PATH]c.char,
+}
 
 
 // since FreeBSD v12
 // since FreeBSD v12
 Dirent :: struct {
 Dirent :: struct {
@@ -254,6 +271,8 @@ X_OK :: 1 // Test for execute permission
 W_OK :: 2 // Test for write permission
 W_OK :: 2 // Test for write permission
 R_OK :: 4 // Test for read permission
 R_OK :: 4 // Test for read permission
 
 
+F_KINFO :: 22
+
 foreign libc {
 foreign libc {
 	@(link_name="__error")		__errno_location :: proc() -> ^c.int ---
 	@(link_name="__error")		__errno_location :: proc() -> ^c.int ---
 
 
@@ -274,6 +293,7 @@ foreign libc {
 	@(link_name="unlink")           _unix_unlink        :: proc(path: cstring) -> c.int ---
 	@(link_name="unlink")           _unix_unlink        :: proc(path: cstring) -> c.int ---
 	@(link_name="rmdir")            _unix_rmdir         :: proc(path: cstring) -> c.int ---
 	@(link_name="rmdir")            _unix_rmdir         :: proc(path: cstring) -> c.int ---
 	@(link_name="mkdir")            _unix_mkdir         :: proc(path: cstring, mode: mode_t) -> c.int ---
 	@(link_name="mkdir")            _unix_mkdir         :: proc(path: cstring, mode: mode_t) -> c.int ---
+	@(link_name="fcntl")            _unix_fcntl         :: proc(fd: Handle, cmd: c.int, arg: uintptr) -> c.int ---
 	
 	
 	@(link_name="fdopendir")        _unix_fdopendir     :: proc(fd: Handle) -> Dir ---
 	@(link_name="fdopendir")        _unix_fdopendir     :: proc(fd: Handle) -> Dir ---
 	@(link_name="closedir")         _unix_closedir      :: proc(dirp: Dir) -> c.int ---
 	@(link_name="closedir")         _unix_closedir      :: proc(dirp: Dir) -> c.int ---
@@ -365,7 +385,7 @@ seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
 }
 }
 
 
 file_size :: proc(fd: Handle) -> (i64, Errno) {
 file_size :: proc(fd: Handle) -> (i64, Errno) {
-	s, err := fstat(fd)
+	s, err := _fstat(fd)
 	if err != ERROR_NONE {
 	if err != ERROR_NONE {
 		return -1, err
 		return -1, err
 	}
 	}
@@ -591,9 +611,26 @@ _readlink :: proc(path: string) -> (string, Errno) {
 	return "", Errno{}
 	return "", Errno{}
 }
 }
 
 
-// XXX FreeBSD
 absolute_path_from_handle :: proc(fd: Handle) -> (string, Errno) {
 absolute_path_from_handle :: proc(fd: Handle) -> (string, Errno) {
-	return "", Errno(ENOSYS)
+	// NOTE(Feoramund): The situation isn't ideal, but this was the best way I
+	// could find to implement this. There are a couple outstanding bug reports
+	// regarding the desire to retrieve an absolute path from a handle, but to
+	// my knowledge, there hasn't been any work done on it.
+	//
+	// https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=198570
+	//
+	// This may be unreliable, according to a comment from 2023.
+
+	kinfo: KInfo_File
+	kinfo.structsize = KINFO_FILE_SIZE
+
+	res := _unix_fcntl(fd, F_KINFO, cast(uintptr)&kinfo)
+	if res == -1 {
+		return "", Errno(get_last_error())
+	}
+
+	path := strings.clone_from_cstring_bounded(cast(cstring)&kinfo.path[0], len(kinfo.path))
+	return path, ERROR_NONE
 }
 }
 
 
 absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) {
 absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) {

+ 1 - 1
core/path/filepath/path_unix.odin

@@ -56,7 +56,7 @@ foreign libc {
 	@(link_name="free") _unix_free :: proc(ptr: rawptr) ---
 	@(link_name="free") _unix_free :: proc(ptr: rawptr) ---
 
 
 }
 }
-when ODIN_OS == .Darwin {
+when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD {
 	@(private)
 	@(private)
 	foreign libc {
 	foreign libc {
 		@(link_name="__error")          __error :: proc() -> ^i32 ---
 		@(link_name="__error")          __error :: proc() -> ^i32 ---

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

@@ -1156,6 +1156,19 @@ foreign kernel32 {
 	SetCommState :: proc(handle: HANDLE, dcb: ^DCB) -> BOOL ---
 	SetCommState :: proc(handle: HANDLE, dcb: ^DCB) -> BOOL ---
 }
 }
 
 
+COMMTIMEOUTS :: struct {
+	ReadIntervalTimeout: DWORD,
+	ReadTotalTimeoutMultiplier: DWORD,
+	ReadTotalTimeoutConstant: DWORD,
+	WriteTotalTimeoutMultiplier: DWORD,
+	WriteTotalTimeoutConstant: DWORD,
+}
+
+@(default_calling_convention="system")
+foreign kernel32 {
+	GetCommTimeouts :: proc(handle: HANDLE, timeouts: ^COMMTIMEOUTS) -> BOOL ---
+	SetCommTimeouts :: proc(handle: HANDLE, timeouts: ^COMMTIMEOUTS) -> BOOL ---
+}
 
 
 LPFIBER_START_ROUTINE :: #type proc "system" (lpFiberParameter: LPVOID)
 LPFIBER_START_ROUTINE :: #type proc "system" (lpFiberParameter: LPVOID)
 
 

+ 2 - 2
core/time/datetime/datetime.odin

@@ -127,13 +127,13 @@ days_remaining :: proc "contextless" (date: Date) -> (days_remaining: i64, err:
 	return delta.days, .None
 	return delta.days, .None
 }
 }
 
 
-last_day_of_month :: proc "contextless" (#any_int year: i64, #any_int month: i8) -> (day: i64, err: Error) {
+last_day_of_month :: proc "contextless" (#any_int year: i64, #any_int month: i8) -> (day: i8, err: Error) {
 	// Not using formula 2.27 from the book. This is far simpler and gives the same answer.
 	// Not using formula 2.27 from the book. This is far simpler and gives the same answer.
 
 
 	validate(Date{year, month, 1}) or_return
 	validate(Date{year, month, 1}) or_return
 	month_days := MONTH_DAYS
 	month_days := MONTH_DAYS
 
 
-	day = i64(month_days[month])
+	day = month_days[month]
 	if month == 2 && is_leap_year(year) {
 	if month == 2 && is_leap_year(year) {
 		day += 1
 		day += 1
 	}
 	}

+ 11 - 1
src/check_decl.cpp

@@ -89,6 +89,9 @@ gb_internal Type *check_init_variable(CheckerContext *ctx, Entity *e, Operand *o
 			return nullptr;
 			return nullptr;
 		} else if (is_type_polymorphic(t)) {
 		} else if (is_type_polymorphic(t)) {
 			Entity *e = entity_of_node(operand->expr);
 			Entity *e = entity_of_node(operand->expr);
+			if (e == nullptr) {
+				return nullptr;
+			}
 			if (e->state.load() != EntityState_Resolved) {
 			if (e->state.load() != EntityState_Resolved) {
 				gbString str = type_to_string(t);
 				gbString str = type_to_string(t);
 				defer (gb_string_free(str));
 				defer (gb_string_free(str));
@@ -1142,7 +1145,14 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
 	}
 	}
 
 
 	if (ac.link_name.len > 0) {
 	if (ac.link_name.len > 0) {
-		e->Procedure.link_name = ac.link_name;
+		String ln = ac.link_name;
+		e->Procedure.link_name = ln;
+		if (ln == "memcpy" ||
+		    ln == "memmove" ||
+		    ln == "mem_copy" ||
+		    ln == "mem_copy_non_overlapping") {
+			e->Procedure.is_memcpy_like = true;
+		}
 	}
 	}
 
 
 	if (ac.deferred_procedure.entity != nullptr) {
 	if (ac.deferred_procedure.entity != nullptr) {

+ 4 - 1
src/check_expr.cpp

@@ -2550,7 +2550,7 @@ gb_internal void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast *
 									error_line("\tSuggestion: Did you want to pass the iterable value to the for statement by pointer to get addressable semantics?\n");
 									error_line("\tSuggestion: Did you want to pass the iterable value to the for statement by pointer to get addressable semantics?\n");
 								}
 								}
 
 
-								if (is_type_map(parent_type)) {
+								if (parent_type != nullptr && is_type_map(parent_type)) {
 									error_line("\t            Prefer doing 'for key, &%.*s in ...'\n", LIT(e->token.string));
 									error_line("\t            Prefer doing 'for key, &%.*s in ...'\n", LIT(e->token.string));
 								} else {
 								} else {
 									error_line("\t            Prefer doing 'for &%.*s in ...'\n", LIT(e->token.string));
 									error_line("\t            Prefer doing 'for &%.*s in ...'\n", LIT(e->token.string));
@@ -3564,6 +3564,9 @@ gb_internal void check_binary_matrix(CheckerContext *c, Token const &op, Operand
 
 
 				x->mode = Addressing_Value;
 				x->mode = Addressing_Value;
 				if (are_types_identical(xt, yt)) {
 				if (are_types_identical(xt, yt)) {
+					if (are_types_identical(x->type, y->type)) {
+						return;
+					}
 					if (!is_type_named(x->type) && is_type_named(y->type)) {
 					if (!is_type_named(x->type) && is_type_named(y->type)) {
 						// prefer the named type
 						// prefer the named type
 						x->type = y->type;
 						x->type = y->type;

+ 1 - 0
src/entity.cpp

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

+ 136 - 108
src/llvm_backend.cpp

@@ -9,6 +9,11 @@
 #endif
 #endif
 
 
 
 
+#ifndef LLVM_IGNORE_VERIFICATION
+#define LLVM_IGNORE_VERIFICATION 0
+#endif
+
+
 #include "llvm_backend.hpp"
 #include "llvm_backend.hpp"
 #include "llvm_abi.cpp"
 #include "llvm_abi.cpp"
 #include "llvm_backend_opt.cpp"
 #include "llvm_backend_opt.cpp"
@@ -1125,6 +1130,53 @@ gb_internal void lb_finalize_objc_names(lbProcedure *p) {
 	lb_end_procedure_body(p);
 	lb_end_procedure_body(p);
 }
 }
 
 
+gb_internal void lb_verify_function(lbModule *m, lbProcedure *p, bool dump_ll=false) {
+	if (LLVM_IGNORE_VERIFICATION) {
+		return;
+	}
+
+	if (!m->debug_builder && LLVMVerifyFunction(p->value, LLVMReturnStatusAction)) {
+		char *llvm_error = nullptr;
+
+		gb_printf_err("LLVM CODE GEN FAILED FOR PROCEDURE: %.*s\n", LIT(p->name));
+		LLVMDumpValue(p->value);
+		gb_printf_err("\n");
+		if (dump_ll) {
+			gb_printf_err("\n\n\n");
+			String filepath_ll = lb_filepath_ll_for_module(m);
+			if (LLVMPrintModuleToFile(m->mod, cast(char const *)filepath_ll.text, &llvm_error)) {
+				gb_printf_err("LLVM Error: %s\n", llvm_error);
+			}
+		}
+		LLVMVerifyFunction(p->value, LLVMPrintMessageAction);
+		exit_with_errors();
+	}
+}
+
+gb_internal WORKER_TASK_PROC(lb_llvm_module_verification_worker_proc) {
+	char *llvm_error = nullptr;
+	defer (LLVMDisposeMessage(llvm_error));
+	lbModule *m = cast(lbModule *)data;
+
+	if (LLVMVerifyModule(m->mod, LLVMReturnStatusAction, &llvm_error)) {
+		gb_printf_err("LLVM Error:\n%s\n", llvm_error);
+		if (build_context.keep_temp_files) {
+			TIME_SECTION("LLVM Print Module to File");
+			String filepath_ll = lb_filepath_ll_for_module(m);
+			if (LLVMPrintModuleToFile(m->mod, cast(char const *)filepath_ll.text, &llvm_error)) {
+				gb_printf_err("LLVM Error: %s\n", llvm_error);
+				exit_with_errors();
+				return false;
+			}
+		}
+		exit_with_errors();
+		return 1;
+	}
+	return 0;
+}
+
+
+
 gb_internal lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProcedure *objc_names, Array<lbGlobalVariable> &global_variables) { // Startup Runtime
 gb_internal lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProcedure *objc_names, Array<lbGlobalVariable> &global_variables) { // Startup Runtime
 	Type *proc_type = alloc_type_proc(nullptr, nullptr, 0, nullptr, 0, false, ProcCC_Odin);
 	Type *proc_type = alloc_type_proc(nullptr, nullptr, 0, nullptr, 0, false, ProcCC_Odin);
 
 
@@ -1227,13 +1279,7 @@ gb_internal lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProc
 
 
 	lb_end_procedure_body(p);
 	lb_end_procedure_body(p);
 
 
-	if (!main_module->debug_builder && LLVMVerifyFunction(p->value, LLVMReturnStatusAction)) {
-		gb_printf_err("LLVM CODE GEN FAILED FOR PROCEDURE: %s\n", "main");
-		LLVMDumpValue(p->value);
-		gb_printf_err("\n\n\n\n");
-		LLVMVerifyFunction(p->value, LLVMAbortProcessAction);
-	}
-
+	lb_verify_function(main_module, p);
 	return p;
 	return p;
 }
 }
 
 
@@ -1256,31 +1302,21 @@ gb_internal lbProcedure *lb_create_cleanup_runtime(lbModule *main_module) { // C
 
 
 	lb_end_procedure_body(p);
 	lb_end_procedure_body(p);
 
 
-	if (!main_module->debug_builder && LLVMVerifyFunction(p->value, LLVMReturnStatusAction)) {
-		gb_printf_err("LLVM CODE GEN FAILED FOR PROCEDURE: %s\n", "main");
-		LLVMDumpValue(p->value);
-		gb_printf_err("\n\n\n\n");
-		LLVMVerifyFunction(p->value, LLVMAbortProcessAction);
-	}
-
+	lb_verify_function(main_module, p);
 	return p;
 	return p;
 }
 }
 
 
 
 
 gb_internal WORKER_TASK_PROC(lb_generate_procedures_and_types_per_module) {
 gb_internal WORKER_TASK_PROC(lb_generate_procedures_and_types_per_module) {
 	lbModule *m = cast(lbModule *)data;
 	lbModule *m = cast(lbModule *)data;
-	for (Entity *e : m->global_procedures_and_types_to_create) {
-		if (e->kind == Entity_TypeName) {
-			(void)lb_get_entity_name(m, e);
-			lb_type(m, e->type);
-		}
+	for (Entity *e : m->global_types_to_create) {
+		(void)lb_get_entity_name(m, e);
+		(void)lb_type(m, e->type);
 	}
 	}
 
 
-	for (Entity *e : m->global_procedures_and_types_to_create) {
-		if (e->kind == Entity_Procedure) {
-			(void)lb_get_entity_name(m, e);
-			array_add(&m->procedures_to_generate, lb_create_procedure(m, e));
-		}
+	for (Entity *e : m->global_procedures_to_create) {
+		(void)lb_get_entity_name(m, e);
+		array_add(&m->procedures_to_generate, lb_create_procedure(m, e));
 	}
 	}
 	return 0;
 	return 0;
 }
 }
@@ -1334,16 +1370,24 @@ gb_internal void lb_create_global_procedures_and_types(lbGenerator *gen, Checker
 			m = lb_module_of_entity(gen, e);
 			m = lb_module_of_entity(gen, e);
 		}
 		}
 
 
-		array_add(&m->global_procedures_and_types_to_create, e);
+		if (e->kind == Entity_Procedure) {
+			array_add(&m->global_procedures_to_create, e);
+		} else if (e->kind == Entity_TypeName) {
+			array_add(&m->global_types_to_create, e);
+		}
 	}
 	}
 
 
-	for (auto const &entry : gen->modules) {
-		lbModule *m = entry.value;
-		if (do_threading) {
+	if (do_threading) {
+		for (auto const &entry : gen->modules) {
+			lbModule *m = entry.value;
 			thread_pool_add_task(lb_generate_procedures_and_types_per_module, m);
 			thread_pool_add_task(lb_generate_procedures_and_types_per_module, m);
-		} else {
+		}
+	} else {
+		for (auto const &entry : gen->modules) {
+			lbModule *m = entry.value;
 			lb_generate_procedures_and_types_per_module(m);
 			lb_generate_procedures_and_types_per_module(m);
 		}
 		}
+
 	}
 	}
 
 
 	thread_pool_wait();
 	thread_pool_wait();
@@ -2374,16 +2418,19 @@ gb_internal WORKER_TASK_PROC(lb_generate_procedures_worker_proc) {
 }
 }
 
 
 gb_internal void lb_generate_procedures(lbGenerator *gen, bool do_threading) {
 gb_internal void lb_generate_procedures(lbGenerator *gen, bool do_threading) {
-	for (auto const &entry : gen->modules) {
-		lbModule *m = entry.value;
-		if (do_threading) {
+	if (do_threading) {
+		for (auto const &entry : gen->modules) {
+			lbModule *m = entry.value;
 			thread_pool_add_task(lb_generate_procedures_worker_proc, m);
 			thread_pool_add_task(lb_generate_procedures_worker_proc, m);
-		} else {
+		}
+
+		thread_pool_wait();
+	} else {
+		for (auto const &entry : gen->modules) {
+			lbModule *m = entry.value;
 			lb_generate_procedures_worker_proc(m);
 			lb_generate_procedures_worker_proc(m);
 		}
 		}
 	}
 	}
-
-	thread_pool_wait();
 }
 }
 
 
 gb_internal WORKER_TASK_PROC(lb_generate_missing_procedures_to_check_worker_proc) {
 gb_internal WORKER_TASK_PROC(lb_generate_missing_procedures_to_check_worker_proc) {
@@ -2397,17 +2444,20 @@ gb_internal WORKER_TASK_PROC(lb_generate_missing_procedures_to_check_worker_proc
 }
 }
 
 
 gb_internal void lb_generate_missing_procedures(lbGenerator *gen, bool do_threading) {
 gb_internal void lb_generate_missing_procedures(lbGenerator *gen, bool do_threading) {
-	for (auto const &entry : gen->modules) {
-		lbModule *m = entry.value;
-		// NOTE(bill): procedures may be added during generation
-		if (do_threading) {
+	if (do_threading) {
+		for (auto const &entry : gen->modules) {
+			lbModule *m = entry.value;
+			// NOTE(bill): procedures may be added during generation
 			thread_pool_add_task(lb_generate_missing_procedures_to_check_worker_proc, m);
 			thread_pool_add_task(lb_generate_missing_procedures_to_check_worker_proc, m);
-		} else {
+		}
+		thread_pool_wait();
+	} else {
+		for (auto const &entry : gen->modules) {
+			lbModule *m = entry.value;
+			// NOTE(bill): procedures may be added during generation
 			lb_generate_missing_procedures_to_check_worker_proc(m);
 			lb_generate_missing_procedures_to_check_worker_proc(m);
 		}
 		}
 	}
 	}
-
-	thread_pool_wait();
 }
 }
 
 
 gb_internal void lb_debug_info_complete_types_and_finalize(lbGenerator *gen) {
 gb_internal void lb_debug_info_complete_types_and_finalize(lbGenerator *gen) {
@@ -2420,32 +2470,45 @@ gb_internal void lb_debug_info_complete_types_and_finalize(lbGenerator *gen) {
 }
 }
 
 
 gb_internal void lb_llvm_function_passes(lbGenerator *gen, bool do_threading) {
 gb_internal void lb_llvm_function_passes(lbGenerator *gen, bool do_threading) {
-	for (auto const &entry : gen->modules) {
-		lbModule *m = entry.value;
-		if (do_threading) {
+	if (do_threading) {
+		for (auto const &entry : gen->modules) {
+			lbModule *m = entry.value;
 			thread_pool_add_task(lb_llvm_function_pass_per_module, m);
 			thread_pool_add_task(lb_llvm_function_pass_per_module, m);
-		} else {
+		}
+		thread_pool_wait();
+	} else {
+		for (auto const &entry : gen->modules) {
+			lbModule *m = entry.value;
 			lb_llvm_function_pass_per_module(m);
 			lb_llvm_function_pass_per_module(m);
 		}
 		}
 	}
 	}
-	thread_pool_wait();
 }
 }
 
 
 
 
 gb_internal void lb_llvm_module_passes(lbGenerator *gen, bool do_threading) {
 gb_internal void lb_llvm_module_passes(lbGenerator *gen, bool do_threading) {
-	for (auto const &entry : gen->modules) {
-		lbModule *m = entry.value;
-		auto wd = gb_alloc_item(permanent_allocator(), lbLLVMModulePassWorkerData);
-		wd->m = m;
-		wd->target_machine = m->target_machine;
+	if (do_threading) {
+		for (auto const &entry : gen->modules) {
+			lbModule *m = entry.value;
+			auto wd = gb_alloc_item(permanent_allocator(), lbLLVMModulePassWorkerData);
+			wd->m = m;
+			wd->target_machine = m->target_machine;
 
 
-		if (do_threading) {
-			thread_pool_add_task(lb_llvm_module_pass_worker_proc, wd);
-		} else {
+			if (do_threading) {
+				thread_pool_add_task(lb_llvm_module_pass_worker_proc, wd);
+			} else {
+				lb_llvm_module_pass_worker_proc(wd);
+			}
+		}
+		thread_pool_wait();
+	} else {
+		for (auto const &entry : gen->modules) {
+			lbModule *m = entry.value;
+			auto wd = gb_alloc_item(permanent_allocator(), lbLLVMModulePassWorkerData);
+			wd->m = m;
+			wd->target_machine = m->target_machine;
 			lb_llvm_module_pass_worker_proc(wd);
 			lb_llvm_module_pass_worker_proc(wd);
 		}
 		}
 	}
 	}
-	thread_pool_wait();
 }
 }
 
 
 gb_internal String lb_filepath_ll_for_module(lbModule *m) {
 gb_internal String lb_filepath_ll_for_module(lbModule *m) {
@@ -2523,40 +2586,27 @@ gb_internal String lb_filepath_obj_for_module(lbModule *m) {
 	return concatenate_strings(permanent_allocator(), path, ext);
 	return concatenate_strings(permanent_allocator(), path, ext);
 }
 }
 
 
-gb_internal WORKER_TASK_PROC(lb_llvm_module_verification_worker_proc) {
-	char *llvm_error = nullptr;
-	defer (LLVMDisposeMessage(llvm_error));
-	lbModule *m = cast(lbModule *)data;
-	if (LLVMVerifyModule(m->mod, LLVMReturnStatusAction, &llvm_error)) {
-		gb_printf_err("LLVM Error:\n%s\n", llvm_error);
-		if (build_context.keep_temp_files) {
-			TIME_SECTION("LLVM Print Module to File");
-			String filepath_ll = lb_filepath_ll_for_module(m);
-			if (LLVMPrintModuleToFile(m->mod, cast(char const *)filepath_ll.text, &llvm_error)) {
-				gb_printf_err("LLVM Error: %s\n", llvm_error);
-				exit_with_errors();
-				return false;
-			}
-		}
-		exit_with_errors();
-		return 1;
-	}
-	return 0;
-}
-
 
 
 gb_internal bool lb_llvm_module_verification(lbGenerator *gen, bool do_threading) {
 gb_internal bool lb_llvm_module_verification(lbGenerator *gen, bool do_threading) {
-	for (auto const &entry : gen->modules) {
-		lbModule *m = entry.value;
-		if (do_threading) {
+	if (LLVM_IGNORE_VERIFICATION) {
+		return true;
+	}
+
+	if (do_threading) {
+		for (auto const &entry : gen->modules) {
+			lbModule *m = entry.value;
 			thread_pool_add_task(lb_llvm_module_verification_worker_proc, m);
 			thread_pool_add_task(lb_llvm_module_verification_worker_proc, m);
-		} else {
+		}
+		thread_pool_wait();
+
+	} else {
+		for (auto const &entry : gen->modules) {
+			lbModule *m = entry.value;
 			if (lb_llvm_module_verification_worker_proc(m)) {
 			if (lb_llvm_module_verification_worker_proc(m)) {
 				return false;
 				return false;
 			}
 			}
 		}
 		}
 	}
 	}
-	thread_pool_wait();
 
 
 	return true;
 	return true;
 }
 }
@@ -2777,12 +2827,7 @@ gb_internal lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *star
 	}
 	}
 
 
 
 
-	if (!m->debug_builder && LLVMVerifyFunction(p->value, LLVMReturnStatusAction)) {
-		gb_printf_err("LLVM CODE GEN FAILED FOR PROCEDURE: %s\n", "main");
-		LLVMDumpValue(p->value);
-		gb_printf_err("\n\n\n\n");
-		LLVMVerifyFunction(p->value, LLVMAbortProcessAction);
-	}
+	lb_verify_function(m, p);
 
 
 	lb_run_function_pass_manager(default_function_pass_manager, p, lbFunctionPassManager_default);
 	lb_run_function_pass_manager(default_function_pass_manager, p, lbFunctionPassManager_default);
 	return p;
 	return p;
@@ -2803,28 +2848,11 @@ gb_internal void lb_generate_procedure(lbModule *m, lbProcedure *p) {
 	lb_end_procedure(p);
 	lb_end_procedure(p);
 
 
 	// Add Flags
 	// Add Flags
-	if (p->body != nullptr) {
-		if (p->name == "memcpy" || p->name == "memmove" ||
-		    p->name == "runtime.mem_copy" || p->name == "mem_copy_non_overlapping" ||
-		    string_starts_with(p->name, str_lit("llvm.memcpy")) ||
-		    string_starts_with(p->name, str_lit("llvm.memmove"))) {
-			p->flags |= lbProcedureFlag_WithoutMemcpyPass;
-		}
+	if (p->entity && p->entity->kind == Entity_Procedure && p->entity->Procedure.is_memcpy_like) {
+		p->flags |= lbProcedureFlag_WithoutMemcpyPass;
 	}
 	}
 
 
-	if (!m->debug_builder && LLVMVerifyFunction(p->value, LLVMReturnStatusAction)) {
-		char *llvm_error = nullptr;
-
-		gb_printf_err("LLVM CODE GEN FAILED FOR PROCEDURE: %.*s\n", LIT(p->name));
-		LLVMDumpValue(p->value);
-		gb_printf_err("\n\n\n\n");
-		String filepath_ll = lb_filepath_ll_for_module(m);
-		if (LLVMPrintModuleToFile(m->mod, cast(char const *)filepath_ll.text, &llvm_error)) {
-			gb_printf_err("LLVM Error: %s\n", llvm_error);
-		}
-		LLVMVerifyFunction(p->value, LLVMPrintMessageAction);
-		exit_with_errors();
-	}
+	lb_verify_function(m, p, true);
 }
 }
 
 
 
 

+ 2 - 1
src/llvm_backend.hpp

@@ -181,7 +181,8 @@ struct lbModule {
 	std::atomic<u32> nested_type_name_guid;
 	std::atomic<u32> nested_type_name_guid;
 
 
 	Array<lbProcedure *> procedures_to_generate;
 	Array<lbProcedure *> procedures_to_generate;
-	Array<Entity *> global_procedures_and_types_to_create;
+	Array<Entity *> global_procedures_to_create;
+	Array<Entity *> global_types_to_create;
 
 
 	lbProcedure *curr_procedure;
 	lbProcedure *curr_procedure;
 
 

+ 2 - 1
src/llvm_backend_general.cpp

@@ -78,7 +78,8 @@ gb_internal void lb_init_module(lbModule *m, Checker *c) {
 		array_init(&m->procedures_to_generate, a, 0, c->info.all_procedures.count);
 		array_init(&m->procedures_to_generate, a, 0, c->info.all_procedures.count);
 		map_init(&m->procedure_values,               c->info.all_procedures.count*2);
 		map_init(&m->procedure_values,               c->info.all_procedures.count*2);
 	}
 	}
-	array_init(&m->global_procedures_and_types_to_create, a, 0, 1024);
+	array_init(&m->global_procedures_to_create, a, 0, 1024);
+	array_init(&m->global_types_to_create, a, 0, 1024);
 	array_init(&m->missing_procedures_to_check, a, 0, 16);
 	array_init(&m->missing_procedures_to_check, a, 0, 16);
 	map_init(&m->debug_values);
 	map_init(&m->debug_values);
 
 

+ 2 - 1
src/main.cpp

@@ -2934,7 +2934,8 @@ int main(int arg_count, char const **arg_ptr) {
 	// TODO(jeroen): Remove the `init_filename` param.
 	// TODO(jeroen): Remove the `init_filename` param.
 	// Let's put that on `build_context.build_paths[0]` instead.
 	// Let's put that on `build_context.build_paths[0]` instead.
 	if (parse_packages(parser, init_filename) != ParseFile_None) {
 	if (parse_packages(parser, init_filename) != ParseFile_None) {
-		return 1;
+		GB_ASSERT_MSG(any_errors(), "parse_packages failed but no error was reported.");
+		// We depend on the next conditional block to return 1, after printing errors.
 	}
 	}
 
 
 	if (any_errors()) {
 	if (any_errors()) {

+ 8 - 0
tests/core/assets/XML/attribute-whitespace.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE foozle>
+<foozle>Barzle</foozle>
+<부끄러운:barzle>
+	<name foo:bar="   birmese
+	kittens   have
+	fur   ">Indeed!</name>
+</부끄러운:barzle>

+ 19 - 5
tests/core/encoding/xml/test_core_xml.odin

@@ -36,7 +36,7 @@ xml_test_utf8_normal :: proc(t: ^testing.T) {
 			},
 			},
 			expected_doctype = "恥ずべきフクロウ",
 			expected_doctype = "恥ずべきフクロウ",
 		},
 		},
-		crc32     = 0xe9b62f03,
+		crc32     = 0xefa55f27,
 	})
 	})
 }
 }
 
 
@@ -52,7 +52,7 @@ xml_test_utf8_unbox_cdata :: proc(t: ^testing.T) {
 			},
 			},
 			expected_doctype = "恥ずべきフクロウ",
 			expected_doctype = "恥ずべきフクロウ",
 		},
 		},
-		crc32     = 0x9c2643ed,
+		crc32     = 0x2dd27770,
 	})
 	})
 }
 }
 
 
@@ -128,7 +128,7 @@ xml_test_entities_unbox :: proc(t: ^testing.T) {
 			},
 			},
 			expected_doctype = "html",
 			expected_doctype = "html",
 		},
 		},
-		crc32     = 0x3b6d4a90,
+		crc32     = 0x350ca83e,
 	})
 	})
 }
 }
 
 
@@ -142,7 +142,21 @@ xml_test_entities_unbox_decode :: proc(t: ^testing.T) {
 			},
 			},
 			expected_doctype = "html",
 			expected_doctype = "html",
 		},
 		},
-		crc32     = 0x5be2ffdc,
+		crc32     = 0x7f58db7d,
+	})
+}
+
+@(test)
+xml_test_attribute_whitespace :: proc(t: ^testing.T) {
+	run_test(t, {
+		// Same as above.
+		// Unbox CDATA in data tag.
+		filename  = "XML/attribute-whitespace.xml",
+		options   = {
+			flags = {},
+			expected_doctype = "foozle",
+		},
+		crc32     = 0x8f5fd6c1,
 	})
 	})
 }
 }
 
 
@@ -172,7 +186,7 @@ xml_test_unicode :: proc(t: ^testing.T) {
 			expected_doctype = "",
 			expected_doctype = "",
 		},
 		},
 		err       = .None,
 		err       = .None,
-		crc32     = 0x0b6100ab,
+		crc32     = 0x73070b55,
 	})
 	})
 }
 }
 
 

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

@@ -258,6 +258,120 @@ test_pointers :: proc(t: ^testing.T) {
 	check(t, "0xFFFF", "%#4p", d)
 	check(t, "0xFFFF", "%#4p", d)
 }
 }
 
 
+@(test)
+test_odin_value_export :: proc(t: ^testing.T) {
+	E :: enum u32 {
+		A, B, C,
+	}
+
+	F :: enum i16 {
+		A, B, F,
+	}
+
+	S :: struct {
+		j, k: int,
+	}
+
+	ST :: struct {
+		x: int    `fmt:"-"`,
+		y: u8     `fmt:"r,0"`,
+		z: string `fmt:"s,0"`,
+	}
+
+	U :: union {
+		i8,
+		i16,
+	}
+
+	UEF :: union { E, F }
+
+	A :: [2]int
+
+	BSE :: distinct bit_set[E]
+
+	i    : int                          = 64
+	f    : f64                          = 3.14
+	c    : complex128                   = 7+3i
+	q    : quaternion256                = 1+2i+3j+4k
+	mat  :               matrix[2,3]f32 = {1.5, 2, 1, 0.777, 0.333, 0.8}
+	matc : #column_major matrix[2,3]f32 = {1.5, 2, 1, 0.777, 0.333, 0.8}
+	e    : enum {A, B, C}               = .B
+	en   : E                            = E.C
+	ena  : [2]E                         = {E.A, E.C}
+	s    : struct { j: int, k: int }    = { j = 16, k = 8 }
+	sn   : S                            = S{ j = 24, k = 12 }
+	st   : ST                           = { 32768, 57, "Hellope" }
+	str  : string                       = "Hellope"
+	strc : cstring                      = "Hellope"
+	bsu  : bit_set[0..<32; u32]         = {0, 1}
+	bs   : bit_set[4..<16]              = {5, 7}
+	bse  : bit_set[E]                   = { .B, .A }
+	bsE  : BSE                          = { .A, .C }
+	arr  : [3]int                       = {1, 2, 3}
+	ars  : [3]S                         = {S{j = 3, k = 2}, S{j = 2, k = 1}, S{j = 1, k = 0}}
+	darr : [dynamic]u8                  = { 128, 64, 32 }
+	dars : [dynamic]S                   = {S{j = 1, k = 2}, S{j = 3, k = 4}}
+	na   : A                            = {7, 5}
+	may0 : Maybe(int)
+	may1 : Maybe(int)                   = 1
+	uz   : union {i8, i16}              = i8(-33)
+	u0   : U                            = U(nil)
+	u1   : U                            = i16(42)
+	uef0 : UEF                          = E.A
+	uefa : [3]UEF                       = { E.A, F.A, F.F }
+	map_ : map[string]u8                = {"foo" = 8, "bar" = 4}
+
+	bf   : bit_field int {
+		a: int | 4,
+		b: int | 4,
+		e: E   | 4,
+	} = {a = 1, b = 2, e = .A}
+
+	defer {
+		delete(darr)
+		delete(dars)
+		delete(map_)
+	}
+
+	check(t, "64",                                                  "%w", i)
+	check(t, "3.14",                                                "%w", f)
+	check(t, "7+3i",                                                "%w", c)
+	check(t, "1+2i+3j+4k",                                          "%w", q)
+	check(t, "{1.5, 2, 1, 0.777, 0.333, 0.8}",                      "%w", mat)
+	check(t, "{1.5, 2, 1, 0.777, 0.333, 0.8}",                      "%w", matc)
+	check(t, ".B",                                                  "%w", e)
+	check(t, "E.C",                                                 "%w", en)
+	check(t, "{E.A, E.C}",                                          "%w", ena)
+	check(t, "{j = 16, k = 8}",                                     "%w", s)
+	check(t, "S{j = 24, k = 12}",                                   "%w", sn)
+	check(t, `ST{y = 57, z = "Hellope"}`,                           "%w", st)
+	check(t, `"Hellope"`,                                           "%w", str)
+	check(t, `"Hellope"`,                                           "%w", strc)
+	check(t, "{0, 1}",                                              "%w", bsu)
+	check(t, "{5, 7}",                                              "%w", bs)
+	check(t, "{E.A, E.B}",                                          "%w", bse)
+	check(t, "{E.A, E.C}",                                          "%w", bsE)
+	check(t, "{1, 2, 3}",                                           "%w", arr)
+	check(t, "{S{j = 3, k = 2}, S{j = 2, k = 1}, S{j = 1, k = 0}}", "%w", ars)
+	check(t, "{128, 64, 32}",                                       "%w", darr)
+	check(t, "{S{j = 1, k = 2}, S{j = 3, k = 4}}",                  "%w", dars)
+	check(t, "{7, 5}",                                              "%w", na)
+	check(t, "nil",                                                 "%w", may0)
+	check(t, "1",                                                   "%w", may1)
+	check(t, "-33",                                                 "%w", uz)
+	check(t, "nil",                                                 "%w", u0)
+	check(t, "42",                                                  "%w", u1)
+	check(t, "E.A",                                                 "%w", uef0)
+	check(t, "{E.A, F.A, F.F}",                                     "%w", uefa)
+	check(t, "{a = 1, b = 2, e = E.A}",                             "%w", bf)
+	// Check this manually due to the non-deterministic ordering of map keys.
+	switch fmt.tprintf("%w", map_) {
+	case `{"foo"=8, "bar"=4}`: break
+	case `{"bar"=4, "foo"=8}`: break
+	case: testing.fail(t)
+	}
+}
+
 @(private)
 @(private)
 check :: proc(t: ^testing.T, exp: string, format: string, args: ..any, loc := #caller_location) {
 check :: proc(t: ^testing.T, exp: string, format: string, args: ..any, loc := #caller_location) {
 	got := fmt.tprintf(format, ..args)
 	got := fmt.tprintf(format, ..args)

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

@@ -8,7 +8,7 @@
 
 
 	A test suite for `core:net`
 	A test suite for `core:net`
 */
 */
-//+build !netbsd
+//+build !netbsd !freebsd !openbsd
 package test_core_net
 package test_core_net
 
 
 import "core:testing"
 import "core:testing"

+ 8 - 6
vendor/raylib/raylib.odin

@@ -984,12 +984,14 @@ foreign lib {
 	LoadShader              :: proc(vsFileName, fsFileName: cstring) -> Shader ---                                                        // Load shader from files and bind default locations
 	LoadShader              :: proc(vsFileName, fsFileName: cstring) -> Shader ---                                                        // Load shader from files and bind default locations
 	LoadShaderFromMemory    :: proc(vsCode, fsCode: cstring) -> Shader ---                                                                // Load shader from code strings and bind default locations
 	LoadShaderFromMemory    :: proc(vsCode, fsCode: cstring) -> Shader ---                                                                // Load shader from code strings and bind default locations
 	IsShaderReady           :: proc(shader: Shader) -> bool ---                                                                           // Check if a shader is ready
 	IsShaderReady           :: proc(shader: Shader) -> bool ---                                                                           // Check if a shader is ready
-	GetShaderLocation       :: proc(shader: Shader, uniformName: cstring) -> ShaderLocationIndex ---                                                    // Get shader uniform location
-	GetShaderLocationAttrib :: proc(shader: Shader, attribName: cstring)  -> ShaderLocationIndex ---                                                    // Get shader attribute location
-	SetShaderValue          :: proc(shader: Shader, locIndex: ShaderLocationIndex, value: rawptr, uniformType: ShaderUniformDataType) ---               // Set shader uniform value
-	SetShaderValueV         :: proc(shader: Shader, locIndex: ShaderLocationIndex, value: rawptr, uniformType: ShaderUniformDataType, count: c.int) --- // Set shader uniform value vector
-	SetShaderValueMatrix    :: proc(shader: Shader, locIndex: ShaderLocationIndex, mat: Matrix) ---                                                     // Set shader uniform value (matrix 4x4)
-	SetShaderValueTexture   :: proc(shader: Shader, locIndex: ShaderLocationIndex, texture: Texture2D) ---                                              // Set shader uniform value for texture (sampler2d)
+	GetShaderLocation       :: proc(shader: Shader, uniformName: cstring) -> c.int ---                                                    // Get shader uniform location
+	GetShaderLocationAttrib :: proc(shader: Shader, attribName: cstring)  -> c.int ---                                                    // Get shader attribute location
+
+	// We use #any_int here so we can pass ShaderLocationIndex
+	SetShaderValue          :: proc(shader: Shader, #any_int locIndex: c.int, value: rawptr, uniformType: ShaderUniformDataType) ---               // Set shader uniform value
+	SetShaderValueV         :: proc(shader: Shader, #any_int locIndex: c.int, value: rawptr, uniformType: ShaderUniformDataType, count: c.int) --- // Set shader uniform value vector
+	SetShaderValueMatrix    :: proc(shader: Shader, #any_int locIndex: c.int, mat: Matrix) ---                                                     // Set shader uniform value (matrix 4x4)
+	SetShaderValueTexture   :: proc(shader: Shader, #any_int locIndex: c.int, texture: Texture2D) ---                                              // Set shader uniform value for texture (sampler2d)
 	UnloadShader            :: proc(shader: Shader) ---                                                                                   // Unload shader from GPU memory (VRAM)
 	UnloadShader            :: proc(shader: Shader) ---                                                                                   // Unload shader from GPU memory (VRAM)
 
 
 	// Screen-space-related functions
 	// Screen-space-related functions

+ 1 - 1
vendor/raylib/raymath.odin

@@ -668,7 +668,7 @@ MatrixLookAt :: proc "c" (eye, target, up: Vector3) -> Matrix {
 // Get float array of matrix data
 // Get float array of matrix data
 @(require_results)
 @(require_results)
 MatrixToFloatV :: proc "c" (mat: Matrix) -> [16]f32 {
 MatrixToFloatV :: proc "c" (mat: Matrix) -> [16]f32 {
-	return transmute([16]f32)mat
+	return transmute([16]f32)linalg.transpose(mat)
 }
 }
 
 
 
 

+ 0 - 555
vendor/raylib/rlgl.odin

@@ -1,555 +0,0 @@
-/**********************************************************************************************
-*
-*   rlgl v5.0 - A multi-OpenGL abstraction layer with an immediate-mode style API
-*
-*   DESCRIPTION:
-*       An abstraction layer for multiple OpenGL versions (1.1, 2.1, 3.3 Core, 4.3 Core, ES 2.0)
-*       that provides a pseudo-OpenGL 1.1 immediate-mode style API (rlVertex, rlTranslate, rlRotate...)
-*
-*   ADDITIONAL NOTES:
-*       When choosing an OpenGL backend different than OpenGL 1.1, some internal buffer are
-*       initialized on rlglInit() to accumulate vertex data.
-*
-*       When an internal state change is required all the stored vertex data is renderer in batch,
-*       additionally, rlDrawRenderBatchActive() could be called to force flushing of the batch.
-*
-*       Some resources are also loaded for convenience, here the complete list:
-*          - Default batch (RLGL.defaultBatch): RenderBatch system to accumulate vertex data
-*          - Default texture (RLGL.defaultTextureId): 1x1 white pixel R8G8B8A8
-*          - Default shader (RLGL.State.defaultShaderId, RLGL.State.defaultShaderLocs)
-*
-*       Internal buffer (and resources) must be manually unloaded calling rlglClose().
-*
-*   CONFIGURATION:
-*       #define GRAPHICS_API_OPENGL_11
-*       #define GRAPHICS_API_OPENGL_21
-*       #define GRAPHICS_API_OPENGL_33
-*       #define GRAPHICS_API_OPENGL_43
-*       #define GRAPHICS_API_OPENGL_ES2
-*       #define GRAPHICS_API_OPENGL_ES3
-*           Use selected OpenGL graphics backend, should be supported by platform
-*           Those preprocessor defines are only used on rlgl module, if OpenGL version is
-*           required by any other module, use rlGetVersion() to check it
-*
-*       #define RLGL_IMPLEMENTATION
-*           Generates the implementation of the library into the included file.
-*           If not defined, the library is in header only mode and can be included in other headers
-*           or source files without problems. But only ONE file should hold the implementation.
-*
-*       #define RLGL_RENDER_TEXTURES_HINT
-*           Enable framebuffer objects (fbo) support (enabled by default)
-*           Some GPUs could not support them despite the OpenGL version
-*
-*       #define RLGL_SHOW_GL_DETAILS_INFO
-*           Show OpenGL extensions and capabilities detailed logs on init
-*
-*       #define RLGL_ENABLE_OPENGL_DEBUG_CONTEXT
-*           Enable debug context (only available on OpenGL 4.3)
-*
-*       rlgl capabilities could be customized just defining some internal
-*       values before library inclusion (default values listed):
-*
-*       #define RL_DEFAULT_BATCH_BUFFER_ELEMENTS   8192    // Default internal render batch elements limits
-*       #define RL_DEFAULT_BATCH_BUFFERS              1    // Default number of batch buffers (multi-buffering)
-*       #define RL_DEFAULT_BATCH_DRAWCALLS          256    // Default number of batch draw calls (by state changes: mode, texture)
-*       #define RL_DEFAULT_BATCH_MAX_TEXTURE_UNITS    4    // Maximum number of textures units that can be activated on batch drawing (SetShaderValueTexture())
-*
-*       #define RL_MAX_MATRIX_STACK_SIZE             32    // Maximum size of internal Matrix stack
-*       #define RL_MAX_SHADER_LOCATIONS              32    // Maximum number of shader locations supported
-*       #define RL_CULL_DISTANCE_NEAR              0.01    // Default projection matrix near cull distance
-*       #define RL_CULL_DISTANCE_FAR             1000.0    // Default projection matrix far cull distance
-*
-*       When loading a shader, the following vertex attributes and uniform
-*       location names are tried to be set automatically:
-*
-*       #define RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION     "vertexPosition"    // Bound by default to shader location: 0
-*       #define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD     "vertexTexCoord"    // Bound by default to shader location: 1
-*       #define RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL       "vertexNormal"      // Bound by default to shader location: 2
-*       #define RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR        "vertexColor"       // Bound by default to shader location: 3
-*       #define RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT      "vertexTangent"     // Bound by default to shader location: 4
-*       #define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2    "vertexTexCoord2"   // Bound by default to shader location: 5
-*       #define RL_DEFAULT_SHADER_UNIFORM_NAME_MVP         "mvp"               // model-view-projection matrix
-*       #define RL_DEFAULT_SHADER_UNIFORM_NAME_VIEW        "matView"           // view matrix
-*       #define RL_DEFAULT_SHADER_UNIFORM_NAME_PROJECTION  "matProjection"     // projection matrix
-*       #define RL_DEFAULT_SHADER_UNIFORM_NAME_MODEL       "matModel"          // model matrix
-*       #define RL_DEFAULT_SHADER_UNIFORM_NAME_NORMAL      "matNormal"         // normal matrix (transpose(inverse(matModelView))
-*       #define RL_DEFAULT_SHADER_UNIFORM_NAME_COLOR       "colDiffuse"        // color diffuse (base tint color, multiplied by texture color)
-*       #define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE0  "texture0"          // texture0 (texture slot active 0)
-*       #define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE1  "texture1"          // texture1 (texture slot active 1)
-*       #define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE2  "texture2"          // texture2 (texture slot active 2)
-*
-*   DEPENDENCIES:
-*      - OpenGL libraries (depending on platform and OpenGL version selected)
-*      - GLAD OpenGL extensions loading library (only for OpenGL 3.3 Core, 4.3 Core)
-*
-*
-*   LICENSE: zlib/libpng
-*
-*   Copyright (c) 2014-2023 Ramon Santamaria (@raysan5)
-*
-*   This software is provided "as-is", without any express or implied warranty. In no event
-*   will the authors be held liable for any damages arising from the use of this software.
-*
-*   Permission is granted to anyone to use this software for any purpose, including commercial
-*   applications, and to alter it and redistribute it freely, subject to the following restrictions:
-*
-*     1. The origin of this software must not be misrepresented; you must not claim that you
-*     wrote the original software. If you use this software in a product, an acknowledgment
-*     in the product documentation would be appreciated but is not required.
-*
-*     2. Altered source versions must be plainly marked as such, and must not be misrepresented
-*     as being the original software.
-*
-*     3. This notice may not be removed or altered from any source distribution.
-*
-**********************************************************************************************/
-
-
-package raylib
-
-import "core:c"
-
-RLGL_VERSION :: "4.5"
-
-when ODIN_OS == .Windows {
-	foreign import lib {
-		"windows/raylib.lib",
-		"system:Winmm.lib",
-		"system:Gdi32.lib",
-		"system:User32.lib",
-		"system:Shell32.lib",
-	}
-} else when ODIN_OS == .Linux  {
-	foreign import lib "linux/libraylib.a"
-} else when ODIN_OS == .Darwin {
-	foreign import lib {
-		"macos-arm64/libraylib.a" when ODIN_ARCH == .arm64 else "macos/libraylib.a",
-		"system:Cocoa.framework",
-		"system:OpenGL.framework",
-		"system:IOKit.framework",
-	}
-} else {
-	foreign import lib "system:raylib"
-}
-
-RL_GRAPHICS_API_OPENGL_11  :: false
-RL_GRAPHICS_API_OPENGL_21  :: true
-RL_GRAPHICS_API_OPENGL_33  :: RL_GRAPHICS_API_OPENGL_21 // default currently
-RL_GRAPHICS_API_OPENGL_ES2 :: false
-RL_GRAPHICS_API_OPENGL_43  :: false
-RL_GRAPHICS_API_OPENGL_ES3 :: false
-
-when RL_GRAPHICS_API_OPENGL_ES3 {
-	RL_GRAPHICS_API_OPENGL_ES2 :: true
-}
- 
-when !RL_GRAPHICS_API_OPENGL_ES2 {
-	// This is the maximum amount of elements (quads) per batch
-	// NOTE: Be careful with text, every letter maps to a quad
-	RL_DEFAULT_BATCH_BUFFER_ELEMENTS :: 8192
-} else {
-	// We reduce memory sizes for embedded systems (RPI and HTML5)
-	// NOTE: On HTML5 (emscripten) this is allocated on heap,
-	// by default it's only 16MB!...just take care...
-	RL_DEFAULT_BATCH_BUFFER_ELEMENTS :: 2048
-}
-
-RL_DEFAULT_BATCH_BUFFERS            :: 1                    // Default number of batch buffers (multi-buffering)
-RL_DEFAULT_BATCH_DRAWCALLS          :: 256                  // Default number of batch draw calls (by state changes: mode, texture)
-RL_DEFAULT_BATCH_MAX_TEXTURE_UNITS  :: 4                    // Maximum number of additional textures that can be activated on batch drawing (SetShaderValueTexture())
-
-// Internal Matrix stack
-RL_MAX_MATRIX_STACK_SIZE          :: 32                   // Maximum size of Matrix stack
-
-// Shader limits
-RL_MAX_SHADER_LOCATIONS           :: 32                   // Maximum number of shader locations supported
-
-// Projection matrix culling
-RL_CULL_DISTANCE_NEAR          :: 0.01                 // Default near cull distance
-RL_CULL_DISTANCE_FAR           :: 1000.0               // Default far cull distance
-
-// Texture parameters (equivalent to OpenGL defines)
-RL_TEXTURE_WRAP_S                       :: 0x2802      // GL_TEXTURE_WRAP_S
-RL_TEXTURE_WRAP_T                       :: 0x2803      // GL_TEXTURE_WRAP_T
-RL_TEXTURE_MAG_FILTER                   :: 0x2800      // GL_TEXTURE_MAG_FILTER
-RL_TEXTURE_MIN_FILTER                   :: 0x2801      // GL_TEXTURE_MIN_FILTER
-
-RL_TEXTURE_FILTER_NEAREST               :: 0x2600      // GL_NEAREST
-RL_TEXTURE_FILTER_LINEAR                :: 0x2601      // GL_LINEAR
-RL_TEXTURE_FILTER_MIP_NEAREST           :: 0x2700      // GL_NEAREST_MIPMAP_NEAREST
-RL_TEXTURE_FILTER_NEAREST_MIP_LINEAR    :: 0x2702      // GL_NEAREST_MIPMAP_LINEAR
-RL_TEXTURE_FILTER_LINEAR_MIP_NEAREST    :: 0x2701      // GL_LINEAR_MIPMAP_NEAREST
-RL_TEXTURE_FILTER_MIP_LINEAR            :: 0x2703      // GL_LINEAR_MIPMAP_LINEAR
-RL_TEXTURE_FILTER_ANISOTROPIC           :: 0x3000      // Anisotropic filter (custom identifier)
-
-RL_TEXTURE_WRAP_REPEAT                  :: 0x2901      // GL_REPEAT
-RL_TEXTURE_WRAP_CLAMP                   :: 0x812F      // GL_CLAMP_TO_EDGE
-RL_TEXTURE_WRAP_MIRROR_REPEAT           :: 0x8370      // GL_MIRRORED_REPEAT
-RL_TEXTURE_WRAP_MIRROR_CLAMP            :: 0x8742      // GL_MIRROR_CLAMP_EXT
-
-// Matrix modes (equivalent to OpenGL)
-RL_MODELVIEW                            :: 0x1700      // GL_MODELVIEW
-RL_PROJECTION                           :: 0x1701      // GL_PROJECTION
-RL_TEXTURE                              :: 0x1702      // GL_TEXTURE
-
-// Primitive assembly draw modes
-RL_LINES                                :: 0x0001      // GL_LINES
-RL_TRIANGLES                            :: 0x0004      // GL_TRIANGLES
-RL_QUADS                                :: 0x0007      // GL_QUADS
-
-// GL equivalent data types
-RL_UNSIGNED_BYTE                        :: 0x1401      // GL_UNSIGNED_BYTE
-RL_FLOAT                                :: 0x1406      // GL_FLOAT
-
-// Buffer usage hint
-RL_STREAM_DRAW                          :: 0x88E0      // GL_STREAM_DRAW
-RL_STREAM_READ                          :: 0x88E1      // GL_STREAM_READ
-RL_STREAM_COPY                          :: 0x88E2      // GL_STREAM_COPY
-RL_STATIC_DRAW                          :: 0x88E4      // GL_STATIC_DRAW
-RL_STATIC_READ                          :: 0x88E5      // GL_STATIC_READ
-RL_STATIC_COPY                          :: 0x88E6      // GL_STATIC_COPY
-RL_DYNAMIC_DRAW                         :: 0x88E8      // GL_DYNAMIC_DRAW
-RL_DYNAMIC_READ                         :: 0x88E9      // GL_DYNAMIC_READ
-RL_DYNAMIC_COPY                         :: 0x88EA      // GL_DYNAMIC_COPY
-
-// GL Shader type
-RL_FRAGMENT_SHADER                      :: 0x8B30      // GL_FRAGMENT_SHADER
-RL_VERTEX_SHADER                        :: 0x8B31      // GL_VERTEX_SHADER
-RL_COMPUTE_SHADER                       :: 0x91B9      // GL_COMPUTE_SHADER
-
-// GL blending factors
-RL_ZERO                                 :: 0           // GL_ZERO
-RL_ONE                                  :: 1           // GL_ONE
-RL_SRC_COLOR                            :: 0x0300      // GL_SRC_COLOR
-RL_ONE_MINUS_SRC_COLOR                  :: 0x0301      // GL_ONE_MINUS_SRC_COLOR
-RL_SRC_ALPHA                            :: 0x0302      // GL_SRC_ALPHA
-RL_ONE_MINUS_SRC_ALPHA                  :: 0x0303      // GL_ONE_MINUS_SRC_ALPHA
-RL_DST_ALPHA                            :: 0x0304      // GL_DST_ALPHA
-RL_ONE_MINUS_DST_ALPHA                  :: 0x0305      // GL_ONE_MINUS_DST_ALPHA
-RL_DST_COLOR                            :: 0x0306      // GL_DST_COLOR
-RL_ONE_MINUS_DST_COLOR                  :: 0x0307      // GL_ONE_MINUS_DST_COLOR
-RL_SRC_ALPHA_SATURATE                   :: 0x0308      // GL_SRC_ALPHA_SATURATE
-RL_CONSTANT_COLOR                       :: 0x8001      // GL_CONSTANT_COLOR
-RL_ONE_MINUS_CONSTANT_COLOR             :: 0x8002      // GL_ONE_MINUS_CONSTANT_COLOR
-RL_CONSTANT_ALPHA                       :: 0x8003      // GL_CONSTANT_ALPHA
-RL_ONE_MINUS_CONSTANT_ALPHA             :: 0x8004      // GL_ONE_MINUS_CONSTANT_ALPHA
-
-// GL blending functions/equations
-RL_FUNC_ADD                             :: 0x8006      // GL_FUNC_ADD
-RL_MIN                                  :: 0x8007      // GL_MIN
-RL_MAX                                  :: 0x8008      // GL_MAX
-RL_FUNC_SUBTRACT                        :: 0x800A      // GL_FUNC_SUBTRACT
-RL_FUNC_REVERSE_SUBTRACT                :: 0x800B      // GL_FUNC_REVERSE_SUBTRACT
-RL_BLEND_EQUATION                       :: 0x8009      // GL_BLEND_EQUATION
-RL_BLEND_EQUATION_RGB                   :: 0x8009      // GL_BLEND_EQUATION_RGB   // (Same as BLEND_EQUATION)
-RL_BLEND_EQUATION_ALPHA                 :: 0x883D      // GL_BLEND_EQUATION_ALPHA
-RL_BLEND_DST_RGB                        :: 0x80C8      // GL_BLEND_DST_RGB
-RL_BLEND_SRC_RGB                        :: 0x80C9      // GL_BLEND_SRC_RGB
-RL_BLEND_DST_ALPHA                      :: 0x80CA      // GL_BLEND_DST_ALPHA
-RL_BLEND_SRC_ALPHA                      :: 0x80CB      // GL_BLEND_SRC_ALPHA
-RL_BLEND_COLOR                          :: 0x8005      // GL_BLEND_COLOR
-
-
-//----------------------------------------------------------------------------------
-// Types and Structures Definition
-//----------------------------------------------------------------------------------
-
-
-VertexBufferIndexType :: c.ushort when RL_GRAPHICS_API_OPENGL_ES2 else c.uint
-
-// Dynamic vertex buffers (position + texcoords + colors + indices arrays)
-VertexBuffer :: struct {
-	elementCount: c.int,                 // Number of elements in the buffer (QUADS)
-
-	vertices:  [^]f32,                   // Vertex position (XYZ - 3 components per vertex) (shader-location = 0)
-	texcoords: [^]f32,                   // Vertex texture coordinates (UV - 2 components per vertex) (shader-location = 1)
-	colors:    [^]u8,                    // Vertex colors (RGBA - 4 components per vertex) (shader-location = 3)
-	indices:   [^]VertexBufferIndexType, // Vertex indices (in case vertex data comes indexed) (6 indices per quad)
-	vaoId:     c.uint,                   // OpenGL Vertex Array Object id
-	vboId:     [4]c.uint,                // OpenGL Vertex Buffer Objects id (4 types of vertex data)
-}
-
-// Draw call type
-// NOTE: Only texture changes register a new draw, other state-change-related elements are not
-// used at this moment (vaoId, shaderId, matrices), raylib just forces a batch draw call if any
-// of those state-change happens (this is done in core module)
-DrawCall :: struct {
-	mode:            c.int,        // Drawing mode: LINES, TRIANGLES, QUADS
-	vertexCount:     c.int,        // Number of vertex of the draw
-	vertexAlignment: c.int,        // Number of vertex required for index alignment (LINES, TRIANGLES)
-	textureId:       c.uint,       // Texture id to be used on the draw -> Use to create new draw call if changes
-}
-
-// RenderBatch type
-RenderBatch :: struct {
-	bufferCount:   c.int,           // Number of vertex buffers (multi-buffering support)
-	currentBuffer: c.int,           // Current buffer tracking in case of multi-buffering
-	vertexBuffer:  [^]VertexBuffer, // Dynamic buffer(s) for vertex data
-
-	draws:         [^]DrawCall,     // Draw calls array, depends on textureId
-	drawCounter:   c.int,           // Draw calls counter
-	currentDepth:  f32,             // Current depth value for next draw
-}
-
-
-// OpenGL version
-GlVersion :: enum c.int {
-	OPENGL_11 = 1,           // OpenGL 1.1
-	OPENGL_21,               // OpenGL 2.1 (GLSL 120)
-	OPENGL_33,               // OpenGL 3.3 (GLSL 330)
-	OPENGL_43,               // OpenGL 4.3 (using GLSL 330)
-	OPENGL_ES_20,            // OpenGL ES 2.0 (GLSL 100)
-	OPENGL_ES_30,            // OpenGL ES 3.0 (GLSL 300 es)
-}
-
-
-// Shader attribute data types
-ShaderAttributeDataType :: enum c.int {
-	FLOAT = 0,         // Shader attribute type: float
-	VEC2,              // Shader attribute type: vec2 (2 float)
-	VEC3,              // Shader attribute type: vec3 (3 float)
-	VEC4,              // Shader attribute type: vec4 (4 float)
-}
-
-// Framebuffer attachment type
-// NOTE: By default up to 8 color channels defined, but it can be more
-FramebufferAttachType :: enum c.int {
-	COLOR_CHANNEL0 = 0,   // Framebuffer attachment type: color 0
-	COLOR_CHANNEL1 = 1,   // Framebuffer attachment type: color 1
-	COLOR_CHANNEL2 = 2,   // Framebuffer attachment type: color 2
-	COLOR_CHANNEL3 = 3,   // Framebuffer attachment type: color 3
-	COLOR_CHANNEL4 = 4,   // Framebuffer attachment type: color 4
-	COLOR_CHANNEL5 = 5,   // Framebuffer attachment type: color 5
-	COLOR_CHANNEL6 = 6,   // Framebuffer attachment type: color 6
-	COLOR_CHANNEL7 = 7,   // Framebuffer attachment type: color 7
-	DEPTH = 100,          // Framebuffer attachment type: depth
-	STENCIL = 200,        // Framebuffer attachment type: stencil
-}
-
-// Framebuffer texture attachment type
-FramebufferAttachTextureType :: enum c.int {
-	CUBEMAP_POSITIVE_X = 0, // Framebuffer texture attachment type: cubemap, +X side
-	CUBEMAP_NEGATIVE_X = 1, // Framebuffer texture attachment type: cubemap, -X side
-	CUBEMAP_POSITIVE_Y = 2, // Framebuffer texture attachment type: cubemap, +Y side
-	CUBEMAP_NEGATIVE_Y = 3, // Framebuffer texture attachment type: cubemap, -Y side
-	CUBEMAP_POSITIVE_Z = 4, // Framebuffer texture attachment type: cubemap, +Z side
-	CUBEMAP_NEGATIVE_Z = 5, // Framebuffer texture attachment type: cubemap, -Z side
-	TEXTURE2D = 100,        // Framebuffer texture attachment type: texture2d
-	RENDERBUFFER = 200,     // Framebuffer texture attachment type: renderbuffer
-}
-
-CullMode :: enum c.int {
-	FRONT = 0,
-	BACK,
-}
-
-@(default_calling_convention="c")
-foreign lib {
-	//------------------------------------------------------------------------------------
-	// Functions Declaration - Matrix operations
-	//------------------------------------------------------------------------------------
-	rlMatrixMode   :: proc(mode: c.int) ---                 // Choose the current matrix to be transformed
-	rlPushMatrix   :: proc() ---                            // Push the current matrix to stack
-	rlPopMatrix    :: proc() ---                            // Pop lattest inserted matrix from stack
-	rlLoadIdentity :: proc() ---                            // Reset current matrix to identity matrix
-	rlTranslatef   :: proc(x, y, z: f32) ---                // Multiply the current matrix by a translation matrix
-	rlRotatef      :: proc(angleDeg: f32, x, y, z: f32) --- // Multiply the current matrix by a rotation matrix
-	rlScalef       :: proc(x, y, z: f32) ---                // Multiply the current matrix by a scaling matrix
-	rlMultMatrixf  :: proc(matf: [^]f32) ---                // Multiply the current matrix by another matrix
-	rlFrustum      :: proc(left, right, bottom, top, znear, zfar: f64) ---
-	rlOrtho        :: proc(left, right, bottom, top, znear, zfar: f64) ---
-	rlViewport     :: proc(x, y, width, height: c.int) ---  // Set the viewport area
-
-	//------------------------------------------------------------------------------------
-	// Functions Declaration - Vertex level operations
-	//------------------------------------------------------------------------------------
-	rlBegin        :: proc(mode: c.int)     --- // Initialize drawing mode (how to organize vertex)
-	rlEnd          :: proc()                --- // Finish vertex providing
-	rlVertex2i     :: proc(x, y: c.int)     --- // Define one vertex (position) - 2 int
-	rlVertex2f     :: proc(x, y: f32)       --- // Define one vertex (position) - 2 f32
-	rlVertex3f     :: proc(x, y, z: f32)    --- // Define one vertex (position) - 3 f32
-	rlTexCoord2f   :: proc(x, y: f32)       --- // Define one vertex (texture coordinate) - 2 f32
-	rlNormal3f     :: proc(x, y, z: f32)    --- // Define one vertex (normal) - 3 f32
-	rlColor4ub     :: proc(r, g, b, a: u8)  --- // Define one vertex (color) - 4 byte
-	rlColor3f      :: proc(x, y, z: f32)    --- // Define one vertex (color) - 3 f32
-	rlColor4f      :: proc(x, y, z, w: f32) --- // Define one vertex (color) - 4 f32
-
-	//------------------------------------------------------------------------------------
-	// Functions Declaration - OpenGL style functions (common to 1.1, 3.3+, ES2)
-	// NOTE: This functions are used to completely abstract raylib code from OpenGL layer,
-	// some of them are direct wrappers over OpenGL calls, some others are custom
-	//------------------------------------------------------------------------------------
-
-	// Vertex buffers state
-	rlEnableVertexArray          :: proc(vaoId: c.uint) -> bool --- // Enable vertex array (VAO, if supported)
-	rlDisableVertexArray         :: proc() ---                      // Disable vertex array (VAO, if supported)
-	rlEnableVertexBuffer         :: proc(id: c.uint) ---            // Enable vertex buffer (VBO)
-	rlDisableVertexBuffer        :: proc() ---                      // Disable vertex buffer (VBO)
-	rlEnableVertexBufferElement  :: proc(id: c.uint) ---            // Enable vertex buffer element (VBO element)
-	rlDisableVertexBufferElement :: proc() ---                      // Disable vertex buffer element (VBO element)
-	rlEnableVertexAttribute      :: proc(index: c.uint) ---         // Enable vertex attribute index
-	rlDisableVertexAttribute     :: proc(index: c.uint) ---         // Disable vertex attribute index
-	when RL_GRAPHICS_API_OPENGL_11 {
-		rlEnableStatePointer :: proc(vertexAttribType: c.int, buffer: rawptr) ---
-		rlDisableStatePointer :: proc(vertexAttribType: c.int) ---
-	}
-
-	// Textures state
-	rlActiveTextureSlot     :: proc(slot: c.int) ---                            // Select and active a texture slot
-	rlEnableTexture         :: proc(id: c.uint) ---                             // Enable texture
-	rlDisableTexture        :: proc() ---                                       // Disable texture
-	rlEnableTextureCubemap  :: proc(id: c.uint) ---                             // Enable texture cubemap
-	rlDisableTextureCubemap :: proc() ---                                       // Disable texture cubemap
-	rlTextureParameters     :: proc(id: c.uint, param: c.int, value: c.int) --- // Set texture parameters (filter, wrap)
-	rlCubemapParameters     :: proc(id: i32, param: c.int, value: c.int) ---    // Set cubemap parameters (filter, wrap)
-
-	// Shader state
-	rlEnableShader  :: proc(id: c.uint) ---                                       // Enable shader program
-	rlDisableShader :: proc() ---                                                 // Disable shader program
-
-	// Framebuffer state
-	rlEnableFramebuffer  :: proc(id: c.uint) ---                                  // Enable render texture (fbo)
-	rlDisableFramebuffer :: proc() ---                                            // Disable render texture (fbo), return to default framebuffer
-	rlActiveDrawBuffers  :: proc(count: c.int) ---                                // Activate multiple draw color buffers
-	rlBlitFramebuffer	 :: proc(srcX, srcY, srcWidth, srcHeight, dstX, dstY, dstWidth, dstHeight, bufferMask: c.int) --- // Blit active framebuffer to main framebuffer
-
-	// General render state
-	rlDisableColorBlend      :: proc() ---                           // Disable color blending
-	rlEnableDepthTest        :: proc() ---                           // Enable depth test
-	rlDisableDepthTest       :: proc() ---                           // Disable depth test
-	rlEnableDepthMask        :: proc() ---                           // Enable depth write
-	rlDisableDepthMask       :: proc() ---                           // Disable depth write
-	rlEnableBackfaceCulling  :: proc() ---                           // Enable backface culling
-	rlDisableBackfaceCulling :: proc() ---                           // Disable backface culling
-	rlSetCullFace            :: proc(mode: CullMode) ---             // Set face culling mode
-	rlEnableScissorTest      :: proc() ---                           // Enable scissor test
-	rlDisableScissorTest     :: proc() ---                           // Disable scissor test
-	rlScissor                :: proc(x, y, width, height: c.int) --- // Scissor test
-	rlEnableWireMode         :: proc() ---                           // Enable wire mode
-	rlEnablePointMode        :: proc() --- 							 // Enable point mode
-	rlDisableWireMode        :: proc() ---                           // Disable wire and point modes
-	rlSetLineWidth           :: proc(width: f32) ---                 // Set the line drawing width
-	rlGetLineWidth           :: proc() -> f32 ---                    // Get the line drawing width
-	rlEnableSmoothLines      :: proc() ---                           // Enable line aliasing
-	rlDisableSmoothLines     :: proc() ---                           // Disable line aliasing
-	rlEnableStereoRender     :: proc() ---                           // Enable stereo rendering
-	rlDisableStereoRender    :: proc() ---                           // Disable stereo rendering
-	rlIsStereoRenderEnabled  :: proc() -> bool ---                   // Check if stereo render is enabled
-
-
-	rlClearColor              :: proc(r, g, b, a: u8) ---                                                        // Clear color buffer with color
-	rlClearScreenBuffers      :: proc() ---                                                                      // Clear used screen buffers (color and depth)
-	rlCheckErrors             :: proc() ---                                                                      // Check and log OpenGL error codes
-	rlSetBlendMode            :: proc(mode: c.int) ---                                                           // Set blending mode
-	rlSetBlendFactors         :: proc(glSrcFactor, glDstFactor, glEquation: c.int) ---                           // Set blending mode factor and equation (using OpenGL factors)
-	rlSetBlendFactorsSeparate :: proc(glSrcRGB, glDstRGB, glSrcAlpha, glDstAlpha, glEqRGB, glEqAlpha: c.int) --- // Set blending mode factors and equations separately (using OpenGL factors)
-
-	//------------------------------------------------------------------------------------
-	// Functions Declaration - rlgl functionality
-	//------------------------------------------------------------------------------------
-	// rlgl initialization functions
-	rlglInit               :: proc(width, height: c.int) --- // Initialize rlgl (buffers, shaders, textures, states)
-	rlglClose              :: proc() ---                     // De-initialize rlgl (buffers, shaders, textures)
-	rlLoadExtensions       :: proc(loader: rawptr) ---       // Load OpenGL extensions (loader function required)
-	rlGetVersion           :: proc() -> GlVersion ---        // Get current OpenGL version
-	rlSetFramebufferWidth  :: proc(width: c.int) ---         // Set current framebuffer width
-	rlGetFramebufferWidth  :: proc() -> c.int ---            // Get default framebuffer width
-	rlSetFramebufferHeight :: proc(height: c.int) ---        // Set current framebuffer height
-	rlGetFramebufferHeight :: proc() -> c.int ---            // Get default framebuffer height
-
-
-	rlGetTextureIdDefault  :: proc() -> c.uint ---   // Get default texture id
-	rlGetShaderIdDefault   :: proc() -> c.uint ---   // Get default shader id
-	rlGetShaderLocsDefault :: proc() -> [^]c.int --- // Get default shader locations
-
-	// Render batch management
-	// NOTE: rlgl provides a default render batch to behave like OpenGL 1.1 immediate mode
-	// but this render batch API is exposed in case of custom batches are required
-	rlLoadRenderBatch       :: proc(numBuffers, bufferElements: c.int) -> RenderBatch --- // Load a render batch system
-	rlUnloadRenderBatch     :: proc(batch: RenderBatch) ---                               // Unload render batch system
-	rlDrawRenderBatch       :: proc(batch: ^RenderBatch) ---                              // Draw render batch data (Update->Draw->Reset)
-	rlSetRenderBatchActive  :: proc(batch: ^RenderBatch) ---                              // Set the active render batch for rlgl (NULL for default internal)
-	rlDrawRenderBatchActive :: proc() ---                                                 // Update and draw internal render batch
-	rlCheckRenderBatchLimit :: proc(vCount: c.int) -> c.int ---                           // Check internal buffer overflow for a given number of vertex
-
-	rlSetTexture :: proc(id: c.uint) --- // Set current texture for render batch and check buffers limits
-
-	//------------------------------------------------------------------------------------------------------------------------
-
-	// Vertex buffers management
-	rlLoadVertexArray                  :: proc() -> c.uint ---                                                      // Load vertex array (vao) if supported
-	rlLoadVertexBuffer                 :: proc(buffer: rawptr, size: c.int, is_dynamic: bool) -> c.uint ---         // Load a vertex buffer attribute
-	rlLoadVertexBufferElement          :: proc(buffer: rawptr, size: c.int, is_dynamic: bool) -> c.uint ---         // Load a new attributes element buffer
-	rlUpdateVertexBuffer               :: proc(bufferId: c.uint, data: rawptr, dataSize: c.int, offset: c.int) ---  // Update GPU buffer with new data
-	rlUpdateVertexBufferElements       :: proc(id: c.uint, data: rawptr, dataSize: c.int, offset: c.int) ---        // Update vertex buffer elements with new data
-	rlUnloadVertexArray                :: proc(vaoId: c.uint) ---
-	rlUnloadVertexBuffer               :: proc(vboId: c.uint) ---
-	rlSetVertexAttribute               :: proc(index: c.uint, compSize: c.int, type: c.int, normalized: bool, stride: c.int, pointer: rawptr) ---
-	rlSetVertexAttributeDivisor        :: proc(index: c.uint, divisor: c.int) ---
-	rlSetVertexAttributeDefault        :: proc(locIndex: c.int, value: rawptr, attribType: c.int, count: c.int) --- // Set vertex attribute default value
-	rlDrawVertexArray                  :: proc(offset: c.int, count: c.int) ---
-	rlDrawVertexArrayElements          :: proc(offset: c.int, count: c.int, buffer: rawptr) ---
-	rlDrawVertexArrayInstanced         :: proc(offset: c.int, count: c.int, instances: c.int) ---
-	rlDrawVertexArrayElementsInstanced :: proc(offset: c.int, count: c.int, buffer: rawptr, instances: c.int) ---
-
-	// Textures management
-	rlLoadTexture         :: proc(data: rawptr, width, height: c.int, format: c.int, mipmapCount: c.int) -> c.uint ---        // Load texture in GPU
-	rlLoadTextureDepth    :: proc(width, height: c.int, useRenderBuffer: bool) -> c.uint ---                                  // Load depth texture/renderbuffer (to be attached to fbo)
-	rlLoadTextureCubemap  :: proc(data: rawptr, size: c.int, format: c.int) -> c.uint ---                                     // Load texture cubemap
-	rlUpdateTexture       :: proc(id: c.uint, offsetX, offsetY: c.int, width, height: c.int, format: c.int, data: rawptr) --- // Update GPU texture with new data
-	rlGetGlTextureFormats :: proc(format: c.int, glInternalFormat, glFormat, glType: ^c.uint) ---                             // Get OpenGL internal formats
-	rlGetPixelFormatName  :: proc(format: c.uint) -> cstring ---                                                              // Get name string for pixel format
-	rlUnloadTexture       :: proc(id: c.uint) ---                                                                             // Unload texture from GPU memory
-	rlGenTextureMipmaps   :: proc(id: c.uint, width, height: c.int, format: c.int, mipmaps: ^c.int) ---                       // Generate mipmap data for selected texture
-	rlReadTexturePixels   :: proc(id: c.uint, width, height: c.int, format: c.int) -> rawptr ---                              // Read texture pixel data
-	rlReadScreenPixels    :: proc(width, height: c.int) -> [^]byte ---                                                        // Read screen pixel data (color buffer)
-
-	// Framebuffer management (fbo)
-	rlLoadFramebuffer     :: proc(width, height: c.int) -> c.uint ---                                           // Load an empty framebuffer
-	rlFramebufferAttach   :: proc(fboId, texId: c.uint, attachType: c.int, texType: c.int, mipLevel: c.int) --- // Attach texture/renderbuffer to a framebuffer
-	rlFramebufferComplete :: proc(id: c.uint) -> bool ---                                                       // Verify framebuffer is complete
-	rlUnloadFramebuffer   :: proc(id: c.uint) ---                                                               // Delete framebuffer from GPU
-
-	// Shaders management
-	rlLoadShaderCode      :: proc(vsCode, fsCode: cstring) -> c.uint ---                                // Load shader from code strings
-	rlCompileShader       :: proc(shaderCode: cstring, type: c.int) -> c.uint ---                       // Compile custom shader and return shader id (type: RL_VERTEX_SHADER, RL_FRAGMENT_SHADER, RL_COMPUTE_SHADER)
-	rlLoadShaderProgram   :: proc(vShaderId, fShaderId: c.uint) -> c.uint ---                           // Load custom shader program
-	rlUnloadShaderProgram :: proc(id: c.uint) ---                                                       // Unload shader program
-	rlGetLocationUniform  :: proc(shaderId: c.uint, uniformName: cstring) -> c.int ---                  // Get shader location uniform
-	rlGetLocationAttrib   :: proc(shaderId: c.uint, attribName: cstring) -> c.int ---                   // Get shader location attribute
-	rlSetUniform          :: proc(locIndex: c.int, value: rawptr, uniformType: c.int, count: c.int) --- // Set shader value uniform
-	rlSetUniformMatrix    :: proc(locIndex: c.int, mat: Matrix) ---                                     // Set shader value matrix
-	rlSetUniformSampler   :: proc(locIndex: c.int, textureId: c.uint) ---                               // Set shader value sampler
-	rlSetShader           :: proc(id: c.uint, locs: [^]c.int) ---                                       // Set shader currently active (id and locations)
-
-	// Compute shader management
-	rlLoadComputeShaderProgram :: proc(shaderId: c.uint) -> c.uint ---     // Load compute shader program
-	rlComputeShaderDispatch    :: proc(groupX, groupY, groupZ: c.uint) --- // Dispatch compute shader (equivalent to *draw* for graphics pipeline)
-
-	// Shader buffer storage object management (ssbo)
-	rlLoadShaderBuffer    :: proc(size: c.uint, data: rawptr, usageHint: c.int) -> c.uint ---              // Load shader storage buffer object (SSBO)
-	rlUnloadShaderBuffer  :: proc(ssboId: c.uint) ---                                                      // Unload shader storage buffer object (SSBO)
-	rlUpdateShaderBuffer  :: proc(id: c.uint, data: rawptr, dataSize: c.uint, offset: c.uint) ---          // Update SSBO buffer data
-	rlBindShaderBuffer    :: proc(id: c.uint, index: c.uint) ---                                           // Bind SSBO buffer
-	rlReadShaderBuffer    :: proc(id: c.uint, dest: rawptr, count: c.uint, offset: c.uint) ---             // Read SSBO buffer data (GPU->CPU)
-	rlCopyShaderBuffer    :: proc(destId, srcId: c.uint, destOffset, srcOffset: c.uint, count: c.uint) --- // Copy SSBO data between buffers
-	rlGetShaderBufferSize :: proc(id: c.uint) -> c.uint ---                                                // Get SSBO buffer size
-
-	// Buffer management
-	rlBindImageTexture :: proc(id: c.uint, index: c.uint, format: c.int, readonly: bool) ---  // Bind image texture
-
-	// Matrix state management
-	rlGetMatrixModelview        :: proc() -> Matrix ---           // Get internal modelview matrix
-	rlGetMatrixProjection       :: proc() -> Matrix ---           // Get internal projection matrix
-	rlGetMatrixTransform        :: proc() -> Matrix ---           // Get internal accumulated transform matrix
-	rlGetMatrixProjectionStereo :: proc(eye: c.int) -> Matrix --- // Get internal projection matrix for stereo render (selected eye)
-	rlGetMatrixViewOffsetStereo :: proc(eye: c.int) -> Matrix --- // Get internal view offset matrix for stereo render (selected eye)
-	rlSetMatrixProjection       :: proc(proj: Matrix) ---         // Set a custom projection matrix (replaces internal projection matrix)
-	rlSetMatrixModelview        :: proc(view: Matrix) ---         // Set a custom modelview matrix (replaces internal modelview matrix)
-	rlSetMatrixProjectionStereo :: proc(right, left: Matrix) ---  // Set eyes projection matrices for stereo rendering
-	rlSetMatrixViewOffsetStereo :: proc(right, left: Matrix) ---  // Set eyes view offsets matrices for stereo rendering
-
-	// Quick and dirty cube/quad buffers load->draw->unload
-	rlLoadDrawCube :: proc() --- // Load and draw a cube
-	rlLoadDrawQuad :: proc() --- // Load and draw a quad
-}

+ 581 - 0
vendor/raylib/rlgl/rlgl.odin

@@ -0,0 +1,581 @@
+/**********************************************************************************************
+*
+*   rlgl v5.0 - A multi-OpenGL abstraction layer with an immediate-mode style API
+*
+*   DESCRIPTION:
+*       An abstraction layer for multiple OpenGL versions (1.1, 2.1, 3.3 Core, 4.3 Core, ES 2.0)
+*       that provides a pseudo-OpenGL 1.1 immediate-mode style API (rlVertex, rlTranslate, rlRotate...)
+*
+*   ADDITIONAL NOTES:
+*       When choosing an OpenGL backend different than OpenGL 1.1, some internal buffer are
+*       initialized on rlglInit() to accumulate vertex data.
+*
+*       When an internal state change is required all the stored vertex data is renderer in batch,
+*       additionally, rlDrawRenderBatchActive() could be called to force flushing of the batch.
+*
+*       Some resources are also loaded for convenience, here the complete list:
+*          - Default batch (RLGL.defaultBatch): RenderBatch system to accumulate vertex data
+*          - Default texture (RLGL.defaultTextureId): 1x1 white pixel R8G8B8A8
+*          - Default shader (RLGL.State.defaultShaderId, RLGL.State.defaultShaderLocs)
+*
+*       Internal buffer (and resources) must be manually unloaded calling rlglClose().
+*
+*   CONFIGURATION:
+*       #define GRAPHICS_API_OPENGL_11
+*       #define GRAPHICS_API_OPENGL_21
+*       #define GRAPHICS_API_OPENGL_33
+*       #define GRAPHICS_API_OPENGL_43
+*       #define GRAPHICS_API_OPENGL_ES2
+*       #define GRAPHICS_API_OPENGL_ES3
+*           Use selected OpenGL graphics backend, should be supported by platform
+*           Those preprocessor defines are only used on rlgl module, if OpenGL version is
+*           required by any other module, use rlGetVersion() to check it
+*
+*       #define RLGL_IMPLEMENTATION
+*           Generates the implementation of the library into the included file.
+*           If not defined, the library is in header only mode and can be included in other headers
+*           or source files without problems. But only ONE file should hold the implementation.
+*
+*       #define RLGL_RENDER_TEXTURES_HINT
+*           Enable framebuffer objects (fbo) support (enabled by default)
+*           Some GPUs could not support them despite the OpenGL version
+*
+*       #define RLGL_SHOW_GL_DETAILS_INFO
+*           Show OpenGL extensions and capabilities detailed logs on init
+*
+*       #define RLGL_ENABLE_OPENGL_DEBUG_CONTEXT
+*           Enable debug context (only available on OpenGL 4.3)
+*
+*       rlgl capabilities could be customized just defining some internal
+*       values before library inclusion (default values listed):
+*
+*       #define RL_DEFAULT_BATCH_BUFFER_ELEMENTS   8192    // Default internal render batch elements limits
+*       #define RL_DEFAULT_BATCH_BUFFERS              1    // Default number of batch buffers (multi-buffering)
+*       #define RL_DEFAULT_BATCH_DRAWCALLS          256    // Default number of batch draw calls (by state changes: mode, texture)
+*       #define RL_DEFAULT_BATCH_MAX_TEXTURE_UNITS    4    // Maximum number of textures units that can be activated on batch drawing (SetShaderValueTexture())
+*
+*       #define RL_MAX_MATRIX_STACK_SIZE             32    // Maximum size of internal Matrix stack
+*       #define RL_MAX_SHADER_LOCATIONS              32    // Maximum number of shader locations supported
+*       #define RL_CULL_DISTANCE_NEAR              0.01    // Default projection matrix near cull distance
+*       #define RL_CULL_DISTANCE_FAR             1000.0    // Default projection matrix far cull distance
+*
+*       When loading a shader, the following vertex attributes and uniform
+*       location names are tried to be set automatically:
+*
+*       #define RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION     "vertexPosition"    // Bound by default to shader location: 0
+*       #define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD     "vertexTexCoord"    // Bound by default to shader location: 1
+*       #define RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL       "vertexNormal"      // Bound by default to shader location: 2
+*       #define RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR        "vertexColor"       // Bound by default to shader location: 3
+*       #define RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT      "vertexTangent"     // Bound by default to shader location: 4
+*       #define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2    "vertexTexCoord2"   // Bound by default to shader location: 5
+*       #define RL_DEFAULT_SHADER_UNIFORM_NAME_MVP         "mvp"               // model-view-projection matrix
+*       #define RL_DEFAULT_SHADER_UNIFORM_NAME_VIEW        "matView"           // view matrix
+*       #define RL_DEFAULT_SHADER_UNIFORM_NAME_PROJECTION  "matProjection"     // projection matrix
+*       #define RL_DEFAULT_SHADER_UNIFORM_NAME_MODEL       "matModel"          // model matrix
+*       #define RL_DEFAULT_SHADER_UNIFORM_NAME_NORMAL      "matNormal"         // normal matrix (transpose(inverse(matModelView))
+*       #define RL_DEFAULT_SHADER_UNIFORM_NAME_COLOR       "colDiffuse"        // color diffuse (base tint color, multiplied by texture color)
+*       #define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE0  "texture0"          // texture0 (texture slot active 0)
+*       #define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE1  "texture1"          // texture1 (texture slot active 1)
+*       #define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE2  "texture2"          // texture2 (texture slot active 2)
+*
+*   DEPENDENCIES:
+*      - OpenGL libraries (depending on platform and OpenGL version selected)
+*      - GLAD OpenGL extensions loading library (only for OpenGL 3.3 Core, 4.3 Core)
+*
+*
+*   LICENSE: zlib/libpng
+*
+*   Copyright (c) 2014-2023 Ramon Santamaria (@raysan5)
+*
+*   This software is provided "as-is", without any express or implied warranty. In no event
+*   will the authors be held liable for any damages arising from the use of this software.
+*
+*   Permission is granted to anyone to use this software for any purpose, including commercial
+*   applications, and to alter it and redistribute it freely, subject to the following restrictions:
+*
+*     1. The origin of this software must not be misrepresented; you must not claim that you
+*     wrote the original software. If you use this software in a product, an acknowledgment
+*     in the product documentation would be appreciated but is not required.
+*
+*     2. Altered source versions must be plainly marked as such, and must not be misrepresented
+*     as being the original software.
+*
+*     3. This notice may not be removed or altered from any source distribution.
+*
+**********************************************************************************************/
+
+
+package rlgl
+
+import "core:c"
+import rl "../."
+
+VERSION :: "5.0"
+
+RAYLIB_SHARED :: #config(RAYLIB_SHARED, false)
+
+// Note: We pull in the full raylib library. If you want a truly stand-alone rlgl, then:
+// - Compile a separate rlgl library and use that in the foreign import blocks below.
+// - Remove the `import rl "../."` line
+// - Copy the code from raylib.odin for any types we alias from that package (see PixelFormat etc)
+
+when ODIN_OS == .Windows {
+	@(extra_linker_flags="/NODEFAULTLIB:" + ("msvcrt" when RAYLIB_SHARED else "libcmt"))
+	foreign import lib {
+		"../windows/raylibdll.lib" when RAYLIB_SHARED else "../windows/raylib.lib" ,
+		"system:Winmm.lib",
+		"system:Gdi32.lib",
+		"system:User32.lib",
+		"system:Shell32.lib",
+	}
+} else when ODIN_OS == .Linux  {
+	foreign import lib {
+		// Note(bumbread): I'm not sure why in `linux/` folder there are
+		// multiple copies of raylib.so, but since these bindings are for
+		// particular version of the library, I better specify it. Ideally,
+		// though, it's best specified in terms of major (.so.4)
+		"../linux/libraylib.so.500" when RAYLIB_SHARED else "../linux/libraylib.a",
+		"system:dl",
+		"system:pthread",
+	}
+} else when ODIN_OS == .Darwin {
+	foreign import lib {
+		"../macos" +
+			("-arm64" when ODIN_ARCH == .arm64 else "") +
+			"/libraylib" + (".500.dylib" when RAYLIB_SHARED else ".a"),
+		"system:Cocoa.framework",
+		"system:OpenGL.framework",
+		"system:IOKit.framework",
+	}
+} else {
+	foreign import lib "system:raylib"
+}
+
+GRAPHICS_API_OPENGL_11  :: false
+GRAPHICS_API_OPENGL_21  :: true
+GRAPHICS_API_OPENGL_33  :: GRAPHICS_API_OPENGL_21 // default currently
+GRAPHICS_API_OPENGL_ES2 :: false
+GRAPHICS_API_OPENGL_43  :: false
+GRAPHICS_API_OPENGL_ES3 :: false
+
+when GRAPHICS_API_OPENGL_ES3 {
+	GRAPHICS_API_OPENGL_ES2 :: true
+}
+ 
+when !GRAPHICS_API_OPENGL_ES2 {
+	// This is the maximum amount of elements (quads) per batch
+	// NOTE: Be careful with text, every letter maps to a quad
+	DEFAULT_BATCH_BUFFER_ELEMENTS :: 8192
+} else {
+	// We reduce memory sizes for embedded systems (RPI and HTML5)
+	// NOTE: On HTML5 (emscripten) this is allocated on heap,
+	// by default it's only 16MB!...just take care...
+	DEFAULT_BATCH_BUFFER_ELEMENTS :: 2048
+}
+
+DEFAULT_BATCH_BUFFERS            :: 1                    // Default number of batch buffers (multi-buffering)
+DEFAULT_BATCH_DRAWCALLS          :: 256                  // Default number of batch draw calls (by state changes: mode, texture)
+DEFAULT_BATCH_MAX_TEXTURE_UNITS  :: 4                    // Maximum number of additional textures that can be activated on batch drawing (SetShaderValueTexture())
+
+// Internal Matrix stack
+MAX_MATRIX_STACK_SIZE          :: 32                   // Maximum size of Matrix stack
+
+// Shader limits
+MAX_SHADER_LOCATIONS           :: 32                   // Maximum number of shader locations supported
+
+// Projection matrix culling
+CULL_DISTANCE_NEAR          :: 0.01                 // Default near cull distance
+CULL_DISTANCE_FAR           :: 1000.0               // Default far cull distance
+
+// Texture parameters (equivalent to OpenGL defines)
+TEXTURE_WRAP_S                       :: 0x2802      // GL_TEXTURE_WRAP_S
+TEXTURE_WRAP_T                       :: 0x2803      // GL_TEXTURE_WRAP_T
+TEXTURE_MAG_FILTER                   :: 0x2800      // GL_TEXTURE_MAG_FILTER
+TEXTURE_MIN_FILTER                   :: 0x2801      // GL_TEXTURE_MIN_FILTER
+
+TEXTURE_FILTER_NEAREST               :: 0x2600      // GL_NEAREST
+TEXTURE_FILTER_LINEAR                :: 0x2601      // GL_LINEAR
+TEXTURE_FILTER_MIP_NEAREST           :: 0x2700      // GL_NEAREST_MIPMAP_NEAREST
+TEXTURE_FILTER_NEAREST_MIP_LINEAR    :: 0x2702      // GL_NEAREST_MIPMAP_LINEAR
+TEXTURE_FILTER_LINEAR_MIP_NEAREST    :: 0x2701      // GL_LINEAR_MIPMAP_NEAREST
+TEXTURE_FILTER_MIP_LINEAR            :: 0x2703      // GL_LINEAR_MIPMAP_LINEAR
+TEXTURE_FILTER_ANISOTROPIC           :: 0x3000      // Anisotropic filter (custom identifier)
+
+TEXTURE_WRAP_REPEAT                  :: 0x2901      // GL_REPEAT
+TEXTURE_WRAP_CLAMP                   :: 0x812F      // GL_CLAMP_TO_EDGE
+TEXTURE_WRAP_MIRROR_REPEAT           :: 0x8370      // GL_MIRRORED_REPEAT
+TEXTURE_WRAP_MIRROR_CLAMP            :: 0x8742      // GL_MIRROR_CLAMP_EXT
+
+// Matrix modes (equivalent to OpenGL)
+MODELVIEW                            :: 0x1700      // GL_MODELVIEW
+PROJECTION                           :: 0x1701      // GL_PROJECTION
+TEXTURE                              :: 0x1702      // GL_TEXTURE
+
+// Primitive assembly draw modes
+LINES                                :: 0x0001      // GL_LINES
+TRIANGLES                            :: 0x0004      // GL_TRIANGLES
+QUADS                                :: 0x0007      // GL_QUADS
+
+// GL equivalent data types
+UNSIGNED_BYTE                        :: 0x1401      // GL_UNSIGNED_BYTE
+FLOAT                                :: 0x1406      // GL_FLOAT
+
+// Buffer usage hint
+STREAM_DRAW                          :: 0x88E0      // GL_STREAM_DRAW
+STREAM_READ                          :: 0x88E1      // GL_STREAM_READ
+STREAM_COPY                          :: 0x88E2      // GL_STREAM_COPY
+STATIC_DRAW                          :: 0x88E4      // GL_STATIC_DRAW
+STATIC_READ                          :: 0x88E5      // GL_STATIC_READ
+STATIC_COPY                          :: 0x88E6      // GL_STATIC_COPY
+DYNAMIC_DRAW                         :: 0x88E8      // GL_DYNAMIC_DRAW
+DYNAMIC_READ                         :: 0x88E9      // GL_DYNAMIC_READ
+DYNAMIC_COPY                         :: 0x88EA      // GL_DYNAMIC_COPY
+
+// GL Shader type
+FRAGMENT_SHADER                      :: 0x8B30      // GL_FRAGMENT_SHADER
+VERTEX_SHADER                        :: 0x8B31      // GL_VERTEX_SHADER
+COMPUTE_SHADER                       :: 0x91B9      // GL_COMPUTE_SHADER
+
+// GL blending factors
+ZERO                                 :: 0           // GL_ZERO
+ONE                                  :: 1           // GL_ONE
+SRC_COLOR                            :: 0x0300      // GL_SRC_COLOR
+ONE_MINUS_SRC_COLOR                  :: 0x0301      // GL_ONE_MINUS_SRC_COLOR
+SRC_ALPHA                            :: 0x0302      // GL_SRC_ALPHA
+ONE_MINUS_SRC_ALPHA                  :: 0x0303      // GL_ONE_MINUS_SRC_ALPHA
+DST_ALPHA                            :: 0x0304      // GL_DST_ALPHA
+ONE_MINUS_DST_ALPHA                  :: 0x0305      // GL_ONE_MINUS_DST_ALPHA
+DST_COLOR                            :: 0x0306      // GL_DST_COLOR
+ONE_MINUS_DST_COLOR                  :: 0x0307      // GL_ONE_MINUS_DST_COLOR
+SRC_ALPHA_SATURATE                   :: 0x0308      // GL_SRC_ALPHA_SATURATE
+CONSTANT_COLOR                       :: 0x8001      // GL_CONSTANT_COLOR
+ONE_MINUS_CONSTANT_COLOR             :: 0x8002      // GL_ONE_MINUS_CONSTANT_COLOR
+CONSTANT_ALPHA                       :: 0x8003      // GL_CONSTANT_ALPHA
+ONE_MINUS_CONSTANT_ALPHA             :: 0x8004      // GL_ONE_MINUS_CONSTANT_ALPHA
+
+// GL blending functions/equations
+FUNC_ADD                             :: 0x8006      // GL_FUNC_ADD
+MIN                                  :: 0x8007      // GL_MIN
+MAX                                  :: 0x8008      // GL_MAX
+FUNC_SUBTRACT                        :: 0x800A      // GL_FUNC_SUBTRACT
+FUNC_REVERSE_SUBTRACT                :: 0x800B      // GL_FUNC_REVERSE_SUBTRACT
+BLEND_EQUATION                       :: 0x8009      // GL_BLEND_EQUATION
+BLEND_EQUATION_RGB                   :: 0x8009      // GL_BLEND_EQUATION_RGB   // (Same as BLEND_EQUATION)
+BLEND_EQUATION_ALPHA                 :: 0x883D      // GL_BLEND_EQUATION_ALPHA
+BLEND_DST_RGB                        :: 0x80C8      // GL_BLEND_DST_RGB
+BLEND_SRC_RGB                        :: 0x80C9      // GL_BLEND_SRC_RGB
+BLEND_DST_ALPHA                      :: 0x80CA      // GL_BLEND_DST_ALPHA
+BLEND_SRC_ALPHA                      :: 0x80CB      // GL_BLEND_SRC_ALPHA
+BLEND_COLOR                          :: 0x8005      // GL_BLEND_COLOR
+
+//----------------------------------------------------------------------------------
+// Types and Structures Definition
+//----------------------------------------------------------------------------------
+
+
+VertexBufferIndexType :: c.ushort when GRAPHICS_API_OPENGL_ES2 else c.uint
+
+// Dynamic vertex buffers (position + texcoords + colors + indices arrays)
+VertexBuffer :: struct {
+	elementCount: c.int,                 // Number of elements in the buffer (QUADS)
+
+	vertices:  [^]f32,                   // Vertex position (XYZ - 3 components per vertex) (shader-location = 0)
+	texcoords: [^]f32,                   // Vertex texture coordinates (UV - 2 components per vertex) (shader-location = 1)
+	colors:    [^]u8,                    // Vertex colors (RGBA - 4 components per vertex) (shader-location = 3)
+	indices:   [^]VertexBufferIndexType, // Vertex indices (in case vertex data comes indexed) (6 indices per quad)
+	vaoId:     c.uint,                   // OpenGL Vertex Array Object id
+	vboId:     [4]c.uint,                // OpenGL Vertex Buffer Objects id (4 types of vertex data)
+}
+
+// Draw call type
+// NOTE: Only texture changes register a new draw, other state-change-related elements are not
+// used at this moment (vaoId, shaderId, matrices), raylib just forces a batch draw call if any
+// of those state-change happens (this is done in core module)
+DrawCall :: struct {
+	mode:            c.int,        // Drawing mode: LINES, TRIANGLES, QUADS
+	vertexCount:     c.int,        // Number of vertex of the draw
+	vertexAlignment: c.int,        // Number of vertex required for index alignment (LINES, TRIANGLES)
+	textureId:       c.uint,       // Texture id to be used on the draw -> Use to create new draw call if changes
+}
+
+// RenderBatch type
+RenderBatch :: struct {
+	bufferCount:   c.int,           // Number of vertex buffers (multi-buffering support)
+	currentBuffer: c.int,           // Current buffer tracking in case of multi-buffering
+	vertexBuffer:  [^]VertexBuffer, // Dynamic buffer(s) for vertex data
+
+	draws:         [^]DrawCall,     // Draw calls array, depends on textureId
+	drawCounter:   c.int,           // Draw calls counter
+	currentDepth:  f32,             // Current depth value for next draw
+}
+
+// OpenGL version
+GlVersion :: enum c.int {
+	OPENGL_11 = 1,           // OpenGL 1.1
+	OPENGL_21,               // OpenGL 2.1 (GLSL 120)
+	OPENGL_33,               // OpenGL 3.3 (GLSL 330)
+	OPENGL_43,               // OpenGL 4.3 (using GLSL 330)
+	OPENGL_ES_20,            // OpenGL ES 2.0 (GLSL 100)
+	OPENGL_ES_30,            // OpenGL ES 3.0 (GLSL 300 es)
+}
+
+PixelFormat :: rl.PixelFormat
+TextureFilter :: rl.TextureFilter
+BlendMode :: rl.BlendMode
+ShaderLocationIndex :: rl.ShaderLocationIndex
+ShaderUniformDataType :: rl.ShaderUniformDataType
+
+// Shader attribute data types
+ShaderAttributeDataType :: enum c.int {
+	FLOAT = 0,         // Shader attribute type: float
+	VEC2,              // Shader attribute type: vec2 (2 float)
+	VEC3,              // Shader attribute type: vec3 (3 float)
+	VEC4,              // Shader attribute type: vec4 (4 float)
+}
+
+// Framebuffer attachment type
+// NOTE: By default up to 8 color channels defined, but it can be more
+FramebufferAttachType :: enum c.int {
+	COLOR_CHANNEL0 = 0,   // Framebuffer attachment type: color 0
+	COLOR_CHANNEL1 = 1,   // Framebuffer attachment type: color 1
+	COLOR_CHANNEL2 = 2,   // Framebuffer attachment type: color 2
+	COLOR_CHANNEL3 = 3,   // Framebuffer attachment type: color 3
+	COLOR_CHANNEL4 = 4,   // Framebuffer attachment type: color 4
+	COLOR_CHANNEL5 = 5,   // Framebuffer attachment type: color 5
+	COLOR_CHANNEL6 = 6,   // Framebuffer attachment type: color 6
+	COLOR_CHANNEL7 = 7,   // Framebuffer attachment type: color 7
+	DEPTH = 100,          // Framebuffer attachment type: depth
+	STENCIL = 200,        // Framebuffer attachment type: stencil
+}
+
+// Framebuffer texture attachment type
+FramebufferAttachTextureType :: enum c.int {
+	CUBEMAP_POSITIVE_X = 0, // Framebuffer texture attachment type: cubemap, +X side
+	CUBEMAP_NEGATIVE_X = 1, // Framebuffer texture attachment type: cubemap, -X side
+	CUBEMAP_POSITIVE_Y = 2, // Framebuffer texture attachment type: cubemap, +Y side
+	CUBEMAP_NEGATIVE_Y = 3, // Framebuffer texture attachment type: cubemap, -Y side
+	CUBEMAP_POSITIVE_Z = 4, // Framebuffer texture attachment type: cubemap, +Z side
+	CUBEMAP_NEGATIVE_Z = 5, // Framebuffer texture attachment type: cubemap, -Z side
+	TEXTURE2D = 100,        // Framebuffer texture attachment type: texture2d
+	RENDERBUFFER = 200,     // Framebuffer texture attachment type: renderbuffer
+}
+
+CullMode :: enum c.int {
+	FRONT = 0,
+	BACK,
+}
+
+Matrix :: rl.Matrix
+
+@(default_calling_convention="c", link_prefix="rl")
+foreign lib {
+	//------------------------------------------------------------------------------------
+	// Functions Declaration - Matrix operations
+	//------------------------------------------------------------------------------------
+	MatrixMode   :: proc(mode: c.int) ---                 // Choose the current matrix to be transformed
+	PushMatrix   :: proc() ---                            // Push the current matrix to stack
+	PopMatrix    :: proc() ---                            // Pop lattest inserted matrix from stack
+	LoadIdentity :: proc() ---                            // Reset current matrix to identity matrix
+	Translatef   :: proc(x, y, z: f32) ---                // Multiply the current matrix by a translation matrix
+	Rotatef      :: proc(angleDeg: f32, x, y, z: f32) --- // Multiply the current matrix by a rotation matrix
+	Scalef       :: proc(x, y, z: f32) ---                // Multiply the current matrix by a scaling matrix
+	MultMatrixf  :: proc(matf: [^]f32) ---                // Multiply the current matrix by another matrix
+	Frustum      :: proc(left, right, bottom, top, znear, zfar: f64) ---
+	Ortho        :: proc(left, right, bottom, top, znear, zfar: f64) ---
+	Viewport     :: proc(x, y, width, height: c.int) ---  // Set the viewport area
+
+	//------------------------------------------------------------------------------------
+	// Functions Declaration - Vertex level operations
+	//------------------------------------------------------------------------------------
+	Begin        :: proc(mode: c.int)     --- // Initialize drawing mode (how to organize vertex)
+	End          :: proc()                --- // Finish vertex providing
+	Vertex2i     :: proc(x, y: c.int)     --- // Define one vertex (position) - 2 int
+	Vertex2f     :: proc(x, y: f32)       --- // Define one vertex (position) - 2 f32
+	Vertex3f     :: proc(x, y, z: f32)    --- // Define one vertex (position) - 3 f32
+	TexCoord2f   :: proc(x, y: f32)       --- // Define one vertex (texture coordinate) - 2 f32
+	Normal3f     :: proc(x, y, z: f32)    --- // Define one vertex (normal) - 3 f32
+	Color4ub     :: proc(r, g, b, a: u8)  --- // Define one vertex (color) - 4 byte
+	Color3f      :: proc(x, y, z: f32)    --- // Define one vertex (color) - 3 f32
+	Color4f      :: proc(x, y, z, w: f32) --- // Define one vertex (color) - 4 f32
+
+	//------------------------------------------------------------------------------------
+	// Functions Declaration - OpenGL style functions (common to 1.1, 3.3+, ES2)
+	// NOTE: This functions are used to completely abstract raylib code from OpenGL layer,
+	// some of them are direct wrappers over OpenGL calls, some others are custom
+	//------------------------------------------------------------------------------------
+
+	// Vertex buffers state
+	EnableVertexArray          :: proc(vaoId: c.uint) -> bool --- // Enable vertex array (VAO, if supported)
+	DisableVertexArray         :: proc() ---                      // Disable vertex array (VAO, if supported)
+	EnableVertexBuffer         :: proc(id: c.uint) ---            // Enable vertex buffer (VBO)
+	DisableVertexBuffer        :: proc() ---                      // Disable vertex buffer (VBO)
+	EnableVertexBufferElement  :: proc(id: c.uint) ---            // Enable vertex buffer element (VBO element)
+	DisableVertexBufferElement :: proc() ---                      // Disable vertex buffer element (VBO element)
+	EnableVertexAttribute      :: proc(index: c.uint) ---         // Enable vertex attribute index
+	DisableVertexAttribute     :: proc(index: c.uint) ---         // Disable vertex attribute index
+	when GRAPHICS_API_OPENGL_11 {
+		EnableStatePointer :: proc(vertexAttribType: c.int, buffer: rawptr) ---
+		DisableStatePointer :: proc(vertexAttribType: c.int) ---
+	}
+
+	// Textures state
+	ActiveTextureSlot     :: proc(slot: c.int) ---                            // Select and active a texture slot
+	EnableTexture         :: proc(id: c.uint) ---                             // Enable texture
+	DisableTexture        :: proc() ---                                       // Disable texture
+	EnableTextureCubemap  :: proc(id: c.uint) ---                             // Enable texture cubemap
+	DisableTextureCubemap :: proc() ---                                       // Disable texture cubemap
+	TextureParameters     :: proc(id: c.uint, param: c.int, value: c.int) --- // Set texture parameters (filter, wrap)
+	CubemapParameters     :: proc(id: i32, param: c.int, value: c.int) ---    // Set cubemap parameters (filter, wrap)
+
+	// Shader state
+	EnableShader  :: proc(id: c.uint) ---                                       // Enable shader program
+	DisableShader :: proc() ---                                                 // Disable shader program
+
+	// Framebuffer state
+	EnableFramebuffer  :: proc(id: c.uint) ---                                  // Enable render texture (fbo)
+	DisableFramebuffer :: proc() ---                                            // Disable render texture (fbo), return to default framebuffer
+	ActiveDrawBuffers  :: proc(count: c.int) ---                                // Activate multiple draw color buffers
+	BlitFramebuffer	 :: proc(srcX, srcY, srcWidth, srcHeight, dstX, dstY, dstWidth, dstHeight, bufferMask: c.int) --- // Blit active framebuffer to main framebuffer
+
+	// General render state
+	DisableColorBlend      :: proc() ---                           // Disable color blending
+	EnableDepthTest        :: proc() ---                           // Enable depth test
+	DisableDepthTest       :: proc() ---                           // Disable depth test
+	EnableDepthMask        :: proc() ---                           // Enable depth write
+	DisableDepthMask       :: proc() ---                           // Disable depth write
+	EnableBackfaceCulling  :: proc() ---                           // Enable backface culling
+	DisableBackfaceCulling :: proc() ---                           // Disable backface culling
+	SetCullFace            :: proc(mode: CullMode) ---             // Set face culling mode
+	EnableScissorTest      :: proc() ---                           // Enable scissor test
+	DisableScissorTest     :: proc() ---                           // Disable scissor test
+	Scissor                :: proc(x, y, width, height: c.int) --- // Scissor test
+	EnableWireMode         :: proc() ---                           // Enable wire mode
+	EnablePointMode        :: proc() --- 							 // Enable point mode
+	DisableWireMode        :: proc() ---                           // Disable wire and point modes
+	SetLineWidth           :: proc(width: f32) ---                 // Set the line drawing width
+	GetLineWidth           :: proc() -> f32 ---                    // Get the line drawing width
+	EnableSmoothLines      :: proc() ---                           // Enable line aliasing
+	DisableSmoothLines     :: proc() ---                           // Disable line aliasing
+	EnableStereoRender     :: proc() ---                           // Enable stereo rendering
+	DisableStereoRender    :: proc() ---                           // Disable stereo rendering
+	IsStereoRenderEnabled  :: proc() -> bool ---                   // Check if stereo render is enabled
+
+
+	ClearColor              :: proc(r, g, b, a: u8) ---                                                        // Clear color buffer with color
+	ClearScreenBuffers      :: proc() ---                                                                      // Clear used screen buffers (color and depth)
+	CheckErrors             :: proc() ---                                                                      // Check and log OpenGL error codes
+	SetBlendMode            :: proc(mode: c.int) ---                                                           // Set blending mode
+	SetBlendFactors         :: proc(glSrcFactor, glDstFactor, glEquation: c.int) ---                           // Set blending mode factor and equation (using OpenGL factors)
+	SetBlendFactorsSeparate :: proc(glSrcRGB, glDstRGB, glSrcAlpha, glDstAlpha, glEqRGB, glEqAlpha: c.int) --- // Set blending mode factors and equations separately (using OpenGL factors)
+
+	//------------------------------------------------------------------------------------
+	// Functions Declaration - rlgl functionality
+	//------------------------------------------------------------------------------------
+	// rlgl initialization functions
+	@(link_prefix="rlgl")
+	Init                 :: proc(width, height: c.int) --- // Initialize rlgl (buffers, shaders, textures, states)
+	@(link_prefix="rlgl")
+	Close                :: proc() ---                     // De-initialize rlgl (buffers, shaders, textures)
+	LoadExtensions       :: proc(loader: rawptr) ---       // Load OpenGL extensions (loader function required)
+	GetVersion           :: proc() -> GlVersion ---        // Get current OpenGL version
+	SetFramebufferWidth  :: proc(width: c.int) ---         // Set current framebuffer width
+	GetFramebufferWidth  :: proc() -> c.int ---            // Get default framebuffer width
+	SetFramebufferHeight :: proc(height: c.int) ---        // Set current framebuffer height
+	GetFramebufferHeight :: proc() -> c.int ---            // Get default framebuffer height
+
+
+	GetTextureIdDefault  :: proc() -> c.uint ---   // Get default texture id
+	GetShaderIdDefault   :: proc() -> c.uint ---   // Get default shader id
+	GetShaderLocsDefault :: proc() -> [^]c.int --- // Get default shader locations
+
+	// Render batch management
+	// NOTE: rlgl provides a default render batch to behave like OpenGL 1.1 immediate mode
+	// but this render batch API is exposed in case of custom batches are required
+	LoadRenderBatch       :: proc(numBuffers, bufferElements: c.int) -> RenderBatch --- // Load a render batch system
+	UnloadRenderBatch     :: proc(batch: RenderBatch) ---                               // Unload render batch system
+	DrawRenderBatch       :: proc(batch: ^RenderBatch) ---                              // Draw render batch data (Update->Draw->Reset)
+	SetRenderBatchActive  :: proc(batch: ^RenderBatch) ---                              // Set the active render batch for rlgl (NULL for default internal)
+	DrawRenderBatchActive :: proc() ---                                                 // Update and draw internal render batch
+	CheckRenderBatchLimit :: proc(vCount: c.int) -> c.int ---                           // Check internal buffer overflow for a given number of vertex
+
+	SetTexture :: proc(id: c.uint) --- // Set current texture for render batch and check buffers limits
+
+	//------------------------------------------------------------------------------------------------------------------------
+
+	// Vertex buffers management
+	LoadVertexArray                  :: proc() -> c.uint ---                                                      // Load vertex array (vao) if supported
+	LoadVertexBuffer                 :: proc(buffer: rawptr, size: c.int, is_dynamic: bool) -> c.uint ---         // Load a vertex buffer attribute
+	LoadVertexBufferElement          :: proc(buffer: rawptr, size: c.int, is_dynamic: bool) -> c.uint ---         // Load a new attributes element buffer
+	UpdateVertexBuffer               :: proc(bufferId: c.uint, data: rawptr, dataSize: c.int, offset: c.int) ---  // Update GPU buffer with new data
+	UpdateVertexBufferElements       :: proc(id: c.uint, data: rawptr, dataSize: c.int, offset: c.int) ---        // Update vertex buffer elements with new data
+	UnloadVertexArray                :: proc(vaoId: c.uint) ---
+	UnloadVertexBuffer               :: proc(vboId: c.uint) ---
+	SetVertexAttribute               :: proc(index: c.uint, compSize: c.int, type: c.int, normalized: bool, stride: c.int, pointer: rawptr) ---
+	SetVertexAttributeDivisor        :: proc(index: c.uint, divisor: c.int) ---
+	SetVertexAttributeDefault        :: proc(locIndex: c.int, value: rawptr, attribType: c.int, count: c.int) --- // Set vertex attribute default value
+	DrawVertexArray                  :: proc(offset: c.int, count: c.int) ---
+	DrawVertexArrayElements          :: proc(offset: c.int, count: c.int, buffer: rawptr) ---
+	DrawVertexArrayInstanced         :: proc(offset: c.int, count: c.int, instances: c.int) ---
+	DrawVertexArrayElementsInstanced :: proc(offset: c.int, count: c.int, buffer: rawptr, instances: c.int) ---
+
+	// Textures management
+	LoadTexture         :: proc(data: rawptr, width, height: c.int, format: c.int, mipmapCount: c.int) -> c.uint ---        // Load texture in GPU
+	LoadTextureDepth    :: proc(width, height: c.int, useRenderBuffer: bool) -> c.uint ---                                  // Load depth texture/renderbuffer (to be attached to fbo)
+	LoadTextureCubemap  :: proc(data: rawptr, size: c.int, format: c.int) -> c.uint ---                                     // Load texture cubemap
+	UpdateTexture       :: proc(id: c.uint, offsetX, offsetY: c.int, width, height: c.int, format: c.int, data: rawptr) --- // Update GPU texture with new data
+	GetGlTextureFormats :: proc(format: c.int, glInternalFormat, glFormat, glType: ^c.uint) ---                             // Get OpenGL internal formats
+	GetPixelFormatName  :: proc(format: c.uint) -> cstring ---                                                              // Get name string for pixel format
+	UnloadTexture       :: proc(id: c.uint) ---                                                                             // Unload texture from GPU memory
+	GenTextureMipmaps   :: proc(id: c.uint, width, height: c.int, format: c.int, mipmaps: ^c.int) ---                       // Generate mipmap data for selected texture
+	ReadTexturePixels   :: proc(id: c.uint, width, height: c.int, format: c.int) -> rawptr ---                              // Read texture pixel data
+	ReadScreenPixels    :: proc(width, height: c.int) -> [^]byte ---                                                        // Read screen pixel data (color buffer)
+
+	// Framebuffer management (fbo)
+	LoadFramebuffer     :: proc(width, height: c.int) -> c.uint ---                                           // Load an empty framebuffer
+	FramebufferAttach   :: proc(fboId, texId: c.uint, attachType: c.int, texType: c.int, mipLevel: c.int) --- // Attach texture/renderbuffer to a framebuffer
+	FramebufferComplete :: proc(id: c.uint) -> bool ---                                                       // Verify framebuffer is complete
+	UnloadFramebuffer   :: proc(id: c.uint) ---                                                               // Delete framebuffer from GPU
+
+	// Shaders management
+	LoadShaderCode      :: proc(vsCode, fsCode: cstring) -> c.uint ---                                // Load shader from code strings
+	CompileShader       :: proc(shaderCode: cstring, type: c.int) -> c.uint ---                       // Compile custom shader and return shader id (type: VERTEX_SHADER, FRAGMENT_SHADER, COMPUTE_SHADER)
+	LoadShaderProgram   :: proc(vShaderId, fShaderId: c.uint) -> c.uint ---                           // Load custom shader program
+	UnloadShaderProgram :: proc(id: c.uint) ---                                                       // Unload shader program
+	GetLocationUniform  :: proc(shaderId: c.uint, uniformName: cstring) -> c.int ---                  // Get shader location uniform
+	GetLocationAttrib   :: proc(shaderId: c.uint, attribName: cstring) -> c.int ---                   // Get shader location attribute
+	SetUniform          :: proc(locIndex: c.int, value: rawptr, uniformType: c.int, count: c.int) --- // Set shader value uniform
+	SetUniformMatrix    :: proc(locIndex: c.int, mat: Matrix) ---                                     // Set shader value matrix
+	SetUniformSampler   :: proc(locIndex: c.int, textureId: c.uint) ---                               // Set shader value sampler
+	SetShader           :: proc(id: c.uint, locs: [^]c.int) ---                                       // Set shader currently active (id and locations)
+
+	// Compute shader management
+	LoadComputeShaderProgram :: proc(shaderId: c.uint) -> c.uint ---     // Load compute shader program
+	ComputeShaderDispatch    :: proc(groupX, groupY, groupZ: c.uint) --- // Dispatch compute shader (equivalent to *draw* for graphics pipeline)
+
+	// Shader buffer storage object management (ssbo)
+	LoadShaderBuffer    :: proc(size: c.uint, data: rawptr, usageHint: c.int) -> c.uint ---              // Load shader storage buffer object (SSBO)
+	UnloadShaderBuffer  :: proc(ssboId: c.uint) ---                                                      // Unload shader storage buffer object (SSBO)
+	UpdateShaderBuffer  :: proc(id: c.uint, data: rawptr, dataSize: c.uint, offset: c.uint) ---          // Update SSBO buffer data
+	BindShaderBuffer    :: proc(id: c.uint, index: c.uint) ---                                           // Bind SSBO buffer
+	ReadShaderBuffer    :: proc(id: c.uint, dest: rawptr, count: c.uint, offset: c.uint) ---             // Read SSBO buffer data (GPU->CPU)
+	CopyShaderBuffer    :: proc(destId, srcId: c.uint, destOffset, srcOffset: c.uint, count: c.uint) --- // Copy SSBO data between buffers
+	GetShaderBufferSize :: proc(id: c.uint) -> c.uint ---                                                // Get SSBO buffer size
+
+	// Buffer management
+	BindImageTexture :: proc(id: c.uint, index: c.uint, format: c.int, readonly: bool) ---  // Bind image texture
+
+	// Matrix state management
+	GetMatrixModelview        :: proc() -> Matrix ---           // Get internal modelview matrix
+	GetMatrixProjection       :: proc() -> Matrix ---           // Get internal projection matrix
+	GetMatrixTransform        :: proc() -> Matrix ---           // Get internal accumulated transform matrix
+	GetMatrixProjectionStereo :: proc(eye: c.int) -> Matrix --- // Get internal projection matrix for stereo render (selected eye)
+	GetMatrixViewOffsetStereo :: proc(eye: c.int) -> Matrix --- // Get internal view offset matrix for stereo render (selected eye)
+	SetMatrixProjection       :: proc(proj: Matrix) ---         // Set a custom projection matrix (replaces internal projection matrix)
+	SetMatrixModelview        :: proc(view: Matrix) ---         // Set a custom modelview matrix (replaces internal modelview matrix)
+	SetMatrixProjectionStereo :: proc(right, left: Matrix) ---  // Set eyes projection matrices for stereo rendering
+	SetMatrixViewOffsetStereo :: proc(right, left: Matrix) ---  // Set eyes view offsets matrices for stereo rendering
+
+	// Quick and dirty cube/quad buffers load->draw->unload
+	LoadDrawCube :: proc() --- // Load and draw a cube
+	LoadDrawQuad :: proc() --- // Load and draw a quad
+}