From 4998f5936dc7da36aba0cd018de2a1a6127dda08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Manuel=20Tom=C3=A1s?= Date: Tue, 19 Jan 2021 09:06:32 -0300 Subject: Make shader sample intervals uniform --- src/lerp.rs | 8 ++-- src/lerp/poly.rs | 119 ------------------------------------------------ src/lerp/poly/iter.rs | 38 ---------------- src/lib.rs | 21 ++++++--- src/main.rs | 61 ++++++++++++++++++------- src/poly.rs | 123 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/poly/iter.rs | 38 ++++++++++++++++ 7 files changed, 223 insertions(+), 185 deletions(-) delete mode 100644 src/lerp/poly.rs delete mode 100644 src/lerp/poly/iter.rs create mode 100644 src/poly.rs create mode 100644 src/poly/iter.rs diff --git a/src/lerp.rs b/src/lerp.rs index b613620..4c829a1 100644 --- a/src/lerp.rs +++ b/src/lerp.rs @@ -1,6 +1,4 @@ -pub mod poly; - -use poly::Poly; +use crate::poly::Poly; pub enum Lerp { Node(Box, Box), @@ -9,7 +7,7 @@ pub enum Lerp { } impl Lerp { - pub fn new(v: Vec) -> Box { + pub fn new(v: &Vec) -> Box { Lerp::new_s(&v[..]) } @@ -33,7 +31,7 @@ impl Lerp { let a = a.to_poly(); let b = b.to_poly(); let c = &b - &a; - &a + &(&c * &Poly::new(vec![0.0, 1.0])) + &a + &c.shift() } } } diff --git a/src/lerp/poly.rs b/src/lerp/poly.rs deleted file mode 100644 index 961c56c..0000000 --- a/src/lerp/poly.rs +++ /dev/null @@ -1,119 +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, - degree: usize, -} - -impl Poly { - pub fn new(data: Vec) -> Poly { - if data.len() > 0 { - let mut i = data.len() - 1; - while data[i] == 0.0 && i > 0 { - i -= 1; - } - Poly { data, degree: i } - } else { - Poly { data, degree: 0 } - } - } - - 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 = 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/lerp/poly/iter.rs b/src/lerp/poly/iter.rs deleted file mode 100644 index 90cc4b5..0000000 --- a/src/lerp/poly/iter.rs +++ /dev/null @@ -1,38 +0,0 @@ -use std::cmp; -use std::iter::{Take, Zip}; - -pub struct Iter { - index: usize, - data: Vec, - degree: usize, -} - -impl Iter { - pub fn new(data: Vec, degree: usize) -> Iter { - Iter { - index: 0, - data, - degree, - } - } - - pub fn zip(self, other: Self) -> Zip, Take> { - 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 { - self.index += 1; - if self.index <= self.data.len() { - Some(self.data[self.index - 1]) - } else { - Some(0.0) - } - } -} diff --git a/src/lib.rs b/src/lib.rs index cadef3c..6f26672 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,14 +1,17 @@ mod lerp; +mod poly; use lerp::Lerp; -use lerp::poly::Poly; +use poly::Poly; pub struct Bezier { + pub degree: usize, pub vx: Vec, pub vy: Vec, pub px: Poly, pub py: Poly, - pub degree: usize + pub dpx: Poly, + pub dpy: Poly } impl Bezier { @@ -18,6 +21,8 @@ impl Bezier { vy: Vec::::new(), px: Poly::new(vec![]), py: Poly::new(vec![]), + dpy: Poly::new(vec![]), + dpx: Poly::new(vec![]), degree: 0, } } @@ -25,16 +30,20 @@ impl Bezier { 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.px = Lerp::new(&self.vx).to_poly(); + self.py = Lerp::new(&self.vy).to_poly(); + self.dpx = self.px.deriv(); + self.dpy = self.py.deriv(); 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.px = Lerp::new(&self.vx).to_poly(); + self.py = Lerp::new(&self.vy).to_poly(); + self.dpx = self.px.deriv(); + self.dpy = self.py.deriv(); self.degree -= 1; } diff --git a/src/main.rs b/src/main.rs index f01526b..a61478f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -37,25 +37,47 @@ fn compile_bezier_shader(c: &Bezier) -> GLuint { #version 410 core out vec4 FragColor; - 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 dpx[{dsx}] = float[{dsx}]({dpx}); + float dpy[{dsy}] = float[{dsy}]({dpy}); + float thr = 32; + float step_size = 10; + float inf = 1000000; - float eval_a(float[{sx}] v, float t) {{ + float eval_px(float t) {{ float result = 0.0; for (int i = 0; i < {sx}; i++) {{ - result += v[i] * pow(t, i); + result += px[i] * pow(t, i); }} return result; }} - float eval_b(float[{sy}] v, float t) {{ + float eval_py(float t) {{ float result = 0.0; for (int i = 0; i < {sy}; i++) {{ - result += v[i] * pow(t, i); + result += py[i] * pow(t, i); + }} + return result; + }} + + float eval_dpx(float t) {{ + float result = 0.0; + for (int i = 0; i < {dsx}; i++) {{ + result += dpx[i] * pow(t, i); + }} + return result; + }} + + float eval_dpy(float t) {{ + float result = 0.0; + for (int i = 0; i < {dsy}; i++) {{ + result += dpy[i] * pow(t, i); }} return result; }} @@ -72,13 +94,14 @@ fn compile_bezier_shader(c: &Bezier) -> GLuint { }} float inside(vec2 pos) {{ - float res = 100; float closest = inf; float t = 0.0; - while (t < 1.0 - 1.0 / res) {{ - float step = t + 1.0 / res; - vec2 a = vec2(eval_a(px, t), eval_b(py, t)); - vec2 b = vec2(eval_a(px, step), eval_b(py, step)); + float dstep = 0.0; + while (t < 1.0 - dstep) {{ + dstep = step_size / length(vec2(eval_dpx(t), eval_dpy(t))); + float step = t + dstep; + vec2 a = vec2(eval_px(t), eval_py(t)); + vec2 b = vec2(eval_px(step), eval_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) {{ @@ -95,13 +118,17 @@ fn compile_bezier_shader(c: &Bezier) -> GLuint { FragColor = vec4(r, c, 0.0, 1.0); }} ", - 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(), + s = c.degree, + vx = c.show_x(), + vy = c.show_y(), + px = &c.px, + py = &c.py, + sx = c.px.degree() + 1, + sy = c.py.degree() + 1, + dpx = &c.dpx, + dpy = &c.dpy, + dsx = c.dpx.degree() + 1, + dsy = c.dpy.degree() + 1, ) .into_bytes(); diff --git a/src/poly.rs b/src/poly.rs new file mode 100644 index 0000000..35e85d8 --- /dev/null +++ b/src/poly.rs @@ -0,0 +1,123 @@ +mod iter; + +use iter::Iter; +use std::fmt; +use std::ops::{Add, Sub}; + +#[derive(PartialEq, Debug, Clone)] +pub struct Poly { + data: Vec, + degree: usize, +} + +impl Poly { + pub fn new(data: Vec) -> Poly { + if data.len() > 1 { + let mut i = data.len() - 1; + while data[i] == 0.0 && i > 0 { + i -= 1; + } + Poly { data, degree: i } + } else { + Poly { data, degree: 0 } + } + } + + pub fn degree(&self) -> usize { + self.degree + } + + fn iter(&self) -> Iter { + Iter::new(self.data.clone(), self.degree()) + } + + pub fn shift(self) -> Poly { + let mut r = vec![0.0]; + r.append(&mut self.data.clone()); + Poly::new(r) + } + + pub fn deriv(&self) -> Poly { + let mut data = vec![0.0; self.degree()]; + if self.degree() > 0 { + for i in 0..self.degree() { + data[i] = self.data[i + 1] * (i + 1) as f32; + } + Poly::new(data) + } else { + Poly::new(vec![0.0]) + } + } +} + +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 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 shift_test() { + let a = Poly::new(vec![1.0, 2.0, 3.0]); + assert_eq!(a.shift(), Poly::new(vec![0.0, 1.0, 2.0, 3.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 deriv_test() { + let p = Poly::new(vec![1.0, 2.0, 3.0, 4.0]); + assert_eq!(p.deriv(), Poly::new(vec![2.0, 6.0, 12.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 new file mode 100644 index 0000000..90cc4b5 --- /dev/null +++ b/src/poly/iter.rs @@ -0,0 +1,38 @@ +use std::cmp; +use std::iter::{Take, Zip}; + +pub struct Iter { + index: usize, + data: Vec, + degree: usize, +} + +impl Iter { + pub fn new(data: Vec, degree: usize) -> Iter { + Iter { + index: 0, + data, + degree, + } + } + + pub fn zip(self, other: Self) -> Zip, Take> { + 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 { + self.index += 1; + if self.index <= self.data.len() { + Some(self.data[self.index - 1]) + } else { + Some(0.0) + } + } +} -- cgit v1.2.3