1 /* 2 * Copyright 2023 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_EdgeAAQuad_DEFINED 9 #define skgpu_graphite_geom_EdgeAAQuad_DEFINED 10 11 #include "include/core/SkRect.h" 12 #include "src/base/SkVx.h" 13 #include "src/core/SkEnumBitMask.h" 14 #include "src/gpu/graphite/geom/Rect.h" 15 16 namespace skgpu::graphite { 17 18 /** 19 * EdgeAAQuad contains (x,y) coordinates for the four corners of a quadrilateral, assumed to be 20 * convex and in a consistent winding (CW vs. CCW is fine). Locally, the vertices are ordered 21 * "top-left", "top-right", "bottom-right", "bottom-left". The edges are in order left (p0-p3), 22 * top (p1-p0), right (p2-p1), and bottom (p3-p2). 23 */ 24 class EdgeAAQuad { 25 public: 26 // SkEnumBitMask<Flags> is a typesafe equivalent to SkCanvas::QuadAAFlags. 27 enum class Flags : uint8_t { 28 kLeft = 0b0001, 29 kTop = 0b0010, 30 kRight = 0b0100, 31 kBottom = 0b1000, 32 33 kNone = 0b0000, 34 kAll = 0b1111, 35 }; 36 37 EdgeAAQuad() = delete; 38 EdgeAAQuad(const SkRect & rect,SkEnumBitMask<Flags> edgeFlags)39 EdgeAAQuad(const SkRect& rect, SkEnumBitMask<Flags> edgeFlags) 40 : fXs{rect.fLeft, rect.fRight, rect.fRight, rect.fLeft} 41 , fYs{rect.fTop, rect.fTop, rect.fBottom, rect.fBottom} 42 , fEdgeFlags(edgeFlags) 43 , fIsRect(true) {} EdgeAAQuad(const Rect & rect,SkEnumBitMask<Flags> edgeFlags)44 EdgeAAQuad(const Rect& rect, SkEnumBitMask<Flags> edgeFlags) 45 : fXs{skvx::shuffle<0,2,2,0>(rect.ltrb())} 46 , fYs{skvx::shuffle<1,1,3,3>(rect.ltrb())} 47 , fEdgeFlags(edgeFlags) 48 , fIsRect(true) {} EdgeAAQuad(const SkPoint points[4],SkEnumBitMask<Flags> edgeFlags)49 EdgeAAQuad(const SkPoint points[4], SkEnumBitMask<Flags> edgeFlags) 50 : fXs{points[0].fX, points[1].fX, points[2].fX, points[3].fX} 51 , fYs{points[0].fY, points[1].fY, points[2].fY, points[3].fY} 52 , fEdgeFlags(edgeFlags) 53 , fIsRect(false) {} EdgeAAQuad(const skvx::float4 & xs,const skvx::float4 & ys,SkEnumBitMask<Flags> edgeFlags)54 EdgeAAQuad(const skvx::float4& xs, const skvx::float4& ys, SkEnumBitMask<Flags> edgeFlags) 55 : fXs(xs) 56 , fYs(ys) 57 , fEdgeFlags(edgeFlags) 58 , fIsRect(false) {} 59 60 // The bounding box of the quadrilateral (not counting any outsetting for anti-aliasing). bounds()61 Rect bounds() const { 62 if (fIsRect) { 63 return Rect({fXs[0], fYs[0]}, {fXs[2], fYs[2]}); 64 } 65 66 Rect p0p1 = Rect::LTRB(skvx::shuffle<0,2,1,3>(skvx::float4(fXs.lo, fYs.lo))).makeSorted(); 67 Rect p2p3 = Rect::LTRB(skvx::shuffle<0,2,1,3>(skvx::float4(fXs.hi, fYs.hi))).makeSorted(); 68 return p0p1.makeJoin(p2p3); 69 } 70 71 // Access the individual elements of the quad data. xs()72 const skvx::float4& xs() const { return fXs; } ys()73 const skvx::float4& ys() const { return fYs; } edgeFlags()74 SkEnumBitMask<Flags> edgeFlags() const { return fEdgeFlags; } 75 isRect()76 bool isRect() const { return fIsRect; } 77 78 private: 79 skvx::float4 fXs; 80 skvx::float4 fYs; 81 SkEnumBitMask<Flags> fEdgeFlags; 82 bool fIsRect; 83 }; 84 85 SK_MAKE_BITMASK_OPS(EdgeAAQuad::Flags) 86 87 } // namespace skgpu::graphite 88 89 #endif // skgpu_graphite_geom_EdgeAAQuad_DEFINED 90