Blender  V2.59
poseUtils.c
Go to the documentation of this file.
00001 /*
00002  * $Id: poseUtils.c 38257 2011-07-09 14:33:28Z campbellbarton $
00003  *
00004  * ***** BEGIN GPL LICENSE BLOCK *****
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software Foundation,
00018  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  *
00020  * The Original Code is Copyright (C) 2009, Blender Foundation, Joshua Leung
00021  * This is a new part of Blender
00022  *
00023  * Contributor(s): Joshua Leung
00024  *
00025  * ***** END GPL LICENSE BLOCK *****
00026  */
00027 
00033 #include <stdlib.h>
00034 #include <stdio.h>
00035 #include <stddef.h>
00036 #include <string.h>
00037 #include <math.h>
00038 #include <float.h>
00039 
00040 #include "MEM_guardedalloc.h"
00041 
00042 #include "BLI_math.h"
00043 #include "BLI_blenlib.h"
00044 #include "BLI_dynstr.h"
00045 #include "BLI_dlrbTree.h"
00046 #include "BLI_utildefines.h"
00047 
00048 #include "DNA_anim_types.h"
00049 #include "DNA_armature_types.h"
00050 #include "DNA_object_types.h"
00051 #include "DNA_scene_types.h"
00052 
00053 #include "BKE_action.h"
00054 #include "BKE_armature.h"
00055 #include "BKE_depsgraph.h"
00056 #include "BKE_idprop.h"
00057 
00058 #include "BKE_context.h"
00059 
00060 #include "RNA_access.h"
00061 
00062 #include "WM_api.h"
00063 #include "WM_types.h"
00064 
00065 
00066 
00067 #include "ED_armature.h"
00068 #include "ED_keyframing.h"
00069 
00070 #include "armature_intern.h"
00071 
00072 /* *********************************************** */
00073 /* Contents of this File:
00074  *
00075  * This file contains methods shared between Pose Slide and Pose Lib;
00076  * primarily the functions in question concern Animato <-> Pose 
00077  * convenience functions, such as applying/getting pose values
00078  * and/or inserting keyframes for these.
00079  */
00080 /* *********************************************** */ 
00081 /* FCurves <-> PoseChannels Links */
00082 
00083 /* helper for poseAnim_mapping_get() -> get the relevant F-Curves per PoseChannel */
00084 static void fcurves_to_pchan_links_get (ListBase *pfLinks, Object *ob, bAction *act, bPoseChannel *pchan)
00085 {
00086         ListBase curves = {NULL, NULL};
00087         int transFlags = action_get_item_transforms(act, ob, pchan, &curves);
00088         
00089         pchan->flag &= ~(POSE_LOC|POSE_ROT|POSE_SIZE);
00090         
00091         /* check if any transforms found... */
00092         if (transFlags) {
00093                 /* make new linkage data */
00094                 tPChanFCurveLink *pfl= MEM_callocN(sizeof(tPChanFCurveLink), "tPChanFCurveLink");
00095                 PointerRNA ptr;
00096                 
00097                 pfl->fcurves= curves;
00098                 pfl->pchan= pchan;
00099                 
00100                 /* get the RNA path to this pchan - this needs to be freed! */
00101                 RNA_pointer_create((ID *)ob, &RNA_PoseBone, pchan, &ptr);
00102                 pfl->pchan_path= RNA_path_from_ID_to_struct(&ptr);
00103                 
00104                 /* add linkage data to operator data */
00105                 BLI_addtail(pfLinks, pfl);
00106                 
00107                 /* set pchan's transform flags */
00108                 if (transFlags & ACT_TRANS_LOC)
00109                         pchan->flag |= POSE_LOC;
00110                 if (transFlags & ACT_TRANS_ROT)
00111                         pchan->flag |= POSE_ROT;
00112                 if (transFlags & ACT_TRANS_SCALE)
00113                         pchan->flag |= POSE_SIZE;
00114                         
00115                 /* store current transforms */
00116                 VECCOPY(pfl->oldloc, pchan->loc);
00117                 VECCOPY(pfl->oldrot, pchan->eul);
00118                 VECCOPY(pfl->oldscale, pchan->size);
00119                 QUATCOPY(pfl->oldquat, pchan->quat);
00120                 VECCOPY(pfl->oldaxis, pchan->rotAxis);
00121                 pfl->oldangle = pchan->rotAngle;
00122                 
00123                 /* make copy of custom properties */
00124                 if (pchan->prop && (transFlags & ACT_TRANS_PROP))
00125                         pfl->oldprops = IDP_CopyProperty(pchan->prop);
00126         }
00127 } 
00128 
00129 
00130 /* get sets of F-Curves providing transforms for the bones in the Pose  */
00131 void poseAnim_mapping_get (bContext *C, ListBase *pfLinks, Object *ob, bAction *act)
00132 {       
00133         /* for each Pose-Channel which gets affected, get the F-Curves for that channel 
00134          * and set the relevant transform flags...
00135          */
00136         CTX_DATA_BEGIN(C, bPoseChannel*, pchan, selected_pose_bones) 
00137         {
00138                 fcurves_to_pchan_links_get(pfLinks, ob, act, pchan);
00139         }
00140         CTX_DATA_END;
00141         
00142         /* if no PoseChannels were found, try a second pass, doing visible ones instead
00143          * i.e. if nothing selected, do whole pose
00144          */
00145         if (pfLinks->first == NULL) {
00146                 CTX_DATA_BEGIN(C, bPoseChannel*, pchan, visible_pose_bones)
00147                 {
00148                         fcurves_to_pchan_links_get(pfLinks, ob, act, pchan);
00149                 }
00150                 CTX_DATA_END;
00151         }
00152 }
00153 
00154 /* free F-Curve <-> PoseChannel links  */
00155 void poseAnim_mapping_free (ListBase *pfLinks)
00156 {
00157         tPChanFCurveLink *pfl, *pfln=NULL;
00158                 
00159         /* free the temp pchan links and their data */
00160         for (pfl= pfLinks->first; pfl; pfl= pfln) {
00161                 pfln= pfl->next;
00162                 
00163                 /* free custom properties */
00164                 if (pfl->oldprops) {
00165                         IDP_FreeProperty(pfl->oldprops);
00166                         MEM_freeN(pfl->oldprops);
00167                 }
00168                 
00169                 /* free list of F-Curve reference links */
00170                 BLI_freelistN(&pfl->fcurves);
00171                 
00172                 /* free pchan RNA Path */
00173                 MEM_freeN(pfl->pchan_path);
00174                 
00175                 /* free link itself */
00176                 BLI_freelinkN(pfLinks, pfl);
00177         }
00178 }
00179 
00180 /* ------------------------- */
00181 
00182 /* helper for apply() / reset() - refresh the data */
00183 void poseAnim_mapping_refresh (bContext *C, Scene *scene, Object *ob)
00184 {
00185         bArmature *arm= (bArmature *)ob->data;
00186         
00187         /* old optimize trick... this enforces to bypass the depgraph 
00188          *      - note: code copied from transform_generics.c -> recalcData()
00189          */
00190         // FIXME: shouldn't this use the builtin stuff?
00191         if ((arm->flag & ARM_DELAYDEFORM)==0)
00192                 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);  /* sets recalc flags */
00193         else
00194                 where_is_pose(scene, ob);
00195         
00196         /* note, notifier might evolve */
00197         WM_event_add_notifier(C, NC_OBJECT|ND_POSE, ob);
00198 }
00199 
00200 /* reset changes made to current pose */
00201 void poseAnim_mapping_reset (ListBase *pfLinks)
00202 {
00203         tPChanFCurveLink *pfl;
00204         
00205         /* iterate over each pose-channel affected, restoring all channels to their original values */
00206         for (pfl= pfLinks->first; pfl; pfl= pfl->next) {
00207                 bPoseChannel *pchan= pfl->pchan;
00208                 
00209                 /* just copy all the values over regardless of whether they changed or not */
00210                 VECCOPY(pchan->loc, pfl->oldloc);
00211                 VECCOPY(pchan->eul, pfl->oldrot);
00212                 VECCOPY(pchan->size, pfl->oldscale);
00213                 QUATCOPY(pchan->quat, pfl->oldquat);
00214                 VECCOPY(pchan->rotAxis, pfl->oldaxis);
00215                 pchan->rotAngle = pfl->oldangle;
00216                 
00217                 /* just overwrite values of properties from the stored copies (there should be some) */
00218                 if (pfl->oldprops)
00219                         IDP_SyncGroupValues(pfl->pchan->prop, pfl->oldprops);
00220         }
00221 }
00222 
00223 /* perform autokeyframing after changes were made + confirmed */
00224 void poseAnim_mapping_autoKeyframe (bContext *C, Scene *scene, Object *ob, ListBase *pfLinks, float cframe)
00225 {
00226         /* insert keyframes as necessary if autokeyframing */
00227         if (autokeyframe_cfra_can_key(scene, &ob->id)) {
00228                 KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, "Whole Character");
00229                 ListBase dsources = {NULL, NULL};
00230                 tPChanFCurveLink *pfl;
00231                 
00232                 /* iterate over each pose-channel affected, tagging bones to be keyed */
00233                 /* XXX: here we already have the information about what transforms exist, though 
00234                  * it might be easier to just overwrite all using normal mechanisms
00235                  */
00236                 for (pfl= pfLinks->first; pfl; pfl= pfl->next) {
00237                         bPoseChannel *pchan= pfl->pchan;
00238                         
00239                         /* add datasource override for the PoseChannel, to be used later */
00240                         ANIM_relative_keyingset_add_source(&dsources, &ob->id, &RNA_PoseBone, pchan); 
00241                         
00242                         /* clear any unkeyed tags */
00243                         if (pchan->bone)
00244                                 pchan->bone->flag &= ~BONE_UNKEYED;
00245                 }
00246                 
00247                 /* insert keyframes for all relevant bones in one go */
00248                 ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cframe);
00249                 BLI_freelistN(&dsources);
00250         }
00251 }
00252 
00253 /* ------------------------- */
00254 
00255 /* find the next F-Curve for a PoseChannel with matching path... 
00256  *      - path is not just the pfl rna_path, since that path doesn't have property info yet
00257  */
00258 LinkData *poseAnim_mapping_getNextFCurve (ListBase *fcuLinks, LinkData *prev, char *path)
00259 {
00260         LinkData *first= (prev)? prev->next : (fcuLinks)? fcuLinks->first : NULL;
00261         LinkData *ld;
00262         
00263         /* check each link to see if the linked F-Curve has a matching path */
00264         for (ld= first; ld; ld= ld->next) {
00265                 FCurve *fcu= (FCurve *)ld->data;
00266                 
00267                 /* check if paths match */
00268                 if (strcmp(path, fcu->rna_path) == 0)
00269                         return ld;
00270         }       
00271         
00272         /* none found */
00273         return NULL;
00274 }
00275 
00276 /* *********************************************** */