Skip to content

Commit

Permalink
Pattern (#23)
Browse files Browse the repository at this point in the history
  • Loading branch information
yutannihilation authored Oct 26, 2024
1 parent 995600a commit 50263cd
Show file tree
Hide file tree
Showing 7 changed files with 286 additions and 94 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,8 @@ cf. <https://github.com/r-devel/r-svn/blob/main/src/include/R_ext/GraphicsDevice
| `clip` || TODO: server version, can I hide the clipping rectangle? |
| `cap` | | |
| `eventHelper` | | |
| `setPattern` | | |
| `releasePattern` | | |
| `setPattern` | | |
| `releasePattern` | | |
| `setClipPath` | | |
| `releaseClipPath` | | |
| `setMask` | | |
Expand Down
109 changes: 91 additions & 18 deletions src/rust/src/debug_device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@ use std::os::raw::c_uint;
use crate::add_tracing_point;
use crate::graphics::DeviceDriver;

use vellogd_shared::ffi::DevDesc;
use vellogd_shared::ffi::R_GE_gcontext;
use vellogd_shared::ffi::R_NilValue;
use vellogd_shared::ffi::*;
use vellogd_shared::text_layouter::TextMetric;

#[cfg(debug_assertions)]
Expand Down Expand Up @@ -137,9 +135,13 @@ impl DeviceDriver for DebugGraphicsDevice {
savvy::r_eprintln!("[polyline] x: {} y: {}", take3(x), take3(y));
}

fn rect(&mut self, from: (f64, f64), to: (f64, f64), _: R_GE_gcontext, _: DevDesc) {
fn rect(&mut self, from: (f64, f64), to: (f64, f64), gc: R_GE_gcontext, _: DevDesc) {
add_tracing_point!();
savvy::r_eprintln!("[rect] from: {from:?} to: {to:?}");
if unsafe { gc.patternFill != R_NilValue } {
let fill = unsafe { *INTEGER(gc.patternFill) };
savvy::r_eprintln!(" fill: {fill}")
}
}

fn path(
Expand Down Expand Up @@ -170,9 +172,9 @@ impl DeviceDriver for DebugGraphicsDevice {

savvy::r_eprintln!(
"[raster]
pixels: {pixels:?}
pos: {pos:?}
size: {size:?}"
pixels: {pixels:?}
pos: {pos:?}
size: {size:?}"
);
}

Expand Down Expand Up @@ -232,21 +234,92 @@ impl DeviceDriver for DebugGraphicsDevice {
let fontfile = std::fs::canonicalize(fontfile);
savvy::r_eprintln!(
"[glyph]
glyphs: {glyphs:?}
x: {x:?}
y: {y:?}
fontfile: {fontfile:?}
index: {index}
family: {family}
weight: {weight}
style: {style}
angle: {angle}
size: {size}
colour: {colour}
glyphs: {glyphs:?}
x: {x:?}
y: {y:?}
fontfile: {fontfile:?}
index: {index}
family: {family}
weight: {weight}
style: {style}
angle: {angle}
size: {size}
colour: {colour}
"
);
}

fn set_pattern(&mut self, pattern: SEXP, _: DevDesc) -> SEXP {
unsafe {
if pattern == R_NilValue {
return Rf_ScalarInteger(-1);
}
}

match unsafe { R_GE_patternType(pattern) } {
1 => unsafe {
let x1 = R_GE_linearGradientX1(pattern);
let y1 = R_GE_linearGradientY1(pattern);
let x2 = R_GE_linearGradientX2(pattern);
let y2 = R_GE_linearGradientY2(pattern);
let extend = R_GE_linearGradientExtend(pattern);
savvy::r_eprintln!(
"[setPattern]
from: ({x1}, {y1})
to: ({x2}, {y2})
extend: {extend}"
);

let num_stops = R_GE_linearGradientNumStops(pattern);
savvy::r_eprintln!(" stops:");

for i in 0..num_stops {
let stop = R_GE_linearGradientStop(pattern, i);
let color = R_GE_linearGradientColour(pattern, i);
savvy::r_eprintln!(" {i}: {stop},{color:08x}");
}
},
2 => unsafe {
let cx1 = R_GE_radialGradientCX1(pattern);
let cy1 = R_GE_radialGradientCY1(pattern);
let r1 = R_GE_radialGradientR1(pattern);
let cx2 = R_GE_radialGradientCX2(pattern);
let cy2 = R_GE_radialGradientCY2(pattern);
let r2 = R_GE_radialGradientR2(pattern);
let extend = R_GE_radialGradientExtend(pattern);
savvy::r_eprintln!(
"[setPattern]
from: ({cx1}, {cy1}), r: {r1}
to: ({cx2}, {cy2}), r: {r2}
extend: {extend}"
);

let num_stops = R_GE_radialGradientNumStops(pattern);
savvy::r_eprintln!(" stops:");

for i in 0..num_stops {
let stop = R_GE_radialGradientStop(pattern, i);
let color = R_GE_radialGradientColour(pattern, i);
savvy::r_eprintln!(" {i}: {stop},{color:08x}");
}
},
3 => {} // tiling
_ => {}
}

unsafe { R_NilValue }
}

fn release_pattern(&mut self, ref_: SEXP, _: DevDesc) {
savvy::r_eprintln!("[releasePattern]");

unsafe {
if ref_ != R_NilValue {
savvy::r_eprintln!(" index: {}", *INTEGER(ref_));
}
}
}

fn on_exit(&mut self, _: DevDesc) {
add_tracing_point!();
savvy::r_eprintln!("[on_exit]");
Expand Down
13 changes: 8 additions & 5 deletions src/rust/src/graphics/device_driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,12 @@ pub trait DeviceDriver: std::marker::Sized {
) {
}

fn set_pattern(&mut self, pattern: SEXP, dd: DevDesc) -> SEXP {
unsafe { R_NilValue }
}

fn release_pattern(&mut self, pattern: SEXP, dd: DevDesc) {}

/// A callback function called when the user aborts some operation. It seems
/// this is rarely implemented.
fn on_exit(&mut self, dd: DevDesc) {}
Expand Down Expand Up @@ -632,18 +638,15 @@ pub trait DeviceDriver: std::marker::Sized {
dd: pDevDesc,
) -> SEXP {
let data = ((*dd).deviceSpecific as *mut T).as_mut().unwrap();
// TODO
// data.setPattern(pattern, *dd)
R_NilValue
data.set_pattern(pattern, *dd)
}

unsafe extern "C" fn device_driver_releasePattern<T: DeviceDriver>(
ref_: SEXP,
dd: pDevDesc,
) {
let data = ((*dd).deviceSpecific as *mut T).as_mut().unwrap();
// TODO
// data.reelasePattern(ref_, *dd);
data.release_pattern(ref_, *dd);
}

unsafe extern "C" fn device_driver_setClipPath<T: DeviceDriver>(
Expand Down
87 changes: 85 additions & 2 deletions src/rust/src/vello_device/default.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ use super::WindowController;
use crate::add_tracing_point;
use crate::graphics::DeviceDriver;
use crate::vello_device::xy_to_path_with_hole;
use vellogd_shared::ffi::DevDesc;
use vellogd_shared::ffi::R_GE_gcontext;
use vellogd_shared::ffi::*;
use vellogd_shared::protocol::FillParams;
use vellogd_shared::protocol::GlyphParams;
use vellogd_shared::protocol::Request;
Expand All @@ -17,6 +16,7 @@ use vellogd_shared::text_layouter::fontface_to_weight_and_style;
use vellogd_shared::text_layouter::TextLayouter;
use vellogd_shared::text_layouter::TextMetric;
use vellogd_shared::winit_app::convert_to_image;
use vellogd_shared::winit_app::FillPattern;
use vellogd_shared::winit_app::VELLO_APP_PROXY;

pub struct VelloGraphicsDevice {
Expand Down Expand Up @@ -339,6 +339,89 @@ impl DeviceDriver for VelloGraphicsDevice {
self.get_text_width(text, gc)
}

fn set_pattern(&mut self, pattern: SEXP, _: DevDesc) -> SEXP {
unsafe {
if pattern == R_NilValue {
return Rf_ScalarInteger(-1);
}
}

match unsafe { R_GE_patternType(pattern) } {
1 => unsafe {
let x1 = R_GE_linearGradientX1(pattern);
let y1 = R_GE_linearGradientY1(pattern);
let x2 = R_GE_linearGradientX2(pattern);
let y2 = R_GE_linearGradientY2(pattern);
let extend = match R_GE_linearGradientExtend(pattern) {
1 => peniko::Extend::Pad, // R_GE_patternExtendPad
2 => peniko::Extend::Repeat, // R_GE_patternExtendRepeat
3 => peniko::Extend::Reflect, // R_GE_patternExtendReflect
_ => peniko::Extend::Pad, // TODO: what should I do when R_GE_patternExtendNone?
};

let num_stops = R_GE_linearGradientNumStops(pattern);

let color_stops_iter = (0..num_stops).map(|i| {
let offset = R_GE_linearGradientStop(pattern, i) as f32;
let [r, g, b, a] = R_GE_linearGradientColour(pattern, i).to_ne_bytes();
let color = peniko::Color::rgba8(r, g, b, a);
peniko::ColorStop { offset, color }
});
let color_stops = peniko::ColorStops::from_iter(color_stops_iter);

let mut gradient =
peniko::Gradient::new_linear((x1, y1), (x2, y2)).with_extend(extend);
// Note: with_stops doesn't accept &[ColorStop] or ColorStops. Why?
gradient.stops = color_stops;

VELLO_APP_PROXY
.scene
.set_pattern(FillPattern::Gradient(gradient));
},
2 => unsafe {
let cx1 = R_GE_radialGradientCX1(pattern);
let cy1 = R_GE_radialGradientCY1(pattern);
let r1 = R_GE_radialGradientR1(pattern) as f32;
let cx2 = R_GE_radialGradientCX2(pattern);
let cy2 = R_GE_radialGradientCY2(pattern);
let r2 = R_GE_radialGradientR2(pattern) as f32;
let extend = match R_GE_radialGradientExtend(pattern) {
1 => peniko::Extend::Pad, // R_GE_patternExtendPad
2 => peniko::Extend::Repeat, // R_GE_patternExtendRepeat
3 => peniko::Extend::Reflect, // R_GE_patternExtendReflect
_ => peniko::Extend::Pad, // TODO: what should I do when R_GE_patternExtendNone?
};

let num_stops = R_GE_radialGradientNumStops(pattern);

let color_stops_iter = (0..num_stops).map(|i| {
let offset = R_GE_radialGradientStop(pattern, i) as f32;
let [r, g, b, a] = R_GE_radialGradientColour(pattern, i).to_ne_bytes();
let color = peniko::Color::rgba8(r, g, b, a);
peniko::ColorStop { offset, color }
});
let color_stops = peniko::ColorStops::from_iter(color_stops_iter);
let mut gradient =
peniko::Gradient::new_two_point_radial((cx1, cy1), r1, (cx2, cy2), r2)
.with_extend(extend);
// Note: with_stops doesn't accept &[ColorStop] or ColorStops. Why?
gradient.stops = color_stops;
VELLO_APP_PROXY
.scene
.set_pattern(FillPattern::Gradient(gradient));
},
3 => {} // tiling
_ => {}
}

unsafe { R_NilValue }
}

fn release_pattern(&mut self, _ref: SEXP, _: DevDesc) {
// TODO: ref_ contains the index of the pattern, so it can be released.
VELLO_APP_PROXY.scene.release_pattern();
}

// TODO
// fn on_exit(&mut self, _: DevDesc) {}

Expand Down
4 changes: 2 additions & 2 deletions src/rust/src/vello_device/with_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use vellogd_shared::{

use crate::{add_tracing_point, graphics::DeviceDriver};

use super::{xy_to_path, WindowController};
use super::{xy_to_path, xy_to_path_with_hole, WindowController};

pub struct VelloGraphicsDeviceWithServer {
filename: String,
Expand Down Expand Up @@ -189,7 +189,7 @@ impl DeviceDriver for VelloGraphicsDeviceWithServer {
let stroke_params = StrokeParams::from_gc(gc);
if fill_params.is_some() || stroke_params.is_some() {
self.send_event(Request::DrawPolygon {
path: xy_to_path(x, y, true),
path: xy_to_path_with_hole(x, y, nper),
fill_params,
stroke_params,
})
Expand Down
43 changes: 41 additions & 2 deletions src/rust/vellogd-shared/src/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,21 @@ use std::os::raw::{c_char, c_int, c_uint, c_void};

pub type SEXP = *mut c_void;
pub type R_xlen_t = usize;
pub type SEXPTYPE = ::std::os::raw::c_uint;
pub type SEXPTYPE = c_uint;

pub const INTSXP: SEXPTYPE = 13;

extern "C" {
pub static mut R_NilValue: SEXP;
pub fn Rf_xlength(arg1: SEXP) -> R_xlen_t;

pub fn SET_VECTOR_ELT(x: SEXP, i: R_xlen_t, v: SEXP) -> SEXP;

pub fn Rf_protect(arg1: SEXP) -> SEXP;
pub fn Rf_unprotect(arg1: c_int);
pub fn INTEGER(x: SEXP) -> *mut c_int;
pub fn Rf_allocVector(arg1: SEXPTYPE, arg2: R_xlen_t) -> SEXP;
pub fn INTEGER(x: SEXP) -> *mut c_int;
pub fn Rf_ScalarInteger(arg1: c_int) -> SEXP;
}

// TODO: do not include GE version
Expand Down Expand Up @@ -316,6 +319,16 @@ pub struct _GEDevDesc {
}
pub type pGEDevDesc = *mut GEDevDesc;

// pattern
pub const R_GE_linearGradientPattern: u32 = 1;
pub const R_GE_radialGradientPattern: u32 = 2;
pub const R_GE_tilingPattern: u32 = 3;

pub const R_GE_patternExtendPad: u32 = 1;
pub const R_GE_patternExtendRepeat: u32 = 2;
pub const R_GE_patternExtendReflect: u32 = 3;
pub const R_GE_patternExtendNone: u32 = 4;

extern "C" {
pub fn GEfromDeviceX(value: f64, to: GEUnit, dd: pGEDevDesc) -> f64;
pub fn GEtoDeviceX(value: f64, from: GEUnit, dd: pGEDevDesc) -> f64;
Expand All @@ -330,6 +343,32 @@ extern "C" {
pub fn GEinitDisplayList(dd: pGEDevDesc);
pub fn GEaddDevice2(arg1: pGEDevDesc, arg2: *const c_char);

// pattern
pub fn R_GE_patternType(pattern: SEXP) -> c_int;

// linear gradient
pub fn R_GE_linearGradientX1(pattern: SEXP) -> f64;
pub fn R_GE_linearGradientY1(pattern: SEXP) -> f64;
pub fn R_GE_linearGradientX2(pattern: SEXP) -> f64;
pub fn R_GE_linearGradientY2(pattern: SEXP) -> f64;
pub fn R_GE_linearGradientNumStops(pattern: SEXP) -> c_int;
pub fn R_GE_linearGradientStop(pattern: SEXP, i: c_int) -> f64;
pub fn R_GE_linearGradientColour(pattern: SEXP, i: c_int) -> c_uint;
pub fn R_GE_linearGradientExtend(pattern: SEXP) -> c_int;

// radial gradient
pub fn R_GE_radialGradientCX1(pattern: SEXP) -> f64;
pub fn R_GE_radialGradientCY1(pattern: SEXP) -> f64;
pub fn R_GE_radialGradientR1(pattern: SEXP) -> f64;
pub fn R_GE_radialGradientCX2(pattern: SEXP) -> f64;
pub fn R_GE_radialGradientCY2(pattern: SEXP) -> f64;
pub fn R_GE_radialGradientR2(pattern: SEXP) -> f64;
pub fn R_GE_radialGradientNumStops(pattern: SEXP) -> c_int;
pub fn R_GE_radialGradientStop(pattern: SEXP, i: c_int) -> f64;
pub fn R_GE_radialGradientColour(pattern: SEXP, i: c_int) -> c_uint;
pub fn R_GE_radialGradientExtend(pattern: SEXP) -> c_int;

// glyph
pub fn R_GE_glyphFontFile(glyphFont: SEXP) -> *const c_char;
pub fn R_GE_glyphFontIndex(glyphFont: SEXP) -> c_int;
pub fn R_GE_glyphFontFamily(glyphFont: SEXP) -> *const c_char;
Expand Down
Loading

0 comments on commit 50263cd

Please sign in to comment.