[librsvg: 2/5] lighting: split DiffuseLighting and SpecularLighting
- From: Federico Mena Quintero <federico src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg: 2/5] lighting: split DiffuseLighting and SpecularLighting
- Date: Wed, 16 Oct 2019 15:40:19 +0000 (UTC)
commit 413152ec15afcada2092bcce07a0eadbc4506409
Author: Paolo Borelli <pborelli gnome org>
Date: Tue Oct 15 15:25:57 2019 +0200
lighting: split DiffuseLighting and SpecularLighting
Use two structs and a shared Lighting trait
rsvg_internals/src/create_node.rs | 6 +-
rsvg_internals/src/filters/light/lighting.rs | 738 ++++++++++++++-------------
2 files changed, 387 insertions(+), 357 deletions(-)
---
diff --git a/rsvg_internals/src/create_node.rs b/rsvg_internals/src/create_node.rs
index f1650cd6..c5256b6b 100644
--- a/rsvg_internals/src/create_node.rs
+++ b/rsvg_internals/src/create_node.rs
@@ -15,7 +15,7 @@ use crate::filters::{
image::Image,
light::{
light_source::DistantLight, light_source::PointLight, light_source::SpotLight,
- lighting::Lighting,
+ lighting::DiffuseLighting, lighting::SpecularLighting,
},
merge::{Merge, MergeNode},
morphology::Morphology,
@@ -68,7 +68,7 @@ mod creators {
n!(create_composite, FeComposite, Composite::default);
n!(create_convolve_matrix, FeConvolveMatrix, ConvolveMatrix::default);
n!(create_defs, Defs, NodeNonRendering::default);
- n!(create_diffuse_lighting, FeDiffuseLighting, Lighting::new_diffuse);
+ n!(create_diffuse_lighting, FeDiffuseLighting, DiffuseLighting::default);
n!(create_distant_light, FeDistantLight, DistantLight::default);
n!(create_displacement_map, FeDisplacementMap, DisplacementMap::default);
n!(create_ellipse, Ellipse, NodeEllipse::default);
@@ -95,7 +95,7 @@ mod creators {
n!(create_polyline, Polyline, NodePoly::new_open);
n!(create_radial_gradient, RadialGradient, NodeRadialGradient::default);
n!(create_rect, Rect, NodeRect::default);
- n!(create_specular_lighting, FeSpecularLighting, Lighting::new_specular);
+ n!(create_specular_lighting, FeSpecularLighting, SpecularLighting::default);
n!(create_spot_light, FeSpotLight, SpotLight::default);
n!(create_stop, Stop, NodeStop::default);
n!(create_style, Style, NodeStyle::default);
diff --git a/rsvg_internals/src/filters/light/lighting.rs b/rsvg_internals/src/filters/light/lighting.rs
index 0b50fb6c..ffdb8def 100644
--- a/rsvg_internals/src/filters/light/lighting.rs
+++ b/rsvg_internals/src/filters/light/lighting.rs
@@ -42,110 +42,26 @@ use crate::surface_utils::{
};
use crate::util::clamp;
-/// Properties specific to either diffuse or specular lighting.
-#[derive(Clone, Copy)]
-enum Data {
- Diffuse {
- diffuse_constant: f64,
- },
- Specular {
- specular_constant: f64,
- specular_exponent: f64,
- },
+trait Lighting {
+ fn common(&self) -> &Common;
+
+ fn compute_factor(&self, normal: Normal, light_vector: Vector3<f64>) -> f64;
}
-/// The `feDiffuseLighting` and `feSpecularLighting` filter primitives.
-pub struct Lighting {
+struct Common {
base: PrimitiveWithInput,
surface_scale: f64,
kernel_unit_length: Option<(f64, f64)>,
- data: Data,
}
-impl Lighting {
- /// Constructs a new diffuse `Lighting` with empty properties.
- #[inline]
- pub fn new_diffuse() -> Lighting {
- Lighting {
- data: Data::Diffuse {
- diffuse_constant: 1.0,
- },
- ..Self::default()
- }
- }
-
- /// Constructs a new specular `Lighting` with empty properties.
- #[inline]
- pub fn new_specular() -> Lighting {
- Lighting {
- data: Data::Specular {
- specular_constant: 1.0,
- specular_exponent: 1.0,
- },
- ..Self::default()
- }
- }
-
- #[inline]
- pub fn compute_factor(&self, normal: Normal, light_vector: Vector3<f64>) -> f64 {
- match self.data {
- Data::Diffuse { diffuse_constant } => {
- let k = if normal.normal.is_zero() {
- // Common case of (0, 0, 1) normal.
- light_vector.z
- } else {
- let mut n = normal
- .normal
- .map(|x| f64::from(x) * self.surface_scale / 255.);
- n.component_mul_assign(&normal.factor);
- let normal = Vector3::new(n.x, n.y, 1.0);
-
- normal.dot(&light_vector) / normal.norm()
- };
-
- diffuse_constant * k
- }
- Data::Specular {
- specular_constant,
- specular_exponent,
- } => {
- let h = light_vector + Vector3::new(0.0, 0.0, 1.0);
- let h_norm = h.norm();
- if h_norm == 0.0 {
- 0.0
- } else {
- let k = if normal.normal.is_zero() {
- // Common case of (0, 0, 1) normal.
- let n_dot_h = h.z / h_norm;
- if specular_exponent == 1.0 {
- n_dot_h
- } else {
- n_dot_h.powf(specular_exponent)
- }
- } else {
- let mut n = normal
- .normal
- .map(|x| f64::from(x) * self.surface_scale / 255.);
- n.component_mul_assign(&normal.factor);
- let normal = Vector3::new(n.x, n.y, 1.0);
-
- let n_dot_h = normal.dot(&h) / normal.norm() / h_norm;
- if specular_exponent == 1.0 {
- n_dot_h
- } else {
- n_dot_h.powf(specular_exponent)
- }
- };
-
- specular_constant * k
- }
- }
+impl Common {
+ fn new(base: PrimitiveWithInput) -> Self {
+ Self {
+ base,
+ surface_scale: 1.0,
+ kernel_unit_length: None,
}
}
-}
-
-impl NodeTrait for Lighting {
- impl_node_as_filter!();
fn set_atts(&mut self, parent: Option<&RsvgNode>, pbag: &PropertyBag<'_>) -> NodeResult {
self.base.set_atts(parent, pbag)?;
@@ -175,67 +91,48 @@ impl NodeTrait for Lighting {
}
}
- match self.data {
- Data::Diffuse {
- ref mut diffuse_constant,
- } => {
- for (attr, value) in pbag.iter() {
- match attr {
- local_name!("diffuseConstant") => {
- *diffuse_constant = parsers::number(value)
- .attribute(attr.clone())
- .and_then(|x| {
- if x >= 0.0 {
- Ok(x)
- } else {
- Err(NodeError::value_error(
- attr,
- "diffuseConstant can't be negative",
- ))
- }
- })?;
- }
- _ => (),
- }
- }
- }
- Data::Specular {
- ref mut specular_constant,
- ref mut specular_exponent,
- } => {
- for (attr, value) in pbag.iter() {
- match attr {
- local_name!("specularConstant") => {
- *specular_constant = parsers::number(value)
- .attribute(attr.clone())
- .and_then(|x| {
- if x >= 0.0 {
- Ok(x)
- } else {
- Err(NodeError::value_error(
- attr,
- "specularConstant can't be negative",
- ))
- }
- })?;
- }
- local_name!("specularExponent") => {
- *specular_exponent = parsers::number(value)
- .attribute(attr.clone())
- .and_then(|x| {
- if x >= 1.0 && x <= 128.0 {
- Ok(x)
- } else {
- Err(NodeError::value_error(
- attr,
- "specularExponent should be between 1.0 and 128.0",
- ))
- }
- })?;
- }
- _ => (),
- }
+ Ok(())
+ }
+}
+
+/// The `feDiffuseLighting` filter primitives.
+pub struct DiffuseLighting {
+ common: Common,
+ diffuse_constant: f64,
+}
+
+impl Default for DiffuseLighting {
+ fn default() -> Self {
+ Self {
+ common: Common::new(PrimitiveWithInput::new::<Self>()),
+ diffuse_constant: 1.0,
+ }
+ }
+}
+
+impl NodeTrait for DiffuseLighting {
+ impl_node_as_filter!();
+
+ fn set_atts(&mut self, parent: Option<&RsvgNode>, pbag: &PropertyBag<'_>) -> NodeResult {
+ self.common.set_atts(parent, pbag)?;
+
+ for (attr, value) in pbag.iter() {
+ match attr {
+ local_name!("diffuseConstant") => {
+ self.diffuse_constant = parsers::number(value)
+ .attribute(attr.clone())
+ .and_then(|x| {
+ if x >= 0.0 {
+ Ok(x)
+ } else {
+ Err(NodeError::value_error(
+ attr,
+ "diffuseConstant can't be negative",
+ ))
+ }
+ })?;
}
+ _ => (),
}
}
@@ -243,237 +140,386 @@ impl NodeTrait for Lighting {
}
}
-impl Filter for Lighting {
- fn render(
- &self,
- node: &RsvgNode,
- ctx: &FilterContext,
- draw_ctx: &mut DrawingCtx,
- ) -> Result<FilterResult, FilterError> {
- let input = self.base.get_input(ctx, draw_ctx)?;
- let mut bounds = self
- .base
- .get_bounds(ctx)
- .add_input(&input)
- .into_irect(draw_ctx);
- let original_bounds = bounds;
-
- let scale = self
- .kernel_unit_length
- .map(|(dx, dy)| ctx.paffine().transform_distance(dx, dy));
-
- 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,
+impl Lighting for DiffuseLighting {
+ #[inline]
+ fn common(&self) -> &Common {
+ &self.common
+ }
+
+ #[inline]
+ fn compute_factor(&self, normal: Normal, light_vector: Vector3<f64>) -> f64 {
+ let k = if normal.normal.is_zero() {
+ // Common case of (0, 0, 1) normal.
+ light_vector.z
+ } else {
+ let mut n = normal
+ .normal
+ .map(|x| f64::from(x) * self.common().surface_scale / 255.);
+ n.component_mul_assign(&normal.factor);
+ let normal = Vector3::new(n.x, n.y, 1.0);
+
+ normal.dot(&light_vector) / normal.norm()
};
- let light_source = find_light_source(node, ctx)?;
- let mut input_surface = input.surface().clone();
+ self.diffuse_constant * k
+ }
+}
- if let Some((ox, oy)) = scale {
- // Scale the input surface to match kernel_unit_length.
- let (new_surface, new_bounds) = input_surface.scale(bounds, 1.0 / ox, 1.0 / oy)?;
+/// The `feSpecularLighting` filter primitives.
+pub struct SpecularLighting {
+ common: Common,
+ specular_constant: f64,
+ specular_exponent: f64,
+}
- input_surface = new_surface;
- bounds = new_bounds;
+impl Default for SpecularLighting {
+ fn default() -> Self {
+ Self {
+ common: Common::new(PrimitiveWithInput::new::<Self>()),
+ specular_constant: 1.0,
+ specular_exponent: 1.0,
}
+ }
+}
- // Check if the surface is too small for normal computation. This case is unspecified;
- // WebKit doesn't render anything in this case.
- if bounds.x1 < bounds.x0 + 2 || bounds.y1 < bounds.y0 + 2 {
- return Err(FilterError::LightingInputTooSmall);
+impl NodeTrait for SpecularLighting {
+ impl_node_as_filter!();
+
+ fn set_atts(&mut self, parent: Option<&RsvgNode>, pbag: &PropertyBag<'_>) -> NodeResult {
+ self.common.set_atts(parent, pbag)?;
+
+ for (attr, value) in pbag.iter() {
+ match attr {
+ local_name!("specularConstant") => {
+ self.specular_constant = parsers::number(value)
+ .attribute(attr.clone())
+ .and_then(|x| {
+ if x >= 0.0 {
+ Ok(x)
+ } else {
+ Err(NodeError::value_error(
+ attr,
+ "specularConstant can't be negative",
+ ))
+ }
+ })?;
+ }
+ local_name!("specularExponent") => {
+ self.specular_exponent = parsers::number(value)
+ .attribute(attr.clone())
+ .and_then(|x| {
+ if x >= 1.0 && x <= 128.0 {
+ Ok(x)
+ } else {
+ Err(NodeError::value_error(
+ attr,
+ "specularExponent should be between 1.0 and 128.0",
+ ))
+ }
+ })?;
+ }
+ _ => (),
+ }
}
- let (ox, oy) = scale.unwrap_or((1.0, 1.0));
-
- let mut output_surface = ImageSurface::create(
- cairo::Format::ARgb32,
- input_surface.width(),
- input_surface.height(),
- )?;
-
- let output_stride = output_surface.get_stride() as usize;
- {
- let mut output_data = output_surface.get_data().unwrap();
- let output_slice = &mut *output_data;
-
- let compute_output_pixel =
- |mut output_slice: &mut [u8], base_y, x, y, normal: Normal| {
- let pixel = input_surface.get_pixel(x, y);
-
- let scaled_x = f64::from(x) * ox;
- let scaled_y = f64::from(y) * oy;
- let z = f64::from(pixel.a) / 255.0 * self.surface_scale;
- let light_vector = light_source.vector(scaled_x, scaled_y, z);
- let light_color = light_source.color(lighting_color, light_vector);
-
- let factor = self.compute_factor(normal, light_vector);
- let compute = |x| (clamp(factor * f64::from(x), 0.0, 255.0) + 0.5) as u8;
-
- let mut output_pixel = Pixel {
- r: compute(light_color.red),
- g: compute(light_color.green),
- b: compute(light_color.blue),
- a: 255,
- };
+ Ok(())
+ }
+}
- if let Data::Specular { .. } = self.data {
- output_pixel.a = max(max(output_pixel.r, output_pixel.g), output_pixel.b);
- }
+impl Lighting for SpecularLighting {
+ #[inline]
+ fn common(&self) -> &Common {
+ &self.common
+ }
+
+ #[inline]
+ fn compute_factor(&self, normal: Normal, light_vector: Vector3<f64>) -> f64 {
+ let h = light_vector + Vector3::new(0.0, 0.0, 1.0);
+ let h_norm = h.norm();
+
+ if h_norm == 0.0 {
+ return 0.0;
+ }
+
+ let k = if normal.normal.is_zero() {
+ // Common case of (0, 0, 1) normal.
+ let n_dot_h = h.z / h_norm;
+ if self.specular_exponent == 1.0 {
+ n_dot_h
+ } else {
+ n_dot_h.powf(self.specular_exponent)
+ }
+ } else {
+ let mut n = normal
+ .normal
+ .map(|x| f64::from(x) * self.common().surface_scale / 255.);
+ n.component_mul_assign(&normal.factor);
+ let normal = Vector3::new(n.x, n.y, 1.0);
+
+ let n_dot_h = normal.dot(&h) / normal.norm() / h_norm;
+ if self.specular_exponent == 1.0 {
+ n_dot_h
+ } else {
+ n_dot_h.powf(self.specular_exponent)
+ }
+ };
+
+ self.specular_constant * k
+ }
+}
- output_slice.set_pixel(output_stride, output_pixel, x, y - base_y);
+// We cannot use a blanket impl<T: Lighting> Filter for T because we do
+// not want to make the Lighting trait public, so we use a macro
+macro_rules! impl_lighting_filter {
+ ($lighting_type:ty, $alpha_func:ident) => {
+ impl Filter for $lighting_type {
+ fn render(
+ &self,
+ node: &RsvgNode,
+ ctx: &FilterContext,
+ draw_ctx: &mut DrawingCtx,
+ ) -> Result<FilterResult, FilterError> {
+ let input = self.common().base.get_input(ctx, draw_ctx)?;
+ let mut bounds = self
+ .common()
+ .base
+ .get_bounds(ctx)
+ .add_input(&input)
+ .into_irect(draw_ctx);
+ let original_bounds = bounds;
+
+ let scale = self
+ .common()
+ .kernel_unit_length
+ .map(|(dx, dy)| ctx.paffine().transform_distance(dx, dy));
+
+ 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,
};
- // Top left.
- compute_output_pixel(
- output_slice,
- 0,
- bounds.x0 as u32,
- bounds.y0 as u32,
- top_left_normal(&input_surface, bounds),
- );
-
- // Top right.
- compute_output_pixel(
- output_slice,
- 0,
- bounds.x1 as u32 - 1,
- bounds.y0 as u32,
- top_right_normal(&input_surface, bounds),
- );
-
- // Bottom left.
- compute_output_pixel(
- output_slice,
- 0,
- bounds.x0 as u32,
- bounds.y1 as u32 - 1,
- bottom_left_normal(&input_surface, bounds),
- );
-
- // Bottom right.
- compute_output_pixel(
- output_slice,
- 0,
- bounds.x1 as u32 - 1,
- bounds.y1 as u32 - 1,
- bottom_right_normal(&input_surface, bounds),
- );
-
- if bounds.x1 - bounds.x0 >= 3 {
- // Top row.
- for x in bounds.x0 as u32 + 1..bounds.x1 as u32 - 1 {
+ let light_source = find_light_source(node, ctx)?;
+ let mut input_surface = input.surface().clone();
+
+ if let Some((ox, oy)) = scale {
+ // Scale the input surface to match kernel_unit_length.
+ let (new_surface, new_bounds) = input_surface.scale(bounds, 1.0 / ox, 1.0 / oy)?;
+
+ input_surface = new_surface;
+ bounds = new_bounds;
+ }
+
+ // Check if the surface is too small for normal computation. This case is unspecified;
+ // WebKit doesn't render anything in this case.
+ if bounds.x1 < bounds.x0 + 2 || bounds.y1 < bounds.y0 + 2 {
+ return Err(FilterError::LightingInputTooSmall);
+ }
+
+ let (ox, oy) = scale.unwrap_or((1.0, 1.0));
+
+ let mut output_surface = ImageSurface::create(
+ cairo::Format::ARgb32,
+ input_surface.width(),
+ input_surface.height(),
+ )?;
+
+ let output_stride = output_surface.get_stride() as usize;
+ {
+ let mut output_data = output_surface.get_data().unwrap();
+ let output_slice = &mut *output_data;
+
+ let compute_output_pixel =
+ |mut output_slice: &mut [u8], base_y, x, y, normal: Normal| {
+ let pixel = input_surface.get_pixel(x, y);
+
+ let scaled_x = f64::from(x) * ox;
+ let scaled_y = f64::from(y) * oy;
+ let z = f64::from(pixel.a) / 255.0 * self.common().surface_scale;
+ let light_vector = light_source.vector(scaled_x, scaled_y, z);
+ let light_color = light_source.color(lighting_color, light_vector);
+
+ // compute the factor just once for the three colors
+ let factor = self.compute_factor(normal, light_vector);
+ let compute = |x| (clamp(factor * f64::from(x), 0.0, 255.0) + 0.5) as u8;
+
+ let r = compute(light_color.red);
+ let g = compute(light_color.green);
+ let b = compute(light_color.blue);
+ let a = $alpha_func(r, g, b);
+
+ let output_pixel = Pixel {
+ r,
+ g,
+ b,
+ a,
+ };
+
+ output_slice.set_pixel(output_stride, output_pixel, x, y - base_y);
+ };
+
+ // Top left.
compute_output_pixel(
output_slice,
0,
- x,
+ bounds.x0 as u32,
bounds.y0 as u32,
- top_row_normal(&input_surface, bounds, x),
+ top_left_normal(&input_surface, bounds),
);
- }
- // Bottom row.
- for x in bounds.x0 as u32 + 1..bounds.x1 as u32 - 1 {
+ // Top right.
compute_output_pixel(
output_slice,
0,
- x,
- bounds.y1 as u32 - 1,
- bottom_row_normal(&input_surface, bounds, x),
+ bounds.x1 as u32 - 1,
+ bounds.y0 as u32,
+ top_right_normal(&input_surface, bounds),
);
- }
- }
- if bounds.y1 - bounds.y0 >= 3 {
- // Left column.
- for y in bounds.y0 as u32 + 1..bounds.y1 as u32 - 1 {
+ // Bottom left.
compute_output_pixel(
output_slice,
0,
bounds.x0 as u32,
- y,
- left_column_normal(&input_surface, bounds, y),
+ bounds.y1 as u32 - 1,
+ bottom_left_normal(&input_surface, bounds),
);
- }
- // Right column.
- for y in bounds.y0 as u32 + 1..bounds.y1 as u32 - 1 {
+ // Bottom right.
compute_output_pixel(
output_slice,
0,
bounds.x1 as u32 - 1,
- y,
- right_column_normal(&input_surface, bounds, y),
+ bounds.y1 as u32 - 1,
+ bottom_right_normal(&input_surface, bounds),
);
- }
- }
- if bounds.x1 - bounds.x0 >= 3 && bounds.y1 - bounds.y0 >= 3 {
- // Interior pixels.
- let first_row = bounds.y0 as u32 + 1;
- let one_past_last_row = bounds.y1 as u32 - 1;
- let first_pixel = (first_row as usize) * output_stride;
- let one_past_last_pixel = (one_past_last_row as usize) * output_stride;
-
- output_slice[first_pixel..one_past_last_pixel]
- .par_chunks_mut(output_stride)
- .zip(first_row..one_past_last_row)
- .for_each(|(slice, y)| {
+ if bounds.x1 - bounds.x0 >= 3 {
+ // Top row.
for x in bounds.x0 as u32 + 1..bounds.x1 as u32 - 1 {
compute_output_pixel(
- slice,
- y,
+ output_slice,
+ 0,
+ x,
+ bounds.y0 as u32,
+ top_row_normal(&input_surface, bounds, x),
+ );
+ }
+
+ // Bottom row.
+ for x in bounds.x0 as u32 + 1..bounds.x1 as u32 - 1 {
+ compute_output_pixel(
+ output_slice,
+ 0,
x,
+ bounds.y1 as u32 - 1,
+ bottom_row_normal(&input_surface, bounds, x),
+ );
+ }
+ }
+
+ if bounds.y1 - bounds.y0 >= 3 {
+ // Left column.
+ for y in bounds.y0 as u32 + 1..bounds.y1 as u32 - 1 {
+ compute_output_pixel(
+ output_slice,
+ 0,
+ bounds.x0 as u32,
+ y,
+ left_column_normal(&input_surface, bounds, y),
+ );
+ }
+
+ // Right column.
+ for y in bounds.y0 as u32 + 1..bounds.y1 as u32 - 1 {
+ compute_output_pixel(
+ output_slice,
+ 0,
+ bounds.x1 as u32 - 1,
y,
- interior_normal(&input_surface, bounds, x, y),
+ right_column_normal(&input_surface, bounds, y),
);
}
- });
+ }
+
+ if bounds.x1 - bounds.x0 >= 3 && bounds.y1 - bounds.y0 >= 3 {
+ // Interior pixels.
+ let first_row = bounds.y0 as u32 + 1;
+ let one_past_last_row = bounds.y1 as u32 - 1;
+ let first_pixel = (first_row as usize) * output_stride;
+ let one_past_last_pixel = (one_past_last_row as usize) * output_stride;
+
+ output_slice[first_pixel..one_past_last_pixel]
+ .par_chunks_mut(output_stride)
+ .zip(first_row..one_past_last_row)
+ .for_each(|(slice, y)| {
+ for x in bounds.x0 as u32 + 1..bounds.x1 as u32 - 1 {
+ compute_output_pixel(
+ slice,
+ y,
+ x,
+ y,
+ interior_normal(&input_surface, bounds, x, y),
+ );
+ }
+ });
+ }
+ }
+
+ let cascaded = CascadedValues::new_from_node(node);
+ let values = cascaded.get();
+ // The generated color values are in the color space determined by
+ // color-interpolation-filters.
+ let surface_type =
+ if values.color_interpolation_filters == ColorInterpolationFilters::LinearRgb {
+ SurfaceType::LinearRgb
+ } else {
+ SurfaceType::SRgb
+ };
+ let mut output_surface = SharedImageSurface::new(output_surface, surface_type)?;
+
+ if let Some((ox, oy)) = scale {
+ // Scale the output surface back.
+ output_surface = output_surface.scale_to(
+ ctx.source_graphic().width(),
+ ctx.source_graphic().height(),
+ original_bounds,
+ ox,
+ oy,
+ )?;
+
+ bounds = original_bounds;
+ }
+
+ Ok(FilterResult {
+ name: self.common().base.result.clone(),
+ output: FilterOutput {
+ surface: output_surface,
+ bounds,
+ },
+ })
}
- }
- let cascaded = CascadedValues::new_from_node(node);
- let values = cascaded.get();
- // The generated color values are in the color space determined by
- // color-interpolation-filters.
- let surface_type =
- if values.color_interpolation_filters == ColorInterpolationFilters::LinearRgb {
- SurfaceType::LinearRgb
- } else {
- SurfaceType::SRgb
- };
- let mut output_surface = SharedImageSurface::new(output_surface, surface_type)?;
-
- if let Some((ox, oy)) = scale {
- // Scale the output surface back.
- output_surface = output_surface.scale_to(
- ctx.source_graphic().width(),
- ctx.source_graphic().height(),
- original_bounds,
- ox,
- oy,
- )?;
-
- bounds = original_bounds;
+ #[inline]
+ fn is_affected_by_color_interpolation_filters(&self) -> bool {
+ true
+ }
}
-
- Ok(FilterResult {
- name: self.base.result.clone(),
- output: FilterOutput {
- surface: output_surface,
- bounds,
- },
- })
}
+}
- #[inline]
- fn is_affected_by_color_interpolation_filters(&self) -> bool {
- true
- }
+const fn diffuse_alpha(_r: u8, _g: u8, _b: u8) -> u8 {
+ 255
}
+fn specular_alpha(r: u8, g: u8, b: u8) -> u8 {
+ max(max(r, g), b)
+}
+
+impl_lighting_filter!(DiffuseLighting, diffuse_alpha);
+impl_lighting_filter!(SpecularLighting, specular_alpha);
+
fn find_light_source(node: &RsvgNode, ctx: &FilterContext) -> Result<LightSource, FilterError> {
let mut light_sources = node
.children()
@@ -502,19 +548,3 @@ fn find_light_source(node: &RsvgNode, ctx: &FilterContext) -> Result<LightSource
Ok(light_source)
}
-
-impl Default for Lighting {
- #[inline]
- fn default() -> Self {
- Self {
- base: PrimitiveWithInput::new::<Self>(),
- surface_scale: 1.0,
- kernel_unit_length: None,
-
- // The data field is unused in this case.
- data: Data::Diffuse {
- diffuse_constant: 1.0,
- },
- }
- }
-}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]