aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gm/shadowutils.cpp17
-rw-r--r--include/utils/SkShadowUtils.h74
-rw-r--r--samplecode/SampleAndroidShadows.cpp10
-rwxr-xr-xsamplecode/SampleShadowUtils.cpp16
-rw-r--r--src/utils/SkShadowUtils.cpp176
5 files changed, 105 insertions, 188 deletions
diff --git a/gm/shadowutils.cpp b/gm/shadowutils.cpp
index 53d9b78602..9d9eaae405 100644
--- a/gm/shadowutils.cpp
+++ b/gm/shadowutils.cpp
@@ -12,24 +12,17 @@
#include "SkShadowUtils.h"
void draw_shadow(SkCanvas* canvas, const SkPath& path, int height, SkColor color, SkPoint3 lightPos,
- SkScalar lightR, bool isAmbient, uint32_t flags, SkResourceCache* cache) {
+ SkScalar lightR, bool isAmbient, uint32_t flags) {
SkScalar ambientAlpha = isAmbient ? .5f : 0.f;
SkScalar spotAlpha = isAmbient ? 0.f : .5f;
SkShadowUtils::DrawShadow(canvas, path, height, lightPos, lightR, ambientAlpha, spotAlpha,
- color, flags, cache);
+ color, flags);
}
static constexpr int kW = 800;
static constexpr int kH = 800;
DEF_SIMPLE_GM(shadow_utils, canvas, kW, kH) {
- // SkShadowUtils uses a cache of SkVertices meshes. The vertices are created in a local
- // coordinate system and then translated when reused. The coordinate system depends on
- // parameters to the generating draw. If other threads are hitting the cache while this GM is
- // running then we may have different cache behavior leading to slight rendering differences.
- // To avoid that we use our own isolated cache rather than the global cache.
- SkResourceCache cache(1 << 20);
-
SkTArray<SkPath> paths;
paths.push_back().addRoundRect(SkRect::MakeWH(50, 50), 10, 10);
SkRRect oddRRect;
@@ -70,10 +63,8 @@ DEF_SIMPLE_GM(shadow_utils, canvas, kW, kH) {
canvas->save();
canvas->concat(m);
- draw_shadow(canvas, path, kHeight, SK_ColorRED, kLightPos, kLightR, true, flags,
- &cache);
- draw_shadow(canvas, path, kHeight, SK_ColorBLUE, kLightPos, kLightR, false, flags,
- &cache);
+ draw_shadow(canvas, path, kHeight, SK_ColorRED, kLightPos, kLightR, true, flags);
+ draw_shadow(canvas, path, kHeight, SK_ColorBLUE, kLightPos, kLightR, false, flags);
// Draw the path outline in green on top of the ambient and spot shadows.
SkPaint paint;
diff --git a/include/utils/SkShadowUtils.h b/include/utils/SkShadowUtils.h
index 4a497bb397..bf804a581f 100644
--- a/include/utils/SkShadowUtils.h
+++ b/include/utils/SkShadowUtils.h
@@ -21,12 +21,14 @@ class SkShadowUtils {
public:
/**
* Draw an offset spot shadow and outlining ambient shadow for the given path using a disc
- * light.
+ * light. The shadow may be cached, depending on the path type and canvas matrix. If the
+ * matrix is perspective or the path is volatile, it will not be cached.
*
* @param canvas The canvas on which to draw the shadows.
* @param path The occluder used to generate the shadows.
- * @param occluderHeight The vertical offset of the occluder from the canvas. This is
- * independent of the canvas's current matrix.
+ * @param zPlaneParams Values for the plane function which returns the Z offset of the
+ * occluder from the canvas based on local x and y values (the current matrix is not applied).
+ * If the canvas matrix is not perspective, then only zPlaneParams.fZ is used.
* @param lightPos The 3D position of the light relative to the canvas plane. This is
* independent of the canvas's current matrix.
* @param lightRadius The radius of the disc light.
@@ -35,20 +37,47 @@ public:
* @param color The shadow color.
* @param flags Options controlling opaque occluder optimizations and shadow appearance. See
* SkShadowFlags.
- * @param cache Used for testing purposes. Clients should pass nullptr (default).
*/
+ static void DrawShadow(SkCanvas* canvas, const SkPath& path, const SkPoint3& zPlaneParams,
+ const SkPoint3& lightPos, SkScalar lightRadius, SkScalar ambientAlpha,
+ SkScalar spotAlpha, SkColor color,
+ uint32_t flags = SkShadowFlags::kNone_ShadowFlag);
+
+ /**
+ * Draw an offset spot shadow and outlining ambient shadow for the given path using a disc
+ * light.
+ *
+ * Deprecated version with height value (to be removed when Android and Flutter are updated).
+ *
+ * @param canvas The canvas on which to draw the shadows.
+ * @param path The occluder used to generate the shadows.
+ * @param occluderHeight The vertical offset of the occluder from the canvas. This is
+ * independent of the canvas's current matrix.
+ * @param lightPos The 3D position of the light relative to the canvas plane. This is
+ * independent of the canvas's current matrix.
+ * @param lightRadius The radius of the disc light.
+ * @param ambientAlpha The maximum alpha of the ambient shadow.
+ * @param spotAlpha The maxium alpha of the spot shadow.
+ * @param color The shadow color.
+ * @param flags Options controlling opaque occluder optimizations and shadow appearance. See
+ * SkShadowFlags.
+ */
static void DrawShadow(SkCanvas* canvas, const SkPath& path, SkScalar occluderHeight,
const SkPoint3& lightPos, SkScalar lightRadius, SkScalar ambientAlpha,
SkScalar spotAlpha, SkColor color,
- uint32_t flags = SkShadowFlags::kNone_ShadowFlag,
- SkResourceCache* cache = nullptr);
+ uint32_t flags = SkShadowFlags::kNone_ShadowFlag) {
+ SkPoint3 zPlane = SkPoint3::Make(0, 0, occluderHeight);
+ DrawShadow(canvas, path, zPlane, lightPos, lightRadius, ambientAlpha, spotAlpha,
+ color, flags);
+ }
+#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
/**
* Draw an offset spot shadow and outlining ambient shadow for the given path using a disc
* light. Takes a function to vary the z value based on the local x and y position.
* This shadow will not be cached, as the assumption is that this will be used for animation.
*
- * Deprecated version with height functor (to be removed when Android is updated).
+ * Deprecated (to be removed when Android is updated).
*
* @param canvas The canvas on which to draw the shadows.
* @param path The occluder used to generate the shadows.
@@ -73,35 +102,10 @@ public:
zPlane.fX = heightFunc(1, 0) - zPlane.fZ;
zPlane.fY = heightFunc(0, 1) - zPlane.fZ;
- DrawUncachedShadow(canvas, path, zPlane, lightPos, lightRadius, ambientAlpha, spotAlpha,
- color, flags);
+ DrawShadow(canvas, path, zPlane, lightPos, lightRadius, ambientAlpha, spotAlpha,
+ color, flags);
}
-
- /**
- * Draw an offset spot shadow and outlining ambient shadow for the given path using a disc
- * light. Uses a plane function to vary the z value based on the local x and y position.
- * This shadow will not be cached, as the assumption is that this will be used for animation.
- *
- * @param canvas The canvas on which to draw the shadows.
- * @param path The occluder used to generate the shadows.
- * @param zPlaneParams Values for the plane function which returns the Z offset of the
- * occluder from the canvas based on local x and y values (the current matrix is not applied).
- * @param lightPos The 3D position of the light relative to the canvas plane. This is
- * independent of the canvas's current matrix.
- * @param lightRadius The radius of the disc light.
- * @param ambientAlpha The maximum alpha of the ambient shadow.
- * @param spotAlpha The maxium alpha of the spot shadow.
- * @param color The shadow color.
- * @param flags Options controlling opaque occluder optimizations and shadow appearance. See
- * SkShadowFlags.
- */
- static void DrawUncachedShadow(SkCanvas* canvas, const SkPath& path,
- const SkPoint3& zPlaneParams,
- const SkPoint3& lightPos, SkScalar lightRadius,
- SkScalar ambientAlpha, SkScalar spotAlpha, SkColor color,
- uint32_t flags = SkShadowFlags::kNone_ShadowFlag);
-
-
+#endif
};
#endif
diff --git a/samplecode/SampleAndroidShadows.cpp b/samplecode/SampleAndroidShadows.cpp
index 81dc0cc2b6..5b070642bb 100644
--- a/samplecode/SampleAndroidShadows.cpp
+++ b/samplecode/SampleAndroidShadows.cpp
@@ -145,13 +145,9 @@ protected:
if (fUseAlt) {
flags |= SkShadowFlags::kGeometricOnly_ShadowFlag;
}
- //SkShadowUtils::DrawShadow(canvas, path,
- // zValue,
- // lightPos, lightWidth,
- // ambientAlpha, spotAlpha, SK_ColorBLACK, flags);
- SkShadowUtils::DrawUncachedShadow(canvas, path, zPlaneParams,
- lightPos, lightWidth,
- ambientAlpha, spotAlpha, SK_ColorBLACK, flags);
+ SkShadowUtils::DrawShadow(canvas, path, zPlaneParams,
+ lightPos, lightWidth,
+ ambientAlpha, spotAlpha, SK_ColorBLACK, flags);
if (fShowObject) {
canvas->drawPath(path, paint);
diff --git a/samplecode/SampleShadowUtils.cpp b/samplecode/SampleShadowUtils.cpp
index 6d047be93d..e3838116f2 100755
--- a/samplecode/SampleShadowUtils.cpp
+++ b/samplecode/SampleShadowUtils.cpp
@@ -126,16 +126,12 @@ protected:
if (fUseAlt) {
flags |= SkShadowFlags::kGeometricOnly_ShadowFlag;
}
- //SkShadowUtils::DrawShadow(canvas, path,
- // zValue,
- // lightPos, lightWidth,
- // ambientAlpha, spotAlpha, SK_ColorBLACK, flags);
- SkShadowUtils::DrawUncachedShadow(canvas, path, zPlaneParams,
- lightPos, lightWidth,
- ambientAlpha, 0, SK_ColorRED, flags);
- SkShadowUtils::DrawUncachedShadow(canvas, path, zPlaneParams,
- lightPos, lightWidth,
- 0, spotAlpha, SK_ColorBLUE, flags);
+ SkShadowUtils::DrawShadow(canvas, path, zPlaneParams,
+ lightPos, lightWidth,
+ ambientAlpha, 0, SK_ColorRED, flags);
+ SkShadowUtils::DrawShadow(canvas, path, zPlaneParams,
+ lightPos, lightWidth,
+ 0, spotAlpha, SK_ColorBLUE, flags);
if (fShowObject) {
canvas->drawPath(path, paint);
diff --git a/src/utils/SkShadowUtils.cpp b/src/utils/SkShadowUtils.cpp
index c095acfb08..caf918e4f2 100644
--- a/src/utils/SkShadowUtils.cpp
+++ b/src/utils/SkShadowUtils.cpp
@@ -441,8 +441,7 @@ static void* kNamespace;
* they are first found in SkResourceCache.
*/
template <typename FACTORY>
-void draw_shadow(const FACTORY& factory, SkCanvas* canvas, ShadowedPath& path, SkColor color,
- SkResourceCache* cache) {
+void draw_shadow(const FACTORY& factory, SkCanvas* canvas, ShadowedPath& path, SkColor color) {
FindContext<FACTORY> context(&path.viewMatrix(), &factory);
SkResourceCache::Key* key = nullptr;
@@ -453,11 +452,7 @@ void draw_shadow(const FACTORY& factory, SkCanvas* canvas, ShadowedPath& path, S
key = new (keyStorage.begin()) SkResourceCache::Key();
path.writeKey((uint32_t*)(keyStorage.begin() + sizeof(*key)));
key->init(&kNamespace, resource_cache_shared_id(), keyDataBytes);
- if (cache) {
- cache->find(*key, FindVisitor<FACTORY>, &context);
- } else {
- SkResourceCache::Find(*key, FindVisitor<FACTORY>, &context);
- }
+ SkResourceCache::Find(*key, FindVisitor<FACTORY>, &context);
}
sk_sp<SkVertices> vertices;
@@ -482,11 +477,7 @@ void draw_shadow(const FACTORY& factory, SkCanvas* canvas, ShadowedPath& path, S
return;
}
auto rec = new CachedTessellationsRec(*key, std::move(tessellations));
- if (cache) {
- cache->add(rec);
- } else {
- SkResourceCache::Add(rec);
- }
+ SkResourceCache::Add(rec);
} else {
vertices = factory.makeVertices(path.path(), path.viewMatrix());
if (!vertices) {
@@ -585,13 +576,13 @@ static SkColor compute_render_color(SkColor color, float alpha) {
}
// Draw an offset spot shadow and outlining ambient shadow for the given path.
-void SkShadowUtils::DrawShadow(SkCanvas* canvas, const SkPath& path, SkScalar occluderHeight,
+void SkShadowUtils::DrawShadow(SkCanvas* canvas, const SkPath& path, const SkPoint3& zPlaneParams,
const SkPoint3& devLightPos, SkScalar lightRadius,
SkScalar ambientAlpha, SkScalar spotAlpha, SkColor color,
- uint32_t flags, SkResourceCache* cache) {
+ uint32_t flags) {
// try fast paths
bool skipAnalytic = SkToBool(flags & SkShadowFlags::kGeometricOnly_ShadowFlag);
- if (!skipAnalytic && draw_analytic_shadows(canvas, path, occluderHeight, devLightPos,
+ if (!skipAnalytic && draw_analytic_shadows(canvas, path, zPlaneParams.fZ, devLightPos,
lightRadius, ambientAlpha, spotAlpha, color,
flags)) {
return;
@@ -604,124 +595,63 @@ void SkShadowUtils::DrawShadow(SkCanvas* canvas, const SkPath& path, SkScalar oc
ShadowedPath shadowedPath(&path, &viewMatrix);
bool transparent = SkToBool(flags & SkShadowFlags::kTransparentOccluder_ShadowFlag);
+ bool uncached = viewMatrix.hasPerspective() || path.isVolatile();
if (ambientAlpha > 0) {
ambientAlpha = SkTMin(ambientAlpha, 1.f);
- AmbientVerticesFactory factory;
- factory.fOccluderHeight = occluderHeight;
- factory.fTransparent = transparent;
+ if (uncached) {
+ sk_sp<SkVertices> vertices = SkShadowTessellator::MakeAmbient(path, viewMatrix,
+ zPlaneParams,
+ transparent);
+ SkColor renderColor = compute_render_color(color, ambientAlpha);
+ SkPaint paint;
+ // Run the vertex color through a GaussianColorFilter and then modulate the grayscale
+ // result of that against our 'color' param.
+ paint.setColorFilter(SkColorFilter::MakeComposeFilter(
+ SkColorFilter::MakeModeFilter(renderColor, SkBlendMode::kModulate),
+ SkGaussianColorFilter::Make()));
+ canvas->drawVertices(vertices, SkBlendMode::kModulate, paint);
+ } else {
+ AmbientVerticesFactory factory;
+ factory.fOccluderHeight = zPlaneParams.fZ;
+ factory.fTransparent = transparent;
- SkColor renderColor = compute_render_color(color, ambientAlpha);
- draw_shadow(factory, canvas, shadowedPath, renderColor, cache);
+ SkColor renderColor = compute_render_color(color, ambientAlpha);
+ draw_shadow(factory, canvas, shadowedPath, renderColor);
+ }
}
if (spotAlpha > 0) {
spotAlpha = SkTMin(spotAlpha, 1.f);
- SpotVerticesFactory factory;
- float zRatio = SkTPin(occluderHeight / (devLightPos.fZ - occluderHeight), 0.0f, 0.95f);
- SkScalar radius = lightRadius * zRatio;
-
- // Compute the scale and translation for the spot shadow.
- SkScalar scale = devLightPos.fZ / (devLightPos.fZ - occluderHeight);
-
- SkPoint center = SkPoint::Make(path.getBounds().centerX(), path.getBounds().centerY());
- viewMatrix.mapPoints(&center, 1);
- factory.fOffset = SkVector::Make(zRatio * (center.fX - devLightPos.fX),
- zRatio * (center.fY - devLightPos.fY));
- factory.fOccluderHeight = occluderHeight;
- factory.fDevLightPos = devLightPos;
- factory.fLightRadius = lightRadius;
-
- SkRRect rrect;
- if (transparent) {
- factory.fOccluderType = SpotVerticesFactory::OccluderType::kTransparent;
+ if (uncached) {
+ sk_sp<SkVertices> vertices = SkShadowTessellator::MakeSpot(path, viewMatrix,
+ zPlaneParams,
+ devLightPos, lightRadius,
+ transparent);
+ SkColor renderColor = compute_render_color(color, spotAlpha);
+ SkPaint paint;
+ // Run the vertex color through a GaussianColorFilter and then modulate the grayscale
+ // result of that against our 'color' param.
+ paint.setColorFilter(SkColorFilter::MakeComposeFilter(
+ SkColorFilter::MakeModeFilter(renderColor, SkBlendMode::kModulate),
+ SkGaussianColorFilter::Make()));
+ canvas->drawVertices(vertices, SkBlendMode::kModulate, paint);
} else {
- factory.fOccluderType = SpotVerticesFactory::OccluderType::kOpaque;
- if (shadowedPath.isRRect(&rrect)) {
- SkRRect devRRect;
- if (rrect.transform(viewMatrix, &devRRect)) {
- SkScalar s = 1.f - scale;
- SkScalar w = devRRect.width();
- SkScalar h = devRRect.height();
- SkScalar hw = w / 2.f;
- SkScalar hh = h / 2.f;
- SkScalar umbraInsetX = s * hw + radius;
- SkScalar umbraInsetY = s * hh + radius;
- // The umbra is inset by radius along the diagonal, so adjust for that.
- SkScalar d = 1.f / SkScalarSqrt(hw * hw + hh * hh);
- umbraInsetX *= hw * d;
- umbraInsetY *= hh * d;
- if (umbraInsetX > hw || umbraInsetY > hh) {
- // There is no umbra to occlude.
- factory.fOccluderType = SpotVerticesFactory::OccluderType::kTransparent;
- } else if (fabsf(factory.fOffset.fX) < umbraInsetX &&
- fabsf(factory.fOffset.fY) < umbraInsetY) {
- factory.fOccluderType =
- SpotVerticesFactory::OccluderType::kOpaqueCoversUmbra;
- } else if (factory.fOffset.fX > w - umbraInsetX ||
- factory.fOffset.fY > h - umbraInsetY) {
- // There umbra is fully exposed, there is nothing to omit.
- factory.fOccluderType = SpotVerticesFactory::OccluderType::kTransparent;
- }
- }
- }
- }
- if (factory.fOccluderType == SpotVerticesFactory::OccluderType::kOpaque) {
+ SpotVerticesFactory factory;
+ SkScalar occluderHeight = zPlaneParams.fZ;
+ float zRatio = SkTPin(occluderHeight / (devLightPos.fZ - occluderHeight), 0.0f, 0.95f);
+ SkPoint center = SkPoint::Make(path.getBounds().centerX(), path.getBounds().centerY());
+ viewMatrix.mapPoints(&center, 1);
+ factory.fOffset = SkVector::Make(zRatio * (center.fX - devLightPos.fX),
+ zRatio * (center.fY - devLightPos.fY));
+ factory.fOccluderHeight = occluderHeight;
+ factory.fDevLightPos = devLightPos;
+ factory.fLightRadius = lightRadius;
+ // the only valid choice we have right now
factory.fOccluderType = SpotVerticesFactory::OccluderType::kTransparent;
- }
-
- SkColor renderColor = compute_render_color(color, spotAlpha);
- draw_shadow(factory, canvas, shadowedPath, renderColor, cache);
- }
-}
-// Draw an offset spot shadow and outlining ambient shadow for the given path,
-// without caching and using a function based on local position to compute the height.
-void SkShadowUtils::DrawUncachedShadow(SkCanvas* canvas, const SkPath& path,
- const SkPoint3& zPlaneParams,
- const SkPoint3& lightPos, SkScalar lightRadius,
- SkScalar ambientAlpha, SkScalar spotAlpha, SkColor color,
- uint32_t flags) {
- // try fast paths
- bool skipAnalytic = SkToBool(flags & SkShadowFlags::kGeometricOnly_ShadowFlag);
- if (!skipAnalytic && draw_analytic_shadows(canvas, path, zPlaneParams.fZ, lightPos,
- lightRadius, ambientAlpha, spotAlpha, color,
- flags)) {
- return;
- }
-
- SkAutoCanvasRestore acr(canvas, true);
- SkMatrix viewMatrix = canvas->getTotalMatrix();
- canvas->resetMatrix();
-
- bool transparent = SkToBool(flags & SkShadowFlags::kTransparentOccluder_ShadowFlag);
-
- if (ambientAlpha > 0) {
- ambientAlpha = SkTMin(ambientAlpha, 1.f);
- sk_sp<SkVertices> vertices = SkShadowTessellator::MakeAmbient(path, viewMatrix,
- zPlaneParams, transparent);
- SkColor renderColor = compute_render_color(color, ambientAlpha);
- SkPaint paint;
- // Run the vertex color through a GaussianColorFilter and then modulate the grayscale
- // result of that against our 'color' param.
- paint.setColorFilter(SkColorFilter::MakeComposeFilter(
- SkColorFilter::MakeModeFilter(renderColor, SkBlendMode::kModulate),
- SkGaussianColorFilter::Make()));
- canvas->drawVertices(vertices, SkBlendMode::kModulate, paint);
- }
-
- if (spotAlpha > 0) {
- spotAlpha = SkTMin(spotAlpha, 1.f);
- sk_sp<SkVertices> vertices = SkShadowTessellator::MakeSpot(path, viewMatrix, zPlaneParams,
- lightPos, lightRadius,
- transparent);
- SkColor renderColor = compute_render_color(color, spotAlpha);
- SkPaint paint;
- // Run the vertex color through a GaussianColorFilter and then modulate the grayscale
- // result of that against our 'color' param.
- paint.setColorFilter(SkColorFilter::MakeComposeFilter(
- SkColorFilter::MakeModeFilter(renderColor, SkBlendMode::kModulate),
- SkGaussianColorFilter::Make()));
- canvas->drawVertices(vertices, SkBlendMode::kModulate, paint);
+ SkColor renderColor = compute_render_color(color, spotAlpha);
+ draw_shadow(factory, canvas, shadowedPath, renderColor);
+ }
}
}