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/GrGLEffect.h"
20 #include "gl/GrGLShaderBuilder.h"
22 #include "GrTBackendEffectFactory.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, const SkPoint3& point) {
40 GR_STATIC_ASSERT(sizeof(SkPoint3) == 3 * sizeof(GrGLfloat));
41 pdman.set3fv(uni, 1, &point.fX);
44 void setUniformNormal3(const GrGLProgramDataManager& pdman, UniformHandle uni, const SkPoint3& point) {
45 setUniformPoint3(pdman, uni, SkPoint3(point.fX, point.fY, point.fZ));
49 // Shift matrix components to the left, as we advance pixels to the right.
50 inline void shiftMatrixLeft(int m[9]) {
59 class DiffuseLightingType {
61 DiffuseLightingType(SkScalar kd)
63 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight, const SkPoint3& lightColor) const {
64 SkScalar colorScale = SkScalarMul(fKD, normal.dot(surfaceTolight));
65 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
66 SkPoint3 color(lightColor * colorScale);
67 return SkPackARGB32(255,
68 SkClampMax(SkScalarRoundToInt(color.fX), 255),
69 SkClampMax(SkScalarRoundToInt(color.fY), 255),
70 SkClampMax(SkScalarRoundToInt(color.fZ), 255));
76 class SpecularLightingType {
78 SpecularLightingType(SkScalar ks, SkScalar shininess)
79 : fKS(ks), fShininess(shininess) {}
80 SkPMColor light(const SkPoint3& normal, const SkPoint3& surfaceTolight, const SkPoint3& lightColor) const {
81 SkPoint3 halfDir(surfaceTolight);
82 halfDir.fZ += SK_Scalar1; // eye position is always (0, 0, 1)
84 SkScalar colorScale = SkScalarMul(fKS,
85 SkScalarPow(normal.dot(halfDir), fShininess));
86 colorScale = SkScalarClampMax(colorScale, SK_Scalar1);
87 SkPoint3 color(lightColor * colorScale);
88 return SkPackARGB32(SkClampMax(SkScalarRoundToInt(color.maxComponent()), 255),
89 SkClampMax(SkScalarRoundToInt(color.fX), 255),
90 SkClampMax(SkScalarRoundToInt(color.fY), 255),
91 SkClampMax(SkScalarRoundToInt(color.fZ), 255));
98 inline SkScalar sobel(int a, int b, int c, int d, int e, int f, SkScalar scale) {
99 return SkScalarMul(SkIntToScalar(-a + b - 2 * c + 2 * d -e + f), scale);
102 inline SkPoint3 pointToNormal(SkScalar x, SkScalar y, SkScalar surfaceScale) {
103 SkPoint3 vector(SkScalarMul(-x, surfaceScale),
104 SkScalarMul(-y, surfaceScale),
110 inline SkPoint3 topLeftNormal(int m[9], SkScalar surfaceScale) {
111 return pointToNormal(sobel(0, 0, m[4], m[5], m[7], m[8], gTwoThirds),
112 sobel(0, 0, m[4], m[7], m[5], m[8], gTwoThirds),
116 inline SkPoint3 topNormal(int m[9], SkScalar surfaceScale) {
117 return pointToNormal(sobel( 0, 0, m[3], m[5], m[6], m[8], gOneThird),
118 sobel(m[3], m[6], m[4], m[7], m[5], m[8], gOneHalf),
122 inline SkPoint3 topRightNormal(int m[9], SkScalar surfaceScale) {
123 return pointToNormal(sobel( 0, 0, m[3], m[4], m[6], m[7], gTwoThirds),
124 sobel(m[3], m[6], m[4], m[7], 0, 0, gTwoThirds),
128 inline SkPoint3 leftNormal(int m[9], SkScalar surfaceScale) {
129 return pointToNormal(sobel(m[1], m[2], m[4], m[5], m[7], m[8], gOneHalf),
130 sobel( 0, 0, m[1], m[7], m[2], m[8], gOneThird),
135 inline SkPoint3 interiorNormal(int m[9], SkScalar surfaceScale) {
136 return pointToNormal(sobel(m[0], m[2], m[3], m[5], m[6], m[8], gOneQuarter),
137 sobel(m[0], m[6], m[1], m[7], m[2], m[8], gOneQuarter),
141 inline SkPoint3 rightNormal(int m[9], SkScalar surfaceScale) {
142 return pointToNormal(sobel(m[0], m[1], m[3], m[4], m[6], m[7], gOneHalf),
143 sobel(m[0], m[6], m[1], m[7], 0, 0, gOneThird),
147 inline SkPoint3 bottomLeftNormal(int m[9], SkScalar surfaceScale) {
148 return pointToNormal(sobel(m[1], m[2], m[4], m[5], 0, 0, gTwoThirds),
149 sobel( 0, 0, m[1], m[4], m[2], m[5], gTwoThirds),
153 inline SkPoint3 bottomNormal(int m[9], SkScalar surfaceScale) {
154 return pointToNormal(sobel(m[0], m[2], m[3], m[5], 0, 0, gOneThird),
155 sobel(m[0], m[3], m[1], m[4], m[2], m[5], gOneHalf),
159 inline SkPoint3 bottomRightNormal(int m[9], SkScalar surfaceScale) {
160 return pointToNormal(sobel(m[0], m[1], m[3], m[4], 0, 0, gTwoThirds),
161 sobel(m[0], m[3], m[1], m[4], 0, 0, gTwoThirds),
165 template <class LightingType, class LightType> void lightBitmap(const LightingType& lightingType, const SkLight* light, const SkBitmap& src, SkBitmap* dst, SkScalar surfaceScale, const SkIRect& bounds) {
166 SkASSERT(dst->width() == bounds.width() && dst->height() == bounds.height());
167 const LightType* l = static_cast<const LightType*>(light);
168 int left = bounds.left(), right = bounds.right();
169 int bottom = bounds.bottom();
170 int y = bounds.top();
171 SkPMColor* dptr = dst->getAddr32(0, 0);
174 const SkPMColor* row1 = src.getAddr32(x, y);
175 const SkPMColor* row2 = src.getAddr32(x, y + 1);
177 m[4] = SkGetPackedA32(*row1++);
178 m[5] = SkGetPackedA32(*row1++);
179 m[7] = SkGetPackedA32(*row2++);
180 m[8] = SkGetPackedA32(*row2++);
181 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
182 *dptr++ = lightingType.light(topLeftNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
183 for (++x; x < right - 1; ++x)
186 m[5] = SkGetPackedA32(*row1++);
187 m[8] = SkGetPackedA32(*row2++);
188 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
189 *dptr++ = lightingType.light(topNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
192 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
193 *dptr++ = lightingType.light(topRightNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
196 for (++y; y < bottom - 1; ++y) {
198 const SkPMColor* row0 = src.getAddr32(x, y - 1);
199 const SkPMColor* row1 = src.getAddr32(x, y);
200 const SkPMColor* row2 = src.getAddr32(x, y + 1);
202 m[1] = SkGetPackedA32(*row0++);
203 m[2] = SkGetPackedA32(*row0++);
204 m[4] = SkGetPackedA32(*row1++);
205 m[5] = SkGetPackedA32(*row1++);
206 m[7] = SkGetPackedA32(*row2++);
207 m[8] = SkGetPackedA32(*row2++);
208 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
209 *dptr++ = lightingType.light(leftNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
210 for (++x; x < right - 1; ++x) {
212 m[2] = SkGetPackedA32(*row0++);
213 m[5] = SkGetPackedA32(*row1++);
214 m[8] = SkGetPackedA32(*row2++);
215 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
216 *dptr++ = lightingType.light(interiorNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
219 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
220 *dptr++ = lightingType.light(rightNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
225 const SkPMColor* row0 = src.getAddr32(x, bottom - 2);
226 const SkPMColor* row1 = src.getAddr32(x, bottom - 1);
228 m[1] = SkGetPackedA32(*row0++);
229 m[2] = SkGetPackedA32(*row0++);
230 m[4] = SkGetPackedA32(*row1++);
231 m[5] = SkGetPackedA32(*row1++);
232 SkPoint3 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
233 *dptr++ = lightingType.light(bottomLeftNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
234 for (++x; x < right - 1; ++x)
237 m[2] = SkGetPackedA32(*row0++);
238 m[5] = SkGetPackedA32(*row1++);
239 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
240 *dptr++ = lightingType.light(bottomNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
243 surfaceToLight = l->surfaceToLight(x, y, m[4], surfaceScale);
244 *dptr++ = lightingType.light(bottomRightNormal(m, surfaceScale), surfaceToLight, l->lightColor(surfaceToLight));
248 SkPoint3 readPoint3(SkReadBuffer& buffer) {
250 point.fX = buffer.readScalar();
251 point.fY = buffer.readScalar();
252 point.fZ = buffer.readScalar();
253 buffer.validate(SkScalarIsFinite(point.fX) &&
254 SkScalarIsFinite(point.fY) &&
255 SkScalarIsFinite(point.fZ));
259 void writePoint3(const SkPoint3& point, SkWriteBuffer& buffer) {
260 buffer.writeScalar(point.fX);
261 buffer.writeScalar(point.fY);
262 buffer.writeScalar(point.fZ);
265 class SkDiffuseLightingImageFilter : public SkLightingImageFilter {
267 SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale,
268 SkScalar kd, SkImageFilter* input, const CropRect* cropRect);
269 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDiffuseLightingImageFilter)
270 SkScalar kd() const { return fKD; }
273 explicit SkDiffuseLightingImageFilter(SkReadBuffer& buffer);
274 virtual void flatten(SkWriteBuffer& buffer) const SK_OVERRIDE;
275 virtual bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
276 SkBitmap* result, SkIPoint* offset) const SK_OVERRIDE;
278 virtual bool asNewEffect(GrEffect** effect, GrTexture*, const SkMatrix& matrix,
279 const SkIRect& bounds) const SK_OVERRIDE;
283 typedef SkLightingImageFilter INHERITED;
287 class SkSpecularLightingImageFilter : public SkLightingImageFilter {
289 SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess, SkImageFilter* input, const CropRect* cropRect);
290 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSpecularLightingImageFilter)
292 SkScalar ks() const { return fKS; }
293 SkScalar shininess() const { return fShininess; }
296 explicit SkSpecularLightingImageFilter(SkReadBuffer& buffer);
297 virtual void flatten(SkWriteBuffer& buffer) const SK_OVERRIDE;
298 virtual bool onFilterImage(Proxy*, const SkBitmap& src, const Context&,
299 SkBitmap* result, SkIPoint* offset) const SK_OVERRIDE;
301 virtual bool asNewEffect(GrEffect** effect, GrTexture*, const SkMatrix& matrix,
302 const SkIRect& bounds) const SK_OVERRIDE;
306 typedef SkLightingImageFilter INHERITED;
313 class GrLightingEffect : public GrSingleTextureEffect {
315 GrLightingEffect(GrTexture* texture, const SkLight* light, SkScalar surfaceScale, const SkMatrix& matrix);
316 virtual ~GrLightingEffect();
318 const SkLight* light() const { return fLight; }
319 SkScalar surfaceScale() const { return fSurfaceScale; }
320 const SkMatrix& filterMatrix() const { return fFilterMatrix; }
322 virtual void getConstantColorComponents(GrColor* color,
323 uint32_t* validFlags) const SK_OVERRIDE {
324 // lighting shaders are complicated. We just throw up our hands.
329 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
332 typedef GrSingleTextureEffect INHERITED;
333 const SkLight* fLight;
334 SkScalar fSurfaceScale;
335 SkMatrix fFilterMatrix;
338 class GrDiffuseLightingEffect : public GrLightingEffect {
340 static GrEffect* Create(GrTexture* texture,
341 const SkLight* light,
342 SkScalar surfaceScale,
343 const SkMatrix& matrix,
345 return SkNEW_ARGS(GrDiffuseLightingEffect, (texture,
352 static const char* Name() { return "DiffuseLighting"; }
354 typedef GrGLDiffuseLightingEffect GLEffect;
356 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
357 SkScalar kd() const { return fKD; }
360 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
362 GrDiffuseLightingEffect(GrTexture* texture,
363 const SkLight* light,
364 SkScalar surfaceScale,
365 const SkMatrix& matrix,
368 GR_DECLARE_EFFECT_TEST;
369 typedef GrLightingEffect INHERITED;
373 class GrSpecularLightingEffect : public GrLightingEffect {
375 static GrEffect* Create(GrTexture* texture,
376 const SkLight* light,
377 SkScalar surfaceScale,
378 const SkMatrix& matrix,
380 SkScalar shininess) {
381 return SkNEW_ARGS(GrSpecularLightingEffect, (texture,
388 static const char* Name() { return "SpecularLighting"; }
390 typedef GrGLSpecularLightingEffect GLEffect;
392 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
393 SkScalar ks() const { return fKS; }
394 SkScalar shininess() const { return fShininess; }
397 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
399 GrSpecularLightingEffect(GrTexture* texture,
400 const SkLight* light,
401 SkScalar surfaceScale,
402 const SkMatrix& matrix,
406 GR_DECLARE_EFFECT_TEST;
407 typedef GrLightingEffect INHERITED;
412 ///////////////////////////////////////////////////////////////////////////////
416 virtual ~GrGLLight() {}
419 * This is called by GrGLLightingEffect::emitCode() before either of the two virtual functions
420 * below. It adds a vec3f uniform visible in the FS that represents the constant light color.
422 void emitLightColorUniform(GrGLShaderBuilder*);
425 * These two functions are called from GrGLLightingEffect's emitCode() function.
426 * emitSurfaceToLight places an expression in param out that is the vector from the surface to
427 * the light. The expression will be used in the FS. emitLightColor writes an expression into
428 * the FS that is the color of the light. Either function may add functions and/or uniforms to
429 * the FS. The default of emitLightColor appends the name of the constant light color uniform
430 * and so this function only needs to be overridden if the light color varies spatially.
432 virtual void emitSurfaceToLight(GrGLShaderBuilder*, const char* z) = 0;
433 virtual void emitLightColor(GrGLShaderBuilder*, const char *surfaceToLight);
435 // This is called from GrGLLightingEffect's setData(). Subclasses of GrGLLight must call
436 // INHERITED::setData().
437 virtual void setData(const GrGLProgramDataManager&,
438 const SkLight* light) const;
442 * Gets the constant light color uniform. Subclasses can use this in their emitLightColor
445 UniformHandle lightColorUni() const { return fColorUni; }
448 UniformHandle fColorUni;
450 typedef SkRefCnt INHERITED;
453 ///////////////////////////////////////////////////////////////////////////////
455 class GrGLDistantLight : public GrGLLight {
457 virtual ~GrGLDistantLight() {}
458 virtual void setData(const GrGLProgramDataManager&,
459 const SkLight* light) const SK_OVERRIDE;
460 virtual void emitSurfaceToLight(GrGLShaderBuilder*, const char* z) SK_OVERRIDE;
463 typedef GrGLLight INHERITED;
464 UniformHandle fDirectionUni;
467 ///////////////////////////////////////////////////////////////////////////////
469 class GrGLPointLight : public GrGLLight {
471 virtual ~GrGLPointLight() {}
472 virtual void setData(const GrGLProgramDataManager&,
473 const SkLight* light) const SK_OVERRIDE;
474 virtual void emitSurfaceToLight(GrGLShaderBuilder*, const char* z) SK_OVERRIDE;
477 typedef GrGLLight INHERITED;
478 UniformHandle fLocationUni;
481 ///////////////////////////////////////////////////////////////////////////////
483 class GrGLSpotLight : public GrGLLight {
485 virtual ~GrGLSpotLight() {}
486 virtual void setData(const GrGLProgramDataManager&,
487 const SkLight* light) const SK_OVERRIDE;
488 virtual void emitSurfaceToLight(GrGLShaderBuilder*, const char* z) SK_OVERRIDE;
489 virtual void emitLightColor(GrGLShaderBuilder*, const char *surfaceToLight) SK_OVERRIDE;
492 typedef GrGLLight INHERITED;
494 SkString fLightColorFunc;
495 UniformHandle fLocationUni;
496 UniformHandle fExponentUni;
497 UniformHandle fCosOuterConeAngleUni;
498 UniformHandle fCosInnerConeAngleUni;
499 UniformHandle fConeScaleUni;
510 ///////////////////////////////////////////////////////////////////////////////
512 class SkLight : public SkRefCnt {
514 SK_DECLARE_INST_COUNT(SkLight)
521 virtual LightType type() const = 0;
522 const SkPoint3& color() const { return fColor; }
523 virtual GrGLLight* createGLLight() const = 0;
524 virtual bool isEqual(const SkLight& other) const {
525 return fColor == other.fColor;
527 // Called to know whether the generated GrGLLight will require access to the fragment position.
528 virtual bool requiresFragmentPosition() const = 0;
529 virtual SkLight* transform(const SkMatrix& matrix) const = 0;
531 // Defined below SkLight's subclasses.
532 void flattenLight(SkWriteBuffer& buffer) const;
533 static SkLight* UnflattenLight(SkReadBuffer& buffer);
536 SkLight(SkColor color)
537 : fColor(SkIntToScalar(SkColorGetR(color)),
538 SkIntToScalar(SkColorGetG(color)),
539 SkIntToScalar(SkColorGetB(color))) {}
540 SkLight(const SkPoint3& color)
542 SkLight(SkReadBuffer& buffer) {
543 fColor = readPoint3(buffer);
546 virtual void onFlattenLight(SkWriteBuffer& buffer) const = 0;
550 typedef SkRefCnt INHERITED;
554 ///////////////////////////////////////////////////////////////////////////////
556 class SkDistantLight : public SkLight {
558 SkDistantLight(const SkPoint3& direction, SkColor color)
559 : INHERITED(color), fDirection(direction) {
562 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
565 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
566 virtual LightType type() const { return kDistant_LightType; }
567 const SkPoint3& direction() const { return fDirection; }
568 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
570 return SkNEW(GrGLDistantLight);
572 SkDEBUGFAIL("Should not call in GPU-less build");
576 virtual bool requiresFragmentPosition() const SK_OVERRIDE { return false; }
578 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
579 if (other.type() != kDistant_LightType) {
583 const SkDistantLight& o = static_cast<const SkDistantLight&>(other);
584 return INHERITED::isEqual(other) &&
585 fDirection == o.fDirection;
588 SkDistantLight(SkReadBuffer& buffer) : INHERITED(buffer) {
589 fDirection = readPoint3(buffer);
593 SkDistantLight(const SkPoint3& direction, const SkPoint3& color)
594 : INHERITED(color), fDirection(direction) {
596 virtual SkLight* transform(const SkMatrix& matrix) const {
597 return new SkDistantLight(direction(), color());
599 virtual void onFlattenLight(SkWriteBuffer& buffer) const SK_OVERRIDE {
600 writePoint3(fDirection, buffer);
604 typedef SkLight INHERITED;
608 ///////////////////////////////////////////////////////////////////////////////
610 class SkPointLight : public SkLight {
612 SkPointLight(const SkPoint3& location, SkColor color)
613 : INHERITED(color), fLocation(location) {}
615 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
616 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
617 fLocation.fY - SkIntToScalar(y),
618 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
619 direction.normalize();
622 SkPoint3 lightColor(const SkPoint3&) const { return color(); }
623 virtual LightType type() const { return kPoint_LightType; }
624 const SkPoint3& location() const { return fLocation; }
625 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
627 return SkNEW(GrGLPointLight);
629 SkDEBUGFAIL("Should not call in GPU-less build");
633 virtual bool requiresFragmentPosition() const SK_OVERRIDE { return true; }
634 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
635 if (other.type() != kPoint_LightType) {
638 const SkPointLight& o = static_cast<const SkPointLight&>(other);
639 return INHERITED::isEqual(other) &&
640 fLocation == o.fLocation;
642 virtual SkLight* transform(const SkMatrix& matrix) const {
643 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
644 matrix.mapPoints(&location2, 1);
645 // Use X scale and Y scale on Z and average the result
646 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
647 matrix.mapVectors(&locationZ, 1);
648 SkPoint3 location(location2.fX, location2.fY, SkScalarAve(locationZ.fX, locationZ.fY));
649 return new SkPointLight(location, color());
652 SkPointLight(SkReadBuffer& buffer) : INHERITED(buffer) {
653 fLocation = readPoint3(buffer);
657 SkPointLight(const SkPoint3& location, const SkPoint3& color)
658 : INHERITED(color), fLocation(location) {}
659 virtual void onFlattenLight(SkWriteBuffer& buffer) const SK_OVERRIDE {
660 writePoint3(fLocation, buffer);
664 typedef SkLight INHERITED;
668 ///////////////////////////////////////////////////////////////////////////////
670 class SkSpotLight : public SkLight {
672 SkSpotLight(const SkPoint3& location, const SkPoint3& target, SkScalar specularExponent, SkScalar cutoffAngle, SkColor color)
676 fSpecularExponent(SkScalarPin(specularExponent, kSpecularExponentMin, kSpecularExponentMax))
678 fS = target - location;
680 fCosOuterConeAngle = SkScalarCos(SkDegreesToRadians(cutoffAngle));
681 const SkScalar antiAliasThreshold = 0.016f;
682 fCosInnerConeAngle = fCosOuterConeAngle + antiAliasThreshold;
683 fConeScale = SkScalarInvert(antiAliasThreshold);
686 virtual SkLight* transform(const SkMatrix& matrix) const {
687 SkPoint location2 = SkPoint::Make(fLocation.fX, fLocation.fY);
688 matrix.mapPoints(&location2, 1);
689 // Use X scale and Y scale on Z and average the result
690 SkPoint locationZ = SkPoint::Make(fLocation.fZ, fLocation.fZ);
691 matrix.mapVectors(&locationZ, 1);
692 SkPoint3 location(location2.fX, location2.fY, SkScalarAve(locationZ.fX, locationZ.fY));
693 SkPoint target2 = SkPoint::Make(fTarget.fX, fTarget.fY);
694 matrix.mapPoints(&target2, 1);
695 SkPoint targetZ = SkPoint::Make(fTarget.fZ, fTarget.fZ);
696 matrix.mapVectors(&targetZ, 1);
697 SkPoint3 target(target2.fX, target2.fY, SkScalarAve(targetZ.fX, targetZ.fY));
698 SkPoint3 s = target - location;
700 return new SkSpotLight(location, target, fSpecularExponent, fCosOuterConeAngle, fCosInnerConeAngle, fConeScale, s, color());
703 SkPoint3 surfaceToLight(int x, int y, int z, SkScalar surfaceScale) const {
704 SkPoint3 direction(fLocation.fX - SkIntToScalar(x),
705 fLocation.fY - SkIntToScalar(y),
706 fLocation.fZ - SkScalarMul(SkIntToScalar(z), surfaceScale));
707 direction.normalize();
710 SkPoint3 lightColor(const SkPoint3& surfaceToLight) const {
711 SkScalar cosAngle = -surfaceToLight.dot(fS);
712 if (cosAngle < fCosOuterConeAngle) {
713 return SkPoint3(0, 0, 0);
715 SkScalar scale = SkScalarPow(cosAngle, fSpecularExponent);
716 if (cosAngle < fCosInnerConeAngle) {
717 scale = SkScalarMul(scale, cosAngle - fCosOuterConeAngle);
718 return color() * SkScalarMul(scale, fConeScale);
720 return color() * scale;
722 virtual GrGLLight* createGLLight() const SK_OVERRIDE {
724 return SkNEW(GrGLSpotLight);
726 SkDEBUGFAIL("Should not call in GPU-less build");
730 virtual bool requiresFragmentPosition() const SK_OVERRIDE { return true; }
731 virtual LightType type() const { return kSpot_LightType; }
732 const SkPoint3& location() const { return fLocation; }
733 const SkPoint3& target() const { return fTarget; }
734 SkScalar specularExponent() const { return fSpecularExponent; }
735 SkScalar cosInnerConeAngle() const { return fCosInnerConeAngle; }
736 SkScalar cosOuterConeAngle() const { return fCosOuterConeAngle; }
737 SkScalar coneScale() const { return fConeScale; }
738 const SkPoint3& s() const { return fS; }
740 SkSpotLight(SkReadBuffer& buffer) : INHERITED(buffer) {
741 fLocation = readPoint3(buffer);
742 fTarget = readPoint3(buffer);
743 fSpecularExponent = buffer.readScalar();
744 fCosOuterConeAngle = buffer.readScalar();
745 fCosInnerConeAngle = buffer.readScalar();
746 fConeScale = buffer.readScalar();
747 fS = readPoint3(buffer);
748 buffer.validate(SkScalarIsFinite(fSpecularExponent) &&
749 SkScalarIsFinite(fCosOuterConeAngle) &&
750 SkScalarIsFinite(fCosInnerConeAngle) &&
751 SkScalarIsFinite(fConeScale));
754 SkSpotLight(const SkPoint3& location, const SkPoint3& target, SkScalar specularExponent, SkScalar cosOuterConeAngle, SkScalar cosInnerConeAngle, SkScalar coneScale, const SkPoint3& s, const SkPoint3& color)
758 fSpecularExponent(specularExponent),
759 fCosOuterConeAngle(cosOuterConeAngle),
760 fCosInnerConeAngle(cosInnerConeAngle),
761 fConeScale(coneScale),
765 virtual void onFlattenLight(SkWriteBuffer& buffer) const SK_OVERRIDE {
766 writePoint3(fLocation, buffer);
767 writePoint3(fTarget, buffer);
768 buffer.writeScalar(fSpecularExponent);
769 buffer.writeScalar(fCosOuterConeAngle);
770 buffer.writeScalar(fCosInnerConeAngle);
771 buffer.writeScalar(fConeScale);
772 writePoint3(fS, buffer);
775 virtual bool isEqual(const SkLight& other) const SK_OVERRIDE {
776 if (other.type() != kSpot_LightType) {
780 const SkSpotLight& o = static_cast<const SkSpotLight&>(other);
781 return INHERITED::isEqual(other) &&
782 fLocation == o.fLocation &&
783 fTarget == o.fTarget &&
784 fSpecularExponent == o.fSpecularExponent &&
785 fCosOuterConeAngle == o.fCosOuterConeAngle;
789 static const SkScalar kSpecularExponentMin;
790 static const SkScalar kSpecularExponentMax;
792 typedef SkLight INHERITED;
795 SkScalar fSpecularExponent;
796 SkScalar fCosOuterConeAngle;
797 SkScalar fCosInnerConeAngle;
802 // According to the spec, the specular term should be in the range [1, 128] :
803 // http://www.w3.org/TR/SVG/filters.html#feSpecularLightingSpecularExponentAttribute
804 const SkScalar SkSpotLight::kSpecularExponentMin = 1.0f;
805 const SkScalar SkSpotLight::kSpecularExponentMax = 128.0f;
807 ///////////////////////////////////////////////////////////////////////////////
809 void SkLight::flattenLight(SkWriteBuffer& buffer) const {
810 // Write type first, then baseclass, then subclass.
811 buffer.writeInt(this->type());
812 writePoint3(fColor, buffer);
813 this->onFlattenLight(buffer);
816 /*static*/ SkLight* SkLight::UnflattenLight(SkReadBuffer& buffer) {
818 const SkLight::LightType type = (SkLight::LightType)buffer.readInt();
820 // Each of these constructors must first call SkLight's, so we'll read the baseclass
821 // then subclass, same order as flattenLight.
822 case SkLight::kDistant_LightType: return SkNEW_ARGS(SkDistantLight, (buffer));
823 case SkLight::kPoint_LightType: return SkNEW_ARGS(SkPointLight, (buffer));
824 case SkLight::kSpot_LightType: return SkNEW_ARGS(SkSpotLight, (buffer));
826 SkDEBUGFAIL("Unknown LightType.");
827 buffer.validate(false);
831 ///////////////////////////////////////////////////////////////////////////////
833 SkLightingImageFilter::SkLightingImageFilter(SkLight* light, SkScalar surfaceScale,
834 SkImageFilter* input, const CropRect* cropRect)
835 : INHERITED(1, &input, cropRect),
837 fSurfaceScale(SkScalarDiv(surfaceScale, SkIntToScalar(255)))
840 // our caller knows that we take ownership of the light, so we don't
841 // need to call ref() here.
844 SkImageFilter* SkLightingImageFilter::CreateDistantLitDiffuse(
845 const SkPoint3& direction, SkColor lightColor, SkScalar surfaceScale,
846 SkScalar kd, SkImageFilter* input, const CropRect* cropRect) {
847 return SkNEW_ARGS(SkDiffuseLightingImageFilter,
848 (SkNEW_ARGS(SkDistantLight, (direction, lightColor)), surfaceScale, kd,
852 SkImageFilter* SkLightingImageFilter::CreatePointLitDiffuse(
853 const SkPoint3& location, SkColor lightColor, SkScalar surfaceScale,
854 SkScalar kd, SkImageFilter* input, const CropRect* cropRect) {
855 return SkNEW_ARGS(SkDiffuseLightingImageFilter,
856 (SkNEW_ARGS(SkPointLight, (location, lightColor)), surfaceScale, kd,
860 SkImageFilter* SkLightingImageFilter::CreateSpotLitDiffuse(
861 const SkPoint3& location, const SkPoint3& target,
862 SkScalar specularExponent, SkScalar cutoffAngle,
863 SkColor lightColor, SkScalar surfaceScale, SkScalar kd,
864 SkImageFilter* input, const CropRect* cropRect) {
865 return SkNEW_ARGS(SkDiffuseLightingImageFilter,
866 (SkNEW_ARGS(SkSpotLight, (location, target, specularExponent,
867 cutoffAngle, lightColor)),
868 surfaceScale, kd, input, cropRect));
871 SkImageFilter* SkLightingImageFilter::CreateDistantLitSpecular(
872 const SkPoint3& direction, SkColor lightColor, SkScalar surfaceScale,
873 SkScalar ks, SkScalar shininess, SkImageFilter* input, const CropRect* cropRect) {
874 return SkNEW_ARGS(SkSpecularLightingImageFilter,
875 (SkNEW_ARGS(SkDistantLight, (direction, lightColor)),
876 surfaceScale, ks, shininess, input, cropRect));
879 SkImageFilter* SkLightingImageFilter::CreatePointLitSpecular(
880 const SkPoint3& location, SkColor lightColor, SkScalar surfaceScale,
881 SkScalar ks, SkScalar shininess, SkImageFilter* input, const CropRect* cropRect) {
882 return SkNEW_ARGS(SkSpecularLightingImageFilter,
883 (SkNEW_ARGS(SkPointLight, (location, lightColor)),
884 surfaceScale, ks, shininess, input, cropRect));
887 SkImageFilter* SkLightingImageFilter::CreateSpotLitSpecular(
888 const SkPoint3& location, const SkPoint3& target,
889 SkScalar specularExponent, SkScalar cutoffAngle,
890 SkColor lightColor, SkScalar surfaceScale,
891 SkScalar ks, SkScalar shininess, SkImageFilter* input, const CropRect* cropRect) {
892 return SkNEW_ARGS(SkSpecularLightingImageFilter,
893 (SkNEW_ARGS(SkSpotLight, (location, target, specularExponent, cutoffAngle, lightColor)),
894 surfaceScale, ks, shininess, input, cropRect));
897 SkLightingImageFilter::~SkLightingImageFilter() {
901 SkLightingImageFilter::SkLightingImageFilter(SkReadBuffer& buffer)
902 : INHERITED(1, buffer) {
903 fLight = SkLight::UnflattenLight(buffer);
904 fSurfaceScale = buffer.readScalar();
905 buffer.validate(SkScalarIsFinite(fSurfaceScale));
908 void SkLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
909 this->INHERITED::flatten(buffer);
910 fLight->flattenLight(buffer);
911 buffer.writeScalar(fSurfaceScale);
914 ///////////////////////////////////////////////////////////////////////////////
916 SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar kd, SkImageFilter* input, const CropRect* cropRect = NULL)
917 : SkLightingImageFilter(light, surfaceScale, input, cropRect),
918 // According to the spec, kd can be any non-negative number :
919 // http://www.w3.org/TR/SVG/filters.html#feDiffuseLightingElement
924 SkDiffuseLightingImageFilter::SkDiffuseLightingImageFilter(SkReadBuffer& buffer)
927 fKD = buffer.readScalar();
928 buffer.validate(SkScalarIsFinite(fKD) && (fKD >= 0));
931 void SkDiffuseLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
932 this->INHERITED::flatten(buffer);
933 buffer.writeScalar(fKD);
936 bool SkDiffuseLightingImageFilter::onFilterImage(Proxy* proxy,
937 const SkBitmap& source,
940 SkIPoint* offset) const {
941 SkImageFilter* input = getInput(0);
942 SkBitmap src = source;
943 SkIPoint srcOffset = SkIPoint::Make(0, 0);
944 if (input && !input->filterImage(proxy, source, ctx, &src, &srcOffset)) {
948 if (src.colorType() != kN32_SkColorType) {
952 if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
956 if (bounds.width() < 2 || bounds.height() < 2) {
960 SkAutoLockPixels alp(src);
961 if (!src.getPixels()) {
965 if (!dst->allocPixels(src.info().makeWH(bounds.width(), bounds.height()))) {
969 SkAutoTUnref<SkLight> transformedLight(light()->transform(ctx.ctm()));
971 DiffuseLightingType lightingType(fKD);
972 offset->fX = bounds.left();
973 offset->fY = bounds.top();
974 bounds.offset(-srcOffset);
975 switch (transformedLight->type()) {
976 case SkLight::kDistant_LightType:
977 lightBitmap<DiffuseLightingType, SkDistantLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
979 case SkLight::kPoint_LightType:
980 lightBitmap<DiffuseLightingType, SkPointLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
982 case SkLight::kSpot_LightType:
983 lightBitmap<DiffuseLightingType, SkSpotLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
991 bool SkDiffuseLightingImageFilter::asNewEffect(GrEffect** effect, GrTexture* texture,
992 const SkMatrix& matrix, const SkIRect&) const {
994 SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
995 *effect = GrDiffuseLightingEffect::Create(texture, light(), scale, matrix, kd());
1001 ///////////////////////////////////////////////////////////////////////////////
1003 SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkLight* light, SkScalar surfaceScale, SkScalar ks, SkScalar shininess, SkImageFilter* input, const CropRect* cropRect)
1004 : SkLightingImageFilter(light, surfaceScale, input, cropRect),
1005 // According to the spec, ks can be any non-negative number :
1006 // http://www.w3.org/TR/SVG/filters.html#feSpecularLightingElement
1007 fKS(ks < 0 ? 0 : ks),
1008 fShininess(shininess)
1012 SkSpecularLightingImageFilter::SkSpecularLightingImageFilter(SkReadBuffer& buffer)
1015 fKS = buffer.readScalar();
1016 fShininess = buffer.readScalar();
1017 buffer.validate(SkScalarIsFinite(fKS) && (fKS >= 0) &&
1018 SkScalarIsFinite(fShininess));
1021 void SkSpecularLightingImageFilter::flatten(SkWriteBuffer& buffer) const {
1022 this->INHERITED::flatten(buffer);
1023 buffer.writeScalar(fKS);
1024 buffer.writeScalar(fShininess);
1027 bool SkSpecularLightingImageFilter::onFilterImage(Proxy* proxy,
1028 const SkBitmap& source,
1031 SkIPoint* offset) const {
1032 SkImageFilter* input = getInput(0);
1033 SkBitmap src = source;
1034 SkIPoint srcOffset = SkIPoint::Make(0, 0);
1035 if (input && !input->filterImage(proxy, source, ctx, &src, &srcOffset)) {
1039 if (src.colorType() != kN32_SkColorType) {
1044 if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &bounds, &src)) {
1048 if (bounds.width() < 2 || bounds.height() < 2) {
1052 SkAutoLockPixels alp(src);
1053 if (!src.getPixels()) {
1057 if (!dst->allocPixels(src.info().makeWH(bounds.width(), bounds.height()))) {
1061 SpecularLightingType lightingType(fKS, fShininess);
1062 offset->fX = bounds.left();
1063 offset->fY = bounds.top();
1064 bounds.offset(-srcOffset);
1065 SkAutoTUnref<SkLight> transformedLight(light()->transform(ctx.ctm()));
1066 switch (transformedLight->type()) {
1067 case SkLight::kDistant_LightType:
1068 lightBitmap<SpecularLightingType, SkDistantLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
1070 case SkLight::kPoint_LightType:
1071 lightBitmap<SpecularLightingType, SkPointLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
1073 case SkLight::kSpot_LightType:
1074 lightBitmap<SpecularLightingType, SkSpotLight>(lightingType, transformedLight, src, dst, surfaceScale(), bounds);
1081 bool SkSpecularLightingImageFilter::asNewEffect(GrEffect** effect, GrTexture* texture,
1082 const SkMatrix& matrix, const SkIRect&) const {
1084 SkScalar scale = SkScalarMul(surfaceScale(), SkIntToScalar(255));
1085 *effect = GrSpecularLightingEffect::Create(texture, light(), scale, matrix, ks(), shininess());
1091 ///////////////////////////////////////////////////////////////////////////////
1096 SkPoint3 random_point3(SkRandom* random) {
1097 return SkPoint3(SkScalarToFloat(random->nextSScalar1()),
1098 SkScalarToFloat(random->nextSScalar1()),
1099 SkScalarToFloat(random->nextSScalar1()));
1102 SkLight* create_random_light(SkRandom* random) {
1103 int type = random->nextULessThan(3);
1106 return SkNEW_ARGS(SkDistantLight, (random_point3(random), random->nextU()));
1109 return SkNEW_ARGS(SkPointLight, (random_point3(random), random->nextU()));
1112 return SkNEW_ARGS(SkSpotLight, (random_point3(random),
1113 random_point3(random),
1114 random->nextUScalar1(),
1115 random->nextUScalar1(),
1119 SkFAIL("Unexpected value.");
1126 class GrGLLightingEffect : public GrGLEffect {
1128 GrGLLightingEffect(const GrBackendEffectFactory& factory,
1129 const GrDrawEffect& effect);
1130 virtual ~GrGLLightingEffect();
1132 virtual void emitCode(GrGLShaderBuilder*,
1133 const GrDrawEffect&,
1135 const char* outputColor,
1136 const char* inputColor,
1137 const TransformedCoordsArray&,
1138 const TextureSamplerArray&) SK_OVERRIDE;
1140 static inline void GenKey(const GrDrawEffect&, const GrGLCaps&, GrEffectKeyBuilder* b);
1143 * Subclasses of GrGLLightingEffect must call INHERITED::setData();
1145 virtual void setData(const GrGLProgramDataManager&, const GrDrawEffect&) SK_OVERRIDE;
1148 virtual void emitLightFunc(GrGLShaderBuilder*, SkString* funcName) = 0;
1151 typedef GrGLEffect INHERITED;
1153 UniformHandle fImageIncrementUni;
1154 UniformHandle fSurfaceScaleUni;
1158 ///////////////////////////////////////////////////////////////////////////////
1160 class GrGLDiffuseLightingEffect : public GrGLLightingEffect {
1162 GrGLDiffuseLightingEffect(const GrBackendEffectFactory& factory,
1163 const GrDrawEffect& drawEffect);
1164 virtual void emitLightFunc(GrGLShaderBuilder*, SkString* funcName) SK_OVERRIDE;
1165 virtual void setData(const GrGLProgramDataManager&, const GrDrawEffect&) SK_OVERRIDE;
1168 typedef GrGLLightingEffect INHERITED;
1170 UniformHandle fKDUni;
1173 ///////////////////////////////////////////////////////////////////////////////
1175 class GrGLSpecularLightingEffect : public GrGLLightingEffect {
1177 GrGLSpecularLightingEffect(const GrBackendEffectFactory& factory,
1178 const GrDrawEffect& effect);
1179 virtual void emitLightFunc(GrGLShaderBuilder*, SkString* funcName) SK_OVERRIDE;
1180 virtual void setData(const GrGLProgramDataManager&, const GrDrawEffect&) SK_OVERRIDE;
1183 typedef GrGLLightingEffect INHERITED;
1185 UniformHandle fKSUni;
1186 UniformHandle fShininessUni;
1189 ///////////////////////////////////////////////////////////////////////////////
1191 GrLightingEffect::GrLightingEffect(GrTexture* texture,
1192 const SkLight* light,
1193 SkScalar surfaceScale,
1194 const SkMatrix& matrix)
1195 : INHERITED(texture, MakeDivByTextureWHMatrix(texture))
1197 , fSurfaceScale(surfaceScale)
1198 , fFilterMatrix(matrix) {
1200 if (light->requiresFragmentPosition()) {
1201 this->setWillReadFragmentPosition();
1205 GrLightingEffect::~GrLightingEffect() {
1209 bool GrLightingEffect::onIsEqual(const GrEffect& sBase) const {
1210 const GrLightingEffect& s = CastEffect<GrLightingEffect>(sBase);
1211 return this->texture(0) == s.texture(0) &&
1212 fLight->isEqual(*s.fLight) &&
1213 fSurfaceScale == s.fSurfaceScale;
1216 ///////////////////////////////////////////////////////////////////////////////
1218 GrDiffuseLightingEffect::GrDiffuseLightingEffect(GrTexture* texture,
1219 const SkLight* light,
1220 SkScalar surfaceScale,
1221 const SkMatrix& matrix,
1223 : INHERITED(texture, light, surfaceScale, matrix), fKD(kd) {
1226 const GrBackendEffectFactory& GrDiffuseLightingEffect::getFactory() const {
1227 return GrTBackendEffectFactory<GrDiffuseLightingEffect>::getInstance();
1230 bool GrDiffuseLightingEffect::onIsEqual(const GrEffect& sBase) const {
1231 const GrDiffuseLightingEffect& s = CastEffect<GrDiffuseLightingEffect>(sBase);
1232 return INHERITED::onIsEqual(sBase) &&
1233 this->kd() == s.kd();
1236 GR_DEFINE_EFFECT_TEST(GrDiffuseLightingEffect);
1238 GrEffect* GrDiffuseLightingEffect::TestCreate(SkRandom* random,
1240 const GrDrawTargetCaps&,
1241 GrTexture* textures[]) {
1242 SkScalar surfaceScale = random->nextSScalar1();
1243 SkScalar kd = random->nextUScalar1();
1244 SkAutoTUnref<SkLight> light(create_random_light(random));
1246 for (int i = 0; i < 9; i++) {
1247 matrix[i] = random->nextUScalar1();
1249 return GrDiffuseLightingEffect::Create(textures[GrEffectUnitTest::kAlphaTextureIdx],
1250 light, surfaceScale, matrix, kd);
1254 ///////////////////////////////////////////////////////////////////////////////
1256 GrGLLightingEffect::GrGLLightingEffect(const GrBackendEffectFactory& factory,
1257 const GrDrawEffect& drawEffect)
1258 : INHERITED(factory) {
1259 const GrLightingEffect& m = drawEffect.castEffect<GrLightingEffect>();
1260 fLight = m.light()->createGLLight();
1263 GrGLLightingEffect::~GrGLLightingEffect() {
1267 void GrGLLightingEffect::emitCode(GrGLShaderBuilder* builder,
1268 const GrDrawEffect&,
1269 const GrEffectKey& key,
1270 const char* outputColor,
1271 const char* inputColor,
1272 const TransformedCoordsArray& coords,
1273 const TextureSamplerArray& samplers) {
1274 SkString coords2D = builder->ensureFSCoords2D(coords, 0);
1276 fImageIncrementUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
1279 fSurfaceScaleUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
1282 fLight->emitLightColorUniform(builder);
1284 this->emitLightFunc(builder, &lightFunc);
1285 static const GrGLShaderVar gSobelArgs[] = {
1286 GrGLShaderVar("a", kFloat_GrSLType),
1287 GrGLShaderVar("b", kFloat_GrSLType),
1288 GrGLShaderVar("c", kFloat_GrSLType),
1289 GrGLShaderVar("d", kFloat_GrSLType),
1290 GrGLShaderVar("e", kFloat_GrSLType),
1291 GrGLShaderVar("f", kFloat_GrSLType),
1292 GrGLShaderVar("scale", kFloat_GrSLType),
1294 SkString sobelFuncName;
1295 builder->fsEmitFunction(kFloat_GrSLType,
1297 SK_ARRAY_COUNT(gSobelArgs),
1299 "\treturn (-a + b - 2.0 * c + 2.0 * d -e + f) * scale;\n",
1301 static const GrGLShaderVar gPointToNormalArgs[] = {
1302 GrGLShaderVar("x", kFloat_GrSLType),
1303 GrGLShaderVar("y", kFloat_GrSLType),
1304 GrGLShaderVar("scale", kFloat_GrSLType),
1306 SkString pointToNormalName;
1307 builder->fsEmitFunction(kVec3f_GrSLType,
1309 SK_ARRAY_COUNT(gPointToNormalArgs),
1311 "\treturn normalize(vec3(-x * scale, y * scale, 1));\n",
1312 &pointToNormalName);
1314 static const GrGLShaderVar gInteriorNormalArgs[] = {
1315 GrGLShaderVar("m", kFloat_GrSLType, 9),
1316 GrGLShaderVar("surfaceScale", kFloat_GrSLType),
1318 SkString interiorNormalBody;
1319 interiorNormalBody.appendf("\treturn %s(%s(m[0], m[2], m[3], m[5], m[6], m[8], 0.25),\n"
1320 "\t %s(m[0], m[6], m[1], m[7], m[2], m[8], 0.25),\n"
1321 "\t surfaceScale);\n",
1322 pointToNormalName.c_str(),
1323 sobelFuncName.c_str(),
1324 sobelFuncName.c_str());
1325 SkString interiorNormalName;
1326 builder->fsEmitFunction(kVec3f_GrSLType,
1328 SK_ARRAY_COUNT(gInteriorNormalArgs),
1329 gInteriorNormalArgs,
1330 interiorNormalBody.c_str(),
1331 &interiorNormalName);
1333 builder->fsCodeAppendf("\t\tvec2 coord = %s;\n", coords2D.c_str());
1334 builder->fsCodeAppend("\t\tfloat m[9];\n");
1336 const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
1337 const char* surfScale = builder->getUniformCStr(fSurfaceScaleUni);
1340 for (int dy = -1; dy <= 1; dy++) {
1341 for (int dx = -1; dx <= 1; dx++) {
1343 texCoords.appendf("coord + vec2(%d, %d) * %s", dx, dy, imgInc);
1344 builder->fsCodeAppendf("\t\tm[%d] = ", index++);
1345 builder->fsAppendTextureLookup(samplers[0], texCoords.c_str());
1346 builder->fsCodeAppend(".a;\n");
1349 builder->fsCodeAppend("\t\tvec3 surfaceToLight = ");
1351 arg.appendf("%s * m[4]", surfScale);
1352 fLight->emitSurfaceToLight(builder, arg.c_str());
1353 builder->fsCodeAppend(";\n");
1354 builder->fsCodeAppendf("\t\t%s = %s(%s(m, %s), surfaceToLight, ",
1355 outputColor, lightFunc.c_str(), interiorNormalName.c_str(), surfScale);
1356 fLight->emitLightColor(builder, "surfaceToLight");
1357 builder->fsCodeAppend(");\n");
1359 GrGLSLMulVarBy4f(&modulate, 2, outputColor, inputColor);
1360 builder->fsCodeAppend(modulate.c_str());
1363 void GrGLLightingEffect::GenKey(const GrDrawEffect& drawEffect,
1364 const GrGLCaps& caps, GrEffectKeyBuilder* b) {
1365 b->add32(drawEffect.castEffect<GrLightingEffect>().light()->type());
1368 void GrGLLightingEffect::setData(const GrGLProgramDataManager& pdman,
1369 const GrDrawEffect& drawEffect) {
1370 const GrLightingEffect& lighting = drawEffect.castEffect<GrLightingEffect>();
1371 GrTexture* texture = lighting.texture(0);
1372 float ySign = texture->origin() == kTopLeft_GrSurfaceOrigin ? -1.0f : 1.0f;
1373 pdman.set2f(fImageIncrementUni, 1.0f / texture->width(), ySign / texture->height());
1374 pdman.set1f(fSurfaceScaleUni, lighting.surfaceScale());
1375 SkAutoTUnref<SkLight> transformedLight(lighting.light()->transform(lighting.filterMatrix()));
1376 fLight->setData(pdman, transformedLight);
1379 ///////////////////////////////////////////////////////////////////////////////
1381 ///////////////////////////////////////////////////////////////////////////////
1383 GrGLDiffuseLightingEffect::GrGLDiffuseLightingEffect(const GrBackendEffectFactory& factory,
1384 const GrDrawEffect& drawEffect)
1385 : INHERITED(factory, drawEffect) {
1388 void GrGLDiffuseLightingEffect::emitLightFunc(GrGLShaderBuilder* builder, SkString* funcName) {
1390 fKDUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
1395 static const GrGLShaderVar gLightArgs[] = {
1396 GrGLShaderVar("normal", kVec3f_GrSLType),
1397 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType),
1398 GrGLShaderVar("lightColor", kVec3f_GrSLType)
1401 lightBody.appendf("\tfloat colorScale = %s * dot(normal, surfaceToLight);\n", kd);
1402 lightBody.appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
1403 builder->fsEmitFunction(kVec4f_GrSLType,
1405 SK_ARRAY_COUNT(gLightArgs),
1411 void GrGLDiffuseLightingEffect::setData(const GrGLProgramDataManager& pdman,
1412 const GrDrawEffect& drawEffect) {
1413 INHERITED::setData(pdman, drawEffect);
1414 const GrDiffuseLightingEffect& diffuse = drawEffect.castEffect<GrDiffuseLightingEffect>();
1415 pdman.set1f(fKDUni, diffuse.kd());
1418 ///////////////////////////////////////////////////////////////////////////////
1420 GrSpecularLightingEffect::GrSpecularLightingEffect(GrTexture* texture,
1421 const SkLight* light,
1422 SkScalar surfaceScale,
1423 const SkMatrix& matrix,
1426 : INHERITED(texture, light, surfaceScale, matrix),
1428 fShininess(shininess) {
1431 const GrBackendEffectFactory& GrSpecularLightingEffect::getFactory() const {
1432 return GrTBackendEffectFactory<GrSpecularLightingEffect>::getInstance();
1435 bool GrSpecularLightingEffect::onIsEqual(const GrEffect& sBase) const {
1436 const GrSpecularLightingEffect& s = CastEffect<GrSpecularLightingEffect>(sBase);
1437 return INHERITED::onIsEqual(sBase) &&
1438 this->ks() == s.ks() &&
1439 this->shininess() == s.shininess();
1442 GR_DEFINE_EFFECT_TEST(GrSpecularLightingEffect);
1444 GrEffect* GrSpecularLightingEffect::TestCreate(SkRandom* random,
1446 const GrDrawTargetCaps&,
1447 GrTexture* textures[]) {
1448 SkScalar surfaceScale = random->nextSScalar1();
1449 SkScalar ks = random->nextUScalar1();
1450 SkScalar shininess = random->nextUScalar1();
1451 SkAutoTUnref<SkLight> light(create_random_light(random));
1453 for (int i = 0; i < 9; i++) {
1454 matrix[i] = random->nextUScalar1();
1456 return GrSpecularLightingEffect::Create(textures[GrEffectUnitTest::kAlphaTextureIdx],
1457 light, surfaceScale, matrix, ks, shininess);
1460 ///////////////////////////////////////////////////////////////////////////////
1462 GrGLSpecularLightingEffect::GrGLSpecularLightingEffect(const GrBackendEffectFactory& factory,
1463 const GrDrawEffect& drawEffect)
1464 : INHERITED(factory, drawEffect) {
1467 void GrGLSpecularLightingEffect::emitLightFunc(GrGLShaderBuilder* builder, SkString* funcName) {
1469 const char* shininess;
1471 fKSUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
1472 kFloat_GrSLType, "KS", &ks);
1473 fShininessUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
1474 kFloat_GrSLType, "Shininess", &shininess);
1476 static const GrGLShaderVar gLightArgs[] = {
1477 GrGLShaderVar("normal", kVec3f_GrSLType),
1478 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType),
1479 GrGLShaderVar("lightColor", kVec3f_GrSLType)
1482 lightBody.appendf("\tvec3 halfDir = vec3(normalize(surfaceToLight + vec3(0, 0, 1)));\n");
1483 lightBody.appendf("\tfloat colorScale = %s * pow(dot(normal, halfDir), %s);\n", ks, shininess);
1484 lightBody.appendf("\tvec3 color = lightColor * clamp(colorScale, 0.0, 1.0);\n");
1485 lightBody.appendf("\treturn vec4(color, max(max(color.r, color.g), color.b));\n");
1486 builder->fsEmitFunction(kVec4f_GrSLType,
1488 SK_ARRAY_COUNT(gLightArgs),
1494 void GrGLSpecularLightingEffect::setData(const GrGLProgramDataManager& pdman,
1495 const GrDrawEffect& drawEffect) {
1496 INHERITED::setData(pdman, drawEffect);
1497 const GrSpecularLightingEffect& spec = drawEffect.castEffect<GrSpecularLightingEffect>();
1498 pdman.set1f(fKSUni, spec.ks());
1499 pdman.set1f(fShininessUni, spec.shininess());
1502 ///////////////////////////////////////////////////////////////////////////////
1503 void GrGLLight::emitLightColorUniform(GrGLShaderBuilder* builder) {
1504 fColorUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
1505 kVec3f_GrSLType, "LightColor");
1508 void GrGLLight::emitLightColor(GrGLShaderBuilder* builder,
1509 const char *surfaceToLight) {
1510 builder->fsCodeAppend(builder->getUniformCStr(this->lightColorUni()));
1513 void GrGLLight::setData(const GrGLProgramDataManager& pdman,
1514 const SkLight* light) const {
1515 setUniformPoint3(pdman, fColorUni, light->color() * SkScalarInvert(SkIntToScalar(255)));
1518 ///////////////////////////////////////////////////////////////////////////////
1520 void GrGLDistantLight::setData(const GrGLProgramDataManager& pdman,
1521 const SkLight* light) const {
1522 INHERITED::setData(pdman, light);
1523 SkASSERT(light->type() == SkLight::kDistant_LightType);
1524 const SkDistantLight* distantLight = static_cast<const SkDistantLight*>(light);
1525 setUniformNormal3(pdman, fDirectionUni, distantLight->direction());
1528 void GrGLDistantLight::emitSurfaceToLight(GrGLShaderBuilder* builder, const char* z) {
1530 fDirectionUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, kVec3f_GrSLType,
1531 "LightDirection", &dir);
1532 builder->fsCodeAppend(dir);
1535 ///////////////////////////////////////////////////////////////////////////////
1537 void GrGLPointLight::setData(const GrGLProgramDataManager& pdman,
1538 const SkLight* light) const {
1539 INHERITED::setData(pdman, light);
1540 SkASSERT(light->type() == SkLight::kPoint_LightType);
1541 const SkPointLight* pointLight = static_cast<const SkPointLight*>(light);
1542 setUniformPoint3(pdman, fLocationUni, pointLight->location());
1545 void GrGLPointLight::emitSurfaceToLight(GrGLShaderBuilder* builder, const char* z) {
1547 fLocationUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, kVec3f_GrSLType,
1548 "LightLocation", &loc);
1549 builder->fsCodeAppendf("normalize(%s - vec3(%s.xy, %s))", loc, builder->fragmentPosition(), z);
1552 ///////////////////////////////////////////////////////////////////////////////
1554 void GrGLSpotLight::setData(const GrGLProgramDataManager& pdman,
1555 const SkLight* light) const {
1556 INHERITED::setData(pdman, light);
1557 SkASSERT(light->type() == SkLight::kSpot_LightType);
1558 const SkSpotLight* spotLight = static_cast<const SkSpotLight *>(light);
1559 setUniformPoint3(pdman, fLocationUni, spotLight->location());
1560 pdman.set1f(fExponentUni, spotLight->specularExponent());
1561 pdman.set1f(fCosInnerConeAngleUni, spotLight->cosInnerConeAngle());
1562 pdman.set1f(fCosOuterConeAngleUni, spotLight->cosOuterConeAngle());
1563 pdman.set1f(fConeScaleUni, spotLight->coneScale());
1564 setUniformNormal3(pdman, fSUni, spotLight->s());
1567 void GrGLSpotLight::emitSurfaceToLight(GrGLShaderBuilder* builder, const char* z) {
1568 const char* location;
1569 fLocationUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
1570 kVec3f_GrSLType, "LightLocation", &location);
1571 builder->fsCodeAppendf("normalize(%s - vec3(%s.xy, %s))",
1572 location, builder->fragmentPosition(), z);
1575 void GrGLSpotLight::emitLightColor(GrGLShaderBuilder* builder,
1576 const char *surfaceToLight) {
1578 const char* color = builder->getUniformCStr(this->lightColorUni()); // created by parent class.
1580 const char* exponent;
1581 const char* cosInner;
1582 const char* cosOuter;
1583 const char* coneScale;
1585 fExponentUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
1586 kFloat_GrSLType, "Exponent", &exponent);
1587 fCosInnerConeAngleUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
1588 kFloat_GrSLType, "CosInnerConeAngle", &cosInner);
1589 fCosOuterConeAngleUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
1590 kFloat_GrSLType, "CosOuterConeAngle", &cosOuter);
1591 fConeScaleUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
1592 kFloat_GrSLType, "ConeScale", &coneScale);
1593 fSUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
1594 kVec3f_GrSLType, "S", &s);
1596 static const GrGLShaderVar gLightColorArgs[] = {
1597 GrGLShaderVar("surfaceToLight", kVec3f_GrSLType)
1599 SkString lightColorBody;
1600 lightColorBody.appendf("\tfloat cosAngle = -dot(surfaceToLight, %s);\n", s);
1601 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosOuter);
1602 lightColorBody.appendf("\t\treturn vec3(0);\n");
1603 lightColorBody.appendf("\t}\n");
1604 lightColorBody.appendf("\tfloat scale = pow(cosAngle, %s);\n", exponent);
1605 lightColorBody.appendf("\tif (cosAngle < %s) {\n", cosInner);
1606 lightColorBody.appendf("\t\treturn %s * scale * (cosAngle - %s) * %s;\n",
1607 color, cosOuter, coneScale);
1608 lightColorBody.appendf("\t}\n");
1609 lightColorBody.appendf("\treturn %s;\n", color);
1610 builder->fsEmitFunction(kVec3f_GrSLType,
1612 SK_ARRAY_COUNT(gLightColorArgs),
1614 lightColorBody.c_str(),
1617 builder->fsCodeAppendf("%s(%s)", fLightColorFunc.c_str(), surfaceToLight);
1622 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingImageFilter)
1623 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDiffuseLightingImageFilter)
1624 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSpecularLightingImageFilter)
1625 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END