From: Joshua Simmons Date: Thu, 20 Apr 2023 20:28:24 +0000 (+0200) Subject: core: Add svg debug output helper X-Git-Url: https://git.nega.tv//gitweb.cgi?a=commitdiff_plain;h=3777e9db1848c04f85c5a5bd40d6ebbc50e4592e;p=josh%2Fnarcissus core: Add svg debug output helper --- diff --git a/libs/narcissus-core/src/lib.rs b/libs/narcissus-core/src/lib.rs index 29a194c..1c03933 100644 --- a/libs/narcissus-core/src/lib.rs +++ b/libs/narcissus-core/src/lib.rs @@ -11,6 +11,7 @@ pub mod rand; pub mod raw_window; mod ref_count; pub mod slice; +pub mod svg; mod uuid; mod virtual_mem; mod virtual_vec; diff --git a/libs/narcissus-core/src/svg.rs b/libs/narcissus-core/src/svg.rs new file mode 100644 index 0000000..6fdba40 --- /dev/null +++ b/libs/narcissus-core/src/svg.rs @@ -0,0 +1,379 @@ +use std::fmt; + +pub const fn rgb(r: u8, g: u8, b: u8) -> Color { + Color::Rgb(Rgb { r, g, b }) +} + +pub const fn hsl(h: u32, s: u32, l: u32) -> Color { + Color::Hsl(Hsl { h, s, l }) +} + +pub const fn black() -> Color { + rgb(0, 0, 0) +} + +pub const fn white() -> Color { + rgb(255, 255, 255) +} + +pub const fn red() -> Color { + rgb(255, 0, 0) +} + +pub const fn green() -> Color { + rgb(0, 255, 0) +} + +pub const fn blue() -> Color { + rgb(0, 0, 255) +} + +pub const fn fill(color: Color, alpha: f32) -> Fill { + Fill::Color(color, alpha) +} + +pub const fn stroke(color: Color, width: f32, alpha: f32) -> Stroke { + Stroke::Color(color, width, alpha) +} + +pub fn svg_begin(w: f32, h: f32) -> SvgBegin { + SvgBegin { w, h } +} + +pub fn svg_end() -> SvgEnd { + SvgEnd +} + +pub fn rect(x: f32, y: f32, w: f32, h: f32) -> Rect { + Rect { + x, + y, + w, + h, + style: Default::default(), + border_radius: 0.0, + } +} + +pub fn circle(x: f32, y: f32, r: f32) -> Circle { + Circle { + x, + y, + r, + style: Default::default(), + } +} + +pub fn path_begin() -> PathBegin { + PathBegin { + style: Default::default(), + } +} + +pub fn path_end() -> PathEnd { + PathEnd +} + +pub fn path_move_to(x: f32, y: f32) -> PathOp { + PathOp::MoveTo { x, y } +} + +pub fn path_line_to(x: f32, y: f32) -> PathOp { + PathOp::MoveTo { x, y } +} + +pub fn path_quadratic(x1: f32, y1: f32, x: f32, y: f32) -> PathOp { + PathOp::QuadraticTo { x1, y1, x, y } +} + +pub fn path_cubic(x1: f32, y1: f32, x2: f32, y2: f32, x: f32, y: f32) -> PathOp { + PathOp::CubicTo { + x1, + y1, + x2, + y2, + x, + y, + } +} + +pub fn path_close() -> PathOp { + PathOp::Close +} + +#[derive(Copy, Clone, PartialEq, Eq)] +pub struct Rgb { + pub r: u8, + pub g: u8, + pub b: u8, +} + +impl fmt::Display for Rgb { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "rgb({}, {}, {})", self.r, self.g, self.b) + } +} + +#[derive(Copy, Clone, PartialEq, Eq)] +pub struct Hsl { + pub h: u32, + pub s: u32, + pub l: u32, +} + +impl fmt::Display for Hsl { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let h = self.h % 360; + let s = self.s.min(100); + let l = self.s.min(100); + write!(f, "hsl({h}, {s}%, {l}%)") + } +} + +#[derive(Copy, Clone, PartialEq, Eq)] +pub enum Color { + Hsl(Hsl), + Rgb(Rgb), +} + +impl fmt::Display for Color { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Color::Hsl(hsl) => write!(f, "{hsl}"), + Color::Rgb(rgb) => write!(f, "{rgb}"), + } + } +} + +#[derive(Copy, Clone, PartialEq)] +pub enum Fill { + None, + Color(Color, f32), +} + +impl fmt::Display for Fill { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Fill::None => write!(f, "fill:none;"), + Fill::Color(color, opacity) => write!(f, "fill:{color};fill-opacity:{opacity};"), + } + } +} + +#[derive(Copy, Clone, PartialEq)] +pub enum Stroke { + None, + Color(Color, f32, f32), +} + +impl fmt::Display for Stroke { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Stroke::None => write!(f, "stroke:none"), + Stroke::Color(color, opacity, width) => write!( + f, + "stroke:{color};stroke-opacity:{opacity};stroke-width:{width}" + ), + } + } +} + +#[derive(Copy, Clone, PartialEq)] +pub struct Style { + fill: Fill, + stroke: Stroke, +} + +impl Default for Style { + fn default() -> Self { + Self { + fill: fill(black(), 1.0), + stroke: Stroke::None, + } + } +} + +impl fmt::Display for Style { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}{}", self.fill, self.stroke) + } +} + +#[derive(Copy, Clone, PartialEq)] +pub struct Rect { + pub x: f32, + pub y: f32, + pub w: f32, + pub h: f32, + pub style: Style, + pub border_radius: f32, +} + +impl Rect { + pub fn style(mut self, style: Style) -> Self { + self.style = style; + self + } + + pub fn border_radius(mut self, border_radius: f32) -> Self { + self.border_radius = border_radius; + self + } +} + +impl fmt::Display for Rect { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + r#"""#, + self.x, self.y, self.w, self.h, self.border_radius, self.style + ) + } +} + +#[derive(Copy, Clone, PartialEq)] +pub struct Circle { + pub x: f32, + pub y: f32, + pub r: f32, + pub style: Style, +} + +impl Circle { + pub fn style(mut self, style: Style) -> Self { + self.style = style; + self + } +} + +impl fmt::Display for Circle { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + r#"""#, + self.x, self.y, self.r, self.style, + ) + } +} + +#[derive(Copy, Clone, PartialEq)] +pub struct PathBegin { + style: Style, +} + +impl PathBegin { + pub fn style(mut self, style: Style) -> Self { + self.style = style; + self + } +} + +impl fmt::Display for PathBegin { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, r#") -> fmt::Result { + match self { + PathOp::MoveTo { x, y } => write!(f, "M {x} {y} "), + PathOp::LineTo { x, y } => write!(f, "L {x} {y} "), + PathOp::QuadraticTo { x1, y1, x, y } => write!(f, "Q {x1} {y1} {x} {y} "), + PathOp::CubicTo { + x1, + y1, + x2, + y2, + x, + y, + } => write!(f, "C {x1} {y1} {x2} {y2} {x} {y} "), + PathOp::Close => write!(f, "Z "), + } + } +} + +#[derive(Copy, Clone, PartialEq)] +pub struct PathEnd; + +impl fmt::Display for PathEnd { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, r#"" />"#) + } +} + +pub struct Text<'a, T> +where + T: fmt::Display, +{ + pub x: f32, + pub y: f32, + pub size: f32, + pub style: Style, + pub text: &'a T, +} + +impl<'a, T> fmt::Display for Text<'a, T> +where + T: fmt::Display, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + r#"{}"#, + self.x, self.y, self.size, self.style, self.text + ) + } +} + +#[derive(Copy, Clone, PartialEq)] +pub struct SvgBegin { + pub w: f32, + pub h: f32, +} + +impl fmt::Display for SvgBegin { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + r#""#, + self.w, self.h, + ) + } +} + +#[derive(Copy, Clone)] +pub struct SvgEnd; + +impl fmt::Display for SvgEnd { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "") + } +}