use crate::gl;
use glin;
use rin_graphics::{self as graphics, Vertex2DColor, vertex2dcolor, PrimitiveType, path::LineCap};
use color::{ToRgba,Rgba};
use rin_util::LazyUpdate;
use super::{CreationContext, VaoMesh, CreationProxy};
use rin_math::{Pnt2, Vec2, Deg, ToVec};
pub struct VaoPath{
path: graphics::Path2D,
vao_mesh_fill: LazyUpdate<VaoMesh<Vec2>>,
vao_mesh_outline: LazyUpdate<VaoMesh<graphics::Vertex2DColor>>,
}
pub struct Builder(pub(crate) CreationProxy);
impl Builder{
pub fn build(&self) -> VaoPath{
let mut vao_path = VaoPath{
path: graphics::Path2D::new(),
vao_mesh_fill: LazyUpdate::new(self.0.new_vao_mesh().build(gl::STATIC_DRAW)),
vao_mesh_outline: LazyUpdate::new(self.0.new_vao_mesh().build(gl::STATIC_DRAW)),
};
vao_path.vao_mesh_fill.mesh_mut().set_primitive_type(PrimitiveType::TriangleFan);
#[cfg(not(any(feature="gles", feature="webgl")))]
vao_path.vao_mesh_outline.mesh_mut().set_primitive_type(PrimitiveType::LinesAdjacency);
#[cfg(any(feature="gles", feature="webgl"))]
vao_path.vao_mesh_outline.mesh_mut().set_primitive_type(PrimitiveType::Lines);
vao_path
}
pub fn from_shader(&self, shader: &glin::Program) -> VaoPath{
let mut vao_path = VaoPath{
path: graphics::Path2D::new(),
vao_mesh_fill: LazyUpdate::new(self.0.new_vao_mesh().from_shader(shader, gl::STATIC_DRAW)),
vao_mesh_outline: LazyUpdate::new(self.0.new_vao_mesh().from_shader(shader, gl::STATIC_DRAW)),
};
vao_path.vao_mesh_fill.mesh_mut().set_primitive_type(PrimitiveType::TriangleFan);
#[cfg(not(any(feature="gles", feature="webgl")))]
vao_path.vao_mesh_outline.mesh_mut().set_primitive_type(PrimitiveType::LinesAdjacency);
#[cfg(any(feature="gles", feature="webgl"))]
vao_path.vao_mesh_outline.mesh_mut().set_primitive_type(PrimitiveType::Lines);
vao_path
}
pub fn from_path(&self, path: graphics::Path2D) -> VaoPath{
let mut vao_path = self.build();
vao_path.path = path;
vao_path
}
pub fn from_path_shader(&self, path: graphics::Path2D, shader: &glin::Program) -> VaoPath{
let mut vao_path = self.from_shader(shader);
vao_path.path = path;
vao_path
}
}
impl VaoPath{
pub fn set_line_width(&mut self, w: f32){
self.path.set_line_width(w);
}
pub fn line_width(&self) -> f32{
self.path.line_width()
}
pub fn set_line_cap(&mut self, cap: LineCap){
self.path.set_line_cap(cap);
}
pub fn line_cap(&self) -> LineCap{
self.path.line_cap()
}
pub fn set_line_color<C: ToRgba>(&mut self, c: &C){
self.path.set_line_color(c);
}
pub fn line_color(&self) -> Rgba<f32>{
self.path.line_color()
}
pub fn set_fill_color<C: ToRgba>(&mut self, c: &C){
self.path.set_fill_color(c);
}
pub fn fill_color(&self) -> Rgba<f32>{
self.path.fill_color()
}
pub fn set_changed(&mut self){
self.vao_mesh_fill.set_changed();
self.vao_mesh_outline.set_changed();
}
pub fn move_to(&mut self, to: Pnt2){
self.path.move_to(to);
self.set_changed();
}
pub fn line_to(&mut self, to: Pnt2){
self.path.line_to(to);
self.set_changed();
}
pub fn bezier_to(&mut self, cp1: Pnt2, cp2: Pnt2, to: Pnt2){
self.path.bezier_to(cp1, cp2, to);
self.set_changed();
}
pub fn quad_bezier_to(&mut self, cp1: Pnt2, to: Pnt2){
self.path.quad_bezier_to(cp1, to);
self.set_changed();
}
pub fn catmull_rom_to(&mut self, to: Pnt2){
self.path.catmull_rom_to(to);
self.set_changed();
}
pub fn arc(&mut self, center: Pnt2, w: f32, h: f32, init_angle: Deg<f32>, angle: Deg<f32>){
self.path.arc(center, w, h, init_angle, angle);
self.set_changed();
}
pub fn close(&mut self){
self.path.close();
}
pub fn append(&mut self, path: graphics::Path2D){
self.path.append(path);
self.set_changed();
}
pub fn set(&mut self, path: graphics::Path2D){
self.path.clear();
self.path.append(path);
self.set_changed();
}
pub fn clear(&mut self){
self.path.clear();
self.set_changed();
}
pub fn is_empty(&self) -> bool {
self.path.is_empty()
}
pub fn to_lines<F>(&self, resolution: u32, f: F)
where F: FnMut(Pnt2, Pnt2, bool){
self.path.to_lines(resolution,f);
}
pub fn to_line_strips<F>(&self, resolution: u32, f: F)
where F: FnMut(Pnt2,bool){
self.path.to_line_strips(resolution,f);
}
pub fn path<'a>(&'a self) -> &'a graphics::Path2D{
&self.path
}
pub fn path_mut<'a>(&'a mut self) -> &'a mut graphics::Path2D{
self.set_changed();
&mut self.path
}
pub fn fill(&self, resolution: u32) -> VaoPathFill{
VaoPathFill{
path: self,
resolution,
}
}
pub fn contour(&self, resolution: u32) -> VaoPathContour{
VaoPathContour{
path: self,
resolution,
}
}
}
pub struct VaoPathFill<'a>{
path: &'a VaoPath,
resolution: u32,
}
impl<'a> VaoPathFill<'a>{
pub fn vao_mesh(&self) -> &VaoMesh<Vec2>{
self.path.vao_mesh_fill.update(|vao| {
vao.mesh_mut().clear();
self.path.path.to_line_strips(self.resolution, |to, _new|{
vao.mesh_mut().push(to.to_vec());
});
});
&self.path.vao_mesh_fill
}
pub fn color(&self) -> Rgba<f32>{
self.path.fill_color()
}
}
pub struct VaoPathContour<'a>{
path: &'a VaoPath,
resolution: u32,
}
impl<'a> VaoPathContour<'a>{
#[cfg(not(any(feature="gles", feature="webgl")))]
pub fn vao_mesh(&self) -> &VaoMesh<Vertex2DColor>{
self.path.vao_mesh_outline.update(|vao| {
vao.mesh_mut().clear();
vao.set_primitive_type(PrimitiveType::LinesAdjacency);
let mut shape_index = 0;
let mut path_index = 0;
let mut first_index = 0;
let mut prev_from = Pnt2::origin();
let mut prev_to = Pnt2::origin();
let mut first = Pnt2::origin();
let mut second = Pnt2::origin();
let mut closed = false;
let vao_mesh_outline = vao.mesh_mut();
self.path.path.to_lines(self.resolution, |from, to, close|{
if shape_index != 0 && from != prev_to && !closed{
let next = prev_to+(prev_to-prev_from);
vao_mesh_outline.push(vertex2dcolor(next.to_vec(), &self.color()));
let first = first-(second-first);
vao_mesh_outline.insert(first_index, vertex2dcolor(first.to_vec(), &self.color()));
path_index += 2;
first_index = path_index;
shape_index = 0;
}
closed = false;
if shape_index == 0{
vao_mesh_outline.push(vertex2dcolor(from.to_vec(), &self.color()));
vao_mesh_outline.push(vertex2dcolor(to.to_vec(), &self.color()));
first = from;
second = to;
shape_index += 2;
path_index += 2;
}else{
vao_mesh_outline.push(vertex2dcolor(to.to_vec(), &self.color()));
vao_mesh_outline.push(vertex2dcolor(prev_from.to_vec(), &self.color()));
vao_mesh_outline.push(vertex2dcolor(from.to_vec(), &self.color()));
vao_mesh_outline.push(vertex2dcolor(to.to_vec(), &self.color()));
shape_index += 4;
path_index += 4;
}
prev_from = from;
prev_to = to;
if close {
vao_mesh_outline.push(vertex2dcolor(second.to_vec(), &self.color()));
vao_mesh_outline.insert(first_index,vertex2dcolor(from.to_vec(), &self.color()));
path_index += 2;
first_index = path_index;
shape_index = 0;
closed = true;
}
});
if !closed{
let next = prev_to+(prev_to-prev_from);
vao_mesh_outline.push(vertex2dcolor(next.to_vec(), &self.color()));
let first = first-(second-first);
vao_mesh_outline.insert(first_index,vertex2dcolor(first.to_vec(), &self.color()));
}
});
&self.path.vao_mesh_outline
}
#[cfg(any(feature="gles", feature="webgl"))]
pub fn vao_mesh(&self) -> &VaoMesh<Vertex2DColor>{
self.path.vao_mesh_outline.update(|vao| {
vao.mesh_mut().clear();
vao.set_primitive_type(PrimitiveType::Lines);
let mut closed = false;
let vao_mesh_outline = vao.mesh_mut();
self.path.path.to_lines(self.resolution, |from, to, close|{
vao_mesh_outline.push(vertex2dcolor(from.to_vec(), &self.color()));
vao_mesh_outline.push(vertex2dcolor(to.to_vec(), &self.color()));
closed = close
});
if closed{
if let Some(p) = vao_mesh_outline.vertices().first().map(|p| *p) {
vao_mesh_outline.push(p);
}
}
});
&self.path.vao_mesh_outline
}
pub fn color(&self) -> Rgba<f32>{
self.path.line_color()
}
pub fn line_cap(&self) -> LineCap {
self.path.line_cap()
}
pub fn line_width(&self) -> f32{
self.path.line_width()
}
}