use crate::kvasir::node::{ExecutionContext, KvasirNode};
use crate::kvasir::nodes::RES_SCENE;
use crate::kvasir::resource::ResourceId;
pub const RES_FILTER_TEMP_A: ResourceId = ResourceId(100);
pub const RES_FILTER_TEMP_B: ResourceId = ResourceId(101);
pub const RES_FILTER_INPUT: ResourceId = ResourceId(102);
pub struct SvgFilterNode {
input: ResourceId,
output: ResourceId,
input_slice: [ResourceId; 1],
output_slice: [ResourceId; 1],
filter_graph: Option<crate::filter::SvgFilterGraph>,
label: &'static str,
}
impl SvgFilterNode {
pub fn new(input: ResourceId, output: ResourceId) -> Self {
Self {
input,
output,
input_slice: [input; 1],
output_slice: [output; 1],
filter_graph: None,
label: "SvgFilter",
}
}
pub fn with_filter_graph(mut self, graph: crate::filter::SvgFilterGraph) -> Self {
self.filter_graph = Some(graph);
self
}
pub fn with_label(mut self, label: &'static str) -> Self {
self.label = label;
self
}
}
impl KvasirNode for SvgFilterNode {
fn label(&self) -> &'static str {
self.label
}
fn inputs(&self) -> &[ResourceId] {
&self.input_slice
}
fn outputs(&self) -> &[ResourceId] {
&self.output_slice
}
fn pass_id(&self) -> crate::kvasir::nodes::PassId {
crate::kvasir::nodes::PassId::PostProcess {
pipeline_id: 0xF1_000,
}
}
fn execute(&self, ctx: &mut ExecutionContext) {
if let Some(ref graph) = self.filter_graph {
let mut engine = crate::filter::FilterEngine::new();
engine.execute(graph, ctx);
tracing::trace!(
"[Kvasir] Executed SVG filter: {} -> {:?} ({} primitives)",
self.label,
self.output,
graph.primitives.len()
);
}
}
}
impl Default for SvgFilterNode {
fn default() -> Self {
Self::new(RES_SCENE, RES_SCENE)
}
}
#[cfg(test)]
mod p1_35_filter_graph_tests {
use super::*;
use crate::filter::SvgFilterGraphBuilder;
#[test]
fn filter_node_identity() {
let node = SvgFilterNode::new(RES_SCENE, RES_FILTER_TEMP_A);
assert_eq!(node.inputs(), &[RES_SCENE]);
assert_eq!(node.outputs(), &[RES_FILTER_TEMP_A]);
assert_eq!(node.label(), "SvgFilter");
}
#[test]
fn filter_node_with_label() {
let node = SvgFilterNode::new(RES_SCENE, RES_FILTER_TEMP_A).with_label("MyFilter");
assert_eq!(node.label(), "MyFilter");
}
#[test]
fn filter_node_pass_id_is_post_process() {
let node = SvgFilterNode::new(RES_SCENE, RES_FILTER_TEMP_A);
match node.pass_id() {
crate::kvasir::nodes::PassId::PostProcess { pipeline_id } => {
assert_eq!(pipeline_id, 0xF1_000);
}
other => panic!("expected PostProcess, got {:?}", other),
}
}
#[test]
fn filter_graph_builder_creates_nodes() {
let builder = SvgFilterGraphBuilder::new();
let nodes = builder.build();
assert!(nodes.is_empty());
}
#[test]
fn filter_node_without_filter_graph_is_noop() {
let node = SvgFilterNode::new(RES_SCENE, RES_FILTER_TEMP_A);
assert!(node.filter_graph.is_none());
}
}