remove unused SkLightingShader

Change-Id: I60a3569b47b599b710c0f3a9522241748f15360d
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/280409
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Mike Reed <reed@google.com>
This commit is contained in:
Mike Reed 2020-03-30 16:14:14 -04:00 committed by Skia Commit-Bot
parent 01e6d17fe8
commit 853c15cdaa
20 changed files with 1 additions and 2463 deletions

View File

@ -1,168 +0,0 @@
/*
* 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/gm.h"
#include "include/core/SkBitmap.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkMatrix.h"
#include "include/core/SkPaint.h"
#include "include/core/SkPoint.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 "src/core/SkNormalSource.h"
#include "src/shaders/SkLightingShader.h"
#include "src/shaders/SkLights.h"
#include "tools/ToolUtils.h"
#include <utility>
// Create a hemispherical normal map
static SkBitmap make_hemi_normalmap(int texSize) {
SkBitmap hemi;
hemi.allocN32Pixels(texSize, texSize);
ToolUtils::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);
ToolUtils::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);
ToolUtils::create_tetra_normal_map(&tetra, SkIRect::MakeWH(texSize, texSize));
return tetra;
}
namespace skiagm {
// This GM exercises lighting shaders by drawing rotated and non-rotated normal mapped rects with
// a directional light off to the viewers right.
class LightingShaderGM : public GM {
public:
LightingShaderGM() {
this->setBGColor(0xFFCCCCCC);
}
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 {
{
SkLights::Builder builder;
// The direction vector is towards the light w/ +Z coming out of the screen
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();
}
fDiffuse = ToolUtils::create_checkerboard_bitmap(
kTexSize, kTexSize, 0x00000000, ToolUtils::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 = fDiffuse.makeShader(&matrix);
sk_sp<SkShader> normalMap = fNormalMaps[mapType].makeShader(&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);
}
// Draw an axis-aligned and rotated version of the normal mapped rect
void drawPair(SkCanvas* canvas, const SkRect& r, NormalMap mapType, const SkVector& v) {
SkMatrix m;
m.setRotate(45.0f, r.centerX(), r.centerY());
m.postTranslate(kScale * v.fX, kScale * v.fY);
this->drawRect(canvas, r, mapType);
canvas->save();
canvas->setMatrix(m);
this->drawRect(canvas, r, mapType);
canvas->restore();
}
void onDraw(SkCanvas* canvas) override {
SkRect r;
r = SkRect::MakeWH(SkIntToScalar(kTexSize), SkIntToScalar(kTexSize));
this->drawPair(canvas, r, kHemi_NormalMap, SkVector::Make(1.0f, 0.0f));
r.offset(kGMSize - kTexSize, 0);
this->drawPair(canvas, r, kFrustum_NormalMap, SkVector::Make(0.0f, 1.0f));
r.offset(0, kGMSize - kTexSize);
this->drawPair(canvas, r, kTetra_NormalMap, SkVector::Make(-1.0, 0.0f));
r.offset(kTexSize - kGMSize, 0);
this->drawPair(canvas, r, kHemi_NormalMap, SkVector::Make(0.0f, -1));
}
private:
static constexpr int kTexSize = 128;
static constexpr int kGMSize = 512;
static constexpr SkScalar kScale = kGMSize/2.0f - kTexSize/2.0f;
SkBitmap fDiffuse;
SkBitmap fNormalMaps[kNormalMapCount];
sk_sp<SkLights> fLights;
typedef GM INHERITED;
};
//////////////////////////////////////////////////////////////////////////////
DEF_GM(return new LightingShaderGM;)
}

View File

@ -1,287 +0,0 @@
/*
* 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;)
}

View File

@ -268,12 +268,6 @@ skia_core_sources = [
"$_src/core/SkNextID.h",
"$_src/core/SkLatticeIter.cpp",
"$_src/core/SkLatticeIter.h",
"$_src/core/SkNormalFlatSource.cpp",
"$_src/core/SkNormalFlatSource.h",
"$_src/core/SkNormalMapSource.cpp",
"$_src/core/SkNormalMapSource.h",
"$_src/core/SkNormalSource.cpp",
"$_src/core/SkNormalSource.h",
"$_src/core/SkOpts.cpp",
"$_src/core/SkOpts.h",
"$_src/core/SkOrderedReadBuffer.h",
@ -440,10 +434,6 @@ skia_core_sources = [
"$_src/shaders/SkEmptyShader.h",
"$_src/shaders/SkImageShader.cpp",
"$_src/shaders/SkImageShader.h",
"$_src/shaders/SkLightingShader.cpp",
"$_src/shaders/SkLightingShader.h",
"$_src/shaders/SkLights.cpp",
"$_src/shaders/SkLights.h",
"$_src/shaders/SkLocalMatrixShader.cpp",
"$_src/shaders/SkLocalMatrixShader.h",
"$_src/shaders/SkShader.cpp",

View File

@ -233,8 +233,6 @@ gm_sources = [
"$_gm/lcdoverlap.cpp",
"$_gm/lcdtext.cpp",
"$_gm/lighting.cpp",
"$_gm/lightingshader.cpp",
"$_gm/lightingshader2.cpp",
"$_gm/linepaths.cpp",
"$_gm/localmatriximagefilter.cpp",
"$_gm/localmatriximageshader.cpp",

View File

@ -55,8 +55,6 @@ samples_sources = [
"$_samplecode/SampleLayerMask.cpp",
"$_samplecode/SampleLayers.cpp",
"$_samplecode/SampleLCD.cpp",
"$_samplecode/SampleLighting.cpp",
"$_samplecode/SampleLitAtlas.cpp",
"$_samplecode/SampleManyRects.cpp",
"$_samplecode/SampleMegaStroke.cpp",
"$_samplecode/SampleMixer.cpp",

View File

@ -37,7 +37,7 @@ public:
kSkShaderBase_Type,
kSkUnused_Type, // used to be SkUnitMapper
kSkUnused_Type2,
kSkNormalSource_Type,
kSkUnused_Type3, // use to be NormalSource,
};
typedef sk_sp<SkFlattenable> (*Factory)(SkReadBuffer&);

View File

@ -1,97 +0,0 @@
/*
* 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 "include/core/SkCanvas.h"
#include "include/core/SkPoint3.h"
#include "samplecode/DecodeFile.h"
#include "samplecode/Sample.h"
#include "src/core/SkNormalSource.h"
#include "src/shaders/SkLightingShader.h"
#include "tools/Resources.h"
static sk_sp<SkLights> create_lights(SkScalar angle, SkScalar blue) {
const SkVector3 dir = SkVector3::Make(SkScalarSin(angle)*SkScalarSin(SK_ScalarPI*0.25f),
SkScalarCos(angle)*SkScalarSin(SK_ScalarPI*0.25f),
SkScalarCos(SK_ScalarPI*0.25f));
SkLights::Builder builder;
builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 1.0f, blue), dir));
builder.setAmbientLightColor(SkColor3f::Make(0.1f, 0.1f, 0.1f));
return builder.finish();
}
////////////////////////////////////////////////////////////////////////////
class LightingView : public Sample {
public:
LightingView() : fLightAngle(0.0f), fColorFactor(0.0f) {}
protected:
SkString name() override { return SkString("Lighting"); }
void onOnceBeforeDraw() override {
{
SkBitmap diffuseBitmap;
SkAssertResult(GetResourceAsBitmap("images/brickwork-texture.jpg", &diffuseBitmap));
fRect = SkRect::MakeIWH(diffuseBitmap.width(), diffuseBitmap.height());
fDiffuseShader = diffuseBitmap.makeShader();
}
{
SkBitmap normalBitmap;
SkAssertResult(GetResourceAsBitmap("images/brickwork_normal-map.jpg", &normalBitmap));
sk_sp<SkShader> normalMap = normalBitmap.makeShader();
fNormalSource = SkNormalSource::MakeFromNormalMap(std::move(normalMap), SkMatrix::I());
}
}
void onDrawContent(SkCanvas* canvas) override {
sk_sp<SkLights> lights(create_lights(fLightAngle, fColorFactor));
SkPaint paint;
paint.setShader(SkLightingShader::Make(fDiffuseShader,
fNormalSource,
std::move(lights)));
paint.setColor(SK_ColorBLACK);
canvas->drawRect(fRect, paint);
}
Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey modi) override {
return this->INHERITED::onFindClickHandler(x, y, modi);
}
bool onAnimate(double nanos) override {
fLightAngle += 0.015f;
fColorFactor += 0.01f;
if (fColorFactor > 1.0f) {
fColorFactor = 0.0f;
}
return true;
}
private:
SkRect fRect;
sk_sp<SkShader> fDiffuseShader;
sk_sp<SkNormalSource> fNormalSource;
SkScalar fLightAngle;
SkScalar fColorFactor;
typedef Sample INHERITED;
};
//////////////////////////////////////////////////////////////////////////////
DEF_SAMPLE( return new LightingView(); )

View File

@ -1,488 +0,0 @@
/*
* 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 "include/core/SkCanvas.h"
#include "include/core/SkDrawable.h"
#include "include/core/SkRSXform.h"
#include "include/utils/SkRandom.h"
#include "samplecode/Sample.h"
#include "src/core/SkNormalSource.h"
#include "src/shaders/SkBitmapProcShader.h"
#include "src/shaders/SkLightingShader.h"
#include "src/shaders/SkLights.h"
#include "tools/ToolUtils.h"
// A crude normal mapped asteroids-like sample
class DrawLitAtlasDrawable : public SkDrawable {
public:
DrawLitAtlasDrawable(const SkRect& r)
: fBounds(r)
, fUseColors(false)
, fLightDir(SkVector3::Make(1.0f, 0.0f, 0.0f)) {
fAtlas = MakeAtlas();
SkRandom rand;
for (int i = 0; i < kNumAsteroids; ++i) {
fAsteroids[i].initAsteroid(&rand, fBounds, &fDiffTex[i], &fNormTex[i]);
}
fShip.initShip(fBounds, &fDiffTex[kNumAsteroids], &fNormTex[kNumAsteroids]);
this->updateLights();
}
void toggleUseColors() {
fUseColors = !fUseColors;
}
void rotateLight() {
SkScalar r = SK_ScalarPI / 6.0f,
s = SkScalarSin(r),
c = SkScalarCos(r);
SkScalar newX = c * fLightDir.fX - s * fLightDir.fY;
SkScalar newY = s * fLightDir.fX + c * fLightDir.fY;
fLightDir.set(newX, newY, 0.0f);
this->updateLights();
}
void left() {
SkScalar newRot = SkScalarMod(fShip.rot() + (2*SK_ScalarPI - SK_ScalarPI/32.0f),
2 * SK_ScalarPI);
fShip.setRot(newRot);
}
void right() {
SkScalar newRot = SkScalarMod(fShip.rot() + SK_ScalarPI/32.0f, 2 * SK_ScalarPI);
fShip.setRot(newRot);
}
void thrust() {
SkScalar s = SkScalarSin(fShip.rot()),
c = SkScalarCos(fShip.rot());
SkVector newVel = fShip.velocity();
newVel.fX += s;
newVel.fY += -c;
SkScalar len = newVel.length();
if (len > kMaxShipSpeed) {
newVel.setLength(SkIntToScalar(kMaxShipSpeed));
}
fShip.setVelocity(newVel);
}
protected:
void onDraw(SkCanvas* canvas) override {
SkRSXform xforms[kNumAsteroids+kNumShips];
SkColor colors[kNumAsteroids+kNumShips];
for (int i = 0; i < kNumAsteroids; ++i) {
fAsteroids[i].advance(fBounds);
xforms[i] = fAsteroids[i].asRSXform();
if (fUseColors) {
colors[i] = SkColorSetARGB(0xFF, 0xFF, 0xFF, 0xFF);
}
}
fShip.advance(fBounds);
xforms[kNumAsteroids] = fShip.asRSXform();
if (fUseColors) {
colors[kNumAsteroids] = SkColorSetARGB(0xFF, 0xFF, 0xFF, 0xFF);
}
#ifdef SK_DEBUG
canvas->drawBitmap(fAtlas, 0, 0); // just to see the atlas
this->drawLightDir(canvas, fBounds.centerX(), fBounds.centerY());
#endif
#if 0
// TODO: revitalize when drawLitAtlas API lands
SkPaint paint;
paint.setFilterQuality(kLow_SkFilterQuality);
const SkRect cull = this->getBounds();
const SkColor* colorsPtr = fUseColors ? colors : NULL;
canvas->drawLitAtlas(fAtlas, xforms, fDiffTex, fNormTex, colorsPtr, kNumAsteroids+1,
SkXfermode::kModulate_Mode, &cull, &paint, fLights);
#else
SkMatrix diffMat, normalMat;
for (int i = 0; i < kNumAsteroids+1; ++i) {
colors[i] = colors[i] & 0xFF000000; // to silence compilers
SkPaint paint;
SkRect r = fDiffTex[i];
r.offsetTo(0, 0);
diffMat.setRectToRect(fDiffTex[i], r, SkMatrix::kFill_ScaleToFit);
normalMat.setRectToRect(fNormTex[i], r, SkMatrix::kFill_ScaleToFit);
SkMatrix m;
m.setRSXform(xforms[i]);
sk_sp<SkShader> normalMap = fAtlas.makeShader(&normalMat);
sk_sp<SkNormalSource> normalSource = SkNormalSource::MakeFromNormalMap(
std::move(normalMap), m);
sk_sp<SkShader> diffuseShader = fAtlas.makeShader(&diffMat);
paint.setShader(SkLightingShader::Make(std::move(diffuseShader),
std::move(normalSource), fLights));
canvas->save();
canvas->setMatrix(m);
canvas->drawRect(r, paint);
canvas->restore();
}
#endif
#ifdef SK_DEBUG
{
SkPaint paint;
paint.setColor(SK_ColorRED);
for (int i = 0; i < kNumAsteroids; ++i) {
canvas->drawCircle(fAsteroids[i].pos().x(), fAsteroids[i].pos().y(), 2, paint);
}
canvas->drawCircle(fShip.pos().x(), fShip.pos().y(), 2, paint);
paint.setStyle(SkPaint::kStroke_Style);
canvas->drawRect(this->getBounds(), paint);
}
#endif
}
SkRect onGetBounds() override {
return fBounds;
}
private:
enum ObjType {
kBigAsteroid_ObjType = 0,
kMedAsteroid_ObjType,
kSmAsteroid_ObjType,
kShip_ObjType,
kLast_ObjType = kShip_ObjType
};
static const int kObjTypeCount = kLast_ObjType + 1;
void updateLights() {
SkLights::Builder builder;
builder.add(SkLights::Light::MakeDirectional(
SkColor3f::Make(1.0f, 1.0f, 1.0f), fLightDir));
builder.setAmbientLightColor(SkColor3f::Make(0.2f, 0.2f, 0.2f));
fLights = builder.finish();
}
#ifdef SK_DEBUG
// Draw a vector to the light
void drawLightDir(SkCanvas* canvas, SkScalar centerX, SkScalar centerY) {
static const int kBgLen = 30;
static const int kSmLen = 5;
// TODO: change the lighting coordinate system to be right handed
SkPoint p1 = SkPoint::Make(centerX + kBgLen * fLightDir.fX,
centerY - kBgLen * fLightDir.fY);
SkPoint p2 = SkPoint::Make(centerX + (kBgLen-kSmLen) * fLightDir.fX,
centerY - (kBgLen-kSmLen) * fLightDir.fY);
SkPaint p;
canvas->drawLine(centerX, centerY, p1.fX, p1.fY, p);
canvas->drawLine(p1.fX, p1.fY,
p2.fX - kSmLen * fLightDir.fY, p2.fY - kSmLen * fLightDir.fX, p);
canvas->drawLine(p1.fX, p1.fY,
p2.fX + kSmLen * fLightDir.fY, p2.fY + kSmLen * fLightDir.fX, p);
}
#endif
// Create the mixed diffuse & normal atlas
//
// big color circle | big normal hemi
// ------------------------------------
// med color circle | med normal pyra
// ------------------------------------
// sm color circle | sm normal hemi
// ------------------------------------
// big ship | big tetra normal
static SkBitmap MakeAtlas() {
SkBitmap atlas;
atlas.allocN32Pixels(kAtlasWidth, kAtlasHeight);
for (int y = 0; y < kAtlasHeight; ++y) {
int x = 0;
for ( ; x < kBigSize+kPad; ++x) {
*atlas.getAddr32(x, y) = SK_ColorTRANSPARENT;
}
for ( ; x < kAtlasWidth; ++x) {
*atlas.getAddr32(x, y) = SkPackARGB32(0xFF, 0x88, 0x88, 0xFF);
}
}
// big asteroid
{
SkPoint bigCenter = SkPoint::Make(kDiffXOff + kBigSize/2.0f, kBigYOff + kBigSize/2.0f);
for (int y = kBigYOff; y < kBigYOff+kBigSize; ++y) {
for (int x = kDiffXOff; x < kDiffXOff+kBigSize; ++x) {
SkScalar distSq = (x - bigCenter.fX) * (x - bigCenter.fX) +
(y - bigCenter.fY) * (y - bigCenter.fY);
if (distSq > kBigSize*kBigSize/4.0f) {
*atlas.getAddr32(x, y) = SkPreMultiplyARGB(0, 0, 0, 0);
} else {
*atlas.getAddr32(x, y) = SkPackARGB32(0xFF, 0xFF, 0, 0);
}
}
}
ToolUtils::create_hemi_normal_map(
&atlas, SkIRect::MakeXYWH(kNormXOff, kBigYOff, kBigSize, kBigSize));
}
// medium asteroid
{
for (int y = kMedYOff; y < kMedYOff+kMedSize; ++y) {
for (int x = kDiffXOff; x < kDiffXOff+kMedSize; ++x) {
*atlas.getAddr32(x, y) = SkPackARGB32(0xFF, 0, 0xFF, 0);
}
}
ToolUtils::create_frustum_normal_map(
&atlas, SkIRect::MakeXYWH(kNormXOff, kMedYOff, kMedSize, kMedSize));
}
// small asteroid
{
SkPoint smCenter = SkPoint::Make(kDiffXOff + kSmSize/2.0f, kSmYOff + kSmSize/2.0f);
for (int y = kSmYOff; y < kSmYOff+kSmSize; ++y) {
for (int x = kDiffXOff; x < kDiffXOff+kSmSize; ++x) {
SkScalar distSq = (x - smCenter.fX) * (x - smCenter.fX) +
(y - smCenter.fY) * (y - smCenter.fY);
if (distSq > kSmSize*kSmSize/4.0f) {
*atlas.getAddr32(x, y) = SkPreMultiplyARGB(0, 0, 0, 0);
} else {
*atlas.getAddr32(x, y) = SkPackARGB32(0xFF, 0, 0, 0xFF);
}
}
}
ToolUtils::create_hemi_normal_map(
&atlas, SkIRect::MakeXYWH(kNormXOff, kSmYOff, kSmSize, kSmSize));
}
// ship
{
SkScalar shipMidLine = kDiffXOff + kMedSize/2.0f;
for (int y = kShipYOff; y < kShipYOff+kMedSize; ++y) {
SkScalar scaledY = (y - kShipYOff)/(float)kMedSize; // 0..1
for (int x = kDiffXOff; x < kDiffXOff+kMedSize; ++x) {
SkScalar scaledX;
if (x < shipMidLine) {
scaledX = 1.0f - (x - kDiffXOff)/(kMedSize/2.0f); // 0..1
} else {
scaledX = (x - shipMidLine)/(kMedSize/2.0f); // 0..1
}
if (scaledX < scaledY) {
*atlas.getAddr32(x, y) = SkPackARGB32(0xFF, 0, 0xFF, 0xFF);
} else {
*atlas.getAddr32(x, y) = SkPackARGB32(0, 0, 0, 0);
}
}
}
ToolUtils::create_tetra_normal_map(
&atlas, SkIRect::MakeXYWH(kNormXOff, kShipYOff, kMedSize, kMedSize));
}
return atlas;
}
class ObjectRecord {
public:
void initAsteroid(SkRandom *rand, const SkRect& bounds,
SkRect* diffTex, SkRect* normTex) {
static const SkScalar gMaxSpeeds[3] = { 1, 2, 5 }; // smaller asteroids can go faster
static const SkScalar gYOffs[3] = { kBigYOff, kMedYOff, kSmYOff };
static const SkScalar gSizes[3] = { kBigSize, kMedSize, kSmSize };
static unsigned int asteroidType = 0;
fObjType = static_cast<ObjType>(asteroidType++ % 3);
fPosition.set(bounds.fLeft + rand->nextUScalar1() * bounds.width(),
bounds.fTop + rand->nextUScalar1() * bounds.height());
fVelocity.fX = rand->nextSScalar1();
fVelocity.fY = sqrt(1.0f - fVelocity.fX * fVelocity.fX);
SkASSERT(SkScalarNearlyEqual(fVelocity.length(), 1.0f));
fVelocity *= gMaxSpeeds[fObjType];
fRot = 0;
fDeltaRot = rand->nextSScalar1() / 32;
diffTex->setXYWH(SkIntToScalar(kDiffXOff), gYOffs[fObjType],
gSizes[fObjType], gSizes[fObjType]);
normTex->setXYWH(SkIntToScalar(kNormXOff), gYOffs[fObjType],
gSizes[fObjType], gSizes[fObjType]);
}
void initShip(const SkRect& bounds, SkRect* diffTex, SkRect* normTex) {
fObjType = kShip_ObjType;
fPosition.set(bounds.centerX(), bounds.centerY());
fVelocity = SkVector::Make(0.0f, 0.0f);
fRot = 0.0f;
fDeltaRot = 0.0f;
diffTex->setXYWH(SkIntToScalar(kDiffXOff), SkIntToScalar(kShipYOff),
SkIntToScalar(kMedSize), SkIntToScalar(kMedSize));
normTex->setXYWH(SkIntToScalar(kNormXOff), SkIntToScalar(kShipYOff),
SkIntToScalar(kMedSize), SkIntToScalar(kMedSize));
}
void advance(const SkRect& bounds) {
fPosition += fVelocity;
if (fPosition.fX > bounds.right()) {
SkASSERT(fVelocity.fX > 0);
fVelocity.fX = -fVelocity.fX;
} else if (fPosition.fX < bounds.left()) {
SkASSERT(fVelocity.fX < 0);
fVelocity.fX = -fVelocity.fX;
}
if (fPosition.fY > bounds.bottom()) {
if (fVelocity.fY > 0) {
fVelocity.fY = -fVelocity.fY;
}
} else if (fPosition.fY < bounds.top()) {
if (fVelocity.fY < 0) {
fVelocity.fY = -fVelocity.fY;
}
}
fRot += fDeltaRot;
fRot = SkScalarMod(fRot, 2 * SK_ScalarPI);
}
const SkPoint& pos() const { return fPosition; }
SkScalar rot() const { return fRot; }
void setRot(SkScalar rot) { fRot = rot; }
const SkPoint& velocity() const { return fVelocity; }
void setVelocity(const SkPoint& velocity) { fVelocity = velocity; }
SkRSXform asRSXform() const {
static const SkScalar gHalfSizes[kObjTypeCount] = {
SkScalarHalf(kBigSize),
SkScalarHalf(kMedSize),
SkScalarHalf(kSmSize),
SkScalarHalf(kMedSize),
};
return SkRSXform::MakeFromRadians(1.0f, fRot, fPosition.x(), fPosition.y(),
gHalfSizes[fObjType],
gHalfSizes[fObjType]);
}
private:
ObjType fObjType;
SkPoint fPosition;
SkVector fVelocity;
SkScalar fRot; // In radians.
SkScalar fDeltaRot; // In radiands. Not used by ship.
};
private:
static const int kNumLights = 2;
static const int kNumAsteroids = 6;
static const int kNumShips = 1;
static const int kBigSize = 128;
static const int kMedSize = 64;
static const int kSmSize = 32;
static const int kPad = 1;
static const int kAtlasWidth = kBigSize + kBigSize + 2 * kPad; // 2 pads in the middle
static const int kAtlasHeight = kBigSize + kMedSize + kSmSize + kMedSize + 3 * kPad;
static const int kDiffXOff = 0;
static const int kNormXOff = kBigSize + 2 * kPad;
static const int kBigYOff = 0;
static const int kMedYOff = kBigSize + kPad;
static const int kSmYOff = kMedYOff + kMedSize + kPad;
static const int kShipYOff = kSmYOff + kSmSize + kPad;
static const int kMaxShipSpeed = 5;
SkBitmap fAtlas;
ObjectRecord fAsteroids[kNumAsteroids];
ObjectRecord fShip;
SkRect fDiffTex[kNumAsteroids+kNumShips];
SkRect fNormTex[kNumAsteroids+kNumShips];
SkRect fBounds;
bool fUseColors;
SkVector3 fLightDir;
sk_sp<SkLights> fLights;
typedef SkDrawable INHERITED;
};
class DrawLitAtlasView : public Sample {
public:
DrawLitAtlasView() : fDrawable(new DrawLitAtlasDrawable(SkRect::MakeWH(640, 480))) {}
protected:
SkString name() override { return SkString("DrawLitAtlas"); }
bool onChar(SkUnichar uni) override {
switch (uni) {
case 'C':
fDrawable->toggleUseColors();
return true;
case 'j':
fDrawable->left();
return true;
case 'k':
fDrawable->thrust();
return true;
case 'l':
fDrawable->right();
return true;
case 'o':
fDrawable->rotateLight();
return true;
default:
break;
}
return false;
}
void onDrawContent(SkCanvas* canvas) override {
canvas->drawDrawable(fDrawable.get());
}
bool onAnimate(double nanos) override { return true; }
private:
sk_sp<DrawLitAtlasDrawable> fDrawable;
typedef Sample INHERITED;
};
//////////////////////////////////////////////////////////////////////////////
DEF_SAMPLE( return new DrawLitAtlasView(); )

View File

@ -1,100 +0,0 @@
/*
* 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 "src/core/SkNormalFlatSource.h"
#include "include/core/SkPoint3.h"
#include "src/core/SkArenaAlloc.h"
#include "src/core/SkNormalSource.h"
#include "src/core/SkReadBuffer.h"
#include "src/core/SkWriteBuffer.h"
#if SK_SUPPORT_GPU
#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
class NormalFlatFP : public GrFragmentProcessor {
public:
static std::unique_ptr<GrFragmentProcessor> Make() {
return std::unique_ptr<GrFragmentProcessor>(new NormalFlatFP());
}
const char* name() const override { return "NormalFlatFP"; }
std::unique_ptr<GrFragmentProcessor> clone() const override { return Make(); }
private:
class GLSLNormalFlatFP : public GrGLSLFragmentProcessor {
public:
GLSLNormalFlatFP() {}
void emitCode(EmitArgs& args) override {
GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
fragBuilder->codeAppendf("%s = half4(0, 0, 1, 0);", args.fOutputColor);
}
private:
void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override {}
};
NormalFlatFP()
: INHERITED(kFlatNormalsFP_ClassID, kConstantOutputForConstantInput_OptimizationFlag) {
}
void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {}
SkPMColor4f constantOutputForConstantInput(const SkPMColor4f&) const override {
return { 0, 0, 1, 0 };
}
GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { return new GLSLNormalFlatFP; }
bool onIsEqual(const GrFragmentProcessor&) const override { return true; }
typedef GrFragmentProcessor INHERITED;
};
std::unique_ptr<GrFragmentProcessor> SkNormalFlatSourceImpl::asFragmentProcessor(
const GrFPArgs&) const {
return NormalFlatFP::Make();
}
#endif // SK_SUPPORT_GPU
////////////////////////////////////////////////////////////////////////////
SkNormalFlatSourceImpl::Provider::Provider() {}
SkNormalFlatSourceImpl::Provider::~Provider() {}
SkNormalSource::Provider* SkNormalFlatSourceImpl::asProvider(const SkShaderBase::ContextRec &rec,
SkArenaAlloc *alloc) const {
return alloc->make<Provider>();
}
void SkNormalFlatSourceImpl::Provider::fillScanLine(int x, int y, SkPoint3 output[],
int count) const {
for (int i = 0; i < count; i++) {
output[i] = {0.0f, 0.0f, 1.0f};
}
}
////////////////////////////////////////////////////////////////////////////////
sk_sp<SkFlattenable> SkNormalFlatSourceImpl::CreateProc(SkReadBuffer& buf) {
return sk_make_sp<SkNormalFlatSourceImpl>();
}
void SkNormalFlatSourceImpl::flatten(SkWriteBuffer& buf) const {
this->INHERITED::flatten(buf);
}
////////////////////////////////////////////////////////////////////////////
sk_sp<SkNormalSource> SkNormalSource::MakeFlat() {
return sk_make_sp<SkNormalFlatSourceImpl>();
}

View File

@ -1,47 +0,0 @@
/*
* Copyright 2016 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkNormalFlatSource_DEFINED
#define SkNormalFlatSource_DEFINED
#include "src/core/SkNormalSource.h"
class SkNormalFlatSourceImpl : public SkNormalSource {
public:
SkNormalFlatSourceImpl(){}
#if SK_SUPPORT_GPU
std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(const GrFPArgs& args) const override;
#endif
SkNormalSource::Provider* asProvider(const SkShaderBase::ContextRec& rec,
SkArenaAlloc* alloc) const override;
protected:
void flatten(SkWriteBuffer& buf) const override;
private:
SK_FLATTENABLE_HOOKS(SkNormalFlatSourceImpl)
class Provider : public SkNormalSource::Provider {
public:
Provider();
~Provider() override;
void fillScanLine(int x, int y, SkPoint3 output[], int count) const override;
private:
typedef SkNormalSource::Provider INHERITED;
};
friend class SkNormalSource;
typedef SkNormalSource INHERITED;
};
#endif

View File

@ -1,256 +0,0 @@
/*
* 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 "src/core/SkNormalMapSource.h"
#include "include/core/SkMatrix.h"
#include "src/core/SkArenaAlloc.h"
#include "src/core/SkNormalSource.h"
#include "src/core/SkReadBuffer.h"
#include "src/core/SkWriteBuffer.h"
#include "src/shaders/SkLightingShader.h"
#if SK_SUPPORT_GPU
#include "src/gpu/GrCoordTransform.h"
#include "src/gpu/SkGr.h"
#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
class NormalMapFP : public GrFragmentProcessor {
public:
static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> mapFP,
const SkMatrix& invCTM) {
return std::unique_ptr<GrFragmentProcessor>(new NormalMapFP(std::move(mapFP), invCTM));
}
const char* name() const override { return "NormalMapFP"; }
const SkMatrix& invCTM() const { return fInvCTM; }
std::unique_ptr<GrFragmentProcessor> clone() const override {
return Make(this->childProcessor(0).clone(), fInvCTM);
}
private:
class GLSLNormalMapFP : public GrGLSLFragmentProcessor {
public:
GLSLNormalMapFP() : fColumnMajorInvCTM22{0.0f} {}
void emitCode(EmitArgs& args) override {
GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
// add uniform
const char* xformUniName = nullptr;
fXformUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kFloat2x2_GrSLType,
"Xform", &xformUniName);
SkString dstNormalColor = this->invokeChild(0, args);
fragBuilder->codeAppendf("float3 normal = normalize(%s.rgb - float3(0.5));",
dstNormalColor.c_str());
// If there's no x & y components, return (0, 0, +/- 1) instead to avoid division by 0
fragBuilder->codeAppend( "if (abs(normal.z) > 0.999) {");
fragBuilder->codeAppendf(" %s = normalize(half4(0.0, 0.0, half(normal.z), 0.0));",
args.fOutputColor);
// Else, Normalizing the transformed X and Y, while keeping constant both Z and the
// vector's angle in the XY plane. This maintains the "slope" for the surface while
// appropriately rotating the normal regardless of any anisotropic scaling that occurs.
// Here, we call 'scaling factor' the number that must divide the transformed X and Y so
// that the normal's length remains equal to 1.
fragBuilder->codeAppend( "} else {");
fragBuilder->codeAppendf(" float2 transformed = %s * normal.xy;",
xformUniName);
fragBuilder->codeAppend( " float scalingFactorSquared = "
"( (transformed.x * transformed.x) "
"+ (transformed.y * transformed.y) )"
"/(1.0 - (normal.z * normal.z));");
fragBuilder->codeAppendf(" %s = half4(half2(transformed * "
"inversesqrt(scalingFactorSquared)),"
"half(normal.z), 0.0);",
args.fOutputColor);
fragBuilder->codeAppend( "}");
}
static void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder* b) {
b->add32(0x0);
}
private:
void onSetData(const GrGLSLProgramDataManager& pdman,
const GrFragmentProcessor& proc) override {
const NormalMapFP& normalMapFP = proc.cast<NormalMapFP>();
const SkMatrix& invCTM = normalMapFP.invCTM();
fColumnMajorInvCTM22[0] = invCTM.get(SkMatrix::kMScaleX);
fColumnMajorInvCTM22[1] = invCTM.get(SkMatrix::kMSkewY);
fColumnMajorInvCTM22[2] = invCTM.get(SkMatrix::kMSkewX);
fColumnMajorInvCTM22[3] = invCTM.get(SkMatrix::kMScaleY);
pdman.setMatrix2f(fXformUni, fColumnMajorInvCTM22);
}
private:
// Upper-right 2x2 corner of the inverse of the CTM in column-major form
float fColumnMajorInvCTM22[4];
GrGLSLProgramDataManager::UniformHandle fXformUni;
};
void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
GLSLNormalMapFP::GenKey(*this, caps, b);
}
NormalMapFP(std::unique_ptr<GrFragmentProcessor> mapFP, const SkMatrix& invCTM)
: INHERITED(kMappedNormalsFP_ClassID, kNone_OptimizationFlags)
, fInvCTM(invCTM) {
this->registerChildProcessor(std::move(mapFP));
}
GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { return new GLSLNormalMapFP; }
bool onIsEqual(const GrFragmentProcessor& proc) const override {
const NormalMapFP& normalMapFP = proc.cast<NormalMapFP>();
return fInvCTM == normalMapFP.fInvCTM;
}
SkMatrix fInvCTM;
typedef GrFragmentProcessor INHERITED;
};
std::unique_ptr<GrFragmentProcessor> SkNormalMapSourceImpl::asFragmentProcessor(
const GrFPArgs& args) const {
std::unique_ptr<GrFragmentProcessor> mapFP = as_SB(fMapShader)->asFragmentProcessor(args);
if (!mapFP) {
return nullptr;
}
return NormalMapFP::Make(std::move(mapFP), fInvCTM);
}
#endif // SK_SUPPORT_GPU
////////////////////////////////////////////////////////////////////////////
SkNormalMapSourceImpl::Provider::Provider(const SkNormalMapSourceImpl& source,
SkShaderBase::Context* mapContext)
: fSource(source)
, fMapContext(mapContext) {}
SkNormalSource::Provider* SkNormalMapSourceImpl::asProvider(const SkShaderBase::ContextRec &rec,
SkArenaAlloc* alloc) const {
SkMatrix normTotalInv;
if (!this->computeNormTotalInverse(rec, &normTotalInv)) {
return nullptr;
}
// Normals really aren't colors, so to ensure we can always make the context, we ignore
// the rec's colorspace
SkColorSpace* dstColorSpace = nullptr;
// Overriding paint's alpha because we need the normal map's RGB channels to be unpremul'd
SkPaint overridePaint {*(rec.fPaint)};
overridePaint.setAlpha(0xFF);
SkShaderBase::ContextRec overrideRec(overridePaint, *(rec.fMatrix), rec.fLocalMatrix,
rec.fDstColorType, dstColorSpace);
auto* context = as_SB(fMapShader)->makeContext(overrideRec, alloc);
if (!context) {
return nullptr;
}
return alloc->make<Provider>(*this, context);
}
bool SkNormalMapSourceImpl::computeNormTotalInverse(const SkShaderBase::ContextRec& rec,
SkMatrix* normTotalInverse) const {
SkMatrix total = SkMatrix::Concat(*rec.fMatrix, as_SB(fMapShader)->getLocalMatrix());
if (rec.fLocalMatrix) {
total.preConcat(*rec.fLocalMatrix);
}
return total.invert(normTotalInverse);
}
#define BUFFER_MAX 16
void SkNormalMapSourceImpl::Provider::fillScanLine(int x, int y, SkPoint3 output[],
int count) const {
SkPMColor tmpNormalColors[BUFFER_MAX];
do {
int n = std::min(count, BUFFER_MAX);
fMapContext->shadeSpan(x, y, tmpNormalColors, n);
for (int i = 0; i < n; i++) {
SkPoint3 tempNorm;
tempNorm.set(SkIntToScalar(SkGetPackedR32(tmpNormalColors[i])) - 127.0f,
SkIntToScalar(SkGetPackedG32(tmpNormalColors[i])) - 127.0f,
SkIntToScalar(SkGetPackedB32(tmpNormalColors[i])) - 127.0f);
tempNorm.normalize();
if (!SkScalarNearlyEqual(SkScalarAbs(tempNorm.fZ), 1.0f)) {
SkVector transformed = fSource.fInvCTM.mapVector(tempNorm.fX, tempNorm.fY);
// Normalizing the transformed X and Y, while keeping constant both Z and the
// vector's angle in the XY plane. This maintains the "slope" for the surface while
// appropriately rotating the normal for any anisotropic scaling that occurs.
// Here, we call scaling factor the number that must divide the transformed X and Y
// so that the normal's length remains equal to 1.
SkScalar scalingFactorSquared =
(SkScalarSquare(transformed.fX) + SkScalarSquare(transformed.fY))
/ (1.0f - SkScalarSquare(tempNorm.fZ));
SkScalar invScalingFactor = SkScalarInvert(SkScalarSqrt(scalingFactorSquared));
output[i].fX = transformed.fX * invScalingFactor;
output[i].fY = transformed.fY * invScalingFactor;
output[i].fZ = tempNorm.fZ;
} else {
output[i] = {0.0f, 0.0f, tempNorm.fZ};
output[i].normalize();
}
SkASSERT(SkScalarNearlyEqual(output[i].length(), 1.0f));
}
output += n;
x += n;
count -= n;
} while (count > 0);
}
////////////////////////////////////////////////////////////////////////////////
sk_sp<SkFlattenable> SkNormalMapSourceImpl::CreateProc(SkReadBuffer& buf) {
sk_sp<SkShader> mapShader = buf.readFlattenable<SkShaderBase>();
SkMatrix invCTM;
buf.readMatrix(&invCTM);
return sk_make_sp<SkNormalMapSourceImpl>(std::move(mapShader), invCTM);
}
void SkNormalMapSourceImpl::flatten(SkWriteBuffer& buf) const {
this->INHERITED::flatten(buf);
buf.writeFlattenable(fMapShader.get());
buf.writeMatrix(fInvCTM);
}
////////////////////////////////////////////////////////////////////////////
sk_sp<SkNormalSource> SkNormalSource::MakeFromNormalMap(sk_sp<SkShader> map, const SkMatrix& ctm) {
SkMatrix invCTM;
if (!ctm.invert(&invCTM) || !map) {
return nullptr;
}
return sk_make_sp<SkNormalMapSourceImpl>(std::move(map), invCTM);
}

View File

@ -1,57 +0,0 @@
/*
* Copyright 2016 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkNormalMapSource_DEFINED
#define SkNormalMapSource_DEFINED
#include "src/core/SkNormalSource.h"
class SkNormalMapSourceImpl : public SkNormalSource {
public:
SkNormalMapSourceImpl(sk_sp<SkShader> mapShader, const SkMatrix& invCTM)
: fMapShader(std::move(mapShader))
, fInvCTM(invCTM) {}
#if SK_SUPPORT_GPU
std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(const GrFPArgs& args) const override;
#endif
SkNormalSource::Provider* asProvider(const SkShaderBase::ContextRec& rec,
SkArenaAlloc* alloc) const override;
protected:
void flatten(SkWriteBuffer& buf) const override;
bool computeNormTotalInverse(const SkShaderBase::ContextRec& rec,
SkMatrix* normTotalInverse) const;
private:
SK_FLATTENABLE_HOOKS(SkNormalMapSourceImpl)
class Provider : public SkNormalSource::Provider {
public:
Provider(const SkNormalMapSourceImpl& source, SkShaderBase::Context* mapContext);
void fillScanLine(int x, int y, SkPoint3 output[], int count) const override;
private:
const SkNormalMapSourceImpl& fSource;
SkShaderBase::Context* fMapContext;
typedef SkNormalSource::Provider INHERITED;
};
sk_sp<SkShader> fMapShader;
SkMatrix fInvCTM; // Inverse of the canvas total matrix, used for rotating normals.
friend class SkNormalSource;
typedef SkNormalSource INHERITED;
};
#endif

View File

@ -1,19 +0,0 @@
/*
* 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 "src/core/SkNormalFlatSource.h"
#include "src/core/SkNormalMapSource.h"
#include "src/core/SkNormalSource.h"
// Generating vtable
SkNormalSource::~SkNormalSource() {}
void SkNormalSource::RegisterFlattenables() {
SK_REGISTER_FLATTENABLE(SkNormalMapSourceImpl);
SK_REGISTER_FLATTENABLE(SkNormalFlatSourceImpl);
}

View File

@ -1,82 +0,0 @@
/*
* Copyright 2016 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkNormalSource_DEFINED
#define SkNormalSource_DEFINED
#include "include/core/SkFlattenable.h"
#include "src/shaders/SkShaderBase.h"
class SkMatrix;
struct SkPoint3;
#if SK_SUPPORT_GPU
class GrFragmentProcessor;
#endif
/** Abstract class that generates or reads in normals for use by SkLightingShader.
*/
class SkNormalSource : public SkFlattenable {
public:
virtual ~SkNormalSource() override;
#if SK_SUPPORT_GPU
/** Returns a fragment processor that takes no input and outputs a normal (already rotated)
as its output color. To be used as a child fragment processor.
*/
virtual std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(const GrFPArgs&) const = 0;
#endif
class Provider {
public:
virtual ~Provider() {}
/** Called for each span of the object being drawn on the CPU. Your subclass should set
the appropriate normals that correspond to the specified device coordinates.
*/
virtual void fillScanLine(int x, int y, SkPoint3 output[], int count) const = 0;
};
/** Returns an instance of 'Provider' that provides normals for the CPU pipeline. The
necessary data will be initialized in place at 'storage'.
*/
virtual Provider* asProvider(const SkShaderBase::ContextRec&, SkArenaAlloc*) const = 0;
/** Returns a normal source that provides normals sourced from the the normal map argument.
@param map a shader that outputs the normal map
@param ctm the current canvas' total matrix, used to rotate normals when necessary.
nullptr will be returned if 'map' is null
The normal map is currently assumed to be an 8888 image where the normal at a texel
is retrieved by:
N.x = R-127;
N.y = G-127;
N.z = B-127;
N.normalize();
The +Z axis is thus encoded in RGB as (127, 127, 255) while the -Z axis is
(127, 127, 0).
*/
static sk_sp<SkNormalSource> MakeFromNormalMap(sk_sp<SkShader> map, const SkMatrix& ctm);
/** Returns a normal source that provides straight-up normals only <0, 0, 1>.
*/
static sk_sp<SkNormalSource> MakeFlat();
static Type GetFlattenableType() { return kSkNormalSource_Type; }
Type getFlattenableType() const override { return GetFlattenableType(); }
static sk_sp<SkNormalSource> Deserialize(const void* data, size_t size,
const SkDeserialProcs* procs = nullptr) {
return sk_sp<SkNormalSource>(static_cast<SkNormalSource*>(
SkFlattenable::Deserialize(GetFlattenableType(), data, size, procs).release()));
}
static void RegisterFlattenables();
};
#endif

