|
Blender
V2.59
|
00001 /* 00002 * $Id: anim_sys.c 36903 2011-05-26 05:35:30Z 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 * All rights reserved. 00022 * 00023 * The Original Code is: all of this file. 00024 * 00025 * Contributor(s): Joshua Leung (full recode) 00026 * 00027 * ***** END GPL LICENSE BLOCK ***** 00028 */ 00029 00035 #include <stdio.h> 00036 #include <string.h> 00037 #include <stddef.h> 00038 #include <float.h> 00039 #include <math.h> 00040 00041 #include "MEM_guardedalloc.h" 00042 00043 #include "BLI_blenlib.h" 00044 #include "BLI_dynstr.h" 00045 #include "BLI_utildefines.h" 00046 00047 #include "DNA_anim_types.h" 00048 #include "DNA_material_types.h" 00049 #include "DNA_scene_types.h" 00050 #include "DNA_texture_types.h" 00051 00052 #include "BKE_animsys.h" 00053 #include "BKE_action.h" 00054 #include "BKE_fcurve.h" 00055 #include "BKE_nla.h" 00056 #include "BKE_global.h" 00057 #include "BKE_main.h" 00058 #include "BKE_library.h" 00059 #include "BKE_utildefines.h" 00060 00061 #include "RNA_access.h" 00062 00063 #include "nla_private.h" 00064 00065 /* ***************************************** */ 00066 /* AnimData API */ 00067 00068 /* Getter/Setter -------------------------------------------- */ 00069 00070 /* Check if ID can have AnimData */ 00071 short id_type_can_have_animdata (ID *id) 00072 { 00073 /* sanity check */ 00074 if (id == NULL) 00075 return 0; 00076 00077 /* Only some ID-blocks have this info for now */ 00078 // TODO: finish adding this for the other blocktypes 00079 switch (GS(id->name)) { 00080 /* has AnimData */ 00081 case ID_OB: 00082 case ID_ME: case ID_MB: case ID_CU: case ID_AR: case ID_LT: 00083 case ID_KE: 00084 case ID_PA: 00085 case ID_MA: case ID_TE: case ID_NT: 00086 case ID_LA: case ID_CA: case ID_WO: 00087 case ID_SCE: 00088 { 00089 return 1; 00090 } 00091 00092 /* no AnimData */ 00093 default: 00094 return 0; 00095 } 00096 } 00097 00098 00099 /* Get AnimData from the given ID-block. In order for this to work, we assume that 00100 * the AnimData pointer is stored immediately after the given ID-block in the struct, 00101 * as per IdAdtTemplate. 00102 */ 00103 AnimData *BKE_animdata_from_id (ID *id) 00104 { 00105 /* only some ID-blocks have this info for now, so we cast the 00106 * types that do to be of type IdAdtTemplate, and extract the 00107 * AnimData that way 00108 */ 00109 if (id_type_can_have_animdata(id)) { 00110 IdAdtTemplate *iat= (IdAdtTemplate *)id; 00111 return iat->adt; 00112 } 00113 else 00114 return NULL; 00115 } 00116 00117 /* Add AnimData to the given ID-block. In order for this to work, we assume that 00118 * the AnimData pointer is stored immediately after the given ID-block in the struct, 00119 * as per IdAdtTemplate. Also note that 00120 */ 00121 AnimData *BKE_id_add_animdata (ID *id) 00122 { 00123 /* Only some ID-blocks have this info for now, so we cast the 00124 * types that do to be of type IdAdtTemplate, and add the AnimData 00125 * to it using the template 00126 */ 00127 if (id_type_can_have_animdata(id)) { 00128 IdAdtTemplate *iat= (IdAdtTemplate *)id; 00129 00130 /* check if there's already AnimData, in which case, don't add */ 00131 if (iat->adt == NULL) { 00132 AnimData *adt; 00133 00134 /* add animdata */ 00135 adt= iat->adt= MEM_callocN(sizeof(AnimData), "AnimData"); 00136 00137 /* set default settings */ 00138 adt->act_influence= 1.0f; 00139 } 00140 00141 return iat->adt; 00142 } 00143 else 00144 return NULL; 00145 } 00146 00147 /* Freeing -------------------------------------------- */ 00148 00149 /* Free AnimData used by the nominated ID-block, and clear ID-block's AnimData pointer */ 00150 void BKE_free_animdata (ID *id) 00151 { 00152 /* Only some ID-blocks have this info for now, so we cast the 00153 * types that do to be of type IdAdtTemplate 00154 */ 00155 if (id_type_can_have_animdata(id)) { 00156 IdAdtTemplate *iat= (IdAdtTemplate *)id; 00157 AnimData *adt= iat->adt; 00158 00159 /* check if there's any AnimData to start with */ 00160 if (adt) { 00161 /* unlink action (don't free, as it's in its own list) */ 00162 if (adt->action) 00163 adt->action->id.us--; 00164 /* same goes for the temporarily displaced action */ 00165 if (adt->tmpact) 00166 adt->tmpact->id.us--; 00167 00168 /* free nla data */ 00169 free_nladata(&adt->nla_tracks); 00170 00171 /* free drivers - stored as a list of F-Curves */ 00172 free_fcurves(&adt->drivers); 00173 00174 /* free overrides */ 00175 // TODO... 00176 00177 /* free animdata now */ 00178 MEM_freeN(adt); 00179 iat->adt= NULL; 00180 } 00181 } 00182 } 00183 00184 /* Freeing -------------------------------------------- */ 00185 00186 /* Make a copy of the given AnimData - to be used when copying datablocks */ 00187 AnimData *BKE_copy_animdata (AnimData *adt, const short do_action) 00188 { 00189 AnimData *dadt; 00190 00191 /* sanity check before duplicating struct */ 00192 if (adt == NULL) 00193 return NULL; 00194 dadt= MEM_dupallocN(adt); 00195 00196 /* make a copy of action - at worst, user has to delete copies... */ 00197 if (do_action) { 00198 dadt->action= copy_action(adt->action); 00199 dadt->tmpact= copy_action(adt->tmpact); 00200 } 00201 else { 00202 id_us_plus((ID *)dadt->action); 00203 id_us_plus((ID *)dadt->tmpact); 00204 } 00205 00206 /* duplicate NLA data */ 00207 copy_nladata(&dadt->nla_tracks, &adt->nla_tracks); 00208 00209 /* duplicate drivers (F-Curves) */ 00210 copy_fcurves(&dadt->drivers, &adt->drivers); 00211 00212 /* don't copy overrides */ 00213 dadt->overrides.first= dadt->overrides.last= NULL; 00214 00215 /* return */ 00216 return dadt; 00217 } 00218 00219 int BKE_copy_animdata_id (ID *id_to, ID *id_from, const short do_action) 00220 { 00221 AnimData *adt; 00222 00223 if ((id_to && id_from) && (GS(id_to->name) != GS(id_from->name))) 00224 return 0; 00225 00226 BKE_free_animdata(id_to); 00227 00228 adt = BKE_animdata_from_id(id_from); 00229 if (adt) { 00230 IdAdtTemplate *iat = (IdAdtTemplate *)id_to; 00231 iat->adt= BKE_copy_animdata(adt, do_action); 00232 } 00233 00234 return 1; 00235 } 00236 00237 void BKE_copy_animdata_id_action(struct ID *id) 00238 { 00239 AnimData *adt= BKE_animdata_from_id(id); 00240 if (adt) { 00241 if (adt->action) { 00242 id_us_min((ID *)adt->action); 00243 adt->action= copy_action(adt->action); 00244 } 00245 if (adt->tmpact) { 00246 id_us_min((ID *)adt->tmpact); 00247 adt->tmpact= copy_action(adt->tmpact); 00248 } 00249 } 00250 } 00251 00252 /* Make Local -------------------------------------------- */ 00253 00254 static void make_local_strips(ListBase *strips) 00255 { 00256 NlaStrip *strip; 00257 00258 for (strip=strips->first; strip; strip=strip->next) { 00259 if (strip->act) make_local_action(strip->act); 00260 if (strip->remap && strip->remap->target) make_local_action(strip->remap->target); 00261 00262 make_local_strips(&strip->strips); 00263 } 00264 } 00265 00266 /* Use local copy instead of linked copy of various ID-blocks */ 00267 void BKE_animdata_make_local(AnimData *adt) 00268 { 00269 NlaTrack *nlt; 00270 00271 /* Actions - Active and Temp */ 00272 if (adt->action) make_local_action(adt->action); 00273 if (adt->tmpact) make_local_action(adt->tmpact); 00274 /* Remaps */ 00275 if (adt->remap && adt->remap->target) make_local_action(adt->remap->target); 00276 00277 /* Drivers */ 00278 // TODO: need to remap the ID-targets too? 00279 00280 /* NLA Data */ 00281 for (nlt=adt->nla_tracks.first; nlt; nlt=nlt->next) 00282 make_local_strips(&nlt->strips); 00283 } 00284 00285 00286 /* When duplicating data (i.e. objects), drivers referring to the original data will 00287 * get updated to point to the duplicated data (if drivers belong to the new data) 00288 */ 00289 void BKE_relink_animdata (AnimData *adt) 00290 { 00291 /* sanity check */ 00292 if (adt == NULL) 00293 return; 00294 00295 /* drivers */ 00296 if (adt->drivers.first) { 00297 FCurve *fcu; 00298 00299 /* check each driver against all the base paths to see if any should go */ 00300 for (fcu= adt->drivers.first; fcu; fcu=fcu->next) { 00301 ChannelDriver *driver= fcu->driver; 00302 DriverVar *dvar; 00303 00304 /* driver variables */ 00305 for (dvar= driver->variables.first; dvar; dvar=dvar->next) { 00306 /* only change the used targets, since the others will need fixing manually anyway */ 00307 DRIVER_TARGETS_USED_LOOPER(dvar) 00308 { 00309 if (dtar->id && dtar->id->newid) { 00310 dtar->id= dtar->id->newid; 00311 } 00312 } 00313 DRIVER_TARGETS_LOOPER_END 00314 } 00315 } 00316 } 00317 } 00318 00319 /* Sub-ID Regrouping ------------------------------------------- */ 00320 00321 /* helper heuristic for determining if a path is compatible with the basepath 00322 * < path: (str) full RNA-path from some data (usually an F-Curve) to compare 00323 * < basepath: (str) shorter path fragment to look for 00324 * > returns (bool) whether there is a match 00325 */ 00326 static short animpath_matches_basepath (const char path[], const char basepath[]) 00327 { 00328 /* we need start of path to be basepath */ 00329 return (path && basepath) && (strstr(path, basepath) == path); 00330 } 00331 00332 /* Move F-Curves in src action to dst action, setting up all the necessary groups 00333 * for this to happen, but only if the F-Curves being moved have the appropriate 00334 * "base path". 00335 * - This is used when data moves from one datablock to another, causing the 00336 * F-Curves to need to be moved over too 00337 */ 00338 void action_move_fcurves_by_basepath (bAction *srcAct, bAction *dstAct, const char basepath[]) 00339 { 00340 FCurve *fcu, *fcn=NULL; 00341 00342 /* sanity checks */ 00343 if ELEM3(NULL, srcAct, dstAct, basepath) { 00344 if (G.f & G_DEBUG) { 00345 printf("ERROR: action_partition_fcurves_by_basepath(%p, %p, %p) has insufficient info to work with\n", 00346 (void *)srcAct, (void *)dstAct, (void *)basepath); 00347 } 00348 return; 00349 } 00350 00351 /* clear 'temp' flags on all groups in src, as we'll be needing them later 00352 * to identify groups that we've managed to empty out here 00353 */ 00354 action_groups_clear_tempflags(srcAct); 00355 00356 /* iterate over all src F-Curves, moving over the ones that need to be moved */ 00357 for (fcu = srcAct->curves.first; fcu; fcu = fcn) { 00358 /* store next pointer in case we move stuff */ 00359 fcn = fcu->next; 00360 00361 /* should F-Curve be moved over? 00362 * - we only need the start of the path to match basepath 00363 */ 00364 if (animpath_matches_basepath(fcu->rna_path, basepath)) { 00365 bActionGroup *agrp = NULL; 00366 00367 /* if grouped... */ 00368 if (fcu->grp) { 00369 /* make sure there will be a matching group on the other side for the migrants */ 00370 agrp = action_groups_find_named(dstAct, fcu->grp->name); 00371 00372 if (agrp == NULL) { 00373 /* add a new one with a similar name (usually will be the same though) */ 00374 agrp = action_groups_add_new(dstAct, fcu->grp->name); 00375 } 00376 00377 /* old groups should be tagged with 'temp' flags so they can be removed later 00378 * if we remove everything from them 00379 */ 00380 fcu->grp->flag |= AGRP_TEMP; 00381 } 00382 00383 /* perform the migration now */ 00384 action_groups_remove_channel(srcAct, fcu); 00385 00386 if (agrp) 00387 action_groups_add_channel(dstAct, agrp, fcu); 00388 else 00389 BLI_addtail(&dstAct->curves, fcu); 00390 } 00391 } 00392 00393 /* cleanup groups (if present) */ 00394 if (srcAct->groups.first) { 00395 bActionGroup *agrp, *grp=NULL; 00396 00397 for (agrp = srcAct->groups.first; agrp; agrp = grp) { 00398 grp = agrp->next; 00399 00400 /* only tagged groups need to be considered - clearing these tags or removing them */ 00401 if (agrp->flag & AGRP_TEMP) { 00402 /* if group is empty and tagged, then we can remove as this operation 00403 * moved out all the channels that were formerly here 00404 */ 00405 if (agrp->channels.first == NULL) 00406 BLI_freelinkN(&srcAct->groups, agrp); 00407 else 00408 agrp->flag &= ~AGRP_TEMP; 00409 } 00410 } 00411 } 00412 } 00413 00414 /* Transfer the animation data from srcID to dstID where the srcID 00415 * animation data is based off "basepath", creating new AnimData and 00416 * associated data as necessary 00417 */ 00418 void BKE_animdata_separate_by_basepath (ID *srcID, ID *dstID, ListBase *basepaths) 00419 { 00420 AnimData *srcAdt=NULL, *dstAdt=NULL; 00421 LinkData *ld; 00422 00423 /* sanity checks */ 00424 if ELEM(NULL, srcID, dstID) { 00425 if (G.f & G_DEBUG) 00426 printf("ERROR: no source or destination ID to separate AnimData with\n"); 00427 return; 00428 } 00429 00430 /* get animdata from src, and create for destination (if needed) */ 00431 srcAdt = BKE_animdata_from_id(srcID); 00432 dstAdt = BKE_id_add_animdata(dstID); 00433 00434 if ELEM(NULL, srcAdt, dstAdt) { 00435 if (G.f & G_DEBUG) 00436 printf("ERROR: no AnimData for this pair of ID's\n"); 00437 return; 00438 } 00439 00440 /* active action */ 00441 if (srcAdt->action) { 00442 /* set up an action if necessary, and name it in a similar way so that it can be easily found again */ 00443 if (dstAdt->action == NULL) { 00444 dstAdt->action = add_empty_action(srcAdt->action->id.name+2); 00445 } 00446 else if (dstAdt->action == srcAdt->action) { 00447 printf("Argh! Source and Destination share animation! ('%s' and '%s' both use '%s') Making new empty action\n", 00448 srcID->name, dstID->name, srcAdt->action->id.name); 00449 00450 // TODO: review this... 00451 id_us_min(&dstAdt->action->id); 00452 dstAdt->action = add_empty_action(dstAdt->action->id.name+2); 00453 } 00454 00455 /* loop over base paths, trying to fix for each one... */ 00456 for (ld = basepaths->first; ld; ld = ld->next) { 00457 const char *basepath = (const char *)ld->data; 00458 action_move_fcurves_by_basepath(srcAdt->action, dstAdt->action, basepath); 00459 } 00460 } 00461 00462 /* drivers */ 00463 if (srcAdt->drivers.first) { 00464 FCurve *fcu, *fcn=NULL; 00465 00466 /* check each driver against all the base paths to see if any should go */ 00467 for (fcu = srcAdt->drivers.first; fcu; fcu = fcn) { 00468 fcn = fcu->next; 00469 00470 /* try each basepath in turn, but stop on the first one which works */ 00471 for (ld = basepaths->first; ld; ld = ld->next) { 00472 const char *basepath = (const char *)ld->data; 00473 00474 if (animpath_matches_basepath(fcu->rna_path, basepath)) { 00475 /* just need to change lists */ 00476 BLI_remlink(&srcAdt->drivers, fcu); 00477 BLI_addtail(&dstAdt->drivers, fcu); 00478 00479 // TODO: add depsgraph flushing calls? 00480 00481 /* can stop now, as moved already */ 00482 break; 00483 } 00484 } 00485 } 00486 } 00487 } 00488 00489 /* Path Validation -------------------------------------------- */ 00490 00491 /* Check if a given RNA Path is valid, by tracing it from the given ID, and seeing if we can resolve it */ 00492 static short check_rna_path_is_valid (ID *owner_id, char *path) 00493 { 00494 PointerRNA id_ptr, ptr; 00495 PropertyRNA *prop=NULL; 00496 00497 /* make initial RNA pointer to start resolving from */ 00498 RNA_id_pointer_create(owner_id, &id_ptr); 00499 00500 /* try to resolve */ 00501 return RNA_path_resolve(&id_ptr, path, &ptr, &prop); 00502 } 00503 00504 /* Check if some given RNA Path needs fixing - free the given path and set a new one as appropriate 00505 * NOTE: we assume that oldName and newName have [" "] padding around them 00506 */ 00507 static char *rna_path_rename_fix (ID *owner_id, const char *prefix, char *oldName, char *newName, char *oldpath, int verify_paths) 00508 { 00509 char *prefixPtr= strstr(oldpath, prefix); 00510 char *oldNamePtr= strstr(oldpath, oldName); 00511 int prefixLen= strlen(prefix); 00512 int oldNameLen= strlen(oldName); 00513 00514 /* only start fixing the path if the prefix and oldName feature in the path, 00515 * and prefix occurs immediately before oldName 00516 */ 00517 if ( (prefixPtr && oldNamePtr) && (prefixPtr+prefixLen == oldNamePtr) ) { 00518 /* if we haven't aren't able to resolve the path now, try again after fixing it */ 00519 if (!verify_paths || check_rna_path_is_valid(owner_id, oldpath) == 0) { 00520 DynStr *ds= BLI_dynstr_new(); 00521 char *postfixPtr= oldNamePtr+oldNameLen; 00522 char *newPath = NULL; 00523 char oldChar; 00524 00525 /* add the part of the string that goes up to the start of the prefix */ 00526 if (prefixPtr > oldpath) { 00527 oldChar= prefixPtr[0]; 00528 prefixPtr[0]= 0; 00529 BLI_dynstr_append(ds, oldpath); 00530 prefixPtr[0]= oldChar; 00531 } 00532 00533 /* add the prefix */ 00534 BLI_dynstr_append(ds, prefix); 00535 00536 /* add the new name (complete with brackets) */ 00537 BLI_dynstr_append(ds, newName); 00538 00539 /* add the postfix */ 00540 BLI_dynstr_append(ds, postfixPtr); 00541 00542 /* create new path, and cleanup old data */ 00543 newPath= BLI_dynstr_get_cstring(ds); 00544 BLI_dynstr_free(ds); 00545 00546 /* check if the new path will solve our problems */ 00547 // TODO: will need to check whether this step really helps in practice 00548 if (!verify_paths || check_rna_path_is_valid(owner_id, newPath)) { 00549 /* free the old path, and return the new one, since we've solved the issues */ 00550 MEM_freeN(oldpath); 00551 return newPath; 00552 } 00553 else { 00554 /* still couldn't resolve the path... so, might as well just leave it alone */ 00555 MEM_freeN(newPath); 00556 } 00557 } 00558 } 00559 00560 /* the old path doesn't need to be changed */ 00561 return oldpath; 00562 } 00563 00564 /* Check RNA-Paths for a list of F-Curves */ 00565 static void fcurves_path_rename_fix (ID *owner_id, const char *prefix, char *oldName, char *newName, ListBase *curves, int verify_paths) 00566 { 00567 FCurve *fcu; 00568 00569 /* we need to check every curve... */ 00570 for (fcu= curves->first; fcu; fcu= fcu->next) { 00571 /* firstly, handle the F-Curve's own path */ 00572 if (fcu->rna_path) 00573 fcu->rna_path= rna_path_rename_fix(owner_id, prefix, oldName, newName, fcu->rna_path, verify_paths); 00574 } 00575 } 00576 00577 /* Check RNA-Paths for a list of Drivers */ 00578 static void drivers_path_rename_fix (ID *owner_id, const char *prefix, char *oldName, char *newName, char *oldKey, char *newKey, ListBase *curves, int verify_paths) 00579 { 00580 FCurve *fcu; 00581 00582 /* we need to check every curve - drivers are F-Curves too! */ 00583 for (fcu= curves->first; fcu; fcu= fcu->next) { 00584 /* firstly, handle the F-Curve's own path */ 00585 if (fcu->rna_path) 00586 fcu->rna_path= rna_path_rename_fix(owner_id, prefix, oldKey, newKey, fcu->rna_path, verify_paths); 00587 00588 /* driver? */ 00589 if (fcu->driver) { 00590 ChannelDriver *driver= fcu->driver; 00591 DriverVar *dvar; 00592 00593 /* driver variables */ 00594 for (dvar= driver->variables.first; dvar; dvar=dvar->next) { 00595 /* only change the used targets, since the others will need fixing manually anyway */ 00596 DRIVER_TARGETS_USED_LOOPER(dvar) 00597 { 00598 /* rename RNA path */ 00599 if (dtar->rna_path && dtar->id) 00600 dtar->rna_path= rna_path_rename_fix(dtar->id, prefix, oldKey, newKey, dtar->rna_path, verify_paths); 00601 00602 /* also fix the bone-name (if applicable) */ 00603 if (strstr(prefix, "bones")) { 00604 if ( ((dtar->id) && (GS(dtar->id->name) == ID_OB)) && 00605 (dtar->pchan_name[0]) && (strcmp(oldName, dtar->pchan_name)==0) ) 00606 { 00607 BLI_strncpy(dtar->pchan_name, newName, sizeof(dtar->pchan_name)); 00608 } 00609 } 00610 } 00611 DRIVER_TARGETS_LOOPER_END 00612 } 00613 } 00614 } 00615 } 00616 00617 /* Fix all RNA-Paths for Actions linked to NLA Strips */ 00618 static void nlastrips_path_rename_fix (ID *owner_id, const char *prefix, char *oldName, char *newName, ListBase *strips, int verify_paths) 00619 { 00620 NlaStrip *strip; 00621 00622 /* recursively check strips, fixing only actions... */ 00623 for (strip= strips->first; strip; strip= strip->next) { 00624 /* fix strip's action */ 00625 if (strip->act) 00626 fcurves_path_rename_fix(owner_id, prefix, oldName, newName, &strip->act->curves, verify_paths); 00627 /* ignore own F-Curves, since those are local... */ 00628 00629 /* check sub-strips (if metas) */ 00630 nlastrips_path_rename_fix(owner_id, prefix, oldName, newName, &strip->strips, verify_paths); 00631 } 00632 } 00633 00634 /* Fix all RNA-Paths in the AnimData block used by the given ID block 00635 * NOTE: it is assumed that the structure we're replacing is <prefix><["><name><"]> 00636 * i.e. pose.bones["Bone"] 00637 */ 00638 void BKE_animdata_fix_paths_rename (ID *owner_id, AnimData *adt, const char *prefix, char *oldName, char *newName, int oldSubscript, int newSubscript, int verify_paths) 00639 { 00640 NlaTrack *nlt; 00641 char *oldN, *newN; 00642 00643 /* if no AnimData, no need to proceed */ 00644 if (ELEM(NULL, owner_id, adt)) 00645 return; 00646 00647 if ((oldName != NULL) && (newName != NULL)) { 00648 /* pad the names with [" "] so that only exact matches are made */ 00649 oldN= BLI_sprintfN("[\"%s\"]", oldName); 00650 newN= BLI_sprintfN("[\"%s\"]", newName); 00651 } 00652 else { 00653 oldN= BLI_sprintfN("[%d]", oldSubscript); 00654 newN= BLI_sprintfN("[%d]", newSubscript); 00655 } 00656 00657 /* Active action and temp action */ 00658 if (adt->action) 00659 fcurves_path_rename_fix(owner_id, prefix, oldN, newN, &adt->action->curves, verify_paths); 00660 if (adt->tmpact) 00661 fcurves_path_rename_fix(owner_id, prefix, oldN, newN, &adt->tmpact->curves, verify_paths); 00662 00663 /* Drivers - Drivers are really F-Curves */ 00664 drivers_path_rename_fix(owner_id, prefix, oldName, newName, oldN, newN, &adt->drivers, verify_paths); 00665 00666 /* NLA Data - Animation Data for Strips */ 00667 for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) 00668 nlastrips_path_rename_fix(owner_id, prefix, oldN, newN, &nlt->strips, verify_paths); 00669 00670 /* free the temp names */ 00671 MEM_freeN(oldN); 00672 MEM_freeN(newN); 00673 } 00674 00675 /* Whole Database Ops -------------------------------------------- */ 00676 00677 /* apply the given callback function on all data in main database */ 00678 void BKE_animdata_main_cb (Main *mainptr, ID_AnimData_Edit_Callback func, void *user_data) 00679 { 00680 ID *id; 00681 00682 /* standard data version */ 00683 #define ANIMDATA_IDS_CB(first) \ 00684 for (id= first; id; id= id->next) { \ 00685 AnimData *adt= BKE_animdata_from_id(id); \ 00686 if (adt) func(id, adt, user_data); \ 00687 } 00688 00689 /* "embedded" nodetree cases (i.e. scene/material/texture->nodetree) */ 00690 #define ANIMDATA_NODETREE_IDS_CB(first, NtId_Type) \ 00691 for (id= first; id; id= id->next) { \ 00692 AnimData *adt= BKE_animdata_from_id(id); \ 00693 NtId_Type *ntp= (NtId_Type *)id; \ 00694 if (ntp->nodetree) { \ 00695 AnimData *adt2= BKE_animdata_from_id((ID *)ntp); \ 00696 if (adt2) func(id, adt2, user_data); \ 00697 } \ 00698 if (adt) func(id, adt, user_data); \ 00699 } 00700 00701 /* nodes */ 00702 ANIMDATA_IDS_CB(mainptr->nodetree.first); 00703 00704 /* textures */ 00705 ANIMDATA_NODETREE_IDS_CB(mainptr->tex.first, Tex); 00706 00707 /* lamps */ 00708 ANIMDATA_IDS_CB(mainptr->lamp.first); 00709 00710 /* materials */ 00711 ANIMDATA_NODETREE_IDS_CB(mainptr->mat.first, Material); 00712 00713 /* cameras */ 00714 ANIMDATA_IDS_CB(mainptr->camera.first); 00715 00716 /* shapekeys */ 00717 ANIMDATA_IDS_CB(mainptr->key.first); 00718 00719 /* metaballs */ 00720 ANIMDATA_IDS_CB(mainptr->mball.first); 00721 00722 /* curves */ 00723 ANIMDATA_IDS_CB(mainptr->curve.first); 00724 00725 /* armatures */ 00726 ANIMDATA_IDS_CB(mainptr->armature.first); 00727 00728 /* lattices */ 00729 ANIMDATA_IDS_CB(mainptr->latt.first); 00730 00731 /* meshes */ 00732 ANIMDATA_IDS_CB(mainptr->mesh.first); 00733 00734 /* particles */ 00735 ANIMDATA_IDS_CB(mainptr->particle.first); 00736 00737 /* objects */ 00738 ANIMDATA_IDS_CB(mainptr->object.first); 00739 00740 /* worlds */ 00741 ANIMDATA_IDS_CB(mainptr->world.first); 00742 00743 /* scenes */ 00744 ANIMDATA_NODETREE_IDS_CB(mainptr->scene.first, Scene); 00745 } 00746 00747 /* Fix all RNA-Paths throughout the database (directly access the Global.main version) 00748 * NOTE: it is assumed that the structure we're replacing is <prefix><["><name><"]> 00749 * i.e. pose.bones["Bone"] 00750 */ 00751 /* TODO: use BKE_animdata_main_cb for looping over all data */ 00752 void BKE_all_animdata_fix_paths_rename (char *prefix, char *oldName, char *newName) 00753 { 00754 Main *mainptr= G.main; 00755 ID *id; 00756 00757 /* macro for less typing 00758 * - whether animdata exists is checked for by the main renaming callback, though taking 00759 * this outside of the function may make things slightly faster? 00760 */ 00761 #define RENAMEFIX_ANIM_IDS(first) \ 00762 for (id= first; id; id= id->next) { \ 00763 AnimData *adt= BKE_animdata_from_id(id); \ 00764 BKE_animdata_fix_paths_rename(id, adt, prefix, oldName, newName, 0, 0, 1);\ 00765 } 00766 00767 /* another version of this macro for nodetrees */ 00768 #define RENAMEFIX_ANIM_NODETREE_IDS(first, NtId_Type) \ 00769 for (id= first; id; id= id->next) { \ 00770 AnimData *adt= BKE_animdata_from_id(id); \ 00771 NtId_Type *ntp= (NtId_Type *)id; \ 00772 if (ntp->nodetree) { \ 00773 AnimData *adt2= BKE_animdata_from_id((ID *)ntp); \ 00774 BKE_animdata_fix_paths_rename((ID *)ntp, adt2, prefix, oldName, newName, 0, 0, 1);\ 00775 } \ 00776 BKE_animdata_fix_paths_rename(id, adt, prefix, oldName, newName, 0, 0, 1);\ 00777 } 00778 00779 /* nodes */ 00780 RENAMEFIX_ANIM_IDS(mainptr->nodetree.first); 00781 00782 /* textures */ 00783 RENAMEFIX_ANIM_NODETREE_IDS(mainptr->tex.first, Tex); 00784 00785 /* lamps */ 00786 RENAMEFIX_ANIM_IDS(mainptr->lamp.first); 00787 00788 /* materials */ 00789 RENAMEFIX_ANIM_NODETREE_IDS(mainptr->mat.first, Material); 00790 00791 /* cameras */ 00792 RENAMEFIX_ANIM_IDS(mainptr->camera.first); 00793 00794 /* shapekeys */ 00795 RENAMEFIX_ANIM_IDS(mainptr->key.first); 00796 00797 /* metaballs */ 00798 RENAMEFIX_ANIM_IDS(mainptr->mball.first); 00799 00800 /* curves */ 00801 RENAMEFIX_ANIM_IDS(mainptr->curve.first); 00802 00803 /* armatures */ 00804 RENAMEFIX_ANIM_IDS(mainptr->armature.first); 00805 00806 /* lattices */ 00807 RENAMEFIX_ANIM_IDS(mainptr->latt.first); 00808 00809 /* meshes */ 00810 RENAMEFIX_ANIM_IDS(mainptr->mesh.first); 00811 00812 /* particles */ 00813 RENAMEFIX_ANIM_IDS(mainptr->particle.first); 00814 00815 /* objects */ 00816 RENAMEFIX_ANIM_IDS(mainptr->object.first); 00817 00818 /* worlds */ 00819 RENAMEFIX_ANIM_IDS(mainptr->world.first); 00820 00821 /* scenes */ 00822 RENAMEFIX_ANIM_NODETREE_IDS(mainptr->scene.first, Scene); 00823 } 00824 00825 /* *********************************** */ 00826 /* KeyingSet API */ 00827 00828 /* Finding Tools --------------------------- */ 00829 00830 /* Find the first path that matches the given criteria */ 00831 // TODO: do we want some method to perform partial matches too? 00832 KS_Path *BKE_keyingset_find_path (KeyingSet *ks, ID *id, const char group_name[], const char rna_path[], int array_index, int UNUSED(group_mode)) 00833 { 00834 KS_Path *ksp; 00835 00836 /* sanity checks */ 00837 if ELEM3(NULL, ks, rna_path, id) 00838 return NULL; 00839 00840 /* loop over paths in the current KeyingSet, finding the first one where all settings match 00841 * (i.e. the first one where none of the checks fail and equal 0) 00842 */ 00843 for (ksp= ks->paths.first; ksp; ksp= ksp->next) { 00844 short eq_id=1, eq_path=1, eq_index=1, eq_group=1; 00845 00846 /* id */ 00847 if (id != ksp->id) 00848 eq_id= 0; 00849 00850 /* path */ 00851 if ((ksp->rna_path==NULL) || strcmp(rna_path, ksp->rna_path)) 00852 eq_path= 0; 00853 00854 /* index - need to compare whole-array setting too... */ 00855 if (ksp->array_index != array_index) 00856 eq_index= 0; 00857 00858 /* group */ 00859 if (group_name) { 00860 // FIXME: these checks need to be coded... for now, it's not too important though 00861 } 00862 00863 /* if all aspects are ok, return */ 00864 if (eq_id && eq_path && eq_index && eq_group) 00865 return ksp; 00866 } 00867 00868 /* none found */ 00869 return NULL; 00870 } 00871 00872 /* Defining Tools --------------------------- */ 00873 00874 /* Used to create a new 'custom' KeyingSet for the user, that will be automatically added to the stack */ 00875 KeyingSet *BKE_keyingset_add (ListBase *list, const char name[], short flag, short keyingflag) 00876 { 00877 KeyingSet *ks; 00878 00879 /* allocate new KeyingSet */ 00880 ks= MEM_callocN(sizeof(KeyingSet), "KeyingSet"); 00881 00882 BLI_strncpy(ks->name, name ? name : "KeyingSet", sizeof(ks->name)); 00883 00884 ks->flag= flag; 00885 ks->keyingflag= keyingflag; 00886 00887 /* add KeyingSet to list */ 00888 BLI_addtail(list, ks); 00889 00890 /* make sure KeyingSet has a unique name (this helps with identification) */ 00891 BLI_uniquename(list, ks, "KeyingSet", '.', offsetof(KeyingSet, name), sizeof(ks->name)); 00892 00893 /* return new KeyingSet for further editing */ 00894 return ks; 00895 } 00896 00897 /* Add a path to a KeyingSet. Nothing is returned for now... 00898 * Checks are performed to ensure that destination is appropriate for the KeyingSet in question 00899 */ 00900 KS_Path *BKE_keyingset_add_path (KeyingSet *ks, ID *id, const char group_name[], const char rna_path[], int array_index, short flag, short groupmode) 00901 { 00902 KS_Path *ksp; 00903 00904 /* sanity checks */ 00905 if ELEM(NULL, ks, rna_path) { 00906 printf("ERROR: no Keying Set and/or RNA Path to add path with \n"); 00907 return NULL; 00908 } 00909 00910 /* ID is required for all types of KeyingSets */ 00911 if (id == NULL) { 00912 printf("ERROR: No ID provided for Keying Set Path. \n"); 00913 return NULL; 00914 } 00915 00916 /* don't add if there is already a matching KS_Path in the KeyingSet */ 00917 if (BKE_keyingset_find_path(ks, id, group_name, rna_path, array_index, groupmode)) { 00918 if (G.f & G_DEBUG) 00919 printf("ERROR: destination already exists in Keying Set \n"); 00920 return NULL; 00921 } 00922 00923 /* allocate a new KeyingSet Path */ 00924 ksp= MEM_callocN(sizeof(KS_Path), "KeyingSet Path"); 00925 00926 /* just store absolute info */ 00927 ksp->id= id; 00928 if (group_name) 00929 BLI_strncpy(ksp->group, group_name, sizeof(ksp->group)); 00930 else 00931 ksp->group[0]= '\0'; 00932 00933 /* store additional info for relative paths (just in case user makes the set relative) */ 00934 if (id) 00935 ksp->idtype= GS(id->name); 00936 00937 /* just copy path info */ 00938 // TODO: should array index be checked too? 00939 ksp->rna_path= BLI_strdupn(rna_path, strlen(rna_path)); 00940 ksp->array_index= array_index; 00941 00942 /* store flags */ 00943 ksp->flag= flag; 00944 ksp->groupmode= groupmode; 00945 00946 /* add KeyingSet path to KeyingSet */ 00947 BLI_addtail(&ks->paths, ksp); 00948 00949 /* return this path */ 00950 return ksp; 00951 } 00952 00953 /* Free the given Keying Set path */ 00954 void BKE_keyingset_free_path (KeyingSet *ks, KS_Path *ksp) 00955 { 00956 /* sanity check */ 00957 if ELEM(NULL, ks, ksp) 00958 return; 00959 00960 /* free RNA-path info */ 00961 if(ksp->rna_path) 00962 MEM_freeN(ksp->rna_path); 00963 00964 /* free path itself */ 00965 BLI_freelinkN(&ks->paths, ksp); 00966 } 00967 00968 /* Copy all KeyingSets in the given list */ 00969 void BKE_keyingsets_copy (ListBase *newlist, ListBase *list) 00970 { 00971 KeyingSet *ksn; 00972 KS_Path *kspn; 00973 00974 BLI_duplicatelist(newlist, list); 00975 00976 for (ksn=newlist->first; ksn; ksn=ksn->next) { 00977 BLI_duplicatelist(&ksn->paths, &ksn->paths); 00978 00979 for (kspn=ksn->paths.first; kspn; kspn=kspn->next) 00980 kspn->rna_path= MEM_dupallocN(kspn->rna_path); 00981 } 00982 } 00983 00984 /* Freeing Tools --------------------------- */ 00985 00986 /* Free data for KeyingSet but not set itself */ 00987 void BKE_keyingset_free (KeyingSet *ks) 00988 { 00989 KS_Path *ksp, *kspn; 00990 00991 /* sanity check */ 00992 if (ks == NULL) 00993 return; 00994 00995 /* free each path as we go to avoid looping twice */ 00996 for (ksp= ks->paths.first; ksp; ksp= kspn) { 00997 kspn= ksp->next; 00998 BKE_keyingset_free_path(ks, ksp); 00999 } 01000 } 01001 01002 /* Free all the KeyingSets in the given list */ 01003 void BKE_keyingsets_free (ListBase *list) 01004 { 01005 KeyingSet *ks, *ksn; 01006 01007 /* sanity check */ 01008 if (list == NULL) 01009 return; 01010 01011 /* loop over KeyingSets freeing them 01012 * - BKE_keyingset_free() doesn't free the set itself, but it frees its sub-data 01013 */ 01014 for (ks= list->first; ks; ks= ksn) { 01015 ksn= ks->next; 01016 BKE_keyingset_free(ks); 01017 BLI_freelinkN(list, ks); 01018 } 01019 } 01020 01021 /* ***************************************** */ 01022 /* Evaluation Data-Setting Backend */ 01023 01024 /* Retrieve string to act as RNA-path, adjusted using mapping-table if provided 01025 * It returns whether the string needs to be freed (i.e. if it was a temp remapped one) 01026 * // FIXME: maybe it would be faster if we didn't have to alloc/free strings like this all the time, but for now it's safer 01027 * 01028 * - remap: remapping table to use 01029 * - path: original path string (as stored in F-Curve data) 01030 * - dst: destination string to write data to 01031 */ 01032 static short animsys_remap_path (AnimMapper *UNUSED(remap), char *path, char **dst) 01033 { 01034 /* is there a valid remapping table to use? */ 01035 //if (remap) { 01036 /* find a matching entry... to use to remap */ 01037 // ...TODO... 01038 //} 01039 01040 /* nothing suitable found, so just set dst to look at path (i.e. no alloc/free needed) */ 01041 *dst= path; 01042 return 0; 01043 } 01044 01045 01046 /* less then 1.0 evaluates to false, use epsilon to avoid float error */ 01047 #define ANIMSYS_FLOAT_AS_BOOL(value) ((value) > ((1.0f-FLT_EPSILON))) 01048 01049 /* Write the given value to a setting using RNA, and return success */ 01050 static short animsys_write_rna_setting (PointerRNA *ptr, char *path, int array_index, float value) 01051 { 01052 PropertyRNA *prop; 01053 PointerRNA new_ptr; 01054 01055 //printf("%p %s %i %f\n", ptr, path, array_index, value); 01056 01057 /* get property to write to */ 01058 if (RNA_path_resolve(ptr, path, &new_ptr, &prop)) 01059 { 01060 /* set value - only for animatable numerical values */ 01061 if (RNA_property_animateable(&new_ptr, prop)) 01062 { 01063 int array_len= RNA_property_array_length(&new_ptr, prop); 01064 01065 if(array_len && array_index >= array_len) 01066 { 01067 if (G.f & G_DEBUG) { 01068 printf("Animato: Invalid array index. ID = '%s', '%s[%d]', array length is %d \n", 01069 (ptr && ptr->id.data) ? (((ID *)ptr->id.data)->name+2) : "<No ID>", 01070 path, array_index, array_len-1); 01071 } 01072 01073 return 0; 01074 } 01075 01076 switch (RNA_property_type(prop)) 01077 { 01078 case PROP_BOOLEAN: 01079 if (array_len) 01080 RNA_property_boolean_set_index(&new_ptr, prop, array_index, ANIMSYS_FLOAT_AS_BOOL(value)); 01081 else 01082 RNA_property_boolean_set(&new_ptr, prop, ANIMSYS_FLOAT_AS_BOOL(value)); 01083 break; 01084 case PROP_INT: 01085 if (array_len) 01086 RNA_property_int_set_index(&new_ptr, prop, array_index, (int)value); 01087 else 01088 RNA_property_int_set(&new_ptr, prop, (int)value); 01089 break; 01090 case PROP_FLOAT: 01091 if (array_len) 01092 RNA_property_float_set_index(&new_ptr, prop, array_index, value); 01093 else 01094 RNA_property_float_set(&new_ptr, prop, value); 01095 break; 01096 case PROP_ENUM: 01097 RNA_property_enum_set(&new_ptr, prop, (int)value); 01098 break; 01099 default: 01100 /* nothing can be done here... so it is unsuccessful? */ 01101 return 0; 01102 } 01103 } 01104 01105 /* successful */ 01106 return 1; 01107 } 01108 else { 01109 /* failed to get path */ 01110 // XXX don't tag as failed yet though, as there are some legit situations (Action Constraint) 01111 // where some channels will not exist, but shouldn't lock up Action 01112 if (G.f & G_DEBUG) { 01113 printf("Animato: Invalid path. ID = '%s', '%s[%d]' \n", 01114 (ptr && ptr->id.data) ? (((ID *)ptr->id.data)->name+2) : "<No ID>", 01115 path, array_index); 01116 } 01117 return 0; 01118 } 01119 } 01120 01121 /* Simple replacement based data-setting of the FCurve using RNA */ 01122 static short animsys_execute_fcurve (PointerRNA *ptr, AnimMapper *remap, FCurve *fcu) 01123 { 01124 char *path = NULL; 01125 short free_path=0; 01126 short ok= 0; 01127 01128 /* get path, remapped as appropriate to work in its new environment */ 01129 free_path= animsys_remap_path(remap, fcu->rna_path, &path); 01130 01131 /* write value to setting */ 01132 if (path) 01133 ok= animsys_write_rna_setting(ptr, path, fcu->array_index, fcu->curval); 01134 01135 /* free temp path-info */ 01136 if (free_path) 01137 MEM_freeN(path); 01138 01139 /* return whether we were successful */ 01140 return ok; 01141 } 01142 01143 /* Evaluate all the F-Curves in the given list 01144 * This performs a set of standard checks. If extra checks are required, separate code should be used 01145 */ 01146 static void animsys_evaluate_fcurves (PointerRNA *ptr, ListBase *list, AnimMapper *remap, float ctime) 01147 { 01148 FCurve *fcu; 01149 01150 /* calculate then execute each curve */ 01151 for (fcu= list->first; fcu; fcu= fcu->next) 01152 { 01153 /* check if this F-Curve doesn't belong to a muted group */ 01154 if ((fcu->grp == NULL) || (fcu->grp->flag & AGRP_MUTED)==0) { 01155 /* check if this curve should be skipped */ 01156 if ((fcu->flag & (FCURVE_MUTED|FCURVE_DISABLED)) == 0) 01157 { 01158 calculate_fcurve(fcu, ctime); 01159 animsys_execute_fcurve(ptr, remap, fcu); 01160 } 01161 } 01162 } 01163 } 01164 01165 /* ***************************************** */ 01166 /* Driver Evaluation */ 01167 01168 /* Evaluate Drivers */ 01169 static void animsys_evaluate_drivers (PointerRNA *ptr, AnimData *adt, float ctime) 01170 { 01171 FCurve *fcu; 01172 01173 /* drivers are stored as F-Curves, but we cannot use the standard code, as we need to check if 01174 * the depsgraph requested that this driver be evaluated... 01175 */ 01176 for (fcu= adt->drivers.first; fcu; fcu= fcu->next) 01177 { 01178 ChannelDriver *driver= fcu->driver; 01179 short ok= 0; 01180 01181 /* check if this driver's curve should be skipped */ 01182 if ((fcu->flag & (FCURVE_MUTED|FCURVE_DISABLED)) == 0) 01183 { 01184 /* check if driver itself is tagged for recalculation */ 01185 if ((driver) && !(driver->flag & DRIVER_FLAG_INVALID)/*&& (driver->flag & DRIVER_FLAG_RECALC)*/) { // XXX driver recalc flag is not set yet by depsgraph! 01186 /* evaluate this using values set already in other places */ 01187 // NOTE: for 'layering' option later on, we should check if we should remove old value before adding new to only be done when drivers only changed 01188 calculate_fcurve(fcu, ctime); 01189 ok= animsys_execute_fcurve(ptr, NULL, fcu); 01190 01191 /* clear recalc flag */ 01192 driver->flag &= ~DRIVER_FLAG_RECALC; 01193 01194 /* set error-flag if evaluation failed */ 01195 if (ok == 0) 01196 driver->flag |= DRIVER_FLAG_INVALID; 01197 } 01198 } 01199 } 01200 } 01201 01202 /* ***************************************** */ 01203 /* Actions Evaluation */ 01204 01205 /* strictly not necessary for actual "evaluation", but it is a useful safety check 01206 * to reduce the amount of times that users end up having to "revive" wrongly-assigned 01207 * actions 01208 */ 01209 static void action_idcode_patch_check (ID *id, bAction *act) 01210 { 01211 int idcode = 0; 01212 01213 /* just in case */ 01214 if (ELEM(NULL, id, act)) 01215 return; 01216 else 01217 idcode = GS(id->name); 01218 01219 /* the actual checks... hopefully not too much of a performance hit in the long run... */ 01220 if (act->idroot == 0) { 01221 /* use the current root if not set already (i.e. newly created actions and actions from 2.50-2.57 builds) 01222 * - this has problems if there are 2 users, and the first one encountered is the invalid one 01223 * in which case, the user will need to manually fix this (?) 01224 */ 01225 act->idroot = idcode; 01226 } 01227 else if (act->idroot != idcode) { 01228 /* only report this error if debug mode is enabled (to save performance everywhere else) */ 01229 if (G.f & G_DEBUG) { 01230 printf("AnimSys Safety Check Failed: Action '%s' is not meant to be used from ID-Blocks of type %d such as '%s'\n", 01231 act->id.name+2, idcode, id->name); 01232 } 01233 } 01234 } 01235 01236 /* ----------------------------------------- */ 01237 01238 /* Evaluate Action Group */ 01239 void animsys_evaluate_action_group (PointerRNA *ptr, bAction *act, bActionGroup *agrp, AnimMapper *remap, float ctime) 01240 { 01241 FCurve *fcu; 01242 01243 /* check if mapper is appropriate for use here (we set to NULL if it's inappropriate) */ 01244 if ELEM(NULL, act, agrp) return; 01245 if ((remap) && (remap->target != act)) remap= NULL; 01246 01247 action_idcode_patch_check(ptr->id.data, act); 01248 01249 /* if group is muted, don't evaluated any of the F-Curve */ 01250 if (agrp->flag & AGRP_MUTED) 01251 return; 01252 01253 /* calculate then execute each curve */ 01254 for (fcu= agrp->channels.first; (fcu) && (fcu->grp == agrp); fcu= fcu->next) 01255 { 01256 /* check if this curve should be skipped */ 01257 if ((fcu->flag & (FCURVE_MUTED|FCURVE_DISABLED)) == 0) 01258 { 01259 calculate_fcurve(fcu, ctime); 01260 animsys_execute_fcurve(ptr, remap, fcu); 01261 } 01262 } 01263 } 01264 01265 /* Evaluate Action (F-Curve Bag) */ 01266 void animsys_evaluate_action (PointerRNA *ptr, bAction *act, AnimMapper *remap, float ctime) 01267 { 01268 /* check if mapper is appropriate for use here (we set to NULL if it's inappropriate) */ 01269 if (act == NULL) return; 01270 if ((remap) && (remap->target != act)) remap= NULL; 01271 01272 action_idcode_patch_check(ptr->id.data, act); 01273 01274 /* calculate then execute each curve */ 01275 animsys_evaluate_fcurves(ptr, &act->curves, remap, ctime); 01276 } 01277 01278 /* ***************************************** */ 01279 /* NLA System - Evaluation */ 01280 01281 /* calculate influence of strip based for given frame based on blendin/out values */ 01282 static float nlastrip_get_influence (NlaStrip *strip, float cframe) 01283 { 01284 /* sanity checks - normalise the blendin/out values? */ 01285 strip->blendin= (float)fabs(strip->blendin); 01286 strip->blendout= (float)fabs(strip->blendout); 01287 01288 /* result depends on where frame is in respect to blendin/out values */ 01289 if (IS_EQ(strip->blendin, 0)==0 && (cframe <= (strip->start + strip->blendin))) { 01290 /* there is some blend-in */ 01291 return (float)fabs(cframe - strip->start) / (strip->blendin); 01292 } 01293 else if (IS_EQ(strip->blendout, 0)==0 && (cframe >= (strip->end - strip->blendout))) { 01294 /* there is some blend-out */ 01295 return (float)fabs(strip->end - cframe) / (strip->blendout); 01296 } 01297 else { 01298 /* in the middle of the strip, we should be full strength */ 01299 return 1.0f; 01300 } 01301 } 01302 01303 /* evaluate the evaluation time and influence for the strip, storing the results in the strip */ 01304 static void nlastrip_evaluate_controls (NlaStrip *strip, float ctime) 01305 { 01306 /* firstly, analytically generate values for influence and time (if applicable) */ 01307 if ((strip->flag & NLASTRIP_FLAG_USR_TIME) == 0) 01308 strip->strip_time= nlastrip_get_frame(strip, ctime, NLATIME_CONVERT_EVAL); 01309 if ((strip->flag & NLASTRIP_FLAG_USR_INFLUENCE) == 0) 01310 strip->influence= nlastrip_get_influence(strip, ctime); 01311 01312 /* now strip's evaluate F-Curves for these settings (if applicable) */ 01313 if (strip->fcurves.first) { 01314 PointerRNA strip_ptr; 01315 01316 /* create RNA-pointer needed to set values */ 01317 RNA_pointer_create(NULL, &RNA_NlaStrip, strip, &strip_ptr); 01318 01319 /* execute these settings as per normal */ 01320 animsys_evaluate_fcurves(&strip_ptr, &strip->fcurves, NULL, ctime); 01321 } 01322 01323 /* if user can control the evaluation time (using F-Curves), consider the option which allows this time to be clamped 01324 * to lie within extents of the action-clip, so that a steady changing rate of progress through several cycles of the clip 01325 * can be achieved easily 01326 */ 01327 // NOTE: if we add any more of these special cases, we better group them up nicely... 01328 if ((strip->flag & NLASTRIP_FLAG_USR_TIME) && (strip->flag & NLASTRIP_FLAG_USR_TIME_CYCLIC)) 01329 strip->strip_time= fmod(strip->strip_time - strip->actstart, strip->actend - strip->actstart); 01330 } 01331 01332 /* gets the strip active at the current time for a list of strips for evaluation purposes */ 01333 NlaEvalStrip *nlastrips_ctime_get_strip (ListBase *list, ListBase *strips, short index, float ctime) 01334 { 01335 NlaStrip *strip, *estrip=NULL; 01336 NlaEvalStrip *nes; 01337 short side= 0; 01338 01339 /* loop over strips, checking if they fall within the range */ 01340 for (strip= strips->first; strip; strip= strip->next) { 01341 /* check if current time occurs within this strip */ 01342 if (IN_RANGE_INCL(ctime, strip->start, strip->end)) { 01343 /* this strip is active, so try to use it */ 01344 estrip= strip; 01345 side= NES_TIME_WITHIN; 01346 break; 01347 } 01348 01349 /* if time occurred before current strip... */ 01350 if (ctime < strip->start) { 01351 if (strip == strips->first) { 01352 /* before first strip - only try to use it if it extends backwards in time too */ 01353 if (strip->extendmode == NLASTRIP_EXTEND_HOLD) 01354 estrip= strip; 01355 01356 /* side is 'before' regardless of whether there's a useful strip */ 01357 side= NES_TIME_BEFORE; 01358 } 01359 else { 01360 /* before next strip - previous strip has ended, but next hasn't begun, 01361 * so blending mode depends on whether strip is being held or not... 01362 * - only occurs when no transition strip added, otherwise the transition would have 01363 * been picked up above... 01364 */ 01365 strip= strip->prev; 01366 01367 if (strip->extendmode != NLASTRIP_EXTEND_NOTHING) 01368 estrip= strip; 01369 side= NES_TIME_AFTER; 01370 } 01371 break; 01372 } 01373 01374 /* if time occurred after current strip... */ 01375 if (ctime > strip->end) { 01376 /* only if this is the last strip should we do anything, and only if that is being held */ 01377 if (strip == strips->last) { 01378 if (strip->extendmode != NLASTRIP_EXTEND_NOTHING) 01379 estrip= strip; 01380 01381 side= NES_TIME_AFTER; 01382 break; 01383 } 01384 01385 /* otherwise, skip... as the 'before' case will catch it more elegantly! */ 01386 } 01387 } 01388 01389 /* check if a valid strip was found 01390 * - must not be muted (i.e. will have contribution 01391 */ 01392 if ((estrip == NULL) || (estrip->flag & NLASTRIP_FLAG_MUTED)) 01393 return NULL; 01394 01395 /* if ctime was not within the boundaries of the strip, clamp! */ 01396 switch (side) { 01397 case NES_TIME_BEFORE: /* extend first frame only */ 01398 ctime= estrip->start; 01399 break; 01400 case NES_TIME_AFTER: /* extend last frame only */ 01401 ctime= estrip->end; 01402 break; 01403 } 01404 01405 /* evaluate strip's evaluation controls 01406 * - skip if no influence (i.e. same effect as muting the strip) 01407 * - negative influence is not supported yet... how would that be defined? 01408 */ 01409 // TODO: this sounds a bit hacky having a few isolated F-Curves stuck on some data it operates on... 01410 nlastrip_evaluate_controls(estrip, ctime); 01411 if (estrip->influence <= 0.0f) 01412 return NULL; 01413 01414 /* check if strip has valid data to evaluate, 01415 * and/or perform any additional type-specific actions 01416 */ 01417 switch (estrip->type) { 01418 case NLASTRIP_TYPE_CLIP: 01419 /* clip must have some action to evaluate */ 01420 if (estrip->act == NULL) 01421 return NULL; 01422 break; 01423 case NLASTRIP_TYPE_TRANSITION: 01424 /* there must be strips to transition from and to (i.e. prev and next required) */ 01425 if (ELEM(NULL, estrip->prev, estrip->next)) 01426 return NULL; 01427 01428 /* evaluate controls for the relevant extents of the bordering strips... */ 01429 nlastrip_evaluate_controls(estrip->prev, estrip->start); 01430 nlastrip_evaluate_controls(estrip->next, estrip->end); 01431 break; 01432 } 01433 01434 /* add to list of strips we need to evaluate */ 01435 nes= MEM_callocN(sizeof(NlaEvalStrip), "NlaEvalStrip"); 01436 01437 nes->strip= estrip; 01438 nes->strip_mode= side; 01439 nes->track_index= index; 01440 nes->strip_time= estrip->strip_time; 01441 01442 if (list) 01443 BLI_addtail(list, nes); 01444 01445 return nes; 01446 } 01447 01448 /* ---------------------- */ 01449 01450 /* find an NlaEvalChannel that matches the given criteria 01451 * - ptr and prop are the RNA data to find a match for 01452 */ 01453 static NlaEvalChannel *nlaevalchan_find_match (ListBase *channels, PointerRNA *ptr, PropertyRNA *prop, int array_index) 01454 { 01455 NlaEvalChannel *nec; 01456 01457 /* sanity check */ 01458 if (channels == NULL) 01459 return NULL; 01460 01461 /* loop through existing channels, checking for a channel which affects the same property */ 01462 for (nec= channels->first; nec; nec= nec->next) { 01463 /* - comparing the PointerRNA's is done by comparing the pointers 01464 * to the actual struct the property resides in, since that all the 01465 * other data stored in PointerRNA cannot allow us to definitively 01466 * identify the data 01467 */ 01468 if ((nec->ptr.data == ptr->data) && (nec->prop == prop) && (nec->index == array_index)) 01469 return nec; 01470 } 01471 01472 /* not found */ 01473 return NULL; 01474 } 01475 01476 /* verify that an appropriate NlaEvalChannel for this F-Curve exists */ 01477 static NlaEvalChannel *nlaevalchan_verify (PointerRNA *ptr, ListBase *channels, NlaEvalStrip *nes, FCurve *fcu, short *newChan) 01478 { 01479 NlaEvalChannel *nec; 01480 NlaStrip *strip= nes->strip; 01481 PropertyRNA *prop; 01482 PointerRNA new_ptr; 01483 char *path = NULL; 01484 short free_path=0; 01485 01486 /* sanity checks */ 01487 if (channels == NULL) 01488 return NULL; 01489 01490 /* get RNA pointer+property info from F-Curve for more convenient handling */ 01491 /* get path, remapped as appropriate to work in its new environment */ 01492 free_path= animsys_remap_path(strip->remap, fcu->rna_path, &path); 01493 01494 /* a valid property must be available, and it must be animateable */ 01495 if (RNA_path_resolve(ptr, path, &new_ptr, &prop) == 0) { 01496 if (G.f & G_DEBUG) printf("NLA Strip Eval: Cannot resolve path \n"); 01497 return NULL; 01498 } 01499 /* only ok if animateable */ 01500 else if (RNA_property_animateable(&new_ptr, prop) == 0) { 01501 if (G.f & G_DEBUG) printf("NLA Strip Eval: Property not animateable \n"); 01502 return NULL; 01503 } 01504 01505 /* try to find a match */ 01506 nec= nlaevalchan_find_match(channels, &new_ptr, prop, fcu->array_index); 01507 01508 /* allocate a new struct for this if none found */ 01509 if (nec == NULL) { 01510 nec= MEM_callocN(sizeof(NlaEvalChannel), "NlaEvalChannel"); 01511 *newChan= 1; 01512 BLI_addtail(channels, nec); 01513 01514 nec->ptr= new_ptr; 01515 nec->prop= prop; 01516 nec->index= fcu->array_index; 01517 } 01518 else 01519 *newChan= 0; 01520 01521 /* we can now return */ 01522 return nec; 01523 } 01524 01525 /* accumulate (i.e. blend) the given value on to the channel it affects */ 01526 static void nlaevalchan_accumulate (NlaEvalChannel *nec, NlaEvalStrip *nes, short newChan, float value) 01527 { 01528 NlaStrip *strip= nes->strip; 01529 short blendmode= strip->blendmode; 01530 float inf= strip->influence; 01531 01532 /* if channel is new, just store value regardless of blending factors, etc. */ 01533 if (newChan) { 01534 nec->value= value; 01535 return; 01536 } 01537 01538 /* if this is being performed as part of transition evaluation, incorporate 01539 * an additional weighting factor for the influence 01540 */ 01541 if (nes->strip_mode == NES_TIME_TRANSITION_END) 01542 inf *= nes->strip_time; 01543 01544 /* premultiply the value by the weighting factor */ 01545 if (IS_EQ(inf, 0)) return; 01546 value *= inf; 01547 01548 /* perform blending */ 01549 switch (blendmode) { 01550 case NLASTRIP_MODE_ADD: 01551 /* simply add the scaled value on to the stack */ 01552 nec->value += value; 01553 break; 01554 01555 case NLASTRIP_MODE_SUBTRACT: 01556 /* simply subtract the scaled value from the stack */ 01557 nec->value -= value; 01558 break; 01559 01560 case NLASTRIP_MODE_MULTIPLY: 01561 /* multiply the scaled value with the stack */ 01562 nec->value *= value; 01563 break; 01564 01565 case NLASTRIP_MODE_REPLACE: 01566 default: // TODO: do we really want to blend by default? it seems more uses might prefer add... 01567 /* do linear interpolation 01568 * - the influence of the accumulated data (elsewhere, that is called dstweight) 01569 * is 1 - influence, since the strip's influence is srcweight 01570 */ 01571 nec->value= nec->value * (1.0f - inf) + value; 01572 break; 01573 } 01574 } 01575 01576 /* accumulate the results of a temporary buffer with the results of the full-buffer */ 01577 static void nlaevalchan_buffers_accumulate (ListBase *channels, ListBase *tmp_buffer, NlaEvalStrip *nes) 01578 { 01579 NlaEvalChannel *nec, *necn, *necd; 01580 01581 /* optimise - abort if no channels */ 01582 if (tmp_buffer->first == NULL) 01583 return; 01584 01585 /* accumulate results in tmp_channels buffer to the accumulation buffer */ 01586 for (nec= tmp_buffer->first; nec; nec= necn) { 01587 /* get pointer to next channel in case we remove the current channel from the temp-buffer */ 01588 necn= nec->next; 01589 01590 /* try to find an existing matching channel for this setting in the accumulation buffer */ 01591 necd= nlaevalchan_find_match(channels, &nec->ptr, nec->prop, nec->index); 01592 01593 /* if there was a matching channel already in the buffer, accumulate to it, 01594 * otherwise, add the current channel to the buffer for efficiency 01595 */ 01596 if (necd) 01597 nlaevalchan_accumulate(necd, nes, 0, nec->value); 01598 else { 01599 BLI_remlink(tmp_buffer, nec); 01600 BLI_addtail(channels, nec); 01601 } 01602 } 01603 01604 /* free temp-channels that haven't been assimilated into the buffer */ 01605 BLI_freelistN(tmp_buffer); 01606 } 01607 01608 /* ---------------------- */ 01609 /* F-Modifier stack joining/separation utilities - should we generalise these for BLI_listbase.h interface? */ 01610 01611 /* Temporarily join two lists of modifiers together, storing the result in a third list */ 01612 static void nlaeval_fmodifiers_join_stacks (ListBase *result, ListBase *list1, ListBase *list2) 01613 { 01614 FModifier *fcm1, *fcm2; 01615 01616 /* if list1 is invalid... */ 01617 if ELEM(NULL, list1, list1->first) { 01618 if (list2 && list2->first) { 01619 result->first= list2->first; 01620 result->last= list2->last; 01621 } 01622 } 01623 /* if list 2 is invalid... */ 01624 else if ELEM(NULL, list2, list2->first) { 01625 result->first= list1->first; 01626 result->last= list1->last; 01627 } 01628 else { 01629 /* list1 should be added first, and list2 second, with the endpoints of these being the endpoints for result 01630 * - the original lists must be left unchanged though, as we need that fact for restoring 01631 */ 01632 result->first= list1->first; 01633 result->last= list2->last; 01634 01635 fcm1= list1->last; 01636 fcm2= list2->first; 01637 01638 fcm1->next= fcm2; 01639 fcm2->prev= fcm1; 01640 } 01641 } 01642 01643 /* Split two temporary lists of modifiers */ 01644 static void nlaeval_fmodifiers_split_stacks (ListBase *list1, ListBase *list2) 01645 { 01646 FModifier *fcm1, *fcm2; 01647 01648 /* if list1/2 is invalid... just skip */ 01649 if ELEM(NULL, list1, list2) 01650 return; 01651 if ELEM(NULL, list1->first, list2->first) 01652 return; 01653 01654 /* get endpoints */ 01655 fcm1= list1->last; 01656 fcm2= list2->first; 01657 01658 /* clear their links */ 01659 fcm1->next= NULL; 01660 fcm2->prev= NULL; 01661 } 01662 01663 /* ---------------------- */ 01664 01665 /* evaluate action-clip strip */ 01666 static void nlastrip_evaluate_actionclip (PointerRNA *ptr, ListBase *channels, ListBase *modifiers, NlaEvalStrip *nes) 01667 { 01668 ListBase tmp_modifiers = {NULL, NULL}; 01669 NlaStrip *strip= nes->strip; 01670 FCurve *fcu; 01671 float evaltime; 01672 01673 /* sanity checks for action */ 01674 if (strip == NULL) 01675 return; 01676 01677 if (strip->act == NULL) { 01678 printf("NLA-Strip Eval Error: Strip '%s' has no Action\n", strip->name); 01679 return; 01680 } 01681 01682 action_idcode_patch_check(ptr->id.data, strip->act); 01683 01684 /* join this strip's modifiers to the parent's modifiers (own modifiers first) */ 01685 nlaeval_fmodifiers_join_stacks(&tmp_modifiers, &strip->modifiers, modifiers); 01686 01687 /* evaluate strip's modifiers which modify time to evaluate the base curves at */ 01688 evaltime= evaluate_time_fmodifiers(&tmp_modifiers, NULL, 0.0f, strip->strip_time); 01689 01690 /* evaluate all the F-Curves in the action, saving the relevant pointers to data that will need to be used */ 01691 for (fcu= strip->act->curves.first; fcu; fcu= fcu->next) { 01692 NlaEvalChannel *nec; 01693 float value = 0.0f; 01694 short newChan = -1; 01695 01696 /* check if this curve should be skipped */ 01697 if (fcu->flag & (FCURVE_MUTED|FCURVE_DISABLED)) 01698 continue; 01699 if ((fcu->grp) && (fcu->grp->flag & AGRP_MUTED)) 01700 continue; 01701 01702 /* evaluate the F-Curve's value for the time given in the strip 01703 * NOTE: we use the modified time here, since strip's F-Curve Modifiers are applied on top of this 01704 */ 01705 value= evaluate_fcurve(fcu, evaltime); 01706 01707 /* apply strip's F-Curve Modifiers on this value 01708 * NOTE: we apply the strip's original evaluation time not the modified one (as per standard F-Curve eval) 01709 */ 01710 evaluate_value_fmodifiers(&tmp_modifiers, fcu, &value, strip->strip_time); 01711 01712 01713 /* get an NLA evaluation channel to work with, and accumulate the evaluated value with the value(s) 01714 * stored in this channel if it has been used already 01715 */ 01716 nec= nlaevalchan_verify(ptr, channels, nes, fcu, &newChan); 01717 if (nec) 01718 nlaevalchan_accumulate(nec, nes, newChan, value); 01719 } 01720 01721 /* unlink this strip's modifiers from the parent's modifiers again */ 01722 nlaeval_fmodifiers_split_stacks(&strip->modifiers, modifiers); 01723 } 01724 01725 /* evaluate transition strip */ 01726 static void nlastrip_evaluate_transition (PointerRNA *ptr, ListBase *channels, ListBase *modifiers, NlaEvalStrip *nes) 01727 { 01728 ListBase tmp_channels = {NULL, NULL}; 01729 ListBase tmp_modifiers = {NULL, NULL}; 01730 NlaEvalStrip tmp_nes; 01731 NlaStrip *s1, *s2; 01732 01733 /* join this strip's modifiers to the parent's modifiers (own modifiers first) */ 01734 nlaeval_fmodifiers_join_stacks(&tmp_modifiers, &nes->strip->modifiers, modifiers); 01735 01736 /* get the two strips to operate on 01737 * - we use the endpoints of the strips directly flanking our strip 01738 * using these as the endpoints of the transition (destination and source) 01739 * - these should have already been determined to be valid... 01740 * - if this strip is being played in reverse, we need to swap these endpoints 01741 * otherwise they will be interpolated wrong 01742 */ 01743 if (nes->strip->flag & NLASTRIP_FLAG_REVERSE) { 01744 s1= nes->strip->next; 01745 s2= nes->strip->prev; 01746 } 01747 else { 01748 s1= nes->strip->prev; 01749 s2= nes->strip->next; 01750 } 01751 01752 /* prepare template for 'evaluation strip' 01753 * - based on the transition strip's evaluation strip data 01754 * - strip_mode is NES_TIME_TRANSITION_* based on which endpoint 01755 * - strip_time is the 'normalised' (i.e. in-strip) time for evaluation, 01756 * which doubles up as an additional weighting factor for the strip influences 01757 * which allows us to appear to be 'interpolating' between the two extremes 01758 */ 01759 tmp_nes= *nes; 01760 01761 /* evaluate these strips into a temp-buffer (tmp_channels) */ 01762 // FIXME: modifier evalation here needs some work... 01763 /* first strip */ 01764 tmp_nes.strip_mode= NES_TIME_TRANSITION_START; 01765 tmp_nes.strip= s1; 01766 nlastrip_evaluate(ptr, &tmp_channels, &tmp_modifiers, &tmp_nes); 01767 01768 /* second strip */ 01769 tmp_nes.strip_mode= NES_TIME_TRANSITION_END; 01770 tmp_nes.strip= s2; 01771 nlastrip_evaluate(ptr, &tmp_channels, &tmp_modifiers, &tmp_nes); 01772 01773 01774 /* assumulate temp-buffer and full-buffer, using the 'real' strip */ 01775 nlaevalchan_buffers_accumulate(channels, &tmp_channels, nes); 01776 01777 /* unlink this strip's modifiers from the parent's modifiers again */ 01778 nlaeval_fmodifiers_split_stacks(&nes->strip->modifiers, modifiers); 01779 } 01780 01781 /* evaluate meta-strip */ 01782 static void nlastrip_evaluate_meta (PointerRNA *ptr, ListBase *channels, ListBase *modifiers, NlaEvalStrip *nes) 01783 { 01784 ListBase tmp_channels = {NULL, NULL}; 01785 ListBase tmp_modifiers = {NULL, NULL}; 01786 NlaStrip *strip= nes->strip; 01787 NlaEvalStrip *tmp_nes; 01788 float evaltime; 01789 01790 /* meta-strip was calculated normally to have some time to be evaluated at 01791 * and here we 'look inside' the meta strip, treating it as a decorated window to 01792 * it's child strips, which get evaluated as if they were some tracks on a strip 01793 * (but with some extra modifiers to apply). 01794 * 01795 * NOTE: keep this in sync with animsys_evaluate_nla() 01796 */ 01797 01798 /* join this strip's modifiers to the parent's modifiers (own modifiers first) */ 01799 nlaeval_fmodifiers_join_stacks(&tmp_modifiers, &strip->modifiers, modifiers); 01800 01801 /* find the child-strip to evaluate */ 01802 evaltime= (nes->strip_time * (strip->end - strip->start)) + strip->start; 01803 tmp_nes= nlastrips_ctime_get_strip(NULL, &strip->strips, -1, evaltime); 01804 if (tmp_nes == NULL) 01805 return; 01806 01807 /* evaluate child-strip into tmp_channels buffer before accumulating 01808 * in the accumulation buffer 01809 */ 01810 nlastrip_evaluate(ptr, &tmp_channels, &tmp_modifiers, tmp_nes); 01811 01812 /* assumulate temp-buffer and full-buffer, using the 'real' strip */ 01813 nlaevalchan_buffers_accumulate(channels, &tmp_channels, nes); 01814 01815 /* free temp eval-strip */ 01816 MEM_freeN(tmp_nes); 01817 01818 /* unlink this strip's modifiers from the parent's modifiers again */ 01819 nlaeval_fmodifiers_split_stacks(&strip->modifiers, modifiers); 01820 } 01821 01822 /* evaluates the given evaluation strip */ 01823 void nlastrip_evaluate (PointerRNA *ptr, ListBase *channels, ListBase *modifiers, NlaEvalStrip *nes) 01824 { 01825 NlaStrip *strip= nes->strip; 01826 01827 /* to prevent potential infinite recursion problems (i.e. transition strip, beside meta strip containing a transition 01828 * several levels deep inside it), we tag the current strip as being evaluated, and clear this when we leave 01829 */ 01830 // TODO: be careful with this flag, since some edit tools may be running and have set this while animplayback was running 01831 if (strip->flag & NLASTRIP_FLAG_EDIT_TOUCHED) 01832 return; 01833 strip->flag |= NLASTRIP_FLAG_EDIT_TOUCHED; 01834 01835 /* actions to take depend on the type of strip */ 01836 switch (strip->type) { 01837 case NLASTRIP_TYPE_CLIP: /* action-clip */ 01838 nlastrip_evaluate_actionclip(ptr, channels, modifiers, nes); 01839 break; 01840 case NLASTRIP_TYPE_TRANSITION: /* transition */ 01841 nlastrip_evaluate_transition(ptr, channels, modifiers, nes); 01842 break; 01843 case NLASTRIP_TYPE_META: /* meta */ 01844 nlastrip_evaluate_meta(ptr, channels, modifiers, nes); 01845 break; 01846 } 01847 01848 /* clear temp recursion safe-check */ 01849 strip->flag &= ~NLASTRIP_FLAG_EDIT_TOUCHED; 01850 } 01851 01852 /* write the accumulated settings to */ 01853 void nladata_flush_channels (ListBase *channels) 01854 { 01855 NlaEvalChannel *nec; 01856 01857 /* sanity checks */ 01858 if (channels == NULL) 01859 return; 01860 01861 /* for each channel with accumulated values, write its value on the property it affects */ 01862 for (nec= channels->first; nec; nec= nec->next) { 01863 PointerRNA *ptr= &nec->ptr; 01864 PropertyRNA *prop= nec->prop; 01865 int array_index= nec->index; 01866 float value= nec->value; 01867 01868 /* write values - see animsys_write_rna_setting() to sync the code */ 01869 switch (RNA_property_type(prop)) 01870 { 01871 case PROP_BOOLEAN: 01872 if (RNA_property_array_length(ptr, prop)) 01873 RNA_property_boolean_set_index(ptr, prop, array_index, ANIMSYS_FLOAT_AS_BOOL(value)); 01874 else 01875 RNA_property_boolean_set(ptr, prop, ANIMSYS_FLOAT_AS_BOOL(value)); 01876 break; 01877 case PROP_INT: 01878 if (RNA_property_array_length(ptr, prop)) 01879 RNA_property_int_set_index(ptr, prop, array_index, (int)value); 01880 else 01881 RNA_property_int_set(ptr, prop, (int)value); 01882 break; 01883 case PROP_FLOAT: 01884 if (RNA_property_array_length(ptr, prop)) 01885 RNA_property_float_set_index(ptr, prop, array_index, value); 01886 else 01887 RNA_property_float_set(ptr, prop, value); 01888 break; 01889 case PROP_ENUM: 01890 RNA_property_enum_set(ptr, prop, (int)value); 01891 break; 01892 default: 01893 // can't do anything with other types of property.... 01894 break; 01895 } 01896 } 01897 } 01898 01899 /* ---------------------- */ 01900 01901 /* NLA Evaluation function - values are calculated and stored in temporary "NlaEvalChannels" 01902 * ! This is exported so that keyframing code can use this for make use of it for anim layers support 01903 * > echannels: (list<NlaEvalChannels>) evaluation channels with calculated values 01904 */ 01905 static void animsys_evaluate_nla (ListBase *echannels, PointerRNA *ptr, AnimData *adt, float ctime) 01906 { 01907 NlaTrack *nlt; 01908 short track_index=0; 01909 short has_strips = 0; 01910 01911 ListBase estrips= {NULL, NULL}; 01912 NlaEvalStrip *nes; 01913 01914 /* 1. get the stack of strips to evaluate at current time (influence calculated here) */ 01915 for (nlt=adt->nla_tracks.first; nlt; nlt=nlt->next, track_index++) { 01916 /* stop here if tweaking is on and this strip is the tweaking track (it will be the first one that's 'disabled')... */ 01917 if ((adt->flag & ADT_NLA_EDIT_ON) && (nlt->flag & NLATRACK_DISABLED)) 01918 break; 01919 01920 /* skip if we're only considering a track tagged 'solo' */ 01921 if ((adt->flag & ADT_NLA_SOLO_TRACK) && (nlt->flag & NLATRACK_SOLO)==0) 01922 continue; 01923 /* skip if track is muted */ 01924 if (nlt->flag & NLATRACK_MUTED) 01925 continue; 01926 01927 /* if this track has strips (but maybe they won't be suitable), set has_strips 01928 * - used for mainly for still allowing normal action evaluation... 01929 */ 01930 if (nlt->strips.first) 01931 has_strips= 1; 01932 01933 /* otherwise, get strip to evaluate for this channel */ 01934 nes= nlastrips_ctime_get_strip(&estrips, &nlt->strips, track_index, ctime); 01935 if (nes) nes->track= nlt; 01936 } 01937 01938 /* add 'active' Action (may be tweaking track) as last strip to evaluate in NLA stack 01939 * - only do this if we're not exclusively evaluating the 'solo' NLA-track 01940 */ 01941 if ((adt->action) && !(adt->flag & ADT_NLA_SOLO_TRACK)) { 01942 /* if there are strips, evaluate action as per NLA rules */ 01943 if ((has_strips) || (adt->actstrip)) { 01944 /* make dummy NLA strip, and add that to the stack */ 01945 NlaStrip dummy_strip= {NULL}; 01946 ListBase dummy_trackslist; 01947 01948 dummy_trackslist.first= dummy_trackslist.last= &dummy_strip; 01949 01950 if ((nlt) && !(adt->flag & ADT_NLA_EDIT_NOMAP)) { 01951 /* edit active action in-place according to its active strip, so copy the data */ 01952 memcpy(&dummy_strip, adt->actstrip, sizeof(NlaStrip)); 01953 dummy_strip.next = dummy_strip.prev = NULL; 01954 } 01955 else { 01956 /* set settings of dummy NLA strip from AnimData settings */ 01957 dummy_strip.act= adt->action; 01958 dummy_strip.remap= adt->remap; 01959 01960 /* action range is calculated taking F-Modifiers into account (which making new strips doesn't do due to the troublesome nature of that) */ 01961 calc_action_range(dummy_strip.act, &dummy_strip.actstart, &dummy_strip.actend, 1); 01962 dummy_strip.start = dummy_strip.actstart; 01963 dummy_strip.end = (IS_EQF(dummy_strip.actstart, dummy_strip.actend)) ? (dummy_strip.actstart + 1.0f): (dummy_strip.actend); 01964 01965 dummy_strip.blendmode= adt->act_blendmode; 01966 dummy_strip.extendmode= adt->act_extendmode; 01967 dummy_strip.influence= adt->act_influence; 01968 } 01969 01970 /* add this to our list of evaluation strips */ 01971 nlastrips_ctime_get_strip(&estrips, &dummy_trackslist, -1, ctime); 01972 } 01973 else { 01974 /* special case - evaluate as if there isn't any NLA data */ 01975 // TODO: this is really just a stop-gap measure... 01976 animsys_evaluate_action(ptr, adt->action, adt->remap, ctime); 01977 return; 01978 } 01979 } 01980 01981 /* only continue if there are strips to evaluate */ 01982 if (estrips.first == NULL) 01983 return; 01984 01985 01986 /* 2. for each strip, evaluate then accumulate on top of existing channels, but don't set values yet */ 01987 for (nes= estrips.first; nes; nes= nes->next) 01988 nlastrip_evaluate(ptr, echannels, NULL, nes); 01989 01990 /* 3. free temporary evaluation data that's not used elsewhere */ 01991 BLI_freelistN(&estrips); 01992 } 01993 01994 /* NLA Evaluation function (mostly for use through do_animdata) 01995 * - All channels that will be affected are not cleared anymore. Instead, we just evaluate into 01996 * some temp channels, where values can be accumulated in one go. 01997 */ 01998 static void animsys_calculate_nla (PointerRNA *ptr, AnimData *adt, float ctime) 01999 { 02000 ListBase echannels= {NULL, NULL}; 02001 02002 // TODO: need to zero out all channels used, otherwise we have problems with threadsafety 02003 // and also when the user jumps between different times instead of moving sequentially... 02004 02005 /* evaluate the NLA stack, obtaining a set of values to flush */ 02006 animsys_evaluate_nla(&echannels, ptr, adt, ctime); 02007 02008 /* flush effects of accumulating channels in NLA to the actual data they affect */ 02009 nladata_flush_channels(&echannels); 02010 02011 /* free temp data */ 02012 BLI_freelistN(&echannels); 02013 } 02014 02015 /* ***************************************** */ 02016 /* Overrides System - Public API */ 02017 02018 /* Clear all overides */ 02019 02020 /* Add or get existing Override for given setting */ 02021 #if 0 02022 AnimOverride *BKE_animsys_validate_override (PointerRNA *UNUSED(ptr), char *UNUSED(path), int UNUSED(array_index)) 02023 { 02024 // FIXME: need to define how to get overrides 02025 return NULL; 02026 } 02027 #endif 02028 02029 /* -------------------- */ 02030 02031 /* Evaluate Overrides */ 02032 static void animsys_evaluate_overrides (PointerRNA *ptr, AnimData *adt) 02033 { 02034 AnimOverride *aor; 02035 02036 /* for each override, simply execute... */ 02037 for (aor= adt->overrides.first; aor; aor= aor->next) 02038 animsys_write_rna_setting(ptr, aor->rna_path, aor->array_index, aor->value); 02039 } 02040 02041 /* ***************************************** */ 02042 /* Evaluation System - Public API */ 02043 02044 /* Overview of how this system works: 02045 * 1) Depsgraph sorts data as necessary, so that data is in an order that means 02046 * that all dependences are resolved before dependants. 02047 * 2) All normal animation is evaluated, so that drivers have some basis values to 02048 * work with 02049 * a. NLA stacks are done first, as the Active Actions act as 'tweaking' tracks 02050 * which modify the effects of the NLA-stacks 02051 * b. Active Action is evaluated as per normal, on top of the results of the NLA tracks 02052 * 02053 * --------------< often in a separate phase... >------------------ 02054 * 02055 * 3) Drivers/expressions are evaluated on top of this, in an order where dependences are 02056 * resolved nicely. 02057 * Note: it may be necessary to have some tools to handle the cases where some higher-level 02058 * drivers are added and cause some problematic dependencies that didn't exist in the local levels... 02059 * 02060 * --------------< always executed >------------------ 02061 * 02062 * Maintainance of editability of settings (XXX): 02063 * In order to ensure that settings that are animated can still be manipulated in the UI without requiring 02064 * that keyframes are added to prevent these values from being overwritten, we use 'overrides'. 02065 * 02066 * Unresolved things: 02067 * - Handling of multi-user settings (i.e. time-offset, group-instancing) -> big cache grids or nodal system? but stored where? 02068 * - Multiple-block dependencies (i.e. drivers for settings are in both local and higher levels) -> split into separate lists? 02069 * 02070 * Current Status: 02071 * - Currently (as of September 2009), overrides we haven't needed to (fully) implement overrides. 02072 * However, the code fo this is relatively harmless, so is left in the code for now. 02073 */ 02074 02075 /* Evaluation loop for evaluation animation data 02076 * 02077 * This assumes that the animation-data provided belongs to the ID block in question, 02078 * and that the flags for which parts of the anim-data settings need to be recalculated 02079 * have been set already by the depsgraph. Now, we use the recalc 02080 */ 02081 void BKE_animsys_evaluate_animdata (ID *id, AnimData *adt, float ctime, short recalc) 02082 { 02083 PointerRNA id_ptr; 02084 02085 /* sanity checks */ 02086 if ELEM(NULL, id, adt) 02087 return; 02088 02089 /* get pointer to ID-block for RNA to use */ 02090 RNA_id_pointer_create(id, &id_ptr); 02091 02092 /* recalculate keyframe data: 02093 * - NLA before Active Action, as Active Action behaves as 'tweaking track' 02094 * that overrides 'rough' work in NLA 02095 */ 02096 // TODO: need to double check that this all works correctly 02097 if ((recalc & ADT_RECALC_ANIM) || (adt->recalc & ADT_RECALC_ANIM)) 02098 { 02099 /* evaluate NLA data */ 02100 if ((adt->nla_tracks.first) && !(adt->flag & ADT_NLA_EVAL_OFF)) 02101 { 02102 /* evaluate NLA-stack 02103 * - active action is evaluated as part of the NLA stack as the last item 02104 */ 02105 animsys_calculate_nla(&id_ptr, adt, ctime); 02106 } 02107 /* evaluate Active Action only */ 02108 else if (adt->action) 02109 animsys_evaluate_action(&id_ptr, adt->action, adt->remap, ctime); 02110 02111 /* reset tag */ 02112 adt->recalc &= ~ADT_RECALC_ANIM; 02113 } 02114 02115 /* recalculate drivers 02116 * - Drivers need to be evaluated afterwards, as they can either override 02117 * or be layered on top of existing animation data. 02118 * - Drivers should be in the appropriate order to be evaluated without problems... 02119 */ 02120 if ((recalc & ADT_RECALC_DRIVERS) /*&& (adt->recalc & ADT_RECALC_DRIVERS)*/) // XXX for now, don't check yet, as depsgraph hasn't been updated 02121 { 02122 animsys_evaluate_drivers(&id_ptr, adt, ctime); 02123 } 02124 02125 /* always execute 'overrides' 02126 * - Overrides allow editing, by overwriting the value(s) set from animation-data, with the 02127 * value last set by the user (and not keyframed yet). 02128 * - Overrides are cleared upon frame change and/or keyframing 02129 * - It is best that we execute this everytime, so that no errors are likely to occur. 02130 */ 02131 animsys_evaluate_overrides(&id_ptr, adt); 02132 02133 /* clear recalc flag now */ 02134 adt->recalc= 0; 02135 } 02136 02137 /* Evaluation of all ID-blocks with Animation Data blocks - Animation Data Only 02138 * 02139 * This will evaluate only the animation info available in the animation data-blocks 02140 * encountered. In order to enforce the system by which some settings controlled by a 02141 * 'local' (i.e. belonging in the nearest ID-block that setting is related to, not a 02142 * standard 'root') block are overridden by a larger 'user' 02143 */ 02144 void BKE_animsys_evaluate_all_animation (Main *main, float ctime) 02145 { 02146 ID *id; 02147 02148 if (G.f & G_DEBUG) 02149 printf("Evaluate all animation - %f \n", ctime); 02150 02151 /* macros for less typing 02152 * - only evaluate animation data for id if it has users (and not just fake ones) 02153 * - whether animdata exists is checked for by the evaluation function, though taking 02154 * this outside of the function may make things slightly faster? 02155 */ 02156 #define EVAL_ANIM_IDS(first, aflag) \ 02157 for (id= first; id; id= id->next) { \ 02158 if (ID_REAL_USERS(id) > 0) { \ 02159 AnimData *adt= BKE_animdata_from_id(id); \ 02160 BKE_animsys_evaluate_animdata(id, adt, ctime, aflag); \ 02161 } \ 02162 } 02163 /* another macro for the "embedded" nodetree cases 02164 * - this is like EVAL_ANIM_IDS, but this handles the case "embedded nodetrees" 02165 * (i.e. scene/material/texture->nodetree) which we need a special exception 02166 * for, otherwise they'd get skipped 02167 * - ntp = "node tree parent" = datablock where node tree stuff resides 02168 */ 02169 #define EVAL_ANIM_NODETREE_IDS(first, NtId_Type, aflag) \ 02170 for (id= first; id; id= id->next) { \ 02171 if (ID_REAL_USERS(id) > 0) { \ 02172 AnimData *adt= BKE_animdata_from_id(id); \ 02173 NtId_Type *ntp= (NtId_Type *)id; \ 02174 if (ntp->nodetree) { \ 02175 AnimData *adt2= BKE_animdata_from_id((ID *)ntp->nodetree); \ 02176 BKE_animsys_evaluate_animdata((ID *)ntp->nodetree, adt2, ctime, ADT_RECALC_ANIM); \ 02177 } \ 02178 BKE_animsys_evaluate_animdata(id, adt, ctime, aflag); \ 02179 } \ 02180 } 02181 02182 /* optimisation: 02183 * when there are no actions, don't go over database and loop over heaps of datablocks, 02184 * which should ultimately be empty, since it is not possible for now to have any animation 02185 * without some actions, and drivers wouldn't get affected by any state changes 02186 * 02187 * however, if there are some curves, we will need to make sure that their 'ctime' property gets 02188 * set correctly, so this optimisation must be skipped in that case... 02189 */ 02190 if ((main->action.first == NULL) && (main->curve.first == NULL)) { 02191 if (G.f & G_DEBUG) 02192 printf("\tNo Actions, so no animation needs to be evaluated...\n"); 02193 02194 return; 02195 } 02196 02197 /* nodes */ 02198 EVAL_ANIM_IDS(main->nodetree.first, ADT_RECALC_ANIM); 02199 02200 /* textures */ 02201 EVAL_ANIM_NODETREE_IDS(main->tex.first, Tex, ADT_RECALC_ANIM); 02202 02203 /* lamps */ 02204 EVAL_ANIM_IDS(main->lamp.first, ADT_RECALC_ANIM); 02205 02206 /* materials */ 02207 EVAL_ANIM_NODETREE_IDS(main->mat.first, Material, ADT_RECALC_ANIM); 02208 02209 /* cameras */ 02210 EVAL_ANIM_IDS(main->camera.first, ADT_RECALC_ANIM); 02211 02212 /* shapekeys */ 02213 EVAL_ANIM_IDS(main->key.first, ADT_RECALC_ANIM); 02214 02215 /* metaballs */ 02216 EVAL_ANIM_IDS(main->mball.first, ADT_RECALC_ANIM); 02217 02218 /* curves */ 02219 EVAL_ANIM_IDS(main->curve.first, ADT_RECALC_ANIM); 02220 02221 /* armatures */ 02222 EVAL_ANIM_IDS(main->armature.first, ADT_RECALC_ANIM); 02223 02224 /* lattices */ 02225 EVAL_ANIM_IDS(main->latt.first, ADT_RECALC_ANIM); 02226 02227 /* meshes */ 02228 EVAL_ANIM_IDS(main->mesh.first, ADT_RECALC_ANIM); 02229 02230 /* particles */ 02231 EVAL_ANIM_IDS(main->particle.first, ADT_RECALC_ANIM); 02232 02233 /* objects */ 02234 /* ADT_RECALC_ANIM doesn't need to be supplied here, since object AnimData gets 02235 * this tagged by Depsgraph on framechange. This optimisation means that objects 02236 * linked from other (not-visible) scenes will not need their data calculated. 02237 */ 02238 EVAL_ANIM_IDS(main->object.first, 0); 02239 02240 /* worlds */ 02241 EVAL_ANIM_IDS(main->world.first, ADT_RECALC_ANIM); 02242 02243 /* scenes */ 02244 EVAL_ANIM_NODETREE_IDS(main->scene.first, Scene, ADT_RECALC_ANIM); 02245 } 02246 02247 /* ***************************************** */