blob: aac6d7d262183eb0a712fb987f79776294030a0a [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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "gm/gm.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -04009#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"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050014#include "include/core/SkPoint3.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040015#include "include/core/SkRect.h"
16#include "include/core/SkRefCnt.h"
17#include "include/core/SkScalar.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050018#include "include/core/SkShader.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040019#include "include/core/SkSize.h"
20#include "include/core/SkString.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050021#include "src/core/SkNormalSource.h"
22#include "src/shaders/SkLightingShader.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040023#include "src/shaders/SkLights.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050024#include "tools/ToolUtils.h"
Robert Phillipsa8cdbd72018-07-17 12:30:40 -040025
Ben Wagner7fde8e12019-05-01 17:28:53 -040026#include <utility>
27
Robert Phillipsa8cdbd72018-07-17 12:30:40 -040028// Create a hemispherical normal map
29static SkBitmap make_hemi_normalmap(int texSize) {
30 SkBitmap hemi;
31 hemi.allocN32Pixels(texSize, texSize);
32
Mike Kleinea3f0142019-03-20 11:12:10 -050033 ToolUtils::create_hemi_normal_map(&hemi, SkIRect::MakeWH(texSize, texSize));
Robert Phillipsa8cdbd72018-07-17 12:30:40 -040034 return hemi;
35}
36
37// Create a truncated pyramid normal map
38static SkBitmap make_frustum_normalmap(int texSize) {
39 SkBitmap frustum;
40 frustum.allocN32Pixels(texSize, texSize);
41
Mike Kleinea3f0142019-03-20 11:12:10 -050042 ToolUtils::create_frustum_normal_map(&frustum, SkIRect::MakeWH(texSize, texSize));
Robert Phillipsa8cdbd72018-07-17 12:30:40 -040043 return frustum;
44}
45
46// Create a tetrahedral normal map
47static SkBitmap make_tetra_normalmap(int texSize) {
48 SkBitmap tetra;
49 tetra.allocN32Pixels(texSize, texSize);
50
Mike Kleinea3f0142019-03-20 11:12:10 -050051 ToolUtils::create_tetra_normal_map(&tetra, SkIRect::MakeWH(texSize, texSize));
Robert Phillipsa8cdbd72018-07-17 12:30:40 -040052 return tetra;
53}
54
55namespace 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.
59class LightingShaderGM : public GM {
60public:
61 LightingShaderGM() {
Mike Kleind46dce32018-08-16 10:17:03 -040062 this->setBGColor(0xFFCCCCCC);
Robert Phillipsa8cdbd72018-07-17 12:30:40 -040063 }
64
65protected:
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
76 SkString onShortName() override { return SkString("lightingshader"); }
77
78 SkISize onISize() override { return SkISize::Make(kGMSize, kGMSize); }
79
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
Mike Kleinea3f0142019-03-20 11:12:10 -050094 fDiffuse = ToolUtils::create_checkerboard_bitmap(
95 kTexSize, kTexSize, 0x00000000, ToolUtils::color_to_565(0xFF804020), 8);
Robert Phillipsa8cdbd72018-07-17 12:30:40 -040096
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
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;
Mike Reed50acf8f2019-04-08 13:20:23 -0400112 sk_sp<SkShader> diffuseShader = fDiffuse.makeShader(&matrix);
113 sk_sp<SkShader> normalMap = fNormalMaps[mapType].makeShader(&matrix);
Robert Phillipsa8cdbd72018-07-17 12:30:40 -0400114 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
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
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
152private:
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
167DEF_GM(return new LightingShaderGM;)
168}