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