1 | /* |
2 | * Copyright 2012 The Android Open Source Project |
3 | * |
4 | * Use of this source code is governed by a BSD-style license that can be |
5 | * found in the LICENSE file. |
6 | */ |
7 | |
8 | #include "include/effects/SkLightingImageFilter.h" |
9 | |
10 | #include "include/core/SkBitmap.h" |
11 | #include "include/core/SkPoint3.h" |
12 | #include "include/core/SkTypes.h" |
13 | #include "include/private/SkColorData.h" |
14 | #include "src/core/SkImageFilter_Base.h" |
15 | #include "src/core/SkReadBuffer.h" |
16 | #include "src/core/SkSpecialImage.h" |
17 | #include "src/core/SkWriteBuffer.h" |
18 | |
19 | #if SK_SUPPORT_GPU |
20 | #include "include/private/GrRecordingContext.h" |
21 | #include "src/gpu/GrCaps.h" |
22 | #include "src/gpu/GrFixedClip.h" |
23 | #include "src/gpu/GrFragmentProcessor.h" |
24 | #include "src/gpu/GrPaint.h" |
25 | #include "src/gpu/GrRecordingContextPriv.h" |
26 | #include "src/gpu/GrRenderTargetContext.h" |
27 | #include "src/gpu/GrTexture.h" |
28 | #include "src/gpu/GrTextureProxy.h" |
29 | |
30 | #include "src/gpu/SkGr.h" |
31 | #include "src/gpu/effects/GrTextureDomain.h" |
32 | #include "src/gpu/glsl/GrGLSLFragmentProcessor.h" |
33 | #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h" |
34 | #include "src/gpu/glsl/GrGLSLProgramDataManager.h" |
35 | #include "src/gpu/glsl/GrGLSLUniformHandler.h" |
36 | |
37 | class GrGLDiffuseLightingEffect; |
38 | class GrGLSpecularLightingEffect; |
39 | |
40 | // For brevity |
41 | typedef GrGLSLProgramDataManager::UniformHandle UniformHandle; |
42 | #endif |
43 | |
44 | const SkScalar gOneThird = SkIntToScalar(1) / 3; |
45 | const SkScalar gTwoThirds = SkIntToScalar(2) / 3; |
46 | const SkScalar gOneHalf = 0.5f; |
47 | const SkScalar gOneQuarter = 0.25f; |
48 | |
49 | #if SK_SUPPORT_GPU |
50 | static void setUniformPoint3(const GrGLSLProgramDataManager& pdman, UniformHandle uni, |
51 | const SkPoint3& point) { |
52 | static_assert(sizeof(SkPoint3) == 3 * sizeof(float)); |
53 | pdman.set3fv(uni, 1, &point.fX); |
54 | } |
55 | |
56 | static void setUniformNormal3(const GrGLSLProgramDataManager& pdman, UniformHandle uni, |
57 | const SkPoint3& point) { |
58 | setUniformPoint3(pdman, uni, point); |
59 | } |
60 | #endif |
61 | |
62 | // Shift matrix components to the left, as we advance pixels to the right. |
63 | static inline void shiftMatrixLeft(int m[9]) { |
64 | m[0] = m[1]; |
65 | m[3] = m[4]; |
66 | m[6] = m[7]; |
67 | m[1] = m[2]; |
68 | m[4] = m[5]; |
69 | m[7] = m[8]; |
70 | } |
71 | |
72 | static inline void fast_normalize(SkPoint3* vector) { |
73 | // add a tiny bit so we don't have to worry about divide-by-zero |
74 | SkScalar magSq = vector->dot(*vector) + SK_ScalarNearlyZero; |
75 | #if defined(_MSC_VER) && _MSC_VER >= 1920 |
76 | // Visual Studio 2019 has some kind of code-generation bug in release builds involving the |
77 | // lighting math in this file. Using the portable rsqrt avoids the issue. This issue appears |
78 | // to be specific to the collection of (inline) functions in this file that call into this |
79 | // function, not with sk_float_rsqrt itself. |
80 | SkScalar scale = sk_float_rsqrt_portable(magSq); |
81 | #else |
82 | SkScalar scale = sk_float_rsqrt(magSq); |
83 | #endif |
84 | vector->fX *= scale; |
85 | vector->fY *= scale; |
86 | vector->fZ *= scale; |
87 | } |
88 | |
89 | static SkPoint3 read_point3(SkReadBuffer& buffer) { |
90 | SkPoint3 point; |
91 | point.fX = buffer.readScalar(); |
92 | point.fY = buffer.readScalar(); |
93 | point.fZ = buffer.readScalar(); |
94 | buffer.validate(SkScalarIsFinite(point.fX) && |
95 | SkScalarIsFinite(point.fY) && |
96 | SkScalarIsFinite(point.fZ)); |
97 | return point; |
98 | }; |
99 | |
100 | static void write_point3(const SkPoint3& point, SkWriteBuffer& buffer) { |
101 | buffer.writeScalar(point.fX); |
102 | buffer.writeScalar(point.fY); |
103 | buffer.writeScalar(point.fZ); |
104 | }; |
105 | |
106 | class GrGLLight; |
107 | class SkImageFilterLight : public SkRefCnt { |
108 | public: |
109 | enum LightType { |
110 | kDistant_LightType, |
111 | kPoint_LightType, |
112 | kSpot_LightType, |
113 | |
114 | kLast_LightType = kSpot_LightType |
115 | }; |
116 | virtual LightType type() const = 0; |
117 | const SkPoint3& color() const { return fColor; } |
118 | virtual GrGLLight* createGLLight() const = 0; |
119 | virtual bool isEqual(const SkImageFilterLight& other) const { |
120 | return fColor == other.fColor; |
121 | } |
122 | virtual SkImageFilterLight* transform(const SkMatrix& matrix) const = 0; |
123 | |
124 | // Defined below SkLight's subclasses. |
125 | void flattenLight(SkWriteBuffer& buffer) const; |
126 | static SkImageFilterLight* UnflattenLight(SkReadBuffer& buffer); |
127 | |
128 | virtual SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const = 0; |
129 | virtual SkPoint3 lightColor(const SkPoint3& surfaceToLight) const = 0; |
130 | |
131 | protected: |
132 | SkImageFilterLight(SkColor color) { |
133 | fColor = SkPoint3::Make(SkIntToScalar(SkColorGetR(color)), |
134 | SkIntToScalar(SkColorGetG(color)), |
135 | SkIntToScalar(SkColorGetB(color))); |
136 | } |
137 | SkImageFilterLight(const SkPoint3& color) : fColor(color) {} |
138 | |
139 | SkImageFilterLight(SkReadBuffer& buffer) { |
140 | fColor = read_point3(buffer); |
141 | } |
142 | |
143 | virtual void onFlattenLight(SkWriteBuffer& buffer) const = 0; |
144 | |
145 | |
146 | private: |
147 | typedef SkRefCnt INHERITED; |
148 | SkPoint3 fColor; |
149 | }; |
150 | |
151 | class BaseLightingType { |
152 | public: |
153 | BaseLightingType() {} |
154 | virtual ~BaseLightingType() {} |
155 | |
156 | virtual SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight, |
157 | const SkPoint3& lightColor) const= 0; |
158 | }; |
159 | |
160 | class DiffuseLightingType : public BaseLightingType { |
161 | public: |
162 | DiffuseLightingType(SkScalar kd) |
163 | : fKD(kd) {} |
164 | SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight, |
165 | const SkPoint3& lightColor) const override { |
166 | SkScalar colorScale = fKD * normal.dot(surfaceTolight); |
167 | colorScale = SkTPin(colorScale, 0.0f, SK_Scalar1); |
168 | SkPoint3 color = lightColor.makeScale(colorScale); |
169 | return SkPackARGB32(255, |
170 | SkTPin(SkScalarRoundToInt(color.fX), 0, 255), |
171 | SkTPin(SkScalarRoundToInt(color.fY), 0, 255), |
172 | SkTPin(SkScalarRoundToInt(color.fZ), 0, 255)); |
173 | } |
174 | private: |
175 | SkScalar fKD; |
176 | }; |
177 | |
178 | static SkScalar max_component(const SkPoint3& p) { |
179 | return p.x() > p.y() ? (p.x() > p.z() ? p.x() : p.z()) : (p.y() > p.z() ? p.y() : p.z()); |
180 | } |
181 | |
182 | class SpecularLightingType : public BaseLightingType { |
183 | public: |
184 | SpecularLightingType(SkScalar ks, SkScalar shininess) |
185 | : fKS(ks), fShininess(shininess) {} |
186 | SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight, |
187 | const SkPoint3& lightColor) const override { |
188 | SkPoint3 halfDir(surfaceTolight); |
189 | halfDir.fZ += SK_Scalar1; // eye position is always (0, 0, 1) |
190 | fast_normalize(&halfDir); |
191 | SkScalar colorScale = fKS * SkScalarPow(normal.dot(halfDir), fShininess); |
192 | colorScale = SkTPin(colorScale, 0.0f, SK_Scalar1); |
193 | SkPoint3 color = lightColor.makeScale(colorScale); |
194 | return SkPackARGB32(SkTPin(SkScalarRoundToInt(max_component(color)), 0, 255), |
195 | SkTPin(SkScalarRoundToInt(color.fX), 0, 255), |
196 | SkTPin(SkScalarRoundToInt(color.fY), 0, 255), |
197 | SkTPin(SkScalarRoundToInt(color.fZ), 0, 255)); |
198 | } |
199 | private: |
200 | SkScalar fKS; |
201 | SkScalar fShininess; |
202 | }; |
203 | |
204 | static inline SkScalar sobel(int a, int b, int c, int d, int e, int f, SkScalar scale) { |
205 | return (-a + b - 2 * c + 2 * d -e + f) * scale; |
206 | } |
207 | |
208 | static inline SkPoint3 pointToNormal(SkScalar x, SkScalar y, SkScalar surfaceScale) { |
209 | SkPoint3 vector = SkPoint3::Make(-x * surfaceScale, -y * surfaceScale, 1); |
210 | fast_normalize(&vector); |
211 | return vector; |
212 | } |
213 | |
214 | static inline SkPoint3 topLeftNormal(int m[9], SkScalar surfaceScale) { |
215 | return pointToNormal(sobel(0, 0, m[4], m[5], m[7], m[8], gTwoThirds), |
216 | sobel(0, 0, m[4], m[7], m[5], m[8], gTwoThirds), |
217 | surfaceScale); |
218 | } |
219 | |
220 | static inline SkPoint3 topNormal(int m[9], SkScalar surfaceScale) { |
221 | return pointToNormal(sobel( 0, 0, m[3], m[5], m[6], m[8], gOneThird), |
222 | sobel(m[3], m[6], m[4], m[7], m[5], m[8], gOneHalf), |
223 | surfaceScale); |
224 | } |
225 | |
226 | static inline SkPoint3 topRightNormal(int m[9], SkScalar surfaceScale) { |
227 | return pointToNormal(sobel( 0, 0, m[3], m[4], m[6], m[7], gTwoThirds), |
228 | sobel(m[3], m[6], m[4], m[7], 0, 0, gTwoThirds), |
229 | surfaceScale); |
230 | } |
231 | |
232 | static inline SkPoint3 leftNormal(int m[9], SkScalar surfaceScale) { |
233 | return pointToNormal(sobel(m[1], m[2], m[4], m[5], m[7], m[8], gOneHalf), |
234 | sobel( 0, 0, m[1], m[7], m[2], m[8], gOneThird), |
235 | surfaceScale); |
236 | } |
237 | |
238 | |
239 | static inline SkPoint3 interiorNormal(int m[9], SkScalar surfaceScale) { |
240 | return pointToNormal(sobel(m[0], m[2], m[3], m[5], m[6], m[8], gOneQuarter), |
241 | sobel(m[0], m[6], m[1], m[7], m[2], m[8], gOneQuarter), |
242 | surfaceScale); |
243 | } |
244 | |
245 | static inline SkPoint3 rightNormal(int m[9], SkScalar surfaceScale) { |
246 | return pointToNormal(sobel(m[0], m[1], m[3], m[4], m[6], m[7], gOneHalf), |
247 | sobel(m[0], m[6], m[1], m[7], 0, 0, gOneThird), |
248 | surfaceScale); |
249 | } |
250 | |
251 | static inline SkPoint3 bottomLeftNormal(int m[9], SkScalar surfaceScale) { |
252 | return pointToNormal(sobel(m[1], m[2], m[4], m[5], 0, 0, gTwoThirds), |
253 | sobel( 0, 0, m[1], m[4], m[2], m[5], gTwoThirds), |
254 | surfaceScale); |
255 | } |
256 | |
257 | static inline SkPoint3 bottomNormal(int m[9], SkScalar surfaceScale) { |
258 | return pointToNormal(sobel(m[0], m[2], m[3], m[5], 0, 0, gOneThird), |
259 | sobel(m[0], m[3], m[1], m[4], m[2], m[5], gOneHalf), |
260 | surfaceScale); |
261 | } |
262 | |
263 | static inline SkPoint3 bottomRightNormal(int m[9], SkScalar surfaceScale) { |
264 | return pointToNormal(sobel(m[0], m[1], m[3], m[4], 0, 0, gTwoThirds), |
265 | sobel(m[0], m[3], m[1], m[4], 0, 0, gTwoThirds), |
266 | surfaceScale); |
267 | } |
268 | |
269 | |
270 | class UncheckedPixelFetcher { |
271 | public: |
272 | static inline uint32_t Fetch(const SkBitmap& src, int x, int y, const SkIRect& bounds) { |
273 | return SkGetPackedA32(*src.getAddr32(x, y)); |
274 | } |
275 | }; |
276 | |
277 | // The DecalPixelFetcher is used when the destination crop rect exceeds the input bitmap bounds. |
278 | class DecalPixelFetcher { |
279 | public: |
280 | static inline uint32_t Fetch(const SkBitmap& src, int x, int y, const SkIRect& bounds) { |
281 | if (x < bounds.fLeft || x >= bounds.fRight || y < bounds.fTop || y >= bounds.fBottom) { |
282 | return 0; |
283 | } else { |
284 | return SkGetPackedA32(*src.getAddr32(x, y)); |
285 | } |
286 | } |
287 | }; |
288 | |
289 | template <class PixelFetcher> |
290 | static void lightBitmap(const BaseLightingType& lightingType, |
291 | const SkImageFilterLight* l, |
292 | const SkBitmap& src, |
293 | SkBitmap* dst, |
294 | SkScalar surfaceScale, |
295 | const SkIRect& bounds) { |
296 | SkASSERT(dst->width() == bounds.width() && dst->height() == bounds.height()); |
297 | int left = bounds.left(), right = bounds.right(); |
298 | int bottom = bounds.bottom(); |
299 | int y = bounds.top(); |
300 | SkIRect srcBounds = src.bounds(); |
301 | SkPMColor* dptr = dst->getAddr32(0, 0); |
302 | { |
303 | int x = left; |
304 | int m[9]; |
305 | m[4] = PixelFetcher::Fetch(src, x, y, srcBounds); |
306 | m[5] = PixelFetcher::Fetch(src, x + 1, y, srcBounds); |
307 | m[7] = PixelFetcher::Fetch(src, x, y + 1, srcBounds); |
308 | m[8] = PixelFetcher::Fetch(src, x + 1, y + 1, srcBounds); |
309 | SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale); |
310 | *dptr++ = lightingType.light(topLeftNormal(m, surfaceScale), surfaceToLight, |
311 | l->lightColor(surfaceToLight)); |
312 | for (++x; x < right - 1; ++x) |
313 | { |
314 | shiftMatrixLeft(m); |
315 | m[5] = PixelFetcher::Fetch(src, x + 1, y, srcBounds); |
316 | m[8] = PixelFetcher::Fetch(src, x + 1, y + 1, srcBounds); |
317 | surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale); |
318 | *dptr++ = lightingType.light(topNormal(m, surfaceScale), surfaceToLight, |
319 | l->lightColor(surfaceToLight)); |
320 | } |
321 | shiftMatrixLeft(m); |
322 | surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale); |
323 | *dptr++ = lightingType.light(topRightNormal(m, surfaceScale), surfaceToLight, |
324 | l->lightColor(surfaceToLight)); |
325 | } |
326 | |
327 | for (++y; y < bottom - 1; ++y) { |
328 | int x = left; |
329 | int m[9]; |
330 | m[1] = PixelFetcher::Fetch(src, x, y - 1, srcBounds); |
331 | m[2] = PixelFetcher::Fetch(src, x + 1, y - 1, srcBounds); |
332 | m[4] = PixelFetcher::Fetch(src, x, y, srcBounds); |
333 | m[5] = PixelFetcher::Fetch(src, x + 1, y, srcBounds); |
334 | m[7] = PixelFetcher::Fetch(src, x, y + 1, srcBounds); |
335 | m[8] = PixelFetcher::Fetch(src, x + 1, y + 1, srcBounds); |
336 | SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale); |
337 | *dptr++ = lightingType.light(leftNormal(m, surfaceScale), surfaceToLight, |
338 | l->lightColor(surfaceToLight)); |
339 | for (++x; x < right - 1; ++x) { |
340 | shiftMatrixLeft(m); |
341 | m[2] = PixelFetcher::Fetch(src, x + 1, y - 1, srcBounds); |
342 | m[5] = PixelFetcher::Fetch(src, x + 1, y, srcBounds); |
343 | m[8] = PixelFetcher::Fetch(src, x + 1, y + 1, srcBounds); |
344 | surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale); |
345 | *dptr++ = lightingType.light(interiorNormal(m, surfaceScale), surfaceToLight, |
346 | l->lightColor(surfaceToLight)); |
347 | } |
348 | shiftMatrixLeft(m); |
349 | surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale); |
350 | *dptr++ = lightingType.light(rightNormal(m, surfaceScale), surfaceToLight, |
351 | l->lightColor(surfaceToLight)); |
352 | } |
353 | |
354 | { |
355 | int x = left; |
356 | int m[9]; |
357 | m[1] = PixelFetcher::Fetch(src, x, bottom - 2, srcBounds); |
358 | m[2] = PixelFetcher::Fetch(src, x + 1, bottom - 2, srcBounds); |
359 | m[4] = PixelFetcher::Fetch(src, x, bottom - 1, srcBounds); |
360 | m[5] = PixelFetcher::Fetch(src, x + 1, bottom - 1, srcBounds); |
361 | SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale); |
362 | *dptr++ = lightingType.light(bottomLeftNormal(m, surfaceScale), surfaceToLight, |
363 | l->lightColor(surfaceToLight)); |
364 | for (++x; x < right - 1; ++x) |
365 | { |
366 | shiftMatrixLeft(m); |
367 | m[2] = PixelFetcher::Fetch(src, x + 1, bottom - 2, srcBounds); |
368 | m[5] = PixelFetcher::Fetch(src, x + 1, bottom - 1, srcBounds); |
369 | surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale); |
370 | *dptr++ = lightingType.light(bottomNormal(m, surfaceScale), surfaceToLight, |
371 | l->lightColor(surfaceToLight)); |
372 | } |
373 | shiftMatrixLeft(m); |
374 | surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale); |
375 | *dptr++ = lightingType.light(bottomRightNormal(m, surfaceScale), surfaceToLight, |
376 | l->lightColor(surfaceToLight)); |
377 | } |
378 | } |
379 | |
380 | static void lightBitmap(const BaseLightingType& lightingType, |
381 | const SkImageFilterLight* light, |
382 | const SkBitmap& src, |
383 | SkBitmap* dst, |
384 | SkScalar surfaceScale, |
385 | const SkIRect& bounds) { |
386 | if (src.bounds().contains(bounds)) { |
387 | lightBitmap<UncheckedPixelFetcher>( |
388 | lightingType, light, src, dst, surfaceScale, bounds); |
389 | } else { |
390 | lightBitmap<DecalPixelFetcher>( |
391 | lightingType, light, src, dst, surfaceScale, bounds); |
392 | } |
393 | } |
394 | |
395 | enum BoundaryMode { |
396 | kTopLeft_BoundaryMode, |
397 | kTop_BoundaryMode, |
398 | kTopRight_BoundaryMode, |
399 | kLeft_BoundaryMode, |
400 | kInterior_BoundaryMode, |
401 | kRight_BoundaryMode, |
402 | kBottomLeft_BoundaryMode, |
403 | kBottom_BoundaryMode, |
404 | kBottomRight_BoundaryMode, |
405 | |
406 | kBoundaryModeCount, |
407 | }; |
408 | |
409 | class SkLightingImageFilterInternal : public SkImageFilter_Base { |
410 | protected: |
411 | SkLightingImageFilterInternal(sk_sp<SkImageFilterLight> light, |
412 | SkScalar surfaceScale, |
413 | sk_sp<SkImageFilter> input, |
414 | const CropRect* cropRect) |
415 | : INHERITED(&input, 1, cropRect) |
416 | , fLight(std::move(light)) |
417 | , fSurfaceScale(surfaceScale / 255) {} |
418 | |
419 | void flatten(SkWriteBuffer& buffer) const override { |
420 | this->INHERITED::flatten(buffer); |
421 | fLight->flattenLight(buffer); |
422 | buffer.writeScalar(fSurfaceScale * 255); |
423 | } |
424 | |
425 | bool affectsTransparentBlack() const override { return true; } |
426 | |
427 | const SkImageFilterLight* light() const { return fLight.get(); } |
428 | inline sk_sp<const SkImageFilterLight> refLight() const { return fLight; } |
429 | SkScalar surfaceScale() const { return fSurfaceScale; } |
430 | |
431 | #if SK_SUPPORT_GPU |
432 | sk_sp<SkSpecialImage> filterImageGPU(const Context& ctx, |
433 | SkSpecialImage* input, |
434 | const SkIRect& bounds, |
435 | const SkMatrix& matrix) const; |
436 | virtual std::unique_ptr<GrFragmentProcessor> makeFragmentProcessor( |
437 | GrSurfaceProxyView, |
438 | const SkMatrix&, |
439 | const SkIRect* srcBounds, |
440 | BoundaryMode boundaryMode) const = 0; |
441 | #endif |
442 | |
443 | private: |
444 | #if SK_SUPPORT_GPU |
445 | void drawRect(GrRenderTargetContext*, |
446 | GrSurfaceProxyView srcView, |
447 | const SkMatrix& matrix, |
448 | const GrClip& clip, |
449 | const SkRect& dstRect, |
450 | BoundaryMode boundaryMode, |
451 | const SkIRect* srcBounds, |
452 | const SkIRect& bounds) const; |
453 | #endif |
454 | |
455 | sk_sp<SkImageFilterLight> fLight; |
456 | SkScalar fSurfaceScale; |
457 | |
458 | typedef SkImageFilter_Base INHERITED; |
459 | }; |
460 | |
461 | #if SK_SUPPORT_GPU |
462 | void SkLightingImageFilterInternal::drawRect(GrRenderTargetContext* renderTargetContext, |
463 | GrSurfaceProxyView srcView, |
464 | const SkMatrix& matrix, |
465 | const GrClip& clip, |
466 | const SkRect& dstRect, |
467 | BoundaryMode boundaryMode, |
468 | const SkIRect* srcBounds, |
469 | const SkIRect& bounds) const { |
470 | SkRect srcRect = dstRect.makeOffset(SkIntToScalar(bounds.x()), SkIntToScalar(bounds.y())); |
471 | GrPaint paint; |
472 | auto fp = this->makeFragmentProcessor(std::move(srcView), matrix, srcBounds, boundaryMode); |
473 | paint.addColorFragmentProcessor(std::move(fp)); |
474 | paint.setPorterDuffXPFactory(SkBlendMode::kSrc); |
475 | renderTargetContext->fillRectToRect(clip, std::move(paint), GrAA::kNo, SkMatrix::I(), dstRect, |
476 | srcRect); |
477 | } |
478 | |
479 | sk_sp<SkSpecialImage> SkLightingImageFilterInternal::filterImageGPU( |
480 | const Context& ctx, |
481 | SkSpecialImage* input, |
482 | const SkIRect& offsetBounds, |
483 | const SkMatrix& matrix) const { |
484 | SkASSERT(ctx.gpuBacked()); |
485 | |
486 | auto context = ctx.getContext(); |
487 | |
488 | GrSurfaceProxyView inputView = input->view(context); |
489 | SkASSERT(inputView.asTextureProxy()); |
490 | |
491 | auto renderTargetContext = GrRenderTargetContext::Make( |
492 | context, ctx.grColorType(), ctx.refColorSpace(), SkBackingFit::kApprox, |
493 | offsetBounds.size(), 1, GrMipMapped::kNo, inputView.proxy()->isProtected(), |
494 | kBottomLeft_GrSurfaceOrigin); |
495 | if (!renderTargetContext) { |
496 | return nullptr; |
497 | } |
498 | |
499 | SkIRect dstIRect = SkIRect::MakeWH(offsetBounds.width(), offsetBounds.height()); |
500 | SkRect dstRect = SkRect::Make(dstIRect); |
501 | |
502 | // setup new clip |
503 | GrFixedClip clip(dstIRect); |
504 | |
505 | const SkIRect inputBounds = SkIRect::MakeWH(input->width(), input->height()); |
506 | SkRect topLeft = SkRect::MakeXYWH(0, 0, 1, 1); |
507 | SkRect top = SkRect::MakeXYWH(1, 0, dstRect.width() - 2, 1); |
508 | SkRect topRight = SkRect::MakeXYWH(dstRect.width() - 1, 0, 1, 1); |
509 | SkRect left = SkRect::MakeXYWH(0, 1, 1, dstRect.height() - 2); |
510 | SkRect interior = dstRect.makeInset(1, 1); |
511 | SkRect right = SkRect::MakeXYWH(dstRect.width() - 1, 1, 1, dstRect.height() - 2); |
512 | SkRect bottomLeft = SkRect::MakeXYWH(0, dstRect.height() - 1, 1, 1); |
513 | SkRect bottom = SkRect::MakeXYWH(1, dstRect.height() - 1, dstRect.width() - 2, 1); |
514 | SkRect bottomRight = SkRect::MakeXYWH(dstRect.width() - 1, dstRect.height() - 1, 1, 1); |
515 | |
516 | const SkIRect* pSrcBounds = inputBounds.contains(offsetBounds) ? nullptr : &inputBounds; |
517 | this->drawRect(renderTargetContext.get(), inputView, matrix, clip, topLeft, |
518 | kTopLeft_BoundaryMode, pSrcBounds, offsetBounds); |
519 | this->drawRect(renderTargetContext.get(), inputView, matrix, clip, top, |
520 | kTop_BoundaryMode, pSrcBounds, offsetBounds); |
521 | this->drawRect(renderTargetContext.get(), inputView, matrix, clip, topRight, |
522 | kTopRight_BoundaryMode, pSrcBounds, offsetBounds); |
523 | this->drawRect(renderTargetContext.get(), inputView, matrix, clip, left, |
524 | kLeft_BoundaryMode, pSrcBounds, offsetBounds); |
525 | this->drawRect(renderTargetContext.get(), inputView, matrix, clip, interior, |
526 | kInterior_BoundaryMode, pSrcBounds, offsetBounds); |
527 | this->drawRect(renderTargetContext.get(), inputView, matrix, clip, right, |
528 | kRight_BoundaryMode, pSrcBounds, offsetBounds); |
529 | this->drawRect(renderTargetContext.get(), inputView, matrix, clip, bottomLeft, |
530 | kBottomLeft_BoundaryMode, pSrcBounds, offsetBounds); |
531 | this->drawRect(renderTargetContext.get(), inputView, matrix, clip, bottom, |
532 | kBottom_BoundaryMode, pSrcBounds, offsetBounds); |
533 | this->drawRect(renderTargetContext.get(), std::move(inputView), matrix, clip, bottomRight, |
534 | kBottomRight_BoundaryMode, pSrcBounds, offsetBounds); |
535 | |
536 | return SkSpecialImage::MakeDeferredFromGpu( |
537 | context, |
538 | SkIRect::MakeWH(offsetBounds.width(), offsetBounds.height()), |
539 | kNeedNewImageUniqueID_SpecialImage, |
540 | renderTargetContext->readSurfaceView(), |
541 | renderTargetContext->colorInfo().colorType(), |
542 | renderTargetContext->colorInfo().refColorSpace()); |
543 | } |
544 | #endif |
545 | |
546 | class SkDiffuseLightingImageFilter : public SkLightingImageFilterInternal { |
547 | public: |
548 | static sk_sp<SkImageFilter> Make(sk_sp<SkImageFilterLight> light, |
549 | SkScalar surfaceScale, |
550 | SkScalar kd, |
551 | sk_sp<SkImageFilter>, |
552 | const CropRect*); |
553 | |
554 | SkScalar kd() const { return fKD; } |
555 | |
556 | protected: |
557 | SkDiffuseLightingImageFilter(sk_sp<SkImageFilterLight> light, SkScalar surfaceScale, |
558 | SkScalar kd, |
559 | sk_sp<SkImageFilter> input, const CropRect* cropRect); |
560 | void flatten(SkWriteBuffer& buffer) const override; |
561 | |
562 | sk_sp<SkSpecialImage> onFilterImage(const Context&, SkIPoint* offset) const override; |
563 | |
564 | #if SK_SUPPORT_GPU |
565 | std::unique_ptr<GrFragmentProcessor> makeFragmentProcessor(GrSurfaceProxyView, |
566 | const SkMatrix&, |
567 | const SkIRect* bounds, |
568 | BoundaryMode) const override; |
569 | #endif |
570 | |
571 | private: |
572 | SK_FLATTENABLE_HOOKS(SkDiffuseLightingImageFilter) |
573 | friend class SkLightingImageFilter; |
574 | SkScalar fKD; |
575 | |
576 | typedef SkLightingImageFilterInternal INHERITED; |
577 | }; |
578 | |
579 | class SkSpecularLightingImageFilter : public SkLightingImageFilterInternal { |
580 | public: |
581 | static sk_sp<SkImageFilter> Make(sk_sp<SkImageFilterLight> light, |
582 | SkScalar surfaceScale, |
583 | SkScalar ks, SkScalar shininess, |
584 | sk_sp<SkImageFilter>, const CropRect*); |
585 | |
586 | SkScalar ks() const { return fKS; } |
587 | SkScalar shininess() const { return fShininess; } |
588 | |
589 | protected: |
590 | SkSpecularLightingImageFilter(sk_sp<SkImageFilterLight> light, |
591 | SkScalar surfaceScale, SkScalar ks, |
592 | SkScalar shininess, |
593 | sk_sp<SkImageFilter> input, const CropRect*); |
594 | void flatten(SkWriteBuffer& buffer) const override; |
595 | |
596 | sk_sp<SkSpecialImage> onFilterImage(const Context&, SkIPoint* offset) const override; |
597 | |
598 | #if SK_SUPPORT_GPU |
599 | std::unique_ptr<GrFragmentProcessor> makeFragmentProcessor(GrSurfaceProxyView, |
600 | const SkMatrix&, |
601 | const SkIRect* bounds, |
602 | BoundaryMode) const override; |
603 | #endif |
604 | |
605 | private: |
606 | SK_FLATTENABLE_HOOKS(SkSpecularLightingImageFilter) |
607 | |
608 | SkScalar fKS; |
609 | SkScalar fShininess; |
610 | friend class SkLightingImageFilter; |
611 | typedef SkLightingImageFilterInternal INHERITED; |
612 | }; |
613 | |
614 | #if SK_SUPPORT_GPU |
615 | |
616 | class GrLightingEffect : public GrFragmentProcessor { |
617 | public: |
618 | const SkImageFilterLight* light() const { return fLight.get(); } |
619 | SkScalar surfaceScale() const { return fSurfaceScale; } |
620 | const SkMatrix& filterMatrix() const { return fFilterMatrix; } |
621 | BoundaryMode boundaryMode() const { return fBoundaryMode; } |
622 | const GrTextureDomain& domain() const { return fDomain; } |
623 | |
624 | protected: |
625 | GrLightingEffect(ClassID classID, GrSurfaceProxyView, sk_sp<const SkImageFilterLight> light, |
626 | SkScalar surfaceScale, const SkMatrix& matrix, BoundaryMode boundaryMode, |
627 | const SkIRect* srcBounds); |
628 | |
629 | GrLightingEffect(const GrLightingEffect& that); |
630 | |
631 | bool onIsEqual(const GrFragmentProcessor&) const override; |
632 | |
633 | private: |
634 | const TextureSampler& onTextureSampler(int) const override { return fTextureSampler; } |
635 | |
636 | GrCoordTransform fCoordTransform; |
637 | GrTextureDomain fDomain; |
638 | TextureSampler fTextureSampler; |
639 | sk_sp<const SkImageFilterLight> fLight; |
640 | SkScalar fSurfaceScale; |
641 | SkMatrix fFilterMatrix; |
642 | BoundaryMode fBoundaryMode; |
643 | |
644 | typedef GrFragmentProcessor INHERITED; |
645 | }; |
646 | |
647 | class GrDiffuseLightingEffect : public GrLightingEffect { |
648 | public: |
649 | static std::unique_ptr<GrFragmentProcessor> Make(GrSurfaceProxyView view, |
650 | sk_sp<const SkImageFilterLight> light, |
651 | SkScalar surfaceScale, |
652 | const SkMatrix& matrix, |
653 | SkScalar kd, |
654 | BoundaryMode boundaryMode, |
655 | const SkIRect* srcBounds) { |
656 | return std::unique_ptr<GrFragmentProcessor>( |
657 | new GrDiffuseLightingEffect(std::move(view), std::move(light), surfaceScale, |
658 | matrix, kd, boundaryMode, srcBounds)); |
659 | } |
660 | |
661 | const char* name() const override { return "DiffuseLighting" ; } |
662 | |
663 | std::unique_ptr<GrFragmentProcessor> clone() const override { |
664 | return std::unique_ptr<GrFragmentProcessor>(new GrDiffuseLightingEffect(*this)); |
665 | } |
666 | |
667 | SkScalar kd() const { return fKD; } |
668 | |
669 | private: |
670 | GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; |
671 | |
672 | void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; |
673 | |
674 | bool onIsEqual(const GrFragmentProcessor&) const override; |
675 | |
676 | GrDiffuseLightingEffect(GrSurfaceProxyView view, |
677 | sk_sp<const SkImageFilterLight> light, |
678 | SkScalar surfaceScale, |
679 | const SkMatrix& matrix, |
680 | SkScalar kd, |
681 | BoundaryMode boundaryMode, |
682 | const SkIRect* srcBounds); |
683 | |
684 | explicit GrDiffuseLightingEffect(const GrDiffuseLightingEffect& that); |
685 | |
686 | GR_DECLARE_FRAGMENT_PROCESSOR_TEST |
687 | SkScalar fKD; |
688 | |
689 | typedef GrLightingEffect INHERITED; |
690 | }; |
691 | |
692 | class GrSpecularLightingEffect : public GrLightingEffect { |
693 | public: |
694 | static std::unique_ptr<GrFragmentProcessor> Make(GrSurfaceProxyView view, |
695 | sk_sp<const SkImageFilterLight> light, |
696 | SkScalar surfaceScale, |
697 | const SkMatrix& matrix, |
698 | SkScalar ks, |
699 | SkScalar shininess, |
700 | BoundaryMode boundaryMode, |
701 | const SkIRect* srcBounds) { |
702 | return std::unique_ptr<GrFragmentProcessor>( |
703 | new GrSpecularLightingEffect(std::move(view), std::move(light), surfaceScale, |
704 | matrix, ks, shininess, boundaryMode, srcBounds)); |
705 | } |
706 | |
707 | const char* name() const override { return "SpecularLighting" ; } |
708 | |
709 | std::unique_ptr<GrFragmentProcessor> clone() const override { |
710 | return std::unique_ptr<GrFragmentProcessor>(new GrSpecularLightingEffect(*this)); |
711 | } |
712 | |
713 | GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; |
714 | |
715 | SkScalar ks() const { return fKS; } |
716 | SkScalar shininess() const { return fShininess; } |
717 | |
718 | private: |
719 | void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; |
720 | |
721 | bool onIsEqual(const GrFragmentProcessor&) const override; |
722 | |
723 | GrSpecularLightingEffect(GrSurfaceProxyView, |
724 | sk_sp<const SkImageFilterLight> light, |
725 | SkScalar surfaceScale, |
726 | const SkMatrix& matrix, |
727 | SkScalar ks, |
728 | SkScalar shininess, |
729 | BoundaryMode boundaryMode, |
730 | const SkIRect* srcBounds); |
731 | |
732 | explicit GrSpecularLightingEffect(const GrSpecularLightingEffect&); |
733 | |
734 | GR_DECLARE_FRAGMENT_PROCESSOR_TEST |
735 | SkScalar fKS; |
736 | SkScalar fShininess; |
737 | |
738 | typedef GrLightingEffect INHERITED; |
739 | }; |
740 | |
741 | /////////////////////////////////////////////////////////////////////////////// |
742 | |
743 | class GrGLLight { |
744 | public: |
745 | virtual ~GrGLLight() {} |
746 | |
747 | /** |
748 | * This is called by GrGLLightingEffect::emitCode() before either of the two virtual functions |
749 | * below. It adds a half3 uniform visible in the FS that represents the constant light color. |
750 | */ |
751 | void emitLightColorUniform(const GrFragmentProcessor*, GrGLSLUniformHandler*); |
752 | |
753 | /** |
754 | * These two functions are called from GrGLLightingEffect's emitCode() function. |
755 | * emitSurfaceToLight places an expression in param out that is the vector from the surface to |
756 | * the light. The expression will be used in the FS. emitLightColor writes an expression into |
757 | * the FS that is the color of the light. Either function may add functions and/or uniforms to |
758 | * the FS. The default of emitLightColor appends the name of the constant light color uniform |
759 | * and so this function only needs to be overridden if the light color varies spatially. |
760 | */ |
761 | virtual void emitSurfaceToLight(const GrFragmentProcessor*, |
762 | GrGLSLUniformHandler*, |
763 | GrGLSLFPFragmentBuilder*, |
764 | const char* z) = 0; |
765 | virtual void emitLightColor(const GrFragmentProcessor*, |
766 | GrGLSLUniformHandler*, |
767 | GrGLSLFPFragmentBuilder*, |
768 | const char *surfaceToLight); |
769 | |
770 | // This is called from GrGLLightingEffect's setData(). Subclasses of GrGLLight must call |
771 | // INHERITED::setData(). |
772 | virtual void setData(const GrGLSLProgramDataManager&, const SkImageFilterLight* light) const; |
773 | |
774 | protected: |
775 | /** |
776 | * Gets the constant light color uniform. Subclasses can use this in their emitLightColor |
777 | * function. |
778 | */ |
779 | UniformHandle lightColorUni() const { return fColorUni; } |
780 | |
781 | private: |
782 | UniformHandle fColorUni; |
783 | |
784 | typedef SkRefCnt INHERITED; |
785 | }; |
786 | |
787 | /////////////////////////////////////////////////////////////////////////////// |
788 | |
789 | class GrGLDistantLight : public GrGLLight { |
790 | public: |
791 | ~GrGLDistantLight() override {} |
792 | void setData(const GrGLSLProgramDataManager&, const SkImageFilterLight* light) const override; |
793 | void emitSurfaceToLight(const GrFragmentProcessor*, GrGLSLUniformHandler*, |
794 | GrGLSLFPFragmentBuilder*, const char* z) override; |
795 | |
796 | private: |
797 | typedef GrGLLight INHERITED; |
798 | UniformHandle fDirectionUni; |
799 | }; |
800 | |
801 | /////////////////////////////////////////////////////////////////////////////// |
802 | |
803 | class GrGLPointLight : public GrGLLight { |
804 | public: |
805 | ~GrGLPointLight() override {} |
806 | void setData(const GrGLSLProgramDataManager&, const SkImageFilterLight* light) const override; |
807 | void emitSurfaceToLight(const GrFragmentProcessor*, GrGLSLUniformHandler*, |
808 | GrGLSLFPFragmentBuilder*, const char* z) override; |
809 | |
810 | private: |
811 | typedef GrGLLight INHERITED; |
812 | UniformHandle fLocationUni; |
813 | }; |
814 | |
815 | /////////////////////////////////////////////////////////////////////////////// |
816 | |
817 | class GrGLSpotLight : public GrGLLight { |
818 | public: |
819 | ~GrGLSpotLight() override {} |
820 | void setData(const GrGLSLProgramDataManager&, const SkImageFilterLight* light) const override; |
821 | void emitSurfaceToLight(const GrFragmentProcessor*, GrGLSLUniformHandler*, |
822 | GrGLSLFPFragmentBuilder*, const char* z) override; |
823 | void emitLightColor(const GrFragmentProcessor*, |
824 | GrGLSLUniformHandler*, |
825 | GrGLSLFPFragmentBuilder*, |
826 | const char *surfaceToLight) override; |
827 | |
828 | private: |
829 | typedef GrGLLight INHERITED; |
830 | |
831 | SkString fLightColorFunc; |
832 | UniformHandle fLocationUni; |
833 | UniformHandle fExponentUni; |
834 | UniformHandle fCosOuterConeAngleUni; |
835 | UniformHandle fCosInnerConeAngleUni; |
836 | UniformHandle fConeScaleUni; |
837 | UniformHandle fSUni; |
838 | }; |
839 | #else |
840 | |
841 | class GrGLLight; |
842 | |
843 | #endif |
844 | |
845 | /////////////////////////////////////////////////////////////////////////////// |
846 | |
847 | /////////////////////////////////////////////////////////////////////////////// |
848 | |
849 | class SkDistantLight : public SkImageFilterLight { |
850 | public: |
851 | SkDistantLight(const SkPoint3& direction, SkColor color) |
852 | : INHERITED(color), fDirection(direction) { |
853 | } |
854 | |
855 | SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const override { |
856 | return fDirection; |
857 | } |
858 | SkPoint3 lightColor(const SkPoint3&) const override { return this->color(); } |
859 | LightType type() const override { return kDistant_LightType; } |
860 | const SkPoint3& direction() const { return fDirection; } |
861 | GrGLLight* createGLLight() const override { |
862 | #if SK_SUPPORT_GPU |
863 | return new GrGLDistantLight; |
864 | #else |
865 | SkDEBUGFAIL("Should not call in GPU-less build" ); |
866 | return nullptr; |
867 | #endif |
868 | } |
869 | |
870 | bool isEqual(const SkImageFilterLight& other) const override { |
871 | if (other.type() != kDistant_LightType) { |
872 | return false; |
873 | } |
874 | |
875 | const SkDistantLight& o = static_cast<const SkDistantLight&>(other); |
876 | return INHERITED::isEqual(other) && |
877 | fDirection == o.fDirection; |
878 | } |
879 | |
880 | SkDistantLight(SkReadBuffer& buffer) : INHERITED(buffer) { |
881 | fDirection = read_point3(buffer); |
882 | } |
883 | |
884 | protected: |
885 | SkDistantLight(const SkPoint3& direction, const SkPoint3& color) |
886 | : INHERITED(color), fDirection(direction) { |
887 | } |
888 | SkImageFilterLight* transform(const SkMatrix& matrix) const override { |
889 | return new SkDistantLight(direction(), color()); |
890 | } |
891 | void onFlattenLight(SkWriteBuffer& buffer) const override { |
892 | write_point3(fDirection, buffer); |
893 | } |
894 | |
895 | private: |
896 | SkPoint3 fDirection; |
897 | |
898 | typedef SkImageFilterLight INHERITED; |
899 | }; |
900 | |
901 | /////////////////////////////////////////////////////////////////////////////// |
902 | |
903 | class SkPointLight : public SkImageFilterLight { |
904 | public: |
905 | SkPointLight(const SkPoint3& location, SkColor color) |
906 | : INHERITED(color), fLocation(location) {} |
907 | |
908 | SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const override { |
909 | SkPoint3 direction = SkPoint3::Make(fLocation.fX - SkIntToScalar(x), |
910 | fLocation.fY - SkIntToScalar(y), |
911 | fLocation.fZ - SkIntToScalar(z) * surfaceScale); |
912 | fast_normalize(&direction); |
913 | return direction; |
914 | } |
915 | SkPoint3 lightColor(const SkPoint3&) const override { return this->color(); } |
916 | LightType type() const override { return kPoint_LightType; } |
917 | const SkPoint3& location() const { return fLocation; } |
918 | GrGLLight* createGLLight() const override { |
919 | #if SK_SUPPORT_GPU |
920 | return new GrGLPointLight; |
921 | #else |
922 | SkDEBUGFAIL("Should not call in GPU-less build" ); |
923 | return nullptr; |
924 | #endif |
925 | } |
926 | |
927 | bool isEqual(const SkImageFilterLight& other) const override { |
928 | if (other.type() != kPoint_LightType) { |
929 | return false; |
930 | } |
931 | const SkPointLight& o = static_cast<const SkPointLight&>(other); |
932 | return INHERITED::isEqual(other) && |
933 | fLocation == o.fLocation; |
934 | } |
935 | SkImageFilterLight* transform(const SkMatrix& matrix) const override { |
936 | SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY); |
937 | matrix.mapPoints(&location2, 1); |
938 | // Use X scale and Y scale on Z and average the result |
939 | SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ); |
940 | matrix.mapVectors(&locationZ, 1); |
941 | SkPoint3 location = SkPoint3::Make(location2.fX, |
942 | location2.fY, |
943 | SkScalarAve(locationZ.fX, locationZ.fY)); |
944 | return new SkPointLight(location, color()); |
945 | } |
946 | |
947 | SkPointLight(SkReadBuffer& buffer) : INHERITED(buffer) { |
948 | fLocation = read_point3(buffer); |
949 | } |
950 | |
951 | protected: |
952 | SkPointLight(const SkPoint3& location, const SkPoint3& color) |
953 | : INHERITED(color), fLocation(location) {} |
954 | void onFlattenLight(SkWriteBuffer& buffer) const override { |
955 | write_point3(fLocation, buffer); |
956 | } |
957 | |
958 | private: |
959 | SkPoint3 fLocation; |
960 | |
961 | typedef SkImageFilterLight INHERITED; |
962 | }; |
963 | |
964 | /////////////////////////////////////////////////////////////////////////////// |
965 | |
966 | class SkSpotLight : public SkImageFilterLight { |
967 | public: |
968 | SkSpotLight(const SkPoint3& location, |
969 | const SkPoint3& target, |
970 | SkScalar specularExponent, |
971 | SkScalar cutoffAngle, |
972 | SkColor color) |
973 | : INHERITED(color), |
974 | fLocation(location), |
975 | fTarget(target), |
976 | fSpecularExponent(SkTPin(specularExponent, kSpecularExponentMin, kSpecularExponentMax)) |
977 | { |
978 | fS = target - location; |
979 | fast_normalize(&fS); |
980 | fCosOuterConeAngle = SkScalarCos(SkDegreesToRadians(cutoffAngle)); |
981 | const SkScalar antiAliasThreshold = 0.016f; |
982 | fCosInnerConeAngle = fCosOuterConeAngle + antiAliasThreshold; |
983 | fConeScale = SkScalarInvert(antiAliasThreshold); |
984 | } |
985 | |
986 | SkImageFilterLight* transform(const SkMatrix& matrix) const override { |
987 | SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY); |
988 | matrix.mapPoints(&location2, 1); |
989 | // Use X scale and Y scale on Z and average the result |
990 | SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ); |
991 | matrix.mapVectors(&locationZ, 1); |
992 | SkPoint3 location = SkPoint3::Make(location2.fX, location2.fY, |
993 | SkScalarAve(locationZ.fX, locationZ.fY)); |
994 | SkPoint target2 = SkPoint::Make(fTarget.fX, fTarget.fY); |
995 | matrix.mapPoints(&target2, 1); |
996 | SkPoint targetZ = SkPoint::Make(fTarget.fZ, fTarget.fZ); |
997 | matrix.mapVectors(&targetZ, 1); |
998 | SkPoint3 target = SkPoint3::Make(target2.fX, target2.fY, |
999 | SkScalarAve(targetZ.fX, targetZ.fY)); |
1000 | SkPoint3 s = target - location; |
1001 | fast_normalize(&s); |
1002 | return new SkSpotLight(location, |
1003 | target, |
1004 | fSpecularExponent, |
1005 | fCosOuterConeAngle, |
1006 | fCosInnerConeAngle, |
1007 | fConeScale, |
1008 | s, |
1009 | color()); |
1010 | } |
1011 | |
1012 | SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const override { |
1013 | SkPoint3 direction = SkPoint3::Make(fLocation.fX - SkIntToScalar(x), |
1014 | fLocation.fY - SkIntToScalar(y), |
1015 | fLocation.fZ - SkIntToScalar(z) * surfaceScale); |
1016 | fast_normalize(&direction); |
1017 | return direction; |
1018 | } |
1019 | SkPoint3 lightColor(const SkPoint3& surfaceToLight) const override { |
1020 | SkScalar cosAngle = -surfaceToLight.dot(fS); |
1021 | SkScalar scale = 0; |
1022 | if (cosAngle >= fCosOuterConeAngle) { |
1023 | scale = SkScalarPow(cosAngle, fSpecularExponent); |
1024 | if (cosAngle < fCosInnerConeAngle) { |
1025 | scale *= (cosAngle - fCosOuterConeAngle) * fConeScale; |
1026 | } |
1027 | } |
1028 | return this->color().makeScale(scale); |
1029 | } |
1030 | GrGLLight* createGLLight() const override { |
1031 | #if SK_SUPPORT_GPU |
1032 | return new GrGLSpotLight; |
1033 | #else |
1034 | SkDEBUGFAIL("Should not call in GPU-less build" ); |
1035 | return nullptr; |
1036 | #endif |
1037 | } |
1038 | LightType type() const override { return kSpot_LightType; } |
1039 | const SkPoint3& location() const { return fLocation; } |
1040 | const SkPoint3& target() const { return fTarget; } |
1041 | SkScalar specularExponent() const { return fSpecularExponent; } |
1042 | SkScalar cosInnerConeAngle() const { return fCosInnerConeAngle; } |
1043 | SkScalar cosOuterConeAngle() const { return fCosOuterConeAngle; } |
1044 | SkScalar coneScale() const { return fConeScale; } |
1045 | const SkPoint3& s() const { return fS; } |
1046 | |
1047 | SkSpotLight(SkReadBuffer& buffer) : INHERITED(buffer) { |
1048 | fLocation = read_point3(buffer); |
1049 | fTarget = read_point3(buffer); |
1050 | fSpecularExponent = buffer.readScalar(); |
1051 | fCosOuterConeAngle = buffer.readScalar(); |
1052 | fCosInnerConeAngle = buffer.readScalar(); |
1053 | fConeScale = buffer.readScalar(); |
1054 | fS = read_point3(buffer); |
1055 | buffer.validate(SkScalarIsFinite(fSpecularExponent) && |
1056 | SkScalarIsFinite(fCosOuterConeAngle) && |
1057 | SkScalarIsFinite(fCosInnerConeAngle) && |
1058 | SkScalarIsFinite(fConeScale)); |
1059 | } |
1060 | protected: |
1061 | SkSpotLight(const SkPoint3& location, |
1062 | const SkPoint3& target, |
1063 | SkScalar specularExponent, |
1064 | SkScalar cosOuterConeAngle, |
1065 | SkScalar cosInnerConeAngle, |
1066 | SkScalar coneScale, |
1067 | const SkPoint3& s, |
1068 | const SkPoint3& color) |
1069 | : INHERITED(color), |
1070 | fLocation(location), |
1071 | fTarget(target), |
1072 | fSpecularExponent(specularExponent), |
1073 | fCosOuterConeAngle(cosOuterConeAngle), |
1074 | fCosInnerConeAngle(cosInnerConeAngle), |
1075 | fConeScale(coneScale), |
1076 | fS(s) |
1077 | { |
1078 | } |
1079 | void onFlattenLight(SkWriteBuffer& buffer) const override { |
1080 | write_point3(fLocation, buffer); |
1081 | write_point3(fTarget, buffer); |
1082 | buffer.writeScalar(fSpecularExponent); |
1083 | buffer.writeScalar(fCosOuterConeAngle); |
1084 | buffer.writeScalar(fCosInnerConeAngle); |
1085 | buffer.writeScalar(fConeScale); |
1086 | write_point3(fS, buffer); |
1087 | } |
1088 | |
1089 | bool isEqual(const SkImageFilterLight& other) const override { |
1090 | if (other.type() != kSpot_LightType) { |
1091 | return false; |
1092 | } |
1093 | |
1094 | const SkSpotLight& o = static_cast<const SkSpotLight&>(other); |
1095 | return INHERITED::isEqual(other) && |
1096 | fLocation == o.fLocation && |
1097 | fTarget == o.fTarget && |
1098 | fSpecularExponent == o.fSpecularExponent && |
1099 | fCosOuterConeAngle == o.fCosOuterConeAngle; |
1100 | } |
1101 | |
1102 | private: |
1103 | static const SkScalar kSpecularExponentMin; |
1104 | static const SkScalar kSpecularExponentMax; |
1105 | |
1106 | SkPoint3 fLocation; |
1107 | SkPoint3 fTarget; |
1108 | SkScalar fSpecularExponent; |
1109 | SkScalar fCosOuterConeAngle; |
1110 | SkScalar fCosInnerConeAngle; |
1111 | SkScalar fConeScale; |
1112 | SkPoint3 fS; |
1113 | |
1114 | typedef SkImageFilterLight INHERITED; |
1115 | }; |
1116 | |
1117 | // According to the spec, the specular term should be in the range [1, 128] : |
1118 | // http://www.w3.org/TR/SVG/filters.html#feSpecularLightingSpecularExponentAttribute |
1119 | const SkScalar SkSpotLight::kSpecularExponentMin = 1.0f; |
1120 | const SkScalar SkSpotLight::kSpecularExponentMax = 128.0f; |
1121 | |
1122 | /////////////////////////////////////////////////////////////////////////////// |
1123 | |
1124 | void SkImageFilterLight::flattenLight(SkWriteBuffer& buffer) const { |
1125 | // Write type first, then baseclass, then subclass. |
1126 | buffer.writeInt(this->type()); |
1127 | write_point3(fColor, buffer); |
1128 | this->onFlattenLight(buffer); |
1129 | } |
1130 | |
1131 | /*static*/ SkImageFilterLight* SkImageFilterLight::UnflattenLight(SkReadBuffer& buffer) { |
1132 | SkImageFilterLight::LightType type = buffer.read32LE(SkImageFilterLight::kLast_LightType); |
1133 | |
1134 | switch (type) { |
1135 | // Each of these constructors must first call SkLight's, so we'll read the baseclass |
1136 | // then subclass, same order as flattenLight. |
1137 | case SkImageFilterLight::kDistant_LightType: |
1138 | return new SkDistantLight(buffer); |
1139 | case SkImageFilterLight::kPoint_LightType: |
1140 | return new SkPointLight(buffer); |
1141 | case SkImageFilterLight::kSpot_LightType: |
1142 | return new SkSpotLight(buffer); |
1143 | default: |
1144 | // Should never get here due to prior check of SkSafeRange |
1145 | SkDEBUGFAIL("Unknown LightType." ); |
1146 | return nullptr; |
1147 | } |
1148 | } |
1149 | /////////////////////////////////////////////////////////////////////////////// |
1150 | |
1151 | sk_sp<SkImageFilter> SkLightingImageFilter::MakeDistantLitDiffuse( |
1152 | const SkPoint3& direction, SkColor lightColor, SkScalar surfaceScale, SkScalar kd, |
1153 | sk_sp<SkImageFilter> input, const SkImageFilter::CropRect* cropRect) { |
1154 | sk_sp<SkImageFilterLight> light(new SkDistantLight(direction, lightColor)); |
1155 | return SkDiffuseLightingImageFilter::Make(std::move(light), surfaceScale, kd, |
1156 | std::move(input), cropRect); |
1157 | } |
1158 | |
1159 | sk_sp<SkImageFilter> SkLightingImageFilter::MakePointLitDiffuse( |
1160 | const SkPoint3& location, SkColor lightColor, SkScalar surfaceScale, SkScalar kd, |
1161 | sk_sp<SkImageFilter> input, const SkImageFilter::CropRect* cropRect) { |
1162 | sk_sp<SkImageFilterLight> light(new SkPointLight(location, lightColor)); |
1163 | return SkDiffuseLightingImageFilter::Make(std::move(light), surfaceScale, kd, |
1164 | std::move(input), cropRect); |
1165 | } |
1166 | |
1167 | sk_sp<SkImageFilter> SkLightingImageFilter::MakeSpotLitDiffuse( |
1168 | const SkPoint3& location, const SkPoint3& target, SkScalar specularExponent, |
1169 | SkScalar cutoffAngle, SkColor lightColor, SkScalar surfaceScale, SkScalar kd, |
1170 | sk_sp<SkImageFilter> input, const SkImageFilter::CropRect* cropRect) { |
1171 | sk_sp<SkImageFilterLight> light( |
1172 | new SkSpotLight(location, target, specularExponent, cutoffAngle, lightColor)); |
1173 | return SkDiffuseLightingImageFilter::Make(std::move(light), surfaceScale, kd, |
1174 | std::move(input), cropRect); |
1175 | } |
1176 | |
1177 | sk_sp<SkImageFilter> SkLightingImageFilter::MakeDistantLitSpecular( |
1178 | const SkPoint3& direction, SkColor lightColor, SkScalar surfaceScale, SkScalar ks, |
1179 | SkScalar shininess, sk_sp<SkImageFilter> input, const SkImageFilter::CropRect* cropRect) { |
1180 | sk_sp<SkImageFilterLight> light(new SkDistantLight(direction, lightColor)); |
1181 | return SkSpecularLightingImageFilter::Make(std::move(light), surfaceScale, ks, shininess, |
1182 | std::move(input), cropRect); |
1183 | } |
1184 | |
1185 | sk_sp<SkImageFilter> SkLightingImageFilter::MakePointLitSpecular( |
1186 | const SkPoint3& location, SkColor lightColor, SkScalar surfaceScale, SkScalar ks, |
1187 | SkScalar shininess, sk_sp<SkImageFilter> input, const SkImageFilter::CropRect* cropRect) { |
1188 | sk_sp<SkImageFilterLight> light(new SkPointLight(location, lightColor)); |
1189 | return SkSpecularLightingImageFilter::Make(std::move(light), surfaceScale, ks, shininess, |
1190 | std::move(input), cropRect); |
1191 | } |
1192 | |
1193 | sk_sp<SkImageFilter> SkLightingImageFilter::MakeSpotLitSpecular( |
1194 | const SkPoint3& location, const SkPoint3& target, SkScalar specularExponent, |
1195 | SkScalar cutoffAngle, SkColor lightColor, SkScalar surfaceScale, SkScalar ks, |
1196 | SkScalar shininess, sk_sp<SkImageFilter> input, const SkImageFilter::CropRect* cropRect) { |
1197 | sk_sp<SkImageFilterLight> light( |
1198 | new SkSpotLight(location, target, specularExponent, cutoffAngle, lightColor)); |
1199 | return SkSpecularLightingImageFilter::Make(std::move(light), surfaceScale, ks, shininess, |
1200 | std::move(input), cropRect); |
1201 | } |
1202 | |
1203 | /////////////////////////////////////////////////////////////////////////////// |
1204 | |
1205 | sk_sp<SkImageFilter> SkDiffuseLightingImageFilter::Make(sk_sp<SkImageFilterLight> light, |
1206 | SkScalar surfaceScale, |
1207 | SkScalar kd, |
1208 | sk_sp<SkImageFilter> input, |
1209 | const CropRect* cropRect) { |
1210 | if (!light) { |
1211 | return nullptr; |
1212 | } |
1213 | if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(kd)) { |
1214 | return nullptr; |
1215 | } |
1216 | // According to the spec, kd can be any non-negative number : |
1217 | // http://www.w3.org/TR/SVG/filters.html#feDiffuseLightingElement |
1218 | if (kd < 0) { |
1219 | return nullptr; |
1220 | } |
1221 | return sk_sp<SkImageFilter>(new SkDiffuseLightingImageFilter(std::move(light), surfaceScale, |
1222 | kd, std::move(input), cropRect)); |
1223 | } |
1224 | |
1225 | SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(sk_sp<SkImageFilterLight> light, |
1226 | SkScalar surfaceScale, |
1227 | SkScalar kd, |
1228 | sk_sp<SkImageFilter> input, |
1229 | const CropRect* cropRect) |
1230 | : INHERITED(std::move(light), surfaceScale, std::move(input), cropRect) |
1231 | , fKD(kd) { |
1232 | } |
1233 | |
1234 | sk_sp<SkFlattenable> SkDiffuseLightingImageFilter::CreateProc(SkReadBuffer& buffer) { |
1235 | SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1); |
1236 | |
1237 | sk_sp<SkImageFilterLight> light(SkImageFilterLight::UnflattenLight(buffer)); |
1238 | SkScalar surfaceScale = buffer.readScalar(); |
1239 | SkScalar kd = buffer.readScalar(); |
1240 | |
1241 | return Make(std::move(light), surfaceScale, kd, common.getInput(0), &common.cropRect()); |
1242 | } |
1243 | |
1244 | void SkDiffuseLightingImageFilter::flatten(SkWriteBuffer& buffer) const { |
1245 | this->INHERITED::flatten(buffer); |
1246 | buffer.writeScalar(fKD); |
1247 | } |
1248 | |
1249 | sk_sp<SkSpecialImage> SkDiffuseLightingImageFilter::onFilterImage(const Context& ctx, |
1250 | SkIPoint* offset) const { |
1251 | SkIPoint inputOffset = SkIPoint::Make(0, 0); |
1252 | sk_sp<SkSpecialImage> input(this->filterInput(0, ctx, &inputOffset)); |
1253 | if (!input) { |
1254 | return nullptr; |
1255 | } |
1256 | |
1257 | const SkIRect inputBounds = SkIRect::MakeXYWH(inputOffset.x(), inputOffset.y(), |
1258 | input->width(), input->height()); |
1259 | SkIRect bounds; |
1260 | if (!this->applyCropRect(ctx, inputBounds, &bounds)) { |
1261 | return nullptr; |
1262 | } |
1263 | |
1264 | offset->fX = bounds.left(); |
1265 | offset->fY = bounds.top(); |
1266 | bounds.offset(-inputOffset); |
1267 | |
1268 | #if SK_SUPPORT_GPU |
1269 | if (ctx.gpuBacked()) { |
1270 | SkMatrix matrix(ctx.ctm()); |
1271 | matrix.postTranslate(SkIntToScalar(-offset->fX), SkIntToScalar(-offset->fY)); |
1272 | |
1273 | return this->filterImageGPU(ctx, input.get(), bounds, matrix); |
1274 | } |
1275 | #endif |
1276 | |
1277 | if (bounds.width() < 2 || bounds.height() < 2) { |
1278 | return nullptr; |
1279 | } |
1280 | |
1281 | SkBitmap inputBM; |
1282 | |
1283 | if (!input->getROPixels(&inputBM)) { |
1284 | return nullptr; |
1285 | } |
1286 | |
1287 | if (inputBM.colorType() != kN32_SkColorType) { |
1288 | return nullptr; |
1289 | } |
1290 | |
1291 | if (!inputBM.getPixels()) { |
1292 | return nullptr; |
1293 | } |
1294 | |
1295 | const SkImageInfo info = SkImageInfo::MakeN32Premul(bounds.width(), bounds.height()); |
1296 | |
1297 | SkBitmap dst; |
1298 | if (!dst.tryAllocPixels(info)) { |
1299 | return nullptr; |
1300 | } |
1301 | |
1302 | SkMatrix matrix(ctx.ctm()); |
1303 | matrix.postTranslate(SkIntToScalar(-inputOffset.x()), SkIntToScalar(-inputOffset.y())); |
1304 | |
1305 | sk_sp<SkImageFilterLight> transformedLight(light()->transform(matrix)); |
1306 | |
1307 | DiffuseLightingType lightingType(fKD); |
1308 | lightBitmap(lightingType, |
1309 | transformedLight.get(), |
1310 | inputBM, |
1311 | &dst, |
1312 | surfaceScale(), |
1313 | bounds); |
1314 | |
1315 | return SkSpecialImage::MakeFromRaster(SkIRect::MakeWH(bounds.width(), bounds.height()), |
1316 | dst); |
1317 | } |
1318 | |
1319 | #if SK_SUPPORT_GPU |
1320 | std::unique_ptr<GrFragmentProcessor> SkDiffuseLightingImageFilter::makeFragmentProcessor( |
1321 | GrSurfaceProxyView view, |
1322 | const SkMatrix& matrix, |
1323 | const SkIRect* srcBounds, |
1324 | BoundaryMode boundaryMode) const { |
1325 | SkScalar scale = this->surfaceScale() * 255; |
1326 | return GrDiffuseLightingEffect::Make(std::move(view), this->refLight(), scale, matrix, |
1327 | this->kd(), boundaryMode, srcBounds); |
1328 | } |
1329 | #endif |
1330 | |
1331 | /////////////////////////////////////////////////////////////////////////////// |
1332 | |
1333 | sk_sp<SkImageFilter> SkSpecularLightingImageFilter::Make(sk_sp<SkImageFilterLight> light, |
1334 | SkScalar surfaceScale, |
1335 | SkScalar ks, |
1336 | SkScalar shininess, |
1337 | sk_sp<SkImageFilter> input, |
1338 | const CropRect* cropRect) { |
1339 | if (!light) { |
1340 | return nullptr; |
1341 | } |
1342 | if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(ks) || !SkScalarIsFinite(shininess)) { |
1343 | return nullptr; |
1344 | } |
1345 | // According to the spec, ks can be any non-negative number : |
1346 | // http://www.w3.org/TR/SVG/filters.html#feSpecularLightingElement |
1347 | if (ks < 0) { |
1348 | return nullptr; |
1349 | } |
1350 | return sk_sp<SkImageFilter>(new SkSpecularLightingImageFilter(std::move(light), surfaceScale, |
1351 | ks, shininess, |
1352 | std::move(input), cropRect)); |
1353 | } |
1354 | |
1355 | SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(sk_sp<SkImageFilterLight> light, |
1356 | SkScalar surfaceScale, |
1357 | SkScalar ks, |
1358 | SkScalar shininess, |
1359 | sk_sp<SkImageFilter> input, |
1360 | const CropRect* cropRect) |
1361 | : INHERITED(std::move(light), surfaceScale, std::move(input), cropRect) |
1362 | , fKS(ks) |
1363 | , fShininess(shininess) { |
1364 | } |
1365 | |
1366 | sk_sp<SkFlattenable> SkSpecularLightingImageFilter::CreateProc(SkReadBuffer& buffer) { |
1367 | SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1); |
1368 | sk_sp<SkImageFilterLight> light(SkImageFilterLight::UnflattenLight(buffer)); |
1369 | SkScalar surfaceScale = buffer.readScalar(); |
1370 | SkScalar ks = buffer.readScalar(); |
1371 | SkScalar shine = buffer.readScalar(); |
1372 | |
1373 | return Make(std::move(light), surfaceScale, ks, shine, common.getInput(0), |
1374 | &common.cropRect()); |
1375 | } |
1376 | |
1377 | void SkSpecularLightingImageFilter::flatten(SkWriteBuffer& buffer) const { |
1378 | this->INHERITED::flatten(buffer); |
1379 | buffer.writeScalar(fKS); |
1380 | buffer.writeScalar(fShininess); |
1381 | } |
1382 | |
1383 | sk_sp<SkSpecialImage> SkSpecularLightingImageFilter::onFilterImage(const Context& ctx, |
1384 | SkIPoint* offset) const { |
1385 | SkIPoint inputOffset = SkIPoint::Make(0, 0); |
1386 | sk_sp<SkSpecialImage> input(this->filterInput(0, ctx, &inputOffset)); |
1387 | if (!input) { |
1388 | return nullptr; |
1389 | } |
1390 | |
1391 | const SkIRect inputBounds = SkIRect::MakeXYWH(inputOffset.x(), inputOffset.y(), |
1392 | input->width(), input->height()); |
1393 | SkIRect bounds; |
1394 | if (!this->applyCropRect(ctx, inputBounds, &bounds)) { |
1395 | return nullptr; |
1396 | } |
1397 | |
1398 | offset->fX = bounds.left(); |
1399 | offset->fY = bounds.top(); |
1400 | bounds.offset(-inputOffset); |
1401 | |
1402 | #if SK_SUPPORT_GPU |
1403 | if (ctx.gpuBacked()) { |
1404 | SkMatrix matrix(ctx.ctm()); |
1405 | matrix.postTranslate(SkIntToScalar(-offset->fX), SkIntToScalar(-offset->fY)); |
1406 | |
1407 | return this->filterImageGPU(ctx, input.get(), bounds, matrix); |
1408 | } |
1409 | #endif |
1410 | |
1411 | if (bounds.width() < 2 || bounds.height() < 2) { |
1412 | return nullptr; |
1413 | } |
1414 | |
1415 | SkBitmap inputBM; |
1416 | |
1417 | if (!input->getROPixels(&inputBM)) { |
1418 | return nullptr; |
1419 | } |
1420 | |
1421 | if (inputBM.colorType() != kN32_SkColorType) { |
1422 | return nullptr; |
1423 | } |
1424 | |
1425 | if (!inputBM.getPixels()) { |
1426 | return nullptr; |
1427 | } |
1428 | |
1429 | const SkImageInfo info = SkImageInfo::MakeN32Premul(bounds.width(), bounds.height()); |
1430 | |
1431 | SkBitmap dst; |
1432 | if (!dst.tryAllocPixels(info)) { |
1433 | return nullptr; |
1434 | } |
1435 | |
1436 | SpecularLightingType lightingType(fKS, fShininess); |
1437 | |
1438 | SkMatrix matrix(ctx.ctm()); |
1439 | matrix.postTranslate(SkIntToScalar(-inputOffset.x()), SkIntToScalar(-inputOffset.y())); |
1440 | |
1441 | sk_sp<SkImageFilterLight> transformedLight(light()->transform(matrix)); |
1442 | |
1443 | lightBitmap(lightingType, |
1444 | transformedLight.get(), |
1445 | inputBM, |
1446 | &dst, |
1447 | surfaceScale(), |
1448 | bounds); |
1449 | |
1450 | return SkSpecialImage::MakeFromRaster(SkIRect::MakeWH(bounds.width(), bounds.height()), dst); |
1451 | } |
1452 | |
1453 | #if SK_SUPPORT_GPU |
1454 | std::unique_ptr<GrFragmentProcessor> SkSpecularLightingImageFilter::makeFragmentProcessor( |
1455 | GrSurfaceProxyView view, |
1456 | const SkMatrix& matrix, |
1457 | const SkIRect* srcBounds, |
1458 | BoundaryMode boundaryMode) const { |
1459 | SkScalar scale = this->surfaceScale() * 255; |
1460 | return GrSpecularLightingEffect::Make(std::move(view), this->refLight(), scale, matrix, |
1461 | this->ks(), this->shininess(), boundaryMode, srcBounds); |
1462 | } |
1463 | #endif |
1464 | |
1465 | /////////////////////////////////////////////////////////////////////////////// |
1466 | |
1467 | #if SK_SUPPORT_GPU |
1468 | |
1469 | static SkString emitNormalFunc(BoundaryMode mode, |
1470 | const char* pointToNormalName, |
1471 | const char* sobelFuncName) { |
1472 | SkString result; |
1473 | switch (mode) { |
1474 | case kTopLeft_BoundaryMode: |
1475 | result.printf("\treturn %s(%s(0.0, 0.0, m[4], m[5], m[7], m[8], %g),\n" |
1476 | "\t %s(0.0, 0.0, m[4], m[7], m[5], m[8], %g),\n" |
1477 | "\t surfaceScale);\n" , |
1478 | pointToNormalName, sobelFuncName, gTwoThirds, |
1479 | sobelFuncName, gTwoThirds); |
1480 | break; |
1481 | case kTop_BoundaryMode: |
1482 | result.printf("\treturn %s(%s(0.0, 0.0, m[3], m[5], m[6], m[8], %g),\n" |
1483 | "\t %s(0.0, 0.0, m[4], m[7], m[5], m[8], %g),\n" |
1484 | "\t surfaceScale);\n" , |
1485 | pointToNormalName, sobelFuncName, gOneThird, |
1486 | sobelFuncName, gOneHalf); |
1487 | break; |
1488 | case kTopRight_BoundaryMode: |
1489 | result.printf("\treturn %s(%s( 0.0, 0.0, m[3], m[4], m[6], m[7], %g),\n" |
1490 | "\t %s(m[3], m[6], m[4], m[7], 0.0, 0.0, %g),\n" |
1491 | "\t surfaceScale);\n" , |
1492 | pointToNormalName, sobelFuncName, gTwoThirds, |
1493 | sobelFuncName, gTwoThirds); |
1494 | break; |
1495 | case kLeft_BoundaryMode: |
1496 | result.printf("\treturn %s(%s(m[1], m[2], m[4], m[5], m[7], m[8], %g),\n" |
1497 | "\t %s( 0.0, 0.0, m[1], m[7], m[2], m[8], %g),\n" |
1498 | "\t surfaceScale);\n" , |
1499 | pointToNormalName, sobelFuncName, gOneHalf, |
1500 | sobelFuncName, gOneThird); |
1501 | break; |
1502 | case kInterior_BoundaryMode: |
1503 | result.printf("\treturn %s(%s(m[0], m[2], m[3], m[5], m[6], m[8], %g),\n" |
1504 | "\t %s(m[0], m[6], m[1], m[7], m[2], m[8], %g),\n" |
1505 | "\t surfaceScale);\n" , |
1506 | pointToNormalName, sobelFuncName, gOneQuarter, |
1507 | sobelFuncName, gOneQuarter); |
1508 | break; |
1509 | case kRight_BoundaryMode: |
1510 | result.printf("\treturn %s(%s(m[0], m[1], m[3], m[4], m[6], m[7], %g),\n" |
1511 | "\t %s(m[0], m[6], m[1], m[7], 0.0, 0.0, %g),\n" |
1512 | "\t surfaceScale);\n" , |
1513 | pointToNormalName, sobelFuncName, gOneHalf, |
1514 | sobelFuncName, gOneThird); |
1515 | break; |
1516 | case kBottomLeft_BoundaryMode: |
1517 | result.printf("\treturn %s(%s(m[1], m[2], m[4], m[5], 0.0, 0.0, %g),\n" |
1518 | "\t %s( 0.0, 0.0, m[1], m[4], m[2], m[5], %g),\n" |
1519 | "\t surfaceScale);\n" , |
1520 | pointToNormalName, sobelFuncName, gTwoThirds, |
1521 | sobelFuncName, gTwoThirds); |
1522 | break; |
1523 | case kBottom_BoundaryMode: |
1524 | result.printf("\treturn %s(%s(m[0], m[2], m[3], m[5], 0.0, 0.0, %g),\n" |
1525 | "\t %s(m[0], m[3], m[1], m[4], m[2], m[5], %g),\n" |
1526 | "\t surfaceScale);\n" , |
1527 | pointToNormalName, sobelFuncName, gOneThird, |
1528 | sobelFuncName, gOneHalf); |
1529 | break; |
1530 | case kBottomRight_BoundaryMode: |
1531 | result.printf("\treturn %s(%s(m[0], m[1], m[3], m[4], 0.0, 0.0, %g),\n" |
1532 | "\t %s(m[0], m[3], m[1], m[4], 0.0, 0.0, %g),\n" |
1533 | "\t surfaceScale);\n" , |
1534 | pointToNormalName, sobelFuncName, gTwoThirds, |
1535 | sobelFuncName, gTwoThirds); |
1536 | break; |
1537 | default: |
1538 | SkASSERT(false); |
1539 | break; |
1540 | } |
1541 | return result; |
1542 | } |
1543 | |
1544 | class GrGLLightingEffect : public GrGLSLFragmentProcessor { |
1545 | public: |
1546 | GrGLLightingEffect() : fLight(nullptr) { } |
1547 | ~GrGLLightingEffect() override { delete fLight; } |
1548 | |
1549 | void emitCode(EmitArgs&) override; |
1550 | |
1551 | static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder* b); |
1552 | |
1553 | protected: |
1554 | /** |
1555 | * Subclasses of GrGLLightingEffect must call INHERITED::onSetData(); |
1556 | */ |
1557 | void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override; |
1558 | |
1559 | virtual void emitLightFunc(const GrFragmentProcessor*, |
1560 | GrGLSLUniformHandler*, |
1561 | GrGLSLFPFragmentBuilder*, |
1562 | SkString* funcName) = 0; |
1563 | |
1564 | private: |
1565 | typedef GrGLSLFragmentProcessor INHERITED; |
1566 | |
1567 | UniformHandle fImageIncrementUni; |
1568 | UniformHandle fSurfaceScaleUni; |
1569 | GrTextureDomain::GLDomain fDomain; |
1570 | GrGLLight* fLight; |
1571 | }; |
1572 | |
1573 | /////////////////////////////////////////////////////////////////////////////// |
1574 | |
1575 | class GrGLDiffuseLightingEffect : public GrGLLightingEffect { |
1576 | public: |
1577 | void emitLightFunc(const GrFragmentProcessor*, GrGLSLUniformHandler*, GrGLSLFPFragmentBuilder*, |
1578 | SkString* funcName) override; |
1579 | |
1580 | protected: |
1581 | void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override; |
1582 | |
1583 | private: |
1584 | typedef GrGLLightingEffect INHERITED; |
1585 | |
1586 | UniformHandle fKDUni; |
1587 | }; |
1588 | |
1589 | /////////////////////////////////////////////////////////////////////////////// |
1590 | |
1591 | class GrGLSpecularLightingEffect : public GrGLLightingEffect { |
1592 | public: |
1593 | void emitLightFunc(const GrFragmentProcessor*, GrGLSLUniformHandler*, GrGLSLFPFragmentBuilder*, |
1594 | SkString* funcName) override; |
1595 | |
1596 | protected: |
1597 | void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override; |
1598 | |
1599 | private: |
1600 | typedef GrGLLightingEffect INHERITED; |
1601 | |
1602 | UniformHandle fKSUni; |
1603 | UniformHandle fShininessUni; |
1604 | }; |
1605 | |
1606 | /////////////////////////////////////////////////////////////////////////////// |
1607 | |
1608 | static GrTextureDomain create_domain(GrSurfaceProxy* proxy, const SkIRect* srcBounds, |
1609 | GrTextureDomain::Mode mode) { |
1610 | if (srcBounds) { |
1611 | SkRect texelDomain = GrTextureDomain::MakeTexelDomain(*srcBounds, mode); |
1612 | return GrTextureDomain(proxy, texelDomain, mode, mode); |
1613 | } else { |
1614 | return GrTextureDomain::IgnoredDomain(); |
1615 | } |
1616 | } |
1617 | |
1618 | GrLightingEffect::GrLightingEffect(ClassID classID, |
1619 | GrSurfaceProxyView view, |
1620 | sk_sp<const SkImageFilterLight> light, |
1621 | SkScalar surfaceScale, |
1622 | const SkMatrix& matrix, |
1623 | BoundaryMode boundaryMode, |
1624 | const SkIRect* srcBounds) |
1625 | // Perhaps this could advertise the opaque or coverage-as-alpha optimizations? |
1626 | : INHERITED(classID, kNone_OptimizationFlags) |
1627 | , fCoordTransform(view.proxy(), view.origin()) |
1628 | , fDomain(create_domain(view.proxy(), srcBounds, GrTextureDomain::kDecal_Mode)) |
1629 | , fTextureSampler(std::move(view)) |
1630 | , fLight(std::move(light)) |
1631 | , fSurfaceScale(surfaceScale) |
1632 | , fFilterMatrix(matrix) |
1633 | , fBoundaryMode(boundaryMode) { |
1634 | this->addCoordTransform(&fCoordTransform); |
1635 | this->setTextureSamplerCnt(1); |
1636 | } |
1637 | |
1638 | GrLightingEffect::GrLightingEffect(const GrLightingEffect& that) |
1639 | : INHERITED(that.classID(), that.optimizationFlags()) |
1640 | , fCoordTransform(that.fCoordTransform) |
1641 | , fDomain(that.fDomain) |
1642 | , fTextureSampler(that.fTextureSampler) |
1643 | , fLight(that.fLight) |
1644 | , fSurfaceScale(that.fSurfaceScale) |
1645 | , fFilterMatrix(that.fFilterMatrix) |
1646 | , fBoundaryMode(that.fBoundaryMode) { |
1647 | this->addCoordTransform(&fCoordTransform); |
1648 | this->setTextureSamplerCnt(1); |
1649 | } |
1650 | |
1651 | bool GrLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const { |
1652 | const GrLightingEffect& s = sBase.cast<GrLightingEffect>(); |
1653 | return fLight->isEqual(*s.fLight) && |
1654 | fSurfaceScale == s.fSurfaceScale && |
1655 | fBoundaryMode == s.fBoundaryMode; |
1656 | } |
1657 | |
1658 | /////////////////////////////////////////////////////////////////////////////// |
1659 | |
1660 | GrDiffuseLightingEffect::GrDiffuseLightingEffect(GrSurfaceProxyView view, |
1661 | sk_sp<const SkImageFilterLight>light, |
1662 | SkScalar surfaceScale, |
1663 | const SkMatrix& matrix, |
1664 | SkScalar kd, |
1665 | BoundaryMode boundaryMode, |
1666 | const SkIRect* srcBounds) |
1667 | : INHERITED(kGrDiffuseLightingEffect_ClassID, std::move(view), std::move(light), |
1668 | surfaceScale, matrix, boundaryMode, srcBounds) |
1669 | , fKD(kd) {} |
1670 | |
1671 | GrDiffuseLightingEffect::GrDiffuseLightingEffect(const GrDiffuseLightingEffect& that) |
1672 | : INHERITED(that), fKD(that.fKD) {} |
1673 | |
1674 | bool GrDiffuseLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const { |
1675 | const GrDiffuseLightingEffect& s = sBase.cast<GrDiffuseLightingEffect>(); |
1676 | return INHERITED::onIsEqual(sBase) && this->kd() == s.kd(); |
1677 | } |
1678 | |
1679 | void GrDiffuseLightingEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, |
1680 | GrProcessorKeyBuilder* b) const { |
1681 | GrGLDiffuseLightingEffect::GenKey(*this, caps, b); |
1682 | } |
1683 | |
1684 | GrGLSLFragmentProcessor* GrDiffuseLightingEffect::onCreateGLSLInstance() const { |
1685 | return new GrGLDiffuseLightingEffect; |
1686 | } |
1687 | |
1688 | GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrDiffuseLightingEffect); |
1689 | |
1690 | #if GR_TEST_UTILS |
1691 | |
1692 | static SkPoint3 random_point3(SkRandom* random) { |
1693 | return SkPoint3::Make(SkScalarToFloat(random->nextSScalar1()), |
1694 | SkScalarToFloat(random->nextSScalar1()), |
1695 | SkScalarToFloat(random->nextSScalar1())); |
1696 | } |
1697 | |
1698 | static SkImageFilterLight* create_random_light(SkRandom* random) { |
1699 | int type = random->nextULessThan(3); |
1700 | switch (type) { |
1701 | case 0: { |
1702 | return new SkDistantLight(random_point3(random), random->nextU()); |
1703 | } |
1704 | case 1: { |
1705 | return new SkPointLight(random_point3(random), random->nextU()); |
1706 | } |
1707 | case 2: { |
1708 | return new SkSpotLight(random_point3(random), random_point3(random), |
1709 | random->nextUScalar1(), random->nextUScalar1(), random->nextU()); |
1710 | } |
1711 | default: |
1712 | SK_ABORT("Unexpected value." ); |
1713 | } |
1714 | } |
1715 | |
1716 | std::unique_ptr<GrFragmentProcessor> GrDiffuseLightingEffect::TestCreate(GrProcessorTestData* d) { |
1717 | auto [view, ct, at] = d->randomView(); |
1718 | SkScalar surfaceScale = d->fRandom->nextSScalar1(); |
1719 | SkScalar kd = d->fRandom->nextUScalar1(); |
1720 | sk_sp<SkImageFilterLight> light(create_random_light(d->fRandom)); |
1721 | SkMatrix matrix; |
1722 | for (int i = 0; i < 9; i++) { |
1723 | matrix[i] = d->fRandom->nextUScalar1(); |
1724 | } |
1725 | |
1726 | uint32_t boundsX = d->fRandom->nextRangeU(0, view.width()); |
1727 | uint32_t boundsY = d->fRandom->nextRangeU(0, view.height()); |
1728 | uint32_t boundsW = d->fRandom->nextRangeU(0, view.width()); |
1729 | uint32_t boundsH = d->fRandom->nextRangeU(0, view.height()); |
1730 | SkIRect srcBounds = SkIRect::MakeXYWH(boundsX, boundsY, boundsW, boundsH); |
1731 | BoundaryMode mode = static_cast<BoundaryMode>(d->fRandom->nextU() % kBoundaryModeCount); |
1732 | |
1733 | return GrDiffuseLightingEffect::Make(std::move(view), std::move(light), surfaceScale, matrix, |
1734 | kd, mode, &srcBounds); |
1735 | } |
1736 | #endif |
1737 | |
1738 | |
1739 | /////////////////////////////////////////////////////////////////////////////// |
1740 | |
1741 | void GrGLLightingEffect::emitCode(EmitArgs& args) { |
1742 | const GrLightingEffect& le = args.fFp.cast<GrLightingEffect>(); |
1743 | if (!fLight) { |
1744 | fLight = le.light()->createGLLight(); |
1745 | } |
1746 | |
1747 | GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; |
1748 | fImageIncrementUni = uniformHandler->addUniform(&le, |
1749 | kFragment_GrShaderFlag, |
1750 | kHalf2_GrSLType, "ImageIncrement" ); |
1751 | fSurfaceScaleUni = uniformHandler->addUniform(&le, |
1752 | kFragment_GrShaderFlag, |
1753 | kHalf_GrSLType, "SurfaceScale" ); |
1754 | fLight->emitLightColorUniform(&le, uniformHandler); |
1755 | GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; |
1756 | SkString lightFunc; |
1757 | this->emitLightFunc(&le, uniformHandler, fragBuilder, &lightFunc); |
1758 | const GrShaderVar gSobelArgs[] = { |
1759 | GrShaderVar("a" , kHalf_GrSLType), |
1760 | GrShaderVar("b" , kHalf_GrSLType), |
1761 | GrShaderVar("c" , kHalf_GrSLType), |
1762 | GrShaderVar("d" , kHalf_GrSLType), |
1763 | GrShaderVar("e" , kHalf_GrSLType), |
1764 | GrShaderVar("f" , kHalf_GrSLType), |
1765 | GrShaderVar("scale" , kHalf_GrSLType), |
1766 | }; |
1767 | SkString sobelFuncName; |
1768 | SkString coords2D = fragBuilder->ensureCoords2D(args.fTransformedCoords[0].fVaryingPoint); |
1769 | |
1770 | fragBuilder->emitFunction(kHalf_GrSLType, |
1771 | "sobel" , |
1772 | SK_ARRAY_COUNT(gSobelArgs), |
1773 | gSobelArgs, |
1774 | "\treturn (-a + b - 2.0 * c + 2.0 * d -e + f) * scale;\n" , |
1775 | &sobelFuncName); |
1776 | const GrShaderVar gPointToNormalArgs[] = { |
1777 | GrShaderVar("x" , kHalf_GrSLType), |
1778 | GrShaderVar("y" , kHalf_GrSLType), |
1779 | GrShaderVar("scale" , kHalf_GrSLType), |
1780 | }; |
1781 | SkString pointToNormalName; |
1782 | fragBuilder->emitFunction(kHalf3_GrSLType, |
1783 | "pointToNormal" , |
1784 | SK_ARRAY_COUNT(gPointToNormalArgs), |
1785 | gPointToNormalArgs, |
1786 | "\treturn normalize(half3(-x * scale, -y * scale, 1));\n" , |
1787 | &pointToNormalName); |
1788 | |
1789 | const GrShaderVar gInteriorNormalArgs[] = { |
1790 | GrShaderVar("m" , kHalf_GrSLType, 9), |
1791 | GrShaderVar("surfaceScale" , kHalf_GrSLType), |
1792 | }; |
1793 | SkString normalBody = emitNormalFunc(le.boundaryMode(), |
1794 | pointToNormalName.c_str(), |
1795 | sobelFuncName.c_str()); |
1796 | SkString normalName; |
1797 | fragBuilder->emitFunction(kHalf3_GrSLType, |
1798 | "normal" , |
1799 | SK_ARRAY_COUNT(gInteriorNormalArgs), |
1800 | gInteriorNormalArgs, |
1801 | normalBody.c_str(), |
1802 | &normalName); |
1803 | |
1804 | fragBuilder->codeAppendf("\t\tfloat2 coord = %s;\n" , coords2D.c_str()); |
1805 | fragBuilder->codeAppend("\t\thalf m[9];\n" ); |
1806 | |
1807 | const char* imgInc = uniformHandler->getUniformCStr(fImageIncrementUni); |
1808 | const char* surfScale = uniformHandler->getUniformCStr(fSurfaceScaleUni); |
1809 | |
1810 | int index = 0; |
1811 | for (int dy = 1; dy >= -1; dy--) { |
1812 | for (int dx = -1; dx <= 1; dx++) { |
1813 | SkString texCoords; |
1814 | texCoords.appendf("coord + half2(%d, %d) * %s" , dx, dy, imgInc); |
1815 | SkString temp; |
1816 | temp.appendf("temp%d" , index); |
1817 | fragBuilder->codeAppendf("half4 %s;" , temp.c_str()); |
1818 | fDomain.sampleTexture(&le, |
1819 | fragBuilder, |
1820 | args.fUniformHandler, |
1821 | args.fShaderCaps, |
1822 | le.domain(), |
1823 | temp.c_str(), |
1824 | texCoords, |
1825 | args.fTexSamplers[0]); |
1826 | fragBuilder->codeAppendf("m[%d] = %s.a;" , index, temp.c_str()); |
1827 | index++; |
1828 | } |
1829 | } |
1830 | fragBuilder->codeAppend("\t\thalf3 surfaceToLight = " ); |
1831 | SkString arg; |
1832 | arg.appendf("%s * m[4]" , surfScale); |
1833 | fLight->emitSurfaceToLight(&le, uniformHandler, fragBuilder, arg.c_str()); |
1834 | fragBuilder->codeAppend(";\n" ); |
1835 | fragBuilder->codeAppendf("\t\t%s = %s(%s(m, %s), surfaceToLight, " , |
1836 | args.fOutputColor, lightFunc.c_str(), normalName.c_str(), surfScale); |
1837 | fLight->emitLightColor(&le, uniformHandler, fragBuilder, "surfaceToLight" ); |
1838 | fragBuilder->codeAppend(");\n" ); |
1839 | fragBuilder->codeAppendf("%s *= %s;\n" , args.fOutputColor, args.fInputColor); |
1840 | } |
1841 | |
1842 | void GrGLLightingEffect::GenKey(const GrProcessor& proc, |
1843 | const GrShaderCaps& caps, GrProcessorKeyBuilder* b) { |
1844 | const GrLightingEffect& lighting = proc.cast<GrLightingEffect>(); |
1845 | b->add32(lighting.boundaryMode() << 2 | lighting.light()->type()); |
1846 | b->add32(GrTextureDomain::GLDomain::DomainKey(lighting.domain())); |
1847 | } |
1848 | |
1849 | void GrGLLightingEffect::onSetData(const GrGLSLProgramDataManager& pdman, |
1850 | const GrFragmentProcessor& proc) { |
1851 | const GrLightingEffect& lighting = proc.cast<GrLightingEffect>(); |
1852 | if (!fLight) { |
1853 | fLight = lighting.light()->createGLLight(); |
1854 | } |
1855 | |
1856 | const GrSurfaceProxyView& view = lighting.textureSampler(0).view(); |
1857 | SkISize textureDims = view.proxy()->backingStoreDimensions(); |
1858 | |
1859 | float ySign = view.origin() == kTopLeft_GrSurfaceOrigin ? -1.0f : 1.0f; |
1860 | pdman.set2f(fImageIncrementUni, 1.0f / textureDims.width(), ySign / textureDims.height()); |
1861 | pdman.set1f(fSurfaceScaleUni, lighting.surfaceScale()); |
1862 | sk_sp<SkImageFilterLight> transformedLight( |
1863 | lighting.light()->transform(lighting.filterMatrix())); |
1864 | fDomain.setData(pdman, lighting.domain(), view, lighting.textureSampler(0).samplerState()); |
1865 | fLight->setData(pdman, transformedLight.get()); |
1866 | } |
1867 | |
1868 | /////////////////////////////////////////////////////////////////////////////// |
1869 | |
1870 | /////////////////////////////////////////////////////////////////////////////// |
1871 | |
1872 | void GrGLDiffuseLightingEffect::emitLightFunc(const GrFragmentProcessor* owner, |
1873 | GrGLSLUniformHandler* uniformHandler, |
1874 | GrGLSLFPFragmentBuilder* fragBuilder, |
1875 | SkString* funcName) { |
1876 | const char* kd; |
1877 | fKDUni = uniformHandler->addUniform(owner, kFragment_GrShaderFlag, kHalf_GrSLType, "KD" , &kd); |
1878 | |
1879 | const GrShaderVar gLightArgs[] = { |
1880 | GrShaderVar("normal" , kHalf3_GrSLType), |
1881 | GrShaderVar("surfaceToLight" , kHalf3_GrSLType), |
1882 | GrShaderVar("lightColor" , kHalf3_GrSLType) |
1883 | }; |
1884 | SkString lightBody; |
1885 | lightBody.appendf("\thalf colorScale = %s * dot(normal, surfaceToLight);\n" , kd); |
1886 | lightBody.appendf("\treturn half4(lightColor * saturate(colorScale), 1.0);\n" ); |
1887 | fragBuilder->emitFunction(kHalf4_GrSLType, |
1888 | "light" , |
1889 | SK_ARRAY_COUNT(gLightArgs), |
1890 | gLightArgs, |
1891 | lightBody.c_str(), |
1892 | funcName); |
1893 | } |
1894 | |
1895 | void GrGLDiffuseLightingEffect::onSetData(const GrGLSLProgramDataManager& pdman, |
1896 | const GrFragmentProcessor& proc) { |
1897 | INHERITED::onSetData(pdman, proc); |
1898 | const GrDiffuseLightingEffect& diffuse = proc.cast<GrDiffuseLightingEffect>(); |
1899 | pdman.set1f(fKDUni, diffuse.kd()); |
1900 | } |
1901 | |
1902 | /////////////////////////////////////////////////////////////////////////////// |
1903 | |
1904 | GrSpecularLightingEffect::GrSpecularLightingEffect(GrSurfaceProxyView view, |
1905 | sk_sp<const SkImageFilterLight> light, |
1906 | SkScalar surfaceScale, |
1907 | const SkMatrix& matrix, |
1908 | SkScalar ks, |
1909 | SkScalar shininess, |
1910 | BoundaryMode boundaryMode, |
1911 | const SkIRect* srcBounds) |
1912 | : INHERITED(kGrSpecularLightingEffect_ClassID, std::move(view), std::move(light), |
1913 | surfaceScale, matrix, boundaryMode, srcBounds) |
1914 | , fKS(ks) |
1915 | , fShininess(shininess) {} |
1916 | |
1917 | GrSpecularLightingEffect::GrSpecularLightingEffect(const GrSpecularLightingEffect& that) |
1918 | : INHERITED(that), fKS(that.fKS), fShininess(that.fShininess) {} |
1919 | |
1920 | bool GrSpecularLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const { |
1921 | const GrSpecularLightingEffect& s = sBase.cast<GrSpecularLightingEffect>(); |
1922 | return INHERITED::onIsEqual(sBase) && |
1923 | this->ks() == s.ks() && |
1924 | this->shininess() == s.shininess(); |
1925 | } |
1926 | |
1927 | void GrSpecularLightingEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, |
1928 | GrProcessorKeyBuilder* b) const { |
1929 | GrGLSpecularLightingEffect::GenKey(*this, caps, b); |
1930 | } |
1931 | |
1932 | GrGLSLFragmentProcessor* GrSpecularLightingEffect::onCreateGLSLInstance() const { |
1933 | return new GrGLSpecularLightingEffect; |
1934 | } |
1935 | |
1936 | GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrSpecularLightingEffect); |
1937 | |
1938 | #if GR_TEST_UTILS |
1939 | std::unique_ptr<GrFragmentProcessor> GrSpecularLightingEffect::TestCreate(GrProcessorTestData* d) { |
1940 | auto [view, ct, at] = d->randomView(); |
1941 | SkScalar surfaceScale = d->fRandom->nextSScalar1(); |
1942 | SkScalar ks = d->fRandom->nextUScalar1(); |
1943 | SkScalar shininess = d->fRandom->nextUScalar1(); |
1944 | sk_sp<SkImageFilterLight> light(create_random_light(d->fRandom)); |
1945 | SkMatrix matrix; |
1946 | for (int i = 0; i < 9; i++) { |
1947 | matrix[i] = d->fRandom->nextUScalar1(); |
1948 | } |
1949 | BoundaryMode mode = static_cast<BoundaryMode>(d->fRandom->nextU() % kBoundaryModeCount); |
1950 | |
1951 | uint32_t boundsX = d->fRandom->nextRangeU(0, view.width()); |
1952 | uint32_t boundsY = d->fRandom->nextRangeU(0, view.height()); |
1953 | uint32_t boundsW = d->fRandom->nextRangeU(0, view.width()); |
1954 | uint32_t boundsH = d->fRandom->nextRangeU(0, view.height()); |
1955 | SkIRect srcBounds = SkIRect::MakeXYWH(boundsX, boundsY, boundsW, boundsH); |
1956 | |
1957 | return GrSpecularLightingEffect::Make(std::move(view), std::move(light), surfaceScale, matrix, |
1958 | ks, shininess, mode, &srcBounds); |
1959 | } |
1960 | #endif |
1961 | |
1962 | /////////////////////////////////////////////////////////////////////////////// |
1963 | |
1964 | void GrGLSpecularLightingEffect::emitLightFunc(const GrFragmentProcessor* owner, |
1965 | GrGLSLUniformHandler* uniformHandler, |
1966 | GrGLSLFPFragmentBuilder* fragBuilder, |
1967 | SkString* funcName) { |
1968 | const char* ks; |
1969 | const char* shininess; |
1970 | |
1971 | fKSUni = uniformHandler->addUniform(owner, kFragment_GrShaderFlag, kHalf_GrSLType, "KS" , &ks); |
1972 | fShininessUni = uniformHandler->addUniform(owner, |
1973 | kFragment_GrShaderFlag, |
1974 | kHalf_GrSLType, |
1975 | "Shininess" , |
1976 | &shininess); |
1977 | |
1978 | const GrShaderVar gLightArgs[] = { |
1979 | GrShaderVar("normal" , kHalf3_GrSLType), |
1980 | GrShaderVar("surfaceToLight" , kHalf3_GrSLType), |
1981 | GrShaderVar("lightColor" , kHalf3_GrSLType) |
1982 | }; |
1983 | SkString lightBody; |
1984 | lightBody.appendf("\thalf3 halfDir = half3(normalize(surfaceToLight + half3(0, 0, 1)));\n" ); |
1985 | lightBody.appendf("\thalf colorScale = half(%s * pow(dot(normal, halfDir), %s));\n" , |
1986 | ks, shininess); |
1987 | lightBody.appendf("\thalf3 color = lightColor * saturate(colorScale);\n" ); |
1988 | lightBody.appendf("\treturn half4(color, max(max(color.r, color.g), color.b));\n" ); |
1989 | fragBuilder->emitFunction(kHalf4_GrSLType, |
1990 | "light" , |
1991 | SK_ARRAY_COUNT(gLightArgs), |
1992 | gLightArgs, |
1993 | lightBody.c_str(), |
1994 | funcName); |
1995 | } |
1996 | |
1997 | void GrGLSpecularLightingEffect::onSetData(const GrGLSLProgramDataManager& pdman, |
1998 | const GrFragmentProcessor& effect) { |
1999 | INHERITED::onSetData(pdman, effect); |
2000 | const GrSpecularLightingEffect& spec = effect.cast<GrSpecularLightingEffect>(); |
2001 | pdman.set1f(fKSUni, spec.ks()); |
2002 | pdman.set1f(fShininessUni, spec.shininess()); |
2003 | } |
2004 | |
2005 | /////////////////////////////////////////////////////////////////////////////// |
2006 | void GrGLLight::emitLightColorUniform(const GrFragmentProcessor* owner, |
2007 | GrGLSLUniformHandler* uniformHandler) { |
2008 | fColorUni = uniformHandler->addUniform(owner, kFragment_GrShaderFlag, kHalf3_GrSLType, |
2009 | "LightColor" ); |
2010 | } |
2011 | |
2012 | void GrGLLight::emitLightColor(const GrFragmentProcessor* owner, |
2013 | GrGLSLUniformHandler* uniformHandler, |
2014 | GrGLSLFPFragmentBuilder* fragBuilder, |
2015 | const char *surfaceToLight) { |
2016 | fragBuilder->codeAppend(uniformHandler->getUniformCStr(this->lightColorUni())); |
2017 | } |
2018 | |
2019 | void GrGLLight::setData(const GrGLSLProgramDataManager& pdman, |
2020 | const SkImageFilterLight* light) const { |
2021 | setUniformPoint3(pdman, fColorUni, |
2022 | light->color().makeScale(SkScalarInvert(SkIntToScalar(255)))); |
2023 | } |
2024 | |
2025 | /////////////////////////////////////////////////////////////////////////////// |
2026 | |
2027 | void GrGLDistantLight::setData(const GrGLSLProgramDataManager& pdman, |
2028 | const SkImageFilterLight* light) const { |
2029 | INHERITED::setData(pdman, light); |
2030 | SkASSERT(light->type() == SkImageFilterLight::kDistant_LightType); |
2031 | const SkDistantLight* distantLight = static_cast<const SkDistantLight*>(light); |
2032 | setUniformNormal3(pdman, fDirectionUni, distantLight->direction()); |
2033 | } |
2034 | |
2035 | void GrGLDistantLight::emitSurfaceToLight(const GrFragmentProcessor* owner, |
2036 | GrGLSLUniformHandler* uniformHandler, |
2037 | GrGLSLFPFragmentBuilder* fragBuilder, |
2038 | const char* z) { |
2039 | const char* dir; |
2040 | fDirectionUni = uniformHandler->addUniform(owner, kFragment_GrShaderFlag, kHalf3_GrSLType, |
2041 | "LightDirection" , &dir); |
2042 | fragBuilder->codeAppend(dir); |
2043 | } |
2044 | |
2045 | /////////////////////////////////////////////////////////////////////////////// |
2046 | |
2047 | void GrGLPointLight::setData(const GrGLSLProgramDataManager& pdman, |
2048 | const SkImageFilterLight* light) const { |
2049 | INHERITED::setData(pdman, light); |
2050 | SkASSERT(light->type() == SkImageFilterLight::kPoint_LightType); |
2051 | const SkPointLight* pointLight = static_cast<const SkPointLight*>(light); |
2052 | setUniformPoint3(pdman, fLocationUni, pointLight->location()); |
2053 | } |
2054 | |
2055 | void GrGLPointLight::emitSurfaceToLight(const GrFragmentProcessor* owner, |
2056 | GrGLSLUniformHandler* uniformHandler, |
2057 | GrGLSLFPFragmentBuilder* fragBuilder, |
2058 | const char* z) { |
2059 | const char* loc; |
2060 | fLocationUni = uniformHandler->addUniform(owner, kFragment_GrShaderFlag, kHalf3_GrSLType, |
2061 | "LightLocation" , &loc); |
2062 | fragBuilder->codeAppendf("normalize(%s - half3(sk_FragCoord.xy, %s))" , |
2063 | loc, z); |
2064 | } |
2065 | |
2066 | /////////////////////////////////////////////////////////////////////////////// |
2067 | |
2068 | void GrGLSpotLight::setData(const GrGLSLProgramDataManager& pdman, |
2069 | const SkImageFilterLight* light) const { |
2070 | INHERITED::setData(pdman, light); |
2071 | SkASSERT(light->type() == SkImageFilterLight::kSpot_LightType); |
2072 | const SkSpotLight* spotLight = static_cast<const SkSpotLight *>(light); |
2073 | setUniformPoint3(pdman, fLocationUni, spotLight->location()); |
2074 | pdman.set1f(fExponentUni, spotLight->specularExponent()); |
2075 | pdman.set1f(fCosInnerConeAngleUni, spotLight->cosInnerConeAngle()); |
2076 | pdman.set1f(fCosOuterConeAngleUni, spotLight->cosOuterConeAngle()); |
2077 | pdman.set1f(fConeScaleUni, spotLight->coneScale()); |
2078 | setUniformNormal3(pdman, fSUni, spotLight->s()); |
2079 | } |
2080 | |
2081 | void GrGLSpotLight::emitSurfaceToLight(const GrFragmentProcessor* owner, |
2082 | GrGLSLUniformHandler* uniformHandler, |
2083 | GrGLSLFPFragmentBuilder* fragBuilder, |
2084 | const char* z) { |
2085 | const char* location; |
2086 | fLocationUni = uniformHandler->addUniform(owner, kFragment_GrShaderFlag, kHalf3_GrSLType, |
2087 | "LightLocation" , &location); |
2088 | |
2089 | fragBuilder->codeAppendf("normalize(%s - half3(sk_FragCoord.xy, %s))" , |
2090 | location, z); |
2091 | } |
2092 | |
2093 | void GrGLSpotLight::emitLightColor(const GrFragmentProcessor* owner, |
2094 | GrGLSLUniformHandler* uniformHandler, |
2095 | GrGLSLFPFragmentBuilder* fragBuilder, |
2096 | const char *surfaceToLight) { |
2097 | |
2098 | const char* color = uniformHandler->getUniformCStr(this->lightColorUni()); // created by parent class. |
2099 | |
2100 | const char* exponent; |
2101 | const char* cosInner; |
2102 | const char* cosOuter; |
2103 | const char* coneScale; |
2104 | const char* s; |
2105 | fExponentUni = uniformHandler->addUniform(owner, kFragment_GrShaderFlag, kHalf_GrSLType, |
2106 | "Exponent" , &exponent); |
2107 | fCosInnerConeAngleUni = uniformHandler->addUniform(owner, kFragment_GrShaderFlag, |
2108 | kHalf_GrSLType, "CosInnerConeAngle" , |
2109 | &cosInner); |
2110 | fCosOuterConeAngleUni = uniformHandler->addUniform(owner, kFragment_GrShaderFlag, |
2111 | kHalf_GrSLType, "CosOuterConeAngle" , |
2112 | &cosOuter); |
2113 | fConeScaleUni = uniformHandler->addUniform(owner, kFragment_GrShaderFlag, kHalf_GrSLType, |
2114 | "ConeScale" , &coneScale); |
2115 | fSUni = uniformHandler->addUniform(owner, kFragment_GrShaderFlag, kHalf3_GrSLType, "S" , &s); |
2116 | |
2117 | const GrShaderVar gLightColorArgs[] = { |
2118 | GrShaderVar("surfaceToLight" , kHalf3_GrSLType) |
2119 | }; |
2120 | SkString lightColorBody; |
2121 | lightColorBody.appendf("\thalf cosAngle = -dot(surfaceToLight, %s);\n" , s); |
2122 | lightColorBody.appendf("\tif (cosAngle < %s) {\n" , cosOuter); |
2123 | lightColorBody.appendf("\t\treturn half3(0);\n" ); |
2124 | lightColorBody.appendf("\t}\n" ); |
2125 | lightColorBody.appendf("\thalf scale = pow(cosAngle, %s);\n" , exponent); |
2126 | lightColorBody.appendf("\tif (cosAngle < %s) {\n" , cosInner); |
2127 | lightColorBody.appendf("\t\treturn %s * scale * (cosAngle - %s) * %s;\n" , |
2128 | color, cosOuter, coneScale); |
2129 | lightColorBody.appendf("\t}\n" ); |
2130 | lightColorBody.appendf("\treturn %s;\n" , color); |
2131 | fragBuilder->emitFunction(kHalf3_GrSLType, |
2132 | "lightColor" , |
2133 | SK_ARRAY_COUNT(gLightColorArgs), |
2134 | gLightColorArgs, |
2135 | lightColorBody.c_str(), |
2136 | &fLightColorFunc); |
2137 | |
2138 | fragBuilder->codeAppendf("%s(%s)" , fLightColorFunc.c_str(), surfaceToLight); |
2139 | } |
2140 | |
2141 | #endif |
2142 | |
2143 | void SkLightingImageFilter::RegisterFlattenables() { |
2144 | SK_REGISTER_FLATTENABLE(SkDiffuseLightingImageFilter); |
2145 | SK_REGISTER_FLATTENABLE(SkSpecularLightingImageFilter); |
2146 | } |
2147 | |