< Summary

Line coverage
99%
Covered lines: 629
Uncovered lines: 5
Coverable lines: 634
Total lines: 1713
Line coverage: 99.2%
Branch coverage
96%
Covered branches: 171
Total branches: 178
Branch coverage: 96%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
File 1: .cctor()100%11100%
File 1: .ctor(...)100%11100%
File 1: FromRows(...)100%11100%
File 1: FromColumns(...)100%11100%
File 1: get_IsAffine()100%66100%
File 1: get_Translation()100%11100%
File 1: get_Right()100%11100%
File 1: get_Left()100%11100%
File 1: get_Up()100%11100%
File 1: get_Down()100%11100%
File 1: get_Forward()100%11100%
File 1: get_Backward()100%11100%
File 1: get_Scale()100%11100%
File 1: get_Rotation()100%11100%
File 1: get_Item(...)100%1717100%
File 1: set_Item(...)100%1717100%
File 1: GetDeterminant()100%22100%
File 1: ResetScaleToIdentity()100%210%
File 1: SetTransform(...)100%11100%
File 2: ExtractTranslation(...)100%11100%
File 2: ExtractRight(...)100%11100%
File 2: ExtractUp(...)100%11100%
File 2: ExtractForward(...)100%11100%
File 2: ExtractScale(...)100%11100%
File 2: ExtractLossyScale(...)100%11100%
File 2: ExtractRotation(...)100%66100%
File 2: Decompose(...)100%88100%
File 2: SetTranslation(...)100%11100%
File 2: SetScale(...)100%11100%
File 2: ApplyScaleToRotation(...)100%11100%
File 2: ResetScaleToIdentity(...)100%210%
File 2: SetGlobalScale(...)100%11100%
File 2: SetRotation(...)100%11100%
File 2: NormalizeRotationMatrix(...)100%11100%
File 3: Equals(...)100%22100%
File 3: Equals(...)100%3030100%
File 3: GetHashCode()100%11100%
File 3: ToString()100%11100%
File 3: ToString(...)100%11100%
File 3: TryFormat(...)61.11%1818100%
File 3: AppendRow(...)100%1212100%
File 4: CreateTranslation(...)100%11100%
File 4: CreateTranslation(...)100%11100%
File 4: CreateRotation(...)100%11100%
File 4: CreateRotationX(...)100%11100%
File 4: CreateRotationY(...)100%11100%
File 4: CreateRotationZ(...)100%11100%
File 4: CreateFromAxisAngle(...)100%11100%
File 4: CreateFromEulerAngles(...)100%11100%
File 4: CreateScale(...)100%11100%
File 4: CreateScale(...)100%11100%
File 4: CreateScale(...)100%11100%
File 4: CreateLookAt(...)100%44100%
File 4: CreateOrthographic(...)100%44100%
File 4: CreateOrthographicOffCenter(...)100%44100%
File 4: CreatePerspective(...)100%44100%
File 4: CreatePerspectiveFieldOfView(...)100%66100%
File 4: CreatePerspectiveOffCenter(...)100%44100%
File 4: CreateWorld(...)100%44100%
File 4: CreateTransform(...)100%11100%
File 4: ScaleRotateTranslate(...)100%11100%
File 4: TranslateRotateScale(...)100%11100%
File 5: FromRotationMatrix(...)100%11100%
File 5: ValidateDepthRange(...)100%44100%
File 5: ValidatePerspectiveDepthRange(...)100%44100%
File 6: op_UnaryNegation(...)100%11100%
File 6: op_Addition(...)100%11100%
File 6: op_Subtraction(...)100%11100%
File 6: op_Multiply(...)100%44100%
File 6: op_Multiply(...)100%11100%
File 6: op_Multiply(...)100%11100%
File 6: op_Division(...)100%11100%
File 6: op_Equality(...)100%11100%
File 6: op_Inequality(...)100%11100%
File 7: Lerp(...)100%11100%
File 7: Transpose(...)100%11100%
File 7: ComponentDivide(...)100%11100%
File 7: InverseDivide(...)100%22100%
File 7: Invert(...)100%44100%
File 7: FullInvert(...)100%22100%
File 7: Transform(...)100%11100%
File 7: TransformPoint(...)100%22100%
File 7: FullTransformPoint(...)100%22100%
File 7: InverseTransformPoint(...)100%44100%
File 7: FullInverseTransformPoint(...)100%22100%

File(s)

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Numerics/Matrices/Fixed4x4.cs

