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 GrQuad(const Sk4f & xs,const Sk4f & ys)64 GrQuad(const Sk4f& xs, const Sk4f& ys) { 65 xs.store(fX); 66 ys.store(fY); 67 } 68 GrQuad(const SkPoint pts[4])69 explicit GrQuad(const SkPoint pts[4]) 70 : fX{pts[0].fX, pts[1].fX, pts[2].fX, pts[3].fX} 71 , fY{pts[0].fY, pts[1].fY, pts[2].fY, pts[3].fY} {} 72 73 /** Sets the quad to the rect as transformed by the matrix. */ 74 static GrQuad MakeFromRect(const SkRect&, const SkMatrix&); 75 76 // Creates a GrQuad from the quadrilateral 'pts', transformed by the matrix. Unlike the explicit 77 // constructor, the input points array is arranged as per SkRect::toQuad (top-left, top-right, 78 // bottom-right, bottom-left). The returned instance's point order will still be CCW tri-strip 79 // order. 80 static GrQuad MakeFromSkQuad(const SkPoint pts[4], const SkMatrix&); 81 82 GrQuad& operator=(const GrQuad& that) = default; 83 point(int i)84 SkPoint point(int i) const { return {fX[i], fY[i]}; } 85 bounds()86 SkRect bounds() const { 87 auto x = this->x4f(), y = this->y4f(); 88 return {x.min(), y.min(), x.max(), y.max()}; 89 } 90 x(int i)91 float x(int i) const { return fX[i]; } y(int i)92 float y(int i) const { return fY[i]; } 93 x4f()94 Sk4f x4f() const { return Sk4f::Load(fX); } y4f()95 Sk4f y4f() const { return Sk4f::Load(fY); } 96 97 // True if anti-aliasing affects this quad. Requires quadType() == kRect_QuadType 98 bool aaHasEffectOnRect() const; 99 100 #ifdef SK_DEBUG 101 GrQuadType quadType() const; 102 #endif 103 104 private: 105 template<typename T> 106 friend class GrQuadListBase; 107 108 float fX[4]; 109 float fY[4]; 110 }; 111 112 class GrPerspQuad { 113 public: 114 GrPerspQuad() = default; 115 GrPerspQuad(const SkRect & rect)116 explicit GrPerspQuad(const SkRect& rect) 117 : fX{rect.fLeft, rect.fLeft, rect.fRight, rect.fRight} 118 , fY{rect.fTop, rect.fBottom, rect.fTop, rect.fBottom} 119 , fW{1.f, 1.f, 1.f, 1.f} {} 120 GrPerspQuad(const Sk4f & xs,const Sk4f & ys)121 GrPerspQuad(const Sk4f& xs, const Sk4f& ys) { 122 xs.store(fX); 123 ys.store(fY); 124 fW[0] = fW[1] = fW[2] = fW[3] = 1.f; 125 } 126 GrPerspQuad(const Sk4f & xs,const Sk4f & ys,const Sk4f & ws)127 GrPerspQuad(const Sk4f& xs, const Sk4f& ys, const Sk4f& ws) { 128 xs.store(fX); 129 ys.store(fY); 130 ws.store(fW); 131 } 132 133 static GrPerspQuad MakeFromRect(const SkRect&, const SkMatrix&); 134 135 // Creates a GrPerspQuad from the quadrilateral 'pts', transformed by the matrix. The input 136 // points array is arranged as per SkRect::toQuad (top-left, top-right, bottom-right, 137 // bottom-left). The returned instance's point order will still be CCW tri-strip order. 138 static GrPerspQuad MakeFromSkQuad(const SkPoint pts[4], const SkMatrix&); 139 140 GrPerspQuad& operator=(const GrPerspQuad&) = default; 141 point(int i)142 SkPoint3 point(int i) const { return {fX[i], fY[i], fW[i]}; } 143 bounds(GrQuadType type)144 SkRect bounds(GrQuadType type) const { 145 SkASSERT(this->quadType() <= type); 146 147 Sk4f x = this->x4f(); 148 Sk4f y = this->y4f(); 149 if (type == GrQuadType::kPerspective) { 150 Sk4f iw = this->iw4f(); 151 x *= iw; 152 y *= iw; 153 } 154 155 return {x.min(), y.min(), x.max(), y.max()}; 156 } 157 x(int i)158 float x(int i) const { return fX[i]; } y(int i)159 float y(int i) const { return fY[i]; } w(int i)160 float w(int i) const { return fW[i]; } iw(int i)161 float iw(int i) const { return sk_ieee_float_divide(1.f, fW[i]); } 162 x4f()163 Sk4f x4f() const { return Sk4f::Load(fX); } y4f()164 Sk4f y4f() const { return Sk4f::Load(fY); } w4f()165 Sk4f w4f() const { return Sk4f::Load(fW); } iw4f()166 Sk4f iw4f() const { return this->w4f().invert(); } 167 hasPerspective()168 bool hasPerspective() const { return (w4f() != Sk4f(1.f)).anyTrue(); } 169 170 // True if anti-aliasing affects this quad. Requires quadType() == kRect_QuadType 171 bool aaHasEffectOnRect() const; 172 173 #ifdef SK_DEBUG 174 GrQuadType quadType() const; 175 #endif 176 177 private: 178 template<typename T> 179 friend class GrQuadListBase; 180 181 // Copy 4 values from each of the arrays into the quad's components 182 GrPerspQuad(const float xs[4], const float ys[4], const float ws[4]); 183 184 float fX[4]; 185 float fY[4]; 186 float fW[4]; 187 }; 188 189 // Underlying data used by GrQuadListBase. It is defined outside of GrQuadListBase due to compiler 190 // issues related to specializing member types. 191 template<typename T> 192 struct QuadData { 193 float fX[4]; 194 float fY[4]; 195 T fMetadata; 196 }; 197 198 template<> 199 struct QuadData<void> { 200 float fX[4]; 201 float fY[4]; 202 }; 203 204 // A dynamic list of (possibly) perspective quads that tracks the most general quad type of all 205 // added quads. It avoids storing the 3rd component if the quad type never becomes perspective. 206 // Use GrQuadList subclass when only storing quads. Use GrTQuadList subclass when storing quads 207 // and per-quad templated metadata (such as color or domain). 208 template<typename T> 209 class GrQuadListBase { 210 public: 211 212 int count() const { return fXYs.count(); } 213 214 GrQuadType quadType() const { return fType; } 215 216 void reserve(int count, GrQuadType forType) { 217 fXYs.reserve(count); 218 if (forType == GrQuadType::kPerspective || fType == GrQuadType::kPerspective) { 219 fWs.reserve(4 * count); 220 } 221 } 222 223 GrPerspQuad operator[] (int i) const { 224 SkASSERT(i < this->count()); 225 SkASSERT(i >= 0); 226 227 const QuadData<T>& item = fXYs[i]; 228 if (fType == GrQuadType::kPerspective) { 229 // Read the explicit ws 230 return GrPerspQuad(item.fX, item.fY, fWs.begin() + 4 * i); 231 } else { 232 // Ws are implicitly 1s. 233 static constexpr float kNoPerspectiveWs[4] = {1.f, 1.f, 1.f, 1.f}; 234 return GrPerspQuad(item.fX, item.fY, kNoPerspectiveWs); 235 } 236 } 237 238 // Subclasses expose push_back(const GrQuad|GrPerspQuad&, GrQuadType, [const T&]), where 239 // the metadata argument is only present in GrTQuadList's push_back definition. 240 241 protected: 242 GrQuadListBase() : fType(GrQuadType::kRect) {} 243 244 void concatImpl(const GrQuadListBase<T>& that) { 245 this->upgradeType(that.fType); 246 fXYs.push_back_n(that.fXYs.count(), that.fXYs.begin()); 247 if (fType == GrQuadType::kPerspective) { 248 if (that.fType == GrQuadType::kPerspective) { 249 // Copy the other's ws into the end of this list's data 250 fWs.push_back_n(that.fWs.count(), that.fWs.begin()); 251 } else { 252 // This list stores ws but the appended list had implicit 1s, so add explicit 1s to 253 // fill out the total list 254 fWs.push_back_n(4 * that.count(), 1.f); 255 } 256 } 257 } 258 259 // Returns the added item data so that its metadata can be initialized if T is not void 260 QuadData<T>& pushBackImpl(const GrQuad& quad, GrQuadType type) { 261 SkASSERT(quad.quadType() <= type); 262 263 this->upgradeType(type); 264 QuadData<T>& item = fXYs.push_back(); 265 memcpy(item.fX, quad.fX, 4 * sizeof(float)); 266 memcpy(item.fY, quad.fY, 4 * sizeof(float)); 267 if (fType == GrQuadType::kPerspective) { 268 fWs.push_back_n(4, 1.f); 269 } 270 return item; 271 } 272 273 QuadData<T>& pushBackImpl(const GrPerspQuad& quad, GrQuadType type) { 274 SkASSERT(quad.quadType() <= type); 275 276 this->upgradeType(type); 277 QuadData<T>& item = fXYs.push_back(); 278 memcpy(item.fX, quad.fX, 4 * sizeof(float)); 279 memcpy(item.fY, quad.fY, 4 * sizeof(float)); 280 if (fType == GrQuadType::kPerspective) { 281 fWs.push_back_n(4, quad.fW); 282 } 283 return item; 284 } 285 286 const QuadData<T>& item(int i) const { 287 return fXYs[i]; 288 } 289 290 QuadData<T>& item(int i) { 291 return fXYs[i]; 292 } 293 294 private: 295 void upgradeType(GrQuadType type) { 296 // Possibly upgrade the overall type tracked by the list 297 if (type > fType) { 298 fType = type; 299 if (type == GrQuadType::kPerspective) { 300 // All existing quads were 2D, so the ws array just needs to be filled with 1s 301 fWs.push_back_n(4 * this->count(), 1.f); 302 } 303 } 304 } 305 306 // Interleaves xs, ys, and per-quad metadata so that all data for a single quad is together 307 // (barring ws, which can be dropped entirely if the quad type allows it). 308 SkSTArray<1, QuadData<T>, true> fXYs; 309 // The w channel is kept separate so that it can remain empty when only dealing with 2D quads. 310 SkTArray<float, true> fWs; 311 312 GrQuadType fType; 313 }; 314 315 // This list only stores the quad data itself. 316 class GrQuadList : public GrQuadListBase<void> { 317 public: 318 GrQuadList() : INHERITED() {} 319 320 void concat(const GrQuadList& that) { 321 this->concatImpl(that); 322 } 323 324 void push_back(const GrQuad& quad, GrQuadType type) { 325 this->pushBackImpl(quad, type); 326 } 327 328 void push_back(const GrPerspQuad& quad, GrQuadType type) { 329 this->pushBackImpl(quad, type); 330 } 331 332 private: 333 typedef GrQuadListBase<void> INHERITED; 334 }; 335 336 // This variant of the list allows simple metadata to be stored per quad as well, such as color 337 // or texture domain. 338 template<typename T> 339 class GrTQuadList : public GrQuadListBase<T> { 340 public: 341 GrTQuadList() : INHERITED() {} 342 343 void concat(const GrTQuadList<T>& that) { 344 this->concatImpl(that); 345 } 346 347 // Adding to the list requires metadata 348 void push_back(const GrQuad& quad, GrQuadType type, T&& metadata) { 349 QuadData<T>& item = this->pushBackImpl(quad, type); 350 item.fMetadata = std::move(metadata); 351 } 352 353 void push_back(const GrPerspQuad& quad, GrQuadType type, T&& metadata) { 354 QuadData<T>& item = this->pushBackImpl(quad, type); 355 item.fMetadata = std::move(metadata); 356 } 357 358 // And provide access to the metadata per quad 359 const T& metadata(int i) const { 360 return this->item(i).fMetadata; 361 } 362 363 T& metadata(int i) { 364 return this->item(i).fMetadata; 365 } 366 367 private: 368 typedef GrQuadListBase<T> INHERITED; 369 }; 370 371 #endif 372