rustbatch 0.4.0

purely game dewelopment crate that offers simple but powerfull 2D rendering and some fast solutions for game world bottle necks
Documentation
use crate::render::batch::{VertexData, Target};
use crate::{Rect, Sprite, Program, Buffer, Vect};
use crate::math::rgba::{WHITE, RGBA};
use crate::math::angle::PI2;

pub enum LineMode {
    Sharp,
    Smooth(usize),
    None
}

/// GeomDrawer can draw lines and rectangles but you can draw almost anything with some math by
/// pushing points. You can reuse what you already drawn if you dont clear the screen, on the other
/// hand if you need more dinamic aproach clear and redraw ewery frame.
///
/// # example
/// ```
/// use rustbatch::{Window, Vect, FPS, Rect};
/// use rustbatch::render::geom::{GeomDrawer, LineMode};
/// use rustbatch::vect;
/// use rustbatch::rect;
/// let (mut window, mut event_pump, _gl, _sdl, _video_subsystem) = Window::new(|sys| {
///             sys.window("rusty batch", 1000, 700)
///                 .opengl()
///                 .resizable()
///                 .build()
///                 .unwrap()
///         });
///
///         window.set_background_color(&[0.5f32, 0.5f32, 0.5f32, 1f32]);
///
///         let mut drawer = GeomDrawer::new();
///         drawer.color = [1.0, 0.0, 1.0, 5.0];
///         drawer.polynomial(vect!(100, 100), 20.0, 100.0, 0.0, 40, LineMode::Sharp);
///         drawer.color = [1.0, 0.0, 1.0, 0.5];
///         drawer.polynomial(Vect::ZERO, 20.0, 100.0, 0.0, 3, LineMode::Sharp);
///         drawer.color = [0.0, 0.5, 1.0, 5.5];
///         drawer.empty_rect(rect!(0, -40, 150, 60), 10.0, LineMode::Sharp);
///         drawer.color = [1.0, 1.0, 0.0, 0.5];
///
///         let mut fps = FPS::new(1f32);
///
///         'main: loop {
///             for event in event_pump.poll_iter() {
///                 match event {
///                     sdl2::event::Event::Quit { .. } => break 'main,
///                     _ => {}
///                 }
///             }
///             let _delta = fps.increase(0f32);
///
///             window.clear();
///
///             drawer.draw(&mut window.canvas);
///
///             window.update();
///        }
/// ```
pub struct GeomDrawer {
    data: VertexData,
    program: Program,
    buffer: Buffer,
    offset: u32,
    pub color: RGBA,
}

impl GeomDrawer {
    #[inline]
    pub fn new() -> Self {
        Self {
            offset: 0,
            color: WHITE,
            data: VertexData::no_texture(),
            program: Program::no_texture(),
            buffer: Buffer::no_texture(),
        }
    }

    #[inline]
    pub fn rect(&mut self, rect: Rect) {
        self.add_rectangle(&rect.verts())
    }

    pub fn empty_rect(&mut self, rect: Rect, thickness: f32, mode: LineMode) {
        let verts = rect.verts();
        self.line(&[verts[0], verts[1], verts[2], verts[3], verts[0]], thickness, mode);
    }

    #[inline]
    pub fn add_rectangle(&mut self, points: &[Vect; 4]) {
        for p in points.iter() {
            self.data.vertices.push(p.x);
            self.data.vertices.push(p.y);
            self.data.vertices.extend(&self.color);
        }

        for i in Sprite::PATTERN.iter() {
            self.data.indices.push(*i + self.offset);
        }

        self.offset += 4;
    }

    pub fn line(&mut self, points: &[Vect], thickness: f32, mode: LineMode) {
        if points.len() < 2 {
            return
        }

        let mut prev0 = points[0];
        let start_offset = prev0.to(points[1]).normal().norm() * thickness;
        let mut prev1 = points[0];
        let mut prev2 = points[0];
        for i in 1..points.len() {
            let curr = points[i];
            let offset = prev0.to(curr).normal().norm() * thickness;
            println!("{:?}", offset);
            let verts = [
                prev0 - offset,
                curr - offset,
                curr + offset,
                prev0 + offset,
            ];

            self.add_rectangle(&verts);

            match mode {
                LineMode::Sharp => {
                    self.add_rectangle(&[verts[0], verts[3], prev2, prev1]);
                    prev1 = verts[1];
                    prev2 = verts[2];
                }
                LineMode::Smooth(_) => {}
                LineMode::None => {}
            }
            prev0 = curr;
        }

        if points[0] == prev0 { match mode {
            LineMode::Sharp => self.add_rectangle(&[prev0 - start_offset, prev0 + start_offset, prev2, prev1]),
            LineMode::Smooth(_) => {}
            LineMode::None => {}
        }}
    }

    pub fn polynomial(&mut self, position: Vect, thickness: f32, radius: f32, rotation: f32, sides: usize, mode: LineMode) {
        let vec = Vect::rad(rotation, radius);

        let mut points = Vec::with_capacity(sides);
        for i in 0..sides {
            points.push(position + vec.rot(PI2/sides as f32 * i as f32))
        }
        points.push(points[0]);

        self.line(&points, thickness, mode);
    }

    #[inline]
    pub fn point(&mut self ,pos: Vect) {
        self.data.vertices.push(pos.x);
        self.data.vertices.push(pos.y);
        self.data.vertices.extend(&self.color);
        self.offset += 1;
        self.data.indices.push(self.offset);
    }

    #[inline]
    pub fn clear(&mut self) {
        self.data.clear();
        self.offset = 0;
    }

    #[inline]
    pub fn draw<T: Target>(&self, target: &mut T) {
        target.append(&self.data.vertices, &self.data.indices, self.data.vertex_size, Some(&self.program), None, Some(&self.buffer));
    }
}