1 2 /* 3 * Copyright 2017 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 "include/core/SkCanvas.h" 9 #include "include/core/SkImage.h" 10 #include "include/core/SkPath.h" 11 #include "include/core/SkPoint3.h" 12 #include "include/utils/SkShadowUtils.h" 13 #include "samplecode/Sample.h" 14 #include "tools/Resources.h" 15 16 //////////////////////////////////////////////////////////////////////////// 17 // Sample to compare the Material Design shadow reference to our results 18 19 class ShadowRefView : public Sample { 20 SkPath fRRectPath; 21 sk_sp<SkImage> fReferenceImage; 22 23 bool fShowAmbient; 24 bool fShowSpot; 25 bool fUseAlt; 26 bool fShowObject; 27 28 public: ShadowRefView()29 ShadowRefView() 30 : fShowAmbient(true) 31 , fShowSpot(true) 32 , fUseAlt(false) 33 , fShowObject(true) {} 34 35 protected: onOnceBeforeDraw()36 void onOnceBeforeDraw() override { 37 fRRectPath.addRRect(SkRRect::MakeRectXY(SkRect::MakeXYWH(-130, -128.5, 130, 128.5), 4, 4)); 38 fReferenceImage = GetResourceAsImage("images/shadowreference.png"); 39 } 40 name()41 SkString name() override { return SkString("ShadowReference"); } 42 onChar(SkUnichar uni)43 bool onChar(SkUnichar uni) override { 44 bool handled = false; 45 switch (uni) { 46 case 'W': 47 fShowAmbient = !fShowAmbient; 48 handled = true; 49 break; 50 case 'S': 51 fShowSpot = !fShowSpot; 52 handled = true; 53 break; 54 case 'T': 55 fUseAlt = !fUseAlt; 56 handled = true; 57 break; 58 case 'O': 59 fShowObject = !fShowObject; 60 handled = true; 61 break; 62 default: 63 break; 64 } 65 if (handled) { 66 return true; 67 } 68 return false; 69 } 70 drawBG(SkCanvas * canvas)71 void drawBG(SkCanvas* canvas) { 72 canvas->drawColor(0xFFFFFFFF); 73 canvas->drawImage(fReferenceImage, 10, 30); 74 } 75 drawShadowedPath(SkCanvas * canvas,const SkPath & path,const SkPoint3 & zPlaneParams,const SkPaint & paint,SkScalar ambientAlpha,const SkPoint3 & lightPos,SkScalar lightWidth,SkScalar spotAlpha)76 void drawShadowedPath(SkCanvas* canvas, const SkPath& path, 77 const SkPoint3& zPlaneParams, 78 const SkPaint& paint, SkScalar ambientAlpha, 79 const SkPoint3& lightPos, SkScalar lightWidth, SkScalar spotAlpha) { 80 if (!fShowAmbient) { 81 ambientAlpha = 0; 82 } 83 if (!fShowSpot) { 84 spotAlpha = 0; 85 } 86 uint32_t flags = 0; 87 if (fUseAlt) { 88 flags |= SkShadowFlags::kGeometricOnly_ShadowFlag; 89 } 90 91 SkColor ambientColor = SkColorSetARGB(ambientAlpha * 255, 0, 0, 0); 92 SkColor spotColor = SkColorSetARGB(spotAlpha * 255, 0, 0, 0); 93 SkShadowUtils::DrawShadow(canvas, path, zPlaneParams, 94 lightPos, lightWidth, 95 ambientColor, spotColor, flags); 96 97 if (fShowObject) { 98 canvas->drawPath(path, paint); 99 } else { 100 SkPaint strokePaint; 101 102 strokePaint.setColor(paint.getColor()); 103 strokePaint.setStyle(SkPaint::kStroke_Style); 104 105 canvas->drawPath(path, strokePaint); 106 } 107 } 108 onDrawContent(SkCanvas * canvas)109 void onDrawContent(SkCanvas* canvas) override { 110 this->drawBG(canvas); 111 const SkScalar kDP = 4; // the reference image is 4x bigger than it is displayed on 112 // on the web page, so we need to reflect that here and 113 // multiply the heights and light params accordingly 114 const SkScalar kLightWidth = kDP*400; 115 const SkScalar kAmbientAlpha = 0.03f; 116 const SkScalar kSpotAlpha = 0.35f; 117 118 SkPaint paint; 119 paint.setAntiAlias(true); 120 paint.setColor(SK_ColorWHITE); 121 122 SkPoint3 lightPos = { 175, -800, kDP * 600 }; 123 SkScalar xPos = 230; 124 SkScalar yPos = 254.25f; 125 SkRect clipRect = SkRect::MakeXYWH(45, 75, 122, 250); 126 SkPoint clipDelta = SkPoint::Make(320, 0); 127 SkPoint3 zPlaneParams = SkPoint3::Make(0, 0, kDP * 2); 128 129 canvas->save(); 130 canvas->clipRect(clipRect); 131 canvas->translate(xPos, yPos); 132 this->drawShadowedPath(canvas, fRRectPath, zPlaneParams, paint, kAmbientAlpha, 133 lightPos, kLightWidth, kSpotAlpha); 134 canvas->restore(); 135 136 lightPos.fX += 320; 137 xPos += 320; 138 clipRect.offset(clipDelta); 139 zPlaneParams.fZ = kDP * 3; 140 canvas->save(); 141 canvas->clipRect(clipRect); 142 canvas->translate(xPos, yPos); 143 this->drawShadowedPath(canvas, fRRectPath, zPlaneParams, paint, kAmbientAlpha, 144 lightPos, kLightWidth, kSpotAlpha); 145 canvas->restore(); 146 147 lightPos.fX += 320; 148 xPos += 320; 149 clipRect.offset(clipDelta); 150 zPlaneParams.fZ = kDP * 4; 151 canvas->save(); 152 canvas->clipRect(clipRect); 153 canvas->translate(xPos, yPos); 154 this->drawShadowedPath(canvas, fRRectPath, zPlaneParams, paint, kAmbientAlpha, 155 lightPos, kLightWidth, kSpotAlpha); 156 canvas->restore(); 157 158 lightPos.fX += 320; 159 xPos += 320; 160 clipRect.offset(clipDelta); 161 zPlaneParams.fZ = kDP * 6; 162 canvas->save(); 163 canvas->clipRect(clipRect); 164 canvas->translate(xPos, yPos); 165 this->drawShadowedPath(canvas, fRRectPath, zPlaneParams, paint, kAmbientAlpha, 166 lightPos, kLightWidth, kSpotAlpha); 167 canvas->restore(); 168 169 lightPos.fX += 320; 170 xPos += 320; 171 clipRect.offset(clipDelta); 172 zPlaneParams.fZ = kDP * 8; 173 canvas->save(); 174 canvas->clipRect(clipRect); 175 canvas->translate(xPos, yPos); 176 this->drawShadowedPath(canvas, fRRectPath, zPlaneParams, paint, kAmbientAlpha, 177 lightPos, kLightWidth, kSpotAlpha); 178 canvas->restore(); 179 180 lightPos.fX += 320; 181 xPos += 320; 182 clipRect.offset(clipDelta); 183 zPlaneParams.fZ = kDP * 16; 184 canvas->save(); 185 canvas->clipRect(clipRect); 186 canvas->translate(xPos, yPos); 187 this->drawShadowedPath(canvas, fRRectPath, zPlaneParams, paint, kAmbientAlpha, 188 lightPos, kLightWidth, kSpotAlpha); 189 canvas->restore(); 190 191 } 192 193 private: 194 using INHERITED = Sample; 195 }; 196 197 ////////////////////////////////////////////////////////////////////////////// 198 199 DEF_SAMPLE( return new ShadowRefView(); ) 200