View File

@ -31,7 +31,6 @@
#include "include/effects/SkShaderMaskFilter.h"
#include "include/effects/SkTableColorFilter.h"
#include "src/core/SkColorFilter_Matrix.h"
#include "src/core/SkNormalSource.h"
#include "src/core/SkRecordedDrawable.h"
#include "src/effects/SkDashImpl.h"
#include "src/effects/SkEmbossMaskFilter.h"
@ -43,7 +42,6 @@
#include "src/shaders/SkComposeShader.h"
#include "src/shaders/SkEmptyShader.h"
#include "src/shaders/SkImageShader.h"
#include "src/shaders/SkLightingShader.h"
#include "src/shaders/SkLocalMatrixShader.h"
#include "src/shaders/SkPictureShader.h"
#include "src/shaders/SkShaderBase.h"
@ -70,7 +68,6 @@
SK_REGISTER_FLATTENABLE(SkLocalMatrixShader);
SK_REGISTER_FLATTENABLE(SkPictureShader);
SkGradientShader::RegisterFlattenables();
SkLightingShader::RegisterFlattenables();
SkPerlinNoiseShader::RegisterFlattenables();
SkShaderBase::RegisterFlattenables();
@ -106,7 +103,6 @@
// Misc.
SK_REGISTER_FLATTENABLE(SkLayerDrawLooper);
SK_REGISTER_FLATTENABLE(SkRecordedDrawable);
SkNormalSource::RegisterFlattenables();
}
/*

View File

@ -1,489 +0,0 @@
/*
* 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 "include/core/SkColor.h"
#include "include/core/SkPoint3.h"
#include "include/core/SkUnPreMultiply.h"
#include "src/core/SkArenaAlloc.h"
#include "src/core/SkBitmapProcState.h"
#include "src/core/SkMathPriv.h"
#include "src/core/SkNormalSource.h"
#include "src/core/SkReadBuffer.h"
#include "src/core/SkWriteBuffer.h"
#include "src/shaders/SkBitmapProcShader.h"
#include "src/shaders/SkEmptyShader.h"
#include "src/shaders/SkLightingShader.h"
#include "src/shaders/SkShaderBase.h"
////////////////////////////////////////////////////////////////////////////
/*
SkLightingShader TODOs:
support different light types
support multiple lights
fix non-opaque diffuse textures
To Test:
A8 diffuse textures
down & upsampled draws
*/
/** \class SkLightingShaderImpl
This subclass of shader applies lighting.
*/
class SkLightingShaderImpl : public SkShaderBase {
public:
/** Create a new lighting shader that uses the provided normal map and
lights to light the diffuse bitmap.
@param diffuseShader the shader that provides the diffuse colors
@param normalSource the source of normals for lighting computation
@param lights the lights applied to the geometry
*/
SkLightingShaderImpl(sk_sp<SkShader> diffuseShader,
sk_sp<SkNormalSource> normalSource,
sk_sp<SkLights> lights)
: fDiffuseShader(std::move(diffuseShader))
, fNormalSource(std::move(normalSource))
, fLights(std::move(lights)) {}
bool isOpaque() const override;
#if SK_SUPPORT_GPU
std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(const GrFPArgs&) const override;
#endif
class LightingShaderContext : public Context {
public:
// The context takes ownership of the context and provider. It will call their destructors
// and then indirectly free their memory by calling free() on heapAllocated
LightingShaderContext(const SkLightingShaderImpl&, const ContextRec&,
SkShaderBase::Context* diffuseContext, SkNormalSource::Provider*,
void* heapAllocated);
void shadeSpan(int x, int y, SkPMColor[], int count) override;
uint32_t getFlags() const override { return fFlags; }
private:
SkShaderBase::Context* fDiffuseContext;
SkNormalSource::Provider* fNormalProvider;
SkColor fPaintColor;
uint32_t fFlags;
typedef Context INHERITED;
};
protected:
void flatten(SkWriteBuffer&) const override;
#ifdef SK_ENABLE_LEGACY_SHADERCONTEXT
Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const override;
#endif
private:
SK_FLATTENABLE_HOOKS(SkLightingShaderImpl)
sk_sp<SkShader> fDiffuseShader;
sk_sp<SkNormalSource> fNormalSource;
sk_sp<SkLights> fLights;
friend class SkLightingShader;
typedef SkShaderBase INHERITED;
};
////////////////////////////////////////////////////////////////////////////
#if SK_SUPPORT_GPU
#include "src/gpu/GrCoordTransform.h"
#include "src/gpu/GrFragmentProcessor.h"
#include "src/gpu/SkGr.h"
#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
#include "src/gpu/glsl/GrGLSLProgramDataManager.h"
#include "src/gpu/glsl/GrGLSLUniformHandler.h"
// This FP expects a premul'd color input for its diffuse color. Premul'ing of the paint's color is
// handled by the asFragmentProcessor() factory, but shaders providing diffuse color must output it
// premul'd.
class LightingFP : public GrFragmentProcessor {
public:
static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> normalFP,
sk_sp<SkLights> lights) {
return std::unique_ptr<GrFragmentProcessor>(new LightingFP(std::move(normalFP),
std::move(lights)));
}
const char* name() const override { return "LightingFP"; }
std::unique_ptr<GrFragmentProcessor> clone() const override {
return std::unique_ptr<GrFragmentProcessor>(new LightingFP(*this));
}
const SkTArray<SkLights::Light>& directionalLights() const { return fDirectionalLights; }
const SkColor3f& ambientColor() const { return fAmbientColor; }
private:
class GLSLLightingFP : public GrGLSLFragmentProcessor {
public:
GLSLLightingFP() {
fAmbientColor.fX = 0.0f;
}
void emitCode(EmitArgs& args) override {
GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
const LightingFP& lightingFP = args.fFp.cast<LightingFP>();
const char *lightDirsUniName = nullptr;
const char *lightColorsUniName = nullptr;
if (lightingFP.fDirectionalLights.count() != 0) {
fLightDirsUni = uniformHandler->addUniformArray(
kFragment_GrShaderFlag,
kFloat3_GrSLType,
"LightDir",
lightingFP.fDirectionalLights.count(),
&lightDirsUniName);
fLightColorsUni = uniformHandler->addUniformArray(
kFragment_GrShaderFlag,
kFloat3_GrSLType,
"LightColor",
lightingFP.fDirectionalLights.count(),
&lightColorsUniName);
}
const char* ambientColorUniName = nullptr;
fAmbientColorUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kFloat3_GrSLType,
"AmbientColor", &ambientColorUniName);
fragBuilder->codeAppendf("half4 diffuseColor = %s;", args.fInputColor);
SkString dstNormalName = this->invokeChild(0, args);
fragBuilder->codeAppendf("float3 normal = %s.xyz;", dstNormalName.c_str());
fragBuilder->codeAppend( "half3 result = half3(0.0);");
// diffuse light
if (lightingFP.fDirectionalLights.count() != 0) {
fragBuilder->codeAppendf("for (int i = 0; i < %d; i++) {",
lightingFP.fDirectionalLights.count());
// TODO: modulate the contribution from each light based on the shadow map
fragBuilder->codeAppendf(" half NdotL = saturate(half(dot(normal, %s[i])));",
lightDirsUniName);
fragBuilder->codeAppendf(" result += half3(%s[i])*diffuseColor.rgb*NdotL;",
lightColorsUniName);
fragBuilder->codeAppend("}");
}
// ambient light
fragBuilder->codeAppendf("result += half3(%s) * diffuseColor.rgb;",
ambientColorUniName);
// Clamping to alpha (equivalent to an unpremul'd clamp to 1.0)
fragBuilder->codeAppendf("%s = half4(clamp(result.rgb, 0.0, diffuseColor.a), "
"diffuseColor.a);", args.fOutputColor);
}
static void GenKey(const GrProcessor& proc, const GrShaderCaps&, GrProcessorKeyBuilder* b) {
const LightingFP& lightingFP = proc.cast<LightingFP>();
b->add32(lightingFP.fDirectionalLights.count());
}
protected:
void onSetData(const GrGLSLProgramDataManager& pdman,
const GrFragmentProcessor& proc) override {
const LightingFP& lightingFP = proc.cast<LightingFP>();
const SkTArray<SkLights::Light>& directionalLights = lightingFP.directionalLights();
if (directionalLights != fDirectionalLights) {
SkTArray<SkColor3f> lightDirs(directionalLights.count());
SkTArray<SkVector3> lightColors(directionalLights.count());
for (const SkLights::Light& light : directionalLights) {
lightDirs.push_back(light.dir());
lightColors.push_back(light.color());
}
pdman.set3fv(fLightDirsUni, directionalLights.count(), &(lightDirs[0].fX));
pdman.set3fv(fLightColorsUni, directionalLights.count(), &(lightColors[0].fX));
fDirectionalLights = directionalLights;
}
const SkColor3f& ambientColor = lightingFP.ambientColor();
if (ambientColor != fAmbientColor) {
pdman.set3fv(fAmbientColorUni, 1, &ambientColor.fX);
fAmbientColor = ambientColor;
}
}
private:
SkTArray<SkLights::Light> fDirectionalLights;
GrGLSLProgramDataManager::UniformHandle fLightDirsUni;
GrGLSLProgramDataManager::UniformHandle fLightColorsUni;
SkColor3f fAmbientColor;
GrGLSLProgramDataManager::UniformHandle fAmbientColorUni;
};
void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
GLSLLightingFP::GenKey(*this, caps, b);
}
LightingFP(std::unique_ptr<GrFragmentProcessor> normalFP, sk_sp<SkLights> lights)
: INHERITED(kLightingFP_ClassID, kPreservesOpaqueInput_OptimizationFlag) {
// fuse all ambient lights into a single one
fAmbientColor = lights->ambientLightColor();
for (int i = 0; i < lights->numLights(); ++i) {
if (SkLights::Light::kDirectional_LightType == lights->light(i).type()) {
fDirectionalLights.push_back(lights->light(i));
// TODO get the handle to the shadow map if there is one
} else {
SkDEBUGFAIL("Unimplemented Light Type passed to LightingFP");
}
}
this->registerChildProcessor(std::move(normalFP));
}
LightingFP(const LightingFP& that)
: INHERITED(kLightingFP_ClassID, kPreservesOpaqueInput_OptimizationFlag)
, fDirectionalLights(that.fDirectionalLights)
, fAmbientColor(that.fAmbientColor) {
this->registerChildProcessor(that.childProcessor(0).clone());
}
GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { return new GLSLLightingFP; }
bool onIsEqual(const GrFragmentProcessor& proc) const override {
const LightingFP& lightingFP = proc.cast<LightingFP>();
return fDirectionalLights == lightingFP.fDirectionalLights &&
fAmbientColor == lightingFP.fAmbientColor;
}
SkTArray<SkLights::Light> fDirectionalLights;
SkColor3f fAmbientColor;
typedef GrFragmentProcessor INHERITED;
};
////////////////////////////////////////////////////////////////////////////
std::unique_ptr<GrFragmentProcessor> SkLightingShaderImpl::asFragmentProcessor(const GrFPArgs& args) const {
std::unique_ptr<GrFragmentProcessor> normalFP(fNormalSource->asFragmentProcessor(args));
if (!normalFP) {
return nullptr;
}
if (fDiffuseShader) {
std::unique_ptr<GrFragmentProcessor> fpPipeline[] = {
as_SB(fDiffuseShader)->asFragmentProcessor(args),
LightingFP::Make(std::move(normalFP), fLights)
};
if (!fpPipeline[0] || !fpPipeline[1]) {
return nullptr;
}
std::unique_ptr<GrFragmentProcessor> innerLightFP = GrFragmentProcessor::RunInSeries(fpPipeline, 2);
// FP is wrapped because paint's alpha needs to be applied to output
return GrFragmentProcessor::MulChildByInputAlpha(std::move(innerLightFP));
} else {
// FP is wrapped because paint comes in unpremul'd to fragment shader, but LightingFP
// expects premul'd color.
return GrFragmentProcessor::PremulInput(LightingFP::Make(std::move(normalFP), fLights));
}
}
#endif
////////////////////////////////////////////////////////////////////////////
bool SkLightingShaderImpl::isOpaque() const {
return (fDiffuseShader ? fDiffuseShader->isOpaque() : false);
}
SkLightingShaderImpl::LightingShaderContext::LightingShaderContext(
const SkLightingShaderImpl& shader, const ContextRec& rec,
SkShaderBase::Context* diffuseContext, SkNormalSource::Provider* normalProvider,
void* heapAllocated)
: INHERITED(shader, rec)
, fDiffuseContext(diffuseContext)
, fNormalProvider(normalProvider) {
bool isOpaque = shader.isOpaque();
// update fFlags
uint32_t flags = 0;
if (isOpaque && (255 == this->getPaintAlpha())) {
flags |= kOpaqueAlpha_Flag;
}
fPaintColor = rec.fPaint->getColor();
fFlags = flags;
}
static inline SkPMColor convert(SkColor3f color, U8CPU a) {
if (color.fX <= 0.0f) {
color.fX = 0.0f;
} else if (color.fX >= 255.0f) {
color.fX = 255.0f;
}
if (color.fY <= 0.0f) {
color.fY = 0.0f;
} else if (color.fY >= 255.0f) {
color.fY = 255.0f;
}
if (color.fZ <= 0.0f) {
color.fZ = 0.0f;
} else if (color.fZ >= 255.0f) {
color.fZ = 255.0f;
}
return SkPreMultiplyARGB(a, (int) color.fX, (int) color.fY, (int) color.fZ);
}
// larger is better (fewer times we have to loop), but we shouldn't
// take up too much stack-space (each one here costs 16 bytes)
#define BUFFER_MAX 16
void SkLightingShaderImpl::LightingShaderContext::shadeSpan(int x, int y,
SkPMColor result[], int count) {
const SkLightingShaderImpl& lightShader = static_cast<const SkLightingShaderImpl&>(fShader);
SkPMColor diffuse[BUFFER_MAX];
SkPoint3 normals[BUFFER_MAX];
SkColor diffColor = fPaintColor;
do {
int n = std::min(count, BUFFER_MAX);
fNormalProvider->fillScanLine(x, y, normals, n);
if (fDiffuseContext) {
fDiffuseContext->shadeSpan(x, y, diffuse, n);
}
for (int i = 0; i < n; ++i) {
if (fDiffuseContext) {
diffColor = SkUnPreMultiply::PMColorToColor(diffuse[i]);
}
SkColor3f accum = SkColor3f::Make(0.0f, 0.0f, 0.0f);
// Adding ambient light
accum.fX += lightShader.fLights->ambientLightColor().fX * SkColorGetR(diffColor);
accum.fY += lightShader.fLights->ambientLightColor().fY * SkColorGetG(diffColor);
accum.fZ += lightShader.fLights->ambientLightColor().fZ * SkColorGetB(diffColor);
// This is all done in linear unpremul color space (each component 0..255.0f though)
for (int l = 0; l < lightShader.fLights->numLights(); ++l) {
const SkLights::Light& light = lightShader.fLights->light(l);
SkScalar illuminanceScalingFactor = 1.0f;
if (SkLights::Light::kDirectional_LightType == light.type()) {
illuminanceScalingFactor = normals[i].dot(light.dir());
if (illuminanceScalingFactor < 0.0f) {
illuminanceScalingFactor = 0.0f;
}
}
accum.fX += light.color().fX * SkColorGetR(diffColor) * illuminanceScalingFactor;
accum.fY += light.color().fY * SkColorGetG(diffColor) * illuminanceScalingFactor;
accum.fZ += light.color().fZ * SkColorGetB(diffColor) * illuminanceScalingFactor;
}
// convert() premultiplies the accumulate color with alpha
result[i] = convert(accum, SkColorGetA(diffColor));
}
result += n;
x += n;
count -= n;
} while (count > 0);
}
////////////////////////////////////////////////////////////////////////////
sk_sp<SkFlattenable> SkLightingShaderImpl::CreateProc(SkReadBuffer& buf) {
// Discarding SkShader flattenable params
bool hasLocalMatrix = buf.readBool();
if (hasLocalMatrix) {
return nullptr;
}
sk_sp<SkLights> lights = SkLights::MakeFromBuffer(buf);
sk_sp<SkNormalSource> normalSource(buf.readFlattenable<SkNormalSource>());
bool hasDiffuse = buf.readBool();
sk_sp<SkShader> diffuseShader = nullptr;
if (hasDiffuse) {
diffuseShader = buf.readFlattenable<SkShaderBase>();
}
return sk_make_sp<SkLightingShaderImpl>(std::move(diffuseShader), std::move(normalSource),
std::move(lights));
}
void SkLightingShaderImpl::flatten(SkWriteBuffer& buf) const {
this->INHERITED::flatten(buf);
fLights->flatten(buf);
buf.writeFlattenable(fNormalSource.get());
buf.writeBool(static_cast<bool>(fDiffuseShader));
if (fDiffuseShader) {
buf.writeFlattenable(fDiffuseShader.get());
}
}
#ifdef SK_ENABLE_LEGACY_SHADERCONTEXT
SkShaderBase::Context* SkLightingShaderImpl::onMakeContext(
const ContextRec& rec, SkArenaAlloc* alloc) const
{
SkShaderBase::Context *diffuseContext = nullptr;
if (fDiffuseShader) {
diffuseContext = as_SB(fDiffuseShader)->makeContext(rec, alloc);
if (!diffuseContext) {
return nullptr;
}
}
SkNormalSource::Provider* normalProvider = fNormalSource->asProvider(rec, alloc);
if (!normalProvider) {
return nullptr;
}
// The diffuse shader can inspect the rec and make its decision about rec's colorspace.
// What about the lighting shader? Is lighting sensitive to the rec's (device) colorspace?
return alloc->make<LightingShaderContext>(*this, rec, diffuseContext, normalProvider, nullptr);
}
#endif
///////////////////////////////////////////////////////////////////////////////
sk_sp<SkShader> SkLightingShader::Make(sk_sp<SkShader> diffuseShader,
sk_sp<SkNormalSource> normalSource,
sk_sp<SkLights> lights) {
SkASSERT(lights);
if (!normalSource) {
normalSource = SkNormalSource::MakeFlat();
}
return sk_make_sp<SkLightingShaderImpl>(std::move(diffuseShader), std::move(normalSource),
std::move(lights));
}
///////////////////////////////////////////////////////////////////////////////
void SkLightingShader::RegisterFlattenables() { SK_REGISTER_FLATTENABLE(SkLightingShaderImpl); }

