use ezu_graph::{
schema_frag, Asset, BuiltNode, EvalCtx, EvalError, FactoryCtx, FactoryError, Node, NodeFactory,
PortKind, PortSpec, PortValue,
};
use ezu_style as spec;
use serde_json::Value;
use xxhash_rust::xxh3::Xxh3;
struct ImageNode {
src: String,
}
impl Node for ImageNode {
fn op_name(&self) -> &'static str {
"image"
}
fn inputs(&self) -> &[PortSpec] {
&[]
}
fn output(&self, _input_kinds: &[Option<PortKind>]) -> PortKind {
PortKind::Sprite
}
fn eval(&self, ctx: &EvalCtx<'_>, _: &[Option<PortValue>]) -> Result<PortValue, EvalError> {
let asset = ctx.assets.load(&self.src)?;
let Asset::Image(raster) = asset else {
return Err(EvalError::Other(format!(
"asset `{}` is not an image",
self.src
)));
};
Ok(PortValue::Sprite(raster))
}
fn param_hash(&self, h: &mut Xxh3) {
h.update(b"image");
h.update(self.src.as_bytes());
}
}
pub(super) struct ImageFactory;
impl NodeFactory for ImageFactory {
fn op_name(&self) -> &'static str {
"image"
}
fn build(
&self,
fields: &serde_json::Map<String, Value>,
ctx: &FactoryCtx<'_>,
) -> Result<BuiltNode, FactoryError> {
let raw = fields
.get("src")
.and_then(Value::as_str)
.ok_or_else(|| FactoryError::MissingField("src".into()))?;
let src = match spec::FieldRef::classify(raw) {
spec::FieldRef::Node(name) => {
let source = ctx
.sources
.get(name)
.ok_or_else(|| FactoryError::UnknownAsset(name.to_string()))?;
let spec::SourceDecl::Image(file) = source else {
return Err(FactoryError::BadField {
field: "src".into(),
msg: format!("source `{name}` is not an image"),
});
};
file.src.clone()
}
spec::FieldRef::Literal(s) => s.to_string(),
spec::FieldRef::Param(_) => {
return Err(FactoryError::BadField {
field: "src".into(),
msg: "param refs not allowed for image src".into(),
});
}
};
Ok(BuiltNode {
node: Box::new(ImageNode { src }),
connections: vec![],
})
}
fn schema(&self) -> Value {
serde_json::json!({
"description": "Image asset source. `src` is an `@asset` ref or a literal path/name resolved by the host's AssetLoader. Output preserves the source dimensions.",
"properties": { "src": schema_frag::asset_ref() },
"required": ["src"],
})
}
}
ezu_graph::submit_node!(ImageFactory);