after-effects
after-effects copied to clipboard
High level interface
I'm designing a high level plugin interface for the bindings, and my general idea is to have something like:
struct PortablePlugin { }
impl AdobePlugin for PortablePlugin {
fn can_load(_host_name: &str, _host_version: &str) -> bool { true }
fn new() -> Self { Self {} }
fn handle_command(&mut self, cmd: Command) {
match cmd {
Command::About { mut out_data, .. } => {
out_data.set_return_msg("Test plugin."));
}
Command::Render { in_data, mut params, output, .. } => {
// ...
}
Command::GpuDeviceSetup { in_data, mut out_data, extra/*: GPUDeviceSetupExtra*/ } => { ... }
// ...
}
}
}
register_plugin!(PortablePlugin);
basically the idea is to only expose relevant and valid data in each command, including all extra
s properly casted. I have that implemented so far, but I have a few concerns I wanted to discuss:
Struct instances
- Should we create and maintain global instance for user? What I imagine is that
PortablePlugin
struct would be stored inglobal_data
and would be a single object alive for the entire time the project is open (and any plugin instance is added to the layer) - Should we create and maintain sequence instance for user? That would be a separate struct, which is unique per every layer where the plugin is applied. This would be stored in
sequence_data
and I imagine I would require the user to make this structserde::Serialize
andserde::Deserialize
and automatically handle flattening the data withbincode
. Also that struct should be Send + Sync I believe, because AE can call the commands from any thread at any time? Is that correct?
I believe these two points are very useful for almost all plugins and at the same time quite time-consuming to implement properly by the user. Pros:
- User can focus on just his actual plugin code without worrying about complicated details of Handles and flattening
- Much easier to get started with writing plugins
Cons:
- A bit of memory overhead, since the instances would be always created. But since we're talking about video processing plugins here, any overhead like that is nothing compared to actual pixels processing so it should be fine. We could maybe make this optional with a
register_plugin
macro parameter or something
Parameters
- What do you think to create something like
ParameterRegistry
, which would be a manager for user params, with the enum-based getter/setter provided by user, and all parameters would be defined and retrieved using this enum. Something like:
enum MyParams {
MixChannels
};
fn handle_command(&mut self, cmd: Command) {
match cmd {
Command::ParamsSetup { mut params } => {
params.add_param(MyParams::MixChannels,
"Mix channels",
ae::FloatSliderDef::new()
.set_value(10.0)
.precision(1)
.display_flags(ae::ValueDisplayFlag::PERCENT)
);
}
Command::Render { mut params, .. } => {
let slider = params.get::<ae::Param::FloatSlider>(MyParams::MixChannels);
// slider.value()
}
}
}
register_plugin!(PortablePlugin, MyParams);
That struct would maintain params array, indexes and counts (and would be stored in global instance data), so users won't have to worry about it.
I'll have more things to discuss once I get further, but let's start with these.
Let me know your thoughts, thanks!
CC @virtualritz @mobile-bungalow