diff --git a/node-graph/gcore/src/graphic_element.rs b/node-graph/gcore/src/graphic_element.rs index d2382053..88db48b7 100644 --- a/node-graph/gcore/src/graphic_element.rs +++ b/node-graph/gcore/src/graphic_element.rs @@ -212,41 +212,6 @@ impl BoundingBox for GraphicGroupTable { } } -impl<'de> serde::Deserialize<'de> for Raster { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - Ok(Raster::new_cpu(Image::deserialize(deserializer)?)) - } -} - -impl serde::Serialize for Raster { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - self.data().serialize(serializer) - } -} -impl<'de> serde::Deserialize<'de> for Raster { - fn deserialize(_deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - unimplemented!() - } -} - -impl serde::Serialize for Raster { - fn serialize(&self, _serializer: S) -> Result - where - S: serde::Serializer, - { - unimplemented!() - } -} - /// Some [`ArtboardData`] with some optional clipping bounds that can be exported. #[derive(Clone, Debug, Hash, PartialEq, DynAny, serde::Serialize, serde::Deserialize)] pub struct Artboard { diff --git a/node-graph/gcore/src/raster_types.rs b/node-graph/gcore/src/raster_types.rs index 937d89b2..cf6e83ea 100644 --- a/node-graph/gcore/src/raster_types.rs +++ b/node-graph/gcore/src/raster_types.rs @@ -6,136 +6,202 @@ use crate::raster::Image; use core::ops::Deref; use dyn_any::DynAny; use glam::{DAffine2, DVec2}; -#[cfg(feature = "wgpu")] -use std::sync::Arc; +use std::fmt::Debug; +use std::ops::DerefMut; -#[derive(Clone, Debug, Hash, PartialEq, Eq, Copy)] -pub struct CPU; -#[derive(Clone, Debug, Hash, PartialEq, Eq, Copy)] -pub struct GPU; +mod __private { + pub trait Sealed {} +} -trait Storage: 'static {} -impl Storage for CPU {} -impl Storage for GPU {} +pub trait Storage: __private::Sealed + Clone + Debug + 'static { + fn is_empty(&self) -> bool; +} -#[derive(Clone, Debug, Hash, PartialEq)] -#[allow(private_bounds)] -pub struct Raster { - data: RasterStorage, +#[derive(Clone, Debug, PartialEq, Hash, Default)] +pub struct Raster +where + Raster: Storage, +{ storage: T, } -unsafe impl dyn_any::StaticType for Raster { +unsafe impl dyn_any::StaticType for Raster +where + Raster: Storage, +{ type Static = Raster; } -#[derive(Clone, Debug, Hash, PartialEq, DynAny)] -pub enum RasterStorage { - Cpu(Image), - #[cfg(feature = "wgpu")] - Gpu(Arc), - #[cfg(not(feature = "wgpu"))] - Gpu(()), + +impl Raster +where + Raster: Storage, +{ + pub fn new(t: T) -> Self { + Self { storage: t } + } } -impl RasterStorage {} -impl Raster { - pub fn new_cpu(image: Image) -> Self { - Self { - data: RasterStorage::Cpu(image), - storage: CPU, - } - } - pub fn data(&self) -> &Image { - let RasterStorage::Cpu(cpu) = &self.data else { unreachable!() }; - cpu - } - pub fn data_mut(&mut self) -> &mut Image { - let RasterStorage::Cpu(cpu) = &mut self.data else { unreachable!() }; - cpu - } - pub fn into_data(self) -> Image { - let RasterStorage::Cpu(cpu) = self.data else { unreachable!() }; - cpu - } - pub fn is_empty(&self) -> bool { - let data = self.data(); - data.height == 0 || data.width == 0 - } -} -impl Default for Raster { - fn default() -> Self { - Self { - data: RasterStorage::Cpu(Image::default()), - storage: CPU, - } - } -} -impl Deref for Raster { - type Target = Image; +impl Deref for Raster +where + Raster: Storage, +{ + type Target = T; fn deref(&self) -> &Self::Target { - self.data() - } -} -#[cfg(feature = "wgpu")] -impl Raster { - pub fn new_gpu(image: Arc) -> Self { - Self { - data: RasterStorage::Gpu(image), - storage: GPU, - } - } - pub fn data(&self) -> &wgpu::Texture { - let RasterStorage::Gpu(gpu) = &self.data else { unreachable!() }; - gpu - } - pub fn data_mut(&mut self) -> &mut Arc { - let RasterStorage::Gpu(gpu) = &mut self.data else { unreachable!() }; - gpu - } - pub fn data_owned(&self) -> Arc { - let RasterStorage::Gpu(gpu) = &self.data else { unreachable!() }; - gpu.clone() + &self.storage } } -impl Raster { - #[cfg(feature = "wgpu")] - pub fn is_empty(&self) -> bool { - let data = self.data(); - data.width() == 0 || data.height() == 0 - } - #[cfg(not(feature = "wgpu"))] - pub fn is_empty(&self) -> bool { - true - } -} - -#[cfg(feature = "wgpu")] -impl Deref for Raster { - type Target = wgpu::Texture; - - fn deref(&self) -> &Self::Target { - self.data() +impl DerefMut for Raster +where + Raster: Storage, +{ + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.storage } } pub type RasterDataTable = Instances>; -// TODO: Make this not dupliated -impl BoundingBox for RasterDataTable { - fn bounding_box(&self, transform: DAffine2, _include_stroke: bool) -> Option<[DVec2; 2]> { - self.instance_ref_iter() - .filter(|instance| !instance.instance.is_empty()) // Eliminate empty images - .flat_map(|instance| { - let transform = transform * *instance.transform; - (transform.matrix2.determinant() != 0.).then(|| (transform * Quad::from_box([DVec2::ZERO, DVec2::ONE])).bounding_box()) - }) - .reduce(Quad::combine_bounds) +pub use cpu::CPU; + +mod cpu { + use super::*; + use crate::raster_types::__private::Sealed; + + #[derive(Clone, Debug, Default, PartialEq, Hash, DynAny)] + pub struct CPU(Image); + + impl Sealed for Raster {} + + impl Storage for Raster { + fn is_empty(&self) -> bool { + self.0.height == 0 || self.0.width == 0 + } + } + + impl Raster { + pub fn new_cpu(image: Image) -> Self { + Self::new(CPU(image)) + } + + pub fn data(&self) -> &Image { + self + } + + pub fn data_mut(&mut self) -> &mut Image { + self + } + + pub fn into_data(self) -> Image { + self.storage.0 + } + } + + impl Deref for CPU { + type Target = Image; + + fn deref(&self) -> &Self::Target { + &self.0 + } + } + + impl DerefMut for CPU { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + + impl<'de> serde::Deserialize<'de> for Raster { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + Ok(Raster::new_cpu(Image::deserialize(deserializer)?)) + } + } + + impl serde::Serialize for Raster { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + self.0.serialize(serializer) + } } } -impl BoundingBox for RasterDataTable { +pub use gpu::GPU; + +#[cfg(feature = "wgpu")] +mod gpu { + use super::*; + use crate::raster_types::__private::Sealed; + + #[derive(Clone, Debug, PartialEq, Hash)] + pub struct GPU { + texture: wgpu::Texture, + } + + impl Sealed for Raster {} + + impl Storage for Raster { + fn is_empty(&self) -> bool { + self.texture.width() == 0 || self.texture.height() == 0 + } + } + + impl Raster { + pub fn new_gpu(texture: wgpu::Texture) -> Self { + Self::new(GPU { texture }) + } + + pub fn data(&self) -> &wgpu::Texture { + &self.texture + } + } +} + +#[cfg(not(feature = "wgpu"))] +mod gpu { + use super::*; + + #[derive(Clone, Debug)] + pub struct GPU; + + impl Storage for Raster { + fn is_empty(&self) -> bool { + true + } + } +} + +mod gpu_common { + use super::*; + + impl<'de> serde::Deserialize<'de> for Raster { + fn deserialize(_deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + unimplemented!() + } + } + + impl serde::Serialize for Raster { + fn serialize(&self, _serializer: S) -> Result + where + S: serde::Serializer, + { + unimplemented!() + } + } +} + +impl BoundingBox for RasterDataTable +where + Raster: Storage, +{ fn bounding_box(&self, transform: DAffine2, _include_stroke: bool) -> Option<[DVec2; 2]> { self.instance_ref_iter() .filter(|instance| !instance.instance.is_empty()) // Eliminate empty images