Refactor vector data type from document-legacy into node graph (#1057)

Add vector data type
This commit is contained in:
0HyperCube 2023-02-25 16:55:05 +00:00 committed by Keavon Chambers
parent 08b2782917
commit 4495488546
20 changed files with 140 additions and 101 deletions

8
Cargo.lock generated
View File

@ -1629,7 +1629,6 @@ dependencies = [
"graphene-core",
"log",
"num-traits",
"rand_chacha 0.3.1",
"serde",
"specta",
]
@ -1647,8 +1646,10 @@ dependencies = [
"log",
"node-macro",
"once_cell",
"rand_chacha 0.3.1",
"serde",
"specta",
"spin 0.9.4",
"spirv-std",
]
@ -1738,12 +1739,10 @@ dependencies = [
"kurbo",
"log",
"once_cell",
"rand_chacha 0.3.1",
"remain",
"serde",
"serde_json",
"specta",
"spin 0.9.4",
"test-case",
"thiserror",
]
@ -2173,7 +2172,6 @@ dependencies = [
"log",
"num-traits",
"once_cell",
"rand_chacha 0.3.1",
"serde",
]
@ -5122,7 +5120,6 @@ dependencies = [
"graphene-core",
"log",
"num-traits",
"rand_chacha 0.3.1",
"serde",
"vulkano",
]
@ -5477,7 +5474,6 @@ dependencies = [
"graphene-core",
"log",
"num-traits",
"rand_chacha 0.3.1",
"serde",
"spirv",
"wgpu",

View File

@ -1,9 +1,3 @@
use graphene_core::raster::color::Color;
// RENDERING
pub const LAYER_OUTLINE_STROKE_COLOR: Color = Color::BLACK;
pub const LAYER_OUTLINE_STROKE_WEIGHT: f64 = 1.;
// BOOLEAN OPERATIONS
// Bezier curve intersection algorithm

View File

@ -25,6 +25,13 @@ pub mod layer_info;
pub mod nodegraph_layer;
/// Contains the [ShapeLayer](shape_layer::ShapeLayer) type, a generic SVG element defined using Bezier paths.
pub mod shape_layer;
pub mod style;
/// Contains the [TextLayer](text_layer::TextLayer) type.
pub mod text_layer;
mod render_data;
pub use render_data::RenderData;
pub mod style {
pub use super::RenderData;
pub use graphene_core::vector::style::*;
}

View File

@ -0,0 +1,22 @@
use super::style::ViewMode;
use super::text_layer::FontCache;
use glam::DVec2;
/// Contains metadata for rendering the document as an svg
#[derive(Debug, Clone, Copy)]
pub struct RenderData<'a> {
pub font_cache: &'a FontCache,
pub view_mode: ViewMode,
pub culling_bounds: Option<[DVec2; 2]>,
}
impl<'a> RenderData<'a> {
pub fn new(font_cache: &'a FontCache, view_mode: ViewMode, culling_bounds: Option<[DVec2; 2]>) -> Self {
Self {
font_cache,
view_mode,
culling_bounds,
}
}
}

View File

@ -23,8 +23,6 @@ serde_json = { version = "1.0" }
graphite-proc-macros = { path = "../proc-macros" }
bezier-rs = { path = "../libraries/bezier-rs" }
glam = { version="0.22", features = ["serde"] }
rand_chacha = "0.3.1"
spin = "0.9.2"
kurbo = { git = "https://github.com/linebender/kurbo.git", features = [
"serde",
] }

View File

@ -1,15 +1,7 @@
use crate::dispatcher::Dispatcher;
use crate::messages::prelude::*;
use rand_chacha::rand_core::{RngCore, SeedableRng};
use rand_chacha::ChaCha20Rng;
use spin::Mutex;
use std::cell::Cell;
static RNG: Mutex<Option<ChaCha20Rng>> = Mutex::new(None);
thread_local! {
pub static UUID_SEED: Cell<Option<u64>> = Cell::new(None);
}
pub use graphene_core::uuid::*;
// TODO: serialize with serde to save the current editor state
pub struct Editor {
@ -39,21 +31,6 @@ impl Default for Editor {
}
}
pub fn set_uuid_seed(random_seed: u64) {
UUID_SEED.with(|seed| seed.set(Some(random_seed)))
}
pub fn generate_uuid() -> u64 {
let mut lock = RNG.lock();
if lock.is_none() {
UUID_SEED.with(|seed| {
let random_seed = seed.get().expect("Random seed not set before editor was initialized");
*lock = Some(ChaCha20Rng::seed_from_u64(random_seed));
})
}
lock.as_mut().map(ChaCha20Rng::next_u64).unwrap()
}
pub fn release_series() -> String {
format!("Release Series: {}", env!("GRAPHITE_RELEASE_SERIES"))
}

View File

@ -33,6 +33,8 @@ kurbo = { git = "https://github.com/linebender/kurbo.git", features = [
"serde",
], optional = true }
glam = { version = "^0.22", default-features = false, features = ["scalar-math", "libm"]}
rand_chacha = "0.3.1"
spin = "0.9.2"
node-macro = {path = "../node-macro"}
specta.workspace = true
once_cell = { version = "1.17.0", default-features = false }

View File

@ -0,0 +1,5 @@
use crate::raster::Color;
// RENDERING
pub const LAYER_OUTLINE_STROKE_COLOR: Color = Color::BLACK;
pub const LAYER_OUTLINE_STROKE_WEIGHT: f64 = 1.;

View File

@ -7,6 +7,7 @@ extern crate alloc;
#[cfg(feature = "log")]
extern crate log;
pub mod consts;
pub mod generic;
pub mod ops;
pub mod structural;
@ -22,6 +23,7 @@ pub mod raster;
pub mod vector;
use core::any::TypeId;
pub use raster::Color;
// pub trait Node: for<'n> NodeIO<'n> {
pub trait Node<'i, Input: 'i>: 'i {

View File

@ -28,7 +28,7 @@ pub struct Color {
alpha: f32,
}
#[allow(clippy::derive_hash_xor_eq)]
#[allow(clippy::derived_hash_with_manual_eq)]
impl Hash for Color {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.red.to_bits().hash(state);

View File

@ -40,3 +40,41 @@ mod u64_string {
u64::from_str(&s).map_err(serde::de::Error::custom)
}
}
mod uuid_generation {
use core::cell::Cell;
use rand_chacha::rand_core::{RngCore, SeedableRng};
use rand_chacha::ChaCha20Rng;
use spin::Mutex;
static RNG: Mutex<Option<ChaCha20Rng>> = Mutex::new(None);
thread_local! {
pub static UUID_SEED: Cell<Option<u64>> = Cell::new(None);
}
pub fn set_uuid_seed(random_seed: u64) {
UUID_SEED.with(|seed| seed.set(Some(random_seed)))
}
pub fn generate_uuid() -> u64 {
let mut lock = RNG.lock();
if lock.is_none() {
UUID_SEED.with(|seed| {
let random_seed = seed.get().unwrap_or(42);
*lock = Some(ChaCha20Rng::seed_from_u64(random_seed));
})
}
lock.as_mut().map(ChaCha20Rng::next_u64).expect("uuid mutex poisoned")
}
}
pub use uuid_generation::*;
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct ManipulatorGroupId(u64);
impl bezier_rs::Identifier for ManipulatorGroupId {
fn new() -> Self {
Self(generate_uuid())
}
}

View File

@ -1,6 +1,16 @@
pub mod consts;
pub mod generator_nodes;
pub mod id_vec;
pub mod manipulator_group;
pub mod manipulator_point;
pub mod style;
pub use style::PathStyle;
pub mod subpath;
pub use subpath::Subpath;
mod vector_data;
pub use vector_data::VectorData;
mod id_vec;
pub use id_vec::IdBackedVec;

View File

@ -1,9 +1,7 @@
//! Contains stylistic options for SVG elements.
use super::text_layer::FontCache;
use crate::consts::{LAYER_OUTLINE_STROKE_COLOR, LAYER_OUTLINE_STROKE_WEIGHT};
use graphene_core::raster::color::Color;
use crate::Color;
use glam::{DAffine2, DVec2};
use serde::{Deserialize, Serialize};
@ -21,36 +19,6 @@ fn format_opacity(name: &str, opacity: f32) -> String {
}
}
/// Represents different ways of rendering an object
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize, specta::Type)]
pub enum ViewMode {
/// Render with normal coloration at the current viewport resolution
#[default]
Normal,
/// Render only the outlines of shapes at the current viewport resolution
Outline,
/// Render with normal coloration at the document resolution, showing the pixels when the current viewport resolution is higher
Pixels,
}
/// Contains metadata for rendering the document as an svg
#[derive(Debug, Clone, Copy)]
pub struct RenderData<'a> {
pub font_cache: &'a FontCache,
pub view_mode: ViewMode,
pub culling_bounds: Option<[DVec2; 2]>,
}
impl<'a> RenderData<'a> {
pub fn new(font_cache: &'a FontCache, view_mode: ViewMode, culling_bounds: Option<[DVec2; 2]>) -> Self {
Self {
font_cache,
view_mode,
culling_bounds,
}
}
}
#[derive(Default, PartialEq, Eq, Clone, Copy, Debug, Hash, Serialize, Deserialize, specta::Type)]
pub enum GradientType {
#[default]
@ -62,7 +30,7 @@ pub enum GradientType {
///
/// Contains the start and end points, along with the colors at varying points along the length.
#[repr(C)]
#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize, specta::Type)]
#[derive(Debug, PartialEq, Default, Serialize, Deserialize, specta::Type)]
pub struct Gradient {
pub start: DVec2,
pub end: DVec2,
@ -71,7 +39,6 @@ pub struct Gradient {
uuid: u64,
pub gradient_type: GradientType,
}
impl Gradient {
/// Constructs a new gradient with the colors at 0 and 1 specified.
pub fn new(start: DVec2, start_color: Color, end: DVec2, end_color: Color, transform: DAffine2, uuid: u64, gradient_type: GradientType) -> Self {
@ -170,6 +137,21 @@ impl Gradient {
}
}
impl Clone for Gradient {
/// Clones the gradient, with the cloned gradient having the new uuid.
/// If multiple gradients have the same id then only one gradient will be shown in the final svg output.
fn clone(&self) -> Self {
Self {
start: self.start,
end: self.end,
transform: self.transform,
positions: self.positions.clone(),
uuid: crate::uuid::generate_uuid(),
gradient_type: self.gradient_type,
}
}
}
/// Describes the fill of a layer.
///
/// Can be None, a solid [Color], a linear [Gradient], a radial [Gradient] or potentially some sort of image or pattern in the future
@ -410,7 +392,7 @@ impl PathStyle {
///
/// # Example
/// ```
/// # use graphite_document_legacy::layers::style::{Fill, PathStyle};
/// # use graphene_core::vector::style::{Fill, PathStyle};
/// # use graphene_core::raster::color::Color;
/// let fill = Fill::solid(Color::RED);
/// let style = PathStyle::new(None, fill.clone());
@ -425,7 +407,7 @@ impl PathStyle {
///
/// # Example
/// ```
/// # use graphite_document_legacy::layers::style::{Fill, Stroke, PathStyle};
/// # use graphene_core::vector::style::{Fill, Stroke, PathStyle};
/// # use graphene_core::raster::color::Color;
/// let stroke = Stroke::new(Color::GREEN, 42.);
/// let style = PathStyle::new(Some(stroke.clone()), Fill::None);
@ -440,7 +422,7 @@ impl PathStyle {
///
/// # Example
/// ```
/// # use graphite_document_legacy::layers::style::{Fill, PathStyle};
/// # use graphene_core::vector::style::{Fill, PathStyle};
/// # use graphene_core::raster::color::Color;
/// let mut style = PathStyle::default();
///
@ -459,7 +441,7 @@ impl PathStyle {
///
/// # Example
/// ```
/// # use graphite_document_legacy::layers::style::{Stroke, PathStyle};
/// # use graphene_core::vector::style::{Stroke, PathStyle};
/// # use graphene_core::raster::color::Color;
/// let mut style = PathStyle::default();
///
@ -478,7 +460,7 @@ impl PathStyle {
///
/// # Example
/// ```
/// # use graphite_document_legacy::layers::style::{Fill, PathStyle};
/// # use graphene_core::vector::style::{Fill, PathStyle};
/// # use graphene_core::raster::color::Color;
/// let mut style = PathStyle::new(None, Fill::Solid(Color::RED));
///
@ -496,7 +478,7 @@ impl PathStyle {
///
/// # Example
/// ```
/// # use graphite_document_legacy::layers::style::{Fill, Stroke, PathStyle};
/// # use graphene_core::vector::style::{Fill, Stroke, PathStyle};
/// # use graphene_core::raster::color::Color;
/// let mut style = PathStyle::new(Some(Stroke::new(Color::GREEN, 42.)), Fill::None);
///
@ -524,3 +506,15 @@ impl PathStyle {
format!("{}{}", fill_attribute, stroke_attribute)
}
}
/// Represents different ways of rendering an object
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize, specta::Type)]
pub enum ViewMode {
/// Render with normal coloration at the current viewport resolution
#[default]
Normal,
/// Render only the outlines of shapes at the current viewport resolution
Outline,
/// Render with normal coloration at the document resolution, showing the pixels when the current viewport resolution is higher
Pixels,
}

View File

@ -0,0 +1,12 @@
use glam::DAffine2;
use super::style::PathStyle;
use crate::uuid::ManipulatorGroupId;
/// [VectorData] is passed between nodes.
/// It contains a list of subpaths (that may be open or closed), a transform and some style information.
pub struct VectorData {
pub subpaths: Vec<bezier_rs::Subpath<ManipulatorGroupId>>,
pub transform: DAffine2,
pub style: PathStyle,
}

View File

@ -16,7 +16,6 @@ graphene-core = { path = "../gcore", features = ["async", "std", "alloc"] }
graph-craft = {path = "../graph-craft", features = ["serde"] }
dyn-any = { path = "../../libraries/dyn-any", features = ["log-bad-types", "rc", "glam"] }
num-traits = "0.2"
rand_chacha = "0.3.1"
log = "0.4"
serde = { version = "1", features = ["derive", "rc"]}
glam = { version = "0.22" }

View File

@ -15,7 +15,6 @@ graphene-core = { path = "../gcore", features = ["std"] }
dyn-any = { path = "../../libraries/dyn-any", features = ["log-bad-types", "rc", "glam"] }
num-traits = "0.2"
dyn-clone = "1.0"
rand_chacha = "0.3.1"
log = "0.4"
serde = { version = "1", features = ["derive", "rc"], optional = true }
glam = { version = "0.22" }

View File

@ -4,27 +4,14 @@ use graphene_core::{NodeIdentifier, Type};
use dyn_any::{DynAny, StaticType};
use glam::IVec2;
pub use graphene_core::uuid::generate_uuid;
use graphene_core::TypeDescriptor;
use rand_chacha::{
rand_core::{RngCore, SeedableRng},
ChaCha20Rng,
};
use std::borrow::Cow;
use std::collections::{HashMap, HashSet};
use std::sync::Mutex;
pub mod value;
pub type NodeId = u64;
static RNG: Mutex<Option<ChaCha20Rng>> = Mutex::new(None);
pub fn generate_uuid() -> u64 {
let mut lock = RNG.lock().expect("uuid mutex poisoned");
if lock.is_none() {
*lock = Some(ChaCha20Rng::seed_from_u64(0));
}
lock.as_mut().map(ChaCha20Rng::next_u64).unwrap()
}
fn merge_ids(a: u64, b: u64) -> u64 {
use std::hash::{Hash, Hasher};

View File

@ -20,7 +20,6 @@ dyn-any = { path = "../../libraries/dyn-any", features = ["log-bad-types", "glam
num-traits = "0.2"
borrow_stack = { path = "../borrow_stack" }
dyn-clone = "1.0"
rand_chacha = "0.3.1"
log = "0.4"
serde = { version = "1", features = ["derive"], optional = true }
glam = { version = "0.22" }

View File

@ -14,7 +14,6 @@ graphene-core = { path = "../gcore", features = ["async", "std", "alloc", "gpu"]
graph-craft = {path = "../graph-craft" }
dyn-any = { path = "../../libraries/dyn-any", features = ["log-bad-types", "rc", "glam"] }
num-traits = "0.2"
rand_chacha = "0.3.1"
log = "0.4"
serde = { version = "1", features = ["derive", "rc"], optional = true }
glam = { version = "0.22" }

View File

@ -15,7 +15,6 @@ graph-craft = {path = "../graph-craft" }
dyn-any = { path = "../../libraries/dyn-any", features = ["log-bad-types", "rc", "glam"] }
future-executor = { path = "../future-executor" }
num-traits = "0.2"
rand_chacha = "0.3.1"
log = "0.4"
serde = { version = "1", features = ["derive", "rc"], optional = true }
glam = { version = "0.22" }