SampleAndroidShadows.cpp revision e7705780c9450bb190abddc47a78b8b89784ed79
1 2/* 3 * Copyright 2016 Google Inc. 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8#include "SampleCode.h" 9#include "SkAnimTimer.h" 10#include "SkBlurMask.h" 11#include "SkBlurMaskFilter.h" 12#include "SkColorFilter.h" 13#include "SkCamera.h" 14#include "SkCanvas.h" 15#include "SkGaussianEdgeShader.h" 16#include "SkPath.h" 17#include "SkPathOps.h" 18#include "SkPoint3.h" 19#include "SkShadowUtils.h" 20#include "SkUtils.h" 21#include "SkView.h" 22#include "sk_tool_utils.h" 23 24//////////////////////////////////////////////////////////////////////////// 25 26class ShadowsView : public SampleView { 27 SkPath fRectPath; 28 SkPath fRRPath; 29 SkPath fCirclePath; 30 SkPath fFunkyRRPath; 31 SkPath fCubicPath; 32 SkPath fSquareRRectPath; 33 SkPath fWideRectPath; 34 SkPath fWideOvalPath; 35 SkPoint3 fLightPos; 36 SkScalar fZDelta; 37 SkScalar fAnimTranslate; 38 SkScalar fAnimAngle; 39 40 bool fShowAmbient; 41 bool fShowSpot; 42 bool fUseAlt; 43 bool fShowObject; 44 bool fIgnoreShadowAlpha; 45 46public: 47 ShadowsView() 48 : fZDelta(0) 49 , fAnimTranslate(0) 50 , fAnimAngle(0) 51 , fShowAmbient(true) 52 , fShowSpot(true) 53 , fUseAlt(false) 54 , fShowObject(true) 55 , fIgnoreShadowAlpha(false) {} 56 57protected: 58 void onOnceBeforeDraw() override { 59 fCirclePath.addCircle(0, 0, 50); 60 fRectPath.addRect(SkRect::MakeXYWH(-100, -50, 200, 100)); 61 fRRPath.addRRect(SkRRect::MakeRectXY(SkRect::MakeXYWH(-100, -50, 200, 100), 4, 4)); 62 fFunkyRRPath.addRoundRect(SkRect::MakeXYWH(-50, -50, SK_Scalar1 * 100, SK_Scalar1 * 100), 63 40 * SK_Scalar1, 20 * SK_Scalar1, 64 SkPath::kCW_Direction); 65 fCubicPath.cubicTo(100 * SK_Scalar1, 50 * SK_Scalar1, 66 20 * SK_Scalar1, 100 * SK_Scalar1, 67 0 * SK_Scalar1, 0 * SK_Scalar1); 68 fSquareRRectPath.addRRect(SkRRect::MakeRectXY(SkRect::MakeXYWH(-50, -50, 100, 100), 69 10, 10)); 70 fWideRectPath.addRect(SkRect::MakeXYWH(0, 0, 630, 70)); 71 fWideOvalPath.addOval(SkRect::MakeXYWH(0, 0, 630, 70)); 72 73 fLightPos = SkPoint3::Make(350, 0, 600); 74 } 75 76 // overrides from SkEventSink 77 bool onQuery(SkEvent* evt) override { 78 if (SampleCode::TitleQ(*evt)) { 79 SampleCode::TitleR(evt, "AndroidShadows"); 80 return true; 81 } 82 83 SkUnichar uni; 84 if (SampleCode::CharQ(*evt, &uni)) { 85 bool handled = false; 86 switch (uni) { 87 case 'W': 88 fShowAmbient = !fShowAmbient; 89 handled = true; 90 break; 91 case 'S': 92 fShowSpot = !fShowSpot; 93 handled = true; 94 break; 95 case 'T': 96 fUseAlt = !fUseAlt; 97 handled = true; 98 break; 99 case 'O': 100 fShowObject = !fShowObject; 101 handled = true; 102 break; 103 case '>': 104 fZDelta += 0.5f; 105 handled = true; 106 break; 107 case '<': 108 fZDelta -= 0.5f; 109 handled = true; 110 break; 111 case '?': 112 fIgnoreShadowAlpha = !fIgnoreShadowAlpha; 113 handled = true; 114 break; 115 default: 116 break; 117 } 118 if (handled) { 119 this->inval(nullptr); 120 return true; 121 } 122 } 123 return this->INHERITED::onQuery(evt); 124 } 125 126 void drawBG(SkCanvas* canvas) { 127 canvas->drawColor(0xFFDDDDDD); 128 } 129 130 void drawShadowedPath(SkCanvas* canvas, const SkPath& path, 131 std::function<SkScalar(SkScalar, SkScalar)> zFunc, 132 const SkPaint& paint, SkScalar ambientAlpha, 133 const SkPoint3& lightPos, SkScalar lightWidth, SkScalar spotAlpha) { 134 if (fIgnoreShadowAlpha) { 135 ambientAlpha = 255; 136 spotAlpha = 255; 137 } 138 if (!fShowAmbient) { 139 ambientAlpha = 0; 140 } 141 if (!fShowSpot) { 142 spotAlpha = 0; 143 } 144 uint32_t flags = 0; 145 if (fUseAlt) { 146 flags |= SkShadowFlags::kGeometricOnly_ShadowFlag; 147 } 148 //SkShadowUtils::DrawShadow(canvas, path, 149 // zValue, 150 // lightPos, lightWidth, 151 // ambientAlpha, spotAlpha, SK_ColorBLACK, flags); 152 SkShadowUtils::DrawUncachedShadow(canvas, path, zFunc, 153 lightPos, lightWidth, 154 ambientAlpha, spotAlpha, SK_ColorBLACK, flags); 155 156 if (fShowObject) { 157 canvas->drawPath(path, paint); 158 } else { 159 SkPaint strokePaint; 160 161 strokePaint.setColor(paint.getColor()); 162 strokePaint.setStyle(SkPaint::kStroke_Style); 163 164 canvas->drawPath(path, strokePaint); 165 } 166 } 167 168 void onDrawContent(SkCanvas* canvas) override { 169 this->drawBG(canvas); 170 const SkScalar kLightWidth = 800; 171 const SkScalar kAmbientAlpha = 0.1f; 172 const SkScalar kSpotAlpha = 0.25f; 173 174 SkPaint paint; 175 paint.setAntiAlias(true); 176 177 SkPoint3 lightPos = fLightPos; 178 179 paint.setColor(SK_ColorWHITE); 180 canvas->translate(200, 90); 181 SkScalar zValue = SkTMax(1.0f, 2 + fZDelta); 182 std::function<SkScalar(SkScalar, SkScalar)> zFunc = 183 [zValue](SkScalar, SkScalar) { return zValue; }; 184 this->drawShadowedPath(canvas, fRRPath, zFunc, paint, kAmbientAlpha, 185 lightPos, kLightWidth, kSpotAlpha); 186 187 paint.setColor(SK_ColorRED); 188 canvas->translate(250, 0); 189 zValue = SkTMax(1.0f, 8 + fZDelta); 190 zFunc = [zValue](SkScalar, SkScalar) { return zValue; }; 191 this->drawShadowedPath(canvas, fRectPath, zFunc, paint, kAmbientAlpha, 192 lightPos, kLightWidth, kSpotAlpha); 193 194 paint.setColor(SK_ColorBLUE); 195 canvas->translate(-250, 110); 196 zValue = SkTMax(1.0f, 12 + fZDelta); 197 zFunc = [zValue](SkScalar, SkScalar) { return zValue; }; 198 this->drawShadowedPath(canvas, fCirclePath, zFunc, paint, kAmbientAlpha, 199 lightPos, kLightWidth, 0.5f); 200 201 paint.setColor(SK_ColorGREEN); 202 canvas->translate(250, 0); 203 zValue = SkTMax(1.0f, 64 + fZDelta); 204 zFunc = [zValue](SkScalar, SkScalar) { return zValue; }; 205 this->drawShadowedPath(canvas, fRRPath, zFunc, paint, kAmbientAlpha, 206 lightPos, kLightWidth, kSpotAlpha); 207 208 paint.setColor(SK_ColorYELLOW); 209 canvas->translate(-250, 110); 210 zValue = SkTMax(1.0f, 8 + fZDelta); 211 zFunc = [zValue](SkScalar, SkScalar) { return zValue; }; 212 this->drawShadowedPath(canvas, fFunkyRRPath, zFunc, paint, kAmbientAlpha, 213 lightPos, kLightWidth, kSpotAlpha); 214 215 paint.setColor(SK_ColorCYAN); 216 canvas->translate(250, 0); 217 zValue = SkTMax(1.0f, 16 + fZDelta); 218 zFunc = [zValue](SkScalar, SkScalar) { return zValue; }; 219 this->drawShadowedPath(canvas, fCubicPath, zFunc, paint, 220 kAmbientAlpha, lightPos, kLightWidth, kSpotAlpha); 221 222 // circular reveal 223 SkPath tmpPath; 224 SkPath tmpClipPath; 225 tmpClipPath.addCircle(fAnimTranslate, 0, 60); 226 Op(fSquareRRectPath, tmpClipPath, kIntersect_SkPathOp, &tmpPath); 227 228 paint.setColor(SK_ColorMAGENTA); 229 canvas->translate(-125, 60); 230 zValue = SkTMax(1.0f, 32 + fZDelta); 231 zFunc = [zValue](SkScalar, SkScalar) { return zValue; }; 232 this->drawShadowedPath(canvas, tmpPath, zFunc, paint, .1f, 233 lightPos, kLightWidth, .5f); 234 235 // perspective paths 236 SkPoint pivot = SkPoint::Make(fWideRectPath.getBounds().width()/2, 237 fWideRectPath.getBounds().height()/2); 238 SkPoint translate = SkPoint::Make(100, 450); 239 paint.setColor(SK_ColorWHITE); 240 Sk3DView view; 241 view.save(); 242 view.rotateX(fAnimAngle); 243 SkMatrix persp; 244 view.getMatrix(&persp); 245 persp.preTranslate(-pivot.fX, -pivot.fY); 246 persp.postTranslate(pivot.fX + translate.fX, pivot.fY + translate.fY); 247 canvas->setMatrix(persp); 248 zValue = SkTMax(1.0f, 16 + fZDelta); 249 SkScalar radians = SkDegreesToRadians(fAnimAngle); 250 zFunc = [zValue, pivot, radians](SkScalar x, SkScalar y) { 251 return SkScalarSin(-radians)*y + 252 zValue - SkScalarSin(-radians)*pivot.fY; 253 }; 254 this->drawShadowedPath(canvas, fWideRectPath, zFunc, paint, .1f, 255 lightPos, kLightWidth, .5f); 256 257 pivot = SkPoint::Make(fWideOvalPath.getBounds().width() / 2, 258 fWideOvalPath.getBounds().height() / 2); 259 translate = SkPoint::Make(100, 600); 260 view.restore(); 261 view.rotateY(fAnimAngle); 262 view.getMatrix(&persp); 263 persp.preTranslate(-pivot.fX, -pivot.fY); 264 persp.postTranslate(pivot.fX + translate.fX, pivot.fY + translate.fY); 265 canvas->setMatrix(persp); 266 zValue = SkTMax(1.0f, 32 + fZDelta); 267 zFunc = [zValue, pivot, radians](SkScalar x, SkScalar y) { 268 return -SkScalarSin(radians)*x + 269 zValue + SkScalarSin(radians)*pivot.fX; 270 }; 271 this->drawShadowedPath(canvas, fWideOvalPath, zFunc, paint, .1f, 272 lightPos, kLightWidth, .5f); 273 } 274 275 bool onAnimate(const SkAnimTimer& timer) override { 276 fAnimTranslate = timer.pingPong(30, 0, 200, -200); 277 fAnimAngle = timer.pingPong(15, 0, 0, 20); 278 279 return true; 280 } 281 282private: 283 typedef SampleView INHERITED; 284}; 285 286////////////////////////////////////////////////////////////////////////////// 287 288static SkView* MyFactory() { return new ShadowsView; } 289static SkViewRegister reg(MyFactory); 290