diff options
| author | Micha White <botahamec@outlook.com> | 2024-08-15 20:16:32 -0400 |
|---|---|---|
| committer | Micha White <botahamec@outlook.com> | 2024-08-15 20:16:32 -0400 |
| commit | db9aa9f1bf49e8bede384b9ceb1e1fb82b522799 (patch) | |
| tree | 0d60727acf481f59b42ef0f74ed07c16ec562bcf /tvg/src/render.rs | |
| parent | f8a80039c74332e2101a177ef3fde31ef2077224 (diff) | |
Delete stuff
Diffstat (limited to 'tvg/src/render.rs')
| -rw-r--r-- | tvg/src/render.rs | 506 |
1 files changed, 0 insertions, 506 deletions
diff --git a/tvg/src/render.rs b/tvg/src/render.rs deleted file mode 100644 index f8c15a1..0000000 --- a/tvg/src/render.rs +++ /dev/null @@ -1,506 +0,0 @@ -use crate::{ - colors::{self, blend, lerp, Color, ColorTable}, - commands::{Command, Point, Rectangle, Style, Vector}, - header::TvgHeader, - path::{Instruction, InstructionData, Path, Sweep}, - TvgFile, -}; - -fn distance(p0: Point, p1: Point) -> f64 { - (p0 - p1).magnitude().abs() -} - -fn rotation_matrix(angle: f64) -> [[f64; 2]; 2] { - let s = angle.sin(); - let c = angle.cos(); - [[c, -s], [s, c]] -} - -fn apply_matrix(matrix: [[f64; 2]; 2], vector: Vector) -> Vector { - Vector { - x: vector.x * matrix[0][0] + vector.y * matrix[0][1], - y: vector.x * matrix[1][0] + vector.y * matrix[1][1], - } -} - -fn apply_matrix_point(matrix: [[f64; 2]; 2], point: Point) -> Point { - Point { - x: point.x * matrix[0][0] + point.y * matrix[0][1], - y: point.x * matrix[1][0] + point.y * matrix[1][1], - } -} - -fn lerp_f64(a: f64, b: f64, x: f64) -> f64 { - a + (b - a) * x -} - -fn lerp_and_reduce(vals: &[f64], f: f64) -> Vec<f64> { - let mut result = Vec::with_capacity(vals.len() - 1); - for i in 0..(vals.len() - 1) { - result.push(lerp_f64(vals[i], vals[i + 1], f)); - } - result -} - -fn lerp_and_reduce_to_one(vals: &[f64], f: f64) -> f64 { - if vals.len() == 1 { - vals[0] - } else { - lerp_and_reduce_to_one(&lerp_and_reduce(vals, f), f) - } -} - -/// A version of [`Point`] that uses usizes for a PixMap -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -struct UPoint { - x: usize, - y: usize, -} - -impl UPoint { - fn new(x: usize, y: usize) -> UPoint { - Self { x, y } - } -} - -struct FrameBuffer<C: Color> { - width: usize, - height: usize, - pixels: Box<[C]>, - scale_x: f64, - scale_y: f64, -} - -impl<C: Color + Clone + Default> FrameBuffer<C> { - fn new(width: usize, height: usize, scale_x: f64, scale_y: f64) -> Self { - let pixel_count = width * height; - Self { - width, - height, - pixels: vec![C::default(); pixel_count].into_boxed_slice(), - scale_x, - scale_y, - } - } - - fn point_to_upoint(&self, point: Point) -> UPoint { - todo!() - } - - fn upoint_to_point(&self, upoint: UPoint) -> Point { - todo!() - } - - /// Blends the new color with the given pixel. Returns `None` if the destination is invalid - fn set_pixel(&mut self, x: usize, y: usize, color: C) -> Option<()> { - if x >= self.width || y >= self.height { - return None; - } - - let offset = y * self.width + x; - let destination_pixel = self.pixels.get_mut(offset)?; - - blend(destination_pixel, &color); - - Some(()) - } - - fn draw_line( - &mut self, - color_table: ColorTable<C>, - style: Style, - width_start: f64, - width_end: f64, - line_start: Point, - line_end: Point, - ) -> Option<()> { - let mut min_x = usize::MAX; - let mut min_y = usize::MAX; - let mut max_x = usize::MIN; - let mut max_y = usize::MIN; - - let max_width = f64::max(width_start, width_end); - - let points = [line_start, line_end]; - for pt in points { - min_x = usize::min(min_x, (self.scale_x * (pt.x - max_width)).floor() as usize); - min_y = usize::min(min_y, (self.scale_y * (pt.y - max_width)).floor() as usize); - max_x = usize::max(max_x, (self.scale_x * (pt.x - max_width)).floor() as usize); - max_y = usize::max(max_y, (self.scale_y * (pt.y - max_width)).floor() as usize); - } - - // limit to framebuffer size - min_x = usize::min(min_x, self.width); - min_y = usize::min(min_y, self.height); - max_x = usize::min(max_x, self.width); - max_y = usize::min(max_y, self.height); - - for y in min_y..=max_y { - for x in min_x..=max_x { - let point = self.upoint_to_point(UPoint { x, y }); - let dist = todo!() as f64; - - if dist >= 0.0 { - self.set_pixel(x, y, style.get_color_at(&color_table, point)?); - } - } - } - - Some(()) - } -} - -#[derive(Debug, Default)] -struct PathMaker { - points: Vec<Point>, - width: Vec<f64>, -} - -impl PathMaker { - fn new(width: f64, start: Point) -> Self { - let points = vec![start]; - let width = vec![width]; - - Self { points, width } - } - - fn render_line(&mut self, width: f64, to_point: Point) { - self.points.push(to_point); - self.width.push(width); - } - - fn render_horizontal_line(&mut self, width: f64, x: f64) { - self.points.push(Point { - x, - y: self.points.last().unwrap().y, - }); - self.width.push(width); - } - - fn render_vertical_line(&mut self, width: f64, y: f64) { - self.points.push(Point { - x: self.points.last().unwrap().x, - y, - }); - self.width.push(width); - } - - fn render_cubic_bezier( - &mut self, - control_0: Point, - control_1: Point, - point: Point, - start_width: f64, - end_width: f64, - ) { - const BEZIER_POLY_COUNT: usize = 16; - - let previous = self.points.last().unwrap(); - let oct0x = [previous.x, control_0.x, control_1.x, point.x]; - let oct0y = [previous.y, control_0.y, control_1.y, point.y]; - - for i in 1..BEZIER_POLY_COUNT { - let f = i as f64 / BEZIER_POLY_COUNT as f64; - let x = lerp_and_reduce_to_one(&oct0x, f); - let y = lerp_and_reduce_to_one(&oct0y, f); - - self.points.push(Point { x, y }); - self.width.push(lerp_f64(start_width, end_width, f)); - } - - self.points.push(point); - self.width.push(end_width); - } - - fn render_quadratic_bezier( - &mut self, - control: Point, - target: Point, - start_width: f64, - end_width: f64, - ) { - const BEZIER_POLY_COUNT: usize = 16; - - let previous = self.points.last().unwrap(); - let oct0x = [previous.x, control.x, target.x]; - let oct0y = [previous.y, control.y, target.y]; - - for i in 1..BEZIER_POLY_COUNT { - let f = i as f64 / BEZIER_POLY_COUNT as f64; - let x = lerp_and_reduce_to_one(&oct0x, f); - let y = lerp_and_reduce_to_one(&oct0y, f); - - self.points.push(Point { x, y }); - self.width.push(lerp_f64(start_width, end_width, f)); - } - - self.points.push(target); - self.width.push(end_width); - } - - fn render_circle( - &mut self, - p0: Point, - p1: Point, - mut radius: f64, - large_arc: bool, - turn_left: bool, - end_width: f64, - ) { - const CIRCLE_POLY_COUNT: usize = 100; - - let start_width = *self.width.last().unwrap(); - let left_side = turn_left == large_arc; - let delta = (p1 - p0).scale(0.5); - let midpoint = p0 + delta; - - let radius_vec = if left_side { - Vector { - x: -delta.y, - y: delta.x, - } - } else { - Vector { - x: delta.y, - y: -delta.x, - } - }; - - let len_squared = radius_vec.x * radius_vec.x + radius_vec.y * radius_vec.y; - if (len_squared - 0.03 > radius * radius) || radius < 0.0 { - radius = len_squared.sqrt(); - } - - let to_center = radius_vec.scale(f64::max(0.0, radius * radius / len_squared - 1.0).sqrt()); - let center = midpoint + to_center; - let angle = len_squared.sqrt().clamp(-1.0, 1.0).asin() * 2.0; - let arc = if large_arc { - std::f64::consts::TAU - angle - } else { - angle - }; - - let position = p0 - center; - for i in 0..CIRCLE_POLY_COUNT { - let arc = if turn_left { -arc } else { arc }; - let step_matrix = rotation_matrix(i as f64 * arc / CIRCLE_POLY_COUNT as f64); - let point = center + apply_matrix(step_matrix, position); - self.points.push(point); - self.width.push(lerp_f64( - start_width, - end_width, - i as f64 / CIRCLE_POLY_COUNT as f64, - )); - } - - self.points.push(p1); - } - - fn render_ellipse( - &mut self, - p0: Point, - p1: Point, - radius_x: f64, - radius_y: f64, - rotation: f64, - large_arc: bool, - turn_left: bool, - end_width: f64, - ) { - let radius_min = distance(p0, p1) / 2.0; - let radius_max = (radius_x * radius_x + radius_y * radius_y).sqrt(); - let upscale = if radius_max < radius_min { - radius_min / radius_max - } else { - 1.0 - }; - - let ratio = radius_x / radius_y; - let rotation = rotation_matrix(-rotation.to_radians()); - let transform = [ - [rotation[0][0] / upscale, rotation[0][1] / upscale], - [ - rotation[1][0] / upscale * ratio, - rotation[1][1] / upscale * ratio, - ], - ]; - let transform_back = [ - [rotation[1][1] * upscale, -rotation[0][1] / ratio * upscale], - [-rotation[1][0] * upscale, rotation[0][0] / ratio * upscale], - ]; - - let mut tmp = PathMaker::default(); - tmp.render_circle( - apply_matrix_point(transform, p0), - apply_matrix_point(transform, p1), - radius_x * upscale, - large_arc, - turn_left, - end_width, - ); - - for i in 0..tmp.points.len() { - let point = tmp.points[i]; - self.points.push(apply_matrix_point(transform_back, point)); - self.width.push(tmp.width[i]); - } - } - - fn close(&mut self, width: f64) { - self.points.push(self.points[0]); - self.width.push(width) - } -} - -fn render_path(path: Path, width: f64) { - for segment in path.segments.iter() { - let mut path_maker = PathMaker::new(width, segment.start); - for instruction in segment.instructions.iter() { - let line_width = instruction - .line_width - .unwrap_or(*path_maker.width.last().unwrap()); - let data = instruction.data; - match data { - InstructionData::Line { position } => path_maker.render_line(line_width, position), - InstructionData::HorizontalLine { x } => { - path_maker.render_horizontal_line(line_width, x) - } - InstructionData::VerticalLine { y } => { - path_maker.render_vertical_line(line_width, y) - } - InstructionData::CubicBezier { - control_0, - control_1, - point_1, - } => path_maker.render_cubic_bezier( - control_0, - control_1, - point_1, - *path_maker.width.last().unwrap(), - line_width, - ), - InstructionData::ArcCircle { - large_arc, - sweep, - radius, - target, - } => path_maker.render_circle( - *path_maker.points.last().unwrap(), - target, - radius, - large_arc, - sweep == Sweep::Left, - line_width, - ), - InstructionData::ArcEllipse { - large_arc, - sweep, - radius_x, - radius_y, - rotation, - target, - } => path_maker.render_ellipse( - *path_maker.points.last().unwrap(), - target, - radius_x, - radius_y, - rotation, - large_arc, - sweep == Sweep::Left, - line_width, - ), - InstructionData::ClosePath => path_maker.close(line_width), - InstructionData::QuadraticBezier { control, target } => path_maker - .render_quadratic_bezier( - control, - target, - *path_maker.width.last().unwrap(), - line_width, - ), - } - } - } -} - -pub enum AntiAliasing { - X1 = 1, - X4 = 2, - X9 = 3, - X16 = 4, - X25 = 6, - X49 = 7, - X64 = 8, -} - -pub fn render<C: Color + Clone + Default>( - file: &TvgFile<C>, - width: u32, - height: u32, - scale_x: f32, - scale_y: f32, - anti_alias: AntiAliasing, -) { - let mut framebuffer: FrameBuffer<C> = FrameBuffer::new( - width as usize, - height as usize, - scale_x.into(), - scale_y.into(), - ); - let header = &file.header; - let color_table = &file.color_table; - - for command in file.commands.iter() { - match command { - Command::EndOfDocument => break, - Command::FillPolygon { - fill_style, - polygon, - } => { - todo!() - } - Command::FillRectangles { - fill_style, - rectangles, - } => todo!(), - Command::FillPath { fill_style, path } => todo!(), - Command::DrawLines { - line_style, - line_width, - lines, - } => todo!(), - Command::DrawLineLoop { - line_style, - line_width, - points, - } => todo!(), - Command::DrawLineStrip { - line_style, - line_width, - points, - } => todo!(), - Command::DrawLinePath { - line_style, - line_width, - path, - } => todo!(), - Command::OutlineFillPolygon { - fill_style, - line_style, - line_width, - points, - } => todo!(), - Command::OutlineFillRectangles { - fill_style, - line_style, - line_width, - rectangles, - } => todo!(), - Command::OutlineFillPath { - fill_style, - line_style, - line_width, - path, - } => todo!(), - } - } -} |
