• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/gm.h"
9 #include "include/core/SkBitmap.h"
10 #include "include/core/SkCanvas.h"
11 #include "include/core/SkMatrix.h"
12 #include "include/core/SkPaint.h"
13 #include "include/core/SkPoint.h"
14 #include "include/core/SkPoint3.h"
15 #include "include/core/SkRect.h"
16 #include "include/core/SkRefCnt.h"
17 #include "include/core/SkScalar.h"
18 #include "include/core/SkShader.h"
19 #include "include/core/SkSize.h"
20 #include "include/core/SkString.h"
21 #include "src/core/SkNormalSource.h"
22 #include "src/shaders/SkLightingShader.h"
23 #include "src/shaders/SkLights.h"
24 #include "tools/ToolUtils.h"
25 
26 #include <utility>
27 
28 // Create a hemispherical normal map
make_hemi_normalmap(int texSize)29 static SkBitmap make_hemi_normalmap(int texSize) {
30     SkBitmap hemi;
31     hemi.allocN32Pixels(texSize, texSize);
32 
33     ToolUtils::create_hemi_normal_map(&hemi, SkIRect::MakeWH(texSize, texSize));
34     return hemi;
35 }
36 
37 // Create a truncated pyramid normal map
make_frustum_normalmap(int texSize)38 static SkBitmap make_frustum_normalmap(int texSize) {
39     SkBitmap frustum;
40     frustum.allocN32Pixels(texSize, texSize);
41 
42     ToolUtils::create_frustum_normal_map(&frustum, SkIRect::MakeWH(texSize, texSize));
43     return frustum;
44 }
45 
46 // Create a tetrahedral normal map
make_tetra_normalmap(int texSize)47 static SkBitmap make_tetra_normalmap(int texSize) {
48     SkBitmap tetra;
49     tetra.allocN32Pixels(texSize, texSize);
50 
51     ToolUtils::create_tetra_normal_map(&tetra, SkIRect::MakeWH(texSize, texSize));
52     return tetra;
53 }
54 
55 namespace skiagm {
56 
57 // This GM exercises lighting shaders by drawing rotated and non-rotated normal mapped rects with
58 // a directional light off to the viewers right.
59 class LightingShaderGM : public GM {
60 public:
LightingShaderGM()61     LightingShaderGM() {
62         this->setBGColor(0xFFCCCCCC);
63     }
64 
65 protected:
66     enum NormalMap {
67         kHemi_NormalMap,
68         kFrustum_NormalMap,
69         kTetra_NormalMap,
70 
71         kLast_NormalMap = kTetra_NormalMap
72     };
73 
74     static constexpr int kNormalMapCount = kLast_NormalMap+1;
75 
onShortName()76     SkString onShortName() override { return SkString("lightingshader"); }
77 
onISize()78     SkISize onISize() override { return SkISize::Make(kGMSize, kGMSize); }
79 
onOnceBeforeDraw()80     void onOnceBeforeDraw() override {
81         {
82             SkLights::Builder builder;
83 
84             // The direction vector is towards the light w/ +Z coming out of the screen
85             builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 1.0f, 1.0f),
86                                                          SkVector3::Make(SK_ScalarRoot2Over2,
87                                                                          0.0f,
88                                                                          SK_ScalarRoot2Over2)));
89             builder.setAmbientLightColor(SkColor3f::Make(0.2f, 0.2f, 0.2f));
90 
91             fLights = builder.finish();
92         }
93 
94         fDiffuse = ToolUtils::create_checkerboard_bitmap(
95                 kTexSize, kTexSize, 0x00000000, ToolUtils::color_to_565(0xFF804020), 8);
96 
97         fNormalMaps[kHemi_NormalMap]    = make_hemi_normalmap(kTexSize);
98         fNormalMaps[kFrustum_NormalMap] = make_frustum_normalmap(kTexSize);
99         fNormalMaps[kTetra_NormalMap]   = make_tetra_normalmap(kTexSize);
100     }
101 
drawRect(SkCanvas * canvas,const SkRect & r,NormalMap mapType)102     void drawRect(SkCanvas* canvas, const SkRect& r, NormalMap mapType) {
103 
104         SkRect bitmapBounds = SkRect::MakeIWH(fDiffuse.width(), fDiffuse.height());
105 
106         SkMatrix matrix;
107         matrix.setRectToRect(bitmapBounds, r, SkMatrix::kFill_ScaleToFit);
108 
109         const SkMatrix& ctm = canvas->getTotalMatrix();
110 
111         SkPaint paint;
112         sk_sp<SkShader> diffuseShader = fDiffuse.makeShader(&matrix);
113         sk_sp<SkShader> normalMap = fNormalMaps[mapType].makeShader(&matrix);
114         sk_sp<SkNormalSource> normalSource = SkNormalSource::MakeFromNormalMap(std::move(normalMap),
115                                                                                ctm);
116         paint.setShader(SkLightingShader::Make(std::move(diffuseShader), std::move(normalSource),
117                                                fLights));
118 
119         canvas->drawRect(r, paint);
120     }
121 
122     // Draw an axis-aligned and rotated version of the normal mapped rect
drawPair(SkCanvas * canvas,const SkRect & r,NormalMap mapType,const SkVector & v)123     void drawPair(SkCanvas* canvas, const SkRect& r, NormalMap mapType, const SkVector& v) {
124         SkMatrix m;
125         m.setRotate(45.0f, r.centerX(), r.centerY());
126         m.postTranslate(kScale * v.fX, kScale * v.fY);
127 
128         this->drawRect(canvas, r, mapType);
129 
130         canvas->save();
131             canvas->setMatrix(m);
132             this->drawRect(canvas, r, mapType);
133         canvas->restore();
134     }
135 
onDraw(SkCanvas * canvas)136     void onDraw(SkCanvas* canvas) override {
137         SkRect r;
138 
139         r = SkRect::MakeWH(SkIntToScalar(kTexSize), SkIntToScalar(kTexSize));
140         this->drawPair(canvas, r, kHemi_NormalMap, SkVector::Make(1.0f, 0.0f));
141 
142         r.offset(kGMSize - kTexSize, 0);
143         this->drawPair(canvas, r, kFrustum_NormalMap, SkVector::Make(0.0f, 1.0f));
144 
145         r.offset(0, kGMSize - kTexSize);
146         this->drawPair(canvas, r, kTetra_NormalMap, SkVector::Make(-1.0, 0.0f));
147 
148         r.offset(kTexSize - kGMSize, 0);
149         this->drawPair(canvas, r, kHemi_NormalMap, SkVector::Make(0.0f, -1));
150     }
151 
152 private:
153     static constexpr int kTexSize = 128;
154     static constexpr int kGMSize  = 512;
155     static constexpr SkScalar kScale = kGMSize/2.0f - kTexSize/2.0f;
156 
157     SkBitmap        fDiffuse;
158     SkBitmap        fNormalMaps[kNormalMapCount];
159 
160     sk_sp<SkLights> fLights;
161 
162     typedef GM INHERITED;
163 };
164 
165 //////////////////////////////////////////////////////////////////////////////
166 
167 DEF_GM(return new LightingShaderGM;)
168 }
169