Home | History | Annotate | Download | only in samplecode
      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 "SkPath.h"
     16 #include "SkPathOps.h"
     17 #include "SkPoint3.h"
     18 #include "SkShadowUtils.h"
     19 #include "SkUtils.h"
     20 #include "SkView.h"
     21 #include "sk_tool_utils.h"
     22 
     23 ////////////////////////////////////////////////////////////////////////////
     24 
     25 class ShadowsView : public SampleView {
     26     SkPath    fRectPath;
     27     SkPath    fRRPath;
     28     SkPath    fCirclePath;
     29     SkPath    fFunkyRRPath;
     30     SkPath    fCubicPath;
     31     SkPath    fSquareRRectPath;
     32     SkPath    fWideRectPath;
     33     SkPath    fWideOvalPath;
     34     SkPoint3  fLightPos;
     35     SkScalar  fZDelta;
     36     SkScalar  fAnimTranslate;
     37     SkScalar  fAnimAngle;
     38 
     39     bool      fShowAmbient;
     40     bool      fShowSpot;
     41     bool      fUseAlt;
     42     bool      fShowObject;
     43     bool      fIgnoreShadowAlpha;
     44 
     45 public:
     46     ShadowsView()
     47         : fZDelta(0)
     48         , fAnimTranslate(0)
     49         , fAnimAngle(0)
     50         , fShowAmbient(true)
     51         , fShowSpot(true)
     52         , fUseAlt(false)
     53         , fShowObject(true)
     54         , fIgnoreShadowAlpha(false) {}
     55 
     56 protected:
     57     void onOnceBeforeDraw() override {
     58         fCirclePath.addCircle(0, 0, 50);
     59         fRectPath.addRect(SkRect::MakeXYWH(-100, -50, 200, 100));
     60         fRRPath.addRRect(SkRRect::MakeRectXY(SkRect::MakeXYWH(-100, -50, 200, 100), 4, 4));
     61         fFunkyRRPath.addRoundRect(SkRect::MakeXYWH(-50, -50, SK_Scalar1 * 100, SK_Scalar1 * 100),
     62                                   40 * SK_Scalar1, 20 * SK_Scalar1,
     63                                   SkPath::kCW_Direction);
     64         fCubicPath.cubicTo(100 * SK_Scalar1, 50 * SK_Scalar1,
     65                            20 * SK_Scalar1, 100 * SK_Scalar1,
     66                            0 * SK_Scalar1, 0 * SK_Scalar1);
     67         fSquareRRectPath.addRRect(SkRRect::MakeRectXY(SkRect::MakeXYWH(-50, -50, 100, 100),
     68                                                       10, 10));
     69         fWideRectPath.addRect(SkRect::MakeXYWH(0, 0, 630, 70));
     70         fWideOvalPath.addOval(SkRect::MakeXYWH(0, 0, 630, 70));
     71 
     72         fLightPos = SkPoint3::Make(350, 0, 600);
     73     }
     74 
     75     // overrides from SkEventSink
     76     bool onQuery(SkEvent* evt) override {
     77         if (SampleCode::TitleQ(*evt)) {
     78             SampleCode::TitleR(evt, "AndroidShadows");
     79             return true;
     80         }
     81 
     82         SkUnichar uni;
     83         if (SampleCode::CharQ(*evt, &uni)) {
     84             bool handled = false;
     85             switch (uni) {
     86                 case 'W':
     87                     fShowAmbient = !fShowAmbient;
     88                     handled = true;
     89                     break;
     90                 case 'S':
     91                     fShowSpot = !fShowSpot;
     92                     handled = true;
     93                     break;
     94                 case 'T':
     95                     fUseAlt = !fUseAlt;
     96                     handled = true;
     97                     break;
     98                 case 'O':
     99                     fShowObject = !fShowObject;
    100                     handled = true;
    101                     break;
    102                 case '>':
    103                     fZDelta += 0.5f;
    104                     handled = true;
    105                     break;
    106                 case '<':
    107                     fZDelta -= 0.5f;
    108                     handled = true;
    109                     break;
    110                 case '?':
    111                     fIgnoreShadowAlpha = !fIgnoreShadowAlpha;
    112                     handled = true;
    113                     break;
    114                 default:
    115                     break;
    116             }
    117             if (handled) {
    118                 this->inval(nullptr);
    119                 return true;
    120             }
    121         }
    122         return this->INHERITED::onQuery(evt);
    123     }
    124 
    125     void drawBG(SkCanvas* canvas) {
    126         canvas->drawColor(0xFFDDDDDD);
    127     }
    128 
    129     void drawShadowedPath(SkCanvas* canvas, const SkPath& path,
    130                           const SkPoint3& zPlaneParams,
    131                           const SkPaint& paint, SkScalar ambientAlpha,
    132                           const SkPoint3& lightPos, SkScalar lightWidth, SkScalar spotAlpha) {
    133         if (fIgnoreShadowAlpha) {
    134             ambientAlpha = 255;
    135             spotAlpha = 255;
    136         }
    137         if (!fShowAmbient) {
    138             ambientAlpha = 0;
    139         }
    140         if (!fShowSpot) {
    141             spotAlpha = 0;
    142         }
    143         uint32_t flags = 0;
    144         if (fUseAlt) {
    145             flags |= SkShadowFlags::kGeometricOnly_ShadowFlag;
    146         }
    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 
    267 private:
    268     typedef SampleView INHERITED;
    269 };
    270 
    271 //////////////////////////////////////////////////////////////////////////////
    272 
    273 static SkView* MyFactory() { return new ShadowsView; }
    274 static SkViewRegister reg(MyFactory);
    275