diff options
Diffstat (limited to 'include/jau/math/mat4f.hpp')
-rw-r--r-- | include/jau/math/mat4f.hpp | 1119 |
1 files changed, 503 insertions, 616 deletions
diff --git a/include/jau/math/mat4f.hpp b/include/jau/math/mat4f.hpp index e80e8d3..f3c51f1 100644 --- a/include/jau/math/mat4f.hpp +++ b/include/jau/math/mat4f.hpp @@ -27,9 +27,11 @@ #include <cmath> #include <cstdarg> #include <cstdint> +#include <cassert> #include <limits> #include <string> #include <vector> +#include <initializer_list> #include <iostream> #include <jau/float_math.hpp> @@ -50,10 +52,12 @@ namespace jau::math { * @{ */ + template<typename Value_type, + std::enable_if_t<std::is_floating_point_v<Value_type>, bool>> class Quaternion; // forward /** - * Basic 4x4 float matrix implementation using fields for intensive use-cases (host operations). + * Basic 4x4 value_type matrix implementation using fields for intensive use-cases (host operations). * <p> * Implementation covers {@link FloatUtil} matrix functionality, exposed in an object oriented manner. * </p> @@ -102,111 +106,86 @@ namespace jau::math { * </ul> * </p> */ -class Mat4f { - private: - float m00, m10, m20, m30; - float m01, m11, m21, m31; - float m02, m12, m22, m32; - float m03, m13, m23, m33; - - friend geom::Frustum; - friend Quaternion; - - class Stack { - private: - int growSize; - std::vector<float> buffer; - - public: - /** - * @param initialSize initial size - * @param growSize grow size if {@link #position()} is reached, maybe <code>0</code> - */ - Stack(int initialSize, int growSize_) - : growSize(growSize_), buffer(initialSize) {} - - size_t growIfNecessary(int length) { - const size_t p = buffer.size(); - const size_t nsz = buffer.size() + length; - if( nsz > buffer.capacity() ) { - buffer.reserve(buffer.size() + std::max(length, growSize)); - } - buffer.resize(nsz); - return p; - } - - Mat4f& push(Mat4f& src) { - size_t p = growIfNecessary(16); - src.get(buffer, p); - return src; - } - - Mat4f& pop(Mat4f& dest) { - size_t sz = buffer.size(); - if( sz < 16 ) { - throw jau::IndexOutOfBoundsException(0, sz, E_FILE_LINE); - } - size_t p = sz - 16; - dest.load(buffer, p); - buffer.resize(p); - return dest; - } - }; - - Stack stack; // start w/ zero size, growSize is half GL-min size (32) + +template<typename Value_type, + std::enable_if_t<std::is_floating_point_v<Value_type>, bool> = true> +class alignas(Value_type) Matrix4 { + public: + typedef Value_type value_type; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef value_type* iterator; + typedef const value_type* const_iterator; + + typedef Vector4F<value_type, std::is_floating_point_v<Value_type>> Vec4; + + constexpr static const value_type zero = value_type(0); + constexpr static const value_type one = value_type(1); + constexpr static const value_type two = value_type(2); + constexpr static const value_type half = one/two; + + private: + // RC + value_type m00, m10, m20, m30; // column 0 + value_type m01, m11, m21, m31; // column 1 + value_type m02, m12, m22, m32; // column 2 + value_type m03, m13, m23, m33; // column 3 + + friend geom::Frustum; + friend Quaternion<value_type, std::is_floating_point_v<Value_type>>; public: /** * Creates a new identity matrix. */ - Mat4f() noexcept - : m00(1.0f), m10(0.0f), m20(0.0f), m30(0.0f), - m01(0.0f), m11(1.0f), m21(0.0f), m31(0.0f), - m02(0.0f), m12(0.0f), m22(1.0f), m32(0.0f), - m03(0.0f), m13(0.0f), m23(0.0f), m33(1.0f), - stack(0, 16*16) + constexpr Matrix4() noexcept + : m00(one), m10(zero), m20(zero), m30(zero), + m01(zero), m11(one), m21(zero), m31(zero), + m02(zero), m12(zero), m22(one), m32(zero), + m03(zero), m13(zero), m23(zero), m33(one) { } /** - * Creates a new matrix based on given float[4*4] column major order. + * Creates a new matrix based on given value_type[4*4] column major order. * @param m 4x4 matrix in column-major order */ - Mat4f(const float m[]) noexcept - : stack(0, 16*16) - { - load(m); - } + constexpr Matrix4(const_iterator m) noexcept + : m00(m[0+0*4]), m10(m[1+0*4]), m20(m[2+0*4]), m30(m[3+0*4]), // column 0 + m01(m[0+1*4]), m11(m[1+1*4]), m21(m[2+1*4]), m31(m[3+1*4]), // column 1 + m02(m[0+2*4]), m12(m[1+2*4]), m22(m[2+2*4]), m32(m[3+2*4]), // column 2 + m03(m[0+3*4]), m13(m[1+3*4]), m23(m[2+3*4]), m33(m[3+3*4]) // column 3 + {} /** - * Creates a new matrix based on given std::vector 4x4 column major order. - * @param m 4x4 matrix std::vector in column-major order starting at {@code src_off} - * @param m_off offset for matrix {@code src} + * Creates a new matrix based on given value_type initializer list in column major order. + * @param m source initializer list value_type data to be copied into this new instance, implied size must be >= 16 */ - Mat4f(const std::vector<float>& m, const size_t m_off) noexcept - : stack(0, 16*16) + constexpr Matrix4(std::initializer_list<value_type> m) noexcept + : m00(m.begin()[0+0*4]), m10(m.begin()[1+0*4]), m20(m.begin()[2+0*4]), m30(m.begin()[3+0*4]), // column 0 + m01(m.begin()[0+1*4]), m11(m.begin()[1+1*4]), m21(m.begin()[2+1*4]), m31(m.begin()[3+1*4]), // column 1 + m02(m.begin()[0+2*4]), m12(m.begin()[1+2*4]), m22(m.begin()[2+2*4]), m32(m.begin()[3+2*4]), // column 2 + m03(m.begin()[0+3*4]), m13(m.begin()[1+3*4]), m23(m.begin()[2+3*4]), m33(m.begin()[3+3*4]) // column 3 { - load(m, m_off); + assert(m.size() >= 16 ); } /** * Creates a new matrix copying the values of the given {@code src} matrix. - * - * The stack is not copied. */ - Mat4f(const Mat4f& o) noexcept + constexpr Matrix4(const Matrix4& o) noexcept : m00(o.m00), m10(o.m10), m20(o.m20), m30(o.m30), m01(o.m01), m11(o.m11), m21(o.m21), m31(o.m31), m02(o.m02), m12(o.m12), m22(o.m22), m32(o.m32), - m03(o.m03), m13(o.m13), m23(o.m23), m33(o.m33), - stack(0, 16*16) { } + m03(o.m03), m13(o.m13), m23(o.m23), m33(o.m33) + { } /** * Copy assignment using the the values of the given {@code src} matrix. - * - * The stack is not copied. */ - Mat4f& operator=(const Mat4f& o) noexcept { + constexpr Matrix4& operator=(const Matrix4& o) noexcept { m00 = o.m00; m10 = o.m10; m20 = o.m20; m30 = o.m30; m01 = o.m01; m11 = o.m11; m21 = o.m21; m31 = o.m31; m02 = o.m02; m12 = o.m12; m22 = o.m22; m32 = o.m32; @@ -214,7 +193,7 @@ class Mat4f { return *this; } - constexpr bool equals(const Mat4f& o, const float epsilon=std::numeric_limits<float>::epsilon()) const noexcept { + constexpr bool equals(const Matrix4& o, const value_type epsilon=std::numeric_limits<value_type>::epsilon()) const noexcept { if( this == &o ) { return true; } else { @@ -236,7 +215,7 @@ class Mat4f { jau::equals(m33, o.m33, epsilon); } } - constexpr bool operator==(const Mat4f& rhs) const noexcept { + constexpr bool operator==(const Matrix4& rhs) const noexcept { return equals(rhs); } @@ -245,38 +224,22 @@ class Mat4f { // /** - * Returns writable reference to the {@code i}th component of the given column-major order matrix, 0 <= i < 16 w/o boundary check + * Returns writable reference to the {@code i}th component of this column-major order matrix, 0 <= i < 16 w/o boundary check */ - float& operator[](size_t i) noexcept { - return reinterpret_cast<float*>(this)[i]; + constexpr reference operator[](size_t i) noexcept { + assert( i < 16 ); + return (&m00)[i]; } - /** Sets the {@code i}th component with float {@code v} 0 <= i < 16 w/ boundary check*/ - void set(const jau::nsize_t i, const float v) { - switch (i) { - case 0+4*0: m00 = v; break; - case 1+4*0: m10 = v; break; - case 2+4*0: m20 = v; break; - case 3+4*0: m30 = v; break; - - case 0+4*1: m01 = v; break; - case 1+4*1: m11 = v; break; - case 2+4*1: m21 = v; break; - case 3+4*1: m31 = v; break; - - case 0+4*2: m02 = v; break; - case 1+4*2: m12 = v; break; - case 2+4*2: m22 = v; break; - case 3+4*2: m32 = v; break; - - case 0+4*3: m03 = v; break; - case 1+4*3: m13 = v; break; - case 2+4*3: m23 = v; break; - case 3+4*3: m33 = v; break; - default: throw jau::IndexOutOfBoundsException(i, 16, E_FILE_LINE); - } + /** Sets the {@code i}th component of this column-major order matrix with value_type {@code v}, 0 <= i < 16 w/o boundary check*/ + constexpr void set(const jau::nsize_t i, const value_type v) noexcept { + assert( i < 16 ); + (&m00)[i] = v; } + explicit operator pointer() noexcept { return &m00; } + constexpr iterator begin() noexcept { return &m00; } + /** * Set this matrix to identity. * <pre> @@ -288,12 +251,12 @@ class Mat4f { * </pre> * @return this matrix for chaining */ - Mat4f& loadIdentity() noexcept { - m00 = m11 = m22 = m33 = 1.0f; + constexpr Matrix4& loadIdentity() noexcept { + m00 = m11 = m22 = m33 = one; m01 = m02 = m03 = m10 = m12 = m13 = m20 = m21 = m23 = - m30 = m31 = m32 = 0.0f; + m30 = m31 = m32 = zero; return *this; } @@ -302,7 +265,7 @@ class Mat4f { * @param src the source values * @return this matrix for chaining */ - Mat4f& load(const Mat4f& src) noexcept { + constexpr Matrix4& load(const Matrix4& src) noexcept { m00 = src.m00; m10 = src.m10; m20 = src.m20; m30 = src.m30; m01 = src.m01; m11 = src.m11; m21 = src.m21; m31 = src.m31; m02 = src.m02; m12 = src.m12; m22 = src.m22; m32 = src.m32; @@ -312,10 +275,11 @@ class Mat4f { /** * Load the values of the given matrix {@code src} to this matrix w/o boundary check. - * @param src 4x4 matrix float[16] in column-major order + * @param src 4x4 matrix value_type[16] in column-major order * @return this matrix for chaining */ - Mat4f& load(const float src[]) noexcept { + constexpr Matrix4& load(const_iterator src) noexcept { + // RC m00 = src[0+0*4]; // column 0 m10 = src[1+0*4]; m20 = src[2+0*4]; @@ -335,35 +299,6 @@ class Mat4f { return *this; } - /** - * Load the values of the given matrix {@code src} to this matrix w/ boundary check. - * @param src 4x4 matrix std::vector in column-major order starting at {@code src_off} - * @param src_off offset for matrix {@code src} - * @return this matrix for chaining - */ - Mat4f& load(const std::vector<float>& src, const size_t src_off) { - if( src.size() < src_off+16 || src_off > std::numeric_limits<size_t>::max() - 15) { - throw jau::IndexOutOfBoundsException(src_off, 16, E_FILE_LINE); - } - m00 = src[src_off+0+0*4]; - m10 = src[src_off+1+0*4]; - m20 = src[src_off+2+0*4]; - m30 = src[src_off+3+0*4]; - m01 = src[src_off+0+1*4]; - m11 = src[src_off+1+1*4]; - m21 = src[src_off+2+1*4]; - m31 = src[src_off+3+1*4]; - m02 = src[src_off+0+2*4]; - m12 = src[src_off+1+2*4]; - m22 = src[src_off+2+2*4]; - m32 = src[src_off+3+2*4]; - m03 = src[src_off+0+3*4]; - m13 = src[src_off+1+3*4]; - m23 = src[src_off+2+3*4]; - m33 = src[src_off+3+3*4]; - return *this; - } - // // Read out Matrix via get(..) // @@ -371,82 +306,57 @@ class Mat4f { /** * Returns read-only {@code i}th component of the given column-major order matrix, 0 <= i < 16 w/o boundary check */ - float operator[](size_t i) const noexcept { - return reinterpret_cast<const float*>(this)[i]; + constexpr value_type operator[](size_t i) const noexcept { + assert( i < 16 ); + return (&m00)[i]; } - /** Returns the {@code i}th component of the given column-major order matrix, 0 <= i < 16, w/ boundary check */ - float get(const jau::nsize_t i) const { - switch (i) { - case 0+4*0: return m00; - case 1+4*0: return m10; - case 2+4*0: return m20; - case 3+4*0: return m30; - - case 0+4*1: return m01; - case 1+4*1: return m11; - case 2+4*1: return m21; - case 3+4*1: return m31; - - case 0+4*2: return m02; - case 1+4*2: return m12; - case 2+4*2: return m22; - case 3+4*2: return m32; - - case 0+4*3: return m03; - case 1+4*3: return m13; - case 2+4*3: return m23; - case 3+4*3: return m33; - - default: throw jau::IndexOutOfBoundsException(i, 16, E_FILE_LINE); - } + /** Returns the {@code i}th component of the given column-major order matrix, 0 <= i < 16, w/o boundary check */ + constexpr value_type get(const jau::nsize_t i) const noexcept { + assert( i < 16 ); + return (&m00)[i]; } + explicit operator const_pointer() const noexcept { return &m00; } + constexpr const_iterator cbegin() const noexcept { return &m00; } + /** - * Get the named column of the given column-major matrix to v_out w/ boundary check. + * Get the named column of the given column-major matrix to v_out w/o boundary check. * @param column named column to copy * @param v_out the column-vector storage * @return given result vector <i>v_out</i> for chaining */ - Vec4f& getColumn(const jau::nsize_t column, Vec4f& v_out) const { - if( column > 3 ) { - throw jau::IndexOutOfBoundsException(3+column*4, 16, E_FILE_LINE); - } - v_out.set( get(0+column*4), - get(1+column*4), - get(2+column*4), - get(3+column*4) ); - return v_out; + constexpr Vec4& getColumn(const jau::nsize_t column, Vec4& v_out) const noexcept { + assert( column < 4 ); + return v_out.set( get(0+column*4), + get(1+column*4), + get(2+column*4), + get(3+column*4) ); } + /** - * Get the named column of the given column-major matrix to v_out w/ boundary check. + * Get the named column of the given column-major matrix to v_out w/o boundary check. * @param column named column to copy * @return result vector holding the requested column */ - Vec4f getColumn(const jau::nsize_t column) const { - if( column > 3 ) { - throw jau::IndexOutOfBoundsException(2+column*4, 16, E_FILE_LINE); - } - return Vec4f( get(0+column*4), - get(1+column*4), - get(2+column*4), - get(3+column*4) ); + constexpr Vec4 getColumn(const jau::nsize_t column) const noexcept { + assert( column < 4 ); + return Vec4( get(0+column*4), + get(1+column*4), + get(2+column*4), + get(3+column*4) ); } /** - * Get the named column of the given column-major matrix to v_out w/ boundary check. + * Get the named column of the given column-major matrix to v_out w/o boundary check. * @param column named column to copy * @param v_out the column-vector storage * @return given result vector <i>v_out</i> for chaining */ - Vec3f& getColumn(const jau::nsize_t column, Vec3f& v_out) const { - if( column > 3 ) { - throw jau::IndexOutOfBoundsException(2+column*4, 16, E_FILE_LINE); - } - v_out.set( get(0+column*4), - get(1+column*4), - get(2+column*4) ); - return v_out; + constexpr Vec3f& getColumn(const jau::nsize_t column, Vec3f& v_out) const noexcept { + return v_out.set( get(0+column*4), + get(1+column*4), + get(2+column*4) ); } /** @@ -455,84 +365,44 @@ class Mat4f { * @param v_out the row-vector storage * @return given result vector <i>v_out</i> for chaining */ - Vec4f& getRow(const jau::nsize_t row, Vec4f& v_out) const { - if( row > 3 ) { - throw jau::IndexOutOfBoundsException(row+3*4, 16, E_FILE_LINE); - } - v_out.set( get(row+0*4), - get(row+1*4), - get(row+2*4), - get(row+3*4) ); - return v_out; + constexpr Vec4& getRow(const jau::nsize_t row, Vec4& v_out) const noexcept { + return v_out.set( get(row+0*4), + get(row+1*4), + get(row+2*4), + get(row+3*4) ); } /** - * Get the named column of the given column-major matrix to v_out w/ boundary check. + * Get the named column of the given column-major matrix to v_out w/o boundary check. * @param row named row to copy * @return result vector holding the requested row */ - Vec4f getRow(const jau::nsize_t row) const { - if( row > 3 ) { - throw jau::IndexOutOfBoundsException(row+3*4, 16, E_FILE_LINE); - } - return Vec4f( get(row+0*4), - get(row+1*4), - get(row+2*4), - get(row+3*4) ); + constexpr Vec4 getRow(const jau::nsize_t row) const noexcept { + return Vec4( get(row+0*4), + get(row+1*4), + get(row+2*4), + get(row+3*4) ); } /** - * Get the named row of the given column-major matrix to v_out w/ boundary check. + * Get the named row of the given column-major matrix to v_out w/o boundary check. * @param row named row to copy - * @param v_out the row-vector storage + * @param v_out the row-vector assert( i < 16 )e * @return given result vector <i>v_out</i> for chaining */ - Vec3f& getRow(const jau::nsize_t row, Vec3f& v_out) const { - if( row > 3 ) { - throw jau::IndexOutOfBoundsException(row+2*4, 16, E_FILE_LINE); - } - v_out.set( get(row+0*4), - get(row+1*4), - get(row+2*4) ); - return v_out; + constexpr Vec3f& getRow(const jau::nsize_t row, Vec3f& v_out) const noexcept { + assert( row <= 2 ); + return v_out.set( get(row+0*4), + get(row+1*4), + get(row+2*4) ); } /** - * Get this matrix into the given float[16] array at {@code dst_off} in column major order w/ boundary check. + * Get this matrix into the given value_type[16] array in column major order w/o boundary check. * - * @param dst float[16] array storage in column major order - * @param dst_off offset + * @param dst value_type[16] array storage in column major order * @return {@code dst} for chaining */ - float* get(float* dst, size_t dst_off) const { - if( dst_off > std::numeric_limits<size_t>::max() - 15) { - throw jau::IndexOutOfBoundsException(dst_off, 16, E_FILE_LINE); - } - dst[dst_off++] = m00; - dst[dst_off++] = m10; - dst[dst_off++] = m20; - dst[dst_off++] = m30; - dst[dst_off++] = m01; - dst[dst_off++] = m11; - dst[dst_off++] = m21; - dst[dst_off++] = m31; - dst[dst_off++] = m02; - dst[dst_off++] = m12; - dst[dst_off++] = m22; - dst[dst_off++] = m32; - dst[dst_off++] = m03; - dst[dst_off++] = m13; - dst[dst_off++] = m23; - dst[dst_off++] = m33; - return dst; - } - - /** - * Get this matrix into the given float[16] array in column major order w/o boundary check. - * - * @param dst float[16] array storage in column major order - * @return {@code dst} for chaining - */ - float* get(float* dst) const noexcept { + constexpr iterator get(iterator dst) const noexcept { dst[0+0*4] = m00; dst[1+0*4] = m10; dst[2+0*4] = m20; @@ -553,16 +423,14 @@ class Mat4f { } /** - * Get this matrix into the given {@link FloatBuffer} in column major order w/ boundary check. + * Get this matrix into the given {@link FloatBuffer} in column major order. * * @param dst 4x4 matrix std::vector in column-major order starting at {@code dst_off} * @param dst_off offset for matrix {@code dst} * @return {@code dst} for chaining */ - std::vector<float>& get(std::vector<float>& dst, size_t dst_off) const { - if( dst.size() < dst_off+16 || dst_off > std::numeric_limits<size_t>::max() - 15) { - throw jau::IndexOutOfBoundsException(dst_off, 16, E_FILE_LINE); - } + constexpr std::vector<value_type>& get(std::vector<value_type>& dst, size_t dst_off) const noexcept { + assert( dst.size() >= dst_off+16 && dst_off <= std::numeric_limits<size_t>::max() - 15 ); dst[dst_off++] = m00; dst[dst_off++] = m10; dst[dst_off++] = m20; @@ -590,8 +458,8 @@ class Mat4f { * Returns the determinant of this matrix * @return the matrix determinant */ - float determinant() const noexcept { - float ret = 0; + value_type determinant() const noexcept { + value_type ret = 0; ret += m00 * ( + m11*(m22*m33 - m23*m32) - m12*(m21*m33 - m23*m31) + m13*(m21*m32 - m22*m31)); ret -= m01 * ( + m10*(m22*m33 - m23*m32) - m12*(m20*m33 - m23*m30) + m13*(m20*m32 - m22*m30)); ret += m02 * ( + m10*(m21*m33 - m23*m31) - m11*(m20*m33 - m23*m30) + m13*(m20*m31 - m21*m30)); @@ -604,8 +472,8 @@ class Mat4f { * * @return this matrix for chaining */ - Mat4f& transpose() noexcept { - float tmp; + Matrix4& transpose() noexcept { + value_type tmp; tmp = m10; m10 = m01; @@ -640,7 +508,7 @@ class Mat4f { * @param src source 4x4 matrix * @return this matrix (result) for chaining */ - Mat4f& transpose(const Mat4f& src) noexcept { + Matrix4& transpose(const Matrix4& src) noexcept { if( &src == this ) { return transpose(); } @@ -671,56 +539,56 @@ class Mat4f { * @return false if this matrix is singular and inversion not possible, otherwise true */ bool invert() noexcept { - const float amax = absMax(); - if( 0.0f == amax ) { + const value_type amax = absMax(); + if( zero == amax ) { return false; } - const float scale = 1.0f/amax; - const float a00 = m00*scale; - const float a10 = m10*scale; - const float a20 = m20*scale; - const float a30 = m30*scale; - - const float a01 = m01*scale; - const float a11 = m11*scale; - const float a21 = m21*scale; - const float a31 = m31*scale; - - const float a02 = m02*scale; - const float a12 = m12*scale; - const float a22 = m22*scale; - const float a32 = m32*scale; - - const float a03 = m03*scale; - const float a13 = m13*scale; - const float a23 = m23*scale; - const float a33 = m33*scale; - - const float b00 = + a11*(a22*a33 - a23*a32) - a12*(a21*a33 - a23*a31) + a13*(a21*a32 - a22*a31); - const float b01 = -( + a10*(a22*a33 - a23*a32) - a12*(a20*a33 - a23*a30) + a13*(a20*a32 - a22*a30)); - const float b02 = + a10*(a21*a33 - a23*a31) - a11*(a20*a33 - a23*a30) + a13*(a20*a31 - a21*a30); - const float b03 = -( + a10*(a21*a32 - a22*a31) - a11*(a20*a32 - a22*a30) + a12*(a20*a31 - a21*a30)); - - const float b10 = -( + a01*(a22*a33 - a23*a32) - a02*(a21*a33 - a23*a31) + a03*(a21*a32 - a22*a31)); - const float b11 = + a00*(a22*a33 - a23*a32) - a02*(a20*a33 - a23*a30) + a03*(a20*a32 - a22*a30); - const float b12 = -( + a00*(a21*a33 - a23*a31) - a01*(a20*a33 - a23*a30) + a03*(a20*a31 - a21*a30)); - const float b13 = + a00*(a21*a32 - a22*a31) - a01*(a20*a32 - a22*a30) + a02*(a20*a31 - a21*a30); - - const float b20 = + a01*(a12*a33 - a13*a32) - a02*(a11*a33 - a13*a31) + a03*(a11*a32 - a12*a31); - const float b21 = -( + a00*(a12*a33 - a13*a32) - a02*(a10*a33 - a13*a30) + a03*(a10*a32 - a12*a30)); - const float b22 = + a00*(a11*a33 - a13*a31) - a01*(a10*a33 - a13*a30) + a03*(a10*a31 - a11*a30); - const float b23 = -( + a00*(a11*a32 - a12*a31) - a01*(a10*a32 - a12*a30) + a02*(a10*a31 - a11*a30)); - - const float b30 = -( + a01*(a12*a23 - a13*a22) - a02*(a11*a23 - a13*a21) + a03*(a11*a22 - a12*a21)); - const float b31 = + a00*(a12*a23 - a13*a22) - a02*(a10*a23 - a13*a20) + a03*(a10*a22 - a12*a20); - const float b32 = -( + a00*(a11*a23 - a13*a21) - a01*(a10*a23 - a13*a20) + a03*(a10*a21 - a11*a20)); - const float b33 = + a00*(a11*a22 - a12*a21) - a01*(a10*a22 - a12*a20) + a02*(a10*a21 - a11*a20); - - const float det = (a00*b00 + a01*b01 + a02*b02 + a03*b03) / scale; + const value_type scale = one/amax; + const value_type a00 = m00*scale; + const value_type a10 = m10*scale; + const value_type a20 = m20*scale; + const value_type a30 = m30*scale; + + const value_type a01 = m01*scale; + const value_type a11 = m11*scale; + const value_type a21 = m21*scale; + const value_type a31 = m31*scale; + + const value_type a02 = m02*scale; + const value_type a12 = m12*scale; + const value_type a22 = m22*scale; + const value_type a32 = m32*scale; + + const value_type a03 = m03*scale; + const value_type a13 = m13*scale; + const value_type a23 = m23*scale; + const value_type a33 = m33*scale; + + const value_type b00 = + a11*(a22*a33 - a23*a32) - a12*(a21*a33 - a23*a31) + a13*(a21*a32 - a22*a31); + const value_type b01 = -( + a10*(a22*a33 - a23*a32) - a12*(a20*a33 - a23*a30) + a13*(a20*a32 - a22*a30)); + const value_type b02 = + a10*(a21*a33 - a23*a31) - a11*(a20*a33 - a23*a30) + a13*(a20*a31 - a21*a30); + const value_type b03 = -( + a10*(a21*a32 - a22*a31) - a11*(a20*a32 - a22*a30) + a12*(a20*a31 - a21*a30)); + + const value_type b10 = -( + a01*(a22*a33 - a23*a32) - a02*(a21*a33 - a23*a31) + a03*(a21*a32 - a22*a31)); + const value_type b11 = + a00*(a22*a33 - a23*a32) - a02*(a20*a33 - a23*a30) + a03*(a20*a32 - a22*a30); + const value_type b12 = -( + a00*(a21*a33 - a23*a31) - a01*(a20*a33 - a23*a30) + a03*(a20*a31 - a21*a30)); + const value_type b13 = + a00*(a21*a32 - a22*a31) - a01*(a20*a32 - a22*a30) + a02*(a20*a31 - a21*a30); + + const value_type b20 = + a01*(a12*a33 - a13*a32) - a02*(a11*a33 - a13*a31) + a03*(a11*a32 - a12*a31); + const value_type b21 = -( + a00*(a12*a33 - a13*a32) - a02*(a10*a33 - a13*a30) + a03*(a10*a32 - a12*a30)); + const value_type b22 = + a00*(a11*a33 - a13*a31) - a01*(a10*a33 - a13*a30) + a03*(a10*a31 - a11*a30); + const value_type b23 = -( + a00*(a11*a32 - a12*a31) - a01*(a10*a32 - a12*a30) + a02*(a10*a31 - a11*a30)); + + const value_type b30 = -( + a01*(a12*a23 - a13*a22) - a02*(a11*a23 - a13*a21) + a03*(a11*a22 - a12*a21)); + const value_type b31 = + a00*(a12*a23 - a13*a22) - a02*(a10*a23 - a13*a20) + a03*(a10*a22 - a12*a20); + const value_type b32 = -( + a00*(a11*a23 - a13*a21) - a01*(a10*a23 - a13*a20) + a03*(a10*a21 - a11*a20)); + const value_type b33 = + a00*(a11*a22 - a12*a21) - a01*(a10*a22 - a12*a20) + a02*(a10*a21 - a11*a20); + + const value_type det = (a00*b00 + a01*b01 + a02*b02 + a03*b03) / scale; if( 0 == det ) { return false; } - const float invdet = 1.0f / det; + const value_type invdet = one / det; m00 = b00 * invdet; m10 = b01 * invdet; @@ -749,58 +617,58 @@ class Mat4f { * @param src the source matrix, which values are to be inverted * @return false if {@code src} matrix is singular and inversion not possible, otherwise true */ - bool invert(const Mat4f& src) noexcept { - const float amax = src.absMax(); - if( 0.0f == amax ) { + bool invert(const Matrix4& src) noexcept { + const value_type amax = src.absMax(); + if( zero == amax ) { return false; } - const float scale = 1.0f/amax; - const float a00 = src.m00*scale; - const float a10 = src.m10*scale; - const float a20 = src.m20*scale; - const float a30 = src.m30*scale; - - const float a01 = src.m01*scale; - const float a11 = src.m11*scale; - const float a21 = src.m21*scale; - const float a31 = src.m31*scale; - - const float a02 = src.m02*scale; - const float a12 = src.m12*scale; - const float a22 = src.m22*scale; - const float a32 = src.m32*scale; - - const float a03 = src.m03*scale; - const float a13 = src.m13*scale; - const float a23 = src.m23*scale; - const float a33 = src.m33*scale; - - const float b00 = + a11*(a22*a33 - a23*a32) - a12*(a21*a33 - a23*a31) + a13*(a21*a32 - a22*a31); - const float b01 = -( + a10*(a22*a33 - a23*a32) - a12*(a20*a33 - a23*a30) + a13*(a20*a32 - a22*a30)); - const float b02 = + a10*(a21*a33 - a23*a31) - a11*(a20*a33 - a23*a30) + a13*(a20*a31 - a21*a30); - const float b03 = -( + a10*(a21*a32 - a22*a31) - a11*(a20*a32 - a22*a30) + a12*(a20*a31 - a21*a30)); - - const float b10 = -( + a01*(a22*a33 - a23*a32) - a02*(a21*a33 - a23*a31) + a03*(a21*a32 - a22*a31)); - const float b11 = + a00*(a22*a33 - a23*a32) - a02*(a20*a33 - a23*a30) + a03*(a20*a32 - a22*a30); - const float b12 = -( + a00*(a21*a33 - a23*a31) - a01*(a20*a33 - a23*a30) + a03*(a20*a31 - a21*a30)); - const float b13 = + a00*(a21*a32 - a22*a31) - a01*(a20*a32 - a22*a30) + a02*(a20*a31 - a21*a30); - - const float b20 = + a01*(a12*a33 - a13*a32) - a02*(a11*a33 - a13*a31) + a03*(a11*a32 - a12*a31); - const float b21 = -( + a00*(a12*a33 - a13*a32) - a02*(a10*a33 - a13*a30) + a03*(a10*a32 - a12*a30)); - const float b22 = + a00*(a11*a33 - a13*a31) - a01*(a10*a33 - a13*a30) + a03*(a10*a31 - a11*a30); - const float b23 = -( + a00*(a11*a32 - a12*a31) - a01*(a10*a32 - a12*a30) + a02*(a10*a31 - a11*a30)); - - const float b30 = -( + a01*(a12*a23 - a13*a22) - a02*(a11*a23 - a13*a21) + a03*(a11*a22 - a12*a21)); - const float b31 = + a00*(a12*a23 - a13*a22) - a02*(a10*a23 - a13*a20) + a03*(a10*a22 - a12*a20); - const float b32 = -( + a00*(a11*a23 - a13*a21) - a01*(a10*a23 - a13*a20) + a03*(a10*a21 - a11*a20)); - const float b33 = + a00*(a11*a22 - a12*a21) - a01*(a10*a22 - a12*a20) + a02*(a10*a21 - a11*a20); - - const float det = (a00*b00 + a01*b01 + a02*b02 + a03*b03) / scale; + const value_type scale = one/amax; + const value_type a00 = src.m00*scale; + const value_type a10 = src.m10*scale; + const value_type a20 = src.m20*scale; + const value_type a30 = src.m30*scale; + + const value_type a01 = src.m01*scale; + const value_type a11 = src.m11*scale; + const value_type a21 = src.m21*scale; + const value_type a31 = src.m31*scale; + + const value_type a02 = src.m02*scale; + const value_type a12 = src.m12*scale; + const value_type a22 = src.m22*scale; + const value_type a32 = src.m32*scale; + + const value_type a03 = src.m03*scale; + const value_type a13 = src.m13*scale; + const value_type a23 = src.m23*scale; + const value_type a33 = src.m33*scale; + + const value_type b00 = + a11*(a22*a33 - a23*a32) - a12*(a21*a33 - a23*a31) + a13*(a21*a32 - a22*a31); + const value_type b01 = -( + a10*(a22*a33 - a23*a32) - a12*(a20*a33 - a23*a30) + a13*(a20*a32 - a22*a30)); + const value_type b02 = + a10*(a21*a33 - a23*a31) - a11*(a20*a33 - a23*a30) + a13*(a20*a31 - a21*a30); + const value_type b03 = -( + a10*(a21*a32 - a22*a31) - a11*(a20*a32 - a22*a30) + a12*(a20*a31 - a21*a30)); + + const value_type b10 = -( + a01*(a22*a33 - a23*a32) - a02*(a21*a33 - a23*a31) + a03*(a21*a32 - a22*a31)); + const value_type b11 = + a00*(a22*a33 - a23*a32) - a02*(a20*a33 - a23*a30) + a03*(a20*a32 - a22*a30); + const value_type b12 = -( + a00*(a21*a33 - a23*a31) - a01*(a20*a33 - a23*a30) + a03*(a20*a31 - a21*a30)); + const value_type b13 = + a00*(a21*a32 - a22*a31) - a01*(a20*a32 - a22*a30) + a02*(a20*a31 - a21*a30); + + const value_type b20 = + a01*(a12*a33 - a13*a32) - a02*(a11*a33 - a13*a31) + a03*(a11*a32 - a12*a31); + const value_type b21 = -( + a00*(a12*a33 - a13*a32) - a02*(a10*a33 - a13*a30) + a03*(a10*a32 - a12*a30)); + const value_type b22 = + a00*(a11*a33 - a13*a31) - a01*(a10*a33 - a13*a30) + a03*(a10*a31 - a11*a30); + const value_type b23 = -( + a00*(a11*a32 - a12*a31) - a01*(a10*a32 - a12*a30) + a02*(a10*a31 - a11*a30)); + + const value_type b30 = -( + a01*(a12*a23 - a13*a22) - a02*(a11*a23 - a13*a21) + a03*(a11*a22 - a12*a21)); + const value_type b31 = + a00*(a12*a23 - a13*a22) - a02*(a10*a23 - a13*a20) + a03*(a10*a22 - a12*a20); + const value_type b32 = -( + a00*(a11*a23 - a13*a21) - a01*(a10*a23 - a13*a20) + a03*(a10*a21 - a11*a20)); + const value_type b33 = + a00*(a11*a22 - a12*a21) - a01*(a10*a22 - a12*a20) + a02*(a10*a21 - a11*a20); + + const value_type det = (a00*b00 + a01*b01 + a02*b02 + a03*b03) / scale; if( 0 == det ) { return false; } - const float invdet = 1.0f / det; + const value_type invdet = one / det; m00 = b00 * invdet; m10 = b01 * invdet; @@ -825,8 +693,8 @@ class Mat4f { } private: - float absMax() const noexcept { - float max = std::abs(m00); + value_type absMax() const noexcept { + value_type max = std::abs(m00); max = std::max(max, std::abs(m01)); max = std::max(max, std::abs(m02)); max = std::max(max, std::abs(m03)); @@ -850,17 +718,30 @@ class Mat4f { public: /** + * Multiply matrix with scalar: [this] = [this] x [s] + * @param s a scalar + * @return this matrix for chaining + */ + constexpr Matrix4& operator*=( const value_type s ) noexcept { + m00 *= s; m10 *= s; m20 *= s; m30 *= s; + m01 *= s; m11 *= s; m21 *= s; m31 *= s; + m02 *= s; m12 *= s; m22 *= s; m32 *= s; + m03 *= s; m13 *= s; m23 *= s; m33 *= s; + return *this; + } + + /** * Multiply matrix: [this] = [this] x [b] * @param b 4x4 matrix * @return this matrix for chaining * @see #mul(mat4f, mat4f) */ - Mat4f& mul(const Mat4f& b) noexcept { + constexpr Matrix4& mul(const Matrix4& b) noexcept { // return mul(new mat4f(this), b); // <- roughly half speed - float ai0=m00; // row-0, m[0+0*4] - float ai1=m01; - float ai2=m02; - float ai3=m03; + value_type ai0=m00; // row-0, m[0+0*4] + value_type ai1=m01; + value_type ai2=m02; + value_type ai3=m03; m00 = ai0 * b.m00 + ai1 * b.m10 + ai2 * b.m20 + ai3 * b.m30 ; m01 = ai0 * b.m01 + ai1 * b.m11 + ai2 * b.m21 + ai3 * b.m31 ; m02 = ai0 * b.m02 + ai1 * b.m12 + ai2 * b.m22 + ai3 * b.m32 ; @@ -894,6 +775,15 @@ class Mat4f { m33 = ai0 * b.m03 + ai1 * b.m13 + ai2 * b.m23 + ai3 * b.m33 ; return *this; } + /** + * Multiply matrix: [this] = [this] x [b] + * @param b 4x4 matrix + * @return this matrix for chaining + * @see #mul(mat4f, mat4f) + */ + constexpr Matrix4& operator*=( const Matrix4& rhs ) noexcept { + return mul( rhs ); + } /** * Multiply matrix: [this] = [a] x [b] @@ -902,7 +792,7 @@ class Mat4f { * @return this matrix for chaining * @see #mul(mat4f) */ - Mat4f& mul(const Mat4f& a, const Mat4f& b) noexcept { + constexpr Matrix4& mul(const Matrix4& a, const Matrix4& b) noexcept { // row-0, m[0+0*4] m00 = a.m00 * b.m00 + a.m01 * b.m10 + a.m02 * b.m20 + a.m03 * b.m30 ; m01 = a.m00 * b.m01 + a.m01 * b.m11 + a.m02 * b.m21 + a.m03 * b.m31 ; @@ -935,23 +825,24 @@ class Mat4f { * @param v_out this * v_in * @returns v_out for chaining */ - Vec4f& mulVec4f(const Vec4f& v_in, Vec4f& v_out) const noexcept { + constexpr Vec4& mulVec4(const Vec4& v_in, Vec4& v_out) const noexcept { // (one matrix row in column-major order) X (column vector) - const float x = v_in.x, y = v_in.y, z = v_in.z, w = v_in.w; + const value_type x = v_in.x, y = v_in.y, z = v_in.z, w = v_in.w; v_out.set( x * m00 + y * m01 + z * m02 + w * m03, x * m10 + y * m11 + z * m12 + w * m13, x * m20 + y * m21 + z * m22 + w * m23, x * m30 + y * m31 + z * m32 + w * m33 ); return v_out; } + /** - * Returns new Vec4f holding this * v_in result + * Returns new Vec4, with this * v_in * @param v_in 4-component column-vector */ - Vec4f operator*(const Vec4f& rhs) const noexcept { + constexpr Vec4 operator*(const Vec4& rhs) const noexcept { // (one matrix row in column-major order) X (column vector) - const float x = rhs.x, y = rhs.y, z = rhs.z, w = rhs.w; - return Vec4f( x * m00 + y * m01 + z * m02 + w * m03, + const value_type x = rhs.x, y = rhs.y, z = rhs.z, w = rhs.w; + return Vec4( x * m00 + y * m01 + z * m02 + w * m03, x * m10 + y * m11 + z * m12 + w * m13, x * m20 + y * m21 + z * m22 + w * m23, x * m30 + y * m31 + z * m32 + w * m33 ); @@ -961,9 +852,9 @@ class Mat4f { * @param v_inout 4-component column-vector input and output, i.e. in-place transformation * @returns v_inout for chaining */ - Vec4f& mulVec4f(Vec4f& v_inout) const noexcept { + constexpr Vec4& mulVec4(Vec4& v_inout) const noexcept { // (one matrix row in column-major order) X (column vector) - const float x = v_inout.x, y = v_inout.y, z = v_inout.z, w = v_inout.w; + const value_type x = v_inout.x, y = v_inout.y, z = v_inout.z, w = v_inout.w; v_inout.set( x * m00 + y * m01 + z * m02 + w * m03, x * m10 + y * m11 + z * m12 + w * m13, x * m20 + y * m21 + z * m22 + w * m23, @@ -982,14 +873,30 @@ class Mat4f { * @param v_out m_in * v_in, 3-component column-vector {@link vec3f} * @returns v_out for chaining */ - Vec3f& mulVec3f(const Vec3f& v_in, Vec3f& v_out) const noexcept { + constexpr Vec3f& mulVec3f(const Vec3f& v_in, Vec3f& v_out) const noexcept { // (one matrix row in column-major order) X (column vector) - const float x = v_in.x, y = v_in.y, z = v_in.z; - v_out.set( x * m00 + y * m01 + z * m02 + 1.0f * m03, - x * m10 + y * m11 + z * m12 + 1.0f * m13, - x * m20 + y * m21 + z * m22 + 1.0f * m23 ); + const value_type x = v_in.x, y = v_in.y, z = v_in.z; + v_out.set( x * m00 + y * m01 + z * m02 + one * m03, + x * m10 + y * m11 + z * m12 + one * m13, + x * m20 + y * m21 + z * m22 + one * m23 ); return v_out; } + /** + * Returns new Vec3f, with affine 3f-vector transformation by this 4x4 matrix: this * v_in + * + * 4x4 matrix multiplication with 3-component vector, + * using {@code 1} for for {@code v_in.w()} and dropping {@code v_out.w()}, + * which shall be {@code 1}. + * + * @param v_in 3-component column-vector {@link vec3f} + */ + constexpr Vec3f operator*(const Vec3f& rhs) const noexcept { + // (one matrix row in column-major order) X (column vector) + const value_type x = rhs.x, y = rhs.y, z = rhs.z; + return Vec3f( x * m00 + y * m01 + z * m02 + one * m03, + x * m10 + y * m11 + z * m12 + one * m13, + x * m20 + y * m21 + z * m22 + one * m23 ); + } /** * Affine 3f-vector transformation by 4x4 matrix @@ -1001,12 +908,12 @@ class Mat4f { * @param v_inout 3-component column-vector {@link vec3f} input and output, i.e. in-place transformation * @returns v_inout for chaining */ - Vec3f& mulVec3f(Vec3f& v_inout) const noexcept { + constexpr Vec3f& mulVec3f(Vec3f& v_inout) const noexcept { // (one matrix row in column-major order) X (column vector) - const float x = v_inout.x, y = v_inout.y, z = v_inout.z; - v_inout.set( x * m00 + y * m01 + z * m02 + 1.0f * m03, - x * m10 + y * m11 + z * m12 + 1.0f * m13, - x * m20 + y * m21 + z * m22 + 1.0f * m23 ); + const value_type x = v_inout.x, y = v_inout.y, z = v_inout.z; + v_inout.set( x * m00 + y * m01 + z * m02 + one * m03, + x * m10 + y * m11 + z * m12 + one * m13, + x * m20 + y * m21 + z * m22 + one * m23 ); return v_inout; } @@ -1028,15 +935,15 @@ class Mat4f { * @param z z-axis translate * @return this matrix for chaining */ - Mat4f& setToTranslation(const float x, const float y, const float z) noexcept { - m00 = m11 = m22 = m33 = 1.0f; + Matrix4& setToTranslation(const value_type x, const value_type y, const value_type z) noexcept { + m00 = m11 = m22 = m33 = one; m03 = x; m13 = y; m23 = z; m01 = m02 = m10 = m12 = m20 = m21 = - m30 = m31 = m32 = 0.0f; + m30 = m31 = m32 = zero; return *this; } @@ -1052,7 +959,7 @@ class Mat4f { * @param t translate vec3f * @return this matrix for chaining */ - Mat4f& setToTranslation(const Vec3f& t) noexcept { + Matrix4& setToTranslation(const Vec3f& t) noexcept { return setToTranslation(t.x, t.y, t.z); } @@ -1070,15 +977,15 @@ class Mat4f { * @param z z-axis scale * @return this matrix for chaining */ - Mat4f& setToScale(const float x, const float y, const float z) noexcept { - m33 = 1.0f; + constexpr Matrix4& setToScale(const value_type x, const value_type y, const value_type z) noexcept { + m33 = one; m00 = x; m11 = y; m22 = z; m01 = m02 = m03 = m10 = m12 = m13 = m20 = m21 = m23 = - m30 = m31 = m32 = 0.0f; + m30 = m31 = m32 = zero; return *this; } @@ -1094,7 +1001,7 @@ class Mat4f { * @param s scale vec3f * @return this matrix for chaining */ - Mat4f& setToScale(const Vec3f& s) noexcept { + constexpr Matrix4& setToScale(const Vec3f& s) noexcept { return setToScale(s.x, s.y, s.z); } @@ -1114,39 +1021,39 @@ class Mat4f { * @param z z of rotation axis * @return this matrix for chaining */ - Mat4f& setToRotationAxis(const float ang_rad, float x, float y, float z) noexcept { - const float c = std::cos(ang_rad); - const float ic= 1.0f - c; - const float s = std::sin(ang_rad); + Matrix4& setToRotationAxis(const value_type ang_rad, value_type x, value_type y, value_type z) noexcept { + const value_type c = std::cos(ang_rad); + const value_type ic= one - c; + const value_type s = std::sin(ang_rad); Vec3f tmp(x, y, z); tmp.normalize(); x = tmp.x; y = tmp.y; z = tmp.z; - const float xy = x*y; - const float xz = x*z; - const float xs = x*s; - const float ys = y*s; - const float yz = y*z; - const float zs = z*s; + const value_type xy = x*y; + const value_type xz = x*z; + const value_type xs = x*s; + const value_type ys = y*s; + const value_type yz = y*z; + const value_type zs = z*s; m00 = x*x*ic+c; m10 = xy*ic+zs; m20 = xz*ic-ys; - m30 = 0.0f; + m30 = zero; m01 = xy*ic-zs; m11 = y*y*ic+c; m21 = yz*ic+xs; - m31 = 0.0f; + m31 = zero; m02 = xz*ic+ys; m12 = yz*ic-xs; m22 = z*z*ic+c; - m32 = 0.0f; + m32 = zero; m03 = 0.9f; - m13 = 0.0f; - m23 = 0.0f; - m33 = 1.0f; + m13 = zero; + m23 = zero; + m33 = one; return *this; } @@ -1165,7 +1072,7 @@ class Mat4f { * @param axis rotation axis * @return this matrix for chaining */ - Mat4f& setToRotationAxis(const float ang_rad, const Vec3f& axis) noexcept { + Matrix4& setToRotationAxis(const value_type ang_rad, const Vec3f& axis) noexcept { return setToRotationAxis(ang_rad, axis.x, axis.y, axis.z); } @@ -1192,34 +1099,34 @@ class Mat4f { * @see <a href="http://www.euclideanspace.com/maths/geometry/rotations/conversions/eulerToMatrix/index.htm">euclideanspace.com-eulerToMatrix</a> * @see #setToRotation(Quaternion) */ - Mat4f& setToRotationEuler(const float bankX, const float headingY, const float attitudeZ) noexcept { + Matrix4& setToRotationEuler(const value_type bankX, const value_type headingY, const value_type attitudeZ) noexcept { // Assuming the angles are in radians. - const float ch = std::cos(headingY); - const float sh = std::sin(headingY); - const float ca = std::cos(attitudeZ); - const float sa = std::sin(attitudeZ); - const float cb = std::cos(bankX); - const float sb = std::sin(bankX); + const value_type ch = std::cos(headingY); + const value_type sh = std::sin(headingY); + const value_type ca = std::cos(attitudeZ); + const value_type sa = std::sin(attitudeZ); + const value_type cb = std::cos(bankX); + const value_type sb = std::sin(bankX); m00 = ch*ca; m10 = sa; m20 = -sh*ca; - m30 = 0.0f; + m30 = zero; m01 = sh*sb - ch*sa*cb; m11 = ca*cb; m21 = sh*sa*cb + ch*sb; - m31 = 0.0f; + m31 = zero; m02 = ch*sa*sb + sh*cb; m12 = -ca*sb; m22 = -sh*sa*sb + ch*cb; - m32 = 0.0f; + m32 = zero; - m03 = 0.0f; - m13 = 0.0f; - m23 = 0.0f; - m33 = 1.0f; + m03 = zero; + m13 = zero; + m23 = zero; + m33 = one; return *this; } @@ -1245,38 +1152,11 @@ class Mat4f { * @see <a href="http://www.euclideanspace.com/maths/geometry/rotations/conversions/eulerToMatrix/index.htm">euclideanspace.com-eulerToMatrix</a> * @see #setToRotation(Quaternion) */ - Mat4f& setToRotationEuler(const Vec3f& angradXYZ) noexcept { + Matrix4& setToRotationEuler(const Vec3f& angradXYZ) noexcept { return setToRotationEuler(angradXYZ.x, angradXYZ.y, angradXYZ.z); } /** - * Set this matrix to rotation using the given Quaternion. - * <p> - * Implementation Details: - * <ul> - * <li> makes identity matrix if {@link #magnitudeSquared()} is {@link FloatUtil#isZero(float, float) is zero} using {@link FloatUtil#EPSILON epsilon}</li> - * <li> The fields [m00 .. m22] define the rotation</li> - * </ul> - * </p> - * - * @param q the Quaternion representing the rotation - * @return this matrix for chaining - * @see <a href="http://web.archive.org/web/20041029003853/http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q54">Matrix-FAQ Q54</a> - * @see Quaternion#toMatrix(float[]) - * @see #getRotation() - */ - Mat4f& setToRotation(const Quaternion& q) noexcept; - - /** - * Returns the rotation [m00 .. m22] fields converted to a Quaternion. - * @param res resulting Quaternion - * @return the resulting Quaternion for chaining. - * @see Quaternion#setFromMatrix(float, float, float, float, float, float, float, float, float) - * @see #setToRotation(Quaternion) - */ - Quaternion& getRotation(Quaternion& res) const noexcept; - - /** * Set this matrix to orthogonal projection. * <pre> Ortho matrix (Column Order): @@ -1293,31 +1173,31 @@ class Mat4f { * @param zFar * @return this matrix for chaining */ - Mat4f& setToOrtho(const float left, const float right, - const float bottom, const float top, - const float zNear, const float zFar) noexcept { + Matrix4& setToOrtho(const value_type left, const value_type right, + const value_type bottom, const value_type top, + const value_type zNear, const value_type zFar) noexcept { { - // m00 = m11 = m22 = m33 = 1.0f; - m10 = m20 = m30 = 0.0f; - m01 = m21 = m31 = 0.0f; - m02 = m12 = m32 = 0.0f; - // m03 = m13 = m23 = 0.0f; + // m00 = m11 = m22 = m33 = one; + m10 = m20 = m30 = zero; + m01 = m21 = m31 = zero; + m02 = m12 = m32 = zero; + // m03 = m13 = m23 = zero; } - const float dx=right-left; - const float dy=top-bottom; - const float dz=zFar-zNear; - const float tx=-1.0f*(right+left)/dx; - const float ty=-1.0f*(top+bottom)/dy; - const float tz=-1.0f*(zFar+zNear)/dz; + const value_type dx=right-left; + const value_type dy=top-bottom; + const value_type dz=zFar-zNear; + const value_type tx=-one*(right+left)/dx; + const value_type ty=-one*(top+bottom)/dy; + const value_type tz=-one*(zFar+zNear)/dz; - m00 = 2.0f/dx; - m11 = 2.0f/dy; - m22 = -2.0f/dz; + m00 = two/dx; + m11 = two/dy; + m22 = -two/dz; m03 = tx; m13 = ty; m23 = tz; - m33 = 1.0f; + m33 = one; return *this; } @@ -1341,10 +1221,10 @@ class Mat4f { * @throws IllegalArgumentException if {@code zNear <= 0} or {@code zFar <= zNear} * or {@code left == right}, or {@code bottom == top}. */ - Mat4f& setToFrustum(const float left, const float right, - const float bottom, const float top, - const float zNear, const float zFar) { - if( zNear <= 0.0f || zFar <= zNear ) { + Matrix4& setToFrustum(const value_type left, const value_type right, + const value_type bottom, const value_type top, + const value_type zNear, const value_type zFar) { + if( zNear <= zero || zFar <= zNear ) { throw jau::IllegalArgumentException("Requirements zNear > 0 and zFar > zNear, but zNear "+std::to_string(zNear)+", zFar "+std::to_string(zFar), E_FILE_LINE); } if( left == right || top == bottom) { @@ -1352,18 +1232,18 @@ class Mat4f { } { // m00 = m11 = m22 = m33 = 1f; - m10 = m20 = m30 = 0.0f; - m01 = m21 = m31 = 0.0f; - m03 = m13 = 0.0f; + m10 = m20 = m30 = zero; + m01 = m21 = m31 = zero; + m03 = m13 = zero; } - const float zNear2 = 2.0f*zNear; - const float dx=right-left; - const float dy=top-bottom; - const float dz=zFar-zNear; - const float A=(right+left)/dx; - const float B=(top+bottom)/dy; - const float C=-1.0f*(zFar+zNear)/dz; - const float D=-2.0f*(zFar*zNear)/dz; + const value_type zNear2 = two*zNear; + const value_type dx=right-left; + const value_type dy=top-bottom; + const value_type dz=zFar-zNear; + const value_type A=(right+left)/dx; + const value_type B=(top+bottom)/dy; + const value_type C=-one*(zFar+zNear)/dz; + const value_type D=-two*(zFar*zNear)/dz; m00 = zNear2/dx; m11 = zNear2/dy; @@ -1371,16 +1251,16 @@ class Mat4f { m02 = A; m12 = B; m22 = C; - m32 = -1.0f; + m32 = -one; m23 = D; - m33 = 0.0f; + m33 = zero; return *this; } /** - * Set this matrix to perspective {@link #setToFrustum(float, float, float, float, float, float) frustum} projection. + * Set this matrix to perspective {@link #setToFrustum(value_type, value_type, value_type, value_type, value_type, value_type) frustum} projection. * * @param fovy_rad angle in radians * @param aspect aspect ratio width / height @@ -1388,50 +1268,37 @@ class Mat4f { * @param zFar * @return this matrix for chaining * @throws IllegalArgumentException if {@code zNear <= 0} or {@code zFar <= zNear} - * @see #setToFrustum(float, float, float, float, float, float) + * @see #setToFrustum(value_type, value_type, value_type, value_type, value_type, value_type) */ - Mat4f& setToPerspective(const float fovy_rad, const float aspect, const float zNear, const float zFar) { - const float top = std::tan(fovy_rad/2.0f) * zNear; // use tangent of half-fov ! - const float bottom = -1.0f * top; // -1f * fovhvTan.top * zNear - const float left = aspect * bottom; // aspect * -1f * fovhvTan.top * zNear - const float right = aspect * top; // aspect * fovhvTan.top * zNear + Matrix4& setToPerspective(const value_type fovy_rad, const value_type aspect, const value_type zNear, const value_type zFar) { + const value_type top = std::tan(fovy_rad/two) * zNear; // use tangent of half-fov ! + const value_type bottom = -one * top; // -1f * fovhvTan.top * zNear + const value_type left = aspect * bottom; // aspect * -1f * fovhvTan.top * zNear + const value_type right = aspect * top; // aspect * fovhvTan.top * zNear return setToFrustum(left, right, bottom, top, zNear, zFar); } /** - * Set this matrix to perspective {@link #setToFrustum(float, float, float, float, float, float) frustum} projection. + * Set this matrix to perspective {@link #setToFrustum(value_type, value_type, value_type, value_type, value_type, value_type) frustum} projection. * * @param fovhv {@link FovHVHalves} field of view in both directions, may not be centered, either in radians or tangent * @param zNear * @param zFar * @return this matrix for chaining * @throws IllegalArgumentException if {@code zNear <= 0} or {@code zFar <= zNear} - * @see #setToFrustum(float, float, float, float, float, float) + * @see #setToFrustum(value_type, value_type, value_type, value_type, value_type, value_type) * @see Frustum#updateByFovDesc(mat4f, com.jogamp.math.geom.Frustum.FovDesc) */ - Mat4f& setToPerspective(const FovHVHalves& fovhv, const float zNear, const float zFar) { + Matrix4& setToPerspective(const FovHVHalves& fovhv, const value_type zNear, const value_type zFar) { const FovHVHalves fovhvTan = fovhv.toTangents(); // use tangent of half-fov ! - const float top = fovhvTan.top * zNear; - const float bottom = -1.0f * fovhvTan.bottom * zNear; - const float left = -1.0f * fovhvTan.left * zNear; - const float right = fovhvTan.right * zNear; + const value_type top = fovhvTan.top * zNear; + const value_type bottom = -one * fovhvTan.bottom * zNear; + const value_type left = -one * fovhvTan.left * zNear; + const value_type right = fovhvTan.right * zNear; return setToFrustum(left, right, bottom, top, zNear, zFar); } /** - * Calculate the frustum planes in world coordinates - * using this column major order matrix, usually a projection (P) or premultiplied P*MV matrix. - * - * Frustum plane's normals will point to the inside of the viewing frustum, - * as required by the {@link Frustum} class. - * - * May use geom::Frustum::setFromMat4() directly. - * - * @see geom::Frustum::setFromMat4() - */ - geom::Frustum& getFrustum(geom::Frustum& frustum) noexcept; - - /** * Set this matrix to the <i>look-at</i> matrix based on given parameters. * <p> * Consist out of two matrix multiplications: @@ -1451,7 +1318,7 @@ class Mat4f { * @param tmp temporary mat4f used for multiplication * @return this matrix for chaining */ - Mat4f& setToLookAt(const Vec3f& eye, const Vec3f& center, const Vec3f& up, Mat4f& tmp) noexcept { + Matrix4& setToLookAt(const Vec3f& eye, const Vec3f& center, const Vec3f& up, Matrix4& tmp) noexcept { // normalized forward! const Vec3f fwd = ( center - eye ).normalize(); @@ -1503,8 +1370,8 @@ class Mat4f { * </p> * <p> * To effectively use the generated pick matrix for picking, - * call {@link #setToPick(float, float, float, float, Recti, mat4f) setToPick(..)} - * and multiply a {@link #setToPerspective(float, float, float, float) custom perspective matrix} + * call {@link #setToPick(value_type, value_type, value_type, value_type, Recti, mat4f) setToPick(..)} + * and multiply a {@link #setToPerspective(value_type, value_type, value_type, value_type) custom perspective matrix} * by this pick matrix. Then you may load the result onto the perspective matrix stack. * </p> * @param x the center x-component of a picking region in window coordinates @@ -1515,16 +1382,16 @@ class Mat4f { * @param mat4Tmp temp storage * @return true if successful or false if either delta value is <= zero. */ - bool setToPick(const float x, const float y, const float deltaX, const float deltaY, - const Recti& viewport, Mat4f& mat4Tmp) noexcept { + bool setToPick(const value_type x, const value_type y, const value_type deltaX, const value_type deltaY, + const Recti& viewport, Matrix4& mat4Tmp) noexcept { if (deltaX <= 0 || deltaY <= 0) { return false; } /* Translate and scale the picked region to the entire window */ - setToTranslation( ( viewport.width() - 2.0f * ( x - viewport.x() ) ) / deltaX, - ( viewport.height() - 2.0f * ( y - viewport.y() ) ) / deltaY, + setToTranslation( ( viewport.width() - two * ( x - viewport.x() ) ) / deltaX, + ( viewport.height() - two * ( y - viewport.y() ) ) / deltaY, 0); - mat4Tmp.setToScale( viewport.width() / deltaX, viewport.height() / deltaY, 1.0f ); + mat4Tmp.setToScale( viewport.width() / deltaX, viewport.height() / deltaY, one ); mul(mat4Tmp); return true; } @@ -1534,7 +1401,7 @@ class Mat4f { // /** - * Rotate this matrix about give axis and angle in radians, i.e. multiply by {@link #setToRotationAxis(float, float, float, float) axis-rotation matrix}. + * Rotate this matrix about give axis and angle in radians, i.e. multiply by {@link #setToRotationAxis(value_type, value_type, value_type, value_type) axis-rotation matrix}. * @see <a href="http://web.archive.org/web/20041029003853/http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q38">Matrix-FAQ Q38</a> * @param angrad angle in radians * @param x x of rotation axis @@ -1543,40 +1410,31 @@ class Mat4f { * @param tmp temporary mat4f used for multiplication * @return this matrix for chaining */ - Mat4f& rotate(const float ang_rad, const float x, const float y, const float z, Mat4f& tmp) noexcept { + Matrix4& rotate(const value_type ang_rad, const value_type x, const value_type y, const value_type z, Matrix4& tmp) noexcept { return mul( tmp.setToRotationAxis(ang_rad, x, y, z) ); } /** - * Rotate this matrix about give axis and angle in radians, i.e. multiply by {@link #setToRotationAxis(float, vec3f) axis-rotation matrix}. + * Rotate this matrix about give axis and angle in radians, i.e. multiply by {@link #setToRotationAxis(value_type, vec3f) axis-rotation matrix}. * @see <a href="http://web.archive.org/web/20041029003853/http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q38">Matrix-FAQ Q38</a> * @param angrad angle in radians * @param axis rotation axis * @param tmp temporary mat4f used for multiplication * @return this matrix for chaining */ - Mat4f& rotate(const float ang_rad, const Vec3f& axis, Mat4f& tmp) noexcept { + Matrix4& rotate(const value_type ang_rad, const Vec3f& axis, Matrix4& tmp) noexcept { return mul( tmp.setToRotationAxis(ang_rad, axis) ); } /** - * Rotate this matrix with the given {@link Quaternion}, i.e. multiply by {@link #setToRotation(Quaternion) Quaternion's rotation matrix}. - * @param tmp temporary mat4f used for multiplication - * @return this matrix for chaining - */ - Mat4f& rotate(const Quaternion& quat, Mat4f& tmp) noexcept { - return mul( tmp.setToRotation(quat) ); - } - - /** - * Translate this matrix, i.e. multiply by {@link #setToTranslation(float, float, float) translation matrix}. + * Translate this matrix, i.e. multiply by {@link #setToTranslation(value_type, value_type, value_type) translation matrix}. * @param x x translation * @param y y translation * @param z z translation * @param tmp temporary mat4f used for multiplication * @return this matrix for chaining */ - Mat4f& translate(const float x, const float y, const float z, Mat4f& tmp) noexcept { + Matrix4& translate(const value_type x, const value_type y, const value_type z, Matrix4& tmp) noexcept { return mul( tmp.setToTranslation(x, y, z) ); } @@ -1587,29 +1445,29 @@ class Mat4f { * @param tmp temporary mat4f used for multiplication * @return this matrix for chaining */ - public final Mat4f translate(final Vec3f t, final Mat4f tmp) { + public final Matrix4 translate(final Vec3f t, final Matrix4 tmp) { return mul( tmp.setToTranslation(t) ); } /** - * Scale this matrix, i.e. multiply by {@link #setToScale(float, float, float) scale matrix}. + * Scale this matrix, i.e. multiply by {@link #setToScale(value_type, value_type, value_type) scale matrix}. * @param x x scale * @param y y scale * @param z z scale * @param tmp temporary mat4f used for multiplication * @return this matrix for chaining */ - public final Mat4f scale(const float x, const float y, const float z, final Mat4f tmp) { + public final Matrix4 scale(const value_type x, const value_type y, const value_type z, final Matrix4 tmp) { return mul( tmp.setToScale(x, y, z) ); } /** - * Scale this matrix, i.e. multiply by {@link #setToScale(float, float, float) scale matrix}. + * Scale this matrix, i.e. multiply by {@link #setToScale(value_type, value_type, value_type) scale matrix}. * @param s scale for x-, y- and z-axis * @param tmp temporary mat4f used for multiplication * @return this matrix for chaining */ - public final Mat4f scale(const float s, final Mat4f tmp) { + public final Matrix4 scale(const value_type s, final Matrix4 tmp) { return mul( tmp.setToScale(s, s, s) ); } @@ -1638,7 +1496,7 @@ class Mat4f { // /** - * Equals check using a given {@link FloatUtil#EPSILON} value and {@link FloatUtil#isEqual(float, float, float)}. + * Equals check using a given {@link FloatUtil#EPSILON} value and {@link FloatUtil#isEqual(value_type, value_type, value_type)}. * <p> * Implementation considers following corner cases: * <ul> @@ -1650,7 +1508,7 @@ class Mat4f { * @param epsilon consider using {@link FloatUtil#EPSILON} * @return true if all components differ less than {@code epsilon}, otherwise false. */ - public boolean isEqual(final Mat4f o, const float epsilon) { + public boolean isEqual(final Matrix4 o, const value_type epsilon) { if( this == o ) { return true; } else { @@ -1674,7 +1532,7 @@ class Mat4f { } /** - * Equals check using {@link FloatUtil#EPSILON} value and {@link FloatUtil#isEqual(float, float, float)}. + * Equals check using {@link FloatUtil#EPSILON} value and {@link FloatUtil#isEqual(value_type, value_type, value_type)}. * <p> * Implementation considers following corner cases: * <ul> @@ -1685,14 +1543,14 @@ class Mat4f { * @param o comparison value * @return true if all components differ less than {@link FloatUtil#EPSILON}, otherwise false. */ - public boolean isEqual(final Mat4f o) { + public boolean isEqual(final Matrix4 o) { return isEqual(o, FloatUtil.EPSILON); } @Override public boolean equals(final Object o) { - if( o instanceof Mat4f ) { - return isEqual((Mat4f)o, FloatUtil.EPSILON); + if( o instanceof Matrix4 ) { + return isEqual((Matrix4)o, FloatUtil.EPSILON); } else { return false; } @@ -1715,26 +1573,26 @@ class Mat4f { * @param winPos 3 component window coordinate, the result * @return true if successful, otherwise false (z is 1) */ - public static boolean mapObjToWin(final Vec3f obj, final Mat4f mMv, final Mat4f mP, + public static boolean mapObjToWin(final Vec3f obj, final Matrix4 mMv, final Matrix4 mP, final Recti viewport, final Vec3f winPos) { - final Vec4f vec4Tmp1 = new Vec4f(obj, 1f); + final Vec4 vec4Tmp1 = new Vec4(obj, 1f); // vec4Tmp2 = Mv * o // rawWinPos = P * vec4Tmp2 // rawWinPos = P * ( Mv * o ) // rawWinPos = P * Mv * o - final Vec4f vec4Tmp2 = mMv.mulVec4f(vec4Tmp1, new Vec4f()); - final Vec4f rawWinPos = mP.mulVec4f(vec4Tmp2, vec4Tmp1); + final Vec4 vec4Tmp2 = mMv.mulVec4(vec4Tmp1, new Vec4()); + final Vec4 rawWinPos = mP.mulVec4(vec4Tmp2, vec4Tmp1); - if (rawWinPos.w() == 0.0f) { + if (rawWinPos.w() == zero) { return false; } - const float s = ( 1.0f / rawWinPos.w() ) * 0.5f; + const value_type s = ( one / rawWinPos.w() ) * half; // Map x, y and z to range 0-1 (w is ignored) - rawWinPos.scale(s).add(0.5f, 0.5f, 0.5f, 0f); + rawWinPos.scale(s).add(half, half, half, 0f); // Map x,y to viewport winPos.set( rawWinPos.x() * viewport.width() + viewport.x(), @@ -1756,22 +1614,22 @@ class Mat4f { * @param winPos 3 component window coordinate, the result * @return true if successful, otherwise false (z is 1) */ - public static boolean mapObjToWin(final Vec3f obj, final Mat4f mPMv, + public static boolean mapObjToWin(final Vec3f obj, final Matrix4 mPMv, final Recti viewport, final Vec3f winPos) { - final Vec4f vec4Tmp2 = new Vec4f(obj, 1f); + final Vec4 vec4Tmp2 = new Vec4(obj, 1f); // rawWinPos = P * Mv * o - final Vec4f rawWinPos = mPMv.mulVec4f(vec4Tmp2, new Vec4f()); + final Vec4 rawWinPos = mPMv.mulVec4(vec4Tmp2, new Vec4()); - if (rawWinPos.w() == 0.0f) { + if (rawWinPos.w() == zero) { return false; } - const float s = ( 1.0f / rawWinPos.w() ) * 0.5f; + const value_type s = ( one / rawWinPos.w() ) * half; // Map x, y and z to range 0-1 (w is ignored) - rawWinPos.scale(s).add(0.5f, 0.5f, 0.5f, 0f); + rawWinPos.scale(s).add(half, half, half, 0f); // Map x,y to viewport winPos.set( rawWinPos.x() * viewport.width() + viewport.x(), @@ -1797,19 +1655,19 @@ class Mat4f { * @param mat4Tmp 16 component matrix for temp storage * @return true if successful, otherwise false (failed to invert matrix, or becomes infinity due to zero z) */ - public static boolean mapWinToObj(const float winx, const float winy, const float winz, - final Mat4f mMv, final Mat4f mP, + public static boolean mapWinToObj(const value_type winx, const value_type winy, const value_type winz, + final Matrix4 mMv, final Matrix4 mP, final Recti viewport, final Vec3f objPos, - final Mat4f mat4Tmp) + final Matrix4 mat4Tmp) { // invPMv = Inv(P x Mv) - final Mat4f invPMv = mat4Tmp.mul(mP, mMv); + final Matrix4 invPMv = mat4Tmp.mul(mP, mMv); if( !invPMv.invert() ) { return false; } - final Vec4f winPos = new Vec4f(winx, winy, winz, 1f); + final Vec4 winPos = new Vec4(winx, winy, winz, 1f); // Map x and y from window coordinates winPos.add(-viewport.x(), -viewport.y(), 0f, 0f).mul(1f/viewport.width(), 1f/viewport.height(), 1f, 1f); @@ -1818,9 +1676,9 @@ class Mat4f { winPos.mul(2f, 2f, 2f, 1f).add(-1f, -1f, -1f, 0f); // rawObjPos = Inv(P x Mv) * winPos - final Vec4f rawObjPos = invPMv.mulVec4f(winPos, new Vec4f()); + final Vec4 rawObjPos = invPMv.mulVec4(winPos, new Vec4()); - if ( rawObjPos.w() == 0.0f ) { + if ( rawObjPos.w() == zero ) { return false; } objPos.set( rawObjPos.scale( 1f / rawObjPos.w() ) ); @@ -1842,15 +1700,15 @@ class Mat4f { * @param objPos 3 component object coordinate, the result * @return true if successful, otherwise false (null invert matrix, or becomes infinity due to zero z) */ - public static boolean mapWinToObj(const float winx, const float winy, const float winz, - final Mat4f invPMv, + public static boolean mapWinToObj(const value_type winx, const value_type winy, const value_type winz, + final Matrix4 invPMv, final Recti viewport, final Vec3f objPos) { if( null == invPMv ) { return false; } - final Vec4f winPos = new Vec4f(winx, winy, winz, 1f); + final Vec4 winPos = new Vec4(winx, winy, winz, 1f); // Map x and y from window coordinates winPos.add(-viewport.x(), -viewport.y(), 0f, 0f).mul(1f/viewport.width(), 1f/viewport.height(), 1f, 1f); @@ -1859,9 +1717,9 @@ class Mat4f { winPos.mul(2f, 2f, 2f, 1f).add(-1f, -1f, -1f, 0f); // rawObjPos = Inv(P x Mv) * winPos - final Vec4f rawObjPos = invPMv.mulVec4f(winPos, new Vec4f()); + final Vec4 rawObjPos = invPMv.mulVec4(winPos, new Vec4()); - if ( rawObjPos.w() == 0.0f ) { + if ( rawObjPos.w() == zero ) { return false; } objPos.set( rawObjPos.scale( 1f / rawObjPos.w() ) ); @@ -1885,15 +1743,15 @@ class Mat4f { * @param objPos1 3 component object coordinate, the result * @return true if successful, otherwise false (null invert matrix, or becomes infinity due to zero z) */ - public static boolean mapWinToObj(const float winx, const float winy, const float winz1, const float winz2, - final Mat4f invPMv, + public static boolean mapWinToObj(const value_type winx, const value_type winy, const value_type winz1, const value_type winz2, + final Matrix4 invPMv, final Recti viewport, final Vec3f objPos1, final Vec3f objPos2) { if( null == invPMv ) { return false; } - final Vec4f winPos = new Vec4f(winx, winy, winz1, 1f); + final Vec4 winPos = new Vec4(winx, winy, winz1, 1f); // Map x and y from window coordinates winPos.add(-viewport.x(), -viewport.y(), 0f, 0f).mul(1f/viewport.width(), 1f/viewport.height(), 1f, 1f); @@ -1902,9 +1760,9 @@ class Mat4f { winPos.mul(2f, 2f, 2f, 1f).add(-1f, -1f, -1f, 0f); // rawObjPos = Inv(P x Mv) * winPos1 - final Vec4f rawObjPos = invPMv.mulVec4f(winPos, new Vec4f()); + final Vec4 rawObjPos = invPMv.mulVec4(winPos, new Vec4()); - if ( rawObjPos.w() == 0.0f ) { + if ( rawObjPos.w() == zero ) { return false; } objPos1.set( rawObjPos.scale( 1f / rawObjPos.w() ) ); @@ -1916,9 +1774,9 @@ class Mat4f { winPos.setZ( winz2 * 2f - 1f ); // rawObjPos = Inv(P x Mv) * winPos2 - invPMv.mulVec4f(winPos, rawObjPos); + invPMv.mulVec4(winPos, rawObjPos); - if ( rawObjPos.w() == 0.0f ) { + if ( rawObjPos.w() == zero ) { return false; } objPos2.set( rawObjPos.scale( 1f / rawObjPos.w() ) ); @@ -1945,20 +1803,20 @@ class Mat4f { * @param mat4Tmp 16 component matrix for temp storage * @return true if successful, otherwise false (failed to invert matrix, or becomes infinity due to zero z) */ - public static boolean mapWinToObj4(const float winx, const float winy, const float winz, const float clipw, - final Mat4f mMv, final Mat4f mP, + public static boolean mapWinToObj4(const value_type winx, const value_type winy, const value_type winz, const value_type clipw, + final Matrix4 mMv, final Matrix4 mP, final Recti viewport, - const float near, const float far, - final Vec4f objPos, - final Mat4f mat4Tmp) + const value_type near, const value_type far, + final Vec4 objPos, + final Matrix4 mat4Tmp) { // invPMv = Inv(P x Mv) - final Mat4f invPMv = mat4Tmp.mul(mP, mMv); + final Matrix4 invPMv = mat4Tmp.mul(mP, mMv); if( !invPMv.invert() ) { return false; } - final Vec4f winPos = new Vec4f(winx, winy, winz, clipw); + final Vec4 winPos = new Vec4(winx, winy, winz, clipw); // Map x and y from window coordinates winPos.add(-viewport.x(), -viewport.y(), -near, 0f).mul(1f/viewport.width(), 1f/viewport.height(), 1f/(far-near), 1f); @@ -1967,9 +1825,9 @@ class Mat4f { winPos.mul(2f, 2f, 2f, 1f).add(-1f, -1f, -1f, 0f); // objPos = Inv(P x Mv) * winPos - invPMv.mulVec4f(winPos, objPos); + invPMv.mulVec4(winPos, objPos); - if ( objPos.w() == 0.0f ) { + if ( objPos.w() == zero ) { return false; } return true; @@ -1992,16 +1850,16 @@ class Mat4f { * @param obj_pos 4 component object coordinate, the result * @return true if successful, otherwise false (null invert matrix, or becomes infinity due to zero z) */ - public static boolean mapWinToObj4(const float winx, const float winy, const float winz, const float clipw, - final Mat4f invPMv, + public static boolean mapWinToObj4(const value_type winx, const value_type winy, const value_type winz, const value_type clipw, + final Matrix4 invPMv, final Recti viewport, - const float near, const float far, - final Vec4f objPos) + const value_type near, const value_type far, + final Vec4 objPos) { if( null == invPMv ) { return false; } - final Vec4f winPos = new Vec4f(winx, winy, winz, clipw); + final Vec4 winPos = new Vec4(winx, winy, winz, clipw); // Map x and y from window coordinates winPos.add(-viewport.x(), -viewport.y(), -near, 0f).mul(1f/viewport.width(), 1f/viewport.height(), 1f/(far-near), 1f); @@ -2010,9 +1868,9 @@ class Mat4f { winPos.mul(2f, 2f, 2f, 1f).add(-1f, -1f, -1f, 0f); // objPos = Inv(P x Mv) * winPos - invPMv.mulVec4f(winPos, objPos); + invPMv.mulVec4(winPos, objPos); - if ( objPos.w() == 0.0f ) { + if ( objPos.w() == zero ) { return false; } return true; @@ -2021,13 +1879,13 @@ class Mat4f { /** * Map two window coordinates w/ shared X/Y and distinctive Z * to a {@link Ray}. The resulting {@link Ray} maybe used for <i>picking</i> - * using a {@link AABBox#getRayIntersection(vec3f, Ray, float, boolean)}. + * using a {@link AABBox#getRayIntersection(vec3f, Ray, value_type, boolean)}. * <p> * Notes for picking <i>winz0</i> and <i>winz1</i>: * <ul> - * <li>see {@link FloatUtil#getZBufferEpsilon(int, float, float)}</li> - * <li>see {@link FloatUtil#getZBufferValue(int, float, float, float)}</li> - * <li>see {@link FloatUtil#getOrthoWinZ(float, float, float)}</li> + * <li>see {@link FloatUtil#getZBufferEpsilon(int, value_type, value_type)}</li> + * <li>see {@link FloatUtil#getZBufferValue(int, value_type, value_type, value_type)}</li> + * <li>see {@link FloatUtil#getOrthoWinZ(value_type, value_type, value_type)}</li> * </ul> * </p> * @param winx @@ -2042,13 +1900,13 @@ class Mat4f { * @param mat4Tmp2 16 component matrix for temp storage * @return true if successful, otherwise false (failed to invert matrix, or becomes z is infinity) */ - public static boolean mapWinToRay(const float winx, const float winy, const float winz0, const float winz1, - final Mat4f mMv, final Mat4f mP, + public static boolean mapWinToRay(const value_type winx, const value_type winy, const value_type winz0, const value_type winz1, + final Matrix4 mMv, final Matrix4 mP, final Recti viewport, final Ray ray, - final Mat4f mat4Tmp1, final Mat4f mat4Tmp2) { + final Matrix4 mat4Tmp1, final Matrix4 mat4Tmp2) { // invPMv = Inv(P x Mv) - final Mat4f invPMv = mat4Tmp1.mul(mP, mMv); + final Matrix4 invPMv = mat4Tmp1.mul(mP, mMv); if( !invPMv.invert() ) { return false; } @@ -2064,13 +1922,13 @@ class Mat4f { /** * Map two window coordinates w/ shared X/Y and distinctive Z * to a {@link Ray}. The resulting {@link Ray} maybe used for <i>picking</i> - * using a {@link AABBox#getRayIntersection(vec3f, Ray, float, boolean)}. + * using a {@link AABBox#getRayIntersection(vec3f, Ray, value_type, boolean)}. * <p> * Notes for picking <i>winz0</i> and <i>winz1</i>: * <ul> - * <li>see {@link FloatUtil#getZBufferEpsilon(int, float, float)}</li> - * <li>see {@link FloatUtil#getZBufferValue(int, float, float, float)}</li> - * <li>see {@link FloatUtil#getOrthoWinZ(float, float, float)}</li> + * <li>see {@link FloatUtil#getZBufferEpsilon(int, value_type, value_type)}</li> + * <li>see {@link FloatUtil#getZBufferValue(int, value_type, value_type, value_type)}</li> + * <li>see {@link FloatUtil#getOrthoWinZ(value_type, value_type, value_type)}</li> * </ul> * </p> * @param winx @@ -2082,8 +1940,8 @@ class Mat4f { * @param ray storage for the resulting {@link Ray} * @return true if successful, otherwise false (null invert matrix, or becomes z is infinity) */ - public static boolean mapWinToRay(const float winx, const float winy, const float winz0, const float winz1, - final Mat4f invPMv, + public static boolean mapWinToRay(const value_type winx, const value_type winy, const value_type winz0, const value_type winz1, + final Matrix4 invPMv, final Recti viewport, final Ray ray) { if( mapWinToObj(winx, winy, winz0, winz1, invPMv, viewport, ray.orig, ray.dir) ) { @@ -2101,11 +1959,11 @@ class Mat4f { /** * @param sb optional passed StringBuilder instance to be used * @param rowPrefix optional prefix for each row - * @param f the format string of one floating point, i.e. "%10.5f", see {@link java.util.Formatter} + * @param f the format string of one value_typeing point, i.e. "%10.5f", see {@link java.util.Formatter} * @return matrix string representation */ public StringBuilder toString(final StringBuilder sb, final String rowPrefix, final String f) { - const float[] tmp = new float[16]; + const value_type[] tmp = new value_type[16]; this.get(tmp); return FloatUtil.matrixToString(sb, rowPrefix, f,tmp, 0, 4, 4, false /* rowMajorOrder */); } @@ -2119,18 +1977,47 @@ class Mat4f { /** * Returns a formatted string representation of this matrix * @param rowPrefix prefix for each row - * @param f format string for each float element, e.g. "%10.5f" + * @param f format string for each value_type element, e.g. "%10.5f" * @return matrix */ - std::string toString(const std::string& rowPrefix, const std::string& f) const noexcept; + std::string toString(const std::string& rowPrefix, const std::string& f) const noexcept { + std::string sb; + value_type tmp[16]; + get(tmp); + return jau::mat_to_string(sb, rowPrefix, f, tmp, 4, 4, false /* rowMajorOrder */); // creates a copy-out! + } std::string toString() const noexcept { return toString("", "%10.5f"); } }; -std::ostream& operator<<(std::ostream& out, const Mat4f& v) noexcept { +template<typename T, + std::enable_if_t<std::is_floating_point_v<T>, bool> = true> +constexpr Matrix4<T> operator*(const Matrix4<T>& lhs, const Matrix4<T>& rhs ) noexcept { + Matrix4<T> r(lhs); r *= rhs; return r; +} + +template<typename T, + std::enable_if_t<std::is_floating_point_v<T>, bool> = true> +constexpr Matrix4<T> operator*(const Matrix4<T>& lhs, const T s ) noexcept { + Matrix4<T> r(lhs); r *= s; return r; +} + +template<typename T, + std::enable_if_t<std::is_floating_point_v<T>, bool> = true> +constexpr Matrix4<T> operator*(const T s, const Matrix4<T>& rhs) noexcept { + Matrix4<T> r(rhs); r *= s; return r; +} + +template<typename T, + std::enable_if_t<std::is_floating_point_v<T>, bool> = true> +std::ostream& operator<<(std::ostream& out, const Matrix4<T>& v) noexcept { return out << v.toString(); } +typedef Matrix4<float> Mat4f; + +static_assert(alignof(float) == alignof(Mat4f)); + /**@}*/ } // namespace jau::math |