blob: 33fd3261ad57549058309a6ea5ef57fe6e88f532 [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
joshualittae5b2c62015-08-19 08:48:41 -070011#include "SkMatrix.h"
Brian Salomona33b67c2018-05-17 10:42:14 -040012#include "SkNx.h"
13#include "SkPoint.h"
Brian Salomonbe3c1d22018-05-21 12:54:39 -040014#include "SkPoint3.h"
Michael Ludwigc96fc372019-01-08 15:46:15 -050015#include "SkTArray.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
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.
40GrQuadType GrQuadTypeForTransformedRect(const SkMatrix& matrix);
41
Michael Ludwig6bee7762018-10-19 09:50:36 -040042// Resolve disagreements between the overall requested AA type and the per-edge quad AA flags.
Michael Ludwigc182b942018-11-16 10:27:51 -050043// knownQuadType must have come from GrQuadTypeForTransformedRect with the matrix that created the
Michael Ludwig6bee7762018-10-19 09:50:36 -040044// provided quad. Both outAAType and outEdgeFlags will be updated.
45template <typename Q>
46void GrResolveAATypeForQuad(GrAAType requestedAAType, GrQuadAAFlags requestedEdgeFlags,
47 const Q& quad, GrQuadType knownQuadType,
48 GrAAType* outAAtype, GrQuadAAFlags* outEdgeFlags);
49
joshualittae5b2c62015-08-19 08:48:41 -070050/**
Brian Salomon57caa662017-10-18 12:21:05 +000051 * 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).
joshualittae5b2c62015-08-19 08:48:41 -070053 */
54class GrQuad {
55public:
Brian Salomona33b67c2018-05-17 10:42:14 -040056 GrQuad() = default;
joshualitt8cce8f12015-08-26 06:23:39 -070057
Brian Salomona33b67c2018-05-17 10:42:14 -040058 GrQuad(const GrQuad& that) = default;
59
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
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
73 SkPoint point(int i) const { return {fX[i], fY[i]}; }
74
75 SkRect bounds() const {
76 auto x = this->x4f(), y = this->y4f();
77 return {x.min(), y.min(), x.max(), y.max()};
joshualittae5b2c62015-08-19 08:48:41 -070078 }
79
Brian Salomona33b67c2018-05-17 10:42:14 -040080 float x(int i) const { return fX[i]; }
81 float y(int i) const { return fY[i]; }
joshualittae5b2c62015-08-19 08:48:41 -070082
Brian Salomona33b67c2018-05-17 10:42:14 -040083 Sk4f x4f() const { return Sk4f::Load(fX); }
84 Sk4f y4f() const { return Sk4f::Load(fY); }
joshualitt8cce8f12015-08-26 06:23:39 -070085
Michael Ludwig1f7e4382018-10-19 09:36:57 -040086 // 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
joshualittae5b2c62015-08-19 08:48:41 -070093private:
Michael Ludwigc96fc372019-01-08 15:46:15 -050094 template<typename T>
95 friend class GrQuadListBase;
96
Brian Salomona33b67c2018-05-17 10:42:14 -040097 float fX[4];
98 float fY[4];
joshualittae5b2c62015-08-19 08:48:41 -070099};
100
Brian Salomonbe3c1d22018-05-21 12:54:39 -0400101class GrPerspQuad {
102public:
103 GrPerspQuad() = default;
104
105 GrPerspQuad(const SkRect&, const SkMatrix&);
106
107 GrPerspQuad& operator=(const GrPerspQuad&) = default;
108
109 SkPoint3 point(int i) const { return {fX[i], fY[i], fW[i]}; }
110
Michael Ludwigc96fc372019-01-08 15:46:15 -0500111 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
Brian Salomonbe3c1d22018-05-21 12:54:39 -0400122 return {x.min(), y.min(), x.max(), y.max()};
123 }
124
125 float x(int i) const { return fX[i]; }
126 float y(int i) const { return fY[i]; }
127 float w(int i) const { return fW[i]; }
Michael Ludwigc96fc372019-01-08 15:46:15 -0500128 float iw(int i) const { return sk_ieee_float_divide(1.f, fW[i]); }
Brian Salomonbe3c1d22018-05-21 12:54:39 -0400129
130 Sk4f x4f() const { return Sk4f::Load(fX); }
131 Sk4f y4f() const { return Sk4f::Load(fY); }
132 Sk4f w4f() const { return Sk4f::Load(fW); }
Michael Ludwigc96fc372019-01-08 15:46:15 -0500133 Sk4f iw4f() const { return this->w4f().invert(); }
Brian Salomonbe3c1d22018-05-21 12:54:39 -0400134
Michael Ludwig1f7e4382018-10-19 09:36:57 -0400135 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
Brian Salomonbe3c1d22018-05-21 12:54:39 -0400144private:
Michael Ludwigc96fc372019-01-08 15:46:15 -0500145 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
Brian Salomonbe3c1d22018-05-21 12:54:39 -0400151 float fX[4];
152 float fY[4];
153 float fW[4];
Michael Ludwigc96fc372019-01-08 15:46:15 -0500154};
155
156// Underlying data used by GrQuadListBase. It is defined outside of GrQuadListBase due to compiler
157// issues related to specializing member types.
158template<typename T>
159struct QuadData {
160 float fX[4];
161 float fY[4];
162 T fMetadata;
163};
164
165template<>
166struct 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).
175template<typename T>
176class GrQuadListBase {
177public:
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
208protected:
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
261private:
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.
283class GrQuadList : public GrQuadListBase<void> {
284public:
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
299private:
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.
305template<typename T>
306class GrTQuadList : public GrQuadListBase<T> {
307public:
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
334private:
335 typedef GrQuadListBase<T> INHERITED;
Brian Salomonbe3c1d22018-05-21 12:54:39 -0400336};
337
joshualittae5b2c62015-08-19 08:48:41 -0700338#endif