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 bool operator==(const SkV2 v) const { return x == v.x && y == v.y; } 19 bool operator!=(const SkV2 v) const { return !(*this == v); } 20 DotSkV221 static SkScalar Dot(SkV2 a, SkV2 b) { return a.x * b.x + a.y * b.y; } CrossSkV222 static SkScalar Cross(SkV2 a, SkV2 b) { return a.x * b.y - a.y * b.x; } NormalizeSkV223 static SkV2 Normalize(SkV2 v) { return v * (1.0f / v.length()); } 24 25 SkV2 operator-() const { return {-x, -y}; } 26 SkV2 operator+(SkV2 v) const { return {x+v.x, y+v.y}; } 27 SkV2 operator-(SkV2 v) const { return {x-v.x, y-v.y}; } 28 29 SkV2 operator*(SkV2 v) const { return {x*v.x, y*v.y}; } 30 friend SkV2 operator*(SkV2 v, SkScalar s) { return {v.x*s, v.y*s}; } 31 friend SkV2 operator*(SkScalar s, SkV2 v) { return {v.x*s, v.y*s}; } 32 friend SkV2 operator/(SkV2 v, SkScalar s) { return {v.x/s, v.y/s}; } 33 34 void operator+=(SkV2 v) { *this = *this + v; } 35 void operator-=(SkV2 v) { *this = *this - v; } 36 void operator*=(SkV2 v) { *this = *this * v; } 37 void operator*=(SkScalar s) { *this = *this * s; } 38 void operator/=(SkScalar s) { *this = *this / s; } 39 lengthSquaredSkV240 SkScalar lengthSquared() const { return Dot(*this, *this); } lengthSkV241 SkScalar length() const { return SkScalarSqrt(this->lengthSquared()); } 42 dotSkV243 SkScalar dot(SkV2 v) const { return Dot(*this, v); } crossSkV244 SkScalar cross(SkV2 v) const { return Cross(*this, v); } normalizeSkV245 SkV2 normalize() const { return Normalize(*this); } 46 ptrSkV247 const float* ptr() const { return &x; } ptrSkV248 float* ptr() { return &x; } 49 }; 50 51 struct SK_API SkV3 { 52 float x, y, z; 53 54 bool operator==(const SkV3& v) const { 55 return x == v.x && y == v.y && z == v.z; 56 } 57 bool operator!=(const SkV3& v) const { return !(*this == v); } 58 DotSkV359 static SkScalar Dot(const SkV3& a, const SkV3& b) { return a.x*b.x + a.y*b.y + a.z*b.z; } CrossSkV360 static SkV3 Cross(const SkV3& a, const SkV3& b) { 61 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 } NormalizeSkV363 static SkV3 Normalize(const SkV3& v) { return v * (1.0f / v.length()); } 64 65 SkV3 operator-() const { return {-x, -y, -z}; } 66 SkV3 operator+(const SkV3& v) const { return { x + v.x, y + v.y, z + v.z }; } 67 SkV3 operator-(const SkV3& v) const { return { x - v.x, y - v.y, z - v.z }; } 68 69 SkV3 operator*(const SkV3& v) const { 70 return { x*v.x, y*v.y, z*v.z }; 71 } 72 friend SkV3 operator*(const SkV3& v, SkScalar s) { 73 return { v.x*s, v.y*s, v.z*s }; 74 } 75 friend SkV3 operator*(SkScalar s, const SkV3& v) { return v*s; } 76 77 void operator+=(SkV3 v) { *this = *this + v; } 78 void operator-=(SkV3 v) { *this = *this - v; } 79 void operator*=(SkV3 v) { *this = *this * v; } 80 void operator*=(SkScalar s) { *this = *this * s; } 81 lengthSquaredSkV382 SkScalar lengthSquared() const { return Dot(*this, *this); } lengthSkV383 SkScalar length() const { return SkScalarSqrt(Dot(*this, *this)); } 84 dotSkV385 SkScalar dot(const SkV3& v) const { return Dot(*this, v); } crossSkV386 SkV3 cross(const SkV3& v) const { return Cross(*this, v); } normalizeSkV387 SkV3 normalize() const { return Normalize(*this); } 88 ptrSkV389 const float* ptr() const { return &x; } ptrSkV390 float* ptr() { return &x; } 91 }; 92 93 struct SK_API SkV4 { 94 float x, y, z, w; 95 96 bool operator==(const SkV4& v) const { 97 return x == v.x && y == v.y && z == v.z && w == v.w; 98 } 99 bool operator!=(const SkV4& v) const { return !(*this == v); } 100 101 SkV4 operator-() const { return {-x, -y, -z, -w}; } 102 SkV4 operator+(const SkV4& v) const { return { x + v.x, y + v.y, z + v.z, w + v.w }; } 103 SkV4 operator-(const SkV4& v) const { return { x - v.x, y - v.y, z - v.z, w - v.w }; } 104 105 SkV4 operator*(const SkV4& v) const { 106 return { x*v.x, y*v.y, z*v.z, w*v.w }; 107 } 108 friend SkV4 operator*(const SkV4& v, SkScalar s) { 109 return { v.x*s, v.y*s, v.z*s, v.w*s }; 110 } 111 friend SkV4 operator*(SkScalar s, const SkV4& v) { return v*s; } 112 ptrSkV4113 const float* ptr() const { return &x; } ptrSkV4114 float* ptr() { return &x; } 115 116 float operator[](int i) const { 117 SkASSERT(i >= 0 && i < 4); 118 return this->ptr()[i]; 119 } 120 float& operator[](int i) { 121 SkASSERT(i >= 0 && i < 4); 122 return this->ptr()[i]; 123 } 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 SkM44()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 {} 145 SkM44(const SkM44 & a,const SkM44 & b)146 SkM44(const SkM44& a, const SkM44& b) { 147 this->setConcat(a, b); 148 } 149 150 enum Uninitialized_Constructor { 151 kUninitialized_Constructor 152 }; SkM44(Uninitialized_Constructor)153 SkM44(Uninitialized_Constructor) {} 154 155 enum NaN_Constructor { 156 kNaN_Constructor 157 }; SkM44(NaN_Constructor)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 {} 164 165 /** 166 * The constructor parameters are in row-major order. 167 */ 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)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 {} 178 Rows(const SkV4 & r0,const SkV4 & r1,const SkV4 & r2,const SkV4 & r3)179 static SkM44 Rows(const SkV4& r0, const SkV4& r1, const SkV4& r2, const SkV4& r3) { 180 SkM44 m(kUninitialized_Constructor); 181 m.setRow(0, r0); 182 m.setRow(1, r1); 183 m.setRow(2, r2); 184 m.setRow(3, r3); 185 return m; 186 } Cols(const SkV4 & c0,const SkV4 & c1,const SkV4 & c2,const SkV4 & c3)187 static SkM44 Cols(const SkV4& c0, const SkV4& c1, const SkV4& c2, const SkV4& c3) { 188 SkM44 m(kUninitialized_Constructor); 189 m.setCol(0, c0); 190 m.setCol(1, c1); 191 m.setCol(2, c2); 192 m.setCol(3, c3); 193 return m; 194 } 195 RowMajor(const SkScalar r[16])196 static SkM44 RowMajor(const SkScalar r[16]) { 197 return SkM44(r[ 0], r[ 1], r[ 2], r[ 3], 198 r[ 4], r[ 5], r[ 6], r[ 7], 199 r[ 8], r[ 9], r[10], r[11], 200 r[12], r[13], r[14], r[15]); 201 } ColMajor(const SkScalar c[16])202 static SkM44 ColMajor(const SkScalar c[16]) { 203 return SkM44(c[0], c[4], c[ 8], c[12], 204 c[1], c[5], c[ 9], c[13], 205 c[2], c[6], c[10], c[14], 206 c[3], c[7], c[11], c[15]); 207 } 208 209 static SkM44 Translate(SkScalar x, SkScalar y, SkScalar z = 0) { 210 return SkM44(1, 0, 0, x, 211 0, 1, 0, y, 212 0, 0, 1, z, 213 0, 0, 0, 1); 214 } 215 216 static SkM44 Scale(SkScalar x, SkScalar y, SkScalar z = 1) { 217 return SkM44(x, 0, 0, 0, 218 0, y, 0, 0, 219 0, 0, z, 0, 220 0, 0, 0, 1); 221 } 222 Rotate(SkV3 axis,SkScalar radians)223 static SkM44 Rotate(SkV3 axis, SkScalar radians) { 224 SkM44 m(kUninitialized_Constructor); 225 m.setRotate(axis, radians); 226 return m; 227 } 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 bool operator!=(const SkM44& other) const { 237 return !(other == *this); 238 } 239 getColMajor(SkScalar v[])240 void getColMajor(SkScalar v[]) const { 241 memcpy(v, fMat, sizeof(fMat)); 242 } 243 void getRowMajor(SkScalar v[]) const; 244 rc(int r,int c)245 SkScalar rc(int r, int c) const { 246 SkASSERT(r >= 0 && r <= 3); 247 SkASSERT(c >= 0 && c <= 3); 248 return fMat[c*4 + r]; 249 } setRC(int r,int c,SkScalar value)250 void setRC(int r, int c, SkScalar value) { 251 SkASSERT(r >= 0 && r <= 3); 252 SkASSERT(c >= 0 && c <= 3); 253 fMat[c*4 + r] = value; 254 } 255 row(int i)256 SkV4 row(int i) const { 257 SkASSERT(i >= 0 && i <= 3); 258 return {fMat[i + 0], fMat[i + 4], fMat[i + 8], fMat[i + 12]}; 259 } col(int i)260 SkV4 col(int i) const { 261 SkASSERT(i >= 0 && i <= 3); 262 return {fMat[i*4 + 0], fMat[i*4 + 1], fMat[i*4 + 2], fMat[i*4 + 3]}; 263 } 264 setRow(int i,const SkV4 & v)265 void setRow(int i, const SkV4& v) { 266 SkASSERT(i >= 0 && i <= 3); 267 fMat[i + 0] = v.x; 268 fMat[i + 4] = v.y; 269 fMat[i + 8] = v.z; 270 fMat[i + 12] = v.w; 271 } setCol(int i,const SkV4 & v)272 void setCol(int i, const SkV4& v) { 273 SkASSERT(i >= 0 && i <= 3); 274 memcpy(&fMat[i*4], v.ptr(), sizeof(v)); 275 } 276 setIdentity()277 SkM44& setIdentity() { 278 *this = { 1, 0, 0, 0, 279 0, 1, 0, 0, 280 0, 0, 1, 0, 281 0, 0, 0, 1 }; 282 return *this; 283 } 284 285 SkM44& setTranslate(SkScalar x, SkScalar y, SkScalar z = 0) { 286 *this = { 1, 0, 0, x, 287 0, 1, 0, y, 288 0, 0, 1, z, 289 0, 0, 0, 1 }; 290 return *this; 291 } 292 293 SkM44& setScale(SkScalar x, SkScalar y, SkScalar z = 1) { 294 *this = { x, 0, 0, 0, 295 0, y, 0, 0, 296 0, 0, z, 0, 297 0, 0, 0, 1 }; 298 return *this; 299 } 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 */ setRotateUnit(SkV3 axis,SkScalar radians)316 SkM44& setRotateUnit(SkV3 axis, SkScalar radians) { 317 return this->setRotateUnitSinCos(axis, SkScalarSin(radians), SkScalarCos(radians)); 318 } 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 friend SkM44 operator*(const SkM44& a, const SkM44& b) { 332 return SkM44(a, b); 333 } 334 preConcat(const SkM44 & m)335 SkM44& preConcat(const SkM44& m) { 336 return this->setConcat(*this, m); 337 } 338 postConcat(const SkM44 & m)339 SkM44& postConcat(const SkM44& m) { 340 return this->setConcat(m, *this); 341 } 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 */ isFinite()362 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 SkV4 operator*(const SkV4& v) const { 377 return this->map(v.x, v.y, v.z, v.w); 378 } 379 SkV3 operator*(SkV3 v) const { 380 auto v4 = this->map(v.x, v.y, v.z, 0); 381 return {v4.x, v4.y, v4.z}; 382 } 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 */ asM33()393 SkMatrix asM33() const { 394 return SkMatrix::MakeAll(fMat[0], fMat[4], fMat[12], 395 fMat[1], fMat[5], fMat[13], 396 fMat[3], fMat[7], fMat[15]); 397 } 398 SkM44(const SkMatrix & src)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 {} 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 427