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 bool operator==(const SkV2 v) const { return x == v.x && y == v.y; } 23 bool operator!=(const SkV2 v) const { return !(*this == v); } 24 DotSkV225 static SkScalar Dot(SkV2 a, SkV2 b) { return a.x * b.x + a.y * b.y; } CrossSkV226 static SkScalar Cross(SkV2 a, SkV2 b) { return a.x * b.y - a.y * b.x; } NormalizeSkV227 static SkV2 Normalize(SkV2 v) { return v * (1.0f / v.length()); } 28 29 SkV2 operator-() const { return {-x, -y}; } 30 SkV2 operator+(SkV2 v) const { return {x+v.x, y+v.y}; } 31 SkV2 operator-(SkV2 v) const { return {x-v.x, y-v.y}; } 32 33 SkV2 operator*(SkV2 v) const { return {x*v.x, y*v.y}; } 34 friend SkV2 operator*(SkV2 v, SkScalar s) { return {v.x*s, v.y*s}; } 35 friend SkV2 operator*(SkScalar s, SkV2 v) { return {v.x*s, v.y*s}; } 36 friend SkV2 operator/(SkV2 v, SkScalar s) { return {v.x/s, v.y/s}; } 37 friend SkV2 operator/(SkScalar s, SkV2 v) { return {s/v.x, s/v.y}; } 38 39 void operator+=(SkV2 v) { *this = *this + v; } 40 void operator-=(SkV2 v) { *this = *this - v; } 41 void operator*=(SkV2 v) { *this = *this * v; } 42 void operator*=(SkScalar s) { *this = *this * s; } 43 void operator/=(SkScalar s) { *this = *this / s; } 44 lengthSquaredSkV245 SkScalar lengthSquared() const { return Dot(*this, *this); } lengthSkV246 SkScalar length() const { return SkScalarSqrt(this->lengthSquared()); } 47 dotSkV248 SkScalar dot(SkV2 v) const { return Dot(*this, v); } crossSkV249 SkScalar cross(SkV2 v) const { return Cross(*this, v); } normalizeSkV250 SkV2 normalize() const { return Normalize(*this); } 51 ptrSkV252 const float* ptr() const { return &x; } ptrSkV253 float* ptr() { return &x; } 54 }; 55 56 struct SK_API SkV3 { 57 float x, y, z; 58 59 bool operator==(const SkV3& v) const { 60 return x == v.x && y == v.y && z == v.z; 61 } 62 bool operator!=(const SkV3& v) const { return !(*this == v); } 63 DotSkV364 static SkScalar Dot(const SkV3& a, const SkV3& b) { return a.x*b.x + a.y*b.y + a.z*b.z; } CrossSkV365 static SkV3 Cross(const SkV3& a, const SkV3& b) { 66 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 } NormalizeSkV368 static SkV3 Normalize(const SkV3& v) { return v * (1.0f / v.length()); } 69 70 SkV3 operator-() const { return {-x, -y, -z}; } 71 SkV3 operator+(const SkV3& v) const { return { x + v.x, y + v.y, z + v.z }; } 72 SkV3 operator-(const SkV3& v) const { return { x - v.x, y - v.y, z - v.z }; } 73 74 SkV3 operator*(const SkV3& v) const { 75 return { x*v.x, y*v.y, z*v.z }; 76 } 77 friend SkV3 operator*(const SkV3& v, SkScalar s) { 78 return { v.x*s, v.y*s, v.z*s }; 79 } 80 friend SkV3 operator*(SkScalar s, const SkV3& v) { return v*s; } 81 82 void operator+=(SkV3 v) { *this = *this + v; } 83 void operator-=(SkV3 v) { *this = *this - v; } 84 void operator*=(SkV3 v) { *this = *this * v; } 85 void operator*=(SkScalar s) { *this = *this * s; } 86 lengthSquaredSkV387 SkScalar lengthSquared() const { return Dot(*this, *this); } lengthSkV388 SkScalar length() const { return SkScalarSqrt(Dot(*this, *this)); } 89 dotSkV390 SkScalar dot(const SkV3& v) const { return Dot(*this, v); } crossSkV391 SkV3 cross(const SkV3& v) const { return Cross(*this, v); } normalizeSkV392 SkV3 normalize() const { return Normalize(*this); } 93 ptrSkV394 const float* ptr() const { return &x; } ptrSkV395 float* ptr() { return &x; } 96 }; 97 98 struct SK_API SkV4 { 99 float x, y, z, w; 100 101 bool operator==(const SkV4& v) const { 102 return x == v.x && y == v.y && z == v.z && w == v.w; 103 } 104 bool operator!=(const SkV4& v) const { return !(*this == v); } 105 DotSkV4106 static SkScalar Dot(const SkV4& a, const SkV4& b) { 107 return a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w; 108 } NormalizeSkV4109 static SkV4 Normalize(const SkV4& v) { return v * (1.0f / v.length()); } 110 111 SkV4 operator-() const { return {-x, -y, -z, -w}; } 112 SkV4 operator+(const SkV4& v) const { return { x + v.x, y + v.y, z + v.z, w + v.w }; } 113 SkV4 operator-(const SkV4& v) const { return { x - v.x, y - v.y, z - v.z, w - v.w }; } 114 115 SkV4 operator*(const SkV4& v) const { 116 return { x*v.x, y*v.y, z*v.z, w*v.w }; 117 } 118 friend SkV4 operator*(const SkV4& v, SkScalar s) { 119 return { v.x*s, v.y*s, v.z*s, v.w*s }; 120 } 121 friend SkV4 operator*(SkScalar s, const SkV4& v) { return v*s; } 122 lengthSquaredSkV4123 SkScalar lengthSquared() const { return Dot(*this, *this); } lengthSkV4124 SkScalar length() const { return SkScalarSqrt(Dot(*this, *this)); } 125 dotSkV4126 SkScalar dot(const SkV4& v) const { return Dot(*this, v); } normalizeSkV4127 SkV4 normalize() const { return Normalize(*this); } 128 ptrSkV4129 const float* ptr() const { return &x; } ptrSkV4130 float* ptr() { return &x; } 131 132 float operator[](int i) const { 133 SkASSERT(i >= 0 && i < 4); 134 return this->ptr()[i]; 135 } 136 float& operator[](int i) { 137 SkASSERT(i >= 0 && i < 4); 138 return this->ptr()[i]; 139 } 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 SkM44()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 {} 161 SkM44(const SkM44 & a,const SkM44 & b)162 SkM44(const SkM44& a, const SkM44& b) { 163 this->setConcat(a, b); 164 } 165 166 enum Uninitialized_Constructor { 167 kUninitialized_Constructor 168 }; SkM44(Uninitialized_Constructor)169 SkM44(Uninitialized_Constructor) {} 170 171 enum NaN_Constructor { 172 kNaN_Constructor 173 }; SkM44(NaN_Constructor)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 {} 180 181 /** 182 * The constructor parameters are in row-major order. 183 */ SkM44(SkScalar m0,SkScalar m4,SkScalar m8,SkScalar m12,SkScalar m1,SkScalar m5,SkScalar m9,SkScalar m13,SkScalar m2,SkScalar m6,SkScalar m10,SkScalar m14,SkScalar m3,SkScalar m7,SkScalar m11,SkScalar m15)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 {} 194 Rows(const SkV4 & r0,const SkV4 & r1,const SkV4 & r2,const SkV4 & r3)195 static SkM44 Rows(const SkV4& r0, const SkV4& r1, const SkV4& r2, const SkV4& r3) { 196 SkM44 m(kUninitialized_Constructor); 197 m.setRow(0, r0); 198 m.setRow(1, r1); 199 m.setRow(2, r2); 200 m.setRow(3, r3); 201 return m; 202 } Cols(const SkV4 & c0,const SkV4 & c1,const SkV4 & c2,const SkV4 & c3)203 static SkM44 Cols(const SkV4& c0, const SkV4& c1, const SkV4& c2, const SkV4& c3) { 204 SkM44 m(kUninitialized_Constructor); 205 m.setCol(0, c0); 206 m.setCol(1, c1); 207 m.setCol(2, c2); 208 m.setCol(3, c3); 209 return m; 210 } 211 RowMajor(const SkScalar r[16])212 static SkM44 RowMajor(const SkScalar r[16]) { 213 return SkM44(r[ 0], r[ 1], r[ 2], r[ 3], 214 r[ 4], r[ 5], r[ 6], r[ 7], 215 r[ 8], r[ 9], r[10], r[11], 216 r[12], r[13], r[14], r[15]); 217 } ColMajor(const SkScalar c[16])218 static SkM44 ColMajor(const SkScalar c[16]) { 219 return SkM44(c[0], c[4], c[ 8], c[12], 220 c[1], c[5], c[ 9], c[13], 221 c[2], c[6], c[10], c[14], 222 c[3], c[7], c[11], c[15]); 223 } 224 225 static SkM44 Translate(SkScalar x, SkScalar y, SkScalar z = 0) { 226 return SkM44(1, 0, 0, x, 227 0, 1, 0, y, 228 0, 0, 1, z, 229 0, 0, 0, 1); 230 } 231 232 static SkM44 Scale(SkScalar x, SkScalar y, SkScalar z = 1) { 233 return SkM44(x, 0, 0, 0, 234 0, y, 0, 0, 235 0, 0, z, 0, 236 0, 0, 0, 1); 237 } 238 Rotate(SkV3 axis,SkScalar radians)239 static SkM44 Rotate(SkV3 axis, SkScalar radians) { 240 SkM44 m(kUninitialized_Constructor); 241 m.setRotate(axis, radians); 242 return m; 243 } 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 bool operator!=(const SkM44& other) const { 253 return !(other == *this); 254 } 255 getColMajor(SkScalar v[])256 void getColMajor(SkScalar v[]) const { 257 memcpy(v, fMat, sizeof(fMat)); 258 } 259 void getRowMajor(SkScalar v[]) const; 260 rc(int r,int c)261 SkScalar rc(int r, int c) const { 262 SkASSERT(r >= 0 && r <= 3); 263 SkASSERT(c >= 0 && c <= 3); 264 return fMat[c*4 + r]; 265 } setRC(int r,int c,SkScalar value)266 void setRC(int r, int c, SkScalar value) { 267 SkASSERT(r >= 0 && r <= 3); 268 SkASSERT(c >= 0 && c <= 3); 269 fMat[c*4 + r] = value; 270 } 271 row(int i)272 SkV4 row(int i) const { 273 SkASSERT(i >= 0 && i <= 3); 274 return {fMat[i + 0], fMat[i + 4], fMat[i + 8], fMat[i + 12]}; 275 } col(int i)276 SkV4 col(int i) const { 277 SkASSERT(i >= 0 && i <= 3); 278 return {fMat[i*4 + 0], fMat[i*4 + 1], fMat[i*4 + 2], fMat[i*4 + 3]}; 279 } 280 setRow(int i,const SkV4 & v)281 void setRow(int i, const SkV4& v) { 282 SkASSERT(i >= 0 && i <= 3); 283 fMat[i + 0] = v.x; 284 fMat[i + 4] = v.y; 285 fMat[i + 8] = v.z; 286 fMat[i + 12] = v.w; 287 } setCol(int i,const SkV4 & v)288 void setCol(int i, const SkV4& v) { 289 SkASSERT(i >= 0 && i <= 3); 290 memcpy(&fMat[i*4], v.ptr(), sizeof(v)); 291 } 292 setIdentity()293 SkM44& setIdentity() { 294 *this = { 1, 0, 0, 0, 295 0, 1, 0, 0, 296 0, 0, 1, 0, 297 0, 0, 0, 1 }; 298 return *this; 299 } 300 301 SkM44& setTranslate(SkScalar x, SkScalar y, SkScalar z = 0) { 302 *this = { 1, 0, 0, x, 303 0, 1, 0, y, 304 0, 0, 1, z, 305 0, 0, 0, 1 }; 306 return *this; 307 } 308 309 SkM44& setScale(SkScalar x, SkScalar y, SkScalar z = 1) { 310 *this = { x, 0, 0, 0, 311 0, y, 0, 0, 312 0, 0, z, 0, 313 0, 0, 0, 1 }; 314 return *this; 315 } 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 */ setRotateUnit(SkV3 axis,SkScalar radians)332 SkM44& setRotateUnit(SkV3 axis, SkScalar radians) { 333 return this->setRotateUnitSinCos(axis, SkScalarSin(radians), SkScalarCos(radians)); 334 } 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 friend SkM44 operator*(const SkM44& a, const SkM44& b) { 348 return SkM44(a, b); 349 } 350 preConcat(const SkM44 & m)351 SkM44& preConcat(const SkM44& m) { 352 return this->setConcat(*this, m); 353 } 354 postConcat(const SkM44 & m)355 SkM44& postConcat(const SkM44& m) { 356 return this->setConcat(m, *this); 357 } 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 */ isFinite()378 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 SkV4 operator*(const SkV4& v) const { 393 return this->map(v.x, v.y, v.z, v.w); 394 } 395 SkV3 operator*(SkV3 v) const { 396 auto v4 = this->map(v.x, v.y, v.z, 0); 397 return {v4.x, v4.y, v4.z}; 398 } 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 */ asM33()409 SkMatrix asM33() const { 410 return SkMatrix::MakeAll(fMat[0], fMat[4], fMat[12], 411 fMat[1], fMat[5], fMat[13], 412 fMat[3], fMat[7], fMat[15]); 413 } 414 SkM44(const SkMatrix & src)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 {} 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 443