Add nondestructive vector editing (#1676)

* Initial vector modify node

* Initial extraction of data from monitor nodes

* Migrate to point id

* Start converting to modify node

* Non destructive spline tool (tout le reste est cassé)

* Fix unconnected modify node

* Fix freehand tool

* Pen tool

* Migrate demo art

* Select points

* Fix the demo artwork

* Fix the X and Y inputs for path tool

* G1 continous toggle

* Delete points

* Fix test

* Insert point

* Improve robustness of handles

* Fix GRS shortcuts on path

* Dragging points

* Fix build

* Preserve opposing handle lengths

* Update demo art and snapping

* Fix polygon tool

* Double click end anchor

* Improve dragging

* Fix text shifting

* Select only connected verts

* Colinear alt

* Cleanup

* Fix imports

* Improve pen tool avoiding handle placement

* Improve disolve

* Remove pivot widget from Transform node properties

* Fix demo art

* Fix bugs

* Re-save demo artwork

* Code review

* Serialize hashmap as tuple vec to enable deserialize_inputs

* Fix migrate

* Add document upgrade function to editor_api.rs

* Finalize document upgrading

* Rename to the Path node

* Remove smoothing from Freehand tool

* Upgrade demo artwork

* Propertly disable raw-rs tests

---------

Co-authored-by: Keavon Chambers <keavon@keavon.com>
Co-authored-by: Adam <adamgerhant@gmail.com>
Co-authored-by: Dennis Kobert <dennis@kobert.dev>
This commit is contained in:
James Lindsay
2024-07-05 21:42:40 +01:00
committed by GitHub
parent fd3613018a
commit 1652c713a6
96 changed files with 3343 additions and 2622 deletions

View File

@@ -2,7 +2,6 @@ use crate::Node;
use bezier_rs::{ManipulatorGroup, Subpath};
use graphene_core::transform::Footprint;
use graphene_core::uuid::ManipulatorGroupId;
use graphene_core::vector::misc::BooleanOperation;
pub use graphene_core::vector::*;
@@ -69,10 +68,10 @@ fn from_svg_string(svg_string: &str) -> VectorData {
return VectorData::empty();
};
VectorData::from_subpaths(convert_usvg_path(path))
VectorData::from_subpaths(convert_usvg_path(path), false)
}
pub fn convert_usvg_path(path: &usvg::Path) -> Vec<Subpath<ManipulatorGroupId>> {
pub fn convert_usvg_path(path: &usvg::Path) -> Vec<Subpath<PointId>> {
let mut subpaths = Vec::new();
let mut groups = Vec::new();

View File

@@ -243,7 +243,7 @@ pub struct DrawImageFrameNode<Surface> {
}
#[node_macro::node_fn(DrawImageFrameNode)]
async fn draw_image_frame_node<'a: 'input>(image: ImageFrame<SRGBA8>, surface_handle: Arc<SurfaceHandle<HtmlCanvasElement>>) -> SurfaceHandleFrame<HtmlCanvasElement> {
async fn draw_image_frame_node<'a: 'input>(image: ImageFrame<SRGBA8>, surface_handle: Arc<WasmSurfaceHandle>) -> SurfaceHandleFrame<HtmlCanvasElement> {
let image_data = image.image.data;
let array: Clamped<&[u8]> = Clamped(bytemuck::cast_slice(image_data.as_slice()));
if image.image.width > 0 && image.image.height > 0 {
@@ -290,9 +290,9 @@ fn decode_image_node<'a: 'input>(data: Arc<[u8]>) -> ImageFrame<Color> {
pub use graph_craft::document::value::RenderOutput;
pub struct RenderNode<Data, Surface, Parameter> {
data: Data,
#[cfg(any(feature = "resvg", feature = "vello"))]
#[cfg(all(any(feature = "resvg", feature = "vello"), target_arch = "wasm32"))]
surface_handle: Surface,
#[cfg(not(any(feature = "resvg", feature = "vello")))]
#[cfg(not(all(any(feature = "resvg", feature = "vello"), target_arch = "wasm32")))]
surface_handle: PhantomData<Surface>,
parameter: PhantomData<Parameter>,
}
@@ -426,7 +426,7 @@ impl<'input, 'a: 'input, T: 'input + GraphicElementRendered, F: 'input + Future<
where
Data: Node<'input, Footprint, Output = F>,
Surface: Node<'input, (), Output = SurfaceFuture>,
SurfaceFuture: core::future::Future<Output = Arc<SurfaceHandle<HtmlCanvasElement>>>,
SurfaceFuture: core::future::Future<Output = Arc<SurfaceHandle<<crate::wasm_application_io::WasmApplicationIo as graphene_core::application_io::ApplicationIo>::Surface>>>,
{
type Output = core::pin::Pin<Box<dyn core::future::Future<Output = RenderOutput> + 'input>>;
@@ -441,7 +441,7 @@ where
let output_format = editor.render_config.export_format;
match output_format {
ExportFormat::Svg => render_svg(self.data.eval(footprint).await, SvgRender::new(), render_params, footprint),
#[cfg(any(feature = "resvg", feature = "vello"))]
#[cfg(all(any(feature = "resvg", feature = "vello"), target_arch = "wasm32"))]
ExportFormat::Canvas => render_canvas(self.data.eval(footprint).await, SvgRender::new(), render_params, footprint, editor, self.surface_handle.eval(()).await),
_ => todo!("Non-SVG render output for {output_format:?}"),
}
@@ -455,7 +455,7 @@ impl<'input, 'a: 'input, T: 'input + GraphicElementRendered, F: 'input + Future<
where
Data: Node<'input, (), Output = F>,
Surface: Node<'input, (), Output = SurfaceFuture>,
SurfaceFuture: core::future::Future<Output = Arc<SurfaceHandle<HtmlCanvasElement>>>,
SurfaceFuture: core::future::Future<Output = Arc<SurfaceHandle<<crate::wasm_application_io::WasmApplicationIo as graphene_core::application_io::ApplicationIo>::Surface>>>,
{
type Output = core::pin::Pin<Box<dyn core::future::Future<Output = RenderOutput> + 'input>>;
#[inline]
@@ -469,7 +469,7 @@ where
let output_format = editor.render_config.export_format;
match output_format {
ExportFormat::Svg => render_svg(self.data.eval(()).await, SvgRender::new(), render_params, footprint),
#[cfg(any(feature = "resvg", feature = "vello"))]
#[cfg(all(any(feature = "resvg", feature = "vello"), target_arch = "wasm32"))]
ExportFormat::Canvas => render_canvas(self.data.eval(()).await, SvgRender::new(), render_params, footprint, editor, self.surface_handle.eval(()).await),
_ => todo!("Non-SVG render output for {output_format:?}"),
}
@@ -481,9 +481,9 @@ impl<Data, Surface, Parameter> RenderNode<Data, Surface, Parameter> {
pub fn new(data: Data, surface_handle: Surface) -> Self {
Self {
data,
#[cfg(any(feature = "resvg", feature = "vello"))]
#[cfg(all(any(feature = "resvg", feature = "vello"), target_arch = "wasm32"))]
surface_handle,
#[cfg(not(any(feature = "resvg", feature = "vello")))]
#[cfg(not(all(any(feature = "resvg", feature = "vello"), target_arch = "wasm32")))]
surface_handle: PhantomData,
parameter: PhantomData,
}