mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-15 14:18:04 +08:00
Define data types for ID-based resource handling (#4168)
* Add resource lib * rename ResourceSource to ResourceInput * Rename ResourceInput -> DataSource and improve API * Review --------- Co-authored-by: Dennis Kobert <dennis@kobert.dev>
This commit is contained in:
12
Cargo.lock
generated
12
Cargo.lock
generated
@@ -1910,6 +1910,7 @@ dependencies = [
|
|||||||
"core-types",
|
"core-types",
|
||||||
"dyn-any",
|
"dyn-any",
|
||||||
"glam",
|
"glam",
|
||||||
|
"graphene-resource",
|
||||||
"log",
|
"log",
|
||||||
"serde",
|
"serde",
|
||||||
"text-nodes",
|
"text-nodes",
|
||||||
@@ -1989,6 +1990,17 @@ dependencies = [
|
|||||||
"syn 2.0.106",
|
"syn 2.0.106",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "graphene-resource"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"blake3",
|
||||||
|
"core-types",
|
||||||
|
"dyn-any",
|
||||||
|
"serde",
|
||||||
|
"url",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "graphene-std"
|
name = "graphene-std"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ graphene-hash = { path = "node-graph/libraries/graphene-hash", features = ["deri
|
|||||||
preprocessor = { path = "node-graph/preprocessor" }
|
preprocessor = { path = "node-graph/preprocessor" }
|
||||||
math-parser = { path = "libraries/math-parser" }
|
math-parser = { path = "libraries/math-parser" }
|
||||||
graphene-application-io = { path = "node-graph/libraries/application-io" }
|
graphene-application-io = { path = "node-graph/libraries/application-io" }
|
||||||
|
graphene-resource = { path = "node-graph/libraries/resources" }
|
||||||
core-types = { path = "node-graph/libraries/core-types" }
|
core-types = { path = "node-graph/libraries/core-types" }
|
||||||
no-std-types = { path = "node-graph/libraries/no-std-types" }
|
no-std-types = { path = "node-graph/libraries/no-std-types" }
|
||||||
raster-types = { path = "node-graph/libraries/raster-types" }
|
raster-types = { path = "node-graph/libraries/raster-types" }
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
use graph_craft::application_io::{PlatformApplicationIo, ResourceStorage};
|
use graph_craft::application_io::PlatformApplicationIo;
|
||||||
|
use graph_craft::application_io::resource::ResourceStorage;
|
||||||
use graphite_editor::application::{Editor, Environment, Host, Platform};
|
use graphite_editor::application::{Editor, Environment, Host, Platform};
|
||||||
use graphite_editor::messages::prelude::{FrontendMessage, Message};
|
use graphite_editor::messages::prelude::{FrontendMessage, Message};
|
||||||
use message_dispatcher::DesktopWrapperMessageDispatcher;
|
use message_dispatcher::DesktopWrapperMessageDispatcher;
|
||||||
use messages::{DesktopFrontendMessage, DesktopWrapperMessage};
|
use messages::{DesktopFrontendMessage, DesktopWrapperMessage};
|
||||||
|
|
||||||
pub use graph_craft::application_io::MmapResourceStorage;
|
pub use graph_craft::application_io::resource::MmapResourceStorage;
|
||||||
pub use graphite_editor::consts::{DOUBLE_CLICK_MILLISECONDS, FILE_EXTENSION};
|
pub use graphite_editor::consts::{DOUBLE_CLICK_MILLISECONDS, FILE_EXTENSION};
|
||||||
pub use wgpu_executor::WgpuContext;
|
pub use wgpu_executor::WgpuContext;
|
||||||
pub use wgpu_executor::WgpuContextBuilder;
|
pub use wgpu_executor::WgpuContextBuilder;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use crate::dispatcher::Dispatcher;
|
use crate::dispatcher::Dispatcher;
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
use graph_craft::application_io::{PlatformApplicationIo, ResourceStorage};
|
use graph_craft::application_io::PlatformApplicationIo;
|
||||||
|
use graph_craft::application_io::resource::ResourceStorage;
|
||||||
pub use graphene_std::uuid::*;
|
pub use graphene_std::uuid::*;
|
||||||
use std::sync::OnceLock;
|
use std::sync::OnceLock;
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use crate::messages::portfolio::utility_types::PanelType;
|
|||||||
use crate::messages::preferences::preferences_message_handler::PreferencesMessageContext;
|
use crate::messages::preferences::preferences_message_handler::PreferencesMessageContext;
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
use crate::messages::tool::common_functionality::utility_functions::make_path_editable_is_allowed;
|
use crate::messages::tool::common_functionality::utility_functions::make_path_editable_is_allowed;
|
||||||
use graph_craft::application_io::ResourceStorage;
|
use graph_craft::application_io::resource::ResourceStorage;
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct Dispatcher {
|
pub struct Dispatcher {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use std::path::PathBuf;
|
|||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use graph_craft::application_io::ResourceHash;
|
use graph_craft::application_io::resource::ResourceHash;
|
||||||
|
|
||||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||||
use crate::messages::portfolio::utility_types::WorkspacePanelLayout;
|
use crate::messages::portfolio::utility_types::WorkspacePanelLayout;
|
||||||
|
|||||||
@@ -30,7 +30,8 @@ use crate::messages::tool::tool_messages::tool_prelude::Key;
|
|||||||
use crate::messages::tool::utility_types::ToolType;
|
use crate::messages::tool::utility_types::ToolType;
|
||||||
use crate::node_graph_executor::NodeGraphExecutor;
|
use crate::node_graph_executor::NodeGraphExecutor;
|
||||||
use glam::{DAffine2, DVec2};
|
use glam::{DAffine2, DVec2};
|
||||||
use graph_craft::application_io::{ResourceHash, wgpu_available};
|
use graph_craft::application_io::resource::ResourceHash;
|
||||||
|
use graph_craft::application_io::wgpu_available;
|
||||||
use graph_craft::descriptor;
|
use graph_craft::descriptor;
|
||||||
use graph_craft::document::value::TaggedValue;
|
use graph_craft::document::value::TaggedValue;
|
||||||
use graph_craft::document::{NodeId, NodeInput, NodeNetwork, OldNodeNetwork};
|
use graph_craft::document::{NodeId, NodeInput, NodeNetwork, OldNodeNetwork};
|
||||||
|
|||||||
@@ -300,7 +300,7 @@ impl<'a> ModifyInputsContext<'a> {
|
|||||||
.default_node_template();
|
.default_node_template();
|
||||||
|
|
||||||
let png_bytes: std::sync::Arc<[u8]> = image.to_png().into();
|
let png_bytes: std::sync::Arc<[u8]> = image.to_png().into();
|
||||||
let hash = graphene_std::application_io::ResourceHash::from(png_bytes.as_ref());
|
let hash = graphene_std::application_io::resource::ResourceHash::from(png_bytes.as_ref());
|
||||||
self.responses.add(ResourceMessage::Store { data: png_bytes });
|
self.responses.add(ResourceMessage::Store { data: png_bytes });
|
||||||
|
|
||||||
let image_node = resolve_proto_node_type(graphene_std::raster_nodes::std_nodes::image::IDENTIFIER)
|
let image_node = resolve_proto_node_type(graphene_std::raster_nodes::std_nodes::image::IDENTIFIER)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use base64::Engine;
|
use base64::Engine;
|
||||||
use base64::engine::general_purpose::STANDARD as BASE64;
|
use base64::engine::general_purpose::STANDARD as BASE64;
|
||||||
use graph_craft::application_io::{Resource, ResourceHash};
|
use graph_craft::application_io::resource::{Resource, ResourceHash};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ use crate::messages::tool::tool_messages::tool_prelude::NumberInputMode;
|
|||||||
use deserialization::deserialize_node_persistent_metadata;
|
use deserialization::deserialize_node_persistent_metadata;
|
||||||
use glam::{DAffine2, DVec2, IVec2};
|
use glam::{DAffine2, DVec2, IVec2};
|
||||||
use graph_craft::Type;
|
use graph_craft::Type;
|
||||||
use graph_craft::application_io::ResourceHash;
|
use graph_craft::application_io::resource::ResourceHash;
|
||||||
use graph_craft::document::value::TaggedValue;
|
use graph_craft::document::value::TaggedValue;
|
||||||
use graph_craft::document::{DocumentNode, DocumentNodeImplementation, NodeId, NodeInput, NodeNetwork, OldDocumentNodeImplementation, OldNodeNetwork};
|
use graph_craft::document::{DocumentNode, DocumentNodeImplementation, NodeId, NodeInput, NodeNetwork, OldDocumentNodeImplementation, OldNodeNetwork};
|
||||||
use graphene_std::ContextDependencies;
|
use graphene_std::ContextDependencies;
|
||||||
|
|||||||
@@ -1597,7 +1597,7 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId],
|
|||||||
});
|
});
|
||||||
|
|
||||||
if let Some(image) = image {
|
if let Some(image) = image {
|
||||||
let hash = document.embedded_resources.store(graphene_std::application_io::Resource::new(image.to_png()));
|
let hash = document.embedded_resources.store(graphene_std::application_io::resource::Resource::new(image.to_png()));
|
||||||
|
|
||||||
let mut node_template = resolve_document_node_type(&reference)?.default_node_template();
|
let mut node_template = resolve_document_node_type(&reference)?.default_node_template();
|
||||||
document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
|
document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ use crate::messages::tool::utility_types::{HintData, ToolType};
|
|||||||
use crate::messages::viewport::ToPhysical;
|
use crate::messages::viewport::ToPhysical;
|
||||||
use crate::node_graph_executor::{ExportConfig, NodeGraphExecutor};
|
use crate::node_graph_executor::{ExportConfig, NodeGraphExecutor};
|
||||||
use glam::{DAffine2, DVec2};
|
use glam::{DAffine2, DVec2};
|
||||||
use graph_craft::application_io::ResourceHash;
|
use graph_craft::application_io::resource::ResourceHash;
|
||||||
use graph_craft::document::NodeId;
|
use graph_craft::document::NodeId;
|
||||||
use graphene_std::Color;
|
use graphene_std::Color;
|
||||||
use graphene_std::raster_types::Image;
|
use graphene_std::raster_types::Image;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
use graph_craft::application_io::ResourceHash;
|
use graph_craft::application_io::resource::ResourceHash;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
#[impl_message(Message, Resource)]
|
#[impl_message(Message, Resource)]
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
use graph_craft::application_io::{LoadResource, ResourceFuture, ResourceHash, ResourceStorage};
|
use graph_craft::application_io::resource::{LoadResource, ResourceFuture, ResourceHash, ResourceStorage};
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@@ -48,7 +48,7 @@ impl Default for ResourceMessageHandler {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
storage: Some(Arc::new(RwLock::new(Box::new(graph_craft::application_io::HashMapResourceStorage::new())))),
|
storage: Some(Arc::new(RwLock::new(Box::new(graph_craft::application_io::resource::HashMapResourceStorage::new())))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,8 +23,6 @@ use editor::messages::portfolio::document::utility_types::network_interface::Imp
|
|||||||
use editor::messages::portfolio::utility_types::{DockingSplitDirection, FontCatalog, FontCatalogFamily, PanelGroupId, PanelType};
|
use editor::messages::portfolio::utility_types::{DockingSplitDirection, FontCatalog, FontCatalogFamily, PanelGroupId, PanelType};
|
||||||
use editor::messages::prelude::*;
|
use editor::messages::prelude::*;
|
||||||
use editor::messages::tool::tool_messages::tool_prelude::WidgetId;
|
use editor::messages::tool::tool_messages::tool_prelude::WidgetId;
|
||||||
#[cfg(all(not(feature = "native"), target_family = "wasm"))]
|
|
||||||
use graph_craft::application_io::OpfsResourceStorage;
|
|
||||||
use graph_craft::document::NodeId;
|
use graph_craft::document::NodeId;
|
||||||
use graphene_std::color::SRGBA8;
|
use graphene_std::color::SRGBA8;
|
||||||
use graphene_std::graphene_hash::CacheHashWrapper;
|
use graphene_std::graphene_hash::CacheHashWrapper;
|
||||||
@@ -75,6 +73,7 @@ impl EditorWrapper {
|
|||||||
#[cfg(all(not(feature = "native"), target_family = "wasm"))]
|
#[cfg(all(not(feature = "native"), target_family = "wasm"))]
|
||||||
pub async fn create(platform: String, uuid_random_seed: u64, frontend_message_handler_callback: js_sys::Function) -> EditorWrapper {
|
pub async fn create(platform: String, uuid_random_seed: u64, frontend_message_handler_callback: js_sys::Function) -> EditorWrapper {
|
||||||
use graph_craft::application_io::PlatformApplicationIo;
|
use graph_craft::application_io::PlatformApplicationIo;
|
||||||
|
use graph_craft::application_io::resource::*;
|
||||||
|
|
||||||
let host = match platform.as_str() {
|
let host = match platform.as_str() {
|
||||||
"Linux" => Host::Linux,
|
"Linux" => Host::Linux,
|
||||||
@@ -83,11 +82,11 @@ impl EditorWrapper {
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let storage: Box<dyn graph_craft::application_io::ResourceStorage> = match OpfsResourceStorage::load("resources").await {
|
let storage: Box<dyn ResourceStorage> = match OpfsResourceStorage::load("resources").await {
|
||||||
Ok(storage) => Box::new(storage),
|
Ok(storage) => Box::new(storage),
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
log::error!("Failed to open OPFS resource storage, falling back to in-memory: {error:?}");
|
log::error!("Failed to open OPFS resource storage, falling back to in-memory: {error:?}");
|
||||||
Box::new(graph_craft::application_io::HashMapResourceStorage::new())
|
Box::new(graph_craft::application_io::resource::HashMapResourceStorage::new())
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -4,18 +4,13 @@ use wgpu_executor::WgpuExecutor;
|
|||||||
|
|
||||||
pub mod resource;
|
pub mod resource;
|
||||||
|
|
||||||
pub use graphene_application_io::{ApplicationIo, LoadResource, Resource, ResourceFuture, ResourceHash, ResourceStorage};
|
pub use graphene_application_io::ApplicationIo;
|
||||||
pub use resource::HashMapResourceStorage;
|
|
||||||
#[cfg(not(target_family = "wasm"))]
|
|
||||||
pub use resource::mmap::MmapResourceStorage;
|
|
||||||
#[cfg(target_family = "wasm")]
|
|
||||||
pub use resource::opfs::OpfsResourceStorage;
|
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct PlatformApplicationIo {
|
pub struct PlatformApplicationIo {
|
||||||
#[cfg(feature = "wgpu")]
|
#[cfg(feature = "wgpu")]
|
||||||
pub(crate) gpu_executor: Option<WgpuExecutor>,
|
pub(crate) gpu_executor: Option<WgpuExecutor>,
|
||||||
resources: Option<Box<dyn LoadResource>>,
|
resources: Option<Box<dyn resource::LoadResource>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PlatformApplicationIo {
|
impl PlatformApplicationIo {
|
||||||
@@ -49,7 +44,7 @@ impl PlatformApplicationIo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn inject_resource_proxy(&mut self, resources: Box<dyn LoadResource>) {
|
pub fn inject_resource_proxy(&mut self, resources: Box<dyn resource::LoadResource>) {
|
||||||
self.resources = Some(resources);
|
self.resources = Some(resources);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -65,7 +60,7 @@ impl ApplicationIo for PlatformApplicationIo {
|
|||||||
self.gpu_executor.as_ref()
|
self.gpu_executor.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_resource(&self, hash: ResourceHash) -> graphene_application_io::ResourceFuture {
|
fn load_resource(&self, hash: resource::ResourceHash) -> resource::ResourceFuture {
|
||||||
self.resources.as_ref().expect("Resource storage not initialized").load(hash)
|
self.resources.as_ref().expect("Resource storage not initialized").load(hash)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,16 @@
|
|||||||
#[cfg(not(target_family = "wasm"))]
|
|
||||||
pub mod mmap;
|
|
||||||
#[cfg(target_family = "wasm")]
|
|
||||||
pub mod opfs;
|
|
||||||
|
|
||||||
use graphene_application_io::{LoadResource, Resource, ResourceFuture, ResourceHash, ResourceStorage};
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
|
pub use graphene_application_io::resource::{LoadResource, Resource, ResourceFuture, ResourceHash, ResourceStorage};
|
||||||
|
#[cfg(not(target_family = "wasm"))]
|
||||||
|
pub mod mmap;
|
||||||
|
#[cfg(not(target_family = "wasm"))]
|
||||||
|
pub use mmap::MmapResourceStorage;
|
||||||
|
#[cfg(target_family = "wasm")]
|
||||||
|
pub mod opfs;
|
||||||
|
#[cfg(target_family = "wasm")]
|
||||||
|
pub use opfs::OpfsResourceStorage;
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct HashMapResourceStorage {
|
pub struct HashMapResourceStorage {
|
||||||
resources: Mutex<HashMap<ResourceHash, Resource>>,
|
resources: Mutex<HashMap<ResourceHash, Resource>>,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use graphene_application_io::{LoadResource, Resource, ResourceFuture, ResourceHash, ResourceStorage};
|
use graphene_application_io::resource::{LoadResource, Resource, ResourceFuture, ResourceHash, ResourceStorage};
|
||||||
use mmap_io::mmap::{MemoryMappedFile, MmapMode};
|
use mmap_io::mmap::{MemoryMappedFile, MmapMode};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use graphene_application_io::{LoadResource, Resource, ResourceFuture, ResourceHash, ResourceStorage};
|
use graphene_application_io::resource::{LoadResource, Resource, ResourceFuture, ResourceHash, ResourceStorage};
|
||||||
use js_sys::Uint8Array;
|
use js_sys::Uint8Array;
|
||||||
use std::collections::{HashMap, HashSet, VecDeque};
|
use std::collections::{HashMap, HashSet, VecDeque};
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|||||||
@@ -396,7 +396,7 @@ tagged_value! {
|
|||||||
Footprint(Footprint),
|
Footprint(Footprint),
|
||||||
VectorModification(Box<VectorModification>),
|
VectorModification(Box<VectorModification>),
|
||||||
ImageData(Image<Color>),
|
ImageData(Image<Color>),
|
||||||
Resource(graphene_application_io::ResourceHash),
|
Resource(graphene_application_io::resource::ResourceHash),
|
||||||
// ==========
|
// ==========
|
||||||
// ENUM TYPES
|
// ENUM TYPES
|
||||||
// ==========
|
// ==========
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
|
|||||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => u64]),
|
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => u64]),
|
||||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => BlendMode]),
|
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => BlendMode]),
|
||||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => ImageTexture]),
|
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => ImageTexture]),
|
||||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_std::application_io::Resource]),
|
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_std::application_io::resource::Resource]),
|
||||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_std::transform::ReferencePoint]),
|
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_std::transform::ReferencePoint]),
|
||||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_std::vector::misc::BooleanOperation]),
|
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_std::vector::misc::BooleanOperation]),
|
||||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_std::vector::style::Fill]),
|
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_std::vector::style::Fill]),
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["serde"]
|
default = ["serde"]
|
||||||
serde = ["dep:serde", "core-types/serde", "vector-types/serde", "text-nodes/serde"]
|
serde = ["dep:serde", "core-types/serde", "vector-types/serde", "text-nodes/serde", "graphene-resource/serde"]
|
||||||
wasm = ["dep:web-sys"]
|
wasm = ["dep:web-sys"]
|
||||||
wgpu = ["dep:wgpu"]
|
wgpu = ["dep:wgpu"]
|
||||||
|
|
||||||
@@ -18,6 +18,7 @@ dyn-any = { workspace = true }
|
|||||||
core-types = { workspace = true }
|
core-types = { workspace = true }
|
||||||
vector-types = { workspace = true }
|
vector-types = { workspace = true }
|
||||||
text-nodes = { workspace = true }
|
text-nodes = { workspace = true }
|
||||||
|
graphene-resource = { workspace = true }
|
||||||
|
|
||||||
# Workspace dependencies
|
# Workspace dependencies
|
||||||
blake3 = { workspace = true }
|
blake3 = { workspace = true }
|
||||||
|
|||||||
@@ -9,9 +9,10 @@ use std::time::Duration;
|
|||||||
use text_nodes::FontCache;
|
use text_nodes::FontCache;
|
||||||
use vector_types::vector::style::RenderMode;
|
use vector_types::vector::style::RenderMode;
|
||||||
|
|
||||||
pub mod resource;
|
pub mod resource {
|
||||||
pub use core_types::resource::Resource;
|
pub use core_types::resource::*;
|
||||||
pub use resource::{LoadResource, ResourceFuture, ResourceHash, ResourceStorage};
|
pub use graphene_resource::*;
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "wgpu")]
|
#[cfg(feature = "wgpu")]
|
||||||
#[derive(Debug, Clone, Hash, PartialEq, Eq, DynAny)]
|
#[derive(Debug, Clone, Hash, PartialEq, Eq, DynAny)]
|
||||||
@@ -49,7 +50,7 @@ pub trait ApplicationIo {
|
|||||||
fn gpu_executor(&self) -> Option<&Self::Executor> {
|
fn gpu_executor(&self) -> Option<&Self::Executor> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
fn load_resource(&self, hash: ResourceHash) -> resource::ResourceFuture;
|
fn load_resource(&self, hash: resource::ResourceHash) -> resource::ResourceFuture;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: ApplicationIo> ApplicationIo for &T {
|
impl<T: ApplicationIo> ApplicationIo for &T {
|
||||||
@@ -59,7 +60,7 @@ impl<T: ApplicationIo> ApplicationIo for &T {
|
|||||||
(**self).gpu_executor()
|
(**self).gpu_executor()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_resource(&self, hash: ResourceHash) -> resource::ResourceFuture {
|
fn load_resource(&self, hash: resource::ResourceHash) -> resource::ResourceFuture {
|
||||||
(**self).load_resource(hash)
|
(**self).load_resource(hash)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,8 +68,8 @@ mod uuid_generation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
#[cfg_attr(feature = "wasm", derive(tsify::Tsify), tsify(large_number_types_as_bigints))]
|
|
||||||
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash, graphene_hash::CacheHash, PartialOrd, Ord, DynAny)]
|
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash, graphene_hash::CacheHash, PartialOrd, Ord, DynAny)]
|
||||||
|
#[cfg_attr(feature = "wasm", derive(tsify::Tsify), tsify(large_number_types_as_bigints))]
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
pub struct NodeId(pub u64);
|
pub struct NodeId(pub u64);
|
||||||
|
|
||||||
|
|||||||
23
node-graph/libraries/resources/Cargo.toml
Normal file
23
node-graph/libraries/resources/Cargo.toml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
[package]
|
||||||
|
name = "graphene-resource"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
description = "graphene resource interface"
|
||||||
|
authors = ["Graphite Authors <contact@graphite.art>"]
|
||||||
|
license = "MIT OR Apache-2.0"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["serde"]
|
||||||
|
serde = ["dep:serde", "url/serde"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
# Local dependencies
|
||||||
|
dyn-any = { workspace = true }
|
||||||
|
core-types = { workspace = true }
|
||||||
|
|
||||||
|
# Workspace dependencies
|
||||||
|
blake3 = { workspace = true }
|
||||||
|
url = { workspace = true }
|
||||||
|
|
||||||
|
# Optional workspace dependencies
|
||||||
|
serde = { workspace = true, optional = true }
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
use core_types::CacheHash;
|
|
||||||
use core_types::resource::Resource;
|
use core_types::resource::Resource;
|
||||||
|
use core_types::{CacheHash, graphene_hash};
|
||||||
use dyn_any::DynAny;
|
use dyn_any::DynAny;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
@@ -18,6 +19,23 @@ pub trait ResourceStorage: LoadResource {
|
|||||||
fn garbage_collect(&mut self, used: &[ResourceHash]);
|
fn garbage_collect(&mut self, used: &[ResourceHash]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[repr(transparent)]
|
||||||
|
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash, graphene_hash::CacheHash, PartialOrd, Ord, DynAny)]
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
pub struct ResourceId(pub u64);
|
||||||
|
|
||||||
|
impl ResourceId {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self(core_types::uuid::generate_uuid())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for ResourceId {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{}", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Blake3 content hash of a resource, represented as 32 bytes
|
/// Blake3 content hash of a resource, represented as 32 bytes
|
||||||
#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord, DynAny)]
|
#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord, DynAny)]
|
||||||
pub struct ResourceHash([u8; 32]);
|
pub struct ResourceHash([u8; 32]);
|
||||||
@@ -166,3 +184,86 @@ impl CacheHash for ResourceHash {
|
|||||||
core::hash::Hash::hash(self, state);
|
core::hash::Hash::hash(self, state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct ResourceInfo {
|
||||||
|
pub id: ResourceId,
|
||||||
|
pub hash: Option<ResourceHash>,
|
||||||
|
pub inputs: DataSources,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type DataSources = Box<[DataSource]>;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
pub enum DataSource {
|
||||||
|
Embedded,
|
||||||
|
Url(url::Url),
|
||||||
|
Font { family: String, style: Option<String> },
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
pub struct ResourceRegistry {
|
||||||
|
hashes: HashMap<ResourceId, ResourceHash>,
|
||||||
|
sources: HashMap<ResourceId, Vec<DataSource>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ResourceRegistry {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.hashes.is_empty() && self.sources.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn contains(&self, id: &ResourceId) -> bool {
|
||||||
|
self.hashes.contains_key(id) || self.sources.contains_key(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ids(&self) -> impl Iterator<Item = ResourceId> + '_ {
|
||||||
|
self.hashes.keys().chain(self.sources.keys().filter(|id| !self.hashes.contains_key(id))).copied()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn info(&self, id: &ResourceId) -> Option<ResourceInfo> {
|
||||||
|
self.contains(id).then(|| ResourceInfo {
|
||||||
|
id: *id,
|
||||||
|
hash: self.hashes.get(id).copied(),
|
||||||
|
inputs: self.sources.get(id).cloned().unwrap_or_default().into_boxed_slice(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_source_back(&mut self, id: &ResourceId, source: DataSource) {
|
||||||
|
self.sources.entry(*id).or_default().push(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_source_front(&mut self, id: &ResourceId, source: DataSource) {
|
||||||
|
self.sources.entry(*id).or_default().insert(0, source);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn delete(&mut self, id: &ResourceId) -> Option<ResourceInfo> {
|
||||||
|
let hash = self.hashes.remove(id);
|
||||||
|
let sources = self.sources.remove(id);
|
||||||
|
if hash.is_none() && sources.is_none() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(ResourceInfo {
|
||||||
|
id: *id,
|
||||||
|
hash,
|
||||||
|
inputs: sources.unwrap_or_default().into_boxed_slice(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn resolve(&mut self, id: &ResourceId, hash: ResourceHash) -> Option<ResourceHash> {
|
||||||
|
self.hashes.insert(*id, hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn hash(&self, id: &ResourceId) -> Option<ResourceHash> {
|
||||||
|
self.hashes.get(id).copied()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unresolved(&self) -> impl Iterator<Item = (ResourceId, &[DataSource])> + '_ {
|
||||||
|
self.sources.iter().filter(|(id, _)| !self.hashes.contains_key(id)).map(|(id, sources)| (*id, sources.as_slice()))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,6 +11,7 @@ use core_types::transform::Footprint;
|
|||||||
#[cfg(target_family = "wasm")]
|
#[cfg(target_family = "wasm")]
|
||||||
use core_types::{ATTR_EDITOR_MERGED_LAYERS, ATTR_TRANSFORM, WasmNotSend};
|
use core_types::{ATTR_EDITOR_MERGED_LAYERS, ATTR_TRANSFORM, WasmNotSend};
|
||||||
use core_types::{Color, Ctx};
|
use core_types::{Color, Ctx};
|
||||||
|
pub use graph_craft::application_io::resource::{Resource, ResourceHash};
|
||||||
pub use graph_craft::application_io::*;
|
pub use graph_craft::application_io::*;
|
||||||
pub use graph_craft::document::value::RenderOutputType;
|
pub use graph_craft::document::value::RenderOutputType;
|
||||||
#[cfg(target_family = "wasm")]
|
#[cfg(target_family = "wasm")]
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ pub fn expand_network(network: &mut NodeNetwork, substitutions: &HashMap<ProtoNo
|
|||||||
|
|
||||||
/// Replace every `TaggedValue::Resource(hash)` input with a reference to a freshly inserted `resource` proto node.
|
/// Replace every `TaggedValue::Resource(hash)` input with a reference to a freshly inserted `resource` proto node.
|
||||||
fn replace_resource_inputs(network: &mut NodeNetwork) {
|
fn replace_resource_inputs(network: &mut NodeNetwork) {
|
||||||
let mut hash_to_node_id: HashMap<application_io::ResourceHash, NodeId> = HashMap::new();
|
let mut hash_to_node_id: HashMap<graph_craft::application_io::resource::ResourceHash, NodeId> = HashMap::new();
|
||||||
let mut new_resource_nodes: Vec<(NodeId, DocumentNode)> = Vec::new();
|
let mut new_resource_nodes: Vec<(NodeId, DocumentNode)> = Vec::new();
|
||||||
|
|
||||||
for node in network.nodes.values_mut() {
|
for node in network.nodes.values_mut() {
|
||||||
|
|||||||
Reference in New Issue
Block a user