[librsvg] Merge diffuse and specular lighting code
- From: Federico Mena Quintero <federico src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg] Merge diffuse and specular lighting code
- Date: Mon, 6 Aug 2018 19:30:16 +0000 (UTC)
commit d25d396f31514098d3b2fad6fccbc7d42d84a859
Author: Ivan Molodetskikh <yalterz gmail com>
Date: Mon Jul 30 12:31:44 2018 +0300
Merge diffuse and specular lighting code
It's very similar, no need to duplicate it.
Makefile.am | 3 +-
.../light/{diffuse_lighting.rs => lighting.rs} | 195 ++++++++++++----
rsvg_internals/src/filters/light/mod.rs | 3 +-
.../src/filters/light/specular_lighting.rs | 249 ---------------------
rsvg_internals/src/filters/mod.rs | 3 +-
rsvg_internals/src/load.rs | 10 +-
6 files changed, 163 insertions(+), 300 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index 691f5e8c..02c57393 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -67,9 +67,8 @@ RUST_SRC = \
rsvg_internals/src/filters/flood.rs \
rsvg_internals/src/filters/gaussian_blur.rs \
rsvg_internals/src/filters/image.rs \
- rsvg_internals/src/filters/light/diffuse_lighting.rs \
rsvg_internals/src/filters/light/light_source.rs \
- rsvg_internals/src/filters/light/specular_lighting.rs \
+ rsvg_internals/src/filters/light/lighting.rs \
rsvg_internals/src/filters/light/mod.rs \
rsvg_internals/src/filters/merge.rs \
rsvg_internals/src/filters/morphology.rs \
diff --git a/rsvg_internals/src/filters/light/diffuse_lighting.rs
b/rsvg_internals/src/filters/light/lighting.rs
similarity index 50%
rename from rsvg_internals/src/filters/light/diffuse_lighting.rs
rename to rsvg_internals/src/filters/light/lighting.rs
index 1b4f7c58..26bc65cd 100644
--- a/rsvg_internals/src/filters/light/diffuse_lighting.rs
+++ b/rsvg_internals/src/filters/light/lighting.rs
@@ -1,7 +1,9 @@
use std::cell::Cell;
+use std::cmp::max;
use cairo::{self, ImageSurface, MatrixTrait};
use cssparser;
+use nalgebra::Vector3;
use attributes::Attribute;
use drawing_ctx::DrawingCtx;
@@ -26,28 +28,51 @@ use surface_utils::{
};
use util::clamp;
-/// The `feDiffuseLighting` filter primitive.
-pub struct DiffuseLighting {
+/// Properties specific to either diffuse or specular lighting.
+enum Data {
+ Diffuse {
+ diffuse_constant: Cell<f64>,
+ },
+ Specular {
+ specular_constant: Cell<f64>,
+ specular_exponent: Cell<f64>,
+ },
+}
+
+/// The `feDiffuseLighting` and `feSpecularLighting` filter primitives.
+pub struct Lighting {
base: PrimitiveWithInput,
surface_scale: Cell<f64>,
- diffuse_constant: Cell<f64>,
kernel_unit_length: Cell<Option<(f64, f64)>>,
+ data: Data,
}
-impl DiffuseLighting {
- /// Constructs a new `DiffuseLighting` with empty properties.
+impl Lighting {
+ /// Constructs a new diffuse `Lighting` with empty properties.
#[inline]
- pub fn new() -> DiffuseLighting {
- DiffuseLighting {
- base: PrimitiveWithInput::new::<Self>(),
- surface_scale: Cell::new(1.0),
- diffuse_constant: Cell::new(1.0),
- kernel_unit_length: Cell::new(None),
+ pub fn new_diffuse() -> Lighting {
+ Lighting {
+ data: Data::Diffuse {
+ diffuse_constant: Cell::new(1.0),
+ },
+ ..Self::default()
+ }
+ }
+
+ /// Constructs a new specular `Lighting` with empty properties.
+ #[inline]
+ pub fn new_specular() -> Lighting {
+ Lighting {
+ data: Data::Specular {
+ specular_constant: Cell::new(1.0),
+ specular_exponent: Cell::new(1.0),
+ },
+ ..Self::default()
}
}
}
-impl NodeTrait for DiffuseLighting {
+impl NodeTrait for Lighting {
fn set_atts(
&self,
node: &RsvgNode,
@@ -61,20 +86,6 @@ impl NodeTrait for DiffuseLighting {
Attribute::SurfaceScale => self
.surface_scale
.set(parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?),
- Attribute::DiffuseConstant => self.diffuse_constant.set(
- parsers::number(value)
- .map_err(|err| NodeError::parse_error(attr, err))
- .and_then(|x| {
- if x >= 0.0 {
- Ok(x)
- } else {
- Err(NodeError::value_error(
- attr,
- "diffuseConstant can't be negative",
- ))
- }
- })?,
- ),
Attribute::KernelUnitLength => self.kernel_unit_length.set(Some(
parsers::number_optional_number(value)
.map_err(|err| NodeError::parse_error(attr, err))
@@ -93,11 +104,75 @@ impl NodeTrait for DiffuseLighting {
}
}
+ match self.data {
+ Data::Diffuse {
+ ref diffuse_constant,
+ } => {
+ for (_key, attr, value) in pbag.iter() {
+ match attr {
+ Attribute::DiffuseConstant => diffuse_constant.set(
+ parsers::number(value)
+ .map_err(|err| NodeError::parse_error(attr, err))
+ .and_then(|x| {
+ if x >= 0.0 {
+ Ok(x)
+ } else {
+ Err(NodeError::value_error(
+ attr,
+ "diffuseConstant can't be negative",
+ ))
+ }
+ })?,
+ ),
+ _ => (),
+ }
+ }
+ }
+ Data::Specular {
+ ref specular_constant,
+ ref specular_exponent,
+ } => {
+ for (_key, attr, value) in pbag.iter() {
+ match attr {
+ Attribute::SpecularConstant => specular_constant.set(
+ parsers::number(value)
+ .map_err(|err| NodeError::parse_error(attr, err))
+ .and_then(|x| {
+ if x >= 0.0 {
+ Ok(x)
+ } else {
+ Err(NodeError::value_error(
+ attr,
+ "specularConstant can't be negative",
+ ))
+ }
+ })?,
+ ),
+ Attribute::SpecularExponent => specular_exponent.set(
+ parsers::number(value)
+ .map_err(|err| NodeError::parse_error(attr, err))
+ .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(())
}
}
-impl Filter for DiffuseLighting {
+impl Filter for Lighting {
fn render(
&self,
node: &RsvgNode,
@@ -118,7 +193,6 @@ impl Filter for DiffuseLighting {
.map(|(dx, dy)| ctx.paffine().transform_distance(dx, dy));
let surface_scale = self.surface_scale.get();
- let diffuse_constant = self.diffuse_constant.get();
let cascaded = node.get_cascaded_values();
let values = cascaded.get();
@@ -168,19 +242,48 @@ impl Filter for DiffuseLighting {
let scaled_y = f64::from(y) * oy;
let z = f64::from(pixel.a) / 255.0 * surface_scale;
let light_vector = light_source.vector(scaled_x, scaled_y, z, ctx);
-
let light_color = light_source.color(lighting_color, light_vector, ctx);
- let n_dot_l = normal.dot(&light_vector);
- let compute =
- |x| clamp(diffuse_constant * n_dot_l * f64::from(x), 0.0, 255.0).round() as u8;
+ let output_pixel = match self.data {
+ Data::Diffuse {
+ ref diffuse_constant,
+ } => {
+ let n_dot_l = normal.dot(&light_vector);
+ let compute = |x| {
+ clamp(diffuse_constant.get() * n_dot_l * f64::from(x), 0.0, 255.0)
+ .round() as u8
+ };
+
+ Pixel {
+ r: compute(light_color.red),
+ g: compute(light_color.green),
+ b: compute(light_color.blue),
+ a: 255,
+ }.premultiply()
+ }
+ Data::Specular {
+ ref specular_constant,
+ ref specular_exponent,
+ } => {
+ let mut h = light_vector + Vector3::new(0.0, 0.0, 1.0);
+ let _ = h.try_normalize_mut(0.0);
+
+ let n_dot_h = normal.dot(&h);
+ let factor =
+ specular_constant.get() * n_dot_h.powf(specular_exponent.get());
+ let compute = |x| clamp(factor * f64::from(x), 0.0, 255.0).round() as u8;
+
+ let mut output_pixel = Pixel {
+ r: compute(light_color.red),
+ g: compute(light_color.green),
+ b: compute(light_color.blue),
+ a: 0,
+ };
+ output_pixel.a = max(max(output_pixel.r, output_pixel.g), output_pixel.b);
+ output_pixel
+ }
+ };
- let output_pixel = Pixel {
- r: compute(light_color.red),
- g: compute(light_color.green),
- b: compute(light_color.blue),
- a: 255,
- }.premultiply();
output_data.set_pixel(output_stride, output_pixel, x, y);
}
}
@@ -224,3 +327,19 @@ impl Filter for DiffuseLighting {
true
}
}
+
+impl Default for Lighting {
+ #[inline]
+ fn default() -> Self {
+ Self {
+ base: PrimitiveWithInput::new::<Self>(),
+ surface_scale: Cell::new(1.0),
+ kernel_unit_length: Cell::new(None),
+
+ // The data field is unused in this case.
+ data: Data::Diffuse {
+ diffuse_constant: Cell::new(1.0),
+ },
+ }
+ }
+}
diff --git a/rsvg_internals/src/filters/light/mod.rs b/rsvg_internals/src/filters/light/mod.rs
index c345c5f4..62f19fd7 100644
--- a/rsvg_internals/src/filters/light/mod.rs
+++ b/rsvg_internals/src/filters/light/mod.rs
@@ -4,9 +4,8 @@ use nalgebra::{Matrix3, Vector3};
use filters::context::IRect;
use surface_utils::{iterators::PixelRectangle, shared_surface::SharedImageSurface, EdgeMode};
-pub mod diffuse_lighting;
pub mod light_source;
-pub mod specular_lighting;
+pub mod lighting;
/// Computes and returns the normal vector for the light filters.
fn normal(
diff --git a/rsvg_internals/src/filters/mod.rs b/rsvg_internals/src/filters/mod.rs
index 410fc6be..0961244c 100644
--- a/rsvg_internals/src/filters/mod.rs
+++ b/rsvg_internals/src/filters/mod.rs
@@ -299,8 +299,7 @@ pub fn render(
flood::Flood,
gaussian_blur::GaussianBlur,
image::Image,
- light::diffuse_lighting::DiffuseLighting,
- light::specular_lighting::SpecularLighting,
+ light::lighting::Lighting,
merge::Merge,
morphology::Morphology,
offset::Offset,
diff --git a/rsvg_internals/src/load.rs b/rsvg_internals/src/load.rs
index efaa474f..537b2230 100644
--- a/rsvg_internals/src/load.rs
+++ b/rsvg_internals/src/load.rs
@@ -14,11 +14,7 @@ use filters::{
flood::Flood,
gaussian_blur::GaussianBlur,
image::Image,
- light::{
- diffuse_lighting::DiffuseLighting,
- light_source::LightSource,
- specular_lighting::SpecularLighting,
- },
+ light::{light_source::LightSource, lighting::Lighting},
merge::{Merge, MergeNode},
morphology::Morphology,
node::NodeFilter,
@@ -97,7 +93,7 @@ node_create_fn!(create_defs, Defs, NodeDefs::new);
node_create_fn!(
create_diffuse_lighting,
FilterPrimitiveDiffuseLighting,
- DiffuseLighting::new
+ Lighting::new_diffuse
);
node_create_fn!(
create_distant_light,
@@ -155,7 +151,7 @@ node_create_fn!(create_rect, Rect, NodeRect::new);
node_create_fn!(
create_specular_lighting,
FilterPrimitiveSpecularLighting,
- SpecularLighting::new
+ Lighting::new_specular
);
node_create_fn!(create_spot_light, LightSource, LightSource::new_spot_light);
node_create_fn!(create_stop, Stop, NodeStop::new);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]