View File

@ -1,39 +0,0 @@
/*
* Copyright 2015 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkLightingShader_DEFINED
#define SkLightingShader_DEFINED
#include "include/core/SkShader.h"
#include "src/shaders/SkLights.h"
class SkBitmap;
class SkMatrix;
class SkNormalSource;
class SkLightingShader {
public:
/** Returns a shader that lights the shape, colored by the diffuseShader, using the
normals from normalSource, with the set of lights provided.
@param diffuseShader the shader that provides the colors. If nullptr, uses the paint's
color.
@param normalSource the source for the shape's normals. If nullptr, assumes straight
up normals (<0,0,1>).
@param lights the lights applied to the normals
The lighting equation is currently:
result = (LightColor * dot(Normal, LightDir) + AmbientColor) * DiffuseColor
*/
static sk_sp<SkShader> Make(sk_sp<SkShader> diffuseShader, sk_sp<SkNormalSource> normalSource,
sk_sp<SkLights> lights);
static void RegisterFlattenables();
};
#endif

View File

@ -1,68 +0,0 @@
/*
* 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 "src/core/SkReadBuffer.h"
#include "src/shaders/SkLights.h"
sk_sp<SkLights> SkLights::MakeFromBuffer(SkReadBuffer& buf) {
Builder builder;
SkColor3f ambColor;
if (!buf.readScalarArray(&ambColor.fX, 3)) {
return nullptr;
}
builder.setAmbientLightColor(ambColor);
int numLights = buf.readInt();
for (int l = 0; l < numLights; ++l) {
bool isPoint = buf.readBool();
SkColor3f color;
if (!buf.readScalarArray(&color.fX, 3)) {
return nullptr;
}
SkVector3 dirOrPos;
if (!buf.readScalarArray(&dirOrPos.fX, 3)) {
return nullptr;
}
if (isPoint) {
SkScalar intensity;
intensity = buf.readScalar();
Light light = Light::MakePoint(color, dirOrPos, intensity);
builder.add(light);
} else {
Light light = Light::MakeDirectional(color, dirOrPos);
builder.add(light);
}
}
return builder.finish();
}
void SkLights::flatten(SkWriteBuffer& buf) const {
buf.writeScalarArray(&this->ambientLightColor().fX, 3);
buf.writeInt(this->numLights());
for (int l = 0; l < this->numLights(); ++l) {
const Light& light = this->light(l);
bool isPoint = Light::kPoint_LightType == light.type();
buf.writeBool(isPoint);
buf.writeScalarArray(&light.color().fX, 3);
buf.writeScalarArray(&light.dir().fX, 3);
if (isPoint) {
buf.writeScalar(light.intensity());
}
}
}

View File

@ -1,192 +0,0 @@
/*
* Copyright 2015 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkLights_DEFINED
#define SkLights_DEFINED
#include "include/core/SkPoint3.h"
#include "include/core/SkRefCnt.h"
#include "include/private/SkTArray.h"
class SkReadBuffer;
class SkWriteBuffer;
/** \class SkLights
SkLights encapsulates a set of directional, point and ambient lights for use with the
SkLightingShader.
*/
class SkLights : public SkRefCnt {
public:
class Light {
public:
enum LightType {
kDirectional_LightType,
kPoint_LightType
};
Light(const Light& other)
: fType(other.fType)
, fColor(other.fColor)
, fDirOrPos(other.fDirOrPos)
, fIntensity(other.fIntensity) {}
Light(Light&& other)
: fType(other.fType)
, fColor(other.fColor)
, fDirOrPos(other.fDirOrPos)
, fIntensity(other.fIntensity) {}
static Light MakeDirectional(const SkColor3f& color, const SkVector3& dir) {
Light light(kDirectional_LightType, color, dir, 0.0f);
if (!light.fDirOrPos.normalize()) {
light.fDirOrPos.set(0.0f, 0.0f, 1.0f);
}
return light;
}
static Light MakePoint(const SkColor3f& color, const SkPoint3& pos, SkScalar intensity) {
return Light(kPoint_LightType, color, pos, intensity);
}
LightType type() const { return fType; }
const SkColor3f& color() const { return fColor; }
const SkVector3& dir() const {
SkASSERT(kDirectional_LightType == fType);
return fDirOrPos;
}
const SkPoint3& pos() const {
SkASSERT(kPoint_LightType == fType);
return fDirOrPos;
}
SkScalar intensity() const {
SkASSERT(kPoint_LightType == fType);
return fIntensity;
}
Light& operator=(const Light& other) {
if (this == &other) {
return *this;
}
fType = other.fType;
fColor = other.fColor;
fDirOrPos = other.fDirOrPos;
fIntensity = other.fIntensity;
return *this;
}
bool operator==(const Light& other) {
return (fType == other.fType) &&
(fColor == other.fColor) &&
(fDirOrPos == other.fDirOrPos) &&
(fIntensity == other.fIntensity);
}
bool operator!=(const Light& other) { return !(this->operator==(other)); }
private:
friend class SkLights;
Light(LightType type, const SkColor3f& color, const SkVector3& dirOrPos,
SkScalar intensity)
: fType(type)
, fColor(color)
, fDirOrPos(dirOrPos)
, fIntensity(intensity) {}
LightType fType;
SkColor3f fColor; // linear (unpremul) color. Range is 0..1 in each channel.
SkVector3 fDirOrPos; // For directional lights, holds the direction towards the
// light (+Z is out of the screen).
// If degenerate, it will be replaced with (0, 0, 1).
// For point lights, holds location of point light
SkScalar fIntensity; // For point lights, dictates the light intensity.
// Simply a multiplier to the final light output value.
};
class Builder {
public:
Builder() : fLights(new SkLights) {}
void add(const Light& light) {
if (fLights) {
fLights->fLights.push_back(light);
}
}
void add(Light&& light) {
if (fLights) {
fLights->fLights.push_back(std::move(light));
}
}
void setAmbientLightColor(const SkColor3f& color) {
if (fLights) {
fLights->fAmbientLightColor = color;
}
}
sk_sp<SkLights> finish() {
return std::move(fLights);
}
private:
sk_sp<SkLights> fLights;
};
/** Returns number of lights not including the ambient light.
@return number of lights not including the ambient light
*/
int numLights() const { return fLights.count(); }
/** Returns the index-th light.
@param index the index of the desired light
@return the index-th light
*/
const Light& light(int index) const { return fLights[index]; }
/** Returns the ambient light.
@return the ambient light
*/
const SkColor3f& ambientLightColor() const {
return fAmbientLightColor;
}
/**
* Recreate an SkLights object that was serialized into a buffer.
*
* @param SkReadBuffer Serialized blob data.
* @return A new SkLights representing the serialized data, or NULL if the buffer is
* invalid.
*/
static sk_sp<SkLights> MakeFromBuffer(SkReadBuffer& buf);
/**
* Serialize to a buffer.
*
* @param buffer the write buffer to write out to
*/
void flatten(SkWriteBuffer& buf) const;
private:
friend class SkLightingShaderImpl;
SkLights() : fAmbientLightColor(SkColor3f::Make(0.0f, 0.0f, 0.0f)) {}
SkTArray<Light> fLights;
SkColor3f fAmbientLightColor;
typedef SkRefCnt INHERITED;
};
#endif

