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