diff options
author | Robert Phillips <robertphillips@google.com> | 2018-07-17 12:30:40 -0400 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2018-07-17 17:24:50 +0000 |
commit | a8cdbd7431b6a27d28db1bc80d7557cedf7e66d0 (patch) | |
tree | 3d866605d2236b31da70535f2a4263c55b01acae /gm | |
parent | 9e0d7e4072e43495a3907bb2bac7824e8e60c368 (diff) |
Restore SkLightingShader and associated classes
This reverts https://skia-review.googlesource.com/c/skia/+/31140 (Remove SkLightingShader and associated classes) and updates the classes to ToT
Change-Id: I3b1df1704cca8907aa00f081a7e93339b65ad4fa
Reviewed-on: https://skia-review.googlesource.com/141545
Reviewed-by: Mike Reed <reed@google.com>
Commit-Queue: Robert Phillips <robertphillips@google.com>
Diffstat (limited to 'gm')
-rw-r--r-- | gm/lightingshader.cpp | 160 | ||||
-rw-r--r-- | gm/lightingshader2.cpp | 278 |
2 files changed, 438 insertions, 0 deletions
diff --git a/gm/lightingshader.cpp b/gm/lightingshader.cpp new file mode 100644 index 0000000000..303a4e233a --- /dev/null +++ b/gm/lightingshader.cpp @@ -0,0 +1,160 @@ +/* + * 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 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(sk_tool_utils::color_to_565(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 = 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); + } + + // 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;) +} diff --git a/gm/lightingshader2.cpp b/gm/lightingshader2.cpp new file mode 100644 index 0000000000..a3454deb4b --- /dev/null +++ b/gm/lightingshader2.cpp @@ -0,0 +1,278 @@ +/* + * 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.h" +#include "sk_tool_utils.h" +#include "SkLightingShader.h" +#include "SkNormalSource.h" +#include "SkPoint3.h" +#include "SkShader.h" +#include "SkTypeface.h" + +// 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; +} + +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(sk_tool_utils::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 = sk_tool_utils::create_checkerboard_bitmap( + kTexSize, kTexSize, SK_ColorBLACK, + sk_tool_utils::color_to_565(0xFF808080), + 8); + fOpaqueDiffuse = SkShader::MakeBitmapShader(opaqueDiffuseMap, SkShader::kClamp_TileMode, + SkShader::kClamp_TileMode, &matrix); + + SkBitmap translucentDiffuseMap = sk_tool_utils::create_checkerboard_bitmap( + kTexSize, kTexSize, + SkColorSetARGB(0x55, 0x00, 0x00, 0x00), + SkColorSetARGB(0x55, 0x80, 0x80, 0x80), + 8); + fTranslucentDiffuse = SkShader::MakeBitmapShader(translucentDiffuseMap, + SkShader::kClamp_TileMode, + SkShader::kClamp_TileMode, &matrix); + + SkBitmap normalMap = make_frustum_normalmap(kTexSize); + fNormalMapShader = SkShader::MakeBitmapShader(normalMap, SkShader::kClamp_TileMode, + SkShader::kClamp_TileMode, &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; + labelPaint.setTypeface(sk_tool_utils::create_portable_typeface("sans-serif",SkFontStyle())); + labelPaint.setAntiAlias(true); + labelPaint.setTextSize(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, labelPaint); + } + { + canvas->translate(0.0f, kLabelSize); + SkString label; + label.appendf("useDiffuseShader: %d", useDiffuseShader); + canvas->drawString(label, 0.0f, 0.0f, labelPaint); + } + { + canvas->translate(0.0f, kLabelSize); + SkString label; + label.appendf("useTranslucentPaint: %d", useTranslucentPaint); + canvas->drawString(label, 0.0f, 0.0f, labelPaint); + } + { + canvas->translate(0.0f, kLabelSize); + SkString label; + label.appendf("useTranslucentShader: %d", useTranslucentShader); + canvas->drawString(label, 0.0f, 0.0f, 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;) +} |