Blender V2.61 - r43446
|
00001 /* 00002 * ***** BEGIN GPL LICENSE BLOCK ***** 00003 * 00004 * This program is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU General Public License 00006 * as published by the Free Software Foundation; either version 2 00007 * of the License, or (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software Foundation, 00016 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 * 00018 * The Original Code is Copyright (C) 2008 Blender Foundation, Joshua Leung 00019 * All rights reserved. 00020 * 00021 * 00022 * Contributor(s): Joshua Leung (original author) 00023 * 00024 * ***** END GPL LICENSE BLOCK ***** 00025 */ 00026 00032 /* This file contains a system used to provide a layer of abstraction between sources 00033 * of animation data and tools in Animation Editors. The method used here involves 00034 * generating a list of edit structures which enable tools to naively perform the actions 00035 * they require without all the boiler-plate associated with loops within loops and checking 00036 * for cases to ignore. 00037 * 00038 * While this is primarily used for the Action/Dopesheet Editor (and its accessory modes), 00039 * the Graph Editor also uses this for its channel list and for determining which curves 00040 * are being edited. Likewise, the NLA Editor also uses this for its channel list and in 00041 * its operators. 00042 * 00043 * Note: much of the original system this was based on was built before the creation of the RNA 00044 * system. In future, it would be interesting to replace some parts of this code with RNA queries, 00045 * however, RNA does not eliminate some of the boiler-plate reduction benefits presented by this 00046 * system, so if any such work does occur, it should only be used for the internals used here... 00047 * 00048 * -- Joshua Leung, Dec 2008 (Last revision July 2009) 00049 */ 00050 00051 #include <string.h> 00052 00053 #include "DNA_anim_types.h" 00054 #include "DNA_armature_types.h" 00055 #include "DNA_camera_types.h" 00056 #include "DNA_lamp_types.h" 00057 #include "DNA_lattice_types.h" 00058 #include "DNA_key_types.h" 00059 #include "DNA_material_types.h" 00060 #include "DNA_mesh_types.h" 00061 #include "DNA_meta_types.h" 00062 #include "DNA_node_types.h" 00063 #include "DNA_particle_types.h" 00064 #include "DNA_space_types.h" 00065 #include "DNA_sequence_types.h" 00066 #include "DNA_scene_types.h" 00067 #include "DNA_screen_types.h" 00068 #include "DNA_speaker_types.h" 00069 #include "DNA_world_types.h" 00070 #include "DNA_gpencil_types.h" 00071 #include "DNA_object_types.h" 00072 00073 #include "MEM_guardedalloc.h" 00074 00075 #include "BLI_blenlib.h" 00076 #include "BLI_utildefines.h" 00077 #include "BLI_ghash.h" 00078 00079 #include "BKE_animsys.h" 00080 #include "BKE_action.h" 00081 #include "BKE_fcurve.h" 00082 #include "BKE_context.h" 00083 #include "BKE_global.h" 00084 #include "BKE_group.h" 00085 #include "BKE_key.h" 00086 #include "BKE_main.h" 00087 #include "BKE_material.h" 00088 #include "BKE_node.h" 00089 #include "BKE_sequencer.h" 00090 #include "BKE_utildefines.h" 00091 00092 #include "ED_anim_api.h" 00093 #include "ED_markers.h" 00094 00095 /* ************************************************************ */ 00096 /* Blender Context <-> Animation Context mapping */ 00097 00098 /* ----------- Private Stuff - Action Editor ------------- */ 00099 00100 /* Get shapekey data being edited (for Action Editor -> ShapeKey mode) */ 00101 /* Note: there's a similar function in key.c (ob_get_key) */ 00102 static Key *actedit_get_shapekeys (bAnimContext *ac) 00103 { 00104 Scene *scene= ac->scene; 00105 Object *ob; 00106 Key *key; 00107 00108 ob = OBACT; 00109 if (ob == NULL) 00110 return NULL; 00111 00112 /* XXX pinning is not available in 'ShapeKey' mode... */ 00113 //if (saction->pin) return NULL; 00114 00115 /* shapekey data is stored with geometry data */ 00116 key= ob_get_key(ob); 00117 00118 if (key) { 00119 if (key->type == KEY_RELATIVE) 00120 return key; 00121 } 00122 00123 return NULL; 00124 } 00125 00126 /* Get data being edited in Action Editor (depending on current 'mode') */ 00127 static short actedit_get_context (bAnimContext *ac, SpaceAction *saction) 00128 { 00129 /* get dopesheet */ 00130 ac->ads = &saction->ads; 00131 00132 /* sync settings with current view status, then return appropriate data */ 00133 switch (saction->mode) { 00134 case SACTCONT_ACTION: /* 'Action Editor' */ 00135 /* if not pinned, sync with active object */ 00136 if (/*saction->pin == 0*/1) { 00137 if (ac->obact && ac->obact->adt) 00138 saction->action = ac->obact->adt->action; 00139 else 00140 saction->action= NULL; 00141 } 00142 00143 ac->datatype= ANIMCONT_ACTION; 00144 ac->data= saction->action; 00145 00146 ac->mode= saction->mode; 00147 return 1; 00148 00149 case SACTCONT_SHAPEKEY: /* 'ShapeKey Editor' */ 00150 ac->datatype= ANIMCONT_SHAPEKEY; 00151 ac->data= actedit_get_shapekeys(ac); 00152 00153 ac->mode= saction->mode; 00154 return 1; 00155 00156 case SACTCONT_GPENCIL: /* Grease Pencil */ // XXX review how this mode is handled... 00157 /* update scene-pointer (no need to check for pinning yet, as not implemented) */ 00158 saction->ads.source= (ID *)ac->scene; 00159 00160 ac->datatype= ANIMCONT_GPENCIL; 00161 ac->data= &saction->ads; 00162 00163 ac->mode= saction->mode; 00164 return 1; 00165 00166 case SACTCONT_DOPESHEET: /* DopeSheet */ 00167 /* update scene-pointer (no need to check for pinning yet, as not implemented) */ 00168 saction->ads.source= (ID *)ac->scene; 00169 00170 ac->datatype= ANIMCONT_DOPESHEET; 00171 ac->data= &saction->ads; 00172 00173 ac->mode= saction->mode; 00174 return 1; 00175 00176 default: /* unhandled yet */ 00177 ac->datatype= ANIMCONT_NONE; 00178 ac->data= NULL; 00179 00180 ac->mode= -1; 00181 return 0; 00182 } 00183 } 00184 00185 /* ----------- Private Stuff - Graph Editor ------------- */ 00186 00187 /* Get data being edited in Graph Editor (depending on current 'mode') */ 00188 static short graphedit_get_context (bAnimContext *ac, SpaceIpo *sipo) 00189 { 00190 /* init dopesheet data if non-existant (i.e. for old files) */ 00191 if (sipo->ads == NULL) { 00192 sipo->ads= MEM_callocN(sizeof(bDopeSheet), "GraphEdit DopeSheet"); 00193 sipo->ads->source= (ID *)ac->scene; 00194 } 00195 ac->ads = sipo->ads; 00196 00197 /* set settings for Graph Editor - "Selected = Editable" */ 00198 if (sipo->flag & SIPO_SELCUVERTSONLY) 00199 sipo->ads->filterflag |= ADS_FILTER_SELEDIT; 00200 else 00201 sipo->ads->filterflag &= ~ADS_FILTER_SELEDIT; 00202 00203 /* sync settings with current view status, then return appropriate data */ 00204 switch (sipo->mode) { 00205 case SIPO_MODE_ANIMATION: /* Animation F-Curve Editor */ 00206 /* update scene-pointer (no need to check for pinning yet, as not implemented) */ 00207 sipo->ads->source= (ID *)ac->scene; 00208 sipo->ads->filterflag &= ~ADS_FILTER_ONLYDRIVERS; 00209 00210 ac->datatype= ANIMCONT_FCURVES; 00211 ac->data= sipo->ads; 00212 00213 ac->mode= sipo->mode; 00214 return 1; 00215 00216 case SIPO_MODE_DRIVERS: /* Driver F-Curve Editor */ 00217 /* update scene-pointer (no need to check for pinning yet, as not implemented) */ 00218 sipo->ads->source= (ID *)ac->scene; 00219 sipo->ads->filterflag |= ADS_FILTER_ONLYDRIVERS; 00220 00221 ac->datatype= ANIMCONT_DRIVERS; 00222 ac->data= sipo->ads; 00223 00224 ac->mode= sipo->mode; 00225 return 1; 00226 00227 default: /* unhandled yet */ 00228 ac->datatype= ANIMCONT_NONE; 00229 ac->data= NULL; 00230 00231 ac->mode= -1; 00232 return 0; 00233 } 00234 } 00235 00236 /* ----------- Private Stuff - NLA Editor ------------- */ 00237 00238 /* Get data being edited in Graph Editor (depending on current 'mode') */ 00239 static short nlaedit_get_context (bAnimContext *ac, SpaceNla *snla) 00240 { 00241 /* init dopesheet data if non-existant (i.e. for old files) */ 00242 if (snla->ads == NULL) 00243 snla->ads= MEM_callocN(sizeof(bDopeSheet), "NlaEdit DopeSheet"); 00244 ac->ads = snla->ads; 00245 00246 /* sync settings with current view status, then return appropriate data */ 00247 /* update scene-pointer (no need to check for pinning yet, as not implemented) */ 00248 snla->ads->source= (ID *)ac->scene; 00249 snla->ads->filterflag |= ADS_FILTER_ONLYNLA; 00250 00251 ac->datatype= ANIMCONT_NLA; 00252 ac->data= snla->ads; 00253 00254 return 1; 00255 } 00256 00257 /* ----------- Public API --------------- */ 00258 00259 /* Obtain current anim-data context, given that context info from Blender context has already been set 00260 * - AnimContext to write to is provided as pointer to var on stack so that we don't have 00261 * allocation/freeing costs (which are not that avoidable with channels). 00262 */ 00263 short ANIM_animdata_context_getdata (bAnimContext *ac) 00264 { 00265 SpaceLink *sl = ac->sl; 00266 short ok= 0; 00267 00268 /* context depends on editor we are currently in */ 00269 if (sl) { 00270 switch (ac->spacetype) { 00271 case SPACE_ACTION: 00272 { 00273 SpaceAction *saction= (SpaceAction *)sl; 00274 ok= actedit_get_context(ac, saction); 00275 } 00276 break; 00277 00278 case SPACE_IPO: 00279 { 00280 SpaceIpo *sipo= (SpaceIpo *)sl; 00281 ok= graphedit_get_context(ac, sipo); 00282 } 00283 break; 00284 00285 case SPACE_NLA: 00286 { 00287 SpaceNla *snla= (SpaceNla *)sl; 00288 ok= nlaedit_get_context(ac, snla); 00289 } 00290 break; 00291 } 00292 } 00293 00294 /* check if there's any valid data */ 00295 if (ok && ac->data) 00296 return 1; 00297 else 00298 return 0; 00299 } 00300 00301 /* Obtain current anim-data context from Blender Context info 00302 * - AnimContext to write to is provided as pointer to var on stack so that we don't have 00303 * allocation/freeing costs (which are not that avoidable with channels). 00304 * - Clears data and sets the information from Blender Context which is useful 00305 */ 00306 short ANIM_animdata_get_context (const bContext *C, bAnimContext *ac) 00307 { 00308 ScrArea *sa= CTX_wm_area(C); 00309 ARegion *ar= CTX_wm_region(C); 00310 SpaceLink *sl= CTX_wm_space_data(C); 00311 Scene *scene= CTX_data_scene(C); 00312 00313 /* clear old context info */ 00314 if (ac == NULL) return 0; 00315 memset(ac, 0, sizeof(bAnimContext)); 00316 00317 /* get useful default context settings from context */ 00318 ac->scene= scene; 00319 if (scene) { 00320 ac->markers= ED_context_get_markers(C); 00321 ac->obact= (scene->basact)? scene->basact->object : NULL; 00322 } 00323 ac->sa= sa; 00324 ac->ar= ar; 00325 ac->sl= sl; 00326 ac->spacetype= (sa) ? sa->spacetype : 0; 00327 ac->regiontype= (ar) ? ar->regiontype : 0; 00328 00329 /* get data context info */ 00330 return ANIM_animdata_context_getdata(ac); 00331 } 00332 00333 /* ************************************************************ */ 00334 /* Blender Data <-- Filter --> Channels to be operated on */ 00335 00336 /* macros to use before/after getting the sub-channels of some channel, 00337 * to abstract away some of the tricky logic involved 00338 * 00339 * cases: 00340 * 1) Graph Edit main area (just data) OR channels visible in Channel List 00341 * 2) If not showing channels, we're only interested in the data (Action Editor's editing) 00342 * 3) We don't care what data, we just care there is some (so that a collapsed 00343 * channel can be kept around). No need to clear channels-flag in order to 00344 * keep expander channels with no sub-data out, as those cases should get 00345 * dealt with by the recursive detection idiom in place. 00346 * 00347 * Implementation Note: 00348 * YES the _doSubChannels variable is NOT read anywhere. BUT, this is NOT an excuse 00349 * to go steamrolling the logic into a single-line expression as from experience, 00350 * those are notoriously difficult to read + debug when extending later on. The code 00351 * below is purposefully laid out so that each case noted above corresponds clearly to 00352 * one case below. 00353 */ 00354 #define BEGIN_ANIMFILTER_SUBCHANNELS(expanded_check) \ 00355 { \ 00356 int _filter = filter_mode; \ 00357 short _doSubChannels = 0; \ 00358 if (!(filter_mode & ANIMFILTER_LIST_VISIBLE) || (expanded_check)) \ 00359 _doSubChannels=1; \ 00360 else if (!(filter_mode & ANIMFILTER_LIST_CHANNELS)) \ 00361 _doSubChannels=2; \ 00362 else {\ 00363 filter_mode |= ANIMFILTER_TMP_PEEK; \ 00364 } \ 00365 (void) _doSubChannels; 00366 /* ... standard sub-channel filtering can go on here now ... */ 00367 #define END_ANIMFILTER_SUBCHANNELS \ 00368 filter_mode = _filter; \ 00369 } 00370 00371 /* ............................... */ 00372 00373 /* quick macro to test if AnimData is usable */ 00374 #define ANIMDATA_HAS_KEYS(id) ((id)->adt && (id)->adt->action) 00375 00376 /* quick macro to test if AnimData is usable for drivers */ 00377 #define ANIMDATA_HAS_DRIVERS(id) ((id)->adt && (id)->adt->drivers.first) 00378 00379 /* quick macro to test if AnimData is usable for NLA */ 00380 #define ANIMDATA_HAS_NLA(id) ((id)->adt && (id)->adt->nla_tracks.first) 00381 00382 /* Quick macro to test for all three above usability tests, performing the appropriate provided 00383 * action for each when the AnimData context is appropriate. 00384 * 00385 * Priority order for this goes (most important, to least): AnimData blocks, NLA, Drivers, Keyframes. 00386 * 00387 * For this to work correctly, a standard set of data needs to be available within the scope that this 00388 * gets called in: 00389 * - ListBase anim_data; 00390 * - bDopeSheet *ads; 00391 * - bAnimListElem *ale; 00392 * - size_t items; 00393 * 00394 * - id: ID block which should have an AnimData pointer following it immediately, to use 00395 * - adtOk: line or block of code to execute for AnimData-blocks case (usually ANIMDATA_ADD_ANIMDATA) 00396 * - nlaOk: line or block of code to execute for NLA tracks+strips case 00397 * - driversOk: line or block of code to execute for Drivers case 00398 * - keysOk: line or block of code for Keyframes case 00399 * 00400 * The checks for the various cases are as follows: 00401 * 0) top level: checks for animdata and also that all the F-Curves for the block will be visible 00402 * 1) animdata check: for filtering animdata blocks only 00403 * 2A) nla tracks: include animdata block's data as there are NLA tracks+strips there 00404 * 2B) actions to convert to nla: include animdata block's data as there is an action that can be 00405 * converted to a new NLA strip, and the filtering options allow this 00406 * 2C) allow non-animated datablocks to be included so that datablocks can be added 00407 * 3) drivers: include drivers from animdata block (for Drivers mode in Graph Editor) 00408 * 4) normal keyframes: only when there is an active action 00409 */ 00410 #define ANIMDATA_FILTER_CASES(id, adtOk, nlaOk, driversOk, keysOk) \ 00411 {\ 00412 if ((id)->adt) {\ 00413 if (!(filter_mode & ANIMFILTER_CURVE_VISIBLE) || !((id)->adt->flag & ADT_CURVES_NOT_VISIBLE)) {\ 00414 if (filter_mode & ANIMFILTER_ANIMDATA) {\ 00415 adtOk\ 00416 }\ 00417 else if (ads->filterflag & ADS_FILTER_ONLYNLA) {\ 00418 if (ANIMDATA_HAS_NLA(id)) {\ 00419 nlaOk\ 00420 }\ 00421 else if (!(ads->filterflag & ADS_FILTER_NLA_NOACT) && ANIMDATA_HAS_KEYS(id)) {\ 00422 nlaOk\ 00423 }\ 00424 }\ 00425 else if (ads->filterflag & ADS_FILTER_ONLYDRIVERS) {\ 00426 if (ANIMDATA_HAS_DRIVERS(id)) {\ 00427 driversOk\ 00428 }\ 00429 }\ 00430 else {\ 00431 if (ANIMDATA_HAS_KEYS(id)) {\ 00432 keysOk\ 00433 }\ 00434 }\ 00435 }\ 00436 }\ 00437 } 00438 00439 /* ............................... */ 00440 00441 /* Add a new animation channel, taking into account the "peek" flag, which is used to just check 00442 * whether any channels will be added (but without needing them to actually get created). 00443 * 00444 * ! This causes the calling function to return early if we're only "peeking" for channels 00445 */ 00446 // XXX: ale_statement stuff is really a hack for one special case. It shouldn't really be needed... 00447 #define ANIMCHANNEL_NEW_CHANNEL_FULL(channel_data, channel_type, owner_id, ale_statement) \ 00448 if (filter_mode & ANIMFILTER_TMP_PEEK) \ 00449 return 1; \ 00450 else { \ 00451 bAnimListElem *ale= make_new_animlistelem(channel_data, channel_type, (ID *)owner_id); \ 00452 if (ale) {\ 00453 BLI_addtail(anim_data, ale); \ 00454 items++; \ 00455 ale_statement \ 00456 } \ 00457 } 00458 00459 #define ANIMCHANNEL_NEW_CHANNEL(channel_data, channel_type, owner_id) \ 00460 ANIMCHANNEL_NEW_CHANNEL_FULL(channel_data, channel_type, owner_id, {}) 00461 00462 /* ............................... */ 00463 00464 /* quick macro to test if an anim-channel representing an AnimData block is suitably active */ 00465 #define ANIMCHANNEL_ACTIVEOK(ale) \ 00466 ( !(filter_mode & ANIMFILTER_ACTIVE) || !(ale->adt) || (ale->adt->flag & ADT_UI_ACTIVE) ) 00467 00468 /* quick macro to test if an anim-channel (F-Curve, Group, etc.) is selected in an acceptable way */ 00469 #define ANIMCHANNEL_SELOK(test_func) \ 00470 ( !(filter_mode & (ANIMFILTER_SEL|ANIMFILTER_UNSEL)) || \ 00471 ((filter_mode & ANIMFILTER_SEL) && test_func) || \ 00472 ((filter_mode & ANIMFILTER_UNSEL) && test_func==0) ) 00473 00474 /* quick macro to test if an anim-channel (F-Curve) is selected ok for editing purposes 00475 * - _SELEDIT means that only selected curves will have visible+editable keyframes 00476 * 00477 * checks here work as follows: 00478 * 1) seledit off - don't need to consider the implications of this option 00479 * 2) foredit off - we're not considering editing, so channel is ok still 00480 * 3) test_func (i.e. selection test) - only if selected, this test will pass 00481 */ 00482 #define ANIMCHANNEL_SELEDITOK(test_func) \ 00483 ( !(filter_mode & ANIMFILTER_SELEDIT) || \ 00484 !(filter_mode & ANIMFILTER_FOREDIT) || \ 00485 (test_func) ) 00486 00487 /* ----------- 'Private' Stuff --------------- */ 00488 00489 /* this function allocates memory for a new bAnimListElem struct for the 00490 * provided animation channel-data. 00491 */ 00492 static bAnimListElem *make_new_animlistelem (void *data, short datatype, ID *owner_id) 00493 { 00494 bAnimListElem *ale= NULL; 00495 00496 /* only allocate memory if there is data to convert */ 00497 if (data) { 00498 /* allocate and set generic data */ 00499 ale= MEM_callocN(sizeof(bAnimListElem), "bAnimListElem"); 00500 00501 ale->data= data; 00502 ale->type= datatype; 00503 00504 ale->id= owner_id; 00505 ale->adt= BKE_animdata_from_id(owner_id); 00506 00507 /* do specifics */ 00508 switch (datatype) { 00509 case ANIMTYPE_SUMMARY: 00510 { 00511 /* nothing to include for now... this is just a dummy wrappy around all the other channels 00512 * in the DopeSheet, and gets included at the start of the list 00513 */ 00514 ale->key_data= NULL; 00515 ale->datatype= ALE_ALL; 00516 } 00517 break; 00518 00519 case ANIMTYPE_SCENE: 00520 { 00521 Scene *sce= (Scene *)data; 00522 00523 ale->flag= sce->flag; 00524 00525 ale->key_data= sce; 00526 ale->datatype= ALE_SCE; 00527 00528 ale->adt= BKE_animdata_from_id(data); 00529 } 00530 break; 00531 case ANIMTYPE_OBJECT: 00532 { 00533 Base *base= (Base *)data; 00534 Object *ob= base->object; 00535 00536 ale->flag= ob->flag; 00537 00538 ale->key_data= ob; 00539 ale->datatype= ALE_OB; 00540 00541 ale->adt= BKE_animdata_from_id(&ob->id); 00542 } 00543 break; 00544 case ANIMTYPE_FILLACTD: 00545 { 00546 bAction *act= (bAction *)data; 00547 00548 ale->flag= act->flag; 00549 00550 ale->key_data= act; 00551 ale->datatype= ALE_ACT; 00552 } 00553 break; 00554 case ANIMTYPE_FILLDRIVERS: 00555 { 00556 AnimData *adt= (AnimData *)data; 00557 00558 ale->flag= adt->flag; 00559 00560 // XXX... drivers don't show summary for now 00561 ale->key_data= NULL; 00562 ale->datatype= ALE_NONE; 00563 } 00564 break; 00565 00566 case ANIMTYPE_DSMAT: 00567 { 00568 Material *ma= (Material *)data; 00569 AnimData *adt= ma->adt; 00570 00571 ale->flag= FILTER_MAT_OBJD(ma); 00572 00573 ale->key_data= (adt) ? adt->action : NULL; 00574 ale->datatype= ALE_ACT; 00575 00576 ale->adt= BKE_animdata_from_id(data); 00577 } 00578 break; 00579 case ANIMTYPE_DSLAM: 00580 { 00581 Lamp *la= (Lamp *)data; 00582 AnimData *adt= la->adt; 00583 00584 ale->flag= FILTER_LAM_OBJD(la); 00585 00586 ale->key_data= (adt) ? adt->action : NULL; 00587 ale->datatype= ALE_ACT; 00588 00589 ale->adt= BKE_animdata_from_id(data); 00590 } 00591 break; 00592 case ANIMTYPE_DSCAM: 00593 { 00594 Camera *ca= (Camera *)data; 00595 AnimData *adt= ca->adt; 00596 00597 ale->flag= FILTER_CAM_OBJD(ca); 00598 00599 ale->key_data= (adt) ? adt->action : NULL; 00600 ale->datatype= ALE_ACT; 00601 00602 ale->adt= BKE_animdata_from_id(data); 00603 } 00604 break; 00605 case ANIMTYPE_DSCUR: 00606 { 00607 Curve *cu= (Curve *)data; 00608 AnimData *adt= cu->adt; 00609 00610 ale->flag= FILTER_CUR_OBJD(cu); 00611 00612 ale->key_data= (adt) ? adt->action : NULL; 00613 ale->datatype= ALE_ACT; 00614 00615 ale->adt= BKE_animdata_from_id(data); 00616 } 00617 break; 00618 case ANIMTYPE_DSARM: 00619 { 00620 bArmature *arm= (bArmature *)data; 00621 AnimData *adt= arm->adt; 00622 00623 ale->flag= FILTER_ARM_OBJD(arm); 00624 00625 ale->key_data= (adt) ? adt->action : NULL; 00626 ale->datatype= ALE_ACT; 00627 00628 ale->adt= BKE_animdata_from_id(data); 00629 } 00630 break; 00631 case ANIMTYPE_DSMESH: 00632 { 00633 Mesh *me= (Mesh *)data; 00634 AnimData *adt= me->adt; 00635 00636 ale->flag= FILTER_MESH_OBJD(me); 00637 00638 ale->key_data= (adt) ? adt->action : NULL; 00639 ale->datatype= ALE_ACT; 00640 00641 ale->adt= BKE_animdata_from_id(data); 00642 } 00643 break; 00644 case ANIMTYPE_DSLAT: 00645 { 00646 Lattice *lt= (Lattice *)data; 00647 AnimData *adt= lt->adt; 00648 00649 ale->flag= FILTER_LATTICE_OBJD(lt); 00650 00651 ale->key_data= (adt) ? adt->action : NULL; 00652 ale->datatype= ALE_ACT; 00653 00654 ale->adt= BKE_animdata_from_id(data); 00655 } 00656 break; 00657 case ANIMTYPE_DSSPK: 00658 { 00659 Speaker *spk= (Speaker *)data; 00660 AnimData *adt= spk->adt; 00661 00662 ale->flag= FILTER_SPK_OBJD(spk); 00663 00664 ale->key_data= (adt) ? adt->action : NULL; 00665 ale->datatype= ALE_ACT; 00666 00667 ale->adt= BKE_animdata_from_id(data); 00668 } 00669 break; 00670 case ANIMTYPE_DSSKEY: 00671 { 00672 Key *key= (Key *)data; 00673 AnimData *adt= key->adt; 00674 00675 ale->flag= FILTER_SKE_OBJD(key); 00676 00677 ale->key_data= (adt) ? adt->action : NULL; 00678 ale->datatype= ALE_ACT; 00679 00680 ale->adt= BKE_animdata_from_id(data); 00681 } 00682 break; 00683 case ANIMTYPE_DSWOR: 00684 { 00685 World *wo= (World *)data; 00686 AnimData *adt= wo->adt; 00687 00688 ale->flag= FILTER_WOR_SCED(wo); 00689 00690 ale->key_data= (adt) ? adt->action : NULL; 00691 ale->datatype= ALE_ACT; 00692 00693 ale->adt= BKE_animdata_from_id(data); 00694 } 00695 break; 00696 case ANIMTYPE_DSNTREE: 00697 { 00698 bNodeTree *ntree= (bNodeTree *)data; 00699 AnimData *adt= ntree->adt; 00700 00701 ale->flag= FILTER_NTREE_DATA(ntree); 00702 00703 ale->key_data= (adt) ? adt->action : NULL; 00704 ale->datatype= ALE_ACT; 00705 00706 ale->adt= BKE_animdata_from_id(data); 00707 } 00708 break; 00709 case ANIMTYPE_DSPART: 00710 { 00711 ParticleSettings *part= (ParticleSettings*)ale->data; 00712 AnimData *adt= part->adt; 00713 00714 ale->flag= FILTER_PART_OBJD(part); 00715 00716 ale->key_data= (adt) ? adt->action : NULL; 00717 ale->datatype= ALE_ACT; 00718 00719 ale->adt= BKE_animdata_from_id(data); 00720 } 00721 break; 00722 case ANIMTYPE_DSTEX: 00723 { 00724 Tex *tex= (Tex *)data; 00725 AnimData *adt= tex->adt; 00726 00727 ale->flag= FILTER_TEX_DATA(tex); 00728 00729 ale->key_data= (adt) ? adt->action : NULL; 00730 ale->datatype= ALE_ACT; 00731 00732 ale->adt= BKE_animdata_from_id(data); 00733 } 00734 break; 00735 00736 case ANIMTYPE_GROUP: 00737 { 00738 bActionGroup *agrp= (bActionGroup *)data; 00739 00740 ale->flag= agrp->flag; 00741 00742 ale->key_data= NULL; 00743 ale->datatype= ALE_GROUP; 00744 } 00745 break; 00746 case ANIMTYPE_FCURVE: 00747 { 00748 FCurve *fcu= (FCurve *)data; 00749 00750 ale->flag= fcu->flag; 00751 00752 ale->key_data= fcu; 00753 ale->datatype= ALE_FCURVE; 00754 } 00755 break; 00756 00757 case ANIMTYPE_SHAPEKEY: 00758 { 00759 KeyBlock *kb= (KeyBlock *)data; 00760 Key *key= (Key *)ale->id; 00761 00762 ale->flag= kb->flag; 00763 00764 /* whether we have keyframes depends on whether there is a Key block to find it from */ 00765 if (key) { 00766 /* index of shapekey is defined by place in key's list */ 00767 ale->index= BLI_findindex(&key->block, kb); 00768 00769 /* the corresponding keyframes are from the animdata */ 00770 if (ale->adt && ale->adt->action) { 00771 bAction *act= ale->adt->action; 00772 char *rna_path = key_get_curValue_rnaPath(key, kb); 00773 00774 /* try to find the F-Curve which corresponds to this exactly, 00775 * then free the MEM_alloc'd string 00776 */ 00777 if (rna_path) { 00778 ale->key_data= (void *)list_find_fcurve(&act->curves, rna_path, 0); 00779 MEM_freeN(rna_path); 00780 } 00781 } 00782 ale->datatype= (ale->key_data)? ALE_FCURVE : ALE_NONE; 00783 } 00784 } 00785 break; 00786 00787 case ANIMTYPE_GPLAYER: 00788 { 00789 bGPDlayer *gpl= (bGPDlayer *)data; 00790 00791 ale->flag= gpl->flag; 00792 00793 ale->key_data= NULL; 00794 ale->datatype= ALE_GPFRAME; 00795 } 00796 break; 00797 00798 case ANIMTYPE_NLATRACK: 00799 { 00800 NlaTrack *nlt= (NlaTrack *)data; 00801 00802 ale->flag= nlt->flag; 00803 00804 ale->key_data= &nlt->strips; 00805 ale->datatype= ALE_NLASTRIP; 00806 } 00807 break; 00808 case ANIMTYPE_NLAACTION: 00809 { 00810 /* nothing to include for now... nothing editable from NLA-perspective here */ 00811 ale->key_data= NULL; 00812 ale->datatype= ALE_NONE; 00813 } 00814 break; 00815 } 00816 } 00817 00818 /* return created datatype */ 00819 return ale; 00820 } 00821 00822 /* ----------------------------------------- */ 00823 00824 /* 'Only Selected' selected data filtering 00825 * NOTE: when this function returns true, the F-Curve is to be skipped 00826 */ 00827 static size_t skip_fcurve_selected_data (bDopeSheet *ads, FCurve *fcu, ID *owner_id, int filter_mode) 00828 { 00829 if (GS(owner_id->name) == ID_OB) { 00830 Object *ob= (Object *)owner_id; 00831 00832 /* only consider if F-Curve involves pose.bones */ 00833 if ((fcu->rna_path) && strstr(fcu->rna_path, "pose.bones")) { 00834 bPoseChannel *pchan; 00835 char *bone_name; 00836 00837 /* get bone-name, and check if this bone is selected */ 00838 bone_name= BLI_getQuotedStr(fcu->rna_path, "pose.bones["); 00839 pchan= get_pose_channel(ob->pose, bone_name); 00840 if (bone_name) MEM_freeN(bone_name); 00841 00842 /* check whether to continue or skip */ 00843 if ((pchan) && (pchan->bone)) { 00844 /* if only visible channels, skip if bone not visible unless user wants channels from hidden data too */ 00845 if ((filter_mode & ANIMFILTER_DATA_VISIBLE) && !(ads->filterflag & ADS_FILTER_INCL_HIDDEN)) { 00846 bArmature *arm= (bArmature *)ob->data; 00847 00848 if ((arm->layer & pchan->bone->layer) == 0) 00849 return 1; 00850 // TODO: manually hidden using flags 00851 } 00852 00853 /* can only add this F-Curve if it is selected */ 00854 if ((pchan->bone->flag & BONE_SELECTED) == 0) 00855 return 1; 00856 } 00857 } 00858 } 00859 else if (GS(owner_id->name) == ID_SCE) { 00860 Scene *scene = (Scene *)owner_id; 00861 00862 /* only consider if F-Curve involves sequence_editor.sequences */ 00863 if ((fcu->rna_path) && strstr(fcu->rna_path, "sequences_all")) { 00864 Editing *ed= seq_give_editing(scene, FALSE); 00865 Sequence *seq; 00866 char *seq_name; 00867 00868 /* get strip name, and check if this strip is selected */ 00869 seq_name= BLI_getQuotedStr(fcu->rna_path, "sequences_all["); 00870 seq = get_seq_by_name(ed->seqbasep, seq_name, FALSE); 00871 if (seq_name) MEM_freeN(seq_name); 00872 00873 /* can only add this F-Curve if it is selected */ 00874 if (seq==NULL || (seq->flag & SELECT)==0) 00875 return 1; 00876 } 00877 } 00878 else if (GS(owner_id->name) == ID_NT) { 00879 bNodeTree *ntree = (bNodeTree *)owner_id; 00880 00881 /* check for selected nodes */ 00882 if ((fcu->rna_path) && strstr(fcu->rna_path, "nodes")) { 00883 bNode *node; 00884 char *node_name; 00885 00886 /* get strip name, and check if this strip is selected */ 00887 node_name= BLI_getQuotedStr(fcu->rna_path, "nodes["); 00888 node = nodeFindNodebyName(ntree, node_name); 00889 if (node_name) MEM_freeN(node_name); 00890 00891 /* can only add this F-Curve if it is selected */ 00892 if ((node) && (node->flag & NODE_SELECT)==0) 00893 return 1; 00894 } 00895 } 00896 return 0; 00897 } 00898 00899 /* (Display-)Name-based F-Curve filtering 00900 * NOTE: when this function returns true, the F-Curve is to be skipped 00901 */ 00902 static short skip_fcurve_with_name (bDopeSheet *ads, FCurve *fcu, ID *owner_id) 00903 { 00904 bAnimListElem ale_dummy = {NULL}; 00905 bAnimChannelType *acf; 00906 00907 /* create a dummy wrapper for the F-Curve */ 00908 ale_dummy.type = ANIMTYPE_FCURVE; 00909 ale_dummy.id = owner_id; 00910 ale_dummy.data = fcu; 00911 00912 /* get type info for channel */ 00913 acf = ANIM_channel_get_typeinfo(&ale_dummy); 00914 if (acf && acf->name) { 00915 char name[256]; /* hopefully this will be enough! */ 00916 00917 /* get name */ 00918 acf->name(&ale_dummy, name); 00919 00920 /* check for partial match with the match string, assuming case insensitive filtering 00921 * if match, this channel shouldn't be ignored! 00922 */ 00923 return BLI_strcasestr(name, ads->searchstr) == NULL; 00924 } 00925 00926 /* just let this go... */ 00927 return 1; 00928 } 00929 00930 /* find the next F-Curve that is usable for inclusion */ 00931 static FCurve *animfilter_fcurve_next (bDopeSheet *ads, FCurve *first, bActionGroup *grp, int filter_mode, ID *owner_id) 00932 { 00933 FCurve *fcu = NULL; 00934 00935 /* loop over F-Curves - assume that the caller of this has already checked that these should be included 00936 * NOTE: we need to check if the F-Curves belong to the same group, as this gets called for groups too... 00937 */ 00938 for (fcu= first; ((fcu) && (fcu->grp==grp)); fcu= fcu->next) { 00939 /* special exception for Pose-Channel/Sequence-Strip/Node Based F-Curves: 00940 * - the 'Only Selected' data filter should be applied to Pose-Channel data too, but those are 00941 * represented as F-Curves. The way the filter for objects worked was to be the first check 00942 * after 'normal' visibility, so this is done first here too... 00943 * - we currently use an 'approximate' method for getting these F-Curves that doesn't require 00944 * carefully checking the entire path 00945 * - this will also affect things like Drivers, and also works for Bone Constraints 00946 */ 00947 if ( ((ads) && (ads->filterflag & ADS_FILTER_ONLYSEL)) && (owner_id) ) { 00948 if (skip_fcurve_selected_data(ads, fcu, owner_id, filter_mode)) 00949 continue; 00950 } 00951 00952 /* only include if visible (Graph Editor check, not channels check) */ 00953 if (!(filter_mode & ANIMFILTER_CURVE_VISIBLE) || (fcu->flag & FCURVE_VISIBLE)) { 00954 /* only work with this channel and its subchannels if it is editable */ 00955 if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_FCU(fcu)) { 00956 /* only include this curve if selected in a way consistent with the filtering requirements */ 00957 if ( ANIMCHANNEL_SELOK(SEL_FCU(fcu)) && ANIMCHANNEL_SELEDITOK(SEL_FCU(fcu)) ) { 00958 /* only include if this curve is active */ 00959 if (!(filter_mode & ANIMFILTER_ACTIVE) || (fcu->flag & FCURVE_ACTIVE)) { 00960 /* name based filtering... */ 00961 if ( ((ads) && (ads->filterflag & ADS_FILTER_BY_FCU_NAME)) && (owner_id) ) { 00962 if (skip_fcurve_with_name(ads, fcu, owner_id)) 00963 continue; 00964 } 00965 00966 /* this F-Curve can be used, so return it */ 00967 return fcu; 00968 } 00969 } 00970 } 00971 } 00972 } 00973 00974 /* no (more) F-Curves from the list are suitable... */ 00975 return NULL; 00976 } 00977 00978 static size_t animfilter_fcurves (ListBase *anim_data, bDopeSheet *ads, FCurve *first, bActionGroup *grp, int filter_mode, ID *owner_id) 00979 { 00980 FCurve *fcu; 00981 size_t items = 0; 00982 00983 /* loop over every F-Curve able to be included 00984 * - this for-loop works like this: 00985 * 1) the starting F-Curve is assigned to the fcu pointer so that we have a starting point to search from 00986 * 2) the first valid F-Curve to start from (which may include the one given as 'first') in the remaining 00987 * list of F-Curves is found, and verified to be non-null 00988 * 3) the F-Curve referenced by fcu pointer is added to the list 00989 * 4) the fcu pointer is set to the F-Curve after the one we just added, so that we can keep going through 00990 * the rest of the F-Curve list without an eternal loop. Back to step 2 :) 00991 */ 00992 for (fcu=first; ( (fcu = animfilter_fcurve_next(ads, fcu, grp, filter_mode, owner_id)) ); fcu=fcu->next) 00993 { 00994 ANIMCHANNEL_NEW_CHANNEL(fcu, ANIMTYPE_FCURVE, owner_id); 00995 } 00996 00997 /* return the number of items added to the list */ 00998 return items; 00999 } 01000 01001 static size_t animfilter_act_group (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, bAction *UNUSED(act), bActionGroup *agrp, int filter_mode, ID *owner_id) 01002 { 01003 ListBase tmp_data = {NULL, NULL}; 01004 size_t tmp_items = 0; 01005 size_t items = 0; 01006 //int ofilter = filter_mode; 01007 01008 /* if we care about the selection status of the channels, 01009 * but the group isn't expanded (1)... 01010 * (1) this only matters if we actually care about the hierarchy though. 01011 * - Hierarchy matters: this hack should be applied 01012 * - Hierarchy ignored: cases like [#21276] won't work properly, unless we skip this hack 01013 */ 01014 if ( ((filter_mode & ANIMFILTER_LIST_VISIBLE) && EXPANDED_AGRP(ac, agrp)==0) && /* care about hierarchy but group isn't expanded */ 01015 (filter_mode & (ANIMFILTER_SEL|ANIMFILTER_UNSEL)) ) /* care about selection status */ 01016 { 01017 /* if the group itself isn't selected appropriately, we shouldn't consider it's children either */ 01018 if (ANIMCHANNEL_SELOK(SEL_AGRP(agrp)) == 0) 01019 return 0; 01020 01021 /* if we're still here, then the selection status of the curves within this group should not matter, 01022 * since this creates too much overhead for animators (i.e. making a slow workflow) 01023 * 01024 * Tools affected by this at time of coding (2010 Feb 09): 01025 * - inserting keyframes on selected channels only 01026 * - pasting keyframes 01027 * - creating ghost curves in Graph Editor 01028 */ 01029 filter_mode &= ~(ANIMFILTER_SEL|ANIMFILTER_UNSEL|ANIMFILTER_LIST_VISIBLE); 01030 } 01031 01032 /* add grouped F-Curves */ 01033 BEGIN_ANIMFILTER_SUBCHANNELS(EXPANDED_AGRP(ac, agrp)) 01034 { 01035 /* special filter so that we can get just the F-Curves within the active group */ 01036 if (!(filter_mode & ANIMFILTER_ACTGROUPED) || (agrp->flag & AGRP_ACTIVE)) { 01037 /* for the Graph Editor, curves may be set to not be visible in the view to lessen clutter, 01038 * but to do this, we need to check that the group doesn't have it's not-visible flag set preventing 01039 * all its sub-curves to be shown 01040 */ 01041 if ( !(filter_mode & ANIMFILTER_CURVE_VISIBLE) || !(agrp->flag & AGRP_NOTVISIBLE) ) 01042 { 01043 /* group must be editable for its children to be editable (if we care about this) */ 01044 if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_AGRP(agrp)) { 01045 /* get first F-Curve which can be used here */ 01046 FCurve *first_fcu = animfilter_fcurve_next(ads, agrp->channels.first, agrp, filter_mode, owner_id); 01047 01048 /* filter list, starting from this F-Curve */ 01049 tmp_items += animfilter_fcurves(&tmp_data, ads, first_fcu, agrp, filter_mode, owner_id); 01050 } 01051 } 01052 } 01053 } 01054 END_ANIMFILTER_SUBCHANNELS; 01055 01056 /* did we find anything? */ 01057 if (tmp_items) { 01058 /* add this group as a channel first */ 01059 if (filter_mode & ANIMFILTER_LIST_CHANNELS) { 01060 /* restore original filter mode so that this next step works ok... */ 01061 //filter_mode = ofilter; 01062 01063 /* filter selection of channel specially here again, since may be open and not subject to previous test */ 01064 if ( ANIMCHANNEL_SELOK(SEL_AGRP(agrp)) ) { 01065 ANIMCHANNEL_NEW_CHANNEL(agrp, ANIMTYPE_GROUP, owner_id); 01066 } 01067 } 01068 01069 /* now add the list of collected channels */ 01070 BLI_movelisttolist(anim_data, &tmp_data); 01071 BLI_assert((tmp_data.first == tmp_data.last) && (tmp_data.first == NULL)); 01072 items += tmp_items; 01073 } 01074 01075 /* return the number of items added to the list */ 01076 return items; 01077 } 01078 01079 static size_t animfilter_action (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, bAction *act, int filter_mode, ID *owner_id) 01080 { 01081 bActionGroup *agrp; 01082 FCurve *lastchan = NULL; 01083 size_t items = 0; 01084 01085 /* don't include anything from this action if it is linked in from another file, 01086 * and we're getting stuff for editing... 01087 */ 01088 // TODO: need a way of tagging other channels that may also be affected... 01089 if ((filter_mode & ANIMFILTER_FOREDIT) && (act->id.lib)) 01090 return 0; 01091 01092 /* do groups */ 01093 // TODO: do nested groups? 01094 for (agrp = act->groups.first; agrp; agrp = agrp->next) { 01095 /* store reference to last channel of group */ 01096 if (agrp->channels.last) 01097 lastchan= agrp->channels.last; 01098 01099 /* action group's channels */ 01100 items += animfilter_act_group(ac, anim_data, ads, act, agrp, filter_mode, owner_id); 01101 } 01102 01103 /* un-grouped F-Curves (only if we're not only considering those channels in the active group) */ 01104 if (!(filter_mode & ANIMFILTER_ACTGROUPED)) { 01105 FCurve *firstfcu = (lastchan)? (lastchan->next) : (act->curves.first); 01106 items += animfilter_fcurves(anim_data, ads, firstfcu, NULL, filter_mode, owner_id); 01107 } 01108 01109 /* return the number of items added to the list */ 01110 return items; 01111 } 01112 01113 /* Include NLA-Data for NLA-Editor: 01114 * - when ANIMFILTER_LIST_CHANNELS is used, that means we should be filtering the list for display 01115 * Although the evaluation order is from the first track to the last and then apply the Action on top, 01116 * we present this in the UI as the Active Action followed by the last track to the first so that we 01117 * get the evaluation order presented as per a stack. 01118 * - for normal filtering (i.e. for editing), we only need the NLA-tracks but they can be in 'normal' evaluation 01119 * order, i.e. first to last. Otherwise, some tools may get screwed up. 01120 */ 01121 static size_t animfilter_nla (bAnimContext *UNUSED(ac), ListBase *anim_data, bDopeSheet *ads, AnimData *adt, int filter_mode, ID *owner_id) 01122 { 01123 NlaTrack *nlt; 01124 NlaTrack *first=NULL, *next=NULL; 01125 size_t items = 0; 01126 01127 /* if showing channels, include active action */ 01128 if (filter_mode & ANIMFILTER_LIST_CHANNELS) { 01129 /* if NLA action-line filtering is off, don't show unless there are keyframes, 01130 * in order to keep things more compact for doing transforms 01131 */ 01132 if (!(ads->filterflag & ADS_FILTER_NLA_NOACT) || (adt->action)) { 01133 /* there isn't really anything editable here, so skip if need editable */ 01134 if ((filter_mode & ANIMFILTER_FOREDIT) == 0) { 01135 /* just add the action track now (this MUST appear for drawing) 01136 * - as AnimData may not have an action, we pass a dummy pointer just to get the list elem created, then 01137 * overwrite this with the real value - REVIEW THIS... 01138 */ 01139 ANIMCHANNEL_NEW_CHANNEL_FULL((void *)(&adt->action), ANIMTYPE_NLAACTION, owner_id, 01140 { 01141 ale->data= adt->action ? adt->action : NULL; 01142 }); 01143 } 01144 } 01145 01146 /* first track to include will be the last one if we're filtering by channels */ 01147 first= adt->nla_tracks.last; 01148 } 01149 else { 01150 /* first track to include will the the first one (as per normal) */ 01151 first= adt->nla_tracks.first; 01152 } 01153 01154 /* loop over NLA Tracks - assume that the caller of this has already checked that these should be included */ 01155 for (nlt= first; nlt; nlt= next) { 01156 /* 'next' NLA-Track to use depends on whether we're filtering for drawing or not */ 01157 if (filter_mode & ANIMFILTER_LIST_CHANNELS) 01158 next= nlt->prev; 01159 else 01160 next= nlt->next; 01161 01162 /* if we're in NLA-tweakmode, don't show this track if it was disabled (due to tweaking) for now 01163 * - active track should still get shown though (even though it has disabled flag set) 01164 */ 01165 // FIXME: the channels after should still get drawn, just 'differently', and after an active-action channel 01166 if ((adt->flag & ADT_NLA_EDIT_ON) && (nlt->flag & NLATRACK_DISABLED) && !(nlt->flag & NLATRACK_ACTIVE)) 01167 continue; 01168 01169 /* only work with this channel and its subchannels if it is editable */ 01170 if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_NLT(nlt)) { 01171 /* only include this track if selected in a way consistent with the filtering requirements */ 01172 if ( ANIMCHANNEL_SELOK(SEL_NLT(nlt)) ) { 01173 /* only include if this track is active */ 01174 if (!(filter_mode & ANIMFILTER_ACTIVE) || (nlt->flag & NLATRACK_ACTIVE)) { 01175 ANIMCHANNEL_NEW_CHANNEL(nlt, ANIMTYPE_NLATRACK, owner_id); 01176 } 01177 } 01178 } 01179 } 01180 01181 /* return the number of items added to the list */ 01182 return items; 01183 } 01184 01185 /* determine what animation data from AnimData block should get displayed */ 01186 static size_t animfilter_block_data (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, ID *id, int filter_mode) 01187 { 01188 AnimData *adt = BKE_animdata_from_id(id); 01189 size_t items = 0; 01190 01191 /* image object datablocks have no anim-data so check for NULL */ 01192 if(adt) { 01193 IdAdtTemplate *iat = (IdAdtTemplate*)id; 01194 01195 /* NOTE: this macro is used instead of inlining the logic here, since this sort of filtering is still needed 01196 * in a few places in he rest of the code still - notably for the few cases where special mode-based 01197 * different types of data expanders are required. 01198 */ 01199 ANIMDATA_FILTER_CASES(iat, 01200 { /* AnimData */ 01201 /* specifically filter animdata block */ 01202 ANIMCHANNEL_NEW_CHANNEL(adt, ANIMTYPE_ANIMDATA, id); 01203 }, 01204 { /* NLA */ 01205 items += animfilter_nla(ac, anim_data, ads, adt, filter_mode, id); 01206 }, 01207 { /* Drivers */ 01208 items += animfilter_fcurves(anim_data, ads, adt->drivers.first, NULL, filter_mode, id); 01209 }, 01210 { /* Keyframes */ 01211 items += animfilter_action(ac, anim_data, ads, adt->action, filter_mode, id); 01212 } 01213 ); 01214 } 01215 01216 return items; 01217 } 01218 01219 01220 01221 /* Include ShapeKey Data for ShapeKey Editor */ 01222 static size_t animdata_filter_shapekey (bAnimContext *ac, ListBase *anim_data, Key *key, int filter_mode) 01223 { 01224 size_t items = 0; 01225 01226 /* check if channels or only F-Curves */ 01227 if (filter_mode & ANIMFILTER_LIST_CHANNELS) { 01228 KeyBlock *kb; 01229 01230 /* loop through the channels adding ShapeKeys as appropriate */ 01231 for (kb= key->block.first; kb; kb= kb->next) { 01232 /* skip the first one, since that's the non-animateable basis */ 01233 // XXX maybe in future this may become handy? 01234 if (kb == key->block.first) continue; 01235 01236 /* only work with this channel and its subchannels if it is editable */ 01237 if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_SHAPEKEY(kb)) { 01238 /* only include this track if selected in a way consistent with the filtering requirements */ 01239 if ( ANIMCHANNEL_SELOK(SEL_SHAPEKEY(kb)) ) { 01240 // TODO: consider 'active' too? 01241 01242 /* owner-id here must be key so that the F-Curve can be resolved... */ 01243 ANIMCHANNEL_NEW_CHANNEL(kb, ANIMTYPE_SHAPEKEY, key); 01244 } 01245 } 01246 } 01247 } 01248 else { 01249 /* just use the action associated with the shapekey */ 01250 // TODO: somehow manage to pass dopesheet info down here too? 01251 if (key->adt) { 01252 if (filter_mode & ANIMFILTER_ANIMDATA) { 01253 ANIMCHANNEL_NEW_CHANNEL(key->adt, ANIMTYPE_ANIMDATA, key); 01254 } 01255 else if (key->adt->action) { 01256 items= animfilter_action(ac, anim_data, NULL, key->adt->action, filter_mode, (ID *)key); 01257 } 01258 } 01259 } 01260 01261 /* return the number of items added to the list */ 01262 return items; 01263 } 01264 01265 static size_t animdata_filter_gpencil_data (ListBase *anim_data, bGPdata *gpd, int filter_mode) 01266 { 01267 bGPDlayer *gpl; 01268 size_t items = 0; 01269 01270 /* loop over layers as the conditions are acceptable */ 01271 for (gpl= gpd->layers.first; gpl; gpl= gpl->next) { 01272 /* only if selected */ 01273 if ( ANIMCHANNEL_SELOK(SEL_GPL(gpl)) ) { 01274 /* only if editable */ 01275 if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_GPL(gpl)) { 01276 /* active... */ 01277 if (!(filter_mode & ANIMFILTER_ACTIVE) || (gpl->flag & GP_LAYER_ACTIVE)) { 01278 /* add to list */ 01279 ANIMCHANNEL_NEW_CHANNEL(gpl, ANIMTYPE_GPLAYER, gpd); 01280 } 01281 } 01282 } 01283 } 01284 01285 return items; 01286 } 01287 01288 /* Grab all Grase Pencil datablocks in file */ 01289 // TODO: should this be amalgamated with the dopesheet filtering code? 01290 static size_t animdata_filter_gpencil (ListBase *anim_data, void *UNUSED(data), int filter_mode) 01291 { 01292 bGPdata *gpd; 01293 size_t items = 0; 01294 01295 /* for now, grab grease pencil datablocks directly from main */ 01296 // XXX: this is not good... 01297 for (gpd = G.main->gpencil.first; gpd; gpd = gpd->id.next) { 01298 ListBase tmp_data = {NULL, NULL}; 01299 size_t tmp_items = 0; 01300 01301 /* only show if gpd is used by something... */ 01302 if (ID_REAL_USERS(gpd) < 1) 01303 continue; 01304 01305 /* add gpencil animation channels */ 01306 BEGIN_ANIMFILTER_SUBCHANNELS(EXPANDED_GPD(gpd)) 01307 { 01308 tmp_items += animdata_filter_gpencil_data(&tmp_data, gpd, filter_mode); 01309 } 01310 END_ANIMFILTER_SUBCHANNELS; 01311 01312 /* did we find anything? */ 01313 if (tmp_items) { 01314 /* include data-expand widget first */ 01315 if (filter_mode & ANIMFILTER_LIST_CHANNELS) { 01316 /* add gpd as channel too (if for drawing, and it has layers) */ 01317 ANIMCHANNEL_NEW_CHANNEL(gpd, ANIMTYPE_GPDATABLOCK, NULL); 01318 } 01319 01320 /* now add the list of collected channels */ 01321 BLI_movelisttolist(anim_data, &tmp_data); 01322 BLI_assert((tmp_data.first == tmp_data.last) && (tmp_data.first == NULL)); 01323 items += tmp_items; 01324 } 01325 } 01326 01327 /* return the number of items added to the list */ 01328 return items; 01329 } 01330 01331 /* NOTE: owner_id is scene, material, or texture block, which is the direct owner of the node tree in question */ 01332 // TODO: how to handle group nodes is still unclear... 01333 static size_t animdata_filter_ds_nodetree (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, ID *owner_id, bNodeTree *ntree, int filter_mode) 01334 { 01335 ListBase tmp_data = {NULL, NULL}; 01336 size_t tmp_items = 0; 01337 size_t items = 0; 01338 01339 /* add nodetree animation channels */ 01340 BEGIN_ANIMFILTER_SUBCHANNELS(FILTER_NTREE_DATA(ntree)) 01341 { 01342 /* animation data filtering */ 01343 tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)ntree, filter_mode); 01344 } 01345 END_ANIMFILTER_SUBCHANNELS; 01346 01347 /* did we find anything? */ 01348 if (tmp_items) { 01349 /* include data-expand widget first */ 01350 if (filter_mode & ANIMFILTER_LIST_CHANNELS) { 01351 /* check if filtering by active status */ 01352 if ANIMCHANNEL_ACTIVEOK(ntree) { 01353 ANIMCHANNEL_NEW_CHANNEL(ntree, ANIMTYPE_DSNTREE, owner_id); 01354 } 01355 } 01356 01357 /* now add the list of collected channels */ 01358 BLI_movelisttolist(anim_data, &tmp_data); 01359 BLI_assert((tmp_data.first == tmp_data.last) && (tmp_data.first == NULL)); 01360 items += tmp_items; 01361 } 01362 01363 /* return the number of items added to the list */ 01364 return items; 01365 } 01366 01367 /* NOTE: owner_id is either material, lamp, or world block, which is the direct owner of the texture stack in question */ 01368 static size_t animdata_filter_ds_textures (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, ID *owner_id, int filter_mode) 01369 { 01370 MTex **mtex = NULL; 01371 size_t items=0; 01372 int a=0; 01373 01374 /* get datatype specific data first */ 01375 if (owner_id == NULL) 01376 return 0; 01377 01378 switch (GS(owner_id->name)) { 01379 case ID_MA: 01380 { 01381 Material *ma= (Material *)owner_id; 01382 mtex= (MTex**)(&ma->mtex); 01383 } 01384 break; 01385 case ID_LA: 01386 { 01387 Lamp *la= (Lamp *)owner_id; 01388 mtex= (MTex**)(&la->mtex); 01389 } 01390 break; 01391 case ID_WO: 01392 { 01393 World *wo= (World *)owner_id; 01394 mtex= (MTex**)(&wo->mtex); 01395 } 01396 break; 01397 default: 01398 { 01399 /* invalid/unsupported option */ 01400 if (G.f & G_DEBUG) 01401 printf("ERROR: unsupported owner_id (i.e. texture stack) for filter textures - %s \n", owner_id->name); 01402 return 0; 01403 } 01404 } 01405 01406 /* firstly check that we actuallly have some textures, by gathering all textures in a temp list */ 01407 for (a=0; a < MAX_MTEX; a++) { 01408 Tex *tex= (mtex[a]) ? mtex[a]->tex : NULL; 01409 ListBase tmp_data = {NULL, NULL}; 01410 size_t tmp_items = 0; 01411 01412 /* for now, if no texture returned, skip (this shouldn't confuse the user I hope) */ 01413 if (tex == NULL) 01414 continue; 01415 01416 /* add texture's animation data to temp collection */ 01417 BEGIN_ANIMFILTER_SUBCHANNELS(FILTER_TEX_DATA(tex)) 01418 { 01419 /* texture animdata */ 01420 tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)tex, filter_mode); 01421 01422 /* nodes */ 01423 if ((tex->nodetree) && !(ads->filterflag & ADS_FILTER_NONTREE)) { 01424 /* owner_id as id instead of texture, since it'll otherwise be impossible to track the depth */ 01425 // FIXME: perhaps as a result, textures should NOT be included under materials, but under their own section instead 01426 // so that free-floating textures can also be animated 01427 tmp_items += animdata_filter_ds_nodetree(ac, &tmp_data, ads, (ID *)tex, tex->nodetree, filter_mode); 01428 } 01429 } 01430 END_ANIMFILTER_SUBCHANNELS; 01431 01432 /* did we find anything? */ 01433 if (tmp_items) { 01434 /* include texture-expand widget? */ 01435 if (filter_mode & ANIMFILTER_LIST_CHANNELS) { 01436 /* check if filtering by active status */ 01437 if ANIMCHANNEL_ACTIVEOK(tex) { 01438 ANIMCHANNEL_NEW_CHANNEL(tex, ANIMTYPE_DSTEX, owner_id); 01439 } 01440 } 01441 01442 /* now add the list of collected channels */ 01443 BLI_movelisttolist(anim_data, &tmp_data); 01444 BLI_assert((tmp_data.first == tmp_data.last) && (tmp_data.first == NULL)); 01445 items += tmp_items; 01446 } 01447 } 01448 01449 /* return the number of items added to the list */ 01450 return items; 01451 } 01452 01453 static size_t animdata_filter_ds_materials (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Object *ob, int filter_mode) 01454 { 01455 size_t items=0; 01456 int a=0; 01457 01458 /* firstly check that we actuallly have some materials, by gathering all materials in a temp list */ 01459 for (a=1; a <= ob->totcol; a++) { 01460 Material *ma= give_current_material(ob, a); 01461 ListBase tmp_data = {NULL, NULL}; 01462 size_t tmp_items = 0; 01463 01464 /* if no material returned, skip - so that we don't get weird blank entries... */ 01465 if (ma == NULL) continue; 01466 01467 /* add material's animation data to temp collection */ 01468 BEGIN_ANIMFILTER_SUBCHANNELS(FILTER_MAT_OBJD(ma)) 01469 { 01470 /* material's animation data */ 01471 tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)ma, filter_mode); 01472 01473 /* textures */ 01474 if (!(ads->filterflag & ADS_FILTER_NOTEX)) 01475 tmp_items += animdata_filter_ds_textures(ac, &tmp_data, ads, (ID *)ma, filter_mode); 01476 01477 /* nodes */ 01478 if ((ma->nodetree) && !(ads->filterflag & ADS_FILTER_NONTREE)) 01479 tmp_items += animdata_filter_ds_nodetree(ac, &tmp_data, ads, (ID *)ma, ma->nodetree, filter_mode); 01480 } 01481 END_ANIMFILTER_SUBCHANNELS; 01482 01483 /* did we find anything? */ 01484 if (tmp_items) { 01485 /* include material-expand widget first */ 01486 // hmm... do we need to store the index of this material in the array anywhere? 01487 if (filter_mode & ANIMFILTER_LIST_CHANNELS) { 01488 /* check if filtering by active status */ 01489 if ANIMCHANNEL_ACTIVEOK(ma) { 01490 ANIMCHANNEL_NEW_CHANNEL(ma, ANIMTYPE_DSMAT, ma); 01491 } 01492 } 01493 01494 /* now add the list of collected channels */ 01495 BLI_movelisttolist(anim_data, &tmp_data); 01496 BLI_assert((tmp_data.first == tmp_data.last) && (tmp_data.first == NULL)); 01497 items += tmp_items; 01498 } 01499 } 01500 01501 /* return the number of items added to the list */ 01502 return items; 01503 } 01504 01505 static size_t animdata_filter_ds_particles (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Object *ob, int filter_mode) 01506 { 01507 ParticleSystem *psys; 01508 size_t items= 0; 01509 01510 for (psys = ob->particlesystem.first; psys; psys=psys->next) { 01511 ListBase tmp_data = {NULL, NULL}; 01512 size_t tmp_items = 0; 01513 01514 /* if no material returned, skip - so that we don't get weird blank entries... */ 01515 if (ELEM(NULL, psys->part, psys->part->adt)) 01516 continue; 01517 01518 /* add particle-system's animation data to temp collection */ 01519 BEGIN_ANIMFILTER_SUBCHANNELS(FILTER_PART_OBJD(psys->part)) 01520 { 01521 /* material's animation data */ 01522 tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)psys->part, filter_mode); 01523 } 01524 END_ANIMFILTER_SUBCHANNELS; 01525 01526 /* did we find anything? */ 01527 if (tmp_items) { 01528 /* include particle-expand widget first */ 01529 if (filter_mode & ANIMFILTER_LIST_CHANNELS) { 01530 /* check if filtering by active status */ 01531 if ANIMCHANNEL_ACTIVEOK(psys->part) { 01532 ANIMCHANNEL_NEW_CHANNEL(psys->part, ANIMTYPE_DSPART, psys->part); 01533 } 01534 } 01535 01536 /* now add the list of collected channels */ 01537 BLI_movelisttolist(anim_data, &tmp_data); 01538 BLI_assert((tmp_data.first == tmp_data.last) && (tmp_data.first == NULL)); 01539 items += tmp_items; 01540 } 01541 } 01542 01543 /* return the number of items added to the list */ 01544 return items; 01545 } 01546 01547 static size_t animdata_filter_ds_obdata (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Object *ob, int filter_mode) 01548 { 01549 ListBase tmp_data = {NULL, NULL}; 01550 size_t tmp_items = 0; 01551 size_t items= 0; 01552 01553 IdAdtTemplate *iat= ob->data; 01554 short type=0, expanded=0; 01555 01556 /* get settings based on data type */ 01557 switch (ob->type) { 01558 case OB_CAMERA: /* ------- Camera ------------ */ 01559 { 01560 Camera *ca= (Camera *)ob->data; 01561 01562 if (ads->filterflag & ADS_FILTER_NOCAM) 01563 return 0; 01564 01565 type= ANIMTYPE_DSCAM; 01566 expanded= FILTER_CAM_OBJD(ca); 01567 } 01568 break; 01569 case OB_LAMP: /* ---------- Lamp ----------- */ 01570 { 01571 Lamp *la= (Lamp *)ob->data; 01572 01573 if (ads->filterflag & ADS_FILTER_NOLAM) 01574 return 0; 01575 01576 type= ANIMTYPE_DSLAM; 01577 expanded= FILTER_LAM_OBJD(la); 01578 } 01579 break; 01580 case OB_CURVE: /* ------- Curve ---------- */ 01581 case OB_SURF: /* ------- Nurbs Surface ---------- */ 01582 case OB_FONT: /* ------- Text Curve ---------- */ 01583 { 01584 Curve *cu= (Curve *)ob->data; 01585 01586 if (ads->filterflag & ADS_FILTER_NOCUR) 01587 return 0; 01588 01589 type= ANIMTYPE_DSCUR; 01590 expanded= FILTER_CUR_OBJD(cu); 01591 } 01592 break; 01593 case OB_MBALL: /* ------- MetaBall ---------- */ 01594 { 01595 MetaBall *mb= (MetaBall *)ob->data; 01596 01597 if (ads->filterflag & ADS_FILTER_NOMBA) 01598 return 0; 01599 01600 type= ANIMTYPE_DSMBALL; 01601 expanded= FILTER_MBALL_OBJD(mb); 01602 } 01603 break; 01604 case OB_ARMATURE: /* ------- Armature ---------- */ 01605 { 01606 bArmature *arm= (bArmature *)ob->data; 01607 01608 if (ads->filterflag & ADS_FILTER_NOARM) 01609 return 0; 01610 01611 type= ANIMTYPE_DSARM; 01612 expanded= FILTER_ARM_OBJD(arm); 01613 } 01614 break; 01615 case OB_MESH: /* ------- Mesh ---------- */ 01616 { 01617 Mesh *me= (Mesh *)ob->data; 01618 01619 if (ads->filterflag & ADS_FILTER_NOMESH) 01620 return 0; 01621 01622 type= ANIMTYPE_DSMESH; 01623 expanded= FILTER_MESH_OBJD(me); 01624 } 01625 break; 01626 case OB_LATTICE: /* ---- Lattice ---- */ 01627 { 01628 Lattice *lt = (Lattice *)ob->data; 01629 01630 if (ads->filterflag & ADS_FILTER_NOLAT) 01631 return 0; 01632 01633 type= ANIMTYPE_DSLAT; 01634 expanded= FILTER_LATTICE_OBJD(lt); 01635 } 01636 break; 01637 case OB_SPEAKER: /* ---------- Speaker ----------- */ 01638 { 01639 Speaker *spk= (Speaker *)ob->data; 01640 01641 type= ANIMTYPE_DSSPK; 01642 expanded= FILTER_SPK_OBJD(spk); 01643 } 01644 break; 01645 } 01646 01647 /* add object data animation channels */ 01648 BEGIN_ANIMFILTER_SUBCHANNELS(expanded) 01649 { 01650 /* animation data filtering */ 01651 tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)iat, filter_mode); 01652 01653 /* sub-data filtering... */ 01654 switch (ob->type) { 01655 case OB_LAMP: /* lamp - textures */ 01656 { 01657 /* textures */ 01658 if (!(ads->filterflag & ADS_FILTER_NOTEX)) 01659 tmp_items += animdata_filter_ds_textures(ac, &tmp_data, ads, ob->data, filter_mode); 01660 } 01661 break; 01662 } 01663 } 01664 END_ANIMFILTER_SUBCHANNELS; 01665 01666 /* did we find anything? */ 01667 if (tmp_items) { 01668 /* include data-expand widget first */ 01669 if (filter_mode & ANIMFILTER_LIST_CHANNELS) { 01670 /* check if filtering by active status */ 01671 if ANIMCHANNEL_ACTIVEOK(iat) { 01672 ANIMCHANNEL_NEW_CHANNEL(iat, type, iat); 01673 } 01674 } 01675 01676 /* now add the list of collected channels */ 01677 BLI_movelisttolist(anim_data, &tmp_data); 01678 BLI_assert((tmp_data.first == tmp_data.last) && (tmp_data.first == NULL)); 01679 items += tmp_items; 01680 } 01681 01682 /* return the number of items added to the list */ 01683 return items; 01684 } 01685 01686 /* shapekey-level animation */ 01687 static size_t animdata_filter_ds_keyanim (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Object *ob, Key *key, int filter_mode) 01688 { 01689 ListBase tmp_data = {NULL, NULL}; 01690 size_t tmp_items = 0; 01691 size_t items = 0; 01692 01693 /* add shapekey-level animation channels */ 01694 BEGIN_ANIMFILTER_SUBCHANNELS(FILTER_SKE_OBJD(key)) 01695 { 01696 /* animation data filtering */ 01697 tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)key, filter_mode); 01698 } 01699 END_ANIMFILTER_SUBCHANNELS; 01700 01701 /* did we find anything? */ 01702 if (tmp_items) { 01703 /* include key-expand widget first */ 01704 if (filter_mode & ANIMFILTER_LIST_CHANNELS) { 01705 if ANIMCHANNEL_ACTIVEOK(key) { 01706 ANIMCHANNEL_NEW_CHANNEL(key, ANIMTYPE_DSSKEY, ob); 01707 } 01708 } 01709 01710 /* now add the list of collected channels */ 01711 BLI_movelisttolist(anim_data, &tmp_data); 01712 BLI_assert((tmp_data.first == tmp_data.last) && (tmp_data.first == NULL)); 01713 items += tmp_items; 01714 } 01715 01716 /* return the number of items added to the list */ 01717 return items; 01718 } 01719 01720 /* object-level animation */ 01721 static size_t animdata_filter_ds_obanim (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Object *ob, int filter_mode) 01722 { 01723 ListBase tmp_data = {NULL, NULL}; 01724 size_t tmp_items = 0; 01725 size_t items = 0; 01726 01727 AnimData *adt = ob->adt; 01728 short type=0, expanded=1; 01729 void *cdata = NULL; 01730 01731 /* determine the type of expander channels to use */ 01732 // this is the best way to do this for now... 01733 ANIMDATA_FILTER_CASES(ob, 01734 {/* AnimData - no channel, but consider data */}, 01735 {/* NLA - no channel, but consider data */}, 01736 {/* Drivers */ 01737 type = ANIMTYPE_FILLDRIVERS; 01738 cdata = adt; 01739 expanded = EXPANDED_DRVD(adt); 01740 }, 01741 {/* Keyframes */ 01742 type = ANIMTYPE_FILLACTD; 01743 cdata = adt->action; 01744 expanded = EXPANDED_ACTC(adt->action); 01745 }); 01746 01747 /* add object-level animation channels */ 01748 BEGIN_ANIMFILTER_SUBCHANNELS(expanded) 01749 { 01750 /* animation data filtering */ 01751 tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)ob, filter_mode); 01752 } 01753 END_ANIMFILTER_SUBCHANNELS; 01754 01755 /* did we find anything? */ 01756 if (tmp_items) { 01757 /* include anim-expand widget first */ 01758 if (filter_mode & ANIMFILTER_LIST_CHANNELS) { 01759 if (type != ANIMTYPE_NONE) { 01760 /* NOTE: active-status (and the associated checks) don't apply here... */ 01761 ANIMCHANNEL_NEW_CHANNEL(cdata, type, ob); 01762 } 01763 } 01764 01765 /* now add the list of collected channels */ 01766 BLI_movelisttolist(anim_data, &tmp_data); 01767 BLI_assert((tmp_data.first == tmp_data.last) && (tmp_data.first == NULL)); 01768 items += tmp_items; 01769 } 01770 01771 /* return the number of items added to the list */ 01772 return items; 01773 } 01774 01775 /* get animation channels from object2 */ 01776 static size_t animdata_filter_dopesheet_ob (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Base *base, int filter_mode) 01777 { 01778 ListBase tmp_data = {NULL, NULL}; 01779 Object *ob= base->object; 01780 size_t tmp_items = 0; 01781 size_t items = 0; 01782 01783 /* filter data contained under object first */ 01784 BEGIN_ANIMFILTER_SUBCHANNELS(EXPANDED_OBJC(ob)) 01785 { 01786 Key *key= ob_get_key(ob); 01787 01788 /* object-level animation */ 01789 if ((ob->adt) && !(ads->filterflag & ADS_FILTER_NOOBJ)) { 01790 tmp_items += animdata_filter_ds_obanim(ac, &tmp_data, ads, ob, filter_mode); 01791 } 01792 01793 /* shape-key */ 01794 if ((key && key->adt) && !(ads->filterflag & ADS_FILTER_NOSHAPEKEYS)) { 01795 tmp_items += animdata_filter_ds_keyanim(ac, &tmp_data, ads, ob, key, filter_mode); 01796 } 01797 01798 /* materials */ 01799 if ((ob->totcol) && !(ads->filterflag & ADS_FILTER_NOMAT)) { 01800 tmp_items += animdata_filter_ds_materials(ac, &tmp_data, ads, ob, filter_mode); 01801 } 01802 01803 /* object data */ 01804 if (ob->data) { 01805 tmp_items += animdata_filter_ds_obdata(ac, &tmp_data, ads, ob, filter_mode); 01806 } 01807 01808 /* particles */ 01809 if ((ob->particlesystem.first) && !(ads->filterflag & ADS_FILTER_NOPART)) { 01810 tmp_items += animdata_filter_ds_particles(ac, &tmp_data, ads, ob, filter_mode); 01811 } 01812 } 01813 END_ANIMFILTER_SUBCHANNELS; 01814 01815 01816 /* if we collected some channels, add these to the new list... */ 01817 if (tmp_items) { 01818 /* firstly add object expander if required */ 01819 if (filter_mode & ANIMFILTER_LIST_CHANNELS) { 01820 /* check if filtering by selection */ 01821 // XXX: double-check on this - most of the time, a lot of tools need to filter out these channels! 01822 if ANIMCHANNEL_SELOK((base->flag & SELECT)) { 01823 /* check if filtering by active status */ 01824 if (ANIMCHANNEL_ACTIVEOK(ob)) { 01825 ANIMCHANNEL_NEW_CHANNEL(base, ANIMTYPE_OBJECT, ob); 01826 } 01827 } 01828 } 01829 01830 /* now add the list of collected channels */ 01831 BLI_movelisttolist(anim_data, &tmp_data); 01832 BLI_assert((tmp_data.first == tmp_data.last) && (tmp_data.first == NULL)); 01833 items += tmp_items; 01834 } 01835 01836 /* return the number of items added */ 01837 return items; 01838 } 01839 01840 static size_t animdata_filter_ds_world (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Scene *sce, World *wo, int filter_mode) 01841 { 01842 ListBase tmp_data = {NULL, NULL}; 01843 size_t tmp_items = 0; 01844 size_t items = 0; 01845 01846 /* add world animation channels */ 01847 BEGIN_ANIMFILTER_SUBCHANNELS(FILTER_WOR_SCED(wo)) 01848 { 01849 /* animation data filtering */ 01850 tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)wo, filter_mode); 01851 01852 /* textures for world */ 01853 if (!(ads->filterflag & ADS_FILTER_NOTEX)) 01854 items += animdata_filter_ds_textures(ac, &tmp_data, ads, (ID *)wo, filter_mode); 01855 01856 /* nodes */ 01857 if ((wo->nodetree) && !(ads->filterflag & ADS_FILTER_NONTREE)) 01858 tmp_items += animdata_filter_ds_nodetree(ac, &tmp_data, ads, (ID *)wo, wo->nodetree, filter_mode); 01859 } 01860 END_ANIMFILTER_SUBCHANNELS; 01861 01862 /* did we find anything? */ 01863 if (tmp_items) { 01864 /* include data-expand widget first */ 01865 if (filter_mode & ANIMFILTER_LIST_CHANNELS) { 01866 /* check if filtering by active status */ 01867 if ANIMCHANNEL_ACTIVEOK(wo) { 01868 ANIMCHANNEL_NEW_CHANNEL(wo, ANIMTYPE_DSWOR, sce); 01869 } 01870 } 01871 01872 /* now add the list of collected channels */ 01873 BLI_movelisttolist(anim_data, &tmp_data); 01874 BLI_assert((tmp_data.first == tmp_data.last) && (tmp_data.first == NULL)); 01875 items += tmp_items; 01876 } 01877 01878 /* return the number of items added to the list */ 01879 return items; 01880 } 01881 01882 static size_t animdata_filter_ds_scene (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Scene *sce, int filter_mode) 01883 { 01884 ListBase tmp_data = {NULL, NULL}; 01885 size_t tmp_items = 0; 01886 size_t items = 0; 01887 01888 AnimData *adt = sce->adt; 01889 short type=0, expanded=1; 01890 void *cdata = NULL; 01891 01892 /* determine the type of expander channels to use */ 01893 // this is the best way to do this for now... 01894 ANIMDATA_FILTER_CASES(sce, 01895 {/* AnimData - no channel, but consider data */}, 01896 {/* NLA - no channel, but consider data */}, 01897 {/* Drivers */ 01898 type = ANIMTYPE_FILLDRIVERS; 01899 cdata = adt; 01900 expanded = EXPANDED_DRVD(adt); 01901 }, 01902 {/* Keyframes */ 01903 type = ANIMTYPE_FILLACTD; 01904 cdata = adt->action; 01905 expanded = EXPANDED_ACTC(adt->action); 01906 }); 01907 01908 /* add scene-level animation channels */ 01909 BEGIN_ANIMFILTER_SUBCHANNELS(expanded) 01910 { 01911 /* animation data filtering */ 01912 tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)sce, filter_mode); 01913 } 01914 END_ANIMFILTER_SUBCHANNELS; 01915 01916 /* did we find anything? */ 01917 if (tmp_items) { 01918 /* include anim-expand widget first */ 01919 if (filter_mode & ANIMFILTER_LIST_CHANNELS) { 01920 if (type != ANIMTYPE_NONE) { 01921 /* NOTE: active-status (and the associated checks) don't apply here... */ 01922 ANIMCHANNEL_NEW_CHANNEL(cdata, type, sce); 01923 } 01924 } 01925 01926 /* now add the list of collected channels */ 01927 BLI_movelisttolist(anim_data, &tmp_data); 01928 BLI_assert((tmp_data.first == tmp_data.last) && (tmp_data.first == NULL)); 01929 items += tmp_items; 01930 } 01931 01932 /* return the number of items added to the list */ 01933 return items; 01934 } 01935 01936 static size_t animdata_filter_dopesheet_scene (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Scene *sce, int filter_mode) 01937 { 01938 ListBase tmp_data = {NULL, NULL}; 01939 size_t tmp_items = 0; 01940 size_t items = 0; 01941 01942 /* filter data contained under object first */ 01943 BEGIN_ANIMFILTER_SUBCHANNELS(EXPANDED_SCEC(sce)) 01944 { 01945 bNodeTree *ntree= sce->nodetree; 01946 World *wo= sce->world; 01947 01948 /* Action, Drivers, or NLA for Scene */ 01949 if ((ads->filterflag & ADS_FILTER_NOSCE) == 0) { 01950 tmp_items += animdata_filter_ds_scene(ac, &tmp_data, ads, sce, filter_mode); 01951 } 01952 01953 /* world */ 01954 if ((wo) && !(ads->filterflag & ADS_FILTER_NOWOR)) { 01955 tmp_items += animdata_filter_ds_world(ac, &tmp_data, ads, sce, wo, filter_mode); 01956 } 01957 01958 /* nodetree */ 01959 if ((ntree) && !(ads->filterflag & ADS_FILTER_NONTREE)) { 01960 tmp_items += animdata_filter_ds_nodetree(ac, &tmp_data, ads, (ID *)sce, ntree, filter_mode); 01961 } 01962 01963 // TODO: one day, when sequencer becomes its own datatype, perhaps it should be included here 01964 } 01965 END_ANIMFILTER_SUBCHANNELS; 01966 01967 /* if we collected some channels, add these to the new list... */ 01968 if (tmp_items) { 01969 /* firstly add object expander if required */ 01970 if (filter_mode & ANIMFILTER_LIST_CHANNELS) { 01971 /* check if filtering by selection */ 01972 if ANIMCHANNEL_SELOK((sce->flag & SCE_DS_SELECTED)) { 01973 /* NOTE: active-status doesn't matter for this! */ 01974 ANIMCHANNEL_NEW_CHANNEL(sce, ANIMTYPE_SCENE, sce); 01975 } 01976 } 01977 01978 /* now add the list of collected channels */ 01979 BLI_movelisttolist(anim_data, &tmp_data); 01980 BLI_assert((tmp_data.first == tmp_data.last) && (tmp_data.first == NULL)); 01981 items += tmp_items; 01982 } 01983 01984 /* return the number of items added */ 01985 return items; 01986 } 01987 01988 // TODO: implement pinning... (if and when pinning is done, what we need to do is to provide freeing mechanisms - to protect against data that was deleted) 01989 static size_t animdata_filter_dopesheet (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, int filter_mode) 01990 { 01991 Scene *sce= (Scene *)ads->source; 01992 Base *base; 01993 size_t items = 0; 01994 01995 /* check that we do indeed have a scene */ 01996 if ((ads->source == NULL) || (GS(ads->source->name)!=ID_SCE)) { 01997 printf("DopeSheet Error: Not scene!\n"); 01998 if (G.f & G_DEBUG) 01999 printf("\tPointer = %p, Name = '%s' \n", (void *)ads->source, (ads->source)?ads->source->name:NULL); 02000 return 0; 02001 } 02002 02003 /* augment the filter-flags with settings based on the dopesheet filterflags 02004 * so that some temp settings can get added automagically... 02005 */ 02006 if (ads->filterflag & ADS_FILTER_SELEDIT) { 02007 /* only selected F-Curves should get their keyframes considered for editability */ 02008 filter_mode |= ANIMFILTER_SELEDIT; 02009 } 02010 02011 /* scene-linked animation - e.g. world, compositing nodes, scene anim (including sequencer currently) */ 02012 items += animdata_filter_dopesheet_scene(ac, anim_data, ads, sce, filter_mode); 02013 02014 /* loop over all bases (i.e.objects) in the scene */ 02015 for (base= sce->base.first; base; base= base->next) { 02016 /* check if there's an object (all the relevant checks are done in the ob-function) */ 02017 if (base->object) { 02018 Object *ob= base->object; 02019 02020 /* firstly, check if object can be included, by the following factors: 02021 * - if only visible, must check for layer and also viewport visibility 02022 * --> while tools may demand only visible, user setting takes priority 02023 * as user option controls whether sets of channels get included while 02024 * tool-flag takes into account collapsed/open channels too 02025 * - if only selected, must check if object is selected 02026 * - there must be animation data to edit (this is done recursively as we 02027 * try to add the channels) 02028 */ 02029 if ((filter_mode & ANIMFILTER_DATA_VISIBLE) && !(ads->filterflag & ADS_FILTER_INCL_HIDDEN)) { 02030 /* layer visibility - we check both object and base, since these may not be in sync yet */ 02031 if ((sce->lay & (ob->lay|base->lay))==0) continue; 02032 02033 /* outliner restrict-flag */ 02034 if (ob->restrictflag & OB_RESTRICT_VIEW) continue; 02035 } 02036 02037 /* if only F-Curves with visible flags set can be shown, check that 02038 * datablock hasn't been set to invisible 02039 */ 02040 if (filter_mode & ANIMFILTER_CURVE_VISIBLE) { 02041 if ((ob->adt) && (ob->adt->flag & ADT_CURVES_NOT_VISIBLE)) 02042 continue; 02043 } 02044 02045 /* check selection and object type filters */ 02046 if ( (ads->filterflag & ADS_FILTER_ONLYSEL) && !((base->flag & SELECT) /*|| (base == sce->basact)*/) ) { 02047 /* only selected should be shown */ 02048 continue; 02049 } 02050 02051 /* check if object belongs to the filtering group if option to filter 02052 * objects by the grouped status is on 02053 * - used to ease the process of doing multiple-character choreographies 02054 */ 02055 if (ads->filterflag & ADS_FILTER_ONLYOBGROUP) { 02056 if (object_in_group(ob, ads->filter_grp) == 0) 02057 continue; 02058 } 02059 02060 /* since we're still here, this object should be usable */ 02061 items += animdata_filter_dopesheet_ob(ac, anim_data, ads, base, filter_mode); 02062 } 02063 } 02064 02065 /* return the number of items in the list */ 02066 return items; 02067 } 02068 02069 /* Summary track for DopeSheet/Action Editor 02070 * - return code is whether the summary lets the other channels get drawn 02071 */ 02072 static short animdata_filter_dopesheet_summary (bAnimContext *ac, ListBase *anim_data, int filter_mode, size_t *items) 02073 { 02074 bDopeSheet *ads = NULL; 02075 02076 /* get the DopeSheet information to use 02077 * - we should only need to deal with the DopeSheet/Action Editor, 02078 * since all the other Animation Editors won't have this concept 02079 * being applicable. 02080 */ 02081 if ((ac && ac->sl) && (ac->spacetype == SPACE_ACTION)) { 02082 SpaceAction *saction= (SpaceAction *)ac->sl; 02083 ads= &saction->ads; 02084 } 02085 else { 02086 /* invalid space type - skip this summary channels */ 02087 return 1; 02088 } 02089 02090 /* dopesheet summary 02091 * - only for drawing and/or selecting keyframes in channels, but not for real editing 02092 * - only useful for DopeSheet/Action/etc. editors where it is actually useful 02093 */ 02094 if ((filter_mode & ANIMFILTER_LIST_CHANNELS) && (ads->filterflag & ADS_FILTER_SUMMARY)) { 02095 bAnimListElem *ale= make_new_animlistelem(ac, ANIMTYPE_SUMMARY, NULL); 02096 if (ale) { 02097 BLI_addtail(anim_data, ale); 02098 (*items)++; 02099 } 02100 02101 /* if summary is collapsed, don't show other channels beneath this 02102 * - this check is put inside the summary check so that it doesn't interfere with normal operation 02103 */ 02104 if (ads->flag & ADS_FLAG_SUMMARY_COLLAPSED) 02105 return 0; 02106 } 02107 02108 /* the other channels beneath this can be shown */ 02109 return 1; 02110 } 02111 02112 /* ......................... */ 02113 02114 /* filter data associated with a channel - usually for handling summary-channels in DopeSheet */ 02115 static size_t animdata_filter_animchan (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, bAnimListElem *channel, int filter_mode) 02116 { 02117 size_t items = 0; 02118 02119 /* data to filter depends on channel type */ 02120 // XXX: only common channel-types have been handled for now 02121 switch (channel->type) { 02122 case ANIMTYPE_SUMMARY: 02123 items += animdata_filter_dopesheet(ac, anim_data, ads, filter_mode); 02124 break; 02125 02126 case ANIMTYPE_SCENE: 02127 items += animdata_filter_dopesheet_scene(ac, anim_data, ads, channel->data, filter_mode); 02128 break; 02129 02130 case ANIMTYPE_OBJECT: 02131 items += animdata_filter_dopesheet_ob(ac, anim_data, ads, channel->data, filter_mode); 02132 break; 02133 } 02134 02135 return items; 02136 } 02137 02138 /* ----------- Cleanup API --------------- */ 02139 02140 /* Remove entries with invalid types in animation channel list */ 02141 static size_t animdata_filter_remove_invalid (ListBase *anim_data) 02142 { 02143 bAnimListElem *ale, *next; 02144 size_t items = 0; 02145 02146 /* only keep entries with valid types */ 02147 for (ale= anim_data->first; ale; ale= next) { 02148 next= ale->next; 02149 02150 if (ale->type == ANIMTYPE_NONE) 02151 BLI_freelinkN(anim_data, ale); 02152 else 02153 items++; 02154 } 02155 02156 return items; 02157 } 02158 02159 /* Remove duplicate entries in animation channel list */ 02160 static size_t animdata_filter_remove_duplis (ListBase *anim_data) 02161 { 02162 bAnimListElem *ale, *next; 02163 GHash *gh; 02164 size_t items = 0; 02165 02166 /* build new hashtable to efficiently store and retrieve which entries have been 02167 * encountered already while searching 02168 */ 02169 gh= BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "animdata_filter_duplis_remove gh"); 02170 02171 /* loop through items, removing them from the list if a similar item occurs already */ 02172 for (ale = anim_data->first; ale; ale = next) { 02173 next = ale->next; 02174 02175 /* check if hash has any record of an entry like this 02176 * - just use ale->data for now, though it would be nicer to involve 02177 * ale->type in combination too to capture corner cases (where same data performs differently) 02178 */ 02179 if (BLI_ghash_haskey(gh, ale->data) == 0) { 02180 /* this entry is 'unique' and can be kept */ 02181 BLI_ghash_insert(gh, ale->data, NULL); 02182 items++; 02183 } 02184 else { 02185 /* this entry isn't needed anymore */ 02186 BLI_freelinkN(anim_data, ale); 02187 } 02188 } 02189 02190 /* free the hash... */ 02191 BLI_ghash_free(gh, NULL, NULL); 02192 02193 /* return the number of items still in the list */ 02194 return items; 02195 } 02196 02197 /* ----------- Public API --------------- */ 02198 02199 /* This function filters the active data source to leave only animation channels suitable for 02200 * usage by the caller. It will return the length of the list 02201 * 02202 * *anim_data: is a pointer to a ListBase, to which the filtered animation channels 02203 * will be placed for use. 02204 * filter_mode: how should the data be filtered - bitmapping accessed flags 02205 */ 02206 size_t ANIM_animdata_filter (bAnimContext *ac, ListBase *anim_data, int filter_mode, void *data, short datatype) 02207 { 02208 size_t items = 0; 02209 02210 /* only filter data if there's somewhere to put it */ 02211 if (data && anim_data) { 02212 02213 /* firstly filter the data */ 02214 switch (datatype) { 02215 case ANIMCONT_ACTION: /* 'Action Editor' */ 02216 { 02217 Object *obact= ac->obact; 02218 SpaceAction *saction = (SpaceAction *)ac->sl; 02219 bDopeSheet *ads = (saction)? &saction->ads : NULL; 02220 02221 /* the check for the DopeSheet summary is included here since the summary works here too */ 02222 if (animdata_filter_dopesheet_summary(ac, anim_data, filter_mode, &items)) 02223 items += animfilter_action(ac, anim_data, ads, data, filter_mode, (ID *)obact); 02224 } 02225 break; 02226 02227 case ANIMCONT_SHAPEKEY: /* 'ShapeKey Editor' */ 02228 { 02229 /* the check for the DopeSheet summary is included here since the summary works here too */ 02230 if (animdata_filter_dopesheet_summary(ac, anim_data, filter_mode, &items)) 02231 items= animdata_filter_shapekey(ac, anim_data, data, filter_mode); 02232 } 02233 break; 02234 02235 case ANIMCONT_GPENCIL: 02236 { 02237 items= animdata_filter_gpencil(anim_data, data, filter_mode); 02238 } 02239 break; 02240 02241 case ANIMCONT_DOPESHEET: /* 'DopeSheet Editor' */ 02242 { 02243 /* the DopeSheet editor is the primary place where the DopeSheet summaries are useful */ 02244 if (animdata_filter_dopesheet_summary(ac, anim_data, filter_mode, &items)) 02245 items += animdata_filter_dopesheet(ac, anim_data, data, filter_mode); 02246 } 02247 break; 02248 02249 case ANIMCONT_FCURVES: /* Graph Editor -> FCurves/Animation Editing */ 02250 case ANIMCONT_DRIVERS: /* Graph Editor -> Drivers Editing */ 02251 case ANIMCONT_NLA: /* NLA Editor */ 02252 { 02253 /* all of these editors use the basic DopeSheet data for filtering options, but don't have all the same features */ 02254 items = animdata_filter_dopesheet(ac, anim_data, data, filter_mode); 02255 } 02256 break; 02257 02258 case ANIMCONT_CHANNEL: /* animation channel */ 02259 { 02260 bDopeSheet *ads = ac->ads; 02261 02262 /* based on the channel type, filter relevant data for this */ 02263 items = animdata_filter_animchan(ac, anim_data, ads, data, filter_mode); 02264 } 02265 break; 02266 } 02267 02268 /* remove any 'weedy' entries */ 02269 items = animdata_filter_remove_invalid(anim_data); 02270 02271 /* remove duplicates (if required) */ 02272 if (filter_mode & ANIMFILTER_NODUPLIS) 02273 items = animdata_filter_remove_duplis(anim_data); 02274 } 02275 02276 /* return the number of items in the list */ 02277 return items; 02278 } 02279 02280 /* ************************************************************ */