• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "include/core/SkMatrix.h"
12 #include "include/core/SkPoint.h"
13 #include "include/core/SkPoint3.h"
14 #include "include/private/SkVx.h"
15 
16 /**
17  * GrQuad is a collection of 4 points which can be used to represent an arbitrary quadrilateral. The
18  * points make a triangle strip with CCW triangles (top-left, bottom-left, top-right, bottom-right).
19  */
20 class GrQuad {
21 public:
22     // Quadrilaterals can be classified in several useful ways that assist AA tessellation and other
23     // analysis when drawing, in particular, knowing if it was originally a rectangle transformed by
24     // certain types of matrices:
25     enum class Type {
26         // The 4 points remain an axis-aligned rectangle; their logical indices may not respect
27         // TL, BL, TR, BR ordering if the transform was a 90 degre rotation or mirror.
28         kAxisAligned,
29         // The 4 points represent a rectangle subjected to a rotation, its corners are right angles.
30         kRectilinear,
31         // Arbitrary 2D quadrilateral; may have been a rectangle transformed with skew or some
32         // clipped polygon. Its w coordinates will all be 1.
33         kGeneral,
34         // Even more general-purpose than kGeneral, this allows the w coordinates to be non-unity.
35         kPerspective,
36         kLast = kPerspective
37     };
38     static const int kTypeCount = static_cast<int>(Type::kLast) + 1;
39 
40     GrQuad() = default;
41 
GrQuad(const SkRect & rect)42     explicit GrQuad(const SkRect& rect)
43             : fX{rect.fLeft, rect.fLeft, rect.fRight, rect.fRight}
44             , fY{rect.fTop, rect.fBottom, rect.fTop, rect.fBottom}
45             , fW{1.f, 1.f, 1.f, 1.f}
46             , fType(Type::kAxisAligned) {}
47 
GrQuad(const skvx::Vec<4,float> & xs,const skvx::Vec<4,float> & ys,Type type)48     GrQuad(const skvx::Vec<4, float>& xs, const skvx::Vec<4, float>& ys, Type type)
49             : fType(type) {
50         SkASSERT(type != Type::kPerspective);
51         xs.store(fX);
52         ys.store(fY);
53         fW[0] = fW[1] = fW[2] = fW[3] = 1.f;
54     }
55 
GrQuad(const skvx::Vec<4,float> & xs,const skvx::Vec<4,float> & ys,const skvx::Vec<4,float> & ws,Type type)56     GrQuad(const skvx::Vec<4, float>& xs, const skvx::Vec<4, float>& ys,
57            const skvx::Vec<4, float>& ws, Type type)
58             : fType(type) {
59         xs.store(fX);
60         ys.store(fY);
61         ws.store(fW);
62     }
63 
64     // Copy 4 values from each of the arrays into the quad's components
GrQuad(const float xs[4],const float ys[4],const float ws[4],Type type)65     GrQuad(const float xs[4], const float ys[4], const float ws[4], Type type)
66             : fType(type) {
67         memcpy(fX, xs, 4 * sizeof(float));
68         memcpy(fY, ys, 4 * sizeof(float));
69         memcpy(fW, ws, 4 * sizeof(float));
70     }
71 
72     static GrQuad MakeFromRect(const SkRect&, const SkMatrix&);
73 
74     // Creates a GrQuad from the quadrilateral 'pts', transformed by the matrix. The input
75     // points array is arranged as per SkRect::toQuad (top-left, top-right, bottom-right,
76     // bottom-left). The returned instance's point order will still be CCW tri-strip order.
77     static GrQuad MakeFromSkQuad(const SkPoint pts[4], const SkMatrix&);
78 
79     GrQuad& operator=(const GrQuad&) = default;
80 
point3(int i)81     SkPoint3 point3(int i) const { return {fX[i], fY[i], fW[i]}; }
82 
point(int i)83     SkPoint point(int i) const {
84         if (fType == Type::kPerspective) {
85             return {fX[i] / fW[i], fY[i] / fW[i]};
86         } else {
87             return {fX[i], fY[i]};
88         }
89     }
90 
bounds()91     SkRect bounds() const {
92         auto x = this->x4f();
93         auto y = this->y4f();
94         if (fType == Type::kPerspective) {
95             auto iw = this->iw4f();
96             x *= iw;
97             y *= iw;
98         }
99 
100         return {min(x), min(y), max(x), max(y)};
101     }
102 
isFinite()103     bool isFinite() const {
104         // If any coordinate is infinity or NaN, then multiplying it with 0 will make accum NaN
105         float accum = 0;
106         for (int i = 0; i < 4; ++i) {
107             accum *= fX[i];
108             accum *= fY[i];
109             accum *= fW[i];
110         }
111         SkASSERT(0 == accum || SkScalarIsNaN(accum));
112         return !SkScalarIsNaN(accum);
113     }
114 
x(int i)115     float x(int i) const { return fX[i]; }
y(int i)116     float y(int i) const { return fY[i]; }
w(int i)117     float w(int i) const { return fW[i]; }
iw(int i)118     float iw(int i) const { return sk_ieee_float_divide(1.f, fW[i]); }
119 
x4f()120     skvx::Vec<4, float> x4f() const { return skvx::Vec<4, float>::Load(fX); }
y4f()121     skvx::Vec<4, float> y4f() const { return skvx::Vec<4, float>::Load(fY); }
w4f()122     skvx::Vec<4, float> w4f() const { return skvx::Vec<4, float>::Load(fW); }
iw4f()123     skvx::Vec<4, float> iw4f() const { return 1.f / this->w4f(); }
124 
quadType()125     Type quadType() const { return fType; }
126 
hasPerspective()127     bool hasPerspective() const { return fType == Type::kPerspective; }
128 
129     // True if anti-aliasing affects this quad. Only valid when quadType == kAxisAligned
130     bool aaHasEffectOnRect() const;
131 
132     // True if this quad is axis-aligned and still has its top-left corner at v0. Equivalently,
133     // quad == GrQuad(quad->bounds()). Axis-aligned quads with flips and rotations may exactly
134     // fill their bounds, but their vertex order will not match TL BL TR BR anymore.
135     bool asRect(SkRect* rect) const;
136 
137     // The non-const pointers are provided to support modifying a GrQuad in-place, but care must be
138     // taken to keep its quad type aligned with the geometric nature of the new coordinates. This is
139     // no different than using the constructors that accept a quad type.
xs()140     const float* xs() const { return fX; }
xs()141     float* xs() { return fX; }
ys()142     const float* ys() const { return fY; }
ys()143     float* ys() { return fY; }
ws()144     const float* ws() const { return fW; }
ws()145     float* ws() { return fW; }
146 
setQuadType(Type newType)147     void setQuadType(Type newType) { fType = newType; }
148 private:
149     template<typename T>
150     friend class GrQuadListBase; // for access to fX, fY, fW
151 
152     float fX[4];
153     float fY[4];
154     float fW[4];
155 
156     Type fType;
157 };
158 
159 #endif
160