lightingshader2.cpp revision 1ec04d9553af68b458c8dd6bd18d8c25ebd41d7a
195efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu/*
295efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu * Copyright 2016 Google Inc.
395efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu *
495efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu * Use of this source code is governed by a BSD-style license that can be
595efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu * found in the LICENSE file.
695efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu */
795efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu
895efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu#include "gm.h"
995efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu#include "SkLightingShader.h"
1095efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu#include "SkNormalSource.h"
1195efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu#include "SkPoint3.h"
1295efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu#include "SkShader.h"
1395efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu
1495efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu// Create a truncated pyramid normal map
1595efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsustatic SkBitmap make_frustum_normalmap(int texSize) {
1695efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu    SkBitmap frustum;
17584bf6606b53bda8bf0810e7c0ad57e24cacb4f1arthurhsu    frustum.allocN32Pixels(texSize, texSize);
18584bf6606b53bda8bf0810e7c0ad57e24cacb4f1arthurhsu
1995efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu    sk_tool_utils::create_frustum_normal_map(&frustum, SkIRect::MakeWH(texSize, texSize));
20158cdcb9cf09418ba8b49f4be7be69e37aa8e9faarthurhsu    return frustum;
21158cdcb9cf09418ba8b49f4be7be69e37aa8e9faarthurhsu}
2295efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu
2395efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsunamespace skiagm {
24de776d4ef06ca29c240de3444348894f032b03ffLei Zhang
2595efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu// This GM exercises lighting shaders. Specifically, nullptr arguments, scaling when using
2695efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu// normal maps, and paint transparency.
2795efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsuclass LightingShader2GM : public GM {
2895efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsupublic:
29007bac39b5a613b17384f72d96457ab91638bab6arthurhsu    LightingShader2GM() {
30007bac39b5a613b17384f72d96457ab91638bab6arthurhsu        this->setBGColor(sk_tool_utils::color_to_565(0xFFCCCCCC));
31007bac39b5a613b17384f72d96457ab91638bab6arthurhsu    }
32007bac39b5a613b17384f72d96457ab91638bab6arthurhsu
33007bac39b5a613b17384f72d96457ab91638bab6arthurhsuprotected:
34007bac39b5a613b17384f72d96457ab91638bab6arthurhsu    SkString onShortName() override {
35007bac39b5a613b17384f72d96457ab91638bab6arthurhsu        return SkString("lightingshader2");
36007bac39b5a613b17384f72d96457ab91638bab6arthurhsu    }
37007bac39b5a613b17384f72d96457ab91638bab6arthurhsu
38007bac39b5a613b17384f72d96457ab91638bab6arthurhsu    SkISize onISize() override {
39007bac39b5a613b17384f72d96457ab91638bab6arthurhsu        return SkISize::Make(600, 740);
40007bac39b5a613b17384f72d96457ab91638bab6arthurhsu    }
41007bac39b5a613b17384f72d96457ab91638bab6arthurhsu
42007bac39b5a613b17384f72d96457ab91638bab6arthurhsu    void onOnceBeforeDraw() override {
43007bac39b5a613b17384f72d96457ab91638bab6arthurhsu        SkLights::Builder builder;
44007bac39b5a613b17384f72d96457ab91638bab6arthurhsu        const SkVector3 kLightFromUpperRight = SkVector3::Make(0.788f, 0.394f, 0.473f);
45007bac39b5a613b17384f72d96457ab91638bab6arthurhsu
46007bac39b5a613b17384f72d96457ab91638bab6arthurhsu        builder.add(SkLights::Light(SkColor3f::Make(1.0f, 1.0f, 1.0f),
4795efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu                                    kLightFromUpperRight));
4895efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu        builder.add(SkLights::Light(SkColor3f::Make(0.2f, 0.2f, 0.2f)));
4995efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu        fLights = builder.finish();
5095efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu
5153e7e87e47c9d9ce7579e53583904ce4921daeadarthurhsu        fRect = SkRect::MakeIWH(kTexSize, kTexSize);
5295efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu        SkMatrix matrix;
5395efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu        SkRect bitmapBounds = SkRect::MakeIWH(kTexSize, kTexSize);
5453e7e87e47c9d9ce7579e53583904ce4921daeadarthurhsu        matrix.setRectToRect(bitmapBounds, fRect, SkMatrix::kFill_ScaleToFit);
55c143ecb4bbc4f3ccca5145dc2b17cc20ca738efearthurhsu
5695efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu        SkBitmap opaqueDiffuseMap = sk_tool_utils::create_checkerboard_bitmap(
5753e7e87e47c9d9ce7579e53583904ce4921daeadarthurhsu                kTexSize, kTexSize,
5853e7e87e47c9d9ce7579e53583904ce4921daeadarthurhsu                sk_tool_utils::color_to_565(0x0),
5995efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu                sk_tool_utils::color_to_565(0xFF804020),
6095efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu                8);
61de776d4ef06ca29c240de3444348894f032b03ffLei Zhang        fOpaqueDiffuse = SkShader::MakeBitmapShader(opaqueDiffuseMap, SkShader::kClamp_TileMode,
6295efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu                                                    SkShader::kClamp_TileMode, &matrix);
6395efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu
6453e7e87e47c9d9ce7579e53583904ce4921daeadarthurhsu        SkBitmap translucentDiffuseMap = sk_tool_utils::create_checkerboard_bitmap(
6595efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu                kTexSize, kTexSize,
6695efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu                SkColorSetARGB(0x55, 0x00, 0x00, 0x00),
6795efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu                SkColorSetARGB(0x55, 0x80, 0x40, 0x20),
68c143ecb4bbc4f3ccca5145dc2b17cc20ca738efearthurhsu                8);
6995efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu        fTranslucentDiffuse = SkShader::MakeBitmapShader(translucentDiffuseMap,
7095efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu                                                         SkShader::kClamp_TileMode,
7153e7e87e47c9d9ce7579e53583904ce4921daeadarthurhsu                                                         SkShader::kClamp_TileMode, &matrix);
7295efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu
7395efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu        SkBitmap normalMap = make_frustum_normalmap(kTexSize);
74c143ecb4bbc4f3ccca5145dc2b17cc20ca738efearthurhsu        fNormalMapShader = SkShader::MakeBitmapShader(normalMap, SkShader::kClamp_TileMode,
7595efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu                                                      SkShader::kClamp_TileMode, &matrix);
7653e7e87e47c9d9ce7579e53583904ce4921daeadarthurhsu
77c143ecb4bbc4f3ccca5145dc2b17cc20ca738efearthurhsu    }
7895efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu
7995efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu    // Scales shape around origin, rotates shape around origin, then translates shape to origin
8095efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu    void positionCTM(SkCanvas *canvas, SkScalar scaleX, SkScalar scaleY, SkScalar rotate) const {
8195efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu        canvas->translate(kTexSize/2.0f, kTexSize/2.0f);
8295efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu        canvas->scale(scaleX, scaleY);
8395efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu        canvas->rotate(rotate);
8495efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu        canvas->translate(-kTexSize/2.0f, -kTexSize/2.0f);
8595efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu    }
8695efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu
8795efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu    static constexpr int NUM_BOOLEAN_PARAMS = 4;
8895efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu    void drawRect(SkCanvas* canvas, SkScalar scaleX, SkScalar scaleY,
8995efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu                  SkScalar rotate, bool useNormalSource, bool useDiffuseShader,
9095efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu                  bool useTranslucentPaint, bool useTranslucentShader) {
9195efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu        canvas->save();
9295efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu
9395efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu        this->positionCTM(canvas, scaleX, scaleY, rotate);
94c143ecb4bbc4f3ccca5145dc2b17cc20ca738efearthurhsu
9595efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu        const SkMatrix& ctm = canvas->getTotalMatrix();
96c143ecb4bbc4f3ccca5145dc2b17cc20ca738efearthurhsu
9753e7e87e47c9d9ce7579e53583904ce4921daeadarthurhsu        SkPaint paint;
9853e7e87e47c9d9ce7579e53583904ce4921daeadarthurhsu        sk_sp<SkNormalSource> normalSource = nullptr;
9953e7e87e47c9d9ce7579e53583904ce4921daeadarthurhsu        sk_sp<SkShader> diffuseShader = nullptr;
10053e7e87e47c9d9ce7579e53583904ce4921daeadarthurhsu
10153e7e87e47c9d9ce7579e53583904ce4921daeadarthurhsu        if (useNormalSource) {
102c143ecb4bbc4f3ccca5145dc2b17cc20ca738efearthurhsu            normalSource = SkNormalSource::MakeFromNormalMap(fNormalMapShader, ctm);
10353e7e87e47c9d9ce7579e53583904ce4921daeadarthurhsu        }
104158cdcb9cf09418ba8b49f4be7be69e37aa8e9faarthurhsu
105158cdcb9cf09418ba8b49f4be7be69e37aa8e9faarthurhsu        if (useDiffuseShader) {
10653e7e87e47c9d9ce7579e53583904ce4921daeadarthurhsu            diffuseShader = (useTranslucentShader) ? fTranslucentDiffuse : fOpaqueDiffuse;
10753e7e87e47c9d9ce7579e53583904ce4921daeadarthurhsu        } else {
10853e7e87e47c9d9ce7579e53583904ce4921daeadarthurhsu            paint.setColor(0xFF00FF00);
109c143ecb4bbc4f3ccca5145dc2b17cc20ca738efearthurhsu        }
11095efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu
111158cdcb9cf09418ba8b49f4be7be69e37aa8e9faarthurhsu        if (useTranslucentPaint) {
112158cdcb9cf09418ba8b49f4be7be69e37aa8e9faarthurhsu            paint.setAlpha(0x99);
113c143ecb4bbc4f3ccca5145dc2b17cc20ca738efearthurhsu        }
11495efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu
11595efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu        paint.setShader(SkLightingShader::Make(std::move(diffuseShader), std::move(normalSource),
11695efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu                                               fLights));
11795efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu        canvas->drawRect(fRect, paint);
11895efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu
11995efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu        canvas->restore();
12095efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu    }
12195efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu
12295efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu    void onDraw(SkCanvas* canvas) override {
12395efcd4ba41e367b466b7206a942605bbbbb2c9arthurhsu
124584bf6606b53bda8bf0810e7c0ad57e24cacb4f1arthurhsu        constexpr SkScalar LABEL_SIZE = 10.0f;
125        SkPaint labelPaint;
126        labelPaint.setTypeface(sk_tool_utils::create_portable_typeface("sans-serif",
127                                                                       SkFontStyle()));
128        labelPaint.setAntiAlias(true);
129        labelPaint.setTextSize(LABEL_SIZE);
130
131        constexpr int GRID_COLUMN_NUM = 4;
132        constexpr SkScalar GRID_CELL_WIDTH = kTexSize + 20.0f + NUM_BOOLEAN_PARAMS * LABEL_SIZE;
133
134        int gridNum = 0;
135
136        // Running through all possible bool parameter combinations
137        for (bool useNormalSource : {true, false}) {
138            for (bool useDiffuseShader : {true, false}) {
139                for (bool useTranslucentPaint : {true, false}) {
140                    for (bool useTranslucentShader : {true, false}) {
141
142                        // Determining position
143                        SkScalar xPos = (gridNum % GRID_COLUMN_NUM) * GRID_CELL_WIDTH;
144                        SkScalar yPos = (gridNum / GRID_COLUMN_NUM) * GRID_CELL_WIDTH;
145
146                        canvas->save();
147
148                        canvas->translate(xPos, yPos);
149                        this->drawRect(canvas, 1.0f, 1.0f, 0.f, useNormalSource, useDiffuseShader,
150                                       useTranslucentPaint, useTranslucentShader);
151                        // Drawing labels
152                        canvas->translate(0.0f, SkIntToScalar(kTexSize));
153                        {
154                            canvas->translate(0.0f, LABEL_SIZE);
155                            SkString label;
156                            label.appendf("useNormalSource: %d", useNormalSource);
157                            canvas->drawText(label.c_str(), label.size(), 0.0f, 0.0f, labelPaint);
158                        }
159                        {
160                            canvas->translate(0.0f, LABEL_SIZE);
161                            SkString label;
162                            label.appendf("useDiffuseShader: %d", useDiffuseShader);
163                            canvas->drawText(label.c_str(), label.size(), 0.0f, 0.0f, labelPaint);
164                        }
165                        {
166                            canvas->translate(0.0f, LABEL_SIZE);
167                            SkString label;
168                            label.appendf("useTranslucentPaint: %d", useTranslucentPaint);
169                            canvas->drawText(label.c_str(), label.size(), 0.0f, 0.0f, labelPaint);
170                        }
171                        {
172                            canvas->translate(0.0f, LABEL_SIZE);
173                            SkString label;
174                            label.appendf("useTranslucentShader: %d", useTranslucentShader);
175                            canvas->drawText(label.c_str(), label.size(), 0.0f, 0.0f, labelPaint);
176                        }
177
178                        canvas->restore();
179
180                        gridNum++;
181                    }
182                }
183            }
184        }
185
186
187        // Rotation/scale test
188        {
189            SkScalar xPos = (gridNum % GRID_COLUMN_NUM) * GRID_CELL_WIDTH;
190            SkScalar yPos = (gridNum / GRID_COLUMN_NUM) * GRID_CELL_WIDTH;
191
192            canvas->save();
193            canvas->translate(xPos, yPos);
194            this->drawRect(canvas, 0.6f, 0.6f, 45.0f, true, true, true, true);
195            canvas->restore();
196
197            gridNum++;
198        }
199
200        // Anisotropic scale test
201        {
202            SkScalar xPos = (gridNum % GRID_COLUMN_NUM) * GRID_CELL_WIDTH;
203            SkScalar yPos = (gridNum / GRID_COLUMN_NUM) * GRID_CELL_WIDTH;
204
205            canvas->save();
206            canvas->translate(xPos, yPos);
207            this->drawRect(canvas, 0.6f, 0.4f, 30.0f, true, true, true, true);
208            canvas->restore();
209
210            gridNum++;
211        }
212    }
213
214private:
215    static const int kTexSize = 96;
216
217    sk_sp<SkShader> fOpaqueDiffuse;
218    sk_sp<SkShader> fTranslucentDiffuse;
219    sk_sp<SkShader> fNormalMapShader;
220
221    SkRect fRect;
222    sk_sp<SkLights> fLights;
223
224    typedef GM INHERITED;
225};
226
227//////////////////////////////////////////////////////////////////////////////
228
229DEF_GM(return new LightingShader2GM;)
230}
231