diff --git a/src/base.rs b/src/base.rs index 11eae31..badace1 100644 --- a/src/base.rs +++ b/src/base.rs @@ -22,6 +22,8 @@ pub trait Sketch { self.fill_rect(x, y, 1.0, 1.0, &tex); } fn save>(&self, path: P); + fn width(&self) -> u32; + fn height(&self) -> u32; } /// Unified color format for wassily, formats from external crates e.g. image-rs, tiny-skia, diff --git a/src/grain.rs b/src/grain.rs index 56a8a03..b368382 100644 --- a/src/grain.rs +++ b/src/grain.rs @@ -2,43 +2,19 @@ use crate::base::{BlendMode, Sketch, Texture, RGBA}; use crate::quiet::{noise2d, NoiseOpts}; use noise::{Fbm, Perlin}; -pub struct Grain { - scale: f32, - factor: f32, - width: u32, - height: u32, -} - -impl Grain { - pub fn new(width: u32, height: u32) -> Self { - Self { - scale: 0.1, - factor: 0.1, - width, - height, - } - } - - pub fn set_scale(&mut self, scale: f32) { - self.scale = scale; - } - - pub fn set_factor(&mut self, factor: f32) { - self.factor = factor; - } - - pub fn apply(&self, canvas: &mut S) { - let noise_opts = NoiseOpts::default().scales(self.scale).factor(self.factor); - let nf = Fbm::::default(); - for i in 0..self.width { - for j in 0..self.height { - let n = noise2d(&nf, &noise_opts, i as f32, j as f32); - let n1 = (n + 1.0) / 2.0 * 255.0; - let c = RGBA::gray(n1 as u8); - let mut texture = Texture::solid_color(c); - texture.mode(BlendMode::Overlay); - canvas.fill_rect(i as f32, j as f32, 1.0, 1.0, &texture); - } +/// Add film grain to a canvas. 'scale' = 0.1 and 'factor' = 0.1 are good +/// defaults. +pub fn grain(canvas: &mut S, scale: f32, factor: f32) { + let noise_opts = NoiseOpts::default().scales(scale).factor(factor); + let nf = Fbm::::default(); + for i in 0..canvas.width() { + for j in 0..canvas.height() { + let n = noise2d(&nf, &noise_opts, i as f32, j as f32); + let n1 = (n + 1.0) / 2.0 * 255.0; + let c = RGBA::gray(n1 as u8); + let mut texture = Texture::solid_color(c); + texture.mode(BlendMode::Overlay); + canvas.fill_rect(i as f32, j as f32, 1.0, 1.0, &texture); } } -} +} \ No newline at end of file diff --git a/src/lines.rs b/src/lines.rs index 2c5e27d..d8c3bd2 100644 --- a/src/lines.rs +++ b/src/lines.rs @@ -1,6 +1,6 @@ use crate::base::*; -use crate::quiet::*; use crate::prelude::{vec2, Vector, BLACK}; +use crate::quiet::*; use crate::util::Rand; use noise::OpenSimplex; use rand::prelude::*; @@ -118,7 +118,14 @@ impl DotLine { } pub fn draw(&self, canvas: &mut T) { - let noise_opts = NoiseOpts::new(1200.0, 1200.0, 1.0, 1.0, 1.0, self.noise_strength); + let noise_opts = NoiseOpts::new( + canvas.width() as f32, + canvas.height() as f32, + 1.0, + 1.0, + 1.0, + self.noise_strength, + ); let nf = OpenSimplex::default(); let v: Vector = self.end - self.start; let n: Vector = vec2(v.y, -v.x).normalize(); // n . v == 0, n is the normal. diff --git a/src/raqote.rs b/src/raqote.rs index 31fb756..12da7c0 100644 --- a/src/raqote.rs +++ b/src/raqote.rs @@ -64,6 +64,14 @@ impl Sketch for Canvas { fn save>(&self, path: P) { self.0.write_png(path).unwrap(); } + + fn width(&self) -> u32 { + self.0.width() as u32 + } + + fn height(&self) -> u32 { + self.0.height() as u32 + } } impl From for SolidSource { diff --git a/src/skia.rs b/src/skia.rs index 1cd4e41..f66aea4 100644 --- a/src/skia.rs +++ b/src/skia.rs @@ -78,6 +78,14 @@ impl Sketch for Canvas { let c: skia::Color = color.into(); pixel_map[k] = c.premultiply().to_color_u8(); } + + fn width(&self) -> u32 { + self.0.width() + } + + fn height(&self) -> u32 { + self.0.height() + } } impl From<&RgbaImage> for Canvas { diff --git a/src/svg.rs b/src/svg.rs index 63715b3..0b73034 100644 --- a/src/svg.rs +++ b/src/svg.rs @@ -6,8 +6,12 @@ use svg::node::element::path::Data; use svg::Document; use num_traits::AsPrimitive; -// The usize is for gradient ids' -pub struct Canvas(pub Document, usize); +pub struct Canvas { + pub doc: Document, + width: u32, + height: u32, + grad_id: usize, +} impl Canvas { pub fn new>(width: T, height: T) -> Self { @@ -16,13 +20,13 @@ impl Canvas { .set("width", width.as_()) .set("height", height.as_()) .set("viewbox", (0, 0, width.as_(), height.as_())); - Canvas(doc, 0) + Canvas {doc, width: width.as_(), height: height.as_(),grad_id: 0} } } impl Sketch for Canvas { fn fill_path(&mut self, path: &base::Path, texture: &base::Texture) { - let doc = self.0.clone(); + let doc = self.doc.clone(); let svg_path: vg::Path = path.into(); let color = match texture.kind { base::TextureKind::SolidColor(c) => c.to_svg(), @@ -35,11 +39,11 @@ impl Sketch for Canvas { .set("transform", transform(path)) .set("fill-rule", fill_rule(path)); - self.0 = doc.add(svg_path); + self.doc = doc.add(svg_path); } fn stroke_path(&mut self, path: &base::Path, texture: &base::Texture, stroke: &base::Stroke) { - let doc = self.0.clone(); + let doc = self.doc.clone(); let svg_path: vg::Path = path.into(); let color = match texture.kind { base::TextureKind::SolidColor(c) => c.to_svg(), @@ -55,22 +59,22 @@ impl Sketch for Canvas { .set("stroke-linecap", linecap(stroke)) .set("stroke-linejoin", linejoin(stroke)) .set("transform", transform(path)); - self.0 = doc.add(svg_path); + self.doc = doc.add(svg_path); } fn fill(&mut self, color: base::RGBA) { - let doc = self.0.clone(); + let doc = self.doc.clone(); let color = color.to_svg(); let rect = vg::Rectangle::new() .set("width", "100%") .set("height", "100%") .set("fill", color.0) .set("fill-opacity", color.1); - self.0 = doc.add(rect); + self.doc = doc.add(rect); } fn fill_rect(&mut self, x: f32, y: f32, width: f32, height: f32, texture: &base::Texture) { - let doc = self.0.clone(); + let doc = self.doc.clone(); let color = match texture.kind { base::TextureKind::SolidColor(c) => c.to_svg(), base::TextureKind::LinearGradient(_) => {todo!()} @@ -82,11 +86,19 @@ impl Sketch for Canvas { .set("width", width) .set("height", height) .set("fill", color.0).set("fill-opacity", color.1); - self.0 = doc.add(rect); + self.doc = doc.add(rect); } fn save>(&self, path: P) { - svg::save(path, &self.0).unwrap(); + svg::save(path, &self.doc).unwrap(); + } + + fn width(&self) -> u32 { + self.width + } + + fn height(&self) -> u32 { + self.height } }