#LineLine coverage
 1//=======================================================================
 2// Fixed4x4.cs
 3//=======================================================================
 4// MIT License, Copyright (c) 2024–present David Oravsky (mrdav30)
 5// See LICENSE file in the project root for full license information.
 6//=======================================================================
 7
 8using MemoryPack;
 9using System;
 10using System.Runtime.CompilerServices;
 11using System.Text.Json.Serialization;
 12
 13namespace FixedMathSharp;
 14
 15/// <summary>
 16/// Represents a 4x4 matrix used for transformations in 3D space, including translation, rotation, scaling, and perspect
 17/// </summary>
 18/// <remarks>
 19/// A 4x4 matrix is the standard structure for 3D transformations because it can handle both linear transformations (rot
 20/// and affine transformations (translation, shearing, and perspective projections).
 21/// It is commonly used in graphics pipelines, game engines, and 3D rendering systems.
 22///
 23/// FixedMathSharp applies transform matrices with a row-vector convention: <c>point * matrix</c>.
 24/// Translation is stored in <c>M41</c>, <c>M42</c>, and <c>M43</c>. Direction properties use the
 25/// canonical 3D basis: <c>+X</c> right, <c>+Y</c> up, and <c>+Z</c> forward.
 26///
 27/// Use Cases:
 28/// - Transforming objects in 3D space (position, orientation, and size).
 29/// - Combining multiple transformations (e.g., model-view-projection matrices).
 30/// - Applying translations, which require an extra dimension for homogeneous coordinates.
 31/// - Useful in animation, physics engines, and 3D rendering for full transformation control.
 32/// </remarks>
 33[Serializable]
 34[MemoryPackable]
 35public partial struct Fixed4x4 : IEquatable<Fixed4x4>, IFormattable
 36#if NET8_0_OR_GREATER
 37    , ISpanFormattable
 38#endif
 39{
 40    #region Static Readonly Fields
 41
 42    /// <summary>
 43    /// Returns the identity matrix (diagonal elements set to 1).
 44    /// </summary>
 145    public static readonly Fixed4x4 Identity = new(
 146        Fixed64.One, Fixed64.Zero, Fixed64.Zero, Fixed64.Zero,
 147        Fixed64.Zero, Fixed64.One, Fixed64.Zero, Fixed64.Zero,
 148        Fixed64.Zero, Fixed64.Zero, Fixed64.One, Fixed64.Zero,
 149        Fixed64.Zero, Fixed64.Zero, Fixed64.Zero, Fixed64.One);
 50
 51    /// <summary>
 52    /// Returns a matrix with all elements set to zero.
 53    /// </summary>
 154    public static readonly Fixed4x4 Zero = new(
 155        Fixed64.Zero, Fixed64.Zero, Fixed64.Zero, Fixed64.Zero,
 156        Fixed64.Zero, Fixed64.Zero, Fixed64.Zero, Fixed64.Zero,
 157        Fixed64.Zero, Fixed64.Zero, Fixed64.Zero, Fixed64.Zero,
 158        Fixed64.Zero, Fixed64.Zero, Fixed64.Zero, Fixed64.Zero);
 59
 60    #endregion
 61    #region Fields and Constants
 62
 63    // First row
 64
 65    /// <summary>
 66    /// Represents the element in the first row and first column of the matrix.
 67    /// </summary>
 68    [JsonInclude]
 69    [MemoryPackOrder(0)]
 70    public Fixed64 M11;
 71    /// <summary>
 72    /// Represents the element in the first row and second column of the matrix.
 73    /// </summary>
 74    [JsonInclude]
 75    [MemoryPackOrder(1)]
 76    public Fixed64 M12;
 77    /// <summary>
 78    /// Represents the element in the first row and third column of the matrix.
 79    /// </summary>
 80    [JsonInclude]
 81    [MemoryPackOrder(2)]
 82    public Fixed64 M13;
 83    /// <summary>
 84    /// Represents the element in the first row and fourth column of the matrix.
 85    /// </summary>
 86    [JsonInclude]
 87    [MemoryPackOrder(3)]
 88    public Fixed64 M14;
 89
 90    // Second row
 91
 92    /// <summary>
 93    /// Represents the element in the second row and first column of the matrix.
 94    /// </summary>
 95    [JsonInclude]
 96    [MemoryPackOrder(4)]
 97    public Fixed64 M21;
 98    /// <summary>
 99    /// Represents the element in the second row and second column of the matrix.
 100    /// </summary>
 101    [JsonInclude]
 102    [MemoryPackOrder(5)]
 103    public Fixed64 M22;
 104    /// <summary>
 105    /// Represents the element in the second row and third column of the matrix.
 106    /// </summary>
 107    [JsonInclude]
 108    [MemoryPackOrder(6)]
 109    public Fixed64 M23;
 110    /// <summary>
 111    /// Represents the element in the second row and fourth column of the matrix.
 112    /// </summary>
 113    [JsonInclude]
 114    [MemoryPackOrder(7)]
 115    public Fixed64 M24;
 116
 117    // Third row
 118
 119    /// <summary>
 120    /// Represents the element in the third row and first column of the matrix.
 121    /// </summary>
 122    [JsonInclude]
 123    [MemoryPackOrder(8)]
 124    public Fixed64 M31;
 125    /// <summary>
 126    /// Represents the element in the third row and second column of the matrix.
 127    /// </summary>
 128    [JsonInclude]
 129    [MemoryPackOrder(9)]
 130    public Fixed64 M32;
 131    /// <summary>
 132    /// Represents the element in the third row and third column of the matrix.
 133    /// </summary>
 134    [JsonInclude]
 135    [MemoryPackOrder(10)]
 136    public Fixed64 M33;
 137    /// <summary>
 138    /// Represents the element in the third row and fourth column of the matrix.
 139    /// </summary>
 140    [JsonInclude]
 141    [MemoryPackOrder(11)]
 142    public Fixed64 M34;
 143
 144    // Fourth row
 145
 146    /// <summary>
 147    /// Represents the element in the fourth row and first column of the matrix.
 148    /// </summary>
 149    [JsonInclude]
 150    [MemoryPackOrder(12)]
 151    public Fixed64 M41;
 152    /// <summary>
 153    /// Represents the element in the fourth row and second column of the matrix.
 154    /// </summary>
 155    [JsonInclude]
 156    [MemoryPackOrder(13)]
 157    public Fixed64 M42;
 158    /// <summary>
 159    /// Represents the element in the fourth row and third column of the matrix.
 160    /// </summary>
 161    [JsonInclude]
 162    [MemoryPackOrder(14)]
 163    public Fixed64 M43;
 164    /// <summary>
 165    /// Represents the element in the fourth row and fourth column of the matrix.
 166    /// </summary>
 167    [JsonInclude]
 168    [MemoryPackOrder(15)]
 169    public Fixed64 M44;
 170
 171    #endregion
 172    #region Constructors
 173
 174    /// <summary>
 175    /// Initializes a new FixedMatrix4x4 with individual elements.
 176    /// </summary>
 177    public Fixed4x4(
 178        Fixed64 m11, Fixed64 m12, Fixed64 m13, Fixed64 m14,
 179        Fixed64 m21, Fixed64 m22, Fixed64 m23, Fixed64 m24,
 180        Fixed64 m31, Fixed64 m32, Fixed64 m33, Fixed64 m34,
 181        Fixed64 m41, Fixed64 m42, Fixed64 m43, Fixed64 m44
 182    )
 183    {
 980184        M11 = m11; M12 = m12; M13 = m13; M14 = m14;
 980185        M21 = m21; M22 = m22; M23 = m23; M24 = m24;
 980186        M31 = m31; M32 = m32; M33 = m33; M34 = m34;
 980187        M41 = m41; M42 = m42; M43 = m43; M44 = m44;
 245188    }
 189
 190    /// <summary>
 191    /// Creates a matrix from four row vectors.
 192    /// </summary>
 193    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 194    public static Fixed4x4 FromRows(Vector4d row1, Vector4d row2, Vector4d row3, Vector4d row4)
 195    {
 1196        return new Fixed4x4(
 1197            row1.X, row1.Y, row1.Z, row1.W,
 1198            row2.X, row2.Y, row2.Z, row2.W,
 1199            row3.X, row3.Y, row3.Z, row3.W,
 1200            row4.X, row4.Y, row4.Z, row4.W);
 201    }
 202
 203    /// <summary>
 204    /// Creates a matrix from four column vectors.
 205    /// </summary>
 206    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 207    public static Fixed4x4 FromColumns(Vector4d column1, Vector4d column2, Vector4d column3, Vector4d column4)
 208    {
 1209        return new Fixed4x4(
 1210            column1.X, column2.X, column3.X, column4.X,
 1211            column1.Y, column2.Y, column3.Y, column4.Y,
 1212            column1.Z, column2.Z, column3.Z, column4.Z,
 1213            column1.W, column2.W, column3.W, column4.W);
 214    }
 215
 216    #endregion
 217    #region Properties
 218
 219    /// <summary>
 220    /// Gets a value indicating whether the matrix represents an affine transformation.
 221    /// </summary>
 222    /// <remarks>
 223    /// An affine transformation is one where the bottom row is (0, 0, 0, 1),
 224    /// allowing for efficient operations such as translation, scaling, rotation, and shearing without perspective disto
 225    /// </remarks>
 226    [JsonIgnore]
 227    [MemoryPackIgnore]
 117228    public readonly bool IsAffine => M44 == Fixed64.One
 117229        && M14 == Fixed64.Zero
 117230        && M24 == Fixed64.Zero
 117231        && M34 == Fixed64.Zero;
 232
 233    /// <inheritdoc cref="ExtractTranslation(Fixed4x4)" />
 234    [JsonIgnore]
 235    [MemoryPackIgnore]
 13236    public readonly Vector3d Translation => ExtractTranslation(this);
 237
 238    /// <summary>
 239    /// Gets the right direction vector for this instance.
 240    /// </summary>
 241    [JsonIgnore]
 242    [MemoryPackIgnore]
 3243    public readonly Vector3d Right => ExtractRight(this);
 244
 245    /// <summary>
 246    /// Gets the left direction vector for this instance.
 247    /// </summary>
 248    [JsonIgnore]
 249    [MemoryPackIgnore]
 3250    public readonly Vector3d Left => -ExtractRight(this);
 251
 252    /// <summary>
 253    /// Gets the upward direction vector for this instance.
 254    /// </summary>
 255    [JsonIgnore]
 256    [MemoryPackIgnore]
 3257    public readonly Vector3d Up => ExtractUp(this);
 258
 259    /// <summary>
 260    /// Gets the downward direction vector for this instance.
 261    /// </summary>
 262    [JsonIgnore]
 263    [MemoryPackIgnore]
 3264    public readonly Vector3d Down => -ExtractUp(this);
 265
 266    /// <summary>
 267    /// Gets the canonical forward direction vector for this instance.
 268    /// </summary>
 269    /// <remarks>
 270    /// FixedMathSharp defines semantic forward as <c>+Z</c>. Convert external matrix or transform
 271    /// conventions at adapter boundaries before relying on this basis extraction.
 272    /// </remarks>
 273    [JsonIgnore]
 274    [MemoryPackIgnore]
 3275    public readonly Vector3d Forward => ExtractForward(this);
 276
 277    /// <summary>
 278    /// Gets the backward direction vector for this instance.
 279    /// </summary>
 280    [JsonIgnore]
 281    [MemoryPackIgnore]
 3282    public readonly Vector3d Backward => -ExtractForward(this);
 283
 284    /// <inheritdoc cref="ExtractScale(Fixed4x4)" />
 285    [JsonIgnore]
 286    [MemoryPackIgnore]
 21287    public readonly Vector3d Scale => ExtractScale(this);
 288
 289    /// <inheritdoc cref="ExtractRotation(Fixed4x4)" />
 290    [JsonIgnore]
 291    [MemoryPackIgnore]
 14292    public readonly FixedQuaternion Rotation => ExtractRotation(this);
 293
 294    /// <summary>
 295    /// Gets or sets the matrix element at the specified linear index.
 296    /// </summary>
 297    /// <remarks>Matrix elements are indexed in row-major order from 0 to 15.</remarks>
 298    /// <param name="index">The zero-based linear index of the matrix element to get or set. Must be in the range 0 to 1
 299    /// <returns>The matrix element at the specified index.</returns>
 300    /// <exception cref="IndexOutOfRangeException">Thrown when the specified index is less than 0 or greater than 15.</e
 301    [JsonIgnore]
 302    [MemoryPackIgnore]
 303    public Fixed64 this[int index]
 304    {
 305        get
 306        {
 18307            return index switch
 18308            {
 1309                0 => M11,
 1310                1 => M21,
 1311                2 => M31,
 1312                3 => M41,
 1313                4 => M12,
 1314                5 => M22,
 1315                6 => M32,
 1316                7 => M42,
 1317                8 => M13,
 1318                9 => M23,
 1319                10 => M33,
 1320                11 => M43,
 1321                12 => M14,
 1322                13 => M24,
 1323                14 => M34,
 1324                15 => M44,
 2325                _ => throw new IndexOutOfRangeException("Invalid matrix index!"),
 18326            };
 327        }
 328        set
 329        {
 330            switch (index)
 331            {
 332                case 0:
 1333                    M11 = value;
 1334                    break;
 335                case 1:
 1336                    M21 = value;
 1337                    break;
 338                case 2:
 1339                    M31 = value;
 1340                    break;
 341                case 3:
 1342                    M41 = value;
 1343                    break;
 344                case 4:
 1345                    M12 = value;
 1346                    break;
 347                case 5:
 1348                    M22 = value;
 1349                    break;
 350                case 6:
 1351                    M32 = value;
 1352                    break;
 353                case 7:
 1354                    M42 = value;
 1355                    break;
 356                case 8:
 1357                    M13 = value;
 1358                    break;
 359                case 9:
 1360                    M23 = value;
 1361                    break;
 362                case 10:
 1363                    M33 = value;
 1364                    break;
 365                case 11:
 1366                    M43 = value;
 1367                    break;
 368                case 12:
 1369                    M14 = value;
 1370                    break;
 371                case 13:
 1372                    M24 = value;
 1373                    break;
 374                case 14:
 1375                    M34 = value;
 1376                    break;
 377                case 15:
 1378                    M44 = value;
 1379                    break;
 380                default:
 2381                    throw new IndexOutOfRangeException("Invalid matrix index!");
 382            }
 383        }
 384    }
 385
 386    #endregion
 387    #region Methods (Instance)
 388
 389    /// <summary>
 390    /// Calculates the determinant of a 4x4 matrix.
 391    /// </summary>
 392    public Fixed64 GetDeterminant()
 393    {
 22394        if (IsAffine)
 395        {
 13396            return M11 * (M22 * M33 - M23 * M32)
 13397                 - M12 * (M21 * M33 - M23 * M31)
 13398                 + M13 * (M21 * M32 - M22 * M31);
 399        }
 400
 401        // Process as full 4x4 matrix
 9402        Fixed64 minor0 = M33 * M44 - M34 * M43;
 9403        Fixed64 minor1 = M32 * M44 - M34 * M42;
 9404        Fixed64 minor2 = M32 * M43 - M33 * M42;
 9405        Fixed64 cofactor0 = M31 * M44 - M34 * M41;
 9406        Fixed64 cofactor1 = M31 * M43 - M33 * M41;
 9407        Fixed64 cofactor2 = M31 * M42 - M32 * M41;
 9408        return M11 * (M22 * minor0 - M23 * minor1 + M24 * minor2)
 9409            - M12 * (M21 * minor0 - M23 * cofactor0 + M24 * cofactor1)
 9410            + M13 * (M21 * minor1 - M22 * cofactor0 + M24 * cofactor2)
 9411            - M14 * (M21 * minor2 - M22 * cofactor1 + M23 * cofactor2);
 412    }
 413
 414    /// <inheritdoc cref="Fixed4x4.ResetScaleToIdentity(Fixed4x4)" />
 415    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 0416    public Fixed4x4 ResetScaleToIdentity() => this = ResetScaleToIdentity(this);
 417
 418    /// <summary>
 419    /// Sets the translation, scale, and rotation components onto the matrix.
 420    /// </summary>
 421    /// <param name="translation">The translation vector.</param>
 422    /// <param name="scale">The scale vector.</param>
 423    /// <param name="rotation">The rotation quaternion.</param>
 424    public void SetTransform(Vector3d translation, FixedQuaternion rotation, Vector3d scale) =>
 5425        this = CreateTransform(translation, rotation, scale);
 426
 427    #endregion
 428}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Numerics/Matrices/Fixed4x4.Decomposition.cs

