| OLD | NEW | 
|---|
|  | (Empty) | 
| 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 #include "SampleCode.h" |  | 
| 9 #include "Resources.h" |  | 
| 10 |  | 
| 11 #include "SkCanvas.h" |  | 
| 12 #include "SkErrorInternals.h" |  | 
| 13 #include "SkGr.h" |  | 
| 14 #include "SkReadBuffer.h" |  | 
| 15 #include "SkShader.h" |  | 
| 16 #include "SkWriteBuffer.h" |  | 
| 17 |  | 
| 18 #include "GrFragmentProcessor.h" |  | 
| 19 #include "GrCoordTransform.h" |  | 
| 20 #include "gl/GrGLProcessor.h" |  | 
| 21 #include "gl/builders/GrGLProgramBuilder.h" |  | 
| 22 |  | 
| 23 /////////////////////////////////////////////////////////////////////////////// |  | 
| 24 |  | 
| 25 struct SkVector3 { |  | 
| 26     SkScalar fX, fY, fZ; |  | 
| 27 |  | 
| 28     bool operator==(const SkVector3& other) const { |  | 
| 29         return fX == other.fX && fY == other.fY && fZ == other.fZ; |  | 
| 30     } |  | 
| 31 |  | 
| 32     bool operator!=(const SkVector3& other) const { |  | 
| 33         return !(*this == other); |  | 
| 34     } |  | 
| 35 }; |  | 
| 36 |  | 
| 37 class LightingShader : public SkShader { |  | 
| 38 public: |  | 
| 39     struct Light { |  | 
| 40         SkVector3   fDirection; |  | 
| 41         SkColor     fColor;           // assumed to be linear color |  | 
| 42     }; |  | 
| 43 |  | 
| 44     LightingShader(const SkBitmap& diffuse, const SkBitmap& normal, const Light&
      light, |  | 
| 45                    const SkColor ambient) |  | 
| 46         : fDiffuseMap(diffuse) |  | 
| 47         , fNormalMap(normal) |  | 
| 48         , fLight(light) |  | 
| 49         , fAmbientColor(ambient) {} |  | 
| 50 |  | 
| 51     SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(LightingShader); |  | 
| 52 |  | 
| 53     void flatten(SkWriteBuffer& buf) const override { |  | 
| 54         buf.writeBitmap(fDiffuseMap); |  | 
| 55         buf.writeBitmap(fNormalMap); |  | 
| 56         buf.writeScalarArray(&fLight.fDirection.fX, 3); |  | 
| 57         buf.writeColor(fLight.fColor); |  | 
| 58         buf.writeColor(fAmbientColor); |  | 
| 59     } |  | 
| 60 |  | 
| 61     bool asFragmentProcessor(GrContext*, const SkPaint& paint, const SkMatrix& v
     iewM, |  | 
| 62                              const SkMatrix* localMatrix, GrColor* color, |  | 
| 63                              GrShaderDataManager*, GrFragmentProcessor** fp) con
     st override; |  | 
| 64 |  | 
| 65     SkShader::BitmapType asABitmap(SkBitmap* bitmap, SkMatrix* matrix, |  | 
| 66                                    SkShader::TileMode* xy) const override { |  | 
| 67         if (bitmap) { |  | 
| 68             *bitmap = fDiffuseMap; |  | 
| 69         } |  | 
| 70         if (matrix) { |  | 
| 71             matrix->reset(); |  | 
| 72         } |  | 
| 73         if (xy) { |  | 
| 74             xy[0] = kClamp_TileMode; |  | 
| 75             xy[1] = kClamp_TileMode; |  | 
| 76         } |  | 
| 77         return kDefault_BitmapType; |  | 
| 78     } |  | 
| 79 |  | 
| 80 #ifndef SK_IGNORE_TO_STRING |  | 
| 81     void toString(SkString* str) const override { |  | 
| 82         str->appendf("LightingShader: ()"); |  | 
| 83     } |  | 
| 84 #endif |  | 
| 85 |  | 
| 86     void setLight(const Light& light) { fLight = light;  } |  | 
| 87 |  | 
| 88 private: |  | 
| 89     SkBitmap fDiffuseMap; |  | 
| 90     SkBitmap fNormalMap; |  | 
| 91     Light    fLight; |  | 
| 92     SkColor  fAmbientColor; |  | 
| 93 }; |  | 
| 94 |  | 
| 95 SkFlattenable* LightingShader::CreateProc(SkReadBuffer& buf) { |  | 
| 96     SkBitmap diffuse; |  | 
| 97     if (!buf.readBitmap(&diffuse)) { |  | 
| 98         return NULL; |  | 
| 99     } |  | 
| 100     diffuse.setImmutable(); |  | 
| 101 |  | 
| 102     SkBitmap normal; |  | 
| 103     if (!buf.readBitmap(&normal)) { |  | 
| 104         return NULL; |  | 
| 105     } |  | 
| 106     normal.setImmutable(); |  | 
| 107 |  | 
| 108     Light light; |  | 
| 109     if (!buf.readScalarArray(&light.fDirection.fX, 3)) { |  | 
| 110         return NULL; |  | 
| 111     } |  | 
| 112     light.fColor = buf.readColor(); |  | 
| 113 |  | 
| 114     SkColor ambient = buf.readColor(); |  | 
| 115 |  | 
| 116     return SkNEW_ARGS(LightingShader, (diffuse, normal, light, ambient)); |  | 
| 117 } |  | 
| 118 |  | 
| 119 //////////////////////////////////////////////////////////////////////////// |  | 
| 120 |  | 
| 121 class LightingFP : public GrFragmentProcessor { |  | 
| 122 public: |  | 
| 123     LightingFP(GrTexture* diffuse, GrTexture* normal, const SkMatrix& matrix, |  | 
| 124                SkVector3 lightDir, GrColor lightColor, GrColor ambientColor) |  | 
| 125         : fDeviceTransform(kDevice_GrCoordSet, matrix) |  | 
| 126         , fDiffuseTextureAccess(diffuse) |  | 
| 127         , fNormalTextureAccess(normal) |  | 
| 128         , fLightDir(lightDir) |  | 
| 129         , fLightColor(lightColor) |  | 
| 130         , fAmbientColor(ambientColor) { |  | 
| 131         this->addCoordTransform(&fDeviceTransform); |  | 
| 132         this->addTextureAccess(&fDiffuseTextureAccess); |  | 
| 133         this->addTextureAccess(&fNormalTextureAccess); |  | 
| 134 |  | 
| 135         this->initClassID<LightingFP>(); |  | 
| 136     } |  | 
| 137 |  | 
| 138     class LightingGLFP : public GrGLFragmentProcessor { |  | 
| 139     public: |  | 
| 140         LightingGLFP() : fLightColor(GrColor_ILLEGAL) { |  | 
| 141             fLightDir.fX = 10000.0f; |  | 
| 142         } |  | 
| 143 |  | 
| 144         void emitCode(GrGLFPBuilder* builder, |  | 
| 145                       const GrFragmentProcessor& fp, |  | 
| 146                       const char* outputColor, |  | 
| 147                       const char* inputColor, |  | 
| 148                       const TransformedCoordsArray& coords, |  | 
| 149                       const TextureSamplerArray& samplers) override { |  | 
| 150 |  | 
| 151             GrGLFragmentBuilder* fpb = builder->getFragmentShaderBuilder(); |  | 
| 152 |  | 
| 153             // add uniforms |  | 
| 154             const char* lightDirUniName = NULL; |  | 
| 155             fLightDirUni = builder->addUniform(GrGLProgramBuilder::kFragment_Vis
     ibility, |  | 
| 156                                                kVec3f_GrSLType, kDefault_GrSLPre
     cision, |  | 
| 157                                                "LightDir", &lightDirUniName); |  | 
| 158 |  | 
| 159             const char* lightColorUniName = NULL; |  | 
| 160             fLightColorUni = builder->addUniform(GrGLProgramBuilder::kFragment_V
     isibility, |  | 
| 161                                                  kVec4f_GrSLType, kDefault_GrSLP
     recision, |  | 
| 162                                                  "LightColor", &lightColorUniNam
     e); |  | 
| 163 |  | 
| 164             const char* ambientColorUniName = NULL; |  | 
| 165             fAmbientColorUni = builder->addUniform(GrGLProgramBuilder::kFragment
     _Visibility, |  | 
| 166                                                    kVec4f_GrSLType, kDefault_GrS
     LPrecision, |  | 
| 167                                                    "AmbientColor", &ambientColor
     UniName); |  | 
| 168 |  | 
| 169             fpb->codeAppend("vec4 diffuseColor = "); |  | 
| 170             fpb->appendTextureLookupAndModulate(inputColor, samplers[0], |  | 
| 171                                                 coords[0].c_str(), coords[0].get
     Type()); |  | 
| 172             fpb->codeAppend(";"); |  | 
| 173 |  | 
| 174             fpb->codeAppend("vec4 normalColor = "); |  | 
| 175             fpb->appendTextureLookup(samplers[1], coords[0].c_str(), coords[0].g
     etType()); |  | 
| 176             fpb->codeAppend(";"); |  | 
| 177 |  | 
| 178             fpb->codeAppend("vec3 normal = normalize(2.0*(normalColor.rgb - vec3
     (0.5)));"); |  | 
| 179             fpb->codeAppendf("vec3 lightDir = normalize(%s);", lightDirUniName); |  | 
| 180             fpb->codeAppend("float NdotL = dot(normal, lightDir);"); |  | 
| 181             // diffuse light |  | 
| 182             fpb->codeAppendf("vec3 result = %s.rgb*diffuseColor.rgb*NdotL;", lig
     htColorUniName); |  | 
| 183             // ambient light |  | 
| 184             fpb->codeAppendf("result += %s.rgb;", ambientColorUniName); |  | 
| 185             fpb->codeAppendf("%s = vec4(result.rgb, diffuseColor.a);", outputCol
     or); |  | 
| 186         } |  | 
| 187 |  | 
| 188         void setData(const GrGLProgramDataManager& pdman, const GrProcessor& pro
     c) override { |  | 
| 189             const LightingFP& lightingFP = proc.cast<LightingFP>(); |  | 
| 190 |  | 
| 191             SkVector3 lightDir = lightingFP.lightDir(); |  | 
| 192             if (lightDir != fLightDir) { |  | 
| 193                 pdman.set3fv(fLightDirUni, 1, &lightDir.fX); |  | 
| 194                 fLightDir = lightDir; |  | 
| 195             } |  | 
| 196 |  | 
| 197             GrColor lightColor = lightingFP.lightColor(); |  | 
| 198             if (lightColor != fLightColor) { |  | 
| 199                 GrGLfloat c[4]; |  | 
| 200                 GrColorToRGBAFloat(lightColor, c); |  | 
| 201                 pdman.set4fv(fLightColorUni, 1, c); |  | 
| 202                 fLightColor = lightColor; |  | 
| 203             } |  | 
| 204 |  | 
| 205             GrColor ambientColor = lightingFP.ambientColor(); |  | 
| 206             if (ambientColor != fAmbientColor) { |  | 
| 207                 GrGLfloat c[4]; |  | 
| 208                 GrColorToRGBAFloat(ambientColor, c); |  | 
| 209                 pdman.set4fv(fAmbientColorUni, 1, c); |  | 
| 210                 fAmbientColor = ambientColor; |  | 
| 211             } |  | 
| 212         } |  | 
| 213 |  | 
| 214         static void GenKey(const GrProcessor& proc, const GrGLSLCaps&, |  | 
| 215                            GrProcessorKeyBuilder* b) { |  | 
| 216 //            const LightingFP& lightingFP = proc.cast<LightingFP>(); |  | 
| 217             // only one shader generated currently |  | 
| 218             b->add32(0x0); |  | 
| 219         } |  | 
| 220 |  | 
| 221     private: |  | 
| 222         SkVector3 fLightDir; |  | 
| 223         GrGLProgramDataManager::UniformHandle fLightDirUni; |  | 
| 224 |  | 
| 225         GrColor fLightColor; |  | 
| 226         GrGLProgramDataManager::UniformHandle fLightColorUni; |  | 
| 227 |  | 
| 228         GrColor fAmbientColor; |  | 
| 229         GrGLProgramDataManager::UniformHandle fAmbientColorUni; |  | 
| 230     }; |  | 
| 231 |  | 
| 232     GrGLFragmentProcessor* createGLInstance() const override { return SkNEW(Ligh
     tingGLFP); } |  | 
