[librsvg: 15/23] fe*Lighting - resolve and render separately
- From: Federico Mena Quintero <federico src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg: 15/23] fe*Lighting - resolve and render separately
- Date: Thu, 11 Mar 2021 23:12:24 +0000 (UTC)
commit 314dd1be224a87eb22dcacfc87ecd28ebb5af8b9
Author: Federico Mena Quintero <federico gnome org>
Date: Thu Mar 11 16:14:18 2021 -0600
fe*Lighting - resolve and render separately
This is still a bit convoluted due to the big impl_lighting_filter macro.
src/filters/lighting.rs | 181 ++++++++++++++++++++++++++++++------------------
src/filters/mod.rs | 9 ++-
2 files changed, 118 insertions(+), 72 deletions(-)
---
diff --git a/src/filters/lighting.rs b/src/filters/lighting.rs
index d23737a5..8858804f 100644
--- a/src/filters/lighting.rs
+++ b/src/filters/lighting.rs
@@ -15,6 +15,7 @@ use crate::filters::{
FilterEffect, FilterError, Input, Primitive, PrimitiveParams,
};
use crate::node::{CascadedValues, Node, NodeBorrow};
+use crate::paint_server::resolve_color;
use crate::parsers::{NonNegative, NumberOptionalNumber, ParseValue};
use crate::property_defs::ColorInterpolationFilters;
use crate::rect::IRect;
@@ -23,6 +24,7 @@ use crate::surface_utils::{
ImageSurfaceDataExt, Pixel,
};
use crate::transform::Transform;
+use crate::unit_interval::UnitInterval;
use crate::util::clamp;
use crate::xml::Attributes;
@@ -67,52 +69,28 @@ struct Light {
color_interpolation_filters: ColorInterpolationFilters,
}
-impl Light {
- pub fn new(node: &Node) -> Result<Light, FilterError> {
- let mut sources = node.children().rev().filter(|c| {
- c.is_element()
- && matches!(
- *c.borrow_element(),
- Element::FeDistantLight(_) | Element::FePointLight(_) | Element::FeSpotLight(_)
- )
- });
-
- let source_node = sources.next();
- if source_node.is_none() || sources.next().is_some() {
- return Err(FilterError::InvalidLightSourceCount);
- }
-
- let source_node = source_node.unwrap();
- let elt = source_node.borrow_element();
-
- if elt.is_in_error() {
- return Err(FilterError::ChildNodeInError);
- }
-
- let source = match *elt {
- Element::FeDistantLight(ref l) => {
- UntransformedLightSource::Distant(l.element_impl.clone())
- }
- Element::FePointLight(ref l) => UntransformedLightSource::Point(l.element_impl.clone()),
- Element::FeSpotLight(ref l) => UntransformedLightSource::Spot(l.element_impl.clone()),
- _ => unreachable!(),
- };
-
- let cascaded = CascadedValues::new_from_node(node);
- let values = cascaded.get();
-
- let lighting_color = match values.lighting_color().0 {
- cssparser::Color::CurrentColor => values.color().0,
- cssparser::Color::RGBA(rgba) => rgba,
- };
+/// Resolved `feDiffuseLighting` primitive for rendering.
+pub struct DiffuseLighting {
+ base: Primitive,
+ in1: Input,
+ surface_scale: f64,
+ kernel_unit_length: Option<(f64, f64)>,
+ diffuse_constant: f64,
+ light: Light,
+}
- Ok(Light {
- source,
- lighting_color,
- color_interpolation_filters: values.color_interpolation_filters(),
- })
- }
+/// Resolved `feSpecularLighting` primitive for rendering.
+pub struct SpecularLighting {
+ base: Primitive,
+ in1: Input,
+ surface_scale: f64,
+ kernel_unit_length: Option<(f64, f64)>,
+ specular_constant: f64,
+ specular_exponent: f64,
+ light: Light,
+}
+impl Light {
/// Returns the color and unit (or null) vector from the image sample to the light.
#[inline]
pub fn color_and_vector(
@@ -350,7 +328,7 @@ impl SetAttributes for FeDiffuseLighting {
}
}
-impl FeDiffuseLighting {
+impl DiffuseLighting {
#[inline]
fn compute_factor(&self, normal: Normal, light_vector: Vector3<f64>) -> f64 {
let k = if normal.normal.is_zero() {
@@ -419,7 +397,7 @@ impl SetAttributes for FeSpecularLighting {
}
}
-impl FeSpecularLighting {
+impl SpecularLighting {
#[inline]
fn compute_factor(&self, normal: Normal, light_vector: Vector3<f64>) -> f64 {
let h = light_vector + Vector3::new(0.0, 0.0, 1.0);
@@ -450,22 +428,19 @@ impl FeSpecularLighting {
}
macro_rules! impl_lighting_filter {
- ($lighting_type:ty, $params_name:ident, $alpha_func:ident) => {
- impl $lighting_type {
+ ($lighting_type:ty, $params_name:ident, $alpha_func:ident, $($specific_fields:ident,)+) => {
+ impl $params_name {
pub fn render(
&self,
- node: &Node,
ctx: &FilterContext,
acquired_nodes: &mut AcquiredNodes<'_>,
draw_ctx: &mut DrawingCtx,
) -> Result<FilterResult, FilterError> {
- let light = Light::new(node)?;
-
let input_1 = ctx.get_input(
acquired_nodes,
draw_ctx,
&self.in1,
- light.color_interpolation_filters,
+ self.light.color_interpolation_filters,
)?;
let mut bounds = self
.base
@@ -499,12 +474,12 @@ macro_rules! impl_lighting_filter {
let (ox, oy) = scale.unwrap_or((1.0, 1.0));
- let source = light.source.transform(ctx.paffine());
+ let source = self.light.source.transform(ctx.paffine());
let mut surface = ExclusiveImageSurface::new(
input_surface.width(),
input_surface.height(),
- SurfaceType::from(light.color_interpolation_filters),
+ SurfaceType::from(self.light.color_interpolation_filters),
)?;
{
@@ -521,7 +496,7 @@ macro_rules! impl_lighting_filter {
let z = f64::from(pixel.a) / 255.0 * self.surface_scale;
let (color, vector) =
- light.color_and_vector(&source, scaled_x, scaled_y, z);
+ self.light.color_and_vector(&source, scaled_x, scaled_y, z);
// compute the factor just once for the three colors
let factor = self.compute_factor(normal, vector);
@@ -670,7 +645,52 @@ macro_rules! impl_lighting_filter {
impl FilterEffect for $lighting_type {
fn resolve(&self, node: &Node) -> Result<PrimitiveParams, FilterError> {
- Ok(PrimitiveParams::$params_name(node.clone()))
+ let mut sources = node.children().rev().filter(|c| {
+ c.is_element()
+ && matches!(
+ *c.borrow_element(),
+ Element::FeDistantLight(_) | Element::FePointLight(_) | Element::FeSpotLight(_)
+ )
+ });
+
+ let source_node = sources.next();
+ if source_node.is_none() || sources.next().is_some() {
+ return Err(FilterError::InvalidLightSourceCount);
+ }
+
+ let source_node = source_node.unwrap();
+ let elt = source_node.borrow_element();
+
+ if elt.is_in_error() {
+ return Err(FilterError::ChildNodeInError);
+ }
+
+ let source = match *elt {
+ Element::FeDistantLight(ref l) => {
+ UntransformedLightSource::Distant(l.element_impl.clone())
+ }
+ Element::FePointLight(ref l) => UntransformedLightSource::Point(l.element_impl.clone()),
+ Element::FeSpotLight(ref l) => UntransformedLightSource::Spot(l.element_impl.clone()),
+ _ => unreachable!(),
+ };
+
+ let cascaded = CascadedValues::new_from_node(node);
+ let values = cascaded.get();
+
+ Ok(PrimitiveParams::$params_name($params_name {
+ base: self.base.clone(),
+ in1: self.in1.clone(),
+ surface_scale: self.surface_scale.clone(),
+ kernel_unit_length: self.kernel_unit_length.clone(),
+
+ $($specific_fields: self.$specific_fields.clone(),)+
+
+ light: Light {
+ source,
+ lighting_color: resolve_color(&values.lighting_color().0, UnitInterval::clamp(1.0),
values.color().0),
+ color_interpolation_filters: values.color_interpolation_filters(),
+ }
+ }))
}
}
};
@@ -684,8 +704,20 @@ fn specular_alpha(r: u8, g: u8, b: u8) -> u8 {
max(max(r, g), b)
}
-impl_lighting_filter!(FeDiffuseLighting, DiffuseLighting, diffuse_alpha);
-impl_lighting_filter!(FeSpecularLighting, SpecularLighting, specular_alpha);
+impl_lighting_filter!(
+ FeDiffuseLighting,
+ DiffuseLighting,
+ diffuse_alpha,
+ diffuse_constant,
+);
+
+impl_lighting_filter!(
+ FeSpecularLighting,
+ SpecularLighting,
+ specular_alpha,
+ specular_constant,
+ specular_exponent,
+);
/// 2D normal and factor stored separately.
///
@@ -957,20 +989,30 @@ mod tests {
"#,
);
- let lighting = document.lookup_internal_node("diffuse_distant").unwrap();
- let light = Light::new(&lighting).unwrap();
+ let node = document.lookup_internal_node("diffuse_distant").unwrap();
+ let lighting = borrow_element_as!(node, FeDiffuseLighting);
+ let params = lighting.resolve(&node).unwrap();
+ let diffuse_lighting = match params {
+ PrimitiveParams::DiffuseLighting(l) => l,
+ _ => unreachable!(),
+ };
assert_eq!(
- light.source,
+ diffuse_lighting.light.source,
UntransformedLightSource::Distant(FeDistantLight {
azimuth: 0.0,
elevation: 45.0,
})
);
- let lighting = document.lookup_internal_node("specular_point").unwrap();
- let light = Light::new(&lighting).unwrap();
+ let node = document.lookup_internal_node("specular_point").unwrap();
+ let lighting = borrow_element_as!(node, FeSpecularLighting);
+ let params = lighting.resolve(&node).unwrap();
+ let specular_lighting = match params {
+ PrimitiveParams::SpecularLighting(l) => l,
+ _ => unreachable!(),
+ };
assert_eq!(
- light.source,
+ specular_lighting.light.source,
UntransformedLightSource::Point(FePointLight {
x: 1.0,
y: 2.0,
@@ -978,10 +1020,15 @@ mod tests {
})
);
- let lighting = document.lookup_internal_node("diffuse_spot").unwrap();
- let light = Light::new(&lighting).unwrap();
+ let node = document.lookup_internal_node("diffuse_spot").unwrap();
+ let lighting = borrow_element_as!(node, FeDiffuseLighting);
+ let params = lighting.resolve(&node).unwrap();
+ let diffuse_lighting = match params {
+ PrimitiveParams::DiffuseLighting(l) => l,
+ _ => unreachable!(),
+ };
assert_eq!(
- light.source,
+ diffuse_lighting.light.source,
UntransformedLightSource::Spot(FeSpotLight {
x: 1.0,
y: 2.0,
diff --git a/src/filters/mod.rs b/src/filters/mod.rs
index a3dea17e..a905f9b8 100644
--- a/src/filters/mod.rs
+++ b/src/filters/mod.rs
@@ -52,7 +52,6 @@ pub mod offset;
pub mod tile;
pub mod turbulence;
-use lighting::{FeDiffuseLighting, FeSpecularLighting};
use merge::FeMerge;
use morphology::FeMorphology;
use offset::FeOffset;
@@ -71,7 +70,7 @@ pub enum PrimitiveParams {
ComponentTransfer(component_transfer::ComponentTransfer),
Composite(composite::Composite),
ConvolveMatrix(convolve_matrix::ConvolveMatrix),
- DiffuseLighting(Node),
+ DiffuseLighting(lighting::DiffuseLighting),
DisplacementMap(displacement_map::DisplacementMap),
Flood(flood::Flood),
GaussianBlur(gaussian_blur::GaussianBlur),
@@ -79,7 +78,7 @@ pub enum PrimitiveParams {
Merge(Node),
Morphology(Node),
Offset(Node),
- SpecularLighting(Node),
+ SpecularLighting(lighting::SpecularLighting),
Tile(Node),
Turbulence(Node),
}
@@ -322,7 +321,7 @@ fn render_primitive(
(Element::FeComponentTransfer(_), ComponentTransfer(p)) => p.render(ctx, acquired_nodes, draw_ctx),
(Element::FeComposite(_), Composite(p)) => p.render(ctx, acquired_nodes, draw_ctx),
(Element::FeConvolveMatrix(_), ConvolveMatrix(p)) => p.render(ctx, acquired_nodes, draw_ctx),
- (Element::FeDiffuseLighting(ref inner), DiffuseLighting(node)) =>
FeDiffuseLighting::render(&inner.element_impl, &node, ctx, acquired_nodes, draw_ctx),
+ (Element::FeDiffuseLighting(_), DiffuseLighting(p)) => p.render(ctx, acquired_nodes, draw_ctx),
(Element::FeDisplacementMap(_), DisplacementMap(p)) => p.render(ctx, acquired_nodes, draw_ctx),
(Element::FeFlood(_), Flood(p)) => p.render(ctx, acquired_nodes, draw_ctx),
(Element::FeGaussianBlur(_), GaussianBlur(p)) => p.render(ctx, acquired_nodes, draw_ctx),
@@ -330,7 +329,7 @@ fn render_primitive(
(Element::FeMerge(ref inner), Merge(node)) =>
FeMerge::render(&inner.element_impl, &node, ctx, acquired_nodes, draw_ctx),
(Element::FeMorphology(ref inner), Morphology(node)) =>
FeMorphology::render(&inner.element_impl, &node, ctx, acquired_nodes, draw_ctx),
(Element::FeOffset(ref inner), Offset(node)) =>
FeOffset::render(&inner.element_impl, &node, ctx, acquired_nodes, draw_ctx),
- (Element::FeSpecularLighting(ref inner), SpecularLighting(node)) =>
FeSpecularLighting::render(&inner.element_impl, &node, ctx, acquired_nodes, draw_ctx),
+ (Element::FeSpecularLighting(_), SpecularLighting(p)) => p.render(ctx, acquired_nodes, draw_ctx),
(Element::FeTile(ref inner), Tile(node)) =>
FeTile::render(&inner.element_impl, &node, ctx, acquired_nodes, draw_ctx),
(Element::FeTurbulence(ref inner), Turbulence(node)) =>
FeTurbulence::render(&inner.element_impl, &node, ctx, acquired_nodes, draw_ctx),
(_, _) => unreachable!(),
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]