Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pattern #23

Merged
merged 4 commits into from
Oct 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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