Update SkLightingShader to take a localMatrix

W/o this we can't draw lit objects anywhere but the origin.

Review URL: https://codereview.chromium.org/1253223003
diff --git a/gm/lightingshader.cpp b/gm/lightingshader.cpp
index e920fb5..ad8823d 100644
--- a/gm/lightingshader.cpp
+++ b/gm/lightingshader.cpp
@@ -18,12 +18,12 @@
     sk_tool_utils::draw_checkerboard(&canvas,
                                      sk_tool_utils::color_to_565(0x0),
                                      sk_tool_utils::color_to_565(0xFF804020),
-                                     16);
+                                     2);
     return bitmap;
 }
 
 // Create a hemispherical normal map
-static SkBitmap make_normalmap(int texSize) {
+static SkBitmap make_hemi_normalmap(int texSize) {
     SkBitmap hemi;
     hemi.allocN32Pixels(texSize, texSize);
 
@@ -49,6 +49,53 @@
     return hemi;
 }
 
+// Create a truncated pyramid normal map
+static SkBitmap make_frustum_normalmap(int texSize) {
+    SkBitmap frustum;
+    frustum.allocN32Pixels(texSize, texSize);
+
+    SkIRect inner = SkIRect::MakeWH(texSize, texSize);
+    inner.inset(texSize/4, texSize/4);
+
+    SkPoint3 norm;
+    const SkPoint3 left =  SkPoint3::Make(-SK_ScalarRoot2Over2, 0.0f, SK_ScalarRoot2Over2);
+    const SkPoint3 up =    SkPoint3::Make(0.0f, -SK_ScalarRoot2Over2, SK_ScalarRoot2Over2);
+    const SkPoint3 right = SkPoint3::Make(SK_ScalarRoot2Over2,  0.0f, SK_ScalarRoot2Over2);
+    const SkPoint3 down =  SkPoint3::Make(0.0f,  SK_ScalarRoot2Over2, SK_ScalarRoot2Over2);
+
+    for (int y = 0; y < texSize; ++y) {
+        for (int x = 0; x < texSize; ++x) {
+            if (inner.contains(x, y)) {
+                norm.set(0.0f, 0.0f, 1.0f);
+            } else {
+                SkScalar locX = x + 0.5f - texSize/2.0f;
+                SkScalar locY = y + 0.5f - texSize/2.0f;
+
+                if (locX >= 0.0f) {
+                    if (locY > 0.0f) {
+                        norm = locX >= locY ? right : down;   // LR corner
+                    } else {
+                        norm = locX > -locY ? right : up;     // UR corner
+                    }    
+                } else {
+                    if (locY > 0.0f) {
+                        norm = -locX > locY ? left : down;    // LL corner
+                    } else {
+                        norm = locX > locY ? up : left;       // UL corner
+                    }    
+                }
+            }
+
+            SkASSERT(SkScalarNearlyEqual(norm.length(), 1.0f));
+            unsigned char r = static_cast<unsigned char>((0.5f *  norm.fX + 0.5f) * 255);
+            unsigned char g = static_cast<unsigned char>((-0.5f * norm.fY + 0.5f) * 255);
+            unsigned char b = static_cast<unsigned char>((0.5f *  norm.fZ + 0.5f) * 255);
+            *frustum.getAddr32(x, y) = SkPackARGB32(0xFF, r, g, b);
+        }
+    }
+
+    return frustum;
+}
 
 namespace skiagm {
 
@@ -57,6 +104,13 @@
 public:
     LightingShaderGM() {
         this->setBGColor(sk_tool_utils::color_to_565(0xFFCCCCCC));
+
+        fLight.fColor = SkColorSetRGB(0xff, 0xff, 0xff);
+        fLight.fDirection.fX = 0.0f;
+        fLight.fDirection.fY = 0.0f;
+        fLight.fDirection.fZ = 1.0f;
+
+        fAmbient = SkColorSetRGB(0x1f, 0x1f, 0x1f);
     }
 
 protected:
@@ -66,40 +120,58 @@
     }
 
     SkISize onISize() override {
-        return SkISize::Make(kTexSize, kTexSize);
+        return SkISize::Make(kGMSize, kGMSize);
     }
 
     void onOnceBeforeDraw() override {
         fDiffuse = make_checkerboard(kTexSize);
-        fNormalMap = make_normalmap(kTexSize);
+        fHemiNormalMap = make_hemi_normalmap(kTexSize);
+        fFrustumNormalMap = make_frustum_normalmap(kTexSize);
     }
 
-    void onDraw(SkCanvas* canvas) override {
+    void drawRect(SkCanvas* canvas, const SkRect& r, bool hemi) {
 
-        SkColor ambient = SkColorSetRGB(0x1f, 0x1f, 0x1f);
+        SkRect bitmapBounds = SkRect::MakeIWH(fDiffuse.width(), fDiffuse.height());
 
-        SkLightingShader::Light light;
-        light.fColor = SkColorSetRGB(0xff, 0xff, 0xff);
-        light.fDirection.fX = 0.0f;
-        light.fDirection.fY = 0.0f;
-        light.fDirection.fZ = 1.0f;
-
-        SkAutoTUnref<SkShader> fShader(SkLightingShader::Create(fDiffuse, fNormalMap, 
-                                                                light, ambient));
+        SkMatrix matrix;
+        matrix.setRectToRect(bitmapBounds, r, SkMatrix::kFill_ScaleToFit);
+    
+        SkAutoTUnref<SkShader> fShader(SkLightingShader::Create(
+                                                        fDiffuse,
+                                                        hemi ? fHemiNormalMap : fFrustumNormalMap, 
+                                                        fLight, fAmbient,
+                                                        &matrix));
 
         SkPaint paint;
         paint.setShader(fShader);
 
-        SkRect r = SkRect::MakeWH(SkIntToScalar(kTexSize), SkIntToScalar(kTexSize));
-
         canvas->drawRect(r, paint);
     }
 
+    void onDraw(SkCanvas* canvas) override {
+        SkRect r = SkRect::MakeWH(SkIntToScalar(kTexSize), SkIntToScalar(kTexSize));
+        this->drawRect(canvas, r, true);
+
+        r.offset(kGMSize - kTexSize, 0);
+        this->drawRect(canvas, r, false);
+
+        r.offset(0, kGMSize - kTexSize);
+        this->drawRect(canvas, r, true);
+
+        r.offset(kTexSize - kGMSize, 0);
+        this->drawRect(canvas, r, false);
+    }
+
 private:
     static const int kTexSize = 128;
+    static const int kGMSize  = 512;
 
-    SkBitmap fDiffuse;
-    SkBitmap fNormalMap;
+    SkBitmap                fDiffuse;
+    SkBitmap                fHemiNormalMap;
+    SkBitmap                fFrustumNormalMap;
+
+    SkLightingShader::Light fLight;
+    SkColor                 fAmbient;
 
     typedef GM INHERITED;
 };
diff --git a/samplecode/SampleLighting.cpp b/samplecode/SampleLighting.cpp
index 079cb68..3cda0c6 100755
--- a/samplecode/SampleLighting.cpp
+++ b/samplecode/SampleLighting.cpp
@@ -41,7 +41,7 @@
         fAmbientColor = SkColorSetRGB(0x1f, 0x1f, 0x1f);
 
         fShader.reset(SkLightingShader::Create(fDiffuseBitmap, fNormalBitmap,
-                                               light, fAmbientColor));
+                                               light, fAmbientColor, nullptr));
     }
 
     virtual ~LightingView() {}
