Home | History | Annotate | Download | only in gm
      1 /*
      2  * Copyright 2016 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 "sk_tool_utils.h"
     10 #include "SkLightingShader.h"
     11 #include "SkNormalSource.h"
     12 #include "SkPoint3.h"
     13 #include "SkShader.h"
     14 
     15 // Create a truncated pyramid normal map
     16 static SkBitmap make_frustum_normalmap(int texSize) {
     17     SkBitmap frustum;
     18     frustum.allocN32Pixels(texSize, texSize);
     19 
     20     sk_tool_utils::create_frustum_normal_map(&frustum, SkIRect::MakeWH(texSize, texSize));
     21     return frustum;
     22 }
     23 
     24 namespace skiagm {
     25 
     26 // This GM exercises lighting shaders. Specifically, nullptr arguments, scaling when using
     27 // normal maps, paint transparency, zero directional lights, multiple directional lights.
     28 class LightingShader2GM : public GM {
     29 public:
     30     LightingShader2GM() {
     31         this->setBGColor(sk_tool_utils::color_to_565(0xFFCCCCCC));
     32     }
     33 
     34 protected:
     35     SkString onShortName() override {
     36         return SkString("lightingshader2");
     37     }
     38 
     39     SkISize onISize() override {
     40         return SkISize::Make(600, 740);
     41     }
     42 
     43     void onOnceBeforeDraw() override {
     44         const SkVector3 kLightFromUpperRight = SkVector3::Make(0.788f, 0.394f, 0.473f);
     45         const SkVector3 kLightFromUpperLeft = SkVector3::Make(-0.788f, 0.394f, 0.473f);
     46 
     47         // Standard set of lights
     48         SkLights::Builder builder;
     49         builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 1.0f, 1.0f),
     50                                                      kLightFromUpperRight));
     51         builder.setAmbientLightColor(SkColor3f::Make(0.2f, 0.2f, 0.2f));
     52         fLights = builder.finish();
     53 
     54         // No directional lights
     55         SkLights::Builder builderNoDir;
     56         builderNoDir.setAmbientLightColor(SkColor3f::Make(0.2f, 0.2f, 0.2f));
     57         fLightsNoDir = builderNoDir.finish();
     58 
     59         // Two directional lights
     60         SkLights::Builder builderTwoDir;
     61         builderTwoDir.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 0.0f, 1.0f),
     62                                                            kLightFromUpperRight));
     63         builderTwoDir.add(SkLights::Light::MakeDirectional(SkColor3f::Make(0.0f, 1.0f, 1.0f),
     64                                                            kLightFromUpperLeft));
     65         builderTwoDir.setAmbientLightColor(SkColor3f::Make(0.2f, 0.2f, 0.2f));
     66         fLightsTwoDir = builderTwoDir.finish();
     67 
     68         fRect = SkRect::MakeIWH(kTexSize, kTexSize);
     69         SkMatrix matrix;
     70         SkRect bitmapBounds = SkRect::MakeIWH(kTexSize, kTexSize);
     71         matrix.setRectToRect(bitmapBounds, fRect, SkMatrix::kFill_ScaleToFit);
     72 
     73         SkBitmap opaqueDiffuseMap = sk_tool_utils::create_checkerboard_bitmap(
     74                 kTexSize, kTexSize,
     75                 sk_tool_utils::color_to_565(0x0),
     76                 sk_tool_utils::color_to_565(0xFF804020),
     77                 8);
     78         fOpaqueDiffuse = SkShader::MakeBitmapShader(opaqueDiffuseMap, SkShader::kClamp_TileMode,
     79                                                     SkShader::kClamp_TileMode, &matrix);
     80 
     81         SkBitmap translucentDiffuseMap = sk_tool_utils::create_checkerboard_bitmap(
     82                 kTexSize, kTexSize,
     83                 SkColorSetARGB(0x55, 0x00, 0x00, 0x00),
     84                 SkColorSetARGB(0x55, 0x80, 0x40, 0x20),
     85                 8);
     86         fTranslucentDiffuse = SkShader::MakeBitmapShader(translucentDiffuseMap,
     87                                                          SkShader::kClamp_TileMode,
     88                                                          SkShader::kClamp_TileMode, &matrix);
     89 
     90         SkBitmap normalMap = make_frustum_normalmap(kTexSize);
     91         fNormalMapShader = SkShader::MakeBitmapShader(normalMap, SkShader::kClamp_TileMode,
     92                                                       SkShader::kClamp_TileMode, &matrix);
     93 
     94     }
     95 
     96     // Scales shape around origin, rotates shape around origin, then translates shape to origin
     97     void positionCTM(SkCanvas *canvas, SkScalar scaleX, SkScalar scaleY, SkScalar rotate) const {
     98         canvas->translate(kTexSize/2.0f, kTexSize/2.0f);
     99         canvas->scale(scaleX, scaleY);
    100         canvas->rotate(rotate);
    101         canvas->translate(-kTexSize/2.0f, -kTexSize/2.0f);
    102     }
    103 
    104     static constexpr int NUM_BOOLEAN_PARAMS = 4;
    105     void drawRect(SkCanvas* canvas, SkScalar scaleX, SkScalar scaleY,
    106                   SkScalar rotate, bool useNormalSource, bool useDiffuseShader,
    107                   bool useTranslucentPaint, bool useTranslucentShader, sk_sp<SkLights> lights) {
    108         canvas->save();
    109 
    110         this->positionCTM(canvas, scaleX, scaleY, rotate);
    111 
    112         const SkMatrix& ctm = canvas->getTotalMatrix();
    113 
    114         SkPaint paint;
    115         sk_sp<SkNormalSource> normalSource = nullptr;
    116         sk_sp<SkShader> diffuseShader = nullptr;
    117 
    118         if (useNormalSource) {
    119             normalSource = SkNormalSource::MakeFromNormalMap(fNormalMapShader, ctm);
    120         }
    121 
    122         if (useDiffuseShader) {
    123             diffuseShader = (useTranslucentShader) ? fTranslucentDiffuse : fOpaqueDiffuse;
    124         } else {
    125             paint.setColor(0xFF00FF00);
    126         }
    127 
    128         if (useTranslucentPaint) {
    129             paint.setAlpha(0x99);
    130         }
    131 
    132         paint.setShader(SkLightingShader::Make(std::move(diffuseShader), std::move(normalSource),
    133                                                std::move(lights)));
    134         canvas->drawRect(fRect, paint);
    135 
    136         canvas->restore();
    137     }
    138 
    139     void onDraw(SkCanvas* canvas) override {
    140 
    141         constexpr SkScalar LABEL_SIZE = 10.0f;
    142         SkPaint labelPaint;
    143         labelPaint.setTypeface(sk_tool_utils::create_portable_typeface("sans-serif",
    144                                                                        SkFontStyle()));
    145         labelPaint.setAntiAlias(true);
    146         labelPaint.setTextSize(LABEL_SIZE);
    147 
    148         constexpr int GRID_COLUMN_NUM = 4;
    149         constexpr SkScalar GRID_CELL_WIDTH = kTexSize + 20.0f + NUM_BOOLEAN_PARAMS * LABEL_SIZE;
    150 
    151         int gridNum = 0;
    152 
    153         // Running through all possible bool parameter combinations
    154         for (bool useNormalSource : {true, false}) {
    155             for (bool useDiffuseShader : {true, false}) {
    156                 for (bool useTranslucentPaint : {true, false}) {
    157                     for (bool useTranslucentShader : {true, false}) {
    158 
    159                         // Determining position
    160                         SkScalar xPos = (gridNum % GRID_COLUMN_NUM) * GRID_CELL_WIDTH;
    161                         SkScalar yPos = (gridNum / GRID_COLUMN_NUM) * GRID_CELL_WIDTH;
    162 
    163                         canvas->save();
    164 
    165                         canvas->translate(xPos, yPos);
    166                         this->drawRect(canvas, 1.0f, 1.0f, 0.f, useNormalSource, useDiffuseShader,
    167                                        useTranslucentPaint, useTranslucentShader, fLights);
    168                         // Drawing labels
    169                         canvas->translate(0.0f, SkIntToScalar(kTexSize));
    170                         {
    171                             canvas->translate(0.0f, LABEL_SIZE);
    172                             SkString label;
    173                             label.appendf("useNormalSource: %d", useNormalSource);
    174                             canvas->drawString(label, 0.0f, 0.0f, labelPaint);
    175                         }
    176                         {
    177                             canvas->translate(0.0f, LABEL_SIZE);
    178                             SkString label;
    179                             label.appendf("useDiffuseShader: %d", useDiffuseShader);
    180                             canvas->drawString(label, 0.0f, 0.0f, labelPaint);
    181                         }
    182                         {
    183                             canvas->translate(0.0f, LABEL_SIZE);
    184                             SkString label;
    185                             label.appendf("useTranslucentPaint: %d", useTranslucentPaint);
    186                             canvas->drawString(label, 0.0f, 0.0f, labelPaint);
    187                         }
    188                         {
    189                             canvas->translate(0.0f, LABEL_SIZE);
    190                             SkString label;
    191                             label.appendf("useTranslucentShader: %d", useTranslucentShader);
    192                             canvas->drawString(label, 0.0f, 0.0f, labelPaint);
    193                         }
    194 
    195                         canvas->restore();
    196 
    197                         gridNum++;
    198                     }
    199                 }
    200             }
    201         }
    202 
    203 
    204         // Rotation/scale test
    205         {
    206             SkScalar xPos = (gridNum % GRID_COLUMN_NUM) * GRID_CELL_WIDTH;
    207             SkScalar yPos = (gridNum / GRID_COLUMN_NUM) * GRID_CELL_WIDTH;
    208 
    209             canvas->save();
    210             canvas->translate(xPos, yPos);
    211             this->drawRect(canvas, 0.6f, 0.6f, 45.0f, true, true, true, true, fLights);
    212             canvas->restore();
    213 
    214             gridNum++;
    215         }
    216 
    217         // Anisotropic scale test
    218         {
    219             SkScalar xPos = (gridNum % GRID_COLUMN_NUM) * GRID_CELL_WIDTH;
    220             SkScalar yPos = (gridNum / GRID_COLUMN_NUM) * GRID_CELL_WIDTH;
    221 
    222             canvas->save();
    223             canvas->translate(xPos, yPos);
    224             this->drawRect(canvas, 0.6f, 0.4f, 30.0f, true, true, true, true, fLights);
    225             canvas->restore();
    226 
    227             gridNum++;
    228         }
    229 
    230         // No directional lights test
    231         {
    232             SkScalar xPos = (gridNum % GRID_COLUMN_NUM) * GRID_CELL_WIDTH;
    233             SkScalar yPos = (gridNum / GRID_COLUMN_NUM) * GRID_CELL_WIDTH;
    234 
    235             canvas->save();
    236             canvas->translate(xPos, yPos);
    237             this->drawRect(canvas, 1.0f, 1.0f, 0.0f, true, true, false, false, fLightsNoDir);
    238             canvas->restore();
    239 
    240             gridNum++;
    241         }
    242 
    243         // Two directional lights test
    244         {
    245             SkScalar xPos = (gridNum % GRID_COLUMN_NUM) * GRID_CELL_WIDTH;
    246             SkScalar yPos = (gridNum / GRID_COLUMN_NUM) * GRID_CELL_WIDTH;
    247 
    248             canvas->save();
    249             canvas->translate(xPos, yPos);
    250             this->drawRect(canvas, 1.0f, 1.0f, 0.0f, true, true, false, false, fLightsTwoDir);
    251             canvas->restore();
    252 
    253             gridNum++;
    254         }
    255     }
    256 
    257 private:
    258     static constexpr int kTexSize = 96;
    259 
    260     sk_sp<SkShader> fOpaqueDiffuse;
    261     sk_sp<SkShader> fTranslucentDiffuse;
    262     sk_sp<SkShader> fNormalMapShader;
    263 
    264     SkRect fRect;
    265     sk_sp<SkLights> fLights;
    266     sk_sp<SkLights> fLightsNoDir;
    267     sk_sp<SkLights> fLightsTwoDir;
    268 
    269     typedef GM INHERITED;
    270 };
    271 
    272 //////////////////////////////////////////////////////////////////////////////
    273 
    274 DEF_GM(return new LightingShader2GM;)
    275 }
    276