Add the SVG Preview render mode in place of the Vello option in the preferences (#3797)
* Remove Vello from preferences * Add the Render Mode: SVG Preview radio button * Remove SVG outline renderer * Add a tooltip explaination when disabled in unsupported browsers * Fix Eyedropper tool to support Outline render mode * Use #[allow(clippy::too_many_arguments)] instead of tuple * Rerun nodegraph when max render area is changed --------- Co-authored-by: Dennis Kobert <dennis@kobert.dev>
This commit is contained in:
parent
a2d3b3f410
commit
9f2c8713ff
|
|
@ -314,38 +314,6 @@ impl PreferencesDialogMessageHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
if wgpu_available {
|
if wgpu_available {
|
||||||
let vello_description = "Auto uses Vello renderer when GPU is available.";
|
|
||||||
let vello_renderer_label = vec![
|
|
||||||
Separator::new(SeparatorStyle::Unrelated).widget_instance(),
|
|
||||||
Separator::new(SeparatorStyle::Unrelated).widget_instance(),
|
|
||||||
TextLabel::new("Vello Renderer")
|
|
||||||
.tooltip_label("Vello Renderer")
|
|
||||||
.tooltip_description(vello_description)
|
|
||||||
.widget_instance(),
|
|
||||||
];
|
|
||||||
let vello_preference = RadioInput::new(vec![
|
|
||||||
RadioEntryData::new("Auto").label("Auto").on_update(move |_| {
|
|
||||||
PreferencesMessage::VelloPreference {
|
|
||||||
preference: graph_craft::wasm_application_io::VelloPreference::Auto,
|
|
||||||
}
|
|
||||||
.into()
|
|
||||||
}),
|
|
||||||
RadioEntryData::new("Disabled").label("Disabled").on_update(move |_| {
|
|
||||||
PreferencesMessage::VelloPreference {
|
|
||||||
preference: graph_craft::wasm_application_io::VelloPreference::Disabled,
|
|
||||||
}
|
|
||||||
.into()
|
|
||||||
}),
|
|
||||||
])
|
|
||||||
.selected_index(Some(preferences.vello_preference as u32))
|
|
||||||
.widget_instance();
|
|
||||||
let vello_preference = vec![
|
|
||||||
Separator::new(SeparatorStyle::Unrelated).widget_instance(),
|
|
||||||
Separator::new(SeparatorStyle::Unrelated).widget_instance(),
|
|
||||||
vello_preference,
|
|
||||||
];
|
|
||||||
rows.extend_from_slice(&[vello_renderer_label, vello_preference]);
|
|
||||||
|
|
||||||
let render_tile_resolution_description = "
|
let render_tile_resolution_description = "
|
||||||
Maximum X or Y resolution per render tile. Larger tiles may improve performance but can cause flickering or missing content in complex artwork if set too high.\n\
|
Maximum X or Y resolution per render tile. Larger tiles may improve performance but can cause flickering or missing content in complex artwork if set too high.\n\
|
||||||
\n\
|
\n\
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ use graphene_std::math::quad::Quad;
|
||||||
use graphene_std::path_bool::{boolean_intersect, path_bool_lib};
|
use graphene_std::path_bool::{boolean_intersect, path_bool_lib};
|
||||||
use graphene_std::raster::BlendMode;
|
use graphene_std::raster::BlendMode;
|
||||||
use graphene_std::raster_types::Raster;
|
use graphene_std::raster_types::Raster;
|
||||||
|
use graphene_std::render_node::wgpu_available;
|
||||||
use graphene_std::subpath::Subpath;
|
use graphene_std::subpath::Subpath;
|
||||||
use graphene_std::table::Table;
|
use graphene_std::table::Table;
|
||||||
use graphene_std::vector::PointId;
|
use graphene_std::vector::PointId;
|
||||||
|
|
@ -2549,29 +2550,46 @@ impl DocumentMessageHandler {
|
||||||
.popover_min_width(Some(320))
|
.popover_min_width(Some(320))
|
||||||
.widget_instance(),
|
.widget_instance(),
|
||||||
Separator::new(SeparatorStyle::Unrelated).widget_instance(),
|
Separator::new(SeparatorStyle::Unrelated).widget_instance(),
|
||||||
RadioInput::new(vec![
|
{
|
||||||
RadioEntryData::new("Normal")
|
let disabled = cfg!(target_family = "wasm") && wgpu_available() == Some(false);
|
||||||
.icon("RenderModeNormal")
|
|
||||||
.tooltip_label("Render Mode: Normal")
|
let mut entries = vec![
|
||||||
.on_update(|_| DocumentMessage::SetRenderMode { render_mode: RenderMode::Normal }.into()),
|
RadioEntryData::new("Normal")
|
||||||
RadioEntryData::new("Outline")
|
.icon("RenderModeNormal")
|
||||||
.icon("RenderModeOutline")
|
.tooltip_label("Render Mode: Normal")
|
||||||
.tooltip_label("Render Mode: Outline")
|
.on_update(|_| DocumentMessage::SetRenderMode { render_mode: RenderMode::Normal }.into()),
|
||||||
.on_update(|_| DocumentMessage::SetRenderMode { render_mode: RenderMode::Outline }.into()),
|
RadioEntryData::new("Outline")
|
||||||
// TODO: See issue #320
|
.icon("RenderModeOutline")
|
||||||
// RadioEntryData::new("PixelPreview")
|
.tooltip_label("Render Mode: Outline")
|
||||||
// .icon("RenderModePixels")
|
.on_update(|_| DocumentMessage::SetRenderMode { render_mode: RenderMode::Outline }.into()),
|
||||||
// .tooltip_label("Render Mode: Pixel Preview")
|
// TODO: See issue #320
|
||||||
// .on_update(|_| todo!()),
|
// RadioEntryData::new("PixelPreview")
|
||||||
// TODO: See issue #1845
|
// .icon("RenderModePixels")
|
||||||
// RadioEntryData::new("SvgPreview")
|
// .tooltip_label("Render Mode: Pixel Preview")
|
||||||
// .icon("RenderModeSvg")
|
// .on_update(|_| todo!()),
|
||||||
// .tooltip_label("Render Mode: SVG Preview")
|
RadioEntryData::new("SvgPreview")
|
||||||
// .on_update(|_| todo!()),
|
.icon("RenderModeSvg")
|
||||||
])
|
.tooltip_label("Render Mode: SVG Preview")
|
||||||
.selected_index(Some(self.render_mode as u32))
|
.on_update(|_| DocumentMessage::SetRenderMode { render_mode: RenderMode::SvgPreview }.into()),
|
||||||
.narrow(true)
|
];
|
||||||
.widget_instance(),
|
let mut selected_index = self.render_mode as u32;
|
||||||
|
|
||||||
|
if disabled {
|
||||||
|
for entry in &mut entries {
|
||||||
|
entry.tooltip_description = "
|
||||||
|
*Normal* and *Outline* render modes are not available in this browser. For compatibility, *SVG Preview* mode is active as a fallback.\n\
|
||||||
|
\n\
|
||||||
|
This functionality requires WebGPU support. Check webgpu.org for browser implementation status.
|
||||||
|
"
|
||||||
|
.trim()
|
||||||
|
.into();
|
||||||
|
}
|
||||||
|
|
||||||
|
selected_index = entries.iter().position(|entry| entry.value == "SvgPreview").unwrap() as u32;
|
||||||
|
}
|
||||||
|
|
||||||
|
RadioInput::new(entries).selected_index(Some(selected_index)).disabled(disabled).narrow(true).widget_instance()
|
||||||
|
},
|
||||||
Separator::new(SeparatorStyle::Unrelated).widget_instance(),
|
Separator::new(SeparatorStyle::Unrelated).widget_instance(),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -157,5 +157,4 @@ pub enum PortfolioMessage {
|
||||||
ToggleRulers,
|
ToggleRulers,
|
||||||
UpdateDocumentWidgets,
|
UpdateDocumentWidgets,
|
||||||
UpdateOpenDocumentsList,
|
UpdateOpenDocumentsList,
|
||||||
UpdateVelloPreference,
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -407,6 +407,13 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
||||||
// Use exact physical dimensions from browser (via ResizeObserver's devicePixelContentBoxSize)
|
// Use exact physical dimensions from browser (via ResizeObserver's devicePixelContentBoxSize)
|
||||||
let physical_resolution = viewport.size().to_physical().into_dvec2().round().as_uvec2();
|
let physical_resolution = viewport.size().to_physical().into_dvec2().round().as_uvec2();
|
||||||
|
|
||||||
|
// TODO: Remove this when we do the SVG rendering with a separate library on desktop, thus avoiding a need for the hole punch.
|
||||||
|
// TODO: See #3796. There is a second instance of this todo comment and code block (be sure to remove both).
|
||||||
|
#[cfg(not(target_family = "wasm"))]
|
||||||
|
responses.add_front(FrontendMessage::UpdateViewportHolePunch {
|
||||||
|
active: document.render_mode != graphene_std::vector::style::RenderMode::SvgPreview,
|
||||||
|
});
|
||||||
|
|
||||||
if let Ok(message) = self.executor.submit_node_graph_evaluation(
|
if let Ok(message) = self.executor.submit_node_graph_evaluation(
|
||||||
self.documents.get_mut(document_id).expect("Tried to render non-existent document"),
|
self.documents.get_mut(document_id).expect("Tried to render non-existent document"),
|
||||||
*document_id,
|
*document_id,
|
||||||
|
|
@ -1163,6 +1170,13 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
||||||
// Use exact physical dimensions from browser (via ResizeObserver's devicePixelContentBoxSize)
|
// Use exact physical dimensions from browser (via ResizeObserver's devicePixelContentBoxSize)
|
||||||
let physical_resolution = viewport.size().to_physical().into_dvec2().round().as_uvec2();
|
let physical_resolution = viewport.size().to_physical().into_dvec2().round().as_uvec2();
|
||||||
|
|
||||||
|
// TODO: Remove this when we do the SVG rendering with a separate library on desktop, thus avoiding a need for the hole punch.
|
||||||
|
// TODO: See #3796. There is a second instance of this todo comment and code block (be sure to remove both).
|
||||||
|
#[cfg(not(target_family = "wasm"))]
|
||||||
|
responses.add_front(FrontendMessage::UpdateViewportHolePunch {
|
||||||
|
active: document.render_mode != graphene_std::vector::style::RenderMode::SvgPreview,
|
||||||
|
});
|
||||||
|
|
||||||
let result = self
|
let result = self
|
||||||
.executor
|
.executor
|
||||||
.submit_node_graph_evaluation(document, document_id, physical_resolution, scale, timing_information, node_to_inspect, ignore_hash, pointer_position);
|
.submit_node_graph_evaluation(document, document_id, physical_resolution, scale, timing_information, node_to_inspect, ignore_hash, pointer_position);
|
||||||
|
|
@ -1197,7 +1211,7 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
||||||
|
|
||||||
let result = self
|
let result = self
|
||||||
.executor
|
.executor
|
||||||
.submit_eyedropper_preview(document_id, preview_transform, pointer_position, resolution, scale, timing_information);
|
.submit_eyedropper_preview(document, document_id, preview_transform, pointer_position, resolution, scale, timing_information);
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
Err(description) => {
|
Err(description) => {
|
||||||
|
|
@ -1364,13 +1378,6 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
||||||
responses.add(PortfolioMessage::RequestWelcomeScreenButtonsLayout);
|
responses.add(PortfolioMessage::RequestWelcomeScreenButtonsLayout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PortfolioMessage::UpdateVelloPreference => {
|
|
||||||
// TODO: Resend this message once the GPU context is initialized to avoid having the hole punch be stuck in an invalid state
|
|
||||||
let active = if cfg!(target_family = "wasm") { false } else { preferences.use_vello() };
|
|
||||||
responses.add(FrontendMessage::UpdateViewportHolePunch { active });
|
|
||||||
responses.add(NodeGraphMessage::RunDocumentGraph);
|
|
||||||
self.persistent_data.use_vello = preferences.use_vello();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ use graphene_std::text::{Font, FontCache};
|
||||||
pub struct PersistentData {
|
pub struct PersistentData {
|
||||||
pub font_cache: FontCache,
|
pub font_cache: FontCache,
|
||||||
pub font_catalog: FontCatalog,
|
pub font_catalog: FontCatalog,
|
||||||
pub use_vello: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Should this be a BTreeMap instead?
|
// TODO: Should this be a BTreeMap instead?
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@ pub enum PreferencesMessage {
|
||||||
ResetToDefaults,
|
ResetToDefaults,
|
||||||
|
|
||||||
// Per-preference messages
|
// Per-preference messages
|
||||||
VelloPreference { preference: graph_craft::wasm_application_io::VelloPreference },
|
|
||||||
SelectionMode { selection_mode: SelectionMode },
|
SelectionMode { selection_mode: SelectionMode },
|
||||||
BrushTool { enabled: bool },
|
BrushTool { enabled: bool },
|
||||||
ModifyLayout { zoom_with_scroll: bool },
|
ModifyLayout { zoom_with_scroll: bool },
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ use crate::messages::preferences::SelectionMode;
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
use crate::messages::tool::utility_types::ToolType;
|
use crate::messages::tool::utility_types::ToolType;
|
||||||
use graph_craft::wasm_application_io::EditorPreferences;
|
use graph_craft::wasm_application_io::EditorPreferences;
|
||||||
use graphene_std::application_io::GetEditorPreferences;
|
|
||||||
|
|
||||||
#[derive(ExtractField)]
|
#[derive(ExtractField)]
|
||||||
pub struct PreferencesMessageContext<'a> {
|
pub struct PreferencesMessageContext<'a> {
|
||||||
|
|
@ -17,7 +16,6 @@ pub struct PreferencesMessageContext<'a> {
|
||||||
pub struct PreferencesMessageHandler {
|
pub struct PreferencesMessageHandler {
|
||||||
pub selection_mode: SelectionMode,
|
pub selection_mode: SelectionMode,
|
||||||
pub zoom_with_scroll: bool,
|
pub zoom_with_scroll: bool,
|
||||||
pub vello_preference: graph_craft::wasm_application_io::VelloPreference,
|
|
||||||
pub brush_tool: bool,
|
pub brush_tool: bool,
|
||||||
pub graph_wire_style: GraphWireStyle,
|
pub graph_wire_style: GraphWireStyle,
|
||||||
pub viewport_zoom_wheel_rate: f64,
|
pub viewport_zoom_wheel_rate: f64,
|
||||||
|
|
@ -37,7 +35,6 @@ impl PreferencesMessageHandler {
|
||||||
|
|
||||||
pub fn editor_preferences(&self) -> EditorPreferences {
|
pub fn editor_preferences(&self) -> EditorPreferences {
|
||||||
EditorPreferences {
|
EditorPreferences {
|
||||||
vello_preference: self.vello_preference,
|
|
||||||
max_render_region_size: self.max_render_region_size,
|
max_render_region_size: self.max_render_region_size,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -45,10 +42,6 @@ impl PreferencesMessageHandler {
|
||||||
pub fn supports_wgpu(&self) -> bool {
|
pub fn supports_wgpu(&self) -> bool {
|
||||||
graph_craft::wasm_application_io::wgpu_available().unwrap_or_default()
|
graph_craft::wasm_application_io::wgpu_available().unwrap_or_default()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn use_vello(&self) -> bool {
|
|
||||||
self.editor_preferences().use_vello()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for PreferencesMessageHandler {
|
impl Default for PreferencesMessageHandler {
|
||||||
|
|
@ -56,7 +49,6 @@ impl Default for PreferencesMessageHandler {
|
||||||
Self {
|
Self {
|
||||||
selection_mode: SelectionMode::Touched,
|
selection_mode: SelectionMode::Touched,
|
||||||
zoom_with_scroll: matches!(MappingVariant::default(), MappingVariant::ZoomWithScroll),
|
zoom_with_scroll: matches!(MappingVariant::default(), MappingVariant::ZoomWithScroll),
|
||||||
vello_preference: EditorPreferences::default().vello_preference,
|
|
||||||
brush_tool: false,
|
brush_tool: false,
|
||||||
graph_wire_style: GraphWireStyle::default(),
|
graph_wire_style: GraphWireStyle::default(),
|
||||||
viewport_zoom_wheel_rate: VIEWPORT_ZOOM_WHEEL_RATE,
|
viewport_zoom_wheel_rate: VIEWPORT_ZOOM_WHEEL_RATE,
|
||||||
|
|
@ -78,7 +70,6 @@ impl MessageHandler<PreferencesMessage, PreferencesMessageContext<'_>> for Prefe
|
||||||
*self = preferences;
|
*self = preferences;
|
||||||
|
|
||||||
responses.add(PortfolioMessage::EditorPreferences);
|
responses.add(PortfolioMessage::EditorPreferences);
|
||||||
responses.add(PortfolioMessage::UpdateVelloPreference);
|
|
||||||
responses.add(PreferencesMessage::ModifyLayout {
|
responses.add(PreferencesMessage::ModifyLayout {
|
||||||
zoom_with_scroll: self.zoom_with_scroll,
|
zoom_with_scroll: self.zoom_with_scroll,
|
||||||
});
|
});
|
||||||
|
|
@ -90,12 +81,6 @@ impl MessageHandler<PreferencesMessage, PreferencesMessageContext<'_>> for Prefe
|
||||||
}
|
}
|
||||||
|
|
||||||
// Per-preference messages
|
// Per-preference messages
|
||||||
PreferencesMessage::VelloPreference { preference } => {
|
|
||||||
self.vello_preference = preference;
|
|
||||||
responses.add(PortfolioMessage::UpdateVelloPreference);
|
|
||||||
responses.add(PortfolioMessage::EditorPreferences);
|
|
||||||
responses.add(PreferencesDialogMessage::Update);
|
|
||||||
}
|
|
||||||
PreferencesMessage::BrushTool { enabled } => {
|
PreferencesMessage::BrushTool { enabled } => {
|
||||||
self.brush_tool = enabled;
|
self.brush_tool = enabled;
|
||||||
|
|
||||||
|
|
@ -131,8 +116,8 @@ impl MessageHandler<PreferencesMessage, PreferencesMessageContext<'_>> for Prefe
|
||||||
}
|
}
|
||||||
PreferencesMessage::MaxRenderRegionSize { size } => {
|
PreferencesMessage::MaxRenderRegionSize { size } => {
|
||||||
self.max_render_region_size = size;
|
self.max_render_region_size = size;
|
||||||
responses.add(PortfolioMessage::UpdateVelloPreference);
|
|
||||||
responses.add(PortfolioMessage::EditorPreferences);
|
responses.add(PortfolioMessage::EditorPreferences);
|
||||||
|
responses.add(NodeGraphMessage::RunDocumentGraph);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -187,9 +187,11 @@ impl NodeGraphExecutor {
|
||||||
self.submit_current_node_graph_evaluation(document, document_id, viewport_resolution, viewport_scale, time, pointer)
|
self.submit_current_node_graph_evaluation(document, document_id, viewport_resolution, viewport_scale, time, pointer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
#[cfg(not(target_family = "wasm"))]
|
#[cfg(not(target_family = "wasm"))]
|
||||||
pub(crate) fn submit_eyedropper_preview(
|
pub(crate) fn submit_eyedropper_preview(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
document: &DocumentMessageHandler,
|
||||||
document_id: DocumentId,
|
document_id: DocumentId,
|
||||||
transform: DAffine2,
|
transform: DAffine2,
|
||||||
pointer: DVec2,
|
pointer: DVec2,
|
||||||
|
|
@ -208,7 +210,7 @@ impl NodeGraphExecutor {
|
||||||
time,
|
time,
|
||||||
pointer,
|
pointer,
|
||||||
export_format: graphene_std::application_io::ExportFormat::Raster,
|
export_format: graphene_std::application_io::ExportFormat::Raster,
|
||||||
render_mode: graphene_std::vector::style::RenderMode::Normal,
|
render_mode: document.render_mode,
|
||||||
hide_artboards: false,
|
hide_artboards: false,
|
||||||
for_export: false,
|
for_export: false,
|
||||||
for_eyedropper: true,
|
for_eyedropper: true,
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ use graphene_std::table::{Table, TableRow};
|
||||||
use graphene_std::text::FontCache;
|
use graphene_std::text::FontCache;
|
||||||
use graphene_std::transform::RenderQuality;
|
use graphene_std::transform::RenderQuality;
|
||||||
use graphene_std::vector::Vector;
|
use graphene_std::vector::Vector;
|
||||||
|
use graphene_std::vector::style::RenderMode;
|
||||||
use graphene_std::wasm_application_io::{RenderOutputType, WasmApplicationIo, WasmEditorApi};
|
use graphene_std::wasm_application_io::{RenderOutputType, WasmApplicationIo, WasmEditorApi};
|
||||||
use graphene_std::{Artboard, Context, Graphic};
|
use graphene_std::{Artboard, Context, Graphic};
|
||||||
use interpreted_executor::dynamic_executor::{DynamicExecutor, IntrospectError, ResolvedDocumentNodeTypesDelta};
|
use interpreted_executor::dynamic_executor::{DynamicExecutor, IntrospectError, ResolvedDocumentNodeTypesDelta};
|
||||||
|
|
@ -243,16 +244,11 @@ impl NodeRuntime {
|
||||||
self.sender.send_generation_response(CompilationResponse { result, node_graph_errors });
|
self.sender.send_generation_response(CompilationResponse { result, node_graph_errors });
|
||||||
}
|
}
|
||||||
GraphRuntimeRequest::ExecutionRequest(ExecutionRequest { execution_id, mut render_config, .. }) => {
|
GraphRuntimeRequest::ExecutionRequest(ExecutionRequest { execution_id, mut render_config, .. }) => {
|
||||||
// There are cases where we want to export via the svg pipeline eventhough raster was requested.
|
// We may want to render via the SVG pipeline even though raster was requested, if SVG Preview render mode is active or WebGPU/Vello is unavailable
|
||||||
if matches!(render_config.export_format, ExportFormat::Raster) {
|
if render_config.export_format == ExportFormat::Raster
|
||||||
let vello_available = self.editor_api.application_io.as_ref().unwrap().gpu_executor().is_some();
|
&& (render_config.render_mode == RenderMode::SvgPreview || self.editor_api.application_io.as_ref().unwrap().gpu_executor().is_none())
|
||||||
let use_vello = vello_available && self.editor_api.editor_preferences.use_vello();
|
{
|
||||||
|
render_config.export_format = ExportFormat::Svg;
|
||||||
// On web when the user has disabled vello rendering in the preferences or we are exporting.
|
|
||||||
// And on all platforms when vello is not supposed to be used.
|
|
||||||
if !use_vello || cfg!(target_family = "wasm") && render_config.for_export {
|
|
||||||
render_config.export_format = ExportFormat::Svg;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let result = self.execute_network(render_config).await;
|
let result = self.execute_network(render_config).await;
|
||||||
|
|
|
||||||
|
|
@ -79,15 +79,6 @@
|
||||||
margin-right: 2px;
|
margin-right: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background: var(--color-6-lowergray);
|
|
||||||
color: var(--color-f-white);
|
|
||||||
|
|
||||||
svg {
|
|
||||||
fill: var(--color-f-white);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.active {
|
&.active {
|
||||||
background: var(--color-e-nearwhite);
|
background: var(--color-e-nearwhite);
|
||||||
color: var(--color-2-mildblack);
|
color: var(--color-2-mildblack);
|
||||||
|
|
@ -112,19 +103,12 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.narrow.narrow {
|
&:not(.disabled) button:not(.active):hover {
|
||||||
--widget-height: 20px;
|
background: var(--color-6-lowergray);
|
||||||
height: var(--widget-height);
|
color: var(--color-f-white);
|
||||||
|
|
||||||
button {
|
svg {
|
||||||
height: 16px;
|
fill: var(--color-f-white);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.mixed {
|
|
||||||
button:not(:hover),
|
|
||||||
&.disabled button:hover {
|
|
||||||
background: var(--color-5-dullgray);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -144,5 +128,21 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.narrow.narrow {
|
||||||
|
--widget-height: 20px;
|
||||||
|
height: var(--widget-height);
|
||||||
|
|
||||||
|
button {
|
||||||
|
height: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.mixed {
|
||||||
|
button:not(:hover),
|
||||||
|
&.disabled button:hover {
|
||||||
|
background: var(--color-5-dullgray);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -967,7 +967,7 @@ async fn poll_node_graph_evaluation() {
|
||||||
|
|
||||||
if !editor::node_graph_executor::run_node_graph().await.0 {
|
if !editor::node_graph_executor::run_node_graph().await.0 {
|
||||||
return;
|
return;
|
||||||
};
|
}
|
||||||
|
|
||||||
editor_and_handle(|editor, handle| {
|
editor_and_handle(|editor, handle| {
|
||||||
let mut messages = VecDeque::new();
|
let mut messages = VecDeque::new();
|
||||||
|
|
|
||||||
|
|
@ -336,27 +336,13 @@ pub type WasmSurfaceHandle = SurfaceHandle<wgpu_executor::Window>;
|
||||||
#[cfg(feature = "wgpu")]
|
#[cfg(feature = "wgpu")]
|
||||||
pub type WasmSurfaceHandleFrame = graphene_application_io::SurfaceHandleFrame<wgpu_executor::Window>;
|
pub type WasmSurfaceHandleFrame = graphene_application_io::SurfaceHandleFrame<wgpu_executor::Window>;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, specta::Type, serde::Serialize, serde::Deserialize)]
|
|
||||||
pub enum VelloPreference {
|
|
||||||
Auto,
|
|
||||||
Disabled,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Hash, specta::Type, serde::Serialize, serde::Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Hash, specta::Type, serde::Serialize, serde::Deserialize)]
|
||||||
pub struct EditorPreferences {
|
pub struct EditorPreferences {
|
||||||
pub vello_preference: VelloPreference,
|
|
||||||
/// Maximum render region size in pixels along one dimension of the square area.
|
/// Maximum render region size in pixels along one dimension of the square area.
|
||||||
pub max_render_region_size: u32,
|
pub max_render_region_size: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl graphene_application_io::GetEditorPreferences for EditorPreferences {
|
impl graphene_application_io::GetEditorPreferences for EditorPreferences {
|
||||||
fn use_vello(&self) -> bool {
|
|
||||||
match self.vello_preference {
|
|
||||||
VelloPreference::Auto => wgpu_available().unwrap_or(false),
|
|
||||||
VelloPreference::Disabled => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn max_render_region_area(&self) -> u32 {
|
fn max_render_region_area(&self) -> u32 {
|
||||||
let size = self.max_render_region_size.min(u32::MAX.isqrt());
|
let size = self.max_render_region_size.min(u32::MAX.isqrt());
|
||||||
size.pow(2)
|
size.pow(2)
|
||||||
|
|
@ -365,10 +351,7 @@ impl graphene_application_io::GetEditorPreferences for EditorPreferences {
|
||||||
|
|
||||||
impl Default for EditorPreferences {
|
impl Default for EditorPreferences {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self { max_render_region_size: 1280 }
|
||||||
vello_preference: VelloPreference::Auto,
|
|
||||||
max_render_region_size: 1280,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -126,7 +126,6 @@ async fn main() -> Result<(), Box<dyn Error>> {
|
||||||
let device = wgpu_executor_ref.context.device.clone();
|
let device = wgpu_executor_ref.context.device.clone();
|
||||||
|
|
||||||
let preferences = EditorPreferences {
|
let preferences = EditorPreferences {
|
||||||
vello_preference: graph_craft::wasm_application_io::VelloPreference::Auto,
|
|
||||||
max_render_region_size: EditorPreferences::default().max_render_region_size,
|
max_render_region_size: EditorPreferences::default().max_render_region_size,
|
||||||
};
|
};
|
||||||
let editor_api = Arc::new(WasmEditorApi {
|
let editor_api = Arc::new(WasmEditorApi {
|
||||||
|
|
|
||||||
|
|
@ -217,7 +217,6 @@ impl<T: NodeGraphUpdateSender> NodeGraphUpdateSender for std::sync::Mutex<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait GetEditorPreferences {
|
pub trait GetEditorPreferences {
|
||||||
fn use_vello(&self) -> bool;
|
|
||||||
fn max_render_region_area(&self) -> u32;
|
fn max_render_region_area(&self) -> u32;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -238,11 +237,11 @@ pub struct TimingInformation {
|
||||||
pub struct RenderConfig {
|
pub struct RenderConfig {
|
||||||
pub viewport: Footprint,
|
pub viewport: Footprint,
|
||||||
pub scale: f64,
|
pub scale: f64,
|
||||||
pub export_format: ExportFormat,
|
|
||||||
pub time: TimingInformation,
|
pub time: TimingInformation,
|
||||||
pub pointer: DVec2,
|
pub pointer: DVec2,
|
||||||
#[serde(alias = "view_mode")]
|
#[serde(alias = "view_mode")]
|
||||||
pub render_mode: RenderMode,
|
pub render_mode: RenderMode,
|
||||||
|
pub export_format: ExportFormat,
|
||||||
pub hide_artboards: bool,
|
pub hide_artboards: bool,
|
||||||
pub for_export: bool,
|
pub for_export: bool,
|
||||||
pub for_eyedropper: bool,
|
pub for_eyedropper: bool,
|
||||||
|
|
@ -259,10 +258,6 @@ impl NodeGraphUpdateSender for Logger {
|
||||||
struct DummyPreferences;
|
struct DummyPreferences;
|
||||||
|
|
||||||
impl GetEditorPreferences for DummyPreferences {
|
impl GetEditorPreferences for DummyPreferences {
|
||||||
fn use_vello(&self) -> bool {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
fn max_render_region_area(&self) -> u32 {
|
fn max_render_region_area(&self) -> u32 {
|
||||||
1024 * 1024
|
1024 * 1024
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,8 @@
|
||||||
use crate::renderer::{RenderParams, black_or_white_for_best_contrast, format_transform_matrix};
|
use crate::renderer::{RenderParams, format_transform_matrix};
|
||||||
use core_types::consts::LAYER_OUTLINE_STROKE_WEIGHT;
|
|
||||||
use core_types::uuid::generate_uuid;
|
use core_types::uuid::generate_uuid;
|
||||||
use glam::DAffine2;
|
use glam::DAffine2;
|
||||||
use graphic_types::vector_types::gradient::{Gradient, GradientType};
|
use graphic_types::vector_types::gradient::{Gradient, GradientType};
|
||||||
use graphic_types::vector_types::vector::style::{Fill, PaintOrder, PathStyle, RenderMode, Stroke, StrokeAlign, StrokeCap, StrokeJoin};
|
use graphic_types::vector_types::vector::style::{Fill, PaintOrder, PathStyle, Stroke, StrokeAlign, StrokeCap, StrokeJoin};
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
|
||||||
pub trait RenderExt {
|
pub trait RenderExt {
|
||||||
|
|
@ -14,7 +13,7 @@ pub trait RenderExt {
|
||||||
impl RenderExt for Gradient {
|
impl RenderExt for Gradient {
|
||||||
type Output = u64;
|
type Output = u64;
|
||||||
|
|
||||||
// /// Adds the gradient def through mutating the first argument, returning the gradient ID.
|
/// Adds the gradient def through mutating the first argument, returning the gradient ID.
|
||||||
fn render(&self, svg_defs: &mut String, element_transform: DAffine2, stroke_transform: DAffine2, bounds: DAffine2, transformed_bounds: DAffine2, _render_params: &RenderParams) -> Self::Output {
|
fn render(&self, svg_defs: &mut String, element_transform: DAffine2, stroke_transform: DAffine2, bounds: DAffine2, transformed_bounds: DAffine2, _render_params: &RenderParams) -> Self::Output {
|
||||||
let mut stop = String::new();
|
let mut stop = String::new();
|
||||||
for (position, color) in self.stops.0.iter() {
|
for (position, color) in self.stops.0.iter() {
|
||||||
|
|
@ -163,28 +162,12 @@ impl RenderExt for PathStyle {
|
||||||
/// Renders the shape's fill and stroke attributes as a string with them concatenated together.
|
/// Renders the shape's fill and stroke attributes as a string with them concatenated together.
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn render(&self, svg_defs: &mut String, element_transform: DAffine2, stroke_transform: DAffine2, bounds: DAffine2, transformed_bounds: DAffine2, render_params: &RenderParams) -> String {
|
fn render(&self, svg_defs: &mut String, element_transform: DAffine2, stroke_transform: DAffine2, bounds: DAffine2, transformed_bounds: DAffine2, render_params: &RenderParams) -> String {
|
||||||
let render_mode = render_params.render_mode;
|
let fill_attribute = self.fill.render(svg_defs, element_transform, stroke_transform, bounds, transformed_bounds, render_params);
|
||||||
match render_mode {
|
let stroke_attribute = self
|
||||||
RenderMode::Outline => {
|
.stroke
|
||||||
let fill_attribute = Fill::None.render(svg_defs, element_transform, stroke_transform, bounds, transformed_bounds, render_params);
|
.as_ref()
|
||||||
|
.map(|stroke| stroke.render(svg_defs, element_transform, stroke_transform, bounds, transformed_bounds, render_params))
|
||||||
let outline_color = black_or_white_for_best_contrast(render_params.artboard_background);
|
.unwrap_or_default();
|
||||||
let mut outline_stroke = Stroke::new(Some(outline_color), LAYER_OUTLINE_STROKE_WEIGHT);
|
format!("{fill_attribute}{stroke_attribute}")
|
||||||
// Outline strokes should be non-scaling by default
|
|
||||||
outline_stroke.non_scaling = true;
|
|
||||||
|
|
||||||
let stroke_attribute = outline_stroke.render(svg_defs, element_transform, stroke_transform, bounds, transformed_bounds, render_params);
|
|
||||||
format!("{fill_attribute}{stroke_attribute}")
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
let fill_attribute = self.fill.render(svg_defs, element_transform, stroke_transform, bounds, transformed_bounds, render_params);
|
|
||||||
let stroke_attribute = self
|
|
||||||
.stroke
|
|
||||||
.as_ref()
|
|
||||||
.map(|stroke| stroke.render(svg_defs, element_transform, stroke_transform, bounds, transformed_bounds, render_params))
|
|
||||||
.unwrap_or_default();
|
|
||||||
format!("{fill_attribute}{stroke_attribute}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -662,6 +662,6 @@ pub enum RenderMode {
|
||||||
Outline,
|
Outline,
|
||||||
// /// Render with normal coloration at the document resolution, showing the pixels when the current viewport resolution is higher
|
// /// Render with normal coloration at the document resolution, showing the pixels when the current viewport resolution is higher
|
||||||
// PixelPreview,
|
// PixelPreview,
|
||||||
// /// Render a preview of how the object would be exported as an SVG.
|
/// Render a preview of how the object would be exported as an SVG.
|
||||||
// SvgPreview,
|
SvgPreview,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue