Coverage Report

Created: 2021-08-22 09:07

/src/skia/include/core/SkM44.h
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2020 Google Inc.
3
 *
4
 * Use of this source code is governed by a BSD-style license that can be
5
 * found in the LICENSE file.
6
 */
7
8
#ifndef SkM44_DEFINED
9
#define SkM44_DEFINED
10
11
#include "include/core/SkMatrix.h"
12
#include "include/core/SkRect.h"
13
#include "include/core/SkScalar.h"
14
15
struct SK_API SkV2 {
16
    float x, y;
17
18
150k
    bool operator==(const SkV2 v) const { return x == v.x && y == v.y; }
19
131k
    bool operator!=(const SkV2 v) const { return !(*this == v); }
20
21
76.7k
    static SkScalar   Dot(SkV2 a, SkV2 b) { return a.x * b.x + a.y * b.y; }
22
0
    static SkScalar Cross(SkV2 a, SkV2 b) { return a.x * b.y - a.y * b.x; }
23
0
    static SkV2 Normalize(SkV2 v) { return v * (1.0f / v.length()); }
24
25
0
    SkV2 operator-() const { return {-x, -y}; }
26
5.53k
    SkV2 operator+(SkV2 v) const { return {x+v.x, y+v.y}; }
27
37.0k
    SkV2 operator-(SkV2 v) const { return {x-v.x, y-v.y}; }
28
29
1.35k
    SkV2 operator*(SkV2 v) const { return {x*v.x, y*v.y}; }
30
5.53k
    friend SkV2 operator*(SkV2 v, SkScalar s) { return {v.x*s, v.y*s}; }
31
0
    friend SkV2 operator*(SkScalar s, SkV2 v) { return {v.x*s, v.y*s}; }
32
0
    friend SkV2 operator/(SkV2 v, SkScalar s) { return {v.x/s, v.y/s}; }
33
34
0
    void operator+=(SkV2 v) { *this = *this + v; }
35
0
    void operator-=(SkV2 v) { *this = *this - v; }
36
0
    void operator*=(SkV2 v) { *this = *this * v; }
37
0
    void operator*=(SkScalar s) { *this = *this * s; }
38
0
    void operator/=(SkScalar s) { *this = *this / s; }
39
40
51.8k
    SkScalar lengthSquared() const { return Dot(*this, *this); }
41
0
    SkScalar length() const { return SkScalarSqrt(this->lengthSquared()); }
42
43
24.8k
    SkScalar   dot(SkV2 v) const { return Dot(*this, v); }
44
0
    SkScalar cross(SkV2 v) const { return Cross(*this, v); }
45
0
    SkV2 normalize()       const { return Normalize(*this); }
46
47
0
    const float* ptr() const { return &x; }
48
0
    float* ptr() { return &x; }
49
};
50
51
struct SK_API SkV3 {
52
    float x, y, z;
53
54
6.72k
    bool operator==(const SkV3& v) const {
55
6.72k
        return x == v.x && y == v.y && z == v.z;
56
6.72k
    }
57
0
    bool operator!=(const SkV3& v) const { return !(*this == v); }
58
59
96.5k
    static SkScalar Dot(const SkV3& a, const SkV3& b) { return a.x*b.x + a.y*b.y + a.z*b.z; }
60
5.70k
    static SkV3   Cross(const SkV3& a, const SkV3& b) {
61
5.70k
        return { a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x };
62
5.70k
    }
63
0
    static SkV3 Normalize(const SkV3& v) { return v * (1.0f / v.length()); }
64
65
2.85k
    SkV3 operator-() const { return {-x, -y, -z}; }
66
22.5k
    SkV3 operator+(const SkV3& v) const { return { x + v.x, y + v.y, z + v.z }; }
67
2.85k
    SkV3 operator-(const SkV3& v) const { return { x - v.x, y - v.y, z - v.z }; }
68
69
0
    SkV3 operator*(const SkV3& v) const {
70
0
        return { x*v.x, y*v.y, z*v.z };
71
0
    }
72
90.1k
    friend SkV3 operator*(const SkV3& v, SkScalar s) {
73
90.1k
        return { v.x*s, v.y*s, v.z*s };
74
90.1k
    }
75
0
    friend SkV3 operator*(SkScalar s, const SkV3& v) { return v*s; }
76
77
0
    void operator+=(SkV3 v) { *this = *this + v; }
78
0
    void operator-=(SkV3 v) { *this = *this - v; }
79
0
    void operator*=(SkV3 v) { *this = *this * v; }
80
0
    void operator*=(SkScalar s) { *this = *this * s; }
81
82
0
    SkScalar lengthSquared() const { return Dot(*this, *this); }
83
96.5k
    SkScalar length() const { return SkScalarSqrt(Dot(*this, *this)); }
84
85
0
    SkScalar dot(const SkV3& v) const { return Dot(*this, v); }
86
5.70k
    SkV3   cross(const SkV3& v) const { return Cross(*this, v); }
87
0
    SkV3 normalize()            const { return Normalize(*this); }
88
89
0
    const float* ptr() const { return &x; }
90
0
    float* ptr() { return &x; }
91
};
92
93
struct SK_API SkV4 {
94
    float x, y, z, w;
95
96
0
    bool operator==(const SkV4& v) const {
97
0
        return x == v.x && y == v.y && z == v.z && w == v.w;
98
0
    }
99
0
    bool operator!=(const SkV4& v) const { return !(*this == v); }
100
101
0
    SkV4 operator-() const { return {-x, -y, -z, -w}; }
102
0
    SkV4 operator+(const SkV4& v) const { return { x + v.x, y + v.y, z + v.z, w + v.w }; }
103
0
    SkV4 operator-(const SkV4& v) const { return { x - v.x, y - v.y, z - v.z, w - v.w }; }
104
105
0
    SkV4 operator*(const SkV4& v) const {
106
0
        return { x*v.x, y*v.y, z*v.z, w*v.w };
107
0
    }
108
0
    friend SkV4 operator*(const SkV4& v, SkScalar s) {
109
0
        return { v.x*s, v.y*s, v.z*s, v.w*s };
110
0
    }
111
0
    friend SkV4 operator*(SkScalar s, const SkV4& v) { return v*s; }
112
113
559k
    const float* ptr() const { return &x; }
114
128
    float* ptr() { return &x; }
115
116
548k
    float operator[](int i) const {
117
548k
        SkASSERT(i >= 0 && i < 4);
118
548k
        return this->ptr()[i];
119
548k
    }
120
128
    float& operator[](int i) {
121
128
        SkASSERT(i >= 0 && i < 4);
122
128
        return this->ptr()[i];
123
128
    }
124
};
125
126
/**
127
 *  4x4 matrix used by SkCanvas and other parts of Skia.
128
 *
129
 *  Skia assumes a right-handed coordinate system:
130
 *      +X goes to the right
131
 *      +Y goes down
132
 *      +Z goes into the screen (away from the viewer)
133
 */
