/// <summary>
        /// Transforms the current vector by a matrix.
        /// </summary>
        /// <param name="m">Matrix to transform current vector with.</param>
        public void Mul(ref Matrix4 m)
        {
            float ox = x;
            float oy = y;
            float oz = z;

            x = ox * m.A1 + oy * m.B1 + oz * m.C1 + m.D1;
            y = ox * m.A2 + oy * m.B2 + oz * m.C2 + m.D2;
            z = ox * m.A3 + oy * m.B3 + oz * m.C3 + m.D3;
        }
        /// <summary>
        /// Spherical quadratic interpolation between matrices.
        /// </summary>
        /// <remarks>The matrices are converted to quaternion for every invocation => it is recommended to use the Quaternion.Squad 
        /// method instead.</remarks>
        /// <param name="pre">One matrix before the actual interpolation matrices.</param>
        /// <param name="a">First matrix.</param>
        /// <param name="b">Second matrix.</param>
        /// <param name="post">One matrix after the actual interpolation matrices.</param>
        /// <param name="time">The interpolation time.</param>
        /// <returns>The interpolated matrix.</returns>
        public static Matrix4 Squad(Matrix4 pre, Matrix4 a, Matrix4 b, Matrix4 post, float time)
        {
            Quaternion qPre = pre.Quaternion;
            Quaternion qa = a.Quaternion;
            Quaternion qb = b.Quaternion;
            Quaternion qPost = post.Quaternion;

            Quaternion interpolated = //Quaternion.Slerp(qa, qb, time);
              Quaternion.SimpleSquad(qPre, qa, qb, qPost, time);

            Matrix4 result = interpolated.Matrix4;

            //result.TranslationVector = CRSpline.Interpolate(time, pre.TranslationVector,
             // a.TranslationVector, b.TranslationVector, post.TranslationVector);
            return result;
        }
 //---------------------------------------------------------------
 /// <summary>
 /// Adds the weighted skinned source vector.
 /// </summary>
 public void AddSkinned(Vector3 sourceVec, ref Matrix4 joint, float weight)
 {
     x += (sourceVec.x * joint.A1 + sourceVec.y * joint.B1 + sourceVec.z * joint.C1 + joint.D1) * weight;
     y += (sourceVec.x * joint.A2 + sourceVec.y * joint.B2 + sourceVec.z * joint.C2 + joint.D2) * weight;
     z += (sourceVec.x * joint.A3 + sourceVec.y * joint.B3 + sourceVec.z * joint.C3 + joint.D3) * weight;
 }
 /// <summary>
 /// builds a rotation matrix for a given vector and an angle
 /// </summary>
 /// <param name="vec">to rotate around</param>
 /// <param name="angle">rotation angle</param>
 /// <returns>rotation matrix</returns>
 public static Matrix4 Rotation(Vector3 vec, float angle)
 {
     float c = Math.Trigonometry.Cos(angle);
     float s = Math.Trigonometry.Sin(angle);
     float t = 1 - c;
     Matrix4 m =
             new Matrix4(t * vec.X * vec.X + c, t * vec.X * vec.Y + s * vec.Z, t * vec.X * vec.Z + s * vec.Y, 0,
                                             t * vec.X * vec.Y - s * vec.Z, t * vec.Y * vec.Y + c, t * vec.Y * vec.Z + s * vec.X, 0,
                                             t * vec.X * vec.Z + s * vec.Y, t * vec.Y * vec.Z - s * vec.X, t * vec.Z * vec.Z + c, 0,
                                                                                         0, 0, 0, 1);
     return Matrix4.Transpose(m);
 }
        /// <summary>
        /// Spherical linear interpolation between to matrices.
        /// </summary>
        /// <param name="a">First matrix.</param>
        /// <param name="b">Second matrix.</param>
        /// <param name="time">Interpolation time [0..1].</param>
        /// <returns>Interpolated matrix.</returns>
        public static Matrix4 Slerp(Matrix4 a, Matrix4 b, float time)
        {
            Quaternion qa = a.Quaternion;
            Quaternion qb = b.Quaternion;

            Quaternion interpolated = Quaternion.Slerp(qa, qb, time);

            Matrix4 result = interpolated.Matrix4;
            result.TranslationVector = Vector3.Lerp(a.TranslationVector, b.TranslationVector, time);
            return result;
        }
 /// <summary>
 /// get 3x3 matrix from 4x4 matrix without specified column and row
 /// </summary>
 /// <param name="source">source matrix (4x4)</param>
 /// <param name="column">column to remove</param>
 /// <param name="row">row to remove</param>
 /// <returns>3x3 matrix from 4x4 matrix without specified column and row</returns>
 public static Matrix3 Minor(Matrix4 source, int column, int row)
 {
     int r = 0;
     Matrix3 result = new Matrix3();
     for (int iRow = 0; iRow < 4; iRow++)
     {
         int c = 0;
         if (iRow != row)
         {
             for (int iColumn = 0; iColumn < 4; iColumn++)
             {
                 if (iColumn != column)
                 {
                     result[c, r] = source[iColumn, iRow];
                     c++;
                 }
             }
             r++;
         }
     }
     return result;
 }
        /// <summary>
        /// calculates the inverse matrix of a source matrix
        /// </summary>
        /// <param name="m">to calculate inverse matrix from</param>
        /// <returns>inverse matrix</returns>
        public static Matrix4 Invert(Matrix4 m)
        {
            // not that efficient at the moment - however, who cares?
            //Matrix4 inverse = Matrix4.Adjoint(m) / m.Det();

            // Hmm perhaps I do care ;-) This is about 50% faster
            Matrix4 inverse = Matrix4.Zero;
            inverse.A1 = m.B3 * m.C4 * m.D2 - m.B4 * m.C3 * m.D2 + m.B4 * m.C2 * m.D3 - m.B2 * m.C4 * m.D3 - m.B3 * m.C2 * m.D4 + m.B2 * m.C3 * m.D4;
            inverse.A2 = m.A4 * m.C3 * m.D2 - m.A3 * m.C4 * m.D2 - m.A4 * m.C2 * m.D3 + m.A2 * m.C4 * m.D3 + m.A3 * m.C2 * m.D4 - m.A2 * m.C3 * m.D4;
            inverse.A3 = m.A3 * m.B4 * m.D2 - m.A4 * m.B3 * m.D2 + m.A4 * m.B2 * m.D3 - m.A2 * m.B4 * m.D3 - m.A3 * m.B2 * m.D4 + m.A2 * m.B3 * m.D4;
            inverse.A4 = m.A4 * m.B3 * m.C2 - m.A3 * m.B4 * m.C2 - m.A4 * m.B2 * m.C3 + m.A2 * m.B4 * m.C3 + m.A3 * m.B2 * m.C4 - m.A2 * m.B3 * m.C4;

            inverse.B1 = m.B4 * m.C3 * m.D1 - m.B3 * m.C4 * m.D1 - m.B4 * m.C1 * m.D3 + m.B1 * m.C4 * m.D3 + m.B3 * m.C1 * m.D4 - m.B1 * m.C3 * m.D4;
            inverse.B2 = m.A3 * m.C4 * m.D1 - m.A4 * m.C3 * m.D1 + m.A4 * m.C1 * m.D3 - m.A1 * m.C4 * m.D3 - m.A3 * m.C1 * m.D4 + m.A1 * m.C3 * m.D4;
            inverse.B3 = m.A4 * m.B3 * m.D1 - m.A3 * m.B4 * m.D1 - m.A4 * m.B1 * m.D3 + m.A1 * m.B4 * m.D3 + m.A3 * m.B1 * m.D4 - m.A1 * m.B3 * m.D4;
            inverse.B4 = m.A3 * m.B4 * m.C1 - m.A4 * m.B3 * m.C1 + m.A4 * m.B1 * m.C3 - m.A1 * m.B4 * m.C3 - m.A3 * m.B1 * m.C4 + m.A1 * m.B3 * m.C4;

            inverse.C1 = m.B2 * m.C4 * m.D1 - m.B4 * m.C2 * m.D1 + m.B4 * m.C1 * m.D2 - m.B1 * m.C4 * m.D2 - m.B2 * m.C1 * m.D4 + m.B1 * m.C2 * m.D4;
            inverse.C2 = m.A4 * m.C2 * m.D1 - m.A2 * m.C4 * m.D1 - m.A4 * m.C1 * m.D2 + m.A1 * m.C4 * m.D2 + m.A2 * m.C1 * m.D4 - m.A1 * m.C2 * m.D4;
            inverse.C3 = m.A2 * m.B4 * m.D1 - m.A4 * m.B2 * m.D1 + m.A4 * m.B1 * m.D2 - m.A1 * m.B4 * m.D2 - m.A2 * m.B1 * m.D4 + m.A1 * m.B2 * m.D4;
            inverse.C4 = m.A4 * m.B2 * m.C1 - m.A2 * m.B4 * m.C1 - m.A4 * m.B1 * m.C2 + m.A1 * m.B4 * m.C2 + m.A2 * m.B1 * m.C4 - m.A1 * m.B2 * m.C4;

            inverse.D1 = m.B3 * m.C2 * m.D1 - m.B2 * m.C3 * m.D1 - m.B3 * m.C1 * m.D2 + m.B1 * m.C3 * m.D2 + m.B2 * m.C1 * m.D3 - m.B1 * m.C2 * m.D3;
            inverse.D2 = m.A2 * m.C3 * m.D1 - m.A3 * m.C2 * m.D1 + m.A3 * m.C1 * m.D2 - m.A1 * m.C3 * m.D2 - m.A2 * m.C1 * m.D3 + m.A1 * m.C2 * m.D3;
            inverse.D3 = m.A3 * m.B2 * m.D1 - m.A2 * m.B3 * m.D1 - m.A3 * m.B1 * m.D2 + m.A1 * m.B3 * m.D2 + m.A2 * m.B1 * m.D3 - m.A1 * m.B2 * m.D3;
            inverse.D4 = m.A2 * m.B3 * m.C1 - m.A3 * m.B2 * m.C1 + m.A3 * m.B1 * m.C2 - m.A1 * m.B3 * m.C2 - m.A2 * m.B1 * m.C3 + m.A1 * m.B2 * m.C3;
            return inverse * (1 / m.Det());
        }
 /// <summary>
 /// Returns an array of matrices.
 /// </summary>
 /// <param name="data">The data stream containing the matrices.</param>
 /// <param name="offset">The offset in the stream to start with.</param>
 /// <param name="count">The number of matrices to load.</param>
 /// <returns>The array of matrices.</returns>
 public static unsafe Matrix4[] From(byte[] data, int offset, int count)
 {
     Matrix4[] ret = new Matrix4[count];
     fixed (byte* p = &data[offset])
     {
         float* floatPtr = (float*)(p);
         for (int i = 0; i < count; i++)
         {
             ret[i] = new Matrix4(
               floatPtr[0], floatPtr[1], floatPtr[2], floatPtr[3],
               floatPtr[4], floatPtr[5], floatPtr[6], floatPtr[7],
               floatPtr[8], floatPtr[9], floatPtr[10], floatPtr[11],
               floatPtr[12], floatPtr[13], floatPtr[14], floatPtr[15]);
             floatPtr += 16;
         }
     }
     return ret;
 }
 /// <summary>
 /// returns the adjoint matrix
 /// </summary>
 /// <param name="source">matrix to calculate adjoint matrix from</param>
 /// <returns></returns>
 public static Matrix4 Adjoint(Matrix4 source)
 {
     Matrix4 result = Matrix4.Zero;
     for (int iRow = 0; iRow < 4; iRow++)
         for (int iCol = 0; iCol < 4; iCol++)
         {
             if (((iCol + iRow) % 2) == 0)
                 result[iCol, iRow] = Matrix4.Minor(source, iRow, iCol).Det();
             else
                 result[iCol, iRow] = -Matrix4.Minor(source, iRow, iCol).Det();
         }
     return result;
 }
 /// <summary>
 /// returns the transposed matrix
 /// </summary>
 /// <param name="matrix">matrix to transpose</param>
 /// <returns>the transposed matrix</returns>
 public static Matrix4 Transpose(Matrix4 matrix)
 {
     Matrix4 m = Matrix4.Zero;
     m.A1 = matrix.A1; m.A2 = matrix.B1; m.A3 = matrix.C1; m.A4 = matrix.D1;
     m.B1 = matrix.A2; m.B2 = matrix.B2; m.B3 = matrix.C2; m.B4 = matrix.D2;
     m.C1 = matrix.A3; m.C2 = matrix.B3; m.C3 = matrix.C3; m.C4 = matrix.D3;
     m.D1 = matrix.A4; m.D2 = matrix.B4; m.D3 = matrix.C4; m.D4 = matrix.D4;
     return m;
 }