skia2/gm/lightingshader2.cpp
Ben Wagner 7fde8e1728 IWYU for gms.
This almost gets gms to be iwyu clean. The last bit is around gm.cpp
and the tracing framework and its use of atomic. Will also need a way
of keeping things from regressing, which is difficult due to needing to
do this outside-in.

Change-Id: I1393531e99da8b0f1a29f55c53c86d53f459af7d
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/211593
Reviewed-by: Herb Derby <herb@google.com>
Commit-Queue: Ben Wagner <bungeman@google.com>
2019-05-02 17:48:53 +00:00

288 lines
10 KiB
C++

/*
* Copyright 2016 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "gm/gm.h"
#include "include/core/SkBitmap.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkColor.h"
#include "include/core/SkFont.h"
#include "include/core/SkFontStyle.h"
#include "include/core/SkMatrix.h"
#include "include/core/SkPaint.h"
#include "include/core/SkPoint3.h"
#include "include/core/SkRect.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkScalar.h"
#include "include/core/SkShader.h"
#include "include/core/SkSize.h"
#include "include/core/SkString.h"
#include "include/core/SkTypeface.h"
#include "src/core/SkNormalSource.h"
#include "src/shaders/SkLightingShader.h"
#include "src/shaders/SkLights.h"
#include "tools/ToolUtils.h"
#include <initializer_list>
#include <utility>
// Create a truncated pyramid normal map
static SkBitmap make_frustum_normalmap(int texSize) {
SkBitmap frustum;
frustum.allocN32Pixels(texSize, texSize);
ToolUtils::create_frustum_normal_map(&frustum, SkIRect::MakeWH(texSize, texSize));
return frustum;
}
namespace skiagm {
// This GM exercises lighting shaders. Specifically, nullptr arguments, scaling when using
// normal maps, paint transparency, zero directional lights, multiple directional lights.
class LightingShader2GM : public GM {
public:
LightingShader2GM() : fRect(SkRect::MakeIWH(kTexSize, kTexSize)) {
this->setBGColor(ToolUtils::color_to_565(0xFF0000CC));
}
protected:
SkString onShortName() override {
return SkString("lightingshader2");
}
SkISize onISize() override {
return SkISize::Make(600, 740);
}
void onOnceBeforeDraw() override {
// The light direction is towards the light with +Z coming out of the screen
const SkVector3 kLightFromUpperRight = SkVector3::Make(0.788f, 0.394f, 0.473f);
const SkVector3 kLightFromUpperLeft = SkVector3::Make(-0.788f, 0.394f, 0.473f);
// Standard set of lights
{
SkLights::Builder builder;
builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 1.0f, 1.0f),
kLightFromUpperRight));
builder.setAmbientLightColor(SkColor3f::Make(0.2f, 0.2f, 0.2f));
fLights = builder.finish();
}
// No directional lights
{
SkLights::Builder builder;
builder.setAmbientLightColor(SkColor3f::Make(0.2f, 0.2f, 0.2f));
fLightsNoDir = builder.finish();
}
// Two directional lights
{
SkLights::Builder builder;
builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 0.0f, 0.0f),
kLightFromUpperRight));
builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(0.0f, 1.0f, 0.0f),
kLightFromUpperLeft));
builder.setAmbientLightColor(SkColor3f::Make(0.2f, 0.2f, 0.2f));
fLightsTwoDir = builder.finish();
}
SkMatrix matrix;
SkRect bitmapBounds = SkRect::MakeIWH(kTexSize, kTexSize);
matrix.setRectToRect(bitmapBounds, fRect, SkMatrix::kFill_ScaleToFit);
SkBitmap opaqueDiffuseMap = ToolUtils::create_checkerboard_bitmap(
kTexSize, kTexSize, SK_ColorBLACK, 0xFF808080, 8);
fOpaqueDiffuse = opaqueDiffuseMap.makeShader(&matrix);
SkBitmap translucentDiffuseMap =
ToolUtils::create_checkerboard_bitmap(kTexSize,
kTexSize,
SkColorSetARGB(0x55, 0x00, 0x00, 0x00),
SkColorSetARGB(0x55, 0x80, 0x80, 0x80),
8);
fTranslucentDiffuse = translucentDiffuseMap.makeShader(&matrix);
SkBitmap normalMap = make_frustum_normalmap(kTexSize);
fNormalMapShader = normalMap.makeShader(&matrix);
}
// Scales shape around origin, rotates shape around origin, then translates shape to origin
void positionCTM(SkCanvas *canvas, SkScalar scaleX, SkScalar scaleY, SkScalar rotate) const {
canvas->translate(kTexSize/2.0f, kTexSize/2.0f);
canvas->scale(scaleX, scaleY);
canvas->rotate(rotate);
canvas->translate(-kTexSize/2.0f, -kTexSize/2.0f);
}
void drawRect(SkCanvas* canvas, SkScalar scaleX, SkScalar scaleY,
SkScalar rotate, bool useNormalSource, bool useDiffuseShader,
bool useTranslucentPaint, bool useTranslucentShader, sk_sp<SkLights> lights) {
canvas->save();
this->positionCTM(canvas, scaleX, scaleY, rotate);
const SkMatrix& ctm = canvas->getTotalMatrix();
SkPaint paint;
sk_sp<SkNormalSource> normalSource = nullptr;
sk_sp<SkShader> diffuseShader = nullptr;
if (useNormalSource) {
normalSource = SkNormalSource::MakeFromNormalMap(fNormalMapShader, ctm);
}
if (useDiffuseShader) {
diffuseShader = (useTranslucentShader) ? fTranslucentDiffuse : fOpaqueDiffuse;
} else {
paint.setColor(SK_ColorGREEN);
}
if (useTranslucentPaint) {
paint.setAlpha(0x99);
}
paint.setShader(SkLightingShader::Make(std::move(diffuseShader), std::move(normalSource),
std::move(lights)));
canvas->drawRect(fRect, paint);
canvas->restore();
}
void onDraw(SkCanvas* canvas) override {
SkPaint labelPaint;
SkFont font(ToolUtils::create_portable_typeface("sans-serif", SkFontStyle()), kLabelSize);
int gridNum = 0;
// Running through all possible bool parameter combinations
for (bool useNormalSource : {true, false}) {
for (bool useDiffuseShader : {true, false}) {
for (bool useTranslucentPaint : {true, false}) {
for (bool useTranslucentShader : {true, false}) {
// Determining position
SkScalar xPos = (gridNum % kGridColumnNum) * kGridCellWidth;
SkScalar yPos = (gridNum / kGridColumnNum) * kGridCellWidth;
canvas->save();
canvas->translate(xPos, yPos);
this->drawRect(canvas, 1.0f, 1.0f, 0.f, useNormalSource, useDiffuseShader,
useTranslucentPaint, useTranslucentShader, fLights);
// Drawing labels
canvas->translate(0.0f, SkIntToScalar(kTexSize));
{
canvas->translate(0.0f, kLabelSize);
SkString label;
label.appendf("useNormalSource: %d", useNormalSource);
canvas->drawString(label, 0.0f, 0.0f, font, labelPaint);
}
{
canvas->translate(0.0f, kLabelSize);
SkString label;
label.appendf("useDiffuseShader: %d", useDiffuseShader);
canvas->drawString(label, 0.0f, 0.0f, font, labelPaint);
}
{
canvas->translate(0.0f, kLabelSize);
SkString label;
label.appendf("useTranslucentPaint: %d", useTranslucentPaint);
canvas->drawString(label, 0.0f, 0.0f, font, labelPaint);
}
{
canvas->translate(0.0f, kLabelSize);
SkString label;
label.appendf("useTranslucentShader: %d", useTranslucentShader);
canvas->drawString(label, 0.0f, 0.0f, font, labelPaint);
}
canvas->restore();
gridNum++;
}
}
}
}
// Rotation/scale test
{
SkScalar xPos = (gridNum % kGridColumnNum) * kGridCellWidth;
SkScalar yPos = (gridNum / kGridColumnNum) * kGridCellWidth;
canvas->save();
canvas->translate(xPos, yPos);
this->drawRect(canvas, 0.6f, 0.6f, 45.0f, true, true, true, true, fLights);
canvas->restore();
gridNum++;
}
// Anisotropic scale test
{
SkScalar xPos = (gridNum % kGridColumnNum) * kGridCellWidth;
SkScalar yPos = (gridNum / kGridColumnNum) * kGridCellWidth;
canvas->save();
canvas->translate(xPos, yPos);
this->drawRect(canvas, 0.6f, 0.4f, 30.0f, true, true, true, true, fLights);
canvas->restore();
gridNum++;
}
// No directional lights test
{
SkScalar xPos = (gridNum % kGridColumnNum) * kGridCellWidth;
SkScalar yPos = (gridNum / kGridColumnNum) * kGridCellWidth;
canvas->save();
canvas->translate(xPos, yPos);
this->drawRect(canvas, 1.0f, 1.0f, 0.0f, true, true, false, false, fLightsNoDir);
canvas->restore();
gridNum++;
}
// Two directional lights test
{
SkScalar xPos = (gridNum % kGridColumnNum) * kGridCellWidth;
SkScalar yPos = (gridNum / kGridColumnNum) * kGridCellWidth;
canvas->save();
canvas->translate(xPos, yPos);
this->drawRect(canvas, 1.0f, 1.0f, 0.0f, true, true, false, false, fLightsTwoDir);
canvas->restore();
gridNum++;
}
}
private:
static constexpr int kTexSize = 96;
static constexpr int kNumBooleanParams = 4;
static constexpr SkScalar kLabelSize = 10.0f;
static constexpr int kGridColumnNum = 4;
static constexpr SkScalar kGridCellWidth = kTexSize + 20.0f + kNumBooleanParams * kLabelSize;
sk_sp<SkShader> fOpaqueDiffuse;
sk_sp<SkShader> fTranslucentDiffuse;
sk_sp<SkShader> fNormalMapShader;
const SkRect fRect;
sk_sp<SkLights> fLights;
sk_sp<SkLights> fLightsNoDir;
sk_sp<SkLights> fLightsTwoDir;
typedef GM INHERITED;
};
//////////////////////////////////////////////////////////////////////////////
DEF_GM(return new LightingShader2GM;)
}