blob: 73b7310dc9122b7c37f23fc95f76b1df767436bf [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
Robert Phillips0dee19b2019-05-23 17:22:19 +000037// If an SkRect is transformed by this matrix, what class of quad is required to represent it.
38GrQuadType GrQuadTypeForTransformedRect(const SkMatrix& matrix);
39// Perform minimal analysis of 'pts' (which are suitable for MakeFromSkQuad), and determine a
40// quad type that will be as minimally general as possible.
41GrQuadType GrQuadTypeForPoints(const SkPoint pts[4], const SkMatrix& matrix);
42
Michael Ludwig6bee7762018-10-19 09:50:36 -040043// Resolve disagreements between the overall requested AA type and the per-edge quad AA flags.
Michael Ludwigc182b942018-11-16 10:27:51 -050044// knownQuadType must have come from GrQuadTypeForTransformedRect with the matrix that created the
Michael Ludwig6bee7762018-10-19 09:50:36 -040045// provided quad. Both outAAType and outEdgeFlags will be updated.
46template <typename Q>
47void GrResolveAATypeForQuad(GrAAType requestedAAType, GrQuadAAFlags requestedEdgeFlags,
Robert Phillips0dee19b2019-05-23 17:22:19 +000048 const Q& quad, GrQuadType knownQuadType,
49 GrAAType* outAAtype, GrQuadAAFlags* outEdgeFlags);
Michael Ludwig6bee7762018-10-19 09:50:36 -040050
joshualittae5b2c62015-08-19 08:48:41 -070051/**
Brian Salomon57caa662017-10-18 12:21:05 +000052 * GrQuad is a collection of 4 points which can be used to represent an arbitrary quadrilateral. The
53 * points make a triangle strip with CCW triangles (top-left, bottom-left, top-right, bottom-right).
joshualittae5b2c62015-08-19 08:48:41 -070054 */
55class GrQuad {
56public:
Brian Salomona33b67c2018-05-17 10:42:14 -040057 GrQuad() = default;
joshualitt8cce8f12015-08-26 06:23:39 -070058
Brian Salomona33b67c2018-05-17 10:42:14 -040059 GrQuad(const GrQuad& that) = default;
60
61 explicit GrQuad(const SkRect& rect)
62 : fX{rect.fLeft, rect.fLeft, rect.fRight, rect.fRight}
Robert Phillips0dee19b2019-05-23 17:22:19 +000063 , fY{rect.fTop, rect.fBottom, rect.fTop, rect.fBottom} {}
Brian Salomona33b67c2018-05-17 10:42:14 -040064
Robert Phillips0dee19b2019-05-23 17:22:19 +000065 GrQuad(const skvx::Vec<4, float>& xs, const skvx::Vec<4, float>& ys) {
Michael Ludwige9c57d32019-02-13 13:39:39 -050066 xs.store(fX);
67 ys.store(fY);
68 }
Brian Salomona33b67c2018-05-17 10:42:14 -040069
Robert Phillips0dee19b2019-05-23 17:22:19 +000070 explicit GrQuad(const SkPoint pts[4])
71 : fX{pts[0].fX, pts[1].fX, pts[2].fX, pts[3].fX}
72 , fY{pts[0].fY, pts[1].fY, pts[2].fY, pts[3].fY} {}
73
Michael Ludwige9c57d32019-02-13 13:39:39 -050074 /** Sets the quad to the rect as transformed by the matrix. */
75 static GrQuad MakeFromRect(const SkRect&, const SkMatrix&);
76
Michael Ludwig009b92e2019-02-15 16:03:53 -050077 // Creates a GrQuad from the quadrilateral 'pts', transformed by the matrix. Unlike the explicit
78 // constructor, the input points array is arranged as per SkRect::toQuad (top-left, top-right,
79 // bottom-right, bottom-left). The returned instance's point order will still be CCW tri-strip
80 // order.
81 static GrQuad MakeFromSkQuad(const SkPoint pts[4], const SkMatrix&);
82
Brian Salomona33b67c2018-05-17 10:42:14 -040083 GrQuad& operator=(const GrQuad& that) = default;
84
85 SkPoint point(int i) const { return {fX[i], fY[i]}; }
86
87 SkRect bounds() const {
88 auto x = this->x4f(), y = this->y4f();
Michael Ludwigb3461fa2019-04-30 11:50:55 -040089 return {min(x), min(y), max(x), max(y)};
joshualittae5b2c62015-08-19 08:48:41 -070090 }
91
Brian Salomona33b67c2018-05-17 10:42:14 -040092 float x(int i) const { return fX[i]; }
93 float y(int i) const { return fY[i]; }
joshualittae5b2c62015-08-19 08:48:41 -070094
Michael Ludwigb3461fa2019-04-30 11:50:55 -040095 skvx::Vec<4, float> x4f() const { return skvx::Vec<4, float>::Load(fX); }
96 skvx::Vec<4, float> y4f() const { return skvx::Vec<4, float>::Load(fY); }
joshualitt8cce8f12015-08-26 06:23:39 -070097
Michael Ludwig9bf37f62019-04-12 14:24:38 -040098 // True if anti-aliasing affects this quad. Only valid when quadType == kRect_QuadType
Michael Ludwig1f7e4382018-10-19 09:36:57 -040099 bool aaHasEffectOnRect() const;
100
joshualittae5b2c62015-08-19 08:48:41 -0700101private:
Michael Ludwigc96fc372019-01-08 15:46:15 -0500102 template<typename T>
103 friend class GrQuadListBase;
104
Brian Salomona33b67c2018-05-17 10:42:14 -0400105 float fX[4];
106 float fY[4];
joshualittae5b2c62015-08-19 08:48:41 -0700107};
108
Brian Salomonbe3c1d22018-05-21 12:54:39 -0400109class GrPerspQuad {
110public:
111 GrPerspQuad() = default;
112
Michael Ludwige9c57d32019-02-13 13:39:39 -0500113 explicit GrPerspQuad(const SkRect& rect)
114 : fX{rect.fLeft, rect.fLeft, rect.fRight, rect.fRight}
115 , fY{rect.fTop, rect.fBottom, rect.fTop, rect.fBottom}
Robert Phillips0dee19b2019-05-23 17:22:19 +0000116 , fW{1.f, 1.f, 1.f, 1.f} {}
Michael Ludwige9c57d32019-02-13 13:39:39 -0500117
Robert Phillips0dee19b2019-05-23 17:22:19 +0000118 GrPerspQuad(const skvx::Vec<4, float>& xs, const skvx::Vec<4, float>& ys) {
Michael Ludwige9c57d32019-02-13 13:39:39 -0500119 xs.store(fX);
120 ys.store(fY);
121 fW[0] = fW[1] = fW[2] = fW[3] = 1.f;
122 }
Michael Ludwig009b92e2019-02-15 16:03:53 -0500123
Michael Ludwigb3461fa2019-04-30 11:50:55 -0400124 GrPerspQuad(const skvx::Vec<4, float>& xs, const skvx::Vec<4, float>& ys,
Robert Phillips0dee19b2019-05-23 17:22:19 +0000125 const skvx::Vec<4, float>& ws) {
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
Robert Phillips0dee19b2019-05-23 17:22:19 +0000142 SkRect bounds(GrQuadType type) const {
Michael Ludwigb3461fa2019-04-30 11:50:55 -0400143 auto x = this->x4f();
144 auto y = this->y4f();
Robert Phillips0dee19b2019-05-23 17:22:19 +0000145 if (type == 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
Robert Phillips0dee19b2019-05-23 17:22:19 +0000164 bool hasPerspective() const { return any(w4f() != 1.f); }
Michael Ludwig1f7e4382018-10-19 09:36:57 -0400165
Michael Ludwig9bf37f62019-04-12 14:24:38 -0400166 // True if anti-aliasing affects this quad. Only valid when quadType == kRect_QuadType
Michael Ludwig1f7e4382018-10-19 09:36:57 -0400167 bool aaHasEffectOnRect() const;
168
Brian Salomonbe3c1d22018-05-21 12:54:39 -0400169private:
Michael Ludwigc96fc372019-01-08 15:46:15 -0500170 template<typename T>
171 friend class GrQuadListBase;
172
173 // Copy 4 values from each of the arrays into the quad's components
Robert Phillips0dee19b2019-05-23 17:22:19 +0000174 GrPerspQuad(const float xs[4], const float ys[4], const float ws[4]);
Michael Ludwigc96fc372019-01-08 15:46:15 -0500175
Brian Salomonbe3c1d22018-05-21 12:54:39 -0400176 float fX[4];
177 float fY[4];
178 float fW[4];
Michael Ludwigc96fc372019-01-08 15:46:15 -0500179};
180
181// Underlying data used by GrQuadListBase. It is defined outside of GrQuadListBase due to compiler
182// issues related to specializing member types.
183template<typename T>
184struct QuadData {
185 float fX[4];
186 float fY[4];
187 T fMetadata;
188};
189
190template<>
191struct QuadData<void> {
192 float fX[4];
193 float fY[4];
194};
195
196// A dynamic list of (possibly) perspective quads that tracks the most general quad type of all
197// added quads. It avoids storing the 3rd component if the quad type never becomes perspective.
198// Use GrQuadList subclass when only storing quads. Use GrTQuadList subclass when storing quads
199// and per-quad templated metadata (such as color or domain).
200template<typename T>
201class GrQuadListBase {
202public:
203
204 int count() const { return fXYs.count(); }
205
206 GrQuadType quadType() const { return fType; }
207
Robert Phillips0dee19b2019-05-23 17:22:19 +0000208 void reserve(int count, GrQuadType forType) {
Michael Ludwigc96fc372019-01-08 15:46:15 -0500209 fXYs.reserve(count);
Robert Phillips0dee19b2019-05-23 17:22:19 +0000210 if (forType == GrQuadType::kPerspective || fType == GrQuadType::kPerspective) {
Michael Ludwigc96fc372019-01-08 15:46:15 -0500211 fWs.reserve(4 * count);
212 }
213 }
214
215 GrPerspQuad operator[] (int i) const {
216 SkASSERT(i < this->count());
217 SkASSERT(i >= 0);
218
219 const QuadData<T>& item = fXYs[i];
220 if (fType == GrQuadType::kPerspective) {
221 // Read the explicit ws
Robert Phillips0dee19b2019-05-23 17:22:19 +0000222 return GrPerspQuad(item.fX, item.fY, fWs.begin() + 4 * i);
Michael Ludwigc96fc372019-01-08 15:46:15 -0500223 } else {
224 // Ws are implicitly 1s.
225 static constexpr float kNoPerspectiveWs[4] = {1.f, 1.f, 1.f, 1.f};
Robert Phillips0dee19b2019-05-23 17:22:19 +0000226 return GrPerspQuad(item.fX, item.fY, kNoPerspectiveWs);
Michael Ludwigc96fc372019-01-08 15:46:15 -0500227 }
228 }
229
230 // Subclasses expose push_back(const GrQuad|GrPerspQuad&, GrQuadType, [const T&]), where
231 // the metadata argument is only present in GrTQuadList's push_back definition.
232
233protected:
234 GrQuadListBase() : fType(GrQuadType::kRect) {}
235
236 void concatImpl(const GrQuadListBase<T>& that) {
237 this->upgradeType(that.fType);
238 fXYs.push_back_n(that.fXYs.count(), that.fXYs.begin());
239 if (fType == GrQuadType::kPerspective) {
240 if (that.fType == GrQuadType::kPerspective) {
241 // Copy the other's ws into the end of this list's data
242 fWs.push_back_n(that.fWs.count(), that.fWs.begin());
243 } else {
244 // This list stores ws but the appended list had implicit 1s, so add explicit 1s to
245 // fill out the total list
246 fWs.push_back_n(4 * that.count(), 1.f);
247 }
248 }
249 }
250
251 // Returns the added item data so that its metadata can be initialized if T is not void
Robert Phillips0dee19b2019-05-23 17:22:19 +0000252 QuadData<T>& pushBackImpl(const GrQuad& quad, GrQuadType type) {
253 this->upgradeType(type);
Michael Ludwigc96fc372019-01-08 15:46:15 -0500254 QuadData<T>& item = fXYs.push_back();
255 memcpy(item.fX, quad.fX, 4 * sizeof(float));
256 memcpy(item.fY, quad.fY, 4 * sizeof(float));
257 if (fType == GrQuadType::kPerspective) {
258 fWs.push_back_n(4, 1.f);
259 }
260 return item;
261 }
262
Robert Phillips0dee19b2019-05-23 17:22:19 +0000263 QuadData<T>& pushBackImpl(const GrPerspQuad& quad, GrQuadType type) {
264 this->upgradeType(type);
Michael Ludwigc96fc372019-01-08 15:46:15 -0500265 QuadData<T>& item = fXYs.push_back();
266 memcpy(item.fX, quad.fX, 4 * sizeof(float));
267 memcpy(item.fY, quad.fY, 4 * sizeof(float));
268 if (fType == GrQuadType::kPerspective) {
269 fWs.push_back_n(4, quad.fW);
270 }
271 return item;
272 }
273
274 const QuadData<T>& item(int i) const {
275 return fXYs[i];
276 }
277
278 QuadData<T>& item(int i) {
279 return fXYs[i];
280 }
281
282private:
283 void upgradeType(GrQuadType type) {
284 // Possibly upgrade the overall type tracked by the list
285 if (type > fType) {
286 fType = type;
287 if (type == GrQuadType::kPerspective) {
288 // All existing quads were 2D, so the ws array just needs to be filled with 1s
289 fWs.push_back_n(4 * this->count(), 1.f);
290 }
291 }
292 }
293
294 // Interleaves xs, ys, and per-quad metadata so that all data for a single quad is together
295 // (barring ws, which can be dropped entirely if the quad type allows it).
296 SkSTArray<1, QuadData<T>, true> fXYs;
297 // The w channel is kept separate so that it can remain empty when only dealing with 2D quads.
298 SkTArray<float, true> fWs;
299
300 GrQuadType fType;
301};
302
303// This list only stores the quad data itself.
304class GrQuadList : public GrQuadListBase<void> {
305public:
306 GrQuadList() : INHERITED() {}
307
308 void concat(const GrQuadList& that) {
309 this->concatImpl(that);
310 }
311
Robert Phillips0dee19b2019-05-23 17:22:19 +0000312 void push_back(const GrQuad& quad, GrQuadType type) {
313 this->pushBackImpl(quad, type);
Michael Ludwigc96fc372019-01-08 15:46:15 -0500314 }
315
Robert Phillips0dee19b2019-05-23 17:22:19 +0000316 void push_back(const GrPerspQuad& quad, GrQuadType type) {
317 this->pushBackImpl(quad, type);
Michael Ludwigc96fc372019-01-08 15:46:15 -0500318 }
319
320private:
321 typedef GrQuadListBase<void> INHERITED;
322};
323
324// This variant of the list allows simple metadata to be stored per quad as well, such as color
325// or texture domain.
326template<typename T>
327class GrTQuadList : public GrQuadListBase<T> {
328public:
329 GrTQuadList() : INHERITED() {}
330
331 void concat(const GrTQuadList<T>& that) {
332 this->concatImpl(that);
333 }
334
335 // Adding to the list requires metadata
Robert Phillips0dee19b2019-05-23 17:22:19 +0000336 void push_back(const GrQuad& quad, GrQuadType type, T&& metadata) {
337 QuadData<T>& item = this->pushBackImpl(quad, type);
Michael Ludwigc96fc372019-01-08 15:46:15 -0500338 item.fMetadata = std::move(metadata);
339 }
340
Robert Phillips0dee19b2019-05-23 17:22:19 +0000341 void push_back(const GrPerspQuad& quad, GrQuadType type, T&& metadata) {
342 QuadData<T>& item = this->pushBackImpl(quad, type);
Michael Ludwigc96fc372019-01-08 15:46:15 -0500343 item.fMetadata = std::move(metadata);
344 }
345
346 // And provide access to the metadata per quad
347 const T& metadata(int i) const {
348 return this->item(i).fMetadata;
349 }
350
351 T& metadata(int i) {
352 return this->item(i).fMetadata;
353 }
354
355private:
356 typedef GrQuadListBase<T> INHERITED;
Brian Salomonbe3c1d22018-05-21 12:54:39 -0400357};
358
joshualittae5b2c62015-08-19 08:48:41 -0700359#endif