Coverage Report

Created: 2024-09-14 07:19

/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
208k
    bool operator==(const SkV2 v) const { return x == v.x && y == v.y; }
23
178k
    bool operator!=(const SkV2 v) const { return !(*this == v); }
24
25
115k
    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
4.50k
    SkV2 operator+(SkV2 v) const { return {x+v.x, y+v.y}; }
31
48.1k
    SkV2 operator-(SkV2 v) const { return {x-v.x, y-v.y}; }
32
33
0
    SkV2 operator*(SkV2 v) const { return {x*v.x, y*v.y}; }
34
4.50k
    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
78.2k
    SkScalar lengthSquared() const { return Dot(*this, *this); }
46
0
    SkScalar length() const { return SkScalarSqrt(this->lengthSquared()); }
47
48
37.4k
    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
10.0k
    bool operator==(const SkV3& v) const {
60
10.0k
        return x == v.x && y == v.y && z == v.z;
61
10.0k
    }
62
0
    bool operator!=(const SkV3& v) const { return !(*this == v); }
63
64
106k
    static SkScalar Dot(const SkV3& a, const SkV3& b) { return a.x*b.x + a.y*b.y + a.z*b.z; }
65
3.92k
    static SkV3   Cross(const SkV3& a, const SkV3& b) {
66
3.92k
        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.92k
    }
68
0
    static SkV3 Normalize(const SkV3& v) { return v * (1.0f / v.length()); }
69
70
1.96k
    SkV3 operator-() const { return {-x, -y, -z}; }
71
21.7k
    SkV3 operator+(const SkV3& v) const { return { x + v.x, y + v.y, z + v.z }; }
72
1.96k
    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
92.0k
    friend SkV3 operator*(const SkV3& v, SkScalar s) {
78
92.0k
        return { v.x*s, v.y*s, v.z*s };
79
92.0k
    }
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
106k
    SkScalar length() const { return SkScalarSqrt(Dot(*this, *this)); }
89
90
0
    SkScalar dot(const SkV3& v) const { return Dot(*this, v); }
91
3.92k
    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
21.4k
    const float* ptr() const { return &x; }
130
3.36k
    float* ptr() { return &x; }
131
132
13.5k
    float operator[](int i) const {
133
13.5k
        SkASSERT(i >= 0 && i < 4);
134
13.5k
        return this->ptr()[i];
135
13.5k
    }
136
2.58k
    float& operator[](int i) {
137
2.58k
        SkASSERT(i >= 0 && i < 4);
138
2.58k
        return this->ptr()[i];
139
2.58k
    }
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
2.83M
        {}
161
162
283k
    SkM44(const SkM44& a, const SkM44& b) {
163
283k
        this->setConcat(a, b);
164
283k
    }
165
166
    enum Uninitialized_Constructor {
167
        kUninitialized_Constructor
168
    };
169
90.0k
    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.19M
    {}
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.96k
    static SkM44 Cols(const SkV4& c0, const SkV4& c1, const SkV4& c2, const SkV4& c3) {
204
1.96k
        SkM44 m(kUninitialized_Constructor);
205
1.96k
        m.setCol(0, c0);
206
1.96k
        m.setCol(1, c1);
207
1.96k
        m.setCol(2, c2);
208
1.96k
        m.setCol(3, c3);
209
1.96k
        return m;
210
1.96k
    }
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
1.66k
    static SkM44 ColMajor(const SkScalar c[16]) {
219
1.66k
        return SkM44(c[0], c[4], c[ 8], c[12],
220
1.66k
                     c[1], c[5], c[ 9], c[13],
221
1.66k
                     c[2], c[6], c[10], c[14],
222
1.66k
                     c[3], c[7], c[11], c[15]);
223
1.66k
    }
224
225
48.2k
    static SkM44 Translate(SkScalar x, SkScalar y, SkScalar z = 0) {
226
48.2k
        return SkM44(1, 0, 0, x,
227
48.2k
                     0, 1, 0, y,
228
48.2k
                     0, 0, 1, z,
229
48.2k
                     0, 0, 0, 1);
230
48.2k
    }
231
232
25.6k
    static SkM44 Scale(SkScalar x, SkScalar y, SkScalar z = 1) {
233
25.6k
        return SkM44(x, 0, 0, 0,
234
25.6k
                     0, y, 0, 0,
235
25.6k
                     0, 0, z, 0,
236
25.6k
                     0, 0, 0, 1);
237
25.6k
    }
238
239
86.0k
    static SkM44 Rotate(SkV3 axis, SkScalar radians) {
240
86.0k
        SkM44 m(kUninitialized_Constructor);
241
86.0k
        m.setRotate(axis, radians);
242
86.0k
        return m;
243
86.0k
    }
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
197
    void getColMajor(SkScalar v[]) const {
257
197
        memcpy(v, fMat, sizeof(fMat));
258
197
    }
259
    void getRowMajor(SkScalar v[]) const;
260
261
5.72M
    SkScalar rc(int r, int c) const {
262
5.72M
        SkASSERT(r >= 0 && r <= 3);
263
5.72M
        SkASSERT(c >= 0 && c <= 3);
264
5.72M
        return fMat[c*4 + r];
265
5.72M
    }
266
9.81k
    void setRC(int r, int c, SkScalar value) {
267
9.81k
        SkASSERT(r >= 0 && r <= 3);
268
9.81k
        SkASSERT(c >= 0 && c <= 3);
269
9.81k
        fMat[c*4 + r] = value;
270
9.81k
    }
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
7.84k
    void setCol(int i, const SkV4& v) {
289
7.84k
        SkASSERT(i >= 0 && i <= 3);
290
7.84k
        memcpy(&fMat[i*4], v.ptr(), sizeof(v));
291
7.84k
    }
292
293
1.12M
    SkM44& setIdentity() {
294
1.12M
        *this = { 1, 0, 0, 0,
295
1.12M
                  0, 1, 0, 0,
296
1.12M
                  0, 0, 1, 0,
297
1.12M
                  0, 0, 0, 1 };
298
1.12M
        return *this;
299
1.12M
    }
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
86.0k
    SkM44& setRotateUnit(SkV3 axis, SkScalar radians) {
333
86.0k
        return this->setRotateUnitSinCos(axis, SkScalarSin(radians), SkScalarCos(radians));
334
86.0k
    }
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
283k
    friend SkM44 operator*(const SkM44& a, const SkM44& b) {
348
283k
        return SkM44(a, b);
349
283k
    }
350
351
147k
    SkM44& preConcat(const SkM44& m) {
352
147k
        return this->setConcat(*this, m);
353
147k
    }
354
355
581k
    SkM44& postConcat(const SkM44& m) {
356
581k
        return this->setConcat(m, *this);
357
581k
    }
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.26M
    SkMatrix asM33() const {
410
1.26M
        return SkMatrix::MakeAll(fMat[0], fMat[4], fMat[12],
411
1.26M
                                 fMat[1], fMat[5], fMat[13],
412
1.26M
                                 fMat[3], fMat[7], fMat[15]);
413
1.26M
    }
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
909k
    {}
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