16#include <unordered_set>
23 paint.setAntiAlias(
true);
27 paint.setStrokeJoin(join);
34 float s1 =
a*
a +
b*
b + c*c +
d*
d;
36 float e =
a*
a +
b*
b - c*c -
d*
d;
43 return {singular1, singular2};
74 SkV4 devP = matrix.map(p.x, p.y, 0.f, 1.f);
76 const float dxdu = matrix.rc(0,0);
77 const float dxdv = matrix.rc(0,1);
78 const float dydu = matrix.rc(1,0);
79 const float dydv = matrix.rc(1,1);
80 const float dwdu = matrix.rc(3,0);
81 const float dwdv = matrix.rc(3,1);
83 float invW2 = 1.f / (devP.
w * devP.
w);
85 float dfdu = (devP.
w*dxdu - devP.
x*dwdu) * invW2;
86 float dfdv = (devP.
w*dxdv - devP.
x*dwdv) * invW2;
87 float dgdu = (devP.
w*dydu - devP.
y*dwdu) * invW2;
88 float dgdv = (devP.
w*dydv - devP.
y*dwdv) * invW2;
99 float minScale = std::min(sv1, sv2);
118 const SkV2& cornerRadii,
const SkV4& devCenter,
float centerWeight,
119 float strokeRadius,
float joinScale,
float localAARadius)
const {
120 const bool snapToCenter = centerWeight +
fCenterWeight > 0.f;
122 return {devCenter.
x, devCenter.
y, devCenter.
w};
129 normalizedPos =
scale*normalizedPos - cornerRadii;
134 if (maxInset.
x < 0.f || maxInset.
y < 0.f) {
136 SkV2{std::min(maxInset.
x, 0.f), std::min(maxInset.
y, 0.f)}
139 normalizedPos += localAARadius *
fNormal;
144 {cornerMapping.
x*normalizedPos.
x + cornerMapping.
y*normalizedPos.
y + cornerPt.
x,
145 cornerMapping.
z*normalizedPos.
x + cornerMapping.
w*normalizedPos.
y + cornerPt.
y};
146 SkV4 devPos = m.map(localPos.
x, localPos.
y, 0.f, 1.f);
148 const bool deviceSpaceNormal =
150 if (deviceSpaceNormal) {
164 float px = cornerMapping.
y*cornerPt.
y - cornerMapping.
w*cornerPt.
x;
165 float py = cornerMapping.
z*cornerPt.
x - cornerMapping.
x*cornerPt.
y;
189 if (normX.
dot(normY) < -0.8) {
192 float sign = normX.
cross(normY) >= 0.f ? 1.f : -1.f;
209 return SkV3{devPos.
x, devPos.
y, devPos.
w};
225 { {0.0f, 1.0f}, { 0.0f, 1.0f}, 1.0f, 0.0f, -2.f },
226 { {0.0f, 1.0f}, { 0.0f, 1.0f}, 1.0f, 1.0f, -2.f },
227 { {0.0f, 1.0f}, {
kHR2,
kHR2}, 1.0f, 1.0f, -2.f },
228 { {1.0f, 0.0f}, {
kHR2,
kHR2}, 1.0f, 1.0f, -2.f },
229 { {1.0f, 0.0f}, { 1.0f, 0.0f}, 1.0f, 1.0f, -2.f },
230 { {1.0f, 0.0f}, { 1.0f, 0.0f}, 1.0f, 0.0f, -2.f },
233 { {0.0f, 1.0f}, { 0.0f, 0.0f}, 1.0f, 0.0f, -2.f },
234 { {0.0f, 1.0f}, { 0.0f, 0.0f}, 1.0f, 1.0f, -2.f },
235 { {1.0f, 0.0f}, { 0.0f, 0.0f}, 1.0f, 1.0f, -2.f },
236 { {1.0f, 0.0f}, { 0.0f, 0.0f}, 1.0f, 0.0f, -2.f },
239 { {0.0f, 1.0f}, { 0.0f, 0.0f}, 0.0f, 0.0f, -2.f },
240 { {0.0f, 1.0f}, { 0.0f, 0.0f}, 0.0f, 1.0f, -2.f },
241 { {1.0f, 0.0f}, { 0.0f, 0.0f}, 0.0f, 1.0f, -2.f },
242 { {1.0f, 0.0f}, { 0.0f, 0.0f}, 0.0f, 0.0f, -2.f },
245 { {0.0f, 1.0f}, { 0.0f, -1.0f}, -1.0f, 0.0f, -1.f },
246 { {0.5f, 0.5f}, {-
kHR2, -
kHR2}, -1.0f, 1.0f, -1.f },
247 { {1.0f, 0.0f}, {-1.0f, 0.0f}, -1.0f, 0.0f, -1.f },
250 { {0.5f, 0.5f}, {-
kHR2, -
kHR2}, -1.0f, 1.0f, 0.f },
251 { {1.0f, 0.0f}, {-1.0f, 0.0f}, -1.0f, 0.0f, 0.f },
256 float centerWeight,
float localAARadius,
float strokeRadius,
262 if (cornerRadii.
x <= 0.f || cornerRadii.
y <= 0.f) {
265 if (strokeRadius > 0.f) {
281 center, centerWeight, strokeRadius, joinScale,
298 float localAARadius = std::max({
305 float centerWeight = 0.f;
306 if (strokeRadius < 0.f) {
318 float maxInset = strokeRadius + localAARadius;
319 if (maxInset >= rrect.
width() - maxInset ||
320 maxInset >= rrect.
height() - maxInset ||
336 static constexpr SkV4 kBRBasis = { 1.f, 0.f, 0.f, 1.f};
337 static constexpr SkV4 kTRBasis = { 0.f, 1.f, -1.f, 0.f};
338 static constexpr SkV4 kTLBasis = {-1.f, 0.f, 0.f, -1.f};
339 static constexpr SkV4 kBLBasis = { 0.f, -1.f, 1.f, 0.f};
346 devCenter, centerWeight, localAARadius, strokeRadius, join);
352 devCenter, centerWeight, localAARadius,strokeRadius, join);
358 devCenter, centerWeight, localAARadius,strokeRadius, join);
364 devCenter, centerWeight, localAARadius,strokeRadius, join);
370 kBR+0,
kBR+6,
kBR+1,
kBR+7,
kBR+2,
kBR+8,
kBR+3,
kBR+8,
kBR+4,
kBR+9,
kBR+5,
kBR+9,
371 kTR+0,
kTR+6,
kTR+1,
kTR+7,
kTR+2,
kTR+8,
kTR+3,
kTR+8,
kTR+4,
kTR+9,
kTR+5,
kTR+9,
372 kTL+0,
kTL+6,
kTL+1,
kTL+7,
kTL+2,
kTL+8,
kTL+3,
kTL+8,
kTL+4,
kTL+9,
kTL+5,
kTL+9,
373 kBL+0,
kBL+6,
kBL+1,
kBL+7,
kBL+2,
kBL+8,
kBL+3,
kBL+8,
kBL+4,
kBL+9,
kBL+5,
kBL+9,
396 kBR+0,
kBR+0,
kBR+6,
kBR+1,
kBR+7,
kBR+2,
kBR+8,
kBR+3,
kBR+8,
kBR+4,
kBR+9,
kBR+5,
kBR+5,
397 kTR+0,
kTR+0,
kTR+6,
kTR+1,
kTR+7,
kTR+2,
kTR+8,
kTR+3,
kTR+8,
kTR+4,
kTR+9,
kTR+5,
kTR+5,
398 kTL+0,
kTL+0,
kTL+6,
kTL+1,
kTL+7,
kTL+2,
kTL+8,
kTL+3,
kTL+8,
kTL+4,
kTL+9,
kTL+5,
kTL+5,
399 kBL+0,
kBL+0,
kBL+6,
kBL+1,
kBL+7,
kBL+2,
kBL+8,
kBL+3,
kBL+8,
kBL+4,
kBL+9,
kBL+5,
kBL+5,
401 kBR+6,
kBR+6,
kBR+10,
kBR+7,
kBR+11,
kBR+8,
kBR+12,
kBR+9,
kBR+13,
kBR+13,
402 kTR+6,
kTR+6,
kTR+10,
kTR+7,
kTR+11,
kTR+8,
kTR+12,
kTR+9,
kTR+13,
kTR+13,
403 kTL+6,
kTL+6,
kTL+10,
kTL+7,
kTL+11,
kTL+8,
kTL+12,
kTL+9,
kTL+13,
kTL+13,
441 static constexpr float kControlPointRadius = 3.f;
442 static constexpr float kBaseScale = 50.f;
446 : fOrigin{300.f, 300.f}
447 , fXAxisPoint{300.f + kBaseScale, 300.f}
448 , fYAxisPoint{300.f, 300.f + kBaseScale}
450 , fJoinMode(
SkPaint::kMiter_Join)
451 , fMode(PrimitiveMode::kFillRect) {
452 fName =
"GraphitePrimitives";
459 canvas->
concat(this->basisMatrix());
464 SkRRect rrect = this->primitiveShape();
471 this->drawVertices(canvas, totalMatrix);
473 SkV4 origin = viewMatrix.
map(fOrigin.
x, fOrigin.
y, 0.f, 1.f);
474 SkV4 xAxis = viewMatrix.
map(fXAxisPoint.
x, fXAxisPoint.
y, 0.f, 1.f);
475 SkV4 yAxis = viewMatrix.
map(fYAxisPoint.
x, fYAxisPoint.
y, 0.f, 1.f);
478 canvas->
drawLine({origin.
x/origin.
w, origin.
y/origin.
w},
480 canvas->
drawLine({origin.
x/origin.
w, origin.
y/origin.
w},
502 enum class PrimitiveMode {
510 SkM44 basisMatrix()
const {
511 SkV2 xAxis = (fXAxisPoint - fOrigin) / kBaseScale;
512 SkV2 yAxis = (fYAxisPoint - fOrigin) / kBaseScale;
515 {yAxis.
x, yAxis.
y, 0.f, 0.f},
516 {0.f, 0.f, 1.f, 0.f},
517 {fOrigin.
x, fOrigin.
y, 0.f, 1.f});
521 if (
fMode == PrimitiveMode::kFillRect ||
fMode == PrimitiveMode::kFillRRect) {
527 SkRRect primitiveShape()
const {
529 kBaseScale, kBaseScale);
531 static const SkVector kOuterRadii[4] = { { 0.25f * kBaseScale, 0.75f * kBaseScale },
533 { 0.5f * kBaseScale, 0.5f * kBaseScale },
534 { 0.75f * kBaseScale, 0.25f * kBaseScale } };
536 static const SkVector kStrokeRadii[4] = { { 0.25f * kBaseScale, 0.25f * kBaseScale },
538 { 0.5f * kBaseScale, 0.5f * kBaseScale },
539 { 0.75f * kBaseScale, 0.75f * kBaseScale } };
541 float strokeRadius = 0.5f * fStrokeWidth;
543 case PrimitiveMode::kFillRect:
545 case PrimitiveMode::kFillRRect: {
550 case PrimitiveMode::kStrokeRect:
552 case PrimitiveMode::kStrokeRRect: {
576 const uint16_t* indices,
580 nullptr,
nullptr, (
int) indexCount, indices);
605 std::unordered_set<uint32_t> edges;
606 auto drawEdge = [&edges, vertices, canvas](uint16_t
e0, uint16_t
e1) {
607 uint32_t edgeID = (std::max(
e0,
e1) << 16) | std::min(
e0,
e1);
608 if (edges.find(edgeID) == edges.end()) {
609 edges.insert(edgeID);
617 for (
size_t i = 2; i < std::size(
kIndices); ++i) {
635 bool fColorize =
true;
644 *fPoint += {delta.fX, delta.fY};
653 auto selected = [
x,
y](
const SkV2& p) {
654 return ((p -
SkV2{
x,
y}).
length() < kControlPointRadius);
657 if (selected(fOrigin)) {
658 return new Click(&fOrigin);
659 }
else if (selected(fXAxisPoint)) {
660 return new Click(&fXAxisPoint);
661 }
else if (selected(fYAxisPoint)) {
662 return new Click(&fYAxisPoint);
677 fMode = PrimitiveMode::kFillRect;
680 fMode = PrimitiveMode::kFillRRect;
683 fMode = PrimitiveMode::kStrokeRect;
686 fMode = PrimitiveMode::kStrokeRRect;
689 fStrokeWidth = std::max(0.f, fStrokeWidth - 0.4f);
692 fStrokeWidth = std::min(5 * kBaseScale, fStrokeWidth + 0.4f);
705 fOrigin = {300.f, 300.f};
706 fXAxisPoint = {300.f + kBaseScale, 300.f};
707 fYAxisPoint = {300.f, 300.f + kBaseScale};
710 fColorize = !fColorize;
static SkM44 inv(const SkM44 &m)
static const int strokeWidth
static const uint16_t kOuterCornerIndices[]
static const uint16_t kEdgeIndices[]
static constexpr float kMiterScale
static const uint16_t kTL
static void compute_vertices(SkV3 devPts[kVertexCount], const SkM44 &m, const SkRRect &rrect, float strokeRadius, SkPaint::Join join)
static const uint16_t kBL
static constexpr float kAARadius
static const size_t kVertexCount
static const uint16_t kInteriorIndices[]
static const uint16_t kIndices[]
static const uint16_t kBR
static constexpr float kBevelScale
static constexpr LocalCornerVert kCornerTemplate[19]
static const uint16_t kTR
static std::pair< float, float > singular_values(float a, float b, float c, float d)
static float local_aa_radius(const SkM44 &matrix, const SkV2 &p)
static void compute_corner(SkV3 devPts[19], const SkM44 &m, const SkV4 &cornerMapping, const SkV2 &cornerPt, const SkV2 &cornerRadii, const SkV4 ¢er, float centerWeight, float localAARadius, float strokeRadius, SkPaint::Join join)
static constexpr float kRoundScale
static constexpr float kHR2
static const uint16_t kInnerCornerIndices[]
static const int points[]
#define SkAssertResult(cond)
constexpr SkColor SK_ColorMAGENTA
constexpr SkColor SK_ColorCYAN
constexpr SkColor SK_ColorGRAY
constexpr SkColor SK_ColorBLUE
constexpr SkColor SK_ColorRED
constexpr SkColor SK_ColorBLACK
constexpr SkColor SK_ColorGREEN
constexpr SkColor SK_ColorDKGRAY
constexpr float SK_FloatSqrt2
static void normalize(int n, double *gauss)
static int sign(SkScalar x)
static bool SkScalarNearlyEqual(SkScalar x, SkScalar y, SkScalar tolerance=SK_ScalarNearlyZero)
#define SK_ScalarNearlyZero
#define SK_ScalarRoot2Over2
static SkScalar center(float pos0, float pos1)
void draw(SkCanvas *canvas) override
bool onClick(Click *) override
Click * onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey) override
GraphitePrimitivesSlide()
bool onChar(SkUnichar) override
void drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint &paint)
SkM44 getLocalToDevice() const
void drawRRect(const SkRRect &rrect, const SkPaint &paint)
void concat(const SkMatrix &matrix)
void drawVertices(const SkVertices *vertices, SkBlendMode mode, const SkPaint &paint)
void drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint &paint)
SkV4 map(float x, float y, float z, float w) const
static SkM44 Cols(const SkV4 &c0, const SkV4 &c1, const SkV4 &c2, const SkV4 &c3)
void setColor(SkColor color)
@ kStroke_Style
set to stroke geometry
@ kMiter_Join
extends to miter limit
@ kBevel_Join
connects outside edges
void outset(SkScalar dx, SkScalar dy, SkRRect *dst) const
SkVector radii(Corner corner) const
@ kUpperLeft_Corner
index of top-left corner radii
@ kLowerRight_Corner
index of bottom-right corner radii
@ kUpperRight_Corner
index of top-right corner radii
@ kLowerLeft_Corner
index of bottom-left corner radii
static SkRRect MakeRect(const SkRect &r)
void setRectRadii(const SkRect &rect, const SkVector radii[4])
const SkRect & getBounds() const
static sk_sp< SkVertices > MakeCopy(VertexMode mode, int vertexCount, const SkPoint positions[], const SkPoint texs[], const SkColor colors[], int indexCount, const uint16_t indices[])
@ kTriangleStrip_VertexMode
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE auto & d
SkV3 transform(const SkM44 &m, const SkV4 &cornerMapping, const SkV2 &cornerPt, const SkV2 &cornerRadii, const SkV4 &devCenter, float centerWeight, float strokeRadius, float joinScale, float localAARadius) const
constexpr float x() const
SkScalar fBottom
larger y-axis bounds
SkRect makeOutset(float dx, float dy) const
constexpr float centerX() const
constexpr float centerY() const
static constexpr SkRect MakeLTRB(float l, float t, float r, float b)
SkScalar fTop
smaller y-axis bounds
SkScalar dot(SkV2 v) const
SkScalar cross(SkV2 v) const
SkScalar dot(const SkV4 &v) const