diff options
| author | avanspector <94762082+avanspector@users.noreply.github.com> | 2025-01-06 16:42:29 +0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-01-06 16:42:29 +0400 |
| commit | be7799459be05af307a79d80bd4ac9f61eedac7c (patch) | |
| tree | 4c272a6d20028768f731367fca3325eeceb3567d | |
| parent | a20d85df1eaf7a24c407256786b714044a87e5ff (diff) | |
| parent | 98efb03934b464a1b23759b5695a12ff37588357 (diff) | |
Merge branch 'odin-lang:master' into master
92 files changed, 2809 insertions, 1207 deletions
diff --git a/base/builtin/builtin.odin b/base/builtin/builtin.odin index c4a9b141f..227ceeb49 100644 --- a/base/builtin/builtin.odin +++ b/base/builtin/builtin.odin @@ -1,6 +1,8 @@ // This is purely for documentation package builtin +import "base:runtime" + nil :: nil false :: 0!=0 true :: 0==0 diff --git a/base/intrinsics/intrinsics.odin b/base/intrinsics/intrinsics.odin index 744a899c0..ee0d357e4 100644 --- a/base/intrinsics/intrinsics.odin +++ b/base/intrinsics/intrinsics.odin @@ -2,6 +2,8 @@ #+build ignore package intrinsics +import "base:runtime" + // Package-Related is_package_imported :: proc(package_name: string) -> bool --- @@ -72,7 +74,7 @@ prefetch_write_instruction :: proc(address: rawptr, #const locality: i32 /* 0..= prefetch_write_data :: proc(address: rawptr, #const locality: i32 /* 0..=3 */) --- // Compiler Hints -expect :: proc(val, expected_val: T) -> T --- +expect :: proc(val, expected_val: $T) -> T --- // Linux and Darwin Only syscall :: proc(id: uintptr, args: ..uintptr) -> uintptr --- @@ -219,7 +221,7 @@ type_map_cell_info :: proc($T: typeid) -> ^runtime.Map_Cell_Info --- type_convert_variants_to_pointers :: proc($T: typeid) -> typeid where type_is_union(T) --- type_merge :: proc($U, $V: typeid) -> typeid where type_is_union(U), type_is_union(V) --- -type_has_shared_fields :: proc($U, $V: typeid) -> bool typeid where type_is_struct(U), type_is_struct(V) --- +type_has_shared_fields :: proc($U, $V: typeid) -> bool where type_is_struct(U), type_is_struct(V) --- constant_utf16_cstring :: proc($literal: string) -> [^]u16 --- diff --git a/base/runtime/core_builtin.odin b/base/runtime/core_builtin.odin index d28dadd02..cf379aacb 100644 --- a/base/runtime/core_builtin.odin +++ b/base/runtime/core_builtin.odin @@ -826,10 +826,12 @@ _resize_dynamic_array :: #force_inline proc(a: ^Raw_Dynamic_Array, size_of_elem, return nil } + if should_zero && a.len < length { + num_reused := min(a.cap, length) - a.len + intrinsics.mem_zero(([^]byte)(a.data)[a.len*size_of_elem:], num_reused*size_of_elem) + } + if length <= a.cap { - if should_zero && a.len < length { - intrinsics.mem_zero(([^]byte)(a.data)[a.len*size_of_elem:], (length-a.len)*size_of_elem) - } a.len = max(length, 0) return nil } @@ -936,6 +938,32 @@ map_upsert :: proc(m: ^$T/map[$K]$V, key: K, value: V, loc := #caller_location) return } +/* +Retrieves a pointer to the key and value for a possibly just inserted entry into the map. + +If the `key` was not in the map `m`, an entry is inserted with the zero value and `just_inserted` will be `true`. +Otherwise the existing entry is left untouched and pointers to its key and value are returned. + +If the map has to grow in order to insert the entry and the allocation fails, `err` is set and returned. + +If `err` is `nil`, `key_ptr` and `value_ptr` are valid pointers and will not be `nil`. + +WARN: User modification of the key pointed at by `key_ptr` should only be done if the new key is equal to (in hash) the old key. +If that is not the case you will corrupt the map. +*/ +@(builtin, require_results) +map_entry :: proc(m: ^$T/map[$K]$V, key: K, loc := #caller_location) -> (key_ptr: ^K, value_ptr: ^V, just_inserted: bool, err: Allocator_Error) { + key := key + zero: V + + _key_ptr, _value_ptr: rawptr + _key_ptr, _value_ptr, just_inserted, err = __dynamic_map_entry((^Raw_Map)(m), map_info(T), &key, &zero, loc) + + key_ptr = (^K)(_key_ptr) + value_ptr = (^V)(_value_ptr) + return +} + @builtin card :: proc "contextless" (s: $S/bit_set[$E; $U]) -> int { @@ -964,6 +992,24 @@ assert :: proc(condition: bool, message := #caller_expression(condition), loc := } } +// Evaluates the condition and aborts the program iff the condition is +// false. This routine ignores `ODIN_DISABLE_ASSERT`, and will always +// execute. +@builtin +ensure :: proc(condition: bool, message := #caller_expression(condition), loc := #caller_location) { + if !condition { + @(cold) + internal :: proc(message: string, loc: Source_Code_Location) { + p := context.assertion_failure_proc + if p == nil { + p = default_assertion_failure_proc + } + p("unsatisfied ensure", message, loc) + } + internal(message, loc) + } +} + @builtin panic :: proc(message: string, loc := #caller_location) -> ! { p := context.assertion_failure_proc @@ -1000,6 +1046,17 @@ assert_contextless :: proc "contextless" (condition: bool, message := #caller_ex } @builtin +ensure_contextless :: proc "contextless" (condition: bool, message := #caller_expression(condition), loc := #caller_location) { + if !condition { + @(cold) + internal :: proc "contextless" (message: string, loc: Source_Code_Location) { + default_assertion_contextless_failure_proc("unsatisfied ensure", message, loc) + } + internal(message, loc) + } +} + +@builtin panic_contextless :: proc "contextless" (message: string, loc := #caller_location) -> ! { default_assertion_contextless_failure_proc("panic", message, loc) } diff --git a/base/runtime/dynamic_map_internal.odin b/base/runtime/dynamic_map_internal.odin index 3dded7716..b95e3cd14 100644 --- a/base/runtime/dynamic_map_internal.odin +++ b/base/runtime/dynamic_map_internal.odin @@ -158,21 +158,21 @@ map_cell_index_static :: #force_inline proc "contextless" (cells: [^]Map_Cell($T } else when (N & (N - 1)) == 0 && N <= 8*size_of(uintptr) { // Likely case, N is a power of two because T is a power of two. + // Unique case, no need to index data here since only one element. + when N == 1 { + return &cells[index].data[0] + } + // Compute the integer log 2 of N, this is the shift amount to index the // correct cell. Odin's intrinsics.count_leading_zeros does not produce a // constant, hence this approach. We only need to check up to N = 64. - SHIFT :: 1 when N < 2 else - 2 when N < 4 else - 3 when N < 8 else - 4 when N < 16 else - 5 when N < 32 else 6 + SHIFT :: 1 when N == 2 else + 2 when N == 4 else + 3 when N == 8 else + 4 when N == 16 else + 5 when N == 32 else 6 #assert(SHIFT <= MAP_CACHE_LINE_LOG2) - // Unique case, no need to index data here since only one element. - when N == 1 { - return &cells[index >> SHIFT].data[0] - } else { - return &cells[index >> SHIFT].data[index & (N - 1)] - } + return &cells[index >> SHIFT].data[index & (N - 1)] } else { // Least likely (and worst case), we pay for a division operation but we // assume the compiler does not actually generate a division. N will be in the @@ -941,6 +941,29 @@ __dynamic_map_set_extra :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^ return nil, rawptr(result) } +__dynamic_map_entry :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_Info, key: rawptr, zero: rawptr, loc := #caller_location) -> (key_ptr: rawptr, value_ptr: rawptr, just_inserted: bool, err: Allocator_Error) { + hash := info.key_hasher(key, map_seed(m^)) + + if key_ptr, value_ptr = __dynamic_map_get_key_and_value(m, info, hash, key); value_ptr != nil { + return + } + + has_grown: bool + if err, has_grown = __dynamic_map_check_grow(m, info, loc); err != nil { + return + } else if has_grown { + hash = info.key_hasher(key, map_seed(m^)) + } + + value_ptr = rawptr(map_insert_hash_dynamic(m, info, hash, uintptr(key), uintptr(zero))) + assert(value_ptr != nil) + key_ptr = rawptr(map_cell_index_dynamic(map_data(m^), info.ks, map_desired_position(m^, hash))) + + m.len += 1 + just_inserted = true + return +} + // IMPORTANT: USED WITHIN THE COMPILER @(private) diff --git a/build_odin.sh b/build_odin.sh index 09094c151..f4452e291 100755 --- a/build_odin.sh +++ b/build_odin.sh @@ -110,8 +110,8 @@ Linux) LDFLAGS="$LDFLAGS -Wl,-rpath=\$ORIGIN" ;; OpenBSD) - CXXFLAGS="$CXXFLAGS $($LLVM_CONFIG --cxxflags --ldflags)" - LDFLAGS="$LDFLAGS -liconv" + CXXFLAGS="$CXXFLAGS -I/usr/local/include $($LLVM_CONFIG --cxxflags --ldflags)" + LDFLAGS="$LDFLAGS -L/usr/local/lib -liconv" LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs)" ;; Haiku) diff --git a/core/encoding/base32/base32.odin b/core/encoding/base32/base32.odin index f3320428d..8629491b1 100644 --- a/core/encoding/base32/base32.odin +++ b/core/encoding/base32/base32.odin @@ -1,148 +1,230 @@ -package encoding_base32
-
-// @note(zh): Encoding utility for Base32
-// A secondary param can be used to supply a custom alphabet to
-// @link(encode) and a matching decoding table to @link(decode).
-// If none is supplied it just uses the standard Base32 alphabet.
-// Incase your specific version does not use padding, you may
-// truncate it from the encoded output.
-
-ENC_TABLE := [32]byte {
- 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
- 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
- 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
- 'Y', 'Z', '2', '3', '4', '5', '6', '7',
-}
-
-PADDING :: '='
-
-DEC_TABLE := [?]u8 {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 26, 27, 28, 29, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
- 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0,
- 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
- 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-}
-
-encode :: proc(data: []byte, ENC_TBL := ENC_TABLE, allocator := context.allocator) -> string {
- out_length := (len(data) + 4) / 5 * 8
- out := make([]byte, out_length)
- _encode(out, data)
- return string(out)
-}
-
-@private
-_encode :: proc(out, data: []byte, ENC_TBL := ENC_TABLE, allocator := context.allocator) {
- out := out
- data := data
-
- for len(data) > 0 {
- carry: byte
- switch len(data) {
- case:
- out[7] = ENC_TABLE[data[4] & 0x1f]
- carry = data[4] >> 5
- fallthrough
- case 4:
- out[6] = ENC_TABLE[carry | (data[3] << 3) & 0x1f]
- out[5] = ENC_TABLE[(data[3] >> 2) & 0x1f]
- carry = data[3] >> 7
- fallthrough
- case 3:
- out[4] = ENC_TABLE[carry | (data[2] << 1) & 0x1f]
- carry = (data[2] >> 4) & 0x1f
- fallthrough
- case 2:
- out[3] = ENC_TABLE[carry | (data[1] << 4) & 0x1f]
- out[2] = ENC_TABLE[(data[1] >> 1) & 0x1f]
- carry = (data[1] >> 6) & 0x1f
- fallthrough
- case 1:
- out[1] = ENC_TABLE[carry | (data[0] << 2) & 0x1f]
- out[0] = ENC_TABLE[data[0] >> 3]
- }
-
- if len(data) < 5 {
- out[7] = byte(PADDING)
- if len(data) < 4 {
- out[6] = byte(PADDING)
- out[5] = byte(PADDING)
- if len(data) < 3 {
- out[4] = byte(PADDING)
- if len(data) < 2 {
- out[3] = byte(PADDING)
- out[2] = byte(PADDING)
- }
- }
- }
- break
- }
- data = data[5:]
- out = out[8:]
- }
-}
-
-decode :: proc(data: string, DEC_TBL := DEC_TABLE, allocator := context.allocator) -> []byte #no_bounds_check{
- if len(data) == 0 {
- return nil
- }
-
- outi := 0
- data := data
-
- out := make([]byte, len(data) / 8 * 5, allocator)
- end := false
- for len(data) > 0 && !end {
- dbuf : [8]byte
- dlen := 8
-
- for j := 0; j < 8; {
- if len(data) == 0 {
- dlen, end = j, true
- break
- }
- input := data[0]
- data = data[1:]
- if input == byte(PADDING) && j >= 2 && len(data) < 8 {
- assert(!(len(data) + j < 8 - 1), "Corrupted input")
- for k := 0; k < 8-1-j; k +=1 {
- assert(len(data) < k || data[k] == byte(PADDING), "Corrupted input")
- }
- dlen, end = j, true
- assert(dlen != 1 && dlen != 3 && dlen != 6, "Corrupted input")
- break
- }
- dbuf[j] = DEC_TABLE[input]
- assert(dbuf[j] != 0xff, "Corrupted input")
- j += 1
- }
-
- switch dlen {
- case 8:
- out[outi + 4] = dbuf[6] << 5 | dbuf[7]
- fallthrough
- case 7:
- out[outi + 3] = dbuf[4] << 7 | dbuf[5] << 2 | dbuf[6] >> 3
- fallthrough
- case 5:
- out[outi + 2] = dbuf[3] << 4 | dbuf[4] >> 1
- fallthrough
- case 4:
- out[outi + 1] = dbuf[1] << 6 | dbuf[2] << 1 | dbuf[3] >> 4
- fallthrough
- case 2:
- out[outi + 0] = dbuf[0] << 3 | dbuf[1] >> 2
- }
- outi += 5
- }
- return out
-}
+// Base32 encoding/decoding implementation as specified in RFC 4648. +// [[ More; https://www.rfc-editor.org/rfc/rfc4648.html ]] +package encoding_base32 + +// @note(zh): Encoding utility for Base32 +// A secondary param can be used to supply a custom alphabet to +// @link(encode) and a matching decoding table to @link(decode). +// If none is supplied it just uses the standard Base32 alphabet. +// In case your specific version does not use padding, you may +// truncate it from the encoded output. + +// Error represents errors that can occur during base32 decoding operations. +// As per RFC 4648: +// - Section 3.3: Invalid character handling +// - Section 3.2: Padding requirements +// - Section 6: Base32 encoding specifics (including block size requirements) +Error :: enum { + None, + Invalid_Character, // Input contains characters outside the specified alphabet + Invalid_Length, // Input length is not valid for base32 (must be a multiple of 8 with proper padding) + Malformed_Input, // Input has improper structure (wrong padding position or incomplete groups) +} + +Validate_Proc :: #type proc(c: byte) -> bool + +@private +_validate_default :: proc(c: byte) -> bool { + return (c >= 'A' && c <= 'Z') || (c >= '2' && c <= '7') +} + +@(rodata) +ENC_TABLE := [32]byte { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', + 'Y', 'Z', '2', '3', '4', '5', '6', '7', +} + +PADDING :: '=' + +@(rodata) +DEC_TABLE := [256]u8 { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 26, 27, 28, 29, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0, + 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +} + +encode :: proc(data: []byte, ENC_TBL := ENC_TABLE, allocator := context.allocator) -> string { + out_length := (len(data) + 4) / 5 * 8 + out := make([]byte, out_length, allocator) + _encode(out, data, ENC_TBL) + return string(out[:]) +} + +@private +_encode :: proc(out, data: []byte, ENC_TBL := ENC_TABLE, allocator := context.allocator) { + out := out + data := data + + for len(data) > 0 { + carry: byte + switch len(data) { + case: + out[7] = ENC_TBL[data[4] & 0x1f] + carry = data[4] >> 5 + fallthrough + case 4: + out[6] = ENC_TBL[carry | (data[3] << 3) & 0x1f] + out[5] = ENC_TBL[(data[3] >> 2) & 0x1f] + carry = data[3] >> 7 + fallthrough + case 3: + out[4] = ENC_TBL[carry | (data[2] << 1) & 0x1f] + carry = (data[2] >> 4) & 0x1f + fallthrough + case 2: + out[3] = ENC_TBL[carry | (data[1] << 4) & 0x1f] + out[2] = ENC_TBL[(data[1] >> 1) & 0x1f] + carry = (data[1] >> 6) & 0x1f + fallthrough + case 1: + out[1] = ENC_TBL[carry | (data[0] << 2) & 0x1f] + out[0] = ENC_TBL[data[0] >> 3] + } + + if len(data) < 5 { + out[7] = byte(PADDING) + if len(data) < 4 { + out[6] = byte(PADDING) + out[5] = byte(PADDING) + if len(data) < 3 { + out[4] = byte(PADDING) + if len(data) < 2 { + out[3] = byte(PADDING) + out[2] = byte(PADDING) + } + } + } + break + } + data = data[5:] + out = out[8:] + } +} + +@(optimization_mode="favor_size") +decode :: proc( + data: string, + DEC_TBL := DEC_TABLE, + validate: Validate_Proc = _validate_default, + allocator := context.allocator) -> (out: []byte, err: Error) { + if len(data) == 0 { + return nil, .None + } + + // Check minimum length requirement first + if len(data) < 2 { + return nil, .Invalid_Length + } + + // Validate characters using provided validation function + for i := 0; i < len(data); i += 1 { + c := data[i] + if c == byte(PADDING) { + break + } + if !validate(c) { + return nil, .Invalid_Character + } + } + + // Validate padding and length + data_len := len(data) + padding_count := 0 + for i := data_len - 1; i >= 0; i -= 1 { + if data[i] != byte(PADDING) { + break + } + padding_count += 1 + } + + // Check for proper padding and length combinations + if padding_count > 0 { + // Verify no padding in the middle + for i := 0; i < data_len - padding_count; i += 1 { + if data[i] == byte(PADDING) { + return nil, .Malformed_Input + } + } + + content_len := data_len - padding_count + mod8 := content_len % 8 + required_padding: int + switch mod8 { + case 2: required_padding = 6 // 2 chars need 6 padding chars + case 4: required_padding = 4 // 4 chars need 4 padding chars + case 5: required_padding = 3 // 5 chars need 3 padding chars + case 7: required_padding = 1 // 7 chars need 1 padding char + case: required_padding = 0 + } + + if required_padding > 0 { + if padding_count != required_padding { + return nil, .Malformed_Input + } + } else if mod8 != 0 { + return nil, .Malformed_Input + } + } else { + // No padding - must be multiple of 8 + if data_len % 8 != 0 { + return nil, .Malformed_Input + } + } + + // Calculate decoded length: 5 bytes for every 8 input chars + input_chars := data_len - padding_count + out_len := input_chars * 5 / 8 + out = make([]byte, out_len, allocator) + defer if err != .None { + delete(out) + } + + // Process input in 8-byte blocks + outi := 0 + for i := 0; i < input_chars; i += 8 { + buf: [8]byte + block_size := min(8, input_chars - i) + + // Decode block + for j := 0; j < block_size; j += 1 { + buf[j] = DEC_TBL[data[i + j]] + } + + // Convert to output bytes based on block size + bytes_to_write := block_size * 5 / 8 + switch block_size { + case 8: + out[outi + 4] = (buf[6] << 5) | buf[7] + fallthrough + case 7: + out[outi + 3] = (buf[4] << 7) | (buf[5] << 2) | (buf[6] >> 3) + fallthrough + case 5: + out[outi + 2] = (buf[3] << 4) | (buf[4] >> 1) + fallthrough + case 4: + out[outi + 1] = (buf[1] << 6) | (buf[2] << 1) | (buf[3] >> 4) + fallthrough + case 2: + out[outi] = (buf[0] << 3) | (buf[1] >> 2) + } + outi += bytes_to_write + } + + return +} diff --git a/core/encoding/base32/base32_test.odin b/core/encoding/base32/base32_test.odin new file mode 100644 index 000000000..ea41ae36f --- /dev/null +++ b/core/encoding/base32/base32_test.odin @@ -0,0 +1,227 @@ +package encoding_base32 + +import "core:testing" +import "core:bytes" + +@(test) +test_base32_decode_valid :: proc(t: ^testing.T) { + // RFC 4648 Section 10 - Test vectors + cases := [?]struct { + input, expected: string, + }{ + {"", ""}, + {"MY======", "f"}, + {"MZXQ====", "fo"}, + {"MZXW6===", "foo"}, + {"MZXW6YQ=", "foob"}, + {"MZXW6YTB", "fooba"}, + {"MZXW6YTBOI======", "foobar"}, + } + + for c in cases { + output, err := decode(c.input) + if output != nil { + defer delete(output) + } + testing.expect_value(t, err, Error.None) + expected := transmute([]u8)c.expected + if output != nil { + testing.expect(t, bytes.equal(output, expected)) + } else { + testing.expect(t, len(c.expected) == 0) + } + } +} + +@(test) +test_base32_encode :: proc(t: ^testing.T) { + // RFC 4648 Section 10 - Test vectors + cases := [?]struct { + input, expected: string, + }{ + {"", ""}, + {"f", "MY======"}, + {"fo", "MZXQ===="}, + {"foo", "MZXW6==="}, + {"foob", "MZXW6YQ="}, + {"fooba", "MZXW6YTB"}, + {"foobar", "MZXW6YTBOI======"}, + } + + for c in cases { + output := encode(transmute([]byte)c.input) + defer delete(output) + testing.expect(t, output == c.expected) + } +} + +@(test) +test_base32_decode_invalid :: proc(t: ^testing.T) { + // Section 3.3 - Non-alphabet characters + { + // Characters outside alphabet + input := "MZ1W6YTB" // '1' not in alphabet (A-Z, 2-7) + output, err := decode(input) + if output != nil { + defer delete(output) + } + testing.expect_value(t, err, Error.Invalid_Character) + } + { + // Lowercase not allowed + input := "mzxq====" + output, err := decode(input) + if output != nil { + defer delete(output) + } + testing.expect_value(t, err, Error.Invalid_Character) + } + + // Section 3.2 - Padding requirements + { + // Padding must only be at end + input := "MZ=Q====" + output, err := decode(input) + if output != nil { + defer delete(output) + } + testing.expect_value(t, err, Error.Malformed_Input) + } + { + // Missing padding + input := "MZXQ" // Should be MZXQ==== + output, err := decode(input) + if output != nil { + defer delete(output) + } + testing.expect_value(t, err, Error.Malformed_Input) + } + { + // Incorrect padding length + input := "MZXQ=" // Needs 4 padding chars + output, err := decode(input) + if output != nil { + defer delete(output) + } + testing.expect_value(t, err, Error.Malformed_Input) + } + { + // Too much padding + input := "MY=========" // Extra padding chars + output, err := decode(input) + if output != nil { + defer delete(output) + } + testing.expect_value(t, err, Error.Malformed_Input) + } + + // Section 6 - Base32 block size requirements + { + // Single character (invalid block) + input := "M" + output, err := decode(input) + if output != nil { + defer delete(output) + } + testing.expect_value(t, err, Error.Invalid_Length) + } +} + +@(test) +test_base32_roundtrip :: proc(t: ^testing.T) { + cases := [?]string{ + "", + "f", + "fo", + "foo", + "foob", + "fooba", + "foobar", + } + + for input in cases { + encoded := encode(transmute([]byte)input) + defer delete(encoded) + decoded, err := decode(encoded) + if decoded != nil { + defer delete(decoded) + } + testing.expect_value(t, err, Error.None) + testing.expect(t, bytes.equal(decoded, transmute([]byte)input)) + } +} + +@(test) +test_base32_custom_alphabet :: proc(t: ^testing.T) { + custom_enc_table := [32]byte{ + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', + 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', + 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', + } + + custom_dec_table: [256]u8 + for i := 0; i < len(custom_enc_table); i += 1 { + custom_dec_table[custom_enc_table[i]] = u8(i) + } + + /* + custom_dec_table := [256]u8{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x00-0x0f + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x10-0x1f + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x20-0x2f + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, // 0x30-0x3f ('0'-'9') + 0, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, // 0x40-0x4f ('A'-'O') + 25, 26, 27, 28, 29, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x50-0x5f ('P'-'V') + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x60-0x6f + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x70-0x7f + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x80-0x8f + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x90-0x9f + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xa0-0xaf + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xb0-0xbf + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xc0-0xcf + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xd0-0xdf + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xe0-0xef + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xf0-0xff + } + */ + + custom_validate :: proc(c: byte) -> bool { + return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'V') || c == byte(PADDING) + } + + cases := [?]struct { + input: string, + enc_expected: string, + }{ + {"f", "CO======"}, + {"fo", "CPNG===="}, + {"foo", "CPNMU==="}, + } + + for c in cases { + // Test encoding + encoded := encode(transmute([]byte)c.input, custom_enc_table) + defer delete(encoded) + testing.expect(t, encoded == c.enc_expected) + + // Test decoding + decoded, err := decode(encoded, custom_dec_table, custom_validate) + defer if decoded != nil { + delete(decoded) + } + + testing.expect_value(t, err, Error.None) + testing.expect(t, bytes.equal(decoded, transmute([]byte)c.input)) + } + + // Test invalid character detection + { + input := "WXY=====" // Contains chars not in our alphabet + output, err := decode(input, custom_dec_table, custom_validate) + if output != nil { + delete(output) + } + testing.expect_value(t, err, Error.Invalid_Character) + } +} diff --git a/core/encoding/json/unmarshal.odin b/core/encoding/json/unmarshal.odin index c70b8d39a..57371e360 100644 --- a/core/encoding/json/unmarshal.odin +++ b/core/encoding/json/unmarshal.odin @@ -439,7 +439,7 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm use_field_idx := -1 for field, field_idx in fields { - tag_value := string(reflect.struct_tag_get(field.tag, "json")) + tag_value := reflect.struct_tag_get(field.tag, "json") json_name, _ := json_name_from_tag_value(tag_value) if key == json_name { use_field_idx = field_idx @@ -470,7 +470,7 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm } } - if field.name == key { + if field.name == key || (field.tag != "" && reflect.struct_tag_get(field.tag, "json") == key) { offset = field.offset type = field.type found = true diff --git a/core/image/general.odin b/core/image/general.odin index c4a884071..e92b54f18 100644 --- a/core/image/general.odin +++ b/core/image/general.odin @@ -146,7 +146,7 @@ which_bytes :: proc(data: []byte) -> Which_File_Type { case s[6:10] == "JFIF", s[6:10] == "Exif": return .JPEG case s[:3] == "\xff\xd8\xff": - switch s[4] { + switch s[3] { case 0xdb, 0xee, 0xe1, 0xe0: return .JPEG } diff --git a/core/image/png/helpers.odin b/core/image/png/helpers.odin index f094b54a9..a9495ed4d 100644 --- a/core/image/png/helpers.odin +++ b/core/image/png/helpers.odin @@ -396,132 +396,4 @@ exif :: proc(c: image.PNG_Chunk) -> (res: Exif, ok: bool) { General helper functions */ -compute_buffer_size :: image.compute_buffer_size - -/* - PNG save helpers -*/ - -when false { - - make_chunk :: proc(c: any, t: Chunk_Type) -> (res: Chunk) { - - data: []u8 - if v, ok := c.([]u8); ok { - data = v - } else { - data = mem.any_to_bytes(c) - } - - res.header.length = u32be(len(data)) - res.header.type = t - res.data = data - - // CRC the type - crc := hash.crc32(mem.any_to_bytes(res.header.type)) - // Extend the CRC with the data - res.crc = u32be(hash.crc32(data, crc)) - return - } - - write_chunk :: proc(fd: os.Handle, chunk: Chunk) { - c := chunk - // Write length + type - os.write_ptr(fd, &c.header, 8) - // Write data - os.write_ptr(fd, mem.raw_data(c.data), int(c.header.length)) - // Write CRC32 - os.write_ptr(fd, &c.crc, 4) - } - - write_image_as_png :: proc(filename: string, image: Image) -> (err: Error) { - profiler.timed_proc() - using image - using os - flags: int = O_WRONLY|O_CREATE|O_TRUNC - - if len(image.pixels) == 0 || len(image.pixels) < image.width * image.height * int(image.channels) { - return .Invalid_Image_Dimensions - } - - mode: int = 0 - when ODIN_OS == .Linux || ODIN_OS == .Darwin { - // NOTE(justasd): 644 (owner read, write; group read; others read) - mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH - } - - fd, fderr := open(filename, flags, mode) - if fderr != nil { - return .Cannot_Open_File - } - defer close(fd) - - magic := Signature - - write_ptr(fd, &magic, 8) - - ihdr := IHDR{ - width = u32be(width), - height = u32be(height), - bit_depth = depth, - compression_method = 0, - filter_method = 0, - interlace_method = .None, - } - - switch channels { - case 1: ihdr.color_type = Color_Type{} - case 2: ihdr.color_type = Color_Type{.Alpha} - case 3: ihdr.color_type = Color_Type{.Color} - case 4: ihdr.color_type = Color_Type{.Color, .Alpha} - case:// Unhandled - return .Unknown_Color_Type - } - h := make_chunk(ihdr, .IHDR) - write_chunk(fd, h) - - bytes_needed := width * height * int(channels) + height - filter_bytes := mem.make_dynamic_array_len_cap([dynamic]u8, bytes_needed, bytes_needed, context.allocator) - defer delete(filter_bytes) - - i := 0; j := 0 - // Add a filter byte 0 per pixel row - for y := 0; y < height; y += 1 { - filter_bytes[j] = 0; j += 1 - for x := 0; x < width; x += 1 { - for z := 0; z < channels; z += 1 { - filter_bytes[j+z] = image.pixels[i+z] - } - i += channels; j += channels - } - } - assert(j == bytes_needed) - - a: []u8 = filter_bytes[:] - - out_buf: ^[dynamic]u8 - defer free(out_buf) - - ctx := zlib.ZLIB_Context{ - in_buf = &a, - out_buf = out_buf, - } - err = zlib.write_zlib_stream_from_memory(&ctx) - - b: []u8 - if err == nil { - b = ctx.out_buf[:] - } else { - return err - } - - idat := make_chunk(b, .IDAT) - - write_chunk(fd, idat) - - iend := make_chunk([]u8{}, .IEND) - write_chunk(fd, iend) - - return nil - } -} +compute_buffer_size :: image.compute_buffer_size
\ No newline at end of file diff --git a/core/io/util.odin b/core/io/util.odin index 296be7bc0..fdbbd5b9f 100644 --- a/core/io/util.odin +++ b/core/io/util.odin @@ -132,9 +132,13 @@ write_encoded_rune :: proc(w: Writer, r: rune, write_quote := true, n_written: ^ buf: [2]byte s := strconv.append_bits(buf[:], u64(r), 16, true, 64, strconv.digits, nil) switch len(s) { - case 0: write_string(w, "00", &n) or_return - case 1: write_byte(w, '0', &n) or_return - case 2: write_string(w, s, &n) or_return + case 0: + write_string(w, "00", &n) or_return + case 1: + write_byte(w, '0', &n) or_return + fallthrough + case 2: + write_string(w, s, &n) or_return } } else { write_rune(w, r, &n) or_return diff --git a/core/math/linalg/general.odin b/core/math/linalg/general.odin index 8c4f2954a..4a0150972 100644 --- a/core/math/linalg/general.odin +++ b/core/math/linalg/general.odin @@ -417,6 +417,13 @@ adjugate :: proc{ matrix4x4_adjugate, } +cofactor :: proc{ + matrix1x1_cofactor, + matrix2x2_cofactor, + matrix3x3_cofactor, + matrix4x4_cofactor, +} + inverse_transpose :: proc{ matrix1x1_inverse_transpose, matrix2x2_inverse_transpose, @@ -479,9 +486,9 @@ matrix3x3_determinant :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (det: T) # } @(require_results) matrix4x4_determinant :: proc "contextless" (m: $M/matrix[4, 4]$T) -> (det: T) #no_bounds_check { - a := adjugate(m) + c := cofactor(m) for i in 0..<4 { - det += m[0, i] * a[0, i] + det += m[0, i] * c[0, i] } return } @@ -498,6 +505,47 @@ matrix1x1_adjugate :: proc "contextless" (x: $M/matrix[1, 1]$T) -> (y: M) #no_bo @(require_results) matrix2x2_adjugate :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) #no_bounds_check { y[0, 0] = +x[1, 1] + y[0, 1] = -x[0, 1] + y[1, 0] = -x[1, 0] + y[1, 1] = +x[0, 0] + return +} + +@(require_results) +matrix3x3_adjugate :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (y: M) #no_bounds_check { + y[0, 0] = +(m[1, 1] * m[2, 2] - m[2, 1] * m[1, 2]) + y[1, 0] = -(m[1, 0] * m[2, 2] - m[2, 0] * m[1, 2]) + y[2, 0] = +(m[1, 0] * m[2, 1] - m[2, 0] * m[1, 1]) + y[0, 1] = -(m[0, 1] * m[2, 2] - m[2, 1] * m[0, 2]) + y[1, 1] = +(m[0, 0] * m[2, 2] - m[2, 0] * m[0, 2]) + y[2, 1] = -(m[0, 0] * m[2, 1] - m[2, 0] * m[0, 1]) + y[0, 2] = +(m[0, 1] * m[1, 2] - m[1, 1] * m[0, 2]) + y[1, 2] = -(m[0, 0] * m[1, 2] - m[1, 0] * m[0, 2]) + y[2, 2] = +(m[0, 0] * m[1, 1] - m[1, 0] * m[0, 1]) + return +} + +@(require_results) +matrix4x4_adjugate :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) #no_bounds_check { + for i in 0..<4 { + for j in 0..<4 { + sign: T = 1 if (i + j) % 2 == 0 else -1 + y[i, j] = sign * matrix_minor(x, j, i) + } + } + return +} + + +@(require_results) +matrix1x1_cofactor :: proc "contextless" (x: $M/matrix[1, 1]$T) -> (y: M) #no_bounds_check { + y = x + return +} + +@(require_results) +matrix2x2_cofactor :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) #no_bounds_check { + y[0, 0] = +x[1, 1] y[0, 1] = -x[1, 0] y[1, 0] = -x[0, 1] y[1, 1] = +x[0, 0] @@ -505,7 +553,7 @@ matrix2x2_adjugate :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) #no_bo } @(require_results) -matrix3x3_adjugate :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (y: M) #no_bounds_check { +matrix3x3_cofactor :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (y: M) #no_bounds_check { y[0, 0] = +(m[1, 1] * m[2, 2] - m[2, 1] * m[1, 2]) y[0, 1] = -(m[1, 0] * m[2, 2] - m[2, 0] * m[1, 2]) y[0, 2] = +(m[1, 0] * m[2, 1] - m[2, 0] * m[1, 1]) @@ -520,7 +568,7 @@ matrix3x3_adjugate :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (y: M) #no_bo @(require_results) -matrix4x4_adjugate :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) #no_bounds_check { +matrix4x4_cofactor :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) #no_bounds_check { for i in 0..<4 { for j in 0..<4 { sign: T = 1 if (i + j) % 2 == 0 else -1 @@ -556,19 +604,19 @@ matrix2x2_inverse_transpose :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: @(require_results) matrix3x3_inverse_transpose :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y: M) #no_bounds_check { - a := adjugate(x) + c := cofactor(x) d := determinant(x) when intrinsics.type_is_integer(T) { for i in 0..<3 { for j in 0..<3 { - y[i, j] = a[i, j] / d + y[i, j] = c[i, j] / d } } } else { id := 1/d for i in 0..<3 { for j in 0..<3 { - y[i, j] = a[i, j] * id + y[i, j] = c[i, j] * id } } } @@ -577,22 +625,22 @@ matrix3x3_inverse_transpose :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y: @(require_results) matrix4x4_inverse_transpose :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) #no_bounds_check { - a := adjugate(x) + c := cofactor(x) d: T for i in 0..<4 { - d += x[0, i] * a[0, i] + d += x[0, i] * c[0, i] } when intrinsics.type_is_integer(T) { for i in 0..<4 { for j in 0..<4 { - y[i, j] = a[i, j] / d + y[i, j] = c[i, j] / d } } } else { id := 1/d for i in 0..<4 { for j in 0..<4 { - y[i, j] = a[i, j] * id + y[i, j] = c[i, j] * id } } } @@ -625,19 +673,19 @@ matrix2x2_inverse :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) #no_bou @(require_results) matrix3x3_inverse :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y: M) #no_bounds_check { - a := adjugate(x) + c := cofactor(x) d := determinant(x) when intrinsics.type_is_integer(T) { for i in 0..<3 { for j in 0..<3 { - y[i, j] = a[j, i] / d + y[i, j] = c[j, i] / d } } } else { id := 1/d for i in 0..<3 { for j in 0..<3 { - y[i, j] = a[j, i] * id + y[i, j] = c[j, i] * id } } } @@ -646,22 +694,22 @@ matrix3x3_inverse :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y: M) #no_bou @(require_results) matrix4x4_inverse :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) #no_bounds_check { - a := adjugate(x) + c := cofactor(x) d: T for i in 0..<4 { - d += x[0, i] * a[0, i] + d += x[0, i] * c[0, i] } when intrinsics.type_is_integer(T) { for i in 0..<4 { for j in 0..<4 { - y[i, j] = a[j, i] / d + y[i, j] = c[j, i] / d } } } else { id := 1/d for i in 0..<4 { for j in 0..<4 { - y[i, j] = a[j, i] * id + y[i, j] = c[j, i] * id } } } diff --git a/core/math/linalg/glsl/linalg_glsl.odin b/core/math/linalg/glsl/linalg_glsl.odin index ca61891cb..bd2cf416a 100644 --- a/core/math/linalg/glsl/linalg_glsl.odin +++ b/core/math/linalg/glsl/linalg_glsl.odin @@ -1882,6 +1882,13 @@ adjugate :: proc{ adjugate_matrix4x4, } +cofactor :: proc{ + cofactor_matrix1x1, + cofactor_matrix2x2, + cofactor_matrix3x3, + cofactor_matrix4x4, +} + inverse_transpose :: proc{ inverse_transpose_matrix1x1, inverse_transpose_matrix2x2, @@ -1944,9 +1951,9 @@ determinant_matrix3x3 :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (det: T) { } @(require_results) determinant_matrix4x4 :: proc "contextless" (m: $M/matrix[4, 4]$T) -> (det: T) { - a := adjugate(m) + c := cofactor(m) #no_bounds_check for i in 0..<4 { - det += m[0, i] * a[0, i] + det += m[0, i] * c[0, i] } return } @@ -1963,6 +1970,47 @@ adjugate_matrix1x1 :: proc "contextless" (x: $M/matrix[1, 1]$T) -> (y: M) { @(require_results) adjugate_matrix2x2 :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) { y[0, 0] = +x[1, 1] + y[0, 1] = -x[0, 1] + y[1, 0] = -x[1, 0] + y[1, 1] = +x[0, 0] + return +} + +@(require_results) +adjugate_matrix3x3 :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (y: M) { + y[0, 0] = +(m[1, 1] * m[2, 2] - m[2, 1] * m[1, 2]) + y[1, 0] = -(m[1, 0] * m[2, 2] - m[2, 0] * m[1, 2]) + y[2, 0] = +(m[1, 0] * m[2, 1] - m[2, 0] * m[1, 1]) + y[0, 1] = -(m[0, 1] * m[2, 2] - m[2, 1] * m[0, 2]) + y[1, 1] = +(m[0, 0] * m[2, 2] - m[2, 0] * m[0, 2]) + y[2, 1] = -(m[0, 0] * m[2, 1] - m[2, 0] * m[0, 1]) + y[0, 2] = +(m[0, 1] * m[1, 2] - m[1, 1] * m[0, 2]) + y[1, 2] = -(m[0, 0] * m[1, 2] - m[1, 0] * m[0, 2]) + y[2, 2] = +(m[0, 0] * m[1, 1] - m[1, 0] * m[0, 1]) + return +} + +@(require_results) +adjugate_matrix4x4 :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) { + for i in 0..<4 { + for j in 0..<4 { + sign: T = 1 if (i + j) % 2 == 0 else -1 + y[i, j] = sign * matrix_minor(x, j, i) + } + } + return +} + + +@(require_results) +cofactor_matrix1x1 :: proc "contextless" (x: $M/matrix[1, 1]$T) -> (y: M) { + y = x + return +} + +@(require_results) +cofactor_matrix2x2 :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) { + y[0, 0] = +x[1, 1] y[0, 1] = -x[1, 0] y[1, 0] = -x[0, 1] y[1, 1] = +x[0, 0] @@ -1970,7 +2018,7 @@ adjugate_matrix2x2 :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) { } @(require_results) -adjugate_matrix3x3 :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (y: M) { +cofactor_matrix3x3 :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (y: M) { y[0, 0] = +(m[1, 1] * m[2, 2] - m[2, 1] * m[1, 2]) y[0, 1] = -(m[1, 0] * m[2, 2] - m[2, 0] * m[1, 2]) y[0, 2] = +(m[1, 0] * m[2, 1] - m[2, 0] * m[1, 1]) @@ -1985,7 +2033,7 @@ adjugate_matrix3x3 :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (y: M) { @(require_results) -adjugate_matrix4x4 :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) { +cofactor_matrix4x4 :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) { for i in 0..<4 { for j in 0..<4 { sign: T = 1 if (i + j) % 2 == 0 else -1 @@ -2021,19 +2069,19 @@ inverse_transpose_matrix2x2 :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: @(require_results) inverse_transpose_matrix3x3 :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y: M) #no_bounds_check { - a := adjugate(x) + c := cofactor(x) d := determinant(x) when intrinsics.type_is_integer(T) { for i in 0..<3 { for j in 0..<3 { - y[i, j] = a[i, j] / d + y[i, j] = c[i, j] / d } } } else { id := 1/d for i in 0..<3 { for j in 0..<3 { - y[i, j] = a[i, j] * id + y[i, j] = c[i, j] * id } } } @@ -2042,22 +2090,22 @@ inverse_transpose_matrix3x3 :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y: @(require_results) inverse_transpose_matrix4x4 :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) #no_bounds_check { - a := adjugate(x) + c := cofactor(x) d: T for i in 0..<4 { - d += x[0, i] * a[0, i] + d += x[0, i] * c[0, i] } when intrinsics.type_is_integer(T) { for i in 0..<4 { for j in 0..<4 { - y[i, j] = a[i, j] / d + y[i, j] = c[i, j] / d } } } else { id := 1/d for i in 0..<4 { for j in 0..<4 { - y[i, j] = a[i, j] * id + y[i, j] = c[i, j] * id } } } @@ -2090,19 +2138,19 @@ inverse_matrix2x2 :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) { @(require_results) inverse_matrix3x3 :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y: M) #no_bounds_check { - a := adjugate(x) + c := cofactor(x) d := determinant(x) when intrinsics.type_is_integer(T) { for i in 0..<3 { for j in 0..<3 { - y[i, j] = a[j, i] / d + y[i, j] = c[j, i] / d } } } else { id := 1/d for i in 0..<3 { for j in 0..<3 { - y[i, j] = a[j, i] * id + y[i, j] = c[j, i] * id } } } @@ -2111,22 +2159,22 @@ inverse_matrix3x3 :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y: M) #no_bou @(require_results) inverse_matrix4x4 :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) #no_bounds_check { - a := adjugate(x) + c := cofactor(x) d: T for i in 0..<4 { - d += x[0, i] * a[0, i] + d += x[0, i] * c[0, i] } when intrinsics.type_is_integer(T) { for i in 0..<4 { for j in 0..<4 { - y[i, j] = a[j, i] / d + y[i, j] = c[j, i] / d } } } else { id := 1/d for i in 0..<4 { for j in 0..<4 { - y[i, j] = a[j, i] * id + y[i, j] = c[j, i] * id } } } diff --git a/core/math/linalg/hlsl/linalg_hlsl.odin b/core/math/linalg/hlsl/linalg_hlsl.odin index a89fdddd3..cca70f9c8 100644 --- a/core/math/linalg/hlsl/linalg_hlsl.odin +++ b/core/math/linalg/hlsl/linalg_hlsl.odin @@ -1514,6 +1514,13 @@ adjugate :: proc{ adjugate_matrix4x4, } +cofactor :: proc{ + cofactor_matrix1x1, + cofactor_matrix2x2, + cofactor_matrix3x3, + cofactor_matrix4x4, +} + inverse_transpose :: proc{ inverse_transpose_matrix1x1, inverse_transpose_matrix2x2, @@ -1568,9 +1575,9 @@ determinant_matrix3x3 :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (det: T) { } @(require_results) determinant_matrix4x4 :: proc "contextless" (m: $M/matrix[4, 4]$T) -> (det: T) { - a := adjugate(m) + c := cofactor(m) #no_bounds_check for i in 0..<4 { - det += m[0, i] * a[0, i] + det += m[0, i] * c[0, i] } return } @@ -1587,6 +1594,47 @@ adjugate_matrix1x1 :: proc "contextless" (x: $M/matrix[1, 1]$T) -> (y: M) { @(require_results) adjugate_matrix2x2 :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) { y[0, 0] = +x[1, 1] + y[0, 1] = -x[0, 1] + y[1, 0] = -x[1, 0] + y[1, 1] = +x[0, 0] + return +} + +@(require_results) +adjugate_matrix3x3 :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (y: M) { + y[0, 0] = +(m[1, 1] * m[2, 2] - m[2, 1] * m[1, 2]) + y[1, 0] = -(m[1, 0] * m[2, 2] - m[2, 0] * m[1, 2]) + y[2, 0] = +(m[1, 0] * m[2, 1] - m[2, 0] * m[1, 1]) + y[0, 1] = -(m[0, 1] * m[2, 2] - m[2, 1] * m[0, 2]) + y[1, 1] = +(m[0, 0] * m[2, 2] - m[2, 0] * m[0, 2]) + y[2, 1] = -(m[0, 0] * m[2, 1] - m[2, 0] * m[0, 1]) + y[0, 2] = +(m[0, 1] * m[1, 2] - m[1, 1] * m[0, 2]) + y[1, 2] = -(m[0, 0] * m[1, 2] - m[1, 0] * m[0, 2]) + y[2, 2] = +(m[0, 0] * m[1, 1] - m[1, 0] * m[0, 1]) + return +} + +@(require_results) +adjugate_matrix4x4 :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) { + for i in 0..<4 { + for j in 0..<4 { + sign: T = 1 if (i + j) % 2 == 0 else -1 + y[i, j] = sign * matrix_minor(x, j, i) + } + } + return +} + + +@(require_results) +cofactor_matrix1x1 :: proc "contextless" (x: $M/matrix[1, 1]$T) -> (y: M) { + y = x + return +} + +@(require_results) +cofactor_matrix2x2 :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) { + y[0, 0] = +x[1, 1] y[0, 1] = -x[1, 0] y[1, 0] = -x[0, 1] y[1, 1] = +x[0, 0] @@ -1594,7 +1642,7 @@ adjugate_matrix2x2 :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) { } @(require_results) -adjugate_matrix3x3 :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (y: M) { +cofactor_matrix3x3 :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (y: M) { y[0, 0] = +(m[1, 1] * m[2, 2] - m[2, 1] * m[1, 2]) y[0, 1] = -(m[1, 0] * m[2, 2] - m[2, 0] * m[1, 2]) y[0, 2] = +(m[1, 0] * m[2, 1] - m[2, 0] * m[1, 1]) @@ -1609,7 +1657,7 @@ adjugate_matrix3x3 :: proc "contextless" (m: $M/matrix[3, 3]$T) -> (y: M) { @(require_results) -adjugate_matrix4x4 :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) { +cofactor_matrix4x4 :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) { for i in 0..<4 { for j in 0..<4 { sign: T = 1 if (i + j) % 2 == 0 else -1 @@ -1645,19 +1693,19 @@ inverse_transpose_matrix2x2 :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: @(require_results) inverse_transpose_matrix3x3 :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y: M) #no_bounds_check { - a := adjugate(x) + c := cofactor(x) d := determinant(x) when intrinsics.type_is_integer(T) { for i in 0..<3 { for j in 0..<3 { - y[i, j] = a[i, j] / d + y[i, j] = c[i, j] / d } } } else { id := 1/d for i in 0..<3 { for j in 0..<3 { - y[i, j] = a[i, j] * id + y[i, j] = c[i, j] * id } } } @@ -1666,22 +1714,22 @@ inverse_transpose_matrix3x3 :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y: @(require_results) inverse_transpose_matrix4x4 :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) #no_bounds_check { - a := adjugate(x) + c := cofactor(x) d: T for i in 0..<4 { - d += x[0, i] * a[0, i] + d += x[0, i] * c[0, i] } when intrinsics.type_is_integer(T) { for i in 0..<4 { for j in 0..<4 { - y[i, j] = a[i, j] / d + y[i, j] = c[i, j] / d } } } else { id := 1/d for i in 0..<4 { for j in 0..<4 { - y[i, j] = a[i, j] * id + y[i, j] = c[i, j] * id } } } @@ -1714,19 +1762,19 @@ inverse_matrix2x2 :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) { @(require_results) inverse_matrix3x3 :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y: M) #no_bounds_check { - a := adjugate(x) + c := cofactor(x) d := determinant(x) when intrinsics.type_is_integer(T) { for i in 0..<3 { for j in 0..<3 { - y[i, j] = a[j, i] / d + y[i, j] = c[j, i] / d } } } else { id := 1/d for i in 0..<3 { for j in 0..<3 { - y[i, j] = a[j, i] * id + y[i, j] = c[j, i] * id } } } @@ -1735,22 +1783,22 @@ inverse_matrix3x3 :: proc "contextless" (x: $M/matrix[3, 3]$T) -> (y: M) #no_bou @(require_results) inverse_matrix4x4 :: proc "contextless" (x: $M/matrix[4, 4]$T) -> (y: M) #no_bounds_check { - a := adjugate(x) + c := cofactor(x) d: T for i in 0..<4 { - d += x[0, i] * a[0, i] + d += x[0, i] * c[0, i] } when intrinsics.type_is_integer(T) { for i in 0..<4 { for j in 0..<4 { - y[i, j] = a[j, i] / d + y[i, j] = c[j, i] / d } } } else { id := 1/d for i in 0..<4 { for j in 0..<4 { - y[i, j] = a[j, i] * id + y[i, j] = c[j, i] * id } } } diff --git a/core/math/rand/rand.odin b/core/math/rand/rand.odin index 474277e84..72d9400d7 100644 --- a/core/math/rand/rand.odin +++ b/core/math/rand/rand.odin @@ -34,30 +34,6 @@ Example: import "core:fmt" set_global_seed_example :: proc() { - rand.set_global_seed(1) - fmt.println(rand.uint64()) - } - -Possible Output: - - 10 -*/ -@(deprecated="Prefer `rand.reset`") -set_global_seed :: proc(seed: u64) { - runtime.random_generator_reset_u64(context.random_generator, seed) -} - -/* -Reset the seed used by the context.random_generator. - -Inputs: -- seed: The seed value - -Example: - import "core:math/rand" - import "core:fmt" - - set_global_seed_example :: proc() { rand.reset(1) fmt.println(rand.uint64()) } diff --git a/core/mem/allocators.odin b/core/mem/allocators.odin index 13d509f1e..028be58e3 100644 --- a/core/mem/allocators.odin +++ b/core/mem/allocators.odin @@ -140,14 +140,6 @@ arena_init :: proc(a: ^Arena, data: []byte) { a.temp_count = 0 } -@(deprecated="prefer 'mem.arena_init'") -init_arena :: proc(a: ^Arena, data: []byte) { - a.data = data - a.offset = 0 - a.peak_used = 0 - a.temp_count = 0 -} - /* Allocate memory from an arena. @@ -786,14 +778,6 @@ stack_init :: proc(s: ^Stack, data: []byte) { s.peak_used = 0 } -@(deprecated="prefer 'mem.stack_init'") -init_stack :: proc(s: ^Stack, data: []byte) { - s.data = data - s.prev_offset = 0 - s.curr_offset = 0 - s.peak_used = 0 -} - /* Allocate memory from stack. @@ -1162,13 +1146,6 @@ small_stack_init :: proc(s: ^Small_Stack, data: []byte) { s.peak_used = 0 } -@(deprecated="prefer 'small_stack_init'") -init_small_stack :: proc(s: ^Small_Stack, data: []byte) { - s.data = data - s.offset = 0 - s.peak_used = 0 -} - /* Small stack allocator. diff --git a/core/mem/mem.odin b/core/mem/mem.odin index ccbc77798..b2a7158a1 100644 --- a/core/mem/mem.odin +++ b/core/mem/mem.odin @@ -685,11 +685,4 @@ calc_padding_with_header :: proc "contextless" (ptr: uintptr, align: uintptr, he } } return int(padding) -} - -@(require_results, deprecated="prefer 'slice.clone'") -clone_slice :: proc(slice: $T/[]$E, allocator := context.allocator, loc := #caller_location) -> (new_slice: T) { - new_slice, _ = make(T, len(slice), allocator, loc) - runtime.copy(new_slice, slice) - return new_slice -} +}
\ No newline at end of file diff --git a/core/mem/virtual/arena.odin b/core/mem/virtual/arena.odin index 79407d80d..4a0fff241 100644 --- a/core/mem/virtual/arena.odin +++ b/core/mem/virtual/arena.odin @@ -204,8 +204,9 @@ arena_free_all :: proc(arena: ^Arena, loc := #caller_location) { } // Zero the first block's memory if arena.curr_block != nil { - mem.zero(arena.curr_block.base, int(arena.curr_block.used)) + curr_block_used := int(arena.curr_block.used) arena.curr_block.used = 0 + mem.zero(arena.curr_block.base, curr_block_used) } arena.total_used = 0 case .Static, .Buffer: diff --git a/core/os/os2/file.odin b/core/os/os2/file.odin index eedf8570c..1a25472a1 100644 --- a/core/os/os2/file.odin +++ b/core/os/os2/file.odin @@ -115,7 +115,7 @@ open :: proc(name: string, flags := File_Flags{.Read}, perm := 0o777) -> (^File, @(require_results) new_file :: proc(handle: uintptr, name: string) -> ^File { - file, err := _new_file(handle, name) + file, err := _new_file(handle, name, file_allocator()) if err != nil { panic(error_string(err)) } diff --git a/core/os/os2/file_linux.odin b/core/os/os2/file_linux.odin index e9ce13447..f8e4026da 100644 --- a/core/os/os2/file_linux.odin +++ b/core/os/os2/file_linux.odin @@ -39,37 +39,23 @@ _stderr := File{ @init _standard_stream_init :: proc() { - @static stdin_impl := File_Impl { - name = "/proc/self/fd/0", - fd = 0, - } - - @static stdout_impl := File_Impl { - name = "/proc/self/fd/1", - fd = 1, - } - - @static stderr_impl := File_Impl { - name = "/proc/self/fd/2", - fd = 2, + new_std :: proc(impl: ^File_Impl, fd: linux.Fd, name: string) -> ^File { + impl.file.impl = impl + impl.fd = linux.Fd(fd) + impl.allocator = runtime.nil_allocator() + impl.name = name + impl.file.stream = { + data = impl, + procedure = _file_stream_proc, + } + impl.file.fstat = _fstat + return &impl.file } - stdin_impl.allocator = file_allocator() - stdout_impl.allocator = file_allocator() - stderr_impl.allocator = file_allocator() - - _stdin.impl = &stdin_impl - _stdout.impl = &stdout_impl - _stderr.impl = &stderr_impl - - // cannot define these initially because cyclic reference - _stdin.stream.data = &stdin_impl - _stdout.stream.data = &stdout_impl - _stderr.stream.data = &stderr_impl - - stdin = &_stdin - stdout = &_stdout - stderr = &_stderr + @(static) files: [3]File_Impl + stdin = new_std(&files[0], 0, "/proc/self/fd/0") + stdout = new_std(&files[1], 1, "/proc/self/fd/1") + stderr = new_std(&files[2], 2, "/proc/self/fd/2") } _open :: proc(name: string, flags: File_Flags, perm: int) -> (f: ^File, err: Error) { @@ -80,6 +66,9 @@ _open :: proc(name: string, flags: File_Flags, perm: int) -> (f: ^File, err: Err // terminal would be incredibly rare. This has no effect on files while // allowing us to open serial devices. sys_flags: linux.Open_Flags = {.NOCTTY, .CLOEXEC} + when size_of(rawptr) == 4 { + sys_flags += {.LARGEFILE} + } switch flags & (O_RDONLY|O_WRONLY|O_RDWR) { case O_RDONLY: case O_WRONLY: sys_flags += {.WRONLY} @@ -97,18 +86,18 @@ _open :: proc(name: string, flags: File_Flags, perm: int) -> (f: ^File, err: Err return nil, _get_platform_error(errno) } - return _new_file(uintptr(fd), name) + return _new_file(uintptr(fd), name, file_allocator()) } -_new_file :: proc(fd: uintptr, _: string = "") -> (f: ^File, err: Error) { - impl := new(File_Impl, file_allocator()) or_return +_new_file :: proc(fd: uintptr, _: string, allocator: runtime.Allocator) -> (f: ^File, err: Error) { + impl := new(File_Impl, allocator) or_return defer if err != nil { - free(impl, file_allocator()) + free(impl, allocator) } impl.file.impl = impl impl.fd = linux.Fd(fd) - impl.allocator = file_allocator() - impl.name = _get_full_path(impl.fd, file_allocator()) or_return + impl.allocator = allocator + impl.name = _get_full_path(impl.fd, impl.allocator) or_return impl.file.stream = { data = impl, procedure = _file_stream_proc, @@ -272,28 +261,12 @@ _truncate :: proc(f: ^File, size: i64) -> Error { } _remove :: proc(name: string) -> Error { - is_dir_fd :: proc(fd: linux.Fd) -> bool { - s: linux.Stat - if linux.fstat(fd, &s) != .NONE { - return false - } - return linux.S_ISDIR(s.mode) - } - TEMP_ALLOCATOR_GUARD() name_cstr := temp_cstring(name) or_return - fd, errno := linux.open(name_cstr, {.NOFOLLOW}) - #partial switch (errno) { - case .ELOOP: - /* symlink */ - case .NONE: - defer linux.close(fd) - if is_dir_fd(fd) { - return _get_platform_error(linux.rmdir(name_cstr)) - } - case: - return _get_platform_error(errno) + if fd, errno := linux.open(name_cstr, _OPENDIR_FLAGS + {.NOFOLLOW}); errno == .NONE { + linux.close(fd) + return _get_platform_error(linux.rmdir(name_cstr)) } return _get_platform_error(linux.unlink(name_cstr)) diff --git a/core/os/os2/file_posix.odin b/core/os/os2/file_posix.odin index b7dc43287..184c89368 100644 --- a/core/os/os2/file_posix.odin +++ b/core/os/os2/file_posix.odin @@ -21,23 +21,29 @@ File_Impl :: struct { name: string, cname: cstring, fd: posix.FD, + allocator: runtime.Allocator, } @(init) init_std_files :: proc() { - // NOTE: is this (paths) also the case on non darwin? - - stdin = __new_file(posix.STDIN_FILENO) - (^File_Impl)(stdin.impl).name = "/dev/stdin" - (^File_Impl)(stdin.impl).cname = "/dev/stdin" - - stdout = __new_file(posix.STDIN_FILENO) - (^File_Impl)(stdout.impl).name = "/dev/stdout" - (^File_Impl)(stdout.impl).cname = "/dev/stdout" + new_std :: proc(impl: ^File_Impl, fd: posix.FD, name: cstring) -> ^File { + impl.file.impl = impl + impl.fd = fd + impl.allocator = runtime.nil_allocator() + impl.cname = name + impl.name = string(name) + impl.file.stream = { + data = impl, + procedure = _file_stream_proc, + } + impl.file.fstat = _fstat + return &impl.file + } - stderr = __new_file(posix.STDIN_FILENO) - (^File_Impl)(stderr.impl).name = "/dev/stderr" - (^File_Impl)(stderr.impl).cname = "/dev/stderr" + @(static) files: [3]File_Impl + stdin = new_std(&files[0], posix.STDIN_FILENO, "/dev/stdin") + stdout = new_std(&files[1], posix.STDOUT_FILENO, "/dev/stdout") + stderr = new_std(&files[2], posix.STDERR_FILENO, "/dev/stderr") } _open :: proc(name: string, flags: File_Flags, perm: int) -> (f: ^File, err: Error) { @@ -72,10 +78,10 @@ _open :: proc(name: string, flags: File_Flags, perm: int) -> (f: ^File, err: Err return } - return _new_file(uintptr(fd), name) + return _new_file(uintptr(fd), name, file_allocator()) } -_new_file :: proc(handle: uintptr, name: string) -> (f: ^File, err: Error) { +_new_file :: proc(handle: uintptr, name: string, allocator: runtime.Allocator) -> (f: ^File, err: Error) { if name == "" { err = .Invalid_Path return @@ -84,10 +90,10 @@ _new_file :: proc(handle: uintptr, name: string) -> (f: ^File, err: Error) { return } - crname := _posix_absolute_path(posix.FD(handle), name, file_allocator()) or_return + crname := _posix_absolute_path(posix.FD(handle), name, allocator) or_return rname := string(crname) - f = __new_file(posix.FD(handle)) + f = __new_file(posix.FD(handle), allocator) impl := (^File_Impl)(f.impl) impl.name = rname impl.cname = crname @@ -95,10 +101,11 @@ _new_file :: proc(handle: uintptr, name: string) -> (f: ^File, err: Error) { return f, nil } -__new_file :: proc(handle: posix.FD) -> ^File { - impl := new(File_Impl, file_allocator()) +__new_file :: proc(handle: posix.FD, allocator: runtime.Allocator) -> ^File { + impl := new(File_Impl, allocator) impl.file.impl = impl impl.fd = posix.FD(handle) + impl.allocator = allocator impl.file.stream = { data = impl, procedure = _file_stream_proc, @@ -114,8 +121,10 @@ _close :: proc(f: ^File_Impl) -> (err: Error) { err = _get_platform_error() } - delete(f.cname, file_allocator()) - free(f, file_allocator()) + allocator := f.allocator + + delete(f.cname, allocator) + free(f, allocator) return } diff --git a/core/os/os2/file_windows.odin b/core/os/os2/file_windows.odin index b91a1bc3b..f594cc72f 100644 --- a/core/os/os2/file_windows.odin +++ b/core/os/os2/file_windows.odin @@ -44,17 +44,38 @@ File_Impl :: struct { @(init) init_std_files :: proc() { - stdin = new_file(uintptr(win32.GetStdHandle(win32.STD_INPUT_HANDLE)), "<stdin>") - stdout = new_file(uintptr(win32.GetStdHandle(win32.STD_OUTPUT_HANDLE)), "<stdout>") - stderr = new_file(uintptr(win32.GetStdHandle(win32.STD_ERROR_HANDLE)), "<stderr>") -} -@(fini) -fini_std_files :: proc() { - _destroy((^File_Impl)(stdin.impl)) - _destroy((^File_Impl)(stdout.impl)) - _destroy((^File_Impl)(stderr.impl)) -} + new_std :: proc(impl: ^File_Impl, code: u32, name: string) -> ^File { + impl.file.impl = impl + + impl.allocator = runtime.nil_allocator() + impl.fd = win32.GetStdHandle(code) + impl.name = name + impl.wname = nil + + handle := _handle(&impl.file) + kind := File_Impl_Kind.File + if m: u32; win32.GetConsoleMode(handle, &m) { + kind = .Console + } + if win32.GetFileType(handle) == win32.FILE_TYPE_PIPE { + kind = .Pipe + } + impl.kind = kind + impl.file.stream = { + data = impl, + procedure = _file_stream_proc, + } + impl.file.fstat = _fstat + + return &impl.file + } + + @(static) files: [3]File_Impl + stdin = new_std(&files[0], win32.STD_INPUT_HANDLE, "<stdin>") + stdout = new_std(&files[1], win32.STD_OUTPUT_HANDLE, "<stdout>") + stderr = new_std(&files[2], win32.STD_ERROR_HANDLE, "<stderr>") +} _handle :: proc(f: ^File) -> win32.HANDLE { return win32.HANDLE(_fd(f)) @@ -132,21 +153,21 @@ _open_internal :: proc(name: string, flags: File_Flags, perm: int) -> (handle: u _open :: proc(name: string, flags: File_Flags, perm: int) -> (f: ^File, err: Error) { flags := flags if flags != nil else {.Read} handle := _open_internal(name, flags, perm) or_return - return _new_file(handle, name) + return _new_file(handle, name, file_allocator()) } -_new_file :: proc(handle: uintptr, name: string) -> (f: ^File, err: Error) { +_new_file :: proc(handle: uintptr, name: string, allocator: runtime.Allocator) -> (f: ^File, err: Error) { if handle == INVALID_HANDLE { return } - impl := new(File_Impl, file_allocator()) or_return + impl := new(File_Impl, allocator) or_return defer if err != nil { - free(impl, file_allocator()) + free(impl, allocator) } impl.file.impl = impl - impl.allocator = file_allocator() + impl.allocator = allocator impl.fd = rawptr(handle) impl.name = clone_string(name, impl.allocator) or_return impl.wname = win32_utf8_to_wstring(name, impl.allocator) or_return @@ -180,7 +201,7 @@ _open_buffered :: proc(name: string, buffer_size: uint, flags := File_Flags{.Rea } _new_file_buffered :: proc(handle: uintptr, name: string, buffer_size: uint) -> (f: ^File, err: Error) { - f, err = _new_file(handle, name) + f, err = _new_file(handle, name, file_allocator()) if f != nil && err == nil { impl := (^File_Impl)(f.impl) impl.r_buf = make([]byte, buffer_size, file_allocator()) diff --git a/core/os/os2/heap_linux.odin b/core/os/os2/heap_linux.odin index ede5eb2ac..8819dfac7 100644 --- a/core/os/os2/heap_linux.odin +++ b/core/os/os2/heap_linux.odin @@ -415,7 +415,7 @@ _region_resize :: proc(alloc: ^Allocation_Header, new_size: int, alloc_is_free_l back_idx := -1 idx: u16 infinite: for { - for i := 0; i < len(region_iter.hdr.free_list); i += 1 { + for i := 0; i < int(region_iter.hdr.free_list_len); i += 1 { idx = region_iter.hdr.free_list[i] if _get_block_count(region_iter.memory[idx]) >= new_block_count { break infinite diff --git a/core/os/os2/path_linux.odin b/core/os/os2/path_linux.odin index 7be4121ae..bfdb645ef 100644 --- a/core/os/os2/path_linux.odin +++ b/core/os/os2/path_linux.odin @@ -77,8 +77,6 @@ _mkdir_all :: proc(path: string, perm: int) -> Error { } _remove_all :: proc(path: string) -> Error { - DT_DIR :: 4 - remove_all_dir :: proc(dfd: linux.Fd) -> Error { n := 64 buf := make([]u8, n) diff --git a/core/os/os2/pipe_linux.odin b/core/os/os2/pipe_linux.odin index 852674c69..bb4456e1c 100644 --- a/core/os/os2/pipe_linux.odin +++ b/core/os/os2/pipe_linux.odin @@ -10,8 +10,8 @@ _pipe :: proc() -> (r, w: ^File, err: Error) { return nil, nil,_get_platform_error(errno) } - r = _new_file(uintptr(fds[0])) or_return - w = _new_file(uintptr(fds[1])) or_return + r = _new_file(uintptr(fds[0]), "", file_allocator()) or_return + w = _new_file(uintptr(fds[1]), "", file_allocator()) or_return return } diff --git a/core/os/os2/pipe_posix.odin b/core/os/os2/pipe_posix.odin index df9425339..edead2ab3 100644 --- a/core/os/os2/pipe_posix.odin +++ b/core/os/os2/pipe_posix.odin @@ -21,7 +21,7 @@ _pipe :: proc() -> (r, w: ^File, err: Error) { return } - r = __new_file(fds[0]) + r = __new_file(fds[0], file_allocator()) ri := (^File_Impl)(r.impl) rname := strings.builder_make(file_allocator()) @@ -31,7 +31,7 @@ _pipe :: proc() -> (r, w: ^File, err: Error) { ri.name = strings.to_string(rname) ri.cname = strings.to_cstring(&rname) - w = __new_file(fds[1]) + w = __new_file(fds[1], file_allocator()) wi := (^File_Impl)(w.impl) wname := strings.builder_make(file_allocator()) diff --git a/core/os/os2/process.odin b/core/os/os2/process.odin index 5b5a6e844..c90e3add2 100644 --- a/core/os/os2/process.odin +++ b/core/os/os2/process.odin @@ -290,12 +290,21 @@ process_open :: proc(pid: int, flags := Process_Open_Flags {}) -> (Process, Erro return _process_open(pid, flags) } + +/* +OS-specific process attributes. +*/ +Process_Attributes :: struct { + sys_attr: _Sys_Process_Attributes, +} + /* The description of how a process should be created. */ Process_Desc :: struct { // OS-specific attributes. - sys_attr: _Sys_Process_Attributes, + sys_attr: Process_Attributes, + // The working directory of the process. If the string has length 0, the // working directory is assumed to be the current working directory of the // current process. diff --git a/core/os/os2/process_linux.odin b/core/os/os2/process_linux.odin index 7eb4dfa44..936fbfc40 100644 --- a/core/os/os2/process_linux.odin +++ b/core/os/os2/process_linux.odin @@ -384,14 +384,6 @@ _Sys_Process_Attributes :: struct {} @(private="package") _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) { - has_executable_permissions :: proc(fd: linux.Fd) -> bool { - backing: [48]u8 - b := strings.builder_from_bytes(backing[:]) - strings.write_string(&b, "/proc/self/fd/") - strings.write_int(&b, int(fd)) - return linux.access(strings.to_cstring(&b), linux.X_OK) == .NONE - } - TEMP_ALLOCATOR_GUARD() if len(desc.command) == 0 { @@ -411,7 +403,7 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) { } // search PATH if just a plain name is provided - exe_fd: linux.Fd + exe_path: cstring executable_name := desc.command[0] if strings.index_byte(executable_name, '/') < 0 { path_env := get_env("PATH", temp_allocator()) @@ -426,16 +418,11 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) { strings.write_byte(&exe_builder, '/') strings.write_string(&exe_builder, executable_name) - exe_path := strings.to_cstring(&exe_builder) - if exe_fd, errno = linux.openat(dir_fd, exe_path, {.PATH, .CLOEXEC}); errno != .NONE { - continue - } - if !has_executable_permissions(exe_fd) { - linux.close(exe_fd) - continue + exe_path = strings.to_cstring(&exe_builder) + if linux.access(exe_path, linux.X_OK) == .NONE { + found = true + break } - found = true - break } if !found { // check in cwd to match windows behavior @@ -443,29 +430,18 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) { strings.write_string(&exe_builder, "./") strings.write_string(&exe_builder, executable_name) - exe_path := strings.to_cstring(&exe_builder) - if exe_fd, errno = linux.openat(dir_fd, exe_path, {.PATH, .CLOEXEC}); errno != .NONE { + exe_path = strings.to_cstring(&exe_builder) + if linux.access(exe_path, linux.X_OK) != .NONE { return process, .Not_Exist } - if !has_executable_permissions(exe_fd) { - linux.close(exe_fd) - return process, .Permission_Denied - } } } else { - exe_path := temp_cstring(executable_name) or_return - if exe_fd, errno = linux.openat(dir_fd, exe_path, {.PATH, .CLOEXEC}); errno != .NONE { - return process, _get_platform_error(errno) - } - if !has_executable_permissions(exe_fd) { - linux.close(exe_fd) - return process, .Permission_Denied + exe_path = temp_cstring(executable_name) or_return + if linux.access(exe_path, linux.X_OK) != .NONE { + return process, .Not_Exist } } - // At this point, we have an executable. - defer linux.close(exe_fd) - // args and environment need to be a list of cstrings // that are terminated by a nil pointer. cargs := make([]cstring, len(desc.command) + 1, temp_allocator()) or_return @@ -492,7 +468,6 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) { } defer linux.close(child_pipe_fds[READ]) - // TODO: This is the traditional textbook implementation with fork. // A more efficient implementation with vfork: // @@ -573,7 +548,7 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) { write_errno_to_parent_and_abort(child_pipe_fds[WRITE], errno) } - errno = linux.execveat(exe_fd, "", &cargs[0], env, {.AT_EMPTY_PATH}) + errno = linux.execveat(dir_fd, exe_path, &cargs[0], env) assert(errno != nil) write_errno_to_parent_and_abort(child_pipe_fds[WRITE], errno) } diff --git a/core/prof/spall/doc.odin b/core/prof/spall/doc.odin index c81bad05f..b007ad4cb 100644 --- a/core/prof/spall/doc.odin +++ b/core/prof/spall/doc.odin @@ -18,6 +18,8 @@ Example: defer spall.context_destroy(&spall_ctx) buffer_backing := make([]u8, spall.BUFFER_DEFAULT_SIZE) + defer delete(buffer_backing) + spall_buffer = spall.buffer_create(buffer_backing, u32(sync.current_thread_id())) defer spall.buffer_destroy(&spall_ctx, &spall_buffer) diff --git a/core/sys/linux/bits.odin b/core/sys/linux/bits.odin index 9ce2e206e..c304397de 100644 --- a/core/sys/linux/bits.odin +++ b/core/sys/linux/bits.odin @@ -152,43 +152,65 @@ Errno :: enum i32 { RDONLY flag is not present, because it has the value of 0, i.e. it is the default, unless WRONLY or RDWR is specified. */ -Open_Flags_Bits :: enum { - WRONLY = 0, - RDWR = 1, - CREAT = 6, - EXCL = 7, - NOCTTY = 8, - TRUNC = 9, - APPEND = 10, - NONBLOCK = 11, - DSYNC = 12, - ASYNC = 13, - DIRECT = 14, - LARGEFILE = 15, - DIRECTORY = 16, - NOFOLLOW = 17, - NOATIME = 18, - CLOEXEC = 19, - PATH = 21, -} -// https://github.com/torvalds/linux/blob/7367539ad4b0f8f9b396baf02110962333719a48/include/uapi/asm-generic/fcntl.h#L19 -#assert(1 << uint(Open_Flags_Bits.WRONLY) == 0o0000000_1) -#assert(1 << uint(Open_Flags_Bits.RDWR) == 0o0000000_2) -#assert(1 << uint(Open_Flags_Bits.CREAT) == 0o00000_100) -#assert(1 << uint(Open_Flags_Bits.EXCL) == 0o00000_200) -#assert(1 << uint(Open_Flags_Bits.NOCTTY) == 0o00000_400) -#assert(1 << uint(Open_Flags_Bits.TRUNC) == 0o0000_1000) -#assert(1 << uint(Open_Flags_Bits.APPEND) == 0o0000_2000) -#assert(1 << uint(Open_Flags_Bits.NONBLOCK) == 0o0000_4000) -#assert(1 << uint(Open_Flags_Bits.DSYNC) == 0o000_10000) -#assert(1 << uint(Open_Flags_Bits.ASYNC) == 0o000_20000) -#assert(1 << uint(Open_Flags_Bits.DIRECT) == 0o000_40000) -#assert(1 << uint(Open_Flags_Bits.LARGEFILE) == 0o00_100000) -#assert(1 << uint(Open_Flags_Bits.DIRECTORY) == 0o00_200000) -#assert(1 << uint(Open_Flags_Bits.NOFOLLOW) == 0o00_400000) -#assert(1 << uint(Open_Flags_Bits.NOATIME) == 0o0_1000000) -#assert(1 << uint(Open_Flags_Bits.CLOEXEC) == 0o0_2000000) -#assert(1 << uint(Open_Flags_Bits.PATH) == 0o_10000000) +when ODIN_ARCH != .arm64 && ODIN_ARCH != .arm32 { + Open_Flags_Bits :: enum { + WRONLY = 0, + RDWR = 1, + CREAT = 6, + EXCL = 7, + NOCTTY = 8, + TRUNC = 9, + APPEND = 10, + NONBLOCK = 11, + DSYNC = 12, + ASYNC = 13, + DIRECT = 14, + LARGEFILE = 15, + DIRECTORY = 16, + NOFOLLOW = 17, + NOATIME = 18, + CLOEXEC = 19, + PATH = 21, + } + // https://github.com/torvalds/linux/blob/7367539ad4b0f8f9b396baf02110962333719a48/include/uapi/asm-generic/fcntl.h#L19 + #assert(1 << uint(Open_Flags_Bits.WRONLY) == 0o0000000_1) + #assert(1 << uint(Open_Flags_Bits.RDWR) == 0o0000000_2) + #assert(1 << uint(Open_Flags_Bits.CREAT) == 0o00000_100) + #assert(1 << uint(Open_Flags_Bits.EXCL) == 0o00000_200) + #assert(1 << uint(Open_Flags_Bits.NOCTTY) == 0o00000_400) + #assert(1 << uint(Open_Flags_Bits.TRUNC) == 0o0000_1000) + #assert(1 << uint(Open_Flags_Bits.APPEND) == 0o0000_2000) + #assert(1 << uint(Open_Flags_Bits.NONBLOCK) == 0o0000_4000) + #assert(1 << uint(Open_Flags_Bits.DSYNC) == 0o000_10000) + #assert(1 << uint(Open_Flags_Bits.ASYNC) == 0o000_20000) + #assert(1 << uint(Open_Flags_Bits.DIRECT) == 0o000_40000) + #assert(1 << uint(Open_Flags_Bits.LARGEFILE) == 0o00_100000) + #assert(1 << uint(Open_Flags_Bits.DIRECTORY) == 0o00_200000) + #assert(1 << uint(Open_Flags_Bits.NOFOLLOW) == 0o00_400000) + #assert(1 << uint(Open_Flags_Bits.NOATIME) == 0o0_1000000) + #assert(1 << uint(Open_Flags_Bits.CLOEXEC) == 0o0_2000000) + #assert(1 << uint(Open_Flags_Bits.PATH) == 0o_10000000) +} else { + Open_Flags_Bits :: enum { + WRONLY = 0, + RDWR = 1, + CREAT = 6, + EXCL = 7, + NOCTTY = 8, + TRUNC = 9, + APPEND = 10, + NONBLOCK = 11, + DSYNC = 12, + ASYNC = 13, + DIRECTORY = 14, + NOFOLLOW = 15, + DIRECT = 16, + LARGEFILE = 17, + NOATIME = 18, + CLOEXEC = 19, + PATH = 21, + } +} /* Bits for FD_Flags bitset diff --git a/core/sys/linux/helpers.odin b/core/sys/linux/helpers.odin index aefc1179e..9a7550d57 100644 --- a/core/sys/linux/helpers.odin +++ b/core/sys/linux/helpers.odin @@ -138,8 +138,8 @@ errno_unwrap :: proc {errno_unwrap2, errno_unwrap3} when size_of(int) == 4 { // xxx64 system calls take some parameters as pairs of ulongs rather than a single pointer @(private) - compat64_arg_pair :: #force_inline proc "contextless" (a: i64) -> (hi: uint, lo: uint) { - no_sign := uint(a) + compat64_arg_pair :: #force_inline proc "contextless" (a: i64) -> (lo: uint, hi: uint) { + no_sign := u64(a) hi = uint(no_sign >> 32) lo = uint(no_sign & 0xffff_ffff) return diff --git a/core/sys/linux/sys.odin b/core/sys/linux/sys.odin index 690902f07..fee385fe8 100644 --- a/core/sys/linux/sys.odin +++ b/core/sys/linux/sys.odin @@ -151,7 +151,8 @@ lseek :: proc "contextless" (fd: Fd, off: i64, whence: Seek_Whence) -> (i64, Err return errno_unwrap(ret, i64) } else { result: i64 = --- - ret := syscall(SYS__llseek, fd, compat64_arg_pair(off), &result, whence) + lo, hi := compat64_arg_pair(off) + ret := syscall(SYS__llseek, fd, hi, lo, &result, whence) return result, Errno(-ret) } } @@ -251,7 +252,11 @@ ioctl :: proc "contextless" (fd: Fd, request: u32, arg: uintptr) -> (uintptr) { Available since Linux 2.2. */ pread :: proc "contextless" (fd: Fd, buf: []u8, offset: i64) -> (int, Errno) { - ret := syscall(SYS_pread64, fd, raw_data(buf), len(buf), compat64_arg_pair(offset)) + when ODIN_ARCH == .arm32 { + ret := syscall(SYS_pread64, fd, raw_data(buf), len(buf), 0, compat64_arg_pair(offset)) + } else { + ret := syscall(SYS_pread64, fd, raw_data(buf), len(buf), compat64_arg_pair(offset)) + } return errno_unwrap(ret, int) } @@ -261,7 +266,11 @@ pread :: proc "contextless" (fd: Fd, buf: []u8, offset: i64) -> (int, Errno) { Available since Linux 2.2. */ pwrite :: proc "contextless" (fd: Fd, buf: []u8, offset: i64) -> (int, Errno) { - ret := syscall(SYS_pwrite64, fd, raw_data(buf), len(buf), compat64_arg_pair(offset)) + when ODIN_ARCH == .arm32 { + ret := syscall(SYS_pwrite64, fd, raw_data(buf), len(buf), 0, compat64_arg_pair(offset)) + } else { + ret := syscall(SYS_pwrite64, fd, raw_data(buf), len(buf), compat64_arg_pair(offset)) + } return errno_unwrap(ret, int) } @@ -1127,7 +1136,10 @@ fdatasync :: proc "contextless" (fd: Fd) -> (Errno) { On 32-bit architectures available since Linux 2.4. */ truncate :: proc "contextless" (name: cstring, length: i64) -> (Errno) { - when size_of(int) == 4 { + when ODIN_ARCH == .arm32 { + ret := syscall(SYS_truncate64, cast(rawptr) name, 0, compat64_arg_pair(length)) + return Errno(-ret) + } else when size_of(int) == 4 { ret := syscall(SYS_truncate64, cast(rawptr) name, compat64_arg_pair(length)) return Errno(-ret) } else { @@ -1141,7 +1153,10 @@ truncate :: proc "contextless" (name: cstring, length: i64) -> (Errno) { On 32-bit architectures available since 2.4. */ ftruncate :: proc "contextless" (fd: Fd, length: i64) -> (Errno) { - when size_of(int) == 4 { + when ODIN_ARCH == .arm32 { + ret := syscall(SYS_ftruncate64, fd, 0, compat64_arg_pair(length)) + return Errno(-ret) + } else when size_of(int) == 4 { ret := syscall(SYS_ftruncate64, fd, compat64_arg_pair(length)) return Errno(-ret) } else { @@ -1952,10 +1967,10 @@ sigaltstack :: proc "contextless" (stack: ^Sig_Stack, old_stack: ^Sig_Stack) -> */ mknod :: proc "contextless" (name: cstring, mode: Mode, dev: Dev) -> (Errno) { when ODIN_ARCH == .arm64 || ODIN_ARCH == .riscv64 { - ret := syscall(SYS_mknodat, AT_FDCWD, cast(rawptr) name, transmute(u32) mode, dev) + ret := syscall(SYS_mknodat, AT_FDCWD, cast(rawptr) name, transmute(u32) mode, cast(uint) dev) return Errno(-ret) } else { - ret := syscall(SYS_mknod, cast(rawptr) name, transmute(u32) mode, dev) + ret := syscall(SYS_mknod, cast(rawptr) name, transmute(u32) mode, cast(uint) dev) return Errno(-ret) } } @@ -2586,7 +2601,7 @@ mkdirat :: proc "contextless" (dirfd: Fd, name: cstring, mode: Mode) -> (Errno) Available since Linux 2.6.16. */ mknodat :: proc "contextless" (dirfd: Fd, name: cstring, mode: Mode, dev: Dev) -> (Errno) { - ret := syscall(SYS_mknodat, dirfd, cast(rawptr) name, transmute(u32) mode, dev) + ret := syscall(SYS_mknodat, dirfd, cast(rawptr) name, transmute(u32) mode, cast(uint) dev) return Errno(-ret) } @@ -2684,13 +2699,8 @@ faccessat :: proc "contextless" (dirfd: Fd, name: cstring, mode: Mode = F_OK) -> Available since Linux 2.6.16. */ ppoll :: proc "contextless" (fds: []Poll_Fd, timeout: ^Time_Spec, sigmask: ^Sig_Set) -> (i32, Errno) { - when size_of(int) == 8 { - ret := syscall(SYS_ppoll, raw_data(fds), len(fds), timeout, sigmask, size_of(Sig_Set)) - return errno_unwrap(ret, i32) - } else { - ret := syscall(SYS_ppoll_time64, raw_data(fds), len(fds), timeout, sigmask, size_of(Sig_Set)) - return errno_unwrap(ret, i32) - } + ret := syscall(SYS_ppoll, raw_data(fds), len(fds), timeout, sigmask, size_of(Sig_Set)) + return errno_unwrap(ret, i32) } // TODO(flysand): unshare diff --git a/core/sys/linux/types.odin b/core/sys/linux/types.odin index 42d5cc988..dcc72f72b 100644 --- a/core/sys/linux/types.odin +++ b/core/sys/linux/types.odin @@ -3,7 +3,7 @@ package linux /* Type for storage device handle. */ -Dev :: distinct int +Dev :: distinct u64 /* Type for 32-bit User IDs. @@ -153,6 +153,7 @@ when ODIN_ARCH == .amd64 { uid: Uid, gid: Gid, rdev: Dev, + _: [4]u8, size: i64, blksize: uint, blocks: u64, @@ -516,79 +517,79 @@ Pid_FD_Flags :: bit_set[Pid_FD_Flags_Bits; i32] Sig_Set :: [_SIGSET_NWORDS]uint @private SI_MAX_SIZE :: 128 -@private SI_ARCH_PREAMBLE :: 4 * size_of(i32) +@private SI_ARCH_PREAMBLE :: 4 * size_of(i32) when size_of(rawptr) == 8 else 3 * size_of(i32) @private SI_PAD_SIZE :: SI_MAX_SIZE - SI_ARCH_PREAMBLE Sig_Handler_Fn :: #type proc "c" (sig: Signal) Sig_Restore_Fn :: #type proc "c" () -> ! -Sig_Info :: struct #packed { - signo: Signal, - errno: Errno, - code: i32, - _pad0: i32, - using _union: struct #raw_union { - _pad1: [SI_PAD_SIZE]u8, - using _kill: struct { - pid: Pid, /* sender's pid */ - uid: Uid, /* sender's uid */ - }, - using _timer: struct { - timerid: i32, /* timer id */ - overrun: i32, /* overrun count */ - value: Sig_Val, /* timer value */ - }, - /* POSIX.1b signals */ - using _rt: struct { - _pid0: Pid, /* sender's pid */ - _uid0: Uid, /* sender's uid */ - }, - /* SIGCHLD */ - using _sigchld: struct { - _pid1: Pid, /* which child */ - _uid1: Uid, /* sender's uid */ - status: i32, /* exit code */ - utime: uint, - stime: uint, //clock_t - }, - /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ - using _sigfault: struct { - addr: rawptr, /* faulting insn/memory ref. */ - using _: struct #raw_union { - trapno: i32, /* Trap number that caused signal */ - addr_lsb: i16, /* LSB of the reported address */ - using _addr_bnd: struct { - _pad2: u64, - lower: rawptr, /* lower bound during fault */ - upper: rawptr, /* upper bound during fault */ - }, - using _addr_pkey: struct { - _pad3: u64, - pkey: u32, /* protection key on PTE that faulted */ - }, - using _perf: struct { - perf_data: u64, - perf_type: u32, - perf_flags: u32, +when size_of(rawptr) == 8 { + Sig_Info :: struct #packed { + signo: Signal, + errno: Errno, + code: i32, + _pad0: i32, + using _union: struct #raw_union { + _pad1: [SI_PAD_SIZE]u8, + using _kill: struct { + pid: Pid, /* sender's pid */ + uid: Uid, /* sender's uid */ + }, + using _timer: struct { + timerid: i32, /* timer id */ + overrun: i32, /* overrun count */ + value: Sig_Val, /* timer value */ + }, + /* POSIX.1b signals */ + using _rt: struct { + _pid0: Pid, /* sender's pid */ + _uid0: Uid, /* sender's uid */ + }, + /* SIGCHLD */ + using _sigchld: struct { + _pid1: Pid, /* which child */ + _uid1: Uid, /* sender's uid */ + status: i32, /* exit code */ + utime: uint, + stime: uint, //clock_t + }, + /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ + using _sigfault: struct { + addr: rawptr, /* faulting insn/memory ref. */ + using _: struct #raw_union { + trapno: i32, /* Trap number that caused signal */ + addr_lsb: i16, /* LSB of the reported address */ + using _addr_bnd: struct { + _pad2: u64, + lower: rawptr, /* lower bound during fault */ + upper: rawptr, /* upper bound during fault */ + }, + using _addr_pkey: struct { + _pad3: u64, + pkey: u32, /* protection key on PTE that faulted */ + }, + using _perf: struct { + perf_data: u64, + perf_type: u32, + perf_flags: u32, + }, }, }, + /* SIGPOLL */ + using _sigpoll: struct { + band: int, /* POLL_IN, POLL_OUT, POLL_MSG */ + fd: Fd, + }, + /* SIGSYS */ + using _sigsys: struct { + call_addr: rawptr, /* calling user insn */ + syscall: i32, /* triggering system call number */ + arch: u32, /* AUDIT_ARCH_* of syscall */ + }, }, - /* SIGPOLL */ - using _sigpoll: struct { - band: int, /* POLL_IN, POLL_OUT, POLL_MSG */ - fd: Fd, - }, - /* SIGSYS */ - using _sigsys: struct { - call_addr: rawptr, /* calling user insn */ - syscall: i32, /* triggering system call number */ - arch: u32, /* AUDIT_ARCH_* of syscall */ - }, - }, -} + } -#assert(size_of(Sig_Info) == 128) -when ODIN_ARCH == .amd64 || ODIN_ARCH == .arm64 { + #assert(size_of(Sig_Info) == 128) #assert(offset_of(Sig_Info, signo) == 0x00) #assert(offset_of(Sig_Info, errno) == 0x04) #assert(offset_of(Sig_Info, code) == 0x08) @@ -615,7 +616,96 @@ when ODIN_ARCH == .amd64 || ODIN_ARCH == .arm64 { #assert(offset_of(Sig_Info, syscall) == 0x18) #assert(offset_of(Sig_Info, arch) == 0x1C) } else { - // TODO + Sig_Info :: struct { + signo: Signal, + errno: Errno, + code: i32, + using _union: struct #raw_union { + _pad1: [SI_PAD_SIZE]u8, + using _kill: struct { + pid: Pid, /* sender's pid */ + uid: Uid, /* sender's uid */ + }, + using _timer: struct { + timerid: i32, /* timer id */ + overrun: i32, /* overrun count */ + value: Sig_Val, /* timer value */ + }, + /* POSIX.1b signals */ + using _rt: struct { + _pid0: Pid, /* sender's pid */ + _uid0: Uid, /* sender's uid */ + }, + /* SIGCHLD */ + using _sigchld: struct { + _pid1: Pid, /* which child */ + _uid1: Uid, /* sender's uid */ + status: i32, /* exit code */ + utime: uint, + stime: uint, //clock_t + }, + /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ + using _sigfault: struct { + addr: rawptr, /* faulting insn/memory ref. */ + using _: struct #raw_union { + trapno: i32, /* Trap number that caused signal */ + addr_lsb: i16, /* LSB of the reported address */ + using _addr_bnd: struct { + _pad2: u32, + lower: rawptr, /* lower bound during fault */ + upper: rawptr, /* upper bound during fault */ + }, + using _addr_pkey: struct { + _pad3: u32, + pkey: u32, /* protection key on PTE that faulted */ + }, + using _perf: struct { + perf_data: u32, + perf_type: u32, + perf_flags: u32, + }, + }, + }, + /* SIGPOLL */ + using _sigpoll: struct { + band: int, /* POLL_IN, POLL_OUT, POLL_MSG */ + fd: Fd, + }, + /* SIGSYS */ + using _sigsys: struct { + call_addr: rawptr, /* calling user insn */ + syscall: i32, /* triggering system call number */ + arch: u32, /* AUDIT_ARCH_* of syscall */ + }, + }, + } + + #assert(size_of(Sig_Info) == 128) + #assert(offset_of(Sig_Info, signo) == 0x00) + #assert(offset_of(Sig_Info, errno) == 0x04) + #assert(offset_of(Sig_Info, code) == 0x08) + #assert(offset_of(Sig_Info, pid) == 0x0c) + #assert(offset_of(Sig_Info, uid) == 0x10) + #assert(offset_of(Sig_Info, timerid) == 0x0c) + #assert(offset_of(Sig_Info, overrun) == 0x10) + #assert(offset_of(Sig_Info, value) == 0x14) + #assert(offset_of(Sig_Info, status) == 0x14) + #assert(offset_of(Sig_Info, utime) == 0x18) + #assert(offset_of(Sig_Info, stime) == 0x1c) + #assert(offset_of(Sig_Info, addr) == 0x0c) + #assert(offset_of(Sig_Info, addr_lsb) == 0x10) + #assert(offset_of(Sig_Info, trapno) == 0x10) + #assert(offset_of(Sig_Info, lower) == 0x14) + #assert(offset_of(Sig_Info, upper) == 0x18) + #assert(offset_of(Sig_Info, pkey) == 0x14) + #assert(offset_of(Sig_Info, perf_data) == 0x10) + #assert(offset_of(Sig_Info, perf_type) == 0x14) + #assert(offset_of(Sig_Info, perf_flags) == 0x18) + #assert(offset_of(Sig_Info, band) == 0x0c) + #assert(offset_of(Sig_Info, fd) == 0x10) + #assert(offset_of(Sig_Info, call_addr) == 0x0c) + #assert(offset_of(Sig_Info, syscall) == 0x10) + #assert(offset_of(Sig_Info, arch) == 0x14) } SIGEV_MAX_SIZE :: 64 @@ -685,12 +775,21 @@ Address_Family :: distinct Protocol_Family Socket_Msg :: bit_set[Socket_Msg_Bits; i32] /* + Struct representing a generic socket address. +*/ +Sock_Addr :: struct #packed { + sa_family: Address_Family, + sa_data: [14]u8, +} + +/* Struct representing IPv4 socket address. */ Sock_Addr_In :: struct #packed { sin_family: Address_Family, sin_port: u16be, sin_addr: [4]u8, + sin_zero: [size_of(Sock_Addr) - size_of(Address_Family) - size_of(u16be) - size_of([4]u8)]u8, } /* @@ -720,6 +819,7 @@ Sock_Addr_Any :: struct #raw_union { family: Address_Family, port: u16be, }, + using generic: Sock_Addr, using ipv4: Sock_Addr_In, using ipv6: Sock_Addr_In6, using uds: Sock_Addr_Un, diff --git a/core/sys/windows/kernel32.odin b/core/sys/windows/kernel32.odin index 8be50bceb..f1d7202da 100644 --- a/core/sys/windows/kernel32.odin +++ b/core/sys/windows/kernel32.odin @@ -20,6 +20,15 @@ COMMON_LVB_GRID_RVERTICAL :: WORD(0x1000) COMMON_LVB_REVERSE_VIDEO :: WORD(0x4000) COMMON_LVB_UNDERSCORE :: WORD(0x8000) COMMON_LVB_SBCSDBCS :: WORD(0x0300) +EV_BREAK :: DWORD(0x0040) +EV_CTS :: DWORD(0x0008) +EV_DSR :: DWORD(0x0010) +EV_ERR :: DWORD(0x0080) +EV_RING :: DWORD(0x0100) +EV_RLSD :: DWORD(0x0020) +EV_RXCHAR :: DWORD(0x0001) +EV_RXFLAG :: DWORD(0x0002) +EV_TXEMPTY :: DWORD(0x0004) @(default_calling_convention="system") foreign kernel32 { @@ -109,7 +118,9 @@ foreign kernel32 { ClearCommError :: proc(hFile: HANDLE, lpErrors: ^Com_Error, lpStat: ^COMSTAT) -> BOOL --- GetCommState :: proc(handle: HANDLE, dcb: ^DCB) -> BOOL --- SetCommState :: proc(handle: HANDLE, dcb: ^DCB) -> BOOL --- - GetCommPorts :: proc(lpPortNumbers: PULONG, uPortNumbersCount: ULONG, puPortNumbersFound: PULONG) -> ULONG --- + SetCommMask :: proc(handle: HANDLE, dwEvtMap: DWORD) -> BOOL --- + GetCommMask :: proc(handle: HANDLE, lpEvtMask: LPDWORD) -> BOOL --- + WaitCommEvent :: proc(handle: HANDLE, lpEvtMask: LPDWORD, lpOverlapped: LPOVERLAPPED) -> BOOL --- GetCommandLineW :: proc() -> LPCWSTR --- GetTempPathW :: proc(nBufferLength: DWORD, lpBuffer: LPCWSTR) -> DWORD --- GetCurrentProcess :: proc() -> HANDLE --- @@ -239,6 +250,10 @@ foreign kernel32 { hThread: HANDLE, lpContext: LPCONTEXT, ) -> BOOL --- + SetThreadContext :: proc( + hThread: HANDLE, + lpContext: LPCONTEXT, + ) -> BOOL --- CreateProcessW :: proc( lpApplicationName: LPCWSTR, lpCommandLine: LPWSTR, @@ -1068,6 +1083,11 @@ foreign one_core { PageProtection: ULONG, PreferredNode: ULONG, ) -> PVOID --- + GetCommPorts :: proc( + lpPortNumbers: PULONG, + uPortNumbersCount: ULONG, + puPortNumbersFound: PULONG, + ) -> ULONG --- } diff --git a/core/sys/windows/types.odin b/core/sys/windows/types.odin index 5dcf09eab..aece4dc43 100644 --- a/core/sys/windows/types.odin +++ b/core/sys/windows/types.odin @@ -143,6 +143,7 @@ LPWSAPROTOCOL_INFO :: ^WSAPROTOCOL_INFO LPSTR :: ^CHAR LPWSTR :: ^WCHAR OLECHAR :: WCHAR +BSTR :: ^OLECHAR LPOLESTR :: ^OLECHAR LPCOLESTR :: LPCSTR LPFILETIME :: ^FILETIME @@ -2694,11 +2695,23 @@ EXCEPTION_MAXIMUM_PARAMETERS :: 15 EXCEPTION_DATATYPE_MISALIGNMENT :: 0x80000002 EXCEPTION_BREAKPOINT :: 0x80000003 +EXCEPTION_SINGLE_STEP :: 0x80000004 EXCEPTION_ACCESS_VIOLATION :: 0xC0000005 +EXCEPTION_IN_PAGE_ERROR :: 0xC0000006 EXCEPTION_ILLEGAL_INSTRUCTION :: 0xC000001D +EXCEPTION_NONCONTINUABLE_EXCEPTION :: 0xC0000025 +EXCEPTION_INVALID_DISPOSITION :: 0xC0000026 EXCEPTION_ARRAY_BOUNDS_EXCEEDED :: 0xC000008C +EXCEPTION_FLT_DENORMAL_OPERAND :: 0xC000008D +EXCEPTION_FLT_DIVIDE_BY_ZERO :: 0xC000008E +EXCEPTION_FLT_INEXACT_RESULT :: 0xC000008F +EXCEPTION_FLT_INVALID_OPERATION :: 0xC0000090 +EXCEPTION_FLT_OVERFLOW :: 0xC0000091 +EXCEPTION_FLT_STACK_CHECK :: 0xC0000092 +EXCEPTION_FLT_UNDERFLOW :: 0xC0000093 EXCEPTION_INT_DIVIDE_BY_ZERO :: 0xC0000094 EXCEPTION_INT_OVERFLOW :: 0xC0000095 +EXCEPTION_PRIV_INSTRUCTION :: 0xC0000096 EXCEPTION_STACK_OVERFLOW :: 0xC00000FD STATUS_PRIVILEGED_INSTRUCTION :: 0xC0000096 @@ -3415,8 +3428,6 @@ TIME_ZONE_INFORMATION :: struct { DaylightBias: LONG, } - -@(private="file") IMAGE_DOS_HEADER :: struct { e_magic: WORD, e_cblp: WORD, @@ -3534,6 +3545,19 @@ IMAGE_EXPORT_DIRECTORY :: struct { AddressOfNameOrdinals: DWORD, // RVA from base of image } +IMAGE_DEBUG_DIRECTORY :: struct { + Characteristics: DWORD, + TimeDateStamp: DWORD, + MajorVersion: WORD, + MinorVersion: WORD, + Type: DWORD, + SizeOfData: DWORD, + AddressOfRawData: DWORD, + PointerToRawData: DWORD, +} + +IMAGE_DEBUG_TYPE_CODEVIEW :: 2 + SICHINTF :: DWORD SHCONTF :: DWORD SFGAOF :: ULONG diff --git a/core/sys/windows/user32.odin b/core/sys/windows/user32.odin index 957d6ab70..da979a3e3 100644 --- a/core/sys/windows/user32.odin +++ b/core/sys/windows/user32.odin @@ -51,6 +51,7 @@ foreign user32 { IsWindowVisible :: proc(hwnd: HWND) -> BOOL --- IsWindowEnabled :: proc(hwnd: HWND) -> BOOL --- IsIconic :: proc(hwnd: HWND) -> BOOL --- + IsZoomed :: proc(hwnd: HWND) -> BOOL --- BringWindowToTop :: proc(hWnd: HWND) -> BOOL --- GetTopWindow :: proc(hWnd: HWND) -> HWND --- SetForegroundWindow :: proc(hWnd: HWND) -> BOOL --- diff --git a/core/time/timezone/tz_windows.odin b/core/time/timezone/tz_windows.odin index 238c4c933..8dc5f533c 100644 --- a/core/time/timezone/tz_windows.odin +++ b/core/time/timezone/tz_windows.odin @@ -11,146 +11,147 @@ TZ_Abbrev :: struct { dst: string, } -tz_abbrevs := map[string]TZ_Abbrev { - "Egypt Standard Time" = {"EET", "EEST"}, // Africa/Cairo - "Morocco Standard Time" = {"+00", "+01"}, // Africa/Casablanca - "South Africa Standard Time" = {"SAST", "SAST"}, // Africa/Johannesburg - "South Sudan Standard Time" = {"CAT", "CAT"}, // Africa/Juba - "Sudan Standard Time" = {"CAT", "CAT"}, // Africa/Khartoum - "W. Central Africa Standard Time" = {"WAT", "WAT"}, // Africa/Lagos - "E. Africa Standard Time" = {"EAT", "EAT"}, // Africa/Nairobi - "Sao Tome Standard Time" = {"GMT", "GMT"}, // Africa/Sao_Tome - "Libya Standard Time" = {"EET", "EET"}, // Africa/Tripoli - "Namibia Standard Time" = {"CAT", "CAT"}, // Africa/Windhoek - "Aleutian Standard Time" = {"HST", "HDT"}, // America/Adak - "Alaskan Standard Time" = {"AKST", "AKDT"}, // America/Anchorage - "Tocantins Standard Time" = {"-03", "-03"}, // America/Araguaina - "Paraguay Standard Time" = {"-04", "-03"}, // America/Asuncion - "Bahia Standard Time" = {"-03", "-03"}, // America/Bahia - "SA Pacific Standard Time" = {"-05", "-05"}, // America/Bogota - "Argentina Standard Time" = {"-03", "-03"}, // America/Buenos_Aires - "Eastern Standard Time (Mexico)" = {"EST", "EST"}, // America/Cancun - "Venezuela Standard Time" = {"-04", "-04"}, // America/Caracas - "SA Eastern Standard Time" = {"-03", "-03"}, // America/Cayenne - "Central Standard Time" = {"CST", "CDT"}, // America/Chicago - "Central Brazilian Standard Time" = {"-04", "-04"}, // America/Cuiaba - "Mountain Standard Time" = {"MST", "MDT"}, // America/Denver - "Greenland Standard Time" = {"-03", "-02"}, // America/Godthab - "Turks And Caicos Standard Time" = {"EST", "EDT"}, // America/Grand_Turk - "Central America Standard Time" = {"CST", "CST"}, // America/Guatemala - "Atlantic Standard Time" = {"AST", "ADT"}, // America/Halifax - "Cuba Standard Time" = {"CST", "CDT"}, // America/Havana - "US Eastern Standard Time" = {"EST", "EDT"}, // America/Indianapolis - "SA Western Standard Time" = {"-04", "-04"}, // America/La_Paz - "Pacific Standard Time" = {"PST", "PDT"}, // America/Los_Angeles - "Mountain Standard Time (Mexico)" = {"MST", "MST"}, // America/Mazatlan - "Central Standard Time (Mexico)" = {"CST", "CST"}, // America/Mexico_City - "Saint Pierre Standard Time" = {"-03", "-02"}, // America/Miquelon - "Montevideo Standard Time" = {"-03", "-03"}, // America/Montevideo - "Eastern Standard Time" = {"EST", "EDT"}, // America/New_York - "US Mountain Standard Time" = {"MST", "MST"}, // America/Phoenix - "Haiti Standard Time" = {"EST", "EDT"}, // America/Port-au-Prince - "Magallanes Standard Time" = {"-03", "-03"}, // America/Punta_Arenas - "Canada Central Standard Time" = {"CST", "CST"}, // America/Regina - "Pacific SA Standard Time" = {"-04", "-03"}, // America/Santiago - "E. South America Standard Time" = {"-03", "-03"}, // America/Sao_Paulo - "Newfoundland Standard Time" = {"NST", "NDT"}, // America/St_Johns - "Pacific Standard Time (Mexico)" = {"PST", "PDT"}, // America/Tijuana - "Yukon Standard Time" = {"MST", "MST"}, // America/Whitehorse - "Central Asia Standard Time" = {"+06", "+06"}, // Asia/Almaty - "Jordan Standard Time" = {"+03", "+03"}, // Asia/Amman - "Arabic Standard Time" = {"+03", "+03"}, // Asia/Baghdad - "Azerbaijan Standard Time" = {"+04", "+04"}, // Asia/Baku - "SE Asia Standard Time" = {"+07", "+07"}, // Asia/Bangkok - "Altai Standard Time" = {"+07", "+07"}, // Asia/Barnaul - "Middle East Standard Time" = {"EET", "EEST"}, // Asia/Beirut - "India Standard Time" = {"IST", "IST"}, // Asia/Calcutta - "Transbaikal Standard Time" = {"+09", "+09"}, // Asia/Chita - "Sri Lanka Standard Time" = {"+0530", "+0530"}, // Asia/Colombo - "Syria Standard Time" = {"+03", "+03"}, // Asia/Damascus - "Bangladesh Standard Time" = {"+06", "+06"}, // Asia/Dhaka - "Arabian Standard Time" = {"+04", "+04"}, // Asia/Dubai - "West Bank Standard Time" = {"EET", "EEST"}, // Asia/Hebron - "W. Mongolia Standard Time" = {"+07", "+07"}, // Asia/Hovd - "North Asia East Standard Time" = {"+08", "+08"}, // Asia/Irkutsk - "Israel Standard Time" = {"IST", "IDT"}, // Asia/Jerusalem - "Afghanistan Standard Time" = {"+0430", "+0430"}, // Asia/Kabul - "Russia Time Zone 11" = {"+12", "+12"}, // Asia/Kamchatka - "Pakistan Standard Time" = {"PKT", "PKT"}, // Asia/Karachi - "Nepal Standard Time" = {"+0545", "+0545"}, // Asia/Katmandu - "North Asia Standard Time" = {"+07", "+07"}, // Asia/Krasnoyarsk - "Magadan Standard Time" = {"+11", "+11"}, // Asia/Magadan - "N. Central Asia Standard Time" = {"+07", "+07"}, // Asia/Novosibirsk - "Omsk Standard Time" = {"+06", "+06"}, // Asia/Omsk - "North Korea Standard Time" = {"KST", "KST"}, // Asia/Pyongyang - "Qyzylorda Standard Time" = {"+05", "+05"}, // Asia/Qyzylorda - "Myanmar Standard Time" = {"+0630", "+0630"}, // Asia/Rangoon - "Arab Standard Time" = {"+03", "+03"}, // Asia/Riyadh - "Sakhalin Standard Time" = {"+11", "+11"}, // Asia/Sakhalin - "Korea Standard Time" = {"KST", "KST"}, // Asia/Seoul - "China Standard Time" = {"CST", "CST"}, // Asia/Shanghai - "Singapore Standard Time" = {"+08", "+08"}, // Asia/Singapore - "Russia Time Zone 10" = {"+11", "+11"}, // Asia/Srednekolymsk - "Taipei Standard Time" = {"CST", "CST"}, // Asia/Taipei - "West Asia Standard Time" = {"+05", "+05"}, // Asia/Tashkent - "Georgian Standard Time" = {"+04", "+04"}, // Asia/Tbilisi - "Iran Standard Time" = {"+0330", "+0330"}, // Asia/Tehran - "Tokyo Standard Time" = {"JST", "JST"}, // Asia/Tokyo - "Tomsk Standard Time" = {"+07", "+07"}, // Asia/Tomsk - "Ulaanbaatar Standard Time" = {"+08", "+08"}, // Asia/Ulaanbaatar - "Vladivostok Standard Time" = {"+10", "+10"}, // Asia/Vladivostok - "Yakutsk Standard Time" = {"+09", "+09"}, // Asia/Yakutsk - "Ekaterinburg Standard Time" = {"+05", "+05"}, // Asia/Yekaterinburg - "Caucasus Standard Time" = {"+04", "+04"}, // Asia/Yerevan - "Azores Standard Time" = {"-01", "+00"}, // Atlantic/Azores - "Cape Verde Standard Time" = {"-01", "-01"}, // Atlantic/Cape_Verde - "Greenwich Standard Time" = {"GMT", "GMT"}, // Atlantic/Reykjavik - "Cen. Australia Standard Time" = {"ACST", "ACDT"}, // Australia/Adelaide - "E. Australia Standard Time" = {"AEST", "AEST"}, // Australia/Brisbane - "AUS Central Standard Time" = {"ACST", "ACST"}, // Australia/Darwin - "Aus Central W. Standard Time" = {"+0845", "+0845"}, // Australia/Eucla - "Tasmania Standard Time" = {"AEST", "AEDT"}, // Australia/Hobart - "Lord Howe Standard Time" = {"+1030", "+11"}, // Australia/Lord_Howe - "W. Australia Standard Time" = {"AWST", "AWST"}, // Australia/Perth - "AUS Eastern Standard Time" = {"AEST", "AEDT"}, // Australia/Sydney - "UTC-11" = {"-11", "-11"}, // Etc/GMT+11 - "Dateline Standard Time" = {"-12", "-12"}, // Etc/GMT+12 - "UTC-02" = {"-02", "-02"}, // Etc/GMT+2 - "UTC-08" = {"-08", "-08"}, // Etc/GMT+8 - "UTC-09" = {"-09", "-09"}, // Etc/GMT+9 - "UTC+12" = {"+12", "+12"}, // Etc/GMT-12 - "UTC+13" = {"+13", "+13"}, // Etc/GMT-13 - "UTC" = {"UTC", "UTC"}, // Etc/UTC - "Astrakhan Standard Time" = {"+04", "+04"}, // Europe/Astrakhan - "W. Europe Standard Time" = {"CET", "CEST"}, // Europe/Berlin - "GTB Standard Time" = {"EET", "EEST"}, // Europe/Bucharest - "Central Europe Standard Time" = {"CET", "CEST"}, // Europe/Budapest - "E. Europe Standard Time" = {"EET", "EEST"}, // Europe/Chisinau - "Turkey Standard Time" = {"+03", "+03"}, // Europe/Istanbul - "Kaliningrad Standard Time" = {"EET", "EET"}, // Europe/Kaliningrad - "FLE Standard Time" = {"EET", "EEST"}, // Europe/Kiev - "GMT Standard Time" = {"GMT", "BST"}, // Europe/London - "Belarus Standard Time" = {"+03", "+03"}, // Europe/Minsk - "Russian Standard Time" = {"MSK", "MSK"}, // Europe/Moscow - "Romance Standard Time" = {"CET", "CEST"}, // Europe/Paris - "Russia Time Zone 3" = {"+04", "+04"}, // Europe/Samara - "Saratov Standard Time" = {"+04", "+04"}, // Europe/Saratov - "Volgograd Standard Time" = {"MSK", "MSK"}, // Europe/Volgograd - "Central European Standard Time" = {"CET", "CEST"}, // Europe/Warsaw - "Mauritius Standard Time" = {"+04", "+04"}, // Indian/Mauritius - "Samoa Standard Time" = {"+13", "+13"}, // Pacific/Apia - "New Zealand Standard Time" = {"NZST", "NZDT"}, // Pacific/Auckland - "Bougainville Standard Time" = {"+11", "+11"}, // Pacific/Bougainville - "Chatham Islands Standard Time" = {"+1245", "+1345"}, // Pacific/Chatham - "Easter Island Standard Time" = {"-06", "-05"}, // Pacific/Easter - "Fiji Standard Time" = {"+12", "+12"}, // Pacific/Fiji - "Central Pacific Standard Time" = {"+11", "+11"}, // Pacific/Guadalcanal - "Hawaiian Standard Time" = {"HST", "HST"}, // Pacific/Honolulu - "Line Islands Standard Time" = {"+14", "+14"}, // Pacific/Kiritimati - "Marquesas Standard Time" = {"-0930", "-0930"}, // Pacific/Marquesas - "Norfolk Standard Time" = {"+11", "+12"}, // Pacific/Norfolk - "West Pacific Standard Time" = {"+10", "+10"}, // Pacific/Port_Moresby - "Tonga Standard Time" = {"+13", "+13"}, // Pacific/Tongatapu +@(rodata) +tz_abbrevs := [?]struct{key: string, value: TZ_Abbrev}{ + {"Egypt Standard Time", {"EET", "EEST"}}, // Africa/Cairo + {"Morocco Standard Time", {"+00", "+01"}}, // Africa/Casablanca + {"South Africa Standard Time", {"SAST", "SAST"}}, // Africa/Johannesburg + {"South Sudan Standard Time", {"CAT", "CAT"}}, // Africa/Juba + {"Sudan Standard Time", {"CAT", "CAT"}}, // Africa/Khartoum + {"W. Central Africa Standard Time", {"WAT", "WAT"}}, // Africa/Lagos + {"E. Africa Standard Time", {"EAT", "EAT"}}, // Africa/Nairobi + {"Sao Tome Standard Time", {"GMT", "GMT"}}, // Africa/Sao_Tome + {"Libya Standard Time", {"EET", "EET"}}, // Africa/Tripoli + {"Namibia Standard Time", {"CAT", "CAT"}}, // Africa/Windhoek + {"Aleutian Standard Time", {"HST", "HDT"}}, // America/Adak + {"Alaskan Standard Time", {"AKST", "AKDT"}}, // America/Anchorage + {"Tocantins Standard Time", {"-03", "-03"}}, // America/Araguaina + {"Paraguay Standard Time", {"-04", "-03"}}, // America/Asuncion + {"Bahia Standard Time", {"-03", "-03"}}, // America/Bahia + {"SA Pacific Standard Time", {"-05", "-05"}}, // America/Bogota + {"Argentina Standard Time", {"-03", "-03"}}, // America/Buenos_Aires + {"Eastern Standard Time (Mexico)", {"EST", "EST"}}, // America/Cancun + {"Venezuela Standard Time", {"-04", "-04"}}, // America/Caracas + {"SA Eastern Standard Time", {"-03", "-03"}}, // America/Cayenne + {"Central Standard Time", {"CST", "CDT"}}, // America/Chicago + {"Central Brazilian Standard Time", {"-04", "-04"}}, // America/Cuiaba + {"Mountain Standard Time", {"MST", "MDT"}}, // America/Denver + {"Greenland Standard Time", {"-03", "-02"}}, // America/Godthab + {"Turks And Caicos Standard Time", {"EST", "EDT"}}, // America/Grand_Turk + {"Central America Standard Time", {"CST", "CST"}}, // America/Guatemala + {"Atlantic Standard Time", {"AST", "ADT"}}, // America/Halifax + {"Cuba Standard Time", {"CST", "CDT"}}, // America/Havana + {"US Eastern Standard Time", {"EST", "EDT"}}, // America/Indianapolis + {"SA Western Standard Time", {"-04", "-04"}}, // America/La_Paz + {"Pacific Standard Time", {"PST", "PDT"}}, // America/Los_Angeles + {"Mountain Standard Time (Mexico)", {"MST", "MST"}}, // America/Mazatlan + {"Central Standard Time (Mexico)", {"CST", "CST"}}, // America/Mexico_City + {"Saint Pierre Standard Time", {"-03", "-02"}}, // America/Miquelon + {"Montevideo Standard Time", {"-03", "-03"}}, // America/Montevideo + {"Eastern Standard Time", {"EST", "EDT"}}, // America/New_York + {"US Mountain Standard Time", {"MST", "MST"}}, // America/Phoenix + {"Haiti Standard Time", {"EST", "EDT"}}, // America/Port-au-Prince + {"Magallanes Standard Time", {"-03", "-03"}}, // America/Punta_Arenas + {"Canada Central Standard Time", {"CST", "CST"}}, // America/Regina + {"Pacific SA Standard Time", {"-04", "-03"}}, // America/Santiago + {"E. South America Standard Time", {"-03", "-03"}}, // America/Sao_Paulo + {"Newfoundland Standard Time", {"NST", "NDT"}}, // America/St_Johns + {"Pacific Standard Time (Mexico)", {"PST", "PDT"}}, // America/Tijuana + {"Yukon Standard Time", {"MST", "MST"}}, // America/Whitehorse + {"Central Asia Standard Time", {"+06", "+06"}}, // Asia/Almaty + {"Jordan Standard Time", {"+03", "+03"}}, // Asia/Amman + {"Arabic Standard Time", {"+03", "+03"}}, // Asia/Baghdad + {"Azerbaijan Standard Time", {"+04", "+04"}}, // Asia/Baku + {"SE Asia Standard Time", {"+07", "+07"}}, // Asia/Bangkok + {"Altai Standard Time", {"+07", "+07"}}, // Asia/Barnaul + {"Middle East Standard Time", {"EET", "EEST"}}, // Asia/Beirut + {"India Standard Time", {"IST", "IST"}}, // Asia/Calcutta + {"Transbaikal Standard Time", {"+09", "+09"}}, // Asia/Chita + {"Sri Lanka Standard Time", {"+0530", "+0530"}}, // Asia/Colombo + {"Syria Standard Time", {"+03", "+03"}}, // Asia/Damascus + {"Bangladesh Standard Time", {"+06", "+06"}}, // Asia/Dhaka + {"Arabian Standard Time", {"+04", "+04"}}, // Asia/Dubai + {"West Bank Standard Time", {"EET", "EEST"}}, // Asia/Hebron + {"W. Mongolia Standard Time", {"+07", "+07"}}, // Asia/Hovd + {"North Asia East Standard Time", {"+08", "+08"}}, // Asia/Irkutsk + {"Israel Standard Time", {"IST", "IDT"}}, // Asia/Jerusalem + {"Afghanistan Standard Time", {"+0430", "+0430"}}, // Asia/Kabul + {"Russia Time Zone 11", {"+12", "+12"}}, // Asia/Kamchatka + {"Pakistan Standard Time", {"PKT", "PKT"}}, // Asia/Karachi + {"Nepal Standard Time", {"+0545", "+0545"}}, // Asia/Katmandu + {"North Asia Standard Time", {"+07", "+07"}}, // Asia/Krasnoyarsk + {"Magadan Standard Time", {"+11", "+11"}}, // Asia/Magadan + {"N. Central Asia Standard Time", {"+07", "+07"}}, // Asia/Novosibirsk + {"Omsk Standard Time", {"+06", "+06"}}, // Asia/Omsk + {"North Korea Standard Time", {"KST", "KST"}}, // Asia/Pyongyang + {"Qyzylorda Standard Time", {"+05", "+05"}}, // Asia/Qyzylorda + {"Myanmar Standard Time", {"+0630", "+0630"}}, // Asia/Rangoon + {"Arab Standard Time", {"+03", "+03"}}, // Asia/Riyadh + {"Sakhalin Standard Time", {"+11", "+11"}}, // Asia/Sakhalin + {"Korea Standard Time", {"KST", "KST"}}, // Asia/Seoul + {"China Standard Time", {"CST", "CST"}}, // Asia/Shanghai + {"Singapore Standard Time", {"+08", "+08"}}, // Asia/Singapore + {"Russia Time Zone 10", {"+11", "+11"}}, // Asia/Srednekolymsk + {"Taipei Standard Time", {"CST", "CST"}}, // Asia/Taipei + {"West Asia Standard Time", {"+05", "+05"}}, // Asia/Tashkent + {"Georgian Standard Time", {"+04", "+04"}}, // Asia/Tbilisi + {"Iran Standard Time", {"+0330", "+0330"}}, // Asia/Tehran + {"Tokyo Standard Time", {"JST", "JST"}}, // Asia/Tokyo + {"Tomsk Standard Time", {"+07", "+07"}}, // Asia/Tomsk + {"Ulaanbaatar Standard Time", {"+08", "+08"}}, // Asia/Ulaanbaatar + {"Vladivostok Standard Time", {"+10", "+10"}}, // Asia/Vladivostok + {"Yakutsk Standard Time", {"+09", "+09"}}, // Asia/Yakutsk + {"Ekaterinburg Standard Time", {"+05", "+05"}}, // Asia/Yekaterinburg + {"Caucasus Standard Time", {"+04", "+04"}}, // Asia/Yerevan + {"Azores Standard Time", {"-01", "+00"}}, // Atlantic/Azores + {"Cape Verde Standard Time", {"-01", "-01"}}, // Atlantic/Cape_Verde + {"Greenwich Standard Time", {"GMT", "GMT"}}, // Atlantic/Reykjavik + {"Cen. Australia Standard Time", {"ACST", "ACDT"}}, // Australia/Adelaide + {"E. Australia Standard Time", {"AEST", "AEST"}}, // Australia/Brisbane + {"AUS Central Standard Time", {"ACST", "ACST"}}, // Australia/Darwin + {"Aus Central W. Standard Time", {"+0845", "+0845"}}, // Australia/Eucla + {"Tasmania Standard Time", {"AEST", "AEDT"}}, // Australia/Hobart + {"Lord Howe Standard Time", {"+1030", "+11"}}, // Australia/Lord_Howe + {"W. Australia Standard Time", {"AWST", "AWST"}}, // Australia/Perth + {"AUS Eastern Standard Time", {"AEST", "AEDT"}}, // Australia/Sydney + {"UTC-11", {"-11", "-11"}}, // Etc/GMT+11 + {"Dateline Standard Time", {"-12", "-12"}}, // Etc/GMT+12 + {"UTC-02", {"-02", "-02"}}, // Etc/GMT+2 + {"UTC-08", {"-08", "-08"}}, // Etc/GMT+8 + {"UTC-09", {"-09", "-09"}}, // Etc/GMT+9 + {"UTC+12", {"+12", "+12"}}, // Etc/GMT-12 + {"UTC+13", {"+13", "+13"}}, // Etc/GMT-13 + {"UTC", {"UTC", "UTC"}}, // Etc/UTC + {"Astrakhan Standard Time", {"+04", "+04"}}, // Europe/Astrakhan + {"W. Europe Standard Time", {"CET", "CEST"}}, // Europe/Berlin + {"GTB Standard Time", {"EET", "EEST"}}, // Europe/Bucharest + {"Central Europe Standard Time", {"CET", "CEST"}}, // Europe/Budapest + {"E. Europe Standard Time", {"EET", "EEST"}}, // Europe/Chisinau + {"Turkey Standard Time", {"+03", "+03"}}, // Europe/Istanbul + {"Kaliningrad Standard Time", {"EET", "EET"}}, // Europe/Kaliningrad + {"FLE Standard Time", {"EET", "EEST"}}, // Europe/Kiev + {"GMT Standard Time", {"GMT", "BST"}}, // Europe/London + {"Belarus Standard Time", {"+03", "+03"}}, // Europe/Minsk + {"Russian Standard Time", {"MSK", "MSK"}}, // Europe/Moscow + {"Romance Standard Time", {"CET", "CEST"}}, // Europe/Paris + {"Russia Time Zone 3", {"+04", "+04"}}, // Europe/Samara + {"Saratov Standard Time", {"+04", "+04"}}, // Europe/Saratov + {"Volgograd Standard Time", {"MSK", "MSK"}}, // Europe/Volgograd + {"Central European Standard Time", {"CET", "CEST"}}, // Europe/Warsaw + {"Mauritius Standard Time", {"+04", "+04"}}, // Indian/Mauritius + {"Samoa Standard Time", {"+13", "+13"}}, // Pacific/Apia + {"New Zealand Standard Time", {"NZST", "NZDT"}}, // Pacific/Auckland + {"Bougainville Standard Time", {"+11", "+11"}}, // Pacific/Bougainville + {"Chatham Islands Standard Time", {"+1245", "+1345"}}, // Pacific/Chatham + {"Easter Island Standard Time", {"-06", "-05"}}, // Pacific/Easter + {"Fiji Standard Time", {"+12", "+12"}}, // Pacific/Fiji + {"Central Pacific Standard Time", {"+11", "+11"}}, // Pacific/Guadalcanal + {"Hawaiian Standard Time", {"HST", "HST"}}, // Pacific/Honolulu + {"Line Islands Standard Time", {"+14", "+14"}}, // Pacific/Kiritimati + {"Marquesas Standard Time", {"-0930", "-0930"}}, // Pacific/Marquesas + {"Norfolk Standard Time", {"+11", "+12"}}, // Pacific/Norfolk + {"West Pacific Standard Time", {"+10", "+10"}}, // Pacific/Port_Moresby + {"Tonga Standard Time", {"+13", "+13"}}, // Pacific/Tongatapu } iana_to_windows_tz :: proc(iana_name: string, allocator := context.allocator) -> (name: string, success: bool) { @@ -269,7 +270,18 @@ _region_load :: proc(reg_str: string, allocator := context.allocator) -> (out_re defer delete(wintz_name, allocator) defer delete(iana_name, allocator) - abbrevs := tz_abbrevs[wintz_name] or_return + abbrevs: TZ_Abbrev + abbrevs_ok: bool + for pair in tz_abbrevs { + if pair.key == wintz_name { + abbrevs = pair.value + abbrevs_ok = true + break + } + } + if !abbrevs_ok { + return + } if abbrevs.std == "UTC" && abbrevs.dst == abbrevs.std { return nil, true } diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index 36d1359ca..82b047103 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -1,4 +1,5 @@ #+vet !using-stmt !using-param +#+feature dynamic-literals package main import "core:fmt" diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 4c3f4b782..93168cf77 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -324,6 +324,18 @@ u64 get_vet_flag_from_name(String const &name) { return VetFlag_NONE; } +enum OptInFeatureFlags : u64 { + OptInFeatureFlag_NONE = 0, + OptInFeatureFlag_DynamicLiterals = 1u<<0, +}; + +u64 get_feature_flag_from_name(String const &name) { + if (name == "dynamic-literals") { + return OptInFeatureFlag_DynamicLiterals; + } + return OptInFeatureFlag_NONE; +} + enum SanitizerFlags : u32 { SanitizerFlag_NONE = 0, @@ -429,7 +441,6 @@ struct BuildContext { bool ignore_unknown_attributes; bool no_bounds_check; bool no_type_assert; - bool no_dynamic_literals; bool no_output_files; bool no_crt; bool no_rpath; @@ -1855,11 +1866,6 @@ gb_internal bool init_build_paths(String init_filename) { produces_output_file = true; } - if (build_context.ODIN_DEFAULT_TO_NIL_ALLOCATOR || - build_context.ODIN_DEFAULT_TO_PANIC_ALLOCATOR) { - bc->no_dynamic_literals = true; - } - if (!produces_output_file) { // Command doesn't produce output files. We're done. return true; diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 60eb030ff..1d792dad8 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -94,12 +94,14 @@ gb_internal Type *check_init_variable(CheckerContext *ctx, Entity *e, Operand *o return nullptr; } if (e2->state.load() != EntityState_Resolved) { - gbString str = type_to_string(t); - defer (gb_string_free(str)); - error(e->token, "Invalid use of a polymorphic type '%s' in %.*s", str, LIT(context_name)); - e->type = t_invalid; + e->type = t; return nullptr; } + gbString str = type_to_string(t); + defer (gb_string_free(str)); + error(operand->expr, "Invalid use of a non-specialized polymorphic type '%s' in %.*s", str, LIT(context_name)); + e->type = t_invalid; + return nullptr; } else if (is_type_empty_union(t)) { gbString str = type_to_string(t); defer (gb_string_free(str)); @@ -971,6 +973,43 @@ gb_internal void check_objc_methods(CheckerContext *ctx, Entity *e, AttributeCon } } +gb_internal void check_foreign_procedure(CheckerContext *ctx, Entity *e, DeclInfo *d) { + GB_ASSERT(e != nullptr); + GB_ASSERT(e->kind == Entity_Procedure); + String name = e->Procedure.link_name; + + mutex_lock(&ctx->info->foreign_mutex); + + auto *fp = &ctx->info->foreigns; + StringHashKey key = string_hash_string(name); + Entity **found = string_map_get(fp, key); + if (found && e != *found) { + Entity *f = *found; + TokenPos pos = f->token.pos; + Type *this_type = base_type(e->type); + Type *other_type = base_type(f->type); + if (is_type_proc(this_type) && is_type_proc(other_type)) { + if (!are_signatures_similar_enough(this_type, other_type)) { + error(d->proc_lit, + "Redeclaration of foreign procedure '%.*s' with different type signatures\n" + "\tat %s", + LIT(name), token_pos_to_string(pos)); + } + } else if (!signature_parameter_similar_enough(this_type, other_type)) { + error(d->proc_lit, + "Foreign entity '%.*s' previously declared elsewhere with a different type\n" + "\tat %s", + LIT(name), token_pos_to_string(pos)); + } + } else if (name == "main") { + error(d->proc_lit, "The link name 'main' is reserved for internal use"); + } else { + string_map_set(fp, key, e); + } + + mutex_unlock(&ctx->info->foreign_mutex); +} + gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) { GB_ASSERT(e->type == nullptr); if (d->proc_lit->kind != Ast_ProcLit) { @@ -1307,57 +1346,16 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) { name = e->Procedure.link_name; } Entity *foreign_library = init_entity_foreign_library(ctx, e); - - if (is_arch_wasm() && foreign_library != nullptr) { - String module_name = str_lit("env"); - GB_ASSERT (foreign_library->kind == Entity_LibraryName); - if (foreign_library->LibraryName.paths.count != 1) { - error(foreign_library->token, "'foreign import' for '%.*s' architecture may only have one path, got %td", - LIT(target_arch_names[build_context.metrics.arch]), foreign_library->LibraryName.paths.count); - } - - if (foreign_library->LibraryName.paths.count >= 1) { - module_name = foreign_library->LibraryName.paths[0]; - } - - if (!string_ends_with(module_name, str_lit(".o"))) { - name = concatenate3_strings(permanent_allocator(), module_name, WASM_MODULE_NAME_SEPARATOR, name); - } - } - e->Procedure.is_foreign = true; e->Procedure.link_name = name; + e->Procedure.foreign_library = foreign_library; - mutex_lock(&ctx->info->foreign_mutex); - - auto *fp = &ctx->info->foreigns; - StringHashKey key = string_hash_string(name); - Entity **found = string_map_get(fp, key); - if (found && e != *found) { - Entity *f = *found; - TokenPos pos = f->token.pos; - Type *this_type = base_type(e->type); - Type *other_type = base_type(f->type); - if (is_type_proc(this_type) && is_type_proc(other_type)) { - if (!are_signatures_similar_enough(this_type, other_type)) { - error(d->proc_lit, - "Redeclaration of foreign procedure '%.*s' with different type signatures\n" - "\tat %s", - LIT(name), token_pos_to_string(pos)); - } - } else if (!signature_parameter_similar_enough(this_type, other_type)) { - error(d->proc_lit, - "Foreign entity '%.*s' previously declared elsewhere with a different type\n" - "\tat %s", - LIT(name), token_pos_to_string(pos)); - } - } else if (name == "main") { - error(d->proc_lit, "The link name 'main' is reserved for internal use"); + if (is_arch_wasm() && foreign_library != nullptr) { + // NOTE(bill): this must be delayed because the foreign import paths might not be evaluated yet until much later + mpsc_enqueue(&ctx->info->foreign_decls_to_check, e); } else { - string_map_set(fp, key, e); + check_foreign_procedure(ctx, e, d); } - - mutex_unlock(&ctx->info->foreign_mutex); } else { String name = e->token.string; if (e->Procedure.link_name.len > 0) { diff --git a/src/check_expr.cpp b/src/check_expr.cpp index cc9483187..231ece2f4 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3672,6 +3672,13 @@ gb_internal bool check_binary_array_expr(CheckerContext *c, Token op, Operand *x } } } + if (is_type_simd_vector(x->type) && !is_type_simd_vector(y->type)) { + if (check_is_assignable_to(c, y, x->type)) { + if (check_binary_op(c, x, op)) { + return true; + } + } + } return false; } @@ -4556,6 +4563,19 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar break; } + case Type_SimdVector: { + Type *elem = base_array_type(t); + if (check_is_assignable_to(c, operand, elem)) { + operand->mode = Addressing_Value; + } else { + operand->mode = Addressing_Invalid; + convert_untyped_error(c, operand, target_type); + return; + } + + break; + } + case Type_Matrix: { Type *elem = base_array_type(t); if (check_is_assignable_to(c, operand, elem)) { @@ -8725,6 +8745,18 @@ gb_internal ExprKind check_basic_directive_expr(CheckerContext *c, Operand *o, A error(node, "#caller_expression may only be used as a default argument parameter"); o->type = t_string; o->mode = Addressing_Value; + } else if (name == "branch_location") { + if (!c->in_defer) { + error(node, "#branch_location may only be used within a 'defer' statement"); + } else if (c->curr_proc_decl) { + Entity *e = c->curr_proc_decl->entity; + if (e != nullptr) { + GB_ASSERT(e->kind == Entity_Procedure); + e->Procedure.uses_branch_location = true; + } + } + o->type = t_source_code_location; + o->mode = Addressing_Value; } else { if (name == "location") { init_core_source_code_location(c->checker); @@ -9339,6 +9371,23 @@ gb_internal bool is_expr_inferred_fixed_array(Ast *type_expr) { return false; } +gb_internal bool check_for_dynamic_literals(CheckerContext *c, Ast *node, AstCompoundLit *cl) { + if (cl->elems.count > 0 && (check_feature_flags(c, node) & OptInFeatureFlag_DynamicLiterals) == 0) { + ERROR_BLOCK(); + error(node, "Compound literals of dynamic types are disabled by default"); + error_line("\tSuggestion: If you want to enable them for this specific file, add '#+feature dynamic-literals' at the top of the file\n"); + error_line("\tWarning: Please understand that dynamic literals will implicitly allocate using the current 'context.allocator' in that scope\n"); + if (build_context.ODIN_DEFAULT_TO_NIL_ALLOCATOR) { + error_line("\tWarning: As '-default-to-panic-allocator' has been set, the dynamic compound literal may not be initialized as expected\n"); + } else if (build_context.ODIN_DEFAULT_TO_PANIC_ALLOCATOR) { + error_line("\tWarning: As '-default-to-panic-allocator' has been set, the dynamic compound literal may not be initialized as expected\n"); + } + return false; + } + + return cl->elems.count > 0; +} + gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) { ExprKind kind = Expr_Expr; ast_node(cl, CompoundLit, node); @@ -9539,11 +9588,6 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * elem_type = t->DynamicArray.elem; context_name = str_lit("dynamic array literal"); is_constant = false; - - if (!build_context.no_dynamic_literals) { - add_package_dependency(c, "runtime", "__dynamic_array_reserve"); - add_package_dependency(c, "runtime", "__dynamic_array_append"); - } } else if (t->kind == Type_SimdVector) { elem_type = t->SimdVector.elem; context_name = str_lit("simd vector literal"); @@ -9718,8 +9762,9 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * if (t->kind == Type_DynamicArray) { - if (build_context.no_dynamic_literals && cl->elems.count) { - error(node, "Compound literals of dynamic types have been disabled"); + if (check_for_dynamic_literals(c, node, cl)) { + add_package_dependency(c, "runtime", "__dynamic_array_reserve"); + add_package_dependency(c, "runtime", "__dynamic_array_append"); } } @@ -10108,9 +10153,7 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * } } - if (build_context.no_dynamic_literals && cl->elems.count) { - error(node, "Compound literals of dynamic types have been disabled"); - } else { + if (check_for_dynamic_literals(c, node, cl)) { add_map_reserve_dependencies(c); add_map_set_dependencies(c); } diff --git a/src/check_type.cpp b/src/check_type.cpp index 13a6125ca..44108ccbe 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2440,8 +2440,12 @@ gb_internal bool check_procedure_type(CheckerContext *ctx, Type *type, Ast *proc bool success = true; isize specialization_count = 0; Type *params = check_get_params(c, c->scope, pt->params, &variadic, &variadic_index, &success, &specialization_count, operands); - Type *results = check_get_results(c, c->scope, pt->results); + bool no_poly_return = c->disallow_polymorphic_return_types; + c->disallow_polymorphic_return_types = c->scope == c->polymorphic_scope; + // NOTE(zen3ger): if the parapoly scope is the current proc's scope, then the return types shall not declare new poly vars + Type *results = check_get_results(c, c->scope, pt->results); + c->disallow_polymorphic_return_types = no_poly_return; isize param_count = 0; isize result_count = 0; @@ -3383,6 +3387,9 @@ gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, T } Type *t = alloc_type_generic(ctx->scope, 0, token.string, specific); if (ctx->allow_polymorphic_types) { + if (ctx->disallow_polymorphic_return_types) { + error(ident, "Undeclared polymorphic parameter '%.*s' in return type", LIT(token.string)); + } Scope *ps = ctx->polymorphic_scope; Scope *s = ctx->scope; Scope *entity_scope = s; diff --git a/src/checker.cpp b/src/checker.cpp index b7cf343f8..5d3263789 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -542,6 +542,23 @@ gb_internal u64 check_vet_flags(Ast *node) { return ast_file_vet_flags(file); } +gb_internal u64 check_feature_flags(CheckerContext *c, Ast *node) { + AstFile *file = c->file; + if (file == nullptr && + c->curr_proc_decl && + c->curr_proc_decl->proc_lit) { + file = c->curr_proc_decl->proc_lit->file(); + } + if (file == nullptr) { + file = node->file(); + } + if (file != nullptr && file->feature_flags_set) { + return file->feature_flags; + } + return 0; +} + + enum VettedEntityKind { VettedEntity_Invalid, @@ -1164,7 +1181,6 @@ gb_internal void init_universal(void) { add_global_bool_constant("ODIN_NO_BOUNDS_CHECK", build_context.no_bounds_check); add_global_bool_constant("ODIN_NO_TYPE_ASSERT", build_context.no_type_assert); add_global_bool_constant("ODIN_DEFAULT_TO_PANIC_ALLOCATOR", bc->ODIN_DEFAULT_TO_PANIC_ALLOCATOR); - add_global_bool_constant("ODIN_NO_DYNAMIC_LITERALS", bc->no_dynamic_literals); add_global_bool_constant("ODIN_NO_CRT", bc->no_crt); add_global_bool_constant("ODIN_USE_SEPARATE_MODULES", bc->use_separate_modules); add_global_bool_constant("ODIN_TEST", bc->command_kind == Command_test); @@ -1356,6 +1372,7 @@ gb_internal void init_checker_info(CheckerInfo *i) { mpsc_init(&i->required_global_variable_queue, a); // 1<<10); mpsc_init(&i->required_foreign_imports_through_force_queue, a); // 1<<10); mpsc_init(&i->foreign_imports_to_check_fullpaths, a); // 1<<10); + mpsc_init(&i->foreign_decls_to_check, a); // 1<<10); mpsc_init(&i->intrinsics_entry_point_usage, a); // 1<<10); // just waste some memory here, even if it probably never used string_map_init(&i->load_directory_cache); @@ -1382,6 +1399,7 @@ gb_internal void destroy_checker_info(CheckerInfo *i) { mpsc_destroy(&i->required_global_variable_queue); mpsc_destroy(&i->required_foreign_imports_through_force_queue); mpsc_destroy(&i->foreign_imports_to_check_fullpaths); + mpsc_destroy(&i->foreign_decls_to_check); map_destroy(&i->objc_msgSend_types); string_map_destroy(&i->load_file_cache); @@ -5094,6 +5112,38 @@ gb_internal void check_foreign_import_fullpaths(Checker *c) { e->LibraryName.paths = fl->fullpaths; } + + for (Entity *e = nullptr; mpsc_dequeue(&c->info.foreign_decls_to_check, &e); /**/) { + GB_ASSERT(e != nullptr); + if (e->kind != Entity_Procedure) { + continue; + } + if (!is_arch_wasm()) { + continue; + } + Entity *foreign_library = e->Procedure.foreign_library; + GB_ASSERT(foreign_library != nullptr); + + String name = e->Procedure.link_name; + + String module_name = str_lit("env"); + GB_ASSERT (foreign_library->kind == Entity_LibraryName); + if (foreign_library->LibraryName.paths.count != 1) { + error(foreign_library->token, "'foreign import' for '%.*s' architecture may only have one path, got %td", + LIT(target_arch_names[build_context.metrics.arch]), foreign_library->LibraryName.paths.count); + } + + if (foreign_library->LibraryName.paths.count >= 1) { + module_name = foreign_library->LibraryName.paths[0]; + } + + if (!string_ends_with(module_name, str_lit(".o"))) { + name = concatenate3_strings(permanent_allocator(), module_name, WASM_MODULE_NAME_SEPARATOR, name); + } + e->Procedure.link_name = name; + + check_foreign_procedure(&ctx, e, e->decl_info); + } } gb_internal void check_add_foreign_import_decl(CheckerContext *ctx, Ast *decl) { diff --git a/src/checker.hpp b/src/checker.hpp index 438156f18..3951fcefe 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -461,6 +461,7 @@ struct CheckerInfo { MPSCQueue<Entity *> required_global_variable_queue; MPSCQueue<Entity *> required_foreign_imports_through_force_queue; MPSCQueue<Entity *> foreign_imports_to_check_fullpaths; + MPSCQueue<Entity *> foreign_decls_to_check; MPSCQueue<Ast *> intrinsics_entry_point_usage; @@ -521,6 +522,7 @@ struct CheckerContext { bool in_enum_type; bool collect_delayed_decls; bool allow_polymorphic_types; + bool disallow_polymorphic_return_types; // NOTE(zen3ger): no poly type decl in return types bool no_polymorphic_errors; bool hide_polymorphic_errors; bool in_polymorphic_specialization; diff --git a/src/entity.cpp b/src/entity.cpp index 0c4a20df4..802b381f9 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -256,6 +256,7 @@ struct Entity { bool entry_point_only : 1; bool has_instrumentation : 1; bool is_memcpy_like : 1; + bool uses_branch_location : 1; } Procedure; struct { Array<Entity *> entities; diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 01ded321e..696ced0df 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -1096,8 +1096,6 @@ gb_internal void lb_internal_dynamic_map_set(lbProcedure *p, lbValue const &map_ } gb_internal lbValue lb_dynamic_map_reserve(lbProcedure *p, lbValue const &map_ptr, isize const capacity, TokenPos const &pos) { - GB_ASSERT(!build_context.no_dynamic_literals); - TEMPORARY_ALLOCATOR_GUARD(); String proc_name = {}; diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index e84ffd1cd..42d283a1e 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -359,6 +359,10 @@ struct lbProcedure { bool in_multi_assignment; Array<LLVMValueRef> raw_input_parameters; + bool uses_branch_location; + TokenPos branch_location_pos; + TokenPos curr_token_pos; + Array<lbVariadicReuseSlices> variadic_reuses; lbAddr variadic_reuse_base_array_ptr; @@ -444,7 +448,8 @@ gb_internal lbValue lb_emit_matrix_ev(lbProcedure *p, lbValue s, isize row, isiz gb_internal lbValue lb_emit_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type); gb_internal lbValue lb_emit_byte_swap(lbProcedure *p, lbValue value, Type *end_type); -gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block); +gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block, TokenPos pos); +gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block, Ast *node); gb_internal lbValue lb_emit_transmute(lbProcedure *p, lbValue value, Type *t); gb_internal lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue right); gb_internal lbValue lb_emit_call(lbProcedure *p, lbValue value, Array<lbValue> const &args, ProcInlining inlining = ProcInlining_none); @@ -742,3 +747,5 @@ gb_global char const *llvm_linkage_strings[] = { }; #define ODIN_METADATA_IS_PACKED str_lit("odin-is-packed") +#define ODIN_METADATA_MIN_ALIGN str_lit("odin-min-align") +#define ODIN_METADATA_MAX_ALIGN str_lit("odin-max-align") diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 9c325e088..df9dca801 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -3502,7 +3502,13 @@ gb_internal lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) { case_ast_node(bd, BasicDirective, expr); TokenPos pos = bd->token.pos; - GB_PANIC("Non-constant basic literal %s - %.*s", token_pos_to_string(pos), LIT(bd->name.string)); + String name = bd->name.string; + if (name == "branch_location") { + GB_ASSERT(p->uses_branch_location); + String proc_name = p->entity->token.string; + return lb_emit_source_code_location_as_global(p, proc_name, p->branch_location_pos); + } + GB_PANIC("Non-constant basic literal %s - %.*s", token_pos_to_string(pos), LIT(name)); case_end; case_ast_node(i, Implicit, expr); @@ -3668,7 +3674,7 @@ gb_internal lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) { lb_emit_if(p, lb_emit_try_has_value(p, rhs), then, else_); lb_start_block(p, else_); - lb_emit_defer_stmts(p, lbDeferExit_Branch, block); + lb_emit_defer_stmts(p, lbDeferExit_Branch, block, expr); lb_emit_jump(p, block); lb_start_block(p, then); @@ -4807,7 +4813,7 @@ gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) { if (cl->elems.count == 0) { break; } - GB_ASSERT(!build_context.no_dynamic_literals); + GB_ASSERT(expr->file()->feature_flags & OptInFeatureFlag_DynamicLiterals); lbValue err = lb_dynamic_map_reserve(p, v.addr, 2*cl->elems.count, pos); gb_unused(err); @@ -4896,7 +4902,7 @@ gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) { if (cl->elems.count == 0) { break; } - GB_ASSERT(!build_context.no_dynamic_literals); + GB_ASSERT(expr->file()->feature_flags & OptInFeatureFlag_DynamicLiterals); Type *et = bt->DynamicArray.elem; lbValue size = lb_const_int(p->module, t_int, type_size_of(et)); @@ -5493,7 +5499,7 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { lb_emit_if(p, lb_emit_try_has_value(p, rhs), then, else_); lb_start_block(p, else_); - lb_emit_defer_stmts(p, lbDeferExit_Branch, block); + lb_emit_defer_stmts(p, lbDeferExit_Branch, block, expr); lb_emit_jump(p, block); lb_start_block(p, then); diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index bab330da7..762256258 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -734,6 +734,17 @@ gb_internal LLVMValueRef OdinLLVMBuildLoad(lbProcedure *p, LLVMTypeRef type, LLV if (is_packed != 0) { LLVMSetAlignment(result, 1); } + u64 align = LLVMGetAlignment(result); + u64 align_min = lb_get_metadata_custom_u64(p->module, value, ODIN_METADATA_MIN_ALIGN); + u64 align_max = lb_get_metadata_custom_u64(p->module, value, ODIN_METADATA_MAX_ALIGN); + if (align_min != 0 && align < align_min) { + align = align_min; + } + if (align_max != 0 && align > align_max) { + align = align_max; + } + GB_ASSERT(align <= UINT_MAX); + LLVMSetAlignment(result, (unsigned int)align); } return result; @@ -2121,6 +2132,7 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { } i64 prev_offset = 0; + bool requires_packing = type->Struct.is_packed; for (i32 field_index : struct_fields_index_by_increasing_offset(temporary_allocator(), type)) { Entity *field = type->Struct.fields[field_index]; i64 offset = type->Struct.offsets[field_index]; @@ -2141,6 +2153,10 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { field_type = t_rawptr; } + // max_field_align might misalign items in a way that requires packing + // so check the alignment of all fields to see if packing is required. + requires_packing = requires_packing || ((offset % type_align_of(field_type)) != 0); + array_add(&fields, lb_type(m, field_type)); prev_offset = offset + type_size_of(field->type); @@ -2155,7 +2171,7 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { GB_ASSERT(fields[i] != nullptr); } - LLVMTypeRef struct_type = LLVMStructTypeInContext(ctx, fields.data, cast(unsigned)fields.count, type->Struct.is_packed); + LLVMTypeRef struct_type = LLVMStructTypeInContext(ctx, fields.data, cast(unsigned)fields.count, requires_packing); map_set(&m->struct_field_remapping, cast(void *)struct_type, field_remapping); map_set(&m->struct_field_remapping, cast(void *)type, field_remapping); #if 0 diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 712e13592..7e44a0046 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -125,6 +125,10 @@ gb_internal lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool i // map_init(&p->selector_addr, 0); // map_init(&p->tuple_fix_map, 0); + if (p->entity != nullptr && p->entity->Procedure.uses_branch_location) { + p->uses_branch_location = true; + } + if (p->is_foreign) { lb_add_foreign_library_path(p->module, entity->Procedure.foreign_library); } @@ -757,7 +761,7 @@ gb_internal void lb_end_procedure_body(lbProcedure *p) { if (p->type->Proc.result_count == 0) { instr = LLVMGetLastInstruction(p->curr_block->block); if (!lb_is_instr_terminating(instr)) { - lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr); + lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr, p->body); lb_set_debug_position_to_procedure_end(p); LLVMBuildRetVoid(p->builder); } diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp index 9a5f25712..a2f0d2f4a 100644 --- a/src/llvm_backend_stmt.cpp +++ b/src/llvm_backend_stmt.cpp @@ -208,8 +208,8 @@ gb_internal void lb_open_scope(lbProcedure *p, Scope *s) { } -gb_internal void lb_close_scope(lbProcedure *p, lbDeferExitKind kind, lbBlock *block, bool pop_stack=true) { - lb_emit_defer_stmts(p, kind, block); +gb_internal void lb_close_scope(lbProcedure *p, lbDeferExitKind kind, lbBlock *block, Ast *node, bool pop_stack=true) { + lb_emit_defer_stmts(p, kind, block, node); GB_ASSERT(p->scope_index > 0); // NOTE(bill): Remove `context`s made in that scope @@ -721,7 +721,7 @@ gb_internal void lb_build_range_interval(lbProcedure *p, AstBinaryExpr *node, lb_build_stmt(p, rs->body); - lb_close_scope(p, lbDeferExit_Default, nullptr); + lb_close_scope(p, lbDeferExit_Default, nullptr, node->left); lb_pop_target_list(p); if (check != nullptr) { @@ -854,7 +854,7 @@ gb_internal void lb_build_range_tuple(lbProcedure *p, AstRangeStmt *rs, Scope *s lb_build_stmt(p, rs->body); - lb_close_scope(p, lbDeferExit_Default, nullptr); + lb_close_scope(p, lbDeferExit_Default, nullptr, rs->body); lb_pop_target_list(p); lb_emit_jump(p, loop); lb_start_block(p, done); @@ -976,7 +976,7 @@ gb_internal void lb_build_range_stmt_struct_soa(lbProcedure *p, AstRangeStmt *rs lb_build_stmt(p, rs->body); - lb_close_scope(p, lbDeferExit_Default, nullptr); + lb_close_scope(p, lbDeferExit_Default, nullptr, rs->body); lb_pop_target_list(p); lb_emit_jump(p, loop); lb_start_block(p, done); @@ -1192,7 +1192,7 @@ gb_internal void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *sc lb_build_stmt(p, rs->body); - lb_close_scope(p, lbDeferExit_Default, nullptr); + lb_close_scope(p, lbDeferExit_Default, nullptr, rs->body); lb_pop_target_list(p); lb_emit_jump(p, loop); lb_start_block(p, done); @@ -1363,7 +1363,7 @@ gb_internal void lb_build_unroll_range_stmt(lbProcedure *p, AstUnrollRangeStmt * } - lb_close_scope(p, lbDeferExit_Default, nullptr); + lb_close_scope(p, lbDeferExit_Default, nullptr, rs->body); } gb_internal bool lb_switch_stmt_can_be_trivial_jump_table(AstSwitchStmt *ss, bool *default_found_) { @@ -1433,6 +1433,7 @@ gb_internal void lb_build_switch_stmt(lbProcedure *p, AstSwitchStmt *ss, Scope * ast_node(body, BlockStmt, ss->body); isize case_count = body->stmts.count; + Ast *default_clause = nullptr; Slice<Ast *> default_stmts = {}; lbBlock *default_fall = nullptr; lbBlock *default_block = nullptr; @@ -1482,6 +1483,7 @@ gb_internal void lb_build_switch_stmt(lbProcedure *p, AstSwitchStmt *ss, Scope * if (cc->list.count == 0) { // default case + default_clause = clause; default_stmts = cc->stmts; default_fall = fall; if (switch_instr == nullptr) { @@ -1552,7 +1554,7 @@ gb_internal void lb_build_switch_stmt(lbProcedure *p, AstSwitchStmt *ss, Scope * lb_push_target_list(p, ss->label, done, nullptr, fall); lb_open_scope(p, body->scope); lb_build_stmt_list(p, cc->stmts); - lb_close_scope(p, lbDeferExit_Default, body); + lb_close_scope(p, lbDeferExit_Default, body, clause); lb_pop_target_list(p); lb_emit_jump(p, done); @@ -1570,13 +1572,13 @@ gb_internal void lb_build_switch_stmt(lbProcedure *p, AstSwitchStmt *ss, Scope * lb_push_target_list(p, ss->label, done, nullptr, default_fall); lb_open_scope(p, default_block->scope); lb_build_stmt_list(p, default_stmts); - lb_close_scope(p, lbDeferExit_Default, default_block); + lb_close_scope(p, lbDeferExit_Default, default_block, default_clause); lb_pop_target_list(p); } lb_emit_jump(p, done); lb_start_block(p, done); - lb_close_scope(p, lbDeferExit_Default, done); + lb_close_scope(p, lbDeferExit_Default, done, ss->body); } gb_internal void lb_store_type_case_implicit(lbProcedure *p, Ast *clause, lbValue value, bool is_default_case) { @@ -1627,7 +1629,7 @@ gb_internal void lb_type_case_body(lbProcedure *p, Ast *label, Ast *clause, lbBl lb_push_target_list(p, label, done, nullptr, nullptr); lb_build_stmt_list(p, cc->stmts); - lb_close_scope(p, lbDeferExit_Default, body); + lb_close_scope(p, lbDeferExit_Default, body, clause); lb_pop_target_list(p); lb_emit_jump(p, done); @@ -1835,7 +1837,7 @@ gb_internal void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss lb_emit_jump(p, done); lb_start_block(p, done); - lb_close_scope(p, lbDeferExit_Default, done); + lb_close_scope(p, lbDeferExit_Default, done, ss->body); } @@ -1959,7 +1961,7 @@ gb_internal void lb_build_assignment(lbProcedure *p, Array<lbAddr> &lvals, Slice p->in_multi_assignment = prev_in_assignment; } -gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res) { +gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res, TokenPos pos) { lbFunctionType *ft = lb_get_function_type(p->module, p->type); bool return_by_pointer = ft->ret.kind == lbArg_Indirect; bool split_returns = ft->multiple_return_original_type != nullptr; @@ -1982,7 +1984,7 @@ gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res) { LLVMBuildStore(p->builder, LLVMConstNull(p->abi_function_type->ret.type), p->return_ptr.addr.value); } - lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr); + lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr, pos); // Check for terminator in the defer stmts LLVMValueRef instr = LLVMGetLastInstruction(p->curr_block->block); @@ -2012,7 +2014,7 @@ gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res) { ret_val = OdinLLVMBuildTransmute(p, ret_val, ret_type); } - lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr); + lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr, pos); // Check for terminator in the defer stmts LLVMValueRef instr = LLVMGetLastInstruction(p->curr_block->block); @@ -2021,7 +2023,7 @@ gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res) { } } } -gb_internal void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return_results) { +gb_internal void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return_results, TokenPos pos) { lb_ensure_abi_function_type(p->module, p); isize return_count = p->type->Proc.result_count; @@ -2029,7 +2031,7 @@ gb_internal void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return if (return_count == 0) { // No return values - lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr); + lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr, pos); // Check for terminator in the defer stmts LLVMValueRef instr = LLVMGetLastInstruction(p->curr_block->block); @@ -2138,11 +2140,11 @@ gb_internal void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return GB_ASSERT(result_values.count-1 == result_eps.count); lb_addr_store(p, p->return_ptr, result_values[result_values.count-1]); - lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr); + lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr, pos); LLVMBuildRetVoid(p->builder); return; } else { - return lb_build_return_stmt_internal(p, result_values[result_values.count-1]); + return lb_build_return_stmt_internal(p, result_values[result_values.count-1], pos); } } else { @@ -2169,7 +2171,7 @@ gb_internal void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return } if (return_by_pointer) { - lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr); + lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr, pos); LLVMBuildRetVoid(p->builder); return; } @@ -2177,13 +2179,13 @@ gb_internal void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return res = lb_emit_load(p, res); } } - lb_build_return_stmt_internal(p, res); + lb_build_return_stmt_internal(p, res, pos); } gb_internal void lb_build_if_stmt(lbProcedure *p, Ast *node) { ast_node(is, IfStmt, node); lb_open_scope(p, is->scope); // Scope #1 - defer (lb_close_scope(p, lbDeferExit_Default, nullptr)); + defer (lb_close_scope(p, lbDeferExit_Default, nullptr, node)); lbBlock *then = lb_create_block(p, "if.then"); lbBlock *done = lb_create_block(p, "if.done"); @@ -2234,7 +2236,7 @@ gb_internal void lb_build_if_stmt(lbProcedure *p, Ast *node) { lb_open_scope(p, scope_of_node(is->else_stmt)); lb_build_stmt(p, is->else_stmt); - lb_close_scope(p, lbDeferExit_Default, nullptr); + lb_close_scope(p, lbDeferExit_Default, nullptr, is->else_stmt); } lb_emit_jump(p, done); @@ -2251,7 +2253,7 @@ gb_internal void lb_build_if_stmt(lbProcedure *p, Ast *node) { lb_open_scope(p, scope_of_node(is->else_stmt)); lb_build_stmt(p, is->else_stmt); - lb_close_scope(p, lbDeferExit_Default, nullptr); + lb_close_scope(p, lbDeferExit_Default, nullptr, is->else_stmt); lb_emit_jump(p, done); } @@ -2322,7 +2324,7 @@ gb_internal void lb_build_for_stmt(lbProcedure *p, Ast *node) { } lb_start_block(p, done); - lb_close_scope(p, lbDeferExit_Default, nullptr); + lb_close_scope(p, lbDeferExit_Default, nullptr, node); } gb_internal void lb_build_assign_stmt_array(lbProcedure *p, TokenKind op, lbAddr const &lhs, lbValue const &value) { @@ -2588,7 +2590,7 @@ gb_internal void lb_build_stmt(lbProcedure *p, Ast *node) { lb_open_scope(p, bs->scope); lb_build_stmt_list(p, bs->stmts); - lb_close_scope(p, lbDeferExit_Default, nullptr); + lb_close_scope(p, lbDeferExit_Default, nullptr, node); if (done != nullptr) { lb_emit_jump(p, done); @@ -2702,7 +2704,7 @@ gb_internal void lb_build_stmt(lbProcedure *p, Ast *node) { case_end; case_ast_node(rs, ReturnStmt, node); - lb_build_return_stmt(p, rs->results); + lb_build_return_stmt(p, rs->results, ast_token(node).pos); case_end; case_ast_node(is, IfStmt, node); @@ -2755,7 +2757,7 @@ gb_internal void lb_build_stmt(lbProcedure *p, Ast *node) { } } if (block != nullptr) { - lb_emit_defer_stmts(p, lbDeferExit_Branch, block); + lb_emit_defer_stmts(p, lbDeferExit_Branch, block, node); } lb_emit_jump(p, block); lb_start_block(p, lb_create_block(p, "unreachable")); @@ -2795,7 +2797,13 @@ gb_internal void lb_build_defer_stmt(lbProcedure *p, lbDefer const &d) { } } -gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block) { +gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block, TokenPos pos) { + TokenPos prev_token_pos = p->branch_location_pos; + if (p->uses_branch_location) { + p->branch_location_pos = pos; + } + defer (p->branch_location_pos = prev_token_pos); + isize count = p->defer_stmts.count; isize i = count; while (i --> 0) { @@ -2822,6 +2830,21 @@ gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlo } } +gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block, Ast *node) { + TokenPos pos = {}; + if (node) { + if (node->kind == Ast_BlockStmt) { + pos = ast_end_token(node).pos; + } else if (node->kind == Ast_CaseClause) { + pos = ast_end_token(node).pos; + } else { + pos = ast_token(node).pos; + } + } + return lb_emit_defer_stmts(p, kind, block, pos); +} + + gb_internal void lb_add_defer_node(lbProcedure *p, isize scope_index, Ast *stmt) { Type *pt = base_type(p->type); GB_ASSERT(pt->kind == Type_Proc); diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index a2a0ba4cc..7b7c9d6e9 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -476,8 +476,8 @@ gb_internal lbValue lb_emit_or_else(lbProcedure *p, Ast *arg, Ast *else_expr, Ty } } -gb_internal void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return_results); -gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res); +gb_internal void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return_results, TokenPos pos); +gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res, TokenPos pos); gb_internal lbValue lb_emit_or_return(lbProcedure *p, Ast *arg, TypeAndValue const &tv) { lbValue lhs = {}; @@ -506,10 +506,10 @@ gb_internal lbValue lb_emit_or_return(lbProcedure *p, Ast *arg, TypeAndValue con lbValue found = map_must_get(&p->module->values, end_entity); lb_emit_store(p, found, rhs); - lb_build_return_stmt(p, {}); + lb_build_return_stmt(p, {}, ast_token(arg).pos); } else { GB_ASSERT(tuple->variables.count == 1); - lb_build_return_stmt_internal(p, rhs); + lb_build_return_stmt_internal(p, rhs, ast_token(arg).pos); } } lb_start_block(p, continue_block); @@ -1200,9 +1200,22 @@ gb_internal lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index) { lbValue gep = lb_emit_struct_ep_internal(p, s, index, result_type); Type *bt = base_type(t); - if (bt->kind == Type_Struct && bt->Struct.is_packed) { - lb_set_metadata_custom_u64(p->module, gep.value, ODIN_METADATA_IS_PACKED, 1); - GB_ASSERT(lb_get_metadata_custom_u64(p->module, gep.value, ODIN_METADATA_IS_PACKED) == 1); + if (bt->kind == Type_Struct) { + if (bt->Struct.is_packed) { + lb_set_metadata_custom_u64(p->module, gep.value, ODIN_METADATA_IS_PACKED, 1); + GB_ASSERT(lb_get_metadata_custom_u64(p->module, gep.value, ODIN_METADATA_IS_PACKED) == 1); + } + u64 align_max = bt->Struct.custom_max_field_align; + u64 align_min = bt->Struct.custom_min_field_align; + GB_ASSERT(align_min == 0 || align_max == 0 || align_min <= align_max); + if (align_max) { + lb_set_metadata_custom_u64(p->module, gep.value, ODIN_METADATA_MAX_ALIGN, align_max); + GB_ASSERT(lb_get_metadata_custom_u64(p->module, gep.value, ODIN_METADATA_MAX_ALIGN) == align_max); + } + if (align_min) { + lb_set_metadata_custom_u64(p->module, gep.value, ODIN_METADATA_MIN_ALIGN, align_min); + GB_ASSERT(lb_get_metadata_custom_u64(p->module, gep.value, ODIN_METADATA_MIN_ALIGN) == align_min); + } } return gep; diff --git a/src/main.cpp b/src/main.cpp index 4d85a9e72..41c7170f6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1192,7 +1192,7 @@ gb_internal bool parse_build_flags(Array<String> args) { build_context.no_type_assert = true; break; case BuildFlag_NoDynamicLiterals: - build_context.no_dynamic_literals = true; + gb_printf_err("Warning: Use of -no-dynamic-literals is now redundant\n"); break; case BuildFlag_NoCRT: build_context.no_crt = true; @@ -2120,7 +2120,7 @@ gb_internal void export_dependencies(Checker *c) { for_array(i, files) { AstFile *file = files[i]; gb_fprintf(&f, "\t\t\"%.*s\"", LIT(file->fullpath)); - if (i+1 == files.count) { + if (i+1 < files.count) { gb_fprintf(&f, ","); } gb_fprintf(&f, "\n"); @@ -2133,7 +2133,7 @@ gb_internal void export_dependencies(Checker *c) { for_array(i, load_files) { LoadFileCache *cache = load_files[i]; gb_fprintf(&f, "\t\t\"%.*s\"", LIT(cache->path)); - if (i+1 == load_files.count) { + if (i+1 < load_files.count) { gb_fprintf(&f, ","); } gb_fprintf(&f, "\n"); diff --git a/src/parser.cpp b/src/parser.cpp index aa90651d3..03c5a5962 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -6265,10 +6265,16 @@ gb_internal u64 parse_vet_tag(Token token_for_pos, String s) { syntax_error(token_for_pos, "Invalid vet flag name: %.*s", LIT(p)); error_line("\tExpected one of the following\n"); error_line("\tunused\n"); + error_line("\tunused-variables\n"); + error_line("\tunused-imports\n"); + error_line("\tunused-procedures\n"); error_line("\tshadowing\n"); error_line("\tusing-stmt\n"); error_line("\tusing-param\n"); + error_line("\tstyle\n"); error_line("\textra\n"); + error_line("\tcast\n"); + error_line("\ttabs\n"); return build_context.vet_flags; } } @@ -6286,6 +6292,63 @@ gb_internal u64 parse_vet_tag(Token token_for_pos, String s) { return vet_flags &~ vet_not_flags; } +gb_internal u64 parse_feature_tag(Token token_for_pos, String s) { + String const prefix = str_lit("feature"); + GB_ASSERT(string_starts_with(s, prefix)); + s = string_trim_whitespace(substring(s, prefix.len, s.len)); + + if (s.len == 0) { + return OptInFeatureFlag_NONE; + } + + u64 feature_flags = 0; + u64 feature_not_flags = 0; + + while (s.len > 0) { + String p = string_trim_whitespace(vet_tag_get_token(s, &s)); + if (p.len == 0) { + break; + } + + bool is_notted = false; + if (p[0] == '!') { + is_notted = true; + p = substring(p, 1, p.len); + if (p.len == 0) { + syntax_error(token_for_pos, "Expected a feature flag name after '!'"); + return OptInFeatureFlag_NONE; + } + } + + u64 flag = get_feature_flag_from_name(p); + if (flag != OptInFeatureFlag_NONE) { + if (is_notted) { + feature_not_flags |= flag; + } else { + feature_flags |= flag; + } + } else { + ERROR_BLOCK(); + syntax_error(token_for_pos, "Invalid feature flag name: %.*s", LIT(p)); + error_line("\tExpected one of the following\n"); + error_line("\tdynamic-literals\n"); + return OptInFeatureFlag_NONE; + } + } + + if (feature_flags == 0 && feature_not_flags == 0) { + return OptInFeatureFlag_NONE; + } + if (feature_flags == 0 && feature_not_flags != 0) { + return OptInFeatureFlag_NONE &~ feature_not_flags; + } + if (feature_flags != 0 && feature_not_flags == 0) { + return feature_flags; + } + GB_ASSERT(feature_flags != 0 && feature_not_flags != 0); + return feature_flags &~ feature_not_flags; +} + gb_internal String dir_from_path(String path) { String base_dir = path; for (isize i = path.len-1; i >= 0; i--) { @@ -6399,6 +6462,9 @@ gb_internal bool parse_file_tag(const String &lc, const Token &tok, AstFile *f) } else if (command == "file") { f->flags |= AstFile_IsPrivateFile; } + } else if (string_starts_with(lc, str_lit("feature"))) { + f->feature_flags |= parse_feature_tag(tok, lc); + f->feature_flags_set = true; } else if (lc == "lazy") { if (build_context.ignore_lazy) { // Ignore @@ -6493,9 +6559,7 @@ gb_internal bool parse_file(Parser *p, AstFile *f) { } f->package_name = package_name.string; - // TODO: Shouldn't single file only matter for build tags? no-instrumentation for example - // should be respected even when in single file mode. - if (!f->pkg->is_single_file) { + { if (docs != nullptr && docs->list.count > 0) { for (Token const &tok : docs->list) { GB_ASSERT(tok.kind == Token_Comment); diff --git a/src/parser.hpp b/src/parser.hpp index e332fed50..bbf70d03e 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -108,7 +108,9 @@ struct AstFile { String package_name; u64 vet_flags; + u64 feature_flags; bool vet_flags_set; + bool feature_flags_set; // >= 0: In Expression // < 0: In Control Clause diff --git a/tests/core/encoding/cbor/test_core_cbor.odin b/tests/core/encoding/cbor/test_core_cbor.odin index c614727b9..ee853ebac 100644 --- a/tests/core/encoding/cbor/test_core_cbor.odin +++ b/tests/core/encoding/cbor/test_core_cbor.odin @@ -1,3 +1,4 @@ +#+feature dynamic-literals package test_encoding_cbor import "base:intrinsics" diff --git a/tests/core/fmt/test_core_fmt.odin b/tests/core/fmt/test_core_fmt.odin index 3a1eb37e7..c79a15e85 100644 --- a/tests/core/fmt/test_core_fmt.odin +++ b/tests/core/fmt/test_core_fmt.odin @@ -1,3 +1,4 @@ +#+feature dynamic-literals package test_core_fmt import "base:runtime" diff --git a/tests/core/hash/test_core_hash.odin b/tests/core/hash/test_core_hash.odin index c3f0bee91..adb55d2d8 100644 --- a/tests/core/hash/test_core_hash.odin +++ b/tests/core/hash/test_core_hash.odin @@ -1,3 +1,4 @@ +#+feature dynamic-literals package test_core_hash import "core:hash/xxhash" diff --git a/tests/core/hash/test_vectors_xxhash.odin b/tests/core/hash/test_vectors_xxhash.odin index f72e2699a..04e2d4f1f 100644 --- a/tests/core/hash/test_vectors_xxhash.odin +++ b/tests/core/hash/test_vectors_xxhash.odin @@ -1,4 +1,5 @@ // Hash Test Vectors +#+feature dynamic-literals package test_core_hash XXHASH_Test_Vectors :: struct #packed { diff --git a/tests/core/image/test_core_image.odin b/tests/core/image/test_core_image.odin index 899596229..8f6091481 100644 --- a/tests/core/image/test_core_image.odin +++ b/tests/core/image/test_core_image.odin @@ -7,6 +7,7 @@ A test suite for PNG, TGA, NetPBM, QOI and BMP. */ +#+feature dynamic-literals package test_core_image import "core:testing" diff --git a/tests/core/net/test_core_net.odin b/tests/core/net/test_core_net.odin index bc3ff5c46..0d57bd94a 100644 --- a/tests/core/net/test_core_net.odin +++ b/tests/core/net/test_core_net.odin @@ -12,6 +12,7 @@ */ #+build !netbsd #+build !openbsd +#+feature dynamic-literals package test_core_net import "core:testing" diff --git a/tests/core/runtime/test_core_runtime.odin b/tests/core/runtime/test_core_runtime.odin index 84fd044cf..be6c24c72 100644 --- a/tests/core/runtime/test_core_runtime.odin +++ b/tests/core/runtime/test_core_runtime.odin @@ -1,3 +1,4 @@ +#+feature dynamic-literals package test_core_runtime import "base:intrinsics" @@ -63,4 +64,101 @@ test_init_cap_map_dynarray :: proc(t: ^testing.T) { defer delete(d2) testing.expect(t, cap(d2) == 0) testing.expect(t, d2.allocator.procedure == ally.procedure) -}
\ No newline at end of file +} + +@(test) +test_map_get :: proc(t: ^testing.T) { + check :: proc(t: ^testing.T, m: map[$K]$V, loc := #caller_location) { + for k, v in m { + got_key, got_val, ok := runtime.map_get(m, k) + testing.expect_value(t, got_key, k, loc = loc) + testing.expect_value(t, got_val, v, loc = loc) + testing.expect(t, ok, loc = loc) + } + } + + // small keys & values + { + m := map[int]int{ + 1 = 10, + 2 = 20, + 3 = 30, + } + defer delete(m) + check(t, m) + } + + // small keys; 2 values per cell + { + m := map[int][3]int{ + 1 = [3]int{10, 100, 1000}, + 2 = [3]int{20, 200, 2000}, + 3 = [3]int{30, 300, 3000}, + } + defer delete(m) + check(t, m) + } + + // 2 keys per cell; small values + { + m := map[[3]int]int{ + [3]int{10, 100, 1000} = 1, + [3]int{20, 200, 2000} = 2, + [3]int{30, 300, 3000} = 3, + } + defer delete(m) + check(t, m) + } + + + // small keys; 3 values per cell + { + val :: struct #packed { + a, b: int, + c: i32, + } + m := map[int]val{ + 1 = val{10, 100, 1000}, + 2 = val{20, 200, 2000}, + 3 = val{30, 300, 3000}, + } + defer delete(m) + check(t, m) + } + + // 3 keys per cell; small values + { + key :: struct #packed { + a, b: int, + c: i32, + } + m := map[key]int{ + key{10, 100, 1000} = 1, + key{20, 200, 2000} = 2, + key{30, 300, 3000} = 3, + } + defer delete(m) + check(t, m) + } + + // small keys; value bigger than a chacheline + { + m := map[int][9]int{ + 1 = [9]int{10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000}, + 2 = [9]int{20, 200, 2000, 20000, 200000, 2000000, 20000000, 200000000, 2000000000}, + 3 = [9]int{30, 300, 3000, 30000, 300000, 3000000, 30000000, 300000000, 3000000000}, + } + defer delete(m) + check(t, m) + } + // keys bigger than a chacheline; small values + { + m := map[[9]int]int{ + [9]int{10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000} = 1, + [9]int{20, 200, 2000, 20000, 200000, 2000000, 20000000, 200000000, 2000000000} = 2, + [9]int{30, 300, 3000, 30000, 300000, 3000000, 30000000, 300000000, 3000000000} = 3, + } + defer delete(m) + check(t, m) + } +} diff --git a/tests/core/slice/test_core_slice.odin b/tests/core/slice/test_core_slice.odin index 9c77f872d..98cb8dbac 100644 --- a/tests/core/slice/test_core_slice.odin +++ b/tests/core/slice/test_core_slice.odin @@ -1,3 +1,4 @@ +#+feature dynamic-literals package test_core_slice import "core:slice" diff --git a/tests/issues/run.bat b/tests/issues/run.bat index dcea3d483..7ed43205d 100644 --- a/tests/issues/run.bat +++ b/tests/issues/run.bat @@ -16,6 +16,7 @@ set COMMON=-define:ODIN_TEST_FANCY=false -file -vet -strict-style ..\..\..\odin test ..\test_issue_2637.odin %COMMON% || exit /b ..\..\..\odin test ..\test_issue_2666.odin %COMMON% || exit /b ..\..\..\odin test ..\test_issue_4210.odin %COMMON% || exit /b +..\..\..\odin test ..\test_issue_4584.odin %COMMON% || exit /b @echo off diff --git a/tests/issues/run.sh b/tests/issues/run.sh index c3bc00e24..54543980e 100755 --- a/tests/issues/run.sh +++ b/tests/issues/run.sh @@ -17,6 +17,7 @@ $ODIN test ../test_issue_2615.odin $COMMON $ODIN test ../test_issue_2637.odin $COMMON $ODIN test ../test_issue_2666.odin $COMMON $ODIN test ../test_issue_4210.odin $COMMON +$ODIN test ../test_issue_4584.odin $COMMON if [[ $($ODIN build ../test_issue_2395.odin $COMMON 2>&1 >/dev/null | grep -c "Error:") -eq 2 ]] ; then echo "SUCCESSFUL 1/1" else diff --git a/tests/issues/test_issue_4584.odin b/tests/issues/test_issue_4584.odin new file mode 100644 index 000000000..9eea23420 --- /dev/null +++ b/tests/issues/test_issue_4584.odin @@ -0,0 +1,198 @@ +// Tests issue #4584 https://github.com/odin-lang/Odin/issues/4584 +package test_issues + +import "core:testing" +import "core:log" +import "core:math/linalg" +import glm "core:math/linalg/glsl" +import hlm "core:math/linalg/hlsl" + +@test +test_adjugate_2x2 :: proc(t: ^testing.T) { + I := linalg.identity(matrix[2,2]int) + m := matrix[2,2]int { + -3, 2, + -1, 0, + } + expected := matrix[2,2]int { + 0, -2, + 1, -3, + } + testing.expect_value(t, linalg.adjugate(m), expected) + testing.expect_value(t, linalg.determinant(m), 2) + testing.expect_value(t, linalg.adjugate(m) * m, 2 * I) + testing.expect_value(t, m * linalg.adjugate(m), 2 * I) + + testing.expect_value(t, glm.adjugate(m), expected) + testing.expect_value(t, glm.determinant(m), 2) + testing.expect_value(t, glm.adjugate(m) * m, 2 * I) + testing.expect_value(t, m * glm.adjugate(m), 2 * I) + + testing.expect_value(t, hlm.adjugate(m), expected) + testing.expect_value(t, hlm.determinant(m), 2) + testing.expect_value(t, hlm.adjugate(m) * m, 2 * I) + testing.expect_value(t, m * hlm.adjugate(m), 2 * I) +} + +@test +test_adjugate_3x3 :: proc(t: ^testing.T) { + I := linalg.identity(matrix[3,3]int) + m := matrix[3,3]int { + -3, 2, -5, + -1, 0, -2, + 3, -4, 1, + } + expected := matrix[3,3]int { + -8, 18, -4, + -5, 12, -1, + 4, -6, 2, + } + testing.expect_value(t, linalg.adjugate(m), expected) + testing.expect_value(t, linalg.determinant(m), -6) + testing.expect_value(t, linalg.adjugate(m) * m, -6 * I) + testing.expect_value(t, m * linalg.adjugate(m), -6 * I) + + testing.expect_value(t, glm.adjugate(m), expected) + testing.expect_value(t, glm.determinant(m), -6) + testing.expect_value(t, glm.adjugate(m) * m, -6 * I) + testing.expect_value(t, m * glm.adjugate(m), -6 * I) + + testing.expect_value(t, hlm.adjugate(m), expected) + testing.expect_value(t, hlm.determinant(m), -6) + testing.expect_value(t, hlm.adjugate(m) * m, -6 * I) + testing.expect_value(t, m * hlm.adjugate(m), -6 * I) +} + +@test +test_adjugate_4x4 :: proc(t: ^testing.T) { + I := linalg.identity(matrix[4,4]int) + m := matrix[4,4]int { + -3, 2, -5, 1, + -1, 0, -2, 2, + 3, -4, 1, 3, + 4, 5, 6, 7, + } + expected := matrix[4,4]int { + -144, 266, -92, -16, + -57, 92, -5, -16, + 105, -142, 55, 2, + 33, -96, 9, -6, + } + testing.expect_value(t, linalg.adjugate(m), expected) + testing.expect_value(t, linalg.determinant(m), -174) + testing.expect_value(t, linalg.adjugate(m) * m, -174 * I) + testing.expect_value(t, m * linalg.adjugate(m), -174 * I) + + testing.expect_value(t, glm.adjugate(m), expected) + testing.expect_value(t, glm.determinant(m), -174) + testing.expect_value(t, glm.adjugate(m) * m, -174 * I) + testing.expect_value(t, m * glm.adjugate(m), -174 * I) + + testing.expect_value(t, hlm.adjugate(m), expected) + testing.expect_value(t, hlm.determinant(m), -174) + testing.expect_value(t, hlm.adjugate(m) * m, -174 * I) + testing.expect_value(t, m * hlm.adjugate(m), -174 * I) +} + +@test +test_inverse_regression_2x2 :: proc(t: ^testing.T) { + I := linalg.identity(matrix[2,2]f32) + m := matrix[2,2]f32 { + -3, 2, + -1, 0, + } + expected := matrix[2,2]f32 { + 0.0, -1.0, + 1.0/2.0, -3.0/2.0, + } + expect_float_matrix_value(t, linalg.inverse(m), expected) + expect_float_matrix_value(t, linalg.inverse_transpose(m), linalg.transpose(expected)) + expect_float_matrix_value(t, linalg.inverse(m) * m, I) + expect_float_matrix_value(t, m * linalg.inverse(m), I) + + expect_float_matrix_value(t, glm.inverse(m), expected) + expect_float_matrix_value(t, glm.inverse_transpose(m), glm.transpose(expected)) + expect_float_matrix_value(t, glm.inverse(m) * m, I) + expect_float_matrix_value(t, m * glm.inverse(m), I) + + expect_float_matrix_value(t, hlm.inverse(m), expected) + expect_float_matrix_value(t, hlm.inverse_transpose(m), hlm.transpose(expected)) + expect_float_matrix_value(t, hlm.inverse(m) * m, I) + expect_float_matrix_value(t, m * hlm.inverse(m), I) +} + +@test +test_inverse_regression_3x3 :: proc(t: ^testing.T) { + I := linalg.identity(matrix[3,3]f32) + m := matrix[3,3]f32 { + -3, 2, -5, + -1, 0, -2, + 3, -4, 1, + } + expected := matrix[3,3]f32 { + 4.0/3.0, -3.0, 2.0/3.0, + 5.0/6.0, -2.0, 1.0/6.0, + -2.0/3.0, 1.0, -1.0/3.0, + } + expect_float_matrix_value(t, linalg.inverse(m), expected) + expect_float_matrix_value(t, linalg.inverse_transpose(m), linalg.transpose(expected)) + expect_float_matrix_value(t, linalg.inverse(m) * m, I) + expect_float_matrix_value(t, m * linalg.inverse(m), I) + + expect_float_matrix_value(t, glm.inverse(m), expected) + expect_float_matrix_value(t, glm.inverse_transpose(m), glm.transpose(expected)) + expect_float_matrix_value(t, glm.inverse(m) * m, I) + expect_float_matrix_value(t, m * glm.inverse(m), I) + + expect_float_matrix_value(t, hlm.inverse(m), expected) + expect_float_matrix_value(t, hlm.inverse_transpose(m), hlm.transpose(expected)) + expect_float_matrix_value(t, hlm.inverse(m) * m, I) + expect_float_matrix_value(t, m * hlm.inverse(m), I) +} + +@test +test_inverse_regression_4x4 :: proc(t: ^testing.T) { + I := linalg.identity(matrix[4,4]f32) + m := matrix[4,4]f32 { + -3, 2, -5, 1, + -1, 0, -2, 2, + 3, -4, 1, 3, + 4, 5, 6, 7, + } + expected := matrix[4,4]f32 { + 24.0/29.0, -133.0/87.0, 46.0/87.0, 8.0/87.0, + 19.0/58.0, -46.0/87.0, 5.0/174.0, 8.0/87.0, + -35.0/58.0, 71.0/87.0, -55.0/174.0, -1.0/87.0, + -11.0/58.0, 16.0/29.0, -3.0/58.0, 1.0/29.0, + } + expect_float_matrix_value(t, linalg.inverse(m), expected) + expect_float_matrix_value(t, linalg.inverse_transpose(m), linalg.transpose(expected)) + expect_float_matrix_value(t, linalg.inverse(m) * m, I) + expect_float_matrix_value(t, m * linalg.inverse(m), I) + + expect_float_matrix_value(t, glm.inverse(m), expected) + expect_float_matrix_value(t, glm.inverse_transpose(m), glm.transpose(expected)) + expect_float_matrix_value(t, glm.inverse(m) * m, I) + expect_float_matrix_value(t, m * glm.inverse(m), I) + + expect_float_matrix_value(t, hlm.inverse(m), expected) + expect_float_matrix_value(t, hlm.inverse_transpose(m), hlm.transpose(expected)) + expect_float_matrix_value(t, hlm.inverse(m) * m, I) + expect_float_matrix_value(t, m * hlm.inverse(m), I) +} + +@(private="file") +expect_float_matrix_value :: proc(t: ^testing.T, value, expected: $M/matrix[$N, N]f32, loc := #caller_location, value_expr := #caller_expression(value)) -> bool { + ok := true + outer: for i in 0..<N { + for j in 0..<N { + diff := abs(value[i, j] - expected[i, j]) + if diff > 1e-6 { + ok = false + break outer + } + } + } + if !ok do log.errorf("expected %v to be %v, got %v", value_expr, expected, value, location=loc) + return ok +}
\ No newline at end of file diff --git a/tests/issues/test_issue_829.odin b/tests/issues/test_issue_829.odin index 229d8e9b4..3287c49fe 100644 --- a/tests/issues/test_issue_829.odin +++ b/tests/issues/test_issue_829.odin @@ -1,4 +1,5 @@ // Tests issue #829 https://github.com/odin-lang/Odin/issues/829 +#+feature dynamic-literals package test_issues import "core:testing" diff --git a/vendor/box2d/box2d.odin b/vendor/box2d/box2d.odin index e7da34a45..8abf6ce03 100644 --- a/vendor/box2d/box2d.odin +++ b/vendor/box2d/box2d.odin @@ -24,19 +24,11 @@ when ODIN_OS == .Windows { } when !#exists(LIB_PATH) { - #panic("Could not find the compiled box2d libraries at \"" + LIB_PATH + "\", they can be compiled by running the `build.sh` script at `" + ODIN_ROOT + "vendor/box2d/build_box2d.sh\"`") + #panic("Could not find the compiled box2d libraries at \"" + LIB_PATH + "\", they can be compiled by running the `build_box2d.sh` script at `" + ODIN_ROOT + "vendor/box2d/build_box2d.sh\"`") } -when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 { - when VECTOR_EXT == "_simd" { - foreign import lib "lib/box2d_wasm_simd.o" - } else { - foreign import lib "lib/box2d_wasm.o" - } -} else { - foreign import lib { - LIB_PATH, - } +foreign import lib { + LIB_PATH, } diff --git a/vendor/box2d/build_box2d.sh b/vendor/box2d/build_box2d.sh index 0c5ff999d..74d75eb57 100755 --- a/vendor/box2d/build_box2d.sh +++ b/vendor/box2d/build_box2d.sh @@ -68,7 +68,12 @@ esac cd .. +set +e make -f wasm.Makefile +if [[ $? -ne 0 ]]; then + printf "\e[30;43mwarning:\e[0m Native Box2D libraries were built successfully, the WASM build failed, likely because your default C compiler and/or linker doesn't support WASM, you can set the CC and LD environment variables to point to a compiler and linker that support it\n" +fi +set -e rm -rf v3.0.0.tar.gz rm -rf box2d-3.0.0 diff --git a/vendor/box2d/wasm.Makefile b/vendor/box2d/wasm.Makefile index 929b61aea..e8ecb485e 100644 --- a/vendor/box2d/wasm.Makefile +++ b/vendor/box2d/wasm.Makefile @@ -2,6 +2,8 @@ # I tried to make a cmake toolchain file for this / use cmake but this is far easier. # NOTE: We are pretending to be emscripten to box2d so it takes WASM code paths, but we don't actually use emscripten. +# WARN: wasm is probably not supported by your default C compiler and linker, overwrite the CC and LD environment variables accordingly. +# Example for MacOS: # CC = $(shell brew --prefix llvm)/bin/clang # LD = $(shell brew --prefix llvm)/bin/wasm-ld @@ -10,7 +12,7 @@ SRCS = $(wildcard box2d-$(VERSION)/src/*.c) OBJS_SIMD = $(SRCS:.c=_simd.o) OBJS = $(SRCS:.c=.o) SYSROOT = $(shell odin root)/vendor/libc -CFLAGS = -Ibox2d-$(VERSION)/include -Ibox2d-$(VERSION)/Extern/simde --target=wasm32 -D__EMSCRIPTEN__ -DNDEBUG -O3 --sysroot=$(SYSROOT) +CFLAGS = -Ibox2d-$(VERSION)/include -Ibox2d-$(VERSION)/extern/simde --target=wasm32 -D__EMSCRIPTEN__ -DNDEBUG -O3 --sysroot=$(SYSROOT) all: lib/box2d_wasm.o lib/box2d_wasm_simd.o clean diff --git a/vendor/cgltf/cgltf.odin b/vendor/cgltf/cgltf.odin index a24c36d64..e9dc7ef84 100644 --- a/vendor/cgltf/cgltf.odin +++ b/vendor/cgltf/cgltf.odin @@ -105,6 +105,7 @@ type :: enum c.int { } primitive_type :: enum c.int { + invalid, points, lines, line_loop, @@ -222,15 +223,6 @@ accessor_sparse :: struct { indices_component_type: component_type, values_buffer_view: ^buffer_view, values_byte_offset: uint, - extras: extras_t, - indices_extras: extras_t, - values_extras: extras_t, - extensions_count: uint, - extensions: [^]extension `fmt:"v,extensions_count"`, - indices_extensions_count: uint, - indices_extensions: [^]extension `fmt:"v,indices_extensions_count"`, - values_extensions_count: uint, - values_extensions: [^]extension `fmt:"v,values_extensions_count"`, } accessor :: struct { @@ -306,9 +298,6 @@ texture_view :: struct { scale: f32, /* equivalent to strength for occlusion_texture */ has_transform: b32, transform: texture_transform, - extras: extras_t, - extensions_count: uint, - extensions: [^]extension `fmt:"v,extensions_count"`, } pbr_metallic_roughness :: struct { @@ -381,6 +370,16 @@ iridescence :: struct { iridescence_thickness_texture: texture_view, } +anisotropy :: struct { + anisotropy_strength: f32, + anisotropy_rotation: f32, + anisotropy_texture: texture_view, +} + +dispersion :: struct { + dispersion: f32, +} + material :: struct { name: cstring, has_pbr_metallic_roughness: b32, @@ -393,6 +392,8 @@ material :: struct { has_sheen: b32, has_emissive_strength: b32, has_iridescence: b32, + has_anisotropy: b32, + has_dispersion: b32, pbr_metallic_roughness: pbr_metallic_roughness, pbr_specular_glossiness: pbr_specular_glossiness, clearcoat: clearcoat, @@ -403,6 +404,8 @@ material :: struct { volume: volume, emissive_strength: emissive_strength, iridescence: iridescence, + anisotropy: anisotropy, + dispersion: dispersion, normal_texture: texture_view, occlusion_texture: texture_view, emissive_texture: texture_view, @@ -432,7 +435,6 @@ draco_mesh_compression :: struct { } mesh_gpu_instancing :: struct { - buffer_view: ^buffer_view, attributes: []attribute, } @@ -684,6 +686,9 @@ foreign lib { node_transform_world :: proc(node: ^node, out_matrix: [^]f32) --- @(require_results) + buffer_view_data :: proc(view: ^/*const*/buffer_view) -> [^]byte --- + + @(require_results) accessor_read_float :: proc(accessor: ^/*const*/accessor, index: uint, out: [^]f32, element_size: uint) -> b32 --- @(require_results) accessor_read_uint :: proc(accessor: ^/*const*/accessor, index: uint, out: [^]c.uint, element_size: uint) -> b32 --- @@ -694,13 +699,53 @@ foreign lib { num_components :: proc(type: type) -> uint --- @(require_results) + component_size :: proc(component_type: component_type) -> uint --- + @(require_results) + calc_size :: proc(type: type, component_type: component_type) -> uint --- + + @(require_results) accessor_unpack_floats :: proc(accessor: ^/*const*/accessor, out: [^]f32, float_count: uint) -> uint --- + @(require_results) + accessor_unpack_indices :: proc(accessor: ^/*const*/accessor , out: rawptr, out_component_size: uint, index_count: uint) -> uint --- /* this function is deprecated and will be removed in the future; use cgltf_extras::data instead */ @(require_results) copy_extras_json :: proc(data: ^data, extras: ^extras_t, dest: [^]byte, dest_size: ^uint) -> result --- @(require_results) + mesh_index :: proc(data: ^/*const*/data, object: ^/*const*/mesh) -> uint --- + @(require_results) + material_index :: proc(data: ^/*const*/data, object: ^/*const*/material) -> uint --- + @(require_results) + accessor_index :: proc(data: ^/*const*/data, object: ^/*const*/accessor) -> uint --- + @(require_results) + buffer_view_index :: proc(data: ^/*const*/data, object: ^/*const*/buffer_view) -> uint --- + @(require_results) + buffer_index :: proc(data: ^/*const*/data, object: ^/*const*/buffer) -> uint --- + @(require_results) + image_index :: proc(data: ^/*const*/data, object: ^/*const*/image) -> uint --- + @(require_results) + texture_index :: proc(data: ^/*const*/data, object: ^/*const*/texture) -> uint --- + @(require_results) + sampler_index :: proc(data: ^/*const*/data, object: ^/*const*/sampler) -> uint --- + @(require_results) + skin_index :: proc(data: ^/*const*/data, object: ^/*const*/skin) -> uint --- + @(require_results) + camera_index :: proc(data: ^/*const*/data, object: ^/*const*/camera) -> uint --- + @(require_results) + light_index :: proc(data: ^/*const*/data, object: ^/*const*/light) -> uint --- + @(require_results) + node_index :: proc(data: ^/*const*/data, object: ^/*const*/node) -> uint --- + @(require_results) + scene_index :: proc(data: ^/*const*/data, object: ^/*const*/scene) -> uint --- + @(require_results) + animation_index :: proc(data: ^/*const*/data, object: ^/*const*/animation) -> uint --- + @(require_results) + animation_sampler_index :: proc(animation: ^/*const*/animation, object: ^/*const*/animation_sampler) -> uint --- + @(require_results) + animation_channel_index :: proc(animation: ^/*const*/animation, object: ^/*const*/animation_channel) -> uint --- + + @(require_results) write_file :: proc(#by_ptr options: options, path: cstring, data: ^data) -> result --- @(require_results) write :: proc(#by_ptr options: options, buffer: [^]byte, size: uint, data: ^data) -> uint --- diff --git a/vendor/cgltf/lib/cgltf.lib b/vendor/cgltf/lib/cgltf.lib Binary files differindex 0d7ea6f9b..b14f79142 100644 --- a/vendor/cgltf/lib/cgltf.lib +++ b/vendor/cgltf/lib/cgltf.lib diff --git a/vendor/cgltf/lib/cgltf_wasm.o b/vendor/cgltf/lib/cgltf_wasm.o Binary files differindex 54346d176..077d480a8 100644 --- a/vendor/cgltf/lib/cgltf_wasm.o +++ b/vendor/cgltf/lib/cgltf_wasm.o diff --git a/vendor/cgltf/src/cgltf.h b/vendor/cgltf/src/cgltf.h index a534cefb4..17dc0ca5d 100644 --- a/vendor/cgltf/src/cgltf.h +++ b/vendor/cgltf/src/cgltf.h @@ -1,7 +1,7 @@ /** * cgltf - a single-file glTF 2.0 parser written in C99. * - * Version: 1.13 + * Version: 1.14 * * Website: https://github.com/jkuhlmann/cgltf * @@ -63,9 +63,15 @@ * By passing null for the output pointer, users can find out how many floats are required in the * output buffer. * + * `cgltf_accessor_unpack_indices` reads in the index data from an accessor. Assumes that + * `cgltf_load_buffers` has already been called. By passing null for the output pointer, users can + * find out how many indices are required in the output buffer. Returns 0 if the accessor is + * sparse or if the output component size is less than the accessor's component size. + * * `cgltf_num_components` is a tiny utility that tells you the dimensionality of * a certain accessor type. This can be used before `cgltf_accessor_unpack_floats` to help allocate - * the necessary amount of memory. + * the necessary amount of memory. `cgltf_component_size` and `cgltf_calc_size` exist for + * similar purposes. * * `cgltf_accessor_read_float` reads a certain element from a non-sparse accessor and converts it to * floating point, assuming that `cgltf_load_buffers` has already been called. The passed-in element @@ -74,7 +80,7 @@ * * `cgltf_accessor_read_uint` is similar to its floating-point counterpart, but limited to reading * vector types and does not support matrix types. The passed-in element size is the number of uints - * in the output buffer, which should be in the range [1, 4]. Returns false if the passed-in + * in the output buffer, which should be in the range [1, 4]. Returns false if the passed-in * element_size is too small, or if the accessor is sparse. * * `cgltf_accessor_read_index` is similar to its floating-point counterpart, but it returns size_t @@ -89,6 +95,7 @@ #define CGLTF_H_INCLUDED__ #include <stddef.h> +#include <stdint.h> /* For uint8_t, uint32_t */ #ifdef __cplusplus extern "C" { @@ -195,6 +202,7 @@ typedef enum cgltf_type typedef enum cgltf_primitive_type { + cgltf_primitive_type_invalid, cgltf_primitive_type_points, cgltf_primitive_type_lines, cgltf_primitive_type_line_loop, @@ -326,15 +334,6 @@ typedef struct cgltf_accessor_sparse cgltf_component_type indices_component_type; cgltf_buffer_view* values_buffer_view; cgltf_size values_byte_offset; - cgltf_extras extras; - cgltf_extras indices_extras; - cgltf_extras values_extras; - cgltf_size extensions_count; - cgltf_extension* extensions; - cgltf_size indices_extensions_count; - cgltf_extension* indices_extensions; - cgltf_size values_extensions_count; - cgltf_extension* values_extensions; } cgltf_accessor_sparse; typedef struct cgltf_accessor @@ -417,9 +416,6 @@ typedef struct cgltf_texture_view cgltf_float scale; /* equivalent to strength for occlusion_texture */ cgltf_bool has_transform; cgltf_texture_transform transform; - cgltf_extras extras; - cgltf_size extensions_count; - cgltf_extension* extensions; } cgltf_texture_view; typedef struct cgltf_pbr_metallic_roughness @@ -502,6 +498,18 @@ typedef struct cgltf_iridescence cgltf_texture_view iridescence_thickness_texture; } cgltf_iridescence; +typedef struct cgltf_anisotropy +{ + cgltf_float anisotropy_strength; + cgltf_float anisotropy_rotation; + cgltf_texture_view anisotropy_texture; +} cgltf_anisotropy; + +typedef struct cgltf_dispersion +{ + cgltf_float dispersion; +} cgltf_dispersion; + typedef struct cgltf_material { char* name; @@ -515,6 +523,8 @@ typedef struct cgltf_material cgltf_bool has_sheen; cgltf_bool has_emissive_strength; cgltf_bool has_iridescence; + cgltf_bool has_anisotropy; + cgltf_bool has_dispersion; cgltf_pbr_metallic_roughness pbr_metallic_roughness; cgltf_pbr_specular_glossiness pbr_specular_glossiness; cgltf_clearcoat clearcoat; @@ -525,6 +535,8 @@ typedef struct cgltf_material cgltf_volume volume; cgltf_emissive_strength emissive_strength; cgltf_iridescence iridescence; + cgltf_anisotropy anisotropy; + cgltf_dispersion dispersion; cgltf_texture_view normal_texture; cgltf_texture_view occlusion_texture; cgltf_texture_view emissive_texture; @@ -557,7 +569,6 @@ typedef struct cgltf_draco_mesh_compression { } cgltf_draco_mesh_compression; typedef struct cgltf_mesh_gpu_instancing { - cgltf_buffer_view* buffer_view; cgltf_attribute* attributes; cgltf_size attributes_count; } cgltf_mesh_gpu_instancing; @@ -829,17 +840,39 @@ void cgltf_free(cgltf_data* data); void cgltf_node_transform_local(const cgltf_node* node, cgltf_float* out_matrix); void cgltf_node_transform_world(const cgltf_node* node, cgltf_float* out_matrix); +const uint8_t* cgltf_buffer_view_data(const cgltf_buffer_view* view); + cgltf_bool cgltf_accessor_read_float(const cgltf_accessor* accessor, cgltf_size index, cgltf_float* out, cgltf_size element_size); cgltf_bool cgltf_accessor_read_uint(const cgltf_accessor* accessor, cgltf_size index, cgltf_uint* out, cgltf_size element_size); cgltf_size cgltf_accessor_read_index(const cgltf_accessor* accessor, cgltf_size index); cgltf_size cgltf_num_components(cgltf_type type); +cgltf_size cgltf_component_size(cgltf_component_type component_type); +cgltf_size cgltf_calc_size(cgltf_type type, cgltf_component_type component_type); cgltf_size cgltf_accessor_unpack_floats(const cgltf_accessor* accessor, cgltf_float* out, cgltf_size float_count); +cgltf_size cgltf_accessor_unpack_indices(const cgltf_accessor* accessor, void* out, cgltf_size out_component_size, cgltf_size index_count); /* this function is deprecated and will be removed in the future; use cgltf_extras::data instead */ cgltf_result cgltf_copy_extras_json(const cgltf_data* data, const cgltf_extras* extras, char* dest, cgltf_size* dest_size); +cgltf_size cgltf_mesh_index(const cgltf_data* data, const cgltf_mesh* object); +cgltf_size cgltf_material_index(const cgltf_data* data, const cgltf_material* object); +cgltf_size cgltf_accessor_index(const cgltf_data* data, const cgltf_accessor* object); +cgltf_size cgltf_buffer_view_index(const cgltf_data* data, const cgltf_buffer_view* object); +cgltf_size cgltf_buffer_index(const cgltf_data* data, const cgltf_buffer* object); +cgltf_size cgltf_image_index(const cgltf_data* data, const cgltf_image* object); +cgltf_size cgltf_texture_index(const cgltf_data* data, const cgltf_texture* object); +cgltf_size cgltf_sampler_index(const cgltf_data* data, const cgltf_sampler* object); +cgltf_size cgltf_skin_index(const cgltf_data* data, const cgltf_skin* object); +cgltf_size cgltf_camera_index(const cgltf_data* data, const cgltf_camera* object); +cgltf_size cgltf_light_index(const cgltf_data* data, const cgltf_light* object); +cgltf_size cgltf_node_index(const cgltf_data* data, const cgltf_node* object); +cgltf_size cgltf_scene_index(const cgltf_data* data, const cgltf_scene* object); +cgltf_size cgltf_animation_index(const cgltf_data* data, const cgltf_animation* object); +cgltf_size cgltf_animation_sampler_index(const cgltf_animation* animation, const cgltf_animation_sampler* object); +cgltf_size cgltf_animation_channel_index(const cgltf_animation* animation, const cgltf_animation_channel* object); + #ifdef __cplusplus } #endif @@ -860,7 +893,7 @@ cgltf_result cgltf_copy_extras_json(const cgltf_data* data, const cgltf_extras* #ifdef CGLTF_IMPLEMENTATION -#include <stdint.h> /* For uint8_t, uint32_t */ +#include <assert.h> /* For assert */ #include <string.h> /* For strncpy */ #include <stdio.h> /* For fopen */ #include <limits.h> /* For UINT_MAX etc */ @@ -870,10 +903,6 @@ cgltf_result cgltf_copy_extras_json(const cgltf_data* data, const cgltf_extras* #include <stdlib.h> /* For malloc, free, atoi, atof */ #endif -#if CGLTF_VALIDATE_ENABLE_ASSERTS -#include <assert.h> -#endif - /* JSMN_PARENT_LINKS is necessary to make parsing large structures linear in input size */ #define JSMN_PARENT_LINKS @@ -902,15 +931,15 @@ enum jsmnerr { }; typedef struct { jsmntype_t type; - int start; - int end; + ptrdiff_t start; + ptrdiff_t end; int size; #ifdef JSMN_PARENT_LINKS int parent; #endif } jsmntok_t; typedef struct { - unsigned int pos; /* offset in the JSON string */ + size_t pos; /* offset in the JSON string */ unsigned int toknext; /* next token to allocate */ int toksuper; /* superior token node, e.g parent object or array */ } jsmn_parser; @@ -922,8 +951,8 @@ static int jsmn_parse(jsmn_parser *parser, const char *js, size_t len, jsmntok_t #ifndef CGLTF_CONSTS -static const cgltf_size GlbHeaderSize = 12; -static const cgltf_size GlbChunkHeaderSize = 8; +#define GlbHeaderSize 12 +#define GlbChunkHeaderSize 8 static const uint32_t GlbVersion = 2; static const uint32_t GlbMagic = 0x46546C67; static const uint32_t GlbMagicJsonChunk = 0x4E4F534A; @@ -995,7 +1024,7 @@ static cgltf_result cgltf_default_file_read(const struct cgltf_memory_options* m { fseek(file, 0, SEEK_END); -#ifdef _WIN32 +#ifdef _MSC_VER __int64 length = _ftelli64(file); #else long length = ftell(file); @@ -1017,7 +1046,7 @@ static cgltf_result cgltf_default_file_read(const struct cgltf_memory_options* m fclose(file); return cgltf_result_out_of_memory; } - + cgltf_size read_size = fread(file_data, 1, file_size, file); fclose(file); @@ -1125,7 +1154,7 @@ cgltf_result cgltf_parse(const cgltf_options* options, const void* data, cgltf_s // JSON chunk: length uint32_t json_length; memcpy(&json_length, json_chunk, 4); - if (GlbHeaderSize + GlbChunkHeaderSize + json_length > size) + if (json_length > size - GlbHeaderSize - GlbChunkHeaderSize) { return cgltf_result_data_too_short; } @@ -1139,10 +1168,10 @@ cgltf_result cgltf_parse(const cgltf_options* options, const void* data, cgltf_s json_chunk += GlbChunkHeaderSize; - const void* bin = 0; + const void* bin = NULL; cgltf_size bin_size = 0; - if (GlbHeaderSize + GlbChunkHeaderSize + json_length + GlbChunkHeaderSize <= size) + if (GlbChunkHeaderSize <= size - GlbHeaderSize - GlbChunkHeaderSize - json_length) { // We can read another chunk const uint8_t* bin_chunk = json_chunk + json_length; @@ -1150,7 +1179,7 @@ cgltf_result cgltf_parse(const cgltf_options* options, const void* data, cgltf_s // Bin chunk: length uint32_t bin_length; memcpy(&bin_length, bin_chunk, 4); - if (GlbHeaderSize + GlbChunkHeaderSize + json_length + GlbChunkHeaderSize + bin_length > size) + if (bin_length > size - GlbHeaderSize - GlbChunkHeaderSize - json_length - GlbChunkHeaderSize) { return cgltf_result_data_too_short; } @@ -1486,8 +1515,6 @@ cgltf_result cgltf_load_buffers(const cgltf_options* options, cgltf_data* data, return cgltf_result_success; } -static cgltf_size cgltf_calc_size(cgltf_type type, cgltf_component_type component_type); - static cgltf_size cgltf_calc_index_bound(cgltf_buffer_view* buffer_view, cgltf_size offset, cgltf_component_type component_type, cgltf_size count) { char* data = (char*)buffer_view->buffer->data + offset + buffer_view->offset; @@ -1538,6 +1565,9 @@ cgltf_result cgltf_validate(cgltf_data* data) { cgltf_accessor* accessor = &data->accessors[i]; + CGLTF_ASSERT_IF(data->accessors[i].component_type == cgltf_component_type_invalid, cgltf_result_invalid_gltf); + CGLTF_ASSERT_IF(data->accessors[i].type == cgltf_type_invalid, cgltf_result_invalid_gltf); + cgltf_size element_size = cgltf_calc_size(accessor->type, accessor->component_type); if (accessor->buffer_view) @@ -1551,7 +1581,7 @@ cgltf_result cgltf_validate(cgltf_data* data) { cgltf_accessor_sparse* sparse = &accessor->sparse; - cgltf_size indices_component_size = cgltf_calc_size(cgltf_type_scalar, sparse->indices_component_type); + cgltf_size indices_component_size = cgltf_component_size(sparse->indices_component_type); cgltf_size indices_req_size = sparse->indices_byte_offset + indices_component_size * sparse->count; cgltf_size values_req_size = sparse->values_byte_offset + element_size * sparse->count; @@ -1617,43 +1647,48 @@ cgltf_result cgltf_validate(cgltf_data* data) for (cgltf_size j = 0; j < data->meshes[i].primitives_count; ++j) { + CGLTF_ASSERT_IF(data->meshes[i].primitives[j].type == cgltf_primitive_type_invalid, cgltf_result_invalid_gltf); CGLTF_ASSERT_IF(data->meshes[i].primitives[j].targets_count != data->meshes[i].primitives[0].targets_count, cgltf_result_invalid_gltf); - if (data->meshes[i].primitives[j].attributes_count) + CGLTF_ASSERT_IF(data->meshes[i].primitives[j].attributes_count == 0, cgltf_result_invalid_gltf); + + cgltf_accessor* first = data->meshes[i].primitives[j].attributes[0].data; + + CGLTF_ASSERT_IF(first->count == 0, cgltf_result_invalid_gltf); + + for (cgltf_size k = 0; k < data->meshes[i].primitives[j].attributes_count; ++k) { - cgltf_accessor* first = data->meshes[i].primitives[j].attributes[0].data; + CGLTF_ASSERT_IF(data->meshes[i].primitives[j].attributes[k].data->count != first->count, cgltf_result_invalid_gltf); + } - for (cgltf_size k = 0; k < data->meshes[i].primitives[j].attributes_count; ++k) + for (cgltf_size k = 0; k < data->meshes[i].primitives[j].targets_count; ++k) + { + for (cgltf_size m = 0; m < data->meshes[i].primitives[j].targets[k].attributes_count; ++m) { - CGLTF_ASSERT_IF(data->meshes[i].primitives[j].attributes[k].data->count != first->count, cgltf_result_invalid_gltf); + CGLTF_ASSERT_IF(data->meshes[i].primitives[j].targets[k].attributes[m].data->count != first->count, cgltf_result_invalid_gltf); } + } - for (cgltf_size k = 0; k < data->meshes[i].primitives[j].targets_count; ++k) - { - for (cgltf_size m = 0; m < data->meshes[i].primitives[j].targets[k].attributes_count; ++m) - { - CGLTF_ASSERT_IF(data->meshes[i].primitives[j].targets[k].attributes[m].data->count != first->count, cgltf_result_invalid_gltf); - } - } + cgltf_accessor* indices = data->meshes[i].primitives[j].indices; - cgltf_accessor* indices = data->meshes[i].primitives[j].indices; + CGLTF_ASSERT_IF(indices && + indices->component_type != cgltf_component_type_r_8u && + indices->component_type != cgltf_component_type_r_16u && + indices->component_type != cgltf_component_type_r_32u, cgltf_result_invalid_gltf); - CGLTF_ASSERT_IF(indices && - indices->component_type != cgltf_component_type_r_8u && - indices->component_type != cgltf_component_type_r_16u && - indices->component_type != cgltf_component_type_r_32u, cgltf_result_invalid_gltf); + CGLTF_ASSERT_IF(indices && indices->type != cgltf_type_scalar, cgltf_result_invalid_gltf); + CGLTF_ASSERT_IF(indices && indices->stride != cgltf_component_size(indices->component_type), cgltf_result_invalid_gltf); - if (indices && indices->buffer_view && indices->buffer_view->buffer->data) - { - cgltf_size index_bound = cgltf_calc_index_bound(indices->buffer_view, indices->offset, indices->component_type, indices->count); + if (indices && indices->buffer_view && indices->buffer_view->buffer->data) + { + cgltf_size index_bound = cgltf_calc_index_bound(indices->buffer_view, indices->offset, indices->component_type, indices->count); - CGLTF_ASSERT_IF(index_bound >= first->count, cgltf_result_data_too_short); - } + CGLTF_ASSERT_IF(index_bound >= first->count, cgltf_result_data_too_short); + } - for (cgltf_size k = 0; k < data->meshes[i].primitives[j].mappings_count; ++k) - { - CGLTF_ASSERT_IF(data->meshes[i].primitives[j].mappings[k].variant >= data->variants_count, cgltf_result_invalid_gltf); - } + for (cgltf_size k = 0; k < data->meshes[i].primitives[j].mappings_count; ++k) + { + CGLTF_ASSERT_IF(data->meshes[i].primitives[j].mappings[k].variant >= data->variants_count, cgltf_result_invalid_gltf); } } } @@ -1710,10 +1745,15 @@ cgltf_result cgltf_validate(cgltf_data* data) cgltf_size values = channel->sampler->interpolation == cgltf_interpolation_type_cubic_spline ? 3 : 1; - CGLTF_ASSERT_IF(channel->sampler->input->count * components * values != channel->sampler->output->count, cgltf_result_data_too_short); + CGLTF_ASSERT_IF(channel->sampler->input->count * components * values != channel->sampler->output->count, cgltf_result_invalid_gltf); } } + for (cgltf_size i = 0; i < data->variants_count; ++i) + { + CGLTF_ASSERT_IF(!data->variants[i].name, cgltf_result_invalid_gltf); + } + return cgltf_result_success; } @@ -1760,12 +1800,6 @@ static void cgltf_free_extensions(cgltf_data* data, cgltf_extension* extensions, data->memory.free_func(data->memory.user_data, extensions); } -static void cgltf_free_texture_view(cgltf_data* data, cgltf_texture_view* view) -{ - cgltf_free_extensions(data, view->extensions, view->extensions_count); - cgltf_free_extras(data, &view->extras); -} - void cgltf_free(cgltf_data* data) { if (!data) @@ -1787,15 +1821,6 @@ void cgltf_free(cgltf_data* data) { data->memory.free_func(data->memory.user_data, data->accessors[i].name); - if(data->accessors[i].is_sparse) - { - cgltf_free_extensions(data, data->accessors[i].sparse.extensions, data->accessors[i].sparse.extensions_count); - cgltf_free_extensions(data, data->accessors[i].sparse.indices_extensions, data->accessors[i].sparse.indices_extensions_count); - cgltf_free_extensions(data, data->accessors[i].sparse.values_extensions, data->accessors[i].sparse.values_extensions_count); - cgltf_free_extras(data, &data->accessors[i].sparse.extras); - cgltf_free_extras(data, &data->accessors[i].sparse.indices_extras); - cgltf_free_extras(data, &data->accessors[i].sparse.values_extras); - } cgltf_free_extensions(data, data->accessors[i].extensions, data->accessors[i].extensions_count); cgltf_free_extras(data, &data->accessors[i].extras); } @@ -1897,57 +1922,13 @@ void cgltf_free(cgltf_data* data) { data->memory.free_func(data->memory.user_data, data->materials[i].name); - if(data->materials[i].has_pbr_metallic_roughness) - { - cgltf_free_texture_view(data, &data->materials[i].pbr_metallic_roughness.metallic_roughness_texture); - cgltf_free_texture_view(data, &data->materials[i].pbr_metallic_roughness.base_color_texture); - } - if(data->materials[i].has_pbr_specular_glossiness) - { - cgltf_free_texture_view(data, &data->materials[i].pbr_specular_glossiness.diffuse_texture); - cgltf_free_texture_view(data, &data->materials[i].pbr_specular_glossiness.specular_glossiness_texture); - } - if(data->materials[i].has_clearcoat) - { - cgltf_free_texture_view(data, &data->materials[i].clearcoat.clearcoat_texture); - cgltf_free_texture_view(data, &data->materials[i].clearcoat.clearcoat_roughness_texture); - cgltf_free_texture_view(data, &data->materials[i].clearcoat.clearcoat_normal_texture); - } - if(data->materials[i].has_specular) - { - cgltf_free_texture_view(data, &data->materials[i].specular.specular_texture); - cgltf_free_texture_view(data, &data->materials[i].specular.specular_color_texture); - } - if(data->materials[i].has_transmission) - { - cgltf_free_texture_view(data, &data->materials[i].transmission.transmission_texture); - } - if (data->materials[i].has_volume) - { - cgltf_free_texture_view(data, &data->materials[i].volume.thickness_texture); - } - if(data->materials[i].has_sheen) - { - cgltf_free_texture_view(data, &data->materials[i].sheen.sheen_color_texture); - cgltf_free_texture_view(data, &data->materials[i].sheen.sheen_roughness_texture); - } - if(data->materials[i].has_iridescence) - { - cgltf_free_texture_view(data, &data->materials[i].iridescence.iridescence_texture); - cgltf_free_texture_view(data, &data->materials[i].iridescence.iridescence_thickness_texture); - } - - cgltf_free_texture_view(data, &data->materials[i].normal_texture); - cgltf_free_texture_view(data, &data->materials[i].occlusion_texture); - cgltf_free_texture_view(data, &data->materials[i].emissive_texture); - cgltf_free_extensions(data, data->materials[i].extensions, data->materials[i].extensions_count); cgltf_free_extras(data, &data->materials[i].extras); } data->memory.free_func(data->memory.user_data, data->materials); - for (cgltf_size i = 0; i < data->images_count; ++i) + for (cgltf_size i = 0; i < data->images_count; ++i) { data->memory.free_func(data->memory.user_data, data->images[i].name); data->memory.free_func(data->memory.user_data, data->images[i].uri); @@ -2195,8 +2176,6 @@ static cgltf_ssize cgltf_component_read_integer(const void* in, cgltf_component_ return *((const uint16_t*) in); case cgltf_component_type_r_32u: return *((const uint32_t*) in); - case cgltf_component_type_r_32f: - return (cgltf_ssize)*((const float*) in); case cgltf_component_type_r_8: return *((const int8_t*) in); case cgltf_component_type_r_8u: @@ -2214,8 +2193,6 @@ static cgltf_size cgltf_component_read_index(const void* in, cgltf_component_typ return *((const uint16_t*) in); case cgltf_component_type_r_32u: return *((const uint32_t*) in); - case cgltf_component_type_r_32f: - return (cgltf_size)*((const float*) in); case cgltf_component_type_r_8u: return *((const uint8_t*) in); default: @@ -2251,8 +2228,6 @@ static cgltf_float cgltf_component_read_float(const void* in, cgltf_component_ty return (cgltf_float)cgltf_component_read_integer(in, component_type); } -static cgltf_size cgltf_component_size(cgltf_component_type component_type); - static cgltf_bool cgltf_element_read_float(const uint8_t* element, cgltf_type type, cgltf_component_type component_type, cgltf_bool normalized, cgltf_float* out, cgltf_size element_size) { cgltf_size num_components = cgltf_num_components(type); @@ -2355,21 +2330,41 @@ cgltf_size cgltf_accessor_unpack_floats(const cgltf_accessor* accessor, cgltf_fl cgltf_size element_count = float_count / floats_per_element; // First pass: convert each element in the base accessor. - cgltf_float* dest = out; - cgltf_accessor dense = *accessor; - dense.is_sparse = 0; - for (cgltf_size index = 0; index < element_count; index++, dest += floats_per_element) + if (accessor->buffer_view == NULL) { - if (!cgltf_accessor_read_float(&dense, index, dest, floats_per_element)) + memset(out, 0, element_count * floats_per_element * sizeof(cgltf_float)); + } + else + { + const uint8_t* element = cgltf_buffer_view_data(accessor->buffer_view); + if (element == NULL) { return 0; } + element += accessor->offset; + + if (accessor->component_type == cgltf_component_type_r_32f && accessor->stride == floats_per_element * sizeof(cgltf_float)) + { + memcpy(out, element, element_count * floats_per_element * sizeof(cgltf_float)); + } + else + { + cgltf_float* dest = out; + + for (cgltf_size index = 0; index < element_count; index++, dest += floats_per_element, element += accessor->stride) + { + if (!cgltf_element_read_float(element, accessor->type, accessor->component_type, accessor->normalized, dest, floats_per_element)) + { + return 0; + } + } + } } // Second pass: write out each element in the sparse accessor. if (accessor->is_sparse) { - const cgltf_accessor_sparse* sparse = &dense.sparse; + const cgltf_accessor_sparse* sparse = &accessor->sparse; const uint8_t* index_data = cgltf_buffer_view_data(sparse->indices_buffer_view); const uint8_t* reader_head = cgltf_buffer_view_data(sparse->values_buffer_view); @@ -2383,17 +2378,15 @@ cgltf_size cgltf_accessor_unpack_floats(const cgltf_accessor* accessor, cgltf_fl reader_head += sparse->values_byte_offset; cgltf_size index_stride = cgltf_component_size(sparse->indices_component_type); - for (cgltf_size reader_index = 0; reader_index < sparse->count; reader_index++, index_data += index_stride) + for (cgltf_size reader_index = 0; reader_index < sparse->count; reader_index++, index_data += index_stride, reader_head += accessor->stride) { size_t writer_index = cgltf_component_read_index(index_data, sparse->indices_component_type); float* writer_head = out + writer_index * floats_per_element; - if (!cgltf_element_read_float(reader_head, dense.type, dense.component_type, dense.normalized, writer_head, floats_per_element)) + if (!cgltf_element_read_float(reader_head, accessor->type, accessor->component_type, accessor->normalized, writer_head, floats_per_element)) { return 0; } - - reader_head += dense.stride; } } @@ -2487,12 +2480,165 @@ cgltf_size cgltf_accessor_read_index(const cgltf_accessor* accessor, cgltf_size return cgltf_component_read_index(element, accessor->component_type); } +cgltf_size cgltf_mesh_index(const cgltf_data* data, const cgltf_mesh* object) +{ + assert(object && (cgltf_size)(object - data->meshes) < data->meshes_count); + return (cgltf_size)(object - data->meshes); +} + +cgltf_size cgltf_material_index(const cgltf_data* data, const cgltf_material* object) +{ + assert(object && (cgltf_size)(object - data->materials) < data->materials_count); + return (cgltf_size)(object - data->materials); +} + +cgltf_size cgltf_accessor_index(const cgltf_data* data, const cgltf_accessor* object) +{ + assert(object && (cgltf_size)(object - data->accessors) < data->accessors_count); + return (cgltf_size)(object - data->accessors); +} + +cgltf_size cgltf_buffer_view_index(const cgltf_data* data, const cgltf_buffer_view* object) +{ + assert(object && (cgltf_size)(object - data->buffer_views) < data->buffer_views_count); + return (cgltf_size)(object - data->buffer_views); +} + +cgltf_size cgltf_buffer_index(const cgltf_data* data, const cgltf_buffer* object) +{ + assert(object && (cgltf_size)(object - data->buffers) < data->buffers_count); + return (cgltf_size)(object - data->buffers); +} + +cgltf_size cgltf_image_index(const cgltf_data* data, const cgltf_image* object) +{ + assert(object && (cgltf_size)(object - data->images) < data->images_count); + return (cgltf_size)(object - data->images); +} + +cgltf_size cgltf_texture_index(const cgltf_data* data, const cgltf_texture* object) +{ + assert(object && (cgltf_size)(object - data->textures) < data->textures_count); + return (cgltf_size)(object - data->textures); +} + +cgltf_size cgltf_sampler_index(const cgltf_data* data, const cgltf_sampler* object) +{ + assert(object && (cgltf_size)(object - data->samplers) < data->samplers_count); + return (cgltf_size)(object - data->samplers); +} + +cgltf_size cgltf_skin_index(const cgltf_data* data, const cgltf_skin* object) +{ + assert(object && (cgltf_size)(object - data->skins) < data->skins_count); + return (cgltf_size)(object - data->skins); +} + +cgltf_size cgltf_camera_index(const cgltf_data* data, const cgltf_camera* object) +{ + assert(object && (cgltf_size)(object - data->cameras) < data->cameras_count); + return (cgltf_size)(object - data->cameras); +} + +cgltf_size cgltf_light_index(const cgltf_data* data, const cgltf_light* object) +{ + assert(object && (cgltf_size)(object - data->lights) < data->lights_count); + return (cgltf_size)(object - data->lights); +} + +cgltf_size cgltf_node_index(const cgltf_data* data, const cgltf_node* object) +{ + assert(object && (cgltf_size)(object - data->nodes) < data->nodes_count); + return (cgltf_size)(object - data->nodes); +} + +cgltf_size cgltf_scene_index(const cgltf_data* data, const cgltf_scene* object) +{ + assert(object && (cgltf_size)(object - data->scenes) < data->scenes_count); + return (cgltf_size)(object - data->scenes); +} + +cgltf_size cgltf_animation_index(const cgltf_data* data, const cgltf_animation* object) +{ + assert(object && (cgltf_size)(object - data->animations) < data->animations_count); + return (cgltf_size)(object - data->animations); +} + +cgltf_size cgltf_animation_sampler_index(const cgltf_animation* animation, const cgltf_animation_sampler* object) +{ + assert(object && (cgltf_size)(object - animation->samplers) < animation->samplers_count); + return (cgltf_size)(object - animation->samplers); +} + +cgltf_size cgltf_animation_channel_index(const cgltf_animation* animation, const cgltf_animation_channel* object) +{ + assert(object && (cgltf_size)(object - animation->channels) < animation->channels_count); + return (cgltf_size)(object - animation->channels); +} + +cgltf_size cgltf_accessor_unpack_indices(const cgltf_accessor* accessor, void* out, cgltf_size out_component_size, cgltf_size index_count) +{ + if (out == NULL) + { + return accessor->count; + } + + index_count = accessor->count < index_count ? accessor->count : index_count; + cgltf_size index_component_size = cgltf_component_size(accessor->component_type); + + if (accessor->is_sparse) + { + return 0; + } + if (accessor->buffer_view == NULL) + { + return 0; + } + if (index_component_size > out_component_size) + { + return 0; + } + const uint8_t* element = cgltf_buffer_view_data(accessor->buffer_view); + if (element == NULL) + { + return 0; + } + element += accessor->offset; + + if (index_component_size == out_component_size && accessor->stride == out_component_size) + { + memcpy(out, element, index_count * index_component_size); + return index_count; + } + + // The component size of the output array is larger than the component size of the index data, so index data will be padded. + switch (out_component_size) + { + case 2: + for (cgltf_size index = 0; index < index_count; index++, element += accessor->stride) + { + ((uint16_t*)out)[index] = (uint16_t)cgltf_component_read_index(element, accessor->component_type); + } + break; + case 4: + for (cgltf_size index = 0; index < index_count; index++, element += accessor->stride) + { + ((uint32_t*)out)[index] = (uint32_t)cgltf_component_read_index(element, accessor->component_type); + } + break; + default: + break; + } + + return index_count; +} + #define CGLTF_ERROR_JSON -1 #define CGLTF_ERROR_NOMEM -2 #define CGLTF_ERROR_LEGACY -3 #define CGLTF_CHECK_TOKTYPE(tok_, type_) if ((tok_).type != (type_)) { return CGLTF_ERROR_JSON; } -#define CGLTF_CHECK_TOKTYPE_RETTYPE(tok_, type_, ret_) if ((tok_).type != (type_)) { return (ret_)CGLTF_ERROR_JSON; } +#define CGLTF_CHECK_TOKTYPE_RET(tok_, type_, ret_) if ((tok_).type != (type_)) { return ret_; } #define CGLTF_CHECK_KEY(tok_) if ((tok_).type != JSMN_STRING || (tok_).size == 0) { return CGLTF_ERROR_JSON; } /* checking size for 0 verifies that a value follows the key */ #define CGLTF_PTRINDEX(type, idx) (type*)((cgltf_size)idx + 1) @@ -2503,7 +2649,7 @@ static int cgltf_json_strcmp(jsmntok_t const* tok, const uint8_t* json_chunk, co { CGLTF_CHECK_TOKTYPE(*tok, JSMN_STRING); size_t const str_len = strlen(str); - size_t const name_length = tok->end - tok->start; + size_t const name_length = (size_t)(tok->end - tok->start); return (str_len == name_length) ? strncmp((const char*)json_chunk + tok->start, str, str_len) : 128; } @@ -2511,7 +2657,7 @@ static int cgltf_json_to_int(jsmntok_t const* tok, const uint8_t* json_chunk) { CGLTF_CHECK_TOKTYPE(*tok, JSMN_PRIMITIVE); char tmp[128]; - int size = (cgltf_size)(tok->end - tok->start) < sizeof(tmp) ? tok->end - tok->start : (int)(sizeof(tmp) - 1); + int size = (size_t)(tok->end - tok->start) < sizeof(tmp) ? (int)(tok->end - tok->start) : (int)(sizeof(tmp) - 1); strncpy(tmp, (const char*)json_chunk + tok->start, size); tmp[size] = 0; return CGLTF_ATOI(tmp); @@ -2519,19 +2665,20 @@ static int cgltf_json_to_int(jsmntok_t const* tok, const uint8_t* json_chunk) static cgltf_size cgltf_json_to_size(jsmntok_t const* tok, const uint8_t* json_chunk) { - CGLTF_CHECK_TOKTYPE_RETTYPE(*tok, JSMN_PRIMITIVE, cgltf_size); + CGLTF_CHECK_TOKTYPE_RET(*tok, JSMN_PRIMITIVE, 0); char tmp[128]; - int size = (cgltf_size)(tok->end - tok->start) < sizeof(tmp) ? tok->end - tok->start : (int)(sizeof(tmp) - 1); + int size = (size_t)(tok->end - tok->start) < sizeof(tmp) ? (int)(tok->end - tok->start) : (int)(sizeof(tmp) - 1); strncpy(tmp, (const char*)json_chunk + tok->start, size); tmp[size] = 0; - return (cgltf_size)CGLTF_ATOLL(tmp); + long long res = CGLTF_ATOLL(tmp); + return res < 0 ? 0 : (cgltf_size)res; } static cgltf_float cgltf_json_to_float(jsmntok_t const* tok, const uint8_t* json_chunk) { CGLTF_CHECK_TOKTYPE(*tok, JSMN_PRIMITIVE); char tmp[128]; - int size = (cgltf_size)(tok->end - tok->start) < sizeof(tmp) ? tok->end - tok->start : (int)(sizeof(tmp) - 1); + int size = (size_t)(tok->end - tok->start) < sizeof(tmp) ? (int)(tok->end - tok->start) : (int)(sizeof(tmp) - 1); strncpy(tmp, (const char*)json_chunk + tok->start, size); tmp[size] = 0; return (cgltf_float)CGLTF_ATOF(tmp); @@ -2539,7 +2686,7 @@ static cgltf_float cgltf_json_to_float(jsmntok_t const* tok, const uint8_t* json static cgltf_bool cgltf_json_to_bool(jsmntok_t const* tok, const uint8_t* json_chunk) { - int size = tok->end - tok->start; + int size = (int)(tok->end - tok->start); return size == 4 && memcmp(json_chunk + tok->start, "true", 4) == 0; } @@ -2605,7 +2752,7 @@ static int cgltf_parse_json_string(cgltf_options* options, jsmntok_t const* toke { return CGLTF_ERROR_JSON; } - int size = tokens[i].end - tokens[i].start; + int size = (int)(tokens[i].end - tokens[i].start); char* result = (char*)options->memory.alloc_func(options->memory.user_data, size + 1); if (!result) { @@ -2706,6 +2853,11 @@ static void cgltf_parse_attribute_type(const char* name, cgltf_attribute_type* o if (us && *out_type != cgltf_attribute_type_invalid) { *out_index = CGLTF_ATOI(us + 1); + if (*out_index < 0) + { + *out_type = cgltf_attribute_type_invalid; + *out_index = 0; + } } } @@ -2863,6 +3015,10 @@ static int cgltf_parse_json_draco_mesh_compression(cgltf_options* options, jsmnt out_draco_mesh_compression->buffer_view = CGLTF_PTRINDEX(cgltf_buffer_view, cgltf_json_to_int(tokens + i, json_chunk)); ++i; } + else + { + i = cgltf_skip_json(tokens, i+1); + } if (i < 0) { @@ -2888,11 +3044,9 @@ static int cgltf_parse_json_mesh_gpu_instancing(cgltf_options* options, jsmntok_ { i = cgltf_parse_json_attribute_list(options, tokens, i + 1, json_chunk, &out_mesh_gpu_instancing->attributes, &out_mesh_gpu_instancing->attributes_count); } - else if (cgltf_json_strcmp(tokens + i, json_chunk, "bufferView") == 0) + else { - ++i; - out_mesh_gpu_instancing->buffer_view = CGLTF_PTRINDEX(cgltf_buffer_view, cgltf_json_to_int(tokens + i, json_chunk)); - ++i; + i = cgltf_skip_json(tokens, i+1); } if (i < 0) @@ -3036,6 +3190,31 @@ static int cgltf_parse_json_material_mappings(cgltf_options* options, jsmntok_t return i; } +static cgltf_primitive_type cgltf_json_to_primitive_type(jsmntok_t const* tok, const uint8_t* json_chunk) +{ + int type = cgltf_json_to_int(tok, json_chunk); + + switch (type) + { + case 0: + return cgltf_primitive_type_points; + case 1: + return cgltf_primitive_type_lines; + case 2: + return cgltf_primitive_type_line_loop; + case 3: + return cgltf_primitive_type_line_strip; + case 4: + return cgltf_primitive_type_triangles; + case 5: + return cgltf_primitive_type_triangle_strip; + case 6: + return cgltf_primitive_type_triangle_fan; + default: + return cgltf_primitive_type_invalid; + } +} + static int cgltf_parse_json_primitive(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_primitive* out_prim) { CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); @@ -3052,9 +3231,7 @@ static int cgltf_parse_json_primitive(cgltf_options* options, jsmntok_t const* t if (cgltf_json_strcmp(tokens+i, json_chunk, "mode") == 0) { ++i; - out_prim->type - = (cgltf_primitive_type) - cgltf_json_to_int(tokens+i, json_chunk); + out_prim->type = cgltf_json_to_primitive_type(tokens+i, json_chunk); ++i; } else if (cgltf_json_strcmp(tokens+i, json_chunk, "indices") == 0) @@ -3290,7 +3467,7 @@ static cgltf_component_type cgltf_json_to_component_type(jsmntok_t const* tok, c } } -static int cgltf_parse_json_accessor_sparse(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_accessor_sparse* out_sparse) +static int cgltf_parse_json_accessor_sparse(jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_accessor_sparse* out_sparse) { CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); @@ -3304,7 +3481,7 @@ static int cgltf_parse_json_accessor_sparse(cgltf_options* options, jsmntok_t co if (cgltf_json_strcmp(tokens+i, json_chunk, "count") == 0) { ++i; - out_sparse->count = cgltf_json_to_int(tokens + i, json_chunk); + out_sparse->count = cgltf_json_to_size(tokens + i, json_chunk); ++i; } else if (cgltf_json_strcmp(tokens+i, json_chunk, "indices") == 0) @@ -3337,14 +3514,6 @@ static int cgltf_parse_json_accessor_sparse(cgltf_options* options, jsmntok_t co out_sparse->indices_component_type = cgltf_json_to_component_type(tokens + i, json_chunk); ++i; } - else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) - { - i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_sparse->indices_extras); - } - else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) - { - i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_sparse->indices_extensions_count, &out_sparse->indices_extensions); - } else { i = cgltf_skip_json(tokens, i+1); @@ -3380,14 +3549,6 @@ static int cgltf_parse_json_accessor_sparse(cgltf_options* options, jsmntok_t co out_sparse->values_byte_offset = cgltf_json_to_size(tokens + i, json_chunk); ++i; } - else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) - { - i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_sparse->values_extras); - } - else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) - { - i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_sparse->values_extensions_count, &out_sparse->values_extensions); - } else { i = cgltf_skip_json(tokens, i+1); @@ -3399,14 +3560,6 @@ static int cgltf_parse_json_accessor_sparse(cgltf_options* options, jsmntok_t co } } } - else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) - { - i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_sparse->extras); - } - else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) - { - i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_sparse->extensions_count, &out_sparse->extensions); - } else { i = cgltf_skip_json(tokens, i+1); @@ -3464,8 +3617,7 @@ static int cgltf_parse_json_accessor(cgltf_options* options, jsmntok_t const* to else if (cgltf_json_strcmp(tokens+i, json_chunk, "count") == 0) { ++i; - out_accessor->count = - cgltf_json_to_int(tokens+i, json_chunk); + out_accessor->count = cgltf_json_to_size(tokens+i, json_chunk); ++i; } else if (cgltf_json_strcmp(tokens+i, json_chunk, "type") == 0) @@ -3520,7 +3672,7 @@ static int cgltf_parse_json_accessor(cgltf_options* options, jsmntok_t const* to else if (cgltf_json_strcmp(tokens + i, json_chunk, "sparse") == 0) { out_accessor->is_sparse = 1; - i = cgltf_parse_json_accessor_sparse(options, tokens, i + 1, json_chunk, &out_accessor->sparse); + i = cgltf_parse_json_accessor_sparse(tokens, i + 1, json_chunk, &out_accessor->sparse); } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) { @@ -3592,6 +3744,8 @@ static int cgltf_parse_json_texture_transform(jsmntok_t const* tokens, int i, co static int cgltf_parse_json_texture_view(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_texture_view* out_texture_view) { + (void)options; + CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); out_texture_view->scale = 1.0f; @@ -3616,7 +3770,7 @@ static int cgltf_parse_json_texture_view(cgltf_options* options, jsmntok_t const out_texture_view->texcoord = cgltf_json_to_int(tokens + i, json_chunk); ++i; } - else if (cgltf_json_strcmp(tokens + i, json_chunk, "scale") == 0) + else if (cgltf_json_strcmp(tokens + i, json_chunk, "scale") == 0) { ++i; out_texture_view->scale = cgltf_json_to_float(tokens + i, json_chunk); @@ -3628,28 +3782,12 @@ static int cgltf_parse_json_texture_view(cgltf_options* options, jsmntok_t const out_texture_view->scale = cgltf_json_to_float(tokens + i, json_chunk); ++i; } - else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) - { - i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_texture_view->extras); - } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) { ++i; CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); - if(out_texture_view->extensions) - { - return CGLTF_ERROR_JSON; - } - int extensions_size = tokens[i].size; - out_texture_view->extensions_count = 0; - out_texture_view->extensions = (cgltf_extension*)cgltf_calloc(options, sizeof(cgltf_extension), extensions_size); - - if (!out_texture_view->extensions) - { - return CGLTF_ERROR_NOMEM; - } ++i; @@ -3664,7 +3802,7 @@ static int cgltf_parse_json_texture_view(cgltf_options* options, jsmntok_t const } else { - i = cgltf_parse_json_unprocessed_extension(options, tokens, i, json_chunk, &(out_texture_view->extensions[out_texture_view->extensions_count++])); + i = cgltf_skip_json(tokens, i + 1); } if (i < 0) @@ -3701,11 +3839,11 @@ static int cgltf_parse_json_pbr_metallic_roughness(cgltf_options* options, jsmnt if (cgltf_json_strcmp(tokens+i, json_chunk, "metallicFactor") == 0) { ++i; - out_pbr->metallic_factor = + out_pbr->metallic_factor = cgltf_json_to_float(tokens + i, json_chunk); ++i; } - else if (cgltf_json_strcmp(tokens+i, json_chunk, "roughnessFactor") == 0) + else if (cgltf_json_strcmp(tokens+i, json_chunk, "roughnessFactor") == 0) { ++i; out_pbr->roughness_factor = @@ -3718,13 +3856,11 @@ static int cgltf_parse_json_pbr_metallic_roughness(cgltf_options* options, jsmnt } else if (cgltf_json_strcmp(tokens+i, json_chunk, "baseColorTexture") == 0) { - i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, - &out_pbr->base_color_texture); + i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_pbr->base_color_texture); } else if (cgltf_json_strcmp(tokens + i, json_chunk, "metallicRoughnessTexture") == 0) { - i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, - &out_pbr->metallic_roughness_texture); + i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_pbr->metallic_roughness_texture); } else { @@ -4127,6 +4263,78 @@ static int cgltf_parse_json_iridescence(cgltf_options* options, jsmntok_t const* return i; } +static int cgltf_parse_json_anisotropy(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_anisotropy* out_anisotropy) +{ + CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); + int size = tokens[i].size; + ++i; + + + for (int j = 0; j < size; ++j) + { + CGLTF_CHECK_KEY(tokens[i]); + + if (cgltf_json_strcmp(tokens + i, json_chunk, "anisotropyStrength") == 0) + { + ++i; + out_anisotropy->anisotropy_strength = cgltf_json_to_float(tokens + i, json_chunk); + ++i; + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "anisotropyRotation") == 0) + { + ++i; + out_anisotropy->anisotropy_rotation = cgltf_json_to_float(tokens + i, json_chunk); + ++i; + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "anisotropyTexture") == 0) + { + i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_anisotropy->anisotropy_texture); + } + else + { + i = cgltf_skip_json(tokens, i + 1); + } + + if (i < 0) + { + return i; + } + } + + return i; +} + +static int cgltf_parse_json_dispersion(jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_dispersion* out_dispersion) +{ + CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); + int size = tokens[i].size; + ++i; + + + for (int j = 0; j < size; ++j) + { + CGLTF_CHECK_KEY(tokens[i]); + + if (cgltf_json_strcmp(tokens + i, json_chunk, "dispersion") == 0) + { + ++i; + out_dispersion->dispersion = cgltf_json_to_float(tokens + i, json_chunk); + ++i; + } + else + { + i = cgltf_skip_json(tokens, i + 1); + } + + if (i < 0) + { + return i; + } + } + + return i; +} + static int cgltf_parse_json_image(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_image* out_image) { CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); @@ -4134,11 +4342,11 @@ static int cgltf_parse_json_image(cgltf_options* options, jsmntok_t const* token int size = tokens[i].size; ++i; - for (int j = 0; j < size; ++j) + for (int j = 0; j < size; ++j) { CGLTF_CHECK_KEY(tokens[i]); - if (cgltf_json_strcmp(tokens + i, json_chunk, "uri") == 0) + if (cgltf_json_strcmp(tokens + i, json_chunk, "uri") == 0) { i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_image->uri); } @@ -4218,7 +4426,7 @@ static int cgltf_parse_json_sampler(cgltf_options* options, jsmntok_t const* tok = cgltf_json_to_int(tokens + i, json_chunk); ++i; } - else if (cgltf_json_strcmp(tokens + i, json_chunk, "wrapT") == 0) + else if (cgltf_json_strcmp(tokens + i, json_chunk, "wrapT") == 0) { ++i; out_sampler->wrap_t @@ -4268,7 +4476,7 @@ static int cgltf_parse_json_texture(cgltf_options* options, jsmntok_t const* tok out_texture->sampler = CGLTF_PTRINDEX(cgltf_sampler, cgltf_json_to_int(tokens + i, json_chunk)); ++i; } - else if (cgltf_json_strcmp(tokens + i, json_chunk, "source") == 0) + else if (cgltf_json_strcmp(tokens + i, json_chunk, "source") == 0) { ++i; out_texture->image = CGLTF_PTRINDEX(cgltf_image, cgltf_json_to_int(tokens + i, json_chunk)); @@ -4515,6 +4723,16 @@ static int cgltf_parse_json_material(cgltf_options* options, jsmntok_t const* to out_material->has_iridescence = 1; i = cgltf_parse_json_iridescence(options, tokens, i + 1, json_chunk, &out_material->iridescence); } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "KHR_materials_anisotropy") == 0) + { + out_material->has_anisotropy = 1; + i = cgltf_parse_json_anisotropy(options, tokens, i + 1, json_chunk, &out_material->anisotropy); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "KHR_materials_dispersion") == 0) + { + out_material->has_dispersion = 1; + i = cgltf_parse_json_dispersion(tokens, i + 1, json_chunk, &out_material->dispersion); + } else { i = cgltf_parse_json_unprocessed_extension(options, tokens, i, json_chunk, &(out_material->extensions[out_material->extensions_count++])); @@ -4674,7 +4892,7 @@ static int cgltf_parse_json_meshopt_compression(cgltf_options* options, jsmntok_ else if (cgltf_json_strcmp(tokens+i, json_chunk, "count") == 0) { ++i; - out_meshopt_compression->count = cgltf_json_to_int(tokens+i, json_chunk); + out_meshopt_compression->count = cgltf_json_to_size(tokens+i, json_chunk); ++i; } else if (cgltf_json_strcmp(tokens+i, json_chunk, "mode") == 0) @@ -5963,7 +6181,7 @@ cgltf_size cgltf_num_components(cgltf_type type) { } } -static cgltf_size cgltf_component_size(cgltf_component_type component_type) { +cgltf_size cgltf_component_size(cgltf_component_type component_type) { switch (component_type) { case cgltf_component_type_r_8: @@ -5981,7 +6199,7 @@ static cgltf_size cgltf_component_size(cgltf_component_type component_type) { } } -static cgltf_size cgltf_calc_size(cgltf_type type, cgltf_component_type component_type) +cgltf_size cgltf_calc_size(cgltf_type type, cgltf_component_type component_type) { cgltf_size component_size = cgltf_component_size(component_type); if (type == cgltf_type_mat2 && component_size == 1) @@ -6366,6 +6584,8 @@ static int cgltf_fixup_pointers(cgltf_data* data) CGLTF_PTRFIXUP(data->materials[i].iridescence.iridescence_texture.texture, data->textures, data->textures_count); CGLTF_PTRFIXUP(data->materials[i].iridescence.iridescence_thickness_texture.texture, data->textures, data->textures_count); + + CGLTF_PTRFIXUP(data->materials[i].anisotropy.anisotropy_texture.texture, data->textures, data->textures_count); } for (cgltf_size i = 0; i < data->buffer_views_count; ++i) @@ -6410,7 +6630,6 @@ static int cgltf_fixup_pointers(cgltf_data* data) if (data->nodes[i].has_mesh_gpu_instancing) { - CGLTF_PTRFIXUP_REQ(data->nodes[i].mesh_gpu_instancing.buffer_view, data->buffer_views, data->buffer_views_count); for (cgltf_size m = 0; m < data->nodes[i].mesh_gpu_instancing.attributes_count; ++m) { CGLTF_PTRFIXUP_REQ(data->nodes[i].mesh_gpu_instancing.attributes[m].data, data->accessors, data->accessors_count); @@ -6499,7 +6718,7 @@ static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, * Fills token type and boundaries. */ static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type, - int start, int end) { + ptrdiff_t start, ptrdiff_t end) { token->type = type; token->start = start; token->end = end; @@ -6512,7 +6731,7 @@ static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type, static int jsmn_parse_primitive(jsmn_parser *parser, const char *js, size_t len, jsmntok_t *tokens, size_t num_tokens) { jsmntok_t *token; - int start; + ptrdiff_t start; start = parser->pos; @@ -6562,7 +6781,7 @@ static int jsmn_parse_string(jsmn_parser *parser, const char *js, size_t len, jsmntok_t *tokens, size_t num_tokens) { jsmntok_t *token; - int start = parser->pos; + ptrdiff_t start = parser->pos; parser->pos++; diff --git a/vendor/cgltf/src/cgltf_write.h b/vendor/cgltf/src/cgltf_write.h index 033b0d1cc..aa648a479 100644 --- a/vendor/cgltf/src/cgltf_write.h +++ b/vendor/cgltf/src/cgltf_write.h @@ -1,7 +1,7 @@ /** * cgltf_write - a single-file glTF 2.0 writer written in C99. * - * Version: 1.13 + * Version: 1.14 * * Website: https://github.com/jkuhlmann/cgltf * @@ -85,6 +85,8 @@ cgltf_size cgltf_write(const cgltf_options* options, char* buffer, cgltf_size si #define CGLTF_EXTENSION_FLAG_MATERIALS_EMISSIVE_STRENGTH (1 << 13) #define CGLTF_EXTENSION_FLAG_MESH_GPU_INSTANCING (1 << 14) #define CGLTF_EXTENSION_FLAG_MATERIALS_IRIDESCENCE (1 << 15) +#define CGLTF_EXTENSION_FLAG_MATERIALS_ANISOTROPY (1 << 16) +#define CGLTF_EXTENSION_FLAG_MATERIALS_DISPERSION (1 << 17) typedef struct { char* buffer; @@ -152,7 +154,6 @@ typedef struct { context->extension_flags |= CGLTF_EXTENSION_FLAG_TEXTURE_TRANSFORM; \ cgltf_write_texture_transform(context, &info.transform); \ } \ - cgltf_write_extras(context, &info.extras); \ cgltf_write_line(context, "}"); } #define CGLTF_WRITE_NORMAL_TEXTURE_INFO(label, info) if (info.texture) { \ @@ -164,7 +165,6 @@ typedef struct { context->extension_flags |= CGLTF_EXTENSION_FLAG_TEXTURE_TRANSFORM; \ cgltf_write_texture_transform(context, &info.transform); \ } \ - cgltf_write_extras(context, &info.extras); \ cgltf_write_line(context, "}"); } #define CGLTF_WRITE_OCCLUSION_TEXTURE_INFO(label, info) if (info.texture) { \ @@ -176,12 +176,11 @@ typedef struct { context->extension_flags |= CGLTF_EXTENSION_FLAG_TEXTURE_TRANSFORM; \ cgltf_write_texture_transform(context, &info.transform); \ } \ - cgltf_write_extras(context, &info.extras); \ cgltf_write_line(context, "}"); } #ifndef CGLTF_CONSTS -static const cgltf_size GlbHeaderSize = 12; -static const cgltf_size GlbChunkHeaderSize = 8; +#define GlbHeaderSize 12 +#define GlbChunkHeaderSize 8 static const uint32_t GlbVersion = 2; static const uint32_t GlbMagic = 0x46546C67; static const uint32_t GlbMagicJsonChunk = 0x4E4F534A; @@ -360,6 +359,21 @@ static int cgltf_int_from_component_type(cgltf_component_type ctype) } } +static int cgltf_int_from_primitive_type(cgltf_primitive_type ctype) +{ + switch (ctype) + { + case cgltf_primitive_type_points: return 0; + case cgltf_primitive_type_lines: return 1; + case cgltf_primitive_type_line_loop: return 2; + case cgltf_primitive_type_line_strip: return 3; + case cgltf_primitive_type_triangles: return 4; + case cgltf_primitive_type_triangle_strip: return 5; + case cgltf_primitive_type_triangle_fan: return 6; + default: return -1; + } +} + static const char* cgltf_str_from_alpha_mode(cgltf_alpha_mode alpha_mode) { switch (alpha_mode) @@ -455,7 +469,7 @@ static void cgltf_write_asset(cgltf_write_context* context, const cgltf_asset* a static void cgltf_write_primitive(cgltf_write_context* context, const cgltf_primitive* prim) { - cgltf_write_intprop(context, "mode", (int) prim->type, 4); + cgltf_write_intprop(context, "mode", cgltf_int_from_primitive_type(prim->type), 4); CGLTF_WRITE_IDXPROP("indices", prim->indices, context->data->accessors); CGLTF_WRITE_IDXPROP("material", prim->material, context->data->materials); cgltf_write_line(context, "\"attributes\": {"); @@ -641,6 +655,16 @@ static void cgltf_write_material(cgltf_write_context* context, const cgltf_mater context->extension_flags |= CGLTF_EXTENSION_FLAG_MATERIALS_IRIDESCENCE; } + if (material->has_anisotropy) + { + context->extension_flags |= CGLTF_EXTENSION_FLAG_MATERIALS_ANISOTROPY; + } + + if (material->has_dispersion) + { + context->extension_flags |= CGLTF_EXTENSION_FLAG_MATERIALS_DISPERSION; + } + if (material->has_pbr_metallic_roughness) { const cgltf_pbr_metallic_roughness* params = &material->pbr_metallic_roughness; @@ -656,7 +680,7 @@ static void cgltf_write_material(cgltf_write_context* context, const cgltf_mater cgltf_write_line(context, "}"); } - if (material->unlit || material->has_pbr_specular_glossiness || material->has_clearcoat || material->has_ior || material->has_specular || material->has_transmission || material->has_sheen || material->has_volume || material->has_emissive_strength || material->has_iridescence) + if (material->unlit || material->has_pbr_specular_glossiness || material->has_clearcoat || material->has_ior || material->has_specular || material->has_transmission || material->has_sheen || material->has_volume || material->has_emissive_strength || material->has_iridescence || material->has_anisotropy || material->has_dispersion) { cgltf_write_line(context, "\"extensions\": {"); if (material->has_clearcoat) @@ -767,6 +791,22 @@ static void cgltf_write_material(cgltf_write_context* context, const cgltf_mater CGLTF_WRITE_TEXTURE_INFO("iridescenceThicknessTexture", params->iridescence_thickness_texture); cgltf_write_line(context, "}"); } + if (material->has_anisotropy) + { + cgltf_write_line(context, "\"KHR_materials_anisotropy\": {"); + const cgltf_anisotropy* params = &material->anisotropy; + cgltf_write_floatprop(context, "anisotropyFactor", params->anisotropy_strength, 0.f); + cgltf_write_floatprop(context, "anisotropyRotation", params->anisotropy_rotation, 0.f); + CGLTF_WRITE_TEXTURE_INFO("anisotropyTexture", params->anisotropy_texture); + cgltf_write_line(context, "}"); + } + if (material->has_dispersion) + { + cgltf_write_line(context, "\"KHR_materials_dispersion\": {"); + const cgltf_dispersion* params = &material->dispersion; + cgltf_write_floatprop(context, "dispersion", params->dispersion, 0.f); + cgltf_write_line(context, "}"); + } cgltf_write_line(context, "}"); } @@ -977,7 +1017,6 @@ static void cgltf_write_node(cgltf_write_context* context, const cgltf_node* nod cgltf_write_line(context, "\"EXT_mesh_gpu_instancing\": {"); { - CGLTF_WRITE_IDXPROP("bufferView", node->mesh_gpu_instancing.buffer_view, context->data->buffer_views); cgltf_write_line(context, "\"attributes\": {"); { for (cgltf_size i = 0; i < node->mesh_gpu_instancing.attributes_count; ++i) @@ -1044,14 +1083,11 @@ static void cgltf_write_accessor(cgltf_write_context* context, const cgltf_acces cgltf_write_sizeprop(context, "byteOffset", (int)accessor->sparse.indices_byte_offset, 0); CGLTF_WRITE_IDXPROP("bufferView", accessor->sparse.indices_buffer_view, context->data->buffer_views); cgltf_write_intprop(context, "componentType", cgltf_int_from_component_type(accessor->sparse.indices_component_type), 0); - cgltf_write_extras(context, &accessor->sparse.indices_extras); cgltf_write_line(context, "}"); cgltf_write_line(context, "\"values\": {"); cgltf_write_sizeprop(context, "byteOffset", (int)accessor->sparse.values_byte_offset, 0); CGLTF_WRITE_IDXPROP("bufferView", accessor->sparse.values_buffer_view, context->data->buffer_views); - cgltf_write_extras(context, &accessor->sparse.values_extras); cgltf_write_line(context, "}"); - cgltf_write_extras(context, &accessor->sparse.extras); cgltf_write_line(context, "}"); } cgltf_write_extras(context, &accessor->extras); @@ -1123,6 +1159,7 @@ static void cgltf_write_light(cgltf_write_context* context, const cgltf_light* l cgltf_write_floatprop(context, "outerConeAngle", light->spot_outer_cone_angle, 3.14159265358979323846f/4.0f); cgltf_write_line(context, "}"); } + cgltf_write_extras( context, &light->extras ); cgltf_write_line(context, "}"); } @@ -1249,9 +1286,15 @@ static void cgltf_write_extensions(cgltf_write_context* context, uint32_t extens if (extension_flags & CGLTF_EXTENSION_FLAG_MATERIALS_IRIDESCENCE) { cgltf_write_stritem(context, "KHR_materials_iridescence"); } + if (extension_flags & CGLTF_EXTENSION_FLAG_MATERIALS_ANISOTROPY) { + cgltf_write_stritem(context, "KHR_materials_anisotropy"); + } if (extension_flags & CGLTF_EXTENSION_FLAG_MESH_GPU_INSTANCING) { cgltf_write_stritem(context, "EXT_mesh_gpu_instancing"); } + if (extension_flags & CGLTF_EXTENSION_FLAG_MATERIALS_DISPERSION) { + cgltf_write_stritem(context, "KHR_materials_dispersion"); + } } cgltf_size cgltf_write(const cgltf_options* options, char* buffer, cgltf_size size, const cgltf_data* data) diff --git a/vendor/libc/include/math.h b/vendor/libc/include/math.h index 3f60d698f..9d486da11 100644 --- a/vendor/libc/include/math.h +++ b/vendor/libc/include/math.h @@ -17,5 +17,5 @@ double fabs(double x); int abs(int); double ldexp(double, int); double exp(double); -float log(float); -float sin(float); +double log(double); +double sin(double); diff --git a/vendor/libc/math.odin b/vendor/libc/math.odin index 59f42dd67..af319ac6d 100644 --- a/vendor/libc/math.odin +++ b/vendor/libc/math.odin @@ -90,11 +90,11 @@ exp :: proc "c" (x: f64) -> f64 { } @(require, linkage="strong", link_name="log") -log :: proc "c" (x: f32) -> f32 { +log :: proc "c" (x: f64) -> f64 { return math.ln(x) } @(require, linkage="strong", link_name="sin") -sin :: proc "c" (x: f32) -> f32 { +sin :: proc "c" (x: f64) -> f64 { return math.sin(x) } diff --git a/vendor/libc/stdio.odin b/vendor/libc/stdio.odin index 10b95b96b..97667a5c8 100644 --- a/vendor/libc/stdio.odin +++ b/vendor/libc/stdio.odin @@ -1,3 +1,4 @@ +#+build !freestanding package odin_libc import "core:c" diff --git a/vendor/raylib/raygui.odin b/vendor/raylib/raygui.odin index a15467ae8..559437a60 100644 --- a/vendor/raylib/raygui.odin +++ b/vendor/raylib/raygui.odin @@ -3,6 +3,7 @@ package raylib import "core:c" RAYGUI_SHARED :: #config(RAYGUI_SHARED, false) +RAYGUI_WASM_LIB :: #config(RAYGUI_WASM_LIB, "wasm/libraygui.a") when ODIN_OS == .Windows { foreign import lib { @@ -22,6 +23,10 @@ when ODIN_OS == .Windows { "macos/libraygui.dylib" when RAYGUI_SHARED else "macos/libraygui.a", } } +} else when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 { + foreign import lib { + RAYGUI_WASM_LIB, + } } else { foreign import lib "system:raygui" } diff --git a/vendor/raylib/raylib.odin b/vendor/raylib/raylib.odin index 34a803b99..bb51f105f 100644 --- a/vendor/raylib/raylib.odin +++ b/vendor/raylib/raylib.odin @@ -100,6 +100,7 @@ MAX_TEXT_BUFFER_LENGTH :: #config(RAYLIB_MAX_TEXT_BUFFER_LENGTH, 1024) #assert(size_of(rune) == size_of(c.int)) RAYLIB_SHARED :: #config(RAYLIB_SHARED, false) +RAYLIB_WASM_LIB :: #config(RAYLIB_WASM_LIB, "wasm/libraylib.a") when ODIN_OS == .Windows { @(extra_linker_flags="/NODEFAULTLIB:" + ("msvcrt" when RAYLIB_SHARED else "libcmt")) @@ -127,6 +128,10 @@ when ODIN_OS == .Windows { "system:OpenGL.framework", "system:IOKit.framework", } +} else when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 { + foreign import lib { + RAYLIB_WASM_LIB, + } } else { foreign import lib "system:raylib" } diff --git a/vendor/raylib/raymath.odin b/vendor/raylib/raymath.odin index c66498e41..c8420d60a 100644 --- a/vendor/raylib/raymath.odin +++ b/vendor/raylib/raymath.odin @@ -523,7 +523,7 @@ Vector3Unproject :: proc "c" (source: Vector3, projection: Matrix, view: Matrix) quat: Quaternion quat.x = source.x - quat.y = source.z + quat.y = source.y quat.z = source.z quat.w = 1 diff --git a/vendor/raylib/rlgl/rlgl.odin b/vendor/raylib/rlgl/rlgl.odin index 40913cd50..6ac19695d 100644 --- a/vendor/raylib/rlgl/rlgl.odin +++ b/vendor/raylib/rlgl/rlgl.odin @@ -113,6 +113,7 @@ import rl "../." VERSION :: "5.0" RAYLIB_SHARED :: #config(RAYLIB_SHARED, false) +RAYLIB_WASM_LIB :: #config(RAYLIB_WASM_LIB, "../wasm/libraylib.a") // Note: We pull in the full raylib library. If you want a truly stand-alone rlgl, then: // - Compile a separate rlgl library and use that in the foreign import blocks below. @@ -145,6 +146,10 @@ when ODIN_OS == .Windows { "system:OpenGL.framework", "system:IOKit.framework", } +} else when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 { + foreign import lib { + RAYLIB_WASM_LIB, + } } else { foreign import lib "system:raylib" } @@ -509,7 +514,7 @@ foreign lib { UpdateVertexBufferElements :: proc(id: c.uint, data: rawptr, dataSize: c.int, offset: c.int) --- // Update vertex buffer elements with new data 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) --- + SetVertexAttribute :: proc(index: c.uint, compSize: c.int, type: c.int, normalized: bool, stride: c.int, offset: c.int) --- SetVertexAttributeDivisor :: proc(index: c.uint, divisor: c.int) --- 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) --- diff --git a/vendor/raylib/wasm/libraygui.a b/vendor/raylib/wasm/libraygui.a Binary files differnew file mode 100644 index 000000000..cfde78a93 --- /dev/null +++ b/vendor/raylib/wasm/libraygui.a diff --git a/vendor/raylib/wasm/libraylib.a b/vendor/raylib/wasm/libraylib.a Binary files differnew file mode 100644 index 000000000..4cdbfa694 --- /dev/null +++ b/vendor/raylib/wasm/libraylib.a diff --git a/vendor/vulkan/_gen/create_vulkan_odin_wrapper.py b/vendor/vulkan/_gen/create_vulkan_odin_wrapper.py index 1a4f96901..407e6371c 100644 --- a/vendor/vulkan/_gen/create_vulkan_odin_wrapper.py +++ b/vendor/vulkan/_gen/create_vulkan_odin_wrapper.py @@ -16,6 +16,8 @@ file_and_urls = [ ("vulkan_macos.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vulkan/vulkan_macos.h', False), ("vulkan_ios.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vulkan/vulkan_ios.h', False), ("vulkan_wayland.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vulkan/vulkan_wayland.h', False), + ("vulkan_xlib.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vulkan/vulkan_xlib.h', False), + ("vulkan_xcb.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vulkan/vulkan_xcb.h', False), # Vulkan Video ("vulkan_video_codec_av1std.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vk_video/vulkan_video_codec_av1std.h', False), ("vulkan_video_codec_av1std_decode.h", 'https://raw.githubusercontent.com/KhronosGroup/Vulkan-Headers/main/include/vk_video/vulkan_video_codec_av1std_decode.h', False), @@ -46,17 +48,18 @@ def no_vk(t): t = t.replace('PFN_', 'Proc') t = t.replace('PFN_', 'Proc') - t = re.sub('(?:Vk|VK_)?(\w+)', '\\1', t) + t = re.sub('(?:Vk|VK_)?(\\w+)', '\\1', t) # Vulkan Video - t = re.sub('(?:Std|STD_|VK_STD)?(\w+)', '\\1', t) + t = re.sub('(?:Std|STD_|VK_STD)?(\\w+)', '\\1', t) return t OPAQUE_STRUCTS = """ -wl_surface :: struct {} // Opaque struct defined by Wayland -wl_display :: struct {} // Opaque struct defined by Wayland -IOSurfaceRef :: struct {} // Opaque struct defined by Apple’s CoreGraphics framework -""" +wl_surface :: struct {} // Opaque struct defined by Wayland +wl_display :: struct {} // Opaque struct defined by Wayland +xcb_connection_t :: struct {} // Opaque struct defined by xcb +IOSurfaceRef :: struct {} // Opaque struct defined by Apple’s CoreGraphics framework +""" def convert_type(t, prev_name, curr_name): table = { @@ -91,6 +94,9 @@ def convert_type(t, prev_name, curr_name): "struct BaseInStructure": "BaseInStructure", "struct wl_display": "wl_display", "struct wl_surface": "wl_surface", + "Display": "XlibDisplay", + "Window": "XlibWindow", + "VisualID": "XlibVisualID", 'v': '', } @@ -106,7 +112,7 @@ def convert_type(t, prev_name, curr_name): elif t.endswith("*"): pointer = "^" ttype = t[:len(t)-1] - elem = convert_type(ttype, prev_name, curr_name) + elem = convert_type(ttype, prev_name, curr_name) if curr_name.endswith("s") or curr_name.endswith("Table"): if prev_name.endswith("Count") or prev_name.endswith("Counts"): @@ -445,7 +451,7 @@ def parse_enums(f): def parse_fake_enums(f): data = re.findall(r"static const Vk(\w+FlagBits2) VK_(\w+?) = (\w+);", src, re.S) - + data.sort(key=lambda x: x[0]) fake_enums = {} @@ -507,7 +513,7 @@ def parse_fake_enums(f): continue ff.append((n, v)) - + max_flag_value = max([int(v) for n, v in ff if is_int(v)] + [0]) max_group_value = max([int(v) for n, v in groups if is_int(v)] + [0]) if max_flag_value < max_group_value: @@ -575,13 +581,13 @@ def parse_structs(f): ffields.append(tuple([bit_field_name, bit_field_type, comment])) prev_name = "" continue - + # The second way has many fields that are each 1 bit elif int(fname) == 1: bit_field_type = do_type(bit_field[0], prev_name, fname) ffields.append(tuple(["bitfield", bit_field_type, comment])) break - + if '[' in fname: @@ -894,6 +900,10 @@ import "core:c" import win32 "core:sys/windows" _ :: win32 + +import "vendor:x11/xlib" +_ :: xlib + when ODIN_OS == .Windows { \tHINSTANCE :: win32.HINSTANCE \tHWND :: win32.HWND @@ -919,7 +929,19 @@ when ODIN_OS == .Windows { \t} } -CAMetalLayer :: struct {} +when xlib.IS_SUPPORTED { +\tXlibDisplay :: xlib.Display +\tXlibWindow :: xlib.Window +\tXlibVisualID :: xlib.VisualID +} else { +\tXlibDisplay :: struct {} // Opaque struct defined by Xlib +\tXlibWindow :: c.ulong +\tXlibVisualID :: c.ulong +} + +xcb_visualid_t :: u32 +xcb_window_t :: u32 +CAMetalLayer :: struct {} MTLBuffer_id :: rawptr MTLTexture_id :: rawptr diff --git a/vendor/vulkan/_gen/vulkan_xcb.h b/vendor/vulkan/_gen/vulkan_xcb.h new file mode 100644 index 000000000..cdf6b5269 --- /dev/null +++ b/vendor/vulkan/_gen/vulkan_xcb.h @@ -0,0 +1,56 @@ +#ifndef VULKAN_XCB_H_ +#define VULKAN_XCB_H_ 1 + +/* +** Copyright 2015-2024 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +// VK_KHR_xcb_surface is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_xcb_surface 1 +#define VK_KHR_XCB_SURFACE_SPEC_VERSION 6 +#define VK_KHR_XCB_SURFACE_EXTENSION_NAME "VK_KHR_xcb_surface" +typedef VkFlags VkXcbSurfaceCreateFlagsKHR; +typedef struct VkXcbSurfaceCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkXcbSurfaceCreateFlagsKHR flags; + xcb_connection_t* connection; + xcb_window_t window; +} VkXcbSurfaceCreateInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateXcbSurfaceKHR)(VkInstance instance, const VkXcbSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); +typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, xcb_connection_t* connection, xcb_visualid_t visual_id); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateXcbSurfaceKHR( + VkInstance instance, + const VkXcbSurfaceCreateInfoKHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); + +VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceXcbPresentationSupportKHR( + VkPhysicalDevice physicalDevice, + uint32_t queueFamilyIndex, + xcb_connection_t* connection, + xcb_visualid_t visual_id); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/vendor/vulkan/_gen/vulkan_xlib.h b/vendor/vulkan/_gen/vulkan_xlib.h new file mode 100644 index 000000000..b3c3e27d7 --- /dev/null +++ b/vendor/vulkan/_gen/vulkan_xlib.h @@ -0,0 +1,56 @@ +#ifndef VULKAN_XLIB_H_ +#define VULKAN_XLIB_H_ 1 + +/* +** Copyright 2015-2024 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 +*/ + +/* +** This header is generated from the Khronos Vulkan XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +// VK_KHR_xlib_surface is a preprocessor guard. Do not pass it to API calls. +#define VK_KHR_xlib_surface 1 +#define VK_KHR_XLIB_SURFACE_SPEC_VERSION 6 +#define VK_KHR_XLIB_SURFACE_EXTENSION_NAME "VK_KHR_xlib_surface" +typedef VkFlags VkXlibSurfaceCreateFlagsKHR; +typedef struct VkXlibSurfaceCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkXlibSurfaceCreateFlagsKHR flags; + Display* dpy; + Window window; +} VkXlibSurfaceCreateInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateXlibSurfaceKHR)(VkInstance instance, const VkXlibSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); +typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, Display* dpy, VisualID visualID); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateXlibSurfaceKHR( + VkInstance instance, + const VkXlibSurfaceCreateInfoKHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); + +VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceXlibPresentationSupportKHR( + VkPhysicalDevice physicalDevice, + uint32_t queueFamilyIndex, + Display* dpy, + VisualID visualID); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/vendor/vulkan/core.odin b/vendor/vulkan/core.odin index a335018f9..f90b65008 100644 --- a/vendor/vulkan/core.odin +++ b/vendor/vulkan/core.odin @@ -1161,6 +1161,12 @@ EXT_METAL_OBJECTS_EXTENSION_NAME :: "VK_EXT_metal_objec KHR_wayland_surface :: 1 KHR_WAYLAND_SURFACE_SPEC_VERSION :: 6 KHR_WAYLAND_SURFACE_EXTENSION_NAME :: "VK_KHR_wayland_surface" +KHR_xlib_surface :: 1 +KHR_XLIB_SURFACE_SPEC_VERSION :: 6 +KHR_XLIB_SURFACE_EXTENSION_NAME :: "VK_KHR_xlib_surface" +KHR_xcb_surface :: 1 +KHR_XCB_SURFACE_SPEC_VERSION :: 6 +KHR_XCB_SURFACE_EXTENSION_NAME :: "VK_KHR_xcb_surface" // Handles types Instance :: distinct Handle diff --git a/vendor/vulkan/enums.odin b/vendor/vulkan/enums.odin index 5ac8d1612..a55ba9e58 100644 --- a/vendor/vulkan/enums.odin +++ b/vendor/vulkan/enums.odin @@ -4585,6 +4585,10 @@ WaylandSurfaceCreateFlagsKHR :: distinct bit_set[Wayland WaylandSurfaceCreateFlagKHR :: enum u32 {} Win32SurfaceCreateFlagsKHR :: distinct bit_set[Win32SurfaceCreateFlagKHR; Flags] Win32SurfaceCreateFlagKHR :: enum u32 {} +XcbSurfaceCreateFlagsKHR :: distinct bit_set[XcbSurfaceCreateFlagKHR; Flags] +XcbSurfaceCreateFlagKHR :: enum u32 {} +XlibSurfaceCreateFlagsKHR :: distinct bit_set[XlibSurfaceCreateFlagKHR; Flags] +XlibSurfaceCreateFlagKHR :: enum u32 {} AccessFlags2 :: distinct bit_set[AccessFlag2; Flags64] AccessFlag2 :: enum Flags64 { INDIRECT_COMMAND_READ = 0, diff --git a/vendor/vulkan/procedures.odin b/vendor/vulkan/procedures.odin index dc03275a2..19f70fc85 100644 --- a/vendor/vulkan/procedures.odin +++ b/vendor/vulkan/procedures.odin @@ -36,6 +36,8 @@ ProcCreateMacOSSurfaceMVK :: #type pr ProcCreateMetalSurfaceEXT :: #type proc "system" (instance: Instance, pCreateInfo: ^MetalSurfaceCreateInfoEXT, pAllocator: ^AllocationCallbacks, pSurface: ^SurfaceKHR) -> Result ProcCreateWaylandSurfaceKHR :: #type proc "system" (instance: Instance, pCreateInfo: ^WaylandSurfaceCreateInfoKHR, pAllocator: ^AllocationCallbacks, pSurface: ^SurfaceKHR) -> Result ProcCreateWin32SurfaceKHR :: #type proc "system" (instance: Instance, pCreateInfo: ^Win32SurfaceCreateInfoKHR, pAllocator: ^AllocationCallbacks, pSurface: ^SurfaceKHR) -> Result +ProcCreateXcbSurfaceKHR :: #type proc "system" (instance: Instance, pCreateInfo: ^XcbSurfaceCreateInfoKHR, pAllocator: ^AllocationCallbacks, pSurface: ^SurfaceKHR) -> Result +ProcCreateXlibSurfaceKHR :: #type proc "system" (instance: Instance, pCreateInfo: ^XlibSurfaceCreateInfoKHR, pAllocator: ^AllocationCallbacks, pSurface: ^SurfaceKHR) -> Result ProcDebugReportMessageEXT :: #type proc "system" (instance: Instance, flags: DebugReportFlagsEXT, objectType: DebugReportObjectTypeEXT, object: u64, location: int, messageCode: i32, pLayerPrefix: cstring, pMessage: cstring) ProcDestroyDebugReportCallbackEXT :: #type proc "system" (instance: Instance, callback: DebugReportCallbackEXT, pAllocator: ^AllocationCallbacks) ProcDestroyDebugUtilsMessengerEXT :: #type proc "system" (instance: Instance, messenger: DebugUtilsMessengerEXT, pAllocator: ^AllocationCallbacks) @@ -113,6 +115,8 @@ ProcGetPhysicalDeviceVideoEncodeQualityLevelPropertiesKHR :: #type pr ProcGetPhysicalDeviceVideoFormatPropertiesKHR :: #type proc "system" (physicalDevice: PhysicalDevice, pVideoFormatInfo: ^PhysicalDeviceVideoFormatInfoKHR, pVideoFormatPropertyCount: ^u32, pVideoFormatProperties: [^]VideoFormatPropertiesKHR) -> Result ProcGetPhysicalDeviceWaylandPresentationSupportKHR :: #type proc "system" (physicalDevice: PhysicalDevice, queueFamilyIndex: u32, display: ^wl_display) -> b32 ProcGetPhysicalDeviceWin32PresentationSupportKHR :: #type proc "system" (physicalDevice: PhysicalDevice, queueFamilyIndex: u32) -> b32 +ProcGetPhysicalDeviceXcbPresentationSupportKHR :: #type proc "system" (physicalDevice: PhysicalDevice, queueFamilyIndex: u32, connection: ^xcb_connection_t, visual_id: xcb_visualid_t) -> b32 +ProcGetPhysicalDeviceXlibPresentationSupportKHR :: #type proc "system" (physicalDevice: PhysicalDevice, queueFamilyIndex: u32, dpy: ^XlibDisplay, visualID: XlibVisualID) -> b32 ProcGetWinrtDisplayNV :: #type proc "system" (physicalDevice: PhysicalDevice, deviceRelativeId: u32, pDisplay: ^DisplayKHR) -> Result ProcReleaseDisplayEXT :: #type proc "system" (physicalDevice: PhysicalDevice, display: DisplayKHR) -> Result ProcSubmitDebugUtilsMessageEXT :: #type proc "system" (instance: Instance, messageSeverity: DebugUtilsMessageSeverityFlagsEXT, messageTypes: DebugUtilsMessageTypeFlagsEXT, pCallbackData: ^DebugUtilsMessengerCallbackDataEXT) @@ -730,6 +734,8 @@ CreateMacOSSurfaceMVK: ProcCreateMacO CreateMetalSurfaceEXT: ProcCreateMetalSurfaceEXT CreateWaylandSurfaceKHR: ProcCreateWaylandSurfaceKHR CreateWin32SurfaceKHR: ProcCreateWin32SurfaceKHR +CreateXcbSurfaceKHR: ProcCreateXcbSurfaceKHR +CreateXlibSurfaceKHR: ProcCreateXlibSurfaceKHR DebugReportMessageEXT: ProcDebugReportMessageEXT DestroyDebugReportCallbackEXT: ProcDestroyDebugReportCallbackEXT DestroyDebugUtilsMessengerEXT: ProcDestroyDebugUtilsMessengerEXT @@ -806,6 +812,8 @@ GetPhysicalDeviceVideoEncodeQualityLevelPropertiesKHR: ProcGetPhysica GetPhysicalDeviceVideoFormatPropertiesKHR: ProcGetPhysicalDeviceVideoFormatPropertiesKHR GetPhysicalDeviceWaylandPresentationSupportKHR: ProcGetPhysicalDeviceWaylandPresentationSupportKHR GetPhysicalDeviceWin32PresentationSupportKHR: ProcGetPhysicalDeviceWin32PresentationSupportKHR +GetPhysicalDeviceXcbPresentationSupportKHR: ProcGetPhysicalDeviceXcbPresentationSupportKHR +GetPhysicalDeviceXlibPresentationSupportKHR: ProcGetPhysicalDeviceXlibPresentationSupportKHR GetWinrtDisplayNV: ProcGetWinrtDisplayNV ReleaseDisplayEXT: ProcReleaseDisplayEXT SubmitDebugUtilsMessageEXT: ProcSubmitDebugUtilsMessageEXT @@ -1423,6 +1431,8 @@ load_proc_addresses_custom :: proc(set_proc_address: SetProcAddressType) { set_proc_address(&CreateMetalSurfaceEXT, "vkCreateMetalSurfaceEXT") set_proc_address(&CreateWaylandSurfaceKHR, "vkCreateWaylandSurfaceKHR") set_proc_address(&CreateWin32SurfaceKHR, "vkCreateWin32SurfaceKHR") + set_proc_address(&CreateXcbSurfaceKHR, "vkCreateXcbSurfaceKHR") + set_proc_address(&CreateXlibSurfaceKHR, "vkCreateXlibSurfaceKHR") set_proc_address(&DebugReportMessageEXT, "vkDebugReportMessageEXT") set_proc_address(&DestroyDebugReportCallbackEXT, "vkDestroyDebugReportCallbackEXT") set_proc_address(&DestroyDebugUtilsMessengerEXT, "vkDestroyDebugUtilsMessengerEXT") @@ -1499,6 +1509,8 @@ load_proc_addresses_custom :: proc(set_proc_address: SetProcAddressType) { set_proc_address(&GetPhysicalDeviceVideoFormatPropertiesKHR, "vkGetPhysicalDeviceVideoFormatPropertiesKHR") set_proc_address(&GetPhysicalDeviceWaylandPresentationSupportKHR, "vkGetPhysicalDeviceWaylandPresentationSupportKHR") set_proc_address(&GetPhysicalDeviceWin32PresentationSupportKHR, "vkGetPhysicalDeviceWin32PresentationSupportKHR") + set_proc_address(&GetPhysicalDeviceXcbPresentationSupportKHR, "vkGetPhysicalDeviceXcbPresentationSupportKHR") + set_proc_address(&GetPhysicalDeviceXlibPresentationSupportKHR, "vkGetPhysicalDeviceXlibPresentationSupportKHR") set_proc_address(&GetWinrtDisplayNV, "vkGetWinrtDisplayNV") set_proc_address(&ReleaseDisplayEXT, "vkReleaseDisplayEXT") set_proc_address(&SubmitDebugUtilsMessageEXT, "vkSubmitDebugUtilsMessageEXT") @@ -3879,6 +3891,8 @@ load_proc_addresses_instance :: proc(instance: Instance) { CreateMetalSurfaceEXT = auto_cast GetInstanceProcAddr(instance, "vkCreateMetalSurfaceEXT") CreateWaylandSurfaceKHR = auto_cast GetInstanceProcAddr(instance, "vkCreateWaylandSurfaceKHR") CreateWin32SurfaceKHR = auto_cast GetInstanceProcAddr(instance, "vkCreateWin32SurfaceKHR") + CreateXcbSurfaceKHR = auto_cast GetInstanceProcAddr(instance, "vkCreateXcbSurfaceKHR") + CreateXlibSurfaceKHR = auto_cast GetInstanceProcAddr(instance, "vkCreateXlibSurfaceKHR") DebugReportMessageEXT = auto_cast GetInstanceProcAddr(instance, "vkDebugReportMessageEXT") DestroyDebugReportCallbackEXT = auto_cast GetInstanceProcAddr(instance, "vkDestroyDebugReportCallbackEXT") DestroyDebugUtilsMessengerEXT = auto_cast GetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT") @@ -3955,6 +3969,8 @@ load_proc_addresses_instance :: proc(instance: Instance) { GetPhysicalDeviceVideoFormatPropertiesKHR = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceVideoFormatPropertiesKHR") GetPhysicalDeviceWaylandPresentationSupportKHR = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceWaylandPresentationSupportKHR") GetPhysicalDeviceWin32PresentationSupportKHR = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceWin32PresentationSupportKHR") + GetPhysicalDeviceXcbPresentationSupportKHR = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceXcbPresentationSupportKHR") + GetPhysicalDeviceXlibPresentationSupportKHR = auto_cast GetInstanceProcAddr(instance, "vkGetPhysicalDeviceXlibPresentationSupportKHR") GetWinrtDisplayNV = auto_cast GetInstanceProcAddr(instance, "vkGetWinrtDisplayNV") ReleaseDisplayEXT = auto_cast GetInstanceProcAddr(instance, "vkReleaseDisplayEXT") SubmitDebugUtilsMessageEXT = auto_cast GetInstanceProcAddr(instance, "vkSubmitDebugUtilsMessageEXT") diff --git a/vendor/vulkan/structs.odin b/vendor/vulkan/structs.odin index 3c41d1923..611a99ed7 100644 --- a/vendor/vulkan/structs.odin +++ b/vendor/vulkan/structs.odin @@ -7,6 +7,10 @@ import "core:c" import win32 "core:sys/windows" _ :: win32 + +import "vendor:x11/xlib" +_ :: xlib + when ODIN_OS == .Windows { HINSTANCE :: win32.HINSTANCE HWND :: win32.HWND @@ -32,7 +36,19 @@ when ODIN_OS == .Windows { } } -CAMetalLayer :: struct {} +when xlib.IS_SUPPORTED { + XlibDisplay :: xlib.Display + XlibWindow :: xlib.Window + XlibVisualID :: xlib.VisualID +} else { + XlibDisplay :: struct {} // Opaque struct defined by Xlib + XlibWindow :: c.ulong + XlibVisualID :: c.ulong +} + +xcb_visualid_t :: u32 +xcb_window_t :: u32 +CAMetalLayer :: struct {} MTLBuffer_id :: rawptr MTLTexture_id :: rawptr @@ -8910,6 +8926,22 @@ WaylandSurfaceCreateInfoKHR :: struct { surface: ^wl_surface, } +XlibSurfaceCreateInfoKHR :: struct { + sType: StructureType, + pNext: rawptr, + flags: XlibSurfaceCreateFlagsKHR, + dpy: ^XlibDisplay, + window: XlibWindow, +} + +XcbSurfaceCreateInfoKHR :: struct { + sType: StructureType, + pNext: rawptr, + flags: XcbSurfaceCreateFlagsKHR, + connection: ^xcb_connection_t, + window: xcb_window_t, +} + VideoAV1ColorConfigFlags :: struct { bitfield: u32, } @@ -9753,9 +9785,10 @@ VideoEncodeH265ReferenceInfo :: struct { // Opaque structs -wl_surface :: struct {} // Opaque struct defined by Wayland -wl_display :: struct {} // Opaque struct defined by Wayland -IOSurfaceRef :: struct {} // Opaque struct defined by Apple’s CoreGraphics framework +wl_surface :: struct {} // Opaque struct defined by Wayland +wl_display :: struct {} // Opaque struct defined by Wayland +xcb_connection_t :: struct {} // Opaque struct defined by xcb +IOSurfaceRef :: struct {} // Opaque struct defined by Apple’s CoreGraphics framework // Aliases PhysicalDeviceVariablePointerFeatures :: PhysicalDeviceVariablePointersFeatures PhysicalDeviceShaderDrawParameterFeatures :: PhysicalDeviceShaderDrawParametersFeatures diff --git a/vendor/x11/xlib/xlib.odin b/vendor/x11/xlib/xlib.odin new file mode 100644 index 000000000..bd9ba3b59 --- /dev/null +++ b/vendor/x11/xlib/xlib.odin @@ -0,0 +1,4 @@ +package xlib + +// Value, specifying whether `vendor:x11/xlib` is available on the current platform. +IS_SUPPORTED :: ODIN_OS == .Linux || ODIN_OS == .FreeBSD || ODIN_OS == .OpenBSD |