use std::ops::{Deref, DerefMut}; use bytemuck::{Pod, Zeroable}; use glow::{HasContext, NativeBuffer, NativeVertexArray}; use crate::components::{fetchcode, CodeComponent, CodeType, Program, Shader, Snippet}; use crate::errors::*; use crate::graphics::transforms::viewport::Viewport; use crate::graphics::transforms::Transform; use crate::graphics::ty::Ty; use crate::graphics::{AttaWithBuffer, Config, Graphics}; use super::Colletion; pub struct AggFastPath { program: Program, buffer: Vec, indice: Vec<[u32; 3]>, vao: Option, vbo: Option, ebo: Option, } impl AggFastPath { pub fn new() -> Result { let vertex = Shader::new( glow::VERTEX_SHADER, CodeType::::Path("agg-fast-path.vert".into()), )?; let fragment = Shader::new( glow::FRAGMENT_SHADER, CodeType::::Path("agg-fast-path.frag".into()), )?; let input_snippet = Snippet::new( "input", CodeType::<&'static str>::Code( " layout(location = 0) in vec3 prev; layout(location = 1) in vec3 curr; layout(location = 2) in vec3 next; layout(location = 3) in float id; uniform float linewidth; uniform float antialias; uniform vec4 color; ", ), false, None, )?; let vertex = vertex.add_snippet_before(input_snippet); let program = Program::new(vertex, fragment, None, "330 core"); // program.set_transform(transform); // program.set_viewport(viewport); Ok(Self { program, buffer: Vec::with_capacity(128), indice: Vec::with_capacity(128 * 2), ebo: None, vao: None, vbo: None, }) } pub fn set_transform(&mut self, transform: &T) { self.program.set_transform(transform); } pub fn set_viewport(&mut self, viewport: &Viewport) { self.program.set_viewport(viewport); } pub fn set_linecolor(&mut self, gl: &glow::Context, color: [f32; 4]) { let loc = self.program.get_uniform_location(gl, "color"); unsafe { gl.uniform_4_f32(loc.as_ref(), color[0], color[1], color[2], color[3]); } } pub fn set_linewidth(&mut self, gl: &glow::Context, linewidth: f32) { let loc = self.program.get_uniform_location(gl, "linewidth"); unsafe { gl.uniform_1_f32(loc.as_ref(), linewidth); } } pub fn set_anatialias(&mut self, gl: &glow::Context, antialias: f32) { let loc = self.program.get_uniform_location(gl, "antialias"); unsafe { gl.uniform_1_f32(loc.as_ref(), antialias); } } pub fn program(&mut self) -> &mut Program { &mut self.program } pub fn program_ref(&self) -> &Program { &self.program } fn init(&mut self, gl: &glow::Context) { self.set_anatialias(gl, 0.005); self.set_linecolor(gl, [1.0, 1.0, 1.0, 1.0]); self.set_linewidth(gl, 0.02); } } impl Colletion for AggFastPath { type Item = Path; fn append(&mut self, item: Self::Item) { self.buffer.extend(item.points); self.indice.extend(item.ebo); } } impl Graphics for AggFastPath { const id: &'static str = "AggPath"; type Config = (); fn compile(&mut self, gl: &glow::Context) -> Result<()> { use bytemuck::cast_slice; self.program.compile(gl)?; unsafe { let vao = gl.create_vertex_array().unwrap(); gl.bind_vertex_array(Some(vao)); for p in self.buffer.iter() { println!("{}", p); } println!("{:?}", self.indice); let vbo = gl.create_buffer().unwrap(); gl.bind_buffer(glow::ARRAY_BUFFER, Some(vbo)); gl.buffer_data_u8_slice( glow::ARRAY_BUFFER, cast_slice(&self.buffer), glow::STATIC_DRAW, ); gl.enable_vertex_attrib_array(0); gl.vertex_attrib_pointer_f32(0, 3, glow::FLOAT, false, 40, 0); gl.enable_vertex_attrib_array(1); gl.vertex_attrib_pointer_f32(1, 3, glow::FLOAT, false, 40, 12); gl.enable_vertex_attrib_array(2); gl.vertex_attrib_pointer_f32(2, 3, glow::FLOAT, false, 40, 24); gl.enable_vertex_attrib_array(3); gl.vertex_attrib_pointer_f32(3, 1, glow::FLOAT, false, 40, 36); let ebo = gl.create_buffer().unwrap(); gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(ebo)); gl.buffer_data_u8_slice( glow::ELEMENT_ARRAY_BUFFER, cast_slice(&self.indice), glow::STATIC_DRAW, ); self.vao = Some(vao); self.vbo = Some(vbo); self.ebo = Some(ebo); gl.bind_vertex_array(None); } Ok(()) } fn draw(&self, gl: &glow::Context, count: i32) -> Result<()> { unsafe { gl.clear(glow::COLOR_BUFFER_BIT); gl.bind_vertex_array(Some(self.vao.unwrap())); gl.draw_elements( glow::TRIANGLES, (self.indice.len() * 3) as i32, glow::UNSIGNED_INT, 0, ); gl.bind_vertex_array(None); } Ok(()) } fn destroy(&mut self, gl: &glow::Context) -> Result<()> { self.program.destroy(gl); unsafe { self.ebo.map(|ebo| gl.delete_buffer(ebo)); self.vao.map(|vao| gl.delete_vertex_array(vao)); self.vbo.map(|vbo| gl.delete_buffer(vbo)); } Ok(()) } fn program_ref(&self) -> &Program { &self.program } fn program_mut(&mut self) -> &mut Program { &mut self.program } fn set_config(&mut self, gl: &glow::Context, config: &Self::Config) -> Result<()> { Ok(()) } fn mount(&mut self, gl: &glow::Context) -> Result<()> { unsafe { gl.use_program(self.program.native_program); self.init(gl); } Ok(()) } fn unmount(&mut self, gl: &glow::Context) -> Result<()> { unsafe { gl.use_program(None); } Ok(()) } } impl AttaWithBuffer for AggFastPath { type Data = (); fn bake( &self, data: &Self::Data, config: &::Config, ) -> Result<(Vec, Option>, i32)> { Ok((vec![], None, 0)) } fn init(&self, gl: &glow::Context) -> (NativeVertexArray, NativeBuffer, Option) { (self.vao.unwrap(), self.vbo.unwrap(), self.ebo) } } #[repr(C)] #[derive(Debug, Clone, Copy, Zeroable, Pod)] pub struct Point { prev: [f32; 3], curr: [f32; 3], next: [f32; 3], id: f32, } impl std::fmt::Display for Point { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( f, "Point {{ prev: {:?}, curr: {:?}, next: {:?}, id: {} }}", self.prev, self.curr, self.next, self.id ) } } impl Ty for Point {} #[derive(Debug)] pub struct Path { points: Vec, ebo: Vec<[u32; 3]>, is_closed: bool, is_empty: bool, } impl Default for Path { fn default() -> Self { Self { points: Vec::with_capacity(500), ebo: Vec::with_capacity(500), is_closed: false, is_empty: true, } } } pub struct PathBuilder { is_closed: bool, } impl Default for PathBuilder { fn default() -> Self { Self { is_closed: false } } } impl PathBuilder { pub fn is_closed(&mut self, is_closed: bool) -> &mut Self { self.is_closed = is_closed; self } pub fn build(&self) -> Path { Path { points: Vec::with_capacity(500), is_closed: self.is_closed, ebo: Vec::with_capacity(500), is_empty: true, } } } impl Path { pub fn new(is_closed: bool) -> Self { Self { points: Vec::with_capacity(500), ebo: Vec::with_capacity(500), is_closed, is_empty: true, } } pub fn builder() -> PathBuilder { PathBuilder::default() } pub fn push(&mut self, point: [f32; 3]) { if self.is_empty { self.points.push(Point { prev: point, curr: point, next: point, id: 1.0, }); self.points.push(Point { prev: point, curr: point, next: point, id: -1.0, }); self.is_empty = false; } else { let len = self.points.len(); let prev = self.points[len - 1].curr; let curr = point; let next = point; self.points.push(Point { prev, curr, next, id: 1.0, }); self.points.push(Point { prev, curr, next, id: -1.0, }); self.points[len - 1].next = curr; self.points[len - 2].next = curr; } } pub fn finish(&mut self) { if self.is_closed { let len = self.points.len(); let curr = self.points.first().unwrap().curr; let prev = self.points[len - 1].curr; let next = self.points[1].next; self.points.push(Point { prev, curr, next, id: 1.0, }); self.points.push(Point { prev, curr, next, id: -1.0, }); self.points[len - 1].next = curr; self.points[len - 2].next = curr; } for s in 0..(self.points.len() / 2) - 1 { let s = s as u32; self.ebo.push([s * 2, s * 2 + 1, (s + 1) * 2 + 1]); self.ebo.push([s * 2, (s + 1) * 2 + 1, (s + 1) * 2]); } } pub fn len(&self) -> usize { self.points.len() } } impl Deref for Path { type Target = [u8]; fn deref(&self) -> &Self::Target { use bytemuck::cast_slice; cast_slice(&self.points) } } impl DerefMut for Path { fn deref_mut(&mut self) -> &mut Self::Target { use bytemuck::cast_slice_mut; cast_slice_mut(&mut self.points) } } mod test { use crate::graphics::transforms::{polar::Polar, position::Position, trackball::Trackball}; use super::*; #[test] fn test_path() { let mut path = Path::builder().is_closed(false).build(); path.push([9.0, 9.0, 9.0]); path.push([9.0, 19.0, 9.0]); path.finish(); println!("{:?}, len: {}", path, path.len()); } #[test] fn test_agg() { // let viewport = Trackball::new().unwrap(); // let trans = Polar::new().unwrap(); // let position = Position::new().unwrap(); // let transform = viewport.chain(trans.chain(position)); // let viewport = &Viewport::new().unwrap(); // let agg_path = AggFastPath::new(&transform, &viewport).unwrap(); } }