1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/thebes/gfx3DMatrix.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,364 @@ 1.4 +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#ifndef GFX_3DMATRIX_H 1.10 +#define GFX_3DMATRIX_H 1.11 + 1.12 +#include <gfxTypes.h> 1.13 +#include <gfxPoint3D.h> 1.14 +#include <gfxPointH3D.h> 1.15 +#include <gfxQuad.h> 1.16 + 1.17 +struct gfxMatrix; 1.18 + 1.19 +/** 1.20 + * This class represents a 3D transformation. The matrix is laid 1.21 + * out as follows: 1.22 + * 1.23 + * _11 _12 _13 _14 1.24 + * _21 _22 _23 _24 1.25 + * _31 _32 _33 _34 1.26 + * _41 _42 _43 _44 1.27 + * 1.28 + * This matrix is treated as row-major. Assuming we consider our vectors row 1.29 + * vectors, this matrix type will be identical in memory to the OpenGL and D3D 1.30 + * matrices. OpenGL matrices are column-major, however OpenGL also treats 1.31 + * vectors as column vectors, the double transposition makes everything work 1.32 + * out nicely. 1.33 + */ 1.34 +class gfx3DMatrix 1.35 +{ 1.36 +public: 1.37 + /** 1.38 + * Create matrix. 1.39 + */ 1.40 + gfx3DMatrix(void); 1.41 + 1.42 + /** 1.43 + * Matrix multiplication. 1.44 + */ 1.45 + gfx3DMatrix operator*(const gfx3DMatrix &aMatrix) const; 1.46 + gfx3DMatrix& operator*=(const gfx3DMatrix &aMatrix); 1.47 + 1.48 + gfxPointH3D& operator[](int aIndex) 1.49 + { 1.50 + NS_ABORT_IF_FALSE(aIndex >= 0 && aIndex <= 3, "Invalid matrix array index"); 1.51 + return *reinterpret_cast<gfxPointH3D*>((&_11)+4*aIndex); 1.52 + } 1.53 + const gfxPointH3D& operator[](int aIndex) const 1.54 + { 1.55 + NS_ABORT_IF_FALSE(aIndex >= 0 && aIndex <= 3, "Invalid matrix array index"); 1.56 + return *reinterpret_cast<const gfxPointH3D*>((&_11)+4*aIndex); 1.57 + } 1.58 + 1.59 + /** 1.60 + * Return true if this matrix and |aMatrix| are the same matrix. 1.61 + */ 1.62 + bool operator==(const gfx3DMatrix& aMatrix) const; 1.63 + bool operator!=(const gfx3DMatrix& aMatrix) const; 1.64 + 1.65 + bool FuzzyEqual(const gfx3DMatrix& aMatrix) const; 1.66 + 1.67 + /** 1.68 + * Divide all values in the matrix by a scalar value 1.69 + */ 1.70 + gfx3DMatrix& operator/=(gfxFloat scalar); 1.71 + 1.72 + /** 1.73 + * Create a 3D matrix from a gfxMatrix 2D affine transformation. 1.74 + * 1.75 + * \param aMatrix gfxMatrix 2D affine transformation. 1.76 + */ 1.77 + static gfx3DMatrix From2D(const gfxMatrix &aMatrix); 1.78 + 1.79 + /** 1.80 + * Returns true if the matrix is isomorphic to a 2D affine transformation 1.81 + * (i.e. as obtained by From2D). If it is, optionally returns the 2D 1.82 + * matrix in aMatrix. 1.83 + */ 1.84 + bool Is2D(gfxMatrix* aMatrix) const; 1.85 + bool Is2D() const; 1.86 + 1.87 + /** 1.88 + * Returns true if the matrix can be reduced to a 2D affine transformation 1.89 + * (i.e. as obtained by From2D). If it is, optionally returns the 2D 1.90 + * matrix in aMatrix. This should only be used on matrices required for 1.91 + * rendering, not for intermediate calculations. It is assumed that the 2D 1.92 + * matrix will only be used for transforming objects on to the z=0 plane, 1.93 + * therefore any z-component perspective is ignored. This means that if 1.94 + * aMatrix is applied to objects with z != 0, the results may be incorrect. 1.95 + * 1.96 + * Since drawing is to a 2d plane, any 3d transform without perspective 1.97 + * can be reduced by dropping the z row and column. 1.98 + */ 1.99 + bool CanDraw2D(gfxMatrix* aMatrix = nullptr) const; 1.100 + 1.101 + /** 1.102 + * Converts the matrix to one that doesn't modify the z coordinate of points, 1.103 + * but leaves the rest of the transformation unchanged. 1.104 + */ 1.105 + gfx3DMatrix& ProjectTo2D(); 1.106 + 1.107 + /** 1.108 + * Returns true if the matrix is the identity matrix. The most important 1.109 + * property we require is that gfx3DMatrix().IsIdentity() returns true. 1.110 + */ 1.111 + bool IsIdentity() const; 1.112 + 1.113 + /** 1.114 + * Pre-multiplication transformation functions: 1.115 + * 1.116 + * These functions construct a temporary matrix containing 1.117 + * a single transformation and pre-multiply it onto the current 1.118 + * matrix. 1.119 + */ 1.120 + 1.121 + /** 1.122 + * Add a translation by aPoint to the matrix. 1.123 + * 1.124 + * This creates this temporary matrix: 1.125 + * | 1 0 0 0 | 1.126 + * | 0 1 0 0 | 1.127 + * | 0 0 1 0 | 1.128 + * | aPoint.x aPoint.y aPoint.z 1 | 1.129 + */ 1.130 + void Translate(const gfxPoint3D& aPoint); 1.131 + 1.132 + /** 1.133 + * Skew the matrix. 1.134 + * 1.135 + * This creates this temporary matrix: 1.136 + * | 1 tan(aYSkew) 0 0 | 1.137 + * | tan(aXSkew) 1 0 0 | 1.138 + * | 0 0 1 0 | 1.139 + * | 0 0 0 1 | 1.140 + */ 1.141 + void SkewXY(double aXSkew, double aYSkew); 1.142 + 1.143 + void SkewXY(double aSkew); 1.144 + void SkewXZ(double aSkew); 1.145 + void SkewYZ(double aSkew); 1.146 + 1.147 + /** 1.148 + * Scale the matrix 1.149 + * 1.150 + * This creates this temporary matrix: 1.151 + * | aX 0 0 0 | 1.152 + * | 0 aY 0 0 | 1.153 + * | 0 0 aZ 0 | 1.154 + * | 0 0 0 1 | 1.155 + */ 1.156 + void Scale(float aX, float aY, float aZ); 1.157 + 1.158 + /** 1.159 + * Return the currently set scaling factors. 1.160 + */ 1.161 + float GetXScale() const { return _11; } 1.162 + float GetYScale() const { return _22; } 1.163 + float GetZScale() const { return _33; } 1.164 + 1.165 + /** 1.166 + * Rotate around the X axis.. 1.167 + * 1.168 + * This creates this temporary matrix: 1.169 + * | 1 0 0 0 | 1.170 + * | 0 cos(aTheta) sin(aTheta) 0 | 1.171 + * | 0 -sin(aTheta) cos(aTheta) 0 | 1.172 + * | 0 0 0 1 | 1.173 + */ 1.174 + void RotateX(double aTheta); 1.175 + 1.176 + /** 1.177 + * Rotate around the Y axis.. 1.178 + * 1.179 + * This creates this temporary matrix: 1.180 + * | cos(aTheta) 0 -sin(aTheta) 0 | 1.181 + * | 0 1 0 0 | 1.182 + * | sin(aTheta) 0 cos(aTheta) 0 | 1.183 + * | 0 0 0 1 | 1.184 + */ 1.185 + void RotateY(double aTheta); 1.186 + 1.187 + /** 1.188 + * Rotate around the Z axis.. 1.189 + * 1.190 + * This creates this temporary matrix: 1.191 + * | cos(aTheta) sin(aTheta) 0 0 | 1.192 + * | -sin(aTheta) cos(aTheta) 0 0 | 1.193 + * | 0 0 1 0 | 1.194 + * | 0 0 0 1 | 1.195 + */ 1.196 + void RotateZ(double aTheta); 1.197 + 1.198 + /** 1.199 + * Apply perspective to the matrix. 1.200 + * 1.201 + * This creates this temporary matrix: 1.202 + * | 1 0 0 0 | 1.203 + * | 0 1 0 0 | 1.204 + * | 0 0 1 -1/aDepth | 1.205 + * | 0 0 0 1 | 1.206 + */ 1.207 + void Perspective(float aDepth); 1.208 + 1.209 + /** 1.210 + * Pre multiply an existing matrix onto the current 1.211 + * matrix 1.212 + */ 1.213 + void PreMultiply(const gfx3DMatrix& aOther); 1.214 + void PreMultiply(const gfxMatrix& aOther); 1.215 + 1.216 + /** 1.217 + * Post-multiplication transformation functions: 1.218 + * 1.219 + * These functions construct a temporary matrix containing 1.220 + * a single transformation and post-multiply it onto the current 1.221 + * matrix. 1.222 + */ 1.223 + 1.224 + /** 1.225 + * Add a translation by aPoint after the matrix. 1.226 + * This is functionally equivalent to: 1.227 + * matrix * gfx3DMatrix::Translation(aPoint) 1.228 + */ 1.229 + void TranslatePost(const gfxPoint3D& aPoint); 1.230 + 1.231 + void ScalePost(float aX, float aY, float aZ); 1.232 + 1.233 + /** 1.234 + * Transforms a point according to this matrix. 1.235 + */ 1.236 + gfxPoint Transform(const gfxPoint& point) const; 1.237 + 1.238 + /** 1.239 + * Transforms a rectangle according to this matrix 1.240 + */ 1.241 + gfxRect TransformBounds(const gfxRect& rect) const; 1.242 + 1.243 + 1.244 + gfxQuad TransformRect(const gfxRect& aRect) const; 1.245 + 1.246 + /** 1.247 + * Transforms a 3D vector according to this matrix. 1.248 + */ 1.249 + gfxPoint3D Transform3D(const gfxPoint3D& point) const; 1.250 + gfxPointH3D Transform4D(const gfxPointH3D& aPoint) const; 1.251 + gfxPointH3D TransposeTransform4D(const gfxPointH3D& aPoint) const; 1.252 + 1.253 + gfxPoint ProjectPoint(const gfxPoint& aPoint) const; 1.254 + gfxRect ProjectRectBounds(const gfxRect& aRect) const; 1.255 + 1.256 + /** 1.257 + * Transforms a point by the inverse of this matrix. In the case of perspective transforms, some screen 1.258 + * points have no equivalent in the untransformed plane (if they exist past the vanishing point). To 1.259 + * avoid this, we need to specify the bounds of the untransformed plane to restrict the search area. 1.260 + * 1.261 + * @param aPoint Point to untransform. 1.262 + * @param aChildBounds Bounds of the untransformed plane. 1.263 + * @param aOut Untransformed point. 1.264 + * @return Returns true if a point was found within a ChildBounds, false otherwise. 1.265 + */ 1.266 + bool UntransformPoint(const gfxPoint& aPoint, const gfxRect& aChildBounds, gfxPoint* aOut) const; 1.267 + 1.268 + 1.269 + /** 1.270 + * Same as UntransformPoint, but untransforms a rect and returns the bounding rect of the result. 1.271 + * Returns an empty rect if the result doesn't intersect aChildBounds. 1.272 + */ 1.273 + gfxRect UntransformBounds(const gfxRect& aRect, const gfxRect& aChildBounds) const; 1.274 + 1.275 + 1.276 + /** 1.277 + * Inverts this matrix, if possible. Otherwise, the matrix is left 1.278 + * unchanged. 1.279 + */ 1.280 + gfx3DMatrix Inverse() const; 1.281 + 1.282 + gfx3DMatrix& Invert() 1.283 + { 1.284 + *this = Inverse(); 1.285 + return *this; 1.286 + } 1.287 + 1.288 + gfx3DMatrix& Normalize(); 1.289 + 1.290 + gfxPointH3D TransposedVector(int aIndex) const 1.291 + { 1.292 + NS_ABORT_IF_FALSE(aIndex >= 0 && aIndex <= 3, "Invalid matrix array index"); 1.293 + return gfxPointH3D(*((&_11)+aIndex), *((&_21)+aIndex), *((&_31)+aIndex), *((&_41)+aIndex)); 1.294 + } 1.295 + 1.296 + void SetTransposedVector(int aIndex, gfxPointH3D &aVector) 1.297 + { 1.298 + NS_ABORT_IF_FALSE(aIndex >= 0 && aIndex <= 3, "Invalid matrix array index"); 1.299 + *((&_11)+aIndex) = aVector.x; 1.300 + *((&_21)+aIndex) = aVector.y; 1.301 + *((&_31)+aIndex) = aVector.z; 1.302 + *((&_41)+aIndex) = aVector.w; 1.303 + } 1.304 + 1.305 + gfx3DMatrix& Transpose(); 1.306 + gfx3DMatrix Transposed() const; 1.307 + 1.308 + /** 1.309 + * Returns a unit vector that is perpendicular to the plane formed 1.310 + * by transform the screen plane (z=0) by this matrix. 1.311 + */ 1.312 + gfxPoint3D GetNormalVector() const; 1.313 + 1.314 + /** 1.315 + * Returns true if a plane transformed by this matrix will 1.316 + * have it's back face visible. 1.317 + */ 1.318 + bool IsBackfaceVisible() const; 1.319 + 1.320 + /** 1.321 + * Check if matrix is singular (no inverse exists). 1.322 + */ 1.323 + bool IsSingular() const; 1.324 + 1.325 + /** 1.326 + * Create a translation matrix. 1.327 + * 1.328 + * \param aX Translation on X-axis. 1.329 + * \param aY Translation on Y-axis. 1.330 + * \param aZ Translation on Z-axis. 1.331 + */ 1.332 + static gfx3DMatrix Translation(float aX, float aY, float aZ); 1.333 + static gfx3DMatrix Translation(const gfxPoint3D& aPoint); 1.334 + 1.335 + /** 1.336 + * Create a scale matrix. Scales uniformly along all axes. 1.337 + * 1.338 + * \param aScale Scale factor 1.339 + */ 1.340 + static gfx3DMatrix ScalingMatrix(float aFactor); 1.341 + 1.342 + /** 1.343 + * Create a scale matrix. 1.344 + */ 1.345 + static gfx3DMatrix ScalingMatrix(float aX, float aY, float aZ); 1.346 + 1.347 + gfxFloat Determinant() const; 1.348 + 1.349 + void NudgeToIntegers(void); 1.350 + 1.351 +private: 1.352 + 1.353 + gfxFloat Determinant3x3() const; 1.354 + gfx3DMatrix Inverse3x3() const; 1.355 + 1.356 + gfx3DMatrix Multiply2D(const gfx3DMatrix &aMatrix) const; 1.357 + 1.358 +public: 1.359 + 1.360 + /** Matrix elements */ 1.361 + float _11, _12, _13, _14; 1.362 + float _21, _22, _23, _24; 1.363 + float _31, _32, _33, _34; 1.364 + float _41, _42, _43, _44; 1.365 +}; 1.366 + 1.367 +#endif /* GFX_3DMATRIX_H */