fix [#27915] Relax Pose crashes blender on bone with ChildOf constraint in linked rig
[blender-staging.git] / source / blender / editors / armature / poseUtils.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2009, Blender Foundation, Joshua Leung
21  * This is a new part of Blender
22  *
23  * Contributor(s): Joshua Leung
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/editors/armature/poseUtils.c
29  *  \ingroup edarmature
30  */
31
32
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <stddef.h>
36 #include <string.h>
37 #include <math.h>
38 #include <float.h>
39
40 #include "MEM_guardedalloc.h"
41
42 #include "BLI_math.h"
43 #include "BLI_blenlib.h"
44 #include "BLI_dynstr.h"
45 #include "BLI_dlrbTree.h"
46 #include "BLI_utildefines.h"
47
48 #include "DNA_anim_types.h"
49 #include "DNA_armature_types.h"
50 #include "DNA_object_types.h"
51 #include "DNA_scene_types.h"
52
53 #include "BKE_action.h"
54 #include "BKE_armature.h"
55 #include "BKE_depsgraph.h"
56 #include "BKE_idprop.h"
57
58 #include "BKE_context.h"
59
60 #include "RNA_access.h"
61
62 #include "WM_api.h"
63 #include "WM_types.h"
64
65
66
67 #include "ED_armature.h"
68 #include "ED_keyframing.h"
69
70 #include "armature_intern.h"
71
72 /* *********************************************** */
73 /* Contents of this File:
74  *
75  * This file contains methods shared between Pose Slide and Pose Lib;
76  * primarily the functions in question concern Animato <-> Pose 
77  * convenience functions, such as applying/getting pose values
78  * and/or inserting keyframes for these.
79  */
80 /* *********************************************** */ 
81 /* FCurves <-> PoseChannels Links */
82
83 /* helper for poseAnim_mapping_get() -> get the relevant F-Curves per PoseChannel */
84 static void fcurves_to_pchan_links_get (ListBase *pfLinks, Object *ob, bAction *act, bPoseChannel *pchan)
85 {
86         ListBase curves = {NULL, NULL};
87         int transFlags = action_get_item_transforms(act, ob, pchan, &curves);
88         
89         pchan->flag &= ~(POSE_LOC|POSE_ROT|POSE_SIZE);
90         
91         /* check if any transforms found... */
92         if (transFlags) {
93                 /* make new linkage data */
94                 tPChanFCurveLink *pfl= MEM_callocN(sizeof(tPChanFCurveLink), "tPChanFCurveLink");
95                 PointerRNA ptr;
96                 
97                 pfl->fcurves= curves;
98                 pfl->pchan= pchan;
99                 
100                 /* get the RNA path to this pchan - this needs to be freed! */
101                 RNA_pointer_create((ID *)ob, &RNA_PoseBone, pchan, &ptr);
102                 pfl->pchan_path= RNA_path_from_ID_to_struct(&ptr);
103                 
104                 /* add linkage data to operator data */
105                 BLI_addtail(pfLinks, pfl);
106                 
107                 /* set pchan's transform flags */
108                 if (transFlags & ACT_TRANS_LOC)
109                         pchan->flag |= POSE_LOC;
110                 if (transFlags & ACT_TRANS_ROT)
111                         pchan->flag |= POSE_ROT;
112                 if (transFlags & ACT_TRANS_SCALE)
113                         pchan->flag |= POSE_SIZE;
114                         
115                 /* store current transforms */
116                 VECCOPY(pfl->oldloc, pchan->loc);
117                 VECCOPY(pfl->oldrot, pchan->eul);
118                 VECCOPY(pfl->oldscale, pchan->size);
119                 QUATCOPY(pfl->oldquat, pchan->quat);
120                 VECCOPY(pfl->oldaxis, pchan->rotAxis);
121                 pfl->oldangle = pchan->rotAngle;
122                 
123                 /* make copy of custom properties */
124                 if (pchan->prop && (transFlags & ACT_TRANS_PROP))
125                         pfl->oldprops = IDP_CopyProperty(pchan->prop);
126         }
127
128
129
130 /* get sets of F-Curves providing transforms for the bones in the Pose  */
131 void poseAnim_mapping_get (bContext *C, ListBase *pfLinks, Object *ob, bAction *act)
132 {       
133         /* for each Pose-Channel which gets affected, get the F-Curves for that channel 
134          * and set the relevant transform flags...
135          */
136         CTX_DATA_BEGIN(C, bPoseChannel*, pchan, selected_pose_bones) 
137         {
138                 fcurves_to_pchan_links_get(pfLinks, ob, act, pchan);
139         }
140         CTX_DATA_END;
141         
142         /* if no PoseChannels were found, try a second pass, doing visible ones instead
143          * i.e. if nothing selected, do whole pose
144          */
145         if (pfLinks->first == NULL) {
146                 CTX_DATA_BEGIN(C, bPoseChannel*, pchan, visible_pose_bones)
147                 {
148                         fcurves_to_pchan_links_get(pfLinks, ob, act, pchan);
149                 }
150                 CTX_DATA_END;
151         }
152 }
153
154 /* free F-Curve <-> PoseChannel links  */
155 void poseAnim_mapping_free (ListBase *pfLinks)
156 {
157         tPChanFCurveLink *pfl, *pfln=NULL;
158                 
159         /* free the temp pchan links and their data */
160         for (pfl= pfLinks->first; pfl; pfl= pfln) {
161                 pfln= pfl->next;
162                 
163                 /* free custom properties */
164                 if (pfl->oldprops) {
165                         IDP_FreeProperty(pfl->oldprops);
166                         MEM_freeN(pfl->oldprops);
167                 }
168                 
169                 /* free list of F-Curve reference links */
170                 BLI_freelistN(&pfl->fcurves);
171                 
172                 /* free pchan RNA Path */
173                 MEM_freeN(pfl->pchan_path);
174                 
175                 /* free link itself */
176                 BLI_freelinkN(pfLinks, pfl);
177         }
178 }
179
180 /* ------------------------- */
181
182 /* helper for apply() / reset() - refresh the data */
183 void poseAnim_mapping_refresh (bContext *C, Scene *scene, Object *ob)
184 {
185         bArmature *arm= (bArmature *)ob->data;
186         
187         /* old optimize trick... this enforces to bypass the depgraph 
188          *      - note: code copied from transform_generics.c -> recalcData()
189          */
190         // FIXME: shouldn't this use the builtin stuff?
191         if ((arm->flag & ARM_DELAYDEFORM)==0)
192                 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);  /* sets recalc flags */
193         else
194                 where_is_pose(scene, ob);
195         
196         /* note, notifier might evolve */
197         WM_event_add_notifier(C, NC_OBJECT|ND_POSE, ob);
198 }
199
200 /* reset changes made to current pose */
201 void poseAnim_mapping_reset (ListBase *pfLinks)
202 {
203         tPChanFCurveLink *pfl;
204         
205         /* iterate over each pose-channel affected, restoring all channels to their original values */
206         for (pfl= pfLinks->first; pfl; pfl= pfl->next) {
207                 bPoseChannel *pchan= pfl->pchan;
208                 
209                 /* just copy all the values over regardless of whether they changed or not */
210                 VECCOPY(pchan->loc, pfl->oldloc);
211                 VECCOPY(pchan->eul, pfl->oldrot);
212                 VECCOPY(pchan->size, pfl->oldscale);
213                 QUATCOPY(pchan->quat, pfl->oldquat);
214                 VECCOPY(pchan->rotAxis, pfl->oldaxis);
215                 pchan->rotAngle = pfl->oldangle;
216                 
217                 /* just overwrite values of properties from the stored copies (there should be some) */
218                 if (pfl->oldprops)
219                         IDP_SyncGroupValues(pfl->pchan->prop, pfl->oldprops);
220         }
221 }
222
223 /* perform autokeyframing after changes were made + confirmed */
224 void poseAnim_mapping_autoKeyframe (bContext *C, Scene *scene, Object *ob, ListBase *pfLinks, float cframe)
225 {
226         /* insert keyframes as necessary if autokeyframing */
227         if (autokeyframe_cfra_can_key(scene, &ob->id)) {
228                 KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, "Whole Character");
229                 ListBase dsources = {NULL, NULL};
230                 tPChanFCurveLink *pfl;
231                 
232                 /* iterate over each pose-channel affected, tagging bones to be keyed */
233                 /* XXX: here we already have the information about what transforms exist, though 
234                  * it might be easier to just overwrite all using normal mechanisms
235                  */
236                 for (pfl= pfLinks->first; pfl; pfl= pfl->next) {
237                         bPoseChannel *pchan= pfl->pchan;
238                         
239                         /* add datasource override for the PoseChannel, to be used later */
240                         ANIM_relative_keyingset_add_source(&dsources, &ob->id, &RNA_PoseBone, pchan); 
241                         
242                         /* clear any unkeyed tags */
243                         if (pchan->bone)
244                                 pchan->bone->flag &= ~BONE_UNKEYED;
245                 }
246                 
247                 /* insert keyframes for all relevant bones in one go */
248                 ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cframe);
249                 BLI_freelistN(&dsources);
250         }
251 }
252
253 /* ------------------------- */
254
255 /* find the next F-Curve for a PoseChannel with matching path... 
256  *      - path is not just the pfl rna_path, since that path doesn't have property info yet
257  */
258 LinkData *poseAnim_mapping_getNextFCurve (ListBase *fcuLinks, LinkData *prev, char *path)
259 {
260         LinkData *first= (prev)? prev->next : (fcuLinks)? fcuLinks->first : NULL;
261         LinkData *ld;
262         
263         /* check each link to see if the linked F-Curve has a matching path */
264         for (ld= first; ld; ld= ld->next) {
265                 FCurve *fcu= (FCurve *)ld->data;
266                 
267                 /* check if paths match */
268                 if (strcmp(path, fcu->rna_path) == 0)
269                         return ld;
270         }       
271         
272         /* none found */
273         return NULL;
274 }
275
276 /* *********************************************** */