From e5c6534c28903403d390961d93ddf6023b1e807f Mon Sep 17 00:00:00 2001 From: Hiroaki Yutani Date: Sun, 27 Oct 2024 21:05:09 +0900 Subject: [PATCH] Remove active pattern --- src/rust/src/vello_device/default.rs | 25 ++++-- src/rust/src/vello_device/mod.rs | 13 +++- src/rust/vellogd-shared/src/protocol.rs | 34 ++++++-- src/rust/vellogd-shared/src/winit_app/mod.rs | 82 ++++++++++++-------- 4 files changed, 106 insertions(+), 48 deletions(-) diff --git a/src/rust/src/vello_device/default.rs b/src/rust/src/vello_device/default.rs index e411fff..0ffc4e4 100644 --- a/src/rust/src/vello_device/default.rs +++ b/src/rust/src/vello_device/default.rs @@ -303,6 +303,7 @@ impl DeviceDriver for VelloGraphicsDevice { raster, pixels.0 as usize, pixels.1 as usize, + peniko::Extend::Pad, alpha, with_extended_edge, ); @@ -374,9 +375,10 @@ impl DeviceDriver for VelloGraphicsDevice { // Note: with_stops doesn't accept &[ColorStop] or ColorStops. Why? gradient.stops = color_stops; - VELLO_APP_PROXY + let index = VELLO_APP_PROXY .scene - .set_pattern(FillPattern::Gradient(gradient)); + .register_pattern(FillPattern::Gradient(gradient)); + Rf_ScalarInteger(index as i32) }, 2 => unsafe { let cx1 = R_GE_radialGradientCX1(pattern); @@ -406,9 +408,11 @@ impl DeviceDriver for VelloGraphicsDevice { .with_extend(extend); // Note: with_stops doesn't accept &[ColorStop] or ColorStops. Why? gradient.stops = color_stops; - VELLO_APP_PROXY + + let index = VELLO_APP_PROXY .scene - .set_pattern(FillPattern::Gradient(gradient)); + .register_pattern(FillPattern::Gradient(gradient)); + Rf_ScalarInteger(index as i32) }, 3 => unsafe { let x = R_GE_tilingPatternX(pattern); @@ -442,7 +446,8 @@ impl DeviceDriver for VelloGraphicsDevice { Rf_eval(call, R_GlobalEnv); Rf_unprotect(1); - self.request_register_tile().unwrap(); + self.request_register_tile(x as f32, y as f32, extend) + .unwrap(); let index = VELLO_APP_PROXY.rx.lock().unwrap().recv().unwrap(); // TODO: use tile and set active pattern @@ -453,11 +458,15 @@ impl DeviceDriver for VelloGraphicsDevice { VELLO_APP_PROXY .stop_rendering .store(false, Ordering::Relaxed); + + if let Response::PatternRegistered { index } = index { + Rf_ScalarInteger(index as i32) + } else { + R_NilValue + } }, - _ => {} + _ => unsafe { R_NilValue }, } - - unsafe { R_NilValue } } fn release_pattern(&mut self, _ref: SEXP, _: DevDesc) { diff --git a/src/rust/src/vello_device/mod.rs b/src/rust/src/vello_device/mod.rs index 4d21137..83901eb 100644 --- a/src/rust/src/vello_device/mod.rs +++ b/src/rust/src/vello_device/mod.rs @@ -99,7 +99,16 @@ pub trait WindowController { }) } - fn request_register_tile(&self) -> savvy::Result<()> { - self.send_event(Request::SaveAsTile) + fn request_register_tile( + &self, + x_offset: f32, + y_offset: f32, + extend: peniko::Extend, + ) -> savvy::Result<()> { + self.send_event(Request::SaveAsTile { + x_offset, + y_offset, + extend, + }) } } diff --git a/src/rust/vellogd-shared/src/protocol.rs b/src/rust/vellogd-shared/src/protocol.rs index 431cd2f..83ad6dc 100644 --- a/src/rust/vellogd-shared/src/protocol.rs +++ b/src/rust/vellogd-shared/src/protocol.rs @@ -1,9 +1,17 @@ -use crate::ffi::R_GE_gcontext; +use crate::ffi::{R_GE_gcontext, R_NilValue, INTEGER}; use serde::{Deserialize, Serialize}; +#[derive(Debug, Clone, Deserialize, Serialize)] +pub enum FillBrush { + /// color + Color(peniko::Color), + /// index of the registered pattern + PatternRef(u32), +} + #[derive(Debug, Clone, Deserialize, Serialize)] pub struct FillParams { - pub color: peniko::Color, + pub brush: FillBrush, pub use_nonzero_rule: bool, } @@ -61,7 +69,11 @@ pub enum Request { PrepareForSaveAsTile { height: u32, }, - SaveAsTile, + SaveAsTile { + x_offset: f32, + y_offset: f32, + extend: peniko::Extend, + }, SetBaseColor { color: u32, @@ -110,7 +122,7 @@ pub enum Request { pub enum Response { WindowSizes { width: u32, height: u32 }, Connect { server_name: String }, - TileRegistered { index: usize }, + PatternRegistered { index: usize }, } pub trait AppResponseRelay { @@ -206,10 +218,18 @@ impl FillParams { if gc.fill == 0 { return None; } - let [r, g, b, a] = gc.fill.to_ne_bytes(); - let color = peniko::Color::rgba8(r, g, b, a); + + let brush = if unsafe { gc.patternFill != R_NilValue } { + let index = unsafe { *INTEGER(gc.patternFill) }; + FillBrush::PatternRef(index as u32) + } else { + let [r, g, b, a] = gc.fill.to_ne_bytes(); + let color = peniko::Color::rgba8(r, g, b, a); + FillBrush::Color(color) + }; + Some(Self { - color, + brush, use_nonzero_rule, }) } diff --git a/src/rust/vellogd-shared/src/winit_app/mod.rs b/src/rust/vellogd-shared/src/winit_app/mod.rs index a0a2cbb..4e4e4fb 100644 --- a/src/rust/vellogd-shared/src/winit_app/mod.rs +++ b/src/rust/vellogd-shared/src/winit_app/mod.rs @@ -27,7 +27,9 @@ use winit::{ }; use crate::{ - protocol::{AppResponseRelay, FillParams, GlyphParams, Request, Response, StrokeParams}, + protocol::{ + AppResponseRelay, FillBrush, FillParams, GlyphParams, Request, Response, StrokeParams, + }, text_layouter::{fontface_to_weight_and_style, TextLayouter}, }; @@ -45,7 +47,7 @@ pub enum RenderState<'a> { #[derive(Debug)] pub enum FillPattern { Gradient(peniko::Gradient), - Tiling, // TODO + Tiling(peniko::Image), // TODO } #[derive(Clone)] @@ -57,7 +59,7 @@ pub struct SceneDrawer { /// tile pattern). edited_scene: Arc>, - tiles: Arc>>, + patterns: Arc>>, // This is a bit tricky. Scene doesn't need to know the window size, but, // since R requires a flipped Y-axis, SceneDrawer needs to know how to flip, @@ -69,8 +71,6 @@ pub struct SceneDrawer { y_transform: Arc>, window_height: Arc, - active_pattern: Arc>>, - needs_redraw: Arc, } @@ -84,10 +84,9 @@ impl SceneDrawer { Self { on_screen_scene: scene.clone(), edited_scene: scene, - tiles: Arc::new(Mutex::new(Vec::new())), + patterns: Arc::new(Mutex::new(Vec::new())), y_transform, window_height, - active_pattern: Arc::new(Mutex::new(None)), needs_redraw, } } @@ -121,20 +120,27 @@ impl SceneDrawer { fn draw_fill_inner( &self, fill_rule: peniko::Fill, - color: peniko::Color, + brush: FillBrush, shape: &impl kurbo::Shape, ) { let scene = &mut self.edited_scene.lock().unwrap(); let y_transform = *self.y_transform.lock().unwrap(); - let fill_pattern = self.active_pattern.lock().unwrap(); - let brush: peniko::BrushRef = match fill_pattern.as_ref() { - Some(ptn) => match ptn { - FillPattern::Gradient(gradient) => gradient.into(), - FillPattern::Tiling => todo!(), - }, - None => color.into(), + match brush { + FillBrush::Color(color) => { + scene.fill(fill_rule, y_transform, color, None, shape); + } + FillBrush::PatternRef(index) => { + let patterns = self.patterns.lock().unwrap(); + match patterns.get(index as usize).unwrap() { + FillPattern::Gradient(gradient) => { + scene.fill(fill_rule, y_transform, gradient, None, shape); + } + FillPattern::Tiling(image) => { + scene.fill(fill_rule, y_transform, image, None, shape); + } + } + } }; - scene.fill(fill_rule, y_transform, brush, None, shape); } pub fn draw_circle( @@ -147,7 +153,7 @@ impl SceneDrawer { let circle = vello::kurbo::Circle::new(center, radius); if let Some(fill_params) = fill_params { - self.draw_fill_inner(peniko::Fill::NonZero, fill_params.color, &circle); + self.draw_fill_inner(peniko::Fill::NonZero, fill_params.brush, &circle); } if let Some(stroke_params) = stroke_params { @@ -180,7 +186,7 @@ impl SceneDrawer { } else { peniko::Fill::EvenOdd }; - self.draw_fill_inner(style, fill_params.color, &path); + self.draw_fill_inner(style, fill_params.brush, &path); } if let Some(stroke_params) = stroke_params { @@ -200,7 +206,7 @@ impl SceneDrawer { let rect = vello::kurbo::Rect::new(p0.x, p0.y, p1.x, p1.y); if let Some(fill_params) = fill_params { - self.draw_fill_inner(peniko::Fill::NonZero, fill_params.color, &rect); + self.draw_fill_inner(peniko::Fill::NonZero, fill_params.brush, &rect); } if let Some(stroke_params) = stroke_params { @@ -352,12 +358,15 @@ impl SceneDrawer { scene.pop_layer(); } - pub fn set_pattern(&self, pattern: FillPattern) { - self.active_pattern.lock().unwrap().replace(pattern); + pub fn register_pattern(&self, pattern: FillPattern) -> usize { + let mut patterns = self.patterns.lock().unwrap(); + patterns.push(pattern); + + patterns.len() - 1 // index } pub fn release_pattern(&self) { - self.active_pattern.lock().unwrap().take(); + // TODO } } @@ -369,6 +378,7 @@ pub fn convert_to_image( raster: &[u8], width: usize, height: usize, + extend: peniko::Extend, alpha: u8, with_extended_edge: bool, ) -> peniko::Image { @@ -398,7 +408,7 @@ pub fn convert_to_image( format: peniko::Format::Rgba8, width, height, - extend: peniko::Extend::Pad, + extend, alpha, } } @@ -754,7 +764,11 @@ impl<'a, T: AppResponseRelay> ApplicationHandler for VelloApp<'a, T> { // *self.scene.edited_scene.lock().unwrap() = Scene::new() } - Request::SaveAsTile => { + Request::SaveAsTile { + x_offset: _, // TODO + y_offset: _, // TODO + extend, + } => { let width = self.width.load(Ordering::Relaxed); let height = self.height.load(Ordering::Relaxed); @@ -763,13 +777,19 @@ impl<'a, T: AppResponseRelay> ApplicationHandler for VelloApp<'a, T> { // register to tiles - let image = - convert_to_image(&data, width as usize, height as usize, u8::MAX, false); - let mut tiles = self.scene.tiles.lock().unwrap(); - tiles.push(image); - let index = tiles.len() - 1; - - self.tx.respond(Response::TileRegistered { index }); + let image = convert_to_image( + &data, + width as usize, + height as usize, + extend, + u8::MAX, + false, + ); + let mut patterns = self.scene.patterns.lock().unwrap(); + patterns.push(FillPattern::Tiling(image)); + let index = patterns.len() - 1; + + self.tx.respond(Response::PatternRegistered { index }); } // ignore other events