Cleanup: style, use braces for editors
[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->curveInX = pchan->curveInX;
119     pfl->curveInY = pchan->curveInY;
120     pfl->curveOutX = pchan->curveOutX;
121     pfl->curveOutY = pchan->curveOutY;
122     pfl->ease1 = pchan->ease1;
123     pfl->ease2 = pchan->ease2;
124     pfl->scaleIn = pchan->scaleIn;
125     pfl->scaleOut = pchan->scaleOut;
126
127     /* make copy of custom properties */
128     if (pchan->prop && (transFlags & ACT_TRANS_PROP)) {
129       pfl->oldprops = IDP_CopyProperty(pchan->prop);
130     }
131   }
132 }
133
134 /**
135  *  Returns a valid pose armature for this object, else returns NULL.
136  */
137 Object *poseAnim_object_get(Object *ob_)
138 {
139   Object *ob = BKE_object_pose_armature_get(ob_);
140   if (!ELEM(NULL, ob, ob->data, ob->adt, ob->adt->action)) {
141     return ob;
142   }
143   return NULL;
144 }
145
146 /* get sets of F-Curves providing transforms for the bones in the Pose  */
147 void poseAnim_mapping_get(bContext *C, ListBase *pfLinks)
148 {
149   /* for each Pose-Channel which gets affected, get the F-Curves for that channel
150    * and set the relevant transform flags...
151    */
152   Object *prev_ob, *ob_pose_armature;
153
154   prev_ob = NULL;
155   ob_pose_armature = NULL;
156   CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, pchan, selected_pose_bones, Object *, ob) {
157     if (ob != prev_ob) {
158       prev_ob = ob;
159       ob_pose_armature = poseAnim_object_get(ob);
160     }
161
162     if (ob_pose_armature == NULL) {
163       continue;
164     }
165
166     fcurves_to_pchan_links_get(pfLinks, ob_pose_armature, ob_pose_armature->adt->action, pchan);
167   }
168   CTX_DATA_END;
169
170   /* if no PoseChannels were found, try a second pass, doing visible ones instead
171    * i.e. if nothing selected, do whole pose
172    */
173   if (BLI_listbase_is_empty(pfLinks)) {
174     prev_ob = NULL;
175     ob_pose_armature = NULL;
176     CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, pchan, visible_pose_bones, Object *, ob) {
177       if (ob != prev_ob) {
178         prev_ob = ob;
179         ob_pose_armature = poseAnim_object_get(ob);
180       }
181
182       if (ob_pose_armature == NULL) {
183         continue;
184       }
185
186       fcurves_to_pchan_links_get(pfLinks, ob_pose_armature, ob_pose_armature->adt->action, pchan);
187     }
188     CTX_DATA_END;
189   }
190 }
191
192 /* free F-Curve <-> PoseChannel links  */
193 void poseAnim_mapping_free(ListBase *pfLinks)
194 {
195   tPChanFCurveLink *pfl, *pfln = NULL;
196
197   /* free the temp pchan links and their data */
198   for (pfl = pfLinks->first; pfl; pfl = pfln) {
199     pfln = pfl->next;
200
201     /* free custom properties */
202     if (pfl->oldprops) {
203       IDP_FreeProperty(pfl->oldprops);
204       MEM_freeN(pfl->oldprops);
205     }
206
207     /* free list of F-Curve reference links */
208     BLI_freelistN(&pfl->fcurves);
209
210     /* free pchan RNA Path */
211     MEM_freeN(pfl->pchan_path);
212
213     /* free link itself */
214     BLI_freelinkN(pfLinks, pfl);
215   }
216 }
217
218 /* ------------------------- */
219
220 /* helper for apply() / reset() - refresh the data */
221 void poseAnim_mapping_refresh(bContext *C, Scene *scene, Object *ob)
222 {
223   Depsgraph *depsgraph = CTX_data_depsgraph(C);
224   bArmature *arm = (bArmature *)ob->data;
225
226   /* old optimize trick... this enforces to bypass the depgraph
227    * - note: code copied from transform_generics.c -> recalcData()
228    */
229   /* FIXME: shouldn't this use the builtin stuff? */
230   if ((arm->flag & ARM_DELAYDEFORM) == 0) {
231     DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); /* sets recalc flags */
232   }
233   else {
234     BKE_pose_where_is(depsgraph, scene, ob);
235   }
236
237   /* otherwise animation doesn't get updated */
238   DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
239   WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
240 }
241
242 /* reset changes made to current pose */
243 void poseAnim_mapping_reset(ListBase *pfLinks)
244 {
245   tPChanFCurveLink *pfl;
246
247   /* iterate over each pose-channel affected, restoring all channels to their original values */
248   for (pfl = pfLinks->first; pfl; pfl = pfl->next) {
249     bPoseChannel *pchan = pfl->pchan;
250
251     /* just copy all the values over regardless of whether they changed or not */
252     copy_v3_v3(pchan->loc, pfl->oldloc);
253     copy_v3_v3(pchan->eul, pfl->oldrot);
254     copy_v3_v3(pchan->size, pfl->oldscale);
255     copy_qt_qt(pchan->quat, pfl->oldquat);
256     copy_v3_v3(pchan->rotAxis, pfl->oldaxis);
257     pchan->rotAngle = pfl->oldangle;
258
259     /* store current bbone values */
260     pchan->roll1 = pfl->roll1;
261     pchan->roll2 = pfl->roll2;
262     pchan->curveInX = pfl->curveInX;
263     pchan->curveInY = pfl->curveInY;
264     pchan->curveOutX = pfl->curveOutX;
265     pchan->curveOutY = pfl->curveOutY;
266     pchan->ease1 = pfl->ease1;
267     pchan->ease2 = pfl->ease2;
268     pchan->scaleIn = pfl->scaleIn;
269     pchan->scaleOut = pfl->scaleOut;
270
271     /* just overwrite values of properties from the stored copies (there should be some) */
272     if (pfl->oldprops) {
273       IDP_SyncGroupValues(pfl->pchan->prop, pfl->oldprops);
274     }
275   }
276 }
277
278 /* perform auto-key-framing after changes were made + confirmed */
279 void poseAnim_mapping_autoKeyframe(bContext *C, Scene *scene, ListBase *pfLinks, float cframe)
280 {
281   ViewLayer *view_layer = CTX_data_view_layer(C);
282   View3D *v3d = CTX_wm_view3d(C);
283   bool skip = true;
284
285   FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, OB_ARMATURE, OB_MODE_POSE, ob) {
286     ob->id.tag &= ~LIB_TAG_DOIT;
287     ob = poseAnim_object_get(ob);
288
289     /* Ensure validity of the settings from the context. */
290     if (ob == NULL) {
291       continue;
292     }
293
294     if (autokeyframe_cfra_can_key(scene, &ob->id)) {
295       ob->id.tag |= LIB_TAG_DOIT;
296       skip = false;
297     }
298   }
299   FOREACH_OBJECT_IN_MODE_END;
300
301   if (skip) {
302     return;
303   }
304
305   /* Insert keyframes as necessary if auto-key-framing. */
306   KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_WHOLE_CHARACTER_ID);
307   ListBase dsources = {NULL, NULL};
308   tPChanFCurveLink *pfl;
309
310   /* iterate over each pose-channel affected, tagging bones to be keyed */
311   /* XXX: here we already have the information about what transforms exist, though
312    * it might be easier to just overwrite all using normal mechanisms
313    */
314   for (pfl = pfLinks->first; pfl; pfl = pfl->next) {
315     bPoseChannel *pchan = pfl->pchan;
316
317     if ((pfl->ob->id.tag & LIB_TAG_DOIT) == 0) {
318       continue;
319     }
320
321     /* add datasource override for the PoseChannel, to be used later */
322     ANIM_relative_keyingset_add_source(&dsources, &pfl->ob->id, &RNA_PoseBone, pchan);
323
324     /* clear any unkeyed tags */
325     if (pchan->bone) {
326       pchan->bone->flag &= ~BONE_UNKEYED;
327     }
328   }
329
330   /* insert keyframes for all relevant bones in one go */
331   ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cframe);
332   BLI_freelistN(&dsources);
333
334   /* do the bone paths
335    * - only do this if keyframes should have been added
336    * - do not calculate unless there are paths already to update...
337    */
338   FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, OB_ARMATURE, OB_MODE_POSE, ob) {
339     if (ob->id.tag & LIB_TAG_DOIT) {
340       if (ob->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS) {
341         //ED_pose_clear_paths(C, ob); // XXX for now, don't need to clear
342         ED_pose_recalculate_paths(C, scene, ob, false);
343       }
344     }
345   }
346   FOREACH_OBJECT_IN_MODE_END;
347 }
348
349 /* ------------------------- */
350
351 /* find the next F-Curve for a PoseChannel with matching path...
352  * - path is not just the pfl rna_path, since that path doesn't have property info yet
353  */
354 LinkData *poseAnim_mapping_getNextFCurve(ListBase *fcuLinks, LinkData *prev, const char *path)
355 {
356   LinkData *first = (prev) ? prev->next : (fcuLinks) ? fcuLinks->first : NULL;
357   LinkData *ld;
358
359   /* check each link to see if the linked F-Curve has a matching path */
360   for (ld = first; ld; ld = ld->next) {
361     FCurve *fcu = (FCurve *)ld->data;
362
363     /* check if paths match */
364     if (STREQ(path, fcu->rna_path)) {
365       return ld;
366     }
367   }
368
369   /* none found */
370   return NULL;
371 }
372
373 /* *********************************************** */