2 * Copyright 2012 The Android Open Source Project
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
8 #include "SkLightingImageFilter.h"
10 #include "SkColorPriv.h"
11 #include "SkReadBuffer.h"
12 #include "SkWriteBuffer.h"
13 #include "SkReadBuffer.h"
14 #include "SkWriteBuffer.h"
18 #include "effects/GrSingleTextureEffect.h"
19 #include "gl/GrGLProcessor.h"
20 #include "gl/builders/GrGLProgramBuilder.h"
21 #include "GrFragmentProcessor.h"
22 #include "GrTBackendProcessorFactory.h"
24 class GrGLDiffuseLightingEffect;
25 class GrGLSpecularLightingEffect;
28 typedef GrGLProgramDataManager::UniformHandle UniformHandle;
33 const SkScalar gOneThird = SkScalarInvert(SkIntToScalar(3));
34 const SkScalar gTwoThirds = SkScalarDiv(SkIntToScalar(2), SkIntToScalar(3));
35 const SkScalar gOneHalf = 0.5f;
36 const SkScalar gOneQuarter = 0.25f;
39 void setUniformPoint3(const GrGLProgramDataManager& pdman, UniformHandle uni,
40 const SkPoint3& point) {
41 GR_STATIC_ASSERT(sizeof(SkPoint3) == 3 * sizeof(GrGLfloat));
42 pdman.set3fv(uni, 1, &point.fX);
45 void setUniformNormal3(const GrGLProgramDataManager& pdman, UniformHandle uni,
46 const SkPoint3& point) {
47 setUniformPoint3(pdman, uni, SkPoint3(point.fX, point.fY, point.fZ));
51 // Shift matrix components to the left, as we advance pixels to the right.
52 inline void shiftMatrixLeft(int m[9]) {
61 class DiffuseLightingType {
63 DiffuseLightingType(SkScalar kd)
65 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight,
66 const SkPoint3& lightColor) const {
67 SkScalar colorScale = SkScalarMul(fKD, normal.dot(surfaceTolight));
68 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
69 SkPoint3 color(lightColor * colorScale);
70 return SkPackARGB32(255,
71 SkClampMax(SkScalarRoundToInt(color.fX), 255),
72 SkClampMax(SkScalarRoundToInt(color.fY), 255),
73 SkClampMax(SkScalarRoundToInt(color.fZ), 255));
79 class SpecularLightingType {
81 SpecularLightingType(SkScalar ks, SkScalar shininess)
82 : fKS(ks), fShininess(shininess) {}
83 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight,
84 const SkPoint3& lightColor) const {
85 SkPoint3 halfDir(surfaceTolight);
86 halfDir.fZ += SK_Scalar1; // eye position is always (0, 0, 1)
88 SkScalar colorScale = SkScalarMul(fKS,
89 SkScalarPow(normal.dot(halfDir), fShininess));
90 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
91 SkPoint3 color(lightColor * colorScale);
92 return SkPackARGB32(SkClampMax(SkScalarRoundToInt(color.maxComponent()), 255),
93 SkClampMax(SkScalarRoundToInt(color.fX), 255),
94 SkClampMax(SkScalarRoundToInt(color.fY), 255),
95 SkClampMax(SkScalarRoundToInt(color.fZ), 255));
102 inline SkScalar sobel(int a, int b, int c, int d, int e, int f, SkScalar scale) {
103 return SkScalarMul(SkIntToScalar(-a + b - 2 * c + 2 * d -e + f), scale);
106 inline SkPoint3 pointToNormal(SkScalar x, SkScalar y, SkScalar surfaceScale) {
107 SkPoint3 vector(SkScalarMul(-x, surfaceScale),
108 SkScalarMul(-y, surfaceScale),
114 inline SkPoint3 topLeftNormal(int m[9], SkScalar surfaceScale) {
115 return pointToNormal(sobel(0, 0, m[4], m[5], m[7], m[8], gTwoThirds),
116 sobel(0, 0, m[4], m[7], m[5], m[8], gTwoThirds),
120 inline SkPoint3 topNormal(int m[9], SkScalar surfaceScale) {
121 return pointToNormal(sobel( 0, 0, m[3], m[5], m[6], m[8], gOneThird),
122 sobel(m[3], m[6], m[4], m[7], m[5], m[8], gOneHalf),
126 inline SkPoint3 topRightNormal(int m[9], SkScalar surfaceScale) {
127 return pointToNormal(sobel( 0, 0, m[3], m[4], m[6], m[7], gTwoThirds),
128 sobel(m[3], m[6], m[4], m[7], 0, 0, gTwoThirds),
132 inline SkPoint3 leftNormal(int m[9], SkScalar surfaceScale) {
133 return pointToNormal(sobel(m[1], m[2], m[4], m[5], m[7], m[8], gOneHalf),
134 sobel( 0, 0, m[1], m[7], m[2], m[8], gOneThird),
139 inline SkPoint3 interiorNormal(int m[9], SkScalar surfaceScale) {
140 return pointToNormal(sobel(m[0], m[2], m[3], m[5], m[6], m[8], gOneQuarter),
141 sobel(m[0], m[6], m[1], m[7], m[2], m[8], gOneQuarter),
145 inline SkPoint3 rightNormal(int m[9], SkScalar surfaceScale) {
146 return pointToNormal(sobel(m[0], m[1], m[3], m[4], m[6], m[7], gOneHalf),
147 sobel(m[0], m[6], m[1], m[7], 0, 0, gOneThird),
151 inline SkPoint3 bottomLeftNormal(int m[9], SkScalar surfaceScale) {
152 return pointToNormal(sobel(m[1], m[2], m[4], m[5], 0, 0, gTwoThirds),
153 sobel( 0, 0, m[1], m[4], m[2], m[5], gTwoThirds),
157 inline SkPoint3 bottomNormal(int m[9], SkScalar surfaceScale) {
158 return pointToNormal(sobel(m[0], m[2], m[3], m[5], 0, 0, gOneThird),
159 sobel(m[0], m[3], m[1], m[4], m[2], m[5], gOneHalf),
163 inline SkPoint3 bottomRightNormal(int m[9], SkScalar surfaceScale) {
164 return pointToNormal(sobel(m[0], m[1], m[3], m[4], 0, 0, gTwoThirds),
165 sobel(m[0], m[3], m[1], m[4], 0, 0, gTwoThirds),
169 template <class LightingType, class LightType> void lightBitmap(
170 const LightingType& lightingType, const SkLight* light, const SkBitmap& src, SkBitmap* dst,
171 SkScalar surfaceScale, const SkIRect& bounds) {
172 SkASSERT(dst->width() == bounds.width() && dst->height() == bounds.height());
173 const LightType* l = static_cast<const LightType*>(light);
174 int left = bounds.left(), right = bounds.right();
175 int bottom = bounds.bottom();
176 int y = bounds.top();
177 SkPMColor* dptr = dst->getAddr32(0, 0);
180 const SkPMColor* row1 = src.getAddr32(x, y);
181 const SkPMColor* row2 = src.getAddr32(x, y + 1);
183 m[4] = SkGetPackedA32(*row1++);
184 m[5] = SkGetPackedA32(*row1++);
185 m[7] = SkGetPackedA32(*row2++);
186 m[8] = SkGetPackedA32(*row2++);
187 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
188 *dptr++ = lightingType.light(topLeftNormal(m, surfaceScale), surfaceToLight,
189 l->lightColor(surfaceToLight));
190 for (++x; x < right - 1; ++x)
193 m[5] = SkGetPackedA32(*row1++);
194 m[8] = SkGetPackedA32(*row2++);
195 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
196 *dptr++ = lightingType.light(topNormal(m, surfaceScale), surfaceToLight,
197 l->lightColor(surfaceToLight));
200 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
201 *dptr++ = lightingType.light(topRightNormal(m, surfaceScale), surfaceToLight,
202 l->lightColor(surfaceToLight));
205 for (++y; y < bottom - 1; ++y) {
207 const SkPMColor* row0 = src.getAddr32(x, y - 1);
208 const SkPMColor* row1 = src.getAddr32(x, y);
209 const SkPMColor* row2 = src.getAddr32(x, y + 1);
211 m[1] = SkGetPackedA32(*row0++);
212 m[2] = SkGetPackedA32(*row0++);
213 m[4] = SkGetPackedA32(*row1++);
214 m[5] = SkGetPackedA32(*row1++);
215 m[7] = SkGetPackedA32(*row2++);
216 m[8] = SkGetPackedA32(*row2++);
217 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
218 *dptr++ = lightingType.light(leftNormal(m, surfaceScale), surfaceToLight,
219 l->lightColor(surfaceToLight));
220 for (++x; x < right - 1; ++x) {
222 m[2] = SkGetPackedA32(*row0++);
223 m[5] = SkGetPackedA32(*row1++);
224 m[8] = SkGetPackedA32(*row2++);
225 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
226 *dptr++ = lightingType.light(interiorNormal(m, surfaceScale), surfaceToLight,
227 l->lightColor(surfaceToLight));
230 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
231 *dptr++ = lightingType.light(rightNormal(m, surfaceScale), surfaceToLight,
232 l->lightColor(surfaceToLight));
237 const SkPMColor* row0 = src.getAddr32(x, bottom - 2);
238 const SkPMColor* row1 = src.getAddr32(x, bottom - 1);
240 m[1] = SkGetPackedA32(*row0++);
241 m[2] = SkGetPackedA32(*row0++);
242 m[4] = SkGetPackedA32(*row1++);
243 m[5] = SkGetPackedA32(*row1++);
244 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
245 *dptr++ = lightingType.light(bottomLeftNormal(m, surfaceScale), surfaceToLight,
246 l->lightColor(surfaceToLight));
247 for (++x; x < right - 1; ++x)
250 m[2] = SkGetPackedA32(*row0++);
251 m[5] = SkGetPackedA32(*row1++);
252 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
253 *dptr++ = lightingType.light(bottomNormal(m, surfaceScale), surfaceToLight,
254 l->lightColor(surfaceToLight));
257 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
258 *dptr++ = lightingType.light(bottomRightNormal(m, surfaceScale), surfaceToLight,
259 l->lightColor(surfaceToLight));
263 SkPoint3 readPoint3(SkReadBuffer& buffer) {
265 point.fX = buffer.readScalar();
266 point.fY = buffer.readScalar();
267 point.fZ = buffer.readScalar();
268 buffer.validate(SkScalarIsFinite(point.fX) &&
269 SkScalarIsFinite(point.fY) &&
270 SkScalarIsFinite(point.fZ));
274 void writePoint3(const SkPoint3& point, SkWriteBuffer& buffer) {
275 buffer.writeScalar(point.fX);
276 buffer.writeScalar(point.fY);
277 buffer.writeScalar(point.fZ);
280 class SkDiffuseLightingImageFilter : public SkLightingImageFilter {
282 static SkImageFilter* Create(SkLight* light, SkScalar surfaceScale, SkScalar kd, SkImageFilter*,
283 const CropRect*, uint32_t uniqueID = 0);
285 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDiffuseLightingImageFilter)
286 SkScalar kd() const { return fKD; }
289 SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale,
290 SkScalar kd, SkImageFilter* input, const CropRect* cropRect,
292 #ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING
293 explicit SkDiffuseLightingImageFilter(SkReadBuffer& buffer);
295 virtual void flatten(SkWriteBuffer& buffer) const SK_OVERRIDE;
296 virtual bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
297 SkBitmap* result, SkIPoint* offset) const SK_OVERRIDE;
299 virtual bool asFragmentProcessor(GrFragmentProcessor**, GrTexture*, const SkMatrix&,
300 const SkIRect& bounds) const SK_OVERRIDE;
304 friend class SkLightingImageFilter;
305 typedef SkLightingImageFilter INHERITED;
309 class SkSpecularLightingImageFilter : public SkLightingImageFilter {
311 static SkImageFilter* Create(SkLight* light, SkScalar surfaceScale,
312 SkScalar ks, SkScalar shininess, SkImageFilter*, const CropRect*,
313 uint32_t uniqueID = 0);
315 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpecularLightingImageFilter)
317 SkScalar ks() const { return fKS; }
318 SkScalar shininess() const { return fShininess; }
321 SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks,
322 SkScalar shininess, SkImageFilter* input, const CropRect*,
324 #ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING
325 explicit SkSpecularLightingImageFilter(SkReadBuffer& buffer);
327 virtual void flatten(SkWriteBuffer& buffer) const SK_OVERRIDE;
328 virtual bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
329 SkBitmap* result, SkIPoint* offset) const SK_OVERRIDE;
331 virtual bool asFragmentProcessor(GrFragmentProcessor**, GrTexture*, const SkMatrix&,
332 const SkIRect& bounds) const SK_OVERRIDE;
338 friend class SkLightingImageFilter;
339 typedef SkLightingImageFilter INHERITED;
344 class GrLightingEffect : public GrSingleTextureEffect {
346 GrLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale, const SkMatrix& matrix);
347 virtual ~GrLightingEffect();
349 const SkLight* light() const { return fLight; }
350 SkScalar surfaceScale() const { return fSurfaceScale; }
351 const SkMatrix& filterMatrix() const { return fFilterMatrix; }
354 virtual bool onIsEqual(const GrFragmentProcessor&) const SK_OVERRIDE;
356 virtual void onComputeInvariantOutput(InvariantOutput* inout) const SK_OVERRIDE {
357 // lighting shaders are complicated. We just throw up our hands.
358 inout->mulByUnknownColor();
362 typedef GrSingleTextureEffect INHERITED;
363 const SkLight* fLight;
364 SkScalar fSurfaceScale;
365 SkMatrix fFilterMatrix;
368 class GrDiffuseLightingEffect : public GrLightingEffect {
370 static GrFragmentProcessor* Create(GrTexture* texture,
371 const SkLight* light,
372 SkScalar surfaceScale,
373 const SkMatrix& matrix,
375 return SkNEW_ARGS(GrDiffuseLightingEffect, (texture,
382 static const char* Name() { return "DiffuseLighting"; }
384 typedef GrGLDiffuseLightingEffect GLProcessor;
386 virtual const GrBackendFragmentProcessorFactory& getFactory() const SK_OVERRIDE;
387 SkScalar kd() const { return fKD; }
390 virtual bool onIsEqual(const GrFragmentProcessor&) const SK_OVERRIDE;
392 GrDiffuseLightingEffect(GrTexture* texture,
393 const SkLight* light,
394 SkScalar surfaceScale,
395 const SkMatrix& matrix,
398 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
399 typedef GrLightingEffect INHERITED;
403 class GrSpecularLightingEffect : public GrLightingEffect {
405 static GrFragmentProcessor* Create(GrTexture* texture,
406 const SkLight* light,
407 SkScalar surfaceScale,
408 const SkMatrix& matrix,
410 SkScalar shininess) {
411 return SkNEW_ARGS(GrSpecularLightingEffect, (texture,
418 static const char* Name() { return "SpecularLighting"; }
420 typedef GrGLSpecularLightingEffect GLProcessor;
422 virtual const GrBackendFragmentProcessorFactory& getFactory() const SK_OVERRIDE;
423 SkScalar ks() const { return fKS; }
424 SkScalar shininess() const { return fShininess; }
427 virtual bool onIsEqual(const GrFragmentProcessor&) const SK_OVERRIDE;
429 GrSpecularLightingEffect(GrTexture* texture,
430 const SkLight* light,
431 SkScalar surfaceScale,
432 const SkMatrix& matrix,
436 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
437 typedef GrLightingEffect INHERITED;
442 ///////////////////////////////////////////////////////////////////////////////
446 virtual ~GrGLLight() {}
449 * This is called by GrGLLightingEffect::emitCode() before either of the two virtual functions
450 * below. It adds a vec3f uniform visible in the FS that represents the constant light color.
452 void emitLightColorUniform(GrGLFPBuilder*);
455 * These two functions are called from GrGLLightingEffect's emitCode() function.
456 * emitSurfaceToLight places an expression in param out that is the vector from the surface to
457 * the light. The expression will be used in the FS. emitLightColor writes an expression into
458 * the FS that is the color of the light. Either function may add functions and/or uniforms to
459 * the FS. The default of emitLightColor appends the name of the constant light color uniform
460 * and so this function only needs to be overridden if the light color varies spatially.
462 virtual void emitSurfaceToLight(GrGLFPBuilder*, const char* z) = 0;
463 virtual void emitLightColor(GrGLFPBuilder*, const char *surfaceToLight);
465 // This is called from GrGLLightingEffect's setData(). Subclasses of GrGLLight must call
466 // INHERITED::setData().
467 virtual void setData(const GrGLProgramDataManager&,
468 const SkLight* light) const;
472 * Gets the constant light color uniform. Subclasses can use this in their emitLightColor
475 UniformHandle lightColorUni() const { return fColorUni; }
478 UniformHandle fColorUni;
480 typedef SkRefCnt INHERITED;
483 ///////////////////////////////////////////////////////////////////////////////
485 class GrGLDistantLight : public GrGLLight {
487 virtual ~GrGLDistantLight() {}
488 virtual void setData(const GrGLProgramDataManager&,
489 const SkLight* light) const SK_OVERRIDE;
490 virtual void emitSurfaceToLight(GrGLFPBuilder*, const char* z) SK_OVERRIDE;
493 typedef GrGLLight INHERITED;
494 UniformHandle fDirectionUni;
497 ///////////////////////////////////////////////////////////////////////////////
499 class GrGLPointLight : public GrGLLight {
501 virtual ~GrGLPointLight() {}
502 virtual void setData(const GrGLProgramDataManager&,
503 const SkLight* light) const SK_OVERRIDE;
504 virtual void emitSurfaceToLight(GrGLFPBuilder*, const char* z) SK_OVERRIDE;
507 typedef GrGLLight INHERITED;
508 UniformHandle fLocationUni;
511 ///////////////////////////////////////////////////////////////////////////////
513 class GrGLSpotLight : public GrGLLight {
515 virtual ~GrGLSpotLight() {}
516 virtual void setData(const GrGLProgramDataManager&,
517 const SkLight* light) const SK_OVERRIDE;
518 virtual void emitSurfaceToLight(GrGLFPBuilder*, const char* z) SK_OVERRIDE;
519 virtual void emitLightColor(GrGLFPBuilder*, const char *surfaceToLight) SK_OVERRIDE;
522 typedef GrGLLight INHERITED;
524 SkString fLightColorFunc;
525 UniformHandle fLocationUni;
526 UniformHandle fExponentUni;
527 UniformHandle fCosOuterConeAngleUni;
528 UniformHandle fCosInnerConeAngleUni;
529 UniformHandle fConeScaleUni;
540 ///////////////////////////////////////////////////////////////////////////////
542 class SkLight : public SkRefCnt {
544 SK_DECLARE_INST_COUNT(SkLight)
551 virtual LightType type() const = 0;
552 const SkPoint3& color() const { return fColor; }
553 virtual GrGLLight* createGLLight() const = 0;
554 virtual bool isEqual(const SkLight& other) const {
555 return fColor == other.fColor;
557 // Called to know whether the generated GrGLLight will require access to the fragment position.
558 virtual bool requiresFragmentPosition() const = 0;
559 virtual SkLight* transform(const SkMatrix& matrix) const = 0;
561 // Defined below SkLight's subclasses.
562 void flattenLight(SkWriteBuffer& buffer) const;
563 static SkLight* UnflattenLight(SkReadBuffer& buffer);
566 SkLight(SkColor color)
567 : fColor(SkIntToScalar(SkColorGetR(color)),
568 SkIntToScalar(SkColorGetG(color)),
569 SkIntToScalar(SkColorGetB(color))) {}
570 SkLight(const SkPoint3& color)
572 SkLight(SkReadBuffer& buffer) {
573 fColor = readPoint3(buffer);
576 virtual void onFlattenLight(SkWriteBuffer& buffer) const = 0;
580 typedef SkRefCnt INHERITED;
584 ///////////////////////////////////////////////////////////////////////////////
586 class SkDistantLight : public SkLight {
588 SkDistantLight(const SkPoint3& direction, SkColor color)
589 : INHERITED(color), fDirection(direction) {
592 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
595 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
596 virtual LightType type() const { return kDistant_LightType; }
597 const SkPoint3& direction() const { return fDirection; }
598 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
600 return SkNEW(GrGLDistantLight);
602 SkDEBUGFAIL("Should not call in GPU-less build");
606 virtual bool requiresFragmentPosition() const SK_OVERRIDE { return false; }
608 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
609 if (other.type() != kDistant_LightType) {
613 const SkDistantLight& o = static_cast<const SkDistantLight&>(other);
614 return INHERITED::isEqual(other) &&
615 fDirection == o.fDirection;
618 SkDistantLight(SkReadBuffer& buffer) : INHERITED(buffer) {
619 fDirection = readPoint3(buffer);
623 SkDistantLight(const SkPoint3& direction, const SkPoint3& color)
624 : INHERITED(color), fDirection(direction) {
626 virtual SkLight* transform(const SkMatrix& matrix) const {
627 return new SkDistantLight(direction(), color());
629 virtual void onFlattenLight(SkWriteBuffer& buffer) const SK_OVERRIDE {
630 writePoint3(fDirection, buffer);
634 typedef SkLight INHERITED;
638 ///////////////////////////////////////////////////////////////////////////////
640 class SkPointLight : public SkLight {
642 SkPointLight(const SkPoint3& location, SkColor color)
643 : INHERITED(color), fLocation(location) {}
645 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
646 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
647 fLocation.fY - SkIntToScalar(y),
648 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
649 direction.normalize();
652 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
653 virtual LightType type() const { return kPoint_LightType; }
654 const SkPoint3& location() const { return fLocation; }
655 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
657 return SkNEW(GrGLPointLight);
659 SkDEBUGFAIL("Should not call in GPU-less build");
663 virtual bool requiresFragmentPosition() const SK_OVERRIDE { return true; }
664 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
665 if (other.type() != kPoint_LightType) {
668 const SkPointLight& o = static_cast<const SkPointLight&>(other);
669 return INHERITED::isEqual(other) &&
670 fLocation == o.fLocation;
672 virtual SkLight* transform(const SkMatrix& matrix) const {
673 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
674 matrix.mapPoints(&location2, 1);
675 // Use X scale and Y scale on Z and average the result
676 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
677 matrix.mapVectors(&locationZ, 1);
678 SkPoint3 location(location2.fX, location2.fY, SkScalarAve(locationZ.fX, locationZ.fY));
679 return new SkPointLight(location, color());
682 SkPointLight(SkReadBuffer& buffer) : INHERITED(buffer) {
683 fLocation = readPoint3(buffer);
687 SkPointLight(const SkPoint3& location, const SkPoint3& color)
688 : INHERITED(color), fLocation(location) {}
689 virtual void onFlattenLight(SkWriteBuffer& buffer) const SK_OVERRIDE {
690 writePoint3(fLocation, buffer);
694 typedef SkLight INHERITED;
698 ///////////////////////////////////////////////////////////////////////////////
700 class SkSpotLight : public SkLight {
702 SkSpotLight(const SkPoint3& location, const SkPoint3& target, SkScalar specularExponent, SkScalar cutoffAngle, SkColor color)
706 fSpecularExponent(SkScalarPin(specularExponent, kSpecularExponentMin, kSpecularExponentMax))
708 fS = target - location;
710 fCosOuterConeAngle = SkScalarCos(SkDegreesToRadians(cutoffAngle));
711 const SkScalar antiAliasThreshold = 0.016f;
712 fCosInnerConeAngle = fCosOuterConeAngle + antiAliasThreshold;
713 fConeScale = SkScalarInvert(antiAliasThreshold);
716 virtual SkLight* transform(const SkMatrix& matrix) const {
717 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
718 matrix.mapPoints(&location2, 1);
719 // Use X scale and Y scale on Z and average the result
720 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
721 matrix.mapVectors(&locationZ, 1);
722 SkPoint3 location(location2.fX, location2.fY, SkScalarAve(locationZ.fX, locationZ.fY));
723 SkPoint target2 = SkPoint::Make(fTarget.fX, fTarget.fY);
724 matrix.mapPoints(&target2, 1);
725 SkPoint targetZ = SkPoint::Make(fTarget.fZ, fTarget.fZ);
726 matrix.mapVectors(&targetZ, 1);
727 SkPoint3 target(target2.fX, target2.fY, SkScalarAve(targetZ.fX, targetZ.fY));
728 SkPoint3 s = target - location;
730 return new SkSpotLight(location, target, fSpecularExponent, fCosOuterConeAngle, fCosInnerConeAngle, fConeScale, s, color());
733 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
734 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
735 fLocation.fY - SkIntToScalar(y),
736 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
737 direction.normalize();
740 SkPoint3 lightColor(const SkPoint3& surfaceToLight) const {
741 SkScalar cosAngle = -surfaceToLight.dot(fS);
742 if (cosAngle < fCosOuterConeAngle) {
743 return SkPoint3(0, 0, 0);
745 SkScalar scale = SkScalarPow(cosAngle, fSpecularExponent);
746 if (cosAngle < fCosInnerConeAngle) {
747 scale = SkScalarMul(scale, cosAngle - fCosOuterConeAngle);
748 return color() * SkScalarMul(scale, fConeScale);
750 return color() * scale;
752 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
754 return SkNEW(GrGLSpotLight);
756 SkDEBUGFAIL("Should not call in GPU-less build");
760 virtual bool requiresFragmentPosition() const SK_OVERRIDE { return true; }
761 virtual LightType type() const { return kSpot_LightType; }
762 const SkPoint3& location() const { return fLocation; }
763 const SkPoint3& target() const { return fTarget; }
764 SkScalar specularExponent() const { return fSpecularExponent; }
765 SkScalar cosInnerConeAngle() const { return fCosInnerConeAngle; }
766 SkScalar cosOuterConeAngle() const { return fCosOuterConeAngle; }
767 SkScalar coneScale() const { return fConeScale; }
768 const SkPoint3& s() const { return fS; }
770 SkSpotLight(SkReadBuffer& buffer) : INHERITED(buffer) {
771 fLocation = readPoint3(buffer);
772 fTarget = readPoint3(buffer);
773 fSpecularExponent = buffer.readScalar();
774 fCosOuterConeAngle = buffer.readScalar();
775 fCosInnerConeAngle = buffer.readScalar();
776 fConeScale = buffer.readScalar();
777 fS = readPoint3(buffer);
778 buffer.validate(SkScalarIsFinite(fSpecularExponent) &&
779 SkScalarIsFinite(fCosOuterConeAngle) &&
780 SkScalarIsFinite(fCosInnerConeAngle) &&
781 SkScalarIsFinite(fConeScale));
784 SkSpotLight(const SkPoint3& location, const SkPoint3& target, SkScalar specularExponent, SkScalar cosOuterConeAngle, SkScalar cosInnerConeAngle, SkScalar coneScale, const SkPoint3& s, const SkPoint3& color)
788 fSpecularExponent(specularExponent),
789 fCosOuterConeAngle(cosOuterConeAngle),
790 fCosInnerConeAngle(cosInnerConeAngle),
791 fConeScale(coneScale),
795 virtual void onFlattenLight(SkWriteBuffer& buffer) const SK_OVERRIDE {
796 writePoint3(fLocation, buffer);
797 writePoint3(fTarget, buffer);
798 buffer.writeScalar(fSpecularExponent);
799 buffer.writeScalar(fCosOuterConeAngle);
800 buffer.writeScalar(fCosInnerConeAngle);
801 buffer.writeScalar(fConeScale);
802 writePoint3(fS, buffer);
805 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
806 if (other.type() != kSpot_LightType) {
810 const SkSpotLight& o = static_cast<const SkSpotLight&>(other);
811 return INHERITED::isEqual(other) &&
812 fLocation == o.fLocation &&
813 fTarget == o.fTarget &&
814 fSpecularExponent == o.fSpecularExponent &&
815 fCosOuterConeAngle == o.fCosOuterConeAngle;
819 static const SkScalar kSpecularExponentMin;
820 static const SkScalar kSpecularExponentMax;
822 typedef SkLight INHERITED;
825 SkScalar fSpecularExponent;
826 SkScalar fCosOuterConeAngle;
827 SkScalar fCosInnerConeAngle;
832 // According to the spec, the specular term should be in the range [1, 128] :
833 // http://www.w3.org/TR/SVG/filters.html#feSpecularLightingSpecularExponentAttribute
834 const SkScalar SkSpotLight::kSpecularExponentMin = 1.0f;
835 const SkScalar SkSpotLight::kSpecularExponentMax = 128.0f;
837 ///////////////////////////////////////////////////////////////////////////////
839 void SkLight::flattenLight(SkWriteBuffer& buffer) const {
840 // Write type first, then baseclass, then subclass.
841 buffer.writeInt(this->type());
842 writePoint3(fColor, buffer);
843 this->onFlattenLight(buffer);
846 /*static*/ SkLight* SkLight::UnflattenLight(SkReadBuffer& buffer) {
848 const SkLight::LightType type = (SkLight::LightType)buffer.readInt();
850 // Each of these constructors must first call SkLight's, so we'll read the baseclass
851 // then subclass, same order as flattenLight.
852 case SkLight::kDistant_LightType: return SkNEW_ARGS(SkDistantLight, (buffer));
853 case SkLight::kPoint_LightType: return SkNEW_ARGS(SkPointLight, (buffer));
854 case SkLight::kSpot_LightType: return SkNEW_ARGS(SkSpotLight, (buffer));
856 SkDEBUGFAIL("Unknown LightType.");
857 buffer.validate(false);
861 ///////////////////////////////////////////////////////////////////////////////
863 SkLightingImageFilter::SkLightingImageFilter(SkLight* light, SkScalar surfaceScale,
864 SkImageFilter* input, const CropRect* cropRect,
866 : INHERITED(1, &input, cropRect, uniqueID)
867 , fLight(SkRef(light))
868 , fSurfaceScale(surfaceScale / 255)
871 SkImageFilter* SkLightingImageFilter::CreateDistantLitDiffuse(const SkPoint3& direction,
873 SkScalar surfaceScale,
875 SkImageFilter* input,
876 const CropRect* cropRect) {
877 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkDistantLight, (direction, lightColor)));
878 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
881 SkImageFilter* SkLightingImageFilter::CreatePointLitDiffuse(const SkPoint3& location,
883 SkScalar surfaceScale,
885 SkImageFilter* input,
886 const CropRect* cropRect) {
887 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkPointLight, (location, lightColor)));
888 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
891 SkImageFilter* SkLightingImageFilter::CreateSpotLitDiffuse(const SkPoint3& location,
892 const SkPoint3& target,
893 SkScalar specularExponent,
894 SkScalar cutoffAngle,
896 SkScalar surfaceScale,
898 SkImageFilter* input,
899 const CropRect* cropRect) {
900 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkSpotLight, (location, target, specularExponent,
901 cutoffAngle, lightColor)));
902 return SkDiffuseLightingImageFilter::Create(light, surfaceScale, kd, input, cropRect);
905 SkImageFilter* SkLightingImageFilter::CreateDistantLitSpecular(const SkPoint3& direction,
907 SkScalar surfaceScale,
910 SkImageFilter* input,
911 const CropRect* cropRect) {
912 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkDistantLight, (direction, lightColor)));
913 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
916 SkImageFilter* SkLightingImageFilter::CreatePointLitSpecular(const SkPoint3& location,
918 SkScalar surfaceScale,
921 SkImageFilter* input,
922 const CropRect* cropRect) {
923 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkPointLight, (location, lightColor)));
924 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
927 SkImageFilter* SkLightingImageFilter::CreateSpotLitSpecular(const SkPoint3& location,
928 const SkPoint3& target,
929 SkScalar specularExponent,
930 SkScalar cutoffAngle,
932 SkScalar surfaceScale,
935 SkImageFilter* input,
936 const CropRect* cropRect) {
937 SkAutoTUnref<SkLight> light(SkNEW_ARGS(SkSpotLight, (location, target, specularExponent,
938 cutoffAngle, lightColor)));
939 return SkSpecularLightingImageFilter::Create(light, surfaceScale, ks, shine, input, cropRect);
942 SkLightingImageFilter::~SkLightingImageFilter() {}
944 #ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING
945 SkLightingImageFilter::SkLightingImageFilter(SkReadBuffer& buffer)
946 : INHERITED(1, buffer) {
947 fLight.reset(SkLight::UnflattenLight(buffer));
948 fSurfaceScale = buffer.readScalar();
949 buffer.validate(SkScalarIsFinite(fSurfaceScale));
953 void SkLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
954 this->INHERITED::flatten(buffer);
955 fLight->flattenLight(buffer);
956 buffer.writeScalar(fSurfaceScale * 255);
959 ///////////////////////////////////////////////////////////////////////////////
961 SkImageFilter* SkDiffuseLightingImageFilter::Create(SkLight* light, SkScalar surfaceScale,
962 SkScalar kd, SkImageFilter* input, const CropRect* cropRect, uint32_t uniqueID) {
966 if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(kd)) {
969 // According to the spec, kd can be any non-negative number :
970 // http://www.w3.org/TR/SVG/filters.html#feDiffuseLightingElement
974 return SkNEW_ARGS(SkDiffuseLightingImageFilter, (light, surfaceScale, kd, input, cropRect, uniqueID));
977 SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar kd, SkImageFilter* input, const CropRect* cropRect, uint32_t uniqueID)
978 : SkLightingImageFilter(light, surfaceScale, input, cropRect, uniqueID),
983 #ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING
984 SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkReadBuffer& buffer)
987 fKD = buffer.readScalar();
988 buffer.validate(SkScalarIsFinite(fKD) && (fKD >= 0));
992 SkFlattenable* SkDiffuseLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
993 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
994 SkAutoTUnref<SkLight> light(SkLight::UnflattenLight(buffer));
995 SkScalar surfaceScale = buffer.readScalar();
996 SkScalar kd = buffer.readScalar();
997 return Create(light, surfaceScale, kd, common.getInput(0), &common.cropRect(), common.uniqueID());
1000 void SkDiffuseLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
1001 this->INHERITED::flatten(buffer);
1002 buffer.writeScalar(fKD);
1005 bool SkDiffuseLightingImageFilter::onFilterImage(Proxy* proxy,
1006 const SkBitmap& source,
1009 SkIPoint* offset) const {
1010 SkImageFilter* input = getInput(0);
1011 SkBitmap src = source;
1012 SkIPoint srcOffset = SkIPoint::Make(0, 0);
1013 if (input && !input->filterImage(proxy, source, ctx, &src, &srcOffset)) {
1017 if (src.colorType() != kN32_SkColorType) {
1021 if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
1025 if (bounds.width() < 2 || bounds.height() < 2) {
1029 SkAutoLockPixels alp(src);
1030 if (!src.getPixels()) {
1034 if (!dst->tryAllocPixels(src.info().makeWH(bounds.width(), bounds.height()))) {
1038 SkAutoTUnref<SkLight> transformedLight(light()->transform(ctx.ctm()));
1040 DiffuseLightingType lightingType(fKD);
1041 offset->fX = bounds.left();
1042 offset->fY = bounds.top();
1043 bounds.offset(-srcOffset);
1044 switch (transformedLight->type()) {
1045 case SkLight::kDistant_LightType:
1046 lightBitmap<DiffuseLightingType, SkDistantLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
1048 case SkLight::kPoint_LightType:
1049 lightBitmap<DiffuseLightingType, SkPointLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
1051 case SkLight::kSpot_LightType:
1052 lightBitmap<DiffuseLightingType, SkSpotLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
1060 bool SkDiffuseLightingImageFilter::asFragmentProcessor(GrFragmentProcessor** fp,
1062 const SkMatrix& matrix,
1063 const SkIRect&) const {
1065 SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
1066 *fp = GrDiffuseLightingEffect::Create(texture, light(), scale, matrix, kd());
1072 ///////////////////////////////////////////////////////////////////////////////
1074 SkImageFilter* SkSpecularLightingImageFilter::Create(SkLight* light, SkScalar surfaceScale,
1075 SkScalar ks, SkScalar shininess, SkImageFilter* input, const CropRect* cropRect, uint32_t uniqueID) {
1076 if (NULL == light) {
1079 if (!SkScalarIsFinite(surfaceScale) || !SkScalarIsFinite(ks) || !SkScalarIsFinite(shininess)) {
1082 // According to the spec, ks can be any non-negative number :
1083 // http://www.w3.org/TR/SVG/filters.html#feSpecularLightingElement
1087 return SkNEW_ARGS(SkSpecularLightingImageFilter,
1088 (light, surfaceScale, ks, shininess, input, cropRect, uniqueID));
1091 SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess, SkImageFilter* input, const CropRect* cropRect, uint32_t uniqueID)
1092 : SkLightingImageFilter(light, surfaceScale, input, cropRect, uniqueID),
1094 fShininess(shininess)
1098 #ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING
1099 SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkReadBuffer& buffer)
1102 fKS = buffer.readScalar();
1103 fShininess = buffer.readScalar();
1104 buffer.validate(SkScalarIsFinite(fKS) && (fKS >= 0) &&
1105 SkScalarIsFinite(fShininess));
1109 SkFlattenable* SkSpecularLightingImageFilter::CreateProc(SkReadBuffer& buffer) {
1110 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
1111 SkAutoTUnref<SkLight> light(SkLight::UnflattenLight(buffer));
1112 SkScalar surfaceScale = buffer.readScalar();
1113 SkScalar ks = buffer.readScalar();
1114 SkScalar shine = buffer.readScalar();
1115 return Create(light, surfaceScale, ks, shine, common.getInput(0), &common.cropRect(), common.uniqueID());
1118 void SkSpecularLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
1119 this->INHERITED::flatten(buffer);
1120 buffer.writeScalar(fKS);
1121 buffer.writeScalar(fShininess);
1124 bool SkSpecularLightingImageFilter::onFilterImage(Proxy* proxy,
1125 const SkBitmap& source,
1128 SkIPoint* offset) const {
1129 SkImageFilter* input = getInput(0);
1130 SkBitmap src = source;
1131 SkIPoint srcOffset = SkIPoint::Make(0, 0);
1132 if (input && !input->filterImage(proxy, source, ctx, &src, &srcOffset)) {
1136 if (src.colorType() != kN32_SkColorType) {
1141 if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
1145 if (bounds.width() < 2 || bounds.height() < 2) {
1149 SkAutoLockPixels alp(src);
1150 if (!src.getPixels()) {
1154 if (!dst->tryAllocPixels(src.info().makeWH(bounds.width(), bounds.height()))) {
1158 SpecularLightingType lightingType(fKS, fShininess);
1159 offset->fX = bounds.left();
1160 offset->fY = bounds.top();
1161 bounds.offset(-srcOffset);
1162 SkAutoTUnref<SkLight> transformedLight(light()->transform(ctx.ctm()));
1163 switch (transformedLight->type()) {
1164 case SkLight::kDistant_LightType:
1165 lightBitmap<SpecularLightingType, SkDistantLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
1167 case SkLight::kPoint_LightType:
1168 lightBitmap<SpecularLightingType, SkPointLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
1170 case SkLight::kSpot_LightType:
1171 lightBitmap<SpecularLightingType, SkSpotLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
1178 bool SkSpecularLightingImageFilter::asFragmentProcessor(GrFragmentProcessor** fp,
1180 const SkMatrix& matrix,
1181 const SkIRect&) const {
1183 SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
1184 *fp = GrSpecularLightingEffect::Create(texture, light(), scale, matrix, ks(), shininess());
1190 ///////////////////////////////////////////////////////////////////////////////
1195 SkPoint3 random_point3(SkRandom* random) {
1196 return SkPoint3(SkScalarToFloat(random->nextSScalar1()),
1197 SkScalarToFloat(random->nextSScalar1()),
1198 SkScalarToFloat(random->nextSScalar1()));
1201 SkLight* create_random_light(SkRandom* random) {
1202 int type = random->nextULessThan(3);
1205 return SkNEW_ARGS(SkDistantLight, (random_point3(random), random->nextU()));
1208 return SkNEW_ARGS(SkPointLight, (random_point3(random), random->nextU()));
1211 return SkNEW_ARGS(SkSpotLight, (random_point3(random),
1212 random_point3(random),
1213 random->nextUScalar1(),
1214 random->nextUScalar1(),
1218 SkFAIL("Unexpected value.");
1225 class GrGLLightingEffect : public GrGLFragmentProcessor {
1227 GrGLLightingEffect(const GrBackendProcessorFactory&, const GrProcessor&);
1228 virtual ~GrGLLightingEffect();
1230 virtual void emitCode(GrGLFPBuilder*,
1231 const GrFragmentProcessor&,
1232 const GrProcessorKey&,
1233 const char* outputColor,
1234 const char* inputColor,
1235 const TransformedCoordsArray&,
1236 const TextureSamplerArray&) SK_OVERRIDE;
1238 static inline void GenKey(const GrProcessor&, const GrGLCaps&, GrProcessorKeyBuilder* b);
1241 * Subclasses of GrGLLightingEffect must call INHERITED::setData();
1243 virtual void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_OVERRIDE;
1246 virtual void emitLightFunc(GrGLFPBuilder*, SkString* funcName) = 0;
1249 typedef GrGLFragmentProcessor INHERITED;
1251 UniformHandle fImageIncrementUni;
1252 UniformHandle fSurfaceScaleUni;
1256 ///////////////////////////////////////////////////////////////////////////////
1258 class GrGLDiffuseLightingEffect : public GrGLLightingEffect {
1260 GrGLDiffuseLightingEffect(const GrBackendProcessorFactory&, const GrProcessor&);
1261 virtual void emitLightFunc(GrGLFPBuilder*, SkString* funcName) SK_OVERRIDE;
1262 virtual void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_OVERRIDE;
1265 typedef GrGLLightingEffect INHERITED;
1267 UniformHandle fKDUni;
1270 ///////////////////////////////////////////////////////////////////////////////
1272 class GrGLSpecularLightingEffect : public GrGLLightingEffect {
1274 GrGLSpecularLightingEffect(const GrBackendProcessorFactory&, const GrProcessor&);
1275 virtual void emitLightFunc(GrGLFPBuilder*, SkString* funcName) SK_OVERRIDE;
1276 virtual void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_OVERRIDE;
1279 typedef GrGLLightingEffect INHERITED;
1281 UniformHandle fKSUni;
1282 UniformHandle fShininessUni;
1285 ///////////////////////////////////////////////////////////////////////////////
1287 GrLightingEffect::GrLightingEffect(GrTexture* texture,
1288 const SkLight* light,
1289 SkScalar surfaceScale,
1290 const SkMatrix& matrix)
1291 : INHERITED(texture, GrCoordTransform::MakeDivByTextureWHMatrix(texture))
1293 , fSurfaceScale(surfaceScale)
1294 , fFilterMatrix(matrix) {
1296 if (light->requiresFragmentPosition()) {
1297 this->setWillReadFragmentPosition();
1301 GrLightingEffect::~GrLightingEffect() {
1305 bool GrLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
1306 const GrLightingEffect& s = sBase.cast<GrLightingEffect>();
1307 return fLight->isEqual(*s.fLight) &&
1308 fSurfaceScale == s.fSurfaceScale;
1311 ///////////////////////////////////////////////////////////////////////////////
1313 GrDiffuseLightingEffect::GrDiffuseLightingEffect(GrTexture* texture,
1314 const SkLight* light,
1315 SkScalar surfaceScale,
1316 const SkMatrix& matrix,
1318 : INHERITED(texture, light, surfaceScale, matrix), fKD(kd) {
1321 const GrBackendFragmentProcessorFactory& GrDiffuseLightingEffect::getFactory() const {
1322 return GrTBackendFragmentProcessorFactory<GrDiffuseLightingEffect>::getInstance();
1325 bool GrDiffuseLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
1326 const GrDiffuseLightingEffect& s = sBase.cast<GrDiffuseLightingEffect>();
1327 return INHERITED::onIsEqual(sBase) &&
1328 this->kd() == s.kd();
1331 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrDiffuseLightingEffect);
1333 GrFragmentProcessor* GrDiffuseLightingEffect::TestCreate(SkRandom* random,
1335 const GrDrawTargetCaps&,
1336 GrTexture* textures[]) {
1337 SkScalar surfaceScale = random->nextSScalar1();
1338 SkScalar kd = random->nextUScalar1();
1339 SkAutoTUnref<SkLight> light(create_random_light(random));
1341 for (int i = 0; i < 9; i++) {
1342 matrix[i] = random->nextUScalar1();
1344 return GrDiffuseLightingEffect::Create(textures[GrProcessorUnitTest::kAlphaTextureIdx],
1345 light, surfaceScale, matrix, kd);
1349 ///////////////////////////////////////////////////////////////////////////////
1351 GrGLLightingEffect::GrGLLightingEffect(const GrBackendProcessorFactory& factory,
1352 const GrProcessor& fp)
1353 : INHERITED(factory) {
1354 const GrLightingEffect& m = fp.cast<GrLightingEffect>();
1355 fLight = m.light()->createGLLight();
1358 GrGLLightingEffect::~GrGLLightingEffect() {
1362 void GrGLLightingEffect::emitCode(GrGLFPBuilder* builder,
1363 const GrFragmentProcessor&,
1364 const GrProcessorKey& key,
1365 const char* outputColor,
1366 const char* inputColor,
1367 const TransformedCoordsArray& coords,
1368 const TextureSamplerArray& samplers) {
1369 fImageIncrementUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
1372 fSurfaceScaleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
1375 fLight->emitLightColorUniform(builder);
1377 this->emitLightFunc(builder, &lightFunc);
1378 static const GrGLShaderVar gSobelArgs[] = {
1379 GrGLShaderVar("a", kFloat_GrSLType),
1380 GrGLShaderVar("b", kFloat_GrSLType),
1381 GrGLShaderVar("c", kFloat_GrSLType),
1382 GrGLShaderVar("d", kFloat_GrSLType),
1383 GrGLShaderVar("e", kFloat_GrSLType),
1384 GrGLShaderVar("f", kFloat_GrSLType),
1385 GrGLShaderVar("scale", kFloat_GrSLType),
1387 SkString sobelFuncName;
1388 GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
1389 SkString coords2D = fsBuilder->ensureFSCoords2D(coords, 0);
1391 fsBuilder->emitFunction(kFloat_GrSLType,
1393 SK_ARRAY_COUNT(gSobelArgs),
1395 "\treturn (-a + b - 2.0 * c + 2.0 * d -e + f) * scale;\n",
1397 static const GrGLShaderVar gPointToNormalArgs[] = {
1398 GrGLShaderVar("x", kFloat_GrSLType),
1399 GrGLShaderVar("y", kFloat_GrSLType),
1400 GrGLShaderVar("scale", kFloat_GrSLType),
1402 SkString pointToNormalName;
1403 fsBuilder->emitFunction(kVec3f_GrSLType,
1405 SK_ARRAY_COUNT(gPointToNormalArgs),
1407 "\treturn normalize(vec3(-x * scale, y * scale, 1));\n",
1408 &pointToNormalName);
1410 static const GrGLShaderVar gInteriorNormalArgs[] = {
1411 GrGLShaderVar("m", kFloat_GrSLType, 9),
1412 GrGLShaderVar("surfaceScale", kFloat_GrSLType),
1414 SkString interiorNormalBody;
1415 interiorNormalBody.appendf("\treturn %s(%s(m[0], m[2], m[3], m[5], m[6], m[8], 0.25),\n"
1416 "\t %s(m[0], m[6], m[1], m[7], m[2], m[8], 0.25),\n"
1417 "\t surfaceScale);\n",
1418 pointToNormalName.c_str(),
1419 sobelFuncName.c_str(),
1420 sobelFuncName.c_str());
1421 SkString interiorNormalName;
1422 fsBuilder->emitFunction(kVec3f_GrSLType,
1424 SK_ARRAY_COUNT(gInteriorNormalArgs),
1425 gInteriorNormalArgs,
1426 interiorNormalBody.c_str(),
1427 &interiorNormalName);
1429 fsBuilder->codeAppendf("\t\tvec2 coord = %s;\n", coords2D.c_str());
1430 fsBuilder->codeAppend("\t\tfloat m[9];\n");
1432 const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
1433 const char* surfScale = builder->getUniformCStr(fSurfaceScaleUni);
1436 for (int dy = -1; dy <= 1; dy++) {
1437 for (int dx = -1; dx <= 1; dx++) {
1439 texCoords.appendf("coord + vec2(%d, %d) * %s", dx, dy, imgInc);
1440 fsBuilder->codeAppendf("\t\tm[%d] = ", index++);
1441 fsBuilder->appendTextureLookup(samplers[0], texCoords.c_str());
1442 fsBuilder->codeAppend(".a;\n");
1445 fsBuilder->codeAppend("\t\tvec3 surfaceToLight = ");
1447 arg.appendf("%s * m[4]", surfScale);
1448 fLight->emitSurfaceToLight(builder, arg.c_str());
1449 fsBuilder->codeAppend(";\n");
1450 fsBuilder->codeAppendf("\t\t%s = %s(%s(m, %s), surfaceToLight, ",
1451 outputColor, lightFunc.c_str(), interiorNormalName.c_str(), surfScale);
1452 fLight->emitLightColor(builder, "surfaceToLight");
1453 fsBuilder->codeAppend(");\n");
1455 GrGLSLMulVarBy4f(&modulate, outputColor, inputColor);
1456 fsBuilder->codeAppend(modulate.c_str());
1459 void GrGLLightingEffect::GenKey(const GrProcessor& proc,
1460 const GrGLCaps& caps, GrProcessorKeyBuilder* b) {
1461 b->add32(proc.cast<GrLightingEffect>().light()->type());
1464 void GrGLLightingEffect::setData(const GrGLProgramDataManager& pdman,
1465 const GrProcessor& proc) {
1466 const GrLightingEffect& lighting = proc.cast<GrLightingEffect>();
1467 GrTexture* texture = lighting.texture(0);
1468 float ySign = texture->origin() == kTopLeft_GrSurfaceOrigin ? -1.0f : 1.0f;
1469 pdman.set2f(fImageIncrementUni, 1.0f / texture->width(), ySign / texture->height());
1470 pdman.set1f(fSurfaceScaleUni, lighting.surfaceScale());
1471 SkAutoTUnref<SkLight> transformedLight(lighting.light()->transform(lighting.filterMatrix()));
1472 fLight->setData(pdman, transformedLight);
1475 ///////////////////////////////////////////////////////////////////////////////
1477 ///////////////////////////////////////////////////////////////////////////////
1479 GrGLDiffuseLightingEffect::GrGLDiffuseLightingEffect(const GrBackendProcessorFactory& factory,
1480 const GrProcessor& proc)
1481 : INHERITED(factory, proc) {
1484 void GrGLDiffuseLightingEffect::emitLightFunc(GrGLFPBuilder* builder, SkString* funcName) {
1486 fKDUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
1491 static const GrGLShaderVar gLightArgs[] = {
1492 GrGLShaderVar("normal", kVec3f_GrSLType),
1493 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType),
1494 GrGLShaderVar("lightColor", kVec3f_GrSLType)
1497 lightBody.appendf("\tfloat colorScale = %s * dot(normal, surfaceToLight);\n", kd);
1498 lightBody.appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
1499 builder->getFragmentShaderBuilder()->emitFunction(kVec4f_GrSLType,
1501 SK_ARRAY_COUNT(gLightArgs),
1507 void GrGLDiffuseLightingEffect::setData(const GrGLProgramDataManager& pdman,
1508 const GrProcessor& proc) {
1509 INHERITED::setData(pdman, proc);
1510 const GrDiffuseLightingEffect& diffuse = proc.cast<GrDiffuseLightingEffect>();
1511 pdman.set1f(fKDUni, diffuse.kd());
1514 ///////////////////////////////////////////////////////////////////////////////
1516 GrSpecularLightingEffect::GrSpecularLightingEffect(GrTexture* texture,
1517 const SkLight* light,
1518 SkScalar surfaceScale,
1519 const SkMatrix& matrix,
1522 : INHERITED(texture, light, surfaceScale, matrix),
1524 fShininess(shininess) {
1527 const GrBackendFragmentProcessorFactory& GrSpecularLightingEffect::getFactory() const {
1528 return GrTBackendFragmentProcessorFactory<GrSpecularLightingEffect>::getInstance();
1531 bool GrSpecularLightingEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
1532 const GrSpecularLightingEffect& s = sBase.cast<GrSpecularLightingEffect>();
1533 return INHERITED::onIsEqual(sBase) &&
1534 this->ks() == s.ks() &&
1535 this->shininess() == s.shininess();
1538 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrSpecularLightingEffect);
1540 GrFragmentProcessor* GrSpecularLightingEffect::TestCreate(SkRandom* random,
1542 const GrDrawTargetCaps&,
1543 GrTexture* textures[]) {
1544 SkScalar surfaceScale = random->nextSScalar1();
1545 SkScalar ks = random->nextUScalar1();
1546 SkScalar shininess = random->nextUScalar1();
1547 SkAutoTUnref<SkLight> light(create_random_light(random));
1549 for (int i = 0; i < 9; i++) {
1550 matrix[i] = random->nextUScalar1();
1552 return GrSpecularLightingEffect::Create(textures[GrProcessorUnitTest::kAlphaTextureIdx],
1553 light, surfaceScale, matrix, ks, shininess);
1556 ///////////////////////////////////////////////////////////////////////////////
1558 GrGLSpecularLightingEffect::GrGLSpecularLightingEffect(const GrBackendProcessorFactory& factory,
1559 const GrProcessor& proc)
1560 : INHERITED(factory, proc) {
1563 void GrGLSpecularLightingEffect::emitLightFunc(GrGLFPBuilder* builder, SkString* funcName) {
1565 const char* shininess;
1567 fKSUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
1568 kFloat_GrSLType, "KS", &ks);
1569 fShininessUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
1570 kFloat_GrSLType, "Shininess", &shininess);
1572 static const GrGLShaderVar gLightArgs[] = {
1573 GrGLShaderVar("normal", kVec3f_GrSLType),
1574 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType),
1575 GrGLShaderVar("lightColor", kVec3f_GrSLType)
1578 lightBody.appendf("\tvec3 halfDir = vec3(normalize(surfaceToLight + vec3(0, 0, 1)));\n");
1579 lightBody.appendf("\tfloat colorScale = %s * pow(dot(normal, halfDir), %s);\n", ks, shininess);
1580 lightBody.appendf("\tvec3 color = lightColor * clamp(colorScale, 0.0, 1.0);\n");
1581 lightBody.appendf("\treturn vec4(color, max(max(color.r, color.g), color.b));\n");
1582 builder->getFragmentShaderBuilder()->emitFunction(kVec4f_GrSLType,
1584 SK_ARRAY_COUNT(gLightArgs),
1590 void GrGLSpecularLightingEffect::setData(const GrGLProgramDataManager& pdman,
1591 const GrProcessor& effect) {
1592 INHERITED::setData(pdman, effect);
1593 const GrSpecularLightingEffect& spec = effect.cast<GrSpecularLightingEffect>();
1594 pdman.set1f(fKSUni, spec.ks());
1595 pdman.set1f(fShininessUni, spec.shininess());
1598 ///////////////////////////////////////////////////////////////////////////////
1599 void GrGLLight::emitLightColorUniform(GrGLFPBuilder* builder) {
1600 fColorUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
1601 kVec3f_GrSLType, "LightColor");
1604 void GrGLLight::emitLightColor(GrGLFPBuilder* builder,
1605 const char *surfaceToLight) {
1606 builder->getFragmentShaderBuilder()->codeAppend(builder->getUniformCStr(this->lightColorUni()));
1609 void GrGLLight::setData(const GrGLProgramDataManager& pdman,
1610 const SkLight* light) const {
1611 setUniformPoint3(pdman, fColorUni, light->color() * SkScalarInvert(SkIntToScalar(255)));
1614 ///////////////////////////////////////////////////////////////////////////////
1616 void GrGLDistantLight::setData(const GrGLProgramDataManager& pdman,
1617 const SkLight* light) const {
1618 INHERITED::setData(pdman, light);
1619 SkASSERT(light->type() == SkLight::kDistant_LightType);
1620 const SkDistantLight* distantLight = static_cast<const SkDistantLight*>(light);
1621 setUniformNormal3(pdman, fDirectionUni, distantLight->direction());
1624 void GrGLDistantLight::emitSurfaceToLight(GrGLFPBuilder* builder, const char* z) {
1626 fDirectionUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, kVec3f_GrSLType,
1627 "LightDirection", &dir);
1628 builder->getFragmentShaderBuilder()->codeAppend(dir);
1631 ///////////////////////////////////////////////////////////////////////////////
1633 void GrGLPointLight::setData(const GrGLProgramDataManager& pdman,
1634 const SkLight* light) const {
1635 INHERITED::setData(pdman, light);
1636 SkASSERT(light->type() == SkLight::kPoint_LightType);
1637 const SkPointLight* pointLight = static_cast<const SkPointLight*>(light);
1638 setUniformPoint3(pdman, fLocationUni, pointLight->location());
1641 void GrGLPointLight::emitSurfaceToLight(GrGLFPBuilder* builder, const char* z) {
1643 fLocationUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, kVec3f_GrSLType,
1644 "LightLocation", &loc);
1645 GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
1646 fsBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))",
1647 loc, fsBuilder->fragmentPosition(), z);
1650 ///////////////////////////////////////////////////////////////////////////////
1652 void GrGLSpotLight::setData(const GrGLProgramDataManager& pdman,
1653 const SkLight* light) const {
1654 INHERITED::setData(pdman, light);
1655 SkASSERT(light->type() == SkLight::kSpot_LightType);
1656 const SkSpotLight* spotLight = static_cast<const SkSpotLight *>(light);
1657 setUniformPoint3(pdman, fLocationUni, spotLight->location());
1658 pdman.set1f(fExponentUni, spotLight->specularExponent());
1659 pdman.set1f(fCosInnerConeAngleUni, spotLight->cosInnerConeAngle());
1660 pdman.set1f(fCosOuterConeAngleUni, spotLight->cosOuterConeAngle());
1661 pdman.set1f(fConeScaleUni, spotLight->coneScale());
1662 setUniformNormal3(pdman, fSUni, spotLight->s());
1665 void GrGLSpotLight::emitSurfaceToLight(GrGLFPBuilder* builder, const char* z) {
1666 const char* location;
1667 fLocationUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
1668 kVec3f_GrSLType, "LightLocation", &location);
1670 GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
1671 fsBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))",
1672 location, fsBuilder->fragmentPosition(), z);
1675 void GrGLSpotLight::emitLightColor(GrGLFPBuilder* builder,
1676 const char *surfaceToLight) {
1678 const char* color = builder->getUniformCStr(this->lightColorUni()); // created by parent class.
1680 const char* exponent;
1681 const char* cosInner;
1682 const char* cosOuter;
1683 const char* coneScale;
1685 fExponentUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
1686 kFloat_GrSLType, "Exponent", &exponent);
1687 fCosInnerConeAngleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
1688 kFloat_GrSLType, "CosInnerConeAngle", &cosInner);
1689 fCosOuterConeAngleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
1690 kFloat_GrSLType, "CosOuterConeAngle", &cosOuter);
1691 fConeScaleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
1692 kFloat_GrSLType, "ConeScale", &coneScale);
1693 fSUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
1694 kVec3f_GrSLType, "S", &s);
1696 static const GrGLShaderVar gLightColorArgs[] = {
1697 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType)
1699 SkString lightColorBody;
1700 lightColorBody.appendf("\tfloat cosAngle = -dot(surfaceToLight, %s);\n", s);
1701 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosOuter);
1702 lightColorBody.appendf("\t\treturn vec3(0);\n");
1703 lightColorBody.appendf("\t}\n");
1704 lightColorBody.appendf("\tfloat scale = pow(cosAngle, %s);\n", exponent);
1705 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosInner);
1706 lightColorBody.appendf("\t\treturn %s * scale * (cosAngle - %s) * %s;\n",
1707 color, cosOuter, coneScale);
1708 lightColorBody.appendf("\t}\n");
1709 lightColorBody.appendf("\treturn %s;\n", color);
1710 GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
1711 fsBuilder->emitFunction(kVec3f_GrSLType,
1713 SK_ARRAY_COUNT(gLightColorArgs),
1715 lightColorBody.c_str(),
1718 fsBuilder->codeAppendf("%s(%s)", fLightColorFunc.c_str(), surfaceToLight);
1723 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingImageFilter)
1724 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiffuseLightingImageFilter)
1725 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpecularLightingImageFilter)
1726 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END