[librsvg: 2/4] Use separate structs for light source nodes
- From: Federico Mena Quintero <federico src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg: 2/4] Use separate structs for light source nodes
- Date: Mon, 14 Oct 2019 23:32:06 +0000 (UTC)
commit 92f6d900a38aa42fa5e84c4edb3abb1870571294
Author: Paolo Borelli <pborelli gnome org>
Date: Sat Oct 12 10:41:18 2019 +0200
Use separate structs for light source nodes
This way they can be created with default()
rsvg_internals/src/create_node.rs | 11 +-
rsvg_internals/src/filters/light/light_source.rs | 285 ++++++++++-------------
rsvg_internals/src/filters/light/lighting.rs | 54 +++--
3 files changed, 163 insertions(+), 187 deletions(-)
---
diff --git a/rsvg_internals/src/create_node.rs b/rsvg_internals/src/create_node.rs
index 2b722d0f..a63279c0 100644
--- a/rsvg_internals/src/create_node.rs
+++ b/rsvg_internals/src/create_node.rs
@@ -13,7 +13,10 @@ use crate::filters::{
flood::Flood,
gaussian_blur::GaussianBlur,
image::Image,
- light::{light_source::LightSource, lighting::Lighting},
+ light::{
+ light_source::DistantLight, light_source::PointLight, light_source::SpotLight,
+ lighting::Lighting,
+ },
merge::{Merge, MergeNode},
morphology::Morphology,
node::NodeFilter,
@@ -66,7 +69,7 @@ mod creators {
n!(create_convolve_matrix, FeConvolveMatrix, ConvolveMatrix::default);
n!(create_defs, Defs, NodeNonRendering::default);
n!(create_diffuse_lighting, FeDiffuseLighting, Lighting::new_diffuse);
- n!(create_distant_light, FeDistantLight, LightSource::new_distant_light);
+ n!(create_distant_light, FeDistantLight, DistantLight::default);
n!(create_displacement_map, FeDisplacementMap, DisplacementMap::default);
n!(create_ellipse, Ellipse, NodeEllipse::default);
n!(create_filter, Filter, NodeFilter::default);
@@ -87,13 +90,13 @@ mod creators {
n!(create_offset, FeOffset, Offset::default);
n!(create_path, Path, NodePath::default);
n!(create_pattern, Pattern, NodePattern::default);
- n!(create_point_light, FePointLight, LightSource::new_point_light);
+ n!(create_point_light, FePointLight, PointLight::default);
n!(create_polygon, Polygon, NodePoly::new_closed);
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_spot_light, FeSpotLight, LightSource::new_spot_light);
+ n!(create_spot_light, FeSpotLight, SpotLight::default);
n!(create_stop, Stop, NodeStop::default);
n!(create_style, Style, NodeStyle::default);
n!(create_svg, Svg, NodeSvg::default);
diff --git a/rsvg_internals/src/filters/light/light_source.rs
b/rsvg_internals/src/filters/light/light_source.rs
index e8661346..1665ee79 100644
--- a/rsvg_internals/src/filters/light/light_source.rs
+++ b/rsvg_internals/src/filters/light/light_source.rs
@@ -9,32 +9,8 @@ use crate::parsers;
use crate::property_bag::PropertyBag;
use crate::util::clamp;
-/// A light source node (`feDistantLight`, `fePointLight` or `feSpotLight`).
-#[derive(Clone)]
+/// A light source with affine transformations applied.
pub enum LightSource {
- Distant {
- azimuth: f64,
- elevation: f64,
- },
- Point {
- x: f64,
- y: f64,
- z: f64,
- },
- Spot {
- x: f64,
- y: f64,
- z: f64,
- points_at_x: f64,
- points_at_y: f64,
- points_at_z: f64,
- specular_exponent: f64,
- limiting_cone_angle: Option<f64>,
- },
-}
-
-/// A light source node with affine transformations applied.
-pub enum TransformedLightSource {
Distant {
azimuth: f64,
elevation: f64,
@@ -51,92 +27,11 @@ pub enum TransformedLightSource {
}
impl LightSource {
- /// Constructs a new `feDistantLight` with empty properties.
- #[inline]
- pub fn new_distant_light() -> LightSource {
- LightSource::Distant {
- azimuth: 0.0,
- elevation: 0.0,
- }
- }
-
- /// Constructs a new `fePointLight` with empty properties.
- #[inline]
- pub fn new_point_light() -> LightSource {
- LightSource::Point {
- x: 0.0,
- y: 0.0,
- z: 0.0,
- }
- }
-
- /// Constructs a new `feSpotLight` with empty properties.
- #[inline]
- pub fn new_spot_light() -> LightSource {
- LightSource::Spot {
- x: 0.0,
- y: 0.0,
- z: 0.0,
- points_at_x: 0.0,
- points_at_y: 0.0,
- points_at_z: 0.0,
- specular_exponent: 0.0,
- limiting_cone_angle: None,
- }
- }
-
- /// Returns a `TransformedLightSource` according to the given `FilterContext`.
- #[inline]
- pub fn transform(&self, ctx: &FilterContext) -> TransformedLightSource {
- match *self {
- LightSource::Distant { azimuth, elevation } => {
- TransformedLightSource::Distant { azimuth, elevation }
- }
- LightSource::Point { x, y, z } => {
- let (x, y) = ctx.paffine().transform_point(x, y);
- let z = ctx.transform_dist(z);
-
- TransformedLightSource::Point {
- origin: Vector3::new(x, y, z),
- }
- }
- LightSource::Spot {
- x,
- y,
- z,
- points_at_x,
- points_at_y,
- points_at_z,
- specular_exponent,
- limiting_cone_angle,
- } => {
- let (x, y) = ctx.paffine().transform_point(x, y);
- let z = ctx.transform_dist(z);
- let (points_at_x, points_at_y) =
- ctx.paffine().transform_point(points_at_x, points_at_y);
- let points_at_z = ctx.transform_dist(points_at_z);
-
- let origin = Vector3::new(x, y, z);
- let mut direction = Vector3::new(points_at_x, points_at_y, points_at_z) - origin;
- let _ = direction.try_normalize_mut(0.0);
-
- TransformedLightSource::Spot {
- origin,
- direction,
- specular_exponent,
- limiting_cone_angle,
- }
- }
- }
- }
-}
-
-impl TransformedLightSource {
/// Returns the unit (or null) vector from the image sample to the light.
#[inline]
pub fn vector(&self, x: f64, y: f64, z: f64) -> Vector3<f64> {
match self {
- TransformedLightSource::Distant { azimuth, elevation } => {
+ LightSource::Distant { azimuth, elevation } => {
let azimuth = azimuth.to_radians();
let elevation = elevation.to_radians();
Vector3::new(
@@ -145,8 +40,7 @@ impl TransformedLightSource {
elevation.sin(),
)
}
- TransformedLightSource::Point { origin }
- | TransformedLightSource::Spot { origin, .. } => {
+ LightSource::Point { origin } | LightSource::Spot { origin, .. } => {
let mut v = origin - Vector3::new(x, y, z);
let _ = v.try_normalize_mut(0.0);
v
@@ -162,7 +56,7 @@ impl TransformedLightSource {
light_vector: Vector3<f64>,
) -> cssparser::RGBA {
match self {
- TransformedLightSource::Spot {
+ LightSource::Spot {
direction,
specular_exponent,
limiting_cone_angle,
@@ -194,60 +88,127 @@ impl TransformedLightSource {
}
}
-impl NodeTrait for LightSource {
+#[derive(Default)]
+pub struct DistantLight {
+ azimuth: f64,
+ elevation: f64,
+}
+
+impl DistantLight {
+ pub fn transform(&self, _ctx: &FilterContext) -> LightSource {
+ LightSource::Distant {
+ azimuth: self.azimuth,
+ elevation: self.elevation,
+ }
+ }
+}
+
+impl NodeTrait for DistantLight {
fn set_atts(&mut self, _: Option<&RsvgNode>, pbag: &PropertyBag<'_>) -> NodeResult {
for (attr, value) in pbag.iter() {
- match *self {
- LightSource::Distant {
- ref mut azimuth,
- ref mut elevation,
- } => match attr {
- local_name!("azimuth") => *azimuth = parsers::number(value).attribute(attr)?,
- local_name!("elevation") => {
- *elevation = parsers::number(value).attribute(attr)?
- }
- _ => (),
- },
- LightSource::Point {
- ref mut x,
- ref mut y,
- ref mut z,
- } => match attr {
- local_name!("x") => *x = parsers::number(value).attribute(attr)?,
- local_name!("y") => *y = parsers::number(value).attribute(attr)?,
- local_name!("z") => *z = parsers::number(value).attribute(attr)?,
- _ => (),
- },
- LightSource::Spot {
- ref mut x,
- ref mut y,
- ref mut z,
- ref mut points_at_x,
- ref mut points_at_y,
- ref mut points_at_z,
- ref mut specular_exponent,
- ref mut limiting_cone_angle,
- } => match attr {
- local_name!("x") => *x = parsers::number(value).attribute(attr)?,
- local_name!("y") => *y = parsers::number(value).attribute(attr)?,
- local_name!("z") => *z = parsers::number(value).attribute(attr)?,
- local_name!("pointsAtX") => {
- *points_at_x = parsers::number(value).attribute(attr)?
- }
- local_name!("pointsAtY") => {
- *points_at_y = parsers::number(value).attribute(attr)?
- }
- local_name!("pointsAtZ") => {
- *points_at_z = parsers::number(value).attribute(attr)?
- }
- local_name!("specularExponent") => {
- *specular_exponent = parsers::number(value).attribute(attr)?
- }
- local_name!("limitingConeAngle") => {
- *limiting_cone_angle = Some(parsers::number(value).attribute(attr)?)
- }
- _ => (),
- },
+ match attr {
+ local_name!("azimuth") => self.azimuth = parsers::number(value).attribute(attr)?,
+ local_name!("elevation") => {
+ self.elevation = parsers::number(value).attribute(attr)?
+ }
+ _ => (),
+ }
+ }
+
+ Ok(())
+ }
+}
+
+#[derive(Default)]
+pub struct PointLight {
+ x: f64,
+ y: f64,
+ z: f64,
+}
+
+impl PointLight {
+ pub fn transform(&self, ctx: &FilterContext) -> LightSource {
+ let (x, y) = ctx.paffine().transform_point(self.x, self.y);
+ let z = ctx.transform_dist(self.z);
+
+ LightSource::Point {
+ origin: Vector3::new(x, y, z),
+ }
+ }
+}
+
+impl NodeTrait for PointLight {
+ fn set_atts(&mut self, _: Option<&RsvgNode>, pbag: &PropertyBag<'_>) -> NodeResult {
+ for (attr, value) in pbag.iter() {
+ match attr {
+ local_name!("x") => self.x = parsers::number(value).attribute(attr)?,
+ local_name!("y") => self.y = parsers::number(value).attribute(attr)?,
+ local_name!("z") => self.z = parsers::number(value).attribute(attr)?,
+ _ => (),
+ }
+ }
+
+ Ok(())
+ }
+}
+
+#[derive(Default)]
+pub struct SpotLight {
+ x: f64,
+ y: f64,
+ z: f64,
+ points_at_x: f64,
+ points_at_y: f64,
+ points_at_z: f64,
+ specular_exponent: f64,
+ limiting_cone_angle: Option<f64>,
+}
+
+impl SpotLight {
+ pub fn transform(&self, ctx: &FilterContext) -> LightSource {
+ let (x, y) = ctx.paffine().transform_point(self.x, self.y);
+ let z = ctx.transform_dist(self.z);
+ let (points_at_x, points_at_y) = ctx
+ .paffine()
+ .transform_point(self.points_at_x, self.points_at_y);
+ let points_at_z = ctx.transform_dist(self.points_at_z);
+
+ let origin = Vector3::new(x, y, z);
+ let mut direction = Vector3::new(points_at_x, points_at_y, points_at_z) - origin;
+ let _ = direction.try_normalize_mut(0.0);
+
+ LightSource::Spot {
+ origin,
+ direction,
+ specular_exponent: self.specular_exponent,
+ limiting_cone_angle: self.limiting_cone_angle,
+ }
+ }
+}
+
+impl NodeTrait for SpotLight {
+ fn set_atts(&mut self, _: Option<&RsvgNode>, pbag: &PropertyBag<'_>) -> NodeResult {
+ for (attr, value) in pbag.iter() {
+ match attr {
+ local_name!("x") => self.x = parsers::number(value).attribute(attr)?,
+ local_name!("y") => self.y = parsers::number(value).attribute(attr)?,
+ local_name!("z") => self.z = parsers::number(value).attribute(attr)?,
+ local_name!("pointsAtX") => {
+ self.points_at_x = parsers::number(value).attribute(attr)?
+ }
+ local_name!("pointsAtY") => {
+ self.points_at_y = parsers::number(value).attribute(attr)?
+ }
+ local_name!("pointsAtZ") => {
+ self.points_at_z = parsers::number(value).attribute(attr)?
+ }
+ local_name!("specularExponent") => {
+ self.specular_exponent = parsers::number(value).attribute(attr)?
+ }
+ local_name!("limitingConeAngle") => {
+ self.limiting_cone_angle = Some(parsers::number(value).attribute(attr)?)
+ }
+ _ => (),
}
}
diff --git a/rsvg_internals/src/filters/light/lighting.rs b/rsvg_internals/src/filters/light/lighting.rs
index 3d3d01bc..4e01de46 100644
--- a/rsvg_internals/src/filters/light/lighting.rs
+++ b/rsvg_internals/src/filters/light/lighting.rs
@@ -17,7 +17,10 @@ use crate::filters::{
bottom_row_normal,
interior_normal,
left_column_normal,
+ light_source::DistantLight,
light_source::LightSource,
+ light_source::PointLight,
+ light_source::SpotLight,
right_column_normal,
top_left_normal,
top_right_normal,
@@ -209,27 +212,7 @@ impl Filter for Lighting {
cssparser::Color::RGBA(rgba) => rgba,
};
- let mut light_sources = node
- .children()
- .rev()
- .filter(|c| match c.borrow().get_type() {
- NodeType::FeDistantLight | NodeType::FePointLight | NodeType::FeSpotLight => true,
- _ => false,
- });
-
- let light_source = light_sources.next();
- if light_source.is_none() || light_sources.next().is_some() {
- return Err(FilterError::InvalidLightSourceCount);
- }
-
- let light_source = light_source.unwrap();
- if light_source.borrow().is_in_error() {
- return Err(FilterError::ChildNodeInError);
- }
-
- let node_data = light_source.borrow();
- let light_source = node_data.get_impl::<LightSource>().transform(ctx);
-
+ let light_source = find_light_source(node, ctx)?;
let mut input_surface = input.surface().clone();
if let Some((ox, oy)) = scale {
@@ -487,6 +470,35 @@ impl Filter for Lighting {
}
}
+fn find_light_source(node: &RsvgNode, ctx: &FilterContext) -> Result<LightSource, FilterError> {
+ let mut light_sources = node
+ .children()
+ .rev()
+ .filter(|c| match c.borrow().get_type() {
+ NodeType::FeDistantLight | NodeType::FePointLight | NodeType::FeSpotLight => true,
+ _ => false,
+ });
+
+ let node = light_sources.next();
+ if node.is_none() || light_sources.next().is_some() {
+ return Err(FilterError::InvalidLightSourceCount);
+ }
+
+ let node = node.unwrap();
+ if node.borrow().is_in_error() {
+ return Err(FilterError::ChildNodeInError);
+ }
+
+ let light_source = match node.borrow().get_type() {
+ NodeType::FeDistantLight => node.borrow().get_impl::<DistantLight>().transform(ctx),
+ NodeType::FePointLight => node.borrow().get_impl::<PointLight>().transform(ctx),
+ NodeType::FeSpotLight => node.borrow().get_impl::<SpotLight>().transform(ctx),
+ _ => unreachable!(),
+ };
+
+ Ok(light_source)
+}
+
impl Default for Lighting {
#[inline]
fn default() -> Self {
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]