diff options
| -rw-r--r-- | src/lerp.rs | 4 | ||||
| -rw-r--r-- | src/lib.rs | 62 | ||||
| -rw-r--r-- | src/main.rs | 68 | ||||
| -rw-r--r-- | src/poly.rs | 115 | ||||
| -rw-r--r-- | src/poly/iter.rs | 38 | 
5 files changed, 108 insertions, 179 deletions
| diff --git a/src/lerp.rs b/src/lerp.rs index 818c686..b613620 100644 --- a/src/lerp.rs +++ b/src/lerp.rs @@ -1,4 +1,6 @@ -use crate::poly::Poly; +pub mod poly; + +use poly::Poly;  pub enum Lerp {      Node(Box<Lerp>, Box<Lerp>), diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..cadef3c --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,62 @@ +mod lerp; + +use lerp::Lerp; +use lerp::poly::Poly; + +pub struct Bezier { +    pub vx: Vec<f32>, +    pub vy: Vec<f32>, +    pub px: Poly, +    pub py: Poly, +    pub degree: usize +} + +impl Bezier { +    pub fn new() -> Bezier { +        Bezier { +            vx: Vec::<f32>::new(), +            vy: Vec::<f32>::new(), +            px: Poly::new(vec![]), +            py: Poly::new(vec![]), +            degree: 0, +        } +    } + +    pub fn push(&mut self, x: i32, y: i32) { +        self.vx.push(x as f32); +        self.vy.push(y as f32); +        self.px = Lerp::new(self.vx.clone()).to_poly(); +        self.py = Lerp::new(self.vy.clone()).to_poly(); +        self.degree += 1; +    } + +    pub fn remove(&mut self, index: usize) { +        self.vx.remove(index); +        self.vy.remove(index); +        self.px = Lerp::new(self.vx.clone()).to_poly(); +        self.py = Lerp::new(self.vy.clone()).to_poly(); +        self.degree -= 1; +    } + +    pub fn show_x(&self) -> String{ +        let mut s = String::new(); +        for i in 0..self.degree { +            s.push_str(&self.vx[i].to_string()); +            if i < self.degree - 1 { +                s.push_str(", "); +            } +        } +        s +    } + +    pub fn show_y(&self) -> String { +        let mut s = String::new(); +        for i in 0..self.degree { +            s.push_str(&self.vy[i].to_string()); +            if i < self.degree - 1 { +                s.push_str(", "); +            } +        } +        s +    } +} diff --git a/src/main.rs b/src/main.rs index ee508e1..2c5dbcc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,4 @@ -mod lerp; -mod poly; - -use lerp::Lerp; -use poly::Poly; +use bezier::Bezier;  use std::ffi::{CStr, CString}; @@ -25,7 +21,7 @@ fn shader_from_source(source: &CStr, shader_type: GLenum) -> GLuint {      }  } -fn compile_bezier_shader(a: Poly, b: Poly) -> GLuint { +fn compile_bezier_shader(c: Bezier) -> GLuint {      let vertex_shader_source = b"      #version 410 core      layout (location = 0) in vec3 aPos; @@ -41,34 +37,48 @@ fn compile_bezier_shader(a: Poly, b: Poly) -> GLuint {      #version 410 core      out vec4 FragColor; -    float pa[{sa}] = float[{sa}]({pa}); -    float pb[{sb}] = float[{sb}]({pb}); +    float inf = 1000000; +    float vx[{s}] = float[{s}]({vx}); +    float vy[{s}] = float[{s}]({vy}); +    float px[{sx}] = float[{sx}]({px}); +    float py[{sy}] = float[{sy}]({py}); +    float thr = 32; -    float eval_a(float[{sa}] v, float t) {{ +    float eval_a(float[{sx}] v, float t) {{          float result = 0.0; -        for (int i = 0; i < {sa}; i++) {{ +        for (int i = 0; i < {sx}; i++) {{            result += v[i] * pow(t, i);          }}          return result;      }} -    float eval_b(float[{sb}] v, float t) {{ +    float eval_b(float[{sy}] v, float t) {{          float result = 0.0; -        for (int i = 0; i < {sb}; i++) {{ +        for (int i = 0; i < {sy}; i++) {{            result += v[i] * pow(t, i);          }}          return result;      }} +    float control(vec2 pos) {{ +      float closest = inf; +      for (int i = 0; i < {s}; i++) {{ +        float d = distance(pos, vec2(vx[i], vy[i])); +        if (d < closest) {{ +          closest = d; +        }} +      }} +      return 1 - closest / thr; +    }} +      float inside(vec2 pos) {{        float res = 100; -      float thr = 32; -      float closest = 1000000; +      float closest = inf;        float t = 0.0; -      while (t < 1.0) {{ +      while (t < 1.0 - 1.0 / res) {{          float step = t + 1.0 / res; -        vec2 a = vec2(eval_a(pa, t), eval_b(pb, t)); -        vec2 b = vec2(eval_a(pa, step), eval_b(pb, step)); +        vec2 a = vec2(eval_a(px, t), eval_b(py, t)); +        vec2 b = vec2(eval_a(px, step), eval_b(py, step));          float c = pow(length(a - b), 2);          float d = distance(pos, a + clamp(dot(pos - a, b - a) / c, 0, 1) * (b - a));          if (d < closest) {{ @@ -81,13 +91,17 @@ fn compile_bezier_shader(a: Poly, b: Poly) -> GLuint {      void main() {{        float r = inside(gl_FragCoord.xy); -        FragColor = vec4(r * 0.8, r * 0.2, r, 1.0); +      float c = control(gl_FragCoord.xy); +      FragColor = vec4(r, c, 0.0, 1.0);      }}      ", -        sa = a.degree() + 1, -        sb = b.degree() + 1, -        pa = &a, -        pb = &b +        sx = c.px.degree() + 1, +        sy = c.py.degree() + 1, +        px = &c.px, +        py = &c.py, +        s  = c.degree, +        vx = c.show_x(), +        vy = c.show_y(),      )      .into_bytes(); @@ -112,8 +126,12 @@ fn compile_bezier_shader(a: Poly, b: Poly) -> GLuint {  }  fn main() { -    let a = Lerp::new(vec![200.0, 500.0, 500.0]).to_poly(); -    let b = Lerp::new(vec![200.0, 500.0, 200.0]).to_poly(); +    let mut curve = Bezier::new(); +    curve.push(200, 200); +    curve.push(300, 800); +    curve.push(800, 100); +    curve.push(1300, 800); +    curve.push(1400, 200);      let sdl_context = sdl2::init().unwrap();      let video_subsystem = sdl_context.video().unwrap(); @@ -167,7 +185,7 @@ fn main() {          gl::EnableVertexAttribArray(0);      } -    let shader_program = compile_bezier_shader(a, b); +    let shader_program = compile_bezier_shader(curve);      let mut event_pump = sdl_context.event_pump().unwrap();      'running: loop { diff --git a/src/poly.rs b/src/poly.rs deleted file mode 100644 index c76e481..0000000 --- a/src/poly.rs +++ /dev/null @@ -1,115 +0,0 @@ -mod iter; - -use iter::Iter; -use std::fmt; -use std::ops::{Add, Mul, Sub}; - -#[derive(PartialEq, Debug, Clone)] -pub struct Poly { -    data: Vec<f32>, -    degree: usize, -} - -impl Poly { -    pub fn new(data: Vec<f32>) -> Poly { -        let mut i = data.len() - 1; -        while data[i] == 0.0 && i > 0 { -            i -= 1; -        } -        Poly { data, degree: i } -    } - -    pub fn degree(&self) -> usize { -        self.degree -    } - -    fn iter(&self) -> Iter { -        Iter::new(self.data.clone(), self.degree()) -    } -} - -impl Add for &Poly { -    type Output = Poly; - -    fn add(self, other: Self) -> Poly { -        Poly::new(self.iter().zip(other.iter()).map(|(x, y)| x + y).collect()) -    } -} - -impl Sub for &Poly { -    type Output = Poly; - -    fn sub(self, other: Self) -> Poly { -        Poly::new(self.iter().zip(other.iter()).map(|(x, y)| x - y).collect()) -    } -} - -impl Mul for &Poly { -    type Output = Poly; - -    fn mul(self, other: Self) -> Poly { -        let mut r = Vec::new(); -        for i in 0..other.degree() + 1 { -            let mut prefix = vec![0.0; i]; -            let mut suffix: Vec<f32> = self -                .iter() -                .take(self.degree() + 1) -                .map(|x| x * other.data[i]) -                .collect(); -            prefix.append(&mut suffix); -            r.push(Poly::new(prefix)); -        } -        r.iter().fold(Poly::new(vec![0.0]), |acc, x| &acc + x) -    } -} - -impl fmt::Display for &Poly { -    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { -        let mut s = String::new(); -        for i in 0..self.data.len() { -            s.push_str(&self.data[i].clone().to_string()); -            if i < self.data.len() - 1 { -                s.push_str(", "); -            } -        } -        write!(f, "{}", s) -    } -} - -#[cfg(test)] -mod tests { -    use super::*; - -    #[test] -    fn mul_test() { -        let a = Poly::new(vec![1.0, 2.0, 3.0]); -        let b = Poly::new(vec![1.0, 2.0]); -        assert_eq!(&a * &b, Poly::new(vec![1.0, 4.0, 7.0, 6.0])); -    } - -    #[test] -    fn add_test() { -        let a = Poly::new(vec![1.0]); -        let b = Poly::new(vec![0.0, 0.0, 0.0, 1.0]); -        assert_eq!(&a + &b, Poly::new(vec![1.0, 0.0, 0.0, 1.0])); -    } - -    #[test] -    fn sub_test() { -        let a = Poly::new(vec![1.0, 2.0, 3.0]); -        let b = Poly::new(vec![1.0, 1.0, 1.0]); -        assert_eq!(&a - &b, Poly::new(vec![0.0, 1.0, 2.0])); -    } - -    #[test] -    fn degree_is_five() { -        let p = Poly::new(vec![0.0, 0.0, 0.0, 0.0, 0.0, 2.0]); -        assert_eq!(p.degree(), 5); -    } - -    #[test] -    fn degree_is_zero() { -        let p = Poly::new(vec![0.0; 6]); -        assert_eq!(p.degree(), 0); -    } -} diff --git a/src/poly/iter.rs b/src/poly/iter.rs deleted file mode 100644 index 90cc4b5..0000000 --- a/src/poly/iter.rs +++ /dev/null @@ -1,38 +0,0 @@ -use std::cmp; -use std::iter::{Take, Zip}; - -pub struct Iter { -    index: usize, -    data: Vec<f32>, -    degree: usize, -} - -impl Iter { -    pub fn new(data: Vec<f32>, degree: usize) -> Iter { -        Iter { -            index: 0, -            data, -            degree, -        } -    } - -    pub fn zip(self, other: Self) -> Zip<Take<Iter>, Take<Iter>> { -        let deg = cmp::max(self.degree, other.degree) + 1; -        let a = self.take(deg); -        let b = other.take(deg); -        a.zip(b) -    } -} - -impl Iterator for Iter { -    type Item = f32; - -    fn next(&mut self) -> Option<f32> { -        self.index += 1; -        if self.index <= self.data.len() { -            Some(self.data[self.index - 1]) -        } else { -            Some(0.0) -        } -    } -} | 
