1 /* 2 * Copyright 2015 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 GrQuad_DEFINED 9 #define GrQuad_DEFINED 10 11 #include "include/core/SkMatrix.h" 12 #include "include/core/SkPoint.h" 13 #include "include/core/SkPoint3.h" 14 #include "include/private/SkVx.h" 15 16 /** 17 * GrQuad is a collection of 4 points which can be used to represent an arbitrary quadrilateral. The 18 * points make a triangle strip with CCW triangles (top-left, bottom-left, top-right, bottom-right). 19 */ 20 class GrQuad { 21 public: 22 // Quadrilaterals can be classified in several useful ways that assist AA tessellation and other 23 // analysis when drawing, in particular, knowing if it was originally a rectangle transformed by 24 // certain types of matrices: 25 enum class Type { 26 // The 4 points remain an axis-aligned rectangle; their logical indices may not respect 27 // TL, BL, TR, BR ordering if the transform was a 90 degre rotation or mirror. 28 kAxisAligned, 29 // The 4 points represent a rectangle subjected to a rotation, its corners are right angles. 30 kRectilinear, 31 // Arbitrary 2D quadrilateral; may have been a rectangle transformed with skew or some 32 // clipped polygon. Its w coordinates will all be 1. 33 kGeneral, 34 // Even more general-purpose than kGeneral, this allows the w coordinates to be non-unity. 35 kPerspective, 36 kLast = kPerspective 37 }; 38 static const int kTypeCount = static_cast<int>(Type::kLast) + 1; 39 40 GrQuad() = default; 41 GrQuad(const SkRect & rect)42 explicit GrQuad(const SkRect& rect) 43 : fX{rect.fLeft, rect.fLeft, rect.fRight, rect.fRight} 44 , fY{rect.fTop, rect.fBottom, rect.fTop, rect.fBottom} 45 , fW{1.f, 1.f, 1.f, 1.f} 46 , fType(Type::kAxisAligned) {} 47 GrQuad(const skvx::Vec<4,float> & xs,const skvx::Vec<4,float> & ys,Type type)48 GrQuad(const skvx::Vec<4, float>& xs, const skvx::Vec<4, float>& ys, Type type) 49 : fType(type) { 50 SkASSERT(type != Type::kPerspective); 51 xs.store(fX); 52 ys.store(fY); 53 fW[0] = fW[1] = fW[2] = fW[3] = 1.f; 54 } 55 GrQuad(const skvx::Vec<4,float> & xs,const skvx::Vec<4,float> & ys,const skvx::Vec<4,float> & ws,Type type)56 GrQuad(const skvx::Vec<4, float>& xs, const skvx::Vec<4, float>& ys, 57 const skvx::Vec<4, float>& ws, Type type) 58 : fType(type) { 59 xs.store(fX); 60 ys.store(fY); 61 ws.store(fW); 62 } 63 64 // Copy 4 values from each of the arrays into the quad's components GrQuad(const float xs[4],const float ys[4],const float ws[4],Type type)65 GrQuad(const float xs[4], const float ys[4], const float ws[4], Type type) 66 : fType(type) { 67 memcpy(fX, xs, 4 * sizeof(float)); 68 memcpy(fY, ys, 4 * sizeof(float)); 69 memcpy(fW, ws, 4 * sizeof(float)); 70 } 71 72 static GrQuad MakeFromRect(const SkRect&, const SkMatrix&); 73 74 // Creates a GrQuad from the quadrilateral 'pts', transformed by the matrix. The input 75 // points array is arranged as per SkRect::toQuad (top-left, top-right, bottom-right, 76 // bottom-left). The returned instance's point order will still be CCW tri-strip order. 77 static GrQuad MakeFromSkQuad(const SkPoint pts[4], const SkMatrix&); 78 79 GrQuad& operator=(const GrQuad&) = default; 80 point3(int i)81 SkPoint3 point3(int i) const { return {fX[i], fY[i], fW[i]}; } 82 point(int i)83 SkPoint point(int i) const { 84 if (fType == Type::kPerspective) { 85 return {fX[i] / fW[i], fY[i] / fW[i]}; 86 } else { 87 return {fX[i], fY[i]}; 88 } 89 } 90 bounds()91 SkRect bounds() const { 92 auto x = this->x4f(); 93 auto y = this->y4f(); 94 if (fType == Type::kPerspective) { 95 auto iw = this->iw4f(); 96 x *= iw; 97 y *= iw; 98 } 99 100 return {min(x), min(y), max(x), max(y)}; 101 } 102 isFinite()103 bool isFinite() const { 104 // If any coordinate is infinity or NaN, then multiplying it with 0 will make accum NaN 105 float accum = 0; 106 for (int i = 0; i < 4; ++i) { 107 accum *= fX[i]; 108 accum *= fY[i]; 109 accum *= fW[i]; 110 } 111 SkASSERT(0 == accum || SkScalarIsNaN(accum)); 112 return !SkScalarIsNaN(accum); 113 } 114 x(int i)115 float x(int i) const { return fX[i]; } y(int i)116 float y(int i) const { return fY[i]; } w(int i)117 float w(int i) const { return fW[i]; } iw(int i)118 float iw(int i) const { return sk_ieee_float_divide(1.f, fW[i]); } 119 x4f()120 skvx::Vec<4, float> x4f() const { return skvx::Vec<4, float>::Load(fX); } y4f()121 skvx::Vec<4, float> y4f() const { return skvx::Vec<4, float>::Load(fY); } w4f()122 skvx::Vec<4, float> w4f() const { return skvx::Vec<4, float>::Load(fW); } iw4f()123 skvx::Vec<4, float> iw4f() const { return 1.f / this->w4f(); } 124 quadType()125 Type quadType() const { return fType; } 126 hasPerspective()127 bool hasPerspective() const { return fType == Type::kPerspective; } 128 129 // True if anti-aliasing affects this quad. Only valid when quadType == kAxisAligned 130 bool aaHasEffectOnRect() const; 131 132 // True if this quad is axis-aligned and still has its top-left corner at v0. Equivalently, 133 // quad == GrQuad(quad->bounds()). Axis-aligned quads with flips and rotations may exactly 134 // fill their bounds, but their vertex order will not match TL BL TR BR anymore. 135 bool asRect(SkRect* rect) const; 136 137 // The non-const pointers are provided to support modifying a GrQuad in-place, but care must be 138 // taken to keep its quad type aligned with the geometric nature of the new coordinates. This is 139 // no different than using the constructors that accept a quad type. xs()140 const float* xs() const { return fX; } xs()141 float* xs() { return fX; } ys()142 const float* ys() const { return fY; } ys()143 float* ys() { return fY; } ws()144 const float* ws() const { return fW; } ws()145 float* ws() { return fW; } 146 setQuadType(Type newType)147 void setQuadType(Type newType) { fType = newType; } 148 private: 149 template<typename T> 150 friend class GrQuadListBase; // for access to fX, fY, fW 151 152 float fX[4]; 153 float fY[4]; 154 float fW[4]; 155 156 Type fType; 157 }; 158 159 #endif 160