* merge r22734 from trunk
[blender.git] / source / blender / makesrna / intern / rna_nla.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * Contributor(s): Blender Foundation (2009), Joshua Leung
21  *
22  * ***** END GPL LICENSE BLOCK *****
23  */
24
25 #include <stdlib.h>
26
27 #include "RNA_define.h"
28 #include "RNA_types.h"
29
30 #include "rna_internal.h"
31
32 #include "DNA_anim_types.h"
33 #include "DNA_action_types.h"
34 #include "DNA_scene_types.h"
35
36 #include "MEM_guardedalloc.h"
37
38 #ifdef RNA_RUNTIME
39
40 #include <stdio.h>
41 #include <math.h>
42
43 /* needed for some of the validation stuff... */
44 #include "BKE_animsys.h"
45 #include "BKE_nla.h"
46
47 /* temp constant defined for these funcs only... */
48 #define NLASTRIP_MIN_LEN_THRESH         0.1f
49
50 void rna_NlaStrip_name_set(PointerRNA *ptr, const char *value)
51 {
52         NlaStrip *data= (NlaStrip *)ptr->data;
53         
54         /* copy the name first */
55         BLI_strncpy(data->name, value, sizeof(data->name));
56         
57         /* validate if there's enough info to do so */
58         if (ptr->id.data) {
59                 AnimData *adt= BKE_animdata_from_id(ptr->id.data);
60                 BKE_nlastrip_validate_name(adt, data);
61         }
62 }
63
64
65 static void rna_NlaStrip_start_frame_set(PointerRNA *ptr, float value)
66 {
67         NlaStrip *data= (NlaStrip*)ptr->data;
68         
69         /* clamp value to lie within valid limits 
70          *      - cannot start past the end of the strip + some flexibility threshold
71          *      - cannot start before the previous strip (if present) ends
72          *              -> but if it was a transition, we could go up to the start of the strip + some flexibility threshold
73          *              as long as we re-adjust the transition afterwards
74          *      - minimum frame is -MAXFRAME so that we don't get clipping on frame 0
75          */
76         if (data->prev) {
77                 if (data->prev->type == NLASTRIP_TYPE_TRANSITION) {
78                         CLAMP(value, data->prev->start+NLASTRIP_MIN_LEN_THRESH, data->end-NLASTRIP_MIN_LEN_THRESH);
79                         
80                         /* readjust the transition to stick to the endpoints of the action-clips */
81                         data->prev->end= value;
82                 }
83                 else {
84                         CLAMP(value, data->prev->end, data->end-NLASTRIP_MIN_LEN_THRESH);
85                 }
86         }
87         else {
88                 CLAMP(value, MINAFRAME, data->end);
89         }
90         data->start= value;
91 }
92
93 static void rna_NlaStrip_end_frame_set(PointerRNA *ptr, float value)
94 {
95         NlaStrip *data= (NlaStrip*)ptr->data;
96         
97         /* clamp value to lie within valid limits
98          *      - must not have zero or negative length strip, so cannot start before the first frame 
99          *        + some minimum-strip-length threshold
100          *      - cannot end later than the start of the next strip (if present)
101          *              -> but if it was a transition, we could go up to the start of the end - some flexibility threshold
102          *              as long as we re-adjust the transition afterwards
103          */
104         if (data->next) {
105                 if (data->next->type == NLASTRIP_TYPE_TRANSITION) {
106                         CLAMP(value, data->start+NLASTRIP_MIN_LEN_THRESH, data->next->end-NLASTRIP_MIN_LEN_THRESH);
107                         
108                         /* readjust the transition to stick to the endpoints of the action-clips */
109                         data->next->start= value;
110                 }
111                 else {
112                         CLAMP(value, data->start+NLASTRIP_MIN_LEN_THRESH, data->next->start);
113                 }
114         }
115         else {
116                 CLAMP(value, data->start+NLASTRIP_MIN_LEN_THRESH, MAXFRAME);
117         }
118         data->end= value;
119         
120         
121         /* calculate the lengths the strip and its action (if applicable) */
122         if (data->type == NLASTRIP_TYPE_CLIP) {
123                 float len, actlen;
124                 
125                 len= data->end - data->start;
126                 actlen= data->actend - data->actstart;
127                 if (IS_EQ(actlen, 0.0f)) actlen= 1.0f;
128                 
129                 /* now, adjust the 'scale' setting to reflect this (so that this change can be valid) */
130                 data->scale= len / ((actlen) * data->repeat);
131         }
132 }
133
134 static void rna_NlaStrip_scale_set(PointerRNA *ptr, float value)
135 {
136         NlaStrip *data= (NlaStrip*)ptr->data;
137         float actlen, mapping;
138         
139         /* set scale value */
140         CLAMP(value, 0.0001f, 1000.0f); /* NOTE: these need to be synced with the values in the property definition in rna_def_nlastrip() */
141         data->scale= value;
142         
143         /* calculate existing factors */
144         actlen= data->actend - data->actstart;
145         if (IS_EQ(actlen, 0.0f)) actlen= 1.0f;
146         mapping= data->scale * data->repeat;
147         
148         /* adjust endpoint of strip in response to this */
149         if (IS_EQ(mapping, 0.0f) == 0)
150                 data->end = (actlen * mapping) + data->start; 
151         else
152                 printf("NlaStrip Set Scale Error (in RNA): Scale = %0.4f, Repeat = %0.4f \n", data->scale, data->repeat);
153 }
154
155 static void rna_NlaStrip_repeat_set(PointerRNA *ptr, float value)
156 {
157         NlaStrip *data= (NlaStrip*)ptr->data;
158         float actlen, mapping;
159         
160         /* set scale value */
161         CLAMP(value, 0.01f, 1000.0f); /* NOTE: these need to be synced with the values in the property definition in rna_def_nlastrip() */
162         data->repeat= value;
163         
164         /* calculate existing factors */
165         actlen= data->actend - data->actstart;
166         if (IS_EQ(actlen, 0.0f)) actlen= 1.0f;
167         mapping= data->scale * data->repeat;
168         
169         /* adjust endpoint of strip in response to this */
170         if (IS_EQ(mapping, 0.0f) == 0)
171                 data->end = (actlen * mapping) + data->start; 
172         else
173                 printf("NlaStrip Set Repeat Error (in RNA): Scale = %0.4f, Repeat = %0.4f \n", data->scale, data->repeat);
174 }
175
176 static void rna_NlaStrip_blend_in_set(PointerRNA *ptr, float value)
177 {
178         NlaStrip *data= (NlaStrip*)ptr->data;
179         float len;
180         
181         /* blend-in is limited to the length of the strip, and also cannot overlap with blendout */
182         len= (data->end - data->start) - data->blendout;
183         CLAMP(value, 0, len);
184         
185         data->blendin= value;
186 }
187
188 static void rna_NlaStrip_blend_out_set(PointerRNA *ptr, float value)
189 {
190         NlaStrip *data= (NlaStrip*)ptr->data;
191         float len;
192         
193         /* blend-out is limited to the length of the strip */
194         len= (data->end - data->start);
195         CLAMP(value, 0, len);
196         
197         /* it also cannot overlap with blendin */
198         if ((len - value) < data->blendin)
199                 value= len - data->blendin;
200         
201         data->blendout= value;
202 }
203
204 static void rna_NlaStrip_action_start_frame_set(PointerRNA *ptr, float value)
205 {
206         NlaStrip *data= (NlaStrip*)ptr->data;
207         CLAMP(value, MINAFRAME, data->actend);
208         data->actstart= value;
209 }
210
211 static void rna_NlaStrip_action_end_frame_set(PointerRNA *ptr, float value)
212 {
213         NlaStrip *data= (NlaStrip*)ptr->data;
214         CLAMP(value, data->actstart, MAXFRAME);
215         data->actend= value;
216 }
217
218 static void rna_NlaStrip_animated_influence_set(PointerRNA *ptr, int value)
219 {
220         NlaStrip *data= (NlaStrip*)ptr->data;
221         
222         if (value) {
223                 /* set the flag, then make sure a curve for this exists */
224                 data->flag |= NLASTRIP_FLAG_USR_INFLUENCE;
225                 BKE_nlastrip_validate_fcurves(data);
226         }
227         else
228                 data->flag &= ~NLASTRIP_FLAG_USR_INFLUENCE;
229 }
230
231 static void rna_NlaStrip_animated_time_set(PointerRNA *ptr, int value)
232 {
233         NlaStrip *data= (NlaStrip*)ptr->data;
234         
235         if (value) {
236                 /* set the flag, then make sure a curve for this exists */
237                 data->flag |= NLASTRIP_FLAG_USR_TIME;
238                 BKE_nlastrip_validate_fcurves(data);
239         }
240         else
241                 data->flag &= ~NLASTRIP_FLAG_USR_TIME;
242 }
243
244 #else
245
246 /* enum defines exported for rna_animation.c */
247 EnumPropertyItem nla_mode_blend_items[] = {
248         {NLASTRIP_MODE_REPLACE, "REPLACE", 0, "Replace", "Result strip replaces the accumulated results by amount specified by influence."},
249         {NLASTRIP_MODE_ADD, "ADD", 0, "Add", "Weighted result of strip is added to the accumlated results."},
250         {NLASTRIP_MODE_SUBTRACT, "SUBTRACT", 0, "Subtract", "Weighted result of strip is removed from the accumlated results."},
251         {NLASTRIP_MODE_MULTIPLY, "MULITPLY", 0, "Multiply", "Weighted result of strip is multiplied with the accumlated results."},
252         {0, NULL, 0, NULL, NULL}};
253 EnumPropertyItem nla_mode_extend_items[] = {
254         {NLASTRIP_EXTEND_NOTHING, "NOTHING", 0, "Nothing", "Strip has no influence past its extents."},
255         {NLASTRIP_EXTEND_HOLD, "HOLD", 0, "Hold", "Hold the first frame if no previous strips in track, and always hold last frame."},
256         {NLASTRIP_EXTEND_HOLD_FORWARD, "HOLD_FORWARD", 0, "Hold Forward", "Only hold last frame."},
257         {0, NULL, 0, NULL, NULL}};
258
259 void rna_def_nlastrip(BlenderRNA *brna)
260 {
261         StructRNA *srna;
262         PropertyRNA *prop;
263         
264                 /* enum defs */
265         static EnumPropertyItem prop_type_items[] = {
266                 {NLASTRIP_TYPE_CLIP, "CLIP", 0, "Action Clip", "NLA Strip references some Action."},
267                 {NLASTRIP_TYPE_TRANSITION, "TRANSITION", 0, "Transition", "NLA Strip 'transitions' between adjacent strips."},
268                 {NLASTRIP_TYPE_META, "META", 0, "Meta", "NLA Strip acts as a container for adjacent strips."},
269                 {0, NULL, 0, NULL, NULL}};
270         
271         /* struct definition */
272         srna= RNA_def_struct(brna, "NlaStrip", NULL);
273         RNA_def_struct_ui_text(srna, "NLA Strip", "A container referencing an existing Action.");
274         RNA_def_struct_ui_icon(srna, ICON_NLA); // XXX
275         
276         /* name property */
277         prop= RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
278         RNA_def_property_ui_text(prop, "Name", "");
279         RNA_def_property_string_funcs(prop, NULL, NULL, "rna_NlaStrip_name_set");
280         RNA_def_struct_name_property(srna, prop);
281         
282         /* Enums */
283         prop= RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
284         RNA_def_property_enum_sdna(prop, NULL, "type");
285         RNA_def_property_clear_flag(prop, PROP_EDITABLE); // XXX for now, not editable, since this is dangerous
286         RNA_def_property_enum_items(prop, prop_type_items);
287         RNA_def_property_ui_text(prop, "Type", "Type of NLA Strip.");
288         
289         prop= RNA_def_property(srna, "extrapolation", PROP_ENUM, PROP_NONE);
290         RNA_def_property_enum_sdna(prop, NULL, "extendmode");
291         RNA_def_property_enum_items(prop, nla_mode_extend_items);
292         RNA_def_property_ui_text(prop, "Extrapolation", "Action to take for gaps past the strip extents.");
293         
294         prop= RNA_def_property(srna, "blending", PROP_ENUM, PROP_NONE);
295         RNA_def_property_enum_sdna(prop, NULL, "blendmode");
296         RNA_def_property_enum_items(prop, nla_mode_blend_items);
297         RNA_def_property_ui_text(prop, "Blending", "Method used for combining strip's result with accumulated result.");
298         
299         /* Strip extents */
300         prop= RNA_def_property(srna, "start_frame", PROP_FLOAT, PROP_TIME);
301         RNA_def_property_float_sdna(prop, NULL, "start");
302         RNA_def_property_float_funcs(prop, NULL, "rna_NlaStrip_start_frame_set", NULL);
303         RNA_def_property_ui_text(prop, "Start Frame", "");
304         
305         prop= RNA_def_property(srna, "end_frame", PROP_FLOAT, PROP_TIME);
306         RNA_def_property_float_sdna(prop, NULL, "end");
307         RNA_def_property_float_funcs(prop, NULL, "rna_NlaStrip_end_frame_set", NULL);
308         RNA_def_property_ui_text(prop, "End Frame", "");
309         
310         /* Blending */
311         prop= RNA_def_property(srna, "blend_in", PROP_FLOAT, PROP_NONE);
312         RNA_def_property_float_sdna(prop, NULL, "blendin");
313         RNA_def_property_float_funcs(prop, NULL, "rna_NlaStrip_blend_in_set", NULL);
314         RNA_def_property_ui_text(prop, "Blend In", "Number of frames at start of strip to fade in influence.");
315         
316         prop= RNA_def_property(srna, "blend_out", PROP_FLOAT, PROP_NONE);
317         RNA_def_property_float_sdna(prop, NULL, "blendout");
318         RNA_def_property_float_funcs(prop, NULL, "rna_NlaStrip_blend_out_set", NULL);
319         RNA_def_property_ui_text(prop, "Blend Out", "");
320         
321         prop= RNA_def_property(srna, "auto_blending", PROP_BOOLEAN, PROP_NONE);
322         RNA_def_property_boolean_sdna(prop, NULL, "flag", NLASTRIP_FLAG_AUTO_BLENDS);
323         RNA_def_property_ui_text(prop, "Auto Blend In/Out", "Number of frames for Blending In/Out is automatically determined from overlapping strips.");
324         
325         /* Action */
326         prop= RNA_def_property(srna, "action", PROP_POINTER, PROP_NONE);
327         RNA_def_property_pointer_sdna(prop, NULL, "act");
328         RNA_def_property_ui_text(prop, "Action", "Action referenced by this strip.");
329         
330         /* Action extents */
331         prop= RNA_def_property(srna, "action_start_frame", PROP_FLOAT, PROP_TIME);
332         RNA_def_property_float_sdna(prop, NULL, "actstart");
333         RNA_def_property_float_funcs(prop, NULL, "rna_NlaStrip_action_start_frame_set", NULL);
334         RNA_def_property_ui_text(prop, "Action Start Frame", "");
335         
336         prop= RNA_def_property(srna, "action_end_frame", PROP_FLOAT, PROP_TIME);
337         RNA_def_property_float_sdna(prop, NULL, "actend");
338         RNA_def_property_float_funcs(prop, NULL, "rna_NlaStrip_action_end_frame_set", NULL);
339         RNA_def_property_ui_text(prop, "Action End Frame", "");
340         
341         /* Action Reuse */
342         prop= RNA_def_property(srna, "repeat", PROP_FLOAT, PROP_NONE);
343         RNA_def_property_float_sdna(prop, NULL, "repeat"); 
344         RNA_def_property_float_funcs(prop, NULL, "rna_NlaStrip_repeat_set", NULL);
345         RNA_def_property_range(prop, 0.1f, 1000.0f); /* these limits have currently be chosen arbitarily, but could be extended (minimum should still be > 0 though) if needed... */
346         RNA_def_property_ui_text(prop, "Repeat", "Number of times to repeat the action range.");
347         
348         prop= RNA_def_property(srna, "scale", PROP_FLOAT, PROP_NONE);
349         RNA_def_property_float_sdna(prop, NULL, "scale"); 
350         RNA_def_property_float_funcs(prop, NULL, "rna_NlaStrip_scale_set", NULL);
351         RNA_def_property_range(prop, 0.0001f, 1000.0f); /* these limits can be extended, but beyond this, we can get some crazy+annoying bugs due to numeric errors */
352         RNA_def_property_ui_text(prop, "Scale", "Scaling factor for action.");
353         
354         /* Strip's F-Curves */
355         prop= RNA_def_property(srna, "fcurves", PROP_COLLECTION, PROP_NONE);
356         RNA_def_property_struct_type(prop, "FCurve");
357         RNA_def_property_ui_text(prop, "F-Curves", "F-Curves for controlling the strip's influence and timing.");
358         
359         /* Strip's F-Modifiers */
360         prop= RNA_def_property(srna, "modifiers", PROP_COLLECTION, PROP_NONE);
361         RNA_def_property_struct_type(prop, "FModifier");
362         RNA_def_property_ui_text(prop, "Modifiers", "Modifiers affecting all the F-Curves in the referenced Action.");
363         
364         /* Strip's Sub-Strips (for Meta-Strips) */
365         prop= RNA_def_property(srna, "strips", PROP_COLLECTION, PROP_NONE);
366         RNA_def_property_struct_type(prop, "NlaStrip");
367         RNA_def_property_ui_text(prop, "NLA Strips", "NLA Strips that this strip acts as a container for (if it is of type Meta).");
368         
369         /* Settings - Values necessary for evaluation */
370         prop= RNA_def_property(srna, "influence", PROP_FLOAT, PROP_NONE);
371         RNA_def_property_range(prop, 0.0f, 1.0f);
372         RNA_def_property_ui_text(prop, "Influence", "Amount the strip contributes to the current result.");
373         
374         prop= RNA_def_property(srna, "strip_time", PROP_FLOAT, PROP_TIME);
375         RNA_def_property_ui_text(prop, "Strip Time", "Frame of referenced Action to evaluate.");
376         
377                 // TODO: should the animated_influence/time settings be animatable themselves?
378         prop= RNA_def_property(srna, "animated_influence", PROP_BOOLEAN, PROP_NONE);
379         RNA_def_property_boolean_sdna(prop, NULL, "flag", NLASTRIP_FLAG_USR_INFLUENCE);
380         RNA_def_property_boolean_funcs(prop, NULL, "rna_NlaStrip_animated_influence_set");
381         RNA_def_property_ui_text(prop, "Animated Influence", "Influence setting is controlled by an F-Curve rather than automatically determined.");
382         
383         prop= RNA_def_property(srna, "animated_time", PROP_BOOLEAN, PROP_NONE);
384         RNA_def_property_boolean_sdna(prop, NULL, "flag", NLASTRIP_FLAG_USR_TIME);
385         RNA_def_property_boolean_funcs(prop, NULL, "rna_NlaStrip_animated_time_set");
386         RNA_def_property_ui_text(prop, "Animated Strip Time", "Strip time is controlled by an F-Curve rather than automatically determined.");
387         
388         /* settings */
389         prop= RNA_def_property(srna, "active", PROP_BOOLEAN, PROP_NONE);
390         RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* can be made editable by hooking it up to the necessary NLA API methods */
391         RNA_def_property_boolean_sdna(prop, NULL, "flag", NLASTRIP_FLAG_ACTIVE);
392         RNA_def_property_ui_text(prop, "Active", "NLA Strip is active.");
393         
394         prop= RNA_def_property(srna, "selected", PROP_BOOLEAN, PROP_NONE);
395         RNA_def_property_boolean_sdna(prop, NULL, "flag", NLASTRIP_FLAG_SELECT);
396         RNA_def_property_ui_text(prop, "Selected", "NLA Strip is selected.");
397         
398         prop= RNA_def_property(srna, "muted", PROP_BOOLEAN, PROP_NONE);
399         RNA_def_property_boolean_sdna(prop, NULL, "flag", NLASTRIP_FLAG_MUTED);
400         RNA_def_property_ui_text(prop, "Muted", "NLA Strip is not evaluated.");
401         
402         prop= RNA_def_property(srna, "reversed", PROP_BOOLEAN, PROP_NONE);
403         RNA_def_property_boolean_sdna(prop, NULL, "flag", NLASTRIP_FLAG_REVERSE);
404         RNA_def_property_ui_text(prop, "Reversed", "NLA Strip is played back in reverse order (only when timing is automatically determined).");
405         
406         // TODO: 
407         // - sync length
408 }
409
410 void rna_def_nlatrack(BlenderRNA *brna)
411 {
412         StructRNA *srna;
413         PropertyRNA *prop;
414         
415         srna= RNA_def_struct(brna, "NlaTrack", NULL);
416         RNA_def_struct_ui_text(srna, "NLA Track", "A animation layer containing Actions referenced as NLA strips.");
417         RNA_def_struct_ui_icon(srna, ICON_NLA);
418         
419         /* strips collection */
420         prop= RNA_def_property(srna, "strips", PROP_COLLECTION, PROP_NONE);
421         RNA_def_property_struct_type(prop, "NlaStrip");
422         RNA_def_property_ui_text(prop, "NLA Strips", "NLA Strips on this NLA-track.");
423         
424         /* name property */
425         prop= RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
426         RNA_def_property_ui_text(prop, "Name", "");
427         RNA_def_struct_name_property(srna, prop);
428         
429         /* settings */
430         prop= RNA_def_property(srna, "active", PROP_BOOLEAN, PROP_NONE);
431         RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* can be made editable by hooking it up to the necessary NLA API methods */
432         RNA_def_property_boolean_sdna(prop, NULL, "flag", NLATRACK_ACTIVE);
433         RNA_def_property_ui_text(prop, "Active", "NLA Track is active.");
434         
435         prop= RNA_def_property(srna, "solo", PROP_BOOLEAN, PROP_NONE);
436         RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* can be made editable by hooking it up to the necessary NLA API methods */
437         RNA_def_property_boolean_sdna(prop, NULL, "flag", NLATRACK_SOLO);
438         RNA_def_property_ui_text(prop, "Solo", "NLA Track is evaluated itself (i.e. active Action and all other NLA Tracks in the same AnimData block are disabled).");
439         
440         prop= RNA_def_property(srna, "selected", PROP_BOOLEAN, PROP_NONE);
441         RNA_def_property_boolean_sdna(prop, NULL, "flag", NLATRACK_SELECTED);
442         RNA_def_property_ui_text(prop, "Selected", "NLA Track is selected.");
443         
444         prop= RNA_def_property(srna, "muted", PROP_BOOLEAN, PROP_NONE);
445         RNA_def_property_boolean_sdna(prop, NULL, "flag", NLATRACK_MUTED);
446         RNA_def_property_ui_text(prop, "Muted", "NLA Track is not evaluated.");
447
448         prop= RNA_def_property(srna, "locked", PROP_BOOLEAN, PROP_NONE);
449         RNA_def_property_boolean_sdna(prop, NULL, "flag", NLATRACK_PROTECTED);
450         RNA_def_property_ui_text(prop, "Locked", "NLA Track is locked.");
451 }
452
453 /* --------- */
454
455 void RNA_def_nla(BlenderRNA *brna)
456 {
457         rna_def_nlatrack(brna);
458         rna_def_nlastrip(brna);
459 }
460
461
462 #endif