Merge remote-tracking branch 'offical/master'

This commit is contained in:
2024-06-15 15:00:21 -04:00
38 changed files with 1432 additions and 1204 deletions
+26
View File
@@ -397,11 +397,34 @@ Logger :: struct {
options: Logger_Options,
}
Random_Generator_Mode :: enum {
Read,
Reset,
Query_Info,
}
Random_Generator_Query_Info_Flag :: enum u32 {
Cryptographic,
Uniform,
External_Entropy,
Resettable,
}
Random_Generator_Query_Info :: distinct bit_set[Random_Generator_Query_Info_Flag; u32]
Random_Generator_Proc :: #type proc(data: rawptr, mode: Random_Generator_Mode, p: []byte)
Random_Generator :: struct {
procedure: Random_Generator_Proc,
data: rawptr,
}
Context :: struct {
allocator: Allocator,
temp_allocator: Allocator,
assertion_failure_proc: Assertion_Failure_Proc,
logger: Logger,
random_generator: Random_Generator,
user_ptr: rawptr,
user_index: int,
@@ -708,6 +731,9 @@ __init_context :: proc "contextless" (c: ^Context) {
c.logger.procedure = default_logger_proc
c.logger.data = nil
c.random_generator.procedure = default_random_generator_proc
c.random_generator.data = nil
}
default_assertion_failure_proc :: proc(prefix, message: string, loc: Source_Code_Location) -> ! {
+115
View File
@@ -0,0 +1,115 @@
package runtime
import "base:intrinsics"
@(require_results)
random_generator_read_bytes :: proc(rg: Random_Generator, p: []byte) -> bool {
if rg.procedure != nil {
rg.procedure(rg.data, .Read, p)
return true
}
return false
}
@(require_results)
random_generator_read_ptr :: proc(rg: Random_Generator, p: rawptr, len: uint) -> bool {
if rg.procedure != nil {
rg.procedure(rg.data, .Read, ([^]byte)(p)[:len])
return true
}
return false
}
@(require_results)
random_generator_query_info :: proc(rg: Random_Generator) -> (info: Random_Generator_Query_Info) {
if rg.procedure != nil {
rg.procedure(rg.data, .Query_Info, ([^]byte)(&info)[:size_of(info)])
}
return
}
random_generator_reset_bytes :: proc(rg: Random_Generator, p: []byte) {
if rg.procedure != nil {
rg.procedure(rg.data, .Reset, p)
}
}
random_generator_reset_u64 :: proc(rg: Random_Generator, p: u64) {
if rg.procedure != nil {
p := p
rg.procedure(rg.data, .Reset, ([^]byte)(&p)[:size_of(p)])
}
}
Default_Random_State :: struct {
state: u64,
inc: u64,
}
default_random_generator_proc :: proc(data: rawptr, mode: Random_Generator_Mode, p: []byte) {
@(require_results)
read_u64 :: proc "contextless" (r: ^Default_Random_State) -> u64 {
old_state := r.state
r.state = old_state * 6364136223846793005 + (r.inc|1)
xor_shifted := (((old_state >> 59) + 5) ~ old_state) * 12605985483714917081
rot := (old_state >> 59)
return (xor_shifted >> rot) | (xor_shifted << ((-rot) & 63))
}
@(thread_local)
global_rand_seed: Default_Random_State
init :: proc "contextless" (r: ^Default_Random_State, seed: u64) {
seed := seed
if seed == 0 {
seed = u64(intrinsics.read_cycle_counter())
}
r.state = 0
r.inc = (seed << 1) | 1
_ = read_u64(r)
r.state += seed
_ = read_u64(r)
}
r := &global_rand_seed
switch mode {
case .Read:
if r.state == 0 && r.inc == 0 {
init(r, 0)
}
pos := i8(0)
val := u64(0)
for &v in p {
if pos == 0 {
val = read_u64(r)
pos = 7
}
v = byte(val)
val >>= 8
pos -= 1
}
case .Reset:
seed: u64
mem_copy_non_overlapping(&seed, raw_data(p), min(size_of(seed), len(p)))
init(r, seed)
case .Query_Info:
if len(p) != size_of(Random_Generator_Query_Info) {
return
}
info := (^Random_Generator_Query_Info)(raw_data(p))
info^ += {.Uniform, .Resettable}
}
}
default_random_generator :: proc "contextless" (state: ^Default_Random_State = nil) -> Random_Generator {
return {
procedure = default_random_generator_proc,
data = state,
}
}
+22
View File
@@ -4,6 +4,7 @@ helper routines.
*/
package crypto
import "base:runtime"
import "core:mem"
// compare_constant_time returns 1 iff a and b are equal, 0 otherwise.
@@ -58,3 +59,24 @@ rand_bytes :: proc (dst: []byte) {
_rand_bytes(dst)
}
random_generator :: proc() -> runtime.Random_Generator {
return {
procedure = proc(data: rawptr, mode: runtime.Random_Generator_Mode, p: []byte) {
switch mode {
case .Read:
rand_bytes(p)
case .Reset:
// do nothing
case .Query_Info:
if len(p) != size_of(runtime.Random_Generator_Query_Info) {
return
}
info := (^runtime.Random_Generator_Query_Info)(raw_data(p))
info^ += {.Uniform, .Cryptographic, .External_Entropy}
}
},
data = nil,
}
}
+54 -69
View File
@@ -56,38 +56,27 @@ CDATA_END :: "]]>"
COMMENT_START :: "<!--"
COMMENT_END :: "-->"
/*
Default: CDATA and comments are passed through unchanged.
*/
// Default: CDATA and comments are passed through unchanged.
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,
/*
CDATA is unboxed.
*/
// CDATA is unboxed.
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,
/*
Comments are stripped.
*/
// Comments are stripped.
Comment_Strip,
// Normalize whitespace
Normalize_Whitespace,
}
XML_Decode_Options :: bit_set[XML_Decode_Option; u8]
/*
Decode a string that may include SGML/XML/HTML entities.
The caller has to free the result.
*/
// Decode a string that may include SGML/XML/HTML entities.
// The caller has to free the result.
decode_xml :: proc(input: string, options := XML_Decode_Options{}, allocator := context.allocator) -> (decoded: string, err: Error) {
context.allocator = allocator
@@ -100,14 +89,14 @@ decode_xml :: proc(input: string, options := XML_Decode_Options{}, allocator :=
t := Tokenizer{src=input}
in_data := false
prev: rune = ' '
loop: for {
advance(&t) or_return
if t.r < 0 { break loop }
/*
Below here we're never inside a CDATA tag.
At most we'll see the start of one, but that doesn't affect the logic.
*/
// Below here we're never inside a CDATA tag. At most we'll see the start of one,
// but that doesn't affect the logic.
switch t.r {
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
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 t.read_offset + len(CDATA_END) < len(t.src) {
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:
if in_data && .Decode_CDATA not_in options {
/*
Unboxed, but undecoded.
*/
// Unboxed, but undecoded.
write_rune(&builder, t.r)
continue
}
if t.r == '&' {
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)
} else {
if .No_Entity_Decode not_in options {
if decoded, ok := xml_decode_entity(entity); ok {
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, entity)
write_string(&builder, ";")
}
} 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
}
@@ -253,24 +256,18 @@ xml_decode_entity :: proc(entity: string) -> (decoded: rune, ok: bool) {
return rune(val), true
case:
/*
Named entity.
*/
// Named entity.
return named_xml_entity_to_rune(entity)
}
}
/*
Private XML helper to extract `&<stuff>;` entity.
*/
// Private XML helper to extract `&<stuff>;` entity.
@(private="file")
_extract_xml_entity :: proc(t: ^Tokenizer) -> (entity: string, err: Error) {
assert(t != nil && t.r == '&')
/*
All of these would be in the ASCII range.
Even if one is not, it doesn't matter. All characters we need to compare to extract are.
*/
// All of these would be in the ASCII range.
// Even if one is not, it doesn't matter. All characters we need to compare to extract are.
length := len(t.src)
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
}
/*
Private XML helper for CDATA and comments.
*/
// Private XML helper for CDATA and comments.
@(private="file")
_handle_xml_special :: proc(t: ^Tokenizer, builder: ^strings.Builder, options: XML_Decode_Options) -> (in_data: bool, err: Error) {
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
if .Unbox_CDATA in options && .Decode_CDATA in options {
/*
We're unboxing _and_ decoding CDATA
*/
// We're unboxing _and_ decoding CDATA
return true, .None
}
/*
CDATA is passed through.
*/
// CDATA is passed through.
offset := t.offset
/*
Scan until end of CDATA.
*/
// Scan until end of CDATA.
for {
advance(t) or_return
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 {
t.read_offset += len(COMMENT_START)
/*
Comment is passed through by default.
*/
// Comment is passed through by default.
offset := t.offset
/*
Scan until end of Comment.
*/
// Scan until end of Comment.
for {
advance(t) or_return
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) {
advance_rune(t)
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 {
break
}
@@ -268,14 +266,10 @@ scan_comment :: proc(t: ^Tokenizer) -> (comment: string, err: Error) {
return string(t.src[offset : t.offset - 1]), .None
}
/*
Skip CDATA
*/
// Skip CDATA
skip_cdata :: proc(t: ^Tokenizer) -> (err: Error) {
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
}
@@ -290,9 +284,7 @@ skip_cdata :: proc(t: ^Tokenizer) -> (err: Error) {
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 string(t.src[t.offset:][:len(CDATA_END)]) == CDATA_END {
t.read_offset += len(CDATA_END)
@@ -319,14 +311,10 @@ scan_string :: proc(t: ^Tokenizer, offset: int, close: rune = '<', consume_close
case '<':
if peek_byte(t) == '!' {
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
} else if peek_byte(t, 1) == '-' && peek_byte(t, 2) == '-' {
/*
Comment start. Eat comment.
*/
// Comment start. Eat comment.
t.read_offset += 3
_ = 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 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
}
advance_rune(t)
}
/*
Strip trailing whitespace.
*/
// Strip trailing whitespace.
lit := string(t.src[offset : t.offset])
end := len(lit)
@@ -369,11 +353,6 @@ scan_string :: proc(t: ^Tokenizer, offset: int, close: rune = '<', consume_close
if consume_close {
advance_rune(t)
}
/*
TODO: Handle decoding escape characters and unboxing CDATA.
*/
return lit, err
}
@@ -384,7 +363,7 @@ peek :: proc(t: ^Tokenizer) -> (token: Token) {
return token
}
scan :: proc(t: ^Tokenizer) -> Token {
scan :: proc(t: ^Tokenizer, multiline_string := false) -> Token {
skip_whitespace(t)
offset := t.offset
@@ -418,7 +397,7 @@ scan :: proc(t: ^Tokenizer) -> Token {
case '"', '\'':
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 {
kind = .String
}
@@ -435,4 +414,4 @@ scan :: proc(t: ^Tokenizer) -> Token {
lit = string(t.src[offset : t.offset])
}
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)
// strings.intern_init(&doc.intern, allocator, allocator)
err = .Unexpected_Token
err = .Unexpected_Token
element, parent: Element_ID
open: Token
@@ -259,8 +257,8 @@ parse_bytes :: proc(data: []u8, options := DEFAULT_OPTIONS, path := "", error_ha
case .Slash:
// Empty tag. Close it.
expect(t, .Gt) or_return
parent = doc.elements[element].parent
element = parent
parent = doc.elements[element].parent
element = parent
case:
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)
return doc, .Mismatched_Closing_Tag
}
parent = doc.elements[element].parent
element = parent
parent = doc.elements[element].parent
element = parent
} else if open.kind == .Exclaim {
// <!
@@ -463,8 +461,8 @@ validate_options :: proc(options: Options) -> (validated: Options, err: Error) {
return validated, .None
}
expect :: proc(t: ^Tokenizer, kind: Token_Kind) -> (tok: Token, err: Error) {
tok = scan(t)
expect :: proc(t: ^Tokenizer, kind: Token_Kind, multiline_string := false) -> (tok: Token, err: Error) {
tok = scan(t, multiline_string=multiline_string)
if tok.kind == kind { return tok, .None }
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)
_ = 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.val = value.text
+1
View File
@@ -9,6 +9,7 @@ The verbs:
General:
%v the value in a default format
%#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
%% a literal percent sign; 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)
if name != "" {
io.write_string(fi.writer, name, &fi.n)
} else {
reflect.write_type(fi.writer, type_info, &fi.n)
if verb != 'w' {
if name != "" {
io.write_string(fi.writer, name, &fi.n)
} else {
reflect.write_type(fi.writer, type_info, &fi.n)
}
}
io.write_byte(fi.writer, '{', &fi.n)
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 {
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 {
v := u64(ev)
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)
commas += 1
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_Slice,
runtime.Type_Info_Struct,
runtime.Type_Info_Union,
runtime.Type_Info_Enum,
runtime.Type_Info_Map,
runtime.Type_Info_Bit_Set,
@@ -2498,8 +2507,9 @@ fmt_matrix :: proc(fi: ^Info, v: any, verb: rune, info: runtime.Type_Info_Matrix
}
} else {
// Printed in Row-Major layout to match text layout
row_separator := ", " if verb == 'w' else "; "
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 {
if col > 0 { io.write_string(fi.writer, ", ", &fi.n) }
+5 -5
View File
@@ -362,11 +362,11 @@ platform_count_lsb :: #force_inline proc(a: $T) -> (count: int)
count_lsb :: proc { int_count_lsb, platform_count_lsb, }
int_random_digit :: proc(r: ^rnd.Rand = nil) -> (res: DIGIT) {
int_random_digit :: proc() -> (res: DIGIT) {
when _DIGIT_BITS == 60 { // DIGIT = u64
return DIGIT(rnd.uint64(r)) & _MASK
return DIGIT(rnd.uint64()) & _MASK
} else when _DIGIT_BITS == 28 { // DIGIT = u32
return DIGIT(rnd.uint32(r)) & _MASK
return DIGIT(rnd.uint32()) & _MASK
} else {
panic("Unsupported DIGIT size.")
}
@@ -374,12 +374,12 @@ int_random_digit :: proc(r: ^rnd.Rand = nil) -> (res: DIGIT) {
return 0 // We shouldn't get here.
}
int_random :: proc(dest: ^Int, bits: int, r: ^rnd.Rand = nil, allocator := context.allocator) -> (err: Error) {
int_random :: proc(dest: ^Int, bits: int, allocator := context.allocator) -> (err: Error) {
/*
Check that `a` is usable.
*/
assert_if_nil(dest)
return #force_inline internal_int_random(dest, bits, r, allocator)
return #force_inline internal_int_random(dest, bits, allocator)
}
random :: proc { int_random, }
+12 -7
View File
@@ -2178,15 +2178,20 @@ internal_int_grow :: proc(a: ^Int, digits: int, allow_shrink := false, allocator
}
/*
If not yet iniialized, initialize the `digit` backing with the allocator we were passed.
If not yet initialized, initialize the `digit` backing with the allocator we were passed.
*/
if cap == 0 {
a.digit = make([dynamic]DIGIT, needed, allocator)
} else if cap != needed {
} else if cap < needed {
/*
`[dynamic]DIGIT` already knows what allocator was used for it, so resize will do the right thing.
*/
resize(&a.digit, needed)
} else if cap > needed {
/*
Same applies to builtin.shrink here as resize above
*/
builtin.shrink(&a.digit, needed)
}
/*
Let's see if the allocation/resize worked as expected.
@@ -2812,11 +2817,11 @@ internal_platform_count_lsb :: #force_inline proc(a: $T) -> (count: int)
internal_count_lsb :: proc { internal_int_count_lsb, internal_platform_count_lsb, }
internal_int_random_digit :: proc(r: ^rnd.Rand = nil) -> (res: DIGIT) {
internal_int_random_digit :: proc() -> (res: DIGIT) {
when _DIGIT_BITS == 60 { // DIGIT = u64
return DIGIT(rnd.uint64(r)) & _MASK
return DIGIT(rnd.uint64()) & _MASK
} else when _DIGIT_BITS == 28 { // DIGIT = u32
return DIGIT(rnd.uint32(r)) & _MASK
return DIGIT(rnd.uint32()) & _MASK
} else {
panic("Unsupported DIGIT size.")
}
@@ -2824,7 +2829,7 @@ internal_int_random_digit :: proc(r: ^rnd.Rand = nil) -> (res: DIGIT) {
return 0 // We shouldn't get here.
}
internal_int_random :: proc(dest: ^Int, bits: int, r: ^rnd.Rand = nil, allocator := context.allocator) -> (err: Error) {
internal_int_random :: proc(dest: ^Int, bits: int, allocator := context.allocator) -> (err: Error) {
context.allocator = allocator
bits := bits
@@ -2841,7 +2846,7 @@ internal_int_random :: proc(dest: ^Int, bits: int, r: ^rnd.Rand = nil, allocator
#force_inline internal_grow(dest, digits) or_return
for i := 0; i < digits; i += 1 {
dest.digit[i] = int_random_digit(r) & _MASK
dest.digit[i] = int_random_digit() & _MASK
}
if bits > 0 {
dest.digit[digits - 1] &= ((1 << uint(bits)) - 1)
+3 -5
View File
@@ -12,8 +12,6 @@
package math_big
import rnd "core:math/rand"
/*
Determines if an Integer is divisible by one of the _PRIME_TABLE primes.
Returns true if it is, false if not.
@@ -315,7 +313,7 @@ internal_int_prime_miller_rabin :: proc(a, b: ^Int, allocator := context.allocat
Assumes `a` not to be `nil` and to have been initialized.
*/
internal_int_is_prime :: proc(a: ^Int, miller_rabin_trials := int(-1), miller_rabin_only := USE_MILLER_RABIN_ONLY, r: ^rnd.Rand = nil, allocator := context.allocator) -> (is_prime: bool, err: Error) {
internal_int_is_prime :: proc(a: ^Int, miller_rabin_trials := int(-1), miller_rabin_only := USE_MILLER_RABIN_ONLY, allocator := context.allocator) -> (is_prime: bool, err: Error) {
context.allocator = allocator
miller_rabin_trials := miller_rabin_trials
@@ -461,7 +459,7 @@ internal_int_is_prime :: proc(a: ^Int, miller_rabin_trials := int(-1), miller_ra
for ix := 0; ix < miller_rabin_trials; ix += 1 {
// rand() guarantees the first digit to be non-zero
internal_random(b, _DIGIT_TYPE_BITS, r) or_return
internal_random(b, _DIGIT_TYPE_BITS) or_return
// Reduce digit before casting because DIGIT might be bigger than
// an unsigned int and "mask" on the other side is most probably not.
@@ -1183,7 +1181,7 @@ internal_int_prime_next_prime :: proc(a: ^Int, trials: int, bbs_style: bool, all
This is possibly the mother of all prime generation functions, muahahahahaha!
*/
internal_random_prime :: proc(a: ^Int, size_in_bits: int, trials: int, flags := Primality_Flags{}, r: ^rnd.Rand = nil, allocator := context.allocator) -> (err: Error) {
internal_random_prime :: proc(a: ^Int, size_in_bits: int, trials: int, flags := Primality_Flags{}, allocator := context.allocator) -> (err: Error) {
context.allocator = allocator
flags := flags
trials := trials
+60 -60
View File
@@ -8,12 +8,12 @@ float32_uniform :: float32_range
// Triangular Distribution
// See: http://wikipedia.org/wiki/Triangular_distribution
@(require_results)
float64_triangular :: proc(lo, hi: f64, mode: Maybe(f64), r: ^Rand = nil) -> f64 {
float64_triangular :: proc(lo, hi: f64, mode: Maybe(f64)) -> f64 {
if hi-lo == 0 {
return lo
}
lo, hi := lo, hi
u := float64(r)
u := float64()
c := f64(0.5) if mode == nil else clamp((mode.?-lo) / (hi-lo), 0, 1)
if u > c {
u = 1-u
@@ -26,12 +26,12 @@ float64_triangular :: proc(lo, hi: f64, mode: Maybe(f64), r: ^Rand = nil) -> f64
// Triangular Distribution
// See: http://wikipedia.org/wiki/Triangular_distribution
@(require_results)
float32_triangular :: proc(lo, hi: f32, mode: Maybe(f32), r: ^Rand = nil) -> f32 {
float32_triangular :: proc(lo, hi: f32, mode: Maybe(f32)) -> f32 {
if hi-lo == 0 {
return lo
}
lo, hi := lo, hi
u := float32(r)
u := float32()
c := f32(0.5) if mode == nil else clamp((mode.?-lo) / (hi-lo), 0, 1)
if u > c {
u = 1-u
@@ -44,25 +44,25 @@ float32_triangular :: proc(lo, hi: f32, mode: Maybe(f32), r: ^Rand = nil) -> f32
// Normal/Gaussian Distribution
@(require_results)
float64_normal :: proc(mean, stddev: f64, r: ^Rand = nil) -> f64 {
return norm_float64(r) * stddev + mean
float64_normal :: proc(mean, stddev: f64) -> f64 {
return norm_float64() * stddev + mean
}
// Normal/Gaussian Distribution
@(require_results)
float32_normal :: proc(mean, stddev: f32, r: ^Rand = nil) -> f32 {
return f32(float64_normal(f64(mean), f64(stddev), r))
float32_normal :: proc(mean, stddev: f32) -> f32 {
return f32(float64_normal(f64(mean), f64(stddev)))
}
// Log Normal Distribution
@(require_results)
float64_log_normal :: proc(mean, stddev: f64, r: ^Rand = nil) -> f64 {
return math.exp(float64_normal(mean, stddev, r))
float64_log_normal :: proc(mean, stddev: f64) -> f64 {
return math.exp(float64_normal(mean, stddev))
}
// Log Normal Distribution
@(require_results)
float32_log_normal :: proc(mean, stddev: f32, r: ^Rand = nil) -> f32 {
return f32(float64_log_normal(f64(mean), f64(stddev), r))
float32_log_normal :: proc(mean, stddev: f32) -> f32 {
return f32(float64_log_normal(f64(mean), f64(stddev)))
}
@@ -72,8 +72,8 @@ float32_log_normal :: proc(mean, stddev: f32, r: ^Rand = nil) -> f32 {
// 0 to positive infinity if lambda > 0
// negative infinity to 0 if lambda <= 0
@(require_results)
float64_exponential :: proc(lambda: f64, r: ^Rand = nil) -> f64 {
return - math.ln(1 - float64(r)) / lambda
float64_exponential :: proc(lambda: f64) -> f64 {
return - math.ln(1 - float64()) / lambda
}
// Exponential Distribution
// `lambda` is 1.0/(desired mean). It should be non-zero.
@@ -81,8 +81,8 @@ float64_exponential :: proc(lambda: f64, r: ^Rand = nil) -> f64 {
// 0 to positive infinity if lambda > 0
// negative infinity to 0 if lambda <= 0
@(require_results)
float32_exponential :: proc(lambda: f32, r: ^Rand = nil) -> f32 {
return f32(float64_exponential(f64(lambda), r))
float32_exponential :: proc(lambda: f32) -> f32 {
return f32(float64_exponential(f64(lambda)))
}
@@ -96,7 +96,7 @@ float32_exponential :: proc(lambda: f32, r: ^Rand = nil) -> f32 {
//
// mean is alpha*beta, variance is math.pow(alpha*beta, 2)
@(require_results)
float64_gamma :: proc(alpha, beta: f64, r: ^Rand = nil) -> f64 {
float64_gamma :: proc(alpha, beta: f64) -> f64 {
if alpha <= 0 || beta <= 0 {
panic(#procedure + ": alpha and beta must be > 0.0")
}
@@ -112,11 +112,11 @@ float64_gamma :: proc(alpha, beta: f64, r: ^Rand = nil) -> f64 {
bbb := alpha - LOG4
ccc := alpha + ainv
for {
u1 := float64(r)
u1 := float64()
if !(1e-7 < u1 && u1 < 0.9999999) {
continue
}
u2 := 1 - float64(r)
u2 := 1 - float64()
v := math.ln(u1 / (1 - u1)) / ainv
x := alpha * math.exp(v)
z := u1 * u1 * u2
@@ -127,12 +127,12 @@ float64_gamma :: proc(alpha, beta: f64, r: ^Rand = nil) -> f64 {
}
case alpha == 1:
// float64_exponential(1/beta)
return -math.ln(1 - float64(r)) * beta
return -math.ln(1 - float64()) * beta
case:
// ALGORITHM GS of Statistical Computing - Kennedy & Gentle
x: f64
for {
u := float64(r)
u := float64()
b := (math.e + alpha) / math.e
p := b * u
if p <= 1 {
@@ -140,7 +140,7 @@ float64_gamma :: proc(alpha, beta: f64, r: ^Rand = nil) -> f64 {
} else {
x = -math.ln((b - p) / alpha)
}
u1 := float64(r)
u1 := float64()
if p > 1 {
if u1 <= math.pow(x, alpha-1) {
break
@@ -162,8 +162,8 @@ float64_gamma :: proc(alpha, beta: f64, r: ^Rand = nil) -> f64 {
//
// mean is alpha*beta, variance is math.pow(alpha*beta, 2)
@(require_results)
float32_gamma :: proc(alpha, beta: f32, r: ^Rand = nil) -> f32 {
return f32(float64_gamma(f64(alpha), f64(beta), r))
float32_gamma :: proc(alpha, beta: f32) -> f32 {
return f32(float64_gamma(f64(alpha), f64(beta)))
}
@@ -173,14 +173,14 @@ float32_gamma :: proc(alpha, beta: f32, r: ^Rand = nil) -> f32 {
//
// Return values range between 0 and 1
@(require_results)
float64_beta :: proc(alpha, beta: f64, r: ^Rand = nil) -> f64 {
float64_beta :: proc(alpha, beta: f64) -> f64 {
if alpha <= 0 || beta <= 0 {
panic(#procedure + ": alpha and beta must be > 0.0")
}
// Knuth Vol 2 Ed 3 pg 134 "the beta distribution"
y := float64_gamma(alpha, 1.0, r)
y := float64_gamma(alpha, 1.0)
if y != 0 {
return y / (y + float64_gamma(beta, 1.0, r))
return y / (y + float64_gamma(beta, 1.0))
}
return 0
}
@@ -190,35 +190,35 @@ float64_beta :: proc(alpha, beta: f64, r: ^Rand = nil) -> f64 {
//
// Return values range between 0 and 1
@(require_results)
float32_beta :: proc(alpha, beta: f32, r: ^Rand = nil) -> f32 {
return f32(float64_beta(f64(alpha), f64(beta), r))
float32_beta :: proc(alpha, beta: f32) -> f32 {
return f32(float64_beta(f64(alpha), f64(beta)))
}
// Pareto distribution, `alpha` is the shape parameter.
// https://wikipedia.org/wiki/Pareto_distribution
@(require_results)
float64_pareto :: proc(alpha: f64, r: ^Rand = nil) -> f64 {
return math.pow(1 - float64(r), -1.0 / alpha)
float64_pareto :: proc(alpha: f64) -> f64 {
return math.pow(1 - float64(), -1.0 / alpha)
}
// Pareto distribution, `alpha` is the shape parameter.
// https://wikipedia.org/wiki/Pareto_distribution
@(require_results)
float32_pareto :: proc(alpha, beta: f32, r: ^Rand = nil) -> f32 {
return f32(float64_pareto(f64(alpha), r))
float32_pareto :: proc(alpha, beta: f32) -> f32 {
return f32(float64_pareto(f64(alpha)))
}
// Weibull distribution, `alpha` is the scale parameter, `beta` is the shape parameter.
@(require_results)
float64_weibull :: proc(alpha, beta: f64, r: ^Rand = nil) -> f64 {
u := 1 - float64(r)
float64_weibull :: proc(alpha, beta: f64) -> f64 {
u := 1 - float64()
return alpha * math.pow(-math.ln(u), 1.0/beta)
}
// Weibull distribution, `alpha` is the scale parameter, `beta` is the shape parameter.
@(require_results)
float32_weibull :: proc(alpha, beta: f32, r: ^Rand = nil) -> f32 {
return f32(float64_weibull(f64(alpha), f64(beta), r))
float32_weibull :: proc(alpha, beta: f32) -> f32 {
return f32(float64_weibull(f64(alpha), f64(beta)))
}
@@ -227,23 +227,23 @@ float32_weibull :: proc(alpha, beta: f32, r: ^Rand = nil) -> f32 {
// `kappa` is the concentration parameter which must be >= 0
// When `kappa` is zero, the Distribution is a uniform Distribution over the range 0 to 2pi
@(require_results)
float64_von_mises :: proc(mean_angle, kappa: f64, r: ^Rand = nil) -> f64 {
float64_von_mises :: proc(mean_angle, kappa: f64) -> f64 {
// Fisher, N.I., "Statistical Analysis of Circular Data", Cambridge University Press, 1993.
mu := mean_angle
if kappa <= 1e-6 {
return math.TAU * float64(r)
return math.TAU * float64()
}
s := 0.5 / kappa
t := s + math.sqrt(1 + s*s)
z: f64
for {
u1 := float64(r)
u1 := float64()
z = math.cos(math.TAU * 0.5 * u1)
d := z / (t + z)
u2 := float64(r)
u2 := float64()
if u2 < 1 - d*d || u2 <= (1-d)*math.exp(d) {
break
}
@@ -251,7 +251,7 @@ float64_von_mises :: proc(mean_angle, kappa: f64, r: ^Rand = nil) -> f64 {
q := 1.0 / t
f := (q + z) / (1 + q*z)
u3 := float64(r)
u3 := float64()
if u3 > 0.5 {
return math.mod(mu + math.acos(f), math.TAU)
} else {
@@ -263,57 +263,57 @@ float64_von_mises :: proc(mean_angle, kappa: f64, r: ^Rand = nil) -> f64 {
// `kappa` is the concentration parameter which must be >= 0
// When `kappa` is zero, the Distribution is a uniform Distribution over the range 0 to 2pi
@(require_results)
float32_von_mises :: proc(mean_angle, kappa: f32, r: ^Rand = nil) -> f32 {
return f32(float64_von_mises(f64(mean_angle), f64(kappa), r))
float32_von_mises :: proc(mean_angle, kappa: f32) -> f32 {
return f32(float64_von_mises(f64(mean_angle), f64(kappa)))
}
// Cauchy-Lorentz Distribution
// `x_0` is the location, `gamma` is the scale where `gamma` > 0
@(require_results)
float64_cauchy_lorentz :: proc(x_0, gamma: f64, r: ^Rand = nil) -> f64 {
float64_cauchy_lorentz :: proc(x_0, gamma: f64) -> f64 {
assert(gamma > 0)
// Calculated from the inverse CDF
return math.tan(math.PI * (float64(r) - 0.5))*gamma + x_0
return math.tan(math.PI * (float64() - 0.5))*gamma + x_0
}
// Cauchy-Lorentz Distribution
// `x_0` is the location, `gamma` is the scale where `gamma` > 0
@(require_results)
float32_cauchy_lorentz :: proc(x_0, gamma: f32, r: ^Rand = nil) -> f32 {
return f32(float64_cauchy_lorentz(f64(x_0), f64(gamma), r))
float32_cauchy_lorentz :: proc(x_0, gamma: f32) -> f32 {
return f32(float64_cauchy_lorentz(f64(x_0), f64(gamma)))
}
// Log Cauchy-Lorentz Distribution
// `x_0` is the location, `gamma` is the scale where `gamma` > 0
@(require_results)
float64_log_cauchy_lorentz :: proc(x_0, gamma: f64, r: ^Rand = nil) -> f64 {
float64_log_cauchy_lorentz :: proc(x_0, gamma: f64) -> f64 {
assert(gamma > 0)
return math.exp(math.tan(math.PI * (float64(r) - 0.5))*gamma + x_0)
return math.exp(math.tan(math.PI * (float64() - 0.5))*gamma + x_0)
}
// Log Cauchy-Lorentz Distribution
// `x_0` is the location, `gamma` is the scale where `gamma` > 0
@(require_results)
float32_log_cauchy_lorentz :: proc(x_0, gamma: f32, r: ^Rand = nil) -> f32 {
return f32(float64_log_cauchy_lorentz(f64(x_0), f64(gamma), r))
float32_log_cauchy_lorentz :: proc(x_0, gamma: f32) -> f32 {
return f32(float64_log_cauchy_lorentz(f64(x_0), f64(gamma)))
}
// Laplace Distribution
// `b` is the scale where `b` > 0
@(require_results)
float64_laplace :: proc(mean, b: f64, r: ^Rand = nil) -> f64 {
float64_laplace :: proc(mean, b: f64) -> f64 {
assert(b > 0)
p := float64(r)-0.5
p := float64()-0.5
return -math.sign(p)*math.ln(1 - 2*abs(p))*b + mean
}
// Laplace Distribution
// `b` is the scale where `b` > 0
@(require_results)
float32_laplace :: proc(mean, b: f32, r: ^Rand = nil) -> f32 {
return f32(float64_laplace(f64(mean), f64(b), r))
float32_laplace :: proc(mean, b: f32) -> f32 {
return f32(float64_laplace(f64(mean), f64(b)))
}
@@ -321,18 +321,18 @@ float32_laplace :: proc(mean, b: f32, r: ^Rand = nil) -> f32 {
// `eta` is the shape, `b` is the scale
// Both `eta` and `b` must be > 0
@(require_results)
float64_gompertz :: proc(eta, b: f64, r: ^Rand = nil) -> f64 {
float64_gompertz :: proc(eta, b: f64) -> f64 {
if eta <= 0 || b <= 0 {
panic(#procedure + ": eta and b must be > 0.0")
}
p := float64(r)
p := float64()
return math.ln(1 - math.ln(1 - p)/eta)/b
}
// Gompertz Distribution
// `eta` is the shape, `b` is the scale
// Both `eta` and `b` must be > 0
@(require_results)
float32_gompertz :: proc(eta, b: f32, r: ^Rand = nil) -> f32 {
return f32(float64_gompertz(f64(eta), f64(b), r))
float32_gompertz :: proc(eta, b: f32) -> f32 {
return f32(float64_gompertz(f64(eta), f64(b)))
}
+4 -4
View File
@@ -16,7 +16,7 @@ import "core:math"
// https://www.jstatsoft.org/article/view/v005i08 [web page]
//
@(require_results)
exp_float64 :: proc(r: ^Rand = nil) -> f64 {
exp_float64 :: proc() -> f64 {
re :: 7.69711747013104972
@(static, rodata)
@@ -199,16 +199,16 @@ exp_float64 :: proc(r: ^Rand = nil) -> f64 {
}
for {
j := uint32(r)
j := uint32()
i := j & 0xFF
x := f64(j) * f64(we[i])
if j < ke[i] {
return x
}
if i == 0 {
return re - math.ln(float64(r))
return re - math.ln(float64())
}
if fe[i]+f32(float64(r))*(fe[i-1]-fe[i]) < f32(math.exp(-x)) {
if fe[i]+f32(float64())*(fe[i-1]-fe[i]) < f32(math.exp(-x)) {
return x
}
}
+5 -12
View File
@@ -18,7 +18,7 @@ import "core:math"
// https://www.jstatsoft.org/article/view/v005i08 [web page]
//
@(require_results)
norm_float64 :: proc(r: ^Rand = nil) -> f64 {
norm_float64 :: proc() -> f64 {
rn :: 3.442619855899
@(static, rodata)
@@ -115,15 +115,8 @@ norm_float64 :: proc(r: ^Rand = nil) -> f64 {
0.008624485, 0.005548995, 0.0026696292,
}
r := r
if r == nil {
// NOTE(bill, 2020-09-07): Do this so that people can
// enforce the global random state if necessary with `nil`
r = &global_rand
}
for {
j := i32(uint32(r))
j := i32(uint32())
i := j & 0x7f
x := f64(j) * f64(wn[i])
if u32(abs(j)) < kn[i] {
@@ -133,15 +126,15 @@ norm_float64 :: proc(r: ^Rand = nil) -> f64 {
if i == 0 {
for {
x = -math.ln(float64(r)) * (1.0/ rn)
y := -math.ln(float64(r))
x = -math.ln(float64()) * (1.0/ rn)
y := -math.ln(float64())
if y+y >= x*x {
break
}
}
return j > 0 ? rn + x : -rn - x
}
if fn[i]+f32(float64(r))*(fn[i-1]-fn[i]) < f32(math.exp(-0.5*x*x)) {
if fn[i]+f32(float64())*(fn[i-1]-fn[i]) < f32(math.exp(-0.5*x*x)) {
return x
}
}
+63 -252
View File
@@ -5,22 +5,22 @@ Package core:math/rand implements various random number generators
package rand
import "base:intrinsics"
import "core:crypto"
import "base:runtime"
import "core:math"
import "core:mem"
Rand :: struct {
state: u64,
inc: u64,
is_system: bool,
Default_Random_State :: runtime.Default_Random_State
default_random_generator :: runtime.default_random_generator
create :: proc(seed: u64) -> (state: Default_Random_State) {
seed := seed
runtime.default_random_generator(&state)
runtime.default_random_generator_proc(&state, .Reset, ([^]byte)(&seed)[:size_of(seed)])
return
}
@(private)
global_rand := create(u64(intrinsics.read_cycle_counter()))
/*
Sets the seed used by the global random number generator.
Reset the seed used by the context.random_generator.
Inputs:
- seed: The seed value
@@ -37,139 +37,46 @@ Example:
Possible Output:
10
*/
@(deprecated="Prefer `rand.reset`")
set_global_seed :: proc(seed: u64) {
init(&global_rand, seed)
runtime.random_generator_reset_u64(context.random_generator, seed)
}
/*
Creates a new random number generator.
Reset the seed used by the context.random_generator.
Inputs:
- seed: The seed value to create the random number generator with
Returns:
- res: The created random number generator
- seed: The seed value
Example:
import "core:math/rand"
import "core:fmt"
create_example :: proc() {
my_rand := rand.create(1)
fmt.println(rand.uint64(&my_rand))
set_global_seed_example :: proc() {
rand.set_global_seed(1)
fmt.println(rand.uint64())
}
Possible Output:
10
*/
@(require_results)
create :: proc(seed: u64) -> (res: Rand) {
r: Rand
init(&r, seed)
return r
reset :: proc(seed: u64) {
runtime.random_generator_reset_u64(context.random_generator, seed)
}
/*
Initialises a random number generator.
Inputs:
- r: The random number generator to initialise
- seed: The seed value to initialise this random number generator
Example:
import "core:math/rand"
import "core:fmt"
init_example :: proc() {
my_rand: rand.Rand
rand.init(&my_rand, 1)
fmt.println(rand.uint64(&my_rand))
}
Possible Output:
10
*/
init :: proc(r: ^Rand, seed: u64) {
r.state = 0
r.inc = (seed << 1) | 1
_random_u64(r)
r.state += seed
_random_u64(r)
}
/*
Initialises a random number generator to use the system random number generator.
The system random number generator is platform specific, and not supported
on all targets.
Inputs:
- r: The random number generator to use the system random number generator
WARNING: Panics if the system random number generator is not supported.
Support can be determined via the `core:crypto.HAS_RAND_BYTES` constant.
Example:
import "core:crypto"
import "core:math/rand"
import "core:fmt"
init_as_system_example :: proc() {
my_rand: rand.Rand
switch crypto.HAS_RAND_BYTES {
case true:
rand.init_as_system(&my_rand)
fmt.println(rand.uint64(&my_rand))
case false:
fmt.println("system random not supported!")
}
}
Possible Output:
10
*/
init_as_system :: proc(r: ^Rand) {
if !crypto.HAS_RAND_BYTES {
panic(#procedure + " is not supported on this platform yet")
}
r.state = 0
r.inc = 0
r.is_system = true
}
@(private)
_random_u64 :: proc(r: ^Rand) -> u64 {
r := r
switch {
case r == nil:
r = &global_rand
case r.is_system:
value: u64
crypto.rand_bytes((cast([^]u8)&value)[:size_of(u64)])
return value
}
old_state := r.state
r.state = old_state * 6364136223846793005 + (r.inc|1)
xor_shifted := (((old_state >> 59) + 5) ~ old_state) * 12605985483714917081
rot := (old_state >> 59)
return (xor_shifted >> rot) | (xor_shifted << ((-rot) & 63))
_random_u64 :: proc() -> (res: u64) {
ok := runtime.random_generator_read_ptr(context.random_generator, &res, size_of(res))
assert(ok, "uninitialized context.random_generator")
return
}
/*
Generates a random 32 bit value using the provided random number generator. If no generator is provided the global random number generator will be used.
Inputs:
- r: The random number generator to use, or nil for the global generator
Returns:
- val: A random unsigned 32 bit value
@@ -178,11 +85,7 @@ Example:
import "core:fmt"
uint32_example :: proc() {
// Using the global random number generator
fmt.println(rand.uint32())
// Using local random number generator
my_rand := rand.create(1)
fmt.println(rand.uint32(&my_rand))
}
Possible Output:
@@ -192,14 +95,11 @@ Possible Output:
*/
@(require_results)
uint32 :: proc(r: ^Rand = nil) -> (val: u32) { return u32(_random_u64(r)) }
uint32 :: proc() -> (val: u32) { return u32(_random_u64()) }
/*
Generates a random 64 bit value using the provided random number generator. If no generator is provided the global random number generator will be used.
Inputs:
- r: The random number generator to use, or nil for the global generator
Returns:
- val: A random unsigned 64 bit value
@@ -208,11 +108,7 @@ Example:
import "core:fmt"
uint64_example :: proc() {
// Using the global random number generator
fmt.println(rand.uint64())
// Using local random number generator
my_rand := rand.create(1)
fmt.println(rand.uint64(&my_rand))
}
Possible Output:
@@ -222,14 +118,11 @@ Possible Output:
*/
@(require_results)
uint64 :: proc(r: ^Rand = nil) -> (val: u64) { return _random_u64(r) }
uint64 :: proc() -> (val: u64) { return _random_u64() }
/*
Generates a random 128 bit value using the provided random number generator. If no generator is provided the global random number generator will be used.
Inputs:
- r: The random number generator to use, or nil for the global generator
Returns:
- val: A random unsigned 128 bit value
@@ -238,11 +131,7 @@ Example:
import "core:fmt"
uint128_example :: proc() {
// Using the global random number generator
fmt.println(rand.uint128())
// Using local random number generator
my_rand := rand.create(1)
fmt.println(rand.uint128(&my_rand))
}
Possible Output:
@@ -252,9 +141,9 @@ Possible Output:
*/
@(require_results)
uint128 :: proc(r: ^Rand = nil) -> (val: u128) {
a := u128(_random_u64(r))
b := u128(_random_u64(r))
uint128 :: proc() -> (val: u128) {
a := u128(_random_u64())
b := u128(_random_u64())
return (a<<64) | b
}
@@ -262,9 +151,6 @@ uint128 :: proc(r: ^Rand = nil) -> (val: u128) {
Generates a random 31 bit value using the provided random number generator. If no generator is provided the global random number generator will be used.
The sign bit will always be set to 0, thus all generated numbers will be positive.
Inputs:
- r: The random number generator to use, or nil for the global generator
Returns:
- val: A random 31 bit value
@@ -273,11 +159,7 @@ Example:
import "core:fmt"
int31_example :: proc() {
// Using the global random number generator
fmt.println(rand.int31())
// Using local random number generator
my_rand := rand.create(1)
fmt.println(rand.int31(&my_rand))
}
Possible Output:
@@ -286,15 +168,12 @@ Possible Output:
389
*/
@(require_results) int31 :: proc(r: ^Rand = nil) -> (val: i32) { return i32(uint32(r) << 1 >> 1) }
@(require_results) int31 :: proc() -> (val: i32) { return i32(uint32() << 1 >> 1) }
/*
Generates a random 63 bit value using the provided random number generator. If no generator is provided the global random number generator will be used.
The sign bit will always be set to 0, thus all generated numbers will be positive.
Inputs:
- r: The random number generator to use, or nil for the global generator
Returns:
- val: A random 63 bit value
@@ -303,11 +182,7 @@ Example:
import "core:fmt"
int63_example :: proc() {
// Using the global random number generator
fmt.println(rand.int63())
// Using local random number generator
my_rand := rand.create(1)
fmt.println(rand.int63(&my_rand))
}
Possible Output:
@@ -316,15 +191,12 @@ Possible Output:
389
*/
@(require_results) int63 :: proc(r: ^Rand = nil) -> (val: i64) { return i64(uint64(r) << 1 >> 1) }
@(require_results) int63 :: proc() -> (val: i64) { return i64(uint64() << 1 >> 1) }
/*
Generates a random 127 bit value using the provided random number generator. If no generator is provided the global random number generator will be used.
The sign bit will always be set to 0, thus all generated numbers will be positive.
Inputs:
- r: The random number generator to use, or nil for the global generator
Returns:
- val: A random 127 bit value
@@ -333,11 +205,7 @@ Example:
import "core:fmt"
int127_example :: proc() {
// Using the global random number generator
fmt.println(rand.int127())
// Using local random number generator
my_rand := rand.create(1)
fmt.println(rand.int127(&my_rand))
}
Possible Output:
@@ -346,14 +214,13 @@ Possible Output:
389
*/
@(require_results) int127 :: proc(r: ^Rand = nil) -> (val: i128) { return i128(uint128(r) << 1 >> 1) }
@(require_results) int127 :: proc() -> (val: i128) { return i128(uint128() << 1 >> 1) }
/*
Generates a random 31 bit value in the range `[0, n)` using the provided random number generator. If no generator is provided the global random number generator will be used.
Inputs:
- n: The upper bound of the generated number, this value is exclusive
- r: The random number generator to use, or nil for the global generator
Returns:
- val: A random 31 bit value in the range `[0, n)`
@@ -365,11 +232,7 @@ Example:
import "core:fmt"
int31_max_example :: proc() {
// Using the global random number generator
fmt.println(rand.int31_max(16))
// Using local random number generator
my_rand := rand.create(1)
fmt.println(rand.int31_max(1024, &my_rand))
}
Possible Output:
@@ -379,17 +242,17 @@ Possible Output:
*/
@(require_results)
int31_max :: proc(n: i32, r: ^Rand = nil) -> (val: i32) {
int31_max :: proc(n: i32) -> (val: i32) {
if n <= 0 {
panic("Invalid argument to int31_max")
}
if n&(n-1) == 0 {
return int31(r) & (n-1)
return int31() & (n-1)
}
max := i32((1<<31) - 1 - (1<<31)%u32(n))
v := int31(r)
v := int31()
for v > max {
v = int31(r)
v = int31()
}
return v % n
}
@@ -399,7 +262,6 @@ Generates a random 63 bit value in the range `[0, n)` using the provided random
Inputs:
- n: The upper bound of the generated number, this value is exclusive
- r: The random number generator to use, or nil for the global generator
Returns:
- val: A random 63 bit value in the range `[0, n)`
@@ -411,11 +273,7 @@ Example:
import "core:fmt"
int63_max_example :: proc() {
// Using the global random number generator
fmt.println(rand.int63_max(16))
// Using local random number generator
my_rand := rand.create(1)
fmt.println(rand.int63_max(1024, &my_rand))
}
Possible Output:
@@ -425,17 +283,17 @@ Possible Output:
*/
@(require_results)
int63_max :: proc(n: i64, r: ^Rand = nil) -> (val: i64) {
int63_max :: proc(n: i64) -> (val: i64) {
if n <= 0 {
panic("Invalid argument to int63_max")
}
if n&(n-1) == 0 {
return int63(r) & (n-1)
return int63() & (n-1)
}
max := i64((1<<63) - 1 - (1<<63)%u64(n))
v := int63(r)
v := int63()
for v > max {
v = int63(r)
v = int63()
}
return v % n
}
@@ -445,7 +303,6 @@ Generates a random 127 bit value in the range `[0, n)` using the provided random
Inputs:
- n: The upper bound of the generated number, this value is exclusive
- r: The random number generator to use, or nil for the global generator
Returns:
- val: A random 127 bit value in the range `[0, n)`
@@ -457,11 +314,7 @@ Example:
import "core:fmt"
int127_max_example :: proc() {
// Using the global random number generator
fmt.println(rand.int127_max(16))
// Using local random number generator
my_rand := rand.create(1)
fmt.println(rand.int127_max(1024, &my_rand))
}
Possible Output:
@@ -471,17 +324,17 @@ Possible Output:
*/
@(require_results)
int127_max :: proc(n: i128, r: ^Rand = nil) -> (val: i128) {
int127_max :: proc(n: i128) -> (val: i128) {
if n <= 0 {
panic("Invalid argument to int127_max")
}
if n&(n-1) == 0 {
return int127(r) & (n-1)
return int127() & (n-1)
}
max := i128((1<<127) - 1 - (1<<127)%u128(n))
v := int127(r)
v := int127()
for v > max {
v = int127(r)
v = int127()
}
return v % n
}
@@ -491,7 +344,6 @@ Generates a random integer value in the range `[0, n)` using the provided random
Inputs:
- n: The upper bound of the generated number, this value is exclusive
- r: The random number generator to use, or nil for the global generator
Returns:
- val: A random integer value in the range `[0, n)`
@@ -503,11 +355,7 @@ Example:
import "core:fmt"
int_max_example :: proc() {
// Using the global random number generator
fmt.println(rand.int_max(16))
// Using local random number generator
my_rand := rand.create(1)
fmt.println(rand.int_max(1024, &my_rand))
}
Possible Output:
@@ -517,23 +365,20 @@ Possible Output:
*/
@(require_results)
int_max :: proc(n: int, r: ^Rand = nil) -> (val: int) {
int_max :: proc(n: int) -> (val: int) {
if n <= 0 {
panic("Invalid argument to int_max")
}
when size_of(int) == 4 {
return int(int31_max(i32(n), r))
return int(int31_max(i32(n)))
} else {
return int(int63_max(i64(n), r))
return int(int63_max(i64(n)))
}
}
/*
Generates a random double floating point value in the range `[0, 1)` using the provided random number generator. If no generator is provided the global random number generator will be used.
Inputs:
- r: The random number generator to use, or nil for the global generator
Returns:
- val: A random double floating point value in the range `[0, 1)`
@@ -542,11 +387,7 @@ Example:
import "core:fmt"
float64_example :: proc() {
// Using the global random number generator
fmt.println(rand.float64())
// Using local random number generator
my_rand := rand.create(1)
fmt.println(rand.float64(&my_rand))
}
Possible Output:
@@ -555,14 +396,11 @@ Possible Output:
0.511
*/
@(require_results) float64 :: proc(r: ^Rand = nil) -> (val: f64) { return f64(int63_max(1<<53, r)) / (1 << 53) }
@(require_results) float64 :: proc() -> (val: f64) { return f64(int63_max(1<<53)) / (1 << 53) }
/*
Generates a random single floating point value in the range `[0, 1)` using the provided random number generator. If no generator is provided the global random number generator will be used.
Inputs:
- r: The random number generator to use, or nil for the global generator
Returns:
- val: A random single floating point value in the range `[0, 1)`
@@ -571,11 +409,7 @@ Example:
import "core:fmt"
float32_example :: proc() {
// Using the global random number generator
fmt.println(rand.float32())
// Using local random number generator
my_rand := rand.create(1)
fmt.println(rand.float32(&my_rand))
}
Possible Output:
@@ -584,7 +418,7 @@ Possible Output:
0.511
*/
@(require_results) float32 :: proc(r: ^Rand = nil) -> (val: f32) { return f32(int31_max(1<<24, r)) / (1 << 24) }
@(require_results) float32 :: proc() -> (val: f32) { return f32(int31_max(1<<24)) / (1 << 24) }
/*
Generates a random double floating point value in the range `[low, high)` using the provided random number generator. If no generator is provided the global random number generator will be used.
@@ -594,7 +428,6 @@ WARNING: Panics if `high < low`
Inputs:
- low: The lower bounds of the value, this value is inclusive
- high: The upper bounds of the value, this value is exclusive
- r: The random number generator to use, or nil for the global generator
Returns:
- val: A random double floating point value in the range [low, high)
@@ -604,11 +437,7 @@ Example:
import "core:fmt"
float64_range_example :: proc() {
// Using the global random number generator
fmt.println(rand.float64_range(-10, 300))
// Using local random number generator
my_rand := rand.create(1)
fmt.println(rand.float64_range(600, 900, &my_rand))
}
Possible Output:
@@ -617,9 +446,9 @@ Possible Output:
673.130
*/
@(require_results) float64_range :: proc(low, high: f64, r: ^Rand = nil) -> (val: f64) {
@(require_results) float64_range :: proc(low, high: f64) -> (val: f64) {
assert(low <= high, "low must be lower than or equal to high")
val = (high-low)*float64(r) + low
val = (high-low)*float64() + low
if val >= high {
val = max(low, high * (1 - math.F64_EPSILON))
}
@@ -632,7 +461,6 @@ Generates a random single floating point value in the range `[low, high)` using
Inputs:
- low: The lower bounds of the value, this value is inclusive
- high: The upper bounds of the value, this value is exclusive
- r: The random number generator to use, or nil for the global generator
Returns:
- val: A random single floating point value in the range [low, high)
@@ -644,11 +472,7 @@ Example:
import "core:fmt"
float32_range_example :: proc() {
// Using the global random number generator
fmt.println(rand.float32_range(-10, 300))
// Using local random number generator
my_rand := rand.create(1)
fmt.println(rand.float32_range(600, 900, &my_rand))
}
Possible Output:
@@ -657,9 +481,9 @@ Possible Output:
673.130
*/
@(require_results) float32_range :: proc(low, high: f32, r: ^Rand = nil) -> (val: f32) {
@(require_results) float32_range :: proc(low, high: f32) -> (val: f32) {
assert(low <= high, "low must be lower than or equal to high")
val = (high-low)*float32(r) + low
val = (high-low)*float32() + low
if val >= high {
val = max(low, high * (1 - math.F32_EPSILON))
}
@@ -672,7 +496,6 @@ Due to floating point precision there is no guarantee if the upper and lower bou
Inputs:
- p: The byte slice to fill
- r: The random number generator to use, or nil for the global generator
Returns:
- n: The number of bytes generated
@@ -682,7 +505,6 @@ Example:
import "core:fmt"
read_example :: proc() {
// Using the global random number generator
data: [8]byte
n := rand.read(data[:])
fmt.println(n)
@@ -696,12 +518,12 @@ Possible Output:
*/
@(require_results)
read :: proc(p: []byte, r: ^Rand = nil) -> (n: int) {
read :: proc(p: []byte) -> (n: int) {
pos := i8(0)
val := i64(0)
for n = 0; n < len(p); n += 1 {
if pos == 0 {
val = int63(r)
val = int63()
pos = 7
}
p[n] = byte(val)
@@ -718,7 +540,6 @@ Creates a slice of `int` filled with random values using the provided random num
Inputs:
- n: The size of the created slice
- r: The random number generator to use, or nil for the global generator
- allocator: (default: context.allocator)
Returns:
@@ -731,16 +552,10 @@ Example:
import "core:fmt"
perm_example :: proc() -> (err: mem.Allocator_Error) {
// Using the global random number generator and using the context allocator
data := rand.perm(4) or_return
fmt.println(data)
defer delete(data, context.allocator)
// Using local random number generator and temp allocator
my_rand := rand.create(1)
data_tmp := rand.perm(4, &my_rand, context.temp_allocator) or_return
fmt.println(data_tmp)
return
}
@@ -751,10 +566,10 @@ Possible Output:
*/
@(require_results)
perm :: proc(n: int, r: ^Rand = nil, allocator := context.allocator) -> (res: []int, err: mem.Allocator_Error) #optional_allocator_error {
perm :: proc(n: int, allocator := context.allocator) -> (res: []int, err: mem.Allocator_Error) #optional_allocator_error {
m := make([]int, n, allocator) or_return
for i := 0; i < n; i += 1 {
j := int_max(i+1, r)
j := int_max(i+1)
m[i] = m[j]
m[j] = i
}
@@ -766,14 +581,12 @@ Randomizes the ordering of elements for the provided slice. If no generator is p
Inputs:
- array: The slice to randomize
- r: The random number generator to use, or nil for the global generator
Example:
import "core:math/rand"
import "core:fmt"
shuffle_example :: proc() {
// Using the global random number generator
data: [4]int = { 1, 2, 3, 4 }
fmt.println(data) // the contents are in order
rand.shuffle(data[:])
@@ -786,14 +599,14 @@ Possible Output:
[2, 4, 3, 1]
*/
shuffle :: proc(array: $T/[]$E, r: ^Rand = nil) {
shuffle :: proc(array: $T/[]$E) {
n := i64(len(array))
if n < 2 {
return
}
for i := i64(n - 1); i > 0; i -= 1 {
j := int63_max(i + 1, r)
j := int63_max(i + 1)
array[i], array[j] = array[j], array[i]
}
}
@@ -803,7 +616,6 @@ Returns a random element from the provided slice. If no generator is provided th
Inputs:
- array: The slice to choose an element from
- r: The random number generator to use, or nil for the global generator
Returns:
- res: A random element from `array`
@@ -813,7 +625,6 @@ Example:
import "core:fmt"
choice_example :: proc() {
// Using the global random number generator
data: [4]int = { 1, 2, 3, 4 }
fmt.println(rand.choice(data[:]))
fmt.println(rand.choice(data[:]))
@@ -830,17 +641,17 @@ Possible Output:
*/
@(require_results)
choice :: proc(array: $T/[]$E, r: ^Rand = nil) -> (res: E) {
choice :: proc(array: $T/[]$E) -> (res: E) {
n := i64(len(array))
if n < 1 {
return E{}
}
return array[int63_max(n, r)]
return array[int63_max(n)]
}
@(require_results)
choice_enum :: proc($T: typeid, r: ^Rand = nil) -> T
choice_enum :: proc($T: typeid) -> T
where
intrinsics.type_is_enum(T),
size_of(T) <= 8,
@@ -848,11 +659,11 @@ choice_enum :: proc($T: typeid, r: ^Rand = nil) -> T
{
when intrinsics.type_is_unsigned(intrinsics.type_core_type(T)) &&
u64(max(T)) > u64(max(i64)) {
i := uint64(r) % u64(len(T))
i := uint64() % u64(len(T))
i += u64(min(T))
return T(i)
} else {
i := int63_max(i64(len(T)), r)
i := int63_max(i64(len(T)))
i += i64(min(T))
return T(i)
}
+2 -2
View File
@@ -180,7 +180,7 @@ binary_search_by :: proc(array: $A/[]$T, key: T, f: proc(T, T) -> Ordering) -> (
}
@(require_results)
equal :: proc(a, b: $T/[]$E) -> bool where intrinsics.type_is_comparable(E) {
equal :: proc(a, b: $T/[]$E) -> bool where intrinsics.type_is_comparable(E) #no_bounds_check {
if len(a) != len(b) {
return false
}
@@ -736,4 +736,4 @@ bitset_to_enum_slice_with_make :: proc(bs: $T, $E: typeid, allocator := context.
return bitset_to_enum_slice(buf, bs)
}
bitset_to_enum_slice :: proc{bitset_to_enum_slice_with_make, bitset_to_enum_slice_with_buffer}
bitset_to_enum_slice :: proc{bitset_to_enum_slice_with_make, bitset_to_enum_slice_with_buffer}
+1 -4
View File
@@ -476,10 +476,7 @@ select_raw :: proc "odin" (recvs: []^Raw_Chan, sends: []^Raw_Chan, send_msgs: []
return
}
r: ^rand.Rand = nil
select_idx = rand.int_max(count, r) if count > 0 else 0
select_idx = rand.int_max(count) if count > 0 else 0
sel := candidates[select_idx]
if sel.is_recv {
Regular → Executable
+72 -109
View File
@@ -64,6 +64,7 @@ foreign kernel32 {
RemoveVectoredContinueHandler :: proc(Handle: LPVOID) -> DWORD ---
RaiseException :: proc(dwExceptionCode, dwExceptionFlags, nNumberOfArguments: DWORD, lpArguments: ^ULONG_PTR) -> ! ---
SetUnhandledExceptionFilter :: proc(lpTopLevelExceptionFilter: LPTOP_LEVEL_EXCEPTION_FILTER) -> LPTOP_LEVEL_EXCEPTION_FILTER ---
CreateHardLinkW :: proc(lpSymlinkFileName: LPCWSTR,
lpTargetFileName: LPCWSTR,
@@ -464,6 +465,8 @@ foreign kernel32 {
GetHandleInformation :: proc(hObject: HANDLE, lpdwFlags: ^DWORD) -> BOOL ---
RtlCaptureStackBackTrace :: proc(FramesToSkip: ULONG, FramesToCapture: ULONG, BackTrace: [^]PVOID, BackTraceHash: PULONG) -> USHORT ---
GetSystemPowerStatus :: proc(lpSystemPowerStatus: ^SYSTEM_POWER_STATUS) -> BOOL ---
}
DEBUG_PROCESS :: 0x00000001
@@ -1009,31 +1012,9 @@ foreign kernel32 {
HandlerRoutine :: proc "system" (dwCtrlType: DWORD) -> BOOL
PHANDLER_ROUTINE :: HandlerRoutine
// NOTE(Jeroen, 2024-06-13): As Odin now supports bit_fields, we no longer need
// a helper procedure. `init_dcb_with_config` and `get_dcb_config` have been removed.
DCB_Config :: struct {
fParity: bool,
fOutxCtsFlow: bool,
fOutxDsrFlow: bool,
fDtrControl: DTR_Control,
fDsrSensitivity: bool,
fTXContinueOnXoff: bool,
fOutX: bool,
fInX: bool,
fErrorChar: bool,
fNull: bool,
fRtsControl: RTS_Control,
fAbortOnError: bool,
BaudRate: DWORD,
ByteSize: BYTE,
Parity: Parity,
StopBits: Stop_Bits,
XonChar: byte,
XoffChar: byte,
ErrorChar: byte,
EvtChar: byte,
}
DTR_Control :: enum byte {
Disable = 0,
Enable = 1,
@@ -1058,92 +1039,35 @@ Stop_Bits :: enum byte {
Two = 2,
}
// A helper procedure to set the values of a DCB structure.
init_dcb_with_config :: proc "contextless" (dcb: ^DCB, config: DCB_Config) {
out: u32
// NOTE(tetra, 2022-09-21): On both Clang 14 on Windows, and MSVC, the bits in the bitfield
// appear to be defined from LSB to MSB order.
// i.e: `fBinary` (the first bitfield in the C source) is the LSB in the `settings` u32.
out |= u32(1) << 0 // fBinary must always be true on Windows.
out |= u32(config.fParity) << 1
out |= u32(config.fOutxCtsFlow) << 2
out |= u32(config.fOutxDsrFlow) << 3
out |= u32(config.fDtrControl) << 4
out |= u32(config.fDsrSensitivity) << 6
out |= u32(config.fTXContinueOnXoff) << 7
out |= u32(config.fOutX) << 8
out |= u32(config.fInX) << 9
out |= u32(config.fErrorChar) << 10
out |= u32(config.fNull) << 11
out |= u32(config.fRtsControl) << 12
out |= u32(config.fAbortOnError) << 14
dcb.settings = out
dcb.BaudRate = config.BaudRate
dcb.ByteSize = config.ByteSize
dcb.Parity = config.Parity
dcb.StopBits = config.StopBits
dcb.XonChar = config.XonChar
dcb.XoffChar = config.XoffChar
dcb.ErrorChar = config.ErrorChar
dcb.EvtChar = config.EvtChar
dcb.DCBlength = size_of(DCB)
}
get_dcb_config :: proc "contextless" (dcb: DCB) -> (config: DCB_Config) {
config.fParity = bool((dcb.settings >> 1) & 0x01)
config.fOutxCtsFlow = bool((dcb.settings >> 2) & 0x01)
config.fOutxDsrFlow = bool((dcb.settings >> 3) & 0x01)
config.fDtrControl = DTR_Control((dcb.settings >> 4) & 0x02)
config.fDsrSensitivity = bool((dcb.settings >> 6) & 0x01)
config.fTXContinueOnXoff = bool((dcb.settings >> 7) & 0x01)
config.fOutX = bool((dcb.settings >> 8) & 0x01)
config.fInX = bool((dcb.settings >> 9) & 0x01)
config.fErrorChar = bool((dcb.settings >> 10) & 0x01)
config.fNull = bool((dcb.settings >> 11) & 0x01)
config.fRtsControl = RTS_Control((dcb.settings >> 12) & 0x02)
config.fAbortOnError = bool((dcb.settings >> 14) & 0x01)
config.BaudRate = dcb.BaudRate
config.ByteSize = dcb.ByteSize
config.Parity = dcb.Parity
config.StopBits = dcb.StopBits
config.XonChar = dcb.XonChar
config.XoffChar = dcb.XoffChar
config.ErrorChar = dcb.ErrorChar
config.EvtChar = dcb.EvtChar
return
}
// NOTE(tetra): See get_dcb_config() and init_dcb_with_config() for help with initializing this.
DCB :: struct {
DCBlength: DWORD, // NOTE(tetra): Must be set to size_of(DCB).
BaudRate: DWORD,
settings: u32, // NOTE(tetra): These are bitfields in the C struct.
wReserved: WORD,
XOnLim: WORD,
XOffLim: WORD,
ByteSize: BYTE,
Parity: Parity,
StopBits: Stop_Bits,
XonChar: byte,
XoffChar: byte,
ErrorChar: byte,
EofChar: byte,
EvtChar: byte,
DCBlength: DWORD,
BaudRate: DWORD,
using _: bit_field DWORD {
fBinary: bool | 1,
fParity: bool | 1,
fOutxCtsFlow: bool | 1,
fOutxDsrFlow: bool | 1,
fDtrControl: DTR_Control | 2,
fDsrSensitivity: bool | 1,
fTXContinueOnXoff: bool | 1,
fOutX: bool | 1,
fInX: bool | 1,
fErrorChar: bool | 1,
fNull: bool | 1,
fRtsControl: RTS_Control | 2,
fAbortOnError: bool | 1,
},
wReserved: WORD,
XOnLim: WORD,
XOffLim: WORD,
ByteSize: BYTE,
Parity: Parity,
StopBits: Stop_Bits,
XonChar: byte,
XoffChar: byte,
ErrorChar: byte,
EofChar: byte,
EvtChar: byte,
wReserved1: WORD,
}
@@ -1153,6 +1077,19 @@ foreign kernel32 {
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)
@@ -1210,6 +1147,30 @@ SYSTEM_LOGICAL_PROCESSOR_INFORMATION :: struct {
DummyUnion: DUMMYUNIONNAME_u,
}
SYSTEM_POWER_STATUS :: struct {
ACLineStatus: AC_Line_Status,
BatteryFlag: Battery_Flags,
BatteryLifePercent: BYTE,
SystemStatusFlag: BYTE,
BatteryLifeTime: DWORD,
BatteryFullLifeTime: DWORD,
}
AC_Line_Status :: enum BYTE {
Offline = 0,
Online = 1,
Unknown = 255,
}
Battery_Flag :: enum BYTE {
High = 0,
Low = 1,
Critical = 2,
Charging = 3,
No_Battery = 7,
}
Battery_Flags :: bit_set[Battery_Flag; BYTE]
/* Global Memory Flags */
GMEM_FIXED :: 0x0000
GMEM_MOVEABLE :: 0x0002
@@ -1228,3 +1189,5 @@ GMEM_INVALID_HANDLE :: 0x8000
GHND :: (GMEM_MOVEABLE | GMEM_ZEROINIT)
GPTR :: (GMEM_FIXED | GMEM_ZEROINIT)
LPTOP_LEVEL_EXCEPTION_FILTER :: PVECTORED_EXCEPTION_HANDLER
+9
View File
@@ -34,6 +34,7 @@ HGDIOBJ :: distinct HANDLE
HBITMAP :: distinct HANDLE
HGLOBAL :: distinct HANDLE
HHOOK :: distinct HANDLE
HWINEVENTHOOK :: distinct HANDLE
HKEY :: distinct HANDLE
HDESK :: distinct HANDLE
HFONT :: distinct HANDLE
@@ -703,6 +704,14 @@ WNDPROC :: #type proc "system" (HWND, UINT, WPARAM, LPARAM) -> LRESULT
HOOKPROC :: #type proc "system" (code: c_int, wParam: WPARAM, lParam: LPARAM) -> LRESULT
WINEVENTPROC :: #type proc "system" (
hWinEventHook: HWINEVENTHOOK,
event: DWORD,
hwnd: HWND,
idObject, idChild: LONG,
idEventThread, dwmsEventTime: DWORD,
)
CWPRETSTRUCT :: struct {
lResult: LRESULT,
lParam: LPARAM,
+21
View File
@@ -17,6 +17,18 @@ foreign user32 {
GetClassNameW :: proc(hWnd: HWND, lpClassName: LPWSTR, nMaxCount: c_int) -> c_int ---
GetParent :: proc(hWnd: HWND) -> HWND ---
IsWindowVisible :: proc(hWnd: HWND) -> BOOL ---
SetWinEventHook :: proc(
eventMin, eventMax: DWORD,
hmodWinEventProc: HMODULE,
pfnWinEvenProc: WINEVENTPROC,
idProcess, idThread: DWORD,
dwFlags: WinEventFlags,
) -> HWINEVENTHOOK ---
IsChild :: proc(hWndParent, hWnd: HWND) -> BOOL ---
RegisterClassW :: proc(lpWndClass: ^WNDCLASSW) -> ATOM ---
RegisterClassExW :: proc(^WNDCLASSEXW) -> ATOM ---
UnregisterClassW :: proc(lpClassName: LPCWSTR, hInstance: HINSTANCE) -> BOOL ---
@@ -568,3 +580,12 @@ RedrawWindowFlags :: enum UINT {
RDW_FRAME = 0x0400,
RDW_NOFRAME = 0x0800,
}
// OUTOFCONTEXT is the zero value, use {}
WinEventFlags :: bit_set[WinEventFlag; DWORD]
WinEventFlag :: enum DWORD {
SKIPOWNTHREAD = 0,
SKIPOWNPROCESS = 1,
INCONTEXT = 2,
}
+1 -1
View File
@@ -47,7 +47,7 @@ ERROR_PIPE_BUSY : DWORD : 231
E_NOTIMPL :: HRESULT(-0x7fff_bfff) // 0x8000_4001
SUCCEEDED :: #force_inline proc(#any_int result: int) -> bool { return result >= 0 }
SUCCEEDED :: #force_inline proc "contextless" (#any_int result: int) -> bool { return result >= 0 }
System_Error :: enum DWORD {
+16 -7
View File
@@ -8,13 +8,22 @@ import "core:strings"
import "core:sync/chan"
import "core:time"
Default_Test_Logger_Opts :: runtime.Logger_Options {
.Level,
.Terminal_Color,
.Short_File_Path,
.Line,
.Procedure,
.Date, .Time,
when USING_SHORT_LOGS {
Default_Test_Logger_Opts :: runtime.Logger_Options {
.Level,
.Terminal_Color,
.Short_File_Path,
.Line,
}
} else {
Default_Test_Logger_Opts :: runtime.Logger_Options {
.Level,
.Terminal_Color,
.Short_File_Path,
.Line,
.Procedure,
.Date, .Time,
}
}
Log_Message :: struct {
+31 -13
View File
@@ -41,6 +41,8 @@ PROGRESS_WIDTH : int : #config(ODIN_TEST_PROGRESS_WIDTH, 24)
SHARED_RANDOM_SEED : u64 : #config(ODIN_TEST_RANDOM_SEED, 0)
// Set the lowest log level for this test run.
LOG_LEVEL : string : #config(ODIN_TEST_LOG_LEVEL, "info")
// Show only the most necessary logging information.
USING_SHORT_LOGS : bool : #config(ODIN_TEST_SHORT_LOGS, false)
get_log_level :: #force_inline proc() -> runtime.Logger_Level {
@@ -497,6 +499,7 @@ runner :: proc(internal_tests: []Internal_Test) -> bool {
data.it = it
data.t.seed = shared_random_seed
data.t.error_count = 0
data.t._fail_now_called = false
thread.pool_add_task(&pool, task.allocator, run_test_task, data, run_index)
}
@@ -604,10 +607,10 @@ runner :: proc(internal_tests: []Internal_Test) -> bool {
})
fmt.assertf(alloc_error == nil, "Error appending to log messages: %v", alloc_error)
find_task_data: for &data in task_data_slots {
find_task_data_for_timeout: for &data in task_data_slots {
if data.it.pkg == it.pkg && data.it.name == it.name {
end_t(&data.t)
break find_task_data
break find_task_data_for_timeout
}
}
}
@@ -645,21 +648,36 @@ runner :: proc(internal_tests: []Internal_Test) -> bool {
"A signal (%v) was raised to stop test #%i %s.%s, but it was unable to be found.",
reason, test_index, it.pkg, it.name)
if test_index not_in failed_test_reason_map {
// We only write a new error message here if there wasn't one
// already, because the message we can provide based only on
// the signal won't be very useful, whereas asserts and panics
// will provide a user-written error message.
failed_test_reason_map[test_index] = fmt.aprintf("Signal caught: %v", reason, allocator = shared_log_allocator)
pkg_log.fatalf("Caught signal to stop test #%i %s.%s for: %v.", test_index, it.pkg, it.name, reason)
// The order this is handled in is a little particular.
task_data: ^Task_Data
find_task_data_for_stop_signal: for &data in task_data_slots {
if data.it.pkg == it.pkg && data.it.name == it.name {
task_data = &data
break find_task_data_for_stop_signal
}
}
when FANCY_OUTPUT {
bypass_progress_overwrite = true
signals_were_raised = true
fmt.assertf(task_data != nil, "A signal (%v) was raised to stop test #%i %s.%s, but its task data is missing.",
reason, test_index, it.pkg, it.name)
if !task_data.t._fail_now_called {
if test_index not_in failed_test_reason_map {
// We only write a new error message here if there wasn't one
// already, because the message we can provide based only on
// the signal won't be very useful, whereas asserts and panics
// will provide a user-written error message.
failed_test_reason_map[test_index] = fmt.aprintf("Signal caught: %v", reason, allocator = shared_log_allocator)
pkg_log.fatalf("Caught signal to stop test #%i %s.%s for: %v.", test_index, it.pkg, it.name, reason)
}
when FANCY_OUTPUT {
bypass_progress_overwrite = true
signals_were_raised = true
}
}
end_t(&task_data.t)
total_failure_count += 1
total_done_count += 1
}
+21 -6
View File
@@ -48,7 +48,7 @@ T :: struct {
// tests during channel transmission.
_log_allocator: runtime.Allocator,
_fail_now: proc() -> !,
_fail_now_called: bool,
}
@@ -66,15 +66,20 @@ fail :: proc(t: ^T, loc := #caller_location) {
pkg_log.error("FAIL", location=loc)
}
fail_now :: proc(t: ^T, msg := "", loc := #caller_location) {
// fail_now will cause a test to immediately fail and abort, much in the same
// way a failed assertion or panic call will stop a thread.
//
// It is for when you absolutely need a test to fail without calling any of its
// deferred statements. It will be cleaner than a regular assert or panic,
// as the test runner will know to expect the signal this procedure will raise.
fail_now :: proc(t: ^T, msg := "", loc := #caller_location) -> ! {
t._fail_now_called = true
if msg != "" {
pkg_log.error("FAIL:", msg, location=loc)
} else {
pkg_log.error("FAIL", location=loc)
}
if t._fail_now != nil {
t._fail_now()
}
runtime.trap()
}
failed :: proc(t: ^T) -> bool {
@@ -94,7 +99,17 @@ logf :: proc(t: ^T, format: string, args: ..any, loc := #caller_location) {
// cleanup registers a procedure and user_data, which will be called when the test, and all its subtests, complete.
// Cleanup procedures will be called in LIFO (last added, first called) order.
// Each procedure will use a copy of the context at the time of registering.
//
// Each procedure will use a copy of the context at the time of registering,
// and if the test failed due to a timeout, failed assertion, panic, bounds-checking error,
// memory access violation, or any other signal-based fault, this procedure will
// run with greater privilege in the test runner's main thread.
//
// That means that any cleanup procedure absolutely must not fail in the same way,
// or it will take down the entire test runner with it. This is for when you
// need something to run no matter what, if a test failed.
//
// For almost every usual case, `defer` should be preferable and sufficient.
cleanup :: proc(t: ^T, procedure: proc(rawptr), user_data: rawptr) {
append(&t.cleanups, Internal_Cleanup{procedure, user_data, context})
}
+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");
}
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));
} else {
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;
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)) {
// prefer the named type
x->type = y->type;
+2 -1
View File
@@ -2934,7 +2934,8 @@ int main(int arg_count, char const **arg_ptr) {
// TODO(jeroen): Remove the `init_filename` param.
// Let's put that on `build_context.build_paths[0]` instead.
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()) {
@@ -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>
+4 -4
View File
@@ -20,15 +20,15 @@ test_avl :: proc(t: ^testing.T) {
iter := avl.iterator(&tree, avl.Direction.Forward)
testing.expect(t, avl.iterator_get(&iter) == nil, "empty/iterator: first node should be nil")
r: rand.Rand
rand.init(&r, t.seed)
r := rand.create(t.seed)
context.random_generator = rand.default_random_generator(&r)
// Test insertion.
NR_INSERTS :: 32 + 1 // Ensure at least 1 collision.
inserted_map := make(map[int]^avl.Node(int))
defer delete(inserted_map)
for i := 0; i < NR_INSERTS; i += 1 {
v := int(rand.uint32(&r) & 0x1f)
v := int(rand.uint32() & 0x1f)
existing_node, in_map := inserted_map[v]
n, ok, _ := avl.find_or_insert(&tree, v)
@@ -78,7 +78,7 @@ test_avl :: proc(t: ^testing.T) {
testing.expect(t, visited == nrEntries, "iterator/backward: visited")
// Test removal.
rand.shuffle(inserted_values[:], &r)
rand.shuffle(inserted_values[:])
for v, i in inserted_values {
node := avl.find(&tree, v)
testing.expect(t, node != nil, "remove: find (pre)")
+5 -5
View File
@@ -14,8 +14,8 @@ test_rbtree_integer :: proc(t: ^testing.T, $Key: typeid, $Value: typeid) {
defer mem.tracking_allocator_destroy(&track)
context.allocator = mem.tracking_allocator(&track)
r: rand.Rand
rand.init(&r, t.seed)
r := rand.create(t.seed)
context.random_generator = rand.default_random_generator(&r)
log.infof("Testing Red-Black Tree($Key=%v,$Value=%v) using random seed %v.", type_info_of(Key), type_info_of(Value), t.seed)
tree: rb.Tree(Key, Value)
@@ -35,9 +35,9 @@ test_rbtree_integer :: proc(t: ^testing.T, $Key: typeid, $Value: typeid) {
max_key := min(Key)
for i := 0; i < NR_INSERTS; i += 1 {
k := Key(rand.uint32(&r)) & 0x1f
k := Key(rand.uint32()) & 0x1f
min_key = min(min_key, k); max_key = max(max_key, k)
v := Value(rand.uint32(&r))
v := Value(rand.uint32())
existing_node, in_map := inserted_map[k]
n, inserted, _ := rb.find_or_insert(&tree, k, v)
@@ -92,7 +92,7 @@ test_rbtree_integer :: proc(t: ^testing.T, $Key: typeid, $Value: typeid) {
testing.expect(t, visited == entry_count, "iterator/backward: visited")
// Test removal (and on_remove callback)
rand.shuffle(inserted_keys[:], &r)
rand.shuffle(inserted_keys[:])
callback_count := entry_count
tree.user_data = &callback_count
tree.on_remove = proc(key: Key, value: Value, user_data: rawptr) {
+19 -5
View File
@@ -36,7 +36,7 @@ xml_test_utf8_normal :: proc(t: ^testing.T) {
},
expected_doctype = "恥ずべきフクロウ",
},
crc32 = 0xe9b62f03,
crc32 = 0xefa55f27,
})
}
@@ -52,7 +52,7 @@ xml_test_utf8_unbox_cdata :: proc(t: ^testing.T) {
},
expected_doctype = "恥ずべきフクロウ",
},
crc32 = 0x9c2643ed,
crc32 = 0x2dd27770,
})
}
@@ -128,7 +128,7 @@ xml_test_entities_unbox :: proc(t: ^testing.T) {
},
expected_doctype = "html",
},
crc32 = 0x3b6d4a90,
crc32 = 0x350ca83e,
})
}
@@ -142,7 +142,21 @@ xml_test_entities_unbox_decode :: proc(t: ^testing.T) {
},
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 = "",
},
err = .None,
crc32 = 0x0b6100ab,
crc32 = 0x73070b55,
})
}
+114
View File
@@ -258,6 +258,120 @@ test_pointers :: proc(t: ^testing.T) {
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)
check :: proc(t: ^testing.T, exp: string, format: string, args: ..any, loc := #caller_location) {
got := fmt.tprintf(format, ..args)
+2 -1
View File
@@ -54,8 +54,9 @@ test_xxhash_zero_streamed_random_updates :: proc(t: ^testing.T) {
// XXH3_128_update
random_seed := rand.create(t.seed)
context.random_generator = rand.default_random_generator(&random_seed)
for len(b) > 0 {
update_size := min(len(b), rand.int_max(8192, &random_seed))
update_size := min(len(b), rand.int_max(8192))
if update_size > 4096 {
update_size %= 73
}
+9 -6
View File
@@ -3,6 +3,7 @@ package test_core_slice
import "core:slice"
import "core:testing"
import "core:math/rand"
import "core:log"
@test
test_sort_with_indices :: proc(t: ^testing.T) {
@@ -11,6 +12,7 @@ test_sort_with_indices :: proc(t: ^testing.T) {
for test_size in test_sizes {
r := rand.create(t.seed)
context.random_generator = rand.default_random_generator(&r)
vals := make([]u64, test_size)
r_idx := make([]int, test_size) // Reverse index
@@ -21,7 +23,7 @@ test_sort_with_indices :: proc(t: ^testing.T) {
// Set up test values
for _, i in vals {
vals[i] = rand.uint64(&r)
vals[i] = rand.uint64()
}
// Sort
@@ -29,7 +31,7 @@ test_sort_with_indices :: proc(t: ^testing.T) {
defer delete(f_idx)
// Verify sorted test values
rand.init(&r, t.seed)
rand.reset(t.seed)
for v, i in f_idx {
r_idx[v] = i
@@ -45,7 +47,7 @@ test_sort_with_indices :: proc(t: ^testing.T) {
}
}
idx_pass := vals[r_idx[i]] == rand.uint64(&r)
idx_pass := vals[r_idx[i]] == rand.uint64()
testing.expect(t, idx_pass, "Expected index to have been sorted")
if !idx_pass {
break
@@ -62,6 +64,7 @@ test_sort_by_indices :: proc(t: ^testing.T) {
for test_size in test_sizes {
r := rand.create(t.seed)
context.random_generator = rand.default_random_generator(&r)
vals := make([]u64, test_size)
r_idx := make([]int, test_size) // Reverse index
@@ -72,7 +75,7 @@ test_sort_by_indices :: proc(t: ^testing.T) {
// Set up test values
for _, i in vals {
vals[i] = rand.uint64(&r)
vals[i] = rand.uint64()
}
// Sort
@@ -80,7 +83,7 @@ test_sort_by_indices :: proc(t: ^testing.T) {
defer delete(f_idx)
// Verify sorted test values
rand.init(&r, t.seed)
rand.reset(t.seed)
{
indices := make([]int, test_size)
@@ -205,7 +208,7 @@ test_permutation_iterator :: proc(t: ^testing.T) {
n += item
}
if n in seen {
testing.fail_now(t, "Permutation iterator made a duplicate permutation.")
log.error("Permutation iterator made a duplicate permutation.")
return
}
seen[n] = true
+41 -21
View File
@@ -17,9 +17,10 @@ map_insert_random_key_value :: proc(t: ^testing.T) {
unique_keys := 0
r := rand.create(t.seed + seed_incr)
context.random_generator = rand.default_random_generator(&r)
for _ in 0..<entries {
k := rand.int63(&r)
v := rand.int63(&r)
k := rand.int63()
v := rand.int63()
if k not_in m {
unique_keys += 1
@@ -37,11 +38,12 @@ map_insert_random_key_value :: proc(t: ^testing.T) {
// Reset randomizer and verify
r = rand.create(t.seed + seed_incr)
context.random_generator = rand.default_random_generator(&r)
num_fails := 0
for _ in 0..<entries {
k := rand.int63(&r)
v := rand.int63(&r)
k := rand.int63()
v := rand.int63()
cond := m[k] == v
if !cond {
@@ -67,9 +69,11 @@ map_update_random_key_value :: proc(t: ^testing.T) {
unique_keys := 0
r := rand.create(t.seed + seed_incr)
context.random_generator = rand.default_random_generator(&r)
for _ in 0..<entries {
k := rand.int63(&r)
v := rand.int63(&r)
k := rand.int63()
v := rand.int63()
if k not_in m {
unique_keys += 1
@@ -89,20 +93,23 @@ map_update_random_key_value :: proc(t: ^testing.T) {
// Reset randomizer and update half the entries
r = rand.create(t.seed + seed_incr)
context.random_generator = rand.default_random_generator(&r)
for _ in 0..<half_entries {
k := rand.int63(&r)
v := rand.int63(&r)
k := rand.int63()
v := rand.int63()
m[k] = v + 42
}
// Reset randomizer and verify
r = rand.create(t.seed + seed_incr)
context.random_generator = rand.default_random_generator(&r)
num_fails := 0
for i in 0..<entries {
k := rand.int63(&r)
v := rand.int63(&r)
k := rand.int63()
v := rand.int63()
diff := i64(42) if i < half_entries else i64(0)
cond := m[k] == (v + diff)
@@ -129,9 +136,11 @@ map_delete_random_key_value :: proc(t: ^testing.T) {
unique_keys := 0
r := rand.create(t.seed + seed_incr)
context.random_generator = rand.default_random_generator(&r)
for _ in 0..<entries {
k := rand.int63(&r)
v := rand.int63(&r)
k := rand.int63()
v := rand.int63()
if k not_in m {
unique_keys += 1
@@ -151,20 +160,23 @@ map_delete_random_key_value :: proc(t: ^testing.T) {
// Reset randomizer and delete half the entries
r = rand.create(t.seed + seed_incr)
context.random_generator = rand.default_random_generator(&r)
for _ in 0..<half_entries {
k := rand.int63(&r)
_ = rand.int63(&r)
k := rand.int63()
_ = rand.int63()
delete_key(&m, k)
}
// Reset randomizer and verify
r = rand.create(t.seed + seed_incr)
context.random_generator = rand.default_random_generator(&r)
num_fails := 0
for i in 0..<entries {
k := rand.int63(&r)
v := rand.int63(&r)
k := rand.int63()
v := rand.int63()
if i < half_entries {
if k in m {
@@ -207,8 +219,10 @@ set_insert_random_key_value :: proc(t: ^testing.T) {
unique_keys := 0
r := rand.create(t.seed + seed_incr)
context.random_generator = rand.default_random_generator(&r)
for _ in 0..<entries {
k := rand.int63(&r)
k := rand.int63()
if k not_in m {
unique_keys += 1
}
@@ -225,10 +239,11 @@ set_insert_random_key_value :: proc(t: ^testing.T) {
// Reset randomizer and verify
r = rand.create(t.seed + seed_incr)
context.random_generator = rand.default_random_generator(&r)
num_fails := 0
for _ in 0..<entries {
k := rand.int63(&r)
k := rand.int63()
cond := k in m
if !cond {
@@ -254,8 +269,10 @@ set_delete_random_key_value :: proc(t: ^testing.T) {
unique_keys := 0
r := rand.create(t.seed + seed_incr)
context.random_generator = rand.default_random_generator(&r)
for _ in 0..<entries {
k := rand.int63(&r)
k := rand.int63()
if k not_in m {
unique_keys += 1
@@ -275,17 +292,20 @@ set_delete_random_key_value :: proc(t: ^testing.T) {
// Reset randomizer and delete half the entries
r = rand.create(t.seed + seed_incr)
context.random_generator = rand.default_random_generator(&r)
for _ in 0..<half_entries {
k := rand.int63(&r)
k := rand.int63()
delete_key(&m, k)
}
// Reset randomizer and verify
r = rand.create(t.seed + seed_incr)
context.random_generator = rand.default_random_generator(&r)
num_fails := 0
for i in 0..<entries {
k := rand.int63(&r)
k := rand.int63()
if i < half_entries {
if k in m {
+1 -1
View File
@@ -668,7 +668,7 @@ MatrixLookAt :: proc "c" (eye, target, up: Vector3) -> Matrix {
// Get float array of matrix data
@(require_results)
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
}