Instance tables refactor part 3: flatten ImageFrame<P> in lieu of Image<P> (#2256)
* Remove ImageFrame<T> by flattening it into Image<T> * Rename TextureFrame to ImageTexture * Fix tests
This commit is contained in:
parent
f1160e1ca6
commit
2f6c6e28f0
|
|
@ -28,7 +28,7 @@ use crate::node_graph_executor::NodeGraphExecutor;
|
||||||
use bezier_rs::Subpath;
|
use bezier_rs::Subpath;
|
||||||
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};
|
||||||
use graphene_core::raster::image::{ImageFrame, ImageFrameTable};
|
use graphene_core::raster::image::ImageFrameTable;
|
||||||
use graphene_core::raster::BlendMode;
|
use graphene_core::raster::BlendMode;
|
||||||
use graphene_core::vector::style::ViewMode;
|
use graphene_core::vector::style::ViewMode;
|
||||||
use graphene_std::renderer::{ClickTarget, Quad};
|
use graphene_std::renderer::{ClickTarget, Quad};
|
||||||
|
|
@ -818,7 +818,7 @@ impl MessageHandler<DocumentMessage, DocumentMessageData<'_>> for DocumentMessag
|
||||||
|
|
||||||
responses.add(DocumentMessage::AddTransaction);
|
responses.add(DocumentMessage::AddTransaction);
|
||||||
|
|
||||||
let layer = graph_modification_utils::new_image_layer(ImageFrameTable::new(ImageFrame { image }), layer_node_id, self.new_layer_parent(true), responses);
|
let layer = graph_modification_utils::new_image_layer(ImageFrameTable::new(image), layer_node_id, self.new_layer_parent(true), responses);
|
||||||
|
|
||||||
if let Some(name) = name {
|
if let Some(name) = name {
|
||||||
responses.add(NodeGraphMessage::SetDisplayName {
|
responses.add(NodeGraphMessage::SetDisplayName {
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ use graphene_core::raster::{
|
||||||
use graphene_core::text::Font;
|
use graphene_core::text::Font;
|
||||||
use graphene_core::vector::misc::CentroidType;
|
use graphene_core::vector::misc::CentroidType;
|
||||||
use graphene_core::vector::style::{GradientType, LineCap, LineJoin};
|
use graphene_core::vector::style::{GradientType, LineCap, LineJoin};
|
||||||
use graphene_std::application_io::TextureFrame;
|
use graphene_std::application_io::TextureFrameTable;
|
||||||
use graphene_std::transform::Footprint;
|
use graphene_std::transform::Footprint;
|
||||||
use graphene_std::vector::misc::BooleanOperation;
|
use graphene_std::vector::misc::BooleanOperation;
|
||||||
use graphene_std::vector::style::{Fill, FillChoice, FillType, GradientStops};
|
use graphene_std::vector::style::{Fill, FillChoice, FillType, GradientStops};
|
||||||
|
|
@ -159,7 +159,7 @@ pub(crate) fn property_from_type(
|
||||||
Some(x) if x == TypeId::of::<Curve>() => curves_widget(document_node, node_id, index, name, true),
|
Some(x) if x == TypeId::of::<Curve>() => curves_widget(document_node, node_id, index, name, true),
|
||||||
Some(x) if x == TypeId::of::<GradientStops>() => color_widget(document_node, node_id, index, name, ColorInput::default().allow_none(false), true),
|
Some(x) if x == TypeId::of::<GradientStops>() => color_widget(document_node, node_id, index, name, ColorInput::default().allow_none(false), true),
|
||||||
Some(x) if x == TypeId::of::<VectorDataTable>() => vector_widget(document_node, node_id, index, name, true).into(),
|
Some(x) if x == TypeId::of::<VectorDataTable>() => vector_widget(document_node, node_id, index, name, true).into(),
|
||||||
Some(x) if x == TypeId::of::<RasterFrame>() || x == TypeId::of::<ImageFrameTable<Color>>() || x == TypeId::of::<TextureFrame>() => {
|
Some(x) if x == TypeId::of::<RasterFrame>() || x == TypeId::of::<ImageFrameTable<Color>>() || x == TypeId::of::<TextureFrameTable>() => {
|
||||||
raster_widget(document_node, node_id, index, name, true).into()
|
raster_widget(document_node, node_id, index, name, true).into()
|
||||||
}
|
}
|
||||||
Some(x) if x == TypeId::of::<GraphicGroupTable>() => group_widget(document_node, node_id, index, name, true).into(),
|
Some(x) if x == TypeId::of::<GraphicGroupTable>() => group_widget(document_node, node_id, index, name, true).into(),
|
||||||
|
|
|
||||||
|
|
@ -6222,10 +6222,11 @@ impl PropertiesRow {
|
||||||
fn migrate_output_names<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result<Vec<String>, D::Error> {
|
fn migrate_output_names<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result<Vec<String>, D::Error> {
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
const REPLACEMENTS: [(&str, &str); 3] = [
|
const REPLACEMENTS: [(&str, &str); 4] = [
|
||||||
("VectorData", "Instances<VectorData>"),
|
("VectorData", "Instances<VectorData>"),
|
||||||
("GraphicGroup", "Instances<GraphicGroup>"),
|
("GraphicGroup", "Instances<GraphicGroup>"),
|
||||||
("ImageFrame", "Instances<ImageFrame>"),
|
("ImageFrame", "Instances<Image>"),
|
||||||
|
("Instances<ImageFrame>", "Instances<Image>"),
|
||||||
];
|
];
|
||||||
|
|
||||||
let mut names = Vec::<String>::deserialize(deserializer)?;
|
let mut names = Vec::<String>::deserialize(deserializer)?;
|
||||||
|
|
|
||||||
|
|
@ -64,17 +64,18 @@ impl Size for web_sys::HtmlCanvasElement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type TextureFrameTable = Instances<TextureFrame>;
|
// TODO: Rename to ImageTextureTable
|
||||||
|
pub type TextureFrameTable = Instances<ImageTexture>;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct TextureFrame {
|
pub struct ImageTexture {
|
||||||
#[cfg(feature = "wgpu")]
|
#[cfg(feature = "wgpu")]
|
||||||
pub texture: Arc<wgpu::Texture>,
|
pub texture: Arc<wgpu::Texture>,
|
||||||
#[cfg(not(feature = "wgpu"))]
|
#[cfg(not(feature = "wgpu"))]
|
||||||
pub texture: (),
|
pub texture: (),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Hash for TextureFrame {
|
impl Hash for ImageTexture {
|
||||||
#[cfg(feature = "wgpu")]
|
#[cfg(feature = "wgpu")]
|
||||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
self.texture.hash(state);
|
self.texture.hash(state);
|
||||||
|
|
@ -83,18 +84,18 @@ impl Hash for TextureFrame {
|
||||||
fn hash<H: Hasher>(&self, _state: &mut H) {}
|
fn hash<H: Hasher>(&self, _state: &mut H) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for TextureFrame {
|
impl PartialEq for ImageTexture {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
self.texture == other.texture
|
self.texture == other.texture
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl StaticType for TextureFrame {
|
unsafe impl StaticType for ImageTexture {
|
||||||
type Static = TextureFrame;
|
type Static = ImageTexture;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "wgpu")]
|
#[cfg(feature = "wgpu")]
|
||||||
impl Size for TextureFrame {
|
impl Size for ImageTexture {
|
||||||
fn size(&self) -> UVec2 {
|
fn size(&self) -> UVec2 {
|
||||||
UVec2::new(self.texture.width(), self.texture.height())
|
UVec2::new(self.texture.width(), self.texture.height())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::application_io::{TextureFrame, TextureFrameTable};
|
use crate::application_io::{ImageTexture, TextureFrameTable};
|
||||||
use crate::instances::Instances;
|
use crate::instances::Instances;
|
||||||
use crate::raster::image::{ImageFrame, ImageFrameTable};
|
use crate::raster::image::{Image, ImageFrameTable};
|
||||||
use crate::raster::BlendMode;
|
use crate::raster::BlendMode;
|
||||||
use crate::transform::{Transform, TransformMut};
|
use crate::transform::{Transform, TransformMut};
|
||||||
use crate::uuid::NodeId;
|
use crate::uuid::NodeId;
|
||||||
|
|
@ -111,9 +111,9 @@ impl From<VectorDataTable> for GraphicGroupTable {
|
||||||
Self::new(GraphicGroup::new(vec![GraphicElement::VectorData(vector_data)]))
|
Self::new(GraphicGroup::new(vec![GraphicElement::VectorData(vector_data)]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl From<ImageFrame<Color>> for GraphicGroupTable {
|
impl From<Image<Color>> for GraphicGroupTable {
|
||||||
fn from(image_frame: ImageFrame<Color>) -> Self {
|
fn from(image: Image<Color>) -> Self {
|
||||||
Self::new(GraphicGroup::new(vec![GraphicElement::RasterFrame(RasterFrame::ImageFrame(ImageFrameTable::new(image_frame)))]))
|
Self::new(GraphicGroup::new(vec![GraphicElement::RasterFrame(RasterFrame::ImageFrame(ImageFrameTable::new(image)))]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl From<ImageFrameTable<Color>> for GraphicGroupTable {
|
impl From<ImageFrameTable<Color>> for GraphicGroupTable {
|
||||||
|
|
@ -121,9 +121,9 @@ impl From<ImageFrameTable<Color>> for GraphicGroupTable {
|
||||||
Self::new(GraphicGroup::new(vec![GraphicElement::RasterFrame(RasterFrame::ImageFrame(image_frame))]))
|
Self::new(GraphicGroup::new(vec![GraphicElement::RasterFrame(RasterFrame::ImageFrame(image_frame))]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl From<TextureFrame> for GraphicGroupTable {
|
impl From<ImageTexture> for GraphicGroupTable {
|
||||||
fn from(texture_frame: TextureFrame) -> Self {
|
fn from(image_texture: ImageTexture) -> Self {
|
||||||
Self::new(GraphicGroup::new(vec![GraphicElement::RasterFrame(RasterFrame::TextureFrame(TextureFrameTable::new(texture_frame)))]))
|
Self::new(GraphicGroup::new(vec![GraphicElement::RasterFrame(RasterFrame::TextureFrame(TextureFrameTable::new(image_texture)))]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl From<TextureFrameTable> for GraphicGroupTable {
|
impl From<TextureFrameTable> for GraphicGroupTable {
|
||||||
|
|
@ -194,11 +194,14 @@ impl GraphicElement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Rename to Raster
|
||||||
#[derive(Clone, Debug, Hash, PartialEq, DynAny)]
|
#[derive(Clone, Debug, Hash, PartialEq, DynAny)]
|
||||||
pub enum RasterFrame {
|
pub enum RasterFrame {
|
||||||
/// A CPU-based bitmap image with a finite position and extent, equivalent to the SVG <image> tag: https://developer.mozilla.org/en-US/docs/Web/SVG/Element/image
|
/// A CPU-based bitmap image with a finite position and extent, equivalent to the SVG <image> tag: https://developer.mozilla.org/en-US/docs/Web/SVG/Element/image
|
||||||
|
// TODO: Rename to ImageTable
|
||||||
ImageFrame(ImageFrameTable<Color>),
|
ImageFrame(ImageFrameTable<Color>),
|
||||||
/// A GPU texture with a finite position and extent
|
/// A GPU texture with a finite position and extent
|
||||||
|
// TODO: Rename to ImageTextureTable
|
||||||
TextureFrame(TextureFrameTable),
|
TextureFrame(TextureFrameTable),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -207,7 +210,7 @@ impl<'de> serde::Deserialize<'de> for RasterFrame {
|
||||||
where
|
where
|
||||||
D: serde::Deserializer<'de>,
|
D: serde::Deserializer<'de>,
|
||||||
{
|
{
|
||||||
Ok(RasterFrame::ImageFrame(ImageFrameTable::new(ImageFrame::deserialize(deserializer)?)))
|
Ok(RasterFrame::ImageFrame(ImageFrameTable::new(Image::deserialize(deserializer)?)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -239,7 +242,7 @@ impl Artboard {
|
||||||
pub fn new(location: IVec2, dimensions: IVec2) -> Self {
|
pub fn new(location: IVec2, dimensions: IVec2) -> Self {
|
||||||
Self {
|
Self {
|
||||||
graphic_group: GraphicGroupTable::default(),
|
graphic_group: GraphicGroupTable::default(),
|
||||||
label: String::from("Artboard"),
|
label: "Artboard".to_string(),
|
||||||
location: location.min(location + dimensions),
|
location: location.min(location + dimensions),
|
||||||
dimensions: dimensions.abs(),
|
dimensions: dimensions.abs(),
|
||||||
background: Color::WHITE,
|
background: Color::WHITE,
|
||||||
|
|
@ -382,16 +385,13 @@ async fn to_artboard<Data: Into<GraphicGroupTable> + 'n>(
|
||||||
}
|
}
|
||||||
|
|
||||||
#[node_macro::node(category(""))]
|
#[node_macro::node(category(""))]
|
||||||
async fn append_artboard(ctx: impl Ctx, mut artboards: ArtboardGroup, artboard: Artboard, node_path: Vec<NodeId>) -> ArtboardGroup {
|
async fn append_artboard(_ctx: impl Ctx, mut artboards: ArtboardGroup, artboard: Artboard, node_path: Vec<NodeId>) -> ArtboardGroup {
|
||||||
// let mut artboards = artboards.eval(ctx.clone()).await;
|
// let mut artboards = artboards.eval(ctx.clone()).await;
|
||||||
// let artboard = artboard.eval(ctx).await;
|
// let artboard = artboard.eval(ctx).await;
|
||||||
// let foot = ctx.footprint();
|
// let foot = ctx.footprint();
|
||||||
// log::debug!("{:?}", foot);
|
// log::debug!("{:?}", foot);
|
||||||
// Get the penultimate element of the node path, or None if the path is too short
|
// Get the penultimate element of the node path, or None if the path is too short.
|
||||||
|
// This is used to get the ID of the user-facing "Artboard" node (which encapsulates this internal "Append Artboard" node).
|
||||||
// TODO: Delete this line
|
|
||||||
let _ctx = ctx;
|
|
||||||
|
|
||||||
let encapsulating_node_id = node_path.get(node_path.len().wrapping_sub(2)).copied();
|
let encapsulating_node_id = node_path.get(node_path.len().wrapping_sub(2)).copied();
|
||||||
artboards.append_artboard(artboard, encapsulating_node_id);
|
artboards.append_artboard(artboard, encapsulating_node_id);
|
||||||
|
|
||||||
|
|
@ -399,8 +399,8 @@ async fn append_artboard(ctx: impl Ctx, mut artboards: ArtboardGroup, artboard:
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Remove this one
|
// TODO: Remove this one
|
||||||
impl From<ImageFrame<Color>> for GraphicElement {
|
impl From<Image<Color>> for GraphicElement {
|
||||||
fn from(image_frame: ImageFrame<Color>) -> Self {
|
fn from(image_frame: Image<Color>) -> Self {
|
||||||
GraphicElement::RasterFrame(RasterFrame::ImageFrame(ImageFrameTable::new(image_frame)))
|
GraphicElement::RasterFrame(RasterFrame::ImageFrame(ImageFrameTable::new(image_frame)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -410,8 +410,8 @@ impl From<ImageFrameTable<Color>> for GraphicElement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO: Remove this one
|
// TODO: Remove this one
|
||||||
impl From<TextureFrame> for GraphicElement {
|
impl From<ImageTexture> for GraphicElement {
|
||||||
fn from(texture: TextureFrame) -> Self {
|
fn from(texture: ImageTexture) -> Self {
|
||||||
GraphicElement::RasterFrame(RasterFrame::TextureFrame(TextureFrameTable::new(texture)))
|
GraphicElement::RasterFrame(RasterFrame::TextureFrame(TextureFrameTable::new(texture)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -462,7 +462,7 @@ trait ToGraphicElement: Into<GraphicElement> {}
|
||||||
|
|
||||||
impl ToGraphicElement for VectorDataTable {}
|
impl ToGraphicElement for VectorDataTable {}
|
||||||
impl ToGraphicElement for ImageFrameTable<Color> {}
|
impl ToGraphicElement for ImageFrameTable<Color> {}
|
||||||
impl ToGraphicElement for TextureFrame {}
|
impl ToGraphicElement for ImageTexture {}
|
||||||
|
|
||||||
impl<T> From<T> for GraphicGroup
|
impl<T> From<T> for GraphicGroup
|
||||||
where
|
where
|
||||||
|
|
|
||||||
|
|
@ -276,6 +276,7 @@ pub struct RenderMetadata {
|
||||||
pub clip_targets: HashSet<NodeId>,
|
pub clip_targets: HashSet<NodeId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Rename to "Graphical"
|
||||||
pub trait GraphicElementRendered {
|
pub trait GraphicElementRendered {
|
||||||
fn render_svg(&self, render: &mut SvgRender, render_params: &RenderParams);
|
fn render_svg(&self, render: &mut SvgRender, render_params: &RenderParams);
|
||||||
|
|
||||||
|
|
@ -831,7 +832,7 @@ impl GraphicElementRendered for ImageFrameTable<Color> {
|
||||||
|
|
||||||
match render_params.image_render_mode {
|
match render_params.image_render_mode {
|
||||||
ImageRenderMode::Base64 => {
|
ImageRenderMode::Base64 => {
|
||||||
let image = &instance.instance.image;
|
let image = &instance.instance;
|
||||||
if image.data.is_empty() {
|
if image.data.is_empty() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -894,7 +895,7 @@ impl GraphicElementRendered for ImageFrameTable<Color> {
|
||||||
use vello::peniko;
|
use vello::peniko;
|
||||||
|
|
||||||
for instance in self.instances() {
|
for instance in self.instances() {
|
||||||
let image = &instance.instance.image;
|
let image = &instance.instance;
|
||||||
if image.data.is_empty() {
|
if image.data.is_empty() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -918,7 +919,7 @@ impl GraphicElementRendered for RasterFrame {
|
||||||
};
|
};
|
||||||
|
|
||||||
for instance in image.instances() {
|
for instance in image.instances() {
|
||||||
let (image, blending) = (&instance.instance.image, instance.alpha_blending);
|
let (image, blending) = (&instance.instance, instance.alpha_blending);
|
||||||
if image.data.is_empty() {
|
if image.data.is_empty() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -992,9 +993,9 @@ impl GraphicElementRendered for RasterFrame {
|
||||||
};
|
};
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
RasterFrame::ImageFrame(image_frame) => {
|
RasterFrame::ImageFrame(image) => {
|
||||||
for instance in image_frame.instances() {
|
for instance in image.instances() {
|
||||||
let image = &instance.instance.image;
|
let image = &instance.instance;
|
||||||
if image.data.is_empty() {
|
if image.data.is_empty() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -1004,8 +1005,8 @@ impl GraphicElementRendered for RasterFrame {
|
||||||
render_stuff(image, *instance.alpha_blending);
|
render_stuff(image, *instance.alpha_blending);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RasterFrame::TextureFrame(texture) => {
|
RasterFrame::TextureFrame(image_texture) => {
|
||||||
for instance in texture.instances() {
|
for instance in image_texture.instances() {
|
||||||
let image =
|
let image =
|
||||||
vello::peniko::Image::new(vec![].into(), peniko::Format::Rgba8, instance.instance.texture.width(), instance.instance.texture.height()).with_extend(peniko::Extend::Repeat);
|
vello::peniko::Image::new(vec![].into(), peniko::Format::Rgba8, instance.instance.texture.width(), instance.instance.texture.height()).with_extend(peniko::Extend::Repeat);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::application_io::{TextureFrame, TextureFrameTable};
|
use crate::application_io::{ImageTexture, TextureFrameTable};
|
||||||
use crate::raster::image::{ImageFrame, ImageFrameTable};
|
use crate::raster::image::{Image, ImageFrameTable};
|
||||||
use crate::raster::Pixel;
|
use crate::raster::Pixel;
|
||||||
use crate::transform::{Transform, TransformMut};
|
use crate::transform::{Transform, TransformMut};
|
||||||
use crate::vector::{InstanceId, VectorData, VectorDataTable};
|
use crate::vector::{InstanceId, VectorData, VectorDataTable};
|
||||||
|
|
@ -180,18 +180,18 @@ impl TransformMut for GraphicGroupTable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TEXTURE FRAME
|
// IMAGE TEXTURE
|
||||||
impl Transform for Instance<'_, TextureFrame> {
|
impl Transform for Instance<'_, ImageTexture> {
|
||||||
fn transform(&self) -> DAffine2 {
|
fn transform(&self) -> DAffine2 {
|
||||||
*self.transform
|
*self.transform
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Transform for InstanceMut<'_, TextureFrame> {
|
impl Transform for InstanceMut<'_, ImageTexture> {
|
||||||
fn transform(&self) -> DAffine2 {
|
fn transform(&self) -> DAffine2 {
|
||||||
*self.transform
|
*self.transform
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl TransformMut for InstanceMut<'_, TextureFrame> {
|
impl TransformMut for InstanceMut<'_, ImageTexture> {
|
||||||
fn transform_mut(&mut self) -> &mut DAffine2 {
|
fn transform_mut(&mut self) -> &mut DAffine2 {
|
||||||
self.transform
|
self.transform
|
||||||
}
|
}
|
||||||
|
|
@ -209,8 +209,8 @@ impl TransformMut for TextureFrameTable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// IMAGE FRAME
|
// IMAGE
|
||||||
impl<P: Pixel> Transform for Instance<'_, ImageFrame<P>> {
|
impl<P: Pixel> Transform for Instance<'_, Image<P>> {
|
||||||
fn transform(&self) -> DAffine2 {
|
fn transform(&self) -> DAffine2 {
|
||||||
*self.transform
|
*self.transform
|
||||||
}
|
}
|
||||||
|
|
@ -218,7 +218,7 @@ impl<P: Pixel> Transform for Instance<'_, ImageFrame<P>> {
|
||||||
self.transform.transform_point2(pivot)
|
self.transform.transform_point2(pivot)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<P: Pixel> Transform for InstanceMut<'_, ImageFrame<P>> {
|
impl<P: Pixel> Transform for InstanceMut<'_, Image<P>> {
|
||||||
fn transform(&self) -> DAffine2 {
|
fn transform(&self) -> DAffine2 {
|
||||||
*self.transform
|
*self.transform
|
||||||
}
|
}
|
||||||
|
|
@ -226,7 +226,7 @@ impl<P: Pixel> Transform for InstanceMut<'_, ImageFrame<P>> {
|
||||||
self.transform.transform_point2(pivot)
|
self.transform.transform_point2(pivot)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<P: Pixel> TransformMut for InstanceMut<'_, ImageFrame<P>> {
|
impl<P: Pixel> TransformMut for InstanceMut<'_, Image<P>> {
|
||||||
fn transform_mut(&mut self) -> &mut DAffine2 {
|
fn transform_mut(&mut self) -> &mut DAffine2 {
|
||||||
self.transform
|
self.transform
|
||||||
}
|
}
|
||||||
|
|
@ -237,7 +237,7 @@ impl<P: Pixel> Transform for ImageFrameTable<P>
|
||||||
where
|
where
|
||||||
P: dyn_any::StaticType,
|
P: dyn_any::StaticType,
|
||||||
P::Static: Pixel,
|
P::Static: Pixel,
|
||||||
GraphicElement: From<ImageFrame<P>>,
|
GraphicElement: From<Image<P>>,
|
||||||
{
|
{
|
||||||
fn transform(&self) -> DAffine2 {
|
fn transform(&self) -> DAffine2 {
|
||||||
self.one_instance().transform()
|
self.one_instance().transform()
|
||||||
|
|
@ -247,7 +247,7 @@ impl<P: Pixel> TransformMut for ImageFrameTable<P>
|
||||||
where
|
where
|
||||||
P: dyn_any::StaticType,
|
P: dyn_any::StaticType,
|
||||||
P::Static: Pixel,
|
P::Static: Pixel,
|
||||||
GraphicElement: From<ImageFrame<P>>,
|
GraphicElement: From<Image<P>>,
|
||||||
{
|
{
|
||||||
fn transform_mut(&mut self) -> &mut DAffine2 {
|
fn transform_mut(&mut self) -> &mut DAffine2 {
|
||||||
self.transform.first_mut().unwrap_or_else(|| panic!("ONE INSTANCE EXPECTED"))
|
self.transform.first_mut().unwrap_or_else(|| panic!("ONE INSTANCE EXPECTED"))
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
use crate::raster::curve::{Curve, CurveManipulatorGroup, ValueMapperNode};
|
use crate::raster::curve::{Curve, CurveManipulatorGroup, ValueMapperNode};
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
use crate::raster::image::{ImageFrame, ImageFrameTable};
|
use crate::raster::image::{Image, ImageFrameTable};
|
||||||
use crate::raster::{Channel, Color, Pixel};
|
use crate::raster::{Channel, Color, Pixel};
|
||||||
use crate::registry::types::{Angle, Percentage, SignedPercentage};
|
use crate::registry::types::{Angle, Percentage, SignedPercentage};
|
||||||
use crate::vector::style::GradientStops;
|
use crate::vector::style::GradientStops;
|
||||||
|
|
@ -605,15 +605,13 @@ impl Blend<Color> for ImageFrameTable<Color> {
|
||||||
let mut result = self.clone();
|
let mut result = self.clone();
|
||||||
|
|
||||||
for (over, under) in result.instances_mut().zip(under.instances()) {
|
for (over, under) in result.instances_mut().zip(under.instances()) {
|
||||||
let data = over.instance.image.data.iter().zip(under.instance.image.data.iter()).map(|(a, b)| blend_fn(*a, *b)).collect();
|
let data = over.instance.data.iter().zip(under.instance.data.iter()).map(|(a, b)| blend_fn(*a, *b)).collect();
|
||||||
|
|
||||||
*over.instance = ImageFrame {
|
*over.instance = Image {
|
||||||
image: super::Image {
|
data,
|
||||||
data,
|
width: over.instance.width,
|
||||||
width: over.instance.image.width,
|
height: over.instance.height,
|
||||||
height: over.instance.image.height,
|
base64_string: None,
|
||||||
base64_string: None,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -738,11 +736,11 @@ impl<P: Pixel> Adjust<P> for ImageFrameTable<P>
|
||||||
where
|
where
|
||||||
P: dyn_any::StaticType,
|
P: dyn_any::StaticType,
|
||||||
P::Static: Pixel,
|
P::Static: Pixel,
|
||||||
GraphicElement: From<ImageFrame<P>>,
|
GraphicElement: From<Image<P>>,
|
||||||
{
|
{
|
||||||
fn adjust(&mut self, map_fn: impl Fn(&P) -> P) {
|
fn adjust(&mut self, map_fn: impl Fn(&P) -> P) {
|
||||||
for instance in self.instances_mut() {
|
for instance in self.instances_mut() {
|
||||||
for c in instance.instance.image.data.iter_mut() {
|
for c in instance.instance.data.iter_mut() {
|
||||||
*c = map_fn(c);
|
*c = map_fn(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1386,7 +1384,7 @@ impl<P: Pixel> MultiplyAlpha for ImageFrameTable<P>
|
||||||
where
|
where
|
||||||
P: dyn_any::StaticType,
|
P: dyn_any::StaticType,
|
||||||
P::Static: Pixel,
|
P::Static: Pixel,
|
||||||
GraphicElement: From<ImageFrame<P>>,
|
GraphicElement: From<Image<P>>,
|
||||||
{
|
{
|
||||||
fn multiply_alpha(&mut self, factor: f64) {
|
fn multiply_alpha(&mut self, factor: f64) {
|
||||||
for instance in self.instances_mut() {
|
for instance in self.instances_mut() {
|
||||||
|
|
@ -1539,13 +1537,13 @@ fn color_overlay<T: Adjust<Color>>(
|
||||||
|
|
||||||
// #[cfg(feature = "alloc")]
|
// #[cfg(feature = "alloc")]
|
||||||
// mod index_node {
|
// mod index_node {
|
||||||
// use crate::raster::{Color, ImageFrame};
|
// use crate::raster::{Color, Image};
|
||||||
// use crate::Ctx;
|
// use crate::Ctx;
|
||||||
|
|
||||||
// #[node_macro::node(category(""))]
|
// #[node_macro::node(category(""))]
|
||||||
// pub fn index<T: Default + Clone>(
|
// pub fn index<T: Default + Clone>(
|
||||||
// _: impl Ctx,
|
// _: impl Ctx,
|
||||||
// #[implementations(Vec<ImageFrame<Color>>, Vec<Color>)]
|
// #[implementations(Vec<Image<Color>>, Vec<Color>)]
|
||||||
// #[widget(ParsedWidgetOverride::Hidden)]
|
// #[widget(ParsedWidgetOverride::Hidden)]
|
||||||
// input: Vec<T>,
|
// input: Vec<T>,
|
||||||
// index: u32,
|
// index: u32,
|
||||||
|
|
@ -1561,8 +1559,8 @@ fn color_overlay<T: Adjust<Color>>(
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use crate::raster::image::{ImageFrame, ImageFrameTable};
|
use crate::raster::adjustments::BlendMode;
|
||||||
use crate::raster::{BlendMode, Image};
|
use crate::raster::image::{Image, ImageFrameTable};
|
||||||
use crate::{Color, Node};
|
use crate::{Color, Node};
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
|
@ -1580,7 +1578,7 @@ mod test {
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn color_overlay_multiply() {
|
async fn color_overlay_multiply() {
|
||||||
let image_color = Color::from_rgbaf32_unchecked(0.7, 0.6, 0.5, 0.4);
|
let image_color = Color::from_rgbaf32_unchecked(0.7, 0.6, 0.5, 0.4);
|
||||||
let image = ImageFrame { image: Image::new(1, 1, image_color) };
|
let image = Image::new(1, 1, image_color);
|
||||||
|
|
||||||
// Color { red: 0., green: 1., blue: 0., alpha: 1. }
|
// Color { red: 0., green: 1., blue: 0., alpha: 1. }
|
||||||
let overlay_color = Color::GREEN;
|
let overlay_color = Color::GREEN;
|
||||||
|
|
@ -1592,6 +1590,6 @@ mod test {
|
||||||
let result = result.one_instance().instance;
|
let result = result.one_instance().instance;
|
||||||
|
|
||||||
// The output should just be the original green and alpha channels (as we multiply them by 1 and other channels by 0)
|
// The output should just be the original green and alpha channels (as we multiply them by 1 and other channels by 0)
|
||||||
assert_eq!(result.image.data[0], Color::from_rgbaf32_unchecked(0., image_color.g(), 0., image_color.a()));
|
assert_eq!(result.data[0], Color::from_rgbaf32_unchecked(0., image_color.g(), 0., image_color.a()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ struct BrushCacheImpl {
|
||||||
impl BrushCacheImpl {
|
impl BrushCacheImpl {
|
||||||
fn compute_brush_plan(&mut self, mut background: ImageFrameTable<Color>, input: &[BrushStroke]) -> BrushPlan {
|
fn compute_brush_plan(&mut self, mut background: ImageFrameTable<Color>, input: &[BrushStroke]) -> BrushPlan {
|
||||||
// Do background invalidation.
|
// Do background invalidation.
|
||||||
if background.one_instance().instance.image != self.background.one_instance().instance.image {
|
if background.one_instance().instance != self.background.one_instance().instance {
|
||||||
self.background = background.clone();
|
self.background = background.clone();
|
||||||
return BrushPlan {
|
return BrushPlan {
|
||||||
strokes: input.to_vec(),
|
strokes: input.to_vec(),
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,8 @@ pub struct Image<P: Pixel> {
|
||||||
/// to an svg string. This is used as a cache in order to not have to encode the data on every graph evaluation.
|
/// to an svg string. This is used as a cache in order to not have to encode the data on every graph evaluation.
|
||||||
#[cfg_attr(feature = "serde", serde(skip))]
|
#[cfg_attr(feature = "serde", serde(skip))]
|
||||||
pub base64_string: Option<String>,
|
pub base64_string: Option<String>,
|
||||||
|
// TODO: Add an `origin` field to store where in the local space the image is anchored.
|
||||||
|
// TODO: Currently it is always anchored at the top left corner at (0, 0). The bottom right corner of the new origin field would correspond to (1, 1).
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P: Pixel + Debug> Debug for Image<P> {
|
impl<P: Pixel + Debug> Debug for Image<P> {
|
||||||
|
|
@ -66,8 +68,9 @@ impl<P: Pixel + Debug> Debug for Image<P> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<P: dyn_any::StaticTypeSized + Pixel> StaticType for Image<P>
|
unsafe impl<P> StaticType for Image<P>
|
||||||
where
|
where
|
||||||
|
P: dyn_any::StaticTypeSized + Pixel,
|
||||||
P::Static: Pixel,
|
P::Static: Pixel,
|
||||||
{
|
{
|
||||||
type Static = Image<P::Static>;
|
type Static = Image<P::Static>;
|
||||||
|
|
@ -212,6 +215,34 @@ impl<P: Pixel> IntoIterator for Image<P> {
|
||||||
pub fn migrate_image_frame<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result<ImageFrameTable<Color>, D::Error> {
|
pub fn migrate_image_frame<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result<ImageFrameTable<Color>, D::Error> {
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
#[derive(Clone, Default, Debug, PartialEq, specta::Type)]
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
pub struct ImageFrame<P: Pixel> {
|
||||||
|
pub image: Image<P>,
|
||||||
|
}
|
||||||
|
impl From<ImageFrame<Color>> for GraphicElement {
|
||||||
|
fn from(image_frame: ImageFrame<Color>) -> Self {
|
||||||
|
GraphicElement::RasterFrame(crate::RasterFrame::ImageFrame(ImageFrameTable::new(image_frame.image)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl From<GraphicElement> for ImageFrame<Color> {
|
||||||
|
fn from(element: GraphicElement) -> Self {
|
||||||
|
match element {
|
||||||
|
GraphicElement::RasterFrame(crate::RasterFrame::ImageFrame(image)) => Self {
|
||||||
|
image: image.one_instance().instance.clone(),
|
||||||
|
},
|
||||||
|
_ => panic!("Expected Image, found {:?}", element),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unsafe impl<P> StaticType for ImageFrame<P>
|
||||||
|
where
|
||||||
|
P: dyn_any::StaticTypeSized + Pixel,
|
||||||
|
P::Static: Pixel,
|
||||||
|
{
|
||||||
|
type Static = ImageFrame<P::Static>;
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Default, Debug, PartialEq, specta::Type)]
|
#[derive(Clone, Default, Debug, PartialEq, specta::Type)]
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
pub struct OldImageFrame<P: Pixel> {
|
pub struct OldImageFrame<P: Pixel> {
|
||||||
|
|
@ -222,60 +253,58 @@ pub fn migrate_image_frame<'de, D: serde::Deserializer<'de>>(deserializer: D) ->
|
||||||
|
|
||||||
#[derive(serde::Serialize, serde::Deserialize)]
|
#[derive(serde::Serialize, serde::Deserialize)]
|
||||||
#[serde(untagged)]
|
#[serde(untagged)]
|
||||||
enum EitherFormat {
|
enum FormatVersions {
|
||||||
ImageFrame(ImageFrame<Color>),
|
Image(Image<Color>),
|
||||||
OldImageFrame(OldImageFrame<Color>),
|
OldImageFrame(OldImageFrame<Color>),
|
||||||
|
ImageFrame(Instances<ImageFrame<Color>>),
|
||||||
ImageFrameTable(ImageFrameTable<Color>),
|
ImageFrameTable(ImageFrameTable<Color>),
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(match EitherFormat::deserialize(deserializer)? {
|
Ok(match FormatVersions::deserialize(deserializer)? {
|
||||||
EitherFormat::ImageFrame(image_frame) => ImageFrameTable::<Color>::new(image_frame),
|
FormatVersions::Image(image) => ImageFrameTable::new(image),
|
||||||
EitherFormat::OldImageFrame(image_frame_with_transform_and_blending) => {
|
FormatVersions::OldImageFrame(image_frame_with_transform_and_blending) => {
|
||||||
let OldImageFrame { image, transform, alpha_blending } = image_frame_with_transform_and_blending;
|
let OldImageFrame { image, transform, alpha_blending } = image_frame_with_transform_and_blending;
|
||||||
let mut image_frame_table = ImageFrameTable::new(ImageFrame { image });
|
let mut image_frame_table = ImageFrameTable::new(image);
|
||||||
*image_frame_table.one_instance_mut().transform = transform;
|
*image_frame_table.one_instance_mut().transform = transform;
|
||||||
*image_frame_table.one_instance_mut().alpha_blending = alpha_blending;
|
*image_frame_table.one_instance_mut().alpha_blending = alpha_blending;
|
||||||
image_frame_table
|
image_frame_table
|
||||||
}
|
}
|
||||||
EitherFormat::ImageFrameTable(image_frame_table) => image_frame_table,
|
FormatVersions::ImageFrame(image_frame) => ImageFrameTable::new(image_frame.one_instance().instance.image.clone()),
|
||||||
|
FormatVersions::ImageFrameTable(image_frame_table) => image_frame_table,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type ImageFrameTable<P> = Instances<ImageFrame<P>>;
|
// TODO: Rename to ImageTable
|
||||||
|
pub type ImageFrameTable<P> = Instances<Image<P>>;
|
||||||
|
|
||||||
/// Construct a 0x0 image frame table. This is useful because ImageFrameTable::default() will return a 1x1 image frame table.
|
/// Construct a 0x0 image frame table. This is useful because ImageFrameTable::default() will return a 1x1 image frame table.
|
||||||
impl ImageFrameTable<Color> {
|
impl ImageFrameTable<Color> {
|
||||||
pub fn empty() -> Self {
|
pub fn empty() -> Self {
|
||||||
let mut result = Self::new(ImageFrame::default());
|
let mut result = Self::new(Image::default());
|
||||||
*result.transform_mut() = DAffine2::ZERO;
|
*result.transform_mut() = DAffine2::ZERO;
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Default, Debug, PartialEq, specta::Type)]
|
impl<P: Debug + Copy + Pixel> Sample for Image<P> {
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
|
||||||
pub struct ImageFrame<P: Pixel> {
|
|
||||||
pub image: Image<P>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<P: Debug + Copy + Pixel> Sample for ImageFrame<P> {
|
|
||||||
type Pixel = P;
|
type Pixel = P;
|
||||||
|
|
||||||
// TODO: Improve sampling logic
|
// TODO: Improve sampling logic
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn sample(&self, pos: DVec2, _area: DVec2) -> Option<Self::Pixel> {
|
fn sample(&self, pos: DVec2, _area: DVec2) -> Option<Self::Pixel> {
|
||||||
let image_size = DVec2::new(self.image.width() as f64, self.image.height() as f64);
|
let image_size = DVec2::new(self.width() as f64, self.height() as f64);
|
||||||
if pos.x < 0. || pos.y < 0. || pos.x >= image_size.x || pos.y >= image_size.y {
|
if pos.x < 0. || pos.y < 0. || pos.x >= image_size.x || pos.y >= image_size.y {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
self.image.get_pixel(pos.x as u32, pos.y as u32)
|
self.get_pixel(pos.x as u32, pos.y as u32)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P: Debug + Copy + Pixel + dyn_any::StaticType> Sample for ImageFrameTable<P>
|
impl<P> Sample for ImageFrameTable<P>
|
||||||
where
|
where
|
||||||
GraphicElement: From<ImageFrame<P>>,
|
P: Debug + Copy + Pixel + dyn_any::StaticType,
|
||||||
P::Static: Pixel,
|
P::Static: Pixel,
|
||||||
|
GraphicElement: From<Image<P>>,
|
||||||
{
|
{
|
||||||
type Pixel = P;
|
type Pixel = P;
|
||||||
|
|
||||||
|
|
@ -292,26 +321,11 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P: Copy + Pixel> Bitmap for ImageFrame<P> {
|
impl<P> Bitmap for ImageFrameTable<P>
|
||||||
type Pixel = P;
|
|
||||||
|
|
||||||
fn width(&self) -> u32 {
|
|
||||||
self.image.width()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn height(&self) -> u32 {
|
|
||||||
self.image.height()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_pixel(&self, x: u32, y: u32) -> Option<Self::Pixel> {
|
|
||||||
self.image.get_pixel(x, y)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<P: Copy + Pixel + dyn_any::StaticType> Bitmap for ImageFrameTable<P>
|
|
||||||
where
|
where
|
||||||
|
P: Copy + Pixel + dyn_any::StaticType,
|
||||||
P::Static: Pixel,
|
P::Static: Pixel,
|
||||||
GraphicElement: From<ImageFrame<P>>,
|
GraphicElement: From<Image<P>>,
|
||||||
{
|
{
|
||||||
type Pixel = P;
|
type Pixel = P;
|
||||||
|
|
||||||
|
|
@ -334,95 +348,57 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P: Copy + Pixel> BitmapMut for ImageFrame<P> {
|
impl<P> BitmapMut for ImageFrameTable<P>
|
||||||
|
where
|
||||||
|
P: Copy + Pixel + dyn_any::StaticType,
|
||||||
|
P::Static: Pixel,
|
||||||
|
GraphicElement: From<Image<P>>,
|
||||||
|
{
|
||||||
fn get_pixel_mut(&mut self, x: u32, y: u32) -> Option<&mut Self::Pixel> {
|
fn get_pixel_mut(&mut self, x: u32, y: u32) -> Option<&mut Self::Pixel> {
|
||||||
self.image.get_pixel_mut(x, y)
|
self.one_instance_mut().instance.get_pixel_mut(x, y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P: Copy + Pixel + dyn_any::StaticType> BitmapMut for ImageFrameTable<P>
|
impl<P: Copy + Pixel> Image<P> {
|
||||||
where
|
|
||||||
GraphicElement: From<ImageFrame<P>>,
|
|
||||||
P::Static: Pixel,
|
|
||||||
{
|
|
||||||
fn get_pixel_mut(&mut self, x: u32, y: u32) -> Option<&mut Self::Pixel> {
|
|
||||||
let image = self.one_instance_mut().instance;
|
|
||||||
|
|
||||||
BitmapMut::get_pixel_mut(image, x, y)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl<P: dyn_any::StaticTypeSized + Pixel> StaticType for ImageFrame<P>
|
|
||||||
where
|
|
||||||
P::Static: Pixel,
|
|
||||||
{
|
|
||||||
type Static = ImageFrame<P::Static>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<P: Copy + Pixel> ImageFrame<P> {
|
|
||||||
pub fn get_mut(&mut self, x: usize, y: usize) -> &mut P {
|
pub fn get_mut(&mut self, x: usize, y: usize) -> &mut P {
|
||||||
&mut self.image.data[y * (self.image.width as usize) + x]
|
&mut self.data[y * (self.width as usize) + x]
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Clamps the provided point to ((0, 0), (ImageSize.x, ImageSize.y)) and returns the closest pixel
|
/// Clamps the provided point to ((0, 0), (ImageSize.x, ImageSize.y)) and returns the closest pixel
|
||||||
pub fn sample(&self, position: DVec2) -> P {
|
pub fn sample(&self, position: DVec2) -> P {
|
||||||
let x = position.x.clamp(0., self.image.width as f64 - 1.) as usize;
|
let x = position.x.clamp(0., self.width as f64 - 1.) as usize;
|
||||||
let y = position.y.clamp(0., self.image.height as f64 - 1.) as usize;
|
let y = position.y.clamp(0., self.height as f64 - 1.) as usize;
|
||||||
|
|
||||||
self.image.data[x + y * self.image.width as usize]
|
self.data[x + y * self.width as usize]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P: Pixel> AsRef<ImageFrame<P>> for ImageFrame<P> {
|
impl<P: Pixel> AsRef<Image<P>> for Image<P> {
|
||||||
fn as_ref(&self) -> &ImageFrame<P> {
|
fn as_ref(&self) -> &Image<P> {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P: Hash + Pixel> Hash for ImageFrame<P> {
|
impl From<Image<Color>> for Image<SRGBA8> {
|
||||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
fn from(image: Image<Color>) -> Self {
|
||||||
0.hash(state);
|
|
||||||
self.image.hash(state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This does not work because of missing specialization
|
|
||||||
* so we have to manually implement this for now
|
|
||||||
impl<S: Into<P> + Pixel, P: Pixel> From<Image<S>> for Image<P> {
|
|
||||||
fn from(image: Image<S>) -> Self {
|
|
||||||
let data = image.data.into_iter().map(|x| x.into()).collect();
|
let data = image.data.into_iter().map(|x| x.into()).collect();
|
||||||
Self {
|
Self {
|
||||||
data,
|
data,
|
||||||
width: image.width,
|
width: image.width,
|
||||||
height: image.height,
|
height: image.height,
|
||||||
}
|
base64_string: None,
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
impl From<ImageFrame<Color>> for ImageFrame<SRGBA8> {
|
|
||||||
fn from(image: ImageFrame<Color>) -> Self {
|
|
||||||
let data = image.image.data.into_iter().map(|x| x.into()).collect();
|
|
||||||
Self {
|
|
||||||
image: Image {
|
|
||||||
data,
|
|
||||||
width: image.image.width,
|
|
||||||
height: image.image.height,
|
|
||||||
base64_string: None,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ImageFrame<SRGBA8>> for ImageFrame<Color> {
|
impl From<Image<SRGBA8>> for Image<Color> {
|
||||||
fn from(image: ImageFrame<SRGBA8>) -> Self {
|
fn from(image: Image<SRGBA8>) -> Self {
|
||||||
let data = image.image.data.into_iter().map(|x| x.into()).collect();
|
let data = image.data.into_iter().map(|x| x.into()).collect();
|
||||||
Self {
|
Self {
|
||||||
image: Image {
|
data,
|
||||||
data,
|
width: image.width,
|
||||||
width: image.image.width,
|
height: image.height,
|
||||||
height: image.image.height,
|
base64_string: None,
|
||||||
base64_string: None,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -150,9 +150,14 @@ fn migrate_type_descriptor_names<'de, D: serde::Deserializer<'de>>(deserializer:
|
||||||
let name = match name.as_str() {
|
let name = match name.as_str() {
|
||||||
"f32" => "f64".to_string(),
|
"f32" => "f64".to_string(),
|
||||||
"graphene_core::transform::Footprint" => "core::option::Option<alloc::sync::Arc<graphene_core::context::OwnedContextImpl>>".to_string(),
|
"graphene_core::transform::Footprint" => "core::option::Option<alloc::sync::Arc<graphene_core::context::OwnedContextImpl>>".to_string(),
|
||||||
"graphene_core::graphic_element::GraphicGroup" => "graphene_core::graphic_element::Instances<graphene_core::graphic_element::GraphicGroup>".to_string(),
|
"graphene_core::graphic_element::GraphicGroup" => "graphene_core::instances::Instances<graphene_core::graphic_element::GraphicGroup>".to_string(),
|
||||||
"graphene_core::vector::vector_data::VectorData" => "graphene_core::graphic_element::Instances<graphene_core::vector::vector_data::VectorData>".to_string(),
|
"graphene_core::vector::vector_data::VectorData" => "graphene_core::instances::Instances<graphene_core::vector::vector_data::VectorData>".to_string(),
|
||||||
"graphene_core::raster::image::ImageFrame<Color>" => "graphene_core::graphic_element::Instances<graphene_core::raster::image::ImageFrame<Color>>".to_string(),
|
"graphene_core::raster::image::ImageFrame<Color>"
|
||||||
|
| "graphene_core::raster::image::ImageFrame<graphene_core::raster::color::Color>"
|
||||||
|
| "graphene_core::instances::Instances<graphene_core::raster::image::ImageFrame<Color>>"
|
||||||
|
| "graphene_core::instances::Instances<graphene_core::raster::image::ImageFrame<graphene_core::raster::color::Color>>" => {
|
||||||
|
"graphene_core::instances::Instances<graphene_core::raster::image::Image<graphene_core::raster::color::Color>>".to_string()
|
||||||
|
}
|
||||||
_ => name,
|
_ => name,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,8 @@ use graph_craft::proto::FutureWrapperNode;
|
||||||
use graphene_core::raster::adjustments::blend_colors;
|
use graphene_core::raster::adjustments::blend_colors;
|
||||||
use graphene_core::raster::bbox::{AxisAlignedBbox, Bbox};
|
use graphene_core::raster::bbox::{AxisAlignedBbox, Bbox};
|
||||||
use graphene_core::raster::brush_cache::BrushCache;
|
use graphene_core::raster::brush_cache::BrushCache;
|
||||||
use graphene_core::raster::image::{ImageFrame, ImageFrameTable};
|
use graphene_core::raster::image::{Image, ImageFrameTable};
|
||||||
use graphene_core::raster::{Alpha, Bitmap, BlendMode, Color, Image, Pixel, Sample};
|
use graphene_core::raster::{Alpha, Bitmap, BlendMode, Color, Pixel, Sample};
|
||||||
use graphene_core::transform::{Transform, TransformMut};
|
use graphene_core::transform::{Transform, TransformMut};
|
||||||
use graphene_core::value::{ClonedNode, CopiedNode, ValueNode};
|
use graphene_core::value::{ClonedNode, CopiedNode, ValueNode};
|
||||||
use graphene_core::vector::brush_stroke::{BrushStroke, BrushStyle};
|
use graphene_core::vector::brush_stroke::{BrushStroke, BrushStyle};
|
||||||
|
|
@ -93,14 +93,14 @@ where
|
||||||
P: Pixel + Alpha + std::fmt::Debug + dyn_any::StaticType,
|
P: Pixel + Alpha + std::fmt::Debug + dyn_any::StaticType,
|
||||||
P::Static: Pixel,
|
P::Static: Pixel,
|
||||||
BlendFn: for<'any_input> Node<'any_input, (P, P), Output = P>,
|
BlendFn: for<'any_input> Node<'any_input, (P, P), Output = P>,
|
||||||
GraphicElement: From<ImageFrame<P>>,
|
GraphicElement: From<Image<P>>,
|
||||||
{
|
{
|
||||||
if positions.is_empty() {
|
if positions.is_empty() {
|
||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
|
|
||||||
let target_width = target.one_instance().instance.image.width;
|
let target_width = target.one_instance().instance.width;
|
||||||
let target_height = target.one_instance().instance.image.height;
|
let target_height = target.one_instance().instance.height;
|
||||||
let target_size = DVec2::new(target_width as f64, target_height as f64);
|
let target_size = DVec2::new(target_width as f64, target_height as f64);
|
||||||
|
|
||||||
let texture_size = DVec2::new(texture.width as f64, texture.height as f64);
|
let texture_size = DVec2::new(texture.width as f64, texture.height as f64);
|
||||||
|
|
@ -125,12 +125,12 @@ where
|
||||||
let max_y = (blit_area_offset.y + blit_area_dimensions.y).saturating_sub(1);
|
let max_y = (blit_area_offset.y + blit_area_dimensions.y).saturating_sub(1);
|
||||||
let max_x = (blit_area_offset.x + blit_area_dimensions.x).saturating_sub(1);
|
let max_x = (blit_area_offset.x + blit_area_dimensions.x).saturating_sub(1);
|
||||||
assert!(texture_index(max_x, max_y) < texture.data.len());
|
assert!(texture_index(max_x, max_y) < texture.data.len());
|
||||||
assert!(target_index(max_x, max_y) < target.one_instance().instance.image.data.len());
|
assert!(target_index(max_x, max_y) < target.one_instance().instance.data.len());
|
||||||
|
|
||||||
for y in blit_area_offset.y..blit_area_offset.y + blit_area_dimensions.y {
|
for y in blit_area_offset.y..blit_area_offset.y + blit_area_dimensions.y {
|
||||||
for x in blit_area_offset.x..blit_area_offset.x + blit_area_dimensions.x {
|
for x in blit_area_offset.x..blit_area_offset.x + blit_area_dimensions.x {
|
||||||
let src_pixel = texture.data[texture_index(x, y)];
|
let src_pixel = texture.data[texture_index(x, y)];
|
||||||
let dst_pixel = &mut target.one_instance_mut().instance.image.data[target_index(x + clamp_start.x, y + clamp_start.y)];
|
let dst_pixel = &mut target.one_instance_mut().instance.data[target_index(x + clamp_start.x, y + clamp_start.y)];
|
||||||
*dst_pixel = blend_mode.eval((src_pixel, *dst_pixel));
|
*dst_pixel = blend_mode.eval((src_pixel, *dst_pixel));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -146,7 +146,7 @@ pub async fn create_brush_texture(brush_style: &BrushStyle) -> Image<Color> {
|
||||||
let blank_texture = empty_image((), transform, Color::TRANSPARENT);
|
let blank_texture = empty_image((), transform, Color::TRANSPARENT);
|
||||||
let image = crate::raster::blend_image_closure(stamp, blank_texture, |a, b| blend_colors(a, b, BlendMode::Normal, 1.));
|
let image = crate::raster::blend_image_closure(stamp, blank_texture, |a, b| blend_colors(a, b, BlendMode::Normal, 1.));
|
||||||
|
|
||||||
image.one_instance().instance.image.clone()
|
image.one_instance().instance.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! inline_blend_funcs {
|
macro_rules! inline_blend_funcs {
|
||||||
|
|
@ -286,9 +286,7 @@ async fn brush(_: impl Ctx, image_frame_table: ImageFrameTable<Color>, bounds: I
|
||||||
|
|
||||||
let has_erase_strokes = strokes.iter().any(|s| s.style.blend_mode == BlendMode::Erase);
|
let has_erase_strokes = strokes.iter().any(|s| s.style.blend_mode == BlendMode::Erase);
|
||||||
if has_erase_strokes {
|
if has_erase_strokes {
|
||||||
let opaque_image = ImageFrame {
|
let opaque_image = Image::new(bbox.size().x as u32, bbox.size().y as u32, Color::WHITE);
|
||||||
image: Image::new(bbox.size().x as u32, bbox.size().y as u32, Color::WHITE),
|
|
||||||
};
|
|
||||||
let mut erase_restore_mask = ImageFrameTable::new(opaque_image);
|
let mut erase_restore_mask = ImageFrameTable::new(opaque_image);
|
||||||
*erase_restore_mask.transform_mut() = background_bounds;
|
*erase_restore_mask.transform_mut() = background_bounds;
|
||||||
*erase_restore_mask.one_instance_mut().alpha_blending = Default::default();
|
*erase_restore_mask.one_instance_mut().alpha_blending = Default::default();
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
use graph_craft::proto::types::Percentage;
|
use graph_craft::proto::types::Percentage;
|
||||||
use graphene_core::raster::image::{ImageFrame, ImageFrameTable};
|
use graphene_core::raster::image::{Image, ImageFrameTable};
|
||||||
use graphene_core::raster::Image;
|
|
||||||
use graphene_core::transform::{Transform, TransformMut};
|
use graphene_core::transform::{Transform, TransformMut};
|
||||||
use graphene_core::{Color, Ctx};
|
use graphene_core::{Color, Ctx};
|
||||||
|
|
||||||
|
|
@ -13,10 +12,9 @@ async fn dehaze(_: impl Ctx, image_frame: ImageFrameTable<Color>, strength: Perc
|
||||||
let image_frame_transform = image_frame.transform();
|
let image_frame_transform = image_frame.transform();
|
||||||
let image_frame_alpha_blending = image_frame.one_instance().alpha_blending;
|
let image_frame_alpha_blending = image_frame.one_instance().alpha_blending;
|
||||||
|
|
||||||
let image_frame = image_frame.one_instance().instance;
|
let image = image_frame.one_instance().instance;
|
||||||
|
|
||||||
// Prepare the image data for processing
|
// Prepare the image data for processing
|
||||||
let image = &image_frame.image;
|
|
||||||
let image_data = bytemuck::cast_vec(image.data.clone());
|
let image_data = bytemuck::cast_vec(image.data.clone());
|
||||||
let image_buffer = image::Rgba32FImage::from_raw(image.width, image.height, image_data).expect("Failed to convert internal image format into image-rs data type.");
|
let image_buffer = image::Rgba32FImage::from_raw(image.width, image.height, image_data).expect("Failed to convert internal image format into image-rs data type.");
|
||||||
let dynamic_image: image::DynamicImage = image_buffer.into();
|
let dynamic_image: image::DynamicImage = image_buffer.into();
|
||||||
|
|
@ -34,7 +32,7 @@ async fn dehaze(_: impl Ctx, image_frame: ImageFrameTable<Color>, strength: Perc
|
||||||
base64_string: None,
|
base64_string: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut result = ImageFrameTable::new(ImageFrame { image: dehazed_image });
|
let mut result = ImageFrameTable::new(dehazed_image);
|
||||||
*result.transform_mut() = image_frame_transform;
|
*result.transform_mut() = image_frame_transform;
|
||||||
*result.one_instance_mut().alpha_blending = *image_frame_alpha_blending;
|
*result.one_instance_mut().alpha_blending = *image_frame_alpha_blending;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@ use graph_craft::document::value::TaggedValue;
|
||||||
use graph_craft::document::*;
|
use graph_craft::document::*;
|
||||||
use graph_craft::proto::*;
|
use graph_craft::proto::*;
|
||||||
use graphene_core::application_io::ApplicationIo;
|
use graphene_core::application_io::ApplicationIo;
|
||||||
use graphene_core::raster::image::{ImageFrame, ImageFrameTable};
|
use graphene_core::raster::image::{Image, ImageFrameTable};
|
||||||
use graphene_core::raster::{BlendMode, Image, Pixel};
|
use graphene_core::raster::{BlendMode, Pixel};
|
||||||
use graphene_core::transform::Transform;
|
use graphene_core::transform::Transform;
|
||||||
use graphene_core::transform::TransformMut;
|
use graphene_core::transform::TransformMut;
|
||||||
use graphene_core::*;
|
use graphene_core::*;
|
||||||
|
|
@ -72,9 +72,7 @@ async fn map_gpu<'a: 'input>(image: ImageFrameTable<Color>, node: DocumentNode,
|
||||||
let executor = &editor_api.application_io.as_ref().and_then(|io| io.gpu_executor()).unwrap();
|
let executor = &editor_api.application_io.as_ref().and_then(|io| io.gpu_executor()).unwrap();
|
||||||
|
|
||||||
#[cfg(feature = "image-compare")]
|
#[cfg(feature = "image-compare")]
|
||||||
let img: image::DynamicImage = image::Rgba32FImage::from_raw(image.image.width, image.image.height, bytemuck::cast_vec(image.image.data.clone()))
|
let img: image::DynamicImage = image::Rgba32FImage::from_raw(image.width, image.height, bytemuck::cast_vec(image.data.clone())).unwrap().into();
|
||||||
.unwrap()
|
|
||||||
.into();
|
|
||||||
|
|
||||||
// TODO: The cache should be based on the network topology not the node name
|
// TODO: The cache should be based on the network topology not the node name
|
||||||
let compute_pass_descriptor = if self.cache.lock().as_ref().unwrap().contains_key("placeholder") {
|
let compute_pass_descriptor = if self.cache.lock().as_ref().unwrap().contains_key("placeholder") {
|
||||||
|
|
@ -94,7 +92,7 @@ async fn map_gpu<'a: 'input>(image: ImageFrameTable<Color>, node: DocumentNode,
|
||||||
.create_compute_pass(
|
.create_compute_pass(
|
||||||
&compute_pass_descriptor.pipeline_layout,
|
&compute_pass_descriptor.pipeline_layout,
|
||||||
compute_pass_descriptor.readback_buffer.clone(),
|
compute_pass_descriptor.readback_buffer.clone(),
|
||||||
ComputePassDimensions::XY(image.image.width / 12 + 1, image.image.height / 8 + 1),
|
ComputePassDimensions::XY(image.width / 12 + 1, image.height / 8 + 1),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
executor.execute_compute_pipeline(compute_pass).unwrap();
|
executor.execute_compute_pipeline(compute_pass).unwrap();
|
||||||
|
|
@ -105,7 +103,7 @@ async fn map_gpu<'a: 'input>(image: ImageFrameTable<Color>, node: DocumentNode,
|
||||||
log::debug!("first color: {:?}", colors[0]);
|
log::debug!("first color: {:?}", colors[0]);
|
||||||
|
|
||||||
#[cfg(feature = "image-compare")]
|
#[cfg(feature = "image-compare")]
|
||||||
let img2: image::DynamicImage = image::Rgba32FImage::from_raw(image.image.width, image.image.height, bytemuck::cast_vec(colors.clone())).unwrap().into();
|
let img2: image::DynamicImage = image::Rgba32FImage::from_raw(image.width, image.height, bytemuck::cast_vec(colors.clone())).unwrap().into();
|
||||||
#[cfg(feature = "image-compare")]
|
#[cfg(feature = "image-compare")]
|
||||||
let score = image_compare::rgb_hybrid_compare(&img.into_rgb8(), &img2.into_rgb8()).unwrap();
|
let score = image_compare::rgb_hybrid_compare(&img.into_rgb8(), &img2.into_rgb8()).unwrap();
|
||||||
#[cfg(feature = "image-compare")]
|
#[cfg(feature = "image-compare")]
|
||||||
|
|
@ -113,11 +111,11 @@ async fn map_gpu<'a: 'input>(image: ImageFrameTable<Color>, node: DocumentNode,
|
||||||
|
|
||||||
let new_image = Image {
|
let new_image = Image {
|
||||||
data: colors,
|
data: colors,
|
||||||
width: image.image.width,
|
width: image.width,
|
||||||
height: image.image.height,
|
height: image.height,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
let mut result = ImageFrameTable::new(ImageFrame { image: new_image });
|
let mut result = ImageFrameTable::new(new_image);
|
||||||
*result.transform_mut() = image_frame_table.transform();
|
*result.transform_mut() = image_frame_table.transform();
|
||||||
*result.one_instance_mut().alpha_blending = *image_frame_table.one_instance().alpha_blending;
|
*result.one_instance_mut().alpha_blending = *image_frame_table.one_instance().alpha_blending;
|
||||||
|
|
||||||
|
|
@ -136,7 +134,7 @@ impl<Node, EditorApi> MapGpuNode<Node, EditorApi> {
|
||||||
|
|
||||||
async fn create_compute_pass_descriptor<T: Clone + Pixel + StaticTypeSized>(node: DocumentNode, image: &ImageFrameTable<T>, executor: &&WgpuExecutor) -> Result<ComputePass, String>
|
async fn create_compute_pass_descriptor<T: Clone + Pixel + StaticTypeSized>(node: DocumentNode, image: &ImageFrameTable<T>, executor: &&WgpuExecutor) -> Result<ComputePass, String>
|
||||||
where
|
where
|
||||||
GraphicElement: From<ImageFrame<T>>,
|
GraphicElement: From<Image<T>>,
|
||||||
T::Static: Pixel,
|
T::Static: Pixel,
|
||||||
{
|
{
|
||||||
let image = image.one_instance().instance;
|
let image = image.one_instance().instance;
|
||||||
|
|
@ -215,11 +213,11 @@ where
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let len: usize = image.image.data.len();
|
let len: usize = image.data.len();
|
||||||
|
|
||||||
let storage_buffer = executor
|
let storage_buffer = executor
|
||||||
.create_storage_buffer(
|
.create_storage_buffer(
|
||||||
image.image.data.clone(),
|
image.data.clone(),
|
||||||
StorageBufferOptions {
|
StorageBufferOptions {
|
||||||
cpu_writable: false,
|
cpu_writable: false,
|
||||||
gpu_writable: true,
|
gpu_writable: true,
|
||||||
|
|
@ -234,7 +232,7 @@ where
|
||||||
// let surface = unsafe { executor.create_surface(canvas) }.unwrap();
|
// let surface = unsafe { executor.create_surface(canvas) }.unwrap();
|
||||||
// let surface_id = surface.surface_id;
|
// let surface_id = surface.surface_id;
|
||||||
|
|
||||||
// let texture = executor.create_texture_buffer(image.image.clone(), TextureBufferOptions::Texture).unwrap();
|
// let texture = executor.create_texture_buffer(image.clone(), TextureBufferOptions::Texture).unwrap();
|
||||||
|
|
||||||
// // executor.create_render_pass(texture, surface).unwrap();
|
// // executor.create_render_pass(texture, surface).unwrap();
|
||||||
|
|
||||||
|
|
@ -245,7 +243,7 @@ where
|
||||||
// return frame;
|
// return frame;
|
||||||
|
|
||||||
log::debug!("creating buffer");
|
log::debug!("creating buffer");
|
||||||
let width_uniform = executor.create_uniform_buffer(image.image.width).unwrap();
|
let width_uniform = executor.create_uniform_buffer(image.width).unwrap();
|
||||||
|
|
||||||
let storage_buffer = Arc::new(storage_buffer);
|
let storage_buffer = Arc::new(storage_buffer);
|
||||||
let output_buffer = executor.create_output_buffer(len, concrete!(Color), false).unwrap();
|
let output_buffer = executor.create_output_buffer(len, concrete!(Color), false).unwrap();
|
||||||
|
|
@ -289,8 +287,8 @@ async fn blend_gpu_image(_: impl Ctx, foreground: ImageFrameTable<Color>, backgr
|
||||||
let foreground = foreground.one_instance().instance;
|
let foreground = foreground.one_instance().instance;
|
||||||
let background = background.one_instance().instance;
|
let background = background.one_instance().instance;
|
||||||
|
|
||||||
let foreground_size = DVec2::new(foreground.image.width as f64, foreground.image.height as f64);
|
let foreground_size = DVec2::new(foreground.width as f64, foreground.height as f64);
|
||||||
let background_size = DVec2::new(background.image.width as f64, background.image.height as f64);
|
let background_size = DVec2::new(background.width as f64, background.height as f64);
|
||||||
|
|
||||||
// Transforms a point from the background image to the foreground image
|
// Transforms a point from the background image to the foreground image
|
||||||
let bg_to_fg = DAffine2::from_scale(foreground_size) * foreground_transform.inverse() * background_transform * DAffine2::from_scale(1. / background_size);
|
let bg_to_fg = DAffine2::from_scale(foreground_size) * foreground_transform.inverse() * background_transform * DAffine2::from_scale(1. / background_size);
|
||||||
|
|
@ -371,16 +369,16 @@ async fn blend_gpu_image(_: impl Ctx, foreground: ImageFrameTable<Color>, backgr
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let len = background.image.data.len();
|
let len = background.data.len();
|
||||||
|
|
||||||
let executor = WgpuExecutor::new()
|
let executor = WgpuExecutor::new()
|
||||||
.await
|
.await
|
||||||
.expect("Failed to create wgpu executor. Please make sure that webgpu is enabled for your browser.");
|
.expect("Failed to create wgpu executor. Please make sure that webgpu is enabled for your browser.");
|
||||||
log::debug!("creating buffer");
|
log::debug!("creating buffer");
|
||||||
let width_uniform = executor.create_uniform_buffer(background.image.width).unwrap();
|
let width_uniform = executor.create_uniform_buffer(background.width).unwrap();
|
||||||
let bg_storage_buffer = executor
|
let bg_storage_buffer = executor
|
||||||
.create_storage_buffer(
|
.create_storage_buffer(
|
||||||
background.image.data.clone(),
|
background.data.clone(),
|
||||||
StorageBufferOptions {
|
StorageBufferOptions {
|
||||||
cpu_writable: false,
|
cpu_writable: false,
|
||||||
gpu_writable: true,
|
gpu_writable: true,
|
||||||
|
|
@ -391,7 +389,7 @@ async fn blend_gpu_image(_: impl Ctx, foreground: ImageFrameTable<Color>, backgr
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let fg_storage_buffer = executor
|
let fg_storage_buffer = executor
|
||||||
.create_storage_buffer(
|
.create_storage_buffer(
|
||||||
foreground.image.data.clone(),
|
foreground.data.clone(),
|
||||||
StorageBufferOptions {
|
StorageBufferOptions {
|
||||||
cpu_writable: false,
|
cpu_writable: false,
|
||||||
gpu_writable: true,
|
gpu_writable: true,
|
||||||
|
|
@ -400,7 +398,7 @@ async fn blend_gpu_image(_: impl Ctx, foreground: ImageFrameTable<Color>, backgr
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let fg_width_uniform = executor.create_uniform_buffer(foreground.image.width).unwrap();
|
let fg_width_uniform = executor.create_uniform_buffer(foreground.width).unwrap();
|
||||||
let transform_uniform = executor.create_uniform_buffer(transform_matrix).unwrap();
|
let transform_uniform = executor.create_uniform_buffer(transform_matrix).unwrap();
|
||||||
let translation_uniform = executor.create_uniform_buffer(translation).unwrap();
|
let translation_uniform = executor.create_uniform_buffer(translation).unwrap();
|
||||||
let width_uniform = Arc::new(width_uniform);
|
let width_uniform = Arc::new(width_uniform);
|
||||||
|
|
@ -442,7 +440,7 @@ async fn blend_gpu_image(_: impl Ctx, foreground: ImageFrameTable<Color>, backgr
|
||||||
};
|
};
|
||||||
log::debug!("created pipeline");
|
log::debug!("created pipeline");
|
||||||
let compute_pass = executor
|
let compute_pass = executor
|
||||||
.create_compute_pass(&pipeline, Some(readback_buffer.clone()), ComputePassDimensions::XY(background.image.width, background.image.height))
|
.create_compute_pass(&pipeline, Some(readback_buffer.clone()), ComputePassDimensions::XY(background.width, background.height))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
executor.execute_compute_pipeline(compute_pass).unwrap();
|
executor.execute_compute_pipeline(compute_pass).unwrap();
|
||||||
log::debug!("executed pipeline");
|
log::debug!("executed pipeline");
|
||||||
|
|
@ -452,12 +450,12 @@ async fn blend_gpu_image(_: impl Ctx, foreground: ImageFrameTable<Color>, backgr
|
||||||
|
|
||||||
let created_image = Image {
|
let created_image = Image {
|
||||||
data: colors,
|
data: colors,
|
||||||
width: background.image.width,
|
width: background.width,
|
||||||
height: background.image.height,
|
height: background.height,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut result = ImageFrameTable::new(ImageFrame { image: created_image });
|
let mut result = ImageFrameTable::new(created_image);
|
||||||
*result.transform_mut() = background_transform;
|
*result.transform_mut() = background_transform;
|
||||||
*result.one_instance_mut().alpha_blending = *background_alpha_blending;
|
*result.one_instance_mut().alpha_blending = *background_alpha_blending;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ async fn image_color_palette(
|
||||||
|
|
||||||
let image = image.one_instance().instance;
|
let image = image.one_instance().instance;
|
||||||
|
|
||||||
for pixel in image.image.data.iter() {
|
for pixel in image.data.iter() {
|
||||||
let r = pixel.r() * GRID;
|
let r = pixel.r() * GRID;
|
||||||
let g = pixel.g() * GRID;
|
let g = pixel.g() * GRID;
|
||||||
let b = pixel.b() * GRID;
|
let b = pixel.b() * GRID;
|
||||||
|
|
@ -65,20 +65,17 @@ async fn image_color_palette(
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use graphene_core::raster::image::{ImageFrame, ImageFrameTable};
|
use graphene_core::raster::image::{Image, ImageFrameTable};
|
||||||
use graphene_core::raster::Image;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_image_color_palette() {
|
fn test_image_color_palette() {
|
||||||
let result = image_color_palette(
|
let result = image_color_palette(
|
||||||
(),
|
(),
|
||||||
ImageFrameTable::new(ImageFrame {
|
ImageFrameTable::new(Image {
|
||||||
image: Image {
|
width: 100,
|
||||||
width: 100,
|
height: 100,
|
||||||
height: 100,
|
data: vec![Color::from_rgbaf32(0., 0., 0., 1.).unwrap(); 10000],
|
||||||
data: vec![Color::from_rgbaf32(0., 0., 0., 1.).unwrap(); 10000],
|
base64_string: None,
|
||||||
base64_string: None,
|
|
||||||
},
|
|
||||||
}),
|
}),
|
||||||
1,
|
1,
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,8 @@
|
||||||
use dyn_any::DynAny;
|
use dyn_any::DynAny;
|
||||||
use graphene_core::raster::bbox::Bbox;
|
use graphene_core::raster::bbox::Bbox;
|
||||||
use graphene_core::raster::image::{ImageFrame, ImageFrameTable};
|
use graphene_core::raster::image::{Image, ImageFrameTable};
|
||||||
use graphene_core::raster::{
|
use graphene_core::raster::{
|
||||||
Alpha, AlphaMut, Bitmap, BitmapMut, CellularDistanceFunction, CellularReturnType, DomainWarpType, FractalType, Image, Linear, LinearChannel, Luminance, NoiseType, Pixel, RGBMut, RedGreenBlue,
|
Alpha, AlphaMut, Bitmap, BitmapMut, CellularDistanceFunction, CellularReturnType, DomainWarpType, FractalType, Linear, LinearChannel, Luminance, NoiseType, Pixel, RGBMut, RedGreenBlue, Sample,
|
||||||
Sample,
|
|
||||||
};
|
};
|
||||||
use graphene_core::transform::{Transform, TransformMut};
|
use graphene_core::transform::{Transform, TransformMut};
|
||||||
use graphene_core::{AlphaBlending, Color, Ctx, ExtractFootprint, GraphicElement, Node};
|
use graphene_core::{AlphaBlending, Color, Ctx, ExtractFootprint, GraphicElement, Node};
|
||||||
|
|
@ -33,10 +32,9 @@ fn sample_image(ctx: impl ExtractFootprint + Clone + Send, image_frame: ImageFra
|
||||||
let image_frame_transform = image_frame.transform();
|
let image_frame_transform = image_frame.transform();
|
||||||
let image_frame_alpha_blending = image_frame.one_instance().alpha_blending;
|
let image_frame_alpha_blending = image_frame.one_instance().alpha_blending;
|
||||||
|
|
||||||
let image_frame = image_frame.one_instance().instance;
|
let image = image_frame.one_instance().instance;
|
||||||
|
|
||||||
// Resize the image using the image crate
|
// Resize the image using the image crate
|
||||||
let image = &image_frame.image;
|
|
||||||
let data = bytemuck::cast_vec(image.data.clone());
|
let data = bytemuck::cast_vec(image.data.clone());
|
||||||
|
|
||||||
let footprint = ctx.footprint();
|
let footprint = ctx.footprint();
|
||||||
|
|
@ -86,7 +84,7 @@ fn sample_image(ctx: impl ExtractFootprint + Clone + Send, image_frame: ImageFra
|
||||||
|
|
||||||
let new_transform = image_frame_transform * DAffine2::from_translation(offset) * DAffine2::from_scale(size);
|
let new_transform = image_frame_transform * DAffine2::from_translation(offset) * DAffine2::from_scale(size);
|
||||||
|
|
||||||
let mut result = ImageFrameTable::new(ImageFrame { image });
|
let mut result = ImageFrameTable::new(image);
|
||||||
*result.transform_mut() = new_transform;
|
*result.transform_mut() = new_transform;
|
||||||
*result.one_instance_mut().alpha_blending = *image_frame_alpha_blending;
|
*result.one_instance_mut().alpha_blending = *image_frame_alpha_blending;
|
||||||
|
|
||||||
|
|
@ -263,7 +261,7 @@ where
|
||||||
_P::Static: Pixel,
|
_P::Static: Pixel,
|
||||||
MapFn: for<'any_input> Node<'any_input, (_P, _P), Output = _P> + 'n + Clone,
|
MapFn: for<'any_input> Node<'any_input, (_P, _P), Output = _P> + 'n + Clone,
|
||||||
_Fg: Sample<Pixel = _P> + Transform + Clone + Send + 'n,
|
_Fg: Sample<Pixel = _P> + Transform + Clone + Send + 'n,
|
||||||
GraphicElement: From<ImageFrame<_P>>,
|
GraphicElement: From<Image<_P>>,
|
||||||
{
|
{
|
||||||
let (background, foreground) = images;
|
let (background, foreground) = images;
|
||||||
|
|
||||||
|
|
@ -330,11 +328,11 @@ fn extend_image_to_bounds(image: ImageFrameTable<Color>, bounds: DAffine2) -> Im
|
||||||
}
|
}
|
||||||
|
|
||||||
let image_instance = image.one_instance().instance;
|
let image_instance = image.one_instance().instance;
|
||||||
if image_instance.image.width == 0 || image_instance.image.height == 0 {
|
if image_instance.width == 0 || image_instance.height == 0 {
|
||||||
return empty_image((), bounds, Color::TRANSPARENT);
|
return empty_image((), bounds, Color::TRANSPARENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
let orig_image_scale = DVec2::new(image_instance.image.width as f64, image_instance.image.height as f64);
|
let orig_image_scale = DVec2::new(image_instance.width as f64, image_instance.height as f64);
|
||||||
let layer_to_image_space = DAffine2::from_scale(orig_image_scale) * image.transform().inverse();
|
let layer_to_image_space = DAffine2::from_scale(orig_image_scale) * image.transform().inverse();
|
||||||
let bounds_in_image_space = Bbox::unit().affine_transform(layer_to_image_space * bounds).to_axis_aligned_bbox();
|
let bounds_in_image_space = Bbox::unit().affine_transform(layer_to_image_space * bounds).to_axis_aligned_bbox();
|
||||||
|
|
||||||
|
|
@ -345,11 +343,11 @@ fn extend_image_to_bounds(image: ImageFrameTable<Color>, bounds: DAffine2) -> Im
|
||||||
// Copy over original image into enlarged image.
|
// Copy over original image into enlarged image.
|
||||||
let mut new_img = Image::new(new_scale.x as u32, new_scale.y as u32, Color::TRANSPARENT);
|
let mut new_img = Image::new(new_scale.x as u32, new_scale.y as u32, Color::TRANSPARENT);
|
||||||
let offset_in_new_image = (-new_start).as_uvec2();
|
let offset_in_new_image = (-new_start).as_uvec2();
|
||||||
for y in 0..image_instance.image.height {
|
for y in 0..image_instance.height {
|
||||||
let old_start = y * image_instance.image.width;
|
let old_start = y * image_instance.width;
|
||||||
let new_start = (y + offset_in_new_image.y) * new_img.width + offset_in_new_image.x;
|
let new_start = (y + offset_in_new_image.y) * new_img.width + offset_in_new_image.x;
|
||||||
let old_row = &image_instance.image.data[old_start as usize..(old_start + image_instance.image.width) as usize];
|
let old_row = &image_instance.data[old_start as usize..(old_start + image_instance.width) as usize];
|
||||||
let new_row = &mut new_img.data[new_start as usize..(new_start + image_instance.image.width) as usize];
|
let new_row = &mut new_img.data[new_start as usize..(new_start + image_instance.width) as usize];
|
||||||
new_row.copy_from_slice(old_row);
|
new_row.copy_from_slice(old_row);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -357,7 +355,7 @@ fn extend_image_to_bounds(image: ImageFrameTable<Color>, bounds: DAffine2) -> Im
|
||||||
// let layer_to_new_texture_space = (DAffine2::from_scale(1. / new_scale) * DAffine2::from_translation(new_start) * layer_to_image_space).inverse();
|
// let layer_to_new_texture_space = (DAffine2::from_scale(1. / new_scale) * DAffine2::from_translation(new_start) * layer_to_image_space).inverse();
|
||||||
let new_texture_to_layer_space = image.transform() * DAffine2::from_scale(1. / orig_image_scale) * DAffine2::from_translation(new_start) * DAffine2::from_scale(new_scale);
|
let new_texture_to_layer_space = image.transform() * DAffine2::from_scale(1. / orig_image_scale) * DAffine2::from_translation(new_start) * DAffine2::from_scale(new_scale);
|
||||||
|
|
||||||
let mut result = ImageFrameTable::new(ImageFrame { image: new_img });
|
let mut result = ImageFrameTable::new(new_img);
|
||||||
*result.transform_mut() = new_texture_to_layer_space;
|
*result.transform_mut() = new_texture_to_layer_space;
|
||||||
*result.one_instance_mut().alpha_blending = *image.one_instance().alpha_blending;
|
*result.one_instance_mut().alpha_blending = *image.one_instance().alpha_blending;
|
||||||
|
|
||||||
|
|
@ -371,7 +369,7 @@ fn empty_image(_: impl Ctx, transform: DAffine2, color: Color) -> ImageFrameTabl
|
||||||
|
|
||||||
let image = Image::new(width, height, color);
|
let image = Image::new(width, height, color);
|
||||||
|
|
||||||
let mut result = ImageFrameTable::new(ImageFrame { image });
|
let mut result = ImageFrameTable::new(image);
|
||||||
*result.transform_mut() = transform;
|
*result.transform_mut() = transform;
|
||||||
*result.one_instance_mut().alpha_blending = AlphaBlending::default();
|
*result.one_instance_mut().alpha_blending = AlphaBlending::default();
|
||||||
|
|
||||||
|
|
@ -559,7 +557,7 @@ fn noise_pattern(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut result = ImageFrameTable::new(ImageFrame { image });
|
let mut result = ImageFrameTable::new(image);
|
||||||
*result.transform_mut() = DAffine2::from_translation(offset) * DAffine2::from_scale(size);
|
*result.transform_mut() = DAffine2::from_translation(offset) * DAffine2::from_scale(size);
|
||||||
*result.one_instance_mut().alpha_blending = AlphaBlending::default();
|
*result.one_instance_mut().alpha_blending = AlphaBlending::default();
|
||||||
|
|
||||||
|
|
@ -621,7 +619,7 @@ fn noise_pattern(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut result = ImageFrameTable::new(ImageFrame { image });
|
let mut result = ImageFrameTable::new(image);
|
||||||
*result.transform_mut() = DAffine2::from_translation(offset) * DAffine2::from_scale(size);
|
*result.transform_mut() = DAffine2::from_translation(offset) * DAffine2::from_scale(size);
|
||||||
*result.one_instance_mut().alpha_blending = AlphaBlending::default();
|
*result.one_instance_mut().alpha_blending = AlphaBlending::default();
|
||||||
|
|
||||||
|
|
@ -669,7 +667,7 @@ fn mandelbrot(ctx: impl ExtractFootprint + Send) -> ImageFrameTable<Color> {
|
||||||
data,
|
data,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
let mut result = ImageFrameTable::new(ImageFrame { image });
|
let mut result = ImageFrameTable::new(image);
|
||||||
*result.transform_mut() = DAffine2::from_translation(offset) * DAffine2::from_scale(size);
|
*result.transform_mut() = DAffine2::from_translation(offset) * DAffine2::from_scale(size);
|
||||||
*result.one_instance_mut().alpha_blending = Default::default();
|
*result.one_instance_mut().alpha_blending = Default::default();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,7 @@ use graphene_core::application_io::SurfaceHandle;
|
||||||
use graphene_core::application_io::{ApplicationIo, ExportFormat, RenderConfig};
|
use graphene_core::application_io::{ApplicationIo, ExportFormat, RenderConfig};
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
use graphene_core::raster::bbox::Bbox;
|
use graphene_core::raster::bbox::Bbox;
|
||||||
use graphene_core::raster::image::{ImageFrame, ImageFrameTable};
|
use graphene_core::raster::image::{Image, ImageFrameTable};
|
||||||
use graphene_core::raster::Image;
|
|
||||||
use graphene_core::renderer::RenderMetadata;
|
use graphene_core::renderer::RenderMetadata;
|
||||||
use graphene_core::renderer::{format_transform_matrix, GraphicElementRendered, ImageRenderMode, RenderParams, RenderSvgSegmentList, SvgRender};
|
use graphene_core::renderer::{format_transform_matrix, GraphicElementRendered, ImageRenderMode, RenderParams, RenderSvgSegmentList, SvgRender};
|
||||||
use graphene_core::transform::Footprint;
|
use graphene_core::transform::Footprint;
|
||||||
|
|
@ -81,13 +80,11 @@ fn decode_image(_: impl Ctx, data: Arc<[u8]>) -> ImageFrameTable<Color> {
|
||||||
return ImageFrameTable::empty();
|
return ImageFrameTable::empty();
|
||||||
};
|
};
|
||||||
let image = image.to_rgba32f();
|
let image = image.to_rgba32f();
|
||||||
let image = ImageFrame {
|
let image = Image {
|
||||||
image: Image {
|
data: image.chunks(4).map(|pixel| Color::from_unassociated_alpha(pixel[0], pixel[1], pixel[2], pixel[3])).collect(),
|
||||||
data: image.chunks(4).map(|pixel| Color::from_unassociated_alpha(pixel[0], pixel[1], pixel[2], pixel[3])).collect(),
|
width: image.width(),
|
||||||
width: image.width(),
|
height: image.height(),
|
||||||
height: image.height(),
|
..Default::default()
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
ImageFrameTable::new(image)
|
ImageFrameTable::new(image)
|
||||||
|
|
@ -204,9 +201,7 @@ async fn rasterize<T: GraphicElementRendered + graphene_core::transform::Transfo
|
||||||
|
|
||||||
let rasterized = context.get_image_data(0., 0., resolution.x as f64, resolution.y as f64).unwrap();
|
let rasterized = context.get_image_data(0., 0., resolution.x as f64, resolution.y as f64).unwrap();
|
||||||
|
|
||||||
let mut result = ImageFrameTable::new(ImageFrame {
|
let mut result = ImageFrameTable::new(Image::from_image_data(&rasterized.data().0, resolution.x as u32, resolution.y as u32));
|
||||||
image: Image::from_image_data(&rasterized.data().0, resolution.x as u32, resolution.y as u32),
|
|
||||||
});
|
|
||||||
*result.transform_mut() = footprint.transform;
|
*result.transform_mut() = footprint.transform;
|
||||||
|
|
||||||
result
|
result
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ use graphene_core::{fn_type_fut, future};
|
||||||
use graphene_core::{Cow, ProtoNodeIdentifier, Type};
|
use graphene_core::{Cow, ProtoNodeIdentifier, Type};
|
||||||
use graphene_core::{Node, NodeIO, NodeIOTypes};
|
use graphene_core::{Node, NodeIO, NodeIOTypes};
|
||||||
use graphene_std::any::{ComposeTypeErased, DowncastBothNode, DynAnyNode, FutureWrapperNode, IntoTypeErasedNode};
|
use graphene_std::any::{ComposeTypeErased, DowncastBothNode, DynAnyNode, FutureWrapperNode, IntoTypeErasedNode};
|
||||||
use graphene_std::application_io::TextureFrame;
|
use graphene_std::application_io::ImageTexture;
|
||||||
use graphene_std::wasm_application_io::*;
|
use graphene_std::wasm_application_io::*;
|
||||||
use graphene_std::Context;
|
use graphene_std::Context;
|
||||||
use graphene_std::GraphicElement;
|
use graphene_std::GraphicElement;
|
||||||
|
|
@ -79,7 +79,7 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
|
||||||
async_node!(graphene_core::ops::IntoNode<GraphicGroupTable>, input: VectorDataTable, params: []),
|
async_node!(graphene_core::ops::IntoNode<GraphicGroupTable>, input: VectorDataTable, params: []),
|
||||||
async_node!(graphene_core::ops::IntoNode<GraphicGroupTable>, input: ImageFrameTable<Color>, params: []),
|
async_node!(graphene_core::ops::IntoNode<GraphicGroupTable>, input: ImageFrameTable<Color>, params: []),
|
||||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => ImageFrameTable<Color>]),
|
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => ImageFrameTable<Color>]),
|
||||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => TextureFrame]),
|
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => ImageTexture]),
|
||||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => VectorDataTable]),
|
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => VectorDataTable]),
|
||||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => GraphicGroupTable]),
|
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => GraphicGroupTable]),
|
||||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => GraphicElement]),
|
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => GraphicElement]),
|
||||||
|
|
@ -268,7 +268,7 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
|
||||||
async_node!(graphene_core::memo::ImpureMemoNode<_, _, _>, input: Context, fn_params: [Context => ShaderInputFrame]),
|
async_node!(graphene_core::memo::ImpureMemoNode<_, _, _>, input: Context, fn_params: [Context => ShaderInputFrame]),
|
||||||
async_node!(graphene_core::memo::ImpureMemoNode<_, _, _>, input: Context, fn_params: [Context => WgpuSurface]),
|
async_node!(graphene_core::memo::ImpureMemoNode<_, _, _>, input: Context, fn_params: [Context => WgpuSurface]),
|
||||||
async_node!(graphene_core::memo::ImpureMemoNode<_, _, _>, input: Context, fn_params: [Context => Option<WgpuSurface>]),
|
async_node!(graphene_core::memo::ImpureMemoNode<_, _, _>, input: Context, fn_params: [Context => Option<WgpuSurface>]),
|
||||||
async_node!(graphene_core::memo::ImpureMemoNode<_, _, _>, input: Context, fn_params: [Context => TextureFrame]),
|
async_node!(graphene_core::memo::ImpureMemoNode<_, _, _>, input: Context, fn_params: [Context => ImageTexture]),
|
||||||
];
|
];
|
||||||
let mut map: HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeConstructor>> = HashMap::new();
|
let mut map: HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeConstructor>> = HashMap::new();
|
||||||
for (id, entry) in graphene_core::registry::NODE_REGISTRY.lock().unwrap().iter() {
|
for (id, entry) in graphene_core::registry::NODE_REGISTRY.lock().unwrap().iter() {
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ pub use executor::GpuExecutor;
|
||||||
|
|
||||||
use dyn_any::{DynAny, StaticType};
|
use dyn_any::{DynAny, StaticType};
|
||||||
use gpu_executor::{ComputePassDimensions, GPUConstant, StorageBufferOptions, TextureBufferOptions, TextureBufferType, ToStorageBuffer, ToUniformBuffer};
|
use gpu_executor::{ComputePassDimensions, GPUConstant, StorageBufferOptions, TextureBufferOptions, TextureBufferType, ToStorageBuffer, ToUniformBuffer};
|
||||||
use graphene_core::application_io::{ApplicationIo, EditorApi, SurfaceHandle, TextureFrame};
|
use graphene_core::application_io::{ApplicationIo, EditorApi, ImageTexture, SurfaceHandle};
|
||||||
use graphene_core::raster::image::ImageFrameTable;
|
use graphene_core::raster::image::ImageFrameTable;
|
||||||
use graphene_core::raster::{Image, SRGBA8};
|
use graphene_core::raster::{Image, SRGBA8};
|
||||||
use graphene_core::transform::{Footprint, Transform};
|
use graphene_core::transform::{Footprint, Transform};
|
||||||
|
|
@ -913,14 +913,14 @@ async fn render_texture<'a: 'n>(
|
||||||
}
|
}
|
||||||
|
|
||||||
#[node_macro::node(category(""))]
|
#[node_macro::node(category(""))]
|
||||||
async fn upload_texture<'a: 'n>(_: impl ExtractFootprint + Ctx, input: ImageFrameTable<Color>, executor: &'a WgpuExecutor) -> TextureFrame {
|
async fn upload_texture<'a: 'n>(_: impl ExtractFootprint + Ctx, input: ImageFrameTable<Color>, executor: &'a WgpuExecutor) -> ImageTexture {
|
||||||
// let new_data: Vec<RGBA16F> = input.image.data.into_iter().map(|c| c.into()).collect();
|
// let new_data: Vec<RGBA16F> = input.image.data.into_iter().map(|c| c.into()).collect();
|
||||||
|
|
||||||
let input = input.one_instance().instance;
|
let input = input.one_instance().instance;
|
||||||
let new_data: Vec<SRGBA8> = input.image.data.iter().map(|x| (*x).into()).collect();
|
let new_data: Vec<SRGBA8> = input.data.iter().map(|x| (*x).into()).collect();
|
||||||
let new_image = Image {
|
let new_image = Image {
|
||||||
width: input.image.width,
|
width: input.width,
|
||||||
height: input.image.height,
|
height: input.height,
|
||||||
data: new_data,
|
data: new_data,
|
||||||
base64_string: None,
|
base64_string: None,
|
||||||
};
|
};
|
||||||
|
|
@ -932,9 +932,9 @@ async fn upload_texture<'a: 'n>(_: impl ExtractFootprint + Ctx, input: ImageFram
|
||||||
_ => unreachable!("Unsupported ShaderInput type"),
|
_ => unreachable!("Unsupported ShaderInput type"),
|
||||||
};
|
};
|
||||||
|
|
||||||
TextureFrame {
|
ImageTexture {
|
||||||
texture: texture.into(),
|
texture: texture.into(),
|
||||||
// TODO: Find an alternate way to encode the transform and alpha_blend now that these fields have been moved up out of TextureFrame
|
// TODO: Find an alternate way to encode the transform and alpha_blend now that these fields have been moved up out of ImageTexture
|
||||||
// transform: input.transform,
|
// transform: input.transform,
|
||||||
// alpha_blend: Default::default(),
|
// alpha_blend: Default::default(),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue