Merge branch 'odin-lang:master' into master

This commit is contained in:
FrancisTheCat
2024-06-14 16:34:21 +02:00
committed by GitHub
30 changed files with 1155 additions and 831 deletions
+29
View File
@@ -39,6 +39,35 @@ jobs:
./odin test tests/vendor -all-packages -define:ODIN_TEST_FANCY=false ./odin test tests/vendor -all-packages -define:ODIN_TEST_FANCY=false
./odin test tests/benchmark -all-packages -define:ODIN_TEST_FANCY=false ./odin test tests/benchmark -all-packages -define:ODIN_TEST_FANCY=false
(cd tests/issues; ./run.sh) (cd tests/issues; ./run.sh)
build_freebsd:
name: FreeBSD Build, Check, and Test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build, Check, and Test
timeout-minutes: 15
uses: vmactions/freebsd-vm@v1
with:
usesh: true
copyback: false
prepare: |
pkg install -y gmake git bash python3 libxml2 llvm17
run: |
# `set -e` is needed for test failures to register. https://github.com/vmactions/freebsd-vm/issues/72
set -e -x
git config --global --add safe.directory $(pwd)
gmake release
./odin version
./odin report
gmake -C vendor/stb/src
gmake -C vendor/cgltf/src
gmake -C vendor/miniaudio/src
./odin check examples/all -vet -strict-style -target:freebsd_amd64
./odin test tests/core/normal.odin -file -all-packages -define:ODIN_TEST_FANCY=false
./odin test tests/core/speed.odin -file -all-packages -o:speed -define:ODIN_TEST_FANCY=false
./odin test tests/vendor -all-packages -define:ODIN_TEST_FANCY=false
./odin test tests/benchmark -all-packages -define:ODIN_TEST_FANCY=false
(cd tests/issues; ./run.sh)
ci: ci:
strategy: strategy:
fail-fast: false fail-fast: false
+5 -5
View File
@@ -383,7 +383,7 @@ clear_map :: proc "contextless" (m: ^$T/map[$K]$V) {
// //
// Note: Prefer the procedure group `reserve` // Note: Prefer the procedure group `reserve`
@builtin @builtin
reserve_map :: proc(m: ^$T/map[$K]$V, capacity: int, loc := #caller_location) -> Allocator_Error { reserve_map :: proc(m: ^$T/map[$K]$V, #any_int capacity: int, loc := #caller_location) -> Allocator_Error {
return __dynamic_map_reserve((^Raw_Map)(m), map_info(T), uint(capacity), loc) if m != nil else nil return __dynamic_map_reserve((^Raw_Map)(m), map_info(T), uint(capacity), loc) if m != nil else nil
} }
@@ -721,12 +721,12 @@ _reserve_dynamic_array :: #force_inline proc(array: ^$T/[dynamic]$E, capacity: i
} }
@builtin @builtin
reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #caller_location) -> Allocator_Error { reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, #any_int capacity: int, loc := #caller_location) -> Allocator_Error {
return _reserve_dynamic_array(array, capacity, true, loc) return _reserve_dynamic_array(array, capacity, true, loc)
} }
@builtin @builtin
non_zero_reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #caller_location) -> Allocator_Error { non_zero_reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, #any_int capacity: int, loc := #caller_location) -> Allocator_Error {
return _reserve_dynamic_array(array, capacity, false, loc) return _reserve_dynamic_array(array, capacity, false, loc)
} }
@@ -773,12 +773,12 @@ _resize_dynamic_array :: #force_inline proc(array: ^$T/[dynamic]$E, length: int,
} }
@builtin @builtin
resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, length: int, loc := #caller_location) -> Allocator_Error { resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, #any_int length: int, loc := #caller_location) -> Allocator_Error {
return _resize_dynamic_array(array, length, true, loc=loc) return _resize_dynamic_array(array, length, true, loc=loc)
} }
@builtin @builtin
non_zero_resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, length: int, loc := #caller_location) -> Allocator_Error { non_zero_resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, #any_int length: int, loc := #caller_location) -> Allocator_Error {
return _resize_dynamic_array(array, length, false, loc=loc) return _resize_dynamic_array(array, length, false, loc=loc)
} }
+2 -2
View File
@@ -11,7 +11,7 @@ HAS_RAND_BYTES :: true
_rand_bytes :: proc(dst: []byte) { _rand_bytes :: proc(dst: []byte) {
err := Sec.RandomCopyBytes(count=len(dst), bytes=raw_data(dst)) err := Sec.RandomCopyBytes(count=len(dst), bytes=raw_data(dst))
if err != .Success { if err != .Success {
msg := CF.StringCopyToOdinString(Sec.CopyErrorMessageString(err)) msg := CF.StringCopyToOdinString(Sec.CopyErrorMessageString(err))
panic(fmt.tprintf("crypto/rand_bytes: SecRandomCopyBytes returned non-zero result: %v %s", err, msg)) fmt.panicf("crypto/rand_bytes: SecRandomCopyBytes returned non-zero result: %v %s", err, msg)
} }
} }
+1 -1
View File
@@ -32,7 +32,7 @@ _rand_bytes :: proc (dst: []byte) {
// All other failures are things that should NEVER happen // All other failures are things that should NEVER happen
// unless the kernel interface changes (ie: the Linux // unless the kernel interface changes (ie: the Linux
// developers break userland). // developers break userland).
panic(fmt.tprintf("crypto: getrandom failed: %v", errno)) fmt.panicf("crypto: getrandom failed: %v", errno)
} }
l -= n_read l -= n_read
dst = dst[n_read:] dst = dst[n_read:]
+10 -10
View File
@@ -11,16 +11,16 @@ _rand_bytes :: proc(dst: []byte) {
ret := (os.Errno)(win32.BCryptGenRandom(nil, raw_data(dst), u32(len(dst)), win32.BCRYPT_USE_SYSTEM_PREFERRED_RNG)) ret := (os.Errno)(win32.BCryptGenRandom(nil, raw_data(dst), u32(len(dst)), win32.BCRYPT_USE_SYSTEM_PREFERRED_RNG))
if ret != os.ERROR_NONE { if ret != os.ERROR_NONE {
switch ret { switch ret {
case os.ERROR_INVALID_HANDLE: case os.ERROR_INVALID_HANDLE:
// The handle to the first parameter is invalid. // The handle to the first parameter is invalid.
// This should not happen here, since we explicitly pass nil to it // This should not happen here, since we explicitly pass nil to it
panic("crypto: BCryptGenRandom Invalid handle for hAlgorithm") panic("crypto: BCryptGenRandom Invalid handle for hAlgorithm")
case os.ERROR_INVALID_PARAMETER: case os.ERROR_INVALID_PARAMETER:
// One of the parameters was invalid // One of the parameters was invalid
panic("crypto: BCryptGenRandom Invalid parameter") panic("crypto: BCryptGenRandom Invalid parameter")
case: case:
// Unknown error // Unknown error
panic(fmt.tprintf("crypto: BCryptGenRandom failed: %d\n", ret)) fmt.panicf("crypto: BCryptGenRandom failed: %d\n", ret)
} }
} }
} }
+54 -69
View File
@@ -56,38 +56,27 @@ CDATA_END :: "]]>"
COMMENT_START :: "<!--" COMMENT_START :: "<!--"
COMMENT_END :: "-->" COMMENT_END :: "-->"
/* // Default: CDATA and comments are passed through unchanged.
Default: CDATA and comments are passed through unchanged.
*/
XML_Decode_Option :: enum u8 { XML_Decode_Option :: enum u8 {
/* // Do not decode & entities. It decodes by default. If given, overrides `Decode_CDATA`.
Do not decode & entities. It decodes by default.
If given, overrides `Decode_CDATA`.
*/
No_Entity_Decode, No_Entity_Decode,
/* // CDATA is unboxed.
CDATA is unboxed.
*/
Unbox_CDATA, Unbox_CDATA,
/* // Unboxed CDATA is decoded as well. Ignored if `.Unbox_CDATA` is not given.
Unboxed CDATA is decoded as well.
Ignored if `.Unbox_CDATA` is not given.
*/
Decode_CDATA, Decode_CDATA,
/* // Comments are stripped.
Comments are stripped.
*/
Comment_Strip, Comment_Strip,
// Normalize whitespace
Normalize_Whitespace,
} }
XML_Decode_Options :: bit_set[XML_Decode_Option; u8] XML_Decode_Options :: bit_set[XML_Decode_Option; u8]
/* // Decode a string that may include SGML/XML/HTML entities.
Decode a string that may include SGML/XML/HTML entities. // The caller has to free the result.
The caller has to free the result.
*/
decode_xml :: proc(input: string, options := XML_Decode_Options{}, allocator := context.allocator) -> (decoded: string, err: Error) { decode_xml :: proc(input: string, options := XML_Decode_Options{}, allocator := context.allocator) -> (decoded: string, err: Error) {
context.allocator = allocator context.allocator = allocator
@@ -100,14 +89,14 @@ decode_xml :: proc(input: string, options := XML_Decode_Options{}, allocator :=
t := Tokenizer{src=input} t := Tokenizer{src=input}
in_data := false in_data := false
prev: rune = ' '
loop: for { loop: for {
advance(&t) or_return advance(&t) or_return
if t.r < 0 { break loop } if t.r < 0 { break loop }
/* // Below here we're never inside a CDATA tag. At most we'll see the start of one,
Below here we're never inside a CDATA tag. // but that doesn't affect the logic.
At most we'll see the start of one, but that doesn't affect the logic.
*/
switch t.r { switch t.r {
case '<': case '<':
/* /*
@@ -126,9 +115,7 @@ decode_xml :: proc(input: string, options := XML_Decode_Options{}, allocator :=
in_data = _handle_xml_special(&t, &builder, options) or_return in_data = _handle_xml_special(&t, &builder, options) or_return
case ']': case ']':
/* // If we're unboxing _and_ decoding CDATA, we'll have to check for the end tag.
If we're unboxing _and_ decoding CDATA, we'll have to check for the end tag.
*/
if in_data { if in_data {
if t.read_offset + len(CDATA_END) < len(t.src) { if t.read_offset + len(CDATA_END) < len(t.src) {
if string(t.src[t.offset:][:len(CDATA_END)]) == CDATA_END { if string(t.src[t.offset:][:len(CDATA_END)]) == CDATA_END {
@@ -143,22 +130,16 @@ decode_xml :: proc(input: string, options := XML_Decode_Options{}, allocator :=
case: case:
if in_data && .Decode_CDATA not_in options { if in_data && .Decode_CDATA not_in options {
/* // Unboxed, but undecoded.
Unboxed, but undecoded.
*/
write_rune(&builder, t.r) write_rune(&builder, t.r)
continue continue
} }
if t.r == '&' { if t.r == '&' {
if entity, entity_err := _extract_xml_entity(&t); entity_err != .None { if entity, entity_err := _extract_xml_entity(&t); entity_err != .None {
/* // We read to the end of the string without closing the entity. Pass through as-is.
We read to the end of the string without closing the entity.
Pass through as-is.
*/
write_string(&builder, entity) write_string(&builder, entity)
} else { } else {
if .No_Entity_Decode not_in options { if .No_Entity_Decode not_in options {
if decoded, ok := xml_decode_entity(entity); ok { if decoded, ok := xml_decode_entity(entity); ok {
write_rune(&builder, decoded) write_rune(&builder, decoded)
@@ -166,19 +147,41 @@ decode_xml :: proc(input: string, options := XML_Decode_Options{}, allocator :=
} }
} }
/* // Literal passthrough because the decode failed or we want entities not decoded.
Literal passthrough because the decode failed or we want entities not decoded.
*/
write_string(&builder, "&") write_string(&builder, "&")
write_string(&builder, entity) write_string(&builder, entity)
write_string(&builder, ";") write_string(&builder, ";")
} }
} else { } else {
write_rune(&builder, t.r) // Handle AV Normalization: https://www.w3.org/TR/2006/REC-xml11-20060816/#AVNormalize
if .Normalize_Whitespace in options {
switch t.r {
case ' ', '\r', '\n', '\t':
if prev != ' ' {
write_rune(&builder, ' ')
prev = ' '
}
case:
write_rune(&builder, t.r)
prev = t.r
}
} else {
// https://www.w3.org/TR/2006/REC-xml11-20060816/#sec-line-ends
switch t.r {
case '\n', 0x85, 0x2028:
write_rune(&builder, '\n')
case '\r': // Do nothing until next character
case:
if prev == '\r' { // Turn a single carriage return into a \n
write_rune(&builder, '\n')
}
write_rune(&builder, t.r)
}
prev = t.r
}
} }
} }
} }
return strings.clone(strings.to_string(builder), allocator), err return strings.clone(strings.to_string(builder), allocator), err
} }
@@ -253,24 +256,18 @@ xml_decode_entity :: proc(entity: string) -> (decoded: rune, ok: bool) {
return rune(val), true return rune(val), true
case: case:
/* // Named entity.
Named entity.
*/
return named_xml_entity_to_rune(entity) return named_xml_entity_to_rune(entity)
} }
} }
/* // Private XML helper to extract `&<stuff>;` entity.
Private XML helper to extract `&<stuff>;` entity.
*/
@(private="file") @(private="file")
_extract_xml_entity :: proc(t: ^Tokenizer) -> (entity: string, err: Error) { _extract_xml_entity :: proc(t: ^Tokenizer) -> (entity: string, err: Error) {
assert(t != nil && t.r == '&') assert(t != nil && t.r == '&')
/* // All of these would be in the ASCII range.
All of these would be in the ASCII range. // Even if one is not, it doesn't matter. All characters we need to compare to extract are.
Even if one is not, it doesn't matter. All characters we need to compare to extract are.
*/
length := len(t.src) length := len(t.src)
found := false found := false
@@ -292,9 +289,7 @@ _extract_xml_entity :: proc(t: ^Tokenizer) -> (entity: string, err: Error) {
return string(t.src[t.offset : t.read_offset]), .Invalid_Entity_Encoding return string(t.src[t.offset : t.read_offset]), .Invalid_Entity_Encoding
} }
/* // Private XML helper for CDATA and comments.
Private XML helper for CDATA and comments.
*/
@(private="file") @(private="file")
_handle_xml_special :: proc(t: ^Tokenizer, builder: ^strings.Builder, options: XML_Decode_Options) -> (in_data: bool, err: Error) { _handle_xml_special :: proc(t: ^Tokenizer, builder: ^strings.Builder, options: XML_Decode_Options) -> (in_data: bool, err: Error) {
assert(t != nil && t.r == '<') assert(t != nil && t.r == '<')
@@ -304,20 +299,14 @@ _handle_xml_special :: proc(t: ^Tokenizer, builder: ^strings.Builder, options: X
t.read_offset += len(CDATA_START) - 1 t.read_offset += len(CDATA_START) - 1
if .Unbox_CDATA in options && .Decode_CDATA in options { if .Unbox_CDATA in options && .Decode_CDATA in options {
/* // We're unboxing _and_ decoding CDATA
We're unboxing _and_ decoding CDATA
*/
return true, .None return true, .None
} }
/* // CDATA is passed through.
CDATA is passed through.
*/
offset := t.offset offset := t.offset
/* // Scan until end of CDATA.
Scan until end of CDATA.
*/
for { for {
advance(t) or_return advance(t) or_return
if t.r < 0 { return true, .CDATA_Not_Terminated } if t.r < 0 { return true, .CDATA_Not_Terminated }
@@ -341,14 +330,10 @@ _handle_xml_special :: proc(t: ^Tokenizer, builder: ^strings.Builder, options: X
} else if string(t.src[t.offset:][:len(COMMENT_START)]) == COMMENT_START { } else if string(t.src[t.offset:][:len(COMMENT_START)]) == COMMENT_START {
t.read_offset += len(COMMENT_START) t.read_offset += len(COMMENT_START)
/* // Comment is passed through by default.
Comment is passed through by default.
*/
offset := t.offset offset := t.offset
/* // Scan until end of Comment.
Scan until end of Comment.
*/
for { for {
advance(t) or_return advance(t) or_return
if t.r < 0 { return true, .Comment_Not_Terminated } if t.r < 0 { return true, .Comment_Not_Terminated }
+11 -32
View File
@@ -218,9 +218,7 @@ scan_identifier :: proc(t: ^Tokenizer) -> string {
for is_valid_identifier_rune(t.ch) { for is_valid_identifier_rune(t.ch) {
advance_rune(t) advance_rune(t)
if t.ch == ':' { if t.ch == ':' {
/* // A namespaced attr can have at most two parts, `namespace:ident`.
A namespaced attr can have at most two parts, `namespace:ident`.
*/
if namespaced { if namespaced {
break break
} }
@@ -268,14 +266,10 @@ scan_comment :: proc(t: ^Tokenizer) -> (comment: string, err: Error) {
return string(t.src[offset : t.offset - 1]), .None return string(t.src[offset : t.offset - 1]), .None
} }
/* // Skip CDATA
Skip CDATA
*/
skip_cdata :: proc(t: ^Tokenizer) -> (err: Error) { skip_cdata :: proc(t: ^Tokenizer) -> (err: Error) {
if t.read_offset + len(CDATA_START) >= len(t.src) { if t.read_offset + len(CDATA_START) >= len(t.src) {
/* // Can't be the start of a CDATA tag.
Can't be the start of a CDATA tag.
*/
return .None return .None
} }
@@ -290,9 +284,7 @@ skip_cdata :: proc(t: ^Tokenizer) -> (err: Error) {
return .Premature_EOF return .Premature_EOF
} }
/* // Scan until the end of a CDATA tag.
Scan until the end of a CDATA tag.
*/
if t.read_offset + len(CDATA_END) < len(t.src) { if t.read_offset + len(CDATA_END) < len(t.src) {
if string(t.src[t.offset:][:len(CDATA_END)]) == CDATA_END { if string(t.src[t.offset:][:len(CDATA_END)]) == CDATA_END {
t.read_offset += len(CDATA_END) t.read_offset += len(CDATA_END)
@@ -319,14 +311,10 @@ scan_string :: proc(t: ^Tokenizer, offset: int, close: rune = '<', consume_close
case '<': case '<':
if peek_byte(t) == '!' { if peek_byte(t) == '!' {
if peek_byte(t, 1) == '[' { if peek_byte(t, 1) == '[' {
/* // Might be the start of a CDATA tag.
Might be the start of a CDATA tag.
*/
skip_cdata(t) or_return skip_cdata(t) or_return
} else if peek_byte(t, 1) == '-' && peek_byte(t, 2) == '-' { } else if peek_byte(t, 1) == '-' && peek_byte(t, 2) == '-' {
/* // Comment start. Eat comment.
Comment start. Eat comment.
*/
t.read_offset += 3 t.read_offset += 3
_ = scan_comment(t) or_return _ = scan_comment(t) or_return
} }
@@ -342,17 +330,13 @@ scan_string :: proc(t: ^Tokenizer, offset: int, close: rune = '<', consume_close
} }
if t.ch == close { if t.ch == close {
/* // If it's not a CDATA or comment, it's the end of this body.
If it's not a CDATA or comment, it's the end of this body.
*/
break loop break loop
} }
advance_rune(t) advance_rune(t)
} }
/* // Strip trailing whitespace.
Strip trailing whitespace.
*/
lit := string(t.src[offset : t.offset]) lit := string(t.src[offset : t.offset])
end := len(lit) end := len(lit)
@@ -369,11 +353,6 @@ scan_string :: proc(t: ^Tokenizer, offset: int, close: rune = '<', consume_close
if consume_close { if consume_close {
advance_rune(t) advance_rune(t)
} }
/*
TODO: Handle decoding escape characters and unboxing CDATA.
*/
return lit, err return lit, err
} }
@@ -384,7 +363,7 @@ peek :: proc(t: ^Tokenizer) -> (token: Token) {
return token return token
} }
scan :: proc(t: ^Tokenizer) -> Token { scan :: proc(t: ^Tokenizer, multiline_string := false) -> Token {
skip_whitespace(t) skip_whitespace(t)
offset := t.offset offset := t.offset
@@ -418,7 +397,7 @@ scan :: proc(t: ^Tokenizer) -> Token {
case '"', '\'': case '"', '\'':
kind = .Invalid kind = .Invalid
lit, err = scan_string(t, t.offset, ch, true, false) lit, err = scan_string(t, t.offset, ch, true, multiline_string)
if err == .None { if err == .None {
kind = .String kind = .String
} }
@@ -435,4 +414,4 @@ scan :: proc(t: ^Tokenizer) -> Token {
lit = string(t.src[offset : t.offset]) lit = string(t.src[offset : t.offset])
} }
return Token{kind, lit, pos} return Token{kind, lit, pos}
} }
+14 -10
View File
@@ -203,9 +203,7 @@ parse_bytes :: proc(data: []u8, options := DEFAULT_OPTIONS, path := "", error_ha
doc.elements = make([dynamic]Element, 1024, 1024, allocator) doc.elements = make([dynamic]Element, 1024, 1024, allocator)
// strings.intern_init(&doc.intern, allocator, allocator) err = .Unexpected_Token
err = .Unexpected_Token
element, parent: Element_ID element, parent: Element_ID
open: Token open: Token
@@ -259,8 +257,8 @@ parse_bytes :: proc(data: []u8, options := DEFAULT_OPTIONS, path := "", error_ha
case .Slash: case .Slash:
// Empty tag. Close it. // Empty tag. Close it.
expect(t, .Gt) or_return expect(t, .Gt) or_return
parent = doc.elements[element].parent parent = doc.elements[element].parent
element = parent element = parent
case: case:
error(t, t.offset, "Expected close tag, got: %#v\n", end_token) error(t, t.offset, "Expected close tag, got: %#v\n", end_token)
@@ -276,8 +274,8 @@ parse_bytes :: proc(data: []u8, options := DEFAULT_OPTIONS, path := "", error_ha
error(t, t.offset, "Mismatched Closing Tag. Expected %v, got %v\n", doc.elements[element].ident, ident.text) error(t, t.offset, "Mismatched Closing Tag. Expected %v, got %v\n", doc.elements[element].ident, ident.text)
return doc, .Mismatched_Closing_Tag return doc, .Mismatched_Closing_Tag
} }
parent = doc.elements[element].parent parent = doc.elements[element].parent
element = parent element = parent
} else if open.kind == .Exclaim { } else if open.kind == .Exclaim {
// <! // <!
@@ -463,8 +461,8 @@ validate_options :: proc(options: Options) -> (validated: Options, err: Error) {
return validated, .None return validated, .None
} }
expect :: proc(t: ^Tokenizer, kind: Token_Kind) -> (tok: Token, err: Error) { expect :: proc(t: ^Tokenizer, kind: Token_Kind, multiline_string := false) -> (tok: Token, err: Error) {
tok = scan(t) tok = scan(t, multiline_string=multiline_string)
if tok.kind == kind { return tok, .None } if tok.kind == kind { return tok, .None }
error(t, t.offset, "Expected \"%v\", got \"%v\".", kind, tok.kind) error(t, t.offset, "Expected \"%v\", got \"%v\".", kind, tok.kind)
@@ -480,7 +478,13 @@ parse_attribute :: proc(doc: ^Document) -> (attr: Attribute, offset: int, err: E
offset = t.offset - len(key.text) offset = t.offset - len(key.text)
_ = expect(t, .Eq) or_return _ = expect(t, .Eq) or_return
value := expect(t, .String) or_return value := expect(t, .String, multiline_string=true) or_return
normalized, normalize_err := entity.decode_xml(value.text, {.Normalize_Whitespace}, doc.allocator)
if normalize_err == .None {
append(&doc.strings_to_free, normalized)
value.text = normalized
}
attr.key = key.text attr.key = key.text
attr.val = value.text attr.val = value.text
+1
View File
@@ -9,6 +9,7 @@ The verbs:
General: General:
%v the value in a default format %v the value in a default format
%#v an expanded format of %v with newlines and indentation %#v an expanded format of %v with newlines and indentation
%w an Odin-syntax representation of the value
%T an Odin-syntax representation of the type of the value %T an Odin-syntax representation of the type of the value
%% a literal percent sign; consumes no value %% a literal percent sign; consumes no value
{{ a literal open brace; consumes no value {{ a literal open brace; consumes no value
+57
View File
@@ -0,0 +1,57 @@
//+build ignore
package custom_formatter_example
import "core:fmt"
import "core:io"
SomeType :: struct {
value: int,
}
My_Custom_Base_Type :: distinct u32
main :: proc() {
// Ensure the fmt._user_formatters map is initialized
fmt.set_user_formatters(new(map[typeid]fmt.User_Formatter))
// Register custom formatters for my favorite types
err := fmt.register_user_formatter(type_info_of(SomeType).id, SomeType_Formatter)
assert(err == .None)
err = fmt.register_user_formatter(type_info_of(My_Custom_Base_Type).id, My_Custom_Base_Formatter)
assert(err == .None)
// Use the custom formatters.
fmt.printfln("SomeType{{42}}: '%v'", SomeType{42})
fmt.printfln("My_Custom_Base_Type(0xdeadbeef): '%v'", My_Custom_Base_Type(0xdeadbeef))
}
SomeType_Formatter :: proc(fi: ^fmt.Info, arg: any, verb: rune) -> bool {
m := cast(^SomeType)arg.data
switch verb {
case 'v', 'd': // We handle `%v` and `%d`
fmt.fmt_int(fi, u64(m.value), true, 8 * size_of(SomeType), verb)
case:
return false
}
return true
}
My_Custom_Base_Formatter :: proc(fi: ^fmt.Info, arg: any, verb: rune) -> bool {
m := cast(^My_Custom_Base_Type)arg.data
switch verb {
case 'v', 'b':
value := u64(m^)
for value > 0 {
if value & 1 == 1 {
io.write_string(fi.writer, "Hellope!", &fi.n)
} else {
io.write_string(fi.writer, "Hellope?", &fi.n)
}
value >>= 1
}
case:
return false
}
return true
}
+16 -6
View File
@@ -1726,10 +1726,12 @@ fmt_bit_set :: proc(fi: ^Info, v: any, name: string = "", verb: rune = 'v') {
et := runtime.type_info_base(info.elem) et := runtime.type_info_base(info.elem)
if name != "" { if verb != 'w' {
io.write_string(fi.writer, name, &fi.n) if name != "" {
} else { io.write_string(fi.writer, name, &fi.n)
reflect.write_type(fi.writer, type_info, &fi.n) } else {
reflect.write_type(fi.writer, type_info, &fi.n)
}
} }
io.write_byte(fi.writer, '{', &fi.n) io.write_byte(fi.writer, '{', &fi.n)
defer io.write_byte(fi.writer, '}', &fi.n) defer io.write_byte(fi.writer, '}', &fi.n)
@@ -1746,9 +1748,17 @@ fmt_bit_set :: proc(fi: ^Info, v: any, name: string = "", verb: rune = 'v') {
} }
if is_enum { if is_enum {
enum_name: string
if ti_named, is_named := info.elem.variant.(runtime.Type_Info_Named); is_named {
enum_name = ti_named.name
}
for ev, evi in e.values { for ev, evi in e.values {
v := u64(ev) v := u64(ev)
if v == u64(i) { if v == u64(i) {
if verb == 'w' {
io.write_string(fi.writer, enum_name, &fi.n)
io.write_byte(fi.writer, '.', &fi.n)
}
io.write_string(fi.writer, e.names[evi], &fi.n) io.write_string(fi.writer, e.names[evi], &fi.n)
commas += 1 commas += 1
continue loop continue loop
@@ -2391,7 +2401,6 @@ fmt_named :: proc(fi: ^Info, v: any, verb: rune, info: runtime.Type_Info_Named)
runtime.Type_Info_Dynamic_Array, runtime.Type_Info_Dynamic_Array,
runtime.Type_Info_Slice, runtime.Type_Info_Slice,
runtime.Type_Info_Struct, runtime.Type_Info_Struct,
runtime.Type_Info_Union,
runtime.Type_Info_Enum, runtime.Type_Info_Enum,
runtime.Type_Info_Map, runtime.Type_Info_Map,
runtime.Type_Info_Bit_Set, runtime.Type_Info_Bit_Set,
@@ -2498,8 +2507,9 @@ fmt_matrix :: proc(fi: ^Info, v: any, verb: rune, info: runtime.Type_Info_Matrix
} }
} else { } else {
// Printed in Row-Major layout to match text layout // Printed in Row-Major layout to match text layout
row_separator := ", " if verb == 'w' else "; "
for row in 0..<info.row_count { for row in 0..<info.row_count {
if row > 0 { io.write_string(fi.writer, "; ", &fi.n) } if row > 0 { io.write_string(fi.writer, row_separator, &fi.n) }
for col in 0..<info.column_count { for col in 0..<info.column_count {
if col > 0 { io.write_string(fi.writer, ", ", &fi.n) } if col > 0 { io.write_string(fi.writer, ", ", &fi.n) }
+49 -12
View File
@@ -112,15 +112,15 @@ EOWNERDEAD: Errno : 96
O_RDONLY :: 0x00000 O_RDONLY :: 0x00000
O_WRONLY :: 0x00001 O_WRONLY :: 0x00001
O_RDWR :: 0x00002 O_RDWR :: 0x00002
O_CREATE :: 0x00040 O_NONBLOCK :: 0x00004
O_EXCL :: 0x00080 O_APPEND :: 0x00008
O_NOCTTY :: 0x00100 O_ASYNC :: 0x00040
O_TRUNC :: 0x00200 O_SYNC :: 0x00080
O_NONBLOCK :: 0x00800 O_CREATE :: 0x00200
O_APPEND :: 0x00400 O_TRUNC :: 0x00400
O_SYNC :: 0x01000 O_EXCL :: 0x00800
O_ASYNC :: 0x02000 O_NOCTTY :: 0x08000
O_CLOEXEC :: 0x80000 O_CLOEXEC :: 0100000
SEEK_DATA :: 3 SEEK_DATA :: 3
@@ -140,6 +140,8 @@ RTLD_NOLOAD :: 0x02000
MAX_PATH :: 1024 MAX_PATH :: 1024
KINFO_FILE_SIZE :: 1392
args := _alloc_command_line_arguments() args := _alloc_command_line_arguments()
Unix_File_Time :: struct { Unix_File_Time :: struct {
@@ -191,6 +193,21 @@ OS_Stat :: struct {
lspare: [10]u64, lspare: [10]u64,
} }
KInfo_File :: struct {
structsize: c.int,
type: c.int,
fd: c.int,
ref_count: c.int,
flags: c.int,
pad0: c.int,
offset: i64,
// NOTE(Feoramund): This field represents a complicated union that I am
// avoiding implementing for now. I only need the path data below.
_union: [336]byte,
path: [MAX_PATH]c.char,
}
// since FreeBSD v12 // since FreeBSD v12
Dirent :: struct { Dirent :: struct {
@@ -254,6 +271,8 @@ X_OK :: 1 // Test for execute permission
W_OK :: 2 // Test for write permission W_OK :: 2 // Test for write permission
R_OK :: 4 // Test for read permission R_OK :: 4 // Test for read permission
F_KINFO :: 22
foreign libc { foreign libc {
@(link_name="__error") __errno_location :: proc() -> ^c.int --- @(link_name="__error") __errno_location :: proc() -> ^c.int ---
@@ -274,6 +293,7 @@ foreign libc {
@(link_name="unlink") _unix_unlink :: proc(path: cstring) -> c.int --- @(link_name="unlink") _unix_unlink :: proc(path: cstring) -> c.int ---
@(link_name="rmdir") _unix_rmdir :: proc(path: cstring) -> c.int --- @(link_name="rmdir") _unix_rmdir :: proc(path: cstring) -> c.int ---
@(link_name="mkdir") _unix_mkdir :: proc(path: cstring, mode: mode_t) -> c.int --- @(link_name="mkdir") _unix_mkdir :: proc(path: cstring, mode: mode_t) -> c.int ---
@(link_name="fcntl") _unix_fcntl :: proc(fd: Handle, cmd: c.int, arg: uintptr) -> c.int ---
@(link_name="fdopendir") _unix_fdopendir :: proc(fd: Handle) -> Dir --- @(link_name="fdopendir") _unix_fdopendir :: proc(fd: Handle) -> Dir ---
@(link_name="closedir") _unix_closedir :: proc(dirp: Dir) -> c.int --- @(link_name="closedir") _unix_closedir :: proc(dirp: Dir) -> c.int ---
@@ -365,7 +385,7 @@ seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
} }
file_size :: proc(fd: Handle) -> (i64, Errno) { file_size :: proc(fd: Handle) -> (i64, Errno) {
s, err := fstat(fd) s, err := _fstat(fd)
if err != ERROR_NONE { if err != ERROR_NONE {
return -1, err return -1, err
} }
@@ -591,9 +611,26 @@ _readlink :: proc(path: string) -> (string, Errno) {
return "", Errno{} return "", Errno{}
} }
// XXX FreeBSD
absolute_path_from_handle :: proc(fd: Handle) -> (string, Errno) { absolute_path_from_handle :: proc(fd: Handle) -> (string, Errno) {
return "", Errno(ENOSYS) // NOTE(Feoramund): The situation isn't ideal, but this was the best way I
// could find to implement this. There are a couple outstanding bug reports
// regarding the desire to retrieve an absolute path from a handle, but to
// my knowledge, there hasn't been any work done on it.
//
// https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=198570
//
// This may be unreliable, according to a comment from 2023.
kinfo: KInfo_File
kinfo.structsize = KINFO_FILE_SIZE
res := _unix_fcntl(fd, F_KINFO, cast(uintptr)&kinfo)
if res == -1 {
return "", Errno(get_last_error())
}
path := strings.clone_from_cstring_bounded(cast(cstring)&kinfo.path[0], len(kinfo.path))
return path, ERROR_NONE
} }
absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) { absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) {
+1 -1
View File
@@ -56,7 +56,7 @@ foreign libc {
@(link_name="free") _unix_free :: proc(ptr: rawptr) --- @(link_name="free") _unix_free :: proc(ptr: rawptr) ---
} }
when ODIN_OS == .Darwin { when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD {
@(private) @(private)
foreign libc { foreign libc {
@(link_name="__error") __error :: proc() -> ^i32 --- @(link_name="__error") __error :: proc() -> ^i32 ---
Regular → Executable
+13
View File
@@ -1156,6 +1156,19 @@ foreign kernel32 {
SetCommState :: proc(handle: HANDLE, dcb: ^DCB) -> BOOL --- SetCommState :: proc(handle: HANDLE, dcb: ^DCB) -> BOOL ---
} }
COMMTIMEOUTS :: struct {
ReadIntervalTimeout: DWORD,
ReadTotalTimeoutMultiplier: DWORD,
ReadTotalTimeoutConstant: DWORD,
WriteTotalTimeoutMultiplier: DWORD,
WriteTotalTimeoutConstant: DWORD,
}
@(default_calling_convention="system")
foreign kernel32 {
GetCommTimeouts :: proc(handle: HANDLE, timeouts: ^COMMTIMEOUTS) -> BOOL ---
SetCommTimeouts :: proc(handle: HANDLE, timeouts: ^COMMTIMEOUTS) -> BOOL ---
}
LPFIBER_START_ROUTINE :: #type proc "system" (lpFiberParameter: LPVOID) LPFIBER_START_ROUTINE :: #type proc "system" (lpFiberParameter: LPVOID)
+2 -2
View File
@@ -127,13 +127,13 @@ days_remaining :: proc "contextless" (date: Date) -> (days_remaining: i64, err:
return delta.days, .None return delta.days, .None
} }
last_day_of_month :: proc "contextless" (#any_int year: i64, #any_int month: i8) -> (day: i64, err: Error) { last_day_of_month :: proc "contextless" (#any_int year: i64, #any_int month: i8) -> (day: i8, err: Error) {
// Not using formula 2.27 from the book. This is far simpler and gives the same answer. // Not using formula 2.27 from the book. This is far simpler and gives the same answer.
validate(Date{year, month, 1}) or_return validate(Date{year, month, 1}) or_return
month_days := MONTH_DAYS month_days := MONTH_DAYS
day = i64(month_days[month]) day = month_days[month]
if month == 2 && is_leap_year(year) { if month == 2 && is_leap_year(year) {
day += 1 day += 1
} }
+11 -1
View File
@@ -89,6 +89,9 @@ gb_internal Type *check_init_variable(CheckerContext *ctx, Entity *e, Operand *o
return nullptr; return nullptr;
} else if (is_type_polymorphic(t)) { } else if (is_type_polymorphic(t)) {
Entity *e = entity_of_node(operand->expr); Entity *e = entity_of_node(operand->expr);
if (e == nullptr) {
return nullptr;
}
if (e->state.load() != EntityState_Resolved) { if (e->state.load() != EntityState_Resolved) {
gbString str = type_to_string(t); gbString str = type_to_string(t);
defer (gb_string_free(str)); defer (gb_string_free(str));
@@ -1142,7 +1145,14 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
} }
if (ac.link_name.len > 0) { if (ac.link_name.len > 0) {
e->Procedure.link_name = ac.link_name; String ln = ac.link_name;
e->Procedure.link_name = ln;
if (ln == "memcpy" ||
ln == "memmove" ||
ln == "mem_copy" ||
ln == "mem_copy_non_overlapping") {
e->Procedure.is_memcpy_like = true;
}
} }
if (ac.deferred_procedure.entity != nullptr) { if (ac.deferred_procedure.entity != nullptr) {
+4 -1
View File
@@ -2550,7 +2550,7 @@ gb_internal void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast *
error_line("\tSuggestion: Did you want to pass the iterable value to the for statement by pointer to get addressable semantics?\n"); error_line("\tSuggestion: Did you want to pass the iterable value to the for statement by pointer to get addressable semantics?\n");
} }
if (is_type_map(parent_type)) { if (parent_type != nullptr && is_type_map(parent_type)) {
error_line("\t Prefer doing 'for key, &%.*s in ...'\n", LIT(e->token.string)); error_line("\t Prefer doing 'for key, &%.*s in ...'\n", LIT(e->token.string));
} else { } else {
error_line("\t Prefer doing 'for &%.*s in ...'\n", LIT(e->token.string)); error_line("\t Prefer doing 'for &%.*s in ...'\n", LIT(e->token.string));
@@ -3564,6 +3564,9 @@ gb_internal void check_binary_matrix(CheckerContext *c, Token const &op, Operand
x->mode = Addressing_Value; x->mode = Addressing_Value;
if (are_types_identical(xt, yt)) { if (are_types_identical(xt, yt)) {
if (are_types_identical(x->type, y->type)) {
return;
}
if (!is_type_named(x->type) && is_type_named(y->type)) { if (!is_type_named(x->type) && is_type_named(y->type)) {
// prefer the named type // prefer the named type
x->type = y->type; x->type = y->type;
+1
View File
@@ -256,6 +256,7 @@ struct Entity {
bool generated_from_polymorphic : 1; bool generated_from_polymorphic : 1;
bool entry_point_only : 1; bool entry_point_only : 1;
bool has_instrumentation : 1; bool has_instrumentation : 1;
bool is_memcpy_like : 1;
} Procedure; } Procedure;
struct { struct {
Array<Entity *> entities; Array<Entity *> entities;
+136 -108
View File
@@ -9,6 +9,11 @@
#endif #endif
#ifndef LLVM_IGNORE_VERIFICATION
#define LLVM_IGNORE_VERIFICATION 0
#endif
#include "llvm_backend.hpp" #include "llvm_backend.hpp"
#include "llvm_abi.cpp" #include "llvm_abi.cpp"
#include "llvm_backend_opt.cpp" #include "llvm_backend_opt.cpp"
@@ -1125,6 +1130,53 @@ gb_internal void lb_finalize_objc_names(lbProcedure *p) {
lb_end_procedure_body(p); lb_end_procedure_body(p);
} }
gb_internal void lb_verify_function(lbModule *m, lbProcedure *p, bool dump_ll=false) {
if (LLVM_IGNORE_VERIFICATION) {
return;
}
if (!m->debug_builder && LLVMVerifyFunction(p->value, LLVMReturnStatusAction)) {
char *llvm_error = nullptr;
gb_printf_err("LLVM CODE GEN FAILED FOR PROCEDURE: %.*s\n", LIT(p->name));
LLVMDumpValue(p->value);
gb_printf_err("\n");
if (dump_ll) {
gb_printf_err("\n\n\n");
String filepath_ll = lb_filepath_ll_for_module(m);
if (LLVMPrintModuleToFile(m->mod, cast(char const *)filepath_ll.text, &llvm_error)) {
gb_printf_err("LLVM Error: %s\n", llvm_error);
}
}
LLVMVerifyFunction(p->value, LLVMPrintMessageAction);
exit_with_errors();
}
}
gb_internal WORKER_TASK_PROC(lb_llvm_module_verification_worker_proc) {
char *llvm_error = nullptr;
defer (LLVMDisposeMessage(llvm_error));
lbModule *m = cast(lbModule *)data;
if (LLVMVerifyModule(m->mod, LLVMReturnStatusAction, &llvm_error)) {
gb_printf_err("LLVM Error:\n%s\n", llvm_error);
if (build_context.keep_temp_files) {
TIME_SECTION("LLVM Print Module to File");
String filepath_ll = lb_filepath_ll_for_module(m);
if (LLVMPrintModuleToFile(m->mod, cast(char const *)filepath_ll.text, &llvm_error)) {
gb_printf_err("LLVM Error: %s\n", llvm_error);
exit_with_errors();
return false;
}
}
exit_with_errors();
return 1;
}
return 0;
}
gb_internal lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProcedure *objc_names, Array<lbGlobalVariable> &global_variables) { // Startup Runtime gb_internal lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProcedure *objc_names, Array<lbGlobalVariable> &global_variables) { // Startup Runtime
Type *proc_type = alloc_type_proc(nullptr, nullptr, 0, nullptr, 0, false, ProcCC_Odin); Type *proc_type = alloc_type_proc(nullptr, nullptr, 0, nullptr, 0, false, ProcCC_Odin);
@@ -1227,13 +1279,7 @@ gb_internal lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProc
lb_end_procedure_body(p); lb_end_procedure_body(p);
if (!main_module->debug_builder && LLVMVerifyFunction(p->value, LLVMReturnStatusAction)) { lb_verify_function(main_module, p);
gb_printf_err("LLVM CODE GEN FAILED FOR PROCEDURE: %s\n", "main");
LLVMDumpValue(p->value);
gb_printf_err("\n\n\n\n");
LLVMVerifyFunction(p->value, LLVMAbortProcessAction);
}
return p; return p;
} }
@@ -1256,31 +1302,21 @@ gb_internal lbProcedure *lb_create_cleanup_runtime(lbModule *main_module) { // C
lb_end_procedure_body(p); lb_end_procedure_body(p);
if (!main_module->debug_builder && LLVMVerifyFunction(p->value, LLVMReturnStatusAction)) { lb_verify_function(main_module, p);
gb_printf_err("LLVM CODE GEN FAILED FOR PROCEDURE: %s\n", "main");
LLVMDumpValue(p->value);
gb_printf_err("\n\n\n\n");
LLVMVerifyFunction(p->value, LLVMAbortProcessAction);
}
return p; return p;
} }
gb_internal WORKER_TASK_PROC(lb_generate_procedures_and_types_per_module) { gb_internal WORKER_TASK_PROC(lb_generate_procedures_and_types_per_module) {
lbModule *m = cast(lbModule *)data; lbModule *m = cast(lbModule *)data;
for (Entity *e : m->global_procedures_and_types_to_create) { for (Entity *e : m->global_types_to_create) {
if (e->kind == Entity_TypeName) { (void)lb_get_entity_name(m, e);
(void)lb_get_entity_name(m, e); (void)lb_type(m, e->type);
lb_type(m, e->type);
}
} }
for (Entity *e : m->global_procedures_and_types_to_create) { for (Entity *e : m->global_procedures_to_create) {
if (e->kind == Entity_Procedure) { (void)lb_get_entity_name(m, e);
(void)lb_get_entity_name(m, e); array_add(&m->procedures_to_generate, lb_create_procedure(m, e));
array_add(&m->procedures_to_generate, lb_create_procedure(m, e));
}
} }
return 0; return 0;
} }
@@ -1334,16 +1370,24 @@ gb_internal void lb_create_global_procedures_and_types(lbGenerator *gen, Checker
m = lb_module_of_entity(gen, e); m = lb_module_of_entity(gen, e);
} }
array_add(&m->global_procedures_and_types_to_create, e); if (e->kind == Entity_Procedure) {
array_add(&m->global_procedures_to_create, e);
} else if (e->kind == Entity_TypeName) {
array_add(&m->global_types_to_create, e);
}
} }
for (auto const &entry : gen->modules) { if (do_threading) {
lbModule *m = entry.value; for (auto const &entry : gen->modules) {
if (do_threading) { lbModule *m = entry.value;
thread_pool_add_task(lb_generate_procedures_and_types_per_module, m); thread_pool_add_task(lb_generate_procedures_and_types_per_module, m);
} else { }
} else {
for (auto const &entry : gen->modules) {
lbModule *m = entry.value;
lb_generate_procedures_and_types_per_module(m); lb_generate_procedures_and_types_per_module(m);
} }
} }
thread_pool_wait(); thread_pool_wait();
@@ -2374,16 +2418,19 @@ gb_internal WORKER_TASK_PROC(lb_generate_procedures_worker_proc) {
} }
gb_internal void lb_generate_procedures(lbGenerator *gen, bool do_threading) { gb_internal void lb_generate_procedures(lbGenerator *gen, bool do_threading) {
for (auto const &entry : gen->modules) { if (do_threading) {
lbModule *m = entry.value; for (auto const &entry : gen->modules) {
if (do_threading) { lbModule *m = entry.value;
thread_pool_add_task(lb_generate_procedures_worker_proc, m); thread_pool_add_task(lb_generate_procedures_worker_proc, m);
} else { }
thread_pool_wait();
} else {
for (auto const &entry : gen->modules) {
lbModule *m = entry.value;
lb_generate_procedures_worker_proc(m); lb_generate_procedures_worker_proc(m);
} }
} }
thread_pool_wait();
} }
gb_internal WORKER_TASK_PROC(lb_generate_missing_procedures_to_check_worker_proc) { gb_internal WORKER_TASK_PROC(lb_generate_missing_procedures_to_check_worker_proc) {
@@ -2397,17 +2444,20 @@ gb_internal WORKER_TASK_PROC(lb_generate_missing_procedures_to_check_worker_proc
} }
gb_internal void lb_generate_missing_procedures(lbGenerator *gen, bool do_threading) { gb_internal void lb_generate_missing_procedures(lbGenerator *gen, bool do_threading) {
for (auto const &entry : gen->modules) { if (do_threading) {
lbModule *m = entry.value; for (auto const &entry : gen->modules) {
// NOTE(bill): procedures may be added during generation lbModule *m = entry.value;
if (do_threading) { // NOTE(bill): procedures may be added during generation
thread_pool_add_task(lb_generate_missing_procedures_to_check_worker_proc, m); thread_pool_add_task(lb_generate_missing_procedures_to_check_worker_proc, m);
} else { }
thread_pool_wait();
} else {
for (auto const &entry : gen->modules) {
lbModule *m = entry.value;
// NOTE(bill): procedures may be added during generation
lb_generate_missing_procedures_to_check_worker_proc(m); lb_generate_missing_procedures_to_check_worker_proc(m);
} }
} }
thread_pool_wait();
} }
gb_internal void lb_debug_info_complete_types_and_finalize(lbGenerator *gen) { gb_internal void lb_debug_info_complete_types_and_finalize(lbGenerator *gen) {
@@ -2420,32 +2470,45 @@ gb_internal void lb_debug_info_complete_types_and_finalize(lbGenerator *gen) {
} }
gb_internal void lb_llvm_function_passes(lbGenerator *gen, bool do_threading) { gb_internal void lb_llvm_function_passes(lbGenerator *gen, bool do_threading) {
for (auto const &entry : gen->modules) { if (do_threading) {
lbModule *m = entry.value; for (auto const &entry : gen->modules) {
if (do_threading) { lbModule *m = entry.value;
thread_pool_add_task(lb_llvm_function_pass_per_module, m); thread_pool_add_task(lb_llvm_function_pass_per_module, m);
} else { }
thread_pool_wait();
} else {
for (auto const &entry : gen->modules) {
lbModule *m = entry.value;
lb_llvm_function_pass_per_module(m); lb_llvm_function_pass_per_module(m);
} }
} }
thread_pool_wait();
} }
gb_internal void lb_llvm_module_passes(lbGenerator *gen, bool do_threading) { gb_internal void lb_llvm_module_passes(lbGenerator *gen, bool do_threading) {
for (auto const &entry : gen->modules) { if (do_threading) {
lbModule *m = entry.value; for (auto const &entry : gen->modules) {
auto wd = gb_alloc_item(permanent_allocator(), lbLLVMModulePassWorkerData); lbModule *m = entry.value;
wd->m = m; auto wd = gb_alloc_item(permanent_allocator(), lbLLVMModulePassWorkerData);
wd->target_machine = m->target_machine; wd->m = m;
wd->target_machine = m->target_machine;
if (do_threading) { if (do_threading) {
thread_pool_add_task(lb_llvm_module_pass_worker_proc, wd); thread_pool_add_task(lb_llvm_module_pass_worker_proc, wd);
} else { } else {
lb_llvm_module_pass_worker_proc(wd);
}
}
thread_pool_wait();
} else {
for (auto const &entry : gen->modules) {
lbModule *m = entry.value;
auto wd = gb_alloc_item(permanent_allocator(), lbLLVMModulePassWorkerData);
wd->m = m;
wd->target_machine = m->target_machine;
lb_llvm_module_pass_worker_proc(wd); lb_llvm_module_pass_worker_proc(wd);
} }
} }
thread_pool_wait();
} }
gb_internal String lb_filepath_ll_for_module(lbModule *m) { gb_internal String lb_filepath_ll_for_module(lbModule *m) {
@@ -2523,40 +2586,27 @@ gb_internal String lb_filepath_obj_for_module(lbModule *m) {
return concatenate_strings(permanent_allocator(), path, ext); return concatenate_strings(permanent_allocator(), path, ext);
} }
gb_internal WORKER_TASK_PROC(lb_llvm_module_verification_worker_proc) {
char *llvm_error = nullptr;
defer (LLVMDisposeMessage(llvm_error));
lbModule *m = cast(lbModule *)data;
if (LLVMVerifyModule(m->mod, LLVMReturnStatusAction, &llvm_error)) {
gb_printf_err("LLVM Error:\n%s\n", llvm_error);
if (build_context.keep_temp_files) {
TIME_SECTION("LLVM Print Module to File");
String filepath_ll = lb_filepath_ll_for_module(m);
if (LLVMPrintModuleToFile(m->mod, cast(char const *)filepath_ll.text, &llvm_error)) {
gb_printf_err("LLVM Error: %s\n", llvm_error);
exit_with_errors();
return false;
}
}
exit_with_errors();
return 1;
}
return 0;
}
gb_internal bool lb_llvm_module_verification(lbGenerator *gen, bool do_threading) { gb_internal bool lb_llvm_module_verification(lbGenerator *gen, bool do_threading) {
for (auto const &entry : gen->modules) { if (LLVM_IGNORE_VERIFICATION) {
lbModule *m = entry.value; return true;
if (do_threading) { }
if (do_threading) {
for (auto const &entry : gen->modules) {
lbModule *m = entry.value;
thread_pool_add_task(lb_llvm_module_verification_worker_proc, m); thread_pool_add_task(lb_llvm_module_verification_worker_proc, m);
} else { }
thread_pool_wait();
} else {
for (auto const &entry : gen->modules) {
lbModule *m = entry.value;
if (lb_llvm_module_verification_worker_proc(m)) { if (lb_llvm_module_verification_worker_proc(m)) {
return false; return false;
} }
} }
} }
thread_pool_wait();
return true; return true;
} }
@@ -2777,12 +2827,7 @@ gb_internal lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *star
} }
if (!m->debug_builder && LLVMVerifyFunction(p->value, LLVMReturnStatusAction)) { lb_verify_function(m, p);
gb_printf_err("LLVM CODE GEN FAILED FOR PROCEDURE: %s\n", "main");
LLVMDumpValue(p->value);
gb_printf_err("\n\n\n\n");
LLVMVerifyFunction(p->value, LLVMAbortProcessAction);
}
lb_run_function_pass_manager(default_function_pass_manager, p, lbFunctionPassManager_default); lb_run_function_pass_manager(default_function_pass_manager, p, lbFunctionPassManager_default);
return p; return p;
@@ -2803,28 +2848,11 @@ gb_internal void lb_generate_procedure(lbModule *m, lbProcedure *p) {
lb_end_procedure(p); lb_end_procedure(p);
// Add Flags // Add Flags
if (p->body != nullptr) { if (p->entity && p->entity->kind == Entity_Procedure && p->entity->Procedure.is_memcpy_like) {
if (p->name == "memcpy" || p->name == "memmove" || p->flags |= lbProcedureFlag_WithoutMemcpyPass;
p->name == "runtime.mem_copy" || p->name == "mem_copy_non_overlapping" ||
string_starts_with(p->name, str_lit("llvm.memcpy")) ||
string_starts_with(p->name, str_lit("llvm.memmove"))) {
p->flags |= lbProcedureFlag_WithoutMemcpyPass;
}
} }
if (!m->debug_builder && LLVMVerifyFunction(p->value, LLVMReturnStatusAction)) { lb_verify_function(m, p, true);
char *llvm_error = nullptr;
gb_printf_err("LLVM CODE GEN FAILED FOR PROCEDURE: %.*s\n", LIT(p->name));
LLVMDumpValue(p->value);
gb_printf_err("\n\n\n\n");
String filepath_ll = lb_filepath_ll_for_module(m);
if (LLVMPrintModuleToFile(m->mod, cast(char const *)filepath_ll.text, &llvm_error)) {
gb_printf_err("LLVM Error: %s\n", llvm_error);
}
LLVMVerifyFunction(p->value, LLVMPrintMessageAction);
exit_with_errors();
}
} }
+2 -1
View File
@@ -181,7 +181,8 @@ struct lbModule {
std::atomic<u32> nested_type_name_guid; std::atomic<u32> nested_type_name_guid;
Array<lbProcedure *> procedures_to_generate; Array<lbProcedure *> procedures_to_generate;
Array<Entity *> global_procedures_and_types_to_create; Array<Entity *> global_procedures_to_create;
Array<Entity *> global_types_to_create;
lbProcedure *curr_procedure; lbProcedure *curr_procedure;
+2 -1
View File
@@ -78,7 +78,8 @@ gb_internal void lb_init_module(lbModule *m, Checker *c) {
array_init(&m->procedures_to_generate, a, 0, c->info.all_procedures.count); array_init(&m->procedures_to_generate, a, 0, c->info.all_procedures.count);
map_init(&m->procedure_values, c->info.all_procedures.count*2); map_init(&m->procedure_values, c->info.all_procedures.count*2);
} }
array_init(&m->global_procedures_and_types_to_create, a, 0, 1024); array_init(&m->global_procedures_to_create, a, 0, 1024);
array_init(&m->global_types_to_create, a, 0, 1024);
array_init(&m->missing_procedures_to_check, a, 0, 16); array_init(&m->missing_procedures_to_check, a, 0, 16);
map_init(&m->debug_values); map_init(&m->debug_values);
+2 -1
View File
@@ -2934,7 +2934,8 @@ int main(int arg_count, char const **arg_ptr) {
// TODO(jeroen): Remove the `init_filename` param. // TODO(jeroen): Remove the `init_filename` param.
// Let's put that on `build_context.build_paths[0]` instead. // Let's put that on `build_context.build_paths[0]` instead.
if (parse_packages(parser, init_filename) != ParseFile_None) { if (parse_packages(parser, init_filename) != ParseFile_None) {
return 1; GB_ASSERT_MSG(any_errors(), "parse_packages failed but no error was reported.");
// We depend on the next conditional block to return 1, after printing errors.
} }
if (any_errors()) { if (any_errors()) {
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE foozle>
<foozle>Barzle</foozle>
<부끄러운:barzle>
<name foo:bar=" birmese
kittens have
fur ">Indeed!</name>
</부끄러운:barzle>
+19 -5
View File
@@ -36,7 +36,7 @@ xml_test_utf8_normal :: proc(t: ^testing.T) {
}, },
expected_doctype = "恥ずべきフクロウ", expected_doctype = "恥ずべきフクロウ",
}, },
crc32 = 0xe9b62f03, crc32 = 0xefa55f27,
}) })
} }
@@ -52,7 +52,7 @@ xml_test_utf8_unbox_cdata :: proc(t: ^testing.T) {
}, },
expected_doctype = "恥ずべきフクロウ", expected_doctype = "恥ずべきフクロウ",
}, },
crc32 = 0x9c2643ed, crc32 = 0x2dd27770,
}) })
} }
@@ -128,7 +128,7 @@ xml_test_entities_unbox :: proc(t: ^testing.T) {
}, },
expected_doctype = "html", expected_doctype = "html",
}, },
crc32 = 0x3b6d4a90, crc32 = 0x350ca83e,
}) })
} }
@@ -142,7 +142,21 @@ xml_test_entities_unbox_decode :: proc(t: ^testing.T) {
}, },
expected_doctype = "html", expected_doctype = "html",
}, },
crc32 = 0x5be2ffdc, crc32 = 0x7f58db7d,
})
}
@(test)
xml_test_attribute_whitespace :: proc(t: ^testing.T) {
run_test(t, {
// Same as above.
// Unbox CDATA in data tag.
filename = "XML/attribute-whitespace.xml",
options = {
flags = {},
expected_doctype = "foozle",
},
crc32 = 0x8f5fd6c1,
}) })
} }
@@ -172,7 +186,7 @@ xml_test_unicode :: proc(t: ^testing.T) {
expected_doctype = "", expected_doctype = "",
}, },
err = .None, err = .None,
crc32 = 0x0b6100ab, crc32 = 0x73070b55,
}) })
} }
+114
View File
@@ -258,6 +258,120 @@ test_pointers :: proc(t: ^testing.T) {
check(t, "0xFFFF", "%#4p", d) check(t, "0xFFFF", "%#4p", d)
} }
@(test)
test_odin_value_export :: proc(t: ^testing.T) {
E :: enum u32 {
A, B, C,
}
F :: enum i16 {
A, B, F,
}
S :: struct {
j, k: int,
}
ST :: struct {
x: int `fmt:"-"`,
y: u8 `fmt:"r,0"`,
z: string `fmt:"s,0"`,
}
U :: union {
i8,
i16,
}
UEF :: union { E, F }
A :: [2]int
BSE :: distinct bit_set[E]
i : int = 64
f : f64 = 3.14
c : complex128 = 7+3i
q : quaternion256 = 1+2i+3j+4k
mat : matrix[2,3]f32 = {1.5, 2, 1, 0.777, 0.333, 0.8}
matc : #column_major matrix[2,3]f32 = {1.5, 2, 1, 0.777, 0.333, 0.8}
e : enum {A, B, C} = .B
en : E = E.C
ena : [2]E = {E.A, E.C}
s : struct { j: int, k: int } = { j = 16, k = 8 }
sn : S = S{ j = 24, k = 12 }
st : ST = { 32768, 57, "Hellope" }
str : string = "Hellope"
strc : cstring = "Hellope"
bsu : bit_set[0..<32; u32] = {0, 1}
bs : bit_set[4..<16] = {5, 7}
bse : bit_set[E] = { .B, .A }
bsE : BSE = { .A, .C }
arr : [3]int = {1, 2, 3}
ars : [3]S = {S{j = 3, k = 2}, S{j = 2, k = 1}, S{j = 1, k = 0}}
darr : [dynamic]u8 = { 128, 64, 32 }
dars : [dynamic]S = {S{j = 1, k = 2}, S{j = 3, k = 4}}
na : A = {7, 5}
may0 : Maybe(int)
may1 : Maybe(int) = 1
uz : union {i8, i16} = i8(-33)
u0 : U = U(nil)
u1 : U = i16(42)
uef0 : UEF = E.A
uefa : [3]UEF = { E.A, F.A, F.F }
map_ : map[string]u8 = {"foo" = 8, "bar" = 4}
bf : bit_field int {
a: int | 4,
b: int | 4,
e: E | 4,
} = {a = 1, b = 2, e = .A}
defer {
delete(darr)
delete(dars)
delete(map_)
}
check(t, "64", "%w", i)
check(t, "3.14", "%w", f)
check(t, "7+3i", "%w", c)
check(t, "1+2i+3j+4k", "%w", q)
check(t, "{1.5, 2, 1, 0.777, 0.333, 0.8}", "%w", mat)
check(t, "{1.5, 2, 1, 0.777, 0.333, 0.8}", "%w", matc)
check(t, ".B", "%w", e)
check(t, "E.C", "%w", en)
check(t, "{E.A, E.C}", "%w", ena)
check(t, "{j = 16, k = 8}", "%w", s)
check(t, "S{j = 24, k = 12}", "%w", sn)
check(t, `ST{y = 57, z = "Hellope"}`, "%w", st)
check(t, `"Hellope"`, "%w", str)
check(t, `"Hellope"`, "%w", strc)
check(t, "{0, 1}", "%w", bsu)
check(t, "{5, 7}", "%w", bs)
check(t, "{E.A, E.B}", "%w", bse)
check(t, "{E.A, E.C}", "%w", bsE)
check(t, "{1, 2, 3}", "%w", arr)
check(t, "{S{j = 3, k = 2}, S{j = 2, k = 1}, S{j = 1, k = 0}}", "%w", ars)
check(t, "{128, 64, 32}", "%w", darr)
check(t, "{S{j = 1, k = 2}, S{j = 3, k = 4}}", "%w", dars)
check(t, "{7, 5}", "%w", na)
check(t, "nil", "%w", may0)
check(t, "1", "%w", may1)
check(t, "-33", "%w", uz)
check(t, "nil", "%w", u0)
check(t, "42", "%w", u1)
check(t, "E.A", "%w", uef0)
check(t, "{E.A, F.A, F.F}", "%w", uefa)
check(t, "{a = 1, b = 2, e = E.A}", "%w", bf)
// Check this manually due to the non-deterministic ordering of map keys.
switch fmt.tprintf("%w", map_) {
case `{"foo"=8, "bar"=4}`: break
case `{"bar"=4, "foo"=8}`: break
case: testing.fail(t)
}
}
@(private) @(private)
check :: proc(t: ^testing.T, exp: string, format: string, args: ..any, loc := #caller_location) { check :: proc(t: ^testing.T, exp: string, format: string, args: ..any, loc := #caller_location) {
got := fmt.tprintf(format, ..args) got := fmt.tprintf(format, ..args)
+1 -1
View File
@@ -8,7 +8,7 @@
A test suite for `core:net` A test suite for `core:net`
*/ */
//+build !netbsd //+build !netbsd !freebsd !openbsd
package test_core_net package test_core_net
import "core:testing" import "core:testing"
+8 -6
View File
@@ -984,12 +984,14 @@ foreign lib {
LoadShader :: proc(vsFileName, fsFileName: cstring) -> Shader --- // Load shader from files and bind default locations LoadShader :: proc(vsFileName, fsFileName: cstring) -> Shader --- // Load shader from files and bind default locations
LoadShaderFromMemory :: proc(vsCode, fsCode: cstring) -> Shader --- // Load shader from code strings and bind default locations LoadShaderFromMemory :: proc(vsCode, fsCode: cstring) -> Shader --- // Load shader from code strings and bind default locations
IsShaderReady :: proc(shader: Shader) -> bool --- // Check if a shader is ready IsShaderReady :: proc(shader: Shader) -> bool --- // Check if a shader is ready
GetShaderLocation :: proc(shader: Shader, uniformName: cstring) -> ShaderLocationIndex --- // Get shader uniform location GetShaderLocation :: proc(shader: Shader, uniformName: cstring) -> c.int --- // Get shader uniform location
GetShaderLocationAttrib :: proc(shader: Shader, attribName: cstring) -> ShaderLocationIndex --- // Get shader attribute location GetShaderLocationAttrib :: proc(shader: Shader, attribName: cstring) -> c.int --- // Get shader attribute location
SetShaderValue :: proc(shader: Shader, locIndex: ShaderLocationIndex, value: rawptr, uniformType: ShaderUniformDataType) --- // Set shader uniform value
SetShaderValueV :: proc(shader: Shader, locIndex: ShaderLocationIndex, value: rawptr, uniformType: ShaderUniformDataType, count: c.int) --- // Set shader uniform value vector // We use #any_int here so we can pass ShaderLocationIndex
SetShaderValueMatrix :: proc(shader: Shader, locIndex: ShaderLocationIndex, mat: Matrix) --- // Set shader uniform value (matrix 4x4) SetShaderValue :: proc(shader: Shader, #any_int locIndex: c.int, value: rawptr, uniformType: ShaderUniformDataType) --- // Set shader uniform value
SetShaderValueTexture :: proc(shader: Shader, locIndex: ShaderLocationIndex, texture: Texture2D) --- // Set shader uniform value for texture (sampler2d) SetShaderValueV :: proc(shader: Shader, #any_int locIndex: c.int, value: rawptr, uniformType: ShaderUniformDataType, count: c.int) --- // Set shader uniform value vector
SetShaderValueMatrix :: proc(shader: Shader, #any_int locIndex: c.int, mat: Matrix) --- // Set shader uniform value (matrix 4x4)
SetShaderValueTexture :: proc(shader: Shader, #any_int locIndex: c.int, texture: Texture2D) --- // Set shader uniform value for texture (sampler2d)
UnloadShader :: proc(shader: Shader) --- // Unload shader from GPU memory (VRAM) UnloadShader :: proc(shader: Shader) --- // Unload shader from GPU memory (VRAM)
// Screen-space-related functions // Screen-space-related functions
+1 -1
View File
@@ -668,7 +668,7 @@ MatrixLookAt :: proc "c" (eye, target, up: Vector3) -> Matrix {
// Get float array of matrix data // Get float array of matrix data
@(require_results) @(require_results)
MatrixToFloatV :: proc "c" (mat: Matrix) -> [16]f32 { MatrixToFloatV :: proc "c" (mat: Matrix) -> [16]f32 {
return transmute([16]f32)mat return transmute([16]f32)linalg.transpose(mat)
} }
-555
View File
@@ -1,555 +0,0 @@
/**********************************************************************************************
*
* rlgl v5.0 - A multi-OpenGL abstraction layer with an immediate-mode style API
*
* DESCRIPTION:
* An abstraction layer for multiple OpenGL versions (1.1, 2.1, 3.3 Core, 4.3 Core, ES 2.0)
* that provides a pseudo-OpenGL 1.1 immediate-mode style API (rlVertex, rlTranslate, rlRotate...)
*
* ADDITIONAL NOTES:
* When choosing an OpenGL backend different than OpenGL 1.1, some internal buffer are
* initialized on rlglInit() to accumulate vertex data.
*
* When an internal state change is required all the stored vertex data is renderer in batch,
* additionally, rlDrawRenderBatchActive() could be called to force flushing of the batch.
*
* Some resources are also loaded for convenience, here the complete list:
* - Default batch (RLGL.defaultBatch): RenderBatch system to accumulate vertex data
* - Default texture (RLGL.defaultTextureId): 1x1 white pixel R8G8B8A8
* - Default shader (RLGL.State.defaultShaderId, RLGL.State.defaultShaderLocs)
*
* Internal buffer (and resources) must be manually unloaded calling rlglClose().
*
* CONFIGURATION:
* #define GRAPHICS_API_OPENGL_11
* #define GRAPHICS_API_OPENGL_21
* #define GRAPHICS_API_OPENGL_33
* #define GRAPHICS_API_OPENGL_43
* #define GRAPHICS_API_OPENGL_ES2
* #define GRAPHICS_API_OPENGL_ES3
* Use selected OpenGL graphics backend, should be supported by platform
* Those preprocessor defines are only used on rlgl module, if OpenGL version is
* required by any other module, use rlGetVersion() to check it
*
* #define RLGL_IMPLEMENTATION
* Generates the implementation of the library into the included file.
* If not defined, the library is in header only mode and can be included in other headers
* or source files without problems. But only ONE file should hold the implementation.
*
* #define RLGL_RENDER_TEXTURES_HINT
* Enable framebuffer objects (fbo) support (enabled by default)
* Some GPUs could not support them despite the OpenGL version
*
* #define RLGL_SHOW_GL_DETAILS_INFO
* Show OpenGL extensions and capabilities detailed logs on init
*
* #define RLGL_ENABLE_OPENGL_DEBUG_CONTEXT
* Enable debug context (only available on OpenGL 4.3)
*
* rlgl capabilities could be customized just defining some internal
* values before library inclusion (default values listed):
*
* #define RL_DEFAULT_BATCH_BUFFER_ELEMENTS 8192 // Default internal render batch elements limits
* #define RL_DEFAULT_BATCH_BUFFERS 1 // Default number of batch buffers (multi-buffering)
* #define RL_DEFAULT_BATCH_DRAWCALLS 256 // Default number of batch draw calls (by state changes: mode, texture)
* #define RL_DEFAULT_BATCH_MAX_TEXTURE_UNITS 4 // Maximum number of textures units that can be activated on batch drawing (SetShaderValueTexture())
*
* #define RL_MAX_MATRIX_STACK_SIZE 32 // Maximum size of internal Matrix stack
* #define RL_MAX_SHADER_LOCATIONS 32 // Maximum number of shader locations supported
* #define RL_CULL_DISTANCE_NEAR 0.01 // Default projection matrix near cull distance
* #define RL_CULL_DISTANCE_FAR 1000.0 // Default projection matrix far cull distance
*
* When loading a shader, the following vertex attributes and uniform
* location names are tried to be set automatically:
*
* #define RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION "vertexPosition" // Bound by default to shader location: 0
* #define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD "vertexTexCoord" // Bound by default to shader location: 1
* #define RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL "vertexNormal" // Bound by default to shader location: 2
* #define RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR "vertexColor" // Bound by default to shader location: 3
* #define RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT "vertexTangent" // Bound by default to shader location: 4
* #define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 "vertexTexCoord2" // Bound by default to shader location: 5
* #define RL_DEFAULT_SHADER_UNIFORM_NAME_MVP "mvp" // model-view-projection matrix
* #define RL_DEFAULT_SHADER_UNIFORM_NAME_VIEW "matView" // view matrix
* #define RL_DEFAULT_SHADER_UNIFORM_NAME_PROJECTION "matProjection" // projection matrix
* #define RL_DEFAULT_SHADER_UNIFORM_NAME_MODEL "matModel" // model matrix
* #define RL_DEFAULT_SHADER_UNIFORM_NAME_NORMAL "matNormal" // normal matrix (transpose(inverse(matModelView))
* #define RL_DEFAULT_SHADER_UNIFORM_NAME_COLOR "colDiffuse" // color diffuse (base tint color, multiplied by texture color)
* #define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE0 "texture0" // texture0 (texture slot active 0)
* #define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE1 "texture1" // texture1 (texture slot active 1)
* #define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE2 "texture2" // texture2 (texture slot active 2)
*
* DEPENDENCIES:
* - OpenGL libraries (depending on platform and OpenGL version selected)
* - GLAD OpenGL extensions loading library (only for OpenGL 3.3 Core, 4.3 Core)
*
*
* LICENSE: zlib/libpng
*
* Copyright (c) 2014-2023 Ramon Santamaria (@raysan5)
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose, including commercial
* applications, and to alter it and redistribute it freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not claim that you
* wrote the original software. If you use this software in a product, an acknowledgment
* in the product documentation would be appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be misrepresented
* as being the original software.
*
* 3. This notice may not be removed or altered from any source distribution.
*
**********************************************************************************************/
package raylib
import "core:c"
RLGL_VERSION :: "4.5"
when ODIN_OS == .Windows {
foreign import lib {
"windows/raylib.lib",
"system:Winmm.lib",
"system:Gdi32.lib",
"system:User32.lib",
"system:Shell32.lib",
}
} else when ODIN_OS == .Linux {
foreign import lib "linux/libraylib.a"
} else when ODIN_OS == .Darwin {
foreign import lib {
"macos-arm64/libraylib.a" when ODIN_ARCH == .arm64 else "macos/libraylib.a",
"system:Cocoa.framework",
"system:OpenGL.framework",
"system:IOKit.framework",
}
} else {
foreign import lib "system:raylib"
}
RL_GRAPHICS_API_OPENGL_11 :: false
RL_GRAPHICS_API_OPENGL_21 :: true
RL_GRAPHICS_API_OPENGL_33 :: RL_GRAPHICS_API_OPENGL_21 // default currently
RL_GRAPHICS_API_OPENGL_ES2 :: false
RL_GRAPHICS_API_OPENGL_43 :: false
RL_GRAPHICS_API_OPENGL_ES3 :: false
when RL_GRAPHICS_API_OPENGL_ES3 {
RL_GRAPHICS_API_OPENGL_ES2 :: true
}
when !RL_GRAPHICS_API_OPENGL_ES2 {
// This is the maximum amount of elements (quads) per batch
// NOTE: Be careful with text, every letter maps to a quad
RL_DEFAULT_BATCH_BUFFER_ELEMENTS :: 8192
} else {
// We reduce memory sizes for embedded systems (RPI and HTML5)
// NOTE: On HTML5 (emscripten) this is allocated on heap,
// by default it's only 16MB!...just take care...
RL_DEFAULT_BATCH_BUFFER_ELEMENTS :: 2048
}
RL_DEFAULT_BATCH_BUFFERS :: 1 // Default number of batch buffers (multi-buffering)
RL_DEFAULT_BATCH_DRAWCALLS :: 256 // Default number of batch draw calls (by state changes: mode, texture)
RL_DEFAULT_BATCH_MAX_TEXTURE_UNITS :: 4 // Maximum number of additional textures that can be activated on batch drawing (SetShaderValueTexture())
// Internal Matrix stack
RL_MAX_MATRIX_STACK_SIZE :: 32 // Maximum size of Matrix stack
// Shader limits
RL_MAX_SHADER_LOCATIONS :: 32 // Maximum number of shader locations supported
// Projection matrix culling
RL_CULL_DISTANCE_NEAR :: 0.01 // Default near cull distance
RL_CULL_DISTANCE_FAR :: 1000.0 // Default far cull distance
// Texture parameters (equivalent to OpenGL defines)
RL_TEXTURE_WRAP_S :: 0x2802 // GL_TEXTURE_WRAP_S
RL_TEXTURE_WRAP_T :: 0x2803 // GL_TEXTURE_WRAP_T
RL_TEXTURE_MAG_FILTER :: 0x2800 // GL_TEXTURE_MAG_FILTER
RL_TEXTURE_MIN_FILTER :: 0x2801 // GL_TEXTURE_MIN_FILTER
RL_TEXTURE_FILTER_NEAREST :: 0x2600 // GL_NEAREST
RL_TEXTURE_FILTER_LINEAR :: 0x2601 // GL_LINEAR
RL_TEXTURE_FILTER_MIP_NEAREST :: 0x2700 // GL_NEAREST_MIPMAP_NEAREST
RL_TEXTURE_FILTER_NEAREST_MIP_LINEAR :: 0x2702 // GL_NEAREST_MIPMAP_LINEAR
RL_TEXTURE_FILTER_LINEAR_MIP_NEAREST :: 0x2701 // GL_LINEAR_MIPMAP_NEAREST
RL_TEXTURE_FILTER_MIP_LINEAR :: 0x2703 // GL_LINEAR_MIPMAP_LINEAR
RL_TEXTURE_FILTER_ANISOTROPIC :: 0x3000 // Anisotropic filter (custom identifier)
RL_TEXTURE_WRAP_REPEAT :: 0x2901 // GL_REPEAT
RL_TEXTURE_WRAP_CLAMP :: 0x812F // GL_CLAMP_TO_EDGE
RL_TEXTURE_WRAP_MIRROR_REPEAT :: 0x8370 // GL_MIRRORED_REPEAT
RL_TEXTURE_WRAP_MIRROR_CLAMP :: 0x8742 // GL_MIRROR_CLAMP_EXT
// Matrix modes (equivalent to OpenGL)
RL_MODELVIEW :: 0x1700 // GL_MODELVIEW
RL_PROJECTION :: 0x1701 // GL_PROJECTION
RL_TEXTURE :: 0x1702 // GL_TEXTURE
// Primitive assembly draw modes
RL_LINES :: 0x0001 // GL_LINES
RL_TRIANGLES :: 0x0004 // GL_TRIANGLES
RL_QUADS :: 0x0007 // GL_QUADS
// GL equivalent data types
RL_UNSIGNED_BYTE :: 0x1401 // GL_UNSIGNED_BYTE
RL_FLOAT :: 0x1406 // GL_FLOAT
// Buffer usage hint
RL_STREAM_DRAW :: 0x88E0 // GL_STREAM_DRAW
RL_STREAM_READ :: 0x88E1 // GL_STREAM_READ
RL_STREAM_COPY :: 0x88E2 // GL_STREAM_COPY
RL_STATIC_DRAW :: 0x88E4 // GL_STATIC_DRAW
RL_STATIC_READ :: 0x88E5 // GL_STATIC_READ
RL_STATIC_COPY :: 0x88E6 // GL_STATIC_COPY
RL_DYNAMIC_DRAW :: 0x88E8 // GL_DYNAMIC_DRAW
RL_DYNAMIC_READ :: 0x88E9 // GL_DYNAMIC_READ
RL_DYNAMIC_COPY :: 0x88EA // GL_DYNAMIC_COPY
// GL Shader type
RL_FRAGMENT_SHADER :: 0x8B30 // GL_FRAGMENT_SHADER
RL_VERTEX_SHADER :: 0x8B31 // GL_VERTEX_SHADER
RL_COMPUTE_SHADER :: 0x91B9 // GL_COMPUTE_SHADER
// GL blending factors
RL_ZERO :: 0 // GL_ZERO
RL_ONE :: 1 // GL_ONE
RL_SRC_COLOR :: 0x0300 // GL_SRC_COLOR
RL_ONE_MINUS_SRC_COLOR :: 0x0301 // GL_ONE_MINUS_SRC_COLOR
RL_SRC_ALPHA :: 0x0302 // GL_SRC_ALPHA
RL_ONE_MINUS_SRC_ALPHA :: 0x0303 // GL_ONE_MINUS_SRC_ALPHA
RL_DST_ALPHA :: 0x0304 // GL_DST_ALPHA
RL_ONE_MINUS_DST_ALPHA :: 0x0305 // GL_ONE_MINUS_DST_ALPHA
RL_DST_COLOR :: 0x0306 // GL_DST_COLOR
RL_ONE_MINUS_DST_COLOR :: 0x0307 // GL_ONE_MINUS_DST_COLOR
RL_SRC_ALPHA_SATURATE :: 0x0308 // GL_SRC_ALPHA_SATURATE
RL_CONSTANT_COLOR :: 0x8001 // GL_CONSTANT_COLOR
RL_ONE_MINUS_CONSTANT_COLOR :: 0x8002 // GL_ONE_MINUS_CONSTANT_COLOR
RL_CONSTANT_ALPHA :: 0x8003 // GL_CONSTANT_ALPHA
RL_ONE_MINUS_CONSTANT_ALPHA :: 0x8004 // GL_ONE_MINUS_CONSTANT_ALPHA
// GL blending functions/equations
RL_FUNC_ADD :: 0x8006 // GL_FUNC_ADD
RL_MIN :: 0x8007 // GL_MIN
RL_MAX :: 0x8008 // GL_MAX
RL_FUNC_SUBTRACT :: 0x800A // GL_FUNC_SUBTRACT
RL_FUNC_REVERSE_SUBTRACT :: 0x800B // GL_FUNC_REVERSE_SUBTRACT
RL_BLEND_EQUATION :: 0x8009 // GL_BLEND_EQUATION
RL_BLEND_EQUATION_RGB :: 0x8009 // GL_BLEND_EQUATION_RGB // (Same as BLEND_EQUATION)
RL_BLEND_EQUATION_ALPHA :: 0x883D // GL_BLEND_EQUATION_ALPHA
RL_BLEND_DST_RGB :: 0x80C8 // GL_BLEND_DST_RGB
RL_BLEND_SRC_RGB :: 0x80C9 // GL_BLEND_SRC_RGB
RL_BLEND_DST_ALPHA :: 0x80CA // GL_BLEND_DST_ALPHA
RL_BLEND_SRC_ALPHA :: 0x80CB // GL_BLEND_SRC_ALPHA
RL_BLEND_COLOR :: 0x8005 // GL_BLEND_COLOR
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
VertexBufferIndexType :: c.ushort when RL_GRAPHICS_API_OPENGL_ES2 else c.uint
// Dynamic vertex buffers (position + texcoords + colors + indices arrays)
VertexBuffer :: struct {
elementCount: c.int, // Number of elements in the buffer (QUADS)
vertices: [^]f32, // Vertex position (XYZ - 3 components per vertex) (shader-location = 0)
texcoords: [^]f32, // Vertex texture coordinates (UV - 2 components per vertex) (shader-location = 1)
colors: [^]u8, // Vertex colors (RGBA - 4 components per vertex) (shader-location = 3)
indices: [^]VertexBufferIndexType, // Vertex indices (in case vertex data comes indexed) (6 indices per quad)
vaoId: c.uint, // OpenGL Vertex Array Object id
vboId: [4]c.uint, // OpenGL Vertex Buffer Objects id (4 types of vertex data)
}
// Draw call type
// NOTE: Only texture changes register a new draw, other state-change-related elements are not
// used at this moment (vaoId, shaderId, matrices), raylib just forces a batch draw call if any
// of those state-change happens (this is done in core module)
DrawCall :: struct {
mode: c.int, // Drawing mode: LINES, TRIANGLES, QUADS
vertexCount: c.int, // Number of vertex of the draw
vertexAlignment: c.int, // Number of vertex required for index alignment (LINES, TRIANGLES)
textureId: c.uint, // Texture id to be used on the draw -> Use to create new draw call if changes
}
// RenderBatch type
RenderBatch :: struct {
bufferCount: c.int, // Number of vertex buffers (multi-buffering support)
currentBuffer: c.int, // Current buffer tracking in case of multi-buffering
vertexBuffer: [^]VertexBuffer, // Dynamic buffer(s) for vertex data
draws: [^]DrawCall, // Draw calls array, depends on textureId
drawCounter: c.int, // Draw calls counter
currentDepth: f32, // Current depth value for next draw
}
// OpenGL version
GlVersion :: enum c.int {
OPENGL_11 = 1, // OpenGL 1.1
OPENGL_21, // OpenGL 2.1 (GLSL 120)
OPENGL_33, // OpenGL 3.3 (GLSL 330)
OPENGL_43, // OpenGL 4.3 (using GLSL 330)
OPENGL_ES_20, // OpenGL ES 2.0 (GLSL 100)
OPENGL_ES_30, // OpenGL ES 3.0 (GLSL 300 es)
}
// Shader attribute data types
ShaderAttributeDataType :: enum c.int {
FLOAT = 0, // Shader attribute type: float
VEC2, // Shader attribute type: vec2 (2 float)
VEC3, // Shader attribute type: vec3 (3 float)
VEC4, // Shader attribute type: vec4 (4 float)
}
// Framebuffer attachment type
// NOTE: By default up to 8 color channels defined, but it can be more
FramebufferAttachType :: enum c.int {
COLOR_CHANNEL0 = 0, // Framebuffer attachment type: color 0
COLOR_CHANNEL1 = 1, // Framebuffer attachment type: color 1
COLOR_CHANNEL2 = 2, // Framebuffer attachment type: color 2
COLOR_CHANNEL3 = 3, // Framebuffer attachment type: color 3
COLOR_CHANNEL4 = 4, // Framebuffer attachment type: color 4
COLOR_CHANNEL5 = 5, // Framebuffer attachment type: color 5
COLOR_CHANNEL6 = 6, // Framebuffer attachment type: color 6
COLOR_CHANNEL7 = 7, // Framebuffer attachment type: color 7
DEPTH = 100, // Framebuffer attachment type: depth
STENCIL = 200, // Framebuffer attachment type: stencil
}
// Framebuffer texture attachment type
FramebufferAttachTextureType :: enum c.int {
CUBEMAP_POSITIVE_X = 0, // Framebuffer texture attachment type: cubemap, +X side
CUBEMAP_NEGATIVE_X = 1, // Framebuffer texture attachment type: cubemap, -X side
CUBEMAP_POSITIVE_Y = 2, // Framebuffer texture attachment type: cubemap, +Y side
CUBEMAP_NEGATIVE_Y = 3, // Framebuffer texture attachment type: cubemap, -Y side
CUBEMAP_POSITIVE_Z = 4, // Framebuffer texture attachment type: cubemap, +Z side
CUBEMAP_NEGATIVE_Z = 5, // Framebuffer texture attachment type: cubemap, -Z side
TEXTURE2D = 100, // Framebuffer texture attachment type: texture2d
RENDERBUFFER = 200, // Framebuffer texture attachment type: renderbuffer
}
CullMode :: enum c.int {
FRONT = 0,
BACK,
}
@(default_calling_convention="c")
foreign lib {
//------------------------------------------------------------------------------------
// Functions Declaration - Matrix operations
//------------------------------------------------------------------------------------
rlMatrixMode :: proc(mode: c.int) --- // Choose the current matrix to be transformed
rlPushMatrix :: proc() --- // Push the current matrix to stack
rlPopMatrix :: proc() --- // Pop lattest inserted matrix from stack
rlLoadIdentity :: proc() --- // Reset current matrix to identity matrix
rlTranslatef :: proc(x, y, z: f32) --- // Multiply the current matrix by a translation matrix
rlRotatef :: proc(angleDeg: f32, x, y, z: f32) --- // Multiply the current matrix by a rotation matrix
rlScalef :: proc(x, y, z: f32) --- // Multiply the current matrix by a scaling matrix
rlMultMatrixf :: proc(matf: [^]f32) --- // Multiply the current matrix by another matrix
rlFrustum :: proc(left, right, bottom, top, znear, zfar: f64) ---
rlOrtho :: proc(left, right, bottom, top, znear, zfar: f64) ---
rlViewport :: proc(x, y, width, height: c.int) --- // Set the viewport area
//------------------------------------------------------------------------------------
// Functions Declaration - Vertex level operations
//------------------------------------------------------------------------------------
rlBegin :: proc(mode: c.int) --- // Initialize drawing mode (how to organize vertex)
rlEnd :: proc() --- // Finish vertex providing
rlVertex2i :: proc(x, y: c.int) --- // Define one vertex (position) - 2 int
rlVertex2f :: proc(x, y: f32) --- // Define one vertex (position) - 2 f32
rlVertex3f :: proc(x, y, z: f32) --- // Define one vertex (position) - 3 f32
rlTexCoord2f :: proc(x, y: f32) --- // Define one vertex (texture coordinate) - 2 f32
rlNormal3f :: proc(x, y, z: f32) --- // Define one vertex (normal) - 3 f32
rlColor4ub :: proc(r, g, b, a: u8) --- // Define one vertex (color) - 4 byte
rlColor3f :: proc(x, y, z: f32) --- // Define one vertex (color) - 3 f32
rlColor4f :: proc(x, y, z, w: f32) --- // Define one vertex (color) - 4 f32
//------------------------------------------------------------------------------------
// Functions Declaration - OpenGL style functions (common to 1.1, 3.3+, ES2)
// NOTE: This functions are used to completely abstract raylib code from OpenGL layer,
// some of them are direct wrappers over OpenGL calls, some others are custom
//------------------------------------------------------------------------------------
// Vertex buffers state
rlEnableVertexArray :: proc(vaoId: c.uint) -> bool --- // Enable vertex array (VAO, if supported)
rlDisableVertexArray :: proc() --- // Disable vertex array (VAO, if supported)
rlEnableVertexBuffer :: proc(id: c.uint) --- // Enable vertex buffer (VBO)
rlDisableVertexBuffer :: proc() --- // Disable vertex buffer (VBO)
rlEnableVertexBufferElement :: proc(id: c.uint) --- // Enable vertex buffer element (VBO element)
rlDisableVertexBufferElement :: proc() --- // Disable vertex buffer element (VBO element)
rlEnableVertexAttribute :: proc(index: c.uint) --- // Enable vertex attribute index
rlDisableVertexAttribute :: proc(index: c.uint) --- // Disable vertex attribute index
when RL_GRAPHICS_API_OPENGL_11 {
rlEnableStatePointer :: proc(vertexAttribType: c.int, buffer: rawptr) ---
rlDisableStatePointer :: proc(vertexAttribType: c.int) ---
}
// Textures state
rlActiveTextureSlot :: proc(slot: c.int) --- // Select and active a texture slot
rlEnableTexture :: proc(id: c.uint) --- // Enable texture
rlDisableTexture :: proc() --- // Disable texture
rlEnableTextureCubemap :: proc(id: c.uint) --- // Enable texture cubemap
rlDisableTextureCubemap :: proc() --- // Disable texture cubemap
rlTextureParameters :: proc(id: c.uint, param: c.int, value: c.int) --- // Set texture parameters (filter, wrap)
rlCubemapParameters :: proc(id: i32, param: c.int, value: c.int) --- // Set cubemap parameters (filter, wrap)
// Shader state
rlEnableShader :: proc(id: c.uint) --- // Enable shader program
rlDisableShader :: proc() --- // Disable shader program
// Framebuffer state
rlEnableFramebuffer :: proc(id: c.uint) --- // Enable render texture (fbo)
rlDisableFramebuffer :: proc() --- // Disable render texture (fbo), return to default framebuffer
rlActiveDrawBuffers :: proc(count: c.int) --- // Activate multiple draw color buffers
rlBlitFramebuffer :: proc(srcX, srcY, srcWidth, srcHeight, dstX, dstY, dstWidth, dstHeight, bufferMask: c.int) --- // Blit active framebuffer to main framebuffer
// General render state
rlDisableColorBlend :: proc() --- // Disable color blending
rlEnableDepthTest :: proc() --- // Enable depth test
rlDisableDepthTest :: proc() --- // Disable depth test
rlEnableDepthMask :: proc() --- // Enable depth write
rlDisableDepthMask :: proc() --- // Disable depth write
rlEnableBackfaceCulling :: proc() --- // Enable backface culling
rlDisableBackfaceCulling :: proc() --- // Disable backface culling
rlSetCullFace :: proc(mode: CullMode) --- // Set face culling mode
rlEnableScissorTest :: proc() --- // Enable scissor test
rlDisableScissorTest :: proc() --- // Disable scissor test
rlScissor :: proc(x, y, width, height: c.int) --- // Scissor test
rlEnableWireMode :: proc() --- // Enable wire mode
rlEnablePointMode :: proc() --- // Enable point mode
rlDisableWireMode :: proc() --- // Disable wire and point modes
rlSetLineWidth :: proc(width: f32) --- // Set the line drawing width
rlGetLineWidth :: proc() -> f32 --- // Get the line drawing width
rlEnableSmoothLines :: proc() --- // Enable line aliasing
rlDisableSmoothLines :: proc() --- // Disable line aliasing
rlEnableStereoRender :: proc() --- // Enable stereo rendering
rlDisableStereoRender :: proc() --- // Disable stereo rendering
rlIsStereoRenderEnabled :: proc() -> bool --- // Check if stereo render is enabled
rlClearColor :: proc(r, g, b, a: u8) --- // Clear color buffer with color
rlClearScreenBuffers :: proc() --- // Clear used screen buffers (color and depth)
rlCheckErrors :: proc() --- // Check and log OpenGL error codes
rlSetBlendMode :: proc(mode: c.int) --- // Set blending mode
rlSetBlendFactors :: proc(glSrcFactor, glDstFactor, glEquation: c.int) --- // Set blending mode factor and equation (using OpenGL factors)
rlSetBlendFactorsSeparate :: proc(glSrcRGB, glDstRGB, glSrcAlpha, glDstAlpha, glEqRGB, glEqAlpha: c.int) --- // Set blending mode factors and equations separately (using OpenGL factors)
//------------------------------------------------------------------------------------
// Functions Declaration - rlgl functionality
//------------------------------------------------------------------------------------
// rlgl initialization functions
rlglInit :: proc(width, height: c.int) --- // Initialize rlgl (buffers, shaders, textures, states)
rlglClose :: proc() --- // De-initialize rlgl (buffers, shaders, textures)
rlLoadExtensions :: proc(loader: rawptr) --- // Load OpenGL extensions (loader function required)
rlGetVersion :: proc() -> GlVersion --- // Get current OpenGL version
rlSetFramebufferWidth :: proc(width: c.int) --- // Set current framebuffer width
rlGetFramebufferWidth :: proc() -> c.int --- // Get default framebuffer width
rlSetFramebufferHeight :: proc(height: c.int) --- // Set current framebuffer height
rlGetFramebufferHeight :: proc() -> c.int --- // Get default framebuffer height
rlGetTextureIdDefault :: proc() -> c.uint --- // Get default texture id
rlGetShaderIdDefault :: proc() -> c.uint --- // Get default shader id
rlGetShaderLocsDefault :: proc() -> [^]c.int --- // Get default shader locations
// Render batch management
// NOTE: rlgl provides a default render batch to behave like OpenGL 1.1 immediate mode
// but this render batch API is exposed in case of custom batches are required
rlLoadRenderBatch :: proc(numBuffers, bufferElements: c.int) -> RenderBatch --- // Load a render batch system
rlUnloadRenderBatch :: proc(batch: RenderBatch) --- // Unload render batch system
rlDrawRenderBatch :: proc(batch: ^RenderBatch) --- // Draw render batch data (Update->Draw->Reset)
rlSetRenderBatchActive :: proc(batch: ^RenderBatch) --- // Set the active render batch for rlgl (NULL for default internal)
rlDrawRenderBatchActive :: proc() --- // Update and draw internal render batch
rlCheckRenderBatchLimit :: proc(vCount: c.int) -> c.int --- // Check internal buffer overflow for a given number of vertex
rlSetTexture :: proc(id: c.uint) --- // Set current texture for render batch and check buffers limits
//------------------------------------------------------------------------------------------------------------------------
// Vertex buffers management
rlLoadVertexArray :: proc() -> c.uint --- // Load vertex array (vao) if supported
rlLoadVertexBuffer :: proc(buffer: rawptr, size: c.int, is_dynamic: bool) -> c.uint --- // Load a vertex buffer attribute
rlLoadVertexBufferElement :: proc(buffer: rawptr, size: c.int, is_dynamic: bool) -> c.uint --- // Load a new attributes element buffer
rlUpdateVertexBuffer :: proc(bufferId: c.uint, data: rawptr, dataSize: c.int, offset: c.int) --- // Update GPU buffer with new data
rlUpdateVertexBufferElements :: proc(id: c.uint, data: rawptr, dataSize: c.int, offset: c.int) --- // Update vertex buffer elements with new data
rlUnloadVertexArray :: proc(vaoId: c.uint) ---
rlUnloadVertexBuffer :: proc(vboId: c.uint) ---
rlSetVertexAttribute :: proc(index: c.uint, compSize: c.int, type: c.int, normalized: bool, stride: c.int, pointer: rawptr) ---
rlSetVertexAttributeDivisor :: proc(index: c.uint, divisor: c.int) ---
rlSetVertexAttributeDefault :: proc(locIndex: c.int, value: rawptr, attribType: c.int, count: c.int) --- // Set vertex attribute default value
rlDrawVertexArray :: proc(offset: c.int, count: c.int) ---
rlDrawVertexArrayElements :: proc(offset: c.int, count: c.int, buffer: rawptr) ---
rlDrawVertexArrayInstanced :: proc(offset: c.int, count: c.int, instances: c.int) ---
rlDrawVertexArrayElementsInstanced :: proc(offset: c.int, count: c.int, buffer: rawptr, instances: c.int) ---
// Textures management
rlLoadTexture :: proc(data: rawptr, width, height: c.int, format: c.int, mipmapCount: c.int) -> c.uint --- // Load texture in GPU
rlLoadTextureDepth :: proc(width, height: c.int, useRenderBuffer: bool) -> c.uint --- // Load depth texture/renderbuffer (to be attached to fbo)
rlLoadTextureCubemap :: proc(data: rawptr, size: c.int, format: c.int) -> c.uint --- // Load texture cubemap
rlUpdateTexture :: proc(id: c.uint, offsetX, offsetY: c.int, width, height: c.int, format: c.int, data: rawptr) --- // Update GPU texture with new data
rlGetGlTextureFormats :: proc(format: c.int, glInternalFormat, glFormat, glType: ^c.uint) --- // Get OpenGL internal formats
rlGetPixelFormatName :: proc(format: c.uint) -> cstring --- // Get name string for pixel format
rlUnloadTexture :: proc(id: c.uint) --- // Unload texture from GPU memory
rlGenTextureMipmaps :: proc(id: c.uint, width, height: c.int, format: c.int, mipmaps: ^c.int) --- // Generate mipmap data for selected texture
rlReadTexturePixels :: proc(id: c.uint, width, height: c.int, format: c.int) -> rawptr --- // Read texture pixel data
rlReadScreenPixels :: proc(width, height: c.int) -> [^]byte --- // Read screen pixel data (color buffer)
// Framebuffer management (fbo)
rlLoadFramebuffer :: proc(width, height: c.int) -> c.uint --- // Load an empty framebuffer
rlFramebufferAttach :: proc(fboId, texId: c.uint, attachType: c.int, texType: c.int, mipLevel: c.int) --- // Attach texture/renderbuffer to a framebuffer
rlFramebufferComplete :: proc(id: c.uint) -> bool --- // Verify framebuffer is complete
rlUnloadFramebuffer :: proc(id: c.uint) --- // Delete framebuffer from GPU
// Shaders management
rlLoadShaderCode :: proc(vsCode, fsCode: cstring) -> c.uint --- // Load shader from code strings
rlCompileShader :: proc(shaderCode: cstring, type: c.int) -> c.uint --- // Compile custom shader and return shader id (type: RL_VERTEX_SHADER, RL_FRAGMENT_SHADER, RL_COMPUTE_SHADER)
rlLoadShaderProgram :: proc(vShaderId, fShaderId: c.uint) -> c.uint --- // Load custom shader program
rlUnloadShaderProgram :: proc(id: c.uint) --- // Unload shader program
rlGetLocationUniform :: proc(shaderId: c.uint, uniformName: cstring) -> c.int --- // Get shader location uniform
rlGetLocationAttrib :: proc(shaderId: c.uint, attribName: cstring) -> c.int --- // Get shader location attribute
rlSetUniform :: proc(locIndex: c.int, value: rawptr, uniformType: c.int, count: c.int) --- // Set shader value uniform
rlSetUniformMatrix :: proc(locIndex: c.int, mat: Matrix) --- // Set shader value matrix
rlSetUniformSampler :: proc(locIndex: c.int, textureId: c.uint) --- // Set shader value sampler
rlSetShader :: proc(id: c.uint, locs: [^]c.int) --- // Set shader currently active (id and locations)
// Compute shader management
rlLoadComputeShaderProgram :: proc(shaderId: c.uint) -> c.uint --- // Load compute shader program
rlComputeShaderDispatch :: proc(groupX, groupY, groupZ: c.uint) --- // Dispatch compute shader (equivalent to *draw* for graphics pipeline)
// Shader buffer storage object management (ssbo)
rlLoadShaderBuffer :: proc(size: c.uint, data: rawptr, usageHint: c.int) -> c.uint --- // Load shader storage buffer object (SSBO)
rlUnloadShaderBuffer :: proc(ssboId: c.uint) --- // Unload shader storage buffer object (SSBO)
rlUpdateShaderBuffer :: proc(id: c.uint, data: rawptr, dataSize: c.uint, offset: c.uint) --- // Update SSBO buffer data
rlBindShaderBuffer :: proc(id: c.uint, index: c.uint) --- // Bind SSBO buffer
rlReadShaderBuffer :: proc(id: c.uint, dest: rawptr, count: c.uint, offset: c.uint) --- // Read SSBO buffer data (GPU->CPU)
rlCopyShaderBuffer :: proc(destId, srcId: c.uint, destOffset, srcOffset: c.uint, count: c.uint) --- // Copy SSBO data between buffers
rlGetShaderBufferSize :: proc(id: c.uint) -> c.uint --- // Get SSBO buffer size
// Buffer management
rlBindImageTexture :: proc(id: c.uint, index: c.uint, format: c.int, readonly: bool) --- // Bind image texture
// Matrix state management
rlGetMatrixModelview :: proc() -> Matrix --- // Get internal modelview matrix
rlGetMatrixProjection :: proc() -> Matrix --- // Get internal projection matrix
rlGetMatrixTransform :: proc() -> Matrix --- // Get internal accumulated transform matrix
rlGetMatrixProjectionStereo :: proc(eye: c.int) -> Matrix --- // Get internal projection matrix for stereo render (selected eye)
rlGetMatrixViewOffsetStereo :: proc(eye: c.int) -> Matrix --- // Get internal view offset matrix for stereo render (selected eye)
rlSetMatrixProjection :: proc(proj: Matrix) --- // Set a custom projection matrix (replaces internal projection matrix)
rlSetMatrixModelview :: proc(view: Matrix) --- // Set a custom modelview matrix (replaces internal modelview matrix)
rlSetMatrixProjectionStereo :: proc(right, left: Matrix) --- // Set eyes projection matrices for stereo rendering
rlSetMatrixViewOffsetStereo :: proc(right, left: Matrix) --- // Set eyes view offsets matrices for stereo rendering
// Quick and dirty cube/quad buffers load->draw->unload
rlLoadDrawCube :: proc() --- // Load and draw a cube
rlLoadDrawQuad :: proc() --- // Load and draw a quad
}
+581
View File
@@ -0,0 +1,581 @@
/**********************************************************************************************
*
* rlgl v5.0 - A multi-OpenGL abstraction layer with an immediate-mode style API
*
* DESCRIPTION:
* An abstraction layer for multiple OpenGL versions (1.1, 2.1, 3.3 Core, 4.3 Core, ES 2.0)
* that provides a pseudo-OpenGL 1.1 immediate-mode style API (rlVertex, rlTranslate, rlRotate...)
*
* ADDITIONAL NOTES:
* When choosing an OpenGL backend different than OpenGL 1.1, some internal buffer are
* initialized on rlglInit() to accumulate vertex data.
*
* When an internal state change is required all the stored vertex data is renderer in batch,
* additionally, rlDrawRenderBatchActive() could be called to force flushing of the batch.
*
* Some resources are also loaded for convenience, here the complete list:
* - Default batch (RLGL.defaultBatch): RenderBatch system to accumulate vertex data
* - Default texture (RLGL.defaultTextureId): 1x1 white pixel R8G8B8A8
* - Default shader (RLGL.State.defaultShaderId, RLGL.State.defaultShaderLocs)
*
* Internal buffer (and resources) must be manually unloaded calling rlglClose().
*
* CONFIGURATION:
* #define GRAPHICS_API_OPENGL_11
* #define GRAPHICS_API_OPENGL_21
* #define GRAPHICS_API_OPENGL_33
* #define GRAPHICS_API_OPENGL_43
* #define GRAPHICS_API_OPENGL_ES2
* #define GRAPHICS_API_OPENGL_ES3
* Use selected OpenGL graphics backend, should be supported by platform
* Those preprocessor defines are only used on rlgl module, if OpenGL version is
* required by any other module, use rlGetVersion() to check it
*
* #define RLGL_IMPLEMENTATION
* Generates the implementation of the library into the included file.
* If not defined, the library is in header only mode and can be included in other headers
* or source files without problems. But only ONE file should hold the implementation.
*
* #define RLGL_RENDER_TEXTURES_HINT
* Enable framebuffer objects (fbo) support (enabled by default)
* Some GPUs could not support them despite the OpenGL version
*
* #define RLGL_SHOW_GL_DETAILS_INFO
* Show OpenGL extensions and capabilities detailed logs on init
*
* #define RLGL_ENABLE_OPENGL_DEBUG_CONTEXT
* Enable debug context (only available on OpenGL 4.3)
*
* rlgl capabilities could be customized just defining some internal
* values before library inclusion (default values listed):
*
* #define RL_DEFAULT_BATCH_BUFFER_ELEMENTS 8192 // Default internal render batch elements limits
* #define RL_DEFAULT_BATCH_BUFFERS 1 // Default number of batch buffers (multi-buffering)
* #define RL_DEFAULT_BATCH_DRAWCALLS 256 // Default number of batch draw calls (by state changes: mode, texture)
* #define RL_DEFAULT_BATCH_MAX_TEXTURE_UNITS 4 // Maximum number of textures units that can be activated on batch drawing (SetShaderValueTexture())
*
* #define RL_MAX_MATRIX_STACK_SIZE 32 // Maximum size of internal Matrix stack
* #define RL_MAX_SHADER_LOCATIONS 32 // Maximum number of shader locations supported
* #define RL_CULL_DISTANCE_NEAR 0.01 // Default projection matrix near cull distance
* #define RL_CULL_DISTANCE_FAR 1000.0 // Default projection matrix far cull distance
*
* When loading a shader, the following vertex attributes and uniform
* location names are tried to be set automatically:
*
* #define RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION "vertexPosition" // Bound by default to shader location: 0
* #define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD "vertexTexCoord" // Bound by default to shader location: 1
* #define RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL "vertexNormal" // Bound by default to shader location: 2
* #define RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR "vertexColor" // Bound by default to shader location: 3
* #define RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT "vertexTangent" // Bound by default to shader location: 4
* #define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 "vertexTexCoord2" // Bound by default to shader location: 5
* #define RL_DEFAULT_SHADER_UNIFORM_NAME_MVP "mvp" // model-view-projection matrix
* #define RL_DEFAULT_SHADER_UNIFORM_NAME_VIEW "matView" // view matrix
* #define RL_DEFAULT_SHADER_UNIFORM_NAME_PROJECTION "matProjection" // projection matrix
* #define RL_DEFAULT_SHADER_UNIFORM_NAME_MODEL "matModel" // model matrix
* #define RL_DEFAULT_SHADER_UNIFORM_NAME_NORMAL "matNormal" // normal matrix (transpose(inverse(matModelView))
* #define RL_DEFAULT_SHADER_UNIFORM_NAME_COLOR "colDiffuse" // color diffuse (base tint color, multiplied by texture color)
* #define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE0 "texture0" // texture0 (texture slot active 0)
* #define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE1 "texture1" // texture1 (texture slot active 1)
* #define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE2 "texture2" // texture2 (texture slot active 2)
*
* DEPENDENCIES:
* - OpenGL libraries (depending on platform and OpenGL version selected)
* - GLAD OpenGL extensions loading library (only for OpenGL 3.3 Core, 4.3 Core)
*
*
* LICENSE: zlib/libpng
*
* Copyright (c) 2014-2023 Ramon Santamaria (@raysan5)
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose, including commercial
* applications, and to alter it and redistribute it freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not claim that you
* wrote the original software. If you use this software in a product, an acknowledgment
* in the product documentation would be appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be misrepresented
* as being the original software.
*
* 3. This notice may not be removed or altered from any source distribution.
*
**********************************************************************************************/
package rlgl
import "core:c"
import rl "../."
VERSION :: "5.0"
RAYLIB_SHARED :: #config(RAYLIB_SHARED, false)
// Note: We pull in the full raylib library. If you want a truly stand-alone rlgl, then:
// - Compile a separate rlgl library and use that in the foreign import blocks below.
// - Remove the `import rl "../."` line
// - Copy the code from raylib.odin for any types we alias from that package (see PixelFormat etc)
when ODIN_OS == .Windows {
@(extra_linker_flags="/NODEFAULTLIB:" + ("msvcrt" when RAYLIB_SHARED else "libcmt"))
foreign import lib {
"../windows/raylibdll.lib" when RAYLIB_SHARED else "../windows/raylib.lib" ,
"system:Winmm.lib",
"system:Gdi32.lib",
"system:User32.lib",
"system:Shell32.lib",
}
} else when ODIN_OS == .Linux {
foreign import lib {
// Note(bumbread): I'm not sure why in `linux/` folder there are
// multiple copies of raylib.so, but since these bindings are for
// particular version of the library, I better specify it. Ideally,
// though, it's best specified in terms of major (.so.4)
"../linux/libraylib.so.500" when RAYLIB_SHARED else "../linux/libraylib.a",
"system:dl",
"system:pthread",
}
} else when ODIN_OS == .Darwin {
foreign import lib {
"../macos" +
("-arm64" when ODIN_ARCH == .arm64 else "") +
"/libraylib" + (".500.dylib" when RAYLIB_SHARED else ".a"),
"system:Cocoa.framework",
"system:OpenGL.framework",
"system:IOKit.framework",
}
} else {
foreign import lib "system:raylib"
}
GRAPHICS_API_OPENGL_11 :: false
GRAPHICS_API_OPENGL_21 :: true
GRAPHICS_API_OPENGL_33 :: GRAPHICS_API_OPENGL_21 // default currently
GRAPHICS_API_OPENGL_ES2 :: false
GRAPHICS_API_OPENGL_43 :: false
GRAPHICS_API_OPENGL_ES3 :: false
when GRAPHICS_API_OPENGL_ES3 {
GRAPHICS_API_OPENGL_ES2 :: true
}
when !GRAPHICS_API_OPENGL_ES2 {
// This is the maximum amount of elements (quads) per batch
// NOTE: Be careful with text, every letter maps to a quad
DEFAULT_BATCH_BUFFER_ELEMENTS :: 8192
} else {
// We reduce memory sizes for embedded systems (RPI and HTML5)
// NOTE: On HTML5 (emscripten) this is allocated on heap,
// by default it's only 16MB!...just take care...
DEFAULT_BATCH_BUFFER_ELEMENTS :: 2048
}
DEFAULT_BATCH_BUFFERS :: 1 // Default number of batch buffers (multi-buffering)
DEFAULT_BATCH_DRAWCALLS :: 256 // Default number of batch draw calls (by state changes: mode, texture)
DEFAULT_BATCH_MAX_TEXTURE_UNITS :: 4 // Maximum number of additional textures that can be activated on batch drawing (SetShaderValueTexture())
// Internal Matrix stack
MAX_MATRIX_STACK_SIZE :: 32 // Maximum size of Matrix stack
// Shader limits
MAX_SHADER_LOCATIONS :: 32 // Maximum number of shader locations supported
// Projection matrix culling
CULL_DISTANCE_NEAR :: 0.01 // Default near cull distance
CULL_DISTANCE_FAR :: 1000.0 // Default far cull distance
// Texture parameters (equivalent to OpenGL defines)
TEXTURE_WRAP_S :: 0x2802 // GL_TEXTURE_WRAP_S
TEXTURE_WRAP_T :: 0x2803 // GL_TEXTURE_WRAP_T
TEXTURE_MAG_FILTER :: 0x2800 // GL_TEXTURE_MAG_FILTER
TEXTURE_MIN_FILTER :: 0x2801 // GL_TEXTURE_MIN_FILTER
TEXTURE_FILTER_NEAREST :: 0x2600 // GL_NEAREST
TEXTURE_FILTER_LINEAR :: 0x2601 // GL_LINEAR
TEXTURE_FILTER_MIP_NEAREST :: 0x2700 // GL_NEAREST_MIPMAP_NEAREST
TEXTURE_FILTER_NEAREST_MIP_LINEAR :: 0x2702 // GL_NEAREST_MIPMAP_LINEAR
TEXTURE_FILTER_LINEAR_MIP_NEAREST :: 0x2701 // GL_LINEAR_MIPMAP_NEAREST
TEXTURE_FILTER_MIP_LINEAR :: 0x2703 // GL_LINEAR_MIPMAP_LINEAR
TEXTURE_FILTER_ANISOTROPIC :: 0x3000 // Anisotropic filter (custom identifier)
TEXTURE_WRAP_REPEAT :: 0x2901 // GL_REPEAT
TEXTURE_WRAP_CLAMP :: 0x812F // GL_CLAMP_TO_EDGE
TEXTURE_WRAP_MIRROR_REPEAT :: 0x8370 // GL_MIRRORED_REPEAT
TEXTURE_WRAP_MIRROR_CLAMP :: 0x8742 // GL_MIRROR_CLAMP_EXT
// Matrix modes (equivalent to OpenGL)
MODELVIEW :: 0x1700 // GL_MODELVIEW
PROJECTION :: 0x1701 // GL_PROJECTION
TEXTURE :: 0x1702 // GL_TEXTURE
// Primitive assembly draw modes
LINES :: 0x0001 // GL_LINES
TRIANGLES :: 0x0004 // GL_TRIANGLES
QUADS :: 0x0007 // GL_QUADS
// GL equivalent data types
UNSIGNED_BYTE :: 0x1401 // GL_UNSIGNED_BYTE
FLOAT :: 0x1406 // GL_FLOAT
// Buffer usage hint
STREAM_DRAW :: 0x88E0 // GL_STREAM_DRAW
STREAM_READ :: 0x88E1 // GL_STREAM_READ
STREAM_COPY :: 0x88E2 // GL_STREAM_COPY
STATIC_DRAW :: 0x88E4 // GL_STATIC_DRAW
STATIC_READ :: 0x88E5 // GL_STATIC_READ
STATIC_COPY :: 0x88E6 // GL_STATIC_COPY
DYNAMIC_DRAW :: 0x88E8 // GL_DYNAMIC_DRAW
DYNAMIC_READ :: 0x88E9 // GL_DYNAMIC_READ
DYNAMIC_COPY :: 0x88EA // GL_DYNAMIC_COPY
// GL Shader type
FRAGMENT_SHADER :: 0x8B30 // GL_FRAGMENT_SHADER
VERTEX_SHADER :: 0x8B31 // GL_VERTEX_SHADER
COMPUTE_SHADER :: 0x91B9 // GL_COMPUTE_SHADER
// GL blending factors
ZERO :: 0 // GL_ZERO
ONE :: 1 // GL_ONE
SRC_COLOR :: 0x0300 // GL_SRC_COLOR
ONE_MINUS_SRC_COLOR :: 0x0301 // GL_ONE_MINUS_SRC_COLOR
SRC_ALPHA :: 0x0302 // GL_SRC_ALPHA
ONE_MINUS_SRC_ALPHA :: 0x0303 // GL_ONE_MINUS_SRC_ALPHA
DST_ALPHA :: 0x0304 // GL_DST_ALPHA
ONE_MINUS_DST_ALPHA :: 0x0305 // GL_ONE_MINUS_DST_ALPHA
DST_COLOR :: 0x0306 // GL_DST_COLOR
ONE_MINUS_DST_COLOR :: 0x0307 // GL_ONE_MINUS_DST_COLOR
SRC_ALPHA_SATURATE :: 0x0308 // GL_SRC_ALPHA_SATURATE
CONSTANT_COLOR :: 0x8001 // GL_CONSTANT_COLOR
ONE_MINUS_CONSTANT_COLOR :: 0x8002 // GL_ONE_MINUS_CONSTANT_COLOR
CONSTANT_ALPHA :: 0x8003 // GL_CONSTANT_ALPHA
ONE_MINUS_CONSTANT_ALPHA :: 0x8004 // GL_ONE_MINUS_CONSTANT_ALPHA
// GL blending functions/equations
FUNC_ADD :: 0x8006 // GL_FUNC_ADD
MIN :: 0x8007 // GL_MIN
MAX :: 0x8008 // GL_MAX
FUNC_SUBTRACT :: 0x800A // GL_FUNC_SUBTRACT
FUNC_REVERSE_SUBTRACT :: 0x800B // GL_FUNC_REVERSE_SUBTRACT
BLEND_EQUATION :: 0x8009 // GL_BLEND_EQUATION
BLEND_EQUATION_RGB :: 0x8009 // GL_BLEND_EQUATION_RGB // (Same as BLEND_EQUATION)
BLEND_EQUATION_ALPHA :: 0x883D // GL_BLEND_EQUATION_ALPHA
BLEND_DST_RGB :: 0x80C8 // GL_BLEND_DST_RGB
BLEND_SRC_RGB :: 0x80C9 // GL_BLEND_SRC_RGB
BLEND_DST_ALPHA :: 0x80CA // GL_BLEND_DST_ALPHA
BLEND_SRC_ALPHA :: 0x80CB // GL_BLEND_SRC_ALPHA
BLEND_COLOR :: 0x8005 // GL_BLEND_COLOR
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
VertexBufferIndexType :: c.ushort when GRAPHICS_API_OPENGL_ES2 else c.uint
// Dynamic vertex buffers (position + texcoords + colors + indices arrays)
VertexBuffer :: struct {
elementCount: c.int, // Number of elements in the buffer (QUADS)
vertices: [^]f32, // Vertex position (XYZ - 3 components per vertex) (shader-location = 0)
texcoords: [^]f32, // Vertex texture coordinates (UV - 2 components per vertex) (shader-location = 1)
colors: [^]u8, // Vertex colors (RGBA - 4 components per vertex) (shader-location = 3)
indices: [^]VertexBufferIndexType, // Vertex indices (in case vertex data comes indexed) (6 indices per quad)
vaoId: c.uint, // OpenGL Vertex Array Object id
vboId: [4]c.uint, // OpenGL Vertex Buffer Objects id (4 types of vertex data)
}
// Draw call type
// NOTE: Only texture changes register a new draw, other state-change-related elements are not
// used at this moment (vaoId, shaderId, matrices), raylib just forces a batch draw call if any
// of those state-change happens (this is done in core module)
DrawCall :: struct {
mode: c.int, // Drawing mode: LINES, TRIANGLES, QUADS
vertexCount: c.int, // Number of vertex of the draw
vertexAlignment: c.int, // Number of vertex required for index alignment (LINES, TRIANGLES)
textureId: c.uint, // Texture id to be used on the draw -> Use to create new draw call if changes
}
// RenderBatch type
RenderBatch :: struct {
bufferCount: c.int, // Number of vertex buffers (multi-buffering support)
currentBuffer: c.int, // Current buffer tracking in case of multi-buffering
vertexBuffer: [^]VertexBuffer, // Dynamic buffer(s) for vertex data
draws: [^]DrawCall, // Draw calls array, depends on textureId
drawCounter: c.int, // Draw calls counter
currentDepth: f32, // Current depth value for next draw
}
// OpenGL version
GlVersion :: enum c.int {
OPENGL_11 = 1, // OpenGL 1.1
OPENGL_21, // OpenGL 2.1 (GLSL 120)
OPENGL_33, // OpenGL 3.3 (GLSL 330)
OPENGL_43, // OpenGL 4.3 (using GLSL 330)
OPENGL_ES_20, // OpenGL ES 2.0 (GLSL 100)
OPENGL_ES_30, // OpenGL ES 3.0 (GLSL 300 es)
}
PixelFormat :: rl.PixelFormat
TextureFilter :: rl.TextureFilter
BlendMode :: rl.BlendMode
ShaderLocationIndex :: rl.ShaderLocationIndex
ShaderUniformDataType :: rl.ShaderUniformDataType
// Shader attribute data types
ShaderAttributeDataType :: enum c.int {
FLOAT = 0, // Shader attribute type: float
VEC2, // Shader attribute type: vec2 (2 float)
VEC3, // Shader attribute type: vec3 (3 float)
VEC4, // Shader attribute type: vec4 (4 float)
}
// Framebuffer attachment type
// NOTE: By default up to 8 color channels defined, but it can be more
FramebufferAttachType :: enum c.int {
COLOR_CHANNEL0 = 0, // Framebuffer attachment type: color 0
COLOR_CHANNEL1 = 1, // Framebuffer attachment type: color 1
COLOR_CHANNEL2 = 2, // Framebuffer attachment type: color 2
COLOR_CHANNEL3 = 3, // Framebuffer attachment type: color 3
COLOR_CHANNEL4 = 4, // Framebuffer attachment type: color 4
COLOR_CHANNEL5 = 5, // Framebuffer attachment type: color 5
COLOR_CHANNEL6 = 6, // Framebuffer attachment type: color 6
COLOR_CHANNEL7 = 7, // Framebuffer attachment type: color 7
DEPTH = 100, // Framebuffer attachment type: depth
STENCIL = 200, // Framebuffer attachment type: stencil
}
// Framebuffer texture attachment type
FramebufferAttachTextureType :: enum c.int {
CUBEMAP_POSITIVE_X = 0, // Framebuffer texture attachment type: cubemap, +X side
CUBEMAP_NEGATIVE_X = 1, // Framebuffer texture attachment type: cubemap, -X side
CUBEMAP_POSITIVE_Y = 2, // Framebuffer texture attachment type: cubemap, +Y side
CUBEMAP_NEGATIVE_Y = 3, // Framebuffer texture attachment type: cubemap, -Y side
CUBEMAP_POSITIVE_Z = 4, // Framebuffer texture attachment type: cubemap, +Z side
CUBEMAP_NEGATIVE_Z = 5, // Framebuffer texture attachment type: cubemap, -Z side
TEXTURE2D = 100, // Framebuffer texture attachment type: texture2d
RENDERBUFFER = 200, // Framebuffer texture attachment type: renderbuffer
}
CullMode :: enum c.int {
FRONT = 0,
BACK,
}
Matrix :: rl.Matrix
@(default_calling_convention="c", link_prefix="rl")
foreign lib {
//------------------------------------------------------------------------------------
// Functions Declaration - Matrix operations
//------------------------------------------------------------------------------------
MatrixMode :: proc(mode: c.int) --- // Choose the current matrix to be transformed
PushMatrix :: proc() --- // Push the current matrix to stack
PopMatrix :: proc() --- // Pop lattest inserted matrix from stack
LoadIdentity :: proc() --- // Reset current matrix to identity matrix
Translatef :: proc(x, y, z: f32) --- // Multiply the current matrix by a translation matrix
Rotatef :: proc(angleDeg: f32, x, y, z: f32) --- // Multiply the current matrix by a rotation matrix
Scalef :: proc(x, y, z: f32) --- // Multiply the current matrix by a scaling matrix
MultMatrixf :: proc(matf: [^]f32) --- // Multiply the current matrix by another matrix
Frustum :: proc(left, right, bottom, top, znear, zfar: f64) ---
Ortho :: proc(left, right, bottom, top, znear, zfar: f64) ---
Viewport :: proc(x, y, width, height: c.int) --- // Set the viewport area
//------------------------------------------------------------------------------------
// Functions Declaration - Vertex level operations
//------------------------------------------------------------------------------------
Begin :: proc(mode: c.int) --- // Initialize drawing mode (how to organize vertex)
End :: proc() --- // Finish vertex providing
Vertex2i :: proc(x, y: c.int) --- // Define one vertex (position) - 2 int
Vertex2f :: proc(x, y: f32) --- // Define one vertex (position) - 2 f32
Vertex3f :: proc(x, y, z: f32) --- // Define one vertex (position) - 3 f32
TexCoord2f :: proc(x, y: f32) --- // Define one vertex (texture coordinate) - 2 f32
Normal3f :: proc(x, y, z: f32) --- // Define one vertex (normal) - 3 f32
Color4ub :: proc(r, g, b, a: u8) --- // Define one vertex (color) - 4 byte
Color3f :: proc(x, y, z: f32) --- // Define one vertex (color) - 3 f32
Color4f :: proc(x, y, z, w: f32) --- // Define one vertex (color) - 4 f32
//------------------------------------------------------------------------------------
// Functions Declaration - OpenGL style functions (common to 1.1, 3.3+, ES2)
// NOTE: This functions are used to completely abstract raylib code from OpenGL layer,
// some of them are direct wrappers over OpenGL calls, some others are custom
//------------------------------------------------------------------------------------
// Vertex buffers state
EnableVertexArray :: proc(vaoId: c.uint) -> bool --- // Enable vertex array (VAO, if supported)
DisableVertexArray :: proc() --- // Disable vertex array (VAO, if supported)
EnableVertexBuffer :: proc(id: c.uint) --- // Enable vertex buffer (VBO)
DisableVertexBuffer :: proc() --- // Disable vertex buffer (VBO)
EnableVertexBufferElement :: proc(id: c.uint) --- // Enable vertex buffer element (VBO element)
DisableVertexBufferElement :: proc() --- // Disable vertex buffer element (VBO element)
EnableVertexAttribute :: proc(index: c.uint) --- // Enable vertex attribute index
DisableVertexAttribute :: proc(index: c.uint) --- // Disable vertex attribute index
when GRAPHICS_API_OPENGL_11 {
EnableStatePointer :: proc(vertexAttribType: c.int, buffer: rawptr) ---
DisableStatePointer :: proc(vertexAttribType: c.int) ---
}
// Textures state
ActiveTextureSlot :: proc(slot: c.int) --- // Select and active a texture slot
EnableTexture :: proc(id: c.uint) --- // Enable texture
DisableTexture :: proc() --- // Disable texture
EnableTextureCubemap :: proc(id: c.uint) --- // Enable texture cubemap
DisableTextureCubemap :: proc() --- // Disable texture cubemap
TextureParameters :: proc(id: c.uint, param: c.int, value: c.int) --- // Set texture parameters (filter, wrap)
CubemapParameters :: proc(id: i32, param: c.int, value: c.int) --- // Set cubemap parameters (filter, wrap)
// Shader state
EnableShader :: proc(id: c.uint) --- // Enable shader program
DisableShader :: proc() --- // Disable shader program
// Framebuffer state
EnableFramebuffer :: proc(id: c.uint) --- // Enable render texture (fbo)
DisableFramebuffer :: proc() --- // Disable render texture (fbo), return to default framebuffer
ActiveDrawBuffers :: proc(count: c.int) --- // Activate multiple draw color buffers
BlitFramebuffer :: proc(srcX, srcY, srcWidth, srcHeight, dstX, dstY, dstWidth, dstHeight, bufferMask: c.int) --- // Blit active framebuffer to main framebuffer
// General render state
DisableColorBlend :: proc() --- // Disable color blending
EnableDepthTest :: proc() --- // Enable depth test
DisableDepthTest :: proc() --- // Disable depth test
EnableDepthMask :: proc() --- // Enable depth write
DisableDepthMask :: proc() --- // Disable depth write
EnableBackfaceCulling :: proc() --- // Enable backface culling
DisableBackfaceCulling :: proc() --- // Disable backface culling
SetCullFace :: proc(mode: CullMode) --- // Set face culling mode
EnableScissorTest :: proc() --- // Enable scissor test
DisableScissorTest :: proc() --- // Disable scissor test
Scissor :: proc(x, y, width, height: c.int) --- // Scissor test
EnableWireMode :: proc() --- // Enable wire mode
EnablePointMode :: proc() --- // Enable point mode
DisableWireMode :: proc() --- // Disable wire and point modes
SetLineWidth :: proc(width: f32) --- // Set the line drawing width
GetLineWidth :: proc() -> f32 --- // Get the line drawing width
EnableSmoothLines :: proc() --- // Enable line aliasing
DisableSmoothLines :: proc() --- // Disable line aliasing
EnableStereoRender :: proc() --- // Enable stereo rendering
DisableStereoRender :: proc() --- // Disable stereo rendering
IsStereoRenderEnabled :: proc() -> bool --- // Check if stereo render is enabled
ClearColor :: proc(r, g, b, a: u8) --- // Clear color buffer with color
ClearScreenBuffers :: proc() --- // Clear used screen buffers (color and depth)
CheckErrors :: proc() --- // Check and log OpenGL error codes
SetBlendMode :: proc(mode: c.int) --- // Set blending mode
SetBlendFactors :: proc(glSrcFactor, glDstFactor, glEquation: c.int) --- // Set blending mode factor and equation (using OpenGL factors)
SetBlendFactorsSeparate :: proc(glSrcRGB, glDstRGB, glSrcAlpha, glDstAlpha, glEqRGB, glEqAlpha: c.int) --- // Set blending mode factors and equations separately (using OpenGL factors)
//------------------------------------------------------------------------------------
// Functions Declaration - rlgl functionality
//------------------------------------------------------------------------------------
// rlgl initialization functions
@(link_prefix="rlgl")
Init :: proc(width, height: c.int) --- // Initialize rlgl (buffers, shaders, textures, states)
@(link_prefix="rlgl")
Close :: proc() --- // De-initialize rlgl (buffers, shaders, textures)
LoadExtensions :: proc(loader: rawptr) --- // Load OpenGL extensions (loader function required)
GetVersion :: proc() -> GlVersion --- // Get current OpenGL version
SetFramebufferWidth :: proc(width: c.int) --- // Set current framebuffer width
GetFramebufferWidth :: proc() -> c.int --- // Get default framebuffer width
SetFramebufferHeight :: proc(height: c.int) --- // Set current framebuffer height
GetFramebufferHeight :: proc() -> c.int --- // Get default framebuffer height
GetTextureIdDefault :: proc() -> c.uint --- // Get default texture id
GetShaderIdDefault :: proc() -> c.uint --- // Get default shader id
GetShaderLocsDefault :: proc() -> [^]c.int --- // Get default shader locations
// Render batch management
// NOTE: rlgl provides a default render batch to behave like OpenGL 1.1 immediate mode
// but this render batch API is exposed in case of custom batches are required
LoadRenderBatch :: proc(numBuffers, bufferElements: c.int) -> RenderBatch --- // Load a render batch system
UnloadRenderBatch :: proc(batch: RenderBatch) --- // Unload render batch system
DrawRenderBatch :: proc(batch: ^RenderBatch) --- // Draw render batch data (Update->Draw->Reset)
SetRenderBatchActive :: proc(batch: ^RenderBatch) --- // Set the active render batch for rlgl (NULL for default internal)
DrawRenderBatchActive :: proc() --- // Update and draw internal render batch
CheckRenderBatchLimit :: proc(vCount: c.int) -> c.int --- // Check internal buffer overflow for a given number of vertex
SetTexture :: proc(id: c.uint) --- // Set current texture for render batch and check buffers limits
//------------------------------------------------------------------------------------------------------------------------
// Vertex buffers management
LoadVertexArray :: proc() -> c.uint --- // Load vertex array (vao) if supported
LoadVertexBuffer :: proc(buffer: rawptr, size: c.int, is_dynamic: bool) -> c.uint --- // Load a vertex buffer attribute
LoadVertexBufferElement :: proc(buffer: rawptr, size: c.int, is_dynamic: bool) -> c.uint --- // Load a new attributes element buffer
UpdateVertexBuffer :: proc(bufferId: c.uint, data: rawptr, dataSize: c.int, offset: c.int) --- // Update GPU buffer with new data
UpdateVertexBufferElements :: proc(id: c.uint, data: rawptr, dataSize: c.int, offset: c.int) --- // Update vertex buffer elements with new data
UnloadVertexArray :: proc(vaoId: c.uint) ---
UnloadVertexBuffer :: proc(vboId: c.uint) ---
SetVertexAttribute :: proc(index: c.uint, compSize: c.int, type: c.int, normalized: bool, stride: c.int, pointer: rawptr) ---
SetVertexAttributeDivisor :: proc(index: c.uint, divisor: c.int) ---
SetVertexAttributeDefault :: proc(locIndex: c.int, value: rawptr, attribType: c.int, count: c.int) --- // Set vertex attribute default value
DrawVertexArray :: proc(offset: c.int, count: c.int) ---
DrawVertexArrayElements :: proc(offset: c.int, count: c.int, buffer: rawptr) ---
DrawVertexArrayInstanced :: proc(offset: c.int, count: c.int, instances: c.int) ---
DrawVertexArrayElementsInstanced :: proc(offset: c.int, count: c.int, buffer: rawptr, instances: c.int) ---
// Textures management
LoadTexture :: proc(data: rawptr, width, height: c.int, format: c.int, mipmapCount: c.int) -> c.uint --- // Load texture in GPU
LoadTextureDepth :: proc(width, height: c.int, useRenderBuffer: bool) -> c.uint --- // Load depth texture/renderbuffer (to be attached to fbo)
LoadTextureCubemap :: proc(data: rawptr, size: c.int, format: c.int) -> c.uint --- // Load texture cubemap
UpdateTexture :: proc(id: c.uint, offsetX, offsetY: c.int, width, height: c.int, format: c.int, data: rawptr) --- // Update GPU texture with new data
GetGlTextureFormats :: proc(format: c.int, glInternalFormat, glFormat, glType: ^c.uint) --- // Get OpenGL internal formats
GetPixelFormatName :: proc(format: c.uint) -> cstring --- // Get name string for pixel format
UnloadTexture :: proc(id: c.uint) --- // Unload texture from GPU memory
GenTextureMipmaps :: proc(id: c.uint, width, height: c.int, format: c.int, mipmaps: ^c.int) --- // Generate mipmap data for selected texture
ReadTexturePixels :: proc(id: c.uint, width, height: c.int, format: c.int) -> rawptr --- // Read texture pixel data
ReadScreenPixels :: proc(width, height: c.int) -> [^]byte --- // Read screen pixel data (color buffer)
// Framebuffer management (fbo)
LoadFramebuffer :: proc(width, height: c.int) -> c.uint --- // Load an empty framebuffer
FramebufferAttach :: proc(fboId, texId: c.uint, attachType: c.int, texType: c.int, mipLevel: c.int) --- // Attach texture/renderbuffer to a framebuffer
FramebufferComplete :: proc(id: c.uint) -> bool --- // Verify framebuffer is complete
UnloadFramebuffer :: proc(id: c.uint) --- // Delete framebuffer from GPU
// Shaders management
LoadShaderCode :: proc(vsCode, fsCode: cstring) -> c.uint --- // Load shader from code strings
CompileShader :: proc(shaderCode: cstring, type: c.int) -> c.uint --- // Compile custom shader and return shader id (type: VERTEX_SHADER, FRAGMENT_SHADER, COMPUTE_SHADER)
LoadShaderProgram :: proc(vShaderId, fShaderId: c.uint) -> c.uint --- // Load custom shader program
UnloadShaderProgram :: proc(id: c.uint) --- // Unload shader program
GetLocationUniform :: proc(shaderId: c.uint, uniformName: cstring) -> c.int --- // Get shader location uniform
GetLocationAttrib :: proc(shaderId: c.uint, attribName: cstring) -> c.int --- // Get shader location attribute
SetUniform :: proc(locIndex: c.int, value: rawptr, uniformType: c.int, count: c.int) --- // Set shader value uniform
SetUniformMatrix :: proc(locIndex: c.int, mat: Matrix) --- // Set shader value matrix
SetUniformSampler :: proc(locIndex: c.int, textureId: c.uint) --- // Set shader value sampler
SetShader :: proc(id: c.uint, locs: [^]c.int) --- // Set shader currently active (id and locations)
// Compute shader management
LoadComputeShaderProgram :: proc(shaderId: c.uint) -> c.uint --- // Load compute shader program
ComputeShaderDispatch :: proc(groupX, groupY, groupZ: c.uint) --- // Dispatch compute shader (equivalent to *draw* for graphics pipeline)
// Shader buffer storage object management (ssbo)
LoadShaderBuffer :: proc(size: c.uint, data: rawptr, usageHint: c.int) -> c.uint --- // Load shader storage buffer object (SSBO)
UnloadShaderBuffer :: proc(ssboId: c.uint) --- // Unload shader storage buffer object (SSBO)
UpdateShaderBuffer :: proc(id: c.uint, data: rawptr, dataSize: c.uint, offset: c.uint) --- // Update SSBO buffer data
BindShaderBuffer :: proc(id: c.uint, index: c.uint) --- // Bind SSBO buffer
ReadShaderBuffer :: proc(id: c.uint, dest: rawptr, count: c.uint, offset: c.uint) --- // Read SSBO buffer data (GPU->CPU)
CopyShaderBuffer :: proc(destId, srcId: c.uint, destOffset, srcOffset: c.uint, count: c.uint) --- // Copy SSBO data between buffers
GetShaderBufferSize :: proc(id: c.uint) -> c.uint --- // Get SSBO buffer size
// Buffer management
BindImageTexture :: proc(id: c.uint, index: c.uint, format: c.int, readonly: bool) --- // Bind image texture
// Matrix state management
GetMatrixModelview :: proc() -> Matrix --- // Get internal modelview matrix
GetMatrixProjection :: proc() -> Matrix --- // Get internal projection matrix
GetMatrixTransform :: proc() -> Matrix --- // Get internal accumulated transform matrix
GetMatrixProjectionStereo :: proc(eye: c.int) -> Matrix --- // Get internal projection matrix for stereo render (selected eye)
GetMatrixViewOffsetStereo :: proc(eye: c.int) -> Matrix --- // Get internal view offset matrix for stereo render (selected eye)
SetMatrixProjection :: proc(proj: Matrix) --- // Set a custom projection matrix (replaces internal projection matrix)
SetMatrixModelview :: proc(view: Matrix) --- // Set a custom modelview matrix (replaces internal modelview matrix)
SetMatrixProjectionStereo :: proc(right, left: Matrix) --- // Set eyes projection matrices for stereo rendering
SetMatrixViewOffsetStereo :: proc(right, left: Matrix) --- // Set eyes view offsets matrices for stereo rendering
// Quick and dirty cube/quad buffers load->draw->unload
LoadDrawCube :: proc() --- // Load and draw a cube
LoadDrawQuad :: proc() --- // Load and draw a quad
}