Index: src/core/SkCanvas.cpp |
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp |
index d42c726c6c6a24c6ca7689bc68937ba616d1c710..24d9506bd79ca2719440e3f0f16cd09fb833f0ca 100644 |
--- a/src/core/SkCanvas.cpp |
+++ b/src/core/SkCanvas.cpp |
@@ -28,6 +28,8 @@ |
#include "SkRasterClip.h" |
#include "SkReadPixelsRec.h" |
#include "SkRRect.h" |
+#include "SkShadowPaintFilterCanvas.h" |
+#include "SkShadowShader.h" |
#include "SkSmallAllocator.h" |
#include "SkSpecialImage.h" |
#include "SkSurface_Base.h" |
@@ -3069,7 +3071,125 @@ void SkCanvas::drawShadowedPicture(const SkPicture* picture, |
void SkCanvas::onDrawShadowedPicture(const SkPicture* picture, |
const SkMatrix* matrix, |
const SkPaint* paint) { |
- this->onDrawPicture(picture, matrix, paint); |
+ if (!paint || paint->canComputeFastBounds()) { |
+ SkRect bounds = picture->cullRect(); |
+ if (paint) { |
+ paint->computeFastBounds(bounds, &bounds); |
+ } |
+ if (matrix) { |
+ matrix->mapRect(&bounds); |
+ } |
+ if (this->quickReject(bounds)) { |
+ return; |
+ } |
+ } |
+ |
+ SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect()); |
+ |
+ for (int i = 0; i < fLights->numLights(); ++i) { |
+ // skip over ambient lights; they don't cast shadows |
+ // lights that have shadow maps do not need updating (because lights are immutable) |
+ |
+ if (SkLights::Light::kAmbient_LightType == fLights->light(i).type() || |
+ fLights->light(i).getShadowMap() != nullptr) { |
+ continue; |
+ } |
+ |
+ // TODO: compute the correct size of the depth map from the light properties |
+ // TODO: maybe add a kDepth_8_SkColorType |
+ // TODO: find actual max depth of picture |
+ SkISize shMapSize = SkShadowPaintFilterCanvas::ComputeDepthMapSize( |
+ fLights->light(i), 255, |
+ picture->cullRect().width(), |
+ picture->cullRect().height()); |
+ |
+ SkImageInfo info = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight, |
+ kBGRA_8888_SkColorType, |
+ kOpaque_SkAlphaType); |
+ |
+ // Create a new surface (that matches the backend of canvas) |
+ // for each shadow map |
+ sk_sp<SkSurface> surf(this->makeSurface(info)); |
+ |
+ // Wrap another SPFCanvas around the surface |
+ sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas = |
+ sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas()); |
+ |
+ // set the depth map canvas to have the light we're drawing. |
+ SkLights::Builder builder; |
+ builder.add(fLights->light(i)); |
+ sk_sp<SkLights> curLight = builder.finish(); |
+ |
+ depthMapCanvas->setLights(std::move(curLight)); |
+ depthMapCanvas->drawPicture(picture); |
+ |
+ fLights->light(i).setShadowMap(surf->makeImageSnapshot()); |
+ } |
+ |
+ sk_sp<SkImage> povDepthMap; |
+ sk_sp<SkImage> diffuseMap; |
+ |
+ // TODO: pass the depth to the shader in vertices, or uniforms |
+ // so we don't have to render depth and color separately |
+ |
+ // povDepthMap |
+ { |
+ SkLights::Builder builder; |
+ builder.add(SkLights::Light(SkColor3f::Make(1.0f, 1.0f, 1.0f), |
+ SkVector3::Make(0.0f, 0.0f, 1.0f))); |
+ sk_sp<SkLights> povLight = builder.finish(); |
+ |
+ SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(), |
+ picture->cullRect().height(), |
+ kBGRA_8888_SkColorType, |
+ kOpaque_SkAlphaType); |
+ |
+ // Create a new surface (that matches the backend of canvas) |
+ // to create the povDepthMap |
+ sk_sp<SkSurface> surf(this->makeSurface(info)); |
+ |
+ // Wrap another SPFCanvas around the surface |
+ sk_sp<SkShadowPaintFilterCanvas> depthMapCanvas = |
+ sk_make_sp<SkShadowPaintFilterCanvas>(surf->getCanvas()); |
+ |
+ // set the depth map canvas to have the light as the user's POV |
+ depthMapCanvas->setLights(std::move(povLight)); |
+ |
+ depthMapCanvas->drawPicture(picture); |
+ |
+ povDepthMap = surf->makeImageSnapshot(); |
+ } |
+ |
+ // diffuseMap |
+ { |
+ SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(), |
+ picture->cullRect().height(), |
+ kBGRA_8888_SkColorType, |
+ kOpaque_SkAlphaType); |
+ |
+ sk_sp<SkSurface> surf(this->makeSurface(info)); |
+ surf->getCanvas()->drawPicture(picture); |
+ |
+ diffuseMap = surf->makeImageSnapshot(); |
+ } |
+ |
+ SkPaint shadowPaint; |
+ |
+ sk_sp<SkShader> povDepthShader = povDepthMap->makeShader(SkShader::kClamp_TileMode, |
+ SkShader::kClamp_TileMode); |
+ |
+ sk_sp<SkShader> diffuseShader = diffuseMap->makeShader(SkShader::kClamp_TileMode, |
+ SkShader::kClamp_TileMode); |
+ |
+ sk_sp<SkShader> shadowShader = SkShadowShader::Make(std::move(povDepthShader), |
+ std::move(diffuseShader), |
+ std::move(fLights), |
+ diffuseMap->width(), |
+ diffuseMap->height()); |
+ |
+ shadowPaint.setShader(shadowShader); |
+ |
+ this->drawRect(SkRect::MakeIWH(diffuseMap->width(), diffuseMap->height()), shadowPaint); |
} |
#endif |