Flutter Engine
The Flutter Engine
GrQuad.h
Go to the documentation of this file.
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
13#include "include/core/SkRect.h"
17#include "src/base/SkVx.h"
19
20#include <algorithm>
21#include <type_traits>
22
23class SkMatrix;
24enum class GrQuadAAFlags;
25
26/**
27 * GrQuad is a collection of 4 points which can be used to represent an arbitrary quadrilateral. The
28 * points make a triangle strip with CCW triangles (top-left, bottom-left, top-right, bottom-right).
29 */
30class GrQuad {
31public:
32 // Quadrilaterals can be classified in several useful ways that assist AA tessellation and other
33 // analysis when drawing, in particular, knowing if it was originally a rectangle transformed by
34 // certain types of matrices:
35 enum class Type {
36 // The 4 points remain an axis-aligned rectangle; their logical indices may not respect
37 // TL, BL, TR, BR ordering if the transform was a 90 degree rotation or mirror.
38 kAxisAligned,
39 // The 4 points represent a rectangle subjected to a rotation, its corners are right angles.
40 kRectilinear,
41 // Arbitrary 2D quadrilateral; may have been a rectangle transformed with skew or some
42 // clipped polygon. Its w coordinates will all be 1.
44 // Even more general-purpose than kGeneral, this allows the w coordinates to be non-unity.
46 kLast = kPerspective
47 };
48 static const int kTypeCount = static_cast<int>(Type::kLast) + 1;
49
50 // This enforces W == 1 for non-perspective quads, but does not initialize X or Y.
51 GrQuad() = default;
52 GrQuad(const GrQuad&) = default;
53
54 explicit GrQuad(const SkRect& rect)
55 : fX{rect.fLeft, rect.fLeft, rect.fRight, rect.fRight}
56 , fY{rect.fTop, rect.fBottom, rect.fTop, rect.fBottom} {}
57
58 static GrQuad MakeFromRect(const SkRect&, const SkMatrix&);
59
60 // Creates a GrQuad from the quadrilateral 'pts', transformed by the matrix. The input
61 // points array is arranged as per SkRect::toQuad (top-left, top-right, bottom-right,
62 // bottom-left). The returned instance's point order will still be CCW tri-strip order.
63 static GrQuad MakeFromSkQuad(const SkPoint pts[4], const SkMatrix&);
64
65 GrQuad& operator=(const GrQuad&) = default;
66
67 SkPoint3 point3(int i) const { return {fX[i], fY[i], fW[i]}; }
68
69 SkPoint point(int i) const {
70 if (fType == Type::kPerspective) {
71 return {fX[i] / fW[i], fY[i] / fW[i]};
72 } else {
73 return {fX[i], fY[i]};
74 }
75 }
76
77 void writeVertex(int cornerIdx, skgpu::VertexWriter& w) const {
78 w << this->point(cornerIdx);
79 }
80
81 SkRect bounds() const {
82 if (fType == GrQuad::Type::kPerspective) {
83 return this->projectedBounds();
84 }
85 // Calculate min/max directly on the 4 floats, instead of loading/unloading into SIMD. Since
86 // there's no horizontal min/max, it's not worth it. Defining non-perspective case in header
87 // also leads to substantial performance boost due to inlining.
88 auto min = [](const float c[4]) { return std::min(std::min(c[0], c[1]),
89 std::min(c[2], c[3]));};
90 auto max = [](const float c[4]) { return std::max(std::max(c[0], c[1]),
91 std::max(c[2], c[3]));};
92 return { min(fX), min(fY), max(fX), max(fY) };
93 }
94
95 bool isFinite() const {
96 // If any coordinate is infinity or NaN, then multiplying it with 0 will make accum NaN
97 float accum = 0;
98 for (int i = 0; i < 4; ++i) {
99 accum *= fX[i];
100 accum *= fY[i];
101 accum *= fW[i];
102 }
103 SkASSERT(0 == accum || SkIsNaN(accum));
104
105 return accum == 0.0f;
106 }
107
108 float x(int i) const { return fX[i]; }
109 float y(int i) const { return fY[i]; }
110 float w(int i) const { return fW[i]; }
111 float iw(int i) const { return sk_ieee_float_divide(1.f, fW[i]); }
112
116 skvx::Vec<4, float> iw4f() const { return 1.f / this->w4f(); }
117
118 Type quadType() const { return fType; }
119
120 bool hasPerspective() const { return fType == Type::kPerspective; }
121
122 // True if anti-aliasing affects this quad. Only valid when quadType == kAxisAligned
123 bool aaHasEffectOnRect(GrQuadAAFlags edgeFlags) const;
124
125 // True if this quad is axis-aligned and still has its top-left corner at v0. Equivalently,
126 // quad == GrQuad(quad->bounds()). Axis-aligned quads with flips and rotations may exactly
127 // fill their bounds, but their vertex order will not match TL BL TR BR anymore.
128 bool asRect(SkRect* rect) const;
129
130 // The non-const pointers are provided to support modifying a GrQuad in-place, but care must be
131 // taken to keep its quad type aligned with the geometric nature of the new coordinates.
132 const float* xs() const { return fX; }
133 float* xs() { return fX; }
134 const float* ys() const { return fY; }
135 float* ys() { return fY; }
136 const float* ws() const { return fW; }
137 float* ws() { return fW; }
138
139 // Automatically ensures ws are 1 if new type is not perspective.
140 void setQuadType(Type newType) {
141 if (newType != Type::kPerspective && fType == Type::kPerspective) {
142 fW[0] = fW[1] = fW[2] = fW[3] = 1.f;
143 }
144 SkASSERT(newType == Type::kPerspective ||
145 (SkScalarNearlyEqual(fW[0], 1.f) && SkScalarNearlyEqual(fW[1], 1.f) &&
146 SkScalarNearlyEqual(fW[2], 1.f) && SkScalarNearlyEqual(fW[3], 1.f)));
147
148 fType = newType;
149 }
150private:
151 template<typename T>
152 friend class GrQuadListBase; // for access to fX, fY, fW
153
155 : fType(type) {
157 xs.store(fX);
158 ys.store(fY);
159 }
160
163 : fW{} // Include fW in member initializer to avoid redundant default initializer
164 , fType(type) {
165 xs.store(fX);
166 ys.store(fY);
167 ws.store(fW);
168 }
169
170 // Defined in GrQuadUtils.cpp to share the coord clipping code
171 SkRect projectedBounds() const;
172
173 float fX[4];
174 float fY[4];
175 float fW[4] = {1.f, 1.f, 1.f, 1.f};
176
177 Type fType = Type::kAxisAligned;
178};
179
180template<> struct skgpu::VertexWriter::is_quad<GrQuad> : std::true_type {};
181
182// A simple struct representing the common work unit of a pair of device and local coordinates, as
183// well as the edge flags controlling anti-aliasing for the quadrilateral when drawn.
184struct DrawQuad {
188};
189
190#endif
GrQuadAAFlags
Definition: GrTypesPriv.h:247
#define SkASSERT(cond)
Definition: SkAssert.h:116
static constexpr bool SkIsNaN(T x)
static constexpr float sk_ieee_float_divide(float numer, float denom)
@ kGeneral
static bool SkScalarNearlyEqual(SkScalar x, SkScalar y, SkScalar tolerance=SK_ScalarNearlyZero)
Definition: SkScalar.h:107
GLenum type
Definition: GrQuad.h:30
skvx::Vec< 4, float > iw4f() const
Definition: GrQuad.h:116
const float * xs() const
Definition: GrQuad.h:132
static const int kTypeCount
Definition: GrQuad.h:48
void writeVertex(int cornerIdx, skgpu::VertexWriter &w) const
Definition: GrQuad.h:77
const float * ys() const
Definition: GrQuad.h:134
float * xs()
Definition: GrQuad.h:133
float y(int i) const
Definition: GrQuad.h:109
Type quadType() const
Definition: GrQuad.h:118
static GrQuad MakeFromRect(const SkRect &, const SkMatrix &)
Definition: GrQuad.cpp:107
float w(int i) const
Definition: GrQuad.h:110
float iw(int i) const
Definition: GrQuad.h:111
skvx::Vec< 4, float > y4f() const
Definition: GrQuad.h:114
bool aaHasEffectOnRect(GrQuadAAFlags edgeFlags) const
Definition: GrQuad.cpp:135
bool hasPerspective() const
Definition: GrQuad.h:120
float x(int i) const
Definition: GrQuad.h:108
bool asRect(SkRect *rect) const
Definition: GrQuad.cpp:141
float * ys()
Definition: GrQuad.h:135
static GrQuad MakeFromSkQuad(const SkPoint pts[4], const SkMatrix &)
Definition: GrQuad.cpp:122
skvx::Vec< 4, float > x4f() const
Definition: GrQuad.h:113
void setQuadType(Type newType)
Definition: GrQuad.h:140
GrQuad & operator=(const GrQuad &)=default
bool isFinite() const
Definition: GrQuad.h:95
SkPoint point(int i) const
Definition: GrQuad.h:69
SkRect bounds() const
Definition: GrQuad.h:81
friend class GrQuadListBase
Definition: GrQuad.h:152
float * ws()
Definition: GrQuad.h:137
SkPoint3 point3(int i) const
Definition: GrQuad.h:67
GrQuad(const GrQuad &)=default
const float * ws() const
Definition: GrQuad.h:136
GrQuad()=default
GrQuad(const SkRect &rect)
Definition: GrQuad.h:54
skvx::Vec< 4, float > w4f() const
Definition: GrQuad.h:115
static float max(float r, float g, float b)
Definition: hsl.cpp:49
static float min(float r, float g, float b)
Definition: hsl.cpp:48
sk_sp< SkBlender > blender SkRect rect
Definition: SkRecords.h:350
GrQuad fLocal
Definition: GrQuad.h:186
GrQuad fDevice
Definition: GrQuad.h:185
GrQuadAAFlags fEdgeFlags
Definition: GrQuad.h:187
Definition: SkVx.h:83
static SKVX_ALWAYS_INLINE Vec Load(const void *ptr)
Definition: SkVx.h:109