Files
Graphite/node-graph/libraries/application-io/src/lib.rs
2026-07-31 23:19:42 +02:00

162 lines
4.7 KiB
Rust

use core_types::transform::Footprint;
use dyn_any::{DynAny, StaticType, StaticTypeSized};
use glam::DVec2;
use std::fmt::Debug;
use std::hash::{Hash, Hasher};
use std::ptr::addr_of;
use std::sync::Arc;
use std::time::Duration;
use vector_types::vector::style::RenderMode;
pub use graphene_resource as resource;
#[cfg(feature = "wgpu")]
pub use raster_types::Texture;
#[cfg(not(feature = "wgpu"))]
#[derive(Debug, Clone, Hash, PartialEq, Eq, DynAny)]
pub struct Texture; // TODO: Consider removing this
pub trait ApplicationIo {
type Executor;
fn gpu_executor(&self) -> Option<&Self::Executor> {
None
}
fn gpu_executor_arc(&self) -> Option<Arc<Self::Executor>> {
None
}
fn load_resource(&self, hash: resource::ResourceHash) -> resource::ResourceFuture<'_>;
}
impl<T: ApplicationIo> ApplicationIo for &T {
type Executor = T::Executor;
fn gpu_executor(&self) -> Option<&T::Executor> {
(**self).gpu_executor()
}
fn gpu_executor_arc(&self) -> Option<Arc<T::Executor>> {
(**self).gpu_executor_arc()
}
fn load_resource(&self, hash: resource::ResourceHash) -> resource::ResourceFuture<'_> {
(**self).load_resource(hash)
}
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum NodeGraphUpdateMessage {}
pub trait NodeGraphUpdateSender {
fn send(&self, message: NodeGraphUpdateMessage);
}
impl<T: NodeGraphUpdateSender> NodeGraphUpdateSender for std::sync::Mutex<T> {
fn send(&self, message: NodeGraphUpdateMessage) {
self.lock().as_mut().unwrap().send(message)
}
}
pub trait GetEditorPreferences {
fn max_render_region_area(&self) -> u32;
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, graphene_hash::CacheHash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ExportFormat {
#[default]
Svg,
Raster,
}
#[derive(Debug, Default, Clone, Copy, PartialEq, DynAny, graphene_hash::CacheHash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TimingInformation {
pub time: f64,
pub animation_time: Duration,
}
#[derive(Debug, Default, Clone, Copy, PartialEq, DynAny, graphene_hash::CacheHash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct RenderConfig {
pub viewport: Footprint,
pub scale: f64,
pub time: TimingInformation,
pub pointer: DVec2,
#[cfg_attr(feature = "serde", serde(alias = "view_mode"))]
pub render_mode: RenderMode,
pub export_format: ExportFormat,
pub for_export: bool,
pub for_eyedropper: bool,
}
struct Logger;
impl NodeGraphUpdateSender for Logger {
fn send(&self, message: NodeGraphUpdateMessage) {
log::warn!("dispatching message with fallback node graph update sender {message:?}");
}
}
struct DummyPreferences;
impl GetEditorPreferences for DummyPreferences {
fn max_render_region_area(&self) -> u32 {
1024 * 1024
}
}
pub struct EditorApi<Io> {
/// Gives access to APIs like resources.
pub application_io: Option<Arc<Io>>,
pub node_graph_message_sender: Box<dyn NodeGraphUpdateSender + Send + Sync>,
/// Editor preferences made available to the graph through the `PlatformEditorApi`.
pub editor_preferences: Box<dyn GetEditorPreferences + Send + Sync>,
pub runtime: core_types::runtime::RuntimeHandle,
}
impl<Io> Eq for EditorApi<Io> {}
impl<Io: Default> Default for EditorApi<Io> {
fn default() -> Self {
Self {
application_io: None,
node_graph_message_sender: Box::new(Logger),
editor_preferences: Box::new(DummyPreferences),
runtime: Default::default(),
}
}
}
impl<Io> Hash for EditorApi<Io> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.application_io.as_ref().map_or(0, |io| io as *const _ as usize).hash(state);
(self.node_graph_message_sender.as_ref() as *const dyn NodeGraphUpdateSender).hash(state);
(self.editor_preferences.as_ref() as *const dyn GetEditorPreferences).hash(state);
}
}
impl<Io> core_types::graphene_hash::CacheHash for EditorApi<Io> {
fn cache_hash<H: core::hash::Hasher>(&self, state: &mut H) {
core::hash::Hash::hash(self, state);
}
}
impl<Io> PartialEq for EditorApi<Io> {
fn eq(&self, other: &Self) -> bool {
self.application_io.as_ref().map_or(0, |io| addr_of!(io) as usize) == other.application_io.as_ref().map_or(0, |io| addr_of!(io) as usize)
&& std::ptr::eq(self.node_graph_message_sender.as_ref() as *const _, other.node_graph_message_sender.as_ref() as *const _)
&& std::ptr::eq(self.editor_preferences.as_ref() as *const _, other.editor_preferences.as_ref() as *const _)
}
}
impl<T> Debug for EditorApi<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("EditorApi").finish()
}
}
unsafe impl<T: StaticTypeSized> StaticType for EditorApi<T> {
type Static = EditorApi<T::Static>;
}