#LineLine coverage
 1//=======================================================================
 2// Fixed4x4.Decomposition.cs
 3//=======================================================================
 4// MIT License, Copyright (c) 2024–present David Oravsky (mrdav30)
 5// See LICENSE file in the project root for full license information.
 6//=======================================================================
 7
 8using System.Runtime.CompilerServices;
 9
 10namespace FixedMathSharp;
 11
 12public partial struct Fixed4x4
 13{
 14    #region Decomposition, Extraction, and Setters
 15
 16    /// <summary>
 17    /// Extracts the translation component from the 4x4 matrix.
 18    /// </summary>
 19    /// <param name="matrix">The matrix from which to extract the translation.</param>
 20    /// <returns>A Vector3d representing the translation component.</returns>
 21    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 2022    public static Vector3d ExtractTranslation(Fixed4x4 matrix) => new(matrix.M41, matrix.M42, matrix.M43);
 23
 24    /// <summary>
 25    /// Extracts the right direction from the 4x4 matrix.
 26    /// </summary>
 627    public static Vector3d ExtractRight(Fixed4x4 matrix) => new Vector3d(matrix.M11, matrix.M12, matrix.M13).NormalizeIn
 28
 29    /// <summary>
 30    /// Extracts the up direction from the 4x4 matrix.
 31    /// </summary>
 32    /// <remarks>
 33    /// This is the surface normal if the matrix represents ground orientation.
 34    /// </remarks>
 35    /// <param name="matrix"></param>
 36    /// <returns>A <see cref="Vector3d"/> representing the up direction.</returns>
 637    public static Vector3d ExtractUp(Fixed4x4 matrix) => new Vector3d(matrix.M21, matrix.M22, matrix.M23).NormalizeInPla
 38
 39    /// <summary>
 40    /// Extracts the forward direction from the 4x4 matrix.
 41    /// </summary>
 642    public static Vector3d ExtractForward(Fixed4x4 matrix) => new Vector3d(matrix.M31, matrix.M32, matrix.M33).Normalize
 43
 44    /// <summary>
 45    /// Extracts the scaling factors from the matrix by calculating the magnitudes of the basis vectors (non-lossy).
 46    /// </summary>
 47    /// <returns>A Vector3d representing the precise scale along the X, Y, and Z axes.</returns>
 48    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 49    public static Vector3d ExtractScale(Fixed4x4 matrix) =>
 5550        new(
 5551            new Vector3d(matrix.M11, matrix.M12, matrix.M13).Magnitude,
 5552            new Vector3d(matrix.M21, matrix.M22, matrix.M23).Magnitude,
 5553            new Vector3d(matrix.M31, matrix.M32, matrix.M33).Magnitude);
 54
 55    /// <summary>
 56    /// Extracts the scaling factors from the matrix by returning the diagonal elements (lossy).
 57    /// </summary>
 58    /// <returns>A Vector3d representing the scale along X, Y, and Z axes (lossy).</returns>
 59    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 260    public static Vector3d ExtractLossyScale(Fixed4x4 matrix) => new(matrix.M11, matrix.M22, matrix.M33);
 61
 62    /// <summary>
 63    /// Extracts the rotation component from the 4x4 matrix by normalizing the rotation matrix.
 64    /// </summary>
 65    /// <param name="matrix">The matrix from which to extract the rotation.</param>
 66    /// <returns>A FixedQuaternion representing the rotation component.</returns>
 67    public static FixedQuaternion ExtractRotation(Fixed4x4 matrix)
 68    {
 2269        Vector3d scale = ExtractScale(matrix);
 70
 71        // prevent divide by zero exception
 2272        Fixed64 scaleX = scale.X == Fixed64.Zero ? Fixed64.One : scale.X;
 2273        Fixed64 scaleY = scale.Y == Fixed64.Zero ? Fixed64.One : scale.Y;
 2274        Fixed64 scaleZ = scale.Z == Fixed64.Zero ? Fixed64.One : scale.Z;
 75
 2276        Fixed4x4 normalizedMatrix = new(
 2277            matrix.M11 / scaleX, matrix.M12 / scaleX, matrix.M13 / scaleX, Fixed64.Zero,
 2278            matrix.M21 / scaleY, matrix.M22 / scaleY, matrix.M23 / scaleY, Fixed64.Zero,
 2279            matrix.M31 / scaleZ, matrix.M32 / scaleZ, matrix.M33 / scaleZ, Fixed64.Zero,
 2280            Fixed64.Zero, Fixed64.Zero, Fixed64.Zero, Fixed64.One
 2281        );
 82
 2283        return FixedQuaternion.FromMatrix(normalizedMatrix);
 84    }
 85
 86    /// <summary>
 87    /// Decomposes a 4x4 matrix into its translation, rotation, and scale components.
 88    /// </summary>
 89    /// <param name="matrix">The 4x4 matrix to decompose.</param>
 90    /// <param name="translation">The extracted translation component.</param>
 91    /// <param name="rotation">The extracted rotation component as a quaternion.</param>
 92    /// <param name="scale">The extracted scale component.</param>
 93    /// <returns>True if decomposition was successful, otherwise false.</returns>
 94    public static bool Decompose(
 95        Fixed4x4 matrix,
 96        out Vector3d translation,
 97        out FixedQuaternion rotation,
 98        out Vector3d scale)
 99    {
 100        // Extract scale by calculating the magnitudes of the basis vectors
 5101        scale = ExtractScale(matrix);
 102
 103        // prevent divide by zero exception
 5104        scale = new Vector3d(
 5105             scale.X == Fixed64.Zero ? Fixed64.One : scale.X,
 5106             scale.Y == Fixed64.Zero ? Fixed64.One : scale.Y,
 5107             scale.Z == Fixed64.Zero ? Fixed64.One : scale.Z);
 108
 109        // normalize rotation and scaling
 5110        var inverseScale = new Vector3d(
 5111            FixedMath.FastDiv(Fixed64.One, scale.X),
 5112            FixedMath.FastDiv(Fixed64.One, scale.Y),
 5113            FixedMath.FastDiv(Fixed64.One, scale.Z));
 5114        Fixed4x4 normalizedMatrix = ApplyScaleToRotation(matrix, inverseScale);
 115
 116        // Extract translation
 5117        translation = new Vector3d(normalizedMatrix.M41, normalizedMatrix.M42, normalizedMatrix.M43);
 118
 119        // Check the determinant to ensure correct handedness
 5120        Fixed64 determinant = normalizedMatrix.GetDeterminant();
 5121        if (determinant < Fixed64.Zero)
 122        {
 123            // Adjust for left-handed coordinate system by flipping one of the axes
 1124            scale.X = -scale.X;
 1125            normalizedMatrix.M11 = -normalizedMatrix.M11;
 1126            normalizedMatrix.M12 = -normalizedMatrix.M12;
 1127            normalizedMatrix.M13 = -normalizedMatrix.M13;
 128        }
 129
 130        // Extract the rotation component from the orthogonalized matrix
 5131        rotation = FixedQuaternion.FromMatrix(normalizedMatrix);
 132
 5133        return true;
 134    }
 135
 136    /// <summary>
 137    /// Sets the translation component of the 4x4 matrix.
 138    /// </summary>
 139    /// <param name="matrix">The matrix to modify.</param>
 140    /// <param name="translation">The new translation vector.</param>
 141    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 142    public static Fixed4x4 SetTranslation(Fixed4x4 matrix, Vector3d translation)
 143    {
 2144        matrix.M41 = translation.X;
 2145        matrix.M42 = translation.Y;
 2146        matrix.M43 = translation.Z;
 2147        return matrix;
 148    }
 149
 150    /// <summary>
 151    /// Sets the scale component of the 4x4 matrix by assigning the provided scale vector to the matrix's diagonal eleme
 152    /// </summary>
 153    /// <param name="matrix">The matrix to modify. Typically an identity or transformation matrix.</param>
 154    /// <param name="scale">The new scale vector to apply along the X, Y, and Z axes.</param>
 155    /// <remarks>
 156    /// Best used for applying scale to an identity matrix or resetting the scale on an existing matrix.
 157    /// For non-uniform scaling in combination with rotation, use <see cref="ApplyScaleToRotation"/>.
 158    /// </remarks>
 159    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 160    public static Fixed4x4 SetScale(Fixed4x4 matrix, Vector3d scale)
 161    {
 2162        matrix.M11 = scale.X;
 2163        matrix.M22 = scale.Y;
 2164        matrix.M33 = scale.Z;
 2165        return matrix;
 166    }
 167
 168    /// <summary>
 169    /// Applies non-uniform scaling to the 4x4 matrix by multiplying the scale vector with the rotation matrix's basis v
 170    /// </summary>
 171    /// <param name="matrix">The matrix to modify. Should already contain a valid rotation component.</param>
 172    /// <param name="scale">The scale vector to apply along the X, Y, and Z axes.</param>
 173    /// <remarks>
 174    /// Use this method when scaling is required in combination with an existing rotation, ensuring proper axis alignmen
 175    /// </remarks>
 176    public static Fixed4x4 ApplyScaleToRotation(Fixed4x4 matrix, Vector3d scale)
 177    {
 178        // Scale each row of the rotation matrix
 5179        matrix.M11 *= scale.X;
 5180        matrix.M12 *= scale.X;
 5181        matrix.M13 *= scale.X;
 182
 5183        matrix.M21 *= scale.Y;
 5184        matrix.M22 *= scale.Y;
 5185        matrix.M23 *= scale.Y;
 186
 5187        matrix.M31 *= scale.Z;
 5188        matrix.M32 *= scale.Z;
 5189        matrix.M33 *= scale.Z;
 190
 5191        return matrix;
 192    }
 193
 194    /// <summary>
 195    /// Resets the scaling part of the matrix to identity (1,1,1).
 196    /// </summary>
 197    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 198    public static Fixed4x4 ResetScaleToIdentity(Fixed4x4 matrix)
 199    {
 0200        matrix.M11 = Fixed64.One;  // X scale
 0201        matrix.M22 = Fixed64.One;  // Y scale
 0202        matrix.M33 = Fixed64.One;  // Z scale
 203
 0204        return matrix;
 205    }
 206
 207    /// <summary>
 208    /// Sets the global scale of an object using a 4x4 transformation matrix.
 209    /// </summary>
 210    /// <param name="matrix">The transformation matrix representing the object's global state.</param>
 211    /// <param name="globalScale">The desired global scale as a vector.</param>
 212    /// <remarks>
 213    /// The method extracts translation and rotation, then rebuilds the transform with the requested
 214    /// scale so component mutation does not silently drop position or distort rotation.
 215    /// </remarks>
 216    public static Fixed4x4 SetGlobalScale(Fixed4x4 matrix, Vector3d globalScale)
 217    {
 4218        Vector3d translation = ExtractTranslation(matrix);
 4219        FixedQuaternion rotation = ExtractRotation(matrix);
 220
 4221        return CreateTransform(translation, rotation, globalScale);
 222    }
 223
 224    /// <summary>
 225    /// Replaces the rotation component of the 4x4 matrix using the provided quaternion, without affecting the translati
 226    /// </summary>
 227    /// <param name="matrix">The matrix to modify. The rotation will replace the upper-left 3x3 portion of the matrix.</
 228    /// <param name="rotation">The quaternion representing the new rotation to apply.</param>
 229    /// <remarks>
 230    /// This method preserves the matrix's translation component. For complete transformation updates, use <see cref="Se
 231    /// </remarks>
 232    public static Fixed4x4 SetRotation(Fixed4x4 matrix, FixedQuaternion rotation)
 233    {
 4234        Fixed3x3 rotationMatrix = rotation.ToMatrix3x3();
 235
 4236        Vector3d scale = ExtractScale(matrix);
 237
 238        // Apply rotation to the upper-left 3x3 matrix
 239
 4240        matrix.M11 = rotationMatrix.M11 * scale.X;
 4241        matrix.M12 = rotationMatrix.M12 * scale.X;
 4242        matrix.M13 = rotationMatrix.M13 * scale.X;
 243
 4244        matrix.M21 = rotationMatrix.M21 * scale.Y;
 4245        matrix.M22 = rotationMatrix.M22 * scale.Y;
 4246        matrix.M23 = rotationMatrix.M23 * scale.Y;
 247
 4248        matrix.M31 = rotationMatrix.M31 * scale.Z;
 4249        matrix.M32 = rotationMatrix.M32 * scale.Z;
 4250        matrix.M33 = rotationMatrix.M33 * scale.Z;
 251
 4252        return matrix;
 253    }
 254
 255    /// <summary>
 256    /// Normalizes the rotation component of a 4x4 matrix by ensuring the basis vectors are orthogonal and unit length.
 257    /// </summary>
 258    /// <remarks>
 259    /// This method recalculates the X, Y, and Z basis vectors from the upper-left 3x3 portion of the matrix, ensuring t
 260    /// The remaining components of the matrix are reset to maintain a valid transformation structure.
 261    ///
 262    /// Use Cases:
 263    /// - Ensuring the rotation component remains stable and accurate after multiple transformations.
 264    /// - Used in 3D transformations to prevent numerical drift from affecting the orientation over time.
 265    /// - Essential for cases where precise orientation is required, such as animations or physics simulations.
 266    /// </remarks>
 267    public static Fixed4x4 NormalizeRotationMatrix(Fixed4x4 matrix)
 268    {
 1269        Vector3d basisX = new Vector3d(matrix.M11, matrix.M12, matrix.M13).NormalizeInPlace();
 1270        Vector3d basisY = new Vector3d(matrix.M21, matrix.M22, matrix.M23).NormalizeInPlace();
 1271        Vector3d basisZ = new Vector3d(matrix.M31, matrix.M32, matrix.M33).NormalizeInPlace();
 272
 1273        return new Fixed4x4(
 1274            basisX.X, basisX.Y, basisX.Z, Fixed64.Zero,
 1275            basisY.X, basisY.Y, basisY.Z, Fixed64.Zero,
 1276            basisZ.X, basisZ.Y, basisZ.Z, Fixed64.Zero,
 1277            Fixed64.Zero, Fixed64.Zero, Fixed64.Zero, Fixed64.One
 1278        );
 279    }
 280
 281    #endregion
 282}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Numerics/Matrices/Fixed4x4.Equality.cs

