aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Jim Van Verth <jvanverth@google.com>2017-01-16 13:03:37 -0500
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2017-01-16 18:40:59 +0000
commit2103cf0ff09763aeaa35508734f765aec9b75665 (patch)
tree444b8499ced29fa07554ea14f0f1fb30afb509e7
parentac04fef619ad3939a25e66bdaef6f6b1e7f5ca50 (diff)
Split ShadowMaskFilter into separate ambient and spot mask filters
This does not change the public API. BUG=skia:6119 Change-Id: Ibdcd2f8611bc2eec332d8a65e5d51246b89a0a90 Reviewed-on: https://skia-review.googlesource.com/7083 Commit-Queue: Jim Van Verth <jvanverth@google.com> Reviewed-by: Jim Van Verth <jvanverth@google.com> Reviewed-by: Robert Phillips <robertphillips@google.com>
-rw-r--r--gn/core.gni1
-rw-r--r--gn/effects.gni7
-rwxr-xr-xinclude/private/SkShadowFlags.h25
-rwxr-xr-xinclude/utils/SkShadowUtils.h16
-rwxr-xr-xsrc/effects/SkShadowMaskFilter.h51
-rwxr-xr-xsrc/effects/shadows/SkAmbientShadowMaskFilter.cpp290
-rwxr-xr-xsrc/effects/shadows/SkAmbientShadowMaskFilter.h33
-rwxr-xr-xsrc/effects/shadows/SkSpotShadowMaskFilter.cpp (renamed from src/effects/SkShadowMaskFilter.cpp)162
-rwxr-xr-xsrc/effects/shadows/SkSpotShadowMaskFilter.h37
-rwxr-xr-xsrc/utils/SkShadowUtils.cpp10
10 files changed, 459 insertions, 173 deletions
diff --git a/gn/core.gni b/gn/core.gni
index 432526364e..e3ace0285a 100644
--- a/gn/core.gni
+++ b/gn/core.gni
@@ -457,6 +457,7 @@ skia_core_sources = [
"$_include/private/SkOnce.h",
"$_include/private/SkRecords.h",
"$_include/private/SkSemaphore.h",
+ "$_include/private/SkShadowFlags.h",
"$_include/private/SkShadowParams.h",
"$_include/private/SkSpinlock.h",
"$_include/private/SkTemplates.h",
diff --git a/gn/effects.gni b/gn/effects.gni
index b8bc2b16cc..b1a49c502f 100644
--- a/gn/effects.gni
+++ b/gn/effects.gni
@@ -58,8 +58,6 @@ skia_effects_sources = [
"$_src/effects/SkPerlinNoiseShader.cpp",
"$_src/effects/SkPictureImageFilter.cpp",
"$_src/effects/SkRRectsGaussianEdgeMaskFilter.cpp",
- "$_src/effects/SkShadowMaskFilter.cpp",
- "$_src/effects/SkShadowMaskFilter.h",
"$_src/effects/SkTableColorFilter.cpp",
"$_src/effects/SkTableMaskFilter.cpp",
"$_src/effects/SkTileImageFilter.cpp",
@@ -87,6 +85,11 @@ skia_effects_sources = [
"$_src/effects/gradients/SkSweepGradient.cpp",
"$_src/effects/gradients/SkSweepGradient.h",
+ "$_src/effects/shadows/SkAmbientShadowMaskFilter.cpp",
+ "$_src/effects/shadows/SkAmbientShadowMaskFilter.h",
+ "$_src/effects/shadows/SkSpotShadowMaskFilter.cpp",
+ "$_src/effects/shadows/SkSpotShadowMaskFilter.h",
+
"$_include/effects/Sk1DPathEffect.h",
"$_include/effects/Sk2DPathEffect.h",
"$_include/effects/SkAlphaThresholdFilter.h",
diff --git a/include/private/SkShadowFlags.h b/include/private/SkShadowFlags.h
new file mode 100755
index 0000000000..0caa01060d
--- /dev/null
+++ b/include/private/SkShadowFlags.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkShadowFlags_DEFINED
+#define SkShadowFlags_DEFINED
+
+// A set of flags shared between the SkAmbientShadowMaskFilter and the SkSpotShadowMaskFilter
+enum SkShadowFlags {
+ kNone_ShadowFlag = 0x00,
+ /** The occluding object is not opaque. Knowing that the occluder is opaque allows
+ * us to cull shadow geometry behind it and improve performance. */
+ kTransparentOccluder_ShadowFlag = 0x01,
+ /** Use a larger umbra for a darker shadow */
+ kLargerUmbra_ShadowFlag = 0x02,
+ /** Use a Gaussian for the edge function rather than smoothstep */
+ kGaussianEdge_ShadowFlag = 0x04,
+ /** mask for all shadow flags */
+ kAll_ShadowFlag = 0x07
+};
+
+#endif
diff --git a/include/utils/SkShadowUtils.h b/include/utils/SkShadowUtils.h
index c3809295fb..795c2cf2ce 100755
--- a/include/utils/SkShadowUtils.h
+++ b/include/utils/SkShadowUtils.h
@@ -10,30 +10,18 @@
#include "SkColor.h"
#include "SkScalar.h"
+#include "../private/SkShadowFlags.h"
class SkCanvas;
class SkPath;
class SkShadowUtils {
public:
- enum ShadowFlags {
- kNone_ShadowFlag = 0x00,
- /** The occluding object is not opaque. Knowing that the occluder is opaque allows
- * us to cull shadow geometry behind it and improve performance. */
- kTransparentOccluder_ShadowFlag = 0x01,
- /** Use a larger umbra for a darker shadow */
- kLargerUmbra_ShadowFlag = 0x02,
- /** Use a Gaussian for the edge function rather than smoothstep */
- kGaussianEdge_ShadowFlag = 0x04,
- /** mask for all shadow flags */
- kAll_ShadowFlag = 0x07
- };
-
// Draw an offset spot shadow and outlining ambient shadow for the given path.
static void DrawShadow(SkCanvas*, const SkPath& path, SkScalar occluderHeight,
const SkPoint3& lightPos, SkScalar lightRadius,
SkScalar ambientAlpha, SkScalar spotAlpha, SkColor color,
- uint32_t flags = kNone_ShadowFlag);
+ uint32_t flags = SkShadowFlags::kNone_ShadowFlag);
};
#endif
diff --git a/src/effects/SkShadowMaskFilter.h b/src/effects/SkShadowMaskFilter.h
deleted file mode 100755
index a85da63db9..0000000000
--- a/src/effects/SkShadowMaskFilter.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright 2016 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef SkShadowMaskFilter_DEFINED
-#define SkShadowMaskFilter_DEFINED
-
-#include "SkMaskFilter.h"
-
-
-/*
- * This filter implements a pair of shadows for an occluding object-- one representing
- * ambient occlusion, and one representing a displaced shadow from a point light.
- */
-class SK_API SkShadowMaskFilter {
-public:
- enum ShadowFlags {
- kNone_ShadowFlag = 0x00,
- /** The occluding object is not opaque. Knowing that the occluder is opaque allows
- * us to cull shadow geometry behind it and improve performance. */
- kTransparentOccluder_ShadowFlag = 0x01,
- /** Use a larger umbra for a darker shadow */
- kLargerUmbra_ShadowFlag = 0x02,
- /** Use a Gaussian for the edge function rather than smoothstep */
- kGaussianEdge_ShadowFlag = 0x04,
- /** mask for all shadow flags */
- kAll_ShadowFlag = 0x07
- };
-
- /** Create a shadow maskfilter.
- * @param occluderHeight Height of occluding object off of ground plane.
- * @param lightPos Position of the light applied to this object.
- * @param lightRadius Radius of the light (light is assumed to be spherical).
- * @param ambientAlpha Base opacity of the ambient occlusion shadow.
- * @param spotAlpha Base opacity of the displaced spot shadow.
- * @param flags Flags to use - defaults to none
- * @return The new shadow maskfilter
- */
- static sk_sp<SkMaskFilter> Make(SkScalar occluderHeight, const SkPoint3& lightPos,
- SkScalar lightRadius, SkScalar ambientAlpha,
- SkScalar spotAlpha, uint32_t flags = kNone_ShadowFlag);
-
- SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP()
-
-private:
- SkShadowMaskFilter(); // can't be instantiated
-};
-#endif
diff --git a/src/effects/shadows/SkAmbientShadowMaskFilter.cpp b/src/effects/shadows/SkAmbientShadowMaskFilter.cpp
new file mode 100755
index 0000000000..3dfd84eedc
--- /dev/null
+++ b/src/effects/shadows/SkAmbientShadowMaskFilter.cpp
@@ -0,0 +1,290 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkAmbientShadowMaskFilter.h"
+#include "SkReadBuffer.h"
+#include "SkStringUtils.h"
+#include "SkWriteBuffer.h"
+
+#if SK_SUPPORT_GPU
+#include "GrContext.h"
+#include "GrRenderTargetContext.h"
+#include "GrFragmentProcessor.h"
+#include "GrInvariantOutput.h"
+#include "GrStyle.h"
+#include "GrTexture.h"
+#include "GrTextureProxy.h"
+#include "glsl/GrGLSLFragmentProcessor.h"
+#include "glsl/GrGLSLFragmentShaderBuilder.h"
+#include "glsl/GrGLSLProgramDataManager.h"
+#include "glsl/GrGLSLUniformHandler.h"
+#include "SkStrokeRec.h"
+#endif
+
+class SkAmbientShadowMaskFilterImpl : public SkMaskFilter {
+public:
+ SkAmbientShadowMaskFilterImpl(SkScalar occluderHeight, SkScalar ambientAlpha, uint32_t flags);
+
+ // overrides from SkMaskFilter
+ SkMask::Format getFormat() const override;
+ bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix&,
+ SkIPoint* margin) const override;
+
+#if SK_SUPPORT_GPU
+ bool canFilterMaskGPU(const SkRRect& devRRect,
+ const SkIRect& clipBounds,
+ const SkMatrix& ctm,
+ SkRect* maskRect) const override;
+ bool directFilterMaskGPU(GrTextureProvider* texProvider,
+ GrRenderTargetContext* drawContext,
+ GrPaint&&,
+ const GrClip&,
+ const SkMatrix& viewMatrix,
+ const SkStrokeRec& strokeRec,
+ const SkPath& path) const override;
+ bool directFilterRRectMaskGPU(GrContext*,
+ GrRenderTargetContext* drawContext,
+ GrPaint&&,
+ const GrClip&,
+ const SkMatrix& viewMatrix,
+ const SkStrokeRec& strokeRec,
+ const SkRRect& rrect,
+ const SkRRect& devRRect) const override;
+ sk_sp<GrTextureProxy> filterMaskGPU(GrContext*,
+ sk_sp<GrTextureProxy> srcProxy,
+ const SkMatrix& ctm,
+ const SkIRect& maskRect) const override;
+#endif
+
+ void computeFastBounds(const SkRect&, SkRect*) const override;
+
+ SK_TO_STRING_OVERRIDE()
+ SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkAmbientShadowMaskFilterImpl)
+
+private:
+ SkScalar fOccluderHeight;
+ SkScalar fAmbientAlpha;
+ uint32_t fFlags;
+
+ SkAmbientShadowMaskFilterImpl(SkReadBuffer&);
+ void flatten(SkWriteBuffer&) const override;
+
+ friend class SkAmbientShadowMaskFilter;
+
+ typedef SkMaskFilter INHERITED;
+};
+
+sk_sp<SkMaskFilter> SkAmbientShadowMaskFilter::Make(SkScalar occluderHeight, SkScalar ambientAlpha,
+ uint32_t flags) {
+ // add some param checks here for early exit
+
+ return sk_sp<SkMaskFilter>(new SkAmbientShadowMaskFilterImpl(occluderHeight, ambientAlpha,
+ flags));
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+SkAmbientShadowMaskFilterImpl::SkAmbientShadowMaskFilterImpl(SkScalar occluderHeight,
+ SkScalar ambientAlpha,
+ uint32_t flags)
+ : fOccluderHeight(occluderHeight)
+ , fAmbientAlpha(ambientAlpha)
+ , fFlags(flags) {
+ SkASSERT(fOccluderHeight > 0);
+ SkASSERT(fAmbientAlpha >= 0);
+}
+
+SkMask::Format SkAmbientShadowMaskFilterImpl::getFormat() const {
+ return SkMask::kA8_Format;
+}
+
+bool SkAmbientShadowMaskFilterImpl::filterMask(SkMask* dst, const SkMask& src,
+ const SkMatrix& matrix,
+ SkIPoint* margin) const {
+ // TODO something
+ return false;
+}
+
+void SkAmbientShadowMaskFilterImpl::computeFastBounds(const SkRect& src, SkRect* dst) const {
+ // TODO compute based on ambient data
+ dst->set(src.fLeft, src.fTop, src.fRight, src.fBottom);
+}
+
+sk_sp<SkFlattenable> SkAmbientShadowMaskFilterImpl::CreateProc(SkReadBuffer& buffer) {
+ const SkScalar occluderHeight = buffer.readScalar();
+ const SkScalar ambientAlpha = buffer.readScalar();
+ const uint32_t flags = buffer.readUInt();
+
+ return SkAmbientShadowMaskFilter::Make(occluderHeight, ambientAlpha, flags);
+}
+
+void SkAmbientShadowMaskFilterImpl::flatten(SkWriteBuffer& buffer) const {
+ buffer.writeScalar(fOccluderHeight);
+ buffer.writeScalar(fAmbientAlpha);
+ buffer.writeUInt(fFlags);
+}
+
+#if SK_SUPPORT_GPU
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+bool SkAmbientShadowMaskFilterImpl::canFilterMaskGPU(const SkRRect& devRRect,
+ const SkIRect& clipBounds,
+ const SkMatrix& ctm,
+ SkRect* maskRect) const {
+ // TODO
+ *maskRect = devRRect.rect();
+ return true;
+}
+
+bool SkAmbientShadowMaskFilterImpl::directFilterMaskGPU(GrTextureProvider* texProvider,
+ GrRenderTargetContext* drawContext,
+ GrPaint&& paint,
+ const GrClip& clip,
+ const SkMatrix& viewMatrix,
+ const SkStrokeRec& strokeRec,
+ const SkPath& path) const {
+ SkASSERT(drawContext);
+ // TODO: this will not handle local coordinates properly
+
+ // if circle
+ // TODO: switch to SkScalarNearlyEqual when either oval renderer is updated or we
+ // have our own GeometryProc.
+ if (path.isOval(nullptr) && path.getBounds().width() == path.getBounds().height()) {
+ SkRRect rrect = SkRRect::MakeOval(path.getBounds());
+ return this->directFilterRRectMaskGPU(nullptr, drawContext, std::move(paint), clip,
+ SkMatrix::I(), strokeRec, rrect, rrect);
+ } else if (path.isRect(nullptr)) {
+ SkRRect rrect = SkRRect::MakeRect(path.getBounds());
+ return this->directFilterRRectMaskGPU(nullptr, drawContext, std::move(paint), clip,
+ SkMatrix::I(), strokeRec, rrect, rrect);
+ }
+
+ // TODO
+ return false;
+}
+
+bool SkAmbientShadowMaskFilterImpl::directFilterRRectMaskGPU(GrContext*,
+ GrRenderTargetContext* rtContext,
+ GrPaint&& paint,
+ const GrClip& clip,
+ const SkMatrix& viewMatrix,
+ const SkStrokeRec& strokeRec,
+ const SkRRect& rrect,
+ const SkRRect& devRRect) const {
+ // It's likely the caller has already done these checks, but we have to be sure.
+ // TODO: support analytic blurring of general rrect
+
+ // Fast path only supports filled rrects for now.
+ // TODO: fill and stroke as well.
+ if (SkStrokeRec::kFill_Style != strokeRec.getStyle()) {
+ return false;
+ }
+ // Fast path only supports simple rrects with circular corners.
+ SkASSERT(devRRect.allCornersCircular());
+ if (!rrect.isRect() && !rrect.isOval() && !rrect.isSimple()) {
+ return false;
+ }
+ // Fast path only supports uniform scale.
+ SkScalar scaleFactors[2];
+ if (!viewMatrix.getMinMaxScales(scaleFactors)) {
+ // matrix is degenerate
+ return false;
+ }
+ if (scaleFactors[0] != scaleFactors[1]) {
+ return false;
+ }
+ SkScalar scaleFactor = scaleFactors[0];
+
+ // For all of these, we need to ensure we have a rrect with radius >= 0.5f in device space
+ const SkScalar minRadius = 0.5f / scaleFactor;
+ bool isRect = rrect.getSimpleRadii().fX <= minRadius;
+
+ // TODO: take flags into account when generating shadow data
+
+ if (fAmbientAlpha > 0.0f) {
+ static const float kHeightFactor = 1.0f / 128.0f;
+ static const float kGeomFactor = 64.0f;
+
+ SkScalar srcSpaceAmbientRadius = fOccluderHeight * kHeightFactor * kGeomFactor;
+ const float umbraAlpha = (1.0f + SkTMax(fOccluderHeight * kHeightFactor, 0.0f));
+ const SkScalar ambientOffset = srcSpaceAmbientRadius * umbraAlpha;
+
+ // For the ambient rrect, we inset the offset rect by half the srcSpaceAmbientRadius
+ // to get our stroke shape.
+ SkScalar ambientPathOutset = SkTMax(ambientOffset - srcSpaceAmbientRadius * 0.5f,
+ minRadius);
+
+ SkRRect ambientRRect;
+ if (isRect) {
+ const SkRect temp = rrect.rect().makeOutset(ambientPathOutset, ambientPathOutset);
+ ambientRRect = SkRRect::MakeRectXY(temp, ambientPathOutset, ambientPathOutset);
+ } else {
+ rrect.outset(ambientPathOutset, ambientPathOutset, &ambientRRect);
+ }
+
+ const SkScalar devSpaceAmbientRadius = srcSpaceAmbientRadius * scaleFactor;
+
+ GrPaint newPaint(paint);
+ GrColor4f color = newPaint.getColor4f();
+ color.fRGBA[3] *= fAmbientAlpha;
+ newPaint.setColor4f(color);
+ SkStrokeRec ambientStrokeRec(SkStrokeRec::kHairline_InitStyle);
+ ambientStrokeRec.setStrokeStyle(srcSpaceAmbientRadius, false);
+
+ rtContext->drawShadowRRect(clip, std::move(newPaint), viewMatrix, ambientRRect,
+ devSpaceAmbientRadius,
+ GrStyle(ambientStrokeRec, nullptr));
+ }
+
+ return true;
+}
+
+sk_sp<GrTextureProxy> SkAmbientShadowMaskFilterImpl::filterMaskGPU(GrContext*,
+ sk_sp<GrTextureProxy> srcProxy,
+ const SkMatrix& ctm,
+ const SkIRect& maskRect) const {
+ // This filter is generative and doesn't operate on pre-existing masks
+ return nullptr;
+}
+
+#endif
+
+#ifndef SK_IGNORE_TO_STRING
+void SkAmbientShadowMaskFilterImpl::toString(SkString* str) const {
+ str->append("SkAmbientShadowMaskFilterImpl: (");
+
+ str->append("occluderHeight: ");
+ str->appendScalar(fOccluderHeight);
+ str->append(" ");
+
+ str->append("ambientAlpha: ");
+ str->appendScalar(fAmbientAlpha);
+ str->append(" ");
+
+ str->append("flags: (");
+ if (fFlags) {
+ bool needSeparator = false;
+ SkAddFlagToString(str,
+ SkToBool(fFlags & SkShadowFlags::kTransparentOccluder_ShadowFlag),
+ "TransparentOccluder", &needSeparator);
+ SkAddFlagToString(str,
+ SkToBool(fFlags & SkShadowFlags::kGaussianEdge_ShadowFlag),
+ "GaussianEdge", &needSeparator);
+ SkAddFlagToString(str,
+ SkToBool(fFlags & SkShadowFlags::kLargerUmbra_ShadowFlag),
+ "LargerUmbra", &needSeparator);
+ } else {
+ str->append("None");
+ }
+ str->append("))");
+}
+#endif
+
+SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkAmbientShadowMaskFilter)
+SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkAmbientShadowMaskFilterImpl)
+SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
diff --git a/src/effects/shadows/SkAmbientShadowMaskFilter.h b/src/effects/shadows/SkAmbientShadowMaskFilter.h
new file mode 100755
index 0000000000..cd77b106a4
--- /dev/null
+++ b/src/effects/shadows/SkAmbientShadowMaskFilter.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkAmbientShadowMaskFilter_DEFINED
+#define SkAmbientShadowMaskFilter_DEFINED
+
+#include "SkMaskFilter.h"
+#include "SkShadowFlags.h"
+
+/*
+ * This filter implements a shadow representing ambient occlusion for an occluding object.
+ */
+class SK_API SkAmbientShadowMaskFilter {
+public:
+ /** Create a shadow maskfilter.
+ * @param occluderHeight Height of occluding object off of ground plane.
+ * @param ambientAlpha Base opacity of the ambient occlusion shadow.
+ * @param flags Flags to use - defaults to none
+ * @return The new shadow maskfilter
+ */
+ static sk_sp<SkMaskFilter> Make(SkScalar occluderHeight, SkScalar ambientAlpha,
+ uint32_t flags = SkShadowFlags::kNone_ShadowFlag);
+
+ SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP()
+
+private:
+ SkAmbientShadowMaskFilter(); // can't be instantiated
+};
+#endif
diff --git a/src/effects/SkShadowMaskFilter.cpp b/src/effects/shadows/SkSpotShadowMaskFilter.cpp
index 61a93b8982..b214cefef2 100755
--- a/src/effects/SkShadowMaskFilter.cpp
+++ b/src/effects/shadows/SkSpotShadowMaskFilter.cpp
@@ -1,11 +1,11 @@
/*
- * Copyright 2016 Google Inc.
+ * Copyright 2017 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
-#include "SkShadowMaskFilter.h"
+#include "SkSpotShadowMaskFilter.h"
#include "SkReadBuffer.h"
#include "SkStringUtils.h"
#include "SkWriteBuffer.h"
@@ -25,10 +25,10 @@
#include "SkStrokeRec.h"
#endif
-class SkShadowMaskFilterImpl : public SkMaskFilter {
+class SkSpotShadowMaskFilterImpl : public SkMaskFilter {
public:
- SkShadowMaskFilterImpl(SkScalar occluderHeight, const SkPoint3& lightPos, SkScalar lightRadius,
- SkScalar ambientAlpha, SkScalar spotAlpha, uint32_t flags);
+ SkSpotShadowMaskFilterImpl(SkScalar occluderHeight, const SkPoint3& lightPos,
+ SkScalar lightRadius, SkScalar spotAlpha, uint32_t flags);
// overrides from SkMaskFilter
SkMask::Format getFormat() const override;
@@ -64,89 +64,86 @@ public:
void computeFastBounds(const SkRect&, SkRect*) const override;
SK_TO_STRING_OVERRIDE()
- SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkShadowMaskFilterImpl)
+ SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpotShadowMaskFilterImpl)
private:
SkScalar fOccluderHeight;
SkPoint3 fLightPos;
SkScalar fLightRadius;
- SkScalar fAmbientAlpha;
SkScalar fSpotAlpha;
uint32_t fFlags;
- SkShadowMaskFilterImpl(SkReadBuffer&);
+ SkSpotShadowMaskFilterImpl(SkReadBuffer&);
void flatten(SkWriteBuffer&) const override;
- friend class SkShadowMaskFilter;
+ friend class SkSpotShadowMaskFilter;
typedef SkMaskFilter INHERITED;
};
-sk_sp<SkMaskFilter> SkShadowMaskFilter::Make(SkScalar occluderHeight, const SkPoint3& lightPos,
- SkScalar lightRadius, SkScalar ambientAlpha,
- SkScalar spotAlpha, uint32_t flags) {
+sk_sp<SkMaskFilter> SkSpotShadowMaskFilter::Make(SkScalar occluderHeight, const SkPoint3& lightPos,
+ SkScalar lightRadius, SkScalar spotAlpha,
+ uint32_t flags) {
// add some param checks here for early exit
- return sk_sp<SkMaskFilter>(new SkShadowMaskFilterImpl(occluderHeight, lightPos, lightRadius,
- ambientAlpha, spotAlpha, flags));
+ return sk_sp<SkMaskFilter>(new SkSpotShadowMaskFilterImpl(occluderHeight, lightPos,
+ lightRadius, spotAlpha, flags));
}
///////////////////////////////////////////////////////////////////////////////////////////////////
-SkShadowMaskFilterImpl::SkShadowMaskFilterImpl(SkScalar occluderHeight, const SkPoint3& lightPos,
- SkScalar lightRadius, SkScalar ambientAlpha,
- SkScalar spotAlpha, uint32_t flags)
+SkSpotShadowMaskFilterImpl::SkSpotShadowMaskFilterImpl(SkScalar occluderHeight,
+ const SkPoint3& lightPos,
+ SkScalar lightRadius,
+ SkScalar spotAlpha,
+ uint32_t flags)
: fOccluderHeight(occluderHeight)
, fLightPos(lightPos)
, fLightRadius(lightRadius)
- , fAmbientAlpha(ambientAlpha)
, fSpotAlpha(spotAlpha)
, fFlags(flags) {
SkASSERT(fOccluderHeight > 0);
SkASSERT(fLightPos.z() > 0 && fLightPos.z() > fOccluderHeight);
SkASSERT(fLightRadius > 0);
- SkASSERT(fAmbientAlpha >= 0);
SkASSERT(fSpotAlpha >= 0);
}
-SkMask::Format SkShadowMaskFilterImpl::getFormat() const {
+SkMask::Format SkSpotShadowMaskFilterImpl::getFormat() const {
return SkMask::kA8_Format;
}
-bool SkShadowMaskFilterImpl::filterMask(SkMask* dst, const SkMask& src,
- const SkMatrix& matrix,
- SkIPoint* margin) const {
+bool SkSpotShadowMaskFilterImpl::filterMask(SkMask* dst, const SkMask& src,
+ const SkMatrix& matrix,
+ SkIPoint* margin) const {
// TODO something
return false;
}
-void SkShadowMaskFilterImpl::computeFastBounds(const SkRect& src, SkRect* dst) const {
+void SkSpotShadowMaskFilterImpl::computeFastBounds(const SkRect& src, SkRect* dst) const {
// TODO compute based on ambient + spot data
dst->set(src.fLeft, src.fTop, src.fRight, src.fBottom);
}
-sk_sp<SkFlattenable> SkShadowMaskFilterImpl::CreateProc(SkReadBuffer& buffer) {
+sk_sp<SkFlattenable> SkSpotShadowMaskFilterImpl::CreateProc(SkReadBuffer& buffer) {
const SkScalar occluderHeight = buffer.readScalar();
const SkScalar lightX = buffer.readScalar();
const SkScalar lightY = buffer.readScalar();
const SkScalar lightZ = buffer.readScalar();
const SkPoint3 lightPos = SkPoint3::Make(lightX, lightY, lightZ);
const SkScalar lightRadius = buffer.readScalar();
- const SkScalar ambientAlpha = buffer.readScalar();
const SkScalar spotAlpha = buffer.readScalar();
const uint32_t flags = buffer.readUInt();
- return SkShadowMaskFilter::Make(occluderHeight, lightPos, lightRadius,
- ambientAlpha, spotAlpha, flags);
+ return SkSpotShadowMaskFilter::Make(occluderHeight, lightPos, lightRadius,
+ spotAlpha, flags);
}
-void SkShadowMaskFilterImpl::flatten(SkWriteBuffer& buffer) const {
+void SkSpotShadowMaskFilterImpl::flatten(SkWriteBuffer& buffer) const {
buffer.writeScalar(fOccluderHeight);
buffer.writeScalar(fLightPos.fX);
buffer.writeScalar(fLightPos.fY);
buffer.writeScalar(fLightPos.fZ);
buffer.writeScalar(fLightRadius);
- buffer.writeScalar(fAmbientAlpha);
buffer.writeScalar(fSpotAlpha);
buffer.writeUInt(fFlags);
}
@@ -155,22 +152,22 @@ void SkShadowMaskFilterImpl::flatten(SkWriteBuffer& buffer) const {
///////////////////////////////////////////////////////////////////////////////////////////////////
-bool SkShadowMaskFilterImpl::canFilterMaskGPU(const SkRRect& devRRect,
- const SkIRect& clipBounds,
- const SkMatrix& ctm,
- SkRect* maskRect) const {
+bool SkSpotShadowMaskFilterImpl::canFilterMaskGPU(const SkRRect& devRRect,
+ const SkIRect& clipBounds,
+ const SkMatrix& ctm,
+ SkRect* maskRect) const {
// TODO
*maskRect = devRRect.rect();
return true;
}
-bool SkShadowMaskFilterImpl::directFilterMaskGPU(GrTextureProvider* texProvider,
- GrRenderTargetContext* drawContext,
- GrPaint&& paint,
- const GrClip& clip,
- const SkMatrix& viewMatrix,
- const SkStrokeRec& strokeRec,
- const SkPath& path) const {
+bool SkSpotShadowMaskFilterImpl::directFilterMaskGPU(GrTextureProvider* texProvider,
+ GrRenderTargetContext* drawContext,
+ GrPaint&& paint,
+ const GrClip& clip,
+ const SkMatrix& viewMatrix,
+ const SkStrokeRec& strokeRec,
+ const SkPath& path) const {
SkASSERT(drawContext);
// TODO: this will not handle local coordinates properly
@@ -191,14 +188,14 @@ bool SkShadowMaskFilterImpl::directFilterMaskGPU(GrTextureProvider* texProvider,
return false;
}
-bool SkShadowMaskFilterImpl::directFilterRRectMaskGPU(GrContext*,
- GrRenderTargetContext* renderTargetContext,
- GrPaint&& paint,
- const GrClip& clip,
- const SkMatrix& viewMatrix,
- const SkStrokeRec& strokeRec,
- const SkRRect& rrect,
- const SkRRect& devRRect) const {
+bool SkSpotShadowMaskFilterImpl::directFilterRRectMaskGPU(GrContext*,
+ GrRenderTargetContext* rtContext,
+ GrPaint&& paint,
+ const GrClip& clip,
+ const SkMatrix& viewMatrix,
+ const SkStrokeRec& strokeRec,
+ const SkRRect& rrect,
+ const SkRRect& devRRect) const {
// It's likely the caller has already done these checks, but we have to be sure.
// TODO: support analytic blurring of general rrect
@@ -229,41 +226,6 @@ bool SkShadowMaskFilterImpl::directFilterRRectMaskGPU(GrContext*,
// TODO: take flags into account when generating shadow data
- if (fAmbientAlpha > 0.0f) {
- static const float kHeightFactor = 1.0f / 128.0f;
- static const float kGeomFactor = 64.0f;
-
- SkScalar srcSpaceAmbientRadius = fOccluderHeight * kHeightFactor * kGeomFactor;
- const float umbraAlpha = (1.0f + SkTMax(fOccluderHeight * kHeightFactor, 0.0f));
- const SkScalar ambientOffset = srcSpaceAmbientRadius * umbraAlpha;
-
- // For the ambient rrect, we inset the offset rect by half the srcSpaceAmbientRadius
- // to get our stroke shape.
- SkScalar ambientPathOutset = SkTMax(ambientOffset - srcSpaceAmbientRadius * 0.5f,
- minRadius);
-
- SkRRect ambientRRect;
- if (isRect) {
- const SkRect temp = rrect.rect().makeOutset(ambientPathOutset, ambientPathOutset);
- ambientRRect = SkRRect::MakeRectXY(temp, ambientPathOutset, ambientPathOutset);
- } else {
- rrect.outset(ambientPathOutset, ambientPathOutset, &ambientRRect);
- }
-
- const SkScalar devSpaceAmbientRadius = srcSpaceAmbientRadius * scaleFactor;
-
- GrPaint newPaint(paint);
- GrColor4f color = newPaint.getColor4f();
- color.fRGBA[3] *= fAmbientAlpha;
- newPaint.setColor4f(color);
- SkStrokeRec ambientStrokeRec(SkStrokeRec::kHairline_InitStyle);
- ambientStrokeRec.setStrokeStyle(srcSpaceAmbientRadius, false);
-
- renderTargetContext->drawShadowRRect(clip, std::move(newPaint), viewMatrix, ambientRRect,
- devSpaceAmbientRadius,
- GrStyle(ambientStrokeRec, nullptr));
- }
-
if (fSpotAlpha > 0.0f) {
float zRatio = SkTPin(fOccluderHeight / (fLightPos.fZ - fOccluderHeight), 0.0f, 0.95f);
@@ -318,7 +280,7 @@ bool SkShadowMaskFilterImpl::directFilterRRectMaskGPU(GrContext*,
// If the area of the stroked geometry is larger than the fill geometry,
// or if the caster is transparent, just fill it.
if (strokedArea > filledArea ||
- fFlags & SkShadowMaskFilter::kTransparentOccluder_ShadowFlag) {
+ fFlags & SkShadowFlags::kTransparentOccluder_ShadowFlag) {
spotStrokeRec.setStrokeStyle(srcSpaceSpotRadius, true);
} else {
// Since we can't have unequal strokes, inset the shadow rect so the inner
@@ -336,17 +298,17 @@ bool SkShadowMaskFilterImpl::directFilterRRectMaskGPU(GrContext*,
spotShadowRRect.offset(spotOffset.fX, spotOffset.fY);
- renderTargetContext->drawShadowRRect(clip, std::move(paint), viewMatrix, spotShadowRRect,
- devSpaceSpotRadius, GrStyle(spotStrokeRec, nullptr));
+ rtContext->drawShadowRRect(clip, std::move(paint), viewMatrix, spotShadowRRect,
+ devSpaceSpotRadius, GrStyle(spotStrokeRec, nullptr));
}
return true;
}
-sk_sp<GrTextureProxy> SkShadowMaskFilterImpl::filterMaskGPU(GrContext*,
- sk_sp<GrTextureProxy> srcProxy,
- const SkMatrix& ctm,
- const SkIRect& maskRect) const {
+sk_sp<GrTextureProxy> SkSpotShadowMaskFilterImpl::filterMaskGPU(GrContext*,
+ sk_sp<GrTextureProxy> srcProxy,
+ const SkMatrix& ctm,
+ const SkIRect& maskRect) const {
// This filter is generative and doesn't operate on pre-existing masks
return nullptr;
}
@@ -354,8 +316,8 @@ sk_sp<GrTextureProxy> SkShadowMaskFilterImpl::filterMaskGPU(GrContext*,
#endif
#ifndef SK_IGNORE_TO_STRING
-void SkShadowMaskFilterImpl::toString(SkString* str) const {
- str->append("SkShadowMaskFilterImpl: (");
+void SkSpotShadowMaskFilterImpl::toString(SkString* str) const {
+ str->append("SkSpotShadowMaskFilterImpl: (");
str->append("occluderHeight: ");
str->appendScalar(fOccluderHeight);
@@ -373,10 +335,6 @@ void SkShadowMaskFilterImpl::toString(SkString* str) const {
str->appendScalar(fLightRadius);
str->append(" ");
- str->append("ambientAlpha: ");
- str->appendScalar(fAmbientAlpha);
- str->append(" ");
-
str->append("spotAlpha: ");
str->appendScalar(fSpotAlpha);
str->append(" ");
@@ -385,13 +343,13 @@ void SkShadowMaskFilterImpl::toString(SkString* str) const {
if (fFlags) {
bool needSeparator = false;
SkAddFlagToString(str,
- SkToBool(fFlags & SkShadowMaskFilter::kTransparentOccluder_ShadowFlag),
+ SkToBool(fFlags & SkShadowFlags::kTransparentOccluder_ShadowFlag),
"TransparentOccluder", &needSeparator);
SkAddFlagToString(str,
- SkToBool(fFlags & SkShadowMaskFilter::kGaussianEdge_ShadowFlag),
+ SkToBool(fFlags & SkShadowFlags::kGaussianEdge_ShadowFlag),
"GaussianEdge", &needSeparator);
SkAddFlagToString(str,
- SkToBool(fFlags & SkShadowMaskFilter::kLargerUmbra_ShadowFlag),
+ SkToBool(fFlags & SkShadowFlags::kLargerUmbra_ShadowFlag),
"LargerUmbra", &needSeparator);
} else {
str->append("None");
@@ -400,6 +358,6 @@ void SkShadowMaskFilterImpl::toString(SkString* str) const {
}
#endif
-SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkShadowMaskFilter)
-SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkShadowMaskFilterImpl)
+SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkSpotShadowMaskFilter)
+SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpotShadowMaskFilterImpl)
SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
diff --git a/src/effects/shadows/SkSpotShadowMaskFilter.h b/src/effects/shadows/SkSpotShadowMaskFilter.h
new file mode 100755
index 0000000000..5e1a4a9ec9
--- /dev/null
+++ b/src/effects/shadows/SkSpotShadowMaskFilter.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkSpotShadowMaskFilter_DEFINED
+#define SkSpotShadowMaskFilter_DEFINED
+
+#include "SkMaskFilter.h"
+#include "SkShadowFlags.h"
+
+/*
+ * This filter implements a shadow for an occluding object
+ * representing a displaced shadow from a point light.
+ */
+class SK_API SkSpotShadowMaskFilter {
+public:
+ /** Create a shadow maskfilter.
+ * @param occluderHeight Height of occluding object off of ground plane.
+ * @param lightPos Position of the light applied to this object.
+ * @param lightRadius Radius of the light (light is assumed to be spherical).
+ * @param spotAlpha Base opacity of the displaced spot shadow.
+ * @param flags Flags to use - defaults to none
+ * @return The new shadow maskfilter
+ */
+ static sk_sp<SkMaskFilter> Make(SkScalar occluderHeight, const SkPoint3& lightPos,
+ SkScalar lightRadius, SkScalar spotAlpha,
+ uint32_t flags = SkShadowFlags::kNone_ShadowFlag);
+
+ SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP()
+
+private:
+ SkSpotShadowMaskFilter(); // can't be instantiated
+};
+#endif
diff --git a/src/utils/SkShadowUtils.cpp b/src/utils/SkShadowUtils.cpp
index e8a1f831d3..e93f778072 100755
--- a/src/utils/SkShadowUtils.cpp
+++ b/src/utils/SkShadowUtils.cpp
@@ -7,7 +7,8 @@
#include "SkShadowUtils.h"
#include "SkCanvas.h"
-#include "../effects/SkShadowMaskFilter.h"
+#include "../effects/shadows/SkAmbientShadowMaskFilter.h"
+#include "../effects/shadows/SkSpotShadowMaskFilter.h"
// Draw an offset spot shadow and outlining ambient shadow for the given path.
void SkShadowUtils::DrawShadow(SkCanvas* canvas, const SkPath& path, SkScalar occluderHeight,
@@ -16,8 +17,9 @@ void SkShadowUtils::DrawShadow(SkCanvas* canvas, const SkPath& path, SkScalar oc
uint32_t flags) {
SkPaint newPaint;
newPaint.setColor(color);
- newPaint.setMaskFilter(SkShadowMaskFilter::Make(occluderHeight, lightPos, lightRadius,
- ambientAlpha, spotAlpha, flags));
-
+ newPaint.setMaskFilter(SkAmbientShadowMaskFilter::Make(occluderHeight, ambientAlpha, flags));
+ canvas->drawPath(path, newPaint);
+ newPaint.setMaskFilter(SkSpotShadowMaskFilter::Make(occluderHeight, lightPos, lightRadius,
+ spotAlpha, flags));
canvas->drawPath(path, newPaint);
}