Coverage Report

Created: 2024-05-20 07:14

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