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()
};