diff --git a/runtime/bindings-generator.cs b/runtime/bindings-generator.cs index 6fdde04a0d..eddf70282c 100644 --- a/runtime/bindings-generator.cs +++ b/runtime/bindings-generator.cs @@ -1991,6 +1991,26 @@ namespace Xamarin.BindingMethods.Generator } ); + data.Add ( + new FunctionData { + Comment = " // void func (MatrixFloat2x2)", + Prefix = "simd__", + Variants = Variants.NonStret, + Parameters = new ParameterData [] { + new ParameterData { TypeData = Types.MatrixFloat2x2 }, + }, + } + ); + + data.Add ( + new FunctionData { + Comment = " // MatrixFloat2x2 func ()", + Prefix = "simd__", + Variants = Variants.All, + ReturnType = Types.MatrixFloat2x2, + } + ); + data.Add ( new FunctionData { Comment = " // IntPtr func (IntPtr, ref MPSImageHistogramInfo)", @@ -2004,6 +2024,42 @@ namespace Xamarin.BindingMethods.Generator } ); + data.Add ( + new FunctionData { + Comment = " // IntPtr func (IntPtr, MatrixFloat2x2)", + Prefix = "simd__", + Variants = Variants.NonStret, + ReturnType = Types.IntPtr, + Parameters = new ParameterData [] { + new ParameterData { TypeData = Types.IntPtr }, + new ParameterData { TypeData = Types.MatrixFloat2x2 }, + }, + } + ); + + data.Add ( + new FunctionData { + Comment = " // void func (MatrixFloat3x3)", + Prefix = "simd__", + Variants = Variants.NonStret, + Parameters = new ParameterData [] { + new ParameterData { TypeData = Types.MatrixFloat3x3 }, + }, + } + ); + + data.Add ( + new FunctionData { + Comment = " // IntPtr func (MatrixFloat3x3)", + Prefix = "simd__", + Variants = Variants.NonStret, + ReturnType = Types.IntPtr, + Parameters = new ParameterData [] { + new ParameterData { TypeData = Types.MatrixFloat3x3 }, + }, + } + ); + data.Add ( new FunctionData { Comment = " // MDLVoxelIndexExtent2 func ()", @@ -2013,6 +2069,15 @@ namespace Xamarin.BindingMethods.Generator } ); + data.Add ( + new FunctionData { + Comment = " // MatrixFloat3x3 func ()", + Prefix = "simd__", + Variants = Variants.All, + ReturnType = Types.MatrixFloat3x3, + } + ); + data.Add ( new FunctionData { Comment = " // void func (MDLVoxelIndexExtent2)", @@ -2020,6 +2085,67 @@ namespace Xamarin.BindingMethods.Generator Variants = Variants.NonStret, Parameters = new ParameterData [] { new ParameterData { TypeData = Types.MDLVoxelIndexExtent2 }, + } + } + ); + + data.Add ( + new FunctionData { + Comment = " // IntPtr func (IntPtr, MatrixFloat3x3)", + Prefix = "simd__", + Variants = Variants.NonStret, + ReturnType = Types.IntPtr, + Parameters = new ParameterData [] { + new ParameterData { TypeData = Types.IntPtr }, + new ParameterData { TypeData = Types.MatrixFloat3x3 }, + }, + } + ); + + data.Add ( + new FunctionData { + Comment = " // void func (MatrixFloat4x4)", + Prefix = "simd__", + Variants = Variants.NonStret, + Parameters = new ParameterData[] { + new ParameterData { TypeData = Types.MatrixFloat4x4 }, + }, + } + ); + + data.Add ( + new FunctionData { + Comment = " // IntPtr func (MatrixFloat4x4)", + Prefix = "simd__", + Variants = Variants.NonStret, + ReturnType = Types.IntPtr, + Parameters = new ParameterData[] { + new ParameterData { TypeData = Types.MatrixFloat4x4 }, + }, + } + ); + + data.Add ( + new FunctionData { + Comment = " // void func (MatrixFloat4x4, double)", + Prefix = "simd__", + Variants = Variants.NonStret, + Parameters = new ParameterData [] { + new ParameterData { TypeData = Types.MatrixFloat4x4 }, + new ParameterData { TypeData = Types.Double }, + }, + } + ); + + data.Add ( + new FunctionData { + Comment = " // IntPtr func (MatrixFloat4x4, bool)", + Prefix = "simd__", + Variants = Variants.NonStret, + ReturnType = Types.IntPtr, + Parameters = new ParameterData [] { + new ParameterData { TypeData = Types.MatrixFloat4x4 }, + new ParameterData { TypeData = Types.Bool }, }, } ); @@ -2036,6 +2162,111 @@ namespace Xamarin.BindingMethods.Generator } ); + + data.Add ( + new FunctionData { + Comment = " // IntPtr func (IntPtr, nuint, MatrixFloat4x4)", + Prefix = "simd__", + Variants = Variants.NonStret, + ReturnType = Types.IntPtr, + Parameters = new ParameterData [] { + new ParameterData { TypeData = Types.IntPtr }, + new ParameterData { TypeData = Types.NUInt }, + new ParameterData { TypeData = Types.MatrixFloat4x4 }, + }, + } + ); + + data.Add ( + new FunctionData { + Comment = " // MatrixFloat4x4 func ()", + Prefix = "simd__", + Variants = Variants.All, + ReturnType = Types.MatrixFloat4x4, + } + ); + + data.Add ( + new FunctionData { + Comment = " // MatrixFloat4x4 func (int, CGSize, nfloat, nfloat)", + Prefix = "simd__", + Variants = Variants.All, + ReturnType = Types.MatrixFloat4x4, + Parameters = new ParameterData [] { + new ParameterData { TypeData = Types.Int32 }, + new ParameterData { TypeData = Types.CGSize }, + new ParameterData { TypeData = Types.NFloat }, + new ParameterData { TypeData = Types.NFloat }, + }, + } + ); + + data.Add ( + new FunctionData { + Comment = " // MatrixFloat4x4 func (Int64, CGSize, nfloat, nfloat)", + Prefix = "simd__", + Variants = Variants.All, + ReturnType = Types.MatrixFloat4x4, + Parameters = new ParameterData [] { + new ParameterData { TypeData = Types.Int64 }, + new ParameterData { TypeData = Types.CGSize }, + new ParameterData { TypeData = Types.NFloat }, + new ParameterData { TypeData = Types.NFloat }, + }, + } + ); + + data.Add ( + new FunctionData { + Comment = " // MatrixFloat4x4 func (double)", + Prefix = "simd__", + Variants = Variants.All, + ReturnType = Types.MatrixFloat4x4, + Parameters = new ParameterData [] { + new ParameterData { TypeData = Types.Double }, + }, + } + ); + + data.Add ( + new FunctionData { + Comment = " // MatrixFloat4x4 func (nint)", + Prefix = "simd__", + Variants = Variants.All, + ReturnType = Types.MatrixFloat4x4, + Parameters = new ParameterData [] { + new ParameterData { TypeData = Types.NInt }, + }, + } + ); + + data.Add ( + new FunctionData { + Comment = " // IntPtr func (IntPtr, nint, MatrixFloat4x4)", + Prefix = "simd__", + Variants = Variants.NonStret, + ReturnType = Types.IntPtr, + Parameters = new ParameterData [] { + new ParameterData { TypeData = Types.IntPtr }, + new ParameterData { TypeData = Types.NInt }, + new ParameterData { TypeData = Types.MatrixFloat4x4 }, + }, + } + ); + + data.Add ( + new FunctionData { + Comment = " // IntPtr func (IntPtr, MatrixFloat4x4)", + Prefix = "simd__", + Variants = Variants.NonStret, + ReturnType = Types.IntPtr, + Parameters = new ParameterData [] { + new ParameterData { TypeData = Types.IntPtr }, + new ParameterData { TypeData = Types.MatrixFloat4x4 }, + }, + } + ); + // We must expand functions with native types to their actual type as well. for (int i = data.Count - 1; i >= 0; i--) { if (!data [i].HasNativeType) @@ -2087,12 +2318,14 @@ namespace Xamarin.BindingMethods.Generator } break; case "Matrix2": + case "MatrixFloat2x2": writer.WriteLine ("\tfor (int i = 0; i < 2; i++) {"); writer.WriteLine ("\t\t{0}{2}columns [i].a = {1}.columns [i] [0];", managedVariable, nativeVariable, accessor); writer.WriteLine ("\t\t{0}{2}columns [i].b = {1}.columns [i] [1];", managedVariable, nativeVariable, accessor); writer.WriteLine ("\t}"); break; case "Matrix3": + case "MatrixFloat3x3": writer.WriteLine ("\tfor (int i = 0; i < 3; i++) {"); writer.WriteLine ("\t\t{0}{2}columns [i].a = {1}.columns [i] [0];", managedVariable, nativeVariable, accessor); writer.WriteLine ("\t\t{0}{2}columns [i].b = {1}.columns [i] [1];", managedVariable, nativeVariable, accessor); @@ -2100,6 +2333,7 @@ namespace Xamarin.BindingMethods.Generator writer.WriteLine ("\t}"); break; case "Matrix4": + case "MatrixFloat4x4": writer.WriteLine ("\tfor (int i = 0; i < 4; i++) {"); writer.WriteLine ("\t\t{0}{2}columns [i].a = {1}.columns [i] [0];", managedVariable, nativeVariable, accessor); writer.WriteLine ("\t\t{0}{2}columns [i].b = {1}.columns [i] [1];", managedVariable, nativeVariable, accessor); @@ -2203,12 +2437,14 @@ namespace Xamarin.BindingMethods.Generator } break; case "Matrix2": + case "MatrixFloat2x2": writer.WriteLine ("\tfor (int i = 0; i < 2; i++) {"); writer.WriteLine ("\t\t{0}.columns [i][0] = {1}{2}columns [i].a;", nativeVariable, managedVariable, accessor); writer.WriteLine ("\t\t{0}.columns [i][1] = {1}{2}columns [i].b;", nativeVariable, managedVariable, accessor); writer.WriteLine ("\t}"); break; case "Matrix3": + case "MatrixFloat3x3": writer.WriteLine ("\tfor (int i = 0; i < 3; i++) {"); writer.WriteLine ("\t\t{0}.columns [i][0] = {1}{2}columns [i].a;", nativeVariable, managedVariable, accessor); writer.WriteLine ("\t\t{0}.columns [i][1] = {1}{2}columns [i].b;", nativeVariable, managedVariable, accessor); @@ -2216,6 +2452,7 @@ namespace Xamarin.BindingMethods.Generator writer.WriteLine ("\t}"); break; case "Matrix4": + case "MatrixFloat4x4": writer.WriteLine ("\tfor (int i = 0; i < 4; i++) {"); writer.WriteLine ("\t\t{0}.columns [i][0] = {1}{2}columns [i].a;", nativeVariable, managedVariable, accessor); writer.WriteLine ("\t\t{0}.columns [i][1] = {1}{2}columns [i].b;", nativeVariable, managedVariable, accessor); @@ -2736,6 +2973,15 @@ namespace Xamarin.BindingMethods.Generator IsX86Stret = true, IsX64Stret = false, }; + public static TypeData MatrixFloat2x2 = new TypeData { + ManagedType = "MatrixFloat2x2", + NativeType = "matrix_float2x2", + NativeWrapperType = "struct MatrixFloat2x2", + RequireMarshal = true, + IsARMStret = true, + IsX86Stret = true, + IsX64Stret = false, + }; public static TypeData Matrix3f = new TypeData { ManagedType = "Matrix3", NativeType = "matrix_float3x3", @@ -2745,6 +2991,15 @@ namespace Xamarin.BindingMethods.Generator IsX86Stret = true, IsX64Stret = true, }; + public static TypeData MatrixFloat3x3 = new TypeData { + ManagedType = "MatrixFloat3x3", + NativeType = "matrix_float3x3", + NativeWrapperType = "struct MatrixFloat3x3", + RequireMarshal = true, + IsARMStret = true, + IsX86Stret = true, + IsX64Stret = true, + }; public static TypeData Matrix4f = new TypeData { ManagedType = "Matrix4", NativeType = "matrix_float4x4", @@ -2754,6 +3009,15 @@ namespace Xamarin.BindingMethods.Generator IsX86Stret = true, IsX64Stret = true, }; + public static TypeData MatrixFloat4x4 = new TypeData { + ManagedType = "MatrixFloat4x4", + NativeType = "matrix_float4x4", + NativeWrapperType = "struct MatrixFloat4x4", + RequireMarshal = true, + IsARMStret = true, + IsX86Stret = true, + IsX64Stret = true, + }; public static TypeData Double = new TypeData { ManagedType = "Double", NativeType = "double", diff --git a/runtime/bindings.h b/runtime/bindings.h index a6715b94ec..a8ed445c3e 100644 --- a/runtime/bindings.h +++ b/runtime/bindings.h @@ -158,14 +158,26 @@ struct Matrix2f { Vector2f columns [2]; }; +struct MatrixFloat2x2 { + Vector2f columns [2]; +}; + struct Matrix3f { Vector3f columns [3]; }; +struct MatrixFloat3x3 { + Vector4f columns [3]; +}; + struct Matrix4f { Vector4f columns [4]; }; +struct MatrixFloat4x4 { + Vector4f columns [4]; +}; + struct QuatF { Vector4f vector; }; diff --git a/src/ModelIO/MDLTransform.cs b/src/ModelIO/MDLTransform.cs new file mode 100644 index 0000000000..54d944b426 --- /dev/null +++ b/src/ModelIO/MDLTransform.cs @@ -0,0 +1,16 @@ +#if XAMCORE_2_0 || !MONOMAC +using System; +using Simd; + +namespace XamCore.ModelIO { + public partial class MDLTransform { +#if !XAMCORE_4_0 + // Inlined from the MDLTransformComponent protocol. + public static MatrixFloat4x4 CreateGlobalTransform4x4 (MDLObject obj, double atTime) + { + return MatrixFloat4x4.Transpose ((MatrixFloat4x4) CreateGlobalTransform (obj, atTime)); + } +#endif + } +} +#endif \ No newline at end of file diff --git a/src/ModelIO/MDLTransformComponent.cs b/src/ModelIO/MDLTransformComponent.cs new file mode 100644 index 0000000000..bd6d14bcf1 --- /dev/null +++ b/src/ModelIO/MDLTransformComponent.cs @@ -0,0 +1,33 @@ +#if XAMCORE_2_0 && !XAMCORE_4_0 +using OpenTK; +using Simd; + +namespace XamCore.ModelIO { + public partial class MDLTransformComponent_Extensions { + public static MatrixFloat4x4 GetMatrix4x4 (this IMDLTransformComponent self) + { + return MatrixFloat4x4.Transpose ((MatrixFloat4x4) self.Matrix); + } + + public static void SetMatrix4x4 (this IMDLTransformComponent self, MatrixFloat4x4 value) + { + self.Matrix = (Matrix4) MatrixFloat4x4.Transpose (value); + } + + public static MatrixFloat4x4 GetLocalTransform4x4(this IMDLTransformComponent This, double time) + { + return MatrixFloat4x4.Transpose ((MatrixFloat4x4) GetLocalTransform (This, time)); + } + + public static void SetLocalTransform4x4 (this IMDLTransformComponent This, MatrixFloat4x4 transform, double time) + { + SetLocalTransform (This, (Matrix4) MatrixFloat4x4.Transpose (transform), time); + } + + public static void SetLocalTransform4x4 (this IMDLTransformComponent This, MatrixFloat4x4 transform) + { + SetLocalTransform (This, (Matrix4) MatrixFloat4x4.Transpose (transform)); + } + } +} +#endif \ No newline at end of file diff --git a/src/Simd/MatrixFloat2x2.cs b/src/Simd/MatrixFloat2x2.cs new file mode 100644 index 0000000000..1057118d1e --- /dev/null +++ b/src/Simd/MatrixFloat2x2.cs @@ -0,0 +1,146 @@ +// +// Authors: +// Rolf Bjarne Kvinge +// +// Copyright (c) 2017 Microsoft Inc +// + +// +// This represents the native matrix_float2x2 type, which has a column-major layout +// (as opposed to OpenTK.Matrix2, which has a row-major layout). +// + +using System; +using System.Runtime.InteropServices; + +using VectorFloat2=global::OpenTK.Vector2; + +namespace Simd +{ + [StructLayout (LayoutKind.Sequential)] + public struct MatrixFloat2x2 : IEquatable + { + public float M11; + public float M21; + public float M12; + public float M22; + + public readonly static MatrixFloat2x2 Identity = new MatrixFloat2x2 ( + 1, 0, + 0, 1); + + public MatrixFloat2x2 (VectorFloat2 column0, VectorFloat2 column1) + { + M11 = column0.X; + M21 = column0.Y; + M12 = column1.X; + M22 = column1.Y; + } + + public MatrixFloat2x2 ( + float m11, float m12, + float m21, float m22) + { + M11 = m11; + M21 = m21; + M12 = m12; + M22 = m22; + } + + public float Determinant { + get { + return M11 * M22 - M21 * M12; + } + } + + public void Transpose () + { + this = Transpose (this); + } + + public static MatrixFloat2x2 Transpose (MatrixFloat2x2 mat) + { + return new MatrixFloat2x2 (mat.M11, mat.M21, mat.M12, mat.M22); + } + + public static void Transpose (ref MatrixFloat2x2 mat, out MatrixFloat2x2 result) + { + result.M11 = mat.M11; + result.M12 = mat.M21; + result.M21 = mat.M12; + result.M22 = mat.M22; + } + + public static MatrixFloat2x2 Multiply (MatrixFloat2x2 left, MatrixFloat2x2 right) + { + MatrixFloat2x2 result; + Multiply (ref left, ref right, out result); + return result; + } + + public static void Multiply (ref MatrixFloat2x2 left, ref MatrixFloat2x2 right, out MatrixFloat2x2 result) + { + result.M11 = left.M11 * right.M11 + left.M12 * right.M21; + result.M12 = left.M11 * right.M12 + left.M12 * right.M22; + + result.M21 = left.M21 * right.M11 + left.M22 * right.M21; + result.M22 = left.M21 * right.M12 + left.M22 * right.M22; + } + + public static MatrixFloat2x2 operator * (MatrixFloat2x2 left, MatrixFloat2x2 right) + { + return Multiply (left, right); + } + + public static bool operator == (MatrixFloat2x2 left, MatrixFloat2x2 right) + { + return left.Equals (right); + } + + public static bool operator != (MatrixFloat2x2 left, MatrixFloat2x2 right) + { + return !left.Equals (right); + } + + public static explicit operator global::OpenTK.Matrix2 (MatrixFloat2x2 value) + { + return new global::OpenTK.Matrix2 ( + value.M11, value.M12, + value.M21, value.M22); + } + + public static explicit operator MatrixFloat2x2 (global::OpenTK.Matrix2 value) + { + return new MatrixFloat2x2 ( + value.R0C0, value.R0C1, + value.R1C0, value.R1C1); + } + + public override string ToString () + { + return $"({M11}, {M12})\n({M21}, {M22})"; + } + + public override int GetHashCode () + { + return M11.GetHashCode () ^ M12.GetHashCode () ^ M21.GetHashCode () ^ M22.GetHashCode (); + } + + public override bool Equals (object obj) + { + if (!(obj is MatrixFloat2x2)) + return false; + + return Equals ((MatrixFloat2x2) obj); + } + + public bool Equals (MatrixFloat2x2 other) + { + return + M11 == other.M11 && + M12 == other.M12 && + M21 == other.M21 && + M22 == other.M22; + } + } +} diff --git a/src/Simd/MatrixFloat3x3.cs b/src/Simd/MatrixFloat3x3.cs new file mode 100644 index 0000000000..74739b8439 --- /dev/null +++ b/src/Simd/MatrixFloat3x3.cs @@ -0,0 +1,207 @@ +// +// Authors: +// Rolf Bjarne Kvinge +// +// Copyright (c) 2017 Microsoft Inc +// + +// +// This represents the native matrix_float3x3 type, which has a column-major layout +// (as opposed to OpenTK.Matrix3, which has a row-major layout). +// + +using System; +using System.Runtime.InteropServices; + +using VectorFloat3=global::OpenTK.Vector3; + +namespace Simd +{ + [StructLayout (LayoutKind.Sequential)] + public struct MatrixFloat3x3 : IEquatable + { + /* Due to memory alignment, vectors of length 3 are + * represented as vectors of length 4, so we pad here + * with dummy fields. + * See top of /usr/include/simd/matrix_types.h for more information. */ + public float M11; + public float M21; + public float M31; + float dummy0; + public float M12; + public float M22; + public float M32; + float dummy1; + public float M13; + public float M23; + public float M33; + float dummy2; + + public readonly static MatrixFloat3x3 Identity = new MatrixFloat3x3 + { + M11 = 1f, + M22 = 1f, + M33 = 1f, + }; + + public MatrixFloat3x3 (VectorFloat3 column0, VectorFloat3 column1, VectorFloat3 column2) + { + M11 = column0.X; + M21 = column0.Y; + M31 = column0.Z; + M12 = column1.X; + M22 = column1.Y; + M32 = column1.Z; + M13 = column2.X; + M23 = column2.Y; + M33 = column2.Z; + dummy0 = 0; + dummy1 = 0; + dummy2 = 0; + } + + public MatrixFloat3x3 ( + float m11, float m12, float m13, + float m21, float m22, float m23, + float m31, float m32, float m33) + { + M11 = m11; + M21 = m21; + M31 = m31; + M12 = m12; + M22 = m22; + M32 = m32; + M13 = m13; + M23 = m23; + M33 = m33; + dummy0 = 0; + dummy1 = 0; + dummy2 = 0; + } + + public float Determinant { + get { + return + M11 * (M22 * M33 - M23 * M32) - + M12 * (M21 * M33 - M23 * M31) + + M13 * (M21 * M32 - M22 * M31); + } + } + + public void Transpose () + { + this = Transpose (this); + } + + public static MatrixFloat3x3 Transpose (MatrixFloat3x3 mat) + { + MatrixFloat3x3 result = new MatrixFloat3x3 (); + Transpose (ref mat, out result); + return result; + } + + public static void Transpose (ref MatrixFloat3x3 mat, out MatrixFloat3x3 result) + { + result.M11 = mat.M11; + result.M21 = mat.M12; + result.M31 = mat.M13; + result.M12 = mat.M21; + result.M22 = mat.M22; + result.M32 = mat.M23; + result.M13 = mat.M31; + result.M23 = mat.M32; + result.M33 = mat.M33; + result.dummy0 = 0; + result.dummy1 = 0; + result.dummy2 = 0; + } + + public static MatrixFloat3x3 Multiply (MatrixFloat3x3 left, MatrixFloat3x3 right) + { + MatrixFloat3x3 result; + Multiply (ref left, ref right, out result); + return result; + } + + public static void Multiply (ref MatrixFloat3x3 left, ref MatrixFloat3x3 right, out MatrixFloat3x3 result) + { + result.M11 = left.M11 * right.M11 + left.M12 * right.M21 + left.M13 * right.M31; + result.M12 = left.M11 * right.M12 + left.M12 * right.M22 + left.M13 * right.M32; + result.M13 = left.M11 * right.M13 + left.M12 * right.M23 + left.M13 * right.M33; + result.dummy0 = 0; + + result.M21 = left.M21 * right.M11 + left.M22 * right.M21 + left.M23 * right.M31; + result.M22 = left.M21 * right.M12 + left.M22 * right.M22 + left.M23 * right.M32; + result.M23 = left.M21 * right.M13 + left.M22 * right.M23 + left.M23 * right.M33; + result.dummy1 = 0; + + result.M31 = left.M31 * right.M11 + left.M32 * right.M21 + left.M33 * right.M31; + result.M32 = left.M31 * right.M12 + left.M32 * right.M22 + left.M33 * right.M32; + result.M33 = left.M31 * right.M13 + left.M32 * right.M23 + left.M33 * right.M33; + result.dummy2 = 0; + } + + public static MatrixFloat3x3 operator * (MatrixFloat3x3 left, MatrixFloat3x3 right) + { + return Multiply (left, right); + } + + public static bool operator == (MatrixFloat3x3 left, MatrixFloat3x3 right) + { + return left.Equals (right); + } + + public static bool operator != (MatrixFloat3x3 left, MatrixFloat3x3 right) + { + return !left.Equals (right); + } + + public static explicit operator global::OpenTK.Matrix3 (MatrixFloat3x3 value) + { + return new global::OpenTK.Matrix3 ( + value.M11, value.M12, value.M13, + value.M21, value.M22, value.M23, + value.M31, value.M32, value.M33); + } + + public static explicit operator MatrixFloat3x3 (global::OpenTK.Matrix3 value) + { + return new MatrixFloat3x3 ( + value.R0C0, value.R0C1, value.R0C2, + value.R1C0, value.R1C1, value.R1C2, + value.R2C0, value.R2C1, value.R2C2); + } + + public override string ToString () + { + return + $"({M11}, {M12}, {M13})\n" + + $"({M21}, {M22}, {M23})\n" + + $"({M31}, {M32}, {M33})"; + } + + public override int GetHashCode () + { + return + M11.GetHashCode () ^ M12.GetHashCode () ^ M13.GetHashCode () ^ + M21.GetHashCode () ^ M22.GetHashCode () ^ M23.GetHashCode () ^ + M31.GetHashCode () ^ M32.GetHashCode () ^ M33.GetHashCode (); + } + + public override bool Equals (object obj) + { + if (!(obj is MatrixFloat3x3)) + return false; + + return Equals ((MatrixFloat3x3) obj); + } + + public bool Equals (MatrixFloat3x3 other) + { + return + M11 == other.M11 && M12 == other.M12 && M13 == other.M13 && + M21 == other.M21 && M22 == other.M22 && M23 == other.M23 && + M31 == other.M31 && M32 == other.M32 && M33 == other.M33; + } + } +} diff --git a/src/Simd/MatrixFloat4x4.cs b/src/Simd/MatrixFloat4x4.cs new file mode 100644 index 0000000000..b7ac7a5488 --- /dev/null +++ b/src/Simd/MatrixFloat4x4.cs @@ -0,0 +1,240 @@ +// +// Authors: +// Rolf Bjarne Kvinge +// +// Copyright (c) 2017 Microsoft Inc +// + +// +// This represents the native matrix_float4x4 type, which has a column-major layout +// (as opposed to OpenTK.Matrix4, which has a row-major layout). +// + +using System; +using System.Runtime.InteropServices; + +using VectorFloat4=global::OpenTK.Vector4; + +namespace Simd +{ + [StructLayout (LayoutKind.Sequential)] + public struct MatrixFloat4x4 : IEquatable + { + public float M11; + public float M21; + public float M31; + public float M41; + + public float M12; + public float M22; + public float M32; + public float M42; + + public float M13; + public float M23; + public float M33; + public float M43; + + public float M14; + public float M24; + public float M34; + public float M44; + + public readonly static MatrixFloat4x4 Identity = new MatrixFloat4x4 { + M11 = 1f, + M22 = 1f, + M33 = 1f, + M44 = 1f, + }; + + public MatrixFloat4x4 (VectorFloat4 column0, VectorFloat4 column1, VectorFloat4 column2, VectorFloat4 column3) + { + M11 = column0.X; + M21 = column0.Y; + M31 = column0.Z; + M41 = column0.W; + M12 = column1.X; + M22 = column1.Y; + M32 = column1.Z; + M42 = column1.W; + M13 = column2.X; + M23 = column2.Y; + M33 = column2.Z; + M43 = column2.W; + M14 = column3.X; + M24 = column3.Y; + M34 = column3.Z; + M44 = column3.W; + } + + public MatrixFloat4x4 ( + float m11, float m12, float m13, float m14, + float m21, float m22, float m23, float m24, + float m31, float m32, float m33, float m34, + float m41, float m42, float m43, float m44) + { + M11 = m11; + M21 = m21; + M31 = m31; + M41 = m41; + M12 = m12; + M22 = m22; + M32 = m32; + M42 = m42; + M13 = m13; + M23 = m23; + M33 = m33; + M43 = m43; + M14 = m14; + M24 = m24; + M34 = m34; + M44 = m44; + } + + public float Determinant { + get { + float a = M33 * M44 - M34 * M43; + float b = M32 * M44 - M34 * M42; + float c = M32 * M43 - M33 * M42; + float d = M31 * M44 - M34 * M41; + float e = M31 * M43 - M33 * M41; + float f = M31 * M42 - M32 * M41; + + return + M11 * (M22 * a - M23 * b + M24 * c) - + M12 * (M21 * a - M23 * d + M24 * e) + + M13 * (M21 * b - M22 * d + M24 * f) - + M14 * (M21 * c - M22 * e + M23 * f); + } + } + + public void Transpose () + { + this = Transpose (this); + } + + public static MatrixFloat4x4 Transpose (MatrixFloat4x4 mat) + { + MatrixFloat4x4 result; + Transpose (ref mat, out result); + return result; + } + + public static void Transpose (ref MatrixFloat4x4 mat, out MatrixFloat4x4 result) + { + result.M11 = mat.M11; + result.M21 = mat.M12; + result.M31 = mat.M13; + result.M41 = mat.M14; + + result.M12 = mat.M21; + result.M22 = mat.M22; + result.M32 = mat.M23; + result.M42 = mat.M24; + + result.M13 = mat.M31; + result.M23 = mat.M32; + result.M33 = mat.M33; + result.M43 = mat.M34; + + result.M14 = mat.M41; + result.M24 = mat.M42; + result.M34 = mat.M43; + result.M44 = mat.M44; + } + + public static MatrixFloat4x4 Multiply (MatrixFloat4x4 left, MatrixFloat4x4 right) + { + MatrixFloat4x4 result; + Multiply (ref left, ref right, out result); + return result; + } + + public static void Multiply (ref MatrixFloat4x4 left, ref MatrixFloat4x4 right, out MatrixFloat4x4 result) + { + result.M11 = left.M11 * right.M11 + left.M12 * right.M21 + left.M13 * right.M31 + left.M14 * right.M41; + result.M12 = left.M11 * right.M12 + left.M12 * right.M22 + left.M13 * right.M32 + left.M14 * right.M42; + result.M13 = left.M11 * right.M13 + left.M12 * right.M23 + left.M13 * right.M33 + left.M14 * right.M43; + result.M14 = left.M11 * right.M14 + left.M12 * right.M24 + left.M13 * right.M34 + left.M14 * right.M44; + + result.M21 = left.M21 * right.M11 + left.M22 * right.M21 + left.M23 * right.M31 + left.M24 * right.M41; + result.M22 = left.M21 * right.M12 + left.M22 * right.M22 + left.M23 * right.M32 + left.M24 * right.M42; + result.M23 = left.M21 * right.M13 + left.M22 * right.M23 + left.M23 * right.M33 + left.M24 * right.M43; + result.M24 = left.M21 * right.M14 + left.M22 * right.M24 + left.M23 * right.M34 + left.M24 * right.M44; + + result.M31 = left.M31 * right.M11 + left.M32 * right.M21 + left.M33 * right.M31 + left.M34 * right.M41; + result.M32 = left.M31 * right.M12 + left.M32 * right.M22 + left.M33 * right.M32 + left.M34 * right.M42; + result.M33 = left.M31 * right.M13 + left.M32 * right.M23 + left.M33 * right.M33 + left.M34 * right.M43; + result.M34 = left.M31 * right.M14 + left.M32 * right.M24 + left.M33 * right.M34 + left.M34 * right.M44; + + result.M41 = left.M41 * right.M11 + left.M42 * right.M21 + left.M43 * right.M31 + left.M44 * right.M41; + result.M42 = left.M41 * right.M12 + left.M42 * right.M22 + left.M43 * right.M32 + left.M44 * right.M42; + result.M43 = left.M41 * right.M13 + left.M42 * right.M23 + left.M43 * right.M33 + left.M44 * right.M43; + result.M44 = left.M41 * right.M14 + left.M42 * right.M24 + left.M43 * right.M34 + left.M44 * right.M44; + } + + public static MatrixFloat4x4 operator * (MatrixFloat4x4 left, MatrixFloat4x4 right) + { + return Multiply (left, right); + } + + public static bool operator == (MatrixFloat4x4 left, MatrixFloat4x4 right) + { + return left.Equals (right); + } + + public static bool operator != (MatrixFloat4x4 left, MatrixFloat4x4 right) + { + return !left.Equals (right); + } + + public static explicit operator global::OpenTK.Matrix4 (MatrixFloat4x4 value) + { + return new global::OpenTK.Matrix4 ( + value.M11, value.M12, value.M13, value.M14, + value.M21, value.M22, value.M23, value.M24, + value.M31, value.M32, value.M33, value.M34, + value.M41, value.M42, value.M43, value.M44); + } + + public static explicit operator MatrixFloat4x4 (global::OpenTK.Matrix4 value) + { + return new MatrixFloat4x4 (value.Column0, value.Column1, value.Column2, value.Column3); + } + + public override string ToString () + { + return + $"({M11}, {M12}, {M13}, {M14})\n" + + $"({M21}, {M22}, {M23}, {M24})\n" + + $"({M31}, {M32}, {M33}, {M34})\n" + + $"({M41}, {M42}, {M43}, {M44})"; + } + + public override int GetHashCode () + { + return + M11.GetHashCode () ^ M12.GetHashCode () ^ M13.GetHashCode () ^ M14.GetHashCode () ^ + M21.GetHashCode () ^ M22.GetHashCode () ^ M23.GetHashCode () ^ M24.GetHashCode () ^ + M31.GetHashCode () ^ M32.GetHashCode () ^ M33.GetHashCode () ^ M34.GetHashCode () ^ + M41.GetHashCode () ^ M42.GetHashCode () ^ M43.GetHashCode () ^ M44.GetHashCode (); + } + + public override bool Equals (object obj) + { + if (!(obj is MatrixFloat4x4)) + return false; + + return Equals ((MatrixFloat4x4) obj); + } + + public bool Equals (MatrixFloat4x4 other) + { + return + M11 == other.M11 && M12 == other.M12 && M13 == other.M13 && M14 == other.M14 && + M21 == other.M21 && M22 == other.M22 && M23 == other.M23 && M24 == other.M24 && + M31 == other.M31 && M32 == other.M32 && M33 == other.M33 && M34 == other.M34 && + M41 == other.M41 && M42 == other.M42 && M43 == other.M43 && M44 == other.M44; + } + } +} diff --git a/src/SpriteKit/SKUniform.cs b/src/SpriteKit/SKUniform.cs index b05c8ab4f0..703a5e5858 100644 --- a/src/SpriteKit/SKUniform.cs +++ b/src/SpriteKit/SKUniform.cs @@ -11,6 +11,8 @@ using System; using XamCore.Foundation; using XamCore.ObjCRuntime; +using Simd; + using Vector2 = global::OpenTK.Vector2; using Vector3 = global::OpenTK.Vector3; using Vector4 = global::OpenTK.Vector4; @@ -71,9 +73,18 @@ namespace XamCore.SpriteKit { InitializeHandle (InitWithNameFloatVector4 (name, value), "initWithName:floatVector4:"); } +#if !XAMCORE_4_0 // Apple deprecated initWithName:floatMatrix2: in macOS10.12/iOS10.0 // and made available initWithName:matrixFloat2x2: so we invoke // the right one at runtime depending on which OS version we are running + // + // Unfortunately our 'initWithName:matrixFloat2x2:' implementation is + // incorrect (the matrix is transposed), but changing it would be a + // breaking change, so we obsolete this constructor and provide a new + // one which implements (only) 'initWithName:matrixFloat2x2:' + // correctly. However, this constructor still does the right thing for + // < macOS 10.12 / iOS 10.0 + [Obsolete ("Use the '(string, MatrixFloat2x2)' overload instead.")] public SKUniform (string name, Matrix2 value) { if (CheckSystemVersion ()) @@ -85,6 +96,14 @@ namespace XamCore.SpriteKit { // Apple deprecated initWithName:floatMatrix3: in macOS10.12/iOS10.0 // and made available initWithName:matrixFloat3x3: so we invoke // the right one at runtime depending on which OS version we are running + // + // Unfortunately our 'initWithName:matrixFloat3x3:' implementation is + // incorrect (the matrix is transposed), but changing it would be a + // breaking change, so we obsolete this constructor and provide a new + // one which implements (only) 'initWithName:matrixFloat3x3:' + // correctly. However, this constructor still does the right thing for + // < macOS 10.12 / iOS 10.0 + [Obsolete ("Use the '(string, MatrixFloat3x3)' overload instead.")] public SKUniform (string name, Matrix3 value) { if (CheckSystemVersion ()) @@ -96,6 +115,14 @@ namespace XamCore.SpriteKit { // Apple deprecated initWithName:floatMatrix4: in macOS10.12/iOS10.0 // and made available initWithName:matrixFloat4x4: so we invoke // the right one at runtime depending on which OS version we are running + // + // Unfortunately our 'initWithName:matrixFloat4x4:' implementation is + // incorrect (the matrix is transposed), but changing it would be a + // breaking change, so we obsolete this constructor and provide a new + // one which implements (only) 'initWithName:matrixFloat4x4:' + // correctly. However, this constructor still does the right thing for + // < macOS 10.12 / iOS 10.0 + [Obsolete ("Use the '(string, MatrixFloat4x4)' overload instead.")] public SKUniform (string name, Matrix4 value) { if (CheckSystemVersion ()) @@ -103,6 +130,7 @@ namespace XamCore.SpriteKit { else InitializeHandle (InitWithNameFloatMatrix4 (name, value), "initWithName:floatMatrix4:"); } +#endif // !XAMCORE_4_0 // Apple deprecated floatVector2Value in macOS10.12/iOS10.0 // and made available vectorFloat2Value so we invoke @@ -161,20 +189,29 @@ namespace XamCore.SpriteKit { } } +#if !XAMCORE_4_0 // Apple deprecated floatMatrix2Value in macOS10.12/iOS10.0 // and made available matrixFloat2x2Value so we invoke // the right one at runtime depending on which OS version we are running + // + // Unfortunately our 'matrixFloat2x2Value' implementation is incorrect + // (we return a transposed matrix), but changing it would be a + // breaking change, so we obsolete this property and provide a new one + // which implements (only) 'matrixFloat4x4Value' correctly. However, + // this property still returns the correct matrix for < macOS 10.12 / + // iOS 10.0 + [Obsolete ("Use 'MatrixFloat2x2Value' instead.")] public virtual Matrix2 FloatMatrix2Value { get { if (CheckSystemVersion ()) - return _MatrixFloat2x2Value; + return (Matrix2) MatrixFloat2x2.Transpose (MatrixFloat2x2Value); else return _FloatMatrix2Value; } set { if (CheckSystemVersion ()) - _MatrixFloat2x2Value = value; + MatrixFloat2x2Value = MatrixFloat2x2.Transpose ((MatrixFloat2x2) value); else _FloatMatrix2Value = value; } @@ -183,17 +220,25 @@ namespace XamCore.SpriteKit { // Apple deprecated floatMatrix3Value in macOS10.12/iOS10.0 // and made available matrixFloat3x3Value so we invoke // the right one at runtime depending on which OS version we are running + // + // Unfortunately our 'matrixFloat3x3Value' implementation is incorrect + // (we return a transposed matrix), but changing it would be a + // breaking change, so we obsolete this property and provide a new one + // which implements (only) 'matrixFloat3x3Value' correctly. However, + // this property still returns the correct matrix for < macOS 10.12 / + // iOS 10.0 + [Obsolete ("Use 'MatrixFloat3x3Value' instead.")] public virtual Matrix3 FloatMatrix3Value { get { if (CheckSystemVersion ()) - return _MatrixFloat3x3Value; + return (Matrix3) MatrixFloat3x3.Transpose (MatrixFloat3x3Value); else return _FloatMatrix3Value; } set { if (CheckSystemVersion ()) - _MatrixFloat3x3Value = value; + MatrixFloat3x3Value = MatrixFloat3x3.Transpose ((MatrixFloat3x3) value); else _FloatMatrix3Value = value; } @@ -202,21 +247,30 @@ namespace XamCore.SpriteKit { // Apple deprecated floatMatrix4Value in macOS10.12/iOS10.0 // and made available matrixFloat4x4Value so we invoke // the right one at runtime depending on which OS version we are running + // + // Unfortunately our 'matrixFloat4x4Value' implementation is incorrect + // (we return a transposed matrix), but changing it would be a + // breaking change, so we obsolete this property and provide a new one + // which implements (only) 'matrixFloat4x4Value' correctly. However, + // this property still returns the correct matrix for < macOS 10.12 / + // iOS 10.0 + [Obsolete ("Use 'MatrixFloat4x4Value' instead.")] public virtual Matrix4 FloatMatrix4Value { get { if (CheckSystemVersion ()) - return _MatrixFloat4x4Value; + return (Matrix4) MatrixFloat4x4.Transpose (MatrixFloat4x4Value); else return _FloatMatrix4Value; } set { if (CheckSystemVersion ()) - _MatrixFloat4x4Value = value; + MatrixFloat4x4Value = MatrixFloat4x4.Transpose ((MatrixFloat4x4) value); else _FloatMatrix4Value = value; } } +#endif // !XAMCORE_4_0 } } #endif // XAMCORE_2_0 diff --git a/src/arkit.cs b/src/arkit.cs index af961b8897..8c3a6043af 100644 --- a/src/arkit.cs +++ b/src/arkit.cs @@ -22,8 +22,8 @@ using XamCore.SceneKit; using XamCore.UIKit; using Vector3 = global::OpenTK.Vector3; -using Matrix3 = global::OpenTK.Matrix3; -using Matrix4 = global::OpenTK.Matrix4; +using Matrix3 = global::Simd.MatrixFloat3x3; +using Matrix4 = global::Simd.MatrixFloat4x4; namespace XamCore.ARKit { diff --git a/src/frameworks.sources b/src/frameworks.sources index 3d080041ba..a6d9b07e62 100644 --- a/src/frameworks.sources +++ b/src/frameworks.sources @@ -1008,6 +1008,8 @@ MODELIO_CORE_SOURCES = \ MODELIO_SOURCES = \ ModelIO/MDLAsset.cs \ ModelIO/MDLNoiseTexture.cs \ + ModelIO/MDLTransform.cs \ + ModelIO/MDLTransformComponent.cs \ ModelIO/MDLVertexDescriptor.cs \ ModelIO/MDLMesh.cs \ @@ -1523,6 +1525,9 @@ SHARED_CORE_SOURCES = \ ObjCRuntime/Protocol.cs \ ObjCRuntime/Registrar.core.cs \ ObjCRuntime/Selector.cs \ + Simd/MatrixFloat2x2.cs \ + Simd/MatrixFloat3x3.cs \ + Simd/MatrixFloat4x4.cs \ SHARED_SOURCES = \ ../runtime/Delegates.generated.cs \ diff --git a/src/gameplaykit.cs b/src/gameplaykit.cs index 587dddb718..8aad4729ab 100644 --- a/src/gameplaykit.cs +++ b/src/gameplaykit.cs @@ -18,6 +18,7 @@ using Vector2i = global::OpenTK.Vector2i; using Vector3 = global::OpenTK.Vector3; using Vector3d = global::OpenTK.Vector3d; using Matrix3 = global::OpenTK.Matrix3; +using Simd; #if MONOMAC using SKColor = XamCore.AppKit.NSColor; @@ -132,6 +133,8 @@ namespace XamCore.GameplayKit { [Export ("rightHanded")] bool RightHanded { get; set; } +#if !XAMCORE_4_0 + [Obsolete ("Use 'Rotation3x3' instead.")] [Export ("rotation", ArgumentSemantic.Assign)] Matrix3 Rotation { [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] @@ -139,6 +142,20 @@ namespace XamCore.GameplayKit { [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] set; } +#endif + + [Export ("rotation", ArgumentSemantic.Assign)] +#if XAMCORE_4_0 + MatrixFloat3x3 Rotation { +#else + [Sealed] + MatrixFloat3x3 Rotation3x3 { +#endif + [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] + get; + [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] + set; + } [Export ("updateWithDeltaTime:")] void Update (double deltaTimeInSeconds); diff --git a/src/modelio.cs b/src/modelio.cs index 418a7b199e..88f63106ce 100644 --- a/src/modelio.cs +++ b/src/modelio.cs @@ -22,9 +22,16 @@ using Vector3 = global::OpenTK.Vector3; using Vector3i = global::OpenTK.Vector3i; using Vector4 = global::OpenTK.Vector4; using Vector4i = global::OpenTK.Vector4i; +#if XAMCORE_4_0 +using Matrix2 = global::Simd.Matrix2; +using Matrix3 = global::Simd.Matrix3; +using Matrix4 = global::Simd.Matrix4; +#else using Matrix2 = global::OpenTK.Matrix2; using Matrix3 = global::OpenTK.Matrix3; using Matrix4 = global::OpenTK.Matrix4; +using Simd; +#endif using Quaternion = global::OpenTK.Quaternion; using MathHelper = global::OpenTK.MathHelper; #if MONOMAC @@ -212,10 +219,21 @@ namespace XamCore.ModelIO { interface MDLCamera { [Export ("projectionMatrix")] +#if !XAMCORE_4_0 + [Obsolete ("Use 'ProjectionMatrix4x4' instead.")] +#endif Matrix4 ProjectionMatrix { [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] get; } +#if !XAMCORE_4_0 + [Sealed] + [Export ("projectionMatrix")] + MatrixFloat4x4 ProjectionMatrix4x4 { + [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] get; + } +#endif + [iOS (10,0)] [Mac (10,12)] [TV (10,0)] @@ -515,8 +533,19 @@ namespace XamCore.ModelIO { [Export ("initWithName:semantic:matrix4x4:")] [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] +#if !XAMCORE_4_0 + [Obsolete ("Use the '(string, MDLMaterialSemantic, MatrixFloat4x4)' overload instead.")] +#endif IntPtr Constructor (string name, MDLMaterialSemantic semantic, Matrix4 value); + +#if !XAMCORE_4_0 + [Sealed] + [Export ("initWithName:semantic:matrix4x4:")] + [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] + IntPtr Constructor (string name, MDLMaterialSemantic semantic, MatrixFloat4x4 value); +#endif + [Export ("initWithName:semantic:URL:")] IntPtr Constructor (string name, MDLMaterialSemantic semantic, [NullAllowed] NSUrl url); @@ -572,12 +601,24 @@ namespace XamCore.ModelIO { [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] set; } +#if !XAMCORE_4_0 + [Obsolete ("Use 'MatrixFloat4x4' instead.")] +#endif [Export ("matrix4x4", ArgumentSemantic.Assign)] Matrix4 Matrix4x4 { [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] get; [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] set; } +#if !XAMCORE_4_0 + [Sealed] + [Export ("matrix4x4", ArgumentSemantic.Assign)] + MatrixFloat4x4 MatrixFloat4x4 { + [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] get; + [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] set; + } +#endif + [iOS (10,0)] [Mac (10,12)] [TV (10,0)] @@ -1362,29 +1403,77 @@ namespace XamCore.ModelIO { [Export ("overlap")] float Overlap { get; set; } +#if !XAMCORE_4_0 + [Obsolete ("Use 'LeftViewMatrix4x4' instead.")] +#endif [Export ("leftViewMatrix")] Matrix4 LeftViewMatrix { [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] get; } +#if !XAMCORE_4_0 + [Sealed] + [Export ("leftViewMatrix")] + MatrixFloat4x4 LeftViewMatrix4x4 { + [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] + get; + } +#endif + +#if !XAMCORE_4_0 + [Obsolete ("Use 'RightViewMatrix4x4' instead.")] +#endif [Export ("rightViewMatrix")] Matrix4 RightViewMatrix { [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] get; } +#if !XAMCORE_4_0 + [Sealed] + [Export ("rightViewMatrix")] + MatrixFloat4x4 RightViewMatrix4x4 { + [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] + get; + } +#endif + +#if !XAMCORE_4_0 + [Obsolete ("Use 'LeftProjectionMatrix4x4' instead.")] +#endif [Export ("leftProjectionMatrix")] Matrix4 LeftProjectionMatrix { [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] get; } +#if !XAMCORE_4_0 + [Sealed] + [Export ("leftProjectionMatrix")] + MatrixFloat4x4 LeftProjectionMatrix4x4 { + [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] + get; + } +#endif + +#if !XAMCORE_4_0 + [Obsolete ("Use 'RightProjectionMatrix4x4' instead.")] +#endif [Export ("rightProjectionMatrix")] Matrix4 RightProjectionMatrix { [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] get; } + +#if !XAMCORE_4_0 + [Sealed] + [Export ("rightProjectionMatrix")] + MatrixFloat4x4 RightProjectionMatrix4x4 { + [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] + get; + } +#endif } [iOS (9,0), Mac(10,11, onlyOn64 : true)] @@ -1576,10 +1665,23 @@ namespace XamCore.ModelIO { [Export ("initWithTransformComponent:resetsTransform:")] IntPtr Constructor (IMDLTransformComponent component, bool resetsTransform); +#if !XAMCORE_4_0 + [Obsolete ("Use the '(MatrixFloat4x4)' overload instead.")] +#endif [Export ("initWithMatrix:")] [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] IntPtr Constructor (Matrix4 matrix); +#if !XAMCORE_4_0 + [Sealed] + [Export ("initWithMatrix:")] + [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] + IntPtr Constructor (MatrixFloat4x4 matrix); +#endif + +#if !XAMCORE_4_0 + [Obsolete ("Use the '(MatrixFloat4x4, bool)' overload instead.")] +#endif [iOS (10,0)] [Mac (10,12)] [TV (10,0)] @@ -1587,6 +1689,14 @@ namespace XamCore.ModelIO { [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] IntPtr Constructor (Matrix4 matrix, bool resetsTransform); +#if !XAMCORE_4_0 + [Sealed] + [iOS (10,0), Mac (10,12), TV (10,0)] + [Export ("initWithMatrix:resetsTransform:")] + [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] + IntPtr Constructor (MatrixFloat4x4 matrix, bool resetsTransform); +#endif + [Export ("setIdentity")] void SetIdentity (); @@ -1606,10 +1716,20 @@ namespace XamCore.ModelIO { [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] Vector3 GetRotation (double atTime); +#if !XAMCORE_4_0 + [Obsolete ("Use 'GetRotationMatrix4x4' instead.")] +#endif [Export ("rotationMatrixAtTime:")] [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] Matrix4 GetRotationMatrix (double atTime); +#if !XAMCORE_4_0 + [Sealed] + [Export ("rotationMatrixAtTime:")] + [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] + MatrixFloat4x4 GetRotationMatrix4x4 (double atTime); +#endif + [Export ("setShear:forTime:")] [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] void SetShear (Vector3 scale, double time); @@ -1629,8 +1749,19 @@ namespace XamCore.ModelIO { [iOS (10,3), TV (10,2), Mac (10,12,4)] [Export ("setMatrix:forTime:")] [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] +#if !XAMCORE_4_0 + [Obsolete ("Use 'SetMatrix4x4' instead.")] +#endif void SetMatrix (Matrix4 matrix, double time); +#if !XAMCORE_4_0 + [Sealed] + [iOS (10,3), TV (10,2), Mac (10,12,4)] + [Export ("setMatrix:forTime:")] + [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] + void SetMatrix4x4 (MatrixFloat4x4 matrix, double time); +#endif + [Export ("shear", ArgumentSemantic.Assign)] Vector3 Shear { [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] @@ -1713,6 +1844,9 @@ namespace XamCore.ModelIO { [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] Matrix4 GetLocalTransform (double atTime); +#if !XAMCORE_4_0 + [Obsolete ("Use 'CreateGlobalTransform4x4' instead.")] +#endif [Static] [Export ("globalTransformWithObject:atTime:")] [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] diff --git a/src/spritekit.cs b/src/spritekit.cs index aa8e5b2a24..8f1c4dcae9 100644 --- a/src/spritekit.cs +++ b/src/spritekit.cs @@ -30,6 +30,7 @@ using Vector3 = global::OpenTK.Vector3; using Matrix2 = global::OpenTK.Matrix2; using Matrix3 = global::OpenTK.Matrix3; using Matrix4 = global::OpenTK.Matrix4; +using Simd; using Vector4 = global::OpenTK.Vector4; using Quaternion = global::OpenTK.Quaternion; @@ -1777,14 +1778,19 @@ namespace XamCore.SpriteKit { IntPtr InitWithNameVectorFloat4 (string name, Vector4 value); #endif +#if !XAMCORE_4_0 [Internal] [NoWatch] [Availability (Deprecated = Platform.iOS_10_0 | Platform.Mac_10_12)] [Export ("initWithName:floatMatrix2:")] IntPtr InitWithNameFloatMatrix2 (string name, Matrix2 value); +#endif +#if !XAMCORE_4_0 + [Obsolete ("Use the '(string, MatrixFloat2x2)' overload instead.")] [iOS (10,0)][Mac (10,12)] [TV (10,0)] + [Sealed] [Export ("initWithName:matrixFloat2x2:")] [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] #if WATCH @@ -1793,15 +1799,25 @@ namespace XamCore.SpriteKit { [Internal] IntPtr InitWithNameMatrixFloat2x2 (string name, Matrix2 value); #endif +#endif // !XAMCORE_4_0 + [iOS (10,0)][Mac (10,12)] + [TV (10,0)] + [Export ("initWithName:matrixFloat2x2:")] + [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] + IntPtr Constructor (string name, MatrixFloat2x2 value); + +#if !XAMCORE_4_0 [Internal] [NoWatch] [Availability (Deprecated = Platform.iOS_10_0 | Platform.Mac_10_12)] [Export ("initWithName:floatMatrix3:")] IntPtr InitWithNameFloatMatrix3 (string name, Matrix3 value); + [Obsolete ("Use the '(string, MatrixFloat3x3)' overload instead.")] [iOS (10,0)][Mac (10,12)] [TV (10,0)] + [Sealed] [Export ("initWithName:matrixFloat3x3:")] [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] #if WATCH @@ -1809,17 +1825,29 @@ namespace XamCore.SpriteKit { #else [Internal] IntPtr InitWithNameMatrixFloat3x3 (string name, Matrix3 value); +#endif #endif + [iOS (10,0)][Mac (10,12)] + [TV (10,0)] + [Export ("initWithName:matrixFloat3x3:")] + [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] + IntPtr Constructor (string name, MatrixFloat3x3 value); + +#if !XAMCORE_4_0 [Internal] [NoWatch] [Availability (Deprecated = Platform.iOS_10_0 | Platform.Mac_10_12)] [Export ("initWithName:floatMatrix4:")] IntPtr InitWithNameFloatMatrix4 (string name, Matrix4 value); +#endif +#if !XAMCORE_4_0 + [Obsolete ("Use the '(string, MatrixFloat4x4)' overload instead.")] [iOS (10,0)][Mac (10,12)] [TV (10,0)] [Export ("initWithName:matrixFloat4x4:")] + [Sealed] [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] #if WATCH IntPtr Constructor (string name, Matrix4 value); @@ -1827,6 +1855,13 @@ namespace XamCore.SpriteKit { [Internal] IntPtr InitWithNameMatrixFloat4x4 (string name, Matrix4 value); #endif +#endif + + [iOS (10,0)][Mac (10,12)] + [TV (10,0)] + [Export ("initWithName:matrixFloat4x4:")] + [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] + IntPtr Constructor (string name, MatrixFloat4x4 value); [Export ("name")] string Name { get; } @@ -1897,59 +1932,92 @@ namespace XamCore.SpriteKit { [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] set; } +#if !XAMCORE_4_0 [Internal] [Availability (Deprecated = Platform.iOS_10_0 | Platform.Mac_10_12)] [NoWatch] [Export ("floatMatrix2Value")] Matrix2 _FloatMatrix2Value { get; set; } +#endif +#if !XAMCORE_4_0 && WATCH + [Obsolete ("Use 'MatrixFloat2x2Value' instead.")] [iOS (10,0)][Mac (10,12)] [TV (10,0)] [Export ("matrixFloat2x2Value", ArgumentSemantic.Assign)] -#if WATCH Matrix2 FloatMatrix2x2Value { -#else - [Internal] - Matrix2 _MatrixFloat2x2Value { + [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] get; + [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] set; + } #endif + +#if !XAMCORE_4_0 && WATCH + [Sealed] // The selector is already used in the 'FloatMatrix2x2Value' property. +#endif + [iOS (10,0)][Mac (10,12)] + [TV (10,0)] + [Export ("matrixFloat2x2Value", ArgumentSemantic.Assign)] + MatrixFloat2x2 MatrixFloat2x2Value { [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] get; [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] set; } +#if !XAMCORE_4_0 [Internal] [NoWatch] [Availability (Deprecated = Platform.iOS_10_0 | Platform.Mac_10_12)] [Export ("floatMatrix3Value")] Matrix3 _FloatMatrix3Value { get; set; } +#endif +#if !XAMCORE_4_0 && WATCH + [Obsolete ("Use 'MatrixFloat3x3Value' instead.")] [iOS (10,0)][Mac (10,12)] [TV (10,0)] [Export ("matrixFloat3x3Value", ArgumentSemantic.Assign)] -#if WATCH Matrix3 FloatMatrix3x3Value { -#else - [Internal] - Matrix3 _MatrixFloat3x3Value { + [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] get; + [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] set; + } #endif + +#if !XAMCORE_4_0 && WATCH + [Sealed] // The selector is already used in the 'FloatMatrix3x3Value' property. +#endif + [iOS (10,0)][Mac (10,12)] + [TV (10,0)] + [Export ("matrixFloat3x3Value", ArgumentSemantic.Assign)] + MatrixFloat3x3 MatrixFloat3x3Value { [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] get; [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] set; } +#if !XAMCORE_4_0 [Internal] [NoWatch] [Availability (Deprecated = Platform.iOS_10_0 | Platform.Mac_10_12)] [Export ("floatMatrix4Value")] Matrix4 _FloatMatrix4Value { get; set; } +#endif +#if !XAMCORE_4_0 && WATCH + [Obsolete ("Use 'FloatMatrix4x4Value' instead.")] [iOS (10,0)][Mac (10,12)] [TV (10,0)] [Export ("matrixFloat4x4Value", ArgumentSemantic.Assign)] -#if WATCH Matrix4 FloatMatrix4x4Value { -#else - [Internal] - Matrix4 _MatrixFloat4x4Value { + [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] get; + [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] set; + } #endif + +#if !XAMCORE_4_0 && WATCH + [Sealed] // The selector is already used in the 'FloatMatrix4x4Value' property. +#endif + [iOS (10,0)][Mac (10,12)] + [TV (10,0)] + [Export ("matrixFloat4x4Value", ArgumentSemantic.Assign)] + MatrixFloat4x4 MatrixFloat4x4Value { [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] get; [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] set; } @@ -1981,23 +2049,50 @@ namespace XamCore.SpriteKit { [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] SKUniform Create (string name, Vector4 value); +#if !XAMCORE_4_0 + [Obsolete ("Use the '(string, MatrixFloat2x2)' overload instead.")] [iOS (10,0)][Mac (10,12)] [Static] [Export ("uniformWithName:matrixFloat2x2:")] [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] SKUniform Create (string name, Matrix2 value); +#endif + [iOS (10,0)][Mac (10,12)] + [Static] + [Export ("uniformWithName:matrixFloat2x2:")] + [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] + SKUniform Create (string name, MatrixFloat2x2 value); + +#if !XAMCORE_4_0 + [Obsolete ("Use the '(string, MatrixFloat3x3)' overload instead.")] [iOS (10,0)][Mac (10,12)] [Static] [Export ("uniformWithName:matrixFloat3x3:")] [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] SKUniform Create (string name, Matrix3 value); +#endif + [iOS (10,0)][Mac (10,12)] + [Static] + [Export ("uniformWithName:matrixFloat3x3:")] + [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] + SKUniform Create (string name, MatrixFloat3x3 value); + +#if !XAMCORE_4_0 + [Obsolete ("Use 'the '(string, MatrixFloat4x4)' overload instead.")] [iOS (10,0)][Mac (10,12)] [Static] [Export ("uniformWithName:matrixFloat4x4:")] [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] SKUniform Create (string name, Matrix4 value); +#endif + + [iOS (10,0)][Mac (10,12)] + [Static] + [Export ("uniformWithName:matrixFloat4x4:")] + [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] + SKUniform Create (string name, MatrixFloat4x4 value); } delegate void SKActionDurationHandler (SKNode node, nfloat elapsedTime); @@ -3358,7 +3453,7 @@ namespace XamCore.SpriteKit { } [Export ("rotationMatrix")] - Matrix3 RotationMatrix { + MatrixFloat3x3 RotationMatrix { [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] get; [MarshalDirective (NativePrefix = "xamarin_simd__", Library = "__Internal")] set; } diff --git a/src/vision.cs b/src/vision.cs index 098900b2fb..39add19020 100644 --- a/src/vision.cs +++ b/src/vision.cs @@ -21,7 +21,7 @@ using XamCore.ObjCRuntime; using XamCore.ImageIO; using Vector2 = global::OpenTK.Vector2; -using Matrix3 = global::OpenTK.Matrix3; +using Matrix3 = global::Simd.MatrixFloat3x3; namespace XamCore.Vision { diff --git a/tests/bindings-framework-test/XTest.framework.linkwith.cs b/tests/bindings-framework-test/XTest.framework.linkwith.cs index 8d0206b07d..fb6f1c9421 100644 --- a/tests/bindings-framework-test/XTest.framework.linkwith.cs +++ b/tests/bindings-framework-test/XTest.framework.linkwith.cs @@ -7,7 +7,16 @@ using MonoTouch.ObjCRuntime; using System.Runtime.InteropServices; #if __UNIFIED__ -[assembly: LinkWith ("XTest.framework")] -[assembly: LinkWith ("XStaticObjectTest.framework", LinkerFlags = "-lz")] -[assembly: LinkWith ("XStaticArTest.framework")] +[assembly: LinkWith ("XTest.framework", Frameworks = LinkWithConstants.Frameworks)] +[assembly: LinkWith ("XStaticObjectTest.framework", LinkerFlags = "-lz", Frameworks = LinkWithConstants.Frameworks)] +[assembly: LinkWith ("XStaticArTest.framework", Frameworks = LinkWithConstants.Frameworks)] #endif + +static class LinkWithConstants +{ +#if __WATCHOS__ + public const string Frameworks = ""; +#else + public const string Frameworks = "ModelIO"; +#endif +} diff --git a/tests/bindings-test/StructsAndEnums.cs b/tests/bindings-test/StructsAndEnums.cs index 26e6b3c073..1d488c1029 100644 --- a/tests/bindings-test/StructsAndEnums.cs +++ b/tests/bindings-test/StructsAndEnums.cs @@ -3,13 +3,103 @@ using System.Runtime.InteropServices; #if !__UNIFIED__ using nint=System.Int32; +#else +using Foundation; +using ObjCRuntime; #endif +using Simd; + namespace Bindings.Test { public static class CFunctions { [DllImport ("__Internal")] public static extern int theUltimateAnswer (); + + [DllImport ("__Internal")] + public static extern void x_get_matrix_float2x2 (IntPtr self, string sel, out float r0c0, out float r0c1, out float r1c0, out float r1c1); + + [DllImport ("__Internal")] + public static extern void x_get_matrix_float3x3 (IntPtr self, string sel, out float r0c0, out float r0c1, out float r0c2, out float r1c0, out float r1c1, out float r1c2, out float r2c0, out float r2c1, out float r2c2); + + [DllImport ("__Internal")] + public static extern void x_get_matrix_float4x4 (IntPtr self, string sel, out float r0c0, out float r0c1, out float r0c2, out float r0c3, out float r1c0, out float r1c1, out float r1c2, out float r1c3, out float r2c0, out float r2c1, out float r2c2, out float r2c3, out float r3c0, out float r3c1, out float r3c2, out float r3c3); + + public static MatrixFloat2x2 GetMatrixFloat2x2 (NSObject obj, string selector) + { + float r0c0, r0c1, r1c0, r1c1; + x_get_matrix_float2x2 (obj.Handle, selector, out r0c0, out r0c1, out r1c0, out r1c1); + return new MatrixFloat2x2 ( + r0c0, r0c1, + r1c0, r1c1); + } + + public static MatrixFloat3x3 GetMatrixFloat3x3 (NSObject obj, string selector) + { + float r0c0, r0c1, r0c2, r1c0, r1c1, r1c2, r2c0, r2c1, r2c2; + x_get_matrix_float3x3 (obj.Handle, selector, out r0c0, out r0c1, out r0c2, out r1c0, out r1c1, out r1c2, out r2c0, out r2c1, out r2c2); + return new MatrixFloat3x3 ( + r0c0, r0c1, r0c2, + r1c0, r1c1, r1c2, + r2c0, r2c1, r2c2); + + } + + public static MatrixFloat4x4 GetMatrixFloat4x4 (NSObject obj, string selector) + { + float r0c0, r0c1, r0c2, r0c3, r1c0, r1c1, r1c2, r1c3, r2c0, r2c1, r2c2, r2c3, r3c0, r3c1, r3c2, r3c3; + x_get_matrix_float4x4 (obj.Handle, selector, out r0c0, out r0c1, out r0c2, out r0c3, out r1c0, out r1c1, out r1c2, out r1c3, out r2c0, out r2c1, out r2c2, out r2c3, out r3c0, out r3c1, out r3c2, out r3c3); + return new MatrixFloat4x4 ( + r0c0, r0c1, r0c2, r0c3, + r1c0, r1c1, r1c2, r1c3, + r2c0, r2c1, r2c2, r2c3, + r3c0, r3c1, r3c2, r3c3); + } + + +#if !__WATCHOS__ + [DllImport ("__Internal")] + public static extern void x_mdltransformcomponent_get_local_transform (IntPtr self, double time, out float r0c0, out float r0c1, out float r0c2, out float r0c3, out float r1c0, out float r1c1, out float r1c2, out float r1c3, out float r2c0, out float r2c1, out float r2c2, out float r2c3, out float r3c0, out float r3c1, out float r3c2, out float r3c3); + + public static MatrixFloat4x4 MDLTransformComponent_GetLocalTransform (INativeObject obj, double time) + { + float r0c0, r0c1, r0c2, r0c3, r1c0, r1c1, r1c2, r1c3, r2c0, r2c1, r2c2, r2c3, r3c0, r3c1, r3c2, r3c3; + x_mdltransformcomponent_get_local_transform (obj.Handle, time, out r0c0, out r0c1, out r0c2, out r0c3, out r1c0, out r1c1, out r1c2, out r1c3, out r2c0, out r2c1, out r2c2, out r2c3, out r3c0, out r3c1, out r3c2, out r3c3); + return new MatrixFloat4x4 ( + r0c0, r0c1, r0c2, r0c3, + r1c0, r1c1, r1c2, r1c3, + r2c0, r2c1, r2c2, r2c3, + r3c0, r3c1, r3c2, r3c3); + } + + [DllImport ("__Internal")] + public static extern void x_mdltransform_create_global_transform (IntPtr obj, double time, out float r0c0, out float r0c1, out float r0c2, out float r0c3, out float r1c0, out float r1c1, out float r1c2, out float r1c3, out float r2c0, out float r2c1, out float r2c2, out float r2c3, out float r3c0, out float r3c1, out float r3c2, out float r3c3); + + public static MatrixFloat4x4 MDLTransform_CreateGlobalTransform (INativeObject obj, double time) + { + float r0c0, r0c1, r0c2, r0c3, r1c0, r1c1, r1c2, r1c3, r2c0, r2c1, r2c2, r2c3, r3c0, r3c1, r3c2, r3c3; + x_mdltransform_create_global_transform (obj.Handle, time, out r0c0, out r0c1, out r0c2, out r0c3, out r1c0, out r1c1, out r1c2, out r1c3, out r2c0, out r2c1, out r2c2, out r2c3, out r3c0, out r3c1, out r3c2, out r3c3); + return new MatrixFloat4x4 ( + r0c0, r0c1, r0c2, r0c3, + r1c0, r1c1, r1c2, r1c3, + r2c0, r2c1, r2c2, r2c3, + r3c0, r3c1, r3c2, r3c3); + } + + [DllImport ("__Internal")] + public static extern void x_mdltransform_get_rotation_matrix (IntPtr obj, double time, out float r0c0, out float r0c1, out float r0c2, out float r0c3, out float r1c0, out float r1c1, out float r1c2, out float r1c3, out float r2c0, out float r2c1, out float r2c2, out float r2c3, out float r3c0, out float r3c1, out float r3c2, out float r3c3); + + public static MatrixFloat4x4 MDLTransform_GetRotationMatrix (INativeObject obj, double time) + { + float r0c0, r0c1, r0c2, r0c3, r1c0, r1c1, r1c2, r1c3, r2c0, r2c1, r2c2, r2c3, r3c0, r3c1, r3c2, r3c3; + x_mdltransform_get_rotation_matrix (obj.Handle, time, out r0c0, out r0c1, out r0c2, out r0c3, out r1c0, out r1c1, out r1c2, out r1c3, out r2c0, out r2c1, out r2c2, out r2c3, out r3c0, out r3c1, out r3c2, out r3c3); + return new MatrixFloat4x4 ( + r0c0, r0c1, r0c2, r0c3, + r1c0, r1c1, r1c2, r1c3, + r2c0, r2c1, r2c2, r2c3, + r3c0, r3c1, r3c2, r3c3); + } +#endif } } diff --git a/tests/bindings-test/libtest.linkwith.cs b/tests/bindings-test/libtest.linkwith.cs index df0c9c264c..15cef44412 100644 --- a/tests/bindings-test/libtest.linkwith.cs +++ b/tests/bindings-test/libtest.linkwith.cs @@ -6,9 +6,18 @@ using MonoTouch.ObjCRuntime; #endif using System.Runtime.InteropServices; -[assembly: LinkWith ("libtest.a", LinkTarget.Simulator | LinkTarget.ArmV6 | LinkTarget.ArmV7 | LinkTarget.ArmV7s | LinkTarget.Arm64 | LinkTarget.Simulator64, SmartLink = true, Frameworks = "Foundation" , LinkerFlags = "-lz")] +[assembly: LinkWith ("libtest.a", LinkTarget.Simulator | LinkTarget.ArmV6 | LinkTarget.ArmV7 | LinkTarget.ArmV7s | LinkTarget.Arm64 | LinkTarget.Simulator64, SmartLink = true, Frameworks = LinkWithConstants.Frameworks, LinkerFlags = "-lz")] public static class LibTest { [DllImport ("__Internal")] public static extern int theUltimateAnswer (); } + +static class LinkWithConstants +{ +#if __WATCHOS__ + public const string Frameworks = "Foundation"; +#else + public const string Frameworks = "Foundation ModelIO"; +#endif +} diff --git a/tests/introspection/ApiSignatureTest.cs b/tests/introspection/ApiSignatureTest.cs index bfd50cc1e9..dfb92a1539 100644 --- a/tests/introspection/ApiSignatureTest.cs +++ b/tests/introspection/ApiSignatureTest.cs @@ -233,6 +233,10 @@ namespace Introspection { if (methodinfo == null && constructorinfo == null) return; + // Don't check obsolete methods, it could be obsoleted because it was broken. + if (m.GetCustomAttributes () != null) + return; + if (m.DeclaringType != t) return; @@ -388,9 +392,9 @@ namespace Introspection { case "Vector4": case "Vector4i": case "Vector4d": - case "Matrix2": - case "Matrix3": - case "Matrix4": + case "MatrixFloat2x2": + case "MatrixFloat3x3": + case "MatrixFloat4x4": case "MDLAxisAlignedBoundingBox": // struct { Vector3, Vector3 } return true; default: diff --git a/tests/monotouch-test/Asserts.cs b/tests/monotouch-test/Asserts.cs index 03ddbc8db0..6a1037aa64 100644 --- a/tests/monotouch-test/Asserts.cs +++ b/tests/monotouch-test/Asserts.cs @@ -10,11 +10,11 @@ using MetalPerformanceShaders; using MonoTouch.ModelIO; #endif using OpenTK; +using Simd; using NUnit.Framework; public static class Asserts { -#if !__WATCHOS__ public static void AreEqual (bool expected, bool actual, string message) { Assert.AreEqual (expected, actual, message + " (M)"); @@ -25,6 +25,11 @@ public static class Asserts Assert.AreEqual (expected, actual, message + " (M)"); } + public static void AreEqual (float expected, float actual, float delta, string message) + { + Assert.AreEqual (expected, actual, delta, message); + } + public static void AreEqual (Vector2 expected, Vector2 actual, string message) { Assert.AreEqual (expected.X, actual.X, message + " (X)"); @@ -38,6 +43,13 @@ public static class Asserts Assert.AreEqual (expected.Z, actual.Z, 0.001, message + " (Z)"); } + public static void AreEqual (Vector3 expected, Vector3 actual, float delta, string message) + { + Assert.AreEqual (expected.X, actual.X, delta, message + " (X)"); + Assert.AreEqual (expected.Y, actual.Y, delta, message + " (Y)"); + Assert.AreEqual (expected.Z, actual.Z, delta, message + " (Z)"); + } + public static void AreEqual (Vector4 expected, Vector4 actual, string message) { Assert.AreEqual (expected.X, actual.X, message + " (X)"); @@ -46,6 +58,14 @@ public static class Asserts Assert.AreEqual (expected.W, actual.W, message + " (W)"); } + public static void AreEqual (Vector4 expected, Vector4 actual, float delta, string message) + { + Assert.AreEqual (expected.X, actual.X, delta, message + " (X)"); + Assert.AreEqual (expected.Y, actual.Y, delta, message + " (Y)"); + Assert.AreEqual (expected.Z, actual.Z, delta, message + " (Z)"); + Assert.AreEqual (expected.W, actual.W, delta, message + " (W)"); + } + public static void AreEqual (Matrix2 expected, Matrix2 actual, string message) { AreEqual (expected.R0C0, actual.R0C0, message + " (R0C0)"); @@ -67,6 +87,19 @@ public static class Asserts AreEqual (expected.R2C2, actual.R2C2, message + " (R2C2)"); } + public static void AreEqual (Matrix3 expected, Matrix3 actual, float delta, string message) + { + AreEqual (expected.R0C0, actual.R0C0, delta, message + " (R0C0)"); + AreEqual (expected.R0C1, actual.R0C1, delta, message + " (R0C1)"); + AreEqual (expected.R0C2, actual.R0C2, delta, message + " (R0C2)"); + AreEqual (expected.R1C0, actual.R1C0, delta, message + " (R1C0)"); + AreEqual (expected.R1C1, actual.R1C1, delta, message + " (R1C1)"); + AreEqual (expected.R1C2, actual.R1C2, delta, message + " (R1C2)"); + AreEqual (expected.R2C0, actual.R2C0, delta, message + " (R2C0)"); + AreEqual (expected.R2C1, actual.R2C1, delta, message + " (R2C1)"); + AreEqual (expected.R2C2, actual.R2C2, delta, message + " (R2C2)"); + } + public static void AreEqual (Matrix4 expected, Matrix4 actual, string message) { AreEqual (expected.Column0, actual.Column0, message + " (Col0)"); @@ -75,17 +108,27 @@ public static class Asserts AreEqual (expected.Column3, actual.Column3, message + " (Col3)"); } + public static void AreEqual (Matrix4 expected, Matrix4 actual, float delta, string message) + { + AreEqual (expected.Column0, actual.Column0, delta, message + " (Col0)"); + AreEqual (expected.Column1, actual.Column1, delta, message + " (Col1)"); + AreEqual (expected.Column2, actual.Column2, delta, message + " (Col2)"); + AreEqual (expected.Column3, actual.Column3, delta, message + " (Col3)"); + } + public static void AreEqual (Vector2i expected, Vector2i actual, string message) { Assert.AreEqual (expected.X, actual.X, message + " (X)"); Assert.AreEqual (expected.Y, actual.Y, message + " (Y)"); } +#if !__WATCHOS__ public static void AreEqual (MDLAxisAlignedBoundingBox expected, MDLAxisAlignedBoundingBox actual, string message) { AreEqual (expected.MaxBounds, actual.MaxBounds, message + " (MaxBounds)"); AreEqual (expected.MinBounds, actual.MinBounds, message + " (MinBounds)"); } +#endif // !__WATCHOS__ public static void AreEqual (Quaternion expected, Quaternion actual, string message) { @@ -95,7 +138,7 @@ public static class Asserts Assert.AreEqual (expected.W, actual.W, message + " (W)"); } -#if !MONOMAC +#if !MONOMAC && !__WATCHOS__ public static void AreEqual (MPSImageHistogramInfo expected, MPSImageHistogramInfo actual, string message) { Assert.AreEqual (expected.HistogramForAlpha, actual.HistogramForAlpha, message + " HistogramForAlpha"); @@ -103,7 +146,190 @@ public static class Asserts Asserts.AreEqual (expected.MinPixelValue, actual.MinPixelValue, message + " MinPixelValue"); Assert.AreEqual (expected.NumberOfHistogramEntries, actual.NumberOfHistogramEntries, message + " NumberOfHistogramEntries"); } -#endif // !MONOMAC -#endif // !__WATCHOS__ +#endif // !MONOMAC && !__WATCHOS__ + + public static void AreEqual (MatrixFloat2x2 expected, MatrixFloat2x2 actual, string message) + { + AreEqual (expected.M11, actual.M11, message + " (M11)"); + AreEqual (expected.M21, actual.M21, message + " (M21)"); + AreEqual (expected.M12, actual.M12, message + " (M12)"); + AreEqual (expected.M22, actual.M22, message + " (M22)"); + } + + public static void AreEqual (MatrixFloat2x2 expected, MatrixFloat2x2 actual, float delta, string message) + { + AreEqual (expected.M11, actual.M11, delta, message + " (M11)"); + AreEqual (expected.M21, actual.M21, delta, message + " (M21)"); + AreEqual (expected.M12, actual.M12, delta, message + " (M12)"); + AreEqual (expected.M22, actual.M22, delta, message + " (M22)"); + } + + public static void AreEqual (Matrix2 expected, MatrixFloat2x2 actual, string message) + { + AreEqual (expected.R0C0, actual.M11, message + " (M11)"); + AreEqual (expected.R0C1, actual.M12, message + " (M12)"); + AreEqual (expected.R1C0, actual.M21, message + " (M21)"); + AreEqual (expected.R1C1, actual.M22, message + " (M22)"); + } + + public static void AreEqual (MatrixFloat2x2 expected, Matrix2 actual, string message) + { + AreEqual (expected.M11, actual.R0C0, message + " (M11)"); + AreEqual (expected.M12, actual.R0C1, message + " (M12)"); + AreEqual (expected.M21, actual.R1C0, message + " (M21)"); + AreEqual (expected.M22, actual.R1C1, message + " (M22)"); + } + + public static void AreEqual (MatrixFloat3x3 expected, MatrixFloat3x3 actual, string message) + { + AreEqual (expected.M11, actual.M11, message + " (M11)"); + AreEqual (expected.M21, actual.M21, message + " (M21)"); + AreEqual (expected.M31, actual.M31, message + " (M31)"); + AreEqual (expected.M12, actual.M12, message + " (M12)"); + AreEqual (expected.M22, actual.M22, message + " (M22)"); + AreEqual (expected.M32, actual.M32, message + " (M32)"); + AreEqual (expected.M13, actual.M13, message + " (M13)"); + AreEqual (expected.M23, actual.M23, message + " (M23)"); + AreEqual (expected.M33, actual.M33, message + " (M33)"); + } + + public static void AreEqual (MatrixFloat3x3 expected, MatrixFloat3x3 actual, float delta, string message) + { + AreEqual (expected.M11, actual.M11, delta, message + " (M11)"); + AreEqual (expected.M21, actual.M21, delta, message + " (M21)"); + AreEqual (expected.M31, actual.M31, delta, message + " (M31)"); + AreEqual (expected.M12, actual.M12, delta, message + " (M12)"); + AreEqual (expected.M22, actual.M22, delta, message + " (M22)"); + AreEqual (expected.M32, actual.M32, delta, message + " (M32)"); + AreEqual (expected.M13, actual.M13, delta, message + " (M13)"); + AreEqual (expected.M23, actual.M23, delta, message + " (M23)"); + AreEqual (expected.M33, actual.M33, delta, message + " (M33)"); + } + + public static void AreEqual (Matrix3 expected, MatrixFloat3x3 actual, string message) + { + AreEqual (expected.R0C0, actual.M11, message + " (M11)"); + AreEqual (expected.R0C1, actual.M12, message + " (M12)"); + AreEqual (expected.R0C2, actual.M13, message + " (M13)"); + AreEqual (expected.R1C0, actual.M21, message + " (M21)"); + AreEqual (expected.R1C1, actual.M22, message + " (M22)"); + AreEqual (expected.R1C2, actual.M23, message + " (M23)"); + AreEqual (expected.R2C0, actual.M31, message + " (M31)"); + AreEqual (expected.R2C1, actual.M32, message + " (M32)"); + AreEqual (expected.R2C2, actual.M33, message + " (M33)"); + } + + public static void AreEqual (MatrixFloat3x3 expected, Matrix3 actual, string message) + { + AreEqual (expected.M11, actual.R0C0, message + " (M11)"); + AreEqual (expected.M12, actual.R0C1, message + " (M12)"); + AreEqual (expected.M13, actual.R0C2, message + " (M13)"); + AreEqual (expected.M21, actual.R1C0, message + " (M21)"); + AreEqual (expected.M22, actual.R1C1, message + " (M22)"); + AreEqual (expected.M23, actual.R1C2, message + " (M23)"); + AreEqual (expected.M31, actual.R2C0, message + " (M31)"); + AreEqual (expected.M32, actual.R2C1, message + " (M32)"); + AreEqual (expected.M33, actual.R2C2, message + " (M33)"); + } + + public static void AreEqual (MatrixFloat4x4 expected, MatrixFloat4x4 actual, string message) + { + AreEqual (expected.M11, actual.M11, message + " (M11)"); + AreEqual (expected.M21, actual.M21, message + " (M21)"); + AreEqual (expected.M31, actual.M31, message + " (M31)"); + AreEqual (expected.M41, actual.M41, message + " (M41)"); + AreEqual (expected.M12, actual.M12, message + " (M12)"); + AreEqual (expected.M22, actual.M22, message + " (M22)"); + AreEqual (expected.M32, actual.M32, message + " (M32)"); + AreEqual (expected.M42, actual.M42, message + " (M42)"); + AreEqual (expected.M13, actual.M13, message + " (M13)"); + AreEqual (expected.M23, actual.M23, message + " (M23)"); + AreEqual (expected.M33, actual.M33, message + " (M33)"); + AreEqual (expected.M43, actual.M43, message + " (M43)"); + AreEqual (expected.M14, actual.M14, message + " (M14)"); + AreEqual (expected.M24, actual.M24, message + " (M24)"); + AreEqual (expected.M34, actual.M34, message + " (M34)"); + AreEqual (expected.M44, actual.M44, message + " (M44)"); + } + + public static void AreEqual (MatrixFloat4x4 expected, MatrixFloat4x4 actual, float delta, string message) + { + AreEqual (expected.M11, actual.M11, delta, message + " (M11)"); + AreEqual (expected.M21, actual.M21, delta, message + " (M21)"); + AreEqual (expected.M31, actual.M31, delta, message + " (M31)"); + AreEqual (expected.M41, actual.M41, delta, message + " (M41)"); + AreEqual (expected.M12, actual.M12, delta, message + " (M12)"); + AreEqual (expected.M22, actual.M22, delta, message + " (M22)"); + AreEqual (expected.M32, actual.M32, delta, message + " (M32)"); + AreEqual (expected.M42, actual.M42, delta, message + " (M42)"); + AreEqual (expected.M13, actual.M13, delta, message + " (M13)"); + AreEqual (expected.M23, actual.M23, delta, message + " (M23)"); + AreEqual (expected.M33, actual.M33, delta, message + " (M33)"); + AreEqual (expected.M43, actual.M43, delta, message + " (M43)"); + AreEqual (expected.M14, actual.M14, delta, message + " (M14)"); + AreEqual (expected.M24, actual.M24, delta, message + " (M24)"); + AreEqual (expected.M34, actual.M34, delta, message + " (M34)"); + AreEqual (expected.M44, actual.M44, delta, message + " (M44)"); + } + + public static void AreEqual (Matrix4 expected, MatrixFloat4x4 actual, string message) + { + AreEqual (expected.M11, actual.M11, message + " (M11)"); + AreEqual (expected.M21, actual.M21, message + " (M21)"); + AreEqual (expected.M31, actual.M31, message + " (M31)"); + AreEqual (expected.M41, actual.M41, message + " (M41)"); + AreEqual (expected.M12, actual.M12, message + " (M12)"); + AreEqual (expected.M22, actual.M22, message + " (M22)"); + AreEqual (expected.M32, actual.M32, message + " (M32)"); + AreEqual (expected.M42, actual.M42, message + " (M42)"); + AreEqual (expected.M13, actual.M13, message + " (M13)"); + AreEqual (expected.M23, actual.M23, message + " (M23)"); + AreEqual (expected.M33, actual.M33, message + " (M33)"); + AreEqual (expected.M43, actual.M43, message + " (M43)"); + AreEqual (expected.M14, actual.M14, message + " (M14)"); + AreEqual (expected.M24, actual.M24, message + " (M24)"); + AreEqual (expected.M34, actual.M34, message + " (M34)"); + AreEqual (expected.M44, actual.M44, message + " (M44)"); + } + + public static void AreEqual (Matrix4 expected, MatrixFloat4x4 actual, float delta, string message) + { + AreEqual (expected.M11, actual.M11, delta, message + " (M11)"); + AreEqual (expected.M21, actual.M21, delta, message + " (M21)"); + AreEqual (expected.M31, actual.M31, delta, message + " (M31)"); + AreEqual (expected.M41, actual.M41, delta, message + " (M41)"); + AreEqual (expected.M12, actual.M12, delta, message + " (M12)"); + AreEqual (expected.M22, actual.M22, delta, message + " (M22)"); + AreEqual (expected.M32, actual.M32, delta, message + " (M32)"); + AreEqual (expected.M42, actual.M42, delta, message + " (M42)"); + AreEqual (expected.M13, actual.M13, delta, message + " (M13)"); + AreEqual (expected.M23, actual.M23, delta, message + " (M23)"); + AreEqual (expected.M33, actual.M33, delta, message + " (M33)"); + AreEqual (expected.M43, actual.M43, delta, message + " (M43)"); + AreEqual (expected.M14, actual.M14, delta, message + " (M14)"); + AreEqual (expected.M24, actual.M24, delta, message + " (M24)"); + AreEqual (expected.M34, actual.M34, delta, message + " (M34)"); + AreEqual (expected.M44, actual.M44, delta, message + " (M44)"); + } + + public static void AreEqual (MatrixFloat4x4 expected, Matrix4 actual, string message) + { + AreEqual (expected.M11, actual.M11, message + " (M11)"); + AreEqual (expected.M21, actual.M21, message + " (M21)"); + AreEqual (expected.M31, actual.M31, message + " (M31)"); + AreEqual (expected.M41, actual.M41, message + " (M41)"); + AreEqual (expected.M12, actual.M12, message + " (M12)"); + AreEqual (expected.M22, actual.M22, message + " (M22)"); + AreEqual (expected.M32, actual.M32, message + " (M32)"); + AreEqual (expected.M42, actual.M42, message + " (M42)"); + AreEqual (expected.M13, actual.M13, message + " (M13)"); + AreEqual (expected.M23, actual.M23, message + " (M23)"); + AreEqual (expected.M33, actual.M33, message + " (M33)"); + AreEqual (expected.M43, actual.M43, message + " (M43)"); + AreEqual (expected.M14, actual.M14, message + " (M14)"); + AreEqual (expected.M24, actual.M24, message + " (M24)"); + AreEqual (expected.M34, actual.M34, message + " (M34)"); + AreEqual (expected.M44, actual.M44, message + " (M44)"); + } } diff --git a/tests/monotouch-test/GameplayKit/GKAgent3DTest.cs b/tests/monotouch-test/GameplayKit/GKAgent3DTest.cs new file mode 100644 index 0000000000..cd814ee216 --- /dev/null +++ b/tests/monotouch-test/GameplayKit/GKAgent3DTest.cs @@ -0,0 +1,62 @@ +// +// Unit tests for GKAgent3D +// +// Authors: +// Rolf Bjarne Kvinge +// +// +// Copyright 2017 Microsoft Inc. All rights reserved. +// + +#if !__WATCHOS__ + +using System; +using OpenTK; + +#if XAMCORE_2_0 +using Foundation; +using GameplayKit; +#else +using MonoTouch.Foundation; +using MonoTouch.GameplayKit; +#endif +using Simd; +using Bindings.Test; +using NUnit.Framework; + +namespace MonoTouchFixtures.GamePlayKit +{ + [TestFixture] + [Preserve (AllMembers = true)] + public class GKAgent3DTest + { + [Test] + public void RotationTest () + { + using (var obj = new GKAgent3D ()) { + var initial = new Matrix3 (0, 0, 1, + 0, 1, 0, + 1, 0, 0); + Asserts.AreEqual (initial, obj.Rotation, "Rotation"); + Asserts.AreEqual ((MatrixFloat3x3) initial, obj.Rotation3x3, "Rotation3x3"); + + var mat = new Matrix3 (1, 2, 3, + 4, 5, 6, + 7, 8, 9); + var mat3x3 = (MatrixFloat3x3) mat; + + obj.Rotation = mat; + Asserts.AreEqual (mat, obj.Rotation, "Rotation after setter"); + var transposed3x3 = MatrixFloat3x3.Transpose ((MatrixFloat3x3) mat); + Asserts.AreEqual (transposed3x3, obj.Rotation3x3, "Rotation3x3 after setter"); + Asserts.AreEqual (transposed3x3, CFunctions.GetMatrixFloat3x3 (obj, "rotation"), "Rotation3x3 after setter native"); + + obj.Rotation3x3 = mat3x3; + Asserts.AreEqual (mat3x3, obj.Rotation3x3, "Rotation3x3 after setter 3x3"); + Asserts.AreEqual (mat3x3, CFunctions.GetMatrixFloat3x3 (obj, "rotation"), "Rotation3x3 after setter native 3x3"); + } + } + } +} + +#endif // __WATCHOS__ diff --git a/tests/monotouch-test/ModelIO/MDLCameraTest.cs b/tests/monotouch-test/ModelIO/MDLCameraTest.cs new file mode 100644 index 0000000000..4cf2bb4cef --- /dev/null +++ b/tests/monotouch-test/ModelIO/MDLCameraTest.cs @@ -0,0 +1,86 @@ +// +// MDLCamera Unit Tests +// +// Authors: +// Rolf Bjarne Kvinge +// +// Copyright 2017 Microsoft Inc. +// + +#if !__WATCHOS__ + +using System; +#if XAMCORE_2_0 +using CoreGraphics; +using Foundation; +#if !MONOMAC +using UIKit; +#endif +#if !__TVOS__ +using MultipeerConnectivity; +#endif +using ModelIO; +using ObjCRuntime; +#else +using MonoTouch.CoreGraphics; +using MonoTouch.Foundation; +#if !__TVOS__ +using MonoTouch.MultipeerConnectivity; +#endif +using MonoTouch.UIKit; +using MonoTouch.ModelIO; +using MonoTouch.ObjCRuntime; +#endif +using OpenTK; +using Simd; +using Bindings.Test; + +using NUnit.Framework; + +namespace MonoTouchFixtures.ModelIO +{ + + [TestFixture] + // we want the test to be available if we use the linker + [Preserve (AllMembers = true)] + public class MDCameraTest + { + [TestFixtureSetUp] + public void Setup () + { + TestRuntime.AssertXcodeVersion (7, 0); + } + + [Test] + public void ProjectionMatrix () + { + using (var obj = new MDLCamera ()) { + Assert.AreEqual (0.1f, obj.NearVisibilityDistance, 0.0001f, "NearVisibilityDistance"); + Assert.AreEqual (1000f, obj.FarVisibilityDistance, 0.0001f, "FarVisibilityDistance"); + Assert.AreEqual (54f, obj.FieldOfView, 0.0001f, "FieldOfView"); + var initialProjectionMatrix = new Matrix4 ( + 1.308407f, 0, 0, 0, + 0, 1.962611f, 0, 0, + 0, 0, -1.0002f, -1, + 0, 0, -0.20002f, 0 + ); + Asserts.AreEqual (initialProjectionMatrix, obj.ProjectionMatrix, 0.0001f, "Initial"); + Asserts.AreEqual (MatrixFloat4x4.Transpose ((MatrixFloat4x4) initialProjectionMatrix), obj.ProjectionMatrix4x4, 0.0001f, "Initial 4x4"); + Asserts.AreEqual (MatrixFloat4x4.Transpose ((MatrixFloat4x4) initialProjectionMatrix), CFunctions.GetMatrixFloat4x4 (obj, "projectionMatrix"), 0.0001f, "Initial native"); + + obj.NearVisibilityDistance = 1.0f; + var modifiedProjectionMatrix = new Matrix4 ( + 1.308407f, 0, 0, 0, + 0, 1.962611f, 0, 0, + 0, 0, -1.002002f, -1, + 0, 0, -2.002002f, 0 + ); + Asserts.AreEqual (modifiedProjectionMatrix, obj.ProjectionMatrix, 0.0001f, "Second"); + Asserts.AreEqual (MatrixFloat4x4.Transpose ((MatrixFloat4x4) modifiedProjectionMatrix), obj.ProjectionMatrix4x4, 0.0001f, "Second 4x4"); + Asserts.AreEqual (MatrixFloat4x4.Transpose ((MatrixFloat4x4) modifiedProjectionMatrix), CFunctions.GetMatrixFloat4x4 (obj, "projectionMatrix"), 0.0001f, "Second native"); + } + } + } +} + +#endif // !__WATCHOS__ diff --git a/tests/monotouch-test/ModelIO/MDLMaterialProperty.cs b/tests/monotouch-test/ModelIO/MDLMaterialProperty.cs index 7141bd500f..6ef2d6f65c 100644 --- a/tests/monotouch-test/ModelIO/MDLMaterialProperty.cs +++ b/tests/monotouch-test/ModelIO/MDLMaterialProperty.cs @@ -33,6 +33,10 @@ using MonoTouch.ModelIO; using MonoTouch.ObjCRuntime; #endif using OpenTK; +using Simd; +#if !TEST_BINDINGS_UNAVAILABLE +using Bindings.Test; +#endif using NUnit.Framework; namespace MonoTouchFixtures.ModelIO { @@ -101,6 +105,7 @@ namespace MonoTouchFixtures.ModelIO { Vector3 V3; Vector4 V4; Matrix4 M4; + MatrixFloat4x4 M4x4; MDLTextureSampler tsv; NSUrl url; @@ -122,6 +127,7 @@ namespace MonoTouchFixtures.ModelIO { V3 = new Vector3 (3, 4, 5); V4 = new Vector4 (6, 7, 8, 9); M4 = new Matrix4 (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + M4x4 = new MatrixFloat4x4 (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); tsv = new MDLTextureSampler (); url = new NSUrl ("http://xamarin.com"); @@ -187,6 +193,17 @@ namespace MonoTouchFixtures.ModelIO { using (var obj = new MDLMaterialProperty ("name", MDLMaterialSemantic.AmbientOcclusion, M4)) { Asserts.AreEqual (M4, obj.Matrix4x4, "7 Matrix4x4"); +#if !TEST_BINDINGS_UNAVAILABLE + Asserts.AreEqual (CFunctions.GetMatrixFloat4x4 (obj, "matrix4x4"), obj.MatrixFloat4x4, "7b MatrixFloat4x4"); +#endif + Asserts.AreEqual (MatrixFloat4x4.Transpose ((MatrixFloat4x4) M4), obj.MatrixFloat4x4, "7c MatrixFloat4x4"); + } + + using (var obj = new MDLMaterialProperty ("name", MDLMaterialSemantic.AmbientOcclusion, M4x4)) { +#if !TEST_BINDINGS_UNAVAILABLE + Asserts.AreEqual (CFunctions.GetMatrixFloat4x4 (obj, "matrix4x4"), obj.MatrixFloat4x4, "7' MatrixFloat4x4"); +#endif + Asserts.AreEqual (M4x4, obj.MatrixFloat4x4, "7'b MatrixFloat4x4"); } using (var obj = new MDLMaterialProperty ("name", MDLMaterialSemantic.AmbientOcclusion, V4)) { diff --git a/tests/monotouch-test/ModelIO/MDLStereoscopicCameraTest.cs b/tests/monotouch-test/ModelIO/MDLStereoscopicCameraTest.cs new file mode 100644 index 0000000000..ffa3b83594 --- /dev/null +++ b/tests/monotouch-test/ModelIO/MDLStereoscopicCameraTest.cs @@ -0,0 +1,96 @@ +// +// MDLStereoscopicCamera Unit Tests +// +// Authors: +// Rolf Bjarne Kvinge +// +// Copyright 2017 Microsoft Inc. +// + +#if !__WATCHOS__ + +using System; +#if XAMCORE_2_0 +using CoreGraphics; +using Foundation; +#if !MONOMAC +using UIKit; +#endif +#if !__TVOS__ +using MultipeerConnectivity; +#endif +using ModelIO; +using ObjCRuntime; +#else +using MonoTouch.CoreGraphics; +using MonoTouch.Foundation; +#if !__TVOS__ +using MonoTouch.MultipeerConnectivity; +#endif +using MonoTouch.UIKit; +using MonoTouch.ModelIO; +using MonoTouch.ObjCRuntime; +#endif +using OpenTK; +using Simd; +using Bindings.Test; +using NUnit.Framework; + +namespace MonoTouchFixtures.ModelIO +{ + [TestFixture] + // we want the test to be available if we use the linker + [Preserve (AllMembers = true)] + public class MDLStereoscopicCameraTest + { + [TestFixtureSetUp] + public void Setup () + { + TestRuntime.AssertXcodeVersion (7, 0); + } + + [Test] + public void Properties () + { + using (var obj = new MDLStereoscopicCamera ()) { + Assert.AreEqual (63f, obj.InterPupillaryDistance, "InterPupillaryDistance"); + Assert.AreEqual (0f, obj.LeftVergence, "LeftVergence"); + Assert.AreEqual (0f, obj.RightVergence, "RightVergence"); + Assert.AreEqual (0f, obj.Overlap, "Overlap"); + + var mat1 = new Matrix4 ( + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + -0.63f, 0, 0, 1); + Asserts.AreEqual (mat1, obj.LeftViewMatrix, "LeftViewMatrix"); + Asserts.AreEqual (MatrixFloat4x4.Transpose ((MatrixFloat4x4) mat1), obj.LeftViewMatrix4x4, "LeftViewMatrix4x4"); + Asserts.AreEqual (MatrixFloat4x4.Transpose ((MatrixFloat4x4) mat1), CFunctions.GetMatrixFloat4x4 (obj, "leftViewMatrix"), "LeftViewMatrix4x4 native"); + + var mat2 = new Matrix4 ( + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0.63f, 0, 0, 1); + Asserts.AreEqual (mat2, obj.RightViewMatrix, "RightViewMatrix"); + Asserts.AreEqual (MatrixFloat4x4.Transpose ((MatrixFloat4x4) mat2), obj.RightViewMatrix4x4, "RightViewMatrix4x4"); + Asserts.AreEqual (MatrixFloat4x4.Transpose ((MatrixFloat4x4) mat2), CFunctions.GetMatrixFloat4x4 (obj, "rightViewMatrix"), "RightViewMatrix4x4 native"); + + var mat3 = new Matrix4 ( + 1.308407f, 0, 0, 0, + 0, 1.962611f, 0, 0, + 0, 0, -1.0002f, -1, + 0, 0, -0.20002f, 0); + Asserts.AreEqual (mat3, obj.LeftProjectionMatrix, 0.0001f, "LeftProjectionMatrix"); + Asserts.AreEqual (MatrixFloat4x4.Transpose ((MatrixFloat4x4) mat3), obj.LeftProjectionMatrix4x4, 0.0001f, "LeftProjectionMatrix4x4"); + Asserts.AreEqual (MatrixFloat4x4.Transpose ((MatrixFloat4x4) mat3), CFunctions.GetMatrixFloat4x4 (obj, "leftProjectionMatrix"), 0.0001f, "LeftProjectionMatrix4x4 native"); + + Asserts.AreEqual (mat3, obj.RightProjectionMatrix, 0.0001f, "RightProjectionMatrix"); + Asserts.AreEqual (MatrixFloat4x4.Transpose ((MatrixFloat4x4) mat3), obj.RightProjectionMatrix4x4, 0.0001f, "RightProjectionMatrix4x4"); + Asserts.AreEqual (MatrixFloat4x4.Transpose ((MatrixFloat4x4) mat3), CFunctions.GetMatrixFloat4x4 (obj, "rightProjectionMatrix"), 0.0001f, "RightProjectionMatrix4x4 native"); + } + } + } +} + +#endif // !__WATCHOS__ diff --git a/tests/monotouch-test/ModelIO/MDLTransform.cs b/tests/monotouch-test/ModelIO/MDLTransform.cs index b169ecabac..4020dd2234 100644 --- a/tests/monotouch-test/ModelIO/MDLTransform.cs +++ b/tests/monotouch-test/ModelIO/MDLTransform.cs @@ -30,6 +30,10 @@ using MonoTouch.ModelIO; using MonoTouch.ObjCRuntime; #endif using OpenTK; +using Simd; +#if !TEST_BINDINGS_UNAVAILABLE +using Bindings.Test; +#endif using NUnit.Framework; namespace MonoTouchFixtures.ModelIO { @@ -120,6 +124,33 @@ namespace MonoTouchFixtures.ModelIO { obj.Rotation = V3; Asserts.AreEqual (V3, obj.Rotation, "Rotation 2"); } + + var m4 = new Matrix4 ( + 4, 0, 0, 0, + 0, 3, 0, 0, + 0, 0, 2, 0, + 2, 3, 4, 1); + using (var obj = new MDLTransform (m4)) { + Asserts.AreEqual (Vector3.Zero, obj.Rotation, "Rotation 3"); + Asserts.AreEqual (new Vector3 (4, 3, 2), obj.Scale, "Scale 3"); + Asserts.AreEqual (new Vector3 (2, 3, 4), obj.Translation, "Translation 3"); + Asserts.AreEqual (m4, obj.Matrix, 0.0001f, "Matrix 3"); + } + + var m4x4 = new MatrixFloat4x4 ( + 4, 0, 0, 2, + 0, 3, 0, 3, + 0, 0, 2, 4, + 0, 0, 0, 1); + using (var obj = new MDLTransform (m4x4)) { + Asserts.AreEqual (Vector3.Zero, obj.Rotation, "Rotation 4"); + Asserts.AreEqual (new Vector3 (4, 3, 2), obj.Scale, "Scale 4"); + Asserts.AreEqual (new Vector3 (2, 3, 4), obj.Translation, "Translation 4"); + Asserts.AreEqual (m4x4, obj.GetMatrix4x4 (), 0.0001f, "Matrix4x4 4"); +#if !TEST_BINDINGS_UNAVAILABLE + Asserts.AreEqual (m4x4, CFunctions.GetMatrixFloat4x4 (obj, "matrix"), 0.0001f, "Matrix4x4-native 4"); +#endif + } } [Test] @@ -157,6 +188,28 @@ namespace MonoTouchFixtures.ModelIO { Asserts.AreEqual (V3, obj.GetRotation (0), "RotationAtTime"); } } + + [Test] + public void GetRotationMatrixTest () + { + var matrix = Matrix4.Identity; + var V3 = new Vector3 (1, 0, 0); + + using (var obj = new MDLTransform (matrix)) { + obj.SetRotation (V3, 0); + var expected = new MatrixFloat4x4 ( + 1, 0, 0, 0, + 0, (float) Math.Cos (1.0f), (float) -Math.Sin(1.0f), 0, + 0, (float) Math.Sin (1.0f), (float) Math.Cos(1.0f), 0, + 0, 0, 0, 1 + ); + Asserts.AreEqual ((Matrix4) MatrixFloat4x4.Transpose (expected), obj.GetRotationMatrix (0), 0.00001f, "GetRotationMatrix"); + Asserts.AreEqual (expected, obj.GetRotationMatrix4x4 (0), 0.00001f, "GetRotationMatrix4x4"); +#if !TEST_BINDINGS_UNAVAILABLE + Asserts.AreEqual (expected, CFunctions.MDLTransform_GetRotationMatrix (obj, 0), 0.00001f, "GetRotationMatrix4x4 native"); +#endif + } + } } } diff --git a/tests/monotouch-test/ModelIO/MDLTransformComponentTest.cs b/tests/monotouch-test/ModelIO/MDLTransformComponentTest.cs new file mode 100644 index 0000000000..3c676fe9d1 --- /dev/null +++ b/tests/monotouch-test/ModelIO/MDLTransformComponentTest.cs @@ -0,0 +1,207 @@ +// +// MDLTransformComponent Unit Tests +// +// Authors: +// Rolf Bjarne Kvinge +// +// Copyright 2017 Microsoft inc +// + +#if !__WATCHOS__ + +using System; +#if XAMCORE_2_0 +using Foundation; +#if !MONOMAC +using UIKit; +#endif +#if !__TVOS__ +using MultipeerConnectivity; +#endif +using ModelIO; +using ObjCRuntime; +#else +using MonoTouch.Foundation; +#if !__TVOS__ +using MonoTouch.MultipeerConnectivity; +#endif +using MonoTouch.UIKit; +using MonoTouch.ModelIO; +using MonoTouch.ObjCRuntime; +#endif +using OpenTK; +using Simd; +using Bindings.Test; +using NUnit.Framework; + +namespace MonoTouchFixtures.ModelIO +{ + + [TestFixture] + // we want the test to be available if we use the linker + [Preserve (AllMembers = true)] + public class MDLTransformComponentTest + { + [TestFixtureSetUp] + public void Setup () + { + TestRuntime.AssertXcodeVersion (7, 0); + } + + [Test] + public void MatrixTest () + { + var m4 = new Matrix4 (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + var m4x4 = (MatrixFloat4x4) m4; + + using (var obj = new MDLTransform ()) { + // identity + Asserts.AreEqual (Matrix4.Identity, obj.Matrix, "Initial identity"); + Asserts.AreEqual (MatrixFloat4x4.Identity, obj.GetMatrix4x4 (), "Initial identity 4x4"); + Asserts.AreEqual (MatrixFloat4x4.Identity, CFunctions.GetMatrixFloat4x4 (obj, "matrix"), "Initial identity native"); + + // translate the transform somewhere + obj.SetTranslation (new Vector3 (2, 2, 2), 0); + + // the matrix should now be a translation matrix like this: + // 1 0 0 0 2 + // 0 1 0 0 2 + // 0 0 1 0 2 + // 0 0 0 1 0 + // but since Matrix4 is transposed when compared to MatrixFloat4x4, we get this: + + Asserts.AreEqual (new Matrix4 ( + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 2, 2, 2, 1 + ), obj.Matrix, "Translated"); + + // The 4x4 version is correct: + Asserts.AreEqual (new Matrix4 ( + 1, 0, 0, 2, + 0, 1, 0, 2, + 0, 0, 1, 2, + 0, 0, 0, 1 + ), obj.GetMatrix4x4 (), "Translated 4x4"); + + // Let's set the matrix to something (different from the identity matrix) + obj.Matrix = m4; + + // And the matrix resets to the identify matrix. + Asserts.AreEqual (Matrix4.Identity, obj.Matrix, "After set_Matrix"); + + // Translate again + obj.SetTranslation (new Vector3 (3, 3, 3), 0); + + // Set the matrix using a 4x4 matrix + obj.SetMatrix4x4 (m4x4); + + // And we still get the identity matrix back + Asserts.AreEqual (MatrixFloat4x4.Identity, obj.GetMatrix4x4 (), "After set_Matrix 2"); + } + } + + [Test] + public void LocalTransformTest () + { + var m4 = new Matrix4 (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + var m4x4 = (MatrixFloat4x4) m4; + + using (var obj = new MDLTransform ()) { + var component = (IMDLTransformComponent) obj; + // identity + Asserts.AreEqual (Matrix4.Identity, component.GetLocalTransform (0), "Initial identity"); + Asserts.AreEqual (MatrixFloat4x4.Identity, component.GetLocalTransform4x4 (0), "Initial identity 4x4"); + Asserts.AreEqual (MatrixFloat4x4.Identity, CFunctions.MDLTransformComponent_GetLocalTransform (component, 0), "Initial identity native"); + + // translate the transform somewhere + obj.SetTranslation (new Vector3 (2, 2, 2), 0); + + // the local transform should now be a translation matrix like this: + // 1 0 0 0 2 + // 0 1 0 0 2 + // 0 0 1 0 2 + // 0 0 0 1 0 + // but since Matrix4 is transposed when compared to MatrixFloat4x4, we get this: + + Asserts.AreEqual (new Matrix4 ( + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 2, 2, 2, 1 + ), component.GetLocalTransform (0), "Translated"); + + // The 4x4 version is correct: + Asserts.AreEqual (new Matrix4 ( + 1, 0, 0, 2, + 0, 1, 0, 2, + 0, 0, 1, 2, + 0, 0, 0, 1 + ), component.GetLocalTransform4x4 (0), "Translated 4x4"); + + // Let's set the local transform at time 1 to something (different from the identity matrix) + component.SetLocalTransform (m4, 1); + + // At time 1 the transform matrix is now the identity matrix + Asserts.AreEqual (Matrix4.Identity, component.GetLocalTransform (1), "After SetLocalTransform at 1"); + + // At time 0.5 we get a middle ground + Asserts.AreEqual (new Matrix4 ( + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 1, 1, 1, 1 + ), component.GetLocalTransform (0.5), 0.00001f, "AfterSetLocalTransform at 0.5"); + + // And at time 0 we still have the translated matrix. + Asserts.AreEqual (new Matrix4 ( + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 2, 2, 2, 1 + ), component.GetLocalTransform (0), 0.00001f, "AfterSetLocalTransform at 0"); + + // Let's set the local transform at all times + component.SetLocalTransform (m4); + + // And we get the identity matrix back at all times + Asserts.AreEqual (Matrix4.Identity, component.GetLocalTransform (0), "Second identity at 0"); + Asserts.AreEqual (Matrix4.Identity, component.GetLocalTransform (1), "Second identity at 1"); + + // Translate again + obj.SetTranslation (new Vector3 (3, 3, 3), 0); + + // Set the local transform using a 4x4 matrix + component.SetLocalTransform4x4 (m4x4, 1); + + // And at time 0.5 we still get a middle ground + // The numbers are different now because the translation matrix was different, + // and the matrix is correct because we're checking the 4x4 version. + Asserts.AreEqual (new MatrixFloat4x4 ( + 1, 0, 0, 1.5f, + 0, 1, 0, 1.5f, + 0, 0, 1, 1.5f, + 0, 0, 0, 1 + ), component.GetLocalTransform4x4 (0.5), 0.00001f, "AfterSetLocalTransform4x4 at 0.5"); + } + } + + [Test] + public void CreateGlobalTransformTest () + { + Matrix4 m4; + MatrixFloat4x4 m4x4; + + using (var obj = new MDLObject ()) { + m4 = MDLTransform.CreateGlobalTransform (obj, 0); + Asserts.AreEqual ((Matrix4) MatrixFloat4x4.Transpose (CFunctions.MDLTransform_CreateGlobalTransform (obj, 0)), m4, "CreateGlobalTransform"); + + m4x4 = MDLTransform.CreateGlobalTransform4x4 (obj, 0); + Asserts.AreEqual (CFunctions.MDLTransform_CreateGlobalTransform (obj, 0), m4, "CreateGlobalTransform4x4"); + } + } + } +} + +#endif // !__WATCHOS__ diff --git a/tests/monotouch-test/Simd/MatrixFloat2x2Test.cs b/tests/monotouch-test/Simd/MatrixFloat2x2Test.cs new file mode 100644 index 0000000000..72bf6c71bc --- /dev/null +++ b/tests/monotouch-test/Simd/MatrixFloat2x2Test.cs @@ -0,0 +1,315 @@ + +using System; +using System.Diagnostics; + +using Foundation; +using ObjCRuntime; + +using OpenTK; +using Simd; + +using NUnit.Framework; + +namespace MonoTouchFixtures.Simd +{ + [TestFixture] + [Preserve (AllMembers = true)] + public class MatrixFloat2x2Test + { + [Test] + public void Identity () + { + var identity = new MatrixFloat2x2 { + M11 = 1f, + M22 = 1f, + }; + Asserts.AreEqual (identity, MatrixFloat2x2.Identity, "identity"); + Asserts.AreEqual (Matrix2.Identity, MatrixFloat2x2.Identity, "opentk identity"); + } + + [Test] + public void ColumnConstructor () + { + var expected = GetTestMatrix (); + var actual = new MatrixFloat2x2 ( + new Vector2 (expected.R0C0, expected.R1C0), + new Vector2 (expected.R0C1, expected.R1C1) + ); + Asserts.AreEqual (expected, actual, "ctor 1"); + } + + [Test] + public void ElementConstructor () + { + var expected = GetTestMatrix (); + var actual = new MatrixFloat2x2 (expected.R0C0, expected.R0C1, + expected.R1C0, expected.R1C1); + Asserts.AreEqual (expected, actual, "ctor 1"); + + } + + [Test] + public void Determinant () + { + var expected = GetTestMatrix (); + var actual = (MatrixFloat2x2) expected; + Assert.AreEqual (expected.Determinant, actual.Determinant, 0.000001f, "determinant\n" + actual); + } + + [Test] + public void Elements () + { + var expected = GetTestMatrix (); + var actual = (MatrixFloat2x2) expected; + + Assert.AreEqual (expected.R0C0, actual.M11, "m11 getter"); + Assert.AreEqual (expected.R0C1, actual.M12, "m12 getter"); + Assert.AreEqual (expected.R1C0, actual.M21, "m21 getter"); + Assert.AreEqual (expected.R1C1, actual.M22, "m22 getter"); + + var newExpected = GetTestMatrix (); + actual.M11 = newExpected.R0C0; + actual.M12 = newExpected.R0C1; + actual.M21 = newExpected.R1C0; + actual.M22 = newExpected.R1C1; + Assert.AreEqual (newExpected.R0C0, actual.M11, "m11 setter"); + Assert.AreEqual (newExpected.R0C1, actual.M12, "m12 setter"); + Assert.AreEqual (newExpected.R1C0, actual.M21, "m21 setter"); + Assert.AreEqual (newExpected.R1C1, actual.M22, "m22 setter"); + } + + [Test] + public void TransposeInstance () + { + var expected = GetTestMatrix (); + var actual = (MatrixFloat2x2) expected; + + expected.Transpose (); + actual.Transpose (); + + Asserts.AreEqual (expected, actual, "transpose"); + } + + [Test] + public void TransposeStatic () + { + var input = GetTestMatrix (); + var inputSimd = (MatrixFloat2x2) input; + + Matrix2 expected; + Matrix2.Transpose (ref input, out expected); + var actual = MatrixFloat2x2.Transpose (inputSimd); + + Asserts.AreEqual (expected, actual, "transpose"); + + input = GetTestMatrix (); + inputSimd = (MatrixFloat2x2) input; + Matrix2.Transpose (ref input, out expected); + MatrixFloat2x2.Transpose (ref inputSimd, out actual); + Asserts.AreEqual (expected, actual, "transpose out/ref"); + } + + [Test] + public void TransposeStatic_ByRef () + { + var input = GetTestMatrix (); + var inputSimd = (MatrixFloat2x2) input; + + Matrix2 expected; + MatrixFloat2x2 actual; + + Matrix2.Transpose (ref input, out expected); + MatrixFloat2x2.Transpose (ref inputSimd, out actual); + Asserts.AreEqual (expected, actual, "transpose out/ref"); + } + + [Test] + public void Multiply () + { + var inputL = GetTestMatrix (); + var inputR = GetTestMatrix (); + var inputSimdL = (MatrixFloat2x2) inputL; + var inputSimdR = (MatrixFloat2x2) inputR; + Matrix2 expected; + Matrix2.Multiply (ref inputR, ref inputL, out expected); // OpenTK.Matrix2 got left/right mixed up... + var actual = MatrixFloat2x2.Multiply (inputSimdL, inputSimdR); + + Asserts.AreEqual (expected, actual, "multiply"); + } + + [Test] + public void Multiply_ByRef () + { + var inputL = GetTestMatrix (); + var inputR = GetTestMatrix (); + var inputSimdL = (MatrixFloat2x2) inputL; + var inputSimdR = (MatrixFloat2x2) inputR; + Matrix2 expected; + MatrixFloat2x2 actual; + + Matrix2.Multiply (ref inputR, ref inputL, out expected); // OpenTK.Matrix2 got left/right mixed up... + MatrixFloat2x2.Multiply (ref inputSimdL, ref inputSimdR, out actual); + + Asserts.AreEqual (expected, actual, "multiply"); + } + + + [Test] + public void Multiply_Operator () + { + var inputL = GetTestMatrix (); + var inputR = GetTestMatrix (); + var inputSimdL = (MatrixFloat2x2) inputL; + var inputSimdR = (MatrixFloat2x2) inputR; + Matrix2 expected; + Matrix2.Multiply (ref inputR, ref inputL, out expected); // OpenTK.Matrix2 got left/right mixed up... + var actual = inputSimdL * inputSimdR; + + Asserts.AreEqual (expected, actual, "multiply"); + } + + [Test] + public void Equality_Operator () + { + var inputL = GetTestMatrix (); + var inputR = GetTestMatrix (); + var inputSimdL = (MatrixFloat2x2) inputL; + var inputSimdR = (MatrixFloat2x2) inputR; + + // matrices are different + Assert.AreEqual (inputL.Equals (inputR), inputSimdL == inputSimdR, "inequality"); + Assert.IsFalse (inputL.Equals (inputR), "inequality 2 expected"); + Assert.IsFalse (inputSimdL == inputSimdR, "inequality 2 actual"); + + inputL = inputR; + inputSimdL = inputSimdR; + // matrices are identical + Assert.AreEqual (inputL.Equals (inputR), inputSimdL == inputSimdR, "equality"); + Assert.IsTrue (inputL.Equals (inputR), "equality 2 expected"); + Assert.IsTrue (inputSimdL == inputSimdR, "equality 2 actual"); + + Assert.IsTrue (MatrixFloat2x2.Identity == (MatrixFloat2x2) Matrix2.Identity, "identity equality"); + } + + [Test] + public void Inequality_Operator () + { + var inputL = GetTestMatrix (); + var inputR = GetTestMatrix (); + var inputSimdL = (MatrixFloat2x2) inputL; + var inputSimdR = (MatrixFloat2x2) inputR; + + // matrices are different + Assert.AreEqual (!inputL.Equals (inputR), inputSimdL != inputSimdR, "inequality"); + Assert.IsTrue (!inputL.Equals (inputR), "inequality 2 expected"); + Assert.IsTrue (inputSimdL != inputSimdR, "inequality 2 actual"); + + inputL = inputR; + inputSimdL = inputSimdR; + // matrices are identical + Assert.AreEqual (!inputL.Equals (inputR), inputSimdL != inputSimdR, "equality"); + Assert.IsFalse (!inputL.Equals (inputR), "equality 2 expected"); + Assert.IsFalse (inputSimdL != inputSimdR, "equality 2 actual"); + + Assert.IsFalse (MatrixFloat2x2.Identity != (MatrixFloat2x2) Matrix2.Identity, "identity equality"); + } + + [Test] + public void Explicit_Operator_ToMatrix2 () + { + var expected = (MatrixFloat2x2) GetTestMatrix (); + var actual = (Matrix2) expected; + + Asserts.AreEqual (expected, actual, "tomatrix2"); + + actual = (Matrix2) MatrixFloat2x2.Identity; + Asserts.AreEqual (MatrixFloat2x2.Identity, actual, "tomatrix2 identity"); + Asserts.AreEqual (Matrix2.Identity, actual, "tomatrix2 identity2"); + } + + [Test] + public void Explicit_Operator_FromMatrix2 () + { + var expected = GetTestMatrix (); + var actual = (MatrixFloat2x2) expected; + + Asserts.AreEqual (expected, actual, "frommatrix2"); + + actual = (MatrixFloat2x2) Matrix2.Identity; + Asserts.AreEqual (MatrixFloat2x2.Identity, actual, "tomatrix2 identity"); + Asserts.AreEqual (Matrix2.Identity, actual, "tomatrix2 identity2"); + } + + [Test] + public void ToStringTest () + { + var actual = new MatrixFloat2x2 (1, 2, 3, 4); + + Assert.AreEqual ("(1, 2)\n(3, 4)", actual.ToString (), "tostring"); + } + + // GetHashCode doesn't have to be identical, so no need to test + + [Test] + public void Equals_Object () + { + var expectedA = GetTestMatrix (); + var expectedB = GetTestMatrix (); + var actualA = (MatrixFloat2x2) expectedA; + var actualB = (MatrixFloat2x2) expectedB; + + Assert.IsTrue (actualA.Equals ((object) actualA), "self"); + Assert.IsFalse (actualA.Equals ((object) actualB), "other"); + Assert.IsFalse (actualA.Equals (null), "null"); + Assert.IsFalse (actualA.Equals (expectedA), "other type"); + } + + [Test] + public void Equals_Matrix () + { + var expectedA = GetTestMatrix (); + var expectedB = GetTestMatrix (); + var actualA = (MatrixFloat2x2) expectedA; + var actualB = (MatrixFloat2x2) expectedB; + + Assert.IsTrue (actualA.Equals (actualA), "self"); + Assert.IsFalse (actualA.Equals (actualB), "other"); + } + + // A collection of test matrices. + // + // I initially tried randomly generating test matrices, but it turns out + // there are accumulative computational differences in the different algorithms + // between Matrix2 and MatrixFloat2x2. Since the differences are accumulative, + // I couldn't find a minimal sensible delta values when comparing + // matrices. + // + // So I just serialized a few matrices that were randomly generated, and + // these have been tested to not produce accumulative computational differences. + // + static Matrix2 [] test_matrices = new [] { + new Matrix2 (3, 5, 7, 11), + new Matrix2 (5, 7, 11, 13), + new Matrix2 (7, 11, 13, 17), + new Matrix2 (0.1532144f, 0.5451511f, 0.2004739f, 0.8351463f), + new Matrix2 (0.7717745f, 0.559364f, 0.00918373f, 0.6579159f), + new Matrix2 (0.2023053f, 0.4701468f, 0.6618567f, 0.7685714f), + new Matrix2 (9.799572E+08f, 1.64794E+09f, 1.117296E+09f, 1.239858E+09f), + new Matrix2 (1.102396E+09f, 3.082477E+08f, 1.126484E+09f, 5.022931E+08f), + new Matrix2 (2.263112E+08f, 8.79644E+08f, 1.303282E+09f, 1.654159E+09f), + new Matrix2 (0.4904693f, 0.841727f, 0.2294401f, 0.5736054f), + new Matrix2 (0.1252193f, 0.08986127f, 0.3407605f, 0.9144857f), + new Matrix2 (8.176959E+08f, 1.386156E+09f, 5.956444E+08f, 4.210506E+08f), + new Matrix2 (0.006755914f, 0.07464754f, 0.287938f, 0.3724834f), + }; + + static int counter; + internal static Matrix2 GetTestMatrix () + { + counter++; + if (counter == test_matrices.Length) + counter = 0; + return test_matrices [counter]; + } + } +} diff --git a/tests/monotouch-test/Simd/MatrixFloat3x3Test.cs b/tests/monotouch-test/Simd/MatrixFloat3x3Test.cs new file mode 100644 index 0000000000..ad936d4847 --- /dev/null +++ b/tests/monotouch-test/Simd/MatrixFloat3x3Test.cs @@ -0,0 +1,333 @@ + +using System; +using System.Diagnostics; + +using Foundation; +using ObjCRuntime; + +using OpenTK; +using Simd; + +using NUnit.Framework; + +namespace MonoTouchFixtures.Simd +{ + [TestFixture] + [Preserve (AllMembers = true)] + public class MatrixFloat3x3Test + { + [Test] + public void Identity () + { + var identity = new MatrixFloat3x3 { + M11 = 1f, + M22 = 1f, + M33 = 1f, + }; + Asserts.AreEqual (identity, MatrixFloat3x3.Identity, "identity"); + Asserts.AreEqual (Matrix3.Identity, MatrixFloat3x3.Identity, "opentk identity"); + } + + [Test] + public void ColumnConstructor () + { + var expected = GetTestMatrix (); + var actual = new MatrixFloat3x3 ( + new Vector3 (expected.R0C0, expected.R1C0, expected.R2C0), + new Vector3 (expected.R0C1, expected.R1C1, expected.R2C1), + new Vector3 (expected.R0C2, expected.R1C2, expected.R2C2) + ); + Asserts.AreEqual (expected, actual, "ctor 1"); + } + + [Test] + public void ElementConstructor () + { + var expected = GetTestMatrix (); + var actual = new MatrixFloat3x3 (expected.R0C0, expected.R0C1, expected.R0C2, + expected.R1C0, expected.R1C1, expected.R1C2, + expected.R2C0, expected.R2C1, expected.R2C2); + Asserts.AreEqual (expected, actual, "ctor 1"); + + } + + [Test] + public void Determinant () + { + var expected = GetTestMatrix (); + var actual = (MatrixFloat3x3) expected; + Assert.AreEqual (expected.Determinant, actual.Determinant, 0.000001f, "determinant\n" + actual); + } + + [Test] + public void Elements () + { + var expected = GetTestMatrix (); + var actual = (MatrixFloat3x3) expected; + + Assert.AreEqual (expected.R0C0, actual.M11, "m11 getter"); + Assert.AreEqual (expected.R0C1, actual.M12, "m12 getter"); + Assert.AreEqual (expected.R0C2, actual.M13, "m13 getter"); + Assert.AreEqual (expected.R1C0, actual.M21, "m21 getter"); + Assert.AreEqual (expected.R1C1, actual.M22, "m22 getter"); + Assert.AreEqual (expected.R1C2, actual.M23, "m23 getter"); + Assert.AreEqual (expected.R2C0, actual.M31, "m31 getter"); + Assert.AreEqual (expected.R2C1, actual.M32, "m32 getter"); + Assert.AreEqual (expected.R2C2, actual.M33, "m33 getter"); + + var newExpected = GetTestMatrix (); + actual.M11 = newExpected.R0C0; + actual.M12 = newExpected.R0C1; + actual.M13 = newExpected.R0C2; + actual.M21 = newExpected.R1C0; + actual.M22 = newExpected.R1C1; + actual.M23 = newExpected.R1C2; + actual.M31 = newExpected.R2C0; + actual.M32 = newExpected.R2C1; + actual.M33 = newExpected.R2C2; + Assert.AreEqual (newExpected.R0C0, actual.M11, "m11 setter"); + Assert.AreEqual (newExpected.R0C1, actual.M12, "m12 setter"); + Assert.AreEqual (newExpected.R0C2, actual.M13, "m13 setter"); + Assert.AreEqual (newExpected.R1C0, actual.M21, "m21 setter"); + Assert.AreEqual (newExpected.R1C1, actual.M22, "m22 setter"); + Assert.AreEqual (newExpected.R1C2, actual.M23, "m23 setter"); + Assert.AreEqual (newExpected.R2C0, actual.M31, "m31 setter"); + Assert.AreEqual (newExpected.R2C1, actual.M32, "m32 setter"); + Assert.AreEqual (newExpected.R2C2, actual.M33, "m33 setter"); + } + + [Test] + public void TransposeInstance () + { + var expected = GetTestMatrix (); + var actual = (MatrixFloat3x3) expected; + + expected.Transpose (); + actual.Transpose (); + + Asserts.AreEqual (expected, actual, "transpose"); + } + + [Test] + public void TransposeStatic () + { + var input = GetTestMatrix (); + var inputSimd = (MatrixFloat3x3) input; + + Matrix3 expected; + Matrix3.Transpose (ref input, out expected); + var actual = MatrixFloat3x3.Transpose (inputSimd); + + Asserts.AreEqual (expected, actual, "transpose"); + + input = GetTestMatrix (); + inputSimd = (MatrixFloat3x3) input; + Matrix3.Transpose (ref input, out expected); + MatrixFloat3x3.Transpose (ref inputSimd, out actual); + Asserts.AreEqual (expected, actual, "transpose out/ref"); + } + + [Test] + public void TransposeStatic_ByRef () + { + var input = GetTestMatrix (); + var inputSimd = (MatrixFloat3x3) input; + + Matrix3 expected; + MatrixFloat3x3 actual; + + Matrix3.Transpose (ref input, out expected); + MatrixFloat3x3.Transpose (ref inputSimd, out actual); + Asserts.AreEqual (expected, actual, "transpose out/ref"); + } + + [Test] + public void Multiply () + { + var inputL = GetTestMatrix (); + var inputR = GetTestMatrix (); + var inputSimdL = (MatrixFloat3x3) inputL; + var inputSimdR = (MatrixFloat3x3) inputR; + Matrix3 expected; + Matrix3.Multiply (ref inputR, ref inputL, out expected); // OpenTK.Matrix3 got left/right mixed up... + var actual = MatrixFloat3x3.Multiply (inputSimdL, inputSimdR); + + Asserts.AreEqual (expected, actual, "multiply"); + } + + [Test] + public void Multiply_ByRef () + { + var inputL = GetTestMatrix (); + var inputR = GetTestMatrix (); + var inputSimdL = (MatrixFloat3x3) inputL; + var inputSimdR = (MatrixFloat3x3) inputR; + Matrix3 expected; + MatrixFloat3x3 actual; + + Matrix3.Multiply (ref inputR, ref inputL, out expected); // OpenTK.Matrix3 got left/right mixed up... + MatrixFloat3x3.Multiply (ref inputSimdL, ref inputSimdR, out actual); + + Asserts.AreEqual (expected, actual, "multiply"); + } + + + [Test] + public void Multiply_Operator () + { + var inputL = GetTestMatrix (); + var inputR = GetTestMatrix (); + var inputSimdL = (MatrixFloat3x3) inputL; + var inputSimdR = (MatrixFloat3x3) inputR; + Matrix3 expected; + Matrix3.Multiply (ref inputR, ref inputL, out expected); // OpenTK.Matrix3 got left/right mixed up... + var actual = inputSimdL * inputSimdR; + + Asserts.AreEqual (expected, actual, "multiply"); + } + + [Test] + public void Equality_Operator () + { + var inputL = GetTestMatrix (); + var inputR = GetTestMatrix (); + var inputSimdL = (MatrixFloat3x3) inputL; + var inputSimdR = (MatrixFloat3x3) inputR; + + // matrices are different + Assert.AreEqual (inputL.Equals (inputR), inputSimdL == inputSimdR, "inequality"); + Assert.IsFalse (inputL.Equals (inputR), "inequality 2 expected"); + Assert.IsFalse (inputSimdL == inputSimdR, "inequality 2 actual"); + + inputL = inputR; + inputSimdL = inputSimdR; + // matrices are identical + Assert.AreEqual (inputL.Equals (inputR), inputSimdL == inputSimdR, "equality"); + Assert.IsTrue (inputL.Equals (inputR), "equality 2 expected"); + Assert.IsTrue (inputSimdL == inputSimdR, "equality 2 actual"); + + Assert.IsTrue (MatrixFloat3x3.Identity == (MatrixFloat3x3) Matrix3.Identity, "identity equality"); + } + + [Test] + public void Inequality_Operator () + { + var inputL = GetTestMatrix (); + var inputR = GetTestMatrix (); + var inputSimdL = (MatrixFloat3x3) inputL; + var inputSimdR = (MatrixFloat3x3) inputR; + + // matrices are different + Assert.AreEqual (!inputL.Equals (inputR), inputSimdL != inputSimdR, "inequality"); + Assert.IsTrue (!inputL.Equals (inputR), "inequality 2 expected"); + Assert.IsTrue (inputSimdL != inputSimdR, "inequality 2 actual"); + + inputL = inputR; + inputSimdL = inputSimdR; + // matrices are identical + Assert.AreEqual (!inputL.Equals (inputR), inputSimdL != inputSimdR, "equality"); + Assert.IsFalse (!inputL.Equals (inputR), "equality 2 expected"); + Assert.IsFalse (inputSimdL != inputSimdR, "equality 2 actual"); + + Assert.IsFalse (MatrixFloat3x3.Identity != (MatrixFloat3x3) Matrix3.Identity, "identity equality"); + } + + [Test] + public void Explicit_Operator_ToMatrix3 () + { + var expected = (MatrixFloat3x3) GetTestMatrix (); + var actual = (Matrix3) expected; + + Asserts.AreEqual (expected, actual, "tomatrix4"); + + actual = (Matrix3) MatrixFloat3x3.Identity; + Asserts.AreEqual (MatrixFloat3x3.Identity, actual, "tomatrix4 identity"); + Asserts.AreEqual (Matrix3.Identity, actual, "tomatrix4 identity2"); + } + + [Test] + public void Explicit_Operator_FromMatrix3 () + { + var expected = GetTestMatrix (); + var actual = (MatrixFloat3x3) expected; + + Asserts.AreEqual (expected, actual, "frommatrix4"); + + actual = (MatrixFloat3x3) Matrix3.Identity; + Asserts.AreEqual (MatrixFloat3x3.Identity, actual, "tomatrix4 identity"); + Asserts.AreEqual (Matrix3.Identity, actual, "tomatrix4 identity2"); + } + + [Test] + public void ToStringTest () + { + var actual = new MatrixFloat3x3 (1, 2, 3, 4, 5, 6, 7, 8, 9); + + Assert.AreEqual ("(1, 2, 3)\n(4, 5, 6)\n(7, 8, 9)", actual.ToString (), "tostring"); + } + + // GetHashCode doesn't have to be identical, so no need to test + + [Test] + public void Equals_Object () + { + var expectedA = GetTestMatrix (); + var expectedB = GetTestMatrix (); + var actualA = (MatrixFloat3x3) expectedA; + var actualB = (MatrixFloat3x3) expectedB; + + Assert.IsTrue (actualA.Equals ((object) actualA), "self"); + Assert.IsFalse (actualA.Equals ((object) actualB), "other"); + Assert.IsFalse (actualA.Equals (null), "null"); + Assert.IsFalse (actualA.Equals (expectedA), "other type"); + } + + [Test] + public void Equals_Matrix () + { + var expectedA = GetTestMatrix (); + var expectedB = GetTestMatrix (); + var actualA = (MatrixFloat3x3) expectedA; + var actualB = (MatrixFloat3x3) expectedB; + + Assert.IsTrue (actualA.Equals (actualA), "self"); + Assert.IsFalse (actualA.Equals (actualB), "other"); + } + + // A collection of test matrices. + // + // I initially tried randomly generating test matrices, but it turns out + // there are accumulative computational differences in the different algorithms + // between Matrix3 and MatrixFloat3x3. Since the differences are accumulative, + // I couldn't find a minimal sensible delta values when comparing + // matrices. + // + // So I just serialized a few matrices that were randomly generated, and + // these have been tested to not produce accumulative computational differences. + // + static Matrix3 [] test_matrices = new [] { + new Matrix3 (3, 5, 7, 11, 13, 17, 19, 23, 29), + new Matrix3 (5, 7, 11, 13, 17, 19, 23, 29, 31), + new Matrix3 (7, 11, 13, 17, 19, 23, 29, 31, 37), + new Matrix3 (0.1532144f, 0.5451511f, 0.2004739f, 0.8351463f, 0.9884372f, 0.1313103f, 0.3327205f, 0.01164342f, 0.6563147f), + new Matrix3 (0.7717745f, 0.559364f, 0.00918373f, 0.6579159f, 0.123461f, 0.9993145f, 0.5487496f, 0.2823398f, 0.9710717f), + new Matrix3 (0.2023053f, 0.4701468f, 0.6618567f, 0.7685714f, 0.8561344f, 0.009231919f, 0.6150167f, 0.7542298f, 0.550727f), + new Matrix3 (9.799572E+08f, 1.64794E+09f, 1.117296E+09f, 1.239858E+09f, 6.389504E+07f, 1.172175E+09f, 1.399567E+09f, 1.187143E+09f, 3.729208E+07f), + new Matrix3 (1.102396E+09f, 3.082477E+08f, 1.126484E+09f, 5.022931E+08f, 1.966322E+09f, 1.1814E+09f, 8.464673E+08f, 1.940651E+09f, 1.229937E+09f), + new Matrix3 (2.263112E+08f, 8.79644E+08f, 1.303282E+09f, 1.654159E+09f, 3.705524E+08f, 1.984941E+09f, 2.175935E+07f, 4.633518E+08f, 1.801243E+09f), + new Matrix3 (0.4904693f, 0.841727f, 0.2294401f, 0.5736054f, 0.5406881f, 0.2172498f, 0.1261143f, 0.6736677f, 0.4570194f), + new Matrix3 (0.1252193f, 0.08986127f, 0.3407605f, 0.9144857f, 0.340791f, 0.2192288f, 0.5144276f, 0.01813344f, 0.07687104f), + new Matrix3 (8.176959E+08f, 1.386156E+09f, 5.956444E+08f, 4.210506E+08f, 1.212676E+09f, 4.131035E+08f, 1.032453E+09f, 2.074689E+08f, 1.536594E+09f), + new Matrix3 (0.006755914f, 0.07464754f, 0.287938f, 0.3724834f, 0.1496783f, 0.6224982f, 0.7150125f, 0.5554719f, 0.4638171f), + }; + + static int counter; + internal static Matrix3 GetTestMatrix () + { + counter++; + if (counter == test_matrices.Length) + counter = 0; + return test_matrices [counter]; + } + } +} diff --git a/tests/monotouch-test/Simd/MatrixFloat4x4Test.cs b/tests/monotouch-test/Simd/MatrixFloat4x4Test.cs new file mode 100644 index 0000000000..c0f351af14 --- /dev/null +++ b/tests/monotouch-test/Simd/MatrixFloat4x4Test.cs @@ -0,0 +1,348 @@ + +using System; +using System.Diagnostics; + +using Foundation; +using ObjCRuntime; + +using OpenTK; +using Simd; + +using NUnit.Framework; + +namespace MonoTouchFixtures.Simd +{ + [TestFixture] + [Preserve (AllMembers = true)] + public class MatrixFloat4x4Test + { + [Test] + public void Identity () + { + var identity = new MatrixFloat4x4 { + M11 = 1f, + M22 = 1f, + M33 = 1f, + M44 = 1f, + }; + Asserts.AreEqual (identity, MatrixFloat4x4.Identity, "identity"); + Asserts.AreEqual (Matrix4.Identity, MatrixFloat4x4.Identity, "opentk identity"); + } + + [Test] + public void ColumnConstructor () + { + var expected = GetTestMatrix (); + var actual = new MatrixFloat4x4 (expected.Column0, expected.Column1, expected.Column2, expected.Column3); + Asserts.AreEqual (expected, actual, "ctor 1"); + } + + [Test] + public void ElementConstructor () + { + var expected = GetTestMatrix (); + var actual = new MatrixFloat4x4 (expected.M11, expected.M12, expected.M13, expected.M14, + expected.M21, expected.M22, expected.M23, expected.M24, + expected.M31, expected.M32, expected.M33, expected.M34, + expected.M41, expected.M42, expected.M43, expected.M44); + Asserts.AreEqual (expected, actual, "ctor 1"); + + } + + [Test] + public void Determinant () + { + var expected = GetTestMatrix (); + var actual = (MatrixFloat4x4) expected; + Assert.AreEqual (expected.Determinant, actual.Determinant, 0.000001f, "determinant\n" + actual); + + } + + [Test] + public void Elements () + { + var expected = GetTestMatrix (); + var actual = (MatrixFloat4x4) expected; + + Assert.AreEqual (expected.M11, actual.M11, "m11 getter"); + Assert.AreEqual (expected.M12, actual.M12, "m12 getter"); + Assert.AreEqual (expected.M13, actual.M13, "m13 getter"); + Assert.AreEqual (expected.M14, actual.M14, "m14 getter"); + Assert.AreEqual (expected.M21, actual.M21, "m21 getter"); + Assert.AreEqual (expected.M22, actual.M22, "m22 getter"); + Assert.AreEqual (expected.M23, actual.M23, "m23 getter"); + Assert.AreEqual (expected.M24, actual.M24, "m24 getter"); + Assert.AreEqual (expected.M31, actual.M31, "m31 getter"); + Assert.AreEqual (expected.M32, actual.M32, "m32 getter"); + Assert.AreEqual (expected.M33, actual.M33, "m33 getter"); + Assert.AreEqual (expected.M34, actual.M34, "m34 getter"); + Assert.AreEqual (expected.M41, actual.M41, "m41 getter"); + Assert.AreEqual (expected.M42, actual.M42, "m42 getter"); + Assert.AreEqual (expected.M43, actual.M43, "m43 getter"); + Assert.AreEqual (expected.M44, actual.M44, "m44 getter"); + + var newExpected = GetTestMatrix (); + actual.M11 = newExpected.M11; + actual.M12 = newExpected.M12; + actual.M13 = newExpected.M13; + actual.M14 = newExpected.M14; + actual.M21 = newExpected.M21; + actual.M22 = newExpected.M22; + actual.M23 = newExpected.M23; + actual.M24 = newExpected.M24; + actual.M31 = newExpected.M31; + actual.M32 = newExpected.M32; + actual.M33 = newExpected.M33; + actual.M34 = newExpected.M34; + actual.M41 = newExpected.M41; + actual.M42 = newExpected.M42; + actual.M43 = newExpected.M43; + actual.M44 = newExpected.M44; + Assert.AreEqual (newExpected.M11, actual.M11, "m11 setter"); + Assert.AreEqual (newExpected.M12, actual.M12, "m12 setter"); + Assert.AreEqual (newExpected.M13, actual.M13, "m13 setter"); + Assert.AreEqual (newExpected.M14, actual.M14, "m14 setter"); + Assert.AreEqual (newExpected.M21, actual.M21, "m21 setter"); + Assert.AreEqual (newExpected.M22, actual.M22, "m22 setter"); + Assert.AreEqual (newExpected.M23, actual.M23, "m23 setter"); + Assert.AreEqual (newExpected.M24, actual.M24, "m24 setter"); + Assert.AreEqual (newExpected.M31, actual.M31, "m31 setter"); + Assert.AreEqual (newExpected.M32, actual.M32, "m32 setter"); + Assert.AreEqual (newExpected.M33, actual.M33, "m33 setter"); + Assert.AreEqual (newExpected.M34, actual.M34, "m34 setter"); + Assert.AreEqual (newExpected.M41, actual.M41, "m41 setter"); + Assert.AreEqual (newExpected.M42, actual.M42, "m42 setter"); + Assert.AreEqual (newExpected.M43, actual.M43, "m43 setter"); + Assert.AreEqual (newExpected.M44, actual.M44, "m44 setter"); + } + + [Test] + public void TransposeInstance () + { + var expected = GetTestMatrix (); + var actual = (MatrixFloat4x4) expected; + + expected.Transpose (); + actual.Transpose (); + + Asserts.AreEqual (expected, actual, "transpose"); + } + + [Test] + public void TransposeStatic () + { + var input = GetTestMatrix (); + var inputSimd = (MatrixFloat4x4) input; + + var expected = Matrix4.Transpose (input); + var actual = MatrixFloat4x4.Transpose (inputSimd); + + Asserts.AreEqual (expected, actual, "transpose"); + + input = GetTestMatrix (); + inputSimd = (MatrixFloat4x4) input; + Matrix4.Transpose (ref input, out expected); + MatrixFloat4x4.Transpose (ref inputSimd, out actual); + Asserts.AreEqual (expected, actual, "transpose out/ref"); + } + + [Test] + public void TransposeStatic_ByRef () + { + var input = GetTestMatrix (); + var inputSimd = (MatrixFloat4x4) input; + + Matrix4 expected; + MatrixFloat4x4 actual; + + Matrix4.Transpose (ref input, out expected); + MatrixFloat4x4.Transpose (ref inputSimd, out actual); + Asserts.AreEqual (expected, actual, "transpose out/ref"); + } + + [Test] + public void Multiply () + { + var inputL = GetTestMatrix (); + var inputR = GetTestMatrix (); + var inputSimdL = (MatrixFloat4x4) inputL; + var inputSimdR = (MatrixFloat4x4) inputR; + var expected = Matrix4.Mult (inputL, inputR); + var actual = MatrixFloat4x4.Multiply (inputSimdL, inputSimdR); + + Asserts.AreEqual (expected, actual, "multiply"); + } + + [Test] + public void Multiply_ByRef () + { + var inputL = GetTestMatrix (); + var inputR = GetTestMatrix (); + var inputSimdL = (MatrixFloat4x4) inputL; + var inputSimdR = (MatrixFloat4x4) inputR; + Matrix4 expected; + MatrixFloat4x4 actual; + + Matrix4.Mult (ref inputL, ref inputR, out expected); + MatrixFloat4x4.Multiply (ref inputSimdL, ref inputSimdR, out actual); + + Asserts.AreEqual (expected, actual, "multiply"); + } + + + [Test] + public void Multiply_Operator () + { + var inputL = GetTestMatrix (); + var inputR = GetTestMatrix (); + var inputSimdL = (MatrixFloat4x4) inputL; + var inputSimdR = (MatrixFloat4x4) inputR; + var expected = inputL * inputR; + var actual = inputSimdL * inputSimdR; + + Asserts.AreEqual (expected, actual, "multiply"); + } + + [Test] + public void Equality_Operator () + { + var inputL = GetTestMatrix (); + var inputR = GetTestMatrix (); + var inputSimdL = (MatrixFloat4x4) inputL; + var inputSimdR = (MatrixFloat4x4) inputR; + + // matrices are different + Assert.AreEqual (inputL == inputR, inputSimdL == inputSimdR, "inequality"); + Assert.IsFalse (inputL == inputR, "inequality 2 expected"); + Assert.IsFalse (inputSimdL == inputSimdR, "inequality 2 actual"); + + inputL = inputR; + inputSimdL = inputSimdR; + // matrices are identical + Assert.AreEqual (inputL == inputR, inputSimdL == inputSimdR, "equality"); + Assert.IsTrue (inputL == inputR, "equality 2 expected"); + Assert.IsTrue (inputSimdL == inputSimdR, "equality 2 actual"); + + Assert.IsTrue (MatrixFloat4x4.Identity == (MatrixFloat4x4) Matrix4.Identity, "identity equality"); + } + + [Test] + public void Inequality_Operator () + { + var inputL = GetTestMatrix (); + var inputR = GetTestMatrix (); + var inputSimdL = (MatrixFloat4x4) inputL; + var inputSimdR = (MatrixFloat4x4) inputR; + + // matrices are different + Assert.AreEqual (inputL != inputR, inputSimdL != inputSimdR, "inequality"); + Assert.IsTrue (inputL != inputR, "inequality 2 expected"); + Assert.IsTrue (inputSimdL != inputSimdR, "inequality 2 actual"); + + inputL = inputR; + inputSimdL = inputSimdR; + // matrices are identical + Assert.AreEqual (inputL != inputR, inputSimdL != inputSimdR, "equality"); + Assert.IsFalse (inputL != inputR, "equality 2 expected"); + Assert.IsFalse (inputSimdL != inputSimdR, "equality 2 actual"); + + Assert.IsFalse (MatrixFloat4x4.Identity != (MatrixFloat4x4) Matrix4.Identity, "identity equality"); + } + + [Test] + public void Explicit_Operator_ToMatrix4 () + { + var expected = (MatrixFloat4x4) GetTestMatrix (); + var actual = (Matrix4) expected; + + Asserts.AreEqual (expected, actual, "tomatrix4"); + + actual = (Matrix4) MatrixFloat4x4.Identity; + Asserts.AreEqual (MatrixFloat4x4.Identity, actual, "tomatrix4 identity"); + Asserts.AreEqual (Matrix4.Identity, actual, "tomatrix4 identity2"); + } + + [Test] + public void Explicit_Operator_FromMatrix4 () + { + var expected = GetTestMatrix (); + var actual = (MatrixFloat4x4) expected; + + Asserts.AreEqual (expected, actual, "frommatrix4"); + + actual = (MatrixFloat4x4) Matrix4.Identity; + Asserts.AreEqual (MatrixFloat4x4.Identity, actual, "tomatrix4 identity"); + Asserts.AreEqual (Matrix4.Identity, actual, "tomatrix4 identity2"); + } + + [Test] + public void ToStringTest () + { + var expected = GetTestMatrix (); + var actual = (MatrixFloat4x4) expected; + + Assert.AreEqual (expected.ToString (), actual.ToString (), "tostring"); + } + + // GetHashCode doesn't have to be identical, so no need to test + + [Test] + public void Equals_Object () + { + var expectedA = GetTestMatrix (); + var expectedB = GetTestMatrix (); + var actualA = (MatrixFloat4x4) expectedA; + var actualB = (MatrixFloat4x4) expectedB; + + Assert.IsTrue (actualA.Equals ((object) actualA), "self"); + Assert.IsFalse (actualA.Equals ((object) actualB), "other"); + Assert.IsFalse (actualA.Equals (null), "null"); + Assert.IsFalse (actualA.Equals (expectedA), "other type"); + } + + [Test] + public void Equals_Matrix () + { + var expectedA = GetTestMatrix (); + var expectedB = GetTestMatrix (); + var actualA = (MatrixFloat4x4) expectedA; + var actualB = (MatrixFloat4x4) expectedB; + + Assert.IsTrue (actualA.Equals (actualA), "self"); + Assert.IsFalse (actualA.Equals (actualB), "other"); + } + + // A collection of test matrices. + // + // I initially tried randomly generating test matrices, but it turns out + // there are accumulative computational differences in the different algorithms + // between Matrix4 and MatrixFloat4x4. Since the differences are accumulative, + // I couldn't find a minimal sensible delta values when comparing + // matrices. + // + // So I just serialized a few matrices that were randomly generated, and + // these have been tested to not produce accumulative computational differences. + // + static Matrix4 [] test_matrices = new [] { + new Matrix4 (0.1532144f, 0.5451511f, 0.2004739f, 0.8351463f, 0.9884372f, 0.1313103f, 0.3327205f, 0.01164342f, 0.6563147f, 0.7923161f, 0.6764754f, 0.07481737f, 0.03239552f, 0.7156482f, 0.6136858f, 0.1864168f), + new Matrix4 (0.7717745f, 0.559364f, 0.00918373f, 0.6579159f, 0.123461f, 0.9993145f, 0.5487496f, 0.2823398f, 0.9710717f, 0.8750508f, 0.472472f, 0.2608089f, 0.5771761f, 0.5617125f, 0.176998f, 0.1271691f), + new Matrix4 (0.2023053f, 0.4701468f, 0.6618567f, 0.7685714f, 0.8561344f, 0.009231919f, 0.6150167f, 0.7542298f, 0.550727f, 0.3625788f, 0.6639862f, 0.5763468f, 0.9717328f, 0.003812184f, 0.985266f, 0.7540002f), + new Matrix4 (9.799572E+08f, 1.64794E+09f, 1.117296E+09f, 1.239858E+09f, 6.389504E+07f, 1.172175E+09f, 1.399567E+09f, 1.187143E+09f, 3.729208E+07f, 5.50313E+08f, 1.847369E+09f, 1.612405E+09f, 1.699488E+08f, 4.952176E+08f, 1.07262E+09f, 2.035059E+09f), + new Matrix4 (1.102396E+09f, 3.082477E+08f, 1.126484E+09f, 5.022931E+08f, 1.966322E+09f, 1.1814E+09f, 8.464673E+08f, 1.940651E+09f, 1.229937E+09f, 1.367379E+09f, 1.900015E+09f, 1.516109E+09f, 2.146064E+09f, 1.870971E+09f, 1.046267E+09f, 1.088363E+09f), + new Matrix4 (2.263112E+08f, 8.79644E+08f, 1.303282E+09f, 1.654159E+09f, 3.705524E+08f, 1.984941E+09f, 2.175935E+07f, 4.633518E+08f, 1.801243E+09f, 1.616996E+09f, 1.620852E+09f, 7291498f, 1.012728E+09f, 2.834145E+08f, 3.5328E+08f, 1.35012E+09f), + new Matrix4 (0.4904693f, 0.841727f, 0.2294401f, 0.5736054f, 0.5406881f, 0.2172498f, 0.1261143f, 0.6736677f, 0.4570194f, 0.9091009f, 0.7669608f, 0.8468134f, 0.01802658f, 0.3850208f, 0.3730424f, 0.2440258f), + new Matrix4 (0.1252193f, 0.08986127f, 0.3407605f, 0.9144857f, 0.340791f, 0.2192288f, 0.5144276f, 0.01813344f, 0.07687104f, 0.7971596f, 0.6393988f, 0.9002907f, 0.1011457f, 0.5047605f, 0.7202546f, 0.07729452f), + new Matrix4 (8.176959E+08f, 1.386156E+09f, 5.956444E+08f, 4.210506E+08f, 1.212676E+09f, 4.131035E+08f, 1.032453E+09f, 2.074689E+08f, 1.536594E+09f, 3.266183E+07f, 5.222072E+08f, 7.923175E+08f, 1.762531E+09f, 7.901702E+08f, 8.1975E+08f, 1.630734E+09f), + new Matrix4 (0.006755914f, 0.07464754f, 0.287938f, 0.3724834f, 0.1496783f, 0.6224982f, 0.7150125f, 0.5554719f, 0.4638171f, 0.4200902f, 0.4867154f, 0.773377f, 0.3558737f, 0.4043404f, 0.04670618f, 0.7695189f), + }; + + static int counter; + internal static Matrix4 GetTestMatrix () + { + counter++; + if (counter == test_matrices.Length) + counter = 0; + return test_matrices [counter]; + } + } +} diff --git a/tests/monotouch-test/SpriteKit/SKTransformNodeTest.cs b/tests/monotouch-test/SpriteKit/SKTransformNodeTest.cs index 2f2fcfa135..0168d9f4ce 100644 --- a/tests/monotouch-test/SpriteKit/SKTransformNodeTest.cs +++ b/tests/monotouch-test/SpriteKit/SKTransformNodeTest.cs @@ -15,6 +15,8 @@ using MonoTouch.UIKit; using MonoTouch.ObjCRuntime; #endif using OpenTK; +using Simd; +using Bindings.Test; using NUnit.Framework; namespace MonoTouchFixtures.SpriteKit { @@ -48,9 +50,30 @@ namespace MonoTouchFixtures.SpriteKit { public void RotationMatrix () { using (var obj = new SKTransformNode ()) { - obj.RotationMatrix = Matrix3.Zero; + var zero = new MatrixFloat3x3 (); + obj.RotationMatrix = zero; // In Swift, a rotated zero matrice also becomes the identity matrice. - Asserts.AreEqual (Matrix3.Identity, obj.RotationMatrix, "RotationMatrix"); + Asserts.AreEqual (MatrixFloat3x3.Identity, obj.RotationMatrix, "RotationMatrix"); + // Changing XRotation (or YRotation for that matter), makes the RotationMatrix change too + obj.XRotation = (nfloat) (Math.PI / 2); + var rotatedMatrix = new MatrixFloat3x3 ( + 1, 0, 0, + 0, 0, -1, + 0, 1, 0 + ); + Asserts.AreEqual (rotatedMatrix, obj.RotationMatrix, 0.000001f, "RotationMatrix a"); + Asserts.AreEqual (rotatedMatrix, CFunctions.GetMatrixFloat3x3 (obj, "rotationMatrix"), 0.000001f, "RotationMatrix native a"); + + // Got this matrix after setting both XRotation and YRotation to Pi/2 + rotatedMatrix = new MatrixFloat3x3 ( + 0, 1, 0, + 0, 0, -1, + -1, 0, 0 + ); + obj.RotationMatrix = rotatedMatrix; + Asserts.AreEqual (rotatedMatrix, obj.RotationMatrix, 0.000001f, "RotationMatrix b"); + Assert.AreEqual ((nfloat) (Math.PI / 2), obj.XRotation, 0.000001f, "XRotation b"); + Assert.AreEqual (0, obj.YRotation, 0.000001f, "YRotation b"); // Setting YRotation changes RotationMatrix, but setting RotationMatrix doesn't change YRotation. } } diff --git a/tests/monotouch-test/SpriteKit/UniformTest.cs b/tests/monotouch-test/SpriteKit/UniformTest.cs index 8918e56a27..7906af9666 100644 --- a/tests/monotouch-test/SpriteKit/UniformTest.cs +++ b/tests/monotouch-test/SpriteKit/UniformTest.cs @@ -15,7 +15,11 @@ using MonoTouch.UIKit; using MonoTouch.ObjCRuntime; #endif using OpenTK; +using Simd; using NUnit.Framework; +#if !TEST_BINDINGS_UNAVAILABLE +using Bindings.Test; +#endif namespace MonoTouchFixtures.SpriteKit { @@ -76,6 +80,9 @@ namespace MonoTouchFixtures.SpriteKit Matrix2 M2; Matrix3 M3; Matrix4 M4; + MatrixFloat2x2 M2x2; + MatrixFloat3x3 M3x3; + MatrixFloat4x4 M4x4; using (var obj = new SKUniform ("name")) { var M4Zero = new Matrix4 (Vector4.Zero, Vector4.Zero, Vector4.Zero, Vector4.Zero); @@ -97,6 +104,9 @@ namespace MonoTouchFixtures.SpriteKit M2 = new Matrix2 (1, 2, 3, 4); M3 = new Matrix3 (1, 2, 3, 4, 5, 6, 7, 8, 9); M4 = new Matrix4 (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + M2x2 = (MatrixFloat2x2) M2; + M3x3 = (MatrixFloat3x3) M3; + M4x4 = (MatrixFloat4x4) M4; obj.TextureValue = texture; Assert.AreEqual (texture, obj.TextureValue, "2 TextureValue"); @@ -123,6 +133,7 @@ namespace MonoTouchFixtures.SpriteKit Asserts.AreEqual (M4, obj.FloatMatrix4Value, "2 FloatMatrix4Value"); } + bool hasSimdConstructors = TestRuntime.CheckXcodeVersion (8, 0); using (var obj = new SKUniform ("name", texture)) { Assert.AreEqual (texture, obj.TextureValue, "3 TextureValue"); } @@ -145,14 +156,109 @@ namespace MonoTouchFixtures.SpriteKit using (var obj = new SKUniform ("name", M2)) { Asserts.AreEqual (M2, obj.FloatMatrix2Value, "8 FloatMatrix2Value"); +#if !TEST_BINDINGS_UNAVAILABLE + Asserts.AreEqual (M2, MatrixFloat2x2.Transpose (CFunctions.GetMatrixFloat2x2 (obj, "matrixFloat2x2Value")), "8b FloatMatrix2Value"); +#endif } using (var obj = new SKUniform ("name", M3)) { Asserts.AreEqual (M3, obj.FloatMatrix3Value, "9 FloatMatrix3Value"); +#if !TEST_BINDINGS_UNAVAILABLE + Asserts.AreEqual (M3, MatrixFloat3x3.Transpose (CFunctions.GetMatrixFloat3x3 (obj, "matrixFloat3x3Value")), "9b FloatMatrix3Value"); +#endif } using (var obj = new SKUniform ("name", M4)) { Asserts.AreEqual (M4, obj.FloatMatrix4Value, "10 FloatMatrix4Value"); +#if !TEST_BINDINGS_UNAVAILABLE + Asserts.AreEqual (M4, MatrixFloat4x4.Transpose (CFunctions.GetMatrixFloat4x4 (obj, "matrixFloat4x4Value")), "10b FloatMatrix4Value"); +#endif + } + + using (var obj = new SKUniform ("name", M2x2)) { + Asserts.AreEqual (M2x2, obj.MatrixFloat2x2Value, "11 MatrixFloat2x2Value"); +#if !TEST_BINDINGS_UNAVAILABLE + Asserts.AreEqual (M2x2, CFunctions.GetMatrixFloat2x2 (obj, "matrixFloat2x2Value"), "11b MatrixFloat2x2Value"); +#endif + var tmp2 = new MatrixFloat2x2 (9, 8, 7, 6); + obj.MatrixFloat2x2Value = tmp2; + Asserts.AreEqual (tmp2, obj.MatrixFloat2x2Value, "11 MatrixFloat2x2Value second"); +#if !TEST_BINDINGS_UNAVAILABLE + Asserts.AreEqual (tmp2, CFunctions.GetMatrixFloat2x2 (obj, "matrixFloat2x2Value"), "11b MatrixFloat2x2Value second"); +#endif + } + + using (var obj = new SKUniform ("name", M3x3)) { + Asserts.AreEqual (M3x3, obj.MatrixFloat3x3Value, "12 MatrixFloat3x3Value"); +#if !TEST_BINDINGS_UNAVAILABLE + Asserts.AreEqual (M3x3, CFunctions.GetMatrixFloat3x3 (obj, "matrixFloat3x3Value"), "12b MatrixFloat3x3Value"); +#endif + var tmp3 = new MatrixFloat3x3 (9, 8, 7, 6, 5, 4, 3, 2, 1); + obj.MatrixFloat3x3Value = tmp3; + Asserts.AreEqual (tmp3, obj.MatrixFloat3x3Value, "12 MatrixFloat3x3Value second"); +#if !TEST_BINDINGS_UNAVAILABLE + Asserts.AreEqual (tmp3, CFunctions.GetMatrixFloat3x3 (obj, "matrixFloat3x3Value"), "12b MatrixFloat3x3Value second"); +#endif + } + + using (var obj = new SKUniform ("name", M4x4)) { + Asserts.AreEqual (M4x4, obj.MatrixFloat4x4Value, "13 MatrixFloat4x4Value"); +#if !TEST_BINDINGS_UNAVAILABLE + Asserts.AreEqual (M4x4, CFunctions.GetMatrixFloat4x4 (obj, "matrixFloat4x4Value"), "13b FloatMatrix4Value"); +#endif + var tmp4 = new MatrixFloat4x4 (9, 8, 7, 6, 5, 4, 3, 2, 1, 0, -1, -2, -3, -4, -5, -6); + obj.MatrixFloat4x4Value = tmp4; + Asserts.AreEqual (tmp4, obj.MatrixFloat4x4Value, "13 MatrixFloat4x4Value second"); +#if !TEST_BINDINGS_UNAVAILABLE + Asserts.AreEqual (tmp4, CFunctions.GetMatrixFloat4x4 (obj, "matrixFloat4x4Value"), "13b MatrixFloat4x4Value second"); +#endif + } + } + + [Test] + public void Create () + { + var M2x2 = new MatrixFloat2x2 (1, 2, 3, 4); + var M3x3 = new MatrixFloat3x3 (1, 2, 3, 4, 5, 6, 7, 8, 9); + var M4x4 = new MatrixFloat4x4 (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + + using (var obj = SKUniform.Create ("name", M2x2)) { + Asserts.AreEqual (M2x2, obj.MatrixFloat2x2Value, "11 MatrixFloat2x2Value"); +#if !TEST_BINDINGS_UNAVAILABLE + Asserts.AreEqual (M2x2, CFunctions.GetMatrixFloat2x2 (obj, "matrixFloat2x2Value"), "11b MatrixFloat2x2Value"); +#endif + var tmp2 = new MatrixFloat2x2 (9, 8, 7, 6); + obj.MatrixFloat2x2Value = tmp2; + Asserts.AreEqual (tmp2, obj.MatrixFloat2x2Value, "11 MatrixFloat2x2Value second"); +#if !TEST_BINDINGS_UNAVAILABLE + Asserts.AreEqual (tmp2, CFunctions.GetMatrixFloat2x2 (obj, "matrixFloat2x2Value"), "11b MatrixFloat2x2Value second"); +#endif + } + + using (var obj = SKUniform.Create ("name", M3x3)) { + Asserts.AreEqual (M3x3, obj.MatrixFloat3x3Value, "12 MatrixFloat3x3Value"); +#if !TEST_BINDINGS_UNAVAILABLE + Asserts.AreEqual (M3x3, CFunctions.GetMatrixFloat3x3 (obj, "matrixFloat3x3Value"), "12b MatrixFloat3x3Value"); +#endif + var tmp3 = new MatrixFloat3x3 (9, 8, 7, 6, 5, 4, 3, 2, 1); + obj.MatrixFloat3x3Value = tmp3; + Asserts.AreEqual (tmp3, obj.MatrixFloat3x3Value, "12 MatrixFloat3x3Value second"); +#if !TEST_BINDINGS_UNAVAILABLE + Asserts.AreEqual (tmp3, CFunctions.GetMatrixFloat3x3 (obj, "matrixFloat3x3Value"), "12b MatrixFloat3x3Value second"); +#endif + } + + using (var obj = SKUniform.Create ("name", M4x4)) { + Asserts.AreEqual (M4x4, obj.MatrixFloat4x4Value, "13 MatrixFloat4x4Value"); +#if !TEST_BINDINGS_UNAVAILABLE + Asserts.AreEqual (M4x4, CFunctions.GetMatrixFloat4x4 (obj, "matrixFloat4x4Value"), "13b FloatMatrix4Value"); +#endif + var tmp4 = new MatrixFloat4x4 (9, 8, 7, 6, 5, 4, 3, 2, 1, 0, -1, -2, -3, -4, -5, -6); + obj.MatrixFloat4x4Value = tmp4; + Asserts.AreEqual (tmp4, obj.MatrixFloat4x4Value, "13 MatrixFloat4x4Value second"); +#if !TEST_BINDINGS_UNAVAILABLE + Asserts.AreEqual (tmp4, CFunctions.GetMatrixFloat4x4 (obj, "matrixFloat4x4Value"), "13b MatrixFloat4x4Value second"); +#endif } } } diff --git a/tests/monotouch-test/monotouch-test.csproj b/tests/monotouch-test/monotouch-test.csproj index ed40287e4c..b215d7a7b5 100644 --- a/tests/monotouch-test/monotouch-test.csproj +++ b/tests/monotouch-test/monotouch-test.csproj @@ -635,6 +635,7 @@ + @@ -647,6 +648,9 @@ + + + @@ -669,6 +673,9 @@ + + + @@ -722,6 +729,7 @@ + diff --git a/tests/test-libraries/libtest.h b/tests/test-libraries/libtest.h index d766173067..3ab8b21d4d 100644 --- a/tests/test-libraries/libtest.h +++ b/tests/test-libraries/libtest.h @@ -1,7 +1,12 @@ #import +#include #include "rename.h" +#if !TARGET_OS_WATCH +#import +#endif + #ifdef __cplusplus extern "C" { #endif @@ -9,6 +14,16 @@ extern "C" { int theUltimateAnswer (); void useZLib (); +void x_get_matrix_float2x2 (id self, const char *sel, float* r0c0, float* r0c1, float* r1c0, float* r1c1); +void x_get_matrix_float3x3 (id self, const char *sel, float* r0c0, float* r0c1, float* r0c2, float* r1c0, float* r1c1, float* r1c2, float* r2c0, float* r2c1, float* r2c2); +void x_get_matrix_float4x4 (id self, const char *sel, float* r0c0, float* r0c1, float* r0c2, float* r0c3, float* r1c0, float* r1c1, float* r1c2, float* r1c3, float* r2c0, float* r2c1, float* r2c2, float* r2c3, float* r3c0, float* r3c1, float* r3c2, float* r3c3); + +#if !TARGET_OS_WATCH +void x_mdltransformcomponent_get_local_transform (id self, NSTimeInterval time, float* r0c0, float* r0c1, float* r0c2, float* r0c3, float* r1c0, float* r1c1, float* r1c2, float* r1c3, float* r2c0, float* r2c1, float* r2c2, float* r2c3, float* r3c0, float* r3c1, float* r3c2, float* r3c3); +void x_mdltransform_create_global_transform (MDLObject *object, NSTimeInterval time, float* r0c0, float* r0c1, float* r0c2, float* r0c3, float* r1c0, float* r1c1, float* r1c2, float* r1c3, float* r2c0, float* r2c1, float* r2c2, float* r2c3, float* r3c0, float* r3c1, float* r3c2, float* r3c3); +void x_mdltransform_get_rotation_matrix (MDLTransform *self, NSTimeInterval time, float* r0c0, float* r0c1, float* r0c2, float* r0c3, float* r1c0, float* r1c1, float* r1c2, float* r1c3, float* r2c0, float* r2c1, float* r2c2, float* r2c3, float* r3c0, float* r3c1, float* r3c2, float* r3c3); +#endif + /* * Various structs used in ObjCRegistrarTest */ diff --git a/tests/test-libraries/libtest.m b/tests/test-libraries/libtest.m index b8ac5d3ab5..73c7764ee5 100644 --- a/tests/test-libraries/libtest.m +++ b/tests/test-libraries/libtest.m @@ -1,6 +1,8 @@ #import +#include #include +#include #include #include "libtest.h" @@ -15,6 +17,198 @@ void useZLib () printf ("ZLib version: %s\n", zlibVersion ()); } +typedef matrix_float2x2 (*func_x_get_matrix_float2x2_msgSend) (id self, SEL sel); +void +x_get_matrix_float2x2 (id self, const char *sel, + float* r0c0, float* r0c1, + float* r1c0, float* r1c1) +{ + matrix_float2x2 rv; +#if __i386__ + IMP msgSend = (IMP) objc_msgSend_stret; +#elif __x86_64__ + IMP msgSend = (IMP) objc_msgSend; +#elif __arm64__ + IMP msgSend = (IMP) objc_msgSend; +#elif __arm__ + IMP msgSend = (IMP) objc_msgSend_stret; +#else +#error unknown architecture +#endif + rv = ((func_x_get_matrix_float2x2_msgSend) msgSend) (self, sel_registerName (sel)); + *r0c0 = rv.columns[0][0]; + *r0c1 = rv.columns[1][0]; + *r1c0 = rv.columns[0][1]; + *r1c1 = rv.columns[1][1]; +} + +typedef matrix_float3x3 (*func_x_get_matrix_float3x3_msgSend) (id self, SEL sel); +void +x_get_matrix_float3x3 (id self, const char *sel, + float* r0c0, float* r0c1, float* r0c2, + float* r1c0, float* r1c1, float* r1c2, + float* r2c0, float* r2c1, float* r2c2) +{ + matrix_float3x3 rv; +#if __i386__ + IMP msgSend = (IMP) objc_msgSend_stret; +#elif __x86_64__ + IMP msgSend = (IMP) objc_msgSend_stret; +#elif __arm64__ + IMP msgSend = (IMP) objc_msgSend; +#elif __arm__ + IMP msgSend = (IMP) objc_msgSend_stret; +#else +#error unknown architecture +#endif + rv = ((func_x_get_matrix_float3x3_msgSend) msgSend) (self, sel_registerName (sel)); + *r0c0 = rv.columns[0][0]; + *r0c1 = rv.columns[1][0]; + *r0c2 = rv.columns[2][0]; + + *r1c0 = rv.columns[0][1]; + *r1c1 = rv.columns[1][1]; + *r1c2 = rv.columns[2][1]; + + *r2c0 = rv.columns[0][2]; + *r2c1 = rv.columns[1][2]; + *r2c2 = rv.columns[2][2]; +} + +typedef matrix_float4x4 (*func_x_get_matrix_float4x4_msgSend) (id self, SEL sel); +void +x_get_matrix_float4x4 (id self, const char *sel, + float* r0c0, float* r0c1, float* r0c2, float* r0c3, + float* r1c0, float* r1c1, float* r1c2, float* r1c3, + float* r2c0, float* r2c1, float* r2c2, float* r2c3, + float* r3c0, float* r3c1, float* r3c2, float* r3c3) +{ + matrix_float4x4 rv; +#if __i386__ + IMP msgSend = (IMP) objc_msgSend_stret; +#elif __x86_64__ + IMP msgSend = (IMP) objc_msgSend_stret; +#elif __arm64__ + IMP msgSend = (IMP) objc_msgSend; +#elif __arm__ + IMP msgSend = (IMP) objc_msgSend_stret; +#else +#error unknown architecture +#endif + rv = ((func_x_get_matrix_float4x4_msgSend) msgSend) (self, sel_registerName (sel)); + *r0c0 = rv.columns[0][0]; + *r0c1 = rv.columns[1][0]; + *r0c2 = rv.columns[2][0]; + *r0c3 = rv.columns[3][0]; + + *r1c0 = rv.columns[0][1]; + *r1c1 = rv.columns[1][1]; + *r1c2 = rv.columns[2][1]; + *r1c3 = rv.columns[3][1]; + + *r2c0 = rv.columns[0][2]; + *r2c1 = rv.columns[1][2]; + *r2c2 = rv.columns[2][2]; + *r2c3 = rv.columns[3][2]; + + *r3c0 = rv.columns[0][3]; + *r3c1 = rv.columns[1][3]; + *r3c2 = rv.columns[2][3]; + *r3c3 = rv.columns[3][3]; +} + +#if !TARGET_OS_WATCH +void +x_mdltransformcomponent_get_local_transform (id self, NSTimeInterval time, + float* r0c0, float* r0c1, float* r0c2, float* r0c3, + float* r1c0, float* r1c1, float* r1c2, float* r1c3, + float* r2c0, float* r2c1, float* r2c2, float* r2c3, + float* r3c0, float* r3c1, float* r3c2, float* r3c3) +{ + matrix_float4x4 rv; + rv = [self localTransformAtTime: time]; + *r0c0 = rv.columns[0][0]; + *r0c1 = rv.columns[1][0]; + *r0c2 = rv.columns[2][0]; + *r0c3 = rv.columns[3][0]; + + *r1c0 = rv.columns[0][1]; + *r1c1 = rv.columns[1][1]; + *r1c2 = rv.columns[2][1]; + *r1c3 = rv.columns[3][1]; + + *r2c0 = rv.columns[0][2]; + *r2c1 = rv.columns[1][2]; + *r2c2 = rv.columns[2][2]; + *r2c3 = rv.columns[3][2]; + + *r3c0 = rv.columns[0][3]; + *r3c1 = rv.columns[1][3]; + *r3c2 = rv.columns[2][3]; + *r3c3 = rv.columns[3][3]; +} + +void +x_mdltransform_create_global_transform (MDLObject *object, NSTimeInterval time, + float* r0c0, float* r0c1, float* r0c2, float* r0c3, + float* r1c0, float* r1c1, float* r1c2, float* r1c3, + float* r2c0, float* r2c1, float* r2c2, float* r2c3, + float* r3c0, float* r3c1, float* r3c2, float* r3c3) +{ + matrix_float4x4 rv; + rv = [MDLTransform globalTransformWithObject: object atTime: time]; + *r0c0 = rv.columns[0][0]; + *r0c1 = rv.columns[1][0]; + *r0c2 = rv.columns[2][0]; + *r0c3 = rv.columns[3][0]; + + *r1c0 = rv.columns[0][1]; + *r1c1 = rv.columns[1][1]; + *r1c2 = rv.columns[2][1]; + *r1c3 = rv.columns[3][1]; + + *r2c0 = rv.columns[0][2]; + *r2c1 = rv.columns[1][2]; + *r2c2 = rv.columns[2][2]; + *r2c3 = rv.columns[3][2]; + + *r3c0 = rv.columns[0][3]; + *r3c1 = rv.columns[1][3]; + *r3c2 = rv.columns[2][3]; + *r3c3 = rv.columns[3][3]; +} + +void +x_mdltransform_get_rotation_matrix (MDLTransform *self, NSTimeInterval time, + float* r0c0, float* r0c1, float* r0c2, float* r0c3, + float* r1c0, float* r1c1, float* r1c2, float* r1c3, + float* r2c0, float* r2c1, float* r2c2, float* r2c3, + float* r3c0, float* r3c1, float* r3c2, float* r3c3) +{ + matrix_float4x4 rv; + rv = [self rotationMatrixAtTime: time]; + *r0c0 = rv.columns[0][0]; + *r0c1 = rv.columns[1][0]; + *r0c2 = rv.columns[2][0]; + *r0c3 = rv.columns[3][0]; + + *r1c0 = rv.columns[0][1]; + *r1c1 = rv.columns[1][1]; + *r1c2 = rv.columns[2][1]; + *r1c3 = rv.columns[3][1]; + + *r2c0 = rv.columns[0][2]; + *r2c1 = rv.columns[1][2]; + *r2c2 = rv.columns[2][2]; + *r2c3 = rv.columns[3][2]; + + *r3c0 = rv.columns[0][3]; + *r3c1 = rv.columns[1][3]; + *r3c2 = rv.columns[2][3]; + *r3c3 = rv.columns[3][3]; +} +#endif // !TARGET_OS_WATCH + @interface UltimateMachine : NSObject { } diff --git a/tests/test-libraries/rename.h b/tests/test-libraries/rename.h index 5d51469e47..4d8fc21c82 100644 --- a/tests/test-libraries/rename.h +++ b/tests/test-libraries/rename.h @@ -53,6 +53,12 @@ #define CtorChaining1 object_CtorChaining1 #define ObjCExceptionTest object_ObjCExceptionTest #define ObjCProtocolClassTest object_ObjCProtocolClassTest + #define x_mdltransform_get_rotation_matrix object_x_mdltransform_get_rotation_matrix + #define x_mdltransformcomponent_get_local_transform object_x_mdltransformcomponent_get_local_transform + #define x_mdltransform_create_global_transform object_x_mdltransform_create_global_transform + #define x_get_matrix_float4x4 object_x_get_matrix_float4x4 + #define x_get_matrix_float3x3 object_x_get_matrix_float3x3 + #define x_get_matrix_float2x2 object_x_get_matrix_float2x2 #elif PREFIX == 2 #define theUltimateAnswer ar_theUltimateAnswer #define useZLib ar_useZLib @@ -107,6 +113,12 @@ #define CtorChaining1 ar_CtorChaining1 #define ObjCExceptionTest ar_ObjCExceptionTest #define ObjCProtocolClassTest ar_ObjCProtocolClassTest + #define x_mdltransform_get_rotation_matrix ar_x_mdltransform_get_rotation_matrix + #define x_mdltransformcomponent_get_local_transform ar_x_mdltransformcomponent_get_local_transform + #define x_mdltransform_create_global_transform ar_x_mdltransform_create_global_transform + #define x_get_matrix_float4x4 ar_x_get_matrix_float4x4 + #define x_get_matrix_float3x3 ar_x_get_matrix_float3x3 + #define x_get_matrix_float2x2 ar_x_get_matrix_float2x2 #else // keep original names #endif diff --git a/tests/xammac_tests/xammac_tests.csproj b/tests/xammac_tests/xammac_tests.csproj index 56f0c6307b..be80c48d44 100644 --- a/tests/xammac_tests/xammac_tests.csproj +++ b/tests/xammac_tests/xammac_tests.csproj @@ -17,7 +17,7 @@ full false bin\x86\Debug - __UNIFIED__;DEBUG;MONOMAC;XAMCORE_2_0 + __UNIFIED__;DEBUG;MONOMAC;XAMCORE_2_0;TEST_BINDINGS_UNAVAILABLE prompt 4 false @@ -38,7 +38,7 @@ true bin\x86\Release - __UNIFIED__;MONOMAC;XAMCORE_2_0 + __UNIFIED__;MONOMAC;XAMCORE_2_0;TEST_BINDINGS_UNAVAILABLE prompt 4 false diff --git a/tests/xtro-sharpie/Helpers.cs b/tests/xtro-sharpie/Helpers.cs index 921cfddeb0..f9032b2d27 100644 --- a/tests/xtro-sharpie/Helpers.cs +++ b/tests/xtro-sharpie/Helpers.cs @@ -248,5 +248,47 @@ namespace Extrospection { { return self.Selector.ToString () ?? (self.IsPropertyAccessor ? self.Name : null); } + + public static bool IsObsolete (this ICustomAttributeProvider provider) + { + if (provider.HasCustomAttributes) { + foreach (var attrib in provider.CustomAttributes) { + var attribType = attrib.Constructor.DeclaringType; + if (attribType.Namespace == "System" && attribType.Name == "ObsoleteAttribute") + return true; + } + } + + // If we're a property accessor, check the property as well. + var prop = FindProperty (provider as MethodReference); + if (prop != null) + return IsObsolete (prop); + + return false; + } + + public static PropertyDefinition FindProperty (this MethodReference method) + { + var def = method?.Resolve (); + if (def == null) + return null; + + if (!def.IsSpecialName) + return null; + + if (!def.DeclaringType.HasProperties) + return null; + + if (!method.Name.StartsWith ("get_", StringComparison.Ordinal) && !method.Name.StartsWith ("set_", StringComparison.Ordinal)) + return null; + + var propName = method.Name.Substring (4); + foreach (var prop in def.DeclaringType.Properties) { + if (prop.Name == propName) + return prop; + } + + return null; + } } } \ No newline at end of file diff --git a/tests/xtro-sharpie/Runner.cs b/tests/xtro-sharpie/Runner.cs index ba556849b5..44fff6c68a 100644 --- a/tests/xtro-sharpie/Runner.cs +++ b/tests/xtro-sharpie/Runner.cs @@ -25,6 +25,7 @@ namespace Extrospection { new ObjCInterfaceCheck (), new ObjCProtocolCheck (), new SelectorCheck (), + new SimdCheck (), // new ListNative (), // for debug }; foreach (var assemblyName in assemblyNames) { diff --git a/tests/xtro-sharpie/SimdCheck.cs b/tests/xtro-sharpie/SimdCheck.cs new file mode 100644 index 0000000000..be487ca641 --- /dev/null +++ b/tests/xtro-sharpie/SimdCheck.cs @@ -0,0 +1,385 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +using Mono.Cecil; + +using Clang.Ast; + +namespace Extrospection +{ + + class SimdCheck : BaseVisitor + { + bool very_strict = false; + bool strict = false; + + // A dictionary of native type -> managed type mapping. + class NativeSimdInfo + { + public string Managed; + public string InvalidManaged; + } + + static Dictionary type_mapping = new Dictionary () { + { "matrix_double2x2", new NativeSimdInfo { Managed ="MatrixDouble2x2", InvalidManaged = "Matrix2d" }}, + { "matrix_double3x3", new NativeSimdInfo { Managed = "MatrixDouble3x3", InvalidManaged = "Matrix3d" }}, + { "matrix_double4x4", new NativeSimdInfo { Managed = "MatrixDouble4x4", InvalidManaged = "Matrix4d" }}, + { "matrix_float2x2", new NativeSimdInfo { Managed = "MatrixFloat2x2", InvalidManaged = "Matrix2", }}, + { "matrix_float3x3", new NativeSimdInfo { Managed = "MatrixFloat3x3", InvalidManaged = "Matrix3", }}, + { "matrix_float4x3", new NativeSimdInfo { Managed = "MatrixFloat4x3", }}, + { "matrix_float4x4", new NativeSimdInfo { Managed = "MatrixFloat4x4", InvalidManaged = "Matrix4", }}, + { "simd_quatd", new NativeSimdInfo { Managed = "Quaternion4d", }}, + { "simd_quatf", new NativeSimdInfo { Managed = "Quaternion4", }}, + { "vector_double2", new NativeSimdInfo { Managed = "Vector2d", }}, + { "vector_double3", new NativeSimdInfo { Managed = "Vector3d", }}, + { "vector_double4", new NativeSimdInfo { Managed = "Vector4d", }}, + { "vector_float2", new NativeSimdInfo { Managed = "Vector2", }}, + { "vector_float3", new NativeSimdInfo { Managed = "Vector3", }}, + { "vector_float4", new NativeSimdInfo { Managed = "Vector4", }}, + { "vector_int2", new NativeSimdInfo { Managed = "Vector2i", }}, + { "vector_int3", new NativeSimdInfo { Managed = "Vector3i", }}, + { "vector_int4", new NativeSimdInfo { Managed = "Vector4i", }}, + { "vector_uint2", new NativeSimdInfo { Managed = "Vector2i", }}, + { "vector_uint3", new NativeSimdInfo { Managed = "Vector3i", }}, + { "vector_uint4", new NativeSimdInfo { Managed = "Vector4i", }}, + // simd_floatX is typedefed to vector_floatX + { "simd_float2", new NativeSimdInfo { Managed = "Vector2" }}, + { "simd_float3", new NativeSimdInfo { Managed = "Vector3" }}, + { "simd_float4", new NativeSimdInfo { Managed = "Vector4" }}, + { "simd_float4x4", new NativeSimdInfo { Managed = "MatrixFloat4x4", InvalidManaged = "Matrix4" }}, + // The native definition is two 'vector_float2' fields. + // The managed definition matches this (two 'Vector2' fields), and should work fine. + { "GKQuad", new NativeSimdInfo { Managed = "GKQuad" }}, + // The native definition is two 'vector_float3' fields. + // In this case each element uses 16 bytes (4 floats) due to padding. + // The managed definition is two Vector3 fields, and does *not* + // match the native definition (missing the padding). + // It still works because we're marshalling this struct manually ([MarshalDirective]). + { "GKBox", new NativeSimdInfo { Managed = "GKBox", }}, + // The native definition is 'vector_float3 points[3]' - an array of three vector_float3. + // In this case each element uses 16 bytes (4 floats) due to padding. + // The managed definition is just an array of Vector3, but luckily + // it's a private field, so we might be able to improve this later. Right now we're marshalling + // this struct manually ([MarshalDirective]), so managed code should get correct + // results. + { "GKTriangle", new NativeSimdInfo { Managed = "GKTriangle", }}, + // This is a 'vector_int4, represented by a Vector4i in managed code, + // which means it's matching the native definition. + { "MDLVoxelIndex", new NativeSimdInfo { Managed = "MDLVoxelIndex" }}, + // In managed code this is struct of two Vector4, so it's matching the native definition. + { "MDLVoxelIndexExtent", new NativeSimdInfo { Managed = "MDLVoxelIndexExtent" }}, + // In managed code this is a struct of two Vector3, so it's *not* matching + // the native definition. However, since we're manually marshalling this type + // (using [MarshalDirective]), managed code doesn't get incorrect results. + { "MDLAxisAlignedBoundingBox", new NativeSimdInfo { Managed = "MDLAxisAlignedBoundingBox", }}, + // The managed definition is identical to the native definition + { "MPSImageHistogramInfo", new NativeSimdInfo { Managed = "MPSImageHistogramInfo" }}, + }; + + static Dictionary managed_simd_types; // bool: invalid_for_simd + + static SimdCheck () + { + managed_simd_types = new Dictionary (); + foreach (var kvp in type_mapping) { + managed_simd_types [kvp.Value.Managed] = false; + if (!string.IsNullOrEmpty (kvp.Value.InvalidManaged)) + managed_simd_types [kvp.Value.InvalidManaged] = true; + } + } + + class ManagedSimdInfo + { + public MethodDefinition Method; + public bool ContainsInvalidMappingForSimd; + } + Dictionary managed_methods = new Dictionary (); + + public override void VisitManagedMethod (MethodDefinition method) + { + var type = method.DeclaringType; + + if (!type.IsNested && type.IsNotPublic) + return; + + if (type.IsNested && (type.IsNestedPrivate || type.IsNestedAssembly || type.IsNestedFamilyAndAssembly)) + return; + + if (method.IsPrivate || method.IsAssembly || method.IsFamilyAndAssembly) + return; // Don't care about non-visible types + + if (type.Namespace == "Simd" || type.Namespace.StartsWith ("OpenTK", StringComparison.Ordinal)) + return; // We're assuming everything in the Simd and OpenTK namespaces can be ignored (the former because it's correctly written, the latter because it doesn't map to native simd types). + + if (method.HasCustomAttributes && method.CustomAttributes.Where ((v) => v.Constructor.DeclaringType.Name == "ExtensionAttribute").Any ()) + return; // Extension methods can't be mapped. + + var invalid_simd_type = false; + var contains_simd_types = ContainsSimdTypes (method, ref invalid_simd_type); + + var key = method.GetName (); + if (key == null) { + if (method.IsObsolete ()) + return; // Don't care about obsolete API. + + if (contains_simd_types && very_strict) { + // We can't map this method to a native function. + Console.WriteLine ($"!missing-simd-native-signature! {method}"); + } + return; + } + + ManagedSimdInfo existing; + if (managed_methods.TryGetValue (key, out existing)) { + if (very_strict) + Console.WriteLine ($"!duplicate-type-mapping! same key '{key}' for both '{existing.Method}' and '{method}'"); + } else { + managed_methods [key] = new ManagedSimdInfo { + Method = method, ContainsInvalidMappingForSimd = invalid_simd_type + }; + } + } + + bool ContainsSimdTypes (MethodDefinition method, ref bool invalid_for_simd) + { + if (IsSimdType (method.ReturnType, ref invalid_for_simd)) + return true; + + if (method.HasParameters) { + foreach (var param in method.Parameters) + if (IsSimdType (param.ParameterType, ref invalid_for_simd)) + return true; + } + + return false; + } + + bool IsSimdType (TypeReference td, ref bool invalid_for_simd) + { + return managed_simd_types.TryGetValue (td.Name, out invalid_for_simd); + } + + bool ContainsSimdTypes (ObjCMethodDecl decl, ref string simd_type, ref bool requires_marshal_directive) + { + if (IsSimdType (decl.ReturnQualType, ref simd_type, ref requires_marshal_directive)) + return true; + + var is_simd_type = false; + foreach (var param in decl.Parameters) + is_simd_type |= IsSimdType (param.QualType, ref simd_type, ref requires_marshal_directive); + + return is_simd_type; + } + + bool IsExtVector (QualType type, ref string simd_type) + { + var rv = false; + var t = type.CanonicalQualType.Type; + + // Unpoint the type + var pointerType = t as Clang.Ast.PointerType; + if (pointerType != null) + t = pointerType.PointeeQualType.Type; + + if (t.Kind == TypeKind.ExtVector) { + rv = true; + } else { + var r = (t as RecordType)?.Decl; + if (r != null) { + foreach (var f in r.Fields) { + var qt = f.QualType.CanonicalQualType.Type; + if (qt.Kind == TypeKind.ExtVector) { + rv = true; + break; + } + var at = qt as ConstantArrayType; + if (at != null) { + if (at.ElementType.Type.Kind == TypeKind.ExtVector) { + rv = true; + break; + } + } + } + } + } + + var typeName = type.ToString (); + + if (!rv && typeName.Contains ("simd")) + Console.WriteLine ($"!unknown-simd-type! Could not detect that {typeName} is a Simd type, but its name contains 'simd'. Something needs fixing in SimdCheck.cs"); + + if (rv) + simd_type = typeName; + + return rv; + } + + bool IsSimdType (QualType type, ref string simd_type, ref bool requires_marshal_directive) + { + var str = Undecorate (type.ToString ()); + + if (type_mapping.TryGetValue (str, out var info)) { + requires_marshal_directive = true; + simd_type = str; + return true; + } + + if (IsExtVector (type, ref simd_type)) + Console.WriteLine ($"!unknown-simd-type-mapping! The Simd type {simd_type} does not have a mapping to a managed type. Please add one in SimdCheck.cs"); + + return false; + } + + string Undecorate (string native_name) + { + if (native_name.StartsWith ("const ", StringComparison.Ordinal)) + return Undecorate (native_name.Substring ("const ".Length)); + + if (native_name.StartsWith ("struct ", StringComparison.Ordinal)) + return Undecorate (native_name.Substring ("struct ".Length)); + + const string _Nonnull = " _Nonnull"; + if (native_name.EndsWith (_Nonnull, StringComparison.Ordinal)) + return Undecorate (native_name.Substring (0, native_name.Length - _Nonnull.Length)); + + const string _Nullable = " _Nullable"; + if (native_name.EndsWith (_Nullable, StringComparison.Ordinal)) + return Undecorate (native_name.Substring (0, native_name.Length - _Nullable.Length)); + + const string _star = " *"; + if (native_name.EndsWith (_star, StringComparison.Ordinal)) + return Undecorate (native_name.Substring (0, native_name.Length - _star.Length)); + + return native_name; + } + + bool HasMarshalDirective (ICustomAttributeProvider provider) + { + if (provider?.HasCustomAttributes != true) + return false; + + foreach (var ca in provider.CustomAttributes) + if (ca.Constructor.DeclaringType.Name == "MarshalDirective") + return true; + + return false; + } + + void CheckMarshalDirective (MethodDefinition method, string simd_type) + { + if (!method.HasBody) + return; + + if (method.IsObsolete ()) + return; + + // The [MarshalDirective] attribute isn't copied to the generated code, + // so instead apply some heuristics and detect calls to the xamarin_simd__ P/Invoke, + // and if there are any, then assume the method binding has a [MarshalDirective]. + var body = method.Body; + var anyCalls = false; + foreach (var i in body.Instructions) { + switch (i.OpCode.Code) { + case Mono.Cecil.Cil.Code.Call: + case Mono.Cecil.Cil.Code.Calli: + case Mono.Cecil.Cil.Code.Callvirt: + var mr = i.Operand as MethodReference; + if (mr != null) { + if (mr.Name.StartsWith ("xamarin_simd__", StringComparison.Ordinal)) + return; + if (mr.Name.StartsWith ("xamarin_vector_float3__", StringComparison.Ordinal)) + return; + } + anyCalls = true; + break; + default: + break; + } + } + + // If the method doesn't call anywhere, it can't be broken. + // For instance if the method just throws an exception. + if (!anyCalls) + return; + + Console.WriteLine ($"!wrong-simd-missing-marshaldirective! {method}: simd type: {simd_type}"); + } + + public override void VisitObjCMethodDecl (ObjCMethodDecl decl, VisitKind visitKind) + { + if (visitKind != VisitKind.Enter) + return; + + // don't process methods (or types) that are unavailable for the current platform + if (!decl.IsAvailable () || !(decl.DeclContext as Decl).IsAvailable ()) + return; + + var simd_type = string.Empty; + var requires_marshal_directive = false; + var native_simd = ContainsSimdTypes (decl, ref simd_type, ref requires_marshal_directive); + + ManagedSimdInfo info; + managed_methods.TryGetValue (decl.GetName (), out info); + var method = info?.Method; + + if (!native_simd) { + if (method != null) { + // The managed method uses types that were incorrectly used in place of the correct Simd types, + // but the native method doesn't use the native Simd types. This means the binding is correct. + } else { + // Neither the managed nor the native method have anything to do with Simd types. + } + return; + } + + if (method == null) { + // Could not map the native method to a managed method. + // This needs investigation, to see why the native method couldn't be mapped. + + // Check if this is new API, in which case it probably couldn't be mapped because we haven't bound it. + var is_new = false; + var attrs = decl.Attrs.ToList (); + var parentClass = decl.DeclContext as Decl; + if (parentClass != null) + attrs.AddRange (parentClass.Attrs); + + foreach (var attr in attrs) { + var av_attr = attr as AvailabilityAttr; + if (av_attr == null) + continue; + if (av_attr.Platform.Name != "ios") + continue; + if (av_attr.Introduced.Major >= 11) { + is_new = true; + break; + } + } + if (is_new && !very_strict) + return; + if (!strict) + return; + Console.WriteLine ($"!missing-simd-managed-method! {decl}: could not find a managed method for the native method {decl.GetName ()} (selector: {decl.Selector}). Found the simd type '{simd_type}' in the native signature."); + return; + } + + if (!info.ContainsInvalidMappingForSimd) { + // The managed method does not have any types that are incorrect for Simd. + if (requires_marshal_directive) + CheckMarshalDirective (method, simd_type); + return; + } + + if (method.IsObsolete ()) { + // We have a potentially broken managed method, but it's obsolete. That's fine. + return; + } + + if (requires_marshal_directive) + CheckMarshalDirective (method, simd_type); + + // We have a potentially broken managed method. This needs fixing/investigation. + Console.WriteLine ($"!unknown-simd-type-in-signature! {method}: the native signature has a simd type ({simd_type}), while the corresponding managed method is using an incorrect (non-simd) type."); + } + } +} \ No newline at end of file diff --git a/tests/xtro-sharpie/common.ignore b/tests/xtro-sharpie/common.ignore index 2689d957e7..61ae64f1cd 100644 --- a/tests/xtro-sharpie/common.ignore +++ b/tests/xtro-sharpie/common.ignore @@ -1,3 +1,8 @@ +# ARKit + +## This method is manually bound. +!simd-missing-marshaldirective! System.IntPtr ARKit.ARPointCloud::GetRawPoints(): simd type: vector_float3 + # AVFoundation ## We only bind "finished" as we cannot use [Bind] here as it would break compatibility with iOS 6.x @@ -68,7 +73,6 @@ ## part of category GKScore_Deprecated !missing-selector! GKScore::playerID not bound - # Intents ## not exposed by our API (better use the OS version) @@ -201,7 +205,6 @@ !incorrect-protocol-member! MDLMeshBufferZone::allocator is REQUIRED and should be abstract !incorrect-protocol-member! MDLMeshBufferZone::capacity is REQUIRED and should be abstract - # Security ## part of mscorlib.dll -> mcs/class/corlib/CommonCrypto/CommonCrypto.cs to implement RNGCryptoServiceProvider diff --git a/tests/xtro-sharpie/xtro-sharpie.csproj b/tests/xtro-sharpie/xtro-sharpie.csproj index 856440adb1..d4e3c4ad5a 100644 --- a/tests/xtro-sharpie/xtro-sharpie.csproj +++ b/tests/xtro-sharpie/xtro-sharpie.csproj @@ -71,6 +71,7 @@ +