diff --git a/gm/shadowutils.cpp b/gm/shadowutils.cpp index 5cbed5c81f..d9cdfd5768 100644 --- a/gm/shadowutils.cpp +++ b/gm/shadowutils.cpp @@ -15,7 +15,6 @@ void draw_shadow(SkCanvas* canvas, const SkPath& path, int height, SkColor color SkScalar lightR, bool isAmbient, uint32_t flags) { SkScalar ambientAlpha = isAmbient ? .5f : 0.f; SkScalar spotAlpha = isAmbient ? 0.f : .5f; - flags |= SkShadowFlags::kDisableTonalColor_ShadowFlag; SkShadowUtils::DrawShadow(canvas, path, height, lightPos, lightR, ambientAlpha, spotAlpha, color, flags); } @@ -23,7 +22,13 @@ void draw_shadow(SkCanvas* canvas, const SkPath& path, int height, SkColor color static constexpr int kW = 800; static constexpr int kH = 800; -void draw_paths(SkCanvas* canvas, bool hideOccluders) { +enum ShadowMode { + kDebugColorNoOccluders, + kDebugColorOccluders, + kGrayscale +}; + +void draw_paths(SkCanvas* canvas, ShadowMode mode) { SkTArray paths; paths.push_back().addRoundRect(SkRect::MakeWH(50, 50), 10, 10); SkRRect oddRRect; @@ -52,7 +57,7 @@ void draw_paths(SkCanvas* canvas, bool hideOccluders) { m->setRotate(33.f, 25.f, 25.f); m->postScale(1.2f, 0.8f, 25.f, 25.f); for (auto& m : matrices) { - for (auto flags : { kNone_ShadowFlag, kTransparentOccluder_ShadowFlag }) { + for (int flags : { kNone_ShadowFlag, kTransparentOccluder_ShadowFlag }) { for (const auto& path : paths) { SkRect postMBounds = path.getBounds(); m.mapRect(&postMBounds); @@ -68,13 +73,22 @@ void draw_paths(SkCanvas* canvas, bool hideOccluders) { canvas->save(); canvas->concat(m); - draw_shadow(canvas, path, kHeight, SK_ColorRED, lightPos, kLightR, true, flags); - draw_shadow(canvas, path, kHeight, SK_ColorBLUE, lightPos, kLightR, false, flags); - // Draw the path outline in green on top of the ambient and spot shadows. + if (kDebugColorNoOccluders == mode || kDebugColorOccluders == mode) { + flags |= SkShadowFlags::kDisableTonalColor_ShadowFlag; + draw_shadow(canvas, path, kHeight, SK_ColorRED, lightPos, kLightR, + true, flags); + draw_shadow(canvas, path, kHeight, SK_ColorBLUE, lightPos, kLightR, + false, flags); + } else if (kGrayscale == mode) { + SkShadowUtils::DrawShadow(canvas, path, kHeight, lightPos, kLightR, + 0.1f, 0.25f, SK_ColorBLACK, flags); + } + SkPaint paint; paint.setAntiAlias(true); - if (hideOccluders) { + if (kDebugColorNoOccluders == mode) { + // Draw the path outline in green on top of the ambient and spot shadows. if (SkToBool(flags & kTransparentOccluder_ShadowFlag)) { paint.setColor(SK_ColorCYAN); } else { @@ -83,7 +97,7 @@ void draw_paths(SkCanvas* canvas, bool hideOccluders) { paint.setStyle(SkPaint::kStroke_Style); paint.setStrokeWidth(0); } else { - paint.setColor(SK_ColorLTGRAY); + paint.setColor(kDebugColorOccluders == mode ? SK_ColorLTGRAY : SK_ColorWHITE); if (SkToBool(flags & kTransparentOccluder_ShadowFlag)) { paint.setAlpha(128); } @@ -112,9 +126,13 @@ void draw_paths(SkCanvas* canvas, bool hideOccluders) { } DEF_SIMPLE_GM(shadow_utils, canvas, kW, kH) { - draw_paths(canvas, true); + draw_paths(canvas, kDebugColorNoOccluders); } DEF_SIMPLE_GM(shadow_utils_occl, canvas, kW, kH) { - draw_paths(canvas, false); + draw_paths(canvas, kDebugColorOccluders); +} + +DEF_SIMPLE_GM(shadow_utils_gray, canvas, kW, kH) { + draw_paths(canvas, kGrayscale); } diff --git a/gm/tonalshadows.cpp b/gm/tonalshadows.cpp new file mode 100644 index 0000000000..83c1b748e4 --- /dev/null +++ b/gm/tonalshadows.cpp @@ -0,0 +1,85 @@ +/* +* Copyright 2017 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 "SkCanvas.h" +#include "SkPath.h" +#include "SkShadowUtils.h" + +enum BackgroundMode { + kLightBackground, + kDarkBackground +}; + +static constexpr int kW = 1225; +static constexpr int kH = 550; + +void draw_content(SkCanvas* canvas, BackgroundMode mode) { + const SkScalar kLightWidth = 600; + const SkScalar kAmbientAlpha = 0.03f; + const SkScalar kSpotAlpha = 0.25f; + + const SkColor kColors[30] = { + // purples + 0xFF3A0072, 0xFF5D0099, 0xFF7F12B2, 0xFFA02AD1, 0xFFC245E5, + 0xFFE95AF9, 0xFFFC79F0, 0xFFFDA6F0, 0xFFFFCCF8, 0xFFFFE1F9, + // oranges + 0xFFEA3200, 0xFFFF4E00, 0xFFFF7300, 0xFFFF9100, 0xFFFFB000, + 0xFFFFCE00, 0xFFFFE000, 0xFFFFF64D, 0xFFFFF98F, 0xFFFFFBCC, + // teals + 0xFF004D51, 0xFF066266, 0xFF057F7F, 0xFF009999, 0xFF00B2B2, + 0xFF15CCBE, 0xFF25E5CE, 0xFF2CFFE0, 0xFF80FFEA, 0xFFB3FFF0 + }; + + SkPaint paint; + paint.setAntiAlias(true); + if (mode == kDarkBackground) { + canvas->drawColor(0xFF111111); + } else { + canvas->drawColor(0xFFEAEAEA); + } + + SkPath path; + path.addRect(SkRect::MakeXYWH(-50, -50, 100, 100)); + + SkPoint3 lightPos = { 75, -400, 600 }; + SkPoint3 zPlaneParams = SkPoint3::Make(0, 0, 16); + SkScalar yPos = 75; + + for (int row = 0; row < 3; ++row) { + lightPos.fX = 75; + SkScalar xPos = 75; + for (int col = 0; col < 10; ++col) { + paint.setColor(kColors[10 * row + col]); + + canvas->save(); + canvas->translate(xPos, yPos); + SkShadowUtils::DrawShadow(canvas, path, zPlaneParams, + lightPos, kLightWidth, + kAmbientAlpha, kSpotAlpha, paint.getColor(), 0); + canvas->drawPath(path, paint); + canvas->restore(); + + lightPos.fX += 120; + xPos += 120; + } + + lightPos.fY += 200; + yPos += 200; + } +} + +DEF_SIMPLE_GM(tonalshadows_light, canvas, kW, kH) { + draw_content(canvas, kLightBackground); +} + +DEF_SIMPLE_GM(tonalshadows_dark, canvas, kW, kH) { + draw_content(canvas, kDarkBackground); +} + + + diff --git a/gn/gm.gni b/gn/gm.gni index d24b8bbb27..85fc6e13a3 100644 --- a/gn/gm.gni +++ b/gn/gm.gni @@ -317,6 +317,7 @@ gm_sources = [ "$_gm/tilemodes.cpp", "$_gm/tilemodes_scaled.cpp", "$_gm/tinybitmap.cpp", + "$_gm/tonalshadows.cpp", "$_gm/transparency.cpp", "$_gm/typeface.cpp", "$_gm/variedtext.cpp", diff --git a/include/utils/SkShadowUtils.h b/include/utils/SkShadowUtils.h index c362488f15..9550a925b9 100644 --- a/include/utils/SkShadowUtils.h +++ b/include/utils/SkShadowUtils.h @@ -84,9 +84,9 @@ public: * set the alpha to (S_a + C_a - S_a*C_a). * * @param r Red value of color - * @param g Red value of color - * @param b Red value of color - * @param a Red value of color + * @param g Green value of color + * @param b Blue value of color + * @param a Alpha value of color * @param colorScale Factor to scale color values by * @param tonalAlpha Value to set alpha to */ @@ -96,14 +96,28 @@ public: SkScalar min = SkTMin(SkTMin(r, g), b); SkScalar luminance = 0.5f*(max + min); - // We get best results with a luminance between 0.3 and 0.5, with smoothstep applied - SkScalar adjustedLuminance = (0.6f - 0.4f*luminance)*luminance*luminance + 0.3f; - // Similarly, we need to tone down the given greyscale alpha depending on how - // much color we're applying. - a -= (0.5f*adjustedLuminance - 0.15f); + // We compute a color alpha value based on the luminance of the color, scaled by an + // adjusted alpha value. We want the following properties to match the UX examples + // (assuming a = 0.25) and to ensure that we have reasonable results when the color + // is black and/or the alpha is 0: + // f(0, a) = 0 + // f(luminance, 0) = 0 + // f(1, 0.25) = .5 + // f(0.5, 0.25) = .4 + // f(1, 1) = 1 + // The following functions match this as closely as possible. + SkScalar alphaAdjust = (2.6f + (-2.66667f + 1.06667f*a)*a)*a; + SkScalar colorAlpha = (3.544762f + (-4.891428f + 2.3466f*luminance)*luminance)*luminance; + colorAlpha = SkTPin(alphaAdjust*colorAlpha, 0.0f, 1.0f); - *colorScale = adjustedLuminance*(SK_Scalar1 - a); - *tonalAlpha = *colorScale + a; + // Similarly, we set the greyscale alpha based on luminance and alpha so that + // f(0, a) = a + // f(luminance, 0) = 0 + // f(1, 0.25) = 0.15 + SkScalar greyscaleAlpha = SkTPin(a*(1 - 0.4f*luminance), 0.0f, 1.0f); + + *colorScale = colorAlpha*(SK_Scalar1 - greyscaleAlpha); + *tonalAlpha = *colorScale + greyscaleAlpha; } }; diff --git a/samplecode/SampleAndroidShadows.cpp b/samplecode/SampleAndroidShadows.cpp index 3db994adda..2621cec073 100644 --- a/samplecode/SampleAndroidShadows.cpp +++ b/samplecode/SampleAndroidShadows.cpp @@ -35,23 +35,27 @@ class ShadowsView : public SampleView { SkScalar fZDelta; SkScalar fAnimTranslate; SkScalar fAnimAngle; + SkScalar fAnimAlpha; bool fShowAmbient; bool fShowSpot; bool fUseAlt; bool fShowObject; bool fIgnoreShadowAlpha; + bool fDoAlphaAnimation; public: ShadowsView() : fZDelta(0) , fAnimTranslate(0) , fAnimAngle(0) + , fAnimAlpha(1) , fShowAmbient(true) , fShowSpot(true) , fUseAlt(false) , fShowObject(true) - , fIgnoreShadowAlpha(false) {} + , fIgnoreShadowAlpha(false) + , fDoAlphaAnimation(false) {} protected: void onOnceBeforeDraw() override { @@ -99,6 +103,13 @@ protected: fShowObject = !fShowObject; handled = true; break; + case 'N': + fDoAlphaAnimation = !fDoAlphaAnimation; + if (!fDoAlphaAnimation) { + fAnimAlpha = 1; + } + handled = true; + break; case '>': fZDelta += 0.5f; handled = true; @@ -175,38 +186,38 @@ protected: paint.setColor(SK_ColorWHITE); canvas->translate(200, 90); zPlaneParams.fZ = SkTMax(1.0f, 2 + fZDelta); - this->drawShadowedPath(canvas, fRRPath, zPlaneParams, paint, kAmbientAlpha, - lightPos, kLightWidth, kSpotAlpha); + this->drawShadowedPath(canvas, fRRPath, zPlaneParams, paint, fAnimAlpha*kAmbientAlpha, + lightPos, kLightWidth, fAnimAlpha*kSpotAlpha); paint.setColor(SK_ColorRED); canvas->translate(250, 0); zPlaneParams.fZ = SkTMax(1.0f, 8 + fZDelta); - this->drawShadowedPath(canvas, fRectPath, zPlaneParams, paint, kAmbientAlpha, - lightPos, kLightWidth, kSpotAlpha); + this->drawShadowedPath(canvas, fRectPath, zPlaneParams, paint, fAnimAlpha*kAmbientAlpha, + lightPos, kLightWidth, fAnimAlpha*kSpotAlpha); paint.setColor(SK_ColorBLUE); canvas->translate(-250, 110); zPlaneParams.fZ = SkTMax(1.0f, 12 + fZDelta); - this->drawShadowedPath(canvas, fCirclePath, zPlaneParams, paint, kAmbientAlpha, - lightPos, kLightWidth, 0.5f); + this->drawShadowedPath(canvas, fCirclePath, zPlaneParams, paint, fAnimAlpha*kAmbientAlpha, + lightPos, kLightWidth, fAnimAlpha*0.5f); paint.setColor(SK_ColorGREEN); canvas->translate(250, 0); zPlaneParams.fZ = SkTMax(1.0f, 64 + fZDelta); - this->drawShadowedPath(canvas, fRRPath, zPlaneParams, paint, kAmbientAlpha, - lightPos, kLightWidth, kSpotAlpha); + this->drawShadowedPath(canvas, fRRPath, zPlaneParams, paint, fAnimAlpha*kAmbientAlpha, + lightPos, kLightWidth, fAnimAlpha*kSpotAlpha); paint.setColor(SK_ColorYELLOW); canvas->translate(-250, 110); zPlaneParams.fZ = SkTMax(1.0f, 8 + fZDelta); - this->drawShadowedPath(canvas, fFunkyRRPath, zPlaneParams, paint, kAmbientAlpha, - lightPos, kLightWidth, kSpotAlpha); + this->drawShadowedPath(canvas, fFunkyRRPath, zPlaneParams, paint, fAnimAlpha*kAmbientAlpha, + lightPos, kLightWidth, fAnimAlpha*kSpotAlpha); paint.setColor(SK_ColorCYAN); canvas->translate(250, 0); zPlaneParams.fZ = SkTMax(1.0f, 16 + fZDelta); - this->drawShadowedPath(canvas, fCubicPath, zPlaneParams, paint, - kAmbientAlpha, lightPos, kLightWidth, kSpotAlpha); + this->drawShadowedPath(canvas, fCubicPath, zPlaneParams, paint, fAnimAlpha*kAmbientAlpha, + lightPos, kLightWidth, fAnimAlpha*kSpotAlpha); // circular reveal SkPath tmpPath; @@ -259,7 +270,9 @@ protected: bool onAnimate(const SkAnimTimer& timer) override { fAnimTranslate = timer.pingPong(30, 0, 200, -200); fAnimAngle = timer.pingPong(15, 0, 0, 20); - + if (fDoAlphaAnimation) { + fAnimAlpha = timer.pingPong(5, 0, 1, 0); + } return true; } diff --git a/samplecode/SampleShadowUtils.cpp b/samplecode/SampleShadowUtils.cpp index 7e6079156d..7d30a10d0b 100755 --- a/samplecode/SampleShadowUtils.cpp +++ b/samplecode/SampleShadowUtils.cpp @@ -121,6 +121,7 @@ protected: if (!fShowSpot) { spotAlpha = 0; } + flags |= SkShadowFlags::kDisableTonalColor_ShadowFlag; if (fUseAlt) { flags |= SkShadowFlags::kGeometricOnly_ShadowFlag; } diff --git a/src/gpu/GrRenderTargetContext.cpp b/src/gpu/GrRenderTargetContext.cpp index 6f93a1c190..1c617c9410 100644 --- a/src/gpu/GrRenderTargetContext.cpp +++ b/src/gpu/GrRenderTargetContext.cpp @@ -1141,7 +1141,7 @@ bool GrRenderTargetContext::drawFastShadow(const GrClip& clip, SkScalar colorScale; SkScalar tonalAlpha; SkShadowUtils::ComputeTonalColorParams(color.fRGBA[0], color.fRGBA[1], - color.fRGBA[2], rec.fSpotAlpha, + color.fRGBA[2], color.fRGBA[3]*rec.fSpotAlpha, &colorScale, &tonalAlpha); color.fRGBA[0] *= colorScale; color.fRGBA[1] *= colorScale; diff --git a/src/utils/SkShadowUtils.cpp b/src/utils/SkShadowUtils.cpp index 44010b7d01..85e9979d79 100644 --- a/src/utils/SkShadowUtils.cpp +++ b/src/utils/SkShadowUtils.cpp @@ -466,7 +466,7 @@ static SkColor compute_render_color(SkColor color, float alpha, bool useTonalCol SkShadowUtils::ComputeTonalColorParams(color4f.fR, color4f.fG, color4f.fB, - alpha, + color4f.fA*alpha, &colorScale, &tonalAlpha); // After pre-multiplying, we want the alpha to be scaled by tonalAlpha, and // the color scaled by colorScale. This scale factor gives that.