Home | History | Annotate | Download | only in gm
      1 /*
      2  * Copyright 2015 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 
     10 #include "SkLightingShader.h"
     11 #include "SkPoint3.h"
     12 #include "SkShader.h"
     13 
     14 // Create a hemispherical normal map
     15 static SkBitmap make_hemi_normalmap(int texSize) {
     16     SkBitmap hemi;
     17     hemi.allocN32Pixels(texSize, texSize);
     18 
     19     sk_tool_utils::create_hemi_normal_map(&hemi, SkIRect::MakeWH(texSize, texSize));
     20     return hemi;
     21 }
     22 
     23 // Create a truncated pyramid normal map
     24 static SkBitmap make_frustum_normalmap(int texSize) {
     25     SkBitmap frustum;
     26     frustum.allocN32Pixels(texSize, texSize);
     27 
     28     sk_tool_utils::create_frustum_normal_map(&frustum, SkIRect::MakeWH(texSize, texSize));
     29     return frustum;
     30 }
     31 
     32 // Create a tetrahedral normal map
     33 static SkBitmap make_tetra_normalmap(int texSize) {
     34     SkBitmap tetra;
     35     tetra.allocN32Pixels(texSize, texSize);
     36 
     37     sk_tool_utils::create_tetra_normal_map(&tetra, SkIRect::MakeWH(texSize, texSize));
     38     return tetra;
     39 }
     40 
     41 namespace skiagm {
     42 
     43 // This GM exercises lighting shaders.
     44 class LightingShaderGM : public GM {
     45 public:
     46     LightingShaderGM() {
     47         this->setBGColor(sk_tool_utils::color_to_565(0xFFCCCCCC));
     48 
     49         SkLightingShader::Lights::Builder builder;
     50 
     51         builder.add(SkLight(SkColor3f::Make(1.0f, 1.0f, 1.0f),
     52                             SkVector3::Make(1.0f, 0.0f, 0.0f)));
     53         builder.add(SkLight(SkColor3f::Make(0.2f, 0.2f, 0.2f)));
     54 
     55         fLights.reset(builder.finish());
     56     }
     57 
     58 protected:
     59     enum NormalMap {
     60         kHemi_NormalMap,
     61         kFrustum_NormalMap,
     62         kTetra_NormalMap,
     63 
     64         kLast_NormalMap = kTetra_NormalMap
     65     };
     66 
     67     static const int kNormalMapCount = kLast_NormalMap+1;
     68 
     69     SkString onShortName() override {
     70         return SkString("lightingshader");
     71     }
     72 
     73     SkISize onISize() override {
     74         return SkISize::Make(kGMSize, kGMSize);
     75     }
     76 
     77     void onOnceBeforeDraw() override {
     78         fDiffuse = sk_tool_utils::create_checkerboard_bitmap(
     79                                                         kTexSize, kTexSize,
     80                                                         sk_tool_utils::color_to_565(0x0),
     81                                                         sk_tool_utils::color_to_565(0xFF804020),
     82                                                         8);
     83 
     84         fNormalMaps[kHemi_NormalMap]    = make_hemi_normalmap(kTexSize);
     85         fNormalMaps[kFrustum_NormalMap] = make_frustum_normalmap(kTexSize);
     86         fNormalMaps[kTetra_NormalMap]   = make_tetra_normalmap(kTexSize);
     87     }
     88 
     89     void drawRect(SkCanvas* canvas, const SkRect& r, NormalMap mapType) {
     90 
     91         SkRect bitmapBounds = SkRect::MakeIWH(fDiffuse.width(), fDiffuse.height());
     92 
     93         SkMatrix matrix;
     94         matrix.setRectToRect(bitmapBounds, r, SkMatrix::kFill_ScaleToFit);
     95 
     96         const SkMatrix& ctm = canvas->getTotalMatrix();
     97 
     98         // TODO: correctly pull out the pure rotation
     99         SkVector invNormRotation = { ctm[SkMatrix::kMScaleX], ctm[SkMatrix::kMSkewY] };
    100 
    101         SkAutoTUnref<SkShader> fShader(SkLightingShader::Create(
    102                                                         fDiffuse,
    103                                                         fNormalMaps[mapType],
    104                                                         fLights,
    105                                                         invNormRotation, &matrix, &matrix));
    106 
    107         SkPaint paint;
    108         paint.setShader(fShader);
    109 
    110         canvas->drawRect(r, paint);
    111     }
    112 
    113     void onDraw(SkCanvas* canvas) override {
    114         SkMatrix m;
    115         SkRect r;
    116 
    117         {
    118             r = SkRect::MakeWH(SkIntToScalar(kTexSize), SkIntToScalar(kTexSize));
    119             this->drawRect(canvas, r, kHemi_NormalMap);
    120 
    121             canvas->save();
    122             m.setRotate(45.0f, r.centerX(), r.centerY());
    123             m.postTranslate(kGMSize/2.0f - kTexSize/2.0f, 0.0f);
    124             canvas->setMatrix(m);
    125             this->drawRect(canvas, r, kHemi_NormalMap);
    126             canvas->restore();
    127         }
    128 
    129         {
    130             r.offset(kGMSize - kTexSize, 0);
    131             this->drawRect(canvas, r, kFrustum_NormalMap);
    132 
    133             canvas->save();
    134             m.setRotate(45.0f, r.centerX(), r.centerY());
    135             m.postTranslate(0.0f, kGMSize/2.0f - kTexSize/2.0f);
    136             canvas->setMatrix(m);
    137             this->drawRect(canvas, r, kFrustum_NormalMap);
    138             canvas->restore();
    139         }
    140 
    141         {
    142             r.offset(0, kGMSize - kTexSize);
    143             this->drawRect(canvas, r, kTetra_NormalMap);
    144 
    145             canvas->save();
    146             m.setRotate(45.0f, r.centerX(), r.centerY());
    147             m.postTranslate(-kGMSize/2.0f + kTexSize/2.0f, 0.0f);
    148             canvas->setMatrix(m);
    149             this->drawRect(canvas, r, kTetra_NormalMap);
    150             canvas->restore();
    151         }
    152 
    153         {
    154             r.offset(kTexSize - kGMSize, 0);
    155             this->drawRect(canvas, r, kHemi_NormalMap);
    156 
    157             canvas->save();
    158             m.setRotate(45.0f, r.centerX(), r.centerY());
    159             m.postTranslate(0.0f, -kGMSize/2.0f + kTexSize/2.0f);
    160             canvas->setMatrix(m);
    161             this->drawRect(canvas, r, kHemi_NormalMap);
    162             canvas->restore();
    163         }
    164     }
    165 
    166 private:
    167     static const int kTexSize = 128;
    168     static const int kGMSize  = 512;
    169 
    170     SkBitmap                fDiffuse;
    171     SkBitmap                fNormalMaps[kNormalMapCount];
    172 
    173     SkAutoTUnref<const SkLightingShader::Lights>  fLights;
    174 
    175     typedef GM INHERITED;
    176 };
    177 
    178 //////////////////////////////////////////////////////////////////////////////
    179 
    180 DEF_GM(return new LightingShaderGM;)
    181 }
    182