summaryrefslogtreecommitdiff
path: root/tvg/src/commands.rs
diff options
context:
space:
mode:
authorMicha White <botahamec@outlook.com>2024-08-15 20:14:15 -0400
committerMicha White <botahamec@outlook.com>2024-08-15 20:14:15 -0400
commitf8a80039c74332e2101a177ef3fde31ef2077224 (patch)
treef887c96bf9879a28b7ce914ad96161f63ee83190 /tvg/src/commands.rs
parent488c7ed94b0662222fa0d825ab81b60b0b1e5d6c (diff)
Lots a changes
Diffstat (limited to 'tvg/src/commands.rs')
-rw-r--r--tvg/src/commands.rs153
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