1cb93a386Sopenharmony_ci 2cb93a386Sopenharmony_ci/* 3cb93a386Sopenharmony_ci * Copyright 2017 Google Inc. 4cb93a386Sopenharmony_ci * 5cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 6cb93a386Sopenharmony_ci * found in the LICENSE file. 7cb93a386Sopenharmony_ci */ 8cb93a386Sopenharmony_ci#include "include/core/SkCanvas.h" 9cb93a386Sopenharmony_ci#include "include/core/SkColorFilter.h" 10cb93a386Sopenharmony_ci#include "include/core/SkPath.h" 11cb93a386Sopenharmony_ci#include "include/core/SkPoint3.h" 12cb93a386Sopenharmony_ci#include "include/pathops/SkPathOps.h" 13cb93a386Sopenharmony_ci#include "include/utils/SkCamera.h" 14cb93a386Sopenharmony_ci#include "include/utils/SkShadowUtils.h" 15cb93a386Sopenharmony_ci#include "samplecode/Sample.h" 16cb93a386Sopenharmony_ci#include "src/core/SkBlurMask.h" 17cb93a386Sopenharmony_ci#include "src/utils/SkUTF.h" 18cb93a386Sopenharmony_ci#include "tools/ToolUtils.h" 19cb93a386Sopenharmony_ci 20cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////////////////// 21cb93a386Sopenharmony_ci 22cb93a386Sopenharmony_ciclass ShadowUtilsView : public Sample { 23cb93a386Sopenharmony_ci SkTArray<SkPath> fConvexPaths; 24cb93a386Sopenharmony_ci SkTArray<SkPath> fConcavePaths; 25cb93a386Sopenharmony_ci SkScalar fZDelta; 26cb93a386Sopenharmony_ci 27cb93a386Sopenharmony_ci bool fShowAmbient; 28cb93a386Sopenharmony_ci bool fShowSpot; 29cb93a386Sopenharmony_ci bool fUseAlt; 30cb93a386Sopenharmony_ci bool fShowObject; 31cb93a386Sopenharmony_ci bool fIgnoreShadowAlpha; 32cb93a386Sopenharmony_ci 33cb93a386Sopenharmony_cipublic: 34cb93a386Sopenharmony_ci ShadowUtilsView() 35cb93a386Sopenharmony_ci : fZDelta(0) 36cb93a386Sopenharmony_ci , fShowAmbient(true) 37cb93a386Sopenharmony_ci , fShowSpot(true) 38cb93a386Sopenharmony_ci , fUseAlt(false) 39cb93a386Sopenharmony_ci , fShowObject(false) 40cb93a386Sopenharmony_ci , fIgnoreShadowAlpha(false) {} 41cb93a386Sopenharmony_ci 42cb93a386Sopenharmony_ciprotected: 43cb93a386Sopenharmony_ci void onOnceBeforeDraw() override { 44cb93a386Sopenharmony_ci fConvexPaths.push_back().addRoundRect(SkRect::MakeWH(50, 50), 10, 10); 45cb93a386Sopenharmony_ci SkRRect oddRRect; 46cb93a386Sopenharmony_ci oddRRect.setNinePatch(SkRect::MakeWH(50, 50), 9, 13, 6, 16); 47cb93a386Sopenharmony_ci fConvexPaths.push_back().addRRect(oddRRect); 48cb93a386Sopenharmony_ci fConvexPaths.push_back().addRect(SkRect::MakeWH(50, 50)); 49cb93a386Sopenharmony_ci fConvexPaths.push_back().addCircle(25, 25, 25); 50cb93a386Sopenharmony_ci fConvexPaths.push_back().cubicTo(100, 50, 20, 100, 0, 0); 51cb93a386Sopenharmony_ci fConvexPaths.push_back().addOval(SkRect::MakeWH(20, 60)); 52cb93a386Sopenharmony_ci 53cb93a386Sopenharmony_ci // star 54cb93a386Sopenharmony_ci fConcavePaths.push_back().moveTo(0.0f, -33.3333f); 55cb93a386Sopenharmony_ci fConcavePaths.back().lineTo(9.62f, -16.6667f); 56cb93a386Sopenharmony_ci fConcavePaths.back().lineTo(28.867f, -16.6667f); 57cb93a386Sopenharmony_ci fConcavePaths.back().lineTo(19.24f, 0.0f); 58cb93a386Sopenharmony_ci fConcavePaths.back().lineTo(28.867f, 16.6667f); 59cb93a386Sopenharmony_ci fConcavePaths.back().lineTo(9.62f, 16.6667f); 60cb93a386Sopenharmony_ci fConcavePaths.back().lineTo(0.0f, 33.3333f); 61cb93a386Sopenharmony_ci fConcavePaths.back().lineTo(-9.62f, 16.6667f); 62cb93a386Sopenharmony_ci fConcavePaths.back().lineTo(-28.867f, 16.6667f); 63cb93a386Sopenharmony_ci fConcavePaths.back().lineTo(-19.24f, 0.0f); 64cb93a386Sopenharmony_ci fConcavePaths.back().lineTo(-28.867f, -16.6667f); 65cb93a386Sopenharmony_ci fConcavePaths.back().lineTo(-9.62f, -16.6667f); 66cb93a386Sopenharmony_ci fConcavePaths.back().close(); 67cb93a386Sopenharmony_ci 68cb93a386Sopenharmony_ci // dumbbell 69cb93a386Sopenharmony_ci fConcavePaths.push_back().moveTo(50, 0); 70cb93a386Sopenharmony_ci fConcavePaths.back().cubicTo(100, 25, 60, 50, 50, 0); 71cb93a386Sopenharmony_ci fConcavePaths.back().cubicTo(0, -25, 40, -50, 50, 0); 72cb93a386Sopenharmony_ci } 73cb93a386Sopenharmony_ci 74cb93a386Sopenharmony_ci SkString name() override { return SkString("ShadowUtils"); } 75cb93a386Sopenharmony_ci 76cb93a386Sopenharmony_ci bool onChar(SkUnichar uni) override { 77cb93a386Sopenharmony_ci bool handled = false; 78cb93a386Sopenharmony_ci switch (uni) { 79cb93a386Sopenharmony_ci case 'W': 80cb93a386Sopenharmony_ci fShowAmbient = !fShowAmbient; 81cb93a386Sopenharmony_ci handled = true; 82cb93a386Sopenharmony_ci break; 83cb93a386Sopenharmony_ci case 'S': 84cb93a386Sopenharmony_ci fShowSpot = !fShowSpot; 85cb93a386Sopenharmony_ci handled = true; 86cb93a386Sopenharmony_ci break; 87cb93a386Sopenharmony_ci case 'T': 88cb93a386Sopenharmony_ci fUseAlt = !fUseAlt; 89cb93a386Sopenharmony_ci handled = true; 90cb93a386Sopenharmony_ci break; 91cb93a386Sopenharmony_ci case 'O': 92cb93a386Sopenharmony_ci fShowObject = !fShowObject; 93cb93a386Sopenharmony_ci handled = true; 94cb93a386Sopenharmony_ci break; 95cb93a386Sopenharmony_ci case '>': 96cb93a386Sopenharmony_ci fZDelta += 0.5f; 97cb93a386Sopenharmony_ci handled = true; 98cb93a386Sopenharmony_ci break; 99cb93a386Sopenharmony_ci case '<': 100cb93a386Sopenharmony_ci fZDelta -= 0.5f; 101cb93a386Sopenharmony_ci handled = true; 102cb93a386Sopenharmony_ci break; 103cb93a386Sopenharmony_ci case '?': 104cb93a386Sopenharmony_ci fIgnoreShadowAlpha = !fIgnoreShadowAlpha; 105cb93a386Sopenharmony_ci handled = true; 106cb93a386Sopenharmony_ci break; 107cb93a386Sopenharmony_ci default: 108cb93a386Sopenharmony_ci break; 109cb93a386Sopenharmony_ci } 110cb93a386Sopenharmony_ci if (handled) { 111cb93a386Sopenharmony_ci return true; 112cb93a386Sopenharmony_ci } 113cb93a386Sopenharmony_ci return false; 114cb93a386Sopenharmony_ci } 115cb93a386Sopenharmony_ci 116cb93a386Sopenharmony_ci void drawBG(SkCanvas* canvas) { 117cb93a386Sopenharmony_ci canvas->drawColor(0xFFFFFFFF); 118cb93a386Sopenharmony_ci } 119cb93a386Sopenharmony_ci 120cb93a386Sopenharmony_ci void drawShadowedPath(SkCanvas* canvas, const SkPath& path, 121cb93a386Sopenharmony_ci const SkPoint3& zPlaneParams, 122cb93a386Sopenharmony_ci const SkPaint& paint, SkScalar ambientAlpha, 123cb93a386Sopenharmony_ci const SkPoint3& lightPos, SkScalar lightWidth, SkScalar spotAlpha, 124cb93a386Sopenharmony_ci uint32_t flags) { 125cb93a386Sopenharmony_ci if (fIgnoreShadowAlpha) { 126cb93a386Sopenharmony_ci ambientAlpha = 255; 127cb93a386Sopenharmony_ci spotAlpha = 255; 128cb93a386Sopenharmony_ci } 129cb93a386Sopenharmony_ci if (!fShowAmbient) { 130cb93a386Sopenharmony_ci ambientAlpha = 0; 131cb93a386Sopenharmony_ci } 132cb93a386Sopenharmony_ci if (!fShowSpot) { 133cb93a386Sopenharmony_ci spotAlpha = 0; 134cb93a386Sopenharmony_ci } 135cb93a386Sopenharmony_ci if (fUseAlt) { 136cb93a386Sopenharmony_ci flags |= SkShadowFlags::kGeometricOnly_ShadowFlag; 137cb93a386Sopenharmony_ci } 138cb93a386Sopenharmony_ci 139cb93a386Sopenharmony_ci SkColor ambientColor = SkColorSetARGB(ambientAlpha * 255, 255, 0, 0); 140cb93a386Sopenharmony_ci SkColor spotColor = SkColorSetARGB(spotAlpha * 255, 0, 0, 255); 141cb93a386Sopenharmony_ci SkShadowUtils::DrawShadow(canvas, path, zPlaneParams, 142cb93a386Sopenharmony_ci lightPos, lightWidth, 143cb93a386Sopenharmony_ci ambientColor, spotColor, flags); 144cb93a386Sopenharmony_ci 145cb93a386Sopenharmony_ci if (fShowObject) { 146cb93a386Sopenharmony_ci canvas->drawPath(path, paint); 147cb93a386Sopenharmony_ci } else { 148cb93a386Sopenharmony_ci SkPaint strokePaint; 149cb93a386Sopenharmony_ci 150cb93a386Sopenharmony_ci strokePaint.setColor(paint.getColor()); 151cb93a386Sopenharmony_ci strokePaint.setStyle(SkPaint::kStroke_Style); 152cb93a386Sopenharmony_ci 153cb93a386Sopenharmony_ci canvas->drawPath(path, strokePaint); 154cb93a386Sopenharmony_ci } 155cb93a386Sopenharmony_ci } 156cb93a386Sopenharmony_ci 157cb93a386Sopenharmony_ci void onDrawContent(SkCanvas* canvas) override { 158cb93a386Sopenharmony_ci this->drawBG(canvas); 159cb93a386Sopenharmony_ci 160cb93a386Sopenharmony_ci static constexpr int kW = 800; 161cb93a386Sopenharmony_ci static constexpr SkScalar kPad = 15.f; 162cb93a386Sopenharmony_ci static constexpr SkScalar kLightR = 100.f; 163cb93a386Sopenharmony_ci static constexpr SkScalar kHeight = 50.f; 164cb93a386Sopenharmony_ci static constexpr SkScalar kAmbientAlpha = 0.5f; 165cb93a386Sopenharmony_ci static constexpr SkScalar kSpotAlpha = 0.5f; 166cb93a386Sopenharmony_ci static constexpr SkPoint3 lightPos = { 250, 400, 500 }; 167cb93a386Sopenharmony_ci 168cb93a386Sopenharmony_ci canvas->translate(3 * kPad, 3 * kPad); 169cb93a386Sopenharmony_ci canvas->save(); 170cb93a386Sopenharmony_ci SkScalar x = 0; 171cb93a386Sopenharmony_ci SkScalar dy = 0; 172cb93a386Sopenharmony_ci SkTDArray<SkMatrix> matrices; 173cb93a386Sopenharmony_ci matrices.push()->reset(); 174cb93a386Sopenharmony_ci matrices.push()->setRotate(33.f, 25.f, 25.f).postScale(1.2f, 0.8f, 25.f, 25.f); 175cb93a386Sopenharmony_ci SkPaint greenPaint; 176cb93a386Sopenharmony_ci greenPaint.setColor(SK_ColorGREEN); 177cb93a386Sopenharmony_ci greenPaint.setAntiAlias(true); 178cb93a386Sopenharmony_ci SkPoint3 zPlaneParams = SkPoint3::Make(0, 0, std::max(1.0f, kHeight + fZDelta)); 179cb93a386Sopenharmony_ci 180cb93a386Sopenharmony_ci // convex paths 181cb93a386Sopenharmony_ci for (auto& m : matrices) { 182cb93a386Sopenharmony_ci for (auto flags : { kNone_ShadowFlag, kTransparentOccluder_ShadowFlag }) { 183cb93a386Sopenharmony_ci for (const auto& path : fConvexPaths) { 184cb93a386Sopenharmony_ci SkRect postMBounds = path.getBounds(); 185cb93a386Sopenharmony_ci m.mapRect(&postMBounds); 186cb93a386Sopenharmony_ci SkScalar w = postMBounds.width() + kHeight; 187cb93a386Sopenharmony_ci SkScalar dx = w + kPad; 188cb93a386Sopenharmony_ci if (x + dx > kW - 3 * kPad) { 189cb93a386Sopenharmony_ci canvas->restore(); 190cb93a386Sopenharmony_ci canvas->translate(0, dy); 191cb93a386Sopenharmony_ci canvas->save(); 192cb93a386Sopenharmony_ci x = 0; 193cb93a386Sopenharmony_ci dy = 0; 194cb93a386Sopenharmony_ci } 195cb93a386Sopenharmony_ci 196cb93a386Sopenharmony_ci canvas->save(); 197cb93a386Sopenharmony_ci canvas->concat(m); 198cb93a386Sopenharmony_ci this->drawShadowedPath(canvas, path, zPlaneParams, greenPaint, kAmbientAlpha, 199cb93a386Sopenharmony_ci lightPos, kLightR, kSpotAlpha, flags); 200cb93a386Sopenharmony_ci canvas->restore(); 201cb93a386Sopenharmony_ci 202cb93a386Sopenharmony_ci canvas->translate(dx, 0); 203cb93a386Sopenharmony_ci x += dx; 204cb93a386Sopenharmony_ci dy = std::max(dy, postMBounds.height() + kPad + kHeight); 205cb93a386Sopenharmony_ci } 206cb93a386Sopenharmony_ci } 207cb93a386Sopenharmony_ci } 208cb93a386Sopenharmony_ci 209cb93a386Sopenharmony_ci // concave paths 210cb93a386Sopenharmony_ci canvas->restore(); 211cb93a386Sopenharmony_ci canvas->translate(kPad, dy); 212cb93a386Sopenharmony_ci canvas->save(); 213cb93a386Sopenharmony_ci x = kPad; 214cb93a386Sopenharmony_ci dy = 0; 215cb93a386Sopenharmony_ci for (auto& m : matrices) { 216cb93a386Sopenharmony_ci for (const auto& path : fConcavePaths) { 217cb93a386Sopenharmony_ci SkRect postMBounds = path.getBounds(); 218cb93a386Sopenharmony_ci m.mapRect(&postMBounds); 219cb93a386Sopenharmony_ci SkScalar w = postMBounds.width(); 220cb93a386Sopenharmony_ci SkScalar dx = w + kPad; 221cb93a386Sopenharmony_ci 222cb93a386Sopenharmony_ci canvas->save(); 223cb93a386Sopenharmony_ci canvas->concat(m); 224cb93a386Sopenharmony_ci this->drawShadowedPath(canvas, path, zPlaneParams, greenPaint, kAmbientAlpha, 225cb93a386Sopenharmony_ci lightPos, kLightR, kSpotAlpha, kNone_ShadowFlag); 226cb93a386Sopenharmony_ci canvas->restore(); 227cb93a386Sopenharmony_ci 228cb93a386Sopenharmony_ci canvas->translate(dx, 0); 229cb93a386Sopenharmony_ci x += dx; 230cb93a386Sopenharmony_ci dy = std::max(dy, postMBounds.height() + kPad + kHeight); 231cb93a386Sopenharmony_ci } 232cb93a386Sopenharmony_ci } 233cb93a386Sopenharmony_ci 234cb93a386Sopenharmony_ci // Show where the light is in x,y as a circle (specified in device space). 235cb93a386Sopenharmony_ci SkMatrix invCanvasM = canvas->getTotalMatrix(); 236cb93a386Sopenharmony_ci if (invCanvasM.invert(&invCanvasM)) { 237cb93a386Sopenharmony_ci canvas->save(); 238cb93a386Sopenharmony_ci canvas->concat(invCanvasM); 239cb93a386Sopenharmony_ci SkPaint blackPaint; 240cb93a386Sopenharmony_ci blackPaint.setColor(SK_ColorBLACK); 241cb93a386Sopenharmony_ci blackPaint.setAntiAlias(true); 242cb93a386Sopenharmony_ci canvas->drawCircle(lightPos.fX, lightPos.fY, kLightR / 10.f, blackPaint); 243cb93a386Sopenharmony_ci canvas->restore(); 244cb93a386Sopenharmony_ci } 245cb93a386Sopenharmony_ci } 246cb93a386Sopenharmony_ci 247cb93a386Sopenharmony_ciprivate: 248cb93a386Sopenharmony_ci using INHERITED = Sample; 249cb93a386Sopenharmony_ci}; 250cb93a386Sopenharmony_ci 251cb93a386Sopenharmony_ci////////////////////////////////////////////////////////////////////////////// 252cb93a386Sopenharmony_ci 253cb93a386Sopenharmony_ciDEF_SAMPLE( return new ShadowUtilsView(); ) 254