147a7ef915cb2e98076dab4ab9df2d492c1a6472
[platform/upstream/libSkiaSharp.git] / src / core / SkLightingShader.cpp
1
2 /*
3  * Copyright 2015 Google Inc.
4  *
5  * Use of this source code is governed by a BSD-style license that can be
6  * found in the LICENSE file.
7  */
8
9 #include "SkBitmapProcState.h"
10 #include "SkColor.h"
11 #include "SkEmptyShader.h"
12 #include "SkErrorInternals.h"
13 #include "SkLightingShader.h"
14 #include "SkMathPriv.h"
15 #include "SkPoint3.h"
16 #include "SkReadBuffer.h"
17 #include "SkWriteBuffer.h"
18
19 ////////////////////////////////////////////////////////////////////////////
20
21 /*
22    SkLightingShader TODOs:
23         support other than clamp mode
24         allow 'diffuse' & 'normal' to be of different dimensions?
25         support different light types
26         support multiple lights
27         enforce normal map is 4 channel
28         use SkImages instead if SkBitmaps
29
30     To Test:
31         non-opaque diffuse textures
32         A8 diffuse textures
33         down & upsampled draws
34 */
35
36
37
38 /** \class SkLightingShaderImpl
39     This subclass of shader applies lighting.
40 */
41 class SK_API SkLightingShaderImpl : public SkShader {
42 public:
43
44     /** Create a new lighting shader that uses the provided normal map and
45         lights to light the diffuse bitmap.
46         @param diffuse    the diffuse bitmap
47         @param normal     the normal map
48         @param lights     the lights applied to the normal map
49         @param invNormRotation rotation applied to the normal map's normals
50         @param diffLocalM the local matrix for the diffuse coordinates
51         @param normLocalM the local matrix for the normal coordinates
52     */
53     SkLightingShaderImpl(const SkBitmap& diffuse, const SkBitmap& normal,
54                          const SkLightingShader::Lights* lights,
55                          const SkVector& invNormRotation,
56                          const SkMatrix* diffLocalM, const SkMatrix* normLocalM) 
57         : INHERITED(diffLocalM)
58         , fDiffuseMap(diffuse)
59         , fNormalMap(normal)
60         , fLights(SkRef(lights))
61         , fInvNormRotation(invNormRotation) {
62
63         if (normLocalM) {
64             fNormLocalMatrix = *normLocalM;
65         } else {
66             fNormLocalMatrix.reset();
67         }
68         // Pre-cache so future calls to fNormLocalMatrix.getType() are threadsafe.
69         (void)fNormLocalMatrix.getType();
70
71     }
72
73     bool isOpaque() const override;
74
75 #if SK_SUPPORT_GPU
76     const GrFragmentProcessor* asFragmentProcessor(GrContext*,
77                                                    const SkMatrix& viewM,
78                                                    const SkMatrix* localMatrix,
79                                                    SkFilterQuality) const override;
80 #endif
81
82     size_t contextSize() const override;
83
84     class LightingShaderContext : public SkShader::Context {
85     public:
86         // The context takes ownership of the states. It will call their destructors
87         // but will NOT free the memory.
88         LightingShaderContext(const SkLightingShaderImpl&, const ContextRec&,
89                               SkBitmapProcState* diffuseState, SkBitmapProcState* normalState);
90         ~LightingShaderContext() override;
91
92         void shadeSpan(int x, int y, SkPMColor[], int count) override;
93
94         uint32_t getFlags() const override { return fFlags; }
95
96     private:
97         SkBitmapProcState* fDiffuseState;
98         SkBitmapProcState* fNormalState;
99         uint32_t           fFlags;
100
101         typedef SkShader::Context INHERITED;
102     };
103
104     SK_TO_STRING_OVERRIDE()
105     SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkLightingShaderImpl)
106
107 protected:
108     void flatten(SkWriteBuffer&) const override;
109     Context* onCreateContext(const ContextRec&, void*) const override;
110     bool computeNormTotalInverse(const ContextRec& rec, SkMatrix* normTotalInverse) const;
111
112 private:
113     SkBitmap  fDiffuseMap;
114     SkBitmap  fNormalMap;
115
116     SkAutoTUnref<const SkLightingShader::Lights>   fLights;
117
118     SkMatrix  fNormLocalMatrix;
119     SkVector  fInvNormRotation;
120
121     friend class SkLightingShader;
122
123     typedef SkShader INHERITED;
124 };
125
126 ////////////////////////////////////////////////////////////////////////////
127
128 #if SK_SUPPORT_GPU
129
130 #include "GrCoordTransform.h"
131 #include "GrFragmentProcessor.h"
132 #include "GrTextureAccess.h"
133 #include "glsl/GrGLSLFragmentProcessor.h"
134 #include "glsl/GrGLSLFragmentShaderBuilder.h"
135 #include "glsl/GrGLSLProgramBuilder.h"
136 #include "glsl/GrGLSLProgramDataManager.h"
137 #include "SkGr.h"
138 #include "SkGrPriv.h"
139
140 class LightingFP : public GrFragmentProcessor {
141 public:
142     LightingFP(GrTexture* diffuse, GrTexture* normal, const SkMatrix& diffMatrix,
143                const SkMatrix& normMatrix, const GrTextureParams& diffParams,
144                const GrTextureParams& normParams, const SkLightingShader::Lights* lights,
145                const SkVector& invNormRotation)
146         : fDiffDeviceTransform(kLocal_GrCoordSet, diffMatrix, diffuse, diffParams.filterMode())
147         , fNormDeviceTransform(kLocal_GrCoordSet, normMatrix, normal, normParams.filterMode())
148         , fDiffuseTextureAccess(diffuse, diffParams)
149         , fNormalTextureAccess(normal, normParams)
150         , fInvNormRotation(invNormRotation) {
151         this->addCoordTransform(&fDiffDeviceTransform);
152         this->addCoordTransform(&fNormDeviceTransform);
153         this->addTextureAccess(&fDiffuseTextureAccess);
154         this->addTextureAccess(&fNormalTextureAccess);
155
156         // fuse all ambient lights into a single one
157         fAmbientColor.set(0.0f, 0.0f, 0.0f);
158         for (int i = 0; i < lights->numLights(); ++i) {
159             if (SkLight::kAmbient_LightType == lights->light(i).type()) {
160                 fAmbientColor += lights->light(i).color();
161             } else {
162                 // TODO: handle more than one of these
163                 fLightColor = lights->light(i).color();
164                 fLightDir = lights->light(i).dir();
165             }
166         }
167
168         this->initClassID<LightingFP>();
169     }
170
171     class LightingGLFP : public GrGLSLFragmentProcessor {
172     public:
173         LightingGLFP() {
174             fLightDir.fX = 10000.0f;
175             fLightColor.fX = 0.0f;
176             fAmbientColor.fX = 0.0f;
177             fInvNormRotation.set(0.0f, 0.0f);
178         }
179
180         void emitCode(EmitArgs& args) override {
181
182             GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
183
184             // add uniforms
185             const char* lightDirUniName = nullptr;
186             fLightDirUni = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility,
187                                                      kVec3f_GrSLType, kDefault_GrSLPrecision,
188                                                      "LightDir", &lightDirUniName);
189
190             const char* lightColorUniName = nullptr;
191             fLightColorUni = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility,
192                                                        kVec3f_GrSLType, kDefault_GrSLPrecision,
193                                                        "LightColor", &lightColorUniName);
194
195             const char* ambientColorUniName = nullptr;
196             fAmbientColorUni = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility,
197                                                          kVec3f_GrSLType, kDefault_GrSLPrecision,
198                                                          "AmbientColor", &ambientColorUniName);
199
200             const char* xformUniName = nullptr;
201             fXformUni = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility,
202                                                   kVec2f_GrSLType, kDefault_GrSLPrecision,
203                                                   "Xform", &xformUniName);
204
205             fragBuilder->codeAppend("vec4 diffuseColor = ");
206             fragBuilder->appendTextureLookupAndModulate(args.fInputColor, args.fSamplers[0], 
207                                                 args.fCoords[0].c_str(), 
208                                                 args.fCoords[0].getType());
209             fragBuilder->codeAppend(";");
210
211             fragBuilder->codeAppend("vec4 normalColor = ");
212             fragBuilder->appendTextureLookup(args.fSamplers[1],
213                                      args.fCoords[1].c_str(), 
214                                      args.fCoords[1].getType());
215             fragBuilder->codeAppend(";");
216
217             fragBuilder->codeAppend("vec3 normal = normalColor.rgb - vec3(0.5);");
218
219             fragBuilder->codeAppendf(
220                                  "mat3 m = mat3(%s.x, -%s.y, 0.0, %s.y, %s.x, 0.0, 0.0, 0.0, 1.0);",
221                                  xformUniName, xformUniName, xformUniName, xformUniName);
222             
223             // TODO: inverse map the light direction vectors in the vertex shader rather than
224             // transforming all the normals here!
225             fragBuilder->codeAppend("normal = normalize(m*normal);");
226
227             fragBuilder->codeAppendf("float NdotL = clamp(dot(normal, %s), 0.0, 1.0);",
228                                      lightDirUniName);
229             // diffuse light
230             fragBuilder->codeAppendf("vec3 result = %s*diffuseColor.rgb*NdotL;", lightColorUniName);
231             // ambient light
232             fragBuilder->codeAppendf("result += %s;", ambientColorUniName);
233             fragBuilder->codeAppendf("%s = vec4(result.rgb, diffuseColor.a);", args.fOutputColor);
234         }
235
236         static void GenKey(const GrProcessor& proc, const GrGLSLCaps&,
237                            GrProcessorKeyBuilder* b) {
238 //            const LightingFP& lightingFP = proc.cast<LightingFP>();
239             // only one shader generated currently
240             b->add32(0x0);
241         }
242
243     protected:
244         void onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor& proc) override {
245             const LightingFP& lightingFP = proc.cast<LightingFP>();
246
247             const SkVector3& lightDir = lightingFP.lightDir();
248             if (lightDir != fLightDir) {
249                 pdman.set3fv(fLightDirUni, 1, &lightDir.fX);
250                 fLightDir = lightDir;
251             }
252
253             const SkColor3f& lightColor = lightingFP.lightColor();
254             if (lightColor != fLightColor) {
255                 pdman.set3fv(fLightColorUni, 1, &lightColor.fX);
256                 fLightColor = lightColor;
257             }
258
259             const SkColor3f& ambientColor = lightingFP.ambientColor();
260             if (ambientColor != fAmbientColor) {
261                 pdman.set3fv(fAmbientColorUni, 1, &ambientColor.fX);
262                 fAmbientColor = ambientColor;
263             }
264
265             const SkVector& invNormRotation = lightingFP.invNormRotation();
266             if (invNormRotation != fInvNormRotation) {
267                 pdman.set2fv(fXformUni, 1, &invNormRotation.fX);
268                 fInvNormRotation = invNormRotation;
269             }
270         }
271
272     private:
273         SkVector3 fLightDir;
274         GrGLSLProgramDataManager::UniformHandle fLightDirUni;
275
276         SkColor3f fLightColor;
277         GrGLSLProgramDataManager::UniformHandle fLightColorUni;
278
279         SkColor3f fAmbientColor;
280         GrGLSLProgramDataManager::UniformHandle fAmbientColorUni;
281
282         SkVector fInvNormRotation;
283         GrGLSLProgramDataManager::UniformHandle fXformUni;
284     };
285
286     void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override {
287         LightingGLFP::GenKey(*this, caps, b);
288     }
289
290     const char* name() const override { return "LightingFP"; }
291
292     void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
293         inout->mulByUnknownFourComponents();
294     }
295
296     const SkVector3& lightDir() const { return fLightDir; }
297     const SkColor3f& lightColor() const { return fLightColor; }
298     const SkColor3f& ambientColor() const { return fAmbientColor; }
299     const SkVector& invNormRotation() const { return fInvNormRotation; }
300
301 private:
302     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { return new LightingGLFP; }
303
304     bool onIsEqual(const GrFragmentProcessor& proc) const override { 
305         const LightingFP& lightingFP = proc.cast<LightingFP>();
306         return fDiffDeviceTransform == lightingFP.fDiffDeviceTransform &&
307                fNormDeviceTransform == lightingFP.fNormDeviceTransform &&
308                fDiffuseTextureAccess == lightingFP.fDiffuseTextureAccess &&
309                fNormalTextureAccess == lightingFP.fNormalTextureAccess &&
310                fLightDir == lightingFP.fLightDir &&
311                fLightColor == lightingFP.fLightColor &&
312                fAmbientColor == lightingFP.fAmbientColor &&
313                fInvNormRotation == lightingFP.fInvNormRotation;
314     }
315
316     GrCoordTransform fDiffDeviceTransform;
317     GrCoordTransform fNormDeviceTransform;
318     GrTextureAccess  fDiffuseTextureAccess;
319     GrTextureAccess  fNormalTextureAccess;
320     SkVector3        fLightDir;
321     SkColor3f        fLightColor;
322     SkColor3f        fAmbientColor;
323
324     SkVector         fInvNormRotation;
325 };
326
327 ////////////////////////////////////////////////////////////////////////////
328
329 static bool make_mat(const SkBitmap& bm,
330                      const SkMatrix& localMatrix1,
331                      const SkMatrix* localMatrix2,
332                      SkMatrix* result) {
333     
334     result->setIDiv(bm.width(), bm.height());
335
336     SkMatrix lmInverse;
337     if (!localMatrix1.invert(&lmInverse)) {
338         return false;
339     }
340     if (localMatrix2) {
341         SkMatrix inv;
342         if (!localMatrix2->invert(&inv)) {
343             return false;
344         }
345         lmInverse.postConcat(inv);
346     }
347     result->preConcat(lmInverse);
348
349     return true;
350 }
351
352 const GrFragmentProcessor* SkLightingShaderImpl::asFragmentProcessor(
353                                                              GrContext* context,
354                                                              const SkMatrix& viewM,
355                                                              const SkMatrix* localMatrix,
356                                                              SkFilterQuality filterQuality) const {
357     // we assume diffuse and normal maps have same width and height
358     // TODO: support different sizes
359     SkASSERT(fDiffuseMap.width() == fNormalMap.width() &&
360              fDiffuseMap.height() == fNormalMap.height());
361     SkMatrix diffM, normM;
362     
363     if (!make_mat(fDiffuseMap, this->getLocalMatrix(), localMatrix, &diffM)) {
364         return nullptr;
365     }
366
367     if (!make_mat(fNormalMap, fNormLocalMatrix, localMatrix, &normM)) {
368         return nullptr;
369     }
370
371     bool doBicubic;
372     GrTextureParams::FilterMode diffFilterMode = GrSkFilterQualityToGrFilterMode(
373                                         SkTMin(filterQuality, kMedium_SkFilterQuality), 
374                                         viewM,
375                                         this->getLocalMatrix(),
376                                         &doBicubic); 
377     SkASSERT(!doBicubic);
378
379     GrTextureParams::FilterMode normFilterMode = GrSkFilterQualityToGrFilterMode(
380                                         SkTMin(filterQuality, kMedium_SkFilterQuality), 
381                                         viewM,
382                                         fNormLocalMatrix,
383                                         &doBicubic); 
384     SkASSERT(!doBicubic);
385
386     // TODO: support other tile modes
387     GrTextureParams diffParams(kClamp_TileMode, diffFilterMode);
388     SkAutoTUnref<GrTexture> diffuseTexture(GrRefCachedBitmapTexture(context,
389                                                                     fDiffuseMap, diffParams));
390     if (!diffuseTexture) {
391         SkErrorInternals::SetError(kInternalError_SkError, "Couldn't convert bitmap to texture.");
392         return nullptr;
393     }
394
395     GrTextureParams normParams(kClamp_TileMode, normFilterMode);
396     SkAutoTUnref<GrTexture> normalTexture(GrRefCachedBitmapTexture(context,
397                                                                    fNormalMap, normParams));
398     if (!normalTexture) {
399         SkErrorInternals::SetError(kInternalError_SkError, "Couldn't convert bitmap to texture.");
400         return nullptr;
401     }
402
403     SkAutoTUnref<const GrFragmentProcessor> inner (
404         new LightingFP(diffuseTexture, normalTexture, diffM, normM, diffParams, normParams, fLights,
405                        fInvNormRotation));
406     return GrFragmentProcessor::MulOutputByInputAlpha(inner);
407 }
408
409 #endif
410
411 ////////////////////////////////////////////////////////////////////////////
412
413 bool SkLightingShaderImpl::isOpaque() const {
414     return fDiffuseMap.isOpaque();
415 }
416
417 size_t SkLightingShaderImpl::contextSize() const {
418     return 2 * sizeof(SkBitmapProcState) + sizeof(LightingShaderContext);
419 }
420
421 SkLightingShaderImpl::LightingShaderContext::LightingShaderContext(const SkLightingShaderImpl& shader,
422                                                                    const ContextRec& rec,
423                                                                    SkBitmapProcState* diffuseState,
424                                                                    SkBitmapProcState* normalState)
425     : INHERITED(shader, rec)
426     , fDiffuseState(diffuseState)
427     , fNormalState(normalState)
428 {
429     const SkPixmap& pixmap = fDiffuseState->fPixmap;
430     bool isOpaque = pixmap.isOpaque();
431
432     // update fFlags
433     uint32_t flags = 0;
434     if (isOpaque && (255 == this->getPaintAlpha())) {
435         flags |= kOpaqueAlpha_Flag;
436     }
437
438     fFlags = flags;
439 }
440
441 SkLightingShaderImpl::LightingShaderContext::~LightingShaderContext() {
442     // The bitmap proc states have been created outside of the context on memory that will be freed
443     // elsewhere. Call the destructors but leave the freeing of the memory to the caller.
444     fDiffuseState->~SkBitmapProcState();
445     fNormalState->~SkBitmapProcState();
446 }
447
448 static inline SkPMColor convert(SkColor3f color, U8CPU a) {
449     if (color.fX <= 0.0f) {
450         color.fX = 0.0f;
451     } else if (color.fX >= 255.0f) {
452         color.fX = 255.0f;
453     } 
454
455     if (color.fY <= 0.0f) {
456         color.fY = 0.0f;
457     } else if (color.fY >= 255.0f) {
458         color.fY = 255.0f;
459     } 
460
461     if (color.fZ <= 0.0f) {
462         color.fZ = 0.0f;
463     } else if (color.fZ >= 255.0f) {
464         color.fZ = 255.0f;
465     } 
466
467     return SkPreMultiplyARGB(a, (int) color.fX,  (int) color.fY, (int) color.fZ);
468 }
469
470 // larger is better (fewer times we have to loop), but we shouldn't
471 // take up too much stack-space (each one here costs 16 bytes)
472 #define TMP_COUNT     16
473
474 void SkLightingShaderImpl::LightingShaderContext::shadeSpan(int x, int y,
475                                                             SkPMColor result[], int count) {
476     const SkLightingShaderImpl& lightShader = static_cast<const SkLightingShaderImpl&>(fShader);
477
478     uint32_t  tmpColor[TMP_COUNT], tmpNormal[TMP_COUNT];
479     SkPMColor tmpColor2[2*TMP_COUNT], tmpNormal2[2*TMP_COUNT];
480
481     SkBitmapProcState::MatrixProc   diffMProc = fDiffuseState->getMatrixProc();
482     SkBitmapProcState::SampleProc32 diffSProc = fDiffuseState->getSampleProc32();
483
484     SkBitmapProcState::MatrixProc   normalMProc = fNormalState->getMatrixProc();
485     SkBitmapProcState::SampleProc32 normalSProc = fNormalState->getSampleProc32();
486
487     int diffMax = fDiffuseState->maxCountForBufferSize(sizeof(tmpColor[0]) * TMP_COUNT);
488     int normMax = fNormalState->maxCountForBufferSize(sizeof(tmpNormal[0]) * TMP_COUNT);
489     int max = SkTMin(diffMax, normMax);
490
491     SkASSERT(fDiffuseState->fPixmap.addr());
492     SkASSERT(fNormalState->fPixmap.addr());
493
494     SkPoint3 norm, xformedNorm;
495
496     do {
497         int n = count;
498         if (n > max) {
499             n = max;
500         }
501
502         diffMProc(*fDiffuseState, tmpColor, n, x, y);
503         diffSProc(*fDiffuseState, tmpColor, n, tmpColor2);
504
505         normalMProc(*fNormalState, tmpNormal, n, x, y);
506         normalSProc(*fNormalState, tmpNormal, n, tmpNormal2);
507
508         for (int i = 0; i < n; ++i) {
509             SkASSERT(0xFF == SkColorGetA(tmpNormal2[i]));  // opaque -> unpremul
510             norm.set(SkIntToScalar(SkGetPackedR32(tmpNormal2[i]))-127.0f,
511                      SkIntToScalar(SkGetPackedG32(tmpNormal2[i]))-127.0f,
512                      SkIntToScalar(SkGetPackedB32(tmpNormal2[i]))-127.0f);
513             norm.normalize();
514
515             xformedNorm.fX = lightShader.fInvNormRotation.fX * norm.fX +
516                              lightShader.fInvNormRotation.fY * norm.fY;
517             xformedNorm.fY = lightShader.fInvNormRotation.fX * norm.fX - 
518                              lightShader.fInvNormRotation.fY * norm.fY;
519             xformedNorm.fZ = norm.fZ;
520
521             SkColor diffColor = SkUnPreMultiply::PMColorToColor(tmpColor2[i]);
522
523             SkColor3f accum = SkColor3f::Make(0.0f, 0.0f, 0.0f);
524             // This is all done in linear unpremul color space (each component 0..255.0f though)
525             for (int l = 0; l < lightShader.fLights->numLights(); ++l) {
526                 const SkLight& light = lightShader.fLights->light(l);
527
528                 if (SkLight::kAmbient_LightType == light.type()) {
529                     accum += light.color().makeScale(255.0f);
530                 } else {
531                     SkScalar NdotL = xformedNorm.dot(light.dir());
532                     if (NdotL < 0.0f) {
533                         NdotL = 0.0f;
534                     }
535
536                     accum.fX += light.color().fX * SkColorGetR(diffColor) * NdotL;
537                     accum.fY += light.color().fY * SkColorGetG(diffColor) * NdotL;
538                     accum.fZ += light.color().fZ * SkColorGetB(diffColor) * NdotL;
539                 }
540             }
541
542             result[i] = convert(accum, SkColorGetA(diffColor));
543         }
544
545         result += n;
546         x += n;
547         count -= n;
548     } while (count > 0);
549 }
550
551 ////////////////////////////////////////////////////////////////////////////
552
553 #ifndef SK_IGNORE_TO_STRING
554 void SkLightingShaderImpl::toString(SkString* str) const {
555     str->appendf("LightingShader: ()");
556 }
557 #endif
558
559 SkFlattenable* SkLightingShaderImpl::CreateProc(SkReadBuffer& buf) {
560     SkMatrix diffLocalM;
561     bool hasDiffLocalM = buf.readBool();
562     if (hasDiffLocalM) {
563         buf.readMatrix(&diffLocalM);
564     } else {
565         diffLocalM.reset();
566     }
567
568     SkMatrix normLocalM;
569     bool hasNormLocalM = buf.readBool();
570     if (hasNormLocalM) {
571         buf.readMatrix(&normLocalM);
572     } else {
573         normLocalM.reset();
574     }
575
576     SkBitmap diffuse;
577     if (!buf.readBitmap(&diffuse)) {
578         return nullptr;
579     }
580     diffuse.setImmutable();
581
582     SkBitmap normal;
583     if (!buf.readBitmap(&normal)) {
584         return nullptr;
585     }
586     normal.setImmutable();
587
588     int numLights = buf.readInt();
589
590     SkLightingShader::Lights::Builder builder;
591
592     for (int l = 0; l < numLights; ++l) {
593         bool isAmbient = buf.readBool();
594
595         SkColor3f color;
596         if (!buf.readScalarArray(&color.fX, 3)) {
597             return nullptr;
598         }
599
600         if (isAmbient) {
601             builder.add(SkLight(color));
602         } else {
603             SkVector3 dir;
604             if (!buf.readScalarArray(&dir.fX, 3)) {
605                 return nullptr;
606             }
607             builder.add(SkLight(color, dir));        
608         }
609     }
610
611     SkAutoTUnref<const SkLightingShader::Lights> lights(builder.finish());
612
613     return new SkLightingShaderImpl(diffuse, normal, lights, SkVector::Make(1.0f, 0.0f),
614                                     &diffLocalM, &normLocalM);
615 }
616
617 void SkLightingShaderImpl::flatten(SkWriteBuffer& buf) const {
618     this->INHERITED::flatten(buf);
619
620     bool hasNormLocalM = !fNormLocalMatrix.isIdentity();
621     buf.writeBool(hasNormLocalM);
622     if (hasNormLocalM) {
623         buf.writeMatrix(fNormLocalMatrix);
624     }
625
626     buf.writeBitmap(fDiffuseMap);
627     buf.writeBitmap(fNormalMap);
628
629     buf.writeInt(fLights->numLights());
630     for (int l = 0; l < fLights->numLights(); ++l) {
631         const SkLight& light = fLights->light(l);
632
633         bool isAmbient = SkLight::kAmbient_LightType == light.type();
634
635         buf.writeBool(isAmbient);
636         buf.writeScalarArray(&light.color().fX, 3);
637         if (!isAmbient) {
638             buf.writeScalarArray(&light.dir().fX, 3);
639         }
640     }
641 }
642
643 bool SkLightingShaderImpl::computeNormTotalInverse(const ContextRec& rec,
644                                                    SkMatrix* normTotalInverse) const {
645     SkMatrix total;
646     total.setConcat(*rec.fMatrix, fNormLocalMatrix);
647
648     const SkMatrix* m = &total;
649     if (rec.fLocalMatrix) {
650         total.setConcat(*m, *rec.fLocalMatrix);
651         m = &total;
652     }
653     return m->invert(normTotalInverse);
654 }
655
656 SkShader::Context* SkLightingShaderImpl::onCreateContext(const ContextRec& rec,
657                                                          void* storage) const {
658
659     SkMatrix diffTotalInv;
660     // computeTotalInverse was called in SkShader::createContext so we know it will succeed
661     SkAssertResult(this->computeTotalInverse(rec, &diffTotalInv));
662
663     SkMatrix normTotalInv;
664     if (!this->computeNormTotalInverse(rec, &normTotalInv)) {
665         return nullptr;
666     }
667
668     void* diffuseStateStorage = (char*)storage + sizeof(LightingShaderContext);
669     SkBitmapProcState* diffuseState = new (diffuseStateStorage) SkBitmapProcState(fDiffuseMap,
670                                               SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
671     SkASSERT(diffuseState);
672     if (!diffuseState->chooseProcs(diffTotalInv, *rec.fPaint)) {
673         diffuseState->~SkBitmapProcState();
674         return nullptr;
675     }
676
677     void* normalStateStorage = (char*)storage + sizeof(LightingShaderContext) + sizeof(SkBitmapProcState);
678     SkBitmapProcState* normalState = new (normalStateStorage) SkBitmapProcState(fNormalMap,
679                                             SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
680     SkASSERT(normalState);
681     if (!normalState->chooseProcs(normTotalInv, *rec.fPaint)) {
682         diffuseState->~SkBitmapProcState();
683         normalState->~SkBitmapProcState();
684         return nullptr;
685     }
686
687     return new (storage) LightingShaderContext(*this, rec, diffuseState, normalState);
688 }
689
690 ///////////////////////////////////////////////////////////////////////////////
691
692 static bool bitmap_is_too_big(const SkBitmap& bm) {
693     // SkBitmapProcShader stores bitmap coordinates in a 16bit buffer, as it
694     // communicates between its matrix-proc and its sampler-proc. Until we can
695     // widen that, we have to reject bitmaps that are larger.
696     //
697     static const int kMaxSize = 65535;
698
699     return bm.width() > kMaxSize || bm.height() > kMaxSize;
700 }
701
702 SkShader* SkLightingShader::Create(const SkBitmap& diffuse, const SkBitmap& normal,
703                                    const Lights* lights,
704                                    const SkVector& invNormRotation,
705                                    const SkMatrix* diffLocalM, const SkMatrix* normLocalM) {
706     if (diffuse.isNull() || bitmap_is_too_big(diffuse) ||
707         normal.isNull() || bitmap_is_too_big(normal) ||
708         diffuse.width() != normal.width() ||
709         diffuse.height() != normal.height()) {
710         return nullptr;
711     }
712
713     SkASSERT(SkScalarNearlyEqual(invNormRotation.lengthSqd(), SK_Scalar1));
714
715     return new SkLightingShaderImpl(diffuse, normal, lights, invNormRotation, diffLocalM,
716                                     normLocalM);
717 }
718
719 ///////////////////////////////////////////////////////////////////////////////
720
721 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLightingShader)
722     SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLightingShaderImpl)
723 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
724
725 ///////////////////////////////////////////////////////////////////////////////