summaryrefslogtreecommitdiff
path: root/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib.rs')
-rw-r--r--src/lib.rs149
1 files changed, 149 insertions, 0 deletions
diff --git a/src/lib.rs b/src/lib.rs
index d6a1374..db5d42f 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -4,6 +4,10 @@ mod poly;
use lerp::Lerp;
use poly::Poly;
+use std::ffi::{CStr, CString};
+
+use gl::types::*;
+
pub struct Bezier {
pub degree: usize,
pub vx: Vec<f32>,
@@ -68,4 +72,149 @@ impl Bezier {
}
s
}
+
+ pub fn draw(&self) {
+ let vertex_shader_source = b"
+ #version 410 core
+ layout (location = 0) in vec3 aPos;
+
+ void main() {
+ gl_Position = vec4(aPos.xyz, 1.0);
+ }
+ "
+ .to_vec();
+
+ let fragment_shader_source = format!(
+ "
+ #version 410 core
+ out vec4 FragColor;
+
+ 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_px(float t) {{
+ float result = 0.0;
+ for (int i = 0; i < {sx}; i++) {{
+ result += px[i] * pow(t, i);
+ }}
+ return result;
+ }}
+
+ float eval_py(float t) {{
+ float result = 0.0;
+ for (int i = 0; i < {sy}; 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;
+ }}
+
+ 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 closest = inf;
+ float t = 0.0;
+ 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) {{
+ closest = d;
+ }}
+ t = step;
+ }}
+ return 1 - closest / thr;
+ }}
+
+ void main() {{
+ float r = inside(gl_FragCoord.xy);
+ float c = control(gl_FragCoord.xy);
+ FragColor = vec4(r, c, 0.0, 1.0);
+ }}
+ ",
+ s = self.degree,
+ vx = self.show_x(),
+ vy = self.show_y(),
+ px = &self.px,
+ py = &self.py,
+ sx = self.px.degree() + 1,
+ sy = self.py.degree() + 1,
+ dpx = &self.dpx,
+ dpy = &self.dpy,
+ dsx = self.dpx.degree() + 1,
+ dsy = self.dpy.degree() + 1,
+ )
+ .into_bytes();
+
+ let shader_program: GLuint;
+ unsafe {
+ let vertex_shader = shader_from_source(
+ &CString::from_vec_unchecked(vertex_shader_source),
+ gl::VERTEX_SHADER,
+ );
+ let fragment_shader = shader_from_source(
+ &CString::from_vec_unchecked(fragment_shader_source),
+ gl::FRAGMENT_SHADER,
+ );
+ shader_program = gl::CreateProgram();
+ gl::AttachShader(shader_program, vertex_shader);
+ gl::AttachShader(shader_program, fragment_shader);
+ gl::LinkProgram(shader_program);
+ gl::DeleteShader(vertex_shader);
+ gl::DeleteShader(fragment_shader);
+ gl::UseProgram(shader_program);
+ }
+ }
}
+
+fn shader_from_source(source: &CStr, shader_type: GLenum) -> GLuint {
+ unsafe {
+ let shader: GLuint = gl::CreateShader(shader_type);
+ gl::ShaderSource(shader, 1, &source.as_ptr(), std::ptr::null());
+ gl::CompileShader(shader);
+ let mut success: gl::types::GLint = 1;
+ gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut success);
+ if success == 0 {
+ println!("Compilation error: {}", source.to_str().unwrap());
+ }
+ shader
+ }
+} \ No newline at end of file