@@ -67,7 +67,7 @@
         light.fDirection.fZ = SkScalarCos(SK_ScalarPI*0.25f);
 
         fShader.reset(SkLightingShader::Create(fDiffuseBitmap, fNormalBitmap,
-                                               light, fAmbientColor));
+                                               light, fAmbientColor, nullptr));
 
         SkPaint paint;
         paint.setShader(fShader);
diff --git a/src/effects/SkLightingShader.cpp b/src/effects/SkLightingShader.cpp
index be92ccf..7dcba95 100644
--- a/src/effects/SkLightingShader.cpp
+++ b/src/effects/SkLightingShader.cpp
@@ -51,8 +51,9 @@
     */
     SkLightingShaderImpl(const SkBitmap& diffuse, const SkBitmap& normal,
                          const SkLightingShader::Light& light,
-                         const SkColor ambient) 
-        : fDiffuseMap(diffuse)
+                         const SkColor ambient, const SkMatrix* localMatrix) 
+        : INHERITED(localMatrix)
+        , fDiffuseMap(diffuse)
         , fNormalMap(normal)
         , fLight(light)
         , fAmbientColor(ambient) {
@@ -480,6 +481,9 @@
 #endif
 
 SkFlattenable* SkLightingShaderImpl::CreateProc(SkReadBuffer& buf) {
+    SkMatrix localMatrix;
+    buf.readMatrix(&localMatrix);
+
     SkBitmap diffuse;
     if (!buf.readBitmap(&diffuse)) {
         return NULL;
@@ -500,12 +504,12 @@
 
     SkColor ambient = buf.readColor();
 
-    // TODO: this would be nice to enable
-    //    return SkCreateLightingShader(diffuse, normal, light, ambient, NULL);
-    return SkNEW_ARGS(SkLightingShaderImpl, (diffuse, normal, light, ambient));
+    return SkNEW_ARGS(SkLightingShaderImpl, (diffuse, normal, light, ambient, &localMatrix));
 }
 
 void SkLightingShaderImpl::flatten(SkWriteBuffer& buf) const {
+    buf.writeMatrix(this->getLocalMatrix());
+
     buf.writeBitmap(fDiffuseMap);
     buf.writeBitmap(fNormalMap);
     buf.writeScalarArray(&fLight.fDirection.fX, 3);
@@ -565,7 +569,8 @@
 
 SkShader* SkLightingShader::Create(const SkBitmap& diffuse, const SkBitmap& normal,
                                    const SkLightingShader::Light& light,
-                                   const SkColor ambient) {
+                                   const SkColor ambient,
+                                   const SkMatrix* localMatrix) {
     if (diffuse.isNull() || bitmap_is_too_big(diffuse) ||
         normal.isNull() || bitmap_is_too_big(normal) ||
         diffuse.width() != normal.width() ||
@@ -573,7 +578,7 @@
         return nullptr;
     }
 
-    return SkNEW_ARGS(SkLightingShaderImpl, (diffuse, normal, light, ambient));
+    return SkNEW_ARGS(SkLightingShaderImpl, (diffuse, normal, light, ambient, localMatrix));
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/src/effects/SkLightingShader.h b/src/effects/SkLightingShader.h
index d3fe3f6..b85e431 100644
--- a/src/effects/SkLightingShader.h
+++ b/src/effects/SkLightingShader.h
@@ -26,10 +26,11 @@
         It returns a shader with a reference count of 1.
         The caller should decrement the shader's reference count when done with the shader.
         It is an error for count to be < 2.
-        @param  diffuse the diffuse bitmap
-        @param  normal  the normal map
-        @param  light   the light applied to the normal map
-        @param  ambient the linear (unpremul) ambient light color. Note: alpha assumed to be 255.
+        @param  diffuse     the diffuse bitmap
+        @param  normal      the normal map
+        @param  light       the light applied to the normal map
+        @param  ambient     the linear (unpremul) ambient light color. Note: alpha assumed to be 255.
+        @param  localMatrix the matrix mapping the textures to the dest rect 
 
         NULL will be returned if:
             either 'diffuse' or 'normal' are empty
@@ -37,7 +38,8 @@
             'diffuse' and 'normal' aren't the same size
     */
     static SkShader* Create(const SkBitmap& diffuse, const SkBitmap& normal,
-                            const SkLightingShader::Light& light, const SkColor ambient);
+                            const SkLightingShader::Light& light, const SkColor ambient,
+                            const SkMatrix* localMatrix);
 
     SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP()
 };