mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-22 15:48:12 +08:00
merge
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
use crate::blending::AlphaBlending;
|
||||
use crate::bounds::BoundingBox;
|
||||
use crate::instances::{Instance, Instances};
|
||||
use crate::raster::BlendMode;
|
||||
use crate::math::quad::Quad;
|
||||
use crate::raster::image::Image;
|
||||
use crate::raster_types::{CPU, GPU, Raster, RasterDataTable};
|
||||
use crate::transform::TransformMut;
|
||||
@@ -7,82 +9,20 @@ use crate::uuid::NodeId;
|
||||
use crate::vector::{VectorData, VectorDataTable};
|
||||
use crate::{CloneVarArgs, Color, Context, Ctx, ExtractAll, OwnedContextImpl};
|
||||
use dyn_any::DynAny;
|
||||
use glam::{DAffine2, IVec2};
|
||||
use glam::{DAffine2, DVec2, IVec2};
|
||||
use std::hash::Hash;
|
||||
|
||||
pub mod renderer;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, DynAny, specta::Type)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
#[serde(default)]
|
||||
pub struct AlphaBlending {
|
||||
pub blend_mode: BlendMode,
|
||||
pub opacity: f32,
|
||||
pub fill: f32,
|
||||
pub clip: bool,
|
||||
}
|
||||
impl Default for AlphaBlending {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
impl core::hash::Hash for AlphaBlending {
|
||||
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
|
||||
self.opacity.to_bits().hash(state);
|
||||
self.fill.to_bits().hash(state);
|
||||
self.blend_mode.hash(state);
|
||||
self.clip.hash(state);
|
||||
}
|
||||
}
|
||||
impl std::fmt::Display for AlphaBlending {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let round = |x: f32| (x * 1e3).round() / 1e3;
|
||||
write!(
|
||||
f,
|
||||
"Blend Mode: {} — Opacity: {}% — Fill: {}% — Clip: {}",
|
||||
self.blend_mode,
|
||||
round(self.opacity * 100.),
|
||||
round(self.fill * 100.),
|
||||
if self.clip { "Yes" } else { "No" }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl AlphaBlending {
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
opacity: 1.,
|
||||
fill: 1.,
|
||||
blend_mode: BlendMode::Normal,
|
||||
clip: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lerp(&self, other: &Self, t: f32) -> Self {
|
||||
let lerp = |a: f32, b: f32, t: f32| a + (b - a) * t;
|
||||
|
||||
AlphaBlending {
|
||||
opacity: lerp(self.opacity, other.opacity, t),
|
||||
fill: lerp(self.fill, other.fill, t),
|
||||
blend_mode: if t < 0.5 { self.blend_mode } else { other.blend_mode },
|
||||
clip: if t < 0.5 { self.clip } else { other.clip },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Eventually remove this migration document upgrade code
|
||||
pub fn migrate_graphic_group<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result<GraphicGroupTable, D::Error> {
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DynAny, Default)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
#[derive(Clone, Debug, PartialEq, DynAny, Default, serde::Serialize, serde::Deserialize)]
|
||||
pub struct OldGraphicGroup {
|
||||
elements: Vec<(GraphicElement, Option<NodeId>)>,
|
||||
transform: DAffine2,
|
||||
alpha_blending: AlphaBlending,
|
||||
}
|
||||
#[derive(Clone, Debug, PartialEq, DynAny, Default)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
#[derive(Clone, Debug, PartialEq, DynAny, Default, serde::Serialize, serde::Deserialize)]
|
||||
pub struct GraphicGroup {
|
||||
elements: Vec<(GraphicElement, Option<NodeId>)>,
|
||||
}
|
||||
@@ -164,8 +104,7 @@ impl From<RasterDataTable<GPU>> for GraphicGroupTable {
|
||||
}
|
||||
|
||||
/// The possible forms of graphical content held in a Vec by the `elements` field of [`GraphicElement`].
|
||||
#[derive(Clone, Debug, Hash, PartialEq, DynAny)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
#[derive(Clone, Debug, Hash, PartialEq, DynAny, serde::Serialize, serde::Deserialize)]
|
||||
pub enum GraphicElement {
|
||||
/// Equivalent to the SVG <g> tag: https://developer.mozilla.org/en-US/docs/Web/SVG/Element/g
|
||||
GraphicGroup(GraphicGroupTable),
|
||||
@@ -245,6 +184,25 @@ impl GraphicElement {
|
||||
}
|
||||
}
|
||||
|
||||
impl BoundingBox for GraphicElement {
|
||||
fn bounding_box(&self, transform: DAffine2, include_stroke: bool) -> Option<[DVec2; 2]> {
|
||||
match self {
|
||||
GraphicElement::VectorData(vector_data) => vector_data.bounding_box(transform, include_stroke),
|
||||
GraphicElement::RasterDataCPU(raster) => raster.bounding_box(transform, include_stroke),
|
||||
GraphicElement::RasterDataGPU(raster) => raster.bounding_box(transform, include_stroke),
|
||||
GraphicElement::GraphicGroup(graphic_group) => graphic_group.bounding_box(transform, include_stroke),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl BoundingBox for GraphicGroupTable {
|
||||
fn bounding_box(&self, transform: DAffine2, include_stroke: bool) -> Option<[DVec2; 2]> {
|
||||
self.instance_ref_iter()
|
||||
.filter_map(|element| element.instance.bounding_box(transform * *element.transform, include_stroke))
|
||||
.reduce(Quad::combine_bounds)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> serde::Deserialize<'de> for Raster<CPU> {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
@@ -281,8 +239,7 @@ impl serde::Serialize for Raster<GPU> {
|
||||
}
|
||||
|
||||
/// Some [`ArtboardData`] with some optional clipping bounds that can be exported.
|
||||
#[derive(Clone, Debug, Hash, PartialEq, DynAny)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
#[derive(Clone, Debug, Hash, PartialEq, DynAny, serde::Serialize, serde::Deserialize)]
|
||||
pub struct Artboard {
|
||||
pub graphic_group: GraphicGroupTable,
|
||||
pub label: String,
|
||||
@@ -311,12 +268,25 @@ impl Artboard {
|
||||
}
|
||||
}
|
||||
|
||||
impl BoundingBox for Artboard {
|
||||
fn bounding_box(&self, transform: DAffine2, include_stroke: bool) -> Option<[DVec2; 2]> {
|
||||
let artboard_bounds = (transform * Quad::from_box([self.location.as_dvec2(), self.location.as_dvec2() + self.dimensions.as_dvec2()])).bounding_box();
|
||||
if self.clip {
|
||||
Some(artboard_bounds)
|
||||
} else {
|
||||
[self.graphic_group.bounding_box(transform, include_stroke), Some(artboard_bounds)]
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.reduce(Quad::combine_bounds)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Eventually remove this migration document upgrade code
|
||||
pub fn migrate_artboard_group<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result<ArtboardGroupTable, D::Error> {
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Clone, Default, Debug, Hash, PartialEq, DynAny)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
#[derive(Clone, Default, Debug, Hash, PartialEq, DynAny, serde::Serialize, serde::Deserialize)]
|
||||
pub struct ArtboardGroup {
|
||||
pub artboards: Vec<(Artboard, Option<NodeId>)>,
|
||||
}
|
||||
@@ -348,8 +318,21 @@ pub fn migrate_artboard_group<'de, D: serde::Deserializer<'de>>(deserializer: D)
|
||||
|
||||
pub type ArtboardGroupTable = Instances<Artboard>;
|
||||
|
||||
impl BoundingBox for ArtboardGroupTable {
|
||||
fn bounding_box(&self, transform: DAffine2, include_stroke: bool) -> Option<[DVec2; 2]> {
|
||||
self.instance_ref_iter()
|
||||
.filter_map(|instance| instance.instance.bounding_box(transform, include_stroke))
|
||||
.reduce(Quad::combine_bounds)
|
||||
}
|
||||
}
|
||||
|
||||
#[node_macro::node(category(""))]
|
||||
async fn layer(_: impl Ctx, mut stack: GraphicGroupTable, element: GraphicElement, node_path: Vec<NodeId>) -> GraphicGroupTable {
|
||||
async fn layer<I: 'n + Send + Clone>(
|
||||
_: impl Ctx,
|
||||
#[implementations(GraphicGroupTable, VectorDataTable, RasterDataTable<CPU>, RasterDataTable<GPU>)] mut stack: Instances<I>,
|
||||
#[implementations(GraphicElement, VectorData, Raster<CPU>, Raster<GPU>)] element: I,
|
||||
node_path: Vec<NodeId>,
|
||||
) -> Instances<I> {
|
||||
// Get the penultimate element of the node path, or None if the path is too short
|
||||
let source_node_id = node_path.get(node_path.len().wrapping_sub(2)).copied();
|
||||
|
||||
@@ -432,7 +415,7 @@ async fn flatten_group(_: impl Ctx, group: GraphicGroupTable, fully_flatten: boo
|
||||
output
|
||||
}
|
||||
|
||||
#[node_macro::node(category("General"))]
|
||||
#[node_macro::node(category("Vector"))]
|
||||
async fn flatten_vector(_: impl Ctx, group: GraphicGroupTable) -> VectorDataTable {
|
||||
// TODO: Avoid mutable reference, instead return a new GraphicGroupTable?
|
||||
fn flatten_group(output_group_table: &mut VectorDataTable, current_group_table: GraphicGroupTable) {
|
||||
@@ -571,3 +554,7 @@ impl From<GraphicGroupTable> for GraphicElement {
|
||||
GraphicElement::GraphicGroup(graphic_group)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ToGraphicElement {
|
||||
fn to_graphic_element(&self) -> GraphicElement;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user