mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-04 14:48:47 +00:00
Add Quaternions: quaternion128, quaternion256
This commit is contained in:
+57
-13
@@ -2,9 +2,7 @@
|
||||
|
||||
#import "os.odin";
|
||||
#import "fmt.odin";
|
||||
#import "mem.odin";
|
||||
#import "utf8.odin";
|
||||
#import "hash.odin";
|
||||
|
||||
// IMPORTANT NOTE(bill): `type_info` & `type_info_val` cannot be used within a
|
||||
// #shared_global_scope due to the internals of the compiler.
|
||||
@@ -42,6 +40,7 @@ Type_Info :: union {
|
||||
Integer{size: int, signed: bool},
|
||||
Float{size: int},
|
||||
Complex{size: int},
|
||||
Quaternion{size: int},
|
||||
String{},
|
||||
Boolean{},
|
||||
Any{},
|
||||
@@ -130,8 +129,6 @@ __trap :: proc() #foreign __llvm_core "llvm.trap";
|
||||
read_cycle_counter :: proc() -> u64 #foreign __llvm_core "llvm.readcyclecounter";
|
||||
|
||||
|
||||
|
||||
|
||||
// IMPORTANT NOTE(bill): Must be in this order (as the compiler relies upon it)
|
||||
Allocator_Mode :: enum u8 {
|
||||
ALLOC,
|
||||
@@ -231,7 +228,7 @@ default_resize_align :: proc(old_memory: rawptr, old_size, new_size, alignment:
|
||||
return nil;
|
||||
}
|
||||
|
||||
mem.copy(new_memory, old_memory, min(old_size, new_size));;
|
||||
__mem_copy(new_memory, old_memory, min(old_size, new_size));;
|
||||
free(old_memory);
|
||||
return new_memory;
|
||||
}
|
||||
@@ -290,7 +287,7 @@ __string_eq :: proc(a, b: string) -> bool {
|
||||
}
|
||||
|
||||
__string_cmp :: proc(a, b: string) -> int {
|
||||
return mem.compare(cast([]byte)a, cast([]byte)b);
|
||||
return __mem_compare(a.data, b.data, min(a.count, b.count));
|
||||
}
|
||||
|
||||
__string_ne :: proc(a, b: string) -> bool #inline { return !__string_eq(a, b); }
|
||||
@@ -300,6 +297,26 @@ __string_le :: proc(a, b: string) -> bool #inline { return __string_cmp(a, b) <=
|
||||
__string_ge :: proc(a, b: string) -> bool #inline { return __string_cmp(a, b) >= 0; }
|
||||
|
||||
|
||||
__complex64_eq :: proc(a, b: complex64) -> bool #inline { return real(a) == real(b) && imag(a) == imag(b); }
|
||||
__complex64_ne :: proc(a, b: complex64) -> bool #inline { return real(a) != real(b) || imag(a) != imag(b); }
|
||||
|
||||
__complex128_eq :: proc(a, b: complex128) -> bool #inline { return real(a) == real(b) && imag(a) == imag(b); }
|
||||
__complex128_ne :: proc(a, b: complex128) -> bool #inline { return real(a) != real(b) || imag(a) != imag(b); }
|
||||
|
||||
|
||||
__quaternion128_eq :: proc(a, b: quaternion128) -> bool #inline {
|
||||
return real(a) == real(b) && imag(a) == imag(b) && jmag(a) == jmag(b) && kmag(a) == kmag(b);
|
||||
}
|
||||
__quaternion128_ne :: proc(a, b: quaternion128) -> bool #inline {
|
||||
return real(a) != real(b) || imag(a) != imag(b) || jmag(a) != jmag(b) || kmag(a) != kmag(b);
|
||||
}
|
||||
__quaternion256_eq :: proc(a, b: quaternion256) -> bool #inline {
|
||||
return real(a) == real(b) && imag(a) == imag(b) && jmag(a) == jmag(b) && kmag(a) == kmag(b);
|
||||
}
|
||||
__quaternion256_ne :: proc(a, b: quaternion256) -> bool #inline {
|
||||
return real(a) != real(b) || imag(a) != imag(b) || jmag(a) != jmag(b) || kmag(a) != kmag(b);
|
||||
}
|
||||
|
||||
__assert :: proc(file: string, line, column: int, msg: string) #inline {
|
||||
fmt.fprintf(os.stderr, "%s(%d:%d) Runtime assertion: %s\n",
|
||||
file, line, column, msg);
|
||||
@@ -381,6 +398,26 @@ __mem_compare :: proc(a, b: ^byte, n: int) -> int {
|
||||
return 0;
|
||||
}
|
||||
|
||||
__sqrt_f32 :: proc(x: f32) -> f32 #foreign __llvm_core "llvm.sqrt.f32";
|
||||
__sqrt_f64 :: proc(x: f64) -> f64 #foreign __llvm_core "llvm.sqrt.f64";
|
||||
__abs_complex64 :: proc(x: complex64) -> f32 #inline {
|
||||
r, i := real(x), imag(x);
|
||||
return __sqrt_f32(r*r + i*i);
|
||||
}
|
||||
__abs_complex128 :: proc(x: complex128) -> f64 #inline {
|
||||
r, i := real(x), imag(x);
|
||||
return __sqrt_f64(r*r + i*i);
|
||||
}
|
||||
__abs_quaternion128 :: proc(x: quaternion128) -> f32 #inline {
|
||||
r, i, j, k := real(x), imag(x), jmag(x), kmag(x);
|
||||
return __sqrt_f32(r*r + i*i + j*j + k*k);
|
||||
}
|
||||
__abs_quaternion256 :: proc(x: quaternion256) -> f64 #inline {
|
||||
r, i, j, k := real(x), imag(x), jmag(x), kmag(x);
|
||||
return __sqrt_f64(r*r + i*i + j*j + k*k);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Raw_Any :: struct #ordered {
|
||||
type_info: ^Type_Info,
|
||||
@@ -460,7 +497,7 @@ __dynamic_array_append :: proc(array_: rawptr, elem_size, elem_align: int,
|
||||
}
|
||||
data := cast(^byte)array.data;
|
||||
assert(data != nil);
|
||||
mem.copy(data + (elem_size*array.count), items, elem_size * item_count);
|
||||
__mem_copy(data + (elem_size*array.count), items, elem_size * item_count);
|
||||
array.count += item_count;
|
||||
return array.count;
|
||||
}
|
||||
@@ -479,7 +516,7 @@ __dynamic_array_append_nothing :: proc(array_: rawptr, elem_size, elem_align: in
|
||||
}
|
||||
data := cast(^byte)array.data;
|
||||
assert(data != nil);
|
||||
mem.zero(data + (elem_size*array.count), elem_size);
|
||||
__mem_zero(data + (elem_size*array.count), elem_size);
|
||||
array.count++;
|
||||
return array.count;
|
||||
}
|
||||
@@ -496,7 +533,7 @@ __slice_append :: proc(slice_: rawptr, elem_size, elem_align: int,
|
||||
if item_count > 0 {
|
||||
data := cast(^byte)slice.data;
|
||||
assert(data != nil);
|
||||
mem.copy(data + (elem_size*slice.count), items, elem_size * item_count);
|
||||
__mem_copy(data + (elem_size*slice.count), items, elem_size * item_count);
|
||||
slice.count += item_count;
|
||||
}
|
||||
return slice.count;
|
||||
@@ -506,7 +543,14 @@ __slice_append :: proc(slice_: rawptr, elem_size, elem_align: int,
|
||||
// Map stuff
|
||||
|
||||
__default_hash :: proc(data: []byte) -> u64 {
|
||||
return hash.fnv64a(data);
|
||||
fnv64a :: proc(data: []byte) -> u64 {
|
||||
h: u64 = 0xcbf29ce484222325;
|
||||
for b in data {
|
||||
h = (h ~ cast(u64)b) * 0x100000001b3;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
return fnv64a(data);
|
||||
}
|
||||
__default_hash_string :: proc(s: string) -> u64 {
|
||||
return __default_hash(cast([]byte)s);
|
||||
@@ -577,7 +621,7 @@ __dynamic_map_rehash :: proc(using header: __Map_Header, new_count: int) {
|
||||
e := __dynamic_map_get_entry(new_header, j);
|
||||
e.next = fr.entry_index;
|
||||
ndata := cast(^byte)e;
|
||||
mem.copy(ndata+value_offset, data+value_offset, entry_size-value_offset);
|
||||
__mem_copy(ndata+value_offset, data+value_offset, entry_size-value_offset);
|
||||
if __dynamic_map_full(new_header) {
|
||||
__dynamic_map_grow(new_header);
|
||||
}
|
||||
@@ -618,7 +662,7 @@ __dynamic_map_set :: proc(using h: __Map_Header, key: __Map_Key, value: rawptr)
|
||||
{
|
||||
data := cast(^byte)__dynamic_map_get_entry(h, index);
|
||||
val := data+value_offset;
|
||||
mem.copy(val, value, entry_size-value_offset);
|
||||
__mem_copy(val, value, entry_size-value_offset);
|
||||
}
|
||||
|
||||
if __dynamic_map_full(h) {
|
||||
@@ -698,7 +742,7 @@ __dynamic_map_erase :: proc(using h: __Map_Header, fr: __Map_Find_Result) {
|
||||
if fr.entry_index == m.entries.count-1 {
|
||||
m.entries.count--;
|
||||
}
|
||||
mem.copy(__dynamic_map_get_entry(h, fr.entry_index), __dynamic_map_get_entry(h, m.entries.count-1), entry_size);
|
||||
__mem_copy(__dynamic_map_get_entry(h, fr.entry_index), __dynamic_map_get_entry(h, m.entries.count-1), entry_size);
|
||||
last := __dynamic_map_find(h, __dynamic_map_get_entry(h, fr.entry_index).key);
|
||||
if last.entry_prev >= 0 {
|
||||
__dynamic_map_get_entry(h, last.entry_prev).next = fr.entry_index;
|
||||
|
||||
+45
-10
@@ -115,6 +115,11 @@ write_type :: proc(buf: ^[]byte, ti: ^Type_Info) {
|
||||
case 8: write_string(buf, "complex64");
|
||||
case 16: write_string(buf, "complex128");
|
||||
}
|
||||
case Quaternion:
|
||||
match info.size {
|
||||
case 16: write_string(buf, "quaternion128");
|
||||
case 32: write_string(buf, "quaternion");
|
||||
}
|
||||
case String: write_string(buf, "string");
|
||||
case Boolean: write_string(buf, "bool");
|
||||
case Pointer:
|
||||
@@ -736,11 +741,12 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
|
||||
fmt_value(fi, any{info.base, v.data}, verb);
|
||||
}
|
||||
|
||||
case Boolean: fmt_arg(fi, v, verb);
|
||||
case Float: fmt_arg(fi, v, verb);
|
||||
case Complex: fmt_arg(fi, v, verb);
|
||||
case Integer: fmt_arg(fi, v, verb);
|
||||
case String: fmt_arg(fi, v, verb);
|
||||
case Boolean: fmt_arg(fi, v, verb);
|
||||
case Integer: fmt_arg(fi, v, verb);
|
||||
case Float: fmt_arg(fi, v, verb);
|
||||
case Complex: fmt_arg(fi, v, verb);
|
||||
case Quaternion: fmt_arg(fi, v, verb);
|
||||
case String: fmt_arg(fi, v, verb);
|
||||
|
||||
case Pointer:
|
||||
if v.type_info == type_info(^Type_Info) {
|
||||
@@ -907,6 +913,33 @@ fmt_complex :: proc(fi: ^Fmt_Info, c: complex128, bits: int, verb: rune) {
|
||||
}
|
||||
}
|
||||
|
||||
fmt_quaternion :: proc(fi: ^Fmt_Info, c: quaternion256, bits: int, verb: rune) {
|
||||
match verb {
|
||||
case 'f', 'F', 'v':
|
||||
r := real(c);
|
||||
i := imag(c);
|
||||
j := jmag(c);
|
||||
k := kmag(c);
|
||||
fmt_float(fi, r, bits/4, verb);
|
||||
|
||||
if !fi.plus && i >= 0 { write_rune(fi.buf, '+'); }
|
||||
fmt_float(fi, i, bits/4, verb);
|
||||
write_rune(fi.buf, 'i');
|
||||
|
||||
if !fi.plus && j >= 0 { write_rune(fi.buf, '+'); }
|
||||
fmt_float(fi, j, bits/4, verb);
|
||||
write_rune(fi.buf, 'j');
|
||||
|
||||
if !fi.plus && k >= 0 { write_rune(fi.buf, '+'); }
|
||||
fmt_float(fi, k, bits/4, verb);
|
||||
write_rune(fi.buf, 'k');
|
||||
|
||||
default:
|
||||
fmt_bad_verb(fi, verb);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
fmt_arg :: proc(fi: ^Fmt_Info, arg: any, verb: rune) {
|
||||
if arg.data == nil || arg.type_info == nil {
|
||||
write_string(fi.buf, "<nil>");
|
||||
@@ -927,11 +960,13 @@ fmt_arg :: proc(fi: ^Fmt_Info, arg: any, verb: rune) {
|
||||
base_arg := arg;
|
||||
base_arg.type_info = type_info_base(base_arg.type_info);
|
||||
match a in base_arg {
|
||||
case bool: fmt_bool(fi, a, verb);
|
||||
case f32: fmt_float(fi, cast(f64)a, 32, verb);
|
||||
case f64: fmt_float(fi, a, 64, verb);
|
||||
case complex64: fmt_complex(fi, cast(complex128)a, 64, verb);
|
||||
case complex128: fmt_complex(fi, a, 128, verb);
|
||||
case bool: fmt_bool(fi, a, verb);
|
||||
case f32: fmt_float(fi, cast(f64)a, 32, verb);
|
||||
case f64: fmt_float(fi, a, 64, verb);
|
||||
case complex64: fmt_complex(fi, cast(complex128)a, 64, verb);
|
||||
case complex128: fmt_complex(fi, a, 128, verb);
|
||||
case quaternion128: fmt_quaternion(fi, cast(quaternion256)a, 128, verb);
|
||||
case quaternion256: fmt_quaternion(fi, a, 256, verb);
|
||||
|
||||
case int: fmt_int(fi, cast(u64)a, true, 8*size_of(int), verb);
|
||||
case i8: fmt_int(fi, cast(u64)a, true, 8, verb);
|
||||
|
||||
+2
-2
@@ -43,8 +43,8 @@ pow :: proc(x, power: f64) -> f64 #foreign __llvm_core "llvm.pow.f64";
|
||||
lerp :: proc(a, b, t: f32) -> f32 { return a*(1-t) + b*t; }
|
||||
lerp :: proc(a, b, t: f64) -> f64 { return a*(1-t) + b*t; }
|
||||
|
||||
sign :: proc(x: f32) -> f32 { if x >= 0 { return +1; } return -1; }
|
||||
sign :: proc(x: f64) -> f64 { if x >= 0 { return +1; } return -1; }
|
||||
sign :: proc(x: f32) -> f32 { return x >= 0 ? +1 : -1; }
|
||||
sign :: proc(x: f64) -> f64 { return x >= 0 ? +1 : -1; }
|
||||
|
||||
bit_reverse :: proc(b: u16) -> u16 #foreign __llvm_core "llvm.bitreverse.i16";
|
||||
bit_reverse :: proc(b: u32) -> u32 #foreign __llvm_core "llvm.bitreverse.i32";
|
||||
|
||||
+42
-88
@@ -1,146 +1,100 @@
|
||||
is_signed :: proc(info: ^Type_Info) -> bool {
|
||||
if is_integer(info) {
|
||||
i := union_cast(^Type_Info.Integer)info;
|
||||
info = type_info_base(info);
|
||||
if i, ok := union_cast(^Type_Info.Integer)info; ok {
|
||||
return i.signed;
|
||||
}
|
||||
if is_float(info) {
|
||||
if _, ok := union_cast(^Type_Info.Float)info; ok {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
is_integer :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false; }
|
||||
|
||||
match i in type_info_base(info) {
|
||||
case Type_Info.Integer: return true;
|
||||
}
|
||||
return false;
|
||||
_, ok := union_cast(^Type_Info.Integer)type_info_base(info);
|
||||
return ok;
|
||||
}
|
||||
is_float :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false; }
|
||||
|
||||
match i in type_info_base(info) {
|
||||
case Type_Info.Float: return true;
|
||||
}
|
||||
return false;
|
||||
_, ok := union_cast(^Type_Info.Float)type_info_base(info);
|
||||
return ok;
|
||||
}
|
||||
is_complex :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false; }
|
||||
_, ok := union_cast(^Type_Info.Complex)type_info_base(info);
|
||||
return ok;
|
||||
}
|
||||
is_any :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false; }
|
||||
|
||||
match i in type_info_base(info) {
|
||||
case Type_Info.Any: return true;
|
||||
}
|
||||
return false;
|
||||
_, ok := union_cast(^Type_Info.Any)type_info_base(info);
|
||||
return ok;
|
||||
}
|
||||
is_string :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false; }
|
||||
|
||||
match i in type_info_base(info) {
|
||||
case Type_Info.String: return true;
|
||||
}
|
||||
return false;
|
||||
_, ok := union_cast(^Type_Info.String)type_info_base(info);
|
||||
return ok;
|
||||
}
|
||||
is_boolean :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false; }
|
||||
|
||||
match i in type_info_base(info) {
|
||||
case Type_Info.Boolean: return true;
|
||||
}
|
||||
return false;
|
||||
_, ok := union_cast(^Type_Info.Boolean)type_info_base(info);
|
||||
return ok;
|
||||
}
|
||||
is_pointer :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false; }
|
||||
|
||||
match i in type_info_base(info) {
|
||||
case Type_Info.Pointer: return true;
|
||||
}
|
||||
return false;
|
||||
_, ok := union_cast(^Type_Info.Pointer)type_info_base(info);
|
||||
return ok;
|
||||
}
|
||||
is_procedure :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false; }
|
||||
|
||||
match i in type_info_base(info) {
|
||||
case Type_Info.Procedure: return true;
|
||||
}
|
||||
return false;
|
||||
_, ok := union_cast(^Type_Info.Procedure)type_info_base(info);
|
||||
return ok;
|
||||
}
|
||||
is_array :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false; }
|
||||
|
||||
match i in type_info_base(info) {
|
||||
case Type_Info.Array: return true;
|
||||
}
|
||||
return false;
|
||||
_, ok := union_cast(^Type_Info.Array)type_info_base(info);
|
||||
return ok;
|
||||
}
|
||||
is_dynamic_array :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false; }
|
||||
|
||||
match i in type_info_base(info) {
|
||||
case Type_Info.Dynamic_Array: return true;
|
||||
}
|
||||
return false;
|
||||
_, ok := union_cast(^Type_Info.Dynamic_Array)type_info_base(info);
|
||||
return ok;
|
||||
}
|
||||
is_dynamic_map :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false; }
|
||||
|
||||
match i in type_info_base(info) {
|
||||
case Type_Info.Map: return i.count == 0;
|
||||
}
|
||||
return false;
|
||||
_, ok := union_cast(^Type_Info.Map)type_info_base(info);
|
||||
return ok;
|
||||
}
|
||||
is_slice :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false; }
|
||||
|
||||
match i in type_info_base(info) {
|
||||
case Type_Info.Slice: return true;
|
||||
}
|
||||
return false;
|
||||
_, ok := union_cast(^Type_Info.Slice)type_info_base(info);
|
||||
return ok;
|
||||
}
|
||||
is_vector :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false; }
|
||||
|
||||
match i in type_info_base(info) {
|
||||
case Type_Info.Vector: return true;
|
||||
}
|
||||
return false;
|
||||
_, ok := union_cast(^Type_Info.Vector)type_info_base(info);
|
||||
return ok;
|
||||
}
|
||||
is_tuple :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false; }
|
||||
|
||||
match i in type_info_base(info) {
|
||||
case Type_Info.Tuple: return true;
|
||||
}
|
||||
return false;
|
||||
_, ok := union_cast(^Type_Info.Tuple)type_info_base(info);
|
||||
return ok;
|
||||
}
|
||||
is_struct :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false; }
|
||||
|
||||
match i in type_info_base(info) {
|
||||
case Type_Info.Struct: return true;
|
||||
}
|
||||
return false;
|
||||
_, ok := union_cast(^Type_Info.Struct)type_info_base(info);
|
||||
return ok;
|
||||
}
|
||||
is_union :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false; }
|
||||
|
||||
match i in type_info_base(info) {
|
||||
case Type_Info.Union: return true;
|
||||
}
|
||||
return false;
|
||||
_, ok := union_cast(^Type_Info.Union)type_info_base(info);
|
||||
return ok;
|
||||
}
|
||||
is_raw_union :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false; }
|
||||
|
||||
match i in type_info_base(info) {
|
||||
case Type_Info.Raw_Union: return true;
|
||||
}
|
||||
return false;
|
||||
_, ok := union_cast(^Type_Info.Raw_Union)type_info_base(info);
|
||||
return ok;
|
||||
}
|
||||
is_enum :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false; }
|
||||
|
||||
match i in type_info_base(info) {
|
||||
case Type_Info.Enum: return true;
|
||||
}
|
||||
return false;
|
||||
_, ok := union_cast(^Type_Info.Enum)type_info_base(info);
|
||||
return ok;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user