// Copyright 2014 The go-gl/mathgl Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // <<.Comment>> // Edit <<.TemplateName>> and run "go generate" to make changes. package mgl32 import ( "bytes" "fmt" "golang.org/x/image/math/f32" "text/tabwriter" ) type Mat2 [4]float32 type Mat2x3 [6]float32 type Mat2x4 [8]float32 type Mat3x2 [6]float32 type Mat3 f32.Mat3 type Mat3x4 [12]float32 type Mat4x2 [8]float32 type Mat4x3 [12]float32 type Mat4 f32.Mat4 func (m Mat2) Mat3() Mat3 { col0, col1 := m.Cols() return Mat3FromCols( col0.Vec3(0), col1.Vec3(0), Vec3{0, 0, 1}, ) } func (m Mat2) Mat4() Mat4 { col0, col1 := m.Cols() return Mat4FromCols( col0.Vec4(0, 0), col1.Vec4(0, 0), Vec4{0, 0, 1, 0}, Vec4{0, 0, 0, 1}, ) } func (m Mat3) Mat2() Mat2 { col0, col1, _ := m.Cols() return Mat2FromCols( col0.Vec2(), col1.Vec2(), ) } func (m Mat3) Mat4() Mat4 { col0, col1, col2 := m.Cols() return Mat4FromCols( col0.Vec4(0), col1.Vec4(0), col2.Vec4(0), Vec4{0, 0, 0, 1}, ) } func (m Mat4) Mat2() Mat2 { col0, col1, _, _ := m.Cols() return Mat2FromCols( col0.Vec2(), col1.Vec2(), ) } func (m Mat4) Mat3() Mat3 { col0, col1, col2, _ := m.Cols() return Mat3FromCols( col0.Vec3(), col1.Vec3(), col2.Vec3(), ) } <> <><> <<$type := typename $m $n>> // Sets a Column within the Matrix, so it mutates the calling matrix. func (m *<<$type>>) SetCol(col int, v <>) { <><>m[col*<<$m>>+<<$i>>]<> = <> } // Sets a Row within the Matrix, so it mutates the calling matrix. func (m *<<$type>>) SetRow(row int, v <>) { <><>m[row+<>]<> = <> } <> // Diag is a basic operation on a square matrix that simply // returns main diagonal (meaning all elements such that row==col). func (m <<$type>>) Diag() <> { return <>{<>m[<>],<>} } <> <> // Ident<<$m>> returns the <<$m>>x<<$n>> identity matrix. // The identity matrix is a square matrix with the value 1 on its // diagonals. The characteristic property of the identity matrix is that // any matrix multiplied by it is itself. (MI = M; IN = N) func Ident<<$m>>() <<$type>> { return <<$type>>{<><>1<>0<>,<>} } <> <> // Diag<<$m>> creates a diagonal matrix from the entries of the input vector. // That is, for each pointer for row==col, vector[row] is the entry. Otherwise it's 0. // // Another way to think about it is that the identity is this function where the every vector element is 1. func Diag<<$m>>(v <>) <<$type>> { var m <<$type>> <><>m[<>]<> = <> return m } <> // <<$type>>FromRows builds a new matrix from row vectors. // The resulting matrix will still be in column major order, but this can be // good for hand-building matrices. func <<$type>>FromRows(<><>row<<$i>><> <>) <<$type>> { return <<$type>>{<>row<<$i.M>>[<<$i.N>>],<>} } // <<$type>>FromCols builds a new matrix from column vectors. func <<$type>>FromCols(<> <>) <<$type>> { return <<$type>>{<>col<<$i.N>>[<<$i.M>>], <>} } // Add performs an element-wise addition of two matrices, this is // equivalent to iterating over every element of m1 and adding the corresponding value of m2. func (m1 <<$type>>) Add(m2 <<$type>>) <<$type>> { return <<$type>>{<< range $i := matiter $m $n>>m1[<<$i>>] + m2[<<$i>>], <>} } // Sub performs an element-wise subtraction of two matrices, this is // equivalent to iterating over every element of m1 and subtracting the corresponding value of m2. func (m1 <<$type>>) Sub(m2 <<$type>>) <<$type>> { return <<$type>>{<< range $i := matiter $m $n>>m1[<<$i>>] - m2[<<$i>>], <>} } // Mul performs a scalar multiplcation of the matrix. This is equivalent to iterating // over every element of the matrix and multiply it by c. func (m1 <<$type>>) Mul(c float32) <<$type>> { return <<$type>>{<< range $i := matiter $m $n>>m1[<<$i>>] * c, <>} } <> // Mul<<$n>><>x<<$o>><> performs a "matrix product" between this matrix // and another of the given dimension. For any two matrices of dimensionality // MxN and NxO, the result will be MxO. For instance, Mat4 multiplied using // Mul4x2 will result in a Mat4x2. func (m1 <<$type>>) Mul<<$n>><>x<<$o>><>(m2 <>) <> { return <>{<> <><>m1[<>]*m2[<>]<>,<> } } <> // Transpose produces the transpose of this matrix. For any MxN matrix // the transpose is an NxM matrix with the rows swapped with the columns. For instance // the transpose of the Mat3x2 is a Mat2x3 like so: // // [[a b]] [[a c e]] // [[c d]] = [[b d f]] // [[e f]] func (m1 <<$type>>) Transpose() <> { return <>{<>m1[<>], <>} } <> // The determinant of a matrix is a measure of a square matrix's // singularity and invertability, among other things. In this library, the // determinant is hard coded based on pre-computed cofactor expansion, and uses // no loops. Of course, the addition and multiplication must still be done. func (m <<$type>>) Det() float32 { <> return m[0]*m[3] - m[1]*m[2] <> return m[0]*m[4]*m[8] + m[3]*m[7]*m[2] + m[6]*m[1]*m[5] - m[6]*m[4]*m[2] - m[3]*m[1]*m[8] - m[0]*m[7]*m[5] <> return m[0]*m[5]*m[10]*m[15] - m[0]*m[5]*m[11]*m[14] - m[0]*m[6]*m[9]*m[15] + m[0]*m[6]*m[11]*m[13] + m[0]*m[7]*m[9]*m[14] - m[0]*m[7]*m[10]*m[13] - m[1]*m[4]*m[10]*m[15] + m[1]*m[4]*m[11]*m[14] + m[1]*m[6]*m[8]*m[15] - m[1]*m[6]*m[11]*m[12] - m[1]*m[7]*m[8]*m[14] + m[1]*m[7]*m[10]*m[12] + m[2]*m[4]*m[9]*m[15] - m[2]*m[4]*m[11]*m[13] - m[2]*m[5]*m[8]*m[15] + m[2]*m[5]*m[11]*m[12] + m[2]*m[7]*m[8]*m[13] - m[2]*m[7]*m[9]*m[12] - m[3]*m[4]*m[9]*m[14] + m[3]*m[4]*m[10]*m[13] + m[3]*m[5]*m[8]*m[14] - m[3]*m[5]*m[10]*m[12] - m[3]*m[6]*m[8]*m[13] + m[3]*m[6]*m[9]*m[12] <> } <> <> // Inv computes the inverse of a square matrix. An inverse is a square matrix such that when multiplied by the // original, yields the identity. // // M_inv * M = M * M_inv = I // // In this library, the math is precomputed, and uses no loops, though the multiplications, additions, determinant calculation, and scaling // are still done. This can still be (relatively) expensive for a 4x4. // // This function checks the determinant to see if the matrix is invertible. // If the determinant is 0.0, this function returns the zero matrix. However, due to floating point errors, it is // entirely plausible to get a false positive or negative. // In the future, an alternate function may be written which takes in a pre-computed determinant. func (m <<$type>>) Inv() <<$type>> { det := m.Det() if FloatEqual(det, float32(0.0)) { return <<$type>>{} } <> retMat := Mat2{m[3], -m[1], -m[2], m[0]} <> retMat := Mat3{ m[4]*m[8] - m[5]*m[7], m[2]*m[7] - m[1]*m[8], m[1]*m[5] - m[2]*m[4], m[5]*m[6] - m[3]*m[8], m[0]*m[8] - m[2]*m[6], m[2]*m[3] - m[0]*m[5], m[3]*m[7] - m[4]*m[6], m[1]*m[6] - m[0]*m[7], m[0]*m[4] - m[1]*m[3], } <> retMat := Mat4{ -m[7]*m[10]*m[13] + m[6]*m[11]*m[13] + m[7]*m[9]*m[14] - m[5]*m[11]*m[14] - m[6]*m[9]*m[15] + m[5]*m[10]*m[15], m[3]*m[10]*m[13] - m[2]*m[11]*m[13] - m[3]*m[9]*m[14] + m[1]*m[11]*m[14] + m[2]*m[9]*m[15] - m[1]*m[10]*m[15], -m[3]*m[6]*m[13] + m[2]*m[7]*m[13] + m[3]*m[5]*m[14] - m[1]*m[7]*m[14] - m[2]*m[5]*m[15] + m[1]*m[6]*m[15], m[3]*m[6]*m[9] - m[2]*m[7]*m[9] - m[3]*m[5]*m[10] + m[1]*m[7]*m[10] + m[2]*m[5]*m[11] - m[1]*m[6]*m[11], m[7]*m[10]*m[12] - m[6]*m[11]*m[12] - m[7]*m[8]*m[14] + m[4]*m[11]*m[14] + m[6]*m[8]*m[15] - m[4]*m[10]*m[15], -m[3]*m[10]*m[12] + m[2]*m[11]*m[12] + m[3]*m[8]*m[14] - m[0]*m[11]*m[14] - m[2]*m[8]*m[15] + m[0]*m[10]*m[15], m[3]*m[6]*m[12] - m[2]*m[7]*m[12] - m[3]*m[4]*m[14] + m[0]*m[7]*m[14] + m[2]*m[4]*m[15] - m[0]*m[6]*m[15], -m[3]*m[6]*m[8] + m[2]*m[7]*m[8] + m[3]*m[4]*m[10] - m[0]*m[7]*m[10] - m[2]*m[4]*m[11] + m[0]*m[6]*m[11], -m[7]*m[9]*m[12] + m[5]*m[11]*m[12] + m[7]*m[8]*m[13] - m[4]*m[11]*m[13] - m[5]*m[8]*m[15] + m[4]*m[9]*m[15], m[3]*m[9]*m[12] - m[1]*m[11]*m[12] - m[3]*m[8]*m[13] + m[0]*m[11]*m[13] + m[1]*m[8]*m[15] - m[0]*m[9]*m[15], -m[3]*m[5]*m[12] + m[1]*m[7]*m[12] + m[3]*m[4]*m[13] - m[0]*m[7]*m[13] - m[1]*m[4]*m[15] + m[0]*m[5]*m[15], m[3]*m[5]*m[8] - m[1]*m[7]*m[8] - m[3]*m[4]*m[9] + m[0]*m[7]*m[9] + m[1]*m[4]*m[11] - m[0]*m[5]*m[11], m[6]*m[9]*m[12] - m[5]*m[10]*m[12] - m[6]*m[8]*m[13] + m[4]*m[10]*m[13] + m[5]*m[8]*m[14] - m[4]*m[9]*m[14], -m[2]*m[9]*m[12] + m[1]*m[10]*m[12] + m[2]*m[8]*m[13] - m[0]*m[10]*m[13] - m[1]*m[8]*m[14] + m[0]*m[9]*m[14], m[2]*m[5]*m[12] - m[1]*m[6]*m[12] - m[2]*m[4]*m[13] + m[0]*m[6]*m[13] + m[1]*m[4]*m[14] - m[0]*m[5]*m[14], -m[2]*m[5]*m[8] + m[1]*m[6]*m[8] + m[2]*m[4]*m[9] - m[0]*m[6]*m[9] - m[1]*m[4]*m[10] + m[0]*m[5]*m[10], } <> return retMat.Mul(1 / det) } <> // ApproxEqual performs an element-wise approximate equality test between two matrices, // as if FloatEqual had been used. func (m1 <<$type>>) ApproxEqual(m2 <<$type>>) bool { for i := range m1 { if !FloatEqual(m1[i], m2[i]) { return false } } return true } // ApproxEqualThreshold performs an element-wise approximate equality test between two matrices // with a given epsilon threshold, as if FloatEqualThreshold had been used. func (m1 <<$type>>) ApproxEqualThreshold(m2 <<$type>>, threshold float32) bool { for i := range m1 { if !FloatEqualThreshold(m1[i], m2[i], threshold) { return false } } return true } // ApproxEqualFunc performs an element-wise approximate equality test between two matrices // with a given equality functions, intended to be used with FloatEqualFunc; although and comparison // function may be used in practice. func (m1 <<$type>>) ApproxFuncEqual(m2 <<$type>>, eq func(float32, float32) bool) bool { for i := range m1 { if !eq(m1[i], m2[i]) { return false } } return true } // At returns the matrix element at the given row and column. // This is equivalent to mat[col * numRow + row] where numRow is constant // (E.G. for a Mat3x2 it's equal to 3) // // This method is garbage-in garbage-out. For instance, on a Mat4 asking for // At(5,0) will work just like At(1,1). Or it may panic if it's out of bounds. func (m <<$type>>) At(row, col int) float32 { return m[col*<<$m>>+row] } // Set sets the corresponding matrix element at the given row and column. // This has a pointer receiver because it mutates the matrix. // // This method is garbage-in garbage-out. For instance, on a Mat4 asking for // Set(5,0,val) will work just like Set(1,1,val). Or it may panic if it's out of bounds. func (m *<<$type>>) Set(row, col int, value float32) { m[col*<<$m>>+row] = value } // Index returns the index of the given row and column, to be used with direct // access. E.G. Index(0,0) = 0. // // This is a garbage-in garbage-out method. For instance, on a Mat4 asking for the index of // (5,0) will work the same as asking for (1,1). Or it may give you a value that will cause // a panic if you try to access the array with it if it's truly out of bounds. func (m <<$type>>) Index(row, col int) int { return col*<<$m>> + row } // Row returns a vector representing the corresponding row (starting at row 0). // This package makes no distinction between row and column vectors, so it // will be a normal VecM for a MxN matrix. func (m <<$type>>) Row(row int) <> { return <>{<>m[row+<>],<>} } // Rows decomposes a matrix into its corresponding row vectors. // This is equivalent to calling mat.Row for each row. func (m <<$type>>) Rows() (<> <>) { return <> } // Col returns a vector representing the corresponding column (starting at col 0). // This package makes no distinction between row and column vectors, so it // will be a normal VecN for a MxN matrix. func (m <<$type>>) Col(col int) <> { return <>{<>m[col*<<$m>>+<<$i>>],<>} } // Cols decomposes a matrix into its corresponding column vectors. // This is equivalent to calling mat.Col for each column. func (m <<$type>>) Cols() (<> <>) { return <> } <> // Trace is a basic operation on a square matrix that simply // sums up all elements on the main diagonal (meaning all elements such that row==col). func (m <<$type>>) Trace() float32 { return <><> m[<>]<> } <> // Abs returns the element-wise absolute value of this matrix func (m <<$type>>) Abs() <<$type>> { return <<$type>>{<>} } // Pretty prints the matrix func (m <<$type>>) String() string { buf := new(bytes.Buffer) w := tabwriter.NewWriter(buf, 4, 4, 1, ' ', tabwriter.AlignRight) for i := 0; i < <<$m>>; i++ { for _, col := range m.Row(i) { fmt.Fprintf(w, "%f\t", col) } fmt.Fprintln(w, "") } w.Flush() return buf.String() } <><> <>