Fix syntax for ID keyword.
[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 #include <stdlib.h>
29 #include <stdio.h>
30 #include <stddef.h>
31 #include <string.h>
32 #include <math.h>
33 #include <float.h>
34
35 #include "MEM_guardedalloc.h"
36
37 #include "BLI_math.h"
38 #include "BLI_blenlib.h"
39 #include "BLI_dynstr.h"
40 #include "BLI_dlrbTree.h"
41
42 #include "DNA_listBase.h"
43 #include "DNA_anim_types.h"
44 #include "DNA_action_types.h"
45 #include "DNA_armature_types.h"
46 #include "DNA_curve_types.h"
47 #include "DNA_object_types.h"
48 #include "DNA_object_force.h"
49 #include "DNA_scene_types.h"
50 #include "DNA_userdef_types.h"
51
52 #include "BKE_animsys.h"
53 #include "BKE_action.h"
54 #include "BKE_armature.h"
55 #include "BKE_depsgraph.h"
56 #include "BKE_fcurve.h"
57 #include "BKE_object.h"
58
59 #include "BKE_global.h"
60 #include "BKE_context.h"
61 #include "BKE_report.h"
62 #include "BKE_utildefines.h"
63
64 #include "RNA_access.h"
65 #include "RNA_define.h"
66 #include "RNA_types.h"
67
68 #include "WM_api.h"
69 #include "WM_types.h"
70
71 #include "UI_interface.h"
72 #include "UI_resources.h"
73
74 #include "BIF_gl.h"
75
76 #include "ED_anim_api.h"
77 #include "ED_armature.h"
78 #include "ED_keyframes_draw.h"
79 #include "ED_keyframing.h"
80 #include "ED_keyframes_edit.h"
81 #include "ED_screen.h"
82
83 #include "armature_intern.h"
84
85 /* *********************************************** */
86 /* Contents of this File:
87  *
88  * This file contains methods shared between Pose Slide and Pose Lib;
89  * primarily the functions in question concern Animato <-> Pose 
90  * convenience functions, such as applying/getting pose values
91  * and/or inserting keyframes for these.
92  */
93 /* *********************************************** */ 
94 /* FCurves <-> PoseChannels Links */
95
96 /* helper for poseAnim_mapping_get() -> get the relevant F-Curves per PoseChannel */
97 static void fcurves_to_pchan_links_get (ListBase *pfLinks, Object *ob, bAction *act, bPoseChannel *pchan)
98 {
99         ListBase curves = {NULL, NULL};
100         int transFlags = action_get_item_transforms(act, ob, pchan, &curves);
101         
102         pchan->flag &= ~(POSE_LOC|POSE_ROT|POSE_SIZE);
103         
104         /* check if any transforms found... */
105         if (transFlags) {
106                 /* make new linkage data */
107                 tPChanFCurveLink *pfl= MEM_callocN(sizeof(tPChanFCurveLink), "tPChanFCurveLink");
108                 PointerRNA ptr;
109                 
110                 pfl->fcurves= curves;
111                 pfl->pchan= pchan;
112                 
113                 /* get the RNA path to this pchan - this needs to be freed! */
114                 RNA_pointer_create((ID *)ob, &RNA_PoseBone, pchan, &ptr);
115                 pfl->pchan_path= RNA_path_from_ID_to_struct(&ptr);
116                 
117                 /* add linkage data to operator data */
118                 BLI_addtail(pfLinks, pfl);
119                 
120                 /* set pchan's transform flags */
121                 if (transFlags & ACT_TRANS_LOC)
122                         pchan->flag |= POSE_LOC;
123                 if (transFlags & ACT_TRANS_ROT)
124                         pchan->flag |= POSE_ROT;
125                 if (transFlags & ACT_TRANS_SCALE)
126                         pchan->flag |= POSE_SIZE;
127                         
128                 /* store current transforms */
129                 // TODO: store axis-angle too?
130                 VECCOPY(pfl->oldloc, pchan->loc);
131                 VECCOPY(pfl->oldrot, pchan->eul);
132                 VECCOPY(pfl->oldscale, pchan->size);
133                 QUATCOPY(pfl->oldquat, pchan->quat);
134         }
135
136
137
138 /* get sets of F-Curves providing transforms for the bones in the Pose  */
139 // TODO: separate the inner workings out to another helper func, since we need option of whether to take selected or visible bones...
140 void poseAnim_mapping_get (bContext *C, ListBase *pfLinks, Object *ob, bAction *act)
141 {       
142         /* for each Pose-Channel which gets affected, get the F-Curves for that channel 
143          * and set the relevant transform flags...
144          */
145         CTX_DATA_BEGIN(C, bPoseChannel*, pchan, selected_pose_bones) 
146         {
147                 fcurves_to_pchan_links_get(pfLinks, ob, act, pchan);
148         }
149         CTX_DATA_END;
150 }
151
152 /* free F-Curve <-> PoseChannel links  */
153 void poseAnim_mapping_free (ListBase *pfLinks)
154 {
155         tPChanFCurveLink *pfl, *pfln=NULL;
156                 
157         /* free the temp pchan links and their data */
158         for (pfl= pfLinks->first; pfl; pfl= pfln) {
159                 pfln= pfl->next;
160                 
161                 /* free list of F-Curve reference links */
162                 BLI_freelistN(&pfl->fcurves);
163                 
164                 /* free pchan RNA Path */
165                 MEM_freeN(pfl->pchan_path);
166                 
167                 /* free link itself */
168                 BLI_freelinkN(pfLinks, pfl);
169         }
170 }
171
172 /* ------------------------- */
173
174 /* helper for apply() / reset() - refresh the data */
175 void poseAnim_mapping_refresh (bContext *C, Scene *scene, Object *ob)
176 {
177         bArmature *arm= (bArmature *)ob->data;
178         
179         /* old optimize trick... this enforces to bypass the depgraph 
180          *      - note: code copied from transform_generics.c -> recalcData()
181          */
182         // FIXME: shouldn't this use the builtin stuff?
183         if ((arm->flag & ARM_DELAYDEFORM)==0)
184                 DAG_id_flush_update(&ob->id, OB_RECALC_DATA);  /* sets recalc flags */
185         else
186                 where_is_pose(scene, ob);
187         
188         /* note, notifier might evolve */
189         WM_event_add_notifier(C, NC_OBJECT|ND_POSE, ob);
190 }
191
192 /* reset changes made to current pose */
193 void poseAnim_mapping_reset (ListBase *pfLinks)
194 {
195         tPChanFCurveLink *pfl;
196         
197         /* iterate over each pose-channel affected, restoring all channels to their original values */
198         for (pfl= pfLinks->first; pfl; pfl= pfl->next) {
199                 bPoseChannel *pchan= pfl->pchan;
200                 
201                 /* just copy all the values over regardless of whether they changed or not */
202                 // TODO; include axis-angle here too?
203                 VECCOPY(pchan->loc, pfl->oldloc);
204                 VECCOPY(pchan->eul, pfl->oldrot);
205                 VECCOPY(pchan->size, pfl->oldscale);
206                 QUATCOPY(pchan->quat, pfl->oldquat);
207         }
208 }
209
210 /* perform autokeyframing after changes were made + confirmed */
211 void poseAnim_mapping_autoKeyframe (bContext *C, Scene *scene, Object *ob, ListBase *pfLinks, float cframe)
212 {
213         static short keyingsets_need_init = 1;
214         static KeyingSet *ks_loc = NULL;
215         static KeyingSet *ks_rot = NULL;
216         static KeyingSet *ks_scale = NULL;
217         
218         /* get keyingsets the first time this is run? 
219          * NOTE: it should be safe to store these static, since they're currently builtin ones
220          * but maybe later this may change, in which case this code needs to be revised!
221          */
222         if (keyingsets_need_init) {
223                 ks_loc= ANIM_builtin_keyingset_get_named(NULL, "Location");
224                 ks_rot= ANIM_builtin_keyingset_get_named(NULL, "Rotation");
225                 ks_scale= ANIM_builtin_keyingset_get_named(NULL, "Scaling");
226                 
227                 keyingsets_need_init = 0;
228         }
229         
230         /* insert keyframes as necessary if autokeyframing */
231         if (autokeyframe_cfra_can_key(scene, &ob->id)) {
232                 tPChanFCurveLink *pfl;
233                 
234                 /* iterate over each pose-channel affected, applying the changes */
235                 for (pfl= pfLinks->first; pfl; pfl= pfl->next) {
236                         ListBase dsources = {NULL, NULL};
237                         bPoseChannel *pchan= pfl->pchan;
238                         
239                         /* add datasource override for the PoseChannel so KeyingSet will do right thing */
240                         ANIM_relative_keyingset_add_source(&dsources, &ob->id, &RNA_PoseBone, pchan); 
241                         
242                         /* insert keyframes 
243                          *      - these keyingsets here use dsources, since we need to specify exactly which keyframes get affected
244                          */
245                         if (pchan->flag & POSE_LOC)
246                                 ANIM_apply_keyingset(C, &dsources, NULL, ks_loc, MODIFYKEY_MODE_INSERT, cframe);
247                         if (pchan->flag & POSE_ROT)
248                                 ANIM_apply_keyingset(C, &dsources, NULL, ks_rot, MODIFYKEY_MODE_INSERT, cframe);
249                         if (pchan->flag & POSE_SIZE)
250                                 ANIM_apply_keyingset(C, &dsources, NULL, ks_scale, MODIFYKEY_MODE_INSERT, cframe);
251                                 
252                         /* free the temp info */
253                         BLI_freelistN(&dsources);
254                 }
255         }
256 }
257
258 /* ------------------------- */
259
260 /* find the next F-Curve for a PoseChannel with matching path... 
261  *      - path is not just the pfl rna_path, since that path doesn't have property info yet
262  */
263 LinkData *poseAnim_mapping_getNextFCurve (ListBase *fcuLinks, LinkData *prev, char *path)
264 {
265         LinkData *first= (prev)? prev->next : (fcuLinks)? fcuLinks->first : NULL;
266         LinkData *ld;
267         
268         /* check each link to see if the linked F-Curve has a matching path */
269         for (ld= first; ld; ld= ld->next) {
270                 FCurve *fcu= (FCurve *)ld->data;
271                 
272                 /* check if paths match */
273                 if (strcmp(path, fcu->rna_path) == 0)
274                         return ld;
275         }       
276         
277         /* none found */
278         return NULL;
279 }
280
281 /* *********************************************** */