SampleAndroidShadows.cpp revision e308a122ef996a64a21a6339e3b50b9edfdf654f
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 const SkPoint3& zPlaneParams, 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, zPlaneParams, 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 SkPoint3 zPlaneParams = SkPoint3::Make(0, 0, 0); 179 180 paint.setColor(SK_ColorWHITE); 181 canvas->translate(200, 90); 182 zPlaneParams.fZ = SkTMax(1.0f, 2 + fZDelta); 183 this->drawShadowedPath(canvas, fRRPath, zPlaneParams, paint, kAmbientAlpha, 184 lightPos, kLightWidth, kSpotAlpha); 185 186 paint.setColor(SK_ColorRED); 187 canvas->translate(250, 0); 188 zPlaneParams.fZ = SkTMax(1.0f, 8 + fZDelta); 189 this->drawShadowedPath(canvas, fRectPath, zPlaneParams, paint, kAmbientAlpha, 190 lightPos, kLightWidth, kSpotAlpha); 191 192 paint.setColor(SK_ColorBLUE); 193 canvas->translate(-250, 110); 194 zPlaneParams.fZ = SkTMax(1.0f, 12 + fZDelta); 195 this->drawShadowedPath(canvas, fCirclePath, zPlaneParams, paint, kAmbientAlpha, 196 lightPos, kLightWidth, 0.5f); 197 198 paint.setColor(SK_ColorGREEN); 199 canvas->translate(250, 0); 200 zPlaneParams.fZ = SkTMax(1.0f, 64 + fZDelta); 201 this->drawShadowedPath(canvas, fRRPath, zPlaneParams, paint, kAmbientAlpha, 202 lightPos, kLightWidth, kSpotAlpha); 203 204 paint.setColor(SK_ColorYELLOW); 205 canvas->translate(-250, 110); 206 zPlaneParams.fZ = SkTMax(1.0f, 8 + fZDelta); 207 this->drawShadowedPath(canvas, fFunkyRRPath, zPlaneParams, paint, kAmbientAlpha, 208 lightPos, kLightWidth, kSpotAlpha); 209 210 paint.setColor(SK_ColorCYAN); 211 canvas->translate(250, 0); 212 zPlaneParams.fZ = SkTMax(1.0f, 16 + fZDelta); 213 this->drawShadowedPath(canvas, fCubicPath, zPlaneParams, paint, 214 kAmbientAlpha, lightPos, kLightWidth, kSpotAlpha); 215 216 // circular reveal 217 SkPath tmpPath; 218 SkPath tmpClipPath; 219 tmpClipPath.addCircle(fAnimTranslate, 0, 60); 220 Op(fSquareRRectPath, tmpClipPath, kIntersect_SkPathOp, &tmpPath); 221 222 paint.setColor(SK_ColorMAGENTA); 223 canvas->translate(-125, 60); 224 zPlaneParams.fZ = SkTMax(1.0f, 32 + fZDelta); 225 this->drawShadowedPath(canvas, tmpPath, zPlaneParams, paint, .1f, 226 lightPos, kLightWidth, .5f); 227 228 // perspective paths 229 SkPoint pivot = SkPoint::Make(fWideRectPath.getBounds().width()/2, 230 fWideRectPath.getBounds().height()/2); 231 SkPoint translate = SkPoint::Make(100, 450); 232 paint.setColor(SK_ColorWHITE); 233 Sk3DView view; 234 view.save(); 235 view.rotateX(fAnimAngle); 236 SkMatrix persp; 237 view.getMatrix(&persp); 238 persp.preTranslate(-pivot.fX, -pivot.fY); 239 persp.postTranslate(pivot.fX + translate.fX, pivot.fY + translate.fY); 240 canvas->setMatrix(persp); 241 SkScalar radians = SkDegreesToRadians(fAnimAngle); 242 zPlaneParams = SkPoint3::Make(0, 243 SkScalarSin(-radians), 244 SkTMax(1.0f, 16 + fZDelta) - SkScalarSin(-radians)*pivot.fY); 245 this->drawShadowedPath(canvas, fWideRectPath, zPlaneParams, paint, .1f, 246 lightPos, kLightWidth, .5f); 247 248 pivot = SkPoint::Make(fWideOvalPath.getBounds().width() / 2, 249 fWideOvalPath.getBounds().height() / 2); 250 translate = SkPoint::Make(100, 600); 251 view.restore(); 252 view.rotateY(fAnimAngle); 253 view.getMatrix(&persp); 254 persp.preTranslate(-pivot.fX, -pivot.fY); 255 persp.postTranslate(pivot.fX + translate.fX, pivot.fY + translate.fY); 256 canvas->setMatrix(persp); 257 zPlaneParams = SkPoint3::Make(-SkScalarSin(radians), 258 0, 259 SkTMax(1.0f, 32 + fZDelta) + SkScalarSin(radians)*pivot.fX); 260 this->drawShadowedPath(canvas, fWideOvalPath, zPlaneParams, paint, .1f, 261 lightPos, kLightWidth, .5f); 262 } 263 264 bool onAnimate(const SkAnimTimer& timer) override { 265 fAnimTranslate = timer.pingPong(30, 0, 200, -200); 266 fAnimAngle = timer.pingPong(15, 0, 0, 20); 267 268 return true; 269 } 270 271private: 272 typedef SampleView INHERITED; 273}; 274 275////////////////////////////////////////////////////////////////////////////// 276 277static SkView* MyFactory() { return new ShadowsView; } 278static SkViewRegister reg(MyFactory); 279