blob: c362488f15726db78e67ad639bda45120d13e77d [file] [log] [blame]
Jim Van Verth43475ad2017-01-13 14:37:37 -05001
2/*
3 * Copyright 2017 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8#ifndef SkShadowUtils_DEFINED
9#define SkShadowUtils_DEFINED
10
11#include "SkColor.h"
Mike Reed54518ac2017-07-22 08:29:48 -040012#include "SkPoint3.h"
Jim Van Verth43475ad2017-01-13 14:37:37 -050013#include "SkScalar.h"
Jim Van Verth2103cf02017-01-16 13:03:37 -050014#include "../private/SkShadowFlags.h"
Jim Van Verth43475ad2017-01-13 14:37:37 -050015
16class SkCanvas;
17class SkPath;
Brian Salomon804e0912017-02-23 09:34:03 -050018class SkResourceCache;
Jim Van Verth43475ad2017-01-13 14:37:37 -050019
Derek Sollenberger2fbf1bc2017-09-20 15:51:08 -040020class SK_API SkShadowUtils {
Jim Van Verth43475ad2017-01-13 14:37:37 -050021public:
Brian Salomon804e0912017-02-23 09:34:03 -050022 /**
23 * Draw an offset spot shadow and outlining ambient shadow for the given path using a disc
Jim Van Verth37c5a962017-05-10 14:13:24 -040024 * light. The shadow may be cached, depending on the path type and canvas matrix. If the
25 * matrix is perspective or the path is volatile, it will not be cached.
Brian Salomon804e0912017-02-23 09:34:03 -050026 *
27 * @param canvas The canvas on which to draw the shadows.
28 * @param path The occluder used to generate the shadows.
Jim Van Verth37c5a962017-05-10 14:13:24 -040029 * @param zPlaneParams Values for the plane function which returns the Z offset of the
30 * occluder from the canvas based on local x and y values (the current matrix is not applied).
Brian Salomon804e0912017-02-23 09:34:03 -050031 * @param lightPos The 3D position of the light relative to the canvas plane. This is
32 * independent of the canvas's current matrix.
33 * @param lightRadius The radius of the disc light.
34 * @param ambientAlpha The maximum alpha of the ambient shadow.
35 * @param spotAlpha The maxium alpha of the spot shadow.
36 * @param color The shadow color.
37 * @param flags Options controlling opaque occluder optimizations and shadow appearance. See
38 * SkShadowFlags.
Brian Salomon804e0912017-02-23 09:34:03 -050039 */
Jim Van Verth37c5a962017-05-10 14:13:24 -040040 static void DrawShadow(SkCanvas* canvas, const SkPath& path, const SkPoint3& zPlaneParams,
41 const SkPoint3& lightPos, SkScalar lightRadius, SkScalar ambientAlpha,
42 SkScalar spotAlpha, SkColor color,
43 uint32_t flags = SkShadowFlags::kNone_ShadowFlag);
44
45 /**
46 * Draw an offset spot shadow and outlining ambient shadow for the given path using a disc
47 * light.
48 *
Jim Van Verth3af1af92017-05-18 15:06:54 -040049 * Deprecated version with height value (to be removed when Flutter is updated).
Jim Van Verth37c5a962017-05-10 14:13:24 -040050 *
51 * @param canvas The canvas on which to draw the shadows.
52 * @param path The occluder used to generate the shadows.
53 * @param occluderHeight The vertical offset of the occluder from the canvas. This is
54 * independent of the canvas's current matrix.
55 * @param lightPos The 3D position of the light relative to the canvas plane. This is
56 * independent of the canvas's current matrix.
57 * @param lightRadius The radius of the disc light.
58 * @param ambientAlpha The maximum alpha of the ambient shadow.
59 * @param spotAlpha The maxium alpha of the spot shadow.
60 * @param color The shadow color.
61 * @param flags Options controlling opaque occluder optimizations and shadow appearance. See
62 * SkShadowFlags.
63 */
Brian Salomon804e0912017-02-23 09:34:03 -050064 static void DrawShadow(SkCanvas* canvas, const SkPath& path, SkScalar occluderHeight,
65 const SkPoint3& lightPos, SkScalar lightRadius, SkScalar ambientAlpha,
66 SkScalar spotAlpha, SkColor color,
Jim Van Verth37c5a962017-05-10 14:13:24 -040067 uint32_t flags = SkShadowFlags::kNone_ShadowFlag) {
68 SkPoint3 zPlane = SkPoint3::Make(0, 0, occluderHeight);
69 DrawShadow(canvas, path, zPlane, lightPos, lightRadius, ambientAlpha, spotAlpha,
70 color, flags);
71 }
Jim Van Verth34d6e4b2017-06-09 11:09:03 -040072
73 /**
74 * Helper routine to compute scale alpha values for one-pass tonal alpha.
75 *
76 * The final color we want to emulate is generated by rendering a color shadow (C_rgb) using an
77 * alpha computed from the color's luminance (C_a), and then a black shadow with alpha (S_a)
78 * which is an adjusted value of 'a'. Assuming SrcOver, a background color of B_rgb, and
79 * ignoring edge falloff, this becomes
80 *
81 * (C_a - S_a*C_a)*C_rgb + (1 - (S_a + C_a - S_a*C_a))*B_rgb
82 *
83 * Since we use premultiplied alpha, this means we can scale the color by (C_a - S_a*C_a) and
84 * set the alpha to (S_a + C_a - S_a*C_a).
85 *
86 * @param r Red value of color
87 * @param g Red value of color
88 * @param b Red value of color
89 * @param a Red value of color
90 * @param colorScale Factor to scale color values by
91 * @param tonalAlpha Value to set alpha to
92 */
93 static inline void ComputeTonalColorParams(SkScalar r, SkScalar g, SkScalar b, SkScalar a,
94 SkScalar* colorScale, SkScalar* tonalAlpha) {
95 SkScalar max = SkTMax(SkTMax(r, g), b);
96 SkScalar min = SkTMin(SkTMin(r, g), b);
97 SkScalar luminance = 0.5f*(max + min);
98
99 // We get best results with a luminance between 0.3 and 0.5, with smoothstep applied
100 SkScalar adjustedLuminance = (0.6f - 0.4f*luminance)*luminance*luminance + 0.3f;
101 // Similarly, we need to tone down the given greyscale alpha depending on how
102 // much color we're applying.
103 a -= (0.5f*adjustedLuminance - 0.15f);
104
105 *colorScale = adjustedLuminance*(SK_Scalar1 - a);
106 *tonalAlpha = *colorScale + a;
107 }
Jim Van Verth1af03d42017-07-31 09:34:58 -0400108
Jim Van Verth43475ad2017-01-13 14:37:37 -0500109};
110
111#endif