Add a lot of update tagging to operations with NLA tracks and strips.
[blender.git] / source / blender / makesrna / intern / rna_nla.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * Contributor(s): Blender Foundation (2009), Joshua Leung
19  *
20  * ***** END GPL LICENSE BLOCK *****
21  */
22
23 /** \file blender/makesrna/intern/rna_nla.c
24  *  \ingroup RNA
25  */
26
27 #include <stdlib.h>
28
29 #include "DNA_anim_types.h"
30 #include "DNA_action_types.h"
31 #include "DNA_scene_types.h"
32
33 #include "BLI_utildefines.h"
34
35 #include "MEM_guardedalloc.h"
36
37 #include "RNA_access.h"
38 #include "RNA_define.h"
39 #include "RNA_enum_types.h"
40
41 #include "rna_internal.h"
42
43 #include "WM_api.h"
44 #include "WM_types.h"
45
46 #ifdef RNA_RUNTIME
47
48 #include <stdio.h>
49 #include <math.h>
50
51 /* needed for some of the validation stuff... */
52 #include "BKE_animsys.h"
53 #include "BKE_fcurve.h"
54 #include "BKE_nla.h"
55
56 #include "DNA_object_types.h"
57
58 #include "ED_anim_api.h"
59
60 #include "DEG_depsgraph_build.h"
61 #include "DEG_depsgraph.h"
62
63 /* temp constant defined for these funcs only... */
64 #define NLASTRIP_MIN_LEN_THRESH     0.1f
65
66 static void rna_NlaStrip_name_set(PointerRNA *ptr, const char *value)
67 {
68         NlaStrip *data = (NlaStrip *)ptr->data;
69
70         /* copy the name first */
71         BLI_strncpy_utf8(data->name, value, sizeof(data->name));
72
73         /* validate if there's enough info to do so */
74         if (ptr->id.data) {
75                 AnimData *adt = BKE_animdata_from_id(ptr->id.data);
76                 BKE_nlastrip_validate_name(adt, data);
77         }
78 }
79
80 static char *rna_NlaStrip_path(PointerRNA *ptr)
81 {
82         NlaStrip *strip = (NlaStrip *)ptr->data;
83         AnimData *adt = BKE_animdata_from_id(ptr->id.data);
84
85         /* if we're attached to AnimData, try to resolve path back to AnimData */
86         if (adt) {
87                 NlaTrack *nlt;
88                 NlaStrip *nls;
89
90                 for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
91                         for (nls = nlt->strips.first; nls; nls = nls->next) {
92                                 if (nls == strip) {
93                                         /* XXX but if we animate like this, the control will never work... */
94                                         char name_esc_nlt[sizeof(nlt->name) * 2];
95                                         char name_esc_strip[sizeof(strip->name) * 2];
96
97                                         BLI_strescape(name_esc_nlt, nlt->name, sizeof(name_esc_nlt));
98                                         BLI_strescape(name_esc_strip, strip->name, sizeof(name_esc_strip));
99                                         return BLI_sprintfN("animation_data.nla_tracks[\"%s\"].strips[\"%s\"]",
100                                                             name_esc_nlt, name_esc_strip);
101                                 }
102                         }
103                 }
104         }
105
106         /* no path */
107         return BLI_strdup("");
108 }
109
110 static void rna_NlaStrip_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
111 {
112         ID *id = ptr->id.data;
113
114         ANIM_id_update(bmain, id);
115 }
116
117 static void rna_NlaStrip_dependency_update(Main *bmain, Scene *scene, PointerRNA *ptr)
118 {
119         DEG_relations_tag_update(bmain);
120
121         rna_NlaStrip_update(bmain, scene, ptr);
122 }
123
124 static void rna_NlaStrip_transform_update(Main *bmain, Scene *scene, PointerRNA *ptr)
125 {
126         NlaStrip *strip = (NlaStrip *)ptr->data;
127
128         BKE_nlameta_flush_transforms(strip);
129
130         /* set the flag */
131         if ((strip->flag & NLASTRIP_FLAG_AUTO_BLENDS) && ptr->id.data) {
132                 /* validate state to ensure that auto-blend gets applied immediately */
133                 IdAdtTemplate *iat = (IdAdtTemplate *)ptr->id.data;
134
135                 if (iat->adt) {
136                         BKE_nla_validate_state(iat->adt);
137                 }
138         }
139
140         rna_NlaStrip_update(bmain, scene, ptr);
141 }
142
143 static void rna_NlaStrip_start_frame_set(PointerRNA *ptr, float value)
144 {
145         NlaStrip *data = (NlaStrip *)ptr->data;
146
147         /* clamp value to lie within valid limits
148          *      - cannot start past the end of the strip + some flexibility threshold
149          *      - cannot start before the previous strip (if present) ends
150          *              -> but if it was a transition, we could go up to the start of the strip + some flexibility threshold
151          *              as long as we re-adjust the transition afterwards
152          *      - minimum frame is -MAXFRAME so that we don't get clipping on frame 0
153          */
154         if (data->prev) {
155                 if (data->prev->type == NLASTRIP_TYPE_TRANSITION) {
156                         CLAMP(value, data->prev->start + NLASTRIP_MIN_LEN_THRESH, data->end - NLASTRIP_MIN_LEN_THRESH);
157
158                         /* re-adjust the transition to stick to the endpoints of the action-clips */
159                         data->prev->end = value;
160                 }
161                 else {
162                         CLAMP(value, data->prev->end, data->end - NLASTRIP_MIN_LEN_THRESH);
163                 }
164         }
165         else {
166                 CLAMP(value, MINAFRAME, data->end);
167         }
168         data->start = value;
169 }
170
171 static void rna_NlaStrip_end_frame_set(PointerRNA *ptr, float value)
172 {
173         NlaStrip *data = (NlaStrip *)ptr->data;
174
175         /* clamp value to lie within valid limits
176          *      - must not have zero or negative length strip, so cannot start before the first frame
177          *        + some minimum-strip-length threshold
178          *      - cannot end later than the start of the next strip (if present)
179          *              -> but if it was a transition, we could go up to the start of the end - some flexibility threshold
180          *              as long as we re-adjust the transition afterwards
181          */
182         if (data->next) {
183                 if (data->next->type == NLASTRIP_TYPE_TRANSITION) {
184                         CLAMP(value, data->start + NLASTRIP_MIN_LEN_THRESH, data->next->end - NLASTRIP_MIN_LEN_THRESH);
185
186                         /* readjust the transition to stick to the endpoints of the action-clips */
187                         data->next->start = value;
188                 }
189                 else {
190                         CLAMP(value, data->start + NLASTRIP_MIN_LEN_THRESH, data->next->start);
191                 }
192         }
193         else {
194                 CLAMP(value, data->start + NLASTRIP_MIN_LEN_THRESH, MAXFRAME);
195         }
196         data->end = value;
197
198
199         /* calculate the lengths the strip and its action (if applicable) */
200         if (data->type == NLASTRIP_TYPE_CLIP) {
201                 float len, actlen;
202
203                 len = data->end - data->start;
204                 actlen = data->actend - data->actstart;
205                 if (IS_EQF(actlen, 0.0f)) actlen = 1.0f;
206
207                 /* now, adjust the 'scale' setting to reflect this (so that this change can be valid) */
208                 data->scale = len / ((actlen) * data->repeat);
209         }
210 }
211
212 static void rna_NlaStrip_scale_set(PointerRNA *ptr, float value)
213 {
214         NlaStrip *data = (NlaStrip *)ptr->data;
215
216         /* set scale value */
217         /* NOTE: these need to be synced with the values in the property definition in rna_def_nlastrip() */
218         CLAMP(value, 0.0001f, 1000.0f);
219         data->scale = value;
220
221         /* adjust the strip extents in response to this */
222         BKE_nlastrip_recalculate_bounds(data);
223 }
224
225 static void rna_NlaStrip_repeat_set(PointerRNA *ptr, float value)
226 {
227         NlaStrip *data = (NlaStrip *)ptr->data;
228
229         /* set repeat value */
230         /* NOTE: these need to be synced with the values in the property definition in rna_def_nlastrip() */
231         CLAMP(value, 0.01f, 1000.0f);
232         data->repeat = value;
233
234         /* adjust the strip extents in response to this */
235         BKE_nlastrip_recalculate_bounds(data);
236 }
237
238 static void rna_NlaStrip_blend_in_set(PointerRNA *ptr, float value)
239 {
240         NlaStrip *data = (NlaStrip *)ptr->data;
241         float len;
242
243         /* blend-in is limited to the length of the strip, and also cannot overlap with blendout */
244         len = (data->end - data->start) - data->blendout;
245         CLAMP(value, 0, len);
246
247         data->blendin = value;
248 }
249
250 static void rna_NlaStrip_blend_out_set(PointerRNA *ptr, float value)
251 {
252         NlaStrip *data = (NlaStrip *)ptr->data;
253         float len;
254
255         /* blend-out is limited to the length of the strip */
256         len = (data->end - data->start);
257         CLAMP(value, 0, len);
258
259         /* it also cannot overlap with blendin */
260         if ((len - value) < data->blendin)
261                 value = len - data->blendin;
262
263         data->blendout = value;
264 }
265
266 static void rna_NlaStrip_use_auto_blend_set(PointerRNA *ptr, bool value)
267 {
268         NlaStrip *data = (NlaStrip *)ptr->data;
269
270         if (value) {
271                 /* set the flag */
272                 data->flag |= NLASTRIP_FLAG_AUTO_BLENDS;
273
274                 /* validate state to ensure that auto-blend gets applied immediately */
275                 if (ptr->id.data) {
276                         IdAdtTemplate *iat = (IdAdtTemplate *)ptr->id.data;
277
278                         if (iat->adt) {
279                                 BKE_nla_validate_state(iat->adt);
280                         }
281                 }
282         }
283         else {
284                 /* clear the flag */
285                 data->flag &= ~NLASTRIP_FLAG_AUTO_BLENDS;
286
287                 /* clear the values too, so that it's clear that there has been an effect */
288                 /* TODO: it's somewhat debatable whether it's better to leave these in instead... */
289                 data->blendin  = 0.0f;
290                 data->blendout = 0.0f;
291         }
292 }
293
294 static int rna_NlaStrip_action_editable(PointerRNA *ptr, const char **UNUSED(r_info))
295 {
296         NlaStrip *strip = (NlaStrip *)ptr->data;
297
298         /* strip actions shouldn't be editable if NLA tweakmode is on */
299         if (ptr->id.data) {
300                 AnimData *adt = BKE_animdata_from_id(ptr->id.data);
301
302                 if (adt) {
303                         /* active action is only editable when it is not a tweaking strip */
304                         if ((adt->flag & ADT_NLA_EDIT_ON) || (adt->actstrip) || (adt->tmpact))
305                                 return 0;
306                 }
307         }
308
309         /* check for clues that strip probably shouldn't be used... */
310         if (strip->flag & NLASTRIP_FLAG_TWEAKUSER)
311                 return 0;
312
313         /* should be ok, though we may still miss some cases */
314         return PROP_EDITABLE;
315 }
316
317 static void rna_NlaStrip_action_start_frame_set(PointerRNA *ptr, float value)
318 {
319         NlaStrip *data = (NlaStrip *)ptr->data;
320
321         /* prevent start frame from occurring after end of action */
322         CLAMP(value, MINAFRAME, data->actend);
323         data->actstart = value;
324
325         /* adjust the strip extents in response to this */
326         /* TODO: should the strip be moved backwards instead as a special case? */
327         BKE_nlastrip_recalculate_bounds(data);
328 }
329
330 static void rna_NlaStrip_action_end_frame_set(PointerRNA *ptr, float value)
331 {
332         NlaStrip *data = (NlaStrip *)ptr->data;
333
334         /* prevent end frame from starting before start of action */
335         CLAMP(value, data->actstart, MAXFRAME);
336         data->actend = value;
337
338         /* adjust the strip extents in response to this */
339         BKE_nlastrip_recalculate_bounds(data);
340 }
341
342 static void rna_NlaStrip_animated_influence_set(PointerRNA *ptr, bool value)
343 {
344         NlaStrip *data = (NlaStrip *)ptr->data;
345
346         if (value) {
347                 /* set the flag, then make sure a curve for this exists */
348                 data->flag |= NLASTRIP_FLAG_USR_INFLUENCE;
349                 BKE_nlastrip_validate_fcurves(data);
350         }
351         else
352                 data->flag &= ~NLASTRIP_FLAG_USR_INFLUENCE;
353 }
354
355 static void rna_NlaStrip_animated_time_set(PointerRNA *ptr, bool value)
356 {
357         NlaStrip *data = (NlaStrip *)ptr->data;
358
359         if (value) {
360                 /* set the flag, then make sure a curve for this exists */
361                 data->flag |= NLASTRIP_FLAG_USR_TIME;
362                 BKE_nlastrip_validate_fcurves(data);
363         }
364         else
365                 data->flag &= ~NLASTRIP_FLAG_USR_TIME;
366 }
367
368 static FCurve *rna_NlaStrip_fcurve_find(NlaStrip *strip, ReportList *reports, const char *data_path, int index)
369 {
370         if (data_path[0] == '\0') {
371                 BKE_report(reports, RPT_ERROR, "F-Curve data path empty, invalid argument");
372                 return NULL;
373         }
374
375         /* Returns NULL if not found. */
376         return list_find_fcurve(&strip->fcurves, data_path, index);
377 }
378
379
380 static NlaStrip *rna_NlaStrip_new(ID *id, NlaTrack *track, Main *bmain, bContext *C, ReportList *reports, const char *UNUSED(name),
381                                   int start, bAction *action)
382 {
383         NlaStrip *strip = BKE_nlastrip_new(action);
384
385         if (strip == NULL) {
386                 BKE_report(reports, RPT_ERROR, "Unable to create new strip");
387                 return NULL;
388         }
389
390         strip->end += (start - strip->start);
391         strip->start = start;
392
393         if (BKE_nlastrips_add_strip(&track->strips, strip) == 0) {
394                 BKE_report(reports, RPT_ERROR,
395                            "Unable to add strip (the track does not have any space to accommodate this new strip)");
396                 BKE_nlastrip_free(NULL, strip, true);
397                 return NULL;
398         }
399
400         /* create dummy AnimData block so that BKE_nlastrip_validate_name()
401          * can be used to ensure a valid name, as we don't have one here...
402          *  - only the nla_tracks list is needed there, which we aim to reverse engineer here...
403          */
404         {
405                 AnimData adt = {NULL};
406                 NlaTrack *nlt, *nlt_p;
407
408                 /* 'first' NLA track is found by going back up chain of given track's parents until we fall off */
409                 nlt_p = track; nlt = track;
410                 while ((nlt = nlt->prev) != NULL)
411                         nlt_p = nlt;
412                 adt.nla_tracks.first = nlt_p;
413
414                 /* do the same thing to find the last track */
415                 nlt_p = track; nlt = track;
416                 while ((nlt = nlt->next) != NULL)
417                         nlt_p = nlt;
418                 adt.nla_tracks.last = nlt_p;
419
420                 /* now we can just auto-name as usual */
421                 BKE_nlastrip_validate_name(&adt, strip);
422         }
423
424         WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_ADDED, NULL);
425
426         DEG_relations_tag_update(bmain);
427         DEG_id_tag_update_ex(bmain, id, DEG_TAG_TIME | DEG_TAG_COPY_ON_WRITE);
428
429         return strip;
430 }
431
432 static void rna_NlaStrip_remove(ID *id, NlaTrack *track, Main *bmain, bContext *C, ReportList *reports, PointerRNA *strip_ptr)
433 {
434         NlaStrip *strip = strip_ptr->data;
435         if (BLI_findindex(&track->strips, strip) == -1) {
436                 BKE_reportf(reports, RPT_ERROR, "NLA strip '%s' not found in track '%s'", strip->name, track->name);
437                 return;
438         }
439
440         BKE_nlastrip_free(&track->strips, strip, true);
441         RNA_POINTER_INVALIDATE(strip_ptr);
442
443         WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_REMOVED, NULL);
444
445         DEG_relations_tag_update(bmain);
446         DEG_id_tag_update_ex(bmain, id, DEG_TAG_TIME | DEG_TAG_COPY_ON_WRITE);
447 }
448
449 /* Set the 'solo' setting for the given NLA-track, making sure that it is the only one
450  * that has this status in its AnimData block.
451  */
452 static void rna_NlaTrack_solo_set(PointerRNA *ptr, bool value)
453 {
454         NlaTrack *data = (NlaTrack *)ptr->data;
455         AnimData *adt = BKE_animdata_from_id(ptr->id.data);
456         NlaTrack *nt;
457
458         if (data == NULL) {
459                 return;
460         }
461
462         /* firstly, make sure 'solo' flag for all tracks is disabled */
463         for (nt = data; nt; nt = nt->next) {
464                 nt->flag &= ~NLATRACK_SOLO;
465         }
466         for (nt = data; nt; nt = nt->prev) {
467                 nt->flag &= ~NLATRACK_SOLO;
468         }
469
470         /* now, enable 'solo' for the given track if appropriate */
471         if (value) {
472                 /* set solo status */
473                 data->flag |= NLATRACK_SOLO;
474
475                 /* set solo-status on AnimData */
476                 adt->flag |= ADT_NLA_SOLO_TRACK;
477         }
478         else {
479                 /* solo status was already cleared on track */
480
481                 /* clear solo-status on AnimData */
482                 adt->flag &= ~ADT_NLA_SOLO_TRACK;
483         }
484 }
485
486 #else
487
488 /* enum defines exported for rna_animation.c */
489 const EnumPropertyItem rna_enum_nla_mode_blend_items[] = {
490         {NLASTRIP_MODE_REPLACE, "REPLACE", 0, "Replace",
491                                 "Result strip replaces the accumulated results by amount specified by influence"},
492         {NLASTRIP_MODE_ADD, "ADD", 0, "Add", "Weighted result of strip is added to the accumulated results"},
493         {NLASTRIP_MODE_SUBTRACT, "SUBTRACT", 0, "Subtract",
494                                  "Weighted result of strip is removed from the accumulated results"},
495         {NLASTRIP_MODE_MULTIPLY, "MULTIPLY", 0, "Multiply",
496                                  "Weighted result of strip is multiplied with the accumulated results"},
497         {0, NULL, 0, NULL, NULL}
498 };
499
500 const EnumPropertyItem rna_enum_nla_mode_extend_items[] = {
501         {NLASTRIP_EXTEND_NOTHING, "NOTHING", 0, "Nothing", "Strip has no influence past its extents"},
502         {NLASTRIP_EXTEND_HOLD, "HOLD", 0, "Hold",
503                                "Hold the first frame if no previous strips in track, and always hold last frame"},
504         {NLASTRIP_EXTEND_HOLD_FORWARD, "HOLD_FORWARD", 0, "Hold Forward", "Only hold last frame"},
505         {0, NULL, 0, NULL, NULL}
506 };
507
508 static void rna_def_strip_fcurves(BlenderRNA *brna, PropertyRNA *cprop)
509 {
510         StructRNA *srna;
511
512         FunctionRNA *func;
513         PropertyRNA *parm;
514
515         RNA_def_property_srna(cprop, "NlaStripFCurves");
516         srna = RNA_def_struct(brna, "NlaStripFCurves", NULL);
517         RNA_def_struct_sdna(srna, "NlaStrip");
518         RNA_def_struct_ui_text(srna, "NLA-Strip F-Curves", "Collection of NLA strip F-Curves");
519
520         /* Strip.fcurves.find(...) */
521         func = RNA_def_function(srna, "find", "rna_NlaStrip_fcurve_find");
522         RNA_def_function_ui_description(func, "Find an F-Curve. Note that this function performs a linear scan "
523                                         "of all F-Curves in the NLA strip.");
524         RNA_def_function_flag(func, FUNC_USE_REPORTS);
525         parm = RNA_def_string(func, "data_path", NULL, 0, "Data Path", "F-Curve data path");
526         RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
527         RNA_def_int(func, "index", 0, 0, INT_MAX, "Index", "Array index", 0, INT_MAX);
528
529         parm = RNA_def_pointer(func, "fcurve", "FCurve", "", "The found F-Curve, or None if it doesn't exist");
530         RNA_def_function_return(func, parm);
531 }
532
533 static void rna_def_nlastrip(BlenderRNA *brna)
534 {
535         StructRNA *srna;
536         PropertyRNA *prop;
537
538         /* enum defs */
539         static const EnumPropertyItem prop_type_items[] = {
540                 {NLASTRIP_TYPE_CLIP, "CLIP", 0, "Action Clip", "NLA Strip references some Action"},
541                 {NLASTRIP_TYPE_TRANSITION, "TRANSITION", 0, "Transition", "NLA Strip 'transitions' between adjacent strips"},
542                 {NLASTRIP_TYPE_META, "META", 0, "Meta", "NLA Strip acts as a container for adjacent strips"},
543                 {NLASTRIP_TYPE_SOUND, "SOUND", 0, "Sound Clip", "NLA Strip representing a sound event for speakers"},
544                 {0, NULL, 0, NULL, NULL}
545         };
546
547         /* struct definition */
548         srna = RNA_def_struct(brna, "NlaStrip", NULL);
549         RNA_def_struct_ui_text(srna, "NLA Strip", "A container referencing an existing Action");
550         RNA_def_struct_path_func(srna, "rna_NlaStrip_path");
551         RNA_def_struct_ui_icon(srna, ICON_NLA); /* XXX */
552
553         /* name property */
554         prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
555         RNA_def_property_ui_text(prop, "Name", "");
556         RNA_def_property_string_funcs(prop, NULL, NULL, "rna_NlaStrip_name_set");
557         RNA_def_struct_name_property(srna, prop);
558         RNA_def_property_update(prop, NC_ANIMATION | ND_NLA, NULL); /* this will do? */
559
560         /* Enums */
561         prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
562         RNA_def_property_enum_sdna(prop, NULL, "type");
563         RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* XXX for now, not editable, since this is dangerous */
564         RNA_def_property_enum_items(prop, prop_type_items);
565         RNA_def_property_ui_text(prop, "Type", "Type of NLA Strip");
566         RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, "rna_NlaStrip_update");
567
568         prop = RNA_def_property(srna, "extrapolation", PROP_ENUM, PROP_NONE);
569         RNA_def_property_enum_sdna(prop, NULL, "extendmode");
570         RNA_def_property_enum_items(prop, rna_enum_nla_mode_extend_items);
571         RNA_def_property_ui_text(prop, "Extrapolation", "Action to take for gaps past the strip extents");
572         RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, "rna_NlaStrip_update");
573
574         prop = RNA_def_property(srna, "blend_type", PROP_ENUM, PROP_NONE);
575         RNA_def_property_enum_sdna(prop, NULL, "blendmode");
576         RNA_def_property_enum_items(prop, rna_enum_nla_mode_blend_items);
577         RNA_def_property_ui_text(prop, "Blending", "Method used for combining strip's result with accumulated result");
578         RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, "rna_NlaStrip_update");
579
580         /* Strip extents */
581         prop = RNA_def_property(srna, "frame_start", PROP_FLOAT, PROP_TIME);
582         RNA_def_property_float_sdna(prop, NULL, "start");
583         RNA_def_property_float_funcs(prop, NULL, "rna_NlaStrip_start_frame_set", NULL);
584         RNA_def_property_ui_text(prop, "Start Frame", "");
585         RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, "rna_NlaStrip_transform_update");
586
587         prop = RNA_def_property(srna, "frame_end", PROP_FLOAT, PROP_TIME);
588         RNA_def_property_float_sdna(prop, NULL, "end");
589         RNA_def_property_float_funcs(prop, NULL, "rna_NlaStrip_end_frame_set", NULL);
590         RNA_def_property_ui_text(prop, "End Frame", "");
591         RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, "rna_NlaStrip_transform_update");
592
593         /* Blending */
594         prop = RNA_def_property(srna, "blend_in", PROP_FLOAT, PROP_NONE);
595         RNA_def_property_float_sdna(prop, NULL, "blendin");
596         RNA_def_property_float_funcs(prop, NULL, "rna_NlaStrip_blend_in_set", NULL);
597         RNA_def_property_ui_text(prop, "Blend In", "Number of frames at start of strip to fade in influence");
598         RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, "rna_NlaStrip_update");
599
600         prop = RNA_def_property(srna, "blend_out", PROP_FLOAT, PROP_NONE);
601         RNA_def_property_float_sdna(prop, NULL, "blendout");
602         RNA_def_property_float_funcs(prop, NULL, "rna_NlaStrip_blend_out_set", NULL);
603         RNA_def_property_ui_text(prop, "Blend Out", "");
604         RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, "rna_NlaStrip_update");
605
606         prop = RNA_def_property(srna, "use_auto_blend", PROP_BOOLEAN, PROP_NONE);
607         RNA_def_property_boolean_sdna(prop, NULL, "flag", NLASTRIP_FLAG_AUTO_BLENDS);
608         RNA_def_property_boolean_funcs(prop, NULL, "rna_NlaStrip_use_auto_blend_set");
609         RNA_def_property_ui_text(prop, "Auto Blend In/Out",
610                                  "Number of frames for Blending In/Out is automatically determined from "
611                                  "overlapping strips");
612         RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, "rna_NlaStrip_update");
613
614         /* Action */
615         prop = RNA_def_property(srna, "action", PROP_POINTER, PROP_NONE);
616         RNA_def_property_pointer_sdna(prop, NULL, "act");
617         RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_Action_id_poll");
618         RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT);
619         RNA_def_property_editable_func(prop, "rna_NlaStrip_action_editable");
620         RNA_def_property_ui_text(prop, "Action", "Action referenced by this strip");
621         RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, "rna_NlaStrip_dependency_update");
622
623         /* Action extents */
624         prop = RNA_def_property(srna, "action_frame_start", PROP_FLOAT, PROP_TIME);
625         RNA_def_property_float_sdna(prop, NULL, "actstart");
626         RNA_def_property_float_funcs(prop, NULL, "rna_NlaStrip_action_start_frame_set", NULL);
627         RNA_def_property_ui_text(prop, "Action Start Frame", "First frame from action to use");
628         RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, "rna_NlaStrip_transform_update");
629
630         prop = RNA_def_property(srna, "action_frame_end", PROP_FLOAT, PROP_TIME);
631         RNA_def_property_float_sdna(prop, NULL, "actend");
632         RNA_def_property_float_funcs(prop, NULL, "rna_NlaStrip_action_end_frame_set", NULL);
633         RNA_def_property_ui_text(prop, "Action End Frame", "Last frame from action to use");
634         RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, "rna_NlaStrip_transform_update");
635
636         /* Action Reuse */
637         prop = RNA_def_property(srna, "repeat", PROP_FLOAT, PROP_NONE);
638         RNA_def_property_float_sdna(prop, NULL, "repeat");
639         RNA_def_property_float_funcs(prop, NULL, "rna_NlaStrip_repeat_set", NULL);
640         /* these limits have currently be chosen arbitrarily, but could be extended
641          * (minimum should still be > 0 though) if needed... */
642         RNA_def_property_range(prop, 0.1f, 1000.0f);
643         RNA_def_property_ui_text(prop, "Repeat", "Number of times to repeat the action range");
644         RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, "rna_NlaStrip_transform_update");
645
646         prop = RNA_def_property(srna, "scale", PROP_FLOAT, PROP_NONE);
647         RNA_def_property_float_sdna(prop, NULL, "scale");
648         RNA_def_property_float_funcs(prop, NULL, "rna_NlaStrip_scale_set", NULL);
649         /* these limits can be extended, but beyond this, we can get some crazy+annoying bugs
650          * due to numeric errors */
651         RNA_def_property_range(prop, 0.0001f, 1000.0f);
652         RNA_def_property_ui_text(prop, "Scale", "Scaling factor for action");
653         RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, "rna_NlaStrip_transform_update");
654
655         /* Strip's F-Curves */
656         prop = RNA_def_property(srna, "fcurves", PROP_COLLECTION, PROP_NONE);
657         RNA_def_property_collection_sdna(prop, NULL, "fcurves", NULL);
658         RNA_def_property_struct_type(prop, "FCurve");
659         RNA_def_property_ui_text(prop, "F-Curves", "F-Curves for controlling the strip's influence and timing");
660         rna_def_strip_fcurves(brna, prop);
661
662         /* Strip's F-Modifiers */
663         prop = RNA_def_property(srna, "modifiers", PROP_COLLECTION, PROP_NONE);
664         RNA_def_property_struct_type(prop, "FModifier");
665         RNA_def_property_ui_text(prop, "Modifiers", "Modifiers affecting all the F-Curves in the referenced Action");
666
667         /* Strip's Sub-Strips (for Meta-Strips) */
668         prop = RNA_def_property(srna, "strips", PROP_COLLECTION, PROP_NONE);
669         RNA_def_property_struct_type(prop, "NlaStrip");
670         RNA_def_property_ui_text(prop, "NLA Strips",
671                                  "NLA Strips that this strip acts as a container for (if it is of type Meta)");
672
673         /* Settings - Values necessary for evaluation */
674         prop = RNA_def_property(srna, "influence", PROP_FLOAT, PROP_FACTOR);
675         RNA_def_property_range(prop, 0.0f, 1.0f);
676         RNA_def_property_ui_text(prop, "Influence", "Amount the strip contributes to the current result");
677         /* XXX: Update temporarily disabled so that the property can be edited at all!
678          * Even autokey only applies after the curves have been re-evaluated, causing the unkeyed values to be lost
679          */
680         RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, /*"rna_NlaStrip_update"*/ NULL);
681
682         prop = RNA_def_property(srna, "strip_time", PROP_FLOAT, PROP_TIME);
683         RNA_def_property_ui_text(prop, "Strip Time", "Frame of referenced Action to evaluate");
684         /* XXX: Update temporarily disabled so that the property can be edited at all!
685          * Even autokey only applies after the curves have been re-evaluated, causing the unkeyed values to be lost
686          */
687         RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, /*"rna_NlaStrip_update"*/ NULL);
688
689         /* TODO: should the animated_influence/time settings be animatable themselves? */
690         prop = RNA_def_property(srna, "use_animated_influence", PROP_BOOLEAN, PROP_NONE);
691         RNA_def_property_boolean_sdna(prop, NULL, "flag", NLASTRIP_FLAG_USR_INFLUENCE);
692         RNA_def_property_boolean_funcs(prop, NULL, "rna_NlaStrip_animated_influence_set");
693         RNA_def_property_ui_text(prop, "Animated Influence",
694                                  "Influence setting is controlled by an F-Curve rather than automatically determined");
695         RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, "rna_NlaStrip_update");
696
697         prop = RNA_def_property(srna, "use_animated_time", PROP_BOOLEAN, PROP_NONE);
698         RNA_def_property_boolean_sdna(prop, NULL, "flag", NLASTRIP_FLAG_USR_TIME);
699         RNA_def_property_boolean_funcs(prop, NULL, "rna_NlaStrip_animated_time_set");
700         RNA_def_property_ui_text(prop, "Animated Strip Time",
701                                  "Strip time is controlled by an F-Curve rather than automatically determined");
702         RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, "rna_NlaStrip_update");
703
704         prop = RNA_def_property(srna, "use_animated_time_cyclic", PROP_BOOLEAN, PROP_NONE);
705         RNA_def_property_boolean_sdna(prop, NULL, "flag", NLASTRIP_FLAG_USR_TIME_CYCLIC);
706         RNA_def_property_ui_text(prop, "Cyclic Strip Time", "Cycle the animated time within the action start & end");
707         RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, "rna_NlaStrip_transform_update");
708
709         /* settings */
710         prop = RNA_def_property(srna, "active", PROP_BOOLEAN, PROP_NONE);
711         /* can be made editable by hooking it up to the necessary NLA API methods */
712         RNA_def_property_clear_flag(prop, PROP_EDITABLE);
713         RNA_def_property_boolean_sdna(prop, NULL, "flag", NLASTRIP_FLAG_ACTIVE);
714         RNA_def_property_ui_text(prop, "Active", "NLA Strip is active");
715         RNA_def_property_update(prop, NC_ANIMATION | ND_NLA, NULL); /* this will do? */
716
717         prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE);
718         RNA_def_property_boolean_sdna(prop, NULL, "flag", NLASTRIP_FLAG_SELECT);
719         RNA_def_property_ui_text(prop, "Select", "NLA Strip is selected");
720         RNA_def_property_update(prop, NC_ANIMATION | ND_NLA, NULL); /* this will do? */
721
722         prop = RNA_def_property(srna, "mute", PROP_BOOLEAN, PROP_NONE);
723         RNA_def_property_boolean_sdna(prop, NULL, "flag", NLASTRIP_FLAG_MUTED);
724         RNA_def_property_ui_text(prop, "Muted", "NLA Strip is not evaluated");
725         RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, "rna_NlaStrip_update");
726
727         prop = RNA_def_property(srna, "use_reverse", PROP_BOOLEAN, PROP_NONE);
728         RNA_def_property_boolean_sdna(prop, NULL, "flag", NLASTRIP_FLAG_REVERSE);
729         RNA_def_property_ui_text(prop, "Reversed",
730                                  "NLA Strip is played back in reverse order (only when timing is "
731                                  "automatically determined)");
732         RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, "rna_NlaStrip_update");
733
734         prop = RNA_def_property(srna, "use_sync_length", PROP_BOOLEAN, PROP_NONE);
735         RNA_def_property_boolean_sdna(prop, NULL, "flag", NLASTRIP_FLAG_SYNC_LENGTH);
736         RNA_def_property_ui_text(prop, "Sync Action Length",
737                                  "Update range of frames referenced from action "
738                                  "after tweaking strip and its keyframes");
739         RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, "rna_NlaStrip_update");
740 }
741
742 static void rna_api_nlatrack_strips(BlenderRNA *brna, PropertyRNA *cprop)
743 {
744         StructRNA *srna;
745         PropertyRNA *parm;
746         FunctionRNA *func;
747
748         RNA_def_property_srna(cprop, "NlaStrips");
749         srna = RNA_def_struct(brna, "NlaStrips", NULL);
750         RNA_def_struct_sdna(srna, "NlaTrack");
751         RNA_def_struct_ui_text(srna, "Nla Strips", "Collection of Nla Strips");
752
753         func = RNA_def_function(srna, "new", "rna_NlaStrip_new");
754         RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_CONTEXT | FUNC_USE_REPORTS);
755         RNA_def_function_ui_description(func, "Add a new Action-Clip strip to the track");
756         parm = RNA_def_string(func, "name", "NlaStrip", 0, "", "Name for the NLA Strips");
757         RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
758         parm = RNA_def_int(func, "start", 0, INT_MIN, INT_MAX, "Start Frame",
759                            "Start frame for this strip", INT_MIN, INT_MAX);
760         RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
761         parm = RNA_def_pointer(func, "action", "Action", "", "Action to assign to this strip");
762         RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
763         /* return type */
764         parm = RNA_def_pointer(func, "strip", "NlaStrip", "", "New NLA Strip");
765         RNA_def_function_return(func, parm);
766
767         func = RNA_def_function(srna, "remove", "rna_NlaStrip_remove");
768         RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_CONTEXT | FUNC_USE_REPORTS);
769         RNA_def_function_ui_description(func, "Remove a NLA Strip");
770         parm = RNA_def_pointer(func, "strip", "NlaStrip", "", "NLA Strip to remove");
771         RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
772         RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
773 }
774
775 static void rna_def_nlatrack(BlenderRNA *brna)
776 {
777         StructRNA *srna;
778         PropertyRNA *prop;
779
780         srna = RNA_def_struct(brna, "NlaTrack", NULL);
781         RNA_def_struct_ui_text(srna, "NLA Track", "A animation layer containing Actions referenced as NLA strips");
782         RNA_def_struct_ui_icon(srna, ICON_NLA);
783
784         /* strips collection */
785         prop = RNA_def_property(srna, "strips", PROP_COLLECTION, PROP_NONE);
786         RNA_def_property_struct_type(prop, "NlaStrip");
787         RNA_def_property_ui_text(prop, "NLA Strips", "NLA Strips on this NLA-track");
788
789         rna_api_nlatrack_strips(brna, prop);
790
791         /* name property */
792         prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
793         RNA_def_property_ui_text(prop, "Name", "");
794         RNA_def_struct_name_property(srna, prop);
795         RNA_def_property_update(prop, NC_ANIMATION | ND_NLA, NULL); /* this will do? */
796
797         /* settings */
798         prop = RNA_def_property(srna, "active", PROP_BOOLEAN, PROP_NONE);
799         /* can be made editable by hooking it up to the necessary NLA API methods */
800         RNA_def_property_clear_flag(prop, PROP_EDITABLE);
801         RNA_def_property_boolean_sdna(prop, NULL, "flag", NLATRACK_ACTIVE);
802         RNA_def_property_ui_text(prop, "Active", "NLA Track is active");
803         RNA_def_property_update(prop, NC_ANIMATION | ND_NLA, NULL); /* this will do? */
804
805         prop = RNA_def_property(srna, "is_solo", PROP_BOOLEAN, PROP_NONE);
806         /* can be made editable by hooking it up to the necessary NLA API methods */
807         RNA_def_property_boolean_sdna(prop, NULL, "flag", NLATRACK_SOLO);
808         RNA_def_property_ui_text(prop, "Solo",
809                                  "NLA Track is evaluated itself (i.e. active Action and all other NLA Tracks in the "
810                                  "same AnimData block are disabled)");
811         RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, "rna_NlaStrip_update");
812         RNA_def_property_boolean_funcs(prop, NULL, "rna_NlaTrack_solo_set");
813
814         prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE);
815         RNA_def_property_boolean_sdna(prop, NULL, "flag", NLATRACK_SELECTED);
816         RNA_def_property_ui_text(prop, "Select", "NLA Track is selected");
817         RNA_def_property_update(prop, NC_ANIMATION | ND_NLA, NULL); /* this will do? */
818
819         prop = RNA_def_property(srna, "mute", PROP_BOOLEAN, PROP_NONE);
820         RNA_def_property_boolean_sdna(prop, NULL, "flag", NLATRACK_MUTED);
821         RNA_def_property_ui_text(prop, "Muted", "NLA Track is not evaluated");
822         RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, "rna_NlaStrip_update");
823
824         prop = RNA_def_property(srna, "lock", PROP_BOOLEAN, PROP_NONE);
825         RNA_def_property_boolean_sdna(prop, NULL, "flag", NLATRACK_PROTECTED);
826         RNA_def_property_ui_text(prop, "Locked", "NLA Track is locked");
827         RNA_def_property_update(prop, NC_ANIMATION | ND_NLA, NULL); /* this will do? */
828 }
829
830 /* --------- */
831
832 void RNA_def_nla(BlenderRNA *brna)
833 {
834         rna_def_nlatrack(brna);
835         rna_def_nlastrip(brna);
836 }
837
838
839 #endif