use super::*;
#[derive(Clone, Debug, PartialEq)]
pub struct Pen<T> {
pub template: T,
}
impl<V: TVertex, U: TUniform> DrawBuilder<V, U> {
#[inline(never)]
pub fn draw_line<T: ToVertex<V>>(&mut self, pen: &Pen<T>, a: Point2f, b: Point2f) {
let vertices = [
pen.template.to_vertex(a, 0),
pen.template.to_vertex(b, 1),
];
let mut cv = self.begin(PrimType::Lines, 2, 1);
cv.add_index2(0, 1);
cv.add_vertices(&vertices);
}
#[inline(never)]
pub fn draw_lines<T: ToVertex<V>>(&mut self, pen: &Pen<T>, pts: &[Point2f], lines: &[(u32, u32)]) {
let mut cv = self.begin(PrimType::Lines, pts.len(), lines.len());
for i in 0..lines.len() {
cv.add_index2(lines[i].0, lines[i].1);
}
for i in 0..pts.len() {
cv.add_vertex(pen.template.to_vertex(pts[i], i));
}
}
#[inline(never)]
pub fn draw_line_rect<T: ToVertex<V>>(&mut self, pen: &Pen<T>, rc: &Bounds2f) {
let vertices = [
pen.template.to_vertex(rc.bottom_left(), 0),
pen.template.to_vertex(rc.top_left(), 1),
pen.template.to_vertex(rc.top_right(), 2),
pen.template.to_vertex(rc.bottom_right(), 3),
];
let mut cv = self.begin(PrimType::Lines, 4, 4);
cv.add_indices(&[0, 1, 1, 2, 2, 3, 3, 0]);
cv.add_vertices(&vertices);
}
#[inline(never)]
pub fn draw_round_rect<T: ToVertex<V>>(&mut self, pen: &Pen<T>, rc: &Bounds2f, sx: f32, sy: f32, _segments: i32) {
let sx = if sx + sx > rc.width() { rc.width() * 0.5 } else { sx };
let sy = if sy + sy > rc.height() { rc.height() * 0.5 } else { sy };
if sx <= 0.0 || sy <= 0.0 {
return self.draw_line_rect(pen, rc);
}
unimplemented!()
}
pub fn draw_arrow<T: ToVertex<V>>(&mut self, pen: &Pen<T>, start: Point2f, end: Point2f, head: f32) {
let pth = (end - start).resize(head);
let pta = (end - pth) + pth.ccw() * 0.5;
let ptb = (end - pth) + pth.cw() * 0.5;
let vertices = [
pen.template.to_vertex(start, 0),
pen.template.to_vertex(end, 1),
pen.template.to_vertex(pta, 2),
pen.template.to_vertex(ptb, 3),
];
let mut cv = self.begin(PrimType::Lines, 4, 3);
cv.add_indices(&[0, 1, 2, 1, 3, 1]);
cv.add_vertices(&vertices);
}
#[inline(never)]
pub fn draw_poly_line<T: ToVertex<V>>(&mut self, pen: &Pen<T>, pts: &[Point2f], close: bool) {
if pts.len() < 2 {
return;
}
let n = pts.len() - (!close) as usize;
let mut cv = self.begin(PrimType::Lines, pts.len(), n);
for i in 0..pts.len() - 1 {
cv.add_index2(i as u32, (i + 1) as u32);
}
if close {
cv.add_index2((pts.len() - 1) as u32, 0);
}
for v in 0..pts.len() {
cv.add_vertex(pen.template.to_vertex(pts[v], v));
}
}
#[inline(never)]
pub fn draw_ellipse<T: ToVertex<V>>(&mut self, pen: &Pen<T>, rc: &Bounds2f, segments: i32) {
let n = cmp::max(3, segments) as usize;
let mut cv = self.begin(PrimType::Lines, n, n);
for i in 0..n - 1 {
cv.add_index2(i as u32, (i + 1) as u32);
}
cv.add_index2((n - 1) as u32, 0);
let (s, c) = (Angle::TURN / (n as i32 as f32)).sin_cos();
let radius = rc.size() * 0.5;
let center = rc.top_left() + radius;
let mut pt = Point2(1.0, 0.0);
for v in 0..n {
cv.add_vertex(pen.template.to_vertex(center + pt * radius, v));
let x = pt.x;
pt.x = c * x - s * pt.y;
pt.y = s * x + c * pt.y;
}
}
#[inline(never)]
pub fn draw_arc<T: ToVertex<V>>(&mut self, pen: &Pen<T>, rc: &Bounds2f, start: Angle<f32>, sweep: Angle<f32>, segments: i32) {
if sweep <= -Angle::TURN || sweep >= Angle::TURN {
return self.draw_ellipse(pen, rc, segments);
}
let n = cmp::max(2, segments) as usize;
let mut cv = self.begin(PrimType::Lines, n + 1, n);
for i in 0..n {
cv.add_index2(i as u32, (i + 1) as u32);
}
let (s, c) = (sweep / (n as i32 as f32)).sin_cos();
let radius = rc.size() * 0.5;
let center = rc.top_left() + radius;
let mut pt = {
let (y, x) = start.sin_cos();
Point2(x, y)
};
for v in 0..n + 1 {
cv.add_vertex(pen.template.to_vertex(center + pt * radius, v));
let x = pt.x;
pt.x = c * x - s * pt.y;
pt.y = s * x + c * pt.y;
}
}
#[inline(never)]
pub fn draw_bezier2<T: ToVertex<V>>(&mut self, pen: &Pen<T>, pts: &[Point2f; 3], segments: i32) {
let n = cmp::max(2, segments) as usize;
let mut cv = self.begin(PrimType::Lines, n + 1, n);
for i in 0..n {
cv.add_index2(i as u32, (i + 1) as u32);
}
for v in 0..n + 1 {
let pt = curve::bezier2(v as i32 as f32 / n as i32 as f32, pts[0], pts[1], pts[2]);
cv.add_vertex(pen.template.to_vertex(pt, v));
}
}
#[inline(never)]
pub fn draw_bezier3<T: ToVertex<V>>(&mut self, pen: &Pen<T>, pts: &[Point2f; 4], segments: i32) {
let n = cmp::max(2, segments) as usize;
let mut cv = self.begin(PrimType::Lines, n + 1, n);
for i in 0..n {
cv.add_index2(i as u32, (i + 1) as u32);
}
for v in 0..n + 1 {
let pt = curve::bezier3(v as i32 as f32 / n as i32 as f32, pts[0], pts[1], pts[2], pts[3]);
cv.add_vertex(pen.template.to_vertex(pt, v));
}
}
#[inline(never)]
pub fn draw_cspline<T: ToVertex<V>>(&mut self, pen: &Pen<T>, pts: &[Point2f], tension: f32, segments: i32) {
if pts.len() < 2 {
return;
}
let mut u = Point2::ZERO;
let mut v;
let tension = (1.0 - tension) * 0.5;
for i in 0..pts.len() - 1 {
v = if i == pts.len() - 2 {
Point2::ZERO
}
else {
(pts[i + 2] - pts[i]) * tension
};
let curve = [
pts[i],
pts[i] + u * (1.0 / 3.0),
pts[i + 1] - v * (1.0 / 3.0),
pts[i + 1],
];
self.draw_bezier3(pen, &curve, segments);
u = v;
}
}
}