SampleAndroidShadows.cpp revision 37c5a96bbdeac2000c8b31d40f4786b31c39f2dd
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, zPlaneParams, 149 lightPos, lightWidth, 150 ambientAlpha, spotAlpha, SK_ColorBLACK, flags); 151 152 if (fShowObject) { 153 canvas->drawPath(path, paint); 154 } else { 155 SkPaint strokePaint; 156 157 strokePaint.setColor(paint.getColor()); 158 strokePaint.setStyle(SkPaint::kStroke_Style); 159 160 canvas->drawPath(path, strokePaint); 161 } 162 } 163 164 void onDrawContent(SkCanvas* canvas) override { 165 this->drawBG(canvas); 166 const SkScalar kLightWidth = 800; 167 const SkScalar kAmbientAlpha = 0.1f; 168 const SkScalar kSpotAlpha = 0.25f; 169 170 SkPaint paint; 171 paint.setAntiAlias(true); 172 173 SkPoint3 lightPos = fLightPos; 174 SkPoint3 zPlaneParams = SkPoint3::Make(0, 0, 0); 175 176 paint.setColor(SK_ColorWHITE); 177 canvas->translate(200, 90); 178 zPlaneParams.fZ = SkTMax(1.0f, 2 + fZDelta); 179 this->drawShadowedPath(canvas, fRRPath, zPlaneParams, paint, kAmbientAlpha, 180 lightPos, kLightWidth, kSpotAlpha); 181 182 paint.setColor(SK_ColorRED); 183 canvas->translate(250, 0); 184 zPlaneParams.fZ = SkTMax(1.0f, 8 + fZDelta); 185 this->drawShadowedPath(canvas, fRectPath, zPlaneParams, paint, kAmbientAlpha, 186 lightPos, kLightWidth, kSpotAlpha); 187 188 paint.setColor(SK_ColorBLUE); 189 canvas->translate(-250, 110); 190 zPlaneParams.fZ = SkTMax(1.0f, 12 + fZDelta); 191 this->drawShadowedPath(canvas, fCirclePath, zPlaneParams, paint, kAmbientAlpha, 192 lightPos, kLightWidth, 0.5f); 193 194 paint.setColor(SK_ColorGREEN); 195 canvas->translate(250, 0); 196 zPlaneParams.fZ = SkTMax(1.0f, 64 + fZDelta); 197 this->drawShadowedPath(canvas, fRRPath, zPlaneParams, paint, kAmbientAlpha, 198 lightPos, kLightWidth, kSpotAlpha); 199 200 paint.setColor(SK_ColorYELLOW); 201 canvas->translate(-250, 110); 202 zPlaneParams.fZ = SkTMax(1.0f, 8 + fZDelta); 203 this->drawShadowedPath(canvas, fFunkyRRPath, zPlaneParams, paint, kAmbientAlpha, 204 lightPos, kLightWidth, kSpotAlpha); 205 206 paint.setColor(SK_ColorCYAN); 207 canvas->translate(250, 0); 208 zPlaneParams.fZ = SkTMax(1.0f, 16 + fZDelta); 209 this->drawShadowedPath(canvas, fCubicPath, zPlaneParams, paint, 210 kAmbientAlpha, lightPos, kLightWidth, kSpotAlpha); 211 212 // circular reveal 213 SkPath tmpPath; 214 SkPath tmpClipPath; 215 tmpClipPath.addCircle(fAnimTranslate, 0, 60); 216 Op(fSquareRRectPath, tmpClipPath, kIntersect_SkPathOp, &tmpPath); 217 218 paint.setColor(SK_ColorMAGENTA); 219 canvas->translate(-125, 60); 220 zPlaneParams.fZ = SkTMax(1.0f, 32 + fZDelta); 221 this->drawShadowedPath(canvas, tmpPath, zPlaneParams, paint, .1f, 222 lightPos, kLightWidth, .5f); 223 224 // perspective paths 225 SkPoint pivot = SkPoint::Make(fWideRectPath.getBounds().width()/2, 226 fWideRectPath.getBounds().height()/2); 227 SkPoint translate = SkPoint::Make(100, 450); 228 paint.setColor(SK_ColorWHITE); 229 Sk3DView view; 230 view.save(); 231 view.rotateX(fAnimAngle); 232 SkMatrix persp; 233 view.getMatrix(&persp); 234 persp.preTranslate(-pivot.fX, -pivot.fY); 235 persp.postTranslate(pivot.fX + translate.fX, pivot.fY + translate.fY); 236 canvas->setMatrix(persp); 237 SkScalar radians = SkDegreesToRadians(fAnimAngle); 238 zPlaneParams = SkPoint3::Make(0, 239 SkScalarSin(-radians), 240 SkTMax(1.0f, 16 + fZDelta) - SkScalarSin(-radians)*pivot.fY); 241 this->drawShadowedPath(canvas, fWideRectPath, zPlaneParams, paint, .1f, 242 lightPos, kLightWidth, .5f); 243 244 pivot = SkPoint::Make(fWideOvalPath.getBounds().width() / 2, 245 fWideOvalPath.getBounds().height() / 2); 246 translate = SkPoint::Make(100, 600); 247 view.restore(); 248 view.rotateY(fAnimAngle); 249 view.getMatrix(&persp); 250 persp.preTranslate(-pivot.fX, -pivot.fY); 251 persp.postTranslate(pivot.fX + translate.fX, pivot.fY + translate.fY); 252 canvas->setMatrix(persp); 253 zPlaneParams = SkPoint3::Make(-SkScalarSin(radians), 254 0, 255 SkTMax(1.0f, 32 + fZDelta) + SkScalarSin(radians)*pivot.fX); 256 this->drawShadowedPath(canvas, fWideOvalPath, zPlaneParams, paint, .1f, 257 lightPos, kLightWidth, .5f); 258 } 259 260 bool onAnimate(const SkAnimTimer& timer) override { 261 fAnimTranslate = timer.pingPong(30, 0, 200, -200); 262 fAnimAngle = timer.pingPong(15, 0, 0, 20); 263 264 return true; 265 } 266 267private: 268 typedef SampleView INHERITED; 269}; 270 271////////////////////////////////////////////////////////////////////////////// 272 273static SkView* MyFactory() { return new ShadowsView; } 274static SkViewRegister reg(MyFactory); 275