Cleanup: rename the curveInX etc bbone DNA fields to curve_in_x etc.
[blender.git] / source / blender / editors / armature / pose_utils.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2009, Blender Foundation, Joshua Leung
17  * This is a new part of Blender
18  */
19
20 /** \file
21  * \ingroup edarmature
22  */
23
24 #include "MEM_guardedalloc.h"
25
26 #include "BLI_math.h"
27 #include "BLI_blenlib.h"
28
29 #include "DNA_anim_types.h"
30 #include "DNA_armature_types.h"
31 #include "DNA_object_types.h"
32 #include "DNA_scene_types.h"
33
34 #include "BKE_action.h"
35 #include "BKE_armature.h"
36 #include "BKE_idprop.h"
37 #include "BKE_layer.h"
38 #include "BKE_object.h"
39
40 #include "BKE_context.h"
41
42 #include "DEG_depsgraph.h"
43
44 #include "RNA_access.h"
45
46 #include "WM_api.h"
47 #include "WM_types.h"
48
49 #include "ED_armature.h"
50 #include "ED_keyframing.h"
51
52 #include "armature_intern.h"
53
54 /* *********************************************** */
55 /* Contents of this File:
56  *
57  * This file contains methods shared between Pose Slide and Pose Lib;
58  * primarily the functions in question concern Animato <-> Pose
59  * convenience functions, such as applying/getting pose values
60  * and/or inserting keyframes for these.
61  */
62 /* *********************************************** */
63 /* FCurves <-> PoseChannels Links */
64
65 /* helper for poseAnim_mapping_get() -> get the relevant F-Curves per PoseChannel */
66 static void fcurves_to_pchan_links_get(ListBase *pfLinks,
67                                        Object *ob,
68                                        bAction *act,
69                                        bPoseChannel *pchan)
70 {
71   ListBase curves = {NULL, NULL};
72   int transFlags = action_get_item_transforms(act, ob, pchan, &curves);
73
74   pchan->flag &= ~(POSE_LOC | POSE_ROT | POSE_SIZE | POSE_BBONE_SHAPE);
75
76   /* check if any transforms found... */
77   if (transFlags) {
78     /* make new linkage data */
79     tPChanFCurveLink *pfl = MEM_callocN(sizeof(tPChanFCurveLink), "tPChanFCurveLink");
80     PointerRNA ptr;
81
82     pfl->ob = ob;
83     pfl->fcurves = curves;
84     pfl->pchan = pchan;
85
86     /* get the RNA path to this pchan - this needs to be freed! */
87     RNA_pointer_create((ID *)ob, &RNA_PoseBone, pchan, &ptr);
88     pfl->pchan_path = RNA_path_from_ID_to_struct(&ptr);
89
90     /* add linkage data to operator data */
91     BLI_addtail(pfLinks, pfl);
92
93     /* set pchan's transform flags */
94     if (transFlags & ACT_TRANS_LOC) {
95       pchan->flag |= POSE_LOC;
96     }
97     if (transFlags & ACT_TRANS_ROT) {
98       pchan->flag |= POSE_ROT;
99     }
100     if (transFlags & ACT_TRANS_SCALE) {
101       pchan->flag |= POSE_SIZE;
102     }
103     if (transFlags & ACT_TRANS_BBONE) {
104       pchan->flag |= POSE_BBONE_SHAPE;
105     }
106
107     /* store current transforms */
108     copy_v3_v3(pfl->oldloc, pchan->loc);
109     copy_v3_v3(pfl->oldrot, pchan->eul);
110     copy_v3_v3(pfl->oldscale, pchan->size);
111     copy_qt_qt(pfl->oldquat, pchan->quat);
112     copy_v3_v3(pfl->oldaxis, pchan->rotAxis);
113     pfl->oldangle = pchan->rotAngle;
114
115     /* store current bbone values */
116     pfl->roll1 = pchan->roll1;
117     pfl->roll2 = pchan->roll2;
118     pfl->curve_in_x = pchan->curve_in_x;
119     pfl->curve_in_y = pchan->curve_in_y;
120     pfl->curve_out_x = pchan->curve_out_x;
121     pfl->curve_out_y = pchan->curve_out_y;
122     pfl->ease1 = pchan->ease1;
123     pfl->ease2 = pchan->ease2;
124     pfl->scale_in_x = pchan->scale_in_x;
125     pfl->scale_in_y = pchan->scale_in_y;
126     pfl->scale_out_x = pchan->scale_out_x;
127     pfl->scale_out_y = pchan->scale_out_y;
128
129     /* make copy of custom properties */
130     if (pchan->prop && (transFlags & ACT_TRANS_PROP)) {
131       pfl->oldprops = IDP_CopyProperty(pchan->prop);
132     }
133   }
134 }
135
136 /**
137  *  Returns a valid pose armature for this object, else returns NULL.
138  */
139 Object *poseAnim_object_get(Object *ob_)
140 {
141   Object *ob = BKE_object_pose_armature_get(ob_);
142   if (!ELEM(NULL, ob, ob->data, ob->adt, ob->adt->action)) {
143     return ob;
144   }
145   return NULL;
146 }
147
148 /* get sets of F-Curves providing transforms for the bones in the Pose  */
149 void poseAnim_mapping_get(bContext *C, ListBase *pfLinks)
150 {
151   /* for each Pose-Channel which gets affected, get the F-Curves for that channel
152    * and set the relevant transform flags...
153    */
154   Object *prev_ob, *ob_pose_armature;
155
156   prev_ob = NULL;
157   ob_pose_armature = NULL;
158   CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, pchan, selected_pose_bones, Object *, ob) {
159     if (ob != prev_ob) {
160       prev_ob = ob;
161       ob_pose_armature = poseAnim_object_get(ob);
162     }
163
164     if (ob_pose_armature == NULL) {
165       continue;
166     }
167
168     fcurves_to_pchan_links_get(pfLinks, ob_pose_armature, ob_pose_armature->adt->action, pchan);
169   }
170   CTX_DATA_END;
171
172   /* if no PoseChannels were found, try a second pass, doing visible ones instead
173    * i.e. if nothing selected, do whole pose
174    */
175   if (BLI_listbase_is_empty(pfLinks)) {
176     prev_ob = NULL;
177     ob_pose_armature = NULL;
178     CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, pchan, visible_pose_bones, Object *, ob) {
179       if (ob != prev_ob) {
180         prev_ob = ob;
181         ob_pose_armature = poseAnim_object_get(ob);
182       }
183
184       if (ob_pose_armature == NULL) {
185         continue;
186       }
187
188       fcurves_to_pchan_links_get(pfLinks, ob_pose_armature, ob_pose_armature->adt->action, pchan);
189     }
190     CTX_DATA_END;
191   }
192 }
193
194 /* free F-Curve <-> PoseChannel links  */
195 void poseAnim_mapping_free(ListBase *pfLinks)
196 {
197   tPChanFCurveLink *pfl, *pfln = NULL;
198
199   /* free the temp pchan links and their data */
200   for (pfl = pfLinks->first; pfl; pfl = pfln) {
201     pfln = pfl->next;
202
203     /* free custom properties */
204     if (pfl->oldprops) {
205       IDP_FreeProperty(pfl->oldprops);
206       MEM_freeN(pfl->oldprops);
207     }
208
209     /* free list of F-Curve reference links */
210     BLI_freelistN(&pfl->fcurves);
211
212     /* free pchan RNA Path */
213     MEM_freeN(pfl->pchan_path);
214
215     /* free link itself */
216     BLI_freelinkN(pfLinks, pfl);
217   }
218 }
219
220 /* ------------------------- */
221
222 /* helper for apply() / reset() - refresh the data */
223 void poseAnim_mapping_refresh(bContext *C, Scene *scene, Object *ob)
224 {
225   Depsgraph *depsgraph = CTX_data_depsgraph(C);
226   bArmature *arm = (bArmature *)ob->data;
227
228   /* old optimize trick... this enforces to bypass the depgraph
229    * - note: code copied from transform_generics.c -> recalcData()
230    */
231   /* FIXME: shouldn't this use the builtin stuff? */
232   if ((arm->flag & ARM_DELAYDEFORM) == 0) {
233     DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); /* sets recalc flags */
234   }
235   else {
236     BKE_pose_where_is(depsgraph, scene, ob);
237   }
238
239   /* otherwise animation doesn't get updated */
240   DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
241   WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
242 }
243
244 /* reset changes made to current pose */
245 void poseAnim_mapping_reset(ListBase *pfLinks)
246 {
247   tPChanFCurveLink *pfl;
248
249   /* iterate over each pose-channel affected, restoring all channels to their original values */
250   for (pfl = pfLinks->first; pfl; pfl = pfl->next) {
251     bPoseChannel *pchan = pfl->pchan;
252
253     /* just copy all the values over regardless of whether they changed or not */
254     copy_v3_v3(pchan->loc, pfl->oldloc);
255     copy_v3_v3(pchan->eul, pfl->oldrot);
256     copy_v3_v3(pchan->size, pfl->oldscale);
257     copy_qt_qt(pchan->quat, pfl->oldquat);
258     copy_v3_v3(pchan->rotAxis, pfl->oldaxis);
259     pchan->rotAngle = pfl->oldangle;
260
261     /* store current bbone values */
262     pchan->roll1 = pfl->roll1;
263     pchan->roll2 = pfl->roll2;
264     pchan->curve_in_x = pfl->curve_in_x;
265     pchan->curve_in_y = pfl->curve_in_y;
266     pchan->curve_out_x = pfl->curve_out_x;
267     pchan->curve_out_y = pfl->curve_out_y;
268     pchan->ease1 = pfl->ease1;
269     pchan->ease2 = pfl->ease2;
270     pchan->scale_in_x = pfl->scale_in_x;
271     pchan->scale_in_y = pfl->scale_in_y;
272     pchan->scale_out_x = pfl->scale_out_x;
273     pchan->scale_out_y = pfl->scale_out_y;
274
275     /* just overwrite values of properties from the stored copies (there should be some) */
276     if (pfl->oldprops) {
277       IDP_SyncGroupValues(pfl->pchan->prop, pfl->oldprops);
278     }
279   }
280 }
281
282 /* perform auto-key-framing after changes were made + confirmed */
283 void poseAnim_mapping_autoKeyframe(bContext *C, Scene *scene, ListBase *pfLinks, float cframe)
284 {
285   ViewLayer *view_layer = CTX_data_view_layer(C);
286   View3D *v3d = CTX_wm_view3d(C);
287   bool skip = true;
288
289   FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, OB_ARMATURE, OB_MODE_POSE, ob) {
290     ob->id.tag &= ~LIB_TAG_DOIT;
291     ob = poseAnim_object_get(ob);
292
293     /* Ensure validity of the settings from the context. */
294     if (ob == NULL) {
295       continue;
296     }
297
298     if (autokeyframe_cfra_can_key(scene, &ob->id)) {
299       ob->id.tag |= LIB_TAG_DOIT;
300       skip = false;
301     }
302   }
303   FOREACH_OBJECT_IN_MODE_END;
304
305   if (skip) {
306     return;
307   }
308
309   /* Insert keyframes as necessary if auto-key-framing. */
310   KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_WHOLE_CHARACTER_ID);
311   ListBase dsources = {NULL, NULL};
312   tPChanFCurveLink *pfl;
313
314   /* iterate over each pose-channel affected, tagging bones to be keyed */
315   /* XXX: here we already have the information about what transforms exist, though
316    * it might be easier to just overwrite all using normal mechanisms
317    */
318   for (pfl = pfLinks->first; pfl; pfl = pfl->next) {
319     bPoseChannel *pchan = pfl->pchan;
320
321     if ((pfl->ob->id.tag & LIB_TAG_DOIT) == 0) {
322       continue;
323     }
324
325     /* add datasource override for the PoseChannel, to be used later */
326     ANIM_relative_keyingset_add_source(&dsources, &pfl->ob->id, &RNA_PoseBone, pchan);
327
328     /* clear any unkeyed tags */
329     if (pchan->bone) {
330       pchan->bone->flag &= ~BONE_UNKEYED;
331     }
332   }
333
334   /* insert keyframes for all relevant bones in one go */
335   ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cframe);
336   BLI_freelistN(&dsources);
337
338   /* do the bone paths
339    * - only do this if keyframes should have been added
340    * - do not calculate unless there are paths already to update...
341    */
342   FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, OB_ARMATURE, OB_MODE_POSE, ob) {
343     if (ob->id.tag & LIB_TAG_DOIT) {
344       if (ob->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS) {
345         //ED_pose_clear_paths(C, ob); // XXX for now, don't need to clear
346         ED_pose_recalculate_paths(C, scene, ob, false);
347       }
348     }
349   }
350   FOREACH_OBJECT_IN_MODE_END;
351 }
352
353 /* ------------------------- */
354
355 /* find the next F-Curve for a PoseChannel with matching path...
356  * - path is not just the pfl rna_path, since that path doesn't have property info yet
357  */
358 LinkData *poseAnim_mapping_getNextFCurve(ListBase *fcuLinks, LinkData *prev, const char *path)
359 {
360   LinkData *first = (prev) ? prev->next : (fcuLinks) ? fcuLinks->first : NULL;
361   LinkData *ld;
362
363   /* check each link to see if the linked F-Curve has a matching path */
364   for (ld = first; ld; ld = ld->next) {
365     FCurve *fcu = (FCurve *)ld->data;
366
367     /* check if paths match */
368     if (STREQ(path, fcu->rna_path)) {
369       return ld;
370     }
371   }
372
373   /* none found */
374   return NULL;
375 }
376
377 /* *********************************************** */