SkShadowTessellator.cpp revision ab664fa5b5fb96dd1079c090534330ca7e8a10ef
1bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth/* 2bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth * Copyright 2017 Google Inc. 3bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth * 4bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth * Use of this source code is governed by a BSD-style license that can be 5bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth * found in the LICENSE file. 6bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth */ 7bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth 8efe3dedbb3493b738abdb56041b093245e4e8711Jim Van Verth#include "SkShadowTessellator.h" 966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon#include "SkColorPriv.h" 1058abc9e2c56464336472493745e91133819deb96Jim Van Verth#include "SkGeometry.h" 11ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon#include "SkInsetConvexPolygon.h" 1285dc96b8cef031cc38d80f63056581c41c57ff7dJim Van Verth#include "SkPath.h" 13aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon#include "SkVertices.h" 1485dc96b8cef031cc38d80f63056581c41c57ff7dJim Van Verth 1585dc96b8cef031cc38d80f63056581c41c57ff7dJim Van Verth#if SK_SUPPORT_GPU 1685dc96b8cef031cc38d80f63056581c41c57ff7dJim Van Verth#include "GrPathUtils.h" 1785dc96b8cef031cc38d80f63056581c41c57ff7dJim Van Verth#endif 1858abc9e2c56464336472493745e91133819deb96Jim Van Verth 19958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon 20a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth/** 21a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth * Base class 22a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth */ 23aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomonclass SkBaseShadowTessellator { 24958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomonpublic: 25aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon SkBaseShadowTessellator(SkScalar radius, SkColor umbraColor, SkColor penumbraColor, 26aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon bool transparent); 27aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon virtual ~SkBaseShadowTessellator() {} 280dda9cb881900241c1c2193ddf3bede72cda898bBrian Salomon 29aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon sk_sp<SkVertices> releaseVertices() { 30aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon if (!fSucceeded) { 31aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon return nullptr; 32aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon } 3397eb4feb112967ba7fcb00d6995adda1002873c2Mike Reed return SkVertices::MakeCopy(SkCanvas::kTriangles_VertexMode, this->vertexCount(), 3497eb4feb112967ba7fcb00d6995adda1002873c2Mike Reed fPositions.begin(), nullptr, fColors.begin(), 3597eb4feb112967ba7fcb00d6995adda1002873c2Mike Reed this->indexCount(), fIndices.begin()); 361a8b79a79e8aa6d4723588fd1125cb3b08886af8Brian Salomon } 37958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon 38a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verthprotected: 39aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon int vertexCount() const { return fPositions.count(); } 40aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon int indexCount() const { return fIndices.count(); } 41aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon 42a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth virtual void handleLine(const SkPoint& p) = 0; 43a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth void handleLine(const SkMatrix& m, SkPoint* p); 44958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon 45958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon void handleQuad(const SkPoint pts[3]); 46a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth void handleQuad(const SkMatrix& m, SkPoint pts[3]); 47958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon 48a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth void handleCubic(const SkMatrix& m, SkPoint pts[4]); 49958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon 50a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth void handleConic(const SkMatrix& m, SkPoint pts[3], SkScalar w); 51958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon 52958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon void addArc(const SkVector& nextNormal); 53958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon void finishArcAndAddEdge(const SkVector& nextPoint, const SkVector& nextNormal); 54a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth virtual void addEdge(const SkVector& nextPoint, const SkVector& nextNormal) = 0; 55958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon 56a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth // first three points 57a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth SkTDArray<SkPoint> fInitPoints; 58a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth // temporary buffer 59a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth SkTDArray<SkPoint> fPointBuffer; 60958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon 61958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon SkTDArray<SkPoint> fPositions; 62958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon SkTDArray<SkColor> fColors; 63958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon SkTDArray<uint16_t> fIndices; 64958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon 65958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon int fFirstVertex; 66958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon SkVector fFirstNormal; 67a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth SkPoint fFirstPoint; 680dda9cb881900241c1c2193ddf3bede72cda898bBrian Salomon 690dda9cb881900241c1c2193ddf3bede72cda898bBrian Salomon bool fSucceeded; 70a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth bool fTransparent; 71a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth 72a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth SkColor fUmbraColor; 73a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth SkColor fPenumbraColor; 74a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth 75a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth SkScalar fRadius; 76a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth SkScalar fDirection; 77a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth int fPrevUmbraIndex; 78a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth SkVector fPrevNormal; 79a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth SkPoint fPrevPoint; 80958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon}; 81958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon 82bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verthstatic bool compute_normal(const SkPoint& p0, const SkPoint& p1, SkScalar radius, SkScalar dir, 83bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth SkVector* newNormal) { 84bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth SkVector normal; 85bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth // compute perpendicular 86bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth normal.fX = p0.fY - p1.fY; 87bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth normal.fY = p1.fX - p0.fX; 88bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth if (!normal.normalize()) { 89bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth return false; 90bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth } 91bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth normal *= radius*dir; 92bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth *newNormal = normal; 93bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth return true; 94bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth} 95bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth 96bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verthstatic void compute_radial_steps(const SkVector& v1, const SkVector& v2, SkScalar r, 97bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth SkScalar* rotSin, SkScalar* rotCos, int* n) { 98bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth const SkScalar kRecipPixelsPerArcSegment = 0.25f; 99bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth 100bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth SkScalar rCos = v1.dot(v2); 101bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth SkScalar rSin = v1.cross(v2); 102bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth SkScalar theta = SkScalarATan2(rSin, rCos); 103bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth 104bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth SkScalar steps = r*theta*kRecipPixelsPerArcSegment; 105bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth 106bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth SkScalar dTheta = theta / steps; 107bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth *rotSin = SkScalarSinCos(dTheta, rotCos); 108bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth *n = SkScalarFloorToInt(steps); 109bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth} 110bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth 111aff27a23ad4b38851429066dbfb43cfa7199e37cBrian SalomonSkBaseShadowTessellator::SkBaseShadowTessellator(SkScalar radius, SkColor umbraColor, 112aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon SkColor penumbraColor, bool transparent) 113aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon : fFirstVertex(-1) 114aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon , fSucceeded(false) 115aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon , fTransparent(transparent) 116aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon , fUmbraColor(umbraColor) 117aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon , fPenumbraColor(penumbraColor) 118aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon , fRadius(radius) 119aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon , fDirection(1) 120aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon , fPrevUmbraIndex(-1) { 121a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth fInitPoints.setReserve(3); 122a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth 123a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth // child classes will set reserve for positions, colors and indices 124a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth} 125a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth 126a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth// tesselation tolerance values, in device space pixels 127b8b51e6b2f431c89907139bec52ed64b7ed303edMike Klein#if SK_SUPPORT_GPU 128a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verthstatic const SkScalar kQuadTolerance = 0.2f; 129a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verthstatic const SkScalar kCubicTolerance = 0.2f; 130b8b51e6b2f431c89907139bec52ed64b7ed303edMike Klein#endif 131a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verthstatic const SkScalar kConicTolerance = 0.5f; 132a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth 133aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomonvoid SkBaseShadowTessellator::handleLine(const SkMatrix& m, SkPoint* p) { 134a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth m.mapPoints(p, 1); 135a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth this->handleLine(*p); 136a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth} 137a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth 138aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomonvoid SkBaseShadowTessellator::handleQuad(const SkPoint pts[3]) { 139a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth#if SK_SUPPORT_GPU 140a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth // TODO: Pull PathUtils out of Ganesh? 141a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth int maxCount = GrPathUtils::quadraticPointCount(pts, kQuadTolerance); 142a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth fPointBuffer.setReserve(maxCount); 143a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth SkPoint* target = fPointBuffer.begin(); 144a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth int count = GrPathUtils::generateQuadraticPoints(pts[0], pts[1], pts[2], 145a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth kQuadTolerance, &target, maxCount); 146a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth fPointBuffer.setCount(count); 147a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth for (int i = 0; i < count; i++) { 148a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth this->handleLine(fPointBuffer[i]); 149a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth } 150a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth#else 151a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth // for now, just to draw something 152a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth this->handleLine(pts[1]); 153a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth this->handleLine(pts[2]); 154a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth#endif 155a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth} 156a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth 157aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomonvoid SkBaseShadowTessellator::handleQuad(const SkMatrix& m, SkPoint pts[3]) { 158a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth m.mapPoints(pts, 3); 159a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth this->handleQuad(pts); 160a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth} 161a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth 162aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomonvoid SkBaseShadowTessellator::handleCubic(const SkMatrix& m, SkPoint pts[4]) { 163a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth m.mapPoints(pts, 4); 164a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth#if SK_SUPPORT_GPU 165a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth // TODO: Pull PathUtils out of Ganesh? 166a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth int maxCount = GrPathUtils::cubicPointCount(pts, kCubicTolerance); 167a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth fPointBuffer.setReserve(maxCount); 168a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth SkPoint* target = fPointBuffer.begin(); 169a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth int count = GrPathUtils::generateCubicPoints(pts[0], pts[1], pts[2], pts[3], 170a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth kCubicTolerance, &target, maxCount); 171a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth fPointBuffer.setCount(count); 172a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth for (int i = 0; i < count; i++) { 173a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth this->handleLine(fPointBuffer[i]); 174a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth } 175a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth#else 176a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth // for now, just to draw something 177a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth this->handleLine(pts[1]); 178a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth this->handleLine(pts[2]); 179a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth this->handleLine(pts[3]); 180a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth#endif 181a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth} 182a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth 183aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomonvoid SkBaseShadowTessellator::handleConic(const SkMatrix& m, SkPoint pts[3], SkScalar w) { 184a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth m.mapPoints(pts, 3); 185a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth SkAutoConicToQuads quadder; 186a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth const SkPoint* quads = quadder.computeQuads(pts, w, kConicTolerance); 187a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth SkPoint lastPoint = *(quads++); 188a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth int count = quadder.countQuads(); 189a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth for (int i = 0; i < count; ++i) { 190a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth SkPoint quadPts[3]; 191a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth quadPts[0] = lastPoint; 192a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth quadPts[1] = quads[0]; 193a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth quadPts[2] = i == count - 1 ? pts[2] : quads[1]; 194a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth this->handleQuad(quadPts); 195a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth lastPoint = quadPts[2]; 196a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth quads += 2; 197a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth } 198a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth} 199a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth 200aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomonvoid SkBaseShadowTessellator::addArc(const SkVector& nextNormal) { 201a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth // fill in fan from previous quad 202a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth SkScalar rotSin, rotCos; 203a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth int numSteps; 204a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth compute_radial_steps(fPrevNormal, nextNormal, fRadius, &rotSin, &rotCos, &numSteps); 205a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth SkVector prevNormal = fPrevNormal; 206a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth for (int i = 0; i < numSteps; ++i) { 207a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth SkVector nextNormal; 208a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth nextNormal.fX = prevNormal.fX*rotCos - prevNormal.fY*rotSin; 209a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth nextNormal.fY = prevNormal.fY*rotCos + prevNormal.fX*rotSin; 210a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth *fPositions.push() = fPrevPoint + nextNormal; 211a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth *fColors.push() = fPenumbraColor; 212a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth *fIndices.push() = fPrevUmbraIndex; 213a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth *fIndices.push() = fPositions.count() - 2; 214a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth *fIndices.push() = fPositions.count() - 1; 215a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth 216a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth prevNormal = nextNormal; 217a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth } 218a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth} 219a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth 220aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomonvoid SkBaseShadowTessellator::finishArcAndAddEdge(const SkPoint& nextPoint, 221aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon const SkVector& nextNormal) { 222a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth // close out previous arc 223a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth *fPositions.push() = fPrevPoint + nextNormal; 224a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth *fColors.push() = fPenumbraColor; 225a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth *fIndices.push() = fPrevUmbraIndex; 226a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth *fIndices.push() = fPositions.count() - 2; 227a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth *fIndices.push() = fPositions.count() - 1; 228a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth 229a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth this->addEdge(nextPoint, nextNormal); 230a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth} 231a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth 232a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth 233a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth////////////////////////////////////////////////////////////////////////////////////////////////// 234a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth 235aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomonclass SkAmbientShadowTessellator : public SkBaseShadowTessellator { 236a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verthpublic: 237a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth SkAmbientShadowTessellator(const SkPath& path, const SkMatrix& ctm, 238a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth SkScalar radius, SkColor umbraColor, 239a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth SkColor penumbraColor, bool transparent); 240a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth 241a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verthprivate: 242a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth void handleLine(const SkPoint& p) override; 243a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth void addEdge(const SkVector& nextPoint, const SkVector& nextNormal) override; 244a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth 245a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth int fCentroidCount; 246a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth 247aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon typedef SkBaseShadowTessellator INHERITED; 248a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth}; 249a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth 250efe3dedbb3493b738abdb56041b093245e4e8711Jim Van VerthSkAmbientShadowTessellator::SkAmbientShadowTessellator(const SkPath& path, 251a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth const SkMatrix& ctm, 252bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth SkScalar radius, 253efe3dedbb3493b738abdb56041b093245e4e8711Jim Van Verth SkColor umbraColor, 254efe3dedbb3493b738abdb56041b093245e4e8711Jim Van Verth SkColor penumbraColor, 255bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth bool transparent) 256a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth : INHERITED(radius, umbraColor, penumbraColor, transparent) { 257bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth // Outer ring: 3*numPts 258bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth // Middle ring: numPts 259bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth fPositions.setReserve(4 * path.countPoints()); 260bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth fColors.setReserve(4 * path.countPoints()); 261bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth // Outer ring: 12*numPts 262bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth // Middle ring: 0 263bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth fIndices.setReserve(12 * path.countPoints()); 264bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth 265bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth // walk around the path, tessellate and generate outer ring 266bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth // if original path is transparent, will accumulate sum of points for centroid 267bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth SkPath::Iter iter(path, true); 268bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth SkPoint pts[4]; 269bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth SkPath::Verb verb; 270bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth if (fTransparent) { 271bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth *fPositions.push() = SkPoint::Make(0, 0); 272bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth *fColors.push() = umbraColor; 273bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth fCentroidCount = 0; 274bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth } 275bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { 276bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth switch (verb) { 277bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth case SkPath::kLine_Verb: 278a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth this->INHERITED::handleLine(ctm, &pts[1]); 279bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth break; 280bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth case SkPath::kQuad_Verb: 281a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth this->handleQuad(ctm, pts); 282bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth break; 283bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth case SkPath::kCubic_Verb: 284a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth this->handleCubic(ctm, pts); 285bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth break; 286bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth case SkPath::kConic_Verb: 287a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth this->handleConic(ctm, pts, iter.conicWeight()); 288bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth break; 289bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth case SkPath::kMove_Verb: 290bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth case SkPath::kClose_Verb: 291bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth case SkPath::kDone_Verb: 292bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth break; 293bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth } 294bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth } 295bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth 2960dda9cb881900241c1c2193ddf3bede72cda898bBrian Salomon if (!this->indexCount()) { 2970dda9cb881900241c1c2193ddf3bede72cda898bBrian Salomon return; 2980dda9cb881900241c1c2193ddf3bede72cda898bBrian Salomon } 2990dda9cb881900241c1c2193ddf3bede72cda898bBrian Salomon 300bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth SkVector normal; 301a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth if (compute_normal(fPrevPoint, fFirstPoint, fRadius, fDirection, 302bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth &normal)) { 303bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth this->addArc(normal); 304bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth 305bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth // close out previous arc 306a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth *fPositions.push() = fPrevPoint + normal; 307bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth *fColors.push() = fPenumbraColor; 30866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon *fIndices.push() = fPrevUmbraIndex; 309bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth *fIndices.push() = fPositions.count() - 2; 310bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth *fIndices.push() = fPositions.count() - 1; 311bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth 312bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth // add final edge 313a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth *fPositions.push() = fFirstPoint + normal; 314bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth *fColors.push() = fPenumbraColor; 315bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth 31666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon *fIndices.push() = fPrevUmbraIndex; 317bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth *fIndices.push() = fPositions.count() - 2; 318bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth *fIndices.push() = fFirstVertex; 319bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth 320bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth *fIndices.push() = fPositions.count() - 2; 321bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth *fIndices.push() = fPositions.count() - 1; 322bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth *fIndices.push() = fFirstVertex; 323bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth } 324bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth 325bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth // finalize centroid 326bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth if (fTransparent) { 327bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth fPositions[0] *= SkScalarFastInvert(fCentroidCount); 328bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth 329bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth *fIndices.push() = 0; 33066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon *fIndices.push() = fPrevUmbraIndex; 331bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth *fIndices.push() = fFirstVertex; 332bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth } 333bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth 334bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth // final fan 335bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth if (fPositions.count() >= 3) { 33666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon fPrevUmbraIndex = fFirstVertex; 337bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth fPrevNormal = normal; 338a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth fPrevPoint = fFirstPoint; 339bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth this->addArc(fFirstNormal); 340bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth 341bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth *fIndices.push() = fFirstVertex; 342bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth *fIndices.push() = fPositions.count() - 1; 343bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth *fIndices.push() = fFirstVertex + 1; 344bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth } 3450dda9cb881900241c1c2193ddf3bede72cda898bBrian Salomon fSucceeded = true; 346bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth} 347bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth 348efe3dedbb3493b738abdb56041b093245e4e8711Jim Van Verthvoid SkAmbientShadowTessellator::handleLine(const SkPoint& p) { 349bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth if (fInitPoints.count() < 2) { 350bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth *fInitPoints.push() = p; 351bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth return; 352bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth } 353bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth 354bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth if (fInitPoints.count() == 2) { 355bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth // determine if cw or ccw 356bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth SkVector v0 = fInitPoints[1] - fInitPoints[0]; 357bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth SkVector v1 = p - fInitPoints[0]; 358bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth SkScalar perpDot = v0.fX*v1.fY - v0.fY*v1.fX; 359bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth if (SkScalarNearlyZero(perpDot)) { 360bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth // nearly parallel, just treat as straight line and continue 361bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth fInitPoints[1] = p; 362bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth return; 363bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth } 364bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth 365bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth // if perpDot > 0, winding is ccw 366bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth fDirection = (perpDot > 0) ? -1 : 1; 367bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth 368bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth // add first quad 369bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth if (!compute_normal(fInitPoints[0], fInitPoints[1], fRadius, fDirection, 370bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth &fFirstNormal)) { 371bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth // first two points are incident, make the third point the second and continue 372bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth fInitPoints[1] = p; 373bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth return; 374bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth } 375bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth 376a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth fFirstPoint = fInitPoints[0]; 377bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth fFirstVertex = fPositions.count(); 378bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth fPrevNormal = fFirstNormal; 379a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth fPrevPoint = fFirstPoint; 38066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon fPrevUmbraIndex = fFirstVertex; 381bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth 382bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth *fPositions.push() = fInitPoints[0]; 383bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth *fColors.push() = fUmbraColor; 384bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth *fPositions.push() = fInitPoints[0] + fFirstNormal; 385bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth *fColors.push() = fPenumbraColor; 386bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth if (fTransparent) { 387bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth fPositions[0] += fInitPoints[0]; 388bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth fCentroidCount = 1; 389bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth } 390bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth this->addEdge(fInitPoints[1], fFirstNormal); 391bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth 392bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth // to ensure we skip this block next time 393bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth *fInitPoints.push() = p; 394bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth } 395bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth 396bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth SkVector normal; 39766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon if (compute_normal(fPositions[fPrevUmbraIndex], p, fRadius, fDirection, &normal)) { 398bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth this->addArc(normal); 39991af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth this->finishArcAndAddEdge(p, normal); 400bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth } 401bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth} 402bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth 403efe3dedbb3493b738abdb56041b093245e4e8711Jim Van Verthvoid SkAmbientShadowTessellator::addEdge(const SkPoint& nextPoint, const SkVector& nextNormal) { 404bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth // add next quad 405bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth *fPositions.push() = nextPoint; 406bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth *fColors.push() = fUmbraColor; 407bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth *fPositions.push() = nextPoint + nextNormal; 408bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth *fColors.push() = fPenumbraColor; 409bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth 41066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon *fIndices.push() = fPrevUmbraIndex; 411bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth *fIndices.push() = fPositions.count() - 3; 412bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth *fIndices.push() = fPositions.count() - 2; 413bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth 414bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth *fIndices.push() = fPositions.count() - 3; 415bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth *fIndices.push() = fPositions.count() - 1; 416bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth *fIndices.push() = fPositions.count() - 2; 417bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth 418bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth // if transparent, add point to first one in array and add to center fan 419bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth if (fTransparent) { 420bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth fPositions[0] += nextPoint; 421bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth ++fCentroidCount; 422bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth 423bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth *fIndices.push() = 0; 42466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon *fIndices.push() = fPrevUmbraIndex; 425bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth *fIndices.push() = fPositions.count() - 2; 426bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth } 427bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth 42866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon fPrevUmbraIndex = fPositions.count() - 2; 429bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth fPrevNormal = nextNormal; 430a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth fPrevPoint = nextPoint; 431bce7496d7dd9131cc7121389a55f6d512ee7661eJim Van Verth} 43291af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth 43391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth/////////////////////////////////////////////////////////////////////////////////////////////////// 43491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth 435aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomonclass SkSpotShadowTessellator : public SkBaseShadowTessellator { 436958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomonpublic: 437a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth SkSpotShadowTessellator(const SkPath& path, const SkMatrix& ctm, 438a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth SkScalar scale, const SkVector& translate, 439958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon SkScalar radius, SkColor umbraColor, SkColor penumbraColor, 440958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon bool transparent); 441958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon 442958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomonprivate: 443ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon void computeClipAndPathPolygons(const SkPath& path, const SkMatrix& ctm, 444ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon SkScalar scale, const SkVector& xlate); 445ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon void computeClipVectorsAndTestCentroid(); 44666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon bool clipUmbraPoint(const SkPoint& umbraPoint, const SkPoint& centroid, SkPoint* clipPoint); 447ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon int getClosestUmbraPoint(const SkPoint& point); 448958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon 449a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth void handleLine(const SkPoint& p) override; 450ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon void handlePolyPoint(const SkPoint& p); 451958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon 452958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon void mapPoints(SkScalar scale, const SkVector& xlate, SkPoint* pts, int count); 453ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon bool addInnerPoint(const SkPoint& pathPoint); 454a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth void addEdge(const SkVector& nextPoint, const SkVector& nextNormal) override; 455958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon 456958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon SkTDArray<SkPoint> fClipPolygon; 45766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon SkTDArray<SkVector> fClipVectors; 458a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth SkPoint fCentroid; 459ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon SkScalar fArea; 460a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth 461ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon SkTDArray<SkPoint> fPathPolygon; 462ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon SkTDArray<SkPoint> fUmbraPolygon; 463ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon int fCurrClipPoint; 464ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon int fCurrUmbraPoint; 46566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon bool fPrevUmbraOutside; 46666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon bool fFirstUmbraOutside; 467a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth bool fValidUmbra; 468958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon 469aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon typedef SkBaseShadowTessellator INHERITED; 470958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon}; 471958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon 472a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van VerthSkSpotShadowTessellator::SkSpotShadowTessellator(const SkPath& path, const SkMatrix& ctm, 47391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth SkScalar scale, const SkVector& translate, 474a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth SkScalar radius, SkColor umbraColor, 475a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth SkColor penumbraColor, bool transparent) 476a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth : INHERITED(radius, umbraColor, penumbraColor, transparent) 477ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon , fCurrClipPoint(0) 4780dda9cb881900241c1c2193ddf3bede72cda898bBrian Salomon , fPrevUmbraOutside(false) 4790dda9cb881900241c1c2193ddf3bede72cda898bBrian Salomon , fFirstUmbraOutside(false) 480a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth , fValidUmbra(true) { 481ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon // TODO: calculate these reserves better 48266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon // Penumbra ring: 3*numPts 48366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon // Umbra ring: numPts 48491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth // Inner ring: numPts 48566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon fPositions.setReserve(5 * path.countPoints()); 48666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon fColors.setReserve(5 * path.countPoints()); 48766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon // Penumbra ring: 12*numPts 48866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon // Umbra ring: 3*numPts 48966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon fIndices.setReserve(15 * path.countPoints()); 490e7c85c45c4c0a97adc6711bb12ecacc36af4ba11Brian Salomon fClipPolygon.setReserve(path.countPoints()); 491ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon 492ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon // compute rough clip bounds for umbra, plus offset polygon, plus centroid 493ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon this->computeClipAndPathPolygons(path, ctm, scale, translate); 494ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon if (fClipPolygon.count() < 3 || fPathPolygon.count() < 3) { 49566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon return; 49666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon } 49766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon 498ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon // check to see if umbra collapses 499ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon SkScalar minDistSq = fCentroid.distanceToLineSegmentBetweenSqd(fPathPolygon[0], 500ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon fPathPolygon[1]); 501ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon for (int i = 1; i < fPathPolygon.count(); ++i) { 502ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon int j = i + 1; 503ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon if (i == fPathPolygon.count() - 1) { 504ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon j = 0; 505ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon } 506ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon SkPoint currPoint = fPathPolygon[i]; 507ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon SkPoint nextPoint = fPathPolygon[j]; 508ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon SkScalar distSq = fCentroid.distanceToLineSegmentBetweenSqd(currPoint, nextPoint); 509ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon if (distSq < minDistSq) { 510ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon minDistSq = distSq; 511ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon } 512ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon } 513ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon static constexpr auto kTolerance = 1.0e-2f; 514ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon if (minDistSq < (radius + kTolerance)*(radius + kTolerance)) { 515ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon // if the umbra would collapse, we back off a bit on inner blur and adjust the alpha 516ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon SkScalar newRadius = SkScalarSqrt(minDistSq) - kTolerance; 517ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon SkScalar ratio = 256 * newRadius / radius; 518ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon // they aren't PMColors, but the interpolation algorithm is the same 519ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon fUmbraColor = SkPMLerp(fUmbraColor, fPenumbraColor, (unsigned)ratio); 520ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon radius = newRadius; 521ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon } 522e5f5bf5175e426ebb6aa234f4387831c898f20adJim Van Verth 523ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon // compute vectors for clip tests 524ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon this->computeClipVectorsAndTestCentroid(); 525ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon 526ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon // generate inner ring 527ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon if (!SkInsetConvexPolygon(&fPathPolygon[0], fPathPolygon.count(), radius, &fUmbraPolygon)) { 528ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon // this shouldn't happen, but just in case we'll inset using the centroid 529ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon fValidUmbra = false; 530ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon } 531ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon 532ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon // walk around the path polygon, generate outer ring and connect to inner ring 53366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon if (fTransparent) { 53466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon *fPositions.push() = fCentroid; 53566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon *fColors.push() = fUmbraColor; 53666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon } 537ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon fCurrUmbraPoint = 0; 538ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon for (int i = 0; i < fPathPolygon.count(); ++i) { 539ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon this->handlePolyPoint(fPathPolygon[i]); 54091af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth } 54191af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth 5420dda9cb881900241c1c2193ddf3bede72cda898bBrian Salomon if (!this->indexCount()) { 5430dda9cb881900241c1c2193ddf3bede72cda898bBrian Salomon return; 5440dda9cb881900241c1c2193ddf3bede72cda898bBrian Salomon } 5450dda9cb881900241c1c2193ddf3bede72cda898bBrian Salomon 546ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon // finish up the final verts 54791af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth SkVector normal; 548ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon if (compute_normal(fPrevPoint, fFirstPoint, fRadius, fDirection, &normal)) { 54991af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth this->addArc(normal); 55091af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth 55191af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth // close out previous arc 55291af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth *fPositions.push() = fPrevPoint + normal; 55391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth *fColors.push() = fPenumbraColor; 55466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon *fIndices.push() = fPrevUmbraIndex; 55591af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth *fIndices.push() = fPositions.count() - 2; 55691af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth *fIndices.push() = fPositions.count() - 1; 55791af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth 55866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon // add to center fan 55966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon if (fTransparent) { 56066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon *fIndices.push() = 0; 56166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon *fIndices.push() = fPrevUmbraIndex; 56266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon *fIndices.push() = fFirstVertex; 56366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon // or to clip ring 56466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon } else { 56566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon if (fFirstUmbraOutside) { 56666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon *fIndices.push() = fPrevUmbraIndex; 56766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon *fIndices.push() = fFirstVertex; 56866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon *fIndices.push() = fFirstVertex + 1; 56966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon if (fPrevUmbraOutside) { 57066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon // fill out quad 57166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon *fIndices.push() = fPrevUmbraIndex; 57266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon *fIndices.push() = fFirstVertex + 1; 57366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon *fIndices.push() = fPrevUmbraIndex + 1; 57466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon } 57566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon } else if (fPrevUmbraOutside) { 57666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon // add tri 57766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon *fIndices.push() = fPrevUmbraIndex; 57866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon *fIndices.push() = fFirstVertex; 57966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon *fIndices.push() = fPrevUmbraIndex + 1; 58066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon } 58166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon } 58266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon 58391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth // add final edge 58491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth *fPositions.push() = fFirstPoint + normal; 58591af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth *fColors.push() = fPenumbraColor; 58691af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth 58766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon *fIndices.push() = fPrevUmbraIndex; 58891af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth *fIndices.push() = fPositions.count() - 2; 58991af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth *fIndices.push() = fFirstVertex; 59091af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth 59191af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth *fIndices.push() = fPositions.count() - 2; 59291af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth *fIndices.push() = fPositions.count() - 1; 59391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth *fIndices.push() = fFirstVertex; 59491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth } 59591af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth 59691af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth // final fan 59791af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth if (fPositions.count() >= 3) { 59866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon fPrevUmbraIndex = fFirstVertex; 59991af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth fPrevPoint = fFirstPoint; 60091af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth fPrevNormal = normal; 60191af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth this->addArc(fFirstNormal); 60291af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth 60391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth *fIndices.push() = fFirstVertex; 60491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth *fIndices.push() = fPositions.count() - 1; 60566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon if (fFirstUmbraOutside) { 60666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon *fIndices.push() = fFirstVertex + 2; 60766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon } else { 60866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon *fIndices.push() = fFirstVertex + 1; 60966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon } 61091af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth } 6110dda9cb881900241c1c2193ddf3bede72cda898bBrian Salomon fSucceeded = true; 61291af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth} 61391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth 614ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomonvoid SkSpotShadowTessellator::computeClipAndPathPolygons(const SkPath& path, const SkMatrix& ctm, 615ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon SkScalar scale, const SkVector& xlate) { 616ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon // For the path polygon we are going to apply 'scale' and 'xlate' (in that order) to each 617ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon // computed path point. We want the effect to be to scale the points relative to the path 618ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon // bounds center and then translate them by the 'xlate' param we were passed. 619ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon SkPoint center = SkPoint::Make(path.getBounds().centerX(), path.getBounds().centerY()); 620ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon ctm.mapPoints(¢er, 1); 621ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon SkVector translate = center * (1.f - scale) + xlate; 622ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon SkMatrix shadowTransform; 623ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon shadowTransform.setScaleTranslate(scale, scale, translate.fX, translate.fY); 624ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon 625ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon fPathPolygon.setReserve(path.countPoints()); 626ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon 627ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon // Walk around the path and compute clip polygon and path polygon. 628ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon // Will also accumulate sum of areas for centroid. 629ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon // For Bezier curves, we compute additional interior points on curve. 63091af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth SkPath::Iter iter(path, true); 63191af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth SkPoint pts[4]; 63291af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth SkPath::Verb verb; 63391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth 634e7c85c45c4c0a97adc6711bb12ecacc36af4ba11Brian Salomon fClipPolygon.reset(); 635e5f5bf5175e426ebb6aa234f4387831c898f20adJim Van Verth 636ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon // init centroid 637ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon fCentroid = SkPoint::Make(0, 0); 638ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon fArea = 0; 639ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon 64066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon // coefficients to compute cubic Bezier at t = 5/16 641ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon static constexpr SkScalar kA = 0.32495117187f; 642ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon static constexpr SkScalar kB = 0.44311523437f; 643ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon static constexpr SkScalar kC = 0.20141601562f; 644ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon static constexpr SkScalar kD = 0.03051757812f; 64566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon 64666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon SkPoint curvePoint; 64766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon SkScalar w; 64891af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { 64991af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth switch (verb) { 65091af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth case SkPath::kLine_Verb: 651a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth ctm.mapPoints(&pts[1], 1); 65291af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth *fClipPolygon.push() = pts[1]; 653ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon this->INHERITED::handleLine(shadowTransform, &pts[1]); 65491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth break; 65591af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth case SkPath::kQuad_Verb: 656a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth ctm.mapPoints(pts, 3); 65766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon // point at t = 1/2 65866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon curvePoint.fX = 0.25f*pts[0].fX + 0.5f*pts[1].fX + 0.25f*pts[2].fX; 65966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon curvePoint.fY = 0.25f*pts[0].fY + 0.5f*pts[1].fY + 0.25f*pts[2].fY; 66066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon *fClipPolygon.push() = curvePoint; 66166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon *fClipPolygon.push() = pts[2]; 662ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon this->handleQuad(shadowTransform, pts); 66391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth break; 66491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth case SkPath::kConic_Verb: 665a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth ctm.mapPoints(pts, 3); 66666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon w = iter.conicWeight(); 667a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth // point at t = 1/2 66866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon curvePoint.fX = 0.25f*pts[0].fX + w*0.5f*pts[1].fX + 0.25f*pts[2].fX; 66966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon curvePoint.fY = 0.25f*pts[0].fY + w*0.5f*pts[1].fY + 0.25f*pts[2].fY; 67066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon curvePoint *= SkScalarInvert(0.5f + 0.5f*w); 67166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon *fClipPolygon.push() = curvePoint; 67266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon *fClipPolygon.push() = pts[2]; 673ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon this->handleConic(shadowTransform, pts, w); 67491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth break; 67591af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth case SkPath::kCubic_Verb: 676a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth ctm.mapPoints(pts, 4); 67766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon // point at t = 5/16 67866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon curvePoint.fX = kA*pts[0].fX + kB*pts[1].fX + kC*pts[2].fX + kD*pts[3].fX; 67966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon curvePoint.fY = kA*pts[0].fY + kB*pts[1].fY + kC*pts[2].fY + kD*pts[3].fY; 68066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon *fClipPolygon.push() = curvePoint; 68166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon // point at t = 11/16 68266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon curvePoint.fX = kD*pts[0].fX + kC*pts[1].fX + kB*pts[2].fX + kA*pts[3].fX; 68366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon curvePoint.fY = kD*pts[0].fY + kC*pts[1].fY + kB*pts[2].fY + kA*pts[3].fY; 68466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon *fClipPolygon.push() = curvePoint; 68566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon *fClipPolygon.push() = pts[3]; 686ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon this->handleCubic(shadowTransform, pts); 68791af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth break; 688ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon case SkPath::kMove_Verb: 68991af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth case SkPath::kClose_Verb: 690ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon case SkPath::kDone_Verb: 69191af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth break; 69291af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth default: 69391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth SkDEBUGFAIL("unknown verb"); 69491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth } 69591af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth } 69691af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth 697ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon // finish centroid 698ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon if (fPathPolygon.count() > 0) { 699ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon SkPoint currPoint = fPathPolygon[fPathPolygon.count() - 1]; 700ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon SkPoint nextPoint = fPathPolygon[0]; 701ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon SkScalar quadArea = currPoint.cross(nextPoint); 702ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon fCentroid.fX += (currPoint.fX + nextPoint.fX) * quadArea; 703ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon fCentroid.fY += (currPoint.fY + nextPoint.fY) * quadArea; 704ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon fArea += quadArea; 705ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon fCentroid *= SK_Scalar1 / (3 * fArea); 706ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon } 707ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon 708ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon fCurrClipPoint = fClipPolygon.count() - 1; 70966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon} 71066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon 711ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomonvoid SkSpotShadowTessellator::computeClipVectorsAndTestCentroid() { 71266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon SkASSERT(fClipPolygon.count() >= 3); 71366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon 714ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon // init clip vectors 71566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon SkVector v0 = fClipPolygon[1] - fClipPolygon[0]; 71666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon *fClipVectors.push() = v0; 71766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon 71866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon // init centroid check 71966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon bool hiddenCentroid = true; 720ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon SkVector v1 = fCentroid - fClipPolygon[0]; 72166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon SkScalar initCross = v0.cross(v1); 72266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon 72366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon for (int p = 1; p < fClipPolygon.count(); ++p) { 724ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon // add to clip vectors 72566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon v0 = fClipPolygon[(p + 1) % fClipPolygon.count()] - fClipPolygon[p]; 72666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon *fClipVectors.push() = v0; 72766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon // Determine if transformed centroid is inside clipPolygon. 728ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon v1 = fCentroid - fClipPolygon[p]; 72966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon if (initCross*v0.cross(v1) <= 0) { 73066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon hiddenCentroid = false; 73166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon } 73266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon } 73366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon SkASSERT(fClipVectors.count() == fClipPolygon.count()); 73466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon 735ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon fTransparent = fTransparent || !hiddenCentroid; 73666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon} 73766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon 73866085ed41779211f9e7e17aa493d4585d73445feBrian Salomonbool SkSpotShadowTessellator::clipUmbraPoint(const SkPoint& umbraPoint, const SkPoint& centroid, 73966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon SkPoint* clipPoint) { 74066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon SkVector segmentVector = centroid - umbraPoint; 74166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon 742ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon int startClipPoint = fCurrClipPoint; 74366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon do { 744ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon SkVector dp = umbraPoint - fClipPolygon[fCurrClipPoint]; 745ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon SkScalar denom = fClipVectors[fCurrClipPoint].cross(segmentVector); 74666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon SkScalar t_num = dp.cross(segmentVector); 74766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon // if line segments are nearly parallel 74866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon if (SkScalarNearlyZero(denom)) { 74966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon // and collinear 75066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon if (SkScalarNearlyZero(t_num)) { 75166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon return false; 75266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon } 75366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon // otherwise are separate, will try the next poly segment 75466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon // else if crossing lies within poly segment 75566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon } else if (t_num >= 0 && t_num <= denom) { 756ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon SkScalar s_num = dp.cross(fClipVectors[fCurrClipPoint]); 75766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon // if umbra point is inside the clip polygon 75866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon if (s_num < 0) { 75966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon return false; 76066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon } else { 76166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon segmentVector *= s_num/denom; 76266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon *clipPoint = umbraPoint + segmentVector; 76366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon return true; 76466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon } 76566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon } 766ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon fCurrClipPoint = (fCurrClipPoint + 1) % fClipPolygon.count(); 767ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon } while (fCurrClipPoint != startClipPoint); 76866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon 76966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon return false; 77091af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth} 77191af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth 772ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomonint SkSpotShadowTessellator::getClosestUmbraPoint(const SkPoint& p) { 773ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon SkScalar minDistance = p.distanceToSqd(fUmbraPolygon[fCurrUmbraPoint]); 774ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon int index = fCurrUmbraPoint; 775ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon int dir = 1; 776ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon int next = (index + dir) % fUmbraPolygon.count(); 777ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon 778ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon // init travel direction 779ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon SkScalar distance = p.distanceToSqd(fUmbraPolygon[next]); 780ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon if (distance < minDistance) { 781ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon index = next; 782ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon minDistance = distance; 783ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon } else { 784ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon dir = fUmbraPolygon.count()-1; 785ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon } 786ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon 787ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon // iterate until we find a point that increases the distance 788ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon next = (index + dir) % fUmbraPolygon.count(); 789ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon distance = p.distanceToSqd(fUmbraPolygon[next]); 790ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon while (distance < minDistance) { 791ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon index = next; 792ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon minDistance = distance; 793ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon next = (index + dir) % fUmbraPolygon.count(); 794ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon distance = p.distanceToSqd(fUmbraPolygon[next]); 795ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon } 796ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon 797ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon fCurrUmbraPoint = index; 798ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon return index; 799ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon} 800ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon 801efe3dedbb3493b738abdb56041b093245e4e8711Jim Van Verthvoid SkSpotShadowTessellator::mapPoints(SkScalar scale, const SkVector& xlate, 80291af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth SkPoint* pts, int count) { 80391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth // TODO: vectorize 80491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth for (int i = 0; i < count; ++i) { 80591af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth pts[i] *= scale; 80691af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth pts[i] += xlate; 80791af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth } 80891af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth} 80991af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth 810ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomonstatic bool duplicate_pt(const SkPoint& p0, const SkPoint& p1) { 811ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon static constexpr SkScalar kClose = (SK_Scalar1 / 16); 812ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon static constexpr SkScalar kCloseSqd = kClose*kClose; 813ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon 814ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon SkScalar distSq = p0.distanceToSqd(p1); 815ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon return distSq < kCloseSqd; 816ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon} 817ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon 818ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomonstatic bool is_collinear(const SkPoint& p0, const SkPoint& p1, const SkPoint& p2) { 819ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon SkVector v0 = p1 - p0; 820ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon SkVector v1 = p2 - p0; 821ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon return (SkScalarNearlyZero(v0.cross(v1))); 822ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon} 823ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon 824efe3dedbb3493b738abdb56041b093245e4e8711Jim Van Verthvoid SkSpotShadowTessellator::handleLine(const SkPoint& p) { 825ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon // remove coincident points and add to centroid 826ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon if (fPathPolygon.count() > 0) { 827ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon const SkPoint& lastPoint = fPathPolygon[fPathPolygon.count() - 1]; 828ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon if (duplicate_pt(p, lastPoint)) { 829ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon return; 830ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon } 831ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon SkScalar quadArea = lastPoint.cross(p); 832ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon fCentroid.fX += (p.fX + lastPoint.fX) * quadArea; 833ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon fCentroid.fY += (p.fY + lastPoint.fY) * quadArea; 834ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon fArea += quadArea; 835ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon } 836ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon 837ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon // try to remove collinear points 838ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon if (fPathPolygon.count() > 1 && is_collinear(fPathPolygon[fPathPolygon.count()-2], 839ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon fPathPolygon[fPathPolygon.count()-1], 840ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon p)) { 841ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon fPathPolygon[fPathPolygon.count() - 1] = p; 842ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon } else { 843ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon *fPathPolygon.push() = p; 844ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon } 845ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon} 846ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon 847ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomonvoid SkSpotShadowTessellator::handlePolyPoint(const SkPoint& p) { 84891af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth if (fInitPoints.count() < 2) { 84991af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth *fInitPoints.push() = p; 85091af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth return; 85191af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth } 85291af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth 85391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth if (fInitPoints.count() == 2) { 85491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth // determine if cw or ccw 85591af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth SkVector v0 = fInitPoints[1] - fInitPoints[0]; 85691af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth SkVector v1 = p - fInitPoints[0]; 857ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon SkScalar perpDot = v0.cross(v1); 85891af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth if (SkScalarNearlyZero(perpDot)) { 85991af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth // nearly parallel, just treat as straight line and continue 86091af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth fInitPoints[1] = p; 86191af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth return; 86291af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth } 86391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth 86491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth // if perpDot > 0, winding is ccw 86591af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth fDirection = (perpDot > 0) ? -1 : 1; 86691af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth 86791af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth // add first quad 86891af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth if (!compute_normal(fInitPoints[0], fInitPoints[1], fRadius, fDirection, 86991af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth &fFirstNormal)) { 87091af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth // first two points are incident, make the third point the second and continue 87191af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth fInitPoints[1] = p; 87291af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth return; 87391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth } 87491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth 87591af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth fFirstPoint = fInitPoints[0]; 87691af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth fFirstVertex = fPositions.count(); 87791af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth fPrevNormal = fFirstNormal; 87891af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth fPrevPoint = fFirstPoint; 87966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon fPrevUmbraIndex = fFirstVertex; 88066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon 88166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon this->addInnerPoint(fFirstPoint); 88266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon 88366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon if (!fTransparent) { 88466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon SkPoint clipPoint; 88566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon bool isOutside = this->clipUmbraPoint(fPositions[fFirstVertex], fCentroid, &clipPoint); 88666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon if (isOutside) { 88766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon *fPositions.push() = clipPoint; 88866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon *fColors.push() = fUmbraColor; 88966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon } 89066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon fPrevUmbraOutside = isOutside; 89166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon fFirstUmbraOutside = isOutside; 89266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon } 89391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth 89491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth SkPoint newPoint = fFirstPoint + fFirstNormal; 89591af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth *fPositions.push() = newPoint; 89691af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth *fColors.push() = fPenumbraColor; 89791af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth this->addEdge(fInitPoints[1], fFirstNormal); 89891af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth 89991af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth // to ensure we skip this block next time 90091af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth *fInitPoints.push() = p; 90191af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth } 90291af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth 90391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth SkVector normal; 90491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth if (compute_normal(fPrevPoint, p, fRadius, fDirection, &normal)) { 90591af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth this->addArc(normal); 90691af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth this->finishArcAndAddEdge(p, normal); 90791af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth } 90891af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth} 90991af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth 910ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomonbool SkSpotShadowTessellator::addInnerPoint(const SkPoint& pathPoint) { 911ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon SkPoint umbraPoint; 912ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon if (!fValidUmbra) { 913ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon SkVector v = fCentroid - pathPoint; 914ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon v *= 0.95f; 915ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon umbraPoint = pathPoint + v; 91691af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth } else { 917ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon umbraPoint = fUmbraPolygon[this->getClosestUmbraPoint(pathPoint)]; 91891af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth } 91966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon 92091af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth fPrevPoint = pathPoint; 921ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon 922ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon // merge "close" points 923ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon if (fPrevUmbraIndex == fFirstVertex || 924ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon !duplicate_pt(umbraPoint, fPositions[fPrevUmbraIndex])) { 925ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon *fPositions.push() = umbraPoint; 926ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon *fColors.push() = fUmbraColor; 927ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon 928ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon return false; 929ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon } else { 930ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon return true; 931ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon } 93291af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth} 93391af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth 934efe3dedbb3493b738abdb56041b093245e4e8711Jim Van Verthvoid SkSpotShadowTessellator::addEdge(const SkPoint& nextPoint, const SkVector& nextNormal) { 93566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon // add next umbra point 936ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon bool duplicate = this->addInnerPoint(nextPoint); 937ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon int prevPenumbraIndex = duplicate ? fPositions.count()-1 : fPositions.count()-2; 938ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon int currUmbraIndex = duplicate ? fPrevUmbraIndex : fPositions.count()-1; 93966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon 940ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon if (!duplicate) { 941ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon // add to center fan if transparent or centroid showing 942ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon if (fTransparent) { 943ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon *fIndices.push() = 0; 944ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon *fIndices.push() = fPrevUmbraIndex; 945ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon *fIndices.push() = currUmbraIndex; 946ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon // otherwise add to clip ring 947ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon } else { 94866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon SkPoint clipPoint; 949ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon bool isOutside = this->clipUmbraPoint(fPositions[currUmbraIndex], fCentroid, 950ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon &clipPoint); 95166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon if (isOutside) { 95266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon *fPositions.push() = clipPoint; 95366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon *fColors.push() = fUmbraColor; 95466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon 95566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon *fIndices.push() = fPrevUmbraIndex; 95666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon *fIndices.push() = currUmbraIndex; 95766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon *fIndices.push() = currUmbraIndex + 1; 95866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon if (fPrevUmbraOutside) { 95966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon // fill out quad 96066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon *fIndices.push() = fPrevUmbraIndex; 96166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon *fIndices.push() = currUmbraIndex + 1; 96266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon *fIndices.push() = fPrevUmbraIndex + 1; 96366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon } 96466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon } else if (fPrevUmbraOutside) { 96566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon // add tri 96666085ed41779211f9e7e17aa493d4585d73445feBrian Salomon *fIndices.push() = fPrevUmbraIndex; 96766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon *fIndices.push() = currUmbraIndex; 96866085ed41779211f9e7e17aa493d4585d73445feBrian Salomon *fIndices.push() = fPrevUmbraIndex + 1; 96966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon } 97066085ed41779211f9e7e17aa493d4585d73445feBrian Salomon fPrevUmbraOutside = isOutside; 97166085ed41779211f9e7e17aa493d4585d73445feBrian Salomon } 97266085ed41779211f9e7e17aa493d4585d73445feBrian Salomon } 97366085ed41779211f9e7e17aa493d4585d73445feBrian Salomon 97466085ed41779211f9e7e17aa493d4585d73445feBrian Salomon // add next penumbra point and quad 97591af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth SkPoint newPoint = nextPoint + nextNormal; 97691af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth *fPositions.push() = newPoint; 97791af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth *fColors.push() = fPenumbraColor; 97891af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth 979ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon if (!duplicate) { 980ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon *fIndices.push() = fPrevUmbraIndex; 981ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon *fIndices.push() = prevPenumbraIndex; 982ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon *fIndices.push() = currUmbraIndex; 983ab664fa5b5fb96dd1079c090534330ca7e8a10efBrian Salomon } 98491af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth 98566085ed41779211f9e7e17aa493d4585d73445feBrian Salomon *fIndices.push() = prevPenumbraIndex; 98691af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth *fIndices.push() = fPositions.count() - 1; 98766085ed41779211f9e7e17aa493d4585d73445feBrian Salomon *fIndices.push() = currUmbraIndex; 98891af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth 98966085ed41779211f9e7e17aa493d4585d73445feBrian Salomon fPrevUmbraIndex = currUmbraIndex; 99091af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth fPrevNormal = nextNormal; 99191af72703830f3946c538b47c6c7c96afc0adde2Jim Van Verth} 992958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon 993958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon/////////////////////////////////////////////////////////////////////////////////////////////////// 994958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon 995aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomonsk_sp<SkVertices> SkShadowTessellator::MakeAmbient(const SkPath& path, const SkMatrix& ctm, 996aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon SkScalar radius, SkColor umbra, SkColor penumbra, 997aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon bool transparent) { 998a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth SkAmbientShadowTessellator ambientTess(path, ctm, radius, umbra, penumbra, transparent); 999aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon return ambientTess.releaseVertices(); 1000958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon} 1001958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon 1002aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomonsk_sp<SkVertices> SkShadowTessellator::MakeSpot(const SkPath& path, const SkMatrix& ctm, 1003aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon SkScalar scale, const SkVector& translate, 1004aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon SkScalar radius, SkColor umbraColor, 1005aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon SkColor penumbraColor, bool transparent) { 1006a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth SkSpotShadowTessellator spotTess(path, ctm, scale, translate, radius, umbraColor, 1007a84898dbb8d8f7cb8c3e9bdfb4c31d85dff1922fJim Van Verth penumbraColor, transparent); 1008aff27a23ad4b38851429066dbfb43cfa7199e37cBrian Salomon return spotTess.releaseVertices(); 1009958fbc460a1e680c6a9979e140da8bfc00b8831dBrian Salomon} 1010