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 "SkMatrix.h" 12 #include "SkNx.h" 13 #include "SkPoint.h" 14 #include "SkPoint3.h" 15 #include "SkTArray.h" 16 17 enum class GrAAType : unsigned; 18 enum class GrQuadAAFlags; 19 20 // Rectangles transformed by matrices (view or local) can be classified in three ways: 21 // 1. Stays a rectangle - the matrix rectStaysRect() is true, or x(0) == x(1) && x(2) == x(3) 22 // and y(0) == y(2) && y(1) == y(3). Or under mirrors, x(0) == x(2) && x(1) == x(3) and 23 // y(0) == y(1) && y(2) == y(3). 24 // 2. Is rectilinear - the matrix does not have skew or perspective, but may rotate (unlike #1) 25 // 3. Is a quadrilateral - the matrix does not have perspective, but may rotate or skew, or 26 // ws() == all ones. 27 // 4. Is a perspective quad - the matrix has perspective, subsuming all previous quad types. 28 enum class GrQuadType { 29 kRect, 30 kRectilinear, 31 kStandard, 32 kPerspective, 33 kLast = kPerspective 34 }; 35 static const int kGrQuadTypeCount = static_cast<int>(GrQuadType::kLast) + 1; 36 37 // If an SkRect is transformed by this matrix, what class of quad is required to represent it. Since 38 // quadType() is only provided on Gr[Persp]Quad in debug builds, production code should use this 39 // to efficiently determine quad types. 40 GrQuadType GrQuadTypeForTransformedRect(const SkMatrix& matrix); 41 42 // Resolve disagreements between the overall requested AA type and the per-edge quad AA flags. 43 // knownQuadType must have come from GrQuadTypeForTransformedRect with the matrix that created the 44 // provided quad. Both outAAType and outEdgeFlags will be updated. 45 template <typename Q> 46 void GrResolveAATypeForQuad(GrAAType requestedAAType, GrQuadAAFlags requestedEdgeFlags, 47 const Q& quad, GrQuadType knownQuadType, 48 GrAAType* outAAtype, GrQuadAAFlags* outEdgeFlags); 49 50 /** 51 * GrQuad is a collection of 4 points which can be used to represent an arbitrary quadrilateral. The 52 * points make a triangle strip with CCW triangles (top-left, bottom-left, top-right, bottom-right). 53 */ 54 class GrQuad { 55 public: 56 GrQuad() = default; 57 58 GrQuad(const GrQuad& that) = default; 59 GrQuad(const SkRect & rect)60 explicit GrQuad(const SkRect& rect) 61 : fX{rect.fLeft, rect.fLeft, rect.fRight, rect.fRight} 62 , fY{rect.fTop, rect.fBottom, rect.fTop, rect.fBottom} {} 63 64 /** Sets the quad to the rect as transformed by the matrix. */ 65 GrQuad(const SkRect&, const SkMatrix&); 66 GrQuad(const SkPoint pts[4])67 explicit GrQuad(const SkPoint pts[4]) 68 : fX{pts[0].fX, pts[1].fX, pts[2].fX, pts[3].fX} 69 , fY{pts[0].fY, pts[1].fY, pts[2].fY, pts[3].fY} {} 70 71 GrQuad& operator=(const GrQuad& that) = default; 72 point(int i)73 SkPoint point(int i) const { return {fX[i], fY[i]}; } 74 bounds()75 SkRect bounds() const { 76 auto x = this->x4f(), y = this->y4f(); 77 return {x.min(), y.min(), x.max(), y.max()}; 78 } 79 x(int i)80 float x(int i) const { return fX[i]; } y(int i)81 float y(int i) const { return fY[i]; } 82 x4f()83 Sk4f x4f() const { return Sk4f::Load(fX); } y4f()84 Sk4f y4f() const { return Sk4f::Load(fY); } 85 86 // True if anti-aliasing affects this quad. Requires quadType() == kRect_QuadType 87 bool aaHasEffectOnRect() const; 88 89 #ifdef SK_DEBUG 90 GrQuadType quadType() const; 91 #endif 92 93 private: 94 template<typename T> 95 friend class GrQuadListBase; 96 97 float fX[4]; 98 float fY[4]; 99 }; 100 101 class GrPerspQuad { 102 public: 103 GrPerspQuad() = default; 104 105 GrPerspQuad(const SkRect&, const SkMatrix&); 106 107 GrPerspQuad& operator=(const GrPerspQuad&) = default; 108 point(int i)109 SkPoint3 point(int i) const { return {fX[i], fY[i], fW[i]}; } 110 bounds(GrQuadType type)111 SkRect bounds(GrQuadType type) const { 112 SkASSERT(this->quadType() <= type); 113 114 Sk4f x = this->x4f(); 115 Sk4f y = this->y4f(); 116 if (type == GrQuadType::kPerspective) { 117 Sk4f iw = this->iw4f(); 118 x *= iw; 119 y *= iw; 120 } 121 122 return {x.min(), y.min(), x.max(), y.max()}; 123 } 124 x(int i)125 float x(int i) const { return fX[i]; } y(int i)126 float y(int i) const { return fY[i]; } w(int i)127 float w(int i) const { return fW[i]; } iw(int i)128 float iw(int i) const { return sk_ieee_float_divide(1.f, fW[i]); } 129 x4f()130 Sk4f x4f() const { return Sk4f::Load(fX); } y4f()131 Sk4f y4f() const { return Sk4f::Load(fY); } w4f()132 Sk4f w4f() const { return Sk4f::Load(fW); } iw4f()133 Sk4f iw4f() const { return this->w4f().invert(); } 134 hasPerspective()135 bool hasPerspective() const { return (w4f() != Sk4f(1.f)).anyTrue(); } 136 137 // True if anti-aliasing affects this quad. Requires quadType() == kRect_QuadType 138 bool aaHasEffectOnRect() const; 139 140 #ifdef SK_DEBUG 141 GrQuadType quadType() const; 142 #endif 143 144 private: 145 template<typename T> 146 friend class GrQuadListBase; 147 148 // Copy 4 values from each of the arrays into the quad's components 149 GrPerspQuad(const float xs[4], const float ys[4], const float ws[4]); 150 151 float fX[4]; 152 float fY[4]; 153 float fW[4]; 154 }; 155 156 // Underlying data used by GrQuadListBase. It is defined outside of GrQuadListBase due to compiler 157 // issues related to specializing member types. 158 template<typename T> 159 struct QuadData { 160 float fX[4]; 161 float fY[4]; 162 T fMetadata; 163 }; 164 165 template<> 166 struct QuadData<void> { 167 float fX[4]; 168 float fY[4]; 169 }; 170 171 // A dynamic list of (possibly) perspective quads that tracks the most general quad type of all 172 // added quads. It avoids storing the 3rd component if the quad type never becomes perspective. 173 // Use GrQuadList subclass when only storing quads. Use GrTQuadList subclass when storing quads 174 // and per-quad templated metadata (such as color or domain). 175 template<typename T> 176 class GrQuadListBase { 177 public: 178 179 int count() const { return fXYs.count(); } 180 181 GrQuadType quadType() const { return fType; } 182 183 void reserve(int count, GrQuadType forType) { 184 fXYs.reserve(count); 185 if (forType == GrQuadType::kPerspective || fType == GrQuadType::kPerspective) { 186 fWs.reserve(4 * count); 187 } 188 } 189 190 GrPerspQuad operator[] (int i) const { 191 SkASSERT(i < this->count()); 192 SkASSERT(i >= 0); 193 194 const QuadData<T>& item = fXYs[i]; 195 if (fType == GrQuadType::kPerspective) { 196 // Read the explicit ws 197 return GrPerspQuad(item.fX, item.fY, fWs.begin() + 4 * i); 198 } else { 199 // Ws are implicitly 1s. 200 static constexpr float kNoPerspectiveWs[4] = {1.f, 1.f, 1.f, 1.f}; 201 return GrPerspQuad(item.fX, item.fY, kNoPerspectiveWs); 202 } 203 } 204 205 // Subclasses expose push_back(const GrQuad|GrPerspQuad&, GrQuadType, [const T&]), where 206 // the metadata argument is only present in GrTQuadList's push_back definition. 207 208 protected: 209 GrQuadListBase() : fType(GrQuadType::kRect) {} 210 211 void concatImpl(const GrQuadListBase<T>& that) { 212 this->upgradeType(that.fType); 213 fXYs.push_back_n(that.fXYs.count(), that.fXYs.begin()); 214 if (fType == GrQuadType::kPerspective) { 215 if (that.fType == GrQuadType::kPerspective) { 216 // Copy the other's ws into the end of this list's data 217 fWs.push_back_n(that.fWs.count(), that.fWs.begin()); 218 } else { 219 // This list stores ws but the appended list had implicit 1s, so add explicit 1s to 220 // fill out the total list 221 fWs.push_back_n(4 * that.count(), 1.f); 222 } 223 } 224 } 225 226 // Returns the added item data so that its metadata can be initialized if T is not void 227 QuadData<T>& pushBackImpl(const GrQuad& quad, GrQuadType type) { 228 SkASSERT(quad.quadType() <= type); 229 230 this->upgradeType(type); 231 QuadData<T>& item = fXYs.push_back(); 232 memcpy(item.fX, quad.fX, 4 * sizeof(float)); 233 memcpy(item.fY, quad.fY, 4 * sizeof(float)); 234 if (fType == GrQuadType::kPerspective) { 235 fWs.push_back_n(4, 1.f); 236 } 237 return item; 238 } 239 240 QuadData<T>& pushBackImpl(const GrPerspQuad& quad, GrQuadType type) { 241 SkASSERT(quad.quadType() <= type); 242 243 this->upgradeType(type); 244 QuadData<T>& item = fXYs.push_back(); 245 memcpy(item.fX, quad.fX, 4 * sizeof(float)); 246 memcpy(item.fY, quad.fY, 4 * sizeof(float)); 247 if (fType == GrQuadType::kPerspective) { 248 fWs.push_back_n(4, quad.fW); 249 } 250 return item; 251 } 252 253 const QuadData<T>& item(int i) const { 254 return fXYs[i]; 255 } 256 257 QuadData<T>& item(int i) { 258 return fXYs[i]; 259 } 260 261 private: 262 void upgradeType(GrQuadType type) { 263 // Possibly upgrade the overall type tracked by the list 264 if (type > fType) { 265 fType = type; 266 if (type == GrQuadType::kPerspective) { 267 // All existing quads were 2D, so the ws array just needs to be filled with 1s 268 fWs.push_back_n(4 * this->count(), 1.f); 269 } 270 } 271 } 272 273 // Interleaves xs, ys, and per-quad metadata so that all data for a single quad is together 274 // (barring ws, which can be dropped entirely if the quad type allows it). 275 SkSTArray<1, QuadData<T>, true> fXYs; 276 // The w channel is kept separate so that it can remain empty when only dealing with 2D quads. 277 SkTArray<float, true> fWs; 278 279 GrQuadType fType; 280 }; 281 282 // This list only stores the quad data itself. 283 class GrQuadList : public GrQuadListBase<void> { 284 public: 285 GrQuadList() : INHERITED() {} 286 287 void concat(const GrQuadList& that) { 288 this->concatImpl(that); 289 } 290 291 void push_back(const GrQuad& quad, GrQuadType type) { 292 this->pushBackImpl(quad, type); 293 } 294 295 void push_back(const GrPerspQuad& quad, GrQuadType type) { 296 this->pushBackImpl(quad, type); 297 } 298 299 private: 300 typedef GrQuadListBase<void> INHERITED; 301 }; 302 303 // This variant of the list allows simple metadata to be stored per quad as well, such as color 304 // or texture domain. 305 template<typename T> 306 class GrTQuadList : public GrQuadListBase<T> { 307 public: 308 GrTQuadList() : INHERITED() {} 309 310 void concat(const GrTQuadList<T>& that) { 311 this->concatImpl(that); 312 } 313 314 // Adding to the list requires metadata 315 void push_back(const GrQuad& quad, GrQuadType type, T&& metadata) { 316 QuadData<T>& item = this->pushBackImpl(quad, type); 317 item.fMetadata = std::move(metadata); 318 } 319 320 void push_back(const GrPerspQuad& quad, GrQuadType type, T&& metadata) { 321 QuadData<T>& item = this->pushBackImpl(quad, type); 322 item.fMetadata = std::move(metadata); 323 } 324 325 // And provide access to the metadata per quad 326 const T& metadata(int i) const { 327 return this->item(i).fMetadata; 328 } 329 330 T& metadata(int i) { 331 return this->item(i).fMetadata; 332 } 333 334 private: 335 typedef GrQuadListBase<T> INHERITED; 336 }; 337 338 #endif 339