Set ambient stroke to full width of blur.
Gives better blur behavior around corners and looks more like an
actual blur. Also removed the color members, as they're mostly
constant.
Bug: skia:7971
Change-Id: I22a5dcb93da1f39040148ca6ddb391844382cc73
Reviewed-on: https://skia-review.googlesource.com/153280
Commit-Queue: Jim Van Verth <jvanverth@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
diff --git a/src/utils/SkShadowTessellator.cpp b/src/utils/SkShadowTessellator.cpp
index 7956f0e..f78c16d 100644
--- a/src/utils/SkShadowTessellator.cpp
+++ b/src/utils/SkShadowTessellator.cpp
@@ -39,6 +39,8 @@
protected:
static constexpr auto kMinHeight = 0.1f;
+ static constexpr auto kPenumbraColor = SK_ColorTRANSPARENT;
+ static constexpr auto kUmbraColor = SK_ColorBLACK;
int vertexCount() const { return fPositions.count(); }
int indexCount() const { return fIndices.count(); }
@@ -52,8 +54,9 @@
bool computeConvexShadow(SkScalar inset, SkScalar outset, bool doClip);
void computeClipVectorsAndTestCentroid();
bool clipUmbraPoint(const SkPoint& umbraPoint, const SkPoint& centroid, SkPoint* clipPoint);
- void addEdge(const SkVector& nextPoint, const SkVector& nextNormal, bool lastEdge, bool doClip);
- bool addInnerPoint(const SkPoint& pathPoint, int* currUmbraIndex);
+ void addEdge(const SkVector& nextPoint, const SkVector& nextNormal, SkColor umbraColor,
+ bool lastEdge, bool doClip);
+ bool addInnerPoint(const SkPoint& pathPoint, SkColor umbraColor, int* currUmbraIndex);
int getClosestUmbraPoint(const SkPoint& point);
// concave shadow methods
@@ -110,9 +113,6 @@
bool fIsConvex;
bool fValidUmbra;
- SkColor fUmbraColor;
- SkColor fPenumbraColor;
-
SkScalar fDirection;
int fPrevUmbraIndex;
int fCurrUmbraIndex;
@@ -123,6 +123,10 @@
SkPoint fPrevPoint;
};
+// make external linkage happy
+constexpr SkColor SkBaseShadowTessellator::kUmbraColor;
+constexpr SkColor SkBaseShadowTessellator::kPenumbraColor;
+
static bool compute_normal(const SkPoint& p0, const SkPoint& p1, SkScalar dir,
SkVector* newNormal) {
SkVector normal;
@@ -244,6 +248,36 @@
this->computeClipVectorsAndTestCentroid();
}
+ // adjust inset distance and umbra color if necessary
+ auto umbraColor = kUmbraColor;
+ SkScalar minDistSq = SkPointPriv::DistanceToLineSegmentBetweenSqd(fCentroid,
+ fPathPolygon[0],
+ fPathPolygon[1]);
+ SkRect bounds;
+ bounds.setBounds(&fPathPolygon[0], fPathPolygon.count());
+ for (int i = 1; i < fPathPolygon.count(); ++i) {
+ int j = i + 1;
+ if (i == fPathPolygon.count() - 1) {
+ j = 0;
+ }
+ SkPoint currPoint = fPathPolygon[i];
+ SkPoint nextPoint = fPathPolygon[j];
+ SkScalar distSq = SkPointPriv::DistanceToLineSegmentBetweenSqd(fCentroid, currPoint,
+ nextPoint);
+ if (distSq < minDistSq) {
+ minDistSq = distSq;
+ }
+ }
+ static constexpr auto kTolerance = 1.0e-2f;
+ if (minDistSq < (inset + kTolerance)*(inset + kTolerance)) {
+ // if the umbra would collapse, we back off a bit on inner blur and adjust the alpha
+ auto newInset = SkScalarSqrt(minDistSq) - kTolerance;
+ auto ratio = 128 * (newInset + inset) / inset;
+ // they aren't PMColors, but the interpolation algorithm is the same
+ umbraColor = SkPMLerp(kUmbraColor, kPenumbraColor, (unsigned)ratio);
+ inset = newInset;
+ }
+
// generate inner ring
if (!SkInsetConvexPolygon(&fPathPolygon[0], fPathPolygon.count(), inset,
&fUmbraPolygon)) {
@@ -254,7 +288,7 @@
// walk around the path polygon, generate outer ring and connect to inner ring
if (fTransparent) {
fPositions.push_back(fCentroid);
- fColors.push_back(fUmbraColor);
+ fColors.push_back(umbraColor);
}
fCurrUmbraIndex = 0;
@@ -273,7 +307,7 @@
fPrevPoint = fFirstPoint;
fPrevUmbraIndex = -1;
- this->addInnerPoint(fFirstPoint, &fPrevUmbraIndex);
+ this->addInnerPoint(fFirstPoint, umbraColor, &fPrevUmbraIndex);
if (!fTransparent && doClip) {
SkPoint clipPoint;
@@ -281,7 +315,7 @@
fCentroid, &clipPoint);
if (isOutside) {
fPositions.push_back(clipPoint);
- fColors.push_back(fUmbraColor);
+ fColors.push_back(umbraColor);
}
fPrevUmbraOutside = isOutside;
fFirstUmbraOutside = isOutside;
@@ -289,8 +323,8 @@
SkPoint newPoint = fFirstPoint + fFirstOutset;
fPositions.push_back(newPoint);
- fColors.push_back(fPenumbraColor);
- this->addEdge(fPathPolygon[0], fFirstOutset, false, doClip);
+ fColors.push_back(kPenumbraColor);
+ this->addEdge(fPathPolygon[0], fFirstOutset, umbraColor, false, doClip);
for (int i = 1; i < polyCount; ++i) {
SkVector normal;
@@ -299,7 +333,7 @@
}
normal *= outset;
this->addArc(normal, outset, true);
- this->addEdge(fPathPolygon[i], normal, i == polyCount - 1, doClip);
+ this->addEdge(fPathPolygon[i], normal, umbraColor, i == polyCount - 1, doClip);
}
SkASSERT(this->indexCount());
@@ -355,7 +389,7 @@
}
void SkBaseShadowTessellator::addEdge(const SkPoint& nextPoint, const SkVector& nextNormal,
- bool lastEdge, bool doClip) {
+ SkColor umbraColor, bool lastEdge, bool doClip) {
// add next umbra point
int currUmbraIndex;
bool duplicate;
@@ -364,7 +398,7 @@
currUmbraIndex = fFirstVertexIndex;
fPrevPoint = nextPoint;
} else {
- duplicate = this->addInnerPoint(nextPoint, &currUmbraIndex);
+ duplicate = this->addInnerPoint(nextPoint, umbraColor, &currUmbraIndex);
}
int prevPenumbraIndex = duplicate || (currUmbraIndex == fFirstVertexIndex)
? fPositions.count() - 1
@@ -382,7 +416,7 @@
if (isOutside) {
if (!lastEdge) {
fPositions.push_back(clipPoint);
- fColors.push_back(fUmbraColor);
+ fColors.push_back(umbraColor);
}
this->appendTriangle(fPrevUmbraIndex, currUmbraIndex, currUmbraIndex + 1);
if (fPrevUmbraOutside) {
@@ -402,7 +436,7 @@
// add next penumbra point and quad
SkPoint newPoint = nextPoint + nextNormal;
fPositions.push_back(newPoint);
- fColors.push_back(fPenumbraColor);
+ fColors.push_back(kPenumbraColor);
if (!duplicate) {
this->appendTriangle(fPrevUmbraIndex, prevPenumbraIndex, currUmbraIndex);
@@ -445,7 +479,8 @@
return false;
}
-bool SkBaseShadowTessellator::addInnerPoint(const SkPoint& pathPoint, int* currUmbraIndex) {
+bool SkBaseShadowTessellator::addInnerPoint(const SkPoint& pathPoint, SkColor umbraColor,
+ int* currUmbraIndex) {
SkPoint umbraPoint;
if (!fValidUmbra) {
SkVector v = fCentroid - pathPoint;
@@ -466,7 +501,7 @@
} else {
*currUmbraIndex = fPositions.count();
fPositions.push_back(umbraPoint);
- fColors.push_back(fUmbraColor);
+ fColors.push_back(umbraColor);
}
return false;
} else {
@@ -583,10 +618,10 @@
}
fPositions.push_back(penumbraPolygon[currPenumbra]);
- fColors.push_back(fPenumbraColor);
+ fColors.push_back(kPenumbraColor);
int prevPenumbraIndex = 0;
fPositions.push_back(umbraPolygon[currUmbra]);
- fColors.push_back(fUmbraColor);
+ fColors.push_back(kUmbraColor);
fPrevUmbraIndex = 1;
indexMap[currUmbra] = 1;
@@ -598,11 +633,11 @@
if ((*umbraIndices)[nextUmbra] == (*penumbraIndices)[nextPenumbra]) {
// advance both one step
fPositions.push_back(penumbraPolygon[nextPenumbra]);
- fColors.push_back(fPenumbraColor);
+ fColors.push_back(kPenumbraColor);
int currPenumbraIndex = fPositions.count() - 1;
fPositions.push_back(umbraPolygon[nextUmbra]);
- fColors.push_back(fUmbraColor);
+ fColors.push_back(kUmbraColor);
int currUmbraIndex = fPositions.count() - 1;
indexMap[nextUmbra] = currUmbraIndex;
@@ -624,7 +659,7 @@
(*penumbraIndices)[nextPenumbra] <= maxPenumbraIndex) {
// fill out penumbra arc
fPositions.push_back(penumbraPolygon[nextPenumbra]);
- fColors.push_back(fPenumbraColor);
+ fColors.push_back(kPenumbraColor);
int currPenumbraIndex = fPositions.count() - 1;
this->appendTriangle(prevPenumbraIndex, currPenumbraIndex, fPrevUmbraIndex);
@@ -640,7 +675,7 @@
(*umbraIndices)[nextUmbra] <= maxUmbraIndex) {
// fill out umbra arc
fPositions.push_back(umbraPolygon[nextUmbra]);
- fColors.push_back(fUmbraColor);
+ fColors.push_back(kUmbraColor);
int currUmbraIndex = fPositions.count() - 1;
indexMap[nextUmbra] = currUmbraIndex;
@@ -655,11 +690,11 @@
}
// finish up by advancing both one step
fPositions.push_back(penumbraPolygon[nextPenumbra]);
- fColors.push_back(fPenumbraColor);
+ fColors.push_back(kPenumbraColor);
int currPenumbraIndex = fPositions.count() - 1;
fPositions.push_back(umbraPolygon[nextUmbra]);
- fColors.push_back(fUmbraColor);
+ fColors.push_back(kUmbraColor);
int currUmbraIndex = fPositions.count() - 1;
indexMap[nextUmbra] = currUmbraIndex;
@@ -800,14 +835,14 @@
currNormal.fX = prevNormal.fX*rotCos - prevNormal.fY*rotSin;
currNormal.fY = prevNormal.fY*rotCos + prevNormal.fX*rotSin;
fPositions.push_back(fPrevPoint + currNormal);
- fColors.push_back(fPenumbraColor);
+ fColors.push_back(kPenumbraColor);
this->appendTriangle(fPrevUmbraIndex, fPositions.count() - 1, fPositions.count() - 2);
prevNormal = currNormal;
}
if (finishArc && numSteps) {
fPositions.push_back(fPrevPoint + nextNormal);
- fColors.push_back(fPenumbraColor);
+ fColors.push_back(kPenumbraColor);
this->appendTriangle(fPrevUmbraIndex, fPositions.count() - 1, fPositions.count() - 2);
}
fPrevOutset = nextNormal;
@@ -846,8 +881,6 @@
private:
bool computePathPolygon(const SkPath& path, const SkMatrix& ctm);
- static constexpr auto kInsetFactor = 0.5f;
-
typedef SkBaseShadowTessellator INHERITED;
};
@@ -857,15 +890,10 @@
bool transparent)
: INHERITED(zPlaneParams, transparent) {
// Set base colors
- SkScalar baseZ = heightFunc(path.getBounds().centerX(), path.getBounds().centerY());
- SkScalar umbraAlpha = SkScalarInvert(SkDrawShadowMetrics::AmbientRecipAlpha(baseZ));
+ auto baseZ = heightFunc(path.getBounds().centerX(), path.getBounds().centerY());
// umbraColor is the interior value, penumbraColor the exterior value.
- // umbraAlpha is the factor that is linearly interpolated from outside to inside, and
- // then "blurred" by the GrBlurredEdgeFP. It is then multiplied by fAmbientAlpha to get
- // the final alpha.
- fUmbraColor = SkColorSetARGB(umbraAlpha * 255.9999f, 0, 0, 0);
- fPenumbraColor = SkColorSetARGB(0, 0, 0, 0);
- SkScalar outset = SkDrawShadowMetrics::AmbientBlurRadius(baseZ);
+ auto outset = SkDrawShadowMetrics::AmbientBlurRadius(baseZ);
+ auto inset = outset * SkDrawShadowMetrics::AmbientRecipAlpha(baseZ) - outset;
if (!this->computePathPolygon(path, ctm)) {
return;
@@ -885,9 +913,9 @@
fIndices.setReserve(12 * path.countPoints());
if (fIsConvex) {
- fSucceeded = this->computeConvexShadow(kInsetFactor, outset, false);
+ fSucceeded = this->computeConvexShadow(inset, outset, false);
} else {
- fSucceeded = this->computeConcaveShadow(kInsetFactor, outset);
+ fSucceeded = this->computeConcaveShadow(inset, outset);
}
}
@@ -961,8 +989,6 @@
// Set radius and colors
SkScalar occluderHeight = this->heightFunc(pathBounds.centerX(), pathBounds.centerY());
- fUmbraColor = SkColorSetARGB(255, 0, 0, 0);
- fPenumbraColor = SkColorSetARGB(0, 0, 0, 0);
// Compute the blur radius, scale and translation for the spot shadow.
SkScalar outset;
@@ -1056,33 +1082,6 @@
fIndices.setReserve(15 * path.countPoints());
if (fIsConvex) {
- SkScalar minDistSq = SkPointPriv::DistanceToLineSegmentBetweenSqd(fCentroid,
- fPathPolygon[0],
- fPathPolygon[1]);
- SkRect bounds;
- bounds.setBounds(&fPathPolygon[0], fPathPolygon.count());
- for (int i = 1; i < fPathPolygon.count(); ++i) {
- int j = i + 1;
- if (i == fPathPolygon.count() - 1) {
- j = 0;
- }
- SkPoint currPoint = fPathPolygon[i];
- SkPoint nextPoint = fPathPolygon[j];
- SkScalar distSq = SkPointPriv::DistanceToLineSegmentBetweenSqd(fCentroid, currPoint,
- nextPoint);
- if (distSq < minDistSq) {
- minDistSq = distSq;
- }
- }
- static constexpr auto kTolerance = 1.0e-2f;
- if (minDistSq < (inset + kTolerance)*(inset + kTolerance)) {
- // if the umbra would collapse, we back off a bit on inner blur and adjust the alpha
- SkScalar newInset = SkScalarSqrt(minDistSq) - kTolerance;
- SkScalar ratio = 128 * (newInset + inset) / inset;
- // they aren't PMColors, but the interpolation algorithm is the same
- fUmbraColor = SkPMLerp(fUmbraColor, fPenumbraColor, (unsigned)ratio);
- inset = newInset;
- }
fSucceeded = this->computeConvexShadow(inset, outset, true);
} else {
fSucceeded = this->computeConcaveShadow(inset, outset);