blob: cb2f15df6427b1ec69e475affe5f7a35cfb49fc1 [file] [log] [blame]
joshualittae5b2c62015-08-19 08:48:41 -07001/*
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
Mike Kleinc0bd9f92019-04-23 12:05:21 -050011#include "include/core/SkMatrix.h"
12#include "include/core/SkPoint.h"
13#include "include/core/SkPoint3.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050014#include "include/private/SkTArray.h"
Michael Ludwigb3461fa2019-04-30 11:50:55 -040015#include "include/private/SkVx.h"
joshualittae5b2c62015-08-19 08:48:41 -070016
Michael Ludwig6bee7762018-10-19 09:50:36 -040017enum class GrAAType : unsigned;
18enum class GrQuadAAFlags;
19
Michael Ludwig1f7e4382018-10-19 09:36:57 -040020// 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).
Michael Ludwigf995c052018-11-26 15:24:29 -050024// 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
Michael Ludwig1f7e4382018-10-19 09:36:57 -040026// ws() == all ones.
Michael Ludwigf995c052018-11-26 15:24:29 -050027// 4. Is a perspective quad - the matrix has perspective, subsuming all previous quad types.
Michael Ludwig1f7e4382018-10-19 09:36:57 -040028enum class GrQuadType {
Michael Ludwigc182b942018-11-16 10:27:51 -050029 kRect,
Michael Ludwigf995c052018-11-26 15:24:29 -050030 kRectilinear,
Michael Ludwigc182b942018-11-16 10:27:51 -050031 kStandard,
32 kPerspective,
33 kLast = kPerspective
Michael Ludwig1f7e4382018-10-19 09:36:57 -040034};
Michael Ludwigc182b942018-11-16 10:27:51 -050035static const int kGrQuadTypeCount = static_cast<int>(GrQuadType::kLast) + 1;
Michael Ludwig1f7e4382018-10-19 09:36:57 -040036
Michael Ludwig6bee7762018-10-19 09:50:36 -040037// Resolve disagreements between the overall requested AA type and the per-edge quad AA flags.
Michael Ludwigc182b942018-11-16 10:27:51 -050038// knownQuadType must have come from GrQuadTypeForTransformedRect with the matrix that created the
Michael Ludwig6bee7762018-10-19 09:50:36 -040039// provided quad. Both outAAType and outEdgeFlags will be updated.
40template <typename Q>
41void GrResolveAATypeForQuad(GrAAType requestedAAType, GrQuadAAFlags requestedEdgeFlags,
Michael Ludwig85766c42019-05-20 15:21:03 -040042 const Q& quad, GrAAType* outAAtype, GrQuadAAFlags* outEdgeFlags);
Michael Ludwig6bee7762018-10-19 09:50:36 -040043
joshualittae5b2c62015-08-19 08:48:41 -070044/**
Brian Salomon57caa662017-10-18 12:21:05 +000045 * GrQuad is a collection of 4 points which can be used to represent an arbitrary quadrilateral. The
46 * points make a triangle strip with CCW triangles (top-left, bottom-left, top-right, bottom-right).
joshualittae5b2c62015-08-19 08:48:41 -070047 */
48class GrQuad {
49public:
Brian Salomona33b67c2018-05-17 10:42:14 -040050 GrQuad() = default;
joshualitt8cce8f12015-08-26 06:23:39 -070051
Brian Salomona33b67c2018-05-17 10:42:14 -040052 GrQuad(const GrQuad& that) = default;
53
54 explicit GrQuad(const SkRect& rect)
55 : fX{rect.fLeft, rect.fLeft, rect.fRight, rect.fRight}
Michael Ludwig85766c42019-05-20 15:21:03 -040056 , fY{rect.fTop, rect.fBottom, rect.fTop, rect.fBottom}
57 , fType(GrQuadType::kRect) {}
Brian Salomona33b67c2018-05-17 10:42:14 -040058
Michael Ludwig85766c42019-05-20 15:21:03 -040059 GrQuad(const skvx::Vec<4, float>& xs, const skvx::Vec<4, float>& ys, GrQuadType type)
60 : fType(type) {
Michael Ludwige9c57d32019-02-13 13:39:39 -050061 xs.store(fX);
62 ys.store(fY);
63 }
Brian Salomona33b67c2018-05-17 10:42:14 -040064
Michael Ludwige9c57d32019-02-13 13:39:39 -050065 /** Sets the quad to the rect as transformed by the matrix. */
66 static GrQuad MakeFromRect(const SkRect&, const SkMatrix&);
67
Michael Ludwig009b92e2019-02-15 16:03:53 -050068 // Creates a GrQuad from the quadrilateral 'pts', transformed by the matrix. Unlike the explicit
69 // constructor, the input points array is arranged as per SkRect::toQuad (top-left, top-right,
70 // bottom-right, bottom-left). The returned instance's point order will still be CCW tri-strip
71 // order.
72 static GrQuad MakeFromSkQuad(const SkPoint pts[4], const SkMatrix&);
73
Brian Salomona33b67c2018-05-17 10:42:14 -040074 GrQuad& operator=(const GrQuad& that) = default;
75
76 SkPoint point(int i) const { return {fX[i], fY[i]}; }
77
78 SkRect bounds() const {
79 auto x = this->x4f(), y = this->y4f();
Michael Ludwigb3461fa2019-04-30 11:50:55 -040080 return {min(x), min(y), max(x), max(y)};
joshualittae5b2c62015-08-19 08:48:41 -070081 }
82
Brian Salomona33b67c2018-05-17 10:42:14 -040083 float x(int i) const { return fX[i]; }
84 float y(int i) const { return fY[i]; }
joshualittae5b2c62015-08-19 08:48:41 -070085
Michael Ludwigb3461fa2019-04-30 11:50:55 -040086 skvx::Vec<4, float> x4f() const { return skvx::Vec<4, float>::Load(fX); }
87 skvx::Vec<4, float> y4f() const { return skvx::Vec<4, float>::Load(fY); }
joshualitt8cce8f12015-08-26 06:23:39 -070088
Michael Ludwig85766c42019-05-20 15:21:03 -040089 GrQuadType quadType() const { return fType; }
90
Michael Ludwig9bf37f62019-04-12 14:24:38 -040091 // True if anti-aliasing affects this quad. Only valid when quadType == kRect_QuadType
Michael Ludwig1f7e4382018-10-19 09:36:57 -040092 bool aaHasEffectOnRect() const;
93
joshualittae5b2c62015-08-19 08:48:41 -070094private:
Michael Ludwigc96fc372019-01-08 15:46:15 -050095 template<typename T>
96 friend class GrQuadListBase;
97
Brian Salomona33b67c2018-05-17 10:42:14 -040098 float fX[4];
99 float fY[4];
Michael Ludwig85766c42019-05-20 15:21:03 -0400100
101 GrQuadType fType;
joshualittae5b2c62015-08-19 08:48:41 -0700102};
103
Brian Salomonbe3c1d22018-05-21 12:54:39 -0400104class GrPerspQuad {
105public:
106 GrPerspQuad() = default;
107
Michael Ludwige9c57d32019-02-13 13:39:39 -0500108 explicit GrPerspQuad(const SkRect& rect)
109 : fX{rect.fLeft, rect.fLeft, rect.fRight, rect.fRight}
110 , fY{rect.fTop, rect.fBottom, rect.fTop, rect.fBottom}
Michael Ludwig85766c42019-05-20 15:21:03 -0400111 , fW{1.f, 1.f, 1.f, 1.f}
112 , fType(GrQuadType::kRect) {}
Michael Ludwige9c57d32019-02-13 13:39:39 -0500113
Michael Ludwig85766c42019-05-20 15:21:03 -0400114 GrPerspQuad(const skvx::Vec<4, float>& xs, const skvx::Vec<4, float>& ys,
115 GrQuadType type)
116 : fType(type) {
117 SkASSERT(type != GrQuadType::kPerspective);
Michael Ludwige9c57d32019-02-13 13:39:39 -0500118 xs.store(fX);
119 ys.store(fY);
120 fW[0] = fW[1] = fW[2] = fW[3] = 1.f;
121 }
Michael Ludwig009b92e2019-02-15 16:03:53 -0500122
Michael Ludwigb3461fa2019-04-30 11:50:55 -0400123 GrPerspQuad(const skvx::Vec<4, float>& xs, const skvx::Vec<4, float>& ys,
Michael Ludwig85766c42019-05-20 15:21:03 -0400124 const skvx::Vec<4, float>& ws, GrQuadType type)
125 : fType(type) {
Michael Ludwige9c57d32019-02-13 13:39:39 -0500126 xs.store(fX);
127 ys.store(fY);
128 ws.store(fW);
129 }
130
131 static GrPerspQuad MakeFromRect(const SkRect&, const SkMatrix&);
Brian Salomonbe3c1d22018-05-21 12:54:39 -0400132
Michael Ludwig009b92e2019-02-15 16:03:53 -0500133 // Creates a GrPerspQuad from the quadrilateral 'pts', transformed by the matrix. The input
134 // points array is arranged as per SkRect::toQuad (top-left, top-right, bottom-right,
135 // bottom-left). The returned instance's point order will still be CCW tri-strip order.
136 static GrPerspQuad MakeFromSkQuad(const SkPoint pts[4], const SkMatrix&);
137
Brian Salomonbe3c1d22018-05-21 12:54:39 -0400138 GrPerspQuad& operator=(const GrPerspQuad&) = default;
139
140 SkPoint3 point(int i) const { return {fX[i], fY[i], fW[i]}; }
141
Michael Ludwig85766c42019-05-20 15:21:03 -0400142 SkRect bounds() const {
Michael Ludwigb3461fa2019-04-30 11:50:55 -0400143 auto x = this->x4f();
144 auto y = this->y4f();
Michael Ludwig85766c42019-05-20 15:21:03 -0400145 if (fType == GrQuadType::kPerspective) {
Michael Ludwigb3461fa2019-04-30 11:50:55 -0400146 auto iw = this->iw4f();
Michael Ludwigc96fc372019-01-08 15:46:15 -0500147 x *= iw;
148 y *= iw;
149 }
150
Michael Ludwigb3461fa2019-04-30 11:50:55 -0400151 return {min(x), min(y), max(x), max(y)};
Brian Salomonbe3c1d22018-05-21 12:54:39 -0400152 }
153
154 float x(int i) const { return fX[i]; }
155 float y(int i) const { return fY[i]; }
156 float w(int i) const { return fW[i]; }
Michael Ludwigc96fc372019-01-08 15:46:15 -0500157 float iw(int i) const { return sk_ieee_float_divide(1.f, fW[i]); }
Brian Salomonbe3c1d22018-05-21 12:54:39 -0400158
Michael Ludwigb3461fa2019-04-30 11:50:55 -0400159 skvx::Vec<4, float> x4f() const { return skvx::Vec<4, float>::Load(fX); }
160 skvx::Vec<4, float> y4f() const { return skvx::Vec<4, float>::Load(fY); }
161 skvx::Vec<4, float> w4f() const { return skvx::Vec<4, float>::Load(fW); }
162 skvx::Vec<4, float> iw4f() const { return 1.f / this->w4f(); }
Brian Salomonbe3c1d22018-05-21 12:54:39 -0400163
Michael Ludwig85766c42019-05-20 15:21:03 -0400164 GrQuadType quadType() const { return fType; }
165
166 bool hasPerspective() const { return fType == GrQuadType::kPerspective; }
Michael Ludwig1f7e4382018-10-19 09:36:57 -0400167
Michael Ludwig9bf37f62019-04-12 14:24:38 -0400168 // True if anti-aliasing affects this quad. Only valid when quadType == kRect_QuadType
Michael Ludwig1f7e4382018-10-19 09:36:57 -0400169 bool aaHasEffectOnRect() const;
170
Brian Salomonbe3c1d22018-05-21 12:54:39 -0400171private:
Michael Ludwigc96fc372019-01-08 15:46:15 -0500172 template<typename T>
173 friend class GrQuadListBase;
174
175 // Copy 4 values from each of the arrays into the quad's components
Michael Ludwig85766c42019-05-20 15:21:03 -0400176 GrPerspQuad(const float xs[4], const float ys[4], const float ws[4], GrQuadType type);
Michael Ludwigc96fc372019-01-08 15:46:15 -0500177
Brian Salomonbe3c1d22018-05-21 12:54:39 -0400178 float fX[4];
179 float fY[4];
180 float fW[4];
Michael Ludwig85766c42019-05-20 15:21:03 -0400181
182 GrQuadType fType;
Michael Ludwigc96fc372019-01-08 15:46:15 -0500183};
184
185// Underlying data used by GrQuadListBase. It is defined outside of GrQuadListBase due to compiler
186// issues related to specializing member types.
187template<typename T>
188struct QuadData {
189 float fX[4];
190 float fY[4];
191 T fMetadata;
192};
193
194template<>
195struct QuadData<void> {
196 float fX[4];
197 float fY[4];
198};
199
200// A dynamic list of (possibly) perspective quads that tracks the most general quad type of all
201// added quads. It avoids storing the 3rd component if the quad type never becomes perspective.
202// Use GrQuadList subclass when only storing quads. Use GrTQuadList subclass when storing quads
203// and per-quad templated metadata (such as color or domain).
204template<typename T>
205class GrQuadListBase {
206public:
207
208 int count() const { return fXYs.count(); }
209
210 GrQuadType quadType() const { return fType; }
211
Michael Ludwig85766c42019-05-20 15:21:03 -0400212 void reserve(int count, bool needsPerspective) {
Michael Ludwigc96fc372019-01-08 15:46:15 -0500213 fXYs.reserve(count);
Michael Ludwig85766c42019-05-20 15:21:03 -0400214 if (needsPerspective || fType == GrQuadType::kPerspective) {
Michael Ludwigc96fc372019-01-08 15:46:15 -0500215 fWs.reserve(4 * count);
216 }
217 }
218
219 GrPerspQuad operator[] (int i) const {
220 SkASSERT(i < this->count());
221 SkASSERT(i >= 0);
222
223 const QuadData<T>& item = fXYs[i];
224 if (fType == GrQuadType::kPerspective) {
225 // Read the explicit ws
Michael Ludwig85766c42019-05-20 15:21:03 -0400226 return GrPerspQuad(item.fX, item.fY, fWs.begin() + 4 * i, fType);
Michael Ludwigc96fc372019-01-08 15:46:15 -0500227 } else {
228 // Ws are implicitly 1s.
229 static constexpr float kNoPerspectiveWs[4] = {1.f, 1.f, 1.f, 1.f};
Michael Ludwig85766c42019-05-20 15:21:03 -0400230 return GrPerspQuad(item.fX, item.fY, kNoPerspectiveWs, fType);
Michael Ludwigc96fc372019-01-08 15:46:15 -0500231 }
232 }
233
234 // Subclasses expose push_back(const GrQuad|GrPerspQuad&, GrQuadType, [const T&]), where
235 // the metadata argument is only present in GrTQuadList's push_back definition.
236
237protected:
238 GrQuadListBase() : fType(GrQuadType::kRect) {}
239
240 void concatImpl(const GrQuadListBase<T>& that) {
241 this->upgradeType(that.fType);
242 fXYs.push_back_n(that.fXYs.count(), that.fXYs.begin());
243 if (fType == GrQuadType::kPerspective) {
244 if (that.fType == GrQuadType::kPerspective) {
245 // Copy the other's ws into the end of this list's data
246 fWs.push_back_n(that.fWs.count(), that.fWs.begin());
247 } else {
248 // This list stores ws but the appended list had implicit 1s, so add explicit 1s to
249 // fill out the total list
250 fWs.push_back_n(4 * that.count(), 1.f);
251 }
252 }
253 }
254
255 // Returns the added item data so that its metadata can be initialized if T is not void
Michael Ludwig85766c42019-05-20 15:21:03 -0400256 QuadData<T>& pushBackImpl(const GrQuad& quad) {
257 this->upgradeType(quad.quadType());
Michael Ludwigc96fc372019-01-08 15:46:15 -0500258 QuadData<T>& item = fXYs.push_back();
259 memcpy(item.fX, quad.fX, 4 * sizeof(float));
260 memcpy(item.fY, quad.fY, 4 * sizeof(float));
261 if (fType == GrQuadType::kPerspective) {
262 fWs.push_back_n(4, 1.f);
263 }
264 return item;
265 }
266
Michael Ludwig85766c42019-05-20 15:21:03 -0400267 QuadData<T>& pushBackImpl(const GrPerspQuad& quad) {
268 this->upgradeType(quad.quadType());
Michael Ludwigc96fc372019-01-08 15:46:15 -0500269 QuadData<T>& item = fXYs.push_back();
270 memcpy(item.fX, quad.fX, 4 * sizeof(float));
271 memcpy(item.fY, quad.fY, 4 * sizeof(float));
272 if (fType == GrQuadType::kPerspective) {
273 fWs.push_back_n(4, quad.fW);
274 }
275 return item;
276 }
277
278 const QuadData<T>& item(int i) const {
279 return fXYs[i];
280 }
281
282 QuadData<T>& item(int i) {
283 return fXYs[i];
284 }
285
286private:
287 void upgradeType(GrQuadType type) {
288 // Possibly upgrade the overall type tracked by the list
289 if (type > fType) {
290 fType = type;
291 if (type == GrQuadType::kPerspective) {
292 // All existing quads were 2D, so the ws array just needs to be filled with 1s
293 fWs.push_back_n(4 * this->count(), 1.f);
294 }
295 }
296 }
297
298 // Interleaves xs, ys, and per-quad metadata so that all data for a single quad is together
299 // (barring ws, which can be dropped entirely if the quad type allows it).
300 SkSTArray<1, QuadData<T>, true> fXYs;
301 // The w channel is kept separate so that it can remain empty when only dealing with 2D quads.
302 SkTArray<float, true> fWs;
303
304 GrQuadType fType;
305};
306
307// This list only stores the quad data itself.
308class GrQuadList : public GrQuadListBase<void> {
309public:
310 GrQuadList() : INHERITED() {}
311
312 void concat(const GrQuadList& that) {
313 this->concatImpl(that);
314 }
315
Michael Ludwig85766c42019-05-20 15:21:03 -0400316 void push_back(const GrQuad& quad) {
317 this->pushBackImpl(quad);
Michael Ludwigc96fc372019-01-08 15:46:15 -0500318 }
319
Michael Ludwig85766c42019-05-20 15:21:03 -0400320 void push_back(const GrPerspQuad& quad) {
321 this->pushBackImpl(quad);
Michael Ludwigc96fc372019-01-08 15:46:15 -0500322 }
323
324private:
325 typedef GrQuadListBase<void> INHERITED;
326};
327
328// This variant of the list allows simple metadata to be stored per quad as well, such as color
329// or texture domain.
330template<typename T>
331class GrTQuadList : public GrQuadListBase<T> {
332public:
333 GrTQuadList() : INHERITED() {}
334
335 void concat(const GrTQuadList<T>& that) {
336 this->concatImpl(that);
337 }
338
339 // Adding to the list requires metadata
Michael Ludwig85766c42019-05-20 15:21:03 -0400340 void push_back(const GrQuad& quad, T&& metadata) {
341 QuadData<T>& item = this->pushBackImpl(quad);
Michael Ludwigc96fc372019-01-08 15:46:15 -0500342 item.fMetadata = std::move(metadata);
343 }
344
Michael Ludwig85766c42019-05-20 15:21:03 -0400345 void push_back(const GrPerspQuad& quad, T&& metadata) {
346 QuadData<T>& item = this->pushBackImpl(quad);
Michael Ludwigc96fc372019-01-08 15:46:15 -0500347 item.fMetadata = std::move(metadata);
348 }
349
350 // And provide access to the metadata per quad
351 const T& metadata(int i) const {
352 return this->item(i).fMetadata;
353 }
354
355 T& metadata(int i) {
356 return this->item(i).fMetadata;
357 }
358
359private:
360 typedef GrQuadListBase<T> INHERITED;
Brian Salomonbe3c1d22018-05-21 12:54:39 -0400361};
362
joshualittae5b2c62015-08-19 08:48:41 -0700363#endif