Skip to main content

femto_mesh/
lib.rs

1#![deny(missing_docs)]
2
3/*!
4Structs to represent and render vector grapics based meshes.
5
6The main mesh is represented by the `VectorMesh` struct.
7
8They can be animated using the `Animation` struct.
9*/
10
11mod animation;
12mod convert;
13mod path;
14mod style;
15
16pub use animation::{Animation, AnimationFrame, AnimationState};
17pub use path::IndexedPath;
18pub use style::{FillStyle, StrokeStyle};
19
20use data_stream::{FromStream, ToStream, collections::SizeSettings, from_stream, to_stream};
21use femto_g::{Canvas, Renderer};
22use ga2::Vector;
23use inner_space::distance;
24use touch_selection::Selector;
25use vector_editor_core::{PointObject, SelectSettings};
26
27use std::io::{Read, Result, Write};
28
29/// A list consisting of multiple indexed paths to be rendered separately.
30#[derive(Clone, Default)]
31pub struct PathList {
32    paths: Vec<IndexedPath>,
33}
34
35impl PathList {
36    /// Create a new `PathList`.
37    pub fn new() -> Self {
38        Self { paths: Vec::new() }
39    }
40}
41
42impl SelectSettings<Vector<f32>> for PathList {
43    #[inline]
44    fn grab_distance(&self) -> f32 {
45        1.0
46    }
47}
48
49impl<S: SizeSettings> ToStream<S> for PathList {
50    fn to_stream<W: Write>(&self, stream: &mut W) -> Result<()> {
51        to_stream::<S, _, _>(&self.paths, stream)
52    }
53}
54
55impl<S: SizeSettings> FromStream<S> for PathList {
56    fn from_stream<R: Read>(stream: &mut R) -> Result<Self> {
57        Ok(Self {
58            paths: from_stream::<S, _, _>(stream)?,
59        })
60    }
61}
62
63/// The type of the vector mesh.
64///
65/// It's a point object using vectors to represent the positions and specifying a list of paths as additional data.
66pub type VectorMesh = PointObject<Vector<f32>, PathList>;
67
68/// A trait for extension methods for the vector mesh.
69pub trait VectorMeshExtensions: Sized {
70    /// Sets the current shape by specifying an `animation` and its `state`.
71    fn set_animation(&mut self, animation: &Animation, state: &AnimationState);
72
73    /// Adds a new path to the mesh.
74    fn add_path(&mut self, path: IndexedPath);
75
76    /// Renders the mesh.
77    fn render<R: Renderer>(&self, canvas: &mut Canvas<R>);
78}
79
80impl VectorMeshExtensions for VectorMesh {
81    fn set_animation(&mut self, animation: &Animation, state: &AnimationState) {
82        animation.set_shape(&mut self.points, state);
83    }
84
85    fn add_path(&mut self, path: IndexedPath) {
86        self.options.paths.push(path);
87    }
88
89    fn render<R: Renderer>(&self, canvas: &mut Canvas<R>) {
90        for indexed_path in &self.options.paths {
91            indexed_path.render(canvas, &self.points);
92        }
93    }
94}
95
96/// A helper struct useful for editing vector meshes.
97pub struct SelectionEditor {
98    move_distance: f32,
99    snapping: Option<i8>,
100}
101
102fn snap(pos: Vector<f32>, f: f32) -> Vector<f32> {
103    let Vector { x, y } = pos;
104    Vector::new((x / f).round(), (y / f).round()) * f
105}
106
107impl SelectionEditor {
108    /// Creates a new `SelectionEditor`.
109    pub fn new() -> Self {
110        Self {
111            move_distance: 0x10 as f32,
112            snapping: Some(0),
113        }
114    }
115}
116
117impl Default for SelectionEditor {
118    fn default() -> Self {
119        Self::new()
120    }
121}
122
123impl Selector for SelectionEditor {
124    type Selectable = VectorMesh;
125    type Position = Vector<f32>;
126
127    fn moved(&self, moved: Vector<f32>, cursor: Vector<f32>) -> bool {
128        distance(moved, cursor) >= self.move_distance
129    }
130
131    fn stop(&self, selectable: &mut Self::Selectable, index: usize) {
132        if let Some(snapping) = self.snapping {
133            let pos = &mut selectable.points[index];
134            *pos = snap(*pos, 2.0f32.powi(snapping as i32));
135        }
136    }
137}