mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 07:38:48 +00:00
Merge remote-tracking branch 'offical/master'
This commit is contained in:
@@ -397,11 +397,34 @@ Logger :: struct {
|
|||||||
options: Logger_Options,
|
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 {
|
Context :: struct {
|
||||||
allocator: Allocator,
|
allocator: Allocator,
|
||||||
temp_allocator: Allocator,
|
temp_allocator: Allocator,
|
||||||
assertion_failure_proc: Assertion_Failure_Proc,
|
assertion_failure_proc: Assertion_Failure_Proc,
|
||||||
logger: Logger,
|
logger: Logger,
|
||||||
|
random_generator: Random_Generator,
|
||||||
|
|
||||||
user_ptr: rawptr,
|
user_ptr: rawptr,
|
||||||
user_index: int,
|
user_index: int,
|
||||||
@@ -708,6 +731,9 @@ __init_context :: proc "contextless" (c: ^Context) {
|
|||||||
|
|
||||||
c.logger.procedure = default_logger_proc
|
c.logger.procedure = default_logger_proc
|
||||||
c.logger.data = nil
|
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) -> ! {
|
default_assertion_failure_proc :: proc(prefix, message: string, loc: Source_Code_Location) -> ! {
|
||||||
|
|||||||
@@ -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,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ helper routines.
|
|||||||
*/
|
*/
|
||||||
package crypto
|
package crypto
|
||||||
|
|
||||||
|
import "base:runtime"
|
||||||
import "core:mem"
|
import "core:mem"
|
||||||
|
|
||||||
// compare_constant_time returns 1 iff a and b are equal, 0 otherwise.
|
// 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)
|
_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,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -56,38 +56,27 @@ CDATA_END :: "]]>"
|
|||||||
COMMENT_START :: "<!--"
|
COMMENT_START :: "<!--"
|
||||||
COMMENT_END :: "-->"
|
COMMENT_END :: "-->"
|
||||||
|
|
||||||
/*
|
// Default: CDATA and comments are passed through unchanged.
|
||||||
Default: CDATA and comments are passed through unchanged.
|
|
||||||
*/
|
|
||||||
XML_Decode_Option :: enum u8 {
|
XML_Decode_Option :: enum u8 {
|
||||||
/*
|
// Do not decode & entities. It decodes by default. If given, overrides `Decode_CDATA`.
|
||||||
Do not decode & entities. It decodes by default.
|
|
||||||
If given, overrides `Decode_CDATA`.
|
|
||||||
*/
|
|
||||||
No_Entity_Decode,
|
No_Entity_Decode,
|
||||||
|
|
||||||
/*
|
// CDATA is unboxed.
|
||||||
CDATA is unboxed.
|
|
||||||
*/
|
|
||||||
Unbox_CDATA,
|
Unbox_CDATA,
|
||||||
|
|
||||||
/*
|
// Unboxed CDATA is decoded as well. Ignored if `.Unbox_CDATA` is not given.
|
||||||
Unboxed CDATA is decoded as well.
|
|
||||||
Ignored if `.Unbox_CDATA` is not given.
|
|
||||||
*/
|
|
||||||
Decode_CDATA,
|
Decode_CDATA,
|
||||||
|
|
||||||
/*
|
// Comments are stripped.
|
||||||
Comments are stripped.
|
|
||||||
*/
|
|
||||||
Comment_Strip,
|
Comment_Strip,
|
||||||
|
|
||||||
|
// Normalize whitespace
|
||||||
|
Normalize_Whitespace,
|
||||||
}
|
}
|
||||||
XML_Decode_Options :: bit_set[XML_Decode_Option; u8]
|
XML_Decode_Options :: bit_set[XML_Decode_Option; u8]
|
||||||
|
|
||||||
/*
|
// Decode a string that may include SGML/XML/HTML entities.
|
||||||
Decode a string that may include SGML/XML/HTML entities.
|
// The caller has to free the result.
|
||||||
The caller has to free the result.
|
|
||||||
*/
|
|
||||||
decode_xml :: proc(input: string, options := XML_Decode_Options{}, allocator := context.allocator) -> (decoded: string, err: Error) {
|
decode_xml :: proc(input: string, options := XML_Decode_Options{}, allocator := context.allocator) -> (decoded: string, err: Error) {
|
||||||
context.allocator = allocator
|
context.allocator = allocator
|
||||||
|
|
||||||
@@ -100,14 +89,14 @@ decode_xml :: proc(input: string, options := XML_Decode_Options{}, allocator :=
|
|||||||
t := Tokenizer{src=input}
|
t := Tokenizer{src=input}
|
||||||
in_data := false
|
in_data := false
|
||||||
|
|
||||||
|
prev: rune = ' '
|
||||||
|
|
||||||
loop: for {
|
loop: for {
|
||||||
advance(&t) or_return
|
advance(&t) or_return
|
||||||
if t.r < 0 { break loop }
|
if t.r < 0 { break loop }
|
||||||
|
|
||||||
/*
|
// Below here we're never inside a CDATA tag. At most we'll see the start of one,
|
||||||
Below here we're never inside a CDATA tag.
|
// but that doesn't affect the logic.
|
||||||
At most we'll see the start of one, but that doesn't affect the logic.
|
|
||||||
*/
|
|
||||||
switch t.r {
|
switch t.r {
|
||||||
case '<':
|
case '<':
|
||||||
/*
|
/*
|
||||||
@@ -126,9 +115,7 @@ decode_xml :: proc(input: string, options := XML_Decode_Options{}, allocator :=
|
|||||||
in_data = _handle_xml_special(&t, &builder, options) or_return
|
in_data = _handle_xml_special(&t, &builder, options) or_return
|
||||||
|
|
||||||
case ']':
|
case ']':
|
||||||
/*
|
// If we're unboxing _and_ decoding CDATA, we'll have to check for the end tag.
|
||||||
If we're unboxing _and_ decoding CDATA, we'll have to check for the end tag.
|
|
||||||
*/
|
|
||||||
if in_data {
|
if in_data {
|
||||||
if t.read_offset + len(CDATA_END) < len(t.src) {
|
if t.read_offset + len(CDATA_END) < len(t.src) {
|
||||||
if string(t.src[t.offset:][:len(CDATA_END)]) == CDATA_END {
|
if string(t.src[t.offset:][:len(CDATA_END)]) == CDATA_END {
|
||||||
@@ -143,22 +130,16 @@ decode_xml :: proc(input: string, options := XML_Decode_Options{}, allocator :=
|
|||||||
|
|
||||||
case:
|
case:
|
||||||
if in_data && .Decode_CDATA not_in options {
|
if in_data && .Decode_CDATA not_in options {
|
||||||
/*
|
// Unboxed, but undecoded.
|
||||||
Unboxed, but undecoded.
|
|
||||||
*/
|
|
||||||
write_rune(&builder, t.r)
|
write_rune(&builder, t.r)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if t.r == '&' {
|
if t.r == '&' {
|
||||||
if entity, entity_err := _extract_xml_entity(&t); entity_err != .None {
|
if entity, entity_err := _extract_xml_entity(&t); entity_err != .None {
|
||||||
/*
|
// We read to the end of the string without closing the entity. Pass through as-is.
|
||||||
We read to the end of the string without closing the entity.
|
|
||||||
Pass through as-is.
|
|
||||||
*/
|
|
||||||
write_string(&builder, entity)
|
write_string(&builder, entity)
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if .No_Entity_Decode not_in options {
|
if .No_Entity_Decode not_in options {
|
||||||
if decoded, ok := xml_decode_entity(entity); ok {
|
if decoded, ok := xml_decode_entity(entity); ok {
|
||||||
write_rune(&builder, decoded)
|
write_rune(&builder, decoded)
|
||||||
@@ -166,19 +147,41 @@ decode_xml :: proc(input: string, options := XML_Decode_Options{}, allocator :=
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// Literal passthrough because the decode failed or we want entities not decoded.
|
||||||
Literal passthrough because the decode failed or we want entities not decoded.
|
|
||||||
*/
|
|
||||||
write_string(&builder, "&")
|
write_string(&builder, "&")
|
||||||
write_string(&builder, entity)
|
write_string(&builder, entity)
|
||||||
write_string(&builder, ";")
|
write_string(&builder, ";")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
write_rune(&builder, t.r)
|
// Handle AV Normalization: https://www.w3.org/TR/2006/REC-xml11-20060816/#AVNormalize
|
||||||
|
if .Normalize_Whitespace in options {
|
||||||
|
switch t.r {
|
||||||
|
case ' ', '\r', '\n', '\t':
|
||||||
|
if prev != ' ' {
|
||||||
|
write_rune(&builder, ' ')
|
||||||
|
prev = ' '
|
||||||
|
}
|
||||||
|
case:
|
||||||
|
write_rune(&builder, t.r)
|
||||||
|
prev = t.r
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// https://www.w3.org/TR/2006/REC-xml11-20060816/#sec-line-ends
|
||||||
|
switch t.r {
|
||||||
|
case '\n', 0x85, 0x2028:
|
||||||
|
write_rune(&builder, '\n')
|
||||||
|
case '\r': // Do nothing until next character
|
||||||
|
case:
|
||||||
|
if prev == '\r' { // Turn a single carriage return into a \n
|
||||||
|
write_rune(&builder, '\n')
|
||||||
|
}
|
||||||
|
write_rune(&builder, t.r)
|
||||||
|
}
|
||||||
|
prev = t.r
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return strings.clone(strings.to_string(builder), allocator), err
|
return strings.clone(strings.to_string(builder), allocator), err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -253,24 +256,18 @@ xml_decode_entity :: proc(entity: string) -> (decoded: rune, ok: bool) {
|
|||||||
return rune(val), true
|
return rune(val), true
|
||||||
|
|
||||||
case:
|
case:
|
||||||
/*
|
// Named entity.
|
||||||
Named entity.
|
|
||||||
*/
|
|
||||||
return named_xml_entity_to_rune(entity)
|
return named_xml_entity_to_rune(entity)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// Private XML helper to extract `&<stuff>;` entity.
|
||||||
Private XML helper to extract `&<stuff>;` entity.
|
|
||||||
*/
|
|
||||||
@(private="file")
|
@(private="file")
|
||||||
_extract_xml_entity :: proc(t: ^Tokenizer) -> (entity: string, err: Error) {
|
_extract_xml_entity :: proc(t: ^Tokenizer) -> (entity: string, err: Error) {
|
||||||
assert(t != nil && t.r == '&')
|
assert(t != nil && t.r == '&')
|
||||||
|
|
||||||
/*
|
// All of these would be in the ASCII range.
|
||||||
All of these would be in the ASCII range.
|
// Even if one is not, it doesn't matter. All characters we need to compare to extract are.
|
||||||
Even if one is not, it doesn't matter. All characters we need to compare to extract are.
|
|
||||||
*/
|
|
||||||
|
|
||||||
length := len(t.src)
|
length := len(t.src)
|
||||||
found := false
|
found := false
|
||||||
@@ -292,9 +289,7 @@ _extract_xml_entity :: proc(t: ^Tokenizer) -> (entity: string, err: Error) {
|
|||||||
return string(t.src[t.offset : t.read_offset]), .Invalid_Entity_Encoding
|
return string(t.src[t.offset : t.read_offset]), .Invalid_Entity_Encoding
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// Private XML helper for CDATA and comments.
|
||||||
Private XML helper for CDATA and comments.
|
|
||||||
*/
|
|
||||||
@(private="file")
|
@(private="file")
|
||||||
_handle_xml_special :: proc(t: ^Tokenizer, builder: ^strings.Builder, options: XML_Decode_Options) -> (in_data: bool, err: Error) {
|
_handle_xml_special :: proc(t: ^Tokenizer, builder: ^strings.Builder, options: XML_Decode_Options) -> (in_data: bool, err: Error) {
|
||||||
assert(t != nil && t.r == '<')
|
assert(t != nil && t.r == '<')
|
||||||
@@ -304,20 +299,14 @@ _handle_xml_special :: proc(t: ^Tokenizer, builder: ^strings.Builder, options: X
|
|||||||
t.read_offset += len(CDATA_START) - 1
|
t.read_offset += len(CDATA_START) - 1
|
||||||
|
|
||||||
if .Unbox_CDATA in options && .Decode_CDATA in options {
|
if .Unbox_CDATA in options && .Decode_CDATA in options {
|
||||||
/*
|
// We're unboxing _and_ decoding CDATA
|
||||||
We're unboxing _and_ decoding CDATA
|
|
||||||
*/
|
|
||||||
return true, .None
|
return true, .None
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// CDATA is passed through.
|
||||||
CDATA is passed through.
|
|
||||||
*/
|
|
||||||
offset := t.offset
|
offset := t.offset
|
||||||
|
|
||||||
/*
|
// Scan until end of CDATA.
|
||||||
Scan until end of CDATA.
|
|
||||||
*/
|
|
||||||
for {
|
for {
|
||||||
advance(t) or_return
|
advance(t) or_return
|
||||||
if t.r < 0 { return true, .CDATA_Not_Terminated }
|
if t.r < 0 { return true, .CDATA_Not_Terminated }
|
||||||
@@ -341,14 +330,10 @@ _handle_xml_special :: proc(t: ^Tokenizer, builder: ^strings.Builder, options: X
|
|||||||
|
|
||||||
} else if string(t.src[t.offset:][:len(COMMENT_START)]) == COMMENT_START {
|
} else if string(t.src[t.offset:][:len(COMMENT_START)]) == COMMENT_START {
|
||||||
t.read_offset += len(COMMENT_START)
|
t.read_offset += len(COMMENT_START)
|
||||||
/*
|
// Comment is passed through by default.
|
||||||
Comment is passed through by default.
|
|
||||||
*/
|
|
||||||
offset := t.offset
|
offset := t.offset
|
||||||
|
|
||||||
/*
|
// Scan until end of Comment.
|
||||||
Scan until end of Comment.
|
|
||||||
*/
|
|
||||||
for {
|
for {
|
||||||
advance(t) or_return
|
advance(t) or_return
|
||||||
if t.r < 0 { return true, .Comment_Not_Terminated }
|
if t.r < 0 { return true, .Comment_Not_Terminated }
|
||||||
|
|||||||
@@ -218,9 +218,7 @@ scan_identifier :: proc(t: ^Tokenizer) -> string {
|
|||||||
for is_valid_identifier_rune(t.ch) {
|
for is_valid_identifier_rune(t.ch) {
|
||||||
advance_rune(t)
|
advance_rune(t)
|
||||||
if t.ch == ':' {
|
if t.ch == ':' {
|
||||||
/*
|
// A namespaced attr can have at most two parts, `namespace:ident`.
|
||||||
A namespaced attr can have at most two parts, `namespace:ident`.
|
|
||||||
*/
|
|
||||||
if namespaced {
|
if namespaced {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -268,14 +266,10 @@ scan_comment :: proc(t: ^Tokenizer) -> (comment: string, err: Error) {
|
|||||||
return string(t.src[offset : t.offset - 1]), .None
|
return string(t.src[offset : t.offset - 1]), .None
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// Skip CDATA
|
||||||
Skip CDATA
|
|
||||||
*/
|
|
||||||
skip_cdata :: proc(t: ^Tokenizer) -> (err: Error) {
|
skip_cdata :: proc(t: ^Tokenizer) -> (err: Error) {
|
||||||
if t.read_offset + len(CDATA_START) >= len(t.src) {
|
if t.read_offset + len(CDATA_START) >= len(t.src) {
|
||||||
/*
|
// Can't be the start of a CDATA tag.
|
||||||
Can't be the start of a CDATA tag.
|
|
||||||
*/
|
|
||||||
return .None
|
return .None
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -290,9 +284,7 @@ skip_cdata :: proc(t: ^Tokenizer) -> (err: Error) {
|
|||||||
return .Premature_EOF
|
return .Premature_EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// Scan until the end of a CDATA tag.
|
||||||
Scan until the end of a CDATA tag.
|
|
||||||
*/
|
|
||||||
if t.read_offset + len(CDATA_END) < len(t.src) {
|
if t.read_offset + len(CDATA_END) < len(t.src) {
|
||||||
if string(t.src[t.offset:][:len(CDATA_END)]) == CDATA_END {
|
if string(t.src[t.offset:][:len(CDATA_END)]) == CDATA_END {
|
||||||
t.read_offset += len(CDATA_END)
|
t.read_offset += len(CDATA_END)
|
||||||
@@ -319,14 +311,10 @@ scan_string :: proc(t: ^Tokenizer, offset: int, close: rune = '<', consume_close
|
|||||||
case '<':
|
case '<':
|
||||||
if peek_byte(t) == '!' {
|
if peek_byte(t) == '!' {
|
||||||
if peek_byte(t, 1) == '[' {
|
if peek_byte(t, 1) == '[' {
|
||||||
/*
|
// Might be the start of a CDATA tag.
|
||||||
Might be the start of a CDATA tag.
|
|
||||||
*/
|
|
||||||
skip_cdata(t) or_return
|
skip_cdata(t) or_return
|
||||||
} else if peek_byte(t, 1) == '-' && peek_byte(t, 2) == '-' {
|
} else if peek_byte(t, 1) == '-' && peek_byte(t, 2) == '-' {
|
||||||
/*
|
// Comment start. Eat comment.
|
||||||
Comment start. Eat comment.
|
|
||||||
*/
|
|
||||||
t.read_offset += 3
|
t.read_offset += 3
|
||||||
_ = scan_comment(t) or_return
|
_ = scan_comment(t) or_return
|
||||||
}
|
}
|
||||||
@@ -342,17 +330,13 @@ scan_string :: proc(t: ^Tokenizer, offset: int, close: rune = '<', consume_close
|
|||||||
}
|
}
|
||||||
|
|
||||||
if t.ch == close {
|
if t.ch == close {
|
||||||
/*
|
// If it's not a CDATA or comment, it's the end of this body.
|
||||||
If it's not a CDATA or comment, it's the end of this body.
|
|
||||||
*/
|
|
||||||
break loop
|
break loop
|
||||||
}
|
}
|
||||||
advance_rune(t)
|
advance_rune(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// Strip trailing whitespace.
|
||||||
Strip trailing whitespace.
|
|
||||||
*/
|
|
||||||
lit := string(t.src[offset : t.offset])
|
lit := string(t.src[offset : t.offset])
|
||||||
|
|
||||||
end := len(lit)
|
end := len(lit)
|
||||||
@@ -369,11 +353,6 @@ scan_string :: proc(t: ^Tokenizer, offset: int, close: rune = '<', consume_close
|
|||||||
if consume_close {
|
if consume_close {
|
||||||
advance_rune(t)
|
advance_rune(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
TODO: Handle decoding escape characters and unboxing CDATA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
return lit, err
|
return lit, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -384,7 +363,7 @@ peek :: proc(t: ^Tokenizer) -> (token: Token) {
|
|||||||
return token
|
return token
|
||||||
}
|
}
|
||||||
|
|
||||||
scan :: proc(t: ^Tokenizer) -> Token {
|
scan :: proc(t: ^Tokenizer, multiline_string := false) -> Token {
|
||||||
skip_whitespace(t)
|
skip_whitespace(t)
|
||||||
|
|
||||||
offset := t.offset
|
offset := t.offset
|
||||||
@@ -418,7 +397,7 @@ scan :: proc(t: ^Tokenizer) -> Token {
|
|||||||
case '"', '\'':
|
case '"', '\'':
|
||||||
kind = .Invalid
|
kind = .Invalid
|
||||||
|
|
||||||
lit, err = scan_string(t, t.offset, ch, true, false)
|
lit, err = scan_string(t, t.offset, ch, true, multiline_string)
|
||||||
if err == .None {
|
if err == .None {
|
||||||
kind = .String
|
kind = .String
|
||||||
}
|
}
|
||||||
@@ -435,4 +414,4 @@ scan :: proc(t: ^Tokenizer) -> Token {
|
|||||||
lit = string(t.src[offset : t.offset])
|
lit = string(t.src[offset : t.offset])
|
||||||
}
|
}
|
||||||
return Token{kind, lit, pos}
|
return Token{kind, lit, pos}
|
||||||
}
|
}
|
||||||
@@ -203,9 +203,7 @@ parse_bytes :: proc(data: []u8, options := DEFAULT_OPTIONS, path := "", error_ha
|
|||||||
|
|
||||||
doc.elements = make([dynamic]Element, 1024, 1024, allocator)
|
doc.elements = make([dynamic]Element, 1024, 1024, allocator)
|
||||||
|
|
||||||
// strings.intern_init(&doc.intern, allocator, allocator)
|
err = .Unexpected_Token
|
||||||
|
|
||||||
err = .Unexpected_Token
|
|
||||||
element, parent: Element_ID
|
element, parent: Element_ID
|
||||||
open: Token
|
open: Token
|
||||||
|
|
||||||
@@ -259,8 +257,8 @@ parse_bytes :: proc(data: []u8, options := DEFAULT_OPTIONS, path := "", error_ha
|
|||||||
case .Slash:
|
case .Slash:
|
||||||
// Empty tag. Close it.
|
// Empty tag. Close it.
|
||||||
expect(t, .Gt) or_return
|
expect(t, .Gt) or_return
|
||||||
parent = doc.elements[element].parent
|
parent = doc.elements[element].parent
|
||||||
element = parent
|
element = parent
|
||||||
|
|
||||||
case:
|
case:
|
||||||
error(t, t.offset, "Expected close tag, got: %#v\n", end_token)
|
error(t, t.offset, "Expected close tag, got: %#v\n", end_token)
|
||||||
@@ -276,8 +274,8 @@ parse_bytes :: proc(data: []u8, options := DEFAULT_OPTIONS, path := "", error_ha
|
|||||||
error(t, t.offset, "Mismatched Closing Tag. Expected %v, got %v\n", doc.elements[element].ident, ident.text)
|
error(t, t.offset, "Mismatched Closing Tag. Expected %v, got %v\n", doc.elements[element].ident, ident.text)
|
||||||
return doc, .Mismatched_Closing_Tag
|
return doc, .Mismatched_Closing_Tag
|
||||||
}
|
}
|
||||||
parent = doc.elements[element].parent
|
parent = doc.elements[element].parent
|
||||||
element = parent
|
element = parent
|
||||||
|
|
||||||
} else if open.kind == .Exclaim {
|
} else if open.kind == .Exclaim {
|
||||||
// <!
|
// <!
|
||||||
@@ -463,8 +461,8 @@ validate_options :: proc(options: Options) -> (validated: Options, err: Error) {
|
|||||||
return validated, .None
|
return validated, .None
|
||||||
}
|
}
|
||||||
|
|
||||||
expect :: proc(t: ^Tokenizer, kind: Token_Kind) -> (tok: Token, err: Error) {
|
expect :: proc(t: ^Tokenizer, kind: Token_Kind, multiline_string := false) -> (tok: Token, err: Error) {
|
||||||
tok = scan(t)
|
tok = scan(t, multiline_string=multiline_string)
|
||||||
if tok.kind == kind { return tok, .None }
|
if tok.kind == kind { return tok, .None }
|
||||||
|
|
||||||
error(t, t.offset, "Expected \"%v\", got \"%v\".", kind, tok.kind)
|
error(t, t.offset, "Expected \"%v\", got \"%v\".", kind, tok.kind)
|
||||||
@@ -480,7 +478,13 @@ parse_attribute :: proc(doc: ^Document) -> (attr: Attribute, offset: int, err: E
|
|||||||
offset = t.offset - len(key.text)
|
offset = t.offset - len(key.text)
|
||||||
|
|
||||||
_ = expect(t, .Eq) or_return
|
_ = expect(t, .Eq) or_return
|
||||||
value := expect(t, .String) or_return
|
value := expect(t, .String, multiline_string=true) or_return
|
||||||
|
|
||||||
|
normalized, normalize_err := entity.decode_xml(value.text, {.Normalize_Whitespace}, doc.allocator)
|
||||||
|
if normalize_err == .None {
|
||||||
|
append(&doc.strings_to_free, normalized)
|
||||||
|
value.text = normalized
|
||||||
|
}
|
||||||
|
|
||||||
attr.key = key.text
|
attr.key = key.text
|
||||||
attr.val = value.text
|
attr.val = value.text
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ The verbs:
|
|||||||
General:
|
General:
|
||||||
%v the value in a default format
|
%v the value in a default format
|
||||||
%#v an expanded format of %v with newlines and indentation
|
%#v an expanded format of %v with newlines and indentation
|
||||||
|
%w an Odin-syntax representation of the value
|
||||||
%T an Odin-syntax representation of the type of the value
|
%T an Odin-syntax representation of the type of the value
|
||||||
%% a literal percent sign; consumes no value
|
%% a literal percent sign; consumes no value
|
||||||
{{ a literal open brace; consumes no value
|
{{ a literal open brace; consumes no value
|
||||||
|
|||||||
@@ -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
@@ -1726,10 +1726,12 @@ fmt_bit_set :: proc(fi: ^Info, v: any, name: string = "", verb: rune = 'v') {
|
|||||||
|
|
||||||
et := runtime.type_info_base(info.elem)
|
et := runtime.type_info_base(info.elem)
|
||||||
|
|
||||||
if name != "" {
|
if verb != 'w' {
|
||||||
io.write_string(fi.writer, name, &fi.n)
|
if name != "" {
|
||||||
} else {
|
io.write_string(fi.writer, name, &fi.n)
|
||||||
reflect.write_type(fi.writer, type_info, &fi.n)
|
} else {
|
||||||
|
reflect.write_type(fi.writer, type_info, &fi.n)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
io.write_byte(fi.writer, '{', &fi.n)
|
io.write_byte(fi.writer, '{', &fi.n)
|
||||||
defer io.write_byte(fi.writer, '}', &fi.n)
|
defer io.write_byte(fi.writer, '}', &fi.n)
|
||||||
@@ -1746,9 +1748,17 @@ fmt_bit_set :: proc(fi: ^Info, v: any, name: string = "", verb: rune = 'v') {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if is_enum {
|
if is_enum {
|
||||||
|
enum_name: string
|
||||||
|
if ti_named, is_named := info.elem.variant.(runtime.Type_Info_Named); is_named {
|
||||||
|
enum_name = ti_named.name
|
||||||
|
}
|
||||||
for ev, evi in e.values {
|
for ev, evi in e.values {
|
||||||
v := u64(ev)
|
v := u64(ev)
|
||||||
if v == u64(i) {
|
if v == u64(i) {
|
||||||
|
if verb == 'w' {
|
||||||
|
io.write_string(fi.writer, enum_name, &fi.n)
|
||||||
|
io.write_byte(fi.writer, '.', &fi.n)
|
||||||
|
}
|
||||||
io.write_string(fi.writer, e.names[evi], &fi.n)
|
io.write_string(fi.writer, e.names[evi], &fi.n)
|
||||||
commas += 1
|
commas += 1
|
||||||
continue loop
|
continue loop
|
||||||
@@ -2391,7 +2401,6 @@ fmt_named :: proc(fi: ^Info, v: any, verb: rune, info: runtime.Type_Info_Named)
|
|||||||
runtime.Type_Info_Dynamic_Array,
|
runtime.Type_Info_Dynamic_Array,
|
||||||
runtime.Type_Info_Slice,
|
runtime.Type_Info_Slice,
|
||||||
runtime.Type_Info_Struct,
|
runtime.Type_Info_Struct,
|
||||||
runtime.Type_Info_Union,
|
|
||||||
runtime.Type_Info_Enum,
|
runtime.Type_Info_Enum,
|
||||||
runtime.Type_Info_Map,
|
runtime.Type_Info_Map,
|
||||||
runtime.Type_Info_Bit_Set,
|
runtime.Type_Info_Bit_Set,
|
||||||
@@ -2498,8 +2507,9 @@ fmt_matrix :: proc(fi: ^Info, v: any, verb: rune, info: runtime.Type_Info_Matrix
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Printed in Row-Major layout to match text layout
|
// Printed in Row-Major layout to match text layout
|
||||||
|
row_separator := ", " if verb == 'w' else "; "
|
||||||
for row in 0..<info.row_count {
|
for row in 0..<info.row_count {
|
||||||
if row > 0 { io.write_string(fi.writer, "; ", &fi.n) }
|
if row > 0 { io.write_string(fi.writer, row_separator, &fi.n) }
|
||||||
for col in 0..<info.column_count {
|
for col in 0..<info.column_count {
|
||||||
if col > 0 { io.write_string(fi.writer, ", ", &fi.n) }
|
if col > 0 { io.write_string(fi.writer, ", ", &fi.n) }
|
||||||
|
|
||||||
|
|||||||
@@ -362,11 +362,11 @@ platform_count_lsb :: #force_inline proc(a: $T) -> (count: int)
|
|||||||
|
|
||||||
count_lsb :: proc { int_count_lsb, platform_count_lsb, }
|
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
|
when _DIGIT_BITS == 60 { // DIGIT = u64
|
||||||
return DIGIT(rnd.uint64(r)) & _MASK
|
return DIGIT(rnd.uint64()) & _MASK
|
||||||
} else when _DIGIT_BITS == 28 { // DIGIT = u32
|
} else when _DIGIT_BITS == 28 { // DIGIT = u32
|
||||||
return DIGIT(rnd.uint32(r)) & _MASK
|
return DIGIT(rnd.uint32()) & _MASK
|
||||||
} else {
|
} else {
|
||||||
panic("Unsupported DIGIT size.")
|
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.
|
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.
|
Check that `a` is usable.
|
||||||
*/
|
*/
|
||||||
assert_if_nil(dest)
|
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, }
|
random :: proc { int_random, }
|
||||||
|
|||||||
@@ -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 {
|
if cap == 0 {
|
||||||
a.digit = make([dynamic]DIGIT, needed, allocator)
|
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.
|
`[dynamic]DIGIT` already knows what allocator was used for it, so resize will do the right thing.
|
||||||
*/
|
*/
|
||||||
resize(&a.digit, needed)
|
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.
|
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_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
|
when _DIGIT_BITS == 60 { // DIGIT = u64
|
||||||
return DIGIT(rnd.uint64(r)) & _MASK
|
return DIGIT(rnd.uint64()) & _MASK
|
||||||
} else when _DIGIT_BITS == 28 { // DIGIT = u32
|
} else when _DIGIT_BITS == 28 { // DIGIT = u32
|
||||||
return DIGIT(rnd.uint32(r)) & _MASK
|
return DIGIT(rnd.uint32()) & _MASK
|
||||||
} else {
|
} else {
|
||||||
panic("Unsupported DIGIT size.")
|
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.
|
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
|
context.allocator = allocator
|
||||||
|
|
||||||
bits := bits
|
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
|
#force_inline internal_grow(dest, digits) or_return
|
||||||
|
|
||||||
for i := 0; i < digits; i += 1 {
|
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 {
|
if bits > 0 {
|
||||||
dest.digit[digits - 1] &= ((1 << uint(bits)) - 1)
|
dest.digit[digits - 1] &= ((1 << uint(bits)) - 1)
|
||||||
|
|||||||
@@ -12,8 +12,6 @@
|
|||||||
|
|
||||||
package math_big
|
package math_big
|
||||||
|
|
||||||
import rnd "core:math/rand"
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Determines if an Integer is divisible by one of the _PRIME_TABLE primes.
|
Determines if an Integer is divisible by one of the _PRIME_TABLE primes.
|
||||||
Returns true if it is, false if not.
|
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.
|
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
|
context.allocator = allocator
|
||||||
miller_rabin_trials := miller_rabin_trials
|
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 {
|
for ix := 0; ix < miller_rabin_trials; ix += 1 {
|
||||||
|
|
||||||
// rand() guarantees the first digit to be non-zero
|
// 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
|
// Reduce digit before casting because DIGIT might be bigger than
|
||||||
// an unsigned int and "mask" on the other side is most probably not.
|
// 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!
|
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
|
context.allocator = allocator
|
||||||
flags := flags
|
flags := flags
|
||||||
trials := trials
|
trials := trials
|
||||||
|
|||||||
@@ -8,12 +8,12 @@ float32_uniform :: float32_range
|
|||||||
// Triangular Distribution
|
// Triangular Distribution
|
||||||
// See: http://wikipedia.org/wiki/Triangular_distribution
|
// See: http://wikipedia.org/wiki/Triangular_distribution
|
||||||
@(require_results)
|
@(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 {
|
if hi-lo == 0 {
|
||||||
return lo
|
return lo
|
||||||
}
|
}
|
||||||
lo, hi := lo, hi
|
lo, hi := lo, hi
|
||||||
u := float64(r)
|
u := float64()
|
||||||
c := f64(0.5) if mode == nil else clamp((mode.?-lo) / (hi-lo), 0, 1)
|
c := f64(0.5) if mode == nil else clamp((mode.?-lo) / (hi-lo), 0, 1)
|
||||||
if u > c {
|
if u > c {
|
||||||
u = 1-u
|
u = 1-u
|
||||||
@@ -26,12 +26,12 @@ float64_triangular :: proc(lo, hi: f64, mode: Maybe(f64), r: ^Rand = nil) -> f64
|
|||||||
// Triangular Distribution
|
// Triangular Distribution
|
||||||
// See: http://wikipedia.org/wiki/Triangular_distribution
|
// See: http://wikipedia.org/wiki/Triangular_distribution
|
||||||
@(require_results)
|
@(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 {
|
if hi-lo == 0 {
|
||||||
return lo
|
return lo
|
||||||
}
|
}
|
||||||
lo, hi := lo, hi
|
lo, hi := lo, hi
|
||||||
u := float32(r)
|
u := float32()
|
||||||
c := f32(0.5) if mode == nil else clamp((mode.?-lo) / (hi-lo), 0, 1)
|
c := f32(0.5) if mode == nil else clamp((mode.?-lo) / (hi-lo), 0, 1)
|
||||||
if u > c {
|
if u > c {
|
||||||
u = 1-u
|
u = 1-u
|
||||||
@@ -44,25 +44,25 @@ float32_triangular :: proc(lo, hi: f32, mode: Maybe(f32), r: ^Rand = nil) -> f32
|
|||||||
|
|
||||||
// Normal/Gaussian Distribution
|
// Normal/Gaussian Distribution
|
||||||
@(require_results)
|
@(require_results)
|
||||||
float64_normal :: proc(mean, stddev: f64, r: ^Rand = nil) -> f64 {
|
float64_normal :: proc(mean, stddev: f64) -> f64 {
|
||||||
return norm_float64(r) * stddev + mean
|
return norm_float64() * stddev + mean
|
||||||
}
|
}
|
||||||
// Normal/Gaussian Distribution
|
// Normal/Gaussian Distribution
|
||||||
@(require_results)
|
@(require_results)
|
||||||
float32_normal :: proc(mean, stddev: f32, r: ^Rand = nil) -> f32 {
|
float32_normal :: proc(mean, stddev: f32) -> f32 {
|
||||||
return f32(float64_normal(f64(mean), f64(stddev), r))
|
return f32(float64_normal(f64(mean), f64(stddev)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Log Normal Distribution
|
// Log Normal Distribution
|
||||||
@(require_results)
|
@(require_results)
|
||||||
float64_log_normal :: proc(mean, stddev: f64, r: ^Rand = nil) -> f64 {
|
float64_log_normal :: proc(mean, stddev: f64) -> f64 {
|
||||||
return math.exp(float64_normal(mean, stddev, r))
|
return math.exp(float64_normal(mean, stddev))
|
||||||
}
|
}
|
||||||
// Log Normal Distribution
|
// Log Normal Distribution
|
||||||
@(require_results)
|
@(require_results)
|
||||||
float32_log_normal :: proc(mean, stddev: f32, r: ^Rand = nil) -> f32 {
|
float32_log_normal :: proc(mean, stddev: f32) -> f32 {
|
||||||
return f32(float64_log_normal(f64(mean), f64(stddev), r))
|
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
|
// 0 to positive infinity if lambda > 0
|
||||||
// negative infinity to 0 if lambda <= 0
|
// negative infinity to 0 if lambda <= 0
|
||||||
@(require_results)
|
@(require_results)
|
||||||
float64_exponential :: proc(lambda: f64, r: ^Rand = nil) -> f64 {
|
float64_exponential :: proc(lambda: f64) -> f64 {
|
||||||
return - math.ln(1 - float64(r)) / lambda
|
return - math.ln(1 - float64()) / lambda
|
||||||
}
|
}
|
||||||
// Exponential Distribution
|
// Exponential Distribution
|
||||||
// `lambda` is 1.0/(desired mean). It should be non-zero.
|
// `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
|
// 0 to positive infinity if lambda > 0
|
||||||
// negative infinity to 0 if lambda <= 0
|
// negative infinity to 0 if lambda <= 0
|
||||||
@(require_results)
|
@(require_results)
|
||||||
float32_exponential :: proc(lambda: f32, r: ^Rand = nil) -> f32 {
|
float32_exponential :: proc(lambda: f32) -> f32 {
|
||||||
return f32(float64_exponential(f64(lambda), r))
|
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)
|
// mean is alpha*beta, variance is math.pow(alpha*beta, 2)
|
||||||
@(require_results)
|
@(require_results)
|
||||||
float64_gamma :: proc(alpha, beta: f64, r: ^Rand = nil) -> f64 {
|
float64_gamma :: proc(alpha, beta: f64) -> f64 {
|
||||||
if alpha <= 0 || beta <= 0 {
|
if alpha <= 0 || beta <= 0 {
|
||||||
panic(#procedure + ": alpha and beta must be > 0.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
|
bbb := alpha - LOG4
|
||||||
ccc := alpha + ainv
|
ccc := alpha + ainv
|
||||||
for {
|
for {
|
||||||
u1 := float64(r)
|
u1 := float64()
|
||||||
if !(1e-7 < u1 && u1 < 0.9999999) {
|
if !(1e-7 < u1 && u1 < 0.9999999) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
u2 := 1 - float64(r)
|
u2 := 1 - float64()
|
||||||
v := math.ln(u1 / (1 - u1)) / ainv
|
v := math.ln(u1 / (1 - u1)) / ainv
|
||||||
x := alpha * math.exp(v)
|
x := alpha * math.exp(v)
|
||||||
z := u1 * u1 * u2
|
z := u1 * u1 * u2
|
||||||
@@ -127,12 +127,12 @@ float64_gamma :: proc(alpha, beta: f64, r: ^Rand = nil) -> f64 {
|
|||||||
}
|
}
|
||||||
case alpha == 1:
|
case alpha == 1:
|
||||||
// float64_exponential(1/beta)
|
// float64_exponential(1/beta)
|
||||||
return -math.ln(1 - float64(r)) * beta
|
return -math.ln(1 - float64()) * beta
|
||||||
case:
|
case:
|
||||||
// ALGORITHM GS of Statistical Computing - Kennedy & Gentle
|
// ALGORITHM GS of Statistical Computing - Kennedy & Gentle
|
||||||
x: f64
|
x: f64
|
||||||
for {
|
for {
|
||||||
u := float64(r)
|
u := float64()
|
||||||
b := (math.e + alpha) / math.e
|
b := (math.e + alpha) / math.e
|
||||||
p := b * u
|
p := b * u
|
||||||
if p <= 1 {
|
if p <= 1 {
|
||||||
@@ -140,7 +140,7 @@ float64_gamma :: proc(alpha, beta: f64, r: ^Rand = nil) -> f64 {
|
|||||||
} else {
|
} else {
|
||||||
x = -math.ln((b - p) / alpha)
|
x = -math.ln((b - p) / alpha)
|
||||||
}
|
}
|
||||||
u1 := float64(r)
|
u1 := float64()
|
||||||
if p > 1 {
|
if p > 1 {
|
||||||
if u1 <= math.pow(x, alpha-1) {
|
if u1 <= math.pow(x, alpha-1) {
|
||||||
break
|
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)
|
// mean is alpha*beta, variance is math.pow(alpha*beta, 2)
|
||||||
@(require_results)
|
@(require_results)
|
||||||
float32_gamma :: proc(alpha, beta: f32, r: ^Rand = nil) -> f32 {
|
float32_gamma :: proc(alpha, beta: f32) -> f32 {
|
||||||
return f32(float64_gamma(f64(alpha), f64(beta), r))
|
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
|
// Return values range between 0 and 1
|
||||||
@(require_results)
|
@(require_results)
|
||||||
float64_beta :: proc(alpha, beta: f64, r: ^Rand = nil) -> f64 {
|
float64_beta :: proc(alpha, beta: f64) -> f64 {
|
||||||
if alpha <= 0 || beta <= 0 {
|
if alpha <= 0 || beta <= 0 {
|
||||||
panic(#procedure + ": alpha and beta must be > 0.0")
|
panic(#procedure + ": alpha and beta must be > 0.0")
|
||||||
}
|
}
|
||||||
// Knuth Vol 2 Ed 3 pg 134 "the beta distribution"
|
// 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 {
|
if y != 0 {
|
||||||
return y / (y + float64_gamma(beta, 1.0, r))
|
return y / (y + float64_gamma(beta, 1.0))
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
@@ -190,35 +190,35 @@ float64_beta :: proc(alpha, beta: f64, r: ^Rand = nil) -> f64 {
|
|||||||
//
|
//
|
||||||
// Return values range between 0 and 1
|
// Return values range between 0 and 1
|
||||||
@(require_results)
|
@(require_results)
|
||||||
float32_beta :: proc(alpha, beta: f32, r: ^Rand = nil) -> f32 {
|
float32_beta :: proc(alpha, beta: f32) -> f32 {
|
||||||
return f32(float64_beta(f64(alpha), f64(beta), r))
|
return f32(float64_beta(f64(alpha), f64(beta)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Pareto distribution, `alpha` is the shape parameter.
|
// Pareto distribution, `alpha` is the shape parameter.
|
||||||
// https://wikipedia.org/wiki/Pareto_distribution
|
// https://wikipedia.org/wiki/Pareto_distribution
|
||||||
@(require_results)
|
@(require_results)
|
||||||
float64_pareto :: proc(alpha: f64, r: ^Rand = nil) -> f64 {
|
float64_pareto :: proc(alpha: f64) -> f64 {
|
||||||
return math.pow(1 - float64(r), -1.0 / alpha)
|
return math.pow(1 - float64(), -1.0 / alpha)
|
||||||
}
|
}
|
||||||
// Pareto distribution, `alpha` is the shape parameter.
|
// Pareto distribution, `alpha` is the shape parameter.
|
||||||
// https://wikipedia.org/wiki/Pareto_distribution
|
// https://wikipedia.org/wiki/Pareto_distribution
|
||||||
@(require_results)
|
@(require_results)
|
||||||
float32_pareto :: proc(alpha, beta: f32, r: ^Rand = nil) -> f32 {
|
float32_pareto :: proc(alpha, beta: f32) -> f32 {
|
||||||
return f32(float64_pareto(f64(alpha), r))
|
return f32(float64_pareto(f64(alpha)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Weibull distribution, `alpha` is the scale parameter, `beta` is the shape parameter.
|
// Weibull distribution, `alpha` is the scale parameter, `beta` is the shape parameter.
|
||||||
@(require_results)
|
@(require_results)
|
||||||
float64_weibull :: proc(alpha, beta: f64, r: ^Rand = nil) -> f64 {
|
float64_weibull :: proc(alpha, beta: f64) -> f64 {
|
||||||
u := 1 - float64(r)
|
u := 1 - float64()
|
||||||
return alpha * math.pow(-math.ln(u), 1.0/beta)
|
return alpha * math.pow(-math.ln(u), 1.0/beta)
|
||||||
}
|
}
|
||||||
// Weibull distribution, `alpha` is the scale parameter, `beta` is the shape parameter.
|
// Weibull distribution, `alpha` is the scale parameter, `beta` is the shape parameter.
|
||||||
@(require_results)
|
@(require_results)
|
||||||
float32_weibull :: proc(alpha, beta: f32, r: ^Rand = nil) -> f32 {
|
float32_weibull :: proc(alpha, beta: f32) -> f32 {
|
||||||
return f32(float64_weibull(f64(alpha), f64(beta), r))
|
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
|
// `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
|
// When `kappa` is zero, the Distribution is a uniform Distribution over the range 0 to 2pi
|
||||||
@(require_results)
|
@(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.
|
// Fisher, N.I., "Statistical Analysis of Circular Data", Cambridge University Press, 1993.
|
||||||
|
|
||||||
mu := mean_angle
|
mu := mean_angle
|
||||||
if kappa <= 1e-6 {
|
if kappa <= 1e-6 {
|
||||||
return math.TAU * float64(r)
|
return math.TAU * float64()
|
||||||
}
|
}
|
||||||
|
|
||||||
s := 0.5 / kappa
|
s := 0.5 / kappa
|
||||||
t := s + math.sqrt(1 + s*s)
|
t := s + math.sqrt(1 + s*s)
|
||||||
z: f64
|
z: f64
|
||||||
for {
|
for {
|
||||||
u1 := float64(r)
|
u1 := float64()
|
||||||
z = math.cos(math.TAU * 0.5 * u1)
|
z = math.cos(math.TAU * 0.5 * u1)
|
||||||
|
|
||||||
d := z / (t + z)
|
d := z / (t + z)
|
||||||
u2 := float64(r)
|
u2 := float64()
|
||||||
if u2 < 1 - d*d || u2 <= (1-d)*math.exp(d) {
|
if u2 < 1 - d*d || u2 <= (1-d)*math.exp(d) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -251,7 +251,7 @@ float64_von_mises :: proc(mean_angle, kappa: f64, r: ^Rand = nil) -> f64 {
|
|||||||
|
|
||||||
q := 1.0 / t
|
q := 1.0 / t
|
||||||
f := (q + z) / (1 + q*z)
|
f := (q + z) / (1 + q*z)
|
||||||
u3 := float64(r)
|
u3 := float64()
|
||||||
if u3 > 0.5 {
|
if u3 > 0.5 {
|
||||||
return math.mod(mu + math.acos(f), math.TAU)
|
return math.mod(mu + math.acos(f), math.TAU)
|
||||||
} else {
|
} 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
|
// `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
|
// When `kappa` is zero, the Distribution is a uniform Distribution over the range 0 to 2pi
|
||||||
@(require_results)
|
@(require_results)
|
||||||
float32_von_mises :: proc(mean_angle, kappa: f32, r: ^Rand = nil) -> f32 {
|
float32_von_mises :: proc(mean_angle, kappa: f32) -> f32 {
|
||||||
return f32(float64_von_mises(f64(mean_angle), f64(kappa), r))
|
return f32(float64_von_mises(f64(mean_angle), f64(kappa)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Cauchy-Lorentz Distribution
|
// Cauchy-Lorentz Distribution
|
||||||
// `x_0` is the location, `gamma` is the scale where `gamma` > 0
|
// `x_0` is the location, `gamma` is the scale where `gamma` > 0
|
||||||
@(require_results)
|
@(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)
|
assert(gamma > 0)
|
||||||
|
|
||||||
// Calculated from the inverse CDF
|
// 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
|
// Cauchy-Lorentz Distribution
|
||||||
// `x_0` is the location, `gamma` is the scale where `gamma` > 0
|
// `x_0` is the location, `gamma` is the scale where `gamma` > 0
|
||||||
@(require_results)
|
@(require_results)
|
||||||
float32_cauchy_lorentz :: proc(x_0, gamma: f32, r: ^Rand = nil) -> f32 {
|
float32_cauchy_lorentz :: proc(x_0, gamma: f32) -> f32 {
|
||||||
return f32(float64_cauchy_lorentz(f64(x_0), f64(gamma), r))
|
return f32(float64_cauchy_lorentz(f64(x_0), f64(gamma)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Log Cauchy-Lorentz Distribution
|
// Log Cauchy-Lorentz Distribution
|
||||||
// `x_0` is the location, `gamma` is the scale where `gamma` > 0
|
// `x_0` is the location, `gamma` is the scale where `gamma` > 0
|
||||||
@(require_results)
|
@(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)
|
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
|
// Log Cauchy-Lorentz Distribution
|
||||||
// `x_0` is the location, `gamma` is the scale where `gamma` > 0
|
// `x_0` is the location, `gamma` is the scale where `gamma` > 0
|
||||||
@(require_results)
|
@(require_results)
|
||||||
float32_log_cauchy_lorentz :: proc(x_0, gamma: f32, r: ^Rand = nil) -> f32 {
|
float32_log_cauchy_lorentz :: proc(x_0, gamma: f32) -> f32 {
|
||||||
return f32(float64_log_cauchy_lorentz(f64(x_0), f64(gamma), r))
|
return f32(float64_log_cauchy_lorentz(f64(x_0), f64(gamma)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Laplace Distribution
|
// Laplace Distribution
|
||||||
// `b` is the scale where `b` > 0
|
// `b` is the scale where `b` > 0
|
||||||
@(require_results)
|
@(require_results)
|
||||||
float64_laplace :: proc(mean, b: f64, r: ^Rand = nil) -> f64 {
|
float64_laplace :: proc(mean, b: f64) -> f64 {
|
||||||
assert(b > 0)
|
assert(b > 0)
|
||||||
p := float64(r)-0.5
|
p := float64()-0.5
|
||||||
return -math.sign(p)*math.ln(1 - 2*abs(p))*b + mean
|
return -math.sign(p)*math.ln(1 - 2*abs(p))*b + mean
|
||||||
}
|
}
|
||||||
// Laplace Distribution
|
// Laplace Distribution
|
||||||
// `b` is the scale where `b` > 0
|
// `b` is the scale where `b` > 0
|
||||||
@(require_results)
|
@(require_results)
|
||||||
float32_laplace :: proc(mean, b: f32, r: ^Rand = nil) -> f32 {
|
float32_laplace :: proc(mean, b: f32) -> f32 {
|
||||||
return f32(float64_laplace(f64(mean), f64(b), r))
|
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
|
// `eta` is the shape, `b` is the scale
|
||||||
// Both `eta` and `b` must be > 0
|
// Both `eta` and `b` must be > 0
|
||||||
@(require_results)
|
@(require_results)
|
||||||
float64_gompertz :: proc(eta, b: f64, r: ^Rand = nil) -> f64 {
|
float64_gompertz :: proc(eta, b: f64) -> f64 {
|
||||||
if eta <= 0 || b <= 0 {
|
if eta <= 0 || b <= 0 {
|
||||||
panic(#procedure + ": eta and b must be > 0.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
|
return math.ln(1 - math.ln(1 - p)/eta)/b
|
||||||
}
|
}
|
||||||
// Gompertz Distribution
|
// Gompertz Distribution
|
||||||
// `eta` is the shape, `b` is the scale
|
// `eta` is the shape, `b` is the scale
|
||||||
// Both `eta` and `b` must be > 0
|
// Both `eta` and `b` must be > 0
|
||||||
@(require_results)
|
@(require_results)
|
||||||
float32_gompertz :: proc(eta, b: f32, r: ^Rand = nil) -> f32 {
|
float32_gompertz :: proc(eta, b: f32) -> f32 {
|
||||||
return f32(float64_gompertz(f64(eta), f64(b), r))
|
return f32(float64_gompertz(f64(eta), f64(b)))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import "core:math"
|
|||||||
// https://www.jstatsoft.org/article/view/v005i08 [web page]
|
// https://www.jstatsoft.org/article/view/v005i08 [web page]
|
||||||
//
|
//
|
||||||
@(require_results)
|
@(require_results)
|
||||||
exp_float64 :: proc(r: ^Rand = nil) -> f64 {
|
exp_float64 :: proc() -> f64 {
|
||||||
re :: 7.69711747013104972
|
re :: 7.69711747013104972
|
||||||
|
|
||||||
@(static, rodata)
|
@(static, rodata)
|
||||||
@@ -199,16 +199,16 @@ exp_float64 :: proc(r: ^Rand = nil) -> f64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
j := uint32(r)
|
j := uint32()
|
||||||
i := j & 0xFF
|
i := j & 0xFF
|
||||||
x := f64(j) * f64(we[i])
|
x := f64(j) * f64(we[i])
|
||||||
if j < ke[i] {
|
if j < ke[i] {
|
||||||
return x
|
return x
|
||||||
}
|
}
|
||||||
if i == 0 {
|
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
|
return x
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import "core:math"
|
|||||||
// https://www.jstatsoft.org/article/view/v005i08 [web page]
|
// https://www.jstatsoft.org/article/view/v005i08 [web page]
|
||||||
//
|
//
|
||||||
@(require_results)
|
@(require_results)
|
||||||
norm_float64 :: proc(r: ^Rand = nil) -> f64 {
|
norm_float64 :: proc() -> f64 {
|
||||||
rn :: 3.442619855899
|
rn :: 3.442619855899
|
||||||
|
|
||||||
@(static, rodata)
|
@(static, rodata)
|
||||||
@@ -115,15 +115,8 @@ norm_float64 :: proc(r: ^Rand = nil) -> f64 {
|
|||||||
0.008624485, 0.005548995, 0.0026696292,
|
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 {
|
for {
|
||||||
j := i32(uint32(r))
|
j := i32(uint32())
|
||||||
i := j & 0x7f
|
i := j & 0x7f
|
||||||
x := f64(j) * f64(wn[i])
|
x := f64(j) * f64(wn[i])
|
||||||
if u32(abs(j)) < kn[i] {
|
if u32(abs(j)) < kn[i] {
|
||||||
@@ -133,15 +126,15 @@ norm_float64 :: proc(r: ^Rand = nil) -> f64 {
|
|||||||
|
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
for {
|
for {
|
||||||
x = -math.ln(float64(r)) * (1.0/ rn)
|
x = -math.ln(float64()) * (1.0/ rn)
|
||||||
y := -math.ln(float64(r))
|
y := -math.ln(float64())
|
||||||
if y+y >= x*x {
|
if y+y >= x*x {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return j > 0 ? rn + x : -rn - x
|
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
|
return x
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+63
-252
@@ -5,22 +5,22 @@ Package core:math/rand implements various random number generators
|
|||||||
package rand
|
package rand
|
||||||
|
|
||||||
import "base:intrinsics"
|
import "base:intrinsics"
|
||||||
import "core:crypto"
|
import "base:runtime"
|
||||||
import "core:math"
|
import "core:math"
|
||||||
import "core:mem"
|
import "core:mem"
|
||||||
|
|
||||||
Rand :: struct {
|
Default_Random_State :: runtime.Default_Random_State
|
||||||
state: u64,
|
default_random_generator :: runtime.default_random_generator
|
||||||
inc: u64,
|
|
||||||
is_system: bool,
|
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:
|
Inputs:
|
||||||
- seed: The seed value
|
- seed: The seed value
|
||||||
@@ -37,139 +37,46 @@ Example:
|
|||||||
Possible Output:
|
Possible Output:
|
||||||
|
|
||||||
10
|
10
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
@(deprecated="Prefer `rand.reset`")
|
||||||
set_global_seed :: proc(seed: u64) {
|
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:
|
Inputs:
|
||||||
- seed: The seed value to create the random number generator with
|
- seed: The seed value
|
||||||
|
|
||||||
Returns:
|
|
||||||
- res: The created random number generator
|
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
import "core:math/rand"
|
import "core:math/rand"
|
||||||
import "core:fmt"
|
import "core:fmt"
|
||||||
|
|
||||||
create_example :: proc() {
|
set_global_seed_example :: proc() {
|
||||||
my_rand := rand.create(1)
|
rand.set_global_seed(1)
|
||||||
fmt.println(rand.uint64(&my_rand))
|
fmt.println(rand.uint64())
|
||||||
}
|
}
|
||||||
|
|
||||||
Possible Output:
|
Possible Output:
|
||||||
|
|
||||||
10
|
10
|
||||||
|
|
||||||
*/
|
*/
|
||||||
@(require_results)
|
reset :: proc(seed: u64) {
|
||||||
create :: proc(seed: u64) -> (res: Rand) {
|
runtime.random_generator_reset_u64(context.random_generator, seed)
|
||||||
r: Rand
|
|
||||||
init(&r, seed)
|
|
||||||
return r
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
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)
|
@(private)
|
||||||
_random_u64 :: proc(r: ^Rand) -> u64 {
|
_random_u64 :: proc() -> (res: u64) {
|
||||||
r := r
|
ok := runtime.random_generator_read_ptr(context.random_generator, &res, size_of(res))
|
||||||
switch {
|
assert(ok, "uninitialized context.random_generator")
|
||||||
case r == nil:
|
return
|
||||||
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))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
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.
|
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:
|
Returns:
|
||||||
- val: A random unsigned 32 bit value
|
- val: A random unsigned 32 bit value
|
||||||
|
|
||||||
@@ -178,11 +85,7 @@ Example:
|
|||||||
import "core:fmt"
|
import "core:fmt"
|
||||||
|
|
||||||
uint32_example :: proc() {
|
uint32_example :: proc() {
|
||||||
// Using the global random number generator
|
|
||||||
fmt.println(rand.uint32())
|
fmt.println(rand.uint32())
|
||||||
// Using local random number generator
|
|
||||||
my_rand := rand.create(1)
|
|
||||||
fmt.println(rand.uint32(&my_rand))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Possible Output:
|
Possible Output:
|
||||||
@@ -192,14 +95,11 @@ Possible Output:
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
@(require_results)
|
@(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.
|
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:
|
Returns:
|
||||||
- val: A random unsigned 64 bit value
|
- val: A random unsigned 64 bit value
|
||||||
|
|
||||||
@@ -208,11 +108,7 @@ Example:
|
|||||||
import "core:fmt"
|
import "core:fmt"
|
||||||
|
|
||||||
uint64_example :: proc() {
|
uint64_example :: proc() {
|
||||||
// Using the global random number generator
|
|
||||||
fmt.println(rand.uint64())
|
fmt.println(rand.uint64())
|
||||||
// Using local random number generator
|
|
||||||
my_rand := rand.create(1)
|
|
||||||
fmt.println(rand.uint64(&my_rand))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Possible Output:
|
Possible Output:
|
||||||
@@ -222,14 +118,11 @@ Possible Output:
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
@(require_results)
|
@(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.
|
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:
|
Returns:
|
||||||
- val: A random unsigned 128 bit value
|
- val: A random unsigned 128 bit value
|
||||||
|
|
||||||
@@ -238,11 +131,7 @@ Example:
|
|||||||
import "core:fmt"
|
import "core:fmt"
|
||||||
|
|
||||||
uint128_example :: proc() {
|
uint128_example :: proc() {
|
||||||
// Using the global random number generator
|
|
||||||
fmt.println(rand.uint128())
|
fmt.println(rand.uint128())
|
||||||
// Using local random number generator
|
|
||||||
my_rand := rand.create(1)
|
|
||||||
fmt.println(rand.uint128(&my_rand))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Possible Output:
|
Possible Output:
|
||||||
@@ -252,9 +141,9 @@ Possible Output:
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
@(require_results)
|
@(require_results)
|
||||||
uint128 :: proc(r: ^Rand = nil) -> (val: u128) {
|
uint128 :: proc() -> (val: u128) {
|
||||||
a := u128(_random_u64(r))
|
a := u128(_random_u64())
|
||||||
b := u128(_random_u64(r))
|
b := u128(_random_u64())
|
||||||
return (a<<64) | b
|
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.
|
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.
|
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:
|
Returns:
|
||||||
- val: A random 31 bit value
|
- val: A random 31 bit value
|
||||||
|
|
||||||
@@ -273,11 +159,7 @@ Example:
|
|||||||
import "core:fmt"
|
import "core:fmt"
|
||||||
|
|
||||||
int31_example :: proc() {
|
int31_example :: proc() {
|
||||||
// Using the global random number generator
|
|
||||||
fmt.println(rand.int31())
|
fmt.println(rand.int31())
|
||||||
// Using local random number generator
|
|
||||||
my_rand := rand.create(1)
|
|
||||||
fmt.println(rand.int31(&my_rand))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Possible Output:
|
Possible Output:
|
||||||
@@ -286,15 +168,12 @@ Possible Output:
|
|||||||
389
|
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.
|
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.
|
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:
|
Returns:
|
||||||
- val: A random 63 bit value
|
- val: A random 63 bit value
|
||||||
|
|
||||||
@@ -303,11 +182,7 @@ Example:
|
|||||||
import "core:fmt"
|
import "core:fmt"
|
||||||
|
|
||||||
int63_example :: proc() {
|
int63_example :: proc() {
|
||||||
// Using the global random number generator
|
|
||||||
fmt.println(rand.int63())
|
fmt.println(rand.int63())
|
||||||
// Using local random number generator
|
|
||||||
my_rand := rand.create(1)
|
|
||||||
fmt.println(rand.int63(&my_rand))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Possible Output:
|
Possible Output:
|
||||||
@@ -316,15 +191,12 @@ Possible Output:
|
|||||||
389
|
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.
|
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.
|
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:
|
Returns:
|
||||||
- val: A random 127 bit value
|
- val: A random 127 bit value
|
||||||
|
|
||||||
@@ -333,11 +205,7 @@ Example:
|
|||||||
import "core:fmt"
|
import "core:fmt"
|
||||||
|
|
||||||
int127_example :: proc() {
|
int127_example :: proc() {
|
||||||
// Using the global random number generator
|
|
||||||
fmt.println(rand.int127())
|
fmt.println(rand.int127())
|
||||||
// Using local random number generator
|
|
||||||
my_rand := rand.create(1)
|
|
||||||
fmt.println(rand.int127(&my_rand))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Possible Output:
|
Possible Output:
|
||||||
@@ -346,14 +214,13 @@ Possible Output:
|
|||||||
389
|
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.
|
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:
|
Inputs:
|
||||||
- n: The upper bound of the generated number, this value is exclusive
|
- 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:
|
Returns:
|
||||||
- val: A random 31 bit value in the range `[0, n)`
|
- val: A random 31 bit value in the range `[0, n)`
|
||||||
@@ -365,11 +232,7 @@ Example:
|
|||||||
import "core:fmt"
|
import "core:fmt"
|
||||||
|
|
||||||
int31_max_example :: proc() {
|
int31_max_example :: proc() {
|
||||||
// Using the global random number generator
|
|
||||||
fmt.println(rand.int31_max(16))
|
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:
|
Possible Output:
|
||||||
@@ -379,17 +242,17 @@ Possible Output:
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
@(require_results)
|
@(require_results)
|
||||||
int31_max :: proc(n: i32, r: ^Rand = nil) -> (val: i32) {
|
int31_max :: proc(n: i32) -> (val: i32) {
|
||||||
if n <= 0 {
|
if n <= 0 {
|
||||||
panic("Invalid argument to int31_max")
|
panic("Invalid argument to int31_max")
|
||||||
}
|
}
|
||||||
if n&(n-1) == 0 {
|
if n&(n-1) == 0 {
|
||||||
return int31(r) & (n-1)
|
return int31() & (n-1)
|
||||||
}
|
}
|
||||||
max := i32((1<<31) - 1 - (1<<31)%u32(n))
|
max := i32((1<<31) - 1 - (1<<31)%u32(n))
|
||||||
v := int31(r)
|
v := int31()
|
||||||
for v > max {
|
for v > max {
|
||||||
v = int31(r)
|
v = int31()
|
||||||
}
|
}
|
||||||
return v % n
|
return v % n
|
||||||
}
|
}
|
||||||
@@ -399,7 +262,6 @@ Generates a random 63 bit value in the range `[0, n)` using the provided random
|
|||||||
|
|
||||||
Inputs:
|
Inputs:
|
||||||
- n: The upper bound of the generated number, this value is exclusive
|
- 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:
|
Returns:
|
||||||
- val: A random 63 bit value in the range `[0, n)`
|
- val: A random 63 bit value in the range `[0, n)`
|
||||||
@@ -411,11 +273,7 @@ Example:
|
|||||||
import "core:fmt"
|
import "core:fmt"
|
||||||
|
|
||||||
int63_max_example :: proc() {
|
int63_max_example :: proc() {
|
||||||
// Using the global random number generator
|
|
||||||
fmt.println(rand.int63_max(16))
|
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:
|
Possible Output:
|
||||||
@@ -425,17 +283,17 @@ Possible Output:
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
@(require_results)
|
@(require_results)
|
||||||
int63_max :: proc(n: i64, r: ^Rand = nil) -> (val: i64) {
|
int63_max :: proc(n: i64) -> (val: i64) {
|
||||||
if n <= 0 {
|
if n <= 0 {
|
||||||
panic("Invalid argument to int63_max")
|
panic("Invalid argument to int63_max")
|
||||||
}
|
}
|
||||||
if n&(n-1) == 0 {
|
if n&(n-1) == 0 {
|
||||||
return int63(r) & (n-1)
|
return int63() & (n-1)
|
||||||
}
|
}
|
||||||
max := i64((1<<63) - 1 - (1<<63)%u64(n))
|
max := i64((1<<63) - 1 - (1<<63)%u64(n))
|
||||||
v := int63(r)
|
v := int63()
|
||||||
for v > max {
|
for v > max {
|
||||||
v = int63(r)
|
v = int63()
|
||||||
}
|
}
|
||||||
return v % n
|
return v % n
|
||||||
}
|
}
|
||||||
@@ -445,7 +303,6 @@ Generates a random 127 bit value in the range `[0, n)` using the provided random
|
|||||||
|
|
||||||
Inputs:
|
Inputs:
|
||||||
- n: The upper bound of the generated number, this value is exclusive
|
- 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:
|
Returns:
|
||||||
- val: A random 127 bit value in the range `[0, n)`
|
- val: A random 127 bit value in the range `[0, n)`
|
||||||
@@ -457,11 +314,7 @@ Example:
|
|||||||
import "core:fmt"
|
import "core:fmt"
|
||||||
|
|
||||||
int127_max_example :: proc() {
|
int127_max_example :: proc() {
|
||||||
// Using the global random number generator
|
|
||||||
fmt.println(rand.int127_max(16))
|
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:
|
Possible Output:
|
||||||
@@ -471,17 +324,17 @@ Possible Output:
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
@(require_results)
|
@(require_results)
|
||||||
int127_max :: proc(n: i128, r: ^Rand = nil) -> (val: i128) {
|
int127_max :: proc(n: i128) -> (val: i128) {
|
||||||
if n <= 0 {
|
if n <= 0 {
|
||||||
panic("Invalid argument to int127_max")
|
panic("Invalid argument to int127_max")
|
||||||
}
|
}
|
||||||
if n&(n-1) == 0 {
|
if n&(n-1) == 0 {
|
||||||
return int127(r) & (n-1)
|
return int127() & (n-1)
|
||||||
}
|
}
|
||||||
max := i128((1<<127) - 1 - (1<<127)%u128(n))
|
max := i128((1<<127) - 1 - (1<<127)%u128(n))
|
||||||
v := int127(r)
|
v := int127()
|
||||||
for v > max {
|
for v > max {
|
||||||
v = int127(r)
|
v = int127()
|
||||||
}
|
}
|
||||||
return v % n
|
return v % n
|
||||||
}
|
}
|
||||||
@@ -491,7 +344,6 @@ Generates a random integer value in the range `[0, n)` using the provided random
|
|||||||
|
|
||||||
Inputs:
|
Inputs:
|
||||||
- n: The upper bound of the generated number, this value is exclusive
|
- 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:
|
Returns:
|
||||||
- val: A random integer value in the range `[0, n)`
|
- val: A random integer value in the range `[0, n)`
|
||||||
@@ -503,11 +355,7 @@ Example:
|
|||||||
import "core:fmt"
|
import "core:fmt"
|
||||||
|
|
||||||
int_max_example :: proc() {
|
int_max_example :: proc() {
|
||||||
// Using the global random number generator
|
|
||||||
fmt.println(rand.int_max(16))
|
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:
|
Possible Output:
|
||||||
@@ -517,23 +365,20 @@ Possible Output:
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
@(require_results)
|
@(require_results)
|
||||||
int_max :: proc(n: int, r: ^Rand = nil) -> (val: int) {
|
int_max :: proc(n: int) -> (val: int) {
|
||||||
if n <= 0 {
|
if n <= 0 {
|
||||||
panic("Invalid argument to int_max")
|
panic("Invalid argument to int_max")
|
||||||
}
|
}
|
||||||
when size_of(int) == 4 {
|
when size_of(int) == 4 {
|
||||||
return int(int31_max(i32(n), r))
|
return int(int31_max(i32(n)))
|
||||||
} else {
|
} 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.
|
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:
|
Returns:
|
||||||
- val: A random double floating point value in the range `[0, 1)`
|
- val: A random double floating point value in the range `[0, 1)`
|
||||||
|
|
||||||
@@ -542,11 +387,7 @@ Example:
|
|||||||
import "core:fmt"
|
import "core:fmt"
|
||||||
|
|
||||||
float64_example :: proc() {
|
float64_example :: proc() {
|
||||||
// Using the global random number generator
|
|
||||||
fmt.println(rand.float64())
|
fmt.println(rand.float64())
|
||||||
// Using local random number generator
|
|
||||||
my_rand := rand.create(1)
|
|
||||||
fmt.println(rand.float64(&my_rand))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Possible Output:
|
Possible Output:
|
||||||
@@ -555,14 +396,11 @@ Possible Output:
|
|||||||
0.511
|
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.
|
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:
|
Returns:
|
||||||
- val: A random single floating point value in the range `[0, 1)`
|
- val: A random single floating point value in the range `[0, 1)`
|
||||||
|
|
||||||
@@ -571,11 +409,7 @@ Example:
|
|||||||
import "core:fmt"
|
import "core:fmt"
|
||||||
|
|
||||||
float32_example :: proc() {
|
float32_example :: proc() {
|
||||||
// Using the global random number generator
|
|
||||||
fmt.println(rand.float32())
|
fmt.println(rand.float32())
|
||||||
// Using local random number generator
|
|
||||||
my_rand := rand.create(1)
|
|
||||||
fmt.println(rand.float32(&my_rand))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Possible Output:
|
Possible Output:
|
||||||
@@ -584,7 +418,7 @@ Possible Output:
|
|||||||
0.511
|
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.
|
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:
|
Inputs:
|
||||||
- low: The lower bounds of the value, this value is inclusive
|
- low: The lower bounds of the value, this value is inclusive
|
||||||
- high: The upper bounds of the value, this value is exclusive
|
- 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:
|
Returns:
|
||||||
- val: A random double floating point value in the range [low, high)
|
- val: A random double floating point value in the range [low, high)
|
||||||
@@ -604,11 +437,7 @@ Example:
|
|||||||
import "core:fmt"
|
import "core:fmt"
|
||||||
|
|
||||||
float64_range_example :: proc() {
|
float64_range_example :: proc() {
|
||||||
// Using the global random number generator
|
|
||||||
fmt.println(rand.float64_range(-10, 300))
|
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:
|
Possible Output:
|
||||||
@@ -617,9 +446,9 @@ Possible Output:
|
|||||||
673.130
|
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")
|
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 {
|
if val >= high {
|
||||||
val = max(low, high * (1 - math.F64_EPSILON))
|
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:
|
Inputs:
|
||||||
- low: The lower bounds of the value, this value is inclusive
|
- low: The lower bounds of the value, this value is inclusive
|
||||||
- high: The upper bounds of the value, this value is exclusive
|
- 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:
|
Returns:
|
||||||
- val: A random single floating point value in the range [low, high)
|
- val: A random single floating point value in the range [low, high)
|
||||||
@@ -644,11 +472,7 @@ Example:
|
|||||||
import "core:fmt"
|
import "core:fmt"
|
||||||
|
|
||||||
float32_range_example :: proc() {
|
float32_range_example :: proc() {
|
||||||
// Using the global random number generator
|
|
||||||
fmt.println(rand.float32_range(-10, 300))
|
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:
|
Possible Output:
|
||||||
@@ -657,9 +481,9 @@ Possible Output:
|
|||||||
673.130
|
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")
|
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 {
|
if val >= high {
|
||||||
val = max(low, high * (1 - math.F32_EPSILON))
|
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:
|
Inputs:
|
||||||
- p: The byte slice to fill
|
- p: The byte slice to fill
|
||||||
- r: The random number generator to use, or nil for the global generator
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
- n: The number of bytes generated
|
- n: The number of bytes generated
|
||||||
@@ -682,7 +505,6 @@ Example:
|
|||||||
import "core:fmt"
|
import "core:fmt"
|
||||||
|
|
||||||
read_example :: proc() {
|
read_example :: proc() {
|
||||||
// Using the global random number generator
|
|
||||||
data: [8]byte
|
data: [8]byte
|
||||||
n := rand.read(data[:])
|
n := rand.read(data[:])
|
||||||
fmt.println(n)
|
fmt.println(n)
|
||||||
@@ -696,12 +518,12 @@ Possible Output:
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
@(require_results)
|
@(require_results)
|
||||||
read :: proc(p: []byte, r: ^Rand = nil) -> (n: int) {
|
read :: proc(p: []byte) -> (n: int) {
|
||||||
pos := i8(0)
|
pos := i8(0)
|
||||||
val := i64(0)
|
val := i64(0)
|
||||||
for n = 0; n < len(p); n += 1 {
|
for n = 0; n < len(p); n += 1 {
|
||||||
if pos == 0 {
|
if pos == 0 {
|
||||||
val = int63(r)
|
val = int63()
|
||||||
pos = 7
|
pos = 7
|
||||||
}
|
}
|
||||||
p[n] = byte(val)
|
p[n] = byte(val)
|
||||||
@@ -718,7 +540,6 @@ Creates a slice of `int` filled with random values using the provided random num
|
|||||||
|
|
||||||
Inputs:
|
Inputs:
|
||||||
- n: The size of the created slice
|
- n: The size of the created slice
|
||||||
- r: The random number generator to use, or nil for the global generator
|
|
||||||
- allocator: (default: context.allocator)
|
- allocator: (default: context.allocator)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
@@ -731,16 +552,10 @@ Example:
|
|||||||
import "core:fmt"
|
import "core:fmt"
|
||||||
|
|
||||||
perm_example :: proc() -> (err: mem.Allocator_Error) {
|
perm_example :: proc() -> (err: mem.Allocator_Error) {
|
||||||
// Using the global random number generator and using the context allocator
|
|
||||||
data := rand.perm(4) or_return
|
data := rand.perm(4) or_return
|
||||||
fmt.println(data)
|
fmt.println(data)
|
||||||
defer delete(data, context.allocator)
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -751,10 +566,10 @@ Possible Output:
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
@(require_results)
|
@(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
|
m := make([]int, n, allocator) or_return
|
||||||
for i := 0; i < n; i += 1 {
|
for i := 0; i < n; i += 1 {
|
||||||
j := int_max(i+1, r)
|
j := int_max(i+1)
|
||||||
m[i] = m[j]
|
m[i] = m[j]
|
||||||
m[j] = i
|
m[j] = i
|
||||||
}
|
}
|
||||||
@@ -766,14 +581,12 @@ Randomizes the ordering of elements for the provided slice. If no generator is p
|
|||||||
|
|
||||||
Inputs:
|
Inputs:
|
||||||
- array: The slice to randomize
|
- array: The slice to randomize
|
||||||
- r: The random number generator to use, or nil for the global generator
|
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
import "core:math/rand"
|
import "core:math/rand"
|
||||||
import "core:fmt"
|
import "core:fmt"
|
||||||
|
|
||||||
shuffle_example :: proc() {
|
shuffle_example :: proc() {
|
||||||
// Using the global random number generator
|
|
||||||
data: [4]int = { 1, 2, 3, 4 }
|
data: [4]int = { 1, 2, 3, 4 }
|
||||||
fmt.println(data) // the contents are in order
|
fmt.println(data) // the contents are in order
|
||||||
rand.shuffle(data[:])
|
rand.shuffle(data[:])
|
||||||
@@ -786,14 +599,14 @@ Possible Output:
|
|||||||
[2, 4, 3, 1]
|
[2, 4, 3, 1]
|
||||||
|
|
||||||
*/
|
*/
|
||||||
shuffle :: proc(array: $T/[]$E, r: ^Rand = nil) {
|
shuffle :: proc(array: $T/[]$E) {
|
||||||
n := i64(len(array))
|
n := i64(len(array))
|
||||||
if n < 2 {
|
if n < 2 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := i64(n - 1); i > 0; i -= 1 {
|
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]
|
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:
|
Inputs:
|
||||||
- array: The slice to choose an element from
|
- array: The slice to choose an element from
|
||||||
- r: The random number generator to use, or nil for the global generator
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
- res: A random element from `array`
|
- res: A random element from `array`
|
||||||
@@ -813,7 +625,6 @@ Example:
|
|||||||
import "core:fmt"
|
import "core:fmt"
|
||||||
|
|
||||||
choice_example :: proc() {
|
choice_example :: proc() {
|
||||||
// Using the global random number generator
|
|
||||||
data: [4]int = { 1, 2, 3, 4 }
|
data: [4]int = { 1, 2, 3, 4 }
|
||||||
fmt.println(rand.choice(data[:]))
|
fmt.println(rand.choice(data[:]))
|
||||||
fmt.println(rand.choice(data[:]))
|
fmt.println(rand.choice(data[:]))
|
||||||
@@ -830,17 +641,17 @@ Possible Output:
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
@(require_results)
|
@(require_results)
|
||||||
choice :: proc(array: $T/[]$E, r: ^Rand = nil) -> (res: E) {
|
choice :: proc(array: $T/[]$E) -> (res: E) {
|
||||||
n := i64(len(array))
|
n := i64(len(array))
|
||||||
if n < 1 {
|
if n < 1 {
|
||||||
return E{}
|
return E{}
|
||||||
}
|
}
|
||||||
return array[int63_max(n, r)]
|
return array[int63_max(n)]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@(require_results)
|
@(require_results)
|
||||||
choice_enum :: proc($T: typeid, r: ^Rand = nil) -> T
|
choice_enum :: proc($T: typeid) -> T
|
||||||
where
|
where
|
||||||
intrinsics.type_is_enum(T),
|
intrinsics.type_is_enum(T),
|
||||||
size_of(T) <= 8,
|
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)) &&
|
when intrinsics.type_is_unsigned(intrinsics.type_core_type(T)) &&
|
||||||
u64(max(T)) > u64(max(i64)) {
|
u64(max(T)) > u64(max(i64)) {
|
||||||
i := uint64(r) % u64(len(T))
|
i := uint64() % u64(len(T))
|
||||||
i += u64(min(T))
|
i += u64(min(T))
|
||||||
return T(i)
|
return T(i)
|
||||||
} else {
|
} else {
|
||||||
i := int63_max(i64(len(T)), r)
|
i := int63_max(i64(len(T)))
|
||||||
i += i64(min(T))
|
i += i64(min(T))
|
||||||
return T(i)
|
return T(i)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -180,7 +180,7 @@ binary_search_by :: proc(array: $A/[]$T, key: T, f: proc(T, T) -> Ordering) -> (
|
|||||||
}
|
}
|
||||||
|
|
||||||
@(require_results)
|
@(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) {
|
if len(a) != len(b) {
|
||||||
return false
|
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)
|
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}
|
||||||
|
|||||||
@@ -476,10 +476,7 @@ select_raw :: proc "odin" (recvs: []^Raw_Chan, sends: []^Raw_Chan, send_msgs: []
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
r: ^rand.Rand = nil
|
select_idx = rand.int_max(count) if count > 0 else 0
|
||||||
|
|
||||||
|
|
||||||
select_idx = rand.int_max(count, r) if count > 0 else 0
|
|
||||||
|
|
||||||
sel := candidates[select_idx]
|
sel := candidates[select_idx]
|
||||||
if sel.is_recv {
|
if sel.is_recv {
|
||||||
|
|||||||
Regular → Executable
+72
-109
@@ -64,6 +64,7 @@ foreign kernel32 {
|
|||||||
RemoveVectoredContinueHandler :: proc(Handle: LPVOID) -> DWORD ---
|
RemoveVectoredContinueHandler :: proc(Handle: LPVOID) -> DWORD ---
|
||||||
RaiseException :: proc(dwExceptionCode, dwExceptionFlags, nNumberOfArguments: DWORD, lpArguments: ^ULONG_PTR) -> ! ---
|
RaiseException :: proc(dwExceptionCode, dwExceptionFlags, nNumberOfArguments: DWORD, lpArguments: ^ULONG_PTR) -> ! ---
|
||||||
|
|
||||||
|
SetUnhandledExceptionFilter :: proc(lpTopLevelExceptionFilter: LPTOP_LEVEL_EXCEPTION_FILTER) -> LPTOP_LEVEL_EXCEPTION_FILTER ---
|
||||||
|
|
||||||
CreateHardLinkW :: proc(lpSymlinkFileName: LPCWSTR,
|
CreateHardLinkW :: proc(lpSymlinkFileName: LPCWSTR,
|
||||||
lpTargetFileName: LPCWSTR,
|
lpTargetFileName: LPCWSTR,
|
||||||
@@ -464,6 +465,8 @@ foreign kernel32 {
|
|||||||
GetHandleInformation :: proc(hObject: HANDLE, lpdwFlags: ^DWORD) -> BOOL ---
|
GetHandleInformation :: proc(hObject: HANDLE, lpdwFlags: ^DWORD) -> BOOL ---
|
||||||
|
|
||||||
RtlCaptureStackBackTrace :: proc(FramesToSkip: ULONG, FramesToCapture: ULONG, BackTrace: [^]PVOID, BackTraceHash: PULONG) -> USHORT ---
|
RtlCaptureStackBackTrace :: proc(FramesToSkip: ULONG, FramesToCapture: ULONG, BackTrace: [^]PVOID, BackTraceHash: PULONG) -> USHORT ---
|
||||||
|
|
||||||
|
GetSystemPowerStatus :: proc(lpSystemPowerStatus: ^SYSTEM_POWER_STATUS) -> BOOL ---
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG_PROCESS :: 0x00000001
|
DEBUG_PROCESS :: 0x00000001
|
||||||
@@ -1009,31 +1012,9 @@ foreign kernel32 {
|
|||||||
HandlerRoutine :: proc "system" (dwCtrlType: DWORD) -> BOOL
|
HandlerRoutine :: proc "system" (dwCtrlType: DWORD) -> BOOL
|
||||||
PHANDLER_ROUTINE :: HandlerRoutine
|
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 {
|
DTR_Control :: enum byte {
|
||||||
Disable = 0,
|
Disable = 0,
|
||||||
Enable = 1,
|
Enable = 1,
|
||||||
@@ -1058,92 +1039,35 @@ Stop_Bits :: enum byte {
|
|||||||
Two = 2,
|
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 {
|
DCB :: struct {
|
||||||
DCBlength: DWORD, // NOTE(tetra): Must be set to size_of(DCB).
|
DCBlength: DWORD,
|
||||||
BaudRate: DWORD,
|
BaudRate: DWORD,
|
||||||
settings: u32, // NOTE(tetra): These are bitfields in the C struct.
|
using _: bit_field DWORD {
|
||||||
wReserved: WORD,
|
fBinary: bool | 1,
|
||||||
XOnLim: WORD,
|
fParity: bool | 1,
|
||||||
XOffLim: WORD,
|
fOutxCtsFlow: bool | 1,
|
||||||
ByteSize: BYTE,
|
fOutxDsrFlow: bool | 1,
|
||||||
Parity: Parity,
|
fDtrControl: DTR_Control | 2,
|
||||||
StopBits: Stop_Bits,
|
fDsrSensitivity: bool | 1,
|
||||||
XonChar: byte,
|
fTXContinueOnXoff: bool | 1,
|
||||||
XoffChar: byte,
|
fOutX: bool | 1,
|
||||||
ErrorChar: byte,
|
fInX: bool | 1,
|
||||||
EofChar: byte,
|
fErrorChar: bool | 1,
|
||||||
EvtChar: byte,
|
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,
|
wReserved1: WORD,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1153,6 +1077,19 @@ foreign kernel32 {
|
|||||||
SetCommState :: proc(handle: HANDLE, dcb: ^DCB) -> BOOL ---
|
SetCommState :: proc(handle: HANDLE, dcb: ^DCB) -> BOOL ---
|
||||||
}
|
}
|
||||||
|
|
||||||
|
COMMTIMEOUTS :: struct {
|
||||||
|
ReadIntervalTimeout: DWORD,
|
||||||
|
ReadTotalTimeoutMultiplier: DWORD,
|
||||||
|
ReadTotalTimeoutConstant: DWORD,
|
||||||
|
WriteTotalTimeoutMultiplier: DWORD,
|
||||||
|
WriteTotalTimeoutConstant: DWORD,
|
||||||
|
}
|
||||||
|
|
||||||
|
@(default_calling_convention="system")
|
||||||
|
foreign kernel32 {
|
||||||
|
GetCommTimeouts :: proc(handle: HANDLE, timeouts: ^COMMTIMEOUTS) -> BOOL ---
|
||||||
|
SetCommTimeouts :: proc(handle: HANDLE, timeouts: ^COMMTIMEOUTS) -> BOOL ---
|
||||||
|
}
|
||||||
|
|
||||||
LPFIBER_START_ROUTINE :: #type proc "system" (lpFiberParameter: LPVOID)
|
LPFIBER_START_ROUTINE :: #type proc "system" (lpFiberParameter: LPVOID)
|
||||||
|
|
||||||
@@ -1210,6 +1147,30 @@ SYSTEM_LOGICAL_PROCESSOR_INFORMATION :: struct {
|
|||||||
DummyUnion: DUMMYUNIONNAME_u,
|
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 */
|
/* Global Memory Flags */
|
||||||
GMEM_FIXED :: 0x0000
|
GMEM_FIXED :: 0x0000
|
||||||
GMEM_MOVEABLE :: 0x0002
|
GMEM_MOVEABLE :: 0x0002
|
||||||
@@ -1228,3 +1189,5 @@ GMEM_INVALID_HANDLE :: 0x8000
|
|||||||
|
|
||||||
GHND :: (GMEM_MOVEABLE | GMEM_ZEROINIT)
|
GHND :: (GMEM_MOVEABLE | GMEM_ZEROINIT)
|
||||||
GPTR :: (GMEM_FIXED | GMEM_ZEROINIT)
|
GPTR :: (GMEM_FIXED | GMEM_ZEROINIT)
|
||||||
|
|
||||||
|
LPTOP_LEVEL_EXCEPTION_FILTER :: PVECTORED_EXCEPTION_HANDLER
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ HGDIOBJ :: distinct HANDLE
|
|||||||
HBITMAP :: distinct HANDLE
|
HBITMAP :: distinct HANDLE
|
||||||
HGLOBAL :: distinct HANDLE
|
HGLOBAL :: distinct HANDLE
|
||||||
HHOOK :: distinct HANDLE
|
HHOOK :: distinct HANDLE
|
||||||
|
HWINEVENTHOOK :: distinct HANDLE
|
||||||
HKEY :: distinct HANDLE
|
HKEY :: distinct HANDLE
|
||||||
HDESK :: distinct HANDLE
|
HDESK :: distinct HANDLE
|
||||||
HFONT :: 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
|
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 {
|
CWPRETSTRUCT :: struct {
|
||||||
lResult: LRESULT,
|
lResult: LRESULT,
|
||||||
lParam: LPARAM,
|
lParam: LPARAM,
|
||||||
|
|||||||
@@ -17,6 +17,18 @@ foreign user32 {
|
|||||||
|
|
||||||
GetClassNameW :: proc(hWnd: HWND, lpClassName: LPWSTR, nMaxCount: c_int) -> c_int ---
|
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 ---
|
RegisterClassW :: proc(lpWndClass: ^WNDCLASSW) -> ATOM ---
|
||||||
RegisterClassExW :: proc(^WNDCLASSEXW) -> ATOM ---
|
RegisterClassExW :: proc(^WNDCLASSEXW) -> ATOM ---
|
||||||
UnregisterClassW :: proc(lpClassName: LPCWSTR, hInstance: HINSTANCE) -> BOOL ---
|
UnregisterClassW :: proc(lpClassName: LPCWSTR, hInstance: HINSTANCE) -> BOOL ---
|
||||||
@@ -568,3 +580,12 @@ RedrawWindowFlags :: enum UINT {
|
|||||||
RDW_FRAME = 0x0400,
|
RDW_FRAME = 0x0400,
|
||||||
RDW_NOFRAME = 0x0800,
|
RDW_NOFRAME = 0x0800,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OUTOFCONTEXT is the zero value, use {}
|
||||||
|
WinEventFlags :: bit_set[WinEventFlag; DWORD]
|
||||||
|
|
||||||
|
WinEventFlag :: enum DWORD {
|
||||||
|
SKIPOWNTHREAD = 0,
|
||||||
|
SKIPOWNPROCESS = 1,
|
||||||
|
INCONTEXT = 2,
|
||||||
|
}
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ ERROR_PIPE_BUSY : DWORD : 231
|
|||||||
|
|
||||||
E_NOTIMPL :: HRESULT(-0x7fff_bfff) // 0x8000_4001
|
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 {
|
System_Error :: enum DWORD {
|
||||||
|
|||||||
@@ -8,13 +8,22 @@ import "core:strings"
|
|||||||
import "core:sync/chan"
|
import "core:sync/chan"
|
||||||
import "core:time"
|
import "core:time"
|
||||||
|
|
||||||
Default_Test_Logger_Opts :: runtime.Logger_Options {
|
when USING_SHORT_LOGS {
|
||||||
.Level,
|
Default_Test_Logger_Opts :: runtime.Logger_Options {
|
||||||
.Terminal_Color,
|
.Level,
|
||||||
.Short_File_Path,
|
.Terminal_Color,
|
||||||
.Line,
|
.Short_File_Path,
|
||||||
.Procedure,
|
.Line,
|
||||||
.Date, .Time,
|
}
|
||||||
|
} else {
|
||||||
|
Default_Test_Logger_Opts :: runtime.Logger_Options {
|
||||||
|
.Level,
|
||||||
|
.Terminal_Color,
|
||||||
|
.Short_File_Path,
|
||||||
|
.Line,
|
||||||
|
.Procedure,
|
||||||
|
.Date, .Time,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Log_Message :: struct {
|
Log_Message :: struct {
|
||||||
|
|||||||
+31
-13
@@ -41,6 +41,8 @@ PROGRESS_WIDTH : int : #config(ODIN_TEST_PROGRESS_WIDTH, 24)
|
|||||||
SHARED_RANDOM_SEED : u64 : #config(ODIN_TEST_RANDOM_SEED, 0)
|
SHARED_RANDOM_SEED : u64 : #config(ODIN_TEST_RANDOM_SEED, 0)
|
||||||
// Set the lowest log level for this test run.
|
// Set the lowest log level for this test run.
|
||||||
LOG_LEVEL : string : #config(ODIN_TEST_LOG_LEVEL, "info")
|
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 {
|
get_log_level :: #force_inline proc() -> runtime.Logger_Level {
|
||||||
@@ -497,6 +499,7 @@ runner :: proc(internal_tests: []Internal_Test) -> bool {
|
|||||||
data.it = it
|
data.it = it
|
||||||
data.t.seed = shared_random_seed
|
data.t.seed = shared_random_seed
|
||||||
data.t.error_count = 0
|
data.t.error_count = 0
|
||||||
|
data.t._fail_now_called = false
|
||||||
|
|
||||||
thread.pool_add_task(&pool, task.allocator, run_test_task, data, run_index)
|
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)
|
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 {
|
if data.it.pkg == it.pkg && data.it.name == it.name {
|
||||||
end_t(&data.t)
|
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.",
|
"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)
|
reason, test_index, it.pkg, it.name)
|
||||||
|
|
||||||
if test_index not_in failed_test_reason_map {
|
// The order this is handled in is a little particular.
|
||||||
// We only write a new error message here if there wasn't one
|
task_data: ^Task_Data
|
||||||
// already, because the message we can provide based only on
|
find_task_data_for_stop_signal: for &data in task_data_slots {
|
||||||
// the signal won't be very useful, whereas asserts and panics
|
if data.it.pkg == it.pkg && data.it.name == it.name {
|
||||||
// will provide a user-written error message.
|
task_data = &data
|
||||||
failed_test_reason_map[test_index] = fmt.aprintf("Signal caught: %v", reason, allocator = shared_log_allocator)
|
break find_task_data_for_stop_signal
|
||||||
pkg_log.fatalf("Caught signal to stop test #%i %s.%s for: %v.", test_index, it.pkg, it.name, reason)
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
when FANCY_OUTPUT {
|
fmt.assertf(task_data != nil, "A signal (%v) was raised to stop test #%i %s.%s, but its task data is missing.",
|
||||||
bypass_progress_overwrite = true
|
reason, test_index, it.pkg, it.name)
|
||||||
signals_were_raised = true
|
|
||||||
|
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_failure_count += 1
|
||||||
total_done_count += 1
|
total_done_count += 1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ T :: struct {
|
|||||||
// tests during channel transmission.
|
// tests during channel transmission.
|
||||||
_log_allocator: runtime.Allocator,
|
_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)
|
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 != "" {
|
if msg != "" {
|
||||||
pkg_log.error("FAIL:", msg, location=loc)
|
pkg_log.error("FAIL:", msg, location=loc)
|
||||||
} else {
|
} else {
|
||||||
pkg_log.error("FAIL", location=loc)
|
pkg_log.error("FAIL", location=loc)
|
||||||
}
|
}
|
||||||
if t._fail_now != nil {
|
runtime.trap()
|
||||||
t._fail_now()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
failed :: proc(t: ^T) -> bool {
|
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 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.
|
// 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) {
|
cleanup :: proc(t: ^T, procedure: proc(rawptr), user_data: rawptr) {
|
||||||
append(&t.cleanups, Internal_Cleanup{procedure, user_data, context})
|
append(&t.cleanups, Internal_Cleanup{procedure, user_data, context})
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-1
@@ -2550,7 +2550,7 @@ gb_internal void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast *
|
|||||||
error_line("\tSuggestion: Did you want to pass the iterable value to the for statement by pointer to get addressable semantics?\n");
|
error_line("\tSuggestion: Did you want to pass the iterable value to the for statement by pointer to get addressable semantics?\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_type_map(parent_type)) {
|
if (parent_type != nullptr && is_type_map(parent_type)) {
|
||||||
error_line("\t Prefer doing 'for key, &%.*s in ...'\n", LIT(e->token.string));
|
error_line("\t Prefer doing 'for key, &%.*s in ...'\n", LIT(e->token.string));
|
||||||
} else {
|
} else {
|
||||||
error_line("\t Prefer doing 'for &%.*s in ...'\n", LIT(e->token.string));
|
error_line("\t Prefer doing 'for &%.*s in ...'\n", LIT(e->token.string));
|
||||||
@@ -3564,6 +3564,9 @@ gb_internal void check_binary_matrix(CheckerContext *c, Token const &op, Operand
|
|||||||
|
|
||||||
x->mode = Addressing_Value;
|
x->mode = Addressing_Value;
|
||||||
if (are_types_identical(xt, yt)) {
|
if (are_types_identical(xt, yt)) {
|
||||||
|
if (are_types_identical(x->type, y->type)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!is_type_named(x->type) && is_type_named(y->type)) {
|
if (!is_type_named(x->type) && is_type_named(y->type)) {
|
||||||
// prefer the named type
|
// prefer the named type
|
||||||
x->type = y->type;
|
x->type = y->type;
|
||||||
|
|||||||
+2
-1
@@ -2934,7 +2934,8 @@ int main(int arg_count, char const **arg_ptr) {
|
|||||||
// TODO(jeroen): Remove the `init_filename` param.
|
// TODO(jeroen): Remove the `init_filename` param.
|
||||||
// Let's put that on `build_context.build_paths[0]` instead.
|
// Let's put that on `build_context.build_paths[0]` instead.
|
||||||
if (parse_packages(parser, init_filename) != ParseFile_None) {
|
if (parse_packages(parser, init_filename) != ParseFile_None) {
|
||||||
return 1;
|
GB_ASSERT_MSG(any_errors(), "parse_packages failed but no error was reported.");
|
||||||
|
// We depend on the next conditional block to return 1, after printing errors.
|
||||||
}
|
}
|
||||||
|
|
||||||
if (any_errors()) {
|
if (any_errors()) {
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!DOCTYPE foozle>
|
||||||
|
<foozle>Barzle</foozle>
|
||||||
|
<부끄러운:barzle>
|
||||||
|
<name foo:bar=" birmese
|
||||||
|
kittens have
|
||||||
|
fur ">Indeed!</name>
|
||||||
|
</부끄러운:barzle>
|
||||||
@@ -20,15 +20,15 @@ test_avl :: proc(t: ^testing.T) {
|
|||||||
iter := avl.iterator(&tree, avl.Direction.Forward)
|
iter := avl.iterator(&tree, avl.Direction.Forward)
|
||||||
testing.expect(t, avl.iterator_get(&iter) == nil, "empty/iterator: first node should be nil")
|
testing.expect(t, avl.iterator_get(&iter) == nil, "empty/iterator: first node should be nil")
|
||||||
|
|
||||||
r: rand.Rand
|
r := rand.create(t.seed)
|
||||||
rand.init(&r, t.seed)
|
context.random_generator = rand.default_random_generator(&r)
|
||||||
|
|
||||||
// Test insertion.
|
// Test insertion.
|
||||||
NR_INSERTS :: 32 + 1 // Ensure at least 1 collision.
|
NR_INSERTS :: 32 + 1 // Ensure at least 1 collision.
|
||||||
inserted_map := make(map[int]^avl.Node(int))
|
inserted_map := make(map[int]^avl.Node(int))
|
||||||
defer delete(inserted_map)
|
defer delete(inserted_map)
|
||||||
for i := 0; i < NR_INSERTS; i += 1 {
|
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]
|
existing_node, in_map := inserted_map[v]
|
||||||
|
|
||||||
n, ok, _ := avl.find_or_insert(&tree, 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")
|
testing.expect(t, visited == nrEntries, "iterator/backward: visited")
|
||||||
|
|
||||||
// Test removal.
|
// Test removal.
|
||||||
rand.shuffle(inserted_values[:], &r)
|
rand.shuffle(inserted_values[:])
|
||||||
for v, i in inserted_values {
|
for v, i in inserted_values {
|
||||||
node := avl.find(&tree, v)
|
node := avl.find(&tree, v)
|
||||||
testing.expect(t, node != nil, "remove: find (pre)")
|
testing.expect(t, node != nil, "remove: find (pre)")
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ test_rbtree_integer :: proc(t: ^testing.T, $Key: typeid, $Value: typeid) {
|
|||||||
defer mem.tracking_allocator_destroy(&track)
|
defer mem.tracking_allocator_destroy(&track)
|
||||||
context.allocator = mem.tracking_allocator(&track)
|
context.allocator = mem.tracking_allocator(&track)
|
||||||
|
|
||||||
r: rand.Rand
|
r := rand.create(t.seed)
|
||||||
rand.init(&r, 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)
|
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)
|
tree: rb.Tree(Key, Value)
|
||||||
@@ -35,9 +35,9 @@ test_rbtree_integer :: proc(t: ^testing.T, $Key: typeid, $Value: typeid) {
|
|||||||
max_key := min(Key)
|
max_key := min(Key)
|
||||||
|
|
||||||
for i := 0; i < NR_INSERTS; i += 1 {
|
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)
|
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]
|
existing_node, in_map := inserted_map[k]
|
||||||
n, inserted, _ := rb.find_or_insert(&tree, k, v)
|
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")
|
testing.expect(t, visited == entry_count, "iterator/backward: visited")
|
||||||
|
|
||||||
// Test removal (and on_remove callback)
|
// Test removal (and on_remove callback)
|
||||||
rand.shuffle(inserted_keys[:], &r)
|
rand.shuffle(inserted_keys[:])
|
||||||
callback_count := entry_count
|
callback_count := entry_count
|
||||||
tree.user_data = &callback_count
|
tree.user_data = &callback_count
|
||||||
tree.on_remove = proc(key: Key, value: Value, user_data: rawptr) {
|
tree.on_remove = proc(key: Key, value: Value, user_data: rawptr) {
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ xml_test_utf8_normal :: proc(t: ^testing.T) {
|
|||||||
},
|
},
|
||||||
expected_doctype = "恥ずべきフクロウ",
|
expected_doctype = "恥ずべきフクロウ",
|
||||||
},
|
},
|
||||||
crc32 = 0xe9b62f03,
|
crc32 = 0xefa55f27,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,7 +52,7 @@ xml_test_utf8_unbox_cdata :: proc(t: ^testing.T) {
|
|||||||
},
|
},
|
||||||
expected_doctype = "恥ずべきフクロウ",
|
expected_doctype = "恥ずべきフクロウ",
|
||||||
},
|
},
|
||||||
crc32 = 0x9c2643ed,
|
crc32 = 0x2dd27770,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,7 +128,7 @@ xml_test_entities_unbox :: proc(t: ^testing.T) {
|
|||||||
},
|
},
|
||||||
expected_doctype = "html",
|
expected_doctype = "html",
|
||||||
},
|
},
|
||||||
crc32 = 0x3b6d4a90,
|
crc32 = 0x350ca83e,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,7 +142,21 @@ xml_test_entities_unbox_decode :: proc(t: ^testing.T) {
|
|||||||
},
|
},
|
||||||
expected_doctype = "html",
|
expected_doctype = "html",
|
||||||
},
|
},
|
||||||
crc32 = 0x5be2ffdc,
|
crc32 = 0x7f58db7d,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
@(test)
|
||||||
|
xml_test_attribute_whitespace :: proc(t: ^testing.T) {
|
||||||
|
run_test(t, {
|
||||||
|
// Same as above.
|
||||||
|
// Unbox CDATA in data tag.
|
||||||
|
filename = "XML/attribute-whitespace.xml",
|
||||||
|
options = {
|
||||||
|
flags = {},
|
||||||
|
expected_doctype = "foozle",
|
||||||
|
},
|
||||||
|
crc32 = 0x8f5fd6c1,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,7 +186,7 @@ xml_test_unicode :: proc(t: ^testing.T) {
|
|||||||
expected_doctype = "",
|
expected_doctype = "",
|
||||||
},
|
},
|
||||||
err = .None,
|
err = .None,
|
||||||
crc32 = 0x0b6100ab,
|
crc32 = 0x73070b55,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -258,6 +258,120 @@ test_pointers :: proc(t: ^testing.T) {
|
|||||||
check(t, "0xFFFF", "%#4p", d)
|
check(t, "0xFFFF", "%#4p", d)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(test)
|
||||||
|
test_odin_value_export :: proc(t: ^testing.T) {
|
||||||
|
E :: enum u32 {
|
||||||
|
A, B, C,
|
||||||
|
}
|
||||||
|
|
||||||
|
F :: enum i16 {
|
||||||
|
A, B, F,
|
||||||
|
}
|
||||||
|
|
||||||
|
S :: struct {
|
||||||
|
j, k: int,
|
||||||
|
}
|
||||||
|
|
||||||
|
ST :: struct {
|
||||||
|
x: int `fmt:"-"`,
|
||||||
|
y: u8 `fmt:"r,0"`,
|
||||||
|
z: string `fmt:"s,0"`,
|
||||||
|
}
|
||||||
|
|
||||||
|
U :: union {
|
||||||
|
i8,
|
||||||
|
i16,
|
||||||
|
}
|
||||||
|
|
||||||
|
UEF :: union { E, F }
|
||||||
|
|
||||||
|
A :: [2]int
|
||||||
|
|
||||||
|
BSE :: distinct bit_set[E]
|
||||||
|
|
||||||
|
i : int = 64
|
||||||
|
f : f64 = 3.14
|
||||||
|
c : complex128 = 7+3i
|
||||||
|
q : quaternion256 = 1+2i+3j+4k
|
||||||
|
mat : matrix[2,3]f32 = {1.5, 2, 1, 0.777, 0.333, 0.8}
|
||||||
|
matc : #column_major matrix[2,3]f32 = {1.5, 2, 1, 0.777, 0.333, 0.8}
|
||||||
|
e : enum {A, B, C} = .B
|
||||||
|
en : E = E.C
|
||||||
|
ena : [2]E = {E.A, E.C}
|
||||||
|
s : struct { j: int, k: int } = { j = 16, k = 8 }
|
||||||
|
sn : S = S{ j = 24, k = 12 }
|
||||||
|
st : ST = { 32768, 57, "Hellope" }
|
||||||
|
str : string = "Hellope"
|
||||||
|
strc : cstring = "Hellope"
|
||||||
|
bsu : bit_set[0..<32; u32] = {0, 1}
|
||||||
|
bs : bit_set[4..<16] = {5, 7}
|
||||||
|
bse : bit_set[E] = { .B, .A }
|
||||||
|
bsE : BSE = { .A, .C }
|
||||||
|
arr : [3]int = {1, 2, 3}
|
||||||
|
ars : [3]S = {S{j = 3, k = 2}, S{j = 2, k = 1}, S{j = 1, k = 0}}
|
||||||
|
darr : [dynamic]u8 = { 128, 64, 32 }
|
||||||
|
dars : [dynamic]S = {S{j = 1, k = 2}, S{j = 3, k = 4}}
|
||||||
|
na : A = {7, 5}
|
||||||
|
may0 : Maybe(int)
|
||||||
|
may1 : Maybe(int) = 1
|
||||||
|
uz : union {i8, i16} = i8(-33)
|
||||||
|
u0 : U = U(nil)
|
||||||
|
u1 : U = i16(42)
|
||||||
|
uef0 : UEF = E.A
|
||||||
|
uefa : [3]UEF = { E.A, F.A, F.F }
|
||||||
|
map_ : map[string]u8 = {"foo" = 8, "bar" = 4}
|
||||||
|
|
||||||
|
bf : bit_field int {
|
||||||
|
a: int | 4,
|
||||||
|
b: int | 4,
|
||||||
|
e: E | 4,
|
||||||
|
} = {a = 1, b = 2, e = .A}
|
||||||
|
|
||||||
|
defer {
|
||||||
|
delete(darr)
|
||||||
|
delete(dars)
|
||||||
|
delete(map_)
|
||||||
|
}
|
||||||
|
|
||||||
|
check(t, "64", "%w", i)
|
||||||
|
check(t, "3.14", "%w", f)
|
||||||
|
check(t, "7+3i", "%w", c)
|
||||||
|
check(t, "1+2i+3j+4k", "%w", q)
|
||||||
|
check(t, "{1.5, 2, 1, 0.777, 0.333, 0.8}", "%w", mat)
|
||||||
|
check(t, "{1.5, 2, 1, 0.777, 0.333, 0.8}", "%w", matc)
|
||||||
|
check(t, ".B", "%w", e)
|
||||||
|
check(t, "E.C", "%w", en)
|
||||||
|
check(t, "{E.A, E.C}", "%w", ena)
|
||||||
|
check(t, "{j = 16, k = 8}", "%w", s)
|
||||||
|
check(t, "S{j = 24, k = 12}", "%w", sn)
|
||||||
|
check(t, `ST{y = 57, z = "Hellope"}`, "%w", st)
|
||||||
|
check(t, `"Hellope"`, "%w", str)
|
||||||
|
check(t, `"Hellope"`, "%w", strc)
|
||||||
|
check(t, "{0, 1}", "%w", bsu)
|
||||||
|
check(t, "{5, 7}", "%w", bs)
|
||||||
|
check(t, "{E.A, E.B}", "%w", bse)
|
||||||
|
check(t, "{E.A, E.C}", "%w", bsE)
|
||||||
|
check(t, "{1, 2, 3}", "%w", arr)
|
||||||
|
check(t, "{S{j = 3, k = 2}, S{j = 2, k = 1}, S{j = 1, k = 0}}", "%w", ars)
|
||||||
|
check(t, "{128, 64, 32}", "%w", darr)
|
||||||
|
check(t, "{S{j = 1, k = 2}, S{j = 3, k = 4}}", "%w", dars)
|
||||||
|
check(t, "{7, 5}", "%w", na)
|
||||||
|
check(t, "nil", "%w", may0)
|
||||||
|
check(t, "1", "%w", may1)
|
||||||
|
check(t, "-33", "%w", uz)
|
||||||
|
check(t, "nil", "%w", u0)
|
||||||
|
check(t, "42", "%w", u1)
|
||||||
|
check(t, "E.A", "%w", uef0)
|
||||||
|
check(t, "{E.A, F.A, F.F}", "%w", uefa)
|
||||||
|
check(t, "{a = 1, b = 2, e = E.A}", "%w", bf)
|
||||||
|
// Check this manually due to the non-deterministic ordering of map keys.
|
||||||
|
switch fmt.tprintf("%w", map_) {
|
||||||
|
case `{"foo"=8, "bar"=4}`: break
|
||||||
|
case `{"bar"=4, "foo"=8}`: break
|
||||||
|
case: testing.fail(t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@(private)
|
@(private)
|
||||||
check :: proc(t: ^testing.T, exp: string, format: string, args: ..any, loc := #caller_location) {
|
check :: proc(t: ^testing.T, exp: string, format: string, args: ..any, loc := #caller_location) {
|
||||||
got := fmt.tprintf(format, ..args)
|
got := fmt.tprintf(format, ..args)
|
||||||
|
|||||||
@@ -54,8 +54,9 @@ test_xxhash_zero_streamed_random_updates :: proc(t: ^testing.T) {
|
|||||||
|
|
||||||
// XXH3_128_update
|
// XXH3_128_update
|
||||||
random_seed := rand.create(t.seed)
|
random_seed := rand.create(t.seed)
|
||||||
|
context.random_generator = rand.default_random_generator(&random_seed)
|
||||||
for len(b) > 0 {
|
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 {
|
if update_size > 4096 {
|
||||||
update_size %= 73
|
update_size %= 73
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package test_core_slice
|
|||||||
import "core:slice"
|
import "core:slice"
|
||||||
import "core:testing"
|
import "core:testing"
|
||||||
import "core:math/rand"
|
import "core:math/rand"
|
||||||
|
import "core:log"
|
||||||
|
|
||||||
@test
|
@test
|
||||||
test_sort_with_indices :: proc(t: ^testing.T) {
|
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 {
|
for test_size in test_sizes {
|
||||||
r := rand.create(t.seed)
|
r := rand.create(t.seed)
|
||||||
|
context.random_generator = rand.default_random_generator(&r)
|
||||||
|
|
||||||
vals := make([]u64, test_size)
|
vals := make([]u64, test_size)
|
||||||
r_idx := make([]int, test_size) // Reverse index
|
r_idx := make([]int, test_size) // Reverse index
|
||||||
@@ -21,7 +23,7 @@ test_sort_with_indices :: proc(t: ^testing.T) {
|
|||||||
|
|
||||||
// Set up test values
|
// Set up test values
|
||||||
for _, i in vals {
|
for _, i in vals {
|
||||||
vals[i] = rand.uint64(&r)
|
vals[i] = rand.uint64()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort
|
// Sort
|
||||||
@@ -29,7 +31,7 @@ test_sort_with_indices :: proc(t: ^testing.T) {
|
|||||||
defer delete(f_idx)
|
defer delete(f_idx)
|
||||||
|
|
||||||
// Verify sorted test values
|
// Verify sorted test values
|
||||||
rand.init(&r, t.seed)
|
rand.reset(t.seed)
|
||||||
|
|
||||||
for v, i in f_idx {
|
for v, i in f_idx {
|
||||||
r_idx[v] = i
|
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")
|
testing.expect(t, idx_pass, "Expected index to have been sorted")
|
||||||
if !idx_pass {
|
if !idx_pass {
|
||||||
break
|
break
|
||||||
@@ -62,6 +64,7 @@ test_sort_by_indices :: proc(t: ^testing.T) {
|
|||||||
|
|
||||||
for test_size in test_sizes {
|
for test_size in test_sizes {
|
||||||
r := rand.create(t.seed)
|
r := rand.create(t.seed)
|
||||||
|
context.random_generator = rand.default_random_generator(&r)
|
||||||
|
|
||||||
vals := make([]u64, test_size)
|
vals := make([]u64, test_size)
|
||||||
r_idx := make([]int, test_size) // Reverse index
|
r_idx := make([]int, test_size) // Reverse index
|
||||||
@@ -72,7 +75,7 @@ test_sort_by_indices :: proc(t: ^testing.T) {
|
|||||||
|
|
||||||
// Set up test values
|
// Set up test values
|
||||||
for _, i in vals {
|
for _, i in vals {
|
||||||
vals[i] = rand.uint64(&r)
|
vals[i] = rand.uint64()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort
|
// Sort
|
||||||
@@ -80,7 +83,7 @@ test_sort_by_indices :: proc(t: ^testing.T) {
|
|||||||
defer delete(f_idx)
|
defer delete(f_idx)
|
||||||
|
|
||||||
// Verify sorted test values
|
// Verify sorted test values
|
||||||
rand.init(&r, t.seed)
|
rand.reset(t.seed)
|
||||||
|
|
||||||
{
|
{
|
||||||
indices := make([]int, test_size)
|
indices := make([]int, test_size)
|
||||||
@@ -205,7 +208,7 @@ test_permutation_iterator :: proc(t: ^testing.T) {
|
|||||||
n += item
|
n += item
|
||||||
}
|
}
|
||||||
if n in seen {
|
if n in seen {
|
||||||
testing.fail_now(t, "Permutation iterator made a duplicate permutation.")
|
log.error("Permutation iterator made a duplicate permutation.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
seen[n] = true
|
seen[n] = true
|
||||||
|
|||||||
@@ -17,9 +17,10 @@ map_insert_random_key_value :: proc(t: ^testing.T) {
|
|||||||
|
|
||||||
unique_keys := 0
|
unique_keys := 0
|
||||||
r := rand.create(t.seed + seed_incr)
|
r := rand.create(t.seed + seed_incr)
|
||||||
|
context.random_generator = rand.default_random_generator(&r)
|
||||||
for _ in 0..<entries {
|
for _ in 0..<entries {
|
||||||
k := rand.int63(&r)
|
k := rand.int63()
|
||||||
v := rand.int63(&r)
|
v := rand.int63()
|
||||||
|
|
||||||
if k not_in m {
|
if k not_in m {
|
||||||
unique_keys += 1
|
unique_keys += 1
|
||||||
@@ -37,11 +38,12 @@ map_insert_random_key_value :: proc(t: ^testing.T) {
|
|||||||
|
|
||||||
// Reset randomizer and verify
|
// Reset randomizer and verify
|
||||||
r = rand.create(t.seed + seed_incr)
|
r = rand.create(t.seed + seed_incr)
|
||||||
|
context.random_generator = rand.default_random_generator(&r)
|
||||||
|
|
||||||
num_fails := 0
|
num_fails := 0
|
||||||
for _ in 0..<entries {
|
for _ in 0..<entries {
|
||||||
k := rand.int63(&r)
|
k := rand.int63()
|
||||||
v := rand.int63(&r)
|
v := rand.int63()
|
||||||
|
|
||||||
cond := m[k] == v
|
cond := m[k] == v
|
||||||
if !cond {
|
if !cond {
|
||||||
@@ -67,9 +69,11 @@ map_update_random_key_value :: proc(t: ^testing.T) {
|
|||||||
|
|
||||||
unique_keys := 0
|
unique_keys := 0
|
||||||
r := rand.create(t.seed + seed_incr)
|
r := rand.create(t.seed + seed_incr)
|
||||||
|
context.random_generator = rand.default_random_generator(&r)
|
||||||
|
|
||||||
for _ in 0..<entries {
|
for _ in 0..<entries {
|
||||||
k := rand.int63(&r)
|
k := rand.int63()
|
||||||
v := rand.int63(&r)
|
v := rand.int63()
|
||||||
|
|
||||||
if k not_in m {
|
if k not_in m {
|
||||||
unique_keys += 1
|
unique_keys += 1
|
||||||
@@ -89,20 +93,23 @@ map_update_random_key_value :: proc(t: ^testing.T) {
|
|||||||
|
|
||||||
// Reset randomizer and update half the entries
|
// Reset randomizer and update half the entries
|
||||||
r = rand.create(t.seed + seed_incr)
|
r = rand.create(t.seed + seed_incr)
|
||||||
|
context.random_generator = rand.default_random_generator(&r)
|
||||||
|
|
||||||
for _ in 0..<half_entries {
|
for _ in 0..<half_entries {
|
||||||
k := rand.int63(&r)
|
k := rand.int63()
|
||||||
v := rand.int63(&r)
|
v := rand.int63()
|
||||||
|
|
||||||
m[k] = v + 42
|
m[k] = v + 42
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset randomizer and verify
|
// Reset randomizer and verify
|
||||||
r = rand.create(t.seed + seed_incr)
|
r = rand.create(t.seed + seed_incr)
|
||||||
|
context.random_generator = rand.default_random_generator(&r)
|
||||||
|
|
||||||
num_fails := 0
|
num_fails := 0
|
||||||
for i in 0..<entries {
|
for i in 0..<entries {
|
||||||
k := rand.int63(&r)
|
k := rand.int63()
|
||||||
v := rand.int63(&r)
|
v := rand.int63()
|
||||||
|
|
||||||
diff := i64(42) if i < half_entries else i64(0)
|
diff := i64(42) if i < half_entries else i64(0)
|
||||||
cond := m[k] == (v + diff)
|
cond := m[k] == (v + diff)
|
||||||
@@ -129,9 +136,11 @@ map_delete_random_key_value :: proc(t: ^testing.T) {
|
|||||||
|
|
||||||
unique_keys := 0
|
unique_keys := 0
|
||||||
r := rand.create(t.seed + seed_incr)
|
r := rand.create(t.seed + seed_incr)
|
||||||
|
context.random_generator = rand.default_random_generator(&r)
|
||||||
|
|
||||||
for _ in 0..<entries {
|
for _ in 0..<entries {
|
||||||
k := rand.int63(&r)
|
k := rand.int63()
|
||||||
v := rand.int63(&r)
|
v := rand.int63()
|
||||||
|
|
||||||
if k not_in m {
|
if k not_in m {
|
||||||
unique_keys += 1
|
unique_keys += 1
|
||||||
@@ -151,20 +160,23 @@ map_delete_random_key_value :: proc(t: ^testing.T) {
|
|||||||
|
|
||||||
// Reset randomizer and delete half the entries
|
// Reset randomizer and delete half the entries
|
||||||
r = rand.create(t.seed + seed_incr)
|
r = rand.create(t.seed + seed_incr)
|
||||||
|
context.random_generator = rand.default_random_generator(&r)
|
||||||
|
|
||||||
for _ in 0..<half_entries {
|
for _ in 0..<half_entries {
|
||||||
k := rand.int63(&r)
|
k := rand.int63()
|
||||||
_ = rand.int63(&r)
|
_ = rand.int63()
|
||||||
|
|
||||||
delete_key(&m, k)
|
delete_key(&m, k)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset randomizer and verify
|
// Reset randomizer and verify
|
||||||
r = rand.create(t.seed + seed_incr)
|
r = rand.create(t.seed + seed_incr)
|
||||||
|
context.random_generator = rand.default_random_generator(&r)
|
||||||
|
|
||||||
num_fails := 0
|
num_fails := 0
|
||||||
for i in 0..<entries {
|
for i in 0..<entries {
|
||||||
k := rand.int63(&r)
|
k := rand.int63()
|
||||||
v := rand.int63(&r)
|
v := rand.int63()
|
||||||
|
|
||||||
if i < half_entries {
|
if i < half_entries {
|
||||||
if k in m {
|
if k in m {
|
||||||
@@ -207,8 +219,10 @@ set_insert_random_key_value :: proc(t: ^testing.T) {
|
|||||||
|
|
||||||
unique_keys := 0
|
unique_keys := 0
|
||||||
r := rand.create(t.seed + seed_incr)
|
r := rand.create(t.seed + seed_incr)
|
||||||
|
context.random_generator = rand.default_random_generator(&r)
|
||||||
|
|
||||||
for _ in 0..<entries {
|
for _ in 0..<entries {
|
||||||
k := rand.int63(&r)
|
k := rand.int63()
|
||||||
if k not_in m {
|
if k not_in m {
|
||||||
unique_keys += 1
|
unique_keys += 1
|
||||||
}
|
}
|
||||||
@@ -225,10 +239,11 @@ set_insert_random_key_value :: proc(t: ^testing.T) {
|
|||||||
|
|
||||||
// Reset randomizer and verify
|
// Reset randomizer and verify
|
||||||
r = rand.create(t.seed + seed_incr)
|
r = rand.create(t.seed + seed_incr)
|
||||||
|
context.random_generator = rand.default_random_generator(&r)
|
||||||
|
|
||||||
num_fails := 0
|
num_fails := 0
|
||||||
for _ in 0..<entries {
|
for _ in 0..<entries {
|
||||||
k := rand.int63(&r)
|
k := rand.int63()
|
||||||
|
|
||||||
cond := k in m
|
cond := k in m
|
||||||
if !cond {
|
if !cond {
|
||||||
@@ -254,8 +269,10 @@ set_delete_random_key_value :: proc(t: ^testing.T) {
|
|||||||
|
|
||||||
unique_keys := 0
|
unique_keys := 0
|
||||||
r := rand.create(t.seed + seed_incr)
|
r := rand.create(t.seed + seed_incr)
|
||||||
|
context.random_generator = rand.default_random_generator(&r)
|
||||||
|
|
||||||
for _ in 0..<entries {
|
for _ in 0..<entries {
|
||||||
k := rand.int63(&r)
|
k := rand.int63()
|
||||||
|
|
||||||
if k not_in m {
|
if k not_in m {
|
||||||
unique_keys += 1
|
unique_keys += 1
|
||||||
@@ -275,17 +292,20 @@ set_delete_random_key_value :: proc(t: ^testing.T) {
|
|||||||
|
|
||||||
// Reset randomizer and delete half the entries
|
// Reset randomizer and delete half the entries
|
||||||
r = rand.create(t.seed + seed_incr)
|
r = rand.create(t.seed + seed_incr)
|
||||||
|
context.random_generator = rand.default_random_generator(&r)
|
||||||
|
|
||||||
for _ in 0..<half_entries {
|
for _ in 0..<half_entries {
|
||||||
k := rand.int63(&r)
|
k := rand.int63()
|
||||||
delete_key(&m, k)
|
delete_key(&m, k)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset randomizer and verify
|
// Reset randomizer and verify
|
||||||
r = rand.create(t.seed + seed_incr)
|
r = rand.create(t.seed + seed_incr)
|
||||||
|
context.random_generator = rand.default_random_generator(&r)
|
||||||
|
|
||||||
num_fails := 0
|
num_fails := 0
|
||||||
for i in 0..<entries {
|
for i in 0..<entries {
|
||||||
k := rand.int63(&r)
|
k := rand.int63()
|
||||||
|
|
||||||
if i < half_entries {
|
if i < half_entries {
|
||||||
if k in m {
|
if k in m {
|
||||||
|
|||||||
Vendored
+1
-1
@@ -668,7 +668,7 @@ MatrixLookAt :: proc "c" (eye, target, up: Vector3) -> Matrix {
|
|||||||
// Get float array of matrix data
|
// Get float array of matrix data
|
||||||
@(require_results)
|
@(require_results)
|
||||||
MatrixToFloatV :: proc "c" (mat: Matrix) -> [16]f32 {
|
MatrixToFloatV :: proc "c" (mat: Matrix) -> [16]f32 {
|
||||||
return transmute([16]f32)mat
|
return transmute([16]f32)linalg.transpose(mat)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Vendored
-555
@@ -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
|
|
||||||
}
|
|
||||||
Vendored
+581
@@ -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
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user