use serde::{Deserialize, Serialize};
use crate::document::layer_kind::{IdMap, LayerKindRegistration, PixelBlobSpec, SerializedEntity};
use crate::format::error::LoadError;
use crate::format::manifest::{texture_format_from_str, texture_format_to_str, ManifestPixelRef};
use crate::gpu::blend_mode;
use crate::layer::{BlendProps, Layer, LayerId, LayerNode, NodeCommon, PixelBuffer, RasterLayer};
pub const TYPE_ID: &str = "raster";
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
struct RasterBody {
name: String,
visible: bool,
locked: bool,
opacity: f32,
blend_mode: String,
pixels: ManifestPixelRef,
#[serde(default)]
modifiers: Vec<u64>,
}
pub fn register() -> LayerKindRegistration {
LayerKindRegistration {
type_id: TYPE_ID,
display_name: "Raster Layer",
can_have_mask: true,
can_rename: true,
has_thumbnail: true,
icon: "",
serialize,
deserialize,
remap_ids,
}
}
fn serialize(node: &LayerNode) -> SerializedEntity {
let r = match node {
LayerNode::Layer(Layer::Raster(r)) => r,
_ => panic!("raster::serialize received non-raster LayerNode"),
};
let blob_path = format!("layers/{}.pixels", r.id.to_ffi());
let pixels = ManifestPixelRef {
format: texture_format_to_str(r.pixels.format).to_string(),
pixels: blob_path.clone(),
bounds: r.pixels.bounds,
};
let body = RasterBody {
name: r.common.name.clone(),
visible: r.common.visible,
locked: r.common.locked,
opacity: r.blend.opacity,
blend_mode: r.blend.blend_mode.type_id.to_string(),
pixels: pixels.clone(),
modifiers: r.filters.iter().map(|m| m.to_ffi()).collect(),
};
SerializedEntity {
body: serde_json::to_value(&body).expect("derived serde for RasterBody is infallible"),
pixel_blobs: vec![PixelBlobSpec {
blob_key: blob_path,
source_node_id: r.id,
pixels,
}],
}
}
fn deserialize(body: &serde_json::Value, id: LayerId) -> Result<LayerNode, LoadError> {
let body: RasterBody =
serde_json::from_value(body.clone()).map_err(|e| LoadError::CorruptManifest {
reason: format!("raster body: {e}"),
})?;
let blend_reg = blend_mode::registry()
.get(&body.blend_mode)
.ok_or_else(|| LoadError::CorruptManifest {
reason: format!(
"raster {} references undeclared blend_mode/{} \
— `requires` block lies",
id.to_ffi(),
body.blend_mode
),
})?;
let format =
texture_format_from_str(&body.pixels.format).ok_or_else(|| LoadError::CorruptManifest {
reason: format!(
"raster {} uses unknown texture format '{}'",
id.to_ffi(),
body.pixels.format
),
})?;
Ok(LayerNode::Layer(Layer::Raster(RasterLayer {
id,
common: NodeCommon {
name: body.name,
visible: body.visible,
locked: body.locked,
},
blend: BlendProps {
opacity: body.opacity,
blend_mode: blend_reg,
},
pixels: PixelBuffer::new(body.pixels.bounds, format),
filters: body.modifiers.into_iter().map(LayerId::from_ffi).collect(),
})))
}
fn remap_ids(node: &mut LayerNode, id_map: &IdMap) {
let LayerNode::Layer(Layer::Raster(r)) = node else {
panic!("raster::remap_ids received non-raster LayerNode");
};
for m in r.filters.iter_mut() {
let old_ffi = m.to_ffi();
if let Some(new_id) = id_map.get(&old_ffi) {
*m = *new_id;
}
}
}