/*
* Copyright 2015 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "gm.h"
#include "sk_tool_utils.h"
#include "SkLightingShader.h"
#include "SkNormalSource.h"
#include "SkPoint3.h"
#include "SkShader.h"
// Create a hemispherical normal map
static SkBitmap make_hemi_normalmap(int texSize) {
SkBitmap hemi;
hemi.allocN32Pixels(texSize, texSize);
sk_tool_utils::create_hemi_normal_map(&hemi, SkIRect::MakeWH(texSize, texSize));
return hemi;
}
// Create a truncated pyramid normal map
static SkBitmap make_frustum_normalmap(int texSize) {
SkBitmap frustum;
frustum.allocN32Pixels(texSize, texSize);
sk_tool_utils::create_frustum_normal_map(&frustum, SkIRect::MakeWH(texSize, texSize));
return frustum;
}
// Create a tetrahedral normal map
static SkBitmap make_tetra_normalmap(int texSize) {
SkBitmap tetra;
tetra.allocN32Pixels(texSize, texSize);
sk_tool_utils::create_tetra_normal_map(&tetra, SkIRect::MakeWH(texSize, texSize));
return tetra;
}
namespace skiagm {
// This GM exercises lighting shaders.
class LightingShaderGM : public GM {
public:
LightingShaderGM() {
this->setBGColor(sk_tool_utils::color_to_565(0xFFCCCCCC));
SkLights::Builder builder;
builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 1.0f, 1.0f),
SkVector3::Make(SK_ScalarRoot2Over2,
0.0f,
SK_ScalarRoot2Over2)));
builder.setAmbientLightColor(SkColor3f::Make(0.2f, 0.2f, 0.2f));
fLights = builder.finish();
}
protected:
enum NormalMap {
kHemi_NormalMap,
kFrustum_NormalMap,
kTetra_NormalMap,
kLast_NormalMap = kTetra_NormalMap
};
static constexpr int kNormalMapCount = kLast_NormalMap+1;
SkString onShortName() override {
return SkString("lightingshader");
}
SkISize onISize() override {
return SkISize::Make(kGMSize, kGMSize);
}
void onOnceBeforeDraw() override {
fDiffuse = sk_tool_utils::create_checkerboard_bitmap(
kTexSize, kTexSize,
sk_tool_utils::color_to_565(0x0),
sk_tool_utils::color_to_565(0xFF804020),
8);
fNormalMaps[kHemi_NormalMap] = make_hemi_normalmap(kTexSize);
fNormalMaps[kFrustum_NormalMap] = make_frustum_normalmap(kTexSize);
fNormalMaps[kTetra_NormalMap] = make_tetra_normalmap(kTexSize);
}
void drawRect(SkCanvas* canvas, const SkRect& r, NormalMap mapType) {
SkRect bitmapBounds = SkRect::MakeIWH(fDiffuse.width(), fDiffuse.height());
SkMatrix matrix;
matrix.setRectToRect(bitmapBounds, r, SkMatrix::kFill_ScaleToFit);
const SkMatrix& ctm = canvas->getTotalMatrix();
SkPaint paint;
sk_sp<SkShader> diffuseShader = SkShader::MakeBitmapShader(fDiffuse,
SkShader::kClamp_TileMode, SkShader::kClamp_TileMode, &matrix);
sk_sp<SkShader> normalMap = SkShader::MakeBitmapShader(fNormalMaps[mapType],
SkShader::kClamp_TileMode, SkShader::kClamp_TileMode, &matrix);
sk_sp<SkNormalSource> normalSource = SkNormalSource::MakeFromNormalMap(std::move(normalMap),
ctm);
paint.setShader(SkLightingShader::Make(std::move(diffuseShader), std::move(normalSource),
fLights));
canvas->drawRect(r, paint);
}
void onDraw(SkCanvas* canvas) override {
SkMatrix m;
SkRect r;
{
r = SkRect::MakeWH(SkIntToScalar(kTexSize), SkIntToScalar(kTexSize));
this->drawRect(canvas, r, kHemi_NormalMap);
canvas->save();
m.setRotate(45.0f, r.centerX(), r.centerY());
m.postTranslate(kGMSize/2.0f - kTexSize/2.0f, 0.0f);
canvas->setMatrix(m);
this->drawRect(canvas, r, kHemi_NormalMap);
canvas->restore();
}
{
r.offset(kGMSize - kTexSize, 0);
this->drawRect(canvas, r, kFrustum_NormalMap);
canvas->save();
m.setRotate(45.0f, r.centerX(), r.centerY());
m.postTranslate(0.0f, kGMSize/2.0f - kTexSize/2.0f);
canvas->setMatrix(m);
this->drawRect(canvas, r, kFrustum_NormalMap);
canvas->restore();
}
{
r.offset(0, kGMSize - kTexSize);
this->drawRect(canvas, r, kTetra_NormalMap);
canvas->save();
m.setRotate(45.0f, r.centerX(), r.centerY());
m.postTranslate(-kGMSize/2.0f + kTexSize/2.0f, 0.0f);
canvas->setMatrix(m);
this->drawRect(canvas, r, kTetra_NormalMap);
canvas->restore();
}
{
r.offset(kTexSize - kGMSize, 0);
this->drawRect(canvas, r, kHemi_NormalMap);
canvas->save();
m.setRotate(45.0f, r.centerX(), r.centerY());
m.postTranslate(0.0f, -kGMSize/2.0f + kTexSize/2.0f);
canvas->setMatrix(m);
this->drawRect(canvas, r, kHemi_NormalMap);
canvas->restore();
}
}
private:
static constexpr int kTexSize = 128;
static constexpr int kGMSize = 512;
SkBitmap fDiffuse;
SkBitmap fNormalMaps[kNormalMapCount];
sk_sp<SkLights> fLights;
typedef GM INHERITED;
};
//////////////////////////////////////////////////////////////////////////////
DEF_GM(return new LightingShaderGM;)
}