blob: 9c45c9b78309e240e37c730443e645cdf3fcd84b [file] [log] [blame]
robertphillips5f865b92015-07-29 12:28:04 -07001/*
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
robertphillips5f865b92015-07-29 12:28:04 -070010#include "SkLightingShader.h"
robertphillipsea4529d2015-08-17 15:04:47 -070011#include "SkPoint3.h"
12#include "SkShader.h"
robertphillips5f865b92015-07-29 12:28:04 -070013
robertphillips5f865b92015-07-29 12:28:04 -070014// Create a hemispherical normal map
robertphillips640898f2015-07-30 05:09:17 -070015static SkBitmap make_hemi_normalmap(int texSize) {
robertphillips5f865b92015-07-29 12:28:04 -070016 SkBitmap hemi;
17 hemi.allocN32Pixels(texSize, texSize);
18
robertphillipsea4529d2015-08-17 15:04:47 -070019 sk_tool_utils::create_hemi_normal_map(&hemi, SkIRect::MakeWH(texSize, texSize));
robertphillips5f865b92015-07-29 12:28:04 -070020 return hemi;
21}
22
robertphillips640898f2015-07-30 05:09:17 -070023// Create a truncated pyramid normal map
24static SkBitmap make_frustum_normalmap(int texSize) {
25 SkBitmap frustum;
26 frustum.allocN32Pixels(texSize, texSize);
27
robertphillipsea4529d2015-08-17 15:04:47 -070028 sk_tool_utils::create_frustum_normal_map(&frustum, SkIRect::MakeWH(texSize, texSize));
robertphillips640898f2015-07-30 05:09:17 -070029 return frustum;
30}
robertphillips5f865b92015-07-29 12:28:04 -070031
robertphillipsea4529d2015-08-17 15:04:47 -070032// Create a tetrahedral normal map
33static 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
robertphillips5f865b92015-07-29 12:28:04 -070041namespace skiagm {
42
43// This GM exercises lighting shaders.
44class LightingShaderGM : public GM {
45public:
46 LightingShaderGM() {
47 this->setBGColor(sk_tool_utils::color_to_565(0xFFCCCCCC));
robertphillips640898f2015-07-30 05:09:17 -070048
robertphillips2f0dbc72015-08-20 05:15:06 -070049 SkLightingShader::Lights::Builder builder;
robertphillips640898f2015-07-30 05:09:17 -070050
robertphillips2f0dbc72015-08-20 05:15:06 -070051 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());
robertphillips5f865b92015-07-29 12:28:04 -070056 }
57
58protected:
robertphillipsea4529d2015-08-17 15:04:47 -070059 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;
robertphillips5f865b92015-07-29 12:28:04 -070068
69 SkString onShortName() override {
70 return SkString("lightingshader");
71 }
72
73 SkISize onISize() override {
robertphillips640898f2015-07-30 05:09:17 -070074 return SkISize::Make(kGMSize, kGMSize);
robertphillips5f865b92015-07-29 12:28:04 -070075 }
76
77 void onOnceBeforeDraw() override {
robertphillips943a4622015-09-03 13:32:33 -070078 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);
robertphillipsea4529d2015-08-17 15:04:47 -070083
84 fNormalMaps[kHemi_NormalMap] = make_hemi_normalmap(kTexSize);
85 fNormalMaps[kFrustum_NormalMap] = make_frustum_normalmap(kTexSize);
86 fNormalMaps[kTetra_NormalMap] = make_tetra_normalmap(kTexSize);
robertphillips5f865b92015-07-29 12:28:04 -070087 }
88
robertphillipsea4529d2015-08-17 15:04:47 -070089 void drawRect(SkCanvas* canvas, const SkRect& r, NormalMap mapType) {
robertphillips5f865b92015-07-29 12:28:04 -070090
robertphillips640898f2015-07-30 05:09:17 -070091 SkRect bitmapBounds = SkRect::MakeIWH(fDiffuse.width(), fDiffuse.height());
robertphillips5f865b92015-07-29 12:28:04 -070092
robertphillips640898f2015-07-30 05:09:17 -070093 SkMatrix matrix;
94 matrix.setRectToRect(bitmapBounds, r, SkMatrix::kFill_ScaleToFit);
95
robertphillips2f0dbc72015-08-20 05:15:06 -070096 const SkMatrix& ctm = canvas->getTotalMatrix();
97
98 // TODO: correctly pull out the pure rotation
99 SkVector invNormRotation = { ctm[SkMatrix::kMScaleX], ctm[SkMatrix::kMSkewY] };
100
robertphillips640898f2015-07-30 05:09:17 -0700101 SkAutoTUnref<SkShader> fShader(SkLightingShader::Create(
102 fDiffuse,
robertphillipsea4529d2015-08-17 15:04:47 -0700103 fNormalMaps[mapType],
robertphillips2f0dbc72015-08-20 05:15:06 -0700104 fLights,
105 invNormRotation, &matrix, &matrix));
robertphillips5f865b92015-07-29 12:28:04 -0700106
107 SkPaint paint;
108 paint.setShader(fShader);
109
robertphillips5f865b92015-07-29 12:28:04 -0700110 canvas->drawRect(r, paint);
111 }
112
robertphillips640898f2015-07-30 05:09:17 -0700113 void onDraw(SkCanvas* canvas) override {
robertphillips2f0dbc72015-08-20 05:15:06 -0700114 SkMatrix m;
115 SkRect r;
robertphillips640898f2015-07-30 05:09:17 -0700116
robertphillips2f0dbc72015-08-20 05:15:06 -0700117 {
118 r = SkRect::MakeWH(SkIntToScalar(kTexSize), SkIntToScalar(kTexSize));
119 this->drawRect(canvas, r, kHemi_NormalMap);
robertphillips640898f2015-07-30 05:09:17 -0700120
robertphillips2f0dbc72015-08-20 05:15:06 -0700121 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 }
robertphillips640898f2015-07-30 05:09:17 -0700128
robertphillips2f0dbc72015-08-20 05:15:06 -0700129 {
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 }
robertphillips640898f2015-07-30 05:09:17 -0700164 }
165
robertphillips5f865b92015-07-29 12:28:04 -0700166private:
167 static const int kTexSize = 128;
robertphillips640898f2015-07-30 05:09:17 -0700168 static const int kGMSize = 512;
robertphillips5f865b92015-07-29 12:28:04 -0700169
robertphillips640898f2015-07-30 05:09:17 -0700170 SkBitmap fDiffuse;
robertphillipsea4529d2015-08-17 15:04:47 -0700171 SkBitmap fNormalMaps[kNormalMapCount];
robertphillips640898f2015-07-30 05:09:17 -0700172
robertphillips2f0dbc72015-08-20 05:15:06 -0700173 SkAutoTUnref<const SkLightingShader::Lights> fLights;
robertphillips5f865b92015-07-29 12:28:04 -0700174
175 typedef GM INHERITED;
176};
177
178//////////////////////////////////////////////////////////////////////////////
179
halcanary385fe4d2015-08-26 13:07:48 -0700180DEF_GM(return new LightingShaderGM;)
robertphillips5f865b92015-07-29 12:28:04 -0700181}