• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2021 Google LLC
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 skgpu_graphite_geom_Rect_DEFINED
9 #define skgpu_graphite_geom_Rect_DEFINED
10 
11 #include "include/core/SkRect.h"
12 #include "src/base/SkVx.h"
13 
14 namespace skgpu::graphite {
15 
16 #define AI SK_ALWAYS_INLINE
17 
18 /**
19  * SIMD rect implementation. Vales are stored internally in the form: [left, top, -right, -bot].
20  *
21  * Some operations (e.g., intersect, inset) may return a negative or empty rect
22  * (negative meaning, left >= right or top >= bot).
23  *
24  * Operations on a rect that is either negative or empty, while well-defined, might not give the
25  * intended result. It is the caller's responsibility to check isEmptyOrNegative() if needed.
26  */
27 class Rect {
28     using float2 = skvx::float2;
29     using float4 = skvx::float4;
30 public:
31     AI Rect() = default;
Rect(float l,float t,float r,float b)32     AI Rect(float l, float t, float r, float b) : fVals(NegateBotRight({l,t,r,b})) {}
Rect(float2 topLeft,float2 botRight)33     AI Rect(float2 topLeft, float2 botRight) : fVals(topLeft, -botRight) {}
Rect(const SkRect & r)34     AI Rect(const SkRect& r) : fVals(NegateBotRight(float4::Load(r.asScalars()))) {}
35 
LTRB(float4 ltrb)36     AI static Rect LTRB(float4 ltrb) {
37         return Rect(NegateBotRight(ltrb));
38     }
39 
XYWH(float x,float y,float w,float h)40     AI static Rect XYWH(float x, float y, float w, float h) {
41         return Rect(x, y, x + w, y + h);
42     }
XYWH(float2 topLeft,float2 size)43     AI static Rect XYWH(float2 topLeft, float2 size) {
44         return Rect(topLeft, topLeft + size);
45     }
WH(float w,float h)46     AI static Rect WH(float w, float h) {
47         return Rect(0, 0, w, h);
48     }
WH(float2 size)49     AI static Rect WH(float2 size) {
50         return Rect(float2(0), size);
51     }
Point(float2 p)52     AI static Rect Point(float2 p) {
53         return Rect(p, p);
54     }
FromVals(float4 vals)55     AI static Rect FromVals(float4 vals) {  // vals.zw must already be negated.
56         return Rect(vals);
57     }
58 
59     // Constructs a Rect with ltrb = [-inf, -inf, inf, inf], useful for accumulating intersections
Infinite()60     AI static Rect Infinite() {
61         return FromVals(float4(SK_FloatNegativeInfinity));
62     }
63     // Constructs a negative Rect with ltrb = [inf, inf, -inf, -inf], useful for accumulating unions
InfiniteInverted()64     AI static Rect InfiniteInverted() {
65         return FromVals(float4(SK_FloatInfinity));
66     }
67 
68     AI bool operator==(Rect rect) const { return all(fVals == rect.fVals); }
69     AI bool operator!=(Rect rect) const { return any(fVals != rect.fVals); }
70 
vals()71     AI const float4& vals() const { return fVals; }  // [left, top, -right, -bot].
vals()72     AI float4& vals() { return fVals; }  // [left, top, -right, -bot].
73 
x()74     AI float x() const { return fVals.x(); }
y()75     AI float y() const { return fVals.y(); }
left()76     AI float left() const { return fVals.x(); }
top()77     AI float top() const { return fVals.y(); }
right()78     AI float right() const { return -fVals.z(); }
bot()79     AI float bot() const { return -fVals.w(); }
topLeft()80     AI float2 topLeft() const { return fVals.xy(); }
botRight()81     AI float2 botRight() const { return -fVals.zw(); }
ltrb()82     AI float4 ltrb() const { return NegateBotRight(fVals); }
83 
setLeft(float left)84     AI void setLeft(float left) { fVals.x() = left; }
setTop(float top)85     AI void setTop(float top) { fVals.y() = top; }
setRight(float right)86     AI void setRight(float right) { fVals.z() = -right; }
setBot(float bot)87     AI void setBot(float bot) { fVals.w() = -bot; }
setTopLeft(float2 topLeft)88     AI void setTopLeft(float2 topLeft) { fVals.xy() = topLeft; }
setBotRight(float2 botRight)89     AI void setBotRight(float2 botRight) { fVals.zw() = -botRight; }
90 
asSkRect()91     AI SkRect asSkRect() const { return skvx::bit_pun<SkRect>(this->ltrb()); }
asSkIRect()92     AI SkIRect asSkIRect() const { return skvx::bit_pun<SkIRect>(skvx::cast<int>(this->ltrb())); }
93 
isEmptyNegativeOrNaN()94     AI bool isEmptyNegativeOrNaN() const {
95         return !all(fVals.xy() + fVals.zw() < 0);  // !([l-r, r-b] < 0) == ([w, h] <= 0)
96                                                    // Use "!(-size < 0)" in order to detect NaN.
97     }
98 
size()99     AI float2 size() const { return -(fVals.xy() + fVals.zw()); }  // == [-(l-r), -(t-b)] == [w, h]
100 
center()101     AI float2 center() const {
102         float4 p = fVals * float4(.5f, .5f, -.5f, -.5f);  // == [l, t, r, b] * .5
103         return p.xy() + p.zw();  // == [(l + r)/2, (t + b)/2]
104     }
105 
area()106     AI float area() const {
107         float2 negativeSize = fVals.xy() + fVals.zw();  // == [l-r, t-b] == [-w, -h]
108         return negativeSize.x() * negativeSize.y();
109     }
110 
111     // A rect stored in a complementary form of: [right, bottom, -left, -top]. Store a local
112     // ComplementRect object if intersects() will be called many times.
113     struct ComplementRect {
ComplementRectComplementRect114         AI ComplementRect(Rect rect) : fVals(-rect.fVals.zwxy()) {}
115         float4 fVals;  // [right, bottom, -left, -top]
116     };
117 
intersects(ComplementRect comp)118     AI bool intersects(ComplementRect comp) const { return all(fVals < comp.fVals); }
contains(Rect rect)119     AI bool contains(Rect rect) const { return all(fVals <= rect.fVals); }
120 
121     // Some operations may return a negative or empty rect. Operations on a rect that either is
122     // negative or empty, while well-defined, might not give the intended result. It is the caller's
123     // responsibility to check isEmptyOrNegative() if needed.
makeRoundIn()124     AI Rect makeRoundIn() const { return ceil(fVals); }
makeRoundOut()125     AI Rect makeRoundOut() const { return floor(fVals); }
makeInset(float inset)126     AI Rect makeInset(float inset) const { return fVals + inset; }
makeInset(float2 inset)127     AI Rect makeInset(float2 inset) const { return fVals + inset.xyxy(); }
makeOutset(float outset)128     AI Rect makeOutset(float outset) const { return fVals - outset; }
makeOutset(float2 outset)129     AI Rect makeOutset(float2 outset) const { return fVals - outset.xyxy(); }
makeOffset(float2 offset)130     AI Rect makeOffset(float2 offset) const { return fVals + float4(offset, -offset); }
makeJoin(Rect rect)131     AI Rect makeJoin(Rect rect) const { return min(fVals, rect.fVals); }
makeIntersect(Rect rect)132     AI Rect makeIntersect(Rect rect) const { return max(fVals, rect.fVals); }
makeSorted()133     AI Rect makeSorted() const { return min(fVals, -fVals.zwxy()); }
134 
roundIn()135     AI Rect& roundIn() { return *this = this->makeRoundIn(); }
roundOut()136     AI Rect& roundOut() { return *this = this->makeRoundOut(); }
inset(float inset)137     AI Rect& inset(float inset) { return *this = this->makeInset(inset); }
inset(float2 inset)138     AI Rect& inset(float2 inset) { return *this = this->makeInset(inset); }
outset(float outset)139     AI Rect& outset(float outset) { return *this = this->makeOutset(outset); }
outset(float2 outset)140     AI Rect& outset(float2 outset) { return *this = this->makeOutset(outset); }
offset(float2 offset)141     AI Rect& offset(float2 offset) { return *this = this->makeOffset(offset); }
join(Rect rect)142     AI Rect& join(Rect rect) { return *this = this->makeJoin(rect); }
intersect(Rect rect)143     AI Rect& intersect(Rect rect) { return *this = this->makeIntersect(rect); }
sort()144     AI Rect& sort() { return *this = this->makeSorted(); }
145 
146 private:
NegateBotRight(float4 vals)147     AI static float4 NegateBotRight(float4 vals) {  // Returns [vals.xy, -vals.zw].
148         using uint4 = skvx::uint4;
149         return skvx::bit_pun<float4>(skvx::bit_pun<uint4>(vals) ^ uint4(0, 0, 1u << 31, 1u << 31));
150     }
151 
Rect(float4 vals)152     AI Rect(float4 vals) : fVals(vals) {}  // vals.zw must already be negated.
153 
154     float4 fVals;  // [left, top, -right, -bottom]
155 };
156 
157 #undef AI
158 
159 } // namespace skgpu::graphite
160 
161 #endif // skgpu_graphite_geom_Rect_DEFINED
162