use bezier::Bezier; use std::ffi::{CStr, CString}; use sdl2::event::Event; use sdl2::keyboard::Keycode; use gl::types::*; 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 } } fn compile_bezier_shader(c: Bezier) -> GLuint { 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 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[{sx}] v, float t) {{ float result = 0.0; for (int i = 0; i < {sx}; i++) {{ result += v[i] * pow(t, i); }} return result; }} float eval_b(float[{sy}] v, float t) {{ float result = 0.0; 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 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 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); }} ", 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(); 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); } shader_program } fn main() { 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(); let gl_attr = video_subsystem.gl_attr(); gl_attr.set_context_profile(sdl2::video::GLProfile::Core); gl_attr.set_context_version(4, 1); let window_w: u32 = 1920; let window_h: u32 = 1080; let window = video_subsystem .window("bezier", window_w, window_h) .position_centered() .opengl() .build() .unwrap(); let _gl_context = window.gl_create_context().unwrap(); gl::load_with(|s| video_subsystem.gl_get_proc_address(s) as *const std::os::raw::c_void); unsafe { gl::Viewport(0, 0, window_w as i32, window_h as i32); } let vertices: [f32; 18] = [1.0, 1.0, 0.0, 1.0, -1.0, 0.0, -1.0, 1.0, 0.0, 1.0, -1.0, 0.0, -1.0, -1.0, 0.0, -1.0, 1.0, 0.0]; let mut vbo: GLuint = 0; let mut vao: GLuint = 0; unsafe { gl::GenVertexArrays(1, &mut vao); gl::BindVertexArray(vao); gl::GenBuffers(1, &mut vbo); gl::BindBuffer(gl::ARRAY_BUFFER, vbo); gl::BufferData( gl::ARRAY_BUFFER, (vertices.len() * std::mem::size_of::()) as GLsizeiptr, vertices.as_ptr() as *const GLvoid, gl::STATIC_DRAW, ); gl::VertexAttribPointer( 0, 3, gl::FLOAT, gl::FALSE, (3 * std::mem::size_of::()) as GLint, std::ptr::null(), ); gl::EnableVertexAttribArray(0); } let shader_program = compile_bezier_shader(curve); let mut event_pump = sdl_context.event_pump().unwrap(); 'running: loop { for event in event_pump.poll_iter() { match event { Event::Quit { .. } | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => break 'running, _ => {} } } unsafe { gl::Clear(gl::COLOR_BUFFER_BIT); gl::UseProgram(shader_program); gl::DrawArrays(gl::TRIANGLES, 0, 6); } window.gl_swap_window(); } }