From 77829af9de0a06b579a3791233b42f5a66421457 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 11 Sep 2020 13:46:52 +0100 Subject: [PATCH] Fix `delete("")` on `-llvm-api`; Fix linalg stuff --- core/math/linalg/extended.odin | 26 +++--- core/math/linalg/general.odin | 83 ++++++++++++++++++- core/math/linalg/specific.odin | 147 +++++++++++++++++++++++++++++++++ src/llvm_backend.cpp | 11 +++ 4 files changed, 251 insertions(+), 16 deletions(-) diff --git a/core/math/linalg/extended.odin b/core/math/linalg/extended.odin index 3010d0b4f..e9c5ef77e 100644 --- a/core/math/linalg/extended.odin +++ b/core/math/linalg/extended.odin @@ -478,44 +478,44 @@ is_inf :: proc{is_inf_single, is_inf_array}; classify :: proc{classify_single, classify_array}; -less_than_single :: proc(x, y: $T) -> (out: bool) where IS_FLOAT(T) { return x < y; } -less_than_equal_single :: proc(x, y: $T) -> (out: bool) where IS_FLOAT(T) { return x <= y; } -greater_than_single :: proc(x, y: $T) -> (out: bool) where IS_FLOAT(T) { return x > y; } -greater_than_equal_single :: proc(x, y: $T) -> (out: bool) where IS_FLOAT(T) { return x >= y; } -equal_single :: proc(x, y: $T) -> (out: bool) where IS_FLOAT(T) { return x == y; } -not_equal_single :: proc(x, y: $T) -> (out: bool) where IS_FLOAT(T) { return x != y; } +less_than_single :: proc(x, y: $T) -> (out: bool) where !IS_ARRAY(T), IS_FLOAT(T) { return x < y; } +less_than_equal_single :: proc(x, y: $T) -> (out: bool) where !IS_ARRAY(T), IS_FLOAT(T) { return x <= y; } +greater_than_single :: proc(x, y: $T) -> (out: bool) where !IS_ARRAY(T), IS_FLOAT(T) { return x > y; } +greater_than_equal_single :: proc(x, y: $T) -> (out: bool) where !IS_ARRAY(T), IS_FLOAT(T) { return x >= y; } +equal_single :: proc(x, y: $T) -> (out: bool) where !IS_ARRAY(T), IS_FLOAT(T) { return x == y; } +not_equal_single :: proc(x, y: $T) -> (out: bool) where !IS_ARRAY(T), IS_FLOAT(T) { return x != y; } -less_than_array :: proc(x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(T), IS_FLOAT(ELEM_TYPE(T)) { +less_than_array :: proc(x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) { for i in 0.. (out: [N]bool) where IS_ARRAY(T), IS_FLOAT(ELEM_TYPE(T)) { +less_than_equal_array :: proc(x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) { for i in 0.. (out: [N]bool) where IS_ARRAY(T), IS_FLOAT(ELEM_TYPE(T)) { +greater_than_array :: proc(x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) { for i in 0.. y[i]; } return; } -greater_than_equal_array :: proc(x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(T), IS_FLOAT(ELEM_TYPE(T)) { +greater_than_equal_array :: proc(x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) { for i in 0..= y[i]; } return; } -equal_array :: proc(x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(T), IS_FLOAT(ELEM_TYPE(T)) { +equal_array :: proc(x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) { for i in 0.. (out: [N]bool) where IS_ARRAY(T), IS_FLOAT(ELEM_TYPE(T)) { +not_equal_array :: proc(x, y: $A/[$N]$T) -> (out: [N]bool) where IS_ARRAY(A), IS_FLOAT(ELEM_TYPE(A)) { for i in 0.. (out: bool) { } all :: proc(x: $A/[$N]bool) -> (out: bool) { for e in x { - if !x { + if !e { return false; } } diff --git a/core/math/linalg/general.odin b/core/math/linalg/general.odin index 23679e252..2b4d43a67 100644 --- a/core/math/linalg/general.odin +++ b/core/math/linalg/general.odin @@ -37,6 +37,10 @@ DEG_PER_RAD :: 360.0/TAU; @private ELEM_TYPE :: intrinsics.type_elem_type; +scalar_dot :: proc(a, b: $T) -> T where IS_FLOAT(T), !IS_ARRAY(T) { + return a * b; +} + vector_dot :: proc(a, b: $T/[$N]$E) -> (c: E) where IS_NUMERIC(E) { for i in 0.. (c: f64) { return a.w*a.w + a.x*b.x + a.y*b.y + a.z*b.z; } -dot :: proc{vector_dot, quaternion128_dot, quaternion256_dot}; +dot :: proc{scalar_dot, vector_dot, quaternion128_dot, quaternion256_dot}; + +inner_product :: dot; +outer_product :: proc(a: $A/[$M]$E, b: $B/[$N]E) -> (out: [M][N]E) where IS_NUMERIC(E) { + for i in 0.. Q where IS_QUATERNION(Q) { return conj(q) * quaternion(1.0/dot(q, q), 0, 0, 0); } +scalar_cross :: proc(a, b: $T) -> T where IS_FLOAT(T), !IS_ARRAY(T) { + return a * b; +} + vector_cross2 :: proc(a, b: $T/[2]$E) -> E where IS_NUMERIC(E) { return a[0]*b[1] - b[0]*a[1]; } @@ -76,8 +94,8 @@ quaternion_cross :: proc(q1, q2: $Q) -> (q3: Q) where IS_QUATERNION(Q) { return; } -vector_cross :: proc{vector_cross2, vector_cross3}; -cross :: proc{vector_cross2, vector_cross3, quaternion_cross}; +vector_cross :: proc{scalar_cross, vector_cross2, vector_cross3}; +cross :: proc{scalar_cross, vector_cross2, vector_cross3, quaternion_cross}; vector_normalize :: proc(v: $T/[$N]$E) -> T where IS_NUMERIC(E) { return v / length(v); @@ -114,9 +132,26 @@ quaternion_length2 :: proc(q: $Q) -> Q where IS_QUATERNION(Q) { return dot(q, q); } +scalar_triple_product :: proc(a, b, c: $T/[$N]$E) -> E where IS_NUMERIC(E) { + // a . (b x c) + // b . (c x a) + // c . (a x b) + return dot(a, cross(b, c)); +} + +vector_triple_product :: proc(a, b, c: $T/[$N]$E) -> T where IS_NUMERIC(E) { + // a x (b x c) + // (a . c)b - (a . b)c + return cross(a, cross(b, c)); +} + + length :: proc{vector_length, quaternion_length}; length2 :: proc{vector_length2, quaternion_length2}; +projection :: proc(x, normal: $T/[$N]$E) -> T where IS_NUMERIC(E) { + return dot(x, normal) / dot(normal, normal) * normal; +} identity :: proc($T: typeid/[$N][N]$E) -> (m: T) { for i in 0.. T { + cos_alpha := dot(x, y); + alpha := math.acos(cos_alpha); + sin_alpha := math.sin(alpha); + + t1 := math.sin((1 - a) * alpha) / sin_alpha; + t2 := math.sin(a * alpha) / sin_alpha; + + return x * t1 + y * t2; +} + +catmull_rom :: proc(v1, v2, v3, v4: $T/[$N]$E, s: E) -> T { + s2 := s*s; + s3 := s2*s; + + f1 := -s3 + 2 * s2 - s; + f2 := 3 * s3 - 5 * s2 + 2; + f3 := -3 * s3 + 4 * s2 + s; + f4 := s3 - s2; + + return (f1 * v1 + f2 * v2 + f3 * v3 + f4 * v4) * 0.5; +} + +hermite :: proc(v1, t1, v2, t2: $T/[$N]$E, s: E) -> T { + s2 := s*s; + s3 := s2*s; + + f1 := 2 * s3 - 3 * s2 + 1; + f2 := -2 * s3 + 3 * s2; + f3 := s3 - 2 * s2 + s; + f4 := s3 - s2; + + return f1 * v1 + f2 * v2 + f3 * t1 + f4 * t2; +} + +cubic :: proc(v1, v2, v3, v4: $T/[$N]$E, s: E) -> T { + return ((v1 * s + v2) * s + v3) * s + v3; +} diff --git a/core/math/linalg/specific.odin b/core/math/linalg/specific.odin index 18727c889..494fc0021 100644 --- a/core/math/linalg/specific.odin +++ b/core/math/linalg/specific.odin @@ -723,3 +723,150 @@ matrix4_infinite_perspective :: proc(fovy, aspect, near: Float, flip_z_axis := t } +matrix2_from_scalar :: proc(f: Float) -> (m: Matrix2) { + m[0][0], m[0][1] = f, 0; + m[1][0], m[1][1] = 0, f; + return; +} + +matrix3_from_scalar :: proc(f: Float) -> (m: Matrix3) { + m[0][0], m[0][1], m[0][2] = f, 0, 0; + m[1][0], m[1][1], m[1][2] = 0, f, 0; + m[2][0], m[2][1], m[2][2] = 0, 0, f; + return; +} + +matrix4_from_scalar :: proc(f: Float) -> (m: Matrix4) { + m[0][0], m[0][1], m[0][2], m[0][3] = f, 0, 0, 0; + m[1][0], m[1][1], m[1][2], m[1][3] = 0, f, 0, 0; + m[2][0], m[2][1], m[2][2], m[2][3] = 0, 0, f, 0; + m[3][0], m[3][1], m[3][2], m[3][3] = 0, 0, 0, f; + return; +} + +matrix2_from_matrix3 :: proc(m: Matrix3) -> (r: Matrix2) { + r[0][0], r[0][1] = m[0][0], m[0][1]; + r[1][0], r[1][1] = m[1][0], m[1][1]; + return; +} + +matrix2_from_matrix4 :: proc(m: Matrix4) -> (r: Matrix2) { + r[0][0], r[0][1] = m[0][0], m[0][1]; + r[1][0], r[1][1] = m[1][0], m[1][1]; + return; +} + +matrix3_from_matrix2 :: proc(m: Matrix2) -> (r: Matrix3) { + r[0][0], r[0][1], r[0][2] = m[0][0], m[0][1], 0; + r[1][0], r[1][1], r[1][2] = m[1][0], m[1][1], 0; + r[2][0], r[2][1], r[2][2] = 0, 0, 1; + return; +} + +matrix3_from_matrix4 :: proc(m: Matrix4) -> (r: Matrix3) { + r[0][0], r[0][1], r[0][2] = m[0][0], m[0][1], m[0][2]; + r[1][0], r[1][1], r[1][2] = m[1][0], m[1][1], m[1][2]; + r[2][0], r[2][1], r[2][2] = m[2][0], m[2][1], m[2][2]; + return; +} + +matrix4_from_matrix2 :: proc(m: Matrix2) -> (r: Matrix4) { + r[0][0], r[0][1], r[0][2], r[0][3] = m[0][0], m[0][1], 0, 0; + r[1][0], r[1][1], r[1][2], r[1][3] = m[1][0], m[1][1], 0, 0; + r[2][0], r[2][1], r[2][2], r[2][3] = 0, 0, 1, 0; + r[3][0], r[3][1], r[3][2], r[3][3] = 0, 0, 0, 1; + return; +} +matrix4_from_matrix3 :: proc(m: Matrix3) -> (r: Matrix4) { + r[0][0], r[0][1], r[0][2], r[0][3] = m[0][0], m[0][1], m[0][2], 0; + r[1][0], r[1][1], r[1][2], r[1][3] = m[1][0], m[1][1], m[1][2], 0; + r[2][0], r[2][1], r[2][2], r[2][3] = m[2][0], m[2][1], m[2][2], 0; + r[3][0], r[3][1], r[3][2], r[3][3] = 0, 0, 0, 1; + return; +} + +quaternion_from_scalar :: proc(f: Float) -> (q: Quaternion) { + q.w = f; + return; +} + +to_matrix2 :: proc{matrix2_from_scalar, matrix2_from_matrix3, matrix2_from_matrix4}; +to_matrix3 :: proc{matrix3_from_scalar, matrix3_from_matrix2, matrix3_from_matrix4, matrix3_from_quaternion}; +to_matrix4 :: proc{matrix4_from_scalar, matrix4_from_matrix2, matrix4_from_matrix3, matrix4_from_quaternion}; +to_quaternion :: proc{quaternion_from_scalar, quaternion_from_matrix3, quaternion_from_matrix4}; + + + +matrix2_orthonormalize :: proc(m: Matrix2) -> (r: Matrix2) { + r[0] = normalize(m[0]); + + d0 := dot(r[0], r[1]); + r[1] -= r[0] * d0; + r[1] = normalize(r[1]); + + return; +} + +matrix3_orthonormalize :: proc(m: Matrix3) -> (r: Matrix3) { + r[0] = normalize(m[0]); + + d0 := dot(r[0], r[1]); + r[1] -= r[0] * d0; + r[1] = normalize(r[1]); + + d1 := dot(r[1], r[2]); + d0 = dot(r[0], r[2]); + r[2] -= r[0]*d0 + r[1]*d1; + r[2] = normalize(r[2]); + + return; +} + +vector3_orthonormalize :: proc(x, y: Vector3) -> (z: Vector3) { + return normalize(x - y * dot(y, x)); +} + + +orthonormalize :: proc{ + matrix2_orthonormalize, + matrix3_orthonormalize, + vector3_orthonormalize, +}; + + +matrix4_orientation :: proc(normal, up: Vector3) -> Matrix4 { + if all(equal(normal, up)) { + return MATRIX4_IDENTITY; + } + + rotation_axis := cross(up, normal); + angle := math.acos(dot(normal, up)); + + return matrix4_rotate(angle, rotation_axis); +} + + + +euclidean_from_polar :: proc(polar: Vector2) -> Vector3 { + latitude, longitude := polar.x, polar.y; + cx, sx := math.cos(latitude), math.sin(latitude); + cy, sy := math.cos(longitude), math.sin(longitude); + + return Vector3{ + cx*sy, + sx, + cx*cy, + }; +} +polar_from_euclidean :: proc(euclidean: Vector3) -> Vector3 { + n := length(euclidean); + tmp := euclidean / n; + + xz_dist := math.sqrt(tmp.x*tmp.x + tmp.z*tmp.z); + + return Vector3{ + math.asin(tmp.y), + math.atan2(tmp.x, tmp.z), + xz_dist, + }; +} diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 706de7d6c..f9807aea9 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -4558,6 +4558,10 @@ lbValue lb_emit_clamp(lbProcedure *p, Type *t, lbValue x, lbValue min, lbValue m LLVMValueRef lb_find_or_add_entity_string_ptr(lbModule *m, String const &str) { + if (str.len == 0) { + return LLVMConstNull(lb_type(m, t_u8_ptr)); + } + StringHashKey key = string_hash_string(str); LLVMValueRef *found = string_map_get(&m->const_strings, key); if (found != nullptr) { @@ -4587,6 +4591,9 @@ LLVMValueRef lb_find_or_add_entity_string_ptr(lbModule *m, String const &str) { } lbValue lb_find_or_add_entity_string(lbModule *m, String const &str) { + if (str.len == 0) { + return lb_zero(m, t_string); + } LLVMValueRef ptr = lb_find_or_add_entity_string_ptr(m, str); LLVMValueRef str_len = LLVMConstInt(lb_type(m, t_int), str.len, true); LLVMValueRef values[2] = {ptr, str_len}; @@ -4598,6 +4605,10 @@ lbValue lb_find_or_add_entity_string(lbModule *m, String const &str) { } lbValue lb_find_or_add_entity_string_byte_slice(lbModule *m, String const &str) { + if (str.len == 0) { + return lb_zero(m, t_u8_slice); + } + LLVMValueRef indices[2] = {llvm_zero(m), llvm_zero(m)}; LLVMValueRef data = LLVMConstStringInContext(m->ctx, cast(char const *)str.text,