1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
use crate::*;
use crate::aegp::*;
use ae_sys::{ A_long, A_short, A_Time, AEGP_StreamValue2, AEGP_KeyframeEase, AEGP_StreamRefH };
define_suite!(
/// Keyframes make After Effects what it is. AEGPs (and...ssshh, don't tell anyone...effects) can use this suite to add, manipulate and remove keyframes from any keyframe-able stream.
///
/// # Adding Multiple Keyframes
/// Each time you call [`insert_keyframe`](Self::insert_keyframe), the entire stream is added to the undo stack.
///
/// If you're adding one or two keyframes, this isn't a problem. However, if you're writing a keyframer, you'll want to do things the *right* way.
///
/// Before you begin adding keyframes, call the (very-appropriately-named) [`start_add_keyframes`](Self::start_add_keyframes).
///
/// For each keyframe to add, call [`AddKeyframesInfoHandle::add_keyframes`] to set the time to be used (and get the newly-added keyframe's index), then [`AddKeyframesInfoHandle::set_add_keyframe`] to specify the value to be used.
///
/// Once you're finished, simply drop the [`AddKeyframesInfoHandle`] to let know After Effects know it's time to add the changed parameter stream to the undo stack.
KeyframeSuite,
AEGP_KeyframeSuite5,
kAEGPKeyframeSuite,
kAEGPKeyframeSuiteVersion5
);
impl KeyframeSuite {
/// Acquire this suite from the host. Returns error if the suite is not available.
/// Suite is released on drop.
pub fn new() -> Result<Self, Error> {
crate::Suite::new()
}
/// Retrieves the number of keyframes on the given stream.
///
/// Returns `-1` if the stream is not keyframe-able.
///
/// Also, note that a stream without keyframes isn't necessarily constant; it can be altered by expressions.
pub fn stream_num_kfs(&self, stream: impl AsPtr<AEGP_StreamRefH>) -> Result<i32, Error> {
Ok(call_suite_fn_single!(self, AEGP_GetStreamNumKFs -> A_long, stream.as_ptr())? as i32)
}
/// Retrieves the time of the specified keyframe.
pub fn keyframe_time(&self, stream: impl AsPtr<AEGP_StreamRefH>, key_index: i32, time_mode: TimeMode) -> Result<Time, Error> {
Ok(call_suite_fn_single!(self, AEGP_GetKeyframeTime -> A_Time, stream.as_ptr(), key_index, time_mode.into())?.into())
}
/// Adds a keyframe to the specified stream (at the specified composition or layer time).
///
/// Returns the new keyframe's index.
///
/// All indexes greater than the new index are now invalid (but you knew that).
///
/// If there is already a keyframe at that time, the values will be updated.
pub fn insert_keyframe(&self, stream: impl AsPtr<AEGP_StreamRefH>, time_mode: TimeMode, time: Time) -> Result<i32, Error> {
Ok(call_suite_fn_single!(self, AEGP_InsertKeyframe -> A_long, stream.as_ptr(), time_mode.into(), &time.into() as *const _)? as i32)
}
/// Deletes the specified keyframe.
pub fn delete_keyframe(&self, stream: impl AsPtr<AEGP_StreamRefH>, key_index: i32) -> Result<(), Error> {
call_suite_fn!(self, AEGP_DeleteKeyframe, stream.as_ptr(), key_index)
}
/// Creates and populates an [`StreamValue`] for the stream's value at the time of the keyframe.
pub fn new_keyframe_value(&self, stream: impl AsPtr<AEGP_StreamRefH>, plugin_id: PluginId, key_index: i32) -> Result<StreamValue, Error> {
let stream_suite = aegp::suites::Stream::new()?;
let type_ = stream_suite.stream_type(stream.as_ptr())?;
let mut sys_stream_value2 = call_suite_fn_single!(self, AEGP_GetNewKeyframeValue -> AEGP_StreamValue2, plugin_id, stream.as_ptr(), key_index)?;
let ret = StreamValue::from_sys(type_, sys_stream_value2.val);
stream_suite.dispose_stream_value(&mut sys_stream_value2)?;
Ok(ret)
}
/// Sets the stream's value at the time of the keyframe.
pub fn set_keyframe_value(&self, stream: impl AsPtr<AEGP_StreamRefH>, key_index: i32, value: StreamValue) -> Result<(), Error> {
let sys_stream_value2 = AEGP_StreamValue2 {
streamH: stream.as_ptr(),
val: value.to_sys()
};
call_suite_fn!(self, AEGP_SetKeyframeValue, stream.as_ptr(), key_index, &sys_stream_value2)
}
/// Retrieves the dimensionality of the stream's value.
pub fn stream_value_dimensionality(&self, stream: impl AsPtr<AEGP_StreamRefH>) -> Result<i16, Error> {
Ok(call_suite_fn_single!(self, AEGP_GetStreamValueDimensionality -> A_short, stream.as_ptr())? as i16)
}
/// Retrieves the temporal dimensionality of the stream.
pub fn stream_temporal_dimensionality(&self, stream: impl AsPtr<AEGP_StreamRefH>) -> Result<i16, Error> {
Ok(call_suite_fn_single!(self, AEGP_GetStreamTemporalDimensionality -> A_short, stream.as_ptr())? as i16)
}
/// Returns the [`StreamValue`]s representing the stream's tangential values at the time of the keyframe.
///
/// Returns a tuple containing the in and out tangents.
pub fn new_keyframe_spatial_tangents(&self, stream: impl AsPtr<AEGP_StreamRefH>, plugin_id: PluginId, key_index: i32) -> Result<(StreamValue, StreamValue), Error> {
let stream_suite = aegp::suites::Stream::new()?;
let type_ = stream_suite.stream_type(stream.as_ptr())?;
let (mut sys_in_tan, mut sys_out_tan) =
call_suite_fn_double!(self, AEGP_GetNewKeyframeSpatialTangents -> AEGP_StreamValue2, AEGP_StreamValue2, plugin_id, stream.as_ptr(), key_index)?;
let in_tan = StreamValue::from_sys(type_, sys_in_tan.val);
let out_tan = StreamValue::from_sys(type_, sys_out_tan.val);
stream_suite.dispose_stream_value(&mut sys_in_tan)?;
stream_suite.dispose_stream_value(&mut sys_out_tan)?;
Ok((in_tan, out_tan))
}
/// Specifies the tangential [`StreamValue`]s to be used for the stream's value at the time of the keyframe.
pub fn set_keyframe_spatial_tangents(&self, stream: impl AsPtr<AEGP_StreamRefH>, key_index: i32, in_tan: StreamValue, out_tan: StreamValue) -> Result<(), Error> {
let sys_in_tan = AEGP_StreamValue2 {
streamH: stream.as_ptr(),
val: in_tan.to_sys()
};
let sys_out_tan = AEGP_StreamValue2 {
streamH: stream.as_ptr(),
val: out_tan.to_sys()
};
call_suite_fn!(self, AEGP_SetKeyframeSpatialTangents, stream.as_ptr(), key_index, &sys_in_tan, &sys_out_tan)
}
/// Retrieves the [`AEGP_KeyframeEase`](after_effects_sys::AEGP_KeyframeEase)s associated with the specified dimension of the stream's value at the time of the keyframe.
pub fn keyframe_temporal_ease(&self, stream: impl AsPtr<AEGP_StreamRefH>, key_index: i32, dimension: i32) -> Result<(AEGP_KeyframeEase, AEGP_KeyframeEase), Error> {
call_suite_fn_double!(self, AEGP_GetKeyframeTemporalEase -> ae_sys::AEGP_KeyframeEase, ae_sys::AEGP_KeyframeEase, stream.as_ptr(), key_index, dimension)
}
/// Specifies the [`AEGP_KeyframeEase`](after_effects_sys::AEGP_KeyframeEase)s to be used for the stream's value at the time of the keyframe.
pub fn set_keyframe_temporal_ease(&self, stream: impl AsPtr<AEGP_StreamRefH>, key_index: i32, dimension: i32, in_ease: &AEGP_KeyframeEase, out_ease: &AEGP_KeyframeEase) -> Result<(), Error> {
call_suite_fn!(self, AEGP_SetKeyframeTemporalEase, stream.as_ptr(), key_index, dimension, in_ease, out_ease)
}
/// Retrieves the flags currently set for the keyframe.
pub fn keyframe_flags(&self, stream: impl AsPtr<AEGP_StreamRefH>, key_index: i32) -> Result<KeyframeFlags, Error> {
Ok(KeyframeFlags::from_bits_truncate(
call_suite_fn_single!(self, AEGP_GetKeyframeFlags -> ae_sys::AEGP_KeyframeFlags, stream.as_ptr(), key_index)?
))
}
/// Sets the specified flag for the keyframe. Flags must be set individually.
pub fn set_keyframe_flag(&self, stream: impl AsPtr<AEGP_StreamRefH>, key_index: i32, flag: KeyframeFlags, value: bool) -> Result<(), Error> {
call_suite_fn!(self, AEGP_SetKeyframeFlag, stream.as_ptr(), key_index, flag.bits(), value.into())
}
/// Retrieves the in and out [`KeyframeInterpolation`]s for the specified keyframe.
pub fn keyframe_interpolation(&self, stream: impl AsPtr<AEGP_StreamRefH>, key_index: i32) -> Result<(KeyframeInterpolation, KeyframeInterpolation), Error> {
let (in_interp, out_interp) =
call_suite_fn_double!(self,
AEGP_GetKeyframeInterpolation -> ae_sys::AEGP_KeyframeInterpolationType, ae_sys::AEGP_KeyframeInterpolationType,
stream.as_ptr(),
key_index
)?;
Ok((in_interp.into(), out_interp.into()))
}
/// Specifies the in and out [`KeyframeInterpolation`]s to be used for the given keyframe.
pub fn set_keyframe_interpolation(&self, stream: impl AsPtr<AEGP_StreamRefH>, key_index: i32, in_interp: KeyframeInterpolation, out_interp: KeyframeInterpolation) -> Result<(), Error> {
call_suite_fn!(self, AEGP_SetKeyframeInterpolation, stream.as_ptr(), key_index, in_interp.into(), out_interp.into())
}
/// Informs After Effects that you're going to be adding several keyframes to the specified stream.
///
/// Returns an [`AddKeyframesInfoHandle`], which you can use to add keyframes.
pub fn start_add_keyframes(&self, stream: impl AsPtr<AEGP_StreamRefH>) -> Result<AddKeyframesInfoHandle, Error> {
Ok(AddKeyframesInfoHandle {
suite: self.clone(),
handle: call_suite_fn_single!(self, AEGP_StartAddKeyframes -> ae_sys::AEGP_AddKeyframesInfoH, stream.as_ptr())?,
add: true
})
}
/// Retrieves the label color index for the specified keyframe.
pub fn keyframe_label_color_index(&self, stream: impl AsPtr<AEGP_StreamRefH>, key_index: i32) -> Result<i32, Error> {
Ok(call_suite_fn_single!(self, AEGP_GetKeyframeLabelColorIndex -> A_long, stream.as_ptr(), key_index)? as i32)
}
/// Specifies the label color index to be used for the specified keyframe.
pub fn set_keyframe_label_color_index(&self, stream: impl AsPtr<AEGP_StreamRefH>, key_index: i32, key_label: i32) -> Result<(), Error> {
call_suite_fn!(self, AEGP_SetKeyframeLabelColorIndex, stream.as_ptr(), key_index, key_label)
}
}
// ――――――――――――――――――――――――――――――――――――――― Types ――――――――――――――――――――――――――――――――――――――――
bitflags::bitflags! {
pub struct KeyframeInterpolationMask: ae_sys::A_long {
const NONE = ae_sys::AEGP_KeyInterpMask_NONE as ae_sys::A_long;
const LINEAR = ae_sys::AEGP_KeyInterpMask_LINEAR as ae_sys::A_long;
const BEZIER = ae_sys::AEGP_KeyInterpMask_BEZIER as ae_sys::A_long;
const HOLD = ae_sys::AEGP_KeyInterpMask_HOLD as ae_sys::A_long;
const CUSTOM = ae_sys::AEGP_KeyInterpMask_CUSTOM as ae_sys::A_long;
const ANY = ae_sys::AEGP_KeyInterpMask_ANY as ae_sys::A_long;
}
}
bitflags::bitflags! {
pub struct KeyframeFlags: ae_sys::A_long {
const NONE = ae_sys::AEGP_KeyframeFlag_NONE as ae_sys::A_long;
const TEMPORAL_CONTINUOUS = ae_sys::AEGP_KeyframeFlag_TEMPORAL_CONTINUOUS as ae_sys::A_long;
const TEMPORAL_AUTOBEZIER = ae_sys::AEGP_KeyframeFlag_TEMPORAL_AUTOBEZIER as ae_sys::A_long;
const SPATIAL_CONTINUOUS = ae_sys::AEGP_KeyframeFlag_SPATIAL_CONTINUOUS as ae_sys::A_long;
const SPATIAL_AUTOBEZIER = ae_sys::AEGP_KeyframeFlag_SPATIAL_AUTOBEZIER as ae_sys::A_long;
const ROVING = ae_sys::AEGP_KeyframeFlag_ROVING as ae_sys::A_long;
}
}
define_enum! {
ae_sys::AEGP_KeyframeInterpolationType,
KeyframeInterpolation {
None = ae_sys::AEGP_KeyInterp_NONE,
Linear = ae_sys::AEGP_KeyInterp_LINEAR,
Bezier = ae_sys::AEGP_KeyInterp_BEZIER,
Hold = ae_sys::AEGP_KeyInterp_HOLD,
}
}
/// Temporary struct to hold the state of adding keyframe batches, returned from [`KeyframeSuite::start_add_keyframes()`].
///
/// Keyframes will be commited when this struct goes out of scope.
pub struct AddKeyframesInfoHandle {
handle: ae_sys::AEGP_AddKeyframesInfoH,
suite: KeyframeSuite,
add: bool,
}
impl AddKeyframesInfoHandle {
/// Adds a keyframe to the specified stream at the specified (layer or composition) time.
///
/// Note: this doesn't actually do anything to the stream's value.
pub fn add_keyframes(&mut self, time_mode: TimeMode, time: Time) -> Result<i32, Error> {
Ok(call_suite_fn_single!(self.suite, AEGP_AddKeyframes -> A_long, self.handle, time_mode.into(), &time.into() as *const _)? as i32)
}
/// Sets the value of the specified keyframe.
pub fn set_add_keyframe(&mut self, key_index: i32, stream: impl AsPtr<AEGP_StreamRefH>, value: StreamValue) -> Result<(), Error> {
let sys_stream_value2 = AEGP_StreamValue2 {
streamH: stream.as_ptr(),
val: value.to_sys()
};
call_suite_fn!(self.suite, AEGP_SetAddKeyframe, self.handle, key_index, &sys_stream_value2)
}
/// Sets the `add` flag, used in a call to `AEGP_EndAddKeyframes`. Defaults to true
pub fn set_add(&mut self, add: bool) {
self.add = add;
}
}
impl Drop for AddKeyframesInfoHandle {
fn drop(&mut self) {
let _ = call_suite_fn!(self.suite, AEGP_EndAddKeyframes, self.add as _, self.handle);
}
}
define_suite_item_wrapper!(
ae_sys::AEGP_StreamRefH, StreamReferenceHandle,
suite: KeyframeSuite,
/// Keyframes make After Effects what it is. AEGPs (and...ssshh, don't tell anyone...effects) can use this suite to add, manipulate and remove keyframes from any keyframe-able stream.
///
/// # Adding Multiple Keyframes
/// Each time you call [`insert`](Self::insert), the entire stream is added to the undo stack.
///
/// If you're adding one or two keyframes, this isn't a problem. However, if you're writing a keyframer, you'll want to do things the *right* way.
///
/// Before you begin adding keyframes, call the (very-appropriately-named) [`start_add_keyframes`](Self::start_add_keyframes).
///
/// For each keyframe to add, call [`AddKeyframesInfoHandle::add_keyframes`] to set the time to be used (and get the newly-added keyframe's index), then [`AddKeyframesInfoHandle::set_add_keyframe`] to specify the value to be used.
///
/// Once you're finished, simply drop the [`AddKeyframesInfoHandle`] to let know After Effects know it's time to add the changed parameter stream to the undo stack.
Keyframes {
dispose: ;
/// Retrieves the number of keyframes on the given stream.
///
/// Returns `-1` if the stream is not keyframe-able.
///
/// Also, note that a stream without keyframes isn't necessarily constant; it can be altered by expressions.
num_keyframes() -> i32 => suite.stream_num_kfs,
/// Retrieves the time of the specified keyframe.
time(key_index: i32, time_mode: TimeMode) -> Time => suite.keyframe_time,
/// Adds a keyframe to the specified stream (at the specified composition or layer time).
///
/// Returns the new keyframe's index.
///
/// All indexes greater than the new index are now invalid (but you knew that).
///
/// If there is already a keyframe at that time, the values will be updated.
insert(time_mode: TimeMode, time: Time) -> i32 => suite.insert_keyframe,
/// Deletes the specified keyframe.
delete(key_index: i32) -> () => suite.delete_keyframe,
/// Creates and populates an [`StreamValue`] for the stream's value at the time of the keyframe.
new_value(plugin_id: PluginId, key_index: i32) -> StreamValue => suite.new_keyframe_value,
/// Sets the stream's value at the time of the keyframe.
set_value(key_index: i32, value: StreamValue) -> () => suite.set_keyframe_value,
/// Retrieves the dimensionality of the stream's value.
stream_value_dimensionality() -> i16 => suite.stream_value_dimensionality,
/// Retrieves the temporal dimensionality of the stream.
stream_temporal_dimensionality() -> i16 => suite.stream_temporal_dimensionality,
/// Returns the [`StreamValue`]s representing the stream's tangential values at the time of the keyframe.
///
/// Returns a tuple containing the in and out tangents.
new_spatial_tangents(plugin_id: PluginId, key_index: i32) -> (StreamValue, StreamValue) => suite.new_keyframe_spatial_tangents,
/// Specifies the tangential [`StreamValue`]s to be used for the stream's value at the time of the keyframe.
set_spatial_tangents(key_index: i32, in_tan: StreamValue, out_tan: StreamValue) -> () => suite.set_keyframe_spatial_tangents,
/// Retrieves the [`AEGP_KeyframeEase`](after_effects_sys::AEGP_KeyframeEase)s associated with the specified dimension of the stream's value at the time of the keyframe.
temporal_ease(key_index: i32, dimension: i32) -> (AEGP_KeyframeEase, AEGP_KeyframeEase) => suite.keyframe_temporal_ease,
/// Specifies the [`AEGP_KeyframeEase`](after_effects_sys::AEGP_KeyframeEase)s to be used for the stream's value at the time of the keyframe.
set_temporal_ease(key_index: i32, dimension: i32, in_ease: &AEGP_KeyframeEase, out_ease: &AEGP_KeyframeEase) -> () => suite.set_keyframe_temporal_ease,
/// Retrieves the flags currently set for the keyframe.
flags(key_index: i32) -> KeyframeFlags => suite.keyframe_flags,
/// Sets the specified flag for the keyframe. Flags must be set individually.
set_flag(key_index: i32, flag: KeyframeFlags, value: bool) -> () => suite.set_keyframe_flag,
/// Retrieves the in and out [`KeyframeInterpolation`]s for the specified keyframe.
interpolation(key_index: i32) -> (KeyframeInterpolation, KeyframeInterpolation) => suite.keyframe_interpolation,
/// Specifies the in and out [`KeyframeInterpolation`]s to be used for the given keyframe.
set_interpolation(key_index: i32, in_interp: KeyframeInterpolation, out_interp: KeyframeInterpolation) -> () => suite.set_keyframe_interpolation,
/// Informs After Effects that you're going to be adding several keyframes to the specified stream.
///
/// Returns an [`AddKeyframesInfoHandle`], which you can use to add keyframes.
start_add_keyframes() -> AddKeyframesInfoHandle => suite.start_add_keyframes,
/// Retrieves the label color index for the specified keyframe.
label_color_index(key_index: i32) -> i32 => suite.keyframe_label_color_index,
/// Specifies the label color index to be used for the specified keyframe.
set_label_color_index(key_index: i32, key_label: i32) -> () => suite.set_keyframe_label_color_index,
}
);