aboutsummaryrefslogtreecommitdiff
path: root/src/svg/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/svg/mod.rs')
-rw-r--r--src/svg/mod.rs178
1 files changed, 0 insertions, 178 deletions
diff --git a/src/svg/mod.rs b/src/svg/mod.rs
deleted file mode 100644
index af066f1..0000000
--- a/src/svg/mod.rs
+++ /dev/null
@@ -1,178 +0,0 @@
-//! Module for drawing SVG files to the screen or maybe a texture etc.
-
-pub mod style;
-
-use crate::math::Vec2;
-use raylib::drawing::RaylibDraw;
-use std::fs::File;
-use std::io::{self, Read};
-use std::ops::Deref;
-use std::path::Path;
-use std::str::FromStr;
-use style::Style;
-use svgtypes::{Path as SVGPath, PathSegment};
-use xmltree::{Element, XMLNode};
-
-/// Find the first XML-Node with the given name. With depth, the maximum depth the
-/// algorithm will search to can be set. If it is set to `None`, the algorithm will search the
-/// entire sub-tree. Returns `None` if no such child can be found. Returns itself, in case the root
-/// node is already of the name given.
-pub fn find_first_node(root: Element, name: &str, depth: Option<usize>) -> Option<Element> {
- // The abort condition of this recursive function. If the element itself is of the required
- // name, return it.
- if root.name == name {
- return Some(root);
- }
- // Also abort, if the depth is reached.
- if depth == Some(0) {
- return None;
- }
-
- // Decrease the depth by one for all calls on the children, if it is set.
- let depth = match depth {
- Some(depth) => Some(depth - 1),
- None => None,
- };
-
- // Recursively look for the element in this node's children.
- for child in root.children {
- // We only care for the elements, not for comments, cdata etc.
- if let XMLNode::Element(element) = child {
- if let Some(element) = find_first_node(element, name, depth) {
- return Some(element);
- }
- }
- }
-
- None
-}
-
-/// Read an svg file from the given path. On success, return the first graphics data that is read
-/// from this file. This can be used to draw an SVG.
-pub fn read_svg_file<P: AsRef<Path>>(file: P) -> io::Result<Element> {
- let mut file = File::open(file)?;
- let mut data = String::new();
- file.read_to_string(&mut data)?;
-
- let root: Element = match Element::parse(data.as_bytes()) {
- Ok(root) => root,
- Err(err) => return Err(io::Error::new(io::ErrorKind::InvalidData, err)),
- };
-
- match find_first_node(root, "g", None) {
- Some(graphics) => Ok(graphics),
- None => Err(io::Error::new(
- io::ErrorKind::InvalidData,
- "No graphics element in the file",
- )),
- }
-}
-
-/// Trait that indicates a struct is capable of drawing SVG-elements.
-pub trait DrawSVG {
- /// Draw the elements given by `svg_data` and all its children to the implementor, with the
- /// specified scale and translated by `position_px`.
- fn draw_svg(&mut self, svg_data: &Element, pixels_per_m: f32, position_px: Vec2<f32>);
-}
-
-impl<D> DrawSVG for D
-where
- D: RaylibDraw,
-{
- fn draw_svg(&mut self, svg_data: &Element, pixels_per_m: f32, position_px: Vec2<f32>) {
- assert_eq!(&svg_data.name, "g");
-
- // Go through all the graphics children and draw them one by one
- for child in &svg_data.children {
- if let XMLNode::Element(child) = child {
- match child.name.as_str() {
- "path" => draw_path(self, child, pixels_per_m, position_px),
- other => warn!("Unsupported SVG-Element {}", other),
- }
- }
- }
- }
-}
-
-// Helper functions to draw specific parts of the SVG file --------------------
-
-fn draw_path(
- d: &mut impl RaylibDraw,
- path_data: &Element,
- pixels_per_m: f32,
- position_px: Vec2<f32>,
-) {
- let style = if let Some(style_data) = path_data.attributes.get("style") {
- match Style::from_str(style_data) {
- Ok(style) => style,
- Err(err) => {
- warn!("Could not parse path style: {}", err);
- warn!("Using default style instead");
- Style::default()
- }
- }
- } else {
- Style::default()
- };
-
- let move_data = match path_data.attributes.get("d") {
- Some(d) => d,
- None => {
- error!("Unable to draw path, no move data found");
- return;
- }
- };
-
- let mut path: SVGPath = match move_data.parse() {
- Ok(mv) => mv,
- Err(err) => {
- error!(
- "Unable to draw path, move data not correctly formatted: {}",
- err
- );
- return;
- }
- };
-
- path.conv_to_absolute();
-
- let mut current_pos: Vec2<f32> = Vec2::new(0., 0.);
- for segment in path.deref() {
- match segment {
- PathSegment::MoveTo { x, y, .. } => {
- current_pos.x = *x as f32;
- current_pos.y = *y as f32;
- }
- PathSegment::LineTo { x, y, .. } => {
- d.draw_line_ex(
- current_pos * pixels_per_m / 1000. + position_px,
- Vec2::new(*x as f32, *y as f32) * pixels_per_m / 1000. + position_px,
- pixels_per_m * style.stroke_width / 1000.,
- style.stroke,
- );
- current_pos.x = *x as f32;
- current_pos.y = *y as f32;
- }
- PathSegment::HorizontalLineTo { x, .. } => {
- d.draw_line_ex(
- current_pos * pixels_per_m / 1000. + position_px,
- Vec2::new(*x as f32, current_pos.y) * pixels_per_m / 1000. + position_px,
- pixels_per_m * style.stroke_width / 1000.,
- style.stroke,
- );
- current_pos.x = *x as f32;
- }
- PathSegment::VerticalLineTo { y, .. } => {
- d.draw_line_ex(
- current_pos * pixels_per_m / 1000. + position_px,
- Vec2::new(current_pos.x, *y as f32) * pixels_per_m / 1000. + position_px,
- pixels_per_m * style.stroke_width / 1000.,
- style.stroke,
- );
- current_pos.y = *y as f32;
- }
- PathSegment::ClosePath { .. } => return,
- other => warn!("Ignoring unsupported {:?}", other),
- }
- }
-}