#LineLine coverage
 1//=======================================================================
 2// Fixed4x4.Equality.cs
 3//=======================================================================
 4// MIT License, Copyright (c) 2024–present David Oravsky (mrdav30)
 5// See LICENSE file in the project root for full license information.
 6//=======================================================================
 7
 8using System;
 9using System.Globalization;
 10using System.Runtime.CompilerServices;
 11
 12namespace FixedMathSharp;
 13
 14public partial struct Fixed4x4
 15{
 16    #region Equality and HashCode Overrides
 17
 18    /// <inheritdoc/>
 19    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 520    public override bool Equals(object? obj) => obj is Fixed4x4 x && Equals(x);
 21
 22    /// <inheritdoc/>
 23    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 24    public bool Equals(Fixed4x4 other) =>
 3625        M11 == other.M11 && M12 == other.M12 && M13 == other.M13 && M14 == other.M14 &&
 3626        M21 == other.M21 && M22 == other.M22 && M23 == other.M23 && M24 == other.M24 &&
 3627        M31 == other.M31 && M32 == other.M32 && M33 == other.M33 && M34 == other.M34 &&
 3628        M41 == other.M41 && M42 == other.M42 && M43 == other.M43 && M44 == other.M44;
 29
 30    /// <inheritdoc/>
 31    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 32    public override int GetHashCode()
 33    {
 34        unchecked
 35        {
 436            int hash = 17;
 437            hash = hash * 23 + M11.GetHashCode();
 438            hash = hash * 23 + M12.GetHashCode();
 439            hash = hash * 23 + M13.GetHashCode();
 440            hash = hash * 23 + M14.GetHashCode();
 441            hash = hash * 23 + M21.GetHashCode();
 442            hash = hash * 23 + M22.GetHashCode();
 443            hash = hash * 23 + M23.GetHashCode();
 444            hash = hash * 23 + M24.GetHashCode();
 445            hash = hash * 23 + M31.GetHashCode();
 446            hash = hash * 23 + M32.GetHashCode();
 447            hash = hash * 23 + M33.GetHashCode();
 448            hash = hash * 23 + M34.GetHashCode();
 449            hash = hash * 23 + M41.GetHashCode();
 450            hash = hash * 23 + M42.GetHashCode();
 451            hash = hash * 23 + M43.GetHashCode();
 452            hash = hash * 23 + M44.GetHashCode();
 453            return hash;
 54        }
 55    }
 56
 57    /// <summary>
 58    /// Returns a string that represents the current matrix in a readable format.
 59    /// </summary>
 60    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 8861    public override string ToString() => ToString(null, CultureInfo.InvariantCulture);
 62
 63    /// <summary>
 64    /// Returns a string that represents the current matrix in a readable format.
 65    /// </summary>
 66    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 67    public string ToString(string? format, IFormatProvider? formatProvider)
 68    {
 8969        Fixed4x4 value = this;
 8970        return FixedDiagnosticsFormatter.ToString((Span<char> destination, out int charsWritten) =>
 8971            value.TryFormat(destination, out charsWritten, format.AsSpan(), formatProvider));
 72    }
 73
 74    /// <summary>
 75    /// Formats this matrix into the provided destination buffer.
 76    /// </summary>
 77    public bool TryFormat(
 78        Span<char> destination,
 79        out int charsWritten,
 80        ReadOnlySpan<char> format,
 81        IFormatProvider? provider)
 82    {
 9183        int written = 0;
 9184        if (!FixedDiagnosticsFormatter.Append('[', destination, ref written) ||
 9185            !AppendRow(M11, M12, M13, M14, destination, ref written, format, provider) ||
 9186            !FixedDiagnosticsFormatter.Append("; ", destination, ref written) ||
 9187            !AppendRow(M21, M22, M23, M24, destination, ref written, format, provider) ||
 9188            !FixedDiagnosticsFormatter.Append("; ", destination, ref written) ||
 9189            !AppendRow(M31, M32, M33, M34, destination, ref written, format, provider) ||
 9190            !FixedDiagnosticsFormatter.Append("; ", destination, ref written) ||
 9191            !AppendRow(M41, M42, M43, M44, destination, ref written, format, provider) ||
 9192            !FixedDiagnosticsFormatter.Append(']', destination, ref written))
 93        {
 194            charsWritten = 0;
 195            return false;
 96        }
 97
 9098        charsWritten = written;
 9099        return true;
 100    }
 101
 102    private static bool AppendRow(
 103        Fixed64 x,
 104        Fixed64 y,
 105        Fixed64 z,
 106        Fixed64 w,
 107        Span<char> destination,
 108        ref int charsWritten,
 109        ReadOnlySpan<char> format,
 110        IFormatProvider? provider)
 111    {
 361112        return FixedDiagnosticsFormatter.Append(x, destination, ref charsWritten, format, provider) &&
 361113               FixedDiagnosticsFormatter.Append(", ", destination, ref charsWritten) &&
 361114               FixedDiagnosticsFormatter.Append(y, destination, ref charsWritten, format, provider) &&
 361115               FixedDiagnosticsFormatter.Append(", ", destination, ref charsWritten) &&
 361116               FixedDiagnosticsFormatter.Append(z, destination, ref charsWritten, format, provider) &&
 361117               FixedDiagnosticsFormatter.Append(", ", destination, ref charsWritten) &&
 361118               FixedDiagnosticsFormatter.Append(w, destination, ref charsWritten, format, provider);
 119    }
 120
 121    #endregion
 122}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Numerics/Matrices/Fixed4x4.Factories.cs

