[svg] Implement spot light sources

Note Chrome, Firefox and Inkscape (only other viewers I tested) disagree
in smallish ways with the W3C png for filters-light-01. We're somewhere
in the middle, but likely conforming enough to call it correct.

Bug: skia:10841
Change-Id: Ia83b9936d260780148fe326b6d3b2248eef69aac
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/403036
Reviewed-by: Florin Malita <fmalita@chromium.org>
Commit-Queue: Tyler Denniston <tdenniston@google.com>
This commit is contained in:
Tyler Denniston 2021-04-30 11:55:07 -04:00 committed by Skia Commit-Bot
parent 7c59ab868d
commit cdcd9a76bb
2 changed files with 56 additions and 1 deletions

View File

@ -13,6 +13,7 @@
class SkSVGFeDistantLight;
class SkSVGFePointLight;
class SkSVGFeSpotLight;
class SkSVGFeLighting : public SkSVGFe {
public:
@ -42,6 +43,10 @@ protected:
const SkSVGFilterContext&,
const SkSVGFePointLight*) const = 0;
virtual sk_sp<SkImageFilter> makeSpotLight(const SkSVGRenderContext&,
const SkSVGFilterContext&,
const SkSVGFeSpotLight*) const = 0;
SkColor resolveLightingColor(const SkSVGRenderContext&) const;
SkPoint3 resolveXYZ(const SkSVGRenderContext&,
@ -74,6 +79,10 @@ protected:
const SkSVGFilterContext&,
const SkSVGFePointLight*) const final;
sk_sp<SkImageFilter> makeSpotLight(const SkSVGRenderContext&,
const SkSVGFilterContext&,
const SkSVGFeSpotLight*) const final;
private:
SkSVGFeSpecularLighting() : INHERITED(SkSVGTag::kFeSpecularLighting) {}
@ -99,6 +108,10 @@ protected:
const SkSVGFilterContext&,
const SkSVGFePointLight*) const final;
sk_sp<SkImageFilter> makeSpotLight(const SkSVGRenderContext&,
const SkSVGFilterContext&,
const SkSVGFeSpotLight*) const final;
private:
SkSVGFeDiffuseLighting() : INHERITED(SkSVGTag::kFeDiffuseLighting) {}

View File

@ -45,13 +45,16 @@ sk_sp<SkImageFilter> SkSVGFeLighting::onMakeImageFilter(const SkSVGRenderContext
case SkSVGTag::kFePointLight:
return this->makePointLight(
ctx, fctx, static_cast<const SkSVGFePointLight*>(child.get()));
case SkSVGTag::kFeSpotLight:
return this->makeSpotLight(
ctx, fctx, static_cast<const SkSVGFeSpotLight*>(child.get()));
default:
// Ignore unknown children, such as <desc> elements
break;
}
}
SkDebugf("lighting filter effect needs exactly one light source");
SkDebugf("lighting filter effect needs exactly one light source\n");
return nullptr;
}
@ -115,6 +118,26 @@ sk_sp<SkImageFilter> SkSVGFeSpecularLighting::makePointLight(const SkSVGRenderCo
this->resolveFilterSubregion(ctx, fctx));
}
sk_sp<SkImageFilter> SkSVGFeSpecularLighting::makeSpotLight(const SkSVGRenderContext& ctx,
const SkSVGFilterContext& fctx,
const SkSVGFeSpotLight* light) const {
const auto& limitingConeAngle = light->getLimitingConeAngle();
const float cutoffAngle = limitingConeAngle.isValid() ? *limitingConeAngle : 180.f;
return SkImageFilters::SpotLitSpecular(
this->resolveXYZ(ctx, fctx, light->getX(), light->getY(), light->getZ()),
this->resolveXYZ(
ctx, fctx, light->getPointsAtX(), light->getPointsAtY(), light->getPointsAtZ()),
light->getSpecularExponent(),
cutoffAngle,
this->resolveLightingColor(ctx),
this->getSurfaceScale(),
fSpecularConstant,
fSpecularExponent,
fctx.resolveInput(ctx, this->getIn(), this->resolveColorspace(ctx, fctx)),
this->resolveFilterSubregion(ctx, fctx));
}
bool SkSVGFeDiffuseLighting::parseAndSetAttribute(const char* n, const char* v) {
return INHERITED::parseAndSetAttribute(n, v) ||
this->setDiffuseConstant(
@ -146,3 +169,22 @@ sk_sp<SkImageFilter> SkSVGFeDiffuseLighting::makePointLight(const SkSVGRenderCon
fctx.resolveInput(ctx, this->getIn(), this->resolveColorspace(ctx, fctx)),
this->resolveFilterSubregion(ctx, fctx));
}
sk_sp<SkImageFilter> SkSVGFeDiffuseLighting::makeSpotLight(const SkSVGRenderContext& ctx,
const SkSVGFilterContext& fctx,
const SkSVGFeSpotLight* light) const {
const auto& limitingConeAngle = light->getLimitingConeAngle();
const float cutoffAngle = limitingConeAngle.isValid() ? *limitingConeAngle : 180.f;
return SkImageFilters::SpotLitDiffuse(
this->resolveXYZ(ctx, fctx, light->getX(), light->getY(), light->getZ()),
this->resolveXYZ(
ctx, fctx, light->getPointsAtX(), light->getPointsAtY(), light->getPointsAtZ()),
light->getSpecularExponent(),
cutoffAngle,
this->resolveLightingColor(ctx),
this->getSurfaceScale(),
this->getDiffuseConstant(),
fctx.resolveInput(ctx, this->getIn(), this->resolveColorspace(ctx, fctx)),
this->resolveFilterSubregion(ctx, fctx));
}