diff options
| author | Micha White <botahamec@outlook.com> | 2024-08-15 20:14:15 -0400 |
|---|---|---|
| committer | Micha White <botahamec@outlook.com> | 2024-08-15 20:14:15 -0400 |
| commit | f8a80039c74332e2101a177ef3fde31ef2077224 (patch) | |
| tree | f887c96bf9879a28b7ce914ad96161f63ee83190 /tvg/src/commands.rs | |
| parent | 488c7ed94b0662222fa0d825ab81b60b0b1e5d6c (diff) | |
Lots a changes
Diffstat (limited to 'tvg/src/commands.rs')
| -rw-r--r-- | tvg/src/commands.rs | 153 |
1 files changed, 148 insertions, 5 deletions
diff --git a/tvg/src/commands.rs b/tvg/src/commands.rs index f316a53..c21099b 100644 --- a/tvg/src/commands.rs +++ b/tvg/src/commands.rs @@ -1,24 +1,101 @@ use std::io::{self, Read}; +use std::ops::{Add, Mul, Sub}; use byteorder::ReadBytesExt; use raise::yeet; -use crate::{header::TvgHeader, path::Path, read_unit, read_varuint, Decode, Point, TvgError}; +use crate::{ + colors::{self, Color, ColorTable}, + header::TvgHeader, + path::Path, + read_unit, read_varuint, Decode, TvgError, +}; + +/// A X and Y coordinate pair. +#[derive(Debug, Clone, Copy)] +pub struct Vector { + /// Horizontal distance of the point to the origin. + pub x: f64, + /// Vertical distance of the point to the origin. + pub y: f64, +} + +impl Vector { + pub fn magnitude(&self) -> f64 { + (self.x * self.x + self.y * self.y).sqrt() + } + + pub fn scale(&self, scale: f64) -> Vector { + Vector { + x: self.x * scale, + y: self.y * scale, + } + } +} + +impl Mul for Vector { + type Output = f64; + + fn mul(self, rhs: Self) -> Self::Output { + self.x * rhs.x + self.y * rhs.y + } +} + +/// A X and Y coordinate pair. +#[derive(Debug, Clone, Copy)] +pub struct Point { + /// Horizontal distance of the point to the origin. + pub x: f64, + /// Vertical distance of the point to the origin. + pub y: f64, +} + +impl Sub for Point { + type Output = Vector; + + fn sub(self, rhs: Self) -> Self::Output { + Vector { + x: self.x - rhs.x, + y: self.y - rhs.y, + } + } +} + +impl Add<Vector> for Point { + type Output = Self; + + fn add(self, vector: Vector) -> Self::Output { + Self { + x: self.x + vector.x, + y: self.y + vector.y, + } + } +} + +impl Decode for Point { + fn read(reader: &mut impl Read, header: &TvgHeader) -> io::Result<Self> { + Ok(Self { + x: read_unit(reader, header)?, + y: read_unit(reader, header)?, + }) + } +} #[derive(Debug, Clone, Copy, PartialEq)] pub struct Rectangle { /// Horizontal distance of the left side to the origin. - x: f64, + pub x: f64, /// Vertical distance of the upper side to the origin. - y: f64, + pub y: f64, /// Horizontal extent of the rectangle. - width: f64, + pub width: f64, /// Vertical extent of the rectangle. - height: f64, + pub height: f64, } impl Decode for Rectangle { fn read(reader: &mut impl Read, header: &TvgHeader) -> io::Result<Self> { + let x = 5; Ok(Self { x: read_unit(reader, header)?, y: read_unit(reader, header)?, @@ -203,6 +280,72 @@ impl Style { color_index_1: read_varuint(reader)?, }) } + + fn linear_get_color_at<C: Color + Clone>( + &self, + color_table: &ColorTable<C>, + point: Point, + ) -> Option<C> { + let Self::LinearGradient { + point_0, + point_1, + color_index_0, + color_index_1 } = self else { panic!() }; + + // TODO remove these unwraps + let color_0 = color_table.get(*color_index_0 as usize)?; + let color_1 = color_table.get(*color_index_1 as usize)?; + + let direction = *point_1 - *point_0; + let delta = point - *point_0; + + if direction * delta <= 0.0 { + return Some(color_0.clone()); + } else if direction * (point - *point_1) >= 0.0 { + return Some(color_1.clone()); + } + + let gradient_length = direction.magnitude(); + let proj = (direction * delta) / (direction * direction); + let gradient_position = direction.scale(proj).magnitude(); + let f = gradient_position / gradient_length; + + Some(colors::lerp(color_0, color_1, f)) + } + + fn radial_get_color_at<C: Color>( + &self, + color_table: &ColorTable<C>, + point: Point, + ) -> Option<C> { + let Self::RadialGradient { + point_0, + point_1, + color_index_0, + color_index_1 } = self else { panic!() }; + + // TODO remove these unwraps + let color_0 = color_table.get(*color_index_0 as usize)?; + let color_1 = color_table.get(*color_index_1 as usize)?; + + let distance_max = (*point_1 - *point_0).magnitude(); + let distance_is = (point - *point_0).magnitude(); + let f = distance_is / distance_max; + + Some(colors::lerp(color_0, color_1, f)) + } + + pub fn get_color_at<C: Color + Clone>( + &self, + color_table: &ColorTable<C>, + point: Point, + ) -> Option<C> { + match self { + Self::FlatColored { color_index } => color_table.get(*color_index as usize).cloned(), + Self::LinearGradient { .. } => self.linear_get_color_at(color_table, point), + Self::RadialGradient { .. } => self.radial_get_color_at(color_table, point), + } + } } /// TinyVG files contain a sequence of draw commands that must be executed in |
