/** * PANDA 3D SOFTWARE * Copyright (c) Carnegie Mellon University. All rights reserved. * * All use of this software is subject to the terms of the revised BSD * license. You should have received a copy of this license along * with this source code in a file named "LICENSE." * * @file lmatrix4_src.I * @author drose * @date 1999-01-15 */ /** * Defines a row-level index accessor to the matrix. */ INLINE_LINMATH FLOATNAME(LMatrix4)::Row:: Row(FLOATTYPE *row) : _row(row) { } /** * */ INLINE_LINMATH FLOATTYPE FLOATNAME(LMatrix4)::Row:: operator [](int i) const { nassertr(i >= 0 && i < 4, 0.0); return _row[i]; } /** * */ INLINE_LINMATH FLOATTYPE &FLOATNAME(LMatrix4)::Row:: operator [](int i) { nassertr(i >= 0 && i < 4, _row[0]); return _row[i]; } /** * Returns 4: the number of columns of a LMatrix4. */ INLINE_LINMATH int FLOATNAME(LMatrix4)::Row:: size() { return 4; } /** * */ INLINE_LINMATH FLOATNAME(LMatrix4)::Row:: operator const FLOATNAME(LVecBase4) &() const { return *(const FLOATNAME(LVecBase4) *)_row; } /** * Defines a row-level constant accessor to the matrix. */ INLINE_LINMATH FLOATNAME(LMatrix4)::CRow:: CRow(const FLOATTYPE *row) : _row(row) { } /** * */ INLINE_LINMATH FLOATTYPE FLOATNAME(LMatrix4)::CRow:: operator [](int i) const { nassertr(i >= 0 && i < 4, 0.0); return _row[i]; } /** * Returns 4: the number of columns of a LMatrix4. */ INLINE_LINMATH int FLOATNAME(LMatrix4)::CRow:: size() { return 4; } /** * */ INLINE_LINMATH FLOATNAME(LMatrix4)::CRow:: operator const FLOATNAME(LVecBase4) &() const { return *(const FLOATNAME(LVecBase4) *)_row; } /** * Returns an identity matrix. * * This function definition must appear first, since some inline functions * below take advantage of it. */ INLINE_LINMATH const FLOATNAME(LMatrix4) &FLOATNAME(LMatrix4):: ident_mat() { return _ident_mat; } /** * Returns an matrix filled with ones. */ INLINE_LINMATH const FLOATNAME(LMatrix4) &FLOATNAME(LMatrix4):: ones_mat() { return _ones_mat; } /** * Returns an matrix filled with zeros. */ INLINE_LINMATH const FLOATNAME(LMatrix4) &FLOATNAME(LMatrix4):: zeros_mat() { return _zeros_mat; } /** * */ INLINE_LINMATH FLOATNAME(LMatrix4):: FLOATNAME(LMatrix4)() { } /** * */ INLINE_LINMATH FLOATNAME(LMatrix4):: FLOATNAME(LMatrix4)(const FLOATNAME(LMatrix4) ©) : _m(copy._m) { } /** * */ INLINE_LINMATH FLOATNAME(LMatrix4):: FLOATNAME(LMatrix4)(const FLOATNAME(UnalignedLMatrix4) ©) { operator = (copy); } /** * */ INLINE_LINMATH FLOATNAME(LMatrix4) &FLOATNAME(LMatrix4):: operator = (const FLOATNAME(LMatrix4) ©) { TAU_PROFILE("void LMatrix4::operator = (const LMatrix4 &)", " ", TAU_USER); _m = copy._m; return *this; } /** * */ INLINE_LINMATH FLOATNAME(LMatrix4) &FLOATNAME(LMatrix4):: operator = (const FLOATNAME(UnalignedLMatrix4) ©) { TAU_PROFILE("void LMatrix4::operator = (const UnalignedLMatrix4 &)", " ", TAU_USER); memcpy(&_m(0, 0), copy.get_data(), sizeof(FLOATTYPE) * num_components); return *this; } /** * */ INLINE_LINMATH FLOATNAME(LMatrix4) &FLOATNAME(LMatrix4):: operator = (FLOATTYPE fill_value) { fill(fill_value); return *this; } /** * */ INLINE_LINMATH FLOATNAME(LMatrix4):: FLOATNAME(LMatrix4)(FLOATTYPE e00, FLOATTYPE e01, FLOATTYPE e02, FLOATTYPE e03, FLOATTYPE e10, FLOATTYPE e11, FLOATTYPE e12, FLOATTYPE e13, FLOATTYPE e20, FLOATTYPE e21, FLOATTYPE e22, FLOATTYPE e23, FLOATTYPE e30, FLOATTYPE e31, FLOATTYPE e32, FLOATTYPE e33) { TAU_PROFILE("LMatrix4::LMatrix4(FLOATTYPE, ...)", " ", TAU_USER); _m(0, 0) = e00; _m(0, 1) = e01; _m(0, 2) = e02; _m(0, 3) = e03; _m(1, 0) = e10; _m(1, 1) = e11; _m(1, 2) = e12; _m(1, 3) = e13; _m(2, 0) = e20; _m(2, 1) = e21; _m(2, 2) = e22; _m(2, 3) = e23; _m(3, 0) = e30; _m(3, 1) = e31; _m(3, 2) = e32; _m(3, 3) = e33; } /** * Constructs the matrix from four individual rows. */ INLINE_LINMATH FLOATNAME(LMatrix4):: FLOATNAME(LMatrix4)(const FLOATNAME(LVecBase4) &row0, const FLOATNAME(LVecBase4) &row1, const FLOATNAME(LVecBase4) &row2, const FLOATNAME(LVecBase4) &row3) { TAU_PROFILE("LMatrix4::LMatrix4(const LVecBase4 &, ...)", " ", TAU_USER); #ifdef HAVE_EIGEN _m.row(0) = row0._v; _m.row(1) = row1._v; _m.row(2) = row2._v; _m.row(3) = row3._v; #else _m(0, 0) = row0._v(0); _m(0, 1) = row0._v(1); _m(0, 2) = row0._v(2); _m(0, 3) = row0._v(3); _m(1, 0) = row1._v(0); _m(1, 1) = row1._v(1); _m(1, 2) = row1._v(2); _m(1, 3) = row1._v(3); _m(2, 0) = row2._v(0); _m(2, 1) = row2._v(1); _m(2, 2) = row2._v(2); _m(2, 3) = row2._v(3); _m(3, 0) = row3._v(0); _m(3, 1) = row3._v(1); _m(3, 2) = row3._v(2); _m(3, 3) = row3._v(3); #endif // HAVE_EIGEN } /** * */ INLINE_LINMATH FLOATNAME(LMatrix4):: FLOATNAME(LMatrix4)(const FLOATNAME(LMatrix3) &upper3) { TAU_PROFILE("void LMatrix4::LMatrix4(const LMatrix3 &)", " ", TAU_USER); _m(0, 0) = upper3._m(0, 0); _m(0, 1) = upper3._m(0, 1); _m(0, 2) = upper3._m(0, 2); _m(0, 3) = 0.0f; _m(1, 0) = upper3._m(1, 0); _m(1, 1) = upper3._m(1, 1); _m(1, 2) = upper3._m(1, 2); _m(1, 3) = 0.0f; _m(2, 0) = upper3._m(2, 0); _m(2, 1) = upper3._m(2, 1); _m(2, 2) = upper3._m(2, 2); _m(2, 3) = 0.0f; _m(3, 0) = 0.0f; _m(3, 1) = 0.0f; _m(3, 2) = 0.0f; _m(3, 3) = 1.0f; } /** * */ INLINE_LINMATH FLOATNAME(LMatrix4):: FLOATNAME(LMatrix4)(const FLOATNAME(LMatrix3) &upper3, const FLOATNAME(LVecBase3) &trans) { TAU_PROFILE("void LMatrix4::LMatrix4(upper3, const LVecBase3 &)", " ", TAU_USER); _m(0, 0) = upper3._m(0, 0); _m(0, 1) = upper3._m(0, 1); _m(0, 2) = upper3._m(0, 2); _m(0, 3) = 0.0f; _m(1, 0) = upper3._m(1, 0); _m(1, 1) = upper3._m(1, 1); _m(1, 2) = upper3._m(1, 2); _m(1, 3) = 0.0f; _m(2, 0) = upper3._m(2, 0); _m(2, 1) = upper3._m(2, 1); _m(2, 2) = upper3._m(2, 2); _m(2, 3) = 0.0f; _m(3, 0) = trans._v(0); _m(3, 1) = trans._v(1); _m(3, 2) = trans._v(2); _m(3, 3) = 1.0f; } /** * Sets each element of the matrix to the indicated fill_value. This is of * questionable value, but is sometimes useful when initializing to zero. */ INLINE_LINMATH void FLOATNAME(LMatrix4):: fill(FLOATTYPE fill_value) { TAU_PROFILE("void LMatrix4::fill(FLOATTYPE)", " ", TAU_USER); #ifdef HAVE_EIGEN _m = EMatrix4::Constant(fill_value); #else set(fill_value, fill_value, fill_value, fill_value, fill_value, fill_value, fill_value, fill_value, fill_value, fill_value, fill_value, fill_value, fill_value, fill_value, fill_value, fill_value); #endif // HAVE_EIGEN } /** * */ INLINE_LINMATH void FLOATNAME(LMatrix4):: set(FLOATTYPE e00, FLOATTYPE e01, FLOATTYPE e02, FLOATTYPE e03, FLOATTYPE e10, FLOATTYPE e11, FLOATTYPE e12, FLOATTYPE e13, FLOATTYPE e20, FLOATTYPE e21, FLOATTYPE e22, FLOATTYPE e23, FLOATTYPE e30, FLOATTYPE e31, FLOATTYPE e32, FLOATTYPE e33) { TAU_PROFILE("void LMatrix4::set(FLOATTYPE, ...)", " ", TAU_USER); _m(0, 0) = e00; _m(0, 1) = e01; _m(0, 2) = e02; _m(0, 3) = e03; _m(1, 0) = e10; _m(1, 1) = e11; _m(1, 2) = e12; _m(1, 3) = e13; _m(2, 0) = e20; _m(2, 1) = e21; _m(2, 2) = e22; _m(2, 3) = e23; _m(3, 0) = e30; _m(3, 1) = e31; _m(3, 2) = e32; _m(3, 3) = e33; } /** * Sets the upper 3x3 submatrix. */ INLINE_LINMATH void FLOATNAME(LMatrix4):: set_upper_3(const FLOATNAME(LMatrix3) &upper3) { TAU_PROFILE("void LMatrix4::set_upper_3(const LMatrix3 &)", " ", TAU_USER); #ifdef HAVE_EIGEN _m.block<3, 3>(0, 0) = upper3._m; #else _m(0, 0) = upper3(0, 0); _m(0, 1) = upper3(0, 1); _m(0, 2) = upper3(0, 2); _m(1, 0) = upper3(1, 0); _m(1, 1) = upper3(1, 1); _m(1, 2) = upper3(1, 2); _m(2, 0) = upper3(2, 0); _m(2, 1) = upper3(2, 1); _m(2, 2) = upper3(2, 2); #endif // HAVE_EIGEN } /** * Retrieves the upper 3x3 submatrix. */ INLINE_LINMATH FLOATNAME(LMatrix3) FLOATNAME(LMatrix4):: get_upper_3() const { TAU_PROFILE("LMatrix3 LMatrix4::get_upper_3()", " ", TAU_USER); #ifdef HAVE_EIGEN return FLOATNAME(LMatrix3)(_m.block<3, 3>(0, 0)); #else return FLOATNAME(LMatrix3) (_m(0, 0), _m(0, 1), _m(0, 2), _m(1, 0), _m(1, 1), _m(1, 2), _m(2, 0), _m(2, 1), _m(2, 2)); #endif // HAVE_EIGEN } /** * Replaces the indicated row of the matrix. */ INLINE_LINMATH void FLOATNAME(LMatrix4):: set_row(int row, const FLOATNAME(LVecBase4) &v) { #ifdef HAVE_EIGEN _m.row(row) = v._v; #else (*this)(row, 0) = v._v(0); (*this)(row, 1) = v._v(1); (*this)(row, 2) = v._v(2); (*this)(row, 3) = v._v(3); #endif // HAVE_EIGEN } /** * Replaces the indicated column of the matrix. */ INLINE_LINMATH void FLOATNAME(LMatrix4):: set_col(int col, const FLOATNAME(LVecBase4) &v) { #ifdef HAVE_EIGEN _m.col(col) = v._v; #else (*this)(0, col) = v._v(0); (*this)(1, col) = v._v(1); (*this)(2, col) = v._v(2); (*this)(3, col) = v._v(3); #endif // HAVE_EIGEN } /** * Replaces the indicated row of the matrix with the indicated 3-component * vector, ignoring the last column. */ INLINE_LINMATH void FLOATNAME(LMatrix4):: set_row(int row, const FLOATNAME(LVecBase3) &v) { #ifdef HAVE_EIGEN _m.block<1, 3>(row, 0) = v._v; #else (*this)(row, 0) = v._v(0); (*this)(row, 1) = v._v(1); (*this)(row, 2) = v._v(2); #endif // HAVE_EIGEN } /** * Replaces the indicated column of the matrix with the indicated 3-component * vector, ignoring the last row. */ INLINE_LINMATH void FLOATNAME(LMatrix4):: set_col(int col, const FLOATNAME(LVecBase3) &v) { #ifdef HAVE_EIGEN _m.block<3, 1>(0, col) = v._v; #else (*this)(0, col) = v._v(0); (*this)(1, col) = v._v(1); (*this)(2, col) = v._v(2); #endif } /** * Retrieves the indicated row of the matrix as a 4-component vector. */ INLINE_LINMATH FLOATNAME(LVecBase4) FLOATNAME(LMatrix4):: get_row(int row) const { #ifdef HAVE_EIGEN return FLOATNAME(LVecBase4)(_m.row(row)); #else return FLOATNAME(LVecBase4)((*this)(row, 0), (*this)(row, 1), (*this)(row, 2), (*this)(row, 3)); #endif // HAVE_EIGEN } /** * Stores the indicated row of the matrix as a 4-component vector. */ INLINE_LINMATH void FLOATNAME(LMatrix4):: get_row(FLOATNAME(LVecBase4) &result_vec, int row) const { #ifdef HAVE_EIGEN result_vec._v = _m.row(row); #else result_vec._v(0) = (*this)(row, 0); result_vec._v(1) = (*this)(row, 1); result_vec._v(2) = (*this)(row, 2); result_vec._v(3) = (*this)(row, 3); #endif // HAVE_EIGEN } /** * Retrieves the indicated column of the matrix as a 4-component vector. */ INLINE_LINMATH FLOATNAME(LVecBase4) FLOATNAME(LMatrix4):: get_col(int col) const { #ifdef HAVE_EIGEN return FLOATNAME(LVecBase4)(_m.col(col)); #else return FLOATNAME(LVecBase4)((*this)(0, col), (*this)(1, col), (*this)(2, col), (*this)(3, col)); #endif // HAVE_EIGEN } /** * Retrieves the row column of the matrix as a 3-component vector, ignoring * the last column. */ INLINE_LINMATH FLOATNAME(LVecBase3) FLOATNAME(LMatrix4):: get_row3(int row) const { return FLOATNAME(LVecBase3)((*this)(row, 0), (*this)(row, 1), (*this)(row, 2)); } /** * Stores the row column of the matrix as a 3-component vector, ignoring the * last column. */ INLINE_LINMATH void FLOATNAME(LMatrix4):: get_row3(FLOATNAME(LVecBase3) &result_vec,int row) const { #ifdef HAVE_EIGEN result_vec._v = _m.block<1, 3>(row, 0); #else result_vec._v(0) = (*this)(row, 0); result_vec._v(1) = (*this)(row, 1); result_vec._v(2) = (*this)(row, 2); #endif // HAVE_EIGEN } /** * Retrieves the indicated column of the matrix as a 3-component vector, * ignoring the last row. */ INLINE_LINMATH FLOATNAME(LVecBase3) FLOATNAME(LMatrix4):: get_col3(int col) const { return FLOATNAME(LVecBase3)((*this)(0, col), (*this)(1, col), (*this)(2, col)); } /** * */ INLINE_LINMATH FLOATTYPE &FLOATNAME(LMatrix4):: operator () (int row, int col) { nassertr(row >= 0 && row < 4 && col >= 0 && col < 4, _m(0, 0)); return _m(row, col); } /** * */ INLINE_LINMATH FLOATTYPE FLOATNAME(LMatrix4):: operator () (int row, int col) const { nassertr(row >= 0 && row < 4 && col >= 0 && col < 4, _m(0, 0)); return _m(row, col); } /** * */ INLINE_LINMATH FLOATNAME(LMatrix4)::CRow FLOATNAME(LMatrix4):: operator [](int i) const { nassertr(i >= 0 && i < 4, CRow(&_m(0, 0))); return CRow(&_m(i, 0)); } /** * */ INLINE_LINMATH FLOATNAME(LMatrix4)::Row FLOATNAME(LMatrix4):: operator [](int i) { nassertr(i >= 0 && i < 4, Row(&_m(0, 0))); return Row(&_m(i, 0)); } /** * Returns 4: the number of rows of a LMatrix4. */ INLINE_LINMATH int FLOATNAME(LMatrix4):: size() { return 4; } /** * Returns true if any component of the matrix is not-a-number, false * otherwise. */ INLINE_LINMATH bool FLOATNAME(LMatrix4):: is_nan() const { TAU_PROFILE("bool LMatrix4::is_nan()", " ", TAU_USER); return cnan(_m(0, 0)) || cnan(_m(0, 1)) || cnan(_m(0, 2)) || cnan(_m(0, 3)) || cnan(_m(1, 0)) || cnan(_m(1, 1)) || cnan(_m(1, 2)) || cnan(_m(1, 3)) || cnan(_m(2, 0)) || cnan(_m(2, 1)) || cnan(_m(2, 2)) || cnan(_m(2, 3)) || cnan(_m(3, 0)) || cnan(_m(3, 1)) || cnan(_m(3, 2)) || cnan(_m(3, 3)); } /** * Returns true if this is (close enough to) the identity matrix, false * otherwise. */ INLINE_LINMATH bool FLOATNAME(LMatrix4):: is_identity() const { // Eigen has isIdentity, but it seems to be twice as slow as this. return almost_equal(ident_mat(), NEARLY_ZERO(FLOATTYPE)); } /** * Returns a particular element of the matrix. */ INLINE_LINMATH FLOATTYPE FLOATNAME(LMatrix4):: get_cell(int row, int col) const { nassertr(row >= 0 && row < 4 && col >= 0 && col < 4, 0.0f); return _m(row, col); } /** * Changes a particular element of the matrix. */ INLINE_LINMATH void FLOATNAME(LMatrix4):: set_cell(int row, int col, FLOATTYPE value) { nassertv(row >= 0 && row < 4 && col >= 0 && col < 4); _m(row, col) = value; } /** * Returns the address of the first of the nine data elements in the matrix. * The remaining elements occupy the next eight positions in row-major order. */ INLINE_LINMATH const FLOATTYPE *FLOATNAME(LMatrix4):: get_data() const { return &_m(0, 0); } /** * Returns the number of elements in the matrix, 16. */ INLINE_LINMATH int FLOATNAME(LMatrix4):: get_num_components() const { return 16; } /** * Returns an iterator that may be used to traverse the elements of the * matrix, STL-style. */ INLINE_LINMATH FLOATNAME(LMatrix4)::iterator FLOATNAME(LMatrix4):: begin() { return &_m(0); } /** * Returns an iterator that may be used to traverse the elements of the * matrix, STL-style. */ INLINE_LINMATH FLOATNAME(LMatrix4)::iterator FLOATNAME(LMatrix4):: end() { return begin() + 16; } /** * Returns an iterator that may be used to traverse the elements of the * matrix, STL-style. */ INLINE_LINMATH FLOATNAME(LMatrix4)::const_iterator FLOATNAME(LMatrix4):: begin() const { return &_m(0); } /** * Returns an iterator that may be used to traverse the elements of the * matrix, STL-style. */ INLINE_LINMATH FLOATNAME(LMatrix4)::const_iterator FLOATNAME(LMatrix4):: end() const { return begin() + 16; } /** * This performs a lexicographical comparison. It's of questionable * mathematical meaning, but sometimes has a practical purpose for sorting * unique vectors, especially in an STL container. Also see compare_to(). */ INLINE_LINMATH bool FLOATNAME(LMatrix4):: operator < (const FLOATNAME(LMatrix4) &other) const { return compare_to(other) < 0; } /** * */ INLINE_LINMATH bool FLOATNAME(LMatrix4):: operator == (const FLOATNAME(LMatrix4) &other) const { return compare_to(other) == 0; } /** * */ INLINE_LINMATH bool FLOATNAME(LMatrix4):: operator != (const FLOATNAME(LMatrix4) &other) const { return compare_to(other) != 0; } /** * This flavor of compare_to uses a default threshold value based on the * numeric type. */ INLINE_LINMATH int FLOATNAME(LMatrix4):: compare_to(const FLOATNAME(LMatrix4) &other) const { return compare_to(other, NEARLY_ZERO(FLOATTYPE)); } /** * Returns a suitable hash for phash_map. */ INLINE_LINMATH size_t FLOATNAME(LMatrix4):: get_hash() const { return add_hash(0); } /** * Returns a suitable hash for phash_map. */ INLINE_LINMATH size_t FLOATNAME(LMatrix4):: get_hash(FLOATTYPE threshold) const { return add_hash(0, threshold); } /** * Adds the vector into the running hash. */ INLINE_LINMATH size_t FLOATNAME(LMatrix4):: add_hash(size_t hash) const { return add_hash(hash, NEARLY_ZERO(FLOATTYPE)); } /** * Adds the vector into the running hash. */ INLINE_LINMATH size_t FLOATNAME(LMatrix4):: add_hash(size_t hash, FLOATTYPE threshold) const { TAU_PROFILE("size_t LMatrix4::add_hash(size_t, FLOATTYPE)", " ", TAU_USER); float_hash fhasher(threshold); hash = fhasher.add_hash(hash, _m(0, 0)); hash = fhasher.add_hash(hash, _m(0, 1)); hash = fhasher.add_hash(hash, _m(0, 2)); hash = fhasher.add_hash(hash, _m(0, 3)); hash = fhasher.add_hash(hash, _m(1, 0)); hash = fhasher.add_hash(hash, _m(1, 1)); hash = fhasher.add_hash(hash, _m(1, 2)); hash = fhasher.add_hash(hash, _m(1, 3)); hash = fhasher.add_hash(hash, _m(2, 0)); hash = fhasher.add_hash(hash, _m(2, 1)); hash = fhasher.add_hash(hash, _m(2, 2)); hash = fhasher.add_hash(hash, _m(2, 3)); hash = fhasher.add_hash(hash, _m(3, 0)); hash = fhasher.add_hash(hash, _m(3, 1)); hash = fhasher.add_hash(hash, _m(3, 2)); hash = fhasher.add_hash(hash, _m(3, 3)); return hash; } #define VECTOR4_MATRIX4_PRODUCT(v_res, v, mat) \ v_res._v(0) = v._v(0)*mat._m(0, 0) + v._v(1)*mat._m(1, 0) + v._v(2)*mat._m(2, 0) + v._v(3)*mat._m(3, 0); \ v_res._v(1) = v._v(0)*mat._m(0, 1) + v._v(1)*mat._m(1, 1) + v._v(2)*mat._m(2, 1) + v._v(3)*mat._m(3, 1); \ v_res._v(2) = v._v(0)*mat._m(0, 2) + v._v(1)*mat._m(1, 2) + v._v(2)*mat._m(2, 2) + v._v(3)*mat._m(3, 2); \ v_res._v(3) = v._v(0)*mat._m(0, 3) + v._v(1)*mat._m(1, 3) + v._v(2)*mat._m(2, 3) + v._v(3)*mat._m(3, 3); /** * 4-component vector or point times matrix. This is a fully general * operation. */ INLINE_LINMATH FLOATNAME(LVecBase4) FLOATNAME(LMatrix4):: xform(const FLOATNAME(LVecBase4) &v) const { TAU_PROFILE("LVecBase3 LMatrix4::xform(const LVecBase3 &)", " ", TAU_USER); FLOATNAME(LVecBase4) v_res; #ifdef HAVE_EIGEN v_res._v.noalias() = v._v * _m; #else VECTOR4_MATRIX4_PRODUCT(v_res, v,(*this)); #endif // HAVE_EIGEN return v_res; } #undef VECTOR4_MATRIX4_PRODUCT /** * The matrix transforms a 3-component point (including translation component) * and returns the result. This assumes the matrix is an affine transform. */ INLINE_LINMATH FLOATNAME(LVecBase3) FLOATNAME(LMatrix4):: xform_point(const FLOATNAME(LVecBase3) &v) const { TAU_PROFILE("LVecBase3 LMatrix4::xform_point(const LVecBase3 &)", " ", TAU_USER); FLOATNAME(LVecBase3) v_res; // v._v(3) == 1.0f for this case #ifdef HAVE_EIGEN v_res._v.noalias() = v._v * _m.block<3, 3>(0, 0) + _m.block<1, 3>(3, 0); #else v_res._v(0) = v._v(0)*_m(0, 0) + v._v(1)*_m(1, 0) + v._v(2)*_m(2, 0) + _m(3, 0); v_res._v(1) = v._v(0)*_m(0, 1) + v._v(1)*_m(1, 1) + v._v(2)*_m(2, 1) + _m(3, 1); v_res._v(2) = v._v(0)*_m(0, 2) + v._v(1)*_m(1, 2) + v._v(2)*_m(2, 2) + _m(3, 2); #endif // HAVE_EIGEN return v_res; } /** * The matrix transforms a 3-component point (including translation component) * and returns the result, as a fully general operation. */ INLINE_LINMATH FLOATNAME(LVecBase3) FLOATNAME(LMatrix4):: xform_point_general(const FLOATNAME(LVecBase3) &v) const { TAU_PROFILE("LVecBase3 LMatrix4::xform_point_general(const LVecBase3 &)", " ", TAU_USER); FLOATNAME(LVecBase4) v4(v[0], v[1], v[2], 1.0); v4 = xform(v4); return FLOATNAME(LVecBase3)(v4[0] / v4[3], v4[1] / v4[3], v4[2] / v4[3]); } /** * The matrix transforms a 3-component vector (without translation component) * and returns the result. This assumes the matrix is an orthonormal * transform. */ INLINE_LINMATH FLOATNAME(LVecBase3) FLOATNAME(LMatrix4):: xform_vec(const FLOATNAME(LVecBase3) &v) const { TAU_PROFILE("LVecBase3 LMatrix4::xform_vec(const LVecBase3 &)", " ", TAU_USER); FLOATNAME(LVecBase3) v_res; // v._v(3) == 0.0f for this case #ifdef HAVE_EIGEN v_res._v.noalias() = v._v * _m.block<3, 3>(0, 0); #else v_res._v(0) = v._v(0)*_m(0, 0) + v._v(1)*_m(1, 0) + v._v(2)*_m(2, 0); v_res._v(1) = v._v(0)*_m(0, 1) + v._v(1)*_m(1, 1) + v._v(2)*_m(2, 1); v_res._v(2) = v._v(0)*_m(0, 2) + v._v(1)*_m(1, 2) + v._v(2)*_m(2, 2); #endif // HAVE_EIGEN return v_res; } /** * The matrix transforms a 3-component vector (without translation component) * and returns the result, as a fully general operation. */ INLINE_LINMATH FLOATNAME(LVecBase3) FLOATNAME(LMatrix4):: xform_vec_general(const FLOATNAME(LVecBase3) &v) const { TAU_PROFILE("LVecBase3 LMatrix4::xform_vec_general(const LVecBase3 &)", " ", TAU_USER); #ifdef HAVE_EIGEN return FLOATNAME(LVecBase3)(v._v * _m.block<3, 3>(0, 0).inverse().transpose()); #else FLOATNAME(LMatrix3) i; i.invert_transpose_from(*this); return i.xform(v); #endif // HAVE_EIGEN } /** * 4-component vector or point times matrix. This is a fully general * operation. */ INLINE_LINMATH void FLOATNAME(LMatrix4):: xform_in_place(FLOATNAME(LVecBase4) &v) const { TAU_PROFILE("void LMatrix4::xform_in_place(LVecBase3 &)", " ", TAU_USER); #ifdef HAVE_EIGEN v._v = v._v * _m; #else v = xform(v); #endif // HAVE_EIGEN } /** * The matrix transforms a 3-component point (including translation * component). This assumes the matrix is an affine transform. */ INLINE_LINMATH void FLOATNAME(LMatrix4):: xform_point_in_place(FLOATNAME(LVecBase3) &v) const { TAU_PROFILE("void LMatrix4::xform_point_in_place(LVecBase3 &)", " ", TAU_USER); // v._v(3) == 1.0f for this case #ifdef HAVE_EIGEN v._v = v._v * _m.block<3, 3>(0, 0) + _m.block<1, 3>(3, 0); #else v = xform_point(v); #endif // HAVE_EIGEN } /** * The matrix transforms a 3-component point (including translation * component), as a fully general operation. */ INLINE_LINMATH void FLOATNAME(LMatrix4):: xform_point_general_in_place(FLOATNAME(LVecBase3) &v) const { TAU_PROFILE("void LMatrix4::xform_point_general_in_place(LVecBase3 &)", " ", TAU_USER); v = xform_point_general(v); } /** * The matrix transforms a 3-component vector (without translation component). * This assumes the matrix is an orthonormal transform. */ INLINE_LINMATH void FLOATNAME(LMatrix4):: xform_vec_in_place(FLOATNAME(LVecBase3) &v) const { TAU_PROFILE("void LMatrix4::xform_vec_in_place(LVecBase3 &)", " ", TAU_USER); // v._v(3) == 0.0f for this case #ifdef HAVE_EIGEN v._v = v._v * _m.block<3, 3>(0, 0); #else v = xform_vec(v); #endif // HAVE_EIGEN } /** * The matrix transforms a 3-component vector (without translation component), * as a fully general operation. */ INLINE_LINMATH void FLOATNAME(LMatrix4):: xform_vec_general_in_place(FLOATNAME(LVecBase3) &v) const { TAU_PROFILE("void LMatrix4::xform_vec_general_in_place(LVecBase3 &)", " ", TAU_USER); #ifdef HAVE_EIGEN v._v = v._v * _m.block<3, 3>(0, 0).inverse().transpose(); #else v = xform_vec_general(v); #endif // HAVE_EIGEN } #define MATRIX4_PRODUCT(res, a, b) \ res._m(0, 0) = a._m(0, 0)*b._m(0, 0) + a._m(0, 1)*b._m(1, 0) + a._m(0, 2)*b._m(2, 0) + a._m(0, 3)*b._m(3, 0); \ res._m(0, 1) = a._m(0, 0)*b._m(0, 1) + a._m(0, 1)*b._m(1, 1) + a._m(0, 2)*b._m(2, 1) + a._m(0, 3)*b._m(3, 1); \ res._m(0, 2) = a._m(0, 0)*b._m(0, 2) + a._m(0, 1)*b._m(1, 2) + a._m(0, 2)*b._m(2, 2) + a._m(0, 3)*b._m(3, 2); \ res._m(0, 3) = a._m(0, 0)*b._m(0, 3) + a._m(0, 1)*b._m(1, 3) + a._m(0, 2)*b._m(2, 3) + a._m(0, 3)*b._m(3, 3); \ \ res._m(1, 0) = a._m(1, 0)*b._m(0, 0) + a._m(1, 1)*b._m(1, 0) + a._m(1, 2)*b._m(2, 0) + a._m(1, 3)*b._m(3, 0); \ res._m(1, 1) = a._m(1, 0)*b._m(0, 1) + a._m(1, 1)*b._m(1, 1) + a._m(1, 2)*b._m(2, 1) + a._m(1, 3)*b._m(3, 1); \ res._m(1, 2) = a._m(1, 0)*b._m(0, 2) + a._m(1, 1)*b._m(1, 2) + a._m(1, 2)*b._m(2, 2) + a._m(1, 3)*b._m(3, 2); \ res._m(1, 3) = a._m(1, 0)*b._m(0, 3) + a._m(1, 1)*b._m(1, 3) + a._m(1, 2)*b._m(2, 3) + a._m(1, 3)*b._m(3, 3); \ \ res._m(2, 0) = a._m(2, 0)*b._m(0, 0) + a._m(2, 1)*b._m(1, 0) + a._m(2, 2)*b._m(2, 0) + a._m(2, 3)*b._m(3, 0); \ res._m(2, 1) = a._m(2, 0)*b._m(0, 1) + a._m(2, 1)*b._m(1, 1) + a._m(2, 2)*b._m(2, 1) + a._m(2, 3)*b._m(3, 1); \ res._m(2, 2) = a._m(2, 0)*b._m(0, 2) + a._m(2, 1)*b._m(1, 2) + a._m(2, 2)*b._m(2, 2) + a._m(2, 3)*b._m(3, 2); \ res._m(2, 3) = a._m(2, 0)*b._m(0, 3) + a._m(2, 1)*b._m(1, 3) + a._m(2, 2)*b._m(2, 3) + a._m(2, 3)*b._m(3, 3); \ \ res._m(3, 0) = a._m(3, 0)*b._m(0, 0) + a._m(3, 1)*b._m(1, 0) + a._m(3, 2)*b._m(2, 0) + a._m(3, 3)*b._m(3, 0); \ res._m(3, 1) = a._m(3, 0)*b._m(0, 1) + a._m(3, 1)*b._m(1, 1) + a._m(3, 2)*b._m(2, 1) + a._m(3, 3)*b._m(3, 1); \ res._m(3, 2) = a._m(3, 0)*b._m(0, 2) + a._m(3, 1)*b._m(1, 2) + a._m(3, 2)*b._m(2, 2) + a._m(3, 3)*b._m(3, 2); \ res._m(3, 3) = a._m(3, 0)*b._m(0, 3) + a._m(3, 1)*b._m(1, 3) + a._m(3, 2)*b._m(2, 3) + a._m(3, 3)*b._m(3, 3); /** * */ INLINE_LINMATH FLOATNAME(LMatrix4) FLOATNAME(LMatrix4):: operator * (const FLOATNAME(LMatrix4) &other) const { TAU_PROFILE("LMatrix4 LMatrix4::operator *(const LMatrix4 &)", " ", TAU_USER); FLOATNAME(LMatrix4) t; t.multiply(*this, other); return t; } // this = other1 * other2 INLINE_LINMATH void FLOATNAME(LMatrix4):: multiply(const FLOATNAME(LMatrix4) &other1, const FLOATNAME(LMatrix4) &other2) { TAU_PROFILE("LMatrix4 multiply(const LMatrix4 &, const LMatrix4 &)", " ", TAU_USER); // faster than operator * since it writes result in place, avoiding extra // copying this will fail if you try to mat.multiply(mat,other_mat) nassertv((&other1 != this) && (&other2 != this)); #ifdef HAVE_EIGEN _m.noalias() = other1._m * other2._m; #else MATRIX4_PRODUCT((*this),other1,other2); #endif // HAVE_EIGEN } #undef MATRIX4_PRODUCT /** * */ INLINE_LINMATH FLOATNAME(LMatrix4) FLOATNAME(LMatrix4):: operator * (FLOATTYPE scalar) const { TAU_PROFILE("LMatrix4 operator *(const LMatrix4 &, FLOATTYPE)", " ", TAU_USER); FLOATNAME(LMatrix4) t; #ifdef HAVE_EIGEN t._m = _m * scalar; #else t._m(0, 0) = _m(0, 0) * scalar; t._m(0, 1) = _m(0, 1) * scalar; t._m(0, 2) = _m(0, 2) * scalar; t._m(0, 3) = _m(0, 3) * scalar; t._m(1, 0) = _m(1, 0) * scalar; t._m(1, 1) = _m(1, 1) * scalar; t._m(1, 2) = _m(1, 2) * scalar; t._m(1, 3) = _m(1, 3) * scalar; t._m(2, 0) = _m(2, 0) * scalar; t._m(2, 1) = _m(2, 1) * scalar; t._m(2, 2) = _m(2, 2) * scalar; t._m(2, 3) = _m(2, 3) * scalar; t._m(3, 0) = _m(3, 0) * scalar; t._m(3, 1) = _m(3, 1) * scalar; t._m(3, 2) = _m(3, 2) * scalar; t._m(3, 3) = _m(3, 3) * scalar; #endif // HAVE_EIGEN return t; } /** * */ INLINE_LINMATH FLOATNAME(LMatrix4) FLOATNAME(LMatrix4):: operator / (FLOATTYPE scalar) const { FLOATTYPE recip_scalar = 1.0f/scalar; return (*this) * recip_scalar; } /** * Performs a memberwise addition between two matrices. */ INLINE_LINMATH FLOATNAME(LMatrix4) &FLOATNAME(LMatrix4):: operator += (const FLOATNAME(LMatrix4) &other) { TAU_PROFILE("LMatrix4 LMatrix4::operator +=(const LMatrix4 &)", " ", TAU_USER); #ifdef HAVE_EIGEN _m += other._m; #else _m(0, 0) += other._m(0, 0); _m(0, 1) += other._m(0, 1); _m(0, 2) += other._m(0, 2); _m(0, 3) += other._m(0, 3); _m(1, 0) += other._m(1, 0); _m(1, 1) += other._m(1, 1); _m(1, 2) += other._m(1, 2); _m(1, 3) += other._m(1, 3); _m(2, 0) += other._m(2, 0); _m(2, 1) += other._m(2, 1); _m(2, 2) += other._m(2, 2); _m(2, 3) += other._m(2, 3); _m(3, 0) += other._m(3, 0); _m(3, 1) += other._m(3, 1); _m(3, 2) += other._m(3, 2); _m(3, 3) += other._m(3, 3); #endif // HAVE_EIGEN return *this; } /** * Performs a memberwise addition between two matrices. */ INLINE_LINMATH FLOATNAME(LMatrix4) &FLOATNAME(LMatrix4):: operator -= (const FLOATNAME(LMatrix4) &other) { TAU_PROFILE("LMatrix4 LMatrix4::operator -=(const LMatrix4 &)", " ", TAU_USER); #ifdef HAVE_EIGEN _m -= other._m; #else _m(0, 0) -= other._m(0, 0); _m(0, 1) -= other._m(0, 1); _m(0, 2) -= other._m(0, 2); _m(0, 3) -= other._m(0, 3); _m(1, 0) -= other._m(1, 0); _m(1, 1) -= other._m(1, 1); _m(1, 2) -= other._m(1, 2); _m(1, 3) -= other._m(1, 3); _m(2, 0) -= other._m(2, 0); _m(2, 1) -= other._m(2, 1); _m(2, 2) -= other._m(2, 2); _m(2, 3) -= other._m(2, 3); _m(3, 0) -= other._m(3, 0); _m(3, 1) -= other._m(3, 1); _m(3, 2) -= other._m(3, 2); _m(3, 3) -= other._m(3, 3); #endif // HAVE_EIGEN return *this; } /** * */ INLINE_LINMATH FLOATNAME(LMatrix4) &FLOATNAME(LMatrix4):: operator *= (const FLOATNAME(LMatrix4) &other) { TAU_PROFILE("LMatrix4 LMatrix4::operator *=(const LMatrix4 &)", " ", TAU_USER); #ifdef HAVE_EIGEN _m *= other._m; #else FLOATNAME(LMatrix4) temp = *this; multiply(temp, other); #endif // HAVE_EIGEN return *this; } /** * */ INLINE_LINMATH FLOATNAME(LMatrix4) &FLOATNAME(LMatrix4):: operator *= (FLOATTYPE scalar) { TAU_PROFILE("LMatrix4 LMatrix4::operator *=(FLOATTYPE)", " ", TAU_USER); #ifdef HAVE_EIGEN _m *= scalar; #else _m(0, 0) *= scalar; _m(0, 1) *= scalar; _m(0, 2) *= scalar; _m(0, 3) *= scalar; _m(1, 0) *= scalar; _m(1, 1) *= scalar; _m(1, 2) *= scalar; _m(1, 3) *= scalar; _m(2, 0) *= scalar; _m(2, 1) *= scalar; _m(2, 2) *= scalar; _m(2, 3) *= scalar; _m(3, 0) *= scalar; _m(3, 1) *= scalar; _m(3, 2) *= scalar; _m(3, 3) *= scalar; #endif // HAVE_EIGEN return *this; } /** * */ INLINE_LINMATH FLOATNAME(LMatrix4) &FLOATNAME(LMatrix4):: operator /= (FLOATTYPE scalar) { TAU_PROFILE("LMatrix4 LMatrix4::operator /=(FLOATTYPE)", " ", TAU_USER); FLOATTYPE recip_scalar = 1.0f/scalar; return operator *= (recip_scalar); } /** * */ INLINE_LINMATH void FLOATNAME(LMatrix4):: componentwise_mult(const FLOATNAME(LMatrix4) &other) { #ifdef HAVE_EIGEN _m = _m.cwiseProduct(other._m); #else _m(0, 0) *= other._m(0, 0); _m(0, 1) *= other._m(0, 1); _m(0, 2) *= other._m(0, 2); _m(0, 3) *= other._m(0, 3); _m(1, 0) *= other._m(1, 0); _m(1, 1) *= other._m(1, 1); _m(1, 2) *= other._m(1, 2); _m(1, 3) *= other._m(1, 3); _m(2, 0) *= other._m(2, 0); _m(2, 1) *= other._m(2, 1); _m(2, 2) *= other._m(2, 2); _m(2, 3) *= other._m(2, 3); _m(3, 0) *= other._m(3, 0); _m(3, 1) *= other._m(3, 1); _m(3, 2) *= other._m(3, 2); _m(3, 3) *= other._m(3, 3); #endif // HAVE_EIGEN } /** * */ INLINE_LINMATH void FLOATNAME(LMatrix4):: transpose_from(const FLOATNAME(LMatrix4) &other) { TAU_PROFILE("LMatrix4 LMatrix4::transpose_from(const LMatrix4 &other)", " ", TAU_USER); #ifdef HAVE_EIGEN _m = other._m.transpose(); #else _m(0, 0) = other._m(0, 0); _m(0, 1) = other._m(1, 0); _m(0, 2) = other._m(2, 0); _m(0, 3) = other._m(3, 0); _m(1, 0) = other._m(0, 1); _m(1, 1) = other._m(1, 1); _m(1, 2) = other._m(2, 1); _m(1, 3) = other._m(3, 1); _m(2, 0) = other._m(0, 2); _m(2, 1) = other._m(1, 2); _m(2, 2) = other._m(2, 2); _m(2, 3) = other._m(3, 2); _m(3, 0) = other._m(0, 3); _m(3, 1) = other._m(1, 3); _m(3, 2) = other._m(2, 3); _m(3, 3) = other._m(3, 3); #endif // HAVE_EIGEN } /** * */ INLINE_LINMATH void FLOATNAME(LMatrix4):: transpose_in_place() { TAU_PROFILE("void LMatrix4::transpose_in_place()", " ", TAU_USER); #ifdef HAVE_EIGEN _m.transposeInPlace(); #else std::swap(_m(0, 1), _m(1, 0)); std::swap(_m(0, 2), _m(2, 0)); std::swap(_m(0, 3), _m(3, 0)); std::swap(_m(1, 2), _m(2, 1)); std::swap(_m(1, 3), _m(3, 1)); std::swap(_m(2, 3), _m(3, 2)); #endif // HAVE_EIGEN } /** * Computes the inverse of the other matrix, and stores the result in this * matrix. This is a fully general operation and makes no assumptions about * the type of transform represented by the matrix. * * The other matrix must be a different object than this matrix. However, if * you need to invert a matrix in place, see invert_in_place. * * The return value is true if the matrix was successfully inverted, false if * the was a singularity. */ INLINE_LINMATH bool FLOATNAME(LMatrix4):: invert_from(const FLOATNAME(LMatrix4) &other) { TAU_PROFILE("bool LMatrix4::invert_from(const LMatrix4 &)", " ", TAU_USER); #ifdef HAVE_EIGEN // We use the squared nearly_zero value as determinant threshold for // checking whether a matrix is singular, since that's the same constant we // use in the non-Eigen case (see lmatrix3_src.I) and also because we // otherwise run into issues very quickly. bool invertible; other._m.computeInverseWithCheck(_m, invertible, NEARLY_ZERO(FLOATTYPE) * NEARLY_ZERO(FLOATTYPE)); if (!invertible) { #ifdef NOTIFY_DEBUG linmath_cat.warning() << "Tried to invert singular LMatrix4.\n"; #endif (*this) = ident_mat(); nassertr(!no_singular_invert, false); } return invertible; #else // HAVE_EIGEN if (IS_NEARLY_EQUAL(other._m(0, 3), 0.0f) && IS_NEARLY_EQUAL(other._m(1, 3), 0.0f) && IS_NEARLY_EQUAL(other._m(2, 3), 0.0f) && IS_NEARLY_EQUAL(other._m(3, 3), 1.0f)) { return invert_affine_from(other); } (*this) = other; int index[4]; if (!decompose_mat(index)) { #ifdef NOTIFY_DEBUG linmath_cat.warning() << "Tried to invert singular LMatrix4.\n"; #endif (*this) = ident_mat(); nassertr(!no_singular_invert, false); return false; } FLOATNAME(LMatrix4) inv = FLOATNAME(LMatrix4)::ident_mat(); int row; for (row = 0; row < 4; row++) { back_sub_mat(index, inv, row); } transpose_from(inv); return true; #endif // HAVE_EIGEN } /** * Performs an invert of the indicated matrix, storing the result in this * matrix. The calculation is only correct of the other matrix represents an * affine transform. * * The other matrix must be a different object than this matrix. However, if * you need to invert a matrix in place, see invert_in_place. * * The return value is true if the matrix was successfully inverted, false if * there was a singularity. */ // bugbug: we could optimize this for rotationscaletranslation matrices // (transpose upper 3x3 and take negative of translation component) INLINE_LINMATH bool FLOATNAME(LMatrix4):: invert_affine_from(const FLOATNAME(LMatrix4) &other) { TAU_PROFILE("bool LMatrix4::invert_affine_from(const LMatrix4 &)", " ", TAU_USER); FLOATNAME(LMatrix3) rot; // probably could use transpose here if (!rot.invert_from(other.get_upper_3())) { return false; } set_upper_3(rot); _m(0, 3) = 0.0f; _m(1, 3) = 0.0f; _m(2, 3) = 0.0f; _m(3, 3) = 1.0f; _m(3, 0) = -(other._m(3, 0) * _m(0, 0) + other._m(3, 1) * _m(1, 0) + other._m(3, 2) * _m(2, 0)); _m(3, 1) = -(other._m(3, 0) * _m(0, 1) + other._m(3, 1) * _m(1, 1) + other._m(3, 2) * _m(2, 1)); _m(3, 2) = -(other._m(3, 0) * _m(0, 2) + other._m(3, 1) * _m(1, 2) + other._m(3, 2) * _m(2, 2)); return true; } /** * Inverts the current matrix. Returns true if the inverse is successful, * false if the matrix was singular. */ INLINE_LINMATH bool FLOATNAME(LMatrix4):: invert_in_place() { TAU_PROFILE("bool LMatrix4::invert_in_place()", " ", TAU_USER); FLOATNAME(LMatrix4) temp = (*this); return invert_from(temp); } /** * Computes (*this) += other * weight. */ INLINE_LINMATH void FLOATNAME(LMatrix4):: accumulate(const FLOATNAME(LMatrix4) &other, FLOATTYPE weight) { #ifdef HAVE_EIGEN _m += other._m * weight; #else _m(0, 0) += other._m(0, 0) * weight; _m(0, 1) += other._m(0, 1) * weight; _m(0, 2) += other._m(0, 2) * weight; _m(0, 3) += other._m(0, 3) * weight; _m(1, 0) += other._m(1, 0) * weight; _m(1, 1) += other._m(1, 1) * weight; _m(1, 2) += other._m(1, 2) * weight; _m(1, 3) += other._m(1, 3) * weight; _m(2, 0) += other._m(2, 0) * weight; _m(2, 1) += other._m(2, 1) * weight; _m(2, 2) += other._m(2, 2) * weight; _m(2, 3) += other._m(2, 3) * weight; _m(3, 0) += other._m(3, 0) * weight; _m(3, 1) += other._m(3, 1) * weight; _m(3, 2) += other._m(3, 2) * weight; _m(3, 3) += other._m(3, 3) * weight; #endif // HAVE_EIGEN } /** * Fills mat with a matrix that applies the indicated translation. */ INLINE_LINMATH void FLOATNAME(LMatrix4):: set_translate_mat(const FLOATNAME(LVecBase3) &trans) { set(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, trans._v(0), trans._v(1), trans._v(2), 1.0f); } /** * Fills mat with a matrix that applies the indicated scale in each of the * three axes. */ INLINE_LINMATH void FLOATNAME(LMatrix4):: set_scale_mat(const FLOATNAME(LVecBase3) &scale) { set(scale._v(0), 0.0f, 0.0f, 0.0f, 0.0f, scale._v(1), 0.0f, 0.0f, 0.0f, 0.0f, scale._v(2), 0.0f, 0.0f, 0.0f, 0.0f, 1.0f); } /** * Fills mat with a matrix that applies the indicated shear in each of the * three planes. */ INLINE_LINMATH void FLOATNAME(LMatrix4):: set_shear_mat(const FLOATNAME(LVecBase3) &shear, CoordinateSystem cs) { set_scale_shear_mat(FLOATNAME(LVecBase3)(1.0f, 1.0f, 1.0f), shear, cs); } /** * Fills mat with a matrix that applies the indicated scale and shear. */ INLINE_LINMATH void FLOATNAME(LMatrix4):: set_scale_shear_mat(const FLOATNAME(LVecBase3) &scale, const FLOATNAME(LVecBase3) &shear, CoordinateSystem cs) { FLOATNAME(LMatrix3) m3; m3.set_scale_shear_mat(scale, shear, cs); set_upper_3(m3); _m(0, 3) = 0.0f; _m(1, 3) = 0.0f; _m(2, 3) = 0.0f; _m(3, 3) = 1.0f; _m(3, 0) = 0.0f; _m(3, 1) = 0.0f; _m(3, 2) = 0.0f; } /** * Returns a matrix that applies the indicated translation. */ INLINE_LINMATH FLOATNAME(LMatrix4) FLOATNAME(LMatrix4):: translate_mat(const FLOATNAME(LVecBase3) &trans) { return FLOATNAME(LMatrix4)(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, trans._v(0), trans._v(1), trans._v(2), 1.0f); } /** * Returns a matrix that applies the indicated translation. */ INLINE_LINMATH FLOATNAME(LMatrix4) FLOATNAME(LMatrix4):: translate_mat(FLOATTYPE tx, FLOATTYPE ty, FLOATTYPE tz) { return FLOATNAME(LMatrix4)(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, tx, ty, tz, 1.0f); } /** * Returns a matrix that rotates by the given angle in degrees * counterclockwise about the indicated vector. */ INLINE_LINMATH FLOATNAME(LMatrix4) FLOATNAME(LMatrix4):: rotate_mat(FLOATTYPE angle, const FLOATNAME(LVecBase3) &axis, CoordinateSystem cs) { FLOATNAME(LMatrix4) mat; mat.set_rotate_mat(angle, axis, cs); return mat; } /** * Returns a matrix that rotates by the given angle in degrees * counterclockwise about the indicated vector. Assumes axis has been * prenormalized. */ INLINE_LINMATH FLOATNAME(LMatrix4) FLOATNAME(LMatrix4):: rotate_mat_normaxis(FLOATTYPE angle, const FLOATNAME(LVecBase3) &axis, CoordinateSystem cs) { TAU_PROFILE("LMatrix4 LMatrix4::rotate_mat_normaxis(FLOATTYPE, const LVecBase3 &, cs)", " ", TAU_USER); FLOATNAME(LMatrix4) mat; mat.set_rotate_mat_normaxis(angle, axis, cs); return mat; } /** * Returns a matrix that applies the indicated scale in each of the three * axes. */ INLINE_LINMATH FLOATNAME(LMatrix4) FLOATNAME(LMatrix4):: scale_mat(const FLOATNAME(LVecBase3) &scale) { return FLOATNAME(LMatrix4)(scale._v(0), 0.0f, 0.0f, 0.0f, 0.0f, scale._v(1), 0.0f, 0.0f, 0.0f, 0.0f, scale._v(2), 0.0f, 0.0f, 0.0f, 0.0f, 1.0f); } /** * Returns a matrix that applies the indicated scale in each of the three * axes. */ INLINE_LINMATH FLOATNAME(LMatrix4) FLOATNAME(LMatrix4):: scale_mat(FLOATTYPE sx, FLOATTYPE sy, FLOATTYPE sz) { return FLOATNAME(LMatrix4)(sx, 0.0f, 0.0f, 0.0f, 0.0f, sy, 0.0f, 0.0f, 0.0f, 0.0f, sz, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f); } /** * Returns a matrix that applies the indicated uniform scale. */ INLINE_LINMATH FLOATNAME(LMatrix4) FLOATNAME(LMatrix4):: scale_mat(FLOATTYPE scale) { return FLOATNAME(LMatrix4)(scale, 0.0f, 0.0f, 0.0f, 0.0f, scale, 0.0f, 0.0f, 0.0f, 0.0f, scale, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f); } /** * Returns a matrix that applies the indicated shear in each of the three * planes. */ INLINE_LINMATH FLOATNAME(LMatrix4) FLOATNAME(LMatrix4):: shear_mat(const FLOATNAME(LVecBase3) &shear, CoordinateSystem cs) { FLOATNAME(LMatrix4) mat; mat.set_shear_mat(shear, cs); return mat; } /** * Returns a matrix that applies the indicated shear in each of the three * planes. */ INLINE_LINMATH FLOATNAME(LMatrix4) FLOATNAME(LMatrix4):: shear_mat(FLOATTYPE shxy, FLOATTYPE shxz, FLOATTYPE shyz, CoordinateSystem cs) { FLOATNAME(LMatrix4) mat; mat.set_shear_mat(FLOATNAME(LVecBase3)(shxy, shxz, shyz), cs); return mat; } /** * Returns a matrix that applies the indicated scale and shear. */ INLINE_LINMATH FLOATNAME(LMatrix4) FLOATNAME(LMatrix4):: scale_shear_mat(const FLOATNAME(LVecBase3) &scale, const FLOATNAME(LVecBase3) &shear, CoordinateSystem cs) { FLOATNAME(LMatrix4) mat; mat.set_scale_shear_mat(scale, shear, cs); return mat; } /** * Returns a matrix that applies the indicated scale and shear. */ INLINE_LINMATH FLOATNAME(LMatrix4) FLOATNAME(LMatrix4):: scale_shear_mat(FLOATTYPE sx, FLOATTYPE sy, FLOATTYPE sz, FLOATTYPE shxy, FLOATTYPE shxz, FLOATTYPE shyz, CoordinateSystem cs) { FLOATNAME(LMatrix4) mat; mat.set_scale_shear_mat(FLOATNAME(LVecBase3)(sx, sy, sz), FLOATNAME(LVecBase3)(shxy, shxz, shyz), cs); return mat; } /** * Returns a matrix that transforms from the Y-up coordinate system to the * Z-up coordinate system. */ INLINE_LINMATH const FLOATNAME(LMatrix4) &FLOATNAME(LMatrix4):: y_to_z_up_mat() { return _y_to_z_up_mat; } /** * Returns a matrix that transforms from the Y-up coordinate system to the * Z-up coordinate system. */ INLINE_LINMATH const FLOATNAME(LMatrix4) &FLOATNAME(LMatrix4):: z_to_y_up_mat() { return _z_to_y_up_mat; } /** * Returns true if two matrices are memberwise equal within a default * tolerance based on the numeric type. */ INLINE_LINMATH bool FLOATNAME(LMatrix4):: almost_equal(const FLOATNAME(LMatrix4) &other) const { return almost_equal(other, NEARLY_ZERO(FLOATTYPE)); } /** * Adds the vector to the indicated hash generator. */ INLINE_LINMATH void FLOATNAME(LMatrix4):: generate_hash(ChecksumHashGenerator &hashgen) const { generate_hash(hashgen, NEARLY_ZERO(FLOATTYPE)); } /** * Transposes the given matrix and returns it. */ INLINE_LINMATH FLOATNAME(LMatrix4) transpose(const FLOATNAME(LMatrix4) &a) { FLOATNAME(LMatrix4) result; result.transpose_from(a); return result; } /** * Inverts the given matrix and returns it. */ INLINE_LINMATH FLOATNAME(LMatrix4) invert(const FLOATNAME(LMatrix4) &a) { TAU_PROFILE("LMatrix4 invert(const LMatrix4 &)", " ", TAU_USER); FLOATNAME(LMatrix4) result; bool nonsingular = result.invert_from(a); #ifndef NDEBUG if (!nonsingular) { nassert_raise("Attempt to compute inverse of singular matrix!"); return FLOATNAME(LMatrix4)::ident_mat(); } #endif return result; } /** * */ INLINE_LINMATH FLOATNAME(UnalignedLMatrix4):: FLOATNAME(UnalignedLMatrix4)() { } /** * */ INLINE_LINMATH FLOATNAME(UnalignedLMatrix4):: FLOATNAME(UnalignedLMatrix4)(const FLOATNAME(LMatrix4) ©) { operator = (copy); } /** * */ INLINE_LINMATH FLOATNAME(UnalignedLMatrix4):: FLOATNAME(UnalignedLMatrix4)(const FLOATNAME(UnalignedLMatrix4) ©) : _m(copy._m) { } /** * */ INLINE_LINMATH FLOATNAME(UnalignedLMatrix4) &FLOATNAME(UnalignedLMatrix4):: operator = (const FLOATNAME(LMatrix4) ©) { memcpy(&_m(0, 0), copy.get_data(), sizeof(FLOATTYPE) * num_components); return *this; } /** * */ INLINE_LINMATH FLOATNAME(UnalignedLMatrix4) &FLOATNAME(UnalignedLMatrix4):: operator = (const FLOATNAME(UnalignedLMatrix4) ©) { TAU_PROFILE("void UnalignedLMatrix4::operator =(UnalignedLMatrix4 &)", " ", TAU_USER); _m = copy._m; return *this; } /** * */ INLINE_LINMATH FLOATNAME(UnalignedLMatrix4):: FLOATNAME(UnalignedLMatrix4)(FLOATTYPE e00, FLOATTYPE e01, FLOATTYPE e02, FLOATTYPE e03, FLOATTYPE e10, FLOATTYPE e11, FLOATTYPE e12, FLOATTYPE e13, FLOATTYPE e20, FLOATTYPE e21, FLOATTYPE e22, FLOATTYPE e23, FLOATTYPE e30, FLOATTYPE e31, FLOATTYPE e32, FLOATTYPE e33) { TAU_PROFILE("UnalignedLMatrix4::UnalignedLMatrix4(FLOATTYPE, ...)", " ", TAU_USER); set(e00, e01, e02, e03, e10, e11, e12, e13, e20, e21, e22, e23, e30, e31, e32, e33); } /** * */ INLINE_LINMATH void FLOATNAME(UnalignedLMatrix4):: set(FLOATTYPE e00, FLOATTYPE e01, FLOATTYPE e02, FLOATTYPE e03, FLOATTYPE e10, FLOATTYPE e11, FLOATTYPE e12, FLOATTYPE e13, FLOATTYPE e20, FLOATTYPE e21, FLOATTYPE e22, FLOATTYPE e23, FLOATTYPE e30, FLOATTYPE e31, FLOATTYPE e32, FLOATTYPE e33) { TAU_PROFILE("void UnalignedLMatrix4::set()", " ", TAU_USER); _m(0, 0) = e00; _m(0, 1) = e01; _m(0, 2) = e02; _m(0, 3) = e03; _m(1, 0) = e10; _m(1, 1) = e11; _m(1, 2) = e12; _m(1, 3) = e13; _m(2, 0) = e20; _m(2, 1) = e21; _m(2, 2) = e22; _m(2, 3) = e23; _m(3, 0) = e30; _m(3, 1) = e31; _m(3, 2) = e32; _m(3, 3) = e33; } /** * */ INLINE_LINMATH FLOATTYPE &FLOATNAME(UnalignedLMatrix4):: operator () (int row, int col) { nassertr(row >= 0 && row < 4 && col >= 0 && col < 4, _m(0, 0)); return _m(row, col); } /** * */ INLINE_LINMATH FLOATTYPE FLOATNAME(UnalignedLMatrix4):: operator () (int row, int col) const { nassertr(row >= 0 && row < 4 && col >= 0 && col < 4, 0.0); return _m(row, col); } /** * Returns the address of the first of the nine data elements in the matrix. * The remaining elements occupy the next eight positions in row-major order. */ INLINE_LINMATH const FLOATTYPE *FLOATNAME(UnalignedLMatrix4):: get_data() const { return &_m(0, 0); } /** * Returns the number of elements in the matrix, sixteen. */ INLINE_LINMATH int FLOATNAME(UnalignedLMatrix4):: get_num_components() const { return 16; } /** * */ INLINE_LINMATH bool FLOATNAME(UnalignedLMatrix4):: operator == (const FLOATNAME(UnalignedLMatrix4) &other) const { return memcmp(get_data(), other.get_data(), sizeof(FLOATTYPE) * 16) == 0; } /** * */ INLINE_LINMATH bool FLOATNAME(UnalignedLMatrix4):: operator != (const FLOATNAME(UnalignedLMatrix4) &other) const { return !operator == (other); }