#LineLine coverage
 1//=======================================================================
 2// Fixed4x4.Factories.cs
 3//=======================================================================
 4// MIT License, Copyright (c) 2024–present David Oravsky (mrdav30)
 5// See LICENSE file in the project root for full license information.
 6//=======================================================================
 7
 8using System;
 9using System.Runtime.CompilerServices;
 10
 11namespace FixedMathSharp;
 12
 13public partial struct Fixed4x4
 14{
 15    #region Static Matrix Generators and Transformations
 16
 17    /// <summary>
 18    /// Creates a translation matrix from the specified 3-dimensional vector.
 19    /// </summary>
 20    /// <param name="position"></param>
 21    /// <returns>The translation matrix.</returns>
 22    public static Fixed4x4 CreateTranslation(Vector3d position)
 23    {
 1224        Fixed4x4 result = default;
 1225        result.M11 = Fixed64.One;
 1226        result.M12 = Fixed64.Zero;
 1227        result.M13 = Fixed64.Zero;
 1228        result.M14 = Fixed64.Zero;
 1229        result.M21 = Fixed64.Zero;
 1230        result.M22 = Fixed64.One;
 1231        result.M23 = Fixed64.Zero;
 1232        result.M24 = Fixed64.Zero;
 1233        result.M31 = Fixed64.Zero;
 1234        result.M32 = Fixed64.Zero;
 1235        result.M33 = Fixed64.One;
 1236        result.M34 = Fixed64.Zero;
 1237        result.M41 = position.X;
 1238        result.M42 = position.Y;
 1239        result.M43 = position.Z;
 1240        result.M44 = Fixed64.One;
 1241        return result;
 42    }
 43
 44    /// <summary>
 45    /// Creates a translation matrix from the specified coordinates.
 46    /// </summary>
 47    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 48    public static Fixed4x4 CreateTranslation(Fixed64 x, Fixed64 y, Fixed64 z) =>
 149        CreateTranslation(new Vector3d(x, y, z));
 50
 51    /// <summary>
 52    /// Creates a rotation matrix from a quaternion.
 53    /// </summary>
 54    /// <param name="rotation">The quaternion representing the rotation.</param>
 55    /// <returns>A 4x4 matrix representing the rotation.</returns>
 56    public static Fixed4x4 CreateRotation(FixedQuaternion rotation)
 57    {
 858        Fixed3x3 rotationMatrix = rotation.ToMatrix3x3();
 59
 860        return new Fixed4x4(
 861            rotationMatrix.M11, rotationMatrix.M12, rotationMatrix.M13, Fixed64.Zero,
 862            rotationMatrix.M21, rotationMatrix.M22, rotationMatrix.M23, Fixed64.Zero,
 863            rotationMatrix.M31, rotationMatrix.M32, rotationMatrix.M33, Fixed64.Zero,
 864            Fixed64.Zero, Fixed64.Zero, Fixed64.Zero, Fixed64.One);
 65    }
 66
 67    /// <summary>
 68    /// Creates a rotation matrix around the X axis.
 69    /// </summary>
 70    public static Fixed4x4 CreateRotationX(Fixed64 angle) =>
 671        FromRotationMatrix(Fixed3x3.CreateRotationX(angle));
 72
 73    /// <summary>
 74    /// Creates a rotation matrix around the Y axis.
 75    /// </summary>
 76    public static Fixed4x4 CreateRotationY(Fixed64 angle) =>
 677        FromRotationMatrix(Fixed3x3.CreateRotationY(angle));
 78
 79    /// <summary>
 80    /// Creates a rotation matrix around the Z axis.
 81    /// </summary>
 82    public static Fixed4x4 CreateRotationZ(Fixed64 angle) =>
 583        FromRotationMatrix(Fixed3x3.CreateRotationZ(angle));
 84
 85    /// <summary>
 86    /// Creates a rotation matrix from an axis and angle.
 87    /// </summary>
 88    public static Fixed4x4 CreateFromAxisAngle(Vector3d axis, Fixed64 angle) =>
 189        CreateRotation(FixedQuaternion.FromAxisAngle(axis, angle));
 90
 91    /// <summary>
 92    /// Creates a rotation matrix from pitch, yaw, and roll angles in radians.
 93    /// </summary>
 94    public static Fixed4x4 CreateFromEulerAngles(Fixed64 pitch, Fixed64 yaw, Fixed64 roll) =>
 195        CreateRotation(FixedQuaternion.FromEulerAngles(pitch, yaw, roll));
 96
 97    /// <summary>
 98    /// Creates a scale matrix from a 3-dimensional vector.
 99    /// </summary>
 100    /// <param name="scale">The vector representing the scale along each axis.</param>
 101    /// <returns>A 4x4 matrix representing the scale transformation.</returns>
 102    public static Fixed4x4 CreateScale(Vector3d scale) =>
 20103        new(
 20104            scale.X, Fixed64.Zero, Fixed64.Zero, Fixed64.Zero,
 20105            Fixed64.Zero, scale.Y, Fixed64.Zero, Fixed64.Zero,
 20106            Fixed64.Zero, Fixed64.Zero, scale.Z, Fixed64.Zero,
 20107            Fixed64.Zero, Fixed64.Zero, Fixed64.Zero, Fixed64.One);
 108
 109    /// <summary>
 110    /// Creates a uniform scale matrix.
 111    /// </summary>
 112    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 1113    public static Fixed4x4 CreateScale(Fixed64 scale) => CreateScale(new Vector3d(scale, scale, scale));
 114
 115    /// <summary>
 116    /// Creates a non-uniform scale matrix from individual scale components.
 117    /// </summary>
 118    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 1119    public static Fixed4x4 CreateScale(Fixed64 x, Fixed64 y, Fixed64 z) => CreateScale(new Vector3d(x, y, z));
 120
 121    /// <summary>
 122    /// Creates a view matrix looking from a camera position toward a target.
 123    /// </summary>
 124    /// <remarks>
 125    /// The view direction is expressed in FixedMathSharp's canonical <c>+Z</c>-forward basis and
 126    /// the resulting matrix follows the row-vector convention used by <see cref="TransformPoint(Fixed4x4, Vector3d)"/>.
 127    /// Convert engine-specific camera conventions at adapter boundaries.
 128    /// </remarks>
 129    public static Fixed4x4 CreateLookAt(Vector3d cameraPosition, Vector3d cameraTarget, Vector3d cameraUpVector)
 130    {
 4131        Vector3d forward = cameraTarget - cameraPosition;
 132
 4133        if (forward.MagnitudeSquared == Fixed64.Zero)
 1134            throw new ArgumentException("Camera position and target must be different.");
 135
 3136        forward = forward.NormalizeInPlace();
 3137        Vector3d right = Vector3d.Cross(cameraUpVector, forward);
 138
 3139        if (right.MagnitudeSquared == Fixed64.Zero)
 1140            throw new ArgumentException("Camera up vector must not be parallel to the view direction.");
 141
 2142        right = right.NormalizeInPlace();
 2143        Vector3d up = Vector3d.Cross(forward, right).NormalizeInPlace();
 144
 2145        return new Fixed4x4(
 2146            right.X, right.Y, right.Z, Fixed64.Zero,
 2147            up.X, up.Y, up.Z, Fixed64.Zero,
 2148            forward.X, forward.Y, forward.Z, Fixed64.Zero,
 2149            -Vector3d.Dot(right, cameraPosition),
 2150            -Vector3d.Dot(up, cameraPosition),
 2151            -Vector3d.Dot(forward, cameraPosition),
 2152            Fixed64.One);
 153    }
 154
 155    /// <summary>
 156    /// Creates an orthographic projection matrix centered on the origin.
 157    /// </summary>
 158    public static Fixed4x4 CreateOrthographic(Fixed64 width, Fixed64 height, Fixed64 zNearPlane, Fixed64 zFarPlane)
 159    {
 5160        if (width <= Fixed64.Zero)
 1161            throw new ArgumentOutOfRangeException(nameof(width), "Width must be greater than zero.");
 162
 4163        if (height <= Fixed64.Zero)
 1164            throw new ArgumentOutOfRangeException(nameof(height), "Height must be greater than zero.");
 165
 3166        Fixed64 halfWidth = width * Fixed64.Half;
 3167        Fixed64 halfHeight = height * Fixed64.Half;
 3168        return CreateOrthographicOffCenter(-halfWidth, halfWidth, -halfHeight, halfHeight, zNearPlane, zFarPlane);
 169    }
 170
 171    /// <summary>
 172    /// Creates an off-center orthographic projection matrix.
 173    /// </summary>
 174    public static Fixed4x4 CreateOrthographicOffCenter(
 175        Fixed64 left,
 176        Fixed64 right,
 177        Fixed64 bottom,
 178        Fixed64 top,
 179        Fixed64 zNearPlane,
 180        Fixed64 zFarPlane)
 181    {
 8182        if (left == right)
 1183            throw new ArgumentOutOfRangeException(nameof(right), "Right must be different from left.");
 184
 7185        if (bottom == top)
 1186            throw new ArgumentOutOfRangeException(nameof(top), "Top must be different from bottom.");
 187
 6188        ValidateDepthRange(zNearPlane, zFarPlane);
 189
 2190        Fixed64 width = right - left;
 2191        Fixed64 height = top - bottom;
 2192        Fixed64 depth = zFarPlane - zNearPlane;
 193
 2194        return new Fixed4x4(
 2195            Fixed64.Two / width, Fixed64.Zero, Fixed64.Zero, Fixed64.Zero,
 2196            Fixed64.Zero, Fixed64.Two / height, Fixed64.Zero, Fixed64.Zero,
 2197            Fixed64.Zero, Fixed64.Zero, Fixed64.One / depth, Fixed64.Zero,
 2198            (left + right) / (left - right),
 2199            (top + bottom) / (bottom - top),
 2200            -zNearPlane / depth,
 2201            Fixed64.One);
 202    }
 203
 204    /// <summary>
 205    /// Creates a perspective projection matrix centered on the near plane.
 206    /// </summary>
 207    public static Fixed4x4 CreatePerspective(
 208        Fixed64 width,
 209        Fixed64 height,
 210        Fixed64 nearPlaneDistance,
 211        Fixed64 farPlaneDistance)
 212    {
 5213        if (width <= Fixed64.Zero)
 1214            throw new ArgumentOutOfRangeException(nameof(width), "Width must be greater than zero.");
 215
 4216        if (height <= Fixed64.Zero)
 1217            throw new ArgumentOutOfRangeException(nameof(height), "Height must be greater than zero.");
 218
 3219        ValidatePerspectiveDepthRange(nearPlaneDistance, farPlaneDistance);
 220
 1221        Fixed64 depth = farPlaneDistance - nearPlaneDistance;
 1222        Fixed64 twoNear = Fixed64.Two * nearPlaneDistance;
 223
 1224        return new Fixed4x4(
 1225            twoNear / width, Fixed64.Zero, Fixed64.Zero, Fixed64.Zero,
 1226            Fixed64.Zero, twoNear / height, Fixed64.Zero, Fixed64.Zero,
 1227            Fixed64.Zero, Fixed64.Zero, farPlaneDistance / depth, Fixed64.One,
 1228            Fixed64.Zero, Fixed64.Zero, -(nearPlaneDistance * farPlaneDistance) / depth, Fixed64.Zero);
 229    }
 230
 231    /// <summary>
 232    /// Creates a perspective projection matrix from a vertical field of view.
 233    /// </summary>
 234    public static Fixed4x4 CreatePerspectiveFieldOfView(
 235        Fixed64 fieldOfView,
 236        Fixed64 aspectRatio,
 237        Fixed64 nearPlaneDistance,
 238        Fixed64 farPlaneDistance)
 239    {
 7240        if (fieldOfView <= Fixed64.Zero || fieldOfView >= Fixed64.Pi)
 2241            throw new ArgumentOutOfRangeException(nameof(fieldOfView), "Field of view must be greater than zero and less
 242
 5243        if (aspectRatio <= Fixed64.Zero)
 1244            throw new ArgumentOutOfRangeException(nameof(aspectRatio), "Aspect ratio must be greater than zero.");
 245
 4246        ValidatePerspectiveDepthRange(nearPlaneDistance, farPlaneDistance);
 247
 2248        Fixed64 yScale = Fixed64.One / FixedMath.Tan(fieldOfView * Fixed64.Half);
 2249        Fixed64 xScale = yScale / aspectRatio;
 2250        Fixed64 depth = farPlaneDistance - nearPlaneDistance;
 251
 2252        return new Fixed4x4(
 2253            xScale, Fixed64.Zero, Fixed64.Zero, Fixed64.Zero,
 2254            Fixed64.Zero, yScale, Fixed64.Zero, Fixed64.Zero,
 2255            Fixed64.Zero, Fixed64.Zero, farPlaneDistance / depth, Fixed64.One,
 2256            Fixed64.Zero, Fixed64.Zero, -(nearPlaneDistance * farPlaneDistance) / depth, Fixed64.Zero);
 257    }
 258
 259    /// <summary>
 260    /// Creates an off-center perspective projection matrix.
 261    /// </summary>
 262    public static Fixed4x4 CreatePerspectiveOffCenter(
 263        Fixed64 left,
 264        Fixed64 right,
 265        Fixed64 bottom,
 266        Fixed64 top,
 267        Fixed64 nearPlaneDistance,
 268        Fixed64 farPlaneDistance)
 269    {
 5270        if (left == right)
 1271            throw new ArgumentOutOfRangeException(nameof(right), "Right must be different from left.");
 272
 4273        if (bottom == top)
 1274            throw new ArgumentOutOfRangeException(nameof(top), "Top must be different from bottom.");
 275
 3276        ValidatePerspectiveDepthRange(nearPlaneDistance, farPlaneDistance);
 277
 1278        Fixed64 width = right - left;
 1279        Fixed64 height = top - bottom;
 1280        Fixed64 depth = farPlaneDistance - nearPlaneDistance;
 1281        Fixed64 twoNear = Fixed64.Two * nearPlaneDistance;
 282
 1283        return new Fixed4x4(
 1284            twoNear / width, Fixed64.Zero, Fixed64.Zero, Fixed64.Zero,
 1285            Fixed64.Zero, twoNear / height, Fixed64.Zero, Fixed64.Zero,
 1286            (left + right) / (left - right),
 1287            (top + bottom) / (bottom - top),
 1288            farPlaneDistance / depth,
 1289            Fixed64.One,
 1290            Fixed64.Zero, Fixed64.Zero, -(nearPlaneDistance * farPlaneDistance) / depth, Fixed64.Zero);
 291    }
 292
 293    /// <summary>
 294    /// Creates a world matrix from a position and orientation basis.
 295    /// </summary>
 296    /// <remarks>
 297    /// The <paramref name="forward"/> and <paramref name="up"/> vectors are semantic basis vectors
 298    /// in FixedMathSharp's canonical coordinate space. The returned matrix stores right, up, and
 299    /// forward basis rows for row-vector transforms.
 300    /// </remarks>
 301    public static Fixed4x4 CreateWorld(Vector3d position, Vector3d forward, Vector3d up)
 302    {
 3303        if (forward.MagnitudeSquared == Fixed64.Zero)
 1304            throw new ArgumentException("Forward vector must be non-zero.");
 305
 2306        forward = forward.NormalizeInPlace();
 2307        Vector3d right = Vector3d.Cross(up, forward);
 308
 2309        if (right.MagnitudeSquared == Fixed64.Zero)
 1310            throw new ArgumentException("Up vector must not be parallel to forward.");
 311
 1312        right = right.NormalizeInPlace();
 1313        up = Vector3d.Cross(forward, right).NormalizeInPlace();
 314
 1315        return new Fixed4x4(
 1316            right.X, right.Y, right.Z, Fixed64.Zero,
 1317            up.X, up.Y, up.Z, Fixed64.Zero,
 1318            forward.X, forward.Y, forward.Z, Fixed64.Zero,
 1319            position.X, position.Y, position.Z, Fixed64.One);
 320    }
 321
 322    /// <summary>
 323    /// Constructs a transformation matrix from translation, scale, and rotation.
 324    /// This method ensures that the rotation is properly normalized, applies the scale to the
 325    /// rotational basis, and sets the translation component separately.
 326    /// </summary>
 327    /// <remarks>
 328    /// - Uses a normalized rotation matrix to maintain numerical stability.
 329    /// - Applies non-uniform scaling to the rotation before setting translation.
 330    /// - Preferred when ensuring transformations remain mathematically correct.
 331    /// - If the rotation is already normalized and combined transformations are needed, consider using <see cref="Scale
 332    /// </remarks>
 333    /// <param name="translation">The translation vector.</param>
 334    /// <param name="scale">The scale vector.</param>
 335    /// <param name="rotation">The rotation quaternion.</param>
 336    /// <returns>A transformation matrix incorporating translation, rotation, and scale.</returns>
 337    public static Fixed4x4 CreateTransform(Vector3d translation, FixedQuaternion rotation, Vector3d scale)
 338    {
 32339        Fixed3x3 rotationMatrix = rotation.ToMatrix3x3();
 340
 32341        return new Fixed4x4(
 32342            rotationMatrix.M11 * scale.X, rotationMatrix.M12 * scale.X, rotationMatrix.M13 * scale.X, Fixed64.Zero,
 32343            rotationMatrix.M21 * scale.Y, rotationMatrix.M22 * scale.Y, rotationMatrix.M23 * scale.Y, Fixed64.Zero,
 32344            rotationMatrix.M31 * scale.Z, rotationMatrix.M32 * scale.Z, rotationMatrix.M33 * scale.Z, Fixed64.Zero,
 32345            translation.X, translation.Y, translation.Z, Fixed64.One);
 346    }
 347
 348    /// <summary>
 349    /// Constructs a transformation matrix from translation, rotation, and scale by multiplying
 350    /// separate matrices in the order: Scale * Rotation * Translation.
 351    /// </summary>
 352    /// <remarks>
 353    /// - This method directly multiplies the scale, rotation, and translation matrices.
 354    /// - Ensures that scale is applied first to preserve correct axis scaling.
 355    /// - Then rotation is applied so that rotation is not affected by non-uniform scaling.
 356    /// - Finally, translation moves the object to its correct world position.
 357    /// </remarks>
 358    public static Fixed4x4 ScaleRotateTranslate(Vector3d translation, FixedQuaternion rotation, Vector3d scale)
 359    {
 9360        return CreateTransform(translation, rotation, scale);
 361    }
 362
 363    /// <summary>
 364    /// Constructs a transformation matrix from translation, rotation, and scale by multiplying
 365    /// matrices in the order: Translation * Rotation * Scale (T * R * S).
 366    /// </summary>
 367    /// <remarks>
 368    /// - Use this method when transformations need to be applied **relative to an object's local origin**.
 369    /// - Example use cases include **animation systems**, **hierarchical transformations**, and **UI transformations**.
 370    /// - If you need to apply world-space transformations, use <see cref="CreateTransform"/> instead.
 371    /// </remarks>
 372    public static Fixed4x4 TranslateRotateScale(Vector3d translation, FixedQuaternion rotation, Vector3d scale)
 373    {
 1374        Fixed3x3 rotationMatrix = rotation.ToMatrix3x3();
 375
 1376        return new Fixed4x4(
 1377            rotationMatrix.M11 * scale.X, rotationMatrix.M12 * scale.Y, rotationMatrix.M13 * scale.Z, Fixed64.Zero,
 1378            rotationMatrix.M21 * scale.X, rotationMatrix.M22 * scale.Y, rotationMatrix.M23 * scale.Z, Fixed64.Zero,
 1379            rotationMatrix.M31 * scale.X, rotationMatrix.M32 * scale.Y, rotationMatrix.M33 * scale.Z, Fixed64.Zero,
 1380            (translation.X * rotationMatrix.M11 + translation.Y * rotationMatrix.M21 + translation.Z * rotationMatrix.M3
 1381            (translation.X * rotationMatrix.M12 + translation.Y * rotationMatrix.M22 + translation.Z * rotationMatrix.M3
 1382            (translation.X * rotationMatrix.M13 + translation.Y * rotationMatrix.M23 + translation.Z * rotationMatrix.M3
 1383            Fixed64.One);
 384    }
 385
 386    #endregion
 387}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Numerics/Matrices/Fixed4x4.Helpers.cs

#LineLine coverage
 1//=======================================================================
 2// Fixed4x4.Helpers.cs
 3//=======================================================================
 4// MIT License, Copyright (c) 2024–present David Oravsky (mrdav30)
 5// See LICENSE file in the project root for full license information.
 6//=======================================================================
 7
 8using System;
 9
 10namespace FixedMathSharp;
 11
 12public partial struct Fixed4x4
 13{
 14    #region Private Helpers
 15
 16    private static Fixed4x4 FromRotationMatrix(Fixed3x3 matrix) =>
 1717        new(
 1718            matrix.M11, matrix.M12, matrix.M13, Fixed64.Zero,
 1719            matrix.M21, matrix.M22, matrix.M23, Fixed64.Zero,
 1720            matrix.M31, matrix.M32, matrix.M33, Fixed64.Zero,
 1721            Fixed64.Zero, Fixed64.Zero, Fixed64.Zero, Fixed64.One);
 22
 23    private static void ValidateDepthRange(Fixed64 nearPlaneDistance, Fixed64 farPlaneDistance)
 24    {
 625        if (nearPlaneDistance < Fixed64.Zero)
 226            throw new ArgumentOutOfRangeException(nameof(nearPlaneDistance), "Near plane distance must be greater than o
 27
 428        if (farPlaneDistance <= nearPlaneDistance)
 229            throw new ArgumentOutOfRangeException(nameof(farPlaneDistance), "Far plane distance must be greater than or 
 230    }
 31
 32    private static void ValidatePerspectiveDepthRange(Fixed64 nearPlaneDistance, Fixed64 farPlaneDistance)
 33    {
 1034        if (nearPlaneDistance <= Fixed64.Zero)
 335            throw new ArgumentOutOfRangeException(nameof(nearPlaneDistance), "Near plane distance must be greater than z
 36
 737        if (farPlaneDistance <= nearPlaneDistance)
 338            throw new ArgumentOutOfRangeException(nameof(farPlaneDistance), "Far plane distance must be greater than nea
 439    }
 40
 41    #endregion
 42}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Numerics/Matrices/Fixed4x4.Operators.cs

#LineLine coverage
 1//=======================================================================
 2// Fixed4x4.Operators.cs
 3//=======================================================================
 4// MIT License, Copyright (c) 2024–present David Oravsky (mrdav30)
 5// See LICENSE file in the project root for full license information.
 6//=======================================================================
 7
 8using System.Runtime.CompilerServices;
 9
 10namespace FixedMathSharp;
 11
 12public partial struct Fixed4x4
 13{
 14    #region Operators
 15
 16    /// <summary>
 17    /// Negates the specified matrix by multiplying all its values by -1.
 18    /// </summary>
 19    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 20    public static Fixed4x4 operator -(Fixed4x4 value)
 21    {
 122        Fixed4x4 result = default;
 123        result.M11 = -value.M11;
 124        result.M12 = -value.M12;
 125        result.M13 = -value.M13;
 126        result.M14 = -value.M14;
 127        result.M21 = -value.M21;
 128        result.M22 = -value.M22;
 129        result.M23 = -value.M23;
 130        result.M24 = -value.M24;
 131        result.M31 = -value.M31;
 132        result.M32 = -value.M32;
 133        result.M33 = -value.M33;
 134        result.M34 = -value.M34;
 135        result.M41 = -value.M41;
 136        result.M42 = -value.M42;
 137        result.M43 = -value.M43;
 138        result.M44 = -value.M44;
 139        return result;
 40    }
 41
 42    /// <summary>
 43    /// Adds two matrices element-wise.
 44    /// </summary>
 45    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 46    public static Fixed4x4 operator +(Fixed4x4 lhs, Fixed4x4 rhs) =>
 347        new(
 348            lhs.M11 + rhs.M11, lhs.M12 + rhs.M12, lhs.M13 + rhs.M13, lhs.M14 + rhs.M14,
 349            lhs.M21 + rhs.M21, lhs.M22 + rhs.M22, lhs.M23 + rhs.M23, lhs.M24 + rhs.M24,
 350            lhs.M31 + rhs.M31, lhs.M32 + rhs.M32, lhs.M33 + rhs.M33, lhs.M34 + rhs.M34,
 351            lhs.M41 + rhs.M41, lhs.M42 + rhs.M42, lhs.M43 + rhs.M43, lhs.M44 + rhs.M44);
 52
 53    /// <summary>
 54    /// Subtracts two matrices element-wise.
 55    /// </summary>
 56    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 57    public static Fixed4x4 operator -(Fixed4x4 lhs, Fixed4x4 rhs) =>
 158        new(
 159            lhs.M11 - rhs.M11, lhs.M12 - rhs.M12, lhs.M13 - rhs.M13, lhs.M14 - rhs.M14,
 160            lhs.M21 - rhs.M21, lhs.M22 - rhs.M22, lhs.M23 - rhs.M23, lhs.M24 - rhs.M24,
 161            lhs.M31 - rhs.M31, lhs.M32 - rhs.M32, lhs.M33 - rhs.M33, lhs.M34 - rhs.M34,
 162            lhs.M41 - rhs.M41, lhs.M42 - rhs.M42, lhs.M43 - rhs.M43, lhs.M44 - rhs.M44);
 63
 64    /// <summary>
 65    /// Multiplies two 4x4 matrices using standard matrix multiplication.
 66    /// </summary>
 67    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 68    public static Fixed4x4 operator *(Fixed4x4 lhs, Fixed4x4 rhs)
 69    {
 2370        if (lhs.IsAffine && rhs.IsAffine)
 71        {
 72            // Optimized affine multiplication (skips full 4×4 multiplication)
 2173            return new Fixed4x4(
 2174                lhs.M11 * rhs.M11 + lhs.M12 * rhs.M21 + lhs.M13 * rhs.M31,
 2175                lhs.M11 * rhs.M12 + lhs.M12 * rhs.M22 + lhs.M13 * rhs.M32,
 2176                lhs.M11 * rhs.M13 + lhs.M12 * rhs.M23 + lhs.M13 * rhs.M33,
 2177                Fixed64.Zero,
 2178
 2179                lhs.M21 * rhs.M11 + lhs.M22 * rhs.M21 + lhs.M23 * rhs.M31,
 2180                lhs.M21 * rhs.M12 + lhs.M22 * rhs.M22 + lhs.M23 * rhs.M32,
 2181                lhs.M21 * rhs.M13 + lhs.M22 * rhs.M23 + lhs.M23 * rhs.M33,
 2182                Fixed64.Zero,
 2183
 2184                lhs.M31 * rhs.M11 + lhs.M32 * rhs.M21 + lhs.M33 * rhs.M31,
 2185                lhs.M31 * rhs.M12 + lhs.M32 * rhs.M22 + lhs.M33 * rhs.M32,
 2186                lhs.M31 * rhs.M13 + lhs.M32 * rhs.M23 + lhs.M33 * rhs.M33,
 2187                Fixed64.Zero,
 2188
 2189                lhs.M41 * rhs.M11 + lhs.M42 * rhs.M21 + lhs.M43 * rhs.M31 + rhs.M41,
 2190                lhs.M41 * rhs.M12 + lhs.M42 * rhs.M22 + lhs.M43 * rhs.M32 + rhs.M42,
 2191                lhs.M41 * rhs.M13 + lhs.M42 * rhs.M23 + lhs.M43 * rhs.M33 + rhs.M43,
 2192                Fixed64.One
 2193            );
 94        }
 95
 96        // Full 4×4 multiplication (fallback for perspective matrices)
 297        return new Fixed4x4(
 298            // Upper-left 3×3 matrix multiplication (rotation & scale)
 299            lhs.M11 * rhs.M11 + lhs.M12 * rhs.M21 + lhs.M13 * rhs.M31 + lhs.M14 * rhs.M41,
 2100            lhs.M11 * rhs.M12 + lhs.M12 * rhs.M22 + lhs.M13 * rhs.M32 + lhs.M14 * rhs.M42,
 2101            lhs.M11 * rhs.M13 + lhs.M12 * rhs.M23 + lhs.M13 * rhs.M33 + lhs.M14 * rhs.M43,
 2102            lhs.M11 * rhs.M14 + lhs.M12 * rhs.M24 + lhs.M13 * rhs.M34 + lhs.M14 * rhs.M44,
 2103
 2104            lhs.M21 * rhs.M11 + lhs.M22 * rhs.M21 + lhs.M23 * rhs.M31 + lhs.M24 * rhs.M41,
 2105            lhs.M21 * rhs.M12 + lhs.M22 * rhs.M22 + lhs.M23 * rhs.M32 + lhs.M24 * rhs.M42,
 2106            lhs.M21 * rhs.M13 + lhs.M22 * rhs.M23 + lhs.M23 * rhs.M33 + lhs.M24 * rhs.M43,
 2107            lhs.M21 * rhs.M14 + lhs.M22 * rhs.M24 + lhs.M23 * rhs.M34 + lhs.M24 * rhs.M44,
 2108
 2109            lhs.M31 * rhs.M11 + lhs.M32 * rhs.M21 + lhs.M33 * rhs.M31 + lhs.M34 * rhs.M41,
 2110            lhs.M31 * rhs.M12 + lhs.M32 * rhs.M22 + lhs.M33 * rhs.M32 + lhs.M34 * rhs.M42,
 2111            lhs.M31 * rhs.M13 + lhs.M32 * rhs.M23 + lhs.M33 * rhs.M33 + lhs.M34 * rhs.M43,
 2112            lhs.M31 * rhs.M14 + lhs.M32 * rhs.M24 + lhs.M33 * rhs.M34 + lhs.M34 * rhs.M44,
 2113
 2114            // Compute new translation
 2115            lhs.M41 * rhs.M11 + lhs.M42 * rhs.M21 + lhs.M43 * rhs.M31 + lhs.M44 * rhs.M41,
 2116            lhs.M41 * rhs.M12 + lhs.M42 * rhs.M22 + lhs.M43 * rhs.M32 + lhs.M44 * rhs.M42,
 2117            lhs.M41 * rhs.M13 + lhs.M42 * rhs.M23 + lhs.M43 * rhs.M33 + lhs.M44 * rhs.M43,
 2118            lhs.M41 * rhs.M14 + lhs.M42 * rhs.M24 + lhs.M43 * rhs.M34 + lhs.M44 * rhs.M44
 2119        );
 120    }
 121
 122    /// <summary>
 123    /// Multiplies every matrix component by a scalar.
 124    /// </summary>
 125    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 126    public static Fixed4x4 operator *(Fixed4x4 matrix, Fixed64 scalar) =>
 5127        new(
 5128            matrix.M11 * scalar, matrix.M12 * scalar, matrix.M13 * scalar, matrix.M14 * scalar,
 5129            matrix.M21 * scalar, matrix.M22 * scalar, matrix.M23 * scalar, matrix.M24 * scalar,
 5130            matrix.M31 * scalar, matrix.M32 * scalar, matrix.M33 * scalar, matrix.M34 * scalar,
 5131            matrix.M41 * scalar, matrix.M42 * scalar, matrix.M43 * scalar, matrix.M44 * scalar);
 132
 133    /// <summary>
 134    /// Multiplies every matrix component by a scalar.
 135    /// </summary>
 136    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 1137    public static Fixed4x4 operator *(Fixed64 scalar, Fixed4x4 matrix) => matrix * scalar;
 138
 139    /// <summary>
 140    /// Divides every matrix component by a scalar.
 141    /// </summary>
 142    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 143    public static Fixed4x4 operator /(Fixed4x4 matrix, Fixed64 scalar)
 144    {
 2145        Fixed64 inverse = Fixed64.One / scalar;
 2146        return matrix * inverse;
 147    }
 148
 149    /// <summary>
 150    /// Determines whether two Fixed4x4 instances are equal.
 151    /// </summary>
 152    /// <param name="left">The first Fixed4x4 instance to compare.</param>
 153    /// <param name="right">The second Fixed4x4 instance to compare.</param>
 154    /// <returns>true if the specified Fixed4x4 instances are equal; otherwise, false.</returns>
 155    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 2156    public static bool operator ==(Fixed4x4 left, Fixed4x4 right) => left.Equals(right);
 157
 158    /// <summary>
 159    /// Determines whether two Fixed4x4 instances are not equal.
 160    /// </summary>
 161    /// <param name="left">The first Fixed4x4 instance to compare.</param>
 162    /// <param name="right">The second Fixed4x4 instance to compare.</param>
 163    /// <returns>true if the specified Fixed4x4 instances are not equal; otherwise, false.</returns>
 164    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 1165    public static bool operator !=(Fixed4x4 left, Fixed4x4 right) => !(left == right);
 166
 167    #endregion
 168}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Numerics/Matrices/Fixed4x4.Statics.cs

#LineLine coverage
 1//=======================================================================
 2// Fixed4x4.Statics.cs
 3//=======================================================================
 4// MIT License, Copyright (c) 2024–present David Oravsky (mrdav30)
 5// See LICENSE file in the project root for full license information.
 6//=======================================================================
 7
 8using System;
 9using System.Runtime.CompilerServices;
 10
 11namespace FixedMathSharp;
 12
 13public partial struct Fixed4x4
 14{
 15    #region Static Matrix Operators
 16
 17    /// <summary>
 18    /// Linearly interpolates between two matrices component-wise.
 19    /// </summary>
 20    public static Fixed4x4 Lerp(Fixed4x4 a, Fixed4x4 b, Fixed64 t) =>
 321         new(
 322            FixedMath.Lerp(a.M11, b.M11, t),
 323            FixedMath.Lerp(a.M12, b.M12, t),
 324            FixedMath.Lerp(a.M13, b.M13, t),
 325            FixedMath.Lerp(a.M14, b.M14, t),
 326            FixedMath.Lerp(a.M21, b.M21, t),
 327            FixedMath.Lerp(a.M22, b.M22, t),
 328            FixedMath.Lerp(a.M23, b.M23, t),
 329            FixedMath.Lerp(a.M24, b.M24, t),
 330            FixedMath.Lerp(a.M31, b.M31, t),
 331            FixedMath.Lerp(a.M32, b.M32, t),
 332            FixedMath.Lerp(a.M33, b.M33, t),
 333            FixedMath.Lerp(a.M34, b.M34, t),
 334            FixedMath.Lerp(a.M41, b.M41, t),
 335            FixedMath.Lerp(a.M42, b.M42, t),
 336            FixedMath.Lerp(a.M43, b.M43, t),
 337            FixedMath.Lerp(a.M44, b.M44, t));
 38
 39    /// <summary>
 40    /// Transposes the matrix by swapping rows and columns.
 41    /// </summary>
 42    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 43    public static Fixed4x4 Transpose(Fixed4x4 matrix) =>
 344         new(
 345            matrix.M11, matrix.M21, matrix.M31, matrix.M41,
 346            matrix.M12, matrix.M22, matrix.M32, matrix.M42,
 347            matrix.M13, matrix.M23, matrix.M33, matrix.M43,
 348            matrix.M14, matrix.M24, matrix.M34, matrix.M44);
 49
 50    /// <summary>
 51    /// Divides each component of one matrix by the corresponding component of another matrix.
 52    /// </summary>
 53    /// <exception cref="DivideByZeroException">
 54    /// Thrown when any divisor component is zero.
 55    /// </exception>
 56    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 57    public static Fixed4x4 ComponentDivide(Fixed4x4 dividend, Fixed4x4 divisor) =>
 258        new(
 259            dividend.M11 / divisor.M11,
 260            dividend.M12 / divisor.M12,
 261            dividend.M13 / divisor.M13,
 262            dividend.M14 / divisor.M14,
 263            dividend.M21 / divisor.M21,
 264            dividend.M22 / divisor.M22,
 265            dividend.M23 / divisor.M23,
 266            dividend.M24 / divisor.M24,
 267            dividend.M31 / divisor.M31,
 268            dividend.M32 / divisor.M32,
 269            dividend.M33 / divisor.M33,
 270            dividend.M34 / divisor.M34,
 271            dividend.M41 / divisor.M41,
 272            dividend.M42 / divisor.M42,
 273            dividend.M43 / divisor.M43,
 274            dividend.M44 / divisor.M44);
 75
 76    /// <summary>
 77    /// Divides one matrix by another using inverse matrix division.
 78    /// </summary>
 79    /// <remarks>
 80    /// This is equivalent to <c>dividend * Invert(divisor)</c>. Use <see cref="ComponentDivide"/>
 81    /// when each matrix component should be divided by the corresponding component of another matrix.
 82    /// </remarks>
 83    /// <exception cref="InvalidOperationException">
 84    /// Thrown when <paramref name="divisor"/> is not invertible.
 85    /// </exception>
 86    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 87    public static Fixed4x4 InverseDivide(Fixed4x4 dividend, Fixed4x4 divisor)
 88    {
 289        if (!Invert(divisor, out Fixed4x4 inverseDivisor))
 190            throw new InvalidOperationException("Matrix divisor is not invertible.");
 91
 192        return dividend * inverseDivisor;
 93    }
 94
 95    /// <summary>
 96    /// Inverts the matrix if it is invertible (i.e., if the determinant is not zero).
 97    /// </summary>
 98    /// <remarks>
 99    /// To Invert a FixedMatrix4x4, we need to calculate the inverse for each element.
 100    /// This involves computing the cofactor for each element,
 101    /// which is the determinant of the submatrix when the row and column of that element are removed,
 102    /// multiplied by a sign based on the element's position.
 103    /// After computing all cofactors, the result is transposed to get the inverse matrix.
 104    /// </remarks>
 105    public static bool Invert(Fixed4x4 matrix, out Fixed4x4 result)
 106    {
 14107        if (!matrix.IsAffine)
 7108            return FullInvert(matrix, out result);
 109
 7110        Fixed64 det = matrix.GetDeterminant();
 111
 7112        if (det == Fixed64.Zero)
 113        {
 1114            result = Identity;
 1115            return false;
 116        }
 117
 6118        Fixed64 invDet = Fixed64.One / det;
 119
 120        // Invert the 3×3 upper-left rotation/scale matrix
 6121        result = new Fixed4x4(
 6122            (matrix.M22 * matrix.M33 - matrix.M23 * matrix.M32) * invDet,
 6123            (matrix.M13 * matrix.M32 - matrix.M12 * matrix.M33) * invDet,
 6124            (matrix.M12 * matrix.M23 - matrix.M13 * matrix.M22) * invDet, Fixed64.Zero,
 6125
 6126            (matrix.M23 * matrix.M31 - matrix.M21 * matrix.M33) * invDet,
 6127            (matrix.M11 * matrix.M33 - matrix.M13 * matrix.M31) * invDet,
 6128            (matrix.M13 * matrix.M21 - matrix.M11 * matrix.M23) * invDet, Fixed64.Zero,
 6129
 6130            (matrix.M21 * matrix.M32 - matrix.M22 * matrix.M31) * invDet,
 6131            (matrix.M12 * matrix.M31 - matrix.M11 * matrix.M32) * invDet,
 6132            (matrix.M11 * matrix.M22 - matrix.M12 * matrix.M21) * invDet, Fixed64.Zero,
 6133
 6134            Fixed64.Zero, Fixed64.Zero, Fixed64.Zero, Fixed64.One  // Ensure homogeneous coordinate stays valid
 6135        );
 136
 6137        result.M41 = -(matrix.M41 * result.M11 + matrix.M42 * result.M21 + matrix.M43 * result.M31);
 6138        result.M42 = -(matrix.M41 * result.M12 + matrix.M42 * result.M22 + matrix.M43 * result.M32);
 6139        result.M43 = -(matrix.M41 * result.M13 + matrix.M42 * result.M23 + matrix.M43 * result.M33);
 6140        result.M44 = Fixed64.One;
 141
 6142        return true;
 143    }
 144
 145    private static bool FullInvert(Fixed4x4 matrix, out Fixed4x4 result)
 146    {
 7147        Fixed64 det = matrix.GetDeterminant();
 148
 7149        if (det == Fixed64.Zero)
 150        {
 3151            result = Fixed4x4.Identity;
 3152            return false;
 153        }
 154
 4155        Fixed64 invDet = Fixed64.One / det;
 156
 157        // Inversion using cofactors and determinants of 3x3 submatrices
 4158        result = new Fixed4x4
 4159        {
 4160            // First row
 4161            M11 = invDet * ((matrix.M22 * matrix.M33 * matrix.M44 + matrix.M23 * matrix.M34 * matrix.M42 + matrix.M24 * 
 4162                          - (matrix.M24 * matrix.M33 * matrix.M42 + matrix.M22 * matrix.M34 * matrix.M43 + matrix.M23 * 
 4163            M12 = invDet * ((matrix.M12 * matrix.M34 * matrix.M43 + matrix.M13 * matrix.M32 * matrix.M44 + matrix.M14 * 
 4164                          - (matrix.M14 * matrix.M32 * matrix.M43 + matrix.M12 * matrix.M33 * matrix.M44 + matrix.M13 * 
 4165            M13 = invDet * ((matrix.M12 * matrix.M23 * matrix.M44 + matrix.M13 * matrix.M24 * matrix.M42 + matrix.M14 * 
 4166                          - (matrix.M14 * matrix.M23 * matrix.M42 + matrix.M12 * matrix.M24 * matrix.M43 + matrix.M13 * 
 4167            M14 = invDet * ((matrix.M12 * matrix.M24 * matrix.M33 + matrix.M13 * matrix.M22 * matrix.M34 + matrix.M14 * 
 4168                          - (matrix.M14 * matrix.M22 * matrix.M33 + matrix.M12 * matrix.M23 * matrix.M34 + matrix.M13 * 
 4169
 4170            // Second row
 4171            M21 = invDet * ((matrix.M21 * matrix.M34 * matrix.M43 + matrix.M23 * matrix.M31 * matrix.M44 + matrix.M24 * 
 4172                          - (matrix.M24 * matrix.M31 * matrix.M43 + matrix.M21 * matrix.M33 * matrix.M44 + matrix.M23 * 
 4173            M22 = invDet * ((matrix.M11 * matrix.M33 * matrix.M44 + matrix.M13 * matrix.M34 * matrix.M41 + matrix.M14 * 
 4174                          - (matrix.M14 * matrix.M31 * matrix.M43 + matrix.M11 * matrix.M34 * matrix.M43 + matrix.M13 * 
 4175            M23 = invDet * ((matrix.M11 * matrix.M24 * matrix.M43 + matrix.M13 * matrix.M21 * matrix.M44 + matrix.M14 * 
 4176                          - (matrix.M14 * matrix.M21 * matrix.M43 + matrix.M11 * matrix.M23 * matrix.M44 + matrix.M13 * 
 4177            M24 = invDet * ((matrix.M11 * matrix.M23 * matrix.M34 + matrix.M13 * matrix.M24 * matrix.M31 + matrix.M14 * 
 4178                          - (matrix.M14 * matrix.M21 * matrix.M33 + matrix.M11 * matrix.M24 * matrix.M33 + matrix.M13 * 
 4179
 4180            // Third row
 4181            M31 = invDet * ((matrix.M21 * matrix.M32 * matrix.M44 + matrix.M22 * matrix.M34 * matrix.M41 + matrix.M24 * 
 4182                          - (matrix.M24 * matrix.M31 * matrix.M42 + matrix.M21 * matrix.M34 * matrix.M42 + matrix.M22 * 
 4183            M32 = invDet * ((matrix.M11 * matrix.M34 * matrix.M42 + matrix.M12 * matrix.M31 * matrix.M44 + matrix.M14 * 
 4184                          - (matrix.M14 * matrix.M31 * matrix.M42 + matrix.M11 * matrix.M32 * matrix.M44 + matrix.M12 * 
 4185            M33 = invDet * ((matrix.M11 * matrix.M22 * matrix.M44 + matrix.M12 * matrix.M24 * matrix.M41 + matrix.M14 * 
 4186                          - (matrix.M14 * matrix.M21 * matrix.M42 + matrix.M11 * matrix.M24 * matrix.M42 + matrix.M12 * 
 4187            M34 = invDet * ((matrix.M11 * matrix.M24 * matrix.M32 + matrix.M12 * matrix.M21 * matrix.M34 + matrix.M14 * 
 4188                          - (matrix.M14 * matrix.M21 * matrix.M32 + matrix.M11 * matrix.M22 * matrix.M34 + matrix.M12 * 
 4189
 4190            // Fourth row
 4191            M41 = invDet * ((matrix.M21 * matrix.M33 * matrix.M42 + matrix.M22 * matrix.M31 * matrix.M43 + matrix.M23 * 
 4192                          - (matrix.M23 * matrix.M31 * matrix.M42 + matrix.M21 * matrix.M32 * matrix.M43 + matrix.M22 * 
 4193            M42 = invDet * ((matrix.M11 * matrix.M32 * matrix.M43 + matrix.M12 * matrix.M33 * matrix.M41 + matrix.M13 * 
 4194                          - (matrix.M13 * matrix.M31 * matrix.M42 + matrix.M11 * matrix.M33 * matrix.M42 + matrix.M12 * 
 4195            M43 = invDet * ((matrix.M11 * matrix.M23 * matrix.M42 + matrix.M12 * matrix.M21 * matrix.M43 + matrix.M13 * 
 4196                          - (matrix.M13 * matrix.M21 * matrix.M42 + matrix.M11 * matrix.M22 * matrix.M43 + matrix.M12 * 
 4197            M44 = invDet * ((matrix.M11 * matrix.M22 * matrix.M33 + matrix.M12 * matrix.M23 * matrix.M31 + matrix.M13 * 
 4198                          - (matrix.M13 * matrix.M21 * matrix.M32 + matrix.M11 * matrix.M23 * matrix.M32 + matrix.M12 * 
 4199        };
 200
 4201        return true;
 202    }
 203
 204    /// <summary>
 205    /// Transforms a 4D vector by a 4x4 matrix, preserving the computed W component.
 206    /// </summary>
 207    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 2208    public static Vector4d Transform(Fixed4x4 matrix, Vector4d vector) => Vector4d.Transform(matrix, vector);
 209
 210    /// <summary>
 211    /// Transforms a point from local space to world space using this transformation matrix.
 212    /// </summary>
 213    /// <remarks>
 214    /// FixedMathSharp applies matrices using a row-vector convention: <c>point * matrix</c>.
 215    /// This is equivalent to <see cref="Vector3d.operator *(Vector3d, Fixed4x4)"/>.
 216    /// </remarks>
 217    /// <param name="matrix">The transformation matrix.</param>
 218    /// <param name="point">The local-space point.</param>
 219    /// <returns>The transformed point in world space.</returns>
 220    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 221    public static Vector3d TransformPoint(Fixed4x4 matrix, Vector3d point)
 222    {
 20223        if (matrix.IsAffine)
 15224            return new Vector3d(
 15225                point.X * matrix.M11 + point.Y * matrix.M21 + point.Z * matrix.M31 + matrix.M41,
 15226                point.X * matrix.M12 + point.Y * matrix.M22 + point.Z * matrix.M32 + matrix.M42,
 15227                point.X * matrix.M13 + point.Y * matrix.M23 + point.Z * matrix.M33 + matrix.M43
 15228            );
 229
 5230        return FullTransformPoint(matrix, point);
 231    }
 232
 233    private static Vector3d FullTransformPoint(Fixed4x4 matrix, Vector3d point)
 234    {
 235        // Full 4×4 transformation (needed for perspective projections)
 5236        Fixed64 w = matrix.M14 * point.X + matrix.M24 * point.Y + matrix.M34 * point.Z + matrix.M44;
 6237        if (w == Fixed64.Zero) w = Fixed64.One;  // Prevent divide-by-zero
 238
 5239        return new Vector3d(
 5240            (point.X * matrix.M11 + point.Y * matrix.M21 + point.Z * matrix.M31 + matrix.M41) / w,
 5241            (point.X * matrix.M12 + point.Y * matrix.M22 + point.Z * matrix.M32 + matrix.M42) / w,
 5242            (point.X * matrix.M13 + point.Y * matrix.M23 + point.Z * matrix.M33 + matrix.M43) / w
 5243        );
 244    }
 245
 246    /// <summary>
 247    /// Transforms a point from world space into the local space of the matrix.
 248    /// </summary>
 249    /// <param name="matrix">The transformation matrix.</param>
 250    /// <param name="point">The world-space point.</param>
 251    /// <returns>The local-space point relative to the transformation matrix.</returns>
 252    public static Vector3d InverseTransformPoint(Fixed4x4 matrix, Vector3d point)
 253    {
 254        // Invert the transformation matrix
 7255        if (!Invert(matrix, out Fixed4x4 inverseMatrix))
 1256            throw new InvalidOperationException("Matrix is not invertible.");
 257
 6258        if (inverseMatrix.IsAffine)
 259        {
 3260            return new Vector3d(
 3261                point.X * inverseMatrix.M11 + point.Y * inverseMatrix.M21 + point.Z * inverseMatrix.M31 + inverseMatrix.
 3262                point.X * inverseMatrix.M12 + point.Y * inverseMatrix.M22 + point.Z * inverseMatrix.M32 + inverseMatrix.
 3263                point.X * inverseMatrix.M13 + point.Y * inverseMatrix.M23 + point.Z * inverseMatrix.M33 + inverseMatrix.
 3264            );
 265        }
 266
 3267        return FullInverseTransformPoint(inverseMatrix, point);
 268    }
 269
 270    private static Vector3d FullInverseTransformPoint(Fixed4x4 matrix, Vector3d point)
 271    {
 272        // Full 4×4 transformation (needed for perspective projections)
 3273        Fixed64 w = matrix.M14 * point.X + matrix.M24 * point.Y + matrix.M34 * point.Z + matrix.M44;
 4274        if (w == Fixed64.Zero) w = Fixed64.One;  // Prevent divide-by-zero
 275
 3276        return new Vector3d(
 3277            (point.X * matrix.M11 + point.Y * matrix.M21 + point.Z * matrix.M31 + matrix.M41) / w,
 3278            (point.X * matrix.M12 + point.Y * matrix.M22 + point.Z * matrix.M32 + matrix.M42) / w,
 3279            (point.X * matrix.M13 + point.Y * matrix.M23 + point.Z * matrix.M33 + matrix.M43) / w
 3280        );
 281    }
 282
 283    #endregion
 284}

Methods/Properties

.cctor()
.ctor(FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64)
FromRows(FixedMathSharp.Vector4d,FixedMathSharp.Vector4d,FixedMathSharp.Vector4d,FixedMathSharp.Vector4d)
FromColumns(FixedMathSharp.Vector4d,FixedMathSharp.Vector4d,FixedMathSharp.Vector4d,FixedMathSharp.Vector4d)
get_IsAffine()
get_Translation()
get_Right()
get_Left()
get_Up()
get_Down()
get_Forward()
get_Backward()
get_Scale()
get_Rotation()
get_Item(System.Int32)
set_Item(System.Int32,FixedMathSharp.Fixed64)
GetDeterminant()
ResetScaleToIdentity()
SetTransform(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d)
ExtractTranslation(FixedMathSharp.Fixed4x4)
ExtractRight(FixedMathSharp.Fixed4x4)
ExtractUp(FixedMathSharp.Fixed4x4)
ExtractForward(FixedMathSharp.Fixed4x4)
ExtractScale(FixedMathSharp.Fixed4x4)
ExtractLossyScale(FixedMathSharp.Fixed4x4)
ExtractRotation(FixedMathSharp.Fixed4x4)
Decompose(FixedMathSharp.Fixed4x4,FixedMathSharp.Vector3d&,FixedMathSharp.FixedQuaternion&,FixedMathSharp.Vector3d&)
SetTranslation(FixedMathSharp.Fixed4x4,FixedMathSharp.Vector3d)
SetScale(FixedMathSharp.Fixed4x4,FixedMathSharp.Vector3d)
ApplyScaleToRotation(FixedMathSharp.Fixed4x4,FixedMathSharp.Vector3d)
ResetScaleToIdentity(FixedMathSharp.Fixed4x4)
SetGlobalScale(FixedMathSharp.Fixed4x4,FixedMathSharp.Vector3d)
SetRotation(FixedMathSharp.Fixed4x4,FixedMathSharp.FixedQuaternion)
NormalizeRotationMatrix(FixedMathSharp.Fixed4x4)
Equals(System.Object)
Equals(FixedMathSharp.Fixed4x4)
GetHashCode()
ToString()
ToString(System.String,System.IFormatProvider)
TryFormat(System.Span`1<System.Char>,System.Int32&,System.ReadOnlySpan`1<System.Char>,System.IFormatProvider)
AppendRow(FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,System.Span`1<System.Char>,System.Int32&,System.ReadOnlySpan`1<System.Char>,System.IFormatProvider)
CreateTranslation(FixedMathSharp.Vector3d)
CreateTranslation(FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64)
CreateRotation(FixedMathSharp.FixedQuaternion)
CreateRotationX(FixedMathSharp.Fixed64)
CreateRotationY(FixedMathSharp.Fixed64)
CreateRotationZ(FixedMathSharp.Fixed64)
CreateFromAxisAngle(FixedMathSharp.Vector3d,FixedMathSharp.Fixed64)
CreateFromEulerAngles(FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64)
CreateScale(FixedMathSharp.Vector3d)
CreateScale(FixedMathSharp.Fixed64)
CreateScale(FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64)
CreateLookAt(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d)
CreateOrthographic(FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64)
CreateOrthographicOffCenter(FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64)
CreatePerspective(FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64)
CreatePerspectiveFieldOfView(FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64)
CreatePerspectiveOffCenter(FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64)
CreateWorld(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d)
CreateTransform(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d)
ScaleRotateTranslate(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d)
TranslateRotateScale(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d)
FromRotationMatrix(FixedMathSharp.Fixed3x3)
ValidateDepthRange(FixedMathSharp.Fixed64,FixedMathSharp.Fixed64)
ValidatePerspectiveDepthRange(FixedMathSharp.Fixed64,FixedMathSharp.Fixed64)
op_UnaryNegation(FixedMathSharp.Fixed4x4)
op_Addition(FixedMathSharp.Fixed4x4,FixedMathSharp.Fixed4x4)
op_Subtraction(FixedMathSharp.Fixed4x4,FixedMathSharp.Fixed4x4)
op_Multiply(FixedMathSharp.Fixed4x4,FixedMathSharp.Fixed4x4)
op_Multiply(FixedMathSharp.Fixed4x4,FixedMathSharp.Fixed64)
op_Multiply(FixedMathSharp.Fixed64,FixedMathSharp.Fixed4x4)
op_Division(FixedMathSharp.Fixed4x4,FixedMathSharp.Fixed64)
op_Equality(FixedMathSharp.Fixed4x4,FixedMathSharp.Fixed4x4)
op_Inequality(FixedMathSharp.Fixed4x4,FixedMathSharp.Fixed4x4)
Lerp(FixedMathSharp.Fixed4x4,FixedMathSharp.Fixed4x4,FixedMathSharp.Fixed64)
Transpose(FixedMathSharp.Fixed4x4)
ComponentDivide(FixedMathSharp.Fixed4x4,FixedMathSharp.Fixed4x4)
InverseDivide(FixedMathSharp.Fixed4x4,FixedMathSharp.Fixed4x4)
Invert(FixedMathSharp.Fixed4x4,FixedMathSharp.Fixed4x4&)
FullInvert(FixedMathSharp.Fixed4x4,FixedMathSharp.Fixed4x4&)
Transform(FixedMathSharp.Fixed4x4,FixedMathSharp.Vector4d)
TransformPoint(FixedMathSharp.Fixed4x4,FixedMathSharp.Vector3d)
FullTransformPoint(FixedMathSharp.Fixed4x4,FixedMathSharp.Vector3d)
InverseTransformPoint(FixedMathSharp.Fixed4x4,FixedMathSharp.Vector3d)
FullInverseTransformPoint(FixedMathSharp.Fixed4x4,FixedMathSharp.Vector3d)