|
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/. */ |
|
5 |
|
6 #ifndef GFX_3DMATRIX_H |
|
7 #define GFX_3DMATRIX_H |
|
8 |
|
9 #include <gfxTypes.h> |
|
10 #include <gfxPoint3D.h> |
|
11 #include <gfxPointH3D.h> |
|
12 #include <gfxQuad.h> |
|
13 |
|
14 struct gfxMatrix; |
|
15 |
|
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); |
|
38 |
|
39 /** |
|
40 * Matrix multiplication. |
|
41 */ |
|
42 gfx3DMatrix operator*(const gfx3DMatrix &aMatrix) const; |
|
43 gfx3DMatrix& operator*=(const gfx3DMatrix &aMatrix); |
|
44 |
|
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 } |
|
55 |
|
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; |
|
61 |
|
62 bool FuzzyEqual(const gfx3DMatrix& aMatrix) const; |
|
63 |
|
64 /** |
|
65 * Divide all values in the matrix by a scalar value |
|
66 */ |
|
67 gfx3DMatrix& operator/=(gfxFloat scalar); |
|
68 |
|
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); |
|
75 |
|
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; |
|
83 |
|
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; |
|
97 |
|
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(); |
|
103 |
|
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; |
|
109 |
|
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 */ |
|
117 |
|
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); |
|
128 |
|
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); |
|
139 |
|
140 void SkewXY(double aSkew); |
|
141 void SkewXZ(double aSkew); |
|
142 void SkewYZ(double aSkew); |
|
143 |
|
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); |
|
154 |
|
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; } |
|
161 |
|
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); |
|
172 |
|
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); |
|
183 |
|
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); |
|
194 |
|
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); |
|
205 |
|
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); |
|
212 |
|
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 */ |
|
220 |
|
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); |
|
227 |
|
228 void ScalePost(float aX, float aY, float aZ); |
|
229 |
|
230 /** |
|
231 * Transforms a point according to this matrix. |
|
232 */ |
|
233 gfxPoint Transform(const gfxPoint& point) const; |
|
234 |
|
235 /** |
|
236 * Transforms a rectangle according to this matrix |
|
237 */ |
|
238 gfxRect TransformBounds(const gfxRect& rect) const; |
|
239 |
|
240 |
|
241 gfxQuad TransformRect(const gfxRect& aRect) const; |
|
242 |
|
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; |
|
249 |
|
250 gfxPoint ProjectPoint(const gfxPoint& aPoint) const; |
|
251 gfxRect ProjectRectBounds(const gfxRect& aRect) const; |
|
252 |
|
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; |
|
264 |
|
265 |
|
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; |
|
271 |
|
272 |
|
273 /** |
|
274 * Inverts this matrix, if possible. Otherwise, the matrix is left |
|
275 * unchanged. |
|
276 */ |
|
277 gfx3DMatrix Inverse() const; |
|
278 |
|
279 gfx3DMatrix& Invert() |
|
280 { |
|
281 *this = Inverse(); |
|
282 return *this; |
|
283 } |
|
284 |
|
285 gfx3DMatrix& Normalize(); |
|
286 |
|
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 } |
|
292 |
|
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 } |
|
301 |
|
302 gfx3DMatrix& Transpose(); |
|
303 gfx3DMatrix Transposed() const; |
|
304 |
|
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; |
|
310 |
|
311 /** |
|
312 * Returns true if a plane transformed by this matrix will |
|
313 * have it's back face visible. |
|
314 */ |
|
315 bool IsBackfaceVisible() const; |
|
316 |
|
317 /** |
|
318 * Check if matrix is singular (no inverse exists). |
|
319 */ |
|
320 bool IsSingular() const; |
|
321 |
|
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); |
|
331 |
|
332 /** |
|
333 * Create a scale matrix. Scales uniformly along all axes. |
|
334 * |
|
335 * \param aScale Scale factor |
|
336 */ |
|
337 static gfx3DMatrix ScalingMatrix(float aFactor); |
|
338 |
|
339 /** |
|
340 * Create a scale matrix. |
|
341 */ |
|
342 static gfx3DMatrix ScalingMatrix(float aX, float aY, float aZ); |
|
343 |
|
344 gfxFloat Determinant() const; |
|
345 |
|
346 void NudgeToIntegers(void); |
|
347 |
|
348 private: |
|
349 |
|
350 gfxFloat Determinant3x3() const; |
|
351 gfx3DMatrix Inverse3x3() const; |
|
352 |
|
353 gfx3DMatrix Multiply2D(const gfx3DMatrix &aMatrix) const; |
|
354 |
|
355 public: |
|
356 |
|
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 }; |
|
363 |
|
364 #endif /* GFX_3DMATRIX_H */ |