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 void draw_paths(SkCanvas* canvas, bool hideOccluders) {
     26     SkTArray<SkPath> paths;
     27     paths.push_back().addRoundRect(SkRect::MakeWH(50, 50), 10, 10);
     28     SkRRect oddRRect;
     29     oddRRect.setNinePatch(SkRect::MakeWH(50, 50), 9, 13, 6, 16);
     30     paths.push_back().addRRect(oddRRect);
     31     paths.push_back().addRect(SkRect::MakeWH(50, 50));
     32     paths.push_back().addCircle(25, 25, 25);
     33     paths.push_back().cubicTo(100, 50, 20, 100, 0, 0);
     34     paths.push_back().addOval(SkRect::MakeWH(20, 60));
     35 
     36     static constexpr SkScalar kPad = 15.f;
     37     static constexpr SkScalar kLightR = 100.f;
     38     static constexpr SkScalar kHeight = 50.f;
     39 
     40     // transform light position relative to canvas to handle tiling
     41     SkPoint lightXY = canvas->getTotalMatrix().mapXY(250, 400);
     42     SkPoint3 lightPos = { lightXY.fX, lightXY.fY, 500 };
     43 
     44     canvas->translate(3 * kPad, 3 * kPad);
     45     canvas->save();
     46     SkScalar x = 0;
     47     SkScalar dy = 0;
     48     SkTDArray<SkMatrix> matrices;
     49     matrices.push()->reset();
     50     SkMatrix* m = matrices.push();
     51     m->setRotate(33.f, 25.f, 25.f);
     52     m->postScale(1.2f, 0.8f, 25.f, 25.f);
     53     for (auto& m : matrices) {
     54         for (auto flags : { kNone_ShadowFlag, kTransparentOccluder_ShadowFlag }) {
     55             for (const auto& path : paths) {
     56                 SkRect postMBounds = path.getBounds();
     57                 m.mapRect(&postMBounds);
     58                 SkScalar w = postMBounds.width() + kHeight;
     59                 SkScalar dx = w + kPad;
     60                 if (x + dx > kW - 3 * kPad) {
     61                     canvas->restore();
     62                     canvas->translate(0, dy);
     63                     canvas->save();
     64                     x = 0;
     65                     dy = 0;
     66                 }
     67 
     68                 canvas->save();
     69                 canvas->concat(m);
     70                 draw_shadow(canvas, path, kHeight, SK_ColorRED, lightPos, kLightR, true, flags);
     71                 draw_shadow(canvas, path, kHeight, SK_ColorBLUE, lightPos, kLightR, false, flags);
     72 
     73                 // Draw the path outline in green on top of the ambient and spot shadows.
     74                 SkPaint paint;
     75                 paint.setAntiAlias(true);
     76                 if (hideOccluders) {
     77                     if (SkToBool(flags & kTransparentOccluder_ShadowFlag)) {
     78                         paint.setColor(SK_ColorCYAN);
     79                     } else {
     80                         paint.setColor(SK_ColorGREEN);
     81                     }
     82                     paint.setStyle(SkPaint::kStroke_Style);
     83                     paint.setStrokeWidth(0);
     84                 } else {
     85                     paint.setColor(SK_ColorLTGRAY);
     86                     if (SkToBool(flags & kTransparentOccluder_ShadowFlag)) {
     87                         paint.setAlpha(128);
     88                     }
     89                     paint.setStyle(SkPaint::kFill_Style);
     90                 }
     91                 canvas->drawPath(path, paint);
     92                 canvas->restore();
     93 
     94                 canvas->translate(dx, 0);
     95                 x += dx;
     96                 dy = SkTMax(dy, postMBounds.height() + kPad + kHeight);
     97             }
     98         }
     99     }
    100     // Show where the light is in x,y as a circle (specified in device space).
    101     SkMatrix invCanvasM = canvas->getTotalMatrix();
    102     if (invCanvasM.invert(&invCanvasM)) {
    103         canvas->save();
    104         canvas->concat(invCanvasM);
    105         SkPaint paint;
    106         paint.setColor(SK_ColorBLACK);
    107         paint.setAntiAlias(true);
    108         canvas->drawCircle(lightPos.fX, lightPos.fY, kLightR / 10.f, paint);
    109         canvas->restore();
    110     }
    111 }
    112 
    113 DEF_SIMPLE_GM(shadow_utils, canvas, kW, kH) {
    114     draw_paths(canvas, true);
    115 }
    116 
    117 DEF_SIMPLE_GM(shadow_utils_occl, canvas, kW, kH) {
    118     draw_paths(canvas, false);
    119 }
    120