From 8608badd2bf2d99d13282d03136ce6a0a844cc21 Mon Sep 17 00:00:00 2001 From: VS MobileTools Engineering Service 2 Date: Tue, 21 Jun 2022 13:04:16 -0700 Subject: [PATCH] [release/6.0.4xx] [SceneKit] Fix SCNMatrix4 in .NET. Fixes #15094. (#15296) When we changed SCNMatrix4 to be column-major instead of row-major in .NET, there were several other related changes we should have done but didn't do. In particular we should have made transformation operations based on column-vectors instead of row-vectors. In legacy Xamarin, a vector would be transformed by a transformation matrix by doing matrix multiplication like this: [ x y z w] * [ 11 21 31 41 ] | 12 22 32 42 | | 13 23 33 43 | [ 14 24 34 41 ] In this case the vector is a row-vector, and it's the left operand in the multiplication. When using column-major matrices, we want to use column-vectors, where the vector is the right operand, like this: [ 11 21 31 41 ] * [ x ] | 12 22 32 42 | | y | | 13 23 33 43 | | z | [ 14 24 34 41 ] [ w ] This affects numerous APIs in SCNMatrix4, SCNVector3 and SCNVector4: * The M## fields have been changed to make the first number the column and the second number the row, to reflect that it's a column-major matrix. * Functions that return a transformation matrix have been modified to return column-vector transformers. Technically this means that these matrices are transposed compared to legacy Xamarin. The functions involved are: * CreateFromAxisAngle * CreateRotation[X|Y|Z] * CreateTranslation * CreatePerspectiveFieldOfView * CreatePerspectiveOffCenter * Rotate * LookAt * Combining two column-vector transforming transformation matrices is done by multiplying them in the reverse order, so the Mult function (and the multiplication operator) have been modified to multiply the given matrices in the opposite order (this matches how the SCNMatrix4Mult function does it). To make things clearer I've changed the parameter names for XAMCORE_5_0. * Functions that transform a vector using a transformation matrix have been modified to do a column-vector transformation instead of a row-vector transformation. This involves the following functions: * SCNVector3.TransformVector * SCNVector3.TransformNormal * SCNVector3.TransformNormalInverse * SCNVector3.TransformPosition * SCNVector4.Transform * Numerous new tests. Fixes https://github.com/xamarin/xamarin-macios/issues/15094. Backport of #15160 Co-authored-by: Rolf Bjarne Kvinge --- src/SceneKit/SCNMatrix4_dotnet.cs | 401 +++++--- src/SceneKit/SCNVector3.cs | 133 ++- src/SceneKit/SCNVector4.cs | 42 +- tests/bindings-test/StructsAndEnums.cs | 20 + tests/monotouch-test/Asserts.cs | 298 ++++++ .../monotouch-test/SceneKit/SCNMatrixTest.cs | 890 ++++++++++++++---- .../monotouch-test/SceneKit/SCNVector3Test.cs | 247 +++++ .../monotouch-test/SceneKit/SCNVector4Test.cs | 73 ++ tests/monotouch-test/monotouch-test.csproj | 2 + tests/test-libraries/libtest.h | 12 + tests/test-libraries/libtest.m | 18 + tests/test-libraries/rename.h | 6 + tests/xammac_tests/xammac_tests.csproj | 1 + .../automation/templates/tests/run-tests.yml | 1 + 14 files changed, 1772 insertions(+), 372 deletions(-) create mode 100644 tests/monotouch-test/SceneKit/SCNVector3Test.cs create mode 100644 tests/monotouch-test/SceneKit/SCNVector4Test.cs diff --git a/src/SceneKit/SCNMatrix4_dotnet.cs b/src/SceneKit/SCNMatrix4_dotnet.cs index 0bc1f3151650..1b0469c0d628 100644 --- a/src/SceneKit/SCNMatrix4_dotnet.cs +++ b/src/SceneKit/SCNMatrix4_dotnet.cs @@ -1,7 +1,4 @@ /* - * This keeps the code of OpenTK's Matrix4 almost intact, except we replace the - * Vector4 with a SCNVector4 - Copyright (c) 2006 - 2008 The Open Toolkit library. Copyright (c) 2014 Xamarin Inc. All rights reserved @@ -52,28 +49,55 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE namespace SceneKit { /// - /// Represents a 4x4 Matrix + /// Represents a 4x4 matrix using a column-major memory layout. /// [Serializable] public struct SCNMatrix4 : IEquatable { #region Fields + /* + * SCNMatrix4 is defined like this for iOS, tvOS and watchOS: + * + * typedef struct SCNMatrix4 { + * float m11, m12, m13, m14; + * float m21, m22, m23, m24; + * float m31, m32, m33, m34; + * float m41, m42, m43, m44; + * } SCNMatrix4; + * + * and like this for macOS: + * + * struct CATransform3D + * { + * CGFloat m11, m12, m13, m14; + * CGFloat m21, m22, m23, m24; + * CGFloat m31, m32, m33, m34; + * CGFloat m41, m42, m43, m44; + * }; + * typedef CATransform3D SCNMatrix4; + * + * It's not obvious from this definitions whether the matrix is row-major or column-major, and neither the documentation + * nor the headers are particularly helpful, but it's possible to do some math to figure it out. See this for more info: + * https://github.com/xamarin/xamarin-macios/issues/15094#issuecomment-1139699662 (result: SCNMatrix4 is using a column-major layout) + * + **/ + /// /// Left-most column of the matrix /// - public SCNVector4 Column0; + public SCNVector4 Column0; // m11, m12, m13, m14 /// /// 2nd column of the matrix /// - public SCNVector4 Column1; + public SCNVector4 Column1; // m21, m22, m23, m24 /// /// 3rd column of the matrix /// - public SCNVector4 Column2; + public SCNVector4 Column2; // m31, m32, m33, m34 /// /// Right-most column of the matrix /// - public SCNVector4 Column3; + public SCNVector4 Column3; // m41, m42, m43, m44 /// /// The identity matrix @@ -133,10 +157,10 @@ public SCNMatrix4 ( #if !WATCH public SCNMatrix4 (CoreAnimation.CATransform3D transform) { - Column0 = new SCNVector4 ((pfloat) transform.M11, (pfloat) transform.M21, (pfloat) transform.M31, (pfloat) transform.M41); - Column1 = new SCNVector4 ((pfloat) transform.M12, (pfloat) transform.M22, (pfloat) transform.M32, (pfloat) transform.M42); - Column2 = new SCNVector4 ((pfloat) transform.M13, (pfloat) transform.M23, (pfloat) transform.M33, (pfloat) transform.M43); - Column3 = new SCNVector4 ((pfloat) transform.M14, (pfloat) transform.M24, (pfloat) transform.M34, (pfloat) transform.M44); + Column0 = new SCNVector4 ((pfloat) transform.M11, (pfloat) transform.M12, (pfloat) transform.M13, (pfloat) transform.M14); + Column1 = new SCNVector4 ((pfloat) transform.M21, (pfloat) transform.M22, (pfloat) transform.M23, (pfloat) transform.M24); + Column2 = new SCNVector4 ((pfloat) transform.M31, (pfloat) transform.M32, (pfloat) transform.M33, (pfloat) transform.M34); + Column3 = new SCNVector4 ((pfloat) transform.M41, (pfloat) transform.M42, (pfloat) transform.M43, (pfloat) transform.M44); } #endif @@ -167,10 +191,10 @@ public pfloat Determinant { public SCNVector4 Row0 { get { return new SCNVector4 (Column0.X, Column1.X, Column2.X, Column3.X); } set { - M11 = value.X; - M12 = value.Y; - M13 = value.Z; - M14 = value.W; + Column0.X = value.X; + Column1.X = value.Y; + Column2.X = value.Z; + Column3.X = value.W; } } @@ -180,10 +204,10 @@ public SCNVector4 Row0 { public SCNVector4 Row1 { get { return new SCNVector4 (Column0.Y, Column1.Y, Column2.Y, Column3.Y); } set { - M21 = value.X; - M22 = value.Y; - M23 = value.Z; - M24 = value.W; + Column0.Y = value.X; + Column1.Y = value.Y; + Column2.Y = value.Z; + Column3.Y = value.W; } } @@ -193,10 +217,10 @@ public SCNVector4 Row1 { public SCNVector4 Row2 { get { return new SCNVector4 (Column0.Z, Column1.Z, Column2.Z, Column3.Z); } set { - M31 = value.X; - M32 = value.Y; - M33 = value.Z; - M34 = value.W; + Column0.Z = value.X; + Column1.Z = value.Y; + Column2.Z = value.Z; + Column3.Z = value.W; } } @@ -206,90 +230,90 @@ public SCNVector4 Row2 { public SCNVector4 Row3 { get { return new SCNVector4 (Column0.W, Column1.W, Column2.W, Column3.W); } set { - M41 = value.X; - M42 = value.Y; - M43 = value.Z; - M44 = value.W; + Column0.W = value.X; + Column1.W = value.Y; + Column2.W = value.Z; + Column3.W = value.W; } } /// - /// Gets or sets the value at row 1, column 1 of this instance. + /// Gets or sets the value at column 1, row 1 of this instance. /// public pfloat M11 { get { return Column0.X; } set { Column0.X = value; } } /// - /// Gets or sets the value at row 1, column 2 of this instance. + /// Gets or sets the value at column 1, row 2 of this instance. /// - public pfloat M12 { get { return Column1.X; } set { Column1.X = value; } } + public pfloat M12 { get { return Column0.Y; } set { Column0.Y = value; } } /// - /// Gets or sets the value at row 1, column 3 of this instance. + /// Gets or sets the value at column 1, row 3 of this instance. /// - public pfloat M13 { get { return Column2.X; } set { Column2.X = value; } } + public pfloat M13 { get { return Column0.Z; } set { Column0.Z = value; } } /// - /// Gets or sets the value at row 1, column 4 of this instance. + /// Gets or sets the value at column 1, row 4 of this instance. /// - public pfloat M14 { get { return Column3.X; } set { Column3.X = value; } } + public pfloat M14 { get { return Column0.W; } set { Column0.W = value; } } /// - /// Gets or sets the value at row 2, column 1 of this instance. + /// Gets or sets the value at column 2, row 1 of this instance. /// - public pfloat M21 { get { return Column0.Y; } set { Column0.Y = value; } } + public pfloat M21 { get { return Column1.X; } set { Column1.X = value; } } /// - /// Gets or sets the value at row 2, column 2 of this instance. + /// Gets or sets the value at column 2, row 2 of this instance. /// public pfloat M22 { get { return Column1.Y; } set { Column1.Y = value; } } /// - /// Gets or sets the value at row 2, column 3 of this instance. + /// Gets or sets the value at column 2, row 3 of this instance. /// - public pfloat M23 { get { return Column2.Y; } set { Column2.Y = value; } } + public pfloat M23 { get { return Column1.Z; } set { Column1.Z = value; } } /// - /// Gets or sets the value at row 2, column 4 of this instance. + /// Gets or sets the value at column 2, row 4 of this instance. /// - public pfloat M24 { get { return Column3.Y; } set { Column3.Y = value; } } + public pfloat M24 { get { return Column1.W; } set { Column1.W = value; } } /// - /// Gets or sets the value at row 3, column 1 of this instance. + /// Gets or sets the value at column 3, row 1 of this instance. /// - public pfloat M31 { get { return Column0.Z; } set { Column0.Z = value; } } + public pfloat M31 { get { return Column2.X; } set { Column2.X = value; } } /// - /// Gets or sets the value at row 3, column 2 of this instance. + /// Gets or sets the value at column 3, row 2 of this instance. /// - public pfloat M32 { get { return Column1.Z; } set { Column1.Z = value; } } + public pfloat M32 { get { return Column2.Y; } set { Column2.Y = value; } } /// - /// Gets or sets the value at row 3, column 3 of this instance. + /// Gets or sets the value at column 3, row 3 of this instance. /// public pfloat M33 { get { return Column2.Z; } set { Column2.Z = value; } } /// - /// Gets or sets the value at row 3, column 4 of this instance. + /// Gets or sets the value at column 3, row 4 of this instance. /// - public pfloat M34 { get { return Column3.Z; } set { Column3.Z = value; } } + public pfloat M34 { get { return Column2.W; } set { Column2.W = value; } } /// - /// Gets or sets the value at row 4, column 1 of this instance. + /// Gets or sets the value at column 4, row 1 of this instance. /// - public pfloat M41 { get { return Column0.W; } set { Column0.W = value; } } + public pfloat M41 { get { return Column3.X; } set { Column3.X = value; } } /// - /// Gets or sets the value at row 4, column 2 of this instance. + /// Gets or sets the value at column 4, row 2 of this instance. /// - public pfloat M42 { get { return Column1.W; } set { Column1.W = value; } } + public pfloat M42 { get { return Column3.Y; } set { Column3.Y = value; } } /// - /// Gets or sets the value at row 4, column 3 of this instance. + /// Gets or sets the value at column 4, row 3 of this instance. /// - public pfloat M43 { get { return Column2.W; } set { Column2.W = value; } } + public pfloat M43 { get { return Column3.Z; } set { Column3.Z = value; } } /// - /// Gets or sets the value at row 4, column 4 of this instance. + /// Gets or sets the value at column 4, row 4 of this instance. /// public pfloat M44 { get { return Column3.W; } set { Column3.W = value; } } @@ -358,44 +382,85 @@ public static void CreateFromColumns (SCNVector4 column0, SCNVector4 column1, SC /// A matrix instance. public static void CreateFromAxisAngle (SCNVector3 axis, pfloat angle, out SCNMatrix4 result) { - pfloat cos = (float) System.Math.Cos (-angle); - pfloat sin = (float) System.Math.Sin (-angle); - pfloat t = 1.0f - cos; - axis.Normalize (); - result = new SCNMatrix4 (t * axis.X * axis.X + cos, t * axis.X * axis.Y - sin * axis.Z, t * axis.X * axis.Z + sin * axis.Y, 0.0f, - t * axis.X * axis.Y + sin * axis.Z, t * axis.Y * axis.Y + cos, t * axis.Y * axis.Z - sin * axis.X, 0.0f, - t * axis.X * axis.Z - sin * axis.Y, t * axis.Y * axis.Z + sin * axis.X, t * axis.Z * axis.Z + cos, 0.0f, - 0, 0, 0, 1); + CreateFromAxisAngle (axis.X, axis.Y, axis.Z, angle, out result); } public static void CreateFromAxisAngle (Vector3 axis, float angle, out SCNMatrix4 result) { - pfloat cos = (float) System.Math.Cos (-angle); - pfloat sin = (float) System.Math.Sin (-angle); - pfloat t = 1.0f - cos; - axis = Vector3.Normalize (axis); - result = new SCNMatrix4 (t * axis.X * axis.X + cos, t * axis.X * axis.Y - sin * axis.Z, t * axis.X * axis.Z + sin * axis.Y, 0.0f, - t * axis.X * axis.Y + sin * axis.Z, t * axis.Y * axis.Y + cos, t * axis.Y * axis.Z - sin * axis.X, 0.0f, - t * axis.X * axis.Z - sin * axis.Y, t * axis.Y * axis.Z + sin * axis.X, t * axis.Z * axis.Z + cos, 0.0f, - 0, 0, 0, 1); + CreateFromAxisAngle (axis.X, axis.Y, axis.Z, angle, out result); } public static void CreateFromAxisAngle (Vector3d axis, double angle, out SCNMatrix4 result) { - double cos = System.Math.Cos (-angle); - double sin = System.Math.Sin (-angle); - double t = 1.0f - cos; - axis.Normalize (); - result = new SCNMatrix4 ((pfloat) (t * axis.X * axis.X + cos), (pfloat) (t * axis.X * axis.Y - sin * axis.Z), (pfloat) (t * axis.X * axis.Z + sin * axis.Y), (pfloat) (0.0f), - (pfloat) ( t * axis.X * axis.Y + sin * axis.Z), (pfloat) (t * axis.Y * axis.Y + cos), (pfloat) (t * axis.Y * axis.Z - sin * axis.X), (pfloat) 0.0f, - (pfloat) (t * axis.X * axis.Z - sin * axis.Y), (pfloat) (t * axis.Y * axis.Z + sin * axis.X), (pfloat) (t * axis.Z * axis.Z + cos), (pfloat) 0.0f, - 0, 0, 0, 1); + CreateFromAxisAngle (axis.X, axis.Y, axis.Z, angle, out result); + } + + /// + /// Build a rotation matrix from the specified axis/angle rotation. + /// + /// The x part of the normalized axis to rotate about. + /// The y part of the normalized axis to rotate about. + /// The z part of the normalized axis to rotate about. + /// Angle in radians to rotate counter-clockwise (looking in the direction of the given axis). + /// A matrix instance. + static void CreateFromAxisAngle (float x, float y, float z, float angle, out SCNMatrix4 result) + { + var cos = MathF.Cos (-angle); + var sin = MathF.Sin (-angle); + var t = 1.0f - cos; + + var m11 = t * x * x + cos; + var m12 = t * x * y - sin * z; + var m13 = t * x * z + sin * y; + var m21 = t * x * y + sin * z; + var m22 = t * y * y + cos; + var m23 = t * y * z - sin * x; + var m31 = t * x * z - sin * y; + var m32 = t * y * z + sin * x; + var m33 = t * z * z + cos; + + result = new SCNMatrix4 ( + m11, m21, m31, 0.0f, + m12, m22, m32, 0.0f, + m13, m23, m33, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f); + } + + /// + /// Build a rotation matrix from the specified axis/angle rotation. + /// + /// The x part of the normalized axis to rotate about. + /// The y part of the normalized axis to rotate about. + /// The z part of the normalized axis to rotate about. + /// Angle in radians to rotate counter-clockwise (looking in the direction of the given axis). + /// A matrix instance. + static void CreateFromAxisAngle (double x, double y, double z, double angle, out SCNMatrix4 result) + { + var cos = Math.Cos (-angle); + var sin = Math.Sin (-angle); + var t = 1.0f - cos; + + var m11 = (pfloat) (t * x * x + cos); + var m12 = (pfloat) (t * x * y - sin * z); + var m13 = (pfloat) (t * x * z + sin * y); + var m21 = (pfloat) (t * x * y + sin * z); + var m22 = (pfloat) (t * y * y + cos); + var m23 = (pfloat) (t * y * z - sin * x); + var m31 = (pfloat) (t * x * z - sin * y); + var m32 = (pfloat) (t * y * z + sin * x); + var m33 = (pfloat) (t * z * z + cos); + + result = new SCNMatrix4 ( + m11, m21, m31, 0.0f, + m12, m22, m32, 0.0f, + m13, m23, m33, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f); } /// @@ -425,11 +490,11 @@ public static void CreateRotationX (pfloat angle, out SCNMatrix4 result) pfloat cos = (pfloat) System.Math.Cos (angle); pfloat sin = (pfloat) System.Math.Sin (angle); - result = new SCNMatrix4 (); - result.Row0 = SCNVector4.UnitX; - result.Row1 = new SCNVector4 (0.0f, cos, sin, 0.0f); - result.Row2 = new SCNVector4 (0.0f, -sin, cos, 0.0f); - result.Row3 = SCNVector4.UnitW; + result = new SCNMatrix4 ( + 1, 0, 0, 0, + 0, cos, -sin, 0, + 0, sin, cos, 0, + 0, 0, 0, 1); } /// @@ -454,11 +519,11 @@ public static void CreateRotationY (pfloat angle, out SCNMatrix4 result) pfloat cos = (pfloat) System.Math.Cos (angle); pfloat sin = (pfloat) System.Math.Sin (angle); - result = new SCNMatrix4 (); - result.Row0 = new SCNVector4 (cos, 0.0f, -sin, 0.0f); - result.Row1 = SCNVector4.UnitY; - result.Row2 = new SCNVector4 (sin, 0.0f, cos, 0.0f); - result.Row3 = SCNVector4.UnitW; + result = new SCNMatrix4 ( + cos, 0, sin, 0, + 0, 1, 0, 0, + -sin, 0, cos, 0, + 0, 0, 0, 1); } /// @@ -483,11 +548,11 @@ public static void CreateRotationZ (pfloat angle, out SCNMatrix4 result) pfloat cos = (pfloat) System.Math.Cos (angle); pfloat sin = (pfloat) System.Math.Sin (angle); - result = new SCNMatrix4 (); - result.Row0 = new SCNVector4 (cos, sin, 0.0f, 0.0f); - result.Row1 = new SCNVector4 (-sin, cos, 0.0f, 0.0f); - result.Row2 = SCNVector4.UnitZ; - result.Row3 = SCNVector4.UnitW; + result = new SCNMatrix4 ( + cos, -sin, 0, 0, + sin, cos, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1); } /// @@ -515,8 +580,11 @@ public static SCNMatrix4 CreateRotationZ (pfloat angle) /// The resulting SCNMatrix4 instance. public static void CreateTranslation (pfloat x, pfloat y, pfloat z, out SCNMatrix4 result) { - result = Identity; - result.Row3 = new SCNVector4 (x, y, z, 1); + result = new SCNMatrix4 ( + 1, 0, 0, x, + 0, 1, 0, y, + 0, 0, 1, z, + 0, 0, 0, 1); } /// @@ -526,8 +594,7 @@ public static void CreateTranslation (pfloat x, pfloat y, pfloat z, out SCNMatri /// The resulting SCNMatrix4 instance. public static void CreateTranslation (ref SCNVector3 vector, out SCNMatrix4 result) { - result = Identity; - result.Row3 = new SCNVector4 (vector.X, vector.Y, vector.Z, 1); + CreateTranslation (vector.X, vector.Y, vector.Z, out result); } /// @@ -743,10 +810,11 @@ public static void CreatePerspectiveOffCenter (pfloat left, pfloat right, pfloat pfloat c = -(zFar + zNear) / (zFar - zNear); pfloat d = -(2.0f * zFar * zNear) / (zFar - zNear); - result = new SCNMatrix4 (x, 0, 0, 0, - 0, y, 0, 0, - a, b, c, -1, - 0, 0, d, 0); + result = new SCNMatrix4 ( + x, 0, a, 0, + 0, y, b, 0, + 0, 0, c, d, + 0, 0, -1, 0); } /// @@ -807,12 +875,11 @@ public static SCNMatrix4 Scale (SCNVector3 scale) /// A scaling matrix public static SCNMatrix4 Scale (pfloat x, pfloat y, pfloat z) { - var result = new SCNMatrix4 (); - result.Row0 = SCNVector4.UnitX * x; - result.Row1 = SCNVector4.UnitY * y; - result.Row2 = SCNVector4.UnitZ * z; - result.Row3 = SCNVector4.UnitW; - return result; + return new SCNMatrix4 ( + x, 0, 0, 0, + 0, y, 0, 0, + 0, 0, z, 0, + 0, 0, 0, 1); } #endregion @@ -865,10 +932,11 @@ public static SCNMatrix4 LookAt (SCNVector3 eye, SCNVector3 target, SCNVector3 u SCNVector3 x = SCNVector3.Normalize (SCNVector3.Cross (up, z)); SCNVector3 y = SCNVector3.Normalize (SCNVector3.Cross (z, x)); - SCNMatrix4 rot = new SCNMatrix4 (new SCNVector4 (x.X, y.X, z.X, 0.0f), - new SCNVector4 (x.Y, y.Y, z.Y, 0.0f), - new SCNVector4 (x.Z, y.Z, z.Z, 0.0f), - SCNVector4.UnitW); + SCNMatrix4 rot = new SCNMatrix4 ( + x.X, x.Y, x.Z, 0.0f, + y.X, y.Y, y.Z, 0.0f, + z.X, z.Y, z.Z, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f); SCNMatrix4 trans = SCNMatrix4.CreateTranslation (-eye); @@ -898,43 +966,92 @@ public static SCNMatrix4 LookAt (pfloat eyeX, pfloat eyeY, pfloat eyeZ, pfloat t #region Multiply Functions /// - /// Multiplies two instances. + /// Combines two transformation matrices. /// - /// The left operand of the multiplication. - /// The right operand of the multiplication. - /// A new instance that is the result of the multiplication - public static SCNMatrix4 Mult (SCNMatrix4 left, SCNMatrix4 right) +#if XAMCORE_5_0 + /// + /// Combining two transformation matrices means using matrix multiplication to multiply them in the reverse order (secondTransformation * firstTransformation). + /// + /// The first transformation of the combination. + /// The second transformation of the combination. +#else + /// + /// Combining two transformation matrices means using matrix multiplication to multiply them in the reverse order (right * left). + /// + /// The first transformation of the combination. + /// The second transformation of the combination. +#endif + /// A new instance that is the result of the combination +#if XAMCORE_5_0 + public static SCNMatrix4 Mult (SCNMatrix4 firstTransformation, SCNMatrix4 secondTransformation) +#else + public static SCNMatrix4 Mult(SCNMatrix4 left, SCNMatrix4 right) +#endif { SCNMatrix4 result; - Mult (ref left, ref right, out result); + // the matrices are reversed: https://github.com/xamarin/xamarin-macios/issues/15094#issuecomment-1139699662 +#if XAMCORE_5_0 + MatrixMultiply (ref secondTransformation, ref firstTransformation, out result); +#else + MatrixMultiply (ref right, ref left, out result); +#endif return result; } /// - /// Multiplies two instances. + /// Combines two transformation matrices. /// - /// The left operand of the multiplication. - /// The right operand of the multiplication. - /// A new instance that is the result of the multiplication - public static void Mult (ref SCNMatrix4 left, ref SCNMatrix4 right, out SCNMatrix4 result) +#if XAMCORE_5_0 + /// + /// Combining two transformation matrices means using matrix multiplication to multiply them in the reverse order (secondTransformation * firstTransformation). + /// + /// The first transformation of the combination. + /// The second transformation of the combination. +#else + /// + /// Combining two transformation matrices means using matrix multiplication to multiply them in the reverse order (right * left). + /// + /// The first transformation of the combination. + /// The second transformation of the combination. +#endif + /// A new instance that is the result of the combination +#if XAMCORE_5_0 + public static void Mult (ref SCNMatrix4 firstTransformation, ref SCNMatrix4 secondTransformation, out SCNMatrix4 result) +#else + public static void Mult(ref SCNMatrix4 left, ref SCNMatrix4 right, out SCNMatrix4 result) +#endif { - result = new SCNMatrix4 ( - left.M11 * right.M11 + left.M12 * right.M21 + left.M13 * right.M31 + left.M14 * right.M41, - left.M11 * right.M12 + left.M12 * right.M22 + left.M13 * right.M32 + left.M14 * right.M42, - left.M11 * right.M13 + left.M12 * right.M23 + left.M13 * right.M33 + left.M14 * right.M43, - left.M11 * right.M14 + left.M12 * right.M24 + left.M13 * right.M34 + left.M14 * right.M44, - left.M21 * right.M11 + left.M22 * right.M21 + left.M23 * right.M31 + left.M24 * right.M41, - left.M21 * right.M12 + left.M22 * right.M22 + left.M23 * right.M32 + left.M24 * right.M42, - left.M21 * right.M13 + left.M22 * right.M23 + left.M23 * right.M33 + left.M24 * right.M43, - left.M21 * right.M14 + left.M22 * right.M24 + left.M23 * right.M34 + left.M24 * right.M44, - left.M31 * right.M11 + left.M32 * right.M21 + left.M33 * right.M31 + left.M34 * right.M41, - left.M31 * right.M12 + left.M32 * right.M22 + left.M33 * right.M32 + left.M34 * right.M42, - left.M31 * right.M13 + left.M32 * right.M23 + left.M33 * right.M33 + left.M34 * right.M43, - left.M31 * right.M14 + left.M32 * right.M24 + left.M33 * right.M34 + left.M34 * right.M44, - left.M41 * right.M11 + left.M42 * right.M21 + left.M43 * right.M31 + left.M44 * right.M41, - left.M41 * right.M12 + left.M42 * right.M22 + left.M43 * right.M32 + left.M44 * right.M42, - left.M41 * right.M13 + left.M42 * right.M23 + left.M43 * right.M33 + left.M44 * right.M43, - left.M41 * right.M14 + left.M42 * right.M24 + left.M43 * right.M34 + left.M44 * right.M44); + // the matrices are reversed: https://github.com/xamarin/xamarin-macios/issues/15094#issuecomment-1139699662 +#if XAMCORE_5_0 + MatrixMultiply (ref secondTransformation, ref firstTransformation, out result); +#else + MatrixMultiply (ref right, ref left, out result); +#endif + } + + // Multiply two matrices in the order you'd expect (left * right). + static void MatrixMultiply (ref SCNMatrix4 left, ref SCNMatrix4 right, out SCNMatrix4 result) + { + result = new SCNMatrix4( + left.Column0.X * right.Column0.X + left.Column1.X * right.Column0.Y + left.Column2.X * right.Column0.Z + left.Column3.X * right.Column0.W, + left.Column0.X * right.Column1.X + left.Column1.X * right.Column1.Y + left.Column2.X * right.Column1.Z + left.Column3.X * right.Column1.W, + left.Column0.X * right.Column2.X + left.Column1.X * right.Column2.Y + left.Column2.X * right.Column2.Z + left.Column3.X * right.Column2.W, + left.Column0.X * right.Column3.X + left.Column1.X * right.Column3.Y + left.Column2.X * right.Column3.Z + left.Column3.X * right.Column3.W, + + left.Column0.Y * right.Column0.X + left.Column1.Y * right.Column0.Y + left.Column2.Y * right.Column0.Z + left.Column3.Y * right.Column0.W, + left.Column0.Y * right.Column1.X + left.Column1.Y * right.Column1.Y + left.Column2.Y * right.Column1.Z + left.Column3.Y * right.Column1.W, + left.Column0.Y * right.Column2.X + left.Column1.Y * right.Column2.Y + left.Column2.Y * right.Column2.Z + left.Column3.Y * right.Column2.W, + left.Column0.Y * right.Column3.X + left.Column1.Y * right.Column3.Y + left.Column2.Y * right.Column3.Z + left.Column3.Y * right.Column3.W, + + left.Column0.Z * right.Column0.X + left.Column1.Z * right.Column0.Y + left.Column2.Z * right.Column0.Z + left.Column3.Z * right.Column0.W, + left.Column0.Z * right.Column1.X + left.Column1.Z * right.Column1.Y + left.Column2.Z * right.Column1.Z + left.Column3.Z * right.Column1.W, + left.Column0.Z * right.Column2.X + left.Column1.Z * right.Column2.Y + left.Column2.Z * right.Column2.Z + left.Column3.Z * right.Column2.W, + left.Column0.Z * right.Column3.X + left.Column1.Z * right.Column3.Y + left.Column2.Z * right.Column3.Z + left.Column3.Z * right.Column3.W, + + left.Column0.W * right.Column0.X + left.Column1.W * right.Column0.Y + left.Column2.W * right.Column0.Z + left.Column3.W * right.Column0.W, + left.Column0.W * right.Column1.X + left.Column1.W * right.Column1.Y + left.Column2.W * right.Column1.Z + left.Column3.W * right.Column1.W, + left.Column0.W * right.Column2.X + left.Column1.W * right.Column2.Y + left.Column2.W * right.Column2.Z + left.Column3.W * right.Column2.W, + left.Column0.W * right.Column3.X + left.Column1.W * right.Column3.Y + left.Column2.W * right.Column3.Z + left.Column3.W * right.Column3.W); } #endregion @@ -1102,7 +1219,7 @@ public static void Transpose (ref SCNMatrix4 mat, out SCNMatrix4 result) #region public override string ToString() /// - /// Returns a System.String that represents the current SCNMatrix44. + /// Returns a System.String that represents the current SCNMatrix4. /// /// public override string ToString () diff --git a/src/SceneKit/SCNVector3.cs b/src/SceneKit/SCNVector3.cs index 22ed3c65c5c4..b25d792bb14e 100644 --- a/src/SceneKit/SCNVector3.cs +++ b/src/SceneKit/SCNVector3.cs @@ -740,29 +740,53 @@ public static void BaryCentric(ref SCNVector3 a, ref SCNVector3 b, ref SCNVector #region Transform +#if NET + /// Transform a direction vector by the given Matrix + /// Assumes the matrix has a right-most column of (0,0,0,1), that is the translation part is ignored. + /// + /// The column vector to transform +#else /// Transform a direction vector by the given Matrix /// Assumes the matrix has a bottom row of (0,0,0,1), that is the translation part is ignored. /// - /// The vector to transform + /// The row vector to transform +#endif /// The desired transformation /// The transformed vector public static SCNVector3 TransformVector(SCNVector3 vec, SCNMatrix4 mat) { - SCNVector3 v; - v.X = SCNVector3.Dot(vec, new SCNVector3(mat.Column0)); - v.Y = SCNVector3.Dot(vec, new SCNVector3(mat.Column1)); - v.Z = SCNVector3.Dot(vec, new SCNVector3(mat.Column2)); + TransformVector (ref vec, ref mat, out var v); return v; } +#if NET + /// Transform a direction vector by the given Matrix + /// Assumes the matrix has a right-most column of (0,0,0,1), that is the translation part is ignored. + /// + /// The column vector to transform +#else /// Transform a direction vector by the given Matrix /// Assumes the matrix has a bottom row of (0,0,0,1), that is the translation part is ignored. /// - /// The vector to transform + /// The row vector to transform +#endif /// The desired transformation /// The transformed vector public static void TransformVector(ref SCNVector3 vec, ref SCNMatrix4 mat, out SCNVector3 result) { +#if NET + result.X = vec.X * mat.Row0.X + + vec.Y * mat.Row0.Y + + vec.Z * mat.Row0.Z; + + result.Y = vec.X * mat.Row1.X + + vec.Y * mat.Row1.Y + + vec.Z * mat.Row1.Z; + + result.Z = vec.X * mat.Row2.X + + vec.Y * mat.Row2.Y + + vec.Z * mat.Row2.Z; +#else result.X = vec.X * mat.Row0.X + vec.Y * mat.Row1.X + vec.Z * mat.Row2.X; @@ -774,6 +798,7 @@ public static void TransformVector(ref SCNVector3 vec, ref SCNMatrix4 mat, out S result.Z = vec.X * mat.Row0.Z + vec.Y * mat.Row1.Z + vec.Z * mat.Row2.Z; +#endif } /// Transform a Normal by the given Matrix @@ -781,7 +806,11 @@ public static void TransformVector(ref SCNVector3 vec, ref SCNMatrix4 mat, out S /// This calculates the inverse of the given matrix, use TransformNormalInverse if you /// already have the inverse to avoid this extra calculation /// - /// The normal to transform +#if NET + /// The column-based normal to transform +#else + /// The row-based normal to transform +#endif /// The desired transformation /// The transformed normal public static SCNVector3 TransformNormal(SCNVector3 norm, SCNMatrix4 mat) @@ -795,7 +824,11 @@ public static SCNVector3 TransformNormal(SCNVector3 norm, SCNMatrix4 mat) /// This calculates the inverse of the given matrix, use TransformNormalInverse if you /// already have the inverse to avoid this extra calculation /// - /// The normal to transform +#if NET + /// The column-based normal to transform +#else + /// The row-based normal to transform +#endif /// The desired transformation /// The transformed normal public static void TransformNormal(ref SCNVector3 norm, ref SCNMatrix4 mat, out SCNVector3 result) @@ -809,15 +842,16 @@ public static void TransformNormal(ref SCNVector3 norm, ref SCNMatrix4 mat, out /// This version doesn't calculate the inverse matrix. /// Use this version if you already have the inverse of the desired transform to hand /// - /// The normal to transform +#if NET + /// The column-based normal to transform +#else + /// The row-based normal to transform +#endif /// The inverse of the desired transformation /// The transformed normal public static SCNVector3 TransformNormalInverse(SCNVector3 norm, SCNMatrix4 invMat) { - SCNVector3 n; - n.X = SCNVector3.Dot(norm, new SCNVector3(invMat.Row0)); - n.Y = SCNVector3.Dot(norm, new SCNVector3(invMat.Row1)); - n.Z = SCNVector3.Dot(norm, new SCNVector3(invMat.Row2)); + TransformNormalInverse (ref norm, ref invMat, out var n); return n; } @@ -826,11 +860,28 @@ public static SCNVector3 TransformNormalInverse(SCNVector3 norm, SCNMatrix4 invM /// This version doesn't calculate the inverse matrix. /// Use this version if you already have the inverse of the desired transform to hand /// - /// The normal to transform +#if NET + /// The column-based normal to transform +#else + /// The row-based normal to transform +#endif /// The inverse of the desired transformation /// The transformed normal public static void TransformNormalInverse(ref SCNVector3 norm, ref SCNMatrix4 invMat, out SCNVector3 result) { +#if NET + result.X = norm.X * invMat.Column0.X + + norm.Y * invMat.Column0.Y + + norm.Z * invMat.Column0.Z; + + result.Y = norm.X * invMat.Column1.X + + norm.Y * invMat.Column1.Y + + norm.Z * invMat.Column1.Z; + + result.Z = norm.X * invMat.Column2.X + + norm.Y * invMat.Column2.Y + + norm.Z * invMat.Column2.Z; +#else result.X = norm.X * invMat.Row0.X + norm.Y * invMat.Row0.Y + norm.Z * invMat.Row0.Z; @@ -842,27 +893,49 @@ public static void TransformNormalInverse(ref SCNVector3 norm, ref SCNMatrix4 in result.Z = norm.X * invMat.Row2.X + norm.Y * invMat.Row2.Y + norm.Z * invMat.Row2.Z; +#endif } /// Transform a Position by the given Matrix - /// The position to transform +#if NET + /// The column-based position to transform +#else + /// The row-based position to transform +#endif /// The desired transformation /// The transformed position public static SCNVector3 TransformPosition(SCNVector3 pos, SCNMatrix4 mat) { - SCNVector3 p; - p.X = SCNVector3.Dot(pos, new SCNVector3(mat.Column0)) + mat.Row3.X; - p.Y = SCNVector3.Dot(pos, new SCNVector3(mat.Column1)) + mat.Row3.Y; - p.Z = SCNVector3.Dot(pos, new SCNVector3(mat.Column2)) + mat.Row3.Z; + TransformPosition (ref pos, ref mat, out var p); return p; } /// Transform a Position by the given Matrix - /// The position to transform +#if NET + /// The column-based position to transform +#else + /// The row-based position to transform +#endif /// The desired transformation /// The transformed position public static void TransformPosition(ref SCNVector3 pos, ref SCNMatrix4 mat, out SCNVector3 result) { +#if NET + result.X = mat.Row0.X * pos.X + + mat.Row0.Y * pos.Y + + mat.Row0.Z * pos.Z + + mat.Row0.W; + + result.Y = mat.Row1.X * pos.X + + mat.Row1.Y * pos.Y + + mat.Row1.Z * pos.Z + + mat.Row1.W; + + result.Z = mat.Row2.X * pos.X + + mat.Row2.Y * pos.Y + + mat.Row2.Z * pos.Z + + mat.Row2.W; +#else result.X = pos.X * mat.Row0.X + pos.Y * mat.Row1.X + pos.Z * mat.Row2.X + @@ -877,25 +950,29 @@ public static void TransformPosition(ref SCNVector3 pos, ref SCNMatrix4 mat, out pos.Y * mat.Row1.Z + pos.Z * mat.Row2.Z + mat.Row3.Z; +#endif } /// Transform a Vector by the given Matrix - /// The vector to transform +#if NET + /// The column vector to transform +#else + /// The row vector to transform +#endif /// The desired transformation /// The transformed vector public static SCNVector4 Transform(SCNVector3 vec, SCNMatrix4 mat) { SCNVector4 v4 = new SCNVector4(vec.X, vec.Y, vec.Z, 1.0f); - SCNVector4 result; - result.X = SCNVector4.Dot(v4, mat.Column0); - result.Y = SCNVector4.Dot(v4, mat.Column1); - result.Z = SCNVector4.Dot(v4, mat.Column2); - result.W = SCNVector4.Dot(v4, mat.Column3); - return result; + return SCNVector4.Transform (v4, mat); } /// Transform a Vector by the given Matrix - /// The vector to transform +#if NET + /// The column vector to transform +#else + /// The row vector to transform +#endif /// The desired transformation /// The transformed vector public static void Transform(ref SCNVector3 vec, ref SCNMatrix4 mat, out SCNVector4 result) diff --git a/src/SceneKit/SCNVector4.cs b/src/SceneKit/SCNVector4.cs index f8097c2cb4e8..d07bd7345437 100644 --- a/src/SceneKit/SCNVector4.cs +++ b/src/SceneKit/SCNVector4.cs @@ -843,25 +843,50 @@ public static void BaryCentric(ref SCNVector4 a, ref SCNVector4 b, ref SCNVector #region Transform /// Transform a Vector by the given Matrix - /// The vector to transform +#if NET + /// The column vector to transform +#else + /// The row vector to transform +#endif /// The desired transformation /// The transformed vector public static SCNVector4 Transform(SCNVector4 vec, SCNMatrix4 mat) { - SCNVector4 result; - result.X = SCNVector4.Dot(vec, mat.Column0); - result.Y = SCNVector4.Dot(vec, mat.Column1); - result.Z = SCNVector4.Dot(vec, mat.Column2); - result.W = SCNVector4.Dot(vec, mat.Column3); + Transform(ref vec, ref mat, out var result); return result; } - /// Transform a Vector by the given Matrix - /// The vector to transform + /// Transform a Vector by the given Matrix. +#if NET + /// The column vector to transform +#else + /// The row vector to transform +#endif /// The desired transformation /// The transformed vector public static void Transform(ref SCNVector4 vec, ref SCNMatrix4 mat, out SCNVector4 result) { +#if NET + result.X = vec.X * mat.Column0.X + + vec.Y * mat.Column1.X + + vec.Z * mat.Column2.X + + vec.W * mat.Column3.X; + + result.Y = vec.X * mat.Column0.Y + + vec.Y * mat.Column1.Y + + vec.Z * mat.Column2.Y + + vec.W * mat.Column3.Y; + + result.Z = vec.X * mat.Column0.Z + + vec.Y * mat.Column1.Z + + vec.Z * mat.Column2.Z + + vec.W * mat.Column3.Z; + + result.W = vec.X * mat.Column0.W + + vec.Y * mat.Column1.W + + vec.Z * mat.Column2.W + + vec.W * mat.Column3.W; +#else result.X = vec.X * mat.Row0.X + vec.Y * mat.Row1.X + vec.Z * mat.Row2.X + @@ -881,6 +906,7 @@ public static void Transform(ref SCNVector4 vec, ref SCNMatrix4 mat, out SCNVect vec.Y * mat.Row1.W + vec.Z * mat.Row2.W + vec.W * mat.Row3.W; +#endif } #endregion diff --git a/tests/bindings-test/StructsAndEnums.cs b/tests/bindings-test/StructsAndEnums.cs index e4737da9d9d6..a8c66280a921 100644 --- a/tests/bindings-test/StructsAndEnums.cs +++ b/tests/bindings-test/StructsAndEnums.cs @@ -3,6 +3,7 @@ using Foundation; using ObjCRuntime; +using SceneKit; #if NET using MatrixFloat2x2 = global::CoreGraphics.NMatrix2; @@ -16,6 +17,16 @@ using MatrixFloat4x4 = global::OpenTK.NMatrix4; #endif +#if __MACOS__ +#if NET +using pfloat = System.Runtime.InteropServices.NFloat; +#else +using pfloat = System.nfloat; +#endif +#else +using pfloat = System.Single; +#endif + public static class LibTest { [DllImport ("__Internal")] public static extern int theUltimateAnswer (); @@ -126,5 +137,14 @@ public static MatrixFloat4x4 MDLTransform_GetRotationMatrix (INativeObject obj, r3c0, r3c1, r3c2, r3c3); } #endif + + [DllImport ("__Internal")] + public static extern SCNMatrix4 x_SCNMatrix4MakeTranslation (pfloat tx, pfloat ty, pfloat tz); + + [DllImport ("__Internal")] + public static extern SCNMatrix4 x_SCNMatrix4MakeScale (pfloat tx, pfloat ty, pfloat tz); + + [DllImport ("__Internal")] + public static extern SCNMatrix4 x_SCNMatrix4Translate (SCNMatrix4 m, pfloat tx, pfloat ty, pfloat tz); } } diff --git a/tests/monotouch-test/Asserts.cs b/tests/monotouch-test/Asserts.cs index 9a4557d20557..852a5800bbdc 100644 --- a/tests/monotouch-test/Asserts.cs +++ b/tests/monotouch-test/Asserts.cs @@ -1,8 +1,15 @@ using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Text; + #if !__WATCHOS__ using ModelIO; using MetalPerformanceShaders; #endif +#if HAS_SCENEKIT +using SceneKit; +#endif #if NET using System.Numerics; @@ -31,6 +38,16 @@ using VectorDouble3 = global::OpenTK.NVector3d; #endif +#if __MACOS__ +#if NET +using pfloat = System.Runtime.InteropServices.NFloat; +#else +using pfloat = System.nfloat; +#endif +#else +using pfloat = System.Single; +#endif + using NUnit.Framework; public static class Asserts @@ -714,4 +731,285 @@ public static void AreEqual (NMatrix4x3 expected, NMatrix4x3 actual, string mess AreEqual (expected.M34, actual.M34, $"{message} (M34) expected: {expected} actual: {actual}"); } #endregion + +#if HAS_SCENEKIT + public static void AreEqual (SCNVector3 expected, SCNVector3 actual, string message) + { + if (AreEqual (expected.X, actual.X, out var dX) & + AreEqual (expected.Y, actual.Y, out var dY) & + AreEqual (expected.Z, actual.Z, out var dZ)) + return; + + var diffString = $"({dX}, {dY}, {dZ})"; + var msg = $"{message}\nExpected:\n{expected}\nActual:\n{actual}\nDiff:\n{diffString}"; + Assert.Fail (msg); + } + + public static void AreEqual (SCNVector3 expected, SCNVector3 actual, pfloat delta, string message) + { + if (AreEqual (expected.X, actual.X, delta, out var dX) & + AreEqual (expected.Y, actual.Y, delta, out var dY) & + AreEqual (expected.Z, actual.Z, delta, out var dZ)) + return; + + var diffString = $"({dX}, {dY}, {dZ})"; + var msg = $"{message}\nExpected:\n{expected}\nActual:\n{actual}\nDiff:\n{diffString}"; + Assert.Fail (msg); + } + + public static void AreEqual (SCNVector4 expected, SCNVector4 actual, string message) + { + if (AreEqual (expected.X, actual.X, out var dX) & + AreEqual (expected.Y, actual.Y, out var dY) & + AreEqual (expected.Z, actual.Z, out var dZ) & + AreEqual (expected.W, actual.W, out var dW)) + return; + + var diffString = $"({dX}, {dY}, {dZ}, {dW})"; + var msg = $"{message}\nExpected:\n{expected}\nActual:\n{actual}\nDiff:\n{diffString}"; + Assert.Fail (msg); + } + + + public static void AreEqual (SCNVector4 expected, SCNVector4 actual, pfloat delta, string message) + { + if (AreEqual (expected.X, actual.X, delta, out var dX) & + AreEqual (expected.Y, actual.Y, delta, out var dY) & + AreEqual (expected.Z, actual.Z, delta, out var dZ) & + AreEqual (expected.W, actual.W, delta, out var dW)) + return; + + var diffString = $"({dX}, {dY}, {dZ}, {dW})"; + var msg = $"{message}\nExpected:\n{expected}\nActual:\n{actual}\nDiff:\n{diffString}"; + Assert.Fail (msg); + } + + public static void AreEqual (SCNQuaternion expected, SCNQuaternion actual, string message) + { + if (AreEqual (expected.X, actual.X, out var dX) & + AreEqual (expected.Y, actual.Y, out var dY) & + AreEqual (expected.Z, actual.Z, out var dZ) & + AreEqual (expected.W, actual.W, out var dW)) + return; + + var diffString = $"[{dX}, {dY}, {dZ}, {dW}]"; + var msg = $"{message}\nExpected:\n{expected}\nActual:\n{actual}\nDiff:\n{diffString}"; + Assert.Fail (msg); + } + + public static void AreEqual (SCNQuaternion expected, SCNQuaternion actual, pfloat delta, string message) + { + if (AreEqual (expected.X, actual.X, delta, out var dX) & + AreEqual (expected.Y, actual.Y, delta, out var dY) & + AreEqual (expected.Z, actual.Z, delta, out var dZ) & + AreEqual (expected.W, actual.W, delta, out var dW)) + return; + + var diffString = $"[{dX}, {dY}, {dZ}, {dW}]"; + var msg = $"{message}\nExpected:\n{expected}\nActual:\n{actual}\nDiff:\n{diffString}"; + Assert.Fail (msg); + } + + public static void AreEqual (SCNMatrix4 expected, SCNMatrix4 actual, string message) + { + if (AreEqual (expected.M11, actual.M11, out var d11) & + AreEqual (expected.M21, actual.M21, out var d21) & + AreEqual (expected.M31, actual.M31, out var d31) & + AreEqual (expected.M41, actual.M41, out var d41) & + AreEqual (expected.M12, actual.M12, out var d12) & + AreEqual (expected.M22, actual.M22, out var d22) & + AreEqual (expected.M32, actual.M32, out var d32) & + AreEqual (expected.M42, actual.M42, out var d42) & + AreEqual (expected.M13, actual.M13, out var d13) & + AreEqual (expected.M23, actual.M23, out var d23) & + AreEqual (expected.M33, actual.M33, out var d33) & + AreEqual (expected.M43, actual.M43, out var d43) & + AreEqual (expected.M14, actual.M14, out var d14) & + AreEqual (expected.M24, actual.M24, out var d24) & + AreEqual (expected.M34, actual.M34, out var d34) & + AreEqual (expected.M44, actual.M44, out var d44)) { + + var size = Marshal.SizeOf (typeof (SCNMatrix4)); + unsafe { + byte* e = (byte*) (void*) &expected; + byte* a = (byte*) (void*) &actual; + AreEqual (e, a, size, message); + } + return; + } + + var actualString = actual.ToString (); + + var expectedString = expected.ToString (); + + var diffRow1 = $"({d11}, {d12}, {d13}, {d14})"; + var diffRow2 = $"({d21}, {d22}, {d23}, {d24})"; + var diffRow3 = $"({d31}, {d32}, {d33}, {d34})"; + var diffRow4 = $"({d41}, {d42}, {d43}, {d44})"; + var diffString = $"{diffRow1}\n{diffRow2}\n{diffRow3}\n{diffRow4}"; + + var msg = $"{message}\nExpected:\n{expected}\nActual:\n{actual}\nDiff:\n{diffString}"; + Assert.Fail (msg); + } + + public static void AreEqual (SCNMatrix4 expected, SCNMatrix4 actual, pfloat delta, string message) + { + if (AreEqual (expected.M11, actual.M11, delta, out var d11) & + AreEqual (expected.M21, actual.M21, delta, out var d21) & + AreEqual (expected.M31, actual.M31, delta, out var d31) & + AreEqual (expected.M41, actual.M41, delta, out var d41) & + AreEqual (expected.M12, actual.M12, delta, out var d12) & + AreEqual (expected.M22, actual.M22, delta, out var d22) & + AreEqual (expected.M32, actual.M32, delta, out var d32) & + AreEqual (expected.M42, actual.M42, delta, out var d42) & + AreEqual (expected.M13, actual.M13, delta, out var d13) & + AreEqual (expected.M23, actual.M23, delta, out var d23) & + AreEqual (expected.M33, actual.M33, delta, out var d33) & + AreEqual (expected.M43, actual.M43, delta, out var d43) & + AreEqual (expected.M14, actual.M14, delta, out var d14) & + AreEqual (expected.M24, actual.M24, delta, out var d24) & + AreEqual (expected.M34, actual.M34, delta, out var d34) & + AreEqual (expected.M44, actual.M44, delta, out var d44)) + return; + + var actualString = actual.ToString (); + var expectedString = expected.ToString (); + + var diffRow1 = $"({d11}, {d12}, {d13}, {d14})"; + var diffRow2 = $"({d21}, {d22}, {d23}, {d24})"; + var diffRow3 = $"({d31}, {d32}, {d33}, {d34})"; + var diffRow4 = $"({d41}, {d42}, {d43}, {d44})"; + var diffString = $"{diffRow1}\n{diffRow2}\n{diffRow3}\n{diffRow4}"; + + var msg = $"{message}\nExpected:\n{expectedString}\nActual:\n{actualString}\nDiff:\n{diffString}"; + Assert.Fail (msg); + } + + + // The m## arguments correspond with the M## fields in SCNMatrix4 + // For .NET this means the first four values are the first column (and the first row for legacy Xamarin). + public static void AreEqual (SCNMatrix4 actual, string message, + pfloat m11, pfloat m12, pfloat m13, pfloat m14, + pfloat m21, pfloat m22, pfloat m23, pfloat m24, + pfloat m31, pfloat m32, pfloat m33, pfloat m34, + pfloat m41, pfloat m42, pfloat m43, pfloat m44) + { + AreEqual (actual, message, + m11, m12, m13, m14, + m21, m22, m23, m24, + m31, m32, m33, m34, + m41, m42, m43, m44, + delta: 0); + } + + // The m## arguments correspond with the M## fields in SCNMatrix4 + // For .NET this means the first four values are the first column (and the first row for legacy Xamarin). + public static void AreEqual (SCNMatrix4 actual, string message, + pfloat m11, pfloat m12, pfloat m13, pfloat m14, + pfloat m21, pfloat m22, pfloat m23, pfloat m24, + pfloat m31, pfloat m32, pfloat m33, pfloat m34, + pfloat m41, pfloat m42, pfloat m43, pfloat m44, + pfloat delta + ) + { + if (AreEqual (m11, actual.M11, delta, out var d11) & + AreEqual (m21, actual.M21, delta, out var d21) & + AreEqual (m31, actual.M31, delta, out var d31) & + AreEqual (m41, actual.M41, delta, out var d41) & + AreEqual (m12, actual.M12, delta, out var d12) & + AreEqual (m22, actual.M22, delta, out var d22) & + AreEqual (m32, actual.M32, delta, out var d32) & + AreEqual (m42, actual.M42, delta, out var d42) & + AreEqual (m13, actual.M13, delta, out var d13) & + AreEqual (m23, actual.M23, delta, out var d23) & + AreEqual (m33, actual.M33, delta, out var d33) & + AreEqual (m43, actual.M43, delta, out var d43) & + AreEqual (m14, actual.M14, delta, out var d14) & + AreEqual (m24, actual.M24, delta, out var d24) & + AreEqual (m34, actual.M34, delta, out var d34) & + AreEqual (m44, actual.M44, delta, out var d44)) + return; + + var actualString = actual.ToString (); + +#if NET + var row1 = $"({m11}, {m21}, {m31}, {m41})"; + var row2 = $"({m12}, {m22}, {m32}, {m42})"; + var row3 = $"({m13}, {m23}, {m33}, {m43})"; + var row4 = $"({m14}, {m24}, {m34}, {m44})"; +#else + var row1 = $"({m11}, {m12}, {m13}, {m14})"; + var row2 = $"({m21}, {m22}, {m23}, {m24})"; + var row3 = $"({m31}, {m32}, {m33}, {m34})"; + var row4 = $"({m41}, {m42}, {m43}, {m44})"; +#endif + var expectedString = $"{row1}\n{row2}\n{row3}\n{row4}"; + + var diffRow1 = $"({d11}, {d12}, {d13}, {d14})"; + var diffRow2 = $"({d21}, {d22}, {d23}, {d24})"; + var diffRow3 = $"({d31}, {d32}, {d33}, {d34})"; + var diffRow4 = $"({d41}, {d42}, {d43}, {d44})"; + var diffString = $"{diffRow1}\n{diffRow2}\n{diffRow3}\n{diffRow4}"; + + var msg = $"{message}\nExpected:\n{expectedString}\nActual:\n{actualString}\nDiff:\n{diffString}"; + Assert.Fail (msg); + } +#endif // HAS_SCENEKIT + + static bool AreEqual (pfloat expected, pfloat actual, out string emojii) + { + return AreEqual (expected, actual, 0, out emojii); + } + + // Use our own implementation to compare two floating point numbers with a tolerance, because + // the NUnit version doesn't seem to work correctly in legacy Xamarin (older NUnit version?). + static bool AreEqual (pfloat expected, pfloat actual, pfloat tolerance, out string emojii) + { + bool rv; + + if (pfloat.IsNaN (expected) && pfloat.IsNaN (actual)) { + rv = true; + } else if (pfloat.IsInfinity (expected) || pfloat.IsNaN (expected) || pfloat.IsNaN (actual)) { + // Handle infinity specially since subtracting two infinite values gives + // NaN and the following test fails. mono also needs NaN to be handled + // specially although ms.net could use either method. Also, handle + // situation where no tolerance is used. + rv = expected.Equals (actual); + } else { + rv = Math.Abs (expected - actual) <= tolerance; + } + + emojii = rv ? "✅" : "❌"; + + return rv; + } + + public unsafe static void AreEqual (byte* expected, byte* actual, int length, string message) + { + // Check if the byte arrays are identical + var equal = true; + for (var i = 0; i < length; i++) { + var e = expected [i]; + var a = actual [i]; + equal &= e == a; + } + if (equal) + return; + // They're not. Create the assertion message and assert. + var e_sb = new StringBuilder (); + var a_sb = new StringBuilder (); + var d_sb = new StringBuilder (); + for (var i = 0; i < length; i++) { + var e = expected [i]; + var a = actual [i]; + e_sb.Append ($"0x{e:X2} "); + a_sb.Append ($"0x{a:X2} "); + if (e == a) { + d_sb.Append (" "); + } else { + d_sb.Append ("^^^^ "); + } + } + Assert.Fail ($"{message}\nExpected: {e_sb}\nActual: {a_sb}\n {d_sb}"); + } } diff --git a/tests/monotouch-test/SceneKit/SCNMatrixTest.cs b/tests/monotouch-test/SceneKit/SCNMatrixTest.cs index 7f10d5a9d829..f7e0ad37f602 100644 --- a/tests/monotouch-test/SceneKit/SCNMatrixTest.cs +++ b/tests/monotouch-test/SceneKit/SCNMatrixTest.cs @@ -12,6 +12,7 @@ #nullable enable using System; +using System.Runtime.InteropServices; using CoreAnimation; using Foundation; using SceneKit; @@ -57,67 +58,21 @@ public class SCNMatrix4Test { static pfloat SqrtTwelve = (pfloat) (Math.Sqrt (12)); // 3.464102 static pfloat OhPointFive = (pfloat) 0.5; - public static bool CloseEnough (double a, double b, double epsilon = 0.00001) - { - const double MinNormal = 2.2250738585072014E-308d; - var absA = Math.Abs (a); - var absB = Math.Abs (b); - var diff = Math.Abs (a - b); - - if (a == b) { - return true; - } else if (a == 0 || b == 0 || absA + absB < MinNormal) { - // a or b is zero or both are extremely close to it - // relative error is less meaningful here - return diff < (epsilon * MinNormal); - } else { // use relative error - return diff / (absA + absB) < epsilon; - } - } - - void AssertEqual (SCNMatrix4 matrix, string message, - pfloat m11, pfloat m12, pfloat m13, pfloat m14, - pfloat m21, pfloat m22, pfloat m23, pfloat m24, - pfloat m31, pfloat m32, pfloat m33, pfloat m34, - pfloat m41, pfloat m42, pfloat m43, pfloat m44 - ) - { - if (CloseEnough (m11, matrix.M11) && CloseEnough (m12, matrix.M12) && CloseEnough (m13, matrix.M13) && CloseEnough (m14, matrix.M14) && - CloseEnough (m21, matrix.M21) && CloseEnough (m22, matrix.M22) && CloseEnough (m23, matrix.M23) && CloseEnough (m24, matrix.M24) && - CloseEnough (m31, matrix.M31) && CloseEnough (m32, matrix.M32) && CloseEnough (m33, matrix.M33) && CloseEnough (m34, matrix.M34) && - CloseEnough (m41, matrix.M41) && CloseEnough (m42, matrix.M42) && CloseEnough (m43, matrix.M43) && CloseEnough (m44, matrix.M44)) - return; - - var actualString = matrix.ToString (); - - var row1 = $"({m11}, {m12}, {m13}, {m14})"; - var row2 = $"({m21}, {m22}, {m23}, {m24})"; - var row3 = $"({m31}, {m32}, {m33}, {m34})"; - var row4 = $"({m41}, {m42}, {m43}, {m44})"; - var expectedString = $"{row1}\n{row2}\n{row3}\n{row4}"; - Assert.Fail ($"Expected matrix:\n{expectedString}\nActual matrix:\n{actualString}\n{message}"); - } - - void AssertEqual (SCNVector4 vector, string message, pfloat m1, pfloat m2, pfloat m3, pfloat m4) - { - if (m1 == vector.X && m2 == vector.Y && m3 == vector.Z && m4 == vector.W) - return; - - var expectedString = vector.ToString (); - var actualString = $"({m1}, {m2}, {m3}, {m4})"; - - Assert.Fail ($"Expected vector:\n{expectedString}\nActual vector:\n{actualString}\n{message}"); - } - [Test] public void Identity () { var matrix = SCNMatrix4.Identity; - AssertEqual (matrix, "Identity", + var expected = new SCNMatrix4 ( 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); + + Asserts.AreEqual (expected, matrix, "Identity"); + + var pos = new SCNVector3 (10, 20, 30); + var transformed = SCNVector3.TransformPosition (pos, matrix); + Asserts.AreEqual (pos, transformed, "Transformed"); } [Test] @@ -128,11 +83,20 @@ public void Constructor_RowVectors () new SCNVector4 (21, 22, 23, 24), new SCNVector4 (31, 32, 33, 34), new SCNVector4 (41, 42, 43, 44)); - AssertEqual (matrix, "Constructor", + var expected = new SCNMatrix4 ( 11, 12, 13, 14, 21, 22, 23, 24, 31, 32, 33, 34, 41, 42, 43, 44); + Asserts.AreEqual (expected, matrix, "Constructor"); + + var pos = new SCNVector3 (10, 20, 30); + var transformed = SCNVector3.TransformPosition (pos, matrix); +#if NET + Asserts.AreEqual (new SCNVector3 (754, 1364, 1974), transformed, "Transformed"); +#else + Asserts.AreEqual (new SCNVector3 (1501, 1562, 1623), transformed, "Transformed"); +#endif } [Test] @@ -143,11 +107,27 @@ public void Constructor_Elements () 21, 22, 23, 24, 31, 32, 33, 34, 41, 42, 43, 44); - AssertEqual (matrix, "Constructor", + + Asserts.AreEqual (matrix, "Constructor", +#if NET + 11, 21, 31, 41, + 12, 22, 32, 42, + 13, 23, 33, 43, + 14, 24, 34, 44); +#else 11, 12, 13, 14, 21, 22, 23, 24, 31, 32, 33, 34, 41, 42, 43, 44); +#endif + + var pos = new SCNVector3 (10, 20, 30); + var transformed = SCNVector3.TransformPosition (pos, matrix); +#if NET + Asserts.AreEqual (new SCNVector3 (754, 1364, 1974), transformed, "Transformed"); +#else + Asserts.AreEqual (new SCNVector3 (1501, 1562, 1623), transformed, "Transformed"); +#endif } #if !WATCH @@ -155,29 +135,25 @@ public void Constructor_Elements () public void Constructor_CATransform3d () { var transform = new CATransform3D () { - M11 = 11, - M12 = 12, - M13 = 13, - M14 = 14, - M21 = 21, - M22 = 22, - M23 = 23, - M24 = 24, - M31 = 31, - M32 = 32, - M33 = 33, - M34 = 34, - M41 = 41, - M42 = 42, - M43 = 43, - M44 = 44, + M11 = 11, M12 = 12, M13 = 13, M14 = 14, + M21 = 21, M22 = 22, M23 = 23, M24 = 24, + M31 = 31, M32 = 32, M33 = 33, M34 = 34, + M41 = 41, M42 = 42, M43 = 43, M44 = 44, }; var matrix = new SCNMatrix4 (transform); - AssertEqual (matrix, "Constructor", - 11, 12, 13, 14, - 21, 22, 23, 24, - 31, 32, 33, 34, - 41, 42, 43, 44); + var expected = new SCNMatrix4 ( + 11, 21, 31, 41, + 12, 22, 32, 42, + 13, 23, 33, 43, + 14, 24, 34, 44); +#if !NET + expected.Transpose (); +#endif + Asserts.AreEqual (expected, matrix, "Constructor"); + + var pos = new SCNVector3 (10, 20, 30); + var transformed = SCNVector3.TransformPosition (pos, matrix); + Asserts.AreEqual (new SCNVector3 (1501, 1562, 1623), transformed, "Transformed"); } #endif @@ -201,20 +177,30 @@ public void Rows () 21, 22, 23, 24, 31, 32, 33, 34, 41, 42, 43, 44); - AssertEqual (matrix.Row0, "Row0", 11, 12, 13, 14); - AssertEqual (matrix.Row1, "Row1", 21, 22, 23, 24); - AssertEqual (matrix.Row2, "Row2", 31, 32, 33, 34); - AssertEqual (matrix.Row3, "Row3", 41, 42, 43, 44); + Asserts.AreEqual (matrix.Row0, new SCNVector4 (11, 12, 13, 14), "Row0"); + Asserts.AreEqual (matrix.Row1, new SCNVector4 (21, 22, 23, 24), "Row1"); + Asserts.AreEqual (matrix.Row2, new SCNVector4 (31, 32, 33, 34), "Row2"); + Asserts.AreEqual (matrix.Row3, new SCNVector4 (41, 42, 43, 44), "Row3"); } [Test] public void Elements () { + // We're column-major in .NET, which means the first number (M#.) is the column, + // and the second number (M.#) is the row. That's the reverse of how it's in legacy + // Xamarin. var matrix = new SCNMatrix4 ( +#if NET + 11, 21, 31, 41, + 12, 22, 32, 42, + 13, 23, 33, 43, + 14, 24, 34, 44); +#else 11, 12, 13, 14, 21, 22, 23, 24, 31, 32, 33, 34, 41, 42, 43, 44); +#endif Assert.AreEqual ((pfloat) 11, matrix.M11, "M11"); Assert.AreEqual ((pfloat) 12, matrix.M12, "M12"); Assert.AreEqual ((pfloat) 13, matrix.M13, "M13"); @@ -231,6 +217,10 @@ public void Elements () Assert.AreEqual ((pfloat) 42, matrix.M42, "M42"); Assert.AreEqual ((pfloat) 43, matrix.M43, "M43"); Assert.AreEqual ((pfloat) 44, matrix.M44, "M44"); + + var pos = new SCNVector3 (10, 20, 30); + var transformed = SCNVector3.TransformPosition (pos, matrix); + Asserts.AreEqual (new SCNVector3 (1501, 1562, 1623), transformed, "Transformed"); } #if NET // The legacy Invert implementation seems very wrong, so only verify .NET behavior @@ -250,13 +240,22 @@ public void Invert () 5, 3, 5, 8, 9, 6, 4, 2, 4, 6, 9, 8); + var originalMatrix = matrix; matrix.Invert (); - AssertEqual (matrix, "Invert", + Assert.AreEqual (SCNMatrix4Invert (originalMatrix), matrix, "Native"); + + var expected = new SCNMatrix4 ( (pfloat) (-0.6181818181818182), (pfloat) (0.3151515151515151), (pfloat) (-0.030303030303030304), (pfloat) (0.3878787878787879), (pfloat) (1.6363636363636365), (pfloat) (-0.696969696969697), (pfloat) (0.3939393939393939), (pfloat) (-1.2424242424242424), (pfloat) (-1.3818181818181818), (pfloat) (0.3515151515151515), (pfloat) (-0.30303030303030304), (pfloat) (1.2787878787878788), (pfloat) (0.6363636363636364), (pfloat) (-0.030303030303030304), (pfloat) (0.06060606060606061), (pfloat) (-0.5757575757575758)); + + Asserts.AreEqual (expected, matrix, (pfloat) 0.00001, "Invert"); + + var pos = new SCNVector3 (10, 20, 30); + var transformed = SCNVector3.TransformPosition (pos, matrix); + Asserts.AreEqual (new SCNVector3 (-0.4f, 13, -14.6f), transformed, 0.00001f, "Transformed"); } #endif @@ -269,11 +268,20 @@ public void Transpose () new SCNVector4 (31, 32, 33, 34), new SCNVector4 (41, 42, 43, 44)); matrix.Transpose (); - AssertEqual (matrix, "Transpose", + var expected = new SCNMatrix4 ( 11, 21, 31, 41, 12, 22, 32, 42, 13, 23, 33, 43, 14, 24, 34, 44); + Asserts.AreEqual (expected, matrix, "Transpose"); + + var pos = new SCNVector3 (10, 20, 30); + var transformed = SCNVector3.TransformPosition (pos, matrix); +#if NET + Asserts.AreEqual (new SCNVector3 (1501, 1562, 1623), transformed, "Transformed"); +#else + Asserts.AreEqual (new SCNVector3 (754, 1364, 1974), transformed, "Transformed"); +#endif } [Test] @@ -284,11 +292,20 @@ public void CreateFromColumns () new SCNVector4 (21, 22, 23, 24), new SCNVector4 (31, 32, 33, 34), new SCNVector4 (41, 42, 43, 44)); - AssertEqual (matrix, "CreateFromColumns", + var expected = new SCNMatrix4 ( 11, 21, 31, 41, 12, 22, 32, 42, 13, 23, 33, 43, 14, 24, 34, 44); + Asserts.AreEqual (expected, matrix, "CreateFromColumns"); + + var pos = new SCNVector3 (10, 20, 30); + var transformed = SCNVector3.TransformPosition (pos, matrix); +#if NET + Asserts.AreEqual (new SCNVector3 (1501, 1562, 1623), transformed, "Transformed"); +#else + Asserts.AreEqual (new SCNVector3 (754, 1364, 1974), transformed, "Transformed"); +#endif } [Test] @@ -300,132 +317,249 @@ public void CreateFromColumns_Out () new SCNVector4 (31, 32, 33, 34), new SCNVector4 (41, 42, 43, 44), out var matrix); - AssertEqual (matrix, "CreateFromColumns", + var expected = new SCNMatrix4 ( 11, 21, 31, 41, 12, 22, 32, 42, 13, 23, 33, 43, 14, 24, 34, 44); + Asserts.AreEqual (expected, matrix, "CreateFromColumns"); + + var pos = new SCNVector3 (10, 20, 30); + var transformed = SCNVector3.TransformPosition (pos, matrix); +#if NET + Asserts.AreEqual (new SCNVector3 (1501, 1562, 1623), transformed, "Transformed"); +#else + Asserts.AreEqual (new SCNVector3 (754, 1364, 1974), transformed, "Transformed"); +#endif } [Test] public void CreateFromAxisAngle_pfloat_Out () { SCNMatrix4.CreateFromAxisAngle (new SCNVector3 (2, 2, 2), (pfloat) (Math.PI / 3), out var matrix); - AssertEqual (matrix, "CreateFromAxisAngle", + var expected = new SCNMatrix4 ( + TwoThirds, -OneThird, TwoThirds, 0, TwoThirds, TwoThirds, -OneThird, 0, -OneThird, TwoThirds, TwoThirds, 0, - TwoThirds, -OneThird, TwoThirds, 0, 0, 0, 0, 1); +#if !NET + expected.Transpose (); +#endif + Asserts.AreEqual (expected, matrix, (pfloat) 0.000001f, "CreateFromAxisAngle"); + + var pos = new SCNVector3 (10, 20, 30); + var transformed = SCNVector3.TransformPosition (pos, matrix); + Asserts.AreEqual (new SCNVector3 (20, 10, 30), transformed, (pfloat) 0.00001, "Transformed"); } [Test] public void CreateFromAxisAngle_float_Out () { SCNMatrix4.CreateFromAxisAngle (new Vector3 (2, 2, 2), (float) (Math.PI / 3), out var matrix); - AssertEqual (matrix, "CreateFromAxisAngle", + var expected = new SCNMatrix4 ( + TwoThirds, -OneThird, TwoThirds, 0, TwoThirds, TwoThirds, -OneThird, 0, -OneThird, TwoThirds, TwoThirds, 0, - TwoThirds, -OneThird, TwoThirds, 0, 0, 0, 0, 1); +#if !NET + expected.Transpose (); +#endif + Asserts.AreEqual (expected, matrix, (pfloat) 0.000001f, "CreateFromAxisAngle"); + + var pos = new SCNVector3 (10, 20, 30); + var transformed = SCNVector3.TransformPosition (pos, matrix); + Asserts.AreEqual (new SCNVector3 (20, 10, 30), transformed, (pfloat) 0.00001, "Transformed"); } [Test] public void CreateFromAxisAngle_double_Out () { SCNMatrix4.CreateFromAxisAngle (new Vector3d (2, 2, 2), (double) (Math.PI / 3), out var matrix); - AssertEqual (matrix, "CreateFromAxisAngle", + var expected = new SCNMatrix4 ( + TwoThirds, -OneThird, TwoThirds, 0, TwoThirds, TwoThirds, -OneThird, 0, -OneThird, TwoThirds, TwoThirds, 0, - TwoThirds, -OneThird, TwoThirds, 0, 0, 0, 0, 1); +#if !NET + expected.Transpose (); +#endif + Asserts.AreEqual (expected, matrix, (pfloat) 0.000001f, "CreateFromAxisAngle"); + + var pos = new SCNVector3 (10, 20, 30); + var transformed = SCNVector3.TransformPosition (pos, matrix); + Asserts.AreEqual (new SCNVector3 (20, 10, 30), transformed, (pfloat) 0.000001, "Transformed"); } [Test] public void CreateFromAxisAngle () { var matrix = SCNMatrix4.CreateFromAxisAngle (new SCNVector3 (2, 2, 2), (pfloat) (Math.PI / 3)); - AssertEqual (matrix, "CreateFromAxisAngle", + var expected = new SCNMatrix4 ( + TwoThirds, -OneThird, TwoThirds, 0, TwoThirds, TwoThirds, -OneThird, 0, -OneThird, TwoThirds, TwoThirds, 0, - TwoThirds, -OneThird, TwoThirds, 0, 0, 0, 0, 1); +#if !NET + expected.Transpose (); +#endif + Asserts.AreEqual (expected, matrix, (pfloat) 0.000001f, "CreateFromAxisAngle"); + + var pos = new SCNVector3 (10, 20, 30); + var transformed = SCNVector3.TransformPosition (pos, matrix); + Asserts.AreEqual (new SCNVector3 (20, 10, 30), transformed, 0.00001f, "Transformed"); } [Test] public void CreateRotationX_Out () { - SCNMatrix4.CreateRotationX ((pfloat) (Math.PI / 3), out var matrix); - AssertEqual (matrix, "CreateRotationX", + var angle = (pfloat) (Math.PI / 3); + SCNMatrix4.CreateRotationX (angle, out var matrix); + var expected = new SCNMatrix4 ( 1, 0, 0, 0, - 0, OhPointFive, SqrtThreeHalved, 0, - 0, -SqrtThreeHalved, OhPointFive, 0, + 0, OhPointFive, -SqrtThreeHalved, 0, + 0, SqrtThreeHalved, OhPointFive, 0, 0, 0, 0, 1); +#if !NET + expected.Transpose (); +#endif + Asserts.AreEqual (expected, matrix, (pfloat) 0.000001f, "CreateRotationX"); + + Asserts.AreEqual (SCNMatrix4MakeRotation (angle, 1, 0, 0), matrix, 0.00001f, "Native"); + + var pos = new SCNVector3 (10, 20, 30); + var transformed = SCNVector3.TransformPosition (pos, matrix); + Asserts.AreEqual (new SCNVector3 (10, -15.980762f, 32.320508f), transformed, 0.0001f, "Transformed"); } [Test] public void CreateRotationX () { - var matrix = SCNMatrix4.CreateRotationX ((pfloat) (Math.PI / 3)); - AssertEqual (matrix, "CreateRotationX", + var angle = (pfloat) (Math.PI / 3); + var matrix = SCNMatrix4.CreateRotationX (angle); + var expected = new SCNMatrix4 ( 1, 0, 0, 0, - 0, OhPointFive, SqrtThreeHalved, 0, - 0, -SqrtThreeHalved, OhPointFive, 0, + 0, OhPointFive, -SqrtThreeHalved, 0, + 0, SqrtThreeHalved, OhPointFive, 0, 0, 0, 0, 1); +#if !NET + expected.Transpose (); +#endif + Asserts.AreEqual (expected, matrix, (pfloat) 0.000001f, "CreateRotationX"); + + Asserts.AreEqual (SCNMatrix4MakeRotation (angle, 1, 0, 0), matrix, 0.00001f, "Native"); + + var pos = new SCNVector3 (10, 20, 30); + var transformed = SCNVector3.TransformPosition (pos, matrix); + Asserts.AreEqual (new SCNVector3 (10, -15.980762f, 32.320508f), transformed, 0.0001f, "Transformed"); } [Test] public void CreateRotationY_Out () { + var angle = (pfloat) (Math.PI / 3); SCNMatrix4.CreateRotationY ((pfloat) (Math.PI / 3), out var matrix); - AssertEqual (matrix, "CreateRotationY", - OhPointFive, 0, -SqrtThreeHalved, 0, + var expected = new SCNMatrix4 ( + OhPointFive, 0, SqrtThreeHalved, 0, 0, 1, 0, 0, - SqrtThreeHalved, 0, OhPointFive, 0, + -SqrtThreeHalved, 0, OhPointFive, 0, 0, 0, 0, 1); +#if !NET + expected.Transpose (); +#endif + Asserts.AreEqual (expected, matrix, (pfloat) 0.000001f, "CreateRotationY"); + + Asserts.AreEqual (SCNMatrix4MakeRotation (angle, 0, 1, 0), matrix, 0.00001f, "Native"); + + var pos = new SCNVector3 (10, 20, 30); + var transformed = SCNVector3.TransformPosition (pos, matrix); + Asserts.AreEqual (new SCNVector3 (30.98076f, 20, 6.33974f), transformed, 0.0001f, "Transformed"); } [Test] public void CreateRotationY () { - var matrix = SCNMatrix4.CreateRotationY ((pfloat) (Math.PI / 3)); - AssertEqual (matrix, "CreateRotationY", - OhPointFive, 0, -SqrtThreeHalved, 0, + var angle = (pfloat) (Math.PI / 3); + var matrix = SCNMatrix4.CreateRotationY (angle); + var expected = new SCNMatrix4 ( + OhPointFive, 0, SqrtThreeHalved, 0, 0, 1, 0, 0, - SqrtThreeHalved, 0, OhPointFive, 0, + -SqrtThreeHalved, 0, OhPointFive, 0, 0, 0, 0, 1); +#if !NET + expected.Transpose (); +#endif + Asserts.AreEqual (expected, matrix, (pfloat) 0.000001f, "CreateRotationY"); + + Asserts.AreEqual (SCNMatrix4MakeRotation (angle, 0, 1, 0), matrix, 0.00001f, "Native"); + + var pos = new SCNVector3 (10, 20, 30); + var transformed = SCNVector3.TransformPosition (pos, matrix); + Asserts.AreEqual (new SCNVector3 (30.98076f, 20, 6.33974f), transformed, 0.00001f, "Transformed"); } [Test] public void CreateRotationZ_Out () { - SCNMatrix4.CreateRotationZ ((pfloat) (Math.PI / 3), out var matrix); - AssertEqual (matrix, "CreateRotationZ", - OhPointFive, SqrtThreeHalved, 0, 0, - -SqrtThreeHalved, OhPointFive, 0, 0, + var angle = (pfloat) (Math.PI / 3); + SCNMatrix4.CreateRotationZ (angle, out var matrix); + var expected = new SCNMatrix4 ( + OhPointFive, -SqrtThreeHalved, 0, 0, + SqrtThreeHalved, OhPointFive, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); +#if !NET + expected.Transpose (); +#endif + Asserts.AreEqual (expected, matrix, (pfloat) 0.000001f, "CreateRotationZ"); + + Asserts.AreEqual (SCNMatrix4MakeRotation (angle, 0, 0, 1), matrix, 0.00001f, "Native"); + + var pos = new SCNVector3 (10, 20, 30); + var transformed = SCNVector3.TransformPosition (pos, matrix); + Asserts.AreEqual (new SCNVector3 (-12.320508f, 18.66025f, 30), transformed, 0.00001f, "Transformed"); } [Test] public void CreateRotationZ () { - var matrix = SCNMatrix4.CreateRotationZ ((pfloat) (Math.PI / 3)); - AssertEqual (matrix, "CreateRotationZ", - OhPointFive, SqrtThreeHalved, 0, 0, - -SqrtThreeHalved, OhPointFive, 0, 0, + var angle = (pfloat) (Math.PI / 3); + var matrix = SCNMatrix4.CreateRotationZ (angle); + var expected = new SCNMatrix4 ( + OhPointFive, -SqrtThreeHalved, 0, 0, + SqrtThreeHalved, OhPointFive, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); +#if !NET + expected.Transpose (); +#endif + Asserts.AreEqual (expected, matrix, (pfloat) 0.000001f, "CreateRotationZ"); + + Asserts.AreEqual (SCNMatrix4MakeRotation (angle, 0, 0, 1), matrix, 0.00001f, "Native"); + + var pos = new SCNVector3 (10, 20, 30); + var transformed = SCNVector3.TransformPosition (pos, matrix); + Asserts.AreEqual (new SCNVector3 (-12.320508f, 18.66025f, 30), transformed, 0.00001f, "Transformed"); } [Test] public void CreateTranslation_Out () { SCNMatrix4.CreateTranslation (1, 2, 3, out var matrix); - AssertEqual (matrix, "CreateTranslation", - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 1, 2, 3, 1); + var expected = new SCNMatrix4 ( + 1, 0, 0, 1, + 0, 1, 0, 2, + 0, 0, 1, 3, + 0, 0, 0, 1); +#if !NET + expected.Transpose (); +#endif + Asserts.AreEqual (expected, matrix, "CreateTranslation"); + + Asserts.AreEqual (SCNMatrix4MakeTranslation (new SCNVector3 (1, 2, 3)), matrix, "Native"); + + var pos = new SCNVector3 (10, 20, 30); + var transformed = SCNVector3.TransformPosition (pos, matrix); + Asserts.AreEqual (new SCNVector3 (11, 22, 33), transformed, "Transformed"); } [Test] @@ -433,22 +567,42 @@ public void CreateTranslation_Vector_Out () { var translation = new SCNVector3 (1, 2, 3); SCNMatrix4.CreateTranslation (ref translation, out var matrix); - AssertEqual (matrix, "CreateTranslation", - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 1, 2, 3, 1); + var expected = new SCNMatrix4 ( + 1, 0, 0, 1, + 0, 1, 0, 2, + 0, 0, 1, 3, + 0, 0, 0, 1); +#if !NET + expected.Transpose (); +#endif + Asserts.AreEqual (expected, matrix, "CreateTranslation"); + + Asserts.AreEqual (SCNMatrix4MakeTranslation (new SCNVector3 (1, 2, 3)), matrix, "Native"); + + var pos = new SCNVector3 (10, 20, 30); + var transformed = SCNVector3.TransformPosition (pos, matrix); + Asserts.AreEqual (new SCNVector3 (11, 22, 33), transformed, "Transformed"); } [Test] public void CreateTranslation () { var matrix = SCNMatrix4.CreateTranslation (1, 2, 3); - AssertEqual (matrix, "CreateTranslation", - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 1, 2, 3, 1); + var expected = new SCNMatrix4 ( + 1, 0, 0, 1, + 0, 1, 0, 2, + 0, 0, 1, 3, + 0, 0, 0, 1); +#if !NET + expected.Transpose (); +#endif + Asserts.AreEqual (expected, matrix, "CreateTranslation"); + + Asserts.AreEqual (SCNMatrix4MakeTranslation (new SCNVector3 (1, 2, 3)), matrix, "Native"); + + var pos = new SCNVector3 (10, 20, 30); + var transformed = SCNVector3.TransformPosition (pos, matrix); + Asserts.AreEqual (new SCNVector3 (11, 22, 33), transformed, "Transformed"); } [Test] @@ -456,132 +610,227 @@ public void CreateTranslation_Vector () { var translation = new SCNVector3 (1, 2, 3); var matrix = SCNMatrix4.CreateTranslation (translation); - AssertEqual (matrix, "CreateTranslation", - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 1, 2, 3, 1); + var expected = new SCNMatrix4 ( + 1, 0, 0, 1, + 0, 1, 0, 2, + 0, 0, 1, 3, + 0, 0, 0, 1); +#if !NET + expected.Transpose (); +#endif + Asserts.AreEqual (expected, matrix, "CreateTranslation"); + + Asserts.AreEqual (SCNMatrix4MakeTranslation (translation), matrix, "Native"); + + var pos = new SCNVector3 (10, 20, 30); + var transformed = SCNVector3.TransformPosition (pos, matrix); + Asserts.AreEqual (new SCNVector3 (11, 22, 33), transformed, "Transformed"); } [Test] public void CreateOrthographic_Out () { SCNMatrix4.CreateOrthographic (1, 2, 3, 4, out var matrix); - AssertEqual (matrix, "CreateOrthographic", + var expected = new SCNMatrix4 ( 2, 0, 0, 0, 0, 1, 0, 0, - 0, 0, -2, 0, - 0, 0, -7, 1); + 0, 0, -2, -7, + 0, 0, 0, 1); +#if !NET + expected.Transpose (); +#endif + Asserts.AreEqual (expected, matrix, 0, "CreateOrthographic"); + + var pos = new SCNVector3 (10, 20, 30); + var transformed = SCNVector3.TransformPosition (pos, matrix); + Asserts.AreEqual (new SCNVector3 (20, 20, -67), transformed, 0.00001f, "Transformed"); } [Test] public void CreateOrthographic () { var matrix = SCNMatrix4.CreateOrthographic (1, 2, 3, 4); - AssertEqual (matrix, "CreateOrthographic", + var expected = new SCNMatrix4 ( 2, 0, 0, 0, 0, 1, 0, 0, - 0, 0, -2, 0, - 0, 0, -7, 1); + 0, 0, -2, -7, + 0, 0, 0, 1); +#if !NET + expected.Transpose (); +#endif + Asserts.AreEqual (expected, matrix, 0, "CreateOrthographic"); + + var pos = new SCNVector3 (10, 20, 30); + var transformed = SCNVector3.TransformPosition (pos, matrix); + Asserts.AreEqual (new SCNVector3 (20, 20, -67), transformed, 0.00001f, "Transformed"); } [Test] public void CreateOrthographicOffCenter_Out () { SCNMatrix4.CreateOrthographicOffCenter (1, 2, 3, 4, 5, 6, out var matrix); - AssertEqual (matrix, "CreateOrthographicOffCenter", - 2, 0, 0, 0, - 0, 2, 0, 0, - 0, 0, -2, 0, - -3, -7, -11, 1); + var expected = new SCNMatrix4 ( + 2, 0, 0, -3, + 0, 2, 0, -7, + 0, 0, -2, -11, + 0, 0, 0, 1); +#if !NET + expected.Transpose (); +#endif + Asserts.AreEqual (expected, matrix, "CreateOrthographicOffCenter"); + + var pos = new SCNVector3 (10, 20, 30); + var transformed = SCNVector3.TransformPosition (pos, matrix); + Asserts.AreEqual (new SCNVector3 (17, 33, -71), transformed, 0.00001f, "Transformed"); } [Test] public void CreateOrthographicOffCenter () { var matrix = SCNMatrix4.CreateOrthographicOffCenter (1, 2, 3, 4, 5, 6); - AssertEqual (matrix, "CreateOrthographicOffCenter", - 2, 0, 0, 0, - 0, 2, 0, 0, - 0, 0, -2, 0, - -3, -7, -11, 1); + var expected = new SCNMatrix4 ( + 2, 0, 0, -3, + 0, 2, 0, -7, + 0, 0, -2, -11, + 0, 0, 0, 1); +#if !NET + expected.Transpose (); +#endif + Asserts.AreEqual (expected, matrix, "CreateOrthographicOffCenter"); + + var pos = new SCNVector3 (10, 20, 30); + var transformed = SCNVector3.TransformPosition (pos, matrix); + Asserts.AreEqual (new SCNVector3 (17, 33, -71), transformed, 0.00001f, "Transformed"); } [Test] public void CreatePerspectiveFieldOfView_Out () { SCNMatrix4.CreatePerspectiveFieldOfView ((pfloat) (Math.PI / 3), 2, 3, 4, out var matrix); - AssertEqual (matrix, "CreatePerspectiveFieldOfView", + var expected = new SCNMatrix4 ( SqrtThreeHalved, 0, 0, 0, 0, SqrtThree, 0, 0, - 0, 0, -7, -1, - 0, 0, -24, 0); + 0, 0, -7, -24, + 0, 0, -1, 0); +#if !NET + expected.Transpose (); +#endif + Asserts.AreEqual (expected, matrix, (pfloat) 0.000001f, "CreatePerspectiveFieldOfView"); + + var pos = new SCNVector3 (10, 20, 30); + var transformed = SCNVector3.TransformPosition (pos, matrix); + Asserts.AreEqual (new SCNVector3 (8.660254f, 34.641016f, -234), transformed, 0.00001f, "Transformed"); } [Test] public void CreatePerspectiveFieldOfView () { var matrix = SCNMatrix4.CreatePerspectiveFieldOfView ((pfloat) (Math.PI / 3), 2, 3, 4); - AssertEqual (matrix, "CreatePerspectiveFieldOfView", + var expected = new SCNMatrix4 ( SqrtThreeHalved, 0, 0, 0, 0, SqrtThree, 0, 0, - 0, 0, -7, -1, - 0, 0, -24, 0); + 0, 0, -7, -24, + 0, 0, -1, 0); +#if !NET + expected.Transpose (); +#endif + Asserts.AreEqual (expected, matrix, (pfloat) 0.000001f, "CreatePerspectiveFieldOfView"); + + var pos = new SCNVector3 (10, 20, 30); + var transformed = SCNVector3.TransformPosition (pos, matrix); + Asserts.AreEqual (new SCNVector3 (8.660254f, 34.641016f, -234), transformed, 0.00001f, "Transformed"); } [Test] public void CreatePerspectiveOffCenter_Out () { SCNMatrix4.CreatePerspectiveOffCenter (1, 2, 3, 4, 5, 6, out var matrix); - AssertEqual (matrix, "CreatePerspectiveOffCenter", - 10, 0, 0, 0, - 0, 10, 0, 0, - 3, 7, -11, -1, - 0, 0, -60, 0); + var expected = new SCNMatrix4 ( + 10, 0, 3, 0, + 0, 10, 7, 0, + 0, 0, -11, -60, + 0, 0, -1, 0); +#if !NET + expected.Transpose (); +#endif + Asserts.AreEqual (expected, matrix, "CreatePerspectiveOffCenter"); + + var pos = new SCNVector3 (10, 20, 30); + var transformed = SCNVector3.TransformPosition (pos, matrix); + Asserts.AreEqual (new SCNVector3 (190, 410, -390), transformed, "Transformed"); } [Test] public void CreatePerspectiveOffCenter () { var matrix = SCNMatrix4.CreatePerspectiveOffCenter (1, 2, 3, 4, 5, 6); - AssertEqual (matrix, "CreatePerspectiveOffCenter", - 10, 0, 0, 0, - 0, 10, 0, 0, - 3, 7, -11, -1, - 0, 0, -60, 0); + var expected = new SCNMatrix4 ( + 10, 0, 3, 0, + 0, 10, 7, 0, + 0, 0, -11, -60, + 0, 0, -1, 0); +#if !NET + expected.Transpose (); +#endif + Asserts.AreEqual (expected, matrix, "CreatePerspectiveOffCenter"); + + var pos = new SCNVector3 (10, 20, 30); + var transformed = SCNVector3.TransformPosition (pos, matrix); + Asserts.AreEqual (new SCNVector3 (190, 410, -390), transformed, "Transformed"); } [Test] public void Scale () { var matrix = SCNMatrix4.Scale (2); - AssertEqual (matrix, "CreateScale", + var expected = new SCNMatrix4 ( 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 1); + Asserts.AreEqual (expected, matrix, "CreateScale"); + + Asserts.AreEqual (SCNMatrix4MakeScale (new SCNVector3 (2, 2, 2)), matrix, "Native"); + + var pos = new SCNVector3 (10, 20, 30); + var transformed = SCNVector3.TransformPosition (pos, matrix); + Asserts.AreEqual (new SCNVector3 (20, 40, 60), transformed, "Transformed"); } [Test] public void Scale_Vector () { var matrix = SCNMatrix4.Scale (new SCNVector3 (1, 2, 3)); - AssertEqual (matrix, "CreateScale", + var expected = new SCNMatrix4 ( 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, 1); + Asserts.AreEqual (expected, matrix, "CreateScale"); + + Asserts.AreEqual (SCNMatrix4MakeScale (new SCNVector3 (1, 2, 3)), matrix, "Native"); + + var pos = new SCNVector3 (10, 20, 30); + var transformed = SCNVector3.TransformPosition (pos, matrix); + Asserts.AreEqual (new SCNVector3 (10, 40, 90), transformed, "Transformed"); } [Test] public void Scale_3 () { var matrix = SCNMatrix4.Scale (1, 2, 3); - AssertEqual (matrix, "CreateScale", + var expected = new SCNMatrix4 ( 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, 1); + Asserts.AreEqual (expected, matrix, "CreateScale"); + + Asserts.AreEqual (SCNMatrix4MakeScale (new SCNVector3 (1, 2, 3)), matrix, "Native"); + + var pos = new SCNVector3 (10, 20, 30); + var transformed = SCNVector3.TransformPosition (pos, matrix); + Asserts.AreEqual (new SCNVector3 (10, 40, 90), transformed, "Transformed"); } [Test] @@ -589,11 +838,19 @@ public void Rotate () { var quaternion = new Quaternion (1, 2, 3, 4); var matrix = SCNMatrix4.Rotate (quaternion); - AssertEqual (matrix, "Rotate", - TwoFifteenths, 7 * TwoFifteenths, -OneThird, 0, - -TwoThirds, OneThird, TwoThirds, 0, - 11 * OneFifteenth, TwoFifteenths, TwoThirds, 0, + var expected = new SCNMatrix4 ( + TwoFifteenths, -TwoThirds, 11 * OneFifteenth, 0, + 7 * TwoFifteenths, OneThird, TwoFifteenths, 0, + -OneThird, TwoThirds, TwoThirds, 0, 0, 0, 0, 1); +#if !NET + expected.Transpose (); +#endif + Asserts.AreEqual (expected, matrix, (pfloat) 0.00001, "Rotate"); + + var pos = new SCNVector3 (10, 20, 30); + var transformed = SCNVector3.TransformPosition (pos, matrix); + Asserts.AreEqual (pos, transformed, 0.0001f, "Transformed"); } [Test] @@ -601,33 +858,57 @@ public void Rotate_d () { var quaternion = new Quaterniond (1, 2, 3, 4); var matrix = SCNMatrix4.Rotate (quaternion); - AssertEqual (matrix, "Rotate", - TwoFifteenths, 7 * TwoFifteenths, -OneThird, 0, - -TwoThirds, OneThird, TwoThirds, 0, - 11 * OneFifteenth, TwoFifteenths, TwoThirds, 0, + var expected = new SCNMatrix4 ( + TwoFifteenths, -TwoThirds, 11 * OneFifteenth, 0, + 7 * TwoFifteenths, OneThird, TwoFifteenths, 0, + -OneThird, TwoThirds, TwoThirds, 0, 0, 0, 0, 1); +#if !NET + expected.Transpose (); +#endif + Asserts.AreEqual (expected, matrix, (pfloat) 0.00001, "Rotate"); + + var pos = new SCNVector3 (10, 20, 30); + var transformed = SCNVector3.TransformPosition (pos, matrix); + Asserts.AreEqual (pos, transformed, 0.0001f, "Transformed"); } [Test] public void LookAt_Vectors () { var matrix = SCNMatrix4.LookAt (new SCNVector3 (1, 2, 3), new SCNVector3 (4, 5, 6), new SCNVector3 (7, 8, 9)); - AssertEqual (matrix, "LookAt", - SqrtSixInverted, -SqrtTwoHalved, -SqrtThreeInverted, 0, - -2 * SqrtSixInverted, 0, -SqrtThreeInverted, 0, - SqrtSixInverted, SqrtTwoHalved, -SqrtThreeInverted, 0, - 0, -SqrtTwo, SqrtTwelve, 1); + var expected = new SCNMatrix4 ( + SqrtSixInverted, -2 * SqrtSixInverted, SqrtSixInverted, 0, + -SqrtTwoHalved, 0, SqrtTwoHalved, -SqrtTwo, + -SqrtThreeInverted, -SqrtThreeInverted, -SqrtThreeInverted, SqrtTwelve, + 0, 0, 0, 1); +#if !NET + expected.Transpose (); +#endif + Asserts.AreEqual (expected, matrix, (pfloat) 0.00001, "LookAt"); + + var pos = new SCNVector3 (10, 20, 30); + var transformed = SCNVector3.TransformPosition (pos, matrix); + Asserts.AreEqual (new SCNVector3 (0, 12.7279220f, -31.1769145f), transformed, 0.00001f, "Transformed"); } [Test] public void LookAt_Elements () { var matrix = SCNMatrix4.LookAt (1, 2, 3, 4, 5, 6, 7, 8, 9); - AssertEqual (matrix, "LookAt", - SqrtSixInverted, -SqrtTwoHalved, -SqrtThreeInverted, 0, - -2 * SqrtSixInverted, 0, -SqrtThreeInverted, 0, - SqrtSixInverted, SqrtTwoHalved, -SqrtThreeInverted, 0, - 0, -SqrtTwo, SqrtTwelve, 1); + var expected = new SCNMatrix4 ( + SqrtSixInverted, -2 * SqrtSixInverted, SqrtSixInverted, 0, + -SqrtTwoHalved, 0, SqrtTwoHalved, -SqrtTwo, + -SqrtThreeInverted, -SqrtThreeInverted, -SqrtThreeInverted, SqrtTwelve, + 0, 0, 0, 1); +#if !NET + expected.Transpose (); +#endif + Asserts.AreEqual (expected, matrix, (pfloat) 0.00001, "LookAt"); + + var pos = new SCNVector3 (10, 20, 30); + var transformed = SCNVector3.TransformPosition (pos, matrix); + Asserts.AreEqual (new SCNVector3 (0, 12.7279220f, -31.1769145f), transformed, 0.00001f, "Transformed"); } [Test] @@ -644,11 +925,29 @@ public void Mult () new SCNVector4 (931, 932, 933, 934), new SCNVector4 (941, 942, 943, 944)); var matrix = SCNMatrix4.Mult (a, b); - AssertEqual (matrix, "Mult", + + Asserts.AreEqual (SCNMatrix4Mult (a, b), matrix, "Native"); + var expected = new SCNMatrix4 ( +#if NET + 94950, 98600, 102250, 105900, + 95990, 99680, 103370, 107060, + 97030, 100760, 104490, 108220, + 98070, 101840, 105610, 109380); +#else 46350, 46400, 46450, 46500, 83390, 83480, 83570, 83660, 120430, 120560, 120690, 120820, 157470, 157640, 157810, 157980); +#endif + Asserts.AreEqual (expected, matrix, "Mult"); + + var pos = new SCNVector3 (10, 20, 30); + var transformed = SCNVector3.TransformPosition (pos, matrix); +#if NET + Asserts.AreEqual (new SCNVector3 (6094900, 6161660, 6228420), transformed, "Transformed"); +#else + Asserts.AreEqual (new SCNVector3 (5901670, 5908040, 5914410), transformed, "Transformed"); +#endif } [Test] @@ -665,11 +964,29 @@ public void Mult_ByRef () new SCNVector4 (931, 932, 933, 934), new SCNVector4 (941, 942, 943, 944)); SCNMatrix4.Mult (ref a, ref b, out var matrix); - AssertEqual (matrix, "Mult", + + Asserts.AreEqual (SCNMatrix4Mult (a, b), matrix, "Native"); + var expected = new SCNMatrix4 ( +#if NET + 94950, 98600, 102250, 105900, + 95990, 99680, 103370, 107060, + 97030, 100760, 104490, 108220, + 98070, 101840, 105610, 109380); +#else 46350, 46400, 46450, 46500, 83390, 83480, 83570, 83660, 120430, 120560, 120690, 120820, 157470, 157640, 157810, 157980); +#endif + Asserts.AreEqual (expected, matrix, "Mult"); + + var pos = new SCNVector3 (10, 20, 30); + var transformed = SCNVector3.TransformPosition (pos, matrix); +#if NET + Asserts.AreEqual (new SCNVector3 (6094900, 6161660, 6228420), transformed, "Transformed"); +#else + Asserts.AreEqual (new SCNVector3 (5901670, 5908040, 5914410), transformed, "Transformed"); +#endif } #if NET // The legacy Invert implementation seems very wrong, so only verify .NET behavior @@ -692,11 +1009,16 @@ public void Static_Invert () var matrix = SCNMatrix4.Invert (a); - AssertEqual (matrix, "Invert", + var expected = new SCNMatrix4 ( (pfloat) (-0.6181818181818182), (pfloat) (0.3151515151515151), (pfloat) (-0.030303030303030304), (pfloat) (0.3878787878787879), (pfloat) (1.6363636363636365), (pfloat) (-0.696969696969697), (pfloat) (0.3939393939393939), (pfloat) (-1.2424242424242424), (pfloat) (-1.3818181818181818), (pfloat) (0.3515151515151515), (pfloat) (-0.30303030303030304), (pfloat) (1.2787878787878788), (pfloat) (0.6363636363636364), (pfloat) (-0.030303030303030304), (pfloat) (0.06060606060606061), (pfloat) (-0.5757575757575758)); + Asserts.AreEqual (expected, matrix, (pfloat) 0.00001f, "Invert"); + + var pos = new SCNVector3 (10, 20, 30); + var transformed = SCNVector3.TransformPosition (pos, matrix); + Asserts.AreEqual (new SCNVector3 (-0.4f, 13, -14.6f), transformed, 0.00001f, "Transformed"); } #endif @@ -709,11 +1031,20 @@ public void Static_Transpose () new SCNVector4 (31, 32, 33, 34), new SCNVector4 (41, 42, 43, 44)); var matrix = SCNMatrix4.Transpose (a); - AssertEqual (matrix, "Transpose", + var expected = new SCNMatrix4 ( 11, 21, 31, 41, 12, 22, 32, 42, 13, 23, 33, 43, 14, 24, 34, 44); + Asserts.AreEqual (expected, matrix, "Transpose"); + + var pos = new SCNVector3 (10, 20, 30); + var transformed = SCNVector3.TransformPosition (pos, matrix); +#if NET + Asserts.AreEqual (new SCNVector3 (1501, 1562, 1623), transformed, "Transformed"); +#else + Asserts.AreEqual (new SCNVector3 (754, 1364, 1974), transformed, "Transformed"); +#endif } [Test] @@ -725,11 +1056,20 @@ public void Static_Transpose_ByRef () new SCNVector4 (31, 32, 33, 34), new SCNVector4 (41, 42, 43, 44)); SCNMatrix4.Transpose (ref a, out var matrix); - AssertEqual (matrix, "Transpose", + var expected = new SCNMatrix4 ( 11, 21, 31, 41, 12, 22, 32, 42, 13, 23, 33, 43, 14, 24, 34, 44); + Asserts.AreEqual (expected, matrix, "Transpose"); + + var pos = new SCNVector3 (10, 20, 30); + var transformed = SCNVector3.TransformPosition (pos, matrix); +#if NET + Asserts.AreEqual (new SCNVector3 (1501, 1562, 1623), transformed, "Transformed"); +#else + Asserts.AreEqual (new SCNVector3 (754, 1364, 1974), transformed, "Transformed"); +#endif } [Test] @@ -746,11 +1086,28 @@ public void Operator_Multiply () new SCNVector4 (931, 932, 933, 934), new SCNVector4 (941, 942, 943, 944)); var matrix = a * b; - AssertEqual (matrix, "*", + Asserts.AreEqual (SCNMatrix4Mult (a, b), matrix, "Native"); + var expected = new SCNMatrix4 ( +#if NET + 94950, 98600, 102250, 105900, + 95990, 99680, 103370, 107060, + 97030, 100760, 104490, 108220, + 98070, 101840, 105610, 109380); +#else 46350, 46400, 46450, 46500, 83390, 83480, 83570, 83660, 120430, 120560, 120690, 120820, 157470, 157640, 157810, 157980); +#endif + Asserts.AreEqual (expected, matrix, "*"); + + var pos = new SCNVector3 (10, 20, 30); + var transformed = SCNVector3.TransformPosition (pos, matrix); +#if NET + Asserts.AreEqual (new SCNVector3 (6094900, 6161660, 6228420), transformed, "Transformed"); +#else + Asserts.AreEqual (new SCNVector3 (5901670, 5908040, 5914410), transformed, "Transformed"); +#endif } [Test] @@ -827,6 +1184,151 @@ public void IEquatable_Equals () new SCNVector4 (941, 942, 943, 944)); Assert.IsFalse (((IEquatable) a).Equals (b), "object.Equals"); } + + [Test] + public void CreateRotationX_NodeComparison () + { + // Create a test node (it defaults to position 0,0,0) + var node = SCNNode.Create (); + // Create a translation matrix + var angle = (pfloat) (Math.PI / 2); + // Use that matrix to transform the node + node.Transform = SCNMatrix4.CreateRotationX (angle); + Asserts.AreEqual (new SCNVector3 (angle, 0, 0), node.EulerAngles, 0.000001f, "EulerAngles"); + Asserts.AreEqual (new SCNQuaternion (SqrtTwoHalved, 0, 0, SqrtTwoHalved), node.Orientation, 0.000001f, "Orientation"); + Asserts.AreEqual (new SCNVector3 (0, 0, 0), node.Position, "Position"); + Asserts.AreEqual (new SCNVector4 (1, 0, 0, angle), node.Rotation, 0.000001f, "Rotation"); + Asserts.AreEqual (new SCNVector3 (1, 1, 1), node.Scale, "Scale"); + } + + [Test] + public void CreateTranslationAndTransformPosition () + { + // Create test point + var point = new SCNVector3 (1, 2, 3); + // Create translation + var matrix = SCNMatrix4.CreateTranslation (10, 0, 0); + // Transform the point + var newPoint = SCNVector3.TransformPosition (point, matrix); + Asserts.AreEqual (new SCNVector3 (11, 2, 3), newPoint, "A"); + } + + [Test] + public void TranslationPosition_ret () + { + // Create test point + var point = new SCNVector3 (1, 2, 3); + // Create translation + var matrix = + SCNMatrix4.CreateTranslation (-1, 0, 0) * + SCNMatrix4.Scale (10, 1, 1); + // Transform the point + var newPoint = SCNVector3.TransformPosition (point, matrix); + Asserts.AreEqual (new SCNVector3 (0, 2, 3), newPoint, "A"); + } + + [Test] + public void TranslationPosition_out () + { + // Create test point + var point = new SCNVector3 (1, 2, 3); + // Create translation + var matrix = + SCNMatrix4.CreateTranslation (-1, 0, 0) * + SCNMatrix4.Scale (10, 1, 1); + // Transform the point + SCNVector3.TransformPosition (ref point, ref matrix, out var newPoint); + Asserts.AreEqual (new SCNVector3 (0, 2, 3), newPoint, "A"); + } + + [Test] + public void CreateTranslations_ret_floats () + { + // Create a test node (it defaults to position 0,0,0) + var node = SCNNode.Create (); + // Create a translation matrix + var matrix = SCNMatrix4.CreateTranslation (1, 2, 3); + // Use that matrix to transform the node + node.Transform = matrix; + // Ask the node to extract just the translation part of the matrix + var newPoint = node.Position; + // Verify that it is now positioned at (1,2,3) + Asserts.AreEqual (new SCNVector3 (1, 2, 3), newPoint, "A"); + } + + [Test] + public void CreateTranslations_ret_SCNVector3 () + { + // Create a test node (it defaults to position 0,0,0) + var node = SCNNode.Create (); + // Create a translation matrix + var matrix = SCNMatrix4.CreateTranslation (new SCNVector3 (1, 2, 3)); + // Use that matrix to transform the node + node.Transform = matrix; + // Ask the node to extract just the translation part of the matrix + var newPoint = node.Position; + // Verify that it is now positioned at (1,2,3) + Asserts.AreEqual (new SCNVector3 (1, 2, 3), newPoint, "A"); + } + + [Test] + public void CreateTranslations_out_floats () + { + // Create a test node (it defaults to position 0,0,0) + var node = SCNNode.Create (); + // Create a translation matrix + SCNMatrix4.CreateTranslation (1, 2, 3, out var matrix); + // Use that matrix to transform the node + node.Transform = matrix; + // Ask the node to extract just the translation part of the matrix + var newPoint = node.Position; + // Verify that it is now positioned at (1,2,3) + Asserts.AreEqual (new SCNVector3 (1, 2, 3), newPoint, "A"); + } + + [Test] + public void CreateTranslations_out_SCNVector3 () + { + // Create a test node (it defaults to position 0,0,0) + var node = SCNNode.Create (); + // Create a translation matrix + var vector = new SCNVector3 (1, 2, 3); + SCNMatrix4.CreateTranslation (ref vector, out var matrix); + // Use that matrix to transform the node + node.Transform = matrix; + // Ask the node to extract just the translation part of the matrix + var newPoint = node.Position; + // Verify that it is now positioned at (1,2,3) + Asserts.AreEqual (new SCNVector3 (1, 2, 3), newPoint, "A"); + } + + [Test] + public void SCNMatrix4Translate () + { + var translationVector = new SCNVector3 (1, 2, 3); + var managedTranslation = SCNMatrix4.CreateTranslation (translationVector); + var nativeTranslation = SCNMatrix4MakeTranslation (translationVector); + Asserts.AreEqual (nativeTranslation, managedTranslation, "A"); + } + + static SCNMatrix4 SCNMatrix4MakeTranslation (SCNVector3 v) + { + return global::Bindings.Test.CFunctions.x_SCNMatrix4MakeTranslation (v.X, v.Y, v.Z); + } + + static SCNMatrix4 SCNMatrix4MakeScale (SCNVector3 v) + { + return global::Bindings.Test.CFunctions.x_SCNMatrix4MakeScale (v.X, v.Y, v.Z); + } + + [DllImport (global::ObjCRuntime.Constants.SceneKitLibrary)] + static extern SCNMatrix4 SCNMatrix4MakeRotation (pfloat angle, pfloat x, pfloat y, pfloat z); + + [DllImport (global::ObjCRuntime.Constants.SceneKitLibrary)] + static extern SCNMatrix4 SCNMatrix4Mult (SCNMatrix4 a, SCNMatrix4 b); + + [DllImport (global::ObjCRuntime.Constants.SceneKitLibrary)] + static extern SCNMatrix4 SCNMatrix4Invert (SCNMatrix4 a); } } #endif // !__WATCHOS__ diff --git a/tests/monotouch-test/SceneKit/SCNVector3Test.cs b/tests/monotouch-test/SceneKit/SCNVector3Test.cs new file mode 100644 index 000000000000..381055025ff3 --- /dev/null +++ b/tests/monotouch-test/SceneKit/SCNVector3Test.cs @@ -0,0 +1,247 @@ +// +// Unit tests for SCNMatrix4 +// +// Authors: +// Sebastien Pouliot +// +// Copyright 2014 Xamarin Inc. All rights reserved. +// + +#if HAS_SCENEKIT + +#nullable enable + +using System; +using Foundation; +using SceneKit; + +using NUnit.Framework; + +#if __MACOS__ +#if NET +using pfloat = System.Runtime.InteropServices.NFloat; +#else +using pfloat = System.nfloat; +#endif +#else +using pfloat = System.Single; +#endif + +namespace MonoTouchFixtures.SceneKit { + + [TestFixture] + [Preserve (AllMembers = true)] + public class SCNVector3Test + { + static pfloat delta = (pfloat) 0.000001; + + [Test] + public void TransformVector() + { + var matrix = new SCNMatrix4 ( + 11, 12, 13, 14, + 21, 22, 23, 24, + 31, 32, 33, 34, + 41, 42, 43, 44); +#if !NET + matrix.Transpose (); +#endif + + var pos = new SCNVector3 (10, 20, 30); + var transformed = SCNVector3.TransformVector (pos, matrix); + Asserts.AreEqual (new SCNVector3 (740, 1340, 1940), transformed, "Transformed"); + } + + [Test] + public void TransformVector_out () + { + var matrix = new SCNMatrix4 ( + 11, 12, 13, 14, + 21, 22, 23, 24, + 31, 32, 33, 34, + 41, 42, 43, 44); +#if !NET + matrix.Transpose (); +#endif + + var pos = new SCNVector3 (10, 20, 30); + SCNVector3.TransformVector (ref pos, ref matrix, out var transformed); + Asserts.AreEqual (new SCNVector3 (740, 1340, 1940), transformed, "Transformed"); + } + + [Test] + public void TransformNormal () + { + var matrix = new SCNMatrix4 ( + 11, 12, 13, 14, + 21, -22, 23, 24, + 31, 32, 33, 34, + 41, 42, 43, -44); +#if !NET + matrix.Transpose (); +#endif + + var pos = new SCNVector3 (10, 20, 30); + pos.Normalize (); + var transformed = SCNVector3.TransformNormal (pos, matrix); + Asserts.AreEqual (new SCNVector3 ((pfloat) 0.406966, 0, (pfloat) (-0.151853)), transformed, delta, "Transformed"); + } + + [Test] + public void TransformNormal_out () + { + var matrix = new SCNMatrix4 ( + 11, 12, 13, 14, + 21, -22, 23, 24, + 31, 32, 33, 34, + 41, 42, 43, -44); +#if !NET + matrix.Transpose (); +#endif + + var pos = new SCNVector3 (10, 20, 30); + pos.Normalize (); + SCNVector3.TransformNormal (ref pos, ref matrix, out var transformed); + Asserts.AreEqual (new SCNVector3 ((pfloat) 0.406966, 0, (pfloat) (-0.151853)), transformed, delta, "Transformed"); + } + + [Test] + public void TransformNormalInverse () + { + var matrix = new SCNMatrix4 ( + 11, 12, 13, 14, + 21, 22, 23, 24, + 31, 32, 33, 34, + 41, 42, 43, 44); +#if !NET + matrix.Transpose (); +#endif + + var pos = new SCNVector3 (10, 20, 30); + pos.Normalize (); + var transformed = SCNVector3.TransformNormalInverse (pos, matrix); + Asserts.AreEqual (new SCNVector3 ((pfloat) 39.0201413, (pfloat) 40.62370877, (pfloat) 42.2272762), transformed, delta, "Transformed"); + } + + [Test] + public void TransformNormalInverse_out () + { + var matrix = new SCNMatrix4 ( + 11, 12, 13, 14, + 21, 22, 23, 24, + 31, 32, 33, 34, + 41, 42, 43, 44); +#if !NET + matrix.Transpose (); +#endif + + var pos = new SCNVector3 (10, 20, 30); + pos.Normalize (); + SCNVector3.TransformNormalInverse (ref pos, ref matrix, out var transformed); + Asserts.AreEqual (new SCNVector3 ((pfloat) 39.0201413, (pfloat) 40.62370877, (pfloat) 42.2272762), transformed, delta, "Transformed"); + } + + [Test] + public void TransformPosition () + { + var matrix = new SCNMatrix4 ( + 11, 12, 13, 14, + 21, 22, 23, 24, + 31, 32, 33, 34, + 41, 42, 43, 44); +#if !NET + matrix.Transpose (); +#endif + + var pos = new SCNVector3 (10, 20, 30); + var transformed = SCNVector3.TransformPosition (pos, matrix); + Asserts.AreEqual (new SCNVector3 (754, 1364, 1974), transformed, "Transformed"); + } + + [Test] + public void TransformPosition_out () + { + var matrix = new SCNMatrix4 ( + 11, 12, 13, 14, + 21, 22, 23, 24, + 31, 32, 33, 34, + 41, 42, 43, 44); +#if !NET + matrix.Transpose (); +#endif + + var pos = new SCNVector3 (10, 20, 30); + SCNVector3.TransformPosition (ref pos, ref matrix, out var transformed); + Asserts.AreEqual (new SCNVector3 (754, 1364, 1974), transformed, "Transformed"); + } + + [Test] + public void Transform () + { + var matrix = new SCNMatrix4 ( + 11, 12, 13, 14, + 21, 22, 23, 24, + 31, 32, 33, 34, + 41, 42, 43, 44); +#if !NET + matrix.Transpose (); +#endif + + var pos = new SCNVector3 (10, 20, 30); + var transformed = SCNVector3.Transform (pos, matrix); + Asserts.AreEqual (new SCNVector4 (754, 1364, 1974, 2584), transformed, "Transformed"); + } + + [Test] + public void Transform_out () + { + var matrix = new SCNMatrix4 ( + 11, 12, 13, 14, + 21, 22, 23, 24, + 31, 32, 33, 34, + 41, 42, 43, 44); +#if !NET + matrix.Transpose (); +#endif + + var pos = new SCNVector3 (10, 20, 30); + SCNVector3.Transform (ref pos, ref matrix, out var transformed); + Asserts.AreEqual (new SCNVector4 (754, 1364, 1974, 2584), transformed, "Transformed"); + } + + [Test] + public void TransformPerspective () + { + var matrix = new SCNMatrix4 ( + 11, 12, 13, 14, + 21, 22, 23, 24, + 31, 32, 33, 34, + 41, 42, 43, 44); +#if !NET + matrix.Transpose (); +#endif + + var pos = new SCNVector3 (10, 20, 30); + var transformed = SCNVector3.TransformPerspective (pos, matrix); + Asserts.AreEqual (new SCNVector3 ((pfloat) 0.291795, (pfloat) 0.5278637, (pfloat) 0.76393188), transformed, delta, "Transformed"); + } + + [Test] + public void TransformPerspective_out () + { + var matrix = new SCNMatrix4 ( + 11, 12, 13, 14, + 21, 22, 23, 24, + 31, 32, 33, 34, + 41, 42, 43, 44); +#if !NET + matrix.Transpose (); +#endif + + var pos = new SCNVector3 (10, 20, 30); + SCNVector3.TransformPerspective (ref pos, ref matrix, out var transformed); + Asserts.AreEqual (new SCNVector3 ((pfloat) 0.291795, (pfloat) 0.5278637, (pfloat) 0.76393188), transformed, delta, "Transformed"); + } + } +} +#endif // HAS_SCENEKIT diff --git a/tests/monotouch-test/SceneKit/SCNVector4Test.cs b/tests/monotouch-test/SceneKit/SCNVector4Test.cs new file mode 100644 index 000000000000..8029638d5dda --- /dev/null +++ b/tests/monotouch-test/SceneKit/SCNVector4Test.cs @@ -0,0 +1,73 @@ +// +// Unit tests for SCNMatrix4 +// +// Authors: +// Sebastien Pouliot +// +// Copyright 2014 Xamarin Inc. All rights reserved. +// + +#if HAS_SCENEKIT + +#nullable enable + +using System; +using Foundation; +using SceneKit; + +using NUnit.Framework; + +#if __MACOS__ +#if NET +using pfloat = System.Runtime.InteropServices.NFloat; +#else +using pfloat = System.nfloat; +#endif +#else +using pfloat = System.Single; +#endif + +namespace MonoTouchFixtures.SceneKit { + + [TestFixture] + [Preserve (AllMembers = true)] + public class SCNVector4Test + { + [Test] + public void Transform () + { + var matrix = new SCNMatrix4 ( + 11, 12, 13, 14, + 21, 22, 23, 24, + 31, 32, 33, 34, + 41, 42, 43, 44); +#if !NET + matrix.Transpose (); +#endif + + var pos = new SCNVector4 (10, 20, 30, 40); + var transformed = SCNVector4.Transform (pos, matrix); + Asserts.AreEqual (new SCNVector4 (1300, 2300, 3300, 4300), transformed, "Transformed"); + } + + [Test] + public void Transform_out () + { + var matrix = new SCNMatrix4 ( + 11, 12, 13, 14, + 21, 22, 23, 24, + 31, 32, 33, 34, + 41, 42, 43, 44); +#if !NET + matrix.Transpose (); +#endif + + var pos = new SCNVector4 (10, 20, 30, 40); + SCNVector4.Transform (ref pos, ref matrix, out var transformed); + Asserts.AreEqual (new SCNVector4 (1300, 2300, 3300, 4300), transformed, "Transformed"); + } + + } +} + +#endif // HAS_SCENEKIT diff --git a/tests/monotouch-test/monotouch-test.csproj b/tests/monotouch-test/monotouch-test.csproj index 8160ca4c9731..19e77aa2b97f 100644 --- a/tests/monotouch-test/monotouch-test.csproj +++ b/tests/monotouch-test/monotouch-test.csproj @@ -223,6 +223,8 @@ ApplePlatform.cs + + diff --git a/tests/test-libraries/libtest.h b/tests/test-libraries/libtest.h index 311327e0e4df..c0e7211e73e5 100644 --- a/tests/test-libraries/libtest.h +++ b/tests/test-libraries/libtest.h @@ -8,6 +8,8 @@ #import #endif +#import + #ifdef __cplusplus extern "C" { #endif @@ -29,6 +31,16 @@ void x_mdltransform_create_global_transform (MDLObject *object, NSTimeInterval t 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 +#if TARGET_OS_OSX +#define pfloat CGFloat +#else +#define pfloat float +#endif + +SCNMatrix4 x_SCNMatrix4MakeTranslation (pfloat tx, pfloat ty, pfloat tz); +SCNMatrix4 x_SCNMatrix4MakeScale (pfloat tx, pfloat ty, pfloat tz); +SCNMatrix4 x_SCNMatrix4Translate (SCNMatrix4 m, pfloat tx, pfloat ty, pfloat tz); + /* * Various structs used in ObjCRegistrarTest */ diff --git a/tests/test-libraries/libtest.m b/tests/test-libraries/libtest.m index 8b980bc0316b..689a950e0995 100644 --- a/tests/test-libraries/libtest.m +++ b/tests/test-libraries/libtest.m @@ -250,6 +250,24 @@ void x_call_block (x_block_callback block) } #endif // !TARGET_OS_WATCH +SCNMatrix4 +x_SCNMatrix4MakeTranslation (pfloat tx, pfloat ty, pfloat tz) +{ + return SCNMatrix4MakeTranslation (tx, ty, tz); +} + +SCNMatrix4 +x_SCNMatrix4MakeScale (pfloat tx, pfloat ty, pfloat tz) +{ + return SCNMatrix4MakeScale (tx, ty, tz); +} + +SCNMatrix4 +x_SCNMatrix4Translate (SCNMatrix4 m, pfloat tx, pfloat ty, pfloat tz) +{ + return SCNMatrix4Translate (m, tx, ty, tz); +} + @interface UltimateMachine : NSObject { } diff --git a/tests/test-libraries/rename.h b/tests/test-libraries/rename.h index 86146b801cf2..9f07f7da0eea 100644 --- a/tests/test-libraries/rename.h +++ b/tests/test-libraries/rename.h @@ -68,6 +68,9 @@ #define x_get_matrix_float3x3 object_x_get_matrix_float3x3 #define x_get_matrix_float2x2 object_x_get_matrix_float2x2 #define x_call_block object_x_call_block + #define x_SCNMatrix4MakeTranslation object_x_SCNMatrix4MakeTranslation + #define x_SCNMatrix4MakeScale object_x_SCNMatrix4MakeScale + #define x_SCNMatrix4Translate object_x_SCNMatrix4Translate #elif PREFIX == 2 #define theUltimateAnswer ar_theUltimateAnswer #define useZLib ar_useZLib @@ -137,6 +140,9 @@ #define x_get_matrix_float3x3 ar_x_get_matrix_float3x3 #define x_get_matrix_float2x2 ar_x_get_matrix_float2x2 #define x_call_block ar_x_call_block + #define x_SCNMatrix4MakeTranslation ar_x_SCNMatrix4MakeTranslation + #define x_SCNMatrix4MakeScale ar_x_SCNMatrix4MakeScale + #define x_SCNMatrix4Translate ar_x_SCNMatrix4Translate #else // keep original names #endif diff --git a/tests/xammac_tests/xammac_tests.csproj b/tests/xammac_tests/xammac_tests.csproj index 852d06b86265..e24917711cc2 100644 --- a/tests/xammac_tests/xammac_tests.csproj +++ b/tests/xammac_tests/xammac_tests.csproj @@ -14,6 +14,7 @@ latest PackageReference .. + $(RootTestsDirectory)\..\src\build\macos-defines.rsp true diff --git a/tools/devops/automation/templates/tests/run-tests.yml b/tools/devops/automation/templates/tests/run-tests.yml index 613d444afc68..ba3d6b781bed 100644 --- a/tools/devops/automation/templates/tests/run-tests.yml +++ b/tools/devops/automation/templates/tests/run-tests.yml @@ -160,6 +160,7 @@ steps: make -C src build/ios.rsp make -C src build/ios-defines.rsp make -C src build/tvos-defines.rsp + make -C src build/macos-defines.rsp make -C src build/dotnet/macos-defines-dotnet.rsp make -C src build/dotnet/ios-defines-dotnet.rsp make -C src build/dotnet/maccatalyst-defines-dotnet.rsp