LCOV - code coverage report
Current view: top level - core/geom - SPMat4.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 42 42 100.0 %
Date: 2024-05-12 00:16:13 Functions: 16 16 100.0 %

          Line data    Source code
       1             : /**
       2             : Copyright 2013 BlackBerry Inc.
       3             : Copyright (c) 2014-2015 Chukong Technologies
       4             : Copyright (c) 2017-2019 Roman Katuntsev <sbkarr@stappler.org>
       5             : Copyright (c) 2023-2024 Stappler LLC <admin@stappler.dev>
       6             : 
       7             : Licensed under the Apache License, Version 2.0 (the "License");
       8             : you may not use this file except in compliance with the License.
       9             : You may obtain a copy of the License at
      10             : 
      11             : http://www.apache.org/licenses/LICENSE-2.0
      12             : 
      13             : Unless required by applicable law or agreed to in writing, software
      14             : distributed under the License is distributed on an "AS IS" BASIS,
      15             : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      16             : See the License for the specific language governing permissions and
      17             : limitations under the License.
      18             : 
      19             : Original file from GamePlay3D: http://gameplay3d.org
      20             : 
      21             : This file was modified to fit the cocos2d-x project
      22             : This file was modified for stappler project
      23             : */
      24             : 
      25             : #ifndef CORE_GEOM_SPMAT4_H_
      26             : #define CORE_GEOM_SPMAT4_H_
      27             : 
      28             : #include "SPVec2.h"
      29             : #include "SPVec3.h"
      30             : #include "SPVec4.h"
      31             : 
      32             : namespace STAPPLER_VERSIONIZED stappler::geom {
      33             : 
      34             : /**
      35             :  * Defines a 4 x 4 floating point matrix representing a 3D transformation.
      36             :  *
      37             :  * Vectors are treated as columns, resulting in a matrix that is represented as follows,
      38             :  * where x, y and z are the translation components of the matrix:
      39             :  *
      40             :  *     1  0  0  x
      41             :  *     0  1  0  y
      42             :  *     0  0  1  z
      43             :  *     0  0  0  1
      44             :  *
      45             :  * This matrix class is directly compatible with OpenGL since its elements are
      46             :  * laid out in memory exactly as they are expected by OpenGL.
      47             :  * The matrix uses column-major format such that array indices increase down column first.
      48             :  * Since matrix multiplication is not commutative, multiplication must be done in the
      49             :  * correct order when combining transformations. Suppose we have a translation
      50             :  * matrix T and a rotation matrix R. To first rotate an object around the origin
      51             :  * and then translate it, you would multiply the two matrices as TR.
      52             :  *
      53             :  * Likewise, to first translate the object and then rotate it, you would do RT.
      54             :  * So generally, matrices must be multiplied in the reverse order in which you
      55             :  * want the transformations to take place (this also applies to
      56             :  * the scale, rotate, and translate methods below; these methods are convenience
      57             :  * methods for post-multiplying by a matrix representing a scale, rotation, or translation).
      58             :  *
      59             :  * In the case of repeated local transformations (i.e. rotate around the Z-axis by 0.76 radians,
      60             :  * then translate by 2.1 along the X-axis, then ...), it is better to use the Transform class
      61             :  * (which is optimized for that kind of usage).
      62             :  *
      63             :  * @see Transform
      64             :  */
      65             : class alignas(16) Mat4 {
      66             : public:
      67             :         static void createLookAt(const Vec3 &eyePosition, const Vec3 &targetPosition, const Vec3 &up, Mat4 *dst);
      68             : 
      69             :         static void createLookAt(float eyePositionX, float eyePositionY, float eyePositionZ,
      70             :                         float targetCenterX, float targetCenterY, float targetCenterZ,
      71             :                         float upX, float upY, float upZ, Mat4 *dst);
      72             : 
      73             :         /** Builds a perspective projection matrix based on a field of view and returns by value.
      74             :          *
      75             :          * Projection space refers to the space after applying projection transformation from view space.
      76             :          * After the projection transformation, visible content has x- and y-coordinates ranging from -1 to 1,
      77             :          * and a z-coordinate ranging from 0 to 1. To obtain the viewable area (in world space) of a scene,
      78             :          * create a BoundingFrustum and pass the combined view and projection matrix to the constructor. */
      79             :         static void createPerspective(float fieldOfView, float aspectRatio, float zNearPlane, float zFarPlane, Mat4 *dst);
      80             : 
      81             :         /** Creates an orthographic projection matrix. */
      82             :         static void createOrthographic(float width, float height, float zNearPlane, float zFarPlane, Mat4 *dst);
      83             : 
      84             :         /** Creates an orthographic projection matrix.
      85             :          *
      86             :          * Projection space refers to the space after applying
      87             :          * projection transformation from view space. After the
      88             :          * projection transformation, visible content has
      89             :          * x and y coordinates ranging from -1 to 1, and z coordinates
      90             :          * ranging from 0 to 1.
      91             :          *
      92             :          * Unlike perspective projection, in orthographic projection
      93             :          * there is no perspective foreshortening.
      94             :          *
      95             :          * The viewable area of this orthographic projection extends
      96             :          * from left to right on the x-axis, bottom to top on the y-axis,
      97             :          * and zNearPlane to zFarPlane on the z-axis. These values are
      98             :          * relative to the position and x, y, and z-axes of the view.
      99             :          * To obtain the viewable area (in world space) of a scene,
     100             :          * create a BoundingFrustum and pass the combined view and
     101             :          * projection matrix to the constructor. */
     102             :         static void createOrthographicOffCenter(float left, float right, float bottom, float top,
     103             :                         float zNearPlane, float zFarPlane, Mat4 *dst);
     104             : 
     105             :     /** Creates a spherical billboard that rotates around a specified object position.
     106             :          *
     107             :          * This method computes the facing direction of the billboard from the object position
     108             :          * and camera position. When the object and camera positions are too close, the matrix
     109             :          * will not be accurate. To avoid this problem, this method defaults to the identity
     110             :          * rotation if the positions are too close. (See the other overload of createBillboard
     111             :          * for an alternative approach). */
     112             :         static void createBillboard(const Vec3 &objectPosition, const Vec3 &cameraPosition,
     113             :                         const Vec3 &cameraUpVector, Mat4 *dst);
     114             : 
     115             :         /** Creates a spherical billboard that rotates around a specified object position with
     116             :          * provision for a safe default orientation.
     117             :          *
     118             :          * This method computes the facing direction of the billboard from the object position
     119             :          * and camera position. When the object and camera positions are too close, the matrix
     120             :          * will not be accurate. To avoid this problem, this method uses the specified camera
     121             :          * forward vector if the positions are too close. (See the other overload of createBillboard
     122             :          * for an alternative approach). */
     123             :         static void createBillboard(const Vec3 &objectPosition, const Vec3 &cameraPosition,
     124             :                         const Vec3 &cameraUpVector, const Vec3 &cameraForwardVector, Mat4 *dst);
     125             : 
     126             :         static void createScale(const Vec3 &scale, Mat4 *dst);
     127             :         static void createScale(float xScale, float yScale, float zScale, Mat4 *dst);
     128             :         static void createRotation(const Quaternion &quat, Mat4 *dst);
     129             :         static void createRotation(const Vec3 &axis, float angle, Mat4 *dst);
     130             :         static void createRotationX(float angle, Mat4 *dst);
     131             :         static void createRotationY(float angle, Mat4 *dst);
     132             :         static void createRotationZ(float angle, Mat4 *dst);
     133             :         static void createTranslation(const Vec3 &translation, Mat4 *dst);
     134             :         static void createTranslation(float xTranslation, float yTranslation, float zTranslation, Mat4 *dst);
     135             : 
     136             :         static void add(const Mat4 &m1, const Mat4 &m2, Mat4 *dst) {
     137             :                 simd::addMat4(m1.m, m2.m, dst->m);
     138             :         }
     139             : 
     140       82100 :         static void multiply(const Mat4 &mat, float scalar, Mat4 *dst) {
     141       82100 :                 simd::multiplyMat4Scalar(mat.m, scalar, dst->m);
     142       82100 :         }
     143             : 
     144     2697115 :         static void multiply(const Mat4 &m1, const Mat4 &m2, Mat4 *dst) {
     145     2697115 :                 simd::multiplyMat4(m1.m, m2.m, dst->m);
     146     2697348 :         }
     147             : 
     148             :     static void subtract(const Mat4& m1, const Mat4& m2, Mat4* dst) {
     149             :                 simd::subtractMat4(m1.m, m2.m, dst->m);
     150             :     }
     151             : 
     152    25680604 :         float m[16];
     153             : 
     154     1652592 :         constexpr Mat4() { *this = IDENTITY; }
     155             : 
     156       60373 :         constexpr Mat4(float m11, float m12, float m13, float m14, float m21, float m22, float m23, float m24,
     157             :                         float m31, float m32, float m33, float m34, float m41, float m42, float m43, float m44)
     158       60373 :         : m { m11, m21, m31, m41, m12, m22, m32, m42, m13, m23, m33, m43, m14, m24, m34, m44 } { }
     159             : 
     160         125 :         constexpr Mat4(float a, float b, float c, float d, float e, float f)
     161         125 :         : m { a, b, 0, 0, c, d, 0, 0, 0, 0, 1, 0, e, f, 0, 1 } { }
     162             : 
     163             :         constexpr Mat4(const Mat4& copy) = default;
     164             : 
     165             :         void add(float scalar) { add(scalar, this); }
     166             :         void add(float scalar, Mat4 *dst) { simd::addMat4Scalar(m, scalar, dst->m); }
     167             :         void add(const Mat4 &mat) { add(*this, mat, this); }
     168             : 
     169             :         bool decompose(Vec3 *scale, Quaternion *rotation, Vec3 *translation) const;
     170             :         bool decompose(float *scale, float *rotation, float *translation) const;
     171             : 
     172             :         float determinant() const;
     173             : 
     174             :         void getScale(Vec3 *scale) const;
     175             :         bool getRotation(Quaternion *rotation) const;
     176             :         void getTranslation(Vec3 *translation) const;
     177             : 
     178             :         void getScale(float *scale) const;
     179             :         bool getRotation(float *rotation) const;
     180             :         void getTranslation(float *translation) const;
     181             : 
     182             :         void getUpVector(Vec3 *dst) const;
     183             :         void getDownVector(Vec3 *dst) const;
     184             :         void getLeftVector(Vec3 *dst) const;
     185             :         void getRightVector(Vec3 *dst) const;
     186             :         void getForwardVector(Vec3 *dst) const;
     187             :         void getBackVector(Vec3 *dst) const;
     188             : 
     189             :         bool inverse();
     190             :         void negate() { simd::negateMat4(m, m); }
     191             :         void transpose() { simd::transposeMat4(m, m); }
     192             : 
     193       16479 :         Mat4 getInversed() const { Mat4 mat(*this); mat.inverse(); return mat; }
     194             :         Mat4 getNegated() const { Mat4 mat(*this); mat.negate(); return mat; }
     195             :         Mat4 getTransposed() const { Mat4 mat(*this); mat.transpose(); return mat; }
     196             : 
     197     1931664 :         bool isIdentity() const { return *this == IDENTITY; }
     198             : 
     199             :         void multiply(float scalar) { multiply(scalar, this); }
     200             :         void multiply(float scalar, Mat4 *dst) const { multiply(*this, scalar, dst); }
     201     1235471 :         void multiply(const Mat4 &mat) { multiply(*this, mat, this); }
     202             : 
     203             :         void rotate(const Quaternion &q);
     204             :         void rotate(const Quaternion &q, Mat4 *dst) const;
     205             :         void rotate(const Vec3 &axis, float angle);
     206             :         void rotate(const Vec3 &axis, float angle, Mat4 *dst) const;
     207             :         void rotateX(float angle);
     208             :         void rotateX(float angle, Mat4 *dst) const;
     209             :         void rotateY(float angle);
     210             :         void rotateY(float angle, Mat4 *dst) const;
     211             :         void rotateZ(float angle);
     212             :         void rotateZ(float angle, Mat4 *dst) const;
     213             : 
     214             :         void scale(float value);
     215             :         void scale(float value, Mat4 *dst) const;
     216             :         void scale(float xScale, float yScale, float zScale);
     217             :         void scale(float xScale, float yScale, float zScale, Mat4 *dst) const;
     218             :         void scale(const Vec3 &s);
     219             :         void scale(const Vec3 &s, Mat4 *dst) const;
     220             :         void subtract(const Mat4 &mat) { subtract(*this, mat, this); }
     221             : 
     222        6229 :         Vec2 transformPoint(const Vec2 &point) const { // TODO: implement simd version of 2D-transform
     223        6229 :                 Vec4 ret;
     224        6229 :                 transformVector(point.x, point.y, 1.0f, 1.0f, &ret);
     225        6229 :                 return Vec2(ret.x, ret.y);
     226             :         }
     227         100 :         void transformPoint(Vec2 *point) const { // TODO: implement simd version of 2D-transform
     228         100 :                 Vec4 ret;
     229         100 :                 transformVector(point->x, point->y, 1.0f, 1.0f, &ret);
     230         100 :                 *point = Vec2(ret.x, ret.y);
     231         100 :         }
     232             :         void transformVector(Vec4 *vector) const {
     233             :                 simd::transformVec4(m, &vector->x, &vector->x);
     234             :         }
     235        6269 :         void transformVector(float x, float y, float z, float w, Vec4 *dst) const {
     236        6269 :                 simd::transformVec4Components(m, x, y, z, w, &dst->x);
     237        6269 :         }
     238         740 :         void transformVector(float x, float y, float z, float w, float *dst) const {
     239         740 :                 simd::transformVec4Components(m, x, y, z, w, dst);
     240         740 :         }
     241             :         void transformVector(const Vec4 &vector, Vec4 *dst) const {
     242             :                 simd::transformVec4(m, &vector.x, &dst->x);
     243             :         }
     244             :         void transformVector(const Vec4 &vector, Vec3 *dst) const {
     245             :                 simd::transformVec4(m, &vector.x, &dst->x);
     246             :         }
     247             : 
     248             :         void translate(float x, float y, float z);
     249             :         void translate(float x, float y, float z, Mat4 *dst) const;
     250             :         void translate(const Vec3 &t);
     251             : 
     252             :         void translate(const Vec3 &t, Mat4 *dst) const;
     253             : 
     254             :         const Mat4 operator+(const Mat4 &mat) const {
     255             :                 Mat4 result(*this);
     256             :                 result.add(mat);
     257             :                 return result;
     258             :         }
     259             : 
     260             :         Mat4& operator+=(const Mat4 &mat) {
     261             :                 add(mat);
     262             :                 return *this;
     263             :         }
     264             : 
     265             :         const Mat4 operator-(const Mat4 &mat) const {
     266             :                 Mat4 result(*this);
     267             :                 result.subtract(mat);
     268             :                 return result;
     269             :         }
     270             : 
     271             :         Mat4& operator-=(const Mat4 &mat) {
     272             :                 subtract(mat);
     273             :                 return *this;
     274             :         }
     275             : 
     276             :         const Mat4 operator-() const {
     277             :                 Mat4 mat(*this);
     278             :                 mat.negate();
     279             :                 return mat;
     280             :         }
     281             : 
     282      751974 :         const Mat4 operator*(const Mat4 &mat) const {
     283      751974 :                 Mat4 result(*this);
     284      751974 :                 result.multiply(mat);
     285      751983 :                 return result;
     286             :         }
     287             : 
     288      584163 :         Mat4& operator*=(const Mat4 &mat) {
     289      584163 :                 multiply(mat);
     290      584112 :                 return *this;
     291             :         }
     292             : 
     293    27088905 :         inline bool operator==(const Mat4&) const = default;
     294             :         inline bool operator!=(const Mat4&) const = default;
     295             : 
     296             :         static const Mat4 ZERO;
     297             :         static const Mat4 IDENTITY;
     298             :         static const Mat4 INVALID;
     299             : 
     300             :         static const Mat4 ROTATION_Z_90;
     301             :         static const Mat4 ROTATION_Z_180;
     302             :         static const Mat4 ROTATION_Z_270;
     303             : };
     304             : 
     305             : #ifndef __LCC__
     306             : 
     307             : constexpr const Mat4 Mat4::IDENTITY = Mat4(
     308             :         1.0f, 0.0f, 0.0f, 0.0f,
     309             :         0.0f, 1.0f, 0.0f, 0.0f,
     310             :         0.0f, 0.0f, 1.0f, 0.0f,
     311             :         0.0f, 0.0f, 0.0f, 1.0f);
     312             : 
     313             : constexpr const Mat4 Mat4::ZERO = Mat4(
     314             :         0.0f, 0.0f, 0.0f, 0.0f,
     315             :         0.0f, 0.0f, 0.0f, 0.0f,
     316             :         0.0f, 0.0f, 0.0f, 0.0f,
     317             :         0.0f, 0.0f, 0.0f, 0.0f );
     318             : 
     319             : constexpr const Mat4 Mat4::INVALID = Mat4(
     320             :         stappler::nan(), stappler::nan(), stappler::nan(), stappler::nan(),
     321             :         stappler::nan(), stappler::nan(), stappler::nan(), stappler::nan(),
     322             :         stappler::nan(), stappler::nan(), stappler::nan(), stappler::nan(),
     323             :         stappler::nan(), stappler::nan(), stappler::nan(), stappler::nan() );
     324             : 
     325             : constexpr const Mat4 Mat4::ROTATION_Z_90 = Mat4(
     326             :         0.0f, -1.0f, 0.0f, 0.0f,
     327             :         1.0f, 0.0f, 0.0f, 0.0f,
     328             :         0.0f, 0.0f, 1.0f, 0.0f,
     329             :         0.0f, 0.0f, 0.0f, 1.0f );
     330             : 
     331             : constexpr const Mat4 Mat4::ROTATION_Z_180 = Mat4(
     332             :         -1.0f, 0.0f, 0.0f, 0.0f,
     333             :         0.0f, -1.0f, 0.0f, 0.0f,
     334             :         0.0f, 0.0f, 1.0f, 0.0f,
     335             :         0.0f, 0.0f, 0.0f, 1.0f );
     336             : 
     337             : constexpr const Mat4 Mat4::ROTATION_Z_270 = Mat4(
     338             :         0.0f, 1.0f, 0.0f, 0.0f,
     339             :         -1.0f, 0.0f, 0.0f, 0.0f,
     340             :         0.0f, 0.0f, 1.0f, 0.0f,
     341             :         0.0f, 0.0f, 0.0f, 1.0f );
     342             : 
     343             : #endif
     344             : 
     345             : inline Vec4& operator*=(Vec4& v, const Mat4& m) {
     346             :         m.transformVector(&v);
     347             :         return v;
     348             : }
     349             : 
     350             : inline const Vec4 operator*(const Mat4& m, const Vec4& v) {
     351             :         Vec4 x;
     352             :         m.transformVector(v, &x);
     353             :         return x;
     354             : }
     355             : 
     356             : inline const Vec3 operator*(const Mat4& m, const Vec3& v) {
     357             :         struct alignas(16) {
     358             :                 Vec3 vec;
     359             :                 float w;
     360             :         } s;
     361             :         m.transformVector(v.x, v.y, v.z, 1.0f, &s.vec.x);
     362             :         return s.vec;
     363             : }
     364             : 
     365         740 : inline const Vec2 operator*(const Mat4& m, const Vec2& v) {
     366             :         struct alignas(16) {
     367             :                 Vec2 vec;
     368             :                 float z;
     369             :                 float w;
     370         740 :         } s;
     371         740 :         m.transformVector(v.x, v.y, 1.0f, 1.0f, &s.vec.x);
     372         740 :         return s.vec;
     373             : }
     374             : 
     375             : inline std::basic_ostream<char> &
     376             : operator << (std::basic_ostream<char> & os, const Mat4 & m) {
     377             :         os << "{\n\t( " << m.m[0] << ", " << m.m[4] << ", " << m.m[8] << ", " << m.m[12] << ")\n"
     378             :                   << "\t( " << m.m[1] << ", " << m.m[5] << ", " << m.m[9] << ", " << m.m[13] << ")\n"
     379             :                   << "\t( " << m.m[2] << ", " << m.m[6] << ", " << m.m[10] << ", " << m.m[14] << ")\n"
     380             :                   << "\t( " << m.m[3] << ", " << m.m[7] << ", " << m.m[11] << ", " << m.m[15] << ")\n"
     381             :                 << "}";
     382             :         return os;
     383             : }
     384             : 
     385             : }
     386             : 
     387             : #endif /* CORE_GEOM_SPMAT4_H_ */

Generated by: LCOV version 1.14