use super::super::rendering::commit_undo_region;
use super::super::{DarklyEngine, PendingFilter};
use crate::coord::WindowRect;
use crate::engine::types::VeilTypeInfo;
use crate::layer::LayerId;
use crate::undo::GpuRegionAction;
impl DarklyEngine {
pub fn filter_types(&self) -> Vec<VeilTypeInfo> {
self.compositor
.filter_pipeline_registry()
.types()
.into_iter()
.map(|(type_id, display_name)| VeilTypeInfo {
type_id,
display_name,
params: Vec::new(),
})
.collect()
}
pub fn apply_filter(&mut self, node_id: LayerId, filter_type: &str) -> bool {
if !self.doc.is_node_editable(node_id) {
return false;
}
if !self.compositor.filter_pipeline_registry().has(filter_type) {
return false;
}
self.auto_commit_floating();
if self.doc.layer(node_id).is_none() && self.doc.find_filter(node_id).is_none() {
return false;
}
let (node_extent, format) = match self.compositor.node_texture(node_id) {
Some(t) => (t.canvas_extent(), t.format()),
None => return false,
};
let (region, mask_tex) = if self.has_selection() {
let bounds = match self.selection_pixel_bounds() {
Some(b) => b,
None => {
let recomputed = self.selection_cpu_cache().and_then(|d| {
crate::mask::pixel_bounds_r8(d, self.doc.width, self.doc.height)
.map(|[x, y, w, h]| WindowRect::from_xywh(x as i32, y as i32, w, h))
});
match recomputed {
Some(b) => {
self.set_selection_pixel_bounds(Some(b));
b
}
None => {
self.pending_filter = Some(PendingFilter {
node_id,
filter_type: filter_type.to_string(),
});
self.kick_selection_readback();
return false;
}
}
}
};
if bounds.width == 0 || bounds.height == 0 {
return false;
}
let region_plane = bounds.to_canvas(self.doc.canvas_origin);
let region = match node_extent.intersect(region_plane) {
Some(r) if r.width > 0 && r.height > 0 => r,
_ => return false,
};
let win_origin = (
region.origin.x - self.doc.canvas_origin.x,
region.origin.y - self.doc.canvas_origin.y,
);
let mask_tex =
self.upload_cropped_selection_texture(win_origin, region.width, region.height);
(region, mask_tex)
} else {
(node_extent, None)
};
let pipeline = match self
.compositor
.filter_pipeline_registry_mut()
.pipeline(filter_type, &self.gpu.device)
{
Some(p) => p,
None => return false,
};
let frame = self
.compositor
.node_texture(node_id)
.expect("checked above")
.canvas_frame();
let snap = self.gpu.encode_ret("filter-save", |enc| {
self.region_scratch
.save_region(&self.gpu.device, enc, &frame, format, region)
});
let entry = commit_undo_region(
&self.gpu,
&self.region_scratch,
&mut self.readbacks,
"filter-commit",
node_id,
&frame,
&snap,
region,
);
let mask_view = mask_tex
.as_ref()
.map(|t| t.create_view(&wgpu::TextureViewDescriptor::default()));
self.gpu.encode("apply-filter", |enc| {
self.compositor.filter_node_region(
&self.gpu.device,
&self.gpu.queue,
enc,
node_id,
region,
mask_view.as_ref(),
&pipeline,
);
});
self.push_undo(Box::new(GpuRegionAction::new(entry)));
self.compositor.mark_dirty();
true
}
}