Home | History | Annotate | Download | only in gm
      1 /*
      2  * Copyright 2017 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "gm.h"
      9 #include "SkCanvas.h"
     10 #include "SkPath.h"
     11 #include "SkResourceCache.h"
     12 #include "SkShadowUtils.h"
     13 
     14 void draw_shadow(SkCanvas* canvas, const SkPath& path, int height, SkColor color, SkPoint3 lightPos,
     15                  SkScalar lightR, bool isAmbient, uint32_t flags) {
     16     SkScalar ambientAlpha = isAmbient ? .5f : 0.f;
     17     SkScalar spotAlpha = isAmbient ? 0.f : .5f;
     18     SkShadowUtils::DrawShadow(canvas, path, height, lightPos, lightR, ambientAlpha, spotAlpha,
     19                               color, flags);
     20 }
     21 
     22 static constexpr int kW = 800;
     23 static constexpr int kH = 800;
     24 
     25 enum ShadowMode {
     26     kDebugColorNoOccluders,
     27     kDebugColorOccluders,
     28     kGrayscale
     29 };
     30 
     31 void draw_paths(SkCanvas* canvas, ShadowMode mode) {
     32     SkTArray<SkPath> paths;
     33     paths.push_back().addRoundRect(SkRect::MakeWH(50, 50), 10, 10);
     34     SkRRect oddRRect;
     35     oddRRect.setNinePatch(SkRect::MakeWH(50, 50), 9, 13, 6, 16);
     36     paths.push_back().addRRect(oddRRect);
     37     paths.push_back().addRect(SkRect::MakeWH(50, 50));
     38     paths.push_back().addCircle(25, 25, 25);
     39     paths.push_back().cubicTo(100, 50, 20, 100, 0, 0);
     40     paths.push_back().addOval(SkRect::MakeWH(20, 60));
     41 
     42     static constexpr SkScalar kPad = 15.f;
     43     static constexpr SkScalar kLightR = 100.f;
     44     static constexpr SkScalar kHeight = 50.f;
     45 
     46     // transform light position relative to canvas to handle tiling
     47     SkPoint lightXY = canvas->getTotalMatrix().mapXY(250, 400);
     48     SkPoint3 lightPos = { lightXY.fX, lightXY.fY, 500 };
     49 
     50     canvas->translate(3 * kPad, 3 * kPad);
     51     canvas->save();
     52     SkScalar x = 0;
     53     SkScalar dy = 0;
     54     SkTDArray<SkMatrix> matrices;
     55     matrices.push()->reset();
     56     SkMatrix* m = matrices.push();
     57     m->setRotate(33.f, 25.f, 25.f);
     58     m->postScale(1.2f, 0.8f, 25.f, 25.f);
     59     for (auto& m : matrices) {
     60         for (int flags : { kNone_ShadowFlag, kTransparentOccluder_ShadowFlag }) {
     61             for (const auto& path : paths) {
     62                 SkRect postMBounds = path.getBounds();
     63                 m.mapRect(&postMBounds);
     64                 SkScalar w = postMBounds.width() + kHeight;
     65                 SkScalar dx = w + kPad;
     66                 if (x + dx > kW - 3 * kPad) {
     67                     canvas->restore();
     68                     canvas->translate(0, dy);
     69                     canvas->save();
     70                     x = 0;
     71                     dy = 0;
     72                 }
     73 
     74                 canvas->save();
     75                 canvas->concat(m);
     76 
     77                 if (kDebugColorNoOccluders == mode || kDebugColorOccluders == mode) {
     78                     flags |= SkShadowFlags::kDisableTonalColor_ShadowFlag;
     79                     draw_shadow(canvas, path, kHeight, SK_ColorRED, lightPos, kLightR,
     80                                 true, flags);
     81                     draw_shadow(canvas, path, kHeight, SK_ColorBLUE, lightPos, kLightR,
     82                                 false, flags);
     83                 } else if (kGrayscale == mode) {
     84                     SkShadowUtils::DrawShadow(canvas, path, kHeight, lightPos, kLightR,
     85                                               0.1f, 0.25f, SK_ColorBLACK, flags);
     86                 }
     87 
     88                 SkPaint paint;
     89                 paint.setAntiAlias(true);
     90                 if (kDebugColorNoOccluders == mode) {
     91                     // Draw the path outline in green on top of the ambient and spot shadows.
     92                     if (SkToBool(flags & kTransparentOccluder_ShadowFlag)) {
     93                         paint.setColor(SK_ColorCYAN);
     94                     } else {
     95                         paint.setColor(SK_ColorGREEN);
     96                     }
     97                     paint.setStyle(SkPaint::kStroke_Style);
     98                     paint.setStrokeWidth(0);
     99                 } else {
    100                     paint.setColor(kDebugColorOccluders == mode ? SK_ColorLTGRAY : SK_ColorWHITE);
    101                     if (SkToBool(flags & kTransparentOccluder_ShadowFlag)) {
    102                         paint.setAlpha(128);
    103                     }
    104                     paint.setStyle(SkPaint::kFill_Style);
    105                 }
    106                 canvas->drawPath(path, paint);
    107                 canvas->restore();
    108 
    109                 canvas->translate(dx, 0);
    110                 x += dx;
    111                 dy = SkTMax(dy, postMBounds.height() + kPad + kHeight);
    112             }
    113         }
    114     }
    115     // Show where the light is in x,y as a circle (specified in device space).
    116     SkMatrix invCanvasM = canvas->getTotalMatrix();
    117     if (invCanvasM.invert(&invCanvasM)) {
    118         canvas->save();
    119         canvas->concat(invCanvasM);
    120         SkPaint paint;
    121         paint.setColor(SK_ColorBLACK);
    122         paint.setAntiAlias(true);
    123         canvas->drawCircle(lightPos.fX, lightPos.fY, kLightR / 10.f, paint);
    124         canvas->restore();
    125     }
    126 }
    127 
    128 DEF_SIMPLE_GM(shadow_utils, canvas, kW, kH) {
    129     draw_paths(canvas, kDebugColorNoOccluders);
    130 }
    131 
    132 DEF_SIMPLE_GM(shadow_utils_occl, canvas, kW, kH) {
    133     draw_paths(canvas, kDebugColorOccluders);
    134 }
    135 
    136 DEF_SIMPLE_GM(shadow_utils_gray, canvas, kW, kH) {
    137     draw_paths(canvas, kGrayscale);
    138 }
    139