mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-26 03:08:11 +08:00
Reach a compiling workspace on the merged tree
This commit is contained in:
@@ -12,16 +12,16 @@ use core_types::{ATTR_TRANSFORM, Ctx, ExtractFootprint};
|
||||
use graphic_types::Graphic;
|
||||
use pipeline::{BasicBrushPipeline, BasicBrushPipelineArgs};
|
||||
use raster_types::{GPU, Raster};
|
||||
use wgpu_executor::{WgpuExecutor, WgpuPipelineCache};
|
||||
use core_types::ProtoNodeIdentifier;
|
||||
use wgpu_executor::{WgpuExecutorHandle, WgpuPipelineCache};
|
||||
|
||||
#[node_macro::node(category("Raster: Brush"))]
|
||||
pub async fn basic_brush<'a: 'n>(
|
||||
pub fn basic_brush(
|
||||
ctx: impl Ctx + ExtractFootprint,
|
||||
strokes: List<Graphic>,
|
||||
#[widget(ParsedWidgetOverride::Hidden)] cache: Item<BrushCache>,
|
||||
#[scope(basic_brush_pipeline::IDENTIFIER)] pipeline: Item<WgpuPipelineCache>,
|
||||
strokes: List<Graphic<'static>>,
|
||||
#[widget(ParsedWidgetOverride::Hidden)] cache: BrushCache,
|
||||
#[scope(basic_brush_pipeline::IDENTIFIER)] pipeline: WgpuPipelineCache,
|
||||
) -> List<Raster<GPU>> {
|
||||
let (cache, pipeline) = (cache.into_element(), pipeline.into_element());
|
||||
let mut stack = vec![strokes.into_iter()];
|
||||
let mut strokes = Vec::new();
|
||||
while let Some(top) = stack.last_mut() {
|
||||
@@ -56,7 +56,7 @@ pub async fn basic_brush<'a: 'n>(
|
||||
strokes: &strokes,
|
||||
cache: &cache,
|
||||
};
|
||||
let Some((texture, transform)) = pipeline.run::<BasicBrushPipeline>(&args).await else {
|
||||
let Some((texture, transform)) = pipeline.run::<BasicBrushPipeline>(&args) else {
|
||||
return List::new();
|
||||
};
|
||||
let raster = Raster::<GPU>::new_gpu(texture);
|
||||
@@ -64,11 +64,11 @@ pub async fn basic_brush<'a: 'n>(
|
||||
}
|
||||
|
||||
#[node_macro::node(category(""), inject_scope)]
|
||||
async fn basic_brush_pipeline<'a: 'n>(
|
||||
fn basic_brush_pipeline(
|
||||
_ctx: impl Ctx,
|
||||
#[scope(ProtoNodeIdentifier::new("graphene_std::platform_application_io::WgpuExecutorNode"))] executor: Item<&'a WgpuExecutor>,
|
||||
#[scope(ProtoNodeIdentifier::new("graphene_std::platform_application_io::WgpuExecutorNode"))] executor: WgpuExecutorHandle,
|
||||
#[data] pipeline: WgpuPipelineCache,
|
||||
) -> Item<WgpuPipelineCache> {
|
||||
executor.into_element().pipeline_init::<BasicBrushPipeline>(pipeline);
|
||||
Item::new_from_element(pipeline.clone())
|
||||
) -> WgpuPipelineCache {
|
||||
executor.pipeline_init::<BasicBrushPipeline>(pipeline);
|
||||
pipeline.clone()
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ use core_types::Color;
|
||||
use core_types::transform::Footprint;
|
||||
use glam::{DAffine2, UVec2};
|
||||
use raster_types::Texture;
|
||||
use wgpu_executor::{AsyncWgpuPipeline, Buffer, WgpuExecutor};
|
||||
use wgpu_executor::{Buffer, WgpuExecutor, WgpuPipeline};
|
||||
|
||||
pub(super) const DENSITY_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::R16Float;
|
||||
pub(super) const COMPOSITE_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Rgba16Float;
|
||||
@@ -71,7 +71,7 @@ pub struct BasicBrushPipelineArgs<'a> {
|
||||
pub(super) cache: &'a BrushCache,
|
||||
}
|
||||
|
||||
impl AsyncWgpuPipeline for BasicBrushPipeline {
|
||||
impl WgpuPipeline for BasicBrushPipeline {
|
||||
type Args<'a> = BasicBrushPipelineArgs<'a>;
|
||||
type Out = Option<(Texture, DAffine2)>;
|
||||
|
||||
@@ -85,7 +85,7 @@ impl AsyncWgpuPipeline for BasicBrushPipeline {
|
||||
}
|
||||
}
|
||||
|
||||
async fn run<'a>(&'a self, executor: &'a WgpuExecutor, args: &'a Self::Args<'_>) -> Self::Out {
|
||||
fn run<'a>(&'a self, executor: &'a WgpuExecutor, args: &'a Self::Args<'_>) -> Self::Out {
|
||||
let frame = super::render::Frame::new(args.strokes)?;
|
||||
let region = Region::new(&args.footprint)?;
|
||||
let state = args.cache.take(&args.footprint).unwrap_or_default();
|
||||
|
||||
@@ -17,11 +17,10 @@ fn brush_strokes(
|
||||
_: impl Ctx,
|
||||
strokes: List<Stroke>,
|
||||
color: List<Color>,
|
||||
#[default(DEFAULT_DIAMETER)] diameter: Item<f64>,
|
||||
#[default(DEFAULT_HARDNESS)] hardness: Item<Percentage>,
|
||||
#[default(DEFAULT_FLOW)] flow: Item<Percentage>,
|
||||
) -> List<Graphic> {
|
||||
let (diameter, hardness, flow) = (diameter.into_element(), hardness.into_element(), flow.into_element());
|
||||
#[default(DEFAULT_DIAMETER)] diameter: f64,
|
||||
#[default(DEFAULT_HARDNESS)] hardness: Percentage,
|
||||
#[default(DEFAULT_FLOW)] flow: Percentage,
|
||||
) -> List<Graphic<'static>> {
|
||||
List::new_from_item(
|
||||
Item::new_from_element(Graphic::from(strokes))
|
||||
.with_attribute(ATTR_COLOR, color.element(0).copied().unwrap_or_default())
|
||||
|
||||
@@ -496,7 +496,7 @@ pub fn to_graphic<'e, T: graphic_types::graphic::IntoGraphicElement>(
|
||||
/// Type-asserts a value to be graphical content, converting each item of other content types into its matching form.
|
||||
/// Use the 'Into Group' node instead to collect the content into a single group.
|
||||
#[node_macro::node(category("General"))]
|
||||
pub fn as_graphic<'e>(_: impl Ctx, value: Graphic<'e>) -> Graphic<'e> {
|
||||
pub fn as_graphic(_: impl Ctx, value: Graphic<'static>) -> Graphic<'static> {
|
||||
value
|
||||
}
|
||||
|
||||
@@ -530,7 +530,7 @@ pub fn to_graphic_element<'e, T: graphic_types::graphic::IntoGraphicElement>(
|
||||
/// The typed-level conversion: the whole level nests as one graphic lane, as
|
||||
/// the pre-flip `Into<Graphic>` list collapse did. Registered under the to
|
||||
/// graphic identifier.
|
||||
#[node_macro::node(category(""), extent(wrap_graphic_extent))]
|
||||
#[node_macro::node(category(""), extent(into_group_extent))]
|
||||
pub fn to_graphic_typed<'e, T: Clone + Send + Sync + core_types::CacheHash + 'static>(
|
||||
_: impl Ctx,
|
||||
#[implementations(Vector, Raster<CPU>, Raster<GPU>, Color, Gradient, String)] content: IList<T>,
|
||||
|
||||
@@ -360,7 +360,7 @@ pub fn render_output_cache(
|
||||
render_params.for_mask,
|
||||
render_params.thumbnail,
|
||||
render_params.aligned_strokes,
|
||||
render_params.stroke_below,
|
||||
render_params.override_paint_order,
|
||||
ctx.try_animation_time().unwrap_or(0.),
|
||||
ctx.try_real_time().unwrap_or(0.),
|
||||
ctx.try_pointer_position(),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use core_types::consts::{DEFAULT_FONT_SIZE, DEFAULT_LINE_HEIGHT};
|
||||
use core_types::list::List;
|
||||
use core_types::list::{Item, List};
|
||||
use core_types::{ATTR_FONT_SIZE, ATTR_LETTER_SPACING, ATTR_LETTER_TILT, ATTR_LINE_HEIGHT, ATTR_MAX_HEIGHT, ATTR_MAX_WIDTH, Ctx};
|
||||
use graph_craft::application_io::resource::Resource;
|
||||
use graphic_types::Vector;
|
||||
@@ -15,15 +15,15 @@ fn text(
|
||||
/// The text content to be drawn.
|
||||
#[widget(ParsedWidgetOverride::Custom = "text_area")]
|
||||
#[default("Lorem ipsum")]
|
||||
text: Item<String>,
|
||||
text: String,
|
||||
/// The loaded font file used to draw the text. The editor resolves the chosen typeface to these bytes via the resource system.
|
||||
#[widget(ParsedWidgetOverride::Custom = "text_font")]
|
||||
font: Item<Resource>,
|
||||
font: Resource,
|
||||
/// The font size used to draw the text.
|
||||
#[unit(" px")]
|
||||
#[default(24.)]
|
||||
#[hard(1..)]
|
||||
size: Item<f64>,
|
||||
size: f64,
|
||||
/// The line height ratio, relative to the font size. Each line is drawn lower than its previous line by the distance of *Size* × *Line Height*.
|
||||
///
|
||||
/// 0 means all lines overlap. 1 means all lines are spaced by just the font size. 1.2 is a common default for readable text. 2 means double-spaced text.
|
||||
@@ -31,41 +31,35 @@ fn text(
|
||||
#[hard(0..)]
|
||||
#[step(0.1)]
|
||||
#[default(1.2)]
|
||||
line_height: Item<f64>,
|
||||
line_height: f64,
|
||||
/// Additional spacing, in pixels, added between each character.
|
||||
#[unit(" px")]
|
||||
#[step(0.1)]
|
||||
letter_spacing: Item<f64>,
|
||||
letter_spacing: f64,
|
||||
/// The angle of faux italic slant applied to each glyph.
|
||||
#[unit("°")]
|
||||
#[hard(-85..85)]
|
||||
letter_tilt: Item<f64>,
|
||||
letter_tilt: f64,
|
||||
/// Enables the maximum width constraint so lines can wrap.
|
||||
#[widget(ParsedWidgetOverride::Hidden)]
|
||||
has_max_width: Item<bool>,
|
||||
has_max_width: bool,
|
||||
/// The maximum width that the text block can occupy before wrapping to a new line. Otherwise, lines do not wrap.
|
||||
#[unit(" px")]
|
||||
#[hard(1..)]
|
||||
#[widget(ParsedWidgetOverride::Custom = "optional_f64")]
|
||||
max_width: Item<f64>,
|
||||
max_width: f64,
|
||||
/// Whether the *Max Height* property is enabled so that lines beyond it are not drawn.
|
||||
#[widget(ParsedWidgetOverride::Hidden)]
|
||||
has_max_height: Item<bool>,
|
||||
has_max_height: bool,
|
||||
/// The maximum height that the text block can occupy. Excess lines are not drawn.
|
||||
#[unit(" px")]
|
||||
#[hard(1..)]
|
||||
#[widget(ParsedWidgetOverride::Custom = "optional_f64")]
|
||||
max_height: Item<f64>,
|
||||
max_height: f64,
|
||||
/// The horizontal alignment of each line of text within its surrounding box. To have an effect on a single line of text, *Max Width* must be set.
|
||||
#[widget(ParsedWidgetOverride::Custom = "text_align")]
|
||||
align: Item<TextAlign>,
|
||||
) -> Item<String> {
|
||||
let text = text.into_element();
|
||||
let font = font.into_element();
|
||||
let (size, line_height, letter_spacing, letter_tilt) = (*size.element(), *line_height.element(), *letter_spacing.element(), *letter_tilt.element());
|
||||
let (has_max_width, max_width, has_max_height, max_height) = (*has_max_width.element(), *max_width.element(), *has_max_height.element(), *max_height.element());
|
||||
let align = align.into_element();
|
||||
|
||||
align: TextAlign,
|
||||
) -> List<String> {
|
||||
let mut item = Item::new_from_element(text);
|
||||
|
||||
if font != Resource::default() {
|
||||
@@ -93,25 +87,27 @@ fn text(
|
||||
item.set_attribute(ATTR_TEXT_ALIGN, align);
|
||||
}
|
||||
|
||||
item
|
||||
List::new_from_item(item)
|
||||
}
|
||||
|
||||
/// Converts a styled text string into a vector compound path.
|
||||
#[node_macro::node(category("Text"), name("Text to Vector"))]
|
||||
fn text_to_vector(
|
||||
_: impl Ctx,
|
||||
/// A styled text string produced by the **Text** node (or any other string source).
|
||||
string: Item<String>,
|
||||
) -> Item<Vector> {
|
||||
shape_text_item(&string, false).into_iter().next().unwrap_or_default()
|
||||
/// A styled list of text strings produced by the **Text** node (or any other `String[]` source).
|
||||
#[implementations(List<String>)]
|
||||
strings: List<String>,
|
||||
) -> List<Vector> {
|
||||
shape_text_list(&strings, false)
|
||||
}
|
||||
|
||||
/// Splits a styled text string into a separate vector item for each of its glyphs (letterforms).
|
||||
#[node_macro::node(category("Text"), name("Text to Vector Glyphs"))]
|
||||
fn text_to_vector_glyphs(
|
||||
_: impl Ctx,
|
||||
/// A styled text string produced by the **Text** node (or any other string source).
|
||||
string: Item<String>,
|
||||
/// A styled list of text strings produced by the **Text** node (or any other `String[]` source).
|
||||
#[implementations(List<String>)]
|
||||
strings: List<String>,
|
||||
) -> List<Vector> {
|
||||
shape_text_item(&string, true)
|
||||
shape_text_list(&strings, true)
|
||||
}
|
||||
|
||||
@@ -45,10 +45,8 @@ fn path_modify<'e>(
|
||||
|
||||
/// Bakes the content's transform attribute into its underlying value, resetting the attribute to the identity.
|
||||
#[node_macro::node(category("Vector"))]
|
||||
fn bake_transform<T: BakeTransform + Clone + Default + Send + Sync + 'static>(
|
||||
_ctx: impl Ctx,
|
||||
#[implementations(Vector, DAffine2, DVec2)] (mut content, transform): (T, Attr<TransformAttr>),
|
||||
) -> (T, Attr<TransformAttr>) {
|
||||
// Monomorphic on Vector: our macro cannot yet read a record element through an open generic, so master's DAffine2 and DVec2 rows have no node here.
|
||||
fn bake_transform(_ctx: impl Ctx, (mut content, transform): (Vector, Attr<TransformAttr>)) -> (Vector, Attr<TransformAttr>) {
|
||||
let transform: DAffine2 = *transform;
|
||||
content.bake_transform(&transform);
|
||||
|
||||
|
||||
@@ -55,9 +55,21 @@ fn carried_lane_attrs<'e>(arena: &'e core_types::arena::Arena, lane: core_types:
|
||||
Ok((Attr(lane.attr::<TransformAttr>()), Attr(layer_path.as_slice())))
|
||||
}
|
||||
|
||||
/// A gradient row's settings, which ride the lane rather than the bare element.
|
||||
fn gradient_settings_from_lane(source: &core_types::node::List<'_, Gradient>, index: usize) -> GradientSettings {
|
||||
let lane = source.lane(index);
|
||||
GradientSettings {
|
||||
spread: lane.attr::<vector_types::markers::GradientSpread>(),
|
||||
cyclic: lane.attr::<vector_types::markers::GradientCyclic>(),
|
||||
space: lane.attr::<vector_types::markers::GradientSpace>(),
|
||||
hue_direction: lane.attr::<vector_types::markers::GradientHueDirection>(),
|
||||
interpolation: lane.attr::<vector_types::markers::GradientInterpolation>(),
|
||||
}
|
||||
}
|
||||
|
||||
/// The gradient color for one assign-colors position, replaying the
|
||||
/// randomized draws up to it.
|
||||
fn assign_color_at(gradient: &Gradient, position: usize, length: usize, randomize: bool, seed: SeedValue, repeat_every: u32) -> Color {
|
||||
fn assign_color_at(gradient: &Gradient, settings: GradientSettings, position: usize, length: usize, randomize: bool, seed: SeedValue, repeat_every: u32) -> Color {
|
||||
let factor = match randomize {
|
||||
true => {
|
||||
let mut rng = rand::rngs::StdRng::seed_from_u64(seed.into());
|
||||
@@ -74,10 +86,7 @@ fn assign_color_at(gradient: &Gradient, position: usize, length: usize, randomiz
|
||||
},
|
||||
};
|
||||
// The factor spans 0..=1, so the spread stays Pad rather than wrapping the last element onto the first stop
|
||||
let settings = GradientSettings {
|
||||
spread: Default::default(),
|
||||
..GradientSettings::from(gradient)
|
||||
};
|
||||
let settings = GradientSettings { spread: Default::default(), ..settings };
|
||||
gradient.evaluate(factor, settings)
|
||||
}
|
||||
|
||||
@@ -157,16 +166,17 @@ fn assign_colors<'e>(
|
||||
return Ok((element, transform, Attr(existing_fill), Attr(existing_stroke), layer_path));
|
||||
}
|
||||
let gradient_element = gradient.element_ref(0);
|
||||
let gradient_settings = gradient_settings_from_lane(&gradient, 0);
|
||||
let reversed;
|
||||
let gradient_element = match reverse {
|
||||
true => {
|
||||
reversed = gradient_element.reversed(GradientSettings::from(gradient_element).cyclic);
|
||||
reversed = gradient_element.reversed(gradient_settings.cyclic);
|
||||
&reversed
|
||||
}
|
||||
false => gradient_element,
|
||||
};
|
||||
|
||||
let color = assign_color_at(gradient_element, lane, content.len(), randomize, seed, repeat_every);
|
||||
let color = assign_color_at(gradient_element, gradient_settings, lane, content.len(), randomize, seed, repeat_every);
|
||||
let paint = List::new_from_element(color).into_graphic_list();
|
||||
let parked = park_paint(ctx.arena(), paint)?;
|
||||
|
||||
@@ -226,10 +236,11 @@ fn assign_colors_graphic<'e>(
|
||||
return Ok((original.clone(), transform, layer_path));
|
||||
}
|
||||
let gradient_element = gradient.element_ref(0);
|
||||
let gradient_settings = gradient_settings_from_lane(&gradient, 0);
|
||||
let reversed;
|
||||
let gradient_element = match reverse {
|
||||
true => {
|
||||
reversed = gradient_element.reversed(GradientSettings::from(gradient_element).cyclic);
|
||||
reversed = gradient_element.reversed(gradient_settings.cyclic);
|
||||
&reversed
|
||||
}
|
||||
false => gradient_element,
|
||||
@@ -272,7 +283,7 @@ fn assign_colors_graphic<'e>(
|
||||
Some(mut rows) => {
|
||||
for row in 0..rows.len() {
|
||||
let has_stroke = lane_has_stroke || has_paint::<StrokeAttr, _>(&rows, row);
|
||||
let color = assign_color_at(gradient_element, position + row, length, randomize, seed, repeat_every);
|
||||
let color = assign_color_at(gradient_element, gradient_settings, position + row, length, randomize, seed, repeat_every);
|
||||
let paint = List::new_from_element(color).into_graphic_list();
|
||||
if fill {
|
||||
set_paint_attribute_at(&mut rows, row, ATTR_FILL, paint.clone());
|
||||
@@ -2858,13 +2869,13 @@ fn morph_core(flattened: List<Vector>, snapshot: List<Graphic<'static>>, progres
|
||||
(Some(Graphic::Color(color_a)), Some(Graphic::Color(color_b))) => Some(List::new_from_element(Graphic::from(color_a.lerp(color_b, time as f32)))),
|
||||
(Some(Graphic::Color(color_a)), Some(Graphic::Gradient(stops_b))) => {
|
||||
let mut solid_to_gradient = stops_b.clone();
|
||||
solid_to_gradient.color.iter_mut().for_each(|color| *color = *color_a);
|
||||
solid_to_gradient.0.iter_element_values_mut().for_each(|color| *color = *color_a);
|
||||
let stops = solid_to_gradient.lerp(stops_b, time);
|
||||
Some(gradient_paint(b, stops, None))
|
||||
}
|
||||
(Some(Graphic::Gradient(stops_a)), Some(Graphic::Color(color_b))) => {
|
||||
let mut gradient_to_solid = stops_a.clone();
|
||||
gradient_to_solid.color.iter_mut().for_each(|color| *color = *color_b);
|
||||
gradient_to_solid.0.iter_element_values_mut().for_each(|color| *color = *color_b);
|
||||
let stops = stops_a.lerp(&gradient_to_solid, time);
|
||||
Some(gradient_paint(a, stops, None))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user