134
class SK_API SkM44 {
135
public:
136
    SkM44(const SkM44& src) = default;
137
    SkM44& operator=(const SkM44& src) = default;
138
139
    constexpr SkM44()
140
        : fMat{1, 0, 0, 0,
141
               0, 1, 0, 0,
142
               0, 0, 1, 0,
143
               0, 0, 0, 1}
144
2.19M
        {}
145
146
1.03M
    SkM44(const SkM44& a, const SkM44& b) {
147
1.03M
        this->setConcat(a, b);
148
1.03M
    }
149
150
    enum Uninitialized_Constructor {
151
        kUninitialized_Constructor
152
    };
153
87.2k
    SkM44(Uninitialized_Constructor) {}
154
155
    enum NaN_Constructor {
156
        kNaN_Constructor
157
    };
158
    constexpr SkM44(NaN_Constructor)
159
        : fMat{SK_ScalarNaN, SK_ScalarNaN, SK_ScalarNaN, SK_ScalarNaN,
160
               SK_ScalarNaN, SK_ScalarNaN, SK_ScalarNaN, SK_ScalarNaN,
161
               SK_ScalarNaN, SK_ScalarNaN, SK_ScalarNaN, SK_ScalarNaN,
162
               SK_ScalarNaN, SK_ScalarNaN, SK_ScalarNaN, SK_ScalarNaN}
163
0
    {}
164
165
    /**
166
     *  The constructor parameters are in row-major order.
167
     */
168
    constexpr SkM44(SkScalar m0, SkScalar m4, SkScalar m8,  SkScalar m12,
169
                    SkScalar m1, SkScalar m5, SkScalar m9,  SkScalar m13,
170
                    SkScalar m2, SkScalar m6, SkScalar m10, SkScalar m14,
171
                    SkScalar m3, SkScalar m7, SkScalar m11, SkScalar m15)
172
        // fMat is column-major order in memory.
173
        : fMat{m0,  m1,  m2,  m3,
174
               m4,  m5,  m6,  m7,
175
               m8,  m9,  m10, m11,
176
               m12, m13, m14, m15}
177
3.06M
    {}
178
179
0
    static SkM44 Rows(const SkV4& r0, const SkV4& r1, const SkV4& r2, const SkV4& r3) {
180
0
        SkM44 m(kUninitialized_Constructor);
181
0
        m.setRow(0, r0);
182
0
        m.setRow(1, r1);
183
0
        m.setRow(2, r2);
184
0
        m.setRow(3, r3);
185
0
        return m;
186
0
    }
187
2.85k
    static SkM44 Cols(const SkV4& c0, const SkV4& c1, const SkV4& c2, const SkV4& c3) {
188
2.85k
        SkM44 m(kUninitialized_Constructor);
189
2.85k
        m.setCol(0, c0);
190
2.85k
        m.setCol(1, c1);
191
2.85k
        m.setCol(2, c2);
192
2.85k
        m.setCol(3, c3);
193
2.85k
        return m;
194
2.85k
    }
195
196
0
    static SkM44 RowMajor(const SkScalar r[16]) {
197
0
        return SkM44(r[ 0], r[ 1], r[ 2], r[ 3],
198
0
                     r[ 4], r[ 5], r[ 6], r[ 7],
199
0
                     r[ 8], r[ 9], r[10], r[11],
200
0
                     r[12], r[13], r[14], r[15]);
201
0
    }
202
0
    static SkM44 ColMajor(const SkScalar c[16]) {
203
0
        return SkM44(c[0], c[4], c[ 8], c[12],
204
0
                     c[1], c[5], c[ 9], c[13],
205
0
                     c[2], c[6], c[10], c[14],
206
0
                     c[3], c[7], c[11], c[15]);
207
0
    }
208
209
177k
    static SkM44 Translate(SkScalar x, SkScalar y, SkScalar z = 0) {
210
177k
        return SkM44(1, 0, 0, x,
211
177k
                     0, 1, 0, y,
212
177k
                     0, 0, 1, z,
213
177k
                     0, 0, 0, 1);
214
177k
    }
215
216
26.6k
    static SkM44 Scale(SkScalar x, SkScalar y, SkScalar z = 1) {
217
26.6k
        return SkM44(x, 0, 0, 0,
218
26.6k
                     0, y, 0, 0,
219
26.6k
                     0, 0, z, 0,
220
26.6k
                     0, 0, 0, 1);
221
26.6k
    }
222
223
81.5k
    static SkM44 Rotate(SkV3 axis, SkScalar radians) {
224
81.5k
        SkM44 m(kUninitialized_Constructor);
225
81.5k
        m.setRotate(axis, radians);
226
81.5k
        return m;
227
81.5k
    }
228
229
    // Scales and translates 'src' to fill 'dst' exactly.
230
    static SkM44 RectToRect(const SkRect& src, const SkRect& dst);
231
232
    static SkM44 LookAt(const SkV3& eye, const SkV3& center, const SkV3& up);
233
    static SkM44 Perspective(float near, float far, float angle);
234
235
    bool operator==(const SkM44& other) const;
236
0
    bool operator!=(const SkM44& other) const {
237
0
        return !(other == *this);
238
0
    }
239
240
0
    void getColMajor(SkScalar v[]) const {
241
0
        memcpy(v, fMat, sizeof(fMat));
242
0
    }
243
    void getRowMajor(SkScalar v[]) const;
244
245
84.0k
    SkScalar rc(int r, int c) const {
246
84.0k
        SkASSERT(r >= 0 && r <= 3);
247
84.0k
        SkASSERT(c >= 0 && c <= 3);
248
84.0k
        return fMat[c*4 + r];
249
84.0k
    }
250
24.9k
    void setRC(int r, int c, SkScalar value) {
251
24.9k
        SkASSERT(r >= 0 && r <= 3);
252
24.9k
        SkASSERT(c >= 0 && c <= 3);
253
24.9k
        fMat[c*4 + r] = value;
254
24.9k
    }
255
256
32
    SkV4 row(int i) const {
257
32
        SkASSERT(i >= 0 && i <= 3);
258
32
        return {fMat[i + 0], fMat[i + 4], fMat[i + 8], fMat[i + 12]};
259
32
    }
260
0
    SkV4 col(int i) const {
261
0
        SkASSERT(i >= 0 && i <= 3);
262
0
        return {fMat[i*4 + 0], fMat[i*4 + 1], fMat[i*4 + 2], fMat[i*4 + 3]};
263
0
    }
264
265
0
    void setRow(int i, const SkV4& v) {
266
0
        SkASSERT(i >= 0 && i <= 3);
267
0
        fMat[i + 0]  = v.x;
268
0
        fMat[i + 4]  = v.y;
269
0
        fMat[i + 8]  = v.z;
270
0
        fMat[i + 12] = v.w;
271
0
    }
272
11.4k
    void setCol(int i, const SkV4& v) {
273
11.4k
        SkASSERT(i >= 0 && i <= 3);
274
11.4k
        memcpy(&fMat[i*4], v.ptr(), sizeof(v));
275
11.4k
    }
276
277
1.06M
    SkM44& setIdentity() {
278
1.06M
        *this = { 1, 0, 0, 0,
279
1.06M
                  0, 1, 0, 0,
280
1.06M
                  0, 0, 1, 0,
281
1.06M
                  0, 0, 0, 1 };
282
1.06M
        return *this;
283
1.06M
    }
284
285
0
    SkM44& setTranslate(SkScalar x, SkScalar y, SkScalar z = 0) {
286
0
        *this = { 1, 0, 0, x,
287
0
                  0, 1, 0, y,
288
0
                  0, 0, 1, z,
289
0
                  0, 0, 0, 1 };
290
0
        return *this;
291
0
    }
292
293
0
    SkM44& setScale(SkScalar x, SkScalar y, SkScalar z = 1) {
294
0
        *this = { x, 0, 0, 0,
295
0
                  0, y, 0, 0,
296
0
                  0, 0, z, 0,
297
0
                  0, 0, 0, 1 };
298
0
        return *this;
299
0
    }
300
301
    /**
302
     *  Set this matrix to rotate about the specified unit-length axis vector,
303
     *  by an angle specified by its sin() and cos().
304
     *
305
     *  This does not attempt to verify that axis.length() == 1 or that the sin,cos values
306
     *  are correct.
307
     */
308
    SkM44& setRotateUnitSinCos(SkV3 axis, SkScalar sinAngle, SkScalar cosAngle);
309
310
    /**
311
     *  Set this matrix to rotate about the specified unit-length axis vector,
312
     *  by an angle specified in radians.
313
     *
314
     *  This does not attempt to verify that axis.length() == 1.
315
     */
316
81.5k
    SkM44& setRotateUnit(SkV3 axis, SkScalar radians) {
317
81.5k
        return this->setRotateUnitSinCos(axis, SkScalarSin(radians), SkScalarCos(radians));
318
81.5k
    }
319
320
    /**
321
     *  Set this matrix to rotate about the specified axis vector,
322
     *  by an angle specified in radians.
323
     *
324
     *  Note: axis is not assumed to be unit-length, so it will be normalized internally.
325
     *        If axis is already unit-length, call setRotateAboutUnitRadians() instead.
326
     */
327
    SkM44& setRotate(SkV3 axis, SkScalar radians);
328
329
    SkM44& setConcat(const SkM44& a, const SkM44& b);
330
331
1.03M
    friend SkM44 operator*(const SkM44& a, const SkM44& b) {
332
1.03M
        return SkM44(a, b);
333
1.03M
    }
334
335
68.6k
    SkM44& preConcat(const SkM44& m) {
336
68.6k
        return this->setConcat(*this, m);
337
68.6k
    }
338
339
885k
    SkM44& postConcat(const SkM44& m) {
340
885k
        return this->setConcat(m, *this);
341
885k
    }
342
343
    /**
344
     *  A matrix is categorized as 'perspective' if the bottom row is not [0, 0, 0, 1].
345
     *  For most uses, a bottom row of [0, 0, 0, X] behaves like a non-perspective matrix, though
346
     *  it will be categorized as perspective. Calling normalizePerspective() will change the
347
     *  matrix such that, if its bottom row was [0, 0, 0, X], it will be changed to [0, 0, 0, 1]
348
     *  by scaling the rest of the matrix by 1/X.
349
     *
350
     *  | A B C D |    | A/X B/X C/X D/X |
351
     *  | E F G H | -> | E/X F/X G/X H/X |   for X != 0
352
     *  | I J K L |    | I/X J/X K/X L/X |
353
     *  | 0 0 0 X |    |  0   0   0   1  |
354
     */
355
    void normalizePerspective();
356
357
    /** Returns true if all elements of the matrix are finite. Returns false if any
358
        element is infinity, or NaN.
359
360
        @return  true if matrix has only finite elements
361
    */
362
0
    bool isFinite() const { return SkScalarsAreFinite(fMat, 16); }
363
364
    /** If this is invertible, return that in inverse and return true. If it is
365
     *  not invertible, return false and leave the inverse parameter unchanged.
366
     */
367
    bool SK_WARN_UNUSED_RESULT invert(SkM44* inverse) const;
368
369
    SkM44 SK_WARN_UNUSED_RESULT transpose() const;
370
371
    void dump() const;
372
373
    ////////////
374
375
    SkV4 map(float x, float y, float z, float w) const;
376
0
    SkV4 operator*(const SkV4& v) const {
377
0
        return this->map(v.x, v.y, v.z, v.w);
378
0
    }
379
0
    SkV3 operator*(SkV3 v) const {
380
0
        auto v4 = this->map(v.x, v.y, v.z, 0);
381
0
        return {v4.x, v4.y, v4.z};
382
0
    }
383
    ////////////////////// Converting to/from SkMatrix
384
385
    /* When converting from SkM44 to SkMatrix, the third row and
386
     * column is dropped.  When converting from SkMatrix to SkM44
387
     * the third row and column remain as identity:
388
     * [ a b c ]      [ a b 0 c ]
389
     * [ d e f ]  ->  [ d e 0 f ]
390
     * [ g h i ]      [ 0 0 1 0 ]
391
     *                [ g h 0 i ]
392
     */
393
2.84M
    SkMatrix asM33() const {
394
2.84M
        return SkMatrix::MakeAll(fMat[0], fMat[4], fMat[12],
395
2.84M
                                 fMat[1], fMat[5], fMat[13],
396
2.84M
                                 fMat[3], fMat[7], fMat[15]);
397
2.84M
    }
398
399
    explicit SkM44(const SkMatrix& src)
400
    : SkM44(src[SkMatrix::kMScaleX], src[SkMatrix::kMSkewX],  0, src[SkMatrix::kMTransX],
401
            src[SkMatrix::kMSkewY],  src[SkMatrix::kMScaleY], 0, src[SkMatrix::kMTransY],
402
            0,                       0,                       1, 0,
403
            src[SkMatrix::kMPersp0], src[SkMatrix::kMPersp1], 0, src[SkMatrix::kMPersp2])
404
1.71M
    {}
405
406
    SkM44& preTranslate(SkScalar x, SkScalar y, SkScalar z = 0);
407
    SkM44& postTranslate(SkScalar x, SkScalar y, SkScalar z = 0);
408
409
    SkM44& preScale(SkScalar x, SkScalar y);
410
    SkM44& preScale(SkScalar x, SkScalar y, SkScalar z);
411
    SkM44& preConcat(const SkMatrix&);
412
413
private:
414
    /* Stored in column-major.
415
     *  Indices
416
     *  0  4  8  12        1 0 0 trans_x
417
     *  1  5  9  13  e.g.  0 1 0 trans_y
418
     *  2  6 10  14        0 0 1 trans_z
419
     *  3  7 11  15        0 0 0 1
420
     */
421
    SkScalar fMat[16];
422
423
    friend class SkMatrixPriv;
424
};
425
426
#endif