From 958fbc460a1e680c6a9979e140da8bfc00b8831d Mon Sep 17 00:00:00 2001 From: Brian Salomon Date: Mon, 30 Jan 2017 17:01:28 -0500 Subject: Make SkShadowUtils tessellations ref counted in preparation for caching them. Change-Id: I60133fcc4101a27bcc3e7ad38e7348ad9147b8a9 Reviewed-on: https://skia-review.googlesource.com/7784 Reviewed-by: Jim Van Verth Commit-Queue: Brian Salomon --- src/utils/SkShadowTessellator.cpp | 135 +++++++++++++++++++++++++++++++++ src/utils/SkShadowTessellator.h | 154 +++++++++++--------------------------- src/utils/SkShadowUtils.cpp | 25 ++++--- 3 files changed, 194 insertions(+), 120 deletions(-) (limited to 'src') diff --git a/src/utils/SkShadowTessellator.cpp b/src/utils/SkShadowTessellator.cpp index ca8927b89d..147ff5399d 100755 --- a/src/utils/SkShadowTessellator.cpp +++ b/src/utils/SkShadowTessellator.cpp @@ -13,6 +13,57 @@ #include "GrPathUtils.h" #endif +template using UniqueArray = SkShadowVertices::UniqueArray; + +// TODO: derive the ambient and spot classes from a base class containing common elements + +class SkAmbientShadowTessellator { +public: + SkAmbientShadowTessellator(const SkPath& path, SkScalar radius, SkColor umbraColor, + SkColor penumbraColor, bool transparent); + + int vertexCount() const { return fPositions.count(); } + int indexCount() const { return fIndices.count(); } + + UniqueArray releasePositions() { return UniqueArray(fPositions.release()); } + UniqueArray releaseColors() { return UniqueArray(fColors.release()); } + UniqueArray releaseIndices() { return UniqueArray(fIndices.release()); } + +private: + void handleLine(const SkPoint& p); + + void handleQuad(const SkPoint pts[3]); + + void handleCubic(SkPoint pts[4]); + + void handleConic(SkPoint pts[3], SkScalar w); + + void addArc(const SkVector& nextNormal); + void finishArcAndAddEdge(const SkVector& nextPoint, const SkVector& nextNormal); + void addEdge(const SkVector& nextPoint, const SkVector& nextNormal); + + SkScalar fRadius; + SkColor fUmbraColor; + SkColor fPenumbraColor; + bool fTransparent; + + SkTDArray fPositions; + SkTDArray fColors; + SkTDArray fIndices; + + int fPrevInnerIndex; + SkVector fPrevNormal; + int fFirstVertex; + SkVector fFirstNormal; + SkScalar fDirection; + int fCentroidCount; + + // first three points + SkTDArray fInitPoints; + // temporary buffer + SkTDArray fPointBuffer; +}; + static bool compute_normal(const SkPoint& p0, const SkPoint& p1, SkScalar radius, SkScalar dir, SkVector* newNormal) { SkVector normal; @@ -307,6 +358,63 @@ void SkAmbientShadowTessellator::addEdge(const SkPoint& nextPoint, const SkVecto /////////////////////////////////////////////////////////////////////////////////////////////////// +class SkSpotShadowTessellator { +public: + SkSpotShadowTessellator(const SkPath& path, SkScalar scale, const SkVector& translate, + SkScalar radius, SkColor umbraColor, SkColor penumbraColor, + bool transparent); + + int vertexCount() const { return fPositions.count(); } + int indexCount() const { return fIndices.count(); } + + UniqueArray releasePositions() { return UniqueArray(fPositions.release()); } + UniqueArray releaseColors() { return UniqueArray(fColors.release()); } + UniqueArray releaseIndices() { return UniqueArray(fIndices.release()); } + +private: + void computeClipBounds(const SkPath& path); + + void handleLine(const SkPoint& p); + void handleLine(SkScalar scale, const SkVector& xlate, SkPoint p); + + void handleQuad(const SkPoint pts[3]); + void handleQuad(SkScalar scale, const SkVector& xlate, SkPoint pts[3]); + + void handleCubic(SkScalar scale, const SkVector& xlate, SkPoint pts[4]); + + void handleConic(SkScalar scale, const SkVector& xlate, SkPoint pts[3], SkScalar w); + + void mapPoints(SkScalar scale, const SkVector& xlate, SkPoint* pts, int count); + void addInnerPoint(const SkPoint& pathPoint, SkColor umbraColor, SkScalar radiusSqd); + void addArc(const SkVector& nextNormal); + void finishArcAndAddEdge(const SkVector& nextPoint, const SkVector& nextNormal); + void addEdge(const SkVector& nextPoint, const SkVector& nextNormal); + + SkScalar fRadius; + SkColor fUmbraColor; + SkColor fPenumbraColor; + + SkTDArray fPositions; + SkTDArray fColors; + SkTDArray fIndices; + + int fPrevInnerIndex; + SkPoint fPrevPoint; + SkVector fPrevNormal; + int fFirstVertex; + SkPoint fFirstPoint; + SkVector fFirstNormal; + SkScalar fDirection; + + SkPoint fCentroid; + SkTDArray fClipPolygon; + + // first three points + SkTDArray fInitPoints; + // temporary buffer + SkTDArray fPointBuffer; +}; + SkSpotShadowTessellator::SkSpotShadowTessellator(const SkPath& path, SkScalar scale, const SkVector& translate, SkScalar radius, @@ -645,3 +753,30 @@ void SkSpotShadowTessellator::addEdge(const SkPoint& nextPoint, const SkVector& fPrevInnerIndex = fPositions.count() - 2; fPrevNormal = nextNormal; } + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +sk_sp SkShadowVertices::MakeAmbient(const SkPath& path, SkScalar radius, + SkColor umbraColor, SkColor penumbraColor, + bool transparent) { + SkAmbientShadowTessellator ambientTess(path, radius, umbraColor, penumbraColor, transparent); + int vcount = ambientTess.vertexCount(); + int icount = ambientTess.indexCount(); + return sk_sp(new SkShadowVertices(ambientTess.releasePositions(), + ambientTess.releaseColors(), + ambientTess.releaseIndices(), vcount, + icount)); +} + +sk_sp SkShadowVertices::MakeSpot(const SkPath& path, SkScalar scale, + const SkVector& translate, SkScalar radius, + SkColor umbraColor, SkColor penumbraColor, + bool transparent) { + SkSpotShadowTessellator spotTess(path, scale, translate, radius, umbraColor, penumbraColor, + transparent); + int vcount = spotTess.vertexCount(); + int icount = spotTess.indexCount(); + return sk_sp(new SkShadowVertices(spotTess.releasePositions(), + spotTess.releaseColors(), + spotTess.releaseIndices(), vcount, icount)); +} diff --git a/src/utils/SkShadowTessellator.h b/src/utils/SkShadowTessellator.h index ababba74dd..301b684267 100755 --- a/src/utils/SkShadowTessellator.h +++ b/src/utils/SkShadowTessellator.h @@ -9,6 +9,7 @@ #define SkShadowTessellator_DEFINED #include "SkTDArray.h" +#include "SkRefCnt.h" #include "SkPoint.h" #include "SkColor.h" @@ -16,118 +17,53 @@ class SkMatrix; class SkPath; -// TODO: derive these two classes from a base class containing common elements - -/** - * This class generates an ambient shadow for a path by walking the path, outsetting by the - * radius, and setting inner and outer colors to umbraColor and penumbraColor, respectively. - * If transparent is true, then the center of the ambient shadow will be filled in. - */ -class SkAmbientShadowTessellator { -public: - SkAmbientShadowTessellator(const SkPath& path, SkScalar radius, SkColor umbraColor, - SkColor penumbraColor, bool transparent); - - int vertexCount() { return fPositions.count(); } - SkPoint* positions() { return fPositions.begin(); } - SkColor* colors() { return fColors.begin(); } - int indexCount() { return fIndices.count(); } - uint16_t* indices() { return fIndices.begin(); } - -private: - void handleLine(const SkPoint& p); - - void handleQuad(const SkPoint pts[3]); - - void handleCubic(SkPoint pts[4]); - - void handleConic(SkPoint pts[3], SkScalar w); - - void addArc(const SkVector& nextNormal); - void finishArcAndAddEdge(const SkVector& nextPoint, const SkVector& nextNormal); - void addEdge(const SkVector& nextPoint, const SkVector& nextNormal); - - SkScalar fRadius; - SkColor fUmbraColor; - SkColor fPenumbraColor; - bool fTransparent; - - SkTDArray fPositions; - SkTDArray fColors; - SkTDArray fIndices; - - int fPrevInnerIndex; - SkVector fPrevNormal; - int fFirstVertex; - SkVector fFirstNormal; - SkScalar fDirection; - int fCentroidCount; - - // first three points - SkTDArray fInitPoints; - // temporary buffer - SkTDArray fPointBuffer; -}; - -/** - * This class generates an spot shadow for a path by walking the transformed path, further - * transforming by the scale and translation, and outsetting and insetting by a radius. - * The center will be clipped against the original path unless transparent is true. - */ -class SkSpotShadowTessellator { +class SkShadowVertices : public SkRefCnt { public: - SkSpotShadowTessellator(const SkPath& path, SkScalar scale, const SkVector& translate, - SkScalar radius, SkColor umbraColor, SkColor penumbraColor, - bool transparent); - - int vertexCount() { return fPositions.count(); } - SkPoint* positions() { return fPositions.begin(); } - SkColor* colors() { return fColors.begin(); } - int indexCount() { return fIndices.count(); } - uint16_t* indices() { return fIndices.begin(); } + /** + * This function generates an ambient shadow mesh for a path by walking the path, outsetting by + * the radius, and setting inner and outer colors to umbraColor and penumbraColor, respectively. + * If transparent is true, then the center of the ambient shadow will be filled in. + */ + static sk_sp MakeAmbient(const SkPath& path, SkScalar radius, + SkColor umbraColor, SkColor penumbraColor, + bool transparent); + + /** + * This function generates a spot shadow mesh for a path by walking the transformed path, + * further transforming by the scale and translation, and outsetting and insetting by a radius. + * The center will be clipped against the original path unless transparent is true. + */ + static sk_sp MakeSpot(const SkPath& path, SkScalar scale, + const SkVector& translate, SkScalar radius, + SkColor umbraColor, SkColor penumbraColor, + bool transparent); + + int vertexCount() const { return fVertexCnt; } + const SkPoint* positions() const { return fPositions.get(); } + const SkColor* colors() const { return fColors.get(); } + + int indexCount() const { return fIndexCnt; } + const uint16_t* indices() const { return fIndices.get(); } private: - void computeClipBounds(const SkPath& path); - - void handleLine(const SkPoint& p); - void handleLine(SkScalar scale, const SkVector& xlate, SkPoint p); - - void handleQuad(const SkPoint pts[3]); - void handleQuad(SkScalar scale, const SkVector& xlate, SkPoint pts[3]); - - void handleCubic(SkScalar scale, const SkVector& xlate, SkPoint pts[4]); - - void handleConic(SkScalar scale, const SkVector& xlate, SkPoint pts[3], SkScalar w); - - void mapPoints(SkScalar scale, const SkVector& xlate, SkPoint* pts, int count); - void addInnerPoint(const SkPoint& pathPoint, SkColor umbraColor, SkScalar radiusSqd); - void addArc(const SkVector& nextNormal); - void finishArcAndAddEdge(const SkVector& nextPoint, const SkVector& nextNormal); - void addEdge(const SkVector& nextPoint, const SkVector& nextNormal); - - SkScalar fRadius; - SkColor fUmbraColor; - SkColor fPenumbraColor; - - SkTDArray fPositions; - SkTDArray fColors; - SkTDArray fIndices; - - int fPrevInnerIndex; - SkPoint fPrevPoint; - SkVector fPrevNormal; - int fFirstVertex; - SkPoint fFirstPoint; - SkVector fFirstNormal; - SkScalar fDirection; - - SkPoint fCentroid; - SkTDArray fClipPolygon; - - // first three points - SkTDArray fInitPoints; - // temporary buffer - SkTDArray fPointBuffer; + template using Deleter = SkTDArray::Deleter; + template using UniqueArray = std::unique_ptr>; + + SkShadowVertices(UniqueArray&& positions, UniqueArray&& colors, + UniqueArray&& indices, int vertexCnt, int indexCnt) + : fVertexCnt(vertexCnt) + , fIndexCnt(indexCnt) + , fPositions(std::move(positions)) + , fColors(std::move(colors)) + , fIndices(std::move(indices)) { + SkASSERT(SkToBool(indices) == SkToBool(indexCnt)); + } + + int fVertexCnt; + int fIndexCnt; + UniqueArray fPositions; + UniqueArray fColors; + UniqueArray fIndices; }; #endif diff --git a/src/utils/SkShadowUtils.cpp b/src/utils/SkShadowUtils.cpp index 5c92d66845..6a08965e1a 100755 --- a/src/utils/SkShadowUtils.cpp +++ b/src/utils/SkShadowUtils.cpp @@ -87,6 +87,8 @@ void SkShadowUtils::DrawShadow(SkCanvas* canvas, const SkPath& path, SkScalar oc canvas->save(); canvas->resetMatrix(); + bool transparent = SkToBool(flags & SkShadowFlags::kTransparentOccluder_ShadowFlag); + if (ambientAlpha > 0) { SkScalar radius = occluderHeight * kHeightFactor * kGeomFactor; SkScalar umbraAlpha = SkScalarInvert((1.0f + SkTMax(occluderHeight*kHeightFactor, 0.0f))); @@ -97,14 +99,15 @@ void SkShadowUtils::DrawShadow(SkCanvas* canvas, const SkPath& path, SkScalar oc SkColor umbraColor = SkColorSetARGB(255, 0, ambientAlpha*255.9999f, umbraAlpha*255.9999f); SkColor penumbraColor = SkColorSetARGB(255, 0, ambientAlpha*255.9999f, 0); - SkAmbientShadowTessellator tess(xformedPath, radius, umbraColor, penumbraColor, - SkToBool(flags & SkShadowFlags::kTransparentOccluder_ShadowFlag)); - + sk_sp vertices = + SkShadowVertices::MakeAmbient(xformedPath, radius, umbraColor, penumbraColor, + transparent); SkPaint paint; paint.setColor(color); paint.setColorFilter(SkGaussianColorFilter::Make()); - canvas->drawVertices(SkCanvas::kTriangles_VertexMode, tess.vertexCount(), tess.positions(), - nullptr, tess.colors(), tess.indices(), tess.indexCount(), paint); + canvas->drawVertices(SkCanvas::kTriangles_VertexMode, vertices->vertexCount(), + vertices->positions(), nullptr, vertices->colors(), + vertices->indices(), vertices->indexCount(), paint); } if (spotAlpha > 0) { @@ -120,15 +123,15 @@ void SkShadowUtils::DrawShadow(SkCanvas* canvas, const SkPath& path, SkScalar oc SkColor umbraColor = SkColorSetARGB(255, 0, spotAlpha*255.9999f, 255); SkColor penumbraColor = SkColorSetARGB(255, 0, spotAlpha*255.9999f, 0); - SkSpotShadowTessellator tess(xformedPath, scale, spotOffset, radius, - umbraColor, penumbraColor, - SkToBool(flags & SkShadowFlags::kTransparentOccluder_ShadowFlag)); - + sk_sp vertices = + SkShadowVertices::MakeSpot(xformedPath, scale, spotOffset, radius, umbraColor, + penumbraColor, transparent); SkPaint paint; paint.setColor(color); paint.setColorFilter(SkGaussianColorFilter::Make()); - canvas->drawVertices(SkCanvas::kTriangles_VertexMode, tess.vertexCount(), tess.positions(), - nullptr, tess.colors(), tess.indices(), tess.indexCount(), paint); + canvas->drawVertices(SkCanvas::kTriangles_VertexMode, vertices->vertexCount(), + vertices->positions(), nullptr, vertices->colors(), + vertices->indices(), vertices->indexCount(), paint); } canvas->restore(); -- cgit v1.2.3