View File

@ -19,12 +19,10 @@
#include "src/core/SkAnnotationKeys.h"
#include "src/core/SkFontDescriptor.h"
#include "src/core/SkMatrixPriv.h"
#include "src/core/SkNormalSource.h"
#include "src/core/SkOSFile.h"
#include "src/core/SkPicturePriv.h"
#include "src/core/SkReadBuffer.h"
#include "src/core/SkWriteBuffer.h"
#include "src/shaders/SkLightingShader.h"
#include "src/shaders/SkShaderBase.h"
#include "tests/Test.h"
#include "tools/Resources.h"
@ -589,59 +587,6 @@ DEF_TEST(Serialization, reporter) {
}
TestPictureTypefaceSerialization(reporter);
// Test SkLightingShader/NormalMapSource serialization
{
const int kTexSize = 2;
SkLights::Builder builder;
builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 1.0f, 1.0f),
SkVector3::Make(1.0f, 0.0f, 0.0f)));
builder.setAmbientLightColor(SkColor3f::Make(0.2f, 0.2f, 0.2f));
sk_sp<SkLights> fLights = builder.finish();
SkBitmap diffuse = ToolUtils::create_checkerboard_bitmap(
kTexSize, kTexSize, 0x00000000, ToolUtils::color_to_565(0xFF804020), 8);
SkRect bitmapBounds = SkRect::MakeIWH(diffuse.width(), diffuse.height());
SkMatrix matrix;
SkRect r = SkRect::MakeWH(SkIntToScalar(kTexSize), SkIntToScalar(kTexSize));
matrix.setRectToRect(bitmapBounds, r, SkMatrix::kFill_ScaleToFit);
SkMatrix ctm;
ctm.setRotate(45);
SkBitmap normals;
normals.allocN32Pixels(kTexSize, kTexSize);
ToolUtils::create_frustum_normal_map(&normals, SkIRect::MakeWH(kTexSize, kTexSize));
sk_sp<SkShader> normalMap = normals.makeShader(&matrix);
sk_sp<SkNormalSource> normalSource = SkNormalSource::MakeFromNormalMap(std::move(normalMap),
ctm);
sk_sp<SkShader> diffuseShader = diffuse.makeShader(&matrix);
sk_sp<SkShader> lightingShader = SkLightingShader::Make(diffuseShader,
normalSource,
fLights);
sk_sp<SkShader>(TestFlattenableSerialization(as_SB(lightingShader.get()), true, reporter));
lightingShader = SkLightingShader::Make(std::move(diffuseShader),
nullptr,
fLights);
sk_sp<SkShader>(TestFlattenableSerialization(as_SB(lightingShader.get()), true, reporter));
lightingShader = SkLightingShader::Make(nullptr,
std::move(normalSource),
fLights);
sk_sp<SkShader>(TestFlattenableSerialization(as_SB(lightingShader.get()), true, reporter));
lightingShader = SkLightingShader::Make(nullptr,
nullptr,
fLights);
sk_sp<SkShader>(TestFlattenableSerialization(as_SB(lightingShader.get()), true, reporter));
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////