| 233 |  | 
| 234     void getGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) con
     st override { |  | 
| 235         LightingGLFP::GenKey(*this, caps, b); |  | 
| 236     } |  | 
| 237 |  | 
| 238     const char* name() const override { return "LightingFP"; } |  | 
| 239 |  | 
| 240     void onComputeInvariantOutput(GrInvariantOutput* inout) const override { |  | 
| 241         inout->mulByUnknownFourComponents(); |  | 
| 242     } |  | 
| 243 |  | 
| 244     SkVector3 lightDir() const { return fLightDir; } |  | 
| 245     GrColor lightColor() const { return fLightColor; } |  | 
| 246     GrColor ambientColor() const { return fAmbientColor; } |  | 
| 247 |  | 
| 248 private: |  | 
| 249     bool onIsEqual(const GrFragmentProcessor& proc) const override { |  | 
| 250         const LightingFP& lightingFP = proc.cast<LightingFP>(); |  | 
| 251         return fDeviceTransform == lightingFP.fDeviceTransform && |  | 
| 252                fDiffuseTextureAccess == lightingFP.fDiffuseTextureAccess && |  | 
| 253                fNormalTextureAccess == lightingFP.fNormalTextureAccess && |  | 
| 254                fLightDir == lightingFP.fLightDir && |  | 
| 255                fLightColor == lightingFP.fLightColor && |  | 
| 256                fAmbientColor == lightingFP.fAmbientColor; |  | 
| 257     } |  | 
| 258 |  | 
| 259     GrCoordTransform fDeviceTransform; |  | 
| 260     GrTextureAccess  fDiffuseTextureAccess; |  | 
| 261     GrTextureAccess  fNormalTextureAccess; |  | 
| 262     SkVector3        fLightDir; |  | 
| 263     GrColor          fLightColor; |  | 
| 264     GrColor          fAmbientColor; |  | 
| 265 }; |  | 
| 266 |  | 
| 267 bool LightingShader::asFragmentProcessor(GrContext* context, const SkPaint& pain
     t, |  | 
| 268                                          const SkMatrix& viewM, const SkMatrix* 
     localMatrix, |  | 
| 269                                          GrColor* color, GrShaderDataManager*, |  | 
| 270                                          GrFragmentProcessor** fp) const { |  | 
| 271     // we assume diffuse and normal maps have same width and height |  | 
| 272     // TODO: support different sizes |  | 
| 273     SkASSERT(fDiffuseMap.width() == fNormalMap.width() && |  | 
| 274              fDiffuseMap.height() == fNormalMap.height()); |  | 
| 275     SkMatrix matrix; |  | 
| 276     matrix.setIDiv(fDiffuseMap.width(), fDiffuseMap.height()); |  | 
| 277 |  | 
| 278     SkMatrix lmInverse; |  | 
| 279     if (!this->getLocalMatrix().invert(&lmInverse)) { |  | 
| 280         return false; |  | 
| 281     } |  | 
| 282     if (localMatrix) { |  | 
| 283         SkMatrix inv; |  | 
| 284         if (!localMatrix->invert(&inv)) { |  | 
| 285             return false; |  | 
| 286         } |  | 
| 287         lmInverse.postConcat(inv); |  | 
| 288     } |  | 
| 289     matrix.preConcat(lmInverse); |  | 
| 290 |  | 
| 291     // Must set wrap and filter on the sampler before requesting a texture. In t
     wo places below |  | 
| 292     // we check the matrix scale factors to determine how to interpret the filte
     r quality setting. |  | 
| 293     // This completely ignores the complexity of the drawVertices case where exp
     licit local coords |  | 
| 294     // are provided by the caller. |  | 
| 295     GrTextureParams::FilterMode textureFilterMode = GrTextureParams::kBilerp_Fil
     terMode; |  | 
| 296     switch (paint.getFilterQuality()) { |  | 
| 297     case kNone_SkFilterQuality: |  | 
| 298         textureFilterMode = GrTextureParams::kNone_FilterMode; |  | 
| 299         break; |  | 
| 300     case kLow_SkFilterQuality: |  | 
| 301         textureFilterMode = GrTextureParams::kBilerp_FilterMode; |  | 
| 302         break; |  | 
| 303     case kMedium_SkFilterQuality:{ |  | 
| 304         SkMatrix matrix; |  | 
| 305         matrix.setConcat(viewM, this->getLocalMatrix()); |  | 
| 306         if (matrix.getMinScale() < SK_Scalar1) { |  | 
| 307             textureFilterMode = GrTextureParams::kMipMap_FilterMode; |  | 
| 308         } else { |  | 
| 309             // Don't trigger MIP level generation unnecessarily. |  | 
| 310             textureFilterMode = GrTextureParams::kBilerp_FilterMode; |  | 
| 311         } |  | 
| 312         break; |  | 
| 313     } |  | 
| 314     case kHigh_SkFilterQuality: |  | 
| 315     default: |  | 
| 316         SkErrorInternals::SetError(kInvalidPaint_SkError, |  | 
| 317             "Sorry, I don't understand the filtering " |  | 
| 318             "mode you asked for.  Falling back to " |  | 
| 319             "MIPMaps."); |  | 
| 320         textureFilterMode = GrTextureParams::kMipMap_FilterMode; |  | 
| 321         break; |  | 
| 322 |  | 
| 323     } |  | 
| 324 |  | 
| 325     // TODO: support other tile modes |  | 
| 326     GrTextureParams params(kClamp_TileMode, textureFilterMode); |  | 
| 327     SkAutoTUnref<GrTexture> diffuseTexture(GrRefCachedBitmapTexture(context, fDi
     ffuseMap, ¶ms)); |  | 
| 328     if (!diffuseTexture) { |  | 
| 329         SkErrorInternals::SetError(kInternalError_SkError, |  | 
| 330             "Couldn't convert bitmap to texture."); |  | 
| 331         return false; |  | 
| 332     } |  | 
| 333 |  | 
| 334     SkAutoTUnref<GrTexture> normalTexture(GrRefCachedBitmapTexture(context, fNor
     malMap, ¶ms)); |  | 
| 335     if (!normalTexture) { |  | 
| 336         SkErrorInternals::SetError(kInternalError_SkError, |  | 
| 337             "Couldn't convert bitmap to texture."); |  | 
| 338         return false; |  | 
| 339     } |  | 
| 340 |  | 
| 341     GrColor lightColor = GrColorPackRGBA(SkColorGetR(fLight.fColor), SkColorGetG
     (fLight.fColor), |  | 
| 342                                          SkColorGetB(fLight.fColor), SkColorGetA
     (fLight.fColor)); |  | 
| 343     GrColor ambientColor = GrColorPackRGBA(SkColorGetR(fAmbientColor), SkColorGe
     tG(fAmbientColor), |  | 
| 344                                            SkColorGetB(fAmbientColor), SkColorGe
     tA(fAmbientColor)); |  | 
| 345 |  | 
| 346     *fp = SkNEW_ARGS(LightingFP, (diffuseTexture, normalTexture, matrix, |  | 
| 347                                   fLight.fDirection, lightColor, ambientColor)); |  | 
| 348     *color = GrColorPackA4(paint.getAlpha()); |  | 
| 349     return true; |  | 
| 350 } |  | 
| 351 |  | 
| 352 //////////////////////////////////////////////////////////////////////////// |  | 
| 353 |  | 
| 354 class LightingView : public SampleView { |  | 
| 355 public: |  | 
| 356     SkAutoTUnref<LightingShader> fShader; |  | 
| 357     SkBitmap                     fDiffuseBitmap; |  | 
| 358     SkBitmap                     fNormalBitmap; |  | 
| 359     SkScalar                     fLightAngle; |  | 
| 360     int                          fColorFactor; |  | 
| 361 |  | 
| 362     LightingView() { |  | 
| 363         SkString diffusePath = GetResourcePath("brickwork-texture.jpg"); |  | 
| 364         SkImageDecoder::DecodeFile(diffusePath.c_str(), &fDiffuseBitmap); |  | 
| 365         SkString normalPath = GetResourcePath("brickwork_normal-map.jpg"); |  | 
| 366         SkImageDecoder::DecodeFile(normalPath.c_str(), &fNormalBitmap); |  | 
| 367 |  | 
| 368         fLightAngle = 0.0f; |  | 
| 369         fColorFactor = 0; |  | 
| 370 |  | 
| 371         LightingShader::Light light; |  | 
| 372         light.fColor = SkColorSetRGB(0xff, 0xff, 0xff); |  | 
| 373         light.fDirection.fX = SkScalarSin(fLightAngle)*SkScalarSin(SK_ScalarPI*0
     .25f); |  | 
| 374         light.fDirection.fY = SkScalarCos(fLightAngle)*SkScalarSin(SK_ScalarPI*0
     .25f); |  | 
| 375         light.fDirection.fZ = SkScalarCos(SK_ScalarPI*0.25f); |  | 
| 376 |  | 
| 377         SkColor ambient = SkColorSetRGB(0x1f, 0x1f, 0x1f); |  | 
| 378 |  | 
| 379         fShader.reset(SkNEW_ARGS(LightingShader, (fDiffuseBitmap, fNormalBitmap,
      light, ambient))); |  | 
| 380     } |  | 
| 381 |  | 
| 382     virtual ~LightingView() {} |  | 
| 383 |  | 
| 384 protected: |  | 
| 385     // overrides from SkEventSink |  | 
| 386     bool onQuery(SkEvent* evt) override { |  | 
| 387         if (SampleCode::TitleQ(*evt)) { |  | 
| 388             SampleCode::TitleR(evt, "Lighting"); |  | 
| 389             return true; |  | 
| 390         } |  | 
| 391         return this->INHERITED::onQuery(evt); |  | 
| 392     } |  | 
| 393 |  | 
| 394     void onDrawContent(SkCanvas* canvas) override { |  | 
| 395         fLightAngle += 0.015f; |  | 
| 396         fColorFactor++; |  | 
| 397 |  | 
| 398         LightingShader::Light light; |  | 
| 399         light.fColor = SkColorSetRGB(0xff, 0xff, (fColorFactor >> 1) & 0xff); |  | 
| 400         light.fDirection.fX = SkScalarSin(fLightAngle)*SkScalarSin(SK_ScalarPI*0
     .25f); |  | 
| 401         light.fDirection.fY = SkScalarCos(fLightAngle)*SkScalarSin(SK_ScalarPI*0
     .25f); |  | 
| 402         light.fDirection.fZ = SkScalarCos(SK_ScalarPI*0.25f); |  | 
| 403 |  | 
| 404         fShader.get()->setLight(light); |  | 
| 405 |  | 
| 406         SkPaint paint; |  | 
| 407         paint.setShader(fShader); |  | 
| 408         paint.setColor(SK_ColorBLACK); |  | 
| 409 |  | 
| 410         SkRect r = SkRect::MakeWH((SkScalar)fDiffuseBitmap.width(), |  | 
| 411                                   (SkScalar)fDiffuseBitmap.height()); |  | 
| 412         canvas->drawRect(r, paint); |  | 
| 413 |  | 
| 414         // so we're constantly updating |  | 
| 415         this->inval(NULL); |  | 
| 416     } |  | 
| 417 |  | 
| 418     SkView::Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned modi) ove
     rride { |  | 
| 419         this->inval(NULL); |  | 
| 420         return this->INHERITED::onFindClickHandler(x, y, modi); |  | 
| 421     } |  | 
| 422 |  | 
| 423 private: |  | 
| 424     typedef SampleView INHERITED; |  | 
| 425 }; |  | 
| 426 |  | 
| 427 ////////////////////////////////////////////////////////////////////////////// |  | 
| 428 |  | 
| 429 static SkView* MyFactory() { return new LightingView; } |  | 
| 430 static SkViewRegister reg(MyFactory); |  | 
| OLD | NEW | 
|---|