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