Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #ifndef GFX_3DMATRIX_H
7 #define GFX_3DMATRIX_H
9 #include <gfxTypes.h>
10 #include <gfxPoint3D.h>
11 #include <gfxPointH3D.h>
12 #include <gfxQuad.h>
14 struct gfxMatrix;
16 /**
17 * This class represents a 3D transformation. The matrix is laid
18 * out as follows:
19 *
20 * _11 _12 _13 _14
21 * _21 _22 _23 _24
22 * _31 _32 _33 _34
23 * _41 _42 _43 _44
24 *
25 * This matrix is treated as row-major. Assuming we consider our vectors row
26 * vectors, this matrix type will be identical in memory to the OpenGL and D3D
27 * matrices. OpenGL matrices are column-major, however OpenGL also treats
28 * vectors as column vectors, the double transposition makes everything work
29 * out nicely.
30 */
31 class gfx3DMatrix
32 {
33 public:
34 /**
35 * Create matrix.
36 */
37 gfx3DMatrix(void);
39 /**
40 * Matrix multiplication.
41 */
42 gfx3DMatrix operator*(const gfx3DMatrix &aMatrix) const;
43 gfx3DMatrix& operator*=(const gfx3DMatrix &aMatrix);
45 gfxPointH3D& operator[](int aIndex)
46 {
47 NS_ABORT_IF_FALSE(aIndex >= 0 && aIndex <= 3, "Invalid matrix array index");
48 return *reinterpret_cast<gfxPointH3D*>((&_11)+4*aIndex);
49 }
50 const gfxPointH3D& operator[](int aIndex) const
51 {
52 NS_ABORT_IF_FALSE(aIndex >= 0 && aIndex <= 3, "Invalid matrix array index");
53 return *reinterpret_cast<const gfxPointH3D*>((&_11)+4*aIndex);
54 }
56 /**
57 * Return true if this matrix and |aMatrix| are the same matrix.
58 */
59 bool operator==(const gfx3DMatrix& aMatrix) const;
60 bool operator!=(const gfx3DMatrix& aMatrix) const;
62 bool FuzzyEqual(const gfx3DMatrix& aMatrix) const;
64 /**
65 * Divide all values in the matrix by a scalar value
66 */
67 gfx3DMatrix& operator/=(gfxFloat scalar);
69 /**
70 * Create a 3D matrix from a gfxMatrix 2D affine transformation.
71 *
72 * \param aMatrix gfxMatrix 2D affine transformation.
73 */
74 static gfx3DMatrix From2D(const gfxMatrix &aMatrix);
76 /**
77 * Returns true if the matrix is isomorphic to a 2D affine transformation
78 * (i.e. as obtained by From2D). If it is, optionally returns the 2D
79 * matrix in aMatrix.
80 */
81 bool Is2D(gfxMatrix* aMatrix) const;
82 bool Is2D() const;
84 /**
85 * Returns true if the matrix can be reduced to a 2D affine transformation
86 * (i.e. as obtained by From2D). If it is, optionally returns the 2D
87 * matrix in aMatrix. This should only be used on matrices required for
88 * rendering, not for intermediate calculations. It is assumed that the 2D
89 * matrix will only be used for transforming objects on to the z=0 plane,
90 * therefore any z-component perspective is ignored. This means that if
91 * aMatrix is applied to objects with z != 0, the results may be incorrect.
92 *
93 * Since drawing is to a 2d plane, any 3d transform without perspective
94 * can be reduced by dropping the z row and column.
95 */
96 bool CanDraw2D(gfxMatrix* aMatrix = nullptr) const;
98 /**
99 * Converts the matrix to one that doesn't modify the z coordinate of points,
100 * but leaves the rest of the transformation unchanged.
101 */
102 gfx3DMatrix& ProjectTo2D();
104 /**
105 * Returns true if the matrix is the identity matrix. The most important
106 * property we require is that gfx3DMatrix().IsIdentity() returns true.
107 */
108 bool IsIdentity() const;
110 /**
111 * Pre-multiplication transformation functions:
112 *
113 * These functions construct a temporary matrix containing
114 * a single transformation and pre-multiply it onto the current
115 * matrix.
116 */
118 /**
119 * Add a translation by aPoint to the matrix.
120 *
121 * This creates this temporary matrix:
122 * | 1 0 0 0 |
123 * | 0 1 0 0 |
124 * | 0 0 1 0 |
125 * | aPoint.x aPoint.y aPoint.z 1 |
126 */
127 void Translate(const gfxPoint3D& aPoint);
129 /**
130 * Skew the matrix.
131 *
132 * This creates this temporary matrix:
133 * | 1 tan(aYSkew) 0 0 |
134 * | tan(aXSkew) 1 0 0 |
135 * | 0 0 1 0 |
136 * | 0 0 0 1 |
137 */
138 void SkewXY(double aXSkew, double aYSkew);
140 void SkewXY(double aSkew);
141 void SkewXZ(double aSkew);
142 void SkewYZ(double aSkew);
144 /**
145 * Scale the matrix
146 *
147 * This creates this temporary matrix:
148 * | aX 0 0 0 |
149 * | 0 aY 0 0 |
150 * | 0 0 aZ 0 |
151 * | 0 0 0 1 |
152 */
153 void Scale(float aX, float aY, float aZ);
155 /**
156 * Return the currently set scaling factors.
157 */
158 float GetXScale() const { return _11; }
159 float GetYScale() const { return _22; }
160 float GetZScale() const { return _33; }
162 /**
163 * Rotate around the X axis..
164 *
165 * This creates this temporary matrix:
166 * | 1 0 0 0 |
167 * | 0 cos(aTheta) sin(aTheta) 0 |
168 * | 0 -sin(aTheta) cos(aTheta) 0 |
169 * | 0 0 0 1 |
170 */
171 void RotateX(double aTheta);
173 /**
174 * Rotate around the Y axis..
175 *
176 * This creates this temporary matrix:
177 * | cos(aTheta) 0 -sin(aTheta) 0 |
178 * | 0 1 0 0 |
179 * | sin(aTheta) 0 cos(aTheta) 0 |
180 * | 0 0 0 1 |
181 */
182 void RotateY(double aTheta);
184 /**
185 * Rotate around the Z axis..
186 *
187 * This creates this temporary matrix:
188 * | cos(aTheta) sin(aTheta) 0 0 |
189 * | -sin(aTheta) cos(aTheta) 0 0 |
190 * | 0 0 1 0 |
191 * | 0 0 0 1 |
192 */
193 void RotateZ(double aTheta);
195 /**
196 * Apply perspective to the matrix.
197 *
198 * This creates this temporary matrix:
199 * | 1 0 0 0 |
200 * | 0 1 0 0 |
201 * | 0 0 1 -1/aDepth |
202 * | 0 0 0 1 |
203 */
204 void Perspective(float aDepth);
206 /**
207 * Pre multiply an existing matrix onto the current
208 * matrix
209 */
210 void PreMultiply(const gfx3DMatrix& aOther);
211 void PreMultiply(const gfxMatrix& aOther);
213 /**
214 * Post-multiplication transformation functions:
215 *
216 * These functions construct a temporary matrix containing
217 * a single transformation and post-multiply it onto the current
218 * matrix.
219 */
221 /**
222 * Add a translation by aPoint after the matrix.
223 * This is functionally equivalent to:
224 * matrix * gfx3DMatrix::Translation(aPoint)
225 */
226 void TranslatePost(const gfxPoint3D& aPoint);
228 void ScalePost(float aX, float aY, float aZ);
230 /**
231 * Transforms a point according to this matrix.
232 */
233 gfxPoint Transform(const gfxPoint& point) const;
235 /**
236 * Transforms a rectangle according to this matrix
237 */
238 gfxRect TransformBounds(const gfxRect& rect) const;
241 gfxQuad TransformRect(const gfxRect& aRect) const;
243 /**
244 * Transforms a 3D vector according to this matrix.
245 */
246 gfxPoint3D Transform3D(const gfxPoint3D& point) const;
247 gfxPointH3D Transform4D(const gfxPointH3D& aPoint) const;
248 gfxPointH3D TransposeTransform4D(const gfxPointH3D& aPoint) const;
250 gfxPoint ProjectPoint(const gfxPoint& aPoint) const;
251 gfxRect ProjectRectBounds(const gfxRect& aRect) const;
253 /**
254 * Transforms a point by the inverse of this matrix. In the case of perspective transforms, some screen
255 * points have no equivalent in the untransformed plane (if they exist past the vanishing point). To
256 * avoid this, we need to specify the bounds of the untransformed plane to restrict the search area.
257 *
258 * @param aPoint Point to untransform.
259 * @param aChildBounds Bounds of the untransformed plane.
260 * @param aOut Untransformed point.
261 * @return Returns true if a point was found within a ChildBounds, false otherwise.
262 */
263 bool UntransformPoint(const gfxPoint& aPoint, const gfxRect& aChildBounds, gfxPoint* aOut) const;
266 /**
267 * Same as UntransformPoint, but untransforms a rect and returns the bounding rect of the result.
268 * Returns an empty rect if the result doesn't intersect aChildBounds.
269 */
270 gfxRect UntransformBounds(const gfxRect& aRect, const gfxRect& aChildBounds) const;
273 /**
274 * Inverts this matrix, if possible. Otherwise, the matrix is left
275 * unchanged.
276 */
277 gfx3DMatrix Inverse() const;
279 gfx3DMatrix& Invert()
280 {
281 *this = Inverse();
282 return *this;
283 }
285 gfx3DMatrix& Normalize();
287 gfxPointH3D TransposedVector(int aIndex) const
288 {
289 NS_ABORT_IF_FALSE(aIndex >= 0 && aIndex <= 3, "Invalid matrix array index");
290 return gfxPointH3D(*((&_11)+aIndex), *((&_21)+aIndex), *((&_31)+aIndex), *((&_41)+aIndex));
291 }
293 void SetTransposedVector(int aIndex, gfxPointH3D &aVector)
294 {
295 NS_ABORT_IF_FALSE(aIndex >= 0 && aIndex <= 3, "Invalid matrix array index");
296 *((&_11)+aIndex) = aVector.x;
297 *((&_21)+aIndex) = aVector.y;
298 *((&_31)+aIndex) = aVector.z;
299 *((&_41)+aIndex) = aVector.w;
300 }
302 gfx3DMatrix& Transpose();
303 gfx3DMatrix Transposed() const;
305 /**
306 * Returns a unit vector that is perpendicular to the plane formed
307 * by transform the screen plane (z=0) by this matrix.
308 */
309 gfxPoint3D GetNormalVector() const;
311 /**
312 * Returns true if a plane transformed by this matrix will
313 * have it's back face visible.
314 */
315 bool IsBackfaceVisible() const;
317 /**
318 * Check if matrix is singular (no inverse exists).
319 */
320 bool IsSingular() const;
322 /**
323 * Create a translation matrix.
324 *
325 * \param aX Translation on X-axis.
326 * \param aY Translation on Y-axis.
327 * \param aZ Translation on Z-axis.
328 */
329 static gfx3DMatrix Translation(float aX, float aY, float aZ);
330 static gfx3DMatrix Translation(const gfxPoint3D& aPoint);
332 /**
333 * Create a scale matrix. Scales uniformly along all axes.
334 *
335 * \param aScale Scale factor
336 */
337 static gfx3DMatrix ScalingMatrix(float aFactor);
339 /**
340 * Create a scale matrix.
341 */
342 static gfx3DMatrix ScalingMatrix(float aX, float aY, float aZ);
344 gfxFloat Determinant() const;
346 void NudgeToIntegers(void);
348 private:
350 gfxFloat Determinant3x3() const;
351 gfx3DMatrix Inverse3x3() const;
353 gfx3DMatrix Multiply2D(const gfx3DMatrix &aMatrix) const;
355 public:
357 /** Matrix elements */
358 float _11, _12, _13, _14;
359 float _21, _22, _23, _24;
360 float _31, _32, _33, _34;
361 float _41, _42, _43, _44;
362 };
364 #endif /* GFX_3DMATRIX_H */